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
package/dist/bin/cli.js
CHANGED
|
@@ -1,1211 +1,1074 @@
|
|
|
1
|
+
import { exists, init_fs_utils } from "../utils/fs-utils.js";
|
|
2
|
+
import { findApiRootPath, findAppRootPath, init_utils } from "../utils/utils.js";
|
|
3
|
+
import { Sonamu, init_sonamu } from "../api/sonamu.js";
|
|
4
|
+
import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
|
|
5
|
+
import { SUPPORTED_PLUGIN_IDS, isValidPluginId } from "../auth/plugins/entity-definitions/index.js";
|
|
6
|
+
import { addCompanionsToEntities, generateBetterAuthEntities } from "../auth/auth-generator.js";
|
|
7
|
+
import { API_ARTIFACTS, WEB_ARTIFACTS } from "./build-config.js";
|
|
8
|
+
import { Migrator, init_migrator } from "../migration/migrator.js";
|
|
9
|
+
import { FixtureManager, init_fixture_manager } from "../testing/fixture-manager.js";
|
|
10
|
+
import { execWithLinePrefix, init_console_util, printBuildSummary, printTaskFailed, printTaskHeader, printTaskStart, printTaskSuccess } from "../utils/console-util.js";
|
|
11
|
+
import { fixtureExploreCommand, fixtureFetchCommand, fixtureGenCommand } from "./fixture.js";
|
|
12
|
+
import { testCommand } from "./test-command.js";
|
|
13
|
+
import assert from "assert";
|
|
14
|
+
import knex from "knex";
|
|
15
|
+
import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "fs/promises";
|
|
16
|
+
import path from "path";
|
|
1
17
|
import chalk from "chalk";
|
|
18
|
+
import os from "os";
|
|
2
19
|
import dotenv from "dotenv";
|
|
3
|
-
dotenv.config();
|
|
4
|
-
import assert from "assert";
|
|
5
20
|
import { execSync, spawn } from "child_process";
|
|
6
|
-
import { cp, mkdir, readdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
7
|
-
import knex from "knex";
|
|
8
21
|
import { createRequire } from "module";
|
|
9
|
-
import os from "os";
|
|
10
|
-
import path from "path";
|
|
11
22
|
import process from "process";
|
|
12
23
|
import { tsicli } from "tsicli";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import { fixtureExploreCommand, fixtureFetchCommand, fixtureGenCommand } from "./fixture.js";
|
|
24
|
-
import { testCommand } from "./test-command.js";
|
|
24
|
+
|
|
25
|
+
//#region src/bin/cli.ts
|
|
26
|
+
init_sonamu();
|
|
27
|
+
init_entity_manager();
|
|
28
|
+
init_migrator();
|
|
29
|
+
init_fixture_manager();
|
|
30
|
+
init_console_util();
|
|
31
|
+
init_fs_utils();
|
|
32
|
+
init_utils();
|
|
33
|
+
dotenv.config();
|
|
25
34
|
let migrator;
|
|
26
35
|
/**
|
|
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
|
-
options
|
|
53
|
-
};
|
|
36
|
+
* CLI 옵션을 파싱하는 헬퍼 함수
|
|
37
|
+
*/
|
|
38
|
+
function parseCliOptions(argv = process.argv) {
|
|
39
|
+
const flags = new Set();
|
|
40
|
+
const options = {};
|
|
41
|
+
for (let i = 0; i < argv.length; i++) {
|
|
42
|
+
const arg = argv[i];
|
|
43
|
+
if (!arg.startsWith("--")) continue;
|
|
44
|
+
if (arg.includes("=")) {
|
|
45
|
+
const [key, value] = arg.slice(2).split("=");
|
|
46
|
+
options[key] = value;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const nextArg = argv[i + 1];
|
|
50
|
+
if (nextArg && !nextArg.startsWith("--") && !nextArg.startsWith("-")) {
|
|
51
|
+
options[arg.slice(2)] = nextArg;
|
|
52
|
+
i++;
|
|
53
|
+
} else {
|
|
54
|
+
flags.add(arg.slice(2));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
flags,
|
|
59
|
+
options
|
|
60
|
+
};
|
|
54
61
|
}
|
|
55
62
|
async function bootstrap() {
|
|
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
|
-
"dev",
|
|
245
|
-
"api"
|
|
246
|
-
],
|
|
247
|
-
[
|
|
248
|
-
"dev",
|
|
249
|
-
"web"
|
|
250
|
-
],
|
|
251
|
-
[
|
|
252
|
-
"start"
|
|
253
|
-
],
|
|
254
|
-
[
|
|
255
|
-
"skills",
|
|
256
|
-
"sync"
|
|
257
|
-
],
|
|
258
|
-
[
|
|
259
|
-
"skills",
|
|
260
|
-
"create",
|
|
261
|
-
"#name"
|
|
262
|
-
],
|
|
263
|
-
[
|
|
264
|
-
"test"
|
|
265
|
-
],
|
|
266
|
-
[
|
|
267
|
-
"auth",
|
|
268
|
-
"generate"
|
|
269
|
-
],
|
|
270
|
-
[
|
|
271
|
-
"auth",
|
|
272
|
-
"add-companions"
|
|
273
|
-
]
|
|
274
|
-
],
|
|
275
|
-
runners: {
|
|
276
|
-
migrate_status,
|
|
277
|
-
migrate_run,
|
|
278
|
-
migrate_apply,
|
|
279
|
-
migrate_generate,
|
|
280
|
-
fixture_init,
|
|
281
|
-
fixture_import,
|
|
282
|
-
fixture_sync,
|
|
283
|
-
fixture_gen,
|
|
284
|
-
fixture_fetch,
|
|
285
|
-
fixture_explore,
|
|
286
|
-
stub_practice,
|
|
287
|
-
stub_entity,
|
|
288
|
-
scaffold_model,
|
|
289
|
-
scaffold_model_test,
|
|
290
|
-
// scaffold_view_list,
|
|
291
|
-
// scaffold_view_form,
|
|
292
|
-
cone_gen,
|
|
293
|
-
sync,
|
|
294
|
-
build_all,
|
|
295
|
-
build_api,
|
|
296
|
-
build_web,
|
|
297
|
-
dev_all,
|
|
298
|
-
dev_api,
|
|
299
|
-
dev_web,
|
|
300
|
-
start,
|
|
301
|
-
skills_sync,
|
|
302
|
-
skills_create,
|
|
303
|
-
test: testCommand,
|
|
304
|
-
auth_generate,
|
|
305
|
-
"auth_add-companions": auth_add_companions
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
} finally{
|
|
309
|
-
await Sonamu.destroy();
|
|
310
|
-
}
|
|
63
|
+
const notToInit = [
|
|
64
|
+
"dev",
|
|
65
|
+
"build",
|
|
66
|
+
"start",
|
|
67
|
+
"skills",
|
|
68
|
+
"test"
|
|
69
|
+
].includes(process.argv[2] ?? "");
|
|
70
|
+
if (!notToInit) {
|
|
71
|
+
await Sonamu.init(false, false);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const filteredArgv = [];
|
|
75
|
+
let skipNext = false;
|
|
76
|
+
let afterDoubleDash = false;
|
|
77
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
78
|
+
const arg = process.argv[i];
|
|
79
|
+
if (arg === "--") {
|
|
80
|
+
afterDoubleDash = true;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (afterDoubleDash) continue;
|
|
84
|
+
if (skipNext) {
|
|
85
|
+
skipNext = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (arg.startsWith("--")) {
|
|
89
|
+
if (arg.includes("=")) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const nextArg = process.argv[i + 1];
|
|
93
|
+
if (nextArg && !nextArg.startsWith("--") && !nextArg.startsWith("-")) {
|
|
94
|
+
skipNext = true;
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
filteredArgv.push(arg);
|
|
99
|
+
}
|
|
100
|
+
const cmd = filteredArgv[2];
|
|
101
|
+
if ((cmd === "build" || cmd === "dev") && filteredArgv.length === 3) {
|
|
102
|
+
filteredArgv.push("all");
|
|
103
|
+
}
|
|
104
|
+
if (cmd === "test") {
|
|
105
|
+
return testCommand();
|
|
106
|
+
}
|
|
107
|
+
await tsicli(filteredArgv, {
|
|
108
|
+
types: {
|
|
109
|
+
"#entityId": {
|
|
110
|
+
type: "autocomplete",
|
|
111
|
+
name: "#entityId",
|
|
112
|
+
message: "Please input #entityId",
|
|
113
|
+
choices: EntityManager.getAllParentIds().map((entityId) => ({
|
|
114
|
+
title: entityId,
|
|
115
|
+
value: entityId
|
|
116
|
+
}))
|
|
117
|
+
},
|
|
118
|
+
"#recordIds": "number[]",
|
|
119
|
+
"#name": "string",
|
|
120
|
+
"#targets": {
|
|
121
|
+
type: "multiselect",
|
|
122
|
+
name: "#targets",
|
|
123
|
+
message: "Please input #targets",
|
|
124
|
+
choices: [
|
|
125
|
+
{
|
|
126
|
+
title: "Development",
|
|
127
|
+
value: "development_master"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
title: "Production",
|
|
131
|
+
value: "production_master"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
title: "Fixture",
|
|
135
|
+
value: "fixture"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
title: "Test",
|
|
139
|
+
value: "test"
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
args: [
|
|
145
|
+
["fixture", "init"],
|
|
146
|
+
[
|
|
147
|
+
"fixture",
|
|
148
|
+
"import",
|
|
149
|
+
"#entityId",
|
|
150
|
+
"#recordIds"
|
|
151
|
+
],
|
|
152
|
+
["fixture", "sync"],
|
|
153
|
+
["fixture", "gen"],
|
|
154
|
+
["fixture", "fetch"],
|
|
155
|
+
["fixture", "explore"],
|
|
156
|
+
["migrate", "run"],
|
|
157
|
+
[
|
|
158
|
+
"migrate",
|
|
159
|
+
"apply",
|
|
160
|
+
"#targets"
|
|
161
|
+
],
|
|
162
|
+
["migrate", "generate"],
|
|
163
|
+
["migrate", "status"],
|
|
164
|
+
[
|
|
165
|
+
"stub",
|
|
166
|
+
"practice",
|
|
167
|
+
"#name"
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
"stub",
|
|
171
|
+
"entity",
|
|
172
|
+
"#name"
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
"scaffold",
|
|
176
|
+
"model",
|
|
177
|
+
"#entityId"
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
"scaffold",
|
|
181
|
+
"model_test",
|
|
182
|
+
"#entityId"
|
|
183
|
+
],
|
|
184
|
+
[
|
|
185
|
+
"scaffold",
|
|
186
|
+
"view_list",
|
|
187
|
+
"#entityId"
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
"scaffold",
|
|
191
|
+
"view_form",
|
|
192
|
+
"#entityId"
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
"cone",
|
|
196
|
+
"gen",
|
|
197
|
+
"#entityId"
|
|
198
|
+
],
|
|
199
|
+
["sync"],
|
|
200
|
+
["build", "all"],
|
|
201
|
+
["build", "api"],
|
|
202
|
+
["build", "web"],
|
|
203
|
+
["dev", "all"],
|
|
204
|
+
["dev", "api"],
|
|
205
|
+
["dev", "web"],
|
|
206
|
+
["start"],
|
|
207
|
+
["skills", "sync"],
|
|
208
|
+
[
|
|
209
|
+
"skills",
|
|
210
|
+
"create",
|
|
211
|
+
"#name"
|
|
212
|
+
],
|
|
213
|
+
["test"],
|
|
214
|
+
["auth", "generate"],
|
|
215
|
+
["auth", "add-companions"]
|
|
216
|
+
],
|
|
217
|
+
runners: {
|
|
218
|
+
migrate_status,
|
|
219
|
+
migrate_run,
|
|
220
|
+
migrate_apply,
|
|
221
|
+
migrate_generate,
|
|
222
|
+
fixture_init,
|
|
223
|
+
fixture_import,
|
|
224
|
+
fixture_sync,
|
|
225
|
+
fixture_gen,
|
|
226
|
+
fixture_fetch,
|
|
227
|
+
fixture_explore,
|
|
228
|
+
stub_practice,
|
|
229
|
+
stub_entity,
|
|
230
|
+
scaffold_model,
|
|
231
|
+
scaffold_model_test,
|
|
232
|
+
cone_gen,
|
|
233
|
+
sync,
|
|
234
|
+
build_all,
|
|
235
|
+
build_api,
|
|
236
|
+
build_web,
|
|
237
|
+
dev_all,
|
|
238
|
+
dev_api,
|
|
239
|
+
dev_web,
|
|
240
|
+
start,
|
|
241
|
+
skills_sync,
|
|
242
|
+
skills_create,
|
|
243
|
+
test: testCommand,
|
|
244
|
+
auth_generate,
|
|
245
|
+
"auth_add-companions": auth_add_companions
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
} finally {
|
|
249
|
+
await Sonamu.destroy();
|
|
250
|
+
}
|
|
311
251
|
}
|
|
312
|
-
bootstrap().finally(async ()=>{
|
|
313
|
-
|
|
252
|
+
bootstrap().finally(async () => {
|
|
253
|
+
await FixtureManager.destroy();
|
|
314
254
|
});
|
|
315
255
|
/**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
256
|
+
* pnpm sync 하면 실행되는 함수입니다.
|
|
257
|
+
* 프로젝트를 싱크합니다.
|
|
258
|
+
*/
|
|
259
|
+
async function sync() {
|
|
260
|
+
await Sonamu.syncer.sync();
|
|
320
261
|
}
|
|
321
262
|
/**
|
|
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
|
-
});
|
|
263
|
+
* API 개발 서버를 실행하는 공통 로직입니다.
|
|
264
|
+
* dev_all과 dev_api에서 공유합니다.
|
|
265
|
+
*
|
|
266
|
+
* TypeScript를 바로 실행할 수 있도록 @sonamu-kit/ts-loader를,
|
|
267
|
+
* HMR을 지원하기 위해 @sonamu-kit/hmr-hook을 import하며,
|
|
268
|
+
* 소스맵 지원을 위해 --enable-source-maps 플래그를 포함하여 실행합니다.
|
|
269
|
+
*
|
|
270
|
+
* 이때 @sonamu-kit/ts-loader와 @sonamu-kit/hmr-hook는 sonamu가 자체적으로 가지고 있는 dependency입니다.
|
|
271
|
+
* 또한 실행에 사용하는 @sonamu-kit/hmr-runner도 마찬가지로 sonamu가 자체적으로 가지고 있는 dependency입니다.
|
|
272
|
+
* 따라서 사용자 프로젝트에서는 이 세 패키지를 직접 설치할 필요가 없습니다.
|
|
273
|
+
*/
|
|
274
|
+
function spawnApiDevServer(options) {
|
|
275
|
+
const apiRoot = findApiRootPath();
|
|
276
|
+
const entryPoint = "src/index.ts";
|
|
277
|
+
const hotRunnerBinPath = createRequire(import.meta.url).resolve("@sonamu-kit/hmr-runner/bin/run.js");
|
|
278
|
+
const serverProcess = spawn(process.execPath, [
|
|
279
|
+
hotRunnerBinPath,
|
|
280
|
+
"--clear-screen=false",
|
|
281
|
+
"--node-args=--import=sonamu/ts-loader-register",
|
|
282
|
+
"--node-args=--import=sonamu/hmr-hook-register",
|
|
283
|
+
"--node-args=--enable-source-maps",
|
|
284
|
+
"--on-key=r:restart:Restart server",
|
|
285
|
+
"--on-key=c:clear:Clear screen",
|
|
286
|
+
`--on-key=f:shell(rm ${path.join(apiRoot, "sonamu.lock")}):restart:Force restart`,
|
|
287
|
+
"--on-key=enter:shell(echo hi):Key binding test",
|
|
288
|
+
"--on-key=ctrl+f ctrl+f:shell(git pull && pnpm install && pnpm --filter sonamu build && echo 'Sonamu is now up-to-date!'):restart:Pull & install & build & restart",
|
|
289
|
+
entryPoint
|
|
290
|
+
], {
|
|
291
|
+
cwd: apiRoot,
|
|
292
|
+
stdio: "inherit",
|
|
293
|
+
env: {
|
|
294
|
+
...process.env,
|
|
295
|
+
NODE_ENV: "development",
|
|
296
|
+
HOT: "yes",
|
|
297
|
+
API_ROOT_PATH: apiRoot,
|
|
298
|
+
...options?.extraEnv
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
const cleanup = () => {
|
|
302
|
+
console.log(chalk.yellow("\n\n👋 Shutting down..."));
|
|
303
|
+
serverProcess.kill("SIGTERM");
|
|
304
|
+
process.exit(0);
|
|
305
|
+
};
|
|
306
|
+
process.on("SIGINT", cleanup);
|
|
307
|
+
process.on("SIGTERM", cleanup);
|
|
308
|
+
serverProcess.on("exit", (code) => {
|
|
309
|
+
if (code !== 0) {
|
|
310
|
+
console.error(chalk.red(`Server exited with code ${code}`));
|
|
311
|
+
process.exit(code || 1);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
375
314
|
}
|
|
376
315
|
/**
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
316
|
+
* pnpm dev / pnpm dev all 하면 실행되는 함수입니다.
|
|
317
|
+
* 프로젝트에 대해 HMR 지원하는 개발 서버를 띄워줍니다.
|
|
318
|
+
*
|
|
319
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
320
|
+
*/
|
|
321
|
+
function dev_all() {
|
|
322
|
+
console.log(chalk.yellow.bold("Starting Sonamu dev server...\n"));
|
|
323
|
+
spawnApiDevServer();
|
|
384
324
|
}
|
|
385
325
|
/**
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
SONAMU_DISABLE_INTEGRATED_WEB: "yes"
|
|
396
|
-
}
|
|
397
|
-
});
|
|
326
|
+
* pnpm dev api 하면 실행되는 함수입니다.
|
|
327
|
+
* API 전용 개발 서버를 띄웁니다.
|
|
328
|
+
* dev_all과 거의 동일하되, 통합 웹 서버를 비활성화합니다.
|
|
329
|
+
*
|
|
330
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
331
|
+
*/
|
|
332
|
+
function dev_api() {
|
|
333
|
+
console.log(chalk.yellow.bold("Starting Sonamu API-only dev server...\n"));
|
|
334
|
+
spawnApiDevServer({ extraEnv: { SONAMU_DISABLE_INTEGRATED_WEB: "yes" } });
|
|
398
335
|
}
|
|
399
336
|
/**
|
|
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
|
-
process.on(signal, ()=>{
|
|
434
|
-
viteProcess.kill(signal);
|
|
435
|
-
});
|
|
436
|
-
}
|
|
337
|
+
* pnpm dev web 하면 실행되는 함수입니다.
|
|
338
|
+
* Vite 개발 서버를 단독으로 실행합니다.
|
|
339
|
+
* -- 뒤의 인자는 Vite에 그대로 전달됩니다.
|
|
340
|
+
*
|
|
341
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
342
|
+
*/
|
|
343
|
+
async function dev_web() {
|
|
344
|
+
const appRoot = findAppRootPath();
|
|
345
|
+
const webPath = path.join(appRoot, "web");
|
|
346
|
+
if (!await exists(webPath)) {
|
|
347
|
+
console.error(`web 디렉토리를 찾을 수 없습니다: ${webPath}`);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
const doubleDashIndex = process.argv.indexOf("--");
|
|
351
|
+
const passthroughArgs = doubleDashIndex !== -1 ? process.argv.slice(doubleDashIndex + 1) : [];
|
|
352
|
+
const viteArgs = [
|
|
353
|
+
"exec",
|
|
354
|
+
"vite",
|
|
355
|
+
...passthroughArgs
|
|
356
|
+
];
|
|
357
|
+
console.log(chalk.yellow.bold("Starting Vite dev server...\n"));
|
|
358
|
+
const viteProcess = spawn("pnpm", viteArgs, {
|
|
359
|
+
cwd: webPath,
|
|
360
|
+
stdio: "inherit"
|
|
361
|
+
});
|
|
362
|
+
viteProcess.on("exit", (code) => {
|
|
363
|
+
process.exit(code ?? 0);
|
|
364
|
+
});
|
|
365
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
366
|
+
process.on(signal, () => {
|
|
367
|
+
viteProcess.kill(signal);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
437
370
|
}
|
|
438
371
|
/**
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
372
|
+
* API 빌드 설정 파일 경로를 결정합니다.
|
|
373
|
+
* 프로젝트 루트에 `tsdown.config.ts`가 있으면 그것을, 없으면 sonamu 기본 설정을 사용합니다.
|
|
374
|
+
*/
|
|
375
|
+
async function resolveApiBuildConfigPath() {
|
|
376
|
+
const localConfigPath = path.join(process.cwd(), "tsdown.config.ts");
|
|
377
|
+
try {
|
|
378
|
+
if (await exists(localConfigPath)) {
|
|
379
|
+
console.log(chalk.dim("Using tsdown.config.ts from project root..."));
|
|
380
|
+
return localConfigPath;
|
|
381
|
+
}
|
|
382
|
+
console.log(chalk.dim("Using default tsdown API config from sonamu package..."));
|
|
383
|
+
return path.join(import.meta.dirname, "..", "..", "tsdown.api.config.ts");
|
|
384
|
+
} catch (error) {
|
|
385
|
+
console.error(chalk.red("Setting up API build config failed."), error);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
455
388
|
}
|
|
456
389
|
/**
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
});
|
|
390
|
+
* sonamu build / sonamu build all 하면 실행되는 함수입니다.
|
|
391
|
+
* build_api + build_web의 합성입니다. Web 디렉토리가 없으면 Web 빌드를 스킵합니다.
|
|
392
|
+
*/
|
|
393
|
+
async function build_all() {
|
|
394
|
+
await build_api();
|
|
395
|
+
await build_web({ skipIfMissing: true });
|
|
464
396
|
}
|
|
465
397
|
/**
|
|
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
|
-
}
|
|
398
|
+
* pnpm build api 하면 실행되는 함수입니다.
|
|
399
|
+
* API 프로젝트만 빌드합니다.
|
|
400
|
+
*
|
|
401
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
402
|
+
*/
|
|
403
|
+
async function build_api() {
|
|
404
|
+
const appRoot = findAppRootPath();
|
|
405
|
+
const configFilePath = await resolveApiBuildConfigPath();
|
|
406
|
+
const apiStartedAt = Date.now();
|
|
407
|
+
try {
|
|
408
|
+
for (const artifact of API_ARTIFACTS) {
|
|
409
|
+
const cwd = path.join(appRoot, artifact.projectPath);
|
|
410
|
+
printTaskHeader(artifact.name, artifact.description, cwd);
|
|
411
|
+
await runBuildSteps(artifact, {
|
|
412
|
+
cwd,
|
|
413
|
+
buildCommandArgs: { configFilePath }
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
printBuildSummary("API", true, Date.now() - apiStartedAt);
|
|
417
|
+
} catch (e) {
|
|
418
|
+
printBuildSummary("API", false, Date.now() - apiStartedAt);
|
|
419
|
+
console.error(e);
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
491
422
|
}
|
|
492
423
|
/**
|
|
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
|
-
|
|
424
|
+
* pnpm build web 하면 실행되는 함수입니다.
|
|
425
|
+
* Web 프로젝트만 빌드합니다.
|
|
426
|
+
*
|
|
427
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
428
|
+
*/
|
|
429
|
+
async function build_web({ skipIfMissing = false } = {}) {
|
|
430
|
+
const appRoot = findAppRootPath();
|
|
431
|
+
const webPath = path.join(appRoot, "web");
|
|
432
|
+
if (!await exists(webPath)) {
|
|
433
|
+
if (skipIfMissing) {
|
|
434
|
+
console.log(chalk.gray("Web 디렉토리가 없으므로 Web 빌드를 건너뜁니다."));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
console.error(`web 디렉토리를 찾을 수 없습니다: ${webPath}`);
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
const webStartedAt = Date.now();
|
|
441
|
+
try {
|
|
442
|
+
for (const artifact of WEB_ARTIFACTS) {
|
|
443
|
+
const cwd = path.join(appRoot, artifact.projectPath);
|
|
444
|
+
printTaskHeader(artifact.name, artifact.description, cwd);
|
|
445
|
+
await runBuildSteps(artifact, {
|
|
446
|
+
cwd,
|
|
447
|
+
buildCommandArgs: {}
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
printBuildSummary("Web", true, Date.now() - webStartedAt);
|
|
451
|
+
} catch (e) {
|
|
452
|
+
printBuildSummary("Web", false, Date.now() - webStartedAt);
|
|
453
|
+
console.error(e);
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
524
456
|
}
|
|
525
457
|
/**
|
|
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
|
-
}
|
|
458
|
+
* pre-build, build, post-build 단계를 순차적으로 실행합니다.
|
|
459
|
+
*/
|
|
460
|
+
async function runBuildSteps(artifact, options) {
|
|
461
|
+
const steps = [
|
|
462
|
+
{
|
|
463
|
+
name: "pre-build",
|
|
464
|
+
cmd: artifact.preBuildCommand?.()
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: "build",
|
|
468
|
+
cmd: artifact.buildCommand(options.buildCommandArgs)
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "post-build",
|
|
472
|
+
cmd: artifact.postBuildCommand?.()
|
|
473
|
+
}
|
|
474
|
+
].filter((step) => step.cmd);
|
|
475
|
+
for (let i = 0; i < steps.length; i++) {
|
|
476
|
+
const step = steps[i];
|
|
477
|
+
const isLast = i === steps.length - 1;
|
|
478
|
+
try {
|
|
479
|
+
assert(step.cmd);
|
|
480
|
+
printTaskStart(step.name, step.cmd, isLast);
|
|
481
|
+
await execWithLinePrefix(step.cmd, { cwd: options.cwd });
|
|
482
|
+
printTaskSuccess(step.name, isLast);
|
|
483
|
+
} catch (e) {
|
|
484
|
+
printTaskFailed(step.name, isLast);
|
|
485
|
+
throw new Error(`${step.name} failed`, { cause: e });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
559
488
|
}
|
|
560
489
|
/**
|
|
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
|
-
|
|
490
|
+
* pnpm start 하면 실행되는 함수입니다.
|
|
491
|
+
* 빌드된 프로젝트를 실행합니다.
|
|
492
|
+
*
|
|
493
|
+
* 빌드된 결과물(dist 디렉토리의 index.js 엔트리포인트)이 없다면 실행을 중단합니다.
|
|
494
|
+
* 소스맵 지원과 dotenv 지원을 포함하여 실행합니다.
|
|
495
|
+
*
|
|
496
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
497
|
+
*/
|
|
498
|
+
async function start() {
|
|
499
|
+
const apiRoot = findApiRootPath();
|
|
500
|
+
const entryPoint = "dist/index.js";
|
|
501
|
+
if (!await exists(entryPoint)) {
|
|
502
|
+
console.log(chalk.red(`${entryPoint} not found. Please build your project first.`));
|
|
503
|
+
console.log(chalk.blue("Run: pnpm sonamu build"));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const { spawn: spawn$1 } = await import("child_process");
|
|
507
|
+
const serverProcess = spawn$1(process.execPath, [
|
|
508
|
+
"--enable-source-maps",
|
|
509
|
+
"-r",
|
|
510
|
+
"dotenv/config",
|
|
511
|
+
entryPoint
|
|
512
|
+
], {
|
|
513
|
+
cwd: apiRoot,
|
|
514
|
+
stdio: "inherit"
|
|
515
|
+
});
|
|
516
|
+
process.on("SIGINT", () => {
|
|
517
|
+
serverProcess.kill("SIGTERM");
|
|
518
|
+
process.exit(0);
|
|
519
|
+
});
|
|
590
520
|
}
|
|
591
521
|
async function setupMigrator() {
|
|
592
|
-
|
|
593
|
-
migrator = new Migrator();
|
|
522
|
+
migrator = new Migrator();
|
|
594
523
|
}
|
|
595
524
|
async function setupFixtureManager() {
|
|
596
|
-
|
|
525
|
+
FixtureManager.init();
|
|
597
526
|
}
|
|
598
527
|
async function migrate_apply(targets) {
|
|
599
|
-
|
|
600
|
-
|
|
528
|
+
await setupMigrator();
|
|
529
|
+
await migrator.runAction("apply", targets);
|
|
601
530
|
}
|
|
602
531
|
async function migrate_run() {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
await migrator.runAction("apply", targets);
|
|
532
|
+
await setupMigrator();
|
|
533
|
+
const localHosts = [
|
|
534
|
+
"localhost",
|
|
535
|
+
"127.0.0.1",
|
|
536
|
+
"0.0.0.0",
|
|
537
|
+
"::1"
|
|
538
|
+
];
|
|
539
|
+
const targets = Object.keys(Sonamu.dbConfig).filter((target) => {
|
|
540
|
+
const targetConfig = Sonamu.dbConfig[target];
|
|
541
|
+
const host = (targetConfig?.connection)?.host ?? "localhost";
|
|
542
|
+
return localHosts.includes(host.toLowerCase());
|
|
543
|
+
});
|
|
544
|
+
await migrator.runAction("apply", targets);
|
|
617
545
|
}
|
|
618
546
|
async function migrate_generate() {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
547
|
+
await setupMigrator();
|
|
548
|
+
const { conns } = await migrator.getStatus();
|
|
549
|
+
const hasStatus0 = conns.some((conn) => conn.status === 0);
|
|
550
|
+
if (!hasStatus0) {
|
|
551
|
+
console.log(chalk.red("마이그레이션 파일을 생성하려면 기존 마이그레이션이 최소 하나의 DB에 모두 적용되어 있어야 합니다."));
|
|
552
|
+
for (const conn of conns) {
|
|
553
|
+
if (conn.pending.length > 0) {
|
|
554
|
+
console.log(chalk.yellow(` ${conn.name}: pending ${conn.pending.length}개`));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
process.exit(1);
|
|
558
|
+
}
|
|
559
|
+
const count = await migrator.generatePreparedCodes();
|
|
560
|
+
if (count > 0) {
|
|
561
|
+
console.log(chalk.green(`${count}개의 마이그레이션 파일이 생성되었습니다.`));
|
|
562
|
+
}
|
|
635
563
|
}
|
|
636
564
|
async function migrate_status() {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
console.log(status);
|
|
565
|
+
await setupMigrator();
|
|
566
|
+
const status = await migrator.getStatus();
|
|
567
|
+
console.log(status);
|
|
641
568
|
}
|
|
642
569
|
async function fixture_init() {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
execSync(`${mysqlCmd} ${conn.database} < ${dumpFilename}`);
|
|
697
|
-
if (await exists(migrationsDump)) {
|
|
698
|
-
execSync(`${mysqlCmd} ${conn.database} < ${migrationsDump}`);
|
|
699
|
-
}
|
|
700
|
-
await db.destroy();
|
|
701
|
-
}
|
|
702
|
-
await _db.destroy();
|
|
570
|
+
const srcConfig = Sonamu.dbConfig.development_master;
|
|
571
|
+
const targets = [{
|
|
572
|
+
label: "(REMOTE) Fixture DB",
|
|
573
|
+
config: Sonamu.dbConfig.fixture
|
|
574
|
+
}, {
|
|
575
|
+
label: "(LOCAL) Testing DB",
|
|
576
|
+
config: Sonamu.dbConfig.test,
|
|
577
|
+
toSkip: (() => {
|
|
578
|
+
const remoteConn = Sonamu.dbConfig.fixture.connection;
|
|
579
|
+
const localConn = Sonamu.dbConfig.test.connection;
|
|
580
|
+
return remoteConn.host === localConn.host && remoteConn.database === localConn.database;
|
|
581
|
+
})()
|
|
582
|
+
}];
|
|
583
|
+
console.log("DUMP...");
|
|
584
|
+
const dumpFilename = `/tmp/sonamu-fixture-init-${Date.now()}.sql`;
|
|
585
|
+
const srcConn = srcConfig.connection;
|
|
586
|
+
const migrationsDump = `/tmp/sonamu-fixture-init-migrations-${Date.now()}.sql`;
|
|
587
|
+
execSync(`mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction -d --no-create-db --triggers ${srcConn.database} > ${dumpFilename}`);
|
|
588
|
+
const _db = knex(srcConfig);
|
|
589
|
+
const [[migrations]] = await _db.raw("SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = ? AND table_name = 'knex_migrations'", [srcConn.database]);
|
|
590
|
+
if (migrations.count > 0) {
|
|
591
|
+
execSync(`mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction --no-create-db --triggers ${srcConn.database} knex_migrations knex_migrations_lock > ${migrationsDump}`);
|
|
592
|
+
}
|
|
593
|
+
for (const { label, config, toSkip } of targets) {
|
|
594
|
+
const conn = config.connection;
|
|
595
|
+
if (toSkip === true) {
|
|
596
|
+
console.log(chalk.red(`${label}: Skipped!`));
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
const db = knex({
|
|
600
|
+
...config,
|
|
601
|
+
connection: {
|
|
602
|
+
...config.connection ?? {},
|
|
603
|
+
database: undefined
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
const [[row]] = await db.raw(`SHOW DATABASES LIKE "${conn.database}"`);
|
|
607
|
+
if (row) {
|
|
608
|
+
console.log(chalk.yellow(`${label}: Database "${conn.database}" Already exists`));
|
|
609
|
+
await db.destroy();
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
console.log(`SYNC to ${label}...`);
|
|
613
|
+
const mysqlCmd = `mysql -h${conn.host} -u${conn.user} -p${conn.password}`;
|
|
614
|
+
execSync(`${mysqlCmd} -e 'DROP DATABASE IF EXISTS \`${conn.database}\`'`);
|
|
615
|
+
execSync(`${mysqlCmd} -e 'CREATE DATABASE \`${conn.database}\`'`);
|
|
616
|
+
execSync(`${mysqlCmd} ${conn.database} < ${dumpFilename}`);
|
|
617
|
+
if (await exists(migrationsDump)) {
|
|
618
|
+
execSync(`${mysqlCmd} ${conn.database} < ${migrationsDump}`);
|
|
619
|
+
}
|
|
620
|
+
await db.destroy();
|
|
621
|
+
}
|
|
622
|
+
await _db.destroy();
|
|
703
623
|
}
|
|
704
624
|
async function fixture_import(entityId, recordIds) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
625
|
+
await setupFixtureManager();
|
|
626
|
+
await FixtureManager.importFixture(entityId, recordIds);
|
|
627
|
+
await FixtureManager.sync();
|
|
708
628
|
}
|
|
709
629
|
async function fixture_sync() {
|
|
710
|
-
|
|
711
|
-
|
|
630
|
+
await setupFixtureManager();
|
|
631
|
+
await FixtureManager.sync();
|
|
712
632
|
}
|
|
713
633
|
/**
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
634
|
+
* fixture gen 명령어
|
|
635
|
+
* 옵션을 process.argv에서 파싱
|
|
636
|
+
*/
|
|
637
|
+
async function fixture_gen() {
|
|
638
|
+
const options = parseOptions(process.argv);
|
|
639
|
+
await fixtureGenCommand(options);
|
|
719
640
|
}
|
|
720
641
|
/**
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
642
|
+
* fixture fetch 명령어
|
|
643
|
+
* 옵션을 process.argv에서 파싱
|
|
644
|
+
*/
|
|
645
|
+
async function fixture_fetch() {
|
|
646
|
+
const options = parseOptions(process.argv);
|
|
647
|
+
await fixtureFetchCommand(options);
|
|
726
648
|
}
|
|
727
649
|
/**
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
650
|
+
* fixture explore 명령어
|
|
651
|
+
* 옵션을 process.argv에서 파싱
|
|
652
|
+
*/
|
|
653
|
+
async function fixture_explore() {
|
|
654
|
+
const options = parseOptions(process.argv);
|
|
655
|
+
await fixtureExploreCommand(options);
|
|
733
656
|
}
|
|
734
657
|
/**
|
|
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
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
return options;
|
|
658
|
+
* 간단한 옵션 파서
|
|
659
|
+
*/
|
|
660
|
+
function parseOptions(argv) {
|
|
661
|
+
const options = { _: [] };
|
|
662
|
+
for (let i = 0; i < argv.length; i++) {
|
|
663
|
+
const arg = argv[i];
|
|
664
|
+
if (arg.startsWith("--")) {
|
|
665
|
+
const key = arg.slice(2);
|
|
666
|
+
if (key.includes("=")) {
|
|
667
|
+
const [k, v] = key.split("=");
|
|
668
|
+
options[k] = v;
|
|
669
|
+
} else {
|
|
670
|
+
const next = argv[i + 1];
|
|
671
|
+
if (next && !next.startsWith("--")) {
|
|
672
|
+
options[key] = next;
|
|
673
|
+
i++;
|
|
674
|
+
} else {
|
|
675
|
+
options[key] = true;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
} else if (arg.startsWith("-")) {
|
|
679
|
+
const key = arg.slice(1);
|
|
680
|
+
const next = argv[i + 1];
|
|
681
|
+
if (next && !next.startsWith("-")) {
|
|
682
|
+
options[key] = next;
|
|
683
|
+
i++;
|
|
684
|
+
} else {
|
|
685
|
+
options[key] = true;
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
options._.push(arg);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return options;
|
|
770
692
|
}
|
|
771
693
|
async function stub_practice(name) {
|
|
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
|
-
await writeFile(dstPath, code);
|
|
807
|
-
execSync(`code ${dstPath}`);
|
|
808
|
-
const runCode = `yarn node -r dotenv/config --enable-source-maps dist/practices/${fileName.replace(".ts", ".js")}`;
|
|
809
|
-
console.log(`${chalk.blue(runCode)} copied to clipboard.`);
|
|
810
|
-
execSync(`echo "${runCode}" | pbcopy`);
|
|
694
|
+
const practiceDir = path.join(Sonamu.apiRootPath, "src", "practices");
|
|
695
|
+
const fileNames = await readdir(practiceDir);
|
|
696
|
+
const maxSeqNo = await (async () => {
|
|
697
|
+
if (!await exists(practiceDir)) {
|
|
698
|
+
await mkdir(practiceDir, { recursive: true });
|
|
699
|
+
}
|
|
700
|
+
const filteredSeqs = fileNames.filter((fileName$1) => fileName$1.startsWith("p") && fileName$1.endsWith(".ts")).map((fileName$1) => {
|
|
701
|
+
const [, seqNo] = fileName$1.match(/^p([0-9]+)-/) ?? ["0", "0"];
|
|
702
|
+
return parseInt(seqNo);
|
|
703
|
+
}).toSorted((a, b) => b - a);
|
|
704
|
+
if (filteredSeqs.length > 0) {
|
|
705
|
+
return filteredSeqs[0];
|
|
706
|
+
}
|
|
707
|
+
return 0;
|
|
708
|
+
})();
|
|
709
|
+
const currentSeqNo = maxSeqNo + 1;
|
|
710
|
+
const fileName = `p${currentSeqNo}-${name}.ts`;
|
|
711
|
+
const dstPath = path.join(practiceDir, fileName);
|
|
712
|
+
const code = [
|
|
713
|
+
`import { Sonamu } from "sonamu";`,
|
|
714
|
+
"",
|
|
715
|
+
`console.clear();`,
|
|
716
|
+
`console.log("${fileName}");`,
|
|
717
|
+
"",
|
|
718
|
+
`Sonamu.runScript(async () => {`,
|
|
719
|
+
` // TODO`,
|
|
720
|
+
`});`,
|
|
721
|
+
""
|
|
722
|
+
].join("\n");
|
|
723
|
+
await writeFile(dstPath, code);
|
|
724
|
+
execSync(`code ${dstPath}`);
|
|
725
|
+
const runCode = `yarn node -r dotenv/config --enable-source-maps dist/practices/${fileName.replace(".ts", ".js")}`;
|
|
726
|
+
console.log(`${chalk.blue(runCode)} copied to clipboard.`);
|
|
727
|
+
execSync(`echo "${runCode}" | pbcopy`);
|
|
811
728
|
}
|
|
812
729
|
async function stub_entity(entityId) {
|
|
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
|
-
// 이를 통해 ANTHROPIC_API_KEY가 없어도 Sonamu를 사용할 수 있으며,
|
|
857
|
-
// 생성된 템플릿 cone은 나중에 'cone gen' 명령어로 AI를 통해 업그레이드할 수 있습니다.
|
|
858
|
-
console.log(`🌟 Generating template cones...`);
|
|
859
|
-
await entity.generateTemplateCones();
|
|
860
|
-
console.log(`✓ Entity '${entityId}' created with template cones`);
|
|
861
|
-
console.log(`💡 Tip: Run 'pnpm sonamu cone gen ${entityId}' to improve with AI`);
|
|
730
|
+
await Sonamu.syncer.createEntity({
|
|
731
|
+
entityId,
|
|
732
|
+
title: entityId
|
|
733
|
+
});
|
|
734
|
+
const { flags } = parseCliOptions();
|
|
735
|
+
const useAI = flags.has("ai");
|
|
736
|
+
const noCones = flags.has("no-cones");
|
|
737
|
+
if (noCones) {
|
|
738
|
+
console.log(`✓ Entity '${entityId}' created without cones`);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const { EntityManager: EntityManager$1 } = await import("../entity/entity-manager.js");
|
|
742
|
+
const entity = EntityManager$1.get(entityId);
|
|
743
|
+
if (!entity) {
|
|
744
|
+
console.error(`Entity not found: ${entityId}`);
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (useAI) {
|
|
748
|
+
console.log(`✓ Entity '${entityId}' created`);
|
|
749
|
+
console.log(`🌟 Generating AI-powered cones...`);
|
|
750
|
+
try {
|
|
751
|
+
const configLocale = Sonamu.config.i18n?.defaultLocale;
|
|
752
|
+
const locale = configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko";
|
|
753
|
+
const result = await entity.generateCones({
|
|
754
|
+
preserveExisting: false,
|
|
755
|
+
onlyEmpty: false,
|
|
756
|
+
locale
|
|
757
|
+
});
|
|
758
|
+
console.log(`✅ Done (${result.tokensUsed} tokens)`);
|
|
759
|
+
} catch (error) {
|
|
760
|
+
if (error instanceof Error && error.message.includes("ANTHROPIC_API_KEY")) {
|
|
761
|
+
console.error(`\n❌ ${error.message}`);
|
|
762
|
+
console.error(`\n💡 Remove --ai flag to use template cones instead`);
|
|
763
|
+
} else {
|
|
764
|
+
throw error;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
console.log(`🌟 Generating template cones...`);
|
|
770
|
+
await entity.generateTemplateCones();
|
|
771
|
+
console.log(`✓ Entity '${entityId}' created with template cones`);
|
|
772
|
+
console.log(`💡 Tip: Run 'pnpm sonamu cone gen ${entityId}' to improve with AI`);
|
|
862
773
|
}
|
|
863
774
|
/**
|
|
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
|
-
} else {
|
|
946
|
-
console.error(`\n❌ Failed to generate cones: Unknown error`);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
775
|
+
* AI를 사용하여 entity의 cone 메타데이터를 생성하거나 업그레이드합니다.
|
|
776
|
+
*
|
|
777
|
+
* 옵션:
|
|
778
|
+
* - --regenerate: 전체 재생성 (기존 cone 덮어쓰기)
|
|
779
|
+
* - --locale <ko|en|ja>: 생성 언어 지정
|
|
780
|
+
* - 기본: onlyEmpty 모드 (기존 fixtureHint 보존)
|
|
781
|
+
*
|
|
782
|
+
* ANTHROPIC_API_KEY 필요 (sonamu.secret.ts 또는 환경변수)
|
|
783
|
+
*/
|
|
784
|
+
async function cone_gen(entityId) {
|
|
785
|
+
const { EntityManager: EntityManager$1 } = await import("../entity/entity-manager.js");
|
|
786
|
+
const { flags, options } = parseCliOptions();
|
|
787
|
+
if (flags.has("all") || entityId === "all") {
|
|
788
|
+
const allEntities = EntityManager$1.getAllEntities();
|
|
789
|
+
console.log(`🌟 Generating AI-powered cones for ${allEntities.length} entities...\n`);
|
|
790
|
+
let totalTokens = 0;
|
|
791
|
+
const errors = [];
|
|
792
|
+
for (const entity$1 of allEntities) {
|
|
793
|
+
try {
|
|
794
|
+
console.log(`Processing ${entity$1.id}...`);
|
|
795
|
+
const configLocale = options.locale || Sonamu.config.i18n?.defaultLocale;
|
|
796
|
+
const locale = configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko";
|
|
797
|
+
const result = await entity$1.generateCones({
|
|
798
|
+
preserveExisting: !flags.has("regenerate"),
|
|
799
|
+
onlyEmpty: !flags.has("regenerate"),
|
|
800
|
+
locale
|
|
801
|
+
});
|
|
802
|
+
totalTokens += result.tokensUsed;
|
|
803
|
+
console.log(` ✓ ${entity$1.id} (${result.tokensUsed} tokens)\n`);
|
|
804
|
+
} catch (error) {
|
|
805
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
806
|
+
errors.push(`${entity$1.id}: ${message}`);
|
|
807
|
+
console.error(` ✗ ${entity$1.id}: ${message}\n`);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
console.log(`\n✅ Done! Total: ${totalTokens} tokens used`);
|
|
811
|
+
const estimatedCost = totalTokens * 9 / 1e6;
|
|
812
|
+
console.log(`💰 Estimated cost: ~$${estimatedCost.toFixed(4)}`);
|
|
813
|
+
if (errors.length > 0) {
|
|
814
|
+
console.error(`\n❌ Failed entities (${errors.length}):`);
|
|
815
|
+
for (const err of errors) {
|
|
816
|
+
console.error(` - ${err}`);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const entity = EntityManager$1.get(entityId);
|
|
822
|
+
if (!entity) {
|
|
823
|
+
console.error(`Entity not found: ${entityId}`);
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
const mode = flags.has("regenerate") ? "regenerating" : "generating";
|
|
827
|
+
console.log(`🌟 ${mode === "regenerating" ? "Regenerating" : "Generating"} AI-powered cones for ${entityId}...`);
|
|
828
|
+
try {
|
|
829
|
+
const configLocale = options.locale || Sonamu.config.i18n?.defaultLocale;
|
|
830
|
+
const locale = configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko";
|
|
831
|
+
const result = await entity.generateCones({
|
|
832
|
+
preserveExisting: !flags.has("regenerate"),
|
|
833
|
+
onlyEmpty: !flags.has("regenerate"),
|
|
834
|
+
locale
|
|
835
|
+
});
|
|
836
|
+
console.log(`✅ Done! (${result.tokensUsed} tokens used)`);
|
|
837
|
+
const estimatedCost = result.tokensUsed * 9 / 1e6;
|
|
838
|
+
console.log(`💰 Estimated cost: ~$${estimatedCost.toFixed(4)}`);
|
|
839
|
+
} catch (error) {
|
|
840
|
+
if (error instanceof Error) {
|
|
841
|
+
if (error.message.includes("ANTHROPIC_API_KEY")) {
|
|
842
|
+
console.error(`\n❌ ${error.message}`);
|
|
843
|
+
console.error(`\n💡 To use AI-powered cone generation:`);
|
|
844
|
+
console.error(` 1. Get an API key from https://console.anthropic.com/`);
|
|
845
|
+
console.error(` 2. Add it to sonamu.secret.ts or set ANTHROPIC_API_KEY environment variable`);
|
|
846
|
+
} else if (error.message.includes("Rate limit")) {
|
|
847
|
+
console.error(`\n❌ ${error.message}`);
|
|
848
|
+
console.error(`\n💡 Please wait a moment and try again.`);
|
|
849
|
+
} else {
|
|
850
|
+
console.error(`\n❌ Failed to generate cones: ${error.message}`);
|
|
851
|
+
}
|
|
852
|
+
} else {
|
|
853
|
+
console.error(`\n❌ Failed to generate cones: Unknown error`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
949
856
|
}
|
|
950
857
|
async function scaffold_model(entityId) {
|
|
951
|
-
|
|
952
|
-
entityId
|
|
953
|
-
});
|
|
858
|
+
await Sonamu.syncer.generateTemplate("model", { entityId });
|
|
954
859
|
}
|
|
955
860
|
async function scaffold_model_test(entityId) {
|
|
956
|
-
|
|
957
|
-
entityId
|
|
958
|
-
});
|
|
861
|
+
await Sonamu.syncer.generateTemplate("model_test", { entityId });
|
|
959
862
|
}
|
|
960
863
|
/**
|
|
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
|
-
useSymlink: true,
|
|
1004
|
-
copyProjectTemplates: true,
|
|
1005
|
-
sourceBase
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
864
|
+
* pnpm sonamu skills sync 하면 실행되는 함수입니다.
|
|
865
|
+
* 공식 Skills를 로컬 프로젝트 또는 글로벌 ~/.claude/로 동기화합니다.
|
|
866
|
+
*
|
|
867
|
+
* --global 플래그: ~/.claude/에 동기화 (프로젝트 생성 전 사용 가능)
|
|
868
|
+
*/
|
|
869
|
+
async function skills_sync() {
|
|
870
|
+
const { flags } = parseCliOptions();
|
|
871
|
+
const isGlobal = flags.has("global");
|
|
872
|
+
const sourceBase = path.resolve(import.meta.dirname, "..", "..", "src", "skills");
|
|
873
|
+
const sourceSkillsDir = path.join(sourceBase, "sonamu");
|
|
874
|
+
const sourceClaudeMd = path.join(sourceBase, "CLAUDE.md");
|
|
875
|
+
if (!await exists(sourceSkillsDir)) {
|
|
876
|
+
console.log(chalk.yellow("Skills source not found in sonamu package."));
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
if (isGlobal) {
|
|
880
|
+
const homeClaudeDir = path.join(os.homedir(), ".claude");
|
|
881
|
+
await skills_sync_to(homeClaudeDir, sourceSkillsDir, sourceClaudeMd, {
|
|
882
|
+
useSymlink: false,
|
|
883
|
+
copyProjectTemplates: false,
|
|
884
|
+
isGlobal: true
|
|
885
|
+
});
|
|
886
|
+
const sourceCommandsDir = path.join(sourceBase, "commands");
|
|
887
|
+
const sourceCommand = path.join(sourceCommandsDir, "sonamu-skills.md");
|
|
888
|
+
if (await exists(sourceCommand)) {
|
|
889
|
+
const targetCommandsDir = path.join(homeClaudeDir, "commands");
|
|
890
|
+
await mkdir(targetCommandsDir, { recursive: true });
|
|
891
|
+
await cp(sourceCommand, path.join(targetCommandsDir, "sonamu-skills.md"));
|
|
892
|
+
console.log(chalk.green(`✓ /sonamu-skills command installed → ~/.claude/commands/`));
|
|
893
|
+
}
|
|
894
|
+
console.log(chalk.cyan(`\n Global sync complete → ~/.claude/skills/sonamu/`));
|
|
895
|
+
console.log(chalk.dim(` These skills are available in all Claude Code sessions.`));
|
|
896
|
+
console.log(chalk.dim(` Once a project is created, run 'pnpm sonamu skills sync' for project-local sync.`));
|
|
897
|
+
} else {
|
|
898
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
899
|
+
const claudeDir = path.join(workspaceRoot, ".claude");
|
|
900
|
+
await skills_sync_to(claudeDir, sourceSkillsDir, sourceClaudeMd, {
|
|
901
|
+
useSymlink: true,
|
|
902
|
+
copyProjectTemplates: true,
|
|
903
|
+
sourceBase
|
|
904
|
+
});
|
|
905
|
+
}
|
|
1008
906
|
}
|
|
1009
907
|
/**
|
|
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
|
-
await writeFile(targetClaudeMd, newContent);
|
|
1105
|
-
console.log(chalk.green(`✓ CLAUDE.md updated (marker region)`));
|
|
1106
|
-
} else {
|
|
1107
|
-
console.log(chalk.yellow(`⏭ CLAUDE.md marker positions invalid, skipped`));
|
|
1108
|
-
}
|
|
1109
|
-
} else {
|
|
1110
|
-
// 마커가 없는 기존 CLAUDE.md에 Sonamu 섹션을 추가합니다
|
|
1111
|
-
const appended = `${targetContent.trimEnd()}\n\n<!-- SONAMU:START -->\n${sourceContent}\n<!-- SONAMU:END -->\n`;
|
|
1112
|
-
await writeFile(targetClaudeMd, appended);
|
|
1113
|
-
console.log(chalk.green(`✓ CLAUDE.md updated (appended Sonamu section)`));
|
|
1114
|
-
}
|
|
1115
|
-
} else {
|
|
1116
|
-
const withMarkers = `<!-- SONAMU:START -->\n${sourceContent}\n<!-- SONAMU:END -->\n`;
|
|
1117
|
-
await writeFile(targetClaudeMd, withMarkers);
|
|
1118
|
-
console.log(chalk.green(`✓ CLAUDE.md created`));
|
|
1119
|
-
}
|
|
1120
|
-
} catch (error) {
|
|
1121
|
-
console.error(chalk.red(`✗ Failed to update CLAUDE.md: ${error instanceof Error ? error.message : String(error)}`));
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
908
|
+
* claudeDir로 skills를 동기화하는 공통 로직입니다.
|
|
909
|
+
*/
|
|
910
|
+
async function skills_sync_to(claudeDir, sourceSkillsDir, sourceClaudeMd, options) {
|
|
911
|
+
const targetSkillsDir = path.join(claudeDir, "skills", "sonamu");
|
|
912
|
+
try {
|
|
913
|
+
await rm(targetSkillsDir, {
|
|
914
|
+
recursive: true,
|
|
915
|
+
force: true
|
|
916
|
+
});
|
|
917
|
+
} catch {}
|
|
918
|
+
await mkdir(path.dirname(targetSkillsDir), { recursive: true });
|
|
919
|
+
if (options.useSymlink) {
|
|
920
|
+
try {
|
|
921
|
+
await symlink(sourceSkillsDir, targetSkillsDir, "dir");
|
|
922
|
+
console.log(chalk.green(`✓ Skills linked (symlink)`));
|
|
923
|
+
} catch (error) {
|
|
924
|
+
console.log(chalk.yellow(`⚠ Symlink failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
925
|
+
console.log(chalk.yellow(` Falling back to copy...`));
|
|
926
|
+
await skillsCopy(sourceSkillsDir, targetSkillsDir);
|
|
927
|
+
}
|
|
928
|
+
} else {
|
|
929
|
+
await skillsCopy(sourceSkillsDir, targetSkillsDir);
|
|
930
|
+
}
|
|
931
|
+
if (options.copyProjectTemplates && options.sourceBase) {
|
|
932
|
+
const sourceProjectDir = path.join(options.sourceBase, "project");
|
|
933
|
+
const targetProjectDir = path.join(claudeDir, "skills", "project");
|
|
934
|
+
if (await exists(sourceProjectDir)) {
|
|
935
|
+
if (!await exists(targetProjectDir)) {
|
|
936
|
+
try {
|
|
937
|
+
await cp(sourceProjectDir, targetProjectDir, { recursive: true });
|
|
938
|
+
console.log(chalk.green(`✓ Project templates initialized`));
|
|
939
|
+
} catch (error) {
|
|
940
|
+
console.error(chalk.red(`✗ Failed to initialize project templates: ${error instanceof Error ? error.message : String(error)}`));
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
console.log(chalk.dim(`⏭ Project templates already exist (preserved)`));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (options.copyProjectTemplates) {
|
|
948
|
+
const settingsLocalPath = path.join(claudeDir, "settings.local.json");
|
|
949
|
+
if (!await exists(settingsLocalPath)) {
|
|
950
|
+
try {
|
|
951
|
+
const settingsContent = { hooks: { PostToolUse: [{
|
|
952
|
+
matcher: "Edit|Write|MultiEdit",
|
|
953
|
+
hooks: [{
|
|
954
|
+
type: "command",
|
|
955
|
+
command: "pnpm check 2>&1 | head -60"
|
|
956
|
+
}]
|
|
957
|
+
}] } };
|
|
958
|
+
await writeFile(settingsLocalPath, `${JSON.stringify(settingsContent, null, 2)}\n`);
|
|
959
|
+
console.log(chalk.green(`✓ .claude/settings.local.json created`));
|
|
960
|
+
} catch (error) {
|
|
961
|
+
console.error(chalk.red(`✗ Failed to create settings.local.json: ${error instanceof Error ? error.message : String(error)}`));
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
console.log(chalk.dim(`⏭ .claude/settings.local.json already exists (preserved)`));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (await exists(sourceClaudeMd)) {
|
|
968
|
+
try {
|
|
969
|
+
const targetClaudeMd = path.join(claudeDir, "CLAUDE.md");
|
|
970
|
+
const rawContent = await readFile(sourceClaudeMd, "utf-8");
|
|
971
|
+
const sourceContent = options.isGlobal ? rawContent.replaceAll(".claude/skills/sonamu/", "~/.claude/skills/sonamu/") : rawContent;
|
|
972
|
+
if (await exists(targetClaudeMd)) {
|
|
973
|
+
const targetContent = await readFile(targetClaudeMd, "utf-8");
|
|
974
|
+
const startMarker = "<!-- SONAMU:START -->";
|
|
975
|
+
const endMarker = "<!-- SONAMU:END -->";
|
|
976
|
+
if (targetContent.includes(startMarker) && targetContent.includes(endMarker)) {
|
|
977
|
+
const startIdx = targetContent.indexOf(startMarker);
|
|
978
|
+
const endIdx = targetContent.indexOf(endMarker);
|
|
979
|
+
if (startIdx !== -1 && endIdx !== -1 && startIdx < endIdx) {
|
|
980
|
+
const before = targetContent.substring(0, startIdx);
|
|
981
|
+
const after = targetContent.substring(endIdx + endMarker.length);
|
|
982
|
+
const newContent = `${before}${startMarker}\n${sourceContent}\n${endMarker}${after}`;
|
|
983
|
+
await writeFile(targetClaudeMd, newContent);
|
|
984
|
+
console.log(chalk.green(`✓ CLAUDE.md updated (marker region)`));
|
|
985
|
+
} else {
|
|
986
|
+
console.log(chalk.yellow(`⏭ CLAUDE.md marker positions invalid, skipped`));
|
|
987
|
+
}
|
|
988
|
+
} else {
|
|
989
|
+
const appended = `${targetContent.trimEnd()}\n\n<!-- SONAMU:START -->\n${sourceContent}\n<!-- SONAMU:END -->\n`;
|
|
990
|
+
await writeFile(targetClaudeMd, appended);
|
|
991
|
+
console.log(chalk.green(`✓ CLAUDE.md updated (appended Sonamu section)`));
|
|
992
|
+
}
|
|
993
|
+
} else {
|
|
994
|
+
const withMarkers = `<!-- SONAMU:START -->\n${sourceContent}\n<!-- SONAMU:END -->\n`;
|
|
995
|
+
await writeFile(targetClaudeMd, withMarkers);
|
|
996
|
+
console.log(chalk.green(`✓ CLAUDE.md created`));
|
|
997
|
+
}
|
|
998
|
+
} catch (error) {
|
|
999
|
+
console.error(chalk.red(`✗ Failed to update CLAUDE.md: ${error instanceof Error ? error.message : String(error)}`));
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1124
1002
|
}
|
|
1125
1003
|
async function skillsCopy(src, dest) {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
throw copyError;
|
|
1134
|
-
}
|
|
1004
|
+
try {
|
|
1005
|
+
await cp(src, dest, { recursive: true });
|
|
1006
|
+
console.log(chalk.green(`✓ Skills copied`));
|
|
1007
|
+
} catch (copyError) {
|
|
1008
|
+
console.error(chalk.red(`✗ Failed to copy skills: ${copyError instanceof Error ? copyError.message : String(copyError)}`));
|
|
1009
|
+
throw copyError;
|
|
1010
|
+
}
|
|
1135
1011
|
}
|
|
1136
1012
|
/**
|
|
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
|
-
if (sanitized !== name) {
|
|
1198
|
-
console.log(chalk.yellow(`⚠ Name sanitized: "${name}" → "${sanitized}"`));
|
|
1199
|
-
}
|
|
1200
|
-
const filePath = path.join(localDir, `${sanitized}.md`);
|
|
1201
|
-
if (await exists(filePath)) {
|
|
1202
|
-
console.log(chalk.yellow(`Skill "${sanitized}" already exists.`));
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1205
|
-
await mkdir(localDir, {
|
|
1206
|
-
recursive: true
|
|
1207
|
-
});
|
|
1208
|
-
const template = `---
|
|
1013
|
+
* pnpm sonamu skills create <name> 하면 실행되는 함수입니다.
|
|
1014
|
+
* 로컬 skill 초안을 생성합니다.
|
|
1015
|
+
*/
|
|
1016
|
+
async function skills_create(name) {
|
|
1017
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
1018
|
+
const localDir = path.join(workspaceRoot, ".claude", "skills", "local");
|
|
1019
|
+
if (!name || name.trim() === "") {
|
|
1020
|
+
console.error(chalk.red("✗ Skill name is required"));
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
let sanitized = name.replace(/\s+/g, "-").replace(/[/\\]/g, "-").replace(/\.\./g, "").replace(/[<>:"|?*]/g, "").replace(/^[.\-_]+|[.\-_]+$/g, "").replace(/-+/g, "-").replace(/[^a-zA-Z0-9-_가-힣]/g, "");
|
|
1024
|
+
const MAX_LENGTH = 100;
|
|
1025
|
+
if (sanitized.length > MAX_LENGTH) {
|
|
1026
|
+
sanitized = sanitized.substring(0, MAX_LENGTH);
|
|
1027
|
+
console.log(chalk.yellow(`⚠ Name truncated to ${MAX_LENGTH} characters`));
|
|
1028
|
+
}
|
|
1029
|
+
const RESERVED_NAMES = [
|
|
1030
|
+
"CON",
|
|
1031
|
+
"PRN",
|
|
1032
|
+
"AUX",
|
|
1033
|
+
"NUL",
|
|
1034
|
+
"COM1",
|
|
1035
|
+
"COM2",
|
|
1036
|
+
"COM3",
|
|
1037
|
+
"COM4",
|
|
1038
|
+
"COM5",
|
|
1039
|
+
"COM6",
|
|
1040
|
+
"COM7",
|
|
1041
|
+
"COM8",
|
|
1042
|
+
"COM9",
|
|
1043
|
+
"LPT1",
|
|
1044
|
+
"LPT2",
|
|
1045
|
+
"LPT3",
|
|
1046
|
+
"LPT4",
|
|
1047
|
+
"LPT5",
|
|
1048
|
+
"LPT6",
|
|
1049
|
+
"LPT7",
|
|
1050
|
+
"LPT8",
|
|
1051
|
+
"LPT9"
|
|
1052
|
+
];
|
|
1053
|
+
if (RESERVED_NAMES.includes(sanitized.toUpperCase())) {
|
|
1054
|
+
sanitized = `skill-${sanitized}`;
|
|
1055
|
+
console.log(chalk.yellow(`⚠ Reserved name detected, prefixed with "skill-"`));
|
|
1056
|
+
}
|
|
1057
|
+
if (sanitized === "") {
|
|
1058
|
+
console.error(chalk.red("✗ Invalid skill name after sanitization"));
|
|
1059
|
+
console.log(chalk.dim(` Original: "${name}"`));
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
if (sanitized !== name) {
|
|
1063
|
+
console.log(chalk.yellow(`⚠ Name sanitized: "${name}" → "${sanitized}"`));
|
|
1064
|
+
}
|
|
1065
|
+
const filePath = path.join(localDir, `${sanitized}.md`);
|
|
1066
|
+
if (await exists(filePath)) {
|
|
1067
|
+
console.log(chalk.yellow(`Skill "${sanitized}" already exists.`));
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
await mkdir(localDir, { recursive: true });
|
|
1071
|
+
const template = `---
|
|
1209
1072
|
name: ${sanitized}
|
|
1210
1073
|
category: other
|
|
1211
1074
|
created_at: ${new Date().toISOString().split("T")[0]}
|
|
@@ -1228,84 +1091,80 @@ status: draft
|
|
|
1228
1091
|
// 예시 코드
|
|
1229
1092
|
\`\`\`
|
|
1230
1093
|
`;
|
|
1231
|
-
|
|
1232
|
-
|
|
1094
|
+
await writeFile(filePath, template);
|
|
1095
|
+
console.log(chalk.green(`✓ Created .claude/skills/local/${sanitized}.md`));
|
|
1233
1096
|
}
|
|
1234
1097
|
/**
|
|
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
|
-
plugins
|
|
1264
|
-
});
|
|
1098
|
+
* pnpm sonamu auth generate 하면 실행되는 함수입니다.
|
|
1099
|
+
* better-auth 엔티티들(User, Session, Account, Verification)을 생성합니다.
|
|
1100
|
+
*
|
|
1101
|
+
* 옵션:
|
|
1102
|
+
* --plugins phone-number,2fa 플러그인 엔티티도 함께 생성
|
|
1103
|
+
*/
|
|
1104
|
+
async function auth_generate() {
|
|
1105
|
+
const pluginsArg = process.argv.find((arg) => arg.startsWith("--plugins"));
|
|
1106
|
+
const plugins = [];
|
|
1107
|
+
if (pluginsArg) {
|
|
1108
|
+
const pluginValue = pluginsArg.includes("=") ? pluginsArg.split("=")[1] : process.argv[process.argv.indexOf(pluginsArg) + 1];
|
|
1109
|
+
if (pluginValue) {
|
|
1110
|
+
const pluginIds = pluginValue.split(",").map((p) => p.trim());
|
|
1111
|
+
for (const id of pluginIds) {
|
|
1112
|
+
if (isValidPluginId(id)) {
|
|
1113
|
+
plugins.push(id);
|
|
1114
|
+
} else {
|
|
1115
|
+
console.log(chalk.yellow(`⚠ Unknown plugin: ${id}`));
|
|
1116
|
+
console.log(chalk.dim(` Supported plugins: ${SUPPORTED_PLUGIN_IDS.join(", ")}`));
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
console.log(chalk.yellow.bold("🔐 Generating better-auth entities...\n"));
|
|
1122
|
+
if (plugins.length > 0) {
|
|
1123
|
+
console.log(chalk.dim(` Plugins: ${plugins.join(", ")}`));
|
|
1124
|
+
}
|
|
1125
|
+
await generateBetterAuthEntities({ plugins });
|
|
1265
1126
|
}
|
|
1266
1127
|
/**
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1128
|
+
* pnpm sonamu auth add-companions 하면 실행되는 함수입니다.
|
|
1129
|
+
* 기존 프로젝트의 entity.json에 fixtureCompanions를 소급 추가합니다.
|
|
1130
|
+
*
|
|
1131
|
+
* 이미 fixtureCompanions가 있는 entity는 스킵합니다 (덮어쓰기 없음).
|
|
1132
|
+
*/
|
|
1133
|
+
async function auth_add_companions() {
|
|
1134
|
+
console.log(chalk.yellow.bold("🔐 Adding fixtureCompanions to better-auth entities...\n"));
|
|
1135
|
+
await addCompanionsToEntities();
|
|
1136
|
+
console.log(chalk.bold("\n✅ Done!"));
|
|
1275
1137
|
}
|
|
1276
1138
|
/**
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
}
|
|
1305
|
-
dir = path.dirname(dir);
|
|
1306
|
-
}
|
|
1307
|
-
// 찾지 못하면 api 폴더의 부모 사용
|
|
1308
|
-
return findAppRootPath();
|
|
1139
|
+
* 워크스페이스 루트를 찾습니다.
|
|
1140
|
+
* 우선순위: pnpm-workspace.yaml > package.json(workspaces) > .agents/
|
|
1141
|
+
*
|
|
1142
|
+
* CLAUDE.md는 서브패키지에도 존재할 수 있으므로 사용하지 않습니다.
|
|
1143
|
+
* .agents/는 agents init이 생성하는 디렉토리로, 워크스페이스 루트에만 존재합니다.
|
|
1144
|
+
*/
|
|
1145
|
+
async function findWorkspaceRoot() {
|
|
1146
|
+
let dir = process.cwd();
|
|
1147
|
+
while (dir !== path.dirname(dir)) {
|
|
1148
|
+
if (await exists(path.join(dir, "pnpm-workspace.yaml"))) {
|
|
1149
|
+
return dir;
|
|
1150
|
+
}
|
|
1151
|
+
const packagePath = path.join(dir, "package.json");
|
|
1152
|
+
if (await exists(packagePath)) {
|
|
1153
|
+
try {
|
|
1154
|
+
const packageJson = JSON.parse(await readFile(packagePath, "utf-8"));
|
|
1155
|
+
if (packageJson.workspaces) {
|
|
1156
|
+
return dir;
|
|
1157
|
+
}
|
|
1158
|
+
} catch {}
|
|
1159
|
+
}
|
|
1160
|
+
if (await exists(path.join(dir, ".agents"))) {
|
|
1161
|
+
return dir;
|
|
1162
|
+
}
|
|
1163
|
+
dir = path.dirname(dir);
|
|
1164
|
+
}
|
|
1165
|
+
return findAppRootPath();
|
|
1309
1166
|
}
|
|
1310
1167
|
|
|
1311
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9iaW4vY2xpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCBkb3RlbnYgZnJvbSBcImRvdGVudlwiO1xuXG5kb3RlbnYuY29uZmlnKCk7XG5cbmltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgZXhlY1N5bmMsIHNwYXduIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IGNwLCBta2RpciwgcmVhZGRpciwgcmVhZEZpbGUsIHJtLCBzeW1saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBrbmV4LCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm1vZHVsZVwiO1xuaW1wb3J0IG9zIGZyb20gXCJvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCBwcm9jZXNzIGZyb20gXCJwcm9jZXNzXCI7XG5pbXBvcnQgeyB0c2ljbGkgfSBmcm9tIFwidHNpY2xpXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpXCI7XG5pbXBvcnQgeyBhZGRDb21wYW5pb25zVG9FbnRpdGllcywgZ2VuZXJhdGVCZXR0ZXJBdXRoRW50aXRpZXMgfSBmcm9tIFwiLi4vYXV0aC9hdXRoLWdlbmVyYXRvclwiO1xuaW1wb3J0IHtcbiAgdHlwZSBCZXR0ZXJBdXRoUGx1Z2luSWQsXG4gIGlzVmFsaWRQbHVnaW5JZCxcbiAgU1VQUE9SVEVEX1BMVUdJTl9JRFMsXG59IGZyb20gXCIuLi9hdXRoL3BsdWdpbnMvZW50aXR5LWRlZmluaXRpb25zXCI7XG5pbXBvcnQgdHlwZSB7IFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgTWlncmF0b3IgfSBmcm9tIFwiLi4vbWlncmF0aW9uL21pZ3JhdG9yXCI7XG5pbXBvcnQgeyBGaXh0dXJlTWFuYWdlciB9IGZyb20gXCIuLi90ZXN0aW5nL2ZpeHR1cmUtbWFuYWdlclwiO1xuaW1wb3J0IHtcbiAgZXhlY1dpdGhMaW5lUHJlZml4LFxuICBwcmludEJ1aWxkU3VtbWFyeSxcbiAgcHJpbnRUYXNrRmFpbGVkLFxuICBwcmludFRhc2tIZWFkZXIsXG4gIHByaW50VGFza1N0YXJ0LFxuICBwcmludFRhc2tTdWNjZXNzLFxufSBmcm9tIFwiLi4vdXRpbHMvY29uc29sZS11dGlsXCI7XG5pbXBvcnQgeyBleGlzdHMgfSBmcm9tIFwiLi4vdXRpbHMvZnMtdXRpbHNcIjtcbmltcG9ydCB7IGZpbmRBcGlSb290UGF0aCwgZmluZEFwcFJvb3RQYXRoIH0gZnJvbSBcIi4uL3V0aWxzL3V0aWxzXCI7XG5pbXBvcnQgeyBBUElfQVJUSUZBQ1RTLCB0eXBlIEJ1aWxkQXJ0aWZhY3QsIFdFQl9BUlRJRkFDVFMgfSBmcm9tIFwiLi9idWlsZC1jb25maWdcIjtcbmltcG9ydCB7IGZpeHR1cmVFeHBsb3JlQ29tbWFuZCwgZml4dHVyZUZldGNoQ29tbWFuZCwgZml4dHVyZUdlbkNvbW1hbmQgfSBmcm9tIFwiLi9maXh0dXJlXCI7XG5pbXBvcnQgeyB0ZXN0Q29tbWFuZCB9IGZyb20gXCIuL3Rlc3QtY29tbWFuZFwiO1xuXG5sZXQgbWlncmF0b3I6IE1pZ3JhdG9yO1xuXG4vKipcbiAqIENMSSDsmLXshZjsnYQg7YyM7Iux7ZWY64qUIO2XrO2NvCDtlajsiJhcbiAqL1xuZnVuY3Rpb24gcGFyc2VDbGlPcHRpb25zKGFyZ3Y6IHN0cmluZ1tdID0gcHJvY2Vzcy5hcmd2KToge1xuICBmbGFnczogU2V0PHN0cmluZz47IC8vIC0tcmVnZW5lcmF0ZSwgLS1haSwgLS1uby1jb25lcyDrk7FcbiAgb3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPjsgLy8gLS1sb2NhbGUga28g65OxXG59IHtcbiAgY29uc3QgZmxhZ3MgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3Qgb3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG4gICAgaWYgKCFhcmcuc3RhcnRzV2l0aChcIi0tXCIpKSBjb250aW51ZTtcblxuICAgIC8vIC0tb3B0aW9uPXZhbHVlIO2YleyLnVxuICAgIGlmIChhcmcuaW5jbHVkZXMoXCI9XCIpKSB7XG4gICAgICBjb25zdCBba2V5LCB2YWx1ZV0gPSBhcmcuc2xpY2UoMikuc3BsaXQoXCI9XCIpO1xuICAgICAgb3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICAvLyAtLW9wdGlvbiB2YWx1ZSDtmJXsi53snbjsp4Ag7ZmV7J24XG4gICAgY29uc3QgbmV4dEFyZyA9IGFyZ3ZbaSArIDFdO1xuICAgIGlmIChuZXh0QXJnICYmICFuZXh0QXJnLnN0YXJ0c1dpdGgoXCItLVwiKSAmJiAhbmV4dEFyZy5zdGFydHNXaXRoKFwiLVwiKSkge1xuICAgICAgb3B0aW9uc1thcmcuc2xpY2UoMildID0gbmV4dEFyZztcbiAgICAgIGkrKzsgLy8g64uk7J2MIGFyZ+uKlCDqsJLsnbTrr4DroZwg7Iqk7YK1XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIC0tZmxhZyDtmJXsi51cbiAgICAgIGZsYWdzLmFkZChhcmcuc2xpY2UoMikpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGZsYWdzLCBvcHRpb25zIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGJvb3RzdHJhcCgpIHtcbiAgY29uc3Qgbm90VG9Jbml0ID0gW1wiZGV2XCIsIFwiYnVpbGRcIiwgXCJzdGFydFwiLCBcInNraWxsc1wiLCBcInRlc3RcIl0uaW5jbHVkZXMocHJvY2Vzcy5hcmd2WzJdID8/IFwiXCIpO1xuICBpZiAoIW5vdFRvSW5pdCkge1xuICAgIGF3YWl0IFNvbmFtdS5pbml0KGZhbHNlLCBmYWxzZSk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIHRzaWNsaeuKlCDsoJXtmZXtlZwg66qF66C57Ja0IOunpOy5reunjCDsp4Dsm5DtlZjrr4DroZwsIC0t66GcIOyLnOyeke2VmOuKlCDsmLXshZjqs7wg6re4IOqwkuydhCDtlYTthLDrp4Htlanri4jri6QuXG4gICAgLy8g7Ji17IWYIO2MjOyLseydgCDqsIEgcnVubmVyIO2VqOyImOyXkOyEnCDsm5Drs7ggcHJvY2Vzcy5hcmd266W8IOyCrOyaqe2VmOyXrCDsiJjtlontlanri4jri6QuXG4gICAgLy8gXCItLVwiKGJhcmUgZG91YmxlIGRhc2gp64qUIHBhc3N0aHJvdWdoIOq1rOu2hOyekOydtOuvgOuhnCwg6re4IOuSpOydmCDrqqjrk6Ag7J247J6Q64+EIOygnOyZuO2VqeuLiOuLpC5cbiAgICBjb25zdCBmaWx0ZXJlZEFyZ3Y6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHNraXBOZXh0ID0gZmFsc2U7XG4gICAgbGV0IGFmdGVyRG91YmxlRGFzaCA9IGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcHJvY2Vzcy5hcmd2Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBhcmcgPSBwcm9jZXNzLmFyZ3ZbaV07XG4gICAgICBpZiAoYXJnID09PSBcIi0tXCIpIHtcbiAgICAgICAgYWZ0ZXJEb3VibGVEYXNoID0gdHJ1ZTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoYWZ0ZXJEb3VibGVEYXNoKSBjb250aW51ZTtcbiAgICAgIGlmIChza2lwTmV4dCkge1xuICAgICAgICBza2lwTmV4dCA9IGZhbHNlO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmIChhcmcuc3RhcnRzV2l0aChcIi0tXCIpKSB7XG4gICAgICAgIC8vIC0tb3B0aW9uPXZhbHVlIO2YleyLneydgCDsnbQgYXJn66eMIOyKpO2CtVxuICAgICAgICBpZiAoYXJnLmluY2x1ZGVzKFwiPVwiKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIC8vIC0tb3B0aW9uIHZhbHVlIO2YleyLneyduOyngCDtmZXsnbg6IOuLpOydjCBhcmfqsIAgLS3roZwg7Iuc7J6R7ZWY7KeAIOyViuycvOuptCDqsJLsnbQg7J6I64qUIOqyg1xuICAgICAgICBjb25zdCBuZXh0QXJnID0gcHJvY2Vzcy5hcmd2W2kgKyAxXTtcbiAgICAgICAgaWYgKG5leHRBcmcgJiYgIW5leHRBcmcuc3RhcnRzV2l0aChcIi0tXCIpICYmICFuZXh0QXJnLnN0YXJ0c1dpdGgoXCItXCIpKSB7XG4gICAgICAgICAgc2tpcE5leHQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgZmlsdGVyZWRBcmd2LnB1c2goYXJnKTtcbiAgICB9XG5cbiAgICAvLyBidWlsZC9kZXYg66qF66C57Ja06rCAIOyEnOu4jOy7pOunqOuTnCDsl4bsnbQg7Zi47Lac65CgIOuVjCBcImFsbFwi7J2EIOq4sOuzuOqwkuycvOuhnCDstpTqsIDtlanri4jri6QuXG4gICAgLy8g7JiIOiBgc29uYW11IGJ1aWxkYCDihpIgYHNvbmFtdSBidWlsZCBhbGxgLCBgc29uYW11IGRldmAg4oaSIGBzb25hbXUgZGV2IGFsbGBcbiAgICBjb25zdCBjbWQgPSBmaWx0ZXJlZEFyZ3ZbMl07XG4gICAgaWYgKChjbWQgPT09IFwiYnVpbGRcIiB8fCBjbWQgPT09IFwiZGV2XCIpICYmIGZpbHRlcmVkQXJndi5sZW5ndGggPT09IDMpIHtcbiAgICAgIGZpbHRlcmVkQXJndi5wdXNoKFwiYWxsXCIpO1xuICAgIH1cblxuICAgIC8vIHRlc3Qg7Luk66eo65Oc64qUIOqwgOuzgCDsnbjsnpAo7YyM7J2866qFLCAtLXBhdHRlcm4g65OxKeulvCDrsJvsnLzrr4DroZwgdHNpY2xp66W8IOyasO2ajO2VqeuLiOuLpC5cbiAgICBpZiAoY21kID09PSBcInRlc3RcIikge1xuICAgICAgcmV0dXJuIHRlc3RDb21tYW5kKCk7XG4gICAgfVxuXG4gICAgYXdhaXQgdHNpY2xpKGZpbHRlcmVkQXJndiwge1xuICAgICAgdHlwZXM6IHtcbiAgICAgICAgXCIjZW50aXR5SWRcIjoge1xuICAgICAgICAgIHR5cGU6IFwiYXV0b2NvbXBsZXRlXCIsXG4gICAgICAgICAgbmFtZTogXCIjZW50aXR5SWRcIixcbiAgICAgICAgICBtZXNzYWdlOiBcIlBsZWFzZSBpbnB1dCAjZW50aXR5SWRcIixcbiAgICAgICAgICBjaG9pY2VzOiBFbnRpdHlNYW5hZ2VyLmdldEFsbFBhcmVudElkcygpLm1hcCgoZW50aXR5SWQpID0+ICh7XG4gICAgICAgICAgICB0aXRsZTogZW50aXR5SWQsXG4gICAgICAgICAgICB2YWx1ZTogZW50aXR5SWQsXG4gICAgICAgICAgfSkpLFxuICAgICAgICB9LFxuICAgICAgICBcIiNyZWNvcmRJZHNcIjogXCJudW1iZXJbXVwiLFxuICAgICAgICBcIiNuYW1lXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiI3RhcmdldHNcIjoge1xuICAgICAgICAgIHR5cGU6IFwibXVsdGlzZWxlY3RcIixcbiAgICAgICAgICBuYW1lOiBcIiN0YXJnZXRzXCIsXG4gICAgICAgICAgbWVzc2FnZTogXCJQbGVhc2UgaW5wdXQgI3RhcmdldHNcIixcbiAgICAgICAgICBjaG9pY2VzOiBbXG4gICAgICAgICAgICB7IHRpdGxlOiBcIkRldmVsb3BtZW50XCIsIHZhbHVlOiBcImRldmVsb3BtZW50X21hc3RlclwiIH0sXG4gICAgICAgICAgICB7IHRpdGxlOiBcIlByb2R1Y3Rpb25cIiwgdmFsdWU6IFwicHJvZHVjdGlvbl9tYXN0ZXJcIiB9LFxuICAgICAgICAgICAgeyB0aXRsZTogXCJGaXh0dXJlXCIsIHZhbHVlOiBcImZpeHR1cmVcIiB9LFxuICAgICAgICAgICAgeyB0aXRsZTogXCJUZXN0XCIsIHZhbHVlOiBcInRlc3RcIiB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgYXJnczogW1xuICAgICAgICBbXCJmaXh0dXJlXCIsIFwiaW5pdFwiXSxcbiAgICAgICAgW1wiZml4dHVyZVwiLCBcImltcG9ydFwiLCBcIiNlbnRpdHlJZFwiLCBcIiNyZWNvcmRJZHNcIl0sXG4gICAgICAgIFtcImZpeHR1cmVcIiwgXCJzeW5jXCJdLFxuICAgICAgICBbXCJmaXh0dXJlXCIsIFwiZ2VuXCJdLFxuICAgICAgICBbXCJmaXh0dXJlXCIsIFwiZmV0Y2hcIl0sXG4gICAgICAgIFtcImZpeHR1cmVcIiwgXCJleHBsb3JlXCJdLFxuICAgICAgICBbXCJtaWdyYXRlXCIsIFwicnVuXCJdLFxuICAgICAgICBbXCJtaWdyYXRlXCIsIFwiYXBwbHlcIiwgXCIjdGFyZ2V0c1wiXSxcbiAgICAgICAgW1wibWlncmF0ZVwiLCBcImdlbmVyYXRlXCJdLFxuICAgICAgICBbXCJtaWdyYXRlXCIsIFwic3RhdHVzXCJdLFxuICAgICAgICBbXCJzdHViXCIsIFwicHJhY3RpY2VcIiwgXCIjbmFtZVwiXSxcbiAgICAgICAgW1wic3R1YlwiLCBcImVudGl0eVwiLCBcIiNuYW1lXCJdLFxuICAgICAgICBbXCJzY2FmZm9sZFwiLCBcIm1vZGVsXCIsIFwiI2VudGl0eUlkXCJdLFxuICAgICAgICBbXCJzY2FmZm9sZFwiLCBcIm1vZGVsX3Rlc3RcIiwgXCIjZW50aXR5SWRcIl0sXG4gICAgICAgIFtcInNjYWZmb2xkXCIsIFwidmlld19saXN0XCIsIFwiI2VudGl0eUlkXCJdLFxuICAgICAgICBbXCJzY2FmZm9sZFwiLCBcInZpZXdfZm9ybVwiLCBcIiNlbnRpdHlJZFwiXSxcbiAgICAgICAgW1wiY29uZVwiLCBcImdlblwiLCBcIiNlbnRpdHlJZFwiXSxcbiAgICAgICAgW1wic3luY1wiXSxcbiAgICAgICAgW1wiYnVpbGRcIiwgXCJhbGxcIl0sXG4gICAgICAgIFtcImJ1aWxkXCIsIFwiYXBpXCJdLFxuICAgICAgICBbXCJidWlsZFwiLCBcIndlYlwiXSxcbiAgICAgICAgW1wiZGV2XCIsIFwiYWxsXCJdLFxuICAgICAgICBbXCJkZXZcIiwgXCJhcGlcIl0sXG4gICAgICAgIFtcImRldlwiLCBcIndlYlwiXSxcbiAgICAgICAgW1wic3RhcnRcIl0sXG4gICAgICAgIFtcInNraWxsc1wiLCBcInN5bmNcIl0sXG4gICAgICAgIFtcInNraWxsc1wiLCBcImNyZWF0ZVwiLCBcIiNuYW1lXCJdLFxuICAgICAgICBbXCJ0ZXN0XCJdLFxuICAgICAgICBbXCJhdXRoXCIsIFwiZ2VuZXJhdGVcIl0sXG4gICAgICAgIFtcImF1dGhcIiwgXCJhZGQtY29tcGFuaW9uc1wiXSxcbiAgICAgIF0sXG4gICAgICBydW5uZXJzOiB7XG4gICAgICAgIG1pZ3JhdGVfc3RhdHVzLFxuICAgICAgICBtaWdyYXRlX3J1bixcbiAgICAgICAgbWlncmF0ZV9hcHBseSxcbiAgICAgICAgbWlncmF0ZV9nZW5lcmF0ZSxcbiAgICAgICAgZml4dHVyZV9pbml0LFxuICAgICAgICBmaXh0dXJlX2ltcG9ydCxcbiAgICAgICAgZml4dHVyZV9zeW5jLFxuICAgICAgICBmaXh0dXJlX2dlbixcbiAgICAgICAgZml4dHVyZV9mZXRjaCxcbiAgICAgICAgZml4dHVyZV9leHBsb3JlLFxuICAgICAgICBzdHViX3ByYWN0aWNlLFxuICAgICAgICBzdHViX2VudGl0eSxcbiAgICAgICAgc2NhZmZvbGRfbW9kZWwsXG4gICAgICAgIHNjYWZmb2xkX21vZGVsX3Rlc3QsXG4gICAgICAgIC8vIHNjYWZmb2xkX3ZpZXdfbGlzdCxcbiAgICAgICAgLy8gc2NhZmZvbGRfdmlld19mb3JtLFxuICAgICAgICBjb25lX2dlbixcbiAgICAgICAgc3luYyxcbiAgICAgICAgYnVpbGRfYWxsLFxuICAgICAgICBidWlsZF9hcGksXG4gICAgICAgIGJ1aWxkX3dlYixcbiAgICAgICAgZGV2X2FsbCxcbiAgICAgICAgZGV2X2FwaSxcbiAgICAgICAgZGV2X3dlYixcbiAgICAgICAgc3RhcnQsXG4gICAgICAgIHNraWxsc19zeW5jLFxuICAgICAgICBza2lsbHNfY3JlYXRlLFxuICAgICAgICB0ZXN0OiB0ZXN0Q29tbWFuZCxcbiAgICAgICAgYXV0aF9nZW5lcmF0ZSxcbiAgICAgICAgXCJhdXRoX2FkZC1jb21wYW5pb25zXCI6IGF1dGhfYWRkX2NvbXBhbmlvbnMsXG4gICAgICB9LFxuICAgIH0pO1xuICB9IGZpbmFsbHkge1xuICAgIGF3YWl0IFNvbmFtdS5kZXN0cm95KCk7XG4gIH1cbn1cblxuYm9vdHN0cmFwKCkuZmluYWxseShhc3luYyAoKSA9PiB7XG4gIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmRlc3Ryb3koKTtcbn0pO1xuXG4vKipcbiAqIHBucG0gc3luYyDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIO2UhOuhnOygne2KuOulvCDsi7Htgaztlanri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN5bmMoKSB7XG4gIGF3YWl0IFNvbmFtdS5zeW5jZXIuc3luYygpO1xufVxuXG4vKipcbiAqIEFQSSDqsJzrsJwg7ISc67KE66W8IOyLpO2Wie2VmOuKlCDqs7XthrUg66Gc7KeB7J6F64uI64ukLlxuICogZGV2X2FsbOqzvCBkZXZfYXBp7JeQ7IScIOqzteycoO2VqeuLiOuLpC5cbiAqXG4gKiBUeXBlU2NyaXB066W8IOuwlOuhnCDsi6TtlontlaAg7IiYIOyeiOuPhOuhnSBAc29uYW11LWtpdC90cy1sb2FkZXLrpbwsXG4gKiBITVLsnYQg7KeA7JuQ7ZWY6riwIOychO2VtCBAc29uYW11LWtpdC9obXItaG9va+ydhCBpbXBvcnTtlZjrqbAsXG4gKiDshozsiqTrp7Ug7KeA7JuQ7J2EIOychO2VtCAtLWVuYWJsZS1zb3VyY2UtbWFwcyDtlIzrnpjqt7jrpbwg7Y+s7ZWo7ZWY7JesIOyLpO2Wie2VqeuLiOuLpC5cbiAqXG4gKiDsnbTrlYwgQHNvbmFtdS1raXQvdHMtbG9hZGVy7JmAIEBzb25hbXUta2l0L2htci1ob29r64qUIHNvbmFtdeqwgCDsnpDssrTsoIHsnLzroZwg6rCA7KeA6rOgIOyeiOuKlCBkZXBlbmRlbmN57J6F64uI64ukLlxuICog65iQ7ZWcIOyLpO2WieyXkCDsgqzsmqntlZjripQgQHNvbmFtdS1raXQvaG1yLXJ1bm5lcuuPhCDrp4jssKzqsIDsp4DroZwgc29uYW116rCAIOyekOyytOyggeycvOuhnCDqsIDsp4Dqs6Ag7J6I64qUIGRlcGVuZGVuY3nsnoXri4jri6QuXG4gKiDrlLDrnbzshJwg7IKs7Jqp7J6QIO2UhOuhnOygne2KuOyXkOyEnOuKlCDsnbQg7IS4IO2MqO2CpOyngOulvCDsp4HsoJEg7ISk7LmY7ZWgIO2VhOyalOqwgCDsl4bsirXri4jri6QuXG4gKi9cbmZ1bmN0aW9uIHNwYXduQXBpRGV2U2VydmVyKG9wdGlvbnM/OiB7IGV4dHJhRW52PzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB9KSB7XG4gIGNvbnN0IGFwaVJvb3QgPSBmaW5kQXBpUm9vdFBhdGgoKTtcbiAgY29uc3QgZW50cnlQb2ludCA9IFwic3JjL2luZGV4LnRzXCI7XG5cbiAgLy8g7J20IHNvbmFtdSDtjKjtgqTsp4DqsIAgZGVwZW5kZW5jaWVz66GcIOqwgOyngOqzoCDsnojripQgQHNvbmFtdS1raXQvaG1yLXJ1bm5lcuydmCBiaW4vcnVuLmpz66W8IOyCrOyaqe2VqeuLiOuLpC5cbiAgLy8g7J20IOqyveuhnCgvYmluL3J1bi5qcynripQgQHNvbmFtdS1raXQvaG1yLXJ1bm5lcuydmCBwYWNrYWdlLmpzb27snZggYmluIO2VhOuTnOyXkCDrqoXsi5zrkJjslrQg7J6I64qUIOq3uOqyg+qzvCDqsJnsirXri4jri6QuXG4gIGNvbnN0IGhvdFJ1bm5lckJpblBhdGggPSBjcmVhdGVSZXF1aXJlKGltcG9ydC5tZXRhLnVybCkucmVzb2x2ZShcbiAgICBcIkBzb25hbXUta2l0L2htci1ydW5uZXIvYmluL3J1bi5qc1wiLFxuICApO1xuXG4gIGNvbnN0IHNlcnZlclByb2Nlc3MgPSBzcGF3bihcbiAgICBwcm9jZXNzLmV4ZWNQYXRoLCAvLyBub2RlXG4gICAgW1xuICAgICAgaG90UnVubmVyQmluUGF0aCwgLy8g7J2066CH6rKMIO2VtOyEnCBob3QtcnVubmVy66W8IOyLpO2Wie2VmOq1rOyalFxuICAgICAgXCItLWNsZWFyLXNjcmVlbj1mYWxzZVwiLCAvLyDsnbTtlZggaG90LXJ1bm5lcuyXkOqyjCDrhJjqsqjspIQg7J247J6Q65Ok7J6F64uI64ukLlxuICAgICAgXCItLW5vZGUtYXJncz0tLWltcG9ydD1zb25hbXUvdHMtbG9hZGVyLXJlZ2lzdGVyXCIsIC8vIFR5cGVTY3JpcHQg7ISc7Y+s7Yq466W8IOychO2VnCDroZzrjZQsXG4gICAgICBcIi0tbm9kZS1hcmdzPS0taW1wb3J0PXNvbmFtdS9obXItaG9vay1yZWdpc3RlclwiLCAvLyBITVLsnYQg7KeA7JuQ7ZWY6riwIOychO2VnCBob29rLFxuICAgICAgXCItLW5vZGUtYXJncz0tLWVuYWJsZS1zb3VyY2UtbWFwc1wiLCAvLyDqt7jrpqzqs6Ag7IaM7Iqk66e1IOyngOybkOydhCDsnITtlZwg7ZSM656Y6re47J6F64uI64ukLlxuICAgICAgXCItLW9uLWtleT1yOnJlc3RhcnQ6UmVzdGFydCBzZXJ2ZXJcIiwgLy8gciDriITrpbTrqbQg7ISc67KEIOyerOyLnOyeke2VmOqyjCDtlbTspJjsmpQuXG4gICAgICBcIi0tb24ta2V5PWM6Y2xlYXI6Q2xlYXIgc2NyZWVuXCIsIC8vIGMg64iE66W066m0IO2EsOuvuOuEkCDtmZTrqbTsnYQg7KeA7JuM7KSY7JqULlxuICAgICAgYC0tb24ta2V5PWY6c2hlbGwocm0gJHtwYXRoLmpvaW4oYXBpUm9vdCwgXCJzb25hbXUubG9ja1wiKX0pOnJlc3RhcnQ6Rm9yY2UgcmVzdGFydGAsIC8vIGYg64iE66W066m0IHNvbmFtdS5sb2NrIO2MjOydvOydhCDsp4DsmrDqs6Ag7ISc67KEIOyerOyLnOyeke2VmOqyjCDtlbTspJjsmpQuXG5cbiAgICAgIFwiLS1vbi1rZXk9ZW50ZXI6c2hlbGwoZWNobyBoaSk6S2V5IGJpbmRpbmcgdGVzdFwiLCAvLyBlbnRlcuulvCBrZXnroZwg7JO4IOyImCDsnojsnYzsnYQg67O07J206riwIOychO2VnCDthYzsiqTtirjsnoXri4jri6QuXG4gICAgICBcIi0tb24ta2V5PWN0cmwrZiBjdHJsK2Y6c2hlbGwoZ2l0IHB1bGwgJiYgcG5wbSBpbnN0YWxsICYmIHBucG0gLS1maWx0ZXIgc29uYW11IGJ1aWxkICYmIGVjaG8gJ1NvbmFtdSBpcyBub3cgdXAtdG8tZGF0ZSEnKTpyZXN0YXJ0OlB1bGwgJiBpbnN0YWxsICYgYnVpbGQgJiByZXN0YXJ0XCIsIC8vIG1vZGlmaWVy7JmA7J2YIOyhsO2VqSwg6re466as6rOgIOuRkCDqsJzsnZggY2hvcmTrpbwg7IKs7Jqp7ZWgIOyImCDsnojsnYzsnYQg67O07J206riwIOychO2VnCDthYzsiqTtirjsnoXri4jri6QuXG4gICAgICBlbnRyeVBvaW50LCAvLyDrp4jsp4Drp4nsnLzroZwg7Iuk7KCcIOyLpO2Wie2VoCDsiqTtgazrpr3tirjsnZgg6rK966Gc66W8IOuEmOqyqOykjeuLiOuLpC5cbiAgICBdLFxuICAgIHtcbiAgICAgIGN3ZDogYXBpUm9vdCxcbiAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgIGVudjoge1xuICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgTk9ERV9FTlY6IFwiZGV2ZWxvcG1lbnRcIixcbiAgICAgICAgSE9UOiBcInllc1wiLCAvLyDslpjqsIAg7J6I7Ja07JW8IEhNUuydtCDtmZzshLHtmZTrkKnri4jri6QuXG4gICAgICAgIEFQSV9ST09UX1BBVEg6IGFwaVJvb3QsIC8vIOydtCDqsr3roZzqsIAgaG1yLWhvb2vsnZgg66Oo7Yq4IOuUlOugie2GoOumrOqwgCDrkKnri4jri6QuXG4gICAgICAgIC4uLm9wdGlvbnM/LmV4dHJhRW52LFxuICAgICAgfSxcbiAgICB9LFxuICApO1xuXG4gIC8vIOyiheujjCDsspjrpqxcbiAgY29uc3QgY2xlYW51cCA9ICgpID0+IHtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coXCJcXG5cXG7wn5GLIFNodXR0aW5nIGRvd24uLi5cIikpO1xuICAgIHNlcnZlclByb2Nlc3Mua2lsbChcIlNJR1RFUk1cIik7XG4gICAgcHJvY2Vzcy5leGl0KDApO1xuICB9O1xuXG4gIHByb2Nlc3Mub24oXCJTSUdJTlRcIiwgY2xlYW51cCk7XG4gIHByb2Nlc3Mub24oXCJTSUdURVJNXCIsIGNsZWFudXApO1xuXG4gIHNlcnZlclByb2Nlc3Mub24oXCJleGl0XCIsIChjb2RlKSA9PiB7XG4gICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoY2hhbGsucmVkKGBTZXJ2ZXIgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9YCkpO1xuICAgICAgcHJvY2Vzcy5leGl0KGNvZGUgfHwgMSk7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIGRldiAvIHBucG0gZGV2IGFsbCDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIO2UhOuhnOygne2KuOyXkCDrjIDtlbQgSE1SIOyngOybkO2VmOuKlCDqsJzrsJwg7ISc67KE66W8IOudhOybjOykjeuLiOuLpC5cbiAqXG4gKiBTb25hbXUuaW5pdCDsl4bsnbQg7Zi47Lac65CgIOqyg+ydhCDsg4HsoJXtlZjsl6wg6rWs7ZiE65CY7JeI7Iq164uI64ukLlxuICovXG5mdW5jdGlvbiBkZXZfYWxsKCkge1xuICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3cuYm9sZChcIlN0YXJ0aW5nIFNvbmFtdSBkZXYgc2VydmVyLi4uXFxuXCIpKTtcbiAgc3Bhd25BcGlEZXZTZXJ2ZXIoKTtcbn1cblxuLyoqXG4gKiBwbnBtIGRldiBhcGkg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiBBUEkg7KCE7JqpIOqwnOuwnCDshJzrsoTrpbwg652E7JuB64uI64ukLlxuICogZGV2X2FsbOqzvCDqsbDsnZgg64+Z7J287ZWY65CYLCDthrXtlakg7Ju5IOyEnOuyhOulvCDruYTtmZzshLHtmZTtlanri4jri6QuXG4gKlxuICogU29uYW11LmluaXQg7JeG7J20IO2YuOy2nOuQoCDqsoPsnYQg7IOB7KCV7ZWY7JesIOq1rO2YhOuQmOyXiOyKteuLiOuLpC5cbiAqL1xuZnVuY3Rpb24gZGV2X2FwaSgpIHtcbiAgY29uc29sZS5sb2coY2hhbGsueWVsbG93LmJvbGQoXCJTdGFydGluZyBTb25hbXUgQVBJLW9ubHkgZGV2IHNlcnZlci4uLlxcblwiKSk7XG4gIHNwYXduQXBpRGV2U2VydmVyKHtcbiAgICBleHRyYUVudjogeyBTT05BTVVfRElTQUJMRV9JTlRFR1JBVEVEX1dFQjogXCJ5ZXNcIiB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIGRldiB3ZWIg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiBWaXRlIOqwnOuwnCDshJzrsoTrpbwg64uo64+F7Jy866GcIOyLpO2Wie2VqeuLiOuLpC5cbiAqIC0tIOuSpOydmCDsnbjsnpDripQgVml0ZeyXkCDqt7jrjIDroZwg7KCE64us65Cp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGRldl93ZWIoKSB7XG4gIGNvbnN0IGFwcFJvb3QgPSBmaW5kQXBwUm9vdFBhdGgoKTtcbiAgY29uc3Qgd2ViUGF0aCA9IHBhdGguam9pbihhcHBSb290LCBcIndlYlwiKTtcblxuICBpZiAoIShhd2FpdCBleGlzdHMod2ViUGF0aCkpKSB7XG4gICAgY29uc29sZS5lcnJvcihgd2ViIOuUlOugie2GoOumrOulvCDssL7snYQg7IiYIOyXhuyKteuLiOuLpDogJHt3ZWJQYXRofWApO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxuXG4gIC8vIC0tIOuSpOydmCDsnbjsnpAg7LaU7LacXG4gIGNvbnN0IGRvdWJsZURhc2hJbmRleCA9IHByb2Nlc3MuYXJndi5pbmRleE9mKFwiLS1cIik7XG4gIGNvbnN0IHBhc3N0aHJvdWdoQXJncyA9IGRvdWJsZURhc2hJbmRleCAhPT0gLTEgPyBwcm9jZXNzLmFyZ3Yuc2xpY2UoZG91YmxlRGFzaEluZGV4ICsgMSkgOiBbXTtcblxuICBjb25zdCB2aXRlQXJncyA9IFtcImV4ZWNcIiwgXCJ2aXRlXCIsIC4uLnBhc3N0aHJvdWdoQXJnc107XG5cbiAgY29uc29sZS5sb2coY2hhbGsueWVsbG93LmJvbGQoXCJTdGFydGluZyBWaXRlIGRldiBzZXJ2ZXIuLi5cXG5cIikpO1xuXG4gIGNvbnN0IHZpdGVQcm9jZXNzID0gc3Bhd24oXCJwbnBtXCIsIHZpdGVBcmdzLCB7XG4gICAgY3dkOiB3ZWJQYXRoLFxuICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgfSk7XG5cbiAgdml0ZVByb2Nlc3Mub24oXCJleGl0XCIsIChjb2RlKSA9PiB7XG4gICAgcHJvY2Vzcy5leGl0KGNvZGUgPz8gMCk7XG4gIH0pO1xuXG4gIC8vIFNJR0lOVC9TSUdURVJNIOyLnCBWaXRlIO2UhOuhnOyEuOyKpOulvCBncmFjZWZ1bGx5IOyiheujjO2VqeuLiOuLpC5cbiAgZm9yIChjb25zdCBzaWduYWwgb2YgW1wiU0lHSU5UXCIsIFwiU0lHVEVSTVwiXSBhcyBjb25zdCkge1xuICAgIHByb2Nlc3Mub24oc2lnbmFsLCAoKSA9PiB7XG4gICAgICB2aXRlUHJvY2Vzcy5raWxsKHNpZ25hbCk7XG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBTV0Mg7ISk7KCVIO2MjOydvCDqsr3roZzrpbwg6rKw7KCV7ZWp64uI64ukLiBBUEkg67mM65OcKFNXQynsl5DshJzrp4wg7IKs7Jqp65Cp64uI64ukLlxuICog7ZSE66Gc7KCd7Yq4IOujqO2KuOyXkCAuc3djcmPqsIAg7J6I7Jy866m0IOq3uOqyg+ydhCwg7JeG7Jy866m0IHNvbmFtdSDquLDrs7gg7ISk7KCV7J2EIOyCrOyaqe2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZVN3Y0NvbmZpZ1BhdGgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgbGV0IHN3Y0ZpbGVQYXRoID0gXCIuc3djcmNcIjtcbiAgdHJ5IHtcbiAgICBpZiAoYXdhaXQgZXhpc3RzKHN3Y0ZpbGVQYXRoKSkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZGltKFwiVXNpbmcgLnN3Y3JjIGZyb20gcHJvamVjdCByb290Li4uXCIpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZGltKFwiVXNpbmcgZGVmYXVsdCAuc3djcmMgZnJvbSBzb25hbXUgcGFja2FnZS4uLlwiKSk7XG4gICAgICBzd2NGaWxlUGF0aCA9IHBhdGguam9pbihpbXBvcnQubWV0YS5kaXJuYW1lLCBcIi4uXCIsIFwiLi5cIiwgXCIuc3djcmMucHJvamVjdC1kZWZhdWx0XCIpO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKGNoYWxrLnJlZChcIlNldHRpbmcgdXAgc3djIGNvbmZpZyBmaWxlIGZhaWxlZC5cIiksIGVycm9yKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbiAgcmV0dXJuIHN3Y0ZpbGVQYXRoO1xufVxuXG4vKipcbiAqIHNvbmFtdSBidWlsZCAvIHNvbmFtdSBidWlsZCBhbGwg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiBidWlsZF9hcGkgKyBidWlsZF93ZWLsnZgg7ZWp7ISx7J6F64uI64ukLiBXZWIg65SU66CJ7Yag66as6rCAIOyXhuycvOuptCBXZWIg67mM65Oc66W8IOyKpO2Cte2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYnVpbGRfYWxsKCkge1xuICBhd2FpdCBidWlsZF9hcGkoKTtcbiAgYXdhaXQgYnVpbGRfd2ViKHsgc2tpcElmTWlzc2luZzogdHJ1ZSB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIGJ1aWxkIGFwaSDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIEFQSSDtlITroZzsoJ3tirjrp4wg67mM65Oc7ZWp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkX2FwaSgpIHtcbiAgY29uc3QgYXBwUm9vdCA9IGZpbmRBcHBSb290UGF0aCgpO1xuICBjb25zdCBzd2NGaWxlUGF0aCA9IGF3YWl0IHJlc29sdmVTd2NDb25maWdQYXRoKCk7XG5cbiAgY29uc3QgYXBpU3RhcnRlZEF0ID0gRGF0ZS5ub3coKTtcbiAgdHJ5IHtcbiAgICBmb3IgKGNvbnN0IGFydGlmYWN0IG9mIEFQSV9BUlRJRkFDVFMpIHtcbiAgICAgIGNvbnN0IGN3ZCA9IHBhdGguam9pbihhcHBSb290LCBhcnRpZmFjdC5wcm9qZWN0UGF0aCk7XG4gICAgICBwcmludFRhc2tIZWFkZXIoYXJ0aWZhY3QubmFtZSwgYXJ0aWZhY3QuZGVzY3JpcHRpb24sIGN3ZCk7XG5cbiAgICAgIGF3YWl0IHJ1bkJ1aWxkU3RlcHMoYXJ0aWZhY3QsIHsgY3dkLCBidWlsZENvbW1hbmRBcmdzOiB7IGNvbmZpZ0ZpbGVQYXRoOiBzd2NGaWxlUGF0aCB9IH0pO1xuICAgIH1cbiAgICBwcmludEJ1aWxkU3VtbWFyeShcIkFQSVwiLCB0cnVlLCBEYXRlLm5vdygpIC0gYXBpU3RhcnRlZEF0KTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHByaW50QnVpbGRTdW1tYXJ5KFwiQVBJXCIsIGZhbHNlLCBEYXRlLm5vdygpIC0gYXBpU3RhcnRlZEF0KTtcbiAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG4vKipcbiAqIHBucG0gYnVpbGQgd2ViIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICogV2ViIO2UhOuhnOygne2KuOunjCDruYzrk5ztlanri4jri6QuXG4gKlxuICogU29uYW11LmluaXQg7JeG7J20IO2YuOy2nOuQoCDqsoPsnYQg7IOB7KCV7ZWY7JesIOq1rO2YhOuQmOyXiOyKteuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYnVpbGRfd2ViKHsgc2tpcElmTWlzc2luZyA9IGZhbHNlIH0gPSB7fSkge1xuICBjb25zdCBhcHBSb290ID0gZmluZEFwcFJvb3RQYXRoKCk7XG4gIGNvbnN0IHdlYlBhdGggPSBwYXRoLmpvaW4oYXBwUm9vdCwgXCJ3ZWJcIik7XG5cbiAgaWYgKCEoYXdhaXQgZXhpc3RzKHdlYlBhdGgpKSkge1xuICAgIGlmIChza2lwSWZNaXNzaW5nKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmF5KFwiV2ViIOuUlOugie2GoOumrOqwgCDsl4bsnLzrr4DroZwgV2ViIOu5jOuTnOulvCDqsbTrhIjrnIHri4jri6QuXCIpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc29sZS5lcnJvcihgd2ViIOuUlOugie2GoOumrOulvCDssL7snYQg7IiYIOyXhuyKteuLiOuLpDogJHt3ZWJQYXRofWApO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxuXG4gIGNvbnN0IHdlYlN0YXJ0ZWRBdCA9IERhdGUubm93KCk7XG4gIHRyeSB7XG4gICAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiBXRUJfQVJUSUZBQ1RTKSB7XG4gICAgICBjb25zdCBjd2QgPSBwYXRoLmpvaW4oYXBwUm9vdCwgYXJ0aWZhY3QucHJvamVjdFBhdGgpO1xuICAgICAgcHJpbnRUYXNrSGVhZGVyKGFydGlmYWN0Lm5hbWUsIGFydGlmYWN0LmRlc2NyaXB0aW9uLCBjd2QpO1xuXG4gICAgICBhd2FpdCBydW5CdWlsZFN0ZXBzKGFydGlmYWN0LCB7IGN3ZCwgYnVpbGRDb21tYW5kQXJnczoge30gfSk7XG4gICAgfVxuICAgIHByaW50QnVpbGRTdW1tYXJ5KFwiV2ViXCIsIHRydWUsIERhdGUubm93KCkgLSB3ZWJTdGFydGVkQXQpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgcHJpbnRCdWlsZFN1bW1hcnkoXCJXZWJcIiwgZmFsc2UsIERhdGUubm93KCkgLSB3ZWJTdGFydGVkQXQpO1xuICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgcHJvY2Vzcy5leGl0KDEpO1xuICB9XG59XG5cbi8qKlxuICogcHJlLWJ1aWxkLCBidWlsZCwgcG9zdC1idWlsZCDri6jqs4Trpbwg7Iic7LCo7KCB7Jy866GcIOyLpO2Wie2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcnVuQnVpbGRTdGVwczxUPihcbiAgYXJ0aWZhY3Q6IEJ1aWxkQXJ0aWZhY3Q8VD4sXG4gIG9wdGlvbnM6IHsgY3dkOiBzdHJpbmc7IGJ1aWxkQ29tbWFuZEFyZ3M6IFQgfSxcbikge1xuICBjb25zdCBzdGVwcyA9IFtcbiAgICB7IG5hbWU6IFwicHJlLWJ1aWxkXCIsIGNtZDogYXJ0aWZhY3QucHJlQnVpbGRDb21tYW5kPy4oKSB9LFxuICAgIHsgbmFtZTogXCJidWlsZFwiLCBjbWQ6IGFydGlmYWN0LmJ1aWxkQ29tbWFuZChvcHRpb25zLmJ1aWxkQ29tbWFuZEFyZ3MpIH0sXG4gICAgeyBuYW1lOiBcInBvc3QtYnVpbGRcIiwgY21kOiBhcnRpZmFjdC5wb3N0QnVpbGRDb21tYW5kPy4oKSB9LFxuICBdLmZpbHRlcigoc3RlcCkgPT4gc3RlcC5jbWQpO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc3RlcHMubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBzdGVwID0gc3RlcHNbaV07XG4gICAgY29uc3QgaXNMYXN0ID0gaSA9PT0gc3RlcHMubGVuZ3RoIC0gMTtcblxuICAgIHRyeSB7XG4gICAgICBhc3NlcnQoc3RlcC5jbWQpO1xuICAgICAgcHJpbnRUYXNrU3RhcnQoc3RlcC5uYW1lLCBzdGVwLmNtZCwgaXNMYXN0KTtcbiAgICAgIGF3YWl0IGV4ZWNXaXRoTGluZVByZWZpeChzdGVwLmNtZCwgeyBjd2Q6IG9wdGlvbnMuY3dkIH0pO1xuICAgICAgcHJpbnRUYXNrU3VjY2VzcyhzdGVwLm5hbWUsIGlzTGFzdCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcHJpbnRUYXNrRmFpbGVkKHN0ZXAubmFtZSwgaXNMYXN0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtzdGVwLm5hbWV9IGZhaWxlZGAsIHsgY2F1c2U6IGUgfSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogcG5wbSBzdGFydCDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIOu5jOuTnOuQnCDtlITroZzsoJ3tirjrpbwg7Iuk7ZaJ7ZWp64uI64ukLlxuICpcbiAqIOu5jOuTnOuQnCDqsrDqs7zrrLwoZGlzdCDrlJTroInthqDrpqzsnZggaW5kZXguanMg7JeU7Yq466as7Y+s7J247Yq4KeydtCDsl4bri6TrqbQg7Iuk7ZaJ7J2EIOykkeuLqO2VqeuLiOuLpC5cbiAqIOyGjOyKpOuntSDsp4Dsm5Dqs7wgZG90ZW52IOyngOybkOydhCDtj6ztlajtlZjsl6wg7Iuk7ZaJ7ZWp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN0YXJ0KCkge1xuICBjb25zdCBhcGlSb290ID0gZmluZEFwaVJvb3RQYXRoKCk7XG4gIGNvbnN0IGVudHJ5UG9pbnQgPSBcImRpc3QvaW5kZXguanNcIjtcblxuICBpZiAoIShhd2FpdCBleGlzdHMoZW50cnlQb2ludCkpKSB7XG4gICAgY29uc29sZS5sb2coY2hhbGsucmVkKGAke2VudHJ5UG9pbnR9IG5vdCBmb3VuZC4gUGxlYXNlIGJ1aWxkIHlvdXIgcHJvamVjdCBmaXJzdC5gKSk7XG4gICAgY29uc29sZS5sb2coY2hhbGsuYmx1ZShcIlJ1bjogcG5wbSBzb25hbXUgYnVpbGRcIikpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHsgc3Bhd24gfSA9IGF3YWl0IGltcG9ydChcImNoaWxkX3Byb2Nlc3NcIik7XG4gIGNvbnN0IHNlcnZlclByb2Nlc3MgPSBzcGF3bihcbiAgICBwcm9jZXNzLmV4ZWNQYXRoLFxuICAgIFtcIi0tZW5hYmxlLXNvdXJjZS1tYXBzXCIsIFwiLXJcIiwgXCJkb3RlbnYvY29uZmlnXCIsIGVudHJ5UG9pbnRdLFxuICAgIHtcbiAgICAgIGN3ZDogYXBpUm9vdCxcbiAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICB9LFxuICApO1xuXG4gIHByb2Nlc3Mub24oXCJTSUdJTlRcIiwgKCkgPT4ge1xuICAgIHNlcnZlclByb2Nlc3Mua2lsbChcIlNJR1RFUk1cIik7XG4gICAgcHJvY2Vzcy5leGl0KDApO1xuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc2V0dXBNaWdyYXRvcigpIHtcbiAgLy8gbWlncmF0b3JcbiAgbWlncmF0b3IgPSBuZXcgTWlncmF0b3IoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc2V0dXBGaXh0dXJlTWFuYWdlcigpIHtcbiAgRml4dHVyZU1hbmFnZXIuaW5pdCgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlX2FwcGx5KHRhcmdldHM6IChrZXlvZiBTb25hbXVEQkNvbmZpZylbXSkge1xuICBhd2FpdCBzZXR1cE1pZ3JhdG9yKCk7XG4gIGF3YWl0IG1pZ3JhdG9yLnJ1bkFjdGlvbihcImFwcGx5XCIsIHRhcmdldHMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlX3J1bigpIHtcbiAgYXdhaXQgc2V0dXBNaWdyYXRvcigpO1xuICBjb25zdCBsb2NhbEhvc3RzID0gW1wibG9jYWxob3N0XCIsIFwiMTI3LjAuMC4xXCIsIFwiMC4wLjAuMFwiLCBcIjo6MVwiXTtcbiAgY29uc3QgdGFyZ2V0cyA9IE9iamVjdC5rZXlzKFNvbmFtdS5kYkNvbmZpZykuZmlsdGVyKCh0YXJnZXQpID0+IHtcbiAgICBjb25zdCB0YXJnZXRDb25maWcgPSBTb25hbXUuZGJDb25maWdbdGFyZ2V0IGFzIGtleW9mIFNvbmFtdURCQ29uZmlnXTtcbiAgICBjb25zdCBob3N0ID0gKHRhcmdldENvbmZpZz8uY29ubmVjdGlvbiBhcyB7IGhvc3Q/OiBzdHJpbmcgfSk/Lmhvc3QgPz8gXCJsb2NhbGhvc3RcIjtcbiAgICByZXR1cm4gbG9jYWxIb3N0cy5pbmNsdWRlcyhob3N0LnRvTG93ZXJDYXNlKCkpO1xuICB9KTtcblxuICAvLyDroZzsu6wg642w7J207YSw67Kg7J207Iqk7JeQIOuMgO2VtOyEnOunjCDsoITssrQg66eI7J206re466CI7J207IWY7JeQ7IScIOuPmeyekVxuICBhd2FpdCBtaWdyYXRvci5ydW5BY3Rpb24oXCJhcHBseVwiLCB0YXJnZXRzIGFzIChrZXlvZiBTb25hbXVEQkNvbmZpZylbXSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1pZ3JhdGVfZ2VuZXJhdGUoKSB7XG4gIGF3YWl0IHNldHVwTWlncmF0b3IoKTtcblxuICBjb25zdCB7IGNvbm5zIH0gPSBhd2FpdCBtaWdyYXRvci5nZXRTdGF0dXMoKTtcbiAgY29uc3QgaGFzU3RhdHVzMCA9IGNvbm5zLnNvbWUoKGNvbm4pID0+IGNvbm4uc3RhdHVzID09PSAwKTtcbiAgaWYgKCFoYXNTdGF0dXMwKSB7XG4gICAgY29uc29sZS5sb2coXG4gICAgICBjaGFsay5yZWQoXG4gICAgICAgIFwi66eI7J206re466CI7J207IWYIO2MjOydvOydhCDsg53shLHtlZjroKTrqbQg6riw7KG0IOuniOydtOq3uOugiOydtOyFmOydtCDstZzshowg7ZWY64KY7J2YIERC7JeQIOuqqOuRkCDsoIHsmqnrkJjslrQg7J6I7Ja07JW8IO2VqeuLiOuLpC5cIixcbiAgICAgICksXG4gICAgKTtcbiAgICBmb3IgKGNvbnN0IGNvbm4gb2YgY29ubnMpIHtcbiAgICAgIGlmIChjb25uLnBlbmRpbmcubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYCAgJHtjb25uLm5hbWV9OiBwZW5kaW5nICR7Y29ubi5wZW5kaW5nLmxlbmd0aH3qsJxgKSk7XG4gICAgICB9XG4gICAgfVxuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxuXG4gIGNvbnN0IGNvdW50ID0gYXdhaXQgbWlncmF0b3IuZ2VuZXJhdGVQcmVwYXJlZENvZGVzKCk7XG4gIGlmIChjb3VudCA+IDApIHtcbiAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgJHtjb3VudH3qsJzsnZgg66eI7J206re466CI7J207IWYIO2MjOydvOydtCDsg53shLHrkJjsl4jsirXri4jri6QuYCkpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1pZ3JhdGVfc3RhdHVzKCkge1xuICBhd2FpdCBzZXR1cE1pZ3JhdG9yKCk7XG5cbiAgY29uc3Qgc3RhdHVzID0gYXdhaXQgbWlncmF0b3IuZ2V0U3RhdHVzKCk7XG4gIC8vIHN0YXR1cztcbiAgY29uc29sZS5sb2coc3RhdHVzKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZml4dHVyZV9pbml0KCkge1xuICBjb25zdCBzcmNDb25maWcgPSBTb25hbXUuZGJDb25maWcuZGV2ZWxvcG1lbnRfbWFzdGVyO1xuICBjb25zdCB0YXJnZXRzID0gW1xuICAgIHtcbiAgICAgIGxhYmVsOiBcIihSRU1PVEUpIEZpeHR1cmUgREJcIixcbiAgICAgIGNvbmZpZzogU29uYW11LmRiQ29uZmlnLmZpeHR1cmUsXG4gICAgfSxcbiAgICB7XG4gICAgICBsYWJlbDogXCIoTE9DQUwpIFRlc3RpbmcgREJcIixcbiAgICAgIGNvbmZpZzogU29uYW11LmRiQ29uZmlnLnRlc3QsXG4gICAgICB0b1NraXA6ICgoKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlbW90ZUNvbm4gPSBTb25hbXUuZGJDb25maWcuZml4dHVyZS5jb25uZWN0aW9uIGFzIEtuZXguQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgICAgY29uc3QgbG9jYWxDb25uID0gU29uYW11LmRiQ29uZmlnLnRlc3QuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWc7XG4gICAgICAgIHJldHVybiByZW1vdGVDb25uLmhvc3QgPT09IGxvY2FsQ29ubi5ob3N0ICYmIHJlbW90ZUNvbm4uZGF0YWJhc2UgPT09IGxvY2FsQ29ubi5kYXRhYmFzZTtcbiAgICAgIH0pKCksXG4gICAgfSxcbiAgXSBhcyB7XG4gICAgbGFiZWw6IHN0cmluZztcbiAgICBjb25maWc6IEtuZXguQ29uZmlnO1xuICAgIHRvU2tpcD86IGJvb2xlYW47XG4gIH1bXTtcblxuICAvLyAxLiDquLDspIBEQiDsiqTtgqTrp4jrpbwg642k7ZSEXG4gIGNvbnNvbGUubG9nKFwiRFVNUC4uLlwiKTtcbiAgY29uc3QgZHVtcEZpbGVuYW1lID0gYC90bXAvc29uYW11LWZpeHR1cmUtaW5pdC0ke0RhdGUubm93KCl9LnNxbGA7XG4gIGNvbnN0IHNyY0Nvbm4gPSBzcmNDb25maWcuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWc7XG4gIGNvbnN0IG1pZ3JhdGlvbnNEdW1wID0gYC90bXAvc29uYW11LWZpeHR1cmUtaW5pdC1taWdyYXRpb25zLSR7RGF0ZS5ub3coKX0uc3FsYDtcbiAgZXhlY1N5bmMoXG4gICAgYG15c3FsZHVtcCAtaCR7c3JjQ29ubi5ob3N0fSAtdSR7c3JjQ29ubi51c2VyfSAtcCR7c3JjQ29ubi5wYXNzd29yZH0gLS1zaW5nbGUtdHJhbnNhY3Rpb24gLWQgLS1uby1jcmVhdGUtZGIgLS10cmlnZ2VycyAke3NyY0Nvbm4uZGF0YWJhc2V9ID4gJHtkdW1wRmlsZW5hbWV9YCxcbiAgKTtcbiAgY29uc3QgX2RiID0ga25leChzcmNDb25maWcpO1xuICBjb25zdCBbW21pZ3JhdGlvbnNdXSA9IGF3YWl0IF9kYi5yYXcoXG4gICAgXCJTRUxFQ1QgQ09VTlQoKikgYXMgY291bnQgRlJPTSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIFdIRVJFIHRhYmxlX3NjaGVtYSA9ID8gQU5EIHRhYmxlX25hbWUgPSAna25leF9taWdyYXRpb25zJ1wiLFxuICAgIFtzcmNDb25uLmRhdGFiYXNlXSxcbiAgKTtcbiAgaWYgKG1pZ3JhdGlvbnMuY291bnQgPiAwKSB7XG4gICAgZXhlY1N5bmMoXG4gICAgICBgbXlzcWxkdW1wIC1oJHtzcmNDb25uLmhvc3R9IC11JHtzcmNDb25uLnVzZXJ9IC1wJHtzcmNDb25uLnBhc3N3b3JkfSAtLXNpbmdsZS10cmFuc2FjdGlvbiAtLW5vLWNyZWF0ZS1kYiAtLXRyaWdnZXJzICR7c3JjQ29ubi5kYXRhYmFzZX0ga25leF9taWdyYXRpb25zIGtuZXhfbWlncmF0aW9uc19sb2NrID4gJHttaWdyYXRpb25zRHVtcH1gLFxuICAgICk7XG4gIH1cblxuICAvLyAyLiDrjIDsg4FEQiDqsIHqsIHsl5Ag64yA7ZWY7JesIOyhtOyerOyXrOu2gCDtmZXsnbgg7ZuEIOu2k+q4sFxuICBmb3IgYXdhaXQgKGNvbnN0IHsgbGFiZWwsIGNvbmZpZywgdG9Ta2lwIH0gb2YgdGFyZ2V0cykge1xuICAgIGNvbnN0IGNvbm4gPSBjb25maWcuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWc7XG5cbiAgICBpZiAodG9Ta2lwID09PSB0cnVlKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5yZWQoYCR7bGFiZWx9OiBTa2lwcGVkIWApKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGRiID0ga25leCh7XG4gICAgICAuLi5jb25maWcsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLigoY29uZmlnLmNvbm5lY3Rpb24gPz8ge30pIGFzIEtuZXguQ29ubmVjdGlvbkNvbmZpZyksXG4gICAgICAgIGRhdGFiYXNlOiB1bmRlZmluZWQsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IFtbcm93XV0gPSBhd2FpdCBkYi5yYXcoYFNIT1cgREFUQUJBU0VTIExJS0UgXCIke2Nvbm4uZGF0YWJhc2V9XCJgKTtcbiAgICBpZiAocm93KSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYCR7bGFiZWx9OiBEYXRhYmFzZSBcIiR7Y29ubi5kYXRhYmFzZX1cIiBBbHJlYWR5IGV4aXN0c2ApKTtcbiAgICAgIGF3YWl0IGRiLmRlc3Ryb3koKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGBTWU5DIHRvICR7bGFiZWx9Li4uYCk7XG4gICAgY29uc3QgbXlzcWxDbWQgPSBgbXlzcWwgLWgke2Nvbm4uaG9zdH0gLXUke2Nvbm4udXNlcn0gLXAke2Nvbm4ucGFzc3dvcmR9YDtcbiAgICBleGVjU3luYyhgJHtteXNxbENtZH0gLWUgJ0RST1AgREFUQUJBU0UgSUYgRVhJU1RTIFxcYCR7Y29ubi5kYXRhYmFzZX1cXGAnYCk7XG4gICAgZXhlY1N5bmMoYCR7bXlzcWxDbWR9IC1lICdDUkVBVEUgREFUQUJBU0UgXFxgJHtjb25uLmRhdGFiYXNlfVxcYCdgKTtcbiAgICBleGVjU3luYyhgJHtteXNxbENtZH0gJHtjb25uLmRhdGFiYXNlfSA8ICR7ZHVtcEZpbGVuYW1lfWApO1xuICAgIGlmIChhd2FpdCBleGlzdHMobWlncmF0aW9uc0R1bXApKSB7XG4gICAgICBleGVjU3luYyhgJHtteXNxbENtZH0gJHtjb25uLmRhdGFiYXNlfSA8ICR7bWlncmF0aW9uc0R1bXB9YCk7XG4gICAgfVxuXG4gICAgYXdhaXQgZGIuZGVzdHJveSgpO1xuICB9XG5cbiAgYXdhaXQgX2RiLmRlc3Ryb3koKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZml4dHVyZV9pbXBvcnQoZW50aXR5SWQ6IHN0cmluZywgcmVjb3JkSWRzOiBudW1iZXJbXSkge1xuICBhd2FpdCBzZXR1cEZpeHR1cmVNYW5hZ2VyKCk7XG5cbiAgYXdhaXQgRml4dHVyZU1hbmFnZXIuaW1wb3J0Rml4dHVyZShlbnRpdHlJZCwgcmVjb3JkSWRzKTtcbiAgYXdhaXQgRml4dHVyZU1hbmFnZXIuc3luYygpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmaXh0dXJlX3N5bmMoKSB7XG4gIGF3YWl0IHNldHVwRml4dHVyZU1hbmFnZXIoKTtcblxuICBhd2FpdCBGaXh0dXJlTWFuYWdlci5zeW5jKCk7XG59XG5cbi8qKlxuICogZml4dHVyZSBnZW4g66qF66C57Ja0XG4gKiDsmLXshZjsnYQgcHJvY2Vzcy5hcmd27JeQ7IScIO2MjOyLsVxuICovXG5hc3luYyBmdW5jdGlvbiBmaXh0dXJlX2dlbigpIHtcbiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlT3B0aW9ucyhwcm9jZXNzLmFyZ3YpO1xuICBhd2FpdCBmaXh0dXJlR2VuQ29tbWFuZChvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBmaXh0dXJlIGZldGNoIOuqheugueyWtFxuICog7Ji17IWY7J2EIHByb2Nlc3MuYXJnduyXkOyEnCDtjIzsi7FcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZml4dHVyZV9mZXRjaCgpIHtcbiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlT3B0aW9ucyhwcm9jZXNzLmFyZ3YpO1xuICBhd2FpdCBmaXh0dXJlRmV0Y2hDb21tYW5kKG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIGZpeHR1cmUgZXhwbG9yZSDrqoXroLnslrRcbiAqIOyYteyFmOydhCBwcm9jZXNzLmFyZ3bsl5DshJwg7YyM7IuxXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZpeHR1cmVfZXhwbG9yZSgpIHtcbiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlT3B0aW9ucyhwcm9jZXNzLmFyZ3YpO1xuICBhd2FpdCBmaXh0dXJlRXhwbG9yZUNvbW1hbmQob3B0aW9ucyk7XG59XG5cbi8qKlxuICog6rCE64uo7ZWcIOyYteyFmCDtjIzshJxcbiAqL1xuZnVuY3Rpb24gcGFyc2VPcHRpb25zKFxuICBhcmd2OiBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IGJvb2xlYW4gfCBzdHJpbmdbXT4gJiB7IF86IHN0cmluZ1tdIH0ge1xuICBjb25zdCBvcHRpb25zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBib29sZWFuIHwgc3RyaW5nW10+ICYgeyBfOiBzdHJpbmdbXSB9ID0geyBfOiBbXSB9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG5cbiAgICBpZiAoYXJnLnN0YXJ0c1dpdGgoXCItLVwiKSkge1xuICAgICAgY29uc3Qga2V5ID0gYXJnLnNsaWNlKDIpO1xuXG4gICAgICBpZiAoa2V5LmluY2x1ZGVzKFwiPVwiKSkge1xuICAgICAgICBjb25zdCBbaywgdl0gPSBrZXkuc3BsaXQoXCI9XCIpO1xuICAgICAgICBvcHRpb25zW2tdID0gdjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IG5leHQgPSBhcmd2W2kgKyAxXTtcbiAgICAgICAgaWYgKG5leHQgJiYgIW5leHQuc3RhcnRzV2l0aChcIi0tXCIpKSB7XG4gICAgICAgICAgb3B0aW9uc1trZXldID0gbmV4dDtcbiAgICAgICAgICBpKys7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb3B0aW9uc1trZXldID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoYXJnLnN0YXJ0c1dpdGgoXCItXCIpKSB7XG4gICAgICBjb25zdCBrZXkgPSBhcmcuc2xpY2UoMSk7XG4gICAgICBjb25zdCBuZXh0ID0gYXJndltpICsgMV07XG5cbiAgICAgIGlmIChuZXh0ICYmICFuZXh0LnN0YXJ0c1dpdGgoXCItXCIpKSB7XG4gICAgICAgIG9wdGlvbnNba2V5XSA9IG5leHQ7XG4gICAgICAgIGkrKztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9wdGlvbnNba2V5XSA9IHRydWU7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG9wdGlvbnMuXy5wdXNoKGFyZyk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG9wdGlvbnM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN0dWJfcHJhY3RpY2UobmFtZTogc3RyaW5nKSB7XG4gIGNvbnN0IHByYWN0aWNlRGlyID0gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmNcIiwgXCJwcmFjdGljZXNcIik7XG4gIGNvbnN0IGZpbGVOYW1lcyA9IGF3YWl0IHJlYWRkaXIocHJhY3RpY2VEaXIpO1xuXG4gIGNvbnN0IG1heFNlcU5vID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICBpZiAoIShhd2FpdCBleGlzdHMocHJhY3RpY2VEaXIpKSkge1xuICAgICAgYXdhaXQgbWtkaXIocHJhY3RpY2VEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbHRlcmVkU2VxcyA9IGZpbGVOYW1lc1xuICAgICAgLmZpbHRlcigoZmlsZU5hbWUpID0+IGZpbGVOYW1lLnN0YXJ0c1dpdGgoXCJwXCIpICYmIGZpbGVOYW1lLmVuZHNXaXRoKFwiLnRzXCIpKVxuICAgICAgLm1hcCgoZmlsZU5hbWUpID0+IHtcbiAgICAgICAgY29uc3QgWywgc2VxTm9dID0gZmlsZU5hbWUubWF0Y2goL15wKFswLTldKyktLykgPz8gW1wiMFwiLCBcIjBcIl07XG4gICAgICAgIHJldHVybiBwYXJzZUludChzZXFObyk7XG4gICAgICB9KVxuICAgICAgLnNvcnQoKGEsIGIpID0+IGIgLSBhKTtcblxuICAgIGlmIChmaWx0ZXJlZFNlcXMubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIGZpbHRlcmVkU2Vxc1swXTtcbiAgICB9XG5cbiAgICByZXR1cm4gMDtcbiAgfSkoKTtcblxuICBjb25zdCBjdXJyZW50U2VxTm8gPSBtYXhTZXFObyArIDE7XG4gIGNvbnN0IGZpbGVOYW1lID0gYHAke2N1cnJlbnRTZXFOb30tJHtuYW1lfS50c2A7XG4gIGNvbnN0IGRzdFBhdGggPSBwYXRoLmpvaW4ocHJhY3RpY2VEaXIsIGZpbGVOYW1lKTtcblxuICBjb25zdCBjb2RlID0gW1xuICAgIGBpbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwic29uYW11XCI7YCxcbiAgICBcIlwiLFxuICAgIGBjb25zb2xlLmNsZWFyKCk7YCxcbiAgICBgY29uc29sZS5sb2coXCIke2ZpbGVOYW1lfVwiKTtgLFxuICAgIFwiXCIsXG4gICAgYFNvbmFtdS5ydW5TY3JpcHQoYXN5bmMgKCkgPT4ge2AsXG4gICAgYCAvLyBUT0RPYCxcbiAgICBgfSk7YCxcbiAgICBcIlwiLFxuICBdLmpvaW4oXCJcXG5cIik7XG4gIGF3YWl0IHdyaXRlRmlsZShkc3RQYXRoLCBjb2RlKTtcblxuICBleGVjU3luYyhgY29kZSAke2RzdFBhdGh9YCk7XG5cbiAgY29uc3QgcnVuQ29kZSA9IGB5YXJuIG5vZGUgLXIgZG90ZW52L2NvbmZpZyAtLWVuYWJsZS1zb3VyY2UtbWFwcyBkaXN0L3ByYWN0aWNlcy8ke2ZpbGVOYW1lLnJlcGxhY2UoXG4gICAgXCIudHNcIixcbiAgICBcIi5qc1wiLFxuICApfWA7XG4gIGNvbnNvbGUubG9nKGAke2NoYWxrLmJsdWUocnVuQ29kZSl9IGNvcGllZCB0byBjbGlwYm9hcmQuYCk7XG4gIGV4ZWNTeW5jKGBlY2hvIFwiJHtydW5Db2RlfVwiIHwgcGJjb3B5YCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN0dWJfZW50aXR5KGVudGl0eUlkOiBzdHJpbmcpIHtcbiAgYXdhaXQgU29uYW11LnN5bmNlci5jcmVhdGVFbnRpdHkoeyBlbnRpdHlJZCwgdGl0bGU6IGVudGl0eUlkIH0pO1xuXG4gIGNvbnN0IHsgZmxhZ3MgfSA9IHBhcnNlQ2xpT3B0aW9ucygpO1xuICBjb25zdCB1c2VBSSA9IGZsYWdzLmhhcyhcImFpXCIpO1xuICBjb25zdCBub0NvbmVzID0gZmxhZ3MuaGFzKFwibm8tY29uZXNcIik7XG5cbiAgLy8gLS1uby1jb25lczogY29uZSDsg53shLEg7Iqk7YK1XG4gIGlmIChub0NvbmVzKSB7XG4gICAgY29uc29sZS5sb2coYOKckyBFbnRpdHkgJyR7ZW50aXR5SWR9JyBjcmVhdGVkIHdpdGhvdXQgY29uZXNgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7IEVudGl0eU1hbmFnZXIgfSA9IGF3YWl0IGltcG9ydChcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiKTtcbiAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpO1xuICBpZiAoIWVudGl0eSkge1xuICAgIGNvbnNvbGUuZXJyb3IoYEVudGl0eSBub3QgZm91bmQ6ICR7ZW50aXR5SWR9YCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gLS1haTogTExN7Jy866GcIGNvbmUg7IOd7ISxXG4gIGlmICh1c2VBSSkge1xuICAgIGNvbnNvbGUubG9nKGDinJMgRW50aXR5ICcke2VudGl0eUlkfScgY3JlYXRlZGApO1xuICAgIGNvbnNvbGUubG9nKGDwn4yfIEdlbmVyYXRpbmcgQUktcG93ZXJlZCBjb25lcy4uLmApO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb25maWdMb2NhbGUgPSBTb25hbXUuY29uZmlnLmkxOG4/LmRlZmF1bHRMb2NhbGU7XG4gICAgICBjb25zdCBsb2NhbGUgPVxuICAgICAgICBjb25maWdMb2NhbGUgPT09IFwia29cIiB8fCBjb25maWdMb2NhbGUgPT09IFwiZW5cIiB8fCBjb25maWdMb2NhbGUgPT09IFwiamFcIlxuICAgICAgICAgID8gY29uZmlnTG9jYWxlXG4gICAgICAgICAgOiBcImtvXCI7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGVudGl0eS5nZW5lcmF0ZUNvbmVzKHtcbiAgICAgICAgcHJlc2VydmVFeGlzdGluZzogZmFsc2UsXG4gICAgICAgIG9ubHlFbXB0eTogZmFsc2UsXG4gICAgICAgIGxvY2FsZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zb2xlLmxvZyhg4pyFIERvbmUgKCR7cmVzdWx0LnRva2Vuc1VzZWR9IHRva2VucylgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcIkFOVEhST1BJQ19BUElfS0VZXCIpKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbuKdjCAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbvCfkqEgUmVtb3ZlIC0tYWkgZmxhZyB0byB1c2UgdGVtcGxhdGUgY29uZXMgaW5zdGVhZGApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIOq4sOuzuDog7YWc7ZSM66a/IGNvbmUg7J6Q64+ZIOyDneyEsVxuICAvLyBMTE0g7JeG7J20IGZha2VyLW1hcHBpbmdzLnRz66W8IO2ZnOyaqe2VmOyXrCDquLDrs7ggY29uZSDrqZTtg4DrjbDsnbTthLDrpbwg7IOd7ISx7ZWp64uI64ukLlxuICAvLyDsnbTrpbwg7Ya17ZW0IEFOVEhST1BJQ19BUElfS0VZ6rCAIOyXhuyWtOuPhCBTb25hbXXrpbwg7IKs7Jqp7ZWgIOyImCDsnojsnLzrqbAsXG4gIC8vIOyDneyEseuQnCDthZztlIzrpr8gY29uZeydgCDrgpjspJHsl5AgJ2NvbmUgZ2VuJyDrqoXroLnslrTroZwgQUnrpbwg7Ya17ZW0IOyXheq3uOugiOydtOuTnO2VoCDsiJgg7J6I7Iq164uI64ukLlxuICBjb25zb2xlLmxvZyhg8J+MnyBHZW5lcmF0aW5nIHRlbXBsYXRlIGNvbmVzLi4uYCk7XG4gIGF3YWl0IGVudGl0eS5nZW5lcmF0ZVRlbXBsYXRlQ29uZXMoKTtcbiAgY29uc29sZS5sb2coYOKckyBFbnRpdHkgJyR7ZW50aXR5SWR9JyBjcmVhdGVkIHdpdGggdGVtcGxhdGUgY29uZXNgKTtcbiAgY29uc29sZS5sb2coYPCfkqEgVGlwOiBSdW4gJ3BucG0gc29uYW11IGNvbmUgZ2VuICR7ZW50aXR5SWR9JyB0byBpbXByb3ZlIHdpdGggQUlgKTtcbn1cblxuLyoqXG4gKiBBSeulvCDsgqzsmqntlZjsl6wgZW50aXR57J2YIGNvbmUg66mU7YOA642w7J207YSw66W8IOyDneyEse2VmOqxsOuCmCDsl4Xqt7jroIjsnbTrk5ztlanri4jri6QuXG4gKlxuICog7Ji17IWYOlxuICogLSAtLXJlZ2VuZXJhdGU6IOyghOyytCDsnqzsg53shLEgKOq4sOyhtCBjb25lIOuNruyWtOyTsOq4sClcbiAqIC0gLS1sb2NhbGUgPGtvfGVufGphPjog7IOd7ISxIOyWuOyWtCDsp4DsoJVcbiAqIC0g6riw67O4OiBvbmx5RW1wdHkg66qo65OcICjquLDsobQgZml4dHVyZUhpbnQg67O07KG0KVxuICpcbiAqIEFOVEhST1BJQ19BUElfS0VZIO2VhOyalCAoc29uYW11LnNlY3JldC50cyDrmJDripQg7ZmY6rK967OA7IiYKVxuICovXG5hc3luYyBmdW5jdGlvbiBjb25lX2dlbihlbnRpdHlJZDogc3RyaW5nKSB7XG4gIGNvbnN0IHsgRW50aXR5TWFuYWdlciB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCIpO1xuICBjb25zdCB7IGZsYWdzLCBvcHRpb25zIH0gPSBwYXJzZUNsaU9wdGlvbnMoKTtcblxuICAvLyAtLWFsbCDsmLXshZg6IOuqqOuToCBlbnRpdHkgY29uZSDsg53shLFcbiAgaWYgKGZsYWdzLmhhcyhcImFsbFwiKSB8fCBlbnRpdHlJZCA9PT0gXCJhbGxcIikge1xuICAgIGNvbnN0IGFsbEVudGl0aWVzID0gRW50aXR5TWFuYWdlci5nZXRBbGxFbnRpdGllcygpO1xuICAgIGNvbnNvbGUubG9nKGDwn4yfIEdlbmVyYXRpbmcgQUktcG93ZXJlZCBjb25lcyBmb3IgJHthbGxFbnRpdGllcy5sZW5ndGh9IGVudGl0aWVzLi4uXFxuYCk7XG5cbiAgICBsZXQgdG90YWxUb2tlbnMgPSAwO1xuICAgIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgZW50aXR5IG9mIGFsbEVudGl0aWVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZyhgUHJvY2Vzc2luZyAke2VudGl0eS5pZH0uLi5gKTtcbiAgICAgICAgY29uc3QgY29uZmlnTG9jYWxlID0gb3B0aW9ucy5sb2NhbGUgfHwgU29uYW11LmNvbmZpZy5pMThuPy5kZWZhdWx0TG9jYWxlO1xuICAgICAgICBjb25zdCBsb2NhbGUgPVxuICAgICAgICAgIGNvbmZpZ0xvY2FsZSA9PT0gXCJrb1wiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJlblwiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJqYVwiXG4gICAgICAgICAgICA/IGNvbmZpZ0xvY2FsZVxuICAgICAgICAgICAgOiBcImtvXCI7XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZW50aXR5LmdlbmVyYXRlQ29uZXMoe1xuICAgICAgICAgIHByZXNlcnZlRXhpc3Rpbmc6ICFmbGFncy5oYXMoXCJyZWdlbmVyYXRlXCIpLFxuICAgICAgICAgIG9ubHlFbXB0eTogIWZsYWdzLmhhcyhcInJlZ2VuZXJhdGVcIiksXG4gICAgICAgICAgbG9jYWxlLFxuICAgICAgICB9KTtcblxuICAgICAgICB0b3RhbFRva2VucyArPSByZXN1bHQudG9rZW5zVXNlZDtcbiAgICAgICAgY29uc29sZS5sb2coYCAg4pyTICR7ZW50aXR5LmlkfSAoJHtyZXN1bHQudG9rZW5zVXNlZH0gdG9rZW5zKVxcbmApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogXCJVbmtub3duIGVycm9yXCI7XG4gICAgICAgIGVycm9ycy5wdXNoKGAke2VudGl0eS5pZH06ICR7bWVzc2FnZX1gKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihgICDinJcgJHtlbnRpdHkuaWR9OiAke21lc3NhZ2V9XFxuYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coYFxcbuKchSBEb25lISBUb3RhbDogJHt0b3RhbFRva2Vuc30gdG9rZW5zIHVzZWRgKTtcbiAgICBjb25zdCBlc3RpbWF0ZWRDb3N0ID0gKHRvdGFsVG9rZW5zICogOSkgLyAxXzAwMF8wMDA7XG4gICAgY29uc29sZS5sb2coYPCfkrAgRXN0aW1hdGVkIGNvc3Q6IH4kJHtlc3RpbWF0ZWRDb3N0LnRvRml4ZWQoNCl9YCk7XG5cbiAgICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbuKdjCBGYWlsZWQgZW50aXRpZXMgKCR7ZXJyb3JzLmxlbmd0aH0pOmApO1xuICAgICAgZm9yIChjb25zdCBlcnIgb2YgZXJyb3JzKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYCAgLSAke2Vycn1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8g64uo7J28IGVudGl0eSBjb25lIOyDneyEsVxuICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCk7XG4gIGlmICghZW50aXR5KSB7XG4gICAgY29uc29sZS5lcnJvcihgRW50aXR5IG5vdCBmb3VuZDogJHtlbnRpdHlJZH1gKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBtb2RlID0gZmxhZ3MuaGFzKFwicmVnZW5lcmF0ZVwiKSA/IFwicmVnZW5lcmF0aW5nXCIgOiBcImdlbmVyYXRpbmdcIjtcbiAgY29uc29sZS5sb2coXG4gICAgYPCfjJ8gJHttb2RlID09PSBcInJlZ2VuZXJhdGluZ1wiID8gXCJSZWdlbmVyYXRpbmdcIiA6IFwiR2VuZXJhdGluZ1wifSBBSS1wb3dlcmVkIGNvbmVzIGZvciAke2VudGl0eUlkfS4uLmAsXG4gICk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWdMb2NhbGUgPSBvcHRpb25zLmxvY2FsZSB8fCBTb25hbXUuY29uZmlnLmkxOG4/LmRlZmF1bHRMb2NhbGU7XG4gICAgY29uc3QgbG9jYWxlID1cbiAgICAgIGNvbmZpZ0xvY2FsZSA9PT0gXCJrb1wiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJlblwiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJqYVwiID8gY29uZmlnTG9jYWxlIDogXCJrb1wiO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZW50aXR5LmdlbmVyYXRlQ29uZXMoe1xuICAgICAgcHJlc2VydmVFeGlzdGluZzogIWZsYWdzLmhhcyhcInJlZ2VuZXJhdGVcIiksXG4gICAgICBvbmx5RW1wdHk6ICFmbGFncy5oYXMoXCJyZWdlbmVyYXRlXCIpLFxuICAgICAgbG9jYWxlLFxuICAgIH0pO1xuXG4gICAgY29uc29sZS5sb2coYOKchSBEb25lISAoJHtyZXN1bHQudG9rZW5zVXNlZH0gdG9rZW5zIHVzZWQpYCk7XG5cbiAgICAvLyDthqDtgbAg67mE7JqpIOqzhOyCsCAo64yA65617KCB7J24IOy2lOyglSlcbiAgICAvLyBDbGF1ZGUgU29ubmV0IDQuNTogaW5wdXQgJDMvTSB0b2tlbnMsIG91dHB1dCAkMTUvTSB0b2tlbnNcbiAgICAvLyDqsITri6jtlZjqsowg7Y+J6regICQ5L00gdG9rZW5z66GcIOqzhOyCsFxuICAgIGNvbnN0IGVzdGltYXRlZENvc3QgPSAocmVzdWx0LnRva2Vuc1VzZWQgKiA5KSAvIDFfMDAwXzAwMDtcbiAgICBjb25zb2xlLmxvZyhg8J+SsCBFc3RpbWF0ZWQgY29zdDogfiQke2VzdGltYXRlZENvc3QudG9GaXhlZCg0KX1gKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgaWYgKGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoXCJBTlRIUk9QSUNfQVBJX0tFWVwiKSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBcXG7inYwgJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgICBjb25zb2xlLmVycm9yKGBcXG7wn5KhIFRvIHVzZSBBSS1wb3dlcmVkIGNvbmUgZ2VuZXJhdGlvbjpgKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihgICAgMS4gR2V0IGFuIEFQSSBrZXkgZnJvbSBodHRwczovL2NvbnNvbGUuYW50aHJvcGljLmNvbS9gKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICBgICAgMi4gQWRkIGl0IHRvIHNvbmFtdS5zZWNyZXQudHMgb3Igc2V0IEFOVEhST1BJQ19BUElfS0VZIGVudmlyb25tZW50IHZhcmlhYmxlYCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcIlJhdGUgbGltaXRcIikpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgXFxu4p2MICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihgXFxu8J+SoSBQbGVhc2Ugd2FpdCBhIG1vbWVudCBhbmQgdHJ5IGFnYWluLmApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgXFxu4p2MIEZhaWxlZCB0byBnZW5lcmF0ZSBjb25lczogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBcXG7inYwgRmFpbGVkIHRvIGdlbmVyYXRlIGNvbmVzOiBVbmtub3duIGVycm9yYCk7XG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNjYWZmb2xkX21vZGVsKGVudGl0eUlkOiBzdHJpbmcpIHtcbiAgYXdhaXQgU29uYW11LnN5bmNlci5nZW5lcmF0ZVRlbXBsYXRlKFwibW9kZWxcIiwge1xuICAgIGVudGl0eUlkLFxuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGRfbW9kZWxfdGVzdChlbnRpdHlJZDogc3RyaW5nKSB7XG4gIGF3YWl0IFNvbmFtdS5zeW5jZXIuZ2VuZXJhdGVUZW1wbGF0ZShcIm1vZGVsX3Rlc3RcIiwge1xuICAgIGVudGl0eUlkLFxuICB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIHNvbmFtdSBza2lsbHMgc3luYyDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIOqzteyLnSBTa2lsbHPrpbwg66Gc7LusIO2UhOuhnOygne2KuCDrmJDripQg6riA66Gc67KMIH4vLmNsYXVkZS/roZwg64+Z6riw7ZmU7ZWp64uI64ukLlxuICpcbiAqIC0tZ2xvYmFsIO2UjOuemOq3uDogfi8uY2xhdWRlL+yXkCDrj5nquLDtmZQgKO2UhOuhnOygne2KuCDsg53shLEg7KCEIOyCrOyaqSDqsIDriqUpXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNraWxsc19zeW5jKCkge1xuICBjb25zdCB7IGZsYWdzIH0gPSBwYXJzZUNsaU9wdGlvbnMoKTtcbiAgY29uc3QgaXNHbG9iYWwgPSBmbGFncy5oYXMoXCJnbG9iYWxcIik7XG5cbiAgLy8g6rCc67CcIO2ZmOqyvSAtIGNsaS50czogc29uYW11L21vZHVsZXMvc29uYW11L3NyYy9iaW4vY2xpLnRzXG4gIC8vIOu5jOuTnCDtm4QgLSBjbGkuanM6IG5vZGVfbW9kdWxlcy9zb25hbXUvZGlzdC9iaW4vY2xpLmpzICjsi6TsoJwg7Iuk7ZaJKVxuICAvLyBza2lsbHMg7JyE7LmYOiBub2RlX21vZHVsZXMvc29uYW11L3NyYy9za2lsbHMgKG5wbSDrsLDtj6wg7IucKVxuICBjb25zdCBzb3VyY2VCYXNlID0gcGF0aC5yZXNvbHZlKGltcG9ydC5tZXRhLmRpcm5hbWUsIFwiLi5cIiwgXCIuLlwiLCBcInNyY1wiLCBcInNraWxsc1wiKTtcbiAgY29uc3Qgc291cmNlU2tpbGxzRGlyID0gcGF0aC5qb2luKHNvdXJjZUJhc2UsIFwic29uYW11XCIpO1xuICBjb25zdCBzb3VyY2VDbGF1ZGVNZCA9IHBhdGguam9pbihzb3VyY2VCYXNlLCBcIkNMQVVERS5tZFwiKTtcblxuICBpZiAoIShhd2FpdCBleGlzdHMoc291cmNlU2tpbGxzRGlyKSkpIHtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coXCJTa2lsbHMgc291cmNlIG5vdCBmb3VuZCBpbiBzb25hbXUgcGFja2FnZS5cIikpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChpc0dsb2JhbCkge1xuICAgIGNvbnN0IGhvbWVDbGF1ZGVEaXIgPSBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCBcIi5jbGF1ZGVcIik7XG4gICAgYXdhaXQgc2tpbGxzX3N5bmNfdG8oaG9tZUNsYXVkZURpciwgc291cmNlU2tpbGxzRGlyLCBzb3VyY2VDbGF1ZGVNZCwge1xuICAgICAgdXNlU3ltbGluazogZmFsc2UsXG4gICAgICBjb3B5UHJvamVjdFRlbXBsYXRlczogZmFsc2UsXG4gICAgICBpc0dsb2JhbDogdHJ1ZSxcbiAgICB9KTtcblxuICAgIC8vIH4vLmNsYXVkZS9jb21tYW5kcy9zb25hbXUtc2tpbGxzLm1kIOyEpOy5mFxuICAgIGNvbnN0IHNvdXJjZUNvbW1hbmRzRGlyID0gcGF0aC5qb2luKHNvdXJjZUJhc2UsIFwiY29tbWFuZHNcIik7XG4gICAgY29uc3Qgc291cmNlQ29tbWFuZCA9IHBhdGguam9pbihzb3VyY2VDb21tYW5kc0RpciwgXCJzb25hbXUtc2tpbGxzLm1kXCIpO1xuICAgIGlmIChhd2FpdCBleGlzdHMoc291cmNlQ29tbWFuZCkpIHtcbiAgICAgIGNvbnN0IHRhcmdldENvbW1hbmRzRGlyID0gcGF0aC5qb2luKGhvbWVDbGF1ZGVEaXIsIFwiY29tbWFuZHNcIik7XG4gICAgICBhd2FpdCBta2Rpcih0YXJnZXRDb21tYW5kc0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBhd2FpdCBjcChzb3VyY2VDb21tYW5kLCBwYXRoLmpvaW4odGFyZ2V0Q29tbWFuZHNEaXIsIFwic29uYW11LXNraWxscy5tZFwiKSk7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihg4pyTIC9zb25hbXUtc2tpbGxzIGNvbW1hbmQgaW5zdGFsbGVkIOKGkiB+Ly5jbGF1ZGUvY29tbWFuZHMvYCkpO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGNoYWxrLmN5YW4oYFxcbiAgR2xvYmFsIHN5bmMgY29tcGxldGUg4oaSIH4vLmNsYXVkZS9za2lsbHMvc29uYW11L2ApKTtcbiAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oYCAgVGhlc2Ugc2tpbGxzIGFyZSBhdmFpbGFibGUgaW4gYWxsIENsYXVkZSBDb2RlIHNlc3Npb25zLmApKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGNoYWxrLmRpbShcbiAgICAgICAgYCAgT25jZSBhIHByb2plY3QgaXMgY3JlYXRlZCwgcnVuICdwbnBtIHNvbmFtdSBza2lsbHMgc3luYycgZm9yIHByb2plY3QtbG9jYWwgc3luYy5gLFxuICAgICAgKSxcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHdvcmtzcGFjZVJvb3QgPSBhd2FpdCBmaW5kV29ya3NwYWNlUm9vdCgpO1xuICAgIGNvbnN0IGNsYXVkZURpciA9IHBhdGguam9pbih3b3Jrc3BhY2VSb290LCBcIi5jbGF1ZGVcIik7XG4gICAgYXdhaXQgc2tpbGxzX3N5bmNfdG8oY2xhdWRlRGlyLCBzb3VyY2VTa2lsbHNEaXIsIHNvdXJjZUNsYXVkZU1kLCB7XG4gICAgICB1c2VTeW1saW5rOiB0cnVlLFxuICAgICAgY29weVByb2plY3RUZW1wbGF0ZXM6IHRydWUsXG4gICAgICBzb3VyY2VCYXNlLFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogY2xhdWRlRGly66GcIHNraWxsc+ulvCDrj5nquLDtmZTtlZjripQg6rO17Ya1IOuhnOyngeyeheuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2tpbGxzX3N5bmNfdG8oXG4gIGNsYXVkZURpcjogc3RyaW5nLFxuICBzb3VyY2VTa2lsbHNEaXI6IHN0cmluZyxcbiAgc291cmNlQ2xhdWRlTWQ6IHN0cmluZyxcbiAgb3B0aW9uczoge1xuICAgIHVzZVN5bWxpbms6IGJvb2xlYW47XG4gICAgY29weVByb2plY3RUZW1wbGF0ZXM6IGJvb2xlYW47XG4gICAgc291cmNlQmFzZT86IHN0cmluZztcbiAgICBpc0dsb2JhbD86IGJvb2xlYW47XG4gIH0sXG4pIHtcbiAgY29uc3QgdGFyZ2V0U2tpbGxzRGlyID0gcGF0aC5qb2luKGNsYXVkZURpciwgXCJza2lsbHNcIiwgXCJzb25hbXVcIik7XG5cbiAgLy8g6riw7KG0IOuUlOugie2GoOumrC9zeW1saW5rIOyCreygnCDtm4Qg7J6s7IOd7ISxXG4gIC8vIGV4aXN0cygp64qUIGJyb2tlbiBzeW1saW5r66W8IOqwkOyngO2VmOyngCDrqrvtlZjrr4DroZwgcm3snYQg66y07KGw6rG0IOyLnOuPhO2VqeuLiOuLpFxuICB0cnkge1xuICAgIGF3YWl0IHJtKHRhcmdldFNraWxsc0RpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICB9IGNhdGNoIHtcbiAgICAvLyDtjIzsnbzsnbQg7JeG7Jy866m0IOustOyLnFxuICB9XG5cbiAgYXdhaXQgbWtkaXIocGF0aC5kaXJuYW1lKHRhcmdldFNraWxsc0RpciksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG4gIGlmIChvcHRpb25zLnVzZVN5bWxpbmspIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgc3ltbGluayhzb3VyY2VTa2lsbHNEaXIsIHRhcmdldFNraWxsc0RpciwgXCJkaXJcIik7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihg4pyTIFNraWxscyBsaW5rZWQgKHN5bWxpbmspYCkpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgY2hhbGsueWVsbG93KGDimqAgU3ltbGluayBmYWlsZWQ6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApLFxuICAgICAgKTtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhgICBGYWxsaW5nIGJhY2sgdG8gY29weS4uLmApKTtcbiAgICAgIGF3YWl0IHNraWxsc0NvcHkoc291cmNlU2tpbGxzRGlyLCB0YXJnZXRTa2lsbHNEaXIpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBhd2FpdCBza2lsbHNDb3B5KHNvdXJjZVNraWxsc0RpciwgdGFyZ2V0U2tpbGxzRGlyKTtcbiAgfVxuXG4gIC8vIHByb2plY3Qg65SU66CJ7Yag66asIOy0iOq4sO2ZlCAo7JeG7Jy866m0IOyDneyEsSwg7J6I7Jy866m0IOycoOyngClcbiAgaWYgKG9wdGlvbnMuY29weVByb2plY3RUZW1wbGF0ZXMgJiYgb3B0aW9ucy5zb3VyY2VCYXNlKSB7XG4gICAgY29uc3Qgc291cmNlUHJvamVjdERpciA9IHBhdGguam9pbihvcHRpb25zLnNvdXJjZUJhc2UsIFwicHJvamVjdFwiKTtcbiAgICBjb25zdCB0YXJnZXRQcm9qZWN0RGlyID0gcGF0aC5qb2luKGNsYXVkZURpciwgXCJza2lsbHNcIiwgXCJwcm9qZWN0XCIpO1xuXG4gICAgaWYgKGF3YWl0IGV4aXN0cyhzb3VyY2VQcm9qZWN0RGlyKSkge1xuICAgICAgaWYgKCEoYXdhaXQgZXhpc3RzKHRhcmdldFByb2plY3REaXIpKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGNwKHNvdXJjZVByb2plY3REaXIsIHRhcmdldFByb2plY3REaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgUHJvamVjdCB0ZW1wbGF0ZXMgaW5pdGlhbGl6ZWRgKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICAgIGNoYWxrLnJlZChcbiAgICAgICAgICAgICAgYOKclyBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBwcm9qZWN0IHRlbXBsYXRlczogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZGltKGDij60gUHJvamVjdCB0ZW1wbGF0ZXMgYWxyZWFkeSBleGlzdCAocHJlc2VydmVkKWApKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBzZXR0aW5ncy5sb2NhbC5qc29uIOKAlCBwcm9qZWN0LWxvY2FsIOuqqOuTnOyXkOyEnOunjCwg7JeG7J2EIOuVjOunjCDsg53shLFcbiAgaWYgKG9wdGlvbnMuY29weVByb2plY3RUZW1wbGF0ZXMpIHtcbiAgICBjb25zdCBzZXR0aW5nc0xvY2FsUGF0aCA9IHBhdGguam9pbihjbGF1ZGVEaXIsIFwic2V0dGluZ3MubG9jYWwuanNvblwiKTtcbiAgICBpZiAoIShhd2FpdCBleGlzdHMoc2V0dGluZ3NMb2NhbFBhdGgpKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qgc2V0dGluZ3NDb250ZW50ID0ge1xuICAgICAgICAgIGhvb2tzOiB7XG4gICAgICAgICAgICBQb3N0VG9vbFVzZTogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbWF0Y2hlcjogXCJFZGl0fFdyaXRlfE11bHRpRWRpdFwiLFxuICAgICAgICAgICAgICAgIGhvb2tzOiBbXG4gICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6IFwiY29tbWFuZFwiLFxuICAgICAgICAgICAgICAgICAgICBjb21tYW5kOiBcInBucG0gYmlvbWUgY2hlY2sgLS1jaGFuZ2VkIDI+JjEgfCBoZWFkIC02MFwiLFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoc2V0dGluZ3NMb2NhbFBhdGgsIGAke0pTT04uc3RyaW5naWZ5KHNldHRpbmdzQ29udGVudCwgbnVsbCwgMil9XFxuYCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgLmNsYXVkZS9zZXR0aW5ncy5sb2NhbC5qc29uIGNyZWF0ZWRgKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgIGNoYWxrLnJlZChcbiAgICAgICAgICAgIGDinJcgRmFpbGVkIHRvIGNyZWF0ZSBzZXR0aW5ncy5sb2NhbC5qc29uOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmRpbShg4o+tIC5jbGF1ZGUvc2V0dGluZ3MubG9jYWwuanNvbiBhbHJlYWR5IGV4aXN0cyAocHJlc2VydmVkKWApKTtcbiAgICB9XG4gIH1cblxuICAvLyBDTEFVREUubWQg67O17IKsL+yXheuNsOydtO2KuFxuICBpZiAoYXdhaXQgZXhpc3RzKHNvdXJjZUNsYXVkZU1kKSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB0YXJnZXRDbGF1ZGVNZCA9IHBhdGguam9pbihjbGF1ZGVEaXIsIFwiQ0xBVURFLm1kXCIpO1xuICAgICAgY29uc3QgcmF3Q29udGVudCA9IGF3YWl0IHJlYWRGaWxlKHNvdXJjZUNsYXVkZU1kLCBcInV0Zi04XCIpO1xuICAgICAgLy8g6riA66Gc67KMIOuqqOuTnOyXkOyEnOuKlCDsg4HrjIAg6rK966Gc66W8IOygiOuMgCDqsr3roZzroZwg67OA7ZmY7ZWp64uI64ukXG4gICAgICBjb25zdCBzb3VyY2VDb250ZW50ID0gb3B0aW9ucy5pc0dsb2JhbFxuICAgICAgICA/IHJhd0NvbnRlbnQucmVwbGFjZUFsbChcIi5jbGF1ZGUvc2tpbGxzL3NvbmFtdS9cIiwgXCJ+Ly5jbGF1ZGUvc2tpbGxzL3NvbmFtdS9cIilcbiAgICAgICAgOiByYXdDb250ZW50O1xuXG4gICAgICBpZiAoYXdhaXQgZXhpc3RzKHRhcmdldENsYXVkZU1kKSkge1xuICAgICAgICBjb25zdCB0YXJnZXRDb250ZW50ID0gYXdhaXQgcmVhZEZpbGUodGFyZ2V0Q2xhdWRlTWQsIFwidXRmLThcIik7XG4gICAgICAgIGNvbnN0IHN0YXJ0TWFya2VyID0gXCI8IS0tIFNPTkFNVTpTVEFSVCAtLT5cIjtcbiAgICAgICAgY29uc3QgZW5kTWFya2VyID0gXCI8IS0tIFNPTkFNVTpFTkQgLS0+XCI7XG4gICAgICAgIGlmICh0YXJnZXRDb250ZW50LmluY2x1ZGVzKHN0YXJ0TWFya2VyKSAmJiB0YXJnZXRDb250ZW50LmluY2x1ZGVzKGVuZE1hcmtlcikpIHtcbiAgICAgICAgICBjb25zdCBzdGFydElkeCA9IHRhcmdldENvbnRlbnQuaW5kZXhPZihzdGFydE1hcmtlcik7XG4gICAgICAgICAgY29uc3QgZW5kSWR4ID0gdGFyZ2V0Q29udGVudC5pbmRleE9mKGVuZE1hcmtlcik7XG5cbiAgICAgICAgICBpZiAoc3RhcnRJZHggIT09IC0xICYmIGVuZElkeCAhPT0gLTEgJiYgc3RhcnRJZHggPCBlbmRJZHgpIHtcbiAgICAgICAgICAgIGNvbnN0IGJlZm9yZSA9IHRhcmdldENvbnRlbnQuc3Vic3RyaW5nKDAsIHN0YXJ0SWR4KTtcbiAgICAgICAgICAgIGNvbnN0IGFmdGVyID0gdGFyZ2V0Q29udGVudC5zdWJzdHJpbmcoZW5kSWR4ICsgZW5kTWFya2VyLmxlbmd0aCk7XG4gICAgICAgICAgICBjb25zdCBuZXdDb250ZW50ID0gYCR7YmVmb3JlfSR7c3RhcnRNYXJrZXJ9XFxuJHtzb3VyY2VDb250ZW50fVxcbiR7ZW5kTWFya2VyfSR7YWZ0ZXJ9YDtcbiAgICAgICAgICAgIGF3YWl0IHdyaXRlRmlsZSh0YXJnZXRDbGF1ZGVNZCwgbmV3Q29udGVudCk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihg4pyTIENMQVVERS5tZCB1cGRhdGVkIChtYXJrZXIgcmVnaW9uKWApKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGDij60gQ0xBVURFLm1kIG1hcmtlciBwb3NpdGlvbnMgaW52YWxpZCwgc2tpcHBlZGApKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8g66eI7Luk6rCAIOyXhuuKlCDquLDsobQgQ0xBVURFLm1k7JeQIFNvbmFtdSDshLnshZjsnYQg7LaU6rCA7ZWp64uI64ukXG4gICAgICAgICAgY29uc3QgYXBwZW5kZWQgPSBgJHt0YXJnZXRDb250ZW50LnRyaW1FbmQoKX1cXG5cXG48IS0tIFNPTkFNVTpTVEFSVCAtLT5cXG4ke3NvdXJjZUNvbnRlbnR9XFxuPCEtLSBTT05BTVU6RU5EIC0tPlxcbmA7XG4gICAgICAgICAgYXdhaXQgd3JpdGVGaWxlKHRhcmdldENsYXVkZU1kLCBhcHBlbmRlZCk7XG4gICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBDTEFVREUubWQgdXBkYXRlZCAoYXBwZW5kZWQgU29uYW11IHNlY3Rpb24pYCkpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB3aXRoTWFya2VycyA9IGA8IS0tIFNPTkFNVTpTVEFSVCAtLT5cXG4ke3NvdXJjZUNvbnRlbnR9XFxuPCEtLSBTT05BTVU6RU5EIC0tPlxcbmA7XG4gICAgICAgIGF3YWl0IHdyaXRlRmlsZSh0YXJnZXRDbGF1ZGVNZCwgd2l0aE1hcmtlcnMpO1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihg4pyTIENMQVVERS5tZCBjcmVhdGVkYCkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICBjaGFsay5yZWQoXG4gICAgICAgICAgYOKclyBGYWlsZWQgdG8gdXBkYXRlIENMQVVERS5tZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNraWxsc0NvcHkoc3JjOiBzdHJpbmcsIGRlc3Q6IHN0cmluZykge1xuICB0cnkge1xuICAgIGF3YWl0IGNwKHNyYywgZGVzdCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBTa2lsbHMgY29waWVkYCkpO1xuICB9IGNhdGNoIChjb3B5RXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKFxuICAgICAgY2hhbGsucmVkKFxuICAgICAgICBg4pyXIEZhaWxlZCB0byBjb3B5IHNraWxsczogJHtjb3B5RXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGNvcHlFcnJvci5tZXNzYWdlIDogU3RyaW5nKGNvcHlFcnJvcil9YCxcbiAgICAgICksXG4gICAgKTtcbiAgICB0aHJvdyBjb3B5RXJyb3I7XG4gIH1cbn1cblxuLyoqXG4gKiBwbnBtIHNvbmFtdSBza2lsbHMgY3JlYXRlIDxuYW1lPiDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIOuhnOy7rCBza2lsbCDstIjslYjsnYQg7IOd7ISx7ZWp64uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBza2lsbHNfY3JlYXRlKG5hbWU6IHN0cmluZykge1xuICBjb25zdCB3b3Jrc3BhY2VSb290ID0gYXdhaXQgZmluZFdvcmtzcGFjZVJvb3QoKTtcbiAgY29uc3QgbG9jYWxEaXIgPSBwYXRoLmpvaW4od29ya3NwYWNlUm9vdCwgXCIuY2xhdWRlXCIsIFwic2tpbGxzXCIsIFwibG9jYWxcIik7XG5cbiAgLy8gPT09IO2MjOydvOuqhSDqsoDspp0g67CPIFNhbml0aXplID09PVxuICBpZiAoIW5hbWUgfHwgbmFtZS50cmltKCkgPT09IFwiXCIpIHtcbiAgICBjb25zb2xlLmVycm9yKGNoYWxrLnJlZChcIuKclyBTa2lsbCBuYW1lIGlzIHJlcXVpcmVkXCIpKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBsZXQgc2FuaXRpemVkID0gbmFtZVxuICAgIC8vIOqzteuwseydhCDtlZjsnbTtlIjsnLzroZxcbiAgICAucmVwbGFjZSgvXFxzKy9nLCBcIi1cIilcbiAgICAvLyDqsr3roZwg6rWs67aE7J6QIOygnOqxsFxuICAgIC5yZXBsYWNlKC9bL1xcXFxdL2csIFwiLVwiKVxuICAgIC8vIFBhdGggdHJhdmVyc2FsIOuwqeyngFxuICAgIC5yZXBsYWNlKC9cXC5cXC4vZywgXCJcIilcbiAgICAvLyBXaW5kb3dzIOq4iOyngCDrrLjsnpAg7KCc6rGwXG4gICAgLnJlcGxhY2UoL1s8PjpcInw/Kl0vZywgXCJcIilcbiAgICAvLyDsi5zsnpEv64GdIOygkCwg7ZWY7J207ZSILCDslrjrjZTsiqTsvZTslrQg7KCc6rGwXG4gICAgLnJlcGxhY2UoL15bLlxcLV9dK3xbLlxcLV9dKyQvZywgXCJcIilcbiAgICAvLyDsl7Dsho3rkJwg7ZWY7J207ZSI7J2EIO2VmOuCmOuhnFxuICAgIC5yZXBsYWNlKC8tKy9nLCBcIi1cIilcbiAgICAvLyDslYztjIzrsrMsIOyIq+yekCwg7ZWY7J207ZSILCDslrjrjZTsiqTsvZTslrQsIO2VnOq4gOunjCDtl4jsmqlcbiAgICAucmVwbGFjZSgvW15hLXpBLVowLTktX+qwgC3tnqNdL2csIFwiXCIpO1xuXG4gIC8vIOq4uOydtCDsoJztlZxcbiAgY29uc3QgTUFYX0xFTkdUSCA9IDEwMDtcbiAgaWYgKHNhbml0aXplZC5sZW5ndGggPiBNQVhfTEVOR1RIKSB7XG4gICAgc2FuaXRpemVkID0gc2FuaXRpemVkLnN1YnN0cmluZygwLCBNQVhfTEVOR1RIKTtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYOKaoCBOYW1lIHRydW5jYXRlZCB0byAke01BWF9MRU5HVEh9IGNoYXJhY3RlcnNgKSk7XG4gIH1cblxuICAvLyBXaW5kb3dzIOyYiOyVveyWtCDtmZXsnbhcbiAgY29uc3QgUkVTRVJWRURfTkFNRVMgPSBbXG4gICAgXCJDT05cIixcbiAgICBcIlBSTlwiLFxuICAgIFwiQVVYXCIsXG4gICAgXCJOVUxcIixcbiAgICBcIkNPTTFcIixcbiAgICBcIkNPTTJcIixcbiAgICBcIkNPTTNcIixcbiAgICBcIkNPTTRcIixcbiAgICBcIkNPTTVcIixcbiAgICBcIkNPTTZcIixcbiAgICBcIkNPTTdcIixcbiAgICBcIkNPTThcIixcbiAgICBcIkNPTTlcIixcbiAgICBcIkxQVDFcIixcbiAgICBcIkxQVDJcIixcbiAgICBcIkxQVDNcIixcbiAgICBcIkxQVDRcIixcbiAgICBcIkxQVDVcIixcbiAgICBcIkxQVDZcIixcbiAgICBcIkxQVDdcIixcbiAgICBcIkxQVDhcIixcbiAgICBcIkxQVDlcIixcbiAgXTtcbiAgaWYgKFJFU0VSVkVEX05BTUVTLmluY2x1ZGVzKHNhbml0aXplZC50b1VwcGVyQ2FzZSgpKSkge1xuICAgIHNhbml0aXplZCA9IGBza2lsbC0ke3Nhbml0aXplZH1gO1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhg4pqgIFJlc2VydmVkIG5hbWUgZGV0ZWN0ZWQsIHByZWZpeGVkIHdpdGggXCJza2lsbC1cImApKTtcbiAgfVxuXG4gIC8vIOu5iCDrrLjsnpDsl7Qg7LK07YGsXG4gIGlmIChzYW5pdGl6ZWQgPT09IFwiXCIpIHtcbiAgICBjb25zb2xlLmVycm9yKGNoYWxrLnJlZChcIuKclyBJbnZhbGlkIHNraWxsIG5hbWUgYWZ0ZXIgc2FuaXRpemF0aW9uXCIpKTtcbiAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oYCAgT3JpZ2luYWw6IFwiJHtuYW1lfVwiYCkpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIOuzgOqyvSDslYzrprxcbiAgaWYgKHNhbml0aXplZCAhPT0gbmFtZSkge1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhg4pqgIE5hbWUgc2FuaXRpemVkOiBcIiR7bmFtZX1cIiDihpIgXCIke3Nhbml0aXplZH1cImApKTtcbiAgfVxuXG4gIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5qb2luKGxvY2FsRGlyLCBgJHtzYW5pdGl6ZWR9Lm1kYCk7XG5cbiAgaWYgKGF3YWl0IGV4aXN0cyhmaWxlUGF0aCkpIHtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYFNraWxsIFwiJHtzYW5pdGl6ZWR9XCIgYWxyZWFkeSBleGlzdHMuYCkpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGF3YWl0IG1rZGlyKGxvY2FsRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IGAtLS1cbm5hbWU6ICR7c2FuaXRpemVkfVxuY2F0ZWdvcnk6IG90aGVyXG5jcmVhdGVkX2F0OiAke25ldyBEYXRlKCkudG9JU09TdHJpbmcoKS5zcGxpdChcIlRcIilbMF19XG5zdGF0dXM6IGRyYWZ0XG4tLS1cblxuIyAke3Nhbml0aXplZH1cblxuIyMg7IOB7ZmpXG5cblvslrTrlqQg66y47KCc7JiA64qU7KeAXVxuXG4jIyDtlbTqsrAg67Cp67KVXG5cblvslrTrlrvqsowg7ZW06rKw7ZaI64qU7KeAXVxuXG4jIyDsvZTrk5wg7JiI7IucXG5cblxcYFxcYFxcYHR5cGVzY3JpcHRcbi8vIOyYiOyLnCDsvZTrk5xcblxcYFxcYFxcYFxuYDtcblxuICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHRlbXBsYXRlKTtcbiAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBDcmVhdGVkIC5jbGF1ZGUvc2tpbGxzL2xvY2FsLyR7c2FuaXRpemVkfS5tZGApKTtcbn1cblxuLyoqXG4gKiBwbnBtIHNvbmFtdSBhdXRoIGdlbmVyYXRlIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICogYmV0dGVyLWF1dGgg7JeU7Yuw7Yuw65OkKFVzZXIsIFNlc3Npb24sIEFjY291bnQsIFZlcmlmaWNhdGlvbinsnYQg7IOd7ISx7ZWp64uI64ukLlxuICpcbiAqIOyYteyFmDpcbiAqIC0tcGx1Z2lucyBwaG9uZS1udW1iZXIsMmZhICDtlIzrn6zqt7jsnbgg7JeU7Yuw7Yuw64+EIO2VqOq7mCDsg53shLFcbiAqL1xuYXN5bmMgZnVuY3Rpb24gYXV0aF9nZW5lcmF0ZSgpIHtcbiAgLy8gLS1wbHVnaW5zIOyYteyFmCDtjIzsi7FcbiAgY29uc3QgcGx1Z2luc0FyZyA9IHByb2Nlc3MuYXJndi5maW5kKChhcmcpID0+IGFyZy5zdGFydHNXaXRoKFwiLS1wbHVnaW5zXCIpKTtcbiAgY29uc3QgcGx1Z2luczogQmV0dGVyQXV0aFBsdWdpbklkW10gPSBbXTtcblxuICBpZiAocGx1Z2luc0FyZykge1xuICAgIGNvbnN0IHBsdWdpblZhbHVlID0gcGx1Z2luc0FyZy5pbmNsdWRlcyhcIj1cIilcbiAgICAgID8gcGx1Z2luc0FyZy5zcGxpdChcIj1cIilbMV1cbiAgICAgIDogcHJvY2Vzcy5hcmd2W3Byb2Nlc3MuYXJndi5pbmRleE9mKHBsdWdpbnNBcmcpICsgMV07XG5cbiAgICBpZiAocGx1Z2luVmFsdWUpIHtcbiAgICAgIGNvbnN0IHBsdWdpbklkcyA9IHBsdWdpblZhbHVlLnNwbGl0KFwiLFwiKS5tYXAoKHApID0+IHAudHJpbSgpKTtcblxuICAgICAgZm9yIChjb25zdCBpZCBvZiBwbHVnaW5JZHMpIHtcbiAgICAgICAgaWYgKGlzVmFsaWRQbHVnaW5JZChpZCkpIHtcbiAgICAgICAgICBwbHVnaW5zLnB1c2goaWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhg4pqgIFVua25vd24gcGx1Z2luOiAke2lkfWApKTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oYCAgU3VwcG9ydGVkIHBsdWdpbnM6ICR7U1VQUE9SVEVEX1BMVUdJTl9JRFMuam9pbihcIiwgXCIpfWApKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdy5ib2xkKFwi8J+UkCBHZW5lcmF0aW5nIGJldHRlci1hdXRoIGVudGl0aWVzLi4uXFxuXCIpKTtcblxuICBpZiAocGx1Z2lucy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5sb2coY2hhbGsuZGltKGAgIFBsdWdpbnM6ICR7cGx1Z2lucy5qb2luKFwiLCBcIil9YCkpO1xuICB9XG5cbiAgYXdhaXQgZ2VuZXJhdGVCZXR0ZXJBdXRoRW50aXRpZXMoeyBwbHVnaW5zIH0pO1xufVxuXG4vKipcbiAqIHBucG0gc29uYW11IGF1dGggYWRkLWNvbXBhbmlvbnMg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiDquLDsobQg7ZSE66Gc7KCd7Yq47J2YIGVudGl0eS5qc29u7JeQIGZpeHR1cmVDb21wYW5pb25z66W8IOyGjOq4iSDstpTqsIDtlanri4jri6QuXG4gKlxuICog7J2066+4IGZpeHR1cmVDb21wYW5pb25z6rCAIOyeiOuKlCBlbnRpdHnripQg7Iqk7YK17ZWp64uI64ukICjrja7slrTsk7DquLAg7JeG7J2MKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYXV0aF9hZGRfY29tcGFuaW9ucygpIHtcbiAgY29uc29sZS5sb2coY2hhbGsueWVsbG93LmJvbGQoXCLwn5SQIEFkZGluZyBmaXh0dXJlQ29tcGFuaW9ucyB0byBiZXR0ZXItYXV0aCBlbnRpdGllcy4uLlxcblwiKSk7XG4gIGF3YWl0IGFkZENvbXBhbmlvbnNUb0VudGl0aWVzKCk7XG4gIGNvbnNvbGUubG9nKGNoYWxrLmJvbGQoXCJcXG7inIUgRG9uZSFcIikpO1xufVxuXG4vKipcbiAqIOybjO2BrOyKpO2OmOydtOyKpCDro6jtirjrpbwg7LC+7Iq164uI64ukLlxuICog7Jqw7ISg7Iic7JyEOiBwbnBtLXdvcmtzcGFjZS55YW1sID4gcGFja2FnZS5qc29uKHdvcmtzcGFjZXMpID4gLmFnZW50cy9cbiAqXG4gKiBDTEFVREUubWTripQg7ISc67iM7Yyo7YKk7KeA7JeQ64+EIOyhtOyerO2VoCDsiJgg7J6I7Jy866+A66GcIOyCrOyaqe2VmOyngCDslYrsirXri4jri6QuXG4gKiAuYWdlbnRzL+uKlCBhZ2VudHMgaW5pdOydtCDsg53shLHtlZjripQg65SU66CJ7Yag66as66GcLCDsm4ztgazsiqTtjpjsnbTsiqQg66Oo7Yq47JeQ66eMIOyhtOyerO2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmluZFdvcmtzcGFjZVJvb3QoKSB7XG4gIGxldCBkaXIgPSBwcm9jZXNzLmN3ZCgpO1xuXG4gIHdoaWxlIChkaXIgIT09IHBhdGguZGlybmFtZShkaXIpKSB7XG4gICAgLy8gMS4gcG5wbS13b3Jrc3BhY2UueWFtbDog7ZmV7Iuk7ZWcIG1vbm9yZXBvIOujqO2KuC5cbiAgICBpZiAoYXdhaXQgZXhpc3RzKHBhdGguam9pbihkaXIsIFwicG5wbS13b3Jrc3BhY2UueWFtbFwiKSkpIHtcbiAgICAgIHJldHVybiBkaXI7XG4gICAgfVxuXG4gICAgLy8gMi4gcGFja2FnZS5qc29u7JeQIHdvcmtzcGFjZXMg7ZWE65Oc6rCAIOyeiOycvOuptCBtb25vcmVwbyDro6jtirguXG4gICAgY29uc3QgcGFja2FnZVBhdGggPSBwYXRoLmpvaW4oZGlyLCBcInBhY2thZ2UuanNvblwiKTtcbiAgICBpZiAoYXdhaXQgZXhpc3RzKHBhY2thZ2VQYXRoKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlKHBhY2thZ2VQYXRoLCBcInV0Zi04XCIpKTtcbiAgICAgICAgaWYgKHBhY2thZ2VKc29uLndvcmtzcGFjZXMpIHtcbiAgICAgICAgICByZXR1cm4gZGlyO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8g7YyM7IuxIOyLpO2MqOyLnCDrrLTsi5xcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyAzLiAuYWdlbnRzLzogYWdlbnRzIGluaXTsnbQg7IOd7ISx7ZWcIOuUlOugie2GoOumrC4g7ISc67iM7Yyo7YKk7KeA7JeQ64qUIOyhtOyerO2VmOyngCDslYrsnYwuXG4gICAgaWYgKGF3YWl0IGV4aXN0cyhwYXRoLmpvaW4oZGlyLCBcIi5hZ2VudHNcIikpKSB7XG4gICAgICByZXR1cm4gZGlyO1xuICAgIH1cblxuICAgIGRpciA9IHBhdGguZGlybmFtZShkaXIpO1xuICB9XG5cbiAgLy8g7LC+7KeAIOuqu+2VmOuptCBhcGkg7Y+0642U7J2YIOu2gOuqqCDsgqzsmqlcbiAgcmV0dXJuIGZpbmRBcHBSb290UGF0aCgpO1xufVxuIl0sIm5hbWVzIjpbImNoYWxrIiwiZG90ZW52IiwiY29uZmlnIiwiYXNzZXJ0IiwiZXhlY1N5bmMiLCJzcGF3biIsImNwIiwibWtkaXIiLCJyZWFkZGlyIiwicmVhZEZpbGUiLCJybSIsInN5bWxpbmsiLCJ3cml0ZUZpbGUiLCJrbmV4IiwiY3JlYXRlUmVxdWlyZSIsIm9zIiwicGF0aCIsInByb2Nlc3MiLCJ0c2ljbGkiLCJTb25hbXUiLCJhZGRDb21wYW5pb25zVG9FbnRpdGllcyIsImdlbmVyYXRlQmV0dGVyQXV0aEVudGl0aWVzIiwiaXNWYWxpZFBsdWdpbklkIiwiU1VQUE9SVEVEX1BMVUdJTl9JRFMiLCJFbnRpdHlNYW5hZ2VyIiwiTWlncmF0b3IiLCJGaXh0dXJlTWFuYWdlciIsImV4ZWNXaXRoTGluZVByZWZpeCIsInByaW50QnVpbGRTdW1tYXJ5IiwicHJpbnRUYXNrRmFpbGVkIiwicHJpbnRUYXNrSGVhZGVyIiwicHJpbnRUYXNrU3RhcnQiLCJwcmludFRhc2tTdWNjZXNzIiwiZXhpc3RzIiwiZmluZEFwaVJvb3RQYXRoIiwiZmluZEFwcFJvb3RQYXRoIiwiQVBJX0FSVElGQUNUUyIsIldFQl9BUlRJRkFDVFMiLCJmaXh0dXJlRXhwbG9yZUNvbW1hbmQiLCJmaXh0dXJlRmV0Y2hDb21tYW5kIiwiZml4dHVyZUdlbkNvbW1hbmQiLCJ0ZXN0Q29tbWFuZCIsIm1pZ3JhdG9yIiwicGFyc2VDbGlPcHRpb25zIiwiYXJndiIsImZsYWdzIiwiU2V0Iiwib3B0aW9ucyIsImkiLCJsZW5ndGgiLCJhcmciLCJzdGFydHNXaXRoIiwiaW5jbHVkZXMiLCJrZXkiLCJ2YWx1ZSIsInNsaWNlIiwic3BsaXQiLCJuZXh0QXJnIiwiYWRkIiwiYm9vdHN0cmFwIiwibm90VG9Jbml0IiwiaW5pdCIsImZpbHRlcmVkQXJndiIsInNraXBOZXh0IiwiYWZ0ZXJEb3VibGVEYXNoIiwicHVzaCIsImNtZCIsInR5cGVzIiwidHlwZSIsIm5hbWUiLCJtZXNzYWdlIiwiY2hvaWNlcyIsImdldEFsbFBhcmVudElkcyIsIm1hcCIsImVudGl0eUlkIiwidGl0bGUiLCJhcmdzIiwicnVubmVycyIsIm1pZ3JhdGVfc3RhdHVzIiwibWlncmF0ZV9ydW4iLCJtaWdyYXRlX2FwcGx5IiwibWlncmF0ZV9nZW5lcmF0ZSIsImZpeHR1cmVfaW5pdCIsImZpeHR1cmVfaW1wb3J0IiwiZml4dHVyZV9zeW5jIiwiZml4dHVyZV9nZW4iLCJmaXh0dXJlX2ZldGNoIiwiZml4dHVyZV9leHBsb3JlIiwic3R1Yl9wcmFjdGljZSIsInN0dWJfZW50aXR5Iiwic2NhZmZvbGRfbW9kZWwiLCJzY2FmZm9sZF9tb2RlbF90ZXN0IiwiY29uZV9nZW4iLCJzeW5jIiwiYnVpbGRfYWxsIiwiYnVpbGRfYXBpIiwiYnVpbGRfd2ViIiwiZGV2X2FsbCIsImRldl9hcGkiLCJkZXZfd2ViIiwic3RhcnQiLCJza2lsbHNfc3luYyIsInNraWxsc19jcmVhdGUiLCJ0ZXN0IiwiYXV0aF9nZW5lcmF0ZSIsImF1dGhfYWRkX2NvbXBhbmlvbnMiLCJkZXN0cm95IiwiZmluYWxseSIsInN5bmNlciIsInNwYXduQXBpRGV2U2VydmVyIiwiYXBpUm9vdCIsImVudHJ5UG9pbnQiLCJob3RSdW5uZXJCaW5QYXRoIiwidXJsIiwicmVzb2x2ZSIsInNlcnZlclByb2Nlc3MiLCJleGVjUGF0aCIsImpvaW4iLCJjd2QiLCJzdGRpbyIsImVudiIsIk5PREVfRU5WIiwiSE9UIiwiQVBJX1JPT1RfUEFUSCIsImV4dHJhRW52IiwiY2xlYW51cCIsImNvbnNvbGUiLCJsb2ciLCJ5ZWxsb3ciLCJraWxsIiwiZXhpdCIsIm9uIiwiY29kZSIsImVycm9yIiwicmVkIiwiYm9sZCIsIlNPTkFNVV9ESVNBQkxFX0lOVEVHUkFURURfV0VCIiwiYXBwUm9vdCIsIndlYlBhdGgiLCJkb3VibGVEYXNoSW5kZXgiLCJpbmRleE9mIiwicGFzc3Rocm91Z2hBcmdzIiwidml0ZUFyZ3MiLCJ2aXRlUHJvY2VzcyIsInNpZ25hbCIsInJlc29sdmVTd2NDb25maWdQYXRoIiwic3djRmlsZVBhdGgiLCJkaW0iLCJkaXJuYW1lIiwic2tpcElmTWlzc2luZyIsImFwaVN0YXJ0ZWRBdCIsIkRhdGUiLCJub3ciLCJhcnRpZmFjdCIsInByb2plY3RQYXRoIiwiZGVzY3JpcHRpb24iLCJydW5CdWlsZFN0ZXBzIiwiYnVpbGRDb21tYW5kQXJncyIsImNvbmZpZ0ZpbGVQYXRoIiwiZSIsImdyYXkiLCJ3ZWJTdGFydGVkQXQiLCJzdGVwcyIsInByZUJ1aWxkQ29tbWFuZCIsImJ1aWxkQ29tbWFuZCIsInBvc3RCdWlsZENvbW1hbmQiLCJmaWx0ZXIiLCJzdGVwIiwiaXNMYXN0IiwiRXJyb3IiLCJjYXVzZSIsImJsdWUiLCJzZXR1cE1pZ3JhdG9yIiwic2V0dXBGaXh0dXJlTWFuYWdlciIsInRhcmdldHMiLCJydW5BY3Rpb24iLCJsb2NhbEhvc3RzIiwiT2JqZWN0Iiwia2V5cyIsImRiQ29uZmlnIiwidGFyZ2V0IiwidGFyZ2V0Q29uZmlnIiwiaG9zdCIsImNvbm5lY3Rpb24iLCJ0b0xvd2VyQ2FzZSIsImNvbm5zIiwiZ2V0U3RhdHVzIiwiaGFzU3RhdHVzMCIsInNvbWUiLCJjb25uIiwic3RhdHVzIiwicGVuZGluZyIsImNvdW50IiwiZ2VuZXJhdGVQcmVwYXJlZENvZGVzIiwiZ3JlZW4iLCJzcmNDb25maWciLCJkZXZlbG9wbWVudF9tYXN0ZXIiLCJsYWJlbCIsImZpeHR1cmUiLCJ0b1NraXAiLCJyZW1vdGVDb25uIiwibG9jYWxDb25uIiwiZGF0YWJhc2UiLCJkdW1wRmlsZW5hbWUiLCJzcmNDb25uIiwibWlncmF0aW9uc0R1bXAiLCJ1c2VyIiwicGFzc3dvcmQiLCJfZGIiLCJtaWdyYXRpb25zIiwicmF3IiwiZGIiLCJ1bmRlZmluZWQiLCJyb3ciLCJteXNxbENtZCIsInJlY29yZElkcyIsImltcG9ydEZpeHR1cmUiLCJwYXJzZU9wdGlvbnMiLCJfIiwiayIsInYiLCJuZXh0IiwicHJhY3RpY2VEaXIiLCJhcGlSb290UGF0aCIsImZpbGVOYW1lcyIsIm1heFNlcU5vIiwicmVjdXJzaXZlIiwiZmlsdGVyZWRTZXFzIiwiZmlsZU5hbWUiLCJlbmRzV2l0aCIsInNlcU5vIiwibWF0Y2giLCJwYXJzZUludCIsInNvcnQiLCJhIiwiYiIsImN1cnJlbnRTZXFObyIsImRzdFBhdGgiLCJydW5Db2RlIiwicmVwbGFjZSIsImNyZWF0ZUVudGl0eSIsInVzZUFJIiwiaGFzIiwibm9Db25lcyIsImVudGl0eSIsImdldCIsImNvbmZpZ0xvY2FsZSIsImkxOG4iLCJkZWZhdWx0TG9jYWxlIiwibG9jYWxlIiwicmVzdWx0IiwiZ2VuZXJhdGVDb25lcyIsInByZXNlcnZlRXhpc3RpbmciLCJvbmx5RW1wdHkiLCJ0b2tlbnNVc2VkIiwiZ2VuZXJhdGVUZW1wbGF0ZUNvbmVzIiwiYWxsRW50aXRpZXMiLCJnZXRBbGxFbnRpdGllcyIsInRvdGFsVG9rZW5zIiwiZXJyb3JzIiwiaWQiLCJlc3RpbWF0ZWRDb3N0IiwidG9GaXhlZCIsImVyciIsIm1vZGUiLCJnZW5lcmF0ZVRlbXBsYXRlIiwiaXNHbG9iYWwiLCJzb3VyY2VCYXNlIiwic291cmNlU2tpbGxzRGlyIiwic291cmNlQ2xhdWRlTWQiLCJob21lQ2xhdWRlRGlyIiwiaG9tZWRpciIsInNraWxsc19zeW5jX3RvIiwidXNlU3ltbGluayIsImNvcHlQcm9qZWN0VGVtcGxhdGVzIiwic291cmNlQ29tbWFuZHNEaXIiLCJzb3VyY2VDb21tYW5kIiwidGFyZ2V0Q29tbWFuZHNEaXIiLCJjeWFuIiwid29ya3NwYWNlUm9vdCIsImZpbmRXb3Jrc3BhY2VSb290IiwiY2xhdWRlRGlyIiwidGFyZ2V0U2tpbGxzRGlyIiwiZm9yY2UiLCJTdHJpbmciLCJza2lsbHNDb3B5Iiwic291cmNlUHJvamVjdERpciIsInRhcmdldFByb2plY3REaXIiLCJzZXR0aW5nc0xvY2FsUGF0aCIsInNldHRpbmdzQ29udGVudCIsImhvb2tzIiwiUG9zdFRvb2xVc2UiLCJtYXRjaGVyIiwiY29tbWFuZCIsIkpTT04iLCJzdHJpbmdpZnkiLCJ0YXJnZXRDbGF1ZGVNZCIsInJhd0NvbnRlbnQiLCJzb3VyY2VDb250ZW50IiwicmVwbGFjZUFsbCIsInRhcmdldENvbnRlbnQiLCJzdGFydE1hcmtlciIsImVuZE1hcmtlciIsInN0YXJ0SWR4IiwiZW5kSWR4IiwiYmVmb3JlIiwic3Vic3RyaW5nIiwiYWZ0ZXIiLCJuZXdDb250ZW50IiwiYXBwZW5kZWQiLCJ0cmltRW5kIiwid2l0aE1hcmtlcnMiLCJzcmMiLCJkZXN0IiwiY29weUVycm9yIiwibG9jYWxEaXIiLCJ0cmltIiwic2FuaXRpemVkIiwiTUFYX0xFTkdUSCIsIlJFU0VSVkVEX05BTUVTIiwidG9VcHBlckNhc2UiLCJmaWxlUGF0aCIsInRlbXBsYXRlIiwidG9JU09TdHJpbmciLCJwbHVnaW5zQXJnIiwiZmluZCIsInBsdWdpbnMiLCJwbHVnaW5WYWx1ZSIsInBsdWdpbklkcyIsInAiLCJkaXIiLCJwYWNrYWdlUGF0aCIs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
|
|
1168
|
+
//#endregion
|
|
1169
|
+
export { };
|
|
1170
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwibmFtZXMiOlsibWlncmF0b3I6IE1pZ3JhdG9yIiwib3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiIsImZpbHRlcmVkQXJndjogc3RyaW5nW10iLCJzcGF3biIsIm9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IGJvb2xlYW4gfCBzdHJpbmdbXT4gJiB7IF86IHN0cmluZ1tdIH0iLCJmaWxlTmFtZSIsIkVudGl0eU1hbmFnZXIiLCJlcnJvcnM6IHN0cmluZ1tdIiwiZW50aXR5IiwicGx1Z2luczogQmV0dGVyQXV0aFBsdWdpbklkW10iXSwic291cmNlcyI6WyIuLi8uLi9zcmMvYmluL2NsaS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgZG90ZW52IGZyb20gXCJkb3RlbnZcIjtcblxuZG90ZW52LmNvbmZpZygpO1xuXG5pbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IGV4ZWNTeW5jLCBzcGF3biB9IGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyBjcCwgbWtkaXIsIHJlYWRkaXIsIHJlYWRGaWxlLCBybSwgc3ltbGluaywgd3JpdGVGaWxlIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSBcIm1vZHVsZVwiO1xuaW1wb3J0IG9zIGZyb20gXCJvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCBwcm9jZXNzIGZyb20gXCJwcm9jZXNzXCI7XG5cbmltcG9ydCBrbmV4IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyB0eXBlIEtuZXggfSBmcm9tIFwia25leFwiO1xuaW1wb3J0IHsgdHNpY2xpIH0gZnJvbSBcInRzaWNsaVwiO1xuXG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpL3NvbmFtdVwiO1xuaW1wb3J0IHsgYWRkQ29tcGFuaW9uc1RvRW50aXRpZXMsIGdlbmVyYXRlQmV0dGVyQXV0aEVudGl0aWVzIH0gZnJvbSBcIi4uL2F1dGgvYXV0aC1nZW5lcmF0b3JcIjtcbmltcG9ydCB7IGlzVmFsaWRQbHVnaW5JZCwgU1VQUE9SVEVEX1BMVUdJTl9JRFMgfSBmcm9tIFwiLi4vYXV0aC9wbHVnaW5zL2VudGl0eS1kZWZpbml0aW9uc1wiO1xuaW1wb3J0IHsgdHlwZSBCZXR0ZXJBdXRoUGx1Z2luSWQgfSBmcm9tIFwiLi4vYXV0aC9wbHVnaW5zL2VudGl0eS1kZWZpbml0aW9uc1wiO1xuaW1wb3J0IHsgdHlwZSBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IE1pZ3JhdG9yIH0gZnJvbSBcIi4uL21pZ3JhdGlvbi9taWdyYXRvclwiO1xuaW1wb3J0IHsgRml4dHVyZU1hbmFnZXIgfSBmcm9tIFwiLi4vdGVzdGluZy9maXh0dXJlLW1hbmFnZXJcIjtcbmltcG9ydCB7XG4gIGV4ZWNXaXRoTGluZVByZWZpeCxcbiAgcHJpbnRCdWlsZFN1bW1hcnksXG4gIHByaW50VGFza0ZhaWxlZCxcbiAgcHJpbnRUYXNrSGVhZGVyLFxuICBwcmludFRhc2tTdGFydCxcbiAgcHJpbnRUYXNrU3VjY2Vzcyxcbn0gZnJvbSBcIi4uL3V0aWxzL2NvbnNvbGUtdXRpbFwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBmaW5kQXBpUm9vdFBhdGgsIGZpbmRBcHBSb290UGF0aCB9IGZyb20gXCIuLi91dGlscy91dGlsc1wiO1xuaW1wb3J0IHsgQVBJX0FSVElGQUNUUywgV0VCX0FSVElGQUNUUyB9IGZyb20gXCIuL2J1aWxkLWNvbmZpZ1wiO1xuaW1wb3J0IHsgdHlwZSBCdWlsZEFydGlmYWN0IH0gZnJvbSBcIi4vYnVpbGQtY29uZmlnXCI7XG5pbXBvcnQgeyBmaXh0dXJlRXhwbG9yZUNvbW1hbmQsIGZpeHR1cmVGZXRjaENvbW1hbmQsIGZpeHR1cmVHZW5Db21tYW5kIH0gZnJvbSBcIi4vZml4dHVyZVwiO1xuaW1wb3J0IHsgdGVzdENvbW1hbmQgfSBmcm9tIFwiLi90ZXN0LWNvbW1hbmRcIjtcblxubGV0IG1pZ3JhdG9yOiBNaWdyYXRvcjtcblxuLyoqXG4gKiBDTEkg7Ji17IWY7J2EIO2MjOyLse2VmOuKlCDtl6ztjbwg7ZWo7IiYXG4gKi9cbmZ1bmN0aW9uIHBhcnNlQ2xpT3B0aW9ucyhhcmd2OiBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndik6IHtcbiAgZmxhZ3M6IFNldDxzdHJpbmc+OyAvLyAtLXJlZ2VuZXJhdGUsIC0tYWksIC0tbm8tY29uZXMg65OxXG4gIG9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47IC8vIC0tbG9jYWxlIGtvIOuTsVxufSB7XG4gIGNvbnN0IGZsYWdzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGNvbnN0IG9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3YubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBhcmcgPSBhcmd2W2ldO1xuICAgIGlmICghYXJnLnN0YXJ0c1dpdGgoXCItLVwiKSkgY29udGludWU7XG5cbiAgICAvLyAtLW9wdGlvbj12YWx1ZSDtmJXsi51cbiAgICBpZiAoYXJnLmluY2x1ZGVzKFwiPVwiKSkge1xuICAgICAgY29uc3QgW2tleSwgdmFsdWVdID0gYXJnLnNsaWNlKDIpLnNwbGl0KFwiPVwiKTtcbiAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgLy8gLS1vcHRpb24gdmFsdWUg7ZiV7Iud7J247KeAIO2ZleyduFxuICAgIGNvbnN0IG5leHRBcmcgPSBhcmd2W2kgKyAxXTtcbiAgICBpZiAobmV4dEFyZyAmJiAhbmV4dEFyZy5zdGFydHNXaXRoKFwiLS1cIikgJiYgIW5leHRBcmcuc3RhcnRzV2l0aChcIi1cIikpIHtcbiAgICAgIG9wdGlvbnNbYXJnLnNsaWNlKDIpXSA9IG5leHRBcmc7XG4gICAgICBpKys7IC8vIOuLpOydjCBhcmfripQg6rCS7J2066+A66GcIOyKpO2CtVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyAtLWZsYWcg7ZiV7IudXG4gICAgICBmbGFncy5hZGQoYXJnLnNsaWNlKDIpKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4geyBmbGFncywgb3B0aW9ucyB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBib290c3RyYXAoKSB7XG4gIGNvbnN0IG5vdFRvSW5pdCA9IFtcImRldlwiLCBcImJ1aWxkXCIsIFwic3RhcnRcIiwgXCJza2lsbHNcIiwgXCJ0ZXN0XCJdLmluY2x1ZGVzKHByb2Nlc3MuYXJndlsyXSA/PyBcIlwiKTtcbiAgaWYgKCFub3RUb0luaXQpIHtcbiAgICBhd2FpdCBTb25hbXUuaW5pdChmYWxzZSwgZmFsc2UpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyB0c2ljbGnripQg7KCV7ZmV7ZWcIOuqheugueyWtCDrp6Tsua3rp4wg7KeA7JuQ7ZWY66+A66GcLCAtLeuhnCDsi5zsnpHtlZjripQg7Ji17IWY6rO8IOq3uCDqsJLsnYQg7ZWE7YSw66eB7ZWp64uI64ukLlxuICAgIC8vIOyYteyFmCDtjIzsi7HsnYAg6rCBIHJ1bm5lciDtlajsiJjsl5DshJwg7JuQ67O4IHByb2Nlc3MuYXJnduulvCDsgqzsmqntlZjsl6wg7IiY7ZaJ7ZWp64uI64ukLlxuICAgIC8vIFwiLS1cIihiYXJlIGRvdWJsZSBkYXNoKeuKlCBwYXNzdGhyb3VnaCDqtazrtoTsnpDsnbTrr4DroZwsIOq3uCDrkqTsnZgg66qo65OgIOyduOyekOuPhCDsoJzsmbjtlanri4jri6QuXG4gICAgY29uc3QgZmlsdGVyZWRBcmd2OiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBza2lwTmV4dCA9IGZhbHNlO1xuICAgIGxldCBhZnRlckRvdWJsZURhc2ggPSBmYWxzZTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHByb2Nlc3MuYXJndi5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgYXJnID0gcHJvY2Vzcy5hcmd2W2ldO1xuICAgICAgaWYgKGFyZyA9PT0gXCItLVwiKSB7XG4gICAgICAgIGFmdGVyRG91YmxlRGFzaCA9IHRydWU7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKGFmdGVyRG91YmxlRGFzaCkgY29udGludWU7XG4gICAgICBpZiAoc2tpcE5leHQpIHtcbiAgICAgICAgc2tpcE5leHQgPSBmYWxzZTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoYXJnLnN0YXJ0c1dpdGgoXCItLVwiKSkge1xuICAgICAgICAvLyAtLW9wdGlvbj12YWx1ZSDtmJXsi53snYAg7J20IGFyZ+unjCDsiqTtgrVcbiAgICAgICAgaWYgKGFyZy5pbmNsdWRlcyhcIj1cIikpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICAvLyAtLW9wdGlvbiB2YWx1ZSDtmJXsi53snbjsp4Ag7ZmV7J24OiDri6TsnYwgYXJn6rCAIC0t66GcIOyLnOyeke2VmOyngCDslYrsnLzrqbQg6rCS7J20IOyeiOuKlCDqsoNcbiAgICAgICAgY29uc3QgbmV4dEFyZyA9IHByb2Nlc3MuYXJndltpICsgMV07XG4gICAgICAgIGlmIChuZXh0QXJnICYmICFuZXh0QXJnLnN0YXJ0c1dpdGgoXCItLVwiKSAmJiAhbmV4dEFyZy5zdGFydHNXaXRoKFwiLVwiKSkge1xuICAgICAgICAgIHNraXBOZXh0ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGZpbHRlcmVkQXJndi5wdXNoKGFyZyk7XG4gICAgfVxuXG4gICAgLy8gYnVpbGQvZGV2IOuqheugueyWtOqwgCDshJzruIzsu6Trp6jrk5wg7JeG7J20IO2YuOy2nOuQoCDrlYwgXCJhbGxcIuydhCDquLDrs7jqsJLsnLzroZwg7LaU6rCA7ZWp64uI64ukLlxuICAgIC8vIOyYiDogYHNvbmFtdSBidWlsZGAg4oaSIGBzb25hbXUgYnVpbGQgYWxsYCwgYHNvbmFtdSBkZXZgIOKGkiBgc29uYW11IGRldiBhbGxgXG4gICAgY29uc3QgY21kID0gZmlsdGVyZWRBcmd2WzJdO1xuICAgIGlmICgoY21kID09PSBcImJ1aWxkXCIgfHwgY21kID09PSBcImRldlwiKSAmJiBmaWx0ZXJlZEFyZ3YubGVuZ3RoID09PSAzKSB7XG4gICAgICBmaWx0ZXJlZEFyZ3YucHVzaChcImFsbFwiKTtcbiAgICB9XG5cbiAgICAvLyB0ZXN0IOy7pOunqOuTnOuKlCDqsIDrs4Ag7J247J6QKO2MjOydvOuqhSwgLS1wYXR0ZXJuIOuTsSnrpbwg67Cb7Jy866+A66GcIHRzaWNsaeulvCDsmrDtmoztlanri4jri6QuXG4gICAgaWYgKGNtZCA9PT0gXCJ0ZXN0XCIpIHtcbiAgICAgIHJldHVybiB0ZXN0Q29tbWFuZCgpO1xuICAgIH1cblxuICAgIGF3YWl0IHRzaWNsaShmaWx0ZXJlZEFyZ3YsIHtcbiAgICAgIHR5cGVzOiB7XG4gICAgICAgIFwiI2VudGl0eUlkXCI6IHtcbiAgICAgICAgICB0eXBlOiBcImF1dG9jb21wbGV0ZVwiLFxuICAgICAgICAgIG5hbWU6IFwiI2VudGl0eUlkXCIsXG4gICAgICAgICAgbWVzc2FnZTogXCJQbGVhc2UgaW5wdXQgI2VudGl0eUlkXCIsXG4gICAgICAgICAgY2hvaWNlczogRW50aXR5TWFuYWdlci5nZXRBbGxQYXJlbnRJZHMoKS5tYXAoKGVudGl0eUlkKSA9PiAoe1xuICAgICAgICAgICAgdGl0bGU6IGVudGl0eUlkLFxuICAgICAgICAgICAgdmFsdWU6IGVudGl0eUlkLFxuICAgICAgICAgIH0pKSxcbiAgICAgICAgfSxcbiAgICAgICAgXCIjcmVjb3JkSWRzXCI6IFwibnVtYmVyW11cIixcbiAgICAgICAgXCIjbmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcIiN0YXJnZXRzXCI6IHtcbiAgICAgICAgICB0eXBlOiBcIm11bHRpc2VsZWN0XCIsXG4gICAgICAgICAgbmFtZTogXCIjdGFyZ2V0c1wiLFxuICAgICAgICAgIG1lc3NhZ2U6IFwiUGxlYXNlIGlucHV0ICN0YXJnZXRzXCIsXG4gICAgICAgICAgY2hvaWNlczogW1xuICAgICAgICAgICAgeyB0aXRsZTogXCJEZXZlbG9wbWVudFwiLCB2YWx1ZTogXCJkZXZlbG9wbWVudF9tYXN0ZXJcIiB9LFxuICAgICAgICAgICAgeyB0aXRsZTogXCJQcm9kdWN0aW9uXCIsIHZhbHVlOiBcInByb2R1Y3Rpb25fbWFzdGVyXCIgfSxcbiAgICAgICAgICAgIHsgdGl0bGU6IFwiRml4dHVyZVwiLCB2YWx1ZTogXCJmaXh0dXJlXCIgfSxcbiAgICAgICAgICAgIHsgdGl0bGU6IFwiVGVzdFwiLCB2YWx1ZTogXCJ0ZXN0XCIgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIGFyZ3M6IFtcbiAgICAgICAgW1wiZml4dHVyZVwiLCBcImluaXRcIl0sXG4gICAgICAgIFtcImZpeHR1cmVcIiwgXCJpbXBvcnRcIiwgXCIjZW50aXR5SWRcIiwgXCIjcmVjb3JkSWRzXCJdLFxuICAgICAgICBbXCJmaXh0dXJlXCIsIFwic3luY1wiXSxcbiAgICAgICAgW1wiZml4dHVyZVwiLCBcImdlblwiXSxcbiAgICAgICAgW1wiZml4dHVyZVwiLCBcImZldGNoXCJdLFxuICAgICAgICBbXCJmaXh0dXJlXCIsIFwiZXhwbG9yZVwiXSxcbiAgICAgICAgW1wibWlncmF0ZVwiLCBcInJ1blwiXSxcbiAgICAgICAgW1wibWlncmF0ZVwiLCBcImFwcGx5XCIsIFwiI3RhcmdldHNcIl0sXG4gICAgICAgIFtcIm1pZ3JhdGVcIiwgXCJnZW5lcmF0ZVwiXSxcbiAgICAgICAgW1wibWlncmF0ZVwiLCBcInN0YXR1c1wiXSxcbiAgICAgICAgW1wic3R1YlwiLCBcInByYWN0aWNlXCIsIFwiI25hbWVcIl0sXG4gICAgICAgIFtcInN0dWJcIiwgXCJlbnRpdHlcIiwgXCIjbmFtZVwiXSxcbiAgICAgICAgW1wic2NhZmZvbGRcIiwgXCJtb2RlbFwiLCBcIiNlbnRpdHlJZFwiXSxcbiAgICAgICAgW1wic2NhZmZvbGRcIiwgXCJtb2RlbF90ZXN0XCIsIFwiI2VudGl0eUlkXCJdLFxuICAgICAgICBbXCJzY2FmZm9sZFwiLCBcInZpZXdfbGlzdFwiLCBcIiNlbnRpdHlJZFwiXSxcbiAgICAgICAgW1wic2NhZmZvbGRcIiwgXCJ2aWV3X2Zvcm1cIiwgXCIjZW50aXR5SWRcIl0sXG4gICAgICAgIFtcImNvbmVcIiwgXCJnZW5cIiwgXCIjZW50aXR5SWRcIl0sXG4gICAgICAgIFtcInN5bmNcIl0sXG4gICAgICAgIFtcImJ1aWxkXCIsIFwiYWxsXCJdLFxuICAgICAgICBbXCJidWlsZFwiLCBcImFwaVwiXSxcbiAgICAgICAgW1wiYnVpbGRcIiwgXCJ3ZWJcIl0sXG4gICAgICAgIFtcImRldlwiLCBcImFsbFwiXSxcbiAgICAgICAgW1wiZGV2XCIsIFwiYXBpXCJdLFxuICAgICAgICBbXCJkZXZcIiwgXCJ3ZWJcIl0sXG4gICAgICAgIFtcInN0YXJ0XCJdLFxuICAgICAgICBbXCJza2lsbHNcIiwgXCJzeW5jXCJdLFxuICAgICAgICBbXCJza2lsbHNcIiwgXCJjcmVhdGVcIiwgXCIjbmFtZVwiXSxcbiAgICAgICAgW1widGVzdFwiXSxcbiAgICAgICAgW1wiYXV0aFwiLCBcImdlbmVyYXRlXCJdLFxuICAgICAgICBbXCJhdXRoXCIsIFwiYWRkLWNvbXBhbmlvbnNcIl0sXG4gICAgICBdLFxuICAgICAgcnVubmVyczoge1xuICAgICAgICBtaWdyYXRlX3N0YXR1cyxcbiAgICAgICAgbWlncmF0ZV9ydW4sXG4gICAgICAgIG1pZ3JhdGVfYXBwbHksXG4gICAgICAgIG1pZ3JhdGVfZ2VuZXJhdGUsXG4gICAgICAgIGZpeHR1cmVfaW5pdCxcbiAgICAgICAgZml4dHVyZV9pbXBvcnQsXG4gICAgICAgIGZpeHR1cmVfc3luYyxcbiAgICAgICAgZml4dHVyZV9nZW4sXG4gICAgICAgIGZpeHR1cmVfZmV0Y2gsXG4gICAgICAgIGZpeHR1cmVfZXhwbG9yZSxcbiAgICAgICAgc3R1Yl9wcmFjdGljZSxcbiAgICAgICAgc3R1Yl9lbnRpdHksXG4gICAgICAgIHNjYWZmb2xkX21vZGVsLFxuICAgICAgICBzY2FmZm9sZF9tb2RlbF90ZXN0LFxuICAgICAgICAvLyBzY2FmZm9sZF92aWV3X2xpc3QsXG4gICAgICAgIC8vIHNjYWZmb2xkX3ZpZXdfZm9ybSxcbiAgICAgICAgY29uZV9nZW4sXG4gICAgICAgIHN5bmMsXG4gICAgICAgIGJ1aWxkX2FsbCxcbiAgICAgICAgYnVpbGRfYXBpLFxuICAgICAgICBidWlsZF93ZWIsXG4gICAgICAgIGRldl9hbGwsXG4gICAgICAgIGRldl9hcGksXG4gICAgICAgIGRldl93ZWIsXG4gICAgICAgIHN0YXJ0LFxuICAgICAgICBza2lsbHNfc3luYyxcbiAgICAgICAgc2tpbGxzX2NyZWF0ZSxcbiAgICAgICAgdGVzdDogdGVzdENvbW1hbmQsXG4gICAgICAgIGF1dGhfZ2VuZXJhdGUsXG4gICAgICAgIFwiYXV0aF9hZGQtY29tcGFuaW9uc1wiOiBhdXRoX2FkZF9jb21wYW5pb25zLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBTb25hbXUuZGVzdHJveSgpO1xuICB9XG59XG5cbmJvb3RzdHJhcCgpLmZpbmFsbHkoYXN5bmMgKCkgPT4ge1xuICBhd2FpdCBGaXh0dXJlTWFuYWdlci5kZXN0cm95KCk7XG59KTtcblxuLyoqXG4gKiBwbnBtIHN5bmMg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiDtlITroZzsoJ3tirjrpbwg7Iux7YGs7ZWp64uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBzeW5jKCkge1xuICBhd2FpdCBTb25hbXUuc3luY2VyLnN5bmMoKTtcbn1cblxuLyoqXG4gKiBBUEkg6rCc67CcIOyEnOuyhOulvCDsi6TtlontlZjripQg6rO17Ya1IOuhnOyngeyeheuLiOuLpC5cbiAqIGRldl9hbGzqs7wgZGV2X2FwaeyXkOyEnCDqs7XsnKDtlanri4jri6QuXG4gKlxuICogVHlwZVNjcmlwdOulvCDrsJTroZwg7Iuk7ZaJ7ZWgIOyImCDsnojrj4TroZ0gQHNvbmFtdS1raXQvdHMtbG9hZGVy66W8LFxuICogSE1S7J2EIOyngOybkO2VmOq4sCDsnITtlbQgQHNvbmFtdS1raXQvaG1yLWhvb2vsnYQgaW1wb3J07ZWY66mwLFxuICog7IaM7Iqk66e1IOyngOybkOydhCDsnITtlbQgLS1lbmFibGUtc291cmNlLW1hcHMg7ZSM656Y6re466W8IO2PrO2VqO2VmOyXrCDsi6Ttlontlanri4jri6QuXG4gKlxuICog7J2065WMIEBzb25hbXUta2l0L3RzLWxvYWRlcuyZgCBAc29uYW11LWtpdC9obXItaG9va+uKlCBzb25hbXXqsIAg7J6Q7LK07KCB7Jy866GcIOqwgOyngOqzoCDsnojripQgZGVwZW5kZW5jeeyeheuLiOuLpC5cbiAqIOuYkO2VnCDsi6Ttlonsl5Ag7IKs7Jqp7ZWY64qUIEBzb25hbXUta2l0L2htci1ydW5uZXLrj4Qg66eI7LCs6rCA7KeA66GcIHNvbmFtdeqwgCDsnpDssrTsoIHsnLzroZwg6rCA7KeA6rOgIOyeiOuKlCBkZXBlbmRlbmN57J6F64uI64ukLlxuICog65Sw65287IScIOyCrOyaqeyekCDtlITroZzsoJ3tirjsl5DshJzripQg7J20IOyEuCDtjKjtgqTsp4Drpbwg7KeB7KCRIOyEpOy5mO2VoCDtlYTsmpTqsIAg7JeG7Iq164uI64ukLlxuICovXG5mdW5jdGlvbiBzcGF3bkFwaURldlNlcnZlcihvcHRpb25zPzogeyBleHRyYUVudj86IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfSkge1xuICBjb25zdCBhcGlSb290ID0gZmluZEFwaVJvb3RQYXRoKCk7XG4gIGNvbnN0IGVudHJ5UG9pbnQgPSBcInNyYy9pbmRleC50c1wiO1xuXG4gIC8vIOydtCBzb25hbXUg7Yyo7YKk7KeA6rCAIGRlcGVuZGVuY2llc+uhnCDqsIDsp4Dqs6Ag7J6I64qUIEBzb25hbXUta2l0L2htci1ydW5uZXLsnZggYmluL3J1bi5qc+ulvCDsgqzsmqntlanri4jri6QuXG4gIC8vIOydtCDqsr3roZwoL2Jpbi9ydW4uanMp64qUIEBzb25hbXUta2l0L2htci1ydW5uZXLsnZggcGFja2FnZS5qc29u7J2YIGJpbiDtlYTrk5zsl5Ag66qF7Iuc65CY7Ja0IOyeiOuKlCDqt7jqsoPqs7wg6rCZ7Iq164uI64ukLlxuICBjb25zdCBob3RSdW5uZXJCaW5QYXRoID0gY3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpLnJlc29sdmUoXG4gICAgXCJAc29uYW11LWtpdC9obXItcnVubmVyL2Jpbi9ydW4uanNcIixcbiAgKTtcblxuICBjb25zdCBzZXJ2ZXJQcm9jZXNzID0gc3Bhd24oXG4gICAgcHJvY2Vzcy5leGVjUGF0aCwgLy8gbm9kZVxuICAgIFtcbiAgICAgIGhvdFJ1bm5lckJpblBhdGgsIC8vIOydtOugh+qyjCDtlbTshJwgaG90LXJ1bm5lcuulvCDsi6TtlontlZjqtazsmpRcbiAgICAgIFwiLS1jbGVhci1zY3JlZW49ZmFsc2VcIiwgLy8g7J207ZWYIGhvdC1ydW5uZXLsl5Dqsowg64SY6rKo7KSEIOyduOyekOuTpOyeheuLiOuLpC5cbiAgICAgIFwiLS1ub2RlLWFyZ3M9LS1pbXBvcnQ9c29uYW11L3RzLWxvYWRlci1yZWdpc3RlclwiLCAvLyBUeXBlU2NyaXB0IOyEnO2PrO2KuOulvCDsnITtlZwg66Gc642ULFxuICAgICAgXCItLW5vZGUtYXJncz0tLWltcG9ydD1zb25hbXUvaG1yLWhvb2stcmVnaXN0ZXJcIiwgLy8gSE1S7J2EIOyngOybkO2VmOq4sCDsnITtlZwgaG9vayxcbiAgICAgIFwiLS1ub2RlLWFyZ3M9LS1lbmFibGUtc291cmNlLW1hcHNcIiwgLy8g6re466as6rOgIOyGjOyKpOuntSDsp4Dsm5DsnYQg7JyE7ZWcIO2UjOuemOq3uOyeheuLiOuLpC5cbiAgICAgIFwiLS1vbi1rZXk9cjpyZXN0YXJ0OlJlc3RhcnQgc2VydmVyXCIsIC8vIHIg64iE66W066m0IOyEnOuyhCDsnqzsi5zsnpHtlZjqsowg7ZW07KSY7JqULlxuICAgICAgXCItLW9uLWtleT1jOmNsZWFyOkNsZWFyIHNjcmVlblwiLCAvLyBjIOuIhOultOuptCDthLDrr7jrhJAg7ZmU66m07J2EIOyngOybjOykmOyalC5cbiAgICAgIGAtLW9uLWtleT1mOnNoZWxsKHJtICR7cGF0aC5qb2luKGFwaVJvb3QsIFwic29uYW11LmxvY2tcIil9KTpyZXN0YXJ0OkZvcmNlIHJlc3RhcnRgLCAvLyBmIOuIhOultOuptCBzb25hbXUubG9jayDtjIzsnbzsnYQg7KeA7Jqw6rOgIOyEnOuyhCDsnqzsi5zsnpHtlZjqsowg7ZW07KSY7JqULlxuXG4gICAgICBcIi0tb24ta2V5PWVudGVyOnNoZWxsKGVjaG8gaGkpOktleSBiaW5kaW5nIHRlc3RcIiwgLy8gZW50ZXLrpbwga2V566GcIOyTuCDsiJgg7J6I7J2M7J2EIOuztOydtOq4sCDsnITtlZwg7YWM7Iqk7Yq47J6F64uI64ukLlxuICAgICAgXCItLW9uLWtleT1jdHJsK2YgY3RybCtmOnNoZWxsKGdpdCBwdWxsICYmIHBucG0gaW5zdGFsbCAmJiBwbnBtIC0tZmlsdGVyIHNvbmFtdSBidWlsZCAmJiBlY2hvICdTb25hbXUgaXMgbm93IHVwLXRvLWRhdGUhJyk6cmVzdGFydDpQdWxsICYgaW5zdGFsbCAmIGJ1aWxkICYgcmVzdGFydFwiLCAvLyBtb2RpZmllcuyZgOydmCDsobDtlaksIOq3uOumrOqzoCDrkZAg6rCc7J2YIGNob3Jk66W8IOyCrOyaqe2VoCDsiJgg7J6I7J2M7J2EIOuztOydtOq4sCDsnITtlZwg7YWM7Iqk7Yq47J6F64uI64ukLlxuICAgICAgZW50cnlQb2ludCwgLy8g66eI7KeA66eJ7Jy866GcIOyLpOygnCDsi6TtlontlaAg7Iqk7YGs66a97Yq47J2YIOqyveuhnOulvCDrhJjqsqjspI3ri4jri6QuXG4gICAgXSxcbiAgICB7XG4gICAgICBjd2Q6IGFwaVJvb3QsXG4gICAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gICAgICBlbnY6IHtcbiAgICAgICAgLi4ucHJvY2Vzcy5lbnYsXG4gICAgICAgIE5PREVfRU5WOiBcImRldmVsb3BtZW50XCIsXG4gICAgICAgIEhPVDogXCJ5ZXNcIiwgLy8g7JaY6rCAIOyeiOyWtOyVvCBITVLsnbQg7Zmc7ISx7ZmU65Cp64uI64ukLlxuICAgICAgICBBUElfUk9PVF9QQVRIOiBhcGlSb290LCAvLyDsnbQg6rK966Gc6rCAIGhtci1ob29r7J2YIOujqO2KuCDrlJTroInthqDrpqzqsIAg65Cp64uI64ukLlxuICAgICAgICAuLi5vcHRpb25zPy5leHRyYUVudixcbiAgICAgIH0sXG4gICAgfSxcbiAgKTtcblxuICAvLyDsooXro4wg7LKY66asXG4gIGNvbnN0IGNsZWFudXAgPSAoKSA9PiB7XG4gICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KFwiXFxuXFxu8J+RiyBTaHV0dGluZyBkb3duLi4uXCIpKTtcbiAgICBzZXJ2ZXJQcm9jZXNzLmtpbGwoXCJTSUdURVJNXCIpO1xuICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgfTtcblxuICBwcm9jZXNzLm9uKFwiU0lHSU5UXCIsIGNsZWFudXApO1xuICBwcm9jZXNzLm9uKFwiU0lHVEVSTVwiLCBjbGVhbnVwKTtcblxuICBzZXJ2ZXJQcm9jZXNzLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgIGlmIChjb2RlICE9PSAwKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGNoYWxrLnJlZChgU2VydmVyIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfWApKTtcbiAgICAgIHByb2Nlc3MuZXhpdChjb2RlIHx8IDEpO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogcG5wbSBkZXYgLyBwbnBtIGRldiBhbGwg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiDtlITroZzsoJ3tirjsl5Ag64yA7ZW0IEhNUiDsp4Dsm5DtlZjripQg6rCc67CcIOyEnOuyhOulvCDrnYTsm4zspI3ri4jri6QuXG4gKlxuICogU29uYW11LmluaXQg7JeG7J20IO2YuOy2nOuQoCDqsoPsnYQg7IOB7KCV7ZWY7JesIOq1rO2YhOuQmOyXiOyKteuLiOuLpC5cbiAqL1xuZnVuY3Rpb24gZGV2X2FsbCgpIHtcbiAgY29uc29sZS5sb2coY2hhbGsueWVsbG93LmJvbGQoXCJTdGFydGluZyBTb25hbXUgZGV2IHNlcnZlci4uLlxcblwiKSk7XG4gIHNwYXduQXBpRGV2U2VydmVyKCk7XG59XG5cbi8qKlxuICogcG5wbSBkZXYgYXBpIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICogQVBJIOyghOyaqSDqsJzrsJwg7ISc67KE66W8IOudhOybgeuLiOuLpC5cbiAqIGRldl9hbGzqs7wg6rGw7J2YIOuPmeydvO2VmOuQmCwg7Ya17ZWpIOybuSDshJzrsoTrpbwg67mE7Zmc7ISx7ZmU7ZWp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmZ1bmN0aW9uIGRldl9hcGkoKSB7XG4gIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdy5ib2xkKFwiU3RhcnRpbmcgU29uYW11IEFQSS1vbmx5IGRldiBzZXJ2ZXIuLi5cXG5cIikpO1xuICBzcGF3bkFwaURldlNlcnZlcih7XG4gICAgZXh0cmFFbnY6IHsgU09OQU1VX0RJU0FCTEVfSU5URUdSQVRFRF9XRUI6IFwieWVzXCIgfSxcbiAgfSk7XG59XG5cbi8qKlxuICogcG5wbSBkZXYgd2ViIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICogVml0ZSDqsJzrsJwg7ISc67KE66W8IOuLqOuPheycvOuhnCDsi6Ttlontlanri4jri6QuXG4gKiAtLSDrkqTsnZgg7J247J6Q64qUIFZpdGXsl5Ag6re464yA66GcIOyghOuLrOuQqeuLiOuLpC5cbiAqXG4gKiBTb25hbXUuaW5pdCDsl4bsnbQg7Zi47Lac65CgIOqyg+ydhCDsg4HsoJXtlZjsl6wg6rWs7ZiE65CY7JeI7Iq164uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBkZXZfd2ViKCkge1xuICBjb25zdCBhcHBSb290ID0gZmluZEFwcFJvb3RQYXRoKCk7XG4gIGNvbnN0IHdlYlBhdGggPSBwYXRoLmpvaW4oYXBwUm9vdCwgXCJ3ZWJcIik7XG5cbiAgaWYgKCEoYXdhaXQgZXhpc3RzKHdlYlBhdGgpKSkge1xuICAgIGNvbnNvbGUuZXJyb3IoYHdlYiDrlJTroInthqDrpqzrpbwg7LC+7J2EIOyImCDsl4bsirXri4jri6Q6ICR7d2ViUGF0aH1gKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cblxuICAvLyAtLSDrkqTsnZgg7J247J6QIOy2lOy2nFxuICBjb25zdCBkb3VibGVEYXNoSW5kZXggPSBwcm9jZXNzLmFyZ3YuaW5kZXhPZihcIi0tXCIpO1xuICBjb25zdCBwYXNzdGhyb3VnaEFyZ3MgPSBkb3VibGVEYXNoSW5kZXggIT09IC0xID8gcHJvY2Vzcy5hcmd2LnNsaWNlKGRvdWJsZURhc2hJbmRleCArIDEpIDogW107XG5cbiAgY29uc3Qgdml0ZUFyZ3MgPSBbXCJleGVjXCIsIFwidml0ZVwiLCAuLi5wYXNzdGhyb3VnaEFyZ3NdO1xuXG4gIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdy5ib2xkKFwiU3RhcnRpbmcgVml0ZSBkZXYgc2VydmVyLi4uXFxuXCIpKTtcblxuICBjb25zdCB2aXRlUHJvY2VzcyA9IHNwYXduKFwicG5wbVwiLCB2aXRlQXJncywge1xuICAgIGN3ZDogd2ViUGF0aCxcbiAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gIH0pO1xuXG4gIHZpdGVQcm9jZXNzLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgIHByb2Nlc3MuZXhpdChjb2RlID8/IDApO1xuICB9KTtcblxuICAvLyBTSUdJTlQvU0lHVEVSTSDsi5wgVml0ZSDtlITroZzshLjsiqTrpbwgZ3JhY2VmdWxseSDsooXro4ztlanri4jri6QuXG4gIGZvciAoY29uc3Qgc2lnbmFsIG9mIFtcIlNJR0lOVFwiLCBcIlNJR1RFUk1cIl0gYXMgY29uc3QpIHtcbiAgICBwcm9jZXNzLm9uKHNpZ25hbCwgKCkgPT4ge1xuICAgICAgdml0ZVByb2Nlc3Mua2lsbChzaWduYWwpO1xuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogQVBJIOu5jOuTnCDshKTsoJUg7YyM7J28IOqyveuhnOulvCDqsrDsoJXtlanri4jri6QuXG4gKiDtlITroZzsoJ3tirgg66Oo7Yq47JeQIGB0c2Rvd24uY29uZmlnLnRzYOqwgCDsnojsnLzrqbQg6re46rKD7J2ELCDsl4bsnLzrqbQgc29uYW11IOq4sOuzuCDshKTsoJXsnYQg7IKs7Jqp7ZWp64uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQXBpQnVpbGRDb25maWdQYXRoKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IGxvY2FsQ29uZmlnUGF0aCA9IHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCBcInRzZG93bi5jb25maWcudHNcIik7XG5cbiAgdHJ5IHtcbiAgICBpZiAoYXdhaXQgZXhpc3RzKGxvY2FsQ29uZmlnUGF0aCkpIHtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmRpbShcIlVzaW5nIHRzZG93bi5jb25maWcudHMgZnJvbSBwcm9qZWN0IHJvb3QuLi5cIikpO1xuICAgICAgcmV0dXJuIGxvY2FsQ29uZmlnUGF0aDtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oXCJVc2luZyBkZWZhdWx0IHRzZG93biBBUEkgY29uZmlnIGZyb20gc29uYW11IHBhY2thZ2UuLi5cIikpO1xuICAgIHJldHVybiBwYXRoLmpvaW4oaW1wb3J0Lm1ldGEuZGlybmFtZSwgXCIuLlwiLCBcIi4uXCIsIFwidHNkb3duLmFwaS5jb25maWcudHNcIik7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihjaGFsay5yZWQoXCJTZXR0aW5nIHVwIEFQSSBidWlsZCBjb25maWcgZmFpbGVkLlwiKSwgZXJyb3IpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG4vKipcbiAqIHNvbmFtdSBidWlsZCAvIHNvbmFtdSBidWlsZCBhbGwg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiBidWlsZF9hcGkgKyBidWlsZF93ZWLsnZgg7ZWp7ISx7J6F64uI64ukLiBXZWIg65SU66CJ7Yag66as6rCAIOyXhuycvOuptCBXZWIg67mM65Oc66W8IOyKpO2Cte2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYnVpbGRfYWxsKCkge1xuICBhd2FpdCBidWlsZF9hcGkoKTtcbiAgYXdhaXQgYnVpbGRfd2ViKHsgc2tpcElmTWlzc2luZzogdHJ1ZSB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIGJ1aWxkIGFwaSDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIEFQSSDtlITroZzsoJ3tirjrp4wg67mM65Oc7ZWp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkX2FwaSgpIHtcbiAgY29uc3QgYXBwUm9vdCA9IGZpbmRBcHBSb290UGF0aCgpO1xuICBjb25zdCBjb25maWdGaWxlUGF0aCA9IGF3YWl0IHJlc29sdmVBcGlCdWlsZENvbmZpZ1BhdGgoKTtcblxuICBjb25zdCBhcGlTdGFydGVkQXQgPSBEYXRlLm5vdygpO1xuICB0cnkge1xuICAgIGZvciAoY29uc3QgYXJ0aWZhY3Qgb2YgQVBJX0FSVElGQUNUUykge1xuICAgICAgY29uc3QgY3dkID0gcGF0aC5qb2luKGFwcFJvb3QsIGFydGlmYWN0LnByb2plY3RQYXRoKTtcbiAgICAgIHByaW50VGFza0hlYWRlcihhcnRpZmFjdC5uYW1lLCBhcnRpZmFjdC5kZXNjcmlwdGlvbiwgY3dkKTtcblxuICAgICAgYXdhaXQgcnVuQnVpbGRTdGVwcyhhcnRpZmFjdCwgeyBjd2QsIGJ1aWxkQ29tbWFuZEFyZ3M6IHsgY29uZmlnRmlsZVBhdGggfSB9KTtcbiAgICB9XG4gICAgcHJpbnRCdWlsZFN1bW1hcnkoXCJBUElcIiwgdHJ1ZSwgRGF0ZS5ub3coKSAtIGFwaVN0YXJ0ZWRBdCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBwcmludEJ1aWxkU3VtbWFyeShcIkFQSVwiLCBmYWxzZSwgRGF0ZS5ub3coKSAtIGFwaVN0YXJ0ZWRBdCk7XG4gICAgY29uc29sZS5lcnJvcihlKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbn1cblxuLyoqXG4gKiBwbnBtIGJ1aWxkIHdlYiDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIFdlYiDtlITroZzsoJ3tirjrp4wg67mM65Oc7ZWp64uI64ukLlxuICpcbiAqIFNvbmFtdS5pbml0IOyXhuydtCDtmLjstpzrkKAg6rKD7J2EIOyDgeygle2VmOyXrCDqtaztmITrkJjsl4jsirXri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkX3dlYih7IHNraXBJZk1pc3NpbmcgPSBmYWxzZSB9ID0ge30pIHtcbiAgY29uc3QgYXBwUm9vdCA9IGZpbmRBcHBSb290UGF0aCgpO1xuICBjb25zdCB3ZWJQYXRoID0gcGF0aC5qb2luKGFwcFJvb3QsIFwid2ViXCIpO1xuXG4gIGlmICghKGF3YWl0IGV4aXN0cyh3ZWJQYXRoKSkpIHtcbiAgICBpZiAoc2tpcElmTWlzc2luZykge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JheShcIldlYiDrlJTroInthqDrpqzqsIAg7JeG7Jy866+A66GcIFdlYiDruYzrk5zrpbwg6rG064SI65yB64uI64ukLlwiKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnNvbGUuZXJyb3IoYHdlYiDrlJTroInthqDrpqzrpbwg7LC+7J2EIOyImCDsl4bsirXri4jri6Q6ICR7d2ViUGF0aH1gKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cblxuICBjb25zdCB3ZWJTdGFydGVkQXQgPSBEYXRlLm5vdygpO1xuICB0cnkge1xuICAgIGZvciAoY29uc3QgYXJ0aWZhY3Qgb2YgV0VCX0FSVElGQUNUUykge1xuICAgICAgY29uc3QgY3dkID0gcGF0aC5qb2luKGFwcFJvb3QsIGFydGlmYWN0LnByb2plY3RQYXRoKTtcbiAgICAgIHByaW50VGFza0hlYWRlcihhcnRpZmFjdC5uYW1lLCBhcnRpZmFjdC5kZXNjcmlwdGlvbiwgY3dkKTtcblxuICAgICAgYXdhaXQgcnVuQnVpbGRTdGVwcyhhcnRpZmFjdCwgeyBjd2QsIGJ1aWxkQ29tbWFuZEFyZ3M6IHt9IH0pO1xuICAgIH1cbiAgICBwcmludEJ1aWxkU3VtbWFyeShcIldlYlwiLCB0cnVlLCBEYXRlLm5vdygpIC0gd2ViU3RhcnRlZEF0KTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHByaW50QnVpbGRTdW1tYXJ5KFwiV2ViXCIsIGZhbHNlLCBEYXRlLm5vdygpIC0gd2ViU3RhcnRlZEF0KTtcbiAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG4vKipcbiAqIHByZS1idWlsZCwgYnVpbGQsIHBvc3QtYnVpbGQg64uo6rOE66W8IOyInOywqOyggeycvOuhnCDsi6Ttlontlanri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJ1bkJ1aWxkU3RlcHM8VD4oXG4gIGFydGlmYWN0OiBCdWlsZEFydGlmYWN0PFQ+LFxuICBvcHRpb25zOiB7IGN3ZDogc3RyaW5nOyBidWlsZENvbW1hbmRBcmdzOiBUIH0sXG4pIHtcbiAgY29uc3Qgc3RlcHMgPSBbXG4gICAgeyBuYW1lOiBcInByZS1idWlsZFwiLCBjbWQ6IGFydGlmYWN0LnByZUJ1aWxkQ29tbWFuZD8uKCkgfSxcbiAgICB7IG5hbWU6IFwiYnVpbGRcIiwgY21kOiBhcnRpZmFjdC5idWlsZENvbW1hbmQob3B0aW9ucy5idWlsZENvbW1hbmRBcmdzKSB9LFxuICAgIHsgbmFtZTogXCJwb3N0LWJ1aWxkXCIsIGNtZDogYXJ0aWZhY3QucG9zdEJ1aWxkQ29tbWFuZD8uKCkgfSxcbiAgXS5maWx0ZXIoKHN0ZXApID0+IHN0ZXAuY21kKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ZXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qgc3RlcCA9IHN0ZXBzW2ldO1xuICAgIGNvbnN0IGlzTGFzdCA9IGkgPT09IHN0ZXBzLmxlbmd0aCAtIDE7XG5cbiAgICB0cnkge1xuICAgICAgYXNzZXJ0KHN0ZXAuY21kKTtcbiAgICAgIHByaW50VGFza1N0YXJ0KHN0ZXAubmFtZSwgc3RlcC5jbWQsIGlzTGFzdCk7XG4gICAgICBhd2FpdCBleGVjV2l0aExpbmVQcmVmaXgoc3RlcC5jbWQsIHsgY3dkOiBvcHRpb25zLmN3ZCB9KTtcbiAgICAgIHByaW50VGFza1N1Y2Nlc3Moc3RlcC5uYW1lLCBpc0xhc3QpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHByaW50VGFza0ZhaWxlZChzdGVwLm5hbWUsIGlzTGFzdCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7c3RlcC5uYW1lfSBmYWlsZWRgLCB7IGNhdXNlOiBlIH0pO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIHBucG0gc3RhcnQg7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiDruYzrk5zrkJwg7ZSE66Gc7KCd7Yq466W8IOyLpO2Wie2VqeuLiOuLpC5cbiAqXG4gKiDruYzrk5zrkJwg6rKw6rO866y8KGRpc3Qg65SU66CJ7Yag66as7J2YIGluZGV4LmpzIOyXlO2KuOumrO2PrOyduO2KuCnsnbQg7JeG64uk66m0IOyLpO2WieydhCDspJHri6jtlanri4jri6QuXG4gKiDshozsiqTrp7Ug7KeA7JuQ6rO8IGRvdGVudiDsp4Dsm5DsnYQg7Y+s7ZWo7ZWY7JesIOyLpO2Wie2VqeuLiOuLpC5cbiAqXG4gKiBTb25hbXUuaW5pdCDsl4bsnbQg7Zi47Lac65CgIOqyg+ydhCDsg4HsoJXtlZjsl6wg6rWs7ZiE65CY7JeI7Iq164uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdGFydCgpIHtcbiAgY29uc3QgYXBpUm9vdCA9IGZpbmRBcGlSb290UGF0aCgpO1xuICBjb25zdCBlbnRyeVBvaW50ID0gXCJkaXN0L2luZGV4LmpzXCI7XG5cbiAgaWYgKCEoYXdhaXQgZXhpc3RzKGVudHJ5UG9pbnQpKSkge1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLnJlZChgJHtlbnRyeVBvaW50fSBub3QgZm91bmQuIFBsZWFzZSBidWlsZCB5b3VyIHByb2plY3QgZmlyc3QuYCkpO1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLmJsdWUoXCJSdW46IHBucG0gc29uYW11IGJ1aWxkXCIpKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7IHNwYXduIH0gPSBhd2FpdCBpbXBvcnQoXCJjaGlsZF9wcm9jZXNzXCIpO1xuICBjb25zdCBzZXJ2ZXJQcm9jZXNzID0gc3Bhd24oXG4gICAgcHJvY2Vzcy5leGVjUGF0aCxcbiAgICBbXCItLWVuYWJsZS1zb3VyY2UtbWFwc1wiLCBcIi1yXCIsIFwiZG90ZW52L2NvbmZpZ1wiLCBlbnRyeVBvaW50XSxcbiAgICB7XG4gICAgICBjd2Q6IGFwaVJvb3QsXG4gICAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gICAgfSxcbiAgKTtcblxuICBwcm9jZXNzLm9uKFwiU0lHSU5UXCIsICgpID0+IHtcbiAgICBzZXJ2ZXJQcm9jZXNzLmtpbGwoXCJTSUdURVJNXCIpO1xuICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNldHVwTWlncmF0b3IoKSB7XG4gIC8vIG1pZ3JhdG9yXG4gIG1pZ3JhdG9yID0gbmV3IE1pZ3JhdG9yKCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNldHVwRml4dHVyZU1hbmFnZXIoKSB7XG4gIEZpeHR1cmVNYW5hZ2VyLmluaXQoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWlncmF0ZV9hcHBseSh0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10pIHtcbiAgYXdhaXQgc2V0dXBNaWdyYXRvcigpO1xuICBhd2FpdCBtaWdyYXRvci5ydW5BY3Rpb24oXCJhcHBseVwiLCB0YXJnZXRzKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWlncmF0ZV9ydW4oKSB7XG4gIGF3YWl0IHNldHVwTWlncmF0b3IoKTtcbiAgY29uc3QgbG9jYWxIb3N0cyA9IFtcImxvY2FsaG9zdFwiLCBcIjEyNy4wLjAuMVwiLCBcIjAuMC4wLjBcIiwgXCI6OjFcIl07XG4gIGNvbnN0IHRhcmdldHMgPSBPYmplY3Qua2V5cyhTb25hbXUuZGJDb25maWcpLmZpbHRlcigodGFyZ2V0KSA9PiB7XG4gICAgY29uc3QgdGFyZ2V0Q29uZmlnID0gU29uYW11LmRiQ29uZmlnW3RhcmdldCBhcyBrZXlvZiBTb25hbXVEQkNvbmZpZ107XG4gICAgY29uc3QgaG9zdCA9ICh0YXJnZXRDb25maWc/LmNvbm5lY3Rpb24gYXMgeyBob3N0Pzogc3RyaW5nIH0pPy5ob3N0ID8/IFwibG9jYWxob3N0XCI7XG4gICAgcmV0dXJuIGxvY2FsSG9zdHMuaW5jbHVkZXMoaG9zdC50b0xvd2VyQ2FzZSgpKTtcbiAgfSk7XG5cbiAgLy8g66Gc7LusIOuNsOydtO2EsOuyoOydtOyKpOyXkCDrjIDtlbTshJzrp4wg7KCE7LK0IOuniOydtOq3uOugiOydtOyFmOyXkOyEnCDrj5nsnpFcbiAgYXdhaXQgbWlncmF0b3IucnVuQWN0aW9uKFwiYXBwbHlcIiwgdGFyZ2V0cyBhcyAoa2V5b2YgU29uYW11REJDb25maWcpW10pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlX2dlbmVyYXRlKCkge1xuICBhd2FpdCBzZXR1cE1pZ3JhdG9yKCk7XG5cbiAgY29uc3QgeyBjb25ucyB9ID0gYXdhaXQgbWlncmF0b3IuZ2V0U3RhdHVzKCk7XG4gIGNvbnN0IGhhc1N0YXR1czAgPSBjb25ucy5zb21lKChjb25uKSA9PiBjb25uLnN0YXR1cyA9PT0gMCk7XG4gIGlmICghaGFzU3RhdHVzMCkge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgY2hhbGsucmVkKFxuICAgICAgICBcIuuniOydtOq3uOugiOydtOyFmCDtjIzsnbzsnYQg7IOd7ISx7ZWY66Ck66m0IOq4sOyhtCDrp4jsnbTqt7jroIjsnbTshZjsnbQg7LWc7IaMIO2VmOuCmOydmCBEQuyXkCDrqqjrkZAg7KCB7Jqp65CY7Ja0IOyeiOyWtOyVvCDtlanri4jri6QuXCIsXG4gICAgICApLFxuICAgICk7XG4gICAgZm9yIChjb25zdCBjb25uIG9mIGNvbm5zKSB7XG4gICAgICBpZiAoY29ubi5wZW5kaW5nLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGAgICR7Y29ubi5uYW1lfTogcGVuZGluZyAke2Nvbm4ucGVuZGluZy5sZW5ndGh96rCcYCkpO1xuICAgICAgfVxuICAgIH1cbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cblxuICBjb25zdCBjb3VudCA9IGF3YWl0IG1pZ3JhdG9yLmdlbmVyYXRlUHJlcGFyZWRDb2RlcygpO1xuICBpZiAoY291bnQgPiAwKSB7XG4gICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYCR7Y291bnR96rCc7J2YIOuniOydtOq3uOugiOydtOyFmCDtjIzsnbzsnbQg7IOd7ISx65CY7JeI7Iq164uI64ukLmApKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlX3N0YXR1cygpIHtcbiAgYXdhaXQgc2V0dXBNaWdyYXRvcigpO1xuXG4gIGNvbnN0IHN0YXR1cyA9IGF3YWl0IG1pZ3JhdG9yLmdldFN0YXR1cygpO1xuICAvLyBzdGF0dXM7XG4gIGNvbnNvbGUubG9nKHN0YXR1cyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpeHR1cmVfaW5pdCgpIHtcbiAgY29uc3Qgc3JjQ29uZmlnID0gU29uYW11LmRiQ29uZmlnLmRldmVsb3BtZW50X21hc3RlcjtcbiAgY29uc3QgdGFyZ2V0cyA9IFtcbiAgICB7XG4gICAgICBsYWJlbDogXCIoUkVNT1RFKSBGaXh0dXJlIERCXCIsXG4gICAgICBjb25maWc6IFNvbmFtdS5kYkNvbmZpZy5maXh0dXJlLFxuICAgIH0sXG4gICAge1xuICAgICAgbGFiZWw6IFwiKExPQ0FMKSBUZXN0aW5nIERCXCIsXG4gICAgICBjb25maWc6IFNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgdG9Ta2lwOiAoKCkgPT4ge1xuICAgICAgICBjb25zdCByZW1vdGVDb25uID0gU29uYW11LmRiQ29uZmlnLmZpeHR1cmUuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWc7XG4gICAgICAgIGNvbnN0IGxvY2FsQ29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnO1xuICAgICAgICByZXR1cm4gcmVtb3RlQ29ubi5ob3N0ID09PSBsb2NhbENvbm4uaG9zdCAmJiByZW1vdGVDb25uLmRhdGFiYXNlID09PSBsb2NhbENvbm4uZGF0YWJhc2U7XG4gICAgICB9KSgpLFxuICAgIH0sXG4gIF0gYXMge1xuICAgIGxhYmVsOiBzdHJpbmc7XG4gICAgY29uZmlnOiBLbmV4LkNvbmZpZztcbiAgICB0b1NraXA/OiBib29sZWFuO1xuICB9W107XG5cbiAgLy8gMS4g6riw7KSAREIg7Iqk7YKk66eI66W8IOuNpO2UhFxuICBjb25zb2xlLmxvZyhcIkRVTVAuLi5cIik7XG4gIGNvbnN0IGR1bXBGaWxlbmFtZSA9IGAvdG1wL3NvbmFtdS1maXh0dXJlLWluaXQtJHtEYXRlLm5vdygpfS5zcWxgO1xuICBjb25zdCBzcmNDb25uID0gc3JjQ29uZmlnLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnO1xuICBjb25zdCBtaWdyYXRpb25zRHVtcCA9IGAvdG1wL3NvbmFtdS1maXh0dXJlLWluaXQtbWlncmF0aW9ucy0ke0RhdGUubm93KCl9LnNxbGA7XG4gIGV4ZWNTeW5jKFxuICAgIGBteXNxbGR1bXAgLWgke3NyY0Nvbm4uaG9zdH0gLXUke3NyY0Nvbm4udXNlcn0gLXAke3NyY0Nvbm4ucGFzc3dvcmR9IC0tc2luZ2xlLXRyYW5zYWN0aW9uIC1kIC0tbm8tY3JlYXRlLWRiIC0tdHJpZ2dlcnMgJHtzcmNDb25uLmRhdGFiYXNlfSA+ICR7ZHVtcEZpbGVuYW1lfWAsXG4gICk7XG4gIGNvbnN0IF9kYiA9IGtuZXgoc3JjQ29uZmlnKTtcbiAgY29uc3QgW1ttaWdyYXRpb25zXV0gPSBhd2FpdCBfZGIucmF3KFxuICAgIFwiU0VMRUNUIENPVU5UKCopIGFzIGNvdW50IEZST00gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyBXSEVSRSB0YWJsZV9zY2hlbWEgPSA/IEFORCB0YWJsZV9uYW1lID0gJ2tuZXhfbWlncmF0aW9ucydcIixcbiAgICBbc3JjQ29ubi5kYXRhYmFzZV0sXG4gICk7XG4gIGlmIChtaWdyYXRpb25zLmNvdW50ID4gMCkge1xuICAgIGV4ZWNTeW5jKFxuICAgICAgYG15c3FsZHVtcCAtaCR7c3JjQ29ubi5ob3N0fSAtdSR7c3JjQ29ubi51c2VyfSAtcCR7c3JjQ29ubi5wYXNzd29yZH0gLS1zaW5nbGUtdHJhbnNhY3Rpb24gLS1uby1jcmVhdGUtZGIgLS10cmlnZ2VycyAke3NyY0Nvbm4uZGF0YWJhc2V9IGtuZXhfbWlncmF0aW9ucyBrbmV4X21pZ3JhdGlvbnNfbG9jayA+ICR7bWlncmF0aW9uc0R1bXB9YCxcbiAgICApO1xuICB9XG5cbiAgLy8gMi4g64yA7IOBREIg6rCB6rCB7JeQIOuMgO2VmOyXrCDsobTsnqzsl6zrtoAg7ZmV7J24IO2bhCDrtpPquLBcbiAgZm9yIChjb25zdCB7IGxhYmVsLCBjb25maWcsIHRvU2tpcCB9IG9mIHRhcmdldHMpIHtcbiAgICBjb25zdCBjb25uID0gY29uZmlnLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnO1xuXG4gICAgaWYgKHRvU2tpcCA9PT0gdHJ1ZSkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsucmVkKGAke2xhYmVsfTogU2tpcHBlZCFgKSk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBjb25zdCBkYiA9IGtuZXgoe1xuICAgICAgLi4uY29uZmlnLFxuICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAuLi4oKGNvbmZpZy5jb25uZWN0aW9uID8/IHt9KSBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWcpLFxuICAgICAgICBkYXRhYmFzZTogdW5kZWZpbmVkLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBjb25zdCBbW3Jvd11dID0gYXdhaXQgZGIucmF3KGBTSE9XIERBVEFCQVNFUyBMSUtFIFwiJHtjb25uLmRhdGFiYXNlfVwiYCk7XG4gICAgaWYgKHJvdykge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGAke2xhYmVsfTogRGF0YWJhc2UgXCIke2Nvbm4uZGF0YWJhc2V9XCIgQWxyZWFkeSBleGlzdHNgKSk7XG4gICAgICBhd2FpdCBkYi5kZXN0cm95KCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZyhgU1lOQyB0byAke2xhYmVsfS4uLmApO1xuICAgIGNvbnN0IG15c3FsQ21kID0gYG15c3FsIC1oJHtjb25uLmhvc3R9IC11JHtjb25uLnVzZXJ9IC1wJHtjb25uLnBhc3N3b3JkfWA7XG4gICAgZXhlY1N5bmMoYCR7bXlzcWxDbWR9IC1lICdEUk9QIERBVEFCQVNFIElGIEVYSVNUUyBcXGAke2Nvbm4uZGF0YWJhc2V9XFxgJ2ApO1xuICAgIGV4ZWNTeW5jKGAke215c3FsQ21kfSAtZSAnQ1JFQVRFIERBVEFCQVNFIFxcYCR7Y29ubi5kYXRhYmFzZX1cXGAnYCk7XG4gICAgZXhlY1N5bmMoYCR7bXlzcWxDbWR9ICR7Y29ubi5kYXRhYmFzZX0gPCAke2R1bXBGaWxlbmFtZX1gKTtcbiAgICBpZiAoYXdhaXQgZXhpc3RzKG1pZ3JhdGlvbnNEdW1wKSkge1xuICAgICAgZXhlY1N5bmMoYCR7bXlzcWxDbWR9ICR7Y29ubi5kYXRhYmFzZX0gPCAke21pZ3JhdGlvbnNEdW1wfWApO1xuICAgIH1cblxuICAgIGF3YWl0IGRiLmRlc3Ryb3koKTtcbiAgfVxuXG4gIGF3YWl0IF9kYi5kZXN0cm95KCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpeHR1cmVfaW1wb3J0KGVudGl0eUlkOiBzdHJpbmcsIHJlY29yZElkczogbnVtYmVyW10pIHtcbiAgYXdhaXQgc2V0dXBGaXh0dXJlTWFuYWdlcigpO1xuXG4gIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmltcG9ydEZpeHR1cmUoZW50aXR5SWQsIHJlY29yZElkcyk7XG4gIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLnN5bmMoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZml4dHVyZV9zeW5jKCkge1xuICBhd2FpdCBzZXR1cEZpeHR1cmVNYW5hZ2VyKCk7XG5cbiAgYXdhaXQgRml4dHVyZU1hbmFnZXIuc3luYygpO1xufVxuXG4vKipcbiAqIGZpeHR1cmUgZ2VuIOuqheugueyWtFxuICog7Ji17IWY7J2EIHByb2Nlc3MuYXJnduyXkOyEnCDtjIzsi7FcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZml4dHVyZV9nZW4oKSB7XG4gIGNvbnN0IG9wdGlvbnMgPSBwYXJzZU9wdGlvbnMocHJvY2Vzcy5hcmd2KTtcbiAgYXdhaXQgZml4dHVyZUdlbkNvbW1hbmQob3B0aW9ucyk7XG59XG5cbi8qKlxuICogZml4dHVyZSBmZXRjaCDrqoXroLnslrRcbiAqIOyYteyFmOydhCBwcm9jZXNzLmFyZ3bsl5DshJwg7YyM7IuxXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZpeHR1cmVfZmV0Y2goKSB7XG4gIGNvbnN0IG9wdGlvbnMgPSBwYXJzZU9wdGlvbnMocHJvY2Vzcy5hcmd2KTtcbiAgYXdhaXQgZml4dHVyZUZldGNoQ29tbWFuZChvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBmaXh0dXJlIGV4cGxvcmUg66qF66C57Ja0XG4gKiDsmLXshZjsnYQgcHJvY2Vzcy5hcmd27JeQ7IScIO2MjOyLsVxuICovXG5hc3luYyBmdW5jdGlvbiBmaXh0dXJlX2V4cGxvcmUoKSB7XG4gIGNvbnN0IG9wdGlvbnMgPSBwYXJzZU9wdGlvbnMocHJvY2Vzcy5hcmd2KTtcbiAgYXdhaXQgZml4dHVyZUV4cGxvcmVDb21tYW5kKG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIOqwhOuLqO2VnCDsmLXshZgg7YyM7IScXG4gKi9cbmZ1bmN0aW9uIHBhcnNlT3B0aW9ucyhcbiAgYXJndjogc3RyaW5nW10sXG4pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBib29sZWFuIHwgc3RyaW5nW10+ICYgeyBfOiBzdHJpbmdbXSB9IHtcbiAgY29uc3Qgb3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgYm9vbGVhbiB8IHN0cmluZ1tdPiAmIHsgXzogc3RyaW5nW10gfSA9IHsgXzogW10gfTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3YubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBhcmcgPSBhcmd2W2ldO1xuXG4gICAgaWYgKGFyZy5zdGFydHNXaXRoKFwiLS1cIikpIHtcbiAgICAgIGNvbnN0IGtleSA9IGFyZy5zbGljZSgyKTtcblxuICAgICAgaWYgKGtleS5pbmNsdWRlcyhcIj1cIikpIHtcbiAgICAgICAgY29uc3QgW2ssIHZdID0ga2V5LnNwbGl0KFwiPVwiKTtcbiAgICAgICAgb3B0aW9uc1trXSA9IHY7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBuZXh0ID0gYXJndltpICsgMV07XG4gICAgICAgIGlmIChuZXh0ICYmICFuZXh0LnN0YXJ0c1dpdGgoXCItLVwiKSkge1xuICAgICAgICAgIG9wdGlvbnNba2V5XSA9IG5leHQ7XG4gICAgICAgICAgaSsrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGFyZy5zdGFydHNXaXRoKFwiLVwiKSkge1xuICAgICAgY29uc3Qga2V5ID0gYXJnLnNsaWNlKDEpO1xuICAgICAgY29uc3QgbmV4dCA9IGFyZ3ZbaSArIDFdO1xuXG4gICAgICBpZiAobmV4dCAmJiAhbmV4dC5zdGFydHNXaXRoKFwiLVwiKSkge1xuICAgICAgICBvcHRpb25zW2tleV0gPSBuZXh0O1xuICAgICAgICBpKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvcHRpb25zW2tleV0gPSB0cnVlO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBvcHRpb25zLl8ucHVzaChhcmcpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBvcHRpb25zO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzdHViX3ByYWN0aWNlKG5hbWU6IHN0cmluZykge1xuICBjb25zdCBwcmFjdGljZURpciA9IHBhdGguam9pbihTb25hbXUuYXBpUm9vdFBhdGgsIFwic3JjXCIsIFwicHJhY3RpY2VzXCIpO1xuICBjb25zdCBmaWxlTmFtZXMgPSBhd2FpdCByZWFkZGlyKHByYWN0aWNlRGlyKTtcblxuICBjb25zdCBtYXhTZXFObyA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgaWYgKCEoYXdhaXQgZXhpc3RzKHByYWN0aWNlRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHByYWN0aWNlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBmaWx0ZXJlZFNlcXMgPSBmaWxlTmFtZXNcbiAgICAgIC5maWx0ZXIoKGZpbGVOYW1lKSA9PiBmaWxlTmFtZS5zdGFydHNXaXRoKFwicFwiKSAmJiBmaWxlTmFtZS5lbmRzV2l0aChcIi50c1wiKSlcbiAgICAgIC5tYXAoKGZpbGVOYW1lKSA9PiB7XG4gICAgICAgIGNvbnN0IFssIHNlcU5vXSA9IGZpbGVOYW1lLm1hdGNoKC9ecChbMC05XSspLS8pID8/IFtcIjBcIiwgXCIwXCJdO1xuICAgICAgICByZXR1cm4gcGFyc2VJbnQoc2VxTm8pO1xuICAgICAgfSlcbiAgICAgIC50b1NvcnRlZCgoYSwgYikgPT4gYiAtIGEpO1xuXG4gICAgaWYgKGZpbHRlcmVkU2Vxcy5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gZmlsdGVyZWRTZXFzWzBdO1xuICAgIH1cblxuICAgIHJldHVybiAwO1xuICB9KSgpO1xuXG4gIGNvbnN0IGN1cnJlbnRTZXFObyA9IG1heFNlcU5vICsgMTtcbiAgY29uc3QgZmlsZU5hbWUgPSBgcCR7Y3VycmVudFNlcU5vfS0ke25hbWV9LnRzYDtcbiAgY29uc3QgZHN0UGF0aCA9IHBhdGguam9pbihwcmFjdGljZURpciwgZmlsZU5hbWUpO1xuXG4gIGNvbnN0IGNvZGUgPSBbXG4gICAgYGltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCJzb25hbXVcIjtgLFxuICAgIFwiXCIsXG4gICAgYGNvbnNvbGUuY2xlYXIoKTtgLFxuICAgIGBjb25zb2xlLmxvZyhcIiR7ZmlsZU5hbWV9XCIpO2AsXG4gICAgXCJcIixcbiAgICBgU29uYW11LnJ1blNjcmlwdChhc3luYyAoKSA9PiB7YCxcbiAgICBgIC8vIFRPRE9gLFxuICAgIGB9KTtgLFxuICAgIFwiXCIsXG4gIF0uam9pbihcIlxcblwiKTtcbiAgYXdhaXQgd3JpdGVGaWxlKGRzdFBhdGgsIGNvZGUpO1xuXG4gIGV4ZWNTeW5jKGBjb2RlICR7ZHN0UGF0aH1gKTtcblxuICBjb25zdCBydW5Db2RlID0gYHlhcm4gbm9kZSAtciBkb3RlbnYvY29uZmlnIC0tZW5hYmxlLXNvdXJjZS1tYXBzIGRpc3QvcHJhY3RpY2VzLyR7ZmlsZU5hbWUucmVwbGFjZShcbiAgICBcIi50c1wiLFxuICAgIFwiLmpzXCIsXG4gICl9YDtcbiAgY29uc29sZS5sb2coYCR7Y2hhbGsuYmx1ZShydW5Db2RlKX0gY29waWVkIHRvIGNsaXBib2FyZC5gKTtcbiAgZXhlY1N5bmMoYGVjaG8gXCIke3J1bkNvZGV9XCIgfCBwYmNvcHlgKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc3R1Yl9lbnRpdHkoZW50aXR5SWQ6IHN0cmluZykge1xuICBhd2FpdCBTb25hbXUuc3luY2VyLmNyZWF0ZUVudGl0eSh7IGVudGl0eUlkLCB0aXRsZTogZW50aXR5SWQgfSk7XG5cbiAgY29uc3QgeyBmbGFncyB9ID0gcGFyc2VDbGlPcHRpb25zKCk7XG4gIGNvbnN0IHVzZUFJID0gZmxhZ3MuaGFzKFwiYWlcIik7XG4gIGNvbnN0IG5vQ29uZXMgPSBmbGFncy5oYXMoXCJuby1jb25lc1wiKTtcblxuICAvLyAtLW5vLWNvbmVzOiBjb25lIOyDneyEsSDsiqTtgrVcbiAgaWYgKG5vQ29uZXMpIHtcbiAgICBjb25zb2xlLmxvZyhg4pyTIEVudGl0eSAnJHtlbnRpdHlJZH0nIGNyZWF0ZWQgd2l0aG91dCBjb25lc2ApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHsgRW50aXR5TWFuYWdlciB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCIpO1xuICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCk7XG4gIGlmICghZW50aXR5KSB7XG4gICAgY29uc29sZS5lcnJvcihgRW50aXR5IG5vdCBmb3VuZDogJHtlbnRpdHlJZH1gKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyAtLWFpOiBMTE3snLzroZwgY29uZSDsg53shLFcbiAgaWYgKHVzZUFJKSB7XG4gICAgY29uc29sZS5sb2coYOKckyBFbnRpdHkgJyR7ZW50aXR5SWR9JyBjcmVhdGVkYCk7XG4gICAgY29uc29sZS5sb2coYPCfjJ8gR2VuZXJhdGluZyBBSS1wb3dlcmVkIGNvbmVzLi4uYCk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbmZpZ0xvY2FsZSA9IFNvbmFtdS5jb25maWcuaTE4bj8uZGVmYXVsdExvY2FsZTtcbiAgICAgIGNvbnN0IGxvY2FsZSA9XG4gICAgICAgIGNvbmZpZ0xvY2FsZSA9PT0gXCJrb1wiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJlblwiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJqYVwiXG4gICAgICAgICAgPyBjb25maWdMb2NhbGVcbiAgICAgICAgICA6IFwia29cIjtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZW50aXR5LmdlbmVyYXRlQ29uZXMoe1xuICAgICAgICBwcmVzZXJ2ZUV4aXN0aW5nOiBmYWxzZSxcbiAgICAgICAgb25seUVtcHR5OiBmYWxzZSxcbiAgICAgICAgbG9jYWxlLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnNvbGUubG9nKGDinIUgRG9uZSAoJHtyZXN1bHQudG9rZW5zVXNlZH0gdG9rZW5zKWApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvciAmJiBlcnJvci5tZXNzYWdlLmluY2x1ZGVzKFwiQU5USFJPUElDX0FQSV9LRVlcIikpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgXFxu4p2MICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihgXFxu8J+SoSBSZW1vdmUgLS1haSBmbGFnIHRvIHVzZSB0ZW1wbGF0ZSBjb25lcyBpbnN0ZWFkYCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8g6riw67O4OiDthZztlIzrpr8gY29uZSDsnpDrj5kg7IOd7ISxXG4gIC8vIExMTSDsl4bsnbQgZmFrZXItbWFwcGluZ3MudHPrpbwg7Zmc7Jqp7ZWY7JesIOq4sOuzuCBjb25lIOuplO2DgOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gIC8vIOydtOulvCDthrXtlbQgQU5USFJPUElDX0FQSV9LRVnqsIAg7JeG7Ja064+EIFNvbmFtdeulvCDsgqzsmqntlaAg7IiYIOyeiOycvOupsCxcbiAgLy8g7IOd7ISx65CcIO2FnO2UjOumvyBjb25l7J2AIOuCmOykkeyXkCAnY29uZSBnZW4nIOuqheugueyWtOuhnCBBSeulvCDthrXtlbQg7JeF6re466CI7J2065Oc7ZWgIOyImCDsnojsirXri4jri6QuXG4gIGNvbnNvbGUubG9nKGDwn4yfIEdlbmVyYXRpbmcgdGVtcGxhdGUgY29uZXMuLi5gKTtcbiAgYXdhaXQgZW50aXR5LmdlbmVyYXRlVGVtcGxhdGVDb25lcygpO1xuICBjb25zb2xlLmxvZyhg4pyTIEVudGl0eSAnJHtlbnRpdHlJZH0nIGNyZWF0ZWQgd2l0aCB0ZW1wbGF0ZSBjb25lc2ApO1xuICBjb25zb2xlLmxvZyhg8J+SoSBUaXA6IFJ1biAncG5wbSBzb25hbXUgY29uZSBnZW4gJHtlbnRpdHlJZH0nIHRvIGltcHJvdmUgd2l0aCBBSWApO1xufVxuXG4vKipcbiAqIEFJ66W8IOyCrOyaqe2VmOyXrCBlbnRpdHnsnZggY29uZSDrqZTtg4DrjbDsnbTthLDrpbwg7IOd7ISx7ZWY6rGw64KYIOyXheq3uOugiOydtOuTnO2VqeuLiOuLpC5cbiAqXG4gKiDsmLXshZg6XG4gKiAtIC0tcmVnZW5lcmF0ZTog7KCE7LK0IOyerOyDneyEsSAo6riw7KG0IGNvbmUg642u7Ja07JOw6riwKVxuICogLSAtLWxvY2FsZSA8a298ZW58amE+OiDsg53shLEg7Ja47Ja0IOyngOyglVxuICogLSDquLDrs7g6IG9ubHlFbXB0eSDrqqjrk5wgKOq4sOyhtCBmaXh0dXJlSGludCDrs7TsobQpXG4gKlxuICogQU5USFJPUElDX0FQSV9LRVkg7ZWE7JqUIChzb25hbXUuc2VjcmV0LnRzIOuYkOuKlCDtmZjqsr3rs4DsiJgpXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNvbmVfZ2VuKGVudGl0eUlkOiBzdHJpbmcpIHtcbiAgY29uc3QgeyBFbnRpdHlNYW5hZ2VyIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIik7XG4gIGNvbnN0IHsgZmxhZ3MsIG9wdGlvbnMgfSA9IHBhcnNlQ2xpT3B0aW9ucygpO1xuXG4gIC8vIC0tYWxsIOyYteyFmDog66qo65OgIGVudGl0eSBjb25lIOyDneyEsVxuICBpZiAoZmxhZ3MuaGFzKFwiYWxsXCIpIHx8IGVudGl0eUlkID09PSBcImFsbFwiKSB7XG4gICAgY29uc3QgYWxsRW50aXRpZXMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbEVudGl0aWVzKCk7XG4gICAgY29uc29sZS5sb2coYPCfjJ8gR2VuZXJhdGluZyBBSS1wb3dlcmVkIGNvbmVzIGZvciAke2FsbEVudGl0aWVzLmxlbmd0aH0gZW50aXRpZXMuLi5cXG5gKTtcblxuICAgIGxldCB0b3RhbFRva2VucyA9IDA7XG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBlbnRpdHkgb2YgYWxsRW50aXRpZXMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBQcm9jZXNzaW5nICR7ZW50aXR5LmlkfS4uLmApO1xuICAgICAgICBjb25zdCBjb25maWdMb2NhbGUgPSBvcHRpb25zLmxvY2FsZSB8fCBTb25hbXUuY29uZmlnLmkxOG4/LmRlZmF1bHRMb2NhbGU7XG4gICAgICAgIGNvbnN0IGxvY2FsZSA9XG4gICAgICAgICAgY29uZmlnTG9jYWxlID09PSBcImtvXCIgfHwgY29uZmlnTG9jYWxlID09PSBcImVuXCIgfHwgY29uZmlnTG9jYWxlID09PSBcImphXCJcbiAgICAgICAgICAgID8gY29uZmlnTG9jYWxlXG4gICAgICAgICAgICA6IFwia29cIjtcblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBlbnRpdHkuZ2VuZXJhdGVDb25lcyh7XG4gICAgICAgICAgcHJlc2VydmVFeGlzdGluZzogIWZsYWdzLmhhcyhcInJlZ2VuZXJhdGVcIiksXG4gICAgICAgICAgb25seUVtcHR5OiAhZmxhZ3MuaGFzKFwicmVnZW5lcmF0ZVwiKSxcbiAgICAgICAgICBsb2NhbGUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRvdGFsVG9rZW5zICs9IHJlc3VsdC50b2tlbnNVc2VkO1xuICAgICAgICBjb25zb2xlLmxvZyhgICDinJMgJHtlbnRpdHkuaWR9ICgke3Jlc3VsdC50b2tlbnNVc2VkfSB0b2tlbnMpXFxuYCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBcIlVua25vd24gZXJyb3JcIjtcbiAgICAgICAgZXJyb3JzLnB1c2goYCR7ZW50aXR5LmlkfTogJHttZXNzYWdlfWApO1xuICAgICAgICBjb25zb2xlLmVycm9yKGAgIOKclyAke2VudGl0eS5pZH06ICR7bWVzc2FnZX1cXG5gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZyhgXFxu4pyFIERvbmUhIFRvdGFsOiAke3RvdGFsVG9rZW5zfSB0b2tlbnMgdXNlZGApO1xuICAgIGNvbnN0IGVzdGltYXRlZENvc3QgPSAodG90YWxUb2tlbnMgKiA5KSAvIDFfMDAwXzAwMDtcbiAgICBjb25zb2xlLmxvZyhg8J+SsCBFc3RpbWF0ZWQgY29zdDogfiQke2VzdGltYXRlZENvc3QudG9GaXhlZCg0KX1gKTtcblxuICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc29sZS5lcnJvcihgXFxu4p2MIEZhaWxlZCBlbnRpdGllcyAoJHtlcnJvcnMubGVuZ3RofSk6YCk7XG4gICAgICBmb3IgKGNvbnN0IGVyciBvZiBlcnJvcnMpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgICAtICR7ZXJyfWApO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm47XG4gIH1cblxuICAvLyDri6jsnbwgZW50aXR5IGNvbmUg7IOd7ISxXG4gIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgaWYgKCFlbnRpdHkpIHtcbiAgICBjb25zb2xlLmVycm9yKGBFbnRpdHkgbm90IGZvdW5kOiAke2VudGl0eUlkfWApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IG1vZGUgPSBmbGFncy5oYXMoXCJyZWdlbmVyYXRlXCIpID8gXCJyZWdlbmVyYXRpbmdcIiA6IFwiZ2VuZXJhdGluZ1wiO1xuICBjb25zb2xlLmxvZyhcbiAgICBg8J+MnyAke21vZGUgPT09IFwicmVnZW5lcmF0aW5nXCIgPyBcIlJlZ2VuZXJhdGluZ1wiIDogXCJHZW5lcmF0aW5nXCJ9IEFJLXBvd2VyZWQgY29uZXMgZm9yICR7ZW50aXR5SWR9Li4uYCxcbiAgKTtcblxuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZ0xvY2FsZSA9IG9wdGlvbnMubG9jYWxlIHx8IFNvbmFtdS5jb25maWcuaTE4bj8uZGVmYXVsdExvY2FsZTtcbiAgICBjb25zdCBsb2NhbGUgPVxuICAgICAgY29uZmlnTG9jYWxlID09PSBcImtvXCIgfHwgY29uZmlnTG9jYWxlID09PSBcImVuXCIgfHwgY29uZmlnTG9jYWxlID09PSBcImphXCIgPyBjb25maWdMb2NhbGUgOiBcImtvXCI7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBlbnRpdHkuZ2VuZXJhdGVDb25lcyh7XG4gICAgICBwcmVzZXJ2ZUV4aXN0aW5nOiAhZmxhZ3MuaGFzKFwicmVnZW5lcmF0ZVwiKSxcbiAgICAgIG9ubHlFbXB0eTogIWZsYWdzLmhhcyhcInJlZ2VuZXJhdGVcIiksXG4gICAgICBsb2NhbGUsXG4gICAgfSk7XG5cbiAgICBjb25zb2xlLmxvZyhg4pyFIERvbmUhICgke3Jlc3VsdC50b2tlbnNVc2VkfSB0b2tlbnMgdXNlZClgKTtcblxuICAgIC8vIO2GoO2BsCDruYTsmqkg6rOE7IKwICjrjIDrnrXsoIHsnbgg7LaU7KCVKVxuICAgIC8vIENsYXVkZSBTb25uZXQgNC41OiBpbnB1dCAkMy9NIHRva2Vucywgb3V0cHV0ICQxNS9NIHRva2Vuc1xuICAgIC8vIOqwhOuLqO2VmOqyjCDtj4nqt6AgJDkvTSB0b2tlbnProZwg6rOE7IKwXG4gICAgY29uc3QgZXN0aW1hdGVkQ29zdCA9IChyZXN1bHQudG9rZW5zVXNlZCAqIDkpIC8gMV8wMDBfMDAwO1xuICAgIGNvbnNvbGUubG9nKGDwn5KwIEVzdGltYXRlZCBjb3N0OiB+JCR7ZXN0aW1hdGVkQ29zdC50b0ZpeGVkKDQpfWApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcIkFOVEhST1BJQ19BUElfS0VZXCIpKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbuKdjCAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbvCfkqEgVG8gdXNlIEFJLXBvd2VyZWQgY29uZSBnZW5lcmF0aW9uOmApO1xuICAgICAgICBjb25zb2xlLmVycm9yKGAgICAxLiBHZXQgYW4gQVBJIGtleSBmcm9tIGh0dHBzOi8vY29uc29sZS5hbnRocm9waWMuY29tL2ApO1xuICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgIGAgICAyLiBBZGQgaXQgdG8gc29uYW11LnNlY3JldC50cyBvciBzZXQgQU5USFJPUElDX0FQSV9LRVkgZW52aXJvbm1lbnQgdmFyaWFibGVgLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChlcnJvci5tZXNzYWdlLmluY2x1ZGVzKFwiUmF0ZSBsaW1pdFwiKSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBcXG7inYwgJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgICBjb25zb2xlLmVycm9yKGBcXG7wn5KhIFBsZWFzZSB3YWl0IGEgbW9tZW50IGFuZCB0cnkgYWdhaW4uYCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBcXG7inYwgRmFpbGVkIHRvIGdlbmVyYXRlIGNvbmVzOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFxcbuKdjCBGYWlsZWQgdG8gZ2VuZXJhdGUgY29uZXM6IFVua25vd24gZXJyb3JgKTtcbiAgICB9XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGRfbW9kZWwoZW50aXR5SWQ6IHN0cmluZykge1xuICBhd2FpdCBTb25hbXUuc3luY2VyLmdlbmVyYXRlVGVtcGxhdGUoXCJtb2RlbFwiLCB7XG4gICAgZW50aXR5SWQsXG4gIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzY2FmZm9sZF9tb2RlbF90ZXN0KGVudGl0eUlkOiBzdHJpbmcpIHtcbiAgYXdhaXQgU29uYW11LnN5bmNlci5nZW5lcmF0ZVRlbXBsYXRlKFwibW9kZWxfdGVzdFwiLCB7XG4gICAgZW50aXR5SWQsXG4gIH0pO1xufVxuXG4vKipcbiAqIHBucG0gc29uYW11IHNraWxscyBzeW5jIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICog6rO17IudIFNraWxsc+ulvCDroZzsu6wg7ZSE66Gc7KCd7Yq4IOuYkOuKlCDquIDroZzrsowgfi8uY2xhdWRlL+uhnCDrj5nquLDtmZTtlanri4jri6QuXG4gKlxuICogLS1nbG9iYWwg7ZSM656Y6re4OiB+Ly5jbGF1ZGUv7JeQIOuPmeq4sO2ZlCAo7ZSE66Gc7KCd7Yq4IOyDneyEsSDsoIQg7IKs7JqpIOqwgOuKpSlcbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2tpbGxzX3N5bmMoKSB7XG4gIGNvbnN0IHsgZmxhZ3MgfSA9IHBhcnNlQ2xpT3B0aW9ucygpO1xuICBjb25zdCBpc0dsb2JhbCA9IGZsYWdzLmhhcyhcImdsb2JhbFwiKTtcblxuICAvLyDqsJzrsJwg7ZmY6rK9IC0gY2xpLnRzOiBzb25hbXUvbW9kdWxlcy9zb25hbXUvc3JjL2Jpbi9jbGkudHNcbiAgLy8g67mM65OcIO2bhCAtIGNsaS5qczogbm9kZV9tb2R1bGVzL3NvbmFtdS9kaXN0L2Jpbi9jbGkuanMgKOyLpOygnCDsi6TtlokpXG4gIC8vIHNraWxscyDsnITsuZg6IG5vZGVfbW9kdWxlcy9zb25hbXUvc3JjL3NraWxscyAobnBtIOuwsO2PrCDsi5wpXG4gIGNvbnN0IHNvdXJjZUJhc2UgPSBwYXRoLnJlc29sdmUoaW1wb3J0Lm1ldGEuZGlybmFtZSwgXCIuLlwiLCBcIi4uXCIsIFwic3JjXCIsIFwic2tpbGxzXCIpO1xuICBjb25zdCBzb3VyY2VTa2lsbHNEaXIgPSBwYXRoLmpvaW4oc291cmNlQmFzZSwgXCJzb25hbXVcIik7XG4gIGNvbnN0IHNvdXJjZUNsYXVkZU1kID0gcGF0aC5qb2luKHNvdXJjZUJhc2UsIFwiQ0xBVURFLm1kXCIpO1xuXG4gIGlmICghKGF3YWl0IGV4aXN0cyhzb3VyY2VTa2lsbHNEaXIpKSkge1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhcIlNraWxscyBzb3VyY2Ugbm90IGZvdW5kIGluIHNvbmFtdSBwYWNrYWdlLlwiKSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGlzR2xvYmFsKSB7XG4gICAgY29uc3QgaG9tZUNsYXVkZURpciA9IHBhdGguam9pbihvcy5ob21lZGlyKCksIFwiLmNsYXVkZVwiKTtcbiAgICBhd2FpdCBza2lsbHNfc3luY190byhob21lQ2xhdWRlRGlyLCBzb3VyY2VTa2lsbHNEaXIsIHNvdXJjZUNsYXVkZU1kLCB7XG4gICAgICB1c2VTeW1saW5rOiBmYWxzZSxcbiAgICAgIGNvcHlQcm9qZWN0VGVtcGxhdGVzOiBmYWxzZSxcbiAgICAgIGlzR2xvYmFsOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgLy8gfi8uY2xhdWRlL2NvbW1hbmRzL3NvbmFtdS1za2lsbHMubWQg7ISk7LmYXG4gICAgY29uc3Qgc291cmNlQ29tbWFuZHNEaXIgPSBwYXRoLmpvaW4oc291cmNlQmFzZSwgXCJjb21tYW5kc1wiKTtcbiAgICBjb25zdCBzb3VyY2VDb21tYW5kID0gcGF0aC5qb2luKHNvdXJjZUNvbW1hbmRzRGlyLCBcInNvbmFtdS1za2lsbHMubWRcIik7XG4gICAgaWYgKGF3YWl0IGV4aXN0cyhzb3VyY2VDb21tYW5kKSkge1xuICAgICAgY29uc3QgdGFyZ2V0Q29tbWFuZHNEaXIgPSBwYXRoLmpvaW4oaG9tZUNsYXVkZURpciwgXCJjb21tYW5kc1wiKTtcbiAgICAgIGF3YWl0IG1rZGlyKHRhcmdldENvbW1hbmRzRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIGF3YWl0IGNwKHNvdXJjZUNvbW1hbmQsIHBhdGguam9pbih0YXJnZXRDb21tYW5kc0RpciwgXCJzb25hbXUtc2tpbGxzLm1kXCIpKTtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgL3NvbmFtdS1za2lsbHMgY29tbWFuZCBpbnN0YWxsZWQg4oaSIH4vLmNsYXVkZS9jb21tYW5kcy9gKSk7XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coY2hhbGsuY3lhbihgXFxuICBHbG9iYWwgc3luYyBjb21wbGV0ZSDihpIgfi8uY2xhdWRlL3NraWxscy9zb25hbXUvYCkpO1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLmRpbShgICBUaGVzZSBza2lsbHMgYXJlIGF2YWlsYWJsZSBpbiBhbGwgQ2xhdWRlIENvZGUgc2Vzc2lvbnMuYCkpO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgY2hhbGsuZGltKFxuICAgICAgICBgICBPbmNlIGEgcHJvamVjdCBpcyBjcmVhdGVkLCBydW4gJ3BucG0gc29uYW11IHNraWxscyBzeW5jJyBmb3IgcHJvamVjdC1sb2NhbCBzeW5jLmAsXG4gICAgICApLFxuICAgICk7XG4gIH0gZWxzZSB7XG4gICAgY29uc3Qgd29ya3NwYWNlUm9vdCA9IGF3YWl0IGZpbmRXb3Jrc3BhY2VSb290KCk7XG4gICAgY29uc3QgY2xhdWRlRGlyID0gcGF0aC5qb2luKHdvcmtzcGFjZVJvb3QsIFwiLmNsYXVkZVwiKTtcbiAgICBhd2FpdCBza2lsbHNfc3luY190byhjbGF1ZGVEaXIsIHNvdXJjZVNraWxsc0Rpciwgc291cmNlQ2xhdWRlTWQsIHtcbiAgICAgIHVzZVN5bWxpbms6IHRydWUsXG4gICAgICBjb3B5UHJvamVjdFRlbXBsYXRlczogdHJ1ZSxcbiAgICAgIHNvdXJjZUJhc2UsXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBjbGF1ZGVEaXLroZwgc2tpbGxz66W8IOuPmeq4sO2ZlO2VmOuKlCDqs7XthrUg66Gc7KeB7J6F64uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBza2lsbHNfc3luY190byhcbiAgY2xhdWRlRGlyOiBzdHJpbmcsXG4gIHNvdXJjZVNraWxsc0Rpcjogc3RyaW5nLFxuICBzb3VyY2VDbGF1ZGVNZDogc3RyaW5nLFxuICBvcHRpb25zOiB7XG4gICAgdXNlU3ltbGluazogYm9vbGVhbjtcbiAgICBjb3B5UHJvamVjdFRlbXBsYXRlczogYm9vbGVhbjtcbiAgICBzb3VyY2VCYXNlPzogc3RyaW5nO1xuICAgIGlzR2xvYmFsPzogYm9vbGVhbjtcbiAgfSxcbikge1xuICBjb25zdCB0YXJnZXRTa2lsbHNEaXIgPSBwYXRoLmpvaW4oY2xhdWRlRGlyLCBcInNraWxsc1wiLCBcInNvbmFtdVwiKTtcblxuICAvLyDquLDsobQg65SU66CJ7Yag66asL3N5bWxpbmsg7IKt7KCcIO2bhCDsnqzsg53shLFcbiAgLy8gZXhpc3RzKCnripQgYnJva2VuIHN5bWxpbmvrpbwg6rCQ7KeA7ZWY7KeAIOuqu+2VmOuvgOuhnCBybeydhCDrrLTsobDqsbQg7Iuc64+E7ZWp64uI64ukXG4gIHRyeSB7XG4gICAgYXdhaXQgcm0odGFyZ2V0U2tpbGxzRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIO2MjOydvOydtCDsl4bsnLzrqbQg66y07IucXG4gIH1cblxuICBhd2FpdCBta2RpcihwYXRoLmRpcm5hbWUodGFyZ2V0U2tpbGxzRGlyKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgaWYgKG9wdGlvbnMudXNlU3ltbGluaykge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBzeW1saW5rKHNvdXJjZVNraWxsc0RpciwgdGFyZ2V0U2tpbGxzRGlyLCBcImRpclwiKTtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgU2tpbGxzIGxpbmtlZCAoc3ltbGluaylgKSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay55ZWxsb3coYOKaoCBTeW1saW5rIGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCksXG4gICAgICApO1xuICAgICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGAgIEZhbGxpbmcgYmFjayB0byBjb3B5Li4uYCkpO1xuICAgICAgYXdhaXQgc2tpbGxzQ29weShzb3VyY2VTa2lsbHNEaXIsIHRhcmdldFNraWxsc0Rpcik7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGF3YWl0IHNraWxsc0NvcHkoc291cmNlU2tpbGxzRGlyLCB0YXJnZXRTa2lsbHNEaXIpO1xuICB9XG5cbiAgLy8gcHJvamVjdCDrlJTroInthqDrpqwg7LSI6riw7ZmUICjsl4bsnLzrqbQg7IOd7ISxLCDsnojsnLzrqbQg7Jyg7KeAKVxuICBpZiAob3B0aW9ucy5jb3B5UHJvamVjdFRlbXBsYXRlcyAmJiBvcHRpb25zLnNvdXJjZUJhc2UpIHtcbiAgICBjb25zdCBzb3VyY2VQcm9qZWN0RGlyID0gcGF0aC5qb2luKG9wdGlvbnMuc291cmNlQmFzZSwgXCJwcm9qZWN0XCIpO1xuICAgIGNvbnN0IHRhcmdldFByb2plY3REaXIgPSBwYXRoLmpvaW4oY2xhdWRlRGlyLCBcInNraWxsc1wiLCBcInByb2plY3RcIik7XG5cbiAgICBpZiAoYXdhaXQgZXhpc3RzKHNvdXJjZVByb2plY3REaXIpKSB7XG4gICAgICBpZiAoIShhd2FpdCBleGlzdHModGFyZ2V0UHJvamVjdERpcikpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgY3Aoc291cmNlUHJvamVjdERpciwgdGFyZ2V0UHJvamVjdERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBQcm9qZWN0IHRlbXBsYXRlcyBpbml0aWFsaXplZGApKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgY2hhbGsucmVkKFxuICAgICAgICAgICAgICBg4pyXIEZhaWxlZCB0byBpbml0aWFsaXplIHByb2plY3QgdGVtcGxhdGVzOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oYOKPrSBQcm9qZWN0IHRlbXBsYXRlcyBhbHJlYWR5IGV4aXN0IChwcmVzZXJ2ZWQpYCkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIHNldHRpbmdzLmxvY2FsLmpzb24g4oCUIHByb2plY3QtbG9jYWwg66qo65Oc7JeQ7ISc66eMLCDsl4bsnYQg65WM66eMIOyDneyEsVxuICBpZiAob3B0aW9ucy5jb3B5UHJvamVjdFRlbXBsYXRlcykge1xuICAgIGNvbnN0IHNldHRpbmdzTG9jYWxQYXRoID0gcGF0aC5qb2luKGNsYXVkZURpciwgXCJzZXR0aW5ncy5sb2NhbC5qc29uXCIpO1xuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzZXR0aW5nc0xvY2FsUGF0aCkpKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzZXR0aW5nc0NvbnRlbnQgPSB7XG4gICAgICAgICAgaG9va3M6IHtcbiAgICAgICAgICAgIFBvc3RUb29sVXNlOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBtYXRjaGVyOiBcIkVkaXR8V3JpdGV8TXVsdGlFZGl0XCIsXG4gICAgICAgICAgICAgICAgaG9va3M6IFtcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJjb21tYW5kXCIsXG4gICAgICAgICAgICAgICAgICAgIGNvbW1hbmQ6IFwicG5wbSBjaGVjayAyPiYxIHwgaGVhZCAtNjBcIixcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKHNldHRpbmdzTG9jYWxQYXRoLCBgJHtKU09OLnN0cmluZ2lmeShzZXR0aW5nc0NvbnRlbnQsIG51bGwsIDIpfVxcbmApO1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihg4pyTIC5jbGF1ZGUvc2V0dGluZ3MubG9jYWwuanNvbiBjcmVhdGVkYCkpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICBjaGFsay5yZWQoXG4gICAgICAgICAgICBg4pyXIEZhaWxlZCB0byBjcmVhdGUgc2V0dGluZ3MubG9jYWwuanNvbjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5kaW0oYOKPrSAuY2xhdWRlL3NldHRpbmdzLmxvY2FsLmpzb24gYWxyZWFkeSBleGlzdHMgKHByZXNlcnZlZClgKSk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ0xBVURFLm1kIOuzteyCrC/sl4XrjbDsnbTtirhcbiAgaWYgKGF3YWl0IGV4aXN0cyhzb3VyY2VDbGF1ZGVNZCkpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGFyZ2V0Q2xhdWRlTWQgPSBwYXRoLmpvaW4oY2xhdWRlRGlyLCBcIkNMQVVERS5tZFwiKTtcbiAgICAgIGNvbnN0IHJhd0NvbnRlbnQgPSBhd2FpdCByZWFkRmlsZShzb3VyY2VDbGF1ZGVNZCwgXCJ1dGYtOFwiKTtcbiAgICAgIC8vIOq4gOuhnOuyjCDrqqjrk5zsl5DshJzripQg7IOB64yAIOqyveuhnOulvCDsoIjrjIAg6rK966Gc66GcIOuzgO2ZmO2VqeuLiOuLpFxuICAgICAgY29uc3Qgc291cmNlQ29udGVudCA9IG9wdGlvbnMuaXNHbG9iYWxcbiAgICAgICAgPyByYXdDb250ZW50LnJlcGxhY2VBbGwoXCIuY2xhdWRlL3NraWxscy9zb25hbXUvXCIsIFwifi8uY2xhdWRlL3NraWxscy9zb25hbXUvXCIpXG4gICAgICAgIDogcmF3Q29udGVudDtcblxuICAgICAgaWYgKGF3YWl0IGV4aXN0cyh0YXJnZXRDbGF1ZGVNZCkpIHtcbiAgICAgICAgY29uc3QgdGFyZ2V0Q29udGVudCA9IGF3YWl0IHJlYWRGaWxlKHRhcmdldENsYXVkZU1kLCBcInV0Zi04XCIpO1xuICAgICAgICBjb25zdCBzdGFydE1hcmtlciA9IFwiPCEtLSBTT05BTVU6U1RBUlQgLS0+XCI7XG4gICAgICAgIGNvbnN0IGVuZE1hcmtlciA9IFwiPCEtLSBTT05BTVU6RU5EIC0tPlwiO1xuICAgICAgICBpZiAodGFyZ2V0Q29udGVudC5pbmNsdWRlcyhzdGFydE1hcmtlcikgJiYgdGFyZ2V0Q29udGVudC5pbmNsdWRlcyhlbmRNYXJrZXIpKSB7XG4gICAgICAgICAgY29uc3Qgc3RhcnRJZHggPSB0YXJnZXRDb250ZW50LmluZGV4T2Yoc3RhcnRNYXJrZXIpO1xuICAgICAgICAgIGNvbnN0IGVuZElkeCA9IHRhcmdldENvbnRlbnQuaW5kZXhPZihlbmRNYXJrZXIpO1xuXG4gICAgICAgICAgaWYgKHN0YXJ0SWR4ICE9PSAtMSAmJiBlbmRJZHggIT09IC0xICYmIHN0YXJ0SWR4IDwgZW5kSWR4KSB7XG4gICAgICAgICAgICBjb25zdCBiZWZvcmUgPSB0YXJnZXRDb250ZW50LnN1YnN0cmluZygwLCBzdGFydElkeCk7XG4gICAgICAgICAgICBjb25zdCBhZnRlciA9IHRhcmdldENvbnRlbnQuc3Vic3RyaW5nKGVuZElkeCArIGVuZE1hcmtlci5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgbmV3Q29udGVudCA9IGAke2JlZm9yZX0ke3N0YXJ0TWFya2VyfVxcbiR7c291cmNlQ29udGVudH1cXG4ke2VuZE1hcmtlcn0ke2FmdGVyfWA7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUodGFyZ2V0Q2xhdWRlTWQsIG5ld0NvbnRlbnQpO1xuICAgICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBDTEFVREUubWQgdXBkYXRlZCAobWFya2VyIHJlZ2lvbilgKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdyhg4o+tIENMQVVERS5tZCBtYXJrZXIgcG9zaXRpb25zIGludmFsaWQsIHNraXBwZWRgKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIOuniOy7pOqwgCDsl4bripQg6riw7KG0IENMQVVERS5tZOyXkCBTb25hbXUg7IS57IWY7J2EIOy2lOqwgO2VqeuLiOuLpFxuICAgICAgICAgIGNvbnN0IGFwcGVuZGVkID0gYCR7dGFyZ2V0Q29udGVudC50cmltRW5kKCl9XFxuXFxuPCEtLSBTT05BTVU6U1RBUlQgLS0+XFxuJHtzb3VyY2VDb250ZW50fVxcbjwhLS0gU09OQU1VOkVORCAtLT5cXG5gO1xuICAgICAgICAgIGF3YWl0IHdyaXRlRmlsZSh0YXJnZXRDbGF1ZGVNZCwgYXBwZW5kZWQpO1xuICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgQ0xBVURFLm1kIHVwZGF0ZWQgKGFwcGVuZGVkIFNvbmFtdSBzZWN0aW9uKWApKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3Qgd2l0aE1hcmtlcnMgPSBgPCEtLSBTT05BTVU6U1RBUlQgLS0+XFxuJHtzb3VyY2VDb250ZW50fVxcbjwhLS0gU09OQU1VOkVORCAtLT5cXG5gO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUodGFyZ2V0Q2xhdWRlTWQsIHdpdGhNYXJrZXJzKTtcbiAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYOKckyBDTEFVREUubWQgY3JlYXRlZGApKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgY2hhbGsucmVkKFxuICAgICAgICAgIGDinJcgRmFpbGVkIHRvIHVwZGF0ZSBDTEFVREUubWQ6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWAsXG4gICAgICAgICksXG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBza2lsbHNDb3B5KHNyYzogc3RyaW5nLCBkZXN0OiBzdHJpbmcpIHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBjcChzcmMsIGRlc3QsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgU2tpbGxzIGNvcGllZGApKTtcbiAgfSBjYXRjaCAoY29weUVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgIGNoYWxrLnJlZChcbiAgICAgICAgYOKclyBGYWlsZWQgdG8gY29weSBza2lsbHM6ICR7Y29weUVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBjb3B5RXJyb3IubWVzc2FnZSA6IFN0cmluZyhjb3B5RXJyb3IpfWAsXG4gICAgICApLFxuICAgICk7XG4gICAgdGhyb3cgY29weUVycm9yO1xuICB9XG59XG5cbi8qKlxuICogcG5wbSBzb25hbXUgc2tpbGxzIGNyZWF0ZSA8bmFtZT4g7ZWY66m0IOyLpO2WieuQmOuKlCDtlajsiJjsnoXri4jri6QuXG4gKiDroZzsu6wgc2tpbGwg7LSI7JWI7J2EIOyDneyEse2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2tpbGxzX2NyZWF0ZShuYW1lOiBzdHJpbmcpIHtcbiAgY29uc3Qgd29ya3NwYWNlUm9vdCA9IGF3YWl0IGZpbmRXb3Jrc3BhY2VSb290KCk7XG4gIGNvbnN0IGxvY2FsRGlyID0gcGF0aC5qb2luKHdvcmtzcGFjZVJvb3QsIFwiLmNsYXVkZVwiLCBcInNraWxsc1wiLCBcImxvY2FsXCIpO1xuXG4gIC8vID09PSDtjIzsnbzrqoUg6rKA7KadIOuwjyBTYW5pdGl6ZSA9PT1cbiAgaWYgKCFuYW1lIHx8IG5hbWUudHJpbSgpID09PSBcIlwiKSB7XG4gICAgY29uc29sZS5lcnJvcihjaGFsay5yZWQoXCLinJcgU2tpbGwgbmFtZSBpcyByZXF1aXJlZFwiKSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgbGV0IHNhbml0aXplZCA9IG5hbWVcbiAgICAvLyDqs7XrsLHsnYQg7ZWY7J207ZSI7Jy866GcXG4gICAgLnJlcGxhY2UoL1xccysvZywgXCItXCIpXG4gICAgLy8g6rK966GcIOq1rOu2hOyekCDsoJzqsbBcbiAgICAucmVwbGFjZSgvWy9cXFxcXS9nLCBcIi1cIilcbiAgICAvLyBQYXRoIHRyYXZlcnNhbCDrsKnsp4BcbiAgICAucmVwbGFjZSgvXFwuXFwuL2csIFwiXCIpXG4gICAgLy8gV2luZG93cyDquIjsp4Ag66y47J6QIOygnOqxsFxuICAgIC5yZXBsYWNlKC9bPD46XCJ8PypdL2csIFwiXCIpXG4gICAgLy8g7Iuc7J6RL+uBnSDsoJAsIO2VmOydtO2UiCwg7Ja4642U7Iqk7L2U7Ja0IOygnOqxsFxuICAgIC5yZXBsYWNlKC9eWy5cXC1fXSt8Wy5cXC1fXSskL2csIFwiXCIpXG4gICAgLy8g7Jew7IaN65CcIO2VmOydtO2UiOydhCDtlZjrgpjroZxcbiAgICAucmVwbGFjZSgvLSsvZywgXCItXCIpXG4gICAgLy8g7JWM7YyM67KzLCDsiKvsnpAsIO2VmOydtO2UiCwg7Ja4642U7Iqk7L2U7Ja0LCDtlZzquIDrp4wg7ZeI7JqpXG4gICAgLnJlcGxhY2UoL1teYS16QS1aMC05LV/qsIAt7Z6jXS9nLCBcIlwiKTtcblxuICAvLyDquLjsnbQg7KCc7ZWcXG4gIGNvbnN0IE1BWF9MRU5HVEggPSAxMDA7XG4gIGlmIChzYW5pdGl6ZWQubGVuZ3RoID4gTUFYX0xFTkdUSCkge1xuICAgIHNhbml0aXplZCA9IHNhbml0aXplZC5zdWJzdHJpbmcoMCwgTUFYX0xFTkdUSCk7XG4gICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGDimqAgTmFtZSB0cnVuY2F0ZWQgdG8gJHtNQVhfTEVOR1RIfSBjaGFyYWN0ZXJzYCkpO1xuICB9XG5cbiAgLy8gV2luZG93cyDsmIjslb3slrQg7ZmV7J24XG4gIGNvbnN0IFJFU0VSVkVEX05BTUVTID0gW1xuICAgIFwiQ09OXCIsXG4gICAgXCJQUk5cIixcbiAgICBcIkFVWFwiLFxuICAgIFwiTlVMXCIsXG4gICAgXCJDT00xXCIsXG4gICAgXCJDT00yXCIsXG4gICAgXCJDT00zXCIsXG4gICAgXCJDT000XCIsXG4gICAgXCJDT001XCIsXG4gICAgXCJDT002XCIsXG4gICAgXCJDT003XCIsXG4gICAgXCJDT004XCIsXG4gICAgXCJDT005XCIsXG4gICAgXCJMUFQxXCIsXG4gICAgXCJMUFQyXCIsXG4gICAgXCJMUFQzXCIsXG4gICAgXCJMUFQ0XCIsXG4gICAgXCJMUFQ1XCIsXG4gICAgXCJMUFQ2XCIsXG4gICAgXCJMUFQ3XCIsXG4gICAgXCJMUFQ4XCIsXG4gICAgXCJMUFQ5XCIsXG4gIF07XG4gIGlmIChSRVNFUlZFRF9OQU1FUy5pbmNsdWRlcyhzYW5pdGl6ZWQudG9VcHBlckNhc2UoKSkpIHtcbiAgICBzYW5pdGl6ZWQgPSBgc2tpbGwtJHtzYW5pdGl6ZWR9YDtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYOKaoCBSZXNlcnZlZCBuYW1lIGRldGVjdGVkLCBwcmVmaXhlZCB3aXRoIFwic2tpbGwtXCJgKSk7XG4gIH1cblxuICAvLyDruYgg66y47J6Q7Je0IOyytO2BrFxuICBpZiAoc2FuaXRpemVkID09PSBcIlwiKSB7XG4gICAgY29uc29sZS5lcnJvcihjaGFsay5yZWQoXCLinJcgSW52YWxpZCBza2lsbCBuYW1lIGFmdGVyIHNhbml0aXphdGlvblwiKSk7XG4gICAgY29uc29sZS5sb2coY2hhbGsuZGltKGAgIE9yaWdpbmFsOiBcIiR7bmFtZX1cImApKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyDrs4Dqsr0g7JWM66a8XG4gIGlmIChzYW5pdGl6ZWQgIT09IG5hbWUpIHtcbiAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYOKaoCBOYW1lIHNhbml0aXplZDogXCIke25hbWV9XCIg4oaSIFwiJHtzYW5pdGl6ZWR9XCJgKSk7XG4gIH1cblxuICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihsb2NhbERpciwgYCR7c2FuaXRpemVkfS5tZGApO1xuXG4gIGlmIChhd2FpdCBleGlzdHMoZmlsZVBhdGgpKSB7XG4gICAgY29uc29sZS5sb2coY2hhbGsueWVsbG93KGBTa2lsbCBcIiR7c2FuaXRpemVkfVwiIGFscmVhZHkgZXhpc3RzLmApKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBhd2FpdCBta2Rpcihsb2NhbERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBgLS0tXG5uYW1lOiAke3Nhbml0aXplZH1cbmNhdGVnb3J5OiBvdGhlclxuY3JlYXRlZF9hdDogJHtuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc3BsaXQoXCJUXCIpWzBdfVxuc3RhdHVzOiBkcmFmdFxuLS0tXG5cbiMgJHtzYW5pdGl6ZWR9XG5cbiMjIOyDge2ZqVxuXG5b7Ja065akIOusuOygnOyYgOuKlOyngF1cblxuIyMg7ZW06rKwIOuwqeuylVxuXG5b7Ja065a76rKMIO2VtOqysO2WiOuKlOyngF1cblxuIyMg7L2U65OcIOyYiOyLnFxuXG5cXGBcXGBcXGB0eXBlc2NyaXB0XG4vLyDsmIjsi5wg7L2U65OcXG5cXGBcXGBcXGBcbmA7XG5cbiAgYXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCB0ZW1wbGF0ZSk7XG4gIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGDinJMgQ3JlYXRlZCAuY2xhdWRlL3NraWxscy9sb2NhbC8ke3Nhbml0aXplZH0ubWRgKSk7XG59XG5cbi8qKlxuICogcG5wbSBzb25hbXUgYXV0aCBnZW5lcmF0ZSDtlZjrqbQg7Iuk7ZaJ65CY64qUIO2VqOyImOyeheuLiOuLpC5cbiAqIGJldHRlci1hdXRoIOyXlO2LsO2LsOuTpChVc2VyLCBTZXNzaW9uLCBBY2NvdW50LCBWZXJpZmljYXRpb24p7J2EIOyDneyEse2VqeuLiOuLpC5cbiAqXG4gKiDsmLXshZg6XG4gKiAtLXBsdWdpbnMgcGhvbmUtbnVtYmVyLDJmYSAg7ZSM65+s6re47J24IOyXlO2LsO2LsOuPhCDtlajqu5gg7IOd7ISxXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGF1dGhfZ2VuZXJhdGUoKSB7XG4gIC8vIC0tcGx1Z2lucyDsmLXshZgg7YyM7IuxXG4gIGNvbnN0IHBsdWdpbnNBcmcgPSBwcm9jZXNzLmFyZ3YuZmluZCgoYXJnKSA9PiBhcmcuc3RhcnRzV2l0aChcIi0tcGx1Z2luc1wiKSk7XG4gIGNvbnN0IHBsdWdpbnM6IEJldHRlckF1dGhQbHVnaW5JZFtdID0gW107XG5cbiAgaWYgKHBsdWdpbnNBcmcpIHtcbiAgICBjb25zdCBwbHVnaW5WYWx1ZSA9IHBsdWdpbnNBcmcuaW5jbHVkZXMoXCI9XCIpXG4gICAgICA/IHBsdWdpbnNBcmcuc3BsaXQoXCI9XCIpWzFdXG4gICAgICA6IHByb2Nlc3MuYXJndltwcm9jZXNzLmFyZ3YuaW5kZXhPZihwbHVnaW5zQXJnKSArIDFdO1xuXG4gICAgaWYgKHBsdWdpblZhbHVlKSB7XG4gICAgICBjb25zdCBwbHVnaW5JZHMgPSBwbHVnaW5WYWx1ZS5zcGxpdChcIixcIikubWFwKChwKSA9PiBwLnRyaW0oKSk7XG5cbiAgICAgIGZvciAoY29uc3QgaWQgb2YgcGx1Z2luSWRzKSB7XG4gICAgICAgIGlmIChpc1ZhbGlkUGx1Z2luSWQoaWQpKSB7XG4gICAgICAgICAgcGx1Z2lucy5wdXNoKGlkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3coYOKaoCBVbmtub3duIHBsdWdpbjogJHtpZH1gKSk7XG4gICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZGltKGAgIFN1cHBvcnRlZCBwbHVnaW5zOiAke1NVUFBPUlRFRF9QTFVHSU5fSURTLmpvaW4oXCIsIFwiKX1gKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmxvZyhjaGFsay55ZWxsb3cuYm9sZChcIvCflJAgR2VuZXJhdGluZyBiZXR0ZXItYXV0aCBlbnRpdGllcy4uLlxcblwiKSk7XG5cbiAgaWYgKHBsdWdpbnMubGVuZ3RoID4gMCkge1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLmRpbShgICBQbHVnaW5zOiAke3BsdWdpbnMuam9pbihcIiwgXCIpfWApKTtcbiAgfVxuXG4gIGF3YWl0IGdlbmVyYXRlQmV0dGVyQXV0aEVudGl0aWVzKHsgcGx1Z2lucyB9KTtcbn1cblxuLyoqXG4gKiBwbnBtIHNvbmFtdSBhdXRoIGFkZC1jb21wYW5pb25zIO2VmOuptCDsi6TtlonrkJjripQg7ZWo7IiY7J6F64uI64ukLlxuICog6riw7KG0IO2UhOuhnOygne2KuOydmCBlbnRpdHkuanNvbuyXkCBmaXh0dXJlQ29tcGFuaW9uc+ulvCDshozquIkg7LaU6rCA7ZWp64uI64ukLlxuICpcbiAqIOydtOuvuCBmaXh0dXJlQ29tcGFuaW9uc+qwgCDsnojripQgZW50aXR564qUIOyKpO2Cte2VqeuLiOuLpCAo642u7Ja07JOw6riwIOyXhuydjCkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGF1dGhfYWRkX2NvbXBhbmlvbnMoKSB7XG4gIGNvbnNvbGUubG9nKGNoYWxrLnllbGxvdy5ib2xkKFwi8J+UkCBBZGRpbmcgZml4dHVyZUNvbXBhbmlvbnMgdG8gYmV0dGVyLWF1dGggZW50aXRpZXMuLi5cXG5cIikpO1xuICBhd2FpdCBhZGRDb21wYW5pb25zVG9FbnRpdGllcygpO1xuICBjb25zb2xlLmxvZyhjaGFsay5ib2xkKFwiXFxu4pyFIERvbmUhXCIpKTtcbn1cblxuLyoqXG4gKiDsm4ztgazsiqTtjpjsnbTsiqQg66Oo7Yq466W8IOywvuyKteuLiOuLpC5cbiAqIOyasOyEoOyInOychDogcG5wbS13b3Jrc3BhY2UueWFtbCA+IHBhY2thZ2UuanNvbih3b3Jrc3BhY2VzKSA+IC5hZ2VudHMvXG4gKlxuICogQ0xBVURFLm1k64qUIOyEnOu4jO2MqO2CpOyngOyXkOuPhCDsobTsnqztlaAg7IiYIOyeiOycvOuvgOuhnCDsgqzsmqntlZjsp4Ag7JWK7Iq164uI64ukLlxuICogLmFnZW50cy/ripQgYWdlbnRzIGluaXTsnbQg7IOd7ISx7ZWY64qUIOuUlOugie2GoOumrOuhnCwg7JuM7YGs7Iqk7Y6Y7J207IqkIOujqO2KuOyXkOunjCDsobTsnqztlanri4jri6QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZpbmRXb3Jrc3BhY2VSb290KCkge1xuICBsZXQgZGlyID0gcHJvY2Vzcy5jd2QoKTtcblxuICB3aGlsZSAoZGlyICE9PSBwYXRoLmRpcm5hbWUoZGlyKSkge1xuICAgIC8vIDEuIHBucG0td29ya3NwYWNlLnlhbWw6IO2ZleyLpO2VnCBtb25vcmVwbyDro6jtirguXG4gICAgaWYgKGF3YWl0IGV4aXN0cyhwYXRoLmpvaW4oZGlyLCBcInBucG0td29ya3NwYWNlLnlhbWxcIikpKSB7XG4gICAgICByZXR1cm4gZGlyO1xuICAgIH1cblxuICAgIC8vIDIuIHBhY2thZ2UuanNvbuyXkCB3b3Jrc3BhY2VzIO2VhOuTnOqwgCDsnojsnLzrqbQgbW9ub3JlcG8g66Oo7Yq4LlxuICAgIGNvbnN0IHBhY2thZ2VQYXRoID0gcGF0aC5qb2luKGRpciwgXCJwYWNrYWdlLmpzb25cIik7XG4gICAgaWYgKGF3YWl0IGV4aXN0cyhwYWNrYWdlUGF0aCkpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VKc29uID0gSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShwYWNrYWdlUGF0aCwgXCJ1dGYtOFwiKSk7XG4gICAgICAgIGlmIChwYWNrYWdlSnNvbi53b3Jrc3BhY2VzKSB7XG4gICAgICAgICAgcmV0dXJuIGRpcjtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIO2MjOyLsSDsi6TtjKjsi5wg66y07IucXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMy4gLmFnZW50cy86IGFnZW50cyBpbml07J20IOyDneyEse2VnCDrlJTroInthqDrpqwuIOyEnOu4jO2MqO2CpOyngOyXkOuKlCDsobTsnqztlZjsp4Ag7JWK7J2MLlxuICAgIGlmIChhd2FpdCBleGlzdHMocGF0aC5qb2luKGRpciwgXCIuYWdlbnRzXCIpKSkge1xuICAgICAgcmV0dXJuIGRpcjtcbiAgICB9XG5cbiAgICBkaXIgPSBwYXRoLmRpcm5hbWUoZGlyKTtcbiAgfVxuXG4gIC8vIOywvuyngCDrqrvtlZjrqbQgYXBpIO2PtOuNlOydmCDrtoDrqqgg7IKs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
|