sonamu 0.6.0 → 0.7.1
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/.swcrc.project-default +18 -0
- package/bin/cli.js +24 -0
- package/dist/ai/agents/agent.d.ts +11 -0
- package/dist/ai/agents/agent.d.ts.map +1 -0
- package/dist/ai/agents/agent.js +65 -0
- package/dist/ai/agents/index.d.ts +3 -0
- package/dist/ai/agents/index.d.ts.map +1 -0
- package/dist/ai/agents/index.js +4 -0
- package/dist/ai/agents/types.d.ts +43 -0
- package/dist/ai/agents/types.d.ts.map +1 -0
- package/dist/ai/agents/types.js +3 -0
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +3 -0
- package/dist/ai/providers/rtzr/api.d.ts +22 -0
- package/dist/ai/providers/rtzr/api.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/api.js +28 -0
- package/dist/ai/providers/rtzr/error.d.ts +18 -0
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/error.js +29 -0
- package/dist/ai/providers/rtzr/index.d.ts +5 -0
- package/dist/ai/providers/rtzr/index.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/index.js +6 -0
- package/dist/ai/providers/rtzr/model.d.ts +52 -0
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/model.js +137 -0
- package/dist/ai/providers/rtzr/options.d.ts +7 -0
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/options.js +47 -0
- package/dist/ai/providers/rtzr/provider.d.ts +18 -0
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/provider.js +54 -0
- package/dist/ai/providers/rtzr/utils.d.ts +19 -0
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/utils.js +88 -0
- package/dist/api/base-frame.d.ts +2 -2
- package/dist/api/base-frame.d.ts.map +1 -1
- package/dist/api/base-frame.js +2 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +6 -1
- package/dist/api/code-converters.d.ts +58 -14
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +178 -409
- package/dist/api/config.d.ts +27 -13
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +19 -26
- package/dist/api/context.d.ts +4 -3
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts +20 -6
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +111 -18
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -3
- package/dist/api/sonamu.d.ts +7 -7
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +83 -51
- package/dist/api/validator.d.ts +6 -0
- package/dist/api/validator.d.ts.map +1 -0
- package/dist/api/validator.js +81 -0
- package/dist/bin/build-config.d.ts +5 -1
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +5 -2
- package/dist/bin/cli.js +165 -64
- package/dist/bin/loader-register.d.ts +2 -0
- package/dist/bin/loader-register.d.ts.map +1 -0
- package/dist/bin/loader-register.js +34 -0
- package/dist/database/_batch_update.d.ts +5 -3
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +30 -13
- package/dist/database/base-model.d.ts +96 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +232 -89
- package/dist/database/base-model.types.d.ts +93 -0
- package/dist/database/base-model.types.d.ts.map +1 -0
- package/dist/database/base-model.types.js +10 -0
- package/dist/database/code-generator.d.ts +1 -1
- package/dist/database/code-generator.d.ts.map +1 -1
- package/dist/database/code-generator.js +11 -10
- package/dist/database/db.d.ts +5 -6
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +22 -25
- package/dist/database/puri-subset.test-d.js +81 -0
- package/dist/database/puri-subset.types.d.ts +123 -0
- package/dist/database/puri-subset.types.d.ts.map +1 -0
- package/dist/database/puri-subset.types.js +16 -0
- package/dist/database/puri-wrapper.d.ts +13 -11
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +2 -2
- package/dist/database/puri.d.ts +25 -14
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +83 -21
- package/dist/database/puri.types.d.ts +21 -7
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +4 -1
- package/dist/database/transaction-context.d.ts +1 -1
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +1 -1
- package/dist/database/upsert-builder.d.ts +9 -3
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +227 -78
- package/dist/entity/entity-manager.d.ts +165 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +26 -10
- package/dist/entity/entity.d.ts +5 -3
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +153 -54
- package/dist/exceptions/error-handler.d.ts +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +1 -1
- package/dist/exceptions/so-exceptions.d.ts +1 -1
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +1 -1
- package/dist/file-storage/driver.d.ts +1 -1
- package/dist/file-storage/driver.d.ts.map +1 -1
- package/dist/file-storage/driver.js +1 -1
- package/dist/file-storage/file-storage.js +2 -2
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -13
- package/dist/migration/code-generation.d.ts +1 -1
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +123 -67
- package/dist/migration/migration-set.d.ts +2 -10
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +67 -218
- package/dist/migration/migrator.d.ts +24 -73
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +121 -301
- package/dist/migration/postgresql-schema-reader.d.ts +51 -0
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
- package/dist/migration/postgresql-schema-reader.js +245 -0
- package/dist/migration/types.d.ts +6 -38
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/migration/types.js +1 -1
- package/dist/naite/messaging-types.d.ts +43 -0
- package/dist/naite/messaging-types.d.ts.map +1 -0
- package/dist/naite/messaging-types.js +7 -0
- package/dist/naite/naite-reporter.d.ts +41 -0
- package/dist/naite/naite-reporter.d.ts.map +1 -0
- package/dist/naite/naite-reporter.js +102 -0
- package/dist/naite/naite.d.ts +91 -8
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +285 -41
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +1 -1
- package/dist/syncer/api-parser.d.ts +3 -13
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +67 -56
- package/dist/syncer/checksum.d.ts +2 -2
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +11 -11
- package/dist/syncer/code-generator.d.ts +3 -3
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +37 -17
- package/dist/syncer/entity-operations.d.ts +2 -2
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +9 -8
- package/dist/syncer/file-patterns.d.ts +1 -1
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +1 -1
- package/dist/syncer/index.d.ts +4 -4
- package/dist/syncer/index.d.ts.map +1 -1
- package/dist/syncer/index.js +5 -5
- package/dist/syncer/module-loader.d.ts +4 -4
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +17 -12
- package/dist/syncer/syncer.d.ts +31 -24
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +92 -45
- 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 +15 -8
- package/dist/template/helpers.d.ts +2 -2
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +3 -3
- package/dist/template/implementations/entity.template.d.ts +2 -2
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.js +4 -5
- package/dist/template/implementations/generated.template.d.ts +2 -3
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +46 -29
- package/dist/template/implementations/generated_http.template.d.ts +2 -3
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +9 -9
- package/dist/template/implementations/generated_sso.template.d.ts +3 -4
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +54 -25
- package/dist/template/implementations/init_types.template.d.ts +2 -2
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.js +2 -2
- package/dist/template/implementations/model.template.d.ts +2 -2
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +47 -37
- package/dist/template/implementations/model_test.template.d.ts +2 -2
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.js +2 -2
- package/dist/template/implementations/service.template.d.ts +4 -4
- package/dist/template/implementations/service.template.d.ts.map +1 -1
- package/dist/template/implementations/service.template.js +24 -16
- package/dist/template/implementations/view_enums_buttonset.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_buttonset.template.js +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.js +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_select.template.js +2 -2
- package/dist/template/implementations/view_form.template.d.ts +2 -2
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +4 -4
- package/dist/template/implementations/view_id_all_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.js +1 -1
- package/dist/template/implementations/view_id_async_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_async_select.template.js +1 -1
- package/dist/template/implementations/view_list.template.d.ts +2 -2
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +29 -19
- package/dist/template/implementations/view_list_columns.template.d.ts +3 -3
- package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list_columns.template.js +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts +2 -2
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +1 -1
- package/dist/template/index.d.ts +4 -2
- package/dist/template/index.d.ts.map +1 -1
- package/dist/template/index.js +5 -3
- package/dist/template/template-manager.d.ts +56 -0
- package/dist/template/template-manager.d.ts.map +1 -0
- package/dist/template/template-manager.js +125 -0
- package/dist/template/template-types.d.ts +16 -0
- package/dist/template/template-types.d.ts.map +1 -0
- package/dist/template/template-types.js +7 -0
- package/dist/template/template.d.ts +12 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +19 -6
- package/dist/template/zod-converter.d.ts +40 -7
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +386 -58
- package/dist/testing/_relation-graph.d.ts +1 -1
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +12 -3
- package/dist/testing/fixture-manager.d.ts +42 -11
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +338 -236
- package/dist/types/types.d.ts +709 -104
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +309 -52
- package/dist/typings/knex.d.js +2 -2
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +3 -3
- package/dist/utils/console-util.js +1 -1
- package/dist/utils/controller.d.ts +1 -0
- package/dist/utils/controller.d.ts.map +1 -1
- package/dist/utils/controller.js +4 -1
- package/dist/utils/esm-utils.d.ts +0 -6
- package/dist/utils/esm-utils.d.ts.map +1 -1
- package/dist/utils/esm-utils.js +2 -9
- package/dist/utils/formatter.d.ts +3 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +110 -0
- package/dist/utils/fs-utils.d.ts +1 -1
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +1 -1
- package/dist/utils/lodash-able.d.ts.map +1 -1
- package/dist/utils/lodash-able.js +1 -1
- package/dist/utils/object-utils.d.ts +44 -0
- package/dist/utils/object-utils.d.ts.map +1 -0
- package/dist/utils/object-utils.js +191 -0
- package/dist/utils/path-utils.d.ts +1 -1
- package/dist/utils/path-utils.d.ts.map +1 -1
- package/dist/utils/path-utils.js +3 -3
- package/dist/utils/process-utils.js +1 -1
- package/dist/utils/sql-parser.d.ts +5 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +14 -3
- package/dist/utils/type-utils.d.ts +23 -0
- package/dist/utils/type-utils.d.ts.map +1 -0
- package/dist/utils/type-utils.js +45 -0
- package/dist/utils/utils.d.ts +7 -1
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +44 -5
- package/dist/utils/zod-error.d.ts +1 -1
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +1 -1
- package/package.json +55 -30
- package/src/ai/agents/agent.ts +87 -0
- package/src/ai/agents/index.ts +2 -0
- package/src/ai/agents/types.ts +47 -0
- package/src/ai/index.ts +1 -0
- package/src/ai/providers/rtzr/api.ts +37 -0
- package/src/ai/providers/rtzr/error.ts +34 -0
- package/src/ai/providers/rtzr/index.ts +4 -0
- package/src/ai/providers/rtzr/model.ts +201 -0
- package/src/ai/providers/rtzr/options.ts +49 -0
- package/src/ai/providers/rtzr/provider.ts +91 -0
- package/src/ai/providers/rtzr/utils.ts +127 -0
- package/src/api/base-frame.ts +4 -2
- package/src/api/caster.ts +17 -23
- package/src/api/code-converters.ts +176 -533
- package/src/api/config.ts +39 -56
- package/src/api/context.ts +7 -18
- package/src/api/decorators.ts +175 -46
- package/src/api/index.ts +2 -2
- package/src/api/sonamu.ts +133 -124
- package/src/api/validator.ts +83 -0
- package/src/bin/build-config.ts +7 -1
- package/src/bin/cli.ts +192 -110
- package/src/bin/loader-register.ts +38 -0
- package/src/database/_batch_update.ts +46 -31
- package/src/database/base-model.ts +390 -182
- package/src/database/base-model.types.ts +155 -0
- package/src/database/code-generator.ts +13 -32
- package/src/database/db.ts +36 -50
- package/src/database/puri-subset.test-d.ts +471 -0
- package/src/database/puri-subset.types.ts +195 -0
- package/src/database/puri-wrapper.ts +58 -67
- package/src/database/puri.ts +182 -126
- package/src/database/puri.types.ts +64 -31
- package/src/database/transaction-context.ts +1 -1
- package/src/database/upsert-builder.ts +261 -132
- package/src/entity/entity-manager.ts +36 -28
- package/src/entity/entity.ts +330 -249
- package/src/exceptions/error-handler.ts +3 -3
- package/src/exceptions/so-exceptions.ts +11 -11
- package/src/file-storage/driver.ts +5 -5
- package/src/file-storage/file-storage.ts +2 -2
- package/src/index.ts +18 -12
- package/src/migration/code-generation.ts +185 -172
- package/src/migration/migration-set.ts +80 -293
- package/src/migration/migrator.ts +182 -425
- package/src/migration/mysql-schema-reader.ts.txt +272 -0
- package/src/migration/postgresql-schema-reader.ts +310 -0
- package/src/migration/types.ts +6 -39
- package/src/naite/messaging-types.ts +51 -0
- package/src/naite/naite-reporter.ts +128 -0
- package/src/naite/naite.ts +378 -33
- package/src/shared/web.shared.ts.txt +20 -24
- package/src/stream/sse.ts +5 -5
- package/src/syncer/api-parser.ts +52 -69
- package/src/syncer/checksum.ts +25 -37
- package/src/syncer/code-generator.ts +58 -62
- package/src/syncer/entity-operations.ts +12 -15
- package/src/syncer/file-patterns.ts +2 -2
- package/src/syncer/index.ts +4 -4
- package/src/syncer/module-loader.ts +28 -25
- package/src/syncer/syncer.ts +155 -162
- package/src/template/entity-converter.ts +18 -27
- package/src/template/helpers.ts +8 -11
- package/src/template/implementations/entity.template.ts +6 -6
- package/src/template/implementations/generated.template.ts +99 -99
- package/src/template/implementations/generated_http.template.ts +21 -54
- package/src/template/implementations/generated_sso.template.ts +78 -65
- package/src/template/implementations/init_types.template.ts +4 -6
- package/src/template/implementations/model.template.ts +47 -38
- package/src/template/implementations/model_test.template.ts +3 -3
- package/src/template/implementations/service.template.ts +56 -80
- package/src/template/implementations/view_enums_buttonset.template.ts +2 -2
- package/src/template/implementations/view_enums_dropdown.template.ts +4 -4
- package/src/template/implementations/view_enums_select.template.ts +3 -3
- package/src/template/implementations/view_form.template.ts +34 -75
- package/src/template/implementations/view_id_all_select.template.ts +2 -2
- package/src/template/implementations/view_id_async_select.template.ts +9 -23
- package/src/template/implementations/view_list.template.ts +54 -95
- package/src/template/implementations/view_list_columns.template.ts +4 -10
- package/src/template/implementations/view_search_input.template.ts +2 -2
- package/src/template/index.ts +4 -2
- package/src/template/template-manager.ts +166 -0
- package/src/template/template-types.ts +16 -0
- package/src/template/template.ts +29 -10
- package/src/template/zod-converter.ts +459 -101
- package/src/testing/_relation-graph.ts +18 -11
- package/src/testing/fixture-manager.ts +468 -362
- package/src/types/types.ts +516 -248
- package/src/typings/knex.d.ts +7 -9
- package/src/utils/async-utils.ts +8 -12
- package/src/utils/console-util.ts +1 -1
- package/src/utils/controller.ts +3 -0
- package/src/utils/esm-utils.ts +8 -18
- package/src/utils/formatter.ts +109 -0
- package/src/utils/fs-utils.ts +1 -1
- package/src/utils/lodash-able.ts +1 -4
- package/src/utils/object-utils.ts +217 -0
- package/src/utils/path-utils.ts +3 -6
- package/src/utils/process-utils.ts +1 -1
- package/src/utils/sql-parser.ts +23 -5
- package/src/utils/type-utils.ts +83 -0
- package/src/utils/utils.ts +58 -9
- package/src/utils/zod-error.ts +3 -3
- package/dist/bin/cli-wrapper.d.ts +0 -3
- package/dist/bin/cli-wrapper.d.ts.map +0 -1
- package/dist/bin/cli-wrapper.js +0 -72
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
- package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -39
- package/dist/entity/entity-utils.d.ts +0 -61
- package/dist/entity/entity-utils.d.ts.map +0 -1
- package/dist/entity/entity-utils.js +0 -210
- package/src/bin/cli-wrapper.ts +0 -82
- package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
- package/src/entity/entity-utils.ts +0 -291
|
@@ -1,57 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import knex from "knex";
|
|
1
|
+
import assert from "assert";
|
|
3
2
|
import chalk from "chalk";
|
|
4
|
-
import { DateTime } from "luxon";
|
|
5
3
|
import { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
|
|
6
|
-
import
|
|
7
|
-
import prompts from "prompts";
|
|
8
|
-
import { execSync } from "child_process";
|
|
4
|
+
import knex from "knex";
|
|
9
5
|
import path from "path";
|
|
10
|
-
import {
|
|
6
|
+
import { group, sum, unique } from "radashi";
|
|
11
7
|
import { Sonamu } from "../api/index.js";
|
|
8
|
+
import { DB } from "../database/db.js";
|
|
9
|
+
import { EntityManager } from "../entity/entity-manager.js";
|
|
12
10
|
import { ServiceUnavailableException } from "../exceptions/so-exceptions.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { Naite } from "../naite/naite.js";
|
|
12
|
+
import { isTest } from "../utils/controller.js";
|
|
13
|
+
import { exists } from "../utils/fs-utils.js";
|
|
14
|
+
import { generateAlterCode, generateCreateCode } from "./code-generation.js";
|
|
15
15
|
import { getMigrationSetFromEntity } from "./migration-set.js";
|
|
16
|
+
import { PostgreSQLSchemaReader } from "./postgresql-schema-reader.js";
|
|
16
17
|
export class Migrator {
|
|
17
|
-
options;
|
|
18
|
-
targets;
|
|
19
|
-
constructor(options){
|
|
20
|
-
this.options = options;
|
|
21
|
-
const { dbConfig } = Sonamu;
|
|
22
|
-
if (this.options.mode === "dev") {
|
|
23
|
-
const devDB = knex(dbConfig.development_master);
|
|
24
|
-
const testDB = knex(dbConfig.test);
|
|
25
|
-
const fixtureLocalDB = knex(dbConfig.fixture_local);
|
|
26
|
-
const applyDBs = [
|
|
27
|
-
devDB,
|
|
28
|
-
testDB,
|
|
29
|
-
fixtureLocalDB
|
|
30
|
-
];
|
|
31
|
-
if (dbConfig.fixture_local.connection.host !== dbConfig.fixture_remote.connection.host || dbConfig.fixture_local.connection.database !== dbConfig.fixture_remote.connection.database) {
|
|
32
|
-
const fixtureRemoteDB = knex(dbConfig.fixture_remote);
|
|
33
|
-
applyDBs.push(fixtureRemoteDB);
|
|
34
|
-
}
|
|
35
|
-
this.targets = {
|
|
36
|
-
compare: devDB,
|
|
37
|
-
pending: devDB,
|
|
38
|
-
shadow: testDB,
|
|
39
|
-
apply: applyDBs
|
|
40
|
-
};
|
|
41
|
-
} else if (this.options.mode === "deploy") {
|
|
42
|
-
const productionDB = knex(dbConfig.production_master);
|
|
43
|
-
const testDB = knex(dbConfig.test);
|
|
44
|
-
this.targets = {
|
|
45
|
-
pending: productionDB,
|
|
46
|
-
shadow: testDB,
|
|
47
|
-
apply: [
|
|
48
|
-
productionDB
|
|
49
|
-
]
|
|
50
|
-
};
|
|
51
|
-
} else {
|
|
52
|
-
throw new Error(`잘못된 모드 ${this.options.mode} 입력`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
18
|
async getMigrationCodes() {
|
|
56
19
|
const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations"); // 이건 환경에 관계없이 항상 src에서 찾아야 해요.
|
|
57
20
|
if (!await exists(srcMigrationsDir)) {
|
|
@@ -63,6 +26,7 @@ export class Migrator {
|
|
|
63
26
|
name: f.replace(".ts", ""),
|
|
64
27
|
path: path.join(srcMigrationsDir, f)
|
|
65
28
|
})).sort((a, b)=>a.name < b.name ? 1 : -1); // 이름 내림차순 정렬(최신순)
|
|
29
|
+
Naite.t("migrator:getMigrationCodes:results", codes);
|
|
66
30
|
return codes;
|
|
67
31
|
}
|
|
68
32
|
/**
|
|
@@ -75,7 +39,9 @@ export class Migrator {
|
|
|
75
39
|
* @returns
|
|
76
40
|
*/ async getStatus() {
|
|
77
41
|
const codes = await this.getMigrationCodes();
|
|
42
|
+
Naite.t("migrator:getStatus:codes", codes);
|
|
78
43
|
const connKeys = Object.keys(Sonamu.dbConfig).filter((key)=>key.endsWith("_slave") === false);
|
|
44
|
+
let migrationStatusError;
|
|
79
45
|
const statuses = await Promise.all(connKeys.map(async (connKey)=>{
|
|
80
46
|
const knexOptions = Sonamu.dbConfig[connKey];
|
|
81
47
|
const tConn = knex(knexOptions);
|
|
@@ -84,7 +50,8 @@ export class Migrator {
|
|
|
84
50
|
return await tConn.migrate.status();
|
|
85
51
|
} catch (err) {
|
|
86
52
|
console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
|
|
87
|
-
|
|
53
|
+
migrationStatusError = err instanceof Error ? err.message : String(err);
|
|
54
|
+
return "error";
|
|
88
55
|
}
|
|
89
56
|
})();
|
|
90
57
|
const pending = await (async ()=>{
|
|
@@ -92,27 +59,31 @@ export class Migrator {
|
|
|
92
59
|
const [, fdList] = await tConn.migrate.list();
|
|
93
60
|
return fdList.map((fd)=>fd.file.replace(".ts", ""));
|
|
94
61
|
} catch (err) {
|
|
62
|
+
migrationStatusError = err instanceof Error ? err.message : String(err);
|
|
95
63
|
return [];
|
|
96
64
|
}
|
|
97
65
|
})();
|
|
98
66
|
const currentVersion = await (async ()=>{
|
|
99
67
|
try {
|
|
100
68
|
return await tConn.migrate.currentVersion();
|
|
101
|
-
} catch (
|
|
69
|
+
} catch (_err) {
|
|
70
|
+
migrationStatusError = _err instanceof Error ? _err.message : String(_err);
|
|
102
71
|
return "error";
|
|
103
72
|
}
|
|
104
73
|
})();
|
|
74
|
+
Naite.t("migrator:getStatus:status", status);
|
|
105
75
|
const connection = knexOptions.connection;
|
|
106
76
|
await tConn.destroy();
|
|
107
77
|
return {
|
|
108
78
|
name: connKey.replace("_master", ""),
|
|
109
79
|
connKey,
|
|
110
|
-
connString: `
|
|
80
|
+
connString: `pg://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`,
|
|
111
81
|
currentVersion,
|
|
112
|
-
status,
|
|
82
|
+
status: status,
|
|
113
83
|
pending
|
|
114
84
|
};
|
|
115
85
|
}));
|
|
86
|
+
Naite.t("migrator:getStatus:conns", statuses);
|
|
116
87
|
const preparedCodes = await (async ()=>{
|
|
117
88
|
const status0conn = statuses.find((status)=>status.status === 0);
|
|
118
89
|
if (status0conn === undefined) {
|
|
@@ -124,20 +95,14 @@ export class Migrator {
|
|
|
124
95
|
await compareDBconn.destroy();
|
|
125
96
|
return genCodes;
|
|
126
97
|
})();
|
|
98
|
+
Naite.t("migrator:getStatus:preparedCodes", preparedCodes);
|
|
127
99
|
return {
|
|
128
100
|
conns: statuses,
|
|
129
101
|
codes,
|
|
130
|
-
preparedCodes
|
|
102
|
+
preparedCodes,
|
|
103
|
+
error: migrationStatusError
|
|
131
104
|
};
|
|
132
|
-
|
|
133
|
-
DB 마이그레이션 상태 확인
|
|
134
|
-
1. 전체 DB설정에 대해서 현재 마이그레이션 상태 확인
|
|
135
|
-
- connKey: string
|
|
136
|
-
- status: number
|
|
137
|
-
- currentVersion: string
|
|
138
|
-
- list: { file: string; directory: string }[]
|
|
139
|
-
|
|
140
|
-
*/ }
|
|
105
|
+
}
|
|
141
106
|
/**
|
|
142
107
|
* 마이그레이션을 적용하거나 롤백합니다.
|
|
143
108
|
* Sonamu UI에서 마이그레이션 작업을 수행할 때 사용됩니다.
|
|
@@ -148,11 +113,13 @@ export class Migrator {
|
|
|
148
113
|
* @param targets 작업 대상 DB 설정 키 (keyof SonamuDBConfig)
|
|
149
114
|
* @returns 작업 결과
|
|
150
115
|
*/ async runAction(action, targets) {
|
|
116
|
+
Naite.t("migrator:runAction:action", action);
|
|
117
|
+
Naite.t("migrator:runAction:targets", targets);
|
|
151
118
|
// get uniq knex configs
|
|
152
|
-
const configs =
|
|
119
|
+
const configs = unique(targets.map((target)=>({
|
|
153
120
|
connKey: target,
|
|
154
121
|
options: Sonamu.dbConfig[target]
|
|
155
|
-
})).filter((c)=>c.options !== undefined), ({ options })=>`${options.connection.host}:${options.connection.port ??
|
|
122
|
+
})).filter((c)=>c.options !== undefined), ({ options })=>`${options.connection.host}:${options.connection.port ?? 5432}/${options.connection.database}`);
|
|
156
123
|
// get connections
|
|
157
124
|
const conns = await Promise.all(configs.map(async (config)=>({
|
|
158
125
|
connKey: config.connKey,
|
|
@@ -185,9 +152,23 @@ export class Migrator {
|
|
|
185
152
|
await Promise.all(conns.map(({ knex })=>{
|
|
186
153
|
return knex.destroy();
|
|
187
154
|
}));
|
|
155
|
+
Naite.t("migrator:runAction:result", result);
|
|
188
156
|
return result;
|
|
189
157
|
}
|
|
190
158
|
/**
|
|
159
|
+
* 삭제 가능한 마이그레이션 코드 파일을 검증합니다.
|
|
160
|
+
*
|
|
161
|
+
* @param conns 마이그레이션 상태 배열
|
|
162
|
+
* @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
|
|
163
|
+
* @returns 삭제 가능 여부 및 적용된 마이그레이션 코드 파일 이름
|
|
164
|
+
*/ validateDeletable(conns, codeNames) {
|
|
165
|
+
const appliedCodes = codeNames.filter((codeName)=>conns.some((conn)=>conn.pending.includes(codeName) === false));
|
|
166
|
+
return {
|
|
167
|
+
canDelete: appliedCodes.length === 0,
|
|
168
|
+
appliedCodes
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
191
172
|
* 마이그레이션 코드 파일을 삭제합니다.
|
|
192
173
|
*
|
|
193
174
|
* Sonamu UI에서 사용됩니다.
|
|
@@ -196,21 +177,23 @@ export class Migrator {
|
|
|
196
177
|
* @returns 삭제된 마이그레이션 코드 파일 개수
|
|
197
178
|
*/ async delCodes(codeNames) {
|
|
198
179
|
const { conns } = await this.getStatus();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
throw new Error("You cannot delete a migration file if there is already applied.");
|
|
180
|
+
const { canDelete, appliedCodes } = this.validateDeletable(conns, codeNames);
|
|
181
|
+
if (!canDelete) {
|
|
182
|
+
throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
|
|
203
183
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (await exists(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return delFiles.includes(".ts") ? 1 : 0;
|
|
184
|
+
return sum(await Promise.all(codeNames.map(async (codeName)=>{
|
|
185
|
+
const filePath = `${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`;
|
|
186
|
+
if (await exists(filePath)) {
|
|
187
|
+
await unlink(filePath);
|
|
188
|
+
return 1;
|
|
210
189
|
}
|
|
211
190
|
return 0;
|
|
212
|
-
}));
|
|
213
|
-
|
|
191
|
+
})));
|
|
192
|
+
}
|
|
193
|
+
genDateTag(index, baseDate = new Date()) {
|
|
194
|
+
const date = new Date(baseDate.getTime() + index * 1000);
|
|
195
|
+
const pad = (num, size = 2)=>num.toString().padStart(size, "0");
|
|
196
|
+
return date.getFullYear().toString() + pad(date.getMonth() + 1) + pad(date.getDate()) + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
|
|
214
197
|
}
|
|
215
198
|
/**
|
|
216
199
|
* 마이그레이션 코드 파일을 생성합니다.
|
|
@@ -220,6 +203,7 @@ export class Migrator {
|
|
|
220
203
|
* @returns 생성된 마이그레이션 코드 파일 개수
|
|
221
204
|
*/ async generatePreparedCodes() {
|
|
222
205
|
const { preparedCodes } = await this.getStatus();
|
|
206
|
+
Naite.t("migrator:generatePreparedCodes:preparedCodes", preparedCodes);
|
|
223
207
|
if (preparedCodes.length === 0) {
|
|
224
208
|
console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
|
|
225
209
|
return 0;
|
|
@@ -228,240 +212,30 @@ export class Migrator {
|
|
|
228
212
|
const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
|
|
229
213
|
for (const [index, pcode] of preparedCodes.entries()){
|
|
230
214
|
if (pcode.formatted) {
|
|
231
|
-
const dateTag =
|
|
232
|
-
seconds: index
|
|
233
|
-
}).toFormat("yyyyMMddHHmmss");
|
|
215
|
+
const dateTag = this.genDateTag(index);
|
|
234
216
|
const filePath = `${migrationsDir}/${dateTag}_${pcode.title}.ts`;
|
|
235
217
|
await writeFile(filePath, pcode.formatted);
|
|
236
|
-
console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
|
|
218
|
+
!isTest() && console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
|
|
237
219
|
}
|
|
238
220
|
}
|
|
239
221
|
return preparedCodes.length;
|
|
240
222
|
}
|
|
241
|
-
/**
|
|
242
|
-
* pending 마이그레이션 목록을 삭제합니다.
|
|
243
|
-
*
|
|
244
|
-
* CLI에서 사용됩니다.
|
|
245
|
-
*/ async clearPendingList() {
|
|
246
|
-
const [, pendingList] = await this.targets.pending.migrate.list();
|
|
247
|
-
const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
|
|
248
|
-
const delList = pendingList.map((df)=>{
|
|
249
|
-
return path.join(migrationsDir, df.file);
|
|
250
|
-
});
|
|
251
|
-
for (let p of delList){
|
|
252
|
-
if (await exists(p)) {
|
|
253
|
-
await unlink(p);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* 마이그레이션 코드 파일을 확인합니다.
|
|
259
|
-
*
|
|
260
|
-
* CLI에서 사용됩니다.
|
|
261
|
-
*/ async check() {
|
|
262
|
-
const codes = await this.compareMigrations(this.targets.compare);
|
|
263
|
-
if (codes.length === 0) {
|
|
264
|
-
console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
// 현재 생성된 코드 표기
|
|
268
|
-
console.table(codes, [
|
|
269
|
-
"type",
|
|
270
|
-
"title"
|
|
271
|
-
]);
|
|
272
|
-
console.log(codes[0]);
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* 마이그레이션을 수행합니다.
|
|
276
|
-
*
|
|
277
|
-
* runAction이 인자로 들어온 타겟들에 대해 주어진 동작(apply/rollback)을 수행한다면,
|
|
278
|
-
* 이 함수는 생성자로 들어온 connection(knex)들에 대해 마이그레이션을 수행합니다.
|
|
279
|
-
*
|
|
280
|
-
* CLI에서 사용됩니다.
|
|
281
|
-
*/ async run() {
|
|
282
|
-
// pending 마이그레이션 확인
|
|
283
|
-
const [, pendingList] = await this.targets.pending.migrate.list();
|
|
284
|
-
if (pendingList.length > 0) {
|
|
285
|
-
console.log(chalk.red("pending 된 마이그레이션이 존재합니다."), pendingList.map((pending)=>pending.file));
|
|
286
|
-
// pending이 있는 경우 Shadow DB 테스트 진행 여부 컨펌
|
|
287
|
-
const answer = await prompts({
|
|
288
|
-
type: "confirm",
|
|
289
|
-
name: "value",
|
|
290
|
-
message: "Shadow DB 테스트를 진행하시겠습니까?",
|
|
291
|
-
initial: true
|
|
292
|
-
});
|
|
293
|
-
if (answer.value === false) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
console.time(chalk.blue("Migrator - runShadowTest"));
|
|
297
|
-
await this.runShadowTest();
|
|
298
|
-
console.timeEnd(chalk.blue("Migrator - runShadowTest"));
|
|
299
|
-
await Promise.all(this.targets.apply.map(async (applyDb)=>{
|
|
300
|
-
const label = chalk.green(`APPLIED ${applyDb.client.connectionSettings.host} ${applyDb.client.database()}`);
|
|
301
|
-
console.time(label);
|
|
302
|
-
const [, ] = await applyDb.migrate.latest();
|
|
303
|
-
console.timeEnd(label);
|
|
304
|
-
}));
|
|
305
|
-
}
|
|
306
|
-
// Entity-DB간 비교하여 코드 생성 리턴
|
|
307
|
-
const codes = await this.compareMigrations(this.targets.compare);
|
|
308
|
-
if (codes.length === 0) {
|
|
309
|
-
console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
// 현재 생성된 코드 표기
|
|
313
|
-
console.table(codes, [
|
|
314
|
-
"type",
|
|
315
|
-
"title"
|
|
316
|
-
]);
|
|
317
|
-
/* DEBUG: 디버깅용 코드
|
|
318
|
-
codes.map((code) => console.log(code.formatted));
|
|
319
|
-
process.exit();
|
|
320
|
-
*/ // 실제 파일 생성 프롬프트
|
|
321
|
-
const answer = await prompts({
|
|
322
|
-
type: "confirm",
|
|
323
|
-
name: "value",
|
|
324
|
-
message: "마이그레이션 코드를 생성하시겠습니까?",
|
|
325
|
-
initial: false
|
|
326
|
-
});
|
|
327
|
-
if (answer.value === false) {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
// 실제 코드 생성
|
|
331
|
-
const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
|
|
332
|
-
for (const [index, code] of codes.entries()){
|
|
333
|
-
if (code.formatted) {
|
|
334
|
-
const dateTag = DateTime.local().plus({
|
|
335
|
-
seconds: index
|
|
336
|
-
}).toFormat("yyyyMMddHHmmss");
|
|
337
|
-
const filePath = `${migrationsDir}/${dateTag}_${code.title}.ts`;
|
|
338
|
-
await writeFile(filePath, code.formatted);
|
|
339
|
-
console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* 타겟으로 지정된 DB를 롤백합니다.
|
|
345
|
-
*
|
|
346
|
-
* runAction이 인자로 들어온 타겟들에 대해 주어진 동작(apply/rollback)을 수행한다면,
|
|
347
|
-
* 이 함수는 생성자로 들어온 connection(knex)들에 대해 롤백을 수행합니다.
|
|
348
|
-
*
|
|
349
|
-
* CLI에서 사용됩니다.
|
|
350
|
-
*/ async rollback() {
|
|
351
|
-
console.time(chalk.red("rollback:"));
|
|
352
|
-
const rollbackAllResult = await Promise.all(this.targets.apply.map(async (db)=>{
|
|
353
|
-
await db.migrate.forceFreeMigrationsLock();
|
|
354
|
-
return db.migrate.rollback(undefined, false);
|
|
355
|
-
}));
|
|
356
|
-
console.dir({
|
|
357
|
-
rollbackAllResult
|
|
358
|
-
}, {
|
|
359
|
-
depth: null
|
|
360
|
-
});
|
|
361
|
-
console.timeEnd(chalk.red("rollback:"));
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Shadow DB 테스트를 진행합니다.
|
|
365
|
-
*
|
|
366
|
-
* Sonamu UI에서 사용됩니다.
|
|
367
|
-
*
|
|
368
|
-
* @returns Shadow DB 테스트 결과
|
|
369
|
-
*/ async runShadowTest() {
|
|
370
|
-
// ShadowDB 생성 후 테스트 진행
|
|
371
|
-
const tdb = knex(Sonamu.dbConfig.test);
|
|
372
|
-
const tdbConn = Sonamu.dbConfig.test.connection;
|
|
373
|
-
const shadowDatabase = tdbConn.database + "__migration_shadow";
|
|
374
|
-
const tmpSqlPath = `/tmp/${shadowDatabase}.sql`;
|
|
375
|
-
// 테스트DB 덤프 후 Database명 치환
|
|
376
|
-
console.log(chalk.magenta(`${tdbConn.database}의 데이터 ${tmpSqlPath}로 덤프`));
|
|
377
|
-
execSync(`mysqldump -h${tdbConn.host} -P${tdbConn.port ?? 3306} -u${tdbConn.user} -p'${tdbConn.password}' ${tdbConn.database} --single-transaction --no-create-db --triggers > ${tmpSqlPath};`);
|
|
378
|
-
execSync(`sed -i'' -e 's/\`${tdbConn.database}\`/\`${shadowDatabase}\`/g' ${tmpSqlPath};`);
|
|
379
|
-
// 기존 ShadowDB 리셋
|
|
380
|
-
console.log(chalk.magenta(`${shadowDatabase} 리셋`));
|
|
381
|
-
await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
|
|
382
|
-
await tdb.raw(`CREATE DATABASE \`${shadowDatabase}\`;`);
|
|
383
|
-
// ShadowDB 테이블 + 데이터 생성
|
|
384
|
-
console.log(chalk.magenta(`${shadowDatabase} 데이터베이스 생성`));
|
|
385
|
-
execSync(`mysql -h${tdbConn.host} -P${tdbConn.port ?? 3306} -u${tdbConn.user} -p'${tdbConn.password}' ${shadowDatabase} < ${tmpSqlPath};`);
|
|
386
|
-
// shadow db 테스트 진행
|
|
387
|
-
const sdb = knex({
|
|
388
|
-
...Sonamu.dbConfig.test,
|
|
389
|
-
connection: {
|
|
390
|
-
...tdbConn,
|
|
391
|
-
database: shadowDatabase,
|
|
392
|
-
password: tdbConn.password
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
// shadow db 테스트 진행
|
|
396
|
-
try {
|
|
397
|
-
const [batchNo, applied] = await sdb.migrate.latest();
|
|
398
|
-
console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
|
|
399
|
-
batchNo,
|
|
400
|
-
applied
|
|
401
|
-
});
|
|
402
|
-
// 생성한 Shadow DB 삭제
|
|
403
|
-
console.log(chalk.magenta(`${shadowDatabase} 삭제`));
|
|
404
|
-
await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
|
|
405
|
-
return [
|
|
406
|
-
{
|
|
407
|
-
connKey: "shadow",
|
|
408
|
-
batchNo,
|
|
409
|
-
applied
|
|
410
|
-
}
|
|
411
|
-
];
|
|
412
|
-
} catch (e) {
|
|
413
|
-
console.error(e);
|
|
414
|
-
throw new ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");
|
|
415
|
-
} finally{
|
|
416
|
-
await tdb.destroy();
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* 모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제합니다.
|
|
421
|
-
*
|
|
422
|
-
* CLI에서 사용됩니다.
|
|
423
|
-
*
|
|
424
|
-
* @returns
|
|
425
|
-
*/ async resetAll() {
|
|
426
|
-
const answer = await prompts({
|
|
427
|
-
type: "confirm",
|
|
428
|
-
name: "value",
|
|
429
|
-
message: "모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제하시겠습니까?",
|
|
430
|
-
initial: false
|
|
431
|
-
});
|
|
432
|
-
if (answer.value === false) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
console.time(chalk.red("rollback-all:"));
|
|
436
|
-
const rollbackAllResult = await Promise.all(this.targets.apply.map(async (db)=>{
|
|
437
|
-
await db.migrate.forceFreeMigrationsLock();
|
|
438
|
-
return db.migrate.rollback(undefined, true);
|
|
439
|
-
}));
|
|
440
|
-
console.log({
|
|
441
|
-
rollbackAllResult
|
|
442
|
-
});
|
|
443
|
-
console.timeEnd(chalk.red("rollback-all:"));
|
|
444
|
-
const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
|
|
445
|
-
console.time(chalk.red("delete migration files"));
|
|
446
|
-
execSync(`rm -f ${migrationsDir}/*`);
|
|
447
|
-
execSync(`rm -f ${migrationsDir.replace("/src/", "/dist/")}/*`);
|
|
448
|
-
console.timeEnd(chalk.red("delete migration files"));
|
|
449
|
-
}
|
|
450
223
|
async compareMigrations(compareDB) {
|
|
451
224
|
// Entity 순회하여 싱크
|
|
452
225
|
const entityIds = EntityManager.getAllIds();
|
|
453
226
|
// 조인테이블 포함하여 Entity에서 MigrationSet 추출
|
|
454
227
|
const entitySetsWithJoinTable = entityIds.filter((entityId)=>EntityManager.get(entityId).props.length > 0).map((entityId)=>getMigrationSetFromEntity(EntityManager.get(entityId)));
|
|
455
228
|
// 조인테이블만 추출
|
|
456
|
-
const joinTablesWithDup = entitySetsWithJoinTable.
|
|
229
|
+
const joinTablesWithDup = entitySetsWithJoinTable.flatMap((entitySet)=>entitySet.joinTables);
|
|
457
230
|
// 중복 제거 (중복인 경우 indexes를 병합)
|
|
458
|
-
const joinTables = Object.values(
|
|
231
|
+
const joinTables = Object.values(group(joinTablesWithDup, (jt)=>jt.table)).map((tables)=>{
|
|
232
|
+
assert(tables !== undefined, "tables is undefined");
|
|
459
233
|
if (tables.length === 1) {
|
|
460
234
|
return tables[0];
|
|
461
235
|
}
|
|
462
236
|
return {
|
|
463
237
|
...tables[0],
|
|
464
|
-
indexes:
|
|
238
|
+
indexes: unique(tables.flatMap((t)=>t.indexes), (index)=>[
|
|
465
239
|
index.type,
|
|
466
240
|
...index.columns.sort()
|
|
467
241
|
].join("-"))
|
|
@@ -473,7 +247,9 @@ export class Migrator {
|
|
|
473
247
|
...joinTables
|
|
474
248
|
];
|
|
475
249
|
const codes = (await Promise.all(entitySets.map(async (entitySet)=>{
|
|
476
|
-
const dbSet = await getMigrationSetFromDB(compareDB, entitySet.table);
|
|
250
|
+
const dbSet = await PostgreSQLSchemaReader.getMigrationSetFromDB(compareDB, entitySet.table);
|
|
251
|
+
Naite.t(`migrator:compareMigrations:entitySet:${entitySet.table}`, entitySet);
|
|
252
|
+
Naite.t(`migrator:compareMigrations:dbSet:${entitySet.table}`, dbSet);
|
|
477
253
|
if (dbSet === null) {
|
|
478
254
|
// 기존 테이블 없음, 새로 테이블 생성
|
|
479
255
|
return await generateCreateCode(entitySet);
|
|
@@ -484,7 +260,7 @@ export class Migrator {
|
|
|
484
260
|
}))).flat();
|
|
485
261
|
// normal 타입이 앞으로, foreign이 뒤로
|
|
486
262
|
codes.sort((codeA, codeB)=>{
|
|
487
|
-
if (codeA.type === "foreign" && codeB.type
|
|
263
|
+
if (codeA.type === "foreign" && codeB.type === "normal") {
|
|
488
264
|
return 1;
|
|
489
265
|
} else if (codeA.type === "normal" && codeB.type === "foreign") {
|
|
490
266
|
return -1;
|
|
@@ -495,16 +271,60 @@ export class Migrator {
|
|
|
495
271
|
return codes;
|
|
496
272
|
}
|
|
497
273
|
/**
|
|
498
|
-
*
|
|
274
|
+
* Shadow DB 테스트를 진행합니다.
|
|
499
275
|
*
|
|
500
|
-
*
|
|
276
|
+
* Sonamu UI에서 사용됩니다.
|
|
501
277
|
*
|
|
502
|
-
* @returns
|
|
503
|
-
*/ async
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
278
|
+
* @returns Shadow DB 테스트 결과
|
|
279
|
+
*/ async runShadowTest() {
|
|
280
|
+
const tdbConn = Sonamu.dbConfig.test.connection;
|
|
281
|
+
const shadowDatabase = `${tdbConn.database}__migration_shadow`;
|
|
282
|
+
// 테스트 상황에서는 트랜잭션을 초기화하고, 새 데이터베이스 커넥션을 가져와야 함
|
|
283
|
+
if (isTest()) {
|
|
284
|
+
await DB.clearTestTransaction();
|
|
285
|
+
await DB.destroy();
|
|
286
|
+
}
|
|
287
|
+
// 기존 Shadow DB 삭제 후 Shadow DB 생성
|
|
288
|
+
const tdb = knex(Sonamu.dbConfig.test);
|
|
289
|
+
!isTest() && console.log(chalk.magenta(`${shadowDatabase} 삭제`));
|
|
290
|
+
await tdb.raw(`DROP DATABASE IF EXISTS ${shadowDatabase}`);
|
|
291
|
+
await tdb.raw(`CREATE DATABASE ${shadowDatabase} TEMPLATE ${tdbConn.database}`);
|
|
292
|
+
// Shadow DB에 연결
|
|
293
|
+
const sdb = knex({
|
|
294
|
+
...Sonamu.dbConfig.test,
|
|
295
|
+
connection: {
|
|
296
|
+
...tdbConn,
|
|
297
|
+
database: shadowDatabase,
|
|
298
|
+
password: tdbConn.password
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
// shadow DB 테스트 진행
|
|
302
|
+
try {
|
|
303
|
+
const [batchNo, applied] = await sdb.migrate.latest();
|
|
304
|
+
!isTest() && console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
|
|
305
|
+
batchNo,
|
|
306
|
+
applied
|
|
307
|
+
});
|
|
308
|
+
return [
|
|
309
|
+
{
|
|
310
|
+
connKey: "shadow",
|
|
311
|
+
batchNo,
|
|
312
|
+
applied
|
|
313
|
+
}
|
|
314
|
+
];
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.error(e);
|
|
317
|
+
throw new ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");
|
|
318
|
+
} finally{
|
|
319
|
+
// Shadow DB 연결 종료
|
|
320
|
+
await sdb.destroy();
|
|
321
|
+
// Shadow DB 삭제
|
|
322
|
+
!isTest() && console.log(chalk.magenta(`${shadowDatabase} 삭제`));
|
|
323
|
+
await tdb.raw(`DROP DATABASE IF EXISTS ${shadowDatabase}`);
|
|
324
|
+
// Test DB 연결 종료
|
|
325
|
+
await tdb.destroy();
|
|
326
|
+
}
|
|
507
327
|
}
|
|
508
328
|
}
|
|
509
329
|
|
|
510
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWdyYXRpb24vbWlncmF0b3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgXyBmcm9tIFwibG9kYXNoLWVzXCI7XG5pbXBvcnQga25leCwgeyBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IERhdGVUaW1lIH0gZnJvbSBcImx1eG9uXCI7XG5pbXBvcnQgeyBta2RpciwgcmVhZGRpciwgdW5saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGV4aXN0cyB9IGZyb20gXCIuLi91dGlscy9mcy11dGlsc1wiO1xuaW1wb3J0IHByb21wdHMgZnJvbSBcInByb21wdHNcIjtcbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBHZW5NaWdyYXRpb25Db2RlLCBNaWdyYXRpb25TZXQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpXCI7XG5pbXBvcnQgeyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24gfSBmcm9tIFwiLi4vZXhjZXB0aW9ucy9zby1leGNlcHRpb25zXCI7XG5pbXBvcnQgeyBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgZ2VuZXJhdGVDcmVhdGVDb2RlLCBnZW5lcmF0ZUFsdGVyQ29kZSB9IGZyb20gXCIuL2NvZGUtZ2VuZXJhdGlvblwiO1xuaW1wb3J0IHsgTWlncmF0aW9uU3RhdHVzLCBNaWdyYXRpb25Db2RlLCBDb25uU3RyaW5nIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IGdldE1pZ3JhdGlvblNldEZyb21EQiB9IGZyb20gXCIuL21pZ3JhdGlvbi1zZXRcIjtcbmltcG9ydCB7IGdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkgfSBmcm9tIFwiLi9taWdyYXRpb24tc2V0XCI7XG5cbnR5cGUgTWlncmF0b3JNb2RlID0gXCJkZXZcIiB8IFwiZGVwbG95XCI7XG5leHBvcnQgdHlwZSBNaWdyYXRvck9wdGlvbnMgPSB7XG4gIHJlYWRvbmx5IG1vZGU6IE1pZ3JhdG9yTW9kZTtcbn07XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRvciB7XG4gIHRhcmdldHM6IHtcbiAgICBjb21wYXJlPzogS25leDtcbiAgICBwZW5kaW5nOiBLbmV4O1xuICAgIHNoYWRvdzogS25leDtcbiAgICBhcHBseTogS25leFtdO1xuICB9O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogTWlncmF0b3JPcHRpb25zKSB7XG4gICAgY29uc3QgeyBkYkNvbmZpZyB9ID0gU29uYW11O1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5tb2RlID09PSBcImRldlwiKSB7XG4gICAgICBjb25zdCBkZXZEQiA9IGtuZXgoZGJDb25maWcuZGV2ZWxvcG1lbnRfbWFzdGVyKTtcbiAgICAgIGNvbnN0IHRlc3REQiA9IGtuZXgoZGJDb25maWcudGVzdCk7XG4gICAgICBjb25zdCBmaXh0dXJlTG9jYWxEQiA9IGtuZXgoZGJDb25maWcuZml4dHVyZV9sb2NhbCk7XG5cbiAgICAgIGNvbnN0IGFwcGx5REJzID0gW2RldkRCLCB0ZXN0REIsIGZpeHR1cmVMb2NhbERCXTtcbiAgICAgIGlmIChcbiAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfbG9jYWwuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAgICAgLmhvc3QgIT09XG4gICAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfcmVtb3RlLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKVxuICAgICAgICAgICAgLmhvc3QgfHxcbiAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfbG9jYWwuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAgICAgLmRhdGFiYXNlICE9PVxuICAgICAgICAgIChkYkNvbmZpZy5maXh0dXJlX3JlbW90ZS5jb25uZWN0aW9uIGFzIEtuZXguTXlTcWwyQ29ubmVjdGlvbkNvbmZpZylcbiAgICAgICAgICAgIC5kYXRhYmFzZVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGZpeHR1cmVSZW1vdGVEQiA9IGtuZXgoZGJDb25maWcuZml4dHVyZV9yZW1vdGUpO1xuICAgICAgICBhcHBseURCcy5wdXNoKGZpeHR1cmVSZW1vdGVEQik7XG4gICAgICB9XG5cbiAgICAgIHRoaXMudGFyZ2V0cyA9IHtcbiAgICAgICAgY29tcGFyZTogZGV2REIsXG4gICAgICAgIHBlbmRpbmc6IGRldkRCLFxuICAgICAgICBzaGFkb3c6IHRlc3REQixcbiAgICAgICAgYXBwbHk6IGFwcGx5REJzLFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucy5tb2RlID09PSBcImRlcGxveVwiKSB7XG4gICAgICBjb25zdCBwcm9kdWN0aW9uREIgPSBrbmV4KGRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyKTtcbiAgICAgIGNvbnN0IHRlc3REQiA9IGtuZXgoZGJDb25maWcudGVzdCk7XG5cbiAgICAgIHRoaXMudGFyZ2V0cyA9IHtcbiAgICAgICAgcGVuZGluZzogcHJvZHVjdGlvbkRCLFxuICAgICAgICBzaGFkb3c6IHRlc3REQixcbiAgICAgICAgYXBwbHk6IFtwcm9kdWN0aW9uREJdLFxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGDsnpjrqrvrkJwg66qo65OcICR7dGhpcy5vcHRpb25zLm1vZGV9IOyeheugpWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0TWlncmF0aW9uQ29kZXMoKTogUHJvbWlzZTxNaWdyYXRpb25Db2RlW10+IHtcbiAgICBjb25zdCBzcmNNaWdyYXRpb25zRGlyID0gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmNcIiwgXCJtaWdyYXRpb25zXCIpOyAvLyDsnbTqsbQg7ZmY6rK97JeQIOq0gOqzhOyXhuydtCDtla3sg4Egc3Jj7JeQ7IScIOywvuyVhOyVvCDtlbTsmpQuXG5cbiAgICBpZiAoIShhd2FpdCBleGlzdHMoc3JjTWlncmF0aW9uc0RpcikpKSB7XG4gICAgICBhd2FpdCBta2RpcihzcmNNaWdyYXRpb25zRGlyLCB7XG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGNvZGVzID0gKGF3YWl0IHJlYWRkaXIoc3JjTWlncmF0aW9uc0RpcikpXG4gICAgICAuZmlsdGVyKChmKSA9PiBmLmVuZHNXaXRoKFwiLnRzXCIpKVxuICAgICAgLm1hcCgoZikgPT4gKHtcbiAgICAgICAgbmFtZTogZi5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpLFxuICAgICAgICBwYXRoOiBwYXRoLmpvaW4oc3JjTWlncmF0aW9uc0RpciwgZiksXG4gICAgICB9KSlcbiAgICAgIC5zb3J0KChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDtg4Dqsp/rs4Qg66eI7J206re466CI7J207IWYIOyDge2DnOyZgCDsvZTrk5wg7IOd7ISxL+ykgOu5hCDsg4Htg5zrpbwg6rWs7ZW07Ji164uI64ukLlxuICAgKiDsi6TsoJzroZwgRELsl5Ag7KCR6re864+EIO2VmOqzoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOuPhCDtmZXsnbjtlZjqs6AsXG4gICAqIO2VhOyalO2VmOuLpOuptCDsoIHsmqntlaAg7IiYIOyeiOuKlCDsvZTrk5zrpbwg7IOd7ISx6rmM7KeAIO2VtOyYteuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMoKTogUHJvbWlzZTxNaWdyYXRpb25TdGF0dXM+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuZ2V0TWlncmF0aW9uQ29kZXMoKTtcblxuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiBrZXkuZW5kc1dpdGgoXCJfc2xhdmVcIikgPT09IGZhbHNlXG4gICAgKSBhcyAoa2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZylbXTtcblxuICAgIGNvbnN0IHN0YXR1c2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25uS2V5cy5tYXAoYXN5bmMgKGNvbm5LZXkpID0+IHtcbiAgICAgICAgY29uc3Qga25leE9wdGlvbnMgPSBTb25hbXUuZGJDb25maWdbY29ubktleV07XG4gICAgICAgIGNvbnN0IHRDb25uID0ga25leChrbmV4T3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuc3RhdHVzKCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBcImVycm9yXCIgLyrtgbTrnbzsnbTslrjtirjsl5DshJwg7JeQ65+sIOyytO2BrOyXkCDsgqzsmqntlZjripQg66as7YSw65+07J6F64uI64ukLiovO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgcGVuZGluZyA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IFssIGZkTGlzdF0gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKTtcbiAgICAgICAgICAgIHJldHVybiBmZExpc3QubWFwKChmZDogeyBmaWxlOiBzdHJpbmcgfSkgPT5cbiAgICAgICAgICAgICAgZmQuZmlsZS5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb24gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5jdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIFwiZXJyb3JcIjtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgY29uc3QgY29ubmVjdGlvbiA9XG4gICAgICAgICAga25leE9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWc7XG5cbiAgICAgICAgYXdhaXQgdENvbm4uZGVzdHJveSgpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZTogY29ubktleS5yZXBsYWNlKFwiX21hc3RlclwiLCBcIlwiKSxcbiAgICAgICAgICBjb25uS2V5LFxuICAgICAgICAgIGNvbm5TdHJpbmc6IGBteXNxbDI6Ly8ke2Nvbm5lY3Rpb24udXNlciA/PyBcIlwifUAke2Nvbm5lY3Rpb24uaG9zdH06JHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ucG9ydFxuICAgICAgICAgIH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZyxcbiAgICAgICAgICBjdXJyZW50VmVyc2lvbixcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcGVuZGluZyxcbiAgICAgICAgfTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IHByZXBhcmVkQ29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXMwY29ubiA9IHN0YXR1c2VzLmZpbmQoKHN0YXR1cykgPT4gc3RhdHVzLnN0YXR1cyA9PT0gMCk7XG4gICAgICBpZiAoc3RhdHVzMGNvbm4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgYFdoaWxlIHRyeWluZyB0byBwcmVwYXJlIG1pZ3JhdGlvbiBjb2Rlcywgd2UgZm91bmQgdGhhdCB0aGVyZSBpcyBubyBkYXRhYmFzZSB0byBjb21wYXJlIG1pZ3JhdGlvbnMuIFdlIG5lZWQgYXQgbGVhc3Qgb25lIGRhdGFiYXNlIHdoZXJlIGV2ZXJ5IG1pZ3JhdGlvbiBpcyBhcHBsaWVkKHN0YXR1cyA9PT0gMCkuIFlvdSBtaWdodCB3YW50IHRvIGFwcGx5IHlvdXIgZXhpc3RpbmcgbWlncmF0aW9ucyB0byBvbmUgb2YgdGhlIGRhdGFiYXNlcy5gXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbXBhcmVEQmNvbm4gPSBrbmV4KFNvbmFtdS5kYkNvbmZpZ1tzdGF0dXMwY29ubi5jb25uS2V5XSk7XG4gICAgICBjb25zdCBnZW5Db2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCY29ubik7XG5cbiAgICAgIGF3YWl0IGNvbXBhcmVEQmNvbm4uZGVzdHJveSgpO1xuXG4gICAgICByZXR1cm4gZ2VuQ29kZXM7XG4gICAgfSkoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb25uczogc3RhdHVzZXMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgfTtcbiAgICAvKlxuICAgIERCIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg7ZmV7J24XG4gICAgMS4g7KCE7LK0IERC7ISk7KCV7JeQIOuMgO2VtOyEnCDtmITsnqwg66eI7J206re466CI7J207IWYIOyDge2DnCDtmZXsnbhcbiAgICAtIGNvbm5LZXk6IHN0cmluZ1xuICAgIC0gc3RhdHVzOiBudW1iZXJcbiAgICAtIGN1cnJlbnRWZXJzaW9uOiBzdHJpbmdcbiAgICAtIGxpc3Q6IHsgZmlsZTogc3RyaW5nOyBkaXJlY3Rvcnk6IHN0cmluZyB9W11cbiAgICBcbiAgICAqL1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsoIHsmqntlZjqsbDrgpgg66Gk67Cx7ZWp64uI64ukLlxuICAgKiBTb25hbXUgVUnsl5DshJwg66eI7J206re466CI7J207IWYIOyekeyXheydhCDsiJjtlontlaAg65WMIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBhY3Rpb24g7J6R7JeFIOycoO2YlSAoYXBwbHkvcm9sbGJhY2spXG4gICAqIEBwYXJhbSB0YXJnZXRzIOyekeyXhSDrjIDsg4EgREIg7ISk7KCVIO2CpCAoa2V5b2YgU29uYW11REJDb25maWcpXG4gICAqIEByZXR1cm5zIOyekeyXhSDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW11cbiAgKTogUHJvbWlzZTxcbiAgICB7XG4gICAgICBjb25uS2V5OiBzdHJpbmc7XG4gICAgICBiYXRjaE5vOiBudW1iZXI7XG4gICAgICBhcHBsaWVkOiBzdHJpbmdbXTtcbiAgICB9W11cbiAgPiB7XG4gICAgLy8gZ2V0IHVuaXEga25leCBjb25maWdzXG4gICAgY29uc3QgY29uZmlncyA9IF8udW5pcUJ5KFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXQgYXMga2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZ10sXG4gICAgICAgIH0pKVxuICAgICAgICAuZmlsdGVyKChjKSA9PiBjLm9wdGlvbnMgIT09IHVuZGVmaW5lZCksXG4gICAgICAoeyBvcHRpb25zIH0pID0+XG4gICAgICAgIGAkeyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5ob3N0fToke1xuICAgICAgICAgIChvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5wb3J0ID8/IDMzMDZcbiAgICAgICAgfS8keyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gXG4gICAgKTtcblxuICAgIC8vIGdldCBjb25uZWN0aW9uc1xuICAgIGNvbnN0IGNvbm5zID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25maWdzLm1hcChhc3luYyAoY29uZmlnKSA9PiAoe1xuICAgICAgICBjb25uS2V5OiBjb25maWcuY29ubktleSxcbiAgICAgICAga25leDoga25leChjb25maWcub3B0aW9ucyksXG4gICAgICB9KSlcbiAgICApO1xuXG4gICAgLy8gYWN0aW9uXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgIHN3aXRjaCAoYWN0aW9uKSB7XG4gICAgICAgIGNhc2UgXCJhcHBseVwiOlxuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIGNvbm5zLm1hcChhc3luYyAoeyBjb25uS2V5LCBrbmV4IH0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gYXdhaXQga25leC5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbm5LZXksXG4gICAgICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICApO1xuICAgICAgICBjYXNlIFwicm9sbGJhY2tcIjpcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICBjb25ucy5tYXAoYXN5bmMgKHsgY29ubktleSwga25leCB9KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9IGF3YWl0IGtuZXgubWlncmF0ZS5yb2xsYmFjaygpO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbm5LZXksXG4gICAgICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICAvLyBkZXN0cm95XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgIHJldHVybiBrbmV4LmRlc3Ryb3koKTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IKt7KCc7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnOuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGRlbENvZGVzKGNvZGVOYW1lczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY29ubnMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgaWYgKFxuICAgICAgY29ubnMuc29tZSgoY29ubikgPT4ge1xuICAgICAgICByZXR1cm4gY29kZU5hbWVzLnNvbWUoXG4gICAgICAgICAgKGNvZGVOYW1lKSA9PiBjb25uLnBlbmRpbmcuaW5jbHVkZXMoY29kZU5hbWUpID09PSBmYWxzZVxuICAgICAgICApO1xuICAgICAgfSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJZb3UgY2Fubm90IGRlbGV0ZSBhIG1pZ3JhdGlvbiBmaWxlIGlmIHRoZXJlIGlzIGFscmVhZHkgYXBwbGllZC5cIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWxGaWxlcyA9IGNvZGVOYW1lcy5tYXAoXG4gICAgICAoY29kZU5hbWUpID0+IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnMvJHtjb2RlTmFtZX0udHNgXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgZGVsRmlsZXMubWFwKGFzeW5jIChkZWxGaWxlKSA9PiB7XG4gICAgICAgIGlmIChhd2FpdCBleGlzdHMoZGVsRmlsZSkpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5yZWQoYERFTEVURTogJHtkZWxGaWxlfWApKTtcbiAgICAgICAgICBhd2FpdCB1bmxpbmsoZGVsRmlsZSk7XG4gICAgICAgICAgcmV0dXJuIGRlbEZpbGVzLmluY2x1ZGVzKFwiLnRzXCIpID8gMSA6IDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9KVxuICAgICk7XG4gICAgcmV0dXJuIF8uc3VtKHJlcyk7XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IOd7ISx7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyDsg53shLHrkJwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg6rCc7IiYXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVByZXBhcmVkQ29kZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IHByZXBhcmVkQ29kZXMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgaWYgKHByZXBhcmVkQ29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8g7Iuk7KCcIOy9lOuTnCDsg53shLFcbiAgICBjb25zdCBtaWdyYXRpb25zRGlyID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9uc2A7XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgcGNvZGVdIG9mIHByZXBhcmVkQ29kZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAocGNvZGUuZm9ybWF0dGVkKSB7XG4gICAgICAgIGNvbnN0IGRhdGVUYWcgPSBEYXRlVGltZS5sb2NhbCgpXG4gICAgICAgICAgLnBsdXMoeyBzZWNvbmRzOiBpbmRleCB9KVxuICAgICAgICAgIC50b0Zvcm1hdChcInl5eXlNTWRkSEhtbXNzXCIpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke21pZ3JhdGlvbnNEaXJ9LyR7ZGF0ZVRhZ31fJHtwY29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHBjb2RlLmZvcm1hdHRlZCEpO1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgTUlHUlRBSU9OIENSRUFURUQgJHtmaWxlUGF0aH1gKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXBhcmVkQ29kZXMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIHBlbmRpbmcg66eI7J206re466CI7J207IWYIOuqqeuhneydhCDsgq3soJztlanri4jri6QuXG4gICAqXG4gICAqIENMSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqL1xuICBhc3luYyBjbGVhclBlbmRpbmdMaXN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IFssIHBlbmRpbmdMaXN0XSA9IChhd2FpdCB0aGlzLnRhcmdldHMucGVuZGluZy5taWdyYXRlLmxpc3QoKSkgYXMgW1xuICAgICAgdW5rbm93bixcbiAgICAgIHtcbiAgICAgICAgZmlsZTogc3RyaW5nO1xuICAgICAgICBkaXJlY3Rvcnk6IHN0cmluZztcbiAgICAgIH1bXSxcbiAgICBdO1xuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcbiAgICBjb25zdCBkZWxMaXN0ID0gcGVuZGluZ0xpc3QubWFwKChkZikgPT4ge1xuICAgICAgcmV0dXJuIHBhdGguam9pbihtaWdyYXRpb25zRGlyLCBkZi5maWxlKTtcbiAgICB9KTtcbiAgICBmb3IgKGxldCBwIG9mIGRlbExpc3QpIHtcbiAgICAgIGlmIChhd2FpdCBleGlzdHMocCkpIHtcbiAgICAgICAgYXdhaXQgdW5saW5rKHApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDtmZXsnbjtlanri4jri6QuXG4gICAqXG4gICAqIENMSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqL1xuICBhc3luYyBjaGVjaygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnModGhpcy50YXJnZXRzLmNvbXBhcmUhKTtcbiAgICBpZiAoY29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIO2YhOyerCDsg53shLHrkJwg7L2U65OcIO2RnOq4sFxuICAgIGNvbnNvbGUudGFibGUoY29kZXMsIFtcInR5cGVcIiwgXCJ0aXRsZVwiXSk7XG4gICAgY29uc29sZS5sb2coY29kZXNbMF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsiJjtlontlanri4jri6QuXG4gICAqXG4gICAqIHJ1bkFjdGlvbuydtCDsnbjsnpDroZwg65Ok7Ja07JioIO2DgOqyn+uTpOyXkCDrjIDtlbQg7KO87Ja07KeEIOuPmeyekShhcHBseS9yb2xsYmFjaynsnYQg7IiY7ZaJ7ZWc64uk66m0LFxuICAgKiDsnbQg7ZWo7IiY64qUIOyDneyEseyekOuhnCDrk6TslrTsmKggY29ubmVjdGlvbihrbmV4KeuTpOyXkCDrjIDtlbQg66eI7J206re466CI7J207IWY7J2EIOyImO2Wie2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJ1bigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBwZW5kaW5nIOuniOydtOq3uOugiOydtOyFmCDtmZXsnbhcbiAgICBjb25zdCBbLCBwZW5kaW5nTGlzdF0gPSBhd2FpdCB0aGlzLnRhcmdldHMucGVuZGluZy5taWdyYXRlLmxpc3QoKTtcbiAgICBpZiAocGVuZGluZ0xpc3QubGVuZ3RoID4gMCkge1xuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLnJlZChcInBlbmRpbmcg65CcIOuniOydtOq3uOugiOydtOyFmOydtCDsobTsnqztlanri4jri6QuXCIpLFxuICAgICAgICBwZW5kaW5nTGlzdC5tYXAoKHBlbmRpbmc6IGFueSkgPT4gcGVuZGluZy5maWxlKVxuICAgICAgKTtcblxuICAgICAgLy8gcGVuZGluZ+ydtCDsnojripQg6rK97JqwIFNoYWRvdyBEQiDthYzsiqTtirgg7KeE7ZaJIOyXrOu2gCDsu6jtjoxcbiAgICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgICB0eXBlOiBcImNvbmZpcm1cIixcbiAgICAgICAgbmFtZTogXCJ2YWx1ZVwiLFxuICAgICAgICBtZXNzYWdlOiBcIlNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgICBpbml0aWFsOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBpZiAoYW5zd2VyLnZhbHVlID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnNvbGUudGltZShjaGFsay5ibHVlKFwiTWlncmF0b3IgLSBydW5TaGFkb3dUZXN0XCIpKTtcbiAgICAgIGF3YWl0IHRoaXMucnVuU2hhZG93VGVzdCgpO1xuICAgICAgY29uc29sZS50aW1lRW5kKGNoYWxrLmJsdWUoXCJNaWdyYXRvciAtIHJ1blNoYWRvd1Rlc3RcIikpO1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIHRoaXMudGFyZ2V0cy5hcHBseS5tYXAoYXN5bmMgKGFwcGx5RGIpID0+IHtcbiAgICAgICAgICBjb25zdCBsYWJlbCA9IGNoYWxrLmdyZWVuKFxuICAgICAgICAgICAgYEFQUExJRUQgJHtcbiAgICAgICAgICAgICAgYXBwbHlEYi5jbGllbnQuY29ubmVjdGlvblNldHRpbmdzLmhvc3RcbiAgICAgICAgICAgIH0gJHthcHBseURiLmNsaWVudC5kYXRhYmFzZSgpfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnNvbGUudGltZShsYWJlbCk7XG4gICAgICAgICAgY29uc3QgWyxdID0gYXdhaXQgYXBwbHlEYi5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgICAgIGNvbnNvbGUudGltZUVuZChsYWJlbCk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEVudGl0eS1EQuqwhCDruYTqtZDtlZjsl6wg7L2U65OcIOyDneyEsSDrpqzthLRcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnModGhpcy50YXJnZXRzLmNvbXBhcmUhKTtcbiAgICBpZiAoY29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIO2YhOyerCDsg53shLHrkJwg7L2U65OcIO2RnOq4sFxuICAgIGNvbnNvbGUudGFibGUoY29kZXMsIFtcInR5cGVcIiwgXCJ0aXRsZVwiXSk7XG5cbiAgICAvKiBERUJVRzog65SU67KE6rmF7JqpIOy9lOuTnFxuICAgIGNvZGVzLm1hcCgoY29kZSkgPT4gY29uc29sZS5sb2coY29kZS5mb3JtYXR0ZWQpKTtcbiAgICBwcm9jZXNzLmV4aXQoKTtcbiAgICAgKi9cblxuICAgIC8vIOyLpOygnCDtjIzsnbwg7IOd7ISxIO2UhOuhrO2UhO2KuFxuICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgdHlwZTogXCJjb25maXJtXCIsXG4gICAgICBuYW1lOiBcInZhbHVlXCIsXG4gICAgICBtZXNzYWdlOiBcIuuniOydtOq3uOugiOydtOyFmCDsvZTrk5zrpbwg7IOd7ISx7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgaW5pdGlhbDogZmFsc2UsXG4gICAgfSk7XG4gICAgaWYgKGFuc3dlci52YWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyDsi6TsoJwg7L2U65OcIOyDneyEsVxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcblxuICAgIGZvciAoY29uc3QgW2luZGV4LCBjb2RlXSBvZiBjb2Rlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChjb2RlLmZvcm1hdHRlZCkge1xuICAgICAgICBjb25zdCBkYXRlVGFnID0gRGF0ZVRpbWUubG9jYWwoKVxuICAgICAgICAgIC5wbHVzKHsgc2Vjb25kczogaW5kZXggfSlcbiAgICAgICAgICAudG9Gb3JtYXQoXCJ5eXl5TU1kZEhIbW1zc1wiKTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHttaWdyYXRpb25zRGlyfS8ke2RhdGVUYWd9XyR7Y29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIGNvZGUuZm9ybWF0dGVkISk7XG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGBNSUdSVEFJT04gQ1JFQVRFRCAke2ZpbGVQYXRofWApKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog7YOA6rKf7Jy866GcIOyngOygleuQnCBEQuulvCDroaTrsLHtlanri4jri6QuXG4gICAqXG4gICAqIHJ1bkFjdGlvbuydtCDsnbjsnpDroZwg65Ok7Ja07JioIO2DgOqyn+uTpOyXkCDrjIDtlbQg7KO87Ja07KeEIOuPmeyekShhcHBseS9yb2xsYmFjaynsnYQg7IiY7ZaJ7ZWc64uk66m0LFxuICAgKiDsnbQg7ZWo7IiY64qUIOyDneyEseyekOuhnCDrk6TslrTsmKggY29ubmVjdGlvbihrbmV4KeuTpOyXkCDrjIDtlbQg66Gk67Cx7J2EIOyImO2Wie2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrKCkge1xuICAgIGNvbnNvbGUudGltZShjaGFsay5yZWQoXCJyb2xsYmFjazpcIikpO1xuICAgIGNvbnN0IHJvbGxiYWNrQWxsUmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB0aGlzLnRhcmdldHMuYXBwbHkubWFwKGFzeW5jIChkYikgPT4ge1xuICAgICAgICBhd2FpdCBkYi5taWdyYXRlLmZvcmNlRnJlZU1pZ3JhdGlvbnNMb2NrKCk7XG4gICAgICAgIHJldHVybiBkYi5taWdyYXRlLnJvbGxiYWNrKHVuZGVmaW5lZCwgZmFsc2UpO1xuICAgICAgfSlcbiAgICApO1xuICAgIGNvbnNvbGUuZGlyKHsgcm9sbGJhY2tBbGxSZXN1bHQgfSwgeyBkZXB0aDogbnVsbCB9KTtcbiAgICBjb25zb2xlLnRpbWVFbmQoY2hhbGsucmVkKFwicm9sbGJhY2s6XCIpKTtcbiAgfVxuICAvKipcbiAgICogU2hhZG93IERCIO2FjOyKpO2KuOulvCDsp4Ttlontlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIFNoYWRvdyBEQiDthYzsiqTtirgg6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5TaGFkb3dUZXN0KCk6IFByb21pc2U8XG4gICAge1xuICAgICAgY29ubktleTogc3RyaW5nO1xuICAgICAgYmF0Y2hObzogbnVtYmVyO1xuICAgICAgYXBwbGllZDogc3RyaW5nW107XG4gICAgfVtdXG4gID4ge1xuICAgIC8vIFNoYWRvd0RCIOyDneyEsSDtm4Qg7YWM7Iqk7Yq4IOynhO2WiVxuICAgIGNvbnN0IHRkYiA9IGtuZXgoU29uYW11LmRiQ29uZmlnLnRlc3QpO1xuICAgIGNvbnN0IHRkYkNvbm4gPSBTb25hbXUuZGJDb25maWcudGVzdFxuICAgICAgLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnO1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gdGRiQ29ubi5kYXRhYmFzZSArIFwiX19taWdyYXRpb25fc2hhZG93XCI7XG4gICAgY29uc3QgdG1wU3FsUGF0aCA9IGAvdG1wLyR7c2hhZG93RGF0YWJhc2V9LnNxbGA7XG5cbiAgICAvLyDthYzsiqTtirhEQiDrjaTtlIQg7ZuEIERhdGFiYXNl66qFIOy5mO2ZmFxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgY2hhbGsubWFnZW50YShgJHt0ZGJDb25uLmRhdGFiYXNlfeydmCDrjbDsnbTthLAgJHt0bXBTcWxQYXRofeuhnCDrjaTtlIRgKVxuICAgICk7XG4gICAgZXhlY1N5bmMoXG4gICAgICBgbXlzcWxkdW1wIC1oJHt0ZGJDb25uLmhvc3R9IC1QJHt0ZGJDb25uLnBvcnQgPz8gMzMwNn0gLXUke3RkYkNvbm4udXNlcn0gLXAnJHt0ZGJDb25uLnBhc3N3b3JkfScgJHt0ZGJDb25uLmRhdGFiYXNlfSAtLXNpbmdsZS10cmFuc2FjdGlvbiAtLW5vLWNyZWF0ZS1kYiAtLXRyaWdnZXJzID4gJHt0bXBTcWxQYXRofTtgXG4gICAgKTtcbiAgICBleGVjU3luYyhcbiAgICAgIGBzZWQgLWknJyAtZSAncy9cXGAke3RkYkNvbm4uZGF0YWJhc2V9XFxgL1xcYCR7c2hhZG93RGF0YWJhc2V9XFxgL2cnICR7dG1wU3FsUGF0aH07YFxuICAgICk7XG5cbiAgICAvLyDquLDsobQgU2hhZG93REIg66as7IWLXG4gICAgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g66as7IWLYCkpO1xuICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTIFxcYCR7c2hhZG93RGF0YWJhc2V9XFxgO2ApO1xuICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSBcXGAke3NoYWRvd0RhdGFiYXNlfVxcYDtgKTtcblxuICAgIC8vIFNoYWRvd0RCIO2FjOydtOu4lCArIOuNsOydtO2EsCDsg53shLFcbiAgICBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDrjbDsnbTthLDrsqDsnbTsiqQg7IOd7ISxYCkpO1xuICAgIGV4ZWNTeW5jKFxuICAgICAgYG15c3FsIC1oJHt0ZGJDb25uLmhvc3R9IC1QJHt0ZGJDb25uLnBvcnQgPz8gMzMwNn0gLXUke3RkYkNvbm4udXNlcn0gLXAnJHt0ZGJDb25uLnBhc3N3b3JkfScgJHtzaGFkb3dEYXRhYmFzZX0gPCAke3RtcFNxbFBhdGh9O2BcbiAgICApO1xuXG4gICAgLy8gc2hhZG93IGRiIO2FjOyKpO2KuCDsp4TtlolcbiAgICBjb25zdCBzZGIgPSBrbmV4KHtcbiAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAuLi50ZGJDb25uLFxuICAgICAgICBkYXRhYmFzZTogc2hhZG93RGF0YWJhc2UsXG4gICAgICAgIHBhc3N3b3JkOiB0ZGJDb25uLnBhc3N3b3JkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIHNoYWRvdyBkYiDthYzsiqTtirgg7KeE7ZaJXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9IGF3YWl0IHNkYi5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJTaGFkb3cgREIg7YWM7Iqk7Yq47JeQIOyEseqzte2WiOyKteuLiOuLpCFcIiksIHtcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgYXBwbGllZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyDsg53shLHtlZwgU2hhZG93IERCIOyCreygnFxuICAgICAgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g7IKt7KCcYCkpO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgXFxgJHtzaGFkb3dEYXRhYmFzZX1cXGA7YCk7XG5cbiAgICAgIHJldHVybiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oXCJTaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiSDspJEg7JeQ65+sXCIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCB0ZGIuZGVzdHJveSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrqqjrk6AgRELrpbwg66Gk67Cx7ZWY6rOgIOyghOyytCDrp4jsnbTqt7jroIjsnbTshZgg7YyM7J287J2EIOyCreygnO2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnNcbiAgICovXG4gIGFzeW5jIHJlc2V0QWxsKCkge1xuICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgdHlwZTogXCJjb25maXJtXCIsXG4gICAgICBuYW1lOiBcInZhbHVlXCIsXG4gICAgICBtZXNzYWdlOiBcIuuqqOuToCBEQuulvCDroaTrsLHtlZjqs6Ag7KCE7LK0IOuniOydtOq3uOugiOydtOyFmCDtjIzsnbzsnYQg7IKt7KCc7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgaW5pdGlhbDogZmFsc2UsXG4gICAgfSk7XG4gICAgaWYgKGFuc3dlci52YWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLnRpbWUoY2hhbGsucmVkKFwicm9sbGJhY2stYWxsOlwiKSk7XG4gICAgY29uc3Qgcm9sbGJhY2tBbGxSZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHRoaXMudGFyZ2V0cy5hcHBseS5tYXAoYXN5bmMgKGRiKSA9PiB7XG4gICAgICAgIGF3YWl0IGRiLm1pZ3JhdGUuZm9yY2VGcmVlTWlncmF0aW9uc0xvY2soKTtcbiAgICAgICAgcmV0dXJuIGRiLm1pZ3JhdGUucm9sbGJhY2sodW5kZWZpbmVkLCB0cnVlKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICBjb25zb2xlLmxvZyh7IHJvbGxiYWNrQWxsUmVzdWx0IH0pO1xuICAgIGNvbnNvbGUudGltZUVuZChjaGFsay5yZWQoXCJyb2xsYmFjay1hbGw6XCIpKTtcblxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcbiAgICBjb25zb2xlLnRpbWUoY2hhbGsucmVkKFwiZGVsZXRlIG1pZ3JhdGlvbiBmaWxlc1wiKSk7XG4gICAgZXhlY1N5bmMoYHJtIC1mICR7bWlncmF0aW9uc0Rpcn0vKmApO1xuICAgIGV4ZWNTeW5jKGBybSAtZiAke21pZ3JhdGlvbnNEaXIucmVwbGFjZShcIi9zcmMvXCIsIFwiL2Rpc3QvXCIpfS8qYCk7XG4gICAgY29uc29sZS50aW1lRW5kKGNoYWxrLnJlZChcImRlbGV0ZSBtaWdyYXRpb24gZmlsZXNcIikpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjb21wYXJlTWlncmF0aW9ucyhcbiAgICBjb21wYXJlREI6IEtuZXhcbiAgKTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICAvLyBFbnRpdHkg7Iic7ZqM7ZWY7JesIOyLse2BrFxuICAgIGNvbnN0IGVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIEVudGl0eeyXkOyEnCBNaWdyYXRpb25TZXQg7LaU7LacXG4gICAgY29uc3QgZW50aXR5U2V0c1dpdGhKb2luVGFibGUgPSBlbnRpdHlJZHNcbiAgICAgIC5maWx0ZXIoKGVudGl0eUlkKSA9PiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMubGVuZ3RoID4gMClcbiAgICAgIC5tYXAoKGVudGl0eUlkKSA9PlxuICAgICAgICBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5KEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKSlcbiAgICAgICk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJTrp4wg7LaU7LacXG4gICAgY29uc3Qgam9pblRhYmxlc1dpdGhEdXAgPSBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZVxuICAgICAgLm1hcCgoZW50aXR5U2V0KSA9PiBlbnRpdHlTZXQuam9pblRhYmxlcylcbiAgICAgIC5mbGF0KCk7XG4gICAgLy8g7KSR67O1IOygnOqxsCAo7KSR67O17J24IOqyveyasCBpbmRleGVz66W8IOuzke2VqSlcbiAgICBjb25zdCBqb2luVGFibGVzID0gT2JqZWN0LnZhbHVlcyhcbiAgICAgIF8uZ3JvdXBCeShqb2luVGFibGVzV2l0aER1cCwgKGp0KSA9PiBqdC50YWJsZSlcbiAgICApLm1hcCgodGFibGVzKSA9PiB7XG4gICAgICBpZiAodGFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGFibGVzWzBdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGFibGVzWzBdLFxuICAgICAgICBpbmRleGVzOiBfLnVuaXFCeShcbiAgICAgICAgICB0YWJsZXMuZmxhdE1hcCgodCkgPT4gdC5pbmRleGVzKSxcbiAgICAgICAgICAoaW5kZXgpID0+IFtpbmRleC50eXBlLCAuLi5pbmRleC5jb2x1bW5zLnNvcnQoKV0uam9pbihcIi1cIilcbiAgICAgICAgKSxcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIE1pZ3JhdGlvblNldCDrsLDsl7RcbiAgICBjb25zdCBlbnRpdHlTZXRzOiBNaWdyYXRpb25TZXRbXSA9IFtcbiAgICAgIC4uLmVudGl0eVNldHNXaXRoSm9pblRhYmxlLFxuICAgICAgLi4uam9pblRhYmxlcyxcbiAgICBdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IChcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBnZXRNaWdyYXRpb25TZXRGcm9tREIoY29tcGFyZURCLCBlbnRpdHlTZXQudGFibGUpO1xuXG4gICAgICAgICAgaWYgKGRiU2V0ID09PSBudWxsKSB7XG4gICAgICAgICAgICAvLyDquLDsobQg7YWM7J2067iUIOyXhuydjCwg7IOI66GcIO2FjOydtOu4lCDsg53shLFcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUNyZWF0ZUNvZGUoZW50aXR5U2V0KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsobTsnqztlZjripQg7LyA7J207IqkXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVBbHRlckNvZGUoZW50aXR5U2V0LCBkYlNldCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgKVxuICAgICkuZmxhdCgpO1xuXG4gICAgLy8gbm9ybWFsIO2DgOyeheydtCDslZ7snLzroZwsIGZvcmVpZ27snbQg65Kk66GcXG4gICAgY29kZXMuc29ydCgoY29kZUEsIGNvZGVCKSA9PiB7XG4gICAgICBpZiAoY29kZUEudHlwZSA9PT0gXCJmb3JlaWduXCIgJiYgY29kZUIudHlwZSA9PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDrjIDsg4Eg7Luk64Sl7IWY7J2EIOyiheujjO2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IOyiheujjCDqsrDqs7xcbiAgICovXG4gIGFzeW5jIGRlc3Ryb3koKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB0aGlzLnRhcmdldHMuYXBwbHkubWFwKChkYikgPT4ge1xuICAgICAgICByZXR1cm4gZGIuZGVzdHJveSgpO1xuICAgICAgfSlcbiAgICApO1xuICB9XG59XG4iXSwibmFtZXMiOlsiXyIsImtuZXgiLCJjaGFsayIsIkRhdGVUaW1lIiwibWtkaXIiLCJyZWFkZGlyIiwidW5saW5rIiwid3JpdGVGaWxlIiwiZXhpc3RzIiwicHJvbXB0cyIsImV4ZWNTeW5jIiwicGF0aCIsIkVudGl0eU1hbmFnZXIiLCJTb25hbXUiLCJTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24iLCJnZW5lcmF0ZUNyZWF0ZUNvZGUiLCJnZW5lcmF0ZUFsdGVyQ29kZSIsImdldE1pZ3JhdGlvblNldEZyb21EQiIsImdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkiLCJNaWdyYXRvciIsInRhcmdldHMiLCJvcHRpb25zIiwiZGJDb25maWciLCJtb2RlIiwiZGV2REIiLCJkZXZlbG9wbWVudF9tYXN0ZXIiLCJ0ZXN0REIiLCJ0ZXN0IiwiZml4dHVyZUxvY2FsREIiLCJmaXh0dXJlX2xvY2FsIiwiYXBwbHlEQnMiLCJjb25uZWN0aW9uIiwiaG9zdCIsImZpeHR1cmVfcmVtb3RlIiwiZGF0YWJhc2UiLCJmaXh0dXJlUmVtb3RlREIiLCJwdXNoIiwiY29tcGFyZSIsInBlbmRpbmciLCJzaGFkb3ciLCJhcHBseSIsInByb2R1Y3Rpb25EQiIsInByb2R1Y3Rpb25fbWFzdGVyIiwiRXJyb3IiLCJnZXRNaWdyYXRpb25Db2RlcyIsInNyY01pZ3JhdGlvbnNEaXIiLCJqb2luIiwiYXBpUm9vdFBhdGgiLCJyZWN1cnNpdmUiLCJjb2RlcyIsImZpbHRlciIsImYiLCJlbmRzV2l0aCIsIm1hcCIsIm5hbWUiLCJyZXBsYWNlIiwic29ydCIsImEiLCJiIiwiZ2V0U3RhdHVzIiwiY29ubktleXMiLCJPYmplY3QiLCJrZXlzIiwia2V5Iiwic3RhdHVzZXMiLCJQcm9taXNlIiwiYWxsIiwiY29ubktleSIsImtuZXhPcHRpb25zIiwidENvbm4iLCJzdGF0dXMiLCJtaWdyYXRlIiwiZXJyIiwiY29uc29sZSIsIndhcm4iLCJ5ZWxsb3ciLCJKU09OIiwic3RyaW5naWZ5IiwiZmRMaXN0IiwibGlzdCIsImZkIiwiZmlsZSIsImN1cnJlbnRWZXJzaW9uIiwiZGVzdHJveSIsImNvbm5TdHJpbmciLCJ1c2VyIiwicG9ydCIsInByZXBhcmVkQ29kZXMiLCJzdGF0dXMwY29ubiIsImZpbmQiLCJ1bmRlZmluZWQiLCJjb21wYXJlREJjb25uIiwiZ2VuQ29kZXMiLCJjb21wYXJlTWlncmF0aW9ucyIsImNvbm5zIiwicnVuQWN0aW9uIiwiYWN0aW9uIiwiY29uZmlncyIsInVuaXFCeSIsInRhcmdldCIsImMiLCJjb25maWciLCJyZXN1bHQiLCJiYXRjaE5vIiwiYXBwbGllZCIsImxhdGVzdCIsInJvbGxiYWNrIiwiZGVsQ29kZXMiLCJjb2RlTmFtZXMiLCJzb21lIiwiY29ubiIsImNvZGVOYW1lIiwiaW5jbHVkZXMiLCJkZWxGaWxlcyIsInJlcyIsImRlbEZpbGUiLCJsb2ciLCJyZWQiLCJzdW0iLCJnZW5lcmF0ZVByZXBhcmVkQ29kZXMiLCJsZW5ndGgiLCJncmVlbiIsIm1pZ3JhdGlvbnNEaXIiLCJpbmRleCIsInBjb2RlIiwiZW50cmllcyIsImZvcm1hdHRlZCIsImRhdGVUYWciLCJsb2NhbCIsInBsdXMiLCJzZWNvbmRzIiwidG9Gb3JtYXQiLCJmaWxlUGF0aCIsInRpdGxlIiwiY2xlYXJQZW5kaW5nTGlzdCIsInBlbmRpbmdMaXN0IiwiZGVsTGlzdCIsImRmIiwicCIsImNoZWNrIiwidGFibGUiLCJydW4iLCJhbnN3ZXIiLCJ0eXBlIiwibWVzc2FnZSIsImluaXRpYWwiLCJ2YWx1ZSIsInRpbWUiLCJibHVlIiwicnVuU2hhZG93VGVzdCIsInRpbWVFbmQiLCJhcHBseURiIiwibGFiZWwiLCJjbGllbnQiLCJjb25uZWN0aW9uU2V0dGluZ3MiLCJjb2RlIiwicm9sbGJhY2tBbGxSZXN1bHQiLCJkYiIsImZvcmNlRnJlZU1pZ3JhdGlvbnNMb2NrIiwiZGlyIiwiZGVwdGgiLCJ0ZGIiLCJ0ZGJDb25uIiwic2hhZG93RGF0YWJhc2UiLCJ0bXBTcWxQYXRoIiwibWFnZW50YSIsInBhc3N3b3JkIiwicmF3Iiwic2RiIiwiZSIsImVycm9yIiwicmVzZXRBbGwiLCJjb21wYXJlREIiLCJlbnRpdHlJZHMiLCJnZXRBbGxJZHMiLCJlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZSIsImVudGl0eUlkIiwiZ2V0IiwicHJvcHMiLCJqb2luVGFibGVzV2l0aER1cCIsImVudGl0eVNldCIsImpvaW5UYWJsZXMiLCJmbGF0IiwidmFsdWVzIiwiZ3JvdXBCeSIsImp0IiwidGFibGVzIiwiaW5kZXhlcyIsImZsYXRNYXAiLCJ0IiwiY29sdW1ucyIsImVudGl0eVNldHMiLCJkYlNldCIsImNvZGVBIiwiY29kZUIiXSwibWFwcGluZ3MiOiJBQUFBLFlBQVlBLE9BQU8sWUFB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
|
|
330
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWdyYXRpb24vbWlncmF0b3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgeyBta2RpciwgcmVhZGRpciwgdW5saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBrbmV4LCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgZ3JvdXAsIHN1bSwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGlcIjtcbmltcG9ydCB7IERCLCB0eXBlIFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgU2VydmljZVVuYXZhaWxhYmxlRXhjZXB0aW9uIH0gZnJvbSBcIi4uL2V4Y2VwdGlvbnMvc28tZXhjZXB0aW9uc1wiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB0eXBlIHsgR2VuTWlncmF0aW9uQ29kZSwgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHR5cGUgeyBDb25uU3RyaW5nLCBNaWdyYXRpb25Db2RlLCBNaWdyYXRpb25TdGF0dXMgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG5leHBvcnQgdHlwZSBNaWdyYXRpb25SZXN1bHQgPSB7XG4gIGNvbm5LZXk6IHN0cmluZztcbiAgYmF0Y2hObzogbnVtYmVyO1xuICBhcHBsaWVkOiBzdHJpbmdbXTtcbn1bXTtcblxuZXhwb3J0IGNsYXNzIE1pZ3JhdG9yIHtcbiAgcHJpdmF0ZSBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnNvcnQoKGEsIGIpID0+IChhLm5hbWUgPCBiLm5hbWUgPyAxIDogLTEpKTsgLy8g7J2066aEIOuCtOumvOywqOyInCDsoJXroKwo7LWc7Iug7IicKVxuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldE1pZ3JhdGlvbkNvZGVzOnJlc3VsdHNcIiwgY29kZXMpO1xuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDtg4Dqsp/rs4Qg66eI7J206re466CI7J207IWYIOyDge2DnOyZgCDsvZTrk5wg7IOd7ISxL+ykgOu5hCDsg4Htg5zrpbwg6rWs7ZW07Ji164uI64ukLlxuICAgKiDsi6TsoJzroZwgRELsl5Ag7KCR6re864+EIO2VmOqzoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOuPhCDtmZXsnbjtlZjqs6AsXG4gICAqIO2VhOyalO2VmOuLpOuptCDsoIHsmqntlaAg7IiYIOyeiOuKlCDsvZTrk5zrpbwg7IOd7ISx6rmM7KeAIO2VtOyYteuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMoKTogUHJvbWlzZTxNaWdyYXRpb25TdGF0dXM+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuZ2V0TWlncmF0aW9uQ29kZXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvZGVzXCIsIGNvZGVzKTtcblxuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiBrZXkuZW5kc1dpdGgoXCJfc2xhdmVcIikgPT09IGZhbHNlLFxuICAgICkgYXMgKGtleW9mIHR5cGVvZiBTb25hbXUuZGJDb25maWcpW107XG5cbiAgICBsZXQgbWlncmF0aW9uU3RhdHVzRXJyb3I6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHN0YXR1c2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25uS2V5cy5tYXAoYXN5bmMgKGNvbm5LZXkpID0+IHtcbiAgICAgICAgY29uc3Qga25leE9wdGlvbnMgPSBTb25hbXUuZGJDb25maWdbY29ubktleV07XG4gICAgICAgIGNvbnN0IHRDb25uID0ga25leChrbmV4T3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuc3RhdHVzKCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmAsXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgICAgICByZXR1cm4gXCJlcnJvclwiO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgcGVuZGluZzogc3RyaW5nW10gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBbLCBmZExpc3RdID0gYXdhaXQgdENvbm4ubWlncmF0ZS5saXN0KCk7XG4gICAgICAgICAgICByZXR1cm4gZmRMaXN0Lm1hcCgoZmQ6IHsgZmlsZTogc3RyaW5nIH0pID0+IGZkLmZpbGUucmVwbGFjZShcIi50c1wiLCBcIlwiKSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRWZXJzaW9uID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuY3VycmVudFZlcnNpb24oKTtcbiAgICAgICAgICB9IGNhdGNoIChfZXJyKSB7XG4gICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IF9lcnIgaW5zdGFuY2VvZiBFcnJvciA/IF9lcnIubWVzc2FnZSA6IFN0cmluZyhfZXJyKTtcbiAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuICAgICAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnN0YXR1c1wiLCBzdGF0dXMpO1xuXG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPSBrbmV4T3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuXG4gICAgICAgIGF3YWl0IHRDb25uLmRlc3Ryb3koKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWU6IGNvbm5LZXkucmVwbGFjZShcIl9tYXN0ZXJcIiwgXCJcIiksXG4gICAgICAgICAgY29ubktleSxcbiAgICAgICAgICBjb25uU3RyaW5nOiBgcGc6Ly8ke2Nvbm5lY3Rpb24udXNlciA/PyBcIlwifUAke2Nvbm5lY3Rpb24uaG9zdH06JHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ucG9ydFxuICAgICAgICAgIH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZyxcbiAgICAgICAgICBjdXJyZW50VmVyc2lvbixcbiAgICAgICAgICBzdGF0dXM6IHN0YXR1cyBhcyBudW1iZXIgfCBcImVycm9yXCIsXG4gICAgICAgICAgcGVuZGluZyxcbiAgICAgICAgfTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvbm5zXCIsIHN0YXR1c2VzKTtcblxuICAgIGNvbnN0IHByZXBhcmVkQ29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXMwY29ubiA9IHN0YXR1c2VzLmZpbmQoKHN0YXR1cykgPT4gc3RhdHVzLnN0YXR1cyA9PT0gMCk7XG4gICAgICBpZiAoc3RhdHVzMGNvbm4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgYFdoaWxlIHRyeWluZyB0byBwcmVwYXJlIG1pZ3JhdGlvbiBjb2Rlcywgd2UgZm91bmQgdGhhdCB0aGVyZSBpcyBubyBkYXRhYmFzZSB0byBjb21wYXJlIG1pZ3JhdGlvbnMuIFdlIG5lZWQgYXQgbGVhc3Qgb25lIGRhdGFiYXNlIHdoZXJlIGV2ZXJ5IG1pZ3JhdGlvbiBpcyBhcHBsaWVkKHN0YXR1cyA9PT0gMCkuIFlvdSBtaWdodCB3YW50IHRvIGFwcGx5IHlvdXIgZXhpc3RpbmcgbWlncmF0aW9ucyB0byBvbmUgb2YgdGhlIGRhdGFiYXNlcy5gLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29tcGFyZURCY29ubiA9IGtuZXgoU29uYW11LmRiQ29uZmlnW3N0YXR1czBjb25uLmNvbm5LZXldKTtcbiAgICAgIGNvbnN0IGdlbkNvZGVzID0gYXdhaXQgdGhpcy5jb21wYXJlTWlncmF0aW9ucyhjb21wYXJlREJjb25uKTtcblxuICAgICAgYXdhaXQgY29tcGFyZURCY29ubi5kZXN0cm95KCk7XG5cbiAgICAgIHJldHVybiBnZW5Db2RlcztcbiAgICB9KSgpO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbm5zOiBzdGF0dXNlcyxcbiAgICAgIGNvZGVzLFxuICAgICAgcHJlcGFyZWRDb2RlcyxcbiAgICAgIGVycm9yOiBtaWdyYXRpb25TdGF0dXNFcnJvcixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsoIHsmqntlZjqsbDrgpgg66Gk67Cx7ZWp64uI64ukLlxuICAgKiBTb25hbXUgVUnsl5DshJwg66eI7J206re466CI7J207IWYIOyekeyXheydhCDsiJjtlontlaAg65WMIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBhY3Rpb24g7J6R7JeFIOycoO2YlSAoYXBwbHkvcm9sbGJhY2spXG4gICAqIEBwYXJhbSB0YXJnZXRzIOyekeyXhSDrjIDsg4EgREIg7ISk7KCVIO2CpCAoa2V5b2YgU29uYW11REJDb25maWcpXG4gICAqIEByZXR1cm5zIOyekeyXhSDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10sXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjphY3Rpb25cIiwgYWN0aW9uKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnRhcmdldHNcIiwgdGFyZ2V0cyk7XG5cbiAgICAvLyBnZXQgdW5pcSBrbmV4IGNvbmZpZ3NcbiAgICBjb25zdCBjb25maWdzID0gdW5pcXVlKFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXQgYXMga2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZ10sXG4gICAgICAgIH0pKVxuICAgICAgICAuZmlsdGVyKChjKSA9PiBjLm9wdGlvbnMgIT09IHVuZGVmaW5lZCksXG4gICAgICAoeyBvcHRpb25zIH0pID0+XG4gICAgICAgIGAkeyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLmhvc3R9OiR7XG4gICAgICAgICAgKG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykucG9ydCA/PyA1NDMyXG4gICAgICAgIH0vJHsob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gLFxuICAgICk7XG5cbiAgICAvLyBnZXQgY29ubmVjdGlvbnNcbiAgICBjb25zdCBjb25ucyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29uZmlncy5tYXAoYXN5bmMgKGNvbmZpZykgPT4gKHtcbiAgICAgICAgY29ubktleTogY29uZmlnLmNvbm5LZXksXG4gICAgICAgIGtuZXg6IGtuZXgoY29uZmlnLm9wdGlvbnMpLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICAvLyBhY3Rpb25cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgc3dpdGNoIChhY3Rpb24pIHtcbiAgICAgICAgY2FzZSBcImFwcGx5XCI6XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgICAgICAgY29ubnMubWFwKGFzeW5jICh7IGNvbm5LZXksIGtuZXggfSkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBrbmV4Lm1pZ3JhdGUubGF0ZXN0KCk7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgICAgIGFwcGxpZWQsIC8vIOydtOuyiCBsYXRlc3Qg7Zi47Lac66GcIOyduO2VtCBcInVwXCLsnbQg7KCB7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDsnbTrpoQoZS5nLiBcIjIwMjUxMTI0MjMzNTU3X2NyZWF0ZV9fY29tcGFuaWVzLnRzXCIp65Ok7J2YIOuwsOyXtOyeheuLiOuLpC4g7LC46rOgOiBodHRwczovL2dpdGh1Yi5jb20va25leC9rbmV4L2Jsb2IvMDFiMTc3YzQ4NWQ2OTZmMWI3Mjg1OGRlZTcyOGJhMTQzYzRmYWQ3Ni9saWIvbWlncmF0aW9ucy9taWdyYXRlL01pZ3JhdG9yLmpzI0w1NjBcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgIGNhc2UgXCJyb2xsYmFja1wiOlxuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIGNvbm5zLm1hcChhc3luYyAoeyBjb25uS2V5LCBrbmV4IH0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gYXdhaXQga25leC5taWdyYXRlLnJvbGxiYWNrKCk7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgICAgIGFwcGxpZWQsIC8vIOydtOuyiCByb2xsYmFjayDtmLjstpzroZwg7J247ZW0IFwiZG93blwi7J20IOyggeyaqeuQnCg966Gk67Cx65CcKSDrp4jsnbTqt7jroIjsnbTshZgg7J2066aEKGUuZy4gXCIyMDI1MTEyNDIzMzU1N19jcmVhdGVfX2NvbXBhbmllcy50c1wiKeuTpOydmCDrsLDsl7TsnoXri4jri6QuIOywuOqzoDogaHR0cHM6Ly9naXRodWIuY29tL2tuZXgva25leC9ibG9iLzAxYjE3N2M0ODVkNjk2ZjFiNzI4NThkZWU3MjhiYTE0M2M0ZmFkNzYvbGliL21pZ3JhdGlvbnMvbWlncmF0ZS9NaWdyYXRvci5qcyNMNjExXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICAvLyBkZXN0cm95XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgIHJldHVybiBrbmV4LmRlc3Ryb3koKTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnJlc3VsdFwiLCByZXN1bHQpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiDsgq3soJwg6rCA64ql7ZWcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOqygOymne2VqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIGNvbm5zIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg67Cw7Je0XG4gICAqIEBwYXJhbSBjb2RlTmFtZXMg7IKt7KCc7ZWgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhCDrsLDsl7RcbiAgICogQHJldHVybnMg7IKt7KCcIOqwgOuKpSDsl6zrtoAg67CPIOyggeyaqeuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoRcbiAgICovXG4gIHZhbGlkYXRlRGVsZXRhYmxlKGNvbm5zOiBNaWdyYXRpb25TdGF0dXNbXCJjb25uc1wiXSwgY29kZU5hbWVzOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IGFwcGxpZWRDb2RlcyA9IGNvZGVOYW1lcy5maWx0ZXIoKGNvZGVOYW1lKSA9PlxuICAgICAgY29ubnMuc29tZSgoY29ubikgPT4gY29ubi5wZW5kaW5nLmluY2x1ZGVzKGNvZGVOYW1lKSA9PT0gZmFsc2UpLFxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY2FuRGVsZXRlOiBhcHBsaWVkQ29kZXMubGVuZ3RoID09PSAwLFxuICAgICAgYXBwbGllZENvZGVzLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IKt7KCc7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnOuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGRlbENvZGVzKGNvZGVOYW1lczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY29ubnMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgY29uc3QgeyBjYW5EZWxldGUsIGFwcGxpZWRDb2RlcyB9ID0gdGhpcy52YWxpZGF0ZURlbGV0YWJsZShjb25ucywgY29kZU5hbWVzKTtcbiAgICBpZiAoIWNhbkRlbGV0ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgWW91IGNhbm5vdCBkZWxldGUgYSBtaWdyYXRpb24gZmlsZSBpZiB0aGVyZSBpcyBhbHJlYWR5IGFwcGxpZWQuIEFwcGxpZWQgY29kZXM6ICR7YXBwbGllZENvZGVzLmpvaW4oXCIsIFwiKX1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3VtKFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGNvZGVOYW1lcy5tYXAoYXN5bmMgKGNvZGVOYW1lKSA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zLyR7Y29kZU5hbWV9LnRzYDtcbiAgICAgICAgICBpZiAoYXdhaXQgZXhpc3RzKGZpbGVQYXRoKSkge1xuICAgICAgICAgICAgYXdhaXQgdW5saW5rKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfSksXG4gICAgICApLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdlbkRhdGVUYWcoaW5kZXg6IG51bWJlciwgYmFzZURhdGU6IERhdGUgPSBuZXcgRGF0ZSgpKTogc3RyaW5nIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoYmFzZURhdGUuZ2V0VGltZSgpICsgaW5kZXggKiAxMDAwKTtcbiAgICBjb25zdCBwYWQgPSAobnVtOiBudW1iZXIsIHNpemU6IG51bWJlciA9IDIpID0+IG51bS50b1N0cmluZygpLnBhZFN0YXJ0KHNpemUsIFwiMFwiKTtcbiAgICByZXR1cm4gKFxuICAgICAgZGF0ZS5nZXRGdWxsWWVhcigpLnRvU3RyaW5nKCkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TW9udGgoKSArIDEpICtcbiAgICAgIHBhZChkYXRlLmdldERhdGUoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0SG91cnMoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TWludXRlcygpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRTZWNvbmRzKCkpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIOyDneyEseuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlUHJlcGFyZWRDb2RlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgcHJlcGFyZWRDb2RlcyB9ID0gYXdhaXQgdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2VuZXJhdGVQcmVwYXJlZENvZGVzOnByZXBhcmVkQ29kZXNcIiwgcHJlcGFyZWRDb2Rlcyk7XG4gICAgaWYgKHByZXBhcmVkQ29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8g7Iuk7KCcIOy9lOuTnCDsg53shLFcbiAgICBjb25zdCBtaWdyYXRpb25zRGlyID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9uc2A7XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgcGNvZGVdIG9mIHByZXBhcmVkQ29kZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAocGNvZGUuZm9ybWF0dGVkKSB7XG4gICAgICAgIGNvbnN0IGRhdGVUYWcgPSB0aGlzLmdlbkRhdGVUYWcoaW5kZXgpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke21pZ3JhdGlvbnNEaXJ9LyR7ZGF0ZVRhZ31fJHtwY29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHBjb2RlLmZvcm1hdHRlZCk7XG4gICAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgTUlHUlRBSU9OIENSRUFURUQgJHtmaWxlUGF0aH1gKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXBhcmVkQ29kZXMubGVuZ3RoO1xuICB9XG5cbiAgYXN5bmMgY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCOiBLbmV4KTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICAvLyBFbnRpdHkg7Iic7ZqM7ZWY7JesIOyLse2BrFxuICAgIGNvbnN0IGVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIEVudGl0eeyXkOyEnCBNaWdyYXRpb25TZXQg7LaU7LacXG4gICAgY29uc3QgZW50aXR5U2V0c1dpdGhKb2luVGFibGUgPSBlbnRpdHlJZHNcbiAgICAgIC5maWx0ZXIoKGVudGl0eUlkKSA9PiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMubGVuZ3RoID4gMClcbiAgICAgIC5tYXAoKGVudGl0eUlkKSA9PiBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5KEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKSkpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iU66eMIOy2lOy2nFxuICAgIGNvbnN0IGpvaW5UYWJsZXNXaXRoRHVwID0gZW50aXR5U2V0c1dpdGhKb2luVGFibGUuZmxhdE1hcCgoZW50aXR5U2V0KSA9PiBlbnRpdHlTZXQuam9pblRhYmxlcyk7XG4gICAgLy8g7KSR67O1IOygnOqxsCAo7KSR67O17J24IOqyveyasCBpbmRleGVz66W8IOuzke2VqSlcbiAgICBjb25zdCBqb2luVGFibGVzID0gT2JqZWN0LnZhbHVlcyhncm91cChqb2luVGFibGVzV2l0aER1cCwgKGp0KSA9PiBqdC50YWJsZSkpLm1hcCgodGFibGVzKSA9PiB7XG4gICAgICBhc3NlcnQodGFibGVzICE9PSB1bmRlZmluZWQsIFwidGFibGVzIGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgIGlmICh0YWJsZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHJldHVybiB0YWJsZXNbMF07XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi50YWJsZXNbMF0sXG4gICAgICAgIGluZGV4ZXM6IHVuaXF1ZShcbiAgICAgICAgICB0YWJsZXMuZmxhdE1hcCgodCkgPT4gdC5pbmRleGVzKSxcbiAgICAgICAgICAoaW5kZXgpID0+IFtpbmRleC50eXBlLCAuLi5pbmRleC5jb2x1bW5zLnNvcnQoKV0uam9pbihcIi1cIiksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBNaWdyYXRpb25TZXQg67Cw7Je0XG4gICAgY29uc3QgZW50aXR5U2V0czogTWlncmF0aW9uU2V0W10gPSBbLi4uZW50aXR5U2V0c1dpdGhKb2luVGFibGUsIC4uLmpvaW5UYWJsZXNdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IChcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBQb3N0Z3JlU1FMU2NoZW1hUmVhZGVyLmdldE1pZ3JhdGlvblNldEZyb21EQihcbiAgICAgICAgICAgIGNvbXBhcmVEQixcbiAgICAgICAgICAgIGVudGl0eVNldC50YWJsZSxcbiAgICAgICAgICApO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmVudGl0eVNldDoke2VudGl0eVNldC50YWJsZX1gLCBlbnRpdHlTZXQpO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmRiU2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGRiU2V0KTtcblxuICAgICAgICAgIGlmIChkYlNldCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsl4bsnYwsIOyDiOuhnCDthYzsnbTruJQg7IOd7ISxXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVDcmVhdGVDb2RlKGVudGl0eVNldCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7KG07J6s7ZWY64qUIOy8gOydtOyKpFxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQWx0ZXJDb2RlKGVudGl0eVNldCwgZGJTZXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICApXG4gICAgKS5mbGF0KCk7XG5cbiAgICAvLyBub3JtYWwg7YOA7J6F7J20IOyVnuycvOuhnCwgZm9yZWlnbuydtCDrkqTroZxcbiAgICBjb2Rlcy5zb3J0KChjb2RlQSwgY29kZUIpID0+IHtcbiAgICAgIGlmIChjb2RlQS50eXBlID09PSBcImZvcmVpZ25cIiAmJiBjb2RlQi50eXBlID09PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyBTaGFkb3cgREIg7YWM7Iqk7Yq4IOqysOqzvFxuICAgKi9cbiAgYXN5bmMgcnVuU2hhZG93VGVzdCgpOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IHRkYkNvbm4gPSBTb25hbXUuZGJDb25maWcudGVzdC5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gYCR7dGRiQ29ubi5kYXRhYmFzZX1fX21pZ3JhdGlvbl9zaGFkb3dgO1xuXG4gICAgLy8g7YWM7Iqk7Yq4IOyDge2ZqeyXkOyEnOuKlCDtirjrnpzsnq3shZjsnYQg7LSI6riw7ZmU7ZWY6rOgLCDsg4gg642w7J207YSw67Kg7J207IqkIOy7pOuEpeyFmOydhCDqsIDsoLjsmYDslbwg7ZWoXG4gICAgaWYgKGlzVGVzdCgpKSB7XG4gICAgICBhd2FpdCBEQi5jbGVhclRlc3RUcmFuc2FjdGlvbigpO1xuICAgICAgYXdhaXQgREIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIC8vIOq4sOyhtCBTaGFkb3cgREIg7IKt7KCcIO2bhCBTaGFkb3cgREIg7IOd7ISxXG4gICAgY29uc3QgdGRiID0ga25leChTb25hbXUuZGJDb25maWcudGVzdCk7XG4gICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSAke3NoYWRvd0RhdGFiYXNlfSBURU1QTEFURSAke3RkYkNvbm4uZGF0YWJhc2V9YCk7XG5cbiAgICAvLyBTaGFkb3cgRELsl5Ag7Jew6rKwXG4gICAgY29uc3Qgc2RiID0ga25leCh7XG4gICAgICAuLi5Tb25hbXUuZGJDb25maWcudGVzdCxcbiAgICAgIGNvbm5lY3Rpb246IHtcbiAgICAgICAgLi4udGRiQ29ubixcbiAgICAgICAgZGF0YWJhc2U6IHNoYWRvd0RhdGFiYXNlLFxuICAgICAgICBwYXNzd29yZDogdGRiQ29ubi5wYXNzd29yZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBzaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QoKTtcbiAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlNoYWRvdyBEQiDthYzsiqTtirjsl5Ag7ISx6rO17ZaI7Iq164uI64ukIVwiKSwge1xuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oXCJTaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiSDspJEg7JeQ65+sXCIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBTaGFkb3cgREIg7Jew6rKwIOyiheujjFxuICAgICAgYXdhaXQgc2RiLmRlc3Ryb3koKTtcblxuICAgICAgLy8gU2hhZG93IERCIOyCreygnFxuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG5cbiAgICAgIC8vIFRlc3QgREIg7Jew6rKwIOyiheujjFxuICAgICAgYXdhaXQgdGRiLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJhc3NlcnQiLCJjaGFsayIsIm1rZGlyIiwicmVhZGRpciIsInVubGluayIsIndyaXRlRmlsZSIsImtuZXgiLCJwYXRoIiwiZ3JvdXAiLCJzdW0iLCJ1bmlxdWUiLCJTb25hbXUiLCJEQiIsIkVudGl0eU1hbmFnZXIiLCJTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24iLCJOYWl0ZSIsImlzVGVzdCIsImV4aXN0cyIsImdlbmVyYXRlQWx0ZXJDb2RlIiwiZ2VuZXJhdGVDcmVhdGVDb2RlIiwiZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eSIsIlBvc3RncmVTUUxTY2hlbWFSZWFkZXIiLCJNaWdyYXRvciIsImdldE1pZ3JhdGlvbkNvZGVzIiwic3JjTWlncmF0aW9uc0RpciIsImpvaW4iLCJhcGlSb290UGF0aCIsInJlY3Vyc2l2ZSIsImNvZGVzIiwiZmlsdGVyIiwiZiIsImVuZHNXaXRoIiwibWFwIiwibmFtZSIsInJlcGxhY2UiLCJzb3J0IiwiYSIsImIiLCJ0IiwiZ2V0U3RhdHVzIiwiY29ubktleXMiLCJPYmplY3QiLCJrZXlzIiwiZGJDb25maWciLCJrZXkiLCJtaWdyYXRpb25TdGF0dXNFcnJvciIsInN0YXR1c2VzIiwiUHJvbWlzZSIsImFsbCIsImNvbm5LZXkiLCJrbmV4T3B0aW9ucyIsInRDb25uIiwic3RhdHVzIiwibWlncmF0ZSIsImVyciIsImNvbnNvbGUiLCJ3YXJuIiwieWVsbG93IiwiSlNPTiIsInN0cmluZ2lmeSIsImNvbm5lY3Rpb24iLCJFcnJvciIsIm1lc3NhZ2UiLCJTdHJpbmciLCJwZW5kaW5nIiwiZmRMaXN0IiwibGlzdCIsImZkIiwiZmlsZSIsImN1cnJlbnRWZXJzaW9uIiwiX2VyciIsImRlc3Ryb3kiLCJjb25uU3RyaW5nIiwidXNlciIsImhvc3QiLCJwb3J0IiwiZGF0YWJhc2UiLCJwcmVwYXJlZENvZGVzIiwic3RhdHVzMGNvbm4iLCJmaW5kIiwidW5kZWZpbmVkIiwiY29tcGFyZURCY29ubiIsImdlbkNvZGVzIiwiY29tcGFyZU1pZ3JhdGlvbnMiLCJjb25ucyIsImVycm9yIiwicnVuQWN0aW9uIiwiYWN0aW9uIiwidGFyZ2V0cyIsImNvbmZpZ3MiLCJ0YXJnZXQiLCJvcHRpb25zIiwiYyIsImNvbmZpZyIsInJlc3VsdCIsImJhdGNoTm8iLCJhcHBsaWVkIiwibGF0ZXN0Iiwicm9sbGJhY2siLCJ2YWxpZGF0ZURlbGV0YWJsZSIsImNvZGVOYW1lcyIsImFwcGxpZWRDb2RlcyIsImNvZGVOYW1lIiwic29tZSIsImNvbm4iLCJpbmNsdWRlcyIsImNhbkRlbGV0ZSIsImxlbmd0aCIsImRlbENvZGVzIiwiZmlsZVBhdGgiLCJnZW5EYXRlVGFnIiwiaW5kZXgiLCJiYXNlRGF0ZSIsIkRhdGUiLCJkYXRlIiwiZ2V0VGltZSIsInBhZCIsIm51bSIsInNpemUiLCJ0b1N0cmluZyIsInBhZFN0YXJ0IiwiZ2V0RnVsbFllYXIiLCJnZXRNb250aCIsImdldERhdGUiLCJnZXRIb3VycyIsImdldE1pbnV0ZXMiLCJnZXRTZWNvbmRzIiwiZ2VuZXJhdGVQcmVwYXJlZENvZGVzIiwibG9nIiwiZ3JlZW4iLCJtaWdyYXRpb25zRGlyIiwicGNvZGUiLCJlbnRyaWVzIiwiZm9ybWF0dGVkIiwiZGF0ZVRhZyIsInRpdGxlIiwiY29tcGFyZURCIiwiZW50aXR5SWRzIiwiZ2V0QWxsSWRzIiwiZW50aXR5U2V0c1dpdGhKb2luVGFibGUiLCJlbnRpdHlJZCIsImdldCIsInByb3BzIiwiam9pblRhYmxlc1dpdGhEdXAiLCJmbGF0TWFwIiwiZW50aXR5U2V0Iiwiam9pblRhYmxlcyIsInZhbHVlcyIsImp0IiwidGFibGUiLCJ0YWJsZXMiLCJpbmRleGVzIiwidHlwZSIsImNvbHVtbnMiLCJlbnRpdHlTZXRzIiwiZGJTZXQiLCJnZXRNaWdyYXRpb25TZXRGcm9tREIiLCJmbGF0IiwiY29kZUEiLCJjb2RlQiIsInJ1blNoYWRvd1Rlc3QiLCJ0ZGJDb25uIiwidGVzdCIsInNoYWRvd0RhdGFiYXNlIiwiY2xlYXJUZXN0VHJhbnNhY3Rpb24iLCJ0ZGIiLCJtYWdlbnRhIiwicmF3Iiwic2RiIiwicGFzc3dvcmQiLCJlIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxZQUFZLFNBQVM7QUFDNUIsT0FBT0MsV0FBVyxRQUFRO0FBQzFCLFNBQVND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
|