sonamu 0.8.26 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +60 -13
- package/dist/_virtual/rolldown_runtime.js +39 -0
- package/dist/ai/agents/agent.d.ts +3 -3
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +76 -73
- package/dist/ai/agents/index.js +3 -3
- package/dist/ai/agents/types.d.ts +3 -3
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/agents/types.js +1 -3
- package/dist/ai/index.js +3 -2
- package/dist/ai/providers/rtzr/api.js +25 -25
- package/dist/ai/providers/rtzr/error.js +25 -26
- package/dist/ai/providers/rtzr/index.js +5 -5
- package/dist/ai/providers/rtzr/model.d.ts +1 -1
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.js +117 -133
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/options.js +35 -41
- package/dist/ai/providers/rtzr/provider.d.ts +1 -1
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/provider.js +53 -51
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.js +84 -84
- package/dist/api/base-frame.d.ts +2 -2
- package/dist/api/base-frame.d.ts.map +1 -1
- package/dist/api/base-frame.js +29 -19
- package/dist/api/caster.d.ts +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +51 -61
- package/dist/api/code-converters.d.ts +4 -3
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +226 -249
- package/dist/api/config.d.ts +17 -17
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +37 -30
- package/dist/api/context.d.ts +10 -10
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +8 -2
- package/dist/api/decorators.d.ts +8 -8
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +245 -268
- package/dist/api/index.js +39 -7
- package/dist/api/secret.js +22 -15
- package/dist/api/sonamu.d.ts +15 -15
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +1012 -1131
- package/dist/api/validator.js +88 -79
- package/dist/auth/auth-generator.d.ts.map +1 -1
- package/dist/auth/auth-generator.js +203 -200
- package/dist/auth/better-auth-entities.d.ts +2 -2
- package/dist/auth/better-auth-entities.d.ts.map +1 -1
- package/dist/auth/better-auth-entities.js +369 -429
- package/dist/auth/index.js +21 -6
- package/dist/auth/knex-adapter.d.ts +2 -2
- package/dist/auth/knex-adapter.d.ts.map +1 -1
- package/dist/auth/knex-adapter.js +153 -157
- package/dist/auth/plugins/entity-definitions/admin.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/admin.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/admin.js +58 -56
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/anonymous.js +20 -20
- package/dist/auth/plugins/entity-definitions/api-key.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/api-key.js +185 -196
- package/dist/auth/plugins/entity-definitions/index.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +26 -29
- package/dist/auth/plugins/entity-definitions/jwt.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/jwt.js +62 -64
- package/dist/auth/plugins/entity-definitions/organization.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/organization.js +362 -421
- package/dist/auth/plugins/entity-definitions/passkey.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/passkey.js +115 -126
- package/dist/auth/plugins/entity-definitions/phone-number.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/phone-number.js +31 -40
- package/dist/auth/plugins/entity-definitions/sso.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/sso.js +94 -107
- package/dist/auth/plugins/entity-definitions/two-factor.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/two-factor.js +78 -92
- package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/types.js +1 -10
- package/dist/auth/plugins/entity-definitions/username.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/username.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/username.js +31 -40
- package/dist/auth/plugins/index.js +12 -3
- package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
- package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/admin.js +28 -29
- package/dist/auth/plugins/wrappers/anonymous.d.ts +2 -1
- package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/anonymous.js +23 -22
- package/dist/auth/plugins/wrappers/api-key.d.ts +2 -1
- package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/api-key.js +39 -34
- package/dist/auth/plugins/wrappers/index.js +11 -11
- package/dist/auth/plugins/wrappers/jwt.d.ts +2 -1
- package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/jwt.js +31 -26
- package/dist/auth/plugins/wrappers/organization.d.ts +2 -1
- package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/organization.js +65 -62
- package/dist/auth/plugins/wrappers/passkey.d.ts +2 -1
- package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/passkey.js +33 -28
- package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/phone-number.js +26 -23
- package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/sso.js +37 -31
- package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/two-factor.js +31 -28
- package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/username.js +23 -23
- package/dist/bin/build-config.js +31 -31
- package/dist/bin/cli.js +1063 -1204
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +266 -259
- package/dist/bin/hmr-hook-register.d.ts.map +1 -1
- package/dist/bin/hmr-hook-register.js +19 -18
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +180 -177
- package/dist/bin/ts-loader-register.js +13 -6
- package/dist/bin/ts-loader-registration.d.ts.map +1 -1
- package/dist/bin/ts-loader-registration.js +28 -38
- package/dist/cache/cache-manager.d.ts +1 -1
- package/dist/cache/cache-manager.d.ts.map +1 -1
- package/dist/cache/cache-manager.js +20 -15
- package/dist/cache/decorator.d.ts +1 -1
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +84 -76
- package/dist/cache/drivers.js +21 -34
- package/dist/cache/index.js +10 -7
- package/dist/cache/types.d.ts +2 -2
- package/dist/cache/types.d.ts.map +1 -1
- package/dist/cache/types.js +1 -6
- package/dist/cache-control/cache-control.d.ts +2 -2
- package/dist/cache-control/cache-control.d.ts.map +1 -1
- package/dist/cache-control/cache-control.js +106 -122
- package/dist/cache-control/types.d.ts +2 -2
- package/dist/cache-control/types.d.ts.map +1 -1
- package/dist/cache-control/types.js +1 -19
- package/dist/compress/compress.d.ts +1 -1
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/compress/compress.js +58 -56
- package/dist/compress/index.js +7 -2
- package/dist/compress/types.js +1 -11
- package/dist/cone/cone-generator.d.ts +1 -1
- package/dist/cone/cone-generator.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +216 -219
- package/dist/database/_batch_update.d.ts +1 -1
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +107 -102
- package/dist/database/base-model.d.ts +8 -9
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +371 -392
- package/dist/database/base-model.types.d.ts +5 -5
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/base-model.types.js +1 -20
- package/dist/database/db.d.ts +5 -2
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +185 -171
- package/dist/database/knex.d.ts +1 -1
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +48 -42
- package/dist/database/puri-subset.types.d.ts +6 -7
- package/dist/database/puri-subset.types.d.ts.map +1 -1
- package/dist/database/puri-subset.types.js +1 -16
- package/dist/database/puri-wrapper.d.ts +6 -6
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +99 -101
- package/dist/database/puri.d.ts +4 -5
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +1021 -1227
- package/dist/database/puri.types.d.ts +6 -6
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +15 -6
- package/dist/database/transaction-context.d.ts +2 -2
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +22 -13
- package/dist/database/upsert-builder.d.ts +3 -3
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +405 -465
- package/dist/dict/en.js +72 -74
- package/dist/dict/index.js +13 -13
- package/dist/dict/ko.js +72 -74
- package/dist/dict/rc-keys.js +150 -168
- package/dist/dict/sd.d.ts +3 -1
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +54 -40
- package/dist/dict/sonamu-dictionary.d.ts +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +887 -955
- package/dist/dict/types.js +1 -7
- package/dist/dict/utils.js +26 -24
- package/dist/entity/entity-manager.d.ts +9 -9
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +226 -223
- package/dist/entity/entity-template-cone.d.ts +1 -1
- package/dist/entity/entity-template-cone.d.ts.map +1 -1
- package/dist/entity/entity-template-cone.js +152 -151
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +952 -1089
- package/dist/exceptions/error-handler.d.ts +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +32 -27
- package/dist/exceptions/so-exceptions.d.ts +1 -1
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +61 -68
- package/dist/filter/index.js +9 -3
- package/dist/filter/types.js +92 -88
- package/dist/filter/utils.d.ts +1 -1
- package/dist/filter/utils.d.ts.map +1 -1
- package/dist/filter/utils.js +147 -161
- package/dist/index.js +87 -40
- package/dist/logger/category.d.ts.map +1 -1
- package/dist/logger/category.js +30 -29
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +83 -107
- package/dist/migration/code-generation.d.ts +2 -2
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +1385 -1578
- package/dist/migration/migration-set.d.ts +1 -1
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +177 -227
- package/dist/migration/migrator.d.ts +4 -3
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +340 -345
- package/dist/migration/postgresql-schema-reader.d.ts +2 -2
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/postgresql-schema-reader.js +506 -564
- package/dist/migration/slack-confirm.d.ts +2 -2
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/migration/slack-confirm.js +205 -193
- package/dist/migration/types.d.ts +2 -2
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/migration/types.js +1 -3
- package/dist/naite/messaging-types.d.ts +1 -0
- package/dist/naite/messaging-types.d.ts.map +1 -1
- package/dist/naite/messaging-types.js +1 -7
- package/dist/naite/naite-reporter.d.ts +2 -2
- package/dist/naite/naite-reporter.d.ts.map +1 -1
- package/dist/naite/naite-reporter.js +127 -120
- package/dist/naite/naite.d.ts +3 -2
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +266 -300
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +13 -3
- package/dist/ssr/registry.d.ts +1 -1
- package/dist/ssr/registry.d.ts.map +1 -1
- package/dist/ssr/registry.js +45 -37
- package/dist/ssr/renderer.d.ts +4 -4
- package/dist/ssr/renderer.d.ts.map +1 -1
- package/dist/ssr/renderer.js +84 -91
- package/dist/ssr/types.d.ts +2 -2
- package/dist/ssr/types.d.ts.map +1 -1
- package/dist/ssr/types.js +1 -3
- package/dist/storage/base-file.js +54 -41
- package/dist/storage/buffered-file.d.ts +2 -2
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.js +51 -44
- package/dist/storage/drivers.d.ts +2 -2
- package/dist/storage/drivers.d.ts.map +1 -1
- package/dist/storage/drivers.js +12 -7
- package/dist/storage/index.js +14 -7
- package/dist/storage/s3-driver.d.ts +2 -2
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/s3-driver.js +52 -48
- package/dist/storage/storage-manager.d.ts +2 -2
- package/dist/storage/storage-manager.d.ts.map +1 -1
- package/dist/storage/storage-manager.js +33 -25
- package/dist/storage/types.d.ts +2 -2
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +1 -5
- package/dist/storage/uploaded-file.d.ts +1 -1
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/storage/uploaded-file.js +45 -35
- package/dist/stream/index.js +7 -2
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +72 -67
- package/dist/syncer/api-parser.d.ts +1 -1
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +224 -245
- package/dist/syncer/checksum.d.ts +1 -1
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +86 -72
- package/dist/syncer/code-generator.d.ts +2 -2
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +154 -160
- package/dist/syncer/entity-operations.d.ts +1 -1
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +63 -54
- package/dist/syncer/file-patterns.d.ts +1 -1
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +38 -38
- package/dist/syncer/index.js +19 -8
- package/dist/syncer/module-loader.d.ts +5 -5
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +83 -78
- package/dist/syncer/syncer-actions.d.ts +2 -2
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +76 -91
- package/dist/syncer/syncer.d.ts +7 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +426 -492
- package/dist/tasks/decorator.d.ts +3 -3
- package/dist/tasks/decorator.d.ts.map +1 -1
- package/dist/tasks/decorator.js +32 -28
- package/dist/tasks/step-wrapper.d.ts +1 -1
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.js +42 -41
- package/dist/tasks/workflow-manager.d.ts +2 -2
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +192 -221
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +103 -103
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +163 -163
- package/dist/template/implementations/entity.template.d.ts +1 -1
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.js +76 -85
- package/dist/template/implementations/entry-server.template.d.ts +1 -1
- package/dist/template/implementations/entry-server.template.d.ts.map +1 -1
- package/dist/template/implementations/entry-server.template.js +32 -27
- package/dist/template/implementations/generated.template.d.ts +1 -1
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +254 -275
- package/dist/template/implementations/generated_http.template.d.ts +2 -2
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +114 -133
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +249 -275
- package/dist/template/implementations/init_types.template.d.ts +1 -1
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.js +40 -34
- package/dist/template/implementations/model.template.d.ts +1 -1
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +56 -53
- package/dist/template/implementations/model_test.template.d.ts +1 -1
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.js +32 -24
- package/dist/template/implementations/queries.template.d.ts +1 -1
- package/dist/template/implementations/queries.template.d.ts.map +1 -1
- package/dist/template/implementations/queries.template.js +84 -89
- package/dist/template/implementations/sd.template.d.ts +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +137 -144
- package/dist/template/implementations/services.template.d.ts +1 -1
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +164 -189
- package/dist/template/implementations/view_form.template.d.ts +1 -1
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +258 -285
- package/dist/template/implementations/view_id_all_select.template.d.ts +1 -1
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.js +31 -25
- package/dist/template/implementations/view_list.template.d.ts +1 -1
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +304 -355
- package/dist/template/implementations/view_search_input.template.d.ts +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +31 -27
- package/dist/template/index.js +21 -7
- package/dist/template/template-manager.d.ts +1 -1
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template-manager.js +132 -123
- package/dist/template/template-types.js +8 -6
- package/dist/template/template.d.ts +2 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +73 -68
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +603 -657
- package/dist/testing/_relation-graph.d.ts +1 -1
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +93 -88
- package/dist/testing/bootstrap.d.ts +22 -13
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +114 -114
- package/dist/testing/data-explorer.d.ts +3 -3
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +237 -265
- package/dist/testing/dev-test-routes.d.ts +2 -2
- package/dist/testing/dev-test-routes.d.ts.map +1 -1
- package/dist/testing/dev-test-routes.js +258 -249
- package/dist/testing/dev-vitest-manager.d.ts +1 -1
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.js +514 -539
- package/dist/testing/faker-mappings.js +422 -420
- package/dist/testing/fixture-generator.d.ts +3 -3
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +1216 -1346
- package/dist/testing/fixture-loader.js +26 -25
- package/dist/testing/fixture-manager.d.ts +3 -3
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +706 -776
- package/dist/testing/global-setup.js +53 -49
- package/dist/testing/index.js +19 -11
- package/dist/testing/naite-vitest-reporter.js +18 -13
- package/dist/testing/parallel-db-manager.d.ts +1 -1
- package/dist/testing/parallel-db-manager.d.ts.map +1 -1
- package/dist/testing/parallel-db-manager.js +63 -78
- package/dist/testing/vitest-helpers.d.ts +1 -1
- package/dist/testing/vitest-helpers.d.ts.map +1 -1
- package/dist/testing/vitest-helpers.js +37 -33
- package/dist/types/types.d.ts +28 -28
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +764 -890
- package/dist/ui/ai-api.d.ts +1 -1
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +52 -42
- package/dist/ui/ai-client.d.ts +1 -2
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +353 -388
- package/dist/ui/api.d.ts +1 -1
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +903 -1145
- package/dist/ui/cdd-service.d.ts +1 -1
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +406 -407
- package/dist/ui/cdd-types.js +1 -3
- package/dist/ui-web/assets/index-C-Zz-wYg.css +1 -0
- package/dist/ui-web/assets/index-DejDON8K.js +238 -0
- package/dist/ui-web/index.html +3 -3
- package/dist/utils/async-utils.js +57 -45
- package/dist/utils/console-util.d.ts.map +1 -1
- package/dist/utils/console-util.js +104 -87
- package/dist/utils/controller.js +26 -19
- package/dist/utils/esm-utils.js +49 -38
- package/dist/utils/formatter.d.ts +1 -2
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +89 -115
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +68 -65
- package/dist/utils/lodash-able.js +11 -4
- package/dist/utils/model.d.ts +1 -1
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +21 -19
- package/dist/utils/object-utils.js +148 -186
- package/dist/utils/path-utils.js +67 -57
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +37 -31
- package/dist/utils/sql-parser.d.ts +1 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +40 -40
- package/dist/utils/type-utils.js +44 -43
- package/dist/utils/utils.d.ts +2 -3
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +81 -93
- package/dist/utils/zod-error.d.ts +1 -1
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +24 -17
- package/dist/vector/chunking.d.ts +1 -1
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/chunking.js +100 -94
- package/dist/vector/config.d.ts +1 -1
- package/dist/vector/config.d.ts.map +1 -1
- package/dist/vector/config.js +76 -78
- package/dist/vector/embedding.d.ts +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +128 -125
- package/dist/vector/index.js +5 -5
- package/dist/vector/types.js +1 -5
- package/package.json +31 -36
- package/src/ai/agents/agent.ts +12 -5
- package/src/ai/agents/types.ts +5 -5
- package/src/ai/providers/rtzr/model.ts +8 -10
- package/src/ai/providers/rtzr/options.ts +2 -1
- package/src/ai/providers/rtzr/provider.ts +5 -3
- package/src/ai/providers/rtzr/utils.ts +2 -7
- package/src/api/__tests__/config.test.ts +15 -8
- package/src/api/base-frame.ts +5 -3
- package/src/api/caster.ts +7 -6
- package/src/api/code-converters.ts +23 -26
- package/src/api/config.ts +23 -17
- package/src/api/context.ts +18 -11
- package/src/api/decorators.ts +17 -18
- package/src/api/sonamu.ts +44 -49
- package/src/auth/auth-generator.ts +4 -6
- package/src/auth/better-auth-entities.ts +3 -2
- package/src/auth/knex-adapter.ts +6 -5
- package/src/auth/plugins/entity-definitions/admin.ts +1 -1
- package/src/auth/plugins/entity-definitions/anonymous.ts +1 -1
- package/src/auth/plugins/entity-definitions/api-key.ts +1 -1
- package/src/auth/plugins/entity-definitions/index.ts +1 -1
- package/src/auth/plugins/entity-definitions/jwt.ts +1 -1
- package/src/auth/plugins/entity-definitions/organization.ts +1 -1
- package/src/auth/plugins/entity-definitions/passkey.ts +1 -1
- package/src/auth/plugins/entity-definitions/phone-number.ts +1 -1
- package/src/auth/plugins/entity-definitions/sso.ts +1 -1
- package/src/auth/plugins/entity-definitions/two-factor.ts +1 -1
- package/src/auth/plugins/entity-definitions/types.ts +1 -1
- package/src/auth/plugins/entity-definitions/username.ts +1 -1
- package/src/auth/plugins/wrappers/admin.ts +3 -1
- package/src/auth/plugins/wrappers/anonymous.ts +3 -1
- package/src/auth/plugins/wrappers/api-key.ts +3 -1
- package/src/auth/plugins/wrappers/jwt.ts +3 -1
- package/src/auth/plugins/wrappers/organization.ts +3 -1
- package/src/auth/plugins/wrappers/passkey.ts +3 -1
- package/src/auth/plugins/wrappers/phone-number.ts +3 -1
- package/src/auth/plugins/wrappers/sso.ts +2 -1
- package/src/auth/plugins/wrappers/two-factor.ts +3 -1
- package/src/auth/plugins/wrappers/username.ts +3 -1
- package/src/bin/__tests__/ts-loader-register.test.ts +7 -12
- package/src/bin/build-config.ts +3 -3
- package/src/bin/cli.ts +27 -25
- package/src/bin/fixture.ts +4 -2
- package/src/bin/hmr-hook-register.ts +1 -0
- package/src/bin/test-command.ts +4 -2
- package/src/bin/ts-loader-registration.ts +6 -22
- package/src/cache/cache-manager.ts +2 -1
- package/src/cache/decorator.ts +2 -2
- package/src/cache/types.ts +3 -3
- package/src/cache-control/cache-control.ts +3 -2
- package/src/cache-control/types.ts +2 -2
- package/src/compress/compress.ts +1 -1
- package/src/cone/cone-generator.ts +5 -3
- package/src/database/_batch_update.ts +1 -1
- package/src/database/base-model.ts +20 -14
- package/src/database/base-model.types.ts +12 -11
- package/src/database/db.ts +56 -21
- package/src/database/knex.ts +2 -2
- package/src/database/puri-subset.test-d.ts +33 -32
- package/src/database/puri-subset.types.ts +6 -7
- package/src/database/puri-wrapper.ts +29 -26
- package/src/database/puri.ts +36 -34
- package/src/database/puri.types.test-d.ts +6 -5
- package/src/database/puri.types.ts +9 -12
- package/src/database/transaction-context.ts +2 -2
- package/src/database/upsert-builder.ts +17 -10
- package/src/dict/sd.ts +17 -4
- package/src/dict/sonamu-dictionary.ts +23 -17
- package/src/entity/entity-manager.ts +9 -7
- package/src/entity/entity-template-cone.ts +10 -3
- package/src/entity/entity.ts +20 -16
- package/src/exceptions/error-handler.ts +2 -1
- package/src/exceptions/so-exceptions.ts +1 -1
- package/src/filter/utils.ts +3 -2
- package/src/logger/category.ts +1 -0
- package/src/logger/configure.ts +5 -5
- package/src/migration/__tests__/code-generation.search-text.test.ts +2 -3
- package/src/migration/code-generation.ts +26 -25
- package/src/migration/migration-set.ts +16 -18
- package/src/migration/migrator.ts +38 -33
- package/src/migration/postgresql-schema-reader.ts +12 -12
- package/src/migration/slack-confirm.ts +5 -4
- package/src/migration/types.ts +2 -2
- package/src/naite/messaging-types.ts +1 -1
- package/src/naite/naite-reporter.ts +5 -3
- package/src/naite/naite.ts +12 -7
- package/src/shared/app.shared.ts.txt +2 -2
- package/src/shared/web.shared.ts.txt +2 -2
- package/src/skills/AGENTS.md +19 -18
- package/src/skills/commands/sonamu-skills.md +9 -9
- package/src/skills/sonamu/SKILL.md +111 -104
- package/src/skills/sonamu/ai-agents.md +27 -26
- package/src/skills/sonamu/api.md +81 -69
- package/src/skills/sonamu/auth-migration.md +13 -27
- package/src/skills/sonamu/auth-plugins.md +41 -31
- package/src/skills/sonamu/auth.md +30 -24
- package/src/skills/sonamu/cdd.md +26 -17
- package/src/skills/sonamu/cone.md +50 -50
- package/src/skills/sonamu/config.md +74 -51
- package/src/skills/sonamu/create-sonamu.md +31 -19
- package/src/skills/sonamu/database.md +43 -26
- package/src/skills/sonamu/entity-basic.md +61 -61
- package/src/skills/sonamu/entity-relations.md +84 -80
- package/src/skills/sonamu/entity-validation-checklist.md +19 -15
- package/src/skills/sonamu/fixture-cli.md +52 -30
- package/src/skills/sonamu/framework-change.md +9 -7
- package/src/skills/sonamu/frontend.md +64 -82
- package/src/skills/sonamu/i18n.md +45 -37
- package/src/skills/sonamu/migration.md +54 -31
- package/src/skills/sonamu/model.md +98 -66
- package/src/skills/sonamu/naite.md +34 -32
- package/src/skills/sonamu/project-init.md +28 -8
- package/src/skills/sonamu/puri.md +82 -91
- package/src/skills/sonamu/scaffolding.md +44 -32
- package/src/skills/sonamu/skill-contribution.md +50 -45
- package/src/skills/sonamu/subset.md +13 -13
- package/src/skills/sonamu/tasks.md +73 -58
- package/src/skills/sonamu/testing-devrunner.md +56 -36
- package/src/skills/sonamu/testing.md +23 -58
- package/src/skills/sonamu/upsert.md +32 -31
- package/src/skills/sonamu/vector.md +37 -36
- package/src/ssr/index.ts +2 -12
- package/src/ssr/registry.ts +1 -1
- package/src/ssr/renderer.ts +7 -5
- package/src/ssr/types.ts +2 -2
- package/src/storage/buffered-file.ts +4 -2
- package/src/storage/drivers.ts +3 -2
- package/src/storage/s3-driver.ts +7 -4
- package/src/storage/storage-manager.ts +3 -2
- package/src/storage/types.ts +3 -2
- package/src/storage/uploaded-file.ts +1 -1
- package/src/stream/sse.ts +2 -2
- package/src/syncer/api-parser.ts +8 -5
- package/src/syncer/checksum.ts +9 -5
- package/src/syncer/code-generator.ts +16 -8
- package/src/syncer/entity-operations.ts +5 -3
- package/src/syncer/file-patterns.ts +2 -1
- package/src/syncer/module-loader.ts +9 -6
- package/src/syncer/syncer-actions.ts +5 -3
- package/src/syncer/syncer.ts +18 -24
- package/src/tasks/decorator.ts +10 -8
- package/src/tasks/step-wrapper.ts +1 -1
- package/src/tasks/workflow-manager.ts +18 -15
- package/src/template/__tests__/generated.template.search-text.test.ts +1 -0
- package/src/template/entity-converter.ts +4 -2
- package/src/template/generated.template.test-d.ts +2 -1
- package/src/template/helpers.ts +5 -2
- package/src/template/implementations/entity.template.ts +9 -8
- package/src/template/implementations/entry-server.template.ts +1 -1
- package/src/template/implementations/generated.template.ts +21 -29
- package/src/template/implementations/generated_http.template.ts +9 -6
- package/src/template/implementations/generated_sso.template.ts +6 -4
- package/src/template/implementations/init_types.template.ts +3 -2
- package/src/template/implementations/model.template.ts +4 -2
- package/src/template/implementations/model_test.template.ts +3 -2
- package/src/template/implementations/queries.template.ts +6 -14
- package/src/template/implementations/sd.template.ts +4 -2
- package/src/template/implementations/services.template.ts +7 -11
- package/src/template/implementations/view_form.template.ts +5 -3
- package/src/template/implementations/view_id_all_select.template.ts +3 -2
- package/src/template/implementations/view_list.template.ts +7 -5
- package/src/template/implementations/view_search_input.template.ts +3 -2
- package/src/template/template-manager.ts +4 -3
- package/src/template/template.ts +4 -3
- package/src/template/zod-converter.ts +10 -7
- package/src/testing/__tests__/dev-test-routes.test.ts +3 -2
- package/src/testing/__tests__/dev-vitest-manager.test.ts +1 -0
- package/src/testing/_relation-graph.ts +2 -2
- package/src/testing/bootstrap.ts +55 -27
- package/src/testing/data-explorer.ts +5 -4
- package/src/testing/dev-test-routes.ts +8 -5
- package/src/testing/dev-vitest-manager.ts +13 -12
- package/src/testing/fixture-generator.ts +11 -17
- package/src/testing/fixture-manager.ts +21 -17
- package/src/testing/parallel-db-manager.ts +2 -1
- package/src/testing/vitest-helpers.ts +2 -1
- package/src/types/__tests__/entity-json-schema-search-text.test.ts +1 -0
- package/src/types/types.ts +8 -8
- package/src/typings/knex.d.ts +4 -4
- package/src/ui/ai-api.ts +5 -3
- package/src/ui/ai-client.ts +6 -5
- package/src/ui/api.ts +25 -23
- package/src/ui/cdd-service.ts +12 -11
- package/src/utils/console-util.ts +3 -1
- package/src/utils/formatter.ts +94 -102
- package/src/utils/fs-utils.ts +2 -1
- package/src/utils/model.ts +2 -2
- package/src/utils/object-utils.ts +3 -3
- package/src/utils/process-utils.ts +2 -1
- package/src/utils/sql-parser.ts +10 -1
- package/src/utils/type-utils.ts +3 -3
- package/src/utils/utils.ts +9 -7
- package/src/utils/zod-error.ts +1 -1
- package/src/vector/chunking.ts +1 -1
- package/src/vector/config.ts +1 -1
- package/src/vector/embedding.ts +11 -9
- package/tsdown.api.config.ts +50 -0
- package/.swcrc.project-default +0 -18
- package/dist/api/__tests__/config.test.js +0 -189
- package/dist/bin/__tests__/test-command.test.js +0 -112
- package/dist/bin/__tests__/ts-loader-register.test.js +0 -45
- package/dist/database/puri-subset.test-d.js +0 -89
- package/dist/database/puri.types.test-d.js +0 -129
- package/dist/migration/__tests__/code-generation.search-text.test.js +0 -435
- package/dist/template/__tests__/generated.template.search-text.test.js +0 -99
- package/dist/template/generated.template.test-d.js +0 -24
- package/dist/testing/__tests__/dev-test-routes.test.js +0 -144
- package/dist/testing/__tests__/dev-vitest-manager.test.js +0 -152
- package/dist/types/__tests__/entity-json-schema-search-text.test.js +0 -256
- package/dist/typings/knex.d.js +0 -3
- package/dist/ui-web/assets/index-CKo0Z2Iu.css +0 -1
- package/dist/ui-web/assets/index-DK-2aacv.js +0 -257
|
@@ -1,554 +1,529 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
lastRunAt = null;
|
|
5
|
-
queue = [];
|
|
6
|
-
processing = false;
|
|
7
|
-
closed = false;
|
|
8
|
-
eventListeners = new Set();
|
|
9
|
-
currentRunContext = null;
|
|
10
|
-
addEventListener(listener) {
|
|
11
|
-
this.eventListeners.add(listener);
|
|
12
|
-
}
|
|
13
|
-
removeEventListener(listener) {
|
|
14
|
-
this.eventListeners.delete(listener);
|
|
15
|
-
}
|
|
16
|
-
emitEvent(event, data) {
|
|
17
|
-
for (const listener of this.eventListeners){
|
|
18
|
-
listener(event, data);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
async start(vitestConfigPath) {
|
|
22
|
-
// 이미 시작된 경우 중복 초기화를 방지
|
|
23
|
-
if (this.vitest) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const { createVitest } = await import("vitest/node");
|
|
27
|
-
const viteOverrides = {
|
|
28
|
-
server: {
|
|
29
|
-
watch: null
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
const cliOptions = {
|
|
33
|
-
watch: true,
|
|
34
|
-
standalone: true,
|
|
35
|
-
forceRerunTriggers: [],
|
|
36
|
-
config: vitestConfigPath,
|
|
37
|
-
env: {
|
|
38
|
-
NODE_ENV: "test"
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
const realtimeReporter = this.createRealtimeProgressReporter();
|
|
42
|
-
viteOverrides.plugins = [
|
|
43
|
-
...viteOverrides.plugins ?? [],
|
|
44
|
-
{
|
|
45
|
-
name: "sonamu-realtime-reporter",
|
|
46
|
-
configureVitest ({ vitest: vitestInstance }) {
|
|
47
|
-
const reporters = vitestInstance.config.reporters;
|
|
48
|
-
if (!reporters.includes(realtimeReporter)) {
|
|
49
|
-
reporters.push(realtimeReporter);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
];
|
|
54
|
-
const vitest = await createVitest("test", cliOptions, viteOverrides);
|
|
55
|
-
try {
|
|
56
|
-
await vitest.init();
|
|
57
|
-
} catch (err) {
|
|
58
|
-
await vitest.close();
|
|
59
|
-
throw err;
|
|
60
|
-
}
|
|
61
|
-
this.vitest = vitest;
|
|
62
|
-
this.vitest.onFilterWatchedSpecification((_spec)=>false);
|
|
63
|
-
this.closed = false;
|
|
64
|
-
}
|
|
65
|
-
async run(opts, runId) {
|
|
66
|
-
if (this.closed) {
|
|
67
|
-
throw new Error("DevVitestManager is already shut down");
|
|
68
|
-
}
|
|
69
|
-
if (!this.vitest) {
|
|
70
|
-
throw new Error("DevVitestManager is not started");
|
|
71
|
-
}
|
|
72
|
-
return new Promise((resolve, reject)=>{
|
|
73
|
-
const task = ()=>this.executeRun(opts, runId);
|
|
74
|
-
this.queue.push({
|
|
75
|
-
runId,
|
|
76
|
-
task,
|
|
77
|
-
resolve,
|
|
78
|
-
reject
|
|
79
|
-
});
|
|
80
|
-
this.processQueue();
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
getStatus() {
|
|
84
|
-
return {
|
|
85
|
-
ready: this.vitest !== null && !this.closed,
|
|
86
|
-
running: this.running,
|
|
87
|
-
lastRunAt: this.lastRunAt
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* 변경된 파일을 Vitest 모듈 그래프에서 무효화합니다.
|
|
92
|
-
* syncFromWatcher에서 호출되어 다음 테스트 실행 시 최신 코드를 사용하도록 합니다.
|
|
93
|
-
*/ invalidateFiles(filePaths) {
|
|
94
|
-
if (!this.vitest || this.closed) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
for (const filePath of filePaths){
|
|
98
|
-
this.vitest.invalidateFile(filePath);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
async shutdown() {
|
|
102
|
-
if (this.closed) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
this.closed = true;
|
|
106
|
-
// 큐에 남은 작업들을 reject하여 호출자가 영구 대기하지 않도록 정리
|
|
107
|
-
while(this.queue.length > 0){
|
|
108
|
-
const entry = this.queue.shift();
|
|
109
|
-
if (entry) {
|
|
110
|
-
entry.reject(new Error("DevVitestManager is being shut down"));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (this.vitest) {
|
|
114
|
-
await this.vitest.close();
|
|
115
|
-
this.vitest = null;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async processQueue() {
|
|
119
|
-
if (this.processing) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
this.processing = true;
|
|
123
|
-
try {
|
|
124
|
-
while(this.queue.length > 0){
|
|
125
|
-
const entry = this.queue.shift();
|
|
126
|
-
if (!entry) break;
|
|
127
|
-
if (this.closed) {
|
|
128
|
-
entry.reject(new Error("DevVitestManager is already shut down"));
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
try {
|
|
132
|
-
const result = await entry.task();
|
|
133
|
-
entry.resolve(result);
|
|
134
|
-
} catch (err) {
|
|
135
|
-
entry.reject(err);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
} finally{
|
|
139
|
-
this.processing = false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async executeRun(opts, runId) {
|
|
143
|
-
const vitest = this.vitest;
|
|
144
|
-
if (!vitest) {
|
|
145
|
-
throw new Error("DevVitestManager is not started");
|
|
146
|
-
}
|
|
147
|
-
this.running = true;
|
|
148
|
-
const startTime = Date.now();
|
|
149
|
-
if (opts.pattern) {
|
|
150
|
-
vitest.setGlobalTestNamePattern(opts.pattern);
|
|
151
|
-
}
|
|
152
|
-
try {
|
|
153
|
-
const specs = opts.files ? await vitest.globTestSpecifications(opts.files) : await vitest.globTestSpecifications();
|
|
154
|
-
const specModuleIds = new Set(specs.map((s)=>s.moduleId));
|
|
155
|
-
// routes에서 생성한 runId를 그대로 사용하여 runStarted/runNodeProgress/runCompleted 간 일관성 보장
|
|
156
|
-
this.currentRunContext = {
|
|
157
|
-
runId,
|
|
158
|
-
startedAt: new Date().toISOString(),
|
|
159
|
-
specModuleIds
|
|
160
|
-
};
|
|
161
|
-
const allTestsRun = !opts.files || opts.files.length === 0;
|
|
162
|
-
const runResult = await vitest.runTestSpecifications(specs, allTestsRun);
|
|
163
|
-
const durationMs = Date.now() - startTime;
|
|
164
|
-
this.lastRunAt = new Date().toISOString();
|
|
165
|
-
return this.collectResults(runResult, durationMs, specModuleIds);
|
|
166
|
-
} finally{
|
|
167
|
-
this.currentRunContext = null;
|
|
168
|
-
if (opts.pattern) {
|
|
169
|
-
vitest.resetGlobalTestNamePattern();
|
|
170
|
-
}
|
|
171
|
-
this.running = false;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
createRealtimeProgressReporter() {
|
|
175
|
-
const emitProgress = (kind, phase, fileId, nodeId, parentId, node)=>{
|
|
176
|
-
const ctx = this.currentRunContext;
|
|
177
|
-
if (!ctx) return;
|
|
178
|
-
this.emitEvent("runNodeProgress", {
|
|
179
|
-
schemaVersion: 1,
|
|
180
|
-
runId: ctx.runId,
|
|
181
|
-
startedAt: ctx.startedAt,
|
|
182
|
-
at: new Date().toISOString(),
|
|
183
|
-
kind,
|
|
184
|
-
phase,
|
|
185
|
-
fileId,
|
|
186
|
-
nodeId,
|
|
187
|
-
parentId,
|
|
188
|
-
node
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
return {
|
|
192
|
-
onTestModuleQueued: (testModule)=>{
|
|
193
|
-
const ctx = this.currentRunContext;
|
|
194
|
-
if (!ctx || !ctx.specModuleIds.has(testModule.moduleId)) return;
|
|
195
|
-
const fileId = testModule.moduleId;
|
|
196
|
-
emitProgress("file", "ready", fileId, fileId, null, this.buildFileProgressNode(testModule, "ready"));
|
|
197
|
-
},
|
|
198
|
-
onTestModuleEnd: (testModule)=>{
|
|
199
|
-
const ctx = this.currentRunContext;
|
|
200
|
-
if (!ctx || !ctx.specModuleIds.has(testModule.moduleId)) return;
|
|
201
|
-
const fileId = testModule.moduleId;
|
|
202
|
-
emitProgress("file", "result", fileId, fileId, null, this.buildFileNode(testModule));
|
|
203
|
-
},
|
|
204
|
-
onTestSuiteReady: (testSuite)=>{
|
|
205
|
-
const ctx = this.currentRunContext;
|
|
206
|
-
if (!ctx || !ctx.specModuleIds.has(testSuite.module.moduleId)) return;
|
|
207
|
-
const fileId = testSuite.module.moduleId;
|
|
208
|
-
const nodeId = `${fileId}::${testSuite.fullName}`;
|
|
209
|
-
const parentId = this.resolveSuiteParentId(testSuite);
|
|
210
|
-
emitProgress("suite", "ready", fileId, nodeId, parentId, this.buildSuiteProgressNode(testSuite, "ready"));
|
|
211
|
-
},
|
|
212
|
-
onTestSuiteResult: (testSuite)=>{
|
|
213
|
-
const ctx = this.currentRunContext;
|
|
214
|
-
if (!ctx || !ctx.specModuleIds.has(testSuite.module.moduleId)) return;
|
|
215
|
-
const fileId = testSuite.module.moduleId;
|
|
216
|
-
const nodeId = `${fileId}::${testSuite.fullName}`;
|
|
217
|
-
const parentId = this.resolveSuiteParentId(testSuite);
|
|
218
|
-
emitProgress("suite", "result", fileId, nodeId, parentId, this.buildSuiteNode(testSuite, fileId));
|
|
219
|
-
},
|
|
220
|
-
onTestCaseReady: (testCase)=>{
|
|
221
|
-
const ctx = this.currentRunContext;
|
|
222
|
-
if (!ctx || !ctx.specModuleIds.has(testCase.module.moduleId)) return;
|
|
223
|
-
const fileId = testCase.module.moduleId;
|
|
224
|
-
const nodeId = `${fileId}::${testCase.fullName}`;
|
|
225
|
-
const parentId = this.resolveTestParentId(testCase);
|
|
226
|
-
emitProgress("test", "ready", fileId, nodeId, parentId, this.buildTestProgressNode(testCase, "ready"));
|
|
227
|
-
},
|
|
228
|
-
onTestCaseResult: (testCase)=>{
|
|
229
|
-
const ctx = this.currentRunContext;
|
|
230
|
-
if (!ctx || !ctx.specModuleIds.has(testCase.module.moduleId)) return;
|
|
231
|
-
const fileId = testCase.module.moduleId;
|
|
232
|
-
const nodeId = `${fileId}::${testCase.fullName}`;
|
|
233
|
-
const parentId = this.resolveTestParentId(testCase);
|
|
234
|
-
emitProgress("test", "result", fileId, nodeId, parentId, this.buildTestNode(testCase, fileId));
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
buildFileProgressNode(testModule, _phase) {
|
|
239
|
-
return {
|
|
240
|
-
id: testModule.moduleId,
|
|
241
|
-
kind: "file",
|
|
242
|
-
name: testModule.moduleId,
|
|
243
|
-
fullName: testModule.moduleId,
|
|
244
|
-
file: testModule.moduleId,
|
|
245
|
-
state: "running",
|
|
246
|
-
durationMs: null,
|
|
247
|
-
counts: {
|
|
248
|
-
total: 0,
|
|
249
|
-
passed: 0,
|
|
250
|
-
failed: 0,
|
|
251
|
-
skipped: 0
|
|
252
|
-
},
|
|
253
|
-
error: null,
|
|
254
|
-
traces: [],
|
|
255
|
-
children: []
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
buildSuiteProgressNode(testSuite, _phase) {
|
|
259
|
-
const fileId = testSuite.module.moduleId;
|
|
260
|
-
return {
|
|
261
|
-
id: `${fileId}::${testSuite.fullName}`,
|
|
262
|
-
kind: "suite",
|
|
263
|
-
name: testSuite.name,
|
|
264
|
-
fullName: testSuite.fullName,
|
|
265
|
-
file: fileId,
|
|
266
|
-
state: "running",
|
|
267
|
-
durationMs: null,
|
|
268
|
-
counts: {
|
|
269
|
-
total: 0,
|
|
270
|
-
passed: 0,
|
|
271
|
-
failed: 0,
|
|
272
|
-
skipped: 0
|
|
273
|
-
},
|
|
274
|
-
error: null,
|
|
275
|
-
traces: [],
|
|
276
|
-
children: []
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
buildTestProgressNode(testCase, _phase) {
|
|
280
|
-
const fileId = testCase.module.moduleId;
|
|
281
|
-
return {
|
|
282
|
-
id: `${fileId}::${testCase.fullName}`,
|
|
283
|
-
kind: "test",
|
|
284
|
-
name: testCase.name,
|
|
285
|
-
fullName: testCase.fullName,
|
|
286
|
-
file: fileId,
|
|
287
|
-
state: "running",
|
|
288
|
-
durationMs: null,
|
|
289
|
-
counts: {
|
|
290
|
-
total: 1,
|
|
291
|
-
passed: 0,
|
|
292
|
-
failed: 0,
|
|
293
|
-
skipped: 0
|
|
294
|
-
},
|
|
295
|
-
error: null,
|
|
296
|
-
traces: [],
|
|
297
|
-
children: []
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
resolveSuiteParentId(testSuite) {
|
|
301
|
-
const parent = testSuite.parent;
|
|
302
|
-
if (parent.type === "suite") {
|
|
303
|
-
return `${testSuite.module.moduleId}::${parent.fullName}`;
|
|
304
|
-
}
|
|
305
|
-
return testSuite.module.moduleId;
|
|
306
|
-
}
|
|
307
|
-
resolveTestParentId(testCase) {
|
|
308
|
-
const parent = testCase.parent;
|
|
309
|
-
if (parent.type === "suite") {
|
|
310
|
-
return `${testCase.module.moduleId}::${parent.fullName}`;
|
|
311
|
-
}
|
|
312
|
-
return testCase.module.moduleId;
|
|
313
|
-
}
|
|
314
|
-
collectResults(runResult, durationMs, specModuleIds) {
|
|
315
|
-
const resultsByFile = new Map();
|
|
316
|
-
for (const testModule of runResult.testModules){
|
|
317
|
-
if (!specModuleIds.has(testModule.moduleId)) continue;
|
|
318
|
-
const nextResult = this.buildFileNode(testModule);
|
|
319
|
-
const existingResult = resultsByFile.get(nextResult.id);
|
|
320
|
-
if (!existingResult) {
|
|
321
|
-
resultsByFile.set(nextResult.id, nextResult);
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
const existingScore = getResultCompletenessScore(existingResult);
|
|
325
|
-
const nextScore = getResultCompletenessScore(nextResult);
|
|
326
|
-
if (nextScore >= existingScore) {
|
|
327
|
-
resultsByFile.set(nextResult.id, nextResult);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
const results = Array.from(resultsByFile.values());
|
|
331
|
-
const summary = aggregateCounts(results);
|
|
332
|
-
return {
|
|
333
|
-
ok: summary.failed === 0,
|
|
334
|
-
summary: {
|
|
335
|
-
...summary,
|
|
336
|
-
durationMs
|
|
337
|
-
},
|
|
338
|
-
results
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
buildFileNode(testModule) {
|
|
342
|
-
const file = testModule.moduleId;
|
|
343
|
-
const children = this.buildChildNodes(testModule, file);
|
|
344
|
-
const counts = aggregateCounts(children);
|
|
345
|
-
const moduleState = testModule.state();
|
|
346
|
-
const diagnostic = testModule.diagnostic();
|
|
347
|
-
return {
|
|
348
|
-
id: testModule.moduleId,
|
|
349
|
-
kind: "file",
|
|
350
|
-
name: testModule.moduleId,
|
|
351
|
-
fullName: testModule.moduleId,
|
|
352
|
-
file,
|
|
353
|
-
state: mapModuleState(moduleState),
|
|
354
|
-
durationMs: diagnostic.duration > 0 ? diagnostic.duration : null,
|
|
355
|
-
counts,
|
|
356
|
-
error: null,
|
|
357
|
-
traces: [],
|
|
358
|
-
children
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
buildChildNodes(parent, file) {
|
|
362
|
-
const result = [];
|
|
363
|
-
for (const child of parent.children){
|
|
364
|
-
if (child.type === "suite") {
|
|
365
|
-
result.push(this.buildSuiteNode(child, file));
|
|
366
|
-
} else {
|
|
367
|
-
result.push(this.buildTestNode(child, file));
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return result;
|
|
371
|
-
}
|
|
372
|
-
buildSuiteNode(suite, file) {
|
|
373
|
-
const children = this.buildChildNodes(suite, file);
|
|
374
|
-
const counts = aggregateCounts(children);
|
|
375
|
-
const suiteState = suite.state();
|
|
376
|
-
return {
|
|
377
|
-
id: `${file}::${suite.fullName}`,
|
|
378
|
-
kind: "suite",
|
|
379
|
-
name: suite.name,
|
|
380
|
-
fullName: suite.fullName,
|
|
381
|
-
file,
|
|
382
|
-
state: mapSuiteState(suiteState),
|
|
383
|
-
durationMs: null,
|
|
384
|
-
counts,
|
|
385
|
-
error: null,
|
|
386
|
-
traces: [],
|
|
387
|
-
children
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
buildTestNode(testCase, file) {
|
|
391
|
-
const result = testCase.result();
|
|
392
|
-
const diagnostic = testCase.diagnostic();
|
|
393
|
-
const state = mapTestResult(result, testCase.options.mode);
|
|
394
|
-
let error = null;
|
|
395
|
-
if (result.state === "failed" && result.errors.length > 0) {
|
|
396
|
-
const firstError = result.errors[0];
|
|
397
|
-
error = {
|
|
398
|
-
message: firstError.message ?? String(firstError),
|
|
399
|
-
stack: firstError.stack
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
const raw = testCase.meta().traces;
|
|
403
|
-
let traces = [];
|
|
404
|
-
if (Array.isArray(raw) && raw.length > 0) {
|
|
405
|
-
traces = raw.filter(isSerializedTrace);
|
|
406
|
-
}
|
|
407
|
-
return {
|
|
408
|
-
id: `${file}::${testCase.fullName}`,
|
|
409
|
-
kind: "test",
|
|
410
|
-
name: testCase.name,
|
|
411
|
-
fullName: testCase.fullName,
|
|
412
|
-
file,
|
|
413
|
-
state,
|
|
414
|
-
durationMs: diagnostic ? diagnostic.duration : null,
|
|
415
|
-
counts: countFromState(state),
|
|
416
|
-
error,
|
|
417
|
-
traces,
|
|
418
|
-
children: []
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
}
|
|
1
|
+
import { __esmMin } from "../_virtual/rolldown_runtime.js";
|
|
2
|
+
|
|
3
|
+
//#region src/testing/dev-vitest-manager.ts
|
|
422
4
|
function mapModuleState(state) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
case "queued":
|
|
432
|
-
return "running";
|
|
433
|
-
default:
|
|
434
|
-
return "unknown";
|
|
435
|
-
}
|
|
5
|
+
switch (state) {
|
|
6
|
+
case "passed": return "passed";
|
|
7
|
+
case "failed": return "failed";
|
|
8
|
+
case "skipped": return "skipped";
|
|
9
|
+
case "pending":
|
|
10
|
+
case "queued": return "running";
|
|
11
|
+
default: return "unknown";
|
|
12
|
+
}
|
|
436
13
|
}
|
|
437
14
|
function mapSuiteState(state) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
case "pending":
|
|
446
|
-
return "running";
|
|
447
|
-
default:
|
|
448
|
-
return "unknown";
|
|
449
|
-
}
|
|
15
|
+
switch (state) {
|
|
16
|
+
case "passed": return "passed";
|
|
17
|
+
case "failed": return "failed";
|
|
18
|
+
case "skipped": return "skipped";
|
|
19
|
+
case "pending": return "running";
|
|
20
|
+
default: return "unknown";
|
|
21
|
+
}
|
|
450
22
|
}
|
|
451
23
|
function mapTestResult(result, mode) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
case "pending":
|
|
460
|
-
return "running";
|
|
461
|
-
default:
|
|
462
|
-
return "unknown";
|
|
463
|
-
}
|
|
24
|
+
switch (result.state) {
|
|
25
|
+
case "passed": return "passed";
|
|
26
|
+
case "failed": return "failed";
|
|
27
|
+
case "skipped": return mode === "todo" ? "todo" : "skipped";
|
|
28
|
+
case "pending": return "running";
|
|
29
|
+
default: return "unknown";
|
|
30
|
+
}
|
|
464
31
|
}
|
|
465
32
|
function countFromState(state) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
passed: 0,
|
|
494
|
-
failed: 0,
|
|
495
|
-
skipped: 0
|
|
496
|
-
};
|
|
497
|
-
}
|
|
33
|
+
switch (state) {
|
|
34
|
+
case "passed": return {
|
|
35
|
+
total: 1,
|
|
36
|
+
passed: 1,
|
|
37
|
+
failed: 0,
|
|
38
|
+
skipped: 0
|
|
39
|
+
};
|
|
40
|
+
case "failed": return {
|
|
41
|
+
total: 1,
|
|
42
|
+
passed: 0,
|
|
43
|
+
failed: 1,
|
|
44
|
+
skipped: 0
|
|
45
|
+
};
|
|
46
|
+
case "skipped":
|
|
47
|
+
case "todo": return {
|
|
48
|
+
total: 1,
|
|
49
|
+
passed: 0,
|
|
50
|
+
failed: 0,
|
|
51
|
+
skipped: 1
|
|
52
|
+
};
|
|
53
|
+
default: return {
|
|
54
|
+
total: 1,
|
|
55
|
+
passed: 0,
|
|
56
|
+
failed: 0,
|
|
57
|
+
skipped: 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
498
60
|
}
|
|
499
61
|
function aggregateCounts(children) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
62
|
+
let total = 0;
|
|
63
|
+
let passed = 0;
|
|
64
|
+
let failed = 0;
|
|
65
|
+
let skipped = 0;
|
|
66
|
+
for (const child of children) {
|
|
67
|
+
total += child.counts.total;
|
|
68
|
+
passed += child.counts.passed;
|
|
69
|
+
failed += child.counts.failed;
|
|
70
|
+
skipped += child.counts.skipped;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
total,
|
|
74
|
+
passed,
|
|
75
|
+
failed,
|
|
76
|
+
skipped
|
|
77
|
+
};
|
|
516
78
|
}
|
|
517
79
|
function getResultCompletenessScore(node) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
break;
|
|
543
|
-
}
|
|
544
|
-
return score;
|
|
80
|
+
let score = 0;
|
|
81
|
+
score += node.counts.total * 1e3;
|
|
82
|
+
score += node.children.length * 100;
|
|
83
|
+
if (node.durationMs !== null) score += 10;
|
|
84
|
+
switch (node.state) {
|
|
85
|
+
case "failed":
|
|
86
|
+
score += 5;
|
|
87
|
+
break;
|
|
88
|
+
case "passed":
|
|
89
|
+
score += 4;
|
|
90
|
+
break;
|
|
91
|
+
case "skipped":
|
|
92
|
+
score += 3;
|
|
93
|
+
break;
|
|
94
|
+
case "todo":
|
|
95
|
+
score += 2;
|
|
96
|
+
break;
|
|
97
|
+
case "running":
|
|
98
|
+
score += 1;
|
|
99
|
+
break;
|
|
100
|
+
case "unknown": break;
|
|
101
|
+
default: break;
|
|
102
|
+
}
|
|
103
|
+
return score;
|
|
545
104
|
}
|
|
546
105
|
function isSerializedTrace(value) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
106
|
+
if (typeof value !== "object" || value === null) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const v = value;
|
|
110
|
+
return typeof v.key === "string" && typeof v.filePath === "string" && typeof v.lineNumber === "number" && typeof v.at === "string" && "value" in v;
|
|
552
111
|
}
|
|
112
|
+
var DevVitestManager;
|
|
113
|
+
var init_dev_vitest_manager = __esmMin((() => {
|
|
114
|
+
DevVitestManager = class {
|
|
115
|
+
vitest = null;
|
|
116
|
+
running = false;
|
|
117
|
+
lastRunAt = null;
|
|
118
|
+
queue = [];
|
|
119
|
+
processing = false;
|
|
120
|
+
closed = false;
|
|
121
|
+
eventListeners = new Set();
|
|
122
|
+
currentRunContext = null;
|
|
123
|
+
addEventListener(listener) {
|
|
124
|
+
this.eventListeners.add(listener);
|
|
125
|
+
}
|
|
126
|
+
removeEventListener(listener) {
|
|
127
|
+
this.eventListeners.delete(listener);
|
|
128
|
+
}
|
|
129
|
+
emitEvent(event, data) {
|
|
130
|
+
for (const listener of this.eventListeners) {
|
|
131
|
+
listener(event, data);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async start(vitestConfigPath) {
|
|
135
|
+
if (this.vitest) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const { createVitest } = await import("vitest/node");
|
|
139
|
+
const viteOverrides = { server: { watch: null } };
|
|
140
|
+
const cliOptions = {
|
|
141
|
+
watch: true,
|
|
142
|
+
standalone: true,
|
|
143
|
+
forceRerunTriggers: [],
|
|
144
|
+
config: vitestConfigPath,
|
|
145
|
+
env: { NODE_ENV: "test" }
|
|
146
|
+
};
|
|
147
|
+
const realtimeReporter = this.createRealtimeProgressReporter();
|
|
148
|
+
viteOverrides.plugins = [...viteOverrides.plugins ?? [], {
|
|
149
|
+
name: "sonamu-realtime-reporter",
|
|
150
|
+
configureVitest({ vitest: vitestInstance }) {
|
|
151
|
+
const reporters = vitestInstance.config.reporters;
|
|
152
|
+
if (!reporters.includes(realtimeReporter)) {
|
|
153
|
+
reporters.push(realtimeReporter);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}];
|
|
157
|
+
const vitest = await createVitest("test", cliOptions, viteOverrides);
|
|
158
|
+
try {
|
|
159
|
+
await vitest.standalone();
|
|
160
|
+
} catch (err) {
|
|
161
|
+
await vitest.close();
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
this.vitest = vitest;
|
|
165
|
+
this.vitest.onFilterWatchedSpecification((_spec) => false);
|
|
166
|
+
this.closed = false;
|
|
167
|
+
}
|
|
168
|
+
async run(opts, runId) {
|
|
169
|
+
if (this.closed) {
|
|
170
|
+
throw new Error("DevVitestManager is already shut down");
|
|
171
|
+
}
|
|
172
|
+
if (!this.vitest) {
|
|
173
|
+
throw new Error("DevVitestManager is not started");
|
|
174
|
+
}
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
const task = () => this.executeRun(opts, runId);
|
|
177
|
+
this.queue.push({
|
|
178
|
+
runId,
|
|
179
|
+
task,
|
|
180
|
+
resolve,
|
|
181
|
+
reject
|
|
182
|
+
});
|
|
183
|
+
this.processQueue();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
getStatus() {
|
|
187
|
+
return {
|
|
188
|
+
ready: this.vitest !== null && !this.closed,
|
|
189
|
+
running: this.running,
|
|
190
|
+
lastRunAt: this.lastRunAt
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* 변경된 파일을 Vitest 모듈 그래프에서 무효화합니다.
|
|
195
|
+
* syncFromWatcher에서 호출되어 다음 테스트 실행 시 최신 코드를 사용하도록 합니다.
|
|
196
|
+
*/
|
|
197
|
+
invalidateFiles(filePaths) {
|
|
198
|
+
if (!this.vitest || this.closed) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
for (const filePath of filePaths) {
|
|
202
|
+
this.vitest.invalidateFile(filePath);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async shutdown() {
|
|
206
|
+
if (this.closed) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.closed = true;
|
|
210
|
+
while (this.queue.length > 0) {
|
|
211
|
+
const entry = this.queue.shift();
|
|
212
|
+
if (entry) {
|
|
213
|
+
entry.reject(new Error("DevVitestManager is being shut down"));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (this.vitest) {
|
|
217
|
+
await this.vitest.close();
|
|
218
|
+
this.vitest = null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async processQueue() {
|
|
222
|
+
if (this.processing) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
this.processing = true;
|
|
226
|
+
try {
|
|
227
|
+
while (this.queue.length > 0) {
|
|
228
|
+
const entry = this.queue.shift();
|
|
229
|
+
if (!entry) break;
|
|
230
|
+
if (this.closed) {
|
|
231
|
+
entry.reject(new Error("DevVitestManager is already shut down"));
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const result = await entry.task();
|
|
236
|
+
entry.resolve(result);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
entry.reject(err);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} finally {
|
|
242
|
+
this.processing = false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async executeRun(opts, runId) {
|
|
246
|
+
const vitest = this.vitest;
|
|
247
|
+
if (!vitest) {
|
|
248
|
+
throw new Error("DevVitestManager is not started");
|
|
249
|
+
}
|
|
250
|
+
this.running = true;
|
|
251
|
+
const startTime = Date.now();
|
|
252
|
+
if (opts.pattern) {
|
|
253
|
+
vitest.setGlobalTestNamePattern(opts.pattern);
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const specs = opts.files ? await vitest.globTestSpecifications(opts.files) : await vitest.globTestSpecifications();
|
|
257
|
+
const specModuleIds = new Set(specs.map((s) => s.moduleId));
|
|
258
|
+
this.currentRunContext = {
|
|
259
|
+
runId,
|
|
260
|
+
startedAt: new Date().toISOString(),
|
|
261
|
+
specModuleIds
|
|
262
|
+
};
|
|
263
|
+
const allTestsRun = !opts.files || opts.files.length === 0;
|
|
264
|
+
const runResult = await vitest.runTestSpecifications(specs, allTestsRun);
|
|
265
|
+
const durationMs = Date.now() - startTime;
|
|
266
|
+
this.lastRunAt = new Date().toISOString();
|
|
267
|
+
return this.collectResults(runResult, durationMs, specModuleIds);
|
|
268
|
+
} finally {
|
|
269
|
+
this.currentRunContext = null;
|
|
270
|
+
if (opts.pattern) {
|
|
271
|
+
vitest.resetGlobalTestNamePattern();
|
|
272
|
+
}
|
|
273
|
+
this.running = false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
createRealtimeProgressReporter() {
|
|
277
|
+
const emitProgress = (kind, phase, fileId, nodeId, parentId, node) => {
|
|
278
|
+
const ctx = this.currentRunContext;
|
|
279
|
+
if (!ctx) return;
|
|
280
|
+
this.emitEvent("runNodeProgress", {
|
|
281
|
+
schemaVersion: 1,
|
|
282
|
+
runId: ctx.runId,
|
|
283
|
+
startedAt: ctx.startedAt,
|
|
284
|
+
at: new Date().toISOString(),
|
|
285
|
+
kind,
|
|
286
|
+
phase,
|
|
287
|
+
fileId,
|
|
288
|
+
nodeId,
|
|
289
|
+
parentId,
|
|
290
|
+
node
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
return {
|
|
294
|
+
onTestModuleQueued: (testModule) => {
|
|
295
|
+
const ctx = this.currentRunContext;
|
|
296
|
+
if (!ctx || !ctx.specModuleIds.has(testModule.moduleId)) return;
|
|
297
|
+
const fileId = testModule.moduleId;
|
|
298
|
+
emitProgress("file", "ready", fileId, fileId, null, this.buildFileProgressNode(testModule, "ready"));
|
|
299
|
+
},
|
|
300
|
+
onTestModuleEnd: (testModule) => {
|
|
301
|
+
const ctx = this.currentRunContext;
|
|
302
|
+
if (!ctx || !ctx.specModuleIds.has(testModule.moduleId)) return;
|
|
303
|
+
const fileId = testModule.moduleId;
|
|
304
|
+
emitProgress("file", "result", fileId, fileId, null, this.buildFileNode(testModule));
|
|
305
|
+
},
|
|
306
|
+
onTestSuiteReady: (testSuite) => {
|
|
307
|
+
const ctx = this.currentRunContext;
|
|
308
|
+
if (!ctx || !ctx.specModuleIds.has(testSuite.module.moduleId)) return;
|
|
309
|
+
const fileId = testSuite.module.moduleId;
|
|
310
|
+
const nodeId = `${fileId}::${testSuite.fullName}`;
|
|
311
|
+
const parentId = this.resolveSuiteParentId(testSuite);
|
|
312
|
+
emitProgress("suite", "ready", fileId, nodeId, parentId, this.buildSuiteProgressNode(testSuite, "ready"));
|
|
313
|
+
},
|
|
314
|
+
onTestSuiteResult: (testSuite) => {
|
|
315
|
+
const ctx = this.currentRunContext;
|
|
316
|
+
if (!ctx || !ctx.specModuleIds.has(testSuite.module.moduleId)) return;
|
|
317
|
+
const fileId = testSuite.module.moduleId;
|
|
318
|
+
const nodeId = `${fileId}::${testSuite.fullName}`;
|
|
319
|
+
const parentId = this.resolveSuiteParentId(testSuite);
|
|
320
|
+
emitProgress("suite", "result", fileId, nodeId, parentId, this.buildSuiteNode(testSuite, fileId));
|
|
321
|
+
},
|
|
322
|
+
onTestCaseReady: (testCase) => {
|
|
323
|
+
const ctx = this.currentRunContext;
|
|
324
|
+
if (!ctx || !ctx.specModuleIds.has(testCase.module.moduleId)) return;
|
|
325
|
+
const fileId = testCase.module.moduleId;
|
|
326
|
+
const nodeId = `${fileId}::${testCase.fullName}`;
|
|
327
|
+
const parentId = this.resolveTestParentId(testCase);
|
|
328
|
+
emitProgress("test", "ready", fileId, nodeId, parentId, this.buildTestProgressNode(testCase, "ready"));
|
|
329
|
+
},
|
|
330
|
+
onTestCaseResult: (testCase) => {
|
|
331
|
+
const ctx = this.currentRunContext;
|
|
332
|
+
if (!ctx || !ctx.specModuleIds.has(testCase.module.moduleId)) return;
|
|
333
|
+
const fileId = testCase.module.moduleId;
|
|
334
|
+
const nodeId = `${fileId}::${testCase.fullName}`;
|
|
335
|
+
const parentId = this.resolveTestParentId(testCase);
|
|
336
|
+
emitProgress("test", "result", fileId, nodeId, parentId, this.buildTestNode(testCase, fileId));
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
buildFileProgressNode(testModule, _phase) {
|
|
341
|
+
return {
|
|
342
|
+
id: testModule.moduleId,
|
|
343
|
+
kind: "file",
|
|
344
|
+
name: testModule.moduleId,
|
|
345
|
+
fullName: testModule.moduleId,
|
|
346
|
+
file: testModule.moduleId,
|
|
347
|
+
state: "running",
|
|
348
|
+
durationMs: null,
|
|
349
|
+
counts: {
|
|
350
|
+
total: 0,
|
|
351
|
+
passed: 0,
|
|
352
|
+
failed: 0,
|
|
353
|
+
skipped: 0
|
|
354
|
+
},
|
|
355
|
+
error: null,
|
|
356
|
+
traces: [],
|
|
357
|
+
children: []
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
buildSuiteProgressNode(testSuite, _phase) {
|
|
361
|
+
const fileId = testSuite.module.moduleId;
|
|
362
|
+
return {
|
|
363
|
+
id: `${fileId}::${testSuite.fullName}`,
|
|
364
|
+
kind: "suite",
|
|
365
|
+
name: testSuite.name,
|
|
366
|
+
fullName: testSuite.fullName,
|
|
367
|
+
file: fileId,
|
|
368
|
+
state: "running",
|
|
369
|
+
durationMs: null,
|
|
370
|
+
counts: {
|
|
371
|
+
total: 0,
|
|
372
|
+
passed: 0,
|
|
373
|
+
failed: 0,
|
|
374
|
+
skipped: 0
|
|
375
|
+
},
|
|
376
|
+
error: null,
|
|
377
|
+
traces: [],
|
|
378
|
+
children: []
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
buildTestProgressNode(testCase, _phase) {
|
|
382
|
+
const fileId = testCase.module.moduleId;
|
|
383
|
+
return {
|
|
384
|
+
id: `${fileId}::${testCase.fullName}`,
|
|
385
|
+
kind: "test",
|
|
386
|
+
name: testCase.name,
|
|
387
|
+
fullName: testCase.fullName,
|
|
388
|
+
file: fileId,
|
|
389
|
+
state: "running",
|
|
390
|
+
durationMs: null,
|
|
391
|
+
counts: {
|
|
392
|
+
total: 1,
|
|
393
|
+
passed: 0,
|
|
394
|
+
failed: 0,
|
|
395
|
+
skipped: 0
|
|
396
|
+
},
|
|
397
|
+
error: null,
|
|
398
|
+
traces: [],
|
|
399
|
+
children: []
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
resolveSuiteParentId(testSuite) {
|
|
403
|
+
const parent = testSuite.parent;
|
|
404
|
+
if (parent.type === "suite") {
|
|
405
|
+
return `${testSuite.module.moduleId}::${parent.fullName}`;
|
|
406
|
+
}
|
|
407
|
+
return testSuite.module.moduleId;
|
|
408
|
+
}
|
|
409
|
+
resolveTestParentId(testCase) {
|
|
410
|
+
const parent = testCase.parent;
|
|
411
|
+
if (parent.type === "suite") {
|
|
412
|
+
return `${testCase.module.moduleId}::${parent.fullName}`;
|
|
413
|
+
}
|
|
414
|
+
return testCase.module.moduleId;
|
|
415
|
+
}
|
|
416
|
+
collectResults(runResult, durationMs, specModuleIds) {
|
|
417
|
+
const resultsByFile = new Map();
|
|
418
|
+
for (const testModule of runResult.testModules) {
|
|
419
|
+
if (!specModuleIds.has(testModule.moduleId)) continue;
|
|
420
|
+
const nextResult = this.buildFileNode(testModule);
|
|
421
|
+
const existingResult = resultsByFile.get(nextResult.id);
|
|
422
|
+
if (!existingResult) {
|
|
423
|
+
resultsByFile.set(nextResult.id, nextResult);
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
const existingScore = getResultCompletenessScore(existingResult);
|
|
427
|
+
const nextScore = getResultCompletenessScore(nextResult);
|
|
428
|
+
if (nextScore >= existingScore) {
|
|
429
|
+
resultsByFile.set(nextResult.id, nextResult);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const results = Array.from(resultsByFile.values());
|
|
433
|
+
const summary = aggregateCounts(results);
|
|
434
|
+
return {
|
|
435
|
+
ok: summary.failed === 0,
|
|
436
|
+
summary: {
|
|
437
|
+
...summary,
|
|
438
|
+
durationMs
|
|
439
|
+
},
|
|
440
|
+
results
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
buildFileNode(testModule) {
|
|
444
|
+
const file = testModule.moduleId;
|
|
445
|
+
const children = this.buildChildNodes(testModule, file);
|
|
446
|
+
const counts = aggregateCounts(children);
|
|
447
|
+
const moduleState = testModule.state();
|
|
448
|
+
const diagnostic = testModule.diagnostic();
|
|
449
|
+
return {
|
|
450
|
+
id: testModule.moduleId,
|
|
451
|
+
kind: "file",
|
|
452
|
+
name: testModule.moduleId,
|
|
453
|
+
fullName: testModule.moduleId,
|
|
454
|
+
file,
|
|
455
|
+
state: mapModuleState(moduleState),
|
|
456
|
+
durationMs: diagnostic.duration > 0 ? diagnostic.duration : null,
|
|
457
|
+
counts,
|
|
458
|
+
error: null,
|
|
459
|
+
traces: [],
|
|
460
|
+
children
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
buildChildNodes(parent, file) {
|
|
464
|
+
const result = [];
|
|
465
|
+
for (const child of parent.children) {
|
|
466
|
+
if (child.type === "suite") {
|
|
467
|
+
result.push(this.buildSuiteNode(child, file));
|
|
468
|
+
} else {
|
|
469
|
+
result.push(this.buildTestNode(child, file));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
buildSuiteNode(suite, file) {
|
|
475
|
+
const children = this.buildChildNodes(suite, file);
|
|
476
|
+
const counts = aggregateCounts(children);
|
|
477
|
+
const suiteState = suite.state();
|
|
478
|
+
return {
|
|
479
|
+
id: `${file}::${suite.fullName}`,
|
|
480
|
+
kind: "suite",
|
|
481
|
+
name: suite.name,
|
|
482
|
+
fullName: suite.fullName,
|
|
483
|
+
file,
|
|
484
|
+
state: mapSuiteState(suiteState),
|
|
485
|
+
durationMs: null,
|
|
486
|
+
counts,
|
|
487
|
+
error: null,
|
|
488
|
+
traces: [],
|
|
489
|
+
children
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
buildTestNode(testCase, file) {
|
|
493
|
+
const result = testCase.result();
|
|
494
|
+
const diagnostic = testCase.diagnostic();
|
|
495
|
+
const state = mapTestResult(result, testCase.options.mode);
|
|
496
|
+
let error = null;
|
|
497
|
+
if (result.state === "failed" && result.errors.length > 0) {
|
|
498
|
+
const firstError = result.errors[0];
|
|
499
|
+
error = {
|
|
500
|
+
message: firstError.message ?? String(firstError),
|
|
501
|
+
stack: firstError.stack
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
const raw = testCase.meta().traces;
|
|
505
|
+
let traces = [];
|
|
506
|
+
if (Array.isArray(raw) && raw.length > 0) {
|
|
507
|
+
traces = raw.filter(isSerializedTrace);
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
id: `${file}::${testCase.fullName}`,
|
|
511
|
+
kind: "test",
|
|
512
|
+
name: testCase.name,
|
|
513
|
+
fullName: testCase.fullName,
|
|
514
|
+
file,
|
|
515
|
+
state,
|
|
516
|
+
durationMs: diagnostic ? diagnostic.duration : null,
|
|
517
|
+
counts: countFromState(state),
|
|
518
|
+
error,
|
|
519
|
+
traces,
|
|
520
|
+
children: []
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
}));
|
|
553
525
|
|
|
554
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2Rldi12aXRlc3QtbWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFVzZXJDb25maWcgYXMgVml0ZVVzZXJDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHR5cGUge1xuICBDbGlPcHRpb25zLFxuICBSZXBvcnRlcixcbiAgVGVzdENhc2UsXG4gIFRlc3RNb2R1bGUsXG4gIFRlc3RSdW5SZXN1bHQsXG4gIFRlc3RTcGVjaWZpY2F0aW9uLFxuICBUZXN0U3VpdGUsXG4gIFZpdGVzdCxcbn0gZnJvbSBcInZpdGVzdC9ub2RlXCI7XG5pbXBvcnQgdHlwZSB7IFNlcmlhbGl6ZWRUcmFjZSB9IGZyb20gXCIuLi9uYWl0ZS9uYWl0ZVwiO1xuXG4vLyDthYzsiqTtirgg7ZWcIOqxtOydmCB0cmFjZSDrqqjsnYxcbmV4cG9ydCB0eXBlIFRlc3ROb2RlS2luZCA9IFwiZmlsZVwiIHwgXCJzdWl0ZVwiIHwgXCJ0ZXN0XCI7XG5leHBvcnQgdHlwZSBUZXN0U3RhdGUgPSBcInBhc3NlZFwiIHwgXCJmYWlsZWRcIiB8IFwic2tpcHBlZFwiIHwgXCJ0b2RvXCIgfCBcInJ1bm5pbmdcIiB8IFwidW5rbm93blwiO1xuXG5leHBvcnQgdHlwZSBUZXN0Q2FzZVJlc3VsdCA9IHtcbiAgaWQ6IHN0cmluZztcbiAga2luZDogVGVzdE5vZGVLaW5kO1xuICBuYW1lOiBzdHJpbmc7XG4gIGZ1bGxOYW1lOiBzdHJpbmc7XG4gIGZpbGU6IHN0cmluZztcbiAgc3RhdGU6IFRlc3RTdGF0ZTtcbiAgZHVyYXRpb25NczogbnVtYmVyIHwgbnVsbDtcbiAgY291bnRzOiB7IHRvdGFsOiBudW1iZXI7IHBhc3NlZDogbnVtYmVyOyBmYWlsZWQ6IG51bWJlcjsgc2tpcHBlZDogbnVtYmVyIH07XG4gIGVycm9yOiB7IG1lc3NhZ2U6IHN0cmluZzsgc3RhY2s/OiBzdHJpbmcgfSB8IG51bGw7XG4gIHRyYWNlczogU2VyaWFsaXplZFRyYWNlW107XG4gIGNoaWxkcmVuOiBUZXN0Q2FzZVJlc3VsdFtdO1xufTtcblxuZXhwb3J0IHR5cGUgUnVuUmVzdWx0ID0ge1xuICBvazogYm9vbGVhbjtcbiAgc3VtbWFyeToge1xuICAgIHRvdGFsOiBudW1iZXI7XG4gICAgcGFzc2VkOiBudW1iZXI7XG4gICAgZmFpbGVkOiBudW1iZXI7XG4gICAgc2tpcHBlZDogbnVtYmVyO1xuICAgIGR1cmF0aW9uTXM6IG51bWJlcjtcbiAgfTtcbiAgcmVzdWx0czogVGVzdENhc2VSZXN1bHRbXTtcbn07XG5cbmV4cG9ydCB0eXBlIE1hbmFnZXJTdGF0dXMgPSB7XG4gIHJlYWR5OiBib29sZWFuO1xuICBydW5uaW5nOiBib29sZWFuO1xuICBsYXN0UnVuQXQ6IHN0cmluZyB8IG51bGw7XG59O1xuXG5leHBvcnQgdHlwZSBUZXN0RXZlbnRMaXN0ZW5lciA9IChldmVudDogc3RyaW5nLCBkYXRhOiB1bmtub3duKSA9PiB2b2lkO1xuXG50eXBlIFF1ZXVlRW50cnkgPSB7XG4gIHJ1bklkOiBzdHJpbmc7XG4gIHRhc2s6ICgpID0+IFByb21pc2U8UnVuUmVzdWx0PjtcbiAgcmVzb2x2ZTogKHJlc3VsdDogUnVuUmVzdWx0KSA9PiB2b2lkO1xuICByZWplY3Q6IChlcnJvcjogdW5rbm93bikgPT4gdm9pZDtcbn07XG5cbmV4cG9ydCBjbGFzcyBEZXZWaXRlc3RNYW5hZ2VyIHtcbiAgcHJpdmF0ZSB2aXRlc3Q6IFZpdGVzdCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHJ1bm5pbmcgPSBmYWxzZTtcbiAgcHJpdmF0ZSBsYXN0UnVuQXQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHF1ZXVlOiBRdWV1ZUVudHJ5W10gPSBbXTtcbiAgcHJpdmF0ZSBwcm9jZXNzaW5nID0gZmFsc2U7XG4gIHByaXZhdGUgY2xvc2VkID0gZmFsc2U7XG4gIHByaXZhdGUgZXZlbnRMaXN0ZW5lcnMgPSBuZXcgU2V0PFRlc3RFdmVudExpc3RlbmVyPigpO1xuICBwcml2YXRlIGN1cnJlbnRSdW5Db250ZXh0OiB7XG4gICAgcnVuSWQ6IHN0cmluZztcbiAgICBzdGFydGVkQXQ6IHN0cmluZztcbiAgICBzcGVjTW9kdWxlSWRzOiBTZXQ8c3RyaW5nPjtcbiAgfSB8IG51bGwgPSBudWxsO1xuXG4gIGFkZEV2ZW50TGlzdGVuZXIobGlzdGVuZXI6IFRlc3RFdmVudExpc3RlbmVyKTogdm9pZCB7XG4gICAgdGhpcy5ldmVudExpc3RlbmVycy5hZGQobGlzdGVuZXIpO1xuICB9XG5cbiAgcmVtb3ZlRXZlbnRMaXN0ZW5lcihsaXN0ZW5lcjogVGVzdEV2ZW50TGlzdGVuZXIpOiB2b2lkIHtcbiAgICB0aGlzLmV2ZW50TGlzdGVuZXJzLmRlbGV0ZShsaXN0ZW5lcik7XG4gIH1cblxuICBlbWl0RXZlbnQoZXZlbnQ6IHN0cmluZywgZGF0YTogdW5rbm93bik6IHZvaWQge1xuICAgIGZvciAoY29uc3QgbGlzdGVuZXIgb2YgdGhpcy5ldmVudExpc3RlbmVycykge1xuICAgICAgbGlzdGVuZXIoZXZlbnQsIGRhdGEpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHN0YXJ0KHZpdGVzdENvbmZpZ1BhdGg/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyDsnbTrr7gg7Iuc7J6R65CcIOqyveyasCDspJHrs7Ug7LSI6riw7ZmU66W8IOuwqeyngFxuICAgIGlmICh0aGlzLnZpdGVzdCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHsgY3JlYXRlVml0ZXN0IH0gPSBhd2FpdCBpbXBvcnQoXCJ2aXRlc3Qvbm9kZVwiKTtcblxuICAgIGNvbnN0IHZpdGVPdmVycmlkZXM6IFZpdGVVc2VyQ29uZmlnID0ge1xuICAgICAgc2VydmVyOiB7IHdhdGNoOiBudWxsIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IGNsaU9wdGlvbnM6IENsaU9wdGlvbnMgPSB7XG4gICAgICB3YXRjaDogdHJ1ZSxcbiAgICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgICBmb3JjZVJlcnVuVHJpZ2dlcnM6IFtdLFxuICAgICAgY29uZmlnOiB2aXRlc3RDb25maWdQYXRoLFxuICAgICAgZW52OiB7XG4gICAgICAgIE5PREVfRU5WOiBcInRlc3RcIixcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IHJlYWx0aW1lUmVwb3J0ZXIgPSB0aGlzLmNyZWF0ZVJlYWx0aW1lUHJvZ3Jlc3NSZXBvcnRlcigpO1xuICAgIHZpdGVPdmVycmlkZXMucGx1Z2lucyA9IFtcbiAgICAgIC4uLih2aXRlT3ZlcnJpZGVzLnBsdWdpbnMgPz8gW10pLFxuICAgICAge1xuICAgICAgICBuYW1lOiBcInNvbmFtdS1yZWFsdGltZS1yZXBvcnRlclwiLFxuICAgICAgICBjb25maWd1cmVWaXRlc3QoeyB2aXRlc3Q6IHZpdGVzdEluc3RhbmNlIH06IHsgdml0ZXN0OiBWaXRlc3QgfSkge1xuICAgICAgICAgIGNvbnN0IHJlcG9ydGVycyA9IHZpdGVzdEluc3RhbmNlLmNvbmZpZy5yZXBvcnRlcnM7XG4gICAgICAgICAgaWYgKCFyZXBvcnRlcnMuaW5jbHVkZXMocmVhbHRpbWVSZXBvcnRlcikpIHtcbiAgICAgICAgICAgIHJlcG9ydGVycy5wdXNoKHJlYWx0aW1lUmVwb3J0ZXIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGNvbnN0IHZpdGVzdCA9IGF3YWl0IGNyZWF0ZVZpdGVzdChcInRlc3RcIiwgY2xpT3B0aW9ucywgdml0ZU92ZXJyaWRlcyk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHZpdGVzdC5pbml0KCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBhd2FpdCB2aXRlc3QuY2xvc2UoKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG5cbiAgICB0aGlzLnZpdGVzdCA9IHZpdGVzdDtcbiAgICB0aGlzLnZpdGVzdC5vbkZpbHRlcldhdGNoZWRTcGVjaWZpY2F0aW9uKChfc3BlYykgPT4gZmFsc2UpO1xuICAgIHRoaXMuY2xvc2VkID0gZmFsc2U7XG4gIH1cblxuICBhc3luYyBydW4ob3B0czogeyBmaWxlcz86IHN0cmluZ1tdOyBwYXR0ZXJuPzogc3RyaW5nIH0sIHJ1bklkOiBzdHJpbmcpOiBQcm9taXNlPFJ1blJlc3VsdD4ge1xuICAgIGlmICh0aGlzLmNsb3NlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGV2Vml0ZXN0TWFuYWdlciBpcyBhbHJlYWR5IHNodXQgZG93blwiKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnZpdGVzdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGV2Vml0ZXN0TWFuYWdlciBpcyBub3Qgc3RhcnRlZFwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8UnVuUmVzdWx0PigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCB0YXNrID0gKCkgPT4gdGhpcy5leGVjdXRlUnVuKG9wdHMsIHJ1bklkKTtcbiAgICAgIHRoaXMucXVldWUucHVzaCh7IHJ1bklkLCB0YXNrLCByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICB0aGlzLnByb2Nlc3NRdWV1ZSgpO1xuICAgIH0pO1xuICB9XG5cbiAgZ2V0U3RhdHVzKCk6IE1hbmFnZXJTdGF0dXMge1xuICAgIHJldHVybiB7XG4gICAgICByZWFkeTogdGhpcy52aXRlc3QgIT09IG51bGwgJiYgIXRoaXMuY2xvc2VkLFxuICAgICAgcnVubmluZzogdGhpcy5ydW5uaW5nLFxuICAgICAgbGFzdFJ1bkF0OiB0aGlzLmxhc3RSdW5BdCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOuzgOqyveuQnCDtjIzsnbzsnYQgVml0ZXN0IOuqqOuTiCDqt7jrnpjtlITsl5DshJwg66y07Zqo7ZmU7ZWp64uI64ukLlxuICAgKiBzeW5jRnJvbVdhdGNoZXLsl5DshJwg7Zi47Lac65CY7Ja0IOuLpOydjCDthYzsiqTtirgg7Iuk7ZaJIOyLnCDstZzsi6Ag7L2U65Oc66W8IOyCrOyaqe2VmOuPhOuhnSDtlanri4jri6QuXG4gICAqL1xuICBpbnZhbGlkYXRlRmlsZXMoZmlsZVBhdGhzOiBzdHJpbmdbXSk6IHZvaWQge1xuICAgIGlmICghdGhpcy52aXRlc3QgfHwgdGhpcy5jbG9zZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yIChjb25zdCBmaWxlUGF0aCBvZiBmaWxlUGF0aHMpIHtcbiAgICAgIHRoaXMudml0ZXN0LmludmFsaWRhdGVGaWxlKGZpbGVQYXRoKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzaHV0ZG93bigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jbG9zZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuXG4gICAgLy8g7YGQ7JeQIOuCqOydgCDsnpHsl4Xrk6TsnYQgcmVqZWN07ZWY7JesIO2YuOy2nOyekOqwgCDsmIHqtawg64yA6riw7ZWY7KeAIOyViuuPhOuhnSDsoJXrpqxcbiAgICB3aGlsZSAodGhpcy5xdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBlbnRyeSA9IHRoaXMucXVldWUuc2hpZnQoKTtcbiAgICAgIGlmIChlbnRyeSkge1xuICAgICAgICBlbnRyeS5yZWplY3QobmV3IEVycm9yKFwiRGV2Vml0ZXN0TWFuYWdlciBpcyBiZWluZyBzaHV0IGRvd25cIikpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLnZpdGVzdCkge1xuICAgICAgYXdhaXQgdGhpcy52aXRlc3QuY2xvc2UoKTtcbiAgICAgIHRoaXMudml0ZXN0ID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHByb2Nlc3NRdWV1ZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5wcm9jZXNzaW5nKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMucHJvY2Vzc2luZyA9IHRydWU7XG5cbiAgICB0cnkge1xuICAgICAgd2hpbGUgKHRoaXMucXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBlbnRyeSA9IHRoaXMucXVldWUuc2hpZnQoKTtcbiAgICAgICAgaWYgKCFlbnRyeSkgYnJlYWs7XG4gICAgICAgIGlmICh0aGlzLmNsb3NlZCkge1xuICAgICAgICAgIGVudHJ5LnJlamVjdChuZXcgRXJyb3IoXCJEZXZWaXRlc3RNYW5hZ2VyIGlzIGFscmVhZHkgc2h1dCBkb3duXCIpKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZW50cnkudGFzaygpO1xuICAgICAgICAgIGVudHJ5LnJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgZW50cnkucmVqZWN0KGVycik7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5wcm9jZXNzaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlUnVuKFxuICAgIG9wdHM6IHsgZmlsZXM/OiBzdHJpbmdbXTsgcGF0dGVybj86IHN0cmluZyB9LFxuICAgIHJ1bklkOiBzdHJpbmcsXG4gICk6IFByb21pc2U8UnVuUmVzdWx0PiB7XG4gICAgY29uc3Qgdml0ZXN0ID0gdGhpcy52aXRlc3Q7XG4gICAgaWYgKCF2aXRlc3QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRldlZpdGVzdE1hbmFnZXIgaXMgbm90IHN0YXJ0ZWRcIik7XG4gICAgfVxuXG4gICAgdGhpcy5ydW5uaW5nID0gdHJ1ZTtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgaWYgKG9wdHMucGF0dGVybikge1xuICAgICAgdml0ZXN0LnNldEdsb2JhbFRlc3ROYW1lUGF0dGVybihvcHRzLnBhdHRlcm4pO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzcGVjczogVGVzdFNwZWNpZmljYXRpb25bXSA9IG9wdHMuZmlsZXNcbiAgICAgICAgPyBhd2FpdCB2aXRlc3QuZ2xvYlRlc3RTcGVjaWZpY2F0aW9ucyhvcHRzLmZpbGVzKVxuICAgICAgICA6IGF3YWl0IHZpdGVzdC5nbG9iVGVzdFNwZWNpZmljYXRpb25zKCk7XG5cbiAgICAgIGNvbnN0IHNwZWNNb2R1bGVJZHMgPSBuZXcgU2V0KHNwZWNzLm1hcCgocykgPT4gcy5tb2R1bGVJZCkpO1xuICAgICAgLy8gcm91dGVz7JeQ7IScIOyDneyEse2VnCBydW5JZOulvCDqt7jrjIDroZwg7IKs7Jqp7ZWY7JesIHJ1blN0YXJ0ZWQvcnVuTm9kZVByb2dyZXNzL3J1bkNvbXBsZXRlZCDqsIQg7J286rSA7ISxIOuztOyepVxuICAgICAgdGhpcy5jdXJyZW50UnVuQ29udGV4dCA9IHtcbiAgICAgICAgcnVuSWQsXG4gICAgICAgIHN0YXJ0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICBzcGVjTW9kdWxlSWRzLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgYWxsVGVzdHNSdW4gPSAhb3B0cy5maWxlcyB8fCBvcHRzLmZpbGVzLmxlbmd0aCA9PT0gMDtcbiAgICAgIGNvbnN0IHJ1blJlc3VsdDogVGVzdFJ1blJlc3VsdCA9IGF3YWl0IHZpdGVzdC5ydW5UZXN0U3BlY2lmaWNhdGlvbnMoc3BlY3MsIGFsbFRlc3RzUnVuKTtcblxuICAgICAgY29uc3QgZHVyYXRpb25NcyA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICB0aGlzLmxhc3RSdW5BdCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcblxuICAgICAgcmV0dXJuIHRoaXMuY29sbGVjdFJlc3VsdHMocnVuUmVzdWx0LCBkdXJhdGlvbk1zLCBzcGVjTW9kdWxlSWRzKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5jdXJyZW50UnVuQ29udGV4dCA9IG51bGw7XG4gICAgICBpZiAob3B0cy5wYXR0ZXJuKSB7XG4gICAgICAgIHZpdGVzdC5yZXNldEdsb2JhbFRlc3ROYW1lUGF0dGVybigpO1xuICAgICAgfVxuICAgICAgdGhpcy5ydW5uaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVSZWFsdGltZVByb2dyZXNzUmVwb3J0ZXIoKTogUmVwb3J0ZXIge1xuICAgIGNvbnN0IGVtaXRQcm9ncmVzcyA9IChcbiAgICAgIGtpbmQ6IFwiZmlsZVwiIHwgXCJzdWl0ZVwiIHwgXCJ0ZXN0XCIsXG4gICAgICBwaGFzZTogXCJyZWFkeVwiIHwgXCJyZXN1bHRcIixcbiAgICAgIGZpbGVJZDogc3RyaW5nLFxuICAgICAgbm9kZUlkOiBzdHJpbmcsXG4gICAgICBwYXJlbnRJZDogc3RyaW5nIHwgbnVsbCxcbiAgICAgIG5vZGU6IFRlc3RDYXNlUmVzdWx0LFxuICAgICkgPT4ge1xuICAgICAgY29uc3QgY3R4ID0gdGhpcy5jdXJyZW50UnVuQ29udGV4dDtcbiAgICAgIGlmICghY3R4KSByZXR1cm47XG4gICAgICB0aGlzLmVtaXRFdmVudChcInJ1bk5vZGVQcm9ncmVzc1wiLCB7XG4gICAgICAgIHNjaGVtYVZlcnNpb246IDEsXG4gICAgICAgIHJ1bklkOiBjdHgucnVuSWQsXG4gICAgICAgIHN0YXJ0ZWRBdDogY3R4LnN0YXJ0ZWRBdCxcbiAgICAgICAgYXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAga2luZCxcbiAgICAgICAgcGhhc2UsXG4gICAgICAgIGZpbGVJZCxcbiAgICAgICAgbm9kZUlkLFxuICAgICAgICBwYXJlbnRJZCxcbiAgICAgICAgbm9kZSxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgb25UZXN0TW9kdWxlUXVldWVkOiAodGVzdE1vZHVsZTogVGVzdE1vZHVsZSkgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSB0aGlzLmN1cnJlbnRSdW5Db250ZXh0O1xuICAgICAgICBpZiAoIWN0eCB8fCAhY3R4LnNwZWNNb2R1bGVJZHMuaGFzKHRlc3RNb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RNb2R1bGUubW9kdWxlSWQ7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcbiAgICAgICAgICBcImZpbGVcIixcbiAgICAgICAgICBcInJlYWR5XCIsXG4gICAgICAgICAgZmlsZUlkLFxuICAgICAgICAgIGZpbGVJZCxcbiAgICAgICAgICBudWxsLFxuICAgICAgICAgIHRoaXMuYnVpbGRGaWxlUHJvZ3Jlc3NOb2RlKHRlc3RNb2R1bGUsIFwicmVhZHlcIiksXG4gICAgICAgICk7XG4gICAgICB9LFxuICAgICAgb25UZXN0TW9kdWxlRW5kOiAodGVzdE1vZHVsZTogVGVzdE1vZHVsZSkgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSB0aGlzLmN1cnJlbnRSdW5Db250ZXh0O1xuICAgICAgICBpZiAoIWN0eCB8fCAhY3R4LnNwZWNNb2R1bGVJZHMuaGFzKHRlc3RNb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RNb2R1bGUubW9kdWxlSWQ7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcImZpbGVcIiwgXCJyZXN1bHRcIiwgZmlsZUlkLCBmaWxlSWQsIG51bGwsIHRoaXMuYnVpbGRGaWxlTm9kZSh0ZXN0TW9kdWxlKSk7XG4gICAgICB9LFxuICAgICAgb25UZXN0U3VpdGVSZWFkeTogKHRlc3RTdWl0ZTogVGVzdFN1aXRlKSA9PiB7XG4gICAgICAgIGNvbnN0IGN0eCA9IHRoaXMuY3VycmVudFJ1bkNvbnRleHQ7XG4gICAgICAgIGlmICghY3R4IHx8ICFjdHguc3BlY01vZHVsZUlkcy5oYXModGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZCkpIHJldHVybjtcbiAgICAgICAgY29uc3QgZmlsZUlkID0gdGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICAgICAgY29uc3Qgbm9kZUlkID0gYCR7ZmlsZUlkfTo6JHt0ZXN0U3VpdGUuZnVsbE5hbWV9YDtcbiAgICAgICAgY29uc3QgcGFyZW50SWQgPSB0aGlzLnJlc29sdmVTdWl0ZVBhcmVudElkKHRlc3RTdWl0ZSk7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcbiAgICAgICAgICBcInN1aXRlXCIsXG4gICAgICAgICAgXCJyZWFkeVwiLFxuICAgICAgICAgIGZpbGVJZCxcbiAgICAgICAgICBub2RlSWQsXG4gICAgICAgICAgcGFyZW50SWQsXG4gICAgICAgICAgdGhpcy5idWlsZFN1aXRlUHJvZ3Jlc3NOb2RlKHRlc3RTdWl0ZSwgXCJyZWFkeVwiKSxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBvblRlc3RTdWl0ZVJlc3VsdDogKHRlc3RTdWl0ZTogVGVzdFN1aXRlKSA9PiB7XG4gICAgICAgIGNvbnN0IGN0eCA9IHRoaXMuY3VycmVudFJ1bkNvbnRleHQ7XG4gICAgICAgIGlmICghY3R4IHx8ICFjdHguc3BlY01vZHVsZUlkcy5oYXModGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZCkpIHJldHVybjtcbiAgICAgICAgY29uc3QgZmlsZUlkID0gdGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICAgICAgY29uc3Qgbm9kZUlkID0gYCR7ZmlsZUlkfTo6JHt0ZXN0U3VpdGUuZnVsbE5hbWV9YDtcbiAgICAgICAgY29uc3QgcGFyZW50SWQgPSB0aGlzLnJlc29sdmVTdWl0ZVBhcmVudElkKHRlc3RTdWl0ZSk7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcbiAgICAgICAgICBcInN1aXRlXCIsXG4gICAgICAgICAgXCJyZXN1bHRcIixcbiAgICAgICAgICBmaWxlSWQsXG4gICAgICAgICAgbm9kZUlkLFxuICAgICAgICAgIHBhcmVudElkLFxuICAgICAgICAgIHRoaXMuYnVpbGRTdWl0ZU5vZGUodGVzdFN1aXRlLCBmaWxlSWQpLFxuICAgICAgICApO1xuICAgICAgfSxcbiAgICAgIG9uVGVzdENhc2VSZWFkeTogKHRlc3RDYXNlOiBUZXN0Q2FzZSkgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSB0aGlzLmN1cnJlbnRSdW5Db250ZXh0O1xuICAgICAgICBpZiAoIWN0eCB8fCAhY3R4LnNwZWNNb2R1bGVJZHMuaGFzKHRlc3RDYXNlLm1vZHVsZS5tb2R1bGVJZCkpIHJldHVybjtcbiAgICAgICAgY29uc3QgZmlsZUlkID0gdGVzdENhc2UubW9kdWxlLm1vZHVsZUlkO1xuICAgICAgICBjb25zdCBub2RlSWQgPSBgJHtmaWxlSWR9Ojoke3Rlc3RDYXNlLmZ1bGxOYW1lfWA7XG4gICAgICAgIGNvbnN0IHBhcmVudElkID0gdGhpcy5yZXNvbHZlVGVzdFBhcmVudElkKHRlc3RDYXNlKTtcbiAgICAgICAgZW1pdFByb2dyZXNzKFxuICAgICAgICAgIFwidGVzdFwiLFxuICAgICAgICAgIFwicmVhZHlcIixcbiAgICAgICAgICBmaWxlSWQsXG4gICAgICAgICAgbm9kZUlkLFxuICAgICAgICAgIHBhcmVudElkLFxuICAgICAgICAgIHRoaXMuYnVpbGRUZXN0UHJvZ3Jlc3NOb2RlKHRlc3RDYXNlLCBcInJlYWR5XCIpLFxuICAgICAgICApO1xuICAgICAgfSxcbiAgICAgIG9uVGVzdENhc2VSZXN1bHQ6ICh0ZXN0Q2FzZTogVGVzdENhc2UpID0+IHtcbiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5jdXJyZW50UnVuQ29udGV4dDtcbiAgICAgICAgaWYgKCFjdHggfHwgIWN0eC5zcGVjTW9kdWxlSWRzLmhhcyh0ZXN0Q2FzZS5tb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RDYXNlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICAgICAgY29uc3Qgbm9kZUlkID0gYCR7ZmlsZUlkfTo6JHt0ZXN0Q2FzZS5mdWxsTmFtZX1gO1xuICAgICAgICBjb25zdCBwYXJlbnRJZCA9IHRoaXMucmVzb2x2ZVRlc3RQYXJlbnRJZCh0ZXN0Q2FzZSk7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcbiAgICAgICAgICBcInRlc3RcIixcbiAgICAgICAgICBcInJlc3VsdFwiLFxuICAgICAgICAgIGZpbGVJZCxcbiAgICAgICAgICBub2RlSWQsXG4gICAgICAgICAgcGFyZW50SWQsXG4gICAgICAgICAgdGhpcy5idWlsZFRlc3ROb2RlKHRlc3RDYXNlLCBmaWxlSWQpLFxuICAgICAgICApO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZEZpbGVQcm9ncmVzc05vZGUodGVzdE1vZHVsZTogVGVzdE1vZHVsZSwgX3BoYXNlOiBcInJlYWR5XCIpOiBUZXN0Q2FzZVJlc3VsdCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAga2luZDogXCJmaWxlXCIsXG4gICAgICBuYW1lOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAgZnVsbE5hbWU6IHRlc3RNb2R1bGUubW9kdWxlSWQsXG4gICAgICBmaWxlOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAgc3RhdGU6IFwicnVubmluZ1wiLFxuICAgICAgZHVyYXRpb25NczogbnVsbCxcbiAgICAgIGNvdW50czogeyB0b3RhbDogMCwgcGFzc2VkOiAwLCBmYWlsZWQ6IDAsIHNraXBwZWQ6IDAgfSxcbiAgICAgIGVycm9yOiBudWxsLFxuICAgICAgdHJhY2VzOiBbXSxcbiAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFN1aXRlUHJvZ3Jlc3NOb2RlKHRlc3RTdWl0ZTogVGVzdFN1aXRlLCBfcGhhc2U6IFwicmVhZHlcIik6IFRlc3RDYXNlUmVzdWx0IHtcbiAgICBjb25zdCBmaWxlSWQgPSB0ZXN0U3VpdGUubW9kdWxlLm1vZHVsZUlkO1xuICAgIHJldHVybiB7XG4gICAgICBpZDogYCR7ZmlsZUlkfTo6JHt0ZXN0U3VpdGUuZnVsbE5hbWV9YCxcbiAgICAgIGtpbmQ6IFwic3VpdGVcIixcbiAgICAgIG5hbWU6IHRlc3RTdWl0ZS5uYW1lLFxuICAgICAgZnVsbE5hbWU6IHRlc3RTdWl0ZS5mdWxsTmFtZSxcbiAgICAgIGZpbGU6IGZpbGVJZCxcbiAgICAgIHN0YXRlOiBcInJ1bm5pbmdcIixcbiAgICAgIGR1cmF0aW9uTXM6IG51bGwsXG4gICAgICBjb3VudHM6IHsgdG90YWw6IDAsIHBhc3NlZDogMCwgZmFpbGVkOiAwLCBza2lwcGVkOiAwIH0sXG4gICAgICBlcnJvcjogbnVsbCxcbiAgICAgIHRyYWNlczogW10sXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRUZXN0UHJvZ3Jlc3NOb2RlKHRlc3RDYXNlOiBUZXN0Q2FzZSwgX3BoYXNlOiBcInJlYWR5XCIpOiBUZXN0Q2FzZVJlc3VsdCB7XG4gICAgY29uc3QgZmlsZUlkID0gdGVzdENhc2UubW9kdWxlLm1vZHVsZUlkO1xuICAgIHJldHVybiB7XG4gICAgICBpZDogYCR7ZmlsZUlkfTo6JHt0ZXN0Q2FzZS5mdWxsTmFtZX1gLFxuICAgICAga2luZDogXCJ0ZXN0XCIsXG4gICAgICBuYW1lOiB0ZXN0Q2FzZS5uYW1lLFxuICAgICAgZnVsbE5hbWU6IHRlc3RDYXNlLmZ1bGxOYW1lLFxuICAgICAgZmlsZTogZmlsZUlkLFxuICAgICAgc3RhdGU6IFwicnVubmluZ1wiLFxuICAgICAgZHVyYXRpb25NczogbnVsbCxcbiAgICAgIGNvdW50czogeyB0b3RhbDogMSwgcGFzc2VkOiAwLCBmYWlsZWQ6IDAsIHNraXBwZWQ6IDAgfSxcbiAgICAgIGVycm9yOiBudWxsLFxuICAgICAgdHJhY2VzOiBbXSxcbiAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSByZXNvbHZlU3VpdGVQYXJlbnRJZCh0ZXN0U3VpdGU6IFRlc3RTdWl0ZSk6IHN0cmluZyB7XG4gICAgY29uc3QgcGFyZW50ID0gdGVzdFN1aXRlLnBhcmVudDtcbiAgICBpZiAocGFyZW50LnR5cGUgPT09IFwic3VpdGVcIikge1xuICAgICAgcmV0dXJuIGAke3Rlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWR9Ojoke3BhcmVudC5mdWxsTmFtZX1gO1xuICAgIH1cbiAgICByZXR1cm4gdGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZDtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZVRlc3RQYXJlbnRJZCh0ZXN0Q2FzZTogVGVzdENhc2UpOiBzdHJpbmcge1xuICAgIGNvbnN0IHBhcmVudCA9IHRlc3RDYXNlLnBhcmVudDtcbiAgICBpZiAocGFyZW50LnR5cGUgPT09IFwic3VpdGVcIikge1xuICAgICAgcmV0dXJuIGAke3Rlc3RDYXNlLm1vZHVsZS5tb2R1bGVJZH06OiR7cGFyZW50LmZ1bGxOYW1lfWA7XG4gICAgfVxuICAgIHJldHVybiB0ZXN0Q2FzZS5tb2R1bGUubW9kdWxlSWQ7XG4gIH1cblxuICBwcml2YXRlIGNvbGxlY3RSZXN1bHRzKFxuICAgIHJ1blJlc3VsdDogVGVzdFJ1blJlc3VsdCxcbiAgICBkdXJhdGlvbk1zOiBudW1iZXIsXG4gICAgc3BlY01vZHVsZUlkczogU2V0PHN0cmluZz4sXG4gICk6IFJ1blJlc3VsdCB7XG4gICAgY29uc3QgcmVzdWx0c0J5RmlsZSA9IG5ldyBNYXA8c3RyaW5nLCBUZXN0Q2FzZVJlc3VsdD4oKTtcblxuICAgIGZvciAoY29uc3QgdGVzdE1vZHVsZSBvZiBydW5SZXN1bHQudGVzdE1vZHVsZXMpIHtcbiAgICAgIGlmICghc3BlY01vZHVsZUlkcy5oYXModGVzdE1vZHVsZS5tb2R1bGVJZCkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgbmV4dFJlc3VsdCA9IHRoaXMuYnVpbGRGaWxlTm9kZSh0ZXN0TW9kdWxlKTtcbiAgICAgIGNvbnN0IGV4aXN0aW5nUmVzdWx0ID0gcmVzdWx0c0J5RmlsZS5nZXQobmV4dFJlc3VsdC5pZCk7XG5cbiAgICAgIGlmICghZXhpc3RpbmdSZXN1bHQpIHtcbiAgICAgICAgcmVzdWx0c0J5RmlsZS5zZXQobmV4dFJlc3VsdC5pZCwgbmV4dFJlc3VsdCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBleGlzdGluZ1Njb3JlID0gZ2V0UmVzdWx0Q29tcGxldGVuZXNzU2NvcmUoZXhpc3RpbmdSZXN1bHQpO1xuICAgICAgY29uc3QgbmV4dFNjb3JlID0gZ2V0UmVzdWx0Q29tcGxldGVuZXNzU2NvcmUobmV4dFJlc3VsdCk7XG4gICAgICBpZiAobmV4dFNjb3JlID49IGV4aXN0aW5nU2NvcmUpIHtcbiAgICAgICAgcmVzdWx0c0J5RmlsZS5zZXQobmV4dFJlc3VsdC5pZCwgbmV4dFJlc3VsdCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgcmVzdWx0cyA9IEFycmF5LmZyb20ocmVzdWx0c0J5RmlsZS52YWx1ZXMoKSk7XG4gICAgY29uc3Qgc3VtbWFyeSA9IGFnZ3JlZ2F0ZUNvdW50cyhyZXN1bHRzKTtcblxuICAgIHJldHVybiB7XG4gICAgICBvazogc3VtbWFyeS5mYWlsZWQgPT09IDAsXG4gICAgICBzdW1tYXJ5OiB7IC4uLnN1bW1hcnksIGR1cmF0aW9uTXMgfSxcbiAgICAgIHJlc3VsdHMsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRGaWxlTm9kZSh0ZXN0TW9kdWxlOiBUZXN0TW9kdWxlKTogVGVzdENhc2VSZXN1bHQge1xuICAgIGNvbnN0IGZpbGUgPSB0ZXN0TW9kdWxlLm1vZHVsZUlkO1xuICAgIGNvbnN0IGNoaWxkcmVuID0gdGhpcy5idWlsZENoaWxkTm9kZXModGVzdE1vZHVsZSwgZmlsZSk7XG4gICAgY29uc3QgY291bnRzID0gYWdncmVnYXRlQ291bnRzKGNoaWxkcmVuKTtcbiAgICBjb25zdCBtb2R1bGVTdGF0ZSA9IHRlc3RNb2R1bGUuc3RhdGUoKTtcbiAgICBjb25zdCBkaWFnbm9zdGljID0gdGVzdE1vZHVsZS5kaWFnbm9zdGljKCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IHRlc3RNb2R1bGUubW9kdWxlSWQsXG4gICAgICBraW5kOiBcImZpbGVcIixcbiAgICAgIG5hbWU6IHRlc3RNb2R1bGUubW9kdWxlSWQsXG4gICAgICBmdWxsTmFtZTogdGVzdE1vZHVsZS5tb2R1bGVJZCxcbiAgICAgIGZpbGUsXG4gICAgICBzdGF0ZTogbWFwTW9kdWxlU3RhdGUobW9kdWxlU3RhdGUpLFxuICAgICAgZHVyYXRpb25NczogZGlhZ25vc3RpYy5kdXJhdGlvbiA+IDAgPyBkaWFnbm9zdGljLmR1cmF0aW9uIDogbnVsbCxcbiAgICAgIGNvdW50cyxcbiAgICAgIGVycm9yOiBudWxsLFxuICAgICAgdHJhY2VzOiBbXSxcbiAgICAgIGNoaWxkcmVuLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkQ2hpbGROb2RlcyhwYXJlbnQ6IFRlc3RNb2R1bGUgfCBUZXN0U3VpdGUsIGZpbGU6IHN0cmluZyk6IFRlc3RDYXNlUmVzdWx0W10ge1xuICAgIGNvbnN0IHJlc3VsdDogVGVzdENhc2VSZXN1bHRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgcGFyZW50LmNoaWxkcmVuKSB7XG4gICAgICBpZiAoY2hpbGQudHlwZSA9PT0gXCJzdWl0ZVwiKSB7XG4gICAgICAgIHJlc3VsdC5wdXNoKHRoaXMuYnVpbGRTdWl0ZU5vZGUoY2hpbGQsIGZpbGUpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc3VsdC5wdXNoKHRoaXMuYnVpbGRUZXN0Tm9kZShjaGlsZCwgZmlsZSkpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFN1aXRlTm9kZShzdWl0ZTogVGVzdFN1aXRlLCBmaWxlOiBzdHJpbmcpOiBUZXN0Q2FzZVJlc3VsdCB7XG4gICAgY29uc3QgY2hpbGRyZW4gPSB0aGlzLmJ1aWxkQ2hpbGROb2RlcyhzdWl0ZSwgZmlsZSk7XG4gICAgY29uc3QgY291bnRzID0gYWdncmVnYXRlQ291bnRzKGNoaWxkcmVuKTtcbiAgICBjb25zdCBzdWl0ZVN0YXRlID0gc3VpdGUuc3RhdGUoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBpZDogYCR7ZmlsZX06OiR7c3VpdGUuZnVsbE5hbWV9YCxcbiAgICAgIGtpbmQ6IFwic3VpdGVcIixcbiAgICAgIG5hbWU6IHN1aXRlLm5hbWUsXG4gICAgICBmdWxsTmFtZTogc3VpdGUuZnVsbE5hbWUsXG4gICAgICBmaWxlLFxuICAgICAgc3RhdGU6IG1hcFN1aXRlU3RhdGUoc3VpdGVTdGF0ZSksXG4gICAgICBkdXJhdGlvbk1zOiBudWxsLFxuICAgICAgY291bnRzLFxuICAgICAgZXJyb3I6IG51bGwsXG4gICAgICB0cmFjZXM6IFtdLFxuICAgICAgY2hpbGRyZW4sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRUZXN0Tm9kZSh0ZXN0Q2FzZTogVGVzdENhc2UsIGZpbGU6IHN0cmluZyk6IFRlc3RDYXNlUmVzdWx0IHtcbiAgICBjb25zdCByZXN1bHQgPSB0ZXN0Q2FzZS5yZXN1bHQoKTtcbiAgICBjb25zdCBkaWFnbm9zdGljID0gdGVzdENhc2UuZGlhZ25vc3RpYygpO1xuICAgIGNvbnN0IHN0YXRlID0gbWFwVGVzdFJlc3VsdChyZXN1bHQsIHRlc3RDYXNlLm9wdGlvbnMubW9kZSk7XG5cbiAgICBsZXQgZXJyb3I6IHsgbWVzc2FnZTogc3RyaW5nOyBzdGFjaz86IHN0cmluZyB9IHwgbnVsbCA9IG51bGw7XG4gICAgaWYgKHJlc3VsdC5zdGF0ZSA9PT0gXCJmYWlsZWRcIiAmJiByZXN1bHQuZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGZpcnN0RXJyb3IgPSByZXN1bHQuZXJyb3JzWzBdO1xuICAgICAgZXJyb3IgPSB7XG4gICAgICAgIG1lc3NhZ2U6IGZpcnN0RXJyb3IubWVzc2FnZSA/PyBTdHJpbmcoZmlyc3RFcnJvciksXG4gICAgICAgIHN0YWNrOiBmaXJzdEVycm9yLnN0YWNrLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCByYXcgPSB0ZXN0Q2FzZS5tZXRhKCkudHJhY2VzO1xuICAgIGxldCB0cmFjZXM6IFNlcmlhbGl6ZWRUcmFjZVtdID0gW107XG4gICAgaWYgKEFycmF5LmlzQXJyYXkocmF3KSAmJiByYXcubGVuZ3RoID4gMCkge1xuICAgICAgdHJhY2VzID0gcmF3LmZpbHRlcihpc1NlcmlhbGl6ZWRUcmFjZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBgJHtmaWxlfTo6JHt0ZXN0Q2FzZS5mdWxsTmFtZX1gLFxuICAgICAga2luZDogXCJ0ZXN0XCIsXG4gICAgICBuYW1lOiB0ZXN0Q2FzZS5uYW1lLFxuICAgICAgZnVsbE5hbWU6IHRlc3RDYXNlLmZ1bGxOYW1lLFxuICAgICAgZmlsZSxcbiAgICAgIHN0YXRlLFxuICAgICAgZHVyYXRpb25NczogZGlhZ25vc3RpYyA/IGRpYWdub3N0aWMuZHVyYXRpb24gOiBudWxsLFxuICAgICAgY291bnRzOiBjb3VudEZyb21TdGF0ZShzdGF0ZSksXG4gICAgICBlcnJvcixcbiAgICAgIHRyYWNlcyxcbiAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIG1hcE1vZHVsZVN0YXRlKHN0YXRlOiBcInNraXBwZWRcIiB8IFwicGVuZGluZ1wiIHwgXCJmYWlsZWRcIiB8IFwicGFzc2VkXCIgfCBcInF1ZXVlZFwiKTogVGVzdFN0YXRlIHtcbiAgc3dpdGNoIChzdGF0ZSkge1xuICAgIGNhc2UgXCJwYXNzZWRcIjpcbiAgICAgIHJldHVybiBcInBhc3NlZFwiO1xuICAgIGNhc2UgXCJmYWlsZWRcIjpcbiAgICAgIHJldHVybiBcImZhaWxlZFwiO1xuICAgIGNhc2UgXCJza2lwcGVkXCI6XG4gICAgICByZXR1cm4gXCJza2lwcGVkXCI7XG4gICAgY2FzZSBcInBlbmRpbmdcIjpcbiAgICBjYXNlIFwicXVldWVkXCI6XG4gICAgICByZXR1cm4gXCJydW5uaW5nXCI7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBcInVua25vd25cIjtcbiAgfVxufVxuXG5mdW5jdGlvbiBtYXBTdWl0ZVN0YXRlKHN0YXRlOiBcInNraXBwZWRcIiB8IFwicGVuZGluZ1wiIHwgXCJmYWlsZWRcIiB8IFwicGFzc2VkXCIpOiBUZXN0U3RhdGUge1xuICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgY2FzZSBcInBhc3NlZFwiOlxuICAgICAgcmV0dXJuIFwicGFzc2VkXCI7XG4gICAgY2FzZSBcImZhaWxlZFwiOlxuICAgICAgcmV0dXJuIFwiZmFpbGVkXCI7XG4gICAgY2FzZSBcInNraXBwZWRcIjpcbiAgICAgIHJldHVybiBcInNraXBwZWRcIjtcbiAgICBjYXNlIFwicGVuZGluZ1wiOlxuICAgICAgcmV0dXJuIFwicnVubmluZ1wiO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gIH1cbn1cblxuZnVuY3Rpb24gbWFwVGVzdFJlc3VsdChcbiAgcmVzdWx0OiBSZXR1cm5UeXBlPFRlc3RDYXNlW1wicmVzdWx0XCJdPixcbiAgbW9kZTogXCJydW5cIiB8IFwib25seVwiIHwgXCJza2lwXCIgfCBcInRvZG9cIixcbik6IFRlc3RTdGF0ZSB7XG4gIHN3aXRjaCAocmVzdWx0LnN0YXRlKSB7XG4gICAgY2FzZSBcInBhc3NlZFwiOlxuICAgICAgcmV0dXJuIFwicGFzc2VkXCI7XG4gICAgY2FzZSBcImZhaWxlZFwiOlxuICAgICAgcmV0dXJuIFwiZmFpbGVkXCI7XG4gICAgY2FzZSBcInNraXBwZWRcIjpcbiAgICAgIHJldHVybiBtb2RlID09PSBcInRvZG9cIiA/IFwidG9kb1wiIDogXCJza2lwcGVkXCI7XG4gICAgY2FzZSBcInBlbmRpbmdcIjpcbiAgICAgIHJldHVybiBcInJ1bm5pbmdcIjtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIFwidW5rbm93blwiO1xuICB9XG59XG5cbmZ1bmN0aW9uIGNvdW50RnJvbVN0YXRlKHN0YXRlOiBUZXN0U3RhdGUpOiB7XG4gIHRvdGFsOiBudW1iZXI7XG4gIHBhc3NlZDogbnVtYmVyO1xuICBmYWlsZWQ6IG51bWJlcjtcbiAgc2tpcHBlZDogbnVtYmVyO1xufSB7XG4gIHN3aXRjaCAoc3RhdGUpIHtcbiAgICBjYXNlIFwicGFzc2VkXCI6XG4gICAgICByZXR1cm4geyB0b3RhbDogMSwgcGFzc2VkOiAxLCBmYWlsZWQ6IDAsIHNraXBwZWQ6IDAgfTtcbiAgICBjYXNlIFwiZmFpbGVkXCI6XG4gICAgICByZXR1cm4geyB0b3RhbDogMSwgcGFzc2VkOiAwLCBmYWlsZWQ6IDEsIHNraXBwZWQ6IDAgfTtcbiAgICBjYXNlIFwic2tpcHBlZFwiOlxuICAgIGNhc2UgXCJ0b2RvXCI6XG4gICAgICByZXR1cm4geyB0b3RhbDogMSwgcGFzc2VkOiAwLCBmYWlsZWQ6IDAsIHNraXBwZWQ6IDEgfTtcbiAgICBkZWZhdWx0OlxuICAgICAgLy8gcnVubmluZy91bmtub3duIOyDge2DnOuPhCB0b3RhbOyXkCDtj6ztlajtlZjsl6wg7YyM7J28IOuFuOuTnCBjb3VudHMudG90YWzsnbQg7ZWY7JyEIO2VqeqzhOyZgCDsnbzsuZjtlZjrj4TroZ0g7ZWoXG4gICAgICByZXR1cm4geyB0b3RhbDogMSwgcGFzc2VkOiAwLCBmYWlsZWQ6IDAsIHNraXBwZWQ6IDAgfTtcbiAgfVxufVxuXG5mdW5jdGlvbiBhZ2dyZWdhdGVDb3VudHMoY2hpbGRyZW46IFRlc3RDYXNlUmVzdWx0W10pOiB7XG4gIHRvdGFsOiBudW1iZXI7XG4gIHBhc3NlZDogbnVtYmVyO1xuICBmYWlsZWQ6IG51bWJlcjtcbiAgc2tpcHBlZDogbnVtYmVyO1xufSB7XG4gIGxldCB0b3RhbCA9IDA7XG4gIGxldCBwYXNzZWQgPSAwO1xuICBsZXQgZmFpbGVkID0gMDtcbiAgbGV0IHNraXBwZWQgPSAwO1xuICBmb3IgKGNvbnN0IGNoaWxkIG9mIGNoaWxkcmVuKSB7XG4gICAgdG90YWwgKz0gY2hpbGQuY291bnRzLnRvdGFsO1xuICAgIHBhc3NlZCArPSBjaGlsZC5jb3VudHMucGFzc2VkO1xuICAgIGZhaWxlZCArPSBjaGlsZC5jb3VudHMuZmFpbGVkO1xuICAgIHNraXBwZWQgKz0gY2hpbGQuY291bnRzLnNraXBwZWQ7XG4gIH1cbiAgcmV0dXJuIHsgdG90YWwsIHBhc3NlZCwgZmFpbGVkLCBza2lwcGVkIH07XG59XG5cbmZ1bmN0aW9uIGdldFJlc3VsdENvbXBsZXRlbmVzc1Njb3JlKG5vZGU6IFRlc3RDYXNlUmVzdWx0KTogbnVtYmVyIHtcbiAgbGV0IHNjb3JlID0gMDtcbiAgLy8g7YWM7Iqk7Yq4IOyImOqwgCDrjZQg66eO7J2AIOqysOqzvOulvCDsmrDshKDtlZjsl6wg7KSR67O1IO2MjOydvCDrs5Htlakg7IucIOygleuztCDshpDsi6TsnYQg7KSE7J6F64uI64ukLlxuICBzY29yZSArPSBub2RlLmNvdW50cy50b3RhbCAqIDEwMDA7XG4gIHNjb3JlICs9IG5vZGUuY2hpbGRyZW4ubGVuZ3RoICogMTAwO1xuICBpZiAobm9kZS5kdXJhdGlvbk1zICE9PSBudWxsKSBzY29yZSArPSAxMDtcblxuICBzd2l0Y2ggKG5vZGUuc3RhdGUpIHtcbiAgICBjYXNlIFwiZmFpbGVkXCI6XG4gICAgICBzY29yZSArPSA1O1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBcInBhc3NlZFwiOlxuICAgICAgc2NvcmUgKz0gNDtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgXCJza2lwcGVkXCI6XG4gICAgICBzY29yZSArPSAzO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBcInRvZG9cIjpcbiAgICAgIHNjb3JlICs9IDI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIFwicnVubmluZ1wiOlxuICAgICAgc2NvcmUgKz0gMTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgXCJ1bmtub3duXCI6XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgYnJlYWs7XG4gIH1cblxuICByZXR1cm4gc2NvcmU7XG59XG5cbmZ1bmN0aW9uIGlzU2VyaWFsaXplZFRyYWNlKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgU2VyaWFsaXplZFRyYWNlIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJvYmplY3RcIiB8fCB2YWx1ZSA9PT0gbnVsbCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCB2ID0gdmFsdWUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIHYua2V5ID09PSBcInN0cmluZ1wiICYmXG4gICAgdHlwZW9mIHYuZmlsZVBhdGggPT09IFwic3RyaW5nXCIgJiZcbiAgICB0eXBlb2Ygdi5saW5lTnVtYmVyID09PSBcIm51bWJlclwiICYmXG4gICAgdHlwZW9mIHYuYXQgPT09IFwic3RyaW5nXCIgJiZcbiAgICBcInZhbHVlXCIgaW4gdlxuICApO1xufVxuIl0sIm5hbWVzIjpbIkRldlZpdGVzdE1hbmFnZXIiLCJ2aXRlc3QiLCJydW5uaW5nIiwibGFzdFJ1bkF0IiwicXVldWUiLCJwcm9jZXNzaW5nIiwiY2xvc2VkIiwiZXZlbnRMaXN0ZW5lcnMiLCJTZXQiLCJjdXJyZW50UnVuQ29udGV4dCIsImFkZEV2ZW50TGlzdGVuZXIiLCJsaXN0ZW5lciIsImFkZCIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJkZWxldGUiLCJlbWl0RXZlbnQiLCJldmVudCIsImRhdGEiLCJzdGFydCIsInZpdGVzdENvbmZpZ1BhdGgiLCJjcmVhdGVWaXRlc3QiLCJ2aXRlT3ZlcnJpZGVzIiwic2VydmVyIiwid2F0Y2giLCJjbGlPcHRpb25zIiwic3RhbmRhbG9uZSIsImZvcmNlUmVydW5UcmlnZ2VycyIsImNvbmZpZyIsImVudiIsIk5PREVfRU5WIiwicmVhbHRpbWVSZXBvcnRlciIsImNyZWF0ZVJlYWx0aW1lUHJvZ3Jlc3NSZXBvcnRlciIsInBsdWdpbnMiLCJuYW1lIiwiY29uZmlndXJlVml0ZXN0Iiwidml0ZXN0SW5zdGFuY2UiLCJyZXBvcnRlcnMiLCJpbmNsdWRlcyIsInB1c2giLCJpbml0IiwiZXJyIiwiY2xvc2UiLCJvbkZpbHRlcldhdGNoZWRTcGVjaWZpY2F0aW9uIiwiX3NwZWMiLCJydW4iLCJvcHRzIiwicnVuSWQiLCJFcnJvciIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwidGFzayIsImV4ZWN1dGVSdW4iLCJwcm9jZXNzUXVldWUiLCJnZXRTdGF0dXMiLCJyZWFkeSIsImludmFsaWRhdGVGaWxlcyIsImZpbGVQYXRocyIsImZpbGVQYXRoIiwiaW52YWxpZGF0ZUZpbGUiLCJzaHV0ZG93biIsImxlbmd0aCIsImVudHJ5Iiwic2hpZnQiLCJyZXN1bHQiLCJzdGFydFRpbWUiLCJEYXRlIiwibm93IiwicGF0dGVybiIsInNldEdsb2JhbFRlc3ROYW1lUGF0dGVybiIsInNwZWNzIiwiZmlsZXMiLCJnbG9iVGVzdFNwZWNpZmljYXRpb25zIiwic3BlY01vZHVsZUlkcyIsIm1hcCIsInMiLCJtb2R1bGVJZCIsInN0YXJ0ZWRBdCIsInRvSVNPU3RyaW5nIiwiYWxsVGVzdHNSdW4iLCJydW5SZXN1bHQiLCJydW5UZXN0U3BlY2lmaWNhdGlvbnMiLCJkdXJhdGlvbk1zIiwiY29sbGVjdFJlc3VsdHMiLCJyZXNldEdsb2JhbFRlc3ROYW1lUGF0dGVybiIsImVtaXRQcm9ncmVzcyIsImtpbmQiLCJwaGFzZSIsImZpbGVJZCIsIm5vZGVJZCIsInBhcmVudElkIiwibm9kZSIsImN0eCIsInNjaGVtYVZlcnNpb24iLCJhdCIsIm9uVGVzdE1vZHVsZVF1ZXVlZCIsInRlc3RNb2R1bGUiLCJoYXMiLCJidWlsZEZpbGVQcm9ncmVzc05vZGUiLCJvblRlc3RNb2R1bGVFbmQiLCJidWlsZEZpbGVOb2RlIiwib25UZXN0U3VpdGVSZWFkeSIsInRlc3RTdWl0ZSIsIm1vZHVsZSIsImZ1bGxOYW1lIiwicmVzb2x2ZVN1aXRlUGFyZW50SWQiLCJidWlsZFN1aXRlUHJvZ3Jlc3NOb2RlIiwib25UZXN0U3VpdGVSZXN1bHQiLCJidWlsZFN1aXRlTm9kZSIsIm9uVGVzdENhc2VSZWFkeSIsInRlc3RDYXNlIiwicmVzb2x2ZVRlc3RQYXJlbnRJZCIsImJ1aWxkVGVzdFByb2dyZXNzTm9kZSIsIm9uVGVzdENhc2VSZXN1bHQiLCJidWlsZFRlc3ROb2RlIiwiX3BoYXNlIiwiaWQiLCJmaWxlIiwic3RhdGUiLCJjb3VudHMiLCJ0b3RhbCIsInBhc3NlZCIsImZhaWxlZCIsInNraXBwZWQiLCJlcnJvciIsInRyYWNlcyIsImNoaWxkcmVuIiwicGFyZW50IiwidHlwZSIsInJlc3VsdHNCeUZpbGUiLCJNYXAiLCJ0ZXN0TW9kdWxlcyIsIm5leHRSZXN1bHQiLCJleGlzdGluZ1Jlc3VsdCIsImdldCIsInNldCIsImV4aXN0aW5nU2NvcmUiLCJnZXRSZXN1bHRDb21wbGV0ZW5lc3NTY29yZSIsIm5leHRTY29yZSIsInJlc3VsdHMiLCJBcnJheSIsImZyb20iLCJ2YWx1ZXMiLCJzdW1tYXJ5IiwiYWdncmVnYXRlQ291bnRzIiwib2siLCJidWlsZENoaWxkTm9kZXMiLCJtb2R1bGVTdGF0ZSIsImRpYWdub3N0aWMiLCJtYXBNb2R1bGVTdGF0ZSIsImR1cmF0aW9uIiwiY2hpbGQiLCJzdWl0ZSIsInN1aXRlU3RhdGUiLCJtYXBTdWl0ZVN0YXRlIiwibWFwVGVzdFJlc3VsdCIsIm9wdGlvbnMiLCJtb2RlIiwiZXJyb3JzIiwiZmlyc3RFcnJvciIsIm1lc3NhZ2UiLCJTdHJpbmciLCJzdGFjayIsInJhdyIsIm1ldGEiLCJpc0FycmF5IiwiZmlsdGVyIiwiaXNTZXJpYWxpemVkVHJhY2UiLCJjb3VudEZyb21TdGF0ZSIsInNjb3JlIiwidmFsdWUiLCJ2Iiwia2V5IiwibGluZU51bWJlciJdLCJtYXBwaW5ncyI6IkFBMERBLE9BQU8sTUFBTUE7SUFDSEMsU0FBd0IsS0FBSztJQUM3QkMsVUFBVSxNQUFNO0lBQ2hCQyxZQUEyQixLQUFLO0lBQ2hDQyxRQUFzQixFQUFFLENBQUM7SUFDekJDLGFBQWEsTUFBTTtJQUNuQkMsU0FBUyxNQUFNO0lBQ2ZDLGlCQUFpQixJQUFJQyxNQUF5QjtJQUM5Q0Msb0JBSUcsS0FBSztJQUVoQkMsaUJBQWlCQyxRQUEyQixFQUFRO1FBQ2xELElBQUksQ0FBQ0osY0FBYyxDQUFDSyxHQUFHLENBQUNEO0lBQzFCO0lBRUFFLG9CQUFvQkYsUUFBMkIsRUFBUTtRQUNyRCxJQUFJLENBQUNKLGNBQWMsQ0FBQ08sTUFBTSxDQUFDSDtJQUM3QjtJQUVBSSxVQUFVQyxLQUFhLEVBQUVDLElBQWEsRUFBUTtRQUM1QyxLQUFLLE1BQU1OLFlBQVksSUFBSSxDQUFDSixjQUFjLENBQUU7WUFDMUNJLFNBQVNLLE9BQU9DO1FBQ2xCO0lBQ0Y7SUFFQSxNQUFN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
|
|
526
|
+
//#endregion
|
|
527
|
+
init_dev_vitest_manager();
|
|
528
|
+
export { DevVitestManager, init_dev_vitest_manager };
|
|
529
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2LXZpdGVzdC1tYW5hZ2VyLmpzIiwibmFtZXMiOlsidml0ZU92ZXJyaWRlczogVml0ZVVzZXJDb25maWciLCJjbGlPcHRpb25zOiBDbGlPcHRpb25zIiwic3BlY3M6IFRlc3RTcGVjaWZpY2F0aW9uW10iLCJydW5SZXN1bHQ6IFRlc3RSdW5SZXN1bHQiLCJyZXN1bHQ6IFRlc3RDYXNlUmVzdWx0W10iLCJlcnJvcjogeyBtZXNzYWdlOiBzdHJpbmc7IHN0YWNrPzogc3RyaW5nIH0gfCBudWxsIiwidHJhY2VzOiBTZXJpYWxpemVkVHJhY2VbXSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2Rldi12aXRlc3QtbWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB0eXBlIFVzZXJDb25maWcgYXMgVml0ZVVzZXJDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHtcbiAgdHlwZSBDbGlPcHRpb25zLFxuICB0eXBlIFJlcG9ydGVyLFxuICB0eXBlIFRlc3RDYXNlLFxuICB0eXBlIFRlc3RNb2R1bGUsXG4gIHR5cGUgVGVzdFJ1blJlc3VsdCxcbiAgdHlwZSBUZXN0U3BlY2lmaWNhdGlvbixcbiAgdHlwZSBUZXN0U3VpdGUsXG4gIHR5cGUgVml0ZXN0LFxufSBmcm9tIFwidml0ZXN0L25vZGVcIjtcblxuaW1wb3J0IHsgdHlwZSBTZXJpYWxpemVkVHJhY2UgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcblxuLy8g7YWM7Iqk7Yq4IO2VnCDqsbTsnZggdHJhY2Ug66qo7J2MXG5leHBvcnQgdHlwZSBUZXN0Tm9kZUtpbmQgPSBcImZpbGVcIiB8IFwic3VpdGVcIiB8IFwidGVzdFwiO1xuZXhwb3J0IHR5cGUgVGVzdFN0YXRlID0gXCJwYXNzZWRcIiB8IFwiZmFpbGVkXCIgfCBcInNraXBwZWRcIiB8IFwidG9kb1wiIHwgXCJydW5uaW5nXCIgfCBcInVua25vd25cIjtcblxuZXhwb3J0IHR5cGUgVGVzdENhc2VSZXN1bHQgPSB7XG4gIGlkOiBzdHJpbmc7XG4gIGtpbmQ6IFRlc3ROb2RlS2luZDtcbiAgbmFtZTogc3RyaW5nO1xuICBmdWxsTmFtZTogc3RyaW5nO1xuICBmaWxlOiBzdHJpbmc7XG4gIHN0YXRlOiBUZXN0U3RhdGU7XG4gIGR1cmF0aW9uTXM6IG51bWJlciB8IG51bGw7XG4gIGNvdW50czogeyB0b3RhbDogbnVtYmVyOyBwYXNzZWQ6IG51bWJlcjsgZmFpbGVkOiBudW1iZXI7IHNraXBwZWQ6IG51bWJlciB9O1xuICBlcnJvcjogeyBtZXNzYWdlOiBzdHJpbmc7IHN0YWNrPzogc3RyaW5nIH0gfCBudWxsO1xuICB0cmFjZXM6IFNlcmlhbGl6ZWRUcmFjZVtdO1xuICBjaGlsZHJlbjogVGVzdENhc2VSZXN1bHRbXTtcbn07XG5cbmV4cG9ydCB0eXBlIFJ1blJlc3VsdCA9IHtcbiAgb2s6IGJvb2xlYW47XG4gIHN1bW1hcnk6IHtcbiAgICB0b3RhbDogbnVtYmVyO1xuICAgIHBhc3NlZDogbnVtYmVyO1xuICAgIGZhaWxlZDogbnVtYmVyO1xuICAgIHNraXBwZWQ6IG51bWJlcjtcbiAgICBkdXJhdGlvbk1zOiBudW1iZXI7XG4gIH07XG4gIHJlc3VsdHM6IFRlc3RDYXNlUmVzdWx0W107XG59O1xuXG5leHBvcnQgdHlwZSBNYW5hZ2VyU3RhdHVzID0ge1xuICByZWFkeTogYm9vbGVhbjtcbiAgcnVubmluZzogYm9vbGVhbjtcbiAgbGFzdFJ1bkF0OiBzdHJpbmcgfCBudWxsO1xufTtcblxuZXhwb3J0IHR5cGUgVGVzdEV2ZW50TGlzdGVuZXIgPSAoZXZlbnQ6IHN0cmluZywgZGF0YTogdW5rbm93bikgPT4gdm9pZDtcblxudHlwZSBRdWV1ZUVudHJ5ID0ge1xuICBydW5JZDogc3RyaW5nO1xuICB0YXNrOiAoKSA9PiBQcm9taXNlPFJ1blJlc3VsdD47XG4gIHJlc29sdmU6IChyZXN1bHQ6IFJ1blJlc3VsdCkgPT4gdm9pZDtcbiAgcmVqZWN0OiAoZXJyb3I6IHVua25vd24pID0+IHZvaWQ7XG59O1xuXG5leHBvcnQgY2xhc3MgRGV2Vml0ZXN0TWFuYWdlciB7XG4gIHByaXZhdGUgdml0ZXN0OiBWaXRlc3QgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBydW5uaW5nID0gZmFsc2U7XG4gIHByaXZhdGUgbGFzdFJ1bkF0OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBxdWV1ZTogUXVldWVFbnRyeVtdID0gW107XG4gIHByaXZhdGUgcHJvY2Vzc2luZyA9IGZhbHNlO1xuICBwcml2YXRlIGNsb3NlZCA9IGZhbHNlO1xuICBwcml2YXRlIGV2ZW50TGlzdGVuZXJzID0gbmV3IFNldDxUZXN0RXZlbnRMaXN0ZW5lcj4oKTtcbiAgcHJpdmF0ZSBjdXJyZW50UnVuQ29udGV4dDoge1xuICAgIHJ1bklkOiBzdHJpbmc7XG4gICAgc3RhcnRlZEF0OiBzdHJpbmc7XG4gICAgc3BlY01vZHVsZUlkczogU2V0PHN0cmluZz47XG4gIH0gfCBudWxsID0gbnVsbDtcblxuICBhZGRFdmVudExpc3RlbmVyKGxpc3RlbmVyOiBUZXN0RXZlbnRMaXN0ZW5lcik6IHZvaWQge1xuICAgIHRoaXMuZXZlbnRMaXN0ZW5lcnMuYWRkKGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXIobGlzdGVuZXI6IFRlc3RFdmVudExpc3RlbmVyKTogdm9pZCB7XG4gICAgdGhpcy5ldmVudExpc3RlbmVycy5kZWxldGUobGlzdGVuZXIpO1xuICB9XG5cbiAgZW1pdEV2ZW50KGV2ZW50OiBzdHJpbmcsIGRhdGE6IHVua25vd24pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGxpc3RlbmVyIG9mIHRoaXMuZXZlbnRMaXN0ZW5lcnMpIHtcbiAgICAgIGxpc3RlbmVyKGV2ZW50LCBkYXRhKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdGFydCh2aXRlc3RDb25maWdQYXRoPzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8g7J2066+4IOyLnOyekeuQnCDqsr3smrAg7KSR67O1IOy0iOq4sO2ZlOulvCDrsKnsp4BcbiAgICBpZiAodGhpcy52aXRlc3QpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB7IGNyZWF0ZVZpdGVzdCB9ID0gYXdhaXQgaW1wb3J0KFwidml0ZXN0L25vZGVcIik7XG5cbiAgICBjb25zdCB2aXRlT3ZlcnJpZGVzOiBWaXRlVXNlckNvbmZpZyA9IHtcbiAgICAgIHNlcnZlcjogeyB3YXRjaDogbnVsbCB9LFxuICAgIH07XG5cbiAgICBjb25zdCBjbGlPcHRpb25zOiBDbGlPcHRpb25zID0ge1xuICAgICAgd2F0Y2g6IHRydWUsXG4gICAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgICAgZm9yY2VSZXJ1blRyaWdnZXJzOiBbXSxcbiAgICAgIGNvbmZpZzogdml0ZXN0Q29uZmlnUGF0aCxcbiAgICAgIGVudjoge1xuICAgICAgICBOT0RFX0VOVjogXCJ0ZXN0XCIsXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBjb25zdCByZWFsdGltZVJlcG9ydGVyID0gdGhpcy5jcmVhdGVSZWFsdGltZVByb2dyZXNzUmVwb3J0ZXIoKTtcbiAgICB2aXRlT3ZlcnJpZGVzLnBsdWdpbnMgPSBbXG4gICAgICAuLi4odml0ZU92ZXJyaWRlcy5wbHVnaW5zID8/IFtdKSxcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJzb25hbXUtcmVhbHRpbWUtcmVwb3J0ZXJcIixcbiAgICAgICAgY29uZmlndXJlVml0ZXN0KHsgdml0ZXN0OiB2aXRlc3RJbnN0YW5jZSB9OiB7IHZpdGVzdDogVml0ZXN0IH0pIHtcbiAgICAgICAgICBjb25zdCByZXBvcnRlcnMgPSB2aXRlc3RJbnN0YW5jZS5jb25maWcucmVwb3J0ZXJzO1xuICAgICAgICAgIGlmICghcmVwb3J0ZXJzLmluY2x1ZGVzKHJlYWx0aW1lUmVwb3J0ZXIpKSB7XG4gICAgICAgICAgICByZXBvcnRlcnMucHVzaChyZWFsdGltZVJlcG9ydGVyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBjb25zdCB2aXRlc3QgPSBhd2FpdCBjcmVhdGVWaXRlc3QoXCJ0ZXN0XCIsIGNsaU9wdGlvbnMsIHZpdGVPdmVycmlkZXMpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB2aXRlc3Quc3RhbmRhbG9uZSgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgYXdhaXQgdml0ZXN0LmNsb3NlKCk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuXG4gICAgdGhpcy52aXRlc3QgPSB2aXRlc3Q7XG4gICAgdGhpcy52aXRlc3Qub25GaWx0ZXJXYXRjaGVkU3BlY2lmaWNhdGlvbigoX3NwZWMpID0+IGZhbHNlKTtcbiAgICB0aGlzLmNsb3NlZCA9IGZhbHNlO1xuICB9XG5cbiAgYXN5bmMgcnVuKG9wdHM6IHsgZmlsZXM/OiBzdHJpbmdbXTsgcGF0dGVybj86IHN0cmluZyB9LCBydW5JZDogc3RyaW5nKTogUHJvbWlzZTxSdW5SZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5jbG9zZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRldlZpdGVzdE1hbmFnZXIgaXMgYWxyZWFkeSBzaHV0IGRvd25cIik7XG4gICAgfVxuICAgIGlmICghdGhpcy52aXRlc3QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRldlZpdGVzdE1hbmFnZXIgaXMgbm90IHN0YXJ0ZWRcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPFJ1blJlc3VsdD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgdGFzayA9ICgpID0+IHRoaXMuZXhlY3V0ZVJ1bihvcHRzLCBydW5JZCk7XG4gICAgICB0aGlzLnF1ZXVlLnB1c2goeyBydW5JZCwgdGFzaywgcmVzb2x2ZSwgcmVqZWN0IH0pO1xuICAgICAgdGhpcy5wcm9jZXNzUXVldWUoKTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldFN0YXR1cygpOiBNYW5hZ2VyU3RhdHVzIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVhZHk6IHRoaXMudml0ZXN0ICE9PSBudWxsICYmICF0aGlzLmNsb3NlZCxcbiAgICAgIHJ1bm5pbmc6IHRoaXMucnVubmluZyxcbiAgICAgIGxhc3RSdW5BdDogdGhpcy5sYXN0UnVuQXQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrs4Dqsr3rkJwg7YyM7J287J2EIFZpdGVzdCDrqqjrk4gg6re4656Y7ZSE7JeQ7IScIOustO2aqO2ZlO2VqeuLiOuLpC5cbiAgICogc3luY0Zyb21XYXRjaGVy7JeQ7IScIO2YuOy2nOuQmOyWtCDri6TsnYwg7YWM7Iqk7Yq4IOyLpO2WiSDsi5wg7LWc7IugIOy9lOuTnOulvCDsgqzsmqntlZjrj4TroZ0g7ZWp64uI64ukLlxuICAgKi9cbiAgaW52YWxpZGF0ZUZpbGVzKGZpbGVQYXRoczogc3RyaW5nW10pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMudml0ZXN0IHx8IHRoaXMuY2xvc2VkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZvciAoY29uc3QgZmlsZVBhdGggb2YgZmlsZVBhdGhzKSB7XG4gICAgICB0aGlzLnZpdGVzdC5pbnZhbGlkYXRlRmlsZShmaWxlUGF0aCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc2h1dGRvd24oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcblxuICAgIC8vIO2BkOyXkCDrgqjsnYAg7J6R7JeF65Ok7J2EIHJlamVjdO2VmOyXrCDtmLjstpzsnpDqsIAg7JiB6rWsIOuMgOq4sO2VmOyngCDslYrrj4TroZ0g7KCV66asXG4gICAgd2hpbGUgKHRoaXMucXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZW50cnkgPSB0aGlzLnF1ZXVlLnNoaWZ0KCk7XG4gICAgICBpZiAoZW50cnkpIHtcbiAgICAgICAgZW50cnkucmVqZWN0KG5ldyBFcnJvcihcIkRldlZpdGVzdE1hbmFnZXIgaXMgYmVpbmcgc2h1dCBkb3duXCIpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodGhpcy52aXRlc3QpIHtcbiAgICAgIGF3YWl0IHRoaXMudml0ZXN0LmNsb3NlKCk7XG4gICAgICB0aGlzLnZpdGVzdCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzUXVldWUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMucHJvY2Vzc2luZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnByb2Nlc3NpbmcgPSB0cnVlO1xuXG4gICAgdHJ5IHtcbiAgICAgIHdoaWxlICh0aGlzLnF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLnF1ZXVlLnNoaWZ0KCk7XG4gICAgICAgIGlmICghZW50cnkpIGJyZWFrO1xuICAgICAgICBpZiAodGhpcy5jbG9zZWQpIHtcbiAgICAgICAgICBlbnRyeS5yZWplY3QobmV3IEVycm9yKFwiRGV2Vml0ZXN0TWFuYWdlciBpcyBhbHJlYWR5IHNodXQgZG93blwiKSk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGVudHJ5LnRhc2soKTtcbiAgICAgICAgICBlbnRyeS5yZXNvbHZlKHJlc3VsdCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGVudHJ5LnJlamVjdChlcnIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMucHJvY2Vzc2luZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZXhlY3V0ZVJ1bihcbiAgICBvcHRzOiB7IGZpbGVzPzogc3RyaW5nW107IHBhdHRlcm4/OiBzdHJpbmcgfSxcbiAgICBydW5JZDogc3RyaW5nLFxuICApOiBQcm9taXNlPFJ1blJlc3VsdD4ge1xuICAgIGNvbnN0IHZpdGVzdCA9IHRoaXMudml0ZXN0O1xuICAgIGlmICghdml0ZXN0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJEZXZWaXRlc3RNYW5hZ2VyIGlzIG5vdCBzdGFydGVkXCIpO1xuICAgIH1cblxuICAgIHRoaXMucnVubmluZyA9IHRydWU7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcblxuICAgIGlmIChvcHRzLnBhdHRlcm4pIHtcbiAgICAgIHZpdGVzdC5zZXRHbG9iYWxUZXN0TmFtZVBhdHRlcm4ob3B0cy5wYXR0ZXJuKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3BlY3M6IFRlc3RTcGVjaWZpY2F0aW9uW10gPSBvcHRzLmZpbGVzXG4gICAgICAgID8gYXdhaXQgdml0ZXN0Lmdsb2JUZXN0U3BlY2lmaWNhdGlvbnMob3B0cy5maWxlcylcbiAgICAgICAgOiBhd2FpdCB2aXRlc3QuZ2xvYlRlc3RTcGVjaWZpY2F0aW9ucygpO1xuXG4gICAgICBjb25zdCBzcGVjTW9kdWxlSWRzID0gbmV3IFNldChzcGVjcy5tYXAoKHMpID0+IHMubW9kdWxlSWQpKTtcbiAgICAgIC8vIHJvdXRlc+yXkOyEnCDsg53shLHtlZwgcnVuSWTrpbwg6re464yA66GcIOyCrOyaqe2VmOyXrCBydW5TdGFydGVkL3J1bk5vZGVQcm9ncmVzcy9ydW5Db21wbGV0ZWQg6rCEIOydvOq0gOyEsSDrs7TsnqVcbiAgICAgIHRoaXMuY3VycmVudFJ1bkNvbnRleHQgPSB7XG4gICAgICAgIHJ1bklkLFxuICAgICAgICBzdGFydGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgc3BlY01vZHVsZUlkcyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGFsbFRlc3RzUnVuID0gIW9wdHMuZmlsZXMgfHwgb3B0cy5maWxlcy5sZW5ndGggPT09IDA7XG4gICAgICBjb25zdCBydW5SZXN1bHQ6IFRlc3RSdW5SZXN1bHQgPSBhd2FpdCB2aXRlc3QucnVuVGVzdFNwZWNpZmljYXRpb25zKHNwZWNzLCBhbGxUZXN0c1J1bik7XG5cbiAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgdGhpcy5sYXN0UnVuQXQgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cbiAgICAgIHJldHVybiB0aGlzLmNvbGxlY3RSZXN1bHRzKHJ1blJlc3VsdCwgZHVyYXRpb25Ncywgc3BlY01vZHVsZUlkcyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuY3VycmVudFJ1bkNvbnRleHQgPSBudWxsO1xuICAgICAgaWYgKG9wdHMucGF0dGVybikge1xuICAgICAgICB2aXRlc3QucmVzZXRHbG9iYWxUZXN0TmFtZVBhdHRlcm4oKTtcbiAgICAgIH1cbiAgICAgIHRoaXMucnVubmluZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlUmVhbHRpbWVQcm9ncmVzc1JlcG9ydGVyKCk6IFJlcG9ydGVyIHtcbiAgICBjb25zdCBlbWl0UHJvZ3Jlc3MgPSAoXG4gICAgICBraW5kOiBcImZpbGVcIiB8IFwic3VpdGVcIiB8IFwidGVzdFwiLFxuICAgICAgcGhhc2U6IFwicmVhZHlcIiB8IFwicmVzdWx0XCIsXG4gICAgICBmaWxlSWQ6IHN0cmluZyxcbiAgICAgIG5vZGVJZDogc3RyaW5nLFxuICAgICAgcGFyZW50SWQ6IHN0cmluZyB8IG51bGwsXG4gICAgICBub2RlOiBUZXN0Q2FzZVJlc3VsdCxcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IGN0eCA9IHRoaXMuY3VycmVudFJ1bkNvbnRleHQ7XG4gICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgdGhpcy5lbWl0RXZlbnQoXCJydW5Ob2RlUHJvZ3Jlc3NcIiwge1xuICAgICAgICBzY2hlbWFWZXJzaW9uOiAxLFxuICAgICAgICBydW5JZDogY3R4LnJ1bklkLFxuICAgICAgICBzdGFydGVkQXQ6IGN0eC5zdGFydGVkQXQsXG4gICAgICAgIGF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIGtpbmQsXG4gICAgICAgIHBoYXNlLFxuICAgICAgICBmaWxlSWQsXG4gICAgICAgIG5vZGVJZCxcbiAgICAgICAgcGFyZW50SWQsXG4gICAgICAgIG5vZGUsXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIG9uVGVzdE1vZHVsZVF1ZXVlZDogKHRlc3RNb2R1bGU6IFRlc3RNb2R1bGUpID0+IHtcbiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5jdXJyZW50UnVuQ29udGV4dDtcbiAgICAgICAgaWYgKCFjdHggfHwgIWN0eC5zcGVjTW9kdWxlSWRzLmhhcyh0ZXN0TW9kdWxlLm1vZHVsZUlkKSkgcmV0dXJuO1xuICAgICAgICBjb25zdCBmaWxlSWQgPSB0ZXN0TW9kdWxlLm1vZHVsZUlkO1xuICAgICAgICBlbWl0UHJvZ3Jlc3MoXG4gICAgICAgICAgXCJmaWxlXCIsXG4gICAgICAgICAgXCJyZWFkeVwiLFxuICAgICAgICAgIGZpbGVJZCxcbiAgICAgICAgICBmaWxlSWQsXG4gICAgICAgICAgbnVsbCxcbiAgICAgICAgICB0aGlzLmJ1aWxkRmlsZVByb2dyZXNzTm9kZSh0ZXN0TW9kdWxlLCBcInJlYWR5XCIpLFxuICAgICAgICApO1xuICAgICAgfSxcbiAgICAgIG9uVGVzdE1vZHVsZUVuZDogKHRlc3RNb2R1bGU6IFRlc3RNb2R1bGUpID0+IHtcbiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5jdXJyZW50UnVuQ29udGV4dDtcbiAgICAgICAgaWYgKCFjdHggfHwgIWN0eC5zcGVjTW9kdWxlSWRzLmhhcyh0ZXN0TW9kdWxlLm1vZHVsZUlkKSkgcmV0dXJuO1xuICAgICAgICBjb25zdCBmaWxlSWQgPSB0ZXN0TW9kdWxlLm1vZHVsZUlkO1xuICAgICAgICBlbWl0UHJvZ3Jlc3MoXCJmaWxlXCIsIFwicmVzdWx0XCIsIGZpbGVJZCwgZmlsZUlkLCBudWxsLCB0aGlzLmJ1aWxkRmlsZU5vZGUodGVzdE1vZHVsZSkpO1xuICAgICAgfSxcbiAgICAgIG9uVGVzdFN1aXRlUmVhZHk6ICh0ZXN0U3VpdGU6IFRlc3RTdWl0ZSkgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSB0aGlzLmN1cnJlbnRSdW5Db250ZXh0O1xuICAgICAgICBpZiAoIWN0eCB8fCAhY3R4LnNwZWNNb2R1bGVJZHMuaGFzKHRlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWQ7XG4gICAgICAgIGNvbnN0IG5vZGVJZCA9IGAke2ZpbGVJZH06OiR7dGVzdFN1aXRlLmZ1bGxOYW1lfWA7XG4gICAgICAgIGNvbnN0IHBhcmVudElkID0gdGhpcy5yZXNvbHZlU3VpdGVQYXJlbnRJZCh0ZXN0U3VpdGUpO1xuICAgICAgICBlbWl0UHJvZ3Jlc3MoXG4gICAgICAgICAgXCJzdWl0ZVwiLFxuICAgICAgICAgIFwicmVhZHlcIixcbiAgICAgICAgICBmaWxlSWQsXG4gICAgICAgICAgbm9kZUlkLFxuICAgICAgICAgIHBhcmVudElkLFxuICAgICAgICAgIHRoaXMuYnVpbGRTdWl0ZVByb2dyZXNzTm9kZSh0ZXN0U3VpdGUsIFwicmVhZHlcIiksXG4gICAgICAgICk7XG4gICAgICB9LFxuICAgICAgb25UZXN0U3VpdGVSZXN1bHQ6ICh0ZXN0U3VpdGU6IFRlc3RTdWl0ZSkgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSB0aGlzLmN1cnJlbnRSdW5Db250ZXh0O1xuICAgICAgICBpZiAoIWN0eCB8fCAhY3R4LnNwZWNNb2R1bGVJZHMuaGFzKHRlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWQ7XG4gICAgICAgIGNvbnN0IG5vZGVJZCA9IGAke2ZpbGVJZH06OiR7dGVzdFN1aXRlLmZ1bGxOYW1lfWA7XG4gICAgICAgIGNvbnN0IHBhcmVudElkID0gdGhpcy5yZXNvbHZlU3VpdGVQYXJlbnRJZCh0ZXN0U3VpdGUpO1xuICAgICAgICBlbWl0UHJvZ3Jlc3MoXG4gICAgICAgICAgXCJzdWl0ZVwiLFxuICAgICAgICAgIFwicmVzdWx0XCIsXG4gICAgICAgICAgZmlsZUlkLFxuICAgICAgICAgIG5vZGVJZCxcbiAgICAgICAgICBwYXJlbnRJZCxcbiAgICAgICAgICB0aGlzLmJ1aWxkU3VpdGVOb2RlKHRlc3RTdWl0ZSwgZmlsZUlkKSxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBvblRlc3RDYXNlUmVhZHk6ICh0ZXN0Q2FzZTogVGVzdENhc2UpID0+IHtcbiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5jdXJyZW50UnVuQ29udGV4dDtcbiAgICAgICAgaWYgKCFjdHggfHwgIWN0eC5zcGVjTW9kdWxlSWRzLmhhcyh0ZXN0Q2FzZS5tb2R1bGUubW9kdWxlSWQpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RDYXNlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICAgICAgY29uc3Qgbm9kZUlkID0gYCR7ZmlsZUlkfTo6JHt0ZXN0Q2FzZS5mdWxsTmFtZX1gO1xuICAgICAgICBjb25zdCBwYXJlbnRJZCA9IHRoaXMucmVzb2x2ZVRlc3RQYXJlbnRJZCh0ZXN0Q2FzZSk7XG4gICAgICAgIGVtaXRQcm9ncmVzcyhcbiAgICAgICAgICBcInRlc3RcIixcbiAgICAgICAgICBcInJlYWR5XCIsXG4gICAgICAgICAgZmlsZUlkLFxuICAgICAgICAgIG5vZGVJZCxcbiAgICAgICAgICBwYXJlbnRJZCxcbiAgICAgICAgICB0aGlzLmJ1aWxkVGVzdFByb2dyZXNzTm9kZSh0ZXN0Q2FzZSwgXCJyZWFkeVwiKSxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBvblRlc3RDYXNlUmVzdWx0OiAodGVzdENhc2U6IFRlc3RDYXNlKSA9PiB7XG4gICAgICAgIGNvbnN0IGN0eCA9IHRoaXMuY3VycmVudFJ1bkNvbnRleHQ7XG4gICAgICAgIGlmICghY3R4IHx8ICFjdHguc3BlY01vZHVsZUlkcy5oYXModGVzdENhc2UubW9kdWxlLm1vZHVsZUlkKSkgcmV0dXJuO1xuICAgICAgICBjb25zdCBmaWxlSWQgPSB0ZXN0Q2FzZS5tb2R1bGUubW9kdWxlSWQ7XG4gICAgICAgIGNvbnN0IG5vZGVJZCA9IGAke2ZpbGVJZH06OiR7dGVzdENhc2UuZnVsbE5hbWV9YDtcbiAgICAgICAgY29uc3QgcGFyZW50SWQgPSB0aGlzLnJlc29sdmVUZXN0UGFyZW50SWQodGVzdENhc2UpO1xuICAgICAgICBlbWl0UHJvZ3Jlc3MoXG4gICAgICAgICAgXCJ0ZXN0XCIsXG4gICAgICAgICAgXCJyZXN1bHRcIixcbiAgICAgICAgICBmaWxlSWQsXG4gICAgICAgICAgbm9kZUlkLFxuICAgICAgICAgIHBhcmVudElkLFxuICAgICAgICAgIHRoaXMuYnVpbGRUZXN0Tm9kZSh0ZXN0Q2FzZSwgZmlsZUlkKSxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRGaWxlUHJvZ3Jlc3NOb2RlKHRlc3RNb2R1bGU6IFRlc3RNb2R1bGUsIF9waGFzZTogXCJyZWFkeVwiKTogVGVzdENhc2VSZXN1bHQge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogdGVzdE1vZHVsZS5tb2R1bGVJZCxcbiAgICAgIGtpbmQ6IFwiZmlsZVwiLFxuICAgICAgbmFtZTogdGVzdE1vZHVsZS5tb2R1bGVJZCxcbiAgICAgIGZ1bGxOYW1lOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAgZmlsZTogdGVzdE1vZHVsZS5tb2R1bGVJZCxcbiAgICAgIHN0YXRlOiBcInJ1bm5pbmdcIixcbiAgICAgIGR1cmF0aW9uTXM6IG51bGwsXG4gICAgICBjb3VudHM6IHsgdG90YWw6IDAsIHBhc3NlZDogMCwgZmFpbGVkOiAwLCBza2lwcGVkOiAwIH0sXG4gICAgICBlcnJvcjogbnVsbCxcbiAgICAgIHRyYWNlczogW10sXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRTdWl0ZVByb2dyZXNzTm9kZSh0ZXN0U3VpdGU6IFRlc3RTdWl0ZSwgX3BoYXNlOiBcInJlYWR5XCIpOiBUZXN0Q2FzZVJlc3VsdCB7XG4gICAgY29uc3QgZmlsZUlkID0gdGVzdFN1aXRlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IGAke2ZpbGVJZH06OiR7dGVzdFN1aXRlLmZ1bGxOYW1lfWAsXG4gICAgICBraW5kOiBcInN1aXRlXCIsXG4gICAgICBuYW1lOiB0ZXN0U3VpdGUubmFtZSxcbiAgICAgIGZ1bGxOYW1lOiB0ZXN0U3VpdGUuZnVsbE5hbWUsXG4gICAgICBmaWxlOiBmaWxlSWQsXG4gICAgICBzdGF0ZTogXCJydW5uaW5nXCIsXG4gICAgICBkdXJhdGlvbk1zOiBudWxsLFxuICAgICAgY291bnRzOiB7IHRvdGFsOiAwLCBwYXNzZWQ6IDAsIGZhaWxlZDogMCwgc2tpcHBlZDogMCB9LFxuICAgICAgZXJyb3I6IG51bGwsXG4gICAgICB0cmFjZXM6IFtdLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkVGVzdFByb2dyZXNzTm9kZSh0ZXN0Q2FzZTogVGVzdENhc2UsIF9waGFzZTogXCJyZWFkeVwiKTogVGVzdENhc2VSZXN1bHQge1xuICAgIGNvbnN0IGZpbGVJZCA9IHRlc3RDYXNlLm1vZHVsZS5tb2R1bGVJZDtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IGAke2ZpbGVJZH06OiR7dGVzdENhc2UuZnVsbE5hbWV9YCxcbiAgICAgIGtpbmQ6IFwidGVzdFwiLFxuICAgICAgbmFtZTogdGVzdENhc2UubmFtZSxcbiAgICAgIGZ1bGxOYW1lOiB0ZXN0Q2FzZS5mdWxsTmFtZSxcbiAgICAgIGZpbGU6IGZpbGVJZCxcbiAgICAgIHN0YXRlOiBcInJ1bm5pbmdcIixcbiAgICAgIGR1cmF0aW9uTXM6IG51bGwsXG4gICAgICBjb3VudHM6IHsgdG90YWw6IDEsIHBhc3NlZDogMCwgZmFpbGVkOiAwLCBza2lwcGVkOiAwIH0sXG4gICAgICBlcnJvcjogbnVsbCxcbiAgICAgIHRyYWNlczogW10sXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZVN1aXRlUGFyZW50SWQodGVzdFN1aXRlOiBUZXN0U3VpdGUpOiBzdHJpbmcge1xuICAgIGNvbnN0IHBhcmVudCA9IHRlc3RTdWl0ZS5wYXJlbnQ7XG4gICAgaWYgKHBhcmVudC50eXBlID09PSBcInN1aXRlXCIpIHtcbiAgICAgIHJldHVybiBgJHt0ZXN0U3VpdGUubW9kdWxlLm1vZHVsZUlkfTo6JHtwYXJlbnQuZnVsbE5hbWV9YDtcbiAgICB9XG4gICAgcmV0dXJuIHRlc3RTdWl0ZS5tb2R1bGUubW9kdWxlSWQ7XG4gIH1cblxuICBwcml2YXRlIHJlc29sdmVUZXN0UGFyZW50SWQodGVzdENhc2U6IFRlc3RDYXNlKTogc3RyaW5nIHtcbiAgICBjb25zdCBwYXJlbnQgPSB0ZXN0Q2FzZS5wYXJlbnQ7XG4gICAgaWYgKHBhcmVudC50eXBlID09PSBcInN1aXRlXCIpIHtcbiAgICAgIHJldHVybiBgJHt0ZXN0Q2FzZS5tb2R1bGUubW9kdWxlSWR9Ojoke3BhcmVudC5mdWxsTmFtZX1gO1xuICAgIH1cbiAgICByZXR1cm4gdGVzdENhc2UubW9kdWxlLm1vZHVsZUlkO1xuICB9XG5cbiAgcHJpdmF0ZSBjb2xsZWN0UmVzdWx0cyhcbiAgICBydW5SZXN1bHQ6IFRlc3RSdW5SZXN1bHQsXG4gICAgZHVyYXRpb25NczogbnVtYmVyLFxuICAgIHNwZWNNb2R1bGVJZHM6IFNldDxzdHJpbmc+LFxuICApOiBSdW5SZXN1bHQge1xuICAgIGNvbnN0IHJlc3VsdHNCeUZpbGUgPSBuZXcgTWFwPHN0cmluZywgVGVzdENhc2VSZXN1bHQ+KCk7XG5cbiAgICBmb3IgKGNvbnN0IHRlc3RNb2R1bGUgb2YgcnVuUmVzdWx0LnRlc3RNb2R1bGVzKSB7XG4gICAgICBpZiAoIXNwZWNNb2R1bGVJZHMuaGFzKHRlc3RNb2R1bGUubW9kdWxlSWQpKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IG5leHRSZXN1bHQgPSB0aGlzLmJ1aWxkRmlsZU5vZGUodGVzdE1vZHVsZSk7XG4gICAgICBjb25zdCBleGlzdGluZ1Jlc3VsdCA9IHJlc3VsdHNCeUZpbGUuZ2V0KG5leHRSZXN1bHQuaWQpO1xuXG4gICAgICBpZiAoIWV4aXN0aW5nUmVzdWx0KSB7XG4gICAgICAgIHJlc3VsdHNCeUZpbGUuc2V0KG5leHRSZXN1bHQuaWQsIG5leHRSZXN1bHQpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpc3RpbmdTY29yZSA9IGdldFJlc3VsdENvbXBsZXRlbmVzc1Njb3JlKGV4aXN0aW5nUmVzdWx0KTtcbiAgICAgIGNvbnN0IG5leHRTY29yZSA9IGdldFJlc3VsdENvbXBsZXRlbmVzc1Njb3JlKG5leHRSZXN1bHQpO1xuICAgICAgaWYgKG5leHRTY29yZSA+PSBleGlzdGluZ1Njb3JlKSB7XG4gICAgICAgIHJlc3VsdHNCeUZpbGUuc2V0KG5leHRSZXN1bHQuaWQsIG5leHRSZXN1bHQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdHMgPSBBcnJheS5mcm9tKHJlc3VsdHNCeUZpbGUudmFsdWVzKCkpO1xuICAgIGNvbnN0IHN1bW1hcnkgPSBhZ2dyZWdhdGVDb3VudHMocmVzdWx0cyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgb2s6IHN1bW1hcnkuZmFpbGVkID09PSAwLFxuICAgICAgc3VtbWFyeTogeyAuLi5zdW1tYXJ5LCBkdXJhdGlvbk1zIH0sXG4gICAgICByZXN1bHRzLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkRmlsZU5vZGUodGVzdE1vZHVsZTogVGVzdE1vZHVsZSk6IFRlc3RDYXNlUmVzdWx0IHtcbiAgICBjb25zdCBmaWxlID0gdGVzdE1vZHVsZS5tb2R1bGVJZDtcbiAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXMuYnVpbGRDaGlsZE5vZGVzKHRlc3RNb2R1bGUsIGZpbGUpO1xuICAgIGNvbnN0IGNvdW50cyA9IGFnZ3JlZ2F0ZUNvdW50cyhjaGlsZHJlbik7XG4gICAgY29uc3QgbW9kdWxlU3RhdGUgPSB0ZXN0TW9kdWxlLnN0YXRlKCk7XG4gICAgY29uc3QgZGlhZ25vc3RpYyA9IHRlc3RNb2R1bGUuZGlhZ25vc3RpYygpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAga2luZDogXCJmaWxlXCIsXG4gICAgICBuYW1lOiB0ZXN0TW9kdWxlLm1vZHVsZUlkLFxuICAgICAgZnVsbE5hbWU6IHRlc3RNb2R1bGUubW9kdWxlSWQsXG4gICAgICBmaWxlLFxuICAgICAgc3RhdGU6IG1hcE1vZHVsZVN0YXRlKG1vZHVsZVN0YXRlKSxcbiAgICAgIGR1cmF0aW9uTXM6IGRpYWdub3N0aWMuZHVyYXRpb24gPiAwID8gZGlhZ25vc3RpYy5kdXJhdGlvbiA6IG51bGwsXG4gICAgICBjb3VudHMsXG4gICAgICBlcnJvcjogbnVsbCxcbiAgICAgIHRyYWNlczogW10sXG4gICAgICBjaGlsZHJlbixcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZENoaWxkTm9kZXMocGFyZW50OiBUZXN0TW9kdWxlIHwgVGVzdFN1aXRlLCBmaWxlOiBzdHJpbmcpOiBUZXN0Q2FzZVJlc3VsdFtdIHtcbiAgICBjb25zdCByZXN1bHQ6IFRlc3RDYXNlUmVzdWx0W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIHBhcmVudC5jaGlsZHJlbikge1xuICAgICAgaWYgKGNoaWxkLnR5cGUgPT09IFwic3VpdGVcIikge1xuICAgICAgICByZXN1bHQucHVzaCh0aGlzLmJ1aWxkU3VpdGVOb2RlKGNoaWxkLCBmaWxlKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQucHVzaCh0aGlzLmJ1aWxkVGVzdE5vZGUoY2hpbGQsIGZpbGUpKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRTdWl0ZU5vZGUoc3VpdGU6IFRlc3RTdWl0ZSwgZmlsZTogc3RyaW5nKTogVGVzdENhc2VSZXN1bHQge1xuICAgIGNvbnN0IGNoaWxkcmVuID0gdGhpcy5idWlsZENoaWxkTm9kZXMoc3VpdGUsIGZpbGUpO1xuICAgIGNvbnN0IGNvdW50cyA9IGFnZ3JlZ2F0ZUNvdW50cyhjaGlsZHJlbik7XG4gICAgY29uc3Qgc3VpdGVTdGF0ZSA9IHN1aXRlLnN0YXRlKCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IGAke2ZpbGV9Ojoke3N1aXRlLmZ1bGxOYW1lfWAsXG4gICAgICBraW5kOiBcInN1aXRlXCIsXG4gICAgICBuYW1lOiBzdWl0ZS5uYW1lLFxuICAgICAgZnVsbE5hbWU6IHN1aXRlLmZ1bGxOYW1lLFxuICAgICAgZmlsZSxcbiAgICAgIHN0YXRlOiBtYXBTdWl0ZVN0YXRlKHN1aXRlU3RhdGUpLFxuICAgICAgZHVyYXRpb25NczogbnVsbCxcbiAgICAgIGNvdW50cyxcbiAgICAgIGVycm9yOiBudWxsLFxuICAgICAgdHJhY2VzOiBbXSxcbiAgICAgIGNoaWxkcmVuLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkVGVzdE5vZGUodGVzdENhc2U6IFRlc3RDYXNlLCBmaWxlOiBzdHJpbmcpOiBUZXN0Q2FzZVJlc3VsdCB7XG4gICAgY29uc3QgcmVzdWx0ID0gdGVzdENhc2UucmVzdWx0KCk7XG4gICAgY29uc3QgZGlhZ25vc3RpYyA9IHRlc3RDYXNlLmRpYWdub3N0aWMoKTtcbiAgICBjb25zdCBzdGF0ZSA9IG1hcFRlc3RSZXN1bHQocmVzdWx0LCB0ZXN0Q2FzZS5vcHRpb25zLm1vZGUpO1xuXG4gICAgbGV0IGVycm9yOiB7IG1lc3NhZ2U6IHN0cmluZzsgc3RhY2s/OiBzdHJpbmcgfSB8IG51bGwgPSBudWxsO1xuICAgIGlmIChyZXN1bHQuc3RhdGUgPT09IFwiZmFpbGVkXCIgJiYgcmVzdWx0LmVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBmaXJzdEVycm9yID0gcmVzdWx0LmVycm9yc1swXTtcbiAgICAgIGVycm9yID0ge1xuICAgICAgICBtZXNzYWdlOiBmaXJzdEVycm9yLm1lc3NhZ2UgPz8gU3RyaW5nKGZpcnN0RXJyb3IpLFxuICAgICAgICBzdGFjazogZmlyc3RFcnJvci5zdGFjayxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgcmF3ID0gdGVzdENhc2UubWV0YSgpLnRyYWNlcztcbiAgICBsZXQgdHJhY2VzOiBTZXJpYWxpemVkVHJhY2VbXSA9IFtdO1xuICAgIGlmIChBcnJheS5pc0FycmF5KHJhdykgJiYgcmF3Lmxlbmd0aCA+IDApIHtcbiAgICAgIHRyYWNlcyA9IHJhdy5maWx0ZXIoaXNTZXJpYWxpemVkVHJhY2UpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpZDogYCR7ZmlsZX06OiR7dGVzdENhc2UuZnVsbE5hbWV9YCxcbiAgICAgIGtpbmQ6IFwidGVzdFwiLFxuICAgICAgbmFtZTogdGVzdENhc2UubmFtZSxcbiAgICAgIGZ1bGxOYW1lOiB0ZXN0Q2FzZS5mdWxsTmFtZSxcbiAgICAgIGZpbGUsXG4gICAgICBzdGF0ZSxcbiAgICAgIGR1cmF0aW9uTXM6IGRpYWdub3N0aWMgPyBkaWFnbm9zdGljLmR1cmF0aW9uIDogbnVsbCxcbiAgICAgIGNvdW50czogY291bnRGcm9tU3RhdGUoc3RhdGUpLFxuICAgICAgZXJyb3IsXG4gICAgICB0cmFjZXMsXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgfTtcbiAgfVxufVxuXG5mdW5jdGlvbiBtYXBNb2R1bGVTdGF0ZShzdGF0ZTogXCJza2lwcGVkXCIgfCBcInBlbmRpbmdcIiB8IFwiZmFpbGVkXCIgfCBcInBhc3NlZFwiIHwgXCJxdWV1ZWRcIik6IFRlc3RTdGF0ZSB7XG4gIHN3aXRjaCAoc3RhdGUpIHtcbiAgICBjYXNlIFwicGFzc2VkXCI6XG4gICAgICByZXR1cm4gXCJwYXNzZWRcIjtcbiAgICBjYXNlIFwiZmFpbGVkXCI6XG4gICAgICByZXR1cm4gXCJmYWlsZWRcIjtcbiAgICBjYXNlIFwic2tpcHBlZFwiOlxuICAgICAgcmV0dXJuIFwic2tpcHBlZFwiO1xuICAgIGNhc2UgXCJwZW5kaW5nXCI6XG4gICAgY2FzZSBcInF1ZXVlZFwiOlxuICAgICAgcmV0dXJuIFwicnVubmluZ1wiO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gIH1cbn1cblxuZnVuY3Rpb24gbWFwU3VpdGVTdGF0ZShzdGF0ZTogXCJza2lwcGVkXCIgfCBcInBlbmRpbmdcIiB8IFwiZmFpbGVkXCIgfCBcInBhc3NlZFwiKTogVGVzdFN0YXRlIHtcbiAgc3dpdGNoIChzdGF0ZSkge1xuICAgIGNhc2UgXCJwYXNzZWRcIjpcbiAgICAgIHJldHVybiBcInBhc3NlZFwiO1xuICAgIGNhc2UgXCJmYWlsZWRcIjpcbiAgICAgIHJldHVybiBcImZhaWxlZFwiO1xuICAgIGNhc2UgXCJza2lwcGVkXCI6XG4gICAgICByZXR1cm4gXCJza2lwcGVkXCI7XG4gICAgY2FzZSBcInBlbmRpbmdcIjpcbiAgICAgIHJldHVybiBcInJ1bm5pbmdcIjtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIFwidW5rbm93blwiO1xuICB9XG59XG5cbmZ1bmN0aW9uIG1hcFRlc3RSZXN1bHQoXG4gIHJlc3VsdDogUmV0dXJuVHlwZTxUZXN0Q2FzZVtcInJlc3VsdFwiXT4sXG4gIG1vZGU6IFwicnVuXCIgfCBcIm9ubHlcIiB8IFwic2tpcFwiIHwgXCJ0b2RvXCIsXG4pOiBUZXN0U3RhdGUge1xuICBzd2l0Y2ggKHJlc3VsdC5zdGF0ZSkge1xuICAgIGNhc2UgXCJwYXNzZWRcIjpcbiAgICAgIHJldHVybiBcInBhc3NlZFwiO1xuICAgIGNhc2UgXCJmYWlsZWRcIjpcbiAgICAgIHJldHVybiBcImZhaWxlZFwiO1xuICAgIGNhc2UgXCJza2lwcGVkXCI6XG4gICAgICByZXR1cm4gbW9kZSA9PT0gXCJ0b2RvXCIgPyBcInRvZG9cIiA6IFwic2tpcHBlZFwiO1xuICAgIGNhc2UgXCJwZW5kaW5nXCI6XG4gICAgICByZXR1cm4gXCJydW5uaW5nXCI7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBcInVua25vd25cIjtcbiAgfVxufVxuXG5mdW5jdGlvbiBjb3VudEZyb21TdGF0ZShzdGF0ZTogVGVzdFN0YXRlKToge1xuICB0b3RhbDogbnVtYmVyO1xuICBwYXNzZWQ6IG51bWJlcjtcbiAgZmFpbGVkOiBudW1iZXI7XG4gIHNraXBwZWQ6IG51bWJlcjtcbn0ge1xuICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgY2FzZSBcInBhc3NlZFwiOlxuICAgICAgcmV0dXJuIHsgdG90YWw6IDEsIHBhc3NlZDogMSwgZmFpbGVkOiAwLCBza2lwcGVkOiAwIH07XG4gICAgY2FzZSBcImZhaWxlZFwiOlxuICAgICAgcmV0dXJuIHsgdG90YWw6IDEsIHBhc3NlZDogMCwgZmFpbGVkOiAxLCBza2lwcGVkOiAwIH07XG4gICAgY2FzZSBcInNraXBwZWRcIjpcbiAgICBjYXNlIFwidG9kb1wiOlxuICAgICAgcmV0dXJuIHsgdG90YWw6IDEsIHBhc3NlZDogMCwgZmFpbGVkOiAwLCBza2lwcGVkOiAxIH07XG4gICAgZGVmYXVsdDpcbiAgICAgIC8vIHJ1bm5pbmcvdW5rbm93biDsg4Htg5zrj4QgdG90YWzsl5Ag7Y+s7ZWo7ZWY7JesIO2MjOydvCDrhbjrk5wgY291bnRzLnRvdGFs7J20IO2VmOychCDtlanqs4TsmYAg7J287LmY7ZWY64+E66GdIO2VqFxuICAgICAgcmV0dXJuIHsgdG90YWw6IDEsIHBhc3NlZDogMCwgZmFpbGVkOiAwLCBza2lwcGVkOiAwIH07XG4gIH1cbn1cblxuZnVuY3Rpb24gYWdncmVnYXRlQ291bnRzKGNoaWxkcmVuOiBUZXN0Q2FzZVJlc3VsdFtdKToge1xuICB0b3RhbDogbnVtYmVyO1xuICBwYXNzZWQ6IG51bWJlcjtcbiAgZmFpbGVkOiBudW1iZXI7XG4gIHNraXBwZWQ6IG51bWJlcjtcbn0ge1xuICBsZXQgdG90YWwgPSAwO1xuICBsZXQgcGFzc2VkID0gMDtcbiAgbGV0IGZhaWxlZCA9IDA7XG4gIGxldCBza2lwcGVkID0gMDtcbiAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikge1xuICAgIHRvdGFsICs9IGNoaWxkLmNvdW50cy50b3RhbDtcbiAgICBwYXNzZWQgKz0gY2hpbGQuY291bnRzLnBhc3NlZDtcbiAgICBmYWlsZWQgKz0gY2hpbGQuY291bnRzLmZhaWxlZDtcbiAgICBza2lwcGVkICs9IGNoaWxkLmNvdW50cy5za2lwcGVkO1xuICB9XG4gIHJldHVybiB7IHRvdGFsLCBwYXNzZWQsIGZhaWxlZCwgc2tpcHBlZCB9O1xufVxuXG5mdW5jdGlvbiBnZXRSZXN1bHRDb21wbGV0ZW5lc3NTY29yZShub2RlOiBUZXN0Q2FzZVJlc3VsdCk6IG51bWJlciB7XG4gIGxldCBzY29yZSA9IDA7XG4gIC8vIO2FjOyKpO2KuCDsiJjqsIAg642UIOunjuydgCDqsrDqs7zrpbwg7Jqw7ISg7ZWY7JesIOykkeuztSDtjIzsnbwg67OR7ZWpIOyLnCDsoJXrs7Qg7IaQ7Iuk7J2EIOykhOyeheuLiOuLpC5cbiAgc2NvcmUgKz0gbm9kZS5jb3VudHMudG90YWwgKiAxMDAwO1xuICBzY29yZSArPSBub2RlLmNoaWxkcmVuLmxlbmd0aCAqIDEwMDtcbiAgaWYgKG5vZGUuZHVyYXRpb25NcyAhPT0gbnVsbCkgc2NvcmUgKz0gMTA7XG5cbiAgc3dpdGNoIChub2RlLnN0YXRlKSB7XG4gICAgY2FzZSBcImZhaWxlZFwiOlxuICAgICAgc2NvcmUgKz0gNTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgXCJwYXNzZWRcIjpcbiAgICAgIHNjb3JlICs9IDQ7XG4gICAgICBicmVhaztcbiAgICBjYXNlIFwic2tpcHBlZFwiOlxuICAgICAgc2NvcmUgKz0gMztcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgXCJ0b2RvXCI6XG4gICAgICBzY29yZSArPSAyO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBcInJ1bm5pbmdcIjpcbiAgICAgIHNjb3JlICs9IDE7XG4gICAgICBicmVhaztcbiAgICBjYXNlIFwidW5rbm93blwiOlxuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgcmV0dXJuIHNjb3JlO1xufVxuXG5mdW5jdGlvbiBpc1NlcmlhbGl6ZWRUcmFjZSh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFNlcmlhbGl6ZWRUcmFjZSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgdiA9IHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiB2LmtleSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgIHR5cGVvZiB2LmZpbGVQYXRoID09PSBcInN0cmluZ1wiICYmXG4gICAgdHlwZW9mIHYubGluZU51bWJlciA9PT0gXCJudW1iZXJcIiAmJlxuICAgIHR5cGVvZiB2LmF0ID09PSBcInN0cmluZ1wiICYmXG4gICAgXCJ2YWx1ZVwiIGluIHZcbiAgKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7O0FBa2pCQSxTQUFTLGVBQWUsT0FBMEU7QUFDaEcsU0FBUSxPQUFSO0VBQ0UsS0FBSyxTQUNILFFBQU87RUFDVCxLQUFLLFNBQ0gsUUFBTztFQUNULEtBQUssVUFDSCxRQUFPO0VBQ1QsS0FBSztFQUNMLEtBQUssU0FDSCxRQUFPO0VBQ1QsUUFDRSxRQUFPOzs7QUFJYixTQUFTLGNBQWMsT0FBK0Q7QUFDcEYsU0FBUSxPQUFSO0VBQ0UsS0FBSyxTQUNILFFBQU87RUFDVCxLQUFLLFNBQ0gsUUFBTztFQUNULEtBQUssVUFDSCxRQUFPO0VBQ1QsS0FBSyxVQUNILFFBQU87RUFDVCxRQUNFLFFBQU87OztBQUliLFNBQVMsY0FDUCxRQUNBLE1BQ1c7QUFDWCxTQUFRLE9BQU8sT0FBZjtFQUNFLEtBQUssU0FDSCxRQUFPO0VBQ1QsS0FBSyxTQUNILFFBQU87RUFDVCxLQUFLLFVBQ0gsUUFBTyxTQUFTLFNBQVMsU0FBUztFQUNwQyxLQUFLLFVBQ0gsUUFBTztFQUNULFFBQ0UsUUFBTzs7O0FBSWIs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
|