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/database/puri.js
CHANGED
|
@@ -1,1231 +1,1025 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import { __esmMin } from "../_virtual/rolldown_runtime.js";
|
|
2
|
+
import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
|
|
3
|
+
import { Naite, init_naite } from "../naite/naite.js";
|
|
4
|
+
import { FUZZY_OPERATORS, init_puri_types } from "./puri.types.js";
|
|
3
5
|
import inflection from "inflection";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
6
|
+
import assert from "assert";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
|
|
9
|
+
//#region src/database/puri.ts
|
|
7
10
|
function normalizeFuzzyOperator(operator) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
export class Puri {
|
|
16
|
-
knex;
|
|
17
|
-
knexQuery;
|
|
18
|
-
tableSpec = null;
|
|
19
|
-
constructor(knex, tableNameOrSource){
|
|
20
|
-
this.knex = knex;
|
|
21
|
-
if (typeof tableNameOrSource === "string") {
|
|
22
|
-
// Case: new Puri(knex, "users")
|
|
23
|
-
this.knexQuery = this.knex(tableNameOrSource).from(tableNameOrSource);
|
|
24
|
-
this.tableSpec = this.safeGetTableSpec(tableNameOrSource);
|
|
25
|
-
} else if (typeof tableNameOrSource === "object") {
|
|
26
|
-
const entries = Object.entries(tableNameOrSource);
|
|
27
|
-
if (entries.length !== 1) {
|
|
28
|
-
throw new Error("Table spec must have exactly one entry");
|
|
29
|
-
}
|
|
30
|
-
assert(entries[0]);
|
|
31
|
-
const [alias, source] = entries[0];
|
|
32
|
-
if (typeof source === "string") {
|
|
33
|
-
this.knexQuery = this.knex(source).from({
|
|
34
|
-
[alias]: source
|
|
35
|
-
});
|
|
36
|
-
this.tableSpec = this.safeGetTableSpec(source);
|
|
37
|
-
} else if (source instanceof Puri) {
|
|
38
|
-
const subqueryBuilder = source.rawQuery();
|
|
39
|
-
this.knexQuery = this.knex.from(subqueryBuilder.as(alias));
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error("Invalid table specification");
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
throw new Error("Invalid table specification");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
safeGetTableSpec(tableName) {
|
|
48
|
-
try {
|
|
49
|
-
return EntityManager.getTableSpec(tableName);
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Static SQL helper functions for SELECT
|
|
55
|
-
static count(column = "*") {
|
|
56
|
-
return {
|
|
57
|
-
_type: "sql_expression",
|
|
58
|
-
_return: "number",
|
|
59
|
-
_sql: `COUNT(??)::integer`,
|
|
60
|
-
_params: [
|
|
61
|
-
column
|
|
62
|
-
]
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
static sum(column) {
|
|
66
|
-
return {
|
|
67
|
-
_type: "sql_expression",
|
|
68
|
-
_return: "number",
|
|
69
|
-
_sql: `SUM(??)`,
|
|
70
|
-
_params: [
|
|
71
|
-
column
|
|
72
|
-
]
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
static avg(column) {
|
|
76
|
-
return {
|
|
77
|
-
_type: "sql_expression",
|
|
78
|
-
_return: "number",
|
|
79
|
-
_sql: `AVG(??)`,
|
|
80
|
-
_params: [
|
|
81
|
-
column
|
|
82
|
-
]
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
static max(column) {
|
|
86
|
-
return {
|
|
87
|
-
_type: "sql_expression",
|
|
88
|
-
_return: "number",
|
|
89
|
-
_sql: `MAX(??)`,
|
|
90
|
-
_params: [
|
|
91
|
-
column
|
|
92
|
-
]
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
static min(column) {
|
|
96
|
-
return {
|
|
97
|
-
_type: "sql_expression",
|
|
98
|
-
_return: "number",
|
|
99
|
-
_sql: `MIN(??)`,
|
|
100
|
-
_params: [
|
|
101
|
-
column
|
|
102
|
-
]
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
static concat(...args) {
|
|
106
|
-
return {
|
|
107
|
-
_type: "sql_expression",
|
|
108
|
-
_return: "string",
|
|
109
|
-
_sql: `CONCAT(${args.map(()=>"?").join(", ")})`,
|
|
110
|
-
_params: args
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
static upper(column) {
|
|
114
|
-
return {
|
|
115
|
-
_type: "sql_expression",
|
|
116
|
-
_return: "string",
|
|
117
|
-
_sql: "UPPER(??)",
|
|
118
|
-
_params: [
|
|
119
|
-
column
|
|
120
|
-
]
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
static lower(column) {
|
|
124
|
-
return {
|
|
125
|
-
_type: "sql_expression",
|
|
126
|
-
_return: "string",
|
|
127
|
-
_sql: "LOWER(??)",
|
|
128
|
-
_params: [
|
|
129
|
-
column
|
|
130
|
-
]
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
static wordSimilarity(column, query) {
|
|
134
|
-
if (typeof column === "string") {
|
|
135
|
-
return {
|
|
136
|
-
_type: "sql_expression",
|
|
137
|
-
_return: "number",
|
|
138
|
-
_sql: "word_similarity(?, ??)",
|
|
139
|
-
_params: [
|
|
140
|
-
query,
|
|
141
|
-
column
|
|
142
|
-
]
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
_type: "sql_expression",
|
|
147
|
-
_return: "number",
|
|
148
|
-
_sql: `word_similarity(?, ${column._sql})`,
|
|
149
|
-
_params: [
|
|
150
|
-
query,
|
|
151
|
-
...column._params
|
|
152
|
-
]
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
static similarity(column, query) {
|
|
156
|
-
if (typeof column === "string") {
|
|
157
|
-
return {
|
|
158
|
-
_type: "sql_expression",
|
|
159
|
-
_return: "number",
|
|
160
|
-
_sql: "similarity(??, ?)",
|
|
161
|
-
_params: [
|
|
162
|
-
column,
|
|
163
|
-
query
|
|
164
|
-
]
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
return {
|
|
168
|
-
_type: "sql_expression",
|
|
169
|
-
_return: "number",
|
|
170
|
-
_sql: `similarity(${column._sql}, ?)`,
|
|
171
|
-
_params: [
|
|
172
|
-
...column._params,
|
|
173
|
-
query
|
|
174
|
-
]
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
static strictWordSimilarity(column, query) {
|
|
178
|
-
if (typeof column === "string") {
|
|
179
|
-
return {
|
|
180
|
-
_type: "sql_expression",
|
|
181
|
-
_return: "number",
|
|
182
|
-
_sql: `strict_word_similarity(?, ??)`,
|
|
183
|
-
_params: [
|
|
184
|
-
query,
|
|
185
|
-
column
|
|
186
|
-
]
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
_type: "sql_expression",
|
|
191
|
-
_return: "number",
|
|
192
|
-
_sql: `strict_word_similarity(?, ${column._sql})`,
|
|
193
|
-
_params: [
|
|
194
|
-
query,
|
|
195
|
-
...column._params
|
|
196
|
-
]
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
// Raw functions for SELECT
|
|
200
|
-
static rawString(sql, params = []) {
|
|
201
|
-
return {
|
|
202
|
-
_type: "sql_expression",
|
|
203
|
-
_return: "string",
|
|
204
|
-
_sql: sql,
|
|
205
|
-
_params: params
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
static rawStringArray(sql, params = []) {
|
|
209
|
-
return {
|
|
210
|
-
_type: "sql_expression",
|
|
211
|
-
_return: "string[]",
|
|
212
|
-
_sql: sql,
|
|
213
|
-
_params: params
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
static rawNumber(sql, params = []) {
|
|
217
|
-
return {
|
|
218
|
-
_type: "sql_expression",
|
|
219
|
-
_return: "number",
|
|
220
|
-
_sql: sql,
|
|
221
|
-
_params: params
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
static rawBoolean(sql, params = []) {
|
|
225
|
-
return {
|
|
226
|
-
_type: "sql_expression",
|
|
227
|
-
_return: "boolean",
|
|
228
|
-
_sql: sql,
|
|
229
|
-
_params: params
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
static rawDate(sql, params = []) {
|
|
233
|
-
return {
|
|
234
|
-
_type: "sql_expression",
|
|
235
|
-
_return: "date",
|
|
236
|
-
_sql: sql,
|
|
237
|
-
_params: params
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* FTS 검색어 하이라이팅
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* .select({
|
|
245
|
-
* title: Puri.highlight("posts.title", search),
|
|
246
|
-
* content: Puri.highlight("posts.content", search, {
|
|
247
|
-
* startSel: "<mark>",
|
|
248
|
-
* stopSel: "</mark>",
|
|
249
|
-
* maxFragments: 3,
|
|
250
|
-
* }),
|
|
251
|
-
* })
|
|
252
|
-
*/ static tsHighlight(column, query, _options) {
|
|
253
|
-
const { parser = "websearch_to_tsquery", config = "simple", ...options } = _options ?? {};
|
|
254
|
-
const hlOptionParts = Object.entries(options).map(([key, value])=>{
|
|
255
|
-
return `${inflection.camelize(key)}=${value}`;
|
|
256
|
-
});
|
|
257
|
-
const hlOptions = hlOptionParts.length > 0 ? `, '${hlOptionParts.join(", ")}'` : "";
|
|
258
|
-
return {
|
|
259
|
-
_type: "sql_expression",
|
|
260
|
-
_return: "string",
|
|
261
|
-
_sql: `ts_headline(?, ??, ${parser}(?, ?)${hlOptions})`,
|
|
262
|
-
_params: [
|
|
263
|
-
config,
|
|
264
|
-
column,
|
|
265
|
-
config,
|
|
266
|
-
query
|
|
267
|
-
]
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
// ts_rank
|
|
271
|
-
static tsRank(column, query, options) {
|
|
272
|
-
return Puri._tsRank("ts_rank", column, query, options);
|
|
273
|
-
}
|
|
274
|
-
// ts_rank_cd
|
|
275
|
-
static tsRankCd(column, query, options) {
|
|
276
|
-
return Puri._tsRank("ts_rank_cd", column, query, options);
|
|
277
|
-
}
|
|
278
|
-
static toTsVector(column, config = "simple") {
|
|
279
|
-
return {
|
|
280
|
-
_type: "sql_expression",
|
|
281
|
-
_return: "tsvector",
|
|
282
|
-
_sql: `to_tsvector(?, ??)`,
|
|
283
|
-
_params: [
|
|
284
|
-
config,
|
|
285
|
-
column
|
|
286
|
-
]
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
static _tsRank(type, column, query, options) {
|
|
290
|
-
const { parser = "websearch_to_tsquery", config = "simple", normalization, weights } = options ?? {};
|
|
291
|
-
const params = [];
|
|
292
|
-
let sqlTemplate = `${type}(`;
|
|
293
|
-
if (weights) {
|
|
294
|
-
sqlTemplate += `ARRAY[${weights.map(()=>"?").join(", ")}]::float4[], `;
|
|
295
|
-
params.push(...weights);
|
|
296
|
-
}
|
|
297
|
-
if (typeof column === "string") {
|
|
298
|
-
sqlTemplate += `??, ${parser}(?, ?)`;
|
|
299
|
-
params.push(column, config, query);
|
|
300
|
-
} else {
|
|
301
|
-
sqlTemplate += `${column._sql}, ${parser}(?, ?)`;
|
|
302
|
-
params.push(...column._params, config, query);
|
|
303
|
-
}
|
|
304
|
-
if (normalization) {
|
|
305
|
-
sqlTemplate += ", ?";
|
|
306
|
-
params.push(normalization);
|
|
307
|
-
}
|
|
308
|
-
sqlTemplate += ")";
|
|
309
|
-
return {
|
|
310
|
-
_type: "sql_expression",
|
|
311
|
-
_return: "number",
|
|
312
|
-
_sql: sqlTemplate,
|
|
313
|
-
_params: params
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* PGroonga FullText 인덱스 검색 점수
|
|
318
|
-
*
|
|
319
|
-
* @example
|
|
320
|
-
* .select({
|
|
321
|
-
* score: Puri.score(),
|
|
322
|
-
* })
|
|
323
|
-
*/ static score() {
|
|
324
|
-
return Puri.rawNumber("pgroonga_score(tableoid, ctid)");
|
|
325
|
-
}
|
|
326
|
-
static highlight(columnOrColumns, query) {
|
|
327
|
-
const queryArr = Array.isArray(query) ? query : [
|
|
328
|
-
query
|
|
329
|
-
];
|
|
330
|
-
const queryClause = `ARRAY[${queryArr.map(()=>"?").join(", ")}]`;
|
|
331
|
-
// 단일 컬럼인 경우
|
|
332
|
-
if (typeof columnOrColumns === "string") {
|
|
333
|
-
return Puri.rawString(`pgroonga_highlight_html(??, ${queryClause})`, [
|
|
334
|
-
columnOrColumns,
|
|
335
|
-
...queryArr
|
|
336
|
-
]);
|
|
337
|
-
}
|
|
338
|
-
// 컬럼 배열인 경우
|
|
339
|
-
return Puri.rawStringArray(`pgroonga_highlight_html(ARRAY[${columnOrColumns.map(()=>"??").join(", ")}], ${queryClause})`, [
|
|
340
|
-
...columnOrColumns,
|
|
341
|
-
...queryArr
|
|
342
|
-
]);
|
|
343
|
-
}
|
|
344
|
-
// SELECT (overwrite)
|
|
345
|
-
select(selectObj) {
|
|
346
|
-
// 중첩 객체를 flat하게 변환
|
|
347
|
-
const flatSelect = this.flattenSelect(selectObj);
|
|
348
|
-
const selectClauses = [];
|
|
349
|
-
for (const [alias, columnOrFunction] of Object.entries(flatSelect)){
|
|
350
|
-
if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
|
|
351
|
-
// SQL 함수인 경우
|
|
352
|
-
selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS "${alias}"`, columnOrFunction._params));
|
|
353
|
-
} else {
|
|
354
|
-
// 일반 컬럼인 경우
|
|
355
|
-
const columnPath = columnOrFunction;
|
|
356
|
-
if (alias === columnPath) {
|
|
357
|
-
// alias와 컬럼명이 같으면 alias 생략
|
|
358
|
-
selectClauses.push(columnPath);
|
|
359
|
-
} else {
|
|
360
|
-
// alias 지정
|
|
361
|
-
selectClauses.push(`${columnPath} AS ${alias}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
this.knexQuery.select(selectClauses);
|
|
366
|
-
return this;
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* 중첩 객체를 flat 객체로 변환
|
|
370
|
-
* 예: { parent: { id: "parent.id", name: "parent.name" } }
|
|
371
|
-
* → { parent__id: "parent.id", parent__name: "parent.name" }
|
|
372
|
-
*/ flattenSelect(selectObj, prefix = "") {
|
|
373
|
-
const flatSelect = {};
|
|
374
|
-
for (const [key, value] of Object.entries(selectObj)){
|
|
375
|
-
const fullKey = prefix ? `${prefix}__${key}` : key;
|
|
376
|
-
if (typeof value === "object" && value !== null && !("_type" in value)) {
|
|
377
|
-
// 중첩 객체인 경우 - 재귀 처리
|
|
378
|
-
const nested = this.flattenSelect(value, fullKey);
|
|
379
|
-
Object.assign(flatSelect, nested);
|
|
380
|
-
} else {
|
|
381
|
-
// 일반 값인 경우 (컬럼 경로 또는 SqlExpression)
|
|
382
|
-
flatSelect[fullKey] = value;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return flatSelect;
|
|
386
|
-
}
|
|
387
|
-
// SELECT (select는 overwrite, appendSelect는 append)
|
|
388
|
-
appendSelect(selectObj) {
|
|
389
|
-
// 중첩 객체를 flat하게 변환
|
|
390
|
-
const flatSelect = this.flattenSelect(selectObj);
|
|
391
|
-
const selectClauses = [];
|
|
392
|
-
for (const [alias, columnOrFunction] of Object.entries(flatSelect)){
|
|
393
|
-
if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
|
|
394
|
-
selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS ${alias}`, columnOrFunction._params));
|
|
395
|
-
} else {
|
|
396
|
-
const columnPath = columnOrFunction;
|
|
397
|
-
if (alias === columnPath) {
|
|
398
|
-
selectClauses.push(columnPath);
|
|
399
|
-
} else {
|
|
400
|
-
selectClauses.push(this.knex.ref(columnPath).as(alias));
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
this.knexQuery.select(selectClauses);
|
|
405
|
-
return this;
|
|
406
|
-
}
|
|
407
|
-
// SELECT *
|
|
408
|
-
selectAll() {
|
|
409
|
-
this.knexQuery.select("*");
|
|
410
|
-
return this;
|
|
411
|
-
}
|
|
412
|
-
distinct(...columns) {
|
|
413
|
-
this.knexQuery.distinct(...columns);
|
|
414
|
-
return this;
|
|
415
|
-
}
|
|
416
|
-
// CLEAR
|
|
417
|
-
clear(statement) {
|
|
418
|
-
this.knexQuery.clear(statement);
|
|
419
|
-
return this;
|
|
420
|
-
}
|
|
421
|
-
// knex에 없어서 직접 구현함
|
|
422
|
-
clearJoin(alias) {
|
|
423
|
-
this.knexQuery._statements = this.knexQuery._statements.filter((s)=>{
|
|
424
|
-
if ("joinType" in s) {
|
|
425
|
-
const [_alias, _table] = Object.entries(s.table)[0];
|
|
426
|
-
return _alias !== alias;
|
|
427
|
-
} else {
|
|
428
|
-
return true;
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
return this;
|
|
432
|
-
}
|
|
433
|
-
// JOIN 실제 구현
|
|
434
|
-
join(tableNameOrSpec, ...args) {
|
|
435
|
-
return this.__commonJoin("join", tableNameOrSpec, ...args);
|
|
436
|
-
}
|
|
437
|
-
// LEFT JOIN 실제 구현
|
|
438
|
-
leftJoin(tableNameOrSpec, ...args) {
|
|
439
|
-
return this.__commonJoin("leftJoin", tableNameOrSpec, ...args);
|
|
440
|
-
}
|
|
441
|
-
__commonJoin(joinType, tableNameOrSpec, ...args) {
|
|
442
|
-
if (typeof tableNameOrSpec === "string") {
|
|
443
|
-
// Case 1: join("posts", ...)
|
|
444
|
-
const tableName = tableNameOrSpec;
|
|
445
|
-
if (args.length === 1 && typeof args[0] === "function") {
|
|
446
|
-
// join("posts", callback)
|
|
447
|
-
const callback = args[0];
|
|
448
|
-
this.knexQuery[joinType](tableName, (joinClause)=>{
|
|
449
|
-
callback(new JoinClauseGroup(joinClause));
|
|
450
|
-
});
|
|
451
|
-
} else {
|
|
452
|
-
// join("posts", left, right)
|
|
453
|
-
const [left, right] = args;
|
|
454
|
-
this.knexQuery[joinType](tableName, left, right);
|
|
455
|
-
}
|
|
456
|
-
} else if (typeof tableNameOrSpec === "object") {
|
|
457
|
-
// Case 2: join({ alias: "table" }, ...) or join({ alias: subquery }, ...)
|
|
458
|
-
const entries = Object.entries(tableNameOrSpec);
|
|
459
|
-
if (entries.length !== 1) {
|
|
460
|
-
throw new Error("Table spec must have exactly one entry");
|
|
461
|
-
}
|
|
462
|
-
assert(entries[0]);
|
|
463
|
-
const [[alias, spec]] = entries;
|
|
464
|
-
if (typeof spec === "string") {
|
|
465
|
-
// 테이블: join({ p: "posts" }, ...)
|
|
466
|
-
if (args.length === 1 && typeof args[0] === "function") {
|
|
467
|
-
// Callback
|
|
468
|
-
const callback = args[0];
|
|
469
|
-
this.knexQuery[joinType]({
|
|
470
|
-
[alias]: spec
|
|
471
|
-
}, (joinClause)=>{
|
|
472
|
-
callback(new JoinClauseGroup(joinClause));
|
|
473
|
-
});
|
|
474
|
-
} else {
|
|
475
|
-
// Simple
|
|
476
|
-
const [left, right] = args;
|
|
477
|
-
this.knexQuery[joinType]({
|
|
478
|
-
[alias]: spec
|
|
479
|
-
}, left, right);
|
|
480
|
-
}
|
|
481
|
-
} else if (spec instanceof Puri) {
|
|
482
|
-
// 서브쿼리: join({ sq: subquery }, ...)
|
|
483
|
-
if (args.length === 1 && typeof args[0] === "function") {
|
|
484
|
-
// Callback
|
|
485
|
-
const callback = args[0];
|
|
486
|
-
this.knexQuery[joinType](spec.rawQuery().as(alias), (joinClause)=>{
|
|
487
|
-
callback(new JoinClauseGroup(joinClause));
|
|
488
|
-
});
|
|
489
|
-
} else {
|
|
490
|
-
// Simple
|
|
491
|
-
const [left, right] = args;
|
|
492
|
-
this.knexQuery[joinType](spec.rawQuery().as(alias), left, right);
|
|
493
|
-
}
|
|
494
|
-
} else {
|
|
495
|
-
throw new Error("Invalid table specification");
|
|
496
|
-
}
|
|
497
|
-
} else {
|
|
498
|
-
throw new Error("Invalid arguments");
|
|
499
|
-
}
|
|
500
|
-
return this;
|
|
501
|
-
}
|
|
502
|
-
// WHERE: 컬럼 - 사용: .where("u.id", "like", "%test%")
|
|
503
|
-
where(...args) {
|
|
504
|
-
const [columnOrConditions, operatorOrValue, value] = args;
|
|
505
|
-
if (typeof columnOrConditions === "object") {
|
|
506
|
-
this.knexQuery.where(columnOrConditions);
|
|
507
|
-
} else if (typeof value === "undefined") {
|
|
508
|
-
if (operatorOrValue === null) {
|
|
509
|
-
this.knexQuery.whereNull(columnOrConditions);
|
|
510
|
-
return this;
|
|
511
|
-
}
|
|
512
|
-
this.knexQuery.where(columnOrConditions, operatorOrValue);
|
|
513
|
-
} else if (typeof value !== "undefined") {
|
|
514
|
-
if (value === null) {
|
|
515
|
-
if (operatorOrValue === "!=") {
|
|
516
|
-
this.knexQuery.whereNotNull(columnOrConditions);
|
|
517
|
-
return this;
|
|
518
|
-
} else if (operatorOrValue === "=") {
|
|
519
|
-
this.knexQuery.whereNull(columnOrConditions);
|
|
520
|
-
return this;
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
this.knexQuery.where(columnOrConditions, operatorOrValue, value);
|
|
524
|
-
} else {
|
|
525
|
-
this.knexQuery.where(columnOrConditions);
|
|
526
|
-
}
|
|
527
|
-
return this;
|
|
528
|
-
}
|
|
529
|
-
// WHERE IN
|
|
530
|
-
whereIn(column, values) {
|
|
531
|
-
this.knexQuery.whereIn(column, values);
|
|
532
|
-
return this;
|
|
533
|
-
}
|
|
534
|
-
// WHERE NOT IN
|
|
535
|
-
whereNotIn(column, values) {
|
|
536
|
-
this.knexQuery.whereNotIn(column, values);
|
|
537
|
-
return this;
|
|
538
|
-
}
|
|
539
|
-
// WHERE MATCH
|
|
540
|
-
whereMatch(column, value) {
|
|
541
|
-
this.knexQuery.whereRaw(`MATCH (${String(column)}) AGAINST (?)`, [
|
|
542
|
-
value
|
|
543
|
-
]);
|
|
544
|
-
return this;
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* PGroonga FullText 인덱스 검색
|
|
548
|
-
* - 사용할 PGroonga 인덱스와 동일한 컬럼 구성으로 검색해야 인덱스가 사용됩니다.
|
|
549
|
-
*
|
|
550
|
-
* 단일 컬럼 검색:
|
|
551
|
-
* ```sql
|
|
552
|
-
* WHERE name &@~ 'search'
|
|
553
|
-
* ```
|
|
554
|
-
*
|
|
555
|
-
* 복합 컬럼 검색:
|
|
556
|
-
* ```sql
|
|
557
|
-
* WHERE ARRAY[name::text, description::text] &@~ 'search'
|
|
558
|
-
* ```
|
|
559
|
-
*/ whereSearch(column, value, options) {
|
|
560
|
-
const { weights } = options ?? {};
|
|
561
|
-
const columnExpr = Array.isArray(column) ? `ARRAY[${column.map((c)=>`${c}::text`).join(",")}]` : column;
|
|
562
|
-
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
563
|
-
this.knexQuery.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
|
|
564
|
-
value
|
|
565
|
-
]);
|
|
566
|
-
return this;
|
|
567
|
-
}
|
|
568
|
-
// WHERE FULLTEXT
|
|
569
|
-
whereTsSearch(column, value, options) {
|
|
570
|
-
const opts = typeof options === "string" ? {
|
|
571
|
-
config: options
|
|
572
|
-
} : options ?? {};
|
|
573
|
-
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
574
|
-
const config = opts.config ?? "simple";
|
|
575
|
-
const columnExpr = typeof column === "object" && column._type === "sql_expression" ? column._sql : String(column);
|
|
576
|
-
this.knexQuery.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
|
|
577
|
-
config,
|
|
578
|
-
value
|
|
579
|
-
]);
|
|
580
|
-
return this;
|
|
581
|
-
}
|
|
582
|
-
whereFuzzy(column, value, options) {
|
|
583
|
-
const operator = normalizeFuzzyOperator(options?.operator);
|
|
584
|
-
if (operator === "%") {
|
|
585
|
-
if (typeof column === "object") {
|
|
586
|
-
this.knexQuery.whereRaw(`${column._sql} ${operator} ?`, [
|
|
587
|
-
...column._params,
|
|
588
|
-
value
|
|
589
|
-
]);
|
|
590
|
-
} else {
|
|
591
|
-
this.knexQuery.whereRaw(`?? ${operator} ?`, [
|
|
592
|
-
column,
|
|
593
|
-
value
|
|
594
|
-
]);
|
|
595
|
-
}
|
|
596
|
-
return this;
|
|
597
|
-
}
|
|
598
|
-
if (typeof column === "object") {
|
|
599
|
-
this.knexQuery.whereRaw(`? ${operator} ${column._sql}`, [
|
|
600
|
-
value,
|
|
601
|
-
...column._params
|
|
602
|
-
]);
|
|
603
|
-
} else {
|
|
604
|
-
this.knexQuery.whereRaw(`? ${operator} ??`, [
|
|
605
|
-
value,
|
|
606
|
-
column
|
|
607
|
-
]);
|
|
608
|
-
}
|
|
609
|
-
return this;
|
|
610
|
-
}
|
|
611
|
-
// WHERE RAW
|
|
612
|
-
whereRaw(sql, bindings) {
|
|
613
|
-
this.knexQuery.whereRaw(sql, bindings);
|
|
614
|
-
return this;
|
|
615
|
-
}
|
|
616
|
-
// WHERE 괄호 그룹핑
|
|
617
|
-
whereGroup(callback) {
|
|
618
|
-
this.knexQuery.where((builder)=>{
|
|
619
|
-
const group = new WhereGroup(builder);
|
|
620
|
-
callback(group);
|
|
621
|
-
});
|
|
622
|
-
return this;
|
|
623
|
-
}
|
|
624
|
-
orWhereGroup(callback) {
|
|
625
|
-
this.knexQuery.orWhere((builder)=>{
|
|
626
|
-
const group = new WhereGroup(builder);
|
|
627
|
-
callback(group);
|
|
628
|
-
});
|
|
629
|
-
return this;
|
|
630
|
-
}
|
|
631
|
-
orderBy(column, direction = "asc") {
|
|
632
|
-
if (typeof column === "object") {
|
|
633
|
-
this.knexQuery.orderByRaw(`${column._sql} ${direction}`, column._params);
|
|
634
|
-
} else {
|
|
635
|
-
this.knexQuery.orderBy(column, direction);
|
|
636
|
-
}
|
|
637
|
-
return this;
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* 벡터 유사도 검색 설정
|
|
641
|
-
*
|
|
642
|
-
* - SELECT에 similarity 컬럼 추가
|
|
643
|
-
* - WHERE col IS NOT NULL 추가
|
|
644
|
-
* - threshold가 있으면 WHERE 조건 추가
|
|
645
|
-
* - 기존 ORDER BY를 clear하고 원시 연산자로 정렬 (HNSW 인덱스 최적화)
|
|
646
|
-
*
|
|
647
|
-
* @param column 벡터 컬럼 경로
|
|
648
|
-
* @param embedding 쿼리 임베딩 벡터
|
|
649
|
-
* @param options method, threshold, as 등 옵션
|
|
650
|
-
*
|
|
651
|
-
* @example
|
|
652
|
-
* ```typescript
|
|
653
|
-
* // cosine similarity (기본값)
|
|
654
|
-
* qb.vectorSimilarity("columnName", queryVector, {
|
|
655
|
-
* method: "cosine",
|
|
656
|
-
* threshold: 0.5
|
|
657
|
-
* });
|
|
658
|
-
*
|
|
659
|
-
* // L2 distance
|
|
660
|
-
* qb.vectorSimilarity("columnName", queryVector, {
|
|
661
|
-
* method: "l2",
|
|
662
|
-
* threshold: 1.5 // 거리가 1.5 이하인 결과만
|
|
663
|
-
* });
|
|
664
|
-
*
|
|
665
|
-
* // Inner product
|
|
666
|
-
* qb.vectorSimilarity("columnName", queryVector, {
|
|
667
|
-
* method: "inner_product",
|
|
668
|
-
* threshold: 0.7
|
|
669
|
-
* });
|
|
670
|
-
* ```
|
|
671
|
-
*/ vectorSimilarity(column, embedding, options = {}) {
|
|
672
|
-
const { method = "cosine", threshold, distinctOn } = options;
|
|
673
|
-
if (!Array.isArray(embedding) || embedding.length === 0 || embedding.some((v)=>!Number.isFinite(v))) {
|
|
674
|
-
throw new Error("Invalid embedding vector: expected a non-empty array of finite numbers");
|
|
675
|
-
}
|
|
676
|
-
const vectorLiteral = JSON.stringify(embedding.map((v)=>Number(v)));
|
|
677
|
-
const operator = {
|
|
678
|
-
cosine: "<=>",
|
|
679
|
-
l2: "<->",
|
|
680
|
-
inner_product: "<#>"
|
|
681
|
-
}[method];
|
|
682
|
-
// method별 연산자 및 similarity 계산식
|
|
683
|
-
// - cosine: <=> (cosine distance, 0~2), similarity = 1 - distance
|
|
684
|
-
// - l2: <-> (euclidean distance), similarity = distance (낮을수록 유사)
|
|
685
|
-
// - inner_product: <#> (negative inner product), similarity = -distance (높을수록 유사)
|
|
686
|
-
const similarityExpr = method === "cosine" ? this.knex.raw(`1 - (?? ${operator} ?::vector) as similarity`, [
|
|
687
|
-
column,
|
|
688
|
-
vectorLiteral
|
|
689
|
-
]) : method === "l2" ? this.knex.raw(`?? ${operator} ?::vector as similarity`, [
|
|
690
|
-
column,
|
|
691
|
-
vectorLiteral
|
|
692
|
-
]) : this.knex.raw(`-(?? ${operator} ?::vector) as similarity`, [
|
|
693
|
-
column,
|
|
694
|
-
vectorLiteral
|
|
695
|
-
]);
|
|
696
|
-
// WHERE NOT NULL
|
|
697
|
-
this.knexQuery.whereNotNull(column);
|
|
698
|
-
// 기존 ORDER BY clear
|
|
699
|
-
this.knexQuery.clear("order");
|
|
700
|
-
if (distinctOn) {
|
|
701
|
-
// DISTINCT ON은 SELECT 절의 맨 앞에 와야 하므로, 기존 select(subset 필드들)를 보존 후 clear하고 다시 추가
|
|
702
|
-
const existingSubsetCols = this.knexQuery._statements.filter((s)=>s.grouping === "columns").flatMap((s)=>s.value);
|
|
703
|
-
this.knexQuery.clear("select");
|
|
704
|
-
this.knexQuery.select(this.knex.raw(`DISTINCT ON (??) ??`, [
|
|
705
|
-
distinctOn,
|
|
706
|
-
distinctOn
|
|
707
|
-
]));
|
|
708
|
-
existingSubsetCols.map((col)=>this.knexQuery.select(col));
|
|
709
|
-
this.knexQuery.select(similarityExpr);
|
|
710
|
-
this.knexQuery.orderByRaw(`??, ?? ${operator} ?::vector`, [
|
|
711
|
-
distinctOn,
|
|
712
|
-
column,
|
|
713
|
-
vectorLiteral
|
|
714
|
-
]);
|
|
715
|
-
this.knexQuery = this.knex.from(this.knexQuery.as("distinct_vectors")).select("*").orderBy("similarity", "desc");
|
|
716
|
-
} else {
|
|
717
|
-
this.knexQuery.select(similarityExpr);
|
|
718
|
-
this.knexQuery.orderByRaw(`?? ${operator} ?::vector`, [
|
|
719
|
-
column,
|
|
720
|
-
vectorLiteral
|
|
721
|
-
]);
|
|
722
|
-
}
|
|
723
|
-
// threshold
|
|
724
|
-
if (typeof threshold === "number") {
|
|
725
|
-
if (!Number.isFinite(threshold)) {
|
|
726
|
-
throw new Error(`Invalid vectorSimilarity threshold: ${threshold}`);
|
|
727
|
-
}
|
|
728
|
-
if (distinctOn) {
|
|
729
|
-
const thresholdOp = method === "l2" ? "<=" : ">=";
|
|
730
|
-
this.knexQuery.where("similarity", thresholdOp, threshold);
|
|
731
|
-
} else {
|
|
732
|
-
const thresholdValue = method === "cosine" ? 1 - threshold : method === "inner_product" ? -threshold : threshold;
|
|
733
|
-
this.knexQuery.whereRaw(`?? ${operator} ?::vector <= ?`, [
|
|
734
|
-
column,
|
|
735
|
-
vectorLiteral,
|
|
736
|
-
thresholdValue
|
|
737
|
-
]);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
return this;
|
|
741
|
-
}
|
|
742
|
-
// 기본 쿼리 메서드들
|
|
743
|
-
limit(count) {
|
|
744
|
-
if (count < 0) {
|
|
745
|
-
throw new Error("Invalid limit: must be >= 0");
|
|
746
|
-
}
|
|
747
|
-
this.knexQuery.limit(count);
|
|
748
|
-
return this;
|
|
749
|
-
}
|
|
750
|
-
offset(count) {
|
|
751
|
-
if (count < 0) {
|
|
752
|
-
throw new Error("Invalid offset: must be >= 0");
|
|
753
|
-
}
|
|
754
|
-
this.knexQuery.offset(count);
|
|
755
|
-
return this;
|
|
756
|
-
}
|
|
757
|
-
groupBy(...columns) {
|
|
758
|
-
this.knexQuery.groupBy(...columns);
|
|
759
|
-
return this;
|
|
760
|
-
}
|
|
761
|
-
// HAVING 구현
|
|
762
|
-
having(...conditions) {
|
|
763
|
-
if (conditions.length === 1) {
|
|
764
|
-
// having("COUNT(*) > 10")
|
|
765
|
-
this.knexQuery.having(this.knex.raw(conditions[0]));
|
|
766
|
-
} else if (conditions.length === 3) {
|
|
767
|
-
// having("count", ">", 10)
|
|
768
|
-
this.knexQuery.having(this.knex.raw(conditions[0]), conditions[1], this.knex.raw(conditions[2]));
|
|
769
|
-
} else {
|
|
770
|
-
throw new Error("Invalid having arguments");
|
|
771
|
-
}
|
|
772
|
-
return this;
|
|
773
|
-
}
|
|
774
|
-
// 실행 메서드들 - thenable 구현
|
|
775
|
-
then(onfulfilled, onrejected) {
|
|
776
|
-
Naite.t("puri:executed-query", this.toQuery());
|
|
777
|
-
return this.knexQuery.then(onfulfilled, onrejected);
|
|
778
|
-
}
|
|
779
|
-
catch(onrejected) {
|
|
780
|
-
return this.knexQuery.catch(onrejected);
|
|
781
|
-
}
|
|
782
|
-
finally(onfinally) {
|
|
783
|
-
return this.knexQuery.finally(onfinally);
|
|
784
|
-
}
|
|
785
|
-
// 하나만 쿼리
|
|
786
|
-
first() {
|
|
787
|
-
this.knexQuery.first();
|
|
788
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
789
|
-
}
|
|
790
|
-
// 쿼리한 레코드에서 특정 컬럼만 추출한 배열 리턴
|
|
791
|
-
pluck(column) {
|
|
792
|
-
this.knexQuery.pluck(column);
|
|
793
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
794
|
-
}
|
|
795
|
-
// INSERT 실제 구현
|
|
796
|
-
insert(rawData) {
|
|
797
|
-
// JSON 컬럼 stringify 로직을 메서드로 분리하여 중복 제거
|
|
798
|
-
const refinedData = this.refineJsonColumns(rawData);
|
|
799
|
-
this.knexQuery.insert(refinedData);
|
|
800
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
801
|
-
}
|
|
802
|
-
// UPDATE
|
|
803
|
-
update(rawData) {
|
|
804
|
-
// JSON 컬럼 stringify 로직을 메서드로 분리하여 중복 제거
|
|
805
|
-
const refinedData = this.refineJsonColumns(rawData);
|
|
806
|
-
this.knexQuery.update(refinedData);
|
|
807
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* JSON 컬럼에 대해 stringify 처리를 수행하는 내부 메서드입니다.
|
|
811
|
-
* object 또는 object 배열을 받고, JSON 컬럼이 있으면 직렬화하여 반환합니다.
|
|
812
|
-
* 직접 값을 변경하므로 side effect가 있습니다.
|
|
813
|
-
*/ refineJsonColumns(data) {
|
|
814
|
-
// tableSpec이나 jsonColumns 없는 경우 바로 반환
|
|
815
|
-
if (!this.tableSpec || !this.tableSpec.jsonColumns.length) {
|
|
816
|
-
return data;
|
|
817
|
-
}
|
|
818
|
-
// 등록된 TableSpec을 통해 JSON컬럼 목록을 가져와 JSON.stringify 처리
|
|
819
|
-
const jsonColumns = this.tableSpec.jsonColumns;
|
|
820
|
-
if (Array.isArray(data)) {
|
|
821
|
-
for (const item of data){
|
|
822
|
-
for (const column of jsonColumns){
|
|
823
|
-
const value = item[column];
|
|
824
|
-
if (value !== undefined && value !== null) {
|
|
825
|
-
item[column] = JSON.stringify(value);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
} else {
|
|
830
|
-
for (const column of jsonColumns){
|
|
831
|
-
const value = data[column];
|
|
832
|
-
if (value !== undefined && value !== null) {
|
|
833
|
-
data[column] = JSON.stringify(value);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
return data;
|
|
838
|
-
}
|
|
839
|
-
// Increment
|
|
840
|
-
increment(column, value) {
|
|
841
|
-
if (value <= 0) {
|
|
842
|
-
throw new Error("Increment value must be greater than 0");
|
|
843
|
-
}
|
|
844
|
-
this.knexQuery.increment(column, value);
|
|
845
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
846
|
-
}
|
|
847
|
-
// Decrement
|
|
848
|
-
decrement(column, value) {
|
|
849
|
-
if (value <= 0) {
|
|
850
|
-
throw new Error("Decrement value must be greater than 0");
|
|
851
|
-
}
|
|
852
|
-
this.knexQuery.decrement(column, value);
|
|
853
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
854
|
-
}
|
|
855
|
-
// DELETE
|
|
856
|
-
delete() {
|
|
857
|
-
this.knexQuery.delete();
|
|
858
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
859
|
-
}
|
|
860
|
-
// 확인 쿼리 리턴
|
|
861
|
-
toQuery() {
|
|
862
|
-
return this.knexQuery.toQuery();
|
|
863
|
-
}
|
|
864
|
-
// 쿼리 디버깅 로그 출력
|
|
865
|
-
debug() {
|
|
866
|
-
console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
|
|
867
|
-
return this;
|
|
868
|
-
}
|
|
869
|
-
clone() {
|
|
870
|
-
// 'dual'은 더미 테이블이며, 바로 아래 줄에서 knexQuery가 덮어씌워집니다.
|
|
871
|
-
const newPuri = new Puri(this.knex, "dual");
|
|
872
|
-
newPuri.knexQuery = this.knexQuery.clone();
|
|
873
|
-
return newPuri;
|
|
874
|
-
}
|
|
875
|
-
formatSQL(unformatted) {
|
|
876
|
-
// SQL 예약어 목록
|
|
877
|
-
const keywords = [
|
|
878
|
-
"SELECT",
|
|
879
|
-
"FROM",
|
|
880
|
-
"WHERE",
|
|
881
|
-
"INSERT",
|
|
882
|
-
"INTO",
|
|
883
|
-
"VALUES",
|
|
884
|
-
"UPDATE",
|
|
885
|
-
"DELETE",
|
|
886
|
-
"CREATE",
|
|
887
|
-
"TABLE",
|
|
888
|
-
"ALTER",
|
|
889
|
-
"DROP",
|
|
890
|
-
"JOIN",
|
|
891
|
-
"ON",
|
|
892
|
-
"INNER",
|
|
893
|
-
"LEFT",
|
|
894
|
-
"RIGHT",
|
|
895
|
-
"FULL",
|
|
896
|
-
"OUTER",
|
|
897
|
-
"GROUP",
|
|
898
|
-
"BY",
|
|
899
|
-
"ORDER",
|
|
900
|
-
"HAVING",
|
|
901
|
-
"DISTINCT",
|
|
902
|
-
"LIMIT",
|
|
903
|
-
"OFFSET",
|
|
904
|
-
"AS",
|
|
905
|
-
"AND",
|
|
906
|
-
"OR",
|
|
907
|
-
"NOT",
|
|
908
|
-
"IN",
|
|
909
|
-
"LIKE",
|
|
910
|
-
"IS",
|
|
911
|
-
"NULL",
|
|
912
|
-
"CASE",
|
|
913
|
-
"WHEN",
|
|
914
|
-
"THEN",
|
|
915
|
-
"ELSE",
|
|
916
|
-
"END",
|
|
917
|
-
"UNION",
|
|
918
|
-
"ALL",
|
|
919
|
-
"EXISTS",
|
|
920
|
-
"BETWEEN"
|
|
921
|
-
];
|
|
922
|
-
let formatted = unformatted;
|
|
923
|
-
// 예약어를 대문자로 변환
|
|
924
|
-
keywords.forEach((keyword)=>{
|
|
925
|
-
const regex = new RegExp(`\\b${keyword}\\b`, "gi");
|
|
926
|
-
formatted = formatted.replace(regex, keyword.toUpperCase());
|
|
927
|
-
});
|
|
928
|
-
// 주요 절 앞에 줄바꿈 추가
|
|
929
|
-
const majorClauses = [
|
|
930
|
-
"SELECT",
|
|
931
|
-
"FROM",
|
|
932
|
-
"WHERE",
|
|
933
|
-
"GROUP BY",
|
|
934
|
-
"ORDER BY",
|
|
935
|
-
"HAVING",
|
|
936
|
-
"LIMIT",
|
|
937
|
-
"UNION"
|
|
938
|
-
];
|
|
939
|
-
majorClauses.forEach((clause)=>{
|
|
940
|
-
const regex = new RegExp(`\\s+(${clause})\\s+`, "gi");
|
|
941
|
-
formatted = formatted.replace(regex, `\n${clause.toUpperCase()} `);
|
|
942
|
-
});
|
|
943
|
-
// JOIN 절 처리
|
|
944
|
-
formatted = formatted.replace(/\s+((?:INNER|LEFT|RIGHT|FULL OUTER)\s+)?JOIN\s+/gi, "\n$1JOIN ");
|
|
945
|
-
// AND, OR 조건 처리
|
|
946
|
-
formatted = formatted.replace(/\s+(AND|OR)\s+/gi, "\n $1 ");
|
|
947
|
-
// 괄호 처리 및 들여쓰기
|
|
948
|
-
const lines = formatted.split("\n");
|
|
949
|
-
const indentedLines = [];
|
|
950
|
-
let indentLevel = 0;
|
|
951
|
-
for (const line of lines){
|
|
952
|
-
const trimmedLine = line.trim();
|
|
953
|
-
if (!trimmedLine) continue;
|
|
954
|
-
// 닫는 괄호가 있으면 들여쓰기 레벨 감소
|
|
955
|
-
const closingParens = (trimmedLine.match(/\)/g) || []).length;
|
|
956
|
-
const openingParens = (trimmedLine.match(/\(/g) || []).length;
|
|
957
|
-
if (closingParens > 0 && openingParens === 0) {
|
|
958
|
-
indentLevel = Math.max(0, indentLevel - closingParens);
|
|
959
|
-
}
|
|
960
|
-
// 현재 들여쓰기 적용
|
|
961
|
-
const indent = " ".repeat(indentLevel);
|
|
962
|
-
indentedLines.push(indent + trimmedLine);
|
|
963
|
-
// 여는 괄호가 있으면 들여쓰기 레벨 증가
|
|
964
|
-
if (openingParens > closingParens) {
|
|
965
|
-
indentLevel += openingParens - closingParens;
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return indentedLines.join("\n").trim();
|
|
969
|
-
}
|
|
970
|
-
raw(sql) {
|
|
971
|
-
return this.knex.raw(sql);
|
|
972
|
-
}
|
|
973
|
-
// Knex 쿼리 빌더 직접 접근
|
|
974
|
-
rawQuery() {
|
|
975
|
-
return this.knexQuery;
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
export class WhereGroup {
|
|
979
|
-
builder;
|
|
980
|
-
constructor(builder){
|
|
981
|
-
this.builder = builder;
|
|
982
|
-
}
|
|
983
|
-
where(...args) {
|
|
984
|
-
this.builder.where(args[0], ...args.slice(1));
|
|
985
|
-
return this;
|
|
986
|
-
}
|
|
987
|
-
whereIn(...args) {
|
|
988
|
-
this.builder.whereIn(args[0], args[1]);
|
|
989
|
-
return this;
|
|
990
|
-
}
|
|
991
|
-
whereNotIn(...args) {
|
|
992
|
-
this.builder.whereNotIn(args[0], args[1]);
|
|
993
|
-
return this;
|
|
994
|
-
}
|
|
995
|
-
orWhere(...args) {
|
|
996
|
-
this.builder.orWhere(args[0], ...args.slice(1));
|
|
997
|
-
return this;
|
|
998
|
-
}
|
|
999
|
-
orWhereIn(...args) {
|
|
1000
|
-
this.builder.orWhereIn(args[0], args[1]);
|
|
1001
|
-
return this;
|
|
1002
|
-
}
|
|
1003
|
-
orWhereNotIn(...args) {
|
|
1004
|
-
this.builder.orWhereNotIn(args[0], args[1]);
|
|
1005
|
-
return this;
|
|
1006
|
-
}
|
|
1007
|
-
whereMatch(...args) {
|
|
1008
|
-
this.builder.whereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [
|
|
1009
|
-
args[1]
|
|
1010
|
-
]);
|
|
1011
|
-
return this;
|
|
1012
|
-
}
|
|
1013
|
-
orWhereMatch(...args) {
|
|
1014
|
-
this.builder.orWhereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [
|
|
1015
|
-
args[1]
|
|
1016
|
-
]);
|
|
1017
|
-
return this;
|
|
1018
|
-
}
|
|
1019
|
-
whereSearch(...args) {
|
|
1020
|
-
const { weights } = args[2] ?? {};
|
|
1021
|
-
const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c)=>`${c}::text`).join(",")}]` : args[0];
|
|
1022
|
-
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
1023
|
-
this.builder.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
|
|
1024
|
-
args[1]
|
|
1025
|
-
]);
|
|
1026
|
-
return this;
|
|
1027
|
-
}
|
|
1028
|
-
orWhereSearch(...args) {
|
|
1029
|
-
const { weights } = args[2] ?? {};
|
|
1030
|
-
const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c)=>`${c}::text`).join(",")}]` : args[0];
|
|
1031
|
-
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
1032
|
-
this.builder.orWhereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
|
|
1033
|
-
args[1]
|
|
1034
|
-
]);
|
|
1035
|
-
return this;
|
|
1036
|
-
}
|
|
1037
|
-
whereTsSearch(...args) {
|
|
1038
|
-
const opts = typeof args[2] === "string" ? {
|
|
1039
|
-
config: args[2]
|
|
1040
|
-
} : args[2] ?? {};
|
|
1041
|
-
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
1042
|
-
const config = opts.config ?? "simple";
|
|
1043
|
-
const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
|
|
1044
|
-
this.builder.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
|
|
1045
|
-
config,
|
|
1046
|
-
args[1]
|
|
1047
|
-
]);
|
|
1048
|
-
return this;
|
|
1049
|
-
}
|
|
1050
|
-
orWhereTsSearch(...args) {
|
|
1051
|
-
const opts = typeof args[2] === "string" ? {
|
|
1052
|
-
config: args[2]
|
|
1053
|
-
} : args[2] ?? {};
|
|
1054
|
-
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
1055
|
-
const config = opts.config ?? "simple";
|
|
1056
|
-
const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
|
|
1057
|
-
this.builder.orWhereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
|
|
1058
|
-
config,
|
|
1059
|
-
args[1]
|
|
1060
|
-
]);
|
|
1061
|
-
return this;
|
|
1062
|
-
}
|
|
1063
|
-
whereFuzzy(...args) {
|
|
1064
|
-
const operator = normalizeFuzzyOperator(args[2]?.operator);
|
|
1065
|
-
if (operator === "%") {
|
|
1066
|
-
if (typeof args[0] === "object") {
|
|
1067
|
-
this.builder.whereRaw(`${args[0]._sql} ${operator} ?`, [
|
|
1068
|
-
...args[0]._params,
|
|
1069
|
-
args[1]
|
|
1070
|
-
]);
|
|
1071
|
-
} else {
|
|
1072
|
-
this.builder.whereRaw(`?? ${operator} ?`, [
|
|
1073
|
-
args[0],
|
|
1074
|
-
args[1]
|
|
1075
|
-
]);
|
|
1076
|
-
}
|
|
1077
|
-
return this;
|
|
1078
|
-
}
|
|
1079
|
-
if (typeof args[0] === "object") {
|
|
1080
|
-
this.builder.whereRaw(`? ${operator} ${args[0]._sql}`, [
|
|
1081
|
-
args[1],
|
|
1082
|
-
...args[0]._params
|
|
1083
|
-
]);
|
|
1084
|
-
} else {
|
|
1085
|
-
this.builder.whereRaw(`? ${operator} ??`, [
|
|
1086
|
-
args[1],
|
|
1087
|
-
args[0]
|
|
1088
|
-
]);
|
|
1089
|
-
}
|
|
1090
|
-
return this;
|
|
1091
|
-
}
|
|
1092
|
-
orWhereFuzzy(...args) {
|
|
1093
|
-
const operator = normalizeFuzzyOperator(args[2]?.operator);
|
|
1094
|
-
if (operator === "%") {
|
|
1095
|
-
if (typeof args[0] === "object") {
|
|
1096
|
-
this.builder.orWhereRaw(`${args[0]._sql} ${operator} ?`, [
|
|
1097
|
-
...args[0]._params,
|
|
1098
|
-
args[1]
|
|
1099
|
-
]);
|
|
1100
|
-
} else {
|
|
1101
|
-
this.builder.orWhereRaw(`?? ${operator} ?`, [
|
|
1102
|
-
args[0],
|
|
1103
|
-
args[1]
|
|
1104
|
-
]);
|
|
1105
|
-
}
|
|
1106
|
-
return this;
|
|
1107
|
-
}
|
|
1108
|
-
if (typeof args[0] === "object") {
|
|
1109
|
-
this.builder.orWhereRaw(`? ${operator} ${args[0]._sql}`, [
|
|
1110
|
-
args[1],
|
|
1111
|
-
...args[0]._params
|
|
1112
|
-
]);
|
|
1113
|
-
} else {
|
|
1114
|
-
this.builder.orWhereRaw(`? ${operator} ??`, [
|
|
1115
|
-
args[1],
|
|
1116
|
-
args[0]
|
|
1117
|
-
]);
|
|
1118
|
-
}
|
|
1119
|
-
return this;
|
|
1120
|
-
}
|
|
1121
|
-
whereGroup(callback) {
|
|
1122
|
-
this.builder.where((subBuilder)=>{
|
|
1123
|
-
const subGroup = new WhereGroup(subBuilder);
|
|
1124
|
-
callback(subGroup);
|
|
1125
|
-
});
|
|
1126
|
-
return this;
|
|
1127
|
-
}
|
|
1128
|
-
orWhereGroup(callback) {
|
|
1129
|
-
this.builder.orWhere((subBuilder)=>{
|
|
1130
|
-
const subGroup = new WhereGroup(subBuilder);
|
|
1131
|
-
callback(subGroup);
|
|
1132
|
-
});
|
|
1133
|
-
return this;
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
// JOIN 절 그룹에는 Left와 Right에 대한 순서가 필요하지 않으므로, 모든 경우의 수를 계산해야함.
|
|
1137
|
-
export class JoinClauseGroup {
|
|
1138
|
-
callback;
|
|
1139
|
-
constructor(callback){
|
|
1140
|
-
this.callback = callback;
|
|
1141
|
-
}
|
|
1142
|
-
// ON(AND) 구현
|
|
1143
|
-
on(...args) {
|
|
1144
|
-
this.callback.on(...args);
|
|
1145
|
-
return this;
|
|
1146
|
-
}
|
|
1147
|
-
// ON(OR) 구현
|
|
1148
|
-
orOn(...args) {
|
|
1149
|
-
this.callback.orOn(...args);
|
|
1150
|
-
return this;
|
|
1151
|
-
}
|
|
1152
|
-
onVal(...args) {
|
|
1153
|
-
this.callback.onVal(...args);
|
|
1154
|
-
return this;
|
|
1155
|
-
}
|
|
1156
|
-
andOnVal(...args) {
|
|
1157
|
-
this.callback.andOnVal(...args);
|
|
1158
|
-
return this;
|
|
1159
|
-
}
|
|
1160
|
-
orOnVal(...args) {
|
|
1161
|
-
this.callback.orOnVal(...args);
|
|
1162
|
-
return this;
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
/*
|
|
1166
|
-
TResolved: 쿼리 실행 후 반환될 결과 타입
|
|
1167
|
-
TReturning: RETURNING 절에 사용될 타입
|
|
1168
|
-
*/ export class ResolvedPuri {
|
|
1169
|
-
knexQuery;
|
|
1170
|
-
knex;
|
|
1171
|
-
constructor(knexQuery, knex){
|
|
1172
|
-
this.knexQuery = knexQuery;
|
|
1173
|
-
this.knex = knex;
|
|
1174
|
-
}
|
|
1175
|
-
[Symbol.toStringTag] = "Promise";
|
|
1176
|
-
toQuery() {
|
|
1177
|
-
return this.knexQuery.toQuery();
|
|
1178
|
-
}
|
|
1179
|
-
debug() {
|
|
1180
|
-
console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
|
|
1181
|
-
return this;
|
|
1182
|
-
}
|
|
1183
|
-
then(onfulfilled, onrejected) {
|
|
1184
|
-
Naite.t("puri:executed-query", this.toQuery());
|
|
1185
|
-
return this.knexQuery.then(onfulfilled, onrejected);
|
|
1186
|
-
}
|
|
1187
|
-
catch(onrejected) {
|
|
1188
|
-
return this.knexQuery.catch(onrejected);
|
|
1189
|
-
}
|
|
1190
|
-
finally(onfinally) {
|
|
1191
|
-
return this.knexQuery.finally(onfinally);
|
|
1192
|
-
}
|
|
1193
|
-
// ON CONFLICT - 컬럼 기반
|
|
1194
|
-
onConflict(columns, action) {
|
|
1195
|
-
const target = Array.isArray(columns) ? columns : [
|
|
1196
|
-
columns
|
|
1197
|
-
];
|
|
1198
|
-
if (!action || action === "nothing") {
|
|
1199
|
-
// DO NOTHING
|
|
1200
|
-
this.knexQuery.onConflict(target).ignore();
|
|
1201
|
-
} else {
|
|
1202
|
-
// DO UPDATE
|
|
1203
|
-
const { update } = action;
|
|
1204
|
-
// action.update 배열 형태 : ["name", "email"]
|
|
1205
|
-
if (Array.isArray(update)) {
|
|
1206
|
-
this.knexQuery.onConflict(target).merge(update);
|
|
1207
|
-
} else {
|
|
1208
|
-
// action.update 객체 형태: { name: "John", count: raw(...) }
|
|
1209
|
-
const mergeObj = {};
|
|
1210
|
-
for (const [key, value] of Object.entries(update)){
|
|
1211
|
-
if (value && typeof value === "object" && "_type" in value && value._type === "sql_expression") {
|
|
1212
|
-
// SqlExpression → knex.raw()로 변환
|
|
1213
|
-
mergeObj[key] = this.knex.raw(value._sql);
|
|
1214
|
-
} else {
|
|
1215
|
-
// 일반 값
|
|
1216
|
-
mergeObj[key] = value;
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
this.knexQuery.onConflict(target).merge(mergeObj);
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
return this;
|
|
1223
|
-
}
|
|
1224
|
-
// RETURNING 구현
|
|
1225
|
-
returning(columnOrColumns) {
|
|
1226
|
-
this.knexQuery.returning(columnOrColumns);
|
|
1227
|
-
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
1228
|
-
}
|
|
11
|
+
const normalized = operator?.trim() ?? "<%";
|
|
12
|
+
const fuzzyOperator = FUZZY_OPERATORS.find((candidate) => candidate === normalized);
|
|
13
|
+
if (!fuzzyOperator) {
|
|
14
|
+
throw new Error(`Invalid fuzzy operator: ${operator ?? ""}`);
|
|
15
|
+
}
|
|
16
|
+
return fuzzyOperator;
|
|
1229
17
|
}
|
|
18
|
+
var Puri, WhereGroup, JoinClauseGroup, ResolvedPuri;
|
|
19
|
+
var init_puri = __esmMin((() => {
|
|
20
|
+
init_entity_manager();
|
|
21
|
+
init_naite();
|
|
22
|
+
init_puri_types();
|
|
23
|
+
Puri = class Puri {
|
|
24
|
+
knexQuery;
|
|
25
|
+
tableSpec = null;
|
|
26
|
+
constructor(knex, tableNameOrSource) {
|
|
27
|
+
this.knex = knex;
|
|
28
|
+
if (typeof tableNameOrSource === "string") {
|
|
29
|
+
this.knexQuery = this.knex(tableNameOrSource).from(tableNameOrSource);
|
|
30
|
+
this.tableSpec = this.safeGetTableSpec(tableNameOrSource);
|
|
31
|
+
} else if (typeof tableNameOrSource === "object") {
|
|
32
|
+
const entries = Object.entries(tableNameOrSource);
|
|
33
|
+
if (entries.length !== 1) {
|
|
34
|
+
throw new Error("Table spec must have exactly one entry");
|
|
35
|
+
}
|
|
36
|
+
assert(entries[0]);
|
|
37
|
+
const [alias, source] = entries[0];
|
|
38
|
+
if (typeof source === "string") {
|
|
39
|
+
this.knexQuery = this.knex(source).from({ [alias]: source });
|
|
40
|
+
this.tableSpec = this.safeGetTableSpec(source);
|
|
41
|
+
} else if (source instanceof Puri) {
|
|
42
|
+
const subqueryBuilder = source.rawQuery();
|
|
43
|
+
this.knexQuery = this.knex.from(subqueryBuilder.as(alias));
|
|
44
|
+
} else {
|
|
45
|
+
throw new Error("Invalid table specification");
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error("Invalid table specification");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
safeGetTableSpec(tableName) {
|
|
52
|
+
try {
|
|
53
|
+
return EntityManager.getTableSpec(tableName);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
static count(column = "*") {
|
|
59
|
+
return {
|
|
60
|
+
_type: "sql_expression",
|
|
61
|
+
_return: "number",
|
|
62
|
+
_sql: `COUNT(??)::integer`,
|
|
63
|
+
_params: [column]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
static sum(column) {
|
|
67
|
+
return {
|
|
68
|
+
_type: "sql_expression",
|
|
69
|
+
_return: "number",
|
|
70
|
+
_sql: `SUM(??)`,
|
|
71
|
+
_params: [column]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
static avg(column) {
|
|
75
|
+
return {
|
|
76
|
+
_type: "sql_expression",
|
|
77
|
+
_return: "number",
|
|
78
|
+
_sql: `AVG(??)`,
|
|
79
|
+
_params: [column]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
static max(column) {
|
|
83
|
+
return {
|
|
84
|
+
_type: "sql_expression",
|
|
85
|
+
_return: "number",
|
|
86
|
+
_sql: `MAX(??)`,
|
|
87
|
+
_params: [column]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
static min(column) {
|
|
91
|
+
return {
|
|
92
|
+
_type: "sql_expression",
|
|
93
|
+
_return: "number",
|
|
94
|
+
_sql: `MIN(??)`,
|
|
95
|
+
_params: [column]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
static concat(...args) {
|
|
99
|
+
return {
|
|
100
|
+
_type: "sql_expression",
|
|
101
|
+
_return: "string",
|
|
102
|
+
_sql: `CONCAT(${args.map(() => "?").join(", ")})`,
|
|
103
|
+
_params: args
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
static upper(column) {
|
|
107
|
+
return {
|
|
108
|
+
_type: "sql_expression",
|
|
109
|
+
_return: "string",
|
|
110
|
+
_sql: "UPPER(??)",
|
|
111
|
+
_params: [column]
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
static lower(column) {
|
|
115
|
+
return {
|
|
116
|
+
_type: "sql_expression",
|
|
117
|
+
_return: "string",
|
|
118
|
+
_sql: "LOWER(??)",
|
|
119
|
+
_params: [column]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
static wordSimilarity(column, query) {
|
|
123
|
+
if (typeof column === "string") {
|
|
124
|
+
return {
|
|
125
|
+
_type: "sql_expression",
|
|
126
|
+
_return: "number",
|
|
127
|
+
_sql: "word_similarity(?, ??)",
|
|
128
|
+
_params: [query, column]
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
_type: "sql_expression",
|
|
133
|
+
_return: "number",
|
|
134
|
+
_sql: `word_similarity(?, ${column._sql})`,
|
|
135
|
+
_params: [query, ...column._params]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
static similarity(column, query) {
|
|
139
|
+
if (typeof column === "string") {
|
|
140
|
+
return {
|
|
141
|
+
_type: "sql_expression",
|
|
142
|
+
_return: "number",
|
|
143
|
+
_sql: "similarity(??, ?)",
|
|
144
|
+
_params: [column, query]
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
_type: "sql_expression",
|
|
149
|
+
_return: "number",
|
|
150
|
+
_sql: `similarity(${column._sql}, ?)`,
|
|
151
|
+
_params: [...column._params, query]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
static strictWordSimilarity(column, query) {
|
|
155
|
+
if (typeof column === "string") {
|
|
156
|
+
return {
|
|
157
|
+
_type: "sql_expression",
|
|
158
|
+
_return: "number",
|
|
159
|
+
_sql: `strict_word_similarity(?, ??)`,
|
|
160
|
+
_params: [query, column]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
_type: "sql_expression",
|
|
165
|
+
_return: "number",
|
|
166
|
+
_sql: `strict_word_similarity(?, ${column._sql})`,
|
|
167
|
+
_params: [query, ...column._params]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
static rawString(sql, params = []) {
|
|
171
|
+
return {
|
|
172
|
+
_type: "sql_expression",
|
|
173
|
+
_return: "string",
|
|
174
|
+
_sql: sql,
|
|
175
|
+
_params: params
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
static rawStringArray(sql, params = []) {
|
|
179
|
+
return {
|
|
180
|
+
_type: "sql_expression",
|
|
181
|
+
_return: "string[]",
|
|
182
|
+
_sql: sql,
|
|
183
|
+
_params: params
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
static rawNumber(sql, params = []) {
|
|
187
|
+
return {
|
|
188
|
+
_type: "sql_expression",
|
|
189
|
+
_return: "number",
|
|
190
|
+
_sql: sql,
|
|
191
|
+
_params: params
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
static rawBoolean(sql, params = []) {
|
|
195
|
+
return {
|
|
196
|
+
_type: "sql_expression",
|
|
197
|
+
_return: "boolean",
|
|
198
|
+
_sql: sql,
|
|
199
|
+
_params: params
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
static rawDate(sql, params = []) {
|
|
203
|
+
return {
|
|
204
|
+
_type: "sql_expression",
|
|
205
|
+
_return: "date",
|
|
206
|
+
_sql: sql,
|
|
207
|
+
_params: params
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* FTS 검색어 하이라이팅
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* .select({
|
|
215
|
+
* title: Puri.highlight("posts.title", search),
|
|
216
|
+
* content: Puri.highlight("posts.content", search, {
|
|
217
|
+
* startSel: "<mark>",
|
|
218
|
+
* stopSel: "</mark>",
|
|
219
|
+
* maxFragments: 3,
|
|
220
|
+
* }),
|
|
221
|
+
* })
|
|
222
|
+
*/
|
|
223
|
+
static tsHighlight(column, query, _options) {
|
|
224
|
+
const { parser = "websearch_to_tsquery", config = "simple", ...options } = _options ?? {};
|
|
225
|
+
const hlOptionParts = Object.entries(options).map(([key, value]) => {
|
|
226
|
+
return `${inflection.camelize(key)}=${value}`;
|
|
227
|
+
});
|
|
228
|
+
const hlOptions = hlOptionParts.length > 0 ? `, '${hlOptionParts.join(", ")}'` : "";
|
|
229
|
+
return {
|
|
230
|
+
_type: "sql_expression",
|
|
231
|
+
_return: "string",
|
|
232
|
+
_sql: `ts_headline(?, ??, ${parser}(?, ?)${hlOptions})`,
|
|
233
|
+
_params: [
|
|
234
|
+
config,
|
|
235
|
+
column,
|
|
236
|
+
config,
|
|
237
|
+
query
|
|
238
|
+
]
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
static tsRank(column, query, options) {
|
|
242
|
+
return Puri._tsRank("ts_rank", column, query, options);
|
|
243
|
+
}
|
|
244
|
+
static tsRankCd(column, query, options) {
|
|
245
|
+
return Puri._tsRank("ts_rank_cd", column, query, options);
|
|
246
|
+
}
|
|
247
|
+
static toTsVector(column, config = "simple") {
|
|
248
|
+
return {
|
|
249
|
+
_type: "sql_expression",
|
|
250
|
+
_return: "tsvector",
|
|
251
|
+
_sql: `to_tsvector(?, ??)`,
|
|
252
|
+
_params: [config, column]
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
static _tsRank(type, column, query, options) {
|
|
256
|
+
const { parser = "websearch_to_tsquery", config = "simple", normalization, weights } = options ?? {};
|
|
257
|
+
const params = [];
|
|
258
|
+
let sqlTemplate = `${type}(`;
|
|
259
|
+
if (weights) {
|
|
260
|
+
sqlTemplate += `ARRAY[${weights.map(() => "?").join(", ")}]::float4[], `;
|
|
261
|
+
params.push(...weights);
|
|
262
|
+
}
|
|
263
|
+
if (typeof column === "string") {
|
|
264
|
+
sqlTemplate += `??, ${parser}(?, ?)`;
|
|
265
|
+
params.push(column, config, query);
|
|
266
|
+
} else {
|
|
267
|
+
sqlTemplate += `${column._sql}, ${parser}(?, ?)`;
|
|
268
|
+
params.push(...column._params, config, query);
|
|
269
|
+
}
|
|
270
|
+
if (normalization) {
|
|
271
|
+
sqlTemplate += ", ?";
|
|
272
|
+
params.push(normalization);
|
|
273
|
+
}
|
|
274
|
+
sqlTemplate += ")";
|
|
275
|
+
return {
|
|
276
|
+
_type: "sql_expression",
|
|
277
|
+
_return: "number",
|
|
278
|
+
_sql: sqlTemplate,
|
|
279
|
+
_params: params
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* PGroonga FullText 인덱스 검색 점수
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* .select({
|
|
287
|
+
* score: Puri.score(),
|
|
288
|
+
* })
|
|
289
|
+
*/
|
|
290
|
+
static score() {
|
|
291
|
+
return Puri.rawNumber("pgroonga_score(tableoid, ctid)");
|
|
292
|
+
}
|
|
293
|
+
static highlight(columnOrColumns, query) {
|
|
294
|
+
const queryArr = Array.isArray(query) ? query : [query];
|
|
295
|
+
const queryClause = `ARRAY[${queryArr.map(() => "?").join(", ")}]`;
|
|
296
|
+
if (typeof columnOrColumns === "string") {
|
|
297
|
+
return Puri.rawString(`pgroonga_highlight_html(??, ${queryClause})`, [columnOrColumns, ...queryArr]);
|
|
298
|
+
}
|
|
299
|
+
return Puri.rawStringArray(`pgroonga_highlight_html(ARRAY[${columnOrColumns.map(() => "??").join(", ")}], ${queryClause})`, [...columnOrColumns, ...queryArr]);
|
|
300
|
+
}
|
|
301
|
+
select(selectObj) {
|
|
302
|
+
const flatSelect = this.flattenSelect(selectObj);
|
|
303
|
+
const selectClauses = [];
|
|
304
|
+
for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
|
|
305
|
+
if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
|
|
306
|
+
selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS "${alias}"`, columnOrFunction._params));
|
|
307
|
+
} else {
|
|
308
|
+
const columnPath = columnOrFunction;
|
|
309
|
+
if (alias === columnPath) {
|
|
310
|
+
selectClauses.push(columnPath);
|
|
311
|
+
} else {
|
|
312
|
+
selectClauses.push(`${columnPath} AS ${alias}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.knexQuery.select(selectClauses);
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 중첩 객체를 flat 객체로 변환
|
|
321
|
+
* 예: { parent: { id: "parent.id", name: "parent.name" } }
|
|
322
|
+
* → { parent__id: "parent.id", parent__name: "parent.name" }
|
|
323
|
+
*/
|
|
324
|
+
flattenSelect(selectObj, prefix = "") {
|
|
325
|
+
const flatSelect = {};
|
|
326
|
+
for (const [key, value] of Object.entries(selectObj)) {
|
|
327
|
+
const fullKey = prefix ? `${prefix}__${key}` : key;
|
|
328
|
+
if (typeof value === "object" && value !== null && !("_type" in value)) {
|
|
329
|
+
const nested = this.flattenSelect(value, fullKey);
|
|
330
|
+
Object.assign(flatSelect, nested);
|
|
331
|
+
} else {
|
|
332
|
+
flatSelect[fullKey] = value;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return flatSelect;
|
|
336
|
+
}
|
|
337
|
+
appendSelect(selectObj) {
|
|
338
|
+
const flatSelect = this.flattenSelect(selectObj);
|
|
339
|
+
const selectClauses = [];
|
|
340
|
+
for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
|
|
341
|
+
if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
|
|
342
|
+
selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS ${alias}`, columnOrFunction._params));
|
|
343
|
+
} else {
|
|
344
|
+
const columnPath = columnOrFunction;
|
|
345
|
+
if (alias === columnPath) {
|
|
346
|
+
selectClauses.push(columnPath);
|
|
347
|
+
} else {
|
|
348
|
+
selectClauses.push(this.knex.ref(columnPath).as(alias));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
this.knexQuery.select(selectClauses);
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
selectAll() {
|
|
356
|
+
this.knexQuery.select("*");
|
|
357
|
+
return this;
|
|
358
|
+
}
|
|
359
|
+
distinct(...columns) {
|
|
360
|
+
this.knexQuery.distinct(...columns);
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
clear(statement) {
|
|
364
|
+
this.knexQuery.clear(statement);
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
clearJoin(alias) {
|
|
368
|
+
this.knexQuery._statements = this.knexQuery._statements.filter((s) => {
|
|
369
|
+
if ("joinType" in s) {
|
|
370
|
+
const [_alias, _table] = Object.entries(s.table)[0];
|
|
371
|
+
return _alias !== alias;
|
|
372
|
+
} else {
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
return this;
|
|
377
|
+
}
|
|
378
|
+
join(tableNameOrSpec, ...args) {
|
|
379
|
+
return this.__commonJoin("join", tableNameOrSpec, ...args);
|
|
380
|
+
}
|
|
381
|
+
leftJoin(tableNameOrSpec, ...args) {
|
|
382
|
+
return this.__commonJoin("leftJoin", tableNameOrSpec, ...args);
|
|
383
|
+
}
|
|
384
|
+
__commonJoin(joinType, tableNameOrSpec, ...args) {
|
|
385
|
+
if (typeof tableNameOrSpec === "string") {
|
|
386
|
+
const tableName = tableNameOrSpec;
|
|
387
|
+
if (args.length === 1 && typeof args[0] === "function") {
|
|
388
|
+
const callback = args[0];
|
|
389
|
+
this.knexQuery[joinType](tableName, (joinClause) => {
|
|
390
|
+
callback(new JoinClauseGroup(joinClause));
|
|
391
|
+
});
|
|
392
|
+
} else {
|
|
393
|
+
const [left, right] = args;
|
|
394
|
+
this.knexQuery[joinType](tableName, left, right);
|
|
395
|
+
}
|
|
396
|
+
} else if (typeof tableNameOrSpec === "object") {
|
|
397
|
+
const entries = Object.entries(tableNameOrSpec);
|
|
398
|
+
if (entries.length !== 1) {
|
|
399
|
+
throw new Error("Table spec must have exactly one entry");
|
|
400
|
+
}
|
|
401
|
+
assert(entries[0]);
|
|
402
|
+
const [[alias, spec]] = entries;
|
|
403
|
+
if (typeof spec === "string") {
|
|
404
|
+
if (args.length === 1 && typeof args[0] === "function") {
|
|
405
|
+
const callback = args[0];
|
|
406
|
+
this.knexQuery[joinType]({ [alias]: spec }, (joinClause) => {
|
|
407
|
+
callback(new JoinClauseGroup(joinClause));
|
|
408
|
+
});
|
|
409
|
+
} else {
|
|
410
|
+
const [left, right] = args;
|
|
411
|
+
this.knexQuery[joinType]({ [alias]: spec }, left, right);
|
|
412
|
+
}
|
|
413
|
+
} else if (spec instanceof Puri) {
|
|
414
|
+
if (args.length === 1 && typeof args[0] === "function") {
|
|
415
|
+
const callback = args[0];
|
|
416
|
+
this.knexQuery[joinType](spec.rawQuery().as(alias), (joinClause) => {
|
|
417
|
+
callback(new JoinClauseGroup(joinClause));
|
|
418
|
+
});
|
|
419
|
+
} else {
|
|
420
|
+
const [left, right] = args;
|
|
421
|
+
this.knexQuery[joinType](spec.rawQuery().as(alias), left, right);
|
|
422
|
+
}
|
|
423
|
+
} else {
|
|
424
|
+
throw new Error("Invalid table specification");
|
|
425
|
+
}
|
|
426
|
+
} else {
|
|
427
|
+
throw new Error("Invalid arguments");
|
|
428
|
+
}
|
|
429
|
+
return this;
|
|
430
|
+
}
|
|
431
|
+
where(...args) {
|
|
432
|
+
const [columnOrConditions, operatorOrValue, value] = args;
|
|
433
|
+
if (typeof columnOrConditions === "object") {
|
|
434
|
+
this.knexQuery.where(columnOrConditions);
|
|
435
|
+
} else if (typeof value === "undefined") {
|
|
436
|
+
if (operatorOrValue === null) {
|
|
437
|
+
this.knexQuery.whereNull(columnOrConditions);
|
|
438
|
+
return this;
|
|
439
|
+
}
|
|
440
|
+
this.knexQuery.where(columnOrConditions, operatorOrValue);
|
|
441
|
+
} else if (typeof value !== "undefined") {
|
|
442
|
+
if (value === null) {
|
|
443
|
+
if (operatorOrValue === "!=") {
|
|
444
|
+
this.knexQuery.whereNotNull(columnOrConditions);
|
|
445
|
+
return this;
|
|
446
|
+
} else if (operatorOrValue === "=") {
|
|
447
|
+
this.knexQuery.whereNull(columnOrConditions);
|
|
448
|
+
return this;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
this.knexQuery.where(columnOrConditions, operatorOrValue, value);
|
|
452
|
+
} else {
|
|
453
|
+
this.knexQuery.where(columnOrConditions);
|
|
454
|
+
}
|
|
455
|
+
return this;
|
|
456
|
+
}
|
|
457
|
+
whereIn(column, values) {
|
|
458
|
+
this.knexQuery.whereIn(column, values);
|
|
459
|
+
return this;
|
|
460
|
+
}
|
|
461
|
+
whereNotIn(column, values) {
|
|
462
|
+
this.knexQuery.whereNotIn(column, values);
|
|
463
|
+
return this;
|
|
464
|
+
}
|
|
465
|
+
whereMatch(column, value) {
|
|
466
|
+
this.knexQuery.whereRaw(`MATCH (${String(column)}) AGAINST (?)`, [value]);
|
|
467
|
+
return this;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* PGroonga FullText 인덱스 검색
|
|
471
|
+
* - 사용할 PGroonga 인덱스와 동일한 컬럼 구성으로 검색해야 인덱스가 사용됩니다.
|
|
472
|
+
*
|
|
473
|
+
* 단일 컬럼 검색:
|
|
474
|
+
* ```sql
|
|
475
|
+
* WHERE name &@~ 'search'
|
|
476
|
+
* ```
|
|
477
|
+
*
|
|
478
|
+
* 복합 컬럼 검색:
|
|
479
|
+
* ```sql
|
|
480
|
+
* WHERE ARRAY[name::text, description::text] &@~ 'search'
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
whereSearch(column, value, options) {
|
|
484
|
+
const { weights } = options ?? {};
|
|
485
|
+
const columnExpr = Array.isArray(column) ? `ARRAY[${column.map((c) => `${c}::text`).join(",")}]` : column;
|
|
486
|
+
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
487
|
+
this.knexQuery.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [value]);
|
|
488
|
+
return this;
|
|
489
|
+
}
|
|
490
|
+
whereTsSearch(column, value, options) {
|
|
491
|
+
const opts = typeof options === "string" ? { config: options } : options ?? {};
|
|
492
|
+
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
493
|
+
const config = opts.config ?? "simple";
|
|
494
|
+
const columnExpr = typeof column === "object" && column._type === "sql_expression" ? column._sql : String(column);
|
|
495
|
+
this.knexQuery.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, value]);
|
|
496
|
+
return this;
|
|
497
|
+
}
|
|
498
|
+
whereFuzzy(column, value, options) {
|
|
499
|
+
const operator = normalizeFuzzyOperator(options?.operator);
|
|
500
|
+
if (operator === "%") {
|
|
501
|
+
if (typeof column === "object") {
|
|
502
|
+
this.knexQuery.whereRaw(`${column._sql} ${operator} ?`, [...column._params, value]);
|
|
503
|
+
} else {
|
|
504
|
+
this.knexQuery.whereRaw(`?? ${operator} ?`, [column, value]);
|
|
505
|
+
}
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
if (typeof column === "object") {
|
|
509
|
+
this.knexQuery.whereRaw(`? ${operator} ${column._sql}`, [value, ...column._params]);
|
|
510
|
+
} else {
|
|
511
|
+
this.knexQuery.whereRaw(`? ${operator} ??`, [value, column]);
|
|
512
|
+
}
|
|
513
|
+
return this;
|
|
514
|
+
}
|
|
515
|
+
whereRaw(sql, bindings) {
|
|
516
|
+
this.knexQuery.whereRaw(sql, bindings);
|
|
517
|
+
return this;
|
|
518
|
+
}
|
|
519
|
+
whereGroup(callback) {
|
|
520
|
+
this.knexQuery.where((builder) => {
|
|
521
|
+
const group = new WhereGroup(builder);
|
|
522
|
+
callback(group);
|
|
523
|
+
});
|
|
524
|
+
return this;
|
|
525
|
+
}
|
|
526
|
+
orWhereGroup(callback) {
|
|
527
|
+
this.knexQuery.orWhere((builder) => {
|
|
528
|
+
const group = new WhereGroup(builder);
|
|
529
|
+
callback(group);
|
|
530
|
+
});
|
|
531
|
+
return this;
|
|
532
|
+
}
|
|
533
|
+
orderBy(column, direction = "asc") {
|
|
534
|
+
if (typeof column === "object") {
|
|
535
|
+
this.knexQuery.orderByRaw(`${column._sql} ${direction}`, column._params);
|
|
536
|
+
} else {
|
|
537
|
+
this.knexQuery.orderBy(column, direction);
|
|
538
|
+
}
|
|
539
|
+
return this;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* 벡터 유사도 검색 설정
|
|
543
|
+
*
|
|
544
|
+
* - SELECT에 similarity 컬럼 추가
|
|
545
|
+
* - WHERE col IS NOT NULL 추가
|
|
546
|
+
* - threshold가 있으면 WHERE 조건 추가
|
|
547
|
+
* - 기존 ORDER BY를 clear하고 원시 연산자로 정렬 (HNSW 인덱스 최적화)
|
|
548
|
+
*
|
|
549
|
+
* @param column 벡터 컬럼 경로
|
|
550
|
+
* @param embedding 쿼리 임베딩 벡터
|
|
551
|
+
* @param options method, threshold, as 등 옵션
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```typescript
|
|
555
|
+
* // cosine similarity (기본값)
|
|
556
|
+
* qb.vectorSimilarity("columnName", queryVector, {
|
|
557
|
+
* method: "cosine",
|
|
558
|
+
* threshold: 0.5
|
|
559
|
+
* });
|
|
560
|
+
*
|
|
561
|
+
* // L2 distance
|
|
562
|
+
* qb.vectorSimilarity("columnName", queryVector, {
|
|
563
|
+
* method: "l2",
|
|
564
|
+
* threshold: 1.5 // 거리가 1.5 이하인 결과만
|
|
565
|
+
* });
|
|
566
|
+
*
|
|
567
|
+
* // Inner product
|
|
568
|
+
* qb.vectorSimilarity("columnName", queryVector, {
|
|
569
|
+
* method: "inner_product",
|
|
570
|
+
* threshold: 0.7
|
|
571
|
+
* });
|
|
572
|
+
* ```
|
|
573
|
+
*/
|
|
574
|
+
vectorSimilarity(column, embedding, options = {}) {
|
|
575
|
+
const { method = "cosine", threshold, distinctOn } = options;
|
|
576
|
+
if (!Array.isArray(embedding) || embedding.length === 0 || embedding.some((v) => !Number.isFinite(v))) {
|
|
577
|
+
throw new Error("Invalid embedding vector: expected a non-empty array of finite numbers");
|
|
578
|
+
}
|
|
579
|
+
const vectorLiteral = JSON.stringify(embedding.map((v) => Number(v)));
|
|
580
|
+
const operator = {
|
|
581
|
+
cosine: "<=>",
|
|
582
|
+
l2: "<->",
|
|
583
|
+
inner_product: "<#>"
|
|
584
|
+
}[method];
|
|
585
|
+
const similarityExpr = method === "cosine" ? this.knex.raw(`1 - (?? ${operator} ?::vector) as similarity`, [column, vectorLiteral]) : method === "l2" ? this.knex.raw(`?? ${operator} ?::vector as similarity`, [column, vectorLiteral]) : this.knex.raw(`-(?? ${operator} ?::vector) as similarity`, [column, vectorLiteral]);
|
|
586
|
+
this.knexQuery.whereNotNull(column);
|
|
587
|
+
this.knexQuery.clear("order");
|
|
588
|
+
if (distinctOn) {
|
|
589
|
+
const existingSubsetCols = this.knexQuery._statements.filter((s) => s.grouping === "columns").flatMap((s) => s.value);
|
|
590
|
+
this.knexQuery.clear("select");
|
|
591
|
+
this.knexQuery.select(this.knex.raw(`DISTINCT ON (??) ??`, [distinctOn, distinctOn]));
|
|
592
|
+
existingSubsetCols.map((col) => this.knexQuery.select(col));
|
|
593
|
+
this.knexQuery.select(similarityExpr);
|
|
594
|
+
this.knexQuery.orderByRaw(`??, ?? ${operator} ?::vector`, [
|
|
595
|
+
distinctOn,
|
|
596
|
+
column,
|
|
597
|
+
vectorLiteral
|
|
598
|
+
]);
|
|
599
|
+
this.knexQuery = this.knex.from(this.knexQuery.as("distinct_vectors")).select("*").orderBy("similarity", "desc");
|
|
600
|
+
} else {
|
|
601
|
+
this.knexQuery.select(similarityExpr);
|
|
602
|
+
this.knexQuery.orderByRaw(`?? ${operator} ?::vector`, [column, vectorLiteral]);
|
|
603
|
+
}
|
|
604
|
+
if (typeof threshold === "number") {
|
|
605
|
+
if (!Number.isFinite(threshold)) {
|
|
606
|
+
throw new Error(`Invalid vectorSimilarity threshold: ${threshold}`);
|
|
607
|
+
}
|
|
608
|
+
if (distinctOn) {
|
|
609
|
+
const thresholdOp = method === "l2" ? "<=" : ">=";
|
|
610
|
+
this.knexQuery.where("similarity", thresholdOp, threshold);
|
|
611
|
+
} else {
|
|
612
|
+
const thresholdValue = method === "cosine" ? 1 - threshold : method === "inner_product" ? -threshold : threshold;
|
|
613
|
+
this.knexQuery.whereRaw(`?? ${operator} ?::vector <= ?`, [
|
|
614
|
+
column,
|
|
615
|
+
vectorLiteral,
|
|
616
|
+
thresholdValue
|
|
617
|
+
]);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
limit(count) {
|
|
623
|
+
if (count < 0) {
|
|
624
|
+
throw new Error("Invalid limit: must be >= 0");
|
|
625
|
+
}
|
|
626
|
+
this.knexQuery.limit(count);
|
|
627
|
+
return this;
|
|
628
|
+
}
|
|
629
|
+
offset(count) {
|
|
630
|
+
if (count < 0) {
|
|
631
|
+
throw new Error("Invalid offset: must be >= 0");
|
|
632
|
+
}
|
|
633
|
+
this.knexQuery.offset(count);
|
|
634
|
+
return this;
|
|
635
|
+
}
|
|
636
|
+
groupBy(...columns) {
|
|
637
|
+
this.knexQuery.groupBy(...columns);
|
|
638
|
+
return this;
|
|
639
|
+
}
|
|
640
|
+
having(...conditions) {
|
|
641
|
+
if (conditions.length === 1) {
|
|
642
|
+
this.knexQuery.having(this.knex.raw(conditions[0]));
|
|
643
|
+
} else if (conditions.length === 3) {
|
|
644
|
+
this.knexQuery.having(this.knex.raw(conditions[0]), conditions[1], this.knex.raw(conditions[2]));
|
|
645
|
+
} else {
|
|
646
|
+
throw new Error("Invalid having arguments");
|
|
647
|
+
}
|
|
648
|
+
return this;
|
|
649
|
+
}
|
|
650
|
+
then(onfulfilled, onrejected) {
|
|
651
|
+
Naite.t("puri:executed-query", this.toQuery());
|
|
652
|
+
return this.knexQuery.then(onfulfilled, onrejected);
|
|
653
|
+
}
|
|
654
|
+
catch(onrejected) {
|
|
655
|
+
return this.knexQuery.catch(onrejected);
|
|
656
|
+
}
|
|
657
|
+
finally(onfinally) {
|
|
658
|
+
return this.knexQuery.finally(onfinally);
|
|
659
|
+
}
|
|
660
|
+
first() {
|
|
661
|
+
this.knexQuery.first();
|
|
662
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
663
|
+
}
|
|
664
|
+
pluck(column) {
|
|
665
|
+
this.knexQuery.pluck(column);
|
|
666
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
667
|
+
}
|
|
668
|
+
insert(rawData) {
|
|
669
|
+
const refinedData = this.refineJsonColumns(rawData);
|
|
670
|
+
this.knexQuery.insert(refinedData);
|
|
671
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
672
|
+
}
|
|
673
|
+
update(rawData) {
|
|
674
|
+
const refinedData = this.refineJsonColumns(rawData);
|
|
675
|
+
this.knexQuery.update(refinedData);
|
|
676
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* JSON 컬럼에 대해 stringify 처리를 수행하는 내부 메서드입니다.
|
|
680
|
+
* object 또는 object 배열을 받고, JSON 컬럼이 있으면 직렬화하여 반환합니다.
|
|
681
|
+
* 직접 값을 변경하므로 side effect가 있습니다.
|
|
682
|
+
*/
|
|
683
|
+
refineJsonColumns(data) {
|
|
684
|
+
if (!this.tableSpec || !this.tableSpec.jsonColumns.length) {
|
|
685
|
+
return data;
|
|
686
|
+
}
|
|
687
|
+
const jsonColumns = this.tableSpec.jsonColumns;
|
|
688
|
+
if (Array.isArray(data)) {
|
|
689
|
+
for (const item of data) {
|
|
690
|
+
for (const column of jsonColumns) {
|
|
691
|
+
const value = item[column];
|
|
692
|
+
if (value !== undefined && value !== null) {
|
|
693
|
+
item[column] = JSON.stringify(value);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
for (const column of jsonColumns) {
|
|
699
|
+
const value = data[column];
|
|
700
|
+
if (value !== undefined && value !== null) {
|
|
701
|
+
data[column] = JSON.stringify(value);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return data;
|
|
706
|
+
}
|
|
707
|
+
increment(column, value) {
|
|
708
|
+
if (value <= 0) {
|
|
709
|
+
throw new Error("Increment value must be greater than 0");
|
|
710
|
+
}
|
|
711
|
+
this.knexQuery.increment(column, value);
|
|
712
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
713
|
+
}
|
|
714
|
+
decrement(column, value) {
|
|
715
|
+
if (value <= 0) {
|
|
716
|
+
throw new Error("Decrement value must be greater than 0");
|
|
717
|
+
}
|
|
718
|
+
this.knexQuery.decrement(column, value);
|
|
719
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
720
|
+
}
|
|
721
|
+
delete() {
|
|
722
|
+
this.knexQuery.delete();
|
|
723
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
724
|
+
}
|
|
725
|
+
toQuery() {
|
|
726
|
+
return this.knexQuery.toQuery();
|
|
727
|
+
}
|
|
728
|
+
debug() {
|
|
729
|
+
console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
|
|
730
|
+
return this;
|
|
731
|
+
}
|
|
732
|
+
clone() {
|
|
733
|
+
const newPuri = new Puri(this.knex, "dual");
|
|
734
|
+
newPuri.knexQuery = this.knexQuery.clone();
|
|
735
|
+
return newPuri;
|
|
736
|
+
}
|
|
737
|
+
formatSQL(unformatted) {
|
|
738
|
+
const keywords = [
|
|
739
|
+
"SELECT",
|
|
740
|
+
"FROM",
|
|
741
|
+
"WHERE",
|
|
742
|
+
"INSERT",
|
|
743
|
+
"INTO",
|
|
744
|
+
"VALUES",
|
|
745
|
+
"UPDATE",
|
|
746
|
+
"DELETE",
|
|
747
|
+
"CREATE",
|
|
748
|
+
"TABLE",
|
|
749
|
+
"ALTER",
|
|
750
|
+
"DROP",
|
|
751
|
+
"JOIN",
|
|
752
|
+
"ON",
|
|
753
|
+
"INNER",
|
|
754
|
+
"LEFT",
|
|
755
|
+
"RIGHT",
|
|
756
|
+
"FULL",
|
|
757
|
+
"OUTER",
|
|
758
|
+
"GROUP",
|
|
759
|
+
"BY",
|
|
760
|
+
"ORDER",
|
|
761
|
+
"HAVING",
|
|
762
|
+
"DISTINCT",
|
|
763
|
+
"LIMIT",
|
|
764
|
+
"OFFSET",
|
|
765
|
+
"AS",
|
|
766
|
+
"AND",
|
|
767
|
+
"OR",
|
|
768
|
+
"NOT",
|
|
769
|
+
"IN",
|
|
770
|
+
"LIKE",
|
|
771
|
+
"IS",
|
|
772
|
+
"NULL",
|
|
773
|
+
"CASE",
|
|
774
|
+
"WHEN",
|
|
775
|
+
"THEN",
|
|
776
|
+
"ELSE",
|
|
777
|
+
"END",
|
|
778
|
+
"UNION",
|
|
779
|
+
"ALL",
|
|
780
|
+
"EXISTS",
|
|
781
|
+
"BETWEEN"
|
|
782
|
+
];
|
|
783
|
+
let formatted = unformatted;
|
|
784
|
+
keywords.forEach((keyword) => {
|
|
785
|
+
const regex = new RegExp(`\\b${keyword}\\b`, "gi");
|
|
786
|
+
formatted = formatted.replace(regex, keyword.toUpperCase());
|
|
787
|
+
});
|
|
788
|
+
const majorClauses = [
|
|
789
|
+
"SELECT",
|
|
790
|
+
"FROM",
|
|
791
|
+
"WHERE",
|
|
792
|
+
"GROUP BY",
|
|
793
|
+
"ORDER BY",
|
|
794
|
+
"HAVING",
|
|
795
|
+
"LIMIT",
|
|
796
|
+
"UNION"
|
|
797
|
+
];
|
|
798
|
+
majorClauses.forEach((clause) => {
|
|
799
|
+
const regex = new RegExp(`\\s+(${clause})\\s+`, "gi");
|
|
800
|
+
formatted = formatted.replace(regex, `\n${clause.toUpperCase()} `);
|
|
801
|
+
});
|
|
802
|
+
formatted = formatted.replace(/\s+((?:INNER|LEFT|RIGHT|FULL OUTER)\s+)?JOIN\s+/gi, "\n$1JOIN ");
|
|
803
|
+
formatted = formatted.replace(/\s+(AND|OR)\s+/gi, "\n $1 ");
|
|
804
|
+
const lines = formatted.split("\n");
|
|
805
|
+
const indentedLines = [];
|
|
806
|
+
let indentLevel = 0;
|
|
807
|
+
for (const line of lines) {
|
|
808
|
+
const trimmedLine = line.trim();
|
|
809
|
+
if (!trimmedLine) continue;
|
|
810
|
+
const closingParens = (trimmedLine.match(/\)/g) || []).length;
|
|
811
|
+
const openingParens = (trimmedLine.match(/\(/g) || []).length;
|
|
812
|
+
if (closingParens > 0 && openingParens === 0) {
|
|
813
|
+
indentLevel = Math.max(0, indentLevel - closingParens);
|
|
814
|
+
}
|
|
815
|
+
const indent = " ".repeat(indentLevel);
|
|
816
|
+
indentedLines.push(indent + trimmedLine);
|
|
817
|
+
if (openingParens > closingParens) {
|
|
818
|
+
indentLevel += openingParens - closingParens;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return indentedLines.join("\n").trim();
|
|
822
|
+
}
|
|
823
|
+
raw(sql) {
|
|
824
|
+
return this.knex.raw(sql);
|
|
825
|
+
}
|
|
826
|
+
rawQuery() {
|
|
827
|
+
return this.knexQuery;
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
WhereGroup = class WhereGroup {
|
|
831
|
+
constructor(builder) {
|
|
832
|
+
this.builder = builder;
|
|
833
|
+
}
|
|
834
|
+
where(...args) {
|
|
835
|
+
this.builder.where(args[0], ...args.slice(1));
|
|
836
|
+
return this;
|
|
837
|
+
}
|
|
838
|
+
whereIn(...args) {
|
|
839
|
+
this.builder.whereIn(args[0], args[1]);
|
|
840
|
+
return this;
|
|
841
|
+
}
|
|
842
|
+
whereNotIn(...args) {
|
|
843
|
+
this.builder.whereNotIn(args[0], args[1]);
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
orWhere(...args) {
|
|
847
|
+
this.builder.orWhere(args[0], ...args.slice(1));
|
|
848
|
+
return this;
|
|
849
|
+
}
|
|
850
|
+
orWhereIn(...args) {
|
|
851
|
+
this.builder.orWhereIn(args[0], args[1]);
|
|
852
|
+
return this;
|
|
853
|
+
}
|
|
854
|
+
orWhereNotIn(...args) {
|
|
855
|
+
this.builder.orWhereNotIn(args[0], args[1]);
|
|
856
|
+
return this;
|
|
857
|
+
}
|
|
858
|
+
whereMatch(...args) {
|
|
859
|
+
this.builder.whereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [args[1]]);
|
|
860
|
+
return this;
|
|
861
|
+
}
|
|
862
|
+
orWhereMatch(...args) {
|
|
863
|
+
this.builder.orWhereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [args[1]]);
|
|
864
|
+
return this;
|
|
865
|
+
}
|
|
866
|
+
whereSearch(...args) {
|
|
867
|
+
const { weights } = args[2] ?? {};
|
|
868
|
+
const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c) => `${c}::text`).join(",")}]` : args[0];
|
|
869
|
+
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
870
|
+
this.builder.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [args[1]]);
|
|
871
|
+
return this;
|
|
872
|
+
}
|
|
873
|
+
orWhereSearch(...args) {
|
|
874
|
+
const { weights } = args[2] ?? {};
|
|
875
|
+
const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c) => `${c}::text`).join(",")}]` : args[0];
|
|
876
|
+
const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
|
|
877
|
+
this.builder.orWhereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [args[1]]);
|
|
878
|
+
return this;
|
|
879
|
+
}
|
|
880
|
+
whereTsSearch(...args) {
|
|
881
|
+
const opts = typeof args[2] === "string" ? { config: args[2] } : args[2] ?? {};
|
|
882
|
+
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
883
|
+
const config = opts.config ?? "simple";
|
|
884
|
+
const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
|
|
885
|
+
this.builder.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
|
|
886
|
+
return this;
|
|
887
|
+
}
|
|
888
|
+
orWhereTsSearch(...args) {
|
|
889
|
+
const opts = typeof args[2] === "string" ? { config: args[2] } : args[2] ?? {};
|
|
890
|
+
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
891
|
+
const config = opts.config ?? "simple";
|
|
892
|
+
const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
|
|
893
|
+
this.builder.orWhereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
|
|
894
|
+
return this;
|
|
895
|
+
}
|
|
896
|
+
whereFuzzy(...args) {
|
|
897
|
+
const operator = normalizeFuzzyOperator(args[2]?.operator);
|
|
898
|
+
if (operator === "%") {
|
|
899
|
+
if (typeof args[0] === "object") {
|
|
900
|
+
this.builder.whereRaw(`${args[0]._sql} ${operator} ?`, [...args[0]._params, args[1]]);
|
|
901
|
+
} else {
|
|
902
|
+
this.builder.whereRaw(`?? ${operator} ?`, [args[0], args[1]]);
|
|
903
|
+
}
|
|
904
|
+
return this;
|
|
905
|
+
}
|
|
906
|
+
if (typeof args[0] === "object") {
|
|
907
|
+
this.builder.whereRaw(`? ${operator} ${args[0]._sql}`, [args[1], ...args[0]._params]);
|
|
908
|
+
} else {
|
|
909
|
+
this.builder.whereRaw(`? ${operator} ??`, [args[1], args[0]]);
|
|
910
|
+
}
|
|
911
|
+
return this;
|
|
912
|
+
}
|
|
913
|
+
orWhereFuzzy(...args) {
|
|
914
|
+
const operator = normalizeFuzzyOperator(args[2]?.operator);
|
|
915
|
+
if (operator === "%") {
|
|
916
|
+
if (typeof args[0] === "object") {
|
|
917
|
+
this.builder.orWhereRaw(`${args[0]._sql} ${operator} ?`, [...args[0]._params, args[1]]);
|
|
918
|
+
} else {
|
|
919
|
+
this.builder.orWhereRaw(`?? ${operator} ?`, [args[0], args[1]]);
|
|
920
|
+
}
|
|
921
|
+
return this;
|
|
922
|
+
}
|
|
923
|
+
if (typeof args[0] === "object") {
|
|
924
|
+
this.builder.orWhereRaw(`? ${operator} ${args[0]._sql}`, [args[1], ...args[0]._params]);
|
|
925
|
+
} else {
|
|
926
|
+
this.builder.orWhereRaw(`? ${operator} ??`, [args[1], args[0]]);
|
|
927
|
+
}
|
|
928
|
+
return this;
|
|
929
|
+
}
|
|
930
|
+
whereGroup(callback) {
|
|
931
|
+
this.builder.where((subBuilder) => {
|
|
932
|
+
const subGroup = new WhereGroup(subBuilder);
|
|
933
|
+
callback(subGroup);
|
|
934
|
+
});
|
|
935
|
+
return this;
|
|
936
|
+
}
|
|
937
|
+
orWhereGroup(callback) {
|
|
938
|
+
this.builder.orWhere((subBuilder) => {
|
|
939
|
+
const subGroup = new WhereGroup(subBuilder);
|
|
940
|
+
callback(subGroup);
|
|
941
|
+
});
|
|
942
|
+
return this;
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
JoinClauseGroup = class {
|
|
946
|
+
constructor(callback) {
|
|
947
|
+
this.callback = callback;
|
|
948
|
+
}
|
|
949
|
+
on(...args) {
|
|
950
|
+
this.callback.on(...args);
|
|
951
|
+
return this;
|
|
952
|
+
}
|
|
953
|
+
orOn(...args) {
|
|
954
|
+
this.callback.orOn(...args);
|
|
955
|
+
return this;
|
|
956
|
+
}
|
|
957
|
+
onVal(...args) {
|
|
958
|
+
this.callback.onVal(...args);
|
|
959
|
+
return this;
|
|
960
|
+
}
|
|
961
|
+
andOnVal(...args) {
|
|
962
|
+
this.callback.andOnVal(...args);
|
|
963
|
+
return this;
|
|
964
|
+
}
|
|
965
|
+
orOnVal(...args) {
|
|
966
|
+
this.callback.orOnVal(...args);
|
|
967
|
+
return this;
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
ResolvedPuri = class ResolvedPuri {
|
|
971
|
+
constructor(knexQuery, knex) {
|
|
972
|
+
this.knexQuery = knexQuery;
|
|
973
|
+
this.knex = knex;
|
|
974
|
+
}
|
|
975
|
+
[Symbol.toStringTag] = "Promise";
|
|
976
|
+
toQuery() {
|
|
977
|
+
return this.knexQuery.toQuery();
|
|
978
|
+
}
|
|
979
|
+
debug() {
|
|
980
|
+
console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
|
|
981
|
+
return this;
|
|
982
|
+
}
|
|
983
|
+
then(onfulfilled, onrejected) {
|
|
984
|
+
Naite.t("puri:executed-query", this.toQuery());
|
|
985
|
+
return this.knexQuery.then(onfulfilled, onrejected);
|
|
986
|
+
}
|
|
987
|
+
catch(onrejected) {
|
|
988
|
+
return this.knexQuery.catch(onrejected);
|
|
989
|
+
}
|
|
990
|
+
finally(onfinally) {
|
|
991
|
+
return this.knexQuery.finally(onfinally);
|
|
992
|
+
}
|
|
993
|
+
onConflict(columns, action) {
|
|
994
|
+
const target = Array.isArray(columns) ? columns : [columns];
|
|
995
|
+
if (!action || action === "nothing") {
|
|
996
|
+
this.knexQuery.onConflict(target).ignore();
|
|
997
|
+
} else {
|
|
998
|
+
const { update } = action;
|
|
999
|
+
if (Array.isArray(update)) {
|
|
1000
|
+
this.knexQuery.onConflict(target).merge(update);
|
|
1001
|
+
} else {
|
|
1002
|
+
const mergeObj = {};
|
|
1003
|
+
for (const [key, value] of Object.entries(update)) {
|
|
1004
|
+
if (value && typeof value === "object" && "_type" in value && value._type === "sql_expression") {
|
|
1005
|
+
mergeObj[key] = this.knex.raw(value._sql);
|
|
1006
|
+
} else {
|
|
1007
|
+
mergeObj[key] = value;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
this.knexQuery.onConflict(target).merge(mergeObj);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return this;
|
|
1014
|
+
}
|
|
1015
|
+
returning(columnOrColumns) {
|
|
1016
|
+
this.knexQuery.returning(columnOrColumns);
|
|
1017
|
+
return new ResolvedPuri(this.knexQuery, this.knex);
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
}));
|
|
1230
1021
|
|
|
1231
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS9wdXJpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKiBiaW9tZS1pZ25vcmUtYWxsIGxpbnQvc3VzcGljaW91cy9ub1RoZW5Qcm9wZXJ0eTogUHVyaeuKlCB0aGVuYWJsZSDsnbjthLDtjpjsnbTsiqTrpbwg6rWs7ZiE7ZWY6rOgIOyeiOyKteuLiOuLpC4gKi9cbi8qKiBiaW9tZS1pZ25vcmUtYWxsIGxpbnQvc3VzcGljaW91cy9ub0V4cGxpY2l0QW55OiBQdXJp64qUIOuLpOyWke2VnCDtg4DsnoXsnYQg7IKs7Jqp7ZWY6rOgIOyeiOyKteuLiOuLpC4gKi9cblxuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHR5cGUgeyBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIsIHR5cGUgVGFibGVTcGVjIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB0eXBlIHtcbiAgQXZhaWxhYmxlQ29sdW1ucyxcbiAgQ29sdW1uS2V5cyxcbiAgQ29tcGFyaXNvbk9wZXJhdG9yLFxuICBFeHBhbmQsXG4gIEV4dHJhY3RDb2x1bW5UeXBlLFxuICBGdWxsdGV4dENvbHVtbnMsXG4gIEZ1enp5T3BlcmF0b3IsXG4gIEluc2VydERhdGEsXG4gIEluc2VydFJlc3VsdCxcbiAgTGVmdEpvaW5lZE1hcmtlcixcbiAgTGVmdEpvaW5NYXJrZXJGb3IsXG4gIE51bWVyaWNDb2x1bW5zLFxuICBPbkNvbmZsaWN0QWN0aW9uLFxuICBQYXJzZVNlbGVjdE9iamVjdCxcbiAgUmVzdWx0QXZhaWxhYmxlQ29sdW1ucyxcbiAgU2VsZWN0QWxsUmVzdWx0LFxuICBTZWxlY3RPYmplY3QsXG4gIFNpbmdsZVRhYmxlVmFsdWUsXG4gIFNxbEV4cHJlc3Npb24sXG4gIFRzSGlnaGxpZ2h0T3B0aW9ucyxcbiAgVHNRdWVyeUNvbmZpZyxcbiAgVHNRdWVyeU9wdGlvbnMsXG4gIFRzUmFua09wdGlvbnMsXG4gIFZlY3RvckNvbHVtbnMsXG4gIFdoZXJlQ29uZGl0aW9uLFxuICBXaGVyZU9wZXJhdG9yLFxufSBmcm9tIFwiLi9wdXJpLnR5cGVzXCI7XG5pbXBvcnQgeyBGVVpaWV9PUEVSQVRPUlMgfSBmcm9tIFwiLi9wdXJpLnR5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IENsZWFyU3RhdGVtZW50cyB9IGZyb20gXCIuL3B1cmktc3Vic2V0LnR5cGVzXCI7XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3Iob3BlcmF0b3I/OiBzdHJpbmcpOiBGdXp6eU9wZXJhdG9yIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IG9wZXJhdG9yPy50cmltKCkgPz8gXCI8JVwiO1xuICBjb25zdCBmdXp6eU9wZXJhdG9yID0gRlVaWllfT1BFUkFUT1JTLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlID09PSBub3JtYWxpemVkKTtcblxuICBpZiAoIWZ1enp5T3BlcmF0b3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZnV6enkgb3BlcmF0b3I6ICR7b3BlcmF0b3IgPz8gXCJcIn1gKTtcbiAgfVxuXG4gIHJldHVybiBmdXp6eU9wZXJhdG9yO1xufVxuXG5leHBvcnQgY2xhc3MgUHVyaTxUU2NoZW1hLCBUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55PiwgVFJlc3VsdD4ge1xuICBwcml2YXRlIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXI7XG4gIHByaXZhdGUgdGFibGVTcGVjOiBUYWJsZVNwZWMgfCBudWxsID0gbnVsbDtcblxuICAvLyDsg53shLHsnpAg7Iuc6re464uI7LKY65OkXG4gIGNvbnN0cnVjdG9yKGtuZXg6IEtuZXgsIHRhYmxlTmFtZTogc3RyaW5nKTtcbiAgY29uc3RydWN0b3Ioa25leDogS25leCwgdGFibGVTb3VyY2U6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IFB1cmk8VFNjaGVtYSwgYW55LCBhbnk+Pik7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBrbmV4OiBLbmV4LFxuICAgIHRhYmxlTmFtZU9yU291cmNlOiBhbnksXG4gICkge1xuICAgIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIC8vIENhc2U6IG5ldyBQdXJpKGtuZXgsIFwidXNlcnNcIilcbiAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4KHRhYmxlTmFtZU9yU291cmNlKS5mcm9tKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICAgIHRoaXMudGFibGVTcGVjID0gdGhpcy5zYWZlR2V0VGFibGVTcGVjKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB0YWJsZU5hbWVPclNvdXJjZSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICAgIGlmIChlbnRyaWVzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWJsZSBzcGVjIG11c3QgaGF2ZSBleGFjdGx5IG9uZSBlbnRyeVwiKTtcbiAgICAgIH1cbiAgICAgIGFzc2VydChlbnRyaWVzWzBdKTtcbiAgICAgIGNvbnN0IFthbGlhcywgc291cmNlXSA9IGVudHJpZXNbMF07XG4gICAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leChzb3VyY2UpLmZyb20oeyBbYWxpYXNdOiBzb3VyY2UgfSk7XG4gICAgICAgIHRoaXMudGFibGVTcGVjID0gdGhpcy5zYWZlR2V0VGFibGVTcGVjKHNvdXJjZSk7XG4gICAgICB9IGVsc2UgaWYgKHNvdXJjZSBpbnN0YW5jZW9mIFB1cmkpIHtcbiAgICAgICAgY29uc3Qgc3VicXVlcnlCdWlsZGVyID0gc291cmNlLnJhd1F1ZXJ5KCk7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4LmZyb20oc3VicXVlcnlCdWlsZGVyLmFzKGFsaWFzKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGFibGUgc3BlY2lmaWNhdGlvblwiKTtcbiAgICB9XG4gIH1cblxuICBzYWZlR2V0VGFibGVTcGVjKHRhYmxlTmFtZTogc3RyaW5nKTogVGFibGVTcGVjIHwgbnVsbCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBFbnRpdHlNYW5hZ2VyLmdldFRhYmxlU3BlYyh0YWJsZU5hbWUpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLy8gU3RhdGljIFNRTCBoZWxwZXIgZnVuY3Rpb25zIGZvciBTRUxFQ1RcbiAgc3RhdGljIGNvdW50KGNvbHVtbjogc3RyaW5nID0gXCIqXCIpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgQ09VTlQoPz8pOjppbnRlZ2VyYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIHN1bShjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBTVU0oPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIGF2Zyhjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBBVkcoPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIG1heChjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBNQVgoPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIG1pbihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBNSU4oPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIGNvbmNhdCguLi5hcmdzOiBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IGBDT05DQVQoJHthcmdzLm1hcCgoKSA9PiBcIj9cIikuam9pbihcIiwgXCIpfSlgLFxuICAgICAgX3BhcmFtczogYXJncyxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyB1cHBlcihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IFwiVVBQRVIoPz8pXCIsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBsb3dlcihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IFwiTE9XRVIoPz8pXCIsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIHdvcmRTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogXCJ3b3JkX3NpbWlsYXJpdHkoPywgPz8pXCIsXG4gICAgICAgIF9wYXJhbXM6IFtxdWVyeSwgY29sdW1uXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYHdvcmRfc2ltaWxhcml0eSg/LCAke2NvbHVtbi5fc3FsfSlgLFxuICAgICAgX3BhcmFtczogW3F1ZXJ5LCAuLi5jb2x1bW4uX3BhcmFtc10sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyBzaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogXCJzaW1pbGFyaXR5KD8/LCA/KVwiLFxuICAgICAgICBfcGFyYW1zOiBbY29sdW1uLCBxdWVyeV0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBzaW1pbGFyaXR5KCR7Y29sdW1uLl9zcWx9LCA/KWAsXG4gICAgICBfcGFyYW1zOiBbLi4uY29sdW1uLl9wYXJhbXMsIHF1ZXJ5XSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIHN0cmljdFdvcmRTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogYHN0cmljdF93b3JkX3NpbWlsYXJpdHkoPywgPz8pYCxcbiAgICAgICAgX3BhcmFtczogW3F1ZXJ5LCBjb2x1bW5dLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgc3RyaWN0X3dvcmRfc2ltaWxhcml0eSg/LCAke2NvbHVtbi5fc3FsfSlgLFxuICAgICAgX3BhcmFtczogW3F1ZXJ5LCAuLi5jb2x1bW4uX3BhcmFtc10sXG4gICAgfTtcbiAgfVxuXG4gIC8vIFJhdyBmdW5jdGlvbnMgZm9yIFNFTEVDVFxuICBzdGF0aWMgcmF3U3RyaW5nKHNxbDogc3RyaW5nLCBwYXJhbXM6IHVua25vd25bXSA9IFtdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJzdHJpbmdcIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdTdHJpbmdBcnJheShzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdbXVwiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJzdHJpbmdbXVwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgc3RhdGljIHJhd051bWJlcihzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwibnVtYmVyXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3Qm9vbGVhbihzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJib29sZWFuXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcImJvb2xlYW5cIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdEYXRlKHNxbDogc3RyaW5nLCBwYXJhbXM6IHVua25vd25bXSA9IFtdKTogU3FsRXhwcmVzc2lvbjxcImRhdGVcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwiZGF0ZVwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEZUUyDqsoDsg4nslrQg7ZWY7J2065287J207YyFXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC5zZWxlY3Qoe1xuICAgKiAgIHRpdGxlOiBQdXJpLmhpZ2hsaWdodChcInBvc3RzLnRpdGxlXCIsIHNlYXJjaCksXG4gICAqICAgY29udGVudDogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy5jb250ZW50XCIsIHNlYXJjaCwge1xuICAgKiAgICAgc3RhcnRTZWw6IFwiPG1hcms+XCIsXG4gICAqICAgICBzdG9wU2VsOiBcIjwvbWFyaz5cIixcbiAgICogICAgIG1heEZyYWdtZW50czogMyxcbiAgICogICB9KSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyB0c0hpZ2hsaWdodChcbiAgICBjb2x1bW46IHN0cmluZyxcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIF9vcHRpb25zPzogVHNIaWdobGlnaHRPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICBjb25zdCB7IHBhcnNlciA9IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIiwgY29uZmlnID0gXCJzaW1wbGVcIiwgLi4ub3B0aW9ucyB9ID0gX29wdGlvbnMgPz8ge307XG5cbiAgICBjb25zdCBobE9wdGlvblBhcnRzID0gT2JqZWN0LmVudHJpZXMob3B0aW9ucykubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIHJldHVybiBgJHtpbmZsZWN0aW9uLmNhbWVsaXplKGtleSl9PSR7dmFsdWV9YDtcbiAgICB9KTtcblxuICAgIGNvbnN0IGhsT3B0aW9ucyA9IGhsT3B0aW9uUGFydHMubGVuZ3RoID4gMCA/IGAsICcke2hsT3B0aW9uUGFydHMuam9pbihcIiwgXCIpfSdgIDogXCJcIjtcblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IGB0c19oZWFkbGluZSg/LCA/PywgJHtwYXJzZXJ9KD8sID8pJHtobE9wdGlvbnN9KWAsXG4gICAgICBfcGFyYW1zOiBbY29uZmlnLCBjb2x1bW4sIGNvbmZpZywgcXVlcnldLFxuICAgIH07XG4gIH1cblxuICAvLyB0c19yYW5rXG4gIHN0YXRpYyB0c1JhbmsoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNSYW5rT3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIFB1cmkuX3RzUmFuayhcInRzX3JhbmtcIiwgY29sdW1uLCBxdWVyeSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyB0c19yYW5rX2NkXG4gIHN0YXRpYyB0c1JhbmtDZChcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJ0c3ZlY3RvclwiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1JhbmtPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4gUHVyaS5fdHNSYW5rKFwidHNfcmFua19jZFwiLCBjb2x1bW4sIHF1ZXJ5LCBvcHRpb25zKTtcbiAgfVxuXG4gIHN0YXRpYyB0b1RzVmVjdG9yKGNvbHVtbjogc3RyaW5nLCBjb25maWc6IHN0cmluZyA9IFwic2ltcGxlXCIpOiBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJ0c3ZlY3RvclwiLFxuICAgICAgX3NxbDogYHRvX3RzdmVjdG9yKD8sID8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29uZmlnLCBjb2x1bW5dLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgX3RzUmFuayhcbiAgICB0eXBlOiBcInRzX3JhbmtcIiB8IFwidHNfcmFua19jZFwiLFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+LFxuICAgIHF1ZXJ5OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUmFua09wdGlvbnMsXG4gICk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHBhcnNlciA9IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIixcbiAgICAgIGNvbmZpZyA9IFwic2ltcGxlXCIsXG4gICAgICBub3JtYWxpemF0aW9uLFxuICAgICAgd2VpZ2h0cyxcbiAgICB9ID0gb3B0aW9ucyA/PyB7fTtcblxuICAgIGNvbnN0IHBhcmFtcyA9IFtdO1xuICAgIGxldCBzcWxUZW1wbGF0ZSA9IGAke3R5cGV9KGA7XG5cbiAgICBpZiAod2VpZ2h0cykge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYEFSUkFZWyR7d2VpZ2h0cy5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX1dOjpmbG9hdDRbXSwgYDtcbiAgICAgIHBhcmFtcy5wdXNoKC4uLndlaWdodHMpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBgPz8sICR7cGFyc2VyfSg/LCA/KWA7XG4gICAgICBwYXJhbXMucHVzaChjb2x1bW4sIGNvbmZpZywgcXVlcnkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBgJHtjb2x1bW4uX3NxbH0sICR7cGFyc2VyfSg/LCA/KWA7XG4gICAgICBwYXJhbXMucHVzaCguLi5jb2x1bW4uX3BhcmFtcywgY29uZmlnLCBxdWVyeSk7XG4gICAgfVxuXG4gICAgaWYgKG5vcm1hbGl6YXRpb24pIHtcbiAgICAgIHNxbFRlbXBsYXRlICs9IFwiLCA/XCI7XG4gICAgICBwYXJhbXMucHVzaChub3JtYWxpemF0aW9uKTtcbiAgICB9XG5cbiAgICBzcWxUZW1wbGF0ZSArPSBcIilcIjtcblxuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwibnVtYmVyXCIsIF9zcWw6IHNxbFRlbXBsYXRlLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQR3Jvb25nYSBGdWxsVGV4dCDsnbjrjbHsiqQg6rKA7IOJIOygkOyImFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICBzY29yZTogUHVyaS5zY29yZSgpLFxuICAgKiB9KVxuICAgKi9cbiAgc3RhdGljIHNjb3JlKCk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiBQdXJpLnJhd051bWJlcihcInBncm9vbmdhX3Njb3JlKHRhYmxlb2lkLCBjdGlkKVwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQR3Jvb25nYSBGdWxsVGV4dCDsnbjrjbHsiqQg6rKA7IOJIO2VmOydtOudvOydtO2MhVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICB0aXRsZTogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy50aXRsZVwiLCBzZWFyY2gpLFxuICAgKiB9KVxuICAgKi9cbiAgc3RhdGljIGhpZ2hsaWdodChjb2x1bW46IHN0cmluZywgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPjtcbiAgc3RhdGljIGhpZ2hsaWdodChjb2x1bW5zOiBzdHJpbmdbXSwgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1tdXCI+O1xuXG4gIHN0YXRpYyBoaWdobGlnaHQoXG4gICAgY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSxcbiAgICBxdWVyeTogc3RyaW5nIHwgc3RyaW5nW10sXG4gICk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nW11cIj4ge1xuICAgIGNvbnN0IHF1ZXJ5QXJyID0gQXJyYXkuaXNBcnJheShxdWVyeSkgPyBxdWVyeSA6IFtxdWVyeV07XG4gICAgY29uc3QgcXVlcnlDbGF1c2UgPSBgQVJSQVlbJHtxdWVyeUFyci5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX1dYDtcblxuICAgIC8vIOuLqOydvCDsu6zrn7zsnbgg6rK97JqwXG4gICAgaWYgKHR5cGVvZiBjb2x1bW5PckNvbHVtbnMgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiBQdXJpLnJhd1N0cmluZyhgcGdyb29uZ2FfaGlnaGxpZ2h0X2h0bWwoPz8sICR7cXVlcnlDbGF1c2V9KWAsIFtcbiAgICAgICAgY29sdW1uT3JDb2x1bW5zLFxuICAgICAgICAuLi5xdWVyeUFycixcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIC8vIOy7rOufvCDrsLDsl7Tsnbgg6rK97JqwXG4gICAgcmV0dXJuIFB1cmkucmF3U3RyaW5nQXJyYXkoXG4gICAgICBgcGdyb29uZ2FfaGlnaGxpZ2h0X2h0bWwoQVJSQVlbJHtjb2x1bW5PckNvbHVtbnMubWFwKCgpID0+IFwiPz9cIikuam9pbihcIiwgXCIpfV0sICR7cXVlcnlDbGF1c2V9KWAsXG4gICAgICBbLi4uY29sdW1uT3JDb2x1bW5zLCAuLi5xdWVyeUFycl0sXG4gICAgKTtcbiAgfVxuXG4gIC8vIFNFTEVDVCAob3ZlcndyaXRlKVxuICBzZWxlY3Q8VFNlbGVjdCBleHRlbmRzIFNlbGVjdE9iamVjdDxUVGFibGVzPj4oXG4gICAgc2VsZWN0T2JqOiBUU2VsZWN0LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFBhcnNlU2VsZWN0T2JqZWN0PFRUYWJsZXMsIFRTZWxlY3Q+PiB7XG4gICAgLy8g7KSR7LKpIOqwneyytOulvCBmbGF07ZWY6rKMIOuzgO2ZmFxuICAgIGNvbnN0IGZsYXRTZWxlY3QgPSB0aGlzLmZsYXR0ZW5TZWxlY3Qoc2VsZWN0T2JqKTtcblxuICAgIGNvbnN0IHNlbGVjdENsYXVzZXM6IChzdHJpbmcgfCBLbmV4LlJhdylbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbYWxpYXMsIGNvbHVtbk9yRnVuY3Rpb25dIG9mIE9iamVjdC5lbnRyaWVzKGZsYXRTZWxlY3QpKSB7XG4gICAgICBpZiAodHlwZW9mIGNvbHVtbk9yRnVuY3Rpb24gPT09IFwib2JqZWN0XCIgJiYgY29sdW1uT3JGdW5jdGlvbi5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiKSB7XG4gICAgICAgIC8vIFNRTCDtlajsiJjsnbgg6rK97JqwXG4gICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChcbiAgICAgICAgICB0aGlzLmtuZXgucmF3KGAke2NvbHVtbk9yRnVuY3Rpb24uX3NxbH0gQVMgXCIke2FsaWFzfVwiYCwgY29sdW1uT3JGdW5jdGlvbi5fcGFyYW1zKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIOydvOuwmCDsu6zrn7zsnbgg6rK97JqwXG4gICAgICAgIGNvbnN0IGNvbHVtblBhdGggPSBjb2x1bW5PckZ1bmN0aW9uIGFzIHN0cmluZztcbiAgICAgICAgaWYgKGFsaWFzID09PSBjb2x1bW5QYXRoKSB7XG4gICAgICAgICAgLy8gYWxpYXPsmYAg7Lus65+866qF7J20IOqwmeycvOuptCBhbGlhcyDsg53rnrVcbiAgICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goY29sdW1uUGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gYWxpYXMg7KeA7KCVXG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGAke2NvbHVtblBhdGh9IEFTICR7YWxpYXN9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2VsZWN0Q2xhdXNlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIOykkeyyqSDqsJ3ssrTrpbwgZmxhdCDqsJ3ssrTroZwg67OA7ZmYXG4gICAqIOyYiDogeyBwYXJlbnQ6IHsgaWQ6IFwicGFyZW50LmlkXCIsIG5hbWU6IFwicGFyZW50Lm5hbWVcIiB9IH1cbiAgICogICDihpIgeyBwYXJlbnRfX2lkOiBcInBhcmVudC5pZFwiLCBwYXJlbnRfX25hbWU6IFwicGFyZW50Lm5hbWVcIiB9XG4gICAqL1xuICBwcml2YXRlIGZsYXR0ZW5TZWxlY3Qoc2VsZWN0T2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBwcmVmaXggPSBcIlwiKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgY29uc3QgZmxhdFNlbGVjdDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2VsZWN0T2JqKSkge1xuICAgICAgY29uc3QgZnVsbEtleSA9IHByZWZpeCA/IGAke3ByZWZpeH1fXyR7a2V5fWAgOiBrZXk7XG5cbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwgJiYgIShcIl90eXBlXCIgaW4gdmFsdWUpKSB7XG4gICAgICAgIC8vIOykkeyyqSDqsJ3ssrTsnbgg6rK97JqwIC0g7J6s6reAIOyymOumrFxuICAgICAgICBjb25zdCBuZXN0ZWQgPSB0aGlzLmZsYXR0ZW5TZWxlY3QodmFsdWUsIGZ1bGxLZXkpO1xuICAgICAgICBPYmplY3QuYXNzaWduKGZsYXRTZWxlY3QsIG5lc3RlZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyDsnbzrsJgg6rCS7J24IOqyveyasCAo7Lus65+8IOqyveuhnCDrmJDripQgU3FsRXhwcmVzc2lvbilcbiAgICAgICAgZmxhdFNlbGVjdFtmdWxsS2V5XSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmbGF0U2VsZWN0O1xuICB9XG5cbiAgLy8gU0VMRUNUIChzZWxlY3TripQgb3ZlcndyaXRlLCBhcHBlbmRTZWxlY3TripQgYXBwZW5kKVxuICBhcHBlbmRTZWxlY3Q8VFNlbGVjdCBleHRlbmRzIFNlbGVjdE9iamVjdDxUVGFibGVzPj4oXG4gICAgc2VsZWN0T2JqOiBUU2VsZWN0LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQgJiBQYXJzZVNlbGVjdE9iamVjdDxUVGFibGVzLCBUU2VsZWN0Pj4ge1xuICAgIC8vIOykkeyyqSDqsJ3ssrTrpbwgZmxhdO2VmOqyjCDrs4DtmZhcbiAgICBjb25zdCBmbGF0U2VsZWN0ID0gdGhpcy5mbGF0dGVuU2VsZWN0KHNlbGVjdE9iaik7XG5cbiAgICBjb25zdCBzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2FsaWFzLCBjb2x1bW5PckZ1bmN0aW9uXSBvZiBPYmplY3QuZW50cmllcyhmbGF0U2VsZWN0KSkge1xuICAgICAgaWYgKHR5cGVvZiBjb2x1bW5PckZ1bmN0aW9uID09PSBcIm9iamVjdFwiICYmIGNvbHVtbk9yRnVuY3Rpb24uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIikge1xuICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goXG4gICAgICAgICAgdGhpcy5rbmV4LnJhdyhgJHtjb2x1bW5PckZ1bmN0aW9uLl9zcWx9IEFTICR7YWxpYXN9YCwgY29sdW1uT3JGdW5jdGlvbi5fcGFyYW1zKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGNvbHVtblBhdGggPSBjb2x1bW5PckZ1bmN0aW9uIGFzIHN0cmluZztcbiAgICAgICAgaWYgKGFsaWFzID09PSBjb2x1bW5QYXRoKSB7XG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGNvbHVtblBhdGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaCh0aGlzLmtuZXgucmVmKGNvbHVtblBhdGgpLmFzKGFsaWFzKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2VsZWN0Q2xhdXNlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gU0VMRUNUICpcbiAgc2VsZWN0QWxsKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgU2VsZWN0QWxsUmVzdWx0PFRUYWJsZXM+PiB7XG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KFwiKlwiKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBESVNUSU5DVFxuICBkaXN0aW5jdDxUQ29sdW1ucyBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KC4uLmNvbHVtbnM6IFRDb2x1bW5zW10pOiB0aGlzO1xuICBkaXN0aW5jdCguLi5jb2x1bW5zOiBzdHJpbmdbXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LmRpc3RpbmN0KC4uLihjb2x1bW5zIGFzIHN0cmluZ1tdKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBDTEVBUlxuICBjbGVhcihzdGF0ZW1lbnQ6IENsZWFyU3RhdGVtZW50cyk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LmNsZWFyKHN0YXRlbWVudCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBrbmV47JeQIOyXhuyWtOyEnCDsp4HsoJEg6rWs7ZiE7ZWoXG4gIGNsZWFySm9pbihhbGlhczogc3RyaW5nKTogdGhpcyB7XG4gICAgKHRoaXMua25leFF1ZXJ5IGFzIGFueSkuX3N0YXRlbWVudHMgPSAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50cy5maWx0ZXIoKHM6IGFueSkgPT4ge1xuICAgICAgaWYgKFwiam9pblR5cGVcIiBpbiBzKSB7XG4gICAgICAgIGNvbnN0IFtfYWxpYXMsIF90YWJsZV0gPSBPYmplY3QuZW50cmllcyhzLnRhYmxlKVswXTtcbiAgICAgICAgcmV0dXJuIF9hbGlhcyAhPT0gYWxpYXM7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzXG4gIGpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFN1YlJlc3VsdD59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4sIC8vIOyEnOu4jOy/vOumrOydmCBUUmVzdWx0XG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBKT0lOOiDthYzsnbTruJQgKyBBbGlhc1xuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLCBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4sIC8vIFRUYWJsZXMg7ZmV7J6lIVxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gSk9JTjog7YWM7J2067iU66qFXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWE+KFxuICAgIHRhYmxlTmFtZTogVEpvaW5UYWJsZSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pblRhYmxlICYgc3RyaW5nfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5UYWJsZSwgVFNjaGVtYVtUSm9pblRhYmxlXT4sIC8vIO2FjOydtOu4lOuqheydtCDtgqRcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzICsg7L2c67CxXG4gIGpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4sIFRSZXN1bHQ+O1xuICAvLyBKT0lOOiDthYzsnbTruJQgKyBBbGlhcyArIOy9nOuwsVxuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLCBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4sIFRSZXN1bHQ+O1xuICAvLyBKT0lOOiDthYzsnbTruJTrqoUgKyDsvZzrsLFcbiAgam9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgVFJlc3VsdD47XG4gIC8vIEpPSU4g7Iuk7KCcIOq1rO2YhFxuICBqb2luKHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX19jb21tb25Kb2luKFwiam9pblwiLCB0YWJsZU5hbWVPclNwZWMsIC4uLmFyZ3MpO1xuICB9XG5cbiAgLy8gTEVGVCBKT0lOOiDshJzruIzsv7zrpqwgKyBBbGlhc1xuICBsZWZ0Sm9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU3ViUmVzdWx0Pn1gLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdCAmIExlZnRKb2luZWRNYXJrZXI+LCBUUmVzdWx0PjsgLy8g7ISc67iM7L+866as7J2YIFRSZXN1bHRcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJQgKyBBbGlhc1xuICAvLyBGSyBudWxsYWJsZSDsl6zrtoDsl5Ag65Sw6528IOyekOuPmeycvOuhnCBMZWZ0Sm9pbmVkTWFya2VyIOqysOyglVxuICBsZWZ0Sm9pbjxcbiAgICBUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSxcbiAgICBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLFxuICAgIFRMZWZ0IGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPixcbiAgPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBsZWZ0OiBUTGVmdCxcbiAgICByaWdodDogYCR7VEpvaW5BbGlhc30uJHtDb2x1bW5LZXlzPFRTY2hlbWFbVEpvaW5UYWJsZV0+fWAsXG4gICk6IFB1cmk8XG4gICAgVFNjaGVtYSxcbiAgICBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbk1hcmtlckZvcjxUVGFibGVzLCBUTGVmdD4+LFxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJTrqoVcbiAgbGVmdEpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRMZWZ0IGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGxlZnQ6IFRMZWZ0LFxuICAgIHJpZ2h0OiBgJHtUSm9pblRhYmxlICYgc3RyaW5nfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5UYWJsZSwgVFNjaGVtYVtUSm9pblRhYmxlXSAmIExlZnRKb2luTWFya2VyRm9yPFRUYWJsZXMsIFRMZWZ0Pj4sXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBMRUZUIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzICsg7L2c67CxXG4gIGxlZnRKb2luPFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsIFRTdWJSZXN1bHQ+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogUHVyaTxUU2NoZW1hLCBhbnksIFRTdWJSZXN1bHQ+IH0sXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luQWxpYXMsIFRTdWJSZXN1bHQ+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTdWJSZXN1bHQgJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTjog7YWM7J2067iUICsgQWxpYXMgKyDsvZzrsLFcbiAgbGVmdEpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+O1xuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lOuqhSArIOy9nOuwsVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+O1xuICAvLyBMRUZUIEpPSU4g7Iuk7KCcIOq1rO2YhFxuICBsZWZ0Sm9pbih0YWJsZU5hbWVPclNwZWM6IGFueSwgLi4uYXJnczogYW55W10pOiBhbnkge1xuICAgIHJldHVybiB0aGlzLl9fY29tbW9uSm9pbihcImxlZnRKb2luXCIsIHRhYmxlTmFtZU9yU3BlYywgLi4uYXJncyk7XG4gIH1cblxuICBfX2NvbW1vbkpvaW4oam9pblR5cGU6IFwiam9pblwiIHwgXCJsZWZ0Sm9pblwiLCB0YWJsZU5hbWVPclNwZWM6IGFueSwgLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBpZiAodHlwZW9mIHRhYmxlTmFtZU9yU3BlYyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgLy8gQ2FzZSAxOiBqb2luKFwicG9zdHNcIiwgLi4uKVxuICAgICAgY29uc3QgdGFibGVOYW1lID0gdGFibGVOYW1lT3JTcGVjO1xuXG4gICAgICBpZiAoYXJncy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGFyZ3NbMF0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAvLyBqb2luKFwicG9zdHNcIiwgY2FsbGJhY2spXG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXJnc1swXTtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHRhYmxlTmFtZSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICBjYWxsYmFjayhuZXcgSm9pbkNsYXVzZUdyb3VwKGpvaW5DbGF1c2UpKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBqb2luKFwicG9zdHNcIiwgbGVmdCwgcmlnaHQpXG4gICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0odGFibGVOYW1lLCBsZWZ0LCByaWdodCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTcGVjID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAvLyBDYXNlIDI6IGpvaW4oeyBhbGlhczogXCJ0YWJsZVwiIH0sIC4uLikgb3Igam9pbih7IGFsaWFzOiBzdWJxdWVyeSB9LCAuLi4pXG4gICAgICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXModGFibGVOYW1lT3JTcGVjKTtcbiAgICAgIGlmIChlbnRyaWVzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWJsZSBzcGVjIG11c3QgaGF2ZSBleGFjdGx5IG9uZSBlbnRyeVwiKTtcbiAgICAgIH1cbiAgICAgIGFzc2VydChlbnRyaWVzWzBdKTtcbiAgICAgIGNvbnN0IFtbYWxpYXMsIHNwZWNdXSA9IGVudHJpZXM7XG5cbiAgICAgIGlmICh0eXBlb2Ygc3BlYyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAvLyDthYzsnbTruJQ6IGpvaW4oeyBwOiBcInBvc3RzXCIgfSwgLi4uKVxuICAgICAgICBpZiAoYXJncy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGFyZ3NbMF0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIC8vIENhbGxiYWNrXG4gICAgICAgICAgY29uc3QgY2FsbGJhY2sgPSBhcmdzWzBdO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh7IFthbGlhc106IHNwZWMgfSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFNpbXBsZVxuICAgICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh7IFthbGlhc106IHNwZWMgfSwgbGVmdCwgcmlnaHQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNwZWMgaW5zdGFuY2VvZiBQdXJpKSB7XG4gICAgICAgIC8vIOyEnOu4jOy/vOumrDogam9pbih7IHNxOiBzdWJxdWVyeSB9LCAuLi4pXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgLy8gQ2FsbGJhY2tcbiAgICAgICAgICBjb25zdCBjYWxsYmFjayA9IGFyZ3NbMF07XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHNwZWMucmF3UXVlcnkoKS5hcyhhbGlhcyksIChqb2luQ2xhdXNlKSA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhuZXcgSm9pbkNsYXVzZUdyb3VwKGpvaW5DbGF1c2UpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBTaW1wbGVcbiAgICAgICAgICBjb25zdCBbbGVmdCwgcmlnaHRdID0gYXJncztcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0oc3BlYy5yYXdRdWVyeSgpLmFzKGFsaWFzKSwgbGVmdCwgcmlnaHQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYXJndW1lbnRzXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkU6IOqwneyytCAtIOyCrOyaqTogLndoZXJlKHsgXCJ1LmlkXCI6IDEsIFwidS5zdGF0dXNcIjogXCJhY3RpdmVcIiB9KVxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgMSksIC53aGVyZShcInUuaWRcIiwgbnVsbClcbiAgd2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgXCI+XCIsIDEwKSwgLndoZXJlKFwidS5pZFwiLCBcIiE9XCIsIG51bGwpXG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgb3BlcmF0b3I6IFdoZXJlT3BlcmF0b3IsXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBXSEVSRTogU1FMIO2RnO2YhOyLnSAtIOyCrOyaqTogLndoZXJlKHB1cmkucmF3KFwiQ09OQ0FUKHUubmFtZSwgdS5lbWFpbClcIiksIFwibGlrZVwiLCBcIiV0ZXN0JVwiKVxuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgS25leC5SYXc+KGNvbHVtbjogVENvbHVtbiwgb3BlcmF0b3I6IFdoZXJlT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICAvLyBXSEVSRTog7Lus65+8IC0g7IKs7JqpOiAud2hlcmUoXCJ1LmlkXCIsIFwibGlrZVwiLCBcIiV0ZXN0JVwiKVxuICB3aGVyZSguLi5hcmdzOiBbY29sdW1uT3JDb25kaXRpb25zOiBhbnksIG9wZXJhdG9yT3JWYWx1ZT86IGFueSwgdmFsdWU/OiBhbnldKTogdGhpcyB7XG4gICAgY29uc3QgW2NvbHVtbk9yQ29uZGl0aW9ucywgb3BlcmF0b3JPclZhbHVlLCB2YWx1ZV0gPSBhcmdzO1xuICAgIGlmICh0eXBlb2YgY29sdW1uT3JDb25kaXRpb25zID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBpZiAob3BlcmF0b3JPclZhbHVlID09PSBudWxsKSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKGNvbHVtbk9yQ29uZGl0aW9ucywgb3BlcmF0b3JPclZhbHVlKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgIGlmIChvcGVyYXRvck9yVmFsdWUgPT09IFwiIT1cIikge1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTm90TnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9IGVsc2UgaWYgKG9wZXJhdG9yT3JWYWx1ZSA9PT0gXCI9XCIpIHtcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZU51bGwoY29sdW1uT3JDb25kaXRpb25zKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUsIHZhbHVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRSBJTlxuICB3aGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQ+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZUluKGNvbHVtbiwgdmFsdWVzKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBXSEVSRSBOT1QgSU5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0PiB7XG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3RJbihjb2x1bW4sIHZhbHVlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgTUFUQ0ggKCR7U3RyaW5nKGNvbHVtbil9KSBBR0FJTlNUICg/KWAsIFt2YWx1ZV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFBHcm9vbmdhIEZ1bGxUZXh0IOyduOuNseyKpCDqsoDsg4lcbiAgICogLSDsgqzsmqntlaAgUEdyb29uZ2Eg7J24642x7Iqk7JmAIOuPmeydvO2VnCDsu6zrn7wg6rWs7ISx7Jy866GcIOqygOyDie2VtOyVvCDsnbjrjbHsiqTqsIAg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiDri6jsnbwg7Lus65+8IOqygOyDiTpcbiAgICogYGBgc3FsXG4gICAqIFdIRVJFIG5hbWUgJkB+ICdzZWFyY2gnXG4gICAqIGBgYFxuICAgKlxuICAgKiDrs7Xtlakg7Lus65+8IOqygOyDiTpcbiAgICogYGBgc3FsXG4gICAqIFdIRVJFIEFSUkFZW25hbWU6OnRleHQsIGRlc2NyaXB0aW9uOjp0ZXh0XSAmQH4gJ3NlYXJjaCdcbiAgICogYGBgXG4gICAqL1xuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHsgd2VpZ2h0cyB9ID0gb3B0aW9ucyA/PyB7fTtcbiAgICBjb25zdCBjb2x1bW5FeHByID0gQXJyYXkuaXNBcnJheShjb2x1bW4pXG4gICAgICA/IGBBUlJBWVske2NvbHVtbi5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogY29sdW1uO1xuICAgIGNvbnN0IHBncm9vbmdhQ29uZGl0aW9uID0gYHBncm9vbmdhX2NvbmRpdGlvbig/JHt3ZWlnaHRzPy5sZW5ndGggPyBgLCB3ZWlnaHRzID0+IEFSUkFZWyR7d2VpZ2h0cy5qb2luKFwiLFwiKX1dYCA6IFwiXCJ9KWA7XG5cbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW5FeHByfSAmQH4gJHtwZ3Jvb25nYUNvbmRpdGlvbn1gLCBbdmFsdWVdKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgRlVMTFRFWFRcbiAgd2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IG9wdGlvbnMgfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAob3B0aW9ucyA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIgJiYgY29sdW1uLl90eXBlID09PSBcInNxbF9leHByZXNzaW9uXCJcbiAgICAgICAgPyBjb2x1bW4uX3NxbFxuICAgICAgICA6IFN0cmluZyhjb2x1bW4pO1xuXG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gQEAgJHtwYXJzZXJ9KD8sID8pYCwgW2NvbmZpZywgdmFsdWVdKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IG9wZXJhdG9yID0gbm9ybWFsaXplRnV6enlPcGVyYXRvcihvcHRpb25zPy5vcGVyYXRvcik7XG5cbiAgICBpZiAob3BlcmF0b3IgPT09IFwiJVwiKSB7XG4gICAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW4uX3NxbH0gJHtvcGVyYXRvcn0gP2AsIFsuLi5jb2x1bW4uX3BhcmFtcywgdmFsdWVdKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/PyAke29wZXJhdG9yfSA/YCwgW2NvbHVtbiwgdmFsdWVdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPyAke29wZXJhdG9yfSAke2NvbHVtbi5fc3FsfWAsIFt2YWx1ZSwgLi4uY29sdW1uLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbdmFsdWUsIGNvbHVtbl0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFJBV1xuICB3aGVyZVJhdyhzcWw6IHN0cmluZywgYmluZGluZ3M/OiByZWFkb25seSB1bmtub3duW10pOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhzcWwsIGJpbmRpbmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIOq0hO2YuCDqt7jro7ntlZFcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZSgoYnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgZ3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihidWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKGdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkub3JXaGVyZSgoYnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgZ3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihidWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKGdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SREVSIEJZIChTcWxFeHByZXNzaW9u7Jy866Gc64+EIO2VoCDsiJgg7J6I7Ja07JW8IO2VqClcbiAgb3JkZXJCeTxUQ29sdW1uIGV4dGVuZHMgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgZGlyZWN0aW9uOiBcImFzY1wiIHwgXCJkZXNjXCIsXG4gICk6IHRoaXM7XG4gIG9yZGVyQnkoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBkaXJlY3Rpb246IFwiYXNjXCIgfCBcImRlc2NcIiA9IFwiYXNjXCIsXG4gICk6IHRoaXMge1xuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5vcmRlckJ5UmF3KGAke2NvbHVtbi5fc3FsfSAke2RpcmVjdGlvbn1gLCBjb2x1bW4uX3BhcmFtcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnkoY29sdW1uLCBkaXJlY3Rpb24pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiDrsqHthLAg7Jyg7IKs64+EIOqygOyDiSDshKTsoJVcbiAgICpcbiAgICogLSBTRUxFQ1Tsl5Agc2ltaWxhcml0eSDsu6zrn7wg7LaU6rCAXG4gICAqIC0gV0hFUkUgY29sIElTIE5PVCBOVUxMIOy2lOqwgFxuICAgKiAtIHRocmVzaG9sZOqwgCDsnojsnLzrqbQgV0hFUkUg7KGw6rG0IOy2lOqwgFxuICAgKiAtIOq4sOyhtCBPUkRFUiBCWeulvCBjbGVhcu2VmOqzoCDsm5Dsi5wg7Jew7IKw7J6Q66GcIOygleugrCAoSE5TVyDsnbjrjbHsiqQg7LWc7KCB7ZmUKVxuICAgKlxuICAgKiBAcGFyYW0gY29sdW1uIOuyoe2EsCDsu6zrn7wg6rK966GcXG4gICAqIEBwYXJhbSBlbWJlZGRpbmcg7L+866asIOyehOuyoOuUqSDrsqHthLBcbiAgICogQHBhcmFtIG9wdGlvbnMgbWV0aG9kLCB0aHJlc2hvbGQsIGFzIOuTsSDsmLXshZhcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBjb3NpbmUgc2ltaWxhcml0eSAo6riw67O46rCSKVxuICAgKiBxYi52ZWN0b3JTaW1pbGFyaXR5KFwiY29sdW1uTmFtZVwiLCBxdWVyeVZlY3Rvciwge1xuICAgKiAgIG1ldGhvZDogXCJjb3NpbmVcIixcbiAgICogICB0aHJlc2hvbGQ6IDAuNVxuICAgKiB9KTtcbiAgICpcbiAgICogLy8gTDIgZGlzdGFuY2VcbiAgICogcWIudmVjdG9yU2ltaWxhcml0eShcImNvbHVtbk5hbWVcIiwgcXVlcnlWZWN0b3IsIHtcbiAgICogICBtZXRob2Q6IFwibDJcIixcbiAgICogICB0aHJlc2hvbGQ6IDEuNSAgLy8g6rGw66as6rCAIDEuNSDsnbTtlZjsnbgg6rKw6rO866eMXG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBJbm5lciBwcm9kdWN0XG4gICAqIHFiLnZlY3RvclNpbWlsYXJpdHkoXCJjb2x1bW5OYW1lXCIsIHF1ZXJ5VmVjdG9yLCB7XG4gICAqICAgbWV0aG9kOiBcImlubmVyX3Byb2R1Y3RcIixcbiAgICogICB0aHJlc2hvbGQ6IDAuN1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICB2ZWN0b3JTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogVmVjdG9yQ29sdW1uczxUVGFibGVzPixcbiAgICBlbWJlZGRpbmc6IG51bWJlcltdLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIG1ldGhvZD86IFwiY29zaW5lXCIgfCBcImwyXCIgfCBcImlubmVyX3Byb2R1Y3RcIjtcbiAgICAgIHRocmVzaG9sZD86IG51bWJlcjtcbiAgICAgIGRpc3RpbmN0T24/OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+O1xuICAgIH0gPSB7fSxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0ICYgeyBzaW1pbGFyaXR5OiBudW1iZXIgfT4ge1xuICAgIGNvbnN0IHsgbWV0aG9kID0gXCJjb3NpbmVcIiwgdGhyZXNob2xkLCBkaXN0aW5jdE9uIH0gPSBvcHRpb25zO1xuXG4gICAgaWYgKFxuICAgICAgIUFycmF5LmlzQXJyYXkoZW1iZWRkaW5nKSB8fFxuICAgICAgZW1iZWRkaW5nLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgZW1iZWRkaW5nLnNvbWUoKHYpID0+ICFOdW1iZXIuaXNGaW5pdGUodikpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGVtYmVkZGluZyB2ZWN0b3I6IGV4cGVjdGVkIGEgbm9uLWVtcHR5IGFycmF5IG9mIGZpbml0ZSBudW1iZXJzXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IHZlY3RvckxpdGVyYWwgPSBKU09OLnN0cmluZ2lmeShlbWJlZGRpbmcubWFwKCh2KSA9PiBOdW1iZXIodikpKTtcbiAgICBjb25zdCBvcGVyYXRvciA9IHsgY29zaW5lOiBcIjw9PlwiLCBsMjogXCI8LT5cIiwgaW5uZXJfcHJvZHVjdDogXCI8Iz5cIiB9W21ldGhvZF07XG5cbiAgICAvLyBtZXRob2Trs4Qg7Jew7IKw7J6QIOuwjyBzaW1pbGFyaXR5IOqzhOyCsOyLnVxuICAgIC8vIC0gY29zaW5lOiA8PT4gKGNvc2luZSBkaXN0YW5jZSwgMH4yKSwgc2ltaWxhcml0eSA9IDEgLSBkaXN0YW5jZVxuICAgIC8vIC0gbDI6IDwtPiAoZXVjbGlkZWFuIGRpc3RhbmNlKSwgc2ltaWxhcml0eSA9IGRpc3RhbmNlICjrgq7snYTsiJjroZ0g7Jyg7IKsKVxuICAgIC8vIC0gaW5uZXJfcHJvZHVjdDogPCM+IChuZWdhdGl2ZSBpbm5lciBwcm9kdWN0KSwgc2ltaWxhcml0eSA9IC1kaXN0YW5jZSAo64aS7J2E7IiY66GdIOycoOyCrClcbiAgICBjb25zdCBzaW1pbGFyaXR5RXhwciA9XG4gICAgICBtZXRob2QgPT09IFwiY29zaW5lXCJcbiAgICAgICAgPyB0aGlzLmtuZXgucmF3KGAxIC0gKD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcikgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKVxuICAgICAgICA6IG1ldGhvZCA9PT0gXCJsMlwiXG4gICAgICAgICAgPyB0aGlzLmtuZXgucmF3KGA/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKVxuICAgICAgICAgIDogdGhpcy5rbmV4LnJhdyhgLSg/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IpIGFzIHNpbWlsYXJpdHlgLCBbY29sdW1uLCB2ZWN0b3JMaXRlcmFsXSk7XG5cbiAgICAvLyBXSEVSRSBOT1QgTlVMTFxuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTm90TnVsbChjb2x1bW4pO1xuXG4gICAgLy8g6riw7KG0IE9SREVSIEJZIGNsZWFyXG4gICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoXCJvcmRlclwiKTtcbiAgICBpZiAoZGlzdGluY3RPbikge1xuICAgICAgLy8gRElTVElOQ1QgT07snYAgU0VMRUNUIOygiOydmCDrp6gg7JWe7JeQIOyZgOyVvCDtlZjrr4DroZwsIOq4sOyhtCBzZWxlY3Qoc3Vic2V0IO2VhOuTnOuTpCnrpbwg67O07KG0IO2bhCBjbGVhcu2VmOqzoCDri6Tsi5wg7LaU6rCAXG4gICAgICBjb25zdCBleGlzdGluZ1N1YnNldENvbHMgPSAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50c1xuICAgICAgICAuZmlsdGVyKChzOiBhbnkpID0+IHMuZ3JvdXBpbmcgPT09IFwiY29sdW1uc1wiKVxuICAgICAgICAuZmxhdE1hcCgoczogYW55KSA9PiBzLnZhbHVlKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5LmNsZWFyKFwic2VsZWN0XCIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHRoaXMua25leC5yYXcoYERJU1RJTkNUIE9OICg/PykgPz9gLCBbZGlzdGluY3RPbiwgZGlzdGluY3RPbl0pKTtcbiAgICAgIGV4aXN0aW5nU3Vic2V0Q29scy5tYXAoKGNvbDogYW55KSA9PiB0aGlzLmtuZXhRdWVyeS5zZWxlY3QoY29sKSk7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2ltaWxhcml0eUV4cHIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeVJhdyhgPz8sID8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcmAsIFtcbiAgICAgICAgZGlzdGluY3RPbixcbiAgICAgICAgY29sdW1uLFxuICAgICAgICB2ZWN0b3JMaXRlcmFsLFxuICAgICAgXSk7XG5cbiAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4XG4gICAgICAgIC5mcm9tKHRoaXMua25leFF1ZXJ5LmFzKFwiZGlzdGluY3RfdmVjdG9yc1wiKSlcbiAgICAgICAgLnNlbGVjdChcIipcIilcbiAgICAgICAgLm9yZGVyQnkoXCJzaW1pbGFyaXR5XCIsIFwiZGVzY1wiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNpbWlsYXJpdHlFeHByKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnlSYXcoYD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcmAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKTtcbiAgICB9XG5cbiAgICAvLyB0aHJlc2hvbGRcbiAgICBpZiAodHlwZW9mIHRocmVzaG9sZCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUodGhyZXNob2xkKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdmVjdG9yU2ltaWxhcml0eSB0aHJlc2hvbGQ6ICR7dGhyZXNob2xkfWApO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGlzdGluY3RPbikge1xuICAgICAgICBjb25zdCB0aHJlc2hvbGRPcCA9IG1ldGhvZCA9PT0gXCJsMlwiID8gXCI8PVwiIDogXCI+PVwiO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShcInNpbWlsYXJpdHlcIiwgdGhyZXNob2xkT3AsIHRocmVzaG9sZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB0aHJlc2hvbGRWYWx1ZSA9XG4gICAgICAgICAgbWV0aG9kID09PSBcImNvc2luZVwiID8gMSAtIHRocmVzaG9sZCA6IG1ldGhvZCA9PT0gXCJpbm5lcl9wcm9kdWN0XCIgPyAtdGhyZXNob2xkIDogdGhyZXNob2xkO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yIDw9ID9gLCBbXG4gICAgICAgICAgY29sdW1uLFxuICAgICAgICAgIHZlY3RvckxpdGVyYWwsXG4gICAgICAgICAgdGhyZXNob2xkVmFsdWUsXG4gICAgICAgIF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIOq4sOuzuCDsv7zrpqwg66mU7ISc65Oc65OkXG4gIGxpbWl0KGNvdW50OiBudW1iZXIpOiB0aGlzIHtcbiAgICBpZiAoY291bnQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGxpbWl0OiBtdXN0IGJlID49IDBcIik7XG4gICAgfVxuICAgIHRoaXMua25leFF1ZXJ5LmxpbWl0KGNvdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9mZnNldChjb3VudDogbnVtYmVyKTogdGhpcyB7XG4gICAgaWYgKGNvdW50IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBvZmZzZXQ6IG11c3QgYmUgPj0gMFwiKTtcbiAgICB9XG4gICAgdGhpcy5rbmV4UXVlcnkub2Zmc2V0KGNvdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEdST1VQIEJZXG4gIGdyb3VwQnk8VENvbHVtbnMgZXh0ZW5kcyBSZXN1bHRBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXMsIFRSZXN1bHQ+PiguLi5jb2x1bW5zOiBUQ29sdW1uc1tdKTogdGhpcztcbiAgZ3JvdXBCeSguLi5jb2x1bW5zOiBzdHJpbmdbXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5Lmdyb3VwQnkoLi4uKGNvbHVtbnMgYXMgc3RyaW5nW10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEhBVklOR1xuICBoYXZpbmcoY29uZGl0aW9uOiBzdHJpbmcpOiB0aGlzO1xuICBoYXZpbmc8VENvbHVtbiBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHZhbHVlOiBhbnksXG4gICk6IHRoaXM7XG4gIC8vIEhBVklORyDqtaztmIRcbiAgaGF2aW5nKC4uLmNvbmRpdGlvbnM6IGFueVtdKTogdGhpcyB7XG4gICAgaWYgKGNvbmRpdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICAvLyBoYXZpbmcoXCJDT1VOVCgqKSA+IDEwXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeS5oYXZpbmcodGhpcy5rbmV4LnJhdyhjb25kaXRpb25zWzBdKSk7XG4gICAgfSBlbHNlIGlmIChjb25kaXRpb25zLmxlbmd0aCA9PT0gMykge1xuICAgICAgLy8gaGF2aW5nKFwiY291bnRcIiwgXCI+XCIsIDEwKVxuICAgICAgdGhpcy5rbmV4UXVlcnkuaGF2aW5nKFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMF0pLFxuICAgICAgICBjb25kaXRpb25zWzFdLFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMl0pLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBoYXZpbmcgYXJndW1lbnRzXCIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOyLpO2WiSDrqZTshJzrk5zrk6QgLSB0aGVuYWJsZSDqtaztmIRcbiAgdGhlbjxUUmVzdWx0MSA9IEV4cGFuZDxUUmVzdWx0PltdLCBUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbmZ1bGZpbGxlZD86ICgodmFsdWU6IEV4cGFuZDxUUmVzdWx0PltdKSA9PiBUUmVzdWx0MSB8IFByb21pc2VMaWtlPFRSZXN1bHQxPikgfCBudWxsLFxuICAgIG9ucmVqZWN0ZWQ/OiAoKHJlYXNvbjogYW55KSA9PiBUUmVzdWx0MiB8IFByb21pc2VMaWtlPFRSZXN1bHQyPikgfCBudWxsLFxuICApOiBQcm9taXNlPFRSZXN1bHQxIHwgVFJlc3VsdDI+IHtcbiAgICBOYWl0ZS50KFwicHVyaTpleGVjdXRlZC1xdWVyeVwiLCB0aGlzLnRvUXVlcnkoKSk7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LnRoZW4ob25mdWxmaWxsZWQgYXMgYW55LCBvbnJlamVjdGVkKTtcbiAgfVxuICBjYXRjaDxUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbnJlamVjdGVkPzogKChyZWFzb246IGFueSkgPT4gVFJlc3VsdDIgfCBQcm9taXNlTGlrZTxUUmVzdWx0Mj4pIHwgbnVsbCxcbiAgKTogUHJvbWlzZTxUUmVzdWx0IHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cbiAgZmluYWxseShvbmZpbmFsbHk/OiAoKCkgPT4gdm9pZCkgfCBudWxsKTogUHJvbWlzZTxUUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LmZpbmFsbHkob25maW5hbGx5KTtcbiAgfVxuXG4gIC8vIO2VmOuCmOunjCDsv7zrpqxcbiAgZmlyc3QoKTogUmVzb2x2ZWRQdXJpPEV4cGFuZDxUUmVzdWx0PiwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5maXJzdCgpO1xuICAgIHJldHVybiBuZXcgUmVzb2x2ZWRQdXJpKHRoaXMua25leFF1ZXJ5LCB0aGlzLmtuZXgpO1xuICB9XG5cbiAgLy8g7L+866as7ZWcIOugiOy9lOuTnOyXkOyEnCDtirnsoJUg7Lus65+866eMIOy2lOy2nO2VnCDrsLDsl7Qg66as7YS0XG4gIHBsdWNrPFRDb2x1bW4gZXh0ZW5kcyBrZXlvZiBUUmVzdWx0IHwgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICApOiBSZXNvbHZlZFB1cmk8XG4gICAgVENvbHVtbiBleHRlbmRzIGtleW9mIFRSZXN1bHRcbiAgICAgID8gVFJlc3VsdFtUQ29sdW1uXVtdXG4gICAgICA6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICAgbmV2ZXJcbiAgPiB7XG4gICAgdGhpcy5rbmV4UXVlcnkucGx1Y2soY29sdW1uIGFzIHN0cmluZyk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBJTlNFUlQgOiDri6jsnbwg6rCd7LK0XG4gIGluc2VydChcbiAgICBkYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+LFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PjtcbiAgLy8gSU5TRVJUOiDrsLDsl7RcbiAgaW5zZXJ0KFxuICAgIGRhdGE6IEluc2VydERhdGE8U2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj5bXSxcbiAgKTogUmVzb2x2ZWRQdXJpPEluc2VydFJlc3VsdCwgU2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj47XG4gIC8vIElOU0VSVCDsi6TsoJwg6rWs7ZiEXG4gIGluc2VydChcbiAgICByYXdEYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHwgSW5zZXJ0RGF0YTxTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PltdLFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkuaW5zZXJ0KHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIFVQREFURVxuICB1cGRhdGUocmF3RGF0YTogV2hlcmVDb25kaXRpb248VFRhYmxlcz4pOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkudXBkYXRlKHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBKU09OIOy7rOufvOyXkCDrjIDtlbQgc3RyaW5naWZ5IOyymOumrOulvCDsiJjtlontlZjripQg64K067aAIOuplOyEnOuTnOyeheuLiOuLpC5cbiAgICogb2JqZWN0IOuYkOuKlCBvYmplY3Qg67Cw7Je07J2EIOuwm+qzoCwgSlNPTiDsu6zrn7zsnbQg7J6I7Jy866m0IOyngeugrO2ZlO2VmOyXrCDrsJjtmZjtlanri4jri6QuXG4gICAqIOyngeygkSDqsJLsnYQg67OA6rK97ZWY66+A66GcIHNpZGUgZWZmZWN06rCAIOyeiOyKteuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgcmVmaW5lSnNvbkNvbHVtbnMoXG4gICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdLFxuICApOiB0eXBlb2YgZGF0YSB7XG4gICAgLy8gdGFibGVTcGVj7J2064KYIGpzb25Db2x1bW5zIOyXhuuKlCDqsr3smrAg67CU66GcIOuwmO2ZmFxuICAgIGlmICghdGhpcy50YWJsZVNwZWMgfHwgIXRoaXMudGFibGVTcGVjLmpzb25Db2x1bW5zLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxuXG4gICAgLy8g65Ox66Gd65CcIFRhYmxlU3BlY+ydhCDthrXtlbQgSlNPTuy7rOufvCDrqqnroZ3snYQg6rCA7KC47JmAIEpTT04uc3RyaW5naWZ5IOyymOumrFxuICAgIGNvbnN0IGpzb25Db2x1bW5zID0gdGhpcy50YWJsZVNwZWMuanNvbkNvbHVtbnM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBkYXRhKSB7XG4gICAgICAgIGZvciAoY29uc3QgY29sdW1uIG9mIGpzb25Db2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBpdGVtW2NvbHVtbl07XG4gICAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGl0ZW1bY29sdW1uXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBjb2x1bW4gb2YganNvbkNvbHVtbnMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBkYXRhW2NvbHVtbl07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgZGF0YVtjb2x1bW5dID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLy8gSW5jcmVtZW50XG4gIGluY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkluY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5pbmNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cbiAgLy8gRGVjcmVtZW50XG4gIGRlY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5kZWNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBERUxFVEVcbiAgZGVsZXRlKCk6IFJlc29sdmVkUHVyaTxudW1iZXIsIFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kZWxldGUoKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIO2ZleyduCDsv7zrpqwg66as7YS0XG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgLy8g7L+866asIOuUlOuyhOq5hSDroZzqt7gg7Lac66ClXG4gIGRlYnVnKCk6IHRoaXMge1xuICAgIGNvbnNvbGUubG9nKGAke2NoYWxrLmN5YW4oXCJbUHVyaSBEZWJ1Z11cIil9ICR7Y2hhbGsueWVsbG93KHRoaXMudG9RdWVyeSgpKX1gKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGNsb25lKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIC8vICdkdWFsJ+ydgCDrjZTrr7gg7YWM7J2067iU7J2066mwLCDrsJTroZwg7JWE656YIOykhOyXkOyEnCBrbmV4UXVlcnnqsIAg642u7Ja07JSM7JuM7KeR64uI64ukLlxuICAgIGNvbnN0IG5ld1B1cmkgPSBuZXcgUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0Pih0aGlzLmtuZXgsIFwiZHVhbFwiKTtcbiAgICBuZXdQdXJpLmtuZXhRdWVyeSA9IHRoaXMua25leFF1ZXJ5LmNsb25lKCk7XG4gICAgcmV0dXJuIG5ld1B1cmk7XG4gIH1cblxuICBmb3JtYXRTUUwodW5mb3JtYXR0ZWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gU1FMIOyYiOyVveyWtCDrqqnroZ1cbiAgICBjb25zdCBrZXl3b3JkcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiSU5TRVJUXCIsXG4gICAgICBcIklOVE9cIixcbiAgICAgIFwiVkFMVUVTXCIsXG4gICAgICBcIlVQREFURVwiLFxuICAgICAgXCJERUxFVEVcIixcbiAgICAgIFwiQ1JFQVRFXCIsXG4gICAgICBcIlRBQkxFXCIsXG4gICAgICBcIkFMVEVSXCIsXG4gICAgICBcIkRST1BcIixcbiAgICAgIFwiSk9JTlwiLFxuICAgICAgXCJPTlwiLFxuICAgICAgXCJJTk5FUlwiLFxuICAgICAgXCJMRUZUXCIsXG4gICAgICBcIlJJR0hUXCIsXG4gICAgICBcIkZVTExcIixcbiAgICAgIFwiT1VURVJcIixcbiAgICAgIFwiR1JPVVBcIixcbiAgICAgIFwiQllcIixcbiAgICAgIFwiT1JERVJcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkRJU1RJTkNUXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIk9GRlNFVFwiLFxuICAgICAgXCJBU1wiLFxuICAgICAgXCJBTkRcIixcbiAgICAgIFwiT1JcIixcbiAgICAgIFwiTk9UXCIsXG4gICAgICBcIklOXCIsXG4gICAgICBcIkxJS0VcIixcbiAgICAgIFwiSVNcIixcbiAgICAgIFwiTlVMTFwiLFxuICAgICAgXCJDQVNFXCIsXG4gICAgICBcIldIRU5cIixcbiAgICAgIFwiVEhFTlwiLFxuICAgICAgXCJFTFNFXCIsXG4gICAgICBcIkVORFwiLFxuICAgICAgXCJVTklPTlwiLFxuICAgICAgXCJBTExcIixcbiAgICAgIFwiRVhJU1RTXCIsXG4gICAgICBcIkJFVFdFRU5cIixcbiAgICBdO1xuXG4gICAgbGV0IGZvcm1hdHRlZCA9IHVuZm9ybWF0dGVkO1xuXG4gICAgLy8g7JiI7JW97Ja066W8IOuMgOusuOyekOuhnCDrs4DtmZhcbiAgICBrZXl3b3Jkcy5mb3JFYWNoKChrZXl3b3JkKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxiJHtrZXl3b3JkfVxcXFxiYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBrZXl3b3JkLnRvVXBwZXJDYXNlKCkpO1xuICAgIH0pO1xuXG4gICAgLy8g7KO87JqUIOygiCDslZ7sl5Ag7KSE67CU6r+IIOy2lOqwgFxuICAgIGNvbnN0IG1ham9yQ2xhdXNlcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiR1JPVVAgQllcIixcbiAgICAgIFwiT1JERVIgQllcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIlVOSU9OXCIsXG4gICAgXTtcbiAgICBtYWpvckNsYXVzZXMuZm9yRWFjaCgoY2xhdXNlKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxzKygke2NsYXVzZX0pXFxcXHMrYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBgXFxuJHtjbGF1c2UudG9VcHBlckNhc2UoKX0gYCk7XG4gICAgfSk7XG5cbiAgICAvLyBKT0lOIOygiCDsspjrpqxcbiAgICBmb3JtYXR0ZWQgPSBmb3JtYXR0ZWQucmVwbGFjZSgvXFxzKygoPzpJTk5FUnxMRUZUfFJJR0hUfEZVTEwgT1VURVIpXFxzKyk/Sk9JTlxccysvZ2ksIFwiXFxuJDFKT0lOIFwiKTtcblxuICAgIC8vIEFORCwgT1Ig7KGw6rG0IOyymOumrFxuICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKC9cXHMrKEFORHxPUilcXHMrL2dpLCBcIlxcbiAgJDEgXCIpO1xuXG4gICAgLy8g6rSE7Zi4IOyymOumrCDrsI8g65Ok7Jes7JOw6riwXG4gICAgY29uc3QgbGluZXMgPSBmb3JtYXR0ZWQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgaW5kZW50ZWRMaW5lcyA9IFtdO1xuICAgIGxldCBpbmRlbnRMZXZlbCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG4gICAgICBpZiAoIXRyaW1tZWRMaW5lKSBjb250aW51ZTtcblxuICAgICAgLy8g64ur64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDqsJDshoxcbiAgICAgIGNvbnN0IGNsb3NpbmdQYXJlbnMgPSAodHJpbW1lZExpbmUubWF0Y2goL1xcKS9nKSB8fCBbXSkubGVuZ3RoO1xuICAgICAgY29uc3Qgb3BlbmluZ1BhcmVucyA9ICh0cmltbWVkTGluZS5tYXRjaCgvXFwoL2cpIHx8IFtdKS5sZW5ndGg7XG5cbiAgICAgIGlmIChjbG9zaW5nUGFyZW5zID4gMCAmJiBvcGVuaW5nUGFyZW5zID09PSAwKSB7XG4gICAgICAgIGluZGVudExldmVsID0gTWF0aC5tYXgoMCwgaW5kZW50TGV2ZWwgLSBjbG9zaW5nUGFyZW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8g7ZiE7J6sIOuTpOyXrOyTsOq4sCDsoIHsmqlcbiAgICAgIGNvbnN0IGluZGVudCA9IFwiICBcIi5yZXBlYXQoaW5kZW50TGV2ZWwpO1xuICAgICAgaW5kZW50ZWRMaW5lcy5wdXNoKGluZGVudCArIHRyaW1tZWRMaW5lKTtcblxuICAgICAgLy8g7Jes64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDspp3qsIBcbiAgICAgIGlmIChvcGVuaW5nUGFyZW5zID4gY2xvc2luZ1BhcmVucykge1xuICAgICAgICBpbmRlbnRMZXZlbCArPSBvcGVuaW5nUGFyZW5zIC0gY2xvc2luZ1BhcmVucztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW5kZW50ZWRMaW5lcy5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgfVxuXG4gIHJhdyhzcWw6IHN0cmluZyk6IEtuZXguUmF3IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4LnJhdyhzcWwpO1xuICB9XG5cbiAgLy8gS25leCDsv7zrpqwg67mM642UIOyngeygkSDsoJHqt7xcbiAgcmF3UXVlcnkoKTogS25leC5RdWVyeUJ1aWxkZXIge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgV2hlcmVHcm91cDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGJ1aWxkZXI6IEtuZXguUXVlcnlCdWlsZGVyKSB7fVxuXG4gIC8vIHdoZXJlIOuplOyEnOuTnOuTpFxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIG9wZXJhdG9yOiBXaGVyZU9wZXJhdG9yLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgd2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmUoYXJnc1swXSwgLi4uYXJncy5zbGljZSgxKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyB3aGVyZUluIC8gd2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgd2hlcmVJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVOb3RJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gb3JXaGVyZSDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZShhcmdzWzBdLCAuLi5hcmdzLnNsaWNlKDEpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIG9yV2hlcmVJbiAvIG9yV2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlSW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlTm90SW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzO1xuICB3aGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoYXJnc1swXSl9KSBBR0FJTlNUICg/KWAsIFthcmdzWzFdXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBvcldoZXJlTWF0Y2g8VENvbHVtbiBleHRlbmRzIEZ1bGx0ZXh0Q29sdW1uczxUVGFibGVzPj4oY29sdW1uOiBUQ29sdW1uLCB2YWx1ZTogc3RyaW5nKTogdGhpcztcbiAgb3JXaGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYE1BVENIICgke1N0cmluZyhhcmdzWzBdKX0pIEFHQUlOU1QgKD8pYCwgW2FyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFNFQVJDSFxuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBhcmdzWzJdID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGFyZ3NbMF0pXG4gICAgICA/IGBBUlJBWVske2FyZ3NbMF0ubWFwKChjKSA9PiBgJHtjfTo6dGV4dGApLmpvaW4oXCIsXCIpfV1gXG4gICAgICA6IGFyZ3NbMF07XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gJkB+ICR7cGdyb29uZ2FDb25kaXRpb259YCwgW2FyZ3NbMV1dKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVTZWFyY2goLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCB7IHdlaWdodHMgfSA9IGFyZ3NbMl0gPz8ge307XG4gICAgY29uc3QgY29sdW1uRXhwciA9IEFycmF5LmlzQXJyYXkoYXJnc1swXSlcbiAgICAgID8gYEFSUkFZWyR7YXJnc1swXS5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogYXJnc1swXTtcbiAgICBjb25zdCBwZ3Jvb25nYUNvbmRpdGlvbiA9IGBwZ3Jvb25nYV9jb25kaXRpb24oPyR7d2VpZ2h0cz8ubGVuZ3RoID8gYCwgd2VpZ2h0cyA9PiBBUlJBWVske3dlaWdodHMuam9pbihcIixcIil9XWAgOiBcIlwifSlgO1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFthcmdzWzFdXSk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIEZVTExURVhUXG4gIHdoZXJlVHNTZWFyY2g8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNRdWVyeU9wdGlvbnMgfCBUc1F1ZXJ5Q29uZmlnLFxuICApOiB0aGlzO1xuICB3aGVyZVRzU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2YgYXJnc1syXSA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogYXJnc1syXSB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChhcmdzWzJdID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIgJiYgYXJnc1swXS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgID8gYXJnc1swXS5fc3FsXG4gICAgICAgIDogU3RyaW5nKGFyZ3NbMF0pO1xuXG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVUc1NlYXJjaCguLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIGFyZ3NbMl0gPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IGFyZ3NbMl0gfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAoYXJnc1syXSA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiICYmIGFyZ3NbMF0uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGFyZ3NbMF0uX3NxbFxuICAgICAgICA6IFN0cmluZyhhcmdzWzBdKTtcblxuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlRnV6enkoLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCBvcGVyYXRvciA9IG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IoYXJnc1syXT8ub3BlcmF0b3IpO1xuXG4gICAgaWYgKG9wZXJhdG9yID09PSBcIiVcIikge1xuICAgICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMuYnVpbGRlci53aGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbYXJnc1swXSwgYXJnc1sxXV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gJHthcmdzWzBdLl9zcWx9YCwgW2FyZ3NbMV0sIC4uLmFyZ3NbMF0uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcztcbiAgb3JXaGVyZUZ1enp5KC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKGFyZ3NbMl0/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYXJnc1swXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gP2AsIFthcmdzWzBdLCBhcmdzWzFdXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7YXJnc1swXS5fc3FsfWAsIFthcmdzWzFdLCAuLi5hcmdzWzBdLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOykkeyyqSDqt7jro7lcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzO1xuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZSgoc3ViQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3Qgc3ViR3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihzdWJCdWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKHN1Ykdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcztcbiAgb3JXaGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlKChzdWJCdWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBzdWJHcm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KHN1YkJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soc3ViR3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8vIEpPSU4g7KCIIOq3uOujueyXkOuKlCBMZWZ07JmAIFJpZ2h07JeQIOuMgO2VnCDsiJzshJzqsIAg7ZWE7JqU7ZWY7KeAIOyViuycvOuvgOuhnCwg66qo65OgIOqyveyasOydmCDsiJjrpbwg6rOE7IKw7ZW07JW87ZWoLlxuZXhwb3J0IGNsYXNzIEpvaW5DbGF1c2VHcm91cDxcbiAgVExlZnQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICBUUmlnaHQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuPiB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2FsbGJhY2s6IEtuZXguSm9pbkNsYXVzZSkge31cblxuICAvLyBPTihBTkQpOiDsu6zrn7wgPSDsu6zrn7xcbiAgb24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvbihsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Pik6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCA9IOqwklxuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIHJpZ2h0OiBFeHRyYWN0Q29sdW1uVHlwZTxUUmlnaHQsIEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDsu6zrn7xcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDqsJJcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oQU5EKTog7L2c67CxXG4gIG9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvbihjYWxsYmFjazogKG5lc3RlZDogSm9pbkNsYXVzZUdyb3VwPFRSaWdodCwgVExlZnQ+KSA9PiB2b2lkKTogdGhpcztcbiAgLy8gT04oQU5EKSDqtaztmIRcbiAgb24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9uKC4uLihhcmdzIGFzIFtzdHJpbmcsIHN0cmluZ10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9OKE9SKTog7Lus65+8ID0g7Lus65+8XG4gIG9yT24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvck9uKGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgcmlnaHQ6IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+KTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgPSDqsJJcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg7Lus65+8XG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvck9uKFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg6rCSXG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VFJpZ2h0LCBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBPTihPUik6IOy9nOuwsVxuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VFJpZ2h0LCBUTGVmdD4pID0+IHZvaWQpOiB0aGlzO1xuICAvLyBPTihPUikg6rWs7ZiEXG4gIG9yT24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9yT24oLi4uKGFyZ3MgYXMgW3N0cmluZywgc3RyaW5nXSkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT04gVkFMKEFORCk6IOy7rOufvCA9IOqwkiAo6rCS7J2EIOy7rOufvCDssLjsobDqsIAg7JWE64uMIO2MjOudvOuvuO2EsOuhnCDrsJTsnbjrlKkpXG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEFORCBPTiBWQUw6IG9uVmFs7J2YIOuqheyLnOyggSBhbGlhcyAoS25leCDtmLjtmZgpXG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5hbmRPblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SIE9OIFZBTDogT1Ig7KGw6rG07Jy866GcIOqwkiDrsJTsnbjrlKlcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+LCB2YWx1ZTogYW55KTogdGhpcztcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvck9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vck9uVmFsKC4uLmFyZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8qXG4gIFRSZXNvbHZlZDog7L+866asIOyLpO2WiSDtm4Qg67CY7ZmY65CgIOqysOqzvCDtg4DsnoVcbiAgVFJldHVybmluZzogUkVUVVJOSU5HIOygiOyXkCDsgqzsmqnrkKAg7YOA7J6FXG4qL1xuZXhwb3J0IGNsYXNzIFJlc29sdmVkUHVyaTxUUmVzb2x2ZWQsIFRSZXR1cm5pbmc+IGltcGxlbWVudHMgUHJvbWlzZTxUUmVzb2x2ZWQ+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBrbmV4OiBLbmV4LFxuICApIHt9XG5cbiAgW1N5bWJvbC50b1N0cmluZ1RhZ106IHN0cmluZyA9IFwiUHJvbWlzZVwiO1xuXG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgZGVidWcoKTogdGhpcyB7XG4gICAgY29uc29sZS5sb2coYCR7Y2hhbGsuY3lhbihcIltQdXJpIERlYnVnXVwiKX0gJHtjaGFsay55ZWxsb3codGhpcy50b1F1ZXJ5KCkpfWApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdGhlbjxUUmVzdWx0MSA9IFRSZXNvbHZlZCwgVFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25mdWxmaWxsZWQ/OiAoKHZhbHVlOiBUUmVzb2x2ZWQpID0+IFRSZXN1bHQxIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDE+KSB8IG51bGwsXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc3VsdDEgfCBUUmVzdWx0Mj4ge1xuICAgIE5haXRlLnQoXCJwdXJpOmV4ZWN1dGVkLXF1ZXJ5XCIsIHRoaXMudG9RdWVyeSgpKTtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudGhlbihvbmZ1bGZpbGxlZCBhcyBhbnksIG9ucmVqZWN0ZWQpO1xuICB9XG5cbiAgY2F0Y2g8VFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc29sdmVkIHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cblxuICBmaW5hbGx5KG9uZmluYWxseT86ICgoKSA9PiB2b2lkKSB8IG51bGwpOiBQcm9taXNlPFRSZXNvbHZlZD4ge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeS5maW5hbGx5KG9uZmluYWxseSk7XG4gIH1cblxuICAvLyBPTiBDT05GTElDVCAtIOy7rOufvCDquLDrsJhcbiAgb25Db25mbGljdDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgVFJldHVybmluZz4+KFxuICAgIGNvbHVtbnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGFjdGlvbj86IE9uQ29uZmxpY3RBY3Rpb248VFRhYmxlcz4sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHRhcmdldCA9IEFycmF5LmlzQXJyYXkoY29sdW1ucykgPyBjb2x1bW5zIDogW2NvbHVtbnNdO1xuXG4gICAgaWYgKCFhY3Rpb24gfHwgYWN0aW9uID09PSBcIm5vdGhpbmdcIikge1xuICAgICAgLy8gRE8gTk9USElOR1xuICAgICAgdGhpcy5rbmV4UXVlcnkub25Db25mbGljdCh0YXJnZXQpLmlnbm9yZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBETyBVUERBVEVcbiAgICAgIGNvbnN0IHsgdXBkYXRlIH0gPSBhY3Rpb247XG5cbiAgICAgIC8vIGFjdGlvbi51cGRhdGUg67Cw7Je0IO2Yle2DnCA6IFtcIm5hbWVcIiwgXCJlbWFpbFwiXVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodXBkYXRlKSkge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UodXBkYXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFjdGlvbi51cGRhdGUg6rCd7LK0IO2Yle2DnDogeyBuYW1lOiBcIkpvaG5cIiwgY291bnQ6IHJhdyguLi4pIH1cbiAgICAgICAgY29uc3QgbWVyZ2VPYmo6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGUpKSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdmFsdWUgJiZcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgXCJfdHlwZVwiIGluIHZhbHVlICYmXG4gICAgICAgICAgICB2YWx1ZS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBTcWxFeHByZXNzaW9uIOKGkiBrbmV4LnJhdygp66GcIOuzgO2ZmFxuICAgICAgICAgICAgbWVyZ2VPYmpba2V5XSA9IHRoaXMua25leC5yYXcoKHZhbHVlIGFzIFNxbEV4cHJlc3Npb248YW55PikuX3NxbCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOydvOuwmCDqsJJcbiAgICAgICAgICAgIG1lcmdlT2JqW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UobWVyZ2VPYmopO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gUkVUVVJOSU5HOiBcIipcIiAtIOyghOyytCDsu6zrn7xcbiAgcmV0dXJuaW5nKGNvbHVtbjogXCIqXCIpOiBSZXNvbHZlZFB1cmk8VFJldHVybmluZ1tdLCBuZXZlcj47XG4gIC8vIFJFVFVSTklORzog64uo7J28IOy7rOufvFxuICByZXR1cm5pbmc8VENvbHVtbiBleHRlbmRzIENvbHVtbktleXM8VFJldHVybmluZz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgKTogUmVzb2x2ZWRQdXJpPFBpY2s8VFJldHVybmluZywgVENvbHVtbj5bXSwgbmV2ZXI+O1xuICAvLyBSRVRVUk5JTkc6IOuzteyImCDsu6zrn7wgKOuwsOyXtClcbiAgcmV0dXJuaW5nPFRDb2x1bW4gZXh0ZW5kcyBDb2x1bW5LZXlzPFRSZXR1cm5pbmc+PihcbiAgICBjb2x1bW5zOiBUQ29sdW1uW10sXG4gICk6IFJlc29sdmVkUHVyaTxQaWNrPFRSZXR1cm5pbmcsIFRDb2x1bW4+W10sIG5ldmVyPjtcbiAgLy8gUkVUVVJOSU5HIOq1rO2YhFxuICByZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSk6IFJlc29sdmVkUHVyaTxhbnlbXSwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5yZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbImFzc2VydCIsImNoYWxrIiwiaW5mbGVjdGlvbiIsIkVudGl0eU1hbmFnZXIiLCJOYWl0ZSIsIkZVWlpZX09QRVJBVE9SUyIsIm5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IiLCJvcGVyYXRvciIsIm5vcm1hbGl6ZWQiLCJ0cmltIiwiZnV6enlPcGVyYXRvciIsImZpbmQiLCJjYW5kaWRhdGUiLCJFcnJvciIsIlB1cmkiLCJrbmV4UXVlcnkiLCJ0YWJsZVNwZWMiLCJrbmV4IiwidGFibGVOYW1lT3JTb3VyY2UiLCJmcm9tIiwic2FmZUdldFRhYmxlU3BlYyIsImVudHJpZXMiLCJPYmplY3QiLCJsZW5ndGgiLCJhbGlhcyIsInNvdXJjZSIsInN1YnF1ZXJ5QnVpbGRlciIsInJhd1F1ZXJ5IiwiYXMiLCJ0YWJsZU5hbWUiLCJnZXRUYWJsZVNwZWMiLCJjb3VudCIsImNvbHVtbiIsIl90eXBlIiwiX3JldHVybiIsIl9zcWwiLCJfcGFyYW1zIiwic3VtIiwiYXZnIiwibWF4IiwibWluIiwiY29uY2F0IiwiYXJncyIsIm1hcCIsImpvaW4iLCJ1cHBlciIsImxvd2VyIiwid29yZFNpbWlsYXJpdHkiLCJxdWVyeSIsInNpbWlsYXJpdHkiLCJzdHJpY3RXb3JkU2ltaWxhcml0eSIsInJhd1N0cmluZyIsInNxbCIsInBhcmFtcyIsInJhd1N0cmluZ0FycmF5IiwicmF3TnVtYmVyIiwicmF3Qm9vbGVhbiIsInJhd0RhdGUiLCJ0c0hpZ2hsaWdodCIsIl9vcHRpb25zIiwicGFyc2VyIiwiY29uZmlnIiwib3B0aW9ucyIsImhsT3B0aW9uUGFydHMiLCJrZXkiLCJ2YWx1ZSIsImNhbWVsaXplIiwiaGxPcHRpb25zIiwidHNSYW5rIiwiX3RzUmFuayIsInRzUmFua0NkIiwidG9Uc1ZlY3RvciIsInR5cGUiLCJub3JtYWxpemF0aW9uIiwid2VpZ2h0cyIsInNxbFRlbXBsYXRlIiwicHVzaCIsInNjb3JlIiwiaGlnaGxpZ2h0IiwiY29sdW1uT3JDb2x1bW5zIiwicXVlcnlBcnIiLCJBcnJheSIsImlzQXJyYXkiLCJxdWVyeUNsYXVzZSIsInNlbGVjdCIsInNlbGVjdE9iaiIsImZsYXRTZWxlY3QiLCJmbGF0dGVuU2VsZWN0Iiwic2VsZWN0Q2xhdXNlcyIsImNvbHVtbk9yRnVuY3Rpb24iLCJyYXciLCJjb2x1bW5QYXRoIiwicHJlZml4IiwiZnVsbEtleSIsIm5lc3RlZCIsImFzc2lnbiIsImFwcGVuZFNlbGVjdCIsInJlZiIsInNlbGVjdEFsbCIsImRpc3RpbmN0IiwiY29sdW1ucyIsImNsZWFyIiwic3RhdGVtZW50IiwiY2xlYXJKb2luIiwiX3N0YXRlbWVudHMiLCJmaWx0ZXIiLCJzIiwiX2FsaWFzIiwiX3RhYmxlIiwidGFibGUiLCJ0YWJsZU5hbWVPclNwZWMiLCJfX2NvbW1vbkpvaW4iLCJsZWZ0Sm9pbiIsImpvaW5UeXBlIiwiY2FsbGJhY2siLCJqb2luQ2xhdXNlIiwiSm9pbkNsYXVzZUdyb3VwIiwibGVmdCIsInJpZ2h0Iiwic3BlYyIsIndoZXJlIiwiY29sdW1uT3JDb25kaXRpb25zIiwib3BlcmF0b3JPclZhbHVlIiwid2hlcmVOdWxsIiwid2hlcmVOb3ROdWxsIiwid2hlcmVJbiIsInZhbHVlcyIsIndoZXJlTm90SW4iLCJ3aGVyZU1hdGNoIiwid2hlcmVSYXciLCJTdHJpbmciLCJ3aGVyZVNlYXJjaCIsImNvbHVtbkV4cHIiLCJjIiwicGdyb29uZ2FDb25kaXRpb24iLCJ3aGVyZVRzU2VhcmNoIiwib3B0cyIsIndoZXJlRnV6enkiLCJiaW5kaW5ncyIsIndoZXJlR3JvdXAiLCJidWlsZGVyIiwiZ3JvdXAiLCJXaGVyZUdyb3VwIiwib3JXaGVyZUdyb3VwIiwib3JXaGVyZSIsIm9yZGVyQnkiLCJkaXJlY3Rpb24iLCJvcmRlckJ5UmF3IiwidmVjdG9yU2ltaWxhcml0eSIsImVtYmVkZGluZyIsIm1ldGhvZCIsInRocmVzaG9sZCIsImRpc3RpbmN0T24iLCJzb21lIiwidiIsIk51bWJlciIsImlzRmluaXRlIiwidmVjdG9yTGl0ZXJhbCIsIkpTT04iLCJzdHJpbmdpZnkiLCJjb3NpbmUiLCJsMiIsImlubmVyX3Byb2R1Y3QiLCJzaW1pbGFyaXR5RXhwciIsImV4aXN0aW5nU3Vic2V0Q29scyIsImdyb3VwaW5nIiwiZmxhdE1hcCIsImNvbCIsInRocmVzaG9sZE9wIiwidGhyZXNob2xkVmFsdWUiLCJsaW1pdCIsIm9mZnNldCIsImdyb3VwQnkiLCJoYXZpbmciLCJjb25kaXRpb25zIiwidGhlbiIsIm9uZnVsZmlsbGVkIiwib25yZWplY3RlZCIsInQiLCJ0b1F1ZXJ5IiwiY2F0Y2giLCJmaW5hbGx5Iiwib25maW5hbGx5IiwiZmlyc3QiLCJSZXNvbHZlZFB1cmkiLCJwbHVjayIsImluc2VydCIsInJhd0RhdGEiLCJyZWZpbmVkRGF0YSIsInJlZmluZUpzb25Db2x1bW5zIiwidXBkYXRlIiwiZGF0YSIsImpzb25Db2x1bW5zIiwiaXRlbSIsInVuZGVmaW5lZCIsImluY3JlbWVudCIsImRlY3JlbWVudCIsImRlbGV0ZSIsImRlYnVnIiwiY29uc29sZSIsImxvZyIsImN5YW4iLCJ5ZWxsb3ciLCJjbG9uZSIsIm5ld1B1cmkiLCJmb3JtYXRTUUwiLCJ1bmZvcm1hdHRlZCIsImtleXdvcmRzIiwiZm9ybWF0dGVkIiwiZm9yRWFjaCIsImtleXdvcmQiLCJyZWdleCIsIlJlZ0V4cCIsInJlcGxhY2UiLCJ0b1VwcGVyQ2FzZSIsIm1ham9yQ2xhdXNlcyIsImNsYXVzZSIsImxpbmVzIiwic3BsaXQiLCJpbmRlbnRlZExpbmVzIiwiaW5kZW50TGV2ZWwiLCJsaW5lIiwidHJpbW1lZExpbmUiLCJjbG9zaW5nUGFyZW5zIiwibWF0Y2giLCJvcGVuaW5nUGFyZW5zIiwiTWF0aCIsImluZGVudCIsInJlcGVhdCIsInNsaWNlIiwib3JXaGVyZUluIiwib3JXaGVyZU5vdEluIiwib3JXaGVyZU1hdGNoIiwib3JXaGVyZVJhdyIsIm9yV2hlcmVTZWFyY2giLCJvcldoZXJlVHNTZWFyY2giLCJvcldoZXJlRnV6enkiLCJzdWJCdWlsZGVyIiwic3ViR3JvdXAiLCJvbiIsIm9yT24iLCJvblZhbCIsImFuZE9uVmFsIiwib3JPblZhbCIsIlN5bWJvbCIsInRvU3RyaW5nVGFnIiwib25Db25mbGljdCIsImFjdGlvbiIsInRhcmdldCIsImln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
|
|
1022
|
+
//#endregion
|
|
1023
|
+
init_puri();
|
|
1024
|
+
export { JoinClauseGroup, Puri, ResolvedPuri, WhereGroup, init_puri };
|
|
1025
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVyaS5qcyIsIm5hbWVzIjpbImtuZXg6IEtuZXgiLCJzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10iLCJmbGF0U2VsZWN0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+IiwiYnVpbGRlcjogS25leC5RdWVyeUJ1aWxkZXIiLCJjYWxsYmFjazogS25leC5Kb2luQ2xhdXNlIiwia25leFF1ZXJ5OiBLbmV4LlF1ZXJ5QnVpbGRlciIsIm1lcmdlT2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RhdGFiYXNlL3B1cmkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogb3hsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLyAvLyBQdXJp64qUIOuLpOyWke2VnCDtg4DsnoXsnYQg7IKs7Jqp7ZWY6rOgIOyeiOyKteuLiOuLpC5cblxuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5cbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCBpbmZsZWN0aW9uIGZyb20gXCJpbmZsZWN0aW9uXCI7XG5pbXBvcnQgeyB0eXBlIEtuZXggfSBmcm9tIFwia25leFwiO1xuXG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgdHlwZSBUYWJsZVNwZWMgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBOYWl0ZSB9IGZyb20gXCIuLi9uYWl0ZS9uYWl0ZVwiO1xuaW1wb3J0IHsgdHlwZSBDbGVhclN0YXRlbWVudHMgfSBmcm9tIFwiLi9wdXJpLXN1YnNldC50eXBlc1wiO1xuaW1wb3J0IHtcbiAgdHlwZSBBdmFpbGFibGVDb2x1bW5zLFxuICB0eXBlIENvbHVtbktleXMsXG4gIHR5cGUgQ29tcGFyaXNvbk9wZXJhdG9yLFxuICB0eXBlIEV4cGFuZCxcbiAgdHlwZSBFeHRyYWN0Q29sdW1uVHlwZSxcbiAgdHlwZSBGdWxsdGV4dENvbHVtbnMsXG4gIHR5cGUgRnV6enlPcGVyYXRvcixcbiAgdHlwZSBJbnNlcnREYXRhLFxuICB0eXBlIEluc2VydFJlc3VsdCxcbiAgdHlwZSBMZWZ0Sm9pbmVkTWFya2VyLFxuICB0eXBlIExlZnRKb2luTWFya2VyRm9yLFxuICB0eXBlIE51bWVyaWNDb2x1bW5zLFxuICB0eXBlIE9uQ29uZmxpY3RBY3Rpb24sXG4gIHR5cGUgUGFyc2VTZWxlY3RPYmplY3QsXG4gIHR5cGUgUmVzdWx0QXZhaWxhYmxlQ29sdW1ucyxcbiAgdHlwZSBTZWxlY3RBbGxSZXN1bHQsXG4gIHR5cGUgU2VsZWN0T2JqZWN0LFxuICB0eXBlIFNpbmdsZVRhYmxlVmFsdWUsXG4gIHR5cGUgU3FsRXhwcmVzc2lvbixcbiAgdHlwZSBUc0hpZ2hsaWdodE9wdGlvbnMsXG4gIHR5cGUgVHNRdWVyeUNvbmZpZyxcbiAgdHlwZSBUc1F1ZXJ5T3B0aW9ucyxcbiAgdHlwZSBUc1JhbmtPcHRpb25zLFxuICB0eXBlIFZlY3RvckNvbHVtbnMsXG4gIHR5cGUgV2hlcmVDb25kaXRpb24sXG4gIHR5cGUgV2hlcmVPcGVyYXRvcixcbn0gZnJvbSBcIi4vcHVyaS50eXBlc1wiO1xuaW1wb3J0IHsgRlVaWllfT1BFUkFUT1JTIH0gZnJvbSBcIi4vcHVyaS50eXBlc1wiO1xuXG5mdW5jdGlvbiBub3JtYWxpemVGdXp6eU9wZXJhdG9yKG9wZXJhdG9yPzogc3RyaW5nKTogRnV6enlPcGVyYXRvciB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBvcGVyYXRvcj8udHJpbSgpID8/IFwiPCVcIjtcbiAgY29uc3QgZnV6enlPcGVyYXRvciA9IEZVWlpZX09QRVJBVE9SUy5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZSA9PT0gbm9ybWFsaXplZCk7XG5cbiAgaWYgKCFmdXp6eU9wZXJhdG9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGZ1enp5IG9wZXJhdG9yOiAke29wZXJhdG9yID8/IFwiXCJ9YCk7XG4gIH1cblxuICByZXR1cm4gZnV6enlPcGVyYXRvcjtcbn1cblxuZXhwb3J0IGNsYXNzIFB1cmk8VFNjaGVtYSwgVFRhYmxlcyBleHRlbmRzIFJlY29yZDxzdHJpbmcsIGFueT4sIFRSZXN1bHQ+IHtcbiAgcHJpdmF0ZSBrbmV4UXVlcnk6IEtuZXguUXVlcnlCdWlsZGVyO1xuICBwcml2YXRlIHRhYmxlU3BlYzogVGFibGVTcGVjIHwgbnVsbCA9IG51bGw7XG5cbiAgLy8g7IOd7ISx7J6QIOyLnOq3uOuLiOyymOuTpFxuICBjb25zdHJ1Y3RvcihrbmV4OiBLbmV4LCB0YWJsZU5hbWU6IHN0cmluZyk7XG4gIGNvbnN0cnVjdG9yKGtuZXg6IEtuZXgsIHRhYmxlU291cmNlOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBQdXJpPFRTY2hlbWEsIGFueSwgYW55Pj4pO1xuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMga25leDogS25leCxcbiAgICB0YWJsZU5hbWVPclNvdXJjZTogYW55LFxuICApIHtcbiAgICBpZiAodHlwZW9mIHRhYmxlTmFtZU9yU291cmNlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAvLyBDYXNlOiBuZXcgUHVyaShrbmV4LCBcInVzZXJzXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leCh0YWJsZU5hbWVPclNvdXJjZSkuZnJvbSh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgICB0aGlzLnRhYmxlU3BlYyA9IHRoaXMuc2FmZUdldFRhYmxlU3BlYyh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTb3VyY2UgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgICBpZiAoZW50cmllcy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGFibGUgc3BlYyBtdXN0IGhhdmUgZXhhY3RseSBvbmUgZW50cnlcIik7XG4gICAgICB9XG4gICAgICBhc3NlcnQoZW50cmllc1swXSk7XG4gICAgICBjb25zdCBbYWxpYXMsIHNvdXJjZV0gPSBlbnRyaWVzWzBdO1xuICAgICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkgPSB0aGlzLmtuZXgoc291cmNlKS5mcm9tKHsgW2FsaWFzXTogc291cmNlIH0pO1xuICAgICAgICB0aGlzLnRhYmxlU3BlYyA9IHRoaXMuc2FmZUdldFRhYmxlU3BlYyhzb3VyY2UpO1xuICAgICAgfSBlbHNlIGlmIChzb3VyY2UgaW5zdGFuY2VvZiBQdXJpKSB7XG4gICAgICAgIGNvbnN0IHN1YnF1ZXJ5QnVpbGRlciA9IHNvdXJjZS5yYXdRdWVyeSgpO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leC5mcm9tKHN1YnF1ZXJ5QnVpbGRlci5hcyhhbGlhcykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCB0YWJsZSBzcGVjaWZpY2F0aW9uXCIpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgfVxuICB9XG5cbiAgc2FmZUdldFRhYmxlU3BlYyh0YWJsZU5hbWU6IHN0cmluZyk6IFRhYmxlU3BlYyB8IG51bGwge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gRW50aXR5TWFuYWdlci5nZXRUYWJsZVNwZWModGFibGVOYW1lKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIFN0YXRpYyBTUUwgaGVscGVyIGZ1bmN0aW9ucyBmb3IgU0VMRUNUXG4gIHN0YXRpYyBjb3VudChjb2x1bW46IHN0cmluZyA9IFwiKlwiKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYENPVU5UKD8/KTo6aW50ZWdlcmAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBzdW0oY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgU1VNKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBhdmcoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgQVZHKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBtYXgoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgTUFYKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBtaW4oY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgTUlOKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBjb25jYXQoLi4uYXJnczogc3RyaW5nW10pOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBgQ09OQ0FUKCR7YXJncy5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX0pYCxcbiAgICAgIF9wYXJhbXM6IGFyZ3MsXG4gICAgfTtcbiAgfVxuICBzdGF0aWMgdXBwZXIoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBcIlVQUEVSKD8/KVwiLFxuICAgICAgX3BhcmFtczogW2NvbHVtbl0sXG4gICAgfTtcbiAgfVxuICBzdGF0aWMgbG93ZXIoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBcIkxPV0VSKD8/KVwiLFxuICAgICAgX3BhcmFtczogW2NvbHVtbl0sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyB3b3JkU2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IFwid29yZF9zaW1pbGFyaXR5KD8sID8/KVwiLFxuICAgICAgICBfcGFyYW1zOiBbcXVlcnksIGNvbHVtbl0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGB3b3JkX3NpbWlsYXJpdHkoPywgJHtjb2x1bW4uX3NxbH0pYCxcbiAgICAgIF9wYXJhbXM6IFtxdWVyeSwgLi4uY29sdW1uLl9wYXJhbXNdLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgc2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IFwic2ltaWxhcml0eSg/PywgPylcIixcbiAgICAgICAgX3BhcmFtczogW2NvbHVtbiwgcXVlcnldLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgc2ltaWxhcml0eSgke2NvbHVtbi5fc3FsfSwgPylgLFxuICAgICAgX3BhcmFtczogWy4uLmNvbHVtbi5fcGFyYW1zLCBxdWVyeV0sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyBzdHJpY3RXb3JkU2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IGBzdHJpY3Rfd29yZF9zaW1pbGFyaXR5KD8sID8/KWAsXG4gICAgICAgIF9wYXJhbXM6IFtxdWVyeSwgY29sdW1uXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYHN0cmljdF93b3JkX3NpbWlsYXJpdHkoPywgJHtjb2x1bW4uX3NxbH0pYCxcbiAgICAgIF9wYXJhbXM6IFtxdWVyeSwgLi4uY29sdW1uLl9wYXJhbXNdLFxuICAgIH07XG4gIH1cblxuICAvLyBSYXcgZnVuY3Rpb25zIGZvciBTRUxFQ1RcbiAgc3RhdGljIHJhd1N0cmluZyhzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwic3RyaW5nXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3U3RyaW5nQXJyYXkoc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nW11cIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwic3RyaW5nW11cIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdOdW1iZXIoc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcIm51bWJlclwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgc3RhdGljIHJhd0Jvb2xlYW4oc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwiYm9vbGVhblwiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJib29sZWFuXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3RGF0ZShzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJkYXRlXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcImRhdGVcIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGVFMg6rKA7IOJ7Ja0IO2VmOydtOudvOydtO2MhVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICB0aXRsZTogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy50aXRsZVwiLCBzZWFyY2gpLFxuICAgKiAgIGNvbnRlbnQ6IFB1cmkuaGlnaGxpZ2h0KFwicG9zdHMuY29udGVudFwiLCBzZWFyY2gsIHtcbiAgICogICAgIHN0YXJ0U2VsOiBcIjxtYXJrPlwiLFxuICAgKiAgICAgc3RvcFNlbDogXCI8L21hcms+XCIsXG4gICAqICAgICBtYXhGcmFnbWVudHM6IDMsXG4gICAqICAgfSksXG4gICAqIH0pXG4gICAqL1xuICBzdGF0aWMgdHNIaWdobGlnaHQoXG4gICAgY29sdW1uOiBzdHJpbmcsXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBfb3B0aW9ucz86IFRzSGlnaGxpZ2h0T3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPiB7XG4gICAgY29uc3QgeyBwYXJzZXIgPSBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCIsIGNvbmZpZyA9IFwic2ltcGxlXCIsIC4uLm9wdGlvbnMgfSA9IF9vcHRpb25zID8/IHt9O1xuXG4gICAgY29uc3QgaGxPcHRpb25QYXJ0cyA9IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICByZXR1cm4gYCR7aW5mbGVjdGlvbi5jYW1lbGl6ZShrZXkpfT0ke3ZhbHVlfWA7XG4gICAgfSk7XG5cbiAgICBjb25zdCBobE9wdGlvbnMgPSBobE9wdGlvblBhcnRzLmxlbmd0aCA+IDAgPyBgLCAnJHtobE9wdGlvblBhcnRzLmpvaW4oXCIsIFwiKX0nYCA6IFwiXCI7XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBgdHNfaGVhZGxpbmUoPywgPz8sICR7cGFyc2VyfSg/LCA/KSR7aGxPcHRpb25zfSlgLFxuICAgICAgX3BhcmFtczogW2NvbmZpZywgY29sdW1uLCBjb25maWcsIHF1ZXJ5XSxcbiAgICB9O1xuICB9XG5cbiAgLy8gdHNfcmFua1xuICBzdGF0aWMgdHNSYW5rKFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+LFxuICAgIHF1ZXJ5OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUmFua09wdGlvbnMsXG4gICk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiBQdXJpLl90c1JhbmsoXCJ0c19yYW5rXCIsIGNvbHVtbiwgcXVlcnksIG9wdGlvbnMpO1xuICB9XG5cbiAgLy8gdHNfcmFua19jZFxuICBzdGF0aWMgdHNSYW5rQ2QoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNSYW5rT3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIFB1cmkuX3RzUmFuayhcInRzX3JhbmtfY2RcIiwgY29sdW1uLCBxdWVyeSwgb3B0aW9ucyk7XG4gIH1cblxuICBzdGF0aWMgdG9Uc1ZlY3Rvcihjb2x1bW46IHN0cmluZywgY29uZmlnOiBzdHJpbmcgPSBcInNpbXBsZVwiKTogU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwidHN2ZWN0b3JcIixcbiAgICAgIF9zcWw6IGB0b190c3ZlY3Rvcig/LCA/PylgLFxuICAgICAgX3BhcmFtczogW2NvbmZpZywgY29sdW1uXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIF90c1JhbmsoXG4gICAgdHlwZTogXCJ0c19yYW5rXCIgfCBcInRzX3JhbmtfY2RcIixcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJ0c3ZlY3RvclwiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1JhbmtPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBjb25zdCB7XG4gICAgICBwYXJzZXIgPSBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCIsXG4gICAgICBjb25maWcgPSBcInNpbXBsZVwiLFxuICAgICAgbm9ybWFsaXphdGlvbixcbiAgICAgIHdlaWdodHMsXG4gICAgfSA9IG9wdGlvbnMgPz8ge307XG5cbiAgICBjb25zdCBwYXJhbXMgPSBbXTtcbiAgICBsZXQgc3FsVGVtcGxhdGUgPSBgJHt0eXBlfShgO1xuXG4gICAgaWYgKHdlaWdodHMpIHtcbiAgICAgIHNxbFRlbXBsYXRlICs9IGBBUlJBWVske3dlaWdodHMubWFwKCgpID0+IFwiP1wiKS5qb2luKFwiLCBcIil9XTo6ZmxvYXQ0W10sIGA7XG4gICAgICBwYXJhbXMucHVzaCguLi53ZWlnaHRzKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYD8/LCAke3BhcnNlcn0oPywgPylgO1xuICAgICAgcGFyYW1zLnB1c2goY29sdW1uLCBjb25maWcsIHF1ZXJ5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYCR7Y29sdW1uLl9zcWx9LCAke3BhcnNlcn0oPywgPylgO1xuICAgICAgcGFyYW1zLnB1c2goLi4uY29sdW1uLl9wYXJhbXMsIGNvbmZpZywgcXVlcnkpO1xuICAgIH1cblxuICAgIGlmIChub3JtYWxpemF0aW9uKSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBcIiwgP1wiO1xuICAgICAgcGFyYW1zLnB1c2gobm9ybWFsaXphdGlvbik7XG4gICAgfVxuXG4gICAgc3FsVGVtcGxhdGUgKz0gXCIpXCI7XG5cbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcIm51bWJlclwiLCBfc3FsOiBzcWxUZW1wbGF0ZSwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiSDsoJDsiJhcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogLnNlbGVjdCh7XG4gICAqICAgc2NvcmU6IFB1cmkuc2NvcmUoKSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyBzY29yZSgpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4gUHVyaS5yYXdOdW1iZXIoXCJwZ3Jvb25nYV9zY29yZSh0YWJsZW9pZCwgY3RpZClcIik7XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiSDtlZjsnbTrnbzsnbTtjIVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogLnNlbGVjdCh7XG4gICAqICAgdGl0bGU6IFB1cmkuaGlnaGxpZ2h0KFwicG9zdHMudGl0bGVcIiwgc2VhcmNoKSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyBoaWdobGlnaHQoY29sdW1uOiBzdHJpbmcsIHF1ZXJ5OiBzdHJpbmcgfCBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj47XG4gIHN0YXRpYyBoaWdobGlnaHQoY29sdW1uczogc3RyaW5nW10sIHF1ZXJ5OiBzdHJpbmcgfCBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdbXVwiPjtcblxuICBzdGF0aWMgaGlnaGxpZ2h0KFxuICAgIGNvbHVtbk9yQ29sdW1uczogc3RyaW5nIHwgc3RyaW5nW10sXG4gICAgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdLFxuICApOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1tdXCI+IHtcbiAgICBjb25zdCBxdWVyeUFyciA9IEFycmF5LmlzQXJyYXkocXVlcnkpID8gcXVlcnkgOiBbcXVlcnldO1xuICAgIGNvbnN0IHF1ZXJ5Q2xhdXNlID0gYEFSUkFZWyR7cXVlcnlBcnIubWFwKCgpID0+IFwiP1wiKS5qb2luKFwiLCBcIil9XWA7XG5cbiAgICAvLyDri6jsnbwg7Lus65+87J24IOqyveyasFxuICAgIGlmICh0eXBlb2YgY29sdW1uT3JDb2x1bW5zID09PSBcInN0cmluZ1wiKSB7XG4gICAgICByZXR1cm4gUHVyaS5yYXdTdHJpbmcoYHBncm9vbmdhX2hpZ2hsaWdodF9odG1sKD8/LCAke3F1ZXJ5Q2xhdXNlfSlgLCBbXG4gICAgICAgIGNvbHVtbk9yQ29sdW1ucyxcbiAgICAgICAgLi4ucXVlcnlBcnIsXG4gICAgICBdKTtcbiAgICB9XG5cbiAgICAvLyDsu6zrn7wg67Cw7Je07J24IOqyveyasFxuICAgIHJldHVybiBQdXJpLnJhd1N0cmluZ0FycmF5KFxuICAgICAgYHBncm9vbmdhX2hpZ2hsaWdodF9odG1sKEFSUkFZWyR7Y29sdW1uT3JDb2x1bW5zLm1hcCgoKSA9PiBcIj8/XCIpLmpvaW4oXCIsIFwiKX1dLCAke3F1ZXJ5Q2xhdXNlfSlgLFxuICAgICAgWy4uLmNvbHVtbk9yQ29sdW1ucywgLi4ucXVlcnlBcnJdLFxuICAgICk7XG4gIH1cblxuICAvLyBTRUxFQ1QgKG92ZXJ3cml0ZSlcbiAgc2VsZWN0PFRTZWxlY3QgZXh0ZW5kcyBTZWxlY3RPYmplY3Q8VFRhYmxlcz4+KFxuICAgIHNlbGVjdE9iajogVFNlbGVjdCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBQYXJzZVNlbGVjdE9iamVjdDxUVGFibGVzLCBUU2VsZWN0Pj4ge1xuICAgIC8vIOykkeyyqSDqsJ3ssrTrpbwgZmxhdO2VmOqyjCDrs4DtmZhcbiAgICBjb25zdCBmbGF0U2VsZWN0ID0gdGhpcy5mbGF0dGVuU2VsZWN0KHNlbGVjdE9iaik7XG5cbiAgICBjb25zdCBzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2FsaWFzLCBjb2x1bW5PckZ1bmN0aW9uXSBvZiBPYmplY3QuZW50cmllcyhmbGF0U2VsZWN0KSkge1xuICAgICAgaWYgKHR5cGVvZiBjb2x1bW5PckZ1bmN0aW9uID09PSBcIm9iamVjdFwiICYmIGNvbHVtbk9yRnVuY3Rpb24uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIikge1xuICAgICAgICAvLyBTUUwg7ZWo7IiY7J24IOqyveyasFxuICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goXG4gICAgICAgICAgdGhpcy5rbmV4LnJhdyhgJHtjb2x1bW5PckZ1bmN0aW9uLl9zcWx9IEFTIFwiJHthbGlhc31cImAsIGNvbHVtbk9yRnVuY3Rpb24uX3BhcmFtcyksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyDsnbzrsJgg7Lus65+87J24IOqyveyasFxuICAgICAgICBjb25zdCBjb2x1bW5QYXRoID0gY29sdW1uT3JGdW5jdGlvbiBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChhbGlhcyA9PT0gY29sdW1uUGF0aCkge1xuICAgICAgICAgIC8vIGFsaWFz7JmAIOy7rOufvOuqheydtCDqsJnsnLzrqbQgYWxpYXMg7IOd6561XG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGNvbHVtblBhdGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGFsaWFzIOyngOyglVxuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChgJHtjb2x1bW5QYXRofSBBUyAke2FsaWFzfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNlbGVjdENsYXVzZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiDspJHssqkg6rCd7LK066W8IGZsYXQg6rCd7LK066GcIOuzgO2ZmFxuICAgKiDsmIg6IHsgcGFyZW50OiB7IGlkOiBcInBhcmVudC5pZFwiLCBuYW1lOiBcInBhcmVudC5uYW1lXCIgfSB9XG4gICAqICAg4oaSIHsgcGFyZW50X19pZDogXCJwYXJlbnQuaWRcIiwgcGFyZW50X19uYW1lOiBcInBhcmVudC5uYW1lXCIgfVxuICAgKi9cbiAgcHJpdmF0ZSBmbGF0dGVuU2VsZWN0KHNlbGVjdE9iajogUmVjb3JkPHN0cmluZywgYW55PiwgcHJlZml4ID0gXCJcIik6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGNvbnN0IGZsYXRTZWxlY3Q6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNlbGVjdE9iaikpIHtcbiAgICAgIGNvbnN0IGZ1bGxLZXkgPSBwcmVmaXggPyBgJHtwcmVmaXh9X18ke2tleX1gIDoga2V5O1xuXG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmIHZhbHVlICE9PSBudWxsICYmICEoXCJfdHlwZVwiIGluIHZhbHVlKSkge1xuICAgICAgICAvLyDspJHssqkg6rCd7LK07J24IOqyveyasCAtIOyerOq3gCDsspjrpqxcbiAgICAgICAgY29uc3QgbmVzdGVkID0gdGhpcy5mbGF0dGVuU2VsZWN0KHZhbHVlLCBmdWxsS2V5KTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihmbGF0U2VsZWN0LCBuZXN0ZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8g7J2867CYIOqwkuyduCDqsr3smrAgKOy7rOufvCDqsr3roZwg65iQ64qUIFNxbEV4cHJlc3Npb24pXG4gICAgICAgIGZsYXRTZWxlY3RbZnVsbEtleV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmxhdFNlbGVjdDtcbiAgfVxuXG4gIC8vIFNFTEVDVCAoc2VsZWN064qUIG92ZXJ3cml0ZSwgYXBwZW5kU2VsZWN064qUIGFwcGVuZClcbiAgYXBwZW5kU2VsZWN0PFRTZWxlY3QgZXh0ZW5kcyBTZWxlY3RPYmplY3Q8VFRhYmxlcz4+KFxuICAgIHNlbGVjdE9iajogVFNlbGVjdCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0ICYgUGFyc2VTZWxlY3RPYmplY3Q8VFRhYmxlcywgVFNlbGVjdD4+IHtcbiAgICAvLyDspJHssqkg6rCd7LK066W8IGZsYXTtlZjqsowg67OA7ZmYXG4gICAgY29uc3QgZmxhdFNlbGVjdCA9IHRoaXMuZmxhdHRlblNlbGVjdChzZWxlY3RPYmopO1xuXG4gICAgY29uc3Qgc2VsZWN0Q2xhdXNlczogKHN0cmluZyB8IEtuZXguUmF3KVtdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IFthbGlhcywgY29sdW1uT3JGdW5jdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZmxhdFNlbGVjdCkpIHtcbiAgICAgIGlmICh0eXBlb2YgY29sdW1uT3JGdW5jdGlvbiA9PT0gXCJvYmplY3RcIiAmJiBjb2x1bW5PckZ1bmN0aW9uLl90eXBlID09PSBcInNxbF9leHByZXNzaW9uXCIpIHtcbiAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKFxuICAgICAgICAgIHRoaXMua25leC5yYXcoYCR7Y29sdW1uT3JGdW5jdGlvbi5fc3FsfSBBUyAke2FsaWFzfWAsIGNvbHVtbk9yRnVuY3Rpb24uX3BhcmFtcyksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBjb2x1bW5QYXRoID0gY29sdW1uT3JGdW5jdGlvbiBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChhbGlhcyA9PT0gY29sdW1uUGF0aCkge1xuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChjb2x1bW5QYXRoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2godGhpcy5rbmV4LnJlZihjb2x1bW5QYXRoKS5hcyhhbGlhcykpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNlbGVjdENsYXVzZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIFNFTEVDVCAqXG4gIHNlbGVjdEFsbCgpOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFNlbGVjdEFsbFJlc3VsdDxUVGFibGVzPj4ge1xuICAgIHRoaXMua25leFF1ZXJ5LnNlbGVjdChcIipcIik7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gRElTVElOQ1RcbiAgZGlzdGluY3Q8VENvbHVtbnMgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PiguLi5jb2x1bW5zOiBUQ29sdW1uc1tdKTogdGhpcztcbiAgZGlzdGluY3QoLi4uY29sdW1uczogc3RyaW5nW10pOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kaXN0aW5jdCguLi5jb2x1bW5zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIENMRUFSXG4gIGNsZWFyKHN0YXRlbWVudDogQ2xlYXJTdGF0ZW1lbnRzKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoc3RhdGVtZW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGtuZXjsl5Ag7JeG7Ja07IScIOyngeygkSDqtaztmITtlahcbiAgY2xlYXJKb2luKGFsaWFzOiBzdHJpbmcpOiB0aGlzIHtcbiAgICAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50cyA9ICh0aGlzLmtuZXhRdWVyeSBhcyBhbnkpLl9zdGF0ZW1lbnRzLmZpbHRlcigoczogYW55KSA9PiB7XG4gICAgICBpZiAoXCJqb2luVHlwZVwiIGluIHMpIHtcbiAgICAgICAgY29uc3QgW19hbGlhcywgX3RhYmxlXSA9IE9iamVjdC5lbnRyaWVzKHMudGFibGUpWzBdO1xuICAgICAgICByZXR1cm4gX2FsaWFzICE9PSBhbGlhcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gSk9JTjog7ISc67iM7L+866asICsgQWxpYXNcbiAgam9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU3ViUmVzdWx0Pn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0PiwgLy8g7ISc67iM7L+866as7J2YIFRSZXN1bHRcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIEpPSU46IO2FjOydtOu4lCArIEFsaWFzXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgLy8gVFRhYmxlcyDtmZXsnqUhXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBKT0lOOiDthYzsnbTruJTrqoVcbiAgam9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luVGFibGUgJiBzdHJpbmd9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgLy8g7YWM7J2067iU66qF7J20IO2CpFxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gSk9JTjog7ISc67iM7L+866asICsgQWxpYXMgKyDsvZzrsLFcbiAgam9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0Pj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0PiwgVFJlc3VsdD47XG4gIC8vIEpPSU46IO2FjOydtOu4lCArIEFsaWFzICsg7L2c67CxXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgVFJlc3VsdD47XG4gIC8vIEpPSU46IO2FjOydtOu4lOuqhSArIOy9nOuwsVxuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hPihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+LCBUUmVzdWx0PjtcbiAgLy8gSk9JTiDsi6TsoJwg6rWs7ZiEXG4gIGpvaW4odGFibGVOYW1lT3JTcGVjOiBhbnksIC4uLmFyZ3M6IGFueVtdKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5fX2NvbW1vbkpvaW4oXCJqb2luXCIsIHRhYmxlTmFtZU9yU3BlYywgLi4uYXJncyk7XG4gIH1cblxuICAvLyBMRUZUIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzXG4gIGxlZnRKb2luPFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsIFRTdWJSZXN1bHQ+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogUHVyaTxUU2NoZW1hLCBhbnksIFRTdWJSZXN1bHQ+IH0sXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPixcbiAgICByaWdodDogYCR7VEpvaW5BbGlhc30uJHtDb2x1bW5LZXlzPFRTdWJSZXN1bHQ+fWAsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0ICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+OyAvLyDshJzruIzsv7zrpqzsnZggVFJlc3VsdFxuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lCArIEFsaWFzXG4gIC8vIEZLIG51bGxhYmxlIOyXrOu2gOyXkCDrlLDrnbwg7J6Q64+Z7Jy866GcIExlZnRKb2luZWRNYXJrZXIg6rKw7KCVXG4gIGxlZnRKb2luPFxuICAgIFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLFxuICAgIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsXG4gICAgVExlZnQgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICA+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGxlZnQ6IFRMZWZ0LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXSAmIExlZnRKb2luTWFya2VyRm9yPFRUYWJsZXMsIFRMZWZ0Pj4sXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lOuqhVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSwgVExlZnQgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgbGVmdDogVExlZnQsXG4gICAgcmlnaHQ6IGAke1RKb2luVGFibGUgJiBzdHJpbmd9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5NYXJrZXJGb3I8VFRhYmxlcywgVExlZnQ+PixcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIExFRlQgSk9JTjog7ISc67iM7L+866asICsgQWxpYXMgKyDsvZzrsLFcbiAgbGVmdEpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdCAmIExlZnRKb2luZWRNYXJrZXI+LCBUUmVzdWx0PjtcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJQgKyBBbGlhcyArIOy9nOuwsVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSwgVEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZz4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBUSm9pblRhYmxlIH0sXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTjog7YWM7J2067iU66qFICsg7L2c67CxXG4gIGxlZnRKb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hPihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTiDsi6TsoJwg6rWs7ZiEXG4gIGxlZnRKb2luKHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX19jb21tb25Kb2luKFwibGVmdEpvaW5cIiwgdGFibGVOYW1lT3JTcGVjLCAuLi5hcmdzKTtcbiAgfVxuXG4gIF9fY29tbW9uSm9pbihqb2luVHlwZTogXCJqb2luXCIgfCBcImxlZnRKb2luXCIsIHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTcGVjID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAvLyBDYXNlIDE6IGpvaW4oXCJwb3N0c1wiLCAuLi4pXG4gICAgICBjb25zdCB0YWJsZU5hbWUgPSB0YWJsZU5hbWVPclNwZWM7XG5cbiAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIC8vIGpvaW4oXCJwb3N0c1wiLCBjYWxsYmFjaylcbiAgICAgICAgY29uc3QgY2FsbGJhY2sgPSBhcmdzWzBdO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0odGFibGVOYW1lLCAoam9pbkNsYXVzZSkgPT4ge1xuICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGpvaW4oXCJwb3N0c1wiLCBsZWZ0LCByaWdodClcbiAgICAgICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGFyZ3M7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh0YWJsZU5hbWUsIGxlZnQsIHJpZ2h0KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB0YWJsZU5hbWVPclNwZWMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIC8vIENhc2UgMjogam9pbih7IGFsaWFzOiBcInRhYmxlXCIgfSwgLi4uKSBvciBqb2luKHsgYWxpYXM6IHN1YnF1ZXJ5IH0sIC4uLilcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyh0YWJsZU5hbWVPclNwZWMpO1xuICAgICAgaWYgKGVudHJpZXMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRhYmxlIHNwZWMgbXVzdCBoYXZlIGV4YWN0bHkgb25lIGVudHJ5XCIpO1xuICAgICAgfVxuICAgICAgYXNzZXJ0KGVudHJpZXNbMF0pO1xuICAgICAgY29uc3QgW1thbGlhcywgc3BlY11dID0gZW50cmllcztcblxuICAgICAgaWYgKHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIC8vIO2FjOydtOu4lDogam9pbih7IHA6IFwicG9zdHNcIiB9LCAuLi4pXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgLy8gQ2FsbGJhY2tcbiAgICAgICAgICBjb25zdCBjYWxsYmFjayA9IGFyZ3NbMF07XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHsgW2FsaWFzXTogc3BlYyB9LCAoam9pbkNsYXVzZSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2sobmV3IEpvaW5DbGF1c2VHcm91cChqb2luQ2xhdXNlKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU2ltcGxlXG4gICAgICAgICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGFyZ3M7XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHsgW2FsaWFzXTogc3BlYyB9LCBsZWZ0LCByaWdodCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc3BlYyBpbnN0YW5jZW9mIFB1cmkpIHtcbiAgICAgICAgLy8g7ISc67iM7L+866asOiBqb2luKHsgc3E6IHN1YnF1ZXJ5IH0sIC4uLilcbiAgICAgICAgaWYgKGFyZ3MubGVuZ3RoID09PSAxICYmIHR5cGVvZiBhcmdzWzBdID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAvLyBDYWxsYmFja1xuICAgICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXJnc1swXTtcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0oc3BlYy5yYXdRdWVyeSgpLmFzKGFsaWFzKSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFNpbXBsZVxuICAgICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXShzcGVjLnJhd1F1ZXJ5KCkuYXMoYWxpYXMpLCBsZWZ0LCByaWdodCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGFibGUgc3BlY2lmaWNhdGlvblwiKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBhcmd1bWVudHNcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRTog6rCd7LK0IC0g7IKs7JqpOiAud2hlcmUoeyBcInUuaWRcIjogMSwgXCJ1LnN0YXR1c1wiOiBcImFjdGl2ZVwiIH0pXG4gIHdoZXJlKGNvbmRpdGlvbnM6IFdoZXJlQ29uZGl0aW9uPFRUYWJsZXM+KTogdGhpcztcbiAgLy8gV0hFUkU6IOy7rOufvCAtIOyCrOyaqTogLndoZXJlKFwidS5pZFwiLCAxKSwgLndoZXJlKFwidS5pZFwiLCBudWxsKVxuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gV0hFUkU6IOy7rOufvCAtIOyCrOyaqTogLndoZXJlKFwidS5pZFwiLCBcIj5cIiwgMTApLCAud2hlcmUoXCJ1LmlkXCIsIFwiIT1cIiwgbnVsbClcbiAgd2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIFdIRVJFOiBTUUwg7ZGc7ZiE7IudIC0g7IKs7JqpOiAud2hlcmUocHVyaS5yYXcoXCJDT05DQVQodS5uYW1lLCB1LmVtYWlsKVwiKSwgXCJsaWtlXCIsIFwiJXRlc3QlXCIpXG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBLbmV4LlJhdz4oY29sdW1uOiBUQ29sdW1uLCBvcGVyYXRvcjogV2hlcmVPcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgXCJsaWtlXCIsIFwiJXRlc3QlXCIpXG4gIHdoZXJlKC4uLmFyZ3M6IFtjb2x1bW5PckNvbmRpdGlvbnM6IGFueSwgb3BlcmF0b3JPclZhbHVlPzogYW55LCB2YWx1ZT86IGFueV0pOiB0aGlzIHtcbiAgICBjb25zdCBbY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUsIHZhbHVlXSA9IGFyZ3M7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW5PckNvbmRpdGlvbnMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIGlmIChvcGVyYXRvck9yVmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOdWxsKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBpZiAodmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgaWYgKG9wZXJhdG9yT3JWYWx1ZSA9PT0gXCIhPVwiKSB7XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3ROdWxsKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0gZWxzZSBpZiAob3BlcmF0b3JPclZhbHVlID09PSBcIj1cIikge1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMsIG9wZXJhdG9yT3JWYWx1ZSwgdmFsdWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIElOXG4gIHdoZXJlSW48VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZXM6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlSW4oY29sdW1uLCB2YWx1ZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIFdIRVJFIE5PVCBJTlxuICB3aGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQ+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZU5vdEluKGNvbHVtbiwgdmFsdWVzKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBXSEVSRSBNQVRDSFxuICB3aGVyZU1hdGNoPFRDb2x1bW4gZXh0ZW5kcyBGdWxsdGV4dENvbHVtbnM8VFRhYmxlcz4+KGNvbHVtbjogVENvbHVtbiwgdmFsdWU6IHN0cmluZyk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoY29sdW1uKX0pIEFHQUlOU1QgKD8pYCwgW3ZhbHVlXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiVxuICAgKiAtIOyCrOyaqe2VoCBQR3Jvb25nYSDsnbjrjbHsiqTsmYAg64+Z7J287ZWcIOy7rOufvCDqtazshLHsnLzroZwg6rKA7IOJ7ZW07JW8IOyduOuNseyKpOqwgCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIOuLqOydvCDsu6zrn7wg6rKA7IOJOlxuICAgKiBgYGBzcWxcbiAgICogV0hFUkUgbmFtZSAmQH4gJ3NlYXJjaCdcbiAgICogYGBgXG4gICAqXG4gICAqIOuzte2VqSDsu6zrn7wg6rKA7IOJOlxuICAgKiBgYGBzcWxcbiAgICogV0hFUkUgQVJSQVlbbmFtZTo6dGV4dCwgZGVzY3JpcHRpb246OnRleHRdICZAfiAnc2VhcmNoJ1xuICAgKiBgYGBcbiAgICovXG4gIHdoZXJlU2VhcmNoPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4gfCBUQ29sdW1uW10sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgd2VpZ2h0cz86IG51bWJlcltdOyAvLyDsoJXsiJgg67Cw7Je0XG4gICAgfSxcbiAgKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBvcHRpb25zID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGNvbHVtbilcbiAgICAgID8gYEFSUkFZWyR7Y29sdW1uLm1hcCgoYykgPT4gYCR7Y306OnRleHRgKS5qb2luKFwiLFwiKX1dYFxuICAgICAgOiBjb2x1bW47XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcblxuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFt2YWx1ZV0pO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRSBGVUxMVEVYVFxuICB3aGVyZVRzU2VhcmNoPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUXVlcnlPcHRpb25zIHwgVHNRdWVyeUNvbmZpZyxcbiAgKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogb3B0aW9ucyB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChvcHRpb25zID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGNvbHVtbiA9PT0gXCJvYmplY3RcIiAmJiBjb2x1bW4uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGNvbHVtbi5fc3FsXG4gICAgICAgIDogU3RyaW5nKGNvbHVtbik7XG5cbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW5FeHByfSBAQCAke3BhcnNlcn0oPywgPylgLCBbY29uZmlnLCB2YWx1ZV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKG9wdGlvbnM/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGAke2NvbHVtbi5fc3FsfSAke29wZXJhdG9yfSA/YCwgWy4uLmNvbHVtbi5fcGFyYW1zLCB2YWx1ZV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbY29sdW1uLCB2YWx1ZV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7Y29sdW1uLl9zcWx9YCwgW3ZhbHVlLCAuLi5jb2x1bW4uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPyAke29wZXJhdG9yfSA/P2AsIFt2YWx1ZSwgY29sdW1uXSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgUkFXXG4gIHdoZXJlUmF3KHNxbDogc3RyaW5nLCBiaW5kaW5ncz86IHJlYWRvbmx5IHVua25vd25bXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KHNxbCwgYmluZGluZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUg6rSE7Zi4IOq3uOujue2VkVxuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKChidWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KGJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soZ3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIG9yV2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS5vcldoZXJlKChidWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KGJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soZ3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT1JERVIgQlkgKFNxbEV4cHJlc3Npb27snLzroZzrj4Qg7ZWgIOyImCDsnojslrTslbwg7ZWoKVxuICBvcmRlckJ5PFRDb2x1bW4gZXh0ZW5kcyBSZXN1bHRBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXMsIFRSZXN1bHQ+PihcbiAgICBjb2x1bW46IFRDb2x1bW4gfCBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBkaXJlY3Rpb246IFwiYXNjXCIgfCBcImRlc2NcIixcbiAgKTogdGhpcztcbiAgb3JkZXJCeShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+LFxuICAgIGRpcmVjdGlvbjogXCJhc2NcIiB8IFwiZGVzY1wiID0gXCJhc2NcIixcbiAgKTogdGhpcyB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnlSYXcoYCR7Y29sdW1uLl9zcWx9ICR7ZGlyZWN0aW9ufWAsIGNvbHVtbi5fcGFyYW1zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeShjb2x1bW4sIGRpcmVjdGlvbik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIOuyoe2EsCDsnKDsgqzrj4Qg6rKA7IOJIOyEpOyglVxuICAgKlxuICAgKiAtIFNFTEVDVOyXkCBzaW1pbGFyaXR5IOy7rOufvCDstpTqsIBcbiAgICogLSBXSEVSRSBjb2wgSVMgTk9UIE5VTEwg7LaU6rCAXG4gICAqIC0gdGhyZXNob2xk6rCAIOyeiOycvOuptCBXSEVSRSDsobDqsbQg7LaU6rCAXG4gICAqIC0g6riw7KG0IE9SREVSIEJZ66W8IGNsZWFy7ZWY6rOgIOybkOyLnCDsl7DsgrDsnpDroZwg7KCV66CsIChITlNXIOyduOuNseyKpCDstZzsoIHtmZQpXG4gICAqXG4gICAqIEBwYXJhbSBjb2x1bW4g67Kh7YSwIOy7rOufvCDqsr3roZxcbiAgICogQHBhcmFtIGVtYmVkZGluZyDsv7zrpqwg7J6E67Kg65SpIOuyoe2EsFxuICAgKiBAcGFyYW0gb3B0aW9ucyBtZXRob2QsIHRocmVzaG9sZCwgYXMg65OxIOyYteyFmFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIGNvc2luZSBzaW1pbGFyaXR5ICjquLDrs7jqsJIpXG4gICAqIHFiLnZlY3RvclNpbWlsYXJpdHkoXCJjb2x1bW5OYW1lXCIsIHF1ZXJ5VmVjdG9yLCB7XG4gICAqICAgbWV0aG9kOiBcImNvc2luZVwiLFxuICAgKiAgIHRocmVzaG9sZDogMC41XG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBMMiBkaXN0YW5jZVxuICAgKiBxYi52ZWN0b3JTaW1pbGFyaXR5KFwiY29sdW1uTmFtZVwiLCBxdWVyeVZlY3Rvciwge1xuICAgKiAgIG1ldGhvZDogXCJsMlwiLFxuICAgKiAgIHRocmVzaG9sZDogMS41ICAvLyDqsbDrpqzqsIAgMS41IOydtO2VmOyduCDqsrDqs7zrp4xcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIElubmVyIHByb2R1Y3RcbiAgICogcWIudmVjdG9yU2ltaWxhcml0eShcImNvbHVtbk5hbWVcIiwgcXVlcnlWZWN0b3IsIHtcbiAgICogICBtZXRob2Q6IFwiaW5uZXJfcHJvZHVjdFwiLFxuICAgKiAgIHRocmVzaG9sZDogMC43XG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIHZlY3RvclNpbWlsYXJpdHkoXG4gICAgY29sdW1uOiBWZWN0b3JDb2x1bW5zPFRUYWJsZXM+LFxuICAgIGVtYmVkZGluZzogbnVtYmVyW10sXG4gICAgb3B0aW9uczoge1xuICAgICAgbWV0aG9kPzogXCJjb3NpbmVcIiB8IFwibDJcIiB8IFwiaW5uZXJfcHJvZHVjdFwiO1xuICAgICAgdGhyZXNob2xkPzogbnVtYmVyO1xuICAgICAgZGlzdGluY3RPbj86IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz47XG4gICAgfSA9IHt9LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQgJiB7IHNpbWlsYXJpdHk6IG51bWJlciB9PiB7XG4gICAgY29uc3QgeyBtZXRob2QgPSBcImNvc2luZVwiLCB0aHJlc2hvbGQsIGRpc3RpbmN0T24gfSA9IG9wdGlvbnM7XG5cbiAgICBpZiAoXG4gICAgICAhQXJyYXkuaXNBcnJheShlbWJlZGRpbmcpIHx8XG4gICAgICBlbWJlZGRpbmcubGVuZ3RoID09PSAwIHx8XG4gICAgICBlbWJlZGRpbmcuc29tZSgodikgPT4gIU51bWJlci5pc0Zpbml0ZSh2KSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZW1iZWRkaW5nIHZlY3RvcjogZXhwZWN0ZWQgYSBub24tZW1wdHkgYXJyYXkgb2YgZmluaXRlIG51bWJlcnNcIik7XG4gICAgfVxuXG4gICAgY29uc3QgdmVjdG9yTGl0ZXJhbCA9IEpTT04uc3RyaW5naWZ5KGVtYmVkZGluZy5tYXAoKHYpID0+IE51bWJlcih2KSkpO1xuICAgIGNvbnN0IG9wZXJhdG9yID0geyBjb3NpbmU6IFwiPD0+XCIsIGwyOiBcIjwtPlwiLCBpbm5lcl9wcm9kdWN0OiBcIjwjPlwiIH1bbWV0aG9kXTtcblxuICAgIC8vIG1ldGhvZOuzhCDsl7DsgrDsnpAg67CPIHNpbWlsYXJpdHkg6rOE7IKw7IudXG4gICAgLy8gLSBjb3NpbmU6IDw9PiAoY29zaW5lIGRpc3RhbmNlLCAwfjIpLCBzaW1pbGFyaXR5ID0gMSAtIGRpc3RhbmNlXG4gICAgLy8gLSBsMjogPC0+IChldWNsaWRlYW4gZGlzdGFuY2UpLCBzaW1pbGFyaXR5ID0gZGlzdGFuY2UgKOuCruydhOyImOuhnSDsnKDsgqwpXG4gICAgLy8gLSBpbm5lcl9wcm9kdWN0OiA8Iz4gKG5lZ2F0aXZlIGlubmVyIHByb2R1Y3QpLCBzaW1pbGFyaXR5ID0gLWRpc3RhbmNlICjrhpLsnYTsiJjroZ0g7Jyg7IKsKVxuICAgIGNvbnN0IHNpbWlsYXJpdHlFeHByID1cbiAgICAgIG1ldGhvZCA9PT0gXCJjb3NpbmVcIlxuICAgICAgICA/IHRoaXMua25leC5yYXcoYDEgLSAoPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yKSBhcyBzaW1pbGFyaXR5YCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pXG4gICAgICAgIDogbWV0aG9kID09PSBcImwyXCJcbiAgICAgICAgICA/IHRoaXMua25leC5yYXcoYD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvciBhcyBzaW1pbGFyaXR5YCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pXG4gICAgICAgICAgOiB0aGlzLmtuZXgucmF3KGAtKD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcikgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKTtcblxuICAgIC8vIFdIRVJFIE5PVCBOVUxMXG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3ROdWxsKGNvbHVtbik7XG5cbiAgICAvLyDquLDsobQgT1JERVIgQlkgY2xlYXJcbiAgICB0aGlzLmtuZXhRdWVyeS5jbGVhcihcIm9yZGVyXCIpO1xuICAgIGlmIChkaXN0aW5jdE9uKSB7XG4gICAgICAvLyBESVNUSU5DVCBPTuydgCBTRUxFQ1Qg7KCI7J2YIOunqCDslZ7sl5Ag7JmA7JW8IO2VmOuvgOuhnCwg6riw7KG0IHNlbGVjdChzdWJzZXQg7ZWE65Oc65OkKeulvCDrs7TsobQg7ZuEIGNsZWFy7ZWY6rOgIOuLpOyLnCDstpTqsIBcbiAgICAgIGNvbnN0IGV4aXN0aW5nU3Vic2V0Q29scyA9ICh0aGlzLmtuZXhRdWVyeSBhcyBhbnkpLl9zdGF0ZW1lbnRzXG4gICAgICAgIC5maWx0ZXIoKHM6IGFueSkgPT4gcy5ncm91cGluZyA9PT0gXCJjb2x1bW5zXCIpXG4gICAgICAgIC5mbGF0TWFwKChzOiBhbnkpID0+IHMudmFsdWUpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoXCJzZWxlY3RcIik7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3QodGhpcy5rbmV4LnJhdyhgRElTVElOQ1QgT04gKD8/KSA/P2AsIFtkaXN0aW5jdE9uLCBkaXN0aW5jdE9uXSkpO1xuICAgICAgZXhpc3RpbmdTdWJzZXRDb2xzLm1hcCgoY29sOiBhbnkpID0+IHRoaXMua25leFF1ZXJ5LnNlbGVjdChjb2wpKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5LnNlbGVjdChzaW1pbGFyaXR5RXhwcik7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5vcmRlckJ5UmF3KGA/PywgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yYCwgW1xuICAgICAgICBkaXN0aW5jdE9uLFxuICAgICAgICBjb2x1bW4sXG4gICAgICAgIHZlY3RvckxpdGVyYWwsXG4gICAgICBdKTtcblxuICAgICAgdGhpcy5rbmV4UXVlcnkgPSB0aGlzLmtuZXhcbiAgICAgICAgLmZyb20odGhpcy5rbmV4UXVlcnkuYXMoXCJkaXN0aW5jdF92ZWN0b3JzXCIpKVxuICAgICAgICAuc2VsZWN0KFwiKlwiKVxuICAgICAgICAub3JkZXJCeShcInNpbWlsYXJpdHlcIiwgXCJkZXNjXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2ltaWxhcml0eUV4cHIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeVJhdyhgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yYCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pO1xuICAgIH1cblxuICAgIC8vIHRocmVzaG9sZFxuICAgIGlmICh0eXBlb2YgdGhyZXNob2xkID09PSBcIm51bWJlclwiKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZSh0aHJlc2hvbGQpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2ZWN0b3JTaW1pbGFyaXR5IHRocmVzaG9sZDogJHt0aHJlc2hvbGR9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChkaXN0aW5jdE9uKSB7XG4gICAgICAgIGNvbnN0IHRocmVzaG9sZE9wID0gbWV0aG9kID09PSBcImwyXCIgPyBcIjw9XCIgOiBcIj49XCI7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKFwic2ltaWxhcml0eVwiLCB0aHJlc2hvbGRPcCwgdGhyZXNob2xkKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRocmVzaG9sZFZhbHVlID1cbiAgICAgICAgICBtZXRob2QgPT09IFwiY29zaW5lXCIgPyAxIC0gdGhyZXNob2xkIDogbWV0aG9kID09PSBcImlubmVyX3Byb2R1Y3RcIiA/IC10aHJlc2hvbGQgOiB0aHJlc2hvbGQ7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IgPD0gP2AsIFtcbiAgICAgICAgICBjb2x1bW4sXG4gICAgICAgICAgdmVjdG9yTGl0ZXJhbCxcbiAgICAgICAgICB0aHJlc2hvbGRWYWx1ZSxcbiAgICAgICAgXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8g6riw67O4IOy/vOumrCDrqZTshJzrk5zrk6RcbiAgbGltaXQoY291bnQ6IG51bWJlcik6IHRoaXMge1xuICAgIGlmIChjb3VudCA8IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbGltaXQ6IG11c3QgYmUgPj0gMFwiKTtcbiAgICB9XG4gICAgdGhpcy5rbmV4UXVlcnkubGltaXQoY291bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb2Zmc2V0KGNvdW50OiBudW1iZXIpOiB0aGlzIHtcbiAgICBpZiAoY291bnQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIG9mZnNldDogbXVzdCBiZSA+PSAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5vZmZzZXQoY291bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gR1JPVVAgQllcbiAgZ3JvdXBCeTxUQ29sdW1ucyBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KC4uLmNvbHVtbnM6IFRDb2x1bW5zW10pOiB0aGlzO1xuICBncm91cEJ5KC4uLmNvbHVtbnM6IHN0cmluZ1tdKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkuZ3JvdXBCeSguLi5jb2x1bW5zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEhBVklOR1xuICBoYXZpbmcoY29uZGl0aW9uOiBzdHJpbmcpOiB0aGlzO1xuICBoYXZpbmc8VENvbHVtbiBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHZhbHVlOiBhbnksXG4gICk6IHRoaXM7XG4gIC8vIEhBVklORyDqtaztmIRcbiAgaGF2aW5nKC4uLmNvbmRpdGlvbnM6IGFueVtdKTogdGhpcyB7XG4gICAgaWYgKGNvbmRpdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICAvLyBoYXZpbmcoXCJDT1VOVCgqKSA+IDEwXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeS5oYXZpbmcodGhpcy5rbmV4LnJhdyhjb25kaXRpb25zWzBdKSk7XG4gICAgfSBlbHNlIGlmIChjb25kaXRpb25zLmxlbmd0aCA9PT0gMykge1xuICAgICAgLy8gaGF2aW5nKFwiY291bnRcIiwgXCI+XCIsIDEwKVxuICAgICAgdGhpcy5rbmV4UXVlcnkuaGF2aW5nKFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMF0pLFxuICAgICAgICBjb25kaXRpb25zWzFdLFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMl0pLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBoYXZpbmcgYXJndW1lbnRzXCIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOyLpO2WiSDrqZTshJzrk5zrk6QgLSB0aGVuYWJsZSDqtaztmIRcbiAgdGhlbjxUUmVzdWx0MSA9IEV4cGFuZDxUUmVzdWx0PltdLCBUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbmZ1bGZpbGxlZD86ICgodmFsdWU6IEV4cGFuZDxUUmVzdWx0PltdKSA9PiBUUmVzdWx0MSB8IFByb21pc2VMaWtlPFRSZXN1bHQxPikgfCBudWxsLFxuICAgIG9ucmVqZWN0ZWQ/OiAoKHJlYXNvbjogYW55KSA9PiBUUmVzdWx0MiB8IFByb21pc2VMaWtlPFRSZXN1bHQyPikgfCBudWxsLFxuICApOiBQcm9taXNlPFRSZXN1bHQxIHwgVFJlc3VsdDI+IHtcbiAgICBOYWl0ZS50KFwicHVyaTpleGVjdXRlZC1xdWVyeVwiLCB0aGlzLnRvUXVlcnkoKSk7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LnRoZW4ob25mdWxmaWxsZWQgYXMgYW55LCBvbnJlamVjdGVkKTtcbiAgfVxuICBjYXRjaDxUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbnJlamVjdGVkPzogKChyZWFzb246IGFueSkgPT4gVFJlc3VsdDIgfCBQcm9taXNlTGlrZTxUUmVzdWx0Mj4pIHwgbnVsbCxcbiAgKTogUHJvbWlzZTxUUmVzdWx0IHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cbiAgZmluYWxseShvbmZpbmFsbHk/OiAoKCkgPT4gdm9pZCkgfCBudWxsKTogUHJvbWlzZTxUUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LmZpbmFsbHkob25maW5hbGx5KTtcbiAgfVxuXG4gIC8vIO2VmOuCmOunjCDsv7zrpqxcbiAgZmlyc3QoKTogUmVzb2x2ZWRQdXJpPEV4cGFuZDxUUmVzdWx0PiwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5maXJzdCgpO1xuICAgIHJldHVybiBuZXcgUmVzb2x2ZWRQdXJpKHRoaXMua25leFF1ZXJ5LCB0aGlzLmtuZXgpO1xuICB9XG5cbiAgLy8g7L+866as7ZWcIOugiOy9lOuTnOyXkOyEnCDtirnsoJUg7Lus65+866eMIOy2lOy2nO2VnCDrsLDsl7Qg66as7YS0XG4gIHBsdWNrPFRDb2x1bW4gZXh0ZW5kcyBrZXlvZiBUUmVzdWx0IHwgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICApOiBSZXNvbHZlZFB1cmk8XG4gICAgVENvbHVtbiBleHRlbmRzIGtleW9mIFRSZXN1bHRcbiAgICAgID8gVFJlc3VsdFtUQ29sdW1uXVtdXG4gICAgICA6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICAgbmV2ZXJcbiAgPiB7XG4gICAgdGhpcy5rbmV4UXVlcnkucGx1Y2soY29sdW1uIGFzIHN0cmluZyk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBJTlNFUlQgOiDri6jsnbwg6rCd7LK0XG4gIGluc2VydChcbiAgICBkYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+LFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PjtcbiAgLy8gSU5TRVJUOiDrsLDsl7RcbiAgaW5zZXJ0KFxuICAgIGRhdGE6IEluc2VydERhdGE8U2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj5bXSxcbiAgKTogUmVzb2x2ZWRQdXJpPEluc2VydFJlc3VsdCwgU2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj47XG4gIC8vIElOU0VSVCDsi6TsoJwg6rWs7ZiEXG4gIGluc2VydChcbiAgICByYXdEYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHwgSW5zZXJ0RGF0YTxTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PltdLFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkuaW5zZXJ0KHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIFVQREFURVxuICB1cGRhdGUocmF3RGF0YTogV2hlcmVDb25kaXRpb248VFRhYmxlcz4pOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkudXBkYXRlKHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBKU09OIOy7rOufvOyXkCDrjIDtlbQgc3RyaW5naWZ5IOyymOumrOulvCDsiJjtlontlZjripQg64K067aAIOuplOyEnOuTnOyeheuLiOuLpC5cbiAgICogb2JqZWN0IOuYkOuKlCBvYmplY3Qg67Cw7Je07J2EIOuwm+qzoCwgSlNPTiDsu6zrn7zsnbQg7J6I7Jy866m0IOyngeugrO2ZlO2VmOyXrCDrsJjtmZjtlanri4jri6QuXG4gICAqIOyngeygkSDqsJLsnYQg67OA6rK97ZWY66+A66GcIHNpZGUgZWZmZWN06rCAIOyeiOyKteuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgcmVmaW5lSnNvbkNvbHVtbnMoXG4gICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdLFxuICApOiB0eXBlb2YgZGF0YSB7XG4gICAgLy8gdGFibGVTcGVj7J2064KYIGpzb25Db2x1bW5zIOyXhuuKlCDqsr3smrAg67CU66GcIOuwmO2ZmFxuICAgIGlmICghdGhpcy50YWJsZVNwZWMgfHwgIXRoaXMudGFibGVTcGVjLmpzb25Db2x1bW5zLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxuXG4gICAgLy8g65Ox66Gd65CcIFRhYmxlU3BlY+ydhCDthrXtlbQgSlNPTuy7rOufvCDrqqnroZ3snYQg6rCA7KC47JmAIEpTT04uc3RyaW5naWZ5IOyymOumrFxuICAgIGNvbnN0IGpzb25Db2x1bW5zID0gdGhpcy50YWJsZVNwZWMuanNvbkNvbHVtbnM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBkYXRhKSB7XG4gICAgICAgIGZvciAoY29uc3QgY29sdW1uIG9mIGpzb25Db2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBpdGVtW2NvbHVtbl07XG4gICAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGl0ZW1bY29sdW1uXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBjb2x1bW4gb2YganNvbkNvbHVtbnMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBkYXRhW2NvbHVtbl07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgZGF0YVtjb2x1bW5dID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLy8gSW5jcmVtZW50XG4gIGluY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkluY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5pbmNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cbiAgLy8gRGVjcmVtZW50XG4gIGRlY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5kZWNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBERUxFVEVcbiAgZGVsZXRlKCk6IFJlc29sdmVkUHVyaTxudW1iZXIsIFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kZWxldGUoKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIO2ZleyduCDsv7zrpqwg66as7YS0XG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgLy8g7L+866asIOuUlOuyhOq5hSDroZzqt7gg7Lac66ClXG4gIGRlYnVnKCk6IHRoaXMge1xuICAgIGNvbnNvbGUubG9nKGAke2NoYWxrLmN5YW4oXCJbUHVyaSBEZWJ1Z11cIil9ICR7Y2hhbGsueWVsbG93KHRoaXMudG9RdWVyeSgpKX1gKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGNsb25lKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIC8vICdkdWFsJ+ydgCDrjZTrr7gg7YWM7J2067iU7J2066mwLCDrsJTroZwg7JWE656YIOykhOyXkOyEnCBrbmV4UXVlcnnqsIAg642u7Ja07JSM7JuM7KeR64uI64ukLlxuICAgIGNvbnN0IG5ld1B1cmkgPSBuZXcgUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0Pih0aGlzLmtuZXgsIFwiZHVhbFwiKTtcbiAgICBuZXdQdXJpLmtuZXhRdWVyeSA9IHRoaXMua25leFF1ZXJ5LmNsb25lKCk7XG4gICAgcmV0dXJuIG5ld1B1cmk7XG4gIH1cblxuICBmb3JtYXRTUUwodW5mb3JtYXR0ZWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gU1FMIOyYiOyVveyWtCDrqqnroZ1cbiAgICBjb25zdCBrZXl3b3JkcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiSU5TRVJUXCIsXG4gICAgICBcIklOVE9cIixcbiAgICAgIFwiVkFMVUVTXCIsXG4gICAgICBcIlVQREFURVwiLFxuICAgICAgXCJERUxFVEVcIixcbiAgICAgIFwiQ1JFQVRFXCIsXG4gICAgICBcIlRBQkxFXCIsXG4gICAgICBcIkFMVEVSXCIsXG4gICAgICBcIkRST1BcIixcbiAgICAgIFwiSk9JTlwiLFxuICAgICAgXCJPTlwiLFxuICAgICAgXCJJTk5FUlwiLFxuICAgICAgXCJMRUZUXCIsXG4gICAgICBcIlJJR0hUXCIsXG4gICAgICBcIkZVTExcIixcbiAgICAgIFwiT1VURVJcIixcbiAgICAgIFwiR1JPVVBcIixcbiAgICAgIFwiQllcIixcbiAgICAgIFwiT1JERVJcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkRJU1RJTkNUXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIk9GRlNFVFwiLFxuICAgICAgXCJBU1wiLFxuICAgICAgXCJBTkRcIixcbiAgICAgIFwiT1JcIixcbiAgICAgIFwiTk9UXCIsXG4gICAgICBcIklOXCIsXG4gICAgICBcIkxJS0VcIixcbiAgICAgIFwiSVNcIixcbiAgICAgIFwiTlVMTFwiLFxuICAgICAgXCJDQVNFXCIsXG4gICAgICBcIldIRU5cIixcbiAgICAgIFwiVEhFTlwiLFxuICAgICAgXCJFTFNFXCIsXG4gICAgICBcIkVORFwiLFxuICAgICAgXCJVTklPTlwiLFxuICAgICAgXCJBTExcIixcbiAgICAgIFwiRVhJU1RTXCIsXG4gICAgICBcIkJFVFdFRU5cIixcbiAgICBdO1xuXG4gICAgbGV0IGZvcm1hdHRlZCA9IHVuZm9ybWF0dGVkO1xuXG4gICAgLy8g7JiI7JW97Ja066W8IOuMgOusuOyekOuhnCDrs4DtmZhcbiAgICBrZXl3b3Jkcy5mb3JFYWNoKChrZXl3b3JkKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxiJHtrZXl3b3JkfVxcXFxiYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBrZXl3b3JkLnRvVXBwZXJDYXNlKCkpO1xuICAgIH0pO1xuXG4gICAgLy8g7KO87JqUIOygiCDslZ7sl5Ag7KSE67CU6r+IIOy2lOqwgFxuICAgIGNvbnN0IG1ham9yQ2xhdXNlcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiR1JPVVAgQllcIixcbiAgICAgIFwiT1JERVIgQllcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIlVOSU9OXCIsXG4gICAgXTtcbiAgICBtYWpvckNsYXVzZXMuZm9yRWFjaCgoY2xhdXNlKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxzKygke2NsYXVzZX0pXFxcXHMrYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBgXFxuJHtjbGF1c2UudG9VcHBlckNhc2UoKX0gYCk7XG4gICAgfSk7XG5cbiAgICAvLyBKT0lOIOygiCDsspjrpqxcbiAgICBmb3JtYXR0ZWQgPSBmb3JtYXR0ZWQucmVwbGFjZSgvXFxzKygoPzpJTk5FUnxMRUZUfFJJR0hUfEZVTEwgT1VURVIpXFxzKyk/Sk9JTlxccysvZ2ksIFwiXFxuJDFKT0lOIFwiKTtcblxuICAgIC8vIEFORCwgT1Ig7KGw6rG0IOyymOumrFxuICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKC9cXHMrKEFORHxPUilcXHMrL2dpLCBcIlxcbiAgJDEgXCIpO1xuXG4gICAgLy8g6rSE7Zi4IOyymOumrCDrsI8g65Ok7Jes7JOw6riwXG4gICAgY29uc3QgbGluZXMgPSBmb3JtYXR0ZWQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgaW5kZW50ZWRMaW5lcyA9IFtdO1xuICAgIGxldCBpbmRlbnRMZXZlbCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG4gICAgICBpZiAoIXRyaW1tZWRMaW5lKSBjb250aW51ZTtcblxuICAgICAgLy8g64ur64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDqsJDshoxcbiAgICAgIGNvbnN0IGNsb3NpbmdQYXJlbnMgPSAodHJpbW1lZExpbmUubWF0Y2goL1xcKS9nKSB8fCBbXSkubGVuZ3RoO1xuICAgICAgY29uc3Qgb3BlbmluZ1BhcmVucyA9ICh0cmltbWVkTGluZS5tYXRjaCgvXFwoL2cpIHx8IFtdKS5sZW5ndGg7XG5cbiAgICAgIGlmIChjbG9zaW5nUGFyZW5zID4gMCAmJiBvcGVuaW5nUGFyZW5zID09PSAwKSB7XG4gICAgICAgIGluZGVudExldmVsID0gTWF0aC5tYXgoMCwgaW5kZW50TGV2ZWwgLSBjbG9zaW5nUGFyZW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8g7ZiE7J6sIOuTpOyXrOyTsOq4sCDsoIHsmqlcbiAgICAgIGNvbnN0IGluZGVudCA9IFwiICBcIi5yZXBlYXQoaW5kZW50TGV2ZWwpO1xuICAgICAgaW5kZW50ZWRMaW5lcy5wdXNoKGluZGVudCArIHRyaW1tZWRMaW5lKTtcblxuICAgICAgLy8g7Jes64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDspp3qsIBcbiAgICAgIGlmIChvcGVuaW5nUGFyZW5zID4gY2xvc2luZ1BhcmVucykge1xuICAgICAgICBpbmRlbnRMZXZlbCArPSBvcGVuaW5nUGFyZW5zIC0gY2xvc2luZ1BhcmVucztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW5kZW50ZWRMaW5lcy5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgfVxuXG4gIHJhdyhzcWw6IHN0cmluZyk6IEtuZXguUmF3IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4LnJhdyhzcWwpO1xuICB9XG5cbiAgLy8gS25leCDsv7zrpqwg67mM642UIOyngeygkSDsoJHqt7xcbiAgcmF3UXVlcnkoKTogS25leC5RdWVyeUJ1aWxkZXIge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgV2hlcmVHcm91cDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGJ1aWxkZXI6IEtuZXguUXVlcnlCdWlsZGVyKSB7fVxuXG4gIC8vIHdoZXJlIOuplOyEnOuTnOuTpFxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIG9wZXJhdG9yOiBXaGVyZU9wZXJhdG9yLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgd2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmUoYXJnc1swXSwgLi4uYXJncy5zbGljZSgxKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyB3aGVyZUluIC8gd2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgd2hlcmVJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVOb3RJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gb3JXaGVyZSDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZShhcmdzWzBdLCAuLi5hcmdzLnNsaWNlKDEpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIG9yV2hlcmVJbiAvIG9yV2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlSW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlTm90SW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzO1xuICB3aGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoYXJnc1swXSl9KSBBR0FJTlNUICg/KWAsIFthcmdzWzFdXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBvcldoZXJlTWF0Y2g8VENvbHVtbiBleHRlbmRzIEZ1bGx0ZXh0Q29sdW1uczxUVGFibGVzPj4oY29sdW1uOiBUQ29sdW1uLCB2YWx1ZTogc3RyaW5nKTogdGhpcztcbiAgb3JXaGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYE1BVENIICgke1N0cmluZyhhcmdzWzBdKX0pIEFHQUlOU1QgKD8pYCwgW2FyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFNFQVJDSFxuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBhcmdzWzJdID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGFyZ3NbMF0pXG4gICAgICA/IGBBUlJBWVske2FyZ3NbMF0ubWFwKChjKSA9PiBgJHtjfTo6dGV4dGApLmpvaW4oXCIsXCIpfV1gXG4gICAgICA6IGFyZ3NbMF07XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gJkB+ICR7cGdyb29uZ2FDb25kaXRpb259YCwgW2FyZ3NbMV1dKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVTZWFyY2goLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCB7IHdlaWdodHMgfSA9IGFyZ3NbMl0gPz8ge307XG4gICAgY29uc3QgY29sdW1uRXhwciA9IEFycmF5LmlzQXJyYXkoYXJnc1swXSlcbiAgICAgID8gYEFSUkFZWyR7YXJnc1swXS5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogYXJnc1swXTtcbiAgICBjb25zdCBwZ3Jvb25nYUNvbmRpdGlvbiA9IGBwZ3Jvb25nYV9jb25kaXRpb24oPyR7d2VpZ2h0cz8ubGVuZ3RoID8gYCwgd2VpZ2h0cyA9PiBBUlJBWVske3dlaWdodHMuam9pbihcIixcIil9XWAgOiBcIlwifSlgO1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFthcmdzWzFdXSk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIEZVTExURVhUXG4gIHdoZXJlVHNTZWFyY2g8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNRdWVyeU9wdGlvbnMgfCBUc1F1ZXJ5Q29uZmlnLFxuICApOiB0aGlzO1xuICB3aGVyZVRzU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2YgYXJnc1syXSA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogYXJnc1syXSB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChhcmdzWzJdID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIgJiYgYXJnc1swXS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgID8gYXJnc1swXS5fc3FsXG4gICAgICAgIDogU3RyaW5nKGFyZ3NbMF0pO1xuXG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVUc1NlYXJjaCguLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIGFyZ3NbMl0gPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IGFyZ3NbMl0gfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAoYXJnc1syXSA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiICYmIGFyZ3NbMF0uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGFyZ3NbMF0uX3NxbFxuICAgICAgICA6IFN0cmluZyhhcmdzWzBdKTtcblxuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlRnV6enkoLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCBvcGVyYXRvciA9IG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IoYXJnc1syXT8ub3BlcmF0b3IpO1xuXG4gICAgaWYgKG9wZXJhdG9yID09PSBcIiVcIikge1xuICAgICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMuYnVpbGRlci53aGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbYXJnc1swXSwgYXJnc1sxXV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gJHthcmdzWzBdLl9zcWx9YCwgW2FyZ3NbMV0sIC4uLmFyZ3NbMF0uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcztcbiAgb3JXaGVyZUZ1enp5KC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKGFyZ3NbMl0/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYXJnc1swXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gP2AsIFthcmdzWzBdLCBhcmdzWzFdXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7YXJnc1swXS5fc3FsfWAsIFthcmdzWzFdLCAuLi5hcmdzWzBdLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOykkeyyqSDqt7jro7lcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzO1xuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZSgoc3ViQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3Qgc3ViR3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihzdWJCdWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKHN1Ykdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcztcbiAgb3JXaGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlKChzdWJCdWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBzdWJHcm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KHN1YkJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soc3ViR3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8vIEpPSU4g7KCIIOq3uOujueyXkOuKlCBMZWZ07JmAIFJpZ2h07JeQIOuMgO2VnCDsiJzshJzqsIAg7ZWE7JqU7ZWY7KeAIOyViuycvOuvgOuhnCwg66qo65OgIOqyveyasOydmCDsiJjrpbwg6rOE7IKw7ZW07JW87ZWoLlxuZXhwb3J0IGNsYXNzIEpvaW5DbGF1c2VHcm91cDxcbiAgVExlZnQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICBUUmlnaHQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuPiB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2FsbGJhY2s6IEtuZXguSm9pbkNsYXVzZSkge31cblxuICAvLyBPTihBTkQpOiDsu6zrn7wgPSDsu6zrn7xcbiAgb24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvbihsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Pik6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCA9IOqwklxuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIHJpZ2h0OiBFeHRyYWN0Q29sdW1uVHlwZTxUUmlnaHQsIEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDsu6zrn7xcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDqsJJcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oQU5EKTog7L2c67CxXG4gIG9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvbihjYWxsYmFjazogKG5lc3RlZDogSm9pbkNsYXVzZUdyb3VwPFRSaWdodCwgVExlZnQ+KSA9PiB2b2lkKTogdGhpcztcbiAgLy8gT04oQU5EKSDqtaztmIRcbiAgb24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9uKC4uLihhcmdzIGFzIFtzdHJpbmcsIHN0cmluZ10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9OKE9SKTog7Lus65+8ID0g7Lus65+8XG4gIG9yT24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvck9uKGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgcmlnaHQ6IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+KTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgPSDqsJJcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg7Lus65+8XG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvck9uKFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg6rCSXG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VFJpZ2h0LCBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBPTihPUik6IOy9nOuwsVxuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VFJpZ2h0LCBUTGVmdD4pID0+IHZvaWQpOiB0aGlzO1xuICAvLyBPTihPUikg6rWs7ZiEXG4gIG9yT24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9yT24oLi4uKGFyZ3MgYXMgW3N0cmluZywgc3RyaW5nXSkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT04gVkFMKEFORCk6IOy7rOufvCA9IOqwkiAo6rCS7J2EIOy7rOufvCDssLjsobDqsIAg7JWE64uMIO2MjOudvOuvuO2EsOuhnCDrsJTsnbjrlKkpXG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEFORCBPTiBWQUw6IG9uVmFs7J2YIOuqheyLnOyggSBhbGlhcyAoS25leCDtmLjtmZgpXG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5hbmRPblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SIE9OIFZBTDogT1Ig7KGw6rG07Jy866GcIOqwkiDrsJTsnbjrlKlcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+LCB2YWx1ZTogYW55KTogdGhpcztcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvck9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vck9uVmFsKC4uLmFyZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8qXG4gIFRSZXNvbHZlZDog7L+866asIOyLpO2WiSDtm4Qg67CY7ZmY65CgIOqysOqzvCDtg4DsnoVcbiAgVFJldHVybmluZzogUkVUVVJOSU5HIOygiOyXkCDsgqzsmqnrkKAg7YOA7J6FXG4qL1xuZXhwb3J0IGNsYXNzIFJlc29sdmVkUHVyaTxUUmVzb2x2ZWQsIFRSZXR1cm5pbmc+IGltcGxlbWVudHMgUHJvbWlzZTxUUmVzb2x2ZWQ+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBrbmV4OiBLbmV4LFxuICApIHt9XG5cbiAgW1N5bWJvbC50b1N0cmluZ1RhZ106IHN0cmluZyA9IFwiUHJvbWlzZVwiO1xuXG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgZGVidWcoKTogdGhpcyB7XG4gICAgY29uc29sZS5sb2coYCR7Y2hhbGsuY3lhbihcIltQdXJpIERlYnVnXVwiKX0gJHtjaGFsay55ZWxsb3codGhpcy50b1F1ZXJ5KCkpfWApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdGhlbjxUUmVzdWx0MSA9IFRSZXNvbHZlZCwgVFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25mdWxmaWxsZWQ/OiAoKHZhbHVlOiBUUmVzb2x2ZWQpID0+IFRSZXN1bHQxIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDE+KSB8IG51bGwsXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc3VsdDEgfCBUUmVzdWx0Mj4ge1xuICAgIE5haXRlLnQoXCJwdXJpOmV4ZWN1dGVkLXF1ZXJ5XCIsIHRoaXMudG9RdWVyeSgpKTtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudGhlbihvbmZ1bGZpbGxlZCBhcyBhbnksIG9ucmVqZWN0ZWQpO1xuICB9XG5cbiAgY2F0Y2g8VFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc29sdmVkIHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cblxuICBmaW5hbGx5KG9uZmluYWxseT86ICgoKSA9PiB2b2lkKSB8IG51bGwpOiBQcm9taXNlPFRSZXNvbHZlZD4ge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeS5maW5hbGx5KG9uZmluYWxseSk7XG4gIH1cblxuICAvLyBPTiBDT05GTElDVCAtIOy7rOufvCDquLDrsJhcbiAgb25Db25mbGljdDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgVFJldHVybmluZz4+KFxuICAgIGNvbHVtbnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGFjdGlvbj86IE9uQ29uZmxpY3RBY3Rpb248VFRhYmxlcz4sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHRhcmdldCA9IEFycmF5LmlzQXJyYXkoY29sdW1ucykgPyBjb2x1bW5zIDogW2NvbHVtbnNdO1xuXG4gICAgaWYgKCFhY3Rpb24gfHwgYWN0aW9uID09PSBcIm5vdGhpbmdcIikge1xuICAgICAgLy8gRE8gTk9USElOR1xuICAgICAgdGhpcy5rbmV4UXVlcnkub25Db25mbGljdCh0YXJnZXQpLmlnbm9yZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBETyBVUERBVEVcbiAgICAgIGNvbnN0IHsgdXBkYXRlIH0gPSBhY3Rpb247XG5cbiAgICAgIC8vIGFjdGlvbi51cGRhdGUg67Cw7Je0IO2Yle2DnCA6IFtcIm5hbWVcIiwgXCJlbWFpbFwiXVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodXBkYXRlKSkge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UodXBkYXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFjdGlvbi51cGRhdGUg6rCd7LK0IO2Yle2DnDogeyBuYW1lOiBcIkpvaG5cIiwgY291bnQ6IHJhdyguLi4pIH1cbiAgICAgICAgY29uc3QgbWVyZ2VPYmo6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGUpKSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdmFsdWUgJiZcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgXCJfdHlwZVwiIGluIHZhbHVlICYmXG4gICAgICAgICAgICB2YWx1ZS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBTcWxFeHByZXNzaW9uIOKGkiBrbmV4LnJhdygp66GcIOuzgO2ZmFxuICAgICAgICAgICAgbWVyZ2VPYmpba2V5XSA9IHRoaXMua25leC5yYXcoKHZhbHVlIGFzIFNxbEV4cHJlc3Npb248YW55PikuX3NxbCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOydvOuwmCDqsJJcbiAgICAgICAgICAgIG1lcmdlT2JqW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UobWVyZ2VPYmopO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gUkVUVVJOSU5HOiBcIipcIiAtIOyghOyytCDsu6zrn7xcbiAgcmV0dXJuaW5nKGNvbHVtbjogXCIqXCIpOiBSZXNvbHZlZFB1cmk8VFJldHVybmluZ1tdLCBuZXZlcj47XG4gIC8vIFJFVFVSTklORzog64uo7J28IOy7rOufvFxuICByZXR1cm5pbmc8VENvbHVtbiBleHRlbmRzIENvbHVtbktleXM8VFJldHVybmluZz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgKTogUmVzb2x2ZWRQdXJpPFBpY2s8VFJldHVybmluZywgVENvbHVtbj5bXSwgbmV2ZXI+O1xuICAvLyBSRVRVUk5JTkc6IOuzteyImCDsu6zrn7wgKOuwsOyXtClcbiAgcmV0dXJuaW5nPFRDb2x1bW4gZXh0ZW5kcyBDb2x1bW5LZXlzPFRSZXR1cm5pbmc+PihcbiAgICBjb2x1bW5zOiBUQ29sdW1uW10sXG4gICk6IFJlc29sdmVkUHVyaTxQaWNrPFRSZXR1cm5pbmcsIFRDb2x1bW4+W10sIG5ldmVyPjtcbiAgLy8gUkVUVVJOSU5HIOq1rO2YhFxuICByZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSk6IFJlc29sdmVkUHVyaTxhbnlbXSwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5yZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUEwQ0EsU0FBUyx1QkFBdUIsVUFBa0M7Q0FDaEUsTUFBTSxhQUFhLFVBQVUsTUFBTSxJQUFJO0NBQ3ZDLE1BQU0sZ0JBQWdCLGdCQUFnQixNQUFNLGNBQWMsY0FBYyxXQUFXO0FBRW5GLEtBQUksQ0FBQyxlQUFlO0FBQ2xCLFFBQU0sSUFBSSxNQUFNLDJCQUEyQixZQUFZLEtBQUs7O0FBRzlELFFBQU87Ozs7c0JBMUNnRDthQUVsQjtrQkE4QlE7Q0FhbEMsT0FBYixNQUFhLEtBQTREO0VBQ3ZFLEFBQVE7RUFDUixBQUFRLFlBQThCO0VBS3RDLFlBQ0UsQUFBT0EsTUFDUCxtQkFDQTtHQUZPO0FBR1AsT0FBSSxPQUFPLHNCQUFzQixVQUFVO0FBRXpDLFNBQUssWUFBWSxLQUFLLEtBQUssa0JBQWtCLENBQUMsS0FBSyxrQkFBa0I7QUFDckUsU0FBSyxZQUFZLEtBQUssaUJBQWlCLGtCQUFrQjtjQUNoRCxPQUFPLHNCQUFzQixVQUFVO0lBQ2hELE1BQU0sVUFBVSxPQUFPLFFBQVEsa0JBQWtCO0FBQ2pELFFBQUksUUFBUSxXQUFXLEdBQUc7QUFDeEIsV0FBTSxJQUFJLE1BQU0seUNBQXlDOztBQUUzRCxXQUFPLFFBQVEsR0FBRztJQUNsQixNQUFNLENBQUMsT0FBTyxVQUFVLFFBQVE7QUFDaEMsUUFBSSxPQUFPLFdBQVcsVUFBVTtBQUM5QixVQUFLLFlBQVksS0FBSyxLQUFLLE9BQU8sQ0FBQyxLQUFLLEdBQUcsUUFBUSxRQUFRLENBQUM7QUFDNUQsVUFBSyxZQUFZLEtBQUssaUJBQWlCLE9BQU87ZUFDckMs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
|