sonamu 0.10.11 → 0.10.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/agents/agent.d.ts +1 -1
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +5 -6
- package/dist/ai/agents/types.d.ts +1 -1
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/api.js +18 -18
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/error.js +17 -15
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.js +3 -2
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/options.js +16 -16
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/provider.js +9 -9
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.js +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +17 -17
- package/dist/api/code-converters.d.ts +4 -2
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +100 -19
- package/dist/api/config.d.ts +16 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +28 -21
- package/dist/api/context.d.ts +2 -2
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +18 -11
- package/dist/api/http-validator.d.ts +36 -0
- package/dist/api/http-validator.d.ts.map +1 -0
- package/dist/api/http-validator.js +72 -0
- package/dist/api/index.js +6 -4
- package/dist/api/sonamu.d.ts +59 -20
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +250 -106
- package/dist/api/websocket-helpers.d.ts +7 -5
- package/dist/api/websocket-helpers.d.ts.map +1 -1
- package/dist/api/websocket-helpers.js +6 -6
- package/dist/auth/audit-log/builders.d.ts.map +1 -1
- package/dist/auth/audit-log/builders.js +1 -1
- package/dist/auth/audit-log/client-ip.d.ts +1 -1
- package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
- package/dist/auth/audit-log/client-ip.js +4 -2
- package/dist/auth/audit-log/events.d.ts +5 -1
- package/dist/auth/audit-log/events.d.ts.map +1 -1
- package/dist/auth/audit-log/events.js +1 -1
- package/dist/auth/audit-log/plugin.d.ts +0 -8
- package/dist/auth/audit-log/plugin.d.ts.map +1 -1
- package/dist/auth/audit-log/plugin.js +48 -52
- package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
- package/dist/auth/audit-log-ingestor.js +16 -12
- package/dist/auth/auth-generator.d.ts.map +1 -1
- package/dist/auth/auth-generator.js +1 -1
- package/dist/auth/better-auth-request.d.ts.map +1 -1
- package/dist/auth/better-auth-request.js +6 -5
- package/dist/auth/knex-adapter.js +1 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +1 -1
- package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
- package/dist/bin/build-config.d.ts +25 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +105 -2
- package/dist/bin/cli.js +133 -29
- package/dist/bin/compiler-policy.d.ts +3 -0
- package/dist/bin/compiler-policy.d.ts.map +1 -0
- package/dist/bin/compiler-policy.js +24 -0
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +5 -3
- package/dist/bin/test-command.d.ts +22 -1
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +18 -10
- package/dist/bin/ts-loader-registration.d.ts +7 -1
- package/dist/bin/ts-loader-registration.d.ts.map +1 -1
- package/dist/bin/ts-loader-registration.js +13 -4
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +11 -4
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/compress/compress.js +1 -1
- package/dist/cone/cone-generator.d.ts +14 -1
- package/dist/cone/cone-generator.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +13 -9
- package/dist/database/_batch_update.js +1 -1
- package/dist/database/base-model.d.ts +22 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +26 -16
- package/dist/database/base-model.types.d.ts +15 -3
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/db.d.ts +12 -2
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +10 -7
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +17 -14
- package/dist/database/puri.d.ts +11 -9
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +93 -79
- package/dist/database/puri.types.d.ts +21 -21
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +1 -1
- package/dist/database/upsert-builder.d.ts +12 -10
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +20 -12
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +1 -1
- package/dist/dict/utils.d.ts.map +1 -1
- package/dist/dict/utils.js +7 -2
- package/dist/entity/entity-manager.d.ts +13 -4
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +19 -11
- package/dist/entity/entity-template-cone.d.ts +73 -5
- package/dist/entity/entity-template-cone.d.ts.map +1 -1
- package/dist/entity/entity-template-cone.js +4 -2
- package/dist/entity/entity.d.ts +6 -2
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +30 -28
- package/dist/env.d.ts +3 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +7 -2
- package/dist/exceptions/so-exceptions.d.ts +24 -20
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +4 -2
- package/dist/filter/utils.d.ts +7 -2
- package/dist/filter/utils.d.ts.map +1 -1
- package/dist/filter/utils.js +8 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -7
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +10 -10
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +50 -46
- package/dist/migration/index-where-predicate.d.ts.map +1 -1
- package/dist/migration/index-where-predicate.js +22 -8
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +1 -1
- package/dist/migration/migrator.d.ts +61 -36
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +276 -167
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/postgresql-schema-reader.js +51 -36
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/migration/slack-confirm.js +1 -1
- package/dist/migration/types.d.ts +54 -0
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/naite/naite-reporter.js +2 -2
- package/dist/naite/naite.d.ts +74 -15
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +5 -19
- package/dist/runtime-type.d.ts +6 -0
- package/dist/runtime-type.d.ts.map +1 -0
- package/dist/runtime-type.js +26 -0
- package/dist/ssr/hmr-opt-out.d.ts +26 -0
- package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
- package/dist/ssr/hmr-opt-out.js +59 -0
- package/dist/ssr/renderer.d.ts.map +1 -1
- package/dist/ssr/renderer.js +4 -1
- package/dist/storage/base-file.js +14 -14
- package/dist/storage/buffered-file.d.ts +2 -2
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.js +12 -12
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/s3-driver.js +1 -1
- package/dist/storage/uploaded-file.d.ts +2 -2
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/storage/uploaded-file.js +8 -8
- package/dist/stream/sse.js +11 -11
- package/dist/stream/ws-core.d.ts +1 -1
- package/dist/stream/ws-core.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts +1 -1
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-delivery.js +6 -4
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.js +4 -2
- package/dist/stream/ws-presence-store.js +1 -1
- package/dist/stream/ws-registry.d.ts +4 -4
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-registry.js +4 -2
- package/dist/stream/ws-telemetry.d.ts +16 -12
- package/dist/stream/ws-telemetry.d.ts.map +1 -1
- package/dist/stream/ws-telemetry.js +22 -18
- package/dist/stream/ws.d.ts +18 -12
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/stream/ws.js +26 -22
- package/dist/syncer/api-parser.js +1 -1
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +7 -8
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +13 -14
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +5 -6
- package/dist/syncer/file-copy.d.ts +5 -0
- package/dist/syncer/file-copy.d.ts.map +1 -0
- package/dist/syncer/file-copy.js +36 -0
- package/dist/syncer/file-patterns.d.ts +1 -0
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +5 -2
- package/dist/syncer/file-tracking.d.ts.map +1 -1
- package/dist/syncer/file-tracking.js +5 -4
- package/dist/syncer/filesystem-dependencies.d.ts +15 -0
- package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
- package/dist/syncer/filesystem-dependencies.js +53 -0
- package/dist/syncer/module-loader.d.ts +1 -1
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +6 -4
- package/dist/syncer/syncer-actions.d.ts +4 -0
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +34 -17
- package/dist/syncer/syncer.d.ts +17 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +71 -29
- package/dist/syncer/watcher.d.ts.map +1 -1
- package/dist/syncer/watcher.js +3 -3
- package/dist/tasks/decorator.d.ts +6 -6
- package/dist/tasks/decorator.d.ts.map +1 -1
- package/dist/tasks/decorator.js +4 -4
- package/dist/tasks/step-wrapper.d.ts +6 -4
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.js +5 -5
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +13 -7
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +2 -2
- package/dist/template/helpers.d.ts +8 -6
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +1 -1
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +4 -4
- package/dist/template/implementations/generated_http.template.d.ts +7 -4
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +21 -21
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +6 -3
- package/dist/template/implementations/http_validators.template.d.ts +18 -0
- package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
- package/dist/template/implementations/http_validators.template.js +127 -0
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +1 -1
- package/dist/template/implementations/queries.template.js +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +79 -39
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +6 -4
- package/dist/template/implementations/view_form.template.d.ts +6 -1
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +23 -15
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +11 -6
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template-manager.js +9 -7
- package/dist/template/template-types.d.ts +12 -5
- package/dist/template/template-types.d.ts.map +1 -1
- package/dist/template/template-types.js +1 -1
- package/dist/template/template.d.ts +2 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +6 -4
- package/dist/template/zod-converter.d.ts +0 -19
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +100 -84
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +2 -1
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +9 -6
- package/dist/testing/data-explorer.d.ts +32 -7
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +77 -31
- package/dist/testing/dev-test-routes.d.ts +8 -1
- package/dist/testing/dev-test-routes.d.ts.map +1 -1
- package/dist/testing/dev-test-routes.js +125 -108
- package/dist/testing/dev-vitest-manager.d.ts +54 -8
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.js +24 -9
- package/dist/testing/faker-mappings.d.ts +412 -1
- package/dist/testing/faker-mappings.d.ts.map +1 -1
- package/dist/testing/faker-mappings.js +1 -1
- package/dist/testing/filesystem.d.ts +2 -0
- package/dist/testing/filesystem.d.ts.map +1 -0
- package/dist/testing/filesystem.js +7 -0
- package/dist/testing/fixture-generator.d.ts +25 -8
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +132 -73
- package/dist/testing/fixture-loader.d.ts +3 -1
- package/dist/testing/fixture-loader.d.ts.map +1 -1
- package/dist/testing/fixture-loader.js +1 -20
- package/dist/testing/fixture-manager.d.ts +8 -7
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +91 -59
- package/dist/testing/global-setup.d.ts.map +1 -1
- package/dist/testing/global-setup.js +5 -2
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +6 -3
- package/dist/types/types.d.ts +101 -99
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +234 -225
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +1 -1
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +28 -18
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +146 -210
- package/dist/ui/async-route.d.ts +3 -0
- package/dist/ui/async-route.d.ts.map +1 -0
- package/dist/ui/async-route.js +12 -0
- package/dist/ui/cdd-service.d.ts +9 -7
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +7 -5
- package/dist/ui/migrations-api.d.ts +3 -0
- package/dist/ui/migrations-api.d.ts.map +1 -0
- package/dist/ui/migrations-api.js +215 -0
- package/dist/ui-web/assets/index-D3QNH-Dv.css +1 -0
- package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
- package/dist/ui-web/index.html +2 -2
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +7 -5
- package/dist/utils/fs-utils.d.ts +3 -3
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +6 -6
- package/dist/utils/model.d.ts +3 -5
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +1 -1
- package/dist/utils/object-utils.d.ts +1 -1
- package/dist/utils/object-utils.d.ts.map +1 -1
- package/dist/utils/object-utils.js +17 -16
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +4 -2
- package/dist/utils/runtime-value.d.ts +13 -0
- package/dist/utils/runtime-value.d.ts.map +1 -0
- package/dist/utils/runtime-value.js +40 -0
- package/dist/utils/sql-parser.d.ts +8 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +6 -3
- package/dist/utils/type-utils.d.ts.map +1 -1
- package/dist/utils/type-utils.js +10 -8
- package/dist/utils/utils.d.ts +2 -2
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +11 -8
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +7 -4
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/chunking.js +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +1 -1
- package/dist/vector/types.d.ts +3 -2
- package/dist/vector/types.d.ts.map +1 -1
- package/package.json +11 -7
- package/src/ai/agents/agent.ts +5 -5
- package/src/ai/agents/types.ts +1 -1
- package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
- package/src/ai/providers/rtzr/error.ts +5 -3
- package/src/ai/providers/rtzr/model.ts +3 -2
- package/src/ai/providers/rtzr/options.ts +10 -5
- package/src/ai/providers/rtzr/provider.ts +10 -10
- package/src/ai/providers/rtzr/utils.ts +3 -1
- package/src/api/__tests__/config.test.ts +11 -21
- package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
- package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
- package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
- package/src/api/caster.ts +6 -8
- package/src/api/code-converters.ts +136 -36
- package/src/api/config.ts +62 -4
- package/src/api/context.ts +3 -3
- package/src/api/decorators.ts +28 -17
- package/src/api/http-validator.ts +149 -0
- package/src/api/sonamu.ts +459 -152
- package/src/api/websocket-helpers.ts +24 -17
- package/src/auth/audit-log/builders.ts +3 -2
- package/src/auth/audit-log/client-ip.ts +4 -2
- package/src/auth/audit-log/events.ts +15 -1
- package/src/auth/audit-log/plugin.ts +129 -200
- package/src/auth/audit-log-ingestor.ts +19 -15
- package/src/auth/auth-generator.ts +10 -5
- package/src/auth/better-auth-request.ts +4 -3
- package/src/auth/knex-adapter.ts +8 -2
- package/src/auth/plugins/entity-definitions/index.ts +6 -5
- package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
- package/src/bin/__tests__/test-command.test.ts +9 -15
- package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
- package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
- package/src/bin/build-config.ts +167 -0
- package/src/bin/cli.ts +155 -38
- package/src/bin/compiler-policy.ts +35 -0
- package/src/bin/fixture.ts +14 -3
- package/src/bin/test-command.ts +74 -29
- package/src/bin/ts-loader-registration.ts +22 -4
- package/src/cache/decorator.ts +10 -3
- package/src/compress/compress.ts +17 -4
- package/src/cone/cone-generator.ts +34 -6
- package/src/database/__tests__/db.test.ts +1 -0
- package/src/database/__tests__/puri.test.ts +16 -15
- package/src/database/__tests__/transaction-scope.test.ts +5 -0
- package/src/database/_batch_update.ts +1 -0
- package/src/database/base-model.ts +81 -50
- package/src/database/base-model.types.ts +6 -6
- package/src/database/db.ts +29 -19
- package/src/database/knex.ts +30 -17
- package/src/database/puri-subset.test-d.ts +17 -0
- package/src/database/puri.ts +181 -143
- package/src/database/puri.types.test-d.ts +31 -1
- package/src/database/puri.types.ts +23 -21
- package/src/database/upsert-builder.ts +75 -53
- package/src/dict/sd.ts +15 -5
- package/src/dict/sonamu-dictionary.ts +6 -6
- package/src/dict/utils.ts +9 -1
- package/src/entity/entity-manager.ts +26 -9
- package/src/entity/entity-template-cone.ts +5 -10
- package/src/entity/entity.ts +50 -34
- package/src/env.ts +7 -3
- package/src/exceptions/error-handler.ts +17 -2
- package/src/exceptions/so-exceptions.ts +26 -20
- package/src/filter/utils.ts +21 -11
- package/src/index.ts +3 -0
- package/src/logger/configure.ts +26 -18
- package/src/migration/__tests__/migrator.test.ts +50 -57
- package/src/migration/code-generation.ts +132 -104
- package/src/migration/index-where-predicate.ts +51 -24
- package/src/migration/migration-set.ts +11 -5
- package/src/migration/migrator.ts +392 -244
- package/src/migration/postgresql-schema-reader.ts +52 -47
- package/src/migration/slack-confirm.ts +17 -15
- package/src/migration/types.ts +57 -0
- package/src/naite/naite-reporter.ts +1 -1
- package/src/naite/naite.ts +97 -24
- package/src/runtime-type.ts +34 -0
- package/src/ssr/hmr-opt-out.ts +78 -0
- package/src/ssr/renderer.ts +6 -0
- package/src/storage/base-file.ts +13 -13
- package/src/storage/buffered-file.ts +11 -11
- package/src/storage/s3-driver.ts +4 -1
- package/src/storage/uploaded-file.ts +8 -8
- package/src/stream/__tests__/ws-contracts.test.ts +4 -2
- package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
- package/src/stream/__tests__/ws.test.ts +30 -6
- package/src/stream/sse.ts +12 -11
- package/src/stream/ws-core.ts +1 -1
- package/src/stream/ws-delivery.ts +16 -7
- package/src/stream/ws-local-connection-store.ts +2 -3
- package/src/stream/ws-presence-store.ts +6 -1
- package/src/stream/ws-registry.ts +16 -7
- package/src/stream/ws-telemetry.ts +66 -43
- package/src/stream/ws.ts +73 -39
- package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
- package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
- package/src/syncer/api-parser.ts +67 -27
- package/src/syncer/checksum.ts +17 -11
- package/src/syncer/code-generator.ts +25 -17
- package/src/syncer/entity-operations.ts +3 -5
- package/src/syncer/file-copy.ts +46 -0
- package/src/syncer/file-patterns.ts +11 -8
- package/src/syncer/file-tracking.ts +3 -4
- package/src/syncer/filesystem-dependencies.ts +73 -0
- package/src/syncer/module-loader.ts +8 -4
- package/src/syncer/syncer-actions.ts +56 -18
- package/src/syncer/syncer.ts +116 -43
- package/src/syncer/watcher.ts +8 -4
- package/src/tasks/decorator.ts +20 -12
- package/src/tasks/step-wrapper.ts +19 -9
- package/src/tasks/workflow-manager.ts +15 -9
- package/src/template/__tests__/http_validators.template.test.ts +160 -0
- package/src/template/__tests__/services.template.mutation.test.ts +24 -23
- package/src/template/__tests__/services.template.websocket.test.ts +21 -25
- package/src/template/entity-converter.ts +5 -2
- package/src/template/helpers.ts +8 -9
- package/src/template/implementations/generated.template.ts +5 -4
- package/src/template/implementations/generated_http.template.ts +61 -15
- package/src/template/implementations/generated_sso.template.ts +15 -4
- package/src/template/implementations/http_validators.template.ts +175 -0
- package/src/template/implementations/model.template.ts +3 -1
- package/src/template/implementations/sd.template.ts +81 -41
- package/src/template/implementations/services.template.ts +2 -2
- package/src/template/implementations/view_form.template.ts +56 -39
- package/src/template/implementations/view_list.template.ts +31 -23
- package/src/template/template-manager.ts +15 -13
- package/src/template/template-types.ts +13 -5
- package/src/template/template.ts +4 -3
- package/src/template/zod-converter.ts +206 -91
- package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
- package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
- package/src/testing/_relation-graph.ts +4 -1
- package/src/testing/bootstrap.ts +12 -5
- package/src/testing/data-explorer.ts +102 -53
- package/src/testing/dev-test-routes.ts +87 -50
- package/src/testing/dev-vitest-manager.ts +88 -32
- package/src/testing/faker-mappings.ts +2 -2
- package/src/testing/filesystem.ts +1 -0
- package/src/testing/fixture-generator.ts +191 -131
- package/src/testing/fixture-loader.ts +5 -1
- package/src/testing/fixture-manager.ts +129 -90
- package/src/testing/global-setup.ts +7 -3
- package/src/testing/index.ts +5 -0
- package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
- package/src/types/types.ts +184 -158
- package/src/ui/ai-api.ts +9 -7
- package/src/ui/ai-client.ts +61 -56
- package/src/ui/api.ts +726 -770
- package/src/ui/async-route.ts +4 -0
- package/src/ui/cdd-service.ts +35 -12
- package/src/ui/migrations-api.ts +381 -0
- package/src/utils/formatter.ts +7 -3
- package/src/utils/fs-utils.ts +5 -5
- package/src/utils/model.ts +4 -5
- package/src/utils/object-utils.ts +32 -22
- package/src/utils/process-utils.ts +4 -1
- package/src/utils/runtime-value.ts +43 -0
- package/src/utils/sql-parser.ts +13 -6
- package/src/utils/type-utils.ts +9 -7
- package/src/utils/utils.ts +19 -21
- package/src/utils/zod-error.ts +4 -2
- package/src/vector/chunking.ts +6 -1
- package/src/vector/embedding.ts +2 -1
- package/src/vector/types.ts +4 -2
- package/tsdown.api.config.ts +5 -2
- package/dist/ui-web/assets/index-CJf8uJYf.js +0 -176
- package/dist/ui-web/assets/index-GMMIVGja.css +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { init_runtime_value, isObjectValue, isStringValue } from "../utils/runtime-value.js";
|
|
2
3
|
import { getSonamuEnvironment, init_env } from "../env.js";
|
|
3
4
|
import { createKnexInstance, init_knex } from "../database/knex.js";
|
|
4
5
|
import { DB, init_db } from "../database/db.js";
|
|
@@ -12,12 +13,16 @@ import { Naite, init_naite } from "../naite/naite.js";
|
|
|
12
13
|
import { PostgreSQLSchemaReader, init_postgresql_schema_reader } from "./postgresql-schema-reader.js";
|
|
13
14
|
import { generateAlterCode, generateCreateCode, init_code_generation } from "./code-generation.js";
|
|
14
15
|
import { getMigrationSetFromEntity, init_migration_set } from "./migration-set.js";
|
|
15
|
-
import {
|
|
16
|
+
import { SlackConfirm, init_slack_confirm } from "./slack-confirm.js";
|
|
17
|
+
import { group, unique } from "radashi";
|
|
16
18
|
import assert from "assert";
|
|
17
19
|
import path from "path";
|
|
18
20
|
import chalk from "chalk";
|
|
19
|
-
import { mkdir, readdir,
|
|
21
|
+
import { mkdir, readdir, writeFile } from "fs/promises";
|
|
20
22
|
//#region src/migration/migrator.ts
|
|
23
|
+
function padDatePart(number, size = 2) {
|
|
24
|
+
return number.toString().padStart(size, "0");
|
|
25
|
+
}
|
|
21
26
|
/**
|
|
22
27
|
* 주어진 Promise가 ms 안에 완료되지 않으면 onTimeout 에러로 reject한다.
|
|
23
28
|
* 원본 Promise 자체는 계속 진행되므로, 호출측에서 커넥션 정리(destroy)를 책임진다.
|
|
@@ -34,7 +39,7 @@ function withTimeout(promise, ms, onTimeout) {
|
|
|
34
39
|
});
|
|
35
40
|
});
|
|
36
41
|
}
|
|
37
|
-
var MIGRATION_CONN_TIMEOUT_MS, Migrator;
|
|
42
|
+
var MigrationTargetExecutionError, MIGRATION_CONN_TIMEOUT_MS, LOCAL_DB_HOSTS, Migrator;
|
|
38
43
|
var init_migrator = __esmMin((() => {
|
|
39
44
|
init_sonamu();
|
|
40
45
|
init_db();
|
|
@@ -46,34 +51,143 @@ var init_migrator = __esmMin((() => {
|
|
|
46
51
|
init_naite();
|
|
47
52
|
init_controller();
|
|
48
53
|
init_fs_utils();
|
|
54
|
+
init_runtime_value();
|
|
49
55
|
init_code_generation();
|
|
50
56
|
init_migration_set();
|
|
51
57
|
init_postgresql_schema_reader();
|
|
58
|
+
init_slack_confirm();
|
|
59
|
+
MigrationTargetExecutionError = class extends Error {
|
|
60
|
+
connKey;
|
|
61
|
+
constructor(connKey, cause) {
|
|
62
|
+
super(cause instanceof Error ? cause.message : String(cause));
|
|
63
|
+
this.connKey = connKey;
|
|
64
|
+
this.name = "MigrationTargetExecutionError";
|
|
65
|
+
}
|
|
66
|
+
};
|
|
52
67
|
MIGRATION_CONN_TIMEOUT_MS = 5e3;
|
|
68
|
+
LOCAL_DB_HOSTS = /* @__PURE__ */ new Set([
|
|
69
|
+
"localhost",
|
|
70
|
+
"127.0.0.1",
|
|
71
|
+
"0.0.0.0",
|
|
72
|
+
"::1"
|
|
73
|
+
]);
|
|
53
74
|
Migrator = class {
|
|
54
75
|
isMissingMigrationTableError(error) {
|
|
55
|
-
if (
|
|
76
|
+
if (!isObjectValue(error) || error === null) return false;
|
|
56
77
|
const maybePostgresError = error;
|
|
57
|
-
return maybePostgresError.code === "42P01" &&
|
|
78
|
+
return maybePostgresError.code === "42P01" && isStringValue(maybePostgresError.message) && maybePostgresError.message.includes("knex_migrations");
|
|
58
79
|
}
|
|
80
|
+
/** 현재 실행 환경에서 허용된 마이그레이션 대상 키를 반환합니다. */
|
|
59
81
|
getMigrationTargetKeys() {
|
|
60
82
|
const connKeys = Object.keys(Sonamu.dbConfig).filter((key) => !key.endsWith("_readonly"));
|
|
61
83
|
if (isLocal()) return connKeys;
|
|
62
84
|
const environment = getSonamuEnvironment();
|
|
63
85
|
return connKeys.filter((key) => key === environment);
|
|
64
86
|
}
|
|
65
|
-
async runMigrationsSequentially(conns, action) {
|
|
87
|
+
async runMigrationsSequentially(conns, action, options) {
|
|
66
88
|
const results = [];
|
|
67
89
|
for (const { connKey, knex } of conns) {
|
|
68
|
-
const
|
|
90
|
+
const progress = this.createProgressHooks(action, connKey, options);
|
|
91
|
+
let migrationResult;
|
|
92
|
+
try {
|
|
93
|
+
migrationResult = action === "apply" ? await knex.migrate.latest(progress) : await knex.migrate.rollback(progress);
|
|
94
|
+
} catch (caught) {
|
|
95
|
+
throw new MigrationTargetExecutionError(connKey, caught);
|
|
96
|
+
}
|
|
97
|
+
const [batchNo, applied] = migrationResult;
|
|
69
98
|
results.push({
|
|
70
99
|
connKey,
|
|
71
100
|
batchNo,
|
|
72
101
|
applied
|
|
73
102
|
});
|
|
103
|
+
this.emitProgress(options, {
|
|
104
|
+
type: "target-complete",
|
|
105
|
+
action,
|
|
106
|
+
connKey,
|
|
107
|
+
batchNo,
|
|
108
|
+
files: applied
|
|
109
|
+
});
|
|
74
110
|
}
|
|
75
111
|
return results;
|
|
76
112
|
}
|
|
113
|
+
migrationName(migration) {
|
|
114
|
+
if (isStringValue(migration)) return path.basename(migration);
|
|
115
|
+
if (isObjectValue(migration) && migration !== null) {
|
|
116
|
+
const candidate = migration;
|
|
117
|
+
if (isStringValue(candidate.file)) return path.basename(candidate.file);
|
|
118
|
+
if (isStringValue(candidate.name)) return path.basename(candidate.name);
|
|
119
|
+
}
|
|
120
|
+
return String(migration);
|
|
121
|
+
}
|
|
122
|
+
emitProgress(options, event) {
|
|
123
|
+
try {
|
|
124
|
+
options?.onProgress?.(event);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn("Migration progress observer failed:", error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
createProgressHooks(action, connKey, options) {
|
|
130
|
+
let files = [];
|
|
131
|
+
const emitFile = (type, migration) => {
|
|
132
|
+
const file = this.migrationName(migration);
|
|
133
|
+
const index = Math.max(files.indexOf(file), 0);
|
|
134
|
+
this.emitProgress(options, {
|
|
135
|
+
type,
|
|
136
|
+
action,
|
|
137
|
+
connKey,
|
|
138
|
+
file,
|
|
139
|
+
index,
|
|
140
|
+
total: files.length
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
beforeAll: async (_knex, migrations) => {
|
|
145
|
+
files = migrations.map((migration) => this.migrationName(migration));
|
|
146
|
+
this.emitProgress(options, {
|
|
147
|
+
type: "target-start",
|
|
148
|
+
action,
|
|
149
|
+
connKey,
|
|
150
|
+
files
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
beforeEach: async (_knex, migrations) => {
|
|
154
|
+
migrations.forEach((migration) => emitFile("file-start", migration));
|
|
155
|
+
},
|
|
156
|
+
afterEach: async (_knex, migrations) => {
|
|
157
|
+
migrations.forEach((migration) => emitFile("file-executed", migration));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
assertMigrationTarget(connKey) {
|
|
162
|
+
if (!this.getMigrationTargetKeys().includes(connKey)) throw new Error(`Migration target is not allowed in NODE_ENV=${getSonamuEnvironment()}: ${String(connKey)}`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 마이그레이션 대상 커넥션의 정적 메타데이터를 반환합니다.
|
|
166
|
+
* DB에 연결하지 않으므로 CLI와 Web이 상태 조회 전에 즉시 사용할 수 있습니다.
|
|
167
|
+
*
|
|
168
|
+
* @category 분리형 마이그레이션 API
|
|
169
|
+
*/
|
|
170
|
+
getConnections() {
|
|
171
|
+
const slackConfirm = new SlackConfirm();
|
|
172
|
+
return this.getMigrationTargetKeys().map((connKey) => {
|
|
173
|
+
const connection = Sonamu.dbConfig[connKey].connection;
|
|
174
|
+
const host = connection.host ?? "localhost";
|
|
175
|
+
return {
|
|
176
|
+
connKey,
|
|
177
|
+
name: String(connKey),
|
|
178
|
+
host,
|
|
179
|
+
port: connection.port ?? 5432,
|
|
180
|
+
database: connection.database ?? "",
|
|
181
|
+
remote: !LOCAL_DB_HOSTS.has(host.toLowerCase()),
|
|
182
|
+
requiresApproval: slackConfirm.isTargetRequiresApproval(connKey)
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 소스에 존재하는 마이그레이션 파일 목록을 반환합니다.
|
|
188
|
+
*
|
|
189
|
+
* @category 분리형 마이그레이션 API
|
|
190
|
+
*/
|
|
77
191
|
async getMigrationCodes() {
|
|
78
192
|
const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations");
|
|
79
193
|
if (!await exists(srcMigrationsDir)) await mkdir(srcMigrationsDir, { recursive: true });
|
|
@@ -85,127 +199,156 @@ var init_migrator = __esmMin((() => {
|
|
|
85
199
|
return codes;
|
|
86
200
|
}
|
|
87
201
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* 필요하다면 적용할 수 있는 코드를 생성까지 해옵니다.
|
|
202
|
+
* 커넥션 하나의 현재 버전과 pending 목록을 독립적으로 조회합니다.
|
|
203
|
+
* 여러 대상은 호출자가 병렬로 조립할 수 있습니다.
|
|
91
204
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @returns
|
|
205
|
+
* @category 분리형 마이그레이션 API
|
|
95
206
|
*/
|
|
96
|
-
async
|
|
207
|
+
async getConnectionStatus(connKey) {
|
|
208
|
+
this.assertMigrationTarget(connKey);
|
|
209
|
+
const startedAt = performance.now();
|
|
97
210
|
const codes = await this.getMigrationCodes();
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
min: 0,
|
|
113
|
-
acquireTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
|
|
114
|
-
createTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
|
|
115
|
-
propagateCreateError: true
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
const connString = `pg://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`;
|
|
119
|
-
try {
|
|
120
|
-
try {
|
|
121
|
-
await withTimeout(tConn.raw("select 1"), MIGRATION_CONN_TIMEOUT_MS, () => /* @__PURE__ */ new Error(`DB 연결 시간 초과 (${MIGRATION_CONN_TIMEOUT_MS}ms) — ${connection.host}:${connection.port}/${connection.database}`));
|
|
122
|
-
} catch (err) {
|
|
123
|
-
console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스에 연결할 수 없습니다.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
|
|
124
|
-
migrationStatusError = err instanceof Error ? err.message : String(err);
|
|
125
|
-
return {
|
|
126
|
-
name: connKey,
|
|
127
|
-
connKey,
|
|
128
|
-
connString,
|
|
129
|
-
currentVersion: "error",
|
|
130
|
-
status: "error",
|
|
131
|
-
pending: []
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
const status = await (async () => {
|
|
135
|
-
try {
|
|
136
|
-
return await tConn.migrate.status();
|
|
137
|
-
} catch (err) {
|
|
138
|
-
if (this.isMissingMigrationTableError(err)) return codes.length;
|
|
139
|
-
console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
|
|
140
|
-
migrationStatusError = err instanceof Error ? err.message : String(err);
|
|
141
|
-
return "error";
|
|
142
|
-
}
|
|
143
|
-
})();
|
|
144
|
-
const pending = await (async () => {
|
|
145
|
-
try {
|
|
146
|
-
const [, fdList] = await tConn.migrate.list();
|
|
147
|
-
return fdList.map((fd) => fd.file.replace(".ts", ""));
|
|
148
|
-
} catch (err) {
|
|
149
|
-
if (this.isMissingMigrationTableError(err)) return codes.map((code) => code.name);
|
|
150
|
-
migrationStatusError = err instanceof Error ? err.message : String(err);
|
|
151
|
-
return [];
|
|
152
|
-
}
|
|
153
|
-
})();
|
|
154
|
-
const currentVersion = await (async () => {
|
|
155
|
-
try {
|
|
156
|
-
return await tConn.migrate.currentVersion();
|
|
157
|
-
} catch (_err) {
|
|
158
|
-
if (this.isMissingMigrationTableError(_err)) return "none";
|
|
159
|
-
migrationStatusError = _err instanceof Error ? _err.message : String(_err);
|
|
160
|
-
return "error";
|
|
161
|
-
}
|
|
162
|
-
})();
|
|
163
|
-
Naite.t("migrator:getStatus:status", status);
|
|
164
|
-
return {
|
|
165
|
-
name: connKey,
|
|
166
|
-
connKey,
|
|
167
|
-
connString,
|
|
168
|
-
currentVersion,
|
|
169
|
-
status,
|
|
170
|
-
pending
|
|
171
|
-
};
|
|
172
|
-
} finally {
|
|
173
|
-
await withTimeout(tConn.destroy(), MIGRATION_CONN_TIMEOUT_MS, () => /* @__PURE__ */ new Error("connection destroy timeout")).catch(() => {});
|
|
211
|
+
const knexOptions = Sonamu.dbConfig[connKey];
|
|
212
|
+
const connection = knexOptions.connection;
|
|
213
|
+
const tConn = createKnexInstance({
|
|
214
|
+
...knexOptions,
|
|
215
|
+
connection: {
|
|
216
|
+
...connection,
|
|
217
|
+
connectionTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS
|
|
218
|
+
},
|
|
219
|
+
pool: {
|
|
220
|
+
...knexOptions.pool,
|
|
221
|
+
min: 0,
|
|
222
|
+
acquireTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
|
|
223
|
+
createTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
|
|
224
|
+
propagateCreateError: true
|
|
174
225
|
}
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
226
|
+
});
|
|
227
|
+
try {
|
|
228
|
+
await withTimeout(tConn.raw("select 1"), MIGRATION_CONN_TIMEOUT_MS, () => {
|
|
229
|
+
return /* @__PURE__ */ new Error(`DB 연결 시간 초과 (${MIGRATION_CONN_TIMEOUT_MS}ms) — ${connection.host}:${connection.port}/${connection.database}`);
|
|
230
|
+
});
|
|
231
|
+
let error;
|
|
232
|
+
const status = await tConn.migrate.status().catch((caught) => {
|
|
233
|
+
if (this.isMissingMigrationTableError(caught)) return codes.length;
|
|
234
|
+
error = caught instanceof Error ? caught.message : String(caught);
|
|
235
|
+
return "error";
|
|
236
|
+
});
|
|
237
|
+
const pending = await tConn.migrate.list().then(([, files]) => files.map(({ file }) => file.replace(/\.ts$/, "")), (cause) => {
|
|
238
|
+
if (this.isMissingMigrationTableError(cause)) return codes.map(({ name }) => name);
|
|
239
|
+
error ??= cause instanceof Error ? cause.message : String(cause);
|
|
181
240
|
return [];
|
|
182
|
-
}
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
241
|
+
});
|
|
242
|
+
const currentVersion = await tConn.migrate.currentVersion().catch((cause) => {
|
|
243
|
+
if (this.isMissingMigrationTableError(cause)) return "none";
|
|
244
|
+
error ??= cause instanceof Error ? cause.message : String(cause);
|
|
245
|
+
return "error";
|
|
246
|
+
});
|
|
247
|
+
Naite.t("migrator:getStatus:status", status);
|
|
248
|
+
const connectionStatus = {
|
|
249
|
+
connKey,
|
|
250
|
+
currentVersion,
|
|
251
|
+
status,
|
|
252
|
+
pending,
|
|
253
|
+
latencyMs: performance.now() - startedAt
|
|
254
|
+
};
|
|
255
|
+
if (error !== void 0) connectionStatus.error = error;
|
|
256
|
+
return connectionStatus;
|
|
257
|
+
} catch (caught) {
|
|
258
|
+
const error = caught instanceof Error ? caught.message : String(caught);
|
|
259
|
+
console.warn(chalk.yellow(`${String(connKey)}의 마이그레이션 상태를 가져오는 데에 실패하였습니다.\n${error}`));
|
|
260
|
+
return {
|
|
261
|
+
connKey,
|
|
262
|
+
currentVersion: "error",
|
|
263
|
+
status: "error",
|
|
264
|
+
pending: [],
|
|
265
|
+
latencyMs: performance.now() - startedAt,
|
|
266
|
+
error
|
|
267
|
+
};
|
|
268
|
+
} finally {
|
|
269
|
+
await withTimeout(tConn.destroy(), MIGRATION_CONN_TIMEOUT_MS, () => {
|
|
270
|
+
return /* @__PURE__ */ new Error("connection destroy timeout");
|
|
271
|
+
}).catch(() => {});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* 최신 상태인 기준 DB와 엔티티 정의를 비교해 생성 예정 코드를 반환합니다.
|
|
276
|
+
*
|
|
277
|
+
* @category 분리형 마이그레이션 API
|
|
278
|
+
*/
|
|
279
|
+
async getPreparedCodes(compareConnKey) {
|
|
280
|
+
const status = await this.getConnectionStatus(compareConnKey);
|
|
281
|
+
if (status.status !== 0 || status.error !== void 0) throw new Error(`Migration comparison requires an up-to-date database: ${String(compareConnKey)}`);
|
|
282
|
+
return this.compareWithConnection(compareConnKey);
|
|
283
|
+
}
|
|
284
|
+
async compareWithConnection(compareConnKey) {
|
|
285
|
+
const compareDB = createKnexInstance(Sonamu.dbConfig[compareConnKey]);
|
|
286
|
+
try {
|
|
287
|
+
return await this.compareMigrations(compareDB);
|
|
288
|
+
} finally {
|
|
289
|
+
await compareDB.destroy();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* @deprecated 신규 UI에서는 커넥션별 조회 API를 사용합니다.
|
|
294
|
+
* 기존 CLI와 스크립트 호환을 위해 전체 상태를 조립합니다.
|
|
295
|
+
* @category 호환용 마이그레이션 API
|
|
296
|
+
*/
|
|
297
|
+
async getStatus() {
|
|
298
|
+
const [codes, connections] = await Promise.all([this.getMigrationCodes(), Promise.resolve(this.getConnections())]);
|
|
299
|
+
Naite.t("migrator:getStatus:codes", codes);
|
|
300
|
+
const connectionStatuses = await Promise.all(connections.map(({ connKey }) => this.getConnectionStatus(connKey)));
|
|
301
|
+
const conns = connections.map((connection, index) => {
|
|
302
|
+
const status = connectionStatuses[index];
|
|
303
|
+
assert(status !== void 0);
|
|
304
|
+
const configured = Sonamu.dbConfig[connection.connKey].connection;
|
|
305
|
+
return {
|
|
306
|
+
name: connection.name,
|
|
307
|
+
connKey: connection.connKey,
|
|
308
|
+
connString: `pg://${configured.user ?? ""}@${configured.host}:${configured.port}/${configured.database}`,
|
|
309
|
+
currentVersion: status.currentVersion,
|
|
310
|
+
status: status.status,
|
|
311
|
+
pending: status.pending
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
Naite.t("migrator:getStatus:conns", conns);
|
|
315
|
+
const compareConn = connectionStatuses.find(({ status, error }) => status === 0 && error === void 0);
|
|
316
|
+
const preparedCodes = compareConn === void 0 ? [] : await this.compareWithConnection(compareConn.connKey);
|
|
190
317
|
Naite.t("migrator:getStatus:preparedCodes", preparedCodes);
|
|
191
318
|
return {
|
|
192
|
-
conns
|
|
319
|
+
conns,
|
|
193
320
|
codes,
|
|
194
321
|
preparedCodes,
|
|
195
|
-
error:
|
|
322
|
+
error: connectionStatuses.find(({ error }) => error !== void 0)?.error
|
|
196
323
|
};
|
|
197
324
|
}
|
|
198
325
|
/**
|
|
199
|
-
* 마이그레이션을
|
|
200
|
-
*
|
|
326
|
+
* 대상 DB에 pending 마이그레이션을 적용합니다.
|
|
327
|
+
* CLI와 Web은 같은 메서드를 사용하며, Web은 `onProgress`를 stream으로 변환합니다.
|
|
201
328
|
*
|
|
202
|
-
*
|
|
329
|
+
* @category 분리형 마이그레이션 API
|
|
330
|
+
*/
|
|
331
|
+
async apply(targets, options) {
|
|
332
|
+
return this.runActionWithProgress("apply", targets, options);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* 대상 DB에서 가장 최근 migration batch를 롤백합니다.
|
|
336
|
+
* CLI와 Web은 같은 메서드를 사용하며, Web은 `onProgress`를 stream으로 변환합니다.
|
|
203
337
|
*
|
|
204
|
-
* @
|
|
205
|
-
|
|
206
|
-
|
|
338
|
+
* @category 분리형 마이그레이션 API
|
|
339
|
+
*/
|
|
340
|
+
async rollback(targets, options) {
|
|
341
|
+
return this.runActionWithProgress("rollback", targets, options);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* @deprecated action 문자열 대신 {@link apply} 또는 {@link rollback}을 직접 사용합니다.
|
|
345
|
+
* 기존 외부 호출의 하위 호환만을 위해 유지합니다.
|
|
346
|
+
* @category 호환용 마이그레이션 API
|
|
207
347
|
*/
|
|
208
348
|
async runAction(action, targets) {
|
|
349
|
+
return action === "apply" ? this.apply(targets) : this.rollback(targets);
|
|
350
|
+
}
|
|
351
|
+
async runActionWithProgress(action, targets, options) {
|
|
209
352
|
Naite.t("migrator:runAction:action", action);
|
|
210
353
|
Naite.t("migrator:runAction:targets", targets);
|
|
211
354
|
const allowedTargets = new Set(this.getMigrationTargetKeys());
|
|
@@ -214,18 +357,13 @@ var init_migrator = __esmMin((() => {
|
|
|
214
357
|
const configs = unique(targets.map((target) => ({
|
|
215
358
|
connKey: target,
|
|
216
359
|
options: Sonamu.dbConfig[target]
|
|
217
|
-
})).filter((c) => c.options !== void 0), ({ options }) => `${
|
|
360
|
+
})).filter((c) => c.options !== void 0), ({ options: dbOptions }) => `${dbOptions.connection.host}:${dbOptions.connection.port ?? 5432}/${dbOptions.connection.database}`);
|
|
218
361
|
const conns = await Promise.all(configs.map(async (config) => ({
|
|
219
362
|
connKey: config.connKey,
|
|
220
363
|
knex: createKnexInstance(config.options)
|
|
221
364
|
})));
|
|
222
365
|
try {
|
|
223
|
-
const result = await (
|
|
224
|
-
switch (action) {
|
|
225
|
-
case "apply": return this.runMigrationsSequentially(conns, "apply");
|
|
226
|
-
case "rollback": return this.runMigrationsSequentially(conns, "rollback");
|
|
227
|
-
}
|
|
228
|
-
})();
|
|
366
|
+
const result = await this.runMigrationsSequentially(conns, action, options);
|
|
229
367
|
Naite.t("migrator:runAction:result", result);
|
|
230
368
|
return result;
|
|
231
369
|
} finally {
|
|
@@ -234,45 +372,9 @@ var init_migrator = __esmMin((() => {
|
|
|
234
372
|
}));
|
|
235
373
|
}
|
|
236
374
|
}
|
|
237
|
-
/**
|
|
238
|
-
* 삭제 가능한 마이그레이션 코드 파일을 검증합니다.
|
|
239
|
-
*
|
|
240
|
-
* @param conns 마이그레이션 상태 배열
|
|
241
|
-
* @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
|
|
242
|
-
* @returns 삭제 가능 여부 및 적용된 마이그레이션 코드 파일 이름
|
|
243
|
-
*/
|
|
244
|
-
validateDeletable(conns, codeNames) {
|
|
245
|
-
const appliedCodes = codeNames.filter((codeName) => conns.some((conn) => !conn.pending.includes(codeName)));
|
|
246
|
-
return {
|
|
247
|
-
canDelete: appliedCodes.length === 0,
|
|
248
|
-
appliedCodes
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* 마이그레이션 코드 파일을 삭제합니다.
|
|
253
|
-
*
|
|
254
|
-
* Sonamu UI에서 사용됩니다.
|
|
255
|
-
*
|
|
256
|
-
* @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
|
|
257
|
-
* @returns 삭제된 마이그레이션 코드 파일 개수
|
|
258
|
-
*/
|
|
259
|
-
async delCodes(codeNames) {
|
|
260
|
-
const { conns } = await this.getStatus();
|
|
261
|
-
const { canDelete, appliedCodes } = this.validateDeletable(conns, codeNames);
|
|
262
|
-
if (!canDelete) throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
|
|
263
|
-
return sum(await Promise.all(codeNames.map(async (codeName) => {
|
|
264
|
-
const filePath = `${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`;
|
|
265
|
-
if (await exists(filePath)) {
|
|
266
|
-
await unlink(filePath);
|
|
267
|
-
return 1;
|
|
268
|
-
}
|
|
269
|
-
return 0;
|
|
270
|
-
})));
|
|
271
|
-
}
|
|
272
375
|
genDateTag(index, baseDate = /* @__PURE__ */ new Date()) {
|
|
273
376
|
const date = new Date(baseDate.getTime() + index * 1e3);
|
|
274
|
-
|
|
275
|
-
return date.getFullYear().toString() + pad(date.getMonth() + 1) + pad(date.getDate()) + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
|
|
377
|
+
return date.getFullYear().toString() + padDatePart(date.getMonth() + 1) + padDatePart(date.getDate()) + padDatePart(date.getHours()) + padDatePart(date.getMinutes()) + padDatePart(date.getSeconds());
|
|
276
378
|
}
|
|
277
379
|
/**
|
|
278
380
|
* 마이그레이션 코드 파일을 생성합니다.
|
|
@@ -281,8 +383,8 @@ var init_migrator = __esmMin((() => {
|
|
|
281
383
|
*
|
|
282
384
|
* @returns 생성된 마이그레이션 코드 파일 개수
|
|
283
385
|
*/
|
|
284
|
-
async generatePreparedCodes() {
|
|
285
|
-
const
|
|
386
|
+
async generatePreparedCodes(compareConnKey) {
|
|
387
|
+
const preparedCodes = compareConnKey === void 0 ? (await this.getStatus()).preparedCodes : await this.getPreparedCodes(compareConnKey);
|
|
286
388
|
Naite.t("migrator:generatePreparedCodes:preparedCodes", preparedCodes);
|
|
287
389
|
if (preparedCodes.length === 0) {
|
|
288
390
|
console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
|
|
@@ -328,13 +430,12 @@ var init_migrator = __esmMin((() => {
|
|
|
328
430
|
return codes;
|
|
329
431
|
}
|
|
330
432
|
/**
|
|
331
|
-
* Shadow DB
|
|
332
|
-
*
|
|
333
|
-
* Sonamu UI에서 사용됩니다.
|
|
433
|
+
* test DB의 snapshot으로 임시 Shadow DB를 만들고 전체 마이그레이션을 검증합니다.
|
|
434
|
+
* CLI와 Web은 `onProgress` 유무만 달리해 같은 실행 의미를 공유할 수 있습니다.
|
|
334
435
|
*
|
|
335
|
-
* @
|
|
436
|
+
* @category 분리형 마이그레이션 API
|
|
336
437
|
*/
|
|
337
|
-
async runShadowTest() {
|
|
438
|
+
async runShadowTest(options) {
|
|
338
439
|
const baseTestConn = Sonamu.dbConfig.test.connection;
|
|
339
440
|
const workerId = process.env.SONAMU_WORKER_DB === "true" ? process.env.VITEST_POOL_ID : null;
|
|
340
441
|
const templateDatabase = workerId !== null ? `${baseTestConn.database}_${workerId ?? "1"}` : baseTestConn.database;
|
|
@@ -373,11 +474,19 @@ var init_migrator = __esmMin((() => {
|
|
|
373
474
|
}
|
|
374
475
|
});
|
|
375
476
|
try {
|
|
376
|
-
const
|
|
477
|
+
const progress = this.createProgressHooks("shadow", "shadow", options);
|
|
478
|
+
const [batchNo, applied] = await sdb.migrate.latest(progress);
|
|
377
479
|
!isTest() && console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
|
|
378
480
|
batchNo,
|
|
379
481
|
applied
|
|
380
482
|
});
|
|
483
|
+
this.emitProgress(options, {
|
|
484
|
+
type: "target-complete",
|
|
485
|
+
action: "shadow",
|
|
486
|
+
connKey: "shadow",
|
|
487
|
+
batchNo,
|
|
488
|
+
files: applied
|
|
489
|
+
});
|
|
381
490
|
return [{
|
|
382
491
|
connKey: "shadow",
|
|
383
492
|
batchNo,
|
|
@@ -385,7 +494,7 @@ var init_migrator = __esmMin((() => {
|
|
|
385
494
|
}];
|
|
386
495
|
} catch (e) {
|
|
387
496
|
console.error(e);
|
|
388
|
-
throw new ServiceUnavailableException(SD("sonamu.error.shadowDbTestFailed"));
|
|
497
|
+
throw new MigrationTargetExecutionError("shadow", new ServiceUnavailableException(SD("sonamu.error.shadowDbTestFailed")));
|
|
389
498
|
} finally {
|
|
390
499
|
await sdb.destroy();
|
|
391
500
|
}
|
|
@@ -404,6 +513,6 @@ var init_migrator = __esmMin((() => {
|
|
|
404
513
|
}));
|
|
405
514
|
//#endregion
|
|
406
515
|
init_migrator();
|
|
407
|
-
export { Migrator, init_migrator };
|
|
516
|
+
export { MigrationTargetExecutionError, Migrator, init_migrator };
|
|
408
517
|
|
|
409
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZ3JhdGlvbi9taWdyYXRvci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCB1bmxpbmssIHdyaXRlRmlsZSB9IGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcblxuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHsgdHlwZSBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCB7IGdyb3VwLCBzdW0sIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5cbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGkvc29uYW11XCI7XG5pbXBvcnQgeyBEQiB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgdHlwZSBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgY3JlYXRlS25leEluc3RhbmNlIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2tuZXhcIjtcbmltcG9ydCB7IFNEIH0gZnJvbSBcIi4uL2RpY3Qvc2RcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBnZXRTb25hbXVFbnZpcm9ubWVudCB9IGZyb20gXCIuLi9lbnZcIjtcbmltcG9ydCB7IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbiB9IGZyb20gXCIuLi9leGNlcHRpb25zL3NvLWV4Y2VwdGlvbnNcIjtcbmltcG9ydCB7IE5haXRlIH0gZnJvbSBcIi4uL25haXRlL25haXRlXCI7XG5pbXBvcnQgeyB0eXBlIEdlbk1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc0xvY2FsLCBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHsgdHlwZSBDb25uU3RyaW5nLCB0eXBlIE1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU3RhdHVzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgTWlncmF0aW9uUmVzdWx0ID0ge1xuICBjb25uS2V5OiBzdHJpbmc7XG4gIGJhdGNoTm86IG51bWJlcjtcbiAgYXBwbGllZDogc3RyaW5nW107XG59W107XG5cbi8vIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg7KGw7ZqMIOyLnCBEQiDsl7DqsrAg7ZmV7J24IO2DgOyehOyVhOybgyhtcykuXG4vLyBjcmVhdGVLbmV4SW5zdGFuY2XsnZgg7Luk64Sl7IWYIO2ajeuTnSDtg4DsnoTslYTsm4MoMzDstIgp7JeQIHN0YXR1cy9saXN0L2N1cnJlbnRWZXJzaW9u7J20XG4vLyDqsIHqsIEg6rG466as66m0IENMSS9VSeqwgCDstZzrjIAg7IiY7IutIOy0iCBoYW5n7ZWc64ukLiDsoJXsg4Eg7J2R64u17J2AIOyImOuwsSBtc+ydtOuvgOuhnCA17LSI66m0IOy2qeu2hO2VmOuLpC5cbmNvbnN0IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMgPSA1MDAwO1xuXG4vKipcbiAqIOyjvOyWtOynhCBQcm9taXNl6rCAIG1zIOyViOyXkCDsmYTro4zrkJjsp4Ag7JWK7Jy866m0IG9uVGltZW91dCDsl5Drn6zroZwgcmVqZWN07ZWc64ukLlxuICog7JuQ67O4IFByb21pc2Ug7J6Q7LK064qUIOqzhOyGjSDsp4TtlonrkJjrr4DroZwsIO2YuOy2nOy4oeyXkOyEnCDsu6TrhKXshZgg7KCV66asKGRlc3Ryb3kp66W8IOyxheyehOynhOuLpC5cbiAqL1xuZnVuY3Rpb24gd2l0aFRpbWVvdXQ8VD4ocHJvbWlzZTogUHJvbWlzZTxUPiwgbXM6IG51bWJlciwgb25UaW1lb3V0OiAoKSA9PiBFcnJvcik6IFByb21pc2U8VD4ge1xuICByZXR1cm4gbmV3IFByb21pc2U8VD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiByZWplY3Qob25UaW1lb3V0KCkpLCBtcyk7XG4gICAgcHJvbWlzZS50aGVuKFxuICAgICAgKHZhbHVlKSA9PiB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgIHJlc29sdmUodmFsdWUpO1xuICAgICAgfSxcbiAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSxcbiAgICApO1xuICB9KTtcbn1cblxuZXhwb3J0IGNsYXNzIE1pZ3JhdG9yIHtcbiAgcHJpdmF0ZSBpc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gICAgaWYgKHR5cGVvZiBlcnJvciAhPT0gXCJvYmplY3RcIiB8fCBlcnJvciA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IG1heWJlUG9zdGdyZXNFcnJvciA9IGVycm9yIGFzIHsgY29kZT86IHVua25vd247IG1lc3NhZ2U/OiB1bmtub3duIH07XG4gICAgcmV0dXJuIChcbiAgICAgIG1heWJlUG9zdGdyZXNFcnJvci5jb2RlID09PSBcIjQyUDAxXCIgJiZcbiAgICAgIHR5cGVvZiBtYXliZVBvc3RncmVzRXJyb3IubWVzc2FnZSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgICAgbWF5YmVQb3N0Z3Jlc0Vycm9yLm1lc3NhZ2UuaW5jbHVkZXMoXCJrbmV4X21pZ3JhdGlvbnNcIilcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRNaWdyYXRpb25UYXJnZXRLZXlzKCk6IChrZXlvZiBTb25hbXVEQkNvbmZpZylbXSB7XG4gICAgY29uc3QgY29ubktleXMgPSBPYmplY3Qua2V5cyhTb25hbXUuZGJDb25maWcpLmZpbHRlcihcbiAgICAgIChrZXkpID0+ICFrZXkuZW5kc1dpdGgoXCJfcmVhZG9ubHlcIiksXG4gICAgKSBhcyAoa2V5b2YgU29uYW11REJDb25maWcpW107XG5cbiAgICBpZiAoaXNMb2NhbCgpKSB7XG4gICAgICByZXR1cm4gY29ubktleXM7XG4gICAgfVxuXG4gICAgY29uc3QgZW52aXJvbm1lbnQgPSBnZXRTb25hbXVFbnZpcm9ubWVudCgpO1xuICAgIHJldHVybiBjb25uS2V5cy5maWx0ZXIoKGtleSkgPT4ga2V5ID09PSBlbnZpcm9ubWVudCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoXG4gICAgY29ubnM6IHsgY29ubktleToga2V5b2YgU29uYW11REJDb25maWc7IGtuZXg6IEtuZXggfVtdLFxuICAgIGFjdGlvbjogXCJhcHBseVwiIHwgXCJyb2xsYmFja1wiLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IHJlc3VsdHM6IE1pZ3JhdGlvblJlc3VsdCA9IFtdO1xuXG4gICAgZm9yIChjb25zdCB7IGNvbm5LZXksIGtuZXggfSBvZiBjb25ucykge1xuICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID1cbiAgICAgICAgYWN0aW9uID09PSBcImFwcGx5XCIgPyBhd2FpdCBrbmV4Lm1pZ3JhdGUubGF0ZXN0KCkgOiBhd2FpdCBrbmV4Lm1pZ3JhdGUucm9sbGJhY2soKTtcblxuICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgY29ubktleSxcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgYXBwbGllZCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnRvU29ydGVkKChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRNaWdyYXRpb25Db2RlczpyZXN1bHRzXCIsIGNvZGVzKTtcbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICog7YOA6rKf67OEIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zsmYAg7L2U65OcIOyDneyEsS/spIDruYQg7IOB7YOc66W8IOq1rO2VtOyYteuLiOuLpC5cbiAgICog7Iuk7KCc66GcIERC7JeQIOygkeq3vOuPhCDtlZjqs6Ag66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzrj4Qg7ZmV7J247ZWY6rOgLFxuICAgKiDtlYTsmpTtlZjri6TrqbQg7KCB7Jqp7ZWgIOyImCDsnojripQg7L2U65Oc66W8IOyDneyEseq5jOyngCDtlbTsmLXri4jri6QuXG4gICAqXG4gICAqIENMSeyZgCBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgYXN5bmMgZ2V0U3RhdHVzKCk6IFByb21pc2U8TWlncmF0aW9uU3RhdHVzPiB7XG4gICAgY29uc3QgY29kZXMgPSBhd2FpdCB0aGlzLmdldE1pZ3JhdGlvbkNvZGVzKCk7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpjb2Rlc1wiLCBjb2Rlcyk7XG5cbiAgICBjb25zdCBjb25uS2V5cyA9IHRoaXMuZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpO1xuXG4gICAgbGV0IG1pZ3JhdGlvblN0YXR1c0Vycm9yOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBzdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29ubktleXMubWFwKGFzeW5jIChjb25uS2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IGtuZXhPcHRpb25zID0gU29uYW11LmRiQ29uZmlnW2Nvbm5LZXldO1xuICAgICAgICBjb25zdCBjb25uZWN0aW9uID0ga25leE9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgICAgLy8g7IOB7YOcIOyhsO2ajOyaqSDsu6TrhKXshZjsnYAgZmFpbC1mYXN066GcIOunjOuToOuLpDog67aI7Ya1IERC7JeQ7IScIOy7pOuEpeyFmCDtmo3rk53snYQg66y07ZWc7KCVXG4gICAgICAgIC8vIOyerOyLnOuPhO2VmOupsCBDTEkg7ZSE66Gc7IS47Iqk6rCAIOyiheujjOuQmOyngCDslYrripQg6rKD7J2EIOunieuKlOuLpC5cbiAgICAgICAgLy8gLSBjb25uZWN0aW9uVGltZW91dE1pbGxpczog7IaM7LyTIOyXsOqysCDsnpDssrTrpbwgNey0iCDslYjsl5Ag7Y+s6riwIOKGkiDshozsvJPsnbQg7KCV66as65CY7Ja0IO2UhOuhnOyEuOyKpOqwgCDsooXro4zrkKhcbiAgICAgICAgLy8gLSBwcm9wYWdhdGVDcmVhdGVFcnJvcjog7LKrIOyXsOqysCDsi6TtjKjrpbwg7KaJ7IucIOyghO2MjCjtkoAg7J6s7Iuc64+EIOyXhuydtCDrsJTroZwg7Iuk7YyoKVxuICAgICAgICBjb25zdCB0Q29ubiA9IGNyZWF0ZUtuZXhJbnN0YW5jZSh7XG4gICAgICAgICAgLi4ua25leE9wdGlvbnMsXG4gICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgLi4uKGNvbm5lY3Rpb24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLFxuICAgICAgICAgICAgY29ubmVjdGlvblRpbWVvdXRNaWxsaXM6IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwb29sOiB7XG4gICAgICAgICAgICAuLi5rbmV4T3B0aW9ucy5wb29sLFxuICAgICAgICAgICAgbWluOiAwLFxuICAgICAgICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLFxuICAgICAgICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IHRydWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGNvbm5TdHJpbmcgPVxuICAgICAgICAgIGBwZzovLyR7Y29ubmVjdGlvbi51c2VyID8/IFwiXCJ9QCR7Y29ubmVjdGlvbi5ob3N0fToke2Nvbm5lY3Rpb24ucG9ydH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIERCIOyXsOqysCDtmZXsnbg6IOu2iO2GtSBEQuyXkOyEnCBzdGF0dXMvbGlzdC9jdXJyZW50VmVyc2lvbuydtCDsu6TrhKXshZgg7ZqN65OdXG4gICAgICAgICAgLy8g7YOA7J6E7JWE7JuD6rmM7KeAIGhhbmftlZjripQg6rKD7J2EIOunieq4sCDsnITtlbQsIOuovOyggCA17LSIIOyViOyXkCDsnZHri7XtlZjripTsp4Ag7ZmV7J247ZWc64ukLlxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB3aXRoVGltZW91dChcbiAgICAgICAgICAgICAgdENvbm4ucmF3KFwic2VsZWN0IDFcIiksXG4gICAgICAgICAgICAgIE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgYERCIOyXsOqysCDsi5zqsIQg7LSI6rO8ICgke01JR1JBVElPTl9DT05OX1RJTUVPVVRfTVN9bXMpIOKAlCAke2Nvbm5lY3Rpb24uaG9zdH06JHtjb25uZWN0aW9uLnBvcnR9LyR7Y29ubmVjdGlvbi5kYXRhYmFzZX1gLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgICAgYCR7Y29ubktleX3snZgg66eI7J206re466CI7J207IWYIOyDge2DnOulvCDqsIDsoLjsmKTripQg642w7JeQIOyLpO2MqO2VmOyYgOyKteuLiOuLpC4g642w7J207YSw67Kg7J207Iqk7JeQIOyXsOqysO2VoCDsiJgg7JeG7Iq164uI64ukLlxcbuyLnOuPhO2VnCDsl7DqsrAg7ISk7KCVOlxcbiR7SlNPTi5zdHJpbmdpZnkoa25leE9wdGlvbnMuY29ubmVjdGlvbiwgbnVsbCwgMil9XFxu67Cc7IOd7ZWcIOyXkOufrDpcXG4ke2Vycn1cXG5gLFxuICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIG1pZ3JhdGlvblN0YXR1c0Vycm9yID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgbmFtZTogY29ubktleSxcbiAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgY29ublN0cmluZyxcbiAgICAgICAgICAgICAgY3VycmVudFZlcnNpb246IFwiZXJyb3JcIiBhcyBjb25zdCxcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCIgYXMgY29uc3QsXG4gICAgICAgICAgICAgIHBlbmRpbmc6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBzdGF0dXM6IG51bWJlciB8IFwiZXJyb3JcIiA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5zdGF0dXMoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGVycikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29kZXMubGVuZ3RoO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICAgIGAke2Nvbm5LZXl97J2YIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zrpbwg6rCA7KC47Jik64qUIOuNsOyXkCDsi6TtjKjtlZjsmIDsirXri4jri6QuIOuNsOydtO2EsOuyoOydtOyKpOqwgCDsmKzrsJTrpbTqsowg6rWs7ISx65CY7KeAIOyViuydgCDqsoMg6rCZ7Iq164uI64ukLiDtmZXsnbjtlZjsi5zqs6Ag64uk7IucIOyLnOuPhO2VtOyjvOyEuOyalC5cXG7si5zrj4TtlZwg7Jew6rKwIOyEpOyglTpcXG4ke0pTT04uc3RyaW5naWZ5KGtuZXhPcHRpb25zLmNvbm5lY3Rpb24sIG51bGwsIDIpfVxcbuuwnOyDne2VnCDsl5Drn6w6XFxuJHtlcnJ9XFxuYCxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFwiZXJyb3JcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICAgIGNvbnN0IHBlbmRpbmc6IHN0cmluZ1tdID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IFssIGZkTGlzdF0gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKTtcbiAgICAgICAgICAgICAgcmV0dXJuIGZkTGlzdC5tYXAoKGZkOiB7IGZpbGU6IHN0cmluZyB9KSA9PiBmZC5maWxlLnJlcGxhY2UoXCIudHNcIiwgXCJcIikpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLmlzTWlzc2luZ01pZ3JhdGlvblRhYmxlRXJyb3IoZXJyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjb2Rlcy5tYXAoKGNvZGUpID0+IGNvZGUubmFtZSk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb246IHN0cmluZyB8IFwiZXJyb3JcIiA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5jdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgICAgfSBjYXRjaCAoX2Vycikge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKF9lcnIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwibm9uZVwiO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBfZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBfZXJyLm1lc3NhZ2UgOiBTdHJpbmcoX2Vycik7XG4gICAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKTtcbiAgICAgICAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnN0YXR1c1wiLCBzdGF0dXMpO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IGNvbm5LZXksXG4gICAgICAgICAgICBjb25uS2V5LFxuICAgICAgICAgICAgY29ublN0cmluZyxcbiAgICAgICAgICAgIGN1cnJlbnRWZXJzaW9uLFxuICAgICAgICAgICAgc3RhdHVzOiBzdGF0dXMsXG4gICAgICAgICAgICBwZW5kaW5nLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgLy8g67aI7Ya1IERC7J2YIOy7pOuEpeyFmCDsoJXrpqzqsIAg7Luk64Sl7IWYIO2ajeuTnSDtg4DsnoTslYTsm4PquYzsp4AgaGFuZ+2VmOyngCDslYrrj4TroZ0g6rCQ7Iu864ukLlxuICAgICAgICAgIGF3YWl0IHdpdGhUaW1lb3V0KFxuICAgICAgICAgICAgdENvbm4uZGVzdHJveSgpLFxuICAgICAgICAgICAgTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgICAgICgpID0+IG5ldyBFcnJvcihcImNvbm5lY3Rpb24gZGVzdHJveSB0aW1lb3V0XCIpLFxuICAgICAgICAgICkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpjb25uc1wiLCBzdGF0dXNlcyk7XG5cbiAgICBjb25zdCBwcmVwYXJlZENvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzMGNvbm4gPSBzdGF0dXNlcy5maW5kKChzdGF0dXMpID0+IHN0YXR1cy5zdGF0dXMgPT09IDApO1xuICAgICAgaWYgKHN0YXR1czBjb25uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgIGBXaGlsZSB0cnlpbmcgdG8gcHJlcGFyZSBtaWdyYXRpb24gY29kZXMsIHdlIGZvdW5kIHRoYXQgdGhlcmUgaXMgbm8gZGF0YWJhc2UgdG8gY29tcGFyZSBtaWdyYXRpb25zLiBXZSBuZWVkIGF0IGxlYXN0IG9uZSBkYXRhYmFzZSB3aGVyZSBldmVyeSBtaWdyYXRpb24gaXMgYXBwbGllZChzdGF0dXMgPT09IDApLiBZb3UgbWlnaHQgd2FudCB0byBhcHBseSB5b3VyIGV4aXN0aW5nIG1pZ3JhdGlvbnMgdG8gb25lIG9mIHRoZSBkYXRhYmFzZXMuYCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbXBhcmVEQmNvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2UoU29uYW11LmRiQ29uZmlnW3N0YXR1czBjb25uLmNvbm5LZXldKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQmNvbm4pO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgY29tcGFyZURCY29ubi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSkoKTtcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRTdGF0dXM6cHJlcGFyZWRDb2Rlc1wiLCBwcmVwYXJlZENvZGVzKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb25uczogc3RhdHVzZXMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgICBlcnJvcjogbWlncmF0aW9uU3RhdHVzRXJyb3IsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZjsnYQg7KCB7Jqp7ZWY6rGw64KYIOuhpOuwse2VqeuLiOuLpC5cbiAgICogU29uYW11IFVJ7JeQ7IScIOuniOydtOq3uOugiOydtOyFmCDsnpHsl4XsnYQg7IiY7ZaJ7ZWgIOuVjCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIENMSeyZgCBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gYWN0aW9uIOyekeyXhSDsnKDtmJUgKGFwcGx5L3JvbGxiYWNrKVxuICAgKiBAcGFyYW0gdGFyZ2V0cyDsnpHsl4Ug64yA7IOBIERCIOyEpOyglSDtgqQgKGtleW9mIFNvbmFtdURCQ29uZmlnKVxuICAgKiBAcmV0dXJucyDsnpHsl4Ug6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5BY3Rpb24oXG4gICAgYWN0aW9uOiBcImFwcGx5XCIgfCBcInJvbGxiYWNrXCIsXG4gICAgdGFyZ2V0czogKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246YWN0aW9uXCIsIGFjdGlvbik7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjp0YXJnZXRzXCIsIHRhcmdldHMpO1xuXG4gICAgY29uc3QgYWxsb3dlZFRhcmdldHMgPSBuZXcgU2V0KHRoaXMuZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpKTtcbiAgICBjb25zdCBkaXNhbGxvd2VkVGFyZ2V0cyA9IHRhcmdldHMuZmlsdGVyKCh0YXJnZXQpID0+ICFhbGxvd2VkVGFyZ2V0cy5oYXModGFyZ2V0KSk7XG4gICAgaWYgKGRpc2FsbG93ZWRUYXJnZXRzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYE1pZ3JhdGlvbiB0YXJnZXRzIGFyZSBub3QgYWxsb3dlZCBpbiBOT0RFX0VOVj0ke2dldFNvbmFtdUVudmlyb25tZW50KCl9OiAke2Rpc2FsbG93ZWRUYXJnZXRzLmpvaW4oXCIsIFwiKX1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBnZXQgdW5pcSBrbmV4IGNvbmZpZ3NcbiAgICBjb25zdCBjb25maWdzID0gdW5pcXVlKFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXRdLFxuICAgICAgICB9KSlcbiAgICAgICAgLmZpbHRlcigoYykgPT4gYy5vcHRpb25zICE9PSB1bmRlZmluZWQpLFxuICAgICAgKHsgb3B0aW9ucyB9KSA9PlxuICAgICAgICBgJHsob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5ob3N0fToke1xuICAgICAgICAgIChvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLnBvcnQgPz8gNTQzMlxuICAgICAgICB9LyR7KG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykuZGF0YWJhc2V9YCxcbiAgICApO1xuXG4gICAgLy8gZ2V0IGNvbm5lY3Rpb25zXG4gICAgY29uc3QgY29ubnMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGNvbmZpZ3MubWFwKGFzeW5jIChjb25maWcpID0+ICh7XG4gICAgICAgIGNvbm5LZXk6IGNvbmZpZy5jb25uS2V5LFxuICAgICAgICBrbmV4OiBjcmVhdGVLbmV4SW5zdGFuY2UoY29uZmlnLm9wdGlvbnMpLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gYWN0aW9uXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBzd2l0Y2ggKGFjdGlvbikge1xuICAgICAgICAgIGNhc2UgXCJhcHBseVwiOlxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucnVuTWlncmF0aW9uc1NlcXVlbnRpYWxseShjb25ucywgXCJhcHBseVwiKTtcbiAgICAgICAgICBjYXNlIFwicm9sbGJhY2tcIjpcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoY29ubnMsIFwicm9sbGJhY2tcIik7XG4gICAgICAgIH1cbiAgICAgIH0pKCk7XG5cbiAgICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246cmVzdWx0XCIsIHJlc3VsdCk7XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGtuZXguZGVzdHJveSgpO1xuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOyCreygnCDqsIDriqXtlZwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg6rKA7Kad7ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29ubnMg66eI7J206re466CI7J207IWYIOyDge2DnCDrsLDsl7RcbiAgICogQHBhcmFtIGNvZGVOYW1lcyDsgq3soJztlaAg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg7J2066aEIOuwsOyXtFxuICAgKiBAcmV0dXJucyDsgq3soJwg6rCA64qlIOyXrOu2gCDrsI8g7KCB7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhFxuICAgKi9cbiAgdmFsaWRhdGVEZWxldGFibGUoY29ubnM6IE1pZ3JhdGlvblN0YXR1c1tcImNvbm5zXCJdLCBjb2RlTmFtZXM6IHN0cmluZ1tdKSB7XG4gICAgY29uc3QgYXBwbGllZENvZGVzID0gY29kZU5hbWVzLmZpbHRlcigoY29kZU5hbWUpID0+XG4gICAgICBjb25ucy5zb21lKChjb25uKSA9PiAhY29ubi5wZW5kaW5nLmluY2x1ZGVzKGNvZGVOYW1lKSksXG4gICAgKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjYW5EZWxldGU6IGFwcGxpZWRDb2Rlcy5sZW5ndGggPT09IDAsXG4gICAgICBhcHBsaWVkQ29kZXMsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDsgq3soJztlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBjb2RlTmFtZXMg7IKt7KCc7ZWgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhCDrsLDsl7RcbiAgICogQHJldHVybnMg7IKt7KCc65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZGVsQ29kZXMoY29kZU5hbWVzOiBzdHJpbmdbXSk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjb25ucyB9ID0gYXdhaXQgdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBjb25zdCB7IGNhbkRlbGV0ZSwgYXBwbGllZENvZGVzIH0gPSB0aGlzLnZhbGlkYXRlRGVsZXRhYmxlKGNvbm5zLCBjb2RlTmFtZXMpO1xuICAgIGlmICghY2FuRGVsZXRlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBZb3UgY2Fubm90IGRlbGV0ZSBhIG1pZ3JhdGlvbiBmaWxlIGlmIHRoZXJlIGlzIGFscmVhZHkgYXBwbGllZC4gQXBwbGllZCBjb2RlczogJHthcHBsaWVkQ29kZXMuam9pbihcIiwgXCIpfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBzdW0oXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgY29kZU5hbWVzLm1hcChhc3luYyAoY29kZU5hbWUpID0+IHtcbiAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnMvJHtjb2RlTmFtZX0udHNgO1xuICAgICAgICAgIGlmIChhd2FpdCBleGlzdHMoZmlsZVBhdGgpKSB7XG4gICAgICAgICAgICBhd2FpdCB1bmxpbmsoZmlsZVBhdGgpO1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2VuRGF0ZVRhZyhpbmRleDogbnVtYmVyLCBiYXNlRGF0ZTogRGF0ZSA9IG5ldyBEYXRlKCkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShiYXNlRGF0ZS5nZXRUaW1lKCkgKyBpbmRleCAqIDEwMDApO1xuICAgIGNvbnN0IHBhZCA9IChudW06IG51bWJlciwgc2l6ZTogbnVtYmVyID0gMikgPT4gbnVtLnRvU3RyaW5nKCkucGFkU3RhcnQoc2l6ZSwgXCIwXCIpO1xuICAgIHJldHVybiAoXG4gICAgICBkYXRlLmdldEZ1bGxZZWFyKCkudG9TdHJpbmcoKSArXG4gICAgICBwYWQoZGF0ZS5nZXRNb250aCgpICsgMSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0RGF0ZSgpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRIb3VycygpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRNaW51dGVzKCkpICtcbiAgICAgIHBhZChkYXRlLmdldFNlY29uZHMoKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGVQcmVwYXJlZENvZGVzKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBwcmVwYXJlZENvZGVzIH0gPSBhd2FpdCB0aGlzLmdldFN0YXR1cygpO1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZW5lcmF0ZVByZXBhcmVkQ29kZXM6cHJlcGFyZWRDb2Rlc1wiLCBwcmVwYXJlZENvZGVzKTtcbiAgICBpZiAocHJlcGFyZWRDb2Rlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKFwiXFxu7ZiE7J6sIOuqqOuRkCDsi7HtgazrkJwg7IOB7YOc7J6F64uI64ukLlwiKSk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICAvLyDsi6TsoJwg7L2U65OcIOyDneyEsVxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcblxuICAgIGZvciAoY29uc3QgW2luZGV4LCBwY29kZV0gb2YgcHJlcGFyZWRDb2Rlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChwY29kZS5mb3JtYXR0ZWQpIHtcbiAgICAgICAgY29uc3QgZGF0ZVRhZyA9IHRoaXMuZ2VuRGF0ZVRhZyhpbmRleCk7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gYCR7bWlncmF0aW9uc0Rpcn0vJHtkYXRlVGFnfV8ke3Bjb2RlLnRpdGxlfS50c2A7XG4gICAgICAgIGF3YWl0IHdyaXRlRmlsZShmaWxlUGF0aCwgcGNvZGUuZm9ybWF0dGVkKTtcbiAgICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGBNSUdSQVRJT04gQ1JFQVRFRCAke2ZpbGVQYXRofWApKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcHJlcGFyZWRDb2Rlcy5sZW5ndGg7XG4gIH1cblxuICBhc3luYyBjb21wYXJlTWlncmF0aW9ucyhjb21wYXJlREI6IEtuZXgpOiBQcm9taXNlPEdlbk1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIC8vIEVudGl0eSDsiJztmoztlZjsl6wg7Iux7YGsXG4gICAgY29uc3QgZW50aXR5SWRzID0gRW50aXR5TWFuYWdlci5nZXRBbGxJZHMoKTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lCDtj6ztlajtlZjsl6wgRW50aXR57JeQ7IScIE1pZ3JhdGlvblNldCDstpTstpxcbiAgICBjb25zdCBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZSA9IGVudGl0eUlkc1xuICAgICAgLmZpbHRlcigoZW50aXR5SWQpID0+IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKS5wcm9wcy5sZW5ndGggPiAwKVxuICAgICAgLm1hcCgoZW50aXR5SWQpID0+IGdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkoRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpKSk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJTrp4wg7LaU7LacXG4gICAgY29uc3Qgam9pblRhYmxlc1dpdGhEdXAgPSBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZS5mbGF0TWFwKChlbnRpdHlTZXQpID0+IGVudGl0eVNldC5qb2luVGFibGVzKTtcbiAgICAvLyDspJHrs7Ug7KCc6rGwICjspJHrs7Xsnbgg6rK97JqwIGluZGV4ZXPrpbwg67OR7ZWpKVxuICAgIGNvbnN0IGpvaW5UYWJsZXMgPSBPYmplY3QudmFsdWVzKGdyb3VwKGpvaW5UYWJsZXNXaXRoRHVwLCAoanQpID0+IGp0LnRhYmxlKSkubWFwKCh0YWJsZXMpID0+IHtcbiAgICAgIGFzc2VydCh0YWJsZXMgIT09IHVuZGVmaW5lZCwgXCJ0YWJsZXMgaXMgdW5kZWZpbmVkXCIpO1xuICAgICAgaWYgKHRhYmxlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIHRhYmxlc1swXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLnRhYmxlc1swXSxcbiAgICAgICAgaW5kZXhlczogdW5pcXVlKFxuICAgICAgICAgIHRhYmxlcy5mbGF0TWFwKCh0KSA9PiB0LmluZGV4ZXMpLFxuICAgICAgICAgIChpbmRleCkgPT4gW2luZGV4LnR5cGUsIC4uLmluZGV4LmNvbHVtbnNdLmpvaW4oXCItXCIpLFxuICAgICAgICApLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lCDtj6ztlajtlZjsl6wgTWlncmF0aW9uU2V0IOuwsOyXtFxuICAgIGNvbnN0IGVudGl0eVNldHM6IE1pZ3JhdGlvblNldFtdID0gWy4uLmVudGl0eVNldHNXaXRoSm9pblRhYmxlLCAuLi5qb2luVGFibGVzXTtcblxuICAgIGNvbnN0IGNvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10gPSBbXTtcbiAgICBjb25zdCBiYXRjaFNpemUgPSA0O1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbnRpdHlTZXRzLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgIGNvbnN0IGJhdGNoQ29kZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZW50aXR5U2V0cy5zbGljZShpLCBpICsgYmF0Y2hTaXplKS5tYXAoYXN5bmMgKGVudGl0eVNldCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGRiU2V0ID0gYXdhaXQgUG9zdGdyZVNRTFNjaGVtYVJlYWRlci5nZXRNaWdyYXRpb25TZXRGcm9tREIoXG4gICAgICAgICAgICBjb21wYXJlREIsXG4gICAgICAgICAgICBlbnRpdHlTZXQudGFibGUsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBOYWl0ZS50KGBtaWdyYXRvcjpjb21wYXJlTWlncmF0aW9uczplbnRpdHlTZXQ6JHtlbnRpdHlTZXQudGFibGV9YCwgZW50aXR5U2V0KTtcbiAgICAgICAgICBOYWl0ZS50KGBtaWdyYXRvcjpjb21wYXJlTWlncmF0aW9uczpkYlNldDoke2VudGl0eVNldC50YWJsZX1gLCBkYlNldCk7XG5cbiAgICAgICAgICBpZiAoZGJTZXQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7JeG7J2MLCDsg4jroZwg7YWM7J2067iUIOyDneyEsVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQ3JlYXRlQ29kZShlbnRpdHlTZXQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyDquLDsobQg7YWM7J2067iUIOyhtOyerO2VmOuKlCDsvIDsnbTsiqRcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUFsdGVyQ29kZShlbnRpdHlTZXQsIGRiU2V0LCBjb21wYXJlREIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICBjb2Rlcy5wdXNoKC4uLmJhdGNoQ29kZXMuZmxhdCgpKTtcbiAgICB9XG5cbiAgICAvLyBub3JtYWwg7YOA7J6F7J20IOyVnuycvOuhnCwgZm9yZWlnbuydtCDrkqTroZxcbiAgICBjb2Rlcy5zb3J0KChjb2RlQSwgY29kZUIpID0+IHtcbiAgICAgIGlmIChjb2RlQS50eXBlID09PSBcImZvcmVpZ25cIiAmJiBjb2RlQi50eXBlID09PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyBTaGFkb3cgREIg7YWM7Iqk7Yq4IOqysOqzvFxuICAgKi9cbiAgYXN5bmMgcnVuU2hhZG93VGVzdCgpOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IGJhc2VUZXN0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWc7XG4gICAgY29uc3Qgd29ya2VySWQgPSBwcm9jZXNzLmVudi5TT05BTVVfV09SS0VSX0RCID09PSBcInRydWVcIiA/IHByb2Nlc3MuZW52LlZJVEVTVF9QT09MX0lEIDogbnVsbDtcbiAgICBjb25zdCB0ZW1wbGF0ZURhdGFiYXNlID1cbiAgICAgIHdvcmtlcklkICE9PSBudWxsID8gYCR7YmFzZVRlc3RDb25uLmRhdGFiYXNlfV8ke3dvcmtlcklkID8/IFwiMVwifWAgOiBiYXNlVGVzdENvbm4uZGF0YWJhc2U7XG4gICAgY29uc3QgdGRiQ29ubiA9IHsgLi4uYmFzZVRlc3RDb25uLCBkYXRhYmFzZTogdGVtcGxhdGVEYXRhYmFzZSB9O1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gYCR7dGVtcGxhdGVEYXRhYmFzZX1fX21pZ3JhdGlvbl9zaGFkb3dgO1xuXG4gICAgLy8g7YWM7Iqk7Yq4IOyDge2ZqeyXkOyEnOuKlCDtirjrnpzsnq3shZjsnYQg7LSI6riw7ZmU7ZWY6rOgLCDsg4gg642w7J207YSw67Kg7J207IqkIOy7pOuEpeyFmOydhCDqsIDsoLjsmYDslbwg7ZWoXG4gICAgaWYgKGlzVGVzdCgpKSB7XG4gICAgICBhd2FpdCBEQi5jbGVhclRlc3RUcmFuc2FjdGlvbigpO1xuICAgICAgYXdhaXQgREIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIC8vIOq4sOyhtCBTaGFkb3cgREIg7IKt7KCcIO2bhCBTaGFkb3cgREIg7IOd7ISxXG4gICAgY29uc3QgdGRiID0gY3JlYXRlS25leEluc3RhbmNlKHtcbiAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAuLi5iYXNlVGVzdENvbm4sXG4gICAgICAgIGRhdGFiYXNlOiBcInBvc3RncmVzXCIsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g7IKt7KCcYCkpO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgJHtzaGFkb3dEYXRhYmFzZX1gKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYFxuICAgICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICAgIEZST00gcGdfc3RhdF9hY3Rpdml0eVxuICAgICAgICBXSEVSRSBkYXRuYW1lID0gJyR7dGRiQ29ubi5kYXRhYmFzZX0nXG4gICAgICAgICAgQU5EIHBpZCA8PiBwZ19iYWNrZW5kX3BpZCgpO1xuICAgICAgYCk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBDUkVBVEUgREFUQUJBU0UgJHtzaGFkb3dEYXRhYmFzZX0gVEVNUExBVEUgJHt0ZGJDb25uLmRhdGFiYXNlfWApO1xuXG4gICAgICAvLyBTaGFkb3cgRELsl5Ag7Jew6rKwXG4gICAgICBjb25zdCBzZGIgPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgICAuLi5Tb25hbXUuZGJDb25maWcudGVzdCxcbiAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgIC4uLnRkYkNvbm4sXG4gICAgICAgICAgZGF0YWJhc2U6IHNoYWRvd0RhdGFiYXNlLFxuICAgICAgICAgIHBhc3N3b3JkOiB0ZGJDb25uLnBhc3N3b3JkLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIHNoYWRvdyBEQiDthYzsiqTtirgg7KeE7ZaJXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QoKTtcbiAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJTaGFkb3cgREIg7YWM7Iqk7Yq47JeQIOyEseqzte2WiOyKteuLiOuLpCFcIiksIHtcbiAgICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgY29ubktleTogXCJzaGFkb3dcIixcbiAgICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgIH0sXG4gICAgICAgIF07XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oU0QoXCJzb25hbXUuZXJyb3Iuc2hhZG93RGJUZXN0RmFpbGVkXCIpKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IHNkYi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIC8vIFNoYWRvdyBEQiDsgq3soJxcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDsgq3soJxgKSk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiU2hhZG93IERCIOygleumrCDsi6TtjKg6XCIsIGUpOyAvLyDsnbTqsowg7JeG7Jy866m0IOyhsOyaqe2eiCDriITsiJhcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IHRkYi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXdDQSxTQUFTLFlBQWUsU0FBcUIsSUFBWSxXQUFvQztDQUMzRixPQUFPLElBQUksU0FBWSxTQUFTLFdBQVc7RUFDekMsTUFBTSxRQUFRLGlCQUFpQixPQUFPLFVBQVUsQ0FBQyxHQUFHLEVBQUU7RUFDdEQsUUFBUSxNQUNMLFVBQVU7R0FDVCxhQUFhLEtBQUs7R0FDbEIsUUFBUSxLQUFLO0VBQ2YsSUFDQyxVQUFVO0dBQ1QsYUFBYSxLQUFLO0dBQ2xCLE9BQU8sS0FBSztFQUNkLENBQ0Y7Q0FDRixDQUFDO0FBQ0g7OzthQTlDc0M7U0FDSDtXQUVrQjtTQUN0QjtxQkFDeUI7VUFDWDtvQkFDNEI7WUFDbkM7aUJBRWU7ZUFDWDtzQkFDK0I7b0JBQ2Q7K0JBQ1E7Q0FZN0QsNEJBQTRCO0NBc0JyQixXQUFiLE1BQXNCO0VBQ3BCLDZCQUFxQyxPQUF5QjtHQUM1RCxJQUFJLE9BQU8sVUFBVSxZQUFZLFVBQVUsTUFDekMsT0FBTztHQUdULE1BQU0scUJBQXFCO0dBQzNCLE9BQ0UsbUJBQW1CLFNBQVMsV0FDNUIsT0FBTyxtQkFBbUIsWUFBWSxZQUN0QyxtQkFBbUIsUUFBUSxTQUFTLGlCQUFpQjtFQUV6RDtFQUVBLHlCQUEyRDtHQUN6RCxNQUFNLFdBQVcsT0FBTyxLQUFLLE9BQU8sUUFBUSxD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
|
|
518
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZ3JhdGlvbi9taWdyYXRvci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyBncm91cCwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IERCIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyB0eXBlIFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBjcmVhdGVLbmV4SW5zdGFuY2UgfSBmcm9tIFwiLi4vZGF0YWJhc2Uva25leFwiO1xuaW1wb3J0IHsgU0QgfSBmcm9tIFwiLi4vZGljdC9zZFwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IGdldFNvbmFtdUVudmlyb25tZW50IH0gZnJvbSBcIi4uL2VudlwiO1xuaW1wb3J0IHsgU2VydmljZVVuYXZhaWxhYmxlRXhjZXB0aW9uIH0gZnJvbSBcIi4uL2V4Y2VwdGlvbnMvc28tZXhjZXB0aW9uc1wiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB7IHR5cGUgR2VuTWlncmF0aW9uQ29kZSwgdHlwZSBNaWdyYXRpb25TZXQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IGlzTG9jYWwsIGlzVGVzdCB9IGZyb20gXCIuLi91dGlscy9jb250cm9sbGVyXCI7XG5pbXBvcnQgeyBleGlzdHMgfSBmcm9tIFwiLi4vdXRpbHMvZnMtdXRpbHNcIjtcbmltcG9ydCB7IGlzT2JqZWN0VmFsdWUsIGlzU3RyaW5nVmFsdWUgfSBmcm9tIFwiLi4vdXRpbHMvcnVudGltZS12YWx1ZVwiO1xuaW1wb3J0IHsgZ2VuZXJhdGVBbHRlckNvZGUsIGdlbmVyYXRlQ3JlYXRlQ29kZSB9IGZyb20gXCIuL2NvZGUtZ2VuZXJhdGlvblwiO1xuaW1wb3J0IHsgZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eSB9IGZyb20gXCIuL21pZ3JhdGlvbi1zZXRcIjtcbmltcG9ydCB7IFBvc3RncmVTUUxTY2hlbWFSZWFkZXIgfSBmcm9tIFwiLi9wb3N0Z3Jlc3FsLXNjaGVtYS1yZWFkZXJcIjtcbmltcG9ydCB7IFNsYWNrQ29uZmlybSB9IGZyb20gXCIuL3NsYWNrLWNvbmZpcm1cIjtcbmltcG9ydCB7XG4gIHR5cGUgQ29ublN0cmluZyxcbiAgdHlwZSBNaWdyYXRpb25BY3Rpb24sXG4gIHR5cGUgTWlncmF0aW9uQ29kZSxcbiAgdHlwZSBNaWdyYXRpb25Db25uZWN0aW9uTWV0YSxcbiAgdHlwZSBNaWdyYXRpb25Db25uZWN0aW9uU3RhdHVzLFxuICB0eXBlIE1pZ3JhdGlvblByb2dyZXNzRXZlbnQsXG4gIHR5cGUgTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgdHlwZSBNaWdyYXRpb25TdGF0dXMsXG4gIHR5cGUgTWlncmF0aW9uVGFyZ2V0LFxufSBmcm9tIFwiLi90eXBlc1wiO1xuXG5leHBvcnQgdHlwZSBNaWdyYXRpb25SZXN1bHQgPSB7XG4gIGNvbm5LZXk6IHN0cmluZztcbiAgYmF0Y2hObzogbnVtYmVyO1xuICBhcHBsaWVkOiBzdHJpbmdbXTtcbn1bXTtcblxuZnVuY3Rpb24gcGFkRGF0ZVBhcnQobnVtYmVyOiBudW1iZXIsIHNpemU6IG51bWJlciA9IDIpOiBzdHJpbmcge1xuICByZXR1cm4gbnVtYmVyLnRvU3RyaW5nKCkucGFkU3RhcnQoc2l6ZSwgXCIwXCIpO1xufVxuXG5leHBvcnQgY2xhc3MgTWlncmF0aW9uVGFyZ2V0RXhlY3V0aW9uRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyByZWFkb25seSBjb25uS2V5OiBNaWdyYXRpb25UYXJnZXQgfCBcInNoYWRvd1wiLFxuICAgIGNhdXNlOiB1bmtub3duLFxuICApIHtcbiAgICBzdXBlcihjYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gY2F1c2UubWVzc2FnZSA6IFN0cmluZyhjYXVzZSkpO1xuICAgIHRoaXMubmFtZSA9IFwiTWlncmF0aW9uVGFyZ2V0RXhlY3V0aW9uRXJyb3JcIjtcbiAgfVxufVxuXG4vLyDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOcIOyhsO2ajCDsi5wgREIg7Jew6rKwIO2ZleyduCDtg4DsnoTslYTsm4MobXMpLlxuLy8gY3JlYXRlS25leEluc3RhbmNl7J2YIOy7pOuEpeyFmCDtmo3rk50g7YOA7J6E7JWE7JuDKDMw7LSIKeyXkCBzdGF0dXMvbGlzdC9jdXJyZW50VmVyc2lvbuydtFxuLy8g6rCB6rCBIOqxuOumrOuptCBDTEkvVUnqsIAg7LWc64yAIOyImOyLrSDstIggaGFuZ+2VnOuLpC4g7KCV7IOBIOydkeuLteydgCDsiJjrsLEgbXPsnbTrr4DroZwgNey0iOuptCDstqnrtoTtlZjri6QuXG5jb25zdCBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TID0gNTAwMDtcbmNvbnN0IExPQ0FMX0RCX0hPU1RTID0gbmV3IFNldChbXCJsb2NhbGhvc3RcIiwgXCIxMjcuMC4wLjFcIiwgXCIwLjAuMC4wXCIsIFwiOjoxXCJdKTtcblxuLyoqXG4gKiDso7zslrTsp4QgUHJvbWlzZeqwgCBtcyDslYjsl5Ag7JmE66OM65CY7KeAIOyViuycvOuptCBvblRpbWVvdXQg7JeQ65+s66GcIHJlamVjdO2VnOuLpC5cbiAqIOybkOuzuCBQcm9taXNlIOyekOyytOuKlCDqs4Tsho0g7KeE7ZaJ65CY66+A66GcLCDtmLjstpzsuKHsl5DshJwg7Luk64Sl7IWYIOygleumrChkZXN0cm95KeulvCDssYXsnoTsp4Tri6QuXG4gKi9cbmZ1bmN0aW9uIHdpdGhUaW1lb3V0PFQ+KHByb21pc2U6IFByb21pc2U8VD4sIG1zOiBudW1iZXIsIG9uVGltZW91dDogKCkgPT4gRXJyb3IpOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlPFQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gcmVqZWN0KG9uVGltZW91dCgpKSwgbXMpO1xuICAgIHByb21pc2UudGhlbihcbiAgICAgICh2YWx1ZSkgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICAgIH0sXG4gICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0sXG4gICAgKTtcbiAgfSk7XG59XG5cbi8qKlxuICogTm90ZSAyMDI2LTA4LTI2LCDrs5HspIBcbiAqIOydtCDtgbTrnpjsiqTsl5DshJwgZGVwcmVjYXRlZCDrtpnslrTsnojripQg7Lmc6rWs65Ok7J2AIO2YhCBDTEnrpbwg7JyE7ZWcIO2VmOychCDtmLjtmZjsnbTri4gsXG4gKiBDTEkg66as7Yyp7Yag66eBIOyLnOygkOyXkOyEnCDsoJzqsbDtlbTso7zshZTrj4Qg66y067Cp7ZWp64uI64ukLlxuICovXG5leHBvcnQgY2xhc3MgTWlncmF0b3Ige1xuICBwcml2YXRlIGlzTWlzc2luZ01pZ3JhdGlvblRhYmxlRXJyb3I8VmFsdWU+KGVycm9yOiBWYWx1ZSk6IGJvb2xlYW4ge1xuICAgIGlmICghaXNPYmplY3RWYWx1ZShlcnJvcikgfHwgZXJyb3IgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBtYXliZVBvc3RncmVzRXJyb3IgPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBlcnJvciBhcyB7XG4gICAgICAgIGNvZGU/OiB1bmtub3duO1xuICAgICAgICBtZXNzYWdlPzogdW5rbm93bjtcbiAgICAgIH07XG4gICAgcmV0dXJuIChcbiAgICAgIG1heWJlUG9zdGdyZXNFcnJvci5jb2RlID09PSBcIjQyUDAxXCIgJiZcbiAgICAgIGlzU3RyaW5nVmFsdWUobWF5YmVQb3N0Z3Jlc0Vycm9yLm1lc3NhZ2UpICYmXG4gICAgICBtYXliZVBvc3RncmVzRXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcImtuZXhfbWlncmF0aW9uc1wiKVxuICAgICk7XG4gIH1cblxuICAvKiog7ZiE7J6sIOyLpO2WiSDtmZjqsr3sl5DshJwg7ZeI7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDrjIDsg4Eg7YKk66W8IOuwmO2ZmO2VqeuLiOuLpC4gKi9cbiAgZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpOiBNaWdyYXRpb25UYXJnZXRbXSB7XG4gICAgY29uc3QgY29ubktleXMgPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBPYmplY3Qua2V5cyhcbiAgICAgICAgU29uYW11LmRiQ29uZmlnLFxuICAgICAgKS5maWx0ZXIoKGtleSkgPT4gIWtleS5lbmRzV2l0aChcIl9yZWFkb25seVwiKSkgYXMgKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdO1xuXG4gICAgaWYgKGlzTG9jYWwoKSkge1xuICAgICAgcmV0dXJuIGNvbm5LZXlzO1xuICAgIH1cblxuICAgIGNvbnN0IGVudmlyb25tZW50ID0gZ2V0U29uYW11RW52aXJvbm1lbnQoKTtcbiAgICByZXR1cm4gY29ubktleXMuZmlsdGVyKChrZXkpID0+IGtleSA9PT0gZW52aXJvbm1lbnQpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBydW5NaWdyYXRpb25zU2VxdWVudGlhbGx5KFxuICAgIGNvbm5zOiB7IGNvbm5LZXk6IGtleW9mIFNvbmFtdURCQ29uZmlnOyBrbmV4OiBLbmV4IH1bXSxcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHRzOiBNaWdyYXRpb25SZXN1bHQgPSBbXTtcblxuICAgIGZvciAoY29uc3QgeyBjb25uS2V5LCBrbmV4IH0gb2YgY29ubnMpIHtcbiAgICAgIGNvbnN0IHByb2dyZXNzID0gdGhpcy5jcmVhdGVQcm9ncmVzc0hvb2tzKGFjdGlvbiwgY29ubktleSwgb3B0aW9ucyk7XG4gICAgICBsZXQgbWlncmF0aW9uUmVzdWx0OiBbbnVtYmVyLCBzdHJpbmdbXV07XG4gICAgICB0cnkge1xuICAgICAgICBtaWdyYXRpb25SZXN1bHQgPVxuICAgICAgICAgIGFjdGlvbiA9PT0gXCJhcHBseVwiXG4gICAgICAgICAgICA/IGF3YWl0IGtuZXgubWlncmF0ZS5sYXRlc3QocHJvZ3Jlc3MpXG4gICAgICAgICAgICA6IGF3YWl0IGtuZXgubWlncmF0ZS5yb2xsYmFjayhwcm9ncmVzcyk7XG4gICAgICB9IGNhdGNoIChjYXVnaHQpIHtcbiAgICAgICAgLy8gbGlmZWN5Y2xlIGhvb2sg7J207KCE7J2YIOyXsOqysMK3bG9ja8K366qp66GdIOyhsO2ajCDsi6TtjKjrj4Qg7Iuk7KCcIOuMgOyDgSBEQuyXkCDqt4Dsho3tlanri4jri6QuXG4gICAgICAgIHRocm93IG5ldyBNaWdyYXRpb25UYXJnZXRFeGVjdXRpb25FcnJvcihjb25uS2V5LCBjYXVnaHQpO1xuICAgICAgfVxuICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gbWlncmF0aW9uUmVzdWx0O1xuXG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBjb25uS2V5LFxuICAgICAgICBiYXRjaE5vLFxuICAgICAgICBhcHBsaWVkLFxuICAgICAgfSk7XG4gICAgICB0aGlzLmVtaXRQcm9ncmVzcyhvcHRpb25zLCB7XG4gICAgICAgIHR5cGU6IFwidGFyZ2V0LWNvbXBsZXRlXCIsXG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgY29ubktleSxcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgZmlsZXM6IGFwcGxpZWQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIHByaXZhdGUgbWlncmF0aW9uTmFtZTxWYWx1ZT4obWlncmF0aW9uOiBWYWx1ZSk6IHN0cmluZyB7XG4gICAgaWYgKGlzU3RyaW5nVmFsdWUobWlncmF0aW9uKSkge1xuICAgICAgcmV0dXJuIHBhdGguYmFzZW5hbWUobWlncmF0aW9uKTtcbiAgICB9XG4gICAgaWYgKGlzT2JqZWN0VmFsdWUobWlncmF0aW9uKSAmJiBtaWdyYXRpb24gIT09IG51bGwpIHtcbiAgICAgIGNvbnN0IGNhbmRpZGF0ZSA9XG4gICAgICAgIC8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gbWlncmF0aW9uIGFzIHtcbiAgICAgICAgICBmaWxlPzogdW5rbm93bjtcbiAgICAgICAgICBuYW1lPzogdW5rbm93bjtcbiAgICAgICAgfTtcbiAgICAgIGlmIChpc1N0cmluZ1ZhbHVlKGNhbmRpZGF0ZS5maWxlKSkge1xuICAgICAgICByZXR1cm4gcGF0aC5iYXNlbmFtZShjYW5kaWRhdGUuZmlsZSk7XG4gICAgICB9XG4gICAgICBpZiAoaXNTdHJpbmdWYWx1ZShjYW5kaWRhdGUubmFtZSkpIHtcbiAgICAgICAgcmV0dXJuIHBhdGguYmFzZW5hbWUoY2FuZGlkYXRlLm5hbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gU3RyaW5nKG1pZ3JhdGlvbik7XG4gIH1cblxuICBwcml2YXRlIGVtaXRQcm9ncmVzcyhvcHRpb25zOiBNaWdyYXRpb25SdW5PcHRpb25zIHwgdW5kZWZpbmVkLCBldmVudDogTWlncmF0aW9uUHJvZ3Jlc3NFdmVudCkge1xuICAgIHRyeSB7XG4gICAgICBvcHRpb25zPy5vblByb2dyZXNzPy4oZXZlbnQpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyDsp4TtlonrpaAg7IaM67mE7J6Q7J2YIOyLpO2MqOqwgCDsnbTrr7gg7Iuc7J6R7ZWcIERCIOyekeyXheqzvCDsoJXrpqzrpbwg67Cp7ZW07ZWY66m0IOyViCDrkKnri4jri6QuXG4gICAgICBjb25zb2xlLndhcm4oXCJNaWdyYXRpb24gcHJvZ3Jlc3Mgb2JzZXJ2ZXIgZmFpbGVkOlwiLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVQcm9ncmVzc0hvb2tzKFxuICAgIGFjdGlvbjogTWlncmF0aW9uQWN0aW9uLFxuICAgIGNvbm5LZXk6IE1pZ3JhdGlvblRhcmdldCB8IFwic2hhZG93XCIsXG4gICAgb3B0aW9ucz86IE1pZ3JhdGlvblJ1bk9wdGlvbnMsXG4gICk6IEtuZXguTWlncmF0b3JDb25maWdXaXRoTGlmZWN5Y2xlSG9va3Mge1xuICAgIGxldCBmaWxlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBlbWl0RmlsZSA9IDxWYWx1ZT4odHlwZTogXCJmaWxlLXN0YXJ0XCIgfCBcImZpbGUtZXhlY3V0ZWRcIiwgbWlncmF0aW9uOiBWYWx1ZSkgPT4ge1xuICAgICAgY29uc3QgZmlsZSA9IHRoaXMubWlncmF0aW9uTmFtZShtaWdyYXRpb24pO1xuICAgICAgY29uc3QgaW5kZXggPSBNYXRoLm1heChmaWxlcy5pbmRleE9mKGZpbGUpLCAwKTtcbiAgICAgIHRoaXMuZW1pdFByb2dyZXNzKG9wdGlvbnMsIHtcbiAgICAgICAgdHlwZSxcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjb25uS2V5LFxuICAgICAgICBmaWxlLFxuICAgICAgICBpbmRleCxcbiAgICAgICAgdG90YWw6IGZpbGVzLmxlbmd0aCxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgYmVmb3JlQWxsOiBhc3luYyAoX2tuZXgsIG1pZ3JhdGlvbnMpID0+IHtcbiAgICAgICAgZmlsZXMgPSBtaWdyYXRpb25zLm1hcCgobWlncmF0aW9uKSA9PiB0aGlzLm1pZ3JhdGlvbk5hbWUobWlncmF0aW9uKSk7XG4gICAgICAgIHRoaXMuZW1pdFByb2dyZXNzKG9wdGlvbnMsIHsgdHlwZTogXCJ0YXJnZXQtc3RhcnRcIiwgYWN0aW9uLCBjb25uS2V5LCBmaWxlcyB9KTtcbiAgICAgIH0sXG4gICAgICBiZWZvcmVFYWNoOiBhc3luYyAoX2tuZXgsIG1pZ3JhdGlvbnMpID0+IHtcbiAgICAgICAgbWlncmF0aW9ucy5mb3JFYWNoKChtaWdyYXRpb24pID0+IGVtaXRGaWxlKFwiZmlsZS1zdGFydFwiLCBtaWdyYXRpb24pKTtcbiAgICAgIH0sXG4gICAgICBhZnRlckVhY2g6IGFzeW5jIChfa25leCwgbWlncmF0aW9ucykgPT4ge1xuICAgICAgICBtaWdyYXRpb25zLmZvckVhY2goKG1pZ3JhdGlvbikgPT4gZW1pdEZpbGUoXCJmaWxlLWV4ZWN1dGVkXCIsIG1pZ3JhdGlvbikpO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3NlcnRNaWdyYXRpb25UYXJnZXQoY29ubktleTogTWlncmF0aW9uVGFyZ2V0KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKS5pbmNsdWRlcyhjb25uS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgTWlncmF0aW9uIHRhcmdldCBpcyBub3QgYWxsb3dlZCBpbiBOT0RFX0VOVj0ke2dldFNvbmFtdUVudmlyb25tZW50KCl9OiAke1N0cmluZyhjb25uS2V5KX1gLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOuMgOyDgSDsu6TrhKXshZjsnZgg7KCV7KCBIOuplO2DgOuNsOydtO2EsOulvCDrsJjtmZjtlanri4jri6QuXG4gICAqIERC7JeQIOyXsOqysO2VmOyngCDslYrsnLzrr4DroZwgQ0xJ7JmAIFdlYuydtCDsg4Htg5wg7KGw7ZqMIOyghOyXkCDsponsi5wg7IKs7Jqp7ZWgIOyImCDsnojsirXri4jri6QuXG4gICAqXG4gICAqIEBjYXRlZ29yeSDrtoTrpqztmJUg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgZ2V0Q29ubmVjdGlvbnMoKTogTWlncmF0aW9uQ29ubmVjdGlvbk1ldGFbXSB7XG4gICAgY29uc3Qgc2xhY2tDb25maXJtID0gbmV3IFNsYWNrQ29uZmlybSgpO1xuICAgIHJldHVybiB0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKS5tYXAoKGNvbm5LZXkpID0+IHtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPVxuICAgICAgICAvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIFNvbmFtdS5kYkNvbmZpZ1tcbiAgICAgICAgICBjb25uS2V5XG4gICAgICAgIF0uY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgIGNvbnN0IGhvc3QgPSBjb25uZWN0aW9uLmhvc3QgPz8gXCJsb2NhbGhvc3RcIjtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIG5hbWU6IFN0cmluZyhjb25uS2V5KSxcbiAgICAgICAgaG9zdCxcbiAgICAgICAgcG9ydDogY29ubmVjdGlvbi5wb3J0ID8/IDU0MzIsXG4gICAgICAgIGRhdGFiYXNlOiBjb25uZWN0aW9uLmRhdGFiYXNlID8/IFwiXCIsXG4gICAgICAgIHJlbW90ZTogIUxPQ0FMX0RCX0hPU1RTLmhhcyhob3N0LnRvTG93ZXJDYXNlKCkpLFxuICAgICAgICByZXF1aXJlc0FwcHJvdmFsOiBzbGFja0NvbmZpcm0uaXNUYXJnZXRSZXF1aXJlc0FwcHJvdmFsKGNvbm5LZXkpLFxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiDshozsiqTsl5Ag7KG07J6s7ZWY64qUIOuniOydtOq3uOugiOydtOyFmCDtjIzsnbwg66qp66Gd7J2EIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnRvU29ydGVkKChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRNaWdyYXRpb25Db2RlczpyZXN1bHRzXCIsIGNvZGVzKTtcbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICog7Luk64Sl7IWYIO2VmOuCmOydmCDtmITsnqwg67KE7KCE6rO8IHBlbmRpbmcg66qp66Gd7J2EIOuPheumveyggeycvOuhnCDsobDtmoztlanri4jri6QuXG4gICAqIOyXrOufrCDrjIDsg4HsnYAg7Zi47Lac7J6Q6rCAIOuzkeugrOuhnCDsobDrpr3tlaAg7IiYIOyeiOyKteuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBnZXRDb25uZWN0aW9uU3RhdHVzKGNvbm5LZXk6IE1pZ3JhdGlvblRhcmdldCk6IFByb21pc2U8TWlncmF0aW9uQ29ubmVjdGlvblN0YXR1cz4ge1xuICAgIHRoaXMuYXNzZXJ0TWlncmF0aW9uVGFyZ2V0KGNvbm5LZXkpO1xuICAgIGNvbnN0IHN0YXJ0ZWRBdCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIGNvbnN0IGNvZGVzID0gYXdhaXQgdGhpcy5nZXRNaWdyYXRpb25Db2RlcygpO1xuICAgIGNvbnN0IGtuZXhPcHRpb25zID0gU29uYW11LmRiQ29uZmlnW2Nvbm5LZXldO1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBrbmV4T3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuICAgIC8vIFNBRkVUWTogS25leOqwgCDsoJzqs7XtlZwgUG9zdGdyZVNRTCDsl7DqsrAg6rWs7ISx7J2EIOuzteyCrO2VtCB0aW1lb3V0IO2VhOuTnOunjCDrja7slrTsk7Tri6QuXG4gICAgY29uc3QgdENvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgLi4ua25leE9wdGlvbnMsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLmNvbm5lY3Rpb24sXG4gICAgICAgIGNvbm5lY3Rpb25UaW1lb3V0TWlsbGlzOiBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLFxuICAgICAgfSxcbiAgICAgIHBvb2w6IHtcbiAgICAgICAgLi4ua25leE9wdGlvbnMucG9vbCxcbiAgICAgICAgbWluOiAwLFxuICAgICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IHRydWUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdpdGhUaW1lb3V0KHRDb25uLnJhdyhcInNlbGVjdCAxXCIpLCBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLCAoKSA9PiB7XG4gICAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgICAgYERCIOyXsOqysCDsi5zqsIQg7LSI6rO8ICgke01JR1JBVElPTl9DT05OX1RJTUVPVVRfTVN9bXMpIOKAlCAke2Nvbm5lY3Rpb24uaG9zdH06JHtjb25uZWN0aW9uLnBvcnR9LyR7Y29ubmVjdGlvbi5kYXRhYmFzZX1gLFxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGxldCBlcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgY29uc3Qgc3RhdHVzOiBudW1iZXIgfCBcImVycm9yXCIgPSBhd2FpdCB0Q29ubi5taWdyYXRlLnN0YXR1cygpLmNhdGNoKChjYXVnaHQpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaXNNaXNzaW5nTWlncmF0aW9uVGFibGVFcnJvcihjYXVnaHQpKSB7XG4gICAgICAgICAgcmV0dXJuIGNvZGVzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICBlcnJvciA9IGNhdWdodCBpbnN0YW5jZW9mIEVycm9yID8gY2F1Z2h0Lm1lc3NhZ2UgOiBTdHJpbmcoY2F1Z2h0KTtcbiAgICAgICAgcmV0dXJuIFwiZXJyb3JcIiBhcyBjb25zdDtcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcGVuZGluZzogc3RyaW5nW10gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKS50aGVuKFxuICAgICAgICAoWywgZmlsZXNdOiBbdW5rbm93bltdLCB7IGZpbGU6IHN0cmluZyB9W11dKSA9PlxuICAgICAgICAgIGZpbGVzLm1hcCgoeyBmaWxlIH0pID0+IGZpbGUucmVwbGFjZSgvXFwudHMkLywgXCJcIikpLFxuICAgICAgICAoY2F1c2U6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGNhdXNlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNvZGVzLm1hcCgoeyBuYW1lIH0pID0+IG5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlcnJvciA/Pz0gY2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm1lc3NhZ2UgOiBTdHJpbmcoY2F1c2UpO1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICBjb25zdCBjdXJyZW50VmVyc2lvbjogc3RyaW5nIHwgXCJub25lXCIgfCBcImVycm9yXCIgPSBhd2FpdCB0Q29ubi5taWdyYXRlXG4gICAgICAgIC5jdXJyZW50VmVyc2lvbigpXG4gICAgICAgIC5jYXRjaCgoY2F1c2U6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGNhdXNlKSkge1xuICAgICAgICAgICAgcmV0dXJuIFwibm9uZVwiIGFzIGNvbnN0O1xuICAgICAgICAgIH1cbiAgICAgICAgICBlcnJvciA/Pz0gY2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm1lc3NhZ2UgOiBTdHJpbmcoY2F1c2UpO1xuICAgICAgICAgIHJldHVybiBcImVycm9yXCIgYXMgY29uc3Q7XG4gICAgICAgIH0pO1xuICAgICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpzdGF0dXNcIiwgc3RhdHVzKTtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb25TdGF0dXM6IE1pZ3JhdGlvbkNvbm5lY3Rpb25TdGF0dXMgPSB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIGN1cnJlbnRWZXJzaW9uLFxuICAgICAgICBzdGF0dXMsXG4gICAgICAgIHBlbmRpbmcsXG4gICAgICAgIGxhdGVuY3lNczogcGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydGVkQXQsXG4gICAgICB9O1xuICAgICAgaWYgKGVycm9yICE9PSB1bmRlZmluZWQpIGNvbm5lY3Rpb25TdGF0dXMuZXJyb3IgPSBlcnJvcjtcbiAgICAgIHJldHVybiBjb25uZWN0aW9uU3RhdHVzO1xuICAgIH0gY2F0Y2ggKGNhdWdodCkge1xuICAgICAgY29uc3QgZXJyb3IgPSBjYXVnaHQgaW5zdGFuY2VvZiBFcnJvciA/IGNhdWdodC5tZXNzYWdlIDogU3RyaW5nKGNhdWdodCk7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICBgJHtTdHJpbmcoY29ubktleSl97J2YIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zrpbwg6rCA7KC47Jik64qUIOuNsOyXkCDsi6TtjKjtlZjsmIDsirXri4jri6QuXFxuJHtlcnJvcn1gLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIGN1cnJlbnRWZXJzaW9uOiBcImVycm9yXCIsXG4gICAgICAgIHN0YXR1czogXCJlcnJvclwiLFxuICAgICAgICBwZW5kaW5nOiBbXSxcbiAgICAgICAgbGF0ZW5jeU1zOiBwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0ZWRBdCxcbiAgICAgICAgZXJyb3IsXG4gICAgICB9O1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCB3aXRoVGltZW91dCh0Q29ubi5kZXN0cm95KCksIE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsICgpID0+IHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcImNvbm5lY3Rpb24gZGVzdHJveSB0aW1lb3V0XCIpO1xuICAgICAgfSkuY2F0Y2goKCkgPT4ge30pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDstZzsi6Ag7IOB7YOc7J24IOq4sOykgCBEQuyZgCDsl5Tti7Dti7Ag7KCV7J2Y66W8IOu5hOq1kO2VtCDsg53shLEg7JiI7KCVIOy9lOuTnOulvCDrsJjtmZjtlanri4jri6QuXG4gICAqXG4gICAqIEBjYXRlZ29yeSDrtoTrpqztmJUg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgYXN5bmMgZ2V0UHJlcGFyZWRDb2Rlcyhjb21wYXJlQ29ubktleTogTWlncmF0aW9uVGFyZ2V0KTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCB0aGlzLmdldENvbm5lY3Rpb25TdGF0dXMoY29tcGFyZUNvbm5LZXkpO1xuICAgIGlmIChzdGF0dXMuc3RhdHVzICE9PSAwIHx8IHN0YXR1cy5lcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNaWdyYXRpb24gY29tcGFyaXNvbiByZXF1aXJlcyBhbiB1cC10by1kYXRlIGRhdGFiYXNlOiAke1N0cmluZyhjb21wYXJlQ29ubktleSl9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuY29tcGFyZVdpdGhDb25uZWN0aW9uKGNvbXBhcmVDb25uS2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29tcGFyZVdpdGhDb25uZWN0aW9uKGNvbXBhcmVDb25uS2V5OiBNaWdyYXRpb25UYXJnZXQpIHtcbiAgICBjb25zdCBjb21wYXJlREIgPSBjcmVhdGVLbmV4SW5zdGFuY2UoU29uYW11LmRiQ29uZmlnW2NvbXBhcmVDb25uS2V5XSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IGNvbXBhcmVEQi5kZXN0cm95KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIOyLoOq3nCBVSeyXkOyEnOuKlCDsu6TrhKXshZjrs4Qg7KGw7ZqMIEFQSeulvCDsgqzsmqntlanri4jri6QuXG4gICAqIOq4sOyhtCBDTEnsmYAg7Iqk7YGs66a97Yq4IO2YuO2ZmOydhCDsnITtlbQg7KCE7LK0IOyDge2DnOulvCDsobDrpr3tlanri4jri6QuXG4gICAqIEBjYXRlZ29yeSDtmLjtmZjsmqkg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgYXN5bmMgZ2V0U3RhdHVzKCk6IFByb21pc2U8TWlncmF0aW9uU3RhdHVzPiB7XG4gICAgY29uc3QgW2NvZGVzLCBjb25uZWN0aW9uc10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLmdldE1pZ3JhdGlvbkNvZGVzKCksXG4gICAgICBQcm9taXNlLnJlc29sdmUodGhpcy5nZXRDb25uZWN0aW9ucygpKSxcbiAgICBdKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvZGVzXCIsIGNvZGVzKTtcblxuICAgIGNvbnN0IGNvbm5lY3Rpb25TdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29ubmVjdGlvbnMubWFwKCh7IGNvbm5LZXkgfSkgPT4gdGhpcy5nZXRDb25uZWN0aW9uU3RhdHVzKGNvbm5LZXkpKSxcbiAgICApO1xuICAgIGNvbnN0IGNvbm5zID0gY29ubmVjdGlvbnMubWFwKChjb25uZWN0aW9uLCBpbmRleCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzID0gY29ubmVjdGlvblN0YXR1c2VzW2luZGV4XTtcbiAgICAgIGFzc2VydChzdGF0dXMgIT09IHVuZGVmaW5lZCk7XG4gICAgICBjb25zdCBjb25maWd1cmVkID1cbiAgICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBTb25hbXUuZGJDb25maWdbXG4gICAgICAgICAgY29ubmVjdGlvbi5jb25uS2V5XG4gICAgICAgIF0uY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IGNvbm5lY3Rpb24ubmFtZSxcbiAgICAgICAgY29ubktleTogY29ubmVjdGlvbi5jb25uS2V5LFxuICAgICAgICBjb25uU3RyaW5nOlxuICAgICAgICAgIC8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gYHBnOi8vJHtjb25maWd1cmVkLnVzZXIgPz8gXCJcIn1AJHtjb25maWd1cmVkLmhvc3R9OiR7Y29uZmlndXJlZC5wb3J0fS8ke2NvbmZpZ3VyZWQuZGF0YWJhc2V9YCBhcyBDb25uU3RyaW5nLFxuICAgICAgICBjdXJyZW50VmVyc2lvbjogc3RhdHVzLmN1cnJlbnRWZXJzaW9uLFxuICAgICAgICBzdGF0dXM6IHN0YXR1cy5zdGF0dXMsXG4gICAgICAgIHBlbmRpbmc6IHN0YXR1cy5wZW5kaW5nLFxuICAgICAgfTtcbiAgICB9KTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvbm5zXCIsIGNvbm5zKTtcblxuICAgIGNvbnN0IGNvbXBhcmVDb25uID0gY29ubmVjdGlvblN0YXR1c2VzLmZpbmQoXG4gICAgICAoeyBzdGF0dXMsIGVycm9yIH0pID0+IHN0YXR1cyA9PT0gMCAmJiBlcnJvciA9PT0gdW5kZWZpbmVkLFxuICAgICk7XG4gICAgY29uc3QgcHJlcGFyZWRDb2RlcyA9XG4gICAgICBjb21wYXJlQ29ubiA9PT0gdW5kZWZpbmVkID8gW10gOiBhd2FpdCB0aGlzLmNvbXBhcmVXaXRoQ29ubmVjdGlvbihjb21wYXJlQ29ubi5jb25uS2V5KTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnByZXBhcmVkQ29kZXNcIiwgcHJlcGFyZWRDb2Rlcyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29ubnMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgICBlcnJvcjogY29ubmVjdGlvblN0YXR1c2VzLmZpbmQoKHsgZXJyb3IgfSkgPT4gZXJyb3IgIT09IHVuZGVmaW5lZCk/LmVycm9yLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog64yA7IOBIERC7JeQIHBlbmRpbmcg66eI7J206re466CI7J207IWY7J2EIOyggeyaqe2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCDqsJnsnYAg66mU7ISc65Oc66W8IOyCrOyaqe2VmOupsCwgV2Vi7J2AIGBvblByb2dyZXNzYOulvCBzdHJlYW3snLzroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKlxuICAgKiBAY2F0ZWdvcnkg67aE66as7ZiVIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIGFwcGx5KHRhcmdldHM6IE1pZ3JhdGlvblRhcmdldFtdLCBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMucnVuQWN0aW9uV2l0aFByb2dyZXNzKFwiYXBwbHlcIiwgdGFyZ2V0cywgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICog64yA7IOBIERC7JeQ7IScIOqwgOyepSDstZzqt7wgbWlncmF0aW9uIGJhdGNo66W8IOuhpOuwse2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCDqsJnsnYAg66mU7ISc65Oc66W8IOyCrOyaqe2VmOupsCwgV2Vi7J2AIGBvblByb2dyZXNzYOulvCBzdHJlYW3snLzroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKlxuICAgKiBAY2F0ZWdvcnkg67aE66as7ZiVIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrKFxuICAgIHRhcmdldHM6IE1pZ3JhdGlvblRhcmdldFtdLFxuICAgIG9wdGlvbnM/OiBNaWdyYXRpb25SdW5PcHRpb25zLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIHJldHVybiB0aGlzLnJ1bkFjdGlvbldpdGhQcm9ncmVzcyhcInJvbGxiYWNrXCIsIHRhcmdldHMsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIGFjdGlvbiDrrLjsnpDsl7Qg64yA7IugIHtAbGluayBhcHBseX0g65iQ64qUIHtAbGluayByb2xsYmFja33snYQg7KeB7KCRIOyCrOyaqe2VqeuLiOuLpC5cbiAgICog6riw7KG0IOyZuOu2gCDtmLjstpzsnZgg7ZWY7JyEIO2YuO2ZmOunjOydhCDsnITtlbQg7Jyg7KeA7ZWp64uI64ukLlxuICAgKiBAY2F0ZWdvcnkg7Zi47ZmY7JqpIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10sXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgcmV0dXJuIGFjdGlvbiA9PT0gXCJhcHBseVwiID8gdGhpcy5hcHBseSh0YXJnZXRzKSA6IHRoaXMucm9sbGJhY2sodGFyZ2V0cyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJ1bkFjdGlvbldpdGhQcm9ncmVzcyhcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiBNaWdyYXRpb25UYXJnZXRbXSxcbiAgICBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOmFjdGlvblwiLCBhY3Rpb24pO1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246dGFyZ2V0c1wiLCB0YXJnZXRzKTtcblxuICAgIGNvbnN0IGFsbG93ZWRUYXJnZXRzID0gbmV3IFNldCh0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKSk7XG4gICAgY29uc3QgZGlzYWxsb3dlZFRhcmdldHMgPSB0YXJnZXRzLmZpbHRlcigodGFyZ2V0KSA9PiAhYWxsb3dlZFRhcmdldHMuaGFzKHRhcmdldCkpO1xuICAgIGlmIChkaXNhbGxvd2VkVGFyZ2V0cy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNaWdyYXRpb24gdGFyZ2V0cyBhcmUgbm90IGFsbG93ZWQgaW4gTk9ERV9FTlY9JHtnZXRTb25hbXVFbnZpcm9ubWVudCgpfTogJHtkaXNhbGxvd2VkVGFyZ2V0cy5qb2luKFwiLCBcIil9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IHVuaXEga25leCBjb25maWdzXG4gICAgY29uc3QgY29uZmlncyA9IHVuaXF1ZShcbiAgICAgIHRhcmdldHNcbiAgICAgICAgLm1hcCgodGFyZ2V0KSA9PiAoe1xuICAgICAgICAgIGNvbm5LZXk6IHRhcmdldCxcbiAgICAgICAgICBvcHRpb25zOiBTb25hbXUuZGJDb25maWdbdGFyZ2V0XSxcbiAgICAgICAgfSkpXG4gICAgICAgIC5maWx0ZXIoKGMpID0+IGMub3B0aW9ucyAhPT0gdW5kZWZpbmVkKSxcbiAgICAgICh7IG9wdGlvbnM6IGRiT3B0aW9ucyB9KSA9PlxuICAgICAgICBgJHsvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIChkYk9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykuaG9zdH06JHtcbiAgICAgICAgICAvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIChcbiAgICAgICAgICAgIGRiT3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnXG4gICAgICAgICAgKS5wb3J0ID8/IDU0MzJcbiAgICAgICAgfS8key8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gKGRiT3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gLFxuICAgICk7XG5cbiAgICAvLyBnZXQgY29ubmVjdGlvbnNcbiAgICBjb25zdCBjb25ucyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29uZmlncy5tYXAoYXN5bmMgKGNvbmZpZykgPT4gKHtcbiAgICAgICAgY29ubktleTogY29uZmlnLmNvbm5LZXksXG4gICAgICAgIGtuZXg6IGNyZWF0ZUtuZXhJbnN0YW5jZShjb25maWcub3B0aW9ucyksXG4gICAgICB9KSksXG4gICAgKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoY29ubnMsIGFjdGlvbiwgb3B0aW9ucyk7XG5cbiAgICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246cmVzdWx0XCIsIHJlc3VsdCk7XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGtuZXguZGVzdHJveSgpO1xuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZW5EYXRlVGFnKGluZGV4OiBudW1iZXIsIGJhc2VEYXRlOiBEYXRlID0gbmV3IERhdGUoKSk6IHN0cmluZyB7XG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGJhc2VEYXRlLmdldFRpbWUoKSArIGluZGV4ICogMTAwMCk7XG4gICAgcmV0dXJuIChcbiAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0TW9udGgoKSArIDEpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0RGF0ZSgpKSArXG4gICAgICBwYWREYXRlUGFydChkYXRlLmdldEhvdXJzKCkpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0TWludXRlcygpKSArXG4gICAgICBwYWREYXRlUGFydChkYXRlLmdldFNlY29uZHMoKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGVQcmVwYXJlZENvZGVzKGNvbXBhcmVDb25uS2V5PzogTWlncmF0aW9uVGFyZ2V0KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBwcmVwYXJlZENvZGVzID1cbiAgICAgIGNvbXBhcmVDb25uS2V5ID09PSB1bmRlZmluZWRcbiAgICAgICAgPyAoYXdhaXQgdGhpcy5nZXRTdGF0dXMoKSkucHJlcGFyZWRDb2Rlc1xuICAgICAgICA6IGF3YWl0IHRoaXMuZ2V0UHJlcGFyZWRDb2Rlcyhjb21wYXJlQ29ubktleSk7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdlbmVyYXRlUHJlcGFyZWRDb2RlczpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuICAgIGlmIChwcmVwYXJlZENvZGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJcXG7tmITsnqwg66qo65GQIOyLse2BrOuQnCDsg4Htg5zsnoXri4jri6QuXCIpKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIC8vIOyLpOygnCDsvZTrk5wg7IOd7ISxXG4gICAgY29uc3QgbWlncmF0aW9uc0RpciA9IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnNgO1xuXG4gICAgZm9yIChjb25zdCBbaW5kZXgsIHBjb2RlXSBvZiBwcmVwYXJlZENvZGVzLmVudHJpZXMoKSkge1xuICAgICAgaWYgKHBjb2RlLmZvcm1hdHRlZCkge1xuICAgICAgICBjb25zdCBkYXRlVGFnID0gdGhpcy5nZW5EYXRlVGFnKGluZGV4KTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHttaWdyYXRpb25zRGlyfS8ke2RhdGVUYWd9XyR7cGNvZGUudGl0bGV9LnRzYDtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCBwY29kZS5mb3JtYXR0ZWQpO1xuICAgICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYE1JR1JBVElPTiBDUkVBVEVEICR7ZmlsZVBhdGh9YCkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwcmVwYXJlZENvZGVzLmxlbmd0aDtcbiAgfVxuXG4gIGFzeW5jIGNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQjogS25leCk6IFByb21pc2U8R2VuTWlncmF0aW9uQ29kZVtdPiB7XG4gICAgLy8gRW50aXR5IOyInO2ajO2VmOyXrCDsi7HtgaxcbiAgICBjb25zdCBlbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBFbnRpdHnsl5DshJwgTWlncmF0aW9uU2V0IOy2lOy2nFxuICAgIGNvbnN0IGVudGl0eVNldHNXaXRoSm9pblRhYmxlID0gZW50aXR5SWRzXG4gICAgICAuZmlsdGVyKChlbnRpdHlJZCkgPT4gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpLnByb3BzLmxlbmd0aCA+IDApXG4gICAgICAubWFwKChlbnRpdHlJZCkgPT4gZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eShFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkpKTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lOunjCDstpTstpxcbiAgICBjb25zdCBqb2luVGFibGVzV2l0aER1cCA9IGVudGl0eVNldHNXaXRoSm9pblRhYmxlLmZsYXRNYXAoKGVudGl0eVNldCkgPT4gZW50aXR5U2V0LmpvaW5UYWJsZXMpO1xuICAgIC8vIOykkeuztSDsoJzqsbAgKOykkeuzteyduCDqsr3smrAgaW5kZXhlc+ulvCDrs5HtlakpXG4gICAgY29uc3Qgam9pblRhYmxlcyA9IE9iamVjdC52YWx1ZXMoZ3JvdXAoam9pblRhYmxlc1dpdGhEdXAsIChqdCkgPT4ganQudGFibGUpKS5tYXAoKHRhYmxlcykgPT4ge1xuICAgICAgYXNzZXJ0KHRhYmxlcyAhPT0gdW5kZWZpbmVkLCBcInRhYmxlcyBpcyB1bmRlZmluZWRcIik7XG4gICAgICBpZiAodGFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGFibGVzWzBdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGFibGVzWzBdLFxuICAgICAgICBpbmRleGVzOiB1bmlxdWUoXG4gICAgICAgICAgdGFibGVzLmZsYXRNYXAoKHQpID0+IHQuaW5kZXhlcyksXG4gICAgICAgICAgKGluZGV4KSA9PiBbaW5kZXgudHlwZSwgLi4uaW5kZXguY29sdW1uc10uam9pbihcIi1cIiksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBNaWdyYXRpb25TZXQg67Cw7Je0XG4gICAgY29uc3QgZW50aXR5U2V0czogTWlncmF0aW9uU2V0W10gPSBbLi4uZW50aXR5U2V0c1dpdGhKb2luVGFibGUsIC4uLmpvaW5UYWJsZXNdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IFtdO1xuICAgIGNvbnN0IGJhdGNoU2l6ZSA9IDQ7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVudGl0eVNldHMubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgICAgY29uc3QgYmF0Y2hDb2RlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBQb3N0Z3JlU1FMU2NoZW1hUmVhZGVyLmdldE1pZ3JhdGlvblNldEZyb21EQihcbiAgICAgICAgICAgIGNvbXBhcmVEQixcbiAgICAgICAgICAgIGVudGl0eVNldC50YWJsZSxcbiAgICAgICAgICApO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmVudGl0eVNldDoke2VudGl0eVNldC50YWJsZX1gLCBlbnRpdHlTZXQpO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmRiU2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGRiU2V0KTtcblxuICAgICAgICAgIGlmIChkYlNldCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsl4bsnYwsIOyDiOuhnCDthYzsnbTruJQg7IOd7ISxXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVDcmVhdGVDb2RlKGVudGl0eVNldCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7KG07J6s7ZWY64qUIOy8gOydtOyKpFxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQWx0ZXJDb2RlKGVudGl0eVNldCwgZGJTZXQsIGNvbXBhcmVEQik7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIGNvZGVzLnB1c2goLi4uYmF0Y2hDb2Rlcy5mbGF0KCkpO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbCDtg4DsnoXsnbQg7JWe7Jy866GcLCBmb3JlaWdu7J20IOuSpOuhnFxuICAgIGNvZGVzLnNvcnQoKGNvZGVBLCBjb2RlQikgPT4ge1xuICAgICAgaWYgKGNvZGVBLnR5cGUgPT09IFwiZm9yZWlnblwiICYmIGNvZGVCLnR5cGUgPT09IFwibm9ybWFsXCIpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9IGVsc2UgaWYgKGNvZGVBLnR5cGUgPT09IFwibm9ybWFsXCIgJiYgY29kZUIudHlwZSA9PT0gXCJmb3JlaWduXCIpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICogdGVzdCBEQuydmCBzbmFwc2hvdOycvOuhnCDsnoTsi5wgU2hhZG93IERC66W8IOunjOuTpOqzoCDsoITssrQg66eI7J206re466CI7J207IWY7J2EIOqygOymne2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCBgb25Qcm9ncmVzc2Ag7Jyg66y066eMIOuLrOumrO2VtCDqsJnsnYAg7Iuk7ZaJIOydmOuvuOulvCDqs7XsnKDtlaAg7IiYIOyeiOyKteuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBydW5TaGFkb3dUZXN0KG9wdGlvbnM/OiBNaWdyYXRpb25SdW5PcHRpb25zKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCBiYXNlVGVzdENvbm4gPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBTb25hbXUuZGJDb25maWdcbiAgICAgICAgLnRlc3QuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCB3b3JrZXJJZCA9IHByb2Nlc3MuZW52LlNPTkFNVV9XT1JLRVJfREIgPT09IFwidHJ1ZVwiID8gcHJvY2Vzcy5lbnYuVklURVNUX1BPT0xfSUQgOiBudWxsO1xuICAgIGNvbnN0IHRlbXBsYXRlRGF0YWJhc2UgPVxuICAgICAgd29ya2VySWQgIT09IG51bGwgPyBgJHtiYXNlVGVzdENvbm4uZGF0YWJhc2V9XyR7d29ya2VySWQgPz8gXCIxXCJ9YCA6IGJhc2VUZXN0Q29ubi5kYXRhYmFzZTtcbiAgICBjb25zdCB0ZGJDb25uID0geyAuLi5iYXNlVGVzdENvbm4sIGRhdGFiYXNlOiB0ZW1wbGF0ZURhdGFiYXNlIH07XG4gICAgY29uc3Qgc2hhZG93RGF0YWJhc2UgPSBgJHt0ZW1wbGF0ZURhdGFiYXNlfV9fbWlncmF0aW9uX3NoYWRvd2A7XG5cbiAgICAvLyDthYzsiqTtirgg7IOB7Zmp7JeQ7ISc64qUIO2KuOuenOyereyFmOydhCDstIjquLDtmZTtlZjqs6AsIOyDiCDrjbDsnbTthLDrsqDsnbTsiqQg7Luk64Sl7IWY7J2EIOqwgOyguOyZgOyVvCDtlahcbiAgICBpZiAoaXNUZXN0KCkpIHtcbiAgICAgIGF3YWl0IERCLmNsZWFyVGVzdFRyYW5zYWN0aW9uKCk7XG4gICAgICBhd2FpdCBEQi5kZXN0cm95KCk7XG4gICAgfVxuXG4gICAgLy8g6riw7KG0IFNoYWRvdyBEQiDsgq3soJwg7ZuEIFNoYWRvdyBEQiDsg53shLFcbiAgICBjb25zdCB0ZGIgPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgLi4uU29uYW11LmRiQ29uZmlnLnRlc3QsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLmJhc2VUZXN0Q29ubixcbiAgICAgICAgZGF0YWJhc2U6IFwicG9zdGdyZXNcIixcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDsgq3soJxgKSk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgXG4gICAgICAgIFNFTEVDVCBwZ190ZXJtaW5hdGVfYmFja2VuZChwZ19zdGF0X2FjdGl2aXR5LnBpZClcbiAgICAgICAgRlJPTSBwZ19zdGF0X2FjdGl2aXR5XG4gICAgICAgIFdIRVJFIGRhdG5hbWUgPSAnJHt0ZGJDb25uLmRhdGFiYXNlfSdcbiAgICAgICAgICBBTkQgcGlkIDw+IHBnX2JhY2tlbmRfcGlkKCk7XG4gICAgICBgKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSAke3NoYWRvd0RhdGFiYXNlfSBURU1QTEFURSAke3RkYkNvbm4uZGF0YWJhc2V9YCk7XG5cbiAgICAgIC8vIFNoYWRvdyBEQuyXkCDsl7DqsrBcbiAgICAgIGNvbnN0IHNkYiA9IGNyZWF0ZUtuZXhJbnN0YW5jZSh7XG4gICAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgICAgLi4udGRiQ29ubixcbiAgICAgICAgICBkYXRhYmFzZTogc2hhZG93RGF0YWJhc2UsXG4gICAgICAgICAgcGFzc3dvcmQ6IHRkYkNvbm4ucGFzc3dvcmQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gc2hhZG93IERCIO2FjOyKpO2KuCDsp4TtlolcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzID0gdGhpcy5jcmVhdGVQcm9ncmVzc0hvb2tzKFwic2hhZG93XCIsIFwic2hhZG93XCIsIG9wdGlvbnMpO1xuICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QocHJvZ3Jlc3MpO1xuICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlNoYWRvdyBEQiDthYzsiqTtirjsl5Ag7ISx6rO17ZaI7Iq164uI64ukIVwiKSwge1xuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3Mob3B0aW9ucywge1xuICAgICAgICAgIHR5cGU6IFwidGFyZ2V0LWNvbXBsZXRlXCIsXG4gICAgICAgICAgYWN0aW9uOiBcInNoYWRvd1wiLFxuICAgICAgICAgIGNvbm5LZXk6IFwic2hhZG93XCIsXG4gICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICBmaWxlczogYXBwbGllZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgdGhyb3cgbmV3IE1pZ3JhdGlvblRhcmdldEV4ZWN1dGlvbkVycm9yKFxuICAgICAgICAgIFwic2hhZG93XCIsXG4gICAgICAgICAgbmV3IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbihTRChcInNvbmFtdS5lcnJvci5zaGFkb3dEYlRlc3RGYWlsZWRcIikpLFxuICAgICAgICApO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgc2RiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gU2hhZG93IERCIOyCreygnFxuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJTaGFkb3cgREIg7KCV66asIOyLpO2MqDpcIiwgZSk7IC8vIOydtOqyjCDsl4bsnLzrqbQg7KGw7Jqp7Z6IIOuIhOyImFxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgdGRiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTJDQSxTQUFTLFlBQVksUUFBZ0IsT0FBZSxHQUFXO0NBQzdELE9BQU8sT0FBTyxTQUFTLENBQUMsQ0FBQyxTQUFTLE1BQU0sR0FBRztBQUM3Qzs7Ozs7QUFzQkEsU0FBUyxZQUFlLFNBQXFCLElBQVksV0FBb0M7Q0FDM0YsT0FBTyxJQUFJLFNBQVksU0FBUyxXQUFXO0VBQ3pDLE1BQU0sUUFBUSxpQkFBaUIsT0FBTyxVQUFVLENBQUMsR0FBRyxFQUFFO0VBQ3RELFFBQVEsTUFDTCxVQUFVO0dBQ1QsYUFBYSxLQUFLO0dBQ2xCLFFBQVEsS0FBSztFQUNmLElBQ0MsVUFBVTtHQUNULGFBQWEsS0FBSztHQUNsQixPQUFPLEtBQUs7RUFDZCxDQUNGO0NBQ0YsQ0FBQztBQUNIOzs7YUF6RXNDO1NBQ0g7V0FFa0I7U0FDdEI7cUJBQ3lCO1VB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
|