sonamu 0.8.26 → 0.9.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/bin/cli.js +60 -13
- package/dist/_virtual/rolldown_runtime.js +39 -0
- package/dist/ai/agents/agent.d.ts +3 -3
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +76 -73
- package/dist/ai/agents/index.js +3 -3
- package/dist/ai/agents/types.d.ts +3 -3
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/agents/types.js +1 -3
- package/dist/ai/index.js +3 -2
- package/dist/ai/providers/rtzr/api.js +25 -25
- package/dist/ai/providers/rtzr/error.js +25 -26
- package/dist/ai/providers/rtzr/index.js +5 -5
- package/dist/ai/providers/rtzr/model.d.ts +1 -1
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.js +117 -133
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/options.js +35 -41
- package/dist/ai/providers/rtzr/provider.d.ts +1 -1
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/provider.js +53 -51
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.js +84 -84
- 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 +29 -19
- package/dist/api/caster.d.ts +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +51 -61
- package/dist/api/code-converters.d.ts +4 -3
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +226 -249
- package/dist/api/config.d.ts +17 -17
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +37 -30
- package/dist/api/context.d.ts +10 -10
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +8 -2
- package/dist/api/decorators.d.ts +8 -8
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +245 -268
- package/dist/api/index.js +39 -7
- package/dist/api/secret.js +22 -15
- package/dist/api/sonamu.d.ts +15 -15
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +1012 -1131
- package/dist/api/validator.js +88 -79
- package/dist/auth/auth-generator.d.ts.map +1 -1
- package/dist/auth/auth-generator.js +203 -200
- package/dist/auth/better-auth-entities.d.ts +2 -2
- package/dist/auth/better-auth-entities.d.ts.map +1 -1
- package/dist/auth/better-auth-entities.js +369 -429
- package/dist/auth/index.js +21 -6
- package/dist/auth/knex-adapter.d.ts +2 -2
- package/dist/auth/knex-adapter.d.ts.map +1 -1
- package/dist/auth/knex-adapter.js +153 -157
- package/dist/auth/plugins/entity-definitions/admin.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/admin.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/admin.js +58 -56
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/anonymous.js +20 -20
- package/dist/auth/plugins/entity-definitions/api-key.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/api-key.js +185 -196
- package/dist/auth/plugins/entity-definitions/index.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +26 -29
- package/dist/auth/plugins/entity-definitions/jwt.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/jwt.js +62 -64
- package/dist/auth/plugins/entity-definitions/organization.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/organization.js +362 -421
- package/dist/auth/plugins/entity-definitions/passkey.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/passkey.js +115 -126
- package/dist/auth/plugins/entity-definitions/phone-number.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/phone-number.js +31 -40
- package/dist/auth/plugins/entity-definitions/sso.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/sso.js +94 -107
- package/dist/auth/plugins/entity-definitions/two-factor.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/two-factor.js +78 -92
- package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/types.js +1 -10
- package/dist/auth/plugins/entity-definitions/username.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/username.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/username.js +31 -40
- package/dist/auth/plugins/index.js +12 -3
- package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
- package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/admin.js +28 -29
- package/dist/auth/plugins/wrappers/anonymous.d.ts +2 -1
- package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/anonymous.js +23 -22
- package/dist/auth/plugins/wrappers/api-key.d.ts +2 -1
- package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/api-key.js +39 -34
- package/dist/auth/plugins/wrappers/index.js +11 -11
- package/dist/auth/plugins/wrappers/jwt.d.ts +2 -1
- package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/jwt.js +31 -26
- package/dist/auth/plugins/wrappers/organization.d.ts +2 -1
- package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/organization.js +65 -62
- package/dist/auth/plugins/wrappers/passkey.d.ts +2 -1
- package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/passkey.js +33 -28
- package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/phone-number.js +26 -23
- package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/sso.js +37 -31
- package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/two-factor.js +31 -28
- package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/username.js +23 -23
- package/dist/bin/build-config.js +31 -31
- package/dist/bin/cli.js +1063 -1204
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +266 -259
- package/dist/bin/hmr-hook-register.d.ts.map +1 -1
- package/dist/bin/hmr-hook-register.js +19 -18
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +180 -177
- package/dist/bin/ts-loader-register.js +13 -6
- package/dist/bin/ts-loader-registration.d.ts.map +1 -1
- package/dist/bin/ts-loader-registration.js +28 -38
- package/dist/cache/cache-manager.d.ts +1 -1
- package/dist/cache/cache-manager.d.ts.map +1 -1
- package/dist/cache/cache-manager.js +20 -15
- package/dist/cache/decorator.d.ts +1 -1
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +84 -76
- package/dist/cache/drivers.js +21 -34
- package/dist/cache/index.js +10 -7
- package/dist/cache/types.d.ts +2 -2
- package/dist/cache/types.d.ts.map +1 -1
- package/dist/cache/types.js +1 -6
- package/dist/cache-control/cache-control.d.ts +2 -2
- package/dist/cache-control/cache-control.d.ts.map +1 -1
- package/dist/cache-control/cache-control.js +106 -122
- package/dist/cache-control/types.d.ts +2 -2
- package/dist/cache-control/types.d.ts.map +1 -1
- package/dist/cache-control/types.js +1 -19
- package/dist/compress/compress.d.ts +1 -1
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/compress/compress.js +58 -56
- package/dist/compress/index.js +7 -2
- package/dist/compress/types.js +1 -11
- package/dist/cone/cone-generator.d.ts +1 -1
- package/dist/cone/cone-generator.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +216 -219
- package/dist/database/_batch_update.d.ts +1 -1
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +107 -102
- package/dist/database/base-model.d.ts +8 -9
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +371 -392
- package/dist/database/base-model.types.d.ts +5 -5
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/base-model.types.js +1 -20
- package/dist/database/db.d.ts +5 -2
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +185 -171
- package/dist/database/knex.d.ts +1 -1
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +48 -42
- package/dist/database/puri-subset.types.d.ts +6 -7
- package/dist/database/puri-subset.types.d.ts.map +1 -1
- package/dist/database/puri-subset.types.js +1 -16
- package/dist/database/puri-wrapper.d.ts +6 -6
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +99 -101
- package/dist/database/puri.d.ts +4 -5
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +1021 -1227
- package/dist/database/puri.types.d.ts +6 -6
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +15 -6
- package/dist/database/transaction-context.d.ts +2 -2
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +22 -13
- package/dist/database/upsert-builder.d.ts +3 -3
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +405 -465
- package/dist/dict/en.js +72 -74
- package/dist/dict/index.js +13 -13
- package/dist/dict/ko.js +72 -74
- package/dist/dict/rc-keys.js +150 -168
- package/dist/dict/sd.d.ts +3 -1
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +54 -40
- package/dist/dict/sonamu-dictionary.d.ts +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +887 -955
- package/dist/dict/types.js +1 -7
- package/dist/dict/utils.js +26 -24
- package/dist/entity/entity-manager.d.ts +9 -9
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +226 -223
- package/dist/entity/entity-template-cone.d.ts +1 -1
- package/dist/entity/entity-template-cone.d.ts.map +1 -1
- package/dist/entity/entity-template-cone.js +152 -151
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +952 -1089
- 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 +32 -27
- 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 +61 -68
- package/dist/filter/index.js +9 -3
- package/dist/filter/types.js +92 -88
- package/dist/filter/utils.d.ts +1 -1
- package/dist/filter/utils.d.ts.map +1 -1
- package/dist/filter/utils.js +147 -161
- package/dist/index.js +87 -40
- package/dist/logger/category.d.ts.map +1 -1
- package/dist/logger/category.js +30 -29
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +83 -107
- package/dist/migration/code-generation.d.ts +2 -2
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +1385 -1578
- package/dist/migration/migration-set.d.ts +1 -1
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +177 -227
- package/dist/migration/migrator.d.ts +4 -3
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +340 -345
- package/dist/migration/postgresql-schema-reader.d.ts +2 -2
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/postgresql-schema-reader.js +506 -564
- package/dist/migration/slack-confirm.d.ts +2 -2
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/migration/slack-confirm.js +205 -193
- package/dist/migration/types.d.ts +2 -2
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/migration/types.js +1 -3
- package/dist/naite/messaging-types.d.ts +1 -0
- package/dist/naite/messaging-types.d.ts.map +1 -1
- package/dist/naite/messaging-types.js +1 -7
- package/dist/naite/naite-reporter.d.ts +2 -2
- package/dist/naite/naite-reporter.d.ts.map +1 -1
- package/dist/naite/naite-reporter.js +127 -120
- package/dist/naite/naite.d.ts +3 -2
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +266 -300
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +13 -3
- package/dist/ssr/registry.d.ts +1 -1
- package/dist/ssr/registry.d.ts.map +1 -1
- package/dist/ssr/registry.js +45 -37
- package/dist/ssr/renderer.d.ts +4 -4
- package/dist/ssr/renderer.d.ts.map +1 -1
- package/dist/ssr/renderer.js +84 -91
- package/dist/ssr/types.d.ts +2 -2
- package/dist/ssr/types.d.ts.map +1 -1
- package/dist/ssr/types.js +1 -3
- package/dist/storage/base-file.js +54 -41
- package/dist/storage/buffered-file.d.ts +2 -2
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.js +51 -44
- package/dist/storage/drivers.d.ts +2 -2
- package/dist/storage/drivers.d.ts.map +1 -1
- package/dist/storage/drivers.js +12 -7
- package/dist/storage/index.js +14 -7
- package/dist/storage/s3-driver.d.ts +2 -2
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/s3-driver.js +52 -48
- package/dist/storage/storage-manager.d.ts +2 -2
- package/dist/storage/storage-manager.d.ts.map +1 -1
- package/dist/storage/storage-manager.js +33 -25
- package/dist/storage/types.d.ts +2 -2
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +1 -5
- package/dist/storage/uploaded-file.d.ts +1 -1
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/storage/uploaded-file.js +45 -35
- package/dist/stream/index.js +7 -2
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +72 -67
- package/dist/syncer/api-parser.d.ts +1 -1
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +224 -245
- package/dist/syncer/checksum.d.ts +1 -1
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +86 -72
- package/dist/syncer/code-generator.d.ts +2 -2
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +154 -160
- package/dist/syncer/entity-operations.d.ts +1 -1
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +63 -54
- package/dist/syncer/file-patterns.d.ts +1 -1
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +38 -38
- package/dist/syncer/index.js +19 -8
- package/dist/syncer/module-loader.d.ts +5 -5
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +83 -78
- package/dist/syncer/syncer-actions.d.ts +2 -2
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +76 -91
- package/dist/syncer/syncer.d.ts +7 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +426 -492
- package/dist/tasks/decorator.d.ts +3 -3
- package/dist/tasks/decorator.d.ts.map +1 -1
- package/dist/tasks/decorator.js +32 -28
- package/dist/tasks/step-wrapper.d.ts +1 -1
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.js +42 -41
- package/dist/tasks/workflow-manager.d.ts +2 -2
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +192 -221
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +103 -103
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +163 -163
- package/dist/template/implementations/entity.template.d.ts +1 -1
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.js +76 -85
- package/dist/template/implementations/entry-server.template.d.ts +1 -1
- package/dist/template/implementations/entry-server.template.d.ts.map +1 -1
- package/dist/template/implementations/entry-server.template.js +32 -27
- package/dist/template/implementations/generated.template.d.ts +1 -1
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +254 -275
- package/dist/template/implementations/generated_http.template.d.ts +2 -2
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +114 -133
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +249 -275
- package/dist/template/implementations/init_types.template.d.ts +1 -1
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.js +40 -34
- package/dist/template/implementations/model.template.d.ts +1 -1
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +56 -53
- package/dist/template/implementations/model_test.template.d.ts +1 -1
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.js +32 -24
- package/dist/template/implementations/queries.template.d.ts +1 -1
- package/dist/template/implementations/queries.template.d.ts.map +1 -1
- package/dist/template/implementations/queries.template.js +84 -89
- package/dist/template/implementations/sd.template.d.ts +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +137 -144
- package/dist/template/implementations/services.template.d.ts +1 -1
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +164 -189
- package/dist/template/implementations/view_form.template.d.ts +1 -1
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +258 -285
- package/dist/template/implementations/view_id_all_select.template.d.ts +1 -1
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.js +31 -25
- package/dist/template/implementations/view_list.template.d.ts +1 -1
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +304 -355
- package/dist/template/implementations/view_search_input.template.d.ts +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +31 -27
- package/dist/template/index.js +21 -7
- package/dist/template/template-manager.d.ts +1 -1
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template-manager.js +132 -123
- package/dist/template/template-types.js +8 -6
- package/dist/template/template.d.ts +2 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +73 -68
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +603 -657
- 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 +93 -88
- package/dist/testing/bootstrap.d.ts +22 -13
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +114 -114
- package/dist/testing/data-explorer.d.ts +3 -3
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +237 -265
- package/dist/testing/dev-test-routes.d.ts +2 -2
- package/dist/testing/dev-test-routes.d.ts.map +1 -1
- package/dist/testing/dev-test-routes.js +258 -249
- package/dist/testing/dev-vitest-manager.d.ts +1 -1
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.js +514 -539
- package/dist/testing/faker-mappings.js +422 -420
- package/dist/testing/fixture-generator.d.ts +3 -3
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +1216 -1346
- package/dist/testing/fixture-loader.js +26 -25
- package/dist/testing/fixture-manager.d.ts +3 -3
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +706 -776
- package/dist/testing/global-setup.js +53 -49
- package/dist/testing/index.js +19 -11
- package/dist/testing/naite-vitest-reporter.js +18 -13
- package/dist/testing/parallel-db-manager.d.ts +1 -1
- package/dist/testing/parallel-db-manager.d.ts.map +1 -1
- package/dist/testing/parallel-db-manager.js +63 -78
- package/dist/testing/vitest-helpers.d.ts +1 -1
- package/dist/testing/vitest-helpers.d.ts.map +1 -1
- package/dist/testing/vitest-helpers.js +37 -33
- package/dist/types/types.d.ts +28 -28
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +764 -890
- package/dist/ui/ai-api.d.ts +1 -1
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +52 -42
- package/dist/ui/ai-client.d.ts +1 -2
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +353 -388
- package/dist/ui/api.d.ts +1 -1
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +903 -1145
- package/dist/ui/cdd-service.d.ts +1 -1
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +406 -407
- package/dist/ui/cdd-types.js +1 -3
- package/dist/ui-web/assets/index-C-Zz-wYg.css +1 -0
- package/dist/ui-web/assets/index-DejDON8K.js +238 -0
- package/dist/ui-web/index.html +3 -3
- package/dist/utils/async-utils.js +57 -45
- package/dist/utils/console-util.d.ts.map +1 -1
- package/dist/utils/console-util.js +104 -87
- package/dist/utils/controller.js +26 -19
- package/dist/utils/esm-utils.js +49 -38
- package/dist/utils/formatter.d.ts +1 -2
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +89 -115
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +68 -65
- package/dist/utils/lodash-able.js +11 -4
- package/dist/utils/model.d.ts +1 -1
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +21 -19
- package/dist/utils/object-utils.js +148 -186
- package/dist/utils/path-utils.js +67 -57
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +37 -31
- package/dist/utils/sql-parser.d.ts +1 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +40 -40
- package/dist/utils/type-utils.js +44 -43
- package/dist/utils/utils.d.ts +2 -3
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +81 -93
- 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 +24 -17
- package/dist/vector/chunking.d.ts +1 -1
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/chunking.js +100 -94
- package/dist/vector/config.d.ts +1 -1
- package/dist/vector/config.d.ts.map +1 -1
- package/dist/vector/config.js +76 -78
- package/dist/vector/embedding.d.ts +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +128 -125
- package/dist/vector/index.js +5 -5
- package/dist/vector/types.js +1 -5
- package/package.json +31 -36
- package/src/ai/agents/agent.ts +12 -5
- package/src/ai/agents/types.ts +5 -5
- package/src/ai/providers/rtzr/model.ts +8 -10
- package/src/ai/providers/rtzr/options.ts +2 -1
- package/src/ai/providers/rtzr/provider.ts +5 -3
- package/src/ai/providers/rtzr/utils.ts +2 -7
- package/src/api/__tests__/config.test.ts +15 -8
- package/src/api/base-frame.ts +5 -3
- package/src/api/caster.ts +7 -6
- package/src/api/code-converters.ts +23 -26
- package/src/api/config.ts +23 -17
- package/src/api/context.ts +18 -11
- package/src/api/decorators.ts +17 -18
- package/src/api/sonamu.ts +44 -49
- package/src/auth/auth-generator.ts +4 -6
- package/src/auth/better-auth-entities.ts +3 -2
- package/src/auth/knex-adapter.ts +6 -5
- package/src/auth/plugins/entity-definitions/admin.ts +1 -1
- package/src/auth/plugins/entity-definitions/anonymous.ts +1 -1
- package/src/auth/plugins/entity-definitions/api-key.ts +1 -1
- package/src/auth/plugins/entity-definitions/index.ts +1 -1
- package/src/auth/plugins/entity-definitions/jwt.ts +1 -1
- package/src/auth/plugins/entity-definitions/organization.ts +1 -1
- package/src/auth/plugins/entity-definitions/passkey.ts +1 -1
- package/src/auth/plugins/entity-definitions/phone-number.ts +1 -1
- package/src/auth/plugins/entity-definitions/sso.ts +1 -1
- package/src/auth/plugins/entity-definitions/two-factor.ts +1 -1
- package/src/auth/plugins/entity-definitions/types.ts +1 -1
- package/src/auth/plugins/entity-definitions/username.ts +1 -1
- package/src/auth/plugins/wrappers/admin.ts +3 -1
- package/src/auth/plugins/wrappers/anonymous.ts +3 -1
- package/src/auth/plugins/wrappers/api-key.ts +3 -1
- package/src/auth/plugins/wrappers/jwt.ts +3 -1
- package/src/auth/plugins/wrappers/organization.ts +3 -1
- package/src/auth/plugins/wrappers/passkey.ts +3 -1
- package/src/auth/plugins/wrappers/phone-number.ts +3 -1
- package/src/auth/plugins/wrappers/sso.ts +2 -1
- package/src/auth/plugins/wrappers/two-factor.ts +3 -1
- package/src/auth/plugins/wrappers/username.ts +3 -1
- package/src/bin/__tests__/ts-loader-register.test.ts +7 -12
- package/src/bin/build-config.ts +3 -3
- package/src/bin/cli.ts +27 -25
- package/src/bin/fixture.ts +4 -2
- package/src/bin/hmr-hook-register.ts +1 -0
- package/src/bin/test-command.ts +4 -2
- package/src/bin/ts-loader-registration.ts +6 -22
- package/src/cache/cache-manager.ts +2 -1
- package/src/cache/decorator.ts +2 -2
- package/src/cache/types.ts +3 -3
- package/src/cache-control/cache-control.ts +3 -2
- package/src/cache-control/types.ts +2 -2
- package/src/compress/compress.ts +1 -1
- package/src/cone/cone-generator.ts +5 -3
- package/src/database/_batch_update.ts +1 -1
- package/src/database/base-model.ts +20 -14
- package/src/database/base-model.types.ts +12 -11
- package/src/database/db.ts +56 -21
- package/src/database/knex.ts +2 -2
- package/src/database/puri-subset.test-d.ts +33 -32
- package/src/database/puri-subset.types.ts +6 -7
- package/src/database/puri-wrapper.ts +29 -26
- package/src/database/puri.ts +36 -34
- package/src/database/puri.types.test-d.ts +6 -5
- package/src/database/puri.types.ts +9 -12
- package/src/database/transaction-context.ts +2 -2
- package/src/database/upsert-builder.ts +17 -10
- package/src/dict/sd.ts +17 -4
- package/src/dict/sonamu-dictionary.ts +23 -17
- package/src/entity/entity-manager.ts +9 -7
- package/src/entity/entity-template-cone.ts +10 -3
- package/src/entity/entity.ts +20 -16
- package/src/exceptions/error-handler.ts +2 -1
- package/src/exceptions/so-exceptions.ts +1 -1
- package/src/filter/utils.ts +3 -2
- package/src/logger/category.ts +1 -0
- package/src/logger/configure.ts +5 -5
- package/src/migration/__tests__/code-generation.search-text.test.ts +2 -3
- package/src/migration/code-generation.ts +26 -25
- package/src/migration/migration-set.ts +16 -18
- package/src/migration/migrator.ts +38 -33
- package/src/migration/postgresql-schema-reader.ts +12 -12
- package/src/migration/slack-confirm.ts +5 -4
- package/src/migration/types.ts +2 -2
- package/src/naite/messaging-types.ts +1 -1
- package/src/naite/naite-reporter.ts +5 -3
- package/src/naite/naite.ts +12 -7
- package/src/shared/app.shared.ts.txt +2 -2
- package/src/shared/web.shared.ts.txt +2 -2
- package/src/skills/AGENTS.md +19 -18
- package/src/skills/commands/sonamu-skills.md +9 -9
- package/src/skills/sonamu/SKILL.md +111 -104
- package/src/skills/sonamu/ai-agents.md +27 -26
- package/src/skills/sonamu/api.md +81 -69
- package/src/skills/sonamu/auth-migration.md +13 -27
- package/src/skills/sonamu/auth-plugins.md +41 -31
- package/src/skills/sonamu/auth.md +30 -24
- package/src/skills/sonamu/cdd.md +26 -17
- package/src/skills/sonamu/cone.md +50 -50
- package/src/skills/sonamu/config.md +74 -51
- package/src/skills/sonamu/create-sonamu.md +31 -19
- package/src/skills/sonamu/database.md +43 -26
- package/src/skills/sonamu/entity-basic.md +61 -61
- package/src/skills/sonamu/entity-relations.md +84 -80
- package/src/skills/sonamu/entity-validation-checklist.md +19 -15
- package/src/skills/sonamu/fixture-cli.md +52 -30
- package/src/skills/sonamu/framework-change.md +9 -7
- package/src/skills/sonamu/frontend.md +64 -82
- package/src/skills/sonamu/i18n.md +45 -37
- package/src/skills/sonamu/migration.md +54 -31
- package/src/skills/sonamu/model.md +98 -66
- package/src/skills/sonamu/naite.md +34 -32
- package/src/skills/sonamu/project-init.md +28 -8
- package/src/skills/sonamu/puri.md +82 -91
- package/src/skills/sonamu/scaffolding.md +44 -32
- package/src/skills/sonamu/skill-contribution.md +50 -45
- package/src/skills/sonamu/subset.md +13 -13
- package/src/skills/sonamu/tasks.md +73 -58
- package/src/skills/sonamu/testing-devrunner.md +56 -36
- package/src/skills/sonamu/testing.md +23 -58
- package/src/skills/sonamu/upsert.md +32 -31
- package/src/skills/sonamu/vector.md +37 -36
- package/src/ssr/index.ts +2 -12
- package/src/ssr/registry.ts +1 -1
- package/src/ssr/renderer.ts +7 -5
- package/src/ssr/types.ts +2 -2
- package/src/storage/buffered-file.ts +4 -2
- package/src/storage/drivers.ts +3 -2
- package/src/storage/s3-driver.ts +7 -4
- package/src/storage/storage-manager.ts +3 -2
- package/src/storage/types.ts +3 -2
- package/src/storage/uploaded-file.ts +1 -1
- package/src/stream/sse.ts +2 -2
- package/src/syncer/api-parser.ts +8 -5
- package/src/syncer/checksum.ts +9 -5
- package/src/syncer/code-generator.ts +16 -8
- package/src/syncer/entity-operations.ts +5 -3
- package/src/syncer/file-patterns.ts +2 -1
- package/src/syncer/module-loader.ts +9 -6
- package/src/syncer/syncer-actions.ts +5 -3
- package/src/syncer/syncer.ts +18 -24
- package/src/tasks/decorator.ts +10 -8
- package/src/tasks/step-wrapper.ts +1 -1
- package/src/tasks/workflow-manager.ts +18 -15
- package/src/template/__tests__/generated.template.search-text.test.ts +1 -0
- package/src/template/entity-converter.ts +4 -2
- package/src/template/generated.template.test-d.ts +2 -1
- package/src/template/helpers.ts +5 -2
- package/src/template/implementations/entity.template.ts +9 -8
- package/src/template/implementations/entry-server.template.ts +1 -1
- package/src/template/implementations/generated.template.ts +21 -29
- package/src/template/implementations/generated_http.template.ts +9 -6
- package/src/template/implementations/generated_sso.template.ts +6 -4
- package/src/template/implementations/init_types.template.ts +3 -2
- package/src/template/implementations/model.template.ts +4 -2
- package/src/template/implementations/model_test.template.ts +3 -2
- package/src/template/implementations/queries.template.ts +6 -14
- package/src/template/implementations/sd.template.ts +4 -2
- package/src/template/implementations/services.template.ts +7 -11
- package/src/template/implementations/view_form.template.ts +5 -3
- package/src/template/implementations/view_id_all_select.template.ts +3 -2
- package/src/template/implementations/view_list.template.ts +7 -5
- package/src/template/implementations/view_search_input.template.ts +3 -2
- package/src/template/template-manager.ts +4 -3
- package/src/template/template.ts +4 -3
- package/src/template/zod-converter.ts +10 -7
- package/src/testing/__tests__/dev-test-routes.test.ts +3 -2
- package/src/testing/__tests__/dev-vitest-manager.test.ts +1 -0
- package/src/testing/_relation-graph.ts +2 -2
- package/src/testing/bootstrap.ts +55 -27
- package/src/testing/data-explorer.ts +5 -4
- package/src/testing/dev-test-routes.ts +8 -5
- package/src/testing/dev-vitest-manager.ts +13 -12
- package/src/testing/fixture-generator.ts +11 -17
- package/src/testing/fixture-manager.ts +21 -17
- package/src/testing/parallel-db-manager.ts +2 -1
- package/src/testing/vitest-helpers.ts +2 -1
- package/src/types/__tests__/entity-json-schema-search-text.test.ts +1 -0
- package/src/types/types.ts +8 -8
- package/src/typings/knex.d.ts +4 -4
- package/src/ui/ai-api.ts +5 -3
- package/src/ui/ai-client.ts +6 -5
- package/src/ui/api.ts +25 -23
- package/src/ui/cdd-service.ts +12 -11
- package/src/utils/console-util.ts +3 -1
- package/src/utils/formatter.ts +94 -102
- package/src/utils/fs-utils.ts +2 -1
- package/src/utils/model.ts +2 -2
- package/src/utils/object-utils.ts +3 -3
- package/src/utils/process-utils.ts +2 -1
- package/src/utils/sql-parser.ts +10 -1
- package/src/utils/type-utils.ts +3 -3
- package/src/utils/utils.ts +9 -7
- package/src/utils/zod-error.ts +1 -1
- package/src/vector/chunking.ts +1 -1
- package/src/vector/config.ts +1 -1
- package/src/vector/embedding.ts +11 -9
- package/tsdown.api.config.ts +50 -0
- package/.swcrc.project-default +0 -18
- package/dist/api/__tests__/config.test.js +0 -189
- package/dist/bin/__tests__/test-command.test.js +0 -112
- package/dist/bin/__tests__/ts-loader-register.test.js +0 -45
- package/dist/database/puri-subset.test-d.js +0 -89
- package/dist/database/puri.types.test-d.js +0 -129
- package/dist/migration/__tests__/code-generation.search-text.test.js +0 -435
- package/dist/template/__tests__/generated.template.search-text.test.js +0 -99
- package/dist/template/generated.template.test-d.js +0 -24
- package/dist/testing/__tests__/dev-test-routes.test.js +0 -144
- package/dist/testing/__tests__/dev-vitest-manager.test.js +0 -152
- package/dist/types/__tests__/entity-json-schema-search-text.test.js +0 -256
- package/dist/typings/knex.d.js +0 -3
- package/dist/ui-web/assets/index-CKo0Z2Iu.css +0 -1
- package/dist/ui-web/assets/index-DK-2aacv.js +0 -257
|
@@ -1,714 +1,660 @@
|
|
|
1
|
+
import { __esmMin, __toCommonJS } from "../_virtual/rolldown_runtime.js";
|
|
2
|
+
import { init_controller, isTest } from "../utils/controller.js";
|
|
3
|
+
import { init_types, isBelongsToOneRelationProp, isOneToOneRelationProp, isRelationProp } from "../types/types.js";
|
|
4
|
+
import { api_exports, init_api } from "../api/index.js";
|
|
5
|
+
import { FixtureManager, init_fixture_manager } from "./fixture-manager.js";
|
|
6
|
+
import { DataExplorer, init_data_explorer } from "./data-explorer.js";
|
|
7
|
+
import { fakerMappings, init_faker_mappings } from "./faker-mappings.js";
|
|
1
8
|
import chalk from "chalk";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (this.llmCache.has(rowCacheKey)) {
|
|
652
|
-
return this.llmCache.get(rowCacheKey);
|
|
653
|
-
}
|
|
654
|
-
// 만약 row 응답에 이 필드가 누락된 경우 단일 필드 fallback
|
|
655
|
-
return this.generateSingleWithLLM(fixtureHint, prop, entity);
|
|
656
|
-
}
|
|
657
|
-
// rowKey가 없으면 기존 단일 필드 방식
|
|
658
|
-
return this.generateSingleWithLLM(fixtureHint, prop, entity);
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* 단일 필드를 LLM으로 생성합니다 (rowKey 없을 때 fallback용)
|
|
662
|
-
*/ async generateSingleWithLLM(fixtureHint, prop, entity) {
|
|
663
|
-
const cacheKey = `${entity.id}:${prop.name}:${fixtureHint}`;
|
|
664
|
-
if (this.options.enableLLMCache && this.llmCache.has(cacheKey)) {
|
|
665
|
-
return this.llmCache.get(cacheKey);
|
|
666
|
-
}
|
|
667
|
-
const apiKey = this.getApiKey();
|
|
668
|
-
const { createAnthropic } = await import("@ai-sdk/anthropic");
|
|
669
|
-
const { generateText } = await import("ai");
|
|
670
|
-
const singleResponse = await generateText({
|
|
671
|
-
model: createAnthropic({
|
|
672
|
-
apiKey
|
|
673
|
-
})(this.options.llmModel || "claude-sonnet-4-6"),
|
|
674
|
-
prompt: this.buildLLMPrompt(fixtureHint, prop, entity)
|
|
675
|
-
});
|
|
676
|
-
if (!singleResponse || typeof singleResponse.text !== "string") {
|
|
677
|
-
throw new Error("Invalid LLM response");
|
|
678
|
-
}
|
|
679
|
-
const value = this.parseLLMResponse(singleResponse.text, prop.type);
|
|
680
|
-
if (this.options.enableLLMCache) {
|
|
681
|
-
this.llmCache.set(cacheKey, value);
|
|
682
|
-
}
|
|
683
|
-
return value;
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* row 전체를 한 번에 생성하는 LLM 프롬프트를 만듭니다.
|
|
687
|
-
*/ buildRowLLMPrompt(props, entity) {
|
|
688
|
-
const locale = this.options.locale || "ko";
|
|
689
|
-
const language = locale === "ko" ? "Korean" : locale === "ja" ? "Japanese" : "English";
|
|
690
|
-
const fieldDescriptions = props.map((p)=>{
|
|
691
|
-
let desc = `- ${p.name} (${p.type}): ${p.cone?.note ?? ""}`;
|
|
692
|
-
if ((p.type === "enum" || p.type === "enum[]") && "id" in p && p.id && entity.enumLabels?.[p.id]) {
|
|
693
|
-
const values = Object.keys(entity.enumLabels[p.id]).join(", ");
|
|
694
|
-
desc += ` [allowed values: ${values}]`;
|
|
695
|
-
}
|
|
696
|
-
return desc;
|
|
697
|
-
}).join("\n");
|
|
698
|
-
// LLM 대상이 아닌 prop들도 맥락으로 제공 (relation 제외)
|
|
699
|
-
const otherProps = entity.props.filter((p)=>!props.includes(p) && !isRelationProp(p) && p.name !== "id" && !("virtual" in p && p.virtual)).map((p)=>{
|
|
700
|
-
let desc = `- ${p.name} (${p.type})`;
|
|
701
|
-
if (p.cone?.note) desc += `: ${p.cone.note}`;
|
|
702
|
-
if ((p.type === "enum" || p.type === "enum[]") && "id" in p && p.id && entity.enumLabels?.[p.id]) {
|
|
703
|
-
const values = Object.keys(entity.enumLabels[p.id]).join(", ");
|
|
704
|
-
desc += ` [allowed values: ${values}]`;
|
|
705
|
-
}
|
|
706
|
-
return desc;
|
|
707
|
-
}).join("\n");
|
|
708
|
-
const otherPropsContext = otherProps ? `\n\nOther fields in this entity (for context, do NOT generate these):\n${otherProps}` : "";
|
|
709
|
-
const outputShape = props.map((p)=>` "${p.name}": <${p.type}>`).join(",\n");
|
|
710
|
-
const entityContext = entity.cone?.note ? `\nEntity description: ${entity.cone.note}` : "";
|
|
711
|
-
return `Generate test fixture data for the ${entity.id} entity. All fields must be coherent and consistent with each other.
|
|
9
|
+
|
|
10
|
+
//#region src/testing/fixture-generator.ts
|
|
11
|
+
var FixtureGenerator;
|
|
12
|
+
var init_fixture_generator = __esmMin((() => {
|
|
13
|
+
init_types();
|
|
14
|
+
init_controller();
|
|
15
|
+
init_data_explorer();
|
|
16
|
+
init_faker_mappings();
|
|
17
|
+
init_fixture_manager();
|
|
18
|
+
FixtureGenerator = class {
|
|
19
|
+
dataExplorer;
|
|
20
|
+
locale;
|
|
21
|
+
mappings;
|
|
22
|
+
llmCache = new Map();
|
|
23
|
+
entityCache = new Map();
|
|
24
|
+
options;
|
|
25
|
+
constructor(sourceDb, _targetDb, targetDbName, entityManager, options) {
|
|
26
|
+
this.sourceDb = sourceDb;
|
|
27
|
+
this.targetDbName = targetDbName;
|
|
28
|
+
this.entityManager = entityManager;
|
|
29
|
+
this.dataExplorer = new DataExplorer(sourceDb, entityManager);
|
|
30
|
+
this.locale = options?.locale || "ko";
|
|
31
|
+
this.mappings = fakerMappings;
|
|
32
|
+
this.options = {
|
|
33
|
+
locale: options?.locale || "ko",
|
|
34
|
+
useLLM: options?.useLLM || false,
|
|
35
|
+
enableLLMCache: options?.enableLLMCache !== false,
|
|
36
|
+
llmModel: options?.llmModel || "claude-sonnet-4-6"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Fixture 생성 (단일)
|
|
41
|
+
* @returns 생성된 fixture 데이터 (메모리 상)
|
|
42
|
+
*/
|
|
43
|
+
async generate(entityName, overrides = {}, context = this.createContext()) {
|
|
44
|
+
let entity = this.entityCache.get(entityName);
|
|
45
|
+
if (!entity) {
|
|
46
|
+
entity = this.entityManager.get(entityName);
|
|
47
|
+
this.entityCache.set(entityName, entity);
|
|
48
|
+
}
|
|
49
|
+
const tempId = `${entityName}#temp#${Date.now()}`;
|
|
50
|
+
const rowKey = this.options.useLLM ? `${entityName}#row#${Date.now()}` : undefined;
|
|
51
|
+
const fixture = {};
|
|
52
|
+
for (const prop of entity.props) {
|
|
53
|
+
if ("virtual" in prop && prop.virtual) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (prop.name === "id") {
|
|
57
|
+
if ("cone" in prop && prop.cone?.fixtureStrategy === "sequence") {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (prop.type === "string") {
|
|
61
|
+
const { faker: _faker } = await import("@faker-js/faker");
|
|
62
|
+
fixture[prop.name] = _faker.string.alphanumeric(32);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (prop.type === "uuid") {
|
|
66
|
+
const { faker: _faker } = await import("@faker-js/faker");
|
|
67
|
+
fixture[prop.name] = _faker.string.uuid();
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (prop.name in overrides) {
|
|
73
|
+
fixture[prop.name] = overrides[prop.name];
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const cone = prop.cone;
|
|
77
|
+
if (isRelationProp(prop)) {
|
|
78
|
+
const fkColName = `${prop.name}_id`;
|
|
79
|
+
if (fkColName in overrides && (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) && prop.hasJoinColumn)) {
|
|
80
|
+
fixture[fkColName] = overrides[fkColName];
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const relationValue = await this.generateRelationValue(entity, prop, context);
|
|
84
|
+
if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) && prop.hasJoinColumn) {
|
|
85
|
+
fixture[`${prop.name}_id`] = relationValue;
|
|
86
|
+
} else {
|
|
87
|
+
fixture[prop.name] = relationValue;
|
|
88
|
+
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (cone?.note && this.options.useLLM) {
|
|
92
|
+
try {
|
|
93
|
+
const llmValue = await this.generateWithLLM(cone.note, prop, entity, rowKey);
|
|
94
|
+
if (typeof llmValue === "string" && "length" in prop && typeof prop.length === "number" && llmValue.length > prop.length) {
|
|
95
|
+
fixture[prop.name] = llmValue.slice(0, prop.length);
|
|
96
|
+
} else {
|
|
97
|
+
fixture[prop.name] = llmValue;
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn(`[FixtureGenerator] LLM generation failed for ${entity.id}.${prop.name}, falling back to fixtureGenerator or default`, error instanceof Error ? error.message : error);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (cone?.fixtureGenerator) {
|
|
105
|
+
fixture[prop.name] = await this.executeGenerator(cone.fixtureGenerator, prop, entity);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (cone?.fixtureDefault !== undefined) {
|
|
109
|
+
fixture[prop.name] = cone.fixtureDefault;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
fixture[prop.name] = await this.generateDefaultValue(prop, entity);
|
|
113
|
+
}
|
|
114
|
+
if ("email" in fixture && typeof fixture.email === "string" && !("email" in overrides)) {
|
|
115
|
+
const nameValue = fixture.name || fixture.username || fixture.full_name || fixture.name_en;
|
|
116
|
+
if (nameValue && typeof nameValue === "string") {
|
|
117
|
+
const domain = fixture.email.split("@")[1] || "example.com";
|
|
118
|
+
const romanized = await this.romanizeName(nameValue);
|
|
119
|
+
fixture.email = `${romanized}@${domain}`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if ("password" in fixture && fixture.password && typeof fixture.password === "string") {
|
|
123
|
+
const bcrypt = await import("bcrypt");
|
|
124
|
+
fixture.password = await bcrypt.hash(fixture.password, 10);
|
|
125
|
+
}
|
|
126
|
+
context.fixtures.set(tempId, fixture);
|
|
127
|
+
return fixture;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Relation 값 생성 + 자동 Import
|
|
131
|
+
*/
|
|
132
|
+
async generateRelationValue(entity, prop, context) {
|
|
133
|
+
if (!isRelationProp(prop)) {
|
|
134
|
+
throw new Error(`FixtureGenerator: ${entity.id}.${prop.name} is not a relation prop`);
|
|
135
|
+
}
|
|
136
|
+
if (!isBelongsToOneRelationProp(prop) && !(isOneToOneRelationProp(prop) && prop.hasJoinColumn)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const cone = prop.cone;
|
|
140
|
+
const dataSource = cone?.dataSource;
|
|
141
|
+
if (dataSource) {
|
|
142
|
+
const cacheKey = `${prop.with}:${JSON.stringify(dataSource)}`;
|
|
143
|
+
if (!context.referenceCache.has(cacheKey)) {
|
|
144
|
+
const exploreResult = await this.dataExplorer.exploreWithRelations(prop.with, {
|
|
145
|
+
strategy: dataSource.strategy,
|
|
146
|
+
limit: dataSource.config?.limit || 10,
|
|
147
|
+
includeRelations: true,
|
|
148
|
+
maxDepth: 3,
|
|
149
|
+
...dataSource.config
|
|
150
|
+
});
|
|
151
|
+
context.referenceCache.set(cacheKey, exploreResult.main.records);
|
|
152
|
+
await this.importExploreResult(exploreResult, context);
|
|
153
|
+
}
|
|
154
|
+
const candidates = context.referenceCache.get(cacheKey);
|
|
155
|
+
if (candidates && candidates.length > 0) {
|
|
156
|
+
const selected = candidates[Math.floor(Math.random() * candidates.length)];
|
|
157
|
+
return selected.id;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const autoKey = `${prop.with}:auto`;
|
|
161
|
+
if (!context.referenceCache.has(autoKey)) {
|
|
162
|
+
const autoExploreResult = await this.dataExplorer.exploreWithRelations(prop.with, {
|
|
163
|
+
strategy: "random",
|
|
164
|
+
limit: 10,
|
|
165
|
+
includeRelations: true,
|
|
166
|
+
maxDepth: 3
|
|
167
|
+
});
|
|
168
|
+
context.referenceCache.set(autoKey, autoExploreResult.main.records);
|
|
169
|
+
if (autoExploreResult.main.records.length > 0) {
|
|
170
|
+
await this.importExploreResult(autoExploreResult, context);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const autoCandidates = context.referenceCache.get(autoKey);
|
|
174
|
+
if (autoCandidates && autoCandidates.length > 0) {
|
|
175
|
+
const selected = autoCandidates[Math.floor(Math.random() * autoCandidates.length)];
|
|
176
|
+
return selected.id;
|
|
177
|
+
}
|
|
178
|
+
if (prop.nullable) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`FixtureGenerator: ${entity.id}.${prop.name}에 필요한 ${prop.with} 데이터가 없습니다. ` + `먼저 ${prop.with}를 생성하거나 cone.dataSource를 설정하세요.`);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* ExploreWithRelations 결과를 targetDb에 import
|
|
185
|
+
*
|
|
186
|
+
* 관계 체인을 따라간 결과(main + related)를 모두 import합니다.
|
|
187
|
+
* 의존성 순서는 FixtureManager.insertFixtures가 자동으로 처리합니다.
|
|
188
|
+
*/
|
|
189
|
+
async importExploreResult(exploreResult, context) {
|
|
190
|
+
const allFixtureRecords = [];
|
|
191
|
+
for (const [entityId, records] of exploreResult.related.entries()) {
|
|
192
|
+
const entity = this.entityManager.get(entityId);
|
|
193
|
+
const recordsToImport = [];
|
|
194
|
+
!isTest() && console.log(chalk.cyan(`Importing related entity: ${entityId} (${records.length} records)`));
|
|
195
|
+
for (const record of records) {
|
|
196
|
+
const recordKey = `${entityId}#${record.id}`;
|
|
197
|
+
if (!context.importedRecords.has(recordKey)) {
|
|
198
|
+
recordsToImport.push(record);
|
|
199
|
+
context.importedRecords.add(recordKey);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (recordsToImport.length > 0) {
|
|
203
|
+
for (const record of recordsToImport) {
|
|
204
|
+
!isTest() && console.log(chalk.gray(` - Processing ${entityId} record:`, JSON.stringify(record).slice(0, 100)));
|
|
205
|
+
const fixtureRecords = await FixtureManager.createFixtureRecord(entity, record, {
|
|
206
|
+
_db: this.sourceDb,
|
|
207
|
+
singleRecord: true
|
|
208
|
+
});
|
|
209
|
+
allFixtureRecords.push(...fixtureRecords);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const mainEntity = this.entityManager.get(exploreResult.main.entityId);
|
|
214
|
+
const mainRecordsToImport = [];
|
|
215
|
+
!isTest() && console.log(chalk.cyan(`Importing main entity: ${exploreResult.main.entityId} (${exploreResult.main.records.length} records)`));
|
|
216
|
+
for (const record of exploreResult.main.records) {
|
|
217
|
+
const recordKey = `${exploreResult.main.entityId}#${record.id}`;
|
|
218
|
+
if (!context.importedRecords.has(recordKey)) {
|
|
219
|
+
mainRecordsToImport.push(record);
|
|
220
|
+
context.importedRecords.add(recordKey);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (mainRecordsToImport.length > 0) {
|
|
224
|
+
for (const record of mainRecordsToImport) {
|
|
225
|
+
!isTest() && console.log(chalk.gray(` - Processing ${exploreResult.main.entityId} record:`, JSON.stringify(record).slice(0, 100)));
|
|
226
|
+
const fixtureRecords = await FixtureManager.createFixtureRecord(mainEntity, record, {
|
|
227
|
+
_db: this.sourceDb,
|
|
228
|
+
singleRecord: true
|
|
229
|
+
});
|
|
230
|
+
allFixtureRecords.push(...fixtureRecords);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (allFixtureRecords.length > 0) {
|
|
234
|
+
await FixtureManager.insertFixtures(this.targetDbName, allFixtureRecords);
|
|
235
|
+
!isTest() && console.log(chalk.green(`Auto-imported ${exploreResult.main.entityId} with relations: ` + `${exploreResult.main.records.length} main + ${exploreResult.related.size} related entities`));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* fixtureGenerator 실행 (Faker.js만 지원)
|
|
240
|
+
*
|
|
241
|
+
* faker.* 형식의 표현식을 안전하게 파싱하여 실행합니다.
|
|
242
|
+
* 예: "faker.internet.email()" → faker.internet.email()
|
|
243
|
+
* 예: "faker.lorem.words(3)" → faker.lorem.words(3)
|
|
244
|
+
*/
|
|
245
|
+
async executeGenerator(generator, prop, entity) {
|
|
246
|
+
if (generator.startsWith("faker.")) {
|
|
247
|
+
const isNameField = prop.name === "username" || prop.name === "name";
|
|
248
|
+
const fakerModule = await import("@faker-js/faker");
|
|
249
|
+
const faker = isNameField ? fakerModule.fakerKO : fakerModule.faker;
|
|
250
|
+
const expr = generator.slice(6);
|
|
251
|
+
try {
|
|
252
|
+
const match = expr.match(/^([\w.]+)(?:\((.*?)\))?$/);
|
|
253
|
+
if (!match) {
|
|
254
|
+
throw new Error(`FixtureGenerator: Invalid faker expression for ${prop.name}: ${generator}`);
|
|
255
|
+
}
|
|
256
|
+
const [, path, argsStr] = match;
|
|
257
|
+
const parts = path.split(".");
|
|
258
|
+
let fn = faker;
|
|
259
|
+
for (const part of parts) {
|
|
260
|
+
if (typeof fn === "object" && fn !== null && part in fn) {
|
|
261
|
+
fn = fn[part];
|
|
262
|
+
} else {
|
|
263
|
+
throw new Error(`FixtureGenerator: Invalid faker path for ${prop.name}: faker.${path}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (typeof fn !== "function") {
|
|
267
|
+
throw new Error(`FixtureGenerator: faker.${path} is not a function (for ${prop.name})`);
|
|
268
|
+
}
|
|
269
|
+
let args = [];
|
|
270
|
+
if (argsStr?.trim()) {
|
|
271
|
+
args = this.parseGeneratorArgs(argsStr, prop.name);
|
|
272
|
+
}
|
|
273
|
+
return fn(...args);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
!isTest() && console.log(chalk.yellow(`Failed to execute generator "${generator}" for ${prop.name}, falling back to default:`), error);
|
|
276
|
+
return this.generateDefaultValue(prop, entity);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
!isTest() && console.log(chalk.yellow(`Unsupported generator expression for ${prop.name}: ${generator}. Only faker.* expressions are supported. Using default value.`));
|
|
280
|
+
return this.generateDefaultValue(prop, entity);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* 필드의 타입과 이름을 분석하여 적절한 기본값을 생성합니다.
|
|
284
|
+
*
|
|
285
|
+
* 우선순위:
|
|
286
|
+
* 1. 필드명 패턴 매칭 (salary, budget 등 의미있는 데이터)
|
|
287
|
+
* 2. 특수 케이스 (Department name 등 도메인 지식)
|
|
288
|
+
* 3. 배열 타입 (JSON 배열)
|
|
289
|
+
* 4. Enum 타입
|
|
290
|
+
* 5. 타입별 기본값
|
|
291
|
+
*/
|
|
292
|
+
async generateDefaultValue(prop, entity) {
|
|
293
|
+
const fakerModule = await import("@faker-js/faker");
|
|
294
|
+
const faker = fakerModule.faker;
|
|
295
|
+
const fakerKO = fakerModule.fakerKO;
|
|
296
|
+
const fakerJA = fakerModule.fakerJA;
|
|
297
|
+
const localeFaker = this.locale === "ko" ? fakerKO : this.locale === "ja" ? fakerJA : faker;
|
|
298
|
+
/**
|
|
299
|
+
* 1. Entity-specific 특수 케이스를 먼저 처리합니다.
|
|
300
|
+
* field_patterns보다 우선하여, 특정 엔티티의 필드에 도메인에 맞는 값을 생성합니다.
|
|
301
|
+
* 예: Department.name → 한국어 부서명 (사람 이름이 아님)
|
|
302
|
+
*/
|
|
303
|
+
/**
|
|
304
|
+
* Department name은 한국어 부서명 목록에서 선택합니다.
|
|
305
|
+
* 고유성을 위해 70% 확률로 prefix/suffix를 추가합니다.
|
|
306
|
+
*/
|
|
307
|
+
if (entity?.id === "Department" && prop.name === "name") {
|
|
308
|
+
const departments = [
|
|
309
|
+
"개발팀",
|
|
310
|
+
"기획팀",
|
|
311
|
+
"마케팅팀",
|
|
312
|
+
"영업팀",
|
|
313
|
+
"인사팀",
|
|
314
|
+
"총무팀",
|
|
315
|
+
"재무팀",
|
|
316
|
+
"회계팀",
|
|
317
|
+
"법무팀",
|
|
318
|
+
"디자인팀",
|
|
319
|
+
"IT팀",
|
|
320
|
+
"고객지원팀",
|
|
321
|
+
"품질관리팀",
|
|
322
|
+
"연구개발팀",
|
|
323
|
+
"생산팀",
|
|
324
|
+
"구매팀",
|
|
325
|
+
"물류팀"
|
|
326
|
+
];
|
|
327
|
+
const prefixes = [
|
|
328
|
+
"신규",
|
|
329
|
+
"통합",
|
|
330
|
+
"전략",
|
|
331
|
+
"글로벌",
|
|
332
|
+
"디지털",
|
|
333
|
+
"핵심"
|
|
334
|
+
];
|
|
335
|
+
const suffixes = [
|
|
336
|
+
"1팀",
|
|
337
|
+
"2팀",
|
|
338
|
+
"3팀",
|
|
339
|
+
"A팀",
|
|
340
|
+
"B팀",
|
|
341
|
+
"본부",
|
|
342
|
+
"센터",
|
|
343
|
+
"그룹"
|
|
344
|
+
];
|
|
345
|
+
const dept = faker.helpers.arrayElement(departments);
|
|
346
|
+
const random = Math.random();
|
|
347
|
+
if (random > .7) {
|
|
348
|
+
const prefix = faker.helpers.arrayElement(prefixes);
|
|
349
|
+
return `${prefix} ${dept}`;
|
|
350
|
+
}
|
|
351
|
+
if (random > .4) {
|
|
352
|
+
const suffix = faker.helpers.arrayElement(suffixes);
|
|
353
|
+
return `${dept} ${suffix}`;
|
|
354
|
+
}
|
|
355
|
+
return dept;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* 2. 필드명에서 의미를 추론하여 현실적인 데이터를 생성합니다.
|
|
359
|
+
* 예: salary → 30M~150M (한국 연봉 범위)
|
|
360
|
+
* budget → 10M~500M (프로젝트 예산 범위)
|
|
361
|
+
*/
|
|
362
|
+
const localeMappings = this.mappings[this.locale] || this.mappings.en;
|
|
363
|
+
const normalizedName = prop.name.toLowerCase().replace(/_/g, "");
|
|
364
|
+
for (const [pattern, config] of Object.entries(localeMappings.field_patterns)) {
|
|
365
|
+
if (normalizedName.includes(pattern.toLowerCase())) {
|
|
366
|
+
try {
|
|
367
|
+
return await this.executeFakerExpression(config.faker, prop);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
!isTest() && console.log(chalk.yellow(`Failed to execute field pattern "${pattern}" for ${prop.name}, falling back:`), error);
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 3. JSON 타입이면서 배열인 경우 (SonamuFile[], string[] 등)
|
|
376
|
+
* 필드명 패턴을 보고 적절한 배열 데이터를 생성합니다.
|
|
377
|
+
*/
|
|
378
|
+
if (prop.type === "json" && "id" in prop && prop.id) {
|
|
379
|
+
if (prop.id.endsWith("[]")) {
|
|
380
|
+
return this.generateArrayValue(prop, entity, faker, localeFaker);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/** 4. Enum 타입은 정의된 값 중 하나를 랜덤 선택합니다 */
|
|
384
|
+
if (prop.type === "enum") {
|
|
385
|
+
let enumValues = [];
|
|
386
|
+
if ("enum" in prop && Array.isArray(prop.enum) && prop.enum.length > 0) {
|
|
387
|
+
enumValues = prop.enum;
|
|
388
|
+
} else if ("id" in prop && prop.id && entity?.enumLabels?.[prop.id]) {
|
|
389
|
+
enumValues = Object.keys(entity.enumLabels[prop.id]);
|
|
390
|
+
}
|
|
391
|
+
if (enumValues.length > 0) {
|
|
392
|
+
return faker.helpers.arrayElement(enumValues);
|
|
393
|
+
}
|
|
394
|
+
return prop.nullable ? null : "UNKNOWN";
|
|
395
|
+
}
|
|
396
|
+
if (prop.type === "enum[]") {
|
|
397
|
+
let enumValues = [];
|
|
398
|
+
if ("enum" in prop && Array.isArray(prop.enum) && prop.enum.length > 0) {
|
|
399
|
+
enumValues = prop.enum;
|
|
400
|
+
} else if ("id" in prop && prop.id && entity?.enumLabels?.[prop.id]) {
|
|
401
|
+
enumValues = Object.keys(entity.enumLabels[prop.id]);
|
|
402
|
+
}
|
|
403
|
+
if (enumValues.length > 0) {
|
|
404
|
+
return [faker.helpers.arrayElement(enumValues)];
|
|
405
|
+
}
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* 5. Vector 타입은 현재 지원하지 않으므로 null을 반환합니다.
|
|
410
|
+
* 향후 AI embedding 생성 기능 추가 시 구현 예정입니다.
|
|
411
|
+
*/
|
|
412
|
+
if (prop.type === "vector" || prop.type === "vector[]" || prop.type === "tsvector") {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
/** 6. 타입별 기본 Faker 표현식을 실행합니다 */
|
|
416
|
+
const typeDefault = localeMappings.type_defaults[prop.type];
|
|
417
|
+
if (typeDefault) {
|
|
418
|
+
try {
|
|
419
|
+
return await this.executeFakerExpression(typeDefault.faker, prop);
|
|
420
|
+
} catch (error) {
|
|
421
|
+
!isTest() && console.log(chalk.yellow(`Failed to execute type default for ${prop.type}, using fallback:`, error));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/** 7. 매핑되지 않은 타입은 기본 Faker 함수로 처리합니다 */
|
|
425
|
+
switch (prop.type) {
|
|
426
|
+
case "string":
|
|
427
|
+
case "string[]": return faker.lorem.words(3);
|
|
428
|
+
case "integer": return faker.number.int({
|
|
429
|
+
min: 1,
|
|
430
|
+
max: 1e3
|
|
431
|
+
});
|
|
432
|
+
case "integer[]": return [faker.number.int({
|
|
433
|
+
min: 1,
|
|
434
|
+
max: 1e3
|
|
435
|
+
})];
|
|
436
|
+
case "bigInteger": return faker.number.bigInt({
|
|
437
|
+
min: 1n,
|
|
438
|
+
max: 1000n
|
|
439
|
+
});
|
|
440
|
+
case "bigInteger[]": return [faker.number.bigInt({
|
|
441
|
+
min: 1n,
|
|
442
|
+
max: 1000n
|
|
443
|
+
})];
|
|
444
|
+
case "number":
|
|
445
|
+
case "numeric": return faker.number.float({
|
|
446
|
+
min: 0,
|
|
447
|
+
max: 1e3
|
|
448
|
+
});
|
|
449
|
+
case "number[]":
|
|
450
|
+
case "numeric[]": return [faker.number.float({
|
|
451
|
+
min: 0,
|
|
452
|
+
max: 1e3
|
|
453
|
+
})];
|
|
454
|
+
case "boolean": return faker.datatype.boolean();
|
|
455
|
+
case "boolean[]": return [faker.datatype.boolean()];
|
|
456
|
+
case "date":
|
|
457
|
+
case "date[]": return faker.date.past();
|
|
458
|
+
case "json": return {};
|
|
459
|
+
case "uuid":
|
|
460
|
+
case "uuid[]": return faker.string.uuid();
|
|
461
|
+
default: return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* 배열 타입의 값을 생성합니다.
|
|
466
|
+
*
|
|
467
|
+
* 타입 ID와 필드명 패턴을 분석하여 적절한 배열 데이터를 생성합니다.
|
|
468
|
+
* 예: image_urls → [{url, name, mime_type}, ...]
|
|
469
|
+
* tag_ids → [1, 23, 45]
|
|
470
|
+
*/
|
|
471
|
+
generateArrayValue(prop, _entity, faker, _localeFaker) {
|
|
472
|
+
const count = faker.number.int({
|
|
473
|
+
min: 1,
|
|
474
|
+
max: 3
|
|
475
|
+
});
|
|
476
|
+
/** SonamuFile[]은 Sonamu 내장 타입으로 구조가 정해져 있습니다 */
|
|
477
|
+
if ("id" in prop && prop.id === "SonamuFile[]") {
|
|
478
|
+
return Array.from({ length: count }, () => ({
|
|
479
|
+
url: faker.image.url(),
|
|
480
|
+
name: faker.system.fileName(),
|
|
481
|
+
mime_type: faker.helpers.arrayElement([
|
|
482
|
+
"image/jpeg",
|
|
483
|
+
"image/png",
|
|
484
|
+
"image/gif",
|
|
485
|
+
"application/pdf"
|
|
486
|
+
])
|
|
487
|
+
}));
|
|
488
|
+
}
|
|
489
|
+
/** 필드명에서 배열의 용도를 추론합니다 */
|
|
490
|
+
const normalizedName = prop.name.toLowerCase().replace(/_/g, "");
|
|
491
|
+
if (normalizedName.includes("url") || normalizedName.includes("image")) {
|
|
492
|
+
return Array.from({ length: count }, () => faker.internet.url());
|
|
493
|
+
}
|
|
494
|
+
if (normalizedName.includes("id") && normalizedName.endsWith("s")) {
|
|
495
|
+
return Array.from({ length: count }, () => faker.number.int({
|
|
496
|
+
min: 1,
|
|
497
|
+
max: 100
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
if (normalizedName.includes("tag") || normalizedName.includes("name")) {
|
|
501
|
+
return Array.from({ length: count }, () => faker.lorem.word());
|
|
502
|
+
}
|
|
503
|
+
/** 패턴 매칭되지 않으면 빈 배열을 반환합니다 */
|
|
504
|
+
return [];
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* JSON 매핑의 Faker 표현식을 파싱하여 실행합니다.
|
|
508
|
+
*
|
|
509
|
+
* 표현식 예시:
|
|
510
|
+
* - "faker.internet.email()" → 인자 없음
|
|
511
|
+
* - "faker.number.int({ min: 1, max: 100 })" → JSON 인자
|
|
512
|
+
* - "{}" → 리터럴 값 (JSON.parse)
|
|
513
|
+
*
|
|
514
|
+
* fakerKO, fakerJA도 지원하여 다국어 데이터를 생성합니다.
|
|
515
|
+
*/
|
|
516
|
+
async executeFakerExpression(expression, prop) {
|
|
517
|
+
const fakerModule = await import("@faker-js/faker");
|
|
518
|
+
const faker = fakerModule.faker;
|
|
519
|
+
const fakerKO = fakerModule.fakerKO;
|
|
520
|
+
const fakerJA = fakerModule.fakerJA;
|
|
521
|
+
/** Faker 표현식이 아닌 리터럴 값은 JSON으로 파싱합니다 */
|
|
522
|
+
if (!expression.startsWith("faker")) {
|
|
523
|
+
try {
|
|
524
|
+
return JSON.parse(expression);
|
|
525
|
+
} catch {
|
|
526
|
+
return expression;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
/** 표현식에서 Faker 객체와 경로를 추출합니다 */
|
|
530
|
+
const match = expression.match(/^(faker|fakerKO|fakerJA)\.(.*?)$/);
|
|
531
|
+
if (!match) {
|
|
532
|
+
throw new Error(`Invalid faker expression: ${expression}`);
|
|
533
|
+
}
|
|
534
|
+
const [, fakerName, expr] = match;
|
|
535
|
+
const selectedFaker = fakerName === "fakerKO" ? fakerKO : fakerName === "fakerJA" ? fakerJA : faker;
|
|
536
|
+
const funcMatch = expr.match(/^([\w.]+)(?:\((.*?)\))?$/);
|
|
537
|
+
if (!funcMatch) {
|
|
538
|
+
throw new Error(`Invalid faker expression for ${prop.name}: ${expression}`);
|
|
539
|
+
}
|
|
540
|
+
const [, path, argsStr] = funcMatch;
|
|
541
|
+
const parts = path.split(".");
|
|
542
|
+
/** 점 표기법(dot notation)으로 Faker 함수를 찾아갑니다 */
|
|
543
|
+
let fn = selectedFaker;
|
|
544
|
+
for (const part of parts) {
|
|
545
|
+
if (typeof fn === "object" && fn !== null && part in fn) {
|
|
546
|
+
fn = fn[part];
|
|
547
|
+
} else {
|
|
548
|
+
throw new Error(`Invalid faker path for ${prop.name}: ${fakerName}.${path}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (typeof fn !== "function") {
|
|
552
|
+
throw new Error(`${fakerName}.${path} is not a function (for ${prop.name})`);
|
|
553
|
+
}
|
|
554
|
+
let args = [];
|
|
555
|
+
if (argsStr?.trim()) {
|
|
556
|
+
args = this.parseGeneratorArgs(argsStr, prop.name);
|
|
557
|
+
}
|
|
558
|
+
return fn(...args);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* fixtureHint를 LLM에게 전달하여 현실적인 테스트 데이터를 생성합니다.
|
|
562
|
+
*
|
|
563
|
+
* faker.js로는 생성하기 어려운 복잡한 텍스트(자기소개, 설명문 등)를
|
|
564
|
+
* LLM을 활용하여 생성합니다. 동일한 hint에 대한 중복 호출을 방지하기 위해
|
|
565
|
+
* 캐싱을 기본으로 지원합니다 (LLM API 비용 절감).
|
|
566
|
+
*
|
|
567
|
+
* ai 패키지는 dynamic import로 불러오므로, useLLM이 false인 경우
|
|
568
|
+
* 의존성이 설치되지 않아도 fixture 생성이 정상 동작합니다.
|
|
569
|
+
*/
|
|
570
|
+
async generateWithLLM(fixtureHint, prop, entity, rowKey) {
|
|
571
|
+
if (rowKey) {
|
|
572
|
+
const rowCacheKey = `${rowKey}:${prop.name}`;
|
|
573
|
+
if (this.llmCache.has(rowCacheKey)) {
|
|
574
|
+
return this.llmCache.get(rowCacheKey);
|
|
575
|
+
}
|
|
576
|
+
const llmProps = entity.props.filter((p) => {
|
|
577
|
+
if (isRelationProp(p)) return false;
|
|
578
|
+
if (p.cone?.fixtureGenerator) return false;
|
|
579
|
+
if (p.name === "id" && p.cone?.fixtureStrategy === "sequence") return false;
|
|
580
|
+
return !!p.cone?.note;
|
|
581
|
+
});
|
|
582
|
+
if (llmProps.length === 0) {
|
|
583
|
+
!isTest() && console.log(`[FixtureGenerator] llmProps is empty for ${entity.id}.${prop.name}, using single field fallback`);
|
|
584
|
+
return this.generateSingleWithLLM(fixtureHint, prop, entity);
|
|
585
|
+
}
|
|
586
|
+
const apiKey = this.getApiKey();
|
|
587
|
+
const { createAnthropic } = await import("@ai-sdk/anthropic");
|
|
588
|
+
const { generateText } = await import("ai");
|
|
589
|
+
const rowResponse = await generateText({
|
|
590
|
+
model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-6"),
|
|
591
|
+
prompt: this.buildRowLLMPrompt(llmProps, entity)
|
|
592
|
+
});
|
|
593
|
+
if (!rowResponse || typeof rowResponse.text !== "string") {
|
|
594
|
+
throw new Error("Invalid LLM response");
|
|
595
|
+
}
|
|
596
|
+
const rowResult = this.parseRowLLMResponse(rowResponse.text, llmProps);
|
|
597
|
+
for (const [fieldName, value] of Object.entries(rowResult)) {
|
|
598
|
+
this.llmCache.set(`${rowKey}:${fieldName}`, value);
|
|
599
|
+
}
|
|
600
|
+
if (this.llmCache.has(rowCacheKey)) {
|
|
601
|
+
return this.llmCache.get(rowCacheKey);
|
|
602
|
+
}
|
|
603
|
+
return this.generateSingleWithLLM(fixtureHint, prop, entity);
|
|
604
|
+
}
|
|
605
|
+
return this.generateSingleWithLLM(fixtureHint, prop, entity);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* 단일 필드를 LLM으로 생성합니다 (rowKey 없을 때 fallback용)
|
|
609
|
+
*/
|
|
610
|
+
async generateSingleWithLLM(fixtureHint, prop, entity) {
|
|
611
|
+
const cacheKey = `${entity.id}:${prop.name}:${fixtureHint}`;
|
|
612
|
+
if (this.options.enableLLMCache && this.llmCache.has(cacheKey)) {
|
|
613
|
+
return this.llmCache.get(cacheKey);
|
|
614
|
+
}
|
|
615
|
+
const apiKey = this.getApiKey();
|
|
616
|
+
const { createAnthropic } = await import("@ai-sdk/anthropic");
|
|
617
|
+
const { generateText } = await import("ai");
|
|
618
|
+
const singleResponse = await generateText({
|
|
619
|
+
model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-6"),
|
|
620
|
+
prompt: this.buildLLMPrompt(fixtureHint, prop, entity)
|
|
621
|
+
});
|
|
622
|
+
if (!singleResponse || typeof singleResponse.text !== "string") {
|
|
623
|
+
throw new Error("Invalid LLM response");
|
|
624
|
+
}
|
|
625
|
+
const value = this.parseLLMResponse(singleResponse.text, prop.type);
|
|
626
|
+
if (this.options.enableLLMCache) {
|
|
627
|
+
this.llmCache.set(cacheKey, value);
|
|
628
|
+
}
|
|
629
|
+
return value;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* row 전체를 한 번에 생성하는 LLM 프롬프트를 만듭니다.
|
|
633
|
+
*/
|
|
634
|
+
buildRowLLMPrompt(props, entity) {
|
|
635
|
+
const locale = this.options.locale || "ko";
|
|
636
|
+
const language = locale === "ko" ? "Korean" : locale === "ja" ? "Japanese" : "English";
|
|
637
|
+
const fieldDescriptions = props.map((p) => {
|
|
638
|
+
let desc = `- ${p.name} (${p.type}): ${p.cone?.note ?? ""}`;
|
|
639
|
+
if ((p.type === "enum" || p.type === "enum[]") && "id" in p && p.id && entity.enumLabels?.[p.id]) {
|
|
640
|
+
const values = Object.keys(entity.enumLabels[p.id]).join(", ");
|
|
641
|
+
desc += ` [allowed values: ${values}]`;
|
|
642
|
+
}
|
|
643
|
+
return desc;
|
|
644
|
+
}).join("\n");
|
|
645
|
+
const otherProps = entity.props.filter((p) => !props.includes(p) && !isRelationProp(p) && p.name !== "id" && !("virtual" in p && p.virtual)).map((p) => {
|
|
646
|
+
let desc = `- ${p.name} (${p.type})`;
|
|
647
|
+
if (p.cone?.note) desc += `: ${p.cone.note}`;
|
|
648
|
+
if ((p.type === "enum" || p.type === "enum[]") && "id" in p && p.id && entity.enumLabels?.[p.id]) {
|
|
649
|
+
const values = Object.keys(entity.enumLabels[p.id]).join(", ");
|
|
650
|
+
desc += ` [allowed values: ${values}]`;
|
|
651
|
+
}
|
|
652
|
+
return desc;
|
|
653
|
+
}).join("\n");
|
|
654
|
+
const otherPropsContext = otherProps ? `\n\nOther fields in this entity (for context, do NOT generate these):\n${otherProps}` : "";
|
|
655
|
+
const outputShape = props.map((p) => ` "${p.name}": <${p.type}>`).join(",\n");
|
|
656
|
+
const entityContext = entity.cone?.note ? `\nEntity description: ${entity.cone.note}` : "";
|
|
657
|
+
return `Generate test fixture data for the ${entity.id} entity. All fields must be coherent and consistent with each other.
|
|
712
658
|
|
|
713
659
|
Entity: ${entity.id}${entityContext}
|
|
714
660
|
Locale: ${locale} (use ${language} for text fields)
|
|
@@ -726,38 +672,39 @@ Return exactly this JSON shape:
|
|
|
726
672
|
{
|
|
727
673
|
${outputShape}
|
|
728
674
|
}`;
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* row LLM 응답을 파싱하여 필드별 값으로 변환합니다.
|
|
678
|
+
*/
|
|
679
|
+
parseRowLLMResponse(text, props) {
|
|
680
|
+
const jsonText = text.trim().replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
|
681
|
+
let parsed;
|
|
682
|
+
try {
|
|
683
|
+
const raw = JSON.parse(jsonText);
|
|
684
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
685
|
+
!isTest() && console.warn("[FixtureGenerator] Row LLM response is not a plain object:", text);
|
|
686
|
+
return {};
|
|
687
|
+
}
|
|
688
|
+
parsed = raw;
|
|
689
|
+
} catch {
|
|
690
|
+
!isTest() && console.warn("[FixtureGenerator] Failed to parse row LLM response:", text);
|
|
691
|
+
return {};
|
|
692
|
+
}
|
|
693
|
+
const result = {};
|
|
694
|
+
for (const prop of props) {
|
|
695
|
+
if (prop.name in parsed) {
|
|
696
|
+
result[prop.name] = this.parseLLMResponse(String(parsed[prop.name] ?? ""), prop.type);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return result;
|
|
700
|
+
}
|
|
701
|
+
buildLLMPrompt(hint, prop, entity) {
|
|
702
|
+
const locale = this.options.locale || "ko";
|
|
703
|
+
const language = locale === "ko" ? "Korean" : locale === "ja" ? "Japanese" : "English";
|
|
704
|
+
const entityContext = entity.cone?.note ? `\nEntity context: ${entity.cone.note}` : "";
|
|
705
|
+
const otherFields = entity.props.filter((p) => p.name !== prop.name && !isRelationProp(p) && p.cone?.note).map((p) => `- ${p.name} (${p.type}): ${p.cone?.note}`).join("\n");
|
|
706
|
+
const otherFieldsContext = otherFields ? `\n\nOther fields in this entity (for context):\n${otherFields}` : "";
|
|
707
|
+
let prompt = `Generate test data for ${entity.id}.${prop.name} (type: ${prop.type})${entityContext}${otherFieldsContext}
|
|
761
708
|
|
|
762
709
|
Requirement: ${hint}
|
|
763
710
|
|
|
@@ -765,608 +712,531 @@ Rules:
|
|
|
765
712
|
- Return ONLY the value, no explanation or markdown
|
|
766
713
|
- Use ${language} language if applicable
|
|
767
714
|
- Format: ${this.getExpectedFormat(prop.type)}`;
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
}
|
|
1292
|
-
return allResults;
|
|
1293
|
-
}
|
|
1294
|
-
/**
|
|
1295
|
-
* overrides 값의 "{{fieldName}}" 템플릿을 부모 fixture 데이터로 치환합니다.
|
|
1296
|
-
*
|
|
1297
|
-
* 예: { "account_id": "{{email}}" } → { "account_id": "user@example.com" }
|
|
1298
|
-
*/ resolveTemplateOverrides(overrides, parentData) {
|
|
1299
|
-
const resolved = {};
|
|
1300
|
-
for (const [key, value] of Object.entries(overrides)){
|
|
1301
|
-
if (typeof value === "string" && value.startsWith("{{") && value.endsWith("}}")) {
|
|
1302
|
-
const fieldName = value.slice(2, -2).trim();
|
|
1303
|
-
if (!(fieldName in parentData)) {
|
|
1304
|
-
throw new Error(`템플릿 필드 "${fieldName}"이(가) 부모 fixture 데이터에 존재하지 않습니다 (override key: "${key}")`);
|
|
1305
|
-
}
|
|
1306
|
-
resolved[key] = parentData[fieldName];
|
|
1307
|
-
} else {
|
|
1308
|
-
resolved[key] = value;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
return resolved;
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* 실제 DB(sourceDb)에서 데이터를 조회하여 fixture DB(targetDb)에 import합니다.
|
|
1315
|
-
*
|
|
1316
|
-
* 1. DataExplorer로 sourceDb에서 데이터 조회 (관련 데이터 포함)
|
|
1317
|
-
* 2. FixtureRecord로 변환
|
|
1318
|
-
* 3. targetDb에 삽입
|
|
1319
|
-
*
|
|
1320
|
-
* @param entityName - 조회할 entity 이름
|
|
1321
|
-
* @param options - 조회 옵션 (strategy, limit, includeRelations 등)
|
|
1322
|
-
* @returns 저장된 fixture 데이터 (실제 DB ID 포함)
|
|
1323
|
-
*
|
|
1324
|
-
* @example
|
|
1325
|
-
* // 프로덕션 DB에서 User 10명 + 관련 Employee, Department 가져오기
|
|
1326
|
-
* await generator.importFromSource("User", {
|
|
1327
|
-
* strategy: "sample",
|
|
1328
|
-
* limit: 10,
|
|
1329
|
-
* includeRelations: true,
|
|
1330
|
-
* maxDepth: 2
|
|
1331
|
-
* });
|
|
1332
|
-
*/ async importFromSource(entityName, options) {
|
|
1333
|
-
!isTest() && console.log(chalk.blue(`Importing ${entityName} from source DB with options: ${JSON.stringify({
|
|
1334
|
-
strategy: options.strategy,
|
|
1335
|
-
limit: options.limit,
|
|
1336
|
-
includeRelations: options.includeRelations,
|
|
1337
|
-
maxDepth: options.maxDepth
|
|
1338
|
-
})}`));
|
|
1339
|
-
// 1. DataExplorer로 sourceDb에서 데이터 조회 (관련 데이터 포함)
|
|
1340
|
-
const exploreResult = await this.dataExplorer.exploreWithRelations(entityName, options);
|
|
1341
|
-
!isTest() && console.log(chalk.cyan(`Found ${exploreResult.main.records.length} ${entityName} records and ${exploreResult.related.size} related entities`));
|
|
1342
|
-
// 2. FixtureRecord로 변환
|
|
1343
|
-
const fixtureRecords = [];
|
|
1344
|
-
// 메인 entity의 records를 FixtureRecord로 변환
|
|
1345
|
-
const mainEntity = this.entityManager.get(entityName);
|
|
1346
|
-
for (const record of exploreResult.main.records){
|
|
1347
|
-
const records = await FixtureManager.createFixtureRecord(mainEntity, record, {
|
|
1348
|
-
_db: this.sourceDb,
|
|
1349
|
-
singleRecord: true
|
|
1350
|
-
});
|
|
1351
|
-
fixtureRecords.push(...records);
|
|
1352
|
-
}
|
|
1353
|
-
// 관련 entity의 records를 FixtureRecord로 변환
|
|
1354
|
-
for (const [relatedEntityName, relatedRecords] of exploreResult.related.entries()){
|
|
1355
|
-
const relatedEntity = this.entityManager.get(relatedEntityName);
|
|
1356
|
-
for (const record of relatedRecords){
|
|
1357
|
-
const records = await FixtureManager.createFixtureRecord(relatedEntity, record, {
|
|
1358
|
-
_db: this.sourceDb,
|
|
1359
|
-
singleRecord: true
|
|
1360
|
-
});
|
|
1361
|
-
fixtureRecords.push(...records);
|
|
1362
|
-
}
|
|
1363
|
-
!isTest() && console.log(chalk.gray(` - ${relatedEntityName}: ${relatedRecords.length} records`));
|
|
1364
|
-
}
|
|
1365
|
-
// 3. targetDb에 삽입 (FixtureManager가 의존성 정렬 처리)
|
|
1366
|
-
const results = await FixtureManager.insertFixtures(this.targetDbName, fixtureRecords);
|
|
1367
|
-
!isTest() && console.log(chalk.green(`Successfully imported ${results.length} records to ${this.targetDbName} (${exploreResult.main.records.length} ${entityName} + ${results.length - exploreResult.main.records.length} related)`));
|
|
1368
|
-
return results;
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
715
|
+
if (prop.type === "enum" || prop.type === "enum[]") {
|
|
716
|
+
let enumValues = [];
|
|
717
|
+
if ("enum" in prop && Array.isArray(prop.enum) && prop.enum.length > 0) {
|
|
718
|
+
enumValues = prop.enum;
|
|
719
|
+
} else if ("id" in prop && prop.id && entity?.enumLabels?.[prop.id]) {
|
|
720
|
+
enumValues = Object.keys(entity.enumLabels[prop.id]);
|
|
721
|
+
}
|
|
722
|
+
if (enumValues.length > 0) {
|
|
723
|
+
prompt += `\n- IMPORTANT: Choose ONLY from these allowed values: ${enumValues.join(", ")}`;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
prompt += `\n\nExample: ${this.getExampleForType(prop.type, locale)}`;
|
|
727
|
+
return prompt;
|
|
728
|
+
}
|
|
729
|
+
parseLLMResponse(text, propType) {
|
|
730
|
+
const cleaned = text.trim();
|
|
731
|
+
if (propType.endsWith("[]")) {
|
|
732
|
+
try {
|
|
733
|
+
const parsed = JSON.parse(cleaned);
|
|
734
|
+
const baseType = propType.slice(0, -2);
|
|
735
|
+
if (Array.isArray(parsed)) {
|
|
736
|
+
return parsed.map((item) => {
|
|
737
|
+
if (item === null || item === undefined) {
|
|
738
|
+
return this.getDefaultValueForType(baseType);
|
|
739
|
+
}
|
|
740
|
+
if (typeof item === "object") {
|
|
741
|
+
return baseType === "json" ? item : this.parseScalarValue(JSON.stringify(item), baseType);
|
|
742
|
+
}
|
|
743
|
+
return this.parseScalarValue(String(item), baseType);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
if (parsed === null || parsed === undefined) {
|
|
747
|
+
return [this.getDefaultValueForType(baseType)];
|
|
748
|
+
}
|
|
749
|
+
return [this.parseScalarValue(String(parsed), baseType)];
|
|
750
|
+
} catch {
|
|
751
|
+
return [];
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return this.parseScalarValue(cleaned, propType);
|
|
755
|
+
}
|
|
756
|
+
getDefaultValueForType(propType) {
|
|
757
|
+
switch (propType) {
|
|
758
|
+
case "integer": return 0;
|
|
759
|
+
case "bigInteger": return 0n;
|
|
760
|
+
case "float":
|
|
761
|
+
case "number":
|
|
762
|
+
case "numeric": return 0;
|
|
763
|
+
case "boolean": return false;
|
|
764
|
+
case "date": return new Date();
|
|
765
|
+
case "json": return {};
|
|
766
|
+
case "uuid": return "00000000-0000-0000-0000-000000000000";
|
|
767
|
+
default: return "";
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
parseScalarValue(text, propType) {
|
|
771
|
+
const cleaned = text.trim();
|
|
772
|
+
switch (propType) {
|
|
773
|
+
case "integer": {
|
|
774
|
+
const num = parseInt(cleaned, 10);
|
|
775
|
+
return Number.isNaN(num) ? 0 : num;
|
|
776
|
+
}
|
|
777
|
+
case "bigInteger": {
|
|
778
|
+
try {
|
|
779
|
+
return BigInt(cleaned);
|
|
780
|
+
} catch {
|
|
781
|
+
return 0n;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
case "float":
|
|
785
|
+
case "number":
|
|
786
|
+
case "numeric": {
|
|
787
|
+
const num = parseFloat(cleaned);
|
|
788
|
+
return Number.isNaN(num) ? 0 : num;
|
|
789
|
+
}
|
|
790
|
+
case "boolean": return cleaned.toLowerCase() === "true";
|
|
791
|
+
case "date": {
|
|
792
|
+
const date = new Date(cleaned);
|
|
793
|
+
return Number.isNaN(date.getTime()) ? new Date() : date;
|
|
794
|
+
}
|
|
795
|
+
case "json": try {
|
|
796
|
+
return JSON.parse(cleaned);
|
|
797
|
+
} catch {
|
|
798
|
+
return cleaned;
|
|
799
|
+
}
|
|
800
|
+
case "uuid":
|
|
801
|
+
case "enum": return cleaned;
|
|
802
|
+
default: return cleaned;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* faker 함수 인자 문자열을 파싱하여 인자 배열로 반환합니다.
|
|
807
|
+
*
|
|
808
|
+
* 3단계 전략:
|
|
809
|
+
* 1. JSON 직접 파싱 (표준 JSON 표현식)
|
|
810
|
+
* 2. JS 객체 리터럴 → JSON 변환 후 재시도 (single quote, unquoted key 처리)
|
|
811
|
+
* 3. 단순 단일 인자 폴백 (숫자, 문자열)
|
|
812
|
+
*/
|
|
813
|
+
parseGeneratorArgs(argsStr, propName) {
|
|
814
|
+
try {
|
|
815
|
+
const parsed = JSON.parse(`[${argsStr}]`);
|
|
816
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
817
|
+
} catch {}
|
|
818
|
+
try {
|
|
819
|
+
const jsonStr = this.convertJsLiteralToJson(argsStr);
|
|
820
|
+
const parsed = JSON.parse(`[${jsonStr}]`);
|
|
821
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
822
|
+
} catch {}
|
|
823
|
+
const trimmed = argsStr.trim();
|
|
824
|
+
if (!Number.isNaN(Number(trimmed))) {
|
|
825
|
+
return [Number(trimmed)];
|
|
826
|
+
}
|
|
827
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
828
|
+
return [trimmed.slice(1, -1)];
|
|
829
|
+
}
|
|
830
|
+
throw new Error(`FixtureGenerator: Cannot parse arguments for ${propName}: ${argsStr}`);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* JS 객체 리터럴을 JSON으로 변환합니다.
|
|
834
|
+
*
|
|
835
|
+
* 두 가지 변환:
|
|
836
|
+
* 1. Single-quoted 문자열 → double-quoted (이스케이프 처리 포함)
|
|
837
|
+
* 2. Unquoted 객체 키 → double-quoted
|
|
838
|
+
*/
|
|
839
|
+
convertJsLiteralToJson(input) {
|
|
840
|
+
const withDoubleQuotes = input.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, (_, content) => `"${content.replace(/"/g, "\\\"").replace(/\\'/g, "'")}"`);
|
|
841
|
+
return withDoubleQuotes.replace(/([{,]\s*)([a-zA-Z_$][\w$]*)(\s*:)/g, "$1\"$2\"$3");
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Sonamu.secret을 우선으로 하고, 없으면 환경변수에서 API 키를 읽습니다.
|
|
845
|
+
*
|
|
846
|
+
* Sonamu.secret은 프로젝트별 설정(sonamu.config.ts)이므로 더 높은 우선순위를 가지며,
|
|
847
|
+
* 환경변수는 개발 환경이나 CI/CD에서 fallback으로 사용됩니다.
|
|
848
|
+
*/
|
|
849
|
+
getApiKey() {
|
|
850
|
+
let apiKey;
|
|
851
|
+
try {
|
|
852
|
+
const { Sonamu } = (init_api(), __toCommonJS(api_exports));
|
|
853
|
+
apiKey = Sonamu.secrets?.anthropic_api_key;
|
|
854
|
+
} catch {}
|
|
855
|
+
if (!apiKey) {
|
|
856
|
+
apiKey = process.env.ANTHROPIC_API_KEY;
|
|
857
|
+
}
|
|
858
|
+
if (!apiKey) {
|
|
859
|
+
throw new Error("ANTHROPIC_API_KEY not found. Set it in environment variables or Sonamu.secret.anthropic_api_key");
|
|
860
|
+
}
|
|
861
|
+
return apiKey;
|
|
862
|
+
}
|
|
863
|
+
getExpectedFormat(propType) {
|
|
864
|
+
if (propType.endsWith("[]")) {
|
|
865
|
+
const baseType = propType.slice(0, -2);
|
|
866
|
+
const baseFormat = this.getScalarFormat(baseType);
|
|
867
|
+
return `JSON array of ${baseFormat} (e.g., [${this.getExampleForType(baseType, "en")}, ...])`;
|
|
868
|
+
}
|
|
869
|
+
return this.getScalarFormat(propType);
|
|
870
|
+
}
|
|
871
|
+
getScalarFormat(propType) {
|
|
872
|
+
switch (propType) {
|
|
873
|
+
case "integer":
|
|
874
|
+
case "bigInteger": return "integer numbers";
|
|
875
|
+
case "float":
|
|
876
|
+
case "number":
|
|
877
|
+
case "numeric": return "decimal numbers";
|
|
878
|
+
case "boolean": return "booleans (true or false)";
|
|
879
|
+
case "date": return "ISO 8601 date strings";
|
|
880
|
+
case "json": return "valid JSON object or array";
|
|
881
|
+
case "uuid": return "UUID strings";
|
|
882
|
+
case "enum": return "one of the allowed enum values";
|
|
883
|
+
default: return "plain text strings";
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
getExampleForType(propType, locale) {
|
|
887
|
+
if (propType.endsWith("[]")) {
|
|
888
|
+
const baseType = propType.slice(0, -2);
|
|
889
|
+
const baseExample = this.getScalarExample(baseType, locale);
|
|
890
|
+
return `[${baseExample}]`;
|
|
891
|
+
}
|
|
892
|
+
return this.getScalarExample(propType, locale);
|
|
893
|
+
}
|
|
894
|
+
getScalarExample(propType, locale) {
|
|
895
|
+
const isKorean = locale === "ko";
|
|
896
|
+
switch (propType) {
|
|
897
|
+
case "integer":
|
|
898
|
+
case "bigInteger": return "42";
|
|
899
|
+
case "float":
|
|
900
|
+
case "number":
|
|
901
|
+
case "numeric": return "3.14";
|
|
902
|
+
case "boolean": return "true";
|
|
903
|
+
case "date": return "2024-01-01";
|
|
904
|
+
case "json": return "{\"key\": \"value\"}";
|
|
905
|
+
case "uuid": return "550e8400-e29b-41d4-a716-446655440000";
|
|
906
|
+
case "enum": return "ENUM_VALUE";
|
|
907
|
+
default: return isKorean ? "안녕하세요" : "Hello";
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* 이름을 이메일 로컬 파트용 로마나이즈드 문자열로 변환합니다.
|
|
912
|
+
*
|
|
913
|
+
* 한글 이름은 초성-중성-종성 분해 후 로마나이즈 처리합니다.
|
|
914
|
+
* 영문 이름은 소문자로 변환하고 공백을 점(.)\uc73c로 치환합니다.
|
|
915
|
+
* 예: "김철수" → "cheolsu.kim", "John Doe" → "john.doe"
|
|
916
|
+
*/
|
|
917
|
+
async romanizeName(name) {
|
|
918
|
+
if (/[\uAC00-\uD7AF]/.test(name)) {
|
|
919
|
+
return this.romanizeKoreanName(name);
|
|
920
|
+
}
|
|
921
|
+
return name.toLowerCase().replace(/\s+/g, ".").replace(/[^a-z0-9.]/g, "");
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* 한글 이름을 로마나이즈 처리합니다.
|
|
925
|
+
*
|
|
926
|
+
* 초성/중성/종성 매핑 테이블을 사용하여 한글을 로마자로 변환합니다.
|
|
927
|
+
* 첫 글자를 성으로 간주하여 "김철수" → "cheolsu.kim" 형태로 출력합니다.
|
|
928
|
+
*/
|
|
929
|
+
romanizeKoreanName(name) {
|
|
930
|
+
const CHOSEONG = [
|
|
931
|
+
"g",
|
|
932
|
+
"kk",
|
|
933
|
+
"n",
|
|
934
|
+
"d",
|
|
935
|
+
"tt",
|
|
936
|
+
"r",
|
|
937
|
+
"m",
|
|
938
|
+
"b",
|
|
939
|
+
"pp",
|
|
940
|
+
"s",
|
|
941
|
+
"ss",
|
|
942
|
+
"",
|
|
943
|
+
"j",
|
|
944
|
+
"jj",
|
|
945
|
+
"ch",
|
|
946
|
+
"k",
|
|
947
|
+
"t",
|
|
948
|
+
"p",
|
|
949
|
+
"h"
|
|
950
|
+
];
|
|
951
|
+
const JUNGSEONG = [
|
|
952
|
+
"a",
|
|
953
|
+
"ae",
|
|
954
|
+
"ya",
|
|
955
|
+
"yae",
|
|
956
|
+
"eo",
|
|
957
|
+
"e",
|
|
958
|
+
"yeo",
|
|
959
|
+
"ye",
|
|
960
|
+
"o",
|
|
961
|
+
"wa",
|
|
962
|
+
"wae",
|
|
963
|
+
"oe",
|
|
964
|
+
"yo",
|
|
965
|
+
"u",
|
|
966
|
+
"wo",
|
|
967
|
+
"we",
|
|
968
|
+
"wi",
|
|
969
|
+
"yu",
|
|
970
|
+
"eu",
|
|
971
|
+
"ui",
|
|
972
|
+
"i"
|
|
973
|
+
];
|
|
974
|
+
const JONGSEONG = [
|
|
975
|
+
"",
|
|
976
|
+
"k",
|
|
977
|
+
"k",
|
|
978
|
+
"k",
|
|
979
|
+
"n",
|
|
980
|
+
"n",
|
|
981
|
+
"n",
|
|
982
|
+
"t",
|
|
983
|
+
"l",
|
|
984
|
+
"l",
|
|
985
|
+
"l",
|
|
986
|
+
"l",
|
|
987
|
+
"l",
|
|
988
|
+
"l",
|
|
989
|
+
"l",
|
|
990
|
+
"l",
|
|
991
|
+
"m",
|
|
992
|
+
"p",
|
|
993
|
+
"p",
|
|
994
|
+
"t",
|
|
995
|
+
"t",
|
|
996
|
+
"ng",
|
|
997
|
+
"t",
|
|
998
|
+
"t",
|
|
999
|
+
"k",
|
|
1000
|
+
"t",
|
|
1001
|
+
"p",
|
|
1002
|
+
"t"
|
|
1003
|
+
];
|
|
1004
|
+
const romanize = (char) => {
|
|
1005
|
+
const code = char.charCodeAt(0);
|
|
1006
|
+
if (code < 44032 || code > 55215) return char;
|
|
1007
|
+
const offset = code - 44032;
|
|
1008
|
+
const cho = Math.floor(offset / 588);
|
|
1009
|
+
const jung = Math.floor(offset % 588 / 28);
|
|
1010
|
+
const jong = offset % 28;
|
|
1011
|
+
return CHOSEONG[cho] + JUNGSEONG[jung] + JONGSEONG[jong];
|
|
1012
|
+
};
|
|
1013
|
+
const chars = [...name];
|
|
1014
|
+
const familyName = romanize(chars[0]);
|
|
1015
|
+
const givenName = chars.slice(1).map(romanize).join("");
|
|
1016
|
+
if (givenName) {
|
|
1017
|
+
return `${givenName}.${familyName}`;
|
|
1018
|
+
}
|
|
1019
|
+
return familyName;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* LLM 캐시 통계를 반환합니다.
|
|
1023
|
+
*/
|
|
1024
|
+
getLLMCacheStats() {
|
|
1025
|
+
return {
|
|
1026
|
+
size: this.llmCache.size,
|
|
1027
|
+
enabled: this.options.enableLLMCache
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* LLM 캐시를 초기화합니다.
|
|
1032
|
+
*/
|
|
1033
|
+
clearLLMCache() {
|
|
1034
|
+
this.llmCache.clear();
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* 컨텍스트 생성
|
|
1038
|
+
*/
|
|
1039
|
+
createContext() {
|
|
1040
|
+
return {
|
|
1041
|
+
fixtures: new Map(),
|
|
1042
|
+
referenceCache: new Map(),
|
|
1043
|
+
importedRecords: new Set()
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* 배치 생성 및 자동 저장
|
|
1048
|
+
*
|
|
1049
|
+
* 1. 각 spec별로 fixture 생성 (메모리)
|
|
1050
|
+
* 2. FixtureRecord로 변환
|
|
1051
|
+
* 3. FixtureManager.insertFixtures()로 targetDb에 저장
|
|
1052
|
+
*
|
|
1053
|
+
* @returns 저장된 fixture 데이터 (실제 DB ID 포함)
|
|
1054
|
+
*/
|
|
1055
|
+
async generateBatch(specs) {
|
|
1056
|
+
const context = this.createContext();
|
|
1057
|
+
const generatedFixtures = [];
|
|
1058
|
+
for (const spec of specs) {
|
|
1059
|
+
const specEntity = this.entityManager.get(spec.entity);
|
|
1060
|
+
if (specEntity.parentId) {
|
|
1061
|
+
const idProp = specEntity.props.find((p) => p.name === "id");
|
|
1062
|
+
const parentOverrides = idProp?.cone?.fixtureParentOverrides ?? {};
|
|
1063
|
+
const parentEntity = this.entityManager.get(specEntity.parentId);
|
|
1064
|
+
let query = this.sourceDb(parentEntity.table).select(`${parentEntity.table}.id`);
|
|
1065
|
+
for (const [col, val] of Object.entries(parentOverrides)) {
|
|
1066
|
+
query = query.where(`${parentEntity.table}.${col}`, val);
|
|
1067
|
+
}
|
|
1068
|
+
query = query.leftJoin(specEntity.table, `${specEntity.table}.id`, `${parentEntity.table}.id`).whereNull(`${specEntity.table}.id`).limit(spec.count);
|
|
1069
|
+
const rows = await query;
|
|
1070
|
+
const availableIds = rows.map((r) => r.id);
|
|
1071
|
+
if (availableIds.length === 0) {
|
|
1072
|
+
!isTest() && console.warn(chalk.yellow(`[parentId] ${spec.entity}: 서브타입이 없는 부모 레코드가 부족합니다. 건너뜁니다.`));
|
|
1073
|
+
} else {
|
|
1074
|
+
for (const parentId of availableIds) {
|
|
1075
|
+
const fixture = await this.generate(spec.entity, spec.overrides || {}, context);
|
|
1076
|
+
fixture.id = parentId;
|
|
1077
|
+
generatedFixtures.push({
|
|
1078
|
+
entity: spec.entity,
|
|
1079
|
+
data: fixture,
|
|
1080
|
+
explicitId: true
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} else {
|
|
1085
|
+
for (let i = 0; i < spec.count; i++) {
|
|
1086
|
+
const fixture = await this.generate(spec.entity, spec.overrides || {}, context);
|
|
1087
|
+
generatedFixtures.push({
|
|
1088
|
+
entity: spec.entity,
|
|
1089
|
+
data: fixture
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
const fixtureRecords = [];
|
|
1095
|
+
for (const { entity: entityName, data, explicitId } of generatedFixtures) {
|
|
1096
|
+
const entity = this.entityManager.get(entityName);
|
|
1097
|
+
const idProp = entity.props.find((p) => p.name === "id");
|
|
1098
|
+
const usesSequence = !explicitId && (idProp?.type === "integer" || idProp?.type === "bigInteger" || idProp?.cone?.fixtureStrategy === "sequence");
|
|
1099
|
+
const dataForRecord = usesSequence ? {
|
|
1100
|
+
...data,
|
|
1101
|
+
id: Math.floor(Math.random() * 1e6)
|
|
1102
|
+
} : data;
|
|
1103
|
+
const records = await FixtureManager.createFixtureRecord(entity, dataForRecord, { singleRecord: true });
|
|
1104
|
+
fixtureRecords.push(...records);
|
|
1105
|
+
}
|
|
1106
|
+
const results = await FixtureManager.insertFixtures(this.targetDbName, fixtureRecords);
|
|
1107
|
+
const companionResults = await this.generateCompanions(specs, results);
|
|
1108
|
+
const total = results.length + companionResults.length;
|
|
1109
|
+
!isTest() && console.log(chalk.green(`Generated and saved ${total} fixtures to ${this.targetDbName}`));
|
|
1110
|
+
return [...results, ...companionResults];
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* 부모 fixture 결과를 기반으로 fixtureCompanions에 선언된 companion Entity를 생성합니다.
|
|
1114
|
+
*
|
|
1115
|
+
* generateBatch()에서만 호출되며, companion 생성 시 재귀를 방지하기 위해
|
|
1116
|
+
* generateBatch()를 다시 호출하지 않고 직접 삽입합니다.
|
|
1117
|
+
*/
|
|
1118
|
+
async generateCompanions(specs, parentResults) {
|
|
1119
|
+
const allResults = [];
|
|
1120
|
+
const processedEntities = new Set();
|
|
1121
|
+
for (const spec of specs) {
|
|
1122
|
+
if (processedEntities.has(spec.entity)) continue;
|
|
1123
|
+
processedEntities.add(spec.entity);
|
|
1124
|
+
const entity = this.entityManager.get(spec.entity);
|
|
1125
|
+
const idProp = entity.props.find((p) => p.name === "id");
|
|
1126
|
+
const companions = idProp?.cone?.fixtureCompanions;
|
|
1127
|
+
if (!companions || companions.length === 0) continue;
|
|
1128
|
+
const entityResults = parentResults.filter((r) => r.entityId === spec.entity);
|
|
1129
|
+
if (entityResults.length === 0) continue;
|
|
1130
|
+
for (const companion of companions) {
|
|
1131
|
+
const companionEntity = this.entityManager.get(companion.entity);
|
|
1132
|
+
const fkProp = companionEntity.props.find((p) => isRelationProp(p) && isBelongsToOneRelationProp(p) && p.with === spec.entity);
|
|
1133
|
+
if (!fkProp) {
|
|
1134
|
+
!isTest() && console.warn(chalk.yellow(`[Companion] No BelongsToOne relation from ${companion.entity} to ${spec.entity}. Skipping.`));
|
|
1135
|
+
continue;
|
|
1136
|
+
}
|
|
1137
|
+
const fkColName = `${fkProp.name}_id`;
|
|
1138
|
+
const companionIdProp = companionEntity.props.find((p) => p.name === "id");
|
|
1139
|
+
const usesSequence = companionIdProp?.type === "integer" || companionIdProp?.type === "bigInteger" || companionIdProp?.cone?.fixtureStrategy === "sequence";
|
|
1140
|
+
const companionCount = companion.count ?? 1;
|
|
1141
|
+
const context = this.createContext();
|
|
1142
|
+
const companionFixtureRecords = [];
|
|
1143
|
+
for (const parentResult of entityResults) {
|
|
1144
|
+
const resolvedOverrides = this.resolveTemplateOverrides(companion.overrides ?? {}, parentResult.data);
|
|
1145
|
+
resolvedOverrides[fkColName] = parentResult.data.id;
|
|
1146
|
+
for (let i = 0; i < companionCount; i++) {
|
|
1147
|
+
const fixture = await this.generate(companion.entity, resolvedOverrides, context);
|
|
1148
|
+
const dataForRecord = usesSequence ? {
|
|
1149
|
+
...fixture,
|
|
1150
|
+
id: Math.floor(Math.random() * 1e6)
|
|
1151
|
+
} : fixture;
|
|
1152
|
+
const records = await FixtureManager.createFixtureRecord(companionEntity, dataForRecord, { singleRecord: true });
|
|
1153
|
+
companionFixtureRecords.push(...records);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
const companionResults = await FixtureManager.insertFixtures(this.targetDbName, companionFixtureRecords);
|
|
1157
|
+
allResults.push(...companionResults);
|
|
1158
|
+
!isTest() && console.log(chalk.green(`[Companion] Generated ${companionResults.length} ${companion.entity} fixtures`));
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return allResults;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* overrides 값의 "{{fieldName}}" 템플릿을 부모 fixture 데이터로 치환합니다.
|
|
1165
|
+
*
|
|
1166
|
+
* 예: { "account_id": "{{email}}" } → { "account_id": "user@example.com" }
|
|
1167
|
+
*/
|
|
1168
|
+
resolveTemplateOverrides(overrides, parentData) {
|
|
1169
|
+
const resolved = {};
|
|
1170
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
1171
|
+
if (typeof value === "string" && value.startsWith("{{") && value.endsWith("}}")) {
|
|
1172
|
+
const fieldName = value.slice(2, -2).trim();
|
|
1173
|
+
if (!(fieldName in parentData)) {
|
|
1174
|
+
throw new Error(`템플릿 필드 "${fieldName}"이(가) 부모 fixture 데이터에 존재하지 않습니다 (override key: "${key}")`);
|
|
1175
|
+
}
|
|
1176
|
+
resolved[key] = parentData[fieldName];
|
|
1177
|
+
} else {
|
|
1178
|
+
resolved[key] = value;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
return resolved;
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* 실제 DB(sourceDb)에서 데이터를 조회하여 fixture DB(targetDb)에 import합니다.
|
|
1185
|
+
*
|
|
1186
|
+
* 1. DataExplorer로 sourceDb에서 데이터 조회 (관련 데이터 포함)
|
|
1187
|
+
* 2. FixtureRecord로 변환
|
|
1188
|
+
* 3. targetDb에 삽입
|
|
1189
|
+
*
|
|
1190
|
+
* @param entityName - 조회할 entity 이름
|
|
1191
|
+
* @param options - 조회 옵션 (strategy, limit, includeRelations 등)
|
|
1192
|
+
* @returns 저장된 fixture 데이터 (실제 DB ID 포함)
|
|
1193
|
+
*
|
|
1194
|
+
* @example
|
|
1195
|
+
* // 프로덕션 DB에서 User 10명 + 관련 Employee, Department 가져오기
|
|
1196
|
+
* await generator.importFromSource("User", {
|
|
1197
|
+
* strategy: "sample",
|
|
1198
|
+
* limit: 10,
|
|
1199
|
+
* includeRelations: true,
|
|
1200
|
+
* maxDepth: 2
|
|
1201
|
+
* });
|
|
1202
|
+
*/
|
|
1203
|
+
async importFromSource(entityName, options) {
|
|
1204
|
+
!isTest() && console.log(chalk.blue(`Importing ${entityName} from source DB with options: ${JSON.stringify({
|
|
1205
|
+
strategy: options.strategy,
|
|
1206
|
+
limit: options.limit,
|
|
1207
|
+
includeRelations: options.includeRelations,
|
|
1208
|
+
maxDepth: options.maxDepth
|
|
1209
|
+
})}`));
|
|
1210
|
+
const exploreResult = await this.dataExplorer.exploreWithRelations(entityName, options);
|
|
1211
|
+
!isTest() && console.log(chalk.cyan(`Found ${exploreResult.main.records.length} ${entityName} records and ${exploreResult.related.size} related entities`));
|
|
1212
|
+
const fixtureRecords = [];
|
|
1213
|
+
const mainEntity = this.entityManager.get(entityName);
|
|
1214
|
+
for (const record of exploreResult.main.records) {
|
|
1215
|
+
const records = await FixtureManager.createFixtureRecord(mainEntity, record, {
|
|
1216
|
+
_db: this.sourceDb,
|
|
1217
|
+
singleRecord: true
|
|
1218
|
+
});
|
|
1219
|
+
fixtureRecords.push(...records);
|
|
1220
|
+
}
|
|
1221
|
+
for (const [relatedEntityName, relatedRecords] of exploreResult.related.entries()) {
|
|
1222
|
+
const relatedEntity = this.entityManager.get(relatedEntityName);
|
|
1223
|
+
for (const record of relatedRecords) {
|
|
1224
|
+
const records = await FixtureManager.createFixtureRecord(relatedEntity, record, {
|
|
1225
|
+
_db: this.sourceDb,
|
|
1226
|
+
singleRecord: true
|
|
1227
|
+
});
|
|
1228
|
+
fixtureRecords.push(...records);
|
|
1229
|
+
}
|
|
1230
|
+
!isTest() && console.log(chalk.gray(` - ${relatedEntityName}: ${relatedRecords.length} records`));
|
|
1231
|
+
}
|
|
1232
|
+
const results = await FixtureManager.insertFixtures(this.targetDbName, fixtureRecords);
|
|
1233
|
+
!isTest() && console.log(chalk.green(`Successfully imported ${results.length} records to ${this.targetDbName} (${exploreResult.main.records.length} ${entityName} + ${results.length - exploreResult.main.records.length} related)`));
|
|
1234
|
+
return results;
|
|
1235
|
+
}
|
|
1236
|
+
};
|
|
1237
|
+
}));
|
|
1371
1238
|
|
|
1372
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2ZpeHR1cmUtZ2VuZXJhdG9yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB0eXBlIHsgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgdHlwZSB7IEVudGl0eSB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5XCI7XG5pbXBvcnQgdHlwZSB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgdHlwZSB7IEVudGl0eVByb3AsIEZpeHR1cmVJbXBvcnRSZXN1bHQsIEZpeHR1cmVSZWNvcmQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wLCBpc09uZVRvT25lUmVsYXRpb25Qcm9wLCBpc1JlbGF0aW9uUHJvcCB9IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgaXNUZXN0IH0gZnJvbSBcIi4uL3V0aWxzL2NvbnRyb2xsZXJcIjtcbmltcG9ydCB7XG4gIERhdGFFeHBsb3JlcixcbiAgdHlwZSBFeHBsb3JlV2l0aFJlbGF0aW9uc09wdGlvbnMsXG4gIHR5cGUgRXhwbG9yZVdpdGhSZWxhdGlvbnNSZXN1bHQsXG59IGZyb20gXCIuL2RhdGEtZXhwbG9yZXJcIjtcbmltcG9ydCB7IHR5cGUgRmFrZXJNYXBwaW5ncywgZmFrZXJNYXBwaW5ncyB9IGZyb20gXCIuL2Zha2VyLW1hcHBpbmdzXCI7XG5pbXBvcnQgeyBGaXh0dXJlTWFuYWdlciB9IGZyb20gXCIuL2ZpeHR1cmUtbWFuYWdlclwiO1xuXG5leHBvcnQgdHlwZSBMb2NhbGUgPSBcImtvXCIgfCBcImVuXCIgfCBcImphXCI7XG5cbmV4cG9ydCB0eXBlIEZpeHR1cmVHZW5lcmF0b3JPcHRpb25zID0ge1xuICBsb2NhbGU/OiBMb2NhbGU7XG4gIHVzZUxMTT86IGJvb2xlYW47XG4gIGVuYWJsZUxMTUNhY2hlPzogYm9vbGVhbjtcbiAgbGxtTW9kZWw/OiBzdHJpbmc7XG59O1xuXG5leHBvcnQgdHlwZSBHZW5lcmF0b3JDb250ZXh0ID0ge1xuICAvKiog7IOd7ISxIOykkeyduCBmaXh0dXJl65OkICjrqZTrqqjrpqwg7IOBKSAqL1xuICBmaXh0dXJlczogTWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj4+O1xuXG4gIC8qKiDssLjsobAg642w7J207YSwIOy6kOyLnCAoRGF0YUV4cGxvcmVyIOqysOqzvCkgKi9cbiAgcmVmZXJlbmNlQ2FjaGU6IE1hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+O1xuXG4gIC8qKiDsnbTrr7ggaW1wb3J065CcIOugiOy9lOuTnOulvCDstpTsoIHtlZjsl6wg7KSR67O1IGltcG9ydOulvCDrsKnsp4Dtlanri4jri6QgKi9cbiAgaW1wb3J0ZWRSZWNvcmRzOiBTZXQ8c3RyaW5nPjsgLy8gXCJVc2VyIzEyM1wiXG59O1xuXG5leHBvcnQgY2xhc3MgRml4dHVyZUdlbmVyYXRvciB7XG4gIHByaXZhdGUgZGF0YUV4cGxvcmVyOiBEYXRhRXhwbG9yZXI7XG4gIHByaXZhdGUgbG9jYWxlOiBMb2NhbGU7XG4gIHByaXZhdGUgbWFwcGluZ3M6IEZha2VyTWFwcGluZ3M7XG4gIHByaXZhdGUgbGxtQ2FjaGU6IE1hcDxzdHJpbmcsIHVua25vd24+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIGVudGl0eUNhY2hlOiBNYXA8c3RyaW5nLCBFbnRpdHk+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIG9wdGlvbnM6IEZpeHR1cmVHZW5lcmF0b3JPcHRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc291cmNlRGI6IEtuZXgsXG4gICAgLy8gRml4dHVyZU1hbmFnZXIuaW5zZXJ0Rml4dHVyZXPqsIAgZGJOYW1lIOusuOyekOyXtOydhCDrsJvquLAg65WM66y47JeQIOyngeygkSDsgqzsmqntlZjsp4Ag7JWK7Iq164uI64ukXG4gICAgLy8g66+4656YIO2ZleyepeyEseydhCDsnITtlbQgQVBJIOyLnOq3uOuLiOyymOyXkOuKlCDtj6ztlajsi5zsvLDsirXri4jri6RcbiAgICBfdGFyZ2V0RGI6IEtuZXgsXG4gICAgcHJpdmF0ZSB0YXJnZXREYk5hbWU6IFwiZml4dHVyZVwiIHwgXCJ0ZXN0XCIgfCBcInByb2R1Y3Rpb25fbWFzdGVyXCIsXG4gICAgcHJpdmF0ZSBlbnRpdHlNYW5hZ2VyOiB0eXBlb2YgRW50aXR5TWFuYWdlcixcbiAgICBvcHRpb25zPzogRml4dHVyZUdlbmVyYXRvck9wdGlvbnMsXG4gICkge1xuICAgIHRoaXMuZGF0YUV4cGxvcmVyID0gbmV3IERhdGFFeHBsb3Jlcihzb3VyY2VEYiwgZW50aXR5TWFuYWdlcik7XG4gICAgdGhpcy5sb2NhbGUgPSBvcHRpb25zPy5sb2NhbGUgfHwgXCJrb1wiO1xuICAgIHRoaXMubWFwcGluZ3MgPSBmYWtlck1hcHBpbmdzO1xuICAgIHRoaXMub3B0aW9ucyA9IHtcbiAgICAgIGxvY2FsZTogb3B0aW9ucz8ubG9jYWxlIHx8IFwia29cIixcbiAgICAgIHVzZUxMTTogb3B0aW9ucz8udXNlTExNIHx8IGZhbHNlLFxuICAgICAgZW5hYmxlTExNQ2FjaGU6IG9wdGlvbnM/LmVuYWJsZUxMTUNhY2hlICE9PSBmYWxzZSxcbiAgICAgIGxsbU1vZGVsOiBvcHRpb25zPy5sbG1Nb2RlbCB8fCBcImNsYXVkZS1zb25uZXQtNC02XCIsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaXh0dXJlIOyDneyEsSAo64uo7J28KVxuICAgKiBAcmV0dXJucyDsg53shLHrkJwgZml4dHVyZSDrjbDsnbTthLAgKOuplOuqqOumrCDsg4EpXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZShcbiAgICBlbnRpdHlOYW1lOiBzdHJpbmcsXG4gICAgb3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9LFxuICAgIGNvbnRleHQ6IEdlbmVyYXRvckNvbnRleHQgPSB0aGlzLmNyZWF0ZUNvbnRleHQoKSxcbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICAgIC8vIEVudGl0eSDsupDsi7E6IO2FjOyKpO2KuOyXkOyEnCBlbnRpdHkgY29uZSDsiJjsoJXsnbQg67CY7JiB65CY64+E66GdIOuztOyepVxuICAgIGxldCBlbnRpdHkgPSB0aGlzLmVudGl0eUNhY2hlLmdldChlbnRpdHlOYW1lKTtcbiAgICBpZiAoIWVudGl0eSkge1xuICAgICAgZW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlOYW1lKTtcbiAgICAgIHRoaXMuZW50aXR5Q2FjaGUuc2V0KGVudGl0eU5hbWUsIGVudGl0eSk7XG4gICAgfVxuXG4gICAgY29uc3QgdGVtcElkID0gYCR7ZW50aXR5TmFtZX0jdGVtcCMke0RhdGUubm93KCl9YDsgLy8g7J6E7IucIElEXG5cbiAgICAvLyBMTE0gcm93IOuLqOychCDsg53shLHsnYQg7JyE7ZWcIOqzoOycoCDtgqQgKOqwmeydgCByb3fsnZgg7ZWE65Oc65Ok7J20IOuPmeydvO2VnCByb3dLZXnrpbwg6rO17JygKVxuICAgIGNvbnN0IHJvd0tleSA9IHRoaXMub3B0aW9ucy51c2VMTE0gPyBgJHtlbnRpdHlOYW1lfSNyb3cjJHtEYXRlLm5vdygpfWAgOiB1bmRlZmluZWQ7XG5cbiAgICAvLyDqsIEgcHJvcOuzhCDqsJIg7IOd7ISxXG4gICAgY29uc3QgZml4dHVyZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcblxuICAgIGZvciAoY29uc3QgcHJvcCBvZiBlbnRpdHkucHJvcHMpIHtcbiAgICAgIC8vIFZpcnR1YWwgcHJvcOydgCDsiqTtgrVcbiAgICAgIGlmIChcInZpcnR1YWxcIiBpbiBwcm9wICYmIHByb3AudmlydHVhbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gaWQgcHJvcCDsspjrpqxcbiAgICAgIGlmIChwcm9wLm5hbWUgPT09IFwiaWRcIikge1xuICAgICAgICBpZiAoXCJjb25lXCIgaW4gcHJvcCAmJiBwcm9wLmNvbmU/LmZpeHR1cmVTdHJhdGVneSA9PT0gXCJzZXF1ZW5jZVwiKSB7XG4gICAgICAgICAgLy8gREIgc2VxdWVuY2XqsIAg7J6Q64+ZIO2VoOuLue2VmOuvgOuhnCDsiqTtgrUgKFVzZXIg65OxKVxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwcm9wLnR5cGUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAvLyBEQiBERUZBVUxUIOyXhuuKlCBzdHJpbmcgUEs6IGFscGhhbnVtZXJpYyAzMuyekCDsg53shLEgKGJldHRlci1hdXRoIOyKpO2DgOydvClcbiAgICAgICAgICBjb25zdCB7IGZha2VyOiBfZmFrZXIgfSA9IGF3YWl0IGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKTtcbiAgICAgICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBfZmFrZXIuc3RyaW5nLmFscGhhbnVtZXJpYygzMik7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHByb3AudHlwZSA9PT0gXCJ1dWlkXCIpIHtcbiAgICAgICAgICBjb25zdCB7IGZha2VyOiBfZmFrZXIgfSA9IGF3YWl0IGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKTtcbiAgICAgICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBfZmFrZXIuc3RyaW5nLnV1aWQoKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBpbnRlZ2VyL2JpZ0ludGVnZXIgUEs6IGdlbmVyYXRlQmF0Y2jsl5DshJwgdGVtcElk66W8IOuEo+ycvOuvgOuhnCDsl6zquLDshKAg7Iqk7YK1XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBvdmVycmlkZeqwgCDsnojsnLzrqbQg7IKs7JqpXG4gICAgICBpZiAocHJvcC5uYW1lIGluIG92ZXJyaWRlcykge1xuICAgICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBvdmVycmlkZXNbcHJvcC5uYW1lXTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIGNvbmXsl5DshJwg7IOd7ISxIOyghOuetSDtmZXsnbhcbiAgICAgIGNvbnN0IGNvbmUgPSBwcm9wLmNvbmU7XG5cbiAgICAgIC8vIDEuIFJlbGF0aW9uIHByb3Ag7LKY66asXG4gICAgICBpZiAoaXNSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgLy8gQmVsb25nc1RvT25lIC8gT25lVG9PbmUoaGFzSm9pbkNvbHVtbinsnYAgRksg7Lus65+866qFKHtwcm9wLm5hbWV9X2lkKeycvOuhnOuPhCBvdmVycmlkZeulvCDrsJvripTri6RcbiAgICAgICAgY29uc3QgZmtDb2xOYW1lID0gYCR7cHJvcC5uYW1lfV9pZGA7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBma0NvbE5hbWUgaW4gb3ZlcnJpZGVzICYmXG4gICAgICAgICAgKGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHByb3ApIHx8IChpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbikpXG4gICAgICAgICkge1xuICAgICAgICAgIGZpeHR1cmVbZmtDb2xOYW1lXSA9IG92ZXJyaWRlc1tma0NvbE5hbWVdO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVsYXRpb25WYWx1ZSA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVSZWxhdGlvblZhbHVlKGVudGl0eSwgcHJvcCwgY29udGV4dCk7XG4gICAgICAgIC8vIEJlbG9uZ3NUb09uZSwgT25lVG9PbmUoaGFzSm9pbkNvbHVtbinsnZgg6rK97JqwIGZvcmVpZ24ga2V5IOy7rOufvOuqheycvOuhnCDsoIDsnqVcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHByb3ApIHx8XG4gICAgICAgICAgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocHJvcCkgJiYgcHJvcC5oYXNKb2luQ29sdW1uKVxuICAgICAgICApIHtcbiAgICAgICAgICBmaXh0dXJlW2Ake3Byb3AubmFtZX1faWRgXSA9IHJlbGF0aW9uVmFsdWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gcmVsYXRpb25WYWx1ZTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gMi4gY29uZS5ub3RlICsgTExNIOyCrOyaqSAodXNlTExN7J2066m0IGZpeHR1cmVHZW5lcmF0b3Lrs7Tri6Qg7Jqw7ISgKVxuICAgICAgaWYgKGNvbmU/Lm5vdGUgJiYgdGhpcy5vcHRpb25zLnVzZUxMTSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGxsbVZhbHVlID0gYXdhaXQgdGhpcy5nZW5lcmF0ZVdpdGhMTE0oY29uZS5ub3RlLCBwcm9wLCBlbnRpdHksIHJvd0tleSk7XG4gICAgICAgICAgLy8gc3RyaW5nIO2DgOyeheydtOqzoCBsZW5ndGgg7KCc7JW97J20IOyeiOycvOuptCDstIjqs7wg7IucIHRydW5jYXRpb25cbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICB0eXBlb2YgbGxtVmFsdWUgPT09IFwic3RyaW5nXCIgJiZcbiAgICAgICAgICAgIFwibGVuZ3RoXCIgaW4gcHJvcCAmJlxuICAgICAgICAgICAgdHlwZW9mIHByb3AubGVuZ3RoID09PSBcIm51bWJlclwiICYmXG4gICAgICAgICAgICBsbG1WYWx1ZS5sZW5ndGggPiBwcm9wLmxlbmd0aFxuICAgICAgICAgICkge1xuICAgICAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gbGxtVmFsdWUuc2xpY2UoMCwgcHJvcC5sZW5ndGgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBsbG1WYWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgYFtGaXh0dXJlR2VuZXJhdG9yXSBMTE0gZ2VuZXJhdGlvbiBmYWlsZWQgZm9yICR7ZW50aXR5LmlkfS4ke3Byb3AubmFtZX0sIGZhbGxpbmcgYmFjayB0byBmaXh0dXJlR2VuZXJhdG9yIG9yIGRlZmF1bHRgLFxuICAgICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBlcnJvcixcbiAgICAgICAgICApO1xuICAgICAgICAgIC8vIGZhbGxiYWNrOiBmaXh0dXJlR2VuZXJhdG9yIOKGkiBmaXh0dXJlRGVmYXVsdCDihpIg6riw67O46rCS7Jy866GcIOqzhOyGjVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIDMuIGZpeHR1cmVHZW5lcmF0b3Ig7IKs7JqpXG4gICAgICBpZiAoY29uZT8uZml4dHVyZUdlbmVyYXRvcikge1xuICAgICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBhd2FpdCB0aGlzLmV4ZWN1dGVHZW5lcmF0b3IoXG4gICAgICAgICAgY29uZS5maXh0dXJlR2VuZXJhdG9yIGFzIHN0cmluZyxcbiAgICAgICAgICBwcm9wLFxuICAgICAgICAgIGVudGl0eSxcbiAgICAgICAgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIDQuIGZpeHR1cmVEZWZhdWx0IOyCrOyaqVxuICAgICAgaWYgKGNvbmU/LmZpeHR1cmVEZWZhdWx0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gY29uZS5maXh0dXJlRGVmYXVsdDtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIDUuIO2DgOyeheuzhCDquLDrs7gg7IOd7ISxXG4gICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBhd2FpdCB0aGlzLmdlbmVyYXRlRGVmYXVsdFZhbHVlKHByb3AsIGVudGl0eSk7XG4gICAgfVxuXG4gICAgLy8gNi4gZW1haWwg7ZWE65Oc6rCAIOyeiOqzoCBuYW1lIO2VhOuTnOqwgCDsnojsnLzrqbQsIGVtYWls7J2YIOuhnOy7rCDtjIztirjrpbwgbmFtZSDquLDrsJjsnLzroZwg67O07KCVXG4gICAgaWYgKFwiZW1haWxcIiBpbiBmaXh0dXJlICYmIHR5cGVvZiBmaXh0dXJlLmVtYWlsID09PSBcInN0cmluZ1wiICYmICEoXCJlbWFpbFwiIGluIG92ZXJyaWRlcykpIHtcbiAgICAgIGNvbnN0IG5hbWVWYWx1ZSA9IGZpeHR1cmUubmFtZSB8fCBmaXh0dXJlLnVzZXJuYW1lIHx8IGZpeHR1cmUuZnVsbF9uYW1lIHx8IGZpeHR1cmUubmFtZV9lbjtcbiAgICAgIGlmIChuYW1lVmFsdWUgJiYgdHlwZW9mIG5hbWVWYWx1ZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBjb25zdCBkb21haW4gPSBmaXh0dXJlLmVtYWlsLnNwbGl0KFwiQFwiKVsxXSB8fCBcImV4YW1wbGUuY29tXCI7XG4gICAgICAgIGNvbnN0IHJvbWFuaXplZCA9IGF3YWl0IHRoaXMucm9tYW5pemVOYW1lKG5hbWVWYWx1ZSk7XG4gICAgICAgIGZpeHR1cmUuZW1haWwgPSBgJHtyb21hbml6ZWR9QCR7ZG9tYWlufWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gNy4gcGFzc3dvcmQg7ZWE65OcIOyVlO2YuO2ZlFxuICAgIGlmIChcInBhc3N3b3JkXCIgaW4gZml4dHVyZSAmJiBmaXh0dXJlLnBhc3N3b3JkICYmIHR5cGVvZiBmaXh0dXJlLnBhc3N3b3JkID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBjb25zdCBiY3J5cHQgPSBhd2FpdCBpbXBvcnQoXCJiY3J5cHRcIik7XG4gICAgICBmaXh0dXJlLnBhc3N3b3JkID0gYXdhaXQgYmNyeXB0Lmhhc2goZml4dHVyZS5wYXNzd29yZCwgMTApO1xuICAgIH1cblxuICAgIGNvbnRleHQuZml4dHVyZXMuc2V0KHRlbXBJZCwgZml4dHVyZSk7XG4gICAgcmV0dXJuIGZpeHR1cmU7XG4gIH1cblxuICAvKipcbiAgICogUmVsYXRpb24g6rCSIOyDneyEsSArIOyekOuPmSBJbXBvcnRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVSZWxhdGlvblZhbHVlKFxuICAgIGVudGl0eTogRW50aXR5LFxuICAgIHByb3A6IEVudGl0eVByb3AsXG4gICAgY29udGV4dDogR2VuZXJhdG9yQ29udGV4dCxcbiAgKTogUHJvbWlzZTxudW1iZXIgfCBudWxsPiB7XG4gICAgaWYgKCFpc1JlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaXh0dXJlR2VuZXJhdG9yOiAke2VudGl0eS5pZH0uJHtwcm9wLm5hbWV9IGlzIG5vdCBhIHJlbGF0aW9uIHByb3BgKTtcbiAgICB9XG5cbiAgICAvLyBCZWxvbmdzVG9PbmUsIE9uZVRvT25lKGhhc0pvaW5Db2x1bW4p66eMIOyymOumrFxuICAgIGlmIChcbiAgICAgICFpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSAmJlxuICAgICAgIShpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbilcbiAgICApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbmUgPSBwcm9wLmNvbmU7XG4gICAgY29uc3QgZGF0YVNvdXJjZSA9IGNvbmU/LmRhdGFTb3VyY2U7XG5cbiAgICAvLyBEYXRhRXhwbG9yZXLroZwg7LC47KGwIOuNsOydtO2EsCDsobDtmowgKHNvdXJjZURiKVxuICAgIC8vIOq0gOqzhCDssrTsnbjsnYQg65Sw65286rCA6riwIOychO2VtCBleHBsb3JlV2l0aFJlbGF0aW9ucyDsgqzsmqlcbiAgICBpZiAoZGF0YVNvdXJjZSkge1xuICAgICAgY29uc3QgY2FjaGVLZXkgPSBgJHtwcm9wLndpdGh9OiR7SlNPTi5zdHJpbmdpZnkoZGF0YVNvdXJjZSl9YDtcblxuICAgICAgaWYgKCFjb250ZXh0LnJlZmVyZW5jZUNhY2hlLmhhcyhjYWNoZUtleSkpIHtcbiAgICAgICAgY29uc3QgZXhwbG9yZVJlc3VsdCA9IGF3YWl0IHRoaXMuZGF0YUV4cGxvcmVyLmV4cGxvcmVXaXRoUmVsYXRpb25zKHByb3Aud2l0aCwge1xuICAgICAgICAgIHN0cmF0ZWd5OiBkYXRhU291cmNlLnN0cmF0ZWd5LFxuICAgICAgICAgIGxpbWl0OlxuICAgICAgICAgICAgKChkYXRhU291cmNlLmNvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCk/LmxpbWl0IGFzXG4gICAgICAgICAgICAgIHwgbnVtYmVyXG4gICAgICAgICAgICAgIHwgdW5kZWZpbmVkKSB8fCAxMCxcbiAgICAgICAgICBpbmNsdWRlUmVsYXRpb25zOiB0cnVlLFxuICAgICAgICAgIG1heERlcHRoOiAzLFxuICAgICAgICAgIC4uLihkYXRhU291cmNlLmNvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCksXG4gICAgICAgIH0pO1xuICAgICAgICBjb250ZXh0LnJlZmVyZW5jZUNhY2hlLnNldChjYWNoZUtleSwgZXhwbG9yZVJlc3VsdC5tYWluLnJlY29yZHMpO1xuXG4gICAgICAgIC8vIOyhsO2ajO2VnCDrjbDsnbTthLDsmYAg6rSA6rOE65CcIOuqqOuToCDsl5Tti7Dti7DrpbwgdGFyZ2V0RGLsl5AgaW1wb3J0XG4gICAgICAgIGF3YWl0IHRoaXMuaW1wb3J0RXhwbG9yZVJlc3VsdChleHBsb3JlUmVzdWx0LCBjb250ZXh0KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY2FuZGlkYXRlcyA9IGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICAgIGlmIChjYW5kaWRhdGVzICYmIGNhbmRpZGF0ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAvLyDrnpzrjaTtlZjqsowg7ZWY64KYIOyEoO2DnVxuICAgICAgICBjb25zdCBzZWxlY3RlZCA9IGNhbmRpZGF0ZXNbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogY2FuZGlkYXRlcy5sZW5ndGgpXTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdGVkLmlkIGFzIG51bWJlcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBkYXRhU291cmNl6rCAIOyXhuydhCDrlYwg7J6Q64+Z7Jy866GcIGZpeHR1cmUgRELsl5DshJwg7KGw7ZqMIOyLnOuPhFxuICAgIC8vIOq0gOqzhCDssrTsnbjsnYQg65Sw65286rCA6riwIOychO2VtCBleHBsb3JlV2l0aFJlbGF0aW9ucyDsgqzsmqlcbiAgICBjb25zdCBhdXRvS2V5ID0gYCR7cHJvcC53aXRofTphdXRvYDtcbiAgICBpZiAoIWNvbnRleHQucmVmZXJlbmNlQ2FjaGUuaGFzKGF1dG9LZXkpKSB7XG4gICAgICAvLyBmaXh0dXJlIERCKHNvdXJjZURiKeyXkOyEnCDsnpDrj5kg7KGw7ZqMICjqtIDqs4Qg7Y+s7ZWoKVxuICAgICAgY29uc3QgYXV0b0V4cGxvcmVSZXN1bHQgPSBhd2FpdCB0aGlzLmRhdGFFeHBsb3Jlci5leHBsb3JlV2l0aFJlbGF0aW9ucyhwcm9wLndpdGgsIHtcbiAgICAgICAgc3RyYXRlZ3k6IFwicmFuZG9tXCIsXG4gICAgICAgIGxpbWl0OiAxMCxcbiAgICAgICAgaW5jbHVkZVJlbGF0aW9uczogdHJ1ZSxcbiAgICAgICAgbWF4RGVwdGg6IDMsXG4gICAgICB9KTtcbiAgICAgIGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuc2V0KGF1dG9LZXksIGF1dG9FeHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcyk7XG5cbiAgICAgIC8vIOyhsO2ajO2VnCDrjbDsnbTthLDsmYAg6rSA6rOE65CcIOuqqOuToCDsl5Tti7Dti7DrpbwgdGFyZ2V0RGLsl5AgaW1wb3J0XG4gICAgICBpZiAoYXV0b0V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbXBvcnRFeHBsb3JlUmVzdWx0KGF1dG9FeHBsb3JlUmVzdWx0LCBjb250ZXh0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBhdXRvQ2FuZGlkYXRlcyA9IGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuZ2V0KGF1dG9LZXkpO1xuICAgIGlmIChhdXRvQ2FuZGlkYXRlcyAmJiBhdXRvQ2FuZGlkYXRlcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyDrnpzrjaTtlZjqsowg7ZWY64KYIOyEoO2DnVxuICAgICAgY29uc3Qgc2VsZWN0ZWQgPSBhdXRvQ2FuZGlkYXRlc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBhdXRvQ2FuZGlkYXRlcy5sZW5ndGgpXTtcbiAgICAgIHJldHVybiBzZWxlY3RlZC5pZCBhcyBudW1iZXI7XG4gICAgfVxuXG4gICAgLy8g7LC47KGwIOuNsOydtO2EsOqwgCDsl4bsnLzrqbQgbnVsbCDrsJjtmZggKG51bGxhYmxl7J24IOqyveyasClcbiAgICBpZiAocHJvcC5udWxsYWJsZSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gbnVsbGFibGXsnbQg7JWE64uI6rOgIOuNsOydtO2EsOuPhCDsl4bsnLzrqbQg7JeQ65+sXG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEZpeHR1cmVHZW5lcmF0b3I6ICR7ZW50aXR5LmlkfS4ke3Byb3AubmFtZX3sl5Ag7ZWE7JqU7ZWcICR7cHJvcC53aXRofSDrjbDsnbTthLDqsIAg7JeG7Iq164uI64ukLiBgICtcbiAgICAgICAgYOuovOyggCAke3Byb3Aud2l0aH3rpbwg7IOd7ISx7ZWY6rGw64KYIGNvbmUuZGF0YVNvdXJjZeulvCDshKTsoJXtlZjshLjsmpQuYCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxvcmVXaXRoUmVsYXRpb25zIOqysOqzvOulvCB0YXJnZXREYuyXkCBpbXBvcnRcbiAgICpcbiAgICog6rSA6rOEIOyytOyduOydhCDrlLDrnbzqsIQg6rKw6rO8KG1haW4gKyByZWxhdGVkKeulvCDrqqjrkZAgaW1wb3J07ZWp64uI64ukLlxuICAgKiDsnZjsobTshLEg7Iic7ISc64qUIEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVz6rCAIOyekOuPmeycvOuhnCDsspjrpqztlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGltcG9ydEV4cGxvcmVSZXN1bHQoXG4gICAgZXhwbG9yZVJlc3VsdDogRXhwbG9yZVdpdGhSZWxhdGlvbnNSZXN1bHQsXG4gICAgY29udGV4dDogR2VuZXJhdG9yQ29udGV4dCxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYWxsRml4dHVyZVJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSA9IFtdO1xuXG4gICAgLy8gMS4gUmVsYXRlZCBlbnRpdGllcyBpbXBvcnQgKENvbXBhbnksIERlcGFydG1lbnQg65OxKVxuICAgIGZvciAoY29uc3QgW2VudGl0eUlkLCByZWNvcmRzXSBvZiBleHBsb3JlUmVzdWx0LnJlbGF0ZWQuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICAgIGNvbnN0IHJlY29yZHNUb0ltcG9ydDogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSA9IFtdO1xuXG4gICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgY2hhbGsuY3lhbihgSW1wb3J0aW5nIHJlbGF0ZWQgZW50aXR5OiAke2VudGl0eUlkfSAoJHtyZWNvcmRzLmxlbmd0aH0gcmVjb3JkcylgKSxcbiAgICAgICAgKTtcblxuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgcmVjb3Jkcykge1xuICAgICAgICBjb25zdCByZWNvcmRLZXkgPSBgJHtlbnRpdHlJZH0jJHtyZWNvcmQuaWR9YDtcbiAgICAgICAgaWYgKCFjb250ZXh0LmltcG9ydGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgICAgIHJlY29yZHNUb0ltcG9ydC5wdXNoKHJlY29yZCk7XG4gICAgICAgICAgY29udGV4dC5pbXBvcnRlZFJlY29yZHMuYWRkKHJlY29yZEtleSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHJlY29yZHNUb0ltcG9ydC5sZW5ndGggPiAwKSB7XG4gICAgICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIHJlY29yZHNUb0ltcG9ydCkge1xuICAgICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgIGNoYWxrLmdyYXkoXG4gICAgICAgICAgICAgICAgYCAgLSBQcm9jZXNzaW5nICR7ZW50aXR5SWR9IHJlY29yZDpgLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHJlY29yZCkuc2xpY2UoMCwgMTAwKSxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgZml4dHVyZVJlY29yZHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5jcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgICAgICAgICAgZW50aXR5LFxuICAgICAgICAgICAgcmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgICAgIHsgX2RiOiB0aGlzLnNvdXJjZURiLCBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGFsbEZpeHR1cmVSZWNvcmRzLnB1c2goLi4uZml4dHVyZVJlY29yZHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMi4gTWFpbiBlbnRpdHkgaW1wb3J0IChFbXBsb3llZSDrk7EpXG4gICAgY29uc3QgbWFpbkVudGl0eSA9IHRoaXMuZW50aXR5TWFuYWdlci5nZXQoZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkKTtcbiAgICBjb25zdCBtYWluUmVjb3Jkc1RvSW1wb3J0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdID0gW107XG5cbiAgICAhaXNUZXN0KCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay5jeWFuKFxuICAgICAgICAgIGBJbXBvcnRpbmcgbWFpbiBlbnRpdHk6ICR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSAoJHtleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcy5sZW5ndGh9IHJlY29yZHMpYCxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcykge1xuICAgICAgY29uc3QgcmVjb3JkS2V5ID0gYCR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSMke3JlY29yZC5pZH1gO1xuICAgICAgaWYgKCFjb250ZXh0LmltcG9ydGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgICBtYWluUmVjb3Jkc1RvSW1wb3J0LnB1c2gocmVjb3JkKTtcbiAgICAgICAgY29udGV4dC5pbXBvcnRlZFJlY29yZHMuYWRkKHJlY29yZEtleSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1haW5SZWNvcmRzVG9JbXBvcnQubGVuZ3RoID4gMCkge1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgbWFpblJlY29yZHNUb0ltcG9ydCkge1xuICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgIGNoYWxrLmdyYXkoXG4gICAgICAgICAgICAgIGAgIC0gUHJvY2Vzc2luZyAke2V4cGxvcmVSZXN1bHQubWFpbi5lbnRpdHlJZH0gcmVjb3JkOmAsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHJlY29yZCkuc2xpY2UoMCwgMTAwKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgZml4dHVyZVJlY29yZHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5jcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgICAgICAgIG1haW5FbnRpdHksXG4gICAgICAgICAgcmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgICB7IF9kYjogdGhpcy5zb3VyY2VEYiwgc2luZ2xlUmVjb3JkOiB0cnVlIH0sXG4gICAgICAgICk7XG4gICAgICAgIGFsbEZpeHR1cmVSZWNvcmRzLnB1c2goLi4uZml4dHVyZVJlY29yZHMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDMuIOuqqOuToCBmaXh0dXJl66W8IO2VnCDrsojsl5Ag7IK97J6FICjsnZjsobTshLEg7Iic7IScIOyekOuPmSDsspjrpqwpXG4gICAgaWYgKGFsbEZpeHR1cmVSZWNvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVzKHRoaXMudGFyZ2V0RGJOYW1lLCBhbGxGaXh0dXJlUmVjb3Jkcyk7XG5cbiAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5ncmVlbihcbiAgICAgICAgICAgIGBBdXRvLWltcG9ydGVkICR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSB3aXRoIHJlbGF0aW9uczogYCArXG4gICAgICAgICAgICAgIGAke2V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aH0gbWFpbiArICR7ZXhwbG9yZVJlc3VsdC5yZWxhdGVkLnNpemV9IHJlbGF0ZWQgZW50aXRpZXNgLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIGZpeHR1cmVHZW5lcmF0b3Ig7Iuk7ZaJIChGYWtlci5qc+unjCDsp4Dsm5ApXG4gICAqXG4gICAqIGZha2VyLiog7ZiV7Iud7J2YIO2RnO2YhOyLneydhCDslYjsoITtlZjqsowg7YyM7Iux7ZWY7JesIOyLpO2Wie2VqeuLiOuLpC5cbiAgICog7JiIOiBcImZha2VyLmludGVybmV0LmVtYWlsKClcIiDihpIgZmFrZXIuaW50ZXJuZXQuZW1haWwoKVxuICAgKiDsmIg6IFwiZmFrZXIubG9yZW0ud29yZHMoMylcIiDihpIgZmFrZXIubG9yZW0ud29yZHMoMylcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXhlY3V0ZUdlbmVyYXRvcihcbiAgICBnZW5lcmF0b3I6IHN0cmluZyxcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIGVudGl0eTogRW50aXR5LFxuICApOiBQcm9taXNlPHVua25vd24+IHtcbiAgICAvLyBGYWtlci5qcyDtkZztmITsi53rp4wg7KeA7JuQXG4gICAgaWYgKGdlbmVyYXRvci5zdGFydHNXaXRoKFwiZmFrZXIuXCIpKSB7XG4gICAgICAvLyB1c2VybmFtZeydtOuCmCBuYW1lIO2VhOuTnOuKlCDtlZzqta3slrQgZmFrZXIg7IKs7JqpXG4gICAgICBjb25zdCBpc05hbWVGaWVsZCA9IHByb3AubmFtZSA9PT0gXCJ1c2VybmFtZVwiIHx8IHByb3AubmFtZSA9PT0gXCJuYW1lXCI7XG4gICAgICBjb25zdCBmYWtlck1vZHVsZSA9IGF3YWl0IGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKTtcbiAgICAgIGNvbnN0IGZha2VyID0gaXNOYW1lRmllbGQgPyBmYWtlck1vZHVsZS5mYWtlcktPIDogZmFrZXJNb2R1bGUuZmFrZXI7XG4gICAgICBjb25zdCBleHByID0gZ2VuZXJhdG9yLnNsaWNlKDYpOyAvLyBcImZha2VyLlwiIOygnOqxsFxuXG4gICAgICB0cnkge1xuICAgICAgICAvLyDtlajsiJgg6rK966Gc7JmAIOyduOyekCDtjIzsi7FcbiAgICAgICAgY29uc3QgbWF0Y2ggPSBleHByLm1hdGNoKC9eKFtcXHcuXSspKD86XFwoKC4qPylcXCkpPyQvKTtcbiAgICAgICAgaWYgKCFtYXRjaCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBGaXh0dXJlR2VuZXJhdG9yOiBJbnZhbGlkIGZha2VyIGV4cHJlc3Npb24gZm9yICR7cHJvcC5uYW1lfTogJHtnZW5lcmF0b3J9YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgWywgcGF0aCwgYXJnc1N0cl0gPSBtYXRjaDtcbiAgICAgICAgY29uc3QgcGFydHMgPSBwYXRoLnNwbGl0KFwiLlwiKTtcblxuICAgICAgICAvLyBmYWtlciDqsJ3ssrTsl5DshJwg7ZWo7IiYIOywvuq4sFxuICAgICAgICBsZXQgZm46IHVua25vd24gPSBmYWtlcjtcbiAgICAgICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBmbiA9PT0gXCJvYmplY3RcIiAmJiBmbiAhPT0gbnVsbCAmJiBwYXJ0IGluIGZuKSB7XG4gICAgICAgICAgICBmbiA9IChmbiBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilbcGFydF07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRml4dHVyZUdlbmVyYXRvcjogSW52YWxpZCBmYWtlciBwYXRoIGZvciAke3Byb3AubmFtZX06IGZha2VyLiR7cGF0aH1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyDtlajsiJjqsIAg7JWE64uI66m0IOyXkOufrFxuICAgICAgICBpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZpeHR1cmVHZW5lcmF0b3I6IGZha2VyLiR7cGF0aH0gaXMgbm90IGEgZnVuY3Rpb24gKGZvciAke3Byb3AubmFtZX0pYCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgYXJnczogdW5rbm93bltdID0gW107XG4gICAgICAgIGlmIChhcmdzU3RyPy50cmltKCkpIHtcbiAgICAgICAgICBhcmdzID0gdGhpcy5wYXJzZUdlbmVyYXRvckFyZ3MoYXJnc1N0ciwgcHJvcC5uYW1lKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmbiguLi5hcmdzKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGV4ZWN1dGUgZ2VuZXJhdG9yIFwiJHtnZW5lcmF0b3J9XCIgZm9yICR7cHJvcC5uYW1lfSwgZmFsbGluZyBiYWNrIHRvIGRlZmF1bHQ6YCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICApO1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZURlZmF1bHRWYWx1ZShwcm9wLCBlbnRpdHkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGZha2VyIOydtOyZuOydmCDtkZztmITsi53snYAg7KeA7JuQ7ZWY7KeAIOyViuydjFxuICAgICFpc1Rlc3QoKSAmJlxuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICBgVW5zdXBwb3J0ZWQgZ2VuZXJhdG9yIGV4cHJlc3Npb24gZm9yICR7cHJvcC5uYW1lfTogJHtnZW5lcmF0b3J9LiBPbmx5IGZha2VyLiogZXhwcmVzc2lvbnMgYXJlIHN1cHBvcnRlZC4gVXNpbmcgZGVmYXVsdCB2YWx1ZS5gLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZURlZmF1bHRWYWx1ZShwcm9wLCBlbnRpdHkpO1xuICB9XG5cbiAgLyoqXG4gICAqIO2VhOuTnOydmCDtg4DsnoXqs7wg7J2066aE7J2EIOu2hOyEne2VmOyXrCDsoIHsoIjtlZwg6riw67O46rCS7J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICog7Jqw7ISg7Iic7JyEOlxuICAgKiAxLiDtlYTrk5zrqoUg7Yyo7YS0IOunpOy5rSAoc2FsYXJ5LCBidWRnZXQg65OxIOydmOuvuOyeiOuKlCDrjbDsnbTthLApXG4gICAqIDIuIO2KueyImCDsvIDsnbTsiqQgKERlcGFydG1lbnQgbmFtZSDrk7Eg64+E66mU7J24IOyngOyLnSlcbiAgICogMy4g67Cw7Je0IO2DgOyehSAoSlNPTiDrsLDsl7QpXG4gICAqIDQuIEVudW0g7YOA7J6FXG4gICAqIDUuIO2DgOyeheuzhCDquLDrs7jqsJJcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVEZWZhdWx0VmFsdWUocHJvcDogRW50aXR5UHJvcCwgZW50aXR5PzogRW50aXR5KTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgY29uc3QgZmFrZXJNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgY29uc3QgZmFrZXIgPSBmYWtlck1vZHVsZS5mYWtlcjtcbiAgICBjb25zdCBmYWtlcktPID0gZmFrZXJNb2R1bGUuZmFrZXJLTztcbiAgICBjb25zdCBmYWtlckpBID0gZmFrZXJNb2R1bGUuZmFrZXJKQTtcblxuICAgIGNvbnN0IGxvY2FsZUZha2VyID0gdGhpcy5sb2NhbGUgPT09IFwia29cIiA/IGZha2VyS08gOiB0aGlzLmxvY2FsZSA9PT0gXCJqYVwiID8gZmFrZXJKQSA6IGZha2VyO1xuXG4gICAgLyoqXG4gICAgICogMS4gRW50aXR5LXNwZWNpZmljIO2KueyImCDsvIDsnbTsiqTrpbwg66i87KCAIOyymOumrO2VqeuLiOuLpC5cbiAgICAgKiBmaWVsZF9wYXR0ZXJuc+uztOuLpCDsmrDshKDtlZjsl6wsIO2KueyglSDsl5Tti7Dti7DsnZgg7ZWE65Oc7JeQIOuPhOuplOyduOyXkCDrp57ripQg6rCS7J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICAgKiDsmIg6IERlcGFydG1lbnQubmFtZSDihpIg7ZWc6rWt7Ja0IOu2gOyEnOuqhSAo7IKs656MIOydtOumhOydtCDslYTri5gpXG4gICAgICovXG5cbiAgICAvKipcbiAgICAgKiBEZXBhcnRtZW50IG5hbWXsnYAg7ZWc6rWt7Ja0IOu2gOyEnOuqhSDrqqnroZ3sl5DshJwg7ISg7YOd7ZWp64uI64ukLlxuICAgICAqIOqzoOycoOyEseydhCDsnITtlbQgNzAlIO2ZleuloOuhnCBwcmVmaXgvc3VmZml466W8IOy2lOqwgO2VqeuLiOuLpC5cbiAgICAgKi9cbiAgICBpZiAoZW50aXR5Py5pZCA9PT0gXCJEZXBhcnRtZW50XCIgJiYgcHJvcC5uYW1lID09PSBcIm5hbWVcIikge1xuICAgICAgY29uc3QgZGVwYXJ0bWVudHMgPSBbXG4gICAgICAgIFwi6rCc67Cc7YyAXCIsXG4gICAgICAgIFwi6riw7ZqN7YyAXCIsXG4gICAgICAgIFwi66eI7LyA7YyF7YyAXCIsXG4gICAgICAgIFwi7JiB7JeF7YyAXCIsXG4gICAgICAgIFwi7J247IKs7YyAXCIsXG4gICAgICAgIFwi7LSd66y07YyAXCIsXG4gICAgICAgIFwi7J6s66y07YyAXCIsXG4gICAgICAgIFwi7ZqM6rOE7YyAXCIsXG4gICAgICAgIFwi67KV66y07YyAXCIsXG4gICAgICAgIFwi65SU7J6Q7J247YyAXCIsXG4gICAgICAgIFwiSVTtjIBcIixcbiAgICAgICAgXCLqs6DqsJ3sp4Dsm5DtjIBcIixcbiAgICAgICAgXCLtkojsp4jqtIDrpqztjIBcIixcbiAgICAgICAgXCLsl7DqtazqsJzrsJztjIBcIixcbiAgICAgICAgXCLsg53sgrDtjIBcIixcbiAgICAgICAgXCLqtazrp6TtjIBcIixcbiAgICAgICAgXCLrrLzrpZjtjIBcIixcbiAgICAgIF07XG4gICAgICBjb25zdCBwcmVmaXhlcyA9IFtcIuyLoOq3nFwiLCBcIu2Gte2VqVwiLCBcIuyghOuetVwiLCBcIuq4gOuhnOuyjFwiLCBcIuuUlOyngO2EuFwiLCBcIu2VteyLrFwiXTtcbiAgICAgIGNvbnN0IHN1ZmZpeGVzID0gW1wiMe2MgFwiLCBcIjLtjIBcIiwgXCIz7YyAXCIsIFwiQe2MgFwiLCBcIkLtjIBcIiwgXCLrs7jrtoBcIiwgXCLshLzthLBcIiwgXCLqt7jro7lcIl07XG5cbiAgICAgIGNvbnN0IGRlcHQgPSBmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChkZXBhcnRtZW50cyk7XG5cbiAgICAgIGNvbnN0IHJhbmRvbSA9IE1hdGgucmFuZG9tKCk7XG4gICAgICBpZiAocmFuZG9tID4gMC43KSB7XG4gICAgICAgIGNvbnN0IHByZWZpeCA9IGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KHByZWZpeGVzKTtcbiAgICAgICAgcmV0dXJuIGAke3ByZWZpeH0gJHtkZXB0fWA7XG4gICAgICB9XG4gICAgICBpZiAocmFuZG9tID4gMC40KSB7XG4gICAgICAgIGNvbnN0IHN1ZmZpeCA9IGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KHN1ZmZpeGVzKTtcbiAgICAgICAgcmV0dXJuIGAke2RlcHR9ICR7c3VmZml4fWA7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGVwdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiAyLiDtlYTrk5zrqoXsl5DshJwg7J2Y66+466W8IOy2lOuhoO2VmOyXrCDtmITsi6TsoIHsnbgg642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICAgKiDsmIg6IHNhbGFyeSDihpIgMzBNfjE1ME0gKO2VnOq1rSDsl7DrtIkg67KU7JyEKVxuICAgICAqICAgICBidWRnZXQg4oaSIDEwTX41MDBNICjtlITroZzsoJ3tirgg7JiI7IKwIOuylOychClcbiAgICAgKi9cbiAgICBjb25zdCBsb2NhbGVNYXBwaW5ncyA9IHRoaXMubWFwcGluZ3NbdGhpcy5sb2NhbGVdIHx8IHRoaXMubWFwcGluZ3MuZW47XG4gICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBwcm9wLm5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9fL2csIFwiXCIpO1xuXG4gICAgZm9yIChjb25zdCBbcGF0dGVybiwgY29uZmlnXSBvZiBPYmplY3QuZW50cmllcyhsb2NhbGVNYXBwaW5ncy5maWVsZF9wYXR0ZXJucykpIHtcbiAgICAgIGlmIChub3JtYWxpemVkTmFtZS5pbmNsdWRlcyhwYXR0ZXJuLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZXhlY3V0ZUZha2VyRXhwcmVzc2lvbihjb25maWcuZmFrZXIsIHByb3ApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgRmFpbGVkIHRvIGV4ZWN1dGUgZmllbGQgcGF0dGVybiBcIiR7cGF0dGVybn1cIiBmb3IgJHtwcm9wLm5hbWV9LCBmYWxsaW5nIGJhY2s6YCxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogMy4gSlNPTiDtg4DsnoXsnbTrqbTshJwg67Cw7Je07J24IOqyveyasCAoU29uYW11RmlsZVtdLCBzdHJpbmdbXSDrk7EpXG4gICAgICog7ZWE65Oc66qFIO2MqO2EtOydhCDrs7Tqs6Ag7KCB7KCI7ZWcIOuwsOyXtCDrjbDsnbTthLDrpbwg7IOd7ISx7ZWp64uI64ukLlxuICAgICAqL1xuICAgIGlmIChwcm9wLnR5cGUgPT09IFwianNvblwiICYmIFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQpIHtcbiAgICAgIGlmIChwcm9wLmlkLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVBcnJheVZhbHVlKHByb3AsIGVudGl0eSwgZmFrZXIsIGxvY2FsZUZha2VyKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogNC4gRW51bSDtg4DsnoXsnYAg7KCV7J2Y65CcIOqwkiDspJEg7ZWY64KY66W8IOuenOuNpCDshKDtg53tlanri4jri6QgKi9cbiAgICBpZiAocHJvcC50eXBlID09PSBcImVudW1cIikge1xuICAgICAgbGV0IGVudW1WYWx1ZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGlmIChcImVudW1cIiBpbiBwcm9wICYmIEFycmF5LmlzQXJyYXkocHJvcC5lbnVtKSAmJiBwcm9wLmVudW0ubGVuZ3RoID4gMCkge1xuICAgICAgICBlbnVtVmFsdWVzID0gcHJvcC5lbnVtO1xuICAgICAgfSBlbHNlIGlmIChcImlkXCIgaW4gcHJvcCAmJiBwcm9wLmlkICYmIGVudGl0eT8uZW51bUxhYmVscz8uW3Byb3AuaWRdKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBPYmplY3Qua2V5cyhlbnRpdHkuZW51bUxhYmVsc1twcm9wLmlkXSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbnVtVmFsdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KGVudW1WYWx1ZXMpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHByb3AubnVsbGFibGUgPyBudWxsIDogXCJVTktOT1dOXCI7XG4gICAgfVxuXG4gICAgaWYgKHByb3AudHlwZSA9PT0gXCJlbnVtW11cIikge1xuICAgICAgbGV0IGVudW1WYWx1ZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGlmIChcImVudW1cIiBpbiBwcm9wICYmIEFycmF5LmlzQXJyYXkocHJvcC5lbnVtKSAmJiBwcm9wLmVudW0ubGVuZ3RoID4gMCkge1xuICAgICAgICBlbnVtVmFsdWVzID0gcHJvcC5lbnVtO1xuICAgICAgfSBlbHNlIGlmIChcImlkXCIgaW4gcHJvcCAmJiBwcm9wLmlkICYmIGVudGl0eT8uZW51bUxhYmVscz8uW3Byb3AuaWRdKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBPYmplY3Qua2V5cyhlbnRpdHkuZW51bUxhYmVsc1twcm9wLmlkXSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbnVtVmFsdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIFtmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChlbnVtVmFsdWVzKV07XG4gICAgICB9XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogNS4gVmVjdG9yIO2DgOyeheydgCDtmITsnqwg7KeA7JuQ7ZWY7KeAIOyViuycvOuvgOuhnCBudWxs7J2EIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICAgKiDtlqXtm4QgQUkgZW1iZWRkaW5nIOyDneyEsSDquLDriqUg7LaU6rCAIOyLnCDqtaztmIQg7JiI7KCV7J6F64uI64ukLlxuICAgICAqL1xuICAgIGlmIChwcm9wLnR5cGUgPT09IFwidmVjdG9yXCIgfHwgcHJvcC50eXBlID09PSBcInZlY3RvcltdXCIgfHwgcHJvcC50eXBlID09PSBcInRzdmVjdG9yXCIpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKiA2LiDtg4DsnoXrs4Qg6riw67O4IEZha2VyIO2RnO2YhOyLneydhCDsi6Ttlontlanri4jri6QgKi9cbiAgICBjb25zdCB0eXBlRGVmYXVsdCA9IGxvY2FsZU1hcHBpbmdzLnR5cGVfZGVmYXVsdHNbcHJvcC50eXBlXTtcbiAgICBpZiAodHlwZURlZmF1bHQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmV4ZWN1dGVGYWtlckV4cHJlc3Npb24odHlwZURlZmF1bHQuZmFrZXIsIHByb3ApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBjaGFsay55ZWxsb3coYEZhaWxlZCB0byBleGVjdXRlIHR5cGUgZGVmYXVsdCBmb3IgJHtwcm9wLnR5cGV9LCB1c2luZyBmYWxsYmFjazpgLCBlcnJvciksXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogNy4g66ek7ZWR65CY7KeAIOyViuydgCDtg4DsnoXsnYAg6riw67O4IEZha2VyIO2VqOyImOuhnCDsspjrpqztlanri4jri6QgKi9cbiAgICBzd2l0Y2ggKHByb3AudHlwZSkge1xuICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgY2FzZSBcInN0cmluZ1tdXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5sb3JlbS53b3JkcygzKTtcbiAgICAgIGNhc2UgXCJpbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMDAgfSk7XG4gICAgICBjYXNlIFwiaW50ZWdlcltdXCI6XG4gICAgICAgIHJldHVybiBbZmFrZXIubnVtYmVyLmludCh7IG1pbjogMSwgbWF4OiAxMDAwIH0pXTtcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5udW1iZXIuYmlnSW50KHsgbWluOiAxbiwgbWF4OiAxMDAwbiB9KTtcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyW11cIjpcbiAgICAgICAgcmV0dXJuIFtmYWtlci5udW1iZXIuYmlnSW50KHsgbWluOiAxbiwgbWF4OiAxMDAwbiB9KV07XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gZmFrZXIubnVtYmVyLmZsb2F0KHsgbWluOiAwLCBtYXg6IDEwMDAgfSk7XG4gICAgICBjYXNlIFwibnVtYmVyW11cIjpcbiAgICAgIGNhc2UgXCJudW1lcmljW11cIjpcbiAgICAgICAgcmV0dXJuIFtmYWtlci5udW1iZXIuZmxvYXQoeyBtaW46IDAsIG1heDogMTAwMCB9KV07XG4gICAgICBjYXNlIFwiYm9vbGVhblwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuZGF0YXR5cGUuYm9vbGVhbigpO1xuICAgICAgY2FzZSBcImJvb2xlYW5bXVwiOlxuICAgICAgICByZXR1cm4gW2Zha2VyLmRhdGF0eXBlLmJvb2xlYW4oKV07XG4gICAgICBjYXNlIFwiZGF0ZVwiOlxuICAgICAgY2FzZSBcImRhdGVbXVwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuZGF0ZS5wYXN0KCk7XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICByZXR1cm4ge307XG4gICAgICBjYXNlIFwidXVpZFwiOlxuICAgICAgY2FzZSBcInV1aWRbXVwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuc3RyaW5nLnV1aWQoKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrsLDsl7Qg7YOA7J6F7J2YIOqwkuydhCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIO2DgOyehSBJROyZgCDtlYTrk5zrqoUg7Yyo7YS07J2EIOu2hOyEne2VmOyXrCDsoIHsoIjtlZwg67Cw7Je0IOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gICAqIOyYiDogaW1hZ2VfdXJscyDihpIgW3t1cmwsIG5hbWUsIG1pbWVfdHlwZX0sIC4uLl1cbiAgICogICAgIHRhZ19pZHMg4oaSIFsxLCAyMywgNDVdXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlQXJyYXlWYWx1ZShcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIF9lbnRpdHk6IEVudGl0eSB8IHVuZGVmaW5lZCxcbiAgICBmYWtlcjogdHlwZW9mIGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKS5mYWtlcixcbiAgICBfbG9jYWxlRmFrZXI6IHR5cGVvZiBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIikuZmFrZXIsXG4gICk6IHVua25vd25bXSB7XG4gICAgY29uc3QgY291bnQgPSBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDMgfSk7XG5cbiAgICAvKiogU29uYW11RmlsZVtd7J2AIFNvbmFtdSDrgrTsnqUg7YOA7J6F7Jy866GcIOq1rOyhsOqwgCDsoJXtlbTsoLgg7J6I7Iq164uI64ukICovXG4gICAgaWYgKFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQgPT09IFwiU29uYW11RmlsZVtdXCIpIHtcbiAgICAgIHJldHVybiBBcnJheS5mcm9tKHsgbGVuZ3RoOiBjb3VudCB9LCAoKSA9PiAoe1xuICAgICAgICB1cmw6IGZha2VyLmltYWdlLnVybCgpLFxuICAgICAgICBuYW1lOiBmYWtlci5zeXN0ZW0uZmlsZU5hbWUoKSxcbiAgICAgICAgbWltZV90eXBlOiBmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChbXG4gICAgICAgICAgXCJpbWFnZS9qcGVnXCIsXG4gICAgICAgICAgXCJpbWFnZS9wbmdcIixcbiAgICAgICAgICBcImltYWdlL2dpZlwiLFxuICAgICAgICAgIFwiYXBwbGljYXRpb24vcGRmXCIsXG4gICAgICAgIF0pLFxuICAgICAgfSkpO1xuICAgIH1cblxuICAgIC8qKiDtlYTrk5zrqoXsl5DshJwg67Cw7Je07J2YIOyaqeuPhOulvCDstpTroaDtlanri4jri6QgKi9cbiAgICBjb25zdCBub3JtYWxpemVkTmFtZSA9IHByb3AubmFtZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL18vZywgXCJcIik7XG5cbiAgICBpZiAobm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJ1cmxcIikgfHwgbm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJpbWFnZVwiKSkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGg6IGNvdW50IH0sICgpID0+IGZha2VyLmludGVybmV0LnVybCgpKTtcbiAgICB9XG5cbiAgICBpZiAobm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJpZFwiKSAmJiBub3JtYWxpemVkTmFtZS5lbmRzV2l0aChcInNcIikpIHtcbiAgICAgIHJldHVybiBBcnJheS5mcm9tKHsgbGVuZ3RoOiBjb3VudCB9LCAoKSA9PiBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMCB9KSk7XG4gICAgfVxuXG4gICAgaWYgKG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKFwidGFnXCIpIHx8IG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKFwibmFtZVwiKSkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGg6IGNvdW50IH0sICgpID0+IGZha2VyLmxvcmVtLndvcmQoKSk7XG4gICAgfVxuXG4gICAgLyoqIO2MqO2EtCDrp6Tsua3rkJjsp4Ag7JWK7Jy866m0IOu5iCDrsLDsl7TsnYQg67CY7ZmY7ZWp64uI64ukICovXG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIEpTT04g66ek7ZWR7J2YIEZha2VyIO2RnO2YhOyLneydhCDtjIzsi7HtlZjsl6wg7Iuk7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiDtkZztmITsi50g7JiI7IucOlxuICAgKiAtIFwiZmFrZXIuaW50ZXJuZXQuZW1haWwoKVwiIOKGkiDsnbjsnpAg7JeG7J2MXG4gICAqIC0gXCJmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMCB9KVwiIOKGkiBKU09OIOyduOyekFxuICAgKiAtIFwie31cIiDihpIg66as7YSw65+0IOqwkiAoSlNPTi5wYXJzZSlcbiAgICpcbiAgICogZmFrZXJLTywgZmFrZXJKQeuPhCDsp4Dsm5DtlZjsl6wg64uk6rWt7Ja0IOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVGYWtlckV4cHJlc3Npb24oZXhwcmVzc2lvbjogc3RyaW5nLCBwcm9wOiBFbnRpdHlQcm9wKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgY29uc3QgZmFrZXJNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgY29uc3QgZmFrZXIgPSBmYWtlck1vZHVsZS5mYWtlcjtcbiAgICBjb25zdCBmYWtlcktPID0gZmFrZXJNb2R1bGUuZmFrZXJLTztcbiAgICBjb25zdCBmYWtlckpBID0gZmFrZXJNb2R1bGUuZmFrZXJKQTtcblxuICAgIC8qKiBGYWtlciDtkZztmITsi53snbQg7JWE64uMIOumrO2EsOuftCDqsJLsnYAgSlNPTuycvOuhnCDtjIzsi7Htlanri4jri6QgKi9cbiAgICBpZiAoIWV4cHJlc3Npb24uc3RhcnRzV2l0aChcImZha2VyXCIpKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShleHByZXNzaW9uKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gZXhwcmVzc2lvbjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiog7ZGc7ZiE7Iud7JeQ7IScIEZha2VyIOqwneyytOyZgCDqsr3roZzrpbwg7LaU7Lac7ZWp64uI64ukICovXG4gICAgY29uc3QgbWF0Y2ggPSBleHByZXNzaW9uLm1hdGNoKC9eKGZha2VyfGZha2VyS098ZmFrZXJKQSlcXC4oLio/KSQvKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZmFrZXIgZXhwcmVzc2lvbjogJHtleHByZXNzaW9ufWApO1xuICAgIH1cblxuICAgIGNvbnN0IFssIGZha2VyTmFtZSwgZXhwcl0gPSBtYXRjaDtcbiAgICBjb25zdCBzZWxlY3RlZEZha2VyID1cbiAgICAgIGZha2VyTmFtZSA9PT0gXCJmYWtlcktPXCIgPyBmYWtlcktPIDogZmFrZXJOYW1lID09PSBcImZha2VySkFcIiA/IGZha2VySkEgOiBmYWtlcjtcblxuICAgIGNvbnN0IGZ1bmNNYXRjaCA9IGV4cHIubWF0Y2goL14oW1xcdy5dKykoPzpcXCgoLio/KVxcKSk/JC8pO1xuICAgIGlmICghZnVuY01hdGNoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZmFrZXIgZXhwcmVzc2lvbiBmb3IgJHtwcm9wLm5hbWV9OiAke2V4cHJlc3Npb259YCk7XG4gICAgfVxuXG4gICAgY29uc3QgWywgcGF0aCwgYXJnc1N0cl0gPSBmdW5jTWF0Y2g7XG4gICAgY29uc3QgcGFydHMgPSBwYXRoLnNwbGl0KFwiLlwiKTtcblxuICAgIC8qKiDsoJAg7ZGc6riw67KVKGRvdCBub3RhdGlvbinsnLzroZwgRmFrZXIg7ZWo7IiY66W8IOywvuyVhOqwkeuLiOuLpCAqL1xuICAgIGxldCBmbjogdW5rbm93biA9IHNlbGVjdGVkRmFrZXI7XG4gICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgICBpZiAodHlwZW9mIGZuID09PSBcIm9iamVjdFwiICYmIGZuICE9PSBudWxsICYmIHBhcnQgaW4gZm4pIHtcbiAgICAgICAgZm4gPSAoZm4gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW3BhcnRdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGZha2VyIHBhdGggZm9yICR7cHJvcC5uYW1lfTogJHtmYWtlck5hbWV9LiR7cGF0aH1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtmYWtlck5hbWV9LiR7cGF0aH0gaXMgbm90IGEgZnVuY3Rpb24gKGZvciAke3Byb3AubmFtZX0pYCk7XG4gICAgfVxuXG4gICAgbGV0IGFyZ3M6IHVua25vd25bXSA9IFtdO1xuICAgIGlmIChhcmdzU3RyPy50cmltKCkpIHtcbiAgICAgIGFyZ3MgPSB0aGlzLnBhcnNlR2VuZXJhdG9yQXJncyhhcmdzU3RyLCBwcm9wLm5hbWUpO1xuICAgIH1cblxuICAgIHJldHVybiBmbiguLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBmaXh0dXJlSGludOulvCBMTE3sl5Dqsowg7KCE64us7ZWY7JesIO2YhOyLpOyggeyduCDthYzsiqTtirgg642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogZmFrZXIuanProZzripQg7IOd7ISx7ZWY6riwIOyWtOugpOyatCDrs7XsnqHtlZwg7YWN7Iqk7Yq4KOyekOq4sOyGjOqwnCwg7ISk66qF66y4IOuTsSnrpbxcbiAgICogTExN7J2EIO2ZnOyaqe2VmOyXrCDsg53shLHtlanri4jri6QuIOuPmeydvO2VnCBoaW507JeQIOuMgO2VnCDspJHrs7Ug7Zi47Lac7J2EIOuwqeyngO2VmOq4sCDsnITtlbRcbiAgICog7LqQ7Iux7J2EIOq4sOuzuOycvOuhnCDsp4Dsm5Dtlanri4jri6QgKExMTSBBUEkg67mE7JqpIOygiOqwkCkuXG4gICAqXG4gICAqIGFpIO2MqO2CpOyngOuKlCBkeW5hbWljIGltcG9ydOuhnCDrtojrn6zsmKTrr4DroZwsIHVzZUxMTeydtCBmYWxzZeyduCDqsr3smrBcbiAgICog7J2Y7KG07ISx7J20IOyEpOy5mOuQmOyngCDslYrslYTrj4QgZml4dHVyZSDsg53shLHsnbQg7KCV7IOBIOuPmeyeke2VqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVXaXRoTExNKFxuICAgIGZpeHR1cmVIaW50OiBzdHJpbmcsXG4gICAgcHJvcDogRW50aXR5UHJvcCxcbiAgICBlbnRpdHk6IEVudGl0eSxcbiAgICByb3dLZXk/OiBzdHJpbmcsXG4gICk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIC8vIHJvd0tleeqwgCDsnojsnLzrqbQgcm93IOuLqOychCDsg53shLEg7KCE6561IOyCrOyaqVxuICAgIGlmIChyb3dLZXkpIHtcbiAgICAgIGNvbnN0IHJvd0NhY2hlS2V5ID0gYCR7cm93S2V5fToke3Byb3AubmFtZX1gO1xuXG4gICAgICAvLyDsnbTrr7gg7J20IHJvd+yXkCDrjIDtlZwgTExNIO2YuOy2nOydtCDsmYTro4zrkJwg6rK97JqwIOy6kOyLnOyXkOyEnCDrsJTroZwg67CY7ZmYXG4gICAgICBpZiAodGhpcy5sbG1DYWNoZS5oYXMocm93Q2FjaGVLZXkpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxsbUNhY2hlLmdldChyb3dDYWNoZUtleSk7XG4gICAgICB9XG5cbiAgICAgIC8vIOyDiCByb3c6IExMTSDrjIDsg4EgcHJvcCDsoITssrTrpbwg7ZWcIOuyiOyXkCDsg53shLFcbiAgICAgIGNvbnN0IGxsbVByb3BzID0gZW50aXR5LnByb3BzLmZpbHRlcigocCkgPT4ge1xuICAgICAgICBpZiAoaXNSZWxhdGlvblByb3AocCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKHAuY29uZT8uZml4dHVyZUdlbmVyYXRvcikgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAocC5uYW1lID09PSBcImlkXCIgJiYgcC5jb25lPy5maXh0dXJlU3RyYXRlZ3kgPT09IFwic2VxdWVuY2VcIikgcmV0dXJuIGZhbHNlO1xuICAgICAgICByZXR1cm4gISFwLmNvbmU/Lm5vdGU7XG4gICAgICB9KTtcblxuICAgICAgLy8gbGxtUHJvcHPqsIAg67mE7Ja07J6I7Jy866m0IOuLqOydvCDtlYTrk5wg67Cp7Iud7Jy866GcIGZhbGxiYWNrXG4gICAgICBpZiAobGxtUHJvcHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgYFtGaXh0dXJlR2VuZXJhdG9yXSBsbG1Qcm9wcyBpcyBlbXB0eSBmb3IgJHtlbnRpdHkuaWR9LiR7cHJvcC5uYW1lfSwgdXNpbmcgc2luZ2xlIGZpZWxkIGZhbGxiYWNrYCxcbiAgICAgICAgICApO1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZVNpbmdsZVdpdGhMTE0oZml4dHVyZUhpbnQsIHByb3AsIGVudGl0eSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFwaUtleSA9IHRoaXMuZ2V0QXBpS2V5KCk7XG4gICAgICBjb25zdCB7IGNyZWF0ZUFudGhyb3BpYyB9ID0gYXdhaXQgaW1wb3J0KFwiQGFpLXNkay9hbnRocm9waWNcIik7XG4gICAgICBjb25zdCB7IGdlbmVyYXRlVGV4dCB9ID0gYXdhaXQgaW1wb3J0KFwiYWlcIik7XG5cbiAgICAgIGNvbnN0IHJvd1Jlc3BvbnNlID0gYXdhaXQgZ2VuZXJhdGVUZXh0KHtcbiAgICAgICAgbW9kZWw6IGNyZWF0ZUFudGhyb3BpYyh7IGFwaUtleSB9KSh0aGlzLm9wdGlvbnMubGxtTW9kZWwgfHwgXCJjbGF1ZGUtc29ubmV0LTQtNlwiKSxcbiAgICAgICAgcHJvbXB0OiB0aGlzLmJ1aWxkUm93TExNUHJvbXB0KGxsbVByb3BzLCBlbnRpdHkpLFxuICAgICAgfSk7XG4gICAgICBpZiAoIXJvd1Jlc3BvbnNlIHx8IHR5cGVvZiByb3dSZXNwb25zZS50ZXh0ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgTExNIHJlc3BvbnNlXCIpO1xuICAgICAgfVxuXG4gICAgICAvLyDsnZHri7XsnYQg7YyM7Iux7ZWY7JesIOqwgSDtlYTrk5zsl5Ag64yA7ZWcIOqysOqzvOulvCDsupDsi5zsl5Ag7KCA7J6lXG4gICAgICBjb25zdCByb3dSZXN1bHQgPSB0aGlzLnBhcnNlUm93TExNUmVzcG9uc2Uocm93UmVzcG9uc2UudGV4dCwgbGxtUHJvcHMpO1xuICAgICAgZm9yIChjb25zdCBbZmllbGROYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocm93UmVzdWx0KSkge1xuICAgICAgICB0aGlzLmxsbUNhY2hlLnNldChgJHtyb3dLZXl9OiR7ZmllbGROYW1lfWAsIHZhbHVlKTtcbiAgICAgIH1cblxuICAgICAgLy8g7JqU7LKt7ZWcIO2VhOuTnOydmCDqsJIg67CY7ZmYICjsl4bsnLzrqbQg64uo7J28IO2VhOuTnCBmYWxsYmFjaylcbiAgICAgIGlmICh0aGlzLmxsbUNhY2hlLmhhcyhyb3dDYWNoZUtleSkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubGxtQ2FjaGUuZ2V0KHJvd0NhY2hlS2V5KTtcbiAgICAgIH1cblxuICAgICAgLy8g66eM7JW9IHJvdyDsnZHri7Xsl5Ag7J20IO2VhOuTnOqwgCDriITrnb3rkJwg6rK97JqwIOuLqOydvCDtlYTrk5wgZmFsbGJhY2tcbiAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlU2luZ2xlV2l0aExMTShmaXh0dXJlSGludCwgcHJvcCwgZW50aXR5KTtcbiAgICB9XG5cbiAgICAvLyByb3dLZXnqsIAg7JeG7Jy866m0IOq4sOyhtCDri6jsnbwg7ZWE65OcIOuwqeyLnVxuICAgIHJldHVybiB0aGlzLmdlbmVyYXRlU2luZ2xlV2l0aExMTShmaXh0dXJlSGludCwgcHJvcCwgZW50aXR5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiDri6jsnbwg7ZWE65Oc66W8IExMTeycvOuhnCDsg53shLHtlanri4jri6QgKHJvd0tleSDsl4bsnYQg65WMIGZhbGxiYWNr7JqpKVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZW5lcmF0ZVNpbmdsZVdpdGhMTE0oXG4gICAgZml4dHVyZUhpbnQ6IHN0cmluZyxcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIGVudGl0eTogRW50aXR5LFxuICApOiBQcm9taXNlPHVua25vd24+IHtcbiAgICBjb25zdCBjYWNoZUtleSA9IGAke2VudGl0eS5pZH06JHtwcm9wLm5hbWV9OiR7Zml4dHVyZUhpbnR9YDtcbiAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxMTUNhY2hlICYmIHRoaXMubGxtQ2FjaGUuaGFzKGNhY2hlS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMubGxtQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICB9XG5cbiAgICBjb25zdCBhcGlLZXkgPSB0aGlzLmdldEFwaUtleSgpO1xuICAgIGNvbnN0IHsgY3JlYXRlQW50aHJvcGljIH0gPSBhd2FpdCBpbXBvcnQoXCJAYWktc2RrL2FudGhyb3BpY1wiKTtcbiAgICBjb25zdCB7IGdlbmVyYXRlVGV4dCB9ID0gYXdhaXQgaW1wb3J0KFwiYWlcIik7XG5cbiAgICBjb25zdCBzaW5nbGVSZXNwb25zZSA9IGF3YWl0IGdlbmVyYXRlVGV4dCh7XG4gICAgICBtb2RlbDogY3JlYXRlQW50aHJvcGljKHsgYXBpS2V5IH0pKHRoaXMub3B0aW9ucy5sbG1Nb2RlbCB8fCBcImNsYXVkZS1zb25uZXQtNC02XCIpLFxuICAgICAgcHJvbXB0OiB0aGlzLmJ1aWxkTExNUHJvbXB0KGZpeHR1cmVIaW50LCBwcm9wLCBlbnRpdHkpLFxuICAgIH0pO1xuICAgIGlmICghc2luZ2xlUmVzcG9uc2UgfHwgdHlwZW9mIHNpbmdsZVJlc3BvbnNlLnRleHQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgTExNIHJlc3BvbnNlXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5wYXJzZUxMTVJlc3BvbnNlKHNpbmdsZVJlc3BvbnNlLnRleHQsIHByb3AudHlwZSk7XG4gICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMTE1DYWNoZSkge1xuICAgICAgdGhpcy5sbG1DYWNoZS5zZXQoY2FjaGVLZXksIHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogcm93IOyghOyytOulvCDtlZwg67KI7JeQIOyDneyEse2VmOuKlCBMTE0g7ZSE66Gs7ZSE7Yq466W8IOunjOuTreuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRSb3dMTE1Qcm9tcHQocHJvcHM6IEVudGl0eVByb3BbXSwgZW50aXR5OiBFbnRpdHkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGxvY2FsZSA9IHRoaXMub3B0aW9ucy5sb2NhbGUgfHwgXCJrb1wiO1xuICAgIGNvbnN0IGxhbmd1YWdlID0gbG9jYWxlID09PSBcImtvXCIgPyBcIktvcmVhblwiIDogbG9jYWxlID09PSBcImphXCIgPyBcIkphcGFuZXNlXCIgOiBcIkVuZ2xpc2hcIjtcblxuICAgIGNvbnN0IGZpZWxkRGVzY3JpcHRpb25zID0gcHJvcHNcbiAgICAgIC5tYXAoKHApID0+IHtcbiAgICAgICAgbGV0IGRlc2MgPSBgLSAke3AubmFtZX0gKCR7cC50eXBlfSk6ICR7cC5jb25lPy5ub3RlID8/IFwiXCJ9YDtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIChwLnR5cGUgPT09IFwiZW51bVwiIHx8IHAudHlwZSA9PT0gXCJlbnVtW11cIikgJiZcbiAgICAgICAgICBcImlkXCIgaW4gcCAmJlxuICAgICAgICAgIHAuaWQgJiZcbiAgICAgICAgICBlbnRpdHkuZW51bUxhYmVscz8uW3AuaWRdXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IHZhbHVlcyA9IE9iamVjdC5rZXlzKGVudGl0eS5lbnVtTGFiZWxzW3AuaWRdKS5qb2luKFwiLCBcIik7XG4gICAgICAgICAgZGVzYyArPSBgIFthbGxvd2VkIHZhbHVlczogJHt2YWx1ZXN9XWA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgICB9KVxuICAgICAgLmpvaW4oXCJcXG5cIik7XG5cbiAgICAvLyBMTE0g64yA7IOB7J20IOyVhOuLjCBwcm9w65Ok64+EIOunpeudveycvOuhnCDsoJzqs7UgKHJlbGF0aW9uIOygnOyZuClcbiAgICBjb25zdCBvdGhlclByb3BzID0gZW50aXR5LnByb3BzXG4gICAgICAuZmlsdGVyKFxuICAgICAgICAocCkgPT5cbiAgICAgICAgICAhcHJvcHMuaW5jbHVkZXMocCkgJiZcbiAgICAgICAgICAhaXNSZWxhdGlvblByb3AocCkgJiZcbiAgICAgICAgICBwLm5hbWUgIT09IFwiaWRcIiAmJlxuICAgICAgICAgICEoXCJ2aXJ0dWFsXCIgaW4gcCAmJiBwLnZpcnR1YWwpLFxuICAgICAgKVxuICAgICAgLm1hcCgocCkgPT4ge1xuICAgICAgICBsZXQgZGVzYyA9IGAtICR7cC5uYW1lfSAoJHtwLnR5cGV9KWA7XG4gICAgICAgIGlmIChwLmNvbmU/Lm5vdGUpIGRlc2MgKz0gYDogJHtwLmNvbmUubm90ZX1gO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgKHAudHlwZSA9PT0gXCJlbnVtXCIgfHwgcC50eXBlID09PSBcImVudW1bXVwiKSAmJlxuICAgICAgICAgIFwiaWRcIiBpbiBwICYmXG4gICAgICAgICAgcC5pZCAmJlxuICAgICAgICAgIGVudGl0eS5lbnVtTGFiZWxzPy5bcC5pZF1cbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWVzID0gT2JqZWN0LmtleXMoZW50aXR5LmVudW1MYWJlbHNbcC5pZF0pLmpvaW4oXCIsIFwiKTtcbiAgICAgICAgICBkZXNjICs9IGAgW2FsbG93ZWQgdmFsdWVzOiAke3ZhbHVlc31dYDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGVzYztcbiAgICAgIH0pXG4gICAgICAuam9pbihcIlxcblwiKTtcbiAgICBjb25zdCBvdGhlclByb3BzQ29udGV4dCA9IG90aGVyUHJvcHNcbiAgICAgID8gYFxcblxcbk90aGVyIGZpZWxkcyBpbiB0aGlzIGVudGl0eSAoZm9yIGNvbnRleHQsIGRvIE5PVCBnZW5lcmF0ZSB0aGVzZSk6XFxuJHtvdGhlclByb3BzfWBcbiAgICAgIDogXCJcIjtcblxuICAgIGNvbnN0IG91dHB1dFNoYXBlID0gcHJvcHMubWFwKChwKSA9PiBgICBcIiR7cC5uYW1lfVwiOiA8JHtwLnR5cGV9PmApLmpvaW4oXCIsXFxuXCIpO1xuXG4gICAgY29uc3QgZW50aXR5Q29udGV4dCA9IGVudGl0eS5jb25lPy5ub3RlID8gYFxcbkVudGl0eSBkZXNjcmlwdGlvbjogJHtlbnRpdHkuY29uZS5ub3RlfWAgOiBcIlwiO1xuXG4gICAgcmV0dXJuIGBHZW5lcmF0ZSB0ZXN0IGZpeHR1cmUgZGF0YSBmb3IgdGhlICR7ZW50aXR5LmlkfSBlbnRpdHkuIEFsbCBmaWVsZHMgbXVzdCBiZSBjb2hlcmVudCBhbmQgY29uc2lzdGVudCB3aXRoIGVhY2ggb3RoZXIuXG5cbkVudGl0eTogJHtlbnRpdHkuaWR9JHtlbnRpdHlDb250ZXh0fVxuTG9jYWxlOiAke2xvY2FsZX0gKHVzZSAke2xhbmd1YWdlfSBmb3IgdGV4dCBmaWVsZHMpXG5cbkZpZWxkcyB0byBnZW5lcmF0ZTpcbiR7ZmllbGREZXNjcmlwdGlvbnN9JHtvdGhlclByb3BzQ29udGV4dH1cblxuUnVsZXM6XG4tIEFsbCBmaWVsZHMgaW4gYSBzaW5nbGUgcm93IG11c3QgYmUgbG9naWNhbGx5IGNvbnNpc3RlbnQgKGUuZy4gbmFtZS9uYW1lX2VuL25hbWVfY24gc2hvdWxkIHJlcHJlc2VudCB0aGUgc2FtZSBwZXJzb24pXG4tIFJldHVybiBPTkxZIHZhbGlkIEpTT04sIG5vIG1hcmtkb3duIG9yIGV4cGxhbmF0aW9uXG4tIERhdGVzIGluIElTTyA4NjAxIGZvcm1hdFxuLSBVc2UgJHtsYW5ndWFnZX0gZm9yIHRleHQgdW5sZXNzIGZpZWxkIGRlc2NyaXB0aW9uIHNheXMgb3RoZXJ3aXNlXG5cblJldHVybiBleGFjdGx5IHRoaXMgSlNPTiBzaGFwZTpcbntcbiR7b3V0cHV0U2hhcGV9XG59YDtcbiAgfVxuXG4gIC8qKlxuICAgKiByb3cgTExNIOydkeuLteydhCDtjIzsi7HtlZjsl6wg7ZWE65Oc67OEIOqwkuycvOuhnCDrs4DtmZjtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIHBhcnNlUm93TExNUmVzcG9uc2UodGV4dDogc3RyaW5nLCBwcm9wczogRW50aXR5UHJvcFtdKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIGNvbnN0IGpzb25UZXh0ID0gdGV4dFxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlcGxhY2UoL15gYGBqc29uXFxzKi9pLCBcIlwiKVxuICAgICAgLnJlcGxhY2UoL2BgYFxccyokLywgXCJcIilcbiAgICAgIC50cmltKCk7XG5cbiAgICBsZXQgcGFyc2VkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmF3ID0gSlNPTi5wYXJzZShqc29uVGV4dCk7XG4gICAgICBpZiAodHlwZW9mIHJhdyAhPT0gXCJvYmplY3RcIiB8fCByYXcgPT09IG51bGwgfHwgQXJyYXkuaXNBcnJheShyYXcpKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUud2FybihcIltGaXh0dXJlR2VuZXJhdG9yXSBSb3cgTExNIHJlc3BvbnNlIGlzIG5vdCBhIHBsYWluIG9iamVjdDpcIiwgdGV4dCk7XG4gICAgICAgIHJldHVybiB7fTtcbiAgICAgIH1cbiAgICAgIHBhcnNlZCA9IHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB9IGNhdGNoIHtcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLndhcm4oXCJbRml4dHVyZUdlbmVyYXRvcl0gRmFpbGVkIHRvIHBhcnNlIHJvdyBMTE0gcmVzcG9uc2U6XCIsIHRleHQpO1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgcHJvcHMpIHtcbiAgICAgIGlmIChwcm9wLm5hbWUgaW4gcGFyc2VkKSB7XG4gICAgICAgIHJlc3VsdFtwcm9wLm5hbWVdID0gdGhpcy5wYXJzZUxMTVJlc3BvbnNlKFN0cmluZyhwYXJzZWRbcHJvcC5uYW1lXSA/PyBcIlwiKSwgcHJvcC50eXBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRMTE1Qcm9tcHQoaGludDogc3RyaW5nLCBwcm9wOiBFbnRpdHlQcm9wLCBlbnRpdHk6IEVudGl0eSk6IHN0cmluZyB7XG4gICAgY29uc3QgbG9jYWxlID0gdGhpcy5vcHRpb25zLmxvY2FsZSB8fCBcImtvXCI7XG4gICAgY29uc3QgbGFuZ3VhZ2UgPSBsb2NhbGUgPT09IFwia29cIiA/IFwiS29yZWFuXCIgOiBsb2NhbGUgPT09IFwiamFcIiA/IFwiSmFwYW5lc2VcIiA6IFwiRW5nbGlzaFwiO1xuXG4gICAgY29uc3QgZW50aXR5Q29udGV4dCA9IGVudGl0eS5jb25lPy5ub3RlID8gYFxcbkVudGl0eSBjb250ZXh0OiAke2VudGl0eS5jb25lLm5vdGV9YCA6IFwiXCI7XG5cbiAgICBjb25zdCBvdGhlckZpZWxkcyA9IGVudGl0eS5wcm9wc1xuICAgICAgLmZpbHRlcigocCkgPT4gcC5uYW1lICE9PSBwcm9wLm5hbWUgJiYgIWlzUmVsYXRpb25Qcm9wKHApICYmIHAuY29uZT8ubm90ZSlcbiAgICAgIC5tYXAoKHApID0+IGAtICR7cC5uYW1lfSAoJHtwLnR5cGV9KTogJHtwLmNvbmU/Lm5vdGV9YClcbiAgICAgIC5qb2luKFwiXFxuXCIpO1xuICAgIGNvbnN0IG90aGVyRmllbGRzQ29udGV4dCA9IG90aGVyRmllbGRzXG4gICAgICA/IGBcXG5cXG5PdGhlciBmaWVsZHMgaW4gdGhpcyBlbnRpdHkgKGZvciBjb250ZXh0KTpcXG4ke290aGVyRmllbGRzfWBcbiAgICAgIDogXCJcIjtcblxuICAgIGxldCBwcm9tcHQgPSBgR2VuZXJhdGUgdGVzdCBkYXRhIGZvciAke2VudGl0eS5pZH0uJHtwcm9wLm5hbWV9ICh0eXBlOiAke3Byb3AudHlwZX0pJHtlbnRpdHlDb250ZXh0fSR7b3RoZXJGaWVsZHNDb250ZXh0fVxuXG5SZXF1aXJlbWVudDogJHtoaW50fVxuXG5SdWxlczpcbi0gUmV0dXJuIE9OTFkgdGhlIHZhbHVlLCBubyBleHBsYW5hdGlvbiBvciBtYXJrZG93blxuLSBVc2UgJHtsYW5ndWFnZX0gbGFuZ3VhZ2UgaWYgYXBwbGljYWJsZVxuLSBGb3JtYXQ6ICR7dGhpcy5nZXRFeHBlY3RlZEZvcm1hdChwcm9wLnR5cGUpfWA7XG5cbiAgICAvLyBlbnVtIO2DgOyeheyduCDqsr3smrAg6rCA64ql7ZWcIOqwkiDrqqnroZ0g7LaU6rCAXG4gICAgaWYgKHByb3AudHlwZSA9PT0gXCJlbnVtXCIgfHwgcHJvcC50eXBlID09PSBcImVudW1bXVwiKSB7XG4gICAgICBsZXQgZW51bVZhbHVlczogc3RyaW5nW10gPSBbXTtcblxuICAgICAgaWYgKFwiZW51bVwiIGluIHByb3AgJiYgQXJyYXkuaXNBcnJheShwcm9wLmVudW0pICYmIHByb3AuZW51bS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBwcm9wLmVudW07XG4gICAgICB9IGVsc2UgaWYgKFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQgJiYgZW50aXR5Py5lbnVtTGFiZWxzPy5bcHJvcC5pZF0pIHtcbiAgICAgICAgZW51bVZhbHVlcyA9IE9iamVjdC5rZXlzKGVudGl0eS5lbnVtTGFiZWxzW3Byb3AuaWRdKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVudW1WYWx1ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBwcm9tcHQgKz0gYFxcbi0gSU1QT1JUQU5UOiBDaG9vc2UgT05MWSBmcm9tIHRoZXNlIGFsbG93ZWQgdmFsdWVzOiAke2VudW1WYWx1ZXMuam9pbihcIiwgXCIpfWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcHJvbXB0ICs9IGBcXG5cXG5FeGFtcGxlOiAke3RoaXMuZ2V0RXhhbXBsZUZvclR5cGUocHJvcC50eXBlLCBsb2NhbGUpfWA7XG5cbiAgICByZXR1cm4gcHJvbXB0O1xuICB9XG5cbiAgcHJpdmF0ZSBwYXJzZUxMTVJlc3BvbnNlKHRleHQ6IHN0cmluZywgcHJvcFR5cGU6IHN0cmluZyk6IHVua25vd24ge1xuICAgIGNvbnN0IGNsZWFuZWQgPSB0ZXh0LnRyaW0oKTtcblxuICAgIC8vIOuwsOyXtCDtg4DsnoUg7LKY66asXG4gICAgaWYgKHByb3BUeXBlLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoY2xlYW5lZCk7XG4gICAgICAgIGNvbnN0IGJhc2VUeXBlID0gcHJvcFR5cGUuc2xpY2UoMCwgLTIpOyAvLyBcImludGVnZXJbXVwiIC0+IFwiaW50ZWdlclwiXG5cbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGFyc2VkKSkge1xuICAgICAgICAgIHJldHVybiBwYXJzZWQubWFwKChpdGVtKSA9PiB7XG4gICAgICAgICAgICAvLyBudWxsL3VuZGVmaW5lZOuKlCDtg4DsnoXrs4Qg6riw67O46rCS7Jy866GcXG4gICAgICAgICAgICBpZiAoaXRlbSA9PT0gbnVsbCB8fCBpdGVtID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0RGVmYXVsdFZhbHVlRm9yVHlwZShiYXNlVHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyDqsJ3ssrTripQgSlNPTi5zdHJpbmdpZnkg7ZuEIO2MjOyLsSAoanNvbiDtg4DsnoXsnbgg6rK97JqwKVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBiYXNlVHlwZSA9PT0gXCJqc29uXCJcbiAgICAgICAgICAgICAgICA/IGl0ZW1cbiAgICAgICAgICAgICAgICA6IHRoaXMucGFyc2VTY2FsYXJWYWx1ZShKU09OLnN0cmluZ2lmeShpdGVtKSwgYmFzZVR5cGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gcHJpbWl0aXZlIOqwkuydgCDrrLjsnpDsl7TroZwg67OA7ZmYIO2bhCDtjIzsi7FcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcnNlU2NhbGFyVmFsdWUoU3RyaW5nKGl0ZW0pLCBiYXNlVHlwZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyDri6jsnbwg6rCS7J20IOyYqCDqsr3smrAg67Cw7Je066GcIOqwkOyLuOq4sFxuICAgICAgICBpZiAocGFyc2VkID09PSBudWxsIHx8IHBhcnNlZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIFt0aGlzLmdldERlZmF1bHRWYWx1ZUZvclR5cGUoYmFzZVR5cGUpXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW3RoaXMucGFyc2VTY2FsYXJWYWx1ZShTdHJpbmcocGFyc2VkKSwgYmFzZVR5cGUpXTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucGFyc2VTY2FsYXJWYWx1ZShjbGVhbmVkLCBwcm9wVHlwZSk7XG4gIH1cblxuICBwcml2YXRlIGdldERlZmF1bHRWYWx1ZUZvclR5cGUocHJvcFR5cGU6IHN0cmluZyk6IHVua25vd24ge1xuICAgIHN3aXRjaCAocHJvcFR5cGUpIHtcbiAgICAgIGNhc2UgXCJpbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgY2FzZSBcImJpZ0ludGVnZXJcIjpcbiAgICAgICAgcmV0dXJuIDBuO1xuICAgICAgY2FzZSBcImZsb2F0XCI6XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gMDtcbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIGNhc2UgXCJkYXRlXCI6XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZSgpO1xuICAgICAgY2FzZSBcImpzb25cIjpcbiAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgICAgcmV0dXJuIFwiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwXCI7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHBhcnNlU2NhbGFyVmFsdWUodGV4dDogc3RyaW5nLCBwcm9wVHlwZTogc3RyaW5nKTogdW5rbm93biB7XG4gICAgY29uc3QgY2xlYW5lZCA9IHRleHQudHJpbSgpO1xuXG4gICAgc3dpdGNoIChwcm9wVHlwZSkge1xuICAgICAgY2FzZSBcImludGVnZXJcIjoge1xuICAgICAgICBjb25zdCBudW0gPSBwYXJzZUludChjbGVhbmVkLCAxMCk7XG4gICAgICAgIHJldHVybiBOdW1iZXIuaXNOYU4obnVtKSA/IDAgOiBudW07XG4gICAgICB9XG4gICAgICBjYXNlIFwiYmlnSW50ZWdlclwiOiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIEJpZ0ludChjbGVhbmVkKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgcmV0dXJuIDBuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjYXNlIFwiZmxvYXRcIjpcbiAgICAgIGNhc2UgXCJudW1iZXJcIjpcbiAgICAgIGNhc2UgXCJudW1lcmljXCI6IHtcbiAgICAgICAgY29uc3QgbnVtID0gcGFyc2VGbG9hdChjbGVhbmVkKTtcbiAgICAgICAgcmV0dXJuIE51bWJlci5pc05hTihudW0pID8gMCA6IG51bTtcbiAgICAgIH1cbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBjbGVhbmVkLnRvTG93ZXJDYXNlKCkgPT09IFwidHJ1ZVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjoge1xuICAgICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoY2xlYW5lZCk7XG4gICAgICAgIHJldHVybiBOdW1iZXIuaXNOYU4oZGF0ZS5nZXRUaW1lKCkpID8gbmV3IERhdGUoKSA6IGRhdGU7XG4gICAgICB9XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICB0cnkge1xuICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGNsZWFuZWQpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm4gY2xlYW5lZDtcbiAgICAgICAgfVxuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgIGNhc2UgXCJlbnVtXCI6XG4gICAgICAgIHJldHVybiBjbGVhbmVkO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGNsZWFuZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIGZha2VyIO2VqOyImCDsnbjsnpAg66y47J6Q7Je07J2EIO2MjOyLse2VmOyXrCDsnbjsnpAg67Cw7Je066GcIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICogM+uLqOqzhCDsoITrnrU6XG4gICAqIDEuIEpTT04g7KeB7KCRIO2MjOyLsSAo7ZGc7KSAIEpTT04g7ZGc7ZiE7IudKVxuICAgKiAyLiBKUyDqsJ3ssrQg66as7YSw65+0IOKGkiBKU09OIOuzgO2ZmCDtm4Qg7J6s7Iuc64+EIChzaW5nbGUgcXVvdGUsIHVucXVvdGVkIGtleSDsspjrpqwpXG4gICAqIDMuIOuLqOyInCDri6jsnbwg7J247J6QIO2PtOuwsSAo7Iir7J6QLCDrrLjsnpDsl7QpXG4gICAqL1xuICBwcml2YXRlIHBhcnNlR2VuZXJhdG9yQXJncyhhcmdzU3RyOiBzdHJpbmcsIHByb3BOYW1lOiBzdHJpbmcpOiB1bmtub3duW10ge1xuICAgIC8vIDEuIEpTT04g7KeB7KCRIO2MjOyLsVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGBbJHthcmdzU3RyfV1gKSBhcyB1bmtub3duO1xuICAgICAgcmV0dXJuIEFycmF5LmlzQXJyYXkocGFyc2VkKSA/IHBhcnNlZCA6IFtwYXJzZWRdO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8g6rOE7IaNXG4gICAgfVxuXG4gICAgLy8gMi4gSlMg6rCd7LK0IOumrO2EsOuftCDihpIgSlNPTiDrs4DtmZgg7ZuEIOyerOyLnOuPhFxuICAgIHRyeSB7XG4gICAgICBjb25zdCBqc29uU3RyID0gdGhpcy5jb252ZXJ0SnNMaXRlcmFsVG9Kc29uKGFyZ3NTdHIpO1xuICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShgWyR7anNvblN0cn1dYCkgYXMgdW5rbm93bjtcbiAgICAgIHJldHVybiBBcnJheS5pc0FycmF5KHBhcnNlZCkgPyBwYXJzZWQgOiBbcGFyc2VkXTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIOqzhOyGjVxuICAgIH1cblxuICAgIC8vIDMuIOuLqOyInCDri6jsnbwg7J247J6QIO2PtOuwsVxuICAgIGNvbnN0IHRyaW1tZWQgPSBhcmdzU3RyLnRyaW0oKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihOdW1iZXIodHJpbW1lZCkpKSB7XG4gICAgICByZXR1cm4gW051bWJlcih0cmltbWVkKV07XG4gICAgfVxuICAgIGlmIChcbiAgICAgICh0cmltbWVkLnN0YXJ0c1dpdGgoJ1wiJykgJiYgdHJpbW1lZC5lbmRzV2l0aCgnXCInKSkgfHxcbiAgICAgICh0cmltbWVkLnN0YXJ0c1dpdGgoXCInXCIpICYmIHRyaW1tZWQuZW5kc1dpdGgoXCInXCIpKVxuICAgICkge1xuICAgICAgcmV0dXJuIFt0cmltbWVkLnNsaWNlKDEsIC0xKV07XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBGaXh0dXJlR2VuZXJhdG9yOiBDYW5ub3QgcGFyc2UgYXJndW1lbnRzIGZvciAke3Byb3BOYW1lfTogJHthcmdzU3RyfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEpTIOqwneyytCDrpqzthLDrn7TsnYQgSlNPTuycvOuhnCDrs4DtmZjtlanri4jri6QuXG4gICAqXG4gICAqIOuRkCDqsIDsp4Ag67OA7ZmYOlxuICAgKiAxLiBTaW5nbGUtcXVvdGVkIOusuOyekOyXtCDihpIgZG91YmxlLXF1b3RlZCAo7J207Iqk7LyA7J207ZSEIOyymOumrCDtj6ztlagpXG4gICAqIDIuIFVucXVvdGVkIOqwneyytCDtgqQg4oaSIGRvdWJsZS1xdW90ZWRcbiAgICovXG4gIHByaXZhdGUgY29udmVydEpzTGl0ZXJhbFRvSnNvbihpbnB1dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyAxLiAndmFsdWUnIOKGkiBcInZhbHVlXCIgKOuCtOu2gCBcIiDsnbTsiqTsvIDsnbTtlIQsIFxcJyDihpIgJylcbiAgICBjb25zdCB3aXRoRG91YmxlUXVvdGVzID0gaW5wdXQucmVwbGFjZShcbiAgICAgIC8nKFteJ1xcXFxdKig/OlxcXFwuW14nXFxcXF0qKSopJy9nLFxuICAgICAgKF8sIGNvbnRlbnQ6IHN0cmluZykgPT4gYFwiJHtjb250ZW50LnJlcGxhY2UoL1wiL2csICdcXFxcXCInKS5yZXBsYWNlKC9cXFxcJy9nLCBcIidcIil9XCJgLFxuICAgICk7XG5cbiAgICAvLyAyLiB7IGtleTog4oaSIHsgXCJrZXlcIjpcbiAgICByZXR1cm4gd2l0aERvdWJsZVF1b3Rlcy5yZXBsYWNlKC8oW3ssXVxccyopKFthLXpBLVpfJF1bXFx3JF0qKShcXHMqOikvZywgJyQxXCIkMlwiJDMnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTb25hbXUuc2VjcmV07J2EIOyasOyEoOycvOuhnCDtlZjqs6AsIOyXhuycvOuptCDtmZjqsr3rs4DsiJjsl5DshJwgQVBJIO2CpOulvCDsnb3sirXri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdS5zZWNyZXTsnYAg7ZSE66Gc7KCd7Yq467OEIOyEpOyglShzb25hbXUuY29uZmlnLnRzKeydtOuvgOuhnCDrjZQg64aS7J2AIOyasOyEoOyInOychOulvCDqsIDsp4DrqbAsXG4gICAqIO2ZmOqyveuzgOyImOuKlCDqsJzrsJwg7ZmY6rK97J2064KYIENJL0NE7JeQ7IScIGZhbGxiYWNr7Jy866GcIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgZ2V0QXBpS2V5KCk6IHN0cmluZyB7XG4gICAgbGV0IGFwaUtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgU29uYW11IH0gPSByZXF1aXJlKFwiLi4vYXBpXCIpO1xuICAgICAgYXBpS2V5ID0gU29uYW11LnNlY3JldHM/LmFudGhyb3BpY19hcGlfa2V5O1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gU29uYW116rCAIOy0iOq4sO2ZlOuQmOyngCDslYrsnYAg6rK97JqwICjthYzsiqTtirgg7ZmY6rK9IOuTsSlcbiAgICB9XG5cbiAgICBpZiAoIWFwaUtleSkge1xuICAgICAgYXBpS2V5ID0gcHJvY2Vzcy5lbnYuQU5USFJPUElDX0FQSV9LRVk7XG4gICAgfVxuXG4gICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJBTlRIUk9QSUNfQVBJX0tFWSBub3QgZm91bmQuIFNldCBpdCBpbiBlbnZpcm9ubWVudCB2YXJpYWJsZXMgb3IgU29uYW11LnNlY3JldC5hbnRocm9waWNfYXBpX2tleVwiLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXBpS2V5O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRFeHBlY3RlZEZvcm1hdChwcm9wVHlwZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyDrsLDsl7Qg7YOA7J6FIOyymOumrFxuICAgIGlmIChwcm9wVHlwZS5lbmRzV2l0aChcIltdXCIpKSB7XG4gICAgICBjb25zdCBiYXNlVHlwZSA9IHByb3BUeXBlLnNsaWNlKDAsIC0yKTtcbiAgICAgIGNvbnN0IGJhc2VGb3JtYXQgPSB0aGlzLmdldFNjYWxhckZvcm1hdChiYXNlVHlwZSk7XG4gICAgICByZXR1cm4gYEpTT04gYXJyYXkgb2YgJHtiYXNlRm9ybWF0fSAoZS5nLiwgWyR7dGhpcy5nZXRFeGFtcGxlRm9yVHlwZShiYXNlVHlwZSwgXCJlblwiKX0sIC4uLl0pYDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5nZXRTY2FsYXJGb3JtYXQocHJvcFR5cGUpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRTY2FsYXJGb3JtYXQocHJvcFR5cGU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgc3dpdGNoIChwcm9wVHlwZSkge1xuICAgICAgY2FzZSBcImludGVnZXJcIjpcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBcImludGVnZXIgbnVtYmVyc1wiO1xuICAgICAgY2FzZSBcImZsb2F0XCI6XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gXCJkZWNpbWFsIG51bWJlcnNcIjtcbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBcImJvb2xlYW5zICh0cnVlIG9yIGZhbHNlKVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgcmV0dXJuIFwiSVNPIDg2MDEgZGF0ZSBzdHJpbmdzXCI7XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICByZXR1cm4gXCJ2YWxpZCBKU09OIG9iamVjdCBvciBhcnJheVwiO1xuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgICAgcmV0dXJuIFwiVVVJRCBzdHJpbmdzXCI7XG4gICAgICBjYXNlIFwiZW51bVwiOlxuICAgICAgICByZXR1cm4gXCJvbmUgb2YgdGhlIGFsbG93ZWQgZW51bSB2YWx1ZXNcIjtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBcInBsYWluIHRleHQgc3RyaW5nc1wiO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0RXhhbXBsZUZvclR5cGUocHJvcFR5cGU6IHN0cmluZywgbG9jYWxlOiBMb2NhbGUpOiBzdHJpbmcge1xuICAgIC8vIOuwsOyXtCDtg4DsnoUg7LKY66asXG4gICAgaWYgKHByb3BUeXBlLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgIGNvbnN0IGJhc2VUeXBlID0gcHJvcFR5cGUuc2xpY2UoMCwgLTIpO1xuICAgICAgY29uc3QgYmFzZUV4YW1wbGUgPSB0aGlzLmdldFNjYWxhckV4YW1wbGUoYmFzZVR5cGUsIGxvY2FsZSk7XG4gICAgICByZXR1cm4gYFske2Jhc2VFeGFtcGxlfV1gO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmdldFNjYWxhckV4YW1wbGUocHJvcFR5cGUsIGxvY2FsZSk7XG4gIH1cblxuICBwcml2YXRlIGdldFNjYWxhckV4YW1wbGUocHJvcFR5cGU6IHN0cmluZywgbG9jYWxlOiBMb2NhbGUpOiBzdHJpbmcge1xuICAgIGNvbnN0IGlzS29yZWFuID0gbG9jYWxlID09PSBcImtvXCI7XG5cbiAgICBzd2l0Y2ggKHByb3BUeXBlKSB7XG4gICAgICBjYXNlIFwiaW50ZWdlclwiOlxuICAgICAgY2FzZSBcImJpZ0ludGVnZXJcIjpcbiAgICAgICAgcmV0dXJuIFwiNDJcIjtcbiAgICAgIGNhc2UgXCJmbG9hdFwiOlxuICAgICAgY2FzZSBcIm51bWJlclwiOlxuICAgICAgY2FzZSBcIm51bWVyaWNcIjpcbiAgICAgICAgcmV0dXJuIFwiMy4xNFwiO1xuICAgICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICAgICAgcmV0dXJuIFwidHJ1ZVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgcmV0dXJuIFwiMjAyNC0wMS0wMVwiO1xuICAgICAgY2FzZSBcImpzb25cIjpcbiAgICAgICAgcmV0dXJuICd7XCJrZXlcIjogXCJ2YWx1ZVwifSc7XG4gICAgICBjYXNlIFwidXVpZFwiOlxuICAgICAgICByZXR1cm4gXCI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDBcIjtcbiAgICAgIGNhc2UgXCJlbnVtXCI6XG4gICAgICAgIHJldHVybiBcIkVOVU1fVkFMVUVcIjtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBpc0tvcmVhbiA/IFwi7JWI64WV7ZWY7IS47JqUXCIgOiBcIkhlbGxvXCI7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOydtOumhOydhCDsnbTrqZTsnbwg66Gc7LusIO2MjO2KuOyaqSDroZzrp4jrgpjsnbTspojrk5wg66y47J6Q7Je066GcIOuzgO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICog7ZWc6riAIOydtOumhOydgCDstIjshLEt7KSR7ISxLeyiheyEsSDrtoTtlbQg7ZuEIOuhnOuniOuCmOydtOymiCDsspjrpqztlanri4jri6QuXG4gICAqIOyYgeusuCDsnbTrpoTsnYAg7IaM66y47J6Q66GcIOuzgO2ZmO2VmOqzoCDqs7XrsLHsnYQg7KCQKC4pXFx1YzczY+uhnCDsuZjtmZjtlanri4jri6QuXG4gICAqIOyYiDogXCLquYDssqDsiJhcIiDihpIgXCJjaGVvbHN1LmtpbVwiLCBcIkpvaG4gRG9lXCIg4oaSIFwiam9obi5kb2VcIlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByb21hbml6ZU5hbWUobmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAvLyDtlZzquIAg7Y+s7ZWoIOyXrOu2gCDtmZXsnbhcbiAgICBpZiAoL1tcXHVBQzAwLVxcdUQ3QUZdLy50ZXN0KG5hbWUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5yb21hbml6ZUtvcmVhbk5hbWUobmFtZSk7XG4gICAgfVxuICAgIC8vIOyYgeusuDog7IaM66y47J6QICsg7KCQIOq1rOu2hFxuICAgIHJldHVybiBuYW1lXG4gICAgICAudG9Mb3dlckNhc2UoKVxuICAgICAgLnJlcGxhY2UoL1xccysvZywgXCIuXCIpXG4gICAgICAucmVwbGFjZSgvW15hLXowLTkuXS9nLCBcIlwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZzquIAg7J2066aE7J2EIOuhnOuniOuCmOydtOymiCDsspjrpqztlanri4jri6QuXG4gICAqXG4gICAqIOy0iOyEsS/spJHshLEv7KKF7ISxIOunpO2VkSDthYzsnbTruJTsnYQg7IKs7Jqp7ZWY7JesIO2VnOq4gOydhCDroZzrp4jsnpDroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKiDssqsg6riA7J6Q66W8IOyEseycvOuhnCDqsITso7ztlZjsl6wgXCLquYDssqDsiJhcIiDihpIgXCJjaGVvbHN1LmtpbVwiIO2Yle2DnOuhnCDstpzroKXtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIHJvbWFuaXplS29yZWFuTmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IENIT1NFT05HID0gW1xuICAgICAgXCJnXCIsXG4gICAgICBcImtrXCIsXG4gICAgICBcIm5cIixcbiAgICAgIFwiZFwiLFxuICAgICAgXCJ0dFwiLFxuICAgICAgXCJyXCIsXG4gICAgICBcIm1cIixcbiAgICAgIFwiYlwiLFxuICAgICAgXCJwcFwiLFxuICAgICAgXCJzXCIsXG4gICAgICBcInNzXCIsXG4gICAgICBcIlwiLFxuICAgICAgXCJqXCIsXG4gICAgICBcImpqXCIsXG4gICAgICBcImNoXCIsXG4gICAgICBcImtcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJwXCIsXG4gICAgICBcImhcIixcbiAgICBdO1xuICAgIGNvbnN0IEpVTkdTRU9ORyA9IFtcbiAgICAgIFwiYVwiLFxuICAgICAgXCJhZVwiLFxuICAgICAgXCJ5YVwiLFxuICAgICAgXCJ5YWVcIixcbiAgICAgIFwiZW9cIixcbiAgICAgIFwiZVwiLFxuICAgICAgXCJ5ZW9cIixcbiAgICAgIFwieWVcIixcbiAgICAgIFwib1wiLFxuICAgICAgXCJ3YVwiLFxuICAgICAgXCJ3YWVcIixcbiAgICAgIFwib2VcIixcbiAgICAgIFwieW9cIixcbiAgICAgIFwidVwiLFxuICAgICAgXCJ3b1wiLFxuICAgICAgXCJ3ZVwiLFxuICAgICAgXCJ3aVwiLFxuICAgICAgXCJ5dVwiLFxuICAgICAgXCJldVwiLFxuICAgICAgXCJ1aVwiLFxuICAgICAgXCJpXCIsXG4gICAgXTtcbiAgICBjb25zdCBKT05HU0VPTkcgPSBbXG4gICAgICBcIlwiLFxuICAgICAgXCJrXCIsXG4gICAgICBcImtcIixcbiAgICAgIFwia1wiLFxuICAgICAgXCJuXCIsXG4gICAgICBcIm5cIixcbiAgICAgIFwiblwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJsXCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJsXCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJtXCIsXG4gICAgICBcInBcIixcbiAgICAgIFwicFwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcInRcIixcbiAgICAgIFwibmdcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcImtcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJwXCIsXG4gICAgICBcInRcIixcbiAgICBdO1xuXG4gICAgY29uc3Qgcm9tYW5pemUgPSAoY2hhcjogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICAgIGNvbnN0IGNvZGUgPSBjaGFyLmNoYXJDb2RlQXQoMCk7XG4gICAgICBpZiAoY29kZSA8IDB4YWMwMCB8fCBjb2RlID4gMHhkN2FmKSByZXR1cm4gY2hhcjtcbiAgICAgIGNvbnN0IG9mZnNldCA9IGNvZGUgLSAweGFjMDA7XG4gICAgICBjb25zdCBjaG8gPSBNYXRoLmZsb29yKG9mZnNldCAvIDU4OCk7XG4gICAgICBjb25zdCBqdW5nID0gTWF0aC5mbG9vcigob2Zmc2V0ICUgNTg4KSAvIDI4KTtcbiAgICAgIGNvbnN0IGpvbmcgPSBvZmZzZXQgJSAyODtcbiAgICAgIHJldHVybiBDSE9TRU9OR1tjaG9dICsgSlVOR1NFT05HW2p1bmddICsgSk9OR1NFT05HW2pvbmddO1xuICAgIH07XG5cbiAgICBjb25zdCBjaGFycyA9IFsuLi5uYW1lXTtcbiAgICAvLyDssqsg6riA7J6Q66W8IOyEsSjlp5Mp7Jy866GcIOqwhOyjvFxuICAgIGNvbnN0IGZhbWlseU5hbWUgPSByb21hbml6ZShjaGFyc1swXSk7XG4gICAgY29uc3QgZ2l2ZW5OYW1lID0gY2hhcnMuc2xpY2UoMSkubWFwKHJvbWFuaXplKS5qb2luKFwiXCIpO1xuXG4gICAgaWYgKGdpdmVuTmFtZSkge1xuICAgICAgcmV0dXJuIGAke2dpdmVuTmFtZX0uJHtmYW1pbHlOYW1lfWA7XG4gICAgfVxuICAgIHJldHVybiBmYW1pbHlOYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIExMTSDsupDsi5wg7Ya16rOE66W8IOuwmO2ZmO2VqeuLiOuLpC5cbiAgICovXG4gIGdldExMTUNhY2hlU3RhdHMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMubGxtQ2FjaGUuc2l6ZSxcbiAgICAgIGVuYWJsZWQ6IHRoaXMub3B0aW9ucy5lbmFibGVMTE1DYWNoZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIExMTSDsupDsi5zrpbwg7LSI6riw7ZmU7ZWp64uI64ukLlxuICAgKi9cbiAgY2xlYXJMTE1DYWNoZSgpIHtcbiAgICB0aGlzLmxsbUNhY2hlLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICog7Luo7YWN7Iqk7Yq4IOyDneyEsVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVDb250ZXh0KCk6IEdlbmVyYXRvckNvbnRleHQge1xuICAgIHJldHVybiB7XG4gICAgICBmaXh0dXJlczogbmV3IE1hcCgpLFxuICAgICAgcmVmZXJlbmNlQ2FjaGU6IG5ldyBNYXAoKSxcbiAgICAgIGltcG9ydGVkUmVjb3JkczogbmV3IFNldCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog67Cw7LmYIOyDneyEsSDrsI8g7J6Q64+ZIOyggOyepVxuICAgKlxuICAgKiAxLiDqsIEgc3BlY+uzhOuhnCBmaXh0dXJlIOyDneyEsSAo66mU66qo66asKVxuICAgKiAyLiBGaXh0dXJlUmVjb3Jk66GcIOuzgO2ZmFxuICAgKiAzLiBGaXh0dXJlTWFuYWdlci5pbnNlcnRGaXh0dXJlcygp66GcIHRhcmdldERi7JeQIOyggOyepVxuICAgKlxuICAgKiBAcmV0dXJucyDsoIDsnqXrkJwgZml4dHVyZSDrjbDsnbTthLAgKOyLpOygnCBEQiBJRCDtj6ztlagpXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUJhdGNoKFxuICAgIHNwZWNzOiBBcnJheTx7IGVudGl0eTogc3RyaW5nOyBjb3VudDogbnVtYmVyOyBvdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PixcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KCk7XG4gICAgY29uc3QgZ2VuZXJhdGVkRml4dHVyZXM6IEFycmF5PHtcbiAgICAgIGVudGl0eTogc3RyaW5nO1xuICAgICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICBleHBsaWNpdElkPzogYm9vbGVhbjtcbiAgICB9PiA9IFtdO1xuXG4gICAgLy8gMS4g6rCBIHNwZWPrs4TroZwgZml4dHVyZSDsg53shLFcbiAgICBmb3IgKGNvbnN0IHNwZWMgb2Ygc3BlY3MpIHtcbiAgICAgIGNvbnN0IHNwZWNFbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KHNwZWMuZW50aXR5KTtcblxuICAgICAgaWYgKHNwZWNFbnRpdHkucGFyZW50SWQpIHtcbiAgICAgICAgLy8gcGFyZW50SWQg7JeU7Yuw7YuwOiBEQuyXkOyEnCDshJzruIztg4DsnoUg7ZaJ7J20IOyXhuuKlCDrtoDrqqggaWTrpbwg7KGw7ZqM7ZWY7JesIOyCrOyaqVxuICAgICAgICAvLyAo7IOIIOu2gOuqqCDsg53shLEg64yA7IugIOq4sOyhtCDrjbDsnbTthLAg7J6s7Zmc7JqpKVxuICAgICAgICBjb25zdCBpZFByb3AgPSBzcGVjRW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gXCJpZFwiKTtcbiAgICAgICAgY29uc3QgcGFyZW50T3ZlcnJpZGVzID1cbiAgICAgICAgICAoaWRQcm9wPy5jb25lPy5maXh0dXJlUGFyZW50T3ZlcnJpZGVzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkKSA/PyB7fTtcbiAgICAgICAgY29uc3QgcGFyZW50RW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChzcGVjRW50aXR5LnBhcmVudElkKTtcblxuICAgICAgICAvLyDrtoDrqqgg7YWM7J2067iU7JeQ7IScIOyEnOu4jO2DgOyehSDthYzsnbTruJTsl5Ag7JeG64qUIGlk66W8IOyhsO2ajFxuICAgICAgICBsZXQgcXVlcnkgPSB0aGlzLnNvdXJjZURiKHBhcmVudEVudGl0eS50YWJsZSkuc2VsZWN0KGAke3BhcmVudEVudGl0eS50YWJsZX0uaWRgKTtcbiAgICAgICAgZm9yIChjb25zdCBbY29sLCB2YWxdIG9mIE9iamVjdC5lbnRyaWVzKHBhcmVudE92ZXJyaWRlcykpIHtcbiAgICAgICAgICBxdWVyeSA9IHF1ZXJ5LndoZXJlKFxuICAgICAgICAgICAgYCR7cGFyZW50RW50aXR5LnRhYmxlfS4ke2NvbH1gLFxuICAgICAgICAgICAgdmFsIGFzIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcXVlcnkgPSBxdWVyeVxuICAgICAgICAgIC5sZWZ0Sm9pbihzcGVjRW50aXR5LnRhYmxlLCBgJHtzcGVjRW50aXR5LnRhYmxlfS5pZGAsIGAke3BhcmVudEVudGl0eS50YWJsZX0uaWRgKVxuICAgICAgICAgIC53aGVyZU51bGwoYCR7c3BlY0VudGl0eS50YWJsZX0uaWRgKVxuICAgICAgICAgIC5saW1pdChzcGVjLmNvdW50KTtcblxuICAgICAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnk7XG4gICAgICAgIGNvbnN0IGF2YWlsYWJsZUlkczogbnVtYmVyW10gPSByb3dzLm1hcCgocjogeyBpZDogbnVtYmVyIH0pID0+IHIuaWQpO1xuXG4gICAgICAgIGlmIChhdmFpbGFibGVJZHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgW3BhcmVudElkXSAke3NwZWMuZW50aXR5fTog7ISc67iM7YOA7J6F7J20IOyXhuuKlCDrtoDrqqgg66CI7L2U65Oc6rCAIOu2gOyhse2VqeuLiOuLpC4g6rG064SI65yB64uI64ukLmAsXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZvciAoY29uc3QgcGFyZW50SWQgb2YgYXZhaWxhYmxlSWRzKSB7XG4gICAgICAgICAgICBjb25zdCBmaXh0dXJlID0gYXdhaXQgdGhpcy5nZW5lcmF0ZShzcGVjLmVudGl0eSwgc3BlYy5vdmVycmlkZXMgfHwge30sIGNvbnRleHQpO1xuICAgICAgICAgICAgZml4dHVyZS5pZCA9IHBhcmVudElkO1xuICAgICAgICAgICAgZ2VuZXJhdGVkRml4dHVyZXMucHVzaCh7IGVudGl0eTogc3BlYy5lbnRpdHksIGRhdGE6IGZpeHR1cmUsIGV4cGxpY2l0SWQ6IHRydWUgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNwZWMuY291bnQ7IGkrKykge1xuICAgICAgICAgIGNvbnN0IGZpeHR1cmUgPSBhd2FpdCB0aGlzLmdlbmVyYXRlKHNwZWMuZW50aXR5LCBzcGVjLm92ZXJyaWRlcyB8fCB7fSwgY29udGV4dCk7XG4gICAgICAgICAgZ2VuZXJhdGVkRml4dHVyZXMucHVzaCh7XG4gICAgICAgICAgICBlbnRpdHk6IHNwZWMuZW50aXR5LFxuICAgICAgICAgICAgZGF0YTogZml4dHVyZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDIuIEZpeHR1cmVSZWNvcmTroZwg67OA7ZmYXG4gICAgY29uc3QgZml4dHVyZVJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgeyBlbnRpdHk6IGVudGl0eU5hbWUsIGRhdGEsIGV4cGxpY2l0SWQgfSBvZiBnZW5lcmF0ZWRGaXh0dXJlcykge1xuICAgICAgY29uc3QgZW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlOYW1lKTtcblxuICAgICAgLy8gaW50ZWdlci9iaWdJbnRlZ2VyIFBL64qUIOyehOyLnCBJRCDsg53shLEgKERCIOyLnO2AgOyKpOqwgCDsi6TsoJwgSUQg7ZWg64u5KVxuICAgICAgLy8gc3RyaW5nIFBL64qUIGdlbmVyYXRlKCnsl5DshJwg7J2066+4IOyDneyEseuQnCBpZCDqsJLsnYQg6re464yA66GcIOyCrOyaqVxuICAgICAgLy8gcGFyZW50SWQg7JeU7Yuw7Yuw64qUIOu2gOuqqOydmCDsi6TsoJwgaWTrpbwg6re464yA66GcIOyCrOyaqSAo7Iuc7YCA7IqkIOuvuOyCrOyaqSlcbiAgICAgIGNvbnN0IGlkUHJvcCA9IGVudGl0eS5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IFwiaWRcIik7XG4gICAgICBjb25zdCB1c2VzU2VxdWVuY2UgPVxuICAgICAgICAhZXhwbGljaXRJZCAmJlxuICAgICAgICAoaWRQcm9wPy50eXBlID09PSBcImludGVnZXJcIiB8fFxuICAgICAgICAgIGlkUHJvcD8udHlwZSA9PT0gXCJiaWdJbnRlZ2VyXCIgfHxcbiAgICAgICAgICBpZFByb3A/LmNvbmU/LmZpeHR1cmVTdHJhdGVneSA9PT0gXCJzZXF1ZW5jZVwiKTtcblxuICAgICAgY29uc3QgZGF0YUZvclJlY29yZCA9IHVzZXNTZXF1ZW5jZVxuICAgICAgICA/IHsgLi4uZGF0YSwgaWQ6IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMDAwMDApIH1cbiAgICAgICAgOiBkYXRhO1xuXG4gICAgICBjb25zdCByZWNvcmRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuY3JlYXRlRml4dHVyZVJlY29yZChcbiAgICAgICAgZW50aXR5LFxuICAgICAgICBkYXRhRm9yUmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgeyBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICk7XG4gICAgICBmaXh0dXJlUmVjb3Jkcy5wdXNoKC4uLnJlY29yZHMpO1xuICAgIH1cblxuICAgIC8vIDMuIHRhcmdldERi7JeQIOyCveyehSAoRml4dHVyZU1hbmFnZXLqsIAg7J2Y7KG07ISxIOygleugrCDsspjrpqwpXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVzKHRoaXMudGFyZ2V0RGJOYW1lLCBmaXh0dXJlUmVjb3Jkcyk7XG5cbiAgICAvLyA0LiBjb21wYW5pb24gZml4dHVyZXMg7IOd7ISxIChmaXh0dXJlQ29tcGFuaW9uc+qwgCDshKDslrjrkJwg6rK97JqwKVxuICAgIGNvbnN0IGNvbXBhbmlvblJlc3VsdHMgPSBhd2FpdCB0aGlzLmdlbmVyYXRlQ29tcGFuaW9ucyhzcGVjcywgcmVzdWx0cyk7XG5cbiAgICBjb25zdCB0b3RhbCA9IHJlc3VsdHMubGVuZ3RoICsgY29tcGFuaW9uUmVzdWx0cy5sZW5ndGg7XG4gICAgIWlzVGVzdCgpICYmXG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgR2VuZXJhdGVkIGFuZCBzYXZlZCAke3RvdGFsfSBmaXh0dXJlcyB0byAke3RoaXMudGFyZ2V0RGJOYW1lfWApKTtcbiAgICByZXR1cm4gWy4uLnJlc3VsdHMsIC4uLmNvbXBhbmlvblJlc3VsdHNdO1xuICB9XG5cbiAgLyoqXG4gICAqIOu2gOuqqCBmaXh0dXJlIOqysOqzvOulvCDquLDrsJjsnLzroZwgZml4dHVyZUNvbXBhbmlvbnPsl5Ag7ISg7Ja465CcIGNvbXBhbmlvbiBFbnRpdHnrpbwg7IOd7ISx7ZWp64uI64ukLlxuICAgKlxuICAgKiBnZW5lcmF0ZUJhdGNoKCnsl5DshJzrp4wg7Zi47Lac65CY66mwLCBjb21wYW5pb24g7IOd7ISxIOyLnCDsnqzqt4Drpbwg67Cp7KeA7ZWY6riwIOychO2VtFxuICAgKiBnZW5lcmF0ZUJhdGNoKCnrpbwg64uk7IucIO2YuOy2nO2VmOyngCDslYrqs6Ag7KeB7KCRIOyCveyehe2VqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVDb21wYW5pb25zKFxuICAgIHNwZWNzOiBBcnJheTx7IGVudGl0eTogc3RyaW5nOyBjb3VudDogbnVtYmVyOyBvdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PixcbiAgICBwYXJlbnRSZXN1bHRzOiBGaXh0dXJlSW1wb3J0UmVzdWx0W10sXG4gICk6IFByb21pc2U8Rml4dHVyZUltcG9ydFJlc3VsdFtdPiB7XG4gICAgY29uc3QgYWxsUmVzdWx0czogRml4dHVyZUltcG9ydFJlc3VsdFtdID0gW107XG4gICAgY29uc3QgcHJvY2Vzc2VkRW50aXRpZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICAgIGZvciAoY29uc3Qgc3BlYyBvZiBzcGVjcykge1xuICAgICAgaWYgKHByb2Nlc3NlZEVudGl0aWVzLmhhcyhzcGVjLmVudGl0eSkpIGNvbnRpbnVlO1xuICAgICAgcHJvY2Vzc2VkRW50aXRpZXMuYWRkKHNwZWMuZW50aXR5KTtcblxuICAgICAgY29uc3QgZW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChzcGVjLmVudGl0eSk7XG4gICAgICBjb25zdCBpZFByb3AgPSBlbnRpdHkucHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBcImlkXCIpO1xuICAgICAgY29uc3QgY29tcGFuaW9ucyA9IGlkUHJvcD8uY29uZT8uZml4dHVyZUNvbXBhbmlvbnM7XG4gICAgICBpZiAoIWNvbXBhbmlvbnMgfHwgY29tcGFuaW9ucy5sZW5ndGggPT09IDApIGNvbnRpbnVlO1xuXG4gICAgICBjb25zdCBlbnRpdHlSZXN1bHRzID0gcGFyZW50UmVzdWx0cy5maWx0ZXIoKHIpID0+IHIuZW50aXR5SWQgPT09IHNwZWMuZW50aXR5KTtcbiAgICAgIGlmIChlbnRpdHlSZXN1bHRzLmxlbmd0aCA9PT0gMCkgY29udGludWU7XG5cbiAgICAgIGZvciAoY29uc3QgY29tcGFuaW9uIG9mIGNvbXBhbmlvbnMpIHtcbiAgICAgICAgLy8gY29tcGFuaW9uIGVudGl0eeyXkOyEnCDrtoDrqqggZW50aXR566Gc7J2YIEJlbG9uZ3NUb09uZSBGSyDsu6zrn7zrqoUg7YyM7JWFXG4gICAgICAgIGNvbnN0IGNvbXBhbmlvbkVudGl0eSA9IHRoaXMuZW50aXR5TWFuYWdlci5nZXQoY29tcGFuaW9uLmVudGl0eSk7XG4gICAgICAgIGNvbnN0IGZrUHJvcCA9IGNvbXBhbmlvbkVudGl0eS5wcm9wcy5maW5kKFxuICAgICAgICAgIChwKSA9PiBpc1JlbGF0aW9uUHJvcChwKSAmJiBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwKSAmJiBwLndpdGggPT09IHNwZWMuZW50aXR5LFxuICAgICAgICApO1xuICAgICAgICBpZiAoIWZrUHJvcCkge1xuICAgICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgICAgYFtDb21wYW5pb25dIE5vIEJlbG9uZ3NUb09uZSByZWxhdGlvbiBmcm9tICR7Y29tcGFuaW9uLmVudGl0eX0gdG8gJHtzcGVjLmVudGl0eX0uIFNraXBwaW5nLmAsXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGZrQ29sTmFtZSA9IGAke2ZrUHJvcC5uYW1lfV9pZGA7XG5cbiAgICAgICAgLy8gY29tcGFuaW9u7J2YIGlkUHJvcCwgdXNlc1NlcXVlbmNlLCBjb3VudOuKlCBjb21wYW5pb24g64uo7JyE66GcIOqzoOyglVxuICAgICAgICBjb25zdCBjb21wYW5pb25JZFByb3AgPSBjb21wYW5pb25FbnRpdHkucHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBcImlkXCIpO1xuICAgICAgICBjb25zdCB1c2VzU2VxdWVuY2UgPVxuICAgICAgICAgIGNvbXBhbmlvbklkUHJvcD8udHlwZSA9PT0gXCJpbnRlZ2VyXCIgfHxcbiAgICAgICAgICBjb21wYW5pb25JZFByb3A/LnR5cGUgPT09IFwiYmlnSW50ZWdlclwiIHx8XG4gICAgICAgICAgY29tcGFuaW9uSWRQcm9wPy5jb25lPy5maXh0dXJlU3RyYXRlZ3kgPT09IFwic2VxdWVuY2VcIjtcbiAgICAgICAgY29uc3QgY29tcGFuaW9uQ291bnQgPSBjb21wYW5pb24uY291bnQgPz8gMTtcblxuICAgICAgICAvLyDqsIEgcGFyZW50IHJlc3VsdOyXkCDrjIDtlbQgY29tcGFuaW9uIGZpeHR1cmUg7IOd7ISxXG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmNyZWF0ZUNvbnRleHQoKTtcbiAgICAgICAgY29uc3QgY29tcGFuaW9uRml4dHVyZVJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSA9IFtdO1xuXG4gICAgICAgIGZvciAoY29uc3QgcGFyZW50UmVzdWx0IG9mIGVudGl0eVJlc3VsdHMpIHtcbiAgICAgICAgICBjb25zdCByZXNvbHZlZE92ZXJyaWRlcyA9IHRoaXMucmVzb2x2ZVRlbXBsYXRlT3ZlcnJpZGVzKFxuICAgICAgICAgICAgY29tcGFuaW9uLm92ZXJyaWRlcyA/PyB7fSxcbiAgICAgICAgICAgIHBhcmVudFJlc3VsdC5kYXRhLFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmVzb2x2ZWRPdmVycmlkZXNbZmtDb2xOYW1lXSA9IHBhcmVudFJlc3VsdC5kYXRhLmlkO1xuXG4gICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb21wYW5pb25Db3VudDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBmaXh0dXJlID0gYXdhaXQgdGhpcy5nZW5lcmF0ZShjb21wYW5pb24uZW50aXR5LCByZXNvbHZlZE92ZXJyaWRlcywgY29udGV4dCk7XG5cbiAgICAgICAgICAgIGNvbnN0IGRhdGFGb3JSZWNvcmQgPSB1c2VzU2VxdWVuY2VcbiAgICAgICAgICAgICAgPyB7IC4uLmZpeHR1cmUsIGlkOiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAxMDAwMDAwKSB9XG4gICAgICAgICAgICAgIDogZml4dHVyZTtcblxuICAgICAgICAgICAgY29uc3QgcmVjb3JkcyA9IGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmNyZWF0ZUZpeHR1cmVSZWNvcmQoXG4gICAgICAgICAgICAgIGNvbXBhbmlvbkVudGl0eSxcbiAgICAgICAgICAgICAgZGF0YUZvclJlY29yZCBhcyB7XG4gICAgICAgICAgICAgICAgaWQ6IG51bWJlciB8IHN0cmluZztcbiAgICAgICAgICAgICAgICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbDtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgeyBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb21wYW5pb25GaXh0dXJlUmVjb3Jkcy5wdXNoKC4uLnJlY29yZHMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbXBhbmlvblJlc3VsdHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5pbnNlcnRGaXh0dXJlcyhcbiAgICAgICAgICB0aGlzLnRhcmdldERiTmFtZSxcbiAgICAgICAgICBjb21wYW5pb25GaXh0dXJlUmVjb3JkcyxcbiAgICAgICAgKTtcbiAgICAgICAgYWxsUmVzdWx0cy5wdXNoKC4uLmNvbXBhbmlvblJlc3VsdHMpO1xuXG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgY2hhbGsuZ3JlZW4oXG4gICAgICAgICAgICAgIGBbQ29tcGFuaW9uXSBHZW5lcmF0ZWQgJHtjb21wYW5pb25SZXN1bHRzLmxlbmd0aH0gJHtjb21wYW5pb24uZW50aXR5fSBmaXh0dXJlc2AsXG4gICAgICAgICAgICApLFxuICAgICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFsbFJlc3VsdHM7XG4gIH1cblxuICAvKipcbiAgICogb3ZlcnJpZGVzIOqwkuydmCBcInt7ZmllbGROYW1lfX1cIiDthZztlIzrpr/snYQg67aA66qoIGZpeHR1cmUg642w7J207YSw66GcIOy5mO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICog7JiIOiB7IFwiYWNjb3VudF9pZFwiOiBcInt7ZW1haWx9fVwiIH0g4oaSIHsgXCJhY2NvdW50X2lkXCI6IFwidXNlckBleGFtcGxlLmNvbVwiIH1cbiAgICovXG4gIHByaXZhdGUgcmVzb2x2ZVRlbXBsYXRlT3ZlcnJpZGVzKFxuICAgIG92ZXJyaWRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgcGFyZW50RGF0YTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgRGF0ZSB8IG51bGwgfSxcbiAgKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIGNvbnN0IHJlc29sdmVkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG92ZXJyaWRlcykpIHtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUuc3RhcnRzV2l0aChcInt7XCIpICYmIHZhbHVlLmVuZHNXaXRoKFwifX1cIikpIHtcbiAgICAgICAgY29uc3QgZmllbGROYW1lID0gdmFsdWUuc2xpY2UoMiwgLTIpLnRyaW0oKTtcbiAgICAgICAgaWYgKCEoZmllbGROYW1lIGluIHBhcmVudERhdGEpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYO2FnO2UjOumvyDtlYTrk5wgXCIke2ZpZWxkTmFtZX1cIuydtCjqsIApIOu2gOuqqCBmaXh0dXJlIOuNsOydtO2EsOyXkCDsobTsnqztlZjsp4Ag7JWK7Iq164uI64ukIChvdmVycmlkZSBrZXk6IFwiJHtrZXl9XCIpYCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJlc29sdmVkW2tleV0gPSBwYXJlbnREYXRhW2ZpZWxkTmFtZV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXNvbHZlZFtrZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXNvbHZlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiDsi6TsoJwgREIoc291cmNlRGIp7JeQ7IScIOuNsOydtO2EsOulvCDsobDtmoztlZjsl6wgZml4dHVyZSBEQih0YXJnZXREYinsl5AgaW1wb3J07ZWp64uI64ukLlxuICAgKlxuICAgKiAxLiBEYXRhRXhwbG9yZXLroZwgc291cmNlRGLsl5DshJwg642w7J207YSwIOyhsO2ajCAo6rSA66CoIOuNsOydtO2EsCDtj6ztlagpXG4gICAqIDIuIEZpeHR1cmVSZWNvcmTroZwg67OA7ZmYXG4gICAqIDMuIHRhcmdldERi7JeQIOyCveyehVxuICAgKlxuICAgKiBAcGFyYW0gZW50aXR5TmFtZSAtIOyhsO2ajO2VoCBlbnRpdHkg7J2066aEXG4gICAqIEBwYXJhbSBvcHRpb25zIC0g7KGw7ZqMIOyYteyFmCAoc3RyYXRlZ3ksIGxpbWl0LCBpbmNsdWRlUmVsYXRpb25zIOuTsSlcbiAgICogQHJldHVybnMg7KCA7J6l65CcIGZpeHR1cmUg642w7J207YSwICjsi6TsoJwgREIgSUQg7Y+s7ZWoKVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAvLyDtlITroZzrjZXshZggRELsl5DshJwgVXNlciAxMOuqhSArIOq0gOugqCBFbXBsb3llZSwgRGVwYXJ0bWVudCDqsIDsoLjsmKTquLBcbiAgICogYXdhaXQgZ2VuZXJhdG9yLmltcG9ydEZyb21Tb3VyY2UoXCJVc2VyXCIsIHtcbiAgICogICBzdHJhdGVneTogXCJzYW1wbGVcIixcbiAgICogICBsaW1pdDogMTAsXG4gICAqICAgaW5jbHVkZVJlbGF0aW9uczogdHJ1ZSxcbiAgICogICBtYXhEZXB0aDogMlxuICAgKiB9KTtcbiAgICovXG4gIGFzeW5jIGltcG9ydEZyb21Tb3VyY2UoXG4gICAgZW50aXR5TmFtZTogc3RyaW5nLFxuICAgIG9wdGlvbnM6IEV4cGxvcmVXaXRoUmVsYXRpb25zT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICAhaXNUZXN0KCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay5ibHVlKFxuICAgICAgICAgIGBJbXBvcnRpbmcgJHtlbnRpdHlOYW1lfSBmcm9tIHNvdXJjZSBEQiB3aXRoIG9wdGlvbnM6ICR7SlNPTi5zdHJpbmdpZnkoeyBzdHJhdGVneTogb3B0aW9ucy5zdHJhdGVneSwgbGltaXQ6IG9wdGlvbnMubGltaXQsIGluY2x1ZGVSZWxhdGlvbnM6IG9wdGlvbnMuaW5jbHVkZVJlbGF0aW9ucywgbWF4RGVwdGg6IG9wdGlvbnMubWF4RGVwdGggfSl9YCxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICAvLyAxLiBEYXRhRXhwbG9yZXLroZwgc291cmNlRGLsl5DshJwg642w7J207YSwIOyhsO2ajCAo6rSA66CoIOuNsOydtO2EsCDtj6ztlagpXG4gICAgY29uc3QgZXhwbG9yZVJlc3VsdCA9IGF3YWl0IHRoaXMuZGF0YUV4cGxvcmVyLmV4cGxvcmVXaXRoUmVsYXRpb25zKGVudGl0eU5hbWUsIG9wdGlvbnMpO1xuXG4gICAgIWlzVGVzdCgpICYmXG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgY2hhbGsuY3lhbihcbiAgICAgICAgICBgRm91bmQgJHtleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcy5sZW5ndGh9ICR7ZW50aXR5TmFtZX0gcmVjb3JkcyBhbmQgJHtleHBsb3JlUmVzdWx0LnJlbGF0ZWQuc2l6ZX0gcmVsYXRlZCBlbnRpdGllc2AsXG4gICAgICAgICksXG4gICAgICApO1xuXG4gICAgLy8gMi4gRml4dHVyZVJlY29yZOuhnCDrs4DtmZhcbiAgICBjb25zdCBmaXh0dXJlUmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gW107XG5cbiAgICAvLyDrqZTsnbggZW50aXR57J2YIHJlY29yZHPrpbwgRml4dHVyZVJlY29yZOuhnCDrs4DtmZhcbiAgICBjb25zdCBtYWluRW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlOYW1lKTtcbiAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcykge1xuICAgICAgY29uc3QgcmVjb3JkcyA9IGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmNyZWF0ZUZpeHR1cmVSZWNvcmQoXG4gICAgICAgIG1haW5FbnRpdHksXG4gICAgICAgIHJlY29yZCBhcyB7IGlkOiBudW1iZXIgfCBzdHJpbmc7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsIH0sXG4gICAgICAgIHsgX2RiOiB0aGlzLnNvdXJjZURiLCBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICk7XG4gICAgICBmaXh0dXJlUmVjb3Jkcy5wdXNoKC4uLnJlY29yZHMpO1xuICAgIH1cblxuICAgIC8vIOq0gOugqCBlbnRpdHnsnZggcmVjb3Jkc+ulvCBGaXh0dXJlUmVjb3Jk66GcIOuzgO2ZmFxuICAgIGZvciAoY29uc3QgW3JlbGF0ZWRFbnRpdHlOYW1lLCByZWxhdGVkUmVjb3Jkc10gb2YgZXhwbG9yZVJlc3VsdC5yZWxhdGVkLmVudHJpZXMoKSkge1xuICAgICAgY29uc3QgcmVsYXRlZEVudGl0eSA9IHRoaXMuZW50aXR5TWFuYWdlci5nZXQocmVsYXRlZEVudGl0eU5hbWUpO1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgcmVsYXRlZFJlY29yZHMpIHtcbiAgICAgICAgY29uc3QgcmVjb3JkcyA9IGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmNyZWF0ZUZpeHR1cmVSZWNvcmQoXG4gICAgICAgICAgcmVsYXRlZEVudGl0eSxcbiAgICAgICAgICByZWNvcmQgYXMgeyBpZDogbnVtYmVyIHwgc3RyaW5nOyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB9LFxuICAgICAgICAgIHsgX2RiOiB0aGlzLnNvdXJjZURiLCBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICAgKTtcbiAgICAgICAgZml4dHVyZVJlY29yZHMucHVzaCguLi5yZWNvcmRzKTtcbiAgICAgIH1cblxuICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyYXkoYCAgLSAke3JlbGF0ZWRFbnRpdHlOYW1lfTogJHtyZWxhdGVkUmVjb3Jkcy5sZW5ndGh9IHJlY29yZHNgKSk7XG4gICAgfVxuXG4gICAgLy8gMy4gdGFyZ2V0RGLsl5Ag7IK97J6FIChGaXh0dXJlTWFuYWdlcuqwgCDsnZjsobTshLEg7KCV66CsIOyymOumrClcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuaW5zZXJ0Rml4dHVyZXModGhpcy50YXJnZXREYk5hbWUsIGZpeHR1cmVSZWNvcmRzKTtcblxuICAgICFpc1Rlc3QoKSAmJlxuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLmdyZWVuKFxuICAgICAgICAgIGBTdWNjZXNzZnVsbHkgaW1wb3J0ZWQgJHtyZXN1bHRzLmxlbmd0aH0gcmVjb3JkcyB0byAke3RoaXMudGFyZ2V0RGJOYW1lfSAoJHtleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcy5sZW5ndGh9ICR7ZW50aXR5TmFtZX0gKyAke3Jlc3VsdHMubGVuZ3RoIC0gZXhwbG9yZVJlc3VsdC5tYWluLnJlY29yZHMubGVuZ3RofSByZWxhdGVkKWAsXG4gICAgICAgICksXG4gICAgICApO1xuXG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJjaGFsayIsImlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wIiwiaXNPbmVUb09uZVJlbGF0aW9uUHJvcCIsImlzUmVsYXRpb25Qcm9wIiwiaXNUZXN0IiwiRGF0YUV4cGxvcmVyIiwiZmFrZXJNYXBwaW5ncyIsIkZpeHR1cmVNYW5hZ2VyIiwiRml4dHVyZUdlbmVyYXRvciIsImRhdGFFeHBsb3JlciIsImxvY2FsZSIsIm1hcHBpbmdzIiwibGxtQ2FjaGUiLCJNYXAiLCJlbnRpdHlDYWNoZSIsIm9wdGlvbnMiLCJzb3VyY2VEYiIsIl90YXJnZXREYiIsInRhcmdldERiTmFtZSIsImVudGl0eU1hbmFnZXIiLCJ1c2VMTE0iLCJlbmFibGVMTE1DYWNoZSIsImxsbU1vZGVsIiwiZ2VuZXJhdGUiLCJlbnRpdHlOYW1lIiwib3ZlcnJpZGVzIiwiY29udGV4dCIsImNyZWF0ZUNvbnRleHQiLCJlbnRpdHkiLCJnZXQiLCJzZXQiLCJ0ZW1wSWQiLCJEYXRlIiwibm93Iiwicm93S2V5IiwidW5kZWZpbmVkIiwiZml4dHVyZSIsInByb3AiLCJwcm9wcyIsInZpcnR1YWwiLCJuYW1lIiwiY29uZSIsImZpeHR1cmVTdHJhdGVneSIsInR5cGUiLCJmYWtlciIsIl9mYWtlciIsInN0cmluZyIsImFscGhhbnVtZXJpYyIsInV1aWQiLCJma0NvbE5hbWUiLCJoYXNKb2luQ29sdW1uIiwicmVsYXRpb25WYWx1ZSIsImdlbmVyYXRlUmVsYXRpb25WYWx1ZSIsIm5vdGUiLCJsbG1WYWx1ZSIsImdlbmVyYXRlV2l0aExMTSIsImxlbmd0aCIsInNsaWNlIiwiZXJyb3IiLCJjb25zb2xlIiwid2FybiIsImlkIiwiRXJyb3IiLCJtZXNzYWdlIiwiZml4dHVyZUdlbmVyYXRvciIsImV4ZWN1dGVHZW5lcmF0b3IiLCJmaXh0dXJlRGVmYXVsdCIsImdlbmVyYXRlRGVmYXVsdFZhbHVlIiwiZW1haWwiLCJuYW1lVmFsdWUiLCJ1c2VybmFtZSIsImZ1bGxfbmFtZSIsIm5hbWVfZW4iLCJkb21haW4iLCJzcGxpdCIsInJvbWFuaXplZCIsInJvbWFuaXplTmFtZSIsInBhc3N3b3JkIiwiYmNyeXB0IiwiaGFzaCIsImZpeHR1cmVzIiwiZGF0YVNvdXJjZSIsImNhY2hlS2V5Iiwid2l0aCIsIkpTT04iLCJzdHJpbmdpZnkiLCJyZWZlcmVuY2VDYWNoZSIsImhhcyIsImV4cGxvcmVSZXN1bHQiLCJleHBsb3JlV2l0aFJlbGF0aW9ucyIsInN0cmF0ZWd5IiwibGltaXQiLCJjb25maWciLCJpbmNsdWRlUmVsYXRpb25zIiwibWF4RGVwdGgiLCJtYWluIiwicmVjb3JkcyIsImltcG9ydEV4cGxvcmVSZXN1bHQiLCJjYW5kaWRhdGVzIiwic2VsZWN0ZWQiLCJNYXRoIiwiZmxvb3IiLCJyYW5kb20iLCJhdXRvS2V5IiwiYXV0b0V4cGxvcmVSZXN1bHQiLCJhdXRvQ2FuZGlkYXRlcyIsIm51bGxhYmxlIiwiYWxsRml4dHVyZVJlY29yZHMiLCJlbnRpdHlJZCIsInJlbGF0ZWQiLCJlbnRyaWVzIiwicmVjb3Jkc1RvSW1wb3J0IiwibG9nIiwiY3lhbiIsInJlY29yZCIsInJlY29yZEtleSIsImltcG9ydGVkUmVjb3JkcyIsInB1c2giLCJhZGQiLCJncmF5IiwiZml4dHVyZVJlY29yZHMiLCJjcmVhdGVGaXh0dXJlUmVjb3JkIiwiX2RiIiwic2luZ2xlUmVjb3JkIiwibWFpbkVudGl0eSIsIm1haW5SZWNvcmRzVG9JbXBvcnQiLCJpbnNlcnRGaXh0dXJlcyIsImdyZWVuIiwic2l6ZSIsImdlbmVyYXRvciIsInN0YXJ0c1dpdGgiLCJpc05hbWVGaWVsZCIsImZha2VyTW9kdWxlIiwiZmFrZXJLTyIsImV4cHIiLCJtYXRjaCIsInBhdGgiLCJhcmdzU3RyIiwicGFydHMiLCJmbiIsInBhcnQiLCJhcmdzIiwidHJpbSIsInBhcnNlR2VuZXJhdG9yQXJncyIsInllbGxvdyIsImZha2VySkEiLCJsb2NhbGVGYWtlciIsImRlcGFydG1lbnRzIiwicHJlZml4ZXMiLCJzdWZmaXhlcyIsImRlcHQiLCJoZWxwZXJzIiwiYXJyYXlFbGVtZW50IiwicHJlZml4Iiwic3VmZml4IiwibG9jYWxlTWFwcGluZ3MiLCJlbiIsIm5vcm1hbGl6ZWROYW1lIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwicGF0dGVybiIsIk9iamVjdCIsImZpZWxkX3BhdHRlcm5zIiwiaW5jbHVkZXMiLCJleGVjdXRlRmFrZXJFeHByZXNzaW9uIiwiZW5kc1dpdGgiLCJnZW5lcmF0ZUFycmF5VmFsdWUiLCJlbnVtVmFsdWVzIiwiQXJyYXkiLCJpc0FycmF5IiwiZW51bSIsImVudW1MYWJlbHMiLCJrZXlzIiwidHlwZURlZmF1bHQiLCJ0eXBlX2RlZmF1bHRzIiwibG9yZW0iLCJ3b3JkcyIsIm51bWJlciIsImludCIsIm1pbiIsIm1heCIsImJpZ0ludCIsImZsb2F0IiwiZGF0YXR5cGUiLCJib29sZWFuIiwiZGF0ZSIsInBhc3QiLCJfZW50aXR5IiwiX2xvY2FsZUZha2VyIiwiY291bnQiLCJmcm9tIiwidXJsIiwiaW1hZ2UiLCJzeXN0ZW0iLCJmaWxlTmFtZSIsIm1pbWVfdHlwZSIsImludGVybmV0Iiwid29yZCIsImV4cHJlc3Npb24iLCJwYXJzZSIsImZha2VyTmFtZSIsInNlbGVjdGVkRmFrZXIiLCJmdW5jTWF0Y2giLCJmaXh0dXJlSGludCIsInJvd0NhY2hlS2V5IiwibGxtUHJvcHMiLCJmaWx0ZXIiLCJwIiwiZ2VuZXJhdGVTaW5nbGVXaXRoTExNIiwiYXBpS2V5IiwiZ2V0QXBpS2V5IiwiY3JlYXRlQW50aHJvcGljIiwiZ2VuZXJhdGVUZXh0Iiwicm93UmVzcG9uc2UiLCJtb2RlbCIsInByb21wdCIsImJ1aWxkUm93TExNUHJvbXB0IiwidGV4dCIsInJvd1Jlc3VsdCIsInBhcnNlUm93TExNUmVzcG9uc2UiLCJmaWVsZE5hbWUiLCJ2YWx1ZSIsInNpbmdsZVJlc3BvbnNlIiwiYnVpbGRMTE1Qcm9tcHQiLCJwYXJzZUxMTVJlc3BvbnNlIiwibGFuZ3VhZ2UiLCJmaWVsZERlc2NyaXB0aW9ucyIsIm1hcCIsImRlc2MiLCJ2YWx1ZXMiLCJqb2luIiwib3RoZXJQcm9wcyIsIm90aGVyUHJvcHNDb250ZXh0Iiwib3V0cHV0U2hhcGUiLCJlbnRpdHlDb250ZXh0IiwianNvblRleHQiLCJwYXJzZWQiLCJyYXciLCJyZXN1bHQiLCJTdHJpbmciLCJoaW50Iiwib3RoZXJGaWVsZHMiLCJvdGhlckZpZWxkc0NvbnRleHQiLCJnZXRFeHBlY3RlZEZvcm1hdCIsImdldEV4YW1wbGVGb3JUeXBlIiwicHJvcFR5cGUiLCJjbGVhbmVkIiwiYmFzZVR5cGUiLCJpdGVtIiwiZ2V0RGVmYXVsdFZhbHVlRm9yVHlwZSIsInBhcnNlU2NhbGFyVmFsdWUiLCJudW0iLCJwYXJzZUludCIsIk51bWJlciIsImlzTmFOIiwiQmlnSW50IiwicGFyc2VGbG9hdCIsImdldFRpbWUiLCJwcm9wTmFtZSIsImpzb25TdHIiLCJjb252ZXJ0SnNMaXRlcmFsVG9Kc29uIiwidHJpbW1lZCIsImlucHV0Iiwid2l0aERvdWJsZVF1b3RlcyIsIl8iLCJjb250ZW50IiwiU29uYW11IiwicmVxdWlyZSIsInNlY3JldHMiLCJhbnRocm9waWNfYXBpX2tleSIsInByb2Nlc3MiLCJlbnYiLCJBTlRIUk9QSUNfQVBJX0tFWSIsImJhc2VGb3JtYXQiLCJnZXRTY2FsYXJGb3JtYXQiLCJiYXNlRXhhbXBsZSIsImdldFNjYWxhckV4YW1wbGUiLCJpc0tvcmVhbiIsInRlc3QiLCJyb21hbml6ZUtvcmVhbk5hbWUiLCJDSE9TRU9ORyIsIkpVTkdTRU9ORyIsIkpPTkdTRU9ORyIsInJvbWFuaXplIiwiY2hhciIsImNvZGUiLCJjaGFyQ29kZUF0Iiwib2Zmc2V0IiwiY2hvIiwianVuZyIsImpvbmciLCJjaGFycyIsImZhbWlseU5hbWUiLCJnaXZlbk5hbWUiLCJnZXRMTE1DYWNoZVN0YXRzIiwiZW5hYmxlZCIsImNsZWFyTExNQ2FjaGUiLCJjbGVhciIsIlNldCIsImdlbmVyYXRlQmF0Y2giLCJzcGVjcyIsImdlbmVyYXRlZEZpeHR1cmVzIiwic3BlYyIsInNwZWNFbnRpdHkiLCJwYXJlbnRJZCIsImlkUHJvcCIsImZpbmQiLCJwYXJlbnRPdmVycmlkZXMiLCJmaXh0dXJlUGFyZW50T3ZlcnJpZGVzIiwicGFyZW50RW50aXR5IiwicXVlcnkiLCJ0YWJsZSIsInNlbGVjdCIsImNvbCIsInZhbCIsIndoZXJlIiwibGVmdEpvaW4iLCJ3aGVyZU51bGwiLCJyb3dzIiwiYXZhaWxhYmxlSWRzIiwiciIsImRhdGEiLCJleHBsaWNpdElkIiwiaSIsInVzZXNTZXF1ZW5jZSIsImRhdGFGb3JSZWNvcmQiLCJyZXN1bHRzIiwiY29tcGFuaW9uUmVzdWx0cyIsImdlbmVyYXRlQ29tcGFuaW9ucyIsInRvdGFsIiwicGFyZW50UmVzdWx0cyIsImFsbFJlc3VsdHMiLCJwcm9jZXNzZWRFbnRpdGllcyIsImNvbXBhbmlvbnMiLCJmaXh0dXJlQ29tcGFuaW9ucyIsImVudGl0eVJlc3VsdHMiLCJjb21wYW5pb24iLCJjb21wYW5pb25FbnRpdHkiLCJma1Byb3AiLCJjb21wYW5pb25JZFByb3AiLCJjb21wYW5pb25Db3VudCIsImNvbXBhbmlvbkZpeHR1cmVSZWNvcmRzIiwicGFyZW50UmVzdWx0IiwicmVzb2x2ZWRPdmVycmlkZXMiLCJyZXNvbHZlVGVtcGxhdGVPdmVycmlkZXMiLCJwYXJlbnREYXRhIiwicmVzb2x2ZWQiLCJrZXkiLCJpbXBvcnRGcm9tU291cmNlIiwiYmx1ZSIsInJlbGF0ZWRFbnRpdHlOYW1lIiwicmVsYXRlZFJlY29yZHMiLCJyZWxhdGVkRW50aXR5Il0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxXQUFXLFFBQVE7QUFLMUIsU0FBU0MsMEJBQTBCLEVBQUVDLHNCQUFzQixFQUFFQyxjQUFjLFFBQVEsb0JBQWlCO0FBQ3BHLFNBQVNDLE1BQU0sUUFBUSx5QkFBc0I7QUFDN0MsU0FDRUMsWUFBWSxRQUdQLHFCQUFrQjtBQUN6QixTQUE2QkMsYUFBYSxRQUFRLHNCQUFtQjtBQUNyRSxTQUFTQyxjQUFjLFFBQVEsdUJBQW9CO0FBc0JuRCxPQUFPLE1BQU1DOzs7O0lBQ0hDLGFBQTJCO0lBQzNCQyxPQUFlO0lBQ2ZDLFNBQXdCO0lBQ3hCQyxXQUFpQyxJQUFJQyxNQUFNO0lBQzNDQyxjQUFtQyxJQUFJRCxNQUFNO0lBQzdDRSxRQUFpQztJQUV6QyxZQUNFLEFBQVFDLFFBQWMsRUFDdEIsaUVBQWlFO0lBQ2pFLGdDQUFnQztJQUNoQ0MsU0FBZSxFQUNmLEFBQVFDLFlBQXNELEVBQzlELEFBQVFDLGFBQW1DLEVBQzNDSixPQUFpQyxD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
|
|
1239
|
+
//#endregion
|
|
1240
|
+
init_fixture_generator();
|
|
1241
|
+
export { FixtureGenerator, init_fixture_generator };
|
|
1242
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZS1nZW5lcmF0b3IuanMiLCJuYW1lcyI6WyJzb3VyY2VEYjogS25leCIsInRhcmdldERiTmFtZTogXCJmaXh0dXJlXCIgfCBcInRlc3RcIiB8IFwicHJvZHVjdGlvbl9tYXN0ZXJcIiIsImVudGl0eU1hbmFnZXI6IHR5cGVvZiBFbnRpdHlNYW5hZ2VyIiwiZml4dHVyZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4iLCJhbGxGaXh0dXJlUmVjb3JkczogRml4dHVyZVJlY29yZFtdIiwicmVjb3Jkc1RvSW1wb3J0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdIiwibWFpblJlY29yZHNUb0ltcG9ydDogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSIsImZuOiB1bmtub3duIiwiYXJnczogdW5rbm93bltdIiwiZW51bVZhbHVlczogc3RyaW5nW10iLCJwYXJzZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IiwicmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiIsImFwaUtleTogc3RyaW5nIHwgdW5kZWZpbmVkIiwiZ2VuZXJhdGVkRml4dHVyZXM6IEFycmF5PHtcbiAgICAgIGVudGl0eTogc3RyaW5nO1xuICAgICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICBleHBsaWNpdElkPzogYm9vbGVhbjtcbiAgICB9PiIsImF2YWlsYWJsZUlkczogbnVtYmVyW10iLCJmaXh0dXJlUmVjb3JkczogRml4dHVyZVJlY29yZFtdIiwiYWxsUmVzdWx0czogRml4dHVyZUltcG9ydFJlc3VsdFtdIiwiY29tcGFuaW9uRml4dHVyZVJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSIsInJlc29sdmVkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2ZpeHR1cmUtZ2VuZXJhdG9yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5cbmltcG9ydCB7IHR5cGUgRW50aXR5IH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHlcIjtcbmltcG9ydCB7IHR5cGUgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IHR5cGUgRW50aXR5UHJvcCwgdHlwZSBGaXh0dXJlSW1wb3J0UmVzdWx0LCB0eXBlIEZpeHR1cmVSZWNvcmQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wLCBpc09uZVRvT25lUmVsYXRpb25Qcm9wLCBpc1JlbGF0aW9uUHJvcCB9IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgaXNUZXN0IH0gZnJvbSBcIi4uL3V0aWxzL2NvbnRyb2xsZXJcIjtcbmltcG9ydCB7IERhdGFFeHBsb3JlciB9IGZyb20gXCIuL2RhdGEtZXhwbG9yZXJcIjtcbmltcG9ydCB7IHR5cGUgRXhwbG9yZVdpdGhSZWxhdGlvbnNPcHRpb25zLCB0eXBlIEV4cGxvcmVXaXRoUmVsYXRpb25zUmVzdWx0IH0gZnJvbSBcIi4vZGF0YS1leHBsb3JlclwiO1xuaW1wb3J0IHsgZmFrZXJNYXBwaW5ncyB9IGZyb20gXCIuL2Zha2VyLW1hcHBpbmdzXCI7XG5pbXBvcnQgeyB0eXBlIEZha2VyTWFwcGluZ3MgfSBmcm9tIFwiLi9mYWtlci1tYXBwaW5nc1wiO1xuaW1wb3J0IHsgRml4dHVyZU1hbmFnZXIgfSBmcm9tIFwiLi9maXh0dXJlLW1hbmFnZXJcIjtcblxuZXhwb3J0IHR5cGUgTG9jYWxlID0gXCJrb1wiIHwgXCJlblwiIHwgXCJqYVwiO1xuXG5leHBvcnQgdHlwZSBGaXh0dXJlR2VuZXJhdG9yT3B0aW9ucyA9IHtcbiAgbG9jYWxlPzogTG9jYWxlO1xuICB1c2VMTE0/OiBib29sZWFuO1xuICBlbmFibGVMTE1DYWNoZT86IGJvb2xlYW47XG4gIGxsbU1vZGVsPzogc3RyaW5nO1xufTtcblxuZXhwb3J0IHR5cGUgR2VuZXJhdG9yQ29udGV4dCA9IHtcbiAgLyoqIOyDneyEsSDspJHsnbggZml4dHVyZeuTpCAo66mU66qo66asIOyDgSkgKi9cbiAgZml4dHVyZXM6IE1hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+PjtcblxuICAvKiog7LC47KGwIOuNsOydtO2EsCDsupDsi5wgKERhdGFFeHBsb3JlciDqsrDqs7wpICovXG4gIHJlZmVyZW5jZUNhY2hlOiBNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPjtcblxuICAvKiog7J2066+4IGltcG9ydOuQnCDroIjsvZTrk5zrpbwg7LaU7KCB7ZWY7JesIOykkeuztSBpbXBvcnTrpbwg67Cp7KeA7ZWp64uI64ukICovXG4gIGltcG9ydGVkUmVjb3JkczogU2V0PHN0cmluZz47IC8vIFwiVXNlciMxMjNcIlxufTtcblxuZXhwb3J0IGNsYXNzIEZpeHR1cmVHZW5lcmF0b3Ige1xuICBwcml2YXRlIGRhdGFFeHBsb3JlcjogRGF0YUV4cGxvcmVyO1xuICBwcml2YXRlIGxvY2FsZTogTG9jYWxlO1xuICBwcml2YXRlIG1hcHBpbmdzOiBGYWtlck1hcHBpbmdzO1xuICBwcml2YXRlIGxsbUNhY2hlOiBNYXA8c3RyaW5nLCB1bmtub3duPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBlbnRpdHlDYWNoZTogTWFwPHN0cmluZywgRW50aXR5PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBvcHRpb25zOiBGaXh0dXJlR2VuZXJhdG9yT3B0aW9ucztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHNvdXJjZURiOiBLbmV4LFxuICAgIC8vIEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVz6rCAIGRiTmFtZSDrrLjsnpDsl7TsnYQg67Cb6riwIOuVjOusuOyXkCDsp4HsoJEg7IKs7Jqp7ZWY7KeAIOyViuyKteuLiOuLpFxuICAgIC8vIOuvuOuemCDtmZXsnqXshLHsnYQg7JyE7ZW0IEFQSSDsi5zqt7jri4jsspjsl5DripQg7Y+s7ZWo7Iuc7Lyw7Iq164uI64ukXG4gICAgX3RhcmdldERiOiBLbmV4LFxuICAgIHByaXZhdGUgdGFyZ2V0RGJOYW1lOiBcImZpeHR1cmVcIiB8IFwidGVzdFwiIHwgXCJwcm9kdWN0aW9uX21hc3RlclwiLFxuICAgIHByaXZhdGUgZW50aXR5TWFuYWdlcjogdHlwZW9mIEVudGl0eU1hbmFnZXIsXG4gICAgb3B0aW9ucz86IEZpeHR1cmVHZW5lcmF0b3JPcHRpb25zLFxuICApIHtcbiAgICB0aGlzLmRhdGFFeHBsb3JlciA9IG5ldyBEYXRhRXhwbG9yZXIoc291cmNlRGIsIGVudGl0eU1hbmFnZXIpO1xuICAgIHRoaXMubG9jYWxlID0gb3B0aW9ucz8ubG9jYWxlIHx8IFwia29cIjtcbiAgICB0aGlzLm1hcHBpbmdzID0gZmFrZXJNYXBwaW5ncztcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICBsb2NhbGU6IG9wdGlvbnM/LmxvY2FsZSB8fCBcImtvXCIsXG4gICAgICB1c2VMTE06IG9wdGlvbnM/LnVzZUxMTSB8fCBmYWxzZSxcbiAgICAgIGVuYWJsZUxMTUNhY2hlOiBvcHRpb25zPy5lbmFibGVMTE1DYWNoZSAhPT0gZmFsc2UsXG4gICAgICBsbG1Nb2RlbDogb3B0aW9ucz8ubGxtTW9kZWwgfHwgXCJjbGF1ZGUtc29ubmV0LTQtNlwiLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRml4dHVyZSDsg53shLEgKOuLqOydvClcbiAgICogQHJldHVybnMg7IOd7ISx65CcIGZpeHR1cmUg642w7J207YSwICjrqZTrqqjrpqwg7IOBKVxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGUoXG4gICAgZW50aXR5TmFtZTogc3RyaW5nLFxuICAgIG92ZXJyaWRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fSxcbiAgICBjb250ZXh0OiBHZW5lcmF0b3JDb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KCksXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgICAvLyBFbnRpdHkg7LqQ7IuxOiDthYzsiqTtirjsl5DshJwgZW50aXR5IGNvbmUg7IiY7KCV7J20IOuwmOyYgeuQmOuPhOuhnSDrs7TsnqVcbiAgICBsZXQgZW50aXR5ID0gdGhpcy5lbnRpdHlDYWNoZS5nZXQoZW50aXR5TmFtZSk7XG4gICAgaWYgKCFlbnRpdHkpIHtcbiAgICAgIGVudGl0eSA9IHRoaXMuZW50aXR5TWFuYWdlci5nZXQoZW50aXR5TmFtZSk7XG4gICAgICB0aGlzLmVudGl0eUNhY2hlLnNldChlbnRpdHlOYW1lLCBlbnRpdHkpO1xuICAgIH1cblxuICAgIGNvbnN0IHRlbXBJZCA9IGAke2VudGl0eU5hbWV9I3RlbXAjJHtEYXRlLm5vdygpfWA7IC8vIOyehOyLnCBJRFxuXG4gICAgLy8gTExNIHJvdyDri6jsnIQg7IOd7ISx7J2EIOychO2VnCDqs6DsnKAg7YKkICjqsJnsnYAgcm937J2YIO2VhOuTnOuTpOydtCDrj5nsnbztlZwgcm93S2V566W8IOqzteycoClcbiAgICBjb25zdCByb3dLZXkgPSB0aGlzLm9wdGlvbnMudXNlTExNID8gYCR7ZW50aXR5TmFtZX0jcm93IyR7RGF0ZS5ub3coKX1gIDogdW5kZWZpbmVkO1xuXG4gICAgLy8g6rCBIHByb3Drs4Qg6rCSIOyDneyEsVxuICAgIGNvbnN0IGZpeHR1cmU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgZW50aXR5LnByb3BzKSB7XG4gICAgICAvLyBWaXJ0dWFsIHByb3DsnYAg7Iqk7YK1XG4gICAgICBpZiAoXCJ2aXJ0dWFsXCIgaW4gcHJvcCAmJiBwcm9wLnZpcnR1YWwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIGlkIHByb3Ag7LKY66asXG4gICAgICBpZiAocHJvcC5uYW1lID09PSBcImlkXCIpIHtcbiAgICAgICAgaWYgKFwiY29uZVwiIGluIHByb3AgJiYgcHJvcC5jb25lPy5maXh0dXJlU3RyYXRlZ3kgPT09IFwic2VxdWVuY2VcIikge1xuICAgICAgICAgIC8vIERCIHNlcXVlbmNl6rCAIOyekOuPmSDtlaDri7ntlZjrr4DroZwg7Iqk7YK1IChVc2VyIOuTsSlcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocHJvcC50eXBlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgLy8gREIgREVGQVVMVCDsl4bripQgc3RyaW5nIFBLOiBhbHBoYW51bWVyaWMgMzLsnpAg7IOd7ISxIChiZXR0ZXItYXV0aCDsiqTtg4DsnbwpXG4gICAgICAgICAgY29uc3QgeyBmYWtlcjogX2Zha2VyIH0gPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gX2Zha2VyLnN0cmluZy5hbHBoYW51bWVyaWMoMzIpO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwcm9wLnR5cGUgPT09IFwidXVpZFwiKSB7XG4gICAgICAgICAgY29uc3QgeyBmYWtlcjogX2Zha2VyIH0gPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gX2Zha2VyLnN0cmluZy51dWlkKCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gaW50ZWdlci9iaWdJbnRlZ2VyIFBLOiBnZW5lcmF0ZUJhdGNo7JeQ7IScIHRlbXBJZOulvCDrhKPsnLzrr4DroZwg7Jes6riw7ISgIOyKpO2CtVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gb3ZlcnJpZGXqsIAg7J6I7Jy866m0IOyCrOyaqVxuICAgICAgaWYgKHByb3AubmFtZSBpbiBvdmVycmlkZXMpIHtcbiAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gb3ZlcnJpZGVzW3Byb3AubmFtZV07XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBjb25l7JeQ7IScIOyDneyEsSDsoITrnrUg7ZmV7J24XG4gICAgICBjb25zdCBjb25lID0gcHJvcC5jb25lO1xuXG4gICAgICAvLyAxLiBSZWxhdGlvbiBwcm9wIOyymOumrFxuICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIC8vIEJlbG9uZ3NUb09uZSAvIE9uZVRvT25lKGhhc0pvaW5Db2x1bW4p7J2AIEZLIOy7rOufvOuqhSh7cHJvcC5uYW1lfV9pZCnsnLzroZzrj4Qgb3ZlcnJpZGXrpbwg67Cb64qU64ukXG4gICAgICAgIGNvbnN0IGZrQ29sTmFtZSA9IGAke3Byb3AubmFtZX1faWRgO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgZmtDb2xOYW1lIGluIG92ZXJyaWRlcyAmJlxuICAgICAgICAgIChpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSB8fCAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChwcm9wKSAmJiBwcm9wLmhhc0pvaW5Db2x1bW4pKVxuICAgICAgICApIHtcbiAgICAgICAgICBmaXh0dXJlW2ZrQ29sTmFtZV0gPSBvdmVycmlkZXNbZmtDb2xOYW1lXTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlbGF0aW9uVmFsdWUgPSBhd2FpdCB0aGlzLmdlbmVyYXRlUmVsYXRpb25WYWx1ZShlbnRpdHksIHByb3AsIGNvbnRleHQpO1xuICAgICAgICAvLyBCZWxvbmdzVG9PbmUsIE9uZVRvT25lKGhhc0pvaW5Db2x1bW4p7J2YIOqyveyasCBmb3JlaWduIGtleSDsu6zrn7zrqoXsnLzroZwg7KCA7J6lXG4gICAgICAgIGlmIChcbiAgICAgICAgICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSB8fFxuICAgICAgICAgIChpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbilcbiAgICAgICAgKSB7XG4gICAgICAgICAgZml4dHVyZVtgJHtwcm9wLm5hbWV9X2lkYF0gPSByZWxhdGlvblZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZpeHR1cmVbcHJvcC5uYW1lXSA9IHJlbGF0aW9uVmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIDIuIGNvbmUubm90ZSArIExMTSDsgqzsmqkgKHVzZUxMTeydtOuptCBmaXh0dXJlR2VuZXJhdG9y67O064ukIOyasOyEoClcbiAgICAgIGlmIChjb25lPy5ub3RlICYmIHRoaXMub3B0aW9ucy51c2VMTE0pIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBsbG1WYWx1ZSA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVXaXRoTExNKGNvbmUubm90ZSwgcHJvcCwgZW50aXR5LCByb3dLZXkpO1xuICAgICAgICAgIC8vIHN0cmluZyDtg4DsnoXsnbTqs6AgbGVuZ3RoIOygnOyVveydtCDsnojsnLzrqbQg7LSI6rO8IOyLnCB0cnVuY2F0aW9uXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdHlwZW9mIGxsbVZhbHVlID09PSBcInN0cmluZ1wiICYmXG4gICAgICAgICAgICBcImxlbmd0aFwiIGluIHByb3AgJiZcbiAgICAgICAgICAgIHR5cGVvZiBwcm9wLmxlbmd0aCA9PT0gXCJudW1iZXJcIiAmJlxuICAgICAgICAgICAgbGxtVmFsdWUubGVuZ3RoID4gcHJvcC5sZW5ndGhcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGZpeHR1cmVbcHJvcC5uYW1lXSA9IGxsbVZhbHVlLnNsaWNlKDAsIHByb3AubGVuZ3RoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gbGxtVmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgIGBbRml4dHVyZUdlbmVyYXRvcl0gTExNIGdlbmVyYXRpb24gZmFpbGVkIGZvciAke2VudGl0eS5pZH0uJHtwcm9wLm5hbWV9LCBmYWxsaW5nIGJhY2sgdG8gZml4dHVyZUdlbmVyYXRvciBvciBkZWZhdWx0YCxcbiAgICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogZXJyb3IsXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBmYWxsYmFjazogZml4dHVyZUdlbmVyYXRvciDihpIgZml4dHVyZURlZmF1bHQg4oaSIOq4sOuzuOqwkuycvOuhnCDqs4Tsho1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyAzLiBmaXh0dXJlR2VuZXJhdG9yIOyCrOyaqVxuICAgICAgaWYgKGNvbmU/LmZpeHR1cmVHZW5lcmF0b3IpIHtcbiAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gYXdhaXQgdGhpcy5leGVjdXRlR2VuZXJhdG9yKGNvbmUuZml4dHVyZUdlbmVyYXRvciwgcHJvcCwgZW50aXR5KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIDQuIGZpeHR1cmVEZWZhdWx0IOyCrOyaqVxuICAgICAgaWYgKGNvbmU/LmZpeHR1cmVEZWZhdWx0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZml4dHVyZVtwcm9wLm5hbWVdID0gY29uZS5maXh0dXJlRGVmYXVsdDtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIDUuIO2DgOyeheuzhCDquLDrs7gg7IOd7ISxXG4gICAgICBmaXh0dXJlW3Byb3AubmFtZV0gPSBhd2FpdCB0aGlzLmdlbmVyYXRlRGVmYXVsdFZhbHVlKHByb3AsIGVudGl0eSk7XG4gICAgfVxuXG4gICAgLy8gNi4gZW1haWwg7ZWE65Oc6rCAIOyeiOqzoCBuYW1lIO2VhOuTnOqwgCDsnojsnLzrqbQsIGVtYWls7J2YIOuhnOy7rCDtjIztirjrpbwgbmFtZSDquLDrsJjsnLzroZwg67O07KCVXG4gICAgaWYgKFwiZW1haWxcIiBpbiBmaXh0dXJlICYmIHR5cGVvZiBmaXh0dXJlLmVtYWlsID09PSBcInN0cmluZ1wiICYmICEoXCJlbWFpbFwiIGluIG92ZXJyaWRlcykpIHtcbiAgICAgIGNvbnN0IG5hbWVWYWx1ZSA9IGZpeHR1cmUubmFtZSB8fCBmaXh0dXJlLnVzZXJuYW1lIHx8IGZpeHR1cmUuZnVsbF9uYW1lIHx8IGZpeHR1cmUubmFtZV9lbjtcbiAgICAgIGlmIChuYW1lVmFsdWUgJiYgdHlwZW9mIG5hbWVWYWx1ZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBjb25zdCBkb21haW4gPSBmaXh0dXJlLmVtYWlsLnNwbGl0KFwiQFwiKVsxXSB8fCBcImV4YW1wbGUuY29tXCI7XG4gICAgICAgIGNvbnN0IHJvbWFuaXplZCA9IGF3YWl0IHRoaXMucm9tYW5pemVOYW1lKG5hbWVWYWx1ZSk7XG4gICAgICAgIGZpeHR1cmUuZW1haWwgPSBgJHtyb21hbml6ZWR9QCR7ZG9tYWlufWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gNy4gcGFzc3dvcmQg7ZWE65OcIOyVlO2YuO2ZlFxuICAgIGlmIChcInBhc3N3b3JkXCIgaW4gZml4dHVyZSAmJiBmaXh0dXJlLnBhc3N3b3JkICYmIHR5cGVvZiBmaXh0dXJlLnBhc3N3b3JkID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBjb25zdCBiY3J5cHQgPSBhd2FpdCBpbXBvcnQoXCJiY3J5cHRcIik7XG4gICAgICBmaXh0dXJlLnBhc3N3b3JkID0gYXdhaXQgYmNyeXB0Lmhhc2goZml4dHVyZS5wYXNzd29yZCwgMTApO1xuICAgIH1cblxuICAgIGNvbnRleHQuZml4dHVyZXMuc2V0KHRlbXBJZCwgZml4dHVyZSk7XG4gICAgcmV0dXJuIGZpeHR1cmU7XG4gIH1cblxuICAvKipcbiAgICogUmVsYXRpb24g6rCSIOyDneyEsSArIOyekOuPmSBJbXBvcnRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVSZWxhdGlvblZhbHVlKFxuICAgIGVudGl0eTogRW50aXR5LFxuICAgIHByb3A6IEVudGl0eVByb3AsXG4gICAgY29udGV4dDogR2VuZXJhdG9yQ29udGV4dCxcbiAgKTogUHJvbWlzZTxudW1iZXIgfCBudWxsPiB7XG4gICAgaWYgKCFpc1JlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaXh0dXJlR2VuZXJhdG9yOiAke2VudGl0eS5pZH0uJHtwcm9wLm5hbWV9IGlzIG5vdCBhIHJlbGF0aW9uIHByb3BgKTtcbiAgICB9XG5cbiAgICAvLyBCZWxvbmdzVG9PbmUsIE9uZVRvT25lKGhhc0pvaW5Db2x1bW4p66eMIOyymOumrFxuICAgIGlmIChcbiAgICAgICFpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSAmJlxuICAgICAgIShpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbilcbiAgICApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbmUgPSBwcm9wLmNvbmU7XG4gICAgY29uc3QgZGF0YVNvdXJjZSA9IGNvbmU/LmRhdGFTb3VyY2U7XG5cbiAgICAvLyBEYXRhRXhwbG9yZXLroZwg7LC47KGwIOuNsOydtO2EsCDsobDtmowgKHNvdXJjZURiKVxuICAgIC8vIOq0gOqzhCDssrTsnbjsnYQg65Sw65286rCA6riwIOychO2VtCBleHBsb3JlV2l0aFJlbGF0aW9ucyDsgqzsmqlcbiAgICBpZiAoZGF0YVNvdXJjZSkge1xuICAgICAgY29uc3QgY2FjaGVLZXkgPSBgJHtwcm9wLndpdGh9OiR7SlNPTi5zdHJpbmdpZnkoZGF0YVNvdXJjZSl9YDtcblxuICAgICAgaWYgKCFjb250ZXh0LnJlZmVyZW5jZUNhY2hlLmhhcyhjYWNoZUtleSkpIHtcbiAgICAgICAgY29uc3QgZXhwbG9yZVJlc3VsdCA9IGF3YWl0IHRoaXMuZGF0YUV4cGxvcmVyLmV4cGxvcmVXaXRoUmVsYXRpb25zKHByb3Aud2l0aCwge1xuICAgICAgICAgIHN0cmF0ZWd5OiBkYXRhU291cmNlLnN0cmF0ZWd5LFxuICAgICAgICAgIGxpbWl0OlxuICAgICAgICAgICAgKChkYXRhU291cmNlLmNvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCk/LmxpbWl0IGFzXG4gICAgICAgICAgICAgIHwgbnVtYmVyXG4gICAgICAgICAgICAgIHwgdW5kZWZpbmVkKSB8fCAxMCxcbiAgICAgICAgICBpbmNsdWRlUmVsYXRpb25zOiB0cnVlLFxuICAgICAgICAgIG1heERlcHRoOiAzLFxuICAgICAgICAgIC4uLihkYXRhU291cmNlLmNvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCksXG4gICAgICAgIH0pO1xuICAgICAgICBjb250ZXh0LnJlZmVyZW5jZUNhY2hlLnNldChjYWNoZUtleSwgZXhwbG9yZVJlc3VsdC5tYWluLnJlY29yZHMpO1xuXG4gICAgICAgIC8vIOyhsO2ajO2VnCDrjbDsnbTthLDsmYAg6rSA6rOE65CcIOuqqOuToCDsl5Tti7Dti7DrpbwgdGFyZ2V0RGLsl5AgaW1wb3J0XG4gICAgICAgIGF3YWl0IHRoaXMuaW1wb3J0RXhwbG9yZVJlc3VsdChleHBsb3JlUmVzdWx0LCBjb250ZXh0KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY2FuZGlkYXRlcyA9IGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICAgIGlmIChjYW5kaWRhdGVzICYmIGNhbmRpZGF0ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAvLyDrnpzrjaTtlZjqsowg7ZWY64KYIOyEoO2DnVxuICAgICAgICBjb25zdCBzZWxlY3RlZCA9IGNhbmRpZGF0ZXNbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogY2FuZGlkYXRlcy5sZW5ndGgpXTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdGVkLmlkIGFzIG51bWJlcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBkYXRhU291cmNl6rCAIOyXhuydhCDrlYwg7J6Q64+Z7Jy866GcIGZpeHR1cmUgRELsl5DshJwg7KGw7ZqMIOyLnOuPhFxuICAgIC8vIOq0gOqzhCDssrTsnbjsnYQg65Sw65286rCA6riwIOychO2VtCBleHBsb3JlV2l0aFJlbGF0aW9ucyDsgqzsmqlcbiAgICBjb25zdCBhdXRvS2V5ID0gYCR7cHJvcC53aXRofTphdXRvYDtcbiAgICBpZiAoIWNvbnRleHQucmVmZXJlbmNlQ2FjaGUuaGFzKGF1dG9LZXkpKSB7XG4gICAgICAvLyBmaXh0dXJlIERCKHNvdXJjZURiKeyXkOyEnCDsnpDrj5kg7KGw7ZqMICjqtIDqs4Qg7Y+s7ZWoKVxuICAgICAgY29uc3QgYXV0b0V4cGxvcmVSZXN1bHQgPSBhd2FpdCB0aGlzLmRhdGFFeHBsb3Jlci5leHBsb3JlV2l0aFJlbGF0aW9ucyhwcm9wLndpdGgsIHtcbiAgICAgICAgc3RyYXRlZ3k6IFwicmFuZG9tXCIsXG4gICAgICAgIGxpbWl0OiAxMCxcbiAgICAgICAgaW5jbHVkZVJlbGF0aW9uczogdHJ1ZSxcbiAgICAgICAgbWF4RGVwdGg6IDMsXG4gICAgICB9KTtcbiAgICAgIGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuc2V0KGF1dG9LZXksIGF1dG9FeHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcyk7XG5cbiAgICAgIC8vIOyhsO2ajO2VnCDrjbDsnbTthLDsmYAg6rSA6rOE65CcIOuqqOuToCDsl5Tti7Dti7DrpbwgdGFyZ2V0RGLsl5AgaW1wb3J0XG4gICAgICBpZiAoYXV0b0V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbXBvcnRFeHBsb3JlUmVzdWx0KGF1dG9FeHBsb3JlUmVzdWx0LCBjb250ZXh0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBhdXRvQ2FuZGlkYXRlcyA9IGNvbnRleHQucmVmZXJlbmNlQ2FjaGUuZ2V0KGF1dG9LZXkpO1xuICAgIGlmIChhdXRvQ2FuZGlkYXRlcyAmJiBhdXRvQ2FuZGlkYXRlcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyDrnpzrjaTtlZjqsowg7ZWY64KYIOyEoO2DnVxuICAgICAgY29uc3Qgc2VsZWN0ZWQgPSBhdXRvQ2FuZGlkYXRlc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBhdXRvQ2FuZGlkYXRlcy5sZW5ndGgpXTtcbiAgICAgIHJldHVybiBzZWxlY3RlZC5pZCBhcyBudW1iZXI7XG4gICAgfVxuXG4gICAgLy8g7LC47KGwIOuNsOydtO2EsOqwgCDsl4bsnLzrqbQgbnVsbCDrsJjtmZggKG51bGxhYmxl7J24IOqyveyasClcbiAgICBpZiAocHJvcC5udWxsYWJsZSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gbnVsbGFibGXsnbQg7JWE64uI6rOgIOuNsOydtO2EsOuPhCDsl4bsnLzrqbQg7JeQ65+sXG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEZpeHR1cmVHZW5lcmF0b3I6ICR7ZW50aXR5LmlkfS4ke3Byb3AubmFtZX3sl5Ag7ZWE7JqU7ZWcICR7cHJvcC53aXRofSDrjbDsnbTthLDqsIAg7JeG7Iq164uI64ukLiBgICtcbiAgICAgICAgYOuovOyggCAke3Byb3Aud2l0aH3rpbwg7IOd7ISx7ZWY6rGw64KYIGNvbmUuZGF0YVNvdXJjZeulvCDshKTsoJXtlZjshLjsmpQuYCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxvcmVXaXRoUmVsYXRpb25zIOqysOqzvOulvCB0YXJnZXREYuyXkCBpbXBvcnRcbiAgICpcbiAgICog6rSA6rOEIOyytOyduOydhCDrlLDrnbzqsIQg6rKw6rO8KG1haW4gKyByZWxhdGVkKeulvCDrqqjrkZAgaW1wb3J07ZWp64uI64ukLlxuICAgKiDsnZjsobTshLEg7Iic7ISc64qUIEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVz6rCAIOyekOuPmeycvOuhnCDsspjrpqztlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGltcG9ydEV4cGxvcmVSZXN1bHQoXG4gICAgZXhwbG9yZVJlc3VsdDogRXhwbG9yZVdpdGhSZWxhdGlvbnNSZXN1bHQsXG4gICAgY29udGV4dDogR2VuZXJhdG9yQ29udGV4dCxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYWxsRml4dHVyZVJlY29yZHM6IEZpeHR1cmVSZWNvcmRbXSA9IFtdO1xuXG4gICAgLy8gMS4gUmVsYXRlZCBlbnRpdGllcyBpbXBvcnQgKENvbXBhbnksIERlcGFydG1lbnQg65OxKVxuICAgIGZvciAoY29uc3QgW2VudGl0eUlkLCByZWNvcmRzXSBvZiBleHBsb3JlUmVzdWx0LnJlbGF0ZWQuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICAgIGNvbnN0IHJlY29yZHNUb0ltcG9ydDogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSA9IFtdO1xuXG4gICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgY2hhbGsuY3lhbihgSW1wb3J0aW5nIHJlbGF0ZWQgZW50aXR5OiAke2VudGl0eUlkfSAoJHtyZWNvcmRzLmxlbmd0aH0gcmVjb3JkcylgKSxcbiAgICAgICAgKTtcblxuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgcmVjb3Jkcykge1xuICAgICAgICBjb25zdCByZWNvcmRLZXkgPSBgJHtlbnRpdHlJZH0jJHtyZWNvcmQuaWR9YDtcbiAgICAgICAgaWYgKCFjb250ZXh0LmltcG9ydGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgICAgIHJlY29yZHNUb0ltcG9ydC5wdXNoKHJlY29yZCk7XG4gICAgICAgICAgY29udGV4dC5pbXBvcnRlZFJlY29yZHMuYWRkKHJlY29yZEtleSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHJlY29yZHNUb0ltcG9ydC5sZW5ndGggPiAwKSB7XG4gICAgICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIHJlY29yZHNUb0ltcG9ydCkge1xuICAgICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgIGNoYWxrLmdyYXkoXG4gICAgICAgICAgICAgICAgYCAgLSBQcm9jZXNzaW5nICR7ZW50aXR5SWR9IHJlY29yZDpgLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHJlY29yZCkuc2xpY2UoMCwgMTAwKSxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgZml4dHVyZVJlY29yZHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5jcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgICAgICAgICAgZW50aXR5LFxuICAgICAgICAgICAgcmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgICAgIHsgX2RiOiB0aGlzLnNvdXJjZURiLCBzaW5nbGVSZWNvcmQ6IHRydWUgfSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGFsbEZpeHR1cmVSZWNvcmRzLnB1c2goLi4uZml4dHVyZVJlY29yZHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMi4gTWFpbiBlbnRpdHkgaW1wb3J0IChFbXBsb3llZSDrk7EpXG4gICAgY29uc3QgbWFpbkVudGl0eSA9IHRoaXMuZW50aXR5TWFuYWdlci5nZXQoZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkKTtcbiAgICBjb25zdCBtYWluUmVjb3Jkc1RvSW1wb3J0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdID0gW107XG5cbiAgICAhaXNUZXN0KCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay5jeWFuKFxuICAgICAgICAgIGBJbXBvcnRpbmcgbWFpbiBlbnRpdHk6ICR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSAoJHtleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcy5sZW5ndGh9IHJlY29yZHMpYCxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcykge1xuICAgICAgY29uc3QgcmVjb3JkS2V5ID0gYCR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSMke3JlY29yZC5pZH1gO1xuICAgICAgaWYgKCFjb250ZXh0LmltcG9ydGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgICBtYWluUmVjb3Jkc1RvSW1wb3J0LnB1c2gocmVjb3JkKTtcbiAgICAgICAgY29udGV4dC5pbXBvcnRlZFJlY29yZHMuYWRkKHJlY29yZEtleSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1haW5SZWNvcmRzVG9JbXBvcnQubGVuZ3RoID4gMCkge1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgbWFpblJlY29yZHNUb0ltcG9ydCkge1xuICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgIGNoYWxrLmdyYXkoXG4gICAgICAgICAgICAgIGAgIC0gUHJvY2Vzc2luZyAke2V4cGxvcmVSZXN1bHQubWFpbi5lbnRpdHlJZH0gcmVjb3JkOmAsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHJlY29yZCkuc2xpY2UoMCwgMTAwKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgZml4dHVyZVJlY29yZHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5jcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgICAgICAgIG1haW5FbnRpdHksXG4gICAgICAgICAgcmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgICB7IF9kYjogdGhpcy5zb3VyY2VEYiwgc2luZ2xlUmVjb3JkOiB0cnVlIH0sXG4gICAgICAgICk7XG4gICAgICAgIGFsbEZpeHR1cmVSZWNvcmRzLnB1c2goLi4uZml4dHVyZVJlY29yZHMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDMuIOuqqOuToCBmaXh0dXJl66W8IO2VnCDrsojsl5Ag7IK97J6FICjsnZjsobTshLEg7Iic7IScIOyekOuPmSDsspjrpqwpXG4gICAgaWYgKGFsbEZpeHR1cmVSZWNvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVzKHRoaXMudGFyZ2V0RGJOYW1lLCBhbGxGaXh0dXJlUmVjb3Jkcyk7XG5cbiAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5ncmVlbihcbiAgICAgICAgICAgIGBBdXRvLWltcG9ydGVkICR7ZXhwbG9yZVJlc3VsdC5tYWluLmVudGl0eUlkfSB3aXRoIHJlbGF0aW9uczogYCArXG4gICAgICAgICAgICAgIGAke2V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aH0gbWFpbiArICR7ZXhwbG9yZVJlc3VsdC5yZWxhdGVkLnNpemV9IHJlbGF0ZWQgZW50aXRpZXNgLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIGZpeHR1cmVHZW5lcmF0b3Ig7Iuk7ZaJIChGYWtlci5qc+unjCDsp4Dsm5ApXG4gICAqXG4gICAqIGZha2VyLiog7ZiV7Iud7J2YIO2RnO2YhOyLneydhCDslYjsoITtlZjqsowg7YyM7Iux7ZWY7JesIOyLpO2Wie2VqeuLiOuLpC5cbiAgICog7JiIOiBcImZha2VyLmludGVybmV0LmVtYWlsKClcIiDihpIgZmFrZXIuaW50ZXJuZXQuZW1haWwoKVxuICAgKiDsmIg6IFwiZmFrZXIubG9yZW0ud29yZHMoMylcIiDihpIgZmFrZXIubG9yZW0ud29yZHMoMylcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXhlY3V0ZUdlbmVyYXRvcihcbiAgICBnZW5lcmF0b3I6IHN0cmluZyxcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIGVudGl0eTogRW50aXR5LFxuICApOiBQcm9taXNlPHVua25vd24+IHtcbiAgICAvLyBGYWtlci5qcyDtkZztmITsi53rp4wg7KeA7JuQXG4gICAgaWYgKGdlbmVyYXRvci5zdGFydHNXaXRoKFwiZmFrZXIuXCIpKSB7XG4gICAgICAvLyB1c2VybmFtZeydtOuCmCBuYW1lIO2VhOuTnOuKlCDtlZzqta3slrQgZmFrZXIg7IKs7JqpXG4gICAgICBjb25zdCBpc05hbWVGaWVsZCA9IHByb3AubmFtZSA9PT0gXCJ1c2VybmFtZVwiIHx8IHByb3AubmFtZSA9PT0gXCJuYW1lXCI7XG4gICAgICBjb25zdCBmYWtlck1vZHVsZSA9IGF3YWl0IGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKTtcbiAgICAgIGNvbnN0IGZha2VyID0gaXNOYW1lRmllbGQgPyBmYWtlck1vZHVsZS5mYWtlcktPIDogZmFrZXJNb2R1bGUuZmFrZXI7XG4gICAgICBjb25zdCBleHByID0gZ2VuZXJhdG9yLnNsaWNlKDYpOyAvLyBcImZha2VyLlwiIOygnOqxsFxuXG4gICAgICB0cnkge1xuICAgICAgICAvLyDtlajsiJgg6rK966Gc7JmAIOyduOyekCDtjIzsi7FcbiAgICAgICAgY29uc3QgbWF0Y2ggPSBleHByLm1hdGNoKC9eKFtcXHcuXSspKD86XFwoKC4qPylcXCkpPyQvKTtcbiAgICAgICAgaWYgKCFtYXRjaCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBGaXh0dXJlR2VuZXJhdG9yOiBJbnZhbGlkIGZha2VyIGV4cHJlc3Npb24gZm9yICR7cHJvcC5uYW1lfTogJHtnZW5lcmF0b3J9YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgWywgcGF0aCwgYXJnc1N0cl0gPSBtYXRjaDtcbiAgICAgICAgY29uc3QgcGFydHMgPSBwYXRoLnNwbGl0KFwiLlwiKTtcblxuICAgICAgICAvLyBmYWtlciDqsJ3ssrTsl5DshJwg7ZWo7IiYIOywvuq4sFxuICAgICAgICBsZXQgZm46IHVua25vd24gPSBmYWtlcjtcbiAgICAgICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBmbiA9PT0gXCJvYmplY3RcIiAmJiBmbiAhPT0gbnVsbCAmJiBwYXJ0IGluIGZuKSB7XG4gICAgICAgICAgICBmbiA9IChmbiBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilbcGFydF07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRml4dHVyZUdlbmVyYXRvcjogSW52YWxpZCBmYWtlciBwYXRoIGZvciAke3Byb3AubmFtZX06IGZha2VyLiR7cGF0aH1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyDtlajsiJjqsIAg7JWE64uI66m0IOyXkOufrFxuICAgICAgICBpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZpeHR1cmVHZW5lcmF0b3I6IGZha2VyLiR7cGF0aH0gaXMgbm90IGEgZnVuY3Rpb24gKGZvciAke3Byb3AubmFtZX0pYCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgYXJnczogdW5rbm93bltdID0gW107XG4gICAgICAgIGlmIChhcmdzU3RyPy50cmltKCkpIHtcbiAgICAgICAgICBhcmdzID0gdGhpcy5wYXJzZUdlbmVyYXRvckFyZ3MoYXJnc1N0ciwgcHJvcC5uYW1lKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmbiguLi5hcmdzKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGV4ZWN1dGUgZ2VuZXJhdG9yIFwiJHtnZW5lcmF0b3J9XCIgZm9yICR7cHJvcC5uYW1lfSwgZmFsbGluZyBiYWNrIHRvIGRlZmF1bHQ6YCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICApO1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZURlZmF1bHRWYWx1ZShwcm9wLCBlbnRpdHkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGZha2VyIOydtOyZuOydmCDtkZztmITsi53snYAg7KeA7JuQ7ZWY7KeAIOyViuydjFxuICAgICFpc1Rlc3QoKSAmJlxuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICBgVW5zdXBwb3J0ZWQgZ2VuZXJhdG9yIGV4cHJlc3Npb24gZm9yICR7cHJvcC5uYW1lfTogJHtnZW5lcmF0b3J9LiBPbmx5IGZha2VyLiogZXhwcmVzc2lvbnMgYXJlIHN1cHBvcnRlZC4gVXNpbmcgZGVmYXVsdCB2YWx1ZS5gLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZURlZmF1bHRWYWx1ZShwcm9wLCBlbnRpdHkpO1xuICB9XG5cbiAgLyoqXG4gICAqIO2VhOuTnOydmCDtg4DsnoXqs7wg7J2066aE7J2EIOu2hOyEne2VmOyXrCDsoIHsoIjtlZwg6riw67O46rCS7J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICog7Jqw7ISg7Iic7JyEOlxuICAgKiAxLiDtlYTrk5zrqoUg7Yyo7YS0IOunpOy5rSAoc2FsYXJ5LCBidWRnZXQg65OxIOydmOuvuOyeiOuKlCDrjbDsnbTthLApXG4gICAqIDIuIO2KueyImCDsvIDsnbTsiqQgKERlcGFydG1lbnQgbmFtZSDrk7Eg64+E66mU7J24IOyngOyLnSlcbiAgICogMy4g67Cw7Je0IO2DgOyehSAoSlNPTiDrsLDsl7QpXG4gICAqIDQuIEVudW0g7YOA7J6FXG4gICAqIDUuIO2DgOyeheuzhCDquLDrs7jqsJJcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVEZWZhdWx0VmFsdWUocHJvcDogRW50aXR5UHJvcCwgZW50aXR5PzogRW50aXR5KTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgY29uc3QgZmFrZXJNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgY29uc3QgZmFrZXIgPSBmYWtlck1vZHVsZS5mYWtlcjtcbiAgICBjb25zdCBmYWtlcktPID0gZmFrZXJNb2R1bGUuZmFrZXJLTztcbiAgICBjb25zdCBmYWtlckpBID0gZmFrZXJNb2R1bGUuZmFrZXJKQTtcblxuICAgIGNvbnN0IGxvY2FsZUZha2VyID0gdGhpcy5sb2NhbGUgPT09IFwia29cIiA/IGZha2VyS08gOiB0aGlzLmxvY2FsZSA9PT0gXCJqYVwiID8gZmFrZXJKQSA6IGZha2VyO1xuXG4gICAgLyoqXG4gICAgICogMS4gRW50aXR5LXNwZWNpZmljIO2KueyImCDsvIDsnbTsiqTrpbwg66i87KCAIOyymOumrO2VqeuLiOuLpC5cbiAgICAgKiBmaWVsZF9wYXR0ZXJuc+uztOuLpCDsmrDshKDtlZjsl6wsIO2KueyglSDsl5Tti7Dti7DsnZgg7ZWE65Oc7JeQIOuPhOuplOyduOyXkCDrp57ripQg6rCS7J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICAgKiDsmIg6IERlcGFydG1lbnQubmFtZSDihpIg7ZWc6rWt7Ja0IOu2gOyEnOuqhSAo7IKs656MIOydtOumhOydtCDslYTri5gpXG4gICAgICovXG5cbiAgICAvKipcbiAgICAgKiBEZXBhcnRtZW50IG5hbWXsnYAg7ZWc6rWt7Ja0IOu2gOyEnOuqhSDrqqnroZ3sl5DshJwg7ISg7YOd7ZWp64uI64ukLlxuICAgICAqIOqzoOycoOyEseydhCDsnITtlbQgNzAlIO2ZleuloOuhnCBwcmVmaXgvc3VmZml466W8IOy2lOqwgO2VqeuLiOuLpC5cbiAgICAgKi9cbiAgICBpZiAoZW50aXR5Py5pZCA9PT0gXCJEZXBhcnRtZW50XCIgJiYgcHJvcC5uYW1lID09PSBcIm5hbWVcIikge1xuICAgICAgY29uc3QgZGVwYXJ0bWVudHMgPSBbXG4gICAgICAgIFwi6rCc67Cc7YyAXCIsXG4gICAgICAgIFwi6riw7ZqN7YyAXCIsXG4gICAgICAgIFwi66eI7LyA7YyF7YyAXCIsXG4gICAgICAgIFwi7JiB7JeF7YyAXCIsXG4gICAgICAgIFwi7J247IKs7YyAXCIsXG4gICAgICAgIFwi7LSd66y07YyAXCIsXG4gICAgICAgIFwi7J6s66y07YyAXCIsXG4gICAgICAgIFwi7ZqM6rOE7YyAXCIsXG4gICAgICAgIFwi67KV66y07YyAXCIsXG4gICAgICAgIFwi65SU7J6Q7J247YyAXCIsXG4gICAgICAgIFwiSVTtjIBcIixcbiAgICAgICAgXCLqs6DqsJ3sp4Dsm5DtjIBcIixcbiAgICAgICAgXCLtkojsp4jqtIDrpqztjIBcIixcbiAgICAgICAgXCLsl7DqtazqsJzrsJztjIBcIixcbiAgICAgICAgXCLsg53sgrDtjIBcIixcbiAgICAgICAgXCLqtazrp6TtjIBcIixcbiAgICAgICAgXCLrrLzrpZjtjIBcIixcbiAgICAgIF07XG4gICAgICBjb25zdCBwcmVmaXhlcyA9IFtcIuyLoOq3nFwiLCBcIu2Gte2VqVwiLCBcIuyghOuetVwiLCBcIuq4gOuhnOuyjFwiLCBcIuuUlOyngO2EuFwiLCBcIu2VteyLrFwiXTtcbiAgICAgIGNvbnN0IHN1ZmZpeGVzID0gW1wiMe2MgFwiLCBcIjLtjIBcIiwgXCIz7YyAXCIsIFwiQe2MgFwiLCBcIkLtjIBcIiwgXCLrs7jrtoBcIiwgXCLshLzthLBcIiwgXCLqt7jro7lcIl07XG5cbiAgICAgIGNvbnN0IGRlcHQgPSBmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChkZXBhcnRtZW50cyk7XG5cbiAgICAgIGNvbnN0IHJhbmRvbSA9IE1hdGgucmFuZG9tKCk7XG4gICAgICBpZiAocmFuZG9tID4gMC43KSB7XG4gICAgICAgIGNvbnN0IHByZWZpeCA9IGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KHByZWZpeGVzKTtcbiAgICAgICAgcmV0dXJuIGAke3ByZWZpeH0gJHtkZXB0fWA7XG4gICAgICB9XG4gICAgICBpZiAocmFuZG9tID4gMC40KSB7XG4gICAgICAgIGNvbnN0IHN1ZmZpeCA9IGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KHN1ZmZpeGVzKTtcbiAgICAgICAgcmV0dXJuIGAke2RlcHR9ICR7c3VmZml4fWA7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGVwdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiAyLiDtlYTrk5zrqoXsl5DshJwg7J2Y66+466W8IOy2lOuhoO2VmOyXrCDtmITsi6TsoIHsnbgg642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICAgKiDsmIg6IHNhbGFyeSDihpIgMzBNfjE1ME0gKO2VnOq1rSDsl7DrtIkg67KU7JyEKVxuICAgICAqICAgICBidWRnZXQg4oaSIDEwTX41MDBNICjtlITroZzsoJ3tirgg7JiI7IKwIOuylOychClcbiAgICAgKi9cbiAgICBjb25zdCBsb2NhbGVNYXBwaW5ncyA9IHRoaXMubWFwcGluZ3NbdGhpcy5sb2NhbGVdIHx8IHRoaXMubWFwcGluZ3MuZW47XG4gICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBwcm9wLm5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9fL2csIFwiXCIpO1xuXG4gICAgZm9yIChjb25zdCBbcGF0dGVybiwgY29uZmlnXSBvZiBPYmplY3QuZW50cmllcyhsb2NhbGVNYXBwaW5ncy5maWVsZF9wYXR0ZXJucykpIHtcbiAgICAgIGlmIChub3JtYWxpemVkTmFtZS5pbmNsdWRlcyhwYXR0ZXJuLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZXhlY3V0ZUZha2VyRXhwcmVzc2lvbihjb25maWcuZmFrZXIsIHByb3ApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgRmFpbGVkIHRvIGV4ZWN1dGUgZmllbGQgcGF0dGVybiBcIiR7cGF0dGVybn1cIiBmb3IgJHtwcm9wLm5hbWV9LCBmYWxsaW5nIGJhY2s6YCxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogMy4gSlNPTiDtg4DsnoXsnbTrqbTshJwg67Cw7Je07J24IOqyveyasCAoU29uYW11RmlsZVtdLCBzdHJpbmdbXSDrk7EpXG4gICAgICog7ZWE65Oc66qFIO2MqO2EtOydhCDrs7Tqs6Ag7KCB7KCI7ZWcIOuwsOyXtCDrjbDsnbTthLDrpbwg7IOd7ISx7ZWp64uI64ukLlxuICAgICAqL1xuICAgIGlmIChwcm9wLnR5cGUgPT09IFwianNvblwiICYmIFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQpIHtcbiAgICAgIGlmIChwcm9wLmlkLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVBcnJheVZhbHVlKHByb3AsIGVudGl0eSwgZmFrZXIsIGxvY2FsZUZha2VyKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogNC4gRW51bSDtg4DsnoXsnYAg7KCV7J2Y65CcIOqwkiDspJEg7ZWY64KY66W8IOuenOuNpCDshKDtg53tlanri4jri6QgKi9cbiAgICBpZiAocHJvcC50eXBlID09PSBcImVudW1cIikge1xuICAgICAgbGV0IGVudW1WYWx1ZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGlmIChcImVudW1cIiBpbiBwcm9wICYmIEFycmF5LmlzQXJyYXkocHJvcC5lbnVtKSAmJiBwcm9wLmVudW0ubGVuZ3RoID4gMCkge1xuICAgICAgICBlbnVtVmFsdWVzID0gcHJvcC5lbnVtO1xuICAgICAgfSBlbHNlIGlmIChcImlkXCIgaW4gcHJvcCAmJiBwcm9wLmlkICYmIGVudGl0eT8uZW51bUxhYmVscz8uW3Byb3AuaWRdKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBPYmplY3Qua2V5cyhlbnRpdHkuZW51bUxhYmVsc1twcm9wLmlkXSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbnVtVmFsdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIGZha2VyLmhlbHBlcnMuYXJyYXlFbGVtZW50KGVudW1WYWx1ZXMpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHByb3AubnVsbGFibGUgPyBudWxsIDogXCJVTktOT1dOXCI7XG4gICAgfVxuXG4gICAgaWYgKHByb3AudHlwZSA9PT0gXCJlbnVtW11cIikge1xuICAgICAgbGV0IGVudW1WYWx1ZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgIGlmIChcImVudW1cIiBpbiBwcm9wICYmIEFycmF5LmlzQXJyYXkocHJvcC5lbnVtKSAmJiBwcm9wLmVudW0ubGVuZ3RoID4gMCkge1xuICAgICAgICBlbnVtVmFsdWVzID0gcHJvcC5lbnVtO1xuICAgICAgfSBlbHNlIGlmIChcImlkXCIgaW4gcHJvcCAmJiBwcm9wLmlkICYmIGVudGl0eT8uZW51bUxhYmVscz8uW3Byb3AuaWRdKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBPYmplY3Qua2V5cyhlbnRpdHkuZW51bUxhYmVsc1twcm9wLmlkXSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbnVtVmFsdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIFtmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChlbnVtVmFsdWVzKV07XG4gICAgICB9XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogNS4gVmVjdG9yIO2DgOyeheydgCDtmITsnqwg7KeA7JuQ7ZWY7KeAIOyViuycvOuvgOuhnCBudWxs7J2EIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICAgKiDtlqXtm4QgQUkgZW1iZWRkaW5nIOyDneyEsSDquLDriqUg7LaU6rCAIOyLnCDqtaztmIQg7JiI7KCV7J6F64uI64ukLlxuICAgICAqL1xuICAgIGlmIChwcm9wLnR5cGUgPT09IFwidmVjdG9yXCIgfHwgcHJvcC50eXBlID09PSBcInZlY3RvcltdXCIgfHwgcHJvcC50eXBlID09PSBcInRzdmVjdG9yXCIpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKiA2LiDtg4DsnoXrs4Qg6riw67O4IEZha2VyIO2RnO2YhOyLneydhCDsi6Ttlontlanri4jri6QgKi9cbiAgICBjb25zdCB0eXBlRGVmYXVsdCA9IGxvY2FsZU1hcHBpbmdzLnR5cGVfZGVmYXVsdHNbcHJvcC50eXBlXTtcbiAgICBpZiAodHlwZURlZmF1bHQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmV4ZWN1dGVGYWtlckV4cHJlc3Npb24odHlwZURlZmF1bHQuZmFrZXIsIHByb3ApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBjaGFsay55ZWxsb3coYEZhaWxlZCB0byBleGVjdXRlIHR5cGUgZGVmYXVsdCBmb3IgJHtwcm9wLnR5cGV9LCB1c2luZyBmYWxsYmFjazpgLCBlcnJvciksXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogNy4g66ek7ZWR65CY7KeAIOyViuydgCDtg4DsnoXsnYAg6riw67O4IEZha2VyIO2VqOyImOuhnCDsspjrpqztlanri4jri6QgKi9cbiAgICBzd2l0Y2ggKHByb3AudHlwZSkge1xuICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgY2FzZSBcInN0cmluZ1tdXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5sb3JlbS53b3JkcygzKTtcbiAgICAgIGNhc2UgXCJpbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMDAgfSk7XG4gICAgICBjYXNlIFwiaW50ZWdlcltdXCI6XG4gICAgICAgIHJldHVybiBbZmFrZXIubnVtYmVyLmludCh7IG1pbjogMSwgbWF4OiAxMDAwIH0pXTtcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBmYWtlci5udW1iZXIuYmlnSW50KHsgbWluOiAxbiwgbWF4OiAxMDAwbiB9KTtcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyW11cIjpcbiAgICAgICAgcmV0dXJuIFtmYWtlci5udW1iZXIuYmlnSW50KHsgbWluOiAxbiwgbWF4OiAxMDAwbiB9KV07XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gZmFrZXIubnVtYmVyLmZsb2F0KHsgbWluOiAwLCBtYXg6IDEwMDAgfSk7XG4gICAgICBjYXNlIFwibnVtYmVyW11cIjpcbiAgICAgIGNhc2UgXCJudW1lcmljW11cIjpcbiAgICAgICAgcmV0dXJuIFtmYWtlci5udW1iZXIuZmxvYXQoeyBtaW46IDAsIG1heDogMTAwMCB9KV07XG4gICAgICBjYXNlIFwiYm9vbGVhblwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuZGF0YXR5cGUuYm9vbGVhbigpO1xuICAgICAgY2FzZSBcImJvb2xlYW5bXVwiOlxuICAgICAgICByZXR1cm4gW2Zha2VyLmRhdGF0eXBlLmJvb2xlYW4oKV07XG4gICAgICBjYXNlIFwiZGF0ZVwiOlxuICAgICAgY2FzZSBcImRhdGVbXVwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuZGF0ZS5wYXN0KCk7XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICByZXR1cm4ge307XG4gICAgICBjYXNlIFwidXVpZFwiOlxuICAgICAgY2FzZSBcInV1aWRbXVwiOlxuICAgICAgICByZXR1cm4gZmFrZXIuc3RyaW5nLnV1aWQoKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrsLDsl7Qg7YOA7J6F7J2YIOqwkuydhCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIO2DgOyehSBJROyZgCDtlYTrk5zrqoUg7Yyo7YS07J2EIOu2hOyEne2VmOyXrCDsoIHsoIjtlZwg67Cw7Je0IOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gICAqIOyYiDogaW1hZ2VfdXJscyDihpIgW3t1cmwsIG5hbWUsIG1pbWVfdHlwZX0sIC4uLl1cbiAgICogICAgIHRhZ19pZHMg4oaSIFsxLCAyMywgNDVdXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlQXJyYXlWYWx1ZShcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIF9lbnRpdHk6IEVudGl0eSB8IHVuZGVmaW5lZCxcbiAgICBmYWtlcjogdHlwZW9mIGltcG9ydChcIkBmYWtlci1qcy9mYWtlclwiKS5mYWtlcixcbiAgICBfbG9jYWxlRmFrZXI6IHR5cGVvZiBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIikuZmFrZXIsXG4gICk6IHVua25vd25bXSB7XG4gICAgY29uc3QgY291bnQgPSBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDMgfSk7XG5cbiAgICAvKiogU29uYW11RmlsZVtd7J2AIFNvbmFtdSDrgrTsnqUg7YOA7J6F7Jy866GcIOq1rOyhsOqwgCDsoJXtlbTsoLgg7J6I7Iq164uI64ukICovXG4gICAgaWYgKFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQgPT09IFwiU29uYW11RmlsZVtdXCIpIHtcbiAgICAgIHJldHVybiBBcnJheS5mcm9tKHsgbGVuZ3RoOiBjb3VudCB9LCAoKSA9PiAoe1xuICAgICAgICB1cmw6IGZha2VyLmltYWdlLnVybCgpLFxuICAgICAgICBuYW1lOiBmYWtlci5zeXN0ZW0uZmlsZU5hbWUoKSxcbiAgICAgICAgbWltZV90eXBlOiBmYWtlci5oZWxwZXJzLmFycmF5RWxlbWVudChbXG4gICAgICAgICAgXCJpbWFnZS9qcGVnXCIsXG4gICAgICAgICAgXCJpbWFnZS9wbmdcIixcbiAgICAgICAgICBcImltYWdlL2dpZlwiLFxuICAgICAgICAgIFwiYXBwbGljYXRpb24vcGRmXCIsXG4gICAgICAgIF0pLFxuICAgICAgfSkpO1xuICAgIH1cblxuICAgIC8qKiDtlYTrk5zrqoXsl5DshJwg67Cw7Je07J2YIOyaqeuPhOulvCDstpTroaDtlanri4jri6QgKi9cbiAgICBjb25zdCBub3JtYWxpemVkTmFtZSA9IHByb3AubmFtZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL18vZywgXCJcIik7XG5cbiAgICBpZiAobm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJ1cmxcIikgfHwgbm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJpbWFnZVwiKSkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGg6IGNvdW50IH0sICgpID0+IGZha2VyLmludGVybmV0LnVybCgpKTtcbiAgICB9XG5cbiAgICBpZiAobm9ybWFsaXplZE5hbWUuaW5jbHVkZXMoXCJpZFwiKSAmJiBub3JtYWxpemVkTmFtZS5lbmRzV2l0aChcInNcIikpIHtcbiAgICAgIHJldHVybiBBcnJheS5mcm9tKHsgbGVuZ3RoOiBjb3VudCB9LCAoKSA9PiBmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMCB9KSk7XG4gICAgfVxuXG4gICAgaWYgKG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKFwidGFnXCIpIHx8IG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKFwibmFtZVwiKSkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGg6IGNvdW50IH0sICgpID0+IGZha2VyLmxvcmVtLndvcmQoKSk7XG4gICAgfVxuXG4gICAgLyoqIO2MqO2EtCDrp6Tsua3rkJjsp4Ag7JWK7Jy866m0IOu5iCDrsLDsl7TsnYQg67CY7ZmY7ZWp64uI64ukICovXG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIEpTT04g66ek7ZWR7J2YIEZha2VyIO2RnO2YhOyLneydhCDtjIzsi7HtlZjsl6wg7Iuk7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiDtkZztmITsi50g7JiI7IucOlxuICAgKiAtIFwiZmFrZXIuaW50ZXJuZXQuZW1haWwoKVwiIOKGkiDsnbjsnpAg7JeG7J2MXG4gICAqIC0gXCJmYWtlci5udW1iZXIuaW50KHsgbWluOiAxLCBtYXg6IDEwMCB9KVwiIOKGkiBKU09OIOyduOyekFxuICAgKiAtIFwie31cIiDihpIg66as7YSw65+0IOqwkiAoSlNPTi5wYXJzZSlcbiAgICpcbiAgICogZmFrZXJLTywgZmFrZXJKQeuPhCDsp4Dsm5DtlZjsl6wg64uk6rWt7Ja0IOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVGYWtlckV4cHJlc3Npb24oZXhwcmVzc2lvbjogc3RyaW5nLCBwcm9wOiBFbnRpdHlQcm9wKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgY29uc3QgZmFrZXJNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCJAZmFrZXItanMvZmFrZXJcIik7XG4gICAgY29uc3QgZmFrZXIgPSBmYWtlck1vZHVsZS5mYWtlcjtcbiAgICBjb25zdCBmYWtlcktPID0gZmFrZXJNb2R1bGUuZmFrZXJLTztcbiAgICBjb25zdCBmYWtlckpBID0gZmFrZXJNb2R1bGUuZmFrZXJKQTtcblxuICAgIC8qKiBGYWtlciDtkZztmITsi53snbQg7JWE64uMIOumrO2EsOuftCDqsJLsnYAgSlNPTuycvOuhnCDtjIzsi7Htlanri4jri6QgKi9cbiAgICBpZiAoIWV4cHJlc3Npb24uc3RhcnRzV2l0aChcImZha2VyXCIpKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShleHByZXNzaW9uKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gZXhwcmVzc2lvbjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiog7ZGc7ZiE7Iud7JeQ7IScIEZha2VyIOqwneyytOyZgCDqsr3roZzrpbwg7LaU7Lac7ZWp64uI64ukICovXG4gICAgY29uc3QgbWF0Y2ggPSBleHByZXNzaW9uLm1hdGNoKC9eKGZha2VyfGZha2VyS098ZmFrZXJKQSlcXC4oLio/KSQvKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZmFrZXIgZXhwcmVzc2lvbjogJHtleHByZXNzaW9ufWApO1xuICAgIH1cblxuICAgIGNvbnN0IFssIGZha2VyTmFtZSwgZXhwcl0gPSBtYXRjaDtcbiAgICBjb25zdCBzZWxlY3RlZEZha2VyID1cbiAgICAgIGZha2VyTmFtZSA9PT0gXCJmYWtlcktPXCIgPyBmYWtlcktPIDogZmFrZXJOYW1lID09PSBcImZha2VySkFcIiA/IGZha2VySkEgOiBmYWtlcjtcblxuICAgIGNvbnN0IGZ1bmNNYXRjaCA9IGV4cHIubWF0Y2goL14oW1xcdy5dKykoPzpcXCgoLio/KVxcKSk/JC8pO1xuICAgIGlmICghZnVuY01hdGNoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZmFrZXIgZXhwcmVzc2lvbiBmb3IgJHtwcm9wLm5hbWV9OiAke2V4cHJlc3Npb259YCk7XG4gICAgfVxuXG4gICAgY29uc3QgWywgcGF0aCwgYXJnc1N0cl0gPSBmdW5jTWF0Y2g7XG4gICAgY29uc3QgcGFydHMgPSBwYXRoLnNwbGl0KFwiLlwiKTtcblxuICAgIC8qKiDsoJAg7ZGc6riw67KVKGRvdCBub3RhdGlvbinsnLzroZwgRmFrZXIg7ZWo7IiY66W8IOywvuyVhOqwkeuLiOuLpCAqL1xuICAgIGxldCBmbjogdW5rbm93biA9IHNlbGVjdGVkRmFrZXI7XG4gICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgICBpZiAodHlwZW9mIGZuID09PSBcIm9iamVjdFwiICYmIGZuICE9PSBudWxsICYmIHBhcnQgaW4gZm4pIHtcbiAgICAgICAgZm4gPSAoZm4gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW3BhcnRdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGZha2VyIHBhdGggZm9yICR7cHJvcC5uYW1lfTogJHtmYWtlck5hbWV9LiR7cGF0aH1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtmYWtlck5hbWV9LiR7cGF0aH0gaXMgbm90IGEgZnVuY3Rpb24gKGZvciAke3Byb3AubmFtZX0pYCk7XG4gICAgfVxuXG4gICAgbGV0IGFyZ3M6IHVua25vd25bXSA9IFtdO1xuICAgIGlmIChhcmdzU3RyPy50cmltKCkpIHtcbiAgICAgIGFyZ3MgPSB0aGlzLnBhcnNlR2VuZXJhdG9yQXJncyhhcmdzU3RyLCBwcm9wLm5hbWUpO1xuICAgIH1cblxuICAgIHJldHVybiBmbiguLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBmaXh0dXJlSGludOulvCBMTE3sl5Dqsowg7KCE64us7ZWY7JesIO2YhOyLpOyggeyduCDthYzsiqTtirgg642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogZmFrZXIuanProZzripQg7IOd7ISx7ZWY6riwIOyWtOugpOyatCDrs7XsnqHtlZwg7YWN7Iqk7Yq4KOyekOq4sOyGjOqwnCwg7ISk66qF66y4IOuTsSnrpbxcbiAgICogTExN7J2EIO2ZnOyaqe2VmOyXrCDsg53shLHtlanri4jri6QuIOuPmeydvO2VnCBoaW507JeQIOuMgO2VnCDspJHrs7Ug7Zi47Lac7J2EIOuwqeyngO2VmOq4sCDsnITtlbRcbiAgICog7LqQ7Iux7J2EIOq4sOuzuOycvOuhnCDsp4Dsm5Dtlanri4jri6QgKExMTSBBUEkg67mE7JqpIOygiOqwkCkuXG4gICAqXG4gICAqIGFpIO2MqO2CpOyngOuKlCBkeW5hbWljIGltcG9ydOuhnCDrtojrn6zsmKTrr4DroZwsIHVzZUxMTeydtCBmYWxzZeyduCDqsr3smrBcbiAgICog7J2Y7KG07ISx7J20IOyEpOy5mOuQmOyngCDslYrslYTrj4QgZml4dHVyZSDsg53shLHsnbQg7KCV7IOBIOuPmeyeke2VqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVXaXRoTExNKFxuICAgIGZpeHR1cmVIaW50OiBzdHJpbmcsXG4gICAgcHJvcDogRW50aXR5UHJvcCxcbiAgICBlbnRpdHk6IEVudGl0eSxcbiAgICByb3dLZXk/OiBzdHJpbmcsXG4gICk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIC8vIHJvd0tleeqwgCDsnojsnLzrqbQgcm93IOuLqOychCDsg53shLEg7KCE6561IOyCrOyaqVxuICAgIGlmIChyb3dLZXkpIHtcbiAgICAgIGNvbnN0IHJvd0NhY2hlS2V5ID0gYCR7cm93S2V5fToke3Byb3AubmFtZX1gO1xuXG4gICAgICAvLyDsnbTrr7gg7J20IHJvd+yXkCDrjIDtlZwgTExNIO2YuOy2nOydtCDsmYTro4zrkJwg6rK97JqwIOy6kOyLnOyXkOyEnCDrsJTroZwg67CY7ZmYXG4gICAgICBpZiAodGhpcy5sbG1DYWNoZS5oYXMocm93Q2FjaGVLZXkpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxsbUNhY2hlLmdldChyb3dDYWNoZUtleSk7XG4gICAgICB9XG5cbiAgICAgIC8vIOyDiCByb3c6IExMTSDrjIDsg4EgcHJvcCDsoITssrTrpbwg7ZWcIOuyiOyXkCDsg53shLFcbiAgICAgIGNvbnN0IGxsbVByb3BzID0gZW50aXR5LnByb3BzLmZpbHRlcigocCkgPT4ge1xuICAgICAgICBpZiAoaXNSZWxhdGlvblByb3AocCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKHAuY29uZT8uZml4dHVyZUdlbmVyYXRvcikgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAocC5uYW1lID09PSBcImlkXCIgJiYgcC5jb25lPy5maXh0dXJlU3RyYXRlZ3kgPT09IFwic2VxdWVuY2VcIikgcmV0dXJuIGZhbHNlO1xuICAgICAgICByZXR1cm4gISFwLmNvbmU/Lm5vdGU7XG4gICAgICB9KTtcblxuICAgICAgLy8gbGxtUHJvcHPqsIAg67mE7Ja07J6I7Jy866m0IOuLqOydvCDtlYTrk5wg67Cp7Iud7Jy866GcIGZhbGxiYWNrXG4gICAgICBpZiAobGxtUHJvcHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgYFtGaXh0dXJlR2VuZXJhdG9yXSBsbG1Qcm9wcyBpcyBlbXB0eSBmb3IgJHtlbnRpdHkuaWR9LiR7cHJvcC5uYW1lfSwgdXNpbmcgc2luZ2xlIGZpZWxkIGZhbGxiYWNrYCxcbiAgICAgICAgICApO1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZVNpbmdsZVdpdGhMTE0oZml4dHVyZUhpbnQsIHByb3AsIGVudGl0eSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFwaUtleSA9IHRoaXMuZ2V0QXBpS2V5KCk7XG4gICAgICBjb25zdCB7IGNyZWF0ZUFudGhyb3BpYyB9ID0gYXdhaXQgaW1wb3J0KFwiQGFpLXNkay9hbnRocm9waWNcIik7XG4gICAgICBjb25zdCB7IGdlbmVyYXRlVGV4dCB9ID0gYXdhaXQgaW1wb3J0KFwiYWlcIik7XG5cbiAgICAgIGNvbnN0IHJvd1Jlc3BvbnNlID0gYXdhaXQgZ2VuZXJhdGVUZXh0KHtcbiAgICAgICAgbW9kZWw6IGNyZWF0ZUFudGhyb3BpYyh7IGFwaUtleSB9KSh0aGlzLm9wdGlvbnMubGxtTW9kZWwgfHwgXCJjbGF1ZGUtc29ubmV0LTQtNlwiKSxcbiAgICAgICAgcHJvbXB0OiB0aGlzLmJ1aWxkUm93TExNUHJvbXB0KGxsbVByb3BzLCBlbnRpdHkpLFxuICAgICAgfSk7XG4gICAgICBpZiAoIXJvd1Jlc3BvbnNlIHx8IHR5cGVvZiByb3dSZXNwb25zZS50ZXh0ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgTExNIHJlc3BvbnNlXCIpO1xuICAgICAgfVxuXG4gICAgICAvLyDsnZHri7XsnYQg7YyM7Iux7ZWY7JesIOqwgSDtlYTrk5zsl5Ag64yA7ZWcIOqysOqzvOulvCDsupDsi5zsl5Ag7KCA7J6lXG4gICAgICBjb25zdCByb3dSZXN1bHQgPSB0aGlzLnBhcnNlUm93TExNUmVzcG9uc2Uocm93UmVzcG9uc2UudGV4dCwgbGxtUHJvcHMpO1xuICAgICAgZm9yIChjb25zdCBbZmllbGROYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocm93UmVzdWx0KSkge1xuICAgICAgICB0aGlzLmxsbUNhY2hlLnNldChgJHtyb3dLZXl9OiR7ZmllbGROYW1lfWAsIHZhbHVlKTtcbiAgICAgIH1cblxuICAgICAgLy8g7JqU7LKt7ZWcIO2VhOuTnOydmCDqsJIg67CY7ZmYICjsl4bsnLzrqbQg64uo7J28IO2VhOuTnCBmYWxsYmFjaylcbiAgICAgIGlmICh0aGlzLmxsbUNhY2hlLmhhcyhyb3dDYWNoZUtleSkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubGxtQ2FjaGUuZ2V0KHJvd0NhY2hlS2V5KTtcbiAgICAgIH1cblxuICAgICAgLy8g66eM7JW9IHJvdyDsnZHri7Xsl5Ag7J20IO2VhOuTnOqwgCDriITrnb3rkJwg6rK97JqwIOuLqOydvCDtlYTrk5wgZmFsbGJhY2tcbiAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlU2luZ2xlV2l0aExMTShmaXh0dXJlSGludCwgcHJvcCwgZW50aXR5KTtcbiAgICB9XG5cbiAgICAvLyByb3dLZXnqsIAg7JeG7Jy866m0IOq4sOyhtCDri6jsnbwg7ZWE65OcIOuwqeyLnVxuICAgIHJldHVybiB0aGlzLmdlbmVyYXRlU2luZ2xlV2l0aExMTShmaXh0dXJlSGludCwgcHJvcCwgZW50aXR5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiDri6jsnbwg7ZWE65Oc66W8IExMTeycvOuhnCDsg53shLHtlanri4jri6QgKHJvd0tleSDsl4bsnYQg65WMIGZhbGxiYWNr7JqpKVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZW5lcmF0ZVNpbmdsZVdpdGhMTE0oXG4gICAgZml4dHVyZUhpbnQ6IHN0cmluZyxcbiAgICBwcm9wOiBFbnRpdHlQcm9wLFxuICAgIGVudGl0eTogRW50aXR5LFxuICApOiBQcm9taXNlPHVua25vd24+IHtcbiAgICBjb25zdCBjYWNoZUtleSA9IGAke2VudGl0eS5pZH06JHtwcm9wLm5hbWV9OiR7Zml4dHVyZUhpbnR9YDtcbiAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxMTUNhY2hlICYmIHRoaXMubGxtQ2FjaGUuaGFzKGNhY2hlS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMubGxtQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICB9XG5cbiAgICBjb25zdCBhcGlLZXkgPSB0aGlzLmdldEFwaUtleSgpO1xuICAgIGNvbnN0IHsgY3JlYXRlQW50aHJvcGljIH0gPSBhd2FpdCBpbXBvcnQoXCJAYWktc2RrL2FudGhyb3BpY1wiKTtcbiAgICBjb25zdCB7IGdlbmVyYXRlVGV4dCB9ID0gYXdhaXQgaW1wb3J0KFwiYWlcIik7XG5cbiAgICBjb25zdCBzaW5nbGVSZXNwb25zZSA9IGF3YWl0IGdlbmVyYXRlVGV4dCh7XG4gICAgICBtb2RlbDogY3JlYXRlQW50aHJvcGljKHsgYXBpS2V5IH0pKHRoaXMub3B0aW9ucy5sbG1Nb2RlbCB8fCBcImNsYXVkZS1zb25uZXQtNC02XCIpLFxuICAgICAgcHJvbXB0OiB0aGlzLmJ1aWxkTExNUHJvbXB0KGZpeHR1cmVIaW50LCBwcm9wLCBlbnRpdHkpLFxuICAgIH0pO1xuICAgIGlmICghc2luZ2xlUmVzcG9uc2UgfHwgdHlwZW9mIHNpbmdsZVJlc3BvbnNlLnRleHQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgTExNIHJlc3BvbnNlXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5wYXJzZUxMTVJlc3BvbnNlKHNpbmdsZVJlc3BvbnNlLnRleHQsIHByb3AudHlwZSk7XG4gICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMTE1DYWNoZSkge1xuICAgICAgdGhpcy5sbG1DYWNoZS5zZXQoY2FjaGVLZXksIHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogcm93IOyghOyytOulvCDtlZwg67KI7JeQIOyDneyEse2VmOuKlCBMTE0g7ZSE66Gs7ZSE7Yq466W8IOunjOuTreuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRSb3dMTE1Qcm9tcHQocHJvcHM6IEVudGl0eVByb3BbXSwgZW50aXR5OiBFbnRpdHkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGxvY2FsZSA9IHRoaXMub3B0aW9ucy5sb2NhbGUgfHwgXCJrb1wiO1xuICAgIGNvbnN0IGxhbmd1YWdlID0gbG9jYWxlID09PSBcImtvXCIgPyBcIktvcmVhblwiIDogbG9jYWxlID09PSBcImphXCIgPyBcIkphcGFuZXNlXCIgOiBcIkVuZ2xpc2hcIjtcblxuICAgIGNvbnN0IGZpZWxkRGVzY3JpcHRpb25zID0gcHJvcHNcbiAgICAgIC5tYXAoKHApID0+IHtcbiAgICAgICAgbGV0IGRlc2MgPSBgLSAke3AubmFtZX0gKCR7cC50eXBlfSk6ICR7cC5jb25lPy5ub3RlID8/IFwiXCJ9YDtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIChwLnR5cGUgPT09IFwiZW51bVwiIHx8IHAudHlwZSA9PT0gXCJlbnVtW11cIikgJiZcbiAgICAgICAgICBcImlkXCIgaW4gcCAmJlxuICAgICAgICAgIHAuaWQgJiZcbiAgICAgICAgICBlbnRpdHkuZW51bUxhYmVscz8uW3AuaWRdXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IHZhbHVlcyA9IE9iamVjdC5rZXlzKGVudGl0eS5lbnVtTGFiZWxzW3AuaWRdKS5qb2luKFwiLCBcIik7XG4gICAgICAgICAgZGVzYyArPSBgIFthbGxvd2VkIHZhbHVlczogJHt2YWx1ZXN9XWA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgICB9KVxuICAgICAgLmpvaW4oXCJcXG5cIik7XG5cbiAgICAvLyBMTE0g64yA7IOB7J20IOyVhOuLjCBwcm9w65Ok64+EIOunpeudveycvOuhnCDsoJzqs7UgKHJlbGF0aW9uIOygnOyZuClcbiAgICBjb25zdCBvdGhlclByb3BzID0gZW50aXR5LnByb3BzXG4gICAgICAuZmlsdGVyKFxuICAgICAgICAocCkgPT5cbiAgICAgICAgICAhcHJvcHMuaW5jbHVkZXMocCkgJiZcbiAgICAgICAgICAhaXNSZWxhdGlvblByb3AocCkgJiZcbiAgICAgICAgICBwLm5hbWUgIT09IFwiaWRcIiAmJlxuICAgICAgICAgICEoXCJ2aXJ0dWFsXCIgaW4gcCAmJiBwLnZpcnR1YWwpLFxuICAgICAgKVxuICAgICAgLm1hcCgocCkgPT4ge1xuICAgICAgICBsZXQgZGVzYyA9IGAtICR7cC5uYW1lfSAoJHtwLnR5cGV9KWA7XG4gICAgICAgIGlmIChwLmNvbmU/Lm5vdGUpIGRlc2MgKz0gYDogJHtwLmNvbmUubm90ZX1gO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgKHAudHlwZSA9PT0gXCJlbnVtXCIgfHwgcC50eXBlID09PSBcImVudW1bXVwiKSAmJlxuICAgICAgICAgIFwiaWRcIiBpbiBwICYmXG4gICAgICAgICAgcC5pZCAmJlxuICAgICAgICAgIGVudGl0eS5lbnVtTGFiZWxzPy5bcC5pZF1cbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWVzID0gT2JqZWN0LmtleXMoZW50aXR5LmVudW1MYWJlbHNbcC5pZF0pLmpvaW4oXCIsIFwiKTtcbiAgICAgICAgICBkZXNjICs9IGAgW2FsbG93ZWQgdmFsdWVzOiAke3ZhbHVlc31dYDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGVzYztcbiAgICAgIH0pXG4gICAgICAuam9pbihcIlxcblwiKTtcbiAgICBjb25zdCBvdGhlclByb3BzQ29udGV4dCA9IG90aGVyUHJvcHNcbiAgICAgID8gYFxcblxcbk90aGVyIGZpZWxkcyBpbiB0aGlzIGVudGl0eSAoZm9yIGNvbnRleHQsIGRvIE5PVCBnZW5lcmF0ZSB0aGVzZSk6XFxuJHtvdGhlclByb3BzfWBcbiAgICAgIDogXCJcIjtcblxuICAgIGNvbnN0IG91dHB1dFNoYXBlID0gcHJvcHMubWFwKChwKSA9PiBgICBcIiR7cC5uYW1lfVwiOiA8JHtwLnR5cGV9PmApLmpvaW4oXCIsXFxuXCIpO1xuXG4gICAgY29uc3QgZW50aXR5Q29udGV4dCA9IGVudGl0eS5jb25lPy5ub3RlID8gYFxcbkVudGl0eSBkZXNjcmlwdGlvbjogJHtlbnRpdHkuY29uZS5ub3RlfWAgOiBcIlwiO1xuXG4gICAgcmV0dXJuIGBHZW5lcmF0ZSB0ZXN0IGZpeHR1cmUgZGF0YSBmb3IgdGhlICR7ZW50aXR5LmlkfSBlbnRpdHkuIEFsbCBmaWVsZHMgbXVzdCBiZSBjb2hlcmVudCBhbmQgY29uc2lzdGVudCB3aXRoIGVhY2ggb3RoZXIuXG5cbkVudGl0eTogJHtlbnRpdHkuaWR9JHtlbnRpdHlDb250ZXh0fVxuTG9jYWxlOiAke2xvY2FsZX0gKHVzZSAke2xhbmd1YWdlfSBmb3IgdGV4dCBmaWVsZHMpXG5cbkZpZWxkcyB0byBnZW5lcmF0ZTpcbiR7ZmllbGREZXNjcmlwdGlvbnN9JHtvdGhlclByb3BzQ29udGV4dH1cblxuUnVsZXM6XG4tIEFsbCBmaWVsZHMgaW4gYSBzaW5nbGUgcm93IG11c3QgYmUgbG9naWNhbGx5IGNvbnNpc3RlbnQgKGUuZy4gbmFtZS9uYW1lX2VuL25hbWVfY24gc2hvdWxkIHJlcHJlc2VudCB0aGUgc2FtZSBwZXJzb24pXG4tIFJldHVybiBPTkxZIHZhbGlkIEpTT04sIG5vIG1hcmtkb3duIG9yIGV4cGxhbmF0aW9uXG4tIERhdGVzIGluIElTTyA4NjAxIGZvcm1hdFxuLSBVc2UgJHtsYW5ndWFnZX0gZm9yIHRleHQgdW5sZXNzIGZpZWxkIGRlc2NyaXB0aW9uIHNheXMgb3RoZXJ3aXNlXG5cblJldHVybiBleGFjdGx5IHRoaXMgSlNPTiBzaGFwZTpcbntcbiR7b3V0cHV0U2hhcGV9XG59YDtcbiAgfVxuXG4gIC8qKlxuICAgKiByb3cgTExNIOydkeuLteydhCDtjIzsi7HtlZjsl6wg7ZWE65Oc67OEIOqwkuycvOuhnCDrs4DtmZjtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIHBhcnNlUm93TExNUmVzcG9uc2UodGV4dDogc3RyaW5nLCBwcm9wczogRW50aXR5UHJvcFtdKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIGNvbnN0IGpzb25UZXh0ID0gdGV4dFxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlcGxhY2UoL15gYGBqc29uXFxzKi9pLCBcIlwiKVxuICAgICAgLnJlcGxhY2UoL2BgYFxccyokLywgXCJcIilcbiAgICAgIC50cmltKCk7XG5cbiAgICBsZXQgcGFyc2VkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmF3ID0gSlNPTi5wYXJzZShqc29uVGV4dCk7XG4gICAgICBpZiAodHlwZW9mIHJhdyAhPT0gXCJvYmplY3RcIiB8fCByYXcgPT09IG51bGwgfHwgQXJyYXkuaXNBcnJheShyYXcpKSB7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUud2FybihcIltGaXh0dXJlR2VuZXJhdG9yXSBSb3cgTExNIHJlc3BvbnNlIGlzIG5vdCBhIHBsYWluIG9iamVjdDpcIiwgdGV4dCk7XG4gICAgICAgIHJldHVybiB7fTtcbiAgICAgIH1cbiAgICAgIHBhcnNlZCA9IHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB9IGNhdGNoIHtcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLndhcm4oXCJbRml4dHVyZUdlbmVyYXRvcl0gRmFpbGVkIHRvIHBhcnNlIHJvdyBMTE0gcmVzcG9uc2U6XCIsIHRleHQpO1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgcHJvcHMpIHtcbiAgICAgIGlmIChwcm9wLm5hbWUgaW4gcGFyc2VkKSB7XG4gICAgICAgIHJlc3VsdFtwcm9wLm5hbWVdID0gdGhpcy5wYXJzZUxMTVJlc3BvbnNlKFN0cmluZyhwYXJzZWRbcHJvcC5uYW1lXSA/PyBcIlwiKSwgcHJvcC50eXBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRMTE1Qcm9tcHQoaGludDogc3RyaW5nLCBwcm9wOiBFbnRpdHlQcm9wLCBlbnRpdHk6IEVudGl0eSk6IHN0cmluZyB7XG4gICAgY29uc3QgbG9jYWxlID0gdGhpcy5vcHRpb25zLmxvY2FsZSB8fCBcImtvXCI7XG4gICAgY29uc3QgbGFuZ3VhZ2UgPSBsb2NhbGUgPT09IFwia29cIiA/IFwiS29yZWFuXCIgOiBsb2NhbGUgPT09IFwiamFcIiA/IFwiSmFwYW5lc2VcIiA6IFwiRW5nbGlzaFwiO1xuXG4gICAgY29uc3QgZW50aXR5Q29udGV4dCA9IGVudGl0eS5jb25lPy5ub3RlID8gYFxcbkVudGl0eSBjb250ZXh0OiAke2VudGl0eS5jb25lLm5vdGV9YCA6IFwiXCI7XG5cbiAgICBjb25zdCBvdGhlckZpZWxkcyA9IGVudGl0eS5wcm9wc1xuICAgICAgLmZpbHRlcigocCkgPT4gcC5uYW1lICE9PSBwcm9wLm5hbWUgJiYgIWlzUmVsYXRpb25Qcm9wKHApICYmIHAuY29uZT8ubm90ZSlcbiAgICAgIC5tYXAoKHApID0+IGAtICR7cC5uYW1lfSAoJHtwLnR5cGV9KTogJHtwLmNvbmU/Lm5vdGV9YClcbiAgICAgIC5qb2luKFwiXFxuXCIpO1xuICAgIGNvbnN0IG90aGVyRmllbGRzQ29udGV4dCA9IG90aGVyRmllbGRzXG4gICAgICA/IGBcXG5cXG5PdGhlciBmaWVsZHMgaW4gdGhpcyBlbnRpdHkgKGZvciBjb250ZXh0KTpcXG4ke290aGVyRmllbGRzfWBcbiAgICAgIDogXCJcIjtcblxuICAgIGxldCBwcm9tcHQgPSBgR2VuZXJhdGUgdGVzdCBkYXRhIGZvciAke2VudGl0eS5pZH0uJHtwcm9wLm5hbWV9ICh0eXBlOiAke3Byb3AudHlwZX0pJHtlbnRpdHlDb250ZXh0fSR7b3RoZXJGaWVsZHNDb250ZXh0fVxuXG5SZXF1aXJlbWVudDogJHtoaW50fVxuXG5SdWxlczpcbi0gUmV0dXJuIE9OTFkgdGhlIHZhbHVlLCBubyBleHBsYW5hdGlvbiBvciBtYXJrZG93blxuLSBVc2UgJHtsYW5ndWFnZX0gbGFuZ3VhZ2UgaWYgYXBwbGljYWJsZVxuLSBGb3JtYXQ6ICR7dGhpcy5nZXRFeHBlY3RlZEZvcm1hdChwcm9wLnR5cGUpfWA7XG5cbiAgICAvLyBlbnVtIO2DgOyeheyduCDqsr3smrAg6rCA64ql7ZWcIOqwkiDrqqnroZ0g7LaU6rCAXG4gICAgaWYgKHByb3AudHlwZSA9PT0gXCJlbnVtXCIgfHwgcHJvcC50eXBlID09PSBcImVudW1bXVwiKSB7XG4gICAgICBsZXQgZW51bVZhbHVlczogc3RyaW5nW10gPSBbXTtcblxuICAgICAgaWYgKFwiZW51bVwiIGluIHByb3AgJiYgQXJyYXkuaXNBcnJheShwcm9wLmVudW0pICYmIHByb3AuZW51bS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGVudW1WYWx1ZXMgPSBwcm9wLmVudW07XG4gICAgICB9IGVsc2UgaWYgKFwiaWRcIiBpbiBwcm9wICYmIHByb3AuaWQgJiYgZW50aXR5Py5lbnVtTGFiZWxzPy5bcHJvcC5pZF0pIHtcbiAgICAgICAgZW51bVZhbHVlcyA9IE9iamVjdC5rZXlzKGVudGl0eS5lbnVtTGFiZWxzW3Byb3AuaWRdKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVudW1WYWx1ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBwcm9tcHQgKz0gYFxcbi0gSU1QT1JUQU5UOiBDaG9vc2UgT05MWSBmcm9tIHRoZXNlIGFsbG93ZWQgdmFsdWVzOiAke2VudW1WYWx1ZXMuam9pbihcIiwgXCIpfWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcHJvbXB0ICs9IGBcXG5cXG5FeGFtcGxlOiAke3RoaXMuZ2V0RXhhbXBsZUZvclR5cGUocHJvcC50eXBlLCBsb2NhbGUpfWA7XG5cbiAgICByZXR1cm4gcHJvbXB0O1xuICB9XG5cbiAgcHJpdmF0ZSBwYXJzZUxMTVJlc3BvbnNlKHRleHQ6IHN0cmluZywgcHJvcFR5cGU6IHN0cmluZyk6IHVua25vd24ge1xuICAgIGNvbnN0IGNsZWFuZWQgPSB0ZXh0LnRyaW0oKTtcblxuICAgIC8vIOuwsOyXtCDtg4DsnoUg7LKY66asXG4gICAgaWYgKHByb3BUeXBlLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoY2xlYW5lZCk7XG4gICAgICAgIGNvbnN0IGJhc2VUeXBlID0gcHJvcFR5cGUuc2xpY2UoMCwgLTIpOyAvLyBcImludGVnZXJbXVwiIC0+IFwiaW50ZWdlclwiXG5cbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGFyc2VkKSkge1xuICAgICAgICAgIHJldHVybiBwYXJzZWQubWFwKChpdGVtKSA9PiB7XG4gICAgICAgICAgICAvLyBudWxsL3VuZGVmaW5lZOuKlCDtg4DsnoXrs4Qg6riw67O46rCS7Jy866GcXG4gICAgICAgICAgICBpZiAoaXRlbSA9PT0gbnVsbCB8fCBpdGVtID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0RGVmYXVsdFZhbHVlRm9yVHlwZShiYXNlVHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyDqsJ3ssrTripQgSlNPTi5zdHJpbmdpZnkg7ZuEIO2MjOyLsSAoanNvbiDtg4DsnoXsnbgg6rK97JqwKVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBiYXNlVHlwZSA9PT0gXCJqc29uXCJcbiAgICAgICAgICAgICAgICA/IGl0ZW1cbiAgICAgICAgICAgICAgICA6IHRoaXMucGFyc2VTY2FsYXJWYWx1ZShKU09OLnN0cmluZ2lmeShpdGVtKSwgYmFzZVR5cGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gcHJpbWl0aXZlIOqwkuydgCDrrLjsnpDsl7TroZwg67OA7ZmYIO2bhCDtjIzsi7FcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcnNlU2NhbGFyVmFsdWUoU3RyaW5nKGl0ZW0pLCBiYXNlVHlwZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyDri6jsnbwg6rCS7J20IOyYqCDqsr3smrAg67Cw7Je066GcIOqwkOyLuOq4sFxuICAgICAgICBpZiAocGFyc2VkID09PSBudWxsIHx8IHBhcnNlZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIFt0aGlzLmdldERlZmF1bHRWYWx1ZUZvclR5cGUoYmFzZVR5cGUpXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW3RoaXMucGFyc2VTY2FsYXJWYWx1ZShTdHJpbmcocGFyc2VkKSwgYmFzZVR5cGUpXTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucGFyc2VTY2FsYXJWYWx1ZShjbGVhbmVkLCBwcm9wVHlwZSk7XG4gIH1cblxuICBwcml2YXRlIGdldERlZmF1bHRWYWx1ZUZvclR5cGUocHJvcFR5cGU6IHN0cmluZyk6IHVua25vd24ge1xuICAgIHN3aXRjaCAocHJvcFR5cGUpIHtcbiAgICAgIGNhc2UgXCJpbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgY2FzZSBcImJpZ0ludGVnZXJcIjpcbiAgICAgICAgcmV0dXJuIDBuO1xuICAgICAgY2FzZSBcImZsb2F0XCI6XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gMDtcbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIGNhc2UgXCJkYXRlXCI6XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZSgpO1xuICAgICAgY2FzZSBcImpzb25cIjpcbiAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgICAgcmV0dXJuIFwiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwXCI7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHBhcnNlU2NhbGFyVmFsdWUodGV4dDogc3RyaW5nLCBwcm9wVHlwZTogc3RyaW5nKTogdW5rbm93biB7XG4gICAgY29uc3QgY2xlYW5lZCA9IHRleHQudHJpbSgpO1xuXG4gICAgc3dpdGNoIChwcm9wVHlwZSkge1xuICAgICAgY2FzZSBcImludGVnZXJcIjoge1xuICAgICAgICBjb25zdCBudW0gPSBwYXJzZUludChjbGVhbmVkLCAxMCk7XG4gICAgICAgIHJldHVybiBOdW1iZXIuaXNOYU4obnVtKSA/IDAgOiBudW07XG4gICAgICB9XG4gICAgICBjYXNlIFwiYmlnSW50ZWdlclwiOiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIEJpZ0ludChjbGVhbmVkKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgcmV0dXJuIDBuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjYXNlIFwiZmxvYXRcIjpcbiAgICAgIGNhc2UgXCJudW1iZXJcIjpcbiAgICAgIGNhc2UgXCJudW1lcmljXCI6IHtcbiAgICAgICAgY29uc3QgbnVtID0gcGFyc2VGbG9hdChjbGVhbmVkKTtcbiAgICAgICAgcmV0dXJuIE51bWJlci5pc05hTihudW0pID8gMCA6IG51bTtcbiAgICAgIH1cbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBjbGVhbmVkLnRvTG93ZXJDYXNlKCkgPT09IFwidHJ1ZVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjoge1xuICAgICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoY2xlYW5lZCk7XG4gICAgICAgIHJldHVybiBOdW1iZXIuaXNOYU4oZGF0ZS5nZXRUaW1lKCkpID8gbmV3IERhdGUoKSA6IGRhdGU7XG4gICAgICB9XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICB0cnkge1xuICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGNsZWFuZWQpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm4gY2xlYW5lZDtcbiAgICAgICAgfVxuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgIGNhc2UgXCJlbnVtXCI6XG4gICAgICAgIHJldHVybiBjbGVhbmVkO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGNsZWFuZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIGZha2VyIO2VqOyImCDsnbjsnpAg66y47J6Q7Je07J2EIO2MjOyLse2VmOyXrCDsnbjsnpAg67Cw7Je066GcIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICogM+uLqOqzhCDsoITrnrU6XG4gICAqIDEuIEpTT04g7KeB7KCRIO2MjOyLsSAo7ZGc7KSAIEpTT04g7ZGc7ZiE7IudKVxuICAgKiAyLiBKUyDqsJ3ssrQg66as7YSw65+0IOKGkiBKU09OIOuzgO2ZmCDtm4Qg7J6s7Iuc64+EIChzaW5nbGUgcXVvdGUsIHVucXVvdGVkIGtleSDsspjrpqwpXG4gICAqIDMuIOuLqOyInCDri6jsnbwg7J247J6QIO2PtOuwsSAo7Iir7J6QLCDrrLjsnpDsl7QpXG4gICAqL1xuICBwcml2YXRlIHBhcnNlR2VuZXJhdG9yQXJncyhhcmdzU3RyOiBzdHJpbmcsIHByb3BOYW1lOiBzdHJpbmcpOiB1bmtub3duW10ge1xuICAgIC8vIDEuIEpTT04g7KeB7KCRIO2MjOyLsVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGBbJHthcmdzU3RyfV1gKSBhcyB1bmtub3duO1xuICAgICAgcmV0dXJuIEFycmF5LmlzQXJyYXkocGFyc2VkKSA/IHBhcnNlZCA6IFtwYXJzZWRdO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8g6rOE7IaNXG4gICAgfVxuXG4gICAgLy8gMi4gSlMg6rCd7LK0IOumrO2EsOuftCDihpIgSlNPTiDrs4DtmZgg7ZuEIOyerOyLnOuPhFxuICAgIHRyeSB7XG4gICAgICBjb25zdCBqc29uU3RyID0gdGhpcy5jb252ZXJ0SnNMaXRlcmFsVG9Kc29uKGFyZ3NTdHIpO1xuICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShgWyR7anNvblN0cn1dYCkgYXMgdW5rbm93bjtcbiAgICAgIHJldHVybiBBcnJheS5pc0FycmF5KHBhcnNlZCkgPyBwYXJzZWQgOiBbcGFyc2VkXTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIOqzhOyGjVxuICAgIH1cblxuICAgIC8vIDMuIOuLqOyInCDri6jsnbwg7J247J6QIO2PtOuwsVxuICAgIGNvbnN0IHRyaW1tZWQgPSBhcmdzU3RyLnRyaW0oKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihOdW1iZXIodHJpbW1lZCkpKSB7XG4gICAgICByZXR1cm4gW051bWJlcih0cmltbWVkKV07XG4gICAgfVxuICAgIGlmIChcbiAgICAgICh0cmltbWVkLnN0YXJ0c1dpdGgoJ1wiJykgJiYgdHJpbW1lZC5lbmRzV2l0aCgnXCInKSkgfHxcbiAgICAgICh0cmltbWVkLnN0YXJ0c1dpdGgoXCInXCIpICYmIHRyaW1tZWQuZW5kc1dpdGgoXCInXCIpKVxuICAgICkge1xuICAgICAgcmV0dXJuIFt0cmltbWVkLnNsaWNlKDEsIC0xKV07XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBGaXh0dXJlR2VuZXJhdG9yOiBDYW5ub3QgcGFyc2UgYXJndW1lbnRzIGZvciAke3Byb3BOYW1lfTogJHthcmdzU3RyfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEpTIOqwneyytCDrpqzthLDrn7TsnYQgSlNPTuycvOuhnCDrs4DtmZjtlanri4jri6QuXG4gICAqXG4gICAqIOuRkCDqsIDsp4Ag67OA7ZmYOlxuICAgKiAxLiBTaW5nbGUtcXVvdGVkIOusuOyekOyXtCDihpIgZG91YmxlLXF1b3RlZCAo7J207Iqk7LyA7J207ZSEIOyymOumrCDtj6ztlagpXG4gICAqIDIuIFVucXVvdGVkIOqwneyytCDtgqQg4oaSIGRvdWJsZS1xdW90ZWRcbiAgICovXG4gIHByaXZhdGUgY29udmVydEpzTGl0ZXJhbFRvSnNvbihpbnB1dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyAxLiAndmFsdWUnIOKGkiBcInZhbHVlXCIgKOuCtOu2gCBcIiDsnbTsiqTsvIDsnbTtlIQsIFxcJyDihpIgJylcbiAgICBjb25zdCB3aXRoRG91YmxlUXVvdGVzID0gaW5wdXQucmVwbGFjZShcbiAgICAgIC8nKFteJ1xcXFxdKig/OlxcXFwuW14nXFxcXF0qKSopJy9nLFxuICAgICAgKF8sIGNvbnRlbnQ6IHN0cmluZykgPT4gYFwiJHtjb250ZW50LnJlcGxhY2UoL1wiL2csICdcXFxcXCInKS5yZXBsYWNlKC9cXFxcJy9nLCBcIidcIil9XCJgLFxuICAgICk7XG5cbiAgICAvLyAyLiB7IGtleTog4oaSIHsgXCJrZXlcIjpcbiAgICByZXR1cm4gd2l0aERvdWJsZVF1b3Rlcy5yZXBsYWNlKC8oW3ssXVxccyopKFthLXpBLVpfJF1bXFx3JF0qKShcXHMqOikvZywgJyQxXCIkMlwiJDMnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTb25hbXUuc2VjcmV07J2EIOyasOyEoOycvOuhnCDtlZjqs6AsIOyXhuycvOuptCDtmZjqsr3rs4DsiJjsl5DshJwgQVBJIO2CpOulvCDsnb3sirXri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdS5zZWNyZXTsnYAg7ZSE66Gc7KCd7Yq467OEIOyEpOyglShzb25hbXUuY29uZmlnLnRzKeydtOuvgOuhnCDrjZQg64aS7J2AIOyasOyEoOyInOychOulvCDqsIDsp4DrqbAsXG4gICAqIO2ZmOqyveuzgOyImOuKlCDqsJzrsJwg7ZmY6rK97J2064KYIENJL0NE7JeQ7IScIGZhbGxiYWNr7Jy866GcIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgZ2V0QXBpS2V5KCk6IHN0cmluZyB7XG4gICAgbGV0IGFwaUtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgU29uYW11IH0gPSByZXF1aXJlKFwiLi4vYXBpXCIpO1xuICAgICAgYXBpS2V5ID0gU29uYW11LnNlY3JldHM/LmFudGhyb3BpY19hcGlfa2V5O1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gU29uYW116rCAIOy0iOq4sO2ZlOuQmOyngCDslYrsnYAg6rK97JqwICjthYzsiqTtirgg7ZmY6rK9IOuTsSlcbiAgICB9XG5cbiAgICBpZiAoIWFwaUtleSkge1xuICAgICAgYXBpS2V5ID0gcHJvY2Vzcy5lbnYuQU5USFJPUElDX0FQSV9LRVk7XG4gICAgfVxuXG4gICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJBTlRIUk9QSUNfQVBJX0tFWSBub3QgZm91bmQuIFNldCBpdCBpbiBlbnZpcm9ubWVudCB2YXJpYWJsZXMgb3IgU29uYW11LnNlY3JldC5hbnRocm9waWNfYXBpX2tleVwiLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXBpS2V5O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRFeHBlY3RlZEZvcm1hdChwcm9wVHlwZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyDrsLDsl7Qg7YOA7J6FIOyymOumrFxuICAgIGlmIChwcm9wVHlwZS5lbmRzV2l0aChcIltdXCIpKSB7XG4gICAgICBjb25zdCBiYXNlVHlwZSA9IHByb3BUeXBlLnNsaWNlKDAsIC0yKTtcbiAgICAgIGNvbnN0IGJhc2VGb3JtYXQgPSB0aGlzLmdldFNjYWxhckZvcm1hdChiYXNlVHlwZSk7XG4gICAgICByZXR1cm4gYEpTT04gYXJyYXkgb2YgJHtiYXNlRm9ybWF0fSAoZS5nLiwgWyR7dGhpcy5nZXRFeGFtcGxlRm9yVHlwZShiYXNlVHlwZSwgXCJlblwiKX0sIC4uLl0pYDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5nZXRTY2FsYXJGb3JtYXQocHJvcFR5cGUpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRTY2FsYXJGb3JtYXQocHJvcFR5cGU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgc3dpdGNoIChwcm9wVHlwZSkge1xuICAgICAgY2FzZSBcImludGVnZXJcIjpcbiAgICAgIGNhc2UgXCJiaWdJbnRlZ2VyXCI6XG4gICAgICAgIHJldHVybiBcImludGVnZXIgbnVtYmVyc1wiO1xuICAgICAgY2FzZSBcImZsb2F0XCI6XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBjYXNlIFwibnVtZXJpY1wiOlxuICAgICAgICByZXR1cm4gXCJkZWNpbWFsIG51bWJlcnNcIjtcbiAgICAgIGNhc2UgXCJib29sZWFuXCI6XG4gICAgICAgIHJldHVybiBcImJvb2xlYW5zICh0cnVlIG9yIGZhbHNlKVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgcmV0dXJuIFwiSVNPIDg2MDEgZGF0ZSBzdHJpbmdzXCI7XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICByZXR1cm4gXCJ2YWxpZCBKU09OIG9iamVjdCBvciBhcnJheVwiO1xuICAgICAgY2FzZSBcInV1aWRcIjpcbiAgICAgICAgcmV0dXJuIFwiVVVJRCBzdHJpbmdzXCI7XG4gICAgICBjYXNlIFwiZW51bVwiOlxuICAgICAgICByZXR1cm4gXCJvbmUgb2YgdGhlIGFsbG93ZWQgZW51bSB2YWx1ZXNcIjtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBcInBsYWluIHRleHQgc3RyaW5nc1wiO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0RXhhbXBsZUZvclR5cGUocHJvcFR5cGU6IHN0cmluZywgbG9jYWxlOiBMb2NhbGUpOiBzdHJpbmcge1xuICAgIC8vIOuwsOyXtCDtg4DsnoUg7LKY66asXG4gICAgaWYgKHByb3BUeXBlLmVuZHNXaXRoKFwiW11cIikpIHtcbiAgICAgIGNvbnN0IGJhc2VUeXBlID0gcHJvcFR5cGUuc2xpY2UoMCwgLTIpO1xuICAgICAgY29uc3QgYmFzZUV4YW1wbGUgPSB0aGlzLmdldFNjYWxhckV4YW1wbGUoYmFzZVR5cGUsIGxvY2FsZSk7XG4gICAgICByZXR1cm4gYFske2Jhc2VFeGFtcGxlfV1gO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmdldFNjYWxhckV4YW1wbGUocHJvcFR5cGUsIGxvY2FsZSk7XG4gIH1cblxuICBwcml2YXRlIGdldFNjYWxhckV4YW1wbGUocHJvcFR5cGU6IHN0cmluZywgbG9jYWxlOiBMb2NhbGUpOiBzdHJpbmcge1xuICAgIGNvbnN0IGlzS29yZWFuID0gbG9jYWxlID09PSBcImtvXCI7XG5cbiAgICBzd2l0Y2ggKHByb3BUeXBlKSB7XG4gICAgICBjYXNlIFwiaW50ZWdlclwiOlxuICAgICAgY2FzZSBcImJpZ0ludGVnZXJcIjpcbiAgICAgICAgcmV0dXJuIFwiNDJcIjtcbiAgICAgIGNhc2UgXCJmbG9hdFwiOlxuICAgICAgY2FzZSBcIm51bWJlclwiOlxuICAgICAgY2FzZSBcIm51bWVyaWNcIjpcbiAgICAgICAgcmV0dXJuIFwiMy4xNFwiO1xuICAgICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICAgICAgcmV0dXJuIFwidHJ1ZVwiO1xuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgcmV0dXJuIFwiMjAyNC0wMS0wMVwiO1xuICAgICAgY2FzZSBcImpzb25cIjpcbiAgICAgICAgcmV0dXJuICd7XCJrZXlcIjogXCJ2YWx1ZVwifSc7XG4gICAgICBjYXNlIFwidXVpZFwiOlxuICAgICAgICByZXR1cm4gXCI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDBcIjtcbiAgICAgIGNhc2UgXCJlbnVtXCI6XG4gICAgICAgIHJldHVybiBcIkVOVU1fVkFMVUVcIjtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBpc0tvcmVhbiA/IFwi7JWI64WV7ZWY7IS47JqUXCIgOiBcIkhlbGxvXCI7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOydtOumhOydhCDsnbTrqZTsnbwg66Gc7LusIO2MjO2KuOyaqSDroZzrp4jrgpjsnbTspojrk5wg66y47J6Q7Je066GcIOuzgO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICog7ZWc6riAIOydtOumhOydgCDstIjshLEt7KSR7ISxLeyiheyEsSDrtoTtlbQg7ZuEIOuhnOuniOuCmOydtOymiCDsspjrpqztlanri4jri6QuXG4gICAqIOyYgeusuCDsnbTrpoTsnYAg7IaM66y47J6Q66GcIOuzgO2ZmO2VmOqzoCDqs7XrsLHsnYQg7KCQKC4pXFx1YzczY+uhnCDsuZjtmZjtlanri4jri6QuXG4gICAqIOyYiDogXCLquYDssqDsiJhcIiDihpIgXCJjaGVvbHN1LmtpbVwiLCBcIkpvaG4gRG9lXCIg4oaSIFwiam9obi5kb2VcIlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByb21hbml6ZU5hbWUobmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAvLyDtlZzquIAg7Y+s7ZWoIOyXrOu2gCDtmZXsnbhcbiAgICBpZiAoL1tcXHVBQzAwLVxcdUQ3QUZdLy50ZXN0KG5hbWUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5yb21hbml6ZUtvcmVhbk5hbWUobmFtZSk7XG4gICAgfVxuICAgIC8vIOyYgeusuDog7IaM66y47J6QICsg7KCQIOq1rOu2hFxuICAgIHJldHVybiBuYW1lXG4gICAgICAudG9Mb3dlckNhc2UoKVxuICAgICAgLnJlcGxhY2UoL1xccysvZywgXCIuXCIpXG4gICAgICAucmVwbGFjZSgvW15hLXowLTkuXS9nLCBcIlwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZzquIAg7J2066aE7J2EIOuhnOuniOuCmOydtOymiCDsspjrpqztlanri4jri6QuXG4gICAqXG4gICAqIOy0iOyEsS/spJHshLEv7KKF7ISxIOunpO2VkSDthYzsnbTruJTsnYQg7IKs7Jqp7ZWY7JesIO2VnOq4gOydhCDroZzrp4jsnpDroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKiDssqsg6riA7J6Q66W8IOyEseycvOuhnCDqsITso7ztlZjsl6wgXCLquYDssqDsiJhcIiDihpIgXCJjaGVvbHN1LmtpbVwiIO2Yle2DnOuhnCDstpzroKXtlanri4jri6QuXG4gICAqL1xuICBwcml2YXRlIHJvbWFuaXplS29yZWFuTmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IENIT1NFT05HID0gW1xuICAgICAgXCJnXCIsXG4gICAgICBcImtrXCIsXG4gICAgICBcIm5cIixcbiAgICAgIFwiZFwiLFxuICAgICAgXCJ0dFwiLFxuICAgICAgXCJyXCIsXG4gICAgICBcIm1cIixcbiAgICAgIFwiYlwiLFxuICAgICAgXCJwcFwiLFxuICAgICAgXCJzXCIsXG4gICAgICBcInNzXCIsXG4gICAgICBcIlwiLFxuICAgICAgXCJqXCIsXG4gICAgICBcImpqXCIsXG4gICAgICBcImNoXCIsXG4gICAgICBcImtcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJwXCIsXG4gICAgICBcImhcIixcbiAgICBdO1xuICAgIGNvbnN0IEpVTkdTRU9ORyA9IFtcbiAgICAgIFwiYVwiLFxuICAgICAgXCJhZVwiLFxuICAgICAgXCJ5YVwiLFxuICAgICAgXCJ5YWVcIixcbiAgICAgIFwiZW9cIixcbiAgICAgIFwiZVwiLFxuICAgICAgXCJ5ZW9cIixcbiAgICAgIFwieWVcIixcbiAgICAgIFwib1wiLFxuICAgICAgXCJ3YVwiLFxuICAgICAgXCJ3YWVcIixcbiAgICAgIFwib2VcIixcbiAgICAgIFwieW9cIixcbiAgICAgIFwidVwiLFxuICAgICAgXCJ3b1wiLFxuICAgICAgXCJ3ZVwiLFxuICAgICAgXCJ3aVwiLFxuICAgICAgXCJ5dVwiLFxuICAgICAgXCJldVwiLFxuICAgICAgXCJ1aVwiLFxuICAgICAgXCJpXCIsXG4gICAgXTtcbiAgICBjb25zdCBKT05HU0VPTkcgPSBbXG4gICAgICBcIlwiLFxuICAgICAgXCJrXCIsXG4gICAgICBcImtcIixcbiAgICAgIFwia1wiLFxuICAgICAgXCJuXCIsXG4gICAgICBcIm5cIixcbiAgICAgIFwiblwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJsXCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJsXCIsXG4gICAgICBcImxcIixcbiAgICAgIFwibFwiLFxuICAgICAgXCJtXCIsXG4gICAgICBcInBcIixcbiAgICAgIFwicFwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcInRcIixcbiAgICAgIFwibmdcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJ0XCIsXG4gICAgICBcImtcIixcbiAgICAgIFwidFwiLFxuICAgICAgXCJwXCIsXG4gICAgICBcInRcIixcbiAgICBdO1xuXG4gICAgY29uc3Qgcm9tYW5pemUgPSAoY2hhcjogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICAgIGNvbnN0IGNvZGUgPSBjaGFyLmNoYXJDb2RlQXQoMCk7XG4gICAgICBpZiAoY29kZSA8IDB4YWMwMCB8fCBjb2RlID4gMHhkN2FmKSByZXR1cm4gY2hhcjtcbiAgICAgIGNvbnN0IG9mZnNldCA9IGNvZGUgLSAweGFjMDA7XG4gICAgICBjb25zdCBjaG8gPSBNYXRoLmZsb29yKG9mZnNldCAvIDU4OCk7XG4gICAgICBjb25zdCBqdW5nID0gTWF0aC5mbG9vcigob2Zmc2V0ICUgNTg4KSAvIDI4KTtcbiAgICAgIGNvbnN0IGpvbmcgPSBvZmZzZXQgJSAyODtcbiAgICAgIHJldHVybiBDSE9TRU9OR1tjaG9dICsgSlVOR1NFT05HW2p1bmddICsgSk9OR1NFT05HW2pvbmddO1xuICAgIH07XG5cbiAgICBjb25zdCBjaGFycyA9IFsuLi5uYW1lXTtcbiAgICAvLyDssqsg6riA7J6Q66W8IOyEsSjlp5Mp7Jy866GcIOqwhOyjvFxuICAgIGNvbnN0IGZhbWlseU5hbWUgPSByb21hbml6ZShjaGFyc1swXSk7XG4gICAgY29uc3QgZ2l2ZW5OYW1lID0gY2hhcnMuc2xpY2UoMSkubWFwKHJvbWFuaXplKS5qb2luKFwiXCIpO1xuXG4gICAgaWYgKGdpdmVuTmFtZSkge1xuICAgICAgcmV0dXJuIGAke2dpdmVuTmFtZX0uJHtmYW1pbHlOYW1lfWA7XG4gICAgfVxuICAgIHJldHVybiBmYW1pbHlOYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIExMTSDsupDsi5wg7Ya16rOE66W8IOuwmO2ZmO2VqeuLiOuLpC5cbiAgICovXG4gIGdldExMTUNhY2hlU3RhdHMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMubGxtQ2FjaGUuc2l6ZSxcbiAgICAgIGVuYWJsZWQ6IHRoaXMub3B0aW9ucy5lbmFibGVMTE1DYWNoZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIExMTSDsupDsi5zrpbwg7LSI6riw7ZmU7ZWp64uI64ukLlxuICAgKi9cbiAgY2xlYXJMTE1DYWNoZSgpIHtcbiAgICB0aGlzLmxsbUNhY2hlLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICog7Luo7YWN7Iqk7Yq4IOyDneyEsVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVDb250ZXh0KCk6IEdlbmVyYXRvckNvbnRleHQge1xuICAgIHJldHVybiB7XG4gICAgICBmaXh0dXJlczogbmV3IE1hcCgpLFxuICAgICAgcmVmZXJlbmNlQ2FjaGU6IG5ldyBNYXAoKSxcbiAgICAgIGltcG9ydGVkUmVjb3JkczogbmV3IFNldCgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog67Cw7LmYIOyDneyEsSDrsI8g7J6Q64+ZIOyggOyepVxuICAgKlxuICAgKiAxLiDqsIEgc3BlY+uzhOuhnCBmaXh0dXJlIOyDneyEsSAo66mU66qo66asKVxuICAgKiAyLiBGaXh0dXJlUmVjb3Jk66GcIOuzgO2ZmFxuICAgKiAzLiBGaXh0dXJlTWFuYWdlci5pbnNlcnRGaXh0dXJlcygp66GcIHRhcmdldERi7JeQIOyggOyepVxuICAgKlxuICAgKiBAcmV0dXJucyDsoIDsnqXrkJwgZml4dHVyZSDrjbDsnbTthLAgKOyLpOygnCBEQiBJRCDtj6ztlagpXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUJhdGNoKFxuICAgIHNwZWNzOiBBcnJheTx7IGVudGl0eTogc3RyaW5nOyBjb3VudDogbnVtYmVyOyBvdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PixcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KCk7XG4gICAgY29uc3QgZ2VuZXJhdGVkRml4dHVyZXM6IEFycmF5PHtcbiAgICAgIGVudGl0eTogc3RyaW5nO1xuICAgICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICBleHBsaWNpdElkPzogYm9vbGVhbjtcbiAgICB9PiA9IFtdO1xuXG4gICAgLy8gMS4g6rCBIHNwZWPrs4TroZwgZml4dHVyZSDsg53shLFcbiAgICBmb3IgKGNvbnN0IHNwZWMgb2Ygc3BlY3MpIHtcbiAgICAgIGNvbnN0IHNwZWNFbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KHNwZWMuZW50aXR5KTtcblxuICAgICAgaWYgKHNwZWNFbnRpdHkucGFyZW50SWQpIHtcbiAgICAgICAgLy8gcGFyZW50SWQg7JeU7Yuw7YuwOiBEQuyXkOyEnCDshJzruIztg4DsnoUg7ZaJ7J20IOyXhuuKlCDrtoDrqqggaWTrpbwg7KGw7ZqM7ZWY7JesIOyCrOyaqVxuICAgICAgICAvLyAo7IOIIOu2gOuqqCDsg53shLEg64yA7IugIOq4sOyhtCDrjbDsnbTthLAg7J6s7Zmc7JqpKVxuICAgICAgICBjb25zdCBpZFByb3AgPSBzcGVjRW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gXCJpZFwiKTtcbiAgICAgICAgY29uc3QgcGFyZW50T3ZlcnJpZGVzID0gaWRQcm9wPy5jb25lPy5maXh0dXJlUGFyZW50T3ZlcnJpZGVzID8/IHt9O1xuICAgICAgICBjb25zdCBwYXJlbnRFbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KHNwZWNFbnRpdHkucGFyZW50SWQpO1xuXG4gICAgICAgIC8vIOu2gOuqqCDthYzsnbTruJTsl5DshJwg7ISc67iM7YOA7J6FIO2FjOydtOu4lOyXkCDsl4bripQgaWTrpbwg7KGw7ZqMXG4gICAgICAgIGxldCBxdWVyeSA9IHRoaXMuc291cmNlRGIocGFyZW50RW50aXR5LnRhYmxlKS5zZWxlY3QoYCR7cGFyZW50RW50aXR5LnRhYmxlfS5pZGApO1xuICAgICAgICBmb3IgKGNvbnN0IFtjb2wsIHZhbF0gb2YgT2JqZWN0LmVudHJpZXMocGFyZW50T3ZlcnJpZGVzKSkge1xuICAgICAgICAgIHF1ZXJ5ID0gcXVlcnkud2hlcmUoXG4gICAgICAgICAgICBgJHtwYXJlbnRFbnRpdHkudGFibGV9LiR7Y29sfWAsXG4gICAgICAgICAgICB2YWwgYXMgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBxdWVyeSA9IHF1ZXJ5XG4gICAgICAgICAgLmxlZnRKb2luKHNwZWNFbnRpdHkudGFibGUsIGAke3NwZWNFbnRpdHkudGFibGV9LmlkYCwgYCR7cGFyZW50RW50aXR5LnRhYmxlfS5pZGApXG4gICAgICAgICAgLndoZXJlTnVsbChgJHtzcGVjRW50aXR5LnRhYmxlfS5pZGApXG4gICAgICAgICAgLmxpbWl0KHNwZWMuY291bnQpO1xuXG4gICAgICAgIGNvbnN0IHJvd3MgPSBhd2FpdCBxdWVyeTtcbiAgICAgICAgY29uc3QgYXZhaWxhYmxlSWRzOiBudW1iZXJbXSA9IHJvd3MubWFwKChyOiB7IGlkOiBudW1iZXIgfSkgPT4gci5pZCk7XG5cbiAgICAgICAgaWYgKGF2YWlsYWJsZUlkcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgICAgIGBbcGFyZW50SWRdICR7c3BlYy5lbnRpdHl9OiDshJzruIztg4DsnoXsnbQg7JeG64qUIOu2gOuqqCDroIjsvZTrk5zqsIAg67aA7KGx7ZWp64uI64ukLiDqsbTrhIjrnIHri4jri6QuYCxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yIChjb25zdCBwYXJlbnRJZCBvZiBhdmFpbGFibGVJZHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpeHR1cmUgPSBhd2FpdCB0aGlzLmdlbmVyYXRlKHNwZWMuZW50aXR5LCBzcGVjLm92ZXJyaWRlcyB8fCB7fSwgY29udGV4dCk7XG4gICAgICAgICAgICBmaXh0dXJlLmlkID0gcGFyZW50SWQ7XG4gICAgICAgICAgICBnZW5lcmF0ZWRGaXh0dXJlcy5wdXNoKHsgZW50aXR5OiBzcGVjLmVudGl0eSwgZGF0YTogZml4dHVyZSwgZXhwbGljaXRJZDogdHJ1ZSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3BlYy5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgZml4dHVyZSA9IGF3YWl0IHRoaXMuZ2VuZXJhdGUoc3BlYy5lbnRpdHksIHNwZWMub3ZlcnJpZGVzIHx8IHt9LCBjb250ZXh0KTtcbiAgICAgICAgICBnZW5lcmF0ZWRGaXh0dXJlcy5wdXNoKHtcbiAgICAgICAgICAgIGVudGl0eTogc3BlYy5lbnRpdHksXG4gICAgICAgICAgICBkYXRhOiBmaXh0dXJlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMi4gRml4dHVyZVJlY29yZOuhnCDrs4DtmZhcbiAgICBjb25zdCBmaXh0dXJlUmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gW107XG4gICAgZm9yIChjb25zdCB7IGVudGl0eTogZW50aXR5TmFtZSwgZGF0YSwgZXhwbGljaXRJZCB9IG9mIGdlbmVyYXRlZEZpeHR1cmVzKSB7XG4gICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eU5hbWUpO1xuXG4gICAgICAvLyBpbnRlZ2VyL2JpZ0ludGVnZXIgUEvripQg7J6E7IucIElEIOyDneyEsSAoREIg7Iuc7YCA7Iqk6rCAIOyLpOygnCBJRCDtlaDri7kpXG4gICAgICAvLyBzdHJpbmcgUEvripQgZ2VuZXJhdGUoKeyXkOyEnCDsnbTrr7gg7IOd7ISx65CcIGlkIOqwkuydhCDqt7jrjIDroZwg7IKs7JqpXG4gICAgICAvLyBwYXJlbnRJZCDsl5Tti7Dti7DripQg67aA66qo7J2YIOyLpOygnCBpZOulvCDqt7jrjIDroZwg7IKs7JqpICjsi5ztgIDsiqQg66+47IKs7JqpKVxuICAgICAgY29uc3QgaWRQcm9wID0gZW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gXCJpZFwiKTtcbiAgICAgIGNvbnN0IHVzZXNTZXF1ZW5jZSA9XG4gICAgICAgICFleHBsaWNpdElkICYmXG4gICAgICAgIChpZFByb3A/LnR5cGUgPT09IFwiaW50ZWdlclwiIHx8XG4gICAgICAgICAgaWRQcm9wPy50eXBlID09PSBcImJpZ0ludGVnZXJcIiB8fFxuICAgICAgICAgIGlkUHJvcD8uY29uZT8uZml4dHVyZVN0cmF0ZWd5ID09PSBcInNlcXVlbmNlXCIpO1xuXG4gICAgICBjb25zdCBkYXRhRm9yUmVjb3JkID0gdXNlc1NlcXVlbmNlXG4gICAgICAgID8geyAuLi5kYXRhLCBpZDogTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMTAwMDAwMCkgfVxuICAgICAgICA6IGRhdGE7XG5cbiAgICAgIGNvbnN0IHJlY29yZHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5jcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgICAgICBlbnRpdHksXG4gICAgICAgIGRhdGFGb3JSZWNvcmQgYXMgeyBpZDogbnVtYmVyIHwgc3RyaW5nOyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB9LFxuICAgICAgICB7IHNpbmdsZVJlY29yZDogdHJ1ZSB9LFxuICAgICAgKTtcbiAgICAgIGZpeHR1cmVSZWNvcmRzLnB1c2goLi4ucmVjb3Jkcyk7XG4gICAgfVxuXG4gICAgLy8gMy4gdGFyZ2V0RGLsl5Ag7IK97J6FIChGaXh0dXJlTWFuYWdlcuqwgCDsnZjsobTshLEg7KCV66CsIOyymOumrClcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuaW5zZXJ0Rml4dHVyZXModGhpcy50YXJnZXREYk5hbWUsIGZpeHR1cmVSZWNvcmRzKTtcblxuICAgIC8vIDQuIGNvbXBhbmlvbiBmaXh0dXJlcyDsg53shLEgKGZpeHR1cmVDb21wYW5pb25z6rCAIOyEoOyWuOuQnCDqsr3smrApXG4gICAgY29uc3QgY29tcGFuaW9uUmVzdWx0cyA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVDb21wYW5pb25zKHNwZWNzLCByZXN1bHRzKTtcblxuICAgIGNvbnN0IHRvdGFsID0gcmVzdWx0cy5sZW5ndGggKyBjb21wYW5pb25SZXN1bHRzLmxlbmd0aDtcbiAgICAhaXNUZXN0KCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGBHZW5lcmF0ZWQgYW5kIHNhdmVkICR7dG90YWx9IGZpeHR1cmVzIHRvICR7dGhpcy50YXJnZXREYk5hbWV9YCkpO1xuICAgIHJldHVybiBbLi4ucmVzdWx0cywgLi4uY29tcGFuaW9uUmVzdWx0c107XG4gIH1cblxuICAvKipcbiAgICog67aA66qoIGZpeHR1cmUg6rKw6rO866W8IOq4sOuwmOycvOuhnCBmaXh0dXJlQ29tcGFuaW9uc+yXkCDshKDslrjrkJwgY29tcGFuaW9uIEVudGl0eeulvCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIGdlbmVyYXRlQmF0Y2goKeyXkOyEnOunjCDtmLjstpzrkJjrqbAsIGNvbXBhbmlvbiDsg53shLEg7IucIOyerOq3gOulvCDrsKnsp4DtlZjquLAg7JyE7ZW0XG4gICAqIGdlbmVyYXRlQmF0Y2goKeulvCDri6Tsi5wg7Zi47Lac7ZWY7KeAIOyViuqzoCDsp4HsoJEg7IK97J6F7ZWp64uI64ukLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZW5lcmF0ZUNvbXBhbmlvbnMoXG4gICAgc3BlY3M6IEFycmF5PHsgZW50aXR5OiBzdHJpbmc7IGNvdW50OiBudW1iZXI7IG92ZXJyaWRlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH0+LFxuICAgIHBhcmVudFJlc3VsdHM6IEZpeHR1cmVJbXBvcnRSZXN1bHRbXSxcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICBjb25zdCBhbGxSZXN1bHRzOiBGaXh0dXJlSW1wb3J0UmVzdWx0W10gPSBbXTtcbiAgICBjb25zdCBwcm9jZXNzZWRFbnRpdGllcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgZm9yIChjb25zdCBzcGVjIG9mIHNwZWNzKSB7XG4gICAgICBpZiAocHJvY2Vzc2VkRW50aXRpZXMuaGFzKHNwZWMuZW50aXR5KSkgY29udGludWU7XG4gICAgICBwcm9jZXNzZWRFbnRpdGllcy5hZGQoc3BlYy5lbnRpdHkpO1xuXG4gICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KHNwZWMuZW50aXR5KTtcbiAgICAgIGNvbnN0IGlkUHJvcCA9IGVudGl0eS5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IFwiaWRcIik7XG4gICAgICBjb25zdCBjb21wYW5pb25zID0gaWRQcm9wPy5jb25lPy5maXh0dXJlQ29tcGFuaW9ucztcbiAgICAgIGlmICghY29tcGFuaW9ucyB8fCBjb21wYW5pb25zLmxlbmd0aCA9PT0gMCkgY29udGludWU7XG5cbiAgICAgIGNvbnN0IGVudGl0eVJlc3VsdHMgPSBwYXJlbnRSZXN1bHRzLmZpbHRlcigocikgPT4gci5lbnRpdHlJZCA9PT0gc3BlYy5lbnRpdHkpO1xuICAgICAgaWYgKGVudGl0eVJlc3VsdHMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcblxuICAgICAgZm9yIChjb25zdCBjb21wYW5pb24gb2YgY29tcGFuaW9ucykge1xuICAgICAgICAvLyBjb21wYW5pb24gZW50aXR57JeQ7IScIOu2gOuqqCBlbnRpdHnroZzsnZggQmVsb25nc1RvT25lIEZLIOy7rOufvOuqhSDtjIzslYVcbiAgICAgICAgY29uc3QgY29tcGFuaW9uRW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChjb21wYW5pb24uZW50aXR5KTtcbiAgICAgICAgY29uc3QgZmtQcm9wID0gY29tcGFuaW9uRW50aXR5LnByb3BzLmZpbmQoXG4gICAgICAgICAgKHApID0+IGlzUmVsYXRpb25Qcm9wKHApICYmIGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHApICYmIHAud2l0aCA9PT0gc3BlYy5lbnRpdHksXG4gICAgICAgICk7XG4gICAgICAgIGlmICghZmtQcm9wKSB7XG4gICAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgW0NvbXBhbmlvbl0gTm8gQmVsb25nc1RvT25lIHJlbGF0aW9uIGZyb20gJHtjb21wYW5pb24uZW50aXR5fSB0byAke3NwZWMuZW50aXR5fS4gU2tpcHBpbmcuYCxcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZmtDb2xOYW1lID0gYCR7ZmtQcm9wLm5hbWV9X2lkYDtcblxuICAgICAgICAvLyBjb21wYW5pb27snZggaWRQcm9wLCB1c2VzU2VxdWVuY2UsIGNvdW5064qUIGNvbXBhbmlvbiDri6jsnITroZwg6rOg7KCVXG4gICAgICAgIGNvbnN0IGNvbXBhbmlvbklkUHJvcCA9IGNvbXBhbmlvbkVudGl0eS5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IFwiaWRcIik7XG4gICAgICAgIGNvbnN0IHVzZXNTZXF1ZW5jZSA9XG4gICAgICAgICAgY29tcGFuaW9uSWRQcm9wPy50eXBlID09PSBcImludGVnZXJcIiB8fFxuICAgICAgICAgIGNvbXBhbmlvbklkUHJvcD8udHlwZSA9PT0gXCJiaWdJbnRlZ2VyXCIgfHxcbiAgICAgICAgICBjb21wYW5pb25JZFByb3A/LmNvbmU/LmZpeHR1cmVTdHJhdGVneSA9PT0gXCJzZXF1ZW5jZVwiO1xuICAgICAgICBjb25zdCBjb21wYW5pb25Db3VudCA9IGNvbXBhbmlvbi5jb3VudCA/PyAxO1xuXG4gICAgICAgIC8vIOqwgSBwYXJlbnQgcmVzdWx07JeQIOuMgO2VtCBjb21wYW5pb24gZml4dHVyZSDsg53shLFcbiAgICAgICAgY29uc3QgY29udGV4dCA9IHRoaXMuY3JlYXRlQ29udGV4dCgpO1xuICAgICAgICBjb25zdCBjb21wYW5pb25GaXh0dXJlUmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gW107XG5cbiAgICAgICAgZm9yIChjb25zdCBwYXJlbnRSZXN1bHQgb2YgZW50aXR5UmVzdWx0cykge1xuICAgICAgICAgIGNvbnN0IHJlc29sdmVkT3ZlcnJpZGVzID0gdGhpcy5yZXNvbHZlVGVtcGxhdGVPdmVycmlkZXMoXG4gICAgICAgICAgICBjb21wYW5pb24ub3ZlcnJpZGVzID8/IHt9LFxuICAgICAgICAgICAgcGFyZW50UmVzdWx0LmRhdGEsXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXNvbHZlZE92ZXJyaWRlc1tma0NvbE5hbWVdID0gcGFyZW50UmVzdWx0LmRhdGEuaWQ7XG5cbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbXBhbmlvbkNvdW50OyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGZpeHR1cmUgPSBhd2FpdCB0aGlzLmdlbmVyYXRlKGNvbXBhbmlvbi5lbnRpdHksIHJlc29sdmVkT3ZlcnJpZGVzLCBjb250ZXh0KTtcblxuICAgICAgICAgICAgY29uc3QgZGF0YUZvclJlY29yZCA9IHVzZXNTZXF1ZW5jZVxuICAgICAgICAgICAgICA/IHsgLi4uZml4dHVyZSwgaWQ6IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMDAwMDApIH1cbiAgICAgICAgICAgICAgOiBmaXh0dXJlO1xuXG4gICAgICAgICAgICBjb25zdCByZWNvcmRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuY3JlYXRlRml4dHVyZVJlY29yZChcbiAgICAgICAgICAgICAgY29tcGFuaW9uRW50aXR5LFxuICAgICAgICAgICAgICBkYXRhRm9yUmVjb3JkIGFzIHtcbiAgICAgICAgICAgICAgICBpZDogbnVtYmVyIHwgc3RyaW5nO1xuICAgICAgICAgICAgICAgIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsO1xuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7IHNpbmdsZVJlY29yZDogdHJ1ZSB9LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbXBhbmlvbkZpeHR1cmVSZWNvcmRzLnB1c2goLi4ucmVjb3Jkcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY29tcGFuaW9uUmVzdWx0cyA9IGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVzKFxuICAgICAgICAgIHRoaXMudGFyZ2V0RGJOYW1lLFxuICAgICAgICAgIGNvbXBhbmlvbkZpeHR1cmVSZWNvcmRzLFxuICAgICAgICApO1xuICAgICAgICBhbGxSZXN1bHRzLnB1c2goLi4uY29tcGFuaW9uUmVzdWx0cyk7XG5cbiAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBjaGFsay5ncmVlbihcbiAgICAgICAgICAgICAgYFtDb21wYW5pb25dIEdlbmVyYXRlZCAke2NvbXBhbmlvblJlc3VsdHMubGVuZ3RofSAke2NvbXBhbmlvbi5lbnRpdHl9IGZpeHR1cmVzYCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gYWxsUmVzdWx0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBvdmVycmlkZXMg6rCS7J2YIFwie3tmaWVsZE5hbWV9fVwiIO2FnO2UjOumv+ydhCDrtoDrqqggZml4dHVyZSDrjbDsnbTthLDroZwg7LmY7ZmY7ZWp64uI64ukLlxuICAgKlxuICAgKiDsmIg6IHsgXCJhY2NvdW50X2lkXCI6IFwie3tlbWFpbH19XCIgfSDihpIgeyBcImFjY291bnRfaWRcIjogXCJ1c2VyQGV4YW1wbGUuY29tXCIgfVxuICAgKi9cbiAgcHJpdmF0ZSByZXNvbHZlVGVtcGxhdGVPdmVycmlkZXMoXG4gICAgb3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBwYXJlbnREYXRhOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBEYXRlIHwgbnVsbCB9LFxuICApOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gICAgY29uc3QgcmVzb2x2ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob3ZlcnJpZGVzKSkge1xuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZS5zdGFydHNXaXRoKFwie3tcIikgJiYgdmFsdWUuZW5kc1dpdGgoXCJ9fVwiKSkge1xuICAgICAgICBjb25zdCBmaWVsZE5hbWUgPSB2YWx1ZS5zbGljZSgyLCAtMikudHJpbSgpO1xuICAgICAgICBpZiAoIShmaWVsZE5hbWUgaW4gcGFyZW50RGF0YSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBg7YWc7ZSM66a/IO2VhOuTnCBcIiR7ZmllbGROYW1lfVwi7J20KOqwgCkg67aA66qoIGZpeHR1cmUg642w7J207YSw7JeQIOyhtOyerO2VmOyngCDslYrsirXri4jri6QgKG92ZXJyaWRlIGtleTogXCIke2tleX1cIilgLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzb2x2ZWRba2V5XSA9IHBhcmVudERhdGFbZmllbGROYW1lXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc29sdmVkW2tleV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc29sdmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIOyLpOygnCBEQihzb3VyY2VEYinsl5DshJwg642w7J207YSw66W8IOyhsO2ajO2VmOyXrCBmaXh0dXJlIERCKHRhcmdldERiKeyXkCBpbXBvcnTtlanri4jri6QuXG4gICAqXG4gICAqIDEuIERhdGFFeHBsb3JlcuuhnCBzb3VyY2VEYuyXkOyEnCDrjbDsnbTthLAg7KGw7ZqMICjqtIDroKgg642w7J207YSwIO2PrO2VqClcbiAgICogMi4gRml4dHVyZVJlY29yZOuhnCDrs4DtmZhcbiAgICogMy4gdGFyZ2V0RGLsl5Ag7IK97J6FXG4gICAqXG4gICAqIEBwYXJhbSBlbnRpdHlOYW1lIC0g7KGw7ZqM7ZWgIGVudGl0eSDsnbTrpoRcbiAgICogQHBhcmFtIG9wdGlvbnMgLSDsobDtmowg7Ji17IWYIChzdHJhdGVneSwgbGltaXQsIGluY2x1ZGVSZWxhdGlvbnMg65OxKVxuICAgKiBAcmV0dXJucyDsoIDsnqXrkJwgZml4dHVyZSDrjbDsnbTthLAgKOyLpOygnCBEQiBJRCDtj6ztlagpXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC8vIO2UhOuhnOuNleyFmCBEQuyXkOyEnCBVc2VyIDEw66qFICsg6rSA66CoIEVtcGxveWVlLCBEZXBhcnRtZW50IOqwgOyguOyYpOq4sFxuICAgKiBhd2FpdCBnZW5lcmF0b3IuaW1wb3J0RnJvbVNvdXJjZShcIlVzZXJcIiwge1xuICAgKiAgIHN0cmF0ZWd5OiBcInNhbXBsZVwiLFxuICAgKiAgIGxpbWl0OiAxMCxcbiAgICogICBpbmNsdWRlUmVsYXRpb25zOiB0cnVlLFxuICAgKiAgIG1heERlcHRoOiAyXG4gICAqIH0pO1xuICAgKi9cbiAgYXN5bmMgaW1wb3J0RnJvbVNvdXJjZShcbiAgICBlbnRpdHlOYW1lOiBzdHJpbmcsXG4gICAgb3B0aW9uczogRXhwbG9yZVdpdGhSZWxhdGlvbnNPcHRpb25zLFxuICApOiBQcm9taXNlPEZpeHR1cmVJbXBvcnRSZXN1bHRbXT4ge1xuICAgICFpc1Rlc3QoKSAmJlxuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLmJsdWUoXG4gICAgICAgICAgYEltcG9ydGluZyAke2VudGl0eU5hbWV9IGZyb20gc291cmNlIERCIHdpdGggb3B0aW9uczogJHtKU09OLnN0cmluZ2lmeSh7IHN0cmF0ZWd5OiBvcHRpb25zLnN0cmF0ZWd5LCBsaW1pdDogb3B0aW9ucy5saW1pdCwgaW5jbHVkZVJlbGF0aW9uczogb3B0aW9ucy5pbmNsdWRlUmVsYXRpb25zLCBtYXhEZXB0aDogb3B0aW9ucy5tYXhEZXB0aCB9KX1gLFxuICAgICAgICApLFxuICAgICAgKTtcblxuICAgIC8vIDEuIERhdGFFeHBsb3JlcuuhnCBzb3VyY2VEYuyXkOyEnCDrjbDsnbTthLAg7KGw7ZqMICjqtIDroKgg642w7J207YSwIO2PrO2VqClcbiAgICBjb25zdCBleHBsb3JlUmVzdWx0ID0gYXdhaXQgdGhpcy5kYXRhRXhwbG9yZXIuZXhwbG9yZVdpdGhSZWxhdGlvbnMoZW50aXR5TmFtZSwgb3B0aW9ucyk7XG5cbiAgICAhaXNUZXN0KCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay5jeWFuKFxuICAgICAgICAgIGBGb3VuZCAke2V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aH0gJHtlbnRpdHlOYW1lfSByZWNvcmRzIGFuZCAke2V4cGxvcmVSZXN1bHQucmVsYXRlZC5zaXplfSByZWxhdGVkIGVudGl0aWVzYCxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICAvLyAyLiBGaXh0dXJlUmVjb3Jk66GcIOuzgO2ZmFxuICAgIGNvbnN0IGZpeHR1cmVSZWNvcmRzOiBGaXh0dXJlUmVjb3JkW10gPSBbXTtcblxuICAgIC8vIOuplOyduCBlbnRpdHnsnZggcmVjb3Jkc+ulvCBGaXh0dXJlUmVjb3Jk66GcIOuzgO2ZmFxuICAgIGNvbnN0IG1haW5FbnRpdHkgPSB0aGlzLmVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eU5hbWUpO1xuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIGV4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzKSB7XG4gICAgICBjb25zdCByZWNvcmRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuY3JlYXRlRml4dHVyZVJlY29yZChcbiAgICAgICAgbWFpbkVudGl0eSxcbiAgICAgICAgcmVjb3JkIGFzIHsgaWQ6IG51bWJlciB8IHN0cmluZzsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfSxcbiAgICAgICAgeyBfZGI6IHRoaXMuc291cmNlRGIsIHNpbmdsZVJlY29yZDogdHJ1ZSB9LFxuICAgICAgKTtcbiAgICAgIGZpeHR1cmVSZWNvcmRzLnB1c2goLi4ucmVjb3Jkcyk7XG4gICAgfVxuXG4gICAgLy8g6rSA66CoIGVudGl0eeydmCByZWNvcmRz66W8IEZpeHR1cmVSZWNvcmTroZwg67OA7ZmYXG4gICAgZm9yIChjb25zdCBbcmVsYXRlZEVudGl0eU5hbWUsIHJlbGF0ZWRSZWNvcmRzXSBvZiBleHBsb3JlUmVzdWx0LnJlbGF0ZWQuZW50cmllcygpKSB7XG4gICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gdGhpcy5lbnRpdHlNYW5hZ2VyLmdldChyZWxhdGVkRW50aXR5TmFtZSk7XG4gICAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiByZWxhdGVkUmVjb3Jkcykge1xuICAgICAgICBjb25zdCByZWNvcmRzID0gYXdhaXQgRml4dHVyZU1hbmFnZXIuY3JlYXRlRml4dHVyZVJlY29yZChcbiAgICAgICAgICByZWxhdGVkRW50aXR5LFxuICAgICAgICAgIHJlY29yZCBhcyB7IGlkOiBudW1iZXIgfCBzdHJpbmc7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsIH0sXG4gICAgICAgICAgeyBfZGI6IHRoaXMuc291cmNlRGIsIHNpbmdsZVJlY29yZDogdHJ1ZSB9LFxuICAgICAgICApO1xuICAgICAgICBmaXh0dXJlUmVjb3Jkcy5wdXNoKC4uLnJlY29yZHMpO1xuICAgICAgfVxuXG4gICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JheShgICAtICR7cmVsYXRlZEVudGl0eU5hbWV9OiAke3JlbGF0ZWRSZWNvcmRzLmxlbmd0aH0gcmVjb3Jkc2ApKTtcbiAgICB9XG5cbiAgICAvLyAzLiB0YXJnZXREYuyXkCDsgr3snoUgKEZpeHR1cmVNYW5hZ2Vy6rCAIOydmOyhtOyEsSDsoJXroKwg7LKY66asKVxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBGaXh0dXJlTWFuYWdlci5pbnNlcnRGaXh0dXJlcyh0aGlzLnRhcmdldERiTmFtZSwgZml4dHVyZVJlY29yZHMpO1xuXG4gICAgIWlzVGVzdCgpICYmXG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgY2hhbGsuZ3JlZW4oXG4gICAgICAgICAgYFN1Y2Nlc3NmdWxseSBpbXBvcnRlZCAke3Jlc3VsdHMubGVuZ3RofSByZWNvcmRzIHRvICR7dGhpcy50YXJnZXREYk5hbWV9ICgke2V4cGxvcmVSZXN1bHQubWFpbi5yZWNvcmRzLmxlbmd0aH0gJHtlbnRpdHlOYW1lfSArICR7cmVzdWx0cy5sZW5ndGggLSBleHBsb3JlUmVzdWx0Lm1haW4ucmVjb3Jkcy5sZW5ndGh9IHJlbGF0ZWQpYCxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7YUFNb0c7a0JBQ3ZEO3FCQUNFO3NCQUVFO3VCQUVFO0NBc0J0QyxtQkFBYixNQUE4QjtFQUM1QixBQUFRO0VBQ1IsQUFBUTtFQUNSLEFBQVE7RUFDUixBQUFRLFdBQWlDLElBQUksS0FBSztFQUNsRCxBQUFRLGNBQW1DLElBQUksS0FBSztFQUNwRCxBQUFRO0VBRVIsWUFDRSxBQUFRQSxVQUdSLFdBQ0EsQUFBUUMsY0FDUixBQUFRQyxlQUNSLFNBQ0E7R0FQUTtHQUlBO0dBQ0E7QUFHUixRQUFLLGVBQWUsSUFBSSxhQUFhLFVBQVUsY0FBYztBQUM3RCxRQUFLLFNBQVMsU0FBUyxVQUFVO0FBQ2pDLFFBQUssV0FB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
|