sonamu 0.5.7 → 0.7.0
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 +13 -2
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +71 -2
- 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 +258 -2
- package/dist/api/config.d.ts +90 -0
- package/dist/api/config.d.ts.map +1 -0
- package/dist/api/config.js +25 -0
- package/dist/api/context.d.ts +4 -2
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +3 -2
- package/dist/api/decorators.d.ts +20 -6
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +235 -2
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +9 -2
- package/dist/api/sonamu.d.ts +10 -24
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +514 -2
- 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 +6 -1
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +15 -2
- package/dist/bin/cli.js +519 -2
- package/dist/bin/hot-hook-register.d.ts +11 -0
- package/dist/bin/hot-hook-register.d.ts.map +1 -0
- package/dist/bin/hot-hook-register.js +21 -0
- 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 +95 -2
- 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 +390 -2
- 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 +54 -2
- package/dist/database/db.d.ts +6 -21
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +129 -2
- 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 +109 -2
- package/dist/database/puri.d.ts +41 -23
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +601 -2
- package/dist/database/puri.types.d.ts +25 -6
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +6 -2
- 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 +14 -2
- 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 +365 -2
- package/dist/entity/entity-manager.d.ts +167 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +130 -2
- package/dist/entity/entity.d.ts +5 -3
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +750 -2
- 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 +29 -2
- 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 +85 -2
- 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 +79 -2
- package/dist/file-storage/file-storage.js +75 -2
- package/dist/index.d.ts +18 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -2
- 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 +614 -2
- 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 +213 -2
- package/dist/migration/migrator.d.ts +24 -82
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +330 -2
- 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 +3 -2
- 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 +95 -0
- package/dist/naite/naite.d.ts.map +1 -0
- package/dist/naite/naite.js +316 -0
- package/dist/stream/index.js +3 -2
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +38 -2
- package/dist/syncer/api-parser.d.ts +10 -0
- package/dist/syncer/api-parser.d.ts.map +1 -0
- package/dist/syncer/api-parser.js +240 -0
- package/dist/syncer/checksum.d.ts +21 -0
- package/dist/syncer/checksum.d.ts.map +1 -0
- package/dist/syncer/checksum.js +98 -0
- package/dist/syncer/code-generator.d.ts +20 -0
- package/dist/syncer/code-generator.d.ts.map +1 -0
- package/dist/syncer/code-generator.js +161 -0
- package/dist/syncer/entity-operations.d.ts +17 -0
- package/dist/syncer/entity-operations.d.ts.map +1 -0
- package/dist/syncer/entity-operations.js +59 -0
- package/dist/syncer/file-patterns.d.ts +29 -0
- package/dist/syncer/file-patterns.d.ts.map +1 -0
- package/dist/syncer/file-patterns.js +38 -0
- package/dist/syncer/index.d.ts +6 -0
- package/dist/syncer/index.d.ts.map +1 -1
- package/dist/syncer/index.js +9 -2
- package/dist/syncer/module-loader.d.ts +35 -0
- package/dist/syncer/module-loader.d.ts.map +1 -0
- package/dist/syncer/module-loader.js +87 -0
- package/dist/syncer/syncer.d.ts +98 -106
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +422 -2
- package/dist/template/entity-converter.d.ts +14 -0
- package/dist/template/entity-converter.d.ts.map +1 -0
- package/dist/template/entity-converter.js +108 -0
- package/dist/template/helpers.d.ts +23 -0
- package/dist/template/helpers.d.ts.map +1 -0
- package/dist/template/helpers.js +64 -0
- package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
- package/dist/template/implementations/entity.template.d.ts.map +1 -0
- package/dist/template/implementations/entity.template.js +86 -0
- package/dist/{templates → template/implementations}/generated.template.d.ts +3 -4
- package/dist/template/implementations/generated.template.d.ts.map +1 -0
- package/dist/template/implementations/generated.template.js +249 -0
- package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -4
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
- package/dist/template/implementations/generated_http.template.js +131 -0
- package/dist/{templates → template/implementations}/generated_sso.template.d.ts +4 -5
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
- package/dist/template/implementations/generated_sso.template.js +134 -0
- package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
- package/dist/template/implementations/init_types.template.d.ts.map +1 -0
- package/dist/template/implementations/init_types.template.js +38 -0
- package/dist/template/implementations/model.template.d.ts +17 -0
- package/dist/template/implementations/model.template.d.ts.map +1 -0
- package/dist/template/implementations/model.template.js +181 -0
- package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
- package/dist/template/implementations/model_test.template.d.ts.map +1 -0
- package/dist/template/implementations/model_test.template.js +35 -0
- package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
- package/dist/template/implementations/service.template.d.ts.map +1 -0
- package/dist/template/implementations/service.template.js +201 -0
- package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
- package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
- package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
- package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
- package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
- package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_select.template.js +55 -0
- package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
- package/dist/template/implementations/view_form.template.d.ts.map +1 -0
- package/dist/template/implementations/view_form.template.js +337 -0
- package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_id_all_select.template.js +31 -0
- package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_id_async_select.template.js +105 -0
- package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
- package/dist/template/implementations/view_list.template.d.ts.map +1 -0
- package/dist/template/implementations/view_list.template.js +475 -0
- package/dist/template/implementations/view_list_columns.template.d.ts +17 -0
- package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
- package/dist/template/implementations/view_list_columns.template.js +49 -0
- package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
- package/dist/template/implementations/view_search_input.template.js +64 -0
- package/dist/template/index.d.ts +7 -0
- package/dist/template/index.d.ts.map +1 -0
- package/dist/template/index.js +8 -0
- 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 +49 -0
- package/dist/template/template.d.ts.map +1 -0
- package/dist/template/template.js +60 -0
- package/dist/template/zod-converter.d.ts +51 -0
- package/dist/template/zod-converter.d.ts.map +1 -0
- package/dist/template/zod-converter.js +449 -0
- 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 +89 -2
- 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 +623 -2
- package/dist/types/types.d.ts +747 -143
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +546 -2
- package/dist/typings/knex.d.js +3 -2
- package/dist/utils/async-utils.d.ts +7 -0
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +57 -2
- package/dist/utils/console-util.d.ts +2 -0
- package/dist/utils/console-util.d.ts.map +1 -0
- package/dist/utils/console-util.js +6 -0
- package/dist/utils/controller.d.ts +1 -0
- package/dist/utils/controller.d.ts.map +1 -1
- package/dist/utils/controller.js +29 -2
- package/dist/utils/esm-utils.d.ts +39 -0
- package/dist/utils/esm-utils.d.ts.map +1 -0
- package/dist/utils/esm-utils.js +49 -0
- 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 +17 -2
- package/dist/utils/lodash-able.d.ts.map +1 -1
- package/dist/utils/lodash-able.js +6 -2
- package/dist/utils/model.js +22 -2
- 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 +89 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +60 -0
- package/dist/utils/process-utils.d.ts +13 -0
- package/dist/utils/process-utils.d.ts.map +1 -0
- package/dist/utils/process-utils.js +36 -0
- 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 +46 -2
- 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 +10 -7
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +72 -2
- 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 +19 -2
- package/package.json +65 -27
- 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 +178 -535
- package/src/api/config.ts +125 -0
- package/src/api/context.ts +7 -17
- package/src/api/decorators.ts +176 -46
- package/src/api/index.ts +2 -2
- package/src/api/sonamu.ts +190 -167
- package/src/api/validator.ts +83 -0
- package/src/bin/build-config.ts +8 -1
- package/src/bin/cli.ts +258 -124
- package/src/bin/hot-hook-register.ts +22 -0
- 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 +40 -96
- 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 +229 -148
- package/src/database/puri.types.ts +76 -30
- package/src/database/transaction-context.ts +1 -1
- package/src/database/upsert-builder.ts +262 -132
- package/src/entity/entity-manager.ts +48 -36
- package/src/entity/entity.ts +330 -248
- 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 -10
- package/src/migration/code-generation.ts +185 -172
- package/src/migration/migration-set.ts +80 -293
- package/src/migration/migrator.ts +199 -571
- 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 +415 -0
- package/src/shared/web.shared.ts.txt +20 -24
- package/src/stream/sse.ts +5 -5
- package/src/syncer/api-parser.ts +282 -0
- package/src/syncer/checksum.ts +140 -0
- package/src/syncer/code-generator.ts +198 -0
- package/src/syncer/entity-operations.ts +65 -0
- package/src/syncer/file-patterns.ts +56 -0
- package/src/syncer/index.ts +6 -0
- package/src/syncer/module-loader.ts +128 -0
- package/src/syncer/syncer.ts +389 -1453
- package/src/template/entity-converter.ts +114 -0
- package/src/template/helpers.ts +81 -0
- package/src/{templates → template/implementations}/entity.template.ts +7 -7
- package/src/{templates → template/implementations}/generated.template.ts +101 -101
- package/src/{templates → template/implementations}/generated_http.template.ts +27 -57
- package/src/template/implementations/generated_sso.template.ts +151 -0
- package/src/{templates → template/implementations}/init_types.template.ts +5 -7
- package/src/{templates → template/implementations}/model.template.ts +52 -43
- package/src/{templates → template/implementations}/model_test.template.ts +5 -5
- package/src/{templates → template/implementations}/service.template.ts +66 -82
- package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
- package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +4 -20
- package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
- package/src/{templates → template/implementations}/view_form.template.ts +40 -83
- package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
- package/src/{templates → template/implementations}/view_id_async_select.template.ts +10 -24
- package/src/{templates → template/implementations}/view_list.template.ts +60 -152
- package/src/{templates → template/implementations}/view_list_columns.template.ts +5 -11
- package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
- package/src/template/index.ts +6 -0
- package/src/template/template-manager.ts +166 -0
- package/src/template/template-types.ts +16 -0
- package/src/template/template.ts +105 -0
- package/src/template/zod-converter.ts +525 -0
- package/src/testing/_relation-graph.ts +18 -11
- package/src/testing/fixture-manager.ts +472 -359
- package/src/types/types.ts +553 -308
- package/src/typings/knex.d.ts +7 -9
- package/src/utils/async-utils.ts +23 -10
- package/src/utils/console-util.ts +4 -0
- package/src/utils/controller.ts +3 -0
- package/src/utils/esm-utils.ts +59 -0
- 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 +99 -0
- package/src/utils/process-utils.ts +46 -0
- package/src/utils/sql-parser.ts +23 -5
- package/src/utils/type-utils.ts +83 -0
- package/src/utils/utils.ts +66 -43
- package/src/utils/zod-error.ts +3 -4
- package/dist/api/base-frame.js.map +0 -1
- package/dist/api/caster.js.map +0 -1
- package/dist/api/code-converters.js.map +0 -1
- package/dist/api/context.js.map +0 -1
- package/dist/api/decorators.js.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/sonamu.js.map +0 -1
- package/dist/bin/build-config.js.map +0 -1
- 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 -3
- package/dist/bin/cli-wrapper.js.map +0 -1
- package/dist/bin/cli.js.map +0 -1
- package/dist/database/_batch_update.js.map +0 -1
- package/dist/database/base-model.js.map +0 -1
- package/dist/database/code-generator.js.map +0 -1
- package/dist/database/db.js.map +0 -1
- 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 -2
- package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
- package/dist/database/puri-wrapper.js.map +0 -1
- package/dist/database/puri.js.map +0 -1
- package/dist/database/puri.types.js.map +0 -1
- package/dist/database/transaction-context.js.map +0 -1
- package/dist/database/upsert-builder.js.map +0 -1
- package/dist/entity/entity-manager.js.map +0 -1
- 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 -2
- package/dist/entity/entity-utils.js.map +0 -1
- package/dist/entity/entity.js.map +0 -1
- package/dist/exceptions/error-handler.js.map +0 -1
- package/dist/exceptions/so-exceptions.js.map +0 -1
- package/dist/file-storage/driver.js.map +0 -1
- package/dist/file-storage/file-storage.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/migration/code-generation.js.map +0 -1
- package/dist/migration/migration-set.js.map +0 -1
- package/dist/migration/migrator.js.map +0 -1
- package/dist/migration/types.js.map +0 -1
- package/dist/stream/index.js.map +0 -1
- package/dist/stream/sse.js.map +0 -1
- package/dist/syncer/index.js.map +0 -1
- package/dist/syncer/syncer.js.map +0 -1
- package/dist/templates/base-template.d.ts +0 -13
- package/dist/templates/base-template.d.ts.map +0 -1
- package/dist/templates/base-template.js +0 -2
- package/dist/templates/base-template.js.map +0 -1
- package/dist/templates/entity.template.d.ts.map +0 -1
- package/dist/templates/entity.template.js +0 -2
- package/dist/templates/entity.template.js.map +0 -1
- package/dist/templates/generated.template.d.ts.map +0 -1
- package/dist/templates/generated.template.js +0 -2
- package/dist/templates/generated.template.js.map +0 -1
- package/dist/templates/generated_http.template.d.ts.map +0 -1
- package/dist/templates/generated_http.template.js +0 -2
- package/dist/templates/generated_http.template.js.map +0 -1
- package/dist/templates/generated_sso.template.d.ts.map +0 -1
- package/dist/templates/generated_sso.template.js +0 -2
- package/dist/templates/generated_sso.template.js.map +0 -1
- package/dist/templates/index.d.ts +0 -2
- package/dist/templates/index.d.ts.map +0 -1
- package/dist/templates/index.js +0 -2
- package/dist/templates/index.js.map +0 -1
- package/dist/templates/init_types.template.d.ts.map +0 -1
- package/dist/templates/init_types.template.js +0 -2
- package/dist/templates/init_types.template.js.map +0 -1
- package/dist/templates/model.template.d.ts +0 -17
- package/dist/templates/model.template.d.ts.map +0 -1
- package/dist/templates/model.template.js +0 -2
- package/dist/templates/model.template.js.map +0 -1
- package/dist/templates/model_test.template.d.ts.map +0 -1
- package/dist/templates/model_test.template.js +0 -2
- package/dist/templates/model_test.template.js.map +0 -1
- package/dist/templates/service.template.d.ts.map +0 -1
- package/dist/templates/service.template.js +0 -2
- package/dist/templates/service.template.js.map +0 -1
- package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
- package/dist/templates/view_enums_buttonset.template.js +0 -2
- package/dist/templates/view_enums_buttonset.template.js.map +0 -1
- package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
- package/dist/templates/view_enums_dropdown.template.js +0 -2
- package/dist/templates/view_enums_dropdown.template.js.map +0 -1
- package/dist/templates/view_enums_select.template.d.ts.map +0 -1
- package/dist/templates/view_enums_select.template.js +0 -2
- package/dist/templates/view_enums_select.template.js.map +0 -1
- package/dist/templates/view_form.template.d.ts.map +0 -1
- package/dist/templates/view_form.template.js +0 -2
- package/dist/templates/view_form.template.js.map +0 -1
- package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
- package/dist/templates/view_id_all_select.template.js +0 -2
- package/dist/templates/view_id_all_select.template.js.map +0 -1
- package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
- package/dist/templates/view_id_async_select.template.js +0 -2
- package/dist/templates/view_id_async_select.template.js.map +0 -1
- package/dist/templates/view_list.template.d.ts.map +0 -1
- package/dist/templates/view_list.template.js +0 -2
- package/dist/templates/view_list.template.js.map +0 -1
- package/dist/templates/view_list_columns.template.d.ts +0 -17
- package/dist/templates/view_list_columns.template.d.ts.map +0 -1
- package/dist/templates/view_list_columns.template.js +0 -2
- package/dist/templates/view_list_columns.template.js.map +0 -1
- package/dist/templates/view_search_input.template.d.ts.map +0 -1
- package/dist/templates/view_search_input.template.js +0 -2
- package/dist/templates/view_search_input.template.js.map +0 -1
- package/dist/testing/_relation-graph.js.map +0 -1
- package/dist/testing/fixture-manager.js.map +0 -1
- package/dist/types/types.js.map +0 -1
- package/dist/typings/knex.d.js.map +0 -1
- package/dist/utils/async-utils.js.map +0 -1
- package/dist/utils/controller.js.map +0 -1
- package/dist/utils/fs-utils.js.map +0 -1
- package/dist/utils/lodash-able.js.map +0 -1
- package/dist/utils/model.js.map +0 -1
- package/dist/utils/sql-parser.js.map +0 -1
- package/dist/utils/utils.js.map +0 -1
- package/dist/utils/zod-error.js.map +0 -1
- package/src/bin/cli-wrapper.ts +0 -75
- package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
- package/src/entity/entity-utils.ts +0 -291
- package/src/templates/base-template.ts +0 -19
- package/src/templates/generated_sso.template.ts +0 -138
- package/src/templates/index.ts +0 -1
|
@@ -1,2 +1,623 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get FixtureManager(){return FixtureManager},get FixtureManagerClass(){return FixtureManagerClass}});var _chalk=/*#__PURE__*/_interop_require_default(require("chalk"));var _lodash=/*#__PURE__*/_interop_require_default(require("lodash"));var _api=require("../api");var _entitymanager=require("../entity/entity-manager");var _types=require("../types/types");var _inflection=/*#__PURE__*/_interop_require_default(require("inflection"));var _fs=require("fs");var _relationgraph=require("./_relation-graph");var _knex=/*#__PURE__*/_interop_require_default(require("knex"));var _basemodel=require("../database/base-model");function _array_like_to_array(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function _array_with_holes(arr){if(Array.isArray(arr))return arr}function _array_without_holes(arr){if(Array.isArray(arr))return _array_like_to_array(arr)}function _async_iterator(iterable){var method,async,sync,retry=2;for("undefined"!=typeof Symbol&&(async=Symbol.asyncIterator,sync=Symbol.iterator);retry--;){if(async&&null!=(method=iterable[async]))return method.call(iterable);if(sync&&null!=(method=iterable[sync]))return new AsyncFromSyncIterator(method.call(iterable));async="@@asyncIterator",sync="@@iterator"}throw new TypeError("Object is not async iterable")}function AsyncFromSyncIterator(s){function AsyncFromSyncIteratorContinuation(r){if(Object(r)!==r)return Promise.reject(new TypeError(r+" is not an object."));var done=r.done;return Promise.resolve(r.value).then(function(value){return{value:value,done:done}})}return AsyncFromSyncIterator=function(s){this.s=s,this.n=s.next},AsyncFromSyncIterator.prototype={s:null,n:null,next:function(){return AsyncFromSyncIteratorContinuation(this.n.apply(this.s,arguments))},return:function(value){var ret=this.s.return;return void 0===ret?Promise.resolve({value:value,done:!0}):AsyncFromSyncIteratorContinuation(ret.apply(this.s,arguments))},throw:function(value){var thr=this.s.return;return void 0===thr?Promise.reject(value):AsyncFromSyncIteratorContinuation(thr.apply(this.s,arguments))}},new AsyncFromSyncIterator(s)}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value}catch(error){reject(error);return}if(info.done){resolve(value)}else{Promise.resolve(value).then(_next,_throw)}}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(undefined)})}}function _class_call_check(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _create_class(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor}function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _instanceof(left,right){if(right!=null&&typeof Symbol!=="undefined"&&right[Symbol.hasInstance]){return!!right[Symbol.hasInstance](left)}else{return left instanceof right}}function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}function _iterable_to_array(iter){if(typeof Symbol!=="undefined"&&iter[Symbol.iterator]!=null||iter["@@iterator"]!=null)return Array.from(iter)}function _iterable_to_array_limit(arr,i){var _i=arr==null?null:typeof Symbol!=="undefined"&&arr[Symbol.iterator]||arr["@@iterator"];if(_i==null)return;var _arr=[];var _n=true;var _d=false;var _s,_e;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _non_iterable_rest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _non_iterable_spread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _sliced_to_array(arr,i){return _array_with_holes(arr)||_iterable_to_array_limit(arr,i)||_unsupported_iterable_to_array(arr,i)||_non_iterable_rest()}function _to_consumable_array(arr){return _array_without_holes(arr)||_iterable_to_array(arr)||_unsupported_iterable_to_array(arr)||_non_iterable_spread()}function _type_of(obj){"@swc/helpers - typeof";return obj&&typeof Symbol!=="undefined"&&obj.constructor===Symbol?"symbol":typeof obj}function _unsupported_iterable_to_array(o,minLen){if(!o)return;if(typeof o==="string")return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _array_like_to_array(o,minLen)}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(t[0]&1)throw t[1];return t[1]},trys:[],ops:[]},g=Object.create((typeof Iterator==="function"?Iterator:Object).prototype);return g.next=verb(0),g["throw"]=verb(1),g["return"]=verb(2),typeof Symbol==="function"&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return step([n,v])}}function step(op){if(f)throw new TypeError("Generator is already executing.");while(g&&(g=0,op[0]&&(_=0)),_)try{if(f=1,y&&(t=op[0]&2?y["return"]:op[0]?y["throw"]||((t=y["return"])&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;if(y=0,t)op=[op[0]&2,t.value];switch(op[0]){case 0:case 1:t=op;break;case 4:_.label++;return{value:op[1],done:false};case 5:_.label++;y=op[1];op=[0];continue;case 7:op=_.ops.pop();_.trys.pop();continue;default:if(!(t=_.trys,t=t.length>0&&t[t.length-1])&&(op[0]===6||op[0]===2)){_=0;continue}if(op[0]===3&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(op[0]===6&&_.label<t[1]){_.label=t[1];t=op;break}if(t&&_.label<t[2]){_.label=t[2];_.ops.push(op);break}if(t[2])_.ops.pop();_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e];y=0}finally{f=t=0}if(op[0]&5)throw op[1];return{value:op[0]?op[1]:void 0,done:true}}}function _ts_values(o){var s=typeof Symbol==="function"&&Symbol.iterator,m=s&&o[s],i=0;if(m)return m.call(o);if(o&&typeof o.length==="number")return{next:function(){if(o&&i>=o.length)o=void 0;return{value:o&&o[i++],done:!o}}};throw new TypeError(s?"Object is not iterable.":"Symbol.iterator is not defined.")}var FixtureManagerClass=/*#__PURE__*/function(){"use strict";function FixtureManagerClass(){_class_call_check(this,FixtureManagerClass);_define_property(this,"_tdb",null);_define_property(this,"_fdb",null);_define_property(this,"cachedTableNames",null);_define_property(this,"relationGraph",new _relationgraph.RelationGraph);_define_property(this,"visitedRecords",new Set)}_create_class(FixtureManagerClass,[{key:"tdb",get:function get(){if(this._tdb===null){throw new Error("FixtureManager has not been initialized")}return this._tdb},set:function set(tdb){this._tdb=tdb}},{key:"fdb",get:function get(){if(this._fdb===null){throw new Error("FixtureManager has not been initialized")}return this._fdb},set:function set(fdb){this._fdb=fdb}},{key:"init",value:function init(){if(this._tdb!==null){return}if(_api.Sonamu.dbConfig.test&&_api.Sonamu.dbConfig.production_master){var tConn=_api.Sonamu.dbConfig.test.connection;var pConn=_api.Sonamu.dbConfig.production_master.connection;var _tConn_host,_tConn_port,_pConn_host,_pConn_port;if("".concat((_tConn_host=tConn.host)!==null&&_tConn_host!==void 0?_tConn_host:"localhost",":").concat((_tConn_port=tConn.port)!==null&&_tConn_port!==void 0?_tConn_port:3306,"/").concat(tConn.database)==="".concat((_pConn_host=pConn.host)!==null&&_pConn_host!==void 0?_pConn_host:"localhost",":").concat((_pConn_port=pConn.port)!==null&&_pConn_port!==void 0?_pConn_port:3306,"/").concat(pConn.database)){throw new Error("테스트DB와 프로덕션DB에 동일한 데이터베이스가 사용되었습니다.")}}this.tdb=(0,_knex.default)(_api.Sonamu.dbConfig.test);this.fdb=(0,_knex.default)(_api.Sonamu.dbConfig.fixture_local)}},{key:"cleanAndSeed",value:function cleanAndSeed(usingTables){return _async_to_generator(function(){var _this,tableNames,tableListStr,_ref,fdbChecksumRows,_ref1,tdbChecksumRows,fdbChecksums,tdbChecksums,changedTables;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;return[4,function(){return _async_to_generator(function(){var _ref,tables,tableNames;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(usingTables){return[2,usingTables]}if(this.cachedTableNames){return[2,this.cachedTableNames]}return[4,this.tdb.raw("SHOW TABLE STATUS WHERE Engine IS NOT NULL AND Name != 'migrations'")];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),tables=_ref[0];tableNames=tables.map(function(tableInfo){return tableInfo["Name"]});this.cachedTableNames=tableNames;return[2,tableNames]}})}).call(_this)}()];case 1:tableNames=_state.sent();tableListStr=tableNames.join(", ");return[4,this.fdb.raw("CHECKSUM TABLE ".concat(tableListStr))];case 2:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),fdbChecksumRows=_ref[0];return[4,this.tdb.raw("CHECKSUM TABLE ".concat(tableListStr))];case 3:_ref1=_sliced_to_array.apply(void 0,[_state.sent(),1]),tdbChecksumRows=_ref1[0];fdbChecksums=new Map(fdbChecksumRows.map(function(row){return[row.Table.split(".").pop(),row.Checksum]}));tdbChecksums=new Map(tdbChecksumRows.map(function(row){return[row.Table.split(".").pop(),row.Checksum]}));changedTables=tableNames.filter(function(tableName){return fdbChecksums.get(tableName)!==tdbChecksums.get(tableName)});return[4,this.tdb.transaction(function(trx){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,Promise.all(changedTables.map(function(tableName){return _async_to_generator(function(){var rawQuery;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,trx(tableName).truncate()];case 2:_state.sent();rawQuery="INSERT INTO ".concat(_api.Sonamu.dbConfig.test.connection.database,".").concat(tableName,"\n SELECT * FROM ").concat(_api.Sonamu.dbConfig.fixture_local.connection.database,".").concat(tableName);return[4,trx.raw(rawQuery)];case 3:_state.sent();return[2]}})})()}))];case 2:_state.sent();return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 1")];case 3:_state.sent();return[2]}})})()})];case 4:_state.sent();return[2]}})}).call(this)}},{key:"getChecksum",value:function getChecksum(db,tableName){return _async_to_generator(function(){var _ref,_ref_,checksumRow;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.raw("CHECKSUM TABLE ".concat(tableName))];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),_ref_=_sliced_to_array(_ref[0],1),checksumRow=_ref_[0];return[2,checksumRow.Checksum]}})})()}},{key:"sync",value:function sync(){return _async_to_generator(function(){var _this,frdb,_ref,tables,tableNames;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;frdb=(0,_knex.default)(_api.Sonamu.dbConfig.fixture_remote);return[4,this.fdb.raw("SHOW TABLE STATUS WHERE Engine IS NOT NULL")];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),tables=_ref[0];tableNames=tables.map(function(table){return table.Name});console.log(_chalk.default.magenta("SYNC..."));return[4,Promise.all(tableNames.map(function(tableName){return _async_to_generator(function(){var remoteChecksum,localChecksum;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(tableName.startsWith("knex_migrations")){return[2]}return[4,this.getChecksum(frdb,tableName)];case 1:remoteChecksum=_state.sent();return[4,this.getChecksum(this.fdb,tableName)];case 2:localChecksum=_state.sent();if(!(remoteChecksum!==localChecksum))return[3,4];return[4,this.fdb.transaction(function(transaction){return _async_to_generator(function(){var rows;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,transaction.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,transaction(tableName).truncate()];case 2:_state.sent();return[4,frdb(tableName)];case 3:rows=_state.sent();if(rows.length===0){return[2]}console.log(_chalk.default.blue(tableName),rows.length);return[4,transaction.insert(rows.map(function(row){return Object.fromEntries(Object.entries(row).map(function(param){var _param=_sliced_to_array(param,2),key=_param[0],value=_param[1];if(value===null){return[key,null]}else if(typeof value==="boolean"){return[key,value?1:0]}else if((typeof value==="undefined"?"undefined":_type_of(value))==="object"&&!_instanceof(value,Date)){return[key,JSON.stringify(value)]}else{return[key,value]}}))})).into(tableName)];case 4:_state.sent();console.log("OK");return[4,transaction.raw("SET FOREIGN_KEY_CHECKS = 1")];case 5:_state.sent();return[2]}})})()})];case 3:_state.sent();_state.label=4;case 4:return[2]}})}).call(_this)}))];case 2:_state.sent();console.log(_chalk.default.magenta("DONE!"));return[4,frdb.destroy()];case 3:_state.sent();return[2]}})}).call(this)}},{key:"importFixture",value:function importFixture(entityId,ids){return _async_to_generator(function(){var _this,queries,_,wdb,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,query,_ref,rsh,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;this.visitedRecords.clear();_=_lodash.default.uniq;return[4,Promise.all(ids.map(function(id){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getImportQueries(entityId,"id",id)];case 1:return[2,_state.sent()]}})}).call(_this)}))];case 1:queries=_.apply(_lodash.default,[_state.sent().flat()]);wdb=_basemodel.BaseModel.getDB("w");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_iterator=queries[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];query=_step.value;return[4,wdb.raw(query)];case 4:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),rsh=_ref[0];console.log({query:query,info:rsh.info});_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:return[2]}})}).call(this)}},{key:"getImportQueries",value:function getImportQueries(entityId,field,id){return _async_to_generator(function(){var _this,recordKey,entity,wdb,_ref,row,fixtureDatabase,realDatabase,selfQuery,args,relQueries;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;recordKey="".concat(entityId,"#").concat(field,"#").concat(id);if(this.visitedRecords.has(recordKey)){return[2,[]]}this.visitedRecords.add(recordKey);console.log({entityId:entityId,field:field,id:id});entity=_entitymanager.EntityManager.get(entityId);wdb=_basemodel.BaseModel.getDB("w");return[4,wdb(entity.table).where(field,id).limit(1)];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),row=_ref[0];if(row===undefined){throw new Error("".concat(entityId,"#").concat(id," row를 찾을 수 없습니다."))}fixtureDatabase=_api.Sonamu.dbConfig.fixture_remote.connection.database;realDatabase=_api.Sonamu.dbConfig.production_master.connection.database;selfQuery="INSERT IGNORE INTO `".concat(fixtureDatabase,"`.`").concat(entity.table,"` (SELECT * FROM `").concat(realDatabase,"`.`").concat(entity.table,"` WHERE `id` = ").concat(id,")");args=Object.entries(entity.relations).filter(function(param){var _param=_sliced_to_array(param,2),relation=_param[1];return(0,_types.isBelongsToOneRelationProp)(relation)||(0,_types.isOneToOneRelationProp)(relation)&&relation.customJoinClause===undefined}).map(function(param){var _param=_sliced_to_array(param,2),relation=_param[1];var _$field;var _$id;if((0,_types.isOneToOneRelationProp)(relation)&&!relation.hasJoinColumn){var _relatedEntity_props_find;var relatedEntity=_entitymanager.EntityManager.get(relation.with);var relatedIdColumnName=(_relatedEntity_props_find=relatedEntity.props.find(function(p){return(0,_types.isRelationProp)(p)&&p.with===entity.id}))===null||_relatedEntity_props_find===void 0?void 0:_relatedEntity_props_find.name;if(!relatedIdColumnName){throw new Error("".concat(relatedEntity.id,"의 ").concat(entity.id," 관계 프롭을 찾을 수 없습니다."))}_$field="".concat(relatedIdColumnName,"_id");_$id=row["id"]}else{_$field="id";_$id=row["".concat(relation.name,"_id")]}return{entityId:relation.with,field:_$field,id:_$id}}).filter(function(arg){return arg.id!==null});return[4,Promise.all(args.map(function(args){return _async_to_generator(function(){return _ts_generator(this,function(_state){return[2,this.getImportQueries(args.entityId,args.field,args.id)]})}).call(_this)}))];case 2:relQueries=_state.sent();return[2,_to_consumable_array(_lodash.default.uniq(relQueries.reverse().flat())).concat([selfQuery])]}})}).call(this)}},{key:"destroy",value:function destroy(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:if(!this._tdb)return[3,2];return[4,this._tdb.destroy()];case 1:_state.sent();this._tdb=null;_state.label=2;case 2:if(!this._fdb)return[3,4];return[4,this._fdb.destroy()];case 3:_state.sent();this._fdb=null;_state.label=4;case 4:return[4,_basemodel.BaseModel.destroy()];case 5:_state.sent();return[2]}})}).call(this)}},{key:"getFixtures",value:function getFixtures(sourceDBName,targetDBName,searchOptions){return _async_to_generator(function(){var _entity_props_find,sourceDB,targetDB,entityId,field,value,searchType,entity,column,query,rows,fixtures,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_this,_loop,_iterator,_step,err,_iteratorAbruptCompletion,_didIteratorError1,_iteratorError1,_iterator1,_step1,_value,fixture,entity1,row,_ref,record,uniqueRow,_ref1,record1,err1;return _ts_generator(this,function(_state){switch(_state.label){case 0:sourceDB=(0,_knex.default)(_api.Sonamu.dbConfig[sourceDBName]);targetDB=(0,_knex.default)(_api.Sonamu.dbConfig[targetDBName]);entityId=searchOptions.entityId,field=searchOptions.field,value=searchOptions.value,searchType=searchOptions.searchType;entity=_entitymanager.EntityManager.get(entityId);column=((_entity_props_find=entity.props.find(function(prop){return prop.name===field}))===null||_entity_props_find===void 0?void 0:_entity_props_find.type)==="relation"?"".concat(field,"_id"):field;query=sourceDB(entity.table);if(searchType==="equals"){query=query.where(column,value)}else if(searchType==="like"){query=query.where(column,"like","%".concat(value,"%"))}return[4,query];case 1:rows=_state.sent();if(rows.length===0){throw new Error("No records found")}fixtures=[];_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_loop=function(){var row,_fixtures,initialRecordsLength,newRecords,currentFixtureRecord;return _ts_generator(this,function(_state){switch(_state.label){case 0:row=_step.value;initialRecordsLength=fixtures.length;return[4,_this.createFixtureRecord(entity,row)];case 1:newRecords=_state.sent();(_fixtures=fixtures).push.apply(_fixtures,_to_consumable_array(newRecords));currentFixtureRecord=fixtures.find(function(r){return r.fixtureId==="".concat(entityId,"#").concat(row.id)});if(currentFixtureRecord){currentFixtureRecord.fetchedRecords=fixtures.filter(function(r){return r.fixtureId!==currentFixtureRecord.fixtureId}).slice(initialRecordsLength).map(function(r){return r.fixtureId})}return[2]}})};_iterator=rows[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_this=this;return[5,_ts_values(_loop())];case 4:_state.sent();_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:_iteratorAbruptCompletion=false,_didIteratorError1=false;_state.label=10;case 10:_state.trys.push([10,20,21,26]);_iterator1=_async_iterator(fixtures);_state.label=11;case 11:return[4,_iterator1.next()];case 12:if(!(_iteratorAbruptCompletion=!(_step1=_state.sent()).done))return[3,19];_value=_step1.value;fixture=_value;entity1=_entitymanager.EntityManager.get(fixture.entityId);return[4,targetDB(entity1.table).where("id",fixture.id).first()];case 13:row=_state.sent();if(!row)return[3,15];return[4,this.createFixtureRecord(entity1,row,{singleRecord:true,_db:targetDB})];case 14:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),record=_ref[0];fixture.target=record;return[3,18];case 15:return[4,this.checkUniqueViolation(targetDB,entity1,fixture)];case 16:uniqueRow=_state.sent();if(!uniqueRow)return[3,18];return[4,this.createFixtureRecord(entity1,uniqueRow,{singleRecord:true,_db:targetDB})];case 17:_ref1=_sliced_to_array.apply(void 0,[_state.sent(),1]),record1=_ref1[0];fixture.unique=record1;_state.label=18;case 18:_iteratorAbruptCompletion=false;return[3,11];case 19:return[3,26];case 20:err1=_state.sent();_didIteratorError1=true;_iteratorError1=err1;return[3,26];case 21:_state.trys.push([21,,24,25]);if(!(_iteratorAbruptCompletion&&_iterator1.return!=null))return[3,23];return[4,_iterator1.return()];case 22:_state.sent();_state.label=23;case 23:return[3,25];case 24:if(_didIteratorError1){throw _iteratorError1}return[7];case 25:return[7];case 26:return[2,_lodash.default.uniqBy(fixtures,function(f){return f.fixtureId})]}})}).call(this)}},{key:"createFixtureRecord",value:function createFixtureRecord(entity,row,options){return _async_to_generator(function(){var records,visitedEntities,create;return _ts_generator(this,function(_state){switch(_state.label){case 0:records=[];visitedEntities=new Set;create=function(entity,row){return _async_to_generator(function(){var fixtureId,record,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,prop,_options__db,db,relatedEntity,throughTable,fromColumn,toColumn,relatedIds,relatedEntity1,relatedIds1,relatedEntity2,relatedProp,relatedRow,relatedId,relatedEntity3,relatedRow1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId="".concat(entity.id,"#").concat(row.id);if(visitedEntities.has(fixtureId)){return[2]}visitedEntities.add(fixtureId);record={fixtureId:fixtureId,entityId:entity.id,id:row.id,columns:{},fetchedRecords:[],belongsRecords:[]};_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,14,15,16]);_iterator=entity.props[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,13];prop=_step.value;if((0,_types.isVirtualProp)(prop)){return[3,12]}record.columns[prop.name]={prop:prop,value:row[prop.name]};db=(_options__db=options===null||options===void 0?void 0:options._db)!==null&&_options__db!==void 0?_options__db:_basemodel.BaseModel.getDB("w");if(!(0,_types.isManyToManyRelationProp)(prop))return[3,4];relatedEntity=_entitymanager.EntityManager.get(prop.with);throughTable=prop.joinTable;fromColumn="".concat(_inflection.default.singularize(entity.table),"_id");toColumn="".concat(_inflection.default.singularize(relatedEntity.table),"_id");return[4,db(throughTable).where(fromColumn,row.id).pluck(toColumn)];case 3:relatedIds=_state.sent();record.columns[prop.name].value=relatedIds;return[3,12];case 4:if(!(0,_types.isHasManyRelationProp)(prop))return[3,6];relatedEntity1=_entitymanager.EntityManager.get(prop.with);return[4,db(relatedEntity1.table).where(prop.joinColumn,row.id).pluck("id")];case 5:relatedIds1=_state.sent();record.columns[prop.name].value=relatedIds1;return[3,12];case 6:if(!((0,_types.isOneToOneRelationProp)(prop)&&!prop.hasJoinColumn))return[3,9];relatedEntity2=_entitymanager.EntityManager.get(prop.with);relatedProp=relatedEntity2.props.find(function(p){return(0,_types.isRelationProp)(p)&&p.with===entity.id});if(!relatedProp)return[3,8];return[4,db(relatedEntity2.table).where("id",row.id).first()];case 7:relatedRow=_state.sent();record.columns[prop.name].value=relatedRow===null||relatedRow===void 0?void 0:relatedRow.id;_state.label=8;case 8:return[3,12];case 9:if(!(0,_types.isRelationProp)(prop))return[3,12];relatedId=row["".concat(prop.name,"_id")];record.columns[prop.name].value=relatedId;if(relatedId){record.belongsRecords.push("".concat(prop.with,"#").concat(relatedId))}if(!(!(options===null||options===void 0?void 0:options.singleRecord)&&relatedId))return[3,12];relatedEntity3=_entitymanager.EntityManager.get(prop.with);return[4,db(relatedEntity3.table).where("id",relatedId).first()];case 10:relatedRow1=_state.sent();if(!relatedRow1)return[3,12];return[4,create(relatedEntity3,relatedRow1)];case 11:_state.sent();_state.label=12;case 12:_iteratorNormalCompletion=true;return[3,2];case 13:return[3,16];case 14:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,16];case 15:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 16:records.push(record);return[2]}})})()};return[4,create(entity,row)];case 1:_state.sent();return[2,records]}})})()}},{key:"insertFixtures",value:function insertFixtures(dbName,_fixtures){return _async_to_generator(function(){var _this,fixtures,insertionOrder,db,records,_iteratorAbruptCompletion,_didIteratorError,_iteratorError,_iterator,_step,_value,r,entity,record,err1;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;fixtures=_lodash.default.uniqBy(_fixtures,function(f){return f.fixtureId});this.relationGraph.buildGraph(fixtures);insertionOrder=this.relationGraph.getInsertionOrder();db=(0,_knex.default)(_api.Sonamu.dbConfig[dbName]);return[4,db.transaction(function(trx){return _async_to_generator(function(){var _iteratorNormalCompletion,_didIteratorError,_iteratorError,_this,_loop,_iterator,_step,err,_iteratorNormalCompletion1,_didIteratorError1,_iteratorError1,_this1,_loop1,_iterator1,_step1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_loop=function(){var fixtureId,fixture,result;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId=_step.value;fixture=fixtures.find(function(f){return f.fixtureId===fixtureId});return[4,_this.insertFixture(trx,fixture)];case 1:result=_state.sent();if(result.id!==fixture.id){console.log(_chalk.default.yellow("Unique constraint violation: ".concat(fixture.entityId,"#").concat(fixture.id," -> ").concat(fixture.entityId,"#").concat(result.id)));fixtures.forEach(function(f){Object.values(f.columns).forEach(function(column){if(column.prop.type==="relation"&&column.prop.with===result.entityId&&column.value===fixture.id){column.value=result.id}})});fixture.id=result.id}return[2]}})};_iterator=insertionOrder[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_this=this;return[5,_ts_values(_loop())];case 4:_state.sent();_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:_iteratorNormalCompletion1=true,_didIteratorError1=false,_iteratorError1=undefined;_state.label=10;case 10:_state.trys.push([10,15,16,17]);_loop1=function(){var fixtureId,fixture;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId=_step1.value;fixture=fixtures.find(function(f){return f.fixtureId===fixtureId});return[4,_this1.handleManyToManyRelations(trx,fixture,fixtures)];case 1:_state.sent();return[2]}})};_iterator1=insertionOrder[Symbol.iterator]();_state.label=11;case 11:if(!!(_iteratorNormalCompletion1=(_step1=_iterator1.next()).done))return[3,14];_this1=this;return[5,_ts_values(_loop1())];case 12:_state.sent();_state.label=13;case 13:_iteratorNormalCompletion1=true;return[3,11];case 14:return[3,17];case 15:err=_state.sent();_didIteratorError1=true;_iteratorError1=err;return[3,17];case 16:try{if(!_iteratorNormalCompletion1&&_iterator1.return!=null){_iterator1.return()}}finally{if(_didIteratorError1){throw _iteratorError1}}return[7];case 17:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 1")];case 18:_state.sent();return[2]}})}).call(_this)})];case 1:_state.sent();records=[];_iteratorAbruptCompletion=false,_didIteratorError=false;_state.label=2;case 2:_state.trys.push([2,8,9,14]);_iterator=_async_iterator(fixtures);_state.label=3;case 3:return[4,_iterator.next()];case 4:if(!(_iteratorAbruptCompletion=!(_step=_state.sent()).done))return[3,7];_value=_step.value;r=_value;entity=_entitymanager.EntityManager.get(r.entityId);return[4,db(entity.table).where("id",r.id).first()];case 5:record=_state.sent();records.push({entityId:r.entityId,data:record});_state.label=6;case 6:_iteratorAbruptCompletion=false;return[3,3];case 7:return[3,14];case 8:err1=_state.sent();_didIteratorError=true;_iteratorError=err1;return[3,14];case 9:_state.trys.push([9,,12,13]);if(!(_iteratorAbruptCompletion&&_iterator.return!=null))return[3,11];return[4,_iterator.return()];case 10:_state.sent();_state.label=11;case 11:return[3,13];case 12:if(_didIteratorError){throw _iteratorError}return[7];case 13:return[7];case 14:return[2,_lodash.default.uniqBy(records,function(r){return"".concat(r.entityId,"#").concat(r.data.id)})]}})}).call(this)}},{key:"prepareInsertData",value:function prepareInsertData(fixture){var insertData={};var _iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{for(var _iterator=Object.entries(fixture.columns)[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var _step_value=_sliced_to_array(_step.value,2),propName=_step_value[0],column=_step_value[1];if((0,_types.isVirtualProp)(column.prop)){continue}var prop=column.prop;if(!(0,_types.isRelationProp)(prop)){if(prop.type==="json"){insertData[propName]=JSON.stringify(column.value)}else if(prop.type==="timestamp"||prop.type==="datetime"){insertData[propName]=new Date(column.value)}else{insertData[propName]=column.value}}else if((0,_types.isBelongsToOneRelationProp)(prop)||(0,_types.isOneToOneRelationProp)(prop)&&prop.hasJoinColumn){insertData["".concat(propName,"_id")]=column.value}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}return insertData}},{key:"insertFixture",value:function insertFixture(db,fixture){return _async_to_generator(function(){var insertData,entity,uniqueFound,found,q,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:insertData=this.prepareInsertData(fixture);entity=_entitymanager.EntityManager.get(fixture.entityId);_state.label=1;case 1:_state.trys.push([1,5,,6]);return[4,this.checkUniqueViolation(db,entity,fixture)];case 2:uniqueFound=_state.sent();if(uniqueFound){return[2,{entityId:fixture.entityId,id:uniqueFound.id}]}return[4,db(entity.table).where("id",fixture.id).first()];case 3:found=_state.sent();if(found&&!fixture.override){return[2,{entityId:fixture.entityId,id:found.id}]}q=db.insert(insertData).into(entity.table);return[4,q.onDuplicateUpdate.apply(q,Object.keys(insertData))];case 4:_state.sent();return[2,{entityId:fixture.entityId,id:fixture.id}];case 5:err=_state.sent();console.log(err);throw err;case 6:return[2]}})}).call(this)}},{key:"handleManyToManyRelations",value:function handleManyToManyRelations(db,fixture,fixtures){return _async_to_generator(function(){var _iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,6,7,8]);_loop=function(){var _step_value,column,prop,joinTable,relatedIds,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_step_value=_sliced_to_array(_step.value,2),column=_step_value[1];prop=column.prop;if(!(0,_types.isManyToManyRelationProp)(prop))return[3,8];joinTable=prop.joinTable;relatedIds=column.value;_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,6,7,8]);_loop=function(){var relatedId,entity,relatedEntity,_obj,_ref,found,_obj1,newIds;return _ts_generator(this,function(_state){switch(_state.label){case 0:relatedId=_step1.value;if(!fixtures.find(function(f){return f.fixtureId==="".concat(prop.with,"#").concat(relatedId)})){return[2,"continue"]}entity=_entitymanager.EntityManager.get(fixture.entityId);relatedEntity=_entitymanager.EntityManager.get(prop.with);if(!entity||!relatedEntity){throw new Error("Entity not found: ".concat(fixture.entityId,", ").concat(prop.with))}return[4,db(joinTable).where((_obj={},_define_property(_obj,"".concat(_inflection.default.singularize(entity.table),"_id"),fixture.id),_define_property(_obj,"".concat(_inflection.default.singularize(relatedEntity.table),"_id"),relatedId),_obj)).limit(1)];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),found=_ref[0];if(found){return[2,"continue"]}return[4,db(joinTable).insert((_obj1={},_define_property(_obj1,"".concat(_inflection.default.singularize(entity.table),"_id"),fixture.id),_define_property(_obj1,"".concat(_inflection.default.singularize(relatedEntity.table),"_id"),relatedId),_obj1))];case 2:newIds=_state.sent();console.log(_chalk.default.green("Inserted into ".concat(joinTable,": ").concat(entity.table,"(").concat(fixture.id,") - ").concat(relatedEntity.table,"(").concat(relatedId,") ID: ").concat(newIds)));return[2]}})};_iterator=relatedIds[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step1=_iterator.next()).done))return[3,5];return[5,_ts_values(_loop())];case 3:_state.sent();_state.label=4;case 4:_iteratorNormalCompletion=true;return[3,2];case 5:return[3,8];case 6:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,8];case 7:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 8:return[2]}})};_iterator=Object.entries(fixture.columns)[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,5];return[5,_ts_values(_loop())];case 3:_state.sent();_state.label=4;case 4:_iteratorNormalCompletion=true;return[3,2];case 5:return[3,8];case 6:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,8];case 7:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 8:return[2]}})})()}},{key:"addFixtureLoader",value:function addFixtureLoader(code){return _async_to_generator(function(){var path,content,fixtureLoaderStart,fixtureLoaderEnd,newContent;return _ts_generator(this,function(_state){path=_api.Sonamu.apiRootPath+"/src/testing/fixture.ts";content=(0,_fs.readFileSync)(path).toString();fixtureLoaderStart=content.indexOf("const fixtureLoader = {");fixtureLoaderEnd=content.indexOf("};",fixtureLoaderStart);if(fixtureLoaderStart!==-1&&fixtureLoaderEnd!==-1){newContent=content.slice(0,fixtureLoaderEnd)+" "+code+"\n"+content.slice(fixtureLoaderEnd);(0,_fs.writeFileSync)(path,newContent)}else{throw new Error("Failed to find fixtureLoader in fixture.ts")}return[2]})})()}},{key:"checkUniqueViolation",value:function checkUniqueViolation(db,entity,fixture){return _async_to_generator(function(){var _uniqueIndexes,uniqueIndexes,uniqueQuery,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step,_ref,uniqueFound;return _ts_generator(this,function(_state){switch(_state.label){case 0:_uniqueIndexes=entity.indexes.filter(function(i){return i.type==="unique"});uniqueIndexes=_uniqueIndexes.filter(function(index){return index.columns.every(function(column){return!column.startsWith("".concat(entity.table,"__"))})});if(uniqueIndexes.length===0){return[2,null]}uniqueQuery=db(entity.table);_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{_loop=function(){var index=_step.value;var containsNull=index.columns.some(function(column){var field=column.split("_id")[0];return fixture.columns[field].value===null});if(containsNull){return"continue"}uniqueQuery=uniqueQuery.orWhere(function(qb){var _iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{for(var _iterator=index.columns[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var column=_step.value;var field=column.split("_id")[0];if(Array.isArray(fixture.columns[field].value)){qb.whereIn(column,fixture.columns[field].value)}else{qb.andWhere(column,fixture.columns[field].value)}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}})};for(_iterator=uniqueIndexes[Symbol.iterator]();!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true)_loop()}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}return[4,uniqueQuery];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),uniqueFound=_ref[0];return[2,uniqueFound]}})})()}}]);return FixtureManagerClass}();var FixtureManager=new FixtureManagerClass;
|
|
2
|
-
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
5
|
+
import inflection from "inflection";
|
|
6
|
+
import knex from "knex";
|
|
7
|
+
import { unique } from "radashi";
|
|
8
|
+
import { inspect } from "util";
|
|
9
|
+
import { Sonamu } from "../api/index.js";
|
|
10
|
+
import { BaseModel } from "../database/base-model.js";
|
|
11
|
+
import { UpsertBuilder } from "../database/upsert-builder.js";
|
|
12
|
+
import { EntityManager } from "../entity/entity-manager.js";
|
|
13
|
+
import { isBelongsToOneRelationProp, isHasManyRelationProp, isManyToManyRelationProp, isOneToOneRelationProp, isRelationProp, isVirtualProp } from "../types/types.js";
|
|
14
|
+
import { RelationGraph } from "./_relation-graph.js";
|
|
15
|
+
export class FixtureManagerClass {
|
|
16
|
+
_tdb = null;
|
|
17
|
+
set tdb(tdb) {
|
|
18
|
+
this._tdb = tdb;
|
|
19
|
+
}
|
|
20
|
+
get tdb() {
|
|
21
|
+
if (this._tdb === null) {
|
|
22
|
+
throw new Error("FixtureManager has not been initialized");
|
|
23
|
+
}
|
|
24
|
+
return this._tdb;
|
|
25
|
+
}
|
|
26
|
+
_fdb = null;
|
|
27
|
+
set fdb(fdb) {
|
|
28
|
+
this._fdb = fdb;
|
|
29
|
+
}
|
|
30
|
+
get fdb() {
|
|
31
|
+
if (this._fdb === null) {
|
|
32
|
+
throw new Error("FixtureManager has not been initialized");
|
|
33
|
+
}
|
|
34
|
+
return this._fdb;
|
|
35
|
+
}
|
|
36
|
+
cachedTableNames = null;
|
|
37
|
+
relationGraph = new RelationGraph();
|
|
38
|
+
// UpsertBuilder 기반 import를 위한 상태
|
|
39
|
+
builder = new UpsertBuilder();
|
|
40
|
+
fixtureRefMap = new Map();
|
|
41
|
+
uuidToFixtureId = new Map();
|
|
42
|
+
skippedFixtures = new Map();
|
|
43
|
+
init() {
|
|
44
|
+
if (this._tdb !== null) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (Sonamu.dbConfig.test && Sonamu.dbConfig.production_master) {
|
|
48
|
+
const tConn = Sonamu.dbConfig.test.connection;
|
|
49
|
+
const pConn = Sonamu.dbConfig.production_master.connection;
|
|
50
|
+
if (`${tConn.host ?? "localhost"}:${tConn.port ?? 5432}/${tConn.database}` === `${pConn.host ?? "localhost"}:${pConn.port ?? 5432}/${pConn.database}`) {
|
|
51
|
+
throw new Error(`테스트DB와 프로덕션DB에 동일한 데이터베이스가 사용되었습니다.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.tdb = knex(Sonamu.dbConfig.test);
|
|
55
|
+
this.fdb = knex(Sonamu.dbConfig.fixture_remote);
|
|
56
|
+
}
|
|
57
|
+
async getChecksum(db, tableName) {
|
|
58
|
+
const [[checksumRow]] = await db.raw(`CHECKSUM TABLE ${tableName}`);
|
|
59
|
+
return checksumRow.Checksum;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
이제 FixtureManager.sync() 는 checksum 비교 없이 create database template 으로 수행합니다.
|
|
63
|
+
*/ async sync() {
|
|
64
|
+
const fixtureConn = Sonamu.dbConfig.fixture_remote.connection;
|
|
65
|
+
const testConn = Sonamu.dbConfig.test.connection;
|
|
66
|
+
// PostgreSQL 패스워드 환경변수 설정
|
|
67
|
+
const pgEnv = {
|
|
68
|
+
PGPASSWORD: testConn.password || ""
|
|
69
|
+
};
|
|
70
|
+
// 1. 연결 강제 종료
|
|
71
|
+
execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "
|
|
72
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
73
|
+
FROM pg_stat_activity
|
|
74
|
+
WHERE datname = '${testConn.database}'
|
|
75
|
+
AND pid <> pg_backend_pid();
|
|
76
|
+
"`, {
|
|
77
|
+
stdio: "inherit",
|
|
78
|
+
env: {
|
|
79
|
+
...process.env,
|
|
80
|
+
...pgEnv
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
execSync(`psql -h ${fixtureConn.host} -p ${fixtureConn.port ?? 5432} -U ${fixtureConn.user} -d postgres -c "
|
|
84
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
85
|
+
FROM pg_stat_activity
|
|
86
|
+
WHERE datname = '${fixtureConn.database}'
|
|
87
|
+
AND pid <> pg_backend_pid();
|
|
88
|
+
"`, {
|
|
89
|
+
stdio: "inherit",
|
|
90
|
+
env: {
|
|
91
|
+
...process.env,
|
|
92
|
+
...pgEnv
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// 2. DROP DATABASE (별도 실행!)
|
|
96
|
+
execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "DROP DATABASE IF EXISTS \\"${testConn.database}\\""`, {
|
|
97
|
+
stdio: "inherit",
|
|
98
|
+
env: {
|
|
99
|
+
...process.env,
|
|
100
|
+
...pgEnv
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// 3. CREATE DATABASE
|
|
104
|
+
execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "CREATE DATABASE \\"${testConn.database}\\" TEMPLATE \\"${fixtureConn.database}\\""`, {
|
|
105
|
+
stdio: "inherit",
|
|
106
|
+
env: {
|
|
107
|
+
...process.env,
|
|
108
|
+
...pgEnv
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
visitedRecords = new Set();
|
|
113
|
+
async importFixture(entityId, ids) {
|
|
114
|
+
// 방문 기록 초기화 (새로운 import 작업 시작)
|
|
115
|
+
this.visitedRecords.clear();
|
|
116
|
+
const queries = unique((await Promise.all(ids.map(async (id)=>{
|
|
117
|
+
return await this.getImportQueries(entityId, "id", id);
|
|
118
|
+
}))).flat());
|
|
119
|
+
const wdb = BaseModel.getDB("w");
|
|
120
|
+
for (const query of queries){
|
|
121
|
+
const [rsh] = await wdb.raw(query);
|
|
122
|
+
console.log({
|
|
123
|
+
query,
|
|
124
|
+
info: rsh.info
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async getImportQueries(entityId, field, id) {
|
|
129
|
+
const recordKey = `${entityId}#${field}#${id}`;
|
|
130
|
+
// 순환 참조 방지: 이미 방문한 레코드는 스킵
|
|
131
|
+
if (this.visitedRecords.has(recordKey)) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
this.visitedRecords.add(recordKey);
|
|
135
|
+
console.log({
|
|
136
|
+
entityId,
|
|
137
|
+
field,
|
|
138
|
+
id
|
|
139
|
+
});
|
|
140
|
+
const entity = EntityManager.get(entityId);
|
|
141
|
+
const wdb = BaseModel.getDB("w");
|
|
142
|
+
// 여기서 실DB의 row 가져옴
|
|
143
|
+
const [row] = await wdb(entity.table).where(field, id).limit(1);
|
|
144
|
+
if (row === undefined) {
|
|
145
|
+
throw new Error(`${entityId}#${id} row를 찾을 수 없습니다.`);
|
|
146
|
+
}
|
|
147
|
+
// 픽스쳐DB, 실DB
|
|
148
|
+
const fixtureDatabase = Sonamu.dbConfig.fixture_remote.connection.database;
|
|
149
|
+
const realDatabase = Sonamu.dbConfig.production_master.connection.database;
|
|
150
|
+
const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${entity.table}\` (SELECT * FROM \`${realDatabase}\`.\`${entity.table}\` WHERE \`id\` = ${id})`;
|
|
151
|
+
const args = Object.entries(entity.relations).filter(([, relation])=>isBelongsToOneRelationProp(relation) || isOneToOneRelationProp(relation) && relation.customJoinClause === undefined).map(([, relation])=>{
|
|
152
|
+
/*
|
|
153
|
+
BelongsToOne인 경우
|
|
154
|
+
Category / 'id' / row[category_id] 호출
|
|
155
|
+
OneToOne에 joinColumn === true 인 경우
|
|
156
|
+
Profile / 'id' / row[profile_id] 호출
|
|
157
|
+
OneToOne에 joinColumn === false 인 경우
|
|
158
|
+
Profile / 'profile_id' / row['id'] 호출
|
|
159
|
+
*/ let field;
|
|
160
|
+
let id;
|
|
161
|
+
if (isOneToOneRelationProp(relation) && !relation.hasJoinColumn) {
|
|
162
|
+
const relatedEntity = EntityManager.get(relation.with);
|
|
163
|
+
const relatedIdColumnName = relatedEntity.props.find((p)=>isRelationProp(p) && p.with === entity.id)?.name;
|
|
164
|
+
if (!relatedIdColumnName) {
|
|
165
|
+
throw new Error(`${relatedEntity.id}의 ${entity.id} 관계 프롭을 찾을 수 없습니다.`);
|
|
166
|
+
}
|
|
167
|
+
field = `${relatedIdColumnName}_id`;
|
|
168
|
+
id = row.id;
|
|
169
|
+
} else {
|
|
170
|
+
field = "id";
|
|
171
|
+
id = row[`${relation.name}_id`];
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
entityId: relation.with,
|
|
175
|
+
field,
|
|
176
|
+
id
|
|
177
|
+
};
|
|
178
|
+
}).filter((arg)=>arg.id !== null);
|
|
179
|
+
const relQueries = await Promise.all(args.map(async (args)=>{
|
|
180
|
+
return this.getImportQueries(args.entityId, args.field, args.id);
|
|
181
|
+
}));
|
|
182
|
+
return [
|
|
183
|
+
...unique(relQueries.reverse().flat()),
|
|
184
|
+
selfQuery
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
async destroy() {
|
|
188
|
+
if (this._tdb) {
|
|
189
|
+
await this._tdb.destroy();
|
|
190
|
+
this._tdb = null;
|
|
191
|
+
}
|
|
192
|
+
if (this._fdb) {
|
|
193
|
+
await this._fdb.destroy();
|
|
194
|
+
this._fdb = null;
|
|
195
|
+
}
|
|
196
|
+
await BaseModel.destroy();
|
|
197
|
+
}
|
|
198
|
+
async getFixtures(sourceDBName, targetDBName, searchOptions, duplicateCheck) {
|
|
199
|
+
const sourceDB = knex(Sonamu.dbConfig[sourceDBName]);
|
|
200
|
+
const targetDB = knex(Sonamu.dbConfig[targetDBName]);
|
|
201
|
+
const { entityId, field, value, searchType } = searchOptions;
|
|
202
|
+
const entity = EntityManager.get(entityId);
|
|
203
|
+
const column = entity.props.find((prop)=>prop.name === field)?.type === "relation" ? `${field}_id` : field;
|
|
204
|
+
let query = sourceDB(entity.table);
|
|
205
|
+
if (searchType === "equals") {
|
|
206
|
+
query = query.where(column, value);
|
|
207
|
+
} else if (searchType === "like") {
|
|
208
|
+
query = query.where(column, "like", `%${value}%`);
|
|
209
|
+
}
|
|
210
|
+
const rows = await query;
|
|
211
|
+
if (rows.length === 0) {
|
|
212
|
+
throw new Error("No records found");
|
|
213
|
+
}
|
|
214
|
+
const fixtures = [];
|
|
215
|
+
for (const row of rows){
|
|
216
|
+
const initialRecordsLength = fixtures.length;
|
|
217
|
+
const newRecords = await this.createFixtureRecord(entity, row, {
|
|
218
|
+
_db: sourceDB
|
|
219
|
+
});
|
|
220
|
+
fixtures.push(...newRecords);
|
|
221
|
+
const currentFixtureRecord = fixtures.find((r)=>r.fixtureId === `${entityId}#${row.id}`);
|
|
222
|
+
if (currentFixtureRecord) {
|
|
223
|
+
// 현재 fixture로부터 생성된 fetchedRecords 설정
|
|
224
|
+
currentFixtureRecord.fetchedRecords = fixtures.filter((r)=>r.fixtureId !== currentFixtureRecord.fixtureId).slice(initialRecordsLength).map((r)=>r.fixtureId);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for await (const fixture of fixtures){
|
|
228
|
+
const entity = EntityManager.get(fixture.entityId);
|
|
229
|
+
// 사용자 지정 컬럼 기준 중복 확인 → target
|
|
230
|
+
const customColumns = duplicateCheck?.columns?.[fixture.entityId];
|
|
231
|
+
if (customColumns && customColumns.length > 0) {
|
|
232
|
+
const customDuplicateRow = await this.checkDuplicateByColumns(targetDB, entity, fixture, customColumns);
|
|
233
|
+
if (customDuplicateRow) {
|
|
234
|
+
const [record] = await this.createFixtureRecord(entity, customDuplicateRow, {
|
|
235
|
+
singleRecord: true,
|
|
236
|
+
_db: targetDB
|
|
237
|
+
});
|
|
238
|
+
fixture.target = record;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Unique index 기준 중복 확인 → fixture.unique
|
|
242
|
+
const uniqueRow = await this.checkUniqueViolation(targetDB, entity, fixture);
|
|
243
|
+
if (uniqueRow) {
|
|
244
|
+
const [record] = await this.createFixtureRecord(entity, uniqueRow, {
|
|
245
|
+
singleRecord: true,
|
|
246
|
+
_db: targetDB
|
|
247
|
+
});
|
|
248
|
+
fixture.unique = record;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
await targetDB.destroy();
|
|
252
|
+
await sourceDB.destroy();
|
|
253
|
+
return unique(fixtures, (f)=>f.fixtureId);
|
|
254
|
+
}
|
|
255
|
+
async createFixtureRecord(entity, row, options) {
|
|
256
|
+
const records = [];
|
|
257
|
+
const visitedEntities = new Set();
|
|
258
|
+
const create = async (entity, row)=>{
|
|
259
|
+
const fixtureId = `${entity.id}#${row.id}`;
|
|
260
|
+
if (visitedEntities.has(fixtureId)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
visitedEntities.add(fixtureId);
|
|
264
|
+
const record = {
|
|
265
|
+
fixtureId,
|
|
266
|
+
entityId: entity.id,
|
|
267
|
+
id: row.id,
|
|
268
|
+
columns: {},
|
|
269
|
+
fetchedRecords: [],
|
|
270
|
+
belongsRecords: []
|
|
271
|
+
};
|
|
272
|
+
for (const prop of entity.props){
|
|
273
|
+
if (isVirtualProp(prop)) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
record.columns[prop.name] = {
|
|
277
|
+
prop: prop,
|
|
278
|
+
value: row[prop.name]
|
|
279
|
+
};
|
|
280
|
+
const db = options?._db ?? BaseModel.getDB("w");
|
|
281
|
+
if (isManyToManyRelationProp(prop)) {
|
|
282
|
+
const relatedEntity = EntityManager.get(prop.with);
|
|
283
|
+
const throughTable = prop.joinTable;
|
|
284
|
+
const fromColumn = `${inflection.singularize(entity.table)}_id`;
|
|
285
|
+
const toColumn = `${inflection.singularize(relatedEntity.table)}_id`;
|
|
286
|
+
const relatedIds = await db(throughTable).where(fromColumn, row.id).pluck(toColumn);
|
|
287
|
+
record.columns[prop.name].value = relatedIds;
|
|
288
|
+
} else if (isHasManyRelationProp(prop)) {
|
|
289
|
+
const relatedEntity = EntityManager.get(prop.with);
|
|
290
|
+
const relatedIds = await db(relatedEntity.table).where(prop.joinColumn, row.id).pluck("id");
|
|
291
|
+
record.columns[prop.name].value = relatedIds;
|
|
292
|
+
} else if (isOneToOneRelationProp(prop) && !prop.hasJoinColumn) {
|
|
293
|
+
const relatedEntity = EntityManager.get(prop.with);
|
|
294
|
+
const relatedProp = relatedEntity.props.find((p)=>isRelationProp(p) && p.with === entity.id);
|
|
295
|
+
if (relatedProp) {
|
|
296
|
+
const relatedRow = await db(relatedEntity.table).where("id", row.id).first();
|
|
297
|
+
record.columns[prop.name].value = relatedRow?.id;
|
|
298
|
+
}
|
|
299
|
+
} else if (isRelationProp(prop)) {
|
|
300
|
+
const relatedId = row[`${prop.name}_id`];
|
|
301
|
+
record.columns[prop.name].value = relatedId;
|
|
302
|
+
if (relatedId) {
|
|
303
|
+
record.belongsRecords.push(`${prop.with}#${relatedId}`);
|
|
304
|
+
}
|
|
305
|
+
if (!options?.singleRecord && relatedId) {
|
|
306
|
+
const relatedEntity = EntityManager.get(prop.with);
|
|
307
|
+
const relatedRow = await db(relatedEntity.table).where("id", relatedId).first();
|
|
308
|
+
if (relatedRow) {
|
|
309
|
+
await create(relatedEntity, relatedRow);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
records.push(record);
|
|
315
|
+
};
|
|
316
|
+
await create(entity, row);
|
|
317
|
+
return records;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 1. RelationGraph로 fixture 단위 삽입 순서 계산 (self-reference 포함)
|
|
321
|
+
* 2. 순서대로 UpsertBuilder에 등록 (UBRef로 참조 관계 표현)
|
|
322
|
+
* 3. 테이블별 upsert 실행 (ID는 DB가 자동 할당)
|
|
323
|
+
*/ async insertFixtures(dbName, _fixtures) {
|
|
324
|
+
const fixtures = unique(_fixtures, (f)=>f.fixtureId);
|
|
325
|
+
// 초기화
|
|
326
|
+
this.builder = new UpsertBuilder();
|
|
327
|
+
this.fixtureRefMap = new Map();
|
|
328
|
+
this.uuidToFixtureId = new Map();
|
|
329
|
+
this.skippedFixtures = new Map();
|
|
330
|
+
const db = knex(Sonamu.dbConfig[dbName]);
|
|
331
|
+
const results = [];
|
|
332
|
+
try {
|
|
333
|
+
// 1. RelationGraph로 fixture 단위 삽입 순서 계산
|
|
334
|
+
this.relationGraph.buildGraph(fixtures);
|
|
335
|
+
const insertionOrder = this.relationGraph.getInsertionOrder();
|
|
336
|
+
// 2. 순서대로 UpsertBuilder에 등록 (override 체크)
|
|
337
|
+
for (const fixtureId of insertionOrder){
|
|
338
|
+
const fixture = fixtures.find((f)=>f.fixtureId === fixtureId);
|
|
339
|
+
if (!fixture) continue;
|
|
340
|
+
const hasTarget = !!fixture.target;
|
|
341
|
+
const hasUnique = !!fixture.unique;
|
|
342
|
+
const hasDuplicate = hasTarget || hasUnique;
|
|
343
|
+
// 중복이 있고 override=false인 경우: 스킵
|
|
344
|
+
if (hasDuplicate && !fixture.override) {
|
|
345
|
+
// 기존 레코드 ID 저장 (unique 우선, 없으면 target)
|
|
346
|
+
const existingId = fixture.unique?.id ?? fixture.target?.id;
|
|
347
|
+
assert(existingId);
|
|
348
|
+
this.skippedFixtures.set(fixtureId, {
|
|
349
|
+
entityId: fixture.entityId,
|
|
350
|
+
existingId
|
|
351
|
+
});
|
|
352
|
+
console.log(chalk.yellow(`Skipped ${fixture.entityId}#${fixture.id} (existing: #${existingId}, override: false)`));
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
this.registerFixture(fixture);
|
|
356
|
+
console.log(chalk.blue(`Registered ${fixture.entityId}#${fixture.id}${fixture.override ? ` (override existing: #${fixture.target?.id})` : ""}`));
|
|
357
|
+
}
|
|
358
|
+
// 3. 테이블별 upsert 실행
|
|
359
|
+
const tableOrder = this.getTableOrder(fixtures);
|
|
360
|
+
await db.transaction(async (trx)=>{
|
|
361
|
+
const insertedIdsByTable = new Map();
|
|
362
|
+
for (const tableName of tableOrder){
|
|
363
|
+
if (!this.builder.hasTable(tableName)) continue;
|
|
364
|
+
// upsert 실행 전 uuid 목록 저장
|
|
365
|
+
const table = this.builder.getTable(tableName);
|
|
366
|
+
const uuids = table.rows.map((row)=>row.uuid);
|
|
367
|
+
console.log(chalk.blue(`Upserting ${tableName} with ${uuids.length} rows`));
|
|
368
|
+
await this.builder.upsert(trx, tableName);
|
|
369
|
+
// upsert된 row들의 uuid -> id 매핑 구축
|
|
370
|
+
if (uuids.length > 0) {
|
|
371
|
+
const uuidToId = new Map();
|
|
372
|
+
const rows = await trx(tableName).select("uuid", "id").whereIn("uuid", uuids);
|
|
373
|
+
for (const row of rows){
|
|
374
|
+
uuidToId.set(row.uuid, row.id);
|
|
375
|
+
}
|
|
376
|
+
insertedIdsByTable.set(tableName, uuidToId);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// 4. ManyToMany 관계 처리
|
|
380
|
+
await this.processManyToManyRelations(trx, fixtures, insertedIdsByTable);
|
|
381
|
+
// 5. 결과 수집
|
|
382
|
+
for (const fixture of fixtures){
|
|
383
|
+
const entity = EntityManager.get(fixture.entityId);
|
|
384
|
+
// 스킵된 fixture는 기존 레코드 정보로 결과 추가
|
|
385
|
+
const skipped = this.skippedFixtures.get(fixture.fixtureId);
|
|
386
|
+
if (skipped) {
|
|
387
|
+
results.push({
|
|
388
|
+
entityId: fixture.entityId,
|
|
389
|
+
data: await trx(entity.table).where("id", skipped.existingId).first()
|
|
390
|
+
});
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
const ref = this.fixtureRefMap.get(fixture.fixtureId);
|
|
394
|
+
if (ref) {
|
|
395
|
+
const uuidToId = insertedIdsByTable.get(entity.table);
|
|
396
|
+
const insertedId = uuidToId?.get(ref.uuid);
|
|
397
|
+
if (insertedId !== undefined) {
|
|
398
|
+
results.push({
|
|
399
|
+
entityId: fixture.entityId,
|
|
400
|
+
data: await trx(entity.table).where("id", insertedId).first()
|
|
401
|
+
});
|
|
402
|
+
console.log(chalk.green(`Inserted into ${entity.table}: #${fixture.id} -> #${insertedId}`));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
} finally{
|
|
408
|
+
await db.destroy();
|
|
409
|
+
}
|
|
410
|
+
return unique(results, (r)=>`${r.entityId}#${r.data.id}`);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* FixtureRecord를 UpsertBuilder에 등록
|
|
414
|
+
*/ registerFixture(fixture) {
|
|
415
|
+
const entity = EntityManager.get(fixture.entityId);
|
|
416
|
+
const row = {};
|
|
417
|
+
// Override 모드 판단: target 또는 unique가 있고 override=true인 경우
|
|
418
|
+
const existingRecord = fixture.target ?? fixture.unique;
|
|
419
|
+
const isOverrideMode = fixture.override && existingRecord;
|
|
420
|
+
for (const [propName, column] of Object.entries(fixture.columns)){
|
|
421
|
+
const prop = column.prop;
|
|
422
|
+
if (isVirtualProp(prop)) {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
// id/uuid 처리: Override 모드일 때만 기존 값 사용
|
|
426
|
+
if (propName === "id" || propName === "uuid") {
|
|
427
|
+
if (isOverrideMode && existingRecord) {
|
|
428
|
+
// Override: 기존 레코드의 값 사용 → UPDATE
|
|
429
|
+
row[propName] = existingRecord.columns[propName]?.value;
|
|
430
|
+
}
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (isRelationProp(prop)) {
|
|
434
|
+
if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) && prop.hasJoinColumn) {
|
|
435
|
+
const relatedId = column.value;
|
|
436
|
+
if (relatedId !== null && relatedId !== undefined) {
|
|
437
|
+
const relatedFixtureId = `${prop.with}#${relatedId}`;
|
|
438
|
+
// 먼저 skip된 fixture인지 확인
|
|
439
|
+
const skippedExistingId = this.skippedFixtures.get(relatedFixtureId)?.existingId;
|
|
440
|
+
if (skippedExistingId !== undefined) {
|
|
441
|
+
// skip된 fixture → target DB의 기존 레코드 id 사용
|
|
442
|
+
row[`${propName}_id`] = skippedExistingId;
|
|
443
|
+
} else {
|
|
444
|
+
const relatedRef = this.fixtureRefMap.get(relatedFixtureId);
|
|
445
|
+
if (relatedRef) {
|
|
446
|
+
// 이미 등록된 fixture 참조 → UBRef 사용
|
|
447
|
+
row[`${propName}_id`] = relatedRef;
|
|
448
|
+
} else {
|
|
449
|
+
// fixtures에 포함되지 않은 레코드 → ID 그대로 사용
|
|
450
|
+
row[`${propName}_id`] = relatedId;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
} else {
|
|
454
|
+
row[`${propName}_id`] = null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// HasMany, ManyToMany는 별도 처리
|
|
458
|
+
} else {
|
|
459
|
+
// 일반 컬럼
|
|
460
|
+
row[propName] = this.convertColumnValue(prop, column.value);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
console.log(chalk.blue(`Registering ${entity.table} - ${inspect(row, false, null, true)}`));
|
|
464
|
+
const ref = this.builder.register(entity.table, row);
|
|
465
|
+
this.fixtureRefMap.set(fixture.fixtureId, ref);
|
|
466
|
+
this.uuidToFixtureId.set(ref.uuid, fixture.fixtureId);
|
|
467
|
+
return ref;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* 컬럼 값 변환
|
|
471
|
+
*/ convertColumnValue(prop, value) {
|
|
472
|
+
if (value === null || value === undefined) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
switch(prop.type){
|
|
476
|
+
case "json":
|
|
477
|
+
// UpsertBuilder.register에서 JSON.stringify 처리하므로 object 그대로 전달
|
|
478
|
+
return value;
|
|
479
|
+
case "date":
|
|
480
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
481
|
+
return new Date(value);
|
|
482
|
+
}
|
|
483
|
+
return value;
|
|
484
|
+
default:
|
|
485
|
+
return value;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* 테이블 순서 추출 (fixtures에 포함된 테이블만)
|
|
490
|
+
*/ getTableOrder(fixtures) {
|
|
491
|
+
const tables = [];
|
|
492
|
+
const seen = new Set();
|
|
493
|
+
for (const fixture of fixtures){
|
|
494
|
+
const entity = EntityManager.get(fixture.entityId);
|
|
495
|
+
if (!seen.has(entity.table)) {
|
|
496
|
+
seen.add(entity.table);
|
|
497
|
+
tables.push(entity.table);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return tables;
|
|
501
|
+
}
|
|
502
|
+
async processManyToManyRelations(trx, fixtures, insertedIdsByTable) {
|
|
503
|
+
for (const fixture of fixtures){
|
|
504
|
+
const entity = EntityManager.get(fixture.entityId);
|
|
505
|
+
const sourceRef = this.fixtureRefMap.get(fixture.fixtureId);
|
|
506
|
+
if (!sourceRef) continue;
|
|
507
|
+
const sourceUuidToId = insertedIdsByTable.get(entity.table);
|
|
508
|
+
const sourceId = sourceUuidToId?.get(sourceRef.uuid);
|
|
509
|
+
if (sourceId === undefined) continue;
|
|
510
|
+
for (const [, column] of Object.entries(fixture.columns)){
|
|
511
|
+
const prop = column.prop;
|
|
512
|
+
if (isManyToManyRelationProp(prop) && Array.isArray(column.value)) {
|
|
513
|
+
// 선택되지 않은 ManyToMany 관계는 저장하지 않음
|
|
514
|
+
const targetTable = EntityManager.get(prop.with);
|
|
515
|
+
if (this.builder.hasTable(targetTable.table) === false) continue;
|
|
516
|
+
const relatedIds = column.value;
|
|
517
|
+
if (relatedIds.length === 0) continue;
|
|
518
|
+
const joinTable = prop.joinTable;
|
|
519
|
+
const relatedEntity = EntityManager.get(prop.with);
|
|
520
|
+
const sourceColumn = `${inflection.singularize(entity.table)}_id`;
|
|
521
|
+
const targetColumn = `${inflection.singularize(relatedEntity.table)}_id`;
|
|
522
|
+
for (const relatedId of relatedIds){
|
|
523
|
+
const relatedFixtureId = `${prop.with}#${relatedId}`;
|
|
524
|
+
const relatedRef = this.fixtureRefMap.get(relatedFixtureId);
|
|
525
|
+
let targetId;
|
|
526
|
+
if (relatedRef) {
|
|
527
|
+
const relatedUuidToId = insertedIdsByTable.get(relatedEntity.table);
|
|
528
|
+
const resolvedId = relatedUuidToId?.get(relatedRef.uuid);
|
|
529
|
+
if (resolvedId === undefined) {
|
|
530
|
+
console.warn(`Related fixture ${relatedFixtureId} not found in insertedIds, skipping`);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
targetId = resolvedId;
|
|
534
|
+
} else {
|
|
535
|
+
targetId = relatedId;
|
|
536
|
+
}
|
|
537
|
+
// JoinTable에 삽입
|
|
538
|
+
const [found] = await trx(joinTable).where({
|
|
539
|
+
[sourceColumn]: sourceId,
|
|
540
|
+
[targetColumn]: targetId
|
|
541
|
+
}).limit(1);
|
|
542
|
+
if (!found) {
|
|
543
|
+
await trx(joinTable).insert({
|
|
544
|
+
[sourceColumn]: sourceId,
|
|
545
|
+
[targetColumn]: targetId
|
|
546
|
+
});
|
|
547
|
+
console.log(chalk.green(`Inserted into ${joinTable}: ${entity.table}(${sourceId}) - ${relatedEntity.table}(${targetId})`));
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
async checkUniqueViolation(db, entity, fixture) {
|
|
555
|
+
const _uniqueIndexes = entity.indexes?.filter((i)=>i.type === "unique") ?? [];
|
|
556
|
+
const uniqueIndexes = _uniqueIndexes.filter((index)=>index.columns.every((column)=>!column.startsWith(`${entity.table}__`)));
|
|
557
|
+
if (uniqueIndexes.length === 0) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
let uniqueQuery = db(entity.table);
|
|
561
|
+
let hasCondition = false;
|
|
562
|
+
for (const index of uniqueIndexes){
|
|
563
|
+
// 컬럼 중 하나라도 null이면 유니크 제약을 위반하지 않기 때문에 해당 인덱스는 무시
|
|
564
|
+
const containsNull = index.columns.some((column)=>{
|
|
565
|
+
const field = column.replace(/_id$/, "");
|
|
566
|
+
return fixture.columns[field]?.value === null;
|
|
567
|
+
});
|
|
568
|
+
if (containsNull) {
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
uniqueQuery = uniqueQuery.orWhere((qb)=>{
|
|
572
|
+
for (const column of index.columns){
|
|
573
|
+
const field = column.replace(/_id$/, "");
|
|
574
|
+
if (Array.isArray(fixture.columns[field]?.value)) {
|
|
575
|
+
qb.whereIn(column, fixture.columns[field].value);
|
|
576
|
+
} else {
|
|
577
|
+
qb.andWhere(column, fixture.columns[field]?.value);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
hasCondition = true;
|
|
582
|
+
}
|
|
583
|
+
if (!hasCondition) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
const [uniqueFound] = await uniqueQuery;
|
|
587
|
+
return uniqueFound;
|
|
588
|
+
}
|
|
589
|
+
async checkDuplicateByColumns(db, entity, fixture, columns) {
|
|
590
|
+
if (columns.length === 0) {
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
const whereClause = {};
|
|
594
|
+
for (const column of columns){
|
|
595
|
+
// relation 필드인 경우 _id 붙이기
|
|
596
|
+
const prop = entity.props.find((p)=>p.name === column);
|
|
597
|
+
const dbColumn = prop && isRelationProp(prop) ? `${column}_id` : column;
|
|
598
|
+
const value = fixture.columns[column]?.value;
|
|
599
|
+
// null 값이 포함된 경우 중복 확인 스킵
|
|
600
|
+
if (value === null || value === undefined) {
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
whereClause[dbColumn] = value;
|
|
604
|
+
}
|
|
605
|
+
const [found] = await db(entity.table).where(whereClause).limit(1);
|
|
606
|
+
return found;
|
|
607
|
+
}
|
|
608
|
+
async addFixtureLoader(code) {
|
|
609
|
+
const path = `${Sonamu.apiRootPath}/src/testing/fixture.ts`;
|
|
610
|
+
const content = readFileSync(path).toString();
|
|
611
|
+
const fixtureLoaderStart = content.indexOf("const fixtureLoader = {");
|
|
612
|
+
const fixtureLoaderEnd = content.indexOf("};", fixtureLoaderStart);
|
|
613
|
+
if (fixtureLoaderStart !== -1 && fixtureLoaderEnd !== -1) {
|
|
614
|
+
const newContent = `${content.slice(0, fixtureLoaderEnd)} ${code}\n${content.slice(fixtureLoaderEnd)}`;
|
|
615
|
+
writeFileSync(path, newContent);
|
|
616
|
+
} else {
|
|
617
|
+
throw new Error("Failed to find fixtureLoader in fixture.ts");
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
export const FixtureManager = new FixtureManagerClass();
|
|
622
|
+
|
|
623
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2ZpeHR1cmUtbWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0IGluZmxlY3Rpb24gZnJvbSBcImluZmxlY3Rpb25cIjtcbmltcG9ydCBrbmV4LCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyB1bmlxdWUgfSBmcm9tIFwicmFkYXNoaVwiO1xuaW1wb3J0IHsgaW5zcGVjdCB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpXCI7XG5pbXBvcnQgeyBCYXNlTW9kZWwgfSBmcm9tIFwiLi4vZGF0YWJhc2UvYmFzZS1tb2RlbFwiO1xuaW1wb3J0IHR5cGUgeyBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgdHlwZSBVQlJlZiwgVXBzZXJ0QnVpbGRlciB9IGZyb20gXCIuLi9kYXRhYmFzZS91cHNlcnQtYnVpbGRlclwiO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHkgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eVwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7XG4gIHR5cGUgRW50aXR5UHJvcCxcbiAgdHlwZSBGaXh0dXJlSW1wb3J0UmVzdWx0LFxuICB0eXBlIEZpeHR1cmVSZWNvcmQsXG4gIHR5cGUgRml4dHVyZVNlYXJjaE9wdGlvbnMsXG4gIGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wLFxuICBpc0hhc01hbnlSZWxhdGlvblByb3AsXG4gIGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbiAgaXNPbmVUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNSZWxhdGlvblByb3AsXG4gIGlzVmlydHVhbFByb3AsXG4gIHR5cGUgTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbn0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBSZWxhdGlvbkdyYXBoIH0gZnJvbSBcIi4vX3JlbGF0aW9uLWdyYXBoXCI7XG5cbi8qKiDsgqzsmqnsnpAg7KeA7KCVIOykkeuztSDtmZXsnbgg7Lus65+8IChlbnRpdHlJZOuzhOuhnCDsp4DsoJUpICovXG5leHBvcnQgaW50ZXJmYWNlIER1cGxpY2F0ZUNoZWNrT3B0aW9ucyB7XG4gIGNvbHVtbnM/OiB7XG4gICAgW2VudGl0eUlkOiBzdHJpbmddOiBzdHJpbmdbXTtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIEZpeHR1cmVNYW5hZ2VyQ2xhc3Mge1xuICBwcml2YXRlIF90ZGI6IEtuZXggfCBudWxsID0gbnVsbDtcbiAgc2V0IHRkYih0ZGI6IEtuZXgpIHtcbiAgICB0aGlzLl90ZGIgPSB0ZGI7XG4gIH1cbiAgZ2V0IHRkYigpOiBLbmV4IHtcbiAgICBpZiAodGhpcy5fdGRiID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaXh0dXJlTWFuYWdlciBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWRcIik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl90ZGI7XG4gIH1cblxuICBwcml2YXRlIF9mZGI6IEtuZXggfCBudWxsID0gbnVsbDtcbiAgc2V0IGZkYihmZGI6IEtuZXgpIHtcbiAgICB0aGlzLl9mZGIgPSBmZGI7XG4gIH1cbiAgZ2V0IGZkYigpOiBLbmV4IHtcbiAgICBpZiAodGhpcy5fZmRiID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaXh0dXJlTWFuYWdlciBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWRcIik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9mZGI7XG4gIH1cbiAgY2FjaGVkVGFibGVOYW1lczogc3RyaW5nW10gfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIHJlbGF0aW9uR3JhcGggPSBuZXcgUmVsYXRpb25HcmFwaCgpO1xuXG4gIC8vIFVwc2VydEJ1aWxkZXIg6riw67CYIGltcG9ydOulvCDsnITtlZwg7IOB7YOcXG4gIHByaXZhdGUgYnVpbGRlcjogVXBzZXJ0QnVpbGRlciA9IG5ldyBVcHNlcnRCdWlsZGVyKCk7XG4gIHByaXZhdGUgZml4dHVyZVJlZk1hcDogTWFwPHN0cmluZywgVUJSZWY+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHV1aWRUb0ZpeHR1cmVJZDogTWFwPHN0cmluZywgc3RyaW5nPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBza2lwcGVkRml4dHVyZXM6IE1hcDxzdHJpbmcsIHsgZW50aXR5SWQ6IHN0cmluZzsgZXhpc3RpbmdJZDogbnVtYmVyIH0+ID0gbmV3IE1hcCgpO1xuXG4gIGluaXQoKSB7XG4gICAgaWYgKHRoaXMuX3RkYiAhPT0gbnVsbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoU29uYW11LmRiQ29uZmlnLnRlc3QgJiYgU29uYW11LmRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyKSB7XG4gICAgICBjb25zdCB0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnICYge1xuICAgICAgICBwb3J0PzogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIGNvbnN0IHBDb25uID0gU29uYW11LmRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnICYge1xuICAgICAgICBwb3J0PzogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIGlmIChcbiAgICAgICAgYCR7dENvbm4uaG9zdCA/PyBcImxvY2FsaG9zdFwifToke3RDb25uLnBvcnQgPz8gNTQzMn0vJHt0Q29ubi5kYXRhYmFzZX1gID09PVxuICAgICAgICBgJHtwQ29ubi5ob3N0ID8/IFwibG9jYWxob3N0XCJ9OiR7cENvbm4ucG9ydCA/PyA1NDMyfS8ke3BDb25uLmRhdGFiYXNlfWBcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYO2FjOyKpO2KuERC7JmAIO2UhOuhnOuNleyFmERC7JeQIOuPmeydvO2VnCDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7IKs7Jqp65CY7JeI7Iq164uI64ukLmApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudGRiID0ga25leChTb25hbXUuZGJDb25maWcudGVzdCk7XG4gICAgdGhpcy5mZGIgPSBrbmV4KFNvbmFtdS5kYkNvbmZpZy5maXh0dXJlX3JlbW90ZSk7XG4gIH1cblxuICBhc3luYyBnZXRDaGVja3N1bShkYjogS25leCwgdGFibGVOYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBbW2NoZWNrc3VtUm93XV0gPSBhd2FpdCBkYi5yYXcoYENIRUNLU1VNIFRBQkxFICR7dGFibGVOYW1lfWApO1xuICAgIHJldHVybiBjaGVja3N1bVJvdy5DaGVja3N1bTtcbiAgfVxuXG4gIC8qKlxuICAgIOydtOygnCBGaXh0dXJlTWFuYWdlci5zeW5jKCkg64qUIGNoZWNrc3VtIOu5hOq1kCDsl4bsnbQgY3JlYXRlIGRhdGFiYXNlIHRlbXBsYXRlIOycvOuhnCDsiJjtlontlanri4jri6QuXG4gICovXG4gIGFzeW5jIHN5bmMoKSB7XG4gICAgY29uc3QgZml4dHVyZUNvbm4gPSBTb25hbXUuZGJDb25maWcuZml4dHVyZV9yZW1vdGUuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCB0ZXN0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWc7XG5cbiAgICAvLyBQb3N0Z3JlU1FMIO2MqOyKpOybjOuTnCDtmZjqsr3rs4DsiJgg7ISk7KCVXG4gICAgY29uc3QgcGdFbnYgPSB7IFBHUEFTU1dPUkQ6IHRlc3RDb25uLnBhc3N3b3JkIHx8IFwiXCIgfTtcblxuICAgIC8vIDEuIOyXsOqysCDqsJXsoJwg7KKF66OMXG4gICAgZXhlY1N5bmMoXG4gICAgICBgcHNxbCAtaCAke3Rlc3RDb25uLmhvc3R9IC1wICR7dGVzdENvbm4ucG9ydCA/PyA1NDMyfSAtVSAke3Rlc3RDb25uLnVzZXJ9IC1kIHBvc3RncmVzIC1jIFwiXG4gICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICBGUk9NIHBnX3N0YXRfYWN0aXZpdHlcbiAgICAgIFdIRVJFIGRhdG5hbWUgPSAnJHt0ZXN0Q29ubi5kYXRhYmFzZX0nXG4gICAgICAgIEFORCBwaWQgPD4gcGdfYmFja2VuZF9waWQoKTtcbiAgICBcImAsXG4gICAgICB7IHN0ZGlvOiBcImluaGVyaXRcIiwgZW52OiB7IC4uLnByb2Nlc3MuZW52LCAuLi5wZ0VudiB9IGFzIE5vZGVKUy5Qcm9jZXNzRW52IH0sXG4gICAgKTtcblxuICAgIGV4ZWNTeW5jKFxuICAgICAgYHBzcWwgLWggJHtmaXh0dXJlQ29ubi5ob3N0fSAtcCAke2ZpeHR1cmVDb25uLnBvcnQgPz8gNTQzMn0gLVUgJHtmaXh0dXJlQ29ubi51c2VyfSAtZCBwb3N0Z3JlcyAtYyBcIlxuICAgICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICAgIEZST00gcGdfc3RhdF9hY3Rpdml0eVxuICAgICAgICBXSEVSRSBkYXRuYW1lID0gJyR7Zml4dHVyZUNvbm4uZGF0YWJhc2V9J1xuICAgICAgICAgIEFORCBwaWQgPD4gcGdfYmFja2VuZF9waWQoKTtcbiAgICAgIFwiYCxcbiAgICAgIHsgc3RkaW86IFwiaW5oZXJpdFwiLCBlbnY6IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLnBnRW52IH0gYXMgTm9kZUpTLlByb2Nlc3NFbnYgfSxcbiAgICApO1xuXG4gICAgLy8gMi4gRFJPUCBEQVRBQkFTRSAo67OE64+EIOyLpO2WiSEpXG4gICAgZXhlY1N5bmMoXG4gICAgICBgcHNxbCAtaCAke3Rlc3RDb25uLmhvc3R9IC1wICR7dGVzdENvbm4ucG9ydCA/PyA1NDMyfSAtVSAke3Rlc3RDb25uLnVzZXJ9IC1kIHBvc3RncmVzIC1jIFwiRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgXFxcXFwiJHt0ZXN0Q29ubi5kYXRhYmFzZX1cXFxcXCJcImAsXG4gICAgICB7IHN0ZGlvOiBcImluaGVyaXRcIiwgZW52OiB7IC4uLnByb2Nlc3MuZW52LCAuLi5wZ0VudiB9IGFzIE5vZGVKUy5Qcm9jZXNzRW52IH0sXG4gICAgKTtcblxuICAgIC8vIDMuIENSRUFURSBEQVRBQkFTRVxuICAgIGV4ZWNTeW5jKFxuICAgICAgYHBzcWwgLWggJHt0ZXN0Q29ubi5ob3N0fSAtcCAke3Rlc3RDb25uLnBvcnQgPz8gNTQzMn0gLVUgJHt0ZXN0Q29ubi51c2VyfSAtZCBwb3N0Z3JlcyAtYyBcIkNSRUFURSBEQVRBQkFTRSBcXFxcXCIke3Rlc3RDb25uLmRhdGFiYXNlfVxcXFxcIiBURU1QTEFURSBcXFxcXCIke2ZpeHR1cmVDb25uLmRhdGFiYXNlfVxcXFxcIlwiYCxcbiAgICAgIHsgc3RkaW86IFwiaW5oZXJpdFwiLCBlbnY6IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLnBnRW52IH0gYXMgTm9kZUpTLlByb2Nlc3NFbnYgfSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSB2aXNpdGVkUmVjb3JkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBhc3luYyBpbXBvcnRGaXh0dXJlKGVudGl0eUlkOiBzdHJpbmcsIGlkczogbnVtYmVyW10pIHtcbiAgICAvLyDrsKnrrLgg6riw66GdIOy0iOq4sO2ZlCAo7IOI66Gc7Jq0IGltcG9ydCDsnpHsl4Ug7Iuc7J6RKVxuICAgIHRoaXMudmlzaXRlZFJlY29yZHMuY2xlYXIoKTtcblxuICAgIGNvbnN0IHF1ZXJpZXMgPSB1bmlxdWUoXG4gICAgICAoXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgIGlkcy5tYXAoYXN5bmMgKGlkKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXRJbXBvcnRRdWVyaWVzKGVudGl0eUlkLCBcImlkXCIsIGlkKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgKVxuICAgICAgKS5mbGF0KCksXG4gICAgKTtcblxuICAgIGNvbnN0IHdkYiA9IEJhc2VNb2RlbC5nZXREQihcIndcIik7XG4gICAgZm9yIChjb25zdCBxdWVyeSBvZiBxdWVyaWVzKSB7XG4gICAgICBjb25zdCBbcnNoXSA9IGF3YWl0IHdkYi5yYXcocXVlcnkpO1xuICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICBxdWVyeSxcbiAgICAgICAgaW5mbzogcnNoLmluZm8sXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBnZXRJbXBvcnRRdWVyaWVzKGVudGl0eUlkOiBzdHJpbmcsIGZpZWxkOiBzdHJpbmcsIGlkOiBudW1iZXIpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgY29uc3QgcmVjb3JkS2V5ID0gYCR7ZW50aXR5SWR9IyR7ZmllbGR9IyR7aWR9YDtcblxuICAgIC8vIOyInO2ZmCDssLjsobAg67Cp7KeAOiDsnbTrr7gg67Cp66y47ZWcIOugiOy9lOuTnOuKlCDsiqTtgrVcbiAgICBpZiAodGhpcy52aXNpdGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICB0aGlzLnZpc2l0ZWRSZWNvcmRzLmFkZChyZWNvcmRLZXkpO1xuXG4gICAgY29uc29sZS5sb2coeyBlbnRpdHlJZCwgZmllbGQsIGlkIH0pO1xuICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICBjb25zdCB3ZGIgPSBCYXNlTW9kZWwuZ2V0REIoXCJ3XCIpO1xuXG4gICAgLy8g7Jes6riw7IScIOyLpERC7J2YIHJvdyDqsIDsoLjsmLRcbiAgICBjb25zdCBbcm93XSA9IGF3YWl0IHdkYihlbnRpdHkudGFibGUpLndoZXJlKGZpZWxkLCBpZCkubGltaXQoMSk7XG4gICAgaWYgKHJvdyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZW50aXR5SWR9IyR7aWR9IHJvd+ulvCDssL7snYQg7IiYIOyXhuyKteuLiOuLpC5gKTtcbiAgICB9XG5cbiAgICAvLyDtlL3siqTss5BEQiwg7IukREJcbiAgICBjb25zdCBmaXh0dXJlRGF0YWJhc2UgPSAoU29uYW11LmRiQ29uZmlnLmZpeHR1cmVfcmVtb3RlLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnKVxuICAgICAgLmRhdGFiYXNlO1xuICAgIGNvbnN0IHJlYWxEYXRhYmFzZSA9IChTb25hbXUuZGJDb25maWcucHJvZHVjdGlvbl9tYXN0ZXIuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAuZGF0YWJhc2U7XG5cbiAgICBjb25zdCBzZWxmUXVlcnkgPSBgSU5TRVJUIElHTk9SRSBJTlRPIFxcYCR7Zml4dHVyZURhdGFiYXNlfVxcYC5cXGAke2VudGl0eS50YWJsZX1cXGAgKFNFTEVDVCAqIEZST00gXFxgJHtyZWFsRGF0YWJhc2V9XFxgLlxcYCR7ZW50aXR5LnRhYmxlfVxcYCBXSEVSRSBcXGBpZFxcYCA9ICR7aWR9KWA7XG5cbiAgICBjb25zdCBhcmdzID0gT2JqZWN0LmVudHJpZXMoZW50aXR5LnJlbGF0aW9ucylcbiAgICAgIC5maWx0ZXIoXG4gICAgICAgIChbLCByZWxhdGlvbl0pID0+XG4gICAgICAgICAgaXNCZWxvbmdzVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pIHx8XG4gICAgICAgICAgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pICYmIHJlbGF0aW9uLmN1c3RvbUpvaW5DbGF1c2UgPT09IHVuZGVmaW5lZCksXG4gICAgICApXG4gICAgICAubWFwKChbLCByZWxhdGlvbl0pID0+IHtcbiAgICAgICAgLypcbiAgICAgICAgQmVsb25nc1RvT25l7J24IOqyveyasFxuICAgICAgICAgIENhdGVnb3J5IC8gJ2lkJyAvIHJvd1tjYXRlZ29yeV9pZF0g7Zi47LacXG4gICAgICAgIE9uZVRvT25l7JeQIGpvaW5Db2x1bW4gPT09IHRydWUg7J24IOqyveyasFxuICAgICAgICAgIFByb2ZpbGUgLyAnaWQnIC8gcm93W3Byb2ZpbGVfaWRdIO2YuOy2nFxuICAgICAgICBPbmVUb09uZeyXkCBqb2luQ29sdW1uID09PSBmYWxzZSDsnbgg6rK97JqwXG4gICAgICAgICAgUHJvZmlsZSAvICdwcm9maWxlX2lkJyAvIHJvd1snaWQnXSDtmLjstpxcbiAgICAgICAgKi9cbiAgICAgICAgbGV0IGZpZWxkOiBzdHJpbmc7XG4gICAgICAgIGxldCBpZDogbnVtYmVyO1xuICAgICAgICBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChyZWxhdGlvbikgJiYgIXJlbGF0aW9uLmhhc0pvaW5Db2x1bW4pIHtcbiAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocmVsYXRpb24ud2l0aCk7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZElkQ29sdW1uTmFtZSA9IHJlbGF0ZWRFbnRpdHkucHJvcHMuZmluZChcbiAgICAgICAgICAgIChwKSA9PiBpc1JlbGF0aW9uUHJvcChwKSAmJiBwLndpdGggPT09IGVudGl0eS5pZCxcbiAgICAgICAgICApPy5uYW1lO1xuICAgICAgICAgIGlmICghcmVsYXRlZElkQ29sdW1uTmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3JlbGF0ZWRFbnRpdHkuaWR97J2YICR7ZW50aXR5LmlkfSDqtIDqs4Qg7ZSE66Gt7J2EIOywvuydhCDsiJgg7JeG7Iq164uI64ukLmApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmaWVsZCA9IGAke3JlbGF0ZWRJZENvbHVtbk5hbWV9X2lkYDtcbiAgICAgICAgICBpZCA9IHJvdy5pZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmaWVsZCA9IFwiaWRcIjtcbiAgICAgICAgICBpZCA9IHJvd1tgJHtyZWxhdGlvbi5uYW1lfV9pZGBdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZW50aXR5SWQ6IHJlbGF0aW9uLndpdGgsXG4gICAgICAgICAgZmllbGQsXG4gICAgICAgICAgaWQsXG4gICAgICAgIH07XG4gICAgICB9KVxuICAgICAgLmZpbHRlcigoYXJnKSA9PiBhcmcuaWQgIT09IG51bGwpO1xuXG4gICAgY29uc3QgcmVsUXVlcmllcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgYXJncy5tYXAoYXN5bmMgKGFyZ3MpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SW1wb3J0UXVlcmllcyhhcmdzLmVudGl0eUlkLCBhcmdzLmZpZWxkLCBhcmdzLmlkKTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICByZXR1cm4gWy4uLnVuaXF1ZShyZWxRdWVyaWVzLnJldmVyc2UoKS5mbGF0KCkpLCBzZWxmUXVlcnldO1xuICB9XG5cbiAgYXN5bmMgZGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5fdGRiKSB7XG4gICAgICBhd2FpdCB0aGlzLl90ZGIuZGVzdHJveSgpO1xuICAgICAgdGhpcy5fdGRiID0gbnVsbDtcbiAgICB9XG4gICAgaWYgKHRoaXMuX2ZkYikge1xuICAgICAgYXdhaXQgdGhpcy5fZmRiLmRlc3Ryb3koKTtcbiAgICAgIHRoaXMuX2ZkYiA9IG51bGw7XG4gICAgfVxuICAgIGF3YWl0IEJhc2VNb2RlbC5kZXN0cm95KCk7XG4gIH1cblxuICBhc3luYyBnZXRGaXh0dXJlcyhcbiAgICBzb3VyY2VEQk5hbWU6IGtleW9mIFNvbmFtdURCQ29uZmlnLFxuICAgIHRhcmdldERCTmFtZToga2V5b2YgU29uYW11REJDb25maWcsXG4gICAgc2VhcmNoT3B0aW9uczogRml4dHVyZVNlYXJjaE9wdGlvbnMsXG4gICAgZHVwbGljYXRlQ2hlY2s/OiBEdXBsaWNhdGVDaGVja09wdGlvbnMsXG4gICkge1xuICAgIGNvbnN0IHNvdXJjZURCID0ga25leChTb25hbXUuZGJDb25maWdbc291cmNlREJOYW1lXSk7XG4gICAgY29uc3QgdGFyZ2V0REIgPSBrbmV4KFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXREQk5hbWVdKTtcblxuICAgIGNvbnN0IHsgZW50aXR5SWQsIGZpZWxkLCB2YWx1ZSwgc2VhcmNoVHlwZSB9ID0gc2VhcmNoT3B0aW9ucztcblxuICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICBjb25zdCBjb2x1bW4gPVxuICAgICAgZW50aXR5LnByb3BzLmZpbmQoKHByb3ApID0+IHByb3AubmFtZSA9PT0gZmllbGQpPy50eXBlID09PSBcInJlbGF0aW9uXCIgPyBgJHtmaWVsZH1faWRgIDogZmllbGQ7XG5cbiAgICBsZXQgcXVlcnkgPSBzb3VyY2VEQihlbnRpdHkudGFibGUpO1xuICAgIGlmIChzZWFyY2hUeXBlID09PSBcImVxdWFsc1wiKSB7XG4gICAgICBxdWVyeSA9IHF1ZXJ5LndoZXJlKGNvbHVtbiwgdmFsdWUpO1xuICAgIH0gZWxzZSBpZiAoc2VhcmNoVHlwZSA9PT0gXCJsaWtlXCIpIHtcbiAgICAgIHF1ZXJ5ID0gcXVlcnkud2hlcmUoY29sdW1uLCBcImxpa2VcIiwgYCUke3ZhbHVlfSVgKTtcbiAgICB9XG5cbiAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnk7XG4gICAgaWYgKHJvd3MubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyByZWNvcmRzIGZvdW5kXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGZpeHR1cmVzOiBGaXh0dXJlUmVjb3JkW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKSB7XG4gICAgICBjb25zdCBpbml0aWFsUmVjb3Jkc0xlbmd0aCA9IGZpeHR1cmVzLmxlbmd0aDtcbiAgICAgIGNvbnN0IG5ld1JlY29yZHMgPSBhd2FpdCB0aGlzLmNyZWF0ZUZpeHR1cmVSZWNvcmQoZW50aXR5LCByb3csIHtcbiAgICAgICAgX2RiOiBzb3VyY2VEQixcbiAgICAgIH0pO1xuICAgICAgZml4dHVyZXMucHVzaCguLi5uZXdSZWNvcmRzKTtcbiAgICAgIGNvbnN0IGN1cnJlbnRGaXh0dXJlUmVjb3JkID0gZml4dHVyZXMuZmluZCgocikgPT4gci5maXh0dXJlSWQgPT09IGAke2VudGl0eUlkfSMke3Jvdy5pZH1gKTtcblxuICAgICAgaWYgKGN1cnJlbnRGaXh0dXJlUmVjb3JkKSB7XG4gICAgICAgIC8vIO2YhOyerCBmaXh0dXJl66Gc67aA7YSwIOyDneyEseuQnCBmZXRjaGVkUmVjb3JkcyDshKTsoJVcbiAgICAgICAgY3VycmVudEZpeHR1cmVSZWNvcmQuZmV0Y2hlZFJlY29yZHMgPSBmaXh0dXJlc1xuICAgICAgICAgIC5maWx0ZXIoKHIpID0+IHIuZml4dHVyZUlkICE9PSBjdXJyZW50Rml4dHVyZVJlY29yZC5maXh0dXJlSWQpXG4gICAgICAgICAgLnNsaWNlKGluaXRpYWxSZWNvcmRzTGVuZ3RoKVxuICAgICAgICAgIC5tYXAoKHIpID0+IHIuZml4dHVyZUlkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgYXdhaXQgKGNvbnN0IGZpeHR1cmUgb2YgZml4dHVyZXMpIHtcbiAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuXG4gICAgICAvLyDsgqzsmqnsnpAg7KeA7KCVIOy7rOufvCDquLDspIAg7KSR67O1IO2ZleyduCDihpIgdGFyZ2V0XG4gICAgICBjb25zdCBjdXN0b21Db2x1bW5zID0gZHVwbGljYXRlQ2hlY2s/LmNvbHVtbnM/LltmaXh0dXJlLmVudGl0eUlkXTtcbiAgICAgIGlmIChjdXN0b21Db2x1bW5zICYmIGN1c3RvbUNvbHVtbnMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBjdXN0b21EdXBsaWNhdGVSb3cgPSBhd2FpdCB0aGlzLmNoZWNrRHVwbGljYXRlQnlDb2x1bW5zKFxuICAgICAgICAgIHRhcmdldERCLFxuICAgICAgICAgIGVudGl0eSxcbiAgICAgICAgICBmaXh0dXJlLFxuICAgICAgICAgIGN1c3RvbUNvbHVtbnMsXG4gICAgICAgICk7XG4gICAgICAgIGlmIChjdXN0b21EdXBsaWNhdGVSb3cpIHtcbiAgICAgICAgICBjb25zdCBbcmVjb3JkXSA9IGF3YWl0IHRoaXMuY3JlYXRlRml4dHVyZVJlY29yZChlbnRpdHksIGN1c3RvbUR1cGxpY2F0ZVJvdywge1xuICAgICAgICAgICAgc2luZ2xlUmVjb3JkOiB0cnVlLFxuICAgICAgICAgICAgX2RiOiB0YXJnZXREQixcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBmaXh0dXJlLnRhcmdldCA9IHJlY29yZDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBVbmlxdWUgaW5kZXgg6riw7KSAIOykkeuztSDtmZXsnbgg4oaSIGZpeHR1cmUudW5pcXVlXG4gICAgICBjb25zdCB1bmlxdWVSb3cgPSBhd2FpdCB0aGlzLmNoZWNrVW5pcXVlVmlvbGF0aW9uKHRhcmdldERCLCBlbnRpdHksIGZpeHR1cmUpO1xuICAgICAgaWYgKHVuaXF1ZVJvdykge1xuICAgICAgICBjb25zdCBbcmVjb3JkXSA9IGF3YWl0IHRoaXMuY3JlYXRlRml4dHVyZVJlY29yZChlbnRpdHksIHVuaXF1ZVJvdywge1xuICAgICAgICAgIHNpbmdsZVJlY29yZDogdHJ1ZSxcbiAgICAgICAgICBfZGI6IHRhcmdldERCLFxuICAgICAgICB9KTtcbiAgICAgICAgZml4dHVyZS51bmlxdWUgPSByZWNvcmQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgdGFyZ2V0REIuZGVzdHJveSgpO1xuICAgIGF3YWl0IHNvdXJjZURCLmRlc3Ryb3koKTtcblxuICAgIHJldHVybiB1bmlxdWUoZml4dHVyZXMsIChmKSA9PiBmLmZpeHR1cmVJZCk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgIGVudGl0eTogRW50aXR5LFxuICAgIHJvdzoge1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsO1xuICAgIH0sXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHNpbmdsZVJlY29yZD86IGJvb2xlYW47XG4gICAgICBfZGI/OiBLbmV4O1xuICAgIH0sXG4gICk6IFByb21pc2U8Rml4dHVyZVJlY29yZFtdPiB7XG4gICAgY29uc3QgcmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gW107XG4gICAgY29uc3QgdmlzaXRlZEVudGl0aWVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICBjb25zdCBjcmVhdGUgPSBhc3luYyAoXG4gICAgICBlbnRpdHk6IEVudGl0eSxcbiAgICAgIHJvdzoge1xuICAgICAgICBpZDogbnVtYmVyO1xuICAgICAgICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbDtcbiAgICAgIH0sXG4gICAgKSA9PiB7XG4gICAgICBjb25zdCBmaXh0dXJlSWQgPSBgJHtlbnRpdHkuaWR9IyR7cm93LmlkfWA7XG4gICAgICBpZiAodmlzaXRlZEVudGl0aWVzLmhhcyhmaXh0dXJlSWQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHZpc2l0ZWRFbnRpdGllcy5hZGQoZml4dHVyZUlkKTtcblxuICAgICAgY29uc3QgcmVjb3JkOiBGaXh0dXJlUmVjb3JkID0ge1xuICAgICAgICBmaXh0dXJlSWQsXG4gICAgICAgIGVudGl0eUlkOiBlbnRpdHkuaWQsXG4gICAgICAgIGlkOiByb3cuaWQsXG4gICAgICAgIGNvbHVtbnM6IHt9LFxuICAgICAgICBmZXRjaGVkUmVjb3JkczogW10sXG4gICAgICAgIGJlbG9uZ3NSZWNvcmRzOiBbXSxcbiAgICAgIH07XG5cbiAgICAgIGZvciAoY29uc3QgcHJvcCBvZiBlbnRpdHkucHJvcHMpIHtcbiAgICAgICAgaWYgKGlzVmlydHVhbFByb3AocHJvcCkpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0gPSB7XG4gICAgICAgICAgcHJvcDogcHJvcCxcbiAgICAgICAgICB2YWx1ZTogcm93W3Byb3AubmFtZV0sXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZGIgPSBvcHRpb25zPy5fZGIgPz8gQmFzZU1vZGVsLmdldERCKFwid1wiKTtcbiAgICAgICAgaWYgKGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuICAgICAgICAgIGNvbnN0IHRocm91Z2hUYWJsZSA9IHByb3Auam9pblRhYmxlO1xuICAgICAgICAgIGNvbnN0IGZyb21Db2x1bW4gPSBgJHtpbmZsZWN0aW9uLnNpbmd1bGFyaXplKGVudGl0eS50YWJsZSl9X2lkYDtcbiAgICAgICAgICBjb25zdCB0b0NvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUocmVsYXRlZEVudGl0eS50YWJsZSl9X2lkYDtcblxuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBhd2FpdCBkYih0aHJvdWdoVGFibGUpLndoZXJlKGZyb21Db2x1bW4sIHJvdy5pZCkucGx1Y2sodG9Db2x1bW4pO1xuICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkSWRzO1xuICAgICAgICB9IGVsc2UgaWYgKGlzSGFzTWFueVJlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKVxuICAgICAgICAgICAgLndoZXJlKHByb3Auam9pbkNvbHVtbiwgcm93LmlkKVxuICAgICAgICAgICAgLnBsdWNrKFwiaWRcIik7XG4gICAgICAgICAgcmVjb3JkLmNvbHVtbnNbcHJvcC5uYW1lXS52YWx1ZSA9IHJlbGF0ZWRJZHM7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChwcm9wKSAmJiAhcHJvcC5oYXNKb2luQ29sdW1uKSB7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZEVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZFByb3AgPSByZWxhdGVkRW50aXR5LnByb3BzLmZpbmQoXG4gICAgICAgICAgICAocCkgPT4gaXNSZWxhdGlvblByb3AocCkgJiYgcC53aXRoID09PSBlbnRpdHkuaWQsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAocmVsYXRlZFByb3ApIHtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRSb3cgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKS53aGVyZShcImlkXCIsIHJvdy5pZCkuZmlyc3QoKTtcbiAgICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkUm93Py5pZDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoaXNSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgICBjb25zdCByZWxhdGVkSWQgPSByb3dbYCR7cHJvcC5uYW1lfV9pZGBdO1xuICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkSWQ7XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZCkge1xuICAgICAgICAgICAgcmVjb3JkLmJlbG9uZ3NSZWNvcmRzLnB1c2goYCR7cHJvcC53aXRofSMke3JlbGF0ZWRJZH1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFvcHRpb25zPy5zaW5nbGVSZWNvcmQgJiYgcmVsYXRlZElkKSB7XG4gICAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocHJvcC53aXRoKTtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRSb3cgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKS53aGVyZShcImlkXCIsIHJlbGF0ZWRJZCkuZmlyc3QoKTtcbiAgICAgICAgICAgIGlmIChyZWxhdGVkUm93KSB7XG4gICAgICAgICAgICAgIGF3YWl0IGNyZWF0ZShyZWxhdGVkRW50aXR5LCByZWxhdGVkUm93KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVjb3Jkcy5wdXNoKHJlY29yZCk7XG4gICAgfTtcblxuICAgIGF3YWl0IGNyZWF0ZShlbnRpdHksIHJvdyk7XG5cbiAgICByZXR1cm4gcmVjb3JkcztcbiAgfVxuXG4gIC8qKlxuICAgKiAxLiBSZWxhdGlvbkdyYXBo66GcIGZpeHR1cmUg64uo7JyEIOyCveyehSDsiJzshJwg6rOE7IKwIChzZWxmLXJlZmVyZW5jZSDtj6ztlagpXG4gICAqIDIuIOyInOyEnOuMgOuhnCBVcHNlcnRCdWlsZGVy7JeQIOuTseuhnSAoVUJSZWbroZwg7LC47KGwIOq0gOqzhCDtkZztmIQpXG4gICAqIDMuIO2FjOydtOu4lOuzhCB1cHNlcnQg7Iuk7ZaJIChJROuKlCBEQuqwgCDsnpDrj5kg7ZWg64u5KVxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0Rml4dHVyZXMoXG4gICAgZGJOYW1lOiBrZXlvZiBTb25hbXVEQkNvbmZpZyxcbiAgICBfZml4dHVyZXM6IEZpeHR1cmVSZWNvcmRbXSxcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICBjb25zdCBmaXh0dXJlcyA9IHVuaXF1ZShfZml4dHVyZXMsIChmKSA9PiBmLmZpeHR1cmVJZCk7XG5cbiAgICAvLyDstIjquLDtmZRcbiAgICB0aGlzLmJ1aWxkZXIgPSBuZXcgVXBzZXJ0QnVpbGRlcigpO1xuICAgIHRoaXMuZml4dHVyZVJlZk1hcCA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLnV1aWRUb0ZpeHR1cmVJZCA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLnNraXBwZWRGaXh0dXJlcyA9IG5ldyBNYXAoKTtcblxuICAgIGNvbnN0IGRiID0ga25leChTb25hbXUuZGJDb25maWdbZGJOYW1lXSk7XG4gICAgY29uc3QgcmVzdWx0czogRml4dHVyZUltcG9ydFJlc3VsdFtdID0gW107XG5cbiAgICB0cnkge1xuICAgICAgLy8gMS4gUmVsYXRpb25HcmFwaOuhnCBmaXh0dXJlIOuLqOychCDsgr3snoUg7Iic7IScIOqzhOyCsFxuICAgICAgdGhpcy5yZWxhdGlvbkdyYXBoLmJ1aWxkR3JhcGgoZml4dHVyZXMpO1xuICAgICAgY29uc3QgaW5zZXJ0aW9uT3JkZXIgPSB0aGlzLnJlbGF0aW9uR3JhcGguZ2V0SW5zZXJ0aW9uT3JkZXIoKTtcblxuICAgICAgLy8gMi4g7Iic7ISc64yA66GcIFVwc2VydEJ1aWxkZXLsl5Ag65Ox66GdIChvdmVycmlkZSDssrTtgawpXG4gICAgICBmb3IgKGNvbnN0IGZpeHR1cmVJZCBvZiBpbnNlcnRpb25PcmRlcikge1xuICAgICAgICBjb25zdCBmaXh0dXJlID0gZml4dHVyZXMuZmluZCgoZikgPT4gZi5maXh0dXJlSWQgPT09IGZpeHR1cmVJZCk7XG4gICAgICAgIGlmICghZml4dHVyZSkgY29udGludWU7XG5cbiAgICAgICAgY29uc3QgaGFzVGFyZ2V0ID0gISFmaXh0dXJlLnRhcmdldDtcbiAgICAgICAgY29uc3QgaGFzVW5pcXVlID0gISFmaXh0dXJlLnVuaXF1ZTtcbiAgICAgICAgY29uc3QgaGFzRHVwbGljYXRlID0gaGFzVGFyZ2V0IHx8IGhhc1VuaXF1ZTtcblxuICAgICAgICAvLyDspJHrs7XsnbQg7J6I6rOgIG92ZXJyaWRlPWZhbHNl7J24IOqyveyasDog7Iqk7YK1XG4gICAgICAgIGlmIChoYXNEdXBsaWNhdGUgJiYgIWZpeHR1cmUub3ZlcnJpZGUpIHtcbiAgICAgICAgICAvLyDquLDsobQg66CI7L2U65OcIElEIOyggOyepSAodW5pcXVlIOyasOyEoCwg7JeG7Jy866m0IHRhcmdldClcbiAgICAgICAgICBjb25zdCBleGlzdGluZ0lkID0gZml4dHVyZS51bmlxdWU/LmlkID8/IGZpeHR1cmUudGFyZ2V0Py5pZDtcbiAgICAgICAgICBhc3NlcnQoZXhpc3RpbmdJZCk7XG4gICAgICAgICAgdGhpcy5za2lwcGVkRml4dHVyZXMuc2V0KGZpeHR1cmVJZCwge1xuICAgICAgICAgICAgZW50aXR5SWQ6IGZpeHR1cmUuZW50aXR5SWQsXG4gICAgICAgICAgICBleGlzdGluZ0lkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgIGBTa2lwcGVkICR7Zml4dHVyZS5lbnRpdHlJZH0jJHtmaXh0dXJlLmlkfSAoZXhpc3Rpbmc6ICMke2V4aXN0aW5nSWR9LCBvdmVycmlkZTogZmFsc2UpYCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVnaXN0ZXJGaXh0dXJlKGZpeHR1cmUpO1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5ibHVlKFxuICAgICAgICAgICAgYFJlZ2lzdGVyZWQgJHtmaXh0dXJlLmVudGl0eUlkfSMke2ZpeHR1cmUuaWR9JHtmaXh0dXJlLm92ZXJyaWRlID8gYCAob3ZlcnJpZGUgZXhpc3Rpbmc6ICMke2ZpeHR1cmUudGFyZ2V0Py5pZH0pYCA6IFwiXCJ9YCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyAzLiDthYzsnbTruJTrs4QgdXBzZXJ0IOyLpO2WiVxuICAgICAgY29uc3QgdGFibGVPcmRlciA9IHRoaXMuZ2V0VGFibGVPcmRlcihmaXh0dXJlcyk7XG5cbiAgICAgIGF3YWl0IGRiLnRyYW5zYWN0aW9uKGFzeW5jICh0cngpID0+IHtcbiAgICAgICAgY29uc3QgaW5zZXJ0ZWRJZHNCeVRhYmxlID0gbmV3IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIG51bWJlcj4+KCk7XG5cbiAgICAgICAgZm9yIChjb25zdCB0YWJsZU5hbWUgb2YgdGFibGVPcmRlcikge1xuICAgICAgICAgIGlmICghdGhpcy5idWlsZGVyLmhhc1RhYmxlKHRhYmxlTmFtZSkpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgLy8gdXBzZXJ0IOyLpO2WiSDsoIQgdXVpZCDrqqnroZ0g7KCA7J6lXG4gICAgICAgICAgY29uc3QgdGFibGUgPSB0aGlzLmJ1aWxkZXIuZ2V0VGFibGUodGFibGVOYW1lKTtcbiAgICAgICAgICBjb25zdCB1dWlkcyA9IHRhYmxlLnJvd3MubWFwKChyb3cpID0+IHJvdy51dWlkIGFzIHN0cmluZyk7XG5cbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ibHVlKGBVcHNlcnRpbmcgJHt0YWJsZU5hbWV9IHdpdGggJHt1dWlkcy5sZW5ndGh9IHJvd3NgKSk7XG4gICAgICAgICAgYXdhaXQgdGhpcy5idWlsZGVyLnVwc2VydCh0cngsIHRhYmxlTmFtZSk7XG5cbiAgICAgICAgICAvLyB1cHNlcnTrkJwgcm9365Ok7J2YIHV1aWQgLT4gaWQg66ek7ZWRIOq1rOy2lVxuICAgICAgICAgIGlmICh1dWlkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCB1dWlkVG9JZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgICAgICAgICBjb25zdCByb3dzID0gYXdhaXQgdHJ4KHRhYmxlTmFtZSkuc2VsZWN0KFwidXVpZFwiLCBcImlkXCIpLndoZXJlSW4oXCJ1dWlkXCIsIHV1aWRzKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygcm93cykge1xuICAgICAgICAgICAgICB1dWlkVG9JZC5zZXQocm93LnV1aWQsIHJvdy5pZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGluc2VydGVkSWRzQnlUYWJsZS5zZXQodGFibGVOYW1lLCB1dWlkVG9JZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gNC4gTWFueVRvTWFueSDqtIDqs4Qg7LKY66asXG4gICAgICAgIGF3YWl0IHRoaXMucHJvY2Vzc01hbnlUb01hbnlSZWxhdGlvbnModHJ4LCBmaXh0dXJlcywgaW5zZXJ0ZWRJZHNCeVRhYmxlKTtcblxuICAgICAgICAvLyA1LiDqsrDqs7wg7IiY7KeRXG4gICAgICAgIGZvciAoY29uc3QgZml4dHVyZSBvZiBmaXh0dXJlcykge1xuICAgICAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuXG4gICAgICAgICAgLy8g7Iqk7YK165CcIGZpeHR1cmXripQg6riw7KG0IOugiOy9lOuTnCDsoJXrs7TroZwg6rKw6rO8IOy2lOqwgFxuICAgICAgICAgIGNvbnN0IHNraXBwZWQgPSB0aGlzLnNraXBwZWRGaXh0dXJlcy5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuICAgICAgICAgIGlmIChza2lwcGVkKSB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgICAgICBlbnRpdHlJZDogZml4dHVyZS5lbnRpdHlJZCxcbiAgICAgICAgICAgICAgZGF0YTogYXdhaXQgdHJ4KGVudGl0eS50YWJsZSkud2hlcmUoXCJpZFwiLCBza2lwcGVkLmV4aXN0aW5nSWQpLmZpcnN0KCksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHJlZiA9IHRoaXMuZml4dHVyZVJlZk1hcC5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuICAgICAgICAgIGlmIChyZWYpIHtcbiAgICAgICAgICAgIGNvbnN0IHV1aWRUb0lkID0gaW5zZXJ0ZWRJZHNCeVRhYmxlLmdldChlbnRpdHkudGFibGUpO1xuICAgICAgICAgICAgY29uc3QgaW5zZXJ0ZWRJZCA9IHV1aWRUb0lkPy5nZXQocmVmLnV1aWQpO1xuXG4gICAgICAgICAgICBpZiAoaW5zZXJ0ZWRJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgZW50aXR5SWQ6IGZpeHR1cmUuZW50aXR5SWQsXG4gICAgICAgICAgICAgICAgZGF0YTogYXdhaXQgdHJ4KGVudGl0eS50YWJsZSkud2hlcmUoXCJpZFwiLCBpbnNlcnRlZElkKS5maXJzdCgpLFxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICBjaGFsay5ncmVlbihgSW5zZXJ0ZWQgaW50byAke2VudGl0eS50YWJsZX06ICMke2ZpeHR1cmUuaWR9IC0+ICMke2luc2VydGVkSWR9YCksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgZGIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHJldHVybiB1bmlxdWUocmVzdWx0cywgKHIpID0+IGAke3IuZW50aXR5SWR9IyR7ci5kYXRhLmlkfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpeHR1cmVSZWNvcmTrpbwgVXBzZXJ0QnVpbGRlcuyXkCDrk7HroZ1cbiAgICovXG4gIHByaXZhdGUgcmVnaXN0ZXJGaXh0dXJlKGZpeHR1cmU6IEZpeHR1cmVSZWNvcmQpOiBVQlJlZiB7XG4gICAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZml4dHVyZS5lbnRpdHlJZCk7XG4gICAgY29uc3Qgcm93OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gICAgLy8gT3ZlcnJpZGUg66qo65OcIO2MkOuLqDogdGFyZ2V0IOuYkOuKlCB1bmlxdWXqsIAg7J6I6rOgIG92ZXJyaWRlPXRydWXsnbgg6rK97JqwXG4gICAgY29uc3QgZXhpc3RpbmdSZWNvcmQgPSBmaXh0dXJlLnRhcmdldCA/PyBmaXh0dXJlLnVuaXF1ZTtcbiAgICBjb25zdCBpc092ZXJyaWRlTW9kZSA9IGZpeHR1cmUub3ZlcnJpZGUgJiYgZXhpc3RpbmdSZWNvcmQ7XG5cbiAgICBmb3IgKGNvbnN0IFtwcm9wTmFtZSwgY29sdW1uXSBvZiBPYmplY3QuZW50cmllcyhmaXh0dXJlLmNvbHVtbnMpKSB7XG4gICAgICBjb25zdCBwcm9wID0gY29sdW1uLnByb3A7XG5cbiAgICAgIGlmIChpc1ZpcnR1YWxQcm9wKHByb3ApKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBpZC91dWlkIOyymOumrDogT3ZlcnJpZGUg66qo65Oc7J28IOuVjOunjCDquLDsobQg6rCSIOyCrOyaqVxuICAgICAgaWYgKHByb3BOYW1lID09PSBcImlkXCIgfHwgcHJvcE5hbWUgPT09IFwidXVpZFwiKSB7XG4gICAgICAgIGlmIChpc092ZXJyaWRlTW9kZSAmJiBleGlzdGluZ1JlY29yZCkge1xuICAgICAgICAgIC8vIE92ZXJyaWRlOiDquLDsobQg66CI7L2U65Oc7J2YIOqwkiDsgqzsmqkg4oaSIFVQREFURVxuICAgICAgICAgIHJvd1twcm9wTmFtZV0gPSBleGlzdGluZ1JlY29yZC5jb2x1bW5zW3Byb3BOYW1lXT8udmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8g7IOIIOugiOy9lOuTnDog7KCc7Jm4IOKGkiBJTlNFUlQgKERCL1Vwc2VydEJ1aWxkZXLqsIAg7IOd7ISxKVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSB8fFxuICAgICAgICAgIChpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbilcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZElkID0gY29sdW1uLnZhbHVlIGFzIG51bWJlciB8IG51bGw7XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZCAhPT0gbnVsbCAmJiByZWxhdGVkSWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgY29uc3QgcmVsYXRlZEZpeHR1cmVJZCA9IGAke3Byb3Aud2l0aH0jJHtyZWxhdGVkSWR9YDtcblxuICAgICAgICAgICAgLy8g66i87KCAIHNraXDrkJwgZml4dHVyZeyduOyngCDtmZXsnbhcbiAgICAgICAgICAgIGNvbnN0IHNraXBwZWRFeGlzdGluZ0lkID0gdGhpcy5za2lwcGVkRml4dHVyZXMuZ2V0KHJlbGF0ZWRGaXh0dXJlSWQpPy5leGlzdGluZ0lkO1xuICAgICAgICAgICAgaWYgKHNraXBwZWRFeGlzdGluZ0lkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgLy8gc2tpcOuQnCBmaXh0dXJlIOKGkiB0YXJnZXQgRELsnZgg6riw7KG0IOugiOy9lOuTnCBpZCDsgqzsmqlcbiAgICAgICAgICAgICAgcm93W2Ake3Byb3BOYW1lfV9pZGBdID0gc2tpcHBlZEV4aXN0aW5nSWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBjb25zdCByZWxhdGVkUmVmID0gdGhpcy5maXh0dXJlUmVmTWFwLmdldChyZWxhdGVkRml4dHVyZUlkKTtcbiAgICAgICAgICAgICAgaWYgKHJlbGF0ZWRSZWYpIHtcbiAgICAgICAgICAgICAgICAvLyDsnbTrr7gg65Ox66Gd65CcIGZpeHR1cmUg7LC47KGwIOKGkiBVQlJlZiDsgqzsmqlcbiAgICAgICAgICAgICAgICByb3dbYCR7cHJvcE5hbWV9X2lkYF0gPSByZWxhdGVkUmVmO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIGZpeHR1cmVz7JeQIO2PrO2VqOuQmOyngCDslYrsnYAg66CI7L2U65OcIOKGkiBJRCDqt7jrjIDroZwg7IKs7JqpXG4gICAgICAgICAgICAgICAgcm93W2Ake3Byb3BOYW1lfV9pZGBdID0gcmVsYXRlZElkO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJvd1tgJHtwcm9wTmFtZX1faWRgXSA9IG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEhhc01hbnksIE1hbnlUb01hbnnripQg67OE64+EIOyymOumrFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8g7J2867CYIOy7rOufvFxuICAgICAgICByb3dbcHJvcE5hbWVdID0gdGhpcy5jb252ZXJ0Q29sdW1uVmFsdWUocHJvcCBhcyBFbnRpdHlQcm9wLCBjb2x1bW4udmFsdWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGNoYWxrLmJsdWUoYFJlZ2lzdGVyaW5nICR7ZW50aXR5LnRhYmxlfSAtICR7aW5zcGVjdChyb3csIGZhbHNlLCBudWxsLCB0cnVlKX1gKSk7XG4gICAgY29uc3QgcmVmID0gdGhpcy5idWlsZGVyLnJlZ2lzdGVyKGVudGl0eS50YWJsZSwgcm93KTtcbiAgICB0aGlzLmZpeHR1cmVSZWZNYXAuc2V0KGZpeHR1cmUuZml4dHVyZUlkLCByZWYpO1xuICAgIHRoaXMudXVpZFRvRml4dHVyZUlkLnNldChyZWYudXVpZCwgZml4dHVyZS5maXh0dXJlSWQpO1xuXG4gICAgcmV0dXJuIHJlZjtcbiAgfVxuXG4gIC8qKlxuICAgKiDsu6zrn7wg6rCSIOuzgO2ZmFxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0Q29sdW1uVmFsdWUocHJvcDogRW50aXR5UHJvcCwgdmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgc3dpdGNoIChwcm9wLnR5cGUpIHtcbiAgICAgIGNhc2UgXCJqc29uXCI6XG4gICAgICAgIC8vIFVwc2VydEJ1aWxkZXIucmVnaXN0ZXLsl5DshJwgSlNPTi5zdHJpbmdpZnkg7LKY66as7ZWY66+A66GcIG9iamVjdCDqt7jrjIDroZwg7KCE64usXG4gICAgICAgIHJldHVybiB2YWx1ZTtcblxuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICByZXR1cm4gbmV3IERhdGUodmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB2YWx1ZTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDthYzsnbTruJQg7Iic7IScIOy2lOy2nCAoZml4dHVyZXPsl5Ag7Y+s7ZWo65CcIO2FjOydtOu4lOunjClcbiAgICovXG4gIHByaXZhdGUgZ2V0VGFibGVPcmRlcihmaXh0dXJlczogRml4dHVyZVJlY29yZFtdKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHRhYmxlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICBmb3IgKGNvbnN0IGZpeHR1cmUgb2YgZml4dHVyZXMpIHtcbiAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuICAgICAgaWYgKCFzZWVuLmhhcyhlbnRpdHkudGFibGUpKSB7XG4gICAgICAgIHNlZW4uYWRkKGVudGl0eS50YWJsZSk7XG4gICAgICAgIHRhYmxlcy5wdXNoKGVudGl0eS50YWJsZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhYmxlcztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc01hbnlUb01hbnlSZWxhdGlvbnMoXG4gICAgdHJ4OiBLbmV4LlRyYW5zYWN0aW9uLFxuICAgIGZpeHR1cmVzOiBGaXh0dXJlUmVjb3JkW10sXG4gICAgaW5zZXJ0ZWRJZHNCeVRhYmxlOiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBudW1iZXI+PixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBmaXh0dXJlIG9mIGZpeHR1cmVzKSB7XG4gICAgICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChmaXh0dXJlLmVudGl0eUlkKTtcbiAgICAgIGNvbnN0IHNvdXJjZVJlZiA9IHRoaXMuZml4dHVyZVJlZk1hcC5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuXG4gICAgICBpZiAoIXNvdXJjZVJlZikgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHNvdXJjZVV1aWRUb0lkID0gaW5zZXJ0ZWRJZHNCeVRhYmxlLmdldChlbnRpdHkudGFibGUpO1xuICAgICAgY29uc3Qgc291cmNlSWQgPSBzb3VyY2VVdWlkVG9JZD8uZ2V0KHNvdXJjZVJlZi51dWlkKTtcblxuICAgICAgaWYgKHNvdXJjZUlkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuXG4gICAgICBmb3IgKGNvbnN0IFssIGNvbHVtbl0gb2YgT2JqZWN0LmVudHJpZXMoZml4dHVyZS5jb2x1bW5zKSkge1xuICAgICAgICBjb25zdCBwcm9wID0gY29sdW1uLnByb3A7XG5cbiAgICAgICAgaWYgKGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChwcm9wKSAmJiBBcnJheS5pc0FycmF5KGNvbHVtbi52YWx1ZSkpIHtcbiAgICAgICAgICAvLyDshKDtg53rkJjsp4Ag7JWK7J2AIE1hbnlUb01hbnkg6rSA6rOE64qUIOyggOyepe2VmOyngCDslYrsnYxcbiAgICAgICAgICBjb25zdCB0YXJnZXRUYWJsZSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgICAgaWYgKHRoaXMuYnVpbGRlci5oYXNUYWJsZSh0YXJnZXRUYWJsZS50YWJsZSkgPT09IGZhbHNlKSBjb250aW51ZTtcblxuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBjb2x1bW4udmFsdWUgYXMgbnVtYmVyW107XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZHMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcblxuICAgICAgICAgIGNvbnN0IGpvaW5UYWJsZSA9IChwcm9wIGFzIE1hbnlUb01hbnlSZWxhdGlvblByb3ApLmpvaW5UYWJsZTtcbiAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocHJvcC53aXRoKTtcblxuICAgICAgICAgIGNvbnN0IHNvdXJjZUNvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUoZW50aXR5LnRhYmxlKX1faWRgO1xuICAgICAgICAgIGNvbnN0IHRhcmdldENvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUocmVsYXRlZEVudGl0eS50YWJsZSl9X2lkYDtcblxuICAgICAgICAgIGZvciAoY29uc3QgcmVsYXRlZElkIG9mIHJlbGF0ZWRJZHMpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRGaXh0dXJlSWQgPSBgJHtwcm9wLndpdGh9IyR7cmVsYXRlZElkfWA7XG4gICAgICAgICAgICBjb25zdCByZWxhdGVkUmVmID0gdGhpcy5maXh0dXJlUmVmTWFwLmdldChyZWxhdGVkRml4dHVyZUlkKTtcblxuICAgICAgICAgICAgbGV0IHRhcmdldElkOiBudW1iZXI7XG5cbiAgICAgICAgICAgIGlmIChyZWxhdGVkUmVmKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRVdWlkVG9JZCA9IGluc2VydGVkSWRzQnlUYWJsZS5nZXQocmVsYXRlZEVudGl0eS50YWJsZSk7XG4gICAgICAgICAgICAgIGNvbnN0IHJlc29sdmVkSWQgPSByZWxhdGVkVXVpZFRvSWQ/LmdldChyZWxhdGVkUmVmLnV1aWQpO1xuXG4gICAgICAgICAgICAgIGlmIChyZXNvbHZlZElkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgICAgICBgUmVsYXRlZCBmaXh0dXJlICR7cmVsYXRlZEZpeHR1cmVJZH0gbm90IGZvdW5kIGluIGluc2VydGVkSWRzLCBza2lwcGluZ2AsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0YXJnZXRJZCA9IHJlc29sdmVkSWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0YXJnZXRJZCA9IHJlbGF0ZWRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSm9pblRhYmxl7JeQIOyCveyehVxuICAgICAgICAgICAgY29uc3QgW2ZvdW5kXSA9IGF3YWl0IHRyeChqb2luVGFibGUpXG4gICAgICAgICAgICAgIC53aGVyZSh7XG4gICAgICAgICAgICAgICAgW3NvdXJjZUNvbHVtbl06IHNvdXJjZUlkLFxuICAgICAgICAgICAgICAgIFt0YXJnZXRDb2x1bW5dOiB0YXJnZXRJZCxcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgLmxpbWl0KDEpO1xuXG4gICAgICAgICAgICBpZiAoIWZvdW5kKSB7XG4gICAgICAgICAgICAgIGF3YWl0IHRyeChqb2luVGFibGUpLmluc2VydCh7XG4gICAgICAgICAgICAgICAgW3NvdXJjZUNvbHVtbl06IHNvdXJjZUlkLFxuICAgICAgICAgICAgICAgIFt0YXJnZXRDb2x1bW5dOiB0YXJnZXRJZCxcbiAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgY2hhbGsuZ3JlZW4oXG4gICAgICAgICAgICAgICAgICBgSW5zZXJ0ZWQgaW50byAke2pvaW5UYWJsZX06ICR7ZW50aXR5LnRhYmxlfSgke3NvdXJjZUlkfSkgLSAke3JlbGF0ZWRFbnRpdHkudGFibGV9KCR7dGFyZ2V0SWR9KWAsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNoZWNrVW5pcXVlVmlvbGF0aW9uKGRiOiBLbmV4LCBlbnRpdHk6IEVudGl0eSwgZml4dHVyZTogRml4dHVyZVJlY29yZCkge1xuICAgIGNvbnN0IF91bmlxdWVJbmRleGVzID0gZW50aXR5LmluZGV4ZXM/LmZpbHRlcigoaSkgPT4gaS50eXBlID09PSBcInVuaXF1ZVwiKSA/PyBbXTtcblxuICAgIGNvbnN0IHVuaXF1ZUluZGV4ZXMgPSBfdW5pcXVlSW5kZXhlcy5maWx0ZXIoKGluZGV4KSA9PlxuICAgICAgaW5kZXguY29sdW1ucy5ldmVyeSgoY29sdW1uKSA9PiAhY29sdW1uLnN0YXJ0c1dpdGgoYCR7ZW50aXR5LnRhYmxlfV9fYCkpLFxuICAgICk7XG4gICAgaWYgKHVuaXF1ZUluZGV4ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsZXQgdW5pcXVlUXVlcnkgPSBkYihlbnRpdHkudGFibGUpO1xuICAgIGxldCBoYXNDb25kaXRpb24gPSBmYWxzZTtcblxuICAgIGZvciAoY29uc3QgaW5kZXggb2YgdW5pcXVlSW5kZXhlcykge1xuICAgICAgLy8g7Lus65+8IOykkSDtlZjrgpjrnbzrj4QgbnVsbOydtOuptCDsnKDri4jtgawg7KCc7JW97J2EIOychOuwmO2VmOyngCDslYrquLAg65WM66y47JeQIO2VtOuLuSDsnbjrjbHsiqTripQg66y07IucXG4gICAgICBjb25zdCBjb250YWluc051bGwgPSBpbmRleC5jb2x1bW5zLnNvbWUoKGNvbHVtbikgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZCA9IGNvbHVtbi5yZXBsYWNlKC9faWQkLywgXCJcIik7XG4gICAgICAgIHJldHVybiBmaXh0dXJlLmNvbHVtbnNbZmllbGRdPy52YWx1ZSA9PT0gbnVsbDtcbiAgICAgIH0pO1xuICAgICAgaWYgKGNvbnRhaW5zTnVsbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdW5pcXVlUXVlcnkgPSB1bmlxdWVRdWVyeS5vcldoZXJlKChxYikgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbHVtbiBvZiBpbmRleC5jb2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgZmllbGQgPSBjb2x1bW4ucmVwbGFjZSgvX2lkJC8sIFwiXCIpO1xuXG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZml4dHVyZS5jb2x1bW5zW2ZpZWxkXT8udmFsdWUpKSB7XG4gICAgICAgICAgICBxYi53aGVyZUluKGNvbHVtbiwgZml4dHVyZS5jb2x1bW5zW2ZpZWxkXS52YWx1ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHFiLmFuZFdoZXJlKGNvbHVtbiwgZml4dHVyZS5jb2x1bW5zW2ZpZWxkXT8udmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBoYXNDb25kaXRpb24gPSB0cnVlO1xuICAgIH1cblxuICAgIGlmICghaGFzQ29uZGl0aW9uKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBbdW5pcXVlRm91bmRdID0gYXdhaXQgdW5pcXVlUXVlcnk7XG4gICAgcmV0dXJuIHVuaXF1ZUZvdW5kO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjaGVja0R1cGxpY2F0ZUJ5Q29sdW1ucyhcbiAgICBkYjogS25leCxcbiAgICBlbnRpdHk6IEVudGl0eSxcbiAgICBmaXh0dXJlOiBGaXh0dXJlUmVjb3JkLFxuICAgIGNvbHVtbnM6IHN0cmluZ1tdLFxuICApIHtcbiAgICBpZiAoY29sdW1ucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHdoZXJlQ2xhdXNlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBjb2x1bW4gb2YgY29sdW1ucykge1xuICAgICAgLy8gcmVsYXRpb24g7ZWE65Oc7J24IOqyveyasCBfaWQg67aZ7J206riwXG4gICAgICBjb25zdCBwcm9wID0gZW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gY29sdW1uKTtcbiAgICAgIGNvbnN0IGRiQ29sdW1uID0gcHJvcCAmJiBpc1JlbGF0aW9uUHJvcChwcm9wKSA/IGAke2NvbHVtbn1faWRgIDogY29sdW1uO1xuICAgICAgY29uc3QgdmFsdWUgPSBmaXh0dXJlLmNvbHVtbnNbY29sdW1uXT8udmFsdWU7XG5cbiAgICAgIC8vIG51bGwg6rCS7J20IO2PrO2VqOuQnCDqsr3smrAg7KSR67O1IO2ZleyduCDsiqTtgrVcbiAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICB3aGVyZUNsYXVzZVtkYkNvbHVtbl0gPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBjb25zdCBbZm91bmRdID0gYXdhaXQgZGIoZW50aXR5LnRhYmxlKS53aGVyZSh3aGVyZUNsYXVzZSkubGltaXQoMSk7XG4gICAgcmV0dXJuIGZvdW5kO1xuICB9XG5cbiAgYXN5bmMgYWRkRml4dHVyZUxvYWRlcihjb2RlOiBzdHJpbmcpIHtcbiAgICBjb25zdCBwYXRoID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvdGVzdGluZy9maXh0dXJlLnRzYDtcbiAgICBjb25zdCBjb250ZW50ID0gcmVhZEZpbGVTeW5jKHBhdGgpLnRvU3RyaW5nKCk7XG5cbiAgICBjb25zdCBmaXh0dXJlTG9hZGVyU3RhcnQgPSBjb250ZW50LmluZGV4T2YoXCJjb25zdCBmaXh0dXJlTG9hZGVyID0ge1wiKTtcbiAgICBjb25zdCBmaXh0dXJlTG9hZGVyRW5kID0gY29udGVudC5pbmRleE9mKFwifTtcIiwgZml4dHVyZUxvYWRlclN0YXJ0KTtcblxuICAgIGlmIChmaXh0dXJlTG9hZGVyU3RhcnQgIT09IC0xICYmIGZpeHR1cmVMb2FkZXJFbmQgIT09IC0xKSB7XG4gICAgICBjb25zdCBuZXdDb250ZW50ID0gYCR7Y29udGVudC5zbGljZSgwLCBmaXh0dXJlTG9hZGVyRW5kKX0gICR7Y29kZX1cXG4ke2NvbnRlbnQuc2xpY2UoZml4dHVyZUxvYWRlckVuZCl9YDtcblxuICAgICAgd3JpdGVGaWxlU3luYyhwYXRoLCBuZXdDb250ZW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIGZpbmQgZml4dHVyZUxvYWRlciBpbiBmaXh0dXJlLnRzXCIpO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgRml4dHVyZU1hbmFnZXIgPSBuZXcgRml4dHVyZU1hbmFnZXJDbGFzcygpO1xuIl0sIm5hbWVzIjpbImFzc2VydCIsImNoYWxrIiwiZXhlY1N5bmMiLCJyZWFkRmlsZVN5bmMiLCJ3cml0ZUZpbGVTeW5jIiwiaW5mbGVjdGlvbiIsImtuZXgiLCJ1bmlxdWUiLCJpbnNwZWN0IiwiU29uYW11IiwiQmFzZU1vZGVsIiwiVXBzZXJ0QnVpbGRlciIsIkVudGl0eU1hbmFnZXIiLCJpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcCIsImlzSGFzTWFueVJlbGF0aW9uUHJvcCIsImlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCIsImlzT25lVG9PbmVSZWxhdGlvblByb3AiLCJpc1JlbGF0aW9uUHJvcCIsImlzVmlydHVhbFByb3AiLCJSZWxhdGlvbkdyYXBoIiwiRml4dHVyZU1hbmFnZXJDbGFzcyIsIl90ZGIiLCJ0ZGIiLCJFcnJvciIsIl9mZGIiLCJmZGIiLCJjYWNoZWRUYWJsZU5hbWVzIiwicmVsYXRpb25HcmFwaCIsImJ1aWxkZXIiLCJmaXh0dXJlUmVmTWFwIiwiTWFwIiwidXVpZFRvRml4dHVyZUlkIiwic2tpcHBlZEZpeHR1cmVzIiwiaW5pdCIsImRiQ29uZmlnIiwidGVzdCIsInByb2R1Y3Rpb25fbWFzdGVyIiwidENvbm4iLCJjb25uZWN0aW9uIiwicENvbm4iLCJob3N0IiwicG9ydCIsImRhdGFiYXNlIiwiZml4dHVyZV9yZW1vdGUiLCJnZXRDaGVja3N1bSIsImRiIiwidGFibGVOYW1lIiwiY2hlY2tzdW1Sb3ciLCJyYXciLCJDaGVja3N1bSIsInN5bmMiLCJmaXh0dXJlQ29ubiIsInRlc3RDb25uIiwicGdFbnYiLCJQR1BBU1NXT1JEIiwicGFzc3dvcmQiLCJ1c2VyIiwic3RkaW8iLCJlbnYiLCJwcm9jZXNzIiwidmlzaXRlZFJlY29yZHMiLCJTZXQiLCJpbXBvcnRGaXh0dXJlIiwiZW50aXR5SWQiLCJpZHMiLCJjbGVhciIsInF1ZXJpZXMiLCJQcm9taXNlIiwiYWxsIiwibWFwIiwiaWQiLCJnZXRJbXBvcnRRdWVyaWVzIiwiZmxhdCIsIndkYiIsImdldERCIiwicXVlcnkiLCJyc2giLCJjb25zb2xlIiwibG9nIiwiaW5mbyIsImZpZWxkIiwicmVjb3JkS2V5IiwiaGFzIiwiYWRkIiwiZW50aXR5IiwiZ2V0Iiwicm93IiwidGFibGUiLCJ3aGVyZSIsImxpbWl0IiwidW5kZWZpbmVkIiwiZml4dHVyZURhdGFiYXNlIiwicmVhbERhdGFiYXNlIiwic2VsZlF1ZXJ5IiwiYXJncyIsIk9iamVjdCIsImVudHJpZXMiLCJyZWxhdGlvbnMiLCJmaWx0ZXIiLCJyZWxhdGlvbiIsImN1c3RvbUpvaW5DbGF1c2UiLCJoYXNKb2luQ29sdW1uIiwicmVsYXRlZEVudGl0eSIsIndpdGgiLCJyZWxhdGVkSWRDb2x1bW5OYW1lIiwicHJvcHMiLCJmaW5kIiwicCIsIm5hbWUiLCJhcmciLCJyZWxRdWVyaWVzIiwicmV2ZXJzZSIsImRlc3Ryb3kiLCJnZXRGaXh0dXJlcyIsInNvdXJjZURCTmFtZSIsInRhcmdldERCTmFtZSIsInNlYXJjaE9wdGlvbnMiLCJkdXBsaWNhdGVDaGVjayIsInNvdXJjZURCIiwidGFyZ2V0REIiLCJ2YWx1ZSIsInNlYXJjaFR5cGUiLCJjb2x1bW4iLCJwcm9wIiwidHlwZSIsInJvd3MiLCJsZW5ndGgiLCJmaXh0dXJlcyIsImluaXRpYWxSZWNvcmRzTGVuZ3RoIiwibmV3UmVjb3JkcyIsImNyZWF0ZUZpeHR1cmVSZWNvcmQiLCJfZGIiLCJwdXNoIiwiY3VycmVudEZpeHR1cmVSZWNvcmQiLCJyIiwiZml4dHVyZUlkIiwiZmV0Y2hlZFJlY29yZHMiLCJzbGljZSIsImZpeHR1cmUiLCJjdXN0b21Db2x1bW5zIiwiY29sdW1ucyIsImN1c3RvbUR1cGxpY2F0ZVJvdyIsImNoZWNrRHVwbGljYXRlQnlDb2x1bW5zIiwicmVjb3JkIiwic2luZ2xlUmVjb3JkIiwidGFyZ2V0IiwidW5pcXVlUm93IiwiY2hlY2tVbmlxdWVWaW9sYXRpb24iLCJmIiwib3B0aW9ucyIsInJlY29yZHMiLCJ2aXNpdGVkRW50aXRpZXMiLCJjcmVhdGUiLCJiZWxvbmdzUmVjb3JkcyIsInRocm91Z2hUYWJsZSIsImpvaW5UYWJsZSIsImZyb21Db2x1bW4iLCJzaW5ndWxhcml6ZSIsInRvQ29sdW1uIiwicmVsYXRlZElkcyIsInBsdWNrIiwiam9pbkNvbHVtbiIsInJlbGF0ZWRQcm9wIiwicmVsYXRlZFJvdyIsImZpcnN0IiwicmVsYXRlZElkIiwiaW5zZXJ0Rml4dHVyZXMiLCJkYk5hbWUiLCJfZml4dHVyZXMiLCJyZXN1bHRzIiwiYnVpbGRHcmFwaCIsImluc2VydGlvbk9yZGVyIiwiZ2V0SW5zZXJ0aW9uT3JkZXIiLCJoYXNUYXJnZXQiLCJoYXNVbmlxdWUiLCJoYXNEdXBsaWNhdGUiLCJvdmVycmlkZSIsImV4aXN0aW5nSWQiLCJzZXQiLCJ5ZWxsb3ciLCJyZWdpc3RlckZpeHR1cmUiLCJibHVlIiwidGFibGVPcmRlciIsImdldFRhYmxlT3JkZXIiLCJ0cmFuc2FjdGlvbiIsInRyeCIsImluc2VydGVkSWRzQnlUYWJsZSIsImhhc1RhYmxlIiwiZ2V0VGFibGUiLCJ1dWlkcyIsInV1aWQiLCJ1cHNlcnQiLCJ1dWlkVG9JZCIsInNlbGVjdCIsIndoZXJlSW4iLCJwcm9jZXNzTWFueVRvTWFueVJlbGF0aW9ucyIsInNraXBwZWQiLCJkYXRhIiwicmVmIiwiaW5zZXJ0ZWRJZCIsImdyZWVuIiwiZXhpc3RpbmdSZWNvcmQiLCJpc092ZXJyaWRlTW9kZSIsInByb3BOYW1lIiwicmVsYXRlZEZpeHR1cmVJZCIsInNraXBwZWRFeGlzdGluZ0lkIiwicmVsYXRlZFJlZiIsImNvbnZlcnRDb2x1bW5WYWx1ZSIsInJlZ2lzdGVyIiwiRGF0ZSIsInRhYmxlcyIsInNlZW4iLCJzb3VyY2VSZWYiLCJzb3VyY2VVdWlkVG9JZCIsInNvdXJjZUlkIiwiQXJyYXkiLCJpc0FycmF5IiwidGFyZ2V0VGFibGUiLCJzb3VyY2VDb2x1bW4iLCJ0YXJnZXRDb2x1bW4iLCJ0YXJnZXRJZCIsInJlbGF0ZWRVdWlkVG9JZCIsInJlc29sdmVkSWQiLCJ3YXJuIiwiZm91bmQiLCJpbnNlcnQiLCJfdW5pcXVlSW5kZXhlcyIsImluZGV4ZXMiLCJpIiwidW5pcXVlSW5kZXhlcyIsImluZGV4IiwiZXZlcnkiLCJzdGFydHNXaXRoIiwidW5pcXVlUXVlcnkiLCJoYXNDb25kaXRpb24iLCJjb250YWluc051bGwiLCJzb21lIiwicmVwbGFjZSIsIm9yV2hlcmUiLCJxYiIsImFuZFdoZXJlIiwidW5pcXVlRm91bmQiLCJ3aGVyZUNsYXVzZSIsImRiQ29sdW1uIiwiYWRkRml4dHVyZUxvYWRlciIsImNvZGUiLCJwYXRoIiwiYXBpUm9vdFBhdGgiLCJjb250ZW50IiwidG9TdHJpbmciLCJmaXh0dXJlTG9hZGVyU3RhcnQiLCJpbmRleE9mIiwiZml4dHVyZUxvYWRlckVuZCIsIm5ld0NvbnRlbnQiLCJGaXh0dXJlTWFuYWdlciJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsWUFBWSxTQUFTO0FBQzVCLE9BQU9DLFdBQVcsUUFBUTtBQUMxQixTQUFTQyxRQUFRLFFBQVEsZ0JBQWdCO0FBQ3pDLFNBQVNDLFlBQVksRUFBRUMsYUFBYSxRQUFRLEtBQUs7QUFDakQsT0FBT0MsZ0JBQWdCLGFBQWE7QUFDcEMsT0FBT0MsVUFBeUIsT0FBTztBQUN2QyxTQUFTQyxNQUFNLFFBQVEsVUFBVTtBQUNqQyxTQUFTQyxPQUFPLFFBQVEsT0FBTztBQUMvQixTQUFTQyxNQUFNLFFBQVEsa0JBQVM7QUFDaEMsU0FBU0MsU0FBUyxRQUFRLDRCQUF5QjtBQUVuRCxTQUFxQkMsYUFBYSxRQUFR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
|