@cartanova/qgrid-cli 2.10.9 → 2.11.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/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
- package/bundle/dist/application/monit/log-buffer.js +12 -6
- package/bundle/dist/application/monit/monit.frame.js +11 -3
- package/bundle/dist/application/monit/monit.types.js +1 -1
- package/bundle/dist/application/qgrid/conv-routing.js +9 -6
- package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
- package/bundle/dist/application/qgrid/oauth.js +31 -4
- package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
- package/bundle/dist/application/qgrid/qgrid-response-format.js +22 -20
- package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +43 -34
- package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
- package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
- package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
- package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
- package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
- package/bundle/dist/application/qgrid/token-death.js +1 -1
- package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
- package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
- package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
- package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
- package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
- package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
- package/bundle/dist/application/request-log/request-log.model.js +83 -69
- package/bundle/dist/application/request-log/request-log.types.js +8 -2
- package/bundle/dist/application/request-log/zod-code-format.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
- package/bundle/dist/application/setting/setting.constant.js +1 -1
- package/bundle/dist/application/setting/setting.model.js +2 -2
- package/bundle/dist/application/setting/setting.store.js +2 -2
- package/bundle/dist/application/setting/setting.types.js +1 -1
- package/bundle/dist/application/sonamu.generated.js +40 -16
- package/bundle/dist/application/sonamu.generated.sso.js +2 -1
- package/bundle/dist/application/token/token.model.js +26 -9
- package/bundle/dist/application/token/token.types.js +20 -3
- package/bundle/dist/i18n/en.js +15 -1
- package/bundle/dist/i18n/ko.js +15 -1
- package/bundle/dist/i18n/sd.generated.js +2 -1
- package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
- package/bundle/dist/migrations/20261018215031_alter_request_logs_add1_alter1.js +15 -0
- package/bundle/dist/server-bootstrap.js +4 -2
- package/bundle/dist/server-error-handler.js +1 -1
- package/bundle/dist/sonamu.config.js +37 -8
- package/bundle/dist/startup-migrations.js +17 -7
- package/bundle/dist/testing/global.js +1 -1
- package/bundle/dist/testing/schema-bench.js +0 -0
- package/bundle/dist/testing/test-database-name.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
- package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
- package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
- package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
- package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
- package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
- package/bundle/dist/utils/providers/common/credentials.js +5 -1
- package/bundle/dist/utils/providers/common/effort.js +3 -3
- package/bundle/dist/utils/providers/common/model-cost.js +69 -14
- package/bundle/dist/utils/providers/common/provider-types.js +29 -1
- package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
- package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
- package/bundle/dist/utils/providers/common/strictifier.js +62 -43
- package/bundle/dist/utils/providers/common/thinking.js +3 -2
- package/bundle/dist/utils/providers/common/ttft.js +1 -1
- package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
- package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
- package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
- package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
- package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
- package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
- package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
- package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
- package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
- package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
- package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
- package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
- package/bundle/dist/utils/providers/grok/index.js +11 -0
- package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
- package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
- package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
- package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
- package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
- package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
- package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
- package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
- package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
- package/bundle/dist/utils/quiet-hours.js +1 -1
- package/bundle/dist/utils/slack-notify.js +14 -8
- package/bundle/dist/utils/subset-loaders.js +4 -5
- package/bundle/src/application/monit/log-buffer.ts +23 -9
- package/bundle/src/application/monit/monit.frame.ts +22 -5
- package/bundle/src/application/monit/monit.types.ts +6 -0
- package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
- package/bundle/src/application/qgrid/conv-routing.ts +35 -9
- package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
- package/bundle/src/application/qgrid/oauth.ts +51 -15
- package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
- package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +33 -0
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +87 -40
- package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
- package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
- package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
- package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
- package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
- package/bundle/src/application/qgrid/token-death.ts +4 -0
- package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
- package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
- package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
- package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
- package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
- package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
- package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
- package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
- package/bundle/src/application/request-log/request-log.entity.json +8 -0
- package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
- package/bundle/src/application/request-log/request-log.model.ts +279 -145
- package/bundle/src/application/request-log/request-log.types.ts +17 -0
- package/bundle/src/application/request-log/zod-code-format.ts +11 -0
- package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
- package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
- package/bundle/src/application/setting/setting.constant.ts +9 -0
- package/bundle/src/application/setting/setting.model.ts +12 -2
- package/bundle/src/application/setting/setting.store.ts +5 -1
- package/bundle/src/application/setting/setting.types.ts +8 -0
- package/bundle/src/application/sonamu.generated.http +135 -0
- package/bundle/src/application/sonamu.generated.sso.ts +3 -0
- package/bundle/src/application/sonamu.generated.ts +29 -0
- package/bundle/src/application/token/token.identity.test.ts +20 -0
- package/bundle/src/application/token/token.model.ts +66 -7
- package/bundle/src/application/token/token.types.ts +24 -1
- package/bundle/src/i18n/en.ts +19 -0
- package/bundle/src/i18n/ko.ts +21 -0
- package/bundle/src/i18n/sd.generated.ts +24 -2
- package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
- package/bundle/src/migrations/20261018215031_alter_request_logs_add1_alter1.ts +15 -0
- package/bundle/src/server-bootstrap.ts +4 -2
- package/bundle/src/server-error-handler.ts +1 -0
- package/bundle/src/sonamu.config.ts +69 -7
- package/bundle/src/startup-migrations.ts +27 -9
- package/bundle/src/testing/global.ts +20 -0
- package/bundle/src/testing/schema-bench.ts +105 -30
- package/bundle/src/testing/test-database-name.ts +2 -0
- package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
- package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
- package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
- package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
- package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
- package/bundle/src/utils/providers/common/credentials.ts +8 -0
- package/bundle/src/utils/providers/common/effort.ts +9 -2
- package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
- package/bundle/src/utils/providers/common/model-cost.ts +259 -158
- package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
- package/bundle/src/utils/providers/common/provider-types.ts +46 -3
- package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
- package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
- package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
- package/bundle/src/utils/providers/common/strictifier.ts +185 -59
- package/bundle/src/utils/providers/common/thinking.ts +2 -2
- package/bundle/src/utils/providers/common/ttft.ts +4 -2
- package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
- package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
- package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
- package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
- package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
- package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
- package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
- package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
- package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
- package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
- package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
- package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
- package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
- package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
- package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
- package/bundle/src/utils/providers/grok/index.ts +20 -0
- package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
- package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
- package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
- package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
- package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
- package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
- package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
- package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
- package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
- package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
- package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
- package/bundle/src/utils/quiet-hours.ts +12 -1
- package/bundle/src/utils/slack-notify.ts +44 -13
- package/bundle/src/utils/subset-loaders.ts +7 -7
- package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
- package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
- package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
- package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
- package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
- package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
- package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
- package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
- package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
- package/bundle/web-dist/client/assets/{services.generated-BsieU37H.js → services.generated-CefiDXEv.js} +5 -5
- package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
- package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
- package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
- package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
- package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
- package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
- package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
- package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
- package/bundle/web-dist/client/index.html +6 -6
- package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
- package/bundle/web-dist/server/assets/{lazyRouteComponent-Dtd0NR4r.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
- package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
- package/bundle/web-dist/server/assets/{monit-DvzribSE.js → monit-B2hqorPe.js} +385 -126
- package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
- package/bundle/web-dist/server/assets/{react-dom-B4a6-uuR.js → react-dom-BIYQzBqG.js} +2 -129
- package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
- package/bundle/web-dist/server/assets/{request-model-CbqfnQOJ.js → request-model-I6OdODSH.js} +15 -6
- package/bundle/web-dist/server/assets/{routes-BAPWTizT.js → routes-B95YlUv2.js} +760 -213
- package/bundle/web-dist/server/assets/{services.generated-CEbGjsI0.js → services.generated-DQATJ6qf.js} +12821 -12194
- package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
- package/bundle/web-dist/server/assets/{show-CxVZTAdv.js → show-Bxaj3rhH.js} +1355 -419
- package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
- package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
- package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
- package/bundle/web-dist/server/assets/{use-update-token-mutation-CfYmk_4_.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +4303 -22810
- package/dist/cli.js +9 -9
- package/package.json +4 -11
- package/postinstall.mjs +12 -0
- package/skills/qgrid/SKILL.md +1 -0
- package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
- package/skills/qgrid/references/decision-rationale.md +24 -1
- package/skills/qgrid/references/grok-runtime.md +89 -0
- package/skills/qgrid/references/provider-runtime-differences.md +30 -29
- package/skills/qgrid/references/repo-map.md +10 -0
- package/skills/qgrid/references/request-log-run-lifecycle.md +1 -1
- package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
- package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
- package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
- package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
- package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
- package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
- package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
- package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
- package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
- package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
- package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
- package/bundle/dist/testing/setup-mocks.js +0 -16
- package/bundle/src/testing/setup-mocks.ts +0 -44
- package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
- package/bundle/web-dist/client/assets/index-CrXKu_J8.js +0 -106
- package/bundle/web-dist/client/assets/logs-B2SmWJXA.js +0 -1
- package/bundle/web-dist/client/assets/monit-D-JwXXoA.js +0 -1
- package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
- package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
- package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
- package/bundle/web-dist/client/assets/routes-C5r4gTvY.js +0 -5
- package/bundle/web-dist/client/assets/settings-D3tDSAck.js +0 -1
- package/bundle/web-dist/client/assets/show-Cah_kUKC.js +0 -2
- package/bundle/web-dist/client/assets/tokens-DU2Iyxxd.js +0 -1
- package/bundle/web-dist/client/assets/use-oauth-login-flow-D0UaR9_e.js +0 -1
- package/bundle/web-dist/client/assets/use-update-token-mutation-DAq0F8p-.js +0 -1
- package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
- package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
- package/bundle/web-dist/server/assets/logs-l91avYif.js +0 -509
- package/bundle/web-dist/server/assets/plus-KZrECewT.js +0 -19
- package/bundle/web-dist/server/assets/refresh-cw-BND93JrF.js +0 -23
- package/bundle/web-dist/server/assets/settings-BZR5HSAL.js +0 -461
- package/bundle/web-dist/server/assets/tokens-D1hb4eKk.js +0 -448
- package/bundle/web-dist/server/assets/use-oauth-login-flow-Cvdy0zF8.js +0 -178
- package/dist/cli.d.ts +0 -10
- /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
- /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
- /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
|
@@ -1,2756 +0,0 @@
|
|
|
1
|
-
import { format, formatRegExp, objDisplay } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js";
|
|
2
|
-
import { assertTypes, createDefer, filterOutComments, isNegativeNaN, isObject, objectAttr, ordinal, shuffle, toArray, unique } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js";
|
|
3
|
-
import { processError } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js";
|
|
4
|
-
import { getSafeTimers } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js";
|
|
5
|
-
import { parseSingleStack } from "../../../../../@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js";
|
|
6
|
-
import { b as relative } from "../../../../../pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js";
|
|
7
|
-
import "../../../../../pathe@2.0.3/node_modules/pathe/dist/index.js";
|
|
8
|
-
//#region ../../node_modules/.pnpm/@vitest+runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js
|
|
9
|
-
var PendingError = class extends Error {
|
|
10
|
-
code = "VITEST_PENDING";
|
|
11
|
-
taskId;
|
|
12
|
-
constructor(message, task, note) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.message = message;
|
|
15
|
-
this.note = note;
|
|
16
|
-
this.taskId = task.id;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
var TestRunAbortError = class extends Error {
|
|
20
|
-
name = "TestRunAbortError";
|
|
21
|
-
reason;
|
|
22
|
-
constructor(message, reason) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.reason = reason;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var FixtureDependencyError = class extends Error {
|
|
28
|
-
name = "FixtureDependencyError";
|
|
29
|
-
};
|
|
30
|
-
var FixtureAccessError = class extends Error {
|
|
31
|
-
name = "FixtureAccessError";
|
|
32
|
-
};
|
|
33
|
-
var FixtureParseError = class extends Error {
|
|
34
|
-
name = "FixtureParseError";
|
|
35
|
-
};
|
|
36
|
-
var AroundHookSetupError = class extends Error {
|
|
37
|
-
name = "AroundHookSetupError";
|
|
38
|
-
};
|
|
39
|
-
var AroundHookTeardownError = class extends Error {
|
|
40
|
-
name = "AroundHookTeardownError";
|
|
41
|
-
};
|
|
42
|
-
var AroundHookMultipleCallsError = class extends Error {
|
|
43
|
-
name = "AroundHookMultipleCallsError";
|
|
44
|
-
};
|
|
45
|
-
const fnMap = /* @__PURE__ */ new WeakMap();
|
|
46
|
-
const testFixtureMap = /* @__PURE__ */ new WeakMap();
|
|
47
|
-
const hooksMap = /* @__PURE__ */ new WeakMap();
|
|
48
|
-
function setFn(key, fn) {
|
|
49
|
-
fnMap.set(key, fn);
|
|
50
|
-
}
|
|
51
|
-
function getFn(key) {
|
|
52
|
-
return fnMap.get(key);
|
|
53
|
-
}
|
|
54
|
-
function setTestFixture(key, fixture) {
|
|
55
|
-
testFixtureMap.set(key, fixture);
|
|
56
|
-
}
|
|
57
|
-
function getTestFixtures(key) {
|
|
58
|
-
return testFixtureMap.get(key);
|
|
59
|
-
}
|
|
60
|
-
function setHooks(key, hooks) {
|
|
61
|
-
hooksMap.set(key, hooks);
|
|
62
|
-
}
|
|
63
|
-
function getHooks(key) {
|
|
64
|
-
return hooksMap.get(key);
|
|
65
|
-
}
|
|
66
|
-
const FIXTURE_STACK_TRACE_KEY = Symbol.for("VITEST_FIXTURE_STACK_TRACE");
|
|
67
|
-
var TestFixtures = class TestFixtures {
|
|
68
|
-
_suiteContexts;
|
|
69
|
-
_overrides = /* @__PURE__ */ new WeakMap();
|
|
70
|
-
_registrations;
|
|
71
|
-
static _definitions = [];
|
|
72
|
-
static _builtinFixtures = [
|
|
73
|
-
"task",
|
|
74
|
-
"signal",
|
|
75
|
-
"onTestFailed",
|
|
76
|
-
"onTestFinished",
|
|
77
|
-
"skip",
|
|
78
|
-
"annotate"
|
|
79
|
-
];
|
|
80
|
-
static _fixtureOptionKeys = [
|
|
81
|
-
"auto",
|
|
82
|
-
"injected",
|
|
83
|
-
"scope"
|
|
84
|
-
];
|
|
85
|
-
static _fixtureScopes = [
|
|
86
|
-
"test",
|
|
87
|
-
"file",
|
|
88
|
-
"worker"
|
|
89
|
-
];
|
|
90
|
-
static _workerContextSuite = { type: "worker" };
|
|
91
|
-
static clearDefinitions() {
|
|
92
|
-
TestFixtures._definitions.length = 0;
|
|
93
|
-
}
|
|
94
|
-
static getWorkerContexts() {
|
|
95
|
-
return TestFixtures._definitions.map((f) => f.getWorkerContext());
|
|
96
|
-
}
|
|
97
|
-
static getFileContexts(file) {
|
|
98
|
-
return TestFixtures._definitions.map((f) => f.getFileContext(file));
|
|
99
|
-
}
|
|
100
|
-
static isFixtureOptions(obj) {
|
|
101
|
-
return isObject(obj) && Object.keys(obj).some((key) => TestFixtures._fixtureOptionKeys.includes(key));
|
|
102
|
-
}
|
|
103
|
-
constructor(registrations) {
|
|
104
|
-
this._registrations = registrations ?? /* @__PURE__ */ new Map();
|
|
105
|
-
this._suiteContexts = /* @__PURE__ */ new WeakMap();
|
|
106
|
-
TestFixtures._definitions.push(this);
|
|
107
|
-
}
|
|
108
|
-
extend(runner, userFixtures) {
|
|
109
|
-
const { suite } = getCurrentSuite();
|
|
110
|
-
const isTopLevel = !suite || suite.file === suite;
|
|
111
|
-
const registrations = this.parseUserFixtures(runner, userFixtures, isTopLevel);
|
|
112
|
-
return new TestFixtures(registrations);
|
|
113
|
-
}
|
|
114
|
-
get(suite) {
|
|
115
|
-
let currentSuite = suite;
|
|
116
|
-
while (currentSuite) {
|
|
117
|
-
const overrides = this._overrides.get(currentSuite);
|
|
118
|
-
if (overrides) return overrides;
|
|
119
|
-
if (currentSuite === currentSuite.file) break;
|
|
120
|
-
currentSuite = currentSuite.suite || currentSuite.file;
|
|
121
|
-
}
|
|
122
|
-
return this._registrations;
|
|
123
|
-
}
|
|
124
|
-
override(runner, userFixtures) {
|
|
125
|
-
const { suite: currentSuite, file } = getCurrentSuite();
|
|
126
|
-
const suite = currentSuite || file;
|
|
127
|
-
const isTopLevel = !currentSuite || currentSuite.file === currentSuite;
|
|
128
|
-
const suiteRegistrations = new Map(this.get(suite));
|
|
129
|
-
const registrations = this.parseUserFixtures(runner, userFixtures, isTopLevel, suiteRegistrations);
|
|
130
|
-
if (isTopLevel) this._registrations = registrations;
|
|
131
|
-
else this._overrides.set(suite, registrations);
|
|
132
|
-
}
|
|
133
|
-
getFileContext(file) {
|
|
134
|
-
if (!this._suiteContexts.has(file)) this._suiteContexts.set(file, Object.create(null));
|
|
135
|
-
return this._suiteContexts.get(file);
|
|
136
|
-
}
|
|
137
|
-
getWorkerContext() {
|
|
138
|
-
if (!this._suiteContexts.has(TestFixtures._workerContextSuite)) this._suiteContexts.set(TestFixtures._workerContextSuite, Object.create(null));
|
|
139
|
-
return this._suiteContexts.get(TestFixtures._workerContextSuite);
|
|
140
|
-
}
|
|
141
|
-
parseUserFixtures(runner, userFixtures, supportNonTest, registrations = new Map(this._registrations)) {
|
|
142
|
-
const errors = [];
|
|
143
|
-
Object.entries(userFixtures).forEach(([name, fn]) => {
|
|
144
|
-
let options;
|
|
145
|
-
let value;
|
|
146
|
-
let _options;
|
|
147
|
-
if (Array.isArray(fn) && fn.length >= 2 && TestFixtures.isFixtureOptions(fn[1])) {
|
|
148
|
-
_options = fn[1];
|
|
149
|
-
options = {
|
|
150
|
-
auto: _options.auto ?? false,
|
|
151
|
-
scope: _options.scope ?? "test",
|
|
152
|
-
injected: _options.injected ?? false
|
|
153
|
-
};
|
|
154
|
-
value = options.injected ? runner.injectValue?.(name) ?? fn[0] : fn[0];
|
|
155
|
-
} else value = fn;
|
|
156
|
-
const parent = registrations.get(name);
|
|
157
|
-
if (parent && options) {
|
|
158
|
-
if (parent.scope !== options.scope) errors.push(new FixtureDependencyError(`The "${name}" fixture was already registered with a "${options.scope}" scope.`));
|
|
159
|
-
if (parent.auto !== options.auto) errors.push(new FixtureDependencyError(`The "${name}" fixture was already registered as { auto: ${options.auto} }.`));
|
|
160
|
-
} else if (parent) options = {
|
|
161
|
-
auto: parent.auto,
|
|
162
|
-
scope: parent.scope,
|
|
163
|
-
injected: parent.injected
|
|
164
|
-
};
|
|
165
|
-
else if (!options) options = {
|
|
166
|
-
auto: false,
|
|
167
|
-
injected: false,
|
|
168
|
-
scope: "test"
|
|
169
|
-
};
|
|
170
|
-
if (options.scope && !TestFixtures._fixtureScopes.includes(options.scope)) errors.push(new FixtureDependencyError(`The "${name}" fixture has unknown scope "${options.scope}".`));
|
|
171
|
-
if (!supportNonTest && options.scope !== "test") errors.push(new FixtureDependencyError(`The "${name}" fixture cannot be defined with a ${options.scope} scope${!_options?.scope && parent?.scope ? " (inherited from the base fixture)" : ""} inside the describe block. Define it at the top level of the file instead.`));
|
|
172
|
-
const deps = isFixtureFunction(value) ? getUsedProps(value) : /* @__PURE__ */ new Set();
|
|
173
|
-
const item = {
|
|
174
|
-
name,
|
|
175
|
-
value,
|
|
176
|
-
auto: options.auto ?? false,
|
|
177
|
-
injected: options.injected ?? false,
|
|
178
|
-
scope: options.scope ?? "test",
|
|
179
|
-
deps,
|
|
180
|
-
parent
|
|
181
|
-
};
|
|
182
|
-
if (isFixtureFunction(value)) Object.assign(value, { [FIXTURE_STACK_TRACE_KEY]: /* @__PURE__ */ new Error("STACK_TRACE_ERROR") });
|
|
183
|
-
registrations.set(name, item);
|
|
184
|
-
if (item.scope === "worker" && (runner.pool === "vmThreads" || runner.pool === "vmForks")) item.scope = "file";
|
|
185
|
-
});
|
|
186
|
-
for (const fixture of registrations.values()) for (const depName of fixture.deps) {
|
|
187
|
-
if (TestFixtures._builtinFixtures.includes(depName)) continue;
|
|
188
|
-
const dep = registrations.get(depName);
|
|
189
|
-
if (!dep) {
|
|
190
|
-
errors.push(new FixtureDependencyError(`The "${fixture.name}" fixture depends on unknown fixture "${depName}".`));
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
if (depName === fixture.name && !fixture.parent) {
|
|
194
|
-
errors.push(new FixtureDependencyError(`The "${fixture.name}" fixture depends on itself, but does not have a base implementation.`));
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (TestFixtures._fixtureScopes.indexOf(fixture.scope) > TestFixtures._fixtureScopes.indexOf(dep.scope)) {
|
|
198
|
-
errors.push(new FixtureDependencyError(`The ${fixture.scope} "${fixture.name}" fixture cannot depend on a ${dep.scope} fixture "${dep.name}".`));
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (errors.length === 1) throw errors[0];
|
|
203
|
-
else if (errors.length > 1) throw new AggregateError(errors, "Cannot resolve user fixtures. See errors for more information.");
|
|
204
|
-
return registrations;
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
const cleanupFnArrayMap = /* @__PURE__ */ new WeakMap();
|
|
208
|
-
async function callFixtureCleanup(context) {
|
|
209
|
-
const cleanupFnArray = cleanupFnArrayMap.get(context) ?? [];
|
|
210
|
-
for (const cleanup of cleanupFnArray.reverse()) await cleanup();
|
|
211
|
-
cleanupFnArrayMap.delete(context);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Returns the current number of cleanup functions registered for the context.
|
|
215
|
-
* This can be used as a checkpoint to later clean up only fixtures added after this point.
|
|
216
|
-
*/
|
|
217
|
-
function getFixtureCleanupCount(context) {
|
|
218
|
-
return cleanupFnArrayMap.get(context)?.length ?? 0;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Cleans up only fixtures that were added after the given checkpoint index.
|
|
222
|
-
* This is used by aroundEach to clean up fixtures created inside runTest()
|
|
223
|
-
* while preserving fixtures that were created for aroundEach itself.
|
|
224
|
-
*/
|
|
225
|
-
async function callFixtureCleanupFrom(context, fromIndex) {
|
|
226
|
-
const cleanupFnArray = cleanupFnArrayMap.get(context);
|
|
227
|
-
if (!cleanupFnArray || cleanupFnArray.length <= fromIndex) return;
|
|
228
|
-
const toCleanup = cleanupFnArray.slice(fromIndex);
|
|
229
|
-
for (const cleanup of toCleanup.reverse()) await cleanup();
|
|
230
|
-
cleanupFnArray.length = fromIndex;
|
|
231
|
-
}
|
|
232
|
-
const contextHasFixturesCache = /* @__PURE__ */ new WeakMap();
|
|
233
|
-
function withFixtures(fn, options) {
|
|
234
|
-
const collector = getCurrentSuite();
|
|
235
|
-
const suite = options?.suite || collector.suite || collector.file;
|
|
236
|
-
return async (hookContext) => {
|
|
237
|
-
const context = hookContext || options?.context;
|
|
238
|
-
if (!context) {
|
|
239
|
-
if (options?.suiteHook) validateSuiteHook(fn, options.suiteHook, options.stackTraceError);
|
|
240
|
-
return fn({});
|
|
241
|
-
}
|
|
242
|
-
const fixtures = options?.fixtures || getTestFixtures(context);
|
|
243
|
-
if (!fixtures) return fn(context);
|
|
244
|
-
const registrations = fixtures.get(suite);
|
|
245
|
-
if (!registrations.size) return fn(context);
|
|
246
|
-
const usedFixtures = [];
|
|
247
|
-
const usedProps = getUsedProps(fn);
|
|
248
|
-
for (const fixture of registrations.values()) if (isAutoFixture(fixture, options) || usedProps.has(fixture.name)) usedFixtures.push(fixture);
|
|
249
|
-
if (!usedFixtures.length) return fn(context);
|
|
250
|
-
if (!cleanupFnArrayMap.has(context)) cleanupFnArrayMap.set(context, []);
|
|
251
|
-
const cleanupFnArray = cleanupFnArrayMap.get(context);
|
|
252
|
-
const pendingFixtures = resolveDeps(usedFixtures, registrations);
|
|
253
|
-
if (!pendingFixtures.length) return fn(context);
|
|
254
|
-
if (options?.suiteHook) {
|
|
255
|
-
const testScopedFixtures = pendingFixtures.filter((f) => f.scope === "test");
|
|
256
|
-
if (testScopedFixtures.length > 0) {
|
|
257
|
-
const fixtureNames = testScopedFixtures.map((f) => `"${f.name}"`).join(", ");
|
|
258
|
-
const error = new FixtureDependencyError(`Test-scoped fixtures cannot be used inside ${options.suiteHook} hook. The following fixtures are test-scoped: ${fixtureNames}. Use { scope: 'file' } or { scope: 'worker' } fixtures instead, or move the logic to ${{
|
|
259
|
-
aroundAll: "aroundEach",
|
|
260
|
-
beforeAll: "beforeEach",
|
|
261
|
-
afterAll: "afterEach"
|
|
262
|
-
}[options.suiteHook]} hook.`);
|
|
263
|
-
if (options.stackTraceError?.stack) error.stack = error.message + options.stackTraceError.stack.replace(options.stackTraceError.message, "");
|
|
264
|
-
throw error;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
if (!contextHasFixturesCache.has(context)) contextHasFixturesCache.set(context, /* @__PURE__ */ new WeakSet());
|
|
268
|
-
const cachedFixtures = contextHasFixturesCache.get(context);
|
|
269
|
-
for (const fixture of pendingFixtures) if (fixture.scope === "test") {
|
|
270
|
-
if (cachedFixtures.has(fixture)) continue;
|
|
271
|
-
cachedFixtures.add(fixture);
|
|
272
|
-
const resolvedValue = await resolveTestFixtureValue(fixture, context, cleanupFnArray);
|
|
273
|
-
context[fixture.name] = resolvedValue;
|
|
274
|
-
cleanupFnArray.push(() => {
|
|
275
|
-
cachedFixtures.delete(fixture);
|
|
276
|
-
});
|
|
277
|
-
} else {
|
|
278
|
-
const resolvedValue = await resolveScopeFixtureValue(fixtures, suite, fixture);
|
|
279
|
-
context[fixture.name] = resolvedValue;
|
|
280
|
-
}
|
|
281
|
-
return fn(context);
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
function isAutoFixture(fixture, options) {
|
|
285
|
-
if (!fixture.auto) return false;
|
|
286
|
-
if (options?.suiteHook && fixture.scope === "test") return false;
|
|
287
|
-
return true;
|
|
288
|
-
}
|
|
289
|
-
function isFixtureFunction(value) {
|
|
290
|
-
return typeof value === "function";
|
|
291
|
-
}
|
|
292
|
-
function resolveTestFixtureValue(fixture, context, cleanupFnArray) {
|
|
293
|
-
if (!isFixtureFunction(fixture.value)) return fixture.value;
|
|
294
|
-
return resolveFixtureFunction(fixture.value, fixture.name, context, cleanupFnArray);
|
|
295
|
-
}
|
|
296
|
-
const scopedFixturePromiseCache = /* @__PURE__ */ new WeakMap();
|
|
297
|
-
async function resolveScopeFixtureValue(fixtures, suite, fixture) {
|
|
298
|
-
const workerContext = fixtures.getWorkerContext();
|
|
299
|
-
const fileContext = fixtures.getFileContext(suite.file);
|
|
300
|
-
const fixtureContext = fixture.scope === "worker" ? workerContext : fileContext;
|
|
301
|
-
if (!isFixtureFunction(fixture.value)) {
|
|
302
|
-
fixtureContext[fixture.name] = fixture.value;
|
|
303
|
-
return fixture.value;
|
|
304
|
-
}
|
|
305
|
-
if (fixture.name in fixtureContext) return fixtureContext[fixture.name];
|
|
306
|
-
if (scopedFixturePromiseCache.has(fixture)) return scopedFixturePromiseCache.get(fixture);
|
|
307
|
-
if (!cleanupFnArrayMap.has(fixtureContext)) cleanupFnArrayMap.set(fixtureContext, []);
|
|
308
|
-
const cleanupFnFileArray = cleanupFnArrayMap.get(fixtureContext);
|
|
309
|
-
const promise = resolveFixtureFunction(fixture.value, fixture.name, fixture.scope === "file" ? {
|
|
310
|
-
...workerContext,
|
|
311
|
-
...fileContext
|
|
312
|
-
} : fixtureContext, cleanupFnFileArray).then((value) => {
|
|
313
|
-
fixtureContext[fixture.name] = value;
|
|
314
|
-
scopedFixturePromiseCache.delete(fixture);
|
|
315
|
-
return value;
|
|
316
|
-
});
|
|
317
|
-
scopedFixturePromiseCache.set(fixture, promise);
|
|
318
|
-
return promise;
|
|
319
|
-
}
|
|
320
|
-
async function resolveFixtureFunction(fixtureFn, fixtureName, context, cleanupFnArray) {
|
|
321
|
-
const useFnArgPromise = createDefer();
|
|
322
|
-
const stackTraceError = FIXTURE_STACK_TRACE_KEY in fixtureFn && fixtureFn[FIXTURE_STACK_TRACE_KEY] instanceof Error ? fixtureFn[FIXTURE_STACK_TRACE_KEY] : void 0;
|
|
323
|
-
let isUseFnArgResolved = false;
|
|
324
|
-
const fixtureReturn = fixtureFn(context, async (useFnArg) => {
|
|
325
|
-
isUseFnArgResolved = true;
|
|
326
|
-
useFnArgPromise.resolve(useFnArg);
|
|
327
|
-
const useReturnPromise = createDefer();
|
|
328
|
-
cleanupFnArray.push(async () => {
|
|
329
|
-
useReturnPromise.resolve();
|
|
330
|
-
await fixtureReturn;
|
|
331
|
-
});
|
|
332
|
-
await useReturnPromise;
|
|
333
|
-
}).then(() => {
|
|
334
|
-
if (!isUseFnArgResolved) {
|
|
335
|
-
const error = /* @__PURE__ */ new Error(`Fixture "${fixtureName}" returned without calling "use". Make sure to call "use" in every code path of the fixture function.`);
|
|
336
|
-
if (stackTraceError?.stack) error.stack = error.message + stackTraceError.stack.replace(stackTraceError.message, "");
|
|
337
|
-
useFnArgPromise.reject(error);
|
|
338
|
-
}
|
|
339
|
-
}).catch((e) => {
|
|
340
|
-
if (!isUseFnArgResolved) {
|
|
341
|
-
useFnArgPromise.reject(e);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
throw e;
|
|
345
|
-
});
|
|
346
|
-
return useFnArgPromise;
|
|
347
|
-
}
|
|
348
|
-
function resolveDeps(usedFixtures, registrations, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
|
|
349
|
-
usedFixtures.forEach((fixture) => {
|
|
350
|
-
if (pendingFixtures.includes(fixture)) return;
|
|
351
|
-
if (!isFixtureFunction(fixture.value) || !fixture.deps) {
|
|
352
|
-
pendingFixtures.push(fixture);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (depSet.has(fixture)) if (fixture.parent) fixture = fixture.parent;
|
|
356
|
-
else throw new Error(`Circular fixture dependency detected: ${fixture.name} <- ${[...depSet].reverse().map((d) => d.name).join(" <- ")}`);
|
|
357
|
-
depSet.add(fixture);
|
|
358
|
-
resolveDeps([...fixture.deps].map((n) => n === fixture.name ? fixture.parent : registrations.get(n)).filter((n) => !!n), registrations, depSet, pendingFixtures);
|
|
359
|
-
pendingFixtures.push(fixture);
|
|
360
|
-
depSet.clear();
|
|
361
|
-
});
|
|
362
|
-
return pendingFixtures;
|
|
363
|
-
}
|
|
364
|
-
function validateSuiteHook(fn, hook, suiteError) {
|
|
365
|
-
const usedProps = getUsedProps(fn, {
|
|
366
|
-
sourceError: suiteError,
|
|
367
|
-
suiteHook: hook
|
|
368
|
-
});
|
|
369
|
-
if (usedProps.size) {
|
|
370
|
-
const error = new FixtureAccessError(`The ${hook} hook uses fixtures "${[...usedProps].join("\", \"")}", but has no access to context. Did you forget to call it as "test.${hook}()" instead of "${hook}()"?\nIf you used internal "suite" task as the first argument previously, access it in the second argument instead. See https://vitest.dev/guide/test-context#suite-level-hooks`);
|
|
371
|
-
if (suiteError) error.stack = suiteError.stack?.replace(suiteError.message, error.message);
|
|
372
|
-
throw error;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
const kPropsSymbol = Symbol("$vitest:fixture-props");
|
|
376
|
-
const kPropNamesSymbol = Symbol("$vitest:fixture-prop-names");
|
|
377
|
-
function configureProps(fn, options) {
|
|
378
|
-
Object.defineProperty(fn, kPropsSymbol, {
|
|
379
|
-
value: options,
|
|
380
|
-
enumerable: false
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
function memoProps(fn, props) {
|
|
384
|
-
fn[kPropNamesSymbol] = props;
|
|
385
|
-
return props;
|
|
386
|
-
}
|
|
387
|
-
function getUsedProps(fn, { sourceError, suiteHook } = {}) {
|
|
388
|
-
if (kPropNamesSymbol in fn) return fn[kPropNamesSymbol];
|
|
389
|
-
const { index: fixturesIndex = 0, original: implementation = fn } = kPropsSymbol in fn ? fn[kPropsSymbol] : {};
|
|
390
|
-
let fnString = filterOutComments(implementation.toString());
|
|
391
|
-
if (/__async\((?:this|null), (?:null|arguments|\[[_0-9, ]*\]), function\*/.test(fnString)) fnString = fnString.split(/__async\((?:this|null),/)[1];
|
|
392
|
-
const match = fnString.match(/[^(]*\(([^)]*)/);
|
|
393
|
-
if (!match) return memoProps(fn, /* @__PURE__ */ new Set());
|
|
394
|
-
const args = splitByComma(match[1]);
|
|
395
|
-
if (!args.length) return memoProps(fn, /* @__PURE__ */ new Set());
|
|
396
|
-
const fixturesArgument = args[fixturesIndex];
|
|
397
|
-
if (!fixturesArgument) return memoProps(fn, /* @__PURE__ */ new Set());
|
|
398
|
-
if (!(fixturesArgument[0] === "{" && fixturesArgument.endsWith("}"))) {
|
|
399
|
-
const ordinalArgument = ordinal(fixturesIndex + 1);
|
|
400
|
-
const error = new FixtureParseError(`The ${ordinalArgument} argument inside a fixture must use object destructuring pattern, e.g. ({ task } => {}). Instead, received "${fixturesArgument}".${suiteHook ? ` If you used internal "suite" task as the ${ordinalArgument} argument previously, access it in the ${ordinal(fixturesIndex + 2)} argument instead.` : ""}`);
|
|
401
|
-
if (sourceError) error.stack = sourceError.stack?.replace(sourceError.message, error.message);
|
|
402
|
-
throw error;
|
|
403
|
-
}
|
|
404
|
-
const props = splitByComma(fixturesArgument.slice(1, -1).replace(/\s/g, "")).map((prop) => {
|
|
405
|
-
return prop.replace(/:.*|=.*/g, "");
|
|
406
|
-
});
|
|
407
|
-
const last = props.at(-1);
|
|
408
|
-
if (last && last.startsWith("...")) {
|
|
409
|
-
const error = new FixtureParseError(`Rest parameters are not supported in fixtures, received "${last}".`);
|
|
410
|
-
if (sourceError) error.stack = sourceError.stack?.replace(sourceError.message, error.message);
|
|
411
|
-
throw error;
|
|
412
|
-
}
|
|
413
|
-
return memoProps(fn, new Set(props));
|
|
414
|
-
}
|
|
415
|
-
function splitByComma(s) {
|
|
416
|
-
const result = [];
|
|
417
|
-
const stack = [];
|
|
418
|
-
let start = 0;
|
|
419
|
-
for (let i = 0; i < s.length; i++) if (s[i] === "{" || s[i] === "[") stack.push(s[i] === "{" ? "}" : "]");
|
|
420
|
-
else if (s[i] === stack.at(-1)) stack.pop();
|
|
421
|
-
else if (!stack.length && s[i] === ",") {
|
|
422
|
-
const token = s.substring(start, i).trim();
|
|
423
|
-
if (token) result.push(token);
|
|
424
|
-
start = i + 1;
|
|
425
|
-
}
|
|
426
|
-
const lastToken = s.substring(start).trim();
|
|
427
|
-
if (lastToken) result.push(lastToken);
|
|
428
|
-
return result;
|
|
429
|
-
}
|
|
430
|
-
let _test;
|
|
431
|
-
function setCurrentTest(test) {
|
|
432
|
-
_test = test;
|
|
433
|
-
}
|
|
434
|
-
function getCurrentTest() {
|
|
435
|
-
return _test;
|
|
436
|
-
}
|
|
437
|
-
const tests = [];
|
|
438
|
-
function addRunningTest(test) {
|
|
439
|
-
tests.push(test);
|
|
440
|
-
return () => {
|
|
441
|
-
tests.splice(tests.indexOf(test));
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function getRunningTests() {
|
|
445
|
-
return tests;
|
|
446
|
-
}
|
|
447
|
-
const kChainableContext = Symbol("kChainableContext");
|
|
448
|
-
function getChainableContext(chainable) {
|
|
449
|
-
return chainable?.[kChainableContext];
|
|
450
|
-
}
|
|
451
|
-
function createChainable(keys, fn, context) {
|
|
452
|
-
function create(context) {
|
|
453
|
-
const chain = function(...args) {
|
|
454
|
-
return fn.apply(context, args);
|
|
455
|
-
};
|
|
456
|
-
Object.assign(chain, fn);
|
|
457
|
-
Object.defineProperty(chain, kChainableContext, {
|
|
458
|
-
value: {
|
|
459
|
-
withContext: () => chain.bind(context),
|
|
460
|
-
getFixtures: () => context.fixtures,
|
|
461
|
-
setContext: (key, value) => {
|
|
462
|
-
context[key] = value;
|
|
463
|
-
},
|
|
464
|
-
mergeContext: (ctx) => {
|
|
465
|
-
Object.assign(context, ctx);
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
enumerable: false
|
|
469
|
-
});
|
|
470
|
-
for (const key of keys) Object.defineProperty(chain, key, { get() {
|
|
471
|
-
return create({
|
|
472
|
-
...context,
|
|
473
|
-
[key]: true
|
|
474
|
-
});
|
|
475
|
-
} });
|
|
476
|
-
return chain;
|
|
477
|
-
}
|
|
478
|
-
const chain = create(context ?? {});
|
|
479
|
-
Object.defineProperty(chain, "fn", {
|
|
480
|
-
value: fn,
|
|
481
|
-
enumerable: false
|
|
482
|
-
});
|
|
483
|
-
return chain;
|
|
484
|
-
}
|
|
485
|
-
function getDefaultHookTimeout() {
|
|
486
|
-
return getRunner().config.hookTimeout;
|
|
487
|
-
}
|
|
488
|
-
const CLEANUP_TIMEOUT_KEY = Symbol.for("VITEST_CLEANUP_TIMEOUT");
|
|
489
|
-
const CLEANUP_STACK_TRACE_KEY = Symbol.for("VITEST_CLEANUP_STACK_TRACE");
|
|
490
|
-
const AROUND_TIMEOUT_KEY = Symbol.for("VITEST_AROUND_TIMEOUT");
|
|
491
|
-
const AROUND_STACK_TRACE_KEY = Symbol.for("VITEST_AROUND_STACK_TRACE");
|
|
492
|
-
function getBeforeHookCleanupCallback(hook, result, context) {
|
|
493
|
-
if (typeof result === "function") return withTimeout(result, CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === "number" ? hook[CLEANUP_TIMEOUT_KEY] : getDefaultHookTimeout(), true, CLEANUP_STACK_TRACE_KEY in hook && hook[CLEANUP_STACK_TRACE_KEY] instanceof Error ? hook[CLEANUP_STACK_TRACE_KEY] : void 0, (_, error) => {
|
|
494
|
-
if (context) abortContextSignal(context, error);
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Registers a callback function to be executed once before all tests within the current suite.
|
|
499
|
-
* This hook is useful for scenarios where you need to perform setup operations that are common to all tests in a suite, such as initializing a database connection or setting up a test environment.
|
|
500
|
-
*
|
|
501
|
-
* **Note:** The `beforeAll` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
502
|
-
*
|
|
503
|
-
* @param {Function} fn - The callback function to be executed before all tests.
|
|
504
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
505
|
-
* @returns {void}
|
|
506
|
-
* @example
|
|
507
|
-
* ```ts
|
|
508
|
-
* // Example of using beforeAll to set up a database connection
|
|
509
|
-
* beforeAll(async () => {
|
|
510
|
-
* await database.connect();
|
|
511
|
-
* });
|
|
512
|
-
* ```
|
|
513
|
-
*/
|
|
514
|
-
function beforeAll(fn, timeout = getDefaultHookTimeout()) {
|
|
515
|
-
assertTypes(fn, "\"beforeAll\" callback", ["function"]);
|
|
516
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
517
|
-
const context = getChainableContext(this);
|
|
518
|
-
return getCurrentSuite().on("beforeAll", Object.assign(withTimeout(withSuiteFixtures("beforeAll", fn, context, stackTraceError), timeout, true, stackTraceError), {
|
|
519
|
-
[CLEANUP_TIMEOUT_KEY]: timeout,
|
|
520
|
-
[CLEANUP_STACK_TRACE_KEY]: stackTraceError
|
|
521
|
-
}));
|
|
522
|
-
}
|
|
523
|
-
/**
|
|
524
|
-
* Registers a callback function to be executed once after all tests within the current suite have completed.
|
|
525
|
-
* This hook is useful for scenarios where you need to perform cleanup operations after all tests in a suite have run, such as closing database connections or cleaning up temporary files.
|
|
526
|
-
*
|
|
527
|
-
* **Note:** The `afterAll` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
528
|
-
*
|
|
529
|
-
* @param {Function} fn - The callback function to be executed after all tests.
|
|
530
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
531
|
-
* @returns {void}
|
|
532
|
-
* @example
|
|
533
|
-
* ```ts
|
|
534
|
-
* // Example of using afterAll to close a database connection
|
|
535
|
-
* afterAll(async () => {
|
|
536
|
-
* await database.disconnect();
|
|
537
|
-
* });
|
|
538
|
-
* ```
|
|
539
|
-
*/
|
|
540
|
-
function afterAll(fn, timeout) {
|
|
541
|
-
assertTypes(fn, "\"afterAll\" callback", ["function"]);
|
|
542
|
-
const context = getChainableContext(this);
|
|
543
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
544
|
-
return getCurrentSuite().on("afterAll", withTimeout(withSuiteFixtures("afterAll", fn, context, stackTraceError), timeout ?? getDefaultHookTimeout(), true, stackTraceError));
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Registers a callback function to be executed before each test within the current suite.
|
|
548
|
-
* This hook is useful for scenarios where you need to reset or reinitialize the test environment before each test runs, such as resetting database states, clearing caches, or reinitializing variables.
|
|
549
|
-
*
|
|
550
|
-
* **Note:** The `beforeEach` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
551
|
-
*
|
|
552
|
-
* @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed.
|
|
553
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
554
|
-
* @returns {void}
|
|
555
|
-
* @example
|
|
556
|
-
* ```ts
|
|
557
|
-
* // Example of using beforeEach to reset a database state
|
|
558
|
-
* beforeEach(async () => {
|
|
559
|
-
* await database.reset();
|
|
560
|
-
* });
|
|
561
|
-
* ```
|
|
562
|
-
*/
|
|
563
|
-
function beforeEach(fn, timeout = getDefaultHookTimeout()) {
|
|
564
|
-
assertTypes(fn, "\"beforeEach\" callback", ["function"]);
|
|
565
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
566
|
-
const wrapper = (context, suite) => {
|
|
567
|
-
return withFixtures(fn, { suite })(context);
|
|
568
|
-
};
|
|
569
|
-
return getCurrentSuite().on("beforeEach", Object.assign(withTimeout(wrapper, timeout ?? getDefaultHookTimeout(), true, stackTraceError, abortIfTimeout), {
|
|
570
|
-
[CLEANUP_TIMEOUT_KEY]: timeout,
|
|
571
|
-
[CLEANUP_STACK_TRACE_KEY]: stackTraceError
|
|
572
|
-
}));
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Registers a callback function to be executed after each test within the current suite has completed.
|
|
576
|
-
* This hook is useful for scenarios where you need to clean up or reset the test environment after each test runs, such as deleting temporary files, clearing test-specific database entries, or resetting mocked functions.
|
|
577
|
-
*
|
|
578
|
-
* **Note:** The `afterEach` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
579
|
-
*
|
|
580
|
-
* @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed.
|
|
581
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
582
|
-
* @returns {void}
|
|
583
|
-
* @example
|
|
584
|
-
* ```ts
|
|
585
|
-
* // Example of using afterEach to delete temporary files created during a test
|
|
586
|
-
* afterEach(async () => {
|
|
587
|
-
* await fileSystem.deleteTempFiles();
|
|
588
|
-
* });
|
|
589
|
-
* ```
|
|
590
|
-
*/
|
|
591
|
-
function afterEach(fn, timeout) {
|
|
592
|
-
assertTypes(fn, "\"afterEach\" callback", ["function"]);
|
|
593
|
-
const wrapper = (context, suite) => {
|
|
594
|
-
return withFixtures(fn, { suite })(context);
|
|
595
|
-
};
|
|
596
|
-
return getCurrentSuite().on("afterEach", withTimeout(wrapper, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Registers a callback function to be executed when a test fails within the current suite.
|
|
600
|
-
* This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
|
|
601
|
-
*
|
|
602
|
-
* **Note:** The `onTestFailed` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
603
|
-
*
|
|
604
|
-
* @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
|
|
605
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
606
|
-
* @throws {Error} Throws an error if the function is not called within a test.
|
|
607
|
-
* @returns {void}
|
|
608
|
-
* @example
|
|
609
|
-
* ```ts
|
|
610
|
-
* // Example of using onTestFailed to log failure details
|
|
611
|
-
* onTestFailed(({ errors }) => {
|
|
612
|
-
* console.log(`Test failed: ${test.name}`, errors);
|
|
613
|
-
* });
|
|
614
|
-
* ```
|
|
615
|
-
*/
|
|
616
|
-
const onTestFailed = createTestHook("onTestFailed", (test, handler, timeout) => {
|
|
617
|
-
test.onFailed ||= [];
|
|
618
|
-
test.onFailed.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
|
|
619
|
-
});
|
|
620
|
-
/**
|
|
621
|
-
* Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
|
|
622
|
-
* This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
|
|
623
|
-
*
|
|
624
|
-
* This hook is useful if you have access to a resource in the test itself and you want to clean it up after the test finishes. It is a more compact way to clean up resources than using the combination of `beforeEach` and `afterEach`.
|
|
625
|
-
*
|
|
626
|
-
* **Note:** The `onTestFinished` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
|
|
627
|
-
*
|
|
628
|
-
* **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
|
|
629
|
-
*
|
|
630
|
-
* @param {Function} fn - The callback function to be executed after a test finishes. The function can receive parameters providing details about the completed test, including its success or failure status.
|
|
631
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
632
|
-
* @throws {Error} Throws an error if the function is not called within a test.
|
|
633
|
-
* @returns {void}
|
|
634
|
-
* @example
|
|
635
|
-
* ```ts
|
|
636
|
-
* // Example of using onTestFinished for cleanup
|
|
637
|
-
* const db = await connectToDatabase();
|
|
638
|
-
* onTestFinished(async () => {
|
|
639
|
-
* await db.disconnect();
|
|
640
|
-
* });
|
|
641
|
-
* ```
|
|
642
|
-
*/
|
|
643
|
-
const onTestFinished = createTestHook("onTestFinished", (test, handler, timeout) => {
|
|
644
|
-
test.onFinished ||= [];
|
|
645
|
-
test.onFinished.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
|
|
646
|
-
});
|
|
647
|
-
/**
|
|
648
|
-
* Registers a callback function that wraps around all tests within the current suite.
|
|
649
|
-
* The callback receives a `runSuite` function that must be called to run the suite's tests.
|
|
650
|
-
* This hook is useful for scenarios where you need to wrap an entire suite in a context
|
|
651
|
-
* (e.g., starting a server, opening a database connection that all tests share).
|
|
652
|
-
*
|
|
653
|
-
* **Note:** When multiple `aroundAll` hooks are registered, they are nested inside each other.
|
|
654
|
-
* The first registered hook is the outermost wrapper.
|
|
655
|
-
*
|
|
656
|
-
* @param {Function} fn - The callback function that wraps the suite. Must call `runSuite()` to run the tests.
|
|
657
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
658
|
-
* @returns {void}
|
|
659
|
-
* @example
|
|
660
|
-
* ```ts
|
|
661
|
-
* // Example of using aroundAll to wrap suite in a tracing span
|
|
662
|
-
* aroundAll(async (runSuite) => {
|
|
663
|
-
* await tracer.trace('test-suite', runSuite);
|
|
664
|
-
* });
|
|
665
|
-
* ```
|
|
666
|
-
* @example
|
|
667
|
-
* ```ts
|
|
668
|
-
* // Example of using aroundAll with fixtures
|
|
669
|
-
* aroundAll(async (runSuite, { db }) => {
|
|
670
|
-
* await db.transaction(() => runSuite());
|
|
671
|
-
* });
|
|
672
|
-
* ```
|
|
673
|
-
*/
|
|
674
|
-
function aroundAll(fn, timeout) {
|
|
675
|
-
assertTypes(fn, "\"aroundAll\" callback", ["function"]);
|
|
676
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
677
|
-
const resolvedTimeout = timeout ?? getDefaultHookTimeout();
|
|
678
|
-
const context = getChainableContext(this);
|
|
679
|
-
return getCurrentSuite().on("aroundAll", Object.assign(withSuiteFixtures("aroundAll", fn, context, stackTraceError, 1), {
|
|
680
|
-
[AROUND_TIMEOUT_KEY]: resolvedTimeout,
|
|
681
|
-
[AROUND_STACK_TRACE_KEY]: stackTraceError
|
|
682
|
-
}));
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* Registers a callback function that wraps around each test within the current suite.
|
|
686
|
-
* The callback receives a `runTest` function that must be called to run the test.
|
|
687
|
-
* This hook is useful for scenarios where you need to wrap tests in a context (e.g., database transactions).
|
|
688
|
-
*
|
|
689
|
-
* **Note:** When multiple `aroundEach` hooks are registered, they are nested inside each other.
|
|
690
|
-
* The first registered hook is the outermost wrapper.
|
|
691
|
-
*
|
|
692
|
-
* @param {Function} fn - The callback function that wraps the test. Must call `runTest()` to run the test.
|
|
693
|
-
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
694
|
-
* @returns {void}
|
|
695
|
-
* @example
|
|
696
|
-
* ```ts
|
|
697
|
-
* // Example of using aroundEach to wrap tests in a database transaction
|
|
698
|
-
* aroundEach(async (runTest) => {
|
|
699
|
-
* await database.transaction(() => runTest());
|
|
700
|
-
* });
|
|
701
|
-
* ```
|
|
702
|
-
* @example
|
|
703
|
-
* ```ts
|
|
704
|
-
* // Example of using aroundEach with fixtures
|
|
705
|
-
* aroundEach(async (runTest, { db }) => {
|
|
706
|
-
* await db.transaction(() => runTest());
|
|
707
|
-
* });
|
|
708
|
-
* ```
|
|
709
|
-
*/
|
|
710
|
-
function aroundEach(fn, timeout) {
|
|
711
|
-
assertTypes(fn, "\"aroundEach\" callback", ["function"]);
|
|
712
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
713
|
-
const resolvedTimeout = timeout ?? getDefaultHookTimeout();
|
|
714
|
-
const wrapper = (runTest, context, suite) => {
|
|
715
|
-
const innerFn = (ctx) => fn(runTest, ctx, suite);
|
|
716
|
-
configureProps(innerFn, {
|
|
717
|
-
index: 1,
|
|
718
|
-
original: fn
|
|
719
|
-
});
|
|
720
|
-
return withFixtures(innerFn, { suite })(context);
|
|
721
|
-
};
|
|
722
|
-
return getCurrentSuite().on("aroundEach", Object.assign(wrapper, {
|
|
723
|
-
[AROUND_TIMEOUT_KEY]: resolvedTimeout,
|
|
724
|
-
[AROUND_STACK_TRACE_KEY]: stackTraceError
|
|
725
|
-
}));
|
|
726
|
-
}
|
|
727
|
-
function withSuiteFixtures(suiteHook, fn, context, stackTraceError, contextIndex = 0) {
|
|
728
|
-
return (...args) => {
|
|
729
|
-
const suite = args.at(-1);
|
|
730
|
-
const prefix = args.slice(0, -1);
|
|
731
|
-
const wrapper = (ctx) => fn(...prefix, ctx, suite);
|
|
732
|
-
configureProps(wrapper, {
|
|
733
|
-
index: contextIndex,
|
|
734
|
-
original: fn
|
|
735
|
-
});
|
|
736
|
-
const fixtures = context?.getFixtures();
|
|
737
|
-
const fileContext = fixtures?.getFileContext(suite.file);
|
|
738
|
-
return withFixtures(wrapper, {
|
|
739
|
-
suiteHook,
|
|
740
|
-
fixtures,
|
|
741
|
-
context: fileContext,
|
|
742
|
-
stackTraceError
|
|
743
|
-
})();
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
function getAroundHookTimeout(hook) {
|
|
747
|
-
return AROUND_TIMEOUT_KEY in hook && typeof hook[AROUND_TIMEOUT_KEY] === "number" ? hook[AROUND_TIMEOUT_KEY] : getDefaultHookTimeout();
|
|
748
|
-
}
|
|
749
|
-
function getAroundHookStackTrace(hook) {
|
|
750
|
-
return AROUND_STACK_TRACE_KEY in hook && hook[AROUND_STACK_TRACE_KEY] instanceof Error ? hook[AROUND_STACK_TRACE_KEY] : void 0;
|
|
751
|
-
}
|
|
752
|
-
function createTestHook(name, handler) {
|
|
753
|
-
return (fn, timeout) => {
|
|
754
|
-
assertTypes(fn, `"${name}" callback`, ["function"]);
|
|
755
|
-
const current = getCurrentTest();
|
|
756
|
-
if (!current) throw new Error(`Hook ${name}() can only be called inside a test`);
|
|
757
|
-
return handler(current, fn, timeout);
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
|
762
|
-
*/
|
|
763
|
-
function interpretTaskModes(file, namePattern, testLocations, testIds, testTagsFilter, onlyMode, parentIsOnly, allowOnly) {
|
|
764
|
-
const matchedLocations = [];
|
|
765
|
-
const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
|
|
766
|
-
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
|
767
|
-
const hasSomeTasksOnly = onlyMode && suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
|
768
|
-
suite.tasks.forEach((t) => {
|
|
769
|
-
const includeTask = hasSomeTasksOnly ? t.mode === "only" || t.type === "suite" && someTasksAreOnly(t) : suiteIsOnly || t.mode === "only";
|
|
770
|
-
if (onlyMode) {
|
|
771
|
-
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
|
772
|
-
if (t.mode === "only") {
|
|
773
|
-
checkAllowOnly(t, allowOnly);
|
|
774
|
-
t.mode = "run";
|
|
775
|
-
}
|
|
776
|
-
} else if (t.mode === "run" && !includeTask) t.mode = "skip";
|
|
777
|
-
else if (t.mode === "only") {
|
|
778
|
-
checkAllowOnly(t, allowOnly);
|
|
779
|
-
t.mode = "run";
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
let hasLocationMatch = parentMatchedWithLocation;
|
|
783
|
-
if (testLocations !== void 0 && testLocations.length !== 0) {
|
|
784
|
-
if (t.location && testLocations?.includes(t.location.line)) {
|
|
785
|
-
t.mode = "run";
|
|
786
|
-
matchedLocations.push(t.location.line);
|
|
787
|
-
hasLocationMatch = true;
|
|
788
|
-
} else if (parentMatchedWithLocation) t.mode = "run";
|
|
789
|
-
else if (t.type === "test") t.mode = "skip";
|
|
790
|
-
}
|
|
791
|
-
if (t.type === "test") {
|
|
792
|
-
if (namePattern && !getTaskFullName(t).match(namePattern)) t.mode = "skip";
|
|
793
|
-
if (testIds && !testIds.includes(t.id)) t.mode = "skip";
|
|
794
|
-
if (testTagsFilter && !testTagsFilter(t.tags || [])) t.mode = "skip";
|
|
795
|
-
} else if (t.type === "suite") if (t.mode === "skip") skipAllTasks(t);
|
|
796
|
-
else if (t.mode === "todo") todoAllTasks(t);
|
|
797
|
-
else traverseSuite(t, includeTask, hasLocationMatch);
|
|
798
|
-
});
|
|
799
|
-
if (suite.mode === "run" || suite.mode === "queued") {
|
|
800
|
-
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) suite.mode = "skip";
|
|
801
|
-
}
|
|
802
|
-
};
|
|
803
|
-
traverseSuite(file, parentIsOnly, false);
|
|
804
|
-
const nonMatching = testLocations?.filter((loc) => !matchedLocations.includes(loc));
|
|
805
|
-
if (nonMatching && nonMatching.length !== 0) {
|
|
806
|
-
const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
|
|
807
|
-
if (file.result === void 0) file.result = {
|
|
808
|
-
state: "fail",
|
|
809
|
-
errors: []
|
|
810
|
-
};
|
|
811
|
-
if (file.result.errors === void 0) file.result.errors = [];
|
|
812
|
-
file.result.errors.push(processError(/* @__PURE__ */ new Error(`No test found in ${file.name} in ${message}`)));
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
function getTaskFullName(task) {
|
|
816
|
-
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
|
817
|
-
}
|
|
818
|
-
function someTasksAreOnly(suite) {
|
|
819
|
-
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
|
820
|
-
}
|
|
821
|
-
function skipAllTasks(suite) {
|
|
822
|
-
suite.tasks.forEach((t) => {
|
|
823
|
-
if (t.mode === "run" || t.mode === "queued") {
|
|
824
|
-
t.mode = "skip";
|
|
825
|
-
if (t.type === "suite") skipAllTasks(t);
|
|
826
|
-
}
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
function todoAllTasks(suite) {
|
|
830
|
-
suite.tasks.forEach((t) => {
|
|
831
|
-
if (t.mode === "run" || t.mode === "queued") {
|
|
832
|
-
t.mode = "todo";
|
|
833
|
-
if (t.type === "suite") todoAllTasks(t);
|
|
834
|
-
}
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
function checkAllowOnly(task, allowOnly) {
|
|
838
|
-
if (allowOnly) return;
|
|
839
|
-
task.result = {
|
|
840
|
-
state: "fail",
|
|
841
|
-
errors: [processError(/* @__PURE__ */ new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"))]
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
/* @__NO_SIDE_EFFECTS__ */
|
|
845
|
-
function generateHash(str) {
|
|
846
|
-
let hash = 0;
|
|
847
|
-
if (str.length === 0) return `${hash}`;
|
|
848
|
-
for (let i = 0; i < str.length; i++) {
|
|
849
|
-
const char = str.charCodeAt(i);
|
|
850
|
-
hash = (hash << 5) - hash + char;
|
|
851
|
-
hash = hash & hash;
|
|
852
|
-
}
|
|
853
|
-
return `${hash}`;
|
|
854
|
-
}
|
|
855
|
-
function calculateSuiteHash(parent) {
|
|
856
|
-
parent.tasks.forEach((t, idx) => {
|
|
857
|
-
t.id = `${parent.id}_${idx}`;
|
|
858
|
-
if (t.type === "suite") calculateSuiteHash(t);
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
function createFileTask(filepath, root, projectName, pool, viteEnvironment) {
|
|
862
|
-
const path = relative(root, filepath);
|
|
863
|
-
const file = {
|
|
864
|
-
id: /* @__PURE__ */ generateFileHash(path, projectName),
|
|
865
|
-
name: path,
|
|
866
|
-
fullName: path,
|
|
867
|
-
type: "suite",
|
|
868
|
-
mode: "queued",
|
|
869
|
-
filepath,
|
|
870
|
-
tasks: [],
|
|
871
|
-
meta: Object.create(null),
|
|
872
|
-
projectName,
|
|
873
|
-
file: void 0,
|
|
874
|
-
pool,
|
|
875
|
-
viteEnvironment
|
|
876
|
-
};
|
|
877
|
-
file.file = file;
|
|
878
|
-
return file;
|
|
879
|
-
}
|
|
880
|
-
/**
|
|
881
|
-
* Generate a unique ID for a file based on its path and project name
|
|
882
|
-
* @param file File relative to the root of the project to keep ID the same between different machines
|
|
883
|
-
* @param projectName The name of the test project
|
|
884
|
-
*/
|
|
885
|
-
/* @__NO_SIDE_EFFECTS__ */
|
|
886
|
-
function generateFileHash(file, projectName) {
|
|
887
|
-
return /* @__PURE__ */ generateHash(`${file}${projectName || ""}`);
|
|
888
|
-
}
|
|
889
|
-
function findTestFileStackTrace(testFilePath, error) {
|
|
890
|
-
const lines = error.split("\n").slice(1);
|
|
891
|
-
for (const line of lines) {
|
|
892
|
-
const stack = parseSingleStack(line);
|
|
893
|
-
if (stack && stack.file === testFilePath) return stack;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Return a function for running multiple async operations with limited concurrency.
|
|
898
|
-
*/
|
|
899
|
-
function limitConcurrency(concurrency = Infinity) {
|
|
900
|
-
let count = 0;
|
|
901
|
-
let head;
|
|
902
|
-
let tail;
|
|
903
|
-
const finish = () => {
|
|
904
|
-
count--;
|
|
905
|
-
if (head) {
|
|
906
|
-
head[0]();
|
|
907
|
-
head = head[1];
|
|
908
|
-
tail = head && tail;
|
|
909
|
-
}
|
|
910
|
-
};
|
|
911
|
-
const acquire = () => {
|
|
912
|
-
let released = false;
|
|
913
|
-
const release = () => {
|
|
914
|
-
if (!released) {
|
|
915
|
-
released = true;
|
|
916
|
-
finish();
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
if (count++ < concurrency) return release;
|
|
920
|
-
return new Promise((resolve) => {
|
|
921
|
-
if (tail) tail = tail[1] = [() => resolve(release)];
|
|
922
|
-
else head = tail = [() => resolve(release)];
|
|
923
|
-
});
|
|
924
|
-
};
|
|
925
|
-
const limiterFn = (func, ...args) => {
|
|
926
|
-
function run(release) {
|
|
927
|
-
try {
|
|
928
|
-
const result = func(...args);
|
|
929
|
-
if (result instanceof Promise) return result.finally(release);
|
|
930
|
-
release();
|
|
931
|
-
return Promise.resolve(result);
|
|
932
|
-
} catch (error) {
|
|
933
|
-
release();
|
|
934
|
-
return Promise.reject(error);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
const release = acquire();
|
|
938
|
-
return release instanceof Promise ? release.then(run) : run(release);
|
|
939
|
-
};
|
|
940
|
-
return Object.assign(limiterFn, { acquire });
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Partition in tasks groups by consecutive concurrent
|
|
944
|
-
*/
|
|
945
|
-
function partitionSuiteChildren(suite) {
|
|
946
|
-
let tasksGroup = [];
|
|
947
|
-
const tasksGroups = [];
|
|
948
|
-
for (const c of suite.tasks) if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) tasksGroup.push(c);
|
|
949
|
-
else {
|
|
950
|
-
tasksGroups.push(tasksGroup);
|
|
951
|
-
tasksGroup = [c];
|
|
952
|
-
}
|
|
953
|
-
if (tasksGroup.length > 0) tasksGroups.push(tasksGroup);
|
|
954
|
-
return tasksGroups;
|
|
955
|
-
}
|
|
956
|
-
const filterMap = /* @__PURE__ */ new WeakMap();
|
|
957
|
-
/**
|
|
958
|
-
* @experimental
|
|
959
|
-
*/
|
|
960
|
-
function matchesTags(testTags) {
|
|
961
|
-
const runner = getRunner();
|
|
962
|
-
const tagsFilter = runner._currentSpecification?.testTagsFilter ?? runner.config.tagsFilter;
|
|
963
|
-
if (!tagsFilter) return true;
|
|
964
|
-
let tagsFilterPredicate = filterMap.get(tagsFilter);
|
|
965
|
-
if (!tagsFilterPredicate) {
|
|
966
|
-
tagsFilterPredicate = createTagsFilter(tagsFilter, runner.config.tags);
|
|
967
|
-
filterMap.set(tagsFilter, tagsFilterPredicate);
|
|
968
|
-
}
|
|
969
|
-
return tagsFilterPredicate(testTags);
|
|
970
|
-
}
|
|
971
|
-
function validateTags(config, tags) {
|
|
972
|
-
if (!config.strictTags) return;
|
|
973
|
-
const availableTags = new Set(config.tags.map((tag) => tag.name));
|
|
974
|
-
for (const tag of tags) if (!availableTags.has(tag)) throw createNoTagsError(config.tags, tag);
|
|
975
|
-
}
|
|
976
|
-
function createNoTagsError(availableTags, tag, prefix = "tag") {
|
|
977
|
-
if (!availableTags.length) throw new Error(`The Vitest config does't define any "tags", cannot apply "${tag}" ${prefix} for this test. See: https://vitest.dev/guide/test-tags`);
|
|
978
|
-
throw new Error(`The ${prefix} "${tag}" is not defined in the configuration. Available tags are:\n${availableTags.map((t) => `- ${t.name}${t.description ? `: ${t.description}` : ""}`).join("\n")}`);
|
|
979
|
-
}
|
|
980
|
-
function createTagsFilter(tagsExpr, availableTags) {
|
|
981
|
-
const matchers = tagsExpr.map((expr) => parseTagsExpression(expr, availableTags));
|
|
982
|
-
return (testTags) => {
|
|
983
|
-
return matchers.every((matcher) => matcher(testTags));
|
|
984
|
-
};
|
|
985
|
-
}
|
|
986
|
-
function parseTagsExpression(expr, availableTags) {
|
|
987
|
-
const stream = new TokenStream(tokenize(expr), expr);
|
|
988
|
-
const ast = parseOrExpression(stream, availableTags);
|
|
989
|
-
if (stream.peek().type !== "EOF") throw new Error(`Invalid tags expression: unexpected "${formatToken(stream.peek())}" in "${expr}"`);
|
|
990
|
-
return (tags) => evaluateNode(ast, tags);
|
|
991
|
-
}
|
|
992
|
-
function formatToken(token) {
|
|
993
|
-
switch (token.type) {
|
|
994
|
-
case "TAG": return token.value;
|
|
995
|
-
default: return formatTokenType(token.type);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
function tokenize(expr) {
|
|
999
|
-
const tokens = [];
|
|
1000
|
-
let i = 0;
|
|
1001
|
-
while (i < expr.length) {
|
|
1002
|
-
if (expr[i] === " " || expr[i] === " ") {
|
|
1003
|
-
i++;
|
|
1004
|
-
continue;
|
|
1005
|
-
}
|
|
1006
|
-
if (expr[i] === "(") {
|
|
1007
|
-
tokens.push({ type: "LPAREN" });
|
|
1008
|
-
i++;
|
|
1009
|
-
continue;
|
|
1010
|
-
}
|
|
1011
|
-
if (expr[i] === ")") {
|
|
1012
|
-
tokens.push({ type: "RPAREN" });
|
|
1013
|
-
i++;
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
if (expr[i] === "!") {
|
|
1017
|
-
tokens.push({ type: "NOT" });
|
|
1018
|
-
i++;
|
|
1019
|
-
continue;
|
|
1020
|
-
}
|
|
1021
|
-
if (expr.slice(i, i + 2) === "&&") {
|
|
1022
|
-
tokens.push({ type: "AND" });
|
|
1023
|
-
i += 2;
|
|
1024
|
-
continue;
|
|
1025
|
-
}
|
|
1026
|
-
if (expr.slice(i, i + 2) === "||") {
|
|
1027
|
-
tokens.push({ type: "OR" });
|
|
1028
|
-
i += 2;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
if (/^and(?:\s|\)|$)/i.test(expr.slice(i))) {
|
|
1032
|
-
tokens.push({ type: "AND" });
|
|
1033
|
-
i += 3;
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
if (/^or(?:\s|\)|$)/i.test(expr.slice(i))) {
|
|
1037
|
-
tokens.push({ type: "OR" });
|
|
1038
|
-
i += 2;
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
if (/^not\s/i.test(expr.slice(i))) {
|
|
1042
|
-
tokens.push({ type: "NOT" });
|
|
1043
|
-
i += 3;
|
|
1044
|
-
continue;
|
|
1045
|
-
}
|
|
1046
|
-
let tag = "";
|
|
1047
|
-
while (i < expr.length && expr[i] !== " " && expr[i] !== " " && expr[i] !== "(" && expr[i] !== ")" && expr[i] !== "!" && expr[i] !== "&" && expr[i] !== "|") {
|
|
1048
|
-
const remaining = expr.slice(i);
|
|
1049
|
-
if (tag === "" && (/^and(?:\s|\)|$)/i.test(remaining) || /^or(?:\s|\)|$)/i.test(remaining) || /^not\s/i.test(remaining))) break;
|
|
1050
|
-
tag += expr[i];
|
|
1051
|
-
i++;
|
|
1052
|
-
}
|
|
1053
|
-
if (tag) tokens.push({
|
|
1054
|
-
type: "TAG",
|
|
1055
|
-
value: tag
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
tokens.push({ type: "EOF" });
|
|
1059
|
-
return tokens;
|
|
1060
|
-
}
|
|
1061
|
-
var TokenStream = class {
|
|
1062
|
-
pos = 0;
|
|
1063
|
-
constructor(tokens, expr) {
|
|
1064
|
-
this.tokens = tokens;
|
|
1065
|
-
this.expr = expr;
|
|
1066
|
-
}
|
|
1067
|
-
peek() {
|
|
1068
|
-
return this.tokens[this.pos];
|
|
1069
|
-
}
|
|
1070
|
-
next() {
|
|
1071
|
-
return this.tokens[this.pos++];
|
|
1072
|
-
}
|
|
1073
|
-
expect(type) {
|
|
1074
|
-
const token = this.next();
|
|
1075
|
-
if (token.type !== type) {
|
|
1076
|
-
if (type === "RPAREN" && token.type === "EOF") throw new Error(`Invalid tags expression: missing closing ")" in "${this.expr}"`);
|
|
1077
|
-
throw new Error(`Invalid tags expression: expected "${formatTokenType(type)}" but got "${formatToken(token)}" in "${this.expr}"`);
|
|
1078
|
-
}
|
|
1079
|
-
return token;
|
|
1080
|
-
}
|
|
1081
|
-
unexpectedToken() {
|
|
1082
|
-
const token = this.peek();
|
|
1083
|
-
if (token.type === "EOF") throw new Error(`Invalid tags expression: unexpected end of expression in "${this.expr}"`);
|
|
1084
|
-
throw new Error(`Invalid tags expression: unexpected "${formatToken(token)}" in "${this.expr}"`);
|
|
1085
|
-
}
|
|
1086
|
-
};
|
|
1087
|
-
function formatTokenType(type) {
|
|
1088
|
-
switch (type) {
|
|
1089
|
-
case "TAG": return "tag";
|
|
1090
|
-
case "AND": return "and";
|
|
1091
|
-
case "OR": return "or";
|
|
1092
|
-
case "NOT": return "not";
|
|
1093
|
-
case "LPAREN": return "(";
|
|
1094
|
-
case "RPAREN": return ")";
|
|
1095
|
-
case "EOF": return "end of expression";
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
function parseOrExpression(stream, availableTags) {
|
|
1099
|
-
let left = parseAndExpression(stream, availableTags);
|
|
1100
|
-
while (stream.peek().type === "OR") {
|
|
1101
|
-
stream.next();
|
|
1102
|
-
const right = parseAndExpression(stream, availableTags);
|
|
1103
|
-
left = {
|
|
1104
|
-
type: "or",
|
|
1105
|
-
left,
|
|
1106
|
-
right
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
return left;
|
|
1110
|
-
}
|
|
1111
|
-
function parseAndExpression(stream, availableTags) {
|
|
1112
|
-
let left = parseUnaryExpression(stream, availableTags);
|
|
1113
|
-
while (stream.peek().type === "AND") {
|
|
1114
|
-
stream.next();
|
|
1115
|
-
const right = parseUnaryExpression(stream, availableTags);
|
|
1116
|
-
left = {
|
|
1117
|
-
type: "and",
|
|
1118
|
-
left,
|
|
1119
|
-
right
|
|
1120
|
-
};
|
|
1121
|
-
}
|
|
1122
|
-
return left;
|
|
1123
|
-
}
|
|
1124
|
-
function parseUnaryExpression(stream, availableTags) {
|
|
1125
|
-
if (stream.peek().type === "NOT") {
|
|
1126
|
-
stream.next();
|
|
1127
|
-
return {
|
|
1128
|
-
type: "not",
|
|
1129
|
-
operand: parseUnaryExpression(stream, availableTags)
|
|
1130
|
-
};
|
|
1131
|
-
}
|
|
1132
|
-
return parsePrimaryExpression(stream, availableTags);
|
|
1133
|
-
}
|
|
1134
|
-
function parsePrimaryExpression(stream, availableTags) {
|
|
1135
|
-
const token = stream.peek();
|
|
1136
|
-
if (token.type === "LPAREN") {
|
|
1137
|
-
stream.next();
|
|
1138
|
-
const expr = parseOrExpression(stream, availableTags);
|
|
1139
|
-
stream.expect("RPAREN");
|
|
1140
|
-
return expr;
|
|
1141
|
-
}
|
|
1142
|
-
if (token.type === "TAG") {
|
|
1143
|
-
stream.next();
|
|
1144
|
-
const tagValue = token.value;
|
|
1145
|
-
return {
|
|
1146
|
-
type: "tag",
|
|
1147
|
-
value: tagValue,
|
|
1148
|
-
pattern: resolveTagPattern(tagValue, availableTags)
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
stream.unexpectedToken();
|
|
1152
|
-
}
|
|
1153
|
-
function createWildcardRegex(pattern) {
|
|
1154
|
-
return new RegExp(`^${pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`);
|
|
1155
|
-
}
|
|
1156
|
-
function resolveTagPattern(tagPattern, availableTags) {
|
|
1157
|
-
if (tagPattern.includes("*")) {
|
|
1158
|
-
const regex = createWildcardRegex(tagPattern);
|
|
1159
|
-
if (!availableTags.some((tag) => regex.test(tag.name))) throw createNoTagsError(availableTags, tagPattern, "tag pattern");
|
|
1160
|
-
return regex;
|
|
1161
|
-
}
|
|
1162
|
-
if (!availableTags.length || !availableTags.some((tag) => tag.name === tagPattern)) throw createNoTagsError(availableTags, tagPattern, "tag pattern");
|
|
1163
|
-
return null;
|
|
1164
|
-
}
|
|
1165
|
-
function evaluateNode(node, tags) {
|
|
1166
|
-
switch (node.type) {
|
|
1167
|
-
case "tag":
|
|
1168
|
-
if (node.pattern) return tags.some((tag) => node.pattern.test(tag));
|
|
1169
|
-
return tags.includes(node.value);
|
|
1170
|
-
case "not": return !evaluateNode(node.operand, tags);
|
|
1171
|
-
case "and": return evaluateNode(node.left, tags) && evaluateNode(node.right, tags);
|
|
1172
|
-
case "or": return evaluateNode(node.left, tags) || evaluateNode(node.right, tags);
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
function isTestCase(s) {
|
|
1176
|
-
return s.type === "test";
|
|
1177
|
-
}
|
|
1178
|
-
function getTests(suite) {
|
|
1179
|
-
const tests = [];
|
|
1180
|
-
const arraySuites = toArray(suite);
|
|
1181
|
-
for (const s of arraySuites) if (isTestCase(s)) tests.push(s);
|
|
1182
|
-
else for (const task of s.tasks) if (isTestCase(task)) tests.push(task);
|
|
1183
|
-
else {
|
|
1184
|
-
const taskTests = getTests(task);
|
|
1185
|
-
for (const test of taskTests) tests.push(test);
|
|
1186
|
-
}
|
|
1187
|
-
return tests;
|
|
1188
|
-
}
|
|
1189
|
-
function getTasks(tasks = []) {
|
|
1190
|
-
return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
|
1191
|
-
}
|
|
1192
|
-
function getSuites(suite) {
|
|
1193
|
-
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
|
1194
|
-
}
|
|
1195
|
-
function hasTests(suite) {
|
|
1196
|
-
return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
|
|
1197
|
-
}
|
|
1198
|
-
function hasFailed(suite) {
|
|
1199
|
-
return toArray(suite).some((s) => s.result?.state === "fail" || s.type === "suite" && hasFailed(s.tasks));
|
|
1200
|
-
}
|
|
1201
|
-
function getNames(task) {
|
|
1202
|
-
const names = [task.name];
|
|
1203
|
-
let current = task;
|
|
1204
|
-
while (current?.suite) {
|
|
1205
|
-
current = current.suite;
|
|
1206
|
-
if (current?.name) names.unshift(current.name);
|
|
1207
|
-
}
|
|
1208
|
-
if (current !== task.file) names.unshift(task.file.name);
|
|
1209
|
-
return names;
|
|
1210
|
-
}
|
|
1211
|
-
function getFullName(task, separator = " > ") {
|
|
1212
|
-
return getNames(task).join(separator);
|
|
1213
|
-
}
|
|
1214
|
-
function getTestName(task, separator = " > ") {
|
|
1215
|
-
return getNames(task).slice(1).join(separator);
|
|
1216
|
-
}
|
|
1217
|
-
function createTaskName(names, separator = " > ") {
|
|
1218
|
-
return names.filter((name) => name !== void 0).join(separator);
|
|
1219
|
-
}
|
|
1220
|
-
/**
|
|
1221
|
-
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
|
|
1222
|
-
* Suites can contain both tests and other suites, enabling complex test structures.
|
|
1223
|
-
*
|
|
1224
|
-
* @param {string} name - The name of the suite, used for identification and reporting.
|
|
1225
|
-
* @param {Function} fn - A function that defines the tests and suites within this suite.
|
|
1226
|
-
* @example
|
|
1227
|
-
* ```ts
|
|
1228
|
-
* // Define a suite with two tests
|
|
1229
|
-
* suite('Math operations', () => {
|
|
1230
|
-
* test('should add two numbers', () => {
|
|
1231
|
-
* expect(add(1, 2)).toBe(3);
|
|
1232
|
-
* });
|
|
1233
|
-
*
|
|
1234
|
-
* test('should subtract two numbers', () => {
|
|
1235
|
-
* expect(subtract(5, 2)).toBe(3);
|
|
1236
|
-
* });
|
|
1237
|
-
* });
|
|
1238
|
-
* ```
|
|
1239
|
-
* @example
|
|
1240
|
-
* ```ts
|
|
1241
|
-
* // Define nested suites
|
|
1242
|
-
* suite('String operations', () => {
|
|
1243
|
-
* suite('Trimming', () => {
|
|
1244
|
-
* test('should trim whitespace from start and end', () => {
|
|
1245
|
-
* expect(' hello '.trim()).toBe('hello');
|
|
1246
|
-
* });
|
|
1247
|
-
* });
|
|
1248
|
-
*
|
|
1249
|
-
* suite('Concatenation', () => {
|
|
1250
|
-
* test('should concatenate two strings', () => {
|
|
1251
|
-
* expect('hello' + ' ' + 'world').toBe('hello world');
|
|
1252
|
-
* });
|
|
1253
|
-
* });
|
|
1254
|
-
* });
|
|
1255
|
-
* ```
|
|
1256
|
-
*/
|
|
1257
|
-
const suite = createSuite();
|
|
1258
|
-
/**
|
|
1259
|
-
* Defines a test case with a given name and test function. The test function can optionally be configured with test options.
|
|
1260
|
-
*
|
|
1261
|
-
* @param {string | Function} name - The name of the test or a function that will be used as a test name.
|
|
1262
|
-
* @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
|
|
1263
|
-
* @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
|
|
1264
|
-
* @throws {Error} If called inside another test function.
|
|
1265
|
-
* @example
|
|
1266
|
-
* ```ts
|
|
1267
|
-
* // Define a simple test
|
|
1268
|
-
* test('should add two numbers', () => {
|
|
1269
|
-
* expect(add(1, 2)).toBe(3);
|
|
1270
|
-
* });
|
|
1271
|
-
* ```
|
|
1272
|
-
* @example
|
|
1273
|
-
* ```ts
|
|
1274
|
-
* // Define a test with options
|
|
1275
|
-
* test('should subtract two numbers', { retry: 3 }, () => {
|
|
1276
|
-
* expect(subtract(5, 2)).toBe(3);
|
|
1277
|
-
* });
|
|
1278
|
-
* ```
|
|
1279
|
-
*/
|
|
1280
|
-
const test = createTest(function(name, optionsOrFn, optionsOrTest) {
|
|
1281
|
-
if (getCurrentTest()) throw new Error("Calling the test function inside another test function is not allowed. Please put it inside \"describe\" or \"suite\" so it can be properly collected.");
|
|
1282
|
-
getCurrentSuite().test.fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
|
|
1283
|
-
});
|
|
1284
|
-
/**
|
|
1285
|
-
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
|
|
1286
|
-
* Suites can contain both tests and other suites, enabling complex test structures.
|
|
1287
|
-
*
|
|
1288
|
-
* @param {string} name - The name of the suite, used for identification and reporting.
|
|
1289
|
-
* @param {Function} fn - A function that defines the tests and suites within this suite.
|
|
1290
|
-
* @example
|
|
1291
|
-
* ```ts
|
|
1292
|
-
* // Define a suite with two tests
|
|
1293
|
-
* describe('Math operations', () => {
|
|
1294
|
-
* test('should add two numbers', () => {
|
|
1295
|
-
* expect(add(1, 2)).toBe(3);
|
|
1296
|
-
* });
|
|
1297
|
-
*
|
|
1298
|
-
* test('should subtract two numbers', () => {
|
|
1299
|
-
* expect(subtract(5, 2)).toBe(3);
|
|
1300
|
-
* });
|
|
1301
|
-
* });
|
|
1302
|
-
* ```
|
|
1303
|
-
* @example
|
|
1304
|
-
* ```ts
|
|
1305
|
-
* // Define nested suites
|
|
1306
|
-
* describe('String operations', () => {
|
|
1307
|
-
* describe('Trimming', () => {
|
|
1308
|
-
* test('should trim whitespace from start and end', () => {
|
|
1309
|
-
* expect(' hello '.trim()).toBe('hello');
|
|
1310
|
-
* });
|
|
1311
|
-
* });
|
|
1312
|
-
*
|
|
1313
|
-
* describe('Concatenation', () => {
|
|
1314
|
-
* test('should concatenate two strings', () => {
|
|
1315
|
-
* expect('hello' + ' ' + 'world').toBe('hello world');
|
|
1316
|
-
* });
|
|
1317
|
-
* });
|
|
1318
|
-
* });
|
|
1319
|
-
* ```
|
|
1320
|
-
*/
|
|
1321
|
-
const describe = suite;
|
|
1322
|
-
/**
|
|
1323
|
-
* Defines a test case with a given name and test function. The test function can optionally be configured with test options.
|
|
1324
|
-
*
|
|
1325
|
-
* @param {string | Function} name - The name of the test or a function that will be used as a test name.
|
|
1326
|
-
* @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
|
|
1327
|
-
* @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
|
|
1328
|
-
* @throws {Error} If called inside another test function.
|
|
1329
|
-
* @example
|
|
1330
|
-
* ```ts
|
|
1331
|
-
* // Define a simple test
|
|
1332
|
-
* it('adds two numbers', () => {
|
|
1333
|
-
* expect(add(1, 2)).toBe(3);
|
|
1334
|
-
* });
|
|
1335
|
-
* ```
|
|
1336
|
-
* @example
|
|
1337
|
-
* ```ts
|
|
1338
|
-
* // Define a test with options
|
|
1339
|
-
* it('subtracts two numbers', { retry: 3 }, () => {
|
|
1340
|
-
* expect(subtract(5, 2)).toBe(3);
|
|
1341
|
-
* });
|
|
1342
|
-
* ```
|
|
1343
|
-
*/
|
|
1344
|
-
const it = test;
|
|
1345
|
-
let runner;
|
|
1346
|
-
let defaultSuite;
|
|
1347
|
-
let currentTestFilepath;
|
|
1348
|
-
function assert(condition, message) {
|
|
1349
|
-
if (!condition) throw new Error(`Vitest failed to find ${message}. One of the following is possible:
|
|
1350
|
-
- "vitest" is imported directly without running "vitest" command
|
|
1351
|
-
- "vitest" is imported inside "globalSetup" (to fix this, use "setupFiles" instead, because "globalSetup" runs in a different context)
|
|
1352
|
-
- "vitest" is imported inside Vite / Vitest config file
|
|
1353
|
-
- Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues
|
|
1354
|
-
`);
|
|
1355
|
-
}
|
|
1356
|
-
function getDefaultSuite() {
|
|
1357
|
-
assert(defaultSuite, "the default suite");
|
|
1358
|
-
return defaultSuite;
|
|
1359
|
-
}
|
|
1360
|
-
function getRunner() {
|
|
1361
|
-
assert(runner, "the runner");
|
|
1362
|
-
return runner;
|
|
1363
|
-
}
|
|
1364
|
-
function createDefaultSuite(runner) {
|
|
1365
|
-
const config = runner.config.sequence;
|
|
1366
|
-
const options = {};
|
|
1367
|
-
if (config.concurrent != null) options.concurrent = config.concurrent;
|
|
1368
|
-
const collector = suite("", options, () => {});
|
|
1369
|
-
delete collector.suite;
|
|
1370
|
-
return collector;
|
|
1371
|
-
}
|
|
1372
|
-
function clearCollectorContext(file, currentRunner) {
|
|
1373
|
-
currentTestFilepath = file.filepath;
|
|
1374
|
-
runner = currentRunner;
|
|
1375
|
-
if (!defaultSuite) defaultSuite = createDefaultSuite(currentRunner);
|
|
1376
|
-
defaultSuite.file = file;
|
|
1377
|
-
collectorContext.tasks.length = 0;
|
|
1378
|
-
defaultSuite.clear();
|
|
1379
|
-
collectorContext.currentSuite = defaultSuite;
|
|
1380
|
-
}
|
|
1381
|
-
function getCurrentSuite() {
|
|
1382
|
-
const currentSuite = collectorContext.currentSuite || defaultSuite;
|
|
1383
|
-
assert(currentSuite, "the current suite");
|
|
1384
|
-
return currentSuite;
|
|
1385
|
-
}
|
|
1386
|
-
function createSuiteHooks() {
|
|
1387
|
-
return {
|
|
1388
|
-
beforeAll: [],
|
|
1389
|
-
afterAll: [],
|
|
1390
|
-
beforeEach: [],
|
|
1391
|
-
afterEach: [],
|
|
1392
|
-
aroundEach: [],
|
|
1393
|
-
aroundAll: []
|
|
1394
|
-
};
|
|
1395
|
-
}
|
|
1396
|
-
const POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
|
1397
|
-
function parseArguments(optionsOrFn, timeoutOrTest) {
|
|
1398
|
-
if (timeoutOrTest != null && typeof timeoutOrTest === "object") throw new TypeError(`Signature "test(name, fn, { ... })" was deprecated in Vitest 3 and removed in Vitest 4. Please, provide options as a second argument instead.`);
|
|
1399
|
-
let options = {};
|
|
1400
|
-
let fn;
|
|
1401
|
-
if (typeof timeoutOrTest === "number") options = { timeout: timeoutOrTest };
|
|
1402
|
-
else if (typeof optionsOrFn === "object") options = optionsOrFn;
|
|
1403
|
-
if (typeof optionsOrFn === "function") {
|
|
1404
|
-
if (typeof timeoutOrTest === "function") throw new TypeError("Cannot use two functions as arguments. Please use the second argument for options.");
|
|
1405
|
-
fn = optionsOrFn;
|
|
1406
|
-
} else if (typeof timeoutOrTest === "function") fn = timeoutOrTest;
|
|
1407
|
-
return {
|
|
1408
|
-
options,
|
|
1409
|
-
handler: fn
|
|
1410
|
-
};
|
|
1411
|
-
}
|
|
1412
|
-
function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions) {
|
|
1413
|
-
const tasks = [];
|
|
1414
|
-
let suite;
|
|
1415
|
-
initSuite(true);
|
|
1416
|
-
const task = function(name = "", options = {}) {
|
|
1417
|
-
const currentSuite = collectorContext.currentSuite?.suite;
|
|
1418
|
-
const testTags = unique([...(currentSuite ?? collectorContext.currentSuite?.file)?.tags || [], ...toArray(options.tags)]);
|
|
1419
|
-
const tagsOptions = testTags.map((tag) => {
|
|
1420
|
-
const tagDefinition = runner.config.tags?.find((t) => t.name === tag);
|
|
1421
|
-
if (!tagDefinition && runner.config.strictTags) throw createNoTagsError(runner.config.tags, tag);
|
|
1422
|
-
return tagDefinition;
|
|
1423
|
-
}).filter((r) => r != null).sort((tag1, tag2) => (tag2.priority ?? POSITIVE_INFINITY) - (tag1.priority ?? POSITIVE_INFINITY)).reduce((acc, tag) => {
|
|
1424
|
-
const { name, description, priority, meta, ...options } = tag;
|
|
1425
|
-
Object.assign(acc, options);
|
|
1426
|
-
if (meta) acc.meta = Object.assign(acc.meta ?? Object.create(null), meta);
|
|
1427
|
-
return acc;
|
|
1428
|
-
}, {});
|
|
1429
|
-
const testOwnMeta = options.meta;
|
|
1430
|
-
options = {
|
|
1431
|
-
...tagsOptions,
|
|
1432
|
-
...options
|
|
1433
|
-
};
|
|
1434
|
-
const timeout = options.timeout ?? runner.config.testTimeout;
|
|
1435
|
-
const parentMeta = currentSuite?.meta;
|
|
1436
|
-
const tagMeta = tagsOptions.meta;
|
|
1437
|
-
const testMeta = Object.create(null);
|
|
1438
|
-
if (tagMeta) Object.assign(testMeta, tagMeta);
|
|
1439
|
-
if (parentMeta) Object.assign(testMeta, parentMeta);
|
|
1440
|
-
if (testOwnMeta) Object.assign(testMeta, testOwnMeta);
|
|
1441
|
-
const task = {
|
|
1442
|
-
id: "",
|
|
1443
|
-
name,
|
|
1444
|
-
fullName: createTaskName([currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName, name]),
|
|
1445
|
-
fullTestName: createTaskName([currentSuite?.fullTestName, name]),
|
|
1446
|
-
suite: currentSuite,
|
|
1447
|
-
each: options.each,
|
|
1448
|
-
fails: options.fails,
|
|
1449
|
-
context: void 0,
|
|
1450
|
-
type: "test",
|
|
1451
|
-
file: currentSuite?.file ?? collectorContext.currentSuite?.file,
|
|
1452
|
-
timeout,
|
|
1453
|
-
retry: options.retry ?? runner.config.retry,
|
|
1454
|
-
repeats: options.repeats,
|
|
1455
|
-
mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
|
|
1456
|
-
meta: testMeta,
|
|
1457
|
-
annotations: [],
|
|
1458
|
-
artifacts: [],
|
|
1459
|
-
tags: testTags
|
|
1460
|
-
};
|
|
1461
|
-
const handler = options.handler;
|
|
1462
|
-
if (task.mode === "run" && !handler) task.mode = "todo";
|
|
1463
|
-
if (options.concurrent ?? (!options.sequential && runner.config.sequence.concurrent)) task.concurrent = true;
|
|
1464
|
-
task.shuffle = suiteOptions?.shuffle;
|
|
1465
|
-
const context = createTestContext(task, runner);
|
|
1466
|
-
Object.defineProperty(task, "context", {
|
|
1467
|
-
value: context,
|
|
1468
|
-
enumerable: false
|
|
1469
|
-
});
|
|
1470
|
-
setTestFixture(context, options.fixtures ?? new TestFixtures());
|
|
1471
|
-
const limit = Error.stackTraceLimit;
|
|
1472
|
-
Error.stackTraceLimit = 10;
|
|
1473
|
-
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
1474
|
-
Error.stackTraceLimit = limit;
|
|
1475
|
-
if (handler) setFn(task, withTimeout(withCancel(withAwaitAsyncAssertions(withFixtures(handler, { context }), task), task.context.signal), timeout, false, stackTraceError, (_, error) => abortIfTimeout([context], error)));
|
|
1476
|
-
if (runner.config.includeTaskLocation) {
|
|
1477
|
-
const error = stackTraceError.stack;
|
|
1478
|
-
const stack = findTestFileStackTrace(currentTestFilepath, error);
|
|
1479
|
-
if (stack) task.location = {
|
|
1480
|
-
line: stack.line,
|
|
1481
|
-
column: stack.column
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
tasks.push(task);
|
|
1485
|
-
return task;
|
|
1486
|
-
};
|
|
1487
|
-
const test = createTest(function(name, optionsOrFn, timeoutOrTest) {
|
|
1488
|
-
let { options, handler } = parseArguments(optionsOrFn, timeoutOrTest);
|
|
1489
|
-
if (typeof suiteOptions === "object") options = Object.assign({}, suiteOptions, options);
|
|
1490
|
-
const concurrent = this.concurrent ?? (!this.sequential && options?.concurrent);
|
|
1491
|
-
if (options.concurrent != null && concurrent != null) options.concurrent = concurrent;
|
|
1492
|
-
const sequential = this.sequential ?? (!this.concurrent && options?.sequential);
|
|
1493
|
-
if (options.sequential != null && sequential != null) options.sequential = sequential;
|
|
1494
|
-
const test = task(formatName(name), {
|
|
1495
|
-
...this,
|
|
1496
|
-
...options,
|
|
1497
|
-
handler
|
|
1498
|
-
});
|
|
1499
|
-
test.type = "test";
|
|
1500
|
-
});
|
|
1501
|
-
const collector = {
|
|
1502
|
-
type: "collector",
|
|
1503
|
-
name,
|
|
1504
|
-
mode,
|
|
1505
|
-
suite,
|
|
1506
|
-
options: suiteOptions,
|
|
1507
|
-
test,
|
|
1508
|
-
file: suite.file,
|
|
1509
|
-
tasks,
|
|
1510
|
-
collect,
|
|
1511
|
-
task,
|
|
1512
|
-
clear,
|
|
1513
|
-
on: addHook
|
|
1514
|
-
};
|
|
1515
|
-
function addHook(name, ...fn) {
|
|
1516
|
-
getHooks(suite)[name].push(...fn);
|
|
1517
|
-
}
|
|
1518
|
-
function initSuite(includeLocation) {
|
|
1519
|
-
if (typeof suiteOptions === "number") suiteOptions = { timeout: suiteOptions };
|
|
1520
|
-
const currentSuite = collectorContext.currentSuite?.suite;
|
|
1521
|
-
const parentTask = currentSuite ?? collectorContext.currentSuite?.file;
|
|
1522
|
-
const suiteTags = toArray(suiteOptions?.tags);
|
|
1523
|
-
validateTags(runner.config, suiteTags);
|
|
1524
|
-
suite = {
|
|
1525
|
-
id: "",
|
|
1526
|
-
type: "suite",
|
|
1527
|
-
name,
|
|
1528
|
-
fullName: createTaskName([currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName, name]),
|
|
1529
|
-
fullTestName: createTaskName([currentSuite?.fullTestName, name]),
|
|
1530
|
-
suite: currentSuite,
|
|
1531
|
-
mode,
|
|
1532
|
-
each,
|
|
1533
|
-
file: currentSuite?.file ?? collectorContext.currentSuite?.file,
|
|
1534
|
-
shuffle: suiteOptions?.shuffle,
|
|
1535
|
-
tasks: [],
|
|
1536
|
-
meta: suiteOptions?.meta ?? Object.create(null),
|
|
1537
|
-
concurrent: suiteOptions?.concurrent,
|
|
1538
|
-
tags: unique([...parentTask?.tags || [], ...suiteTags])
|
|
1539
|
-
};
|
|
1540
|
-
if (runner && includeLocation && runner.config.includeTaskLocation) {
|
|
1541
|
-
const limit = Error.stackTraceLimit;
|
|
1542
|
-
Error.stackTraceLimit = 15;
|
|
1543
|
-
const error = (/* @__PURE__ */ new Error("stacktrace")).stack;
|
|
1544
|
-
Error.stackTraceLimit = limit;
|
|
1545
|
-
const stack = findTestFileStackTrace(currentTestFilepath, error);
|
|
1546
|
-
if (stack) suite.location = {
|
|
1547
|
-
line: stack.line,
|
|
1548
|
-
column: stack.column
|
|
1549
|
-
};
|
|
1550
|
-
}
|
|
1551
|
-
setHooks(suite, createSuiteHooks());
|
|
1552
|
-
}
|
|
1553
|
-
function clear() {
|
|
1554
|
-
tasks.length = 0;
|
|
1555
|
-
initSuite(false);
|
|
1556
|
-
}
|
|
1557
|
-
async function collect(file) {
|
|
1558
|
-
if (!file) throw new TypeError("File is required to collect tasks.");
|
|
1559
|
-
if (factory) await runWithSuite(collector, () => factory(test));
|
|
1560
|
-
const allChildren = [];
|
|
1561
|
-
for (const i of tasks) allChildren.push(i.type === "collector" ? await i.collect(file) : i);
|
|
1562
|
-
suite.tasks = allChildren;
|
|
1563
|
-
return suite;
|
|
1564
|
-
}
|
|
1565
|
-
collectTask(collector);
|
|
1566
|
-
return collector;
|
|
1567
|
-
}
|
|
1568
|
-
function withAwaitAsyncAssertions(fn, task) {
|
|
1569
|
-
return (async (...args) => {
|
|
1570
|
-
const fnResult = await fn(...args);
|
|
1571
|
-
if (task.promises) {
|
|
1572
|
-
const errors = (await Promise.allSettled(task.promises)).map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
|
|
1573
|
-
if (errors.length) throw errors;
|
|
1574
|
-
}
|
|
1575
|
-
return fnResult;
|
|
1576
|
-
});
|
|
1577
|
-
}
|
|
1578
|
-
function createSuite() {
|
|
1579
|
-
function suiteFn(name, factoryOrOptions, optionsOrFactory) {
|
|
1580
|
-
if (getCurrentTest()) throw new Error("Calling the suite function inside test function is not allowed. It can be only called at the top level or inside another suite function.");
|
|
1581
|
-
const currentSuite = collectorContext.currentSuite || defaultSuite;
|
|
1582
|
-
let { options, handler: factory } = parseArguments(factoryOrOptions, optionsOrFactory);
|
|
1583
|
-
const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
|
|
1584
|
-
const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
|
|
1585
|
-
const { meta: parentMeta, ...parentOptions } = currentSuite?.options || {};
|
|
1586
|
-
options = {
|
|
1587
|
-
...parentOptions,
|
|
1588
|
-
...options
|
|
1589
|
-
};
|
|
1590
|
-
const shuffle = this.shuffle ?? options.shuffle ?? currentSuite?.options?.shuffle ?? runner?.config.sequence.shuffle;
|
|
1591
|
-
if (shuffle != null) options.shuffle = shuffle;
|
|
1592
|
-
let mode = this.only ?? options.only ? "only" : this.skip ?? options.skip ? "skip" : this.todo ?? options.todo ? "todo" : "run";
|
|
1593
|
-
if (mode === "run" && !factory) mode = "todo";
|
|
1594
|
-
const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
|
|
1595
|
-
const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
|
|
1596
|
-
if (isConcurrent != null) options.concurrent = isConcurrent && !isSequential;
|
|
1597
|
-
if (isSequential != null) options.sequential = isSequential && !isConcurrent;
|
|
1598
|
-
if (parentMeta) options.meta = Object.assign(Object.create(null), parentMeta, options.meta);
|
|
1599
|
-
return createSuiteCollector(formatName(name), factory, mode, this.each, options);
|
|
1600
|
-
}
|
|
1601
|
-
suiteFn.each = function(cases, ...args) {
|
|
1602
|
-
const context = getChainableContext(this);
|
|
1603
|
-
const suite = context.withContext();
|
|
1604
|
-
context.setContext("each", true);
|
|
1605
|
-
if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
|
|
1606
|
-
return (name, optionsOrFn, fnOrOptions) => {
|
|
1607
|
-
const _name = formatName(name);
|
|
1608
|
-
const arrayOnlyCases = cases.every(Array.isArray);
|
|
1609
|
-
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
|
1610
|
-
const fnFirst = typeof optionsOrFn === "function";
|
|
1611
|
-
cases.forEach((i, idx) => {
|
|
1612
|
-
const items = Array.isArray(i) ? i : [i];
|
|
1613
|
-
if (fnFirst) if (arrayOnlyCases) suite(formatTitle(_name, items, idx), handler ? () => handler(...items) : void 0, options.timeout);
|
|
1614
|
-
else suite(formatTitle(_name, items, idx), handler ? () => handler(i) : void 0, options.timeout);
|
|
1615
|
-
else if (arrayOnlyCases) suite(formatTitle(_name, items, idx), options, handler ? () => handler(...items) : void 0);
|
|
1616
|
-
else suite(formatTitle(_name, items, idx), options, handler ? () => handler(i) : void 0);
|
|
1617
|
-
});
|
|
1618
|
-
context.setContext("each", void 0);
|
|
1619
|
-
};
|
|
1620
|
-
};
|
|
1621
|
-
suiteFn.for = function(cases, ...args) {
|
|
1622
|
-
if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
|
|
1623
|
-
return (name, optionsOrFn, fnOrOptions) => {
|
|
1624
|
-
const name_ = formatName(name);
|
|
1625
|
-
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
|
1626
|
-
cases.forEach((item, idx) => {
|
|
1627
|
-
suite(formatTitle(name_, toArray(item), idx), options, handler ? () => handler(item) : void 0);
|
|
1628
|
-
});
|
|
1629
|
-
};
|
|
1630
|
-
};
|
|
1631
|
-
suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
|
|
1632
|
-
suiteFn.runIf = (condition) => condition ? suite : suite.skip;
|
|
1633
|
-
return createChainable([
|
|
1634
|
-
"concurrent",
|
|
1635
|
-
"sequential",
|
|
1636
|
-
"shuffle",
|
|
1637
|
-
"skip",
|
|
1638
|
-
"only",
|
|
1639
|
-
"todo"
|
|
1640
|
-
], suiteFn);
|
|
1641
|
-
}
|
|
1642
|
-
function createTaskCollector(fn) {
|
|
1643
|
-
const taskFn = fn;
|
|
1644
|
-
taskFn.each = function(cases, ...args) {
|
|
1645
|
-
const context = getChainableContext(this);
|
|
1646
|
-
const test = context.withContext();
|
|
1647
|
-
context.setContext("each", true);
|
|
1648
|
-
if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
|
|
1649
|
-
return (name, optionsOrFn, fnOrOptions) => {
|
|
1650
|
-
const _name = formatName(name);
|
|
1651
|
-
const arrayOnlyCases = cases.every(Array.isArray);
|
|
1652
|
-
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
|
1653
|
-
const fnFirst = typeof optionsOrFn === "function";
|
|
1654
|
-
cases.forEach((i, idx) => {
|
|
1655
|
-
const items = Array.isArray(i) ? i : [i];
|
|
1656
|
-
if (fnFirst) if (arrayOnlyCases) test(formatTitle(_name, items, idx), handler ? () => handler(...items) : void 0, options.timeout);
|
|
1657
|
-
else test(formatTitle(_name, items, idx), handler ? () => handler(i) : void 0, options.timeout);
|
|
1658
|
-
else if (arrayOnlyCases) test(formatTitle(_name, items, idx), options, handler ? () => handler(...items) : void 0);
|
|
1659
|
-
else test(formatTitle(_name, items, idx), options, handler ? () => handler(i) : void 0);
|
|
1660
|
-
});
|
|
1661
|
-
context.setContext("each", void 0);
|
|
1662
|
-
};
|
|
1663
|
-
};
|
|
1664
|
-
taskFn.for = function(cases, ...args) {
|
|
1665
|
-
const test = getChainableContext(this).withContext();
|
|
1666
|
-
if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
|
|
1667
|
-
return (name, optionsOrFn, fnOrOptions) => {
|
|
1668
|
-
const _name = formatName(name);
|
|
1669
|
-
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
|
1670
|
-
cases.forEach((item, idx) => {
|
|
1671
|
-
const handlerWrapper = handler ? (ctx) => handler(item, ctx) : void 0;
|
|
1672
|
-
if (handlerWrapper) configureProps(handlerWrapper, {
|
|
1673
|
-
index: 1,
|
|
1674
|
-
original: handler
|
|
1675
|
-
});
|
|
1676
|
-
test(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
|
|
1677
|
-
});
|
|
1678
|
-
};
|
|
1679
|
-
};
|
|
1680
|
-
taskFn.skipIf = function(condition) {
|
|
1681
|
-
return condition ? this.skip : this;
|
|
1682
|
-
};
|
|
1683
|
-
taskFn.runIf = function(condition) {
|
|
1684
|
-
return condition ? this : this.skip;
|
|
1685
|
-
};
|
|
1686
|
-
/**
|
|
1687
|
-
* Parse builder pattern arguments into a fixtures object.
|
|
1688
|
-
* Handles both builder pattern (name, options?, value) and object syntax.
|
|
1689
|
-
*/
|
|
1690
|
-
function parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn) {
|
|
1691
|
-
if (typeof fixturesOrName !== "string") return fixturesOrName;
|
|
1692
|
-
const fixtureName = fixturesOrName;
|
|
1693
|
-
let fixtureOptions;
|
|
1694
|
-
let fixtureValue;
|
|
1695
|
-
if (maybeFn !== void 0) {
|
|
1696
|
-
fixtureOptions = optionsOrFn;
|
|
1697
|
-
fixtureValue = maybeFn;
|
|
1698
|
-
} else if (optionsOrFn !== null && typeof optionsOrFn === "object" && !Array.isArray(optionsOrFn) && TestFixtures.isFixtureOptions(optionsOrFn)) {
|
|
1699
|
-
fixtureOptions = optionsOrFn;
|
|
1700
|
-
fixtureValue = {};
|
|
1701
|
-
} else {
|
|
1702
|
-
fixtureOptions = void 0;
|
|
1703
|
-
fixtureValue = optionsOrFn;
|
|
1704
|
-
}
|
|
1705
|
-
if (typeof fixtureValue === "function") {
|
|
1706
|
-
const builderFn = fixtureValue;
|
|
1707
|
-
const fixture = async (ctx, use) => {
|
|
1708
|
-
let cleanup;
|
|
1709
|
-
const onCleanup = (fn) => {
|
|
1710
|
-
if (cleanup !== void 0) throw new Error("onCleanup can only be called once per fixture. Define separate fixtures if you need multiple cleanup functions.");
|
|
1711
|
-
cleanup = fn;
|
|
1712
|
-
};
|
|
1713
|
-
await use(await builderFn(ctx, { onCleanup }));
|
|
1714
|
-
if (cleanup) await cleanup();
|
|
1715
|
-
};
|
|
1716
|
-
configureProps(fixture, { original: builderFn });
|
|
1717
|
-
if (fixtureOptions) return { [fixtureName]: [fixture, fixtureOptions] };
|
|
1718
|
-
return { [fixtureName]: fixture };
|
|
1719
|
-
}
|
|
1720
|
-
if (fixtureOptions) return { [fixtureName]: [fixtureValue, fixtureOptions] };
|
|
1721
|
-
return { [fixtureName]: fixtureValue };
|
|
1722
|
-
}
|
|
1723
|
-
taskFn.override = function(fixturesOrName, optionsOrFn, maybeFn) {
|
|
1724
|
-
const userFixtures = parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn);
|
|
1725
|
-
getChainableContext(this).getFixtures().override(runner, userFixtures);
|
|
1726
|
-
return this;
|
|
1727
|
-
};
|
|
1728
|
-
taskFn.scoped = function(fixtures) {
|
|
1729
|
-
console.warn(`test.scoped() is deprecated and will be removed in future versions. Please use test.override() instead.`);
|
|
1730
|
-
return this.override(fixtures);
|
|
1731
|
-
};
|
|
1732
|
-
taskFn.extend = function(fixturesOrName, optionsOrFn, maybeFn) {
|
|
1733
|
-
const userFixtures = parseBuilderFixtures(fixturesOrName, optionsOrFn, maybeFn);
|
|
1734
|
-
const fixtures = getChainableContext(this).getFixtures().extend(runner, userFixtures);
|
|
1735
|
-
const _test = createTest(function(name, optionsOrFn, optionsOrTest) {
|
|
1736
|
-
fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
|
|
1737
|
-
});
|
|
1738
|
-
getChainableContext(_test).mergeContext({ fixtures });
|
|
1739
|
-
return _test;
|
|
1740
|
-
};
|
|
1741
|
-
taskFn.describe = suite;
|
|
1742
|
-
taskFn.suite = suite;
|
|
1743
|
-
taskFn.beforeEach = beforeEach;
|
|
1744
|
-
taskFn.afterEach = afterEach;
|
|
1745
|
-
taskFn.beforeAll = beforeAll;
|
|
1746
|
-
taskFn.afterAll = afterAll;
|
|
1747
|
-
taskFn.aroundEach = aroundEach;
|
|
1748
|
-
taskFn.aroundAll = aroundAll;
|
|
1749
|
-
return createChainable([
|
|
1750
|
-
"concurrent",
|
|
1751
|
-
"sequential",
|
|
1752
|
-
"skip",
|
|
1753
|
-
"only",
|
|
1754
|
-
"todo",
|
|
1755
|
-
"fails"
|
|
1756
|
-
], taskFn, { fixtures: new TestFixtures() });
|
|
1757
|
-
}
|
|
1758
|
-
function createTest(fn) {
|
|
1759
|
-
return createTaskCollector(fn);
|
|
1760
|
-
}
|
|
1761
|
-
function formatName(name) {
|
|
1762
|
-
return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
|
|
1763
|
-
}
|
|
1764
|
-
function formatTitle(template, items, idx) {
|
|
1765
|
-
if (template.includes("%#") || template.includes("%$")) template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
|
|
1766
|
-
const count = template.split("%").length - 1;
|
|
1767
|
-
if (template.includes("%f")) (template.match(/%f/g) || []).forEach((_, i) => {
|
|
1768
|
-
if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
|
|
1769
|
-
let occurrence = 0;
|
|
1770
|
-
template = template.replace(/%f/g, (match) => {
|
|
1771
|
-
occurrence++;
|
|
1772
|
-
return occurrence === i + 1 ? "-%f" : match;
|
|
1773
|
-
});
|
|
1774
|
-
}
|
|
1775
|
-
});
|
|
1776
|
-
const isObjectItem = isObject(items[0]);
|
|
1777
|
-
function formatAttribute(s) {
|
|
1778
|
-
return s.replace(/\$([$\w.]+)/g, (_, key) => {
|
|
1779
|
-
const isArrayKey = /^\d+$/.test(key);
|
|
1780
|
-
if (!isObjectItem && !isArrayKey) return `$${key}`;
|
|
1781
|
-
const arrayElement = isArrayKey ? objectAttr(items, key) : void 0;
|
|
1782
|
-
return objDisplay(isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement, { truncate: runner?.config?.chaiConfig?.truncateThreshold });
|
|
1783
|
-
});
|
|
1784
|
-
}
|
|
1785
|
-
let output = "";
|
|
1786
|
-
let i = 0;
|
|
1787
|
-
handleRegexMatch(template, formatRegExp, (match) => {
|
|
1788
|
-
if (i < count) output += format(match[0], items[i++]);
|
|
1789
|
-
else output += match[0];
|
|
1790
|
-
}, (nonMatch) => {
|
|
1791
|
-
output += formatAttribute(nonMatch);
|
|
1792
|
-
});
|
|
1793
|
-
return output;
|
|
1794
|
-
}
|
|
1795
|
-
function handleRegexMatch(input, regex, onMatch, onNonMatch) {
|
|
1796
|
-
let lastIndex = 0;
|
|
1797
|
-
for (const m of input.matchAll(regex)) {
|
|
1798
|
-
if (lastIndex < m.index) onNonMatch(input.slice(lastIndex, m.index));
|
|
1799
|
-
onMatch(m);
|
|
1800
|
-
lastIndex = m.index + m[0].length;
|
|
1801
|
-
}
|
|
1802
|
-
if (lastIndex < input.length) onNonMatch(input.slice(lastIndex));
|
|
1803
|
-
}
|
|
1804
|
-
function formatTemplateString(cases, args) {
|
|
1805
|
-
const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
|
|
1806
|
-
const res = [];
|
|
1807
|
-
for (let i = 0; i < Math.floor(args.length / header.length); i++) {
|
|
1808
|
-
const oneCase = {};
|
|
1809
|
-
for (let j = 0; j < header.length; j++) oneCase[header[j]] = args[i * header.length + j];
|
|
1810
|
-
res.push(oneCase);
|
|
1811
|
-
}
|
|
1812
|
-
return res;
|
|
1813
|
-
}
|
|
1814
|
-
const now$2 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
1815
|
-
const collectorContext = {
|
|
1816
|
-
tasks: [],
|
|
1817
|
-
currentSuite: null
|
|
1818
|
-
};
|
|
1819
|
-
function collectTask(task) {
|
|
1820
|
-
collectorContext.currentSuite?.tasks.push(task);
|
|
1821
|
-
}
|
|
1822
|
-
async function runWithSuite(suite, fn) {
|
|
1823
|
-
const prev = collectorContext.currentSuite;
|
|
1824
|
-
collectorContext.currentSuite = suite;
|
|
1825
|
-
await fn();
|
|
1826
|
-
collectorContext.currentSuite = prev;
|
|
1827
|
-
}
|
|
1828
|
-
function withTimeout(fn, timeout, isHook = false, stackTraceError, onTimeout) {
|
|
1829
|
-
if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) return fn;
|
|
1830
|
-
const { setTimeout, clearTimeout } = getSafeTimers();
|
|
1831
|
-
return (function runWithTimeout(...args) {
|
|
1832
|
-
const startTime = now$2();
|
|
1833
|
-
const runner = getRunner();
|
|
1834
|
-
runner._currentTaskStartTime = startTime;
|
|
1835
|
-
runner._currentTaskTimeout = timeout;
|
|
1836
|
-
return new Promise((resolve_, reject_) => {
|
|
1837
|
-
const timer = setTimeout(() => {
|
|
1838
|
-
clearTimeout(timer);
|
|
1839
|
-
rejectTimeoutError();
|
|
1840
|
-
}, timeout);
|
|
1841
|
-
timer.unref?.();
|
|
1842
|
-
function rejectTimeoutError() {
|
|
1843
|
-
const error = makeTimeoutError(isHook, timeout, stackTraceError);
|
|
1844
|
-
onTimeout?.(args, error);
|
|
1845
|
-
reject_(error);
|
|
1846
|
-
}
|
|
1847
|
-
function resolve(result) {
|
|
1848
|
-
runner._currentTaskStartTime = void 0;
|
|
1849
|
-
runner._currentTaskTimeout = void 0;
|
|
1850
|
-
clearTimeout(timer);
|
|
1851
|
-
if (now$2() - startTime >= timeout) {
|
|
1852
|
-
rejectTimeoutError();
|
|
1853
|
-
return;
|
|
1854
|
-
}
|
|
1855
|
-
resolve_(result);
|
|
1856
|
-
}
|
|
1857
|
-
function reject(error) {
|
|
1858
|
-
runner._currentTaskStartTime = void 0;
|
|
1859
|
-
runner._currentTaskTimeout = void 0;
|
|
1860
|
-
clearTimeout(timer);
|
|
1861
|
-
reject_(error);
|
|
1862
|
-
}
|
|
1863
|
-
try {
|
|
1864
|
-
const result = fn(...args);
|
|
1865
|
-
if (typeof result === "object" && result != null && typeof result.then === "function") result.then(resolve, reject);
|
|
1866
|
-
else resolve(result);
|
|
1867
|
-
} catch (error) {
|
|
1868
|
-
reject(error);
|
|
1869
|
-
}
|
|
1870
|
-
});
|
|
1871
|
-
});
|
|
1872
|
-
}
|
|
1873
|
-
function withCancel(fn, signal) {
|
|
1874
|
-
return (function runWithCancel(...args) {
|
|
1875
|
-
return new Promise((resolve, reject) => {
|
|
1876
|
-
signal.addEventListener("abort", () => reject(signal.reason));
|
|
1877
|
-
try {
|
|
1878
|
-
const result = fn(...args);
|
|
1879
|
-
if (typeof result === "object" && result != null && typeof result.then === "function") result.then(resolve, reject);
|
|
1880
|
-
else resolve(result);
|
|
1881
|
-
} catch (error) {
|
|
1882
|
-
reject(error);
|
|
1883
|
-
}
|
|
1884
|
-
});
|
|
1885
|
-
});
|
|
1886
|
-
}
|
|
1887
|
-
const abortControllers = /* @__PURE__ */ new WeakMap();
|
|
1888
|
-
function abortIfTimeout([context], error) {
|
|
1889
|
-
if (context) abortContextSignal(context, error);
|
|
1890
|
-
}
|
|
1891
|
-
function abortContextSignal(context, error) {
|
|
1892
|
-
abortControllers.get(context)?.abort(error);
|
|
1893
|
-
}
|
|
1894
|
-
function createTestContext(test, runner) {
|
|
1895
|
-
const context = function() {
|
|
1896
|
-
throw new Error("done() callback is deprecated, use promise instead");
|
|
1897
|
-
};
|
|
1898
|
-
let abortController = abortControllers.get(context);
|
|
1899
|
-
if (!abortController) {
|
|
1900
|
-
abortController = new AbortController();
|
|
1901
|
-
abortControllers.set(context, abortController);
|
|
1902
|
-
}
|
|
1903
|
-
context.signal = abortController.signal;
|
|
1904
|
-
context.task = test;
|
|
1905
|
-
context.skip = (condition, note) => {
|
|
1906
|
-
if (condition === false) return;
|
|
1907
|
-
test.result ??= { state: "skip" };
|
|
1908
|
-
test.result.pending = true;
|
|
1909
|
-
throw new PendingError("test is skipped; abort execution", test, typeof condition === "string" ? condition : note);
|
|
1910
|
-
};
|
|
1911
|
-
context.annotate = ((message, type, attachment) => {
|
|
1912
|
-
if (test.result && test.result.state !== "run") throw new Error(`Cannot annotate tests outside of the test run. The test "${test.name}" finished running with the "${test.result.state}" state already.`);
|
|
1913
|
-
const annotation = {
|
|
1914
|
-
message,
|
|
1915
|
-
type: typeof type === "object" || type === void 0 ? "notice" : type
|
|
1916
|
-
};
|
|
1917
|
-
const annotationAttachment = typeof type === "object" ? type : attachment;
|
|
1918
|
-
if (annotationAttachment) {
|
|
1919
|
-
annotation.attachment = annotationAttachment;
|
|
1920
|
-
manageArtifactAttachment(annotation.attachment);
|
|
1921
|
-
}
|
|
1922
|
-
return recordAsyncOperation(test, recordArtifact(test, {
|
|
1923
|
-
type: "internal:annotation",
|
|
1924
|
-
annotation
|
|
1925
|
-
}).then(async ({ annotation }) => {
|
|
1926
|
-
if (!runner.onTestAnnotate) throw new Error(`Test runner doesn't support test annotations.`);
|
|
1927
|
-
await finishSendTasksUpdate(runner);
|
|
1928
|
-
const resolvedAnnotation = await runner.onTestAnnotate(test, annotation);
|
|
1929
|
-
test.annotations.push(resolvedAnnotation);
|
|
1930
|
-
return resolvedAnnotation;
|
|
1931
|
-
}));
|
|
1932
|
-
});
|
|
1933
|
-
context.onTestFailed = (handler, timeout) => {
|
|
1934
|
-
test.onFailed ||= [];
|
|
1935
|
-
test.onFailed.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
|
|
1936
|
-
};
|
|
1937
|
-
context.onTestFinished = (handler, timeout) => {
|
|
1938
|
-
test.onFinished ||= [];
|
|
1939
|
-
test.onFinished.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
|
|
1940
|
-
};
|
|
1941
|
-
return runner.extendTaskContext?.(context) || context;
|
|
1942
|
-
}
|
|
1943
|
-
function makeTimeoutError(isHook, timeout, stackTraceError) {
|
|
1944
|
-
const message = `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.\nIf this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
|
|
1945
|
-
const error = new Error(message);
|
|
1946
|
-
if (stackTraceError?.stack) error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
|
|
1947
|
-
return error;
|
|
1948
|
-
}
|
|
1949
|
-
async function runSetupFiles(config, files, runner) {
|
|
1950
|
-
if (config.sequence.setupFiles === "parallel") await Promise.all(files.map(async (fsPath) => {
|
|
1951
|
-
await runner.importFile(fsPath, "setup");
|
|
1952
|
-
}));
|
|
1953
|
-
else for (const fsPath of files) await runner.importFile(fsPath, "setup");
|
|
1954
|
-
}
|
|
1955
|
-
const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
1956
|
-
async function collectTests(specs, runner) {
|
|
1957
|
-
const files = [];
|
|
1958
|
-
const config = runner.config;
|
|
1959
|
-
const $ = runner.trace;
|
|
1960
|
-
let defaultTagsFilter;
|
|
1961
|
-
for (const spec of specs) {
|
|
1962
|
-
const filepath = typeof spec === "string" ? spec : spec.filepath;
|
|
1963
|
-
await $("collect_spec", { "code.file.path": filepath }, async () => {
|
|
1964
|
-
runner._currentSpecification = typeof spec === "string" ? { filepath: spec } : spec;
|
|
1965
|
-
const testLocations = typeof spec === "string" ? void 0 : spec.testLocations;
|
|
1966
|
-
const testNamePattern = typeof spec === "string" ? void 0 : spec.testNamePattern;
|
|
1967
|
-
const testIds = typeof spec === "string" ? void 0 : spec.testIds;
|
|
1968
|
-
const testTagsFilter = typeof spec === "object" && spec.testTagsFilter ? createTagsFilter(spec.testTagsFilter, config.tags) : void 0;
|
|
1969
|
-
const fileTags = typeof spec === "string" ? [] : spec.fileTags || [];
|
|
1970
|
-
const file = createFileTask(filepath, config.root, config.name, runner.pool, runner.viteEnvironment);
|
|
1971
|
-
file.tags = fileTags;
|
|
1972
|
-
file.shuffle = config.sequence.shuffle;
|
|
1973
|
-
try {
|
|
1974
|
-
validateTags(runner.config, fileTags);
|
|
1975
|
-
runner.onCollectStart?.(file);
|
|
1976
|
-
clearCollectorContext(file, runner);
|
|
1977
|
-
const setupFiles = toArray(config.setupFiles);
|
|
1978
|
-
if (setupFiles.length) {
|
|
1979
|
-
const setupStart = now$1();
|
|
1980
|
-
await runSetupFiles(config, setupFiles, runner);
|
|
1981
|
-
file.setupDuration = now$1() - setupStart;
|
|
1982
|
-
} else file.setupDuration = 0;
|
|
1983
|
-
const collectStart = now$1();
|
|
1984
|
-
await runner.importFile(filepath, "collect");
|
|
1985
|
-
const durations = runner.getImportDurations?.();
|
|
1986
|
-
if (durations) file.importDurations = durations;
|
|
1987
|
-
const defaultTasks = await getDefaultSuite().collect(file);
|
|
1988
|
-
const fileHooks = createSuiteHooks();
|
|
1989
|
-
mergeHooks(fileHooks, getHooks(defaultTasks));
|
|
1990
|
-
for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) if (c.type === "test" || c.type === "suite") file.tasks.push(c);
|
|
1991
|
-
else if (c.type === "collector") {
|
|
1992
|
-
const suite = await c.collect(file);
|
|
1993
|
-
if (suite.name || suite.tasks.length) {
|
|
1994
|
-
mergeHooks(fileHooks, getHooks(suite));
|
|
1995
|
-
file.tasks.push(suite);
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
setHooks(file, fileHooks);
|
|
1999
|
-
file.collectDuration = now$1() - collectStart;
|
|
2000
|
-
} catch (e) {
|
|
2001
|
-
file.result = {
|
|
2002
|
-
state: "fail",
|
|
2003
|
-
errors: e instanceof AggregateError ? e.errors.map((e) => processError(e, runner.config.diffOptions)) : [processError(e, runner.config.diffOptions)]
|
|
2004
|
-
};
|
|
2005
|
-
const durations = runner.getImportDurations?.();
|
|
2006
|
-
if (durations) file.importDurations = durations;
|
|
2007
|
-
}
|
|
2008
|
-
calculateSuiteHash(file);
|
|
2009
|
-
const hasOnlyTasks = someTasksAreOnly(file);
|
|
2010
|
-
if (!testTagsFilter && !defaultTagsFilter && config.tagsFilter) defaultTagsFilter = createTagsFilter(config.tagsFilter, config.tags);
|
|
2011
|
-
interpretTaskModes(file, testNamePattern ?? config.testNamePattern, testLocations, testIds, testTagsFilter ?? defaultTagsFilter, hasOnlyTasks, false, config.allowOnly);
|
|
2012
|
-
if (file.mode === "queued") file.mode = "run";
|
|
2013
|
-
files.push(file);
|
|
2014
|
-
});
|
|
2015
|
-
}
|
|
2016
|
-
return files;
|
|
2017
|
-
}
|
|
2018
|
-
function mergeHooks(baseHooks, hooks) {
|
|
2019
|
-
for (const _key in hooks) {
|
|
2020
|
-
const key = _key;
|
|
2021
|
-
baseHooks[key].push(...hooks[key]);
|
|
2022
|
-
}
|
|
2023
|
-
return baseHooks;
|
|
2024
|
-
}
|
|
2025
|
-
const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
2026
|
-
const unixNow = Date.now;
|
|
2027
|
-
const { clearTimeout, setTimeout } = getSafeTimers();
|
|
2028
|
-
let limitMaxConcurrency;
|
|
2029
|
-
/**
|
|
2030
|
-
* Normalizes retry configuration to extract individual values.
|
|
2031
|
-
* Handles both number and object forms.
|
|
2032
|
-
*/
|
|
2033
|
-
function getRetryCount(retry) {
|
|
2034
|
-
if (retry === void 0) return 0;
|
|
2035
|
-
if (typeof retry === "number") return retry;
|
|
2036
|
-
return retry.count ?? 0;
|
|
2037
|
-
}
|
|
2038
|
-
function getRetryDelay(retry) {
|
|
2039
|
-
if (retry === void 0) return 0;
|
|
2040
|
-
if (typeof retry === "number") return 0;
|
|
2041
|
-
return retry.delay ?? 0;
|
|
2042
|
-
}
|
|
2043
|
-
function getRetryCondition(retry) {
|
|
2044
|
-
if (retry === void 0) return;
|
|
2045
|
-
if (typeof retry === "number") return;
|
|
2046
|
-
return retry.condition;
|
|
2047
|
-
}
|
|
2048
|
-
function updateSuiteHookState(task, name, state, runner) {
|
|
2049
|
-
if (!task.result) task.result = { state: "run" };
|
|
2050
|
-
if (!task.result.hooks) task.result.hooks = {};
|
|
2051
|
-
const suiteHooks = task.result.hooks;
|
|
2052
|
-
if (suiteHooks) {
|
|
2053
|
-
suiteHooks[name] = state;
|
|
2054
|
-
let event = state === "run" ? "before-hook-start" : "before-hook-end";
|
|
2055
|
-
if (name === "afterAll" || name === "afterEach") event = state === "run" ? "after-hook-start" : "after-hook-end";
|
|
2056
|
-
updateTask(event, task, runner);
|
|
2057
|
-
}
|
|
2058
|
-
}
|
|
2059
|
-
function getSuiteHooks(suite, name, sequence) {
|
|
2060
|
-
const hooks = getHooks(suite)[name];
|
|
2061
|
-
if (sequence === "stack" && (name === "afterAll" || name === "afterEach")) return hooks.slice().reverse();
|
|
2062
|
-
return hooks;
|
|
2063
|
-
}
|
|
2064
|
-
async function callTestHooks(runner, test, hooks, sequence) {
|
|
2065
|
-
if (sequence === "stack") hooks = hooks.slice().reverse();
|
|
2066
|
-
if (!hooks.length) return;
|
|
2067
|
-
const context = test.context;
|
|
2068
|
-
const onTestFailed = test.context.onTestFailed;
|
|
2069
|
-
const onTestFinished = test.context.onTestFinished;
|
|
2070
|
-
context.onTestFailed = () => {
|
|
2071
|
-
throw new Error(`Cannot call "onTestFailed" inside a test hook.`);
|
|
2072
|
-
};
|
|
2073
|
-
context.onTestFinished = () => {
|
|
2074
|
-
throw new Error(`Cannot call "onTestFinished" inside a test hook.`);
|
|
2075
|
-
};
|
|
2076
|
-
if (sequence === "parallel") try {
|
|
2077
|
-
await Promise.all(hooks.map((fn) => limitMaxConcurrency(() => fn(test.context))));
|
|
2078
|
-
} catch (e) {
|
|
2079
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2080
|
-
}
|
|
2081
|
-
else for (const fn of hooks) try {
|
|
2082
|
-
await limitMaxConcurrency(() => fn(test.context));
|
|
2083
|
-
} catch (e) {
|
|
2084
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2085
|
-
}
|
|
2086
|
-
context.onTestFailed = onTestFailed;
|
|
2087
|
-
context.onTestFinished = onTestFinished;
|
|
2088
|
-
}
|
|
2089
|
-
async function callSuiteHook(suite, currentTask, name, runner, args) {
|
|
2090
|
-
const sequence = runner.config.sequence.hooks;
|
|
2091
|
-
const callbacks = [];
|
|
2092
|
-
const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
|
|
2093
|
-
if (name === "beforeEach" && parentSuite) callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
|
|
2094
|
-
const hooks = getSuiteHooks(suite, name, sequence);
|
|
2095
|
-
if (hooks.length > 0) updateSuiteHookState(currentTask, name, "run", runner);
|
|
2096
|
-
async function runHook(hook) {
|
|
2097
|
-
return limitMaxConcurrency(async () => {
|
|
2098
|
-
return getBeforeHookCleanupCallback(hook, await hook(...args), name === "beforeEach" ? args[0] : void 0);
|
|
2099
|
-
});
|
|
2100
|
-
}
|
|
2101
|
-
if (sequence === "parallel") callbacks.push(...await Promise.all(hooks.map((hook) => runHook(hook))));
|
|
2102
|
-
else for (const hook of hooks) callbacks.push(await runHook(hook));
|
|
2103
|
-
if (hooks.length > 0) updateSuiteHookState(currentTask, name, "pass", runner);
|
|
2104
|
-
if (name === "afterEach" && parentSuite) callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
|
|
2105
|
-
return callbacks;
|
|
2106
|
-
}
|
|
2107
|
-
function getAroundEachHooks(suite) {
|
|
2108
|
-
const hooks = [];
|
|
2109
|
-
const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
|
|
2110
|
-
if (parentSuite) hooks.push(...getAroundEachHooks(parentSuite));
|
|
2111
|
-
hooks.push(...getHooks(suite).aroundEach);
|
|
2112
|
-
return hooks;
|
|
2113
|
-
}
|
|
2114
|
-
function getAroundAllHooks(suite) {
|
|
2115
|
-
return getHooks(suite).aroundAll;
|
|
2116
|
-
}
|
|
2117
|
-
function makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError) {
|
|
2118
|
-
const message = `The ${phase} phase of "${hookName}" hook timed out after ${timeout}ms.`;
|
|
2119
|
-
const error = new (phase === "setup" ? AroundHookSetupError : AroundHookTeardownError)(message);
|
|
2120
|
-
if (stackTraceError?.stack) error.stack = stackTraceError.stack.replace(stackTraceError.message, error.message);
|
|
2121
|
-
return error;
|
|
2122
|
-
}
|
|
2123
|
-
async function callAroundHooks(runInner, options) {
|
|
2124
|
-
const { hooks, hookName, callbackName, onTimeout, invokeHook } = options;
|
|
2125
|
-
if (!hooks.length) {
|
|
2126
|
-
await runInner();
|
|
2127
|
-
return;
|
|
2128
|
-
}
|
|
2129
|
-
const hookErrors = [];
|
|
2130
|
-
const createTimeoutPromise = (timeout, phase, stackTraceError) => {
|
|
2131
|
-
let timer;
|
|
2132
|
-
let timedout = false;
|
|
2133
|
-
const promise = new Promise((_, reject) => {
|
|
2134
|
-
if (timeout > 0 && timeout !== Number.POSITIVE_INFINITY) {
|
|
2135
|
-
timer = setTimeout(() => {
|
|
2136
|
-
timedout = true;
|
|
2137
|
-
const error = makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError);
|
|
2138
|
-
onTimeout?.(error);
|
|
2139
|
-
reject(error);
|
|
2140
|
-
}, timeout);
|
|
2141
|
-
timer.unref?.();
|
|
2142
|
-
}
|
|
2143
|
-
});
|
|
2144
|
-
const clear = () => {
|
|
2145
|
-
if (timer) {
|
|
2146
|
-
clearTimeout(timer);
|
|
2147
|
-
timer = void 0;
|
|
2148
|
-
}
|
|
2149
|
-
};
|
|
2150
|
-
return {
|
|
2151
|
-
promise,
|
|
2152
|
-
clear,
|
|
2153
|
-
isTimedOut: () => timedout
|
|
2154
|
-
};
|
|
2155
|
-
};
|
|
2156
|
-
const runNextHook = async (index) => {
|
|
2157
|
-
if (index >= hooks.length) return runInner();
|
|
2158
|
-
const hook = hooks[index];
|
|
2159
|
-
const timeout = getAroundHookTimeout(hook);
|
|
2160
|
-
const stackTraceError = getAroundHookStackTrace(hook);
|
|
2161
|
-
let useCalled = false;
|
|
2162
|
-
let setupTimeout;
|
|
2163
|
-
let teardownTimeout;
|
|
2164
|
-
let setupLimitConcurrencyRelease;
|
|
2165
|
-
let teardownLimitConcurrencyRelease;
|
|
2166
|
-
let resolveUseCalled;
|
|
2167
|
-
const useCalledPromise = new Promise((resolve) => {
|
|
2168
|
-
resolveUseCalled = resolve;
|
|
2169
|
-
});
|
|
2170
|
-
let resolveUseReturned;
|
|
2171
|
-
const useReturnedPromise = new Promise((resolve) => {
|
|
2172
|
-
resolveUseReturned = resolve;
|
|
2173
|
-
});
|
|
2174
|
-
let resolveHookComplete;
|
|
2175
|
-
let rejectHookComplete;
|
|
2176
|
-
const hookCompletePromise = new Promise((resolve, reject) => {
|
|
2177
|
-
resolveHookComplete = resolve;
|
|
2178
|
-
rejectHookComplete = reject;
|
|
2179
|
-
});
|
|
2180
|
-
const use = async () => {
|
|
2181
|
-
if (setupTimeout.isTimedOut()) throw new Error("__VITEST_INTERNAL_AROUND_HOOK_ABORT__");
|
|
2182
|
-
if (useCalled) throw new AroundHookMultipleCallsError(`The \`${callbackName}\` callback was called multiple times in the \`${hookName}\` hook. The callback can only be called once per hook.`);
|
|
2183
|
-
useCalled = true;
|
|
2184
|
-
resolveUseCalled();
|
|
2185
|
-
setupTimeout.clear();
|
|
2186
|
-
setupLimitConcurrencyRelease?.();
|
|
2187
|
-
await runNextHook(index + 1).catch((e) => hookErrors.push(e));
|
|
2188
|
-
teardownLimitConcurrencyRelease = await limitMaxConcurrency.acquire();
|
|
2189
|
-
teardownTimeout = createTimeoutPromise(timeout, "teardown", stackTraceError);
|
|
2190
|
-
resolveUseReturned();
|
|
2191
|
-
};
|
|
2192
|
-
setupLimitConcurrencyRelease = await limitMaxConcurrency.acquire();
|
|
2193
|
-
setupTimeout = createTimeoutPromise(timeout, "setup", stackTraceError);
|
|
2194
|
-
(async () => {
|
|
2195
|
-
try {
|
|
2196
|
-
await invokeHook(hook, use);
|
|
2197
|
-
if (!useCalled) throw new AroundHookSetupError(`The \`${callbackName}\` callback was not called in the \`${hookName}\` hook. Make sure to call \`${callbackName}\` to run the ${hookName === "aroundEach" ? "test" : "suite"}.`);
|
|
2198
|
-
resolveHookComplete();
|
|
2199
|
-
} catch (error) {
|
|
2200
|
-
rejectHookComplete(error);
|
|
2201
|
-
} finally {
|
|
2202
|
-
setupLimitConcurrencyRelease?.();
|
|
2203
|
-
teardownLimitConcurrencyRelease?.();
|
|
2204
|
-
}
|
|
2205
|
-
})();
|
|
2206
|
-
try {
|
|
2207
|
-
await Promise.race([
|
|
2208
|
-
useCalledPromise,
|
|
2209
|
-
hookCompletePromise,
|
|
2210
|
-
setupTimeout.promise
|
|
2211
|
-
]);
|
|
2212
|
-
} finally {
|
|
2213
|
-
setupLimitConcurrencyRelease?.();
|
|
2214
|
-
setupTimeout.clear();
|
|
2215
|
-
}
|
|
2216
|
-
await Promise.race([useReturnedPromise, hookCompletePromise]);
|
|
2217
|
-
try {
|
|
2218
|
-
await Promise.race([hookCompletePromise, teardownTimeout?.promise]);
|
|
2219
|
-
} finally {
|
|
2220
|
-
teardownLimitConcurrencyRelease?.();
|
|
2221
|
-
teardownTimeout?.clear();
|
|
2222
|
-
}
|
|
2223
|
-
};
|
|
2224
|
-
await runNextHook(0).catch((e) => hookErrors.push(e));
|
|
2225
|
-
if (hookErrors.length > 0) throw hookErrors;
|
|
2226
|
-
}
|
|
2227
|
-
async function callAroundAllHooks(suite, runSuiteInner) {
|
|
2228
|
-
await callAroundHooks(runSuiteInner, {
|
|
2229
|
-
hooks: getAroundAllHooks(suite),
|
|
2230
|
-
hookName: "aroundAll",
|
|
2231
|
-
callbackName: "runSuite()",
|
|
2232
|
-
invokeHook: (hook, use) => hook(use, suite)
|
|
2233
|
-
});
|
|
2234
|
-
}
|
|
2235
|
-
async function callAroundEachHooks(suite, test, runTest) {
|
|
2236
|
-
await callAroundHooks(() => runTest(getFixtureCleanupCount(test.context)), {
|
|
2237
|
-
hooks: getAroundEachHooks(suite),
|
|
2238
|
-
hookName: "aroundEach",
|
|
2239
|
-
callbackName: "runTest()",
|
|
2240
|
-
onTimeout: (error) => abortContextSignal(test.context, error),
|
|
2241
|
-
invokeHook: (hook, use) => hook(use, test.context, suite)
|
|
2242
|
-
});
|
|
2243
|
-
}
|
|
2244
|
-
const packs = /* @__PURE__ */ new Map();
|
|
2245
|
-
const eventsPacks = [];
|
|
2246
|
-
const pendingTasksUpdates = [];
|
|
2247
|
-
function sendTasksUpdate(runner) {
|
|
2248
|
-
if (packs.size) {
|
|
2249
|
-
const taskPacks = Array.from(packs).map(([id, task]) => {
|
|
2250
|
-
return [
|
|
2251
|
-
id,
|
|
2252
|
-
task[0],
|
|
2253
|
-
task[1]
|
|
2254
|
-
];
|
|
2255
|
-
});
|
|
2256
|
-
const p = runner.onTaskUpdate?.(taskPacks, eventsPacks);
|
|
2257
|
-
if (p) {
|
|
2258
|
-
pendingTasksUpdates.push(p);
|
|
2259
|
-
p.then(() => pendingTasksUpdates.splice(pendingTasksUpdates.indexOf(p), 1), () => {});
|
|
2260
|
-
}
|
|
2261
|
-
eventsPacks.length = 0;
|
|
2262
|
-
packs.clear();
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
|
-
async function finishSendTasksUpdate(runner) {
|
|
2266
|
-
sendTasksUpdate(runner);
|
|
2267
|
-
await Promise.all(pendingTasksUpdates);
|
|
2268
|
-
}
|
|
2269
|
-
function throttle(fn, ms) {
|
|
2270
|
-
let last = 0;
|
|
2271
|
-
let pendingCall;
|
|
2272
|
-
return function call(...args) {
|
|
2273
|
-
const now = unixNow();
|
|
2274
|
-
if (now - last > ms) {
|
|
2275
|
-
last = now;
|
|
2276
|
-
clearTimeout(pendingCall);
|
|
2277
|
-
pendingCall = void 0;
|
|
2278
|
-
return fn.apply(this, args);
|
|
2279
|
-
}
|
|
2280
|
-
pendingCall ??= setTimeout(() => call.bind(this)(...args), ms);
|
|
2281
|
-
};
|
|
2282
|
-
}
|
|
2283
|
-
const sendTasksUpdateThrottled = throttle(sendTasksUpdate, 100);
|
|
2284
|
-
function updateTask(event, task, runner) {
|
|
2285
|
-
eventsPacks.push([
|
|
2286
|
-
task.id,
|
|
2287
|
-
event,
|
|
2288
|
-
void 0
|
|
2289
|
-
]);
|
|
2290
|
-
packs.set(task.id, [task.result, task.meta]);
|
|
2291
|
-
sendTasksUpdateThrottled(runner);
|
|
2292
|
-
}
|
|
2293
|
-
async function callCleanupHooks(runner, cleanups) {
|
|
2294
|
-
const sequence = runner.config.sequence.hooks;
|
|
2295
|
-
if (sequence === "stack") cleanups = cleanups.slice().reverse();
|
|
2296
|
-
if (sequence === "parallel") await Promise.all(cleanups.map(async (fn) => {
|
|
2297
|
-
if (typeof fn !== "function") return;
|
|
2298
|
-
await limitMaxConcurrency(() => fn());
|
|
2299
|
-
}));
|
|
2300
|
-
else for (const fn of cleanups) {
|
|
2301
|
-
if (typeof fn !== "function") continue;
|
|
2302
|
-
await limitMaxConcurrency(() => fn());
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
/**
|
|
2306
|
-
* Determines if a test should be retried based on its retryCondition configuration
|
|
2307
|
-
*/
|
|
2308
|
-
function passesRetryCondition(test, errors) {
|
|
2309
|
-
const condition = getRetryCondition(test.retry);
|
|
2310
|
-
if (!errors || errors.length === 0) return false;
|
|
2311
|
-
if (!condition) return true;
|
|
2312
|
-
const error = errors[errors.length - 1];
|
|
2313
|
-
if (condition instanceof RegExp) return condition.test(error.message || "");
|
|
2314
|
-
else if (typeof condition === "function") return condition(error);
|
|
2315
|
-
return false;
|
|
2316
|
-
}
|
|
2317
|
-
async function runTest(test, runner) {
|
|
2318
|
-
await runner.onBeforeRunTask?.(test);
|
|
2319
|
-
if (test.mode !== "run" && test.mode !== "queued") {
|
|
2320
|
-
updateTask("test-prepare", test, runner);
|
|
2321
|
-
updateTask("test-finished", test, runner);
|
|
2322
|
-
return;
|
|
2323
|
-
}
|
|
2324
|
-
if (test.result?.state === "fail") {
|
|
2325
|
-
updateTask("test-failed-early", test, runner);
|
|
2326
|
-
return;
|
|
2327
|
-
}
|
|
2328
|
-
const start = now();
|
|
2329
|
-
test.result = {
|
|
2330
|
-
state: "run",
|
|
2331
|
-
startTime: unixNow(),
|
|
2332
|
-
retryCount: 0
|
|
2333
|
-
};
|
|
2334
|
-
updateTask("test-prepare", test, runner);
|
|
2335
|
-
const cleanupRunningTest = addRunningTest(test);
|
|
2336
|
-
setCurrentTest(test);
|
|
2337
|
-
const suite = test.suite || test.file;
|
|
2338
|
-
const $ = runner.trace;
|
|
2339
|
-
const repeats = test.repeats ?? 0;
|
|
2340
|
-
for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
|
|
2341
|
-
const retry = getRetryCount(test.retry);
|
|
2342
|
-
for (let retryCount = 0; retryCount <= retry; retryCount++) {
|
|
2343
|
-
let beforeEachCleanups = [];
|
|
2344
|
-
await callAroundEachHooks(suite, test, async (fixtureCheckpoint) => {
|
|
2345
|
-
try {
|
|
2346
|
-
await runner.onBeforeTryTask?.(test, {
|
|
2347
|
-
retry: retryCount,
|
|
2348
|
-
repeats: repeatCount
|
|
2349
|
-
});
|
|
2350
|
-
test.result.repeatCount = repeatCount;
|
|
2351
|
-
beforeEachCleanups = await $("test.beforeEach", () => callSuiteHook(suite, test, "beforeEach", runner, [test.context, suite]));
|
|
2352
|
-
if (runner.runTask) await $("test.callback", () => limitMaxConcurrency(() => runner.runTask(test)));
|
|
2353
|
-
else {
|
|
2354
|
-
const fn = getFn(test);
|
|
2355
|
-
if (!fn) throw new Error("Test function is not found. Did you add it using `setFn`?");
|
|
2356
|
-
await $("test.callback", () => limitMaxConcurrency(() => fn()));
|
|
2357
|
-
}
|
|
2358
|
-
await runner.onAfterTryTask?.(test, {
|
|
2359
|
-
retry: retryCount,
|
|
2360
|
-
repeats: repeatCount
|
|
2361
|
-
});
|
|
2362
|
-
if (test.result.state !== "fail") test.result.state = "pass";
|
|
2363
|
-
} catch (e) {
|
|
2364
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2365
|
-
}
|
|
2366
|
-
try {
|
|
2367
|
-
await runner.onTaskFinished?.(test);
|
|
2368
|
-
} catch (e) {
|
|
2369
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2370
|
-
}
|
|
2371
|
-
try {
|
|
2372
|
-
await $("test.afterEach", () => callSuiteHook(suite, test, "afterEach", runner, [test.context, suite]));
|
|
2373
|
-
if (beforeEachCleanups.length) await $("test.cleanup", () => callCleanupHooks(runner, beforeEachCleanups));
|
|
2374
|
-
await callFixtureCleanupFrom(test.context, fixtureCheckpoint);
|
|
2375
|
-
} catch (e) {
|
|
2376
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2377
|
-
}
|
|
2378
|
-
if (test.onFinished?.length) await $("test.onFinished", () => callTestHooks(runner, test, test.onFinished, "stack"));
|
|
2379
|
-
if (test.result.state === "fail" && test.onFailed?.length) await $("test.onFailed", () => callTestHooks(runner, test, test.onFailed, runner.config.sequence.hooks));
|
|
2380
|
-
test.onFailed = void 0;
|
|
2381
|
-
test.onFinished = void 0;
|
|
2382
|
-
await runner.onAfterRetryTask?.(test, {
|
|
2383
|
-
retry: retryCount,
|
|
2384
|
-
repeats: repeatCount
|
|
2385
|
-
});
|
|
2386
|
-
}).catch((error) => {
|
|
2387
|
-
failTask(test.result, error, runner.config.diffOptions);
|
|
2388
|
-
});
|
|
2389
|
-
try {
|
|
2390
|
-
await callFixtureCleanup(test.context);
|
|
2391
|
-
} catch (e) {
|
|
2392
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
2393
|
-
}
|
|
2394
|
-
if (test.result?.pending || test.result?.state === "skip") {
|
|
2395
|
-
test.mode = "skip";
|
|
2396
|
-
test.result = {
|
|
2397
|
-
state: "skip",
|
|
2398
|
-
note: test.result?.note,
|
|
2399
|
-
pending: true,
|
|
2400
|
-
duration: now() - start
|
|
2401
|
-
};
|
|
2402
|
-
updateTask("test-finished", test, runner);
|
|
2403
|
-
setCurrentTest(void 0);
|
|
2404
|
-
cleanupRunningTest();
|
|
2405
|
-
return;
|
|
2406
|
-
}
|
|
2407
|
-
if (test.result.state === "pass") break;
|
|
2408
|
-
if (retryCount < retry) {
|
|
2409
|
-
if (!passesRetryCondition(test, test.result.errors)) break;
|
|
2410
|
-
test.result.state = "run";
|
|
2411
|
-
test.result.retryCount = (test.result.retryCount ?? 0) + 1;
|
|
2412
|
-
const delay = getRetryDelay(test.retry);
|
|
2413
|
-
if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2414
|
-
}
|
|
2415
|
-
updateTask("test-retried", test, runner);
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
if (test.fails) if (test.result.state === "pass") {
|
|
2419
|
-
const error = processError(/* @__PURE__ */ new Error("Expect test to fail"));
|
|
2420
|
-
test.result.state = "fail";
|
|
2421
|
-
test.result.errors = [error];
|
|
2422
|
-
} else {
|
|
2423
|
-
test.result.state = "pass";
|
|
2424
|
-
test.result.errors = void 0;
|
|
2425
|
-
}
|
|
2426
|
-
cleanupRunningTest();
|
|
2427
|
-
setCurrentTest(void 0);
|
|
2428
|
-
test.result.duration = now() - start;
|
|
2429
|
-
await runner.onAfterRunTask?.(test);
|
|
2430
|
-
updateTask("test-finished", test, runner);
|
|
2431
|
-
}
|
|
2432
|
-
function failTask(result, err, diffOptions) {
|
|
2433
|
-
if (err instanceof PendingError) {
|
|
2434
|
-
result.state = "skip";
|
|
2435
|
-
result.note = err.note;
|
|
2436
|
-
result.pending = true;
|
|
2437
|
-
return;
|
|
2438
|
-
}
|
|
2439
|
-
if (err instanceof TestRunAbortError) {
|
|
2440
|
-
result.state = "skip";
|
|
2441
|
-
result.note = err.message;
|
|
2442
|
-
return;
|
|
2443
|
-
}
|
|
2444
|
-
result.state = "fail";
|
|
2445
|
-
const errors = Array.isArray(err) ? err : [err];
|
|
2446
|
-
for (const e of errors) {
|
|
2447
|
-
const errors = e instanceof AggregateError ? e.errors.map((e) => processError(e, diffOptions)) : [processError(e, diffOptions)];
|
|
2448
|
-
result.errors ??= [];
|
|
2449
|
-
result.errors.push(...errors);
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
function markTasksAsSkipped(suite, runner) {
|
|
2453
|
-
suite.tasks.forEach((t) => {
|
|
2454
|
-
t.mode = "skip";
|
|
2455
|
-
t.result = {
|
|
2456
|
-
...t.result,
|
|
2457
|
-
state: "skip"
|
|
2458
|
-
};
|
|
2459
|
-
updateTask("test-finished", t, runner);
|
|
2460
|
-
if (t.type === "suite") markTasksAsSkipped(t, runner);
|
|
2461
|
-
});
|
|
2462
|
-
}
|
|
2463
|
-
function markPendingTasksAsSkipped(suite, runner, note) {
|
|
2464
|
-
suite.tasks.forEach((t) => {
|
|
2465
|
-
if (!t.result || t.result.state === "run") {
|
|
2466
|
-
t.mode = "skip";
|
|
2467
|
-
t.result = {
|
|
2468
|
-
...t.result,
|
|
2469
|
-
state: "skip",
|
|
2470
|
-
note
|
|
2471
|
-
};
|
|
2472
|
-
updateTask("test-cancel", t, runner);
|
|
2473
|
-
}
|
|
2474
|
-
if (t.type === "suite") markPendingTasksAsSkipped(t, runner, note);
|
|
2475
|
-
});
|
|
2476
|
-
}
|
|
2477
|
-
async function runSuite(suite, runner) {
|
|
2478
|
-
await runner.onBeforeRunSuite?.(suite);
|
|
2479
|
-
if (suite.result?.state === "fail") {
|
|
2480
|
-
markTasksAsSkipped(suite, runner);
|
|
2481
|
-
updateTask("suite-failed-early", suite, runner);
|
|
2482
|
-
return;
|
|
2483
|
-
}
|
|
2484
|
-
const start = now();
|
|
2485
|
-
const mode = suite.mode;
|
|
2486
|
-
suite.result = {
|
|
2487
|
-
state: mode === "skip" || mode === "todo" ? mode : "run",
|
|
2488
|
-
startTime: unixNow()
|
|
2489
|
-
};
|
|
2490
|
-
const $ = runner.trace;
|
|
2491
|
-
updateTask("suite-prepare", suite, runner);
|
|
2492
|
-
let beforeAllCleanups = [];
|
|
2493
|
-
if (suite.mode === "skip") {
|
|
2494
|
-
suite.result.state = "skip";
|
|
2495
|
-
updateTask("suite-finished", suite, runner);
|
|
2496
|
-
} else if (suite.mode === "todo") {
|
|
2497
|
-
suite.result.state = "todo";
|
|
2498
|
-
updateTask("suite-finished", suite, runner);
|
|
2499
|
-
} else {
|
|
2500
|
-
let suiteRan = false;
|
|
2501
|
-
try {
|
|
2502
|
-
await callAroundAllHooks(suite, async () => {
|
|
2503
|
-
suiteRan = true;
|
|
2504
|
-
try {
|
|
2505
|
-
try {
|
|
2506
|
-
beforeAllCleanups = await $("suite.beforeAll", () => callSuiteHook(suite, suite, "beforeAll", runner, [suite]));
|
|
2507
|
-
} catch (e) {
|
|
2508
|
-
failTask(suite.result, e, runner.config.diffOptions);
|
|
2509
|
-
markTasksAsSkipped(suite, runner);
|
|
2510
|
-
return;
|
|
2511
|
-
}
|
|
2512
|
-
if (runner.runSuite) await runner.runSuite(suite);
|
|
2513
|
-
else for (let tasksGroup of partitionSuiteChildren(suite)) if (tasksGroup[0].concurrent === true) {
|
|
2514
|
-
const groupLimiter = limitConcurrency(runner.config.maxConcurrency);
|
|
2515
|
-
await Promise.all(tasksGroup.map((c) => groupLimiter(() => runSuiteChild(c, runner))));
|
|
2516
|
-
} else {
|
|
2517
|
-
const { sequence } = runner.config;
|
|
2518
|
-
if (suite.shuffle) tasksGroup = shuffle([tasksGroup.filter((group) => group.type === "suite"), tasksGroup.filter((group) => group.type === "test")], sequence.seed).flatMap((group) => shuffle(group, sequence.seed));
|
|
2519
|
-
for (const c of tasksGroup) await runSuiteChild(c, runner);
|
|
2520
|
-
}
|
|
2521
|
-
} finally {
|
|
2522
|
-
try {
|
|
2523
|
-
await $("suite.afterAll", () => callSuiteHook(suite, suite, "afterAll", runner, [suite]));
|
|
2524
|
-
if (beforeAllCleanups.length) await $("suite.cleanup", () => callCleanupHooks(runner, beforeAllCleanups));
|
|
2525
|
-
if (suite.file === suite) {
|
|
2526
|
-
const contexts = TestFixtures.getFileContexts(suite.file);
|
|
2527
|
-
await Promise.all(contexts.map((context) => callFixtureCleanup(context)));
|
|
2528
|
-
}
|
|
2529
|
-
} catch (e) {
|
|
2530
|
-
failTask(suite.result, e, runner.config.diffOptions);
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
});
|
|
2534
|
-
} catch (e) {
|
|
2535
|
-
if (!suiteRan) markTasksAsSkipped(suite, runner);
|
|
2536
|
-
failTask(suite.result, e, runner.config.diffOptions);
|
|
2537
|
-
}
|
|
2538
|
-
if (suite.mode === "run" || suite.mode === "queued") if (!runner.config.passWithNoTests && !hasTests(suite)) {
|
|
2539
|
-
suite.result.state = "fail";
|
|
2540
|
-
if (!suite.result.errors?.length) {
|
|
2541
|
-
const error = processError(/* @__PURE__ */ new Error(`No test found in suite ${suite.name}`));
|
|
2542
|
-
suite.result.errors = [error];
|
|
2543
|
-
}
|
|
2544
|
-
} else if (hasFailed(suite)) suite.result.state = "fail";
|
|
2545
|
-
else suite.result.state = "pass";
|
|
2546
|
-
suite.result.duration = now() - start;
|
|
2547
|
-
await runner.onAfterRunSuite?.(suite);
|
|
2548
|
-
updateTask("suite-finished", suite, runner);
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
async function runSuiteChild(c, runner) {
|
|
2552
|
-
const $ = runner.trace;
|
|
2553
|
-
if (c.type === "test") return $("run.test", {
|
|
2554
|
-
"vitest.test.id": c.id,
|
|
2555
|
-
"vitest.test.name": c.name,
|
|
2556
|
-
"vitest.test.mode": c.mode,
|
|
2557
|
-
"vitest.test.timeout": c.timeout,
|
|
2558
|
-
"code.file.path": c.file.filepath,
|
|
2559
|
-
"code.line.number": c.location?.line,
|
|
2560
|
-
"code.column.number": c.location?.column
|
|
2561
|
-
}, () => runTest(c, runner));
|
|
2562
|
-
else if (c.type === "suite") return $("run.suite", {
|
|
2563
|
-
"vitest.suite.id": c.id,
|
|
2564
|
-
"vitest.suite.name": c.name,
|
|
2565
|
-
"vitest.suite.mode": c.mode,
|
|
2566
|
-
"code.file.path": c.file.filepath,
|
|
2567
|
-
"code.line.number": c.location?.line,
|
|
2568
|
-
"code.column.number": c.location?.column
|
|
2569
|
-
}, () => runSuite(c, runner));
|
|
2570
|
-
}
|
|
2571
|
-
async function runFiles(files, runner) {
|
|
2572
|
-
limitMaxConcurrency ??= limitConcurrency(runner.config.maxConcurrency);
|
|
2573
|
-
for (const file of files) {
|
|
2574
|
-
if (!file.tasks.length && !runner.config.passWithNoTests) {
|
|
2575
|
-
if (!file.result?.errors?.length) file.result = {
|
|
2576
|
-
state: "fail",
|
|
2577
|
-
errors: [processError(/* @__PURE__ */ new Error(`No test suite found in file ${file.filepath}`))]
|
|
2578
|
-
};
|
|
2579
|
-
}
|
|
2580
|
-
await runner.trace("run.spec", {
|
|
2581
|
-
"code.file.path": file.filepath,
|
|
2582
|
-
"vitest.suite.tasks.length": file.tasks.length
|
|
2583
|
-
}, () => runSuite(file, runner));
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
const workerRunners = /* @__PURE__ */ new WeakSet();
|
|
2587
|
-
function defaultTrace(_, attributes, cb) {
|
|
2588
|
-
if (typeof attributes === "function") return attributes();
|
|
2589
|
-
return cb();
|
|
2590
|
-
}
|
|
2591
|
-
async function startTests(specs, runner) {
|
|
2592
|
-
runner.trace ??= defaultTrace;
|
|
2593
|
-
const cancel = runner.cancel?.bind(runner);
|
|
2594
|
-
runner.cancel = (reason) => {
|
|
2595
|
-
const error = new TestRunAbortError("The test run was aborted by the user.", reason);
|
|
2596
|
-
getRunningTests().forEach((test) => {
|
|
2597
|
-
abortContextSignal(test.context, error);
|
|
2598
|
-
markPendingTasksAsSkipped(test.file, runner, error.message);
|
|
2599
|
-
});
|
|
2600
|
-
return cancel?.(reason);
|
|
2601
|
-
};
|
|
2602
|
-
if (!workerRunners.has(runner)) {
|
|
2603
|
-
runner.onCleanupWorkerContext?.(async () => {
|
|
2604
|
-
await Promise.all([...TestFixtures.getWorkerContexts()].map((context) => callFixtureCleanup(context))).finally(() => {
|
|
2605
|
-
TestFixtures.clearDefinitions();
|
|
2606
|
-
});
|
|
2607
|
-
});
|
|
2608
|
-
workerRunners.add(runner);
|
|
2609
|
-
}
|
|
2610
|
-
try {
|
|
2611
|
-
const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
|
|
2612
|
-
await runner.onBeforeCollect?.(paths);
|
|
2613
|
-
const files = await collectTests(specs, runner);
|
|
2614
|
-
await runner.onCollected?.(files);
|
|
2615
|
-
await runner.onBeforeRunFiles?.(files);
|
|
2616
|
-
await runFiles(files, runner);
|
|
2617
|
-
await runner.onAfterRunFiles?.(files);
|
|
2618
|
-
await finishSendTasksUpdate(runner);
|
|
2619
|
-
return files;
|
|
2620
|
-
} finally {
|
|
2621
|
-
runner.cancel = cancel;
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
|
-
async function publicCollect(specs, runner) {
|
|
2625
|
-
runner.trace ??= defaultTrace;
|
|
2626
|
-
const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
|
|
2627
|
-
await runner.onBeforeCollect?.(paths);
|
|
2628
|
-
const files = await collectTests(specs, runner);
|
|
2629
|
-
await runner.onCollected?.(files);
|
|
2630
|
-
return files;
|
|
2631
|
-
}
|
|
2632
|
-
/**
|
|
2633
|
-
* @experimental
|
|
2634
|
-
* @advanced
|
|
2635
|
-
*
|
|
2636
|
-
* Records a custom test artifact during test execution.
|
|
2637
|
-
*
|
|
2638
|
-
* This function allows you to attach structured data, files, or metadata to a test.
|
|
2639
|
-
*
|
|
2640
|
-
* Vitest automatically injects the source location where the artifact was created and manages any attachments you include.
|
|
2641
|
-
*
|
|
2642
|
-
* **Note:** artifacts must be recorded before the task is reported. Any artifacts recorded after that will not be included in the task.
|
|
2643
|
-
*
|
|
2644
|
-
* @param task - The test task context, typically accessed via `this.task` in custom matchers or `context.task` in tests
|
|
2645
|
-
* @param artifact - The artifact to record. Must extend {@linkcode TestArtifactBase}
|
|
2646
|
-
*
|
|
2647
|
-
* @returns A promise that resolves to the recorded artifact with location injected
|
|
2648
|
-
*
|
|
2649
|
-
* @throws {Error} If the test runner doesn't support artifacts
|
|
2650
|
-
*
|
|
2651
|
-
* @example
|
|
2652
|
-
* ```ts
|
|
2653
|
-
* // In a custom assertion
|
|
2654
|
-
* async function toHaveValidSchema(this: MatcherState, actual: unknown) {
|
|
2655
|
-
* const validation = validateSchema(actual)
|
|
2656
|
-
*
|
|
2657
|
-
* await recordArtifact(this.task, {
|
|
2658
|
-
* type: 'my-plugin:schema-validation',
|
|
2659
|
-
* passed: validation.valid,
|
|
2660
|
-
* errors: validation.errors,
|
|
2661
|
-
* })
|
|
2662
|
-
*
|
|
2663
|
-
* return { pass: validation.valid, message: () => '...' }
|
|
2664
|
-
* }
|
|
2665
|
-
* ```
|
|
2666
|
-
*/
|
|
2667
|
-
async function recordArtifact(task, artifact) {
|
|
2668
|
-
const runner = getRunner();
|
|
2669
|
-
const stack = findTestFileStackTrace(task.file.filepath, (/* @__PURE__ */ new Error("STACK_TRACE")).stack);
|
|
2670
|
-
if (stack) {
|
|
2671
|
-
artifact.location = {
|
|
2672
|
-
file: stack.file,
|
|
2673
|
-
line: stack.line,
|
|
2674
|
-
column: stack.column
|
|
2675
|
-
};
|
|
2676
|
-
if (artifact.type === "internal:annotation") artifact.annotation.location = artifact.location;
|
|
2677
|
-
}
|
|
2678
|
-
if (Array.isArray(artifact.attachments)) for (const attachment of artifact.attachments) manageArtifactAttachment(attachment);
|
|
2679
|
-
if (artifact.type === "internal:annotation") return artifact;
|
|
2680
|
-
if (!runner.onTestArtifactRecord) throw new Error(`Test runner doesn't support test artifacts.`);
|
|
2681
|
-
await finishSendTasksUpdate(runner);
|
|
2682
|
-
const resolvedArtifact = await runner.onTestArtifactRecord(task, artifact);
|
|
2683
|
-
task.artifacts.push(resolvedArtifact);
|
|
2684
|
-
return resolvedArtifact;
|
|
2685
|
-
}
|
|
2686
|
-
const table = [];
|
|
2687
|
-
for (let i = 65; i < 91; i++) table.push(String.fromCharCode(i));
|
|
2688
|
-
for (let i = 97; i < 123; i++) table.push(String.fromCharCode(i));
|
|
2689
|
-
for (let i = 0; i < 10; i++) table.push(i.toString(10));
|
|
2690
|
-
table.push("+", "/");
|
|
2691
|
-
function encodeUint8Array(bytes) {
|
|
2692
|
-
let base64 = "";
|
|
2693
|
-
const len = bytes.byteLength;
|
|
2694
|
-
for (let i = 0; i < len; i += 3) if (len === i + 1) {
|
|
2695
|
-
const a = (bytes[i] & 252) >> 2;
|
|
2696
|
-
const b = (bytes[i] & 3) << 4;
|
|
2697
|
-
base64 += table[a];
|
|
2698
|
-
base64 += table[b];
|
|
2699
|
-
base64 += "==";
|
|
2700
|
-
} else if (len === i + 2) {
|
|
2701
|
-
const a = (bytes[i] & 252) >> 2;
|
|
2702
|
-
const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
|
|
2703
|
-
const c = (bytes[i + 1] & 15) << 2;
|
|
2704
|
-
base64 += table[a];
|
|
2705
|
-
base64 += table[b];
|
|
2706
|
-
base64 += table[c];
|
|
2707
|
-
base64 += "=";
|
|
2708
|
-
} else {
|
|
2709
|
-
const a = (bytes[i] & 252) >> 2;
|
|
2710
|
-
const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
|
|
2711
|
-
const c = (bytes[i + 1] & 15) << 2 | (bytes[i + 2] & 192) >> 6;
|
|
2712
|
-
const d = bytes[i + 2] & 63;
|
|
2713
|
-
base64 += table[a];
|
|
2714
|
-
base64 += table[b];
|
|
2715
|
-
base64 += table[c];
|
|
2716
|
-
base64 += table[d];
|
|
2717
|
-
}
|
|
2718
|
-
return base64;
|
|
2719
|
-
}
|
|
2720
|
-
/**
|
|
2721
|
-
* Records an async operation associated with a test task.
|
|
2722
|
-
*
|
|
2723
|
-
* This function tracks promises that should be awaited before a test completes.
|
|
2724
|
-
* The promise is automatically removed from the test's promise list once it settles.
|
|
2725
|
-
*/
|
|
2726
|
-
function recordAsyncOperation(test, promise) {
|
|
2727
|
-
promise = promise.finally(() => {
|
|
2728
|
-
if (!test.promises) return;
|
|
2729
|
-
const index = test.promises.indexOf(promise);
|
|
2730
|
-
if (index !== -1) test.promises.splice(index, 1);
|
|
2731
|
-
});
|
|
2732
|
-
if (!test.promises) test.promises = [];
|
|
2733
|
-
test.promises.push(promise);
|
|
2734
|
-
return promise;
|
|
2735
|
-
}
|
|
2736
|
-
/**
|
|
2737
|
-
* Validates and prepares a test attachment for serialization.
|
|
2738
|
-
*
|
|
2739
|
-
* This function ensures attachments have either `body` or `path` set (but not both), and converts `Uint8Array` bodies to base64-encoded strings for easier serialization.
|
|
2740
|
-
*
|
|
2741
|
-
* @param attachment - The attachment to validate and prepare
|
|
2742
|
-
*
|
|
2743
|
-
* @throws {TypeError} If neither `body` nor `path` is provided
|
|
2744
|
-
* @throws {TypeError} If both `body` and `path` are provided
|
|
2745
|
-
*/
|
|
2746
|
-
function manageArtifactAttachment(attachment) {
|
|
2747
|
-
if (attachment.body == null && !attachment.path) throw new TypeError(`Test attachment requires "body" or "path" to be set. Both are missing.`);
|
|
2748
|
-
if (attachment.body && attachment.path) throw new TypeError(`Test attachment requires only one of "body" or "path" to be set. Both are specified.`);
|
|
2749
|
-
if (attachment.path && attachment.bodyEncoding) throw new TypeError(`Test attachment with "path" should not have "bodyEncoding" specified.`);
|
|
2750
|
-
if (attachment.body instanceof Uint8Array) attachment.body = encodeUint8Array(attachment.body);
|
|
2751
|
-
if (attachment.body != null) attachment.bodyEncoding ??= "base64";
|
|
2752
|
-
}
|
|
2753
|
-
//#endregion
|
|
2754
|
-
export { createTagsFilter as A, createTaskName as B, findTestFileStackTrace as C, generateFileHash as D, generateHash as E, getFullName as F, getNames as G, getSuites as H, getTasks as I, getTestName as J, getTests as K, hasFailed as L, hasTests as M, interpretTaskModes as N, isTestCase as O, limitConcurrency as P, matchesTags as Q, partitionSuiteChildren as R, someTasksAreOnly as S, validateTags as T, afterAll as a, afterEach as b, aroundAll as c, aroundEach as d, beforeAll as e, beforeEach as f, createTaskCollector as g, describe as h, getCurrentSuite as i, getCurrentTest as j, getFn as k, getHooks as l, it as m, onTestFinished as n, onTestFailed as o, publicCollect as p, setHooks as q, recordArtifact as r, setFn as s, startTests as t, suite as u, test as v, updateTask as w, calculateSuiteHash as x, createChainable as y, createFileTask as z };
|
|
2755
|
-
|
|
2756
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2h1bmstYXJ0aWZhY3QuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL0B2aXRlc3QrcnVubmVyQDQuMS4xMC9ub2RlX21vZHVsZXMvQHZpdGVzdC9ydW5uZXIvZGlzdC9jaHVuay1hcnRpZmFjdC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBwcm9jZXNzRXJyb3IgfSBmcm9tICdAdml0ZXN0L3V0aWxzL2Vycm9yJztcbmltcG9ydCB7IGlzT2JqZWN0LCBmaWx0ZXJPdXRDb21tZW50cywgb3JkaW5hbCwgY3JlYXRlRGVmZXIsIGFzc2VydFR5cGVzLCB0b0FycmF5LCBpc05lZ2F0aXZlTmFOLCB1bmlxdWUsIG9iamVjdEF0dHIsIHNodWZmbGUgfSBmcm9tICdAdml0ZXN0L3V0aWxzL2hlbHBlcnMnO1xuaW1wb3J0IHsgZ2V0U2FmZVRpbWVycyB9IGZyb20gJ0B2aXRlc3QvdXRpbHMvdGltZXJzJztcbmltcG9ydCB7IGZvcm1hdCwgZm9ybWF0UmVnRXhwLCBvYmpEaXNwbGF5IH0gZnJvbSAnQHZpdGVzdC91dGlscy9kaXNwbGF5JztcbmltcG9ydCB7IHBhcnNlU2luZ2xlU3RhY2sgfSBmcm9tICdAdml0ZXN0L3V0aWxzL3NvdXJjZS1tYXAnO1xuaW1wb3J0IHsgcmVsYXRpdmUgfSBmcm9tICdwYXRoZSc7XG5cbmNsYXNzIFBlbmRpbmdFcnJvciBleHRlbmRzIEVycm9yIHtcblx0Y29kZSA9IFwiVklURVNUX1BFTkRJTkdcIjtcblx0dGFza0lkO1xuXHRjb25zdHJ1Y3RvcihtZXNzYWdlLCB0YXNrLCBub3RlKSB7XG5cdFx0c3VwZXIobWVzc2FnZSk7XG5cdFx0dGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcblx0XHR0aGlzLm5vdGUgPSBub3RlO1xuXHRcdHRoaXMudGFza0lkID0gdGFzay5pZDtcblx0fVxufVxuY2xhc3MgVGVzdFJ1bkFib3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIlRlc3RSdW5BYm9ydEVycm9yXCI7XG5cdHJlYXNvbjtcblx0Y29uc3RydWN0b3IobWVzc2FnZSwgcmVhc29uKSB7XG5cdFx0c3VwZXIobWVzc2FnZSk7XG5cdFx0dGhpcy5yZWFzb24gPSByZWFzb247XG5cdH1cbn1cbmNsYXNzIEZpeHR1cmVEZXBlbmRlbmN5RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIkZpeHR1cmVEZXBlbmRlbmN5RXJyb3JcIjtcbn1cbmNsYXNzIEZpeHR1cmVBY2Nlc3NFcnJvciBleHRlbmRzIEVycm9yIHtcblx0bmFtZSA9IFwiRml4dHVyZUFjY2Vzc0Vycm9yXCI7XG59XG5jbGFzcyBGaXh0dXJlUGFyc2VFcnJvciBleHRlbmRzIEVycm9yIHtcblx0bmFtZSA9IFwiRml4dHVyZVBhcnNlRXJyb3JcIjtcbn1cbmNsYXNzIEFyb3VuZEhvb2tTZXR1cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuXHRuYW1lID0gXCJBcm91bmRIb29rU2V0dXBFcnJvclwiO1xufVxuY2xhc3MgQXJvdW5kSG9va1RlYXJkb3duRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG5cdG5hbWUgPSBcIkFyb3VuZEhvb2tUZWFyZG93bkVycm9yXCI7XG59XG5jbGFzcyBBcm91bmRIb29rTXVsdGlwbGVDYWxsc0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuXHRuYW1lID0gXCJBcm91bmRIb29rTXVsdGlwbGVDYWxsc0Vycm9yXCI7XG59XG5cbi8vIHVzZSBXZWFrTWFwIGhlcmUgdG8gbWFrZSB0aGUgVGVzdCBhbmQgU3VpdGUgb2JqZWN0IHNlcmlhbGl6YWJsZVxuY29uc3QgZm5NYXAgPSBuZXcgV2Vha01hcCgpO1xuY29uc3QgdGVzdEZpeHR1cmVNYXAgPSBuZXcgV2Vha01hcCgpO1xuY29uc3QgaG9va3NNYXAgPSBuZXcgV2Vha01hcCgpO1xuZnVuY3Rpb24gc2V0Rm4oa2V5LCBmbikge1xuXHRmbk1hcC5zZXQoa2V5LCBmbik7XG59XG5mdW5jdGlvbiBnZXRGbihrZXkpIHtcblx0cmV0dXJuIGZuTWFwLmdldChrZXkpO1xufVxuZnVuY3Rpb24gc2V0VGVzdEZpeHR1cmUoa2V5LCBmaXh0dXJlKSB7XG5cdHRlc3RGaXh0dXJlTWFwLnNldChrZXksIGZpeHR1cmUpO1xufVxuZnVuY3Rpb24gZ2V0VGVzdEZpeHR1cmVzKGtleSkge1xuXHRyZXR1cm4gdGVzdEZpeHR1cmVNYXAuZ2V0KGtleSk7XG59XG5mdW5jdGlvbiBzZXRIb29rcyhrZXksIGhvb2tzKSB7XG5cdGhvb2tzTWFwLnNldChrZXksIGhvb2tzKTtcbn1cbmZ1bmN0aW9uIGdldEhvb2tzKGtleSkge1xuXHRyZXR1cm4gaG9va3NNYXAuZ2V0KGtleSk7XG59XG5cbmNvbnN0IEZJWFRVUkVfU1RBQ0tfVFJBQ0VfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9GSVhUVVJFX1NUQUNLX1RSQUNFXCIpO1xuY2xhc3MgVGVzdEZpeHR1cmVzIHtcblx0X3N1aXRlQ29udGV4dHM7XG5cdF9vdmVycmlkZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRfcmVnaXN0cmF0aW9ucztcblx0c3RhdGljIF9kZWZpbml0aW9ucyA9IFtdO1xuXHRzdGF0aWMgX2J1aWx0aW5GaXh0dXJlcyA9IFtcblx0XHRcInRhc2tcIixcblx0XHRcInNpZ25hbFwiLFxuXHRcdFwib25UZXN0RmFpbGVkXCIsXG5cdFx0XCJvblRlc3RGaW5pc2hlZFwiLFxuXHRcdFwic2tpcFwiLFxuXHRcdFwiYW5ub3RhdGVcIlxuXHRdO1xuXHRzdGF0aWMgX2ZpeHR1cmVPcHRpb25LZXlzID0gW1xuXHRcdFwiYXV0b1wiLFxuXHRcdFwiaW5qZWN0ZWRcIixcblx0XHRcInNjb3BlXCJcblx0XTtcblx0c3RhdGljIF9maXh0dXJlU2NvcGVzID0gW1xuXHRcdFwidGVzdFwiLFxuXHRcdFwiZmlsZVwiLFxuXHRcdFwid29ya2VyXCJcblx0XTtcblx0c3RhdGljIF93b3JrZXJDb250ZXh0U3VpdGUgPSB7IHR5cGU6IFwid29ya2VyXCIgfTtcblx0c3RhdGljIGNsZWFyRGVmaW5pdGlvbnMoKSB7XG5cdFx0VGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5sZW5ndGggPSAwO1xuXHR9XG5cdHN0YXRpYyBnZXRXb3JrZXJDb250ZXh0cygpIHtcblx0XHRyZXR1cm4gVGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5tYXAoKGYpID0+IGYuZ2V0V29ya2VyQ29udGV4dCgpKTtcblx0fVxuXHRzdGF0aWMgZ2V0RmlsZUNvbnRleHRzKGZpbGUpIHtcblx0XHRyZXR1cm4gVGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5tYXAoKGYpID0+IGYuZ2V0RmlsZUNvbnRleHQoZmlsZSkpO1xuXHR9XG5cdHN0YXRpYyBpc0ZpeHR1cmVPcHRpb25zKG9iaikge1xuXHRcdHJldHVybiBpc09iamVjdChvYmopICYmIE9iamVjdC5rZXlzKG9iaikuc29tZSgoa2V5KSA9PiBUZXN0Rml4dHVyZXMuX2ZpeHR1cmVPcHRpb25LZXlzLmluY2x1ZGVzKGtleSkpO1xuXHR9XG5cdGNvbnN0cnVjdG9yKHJlZ2lzdHJhdGlvbnMpIHtcblx0XHR0aGlzLl9yZWdpc3RyYXRpb25zID0gcmVnaXN0cmF0aW9ucyA/PyBuZXcgTWFwKCk7XG5cdFx0dGhpcy5fc3VpdGVDb250ZXh0cyA9IG5ldyBXZWFrTWFwKCk7XG5cdFx0VGVzdEZpeHR1cmVzLl9kZWZpbml0aW9ucy5wdXNoKHRoaXMpO1xuXHR9XG5cdGV4dGVuZChydW5uZXIsIHVzZXJGaXh0dXJlcykge1xuXHRcdGNvbnN0IHsgc3VpdGUgfSA9IGdldEN1cnJlbnRTdWl0ZSgpO1xuXHRcdGNvbnN0IGlzVG9wTGV2ZWwgPSAhc3VpdGUgfHwgc3VpdGUuZmlsZSA9PT0gc3VpdGU7XG5cdFx0Y29uc3QgcmVnaXN0cmF0aW9ucyA9IHRoaXMucGFyc2VVc2VyRml4dHVyZXMocnVubmVyLCB1c2VyRml4dHVyZXMsIGlzVG9wTGV2ZWwpO1xuXHRcdHJldHVybiBuZXcgVGVzdEZpeHR1cmVzKHJlZ2lzdHJhdGlvbnMpO1xuXHR9XG5cdGdldChzdWl0ZSkge1xuXHRcdGxldCBjdXJyZW50U3VpdGUgPSBzdWl0ZTtcblx0XHR3aGlsZSAoY3VycmVudFN1aXRlKSB7XG5cdFx0XHRjb25zdCBvdmVycmlkZXMgPSB0aGlzLl9vdmVycmlkZXMuZ2V0KGN1cnJlbnRTdWl0ZSk7XG5cdFx0XHQvLyByZXR1cm4gdGhlIGNsb3Nlc3Qgb3ZlcnJpZGVcblx0XHRcdGlmIChvdmVycmlkZXMpIHtcblx0XHRcdFx0cmV0dXJuIG92ZXJyaWRlcztcblx0XHRcdH1cblx0XHRcdGlmIChjdXJyZW50U3VpdGUgPT09IGN1cnJlbnRTdWl0ZS5maWxlKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0Y3VycmVudFN1aXRlID0gY3VycmVudFN1aXRlLnN1aXRlIHx8IGN1cnJlbnRTdWl0ZS5maWxlO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fcmVnaXN0cmF0aW9ucztcblx0fVxuXHRvdmVycmlkZShydW5uZXIsIHVzZXJGaXh0dXJlcykge1xuXHRcdGNvbnN0IHsgc3VpdGU6IGN1cnJlbnRTdWl0ZSwgZmlsZSB9ID0gZ2V0Q3VycmVudFN1aXRlKCk7XG5cdFx0Y29uc3Qgc3VpdGUgPSBjdXJyZW50U3VpdGUgfHwgZmlsZTtcblx0XHRjb25zdCBpc1RvcExldmVsID0gIWN1cnJlbnRTdWl0ZSB8fCBjdXJyZW50U3VpdGUuZmlsZSA9PT0gY3VycmVudFN1aXRlO1xuXHRcdC8vIENyZWF0ZSBhIGNvcHkgb2YgdGhlIGNsb3Nlc3QgcGFyZW50J3MgcmVnaXN0cmF0aW9ucyB0byBhdm9pZCBtb2RpZnlpbmcgdGhlbVxuXHRcdC8vIEZvciBjaGFpbmVkIGNhbGxzLCB0aGlzLmdldChzdWl0ZSkgcmV0dXJucyB0aGlzIHN1aXRlJ3Mgb3ZlcnJpZGVzOyBmb3IgZmlyc3QgY2FsbCwgcmV0dXJucyBwYXJlbnQnc1xuXHRcdGNvbnN0IHN1aXRlUmVnaXN0cmF0aW9ucyA9IG5ldyBNYXAodGhpcy5nZXQoc3VpdGUpKTtcblx0XHRjb25zdCByZWdpc3RyYXRpb25zID0gdGhpcy5wYXJzZVVzZXJGaXh0dXJlcyhydW5uZXIsIHVzZXJGaXh0dXJlcywgaXNUb3BMZXZlbCwgc3VpdGVSZWdpc3RyYXRpb25zKTtcblx0XHQvLyBJZiBkZWZpbmVkIGluIHRvcC1sZXZlbCwganVzdCBvdmVycmlkZSBhbGwgcmVnaXN0cmF0aW9uc1xuXHRcdC8vIFdlIGRvbid0IHN1cHBvcnQgb3ZlcnJpZGluZyBzdWl0ZS1sZXZlbCBmaXh0dXJlcyBhbnl3YXkgKGl0IHdpbGwgdGhyb3cgYW4gZXJyb3IpXG5cdFx0aWYgKGlzVG9wTGV2ZWwpIHtcblx0XHRcdHRoaXMuX3JlZ2lzdHJhdGlvbnMgPSByZWdpc3RyYXRpb25zO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9vdmVycmlkZXMuc2V0KHN1aXRlLCByZWdpc3RyYXRpb25zKTtcblx0XHR9XG5cdH1cblx0Z2V0RmlsZUNvbnRleHQoZmlsZSkge1xuXHRcdGlmICghdGhpcy5fc3VpdGVDb250ZXh0cy5oYXMoZmlsZSkpIHtcblx0XHRcdHRoaXMuX3N1aXRlQ29udGV4dHMuc2V0KGZpbGUsIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fc3VpdGVDb250ZXh0cy5nZXQoZmlsZSk7XG5cdH1cblx0Z2V0V29ya2VyQ29udGV4dCgpIHtcblx0XHRpZiAoIXRoaXMuX3N1aXRlQ29udGV4dHMuaGFzKFRlc3RGaXh0dXJlcy5fd29ya2VyQ29udGV4dFN1aXRlKSkge1xuXHRcdFx0dGhpcy5fc3VpdGVDb250ZXh0cy5zZXQoVGVzdEZpeHR1cmVzLl93b3JrZXJDb250ZXh0U3VpdGUsIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fc3VpdGVDb250ZXh0cy5nZXQoVGVzdEZpeHR1cmVzLl93b3JrZXJDb250ZXh0U3VpdGUpO1xuXHR9XG5cdHBhcnNlVXNlckZpeHR1cmVzKHJ1bm5lciwgdXNlckZpeHR1cmVzLCBzdXBwb3J0Tm9uVGVzdCwgcmVnaXN0cmF0aW9ucyA9IG5ldyBNYXAodGhpcy5fcmVnaXN0cmF0aW9ucykpIHtcblx0XHRjb25zdCBlcnJvcnMgPSBbXTtcblx0XHRPYmplY3QuZW50cmllcyh1c2VyRml4dHVyZXMpLmZvckVhY2goKFtuYW1lLCBmbl0pID0+IHtcblx0XHRcdGxldCBvcHRpb25zO1xuXHRcdFx0bGV0IHZhbHVlO1xuXHRcdFx0bGV0IF9vcHRpb25zO1xuXHRcdFx0aWYgKEFycmF5LmlzQXJyYXkoZm4pICYmIGZuLmxlbmd0aCA+PSAyICYmIFRlc3RGaXh0dXJlcy5pc0ZpeHR1cmVPcHRpb25zKGZuWzFdKSkge1xuXHRcdFx0XHRfb3B0aW9ucyA9IGZuWzFdO1xuXHRcdFx0XHRvcHRpb25zID0ge1xuXHRcdFx0XHRcdGF1dG86IF9vcHRpb25zLmF1dG8gPz8gZmFsc2UsXG5cdFx0XHRcdFx0c2NvcGU6IF9vcHRpb25zLnNjb3BlID8/IFwidGVzdFwiLFxuXHRcdFx0XHRcdGluamVjdGVkOiBfb3B0aW9ucy5pbmplY3RlZCA/PyBmYWxzZVxuXHRcdFx0XHR9O1xuXHRcdFx0XHR2YWx1ZSA9IG9wdGlvbnMuaW5qZWN0ZWQgPyBydW5uZXIuaW5qZWN0VmFsdWU/LihuYW1lKSA/PyBmblswXSA6IGZuWzBdO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFsdWUgPSBmbjtcblx0XHRcdH1cblx0XHRcdGNvbnN0IHBhcmVudCA9IHJlZ2lzdHJhdGlvbnMuZ2V0KG5hbWUpO1xuXHRcdFx0aWYgKHBhcmVudCAmJiBvcHRpb25zKSB7XG5cdFx0XHRcdGlmIChwYXJlbnQuc2NvcGUgIT09IG9wdGlvbnMuc2NvcGUpIHtcblx0XHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgd2FzIGFscmVhZHkgcmVnaXN0ZXJlZCB3aXRoIGEgXCIke29wdGlvbnMuc2NvcGV9XCIgc2NvcGUuYCkpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChwYXJlbnQuYXV0byAhPT0gb3B0aW9ucy5hdXRvKSB7XG5cdFx0XHRcdFx0ZXJyb3JzLnB1c2gobmV3IEZpeHR1cmVEZXBlbmRlbmN5RXJyb3IoYFRoZSBcIiR7bmFtZX1cIiBmaXh0dXJlIHdhcyBhbHJlYWR5IHJlZ2lzdGVyZWQgYXMgeyBhdXRvOiAke29wdGlvbnMuYXV0b30gfS5gKSk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAocGFyZW50KSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7XG5cdFx0XHRcdFx0YXV0bzogcGFyZW50LmF1dG8sXG5cdFx0XHRcdFx0c2NvcGU6IHBhcmVudC5zY29wZSxcblx0XHRcdFx0XHRpbmplY3RlZDogcGFyZW50LmluamVjdGVkXG5cdFx0XHRcdH07XG5cdFx0XHR9IGVsc2UgaWYgKCFvcHRpb25zKSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7XG5cdFx0XHRcdFx0YXV0bzogZmFsc2UsXG5cdFx0XHRcdFx0aW5qZWN0ZWQ6IGZhbHNlLFxuXHRcdFx0XHRcdHNjb3BlOiBcInRlc3RcIlxuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0aWYgKG9wdGlvbnMuc2NvcGUgJiYgIVRlc3RGaXh0dXJlcy5fZml4dHVyZVNjb3Blcy5pbmNsdWRlcyhvcHRpb25zLnNjb3BlKSkge1xuXHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgaGFzIHVua25vd24gc2NvcGUgXCIke29wdGlvbnMuc2NvcGV9XCIuYCkpO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCFzdXBwb3J0Tm9uVGVzdCAmJiBvcHRpb25zLnNjb3BlICE9PSBcInRlc3RcIikge1xuXHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlIFwiJHtuYW1lfVwiIGZpeHR1cmUgY2Fubm90IGJlIGRlZmluZWQgd2l0aCBhICR7b3B0aW9ucy5zY29wZX0gc2NvcGUkeyFfb3B0aW9ucz8uc2NvcGUgJiYgcGFyZW50Py5zY29wZSA/IFwiIChpbmhlcml0ZWQgZnJvbSB0aGUgYmFzZSBmaXh0dXJlKVwiIDogXCJcIn0gaW5zaWRlIHRoZSBkZXNjcmliZSBibG9jay4gRGVmaW5lIGl0IGF0IHRoZSB0b3AgbGV2ZWwgb2YgdGhlIGZpbGUgaW5zdGVhZC5gKSk7XG5cdFx0XHR9XG5cdFx0XHRjb25zdCBkZXBzID0gaXNGaXh0dXJlRnVuY3Rpb24odmFsdWUpID8gZ2V0VXNlZFByb3BzKHZhbHVlKSA6IG5ldyBTZXQoKTtcblx0XHRcdGNvbnN0IGl0ZW0gPSB7XG5cdFx0XHRcdG5hbWUsXG5cdFx0XHRcdHZhbHVlLFxuXHRcdFx0XHRhdXRvOiBvcHRpb25zLmF1dG8gPz8gZmFsc2UsXG5cdFx0XHRcdGluamVjdGVkOiBvcHRpb25zLmluamVjdGVkID8/IGZhbHNlLFxuXHRcdFx0XHRzY29wZTogb3B0aW9ucy5zY29wZSA/PyBcInRlc3RcIixcblx0XHRcdFx0ZGVwcyxcblx0XHRcdFx0cGFyZW50XG5cdFx0XHR9O1xuXHRcdFx0aWYgKGlzRml4dHVyZUZ1bmN0aW9uKHZhbHVlKSkge1xuXHRcdFx0XHRPYmplY3QuYXNzaWduKHZhbHVlLCB7IFtGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV06IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpIH0pO1xuXHRcdFx0fVxuXHRcdFx0cmVnaXN0cmF0aW9ucy5zZXQobmFtZSwgaXRlbSk7XG5cdFx0XHRpZiAoaXRlbS5zY29wZSA9PT0gXCJ3b3JrZXJcIiAmJiAocnVubmVyLnBvb2wgPT09IFwidm1UaHJlYWRzXCIgfHwgcnVubmVyLnBvb2wgPT09IFwidm1Gb3Jrc1wiKSkge1xuXHRcdFx0XHRpdGVtLnNjb3BlID0gXCJmaWxlXCI7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ly8gdmFsaWRhdGUgZml4dHVyZSBkZXBlbmRlbmN5IHNjb3Blc1xuXHRcdGZvciAoY29uc3QgZml4dHVyZSBvZiByZWdpc3RyYXRpb25zLnZhbHVlcygpKSB7XG5cdFx0XHRmb3IgKGNvbnN0IGRlcE5hbWUgb2YgZml4dHVyZS5kZXBzKSB7XG5cdFx0XHRcdGlmIChUZXN0Rml4dHVyZXMuX2J1aWx0aW5GaXh0dXJlcy5pbmNsdWRlcyhkZXBOYW1lKSkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNvbnN0IGRlcCA9IHJlZ2lzdHJhdGlvbnMuZ2V0KGRlcE5hbWUpO1xuXHRcdFx0XHRpZiAoIWRlcCkge1xuXHRcdFx0XHRcdGVycm9ycy5wdXNoKG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUaGUgXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGRlcGVuZHMgb24gdW5rbm93biBmaXh0dXJlIFwiJHtkZXBOYW1lfVwiLmApKTtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoZGVwTmFtZSA9PT0gZml4dHVyZS5uYW1lICYmICFmaXh0dXJlLnBhcmVudCkge1xuXHRcdFx0XHRcdGVycm9ycy5wdXNoKG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUaGUgXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGRlcGVuZHMgb24gaXRzZWxmLCBidXQgZG9lcyBub3QgaGF2ZSBhIGJhc2UgaW1wbGVtZW50YXRpb24uYCkpO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChUZXN0Rml4dHVyZXMuX2ZpeHR1cmVTY29wZXMuaW5kZXhPZihmaXh0dXJlLnNjb3BlKSA+IFRlc3RGaXh0dXJlcy5fZml4dHVyZVNjb3Blcy5pbmRleE9mKGRlcC5zY29wZSkpIHtcblx0XHRcdFx0XHRlcnJvcnMucHVzaChuZXcgRml4dHVyZURlcGVuZGVuY3lFcnJvcihgVGhlICR7Zml4dHVyZS5zY29wZX0gXCIke2ZpeHR1cmUubmFtZX1cIiBmaXh0dXJlIGNhbm5vdCBkZXBlbmQgb24gYSAke2RlcC5zY29wZX0gZml4dHVyZSBcIiR7ZGVwLm5hbWV9XCIuYCkpO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmIChlcnJvcnMubGVuZ3RoID09PSAxKSB7XG5cdFx0XHR0aHJvdyBlcnJvcnNbMF07XG5cdFx0fSBlbHNlIGlmIChlcnJvcnMubGVuZ3RoID4gMSkge1xuXHRcdFx0dGhyb3cgbmV3IEFnZ3JlZ2F0ZUVycm9yKGVycm9ycywgXCJDYW5ub3QgcmVzb2x2ZSB1c2VyIGZpeHR1cmVzLiBTZWUgZXJyb3JzIGZvciBtb3JlIGluZm9ybWF0aW9uLlwiKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlZ2lzdHJhdGlvbnM7XG5cdH1cbn1cbmNvbnN0IGNsZWFudXBGbkFycmF5TWFwID0gbmV3IFdlYWtNYXAoKTtcbmFzeW5jIGZ1bmN0aW9uIGNhbGxGaXh0dXJlQ2xlYW51cChjb250ZXh0KSB7XG5cdGNvbnN0IGNsZWFudXBGbkFycmF5ID0gY2xlYW51cEZuQXJyYXlNYXAuZ2V0KGNvbnRleHQpID8/IFtdO1xuXHRmb3IgKGNvbnN0IGNsZWFudXAgb2YgY2xlYW51cEZuQXJyYXkucmV2ZXJzZSgpKSB7XG5cdFx0YXdhaXQgY2xlYW51cCgpO1xuXHR9XG5cdGNsZWFudXBGbkFycmF5TWFwLmRlbGV0ZShjb250ZXh0KTtcbn1cbi8qKlxuKiBSZXR1cm5zIHRoZSBjdXJyZW50IG51bWJlciBvZiBjbGVhbnVwIGZ1bmN0aW9ucyByZWdpc3RlcmVkIGZvciB0aGUgY29udGV4dC5cbiogVGhpcyBjYW4gYmUgdXNlZCBhcyBhIGNoZWNrcG9pbnQgdG8gbGF0ZXIgY2xlYW4gdXAgb25seSBmaXh0dXJlcyBhZGRlZCBhZnRlciB0aGlzIHBvaW50LlxuKi9cbmZ1bmN0aW9uIGdldEZpeHR1cmVDbGVhbnVwQ291bnQoY29udGV4dCkge1xuXHRyZXR1cm4gY2xlYW51cEZuQXJyYXlNYXAuZ2V0KGNvbnRleHQpPy5sZW5ndGggPz8gMDtcbn1cbi8qKlxuKiBDbGVhbnMgdXAgb25seSBmaXh0dXJlcyB0aGF0IHdlcmUgYWRkZWQgYWZ0ZXIgdGhlIGdpdmVuIGNoZWNrcG9pbnQgaW5kZXguXG4qIFRoaXMgaXMgdXNlZCBieSBhcm91bmRFYWNoIHRvIGNsZWFuIHVwIGZpeHR1cmVzIGNyZWF0ZWQgaW5zaWRlIHJ1blRlc3QoKVxuKiB3aGlsZSBwcmVzZXJ2aW5nIGZpeHR1cmVzIHRoYXQgd2VyZSBjcmVhdGVkIGZvciBhcm91bmRFYWNoIGl0c2VsZi5cbiovXG5hc3luYyBmdW5jdGlvbiBjYWxsRml4dHVyZUNsZWFudXBGcm9tKGNvbnRleHQsIGZyb21JbmRleCkge1xuXHRjb25zdCBjbGVhbnVwRm5BcnJheSA9IGNsZWFudXBGbkFycmF5TWFwLmdldChjb250ZXh0KTtcblx0aWYgKCFjbGVhbnVwRm5BcnJheSB8fCBjbGVhbnVwRm5BcnJheS5sZW5ndGggPD0gZnJvbUluZGV4KSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdC8vIEdldCBpdGVtcyBhZGRlZCBhZnRlciB0aGUgY2hlY2twb2ludFxuXHRjb25zdCB0b0NsZWFudXAgPSBjbGVhbnVwRm5BcnJheS5zbGljZShmcm9tSW5kZXgpO1xuXHQvLyBDbGVhbiB1cCBpbiByZXZlcnNlIG9yZGVyXG5cdGZvciAoY29uc3QgY2xlYW51cCBvZiB0b0NsZWFudXAucmV2ZXJzZSgpKSB7XG5cdFx0YXdhaXQgY2xlYW51cCgpO1xuXHR9XG5cdC8vIFJlbW92ZSBjbGVhbmVkIHVwIGl0ZW1zIGZyb20gdGhlIGFycmF5LCBrZWVwaW5nIGl0ZW1zIGJlZm9yZSBjaGVja3BvaW50XG5cdGNsZWFudXBGbkFycmF5Lmxlbmd0aCA9IGZyb21JbmRleDtcbn1cbmNvbnN0IGNvbnRleHRIYXNGaXh0dXJlc0NhY2hlID0gbmV3IFdlYWtNYXAoKTtcbmZ1bmN0aW9uIHdpdGhGaXh0dXJlcyhmbiwgb3B0aW9ucykge1xuXHRjb25zdCBjb2xsZWN0b3IgPSBnZXRDdXJyZW50U3VpdGUoKTtcblx0Y29uc3Qgc3VpdGUgPSBvcHRpb25zPy5zdWl0ZSB8fCBjb2xsZWN0b3Iuc3VpdGUgfHwgY29sbGVjdG9yLmZpbGU7XG5cdHJldHVybiBhc3luYyAoaG9va0NvbnRleHQpID0+IHtcblx0XHRjb25zdCBjb250ZXh0ID0gaG9va0NvbnRleHQgfHwgb3B0aW9ucz8uY29udGV4dDtcblx0XHRpZiAoIWNvbnRleHQpIHtcblx0XHRcdGlmIChvcHRpb25zPy5zdWl0ZUhvb2spIHtcblx0XHRcdFx0dmFsaWRhdGVTdWl0ZUhvb2soZm4sIG9wdGlvbnMuc3VpdGVIb29rLCBvcHRpb25zLnN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZm4oe30pO1xuXHRcdH1cblx0XHRjb25zdCBmaXh0dXJlcyA9IG9wdGlvbnM/LmZpeHR1cmVzIHx8IGdldFRlc3RGaXh0dXJlcyhjb250ZXh0KTtcblx0XHRpZiAoIWZpeHR1cmVzKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGNvbnN0IHJlZ2lzdHJhdGlvbnMgPSBmaXh0dXJlcy5nZXQoc3VpdGUpO1xuXHRcdGlmICghcmVnaXN0cmF0aW9ucy5zaXplKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGNvbnN0IHVzZWRGaXh0dXJlcyA9IFtdO1xuXHRcdGNvbnN0IHVzZWRQcm9wcyA9IGdldFVzZWRQcm9wcyhmbik7XG5cdFx0Zm9yIChjb25zdCBmaXh0dXJlIG9mIHJlZ2lzdHJhdGlvbnMudmFsdWVzKCkpIHtcblx0XHRcdGlmIChpc0F1dG9GaXh0dXJlKGZpeHR1cmUsIG9wdGlvbnMpIHx8IHVzZWRQcm9wcy5oYXMoZml4dHVyZS5uYW1lKSkge1xuXHRcdFx0XHR1c2VkRml4dHVyZXMucHVzaChmaXh0dXJlKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCF1c2VkRml4dHVyZXMubGVuZ3RoKSB7XG5cdFx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdFx0fVxuXHRcdGlmICghY2xlYW51cEZuQXJyYXlNYXAuaGFzKGNvbnRleHQpKSB7XG5cdFx0XHRjbGVhbnVwRm5BcnJheU1hcC5zZXQoY29udGV4dCwgW10pO1xuXHRcdH1cblx0XHRjb25zdCBjbGVhbnVwRm5BcnJheSA9IGNsZWFudXBGbkFycmF5TWFwLmdldChjb250ZXh0KTtcblx0XHRjb25zdCBwZW5kaW5nRml4dHVyZXMgPSByZXNvbHZlRGVwcyh1c2VkRml4dHVyZXMsIHJlZ2lzdHJhdGlvbnMpO1xuXHRcdGlmICghcGVuZGluZ0ZpeHR1cmVzLmxlbmd0aCkge1xuXHRcdFx0cmV0dXJuIGZuKGNvbnRleHQpO1xuXHRcdH1cblx0XHQvLyBDaGVjayBpZiBzdWl0ZS1sZXZlbCBob29rIGlzIHRyeWluZyB0byBhY2Nlc3MgdGVzdC1zY29wZWQgZml4dHVyZXNcblx0XHQvLyBTdWl0ZSBob29rcyAoYmVmb3JlQWxsL2FmdGVyQWxsL2Fyb3VuZEFsbCkgY2FuIG9ubHkgYWNjZXNzIGZpbGUvd29ya2VyIHNjb3BlZCBmaXh0dXJlc1xuXHRcdGlmIChvcHRpb25zPy5zdWl0ZUhvb2spIHtcblx0XHRcdGNvbnN0IHRlc3RTY29wZWRGaXh0dXJlcyA9IHBlbmRpbmdGaXh0dXJlcy5maWx0ZXIoKGYpID0+IGYuc2NvcGUgPT09IFwidGVzdFwiKTtcblx0XHRcdGlmICh0ZXN0U2NvcGVkRml4dHVyZXMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRjb25zdCBmaXh0dXJlTmFtZXMgPSB0ZXN0U2NvcGVkRml4dHVyZXMubWFwKChmKSA9PiBgXCIke2YubmFtZX1cImApLmpvaW4oXCIsIFwiKTtcblx0XHRcdFx0Y29uc3QgYWx0ZXJuYXRpdmVIb29rID0ge1xuXHRcdFx0XHRcdGFyb3VuZEFsbDogXCJhcm91bmRFYWNoXCIsXG5cdFx0XHRcdFx0YmVmb3JlQWxsOiBcImJlZm9yZUVhY2hcIixcblx0XHRcdFx0XHRhZnRlckFsbDogXCJhZnRlckVhY2hcIlxuXHRcdFx0XHR9O1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IG5ldyBGaXh0dXJlRGVwZW5kZW5jeUVycm9yKGBUZXN0LXNjb3BlZCBmaXh0dXJlcyBjYW5ub3QgYmUgdXNlZCBpbnNpZGUgJHtvcHRpb25zLnN1aXRlSG9va30gaG9vay4gYCArIGBUaGUgZm9sbG93aW5nIGZpeHR1cmVzIGFyZSB0ZXN0LXNjb3BlZDogJHtmaXh0dXJlTmFtZXN9LiBgICsgYFVzZSB7IHNjb3BlOiAnZmlsZScgfSBvciB7IHNjb3BlOiAnd29ya2VyJyB9IGZpeHR1cmVzIGluc3RlYWQsIG9yIG1vdmUgdGhlIGxvZ2ljIHRvICR7YWx0ZXJuYXRpdmVIb29rW29wdGlvbnMuc3VpdGVIb29rXX0gaG9vay5gKTtcblx0XHRcdFx0Ly8gVXNlIHN0YWNrIHRyYWNlIGZyb20gaG9vayByZWdpc3RyYXRpb24gZm9yIGJldHRlciBlcnJvciBsb2NhdGlvblxuXHRcdFx0XHRpZiAob3B0aW9ucy5zdGFja1RyYWNlRXJyb3I/LnN0YWNrKSB7XG5cdFx0XHRcdFx0ZXJyb3Iuc3RhY2sgPSBlcnJvci5tZXNzYWdlICsgb3B0aW9ucy5zdGFja1RyYWNlRXJyb3Iuc3RhY2sucmVwbGFjZShvcHRpb25zLnN0YWNrVHJhY2VFcnJvci5tZXNzYWdlLCBcIlwiKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aHJvdyBlcnJvcjtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCFjb250ZXh0SGFzRml4dHVyZXNDYWNoZS5oYXMoY29udGV4dCkpIHtcblx0XHRcdGNvbnRleHRIYXNGaXh0dXJlc0NhY2hlLnNldChjb250ZXh0LCBuZXcgV2Vha1NldCgpKTtcblx0XHR9XG5cdFx0Y29uc3QgY2FjaGVkRml4dHVyZXMgPSBjb250ZXh0SGFzRml4dHVyZXNDYWNoZS5nZXQoY29udGV4dCk7XG5cdFx0Zm9yIChjb25zdCBmaXh0dXJlIG9mIHBlbmRpbmdGaXh0dXJlcykge1xuXHRcdFx0aWYgKGZpeHR1cmUuc2NvcGUgPT09IFwidGVzdFwiKSB7XG5cdFx0XHRcdC8vIGZpeHR1cmUgY291bGQgYmUgYWxyZWFkeSBpbml0aWFsaXplZCBkdXJpbmcgXCJiZWZvcmVcIiBob29rXG5cdFx0XHRcdC8vIHdlIGNhbid0IGNoZWNrIFwiZml4dHVyZS5uYW1lXCIgaW4gY29udGV4dCBiZWNhdXNlIGNvbnRleHQgbWF5XG5cdFx0XHRcdC8vIGFjY2VzcyB0aGUgcGFyZW50IGZpeHR1cmUgKHsgYTogKHsgYSB9KSA9PiB7fSB9KVxuXHRcdFx0XHRpZiAoY2FjaGVkRml4dHVyZXMuaGFzKGZpeHR1cmUpKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2FjaGVkRml4dHVyZXMuYWRkKGZpeHR1cmUpO1xuXHRcdFx0XHRjb25zdCByZXNvbHZlZFZhbHVlID0gYXdhaXQgcmVzb2x2ZVRlc3RGaXh0dXJlVmFsdWUoZml4dHVyZSwgY29udGV4dCwgY2xlYW51cEZuQXJyYXkpO1xuXHRcdFx0XHRjb250ZXh0W2ZpeHR1cmUubmFtZV0gPSByZXNvbHZlZFZhbHVlO1xuXHRcdFx0XHRjbGVhbnVwRm5BcnJheS5wdXNoKCgpID0+IHtcblx0XHRcdFx0XHRjYWNoZWRGaXh0dXJlcy5kZWxldGUoZml4dHVyZSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgcmVzb2x2ZWRWYWx1ZSA9IGF3YWl0IHJlc29sdmVTY29wZUZpeHR1cmVWYWx1ZShmaXh0dXJlcywgc3VpdGUsIGZpeHR1cmUpO1xuXHRcdFx0XHRjb250ZXh0W2ZpeHR1cmUubmFtZV0gPSByZXNvbHZlZFZhbHVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZm4oY29udGV4dCk7XG5cdH07XG59XG5mdW5jdGlvbiBpc0F1dG9GaXh0dXJlKGZpeHR1cmUsIG9wdGlvbnMpIHtcblx0aWYgKCFmaXh0dXJlLmF1dG8pIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblx0Ly8gc3VpdGUgaG9vayBkb2Vzbid0IGF1dG9tYXRpY2FsbHkgdHJpZ2dlciB1bnVzZWQgdGVzdC1zY29wZWQgZml4dHVyZXMuXG5cdGlmIChvcHRpb25zPy5zdWl0ZUhvb2sgJiYgZml4dHVyZS5zY29wZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblx0cmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBpc0ZpeHR1cmVGdW5jdGlvbih2YWx1ZSkge1xuXHRyZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCI7XG59XG5mdW5jdGlvbiByZXNvbHZlVGVzdEZpeHR1cmVWYWx1ZShmaXh0dXJlLCBjb250ZXh0LCBjbGVhbnVwRm5BcnJheSkge1xuXHRpZiAoIWlzRml4dHVyZUZ1bmN0aW9uKGZpeHR1cmUudmFsdWUpKSB7XG5cdFx0cmV0dXJuIGZpeHR1cmUudmFsdWU7XG5cdH1cblx0cmV0dXJuIHJlc29sdmVGaXh0dXJlRnVuY3Rpb24oZml4dHVyZS52YWx1ZSwgZml4dHVyZS5uYW1lLCBjb250ZXh0LCBjbGVhbnVwRm5BcnJheSk7XG59XG5jb25zdCBzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlID0gbmV3IFdlYWtNYXAoKTtcbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTY29wZUZpeHR1cmVWYWx1ZShmaXh0dXJlcywgc3VpdGUsIGZpeHR1cmUpIHtcblx0Y29uc3Qgd29ya2VyQ29udGV4dCA9IGZpeHR1cmVzLmdldFdvcmtlckNvbnRleHQoKTtcblx0Y29uc3QgZmlsZUNvbnRleHQgPSBmaXh0dXJlcy5nZXRGaWxlQ29udGV4dChzdWl0ZS5maWxlKTtcblx0Y29uc3QgZml4dHVyZUNvbnRleHQgPSBmaXh0dXJlLnNjb3BlID09PSBcIndvcmtlclwiID8gd29ya2VyQ29udGV4dCA6IGZpbGVDb250ZXh0O1xuXHRpZiAoIWlzRml4dHVyZUZ1bmN0aW9uKGZpeHR1cmUudmFsdWUpKSB7XG5cdFx0Zml4dHVyZUNvbnRleHRbZml4dHVyZS5uYW1lXSA9IGZpeHR1cmUudmFsdWU7XG5cdFx0cmV0dXJuIGZpeHR1cmUudmFsdWU7XG5cdH1cblx0aWYgKGZpeHR1cmUubmFtZSBpbiBmaXh0dXJlQ29udGV4dCkge1xuXHRcdHJldHVybiBmaXh0dXJlQ29udGV4dFtmaXh0dXJlLm5hbWVdO1xuXHR9XG5cdGlmIChzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlLmhhcyhmaXh0dXJlKSkge1xuXHRcdHJldHVybiBzY29wZWRGaXh0dXJlUHJvbWlzZUNhY2hlLmdldChmaXh0dXJlKTtcblx0fVxuXHRpZiAoIWNsZWFudXBGbkFycmF5TWFwLmhhcyhmaXh0dXJlQ29udGV4dCkpIHtcblx0XHRjbGVhbnVwRm5BcnJheU1hcC5zZXQoZml4dHVyZUNvbnRleHQsIFtdKTtcblx0fVxuXHRjb25zdCBjbGVhbnVwRm5GaWxlQXJyYXkgPSBjbGVhbnVwRm5BcnJheU1hcC5nZXQoZml4dHVyZUNvbnRleHQpO1xuXHRjb25zdCBwcm9taXNlID0gcmVzb2x2ZUZpeHR1cmVGdW5jdGlvbihmaXh0dXJlLnZhbHVlLCBmaXh0dXJlLm5hbWUsIGZpeHR1cmUuc2NvcGUgPT09IFwiZmlsZVwiID8ge1xuXHRcdC4uLndvcmtlckNvbnRleHQsXG5cdFx0Li4uZmlsZUNvbnRleHRcblx0fSA6IGZpeHR1cmVDb250ZXh0LCBjbGVhbnVwRm5GaWxlQXJyYXkpLnRoZW4oKHZhbHVlKSA9PiB7XG5cdFx0Zml4dHVyZUNvbnRleHRbZml4dHVyZS5uYW1lXSA9IHZhbHVlO1xuXHRcdHNjb3BlZEZpeHR1cmVQcm9taXNlQ2FjaGUuZGVsZXRlKGZpeHR1cmUpO1xuXHRcdHJldHVybiB2YWx1ZTtcblx0fSk7XG5cdHNjb3BlZEZpeHR1cmVQcm9taXNlQ2FjaGUuc2V0KGZpeHR1cmUsIHByb21pc2UpO1xuXHRyZXR1cm4gcHJvbWlzZTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVGaXh0dXJlRnVuY3Rpb24oZml4dHVyZUZuLCBmaXh0dXJlTmFtZSwgY29udGV4dCwgY2xlYW51cEZuQXJyYXkpIHtcblx0Ly8gd2FpdCBmb3IgYHVzZWAgY2FsbCB0byBleHRyYWN0IGZpeHR1cmUgdmFsdWVcblx0Y29uc3QgdXNlRm5BcmdQcm9taXNlID0gY3JlYXRlRGVmZXIoKTtcblx0Y29uc3Qgc3RhY2tUcmFjZUVycm9yID0gRklYVFVSRV9TVEFDS19UUkFDRV9LRVkgaW4gZml4dHVyZUZuICYmIGZpeHR1cmVGbltGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV0gaW5zdGFuY2VvZiBFcnJvciA/IGZpeHR1cmVGbltGSVhUVVJFX1NUQUNLX1RSQUNFX0tFWV0gOiB1bmRlZmluZWQ7XG5cdGxldCBpc1VzZUZuQXJnUmVzb2x2ZWQgPSBmYWxzZTtcblx0Y29uc3QgZml4dHVyZVJldHVybiA9IGZpeHR1cmVGbihjb250ZXh0LCBhc3luYyAodXNlRm5BcmcpID0+IHtcblx0XHQvLyBleHRyYWN0IGB1c2VgIGFyZ3VtZW50XG5cdFx0aXNVc2VGbkFyZ1Jlc29sdmVkID0gdHJ1ZTtcblx0XHR1c2VGbkFyZ1Byb21pc2UucmVzb2x2ZSh1c2VGbkFyZyk7XG5cdFx0Ly8gc3VzcGVuZCBmaXh0dXJlIHRlYXJkb3duIGJ5IGhvbGRpbmcgb2ZmIGB1c2VSZXR1cm5Qcm9taXNlYCByZXNvbHV0aW9uIHVudGlsIGNsZWFudXBcblx0XHRjb25zdCB1c2VSZXR1cm5Qcm9taXNlID0gY3JlYXRlRGVmZXIoKTtcblx0XHRjbGVhbnVwRm5BcnJheS5wdXNoKGFzeW5jICgpID0+IHtcblx0XHRcdC8vIHN0YXJ0IHRlYXJkb3duIGJ5IHJlc29sdmluZyBgdXNlYCBQcm9taXNlXG5cdFx0XHR1c2VSZXR1cm5Qcm9taXNlLnJlc29sdmUoKTtcblx0XHRcdC8vIHdhaXQgZm9yIGZpbmlzaGluZyB0ZWFyZG93blxuXHRcdFx0YXdhaXQgZml4dHVyZVJldHVybjtcblx0XHR9KTtcblx0XHRhd2FpdCB1c2VSZXR1cm5Qcm9taXNlO1xuXHR9KS50aGVuKCgpID0+IHtcblx0XHQvLyBmaXh0dXJlIHJldHVybmVkIHdpdGhvdXQgY2FsbGluZyB1c2UoKVxuXHRcdGlmICghaXNVc2VGbkFyZ1Jlc29sdmVkKSB7XG5cdFx0XHRjb25zdCBlcnJvciA9IG5ldyBFcnJvcihgRml4dHVyZSBcIiR7Zml4dHVyZU5hbWV9XCIgcmV0dXJuZWQgd2l0aG91dCBjYWxsaW5nIFwidXNlXCIuIE1ha2Ugc3VyZSB0byBjYWxsIFwidXNlXCIgaW4gZXZlcnkgY29kZSBwYXRoIG9mIHRoZSBmaXh0dXJlIGZ1bmN0aW9uLmApO1xuXHRcdFx0aWYgKHN0YWNrVHJhY2VFcnJvcj8uc3RhY2spIHtcblx0XHRcdFx0ZXJyb3Iuc3RhY2sgPSBlcnJvci5tZXNzYWdlICsgc3RhY2tUcmFjZUVycm9yLnN0YWNrLnJlcGxhY2Uoc3RhY2tUcmFjZUVycm9yLm1lc3NhZ2UsIFwiXCIpO1xuXHRcdFx0fVxuXHRcdFx0dXNlRm5BcmdQcm9taXNlLnJlamVjdChlcnJvcik7XG5cdFx0fVxuXHR9KS5jYXRjaCgoZSkgPT4ge1xuXHRcdC8vIHRyZWF0IGZpeHR1cmUgc2V0dXAgZXJyb3IgYXMgdGVzdCBmYWlsdXJlXG5cdFx0aWYgKCFpc1VzZUZuQXJnUmVzb2x2ZWQpIHtcblx0XHRcdHVzZUZuQXJnUHJvbWlzZS5yZWplY3QoZSk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdC8vIG90aGVyd2lzZSByZS10aHJvdyB0byBhdm9pZCBzaWxlbmNpbmcgZXJyb3IgZHVyaW5nIGNsZWFudXBcblx0XHR0aHJvdyBlO1xuXHR9KTtcblx0cmV0dXJuIHVzZUZuQXJnUHJvbWlzZTtcbn1cbmZ1bmN0aW9uIHJlc29sdmVEZXBzKHVzZWRGaXh0dXJlcywgcmVnaXN0cmF0aW9ucywgZGVwU2V0ID0gbmV3IFNldCgpLCBwZW5kaW5nRml4dHVyZXMgPSBbXSkge1xuXHR1c2VkRml4dHVyZXMuZm9yRWFjaCgoZml4dHVyZSkgPT4ge1xuXHRcdGlmIChwZW5kaW5nRml4dHVyZXMuaW5jbHVkZXMoZml4dHVyZSkpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCFpc0ZpeHR1cmVGdW5jdGlvbihmaXh0dXJlLnZhbHVlKSB8fCAhZml4dHVyZS5kZXBzKSB7XG5cdFx0XHRwZW5kaW5nRml4dHVyZXMucHVzaChmaXh0dXJlKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKGRlcFNldC5oYXMoZml4dHVyZSkpIHtcblx0XHRcdGlmIChmaXh0dXJlLnBhcmVudCkge1xuXHRcdFx0XHRmaXh0dXJlID0gZml4dHVyZS5wYXJlbnQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoYENpcmN1bGFyIGZpeHR1cmUgZGVwZW5kZW5jeSBkZXRlY3RlZDogJHtmaXh0dXJlLm5hbWV9IDwtICR7Wy4uLmRlcFNldF0ucmV2ZXJzZSgpLm1hcCgoZCkgPT4gZC5uYW1lKS5qb2luKFwiIDwtIFwiKX1gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZGVwU2V0LmFkZChmaXh0dXJlKTtcblx0XHRyZXNvbHZlRGVwcyhbLi4uZml4dHVyZS5kZXBzXS5tYXAoKG4pID0+IG4gPT09IGZpeHR1cmUubmFtZSA/IGZpeHR1cmUucGFyZW50IDogcmVnaXN0cmF0aW9ucy5nZXQobikpLmZpbHRlcigobikgPT4gISFuKSwgcmVnaXN0cmF0aW9ucywgZGVwU2V0LCBwZW5kaW5nRml4dHVyZXMpO1xuXHRcdHBlbmRpbmdGaXh0dXJlcy5wdXNoKGZpeHR1cmUpO1xuXHRcdGRlcFNldC5jbGVhcigpO1xuXHR9KTtcblx0cmV0dXJuIHBlbmRpbmdGaXh0dXJlcztcbn1cbmZ1bmN0aW9uIHZhbGlkYXRlU3VpdGVIb29rKGZuLCBob29rLCBzdWl0ZUVycm9yKSB7XG5cdGNvbnN0IHVzZWRQcm9wcyA9IGdldFVzZWRQcm9wcyhmbiwge1xuXHRcdHNvdXJjZUVycm9yOiBzdWl0ZUVycm9yLFxuXHRcdHN1aXRlSG9vazogaG9va1xuXHR9KTtcblx0aWYgKHVzZWRQcm9wcy5zaXplKSB7XG5cdFx0Y29uc3QgZXJyb3IgPSBuZXcgRml4dHVyZUFjY2Vzc0Vycm9yKGBUaGUgJHtob29rfSBob29rIHVzZXMgZml4dHVyZXMgXCIke1suLi51c2VkUHJvcHNdLmpvaW4oXCJcXFwiLCBcXFwiXCIpfVwiLCBidXQgaGFzIG5vIGFjY2VzcyB0byBjb250ZXh0LiBgICsgYERpZCB5b3UgZm9yZ2V0IHRvIGNhbGwgaXQgYXMgXCJ0ZXN0LiR7aG9va30oKVwiIGluc3RlYWQgb2YgXCIke2hvb2t9KClcIj9cXG5gICsgYElmIHlvdSB1c2VkIGludGVybmFsIFwic3VpdGVcIiB0YXNrIGFzIHRoZSBmaXJzdCBhcmd1bWVudCBwcmV2aW91c2x5LCBhY2Nlc3MgaXQgaW4gdGhlIHNlY29uZCBhcmd1bWVudCBpbnN0ZWFkLiBgICsgYFNlZSBodHRwczovL3ZpdGVzdC5kZXYvZ3VpZGUvdGVzdC1jb250ZXh0I3N1aXRlLWxldmVsLWhvb2tzYCk7XG5cdFx0aWYgKHN1aXRlRXJyb3IpIHtcblx0XHRcdGVycm9yLnN0YWNrID0gc3VpdGVFcnJvci5zdGFjaz8ucmVwbGFjZShzdWl0ZUVycm9yLm1lc3NhZ2UsIGVycm9yLm1lc3NhZ2UpO1xuXHRcdH1cblx0XHR0aHJvdyBlcnJvcjtcblx0fVxufVxuY29uc3Qga1Byb3BzU3ltYm9sID0gU3ltYm9sKFwiJHZpdGVzdDpmaXh0dXJlLXByb3BzXCIpO1xuY29uc3Qga1Byb3BOYW1lc1N5bWJvbCA9IFN5bWJvbChcIiR2aXRlc3Q6Zml4dHVyZS1wcm9wLW5hbWVzXCIpO1xuZnVuY3Rpb24gY29uZmlndXJlUHJvcHMoZm4sIG9wdGlvbnMpIHtcblx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGZuLCBrUHJvcHNTeW1ib2wsIHtcblx0XHR2YWx1ZTogb3B0aW9ucyxcblx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHR9KTtcbn1cbmZ1bmN0aW9uIG1lbW9Qcm9wcyhmbiwgcHJvcHMpIHtcblx0Zm5ba1Byb3BOYW1lc1N5bWJvbF0gPSBwcm9wcztcblx0cmV0dXJuIHByb3BzO1xufVxuZnVuY3Rpb24gZ2V0VXNlZFByb3BzKGZuLCB7IHNvdXJjZUVycm9yLCBzdWl0ZUhvb2sgfSA9IHt9KSB7XG5cdGlmIChrUHJvcE5hbWVzU3ltYm9sIGluIGZuKSB7XG5cdFx0cmV0dXJuIGZuW2tQcm9wTmFtZXNTeW1ib2xdO1xuXHR9XG5cdGNvbnN0IHsgaW5kZXg6IGZpeHR1cmVzSW5kZXggPSAwLCBvcmlnaW5hbDogaW1wbGVtZW50YXRpb24gPSBmbiB9ID0ga1Byb3BzU3ltYm9sIGluIGZuID8gZm5ba1Byb3BzU3ltYm9sXSA6IHt9O1xuXHRsZXQgZm5TdHJpbmcgPSBmaWx0ZXJPdXRDb21tZW50cyhpbXBsZW1lbnRhdGlvbi50b1N0cmluZygpKTtcblx0Ly8gbWF0Y2ggbG93ZXJlZCBhc3luYyBmdW5jdGlvbiBhbmQgc3RyaXAgaXQgb2ZmXG5cdC8vIGV4YW1wbGUgY29kZSBvbiBlc2J1aWxkLXRyeSBodHRwczovL2VzYnVpbGQuZ2l0aHViLmlvL3RyeS8jWWdBd0xqSTBMakFBTFMxemRYQndiM0owWldRNllYTjVibU10WVhkaGFYUTlabUZzYzJVQVpRQmxiblJ5ZVM1MGN3QmpiMjV6ZENCdklEMGdld29nSUdZeE9pQmhjM2x1WXlBb0tTQTlQaUI3ZlN3S0lDQm1Nam9nWVhONWJtTWdLR0VwSUQwK0lIdDlMQW9nSUdZek9pQmhjM2x1WXlBb1lTd2dZaWtnUFQ0Z2UzMHNDaUFnWmpRNklHRnplVzVqSUdaMWJtTjBhVzl1S0dFcElIdDlMQW9nSUdZMU9pQmhjM2x1WXlCbWRXNWpkR2x2YmlCbVppaGhLU0I3ZlN3S0lDQmhjM2x1WXlCbU5paGhLU0I3ZlN3S0NpQWdaekU2SUdGemVXNWpJQ2dwSUQwK0lIdDlMQW9nSUdjeU9pQmhjM2x1WXlBb2V5QmhJSDBwSUQwK0lIdDlMQW9nSUdjek9pQmhjM2x1WXlBb2V5QmhJSDBzSUdJcElEMCtJSHQ5TEFvZ0lHYzBPaUJoYzNsdVl5Qm1kVzVqZEdsdmJpQW9leUJoSUgwcElIdDlMQW9nSUdjMU9pQmhjM2x1WXlCbWRXNWpkR2x2YmlCblp5aDdJR0VnZlNrZ2UzMHNDaUFnWVhONWJtTWdaellvZXlCaElIMHBJSHQ5TEFvS0lDQm9NVG9nWVhONWJtTWdLQ2tnUFQ0Z2UzMHNDaUFnTHk4Z1kyOXRiV1Z1ZENCaVpYUjNaV1Z1Q2lBZ2FESTZJR0Z6ZVc1aklDaGhLU0E5UGlCN2ZTd0tmUVxuXHQvLyAgIF9fYXN5bmModGhpcywgbnVsbCwgZnVuY3Rpb24qXG5cdC8vICAgX19hc3luYyh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uKlxuXHQvLyAgIF9fYXN5bmModGhpcywgW18wLCBfMV0sIGZ1bmN0aW9uKlxuXHRpZiAoL19fYXN5bmNcXCgoPzp0aGlzfG51bGwpLCAoPzpudWxsfGFyZ3VtZW50c3xcXFtbXzAtOSwgXSpcXF0pLCBmdW5jdGlvblxcKi8udGVzdChmblN0cmluZykpIHtcblx0XHRmblN0cmluZyA9IGZuU3RyaW5nLnNwbGl0KC9fX2FzeW5jXFwoKD86dGhpc3xudWxsKSwvKVsxXTtcblx0fVxuXHRjb25zdCBtYXRjaCA9IGZuU3RyaW5nLm1hdGNoKC9bXihdKlxcKChbXildKikvKTtcblx0aWYgKCFtYXRjaCkge1xuXHRcdHJldHVybiBtZW1vUHJvcHMoZm4sIG5ldyBTZXQoKSk7XG5cdH1cblx0Y29uc3QgYXJncyA9IHNwbGl0QnlDb21tYShtYXRjaFsxXSk7XG5cdGlmICghYXJncy5sZW5ndGgpIHtcblx0XHRyZXR1cm4gbWVtb1Byb3BzKGZuLCBuZXcgU2V0KCkpO1xuXHR9XG5cdGNvbnN0IGZpeHR1cmVzQXJndW1lbnQgPSBhcmdzW2ZpeHR1cmVzSW5kZXhdO1xuXHRpZiAoIWZpeHR1cmVzQXJndW1lbnQpIHtcblx0XHRyZXR1cm4gbWVtb1Byb3BzKGZuLCBuZXcgU2V0KCkpO1xuXHR9XG5cdGlmICghKGZpeHR1cmVzQXJndW1lbnRbMF0gPT09IFwie1wiICYmIGZpeHR1cmVzQXJndW1lbnQuZW5kc1dpdGgoXCJ9XCIpKSkge1xuXHRcdGNvbnN0IG9yZGluYWxBcmd1bWVudCA9IG9yZGluYWwoZml4dHVyZXNJbmRleCArIDEpO1xuXHRcdGNvbnN0IGVycm9yID0gbmV3IEZpeHR1cmVQYXJzZUVycm9yKGBUaGUgJHtvcmRpbmFsQXJndW1lbnR9IGFyZ3VtZW50IGluc2lkZSBhIGZpeHR1cmUgbXVzdCB1c2Ugb2JqZWN0IGRlc3RydWN0dXJpbmcgcGF0dGVybiwgZS5nLiAoeyB0YXNrIH0gPT4ge30pLiBgICsgYEluc3RlYWQsIHJlY2VpdmVkIFwiJHtmaXh0dXJlc0FyZ3VtZW50fVwiLmAgKyBgJHtzdWl0ZUhvb2sgPyBgIElmIHlvdSB1c2VkIGludGVybmFsIFwic3VpdGVcIiB0YXNrIGFzIHRoZSAke29yZGluYWxBcmd1bWVudH0gYXJndW1lbnQgcHJldmlvdXNseSwgYWNjZXNzIGl0IGluIHRoZSAke29yZGluYWwoZml4dHVyZXNJbmRleCArIDIpfSBhcmd1bWVudCBpbnN0ZWFkLmAgOiBcIlwifWApO1xuXHRcdGlmIChzb3VyY2VFcnJvcikge1xuXHRcdFx0ZXJyb3Iuc3RhY2sgPSBzb3VyY2VFcnJvci5zdGFjaz8ucmVwbGFjZShzb3VyY2VFcnJvci5tZXNzYWdlLCBlcnJvci5tZXNzYWdlKTtcblx0XHR9XG5cdFx0dGhyb3cgZXJyb3I7XG5cdH1cblx0Y29uc3QgX2ZpcnN0ID0gZml4dHVyZXNBcmd1bWVudC5zbGljZSgxLCAtMSkucmVwbGFjZSgvXFxzL2csIFwiXCIpO1xuXHRjb25zdCBwcm9wcyA9IHNwbGl0QnlDb21tYShfZmlyc3QpLm1hcCgocHJvcCkgPT4ge1xuXHRcdHJldHVybiBwcm9wLnJlcGxhY2UoLzouKnw9LiovZywgXCJcIik7XG5cdH0pO1xuXHRjb25zdCBsYXN0ID0gcHJvcHMuYXQoLTEpO1xuXHRpZiAobGFzdCAmJiBsYXN0LnN0YXJ0c1dpdGgoXCIuLi5cIikpIHtcblx0XHRjb25zdCBlcnJvciA9IG5ldyBGaXh0dXJlUGFyc2VFcnJvcihgUmVzdCBwYXJhbWV0ZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGluIGZpeHR1cmVzLCByZWNlaXZlZCBcIiR7bGFzdH1cIi5gKTtcblx0XHRpZiAoc291cmNlRXJyb3IpIHtcblx0XHRcdGVycm9yLnN0YWNrID0gc291cmNlRXJyb3Iuc3RhY2s/LnJlcGxhY2Uoc291cmNlRXJyb3IubWVzc2FnZSwgZXJyb3IubWVzc2FnZSk7XG5cdFx0fVxuXHRcdHRocm93IGVycm9yO1xuXHR9XG5cdHJldHVybiBtZW1vUHJvcHMoZm4sIG5ldyBTZXQocHJvcHMpKTtcbn1cbmZ1bmN0aW9uIHNwbGl0QnlDb21tYShzKSB7XG5cdGNvbnN0IHJlc3VsdCA9IFtdO1xuXHRjb25zdCBzdGFjayA9IFtdO1xuXHRsZXQgc3RhcnQgPSAwO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IHMubGVuZ3RoOyBpKyspIHtcblx0XHRpZiAoc1tpXSA9PT0gXCJ7XCIgfHwgc1tpXSA9PT0gXCJbXCIpIHtcblx0XHRcdHN0YWNrLnB1c2goc1tpXSA9PT0gXCJ7XCIgPyBcIn1cIiA6IFwiXVwiKTtcblx0XHR9IGVsc2UgaWYgKHNbaV0gPT09IHN0YWNrLmF0KC0xKSkge1xuXHRcdFx0c3RhY2sucG9wKCk7XG5cdFx0fSBlbHNlIGlmICghc3RhY2subGVuZ3RoICYmIHNbaV0gPT09IFwiLFwiKSB7XG5cdFx0XHRjb25zdCB0b2tlbiA9IHMuc3Vic3RyaW5nKHN0YXJ0LCBpKS50cmltKCk7XG5cdFx0XHRpZiAodG9rZW4pIHtcblx0XHRcdFx0cmVzdWx0LnB1c2godG9rZW4pO1xuXHRcdFx0fVxuXHRcdFx0c3RhcnQgPSBpICsgMTtcblx0XHR9XG5cdH1cblx0Y29uc3QgbGFzdFRva2VuID0gcy5zdWJzdHJpbmcoc3RhcnQpLnRyaW0oKTtcblx0aWYgKGxhc3RUb2tlbikge1xuXHRcdHJlc3VsdC5wdXNoKGxhc3RUb2tlbik7XG5cdH1cblx0cmV0dXJuIHJlc3VsdDtcbn1cblxubGV0IF90ZXN0O1xuZnVuY3Rpb24gc2V0Q3VycmVudFRlc3QodGVzdCkge1xuXHRfdGVzdCA9IHRlc3Q7XG59XG5mdW5jdGlvbiBnZXRDdXJyZW50VGVzdCgpIHtcblx0cmV0dXJuIF90ZXN0O1xufVxuY29uc3QgdGVzdHMgPSBbXTtcbmZ1bmN0aW9uIGFkZFJ1bm5pbmdUZXN0KHRlc3QpIHtcblx0dGVzdHMucHVzaCh0ZXN0KTtcblx0cmV0dXJuICgpID0+IHtcblx0XHR0ZXN0cy5zcGxpY2UodGVzdHMuaW5kZXhPZih0ZXN0KSk7XG5cdH07XG59XG5mdW5jdGlvbiBnZXRSdW5uaW5nVGVzdHMoKSB7XG5cdHJldHVybiB0ZXN0cztcbn1cblxuY29uc3Qga0NoYWluYWJsZUNvbnRleHQgPSBTeW1ib2woXCJrQ2hhaW5hYmxlQ29udGV4dFwiKTtcbmZ1bmN0aW9uIGdldENoYWluYWJsZUNvbnRleHQoY2hhaW5hYmxlKSB7XG5cdHJldHVybiBjaGFpbmFibGU/LltrQ2hhaW5hYmxlQ29udGV4dF07XG59XG5mdW5jdGlvbiBjcmVhdGVDaGFpbmFibGUoa2V5cywgZm4sIGNvbnRleHQpIHtcblx0ZnVuY3Rpb24gY3JlYXRlKGNvbnRleHQpIHtcblx0XHRjb25zdCBjaGFpbiA9IGZ1bmN0aW9uKC4uLmFyZ3MpIHtcblx0XHRcdHJldHVybiBmbi5hcHBseShjb250ZXh0LCBhcmdzKTtcblx0XHR9O1xuXHRcdE9iamVjdC5hc3NpZ24oY2hhaW4sIGZuKTtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoY2hhaW4sIGtDaGFpbmFibGVDb250ZXh0LCB7XG5cdFx0XHR2YWx1ZToge1xuXHRcdFx0XHR3aXRoQ29udGV4dDogKCkgPT4gY2hhaW4uYmluZChjb250ZXh0KSxcblx0XHRcdFx0Z2V0Rml4dHVyZXM6ICgpID0+IGNvbnRleHQuZml4dHVyZXMsXG5cdFx0XHRcdHNldENvbnRleHQ6IChrZXksIHZhbHVlKSA9PiB7XG5cdFx0XHRcdFx0Y29udGV4dFtrZXldID0gdmFsdWU7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdG1lcmdlQ29udGV4dDogKGN0eCkgPT4ge1xuXHRcdFx0XHRcdE9iamVjdC5hc3NpZ24oY29udGV4dCwgY3R4KTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGVudW1lcmFibGU6IGZhbHNlXG5cdFx0fSk7XG5cdFx0Zm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGNoYWluLCBrZXksIHsgZ2V0KCkge1xuXHRcdFx0XHRyZXR1cm4gY3JlYXRlKHtcblx0XHRcdFx0XHQuLi5jb250ZXh0LFxuXHRcdFx0XHRcdFtrZXldOiB0cnVlXG5cdFx0XHRcdH0pO1xuXHRcdFx0fSB9KTtcblx0XHR9XG5cdFx0cmV0dXJuIGNoYWluO1xuXHR9XG5cdGNvbnN0IGNoYWluID0gY3JlYXRlKGNvbnRleHQgPz8ge30pO1xuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoY2hhaW4sIFwiZm5cIiwge1xuXHRcdHZhbHVlOiBmbixcblx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHR9KTtcblx0cmV0dXJuIGNoYWluO1xufVxuXG5mdW5jdGlvbiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSB7XG5cdHJldHVybiBnZXRSdW5uZXIoKS5jb25maWcuaG9va1RpbWVvdXQ7XG59XG5jb25zdCBDTEVBTlVQX1RJTUVPVVRfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9DTEVBTlVQX1RJTUVPVVRcIik7XG5jb25zdCBDTEVBTlVQX1NUQUNLX1RSQUNFX0tFWSA9IFN5bWJvbC5mb3IoXCJWSVRFU1RfQ0xFQU5VUF9TVEFDS19UUkFDRVwiKTtcbmNvbnN0IEFST1VORF9USU1FT1VUX0tFWSA9IFN5bWJvbC5mb3IoXCJWSVRFU1RfQVJPVU5EX1RJTUVPVVRcIik7XG5jb25zdCBBUk9VTkRfU1RBQ0tfVFJBQ0VfS0VZID0gU3ltYm9sLmZvcihcIlZJVEVTVF9BUk9VTkRfU1RBQ0tfVFJBQ0VcIik7XG5mdW5jdGlvbiBnZXRCZWZvcmVIb29rQ2xlYW51cENhbGxiYWNrKGhvb2ssIHJlc3VsdCwgY29udGV4dCkge1xuXHRpZiAodHlwZW9mIHJlc3VsdCA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0Y29uc3QgdGltZW91dCA9IENMRUFOVVBfVElNRU9VVF9LRVkgaW4gaG9vayAmJiB0eXBlb2YgaG9va1tDTEVBTlVQX1RJTUVPVVRfS0VZXSA9PT0gXCJudW1iZXJcIiA/IGhvb2tbQ0xFQU5VUF9USU1FT1VUX0tFWV0gOiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBDTEVBTlVQX1NUQUNLX1RSQUNFX0tFWSBpbiBob29rICYmIGhvb2tbQ0xFQU5VUF9TVEFDS19UUkFDRV9LRVldIGluc3RhbmNlb2YgRXJyb3IgPyBob29rW0NMRUFOVVBfU1RBQ0tfVFJBQ0VfS0VZXSA6IHVuZGVmaW5lZDtcblx0XHRyZXR1cm4gd2l0aFRpbWVvdXQocmVzdWx0LCB0aW1lb3V0LCB0cnVlLCBzdGFja1RyYWNlRXJyb3IsIChfLCBlcnJvcikgPT4ge1xuXHRcdFx0aWYgKGNvbnRleHQpIHtcblx0XHRcdFx0YWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fVxufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIG9uY2UgYmVmb3JlIGFsbCB0ZXN0cyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUuXG4qIFRoaXMgaG9vayBpcyB1c2VmdWwgZm9yIHNjZW5hcmlvcyB3aGVyZSB5b3UgbmVlZCB0byBwZXJmb3JtIHNldHVwIG9wZXJhdGlvbnMgdGhhdCBhcmUgY29tbW9uIHRvIGFsbCB0ZXN0cyBpbiBhIHN1aXRlLCBzdWNoIGFzIGluaXRpYWxpemluZyBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gb3Igc2V0dGluZyB1cCBhIHRlc3QgZW52aXJvbm1lbnQuXG4qXG4qICoqTm90ZToqKiBUaGUgYGJlZm9yZUFsbGAgaG9va3MgYXJlIGV4ZWN1dGVkIGluIHRoZSBvcmRlciB0aGV5IGFyZSBkZWZpbmVkIG9uZSBhZnRlciBhbm90aGVyLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBhbGwgdGVzdHMuXG4qIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dF0gLSBPcHRpb25hbCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIGhvb2suIElmIG5vdCBwcm92aWRlZCwgdGhlIGRlZmF1bHQgaG9vayB0aW1lb3V0IGZyb20gdGhlIHJ1bm5lcidzIGNvbmZpZ3VyYXRpb24gaXMgdXNlZC5cbiogQHJldHVybnMge3ZvaWR9XG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgYmVmb3JlQWxsIHRvIHNldCB1cCBhIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiogYmVmb3JlQWxsKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYXRhYmFzZS5jb25uZWN0KCk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBiZWZvcmVBbGwoZm4sIHRpbWVvdXQgPSBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSkge1xuXHRhc3NlcnRUeXBlcyhmbiwgXCJcXFwiYmVmb3JlQWxsXFxcIiBjYWxsYmFja1wiLCBbXCJmdW5jdGlvblwiXSk7XG5cdGNvbnN0IHN0YWNrVHJhY2VFcnJvciA9IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpO1xuXHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0cmV0dXJuIGdldEN1cnJlbnRTdWl0ZSgpLm9uKFwiYmVmb3JlQWxsXCIsIE9iamVjdC5hc3NpZ24od2l0aFRpbWVvdXQod2l0aFN1aXRlRml4dHVyZXMoXCJiZWZvcmVBbGxcIiwgZm4sIGNvbnRleHQsIHN0YWNrVHJhY2VFcnJvciksIHRpbWVvdXQsIHRydWUsIHN0YWNrVHJhY2VFcnJvciksIHtcblx0XHRbQ0xFQU5VUF9USU1FT1VUX0tFWV06IHRpbWVvdXQsXG5cdFx0W0NMRUFOVVBfU1RBQ0tfVFJBQ0VfS0VZXTogc3RhY2tUcmFjZUVycm9yXG5cdH0pKTtcbn1cbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBvbmNlIGFmdGVyIGFsbCB0ZXN0cyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUgaGF2ZSBjb21wbGV0ZWQuXG4qIFRoaXMgaG9vayBpcyB1c2VmdWwgZm9yIHNjZW5hcmlvcyB3aGVyZSB5b3UgbmVlZCB0byBwZXJmb3JtIGNsZWFudXAgb3BlcmF0aW9ucyBhZnRlciBhbGwgdGVzdHMgaW4gYSBzdWl0ZSBoYXZlIHJ1biwgc3VjaCBhcyBjbG9zaW5nIGRhdGFiYXNlIGNvbm5lY3Rpb25zIG9yIGNsZWFuaW5nIHVwIHRlbXBvcmFyeSBmaWxlcy5cbipcbiogKipOb3RlOioqIFRoZSBgYWZ0ZXJBbGxgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGFsbCB0ZXN0cy5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhZnRlckFsbCB0byBjbG9zZSBhIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiogYWZ0ZXJBbGwoYXN5bmMgKCkgPT4ge1xuKiAgIGF3YWl0IGRhdGFiYXNlLmRpc2Nvbm5lY3QoKTtcbiogfSk7XG4qIGBgYFxuKi9cbmZ1bmN0aW9uIGFmdGVyQWxsKGZuLCB0aW1lb3V0KSB7XG5cdGFzc2VydFR5cGVzKGZuLCBcIlxcXCJhZnRlckFsbFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0Y29uc3Qgc3RhY2tUcmFjZUVycm9yID0gbmV3IEVycm9yKFwiU1RBQ0tfVFJBQ0VfRVJST1JcIik7XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFmdGVyQWxsXCIsIHdpdGhUaW1lb3V0KHdpdGhTdWl0ZUZpeHR1cmVzKFwiYWZ0ZXJBbGxcIiwgZm4sIGNvbnRleHQsIHN0YWNrVHJhY2VFcnJvciksIHRpbWVvdXQgPz8gZ2V0RGVmYXVsdEhvb2tUaW1lb3V0KCksIHRydWUsIHN0YWNrVHJhY2VFcnJvcikpO1xufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBlYWNoIHRlc3Qgd2l0aGluIHRoZSBjdXJyZW50IHN1aXRlLlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gcmVzZXQgb3IgcmVpbml0aWFsaXplIHRoZSB0ZXN0IGVudmlyb25tZW50IGJlZm9yZSBlYWNoIHRlc3QgcnVucywgc3VjaCBhcyByZXNldHRpbmcgZGF0YWJhc2Ugc3RhdGVzLCBjbGVhcmluZyBjYWNoZXMsIG9yIHJlaW5pdGlhbGl6aW5nIHZhcmlhYmxlcy5cbipcbiogKipOb3RlOioqIFRoZSBgYmVmb3JlRWFjaGAgaG9va3MgYXJlIGV4ZWN1dGVkIGluIHRoZSBvcmRlciB0aGV5IGFyZSBkZWZpbmVkIG9uZSBhZnRlciBhbm90aGVyLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGJlZm9yZSBlYWNoIHRlc3QuIFRoaXMgZnVuY3Rpb24gcmVjZWl2ZXMgYW4gYFRlc3RDb250ZXh0YCBwYXJhbWV0ZXIgaWYgYWRkaXRpb25hbCB0ZXN0IGNvbnRleHQgaXMgbmVlZGVkLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEByZXR1cm5zIHt2b2lkfVxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGJlZm9yZUVhY2ggdG8gcmVzZXQgYSBkYXRhYmFzZSBzdGF0ZVxuKiBiZWZvcmVFYWNoKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYXRhYmFzZS5yZXNldCgpO1xuKiB9KTtcbiogYGBgXG4qL1xuZnVuY3Rpb24gYmVmb3JlRWFjaChmbiwgdGltZW91dCA9IGdldERlZmF1bHRIb29rVGltZW91dCgpKSB7XG5cdGFzc2VydFR5cGVzKGZuLCBcIlxcXCJiZWZvcmVFYWNoXFxcIiBjYWxsYmFja1wiLCBbXCJmdW5jdGlvblwiXSk7XG5cdGNvbnN0IHN0YWNrVHJhY2VFcnJvciA9IG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpO1xuXHRjb25zdCB3cmFwcGVyID0gKGNvbnRleHQsIHN1aXRlKSA9PiB7XG5cdFx0Y29uc3QgZml4dHVyZVJlc29sdmVyID0gd2l0aEZpeHR1cmVzKGZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImJlZm9yZUVhY2hcIiwgT2JqZWN0LmFzc2lnbih3aXRoVGltZW91dCh3cmFwcGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBzdGFja1RyYWNlRXJyb3IsIGFib3J0SWZUaW1lb3V0KSwge1xuXHRcdFtDTEVBTlVQX1RJTUVPVVRfS0VZXTogdGltZW91dCxcblx0XHRbQ0xFQU5VUF9TVEFDS19UUkFDRV9LRVldOiBzdGFja1RyYWNlRXJyb3Jcblx0fSkpO1xufVxuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGVhY2ggdGVzdCB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUgaGFzIGNvbXBsZXRlZC5cbiogVGhpcyBob29rIGlzIHVzZWZ1bCBmb3Igc2NlbmFyaW9zIHdoZXJlIHlvdSBuZWVkIHRvIGNsZWFuIHVwIG9yIHJlc2V0IHRoZSB0ZXN0IGVudmlyb25tZW50IGFmdGVyIGVhY2ggdGVzdCBydW5zLCBzdWNoIGFzIGRlbGV0aW5nIHRlbXBvcmFyeSBmaWxlcywgY2xlYXJpbmcgdGVzdC1zcGVjaWZpYyBkYXRhYmFzZSBlbnRyaWVzLCBvciByZXNldHRpbmcgbW9ja2VkIGZ1bmN0aW9ucy5cbipcbiogKipOb3RlOioqIFRoZSBgYWZ0ZXJFYWNoYCBob29rcyBhcmUgcnVubmluZyBpbiByZXZlcnNlIG9yZGVyIG9mIHRoZWlyIHJlZ2lzdHJhdGlvbi4gWW91IGNhbiBjb25maWd1cmUgdGhpcyBieSBjaGFuZ2luZyB0aGUgYHNlcXVlbmNlLmhvb2tzYCBvcHRpb24gaW4gdGhlIGNvbmZpZyBmaWxlLlxuKlxuKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBhZnRlciBlYWNoIHRlc3QuIFRoaXMgZnVuY3Rpb24gcmVjZWl2ZXMgYW4gYFRlc3RDb250ZXh0YCBwYXJhbWV0ZXIgaWYgYWRkaXRpb25hbCB0ZXN0IGNvbnRleHQgaXMgbmVlZGVkLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEByZXR1cm5zIHt2b2lkfVxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGFmdGVyRWFjaCB0byBkZWxldGUgdGVtcG9yYXJ5IGZpbGVzIGNyZWF0ZWQgZHVyaW5nIGEgdGVzdFxuKiBhZnRlckVhY2goYXN5bmMgKCkgPT4ge1xuKiAgIGF3YWl0IGZpbGVTeXN0ZW0uZGVsZXRlVGVtcEZpbGVzKCk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBhZnRlckVhY2goZm4sIHRpbWVvdXQpIHtcblx0YXNzZXJ0VHlwZXMoZm4sIFwiXFxcImFmdGVyRWFjaFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCB3cmFwcGVyID0gKGNvbnRleHQsIHN1aXRlKSA9PiB7XG5cdFx0Y29uc3QgZml4dHVyZVJlc29sdmVyID0gd2l0aEZpeHR1cmVzKGZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFmdGVyRWFjaFwiLCB3aXRoVGltZW91dCh3cmFwcGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKSwgYWJvcnRJZlRpbWVvdXQpKTtcbn1cbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCB3aGVuIGEgdGVzdCBmYWlscyB3aXRoaW4gdGhlIGN1cnJlbnQgc3VpdGUuXG4qIFRoaXMgZnVuY3Rpb24gYWxsb3dzIGZvciBjdXN0b20gYWN0aW9ucyB0byBiZSBwZXJmb3JtZWQgaW4gcmVzcG9uc2UgdG8gdGVzdCBmYWlsdXJlcywgc3VjaCBhcyBsb2dnaW5nLCBjbGVhbnVwLCBvciBhZGRpdGlvbmFsIGRpYWdub3N0aWNzLlxuKlxuKiAqKk5vdGU6KiogVGhlIGBvblRlc3RGYWlsZWRgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIHVwb24gYSB0ZXN0IGZhaWx1cmUuIFRoZSBmdW5jdGlvbiByZWNlaXZlcyB0aGUgdGVzdCByZXN1bHQgKGluY2x1ZGluZyBlcnJvcnMpLlxuKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRdIC0gT3B0aW9uYWwgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBob29rLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWZhdWx0IGhvb2sgdGltZW91dCBmcm9tIHRoZSBydW5uZXIncyBjb25maWd1cmF0aW9uIGlzIHVzZWQuXG4qIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGZ1bmN0aW9uIGlzIG5vdCBjYWxsZWQgd2l0aGluIGEgdGVzdC5cbiogQHJldHVybnMge3ZvaWR9XG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgb25UZXN0RmFpbGVkIHRvIGxvZyBmYWlsdXJlIGRldGFpbHNcbiogb25UZXN0RmFpbGVkKCh7IGVycm9ycyB9KSA9PiB7XG4qICAgY29uc29sZS5sb2coYFRlc3QgZmFpbGVkOiAke3Rlc3QubmFtZX1gLCBlcnJvcnMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3Qgb25UZXN0RmFpbGVkID0gY3JlYXRlVGVzdEhvb2soXCJvblRlc3RGYWlsZWRcIiwgKHRlc3QsIGhhbmRsZXIsIHRpbWVvdXQpID0+IHtcblx0dGVzdC5vbkZhaWxlZCB8fD0gW107XG5cdHRlc3Qub25GYWlsZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IGdldERlZmF1bHRIb29rVGltZW91dCgpLCB0cnVlLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKSwgYWJvcnRJZlRpbWVvdXQpKTtcbn0pO1xuLyoqXG4qIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIGN1cnJlbnQgdGVzdCBmaW5pc2hlcywgcmVnYXJkbGVzcyBvZiB0aGUgb3V0Y29tZSAocGFzcyBvciBmYWlsKS5cbiogVGhpcyBmdW5jdGlvbiBpcyBpZGVhbCBmb3IgcGVyZm9ybWluZyBhY3Rpb25zIHRoYXQgc2hvdWxkIG9jY3VyIGFmdGVyIGV2ZXJ5IHRlc3QgZXhlY3V0aW9uLCBzdWNoIGFzIGNsZWFudXAsIGxvZ2dpbmcsIG9yIHJlc2V0dGluZyBzaGFyZWQgcmVzb3VyY2VzLlxuKlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGlmIHlvdSBoYXZlIGFjY2VzcyB0byBhIHJlc291cmNlIGluIHRoZSB0ZXN0IGl0c2VsZiBhbmQgeW91IHdhbnQgdG8gY2xlYW4gaXQgdXAgYWZ0ZXIgdGhlIHRlc3QgZmluaXNoZXMuIEl0IGlzIGEgbW9yZSBjb21wYWN0IHdheSB0byBjbGVhbiB1cCByZXNvdXJjZXMgdGhhbiB1c2luZyB0aGUgY29tYmluYXRpb24gb2YgYGJlZm9yZUVhY2hgIGFuZCBgYWZ0ZXJFYWNoYC5cbipcbiogKipOb3RlOioqIFRoZSBgb25UZXN0RmluaXNoZWRgIGhvb2tzIGFyZSBydW5uaW5nIGluIHJldmVyc2Ugb3JkZXIgb2YgdGhlaXIgcmVnaXN0cmF0aW9uLiBZb3UgY2FuIGNvbmZpZ3VyZSB0aGlzIGJ5IGNoYW5naW5nIHRoZSBgc2VxdWVuY2UuaG9va3NgIG9wdGlvbiBpbiB0aGUgY29uZmlnIGZpbGUuXG4qXG4qICoqTm90ZToqKiBUaGUgYG9uVGVzdEZpbmlzaGVkYCBob29rIGlzIG5vdCBjYWxsZWQgaWYgdGhlIHRlc3QgaXMgY2FuY2VsZWQgd2l0aCBhIGR5bmFtaWMgYGN0eC5za2lwKClgIGNhbGwuXG4qXG4qIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIGFmdGVyIGEgdGVzdCBmaW5pc2hlcy4gVGhlIGZ1bmN0aW9uIGNhbiByZWNlaXZlIHBhcmFtZXRlcnMgcHJvdmlkaW5nIGRldGFpbHMgYWJvdXQgdGhlIGNvbXBsZXRlZCB0ZXN0LCBpbmNsdWRpbmcgaXRzIHN1Y2Nlc3Mgb3IgZmFpbHVyZSBzdGF0dXMuXG4qIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dF0gLSBPcHRpb25hbCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIGhvb2suIElmIG5vdCBwcm92aWRlZCwgdGhlIGRlZmF1bHQgaG9vayB0aW1lb3V0IGZyb20gdGhlIHJ1bm5lcidzIGNvbmZpZ3VyYXRpb24gaXMgdXNlZC5cbiogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgZnVuY3Rpb24gaXMgbm90IGNhbGxlZCB3aXRoaW4gYSB0ZXN0LlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBvblRlc3RGaW5pc2hlZCBmb3IgY2xlYW51cFxuKiBjb25zdCBkYiA9IGF3YWl0IGNvbm5lY3RUb0RhdGFiYXNlKCk7XG4qIG9uVGVzdEZpbmlzaGVkKGFzeW5jICgpID0+IHtcbiogICBhd2FpdCBkYi5kaXNjb25uZWN0KCk7XG4qIH0pO1xuKiBgYGBcbiovXG5jb25zdCBvblRlc3RGaW5pc2hlZCA9IGNyZWF0ZVRlc3RIb29rKFwib25UZXN0RmluaXNoZWRcIiwgKHRlc3QsIGhhbmRsZXIsIHRpbWVvdXQpID0+IHtcblx0dGVzdC5vbkZpbmlzaGVkIHx8PSBbXTtcblx0dGVzdC5vbkZpbmlzaGVkLnB1c2god2l0aFRpbWVvdXQoaGFuZGxlciwgdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKSwgdHJ1ZSwgbmV3IEVycm9yKFwiU1RBQ0tfVFJBQ0VfRVJST1JcIiksIGFib3J0SWZUaW1lb3V0KSk7XG59KTtcbi8qKlxuKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0aGF0IHdyYXBzIGFyb3VuZCBhbGwgdGVzdHMgd2l0aGluIHRoZSBjdXJyZW50IHN1aXRlLlxuKiBUaGUgY2FsbGJhY2sgcmVjZWl2ZXMgYSBgcnVuU3VpdGVgIGZ1bmN0aW9uIHRoYXQgbXVzdCBiZSBjYWxsZWQgdG8gcnVuIHRoZSBzdWl0ZSdzIHRlc3RzLlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gd3JhcCBhbiBlbnRpcmUgc3VpdGUgaW4gYSBjb250ZXh0XG4qIChlLmcuLCBzdGFydGluZyBhIHNlcnZlciwgb3BlbmluZyBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gdGhhdCBhbGwgdGVzdHMgc2hhcmUpLlxuKlxuKiAqKk5vdGU6KiogV2hlbiBtdWx0aXBsZSBgYXJvdW5kQWxsYCBob29rcyBhcmUgcmVnaXN0ZXJlZCwgdGhleSBhcmUgbmVzdGVkIGluc2lkZSBlYWNoIG90aGVyLlxuKiBUaGUgZmlyc3QgcmVnaXN0ZXJlZCBob29rIGlzIHRoZSBvdXRlcm1vc3Qgd3JhcHBlci5cbipcbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyB0aGUgc3VpdGUuIE11c3QgY2FsbCBgcnVuU3VpdGUoKWAgdG8gcnVuIHRoZSB0ZXN0cy5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhcm91bmRBbGwgdG8gd3JhcCBzdWl0ZSBpbiBhIHRyYWNpbmcgc3BhblxuKiBhcm91bmRBbGwoYXN5bmMgKHJ1blN1aXRlKSA9PiB7XG4qICAgYXdhaXQgdHJhY2VyLnRyYWNlKCd0ZXN0LXN1aXRlJywgcnVuU3VpdGUpO1xuKiB9KTtcbiogYGBgXG4qIEBleGFtcGxlXG4qIGBgYHRzXG4qIC8vIEV4YW1wbGUgb2YgdXNpbmcgYXJvdW5kQWxsIHdpdGggZml4dHVyZXNcbiogYXJvdW5kQWxsKGFzeW5jIChydW5TdWl0ZSwgeyBkYiB9KSA9PiB7XG4qICAgYXdhaXQgZGIudHJhbnNhY3Rpb24oKCkgPT4gcnVuU3VpdGUoKSk7XG4qIH0pO1xuKiBgYGBcbiovXG5mdW5jdGlvbiBhcm91bmRBbGwoZm4sIHRpbWVvdXQpIHtcblx0YXNzZXJ0VHlwZXMoZm4sIFwiXFxcImFyb3VuZEFsbFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0Y29uc3QgcmVzb2x2ZWRUaW1lb3V0ID0gdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFyb3VuZEFsbFwiLCBPYmplY3QuYXNzaWduKHdpdGhTdWl0ZUZpeHR1cmVzKFwiYXJvdW5kQWxsXCIsIGZuLCBjb250ZXh0LCBzdGFja1RyYWNlRXJyb3IsIDEpLCB7XG5cdFx0W0FST1VORF9USU1FT1VUX0tFWV06IHJlc29sdmVkVGltZW91dCxcblx0XHRbQVJPVU5EX1NUQUNLX1RSQUNFX0tFWV06IHN0YWNrVHJhY2VFcnJvclxuXHR9KSk7XG59XG4vKipcbiogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyBhcm91bmQgZWFjaCB0ZXN0IHdpdGhpbiB0aGUgY3VycmVudCBzdWl0ZS5cbiogVGhlIGNhbGxiYWNrIHJlY2VpdmVzIGEgYHJ1blRlc3RgIGZ1bmN0aW9uIHRoYXQgbXVzdCBiZSBjYWxsZWQgdG8gcnVuIHRoZSB0ZXN0LlxuKiBUaGlzIGhvb2sgaXMgdXNlZnVsIGZvciBzY2VuYXJpb3Mgd2hlcmUgeW91IG5lZWQgdG8gd3JhcCB0ZXN0cyBpbiBhIGNvbnRleHQgKGUuZy4sIGRhdGFiYXNlIHRyYW5zYWN0aW9ucykuXG4qXG4qICoqTm90ZToqKiBXaGVuIG11bHRpcGxlIGBhcm91bmRFYWNoYCBob29rcyBhcmUgcmVnaXN0ZXJlZCwgdGhleSBhcmUgbmVzdGVkIGluc2lkZSBlYWNoIG90aGVyLlxuKiBUaGUgZmlyc3QgcmVnaXN0ZXJlZCBob29rIGlzIHRoZSBvdXRlcm1vc3Qgd3JhcHBlci5cbipcbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB3cmFwcyB0aGUgdGVzdC4gTXVzdCBjYWxsIGBydW5UZXN0KClgIHRvIHJ1biB0aGUgdGVzdC5cbiogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XSAtIE9wdGlvbmFsIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgaG9vay4gSWYgbm90IHByb3ZpZGVkLCB0aGUgZGVmYXVsdCBob29rIHRpbWVvdXQgZnJvbSB0aGUgcnVubmVyJ3MgY29uZmlndXJhdGlvbiBpcyB1c2VkLlxuKiBAcmV0dXJucyB7dm9pZH1cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRXhhbXBsZSBvZiB1c2luZyBhcm91bmRFYWNoIHRvIHdyYXAgdGVzdHMgaW4gYSBkYXRhYmFzZSB0cmFuc2FjdGlvblxuKiBhcm91bmRFYWNoKGFzeW5jIChydW5UZXN0KSA9PiB7XG4qICAgYXdhaXQgZGF0YWJhc2UudHJhbnNhY3Rpb24oKCkgPT4gcnVuVGVzdCgpKTtcbiogfSk7XG4qIGBgYFxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBFeGFtcGxlIG9mIHVzaW5nIGFyb3VuZEVhY2ggd2l0aCBmaXh0dXJlc1xuKiBhcm91bmRFYWNoKGFzeW5jIChydW5UZXN0LCB7IGRiIH0pID0+IHtcbiogICBhd2FpdCBkYi50cmFuc2FjdGlvbigoKSA9PiBydW5UZXN0KCkpO1xuKiB9KTtcbiogYGBgXG4qL1xuZnVuY3Rpb24gYXJvdW5kRWFjaChmbiwgdGltZW91dCkge1xuXHRhc3NlcnRUeXBlcyhmbiwgXCJcXFwiYXJvdW5kRWFjaFxcXCIgY2FsbGJhY2tcIiwgW1wiZnVuY3Rpb25cIl0pO1xuXHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0Y29uc3QgcmVzb2x2ZWRUaW1lb3V0ID0gdGltZW91dCA/PyBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcblx0Y29uc3Qgd3JhcHBlciA9IChydW5UZXN0LCBjb250ZXh0LCBzdWl0ZSkgPT4ge1xuXHRcdGNvbnN0IGlubmVyRm4gPSAoY3R4KSA9PiBmbihydW5UZXN0LCBjdHgsIHN1aXRlKTtcblx0XHRjb25maWd1cmVQcm9wcyhpbm5lckZuLCB7XG5cdFx0XHRpbmRleDogMSxcblx0XHRcdG9yaWdpbmFsOiBmblxuXHRcdH0pO1xuXHRcdGNvbnN0IGZpeHR1cmVSZXNvbHZlciA9IHdpdGhGaXh0dXJlcyhpbm5lckZuLCB7IHN1aXRlIH0pO1xuXHRcdHJldHVybiBmaXh0dXJlUmVzb2x2ZXIoY29udGV4dCk7XG5cdH07XG5cdHJldHVybiBnZXRDdXJyZW50U3VpdGUoKS5vbihcImFyb3VuZEVhY2hcIiwgT2JqZWN0LmFzc2lnbih3cmFwcGVyLCB7XG5cdFx0W0FST1VORF9USU1FT1VUX0tFWV06IHJlc29sdmVkVGltZW91dCxcblx0XHRbQVJPVU5EX1NUQUNLX1RSQUNFX0tFWV06IHN0YWNrVHJhY2VFcnJvclxuXHR9KSk7XG59XG5mdW5jdGlvbiB3aXRoU3VpdGVGaXh0dXJlcyhzdWl0ZUhvb2ssIGZuLCBjb250ZXh0LCBzdGFja1RyYWNlRXJyb3IsIGNvbnRleHRJbmRleCA9IDApIHtcblx0cmV0dXJuICguLi5hcmdzKSA9PiB7XG5cdFx0Y29uc3Qgc3VpdGUgPSBhcmdzLmF0KC0xKTtcblx0XHRjb25zdCBwcmVmaXggPSBhcmdzLnNsaWNlKDAsIC0xKTtcblx0XHRjb25zdCB3cmFwcGVyID0gKGN0eCkgPT4gZm4oLi4ucHJlZml4LCBjdHgsIHN1aXRlKTtcblx0XHRjb25maWd1cmVQcm9wcyh3cmFwcGVyLCB7XG5cdFx0XHRpbmRleDogY29udGV4dEluZGV4LFxuXHRcdFx0b3JpZ2luYWw6IGZuXG5cdFx0fSk7XG5cdFx0Y29uc3QgZml4dHVyZXMgPSBjb250ZXh0Py5nZXRGaXh0dXJlcygpO1xuXHRcdGNvbnN0IGZpbGVDb250ZXh0ID0gZml4dHVyZXM/LmdldEZpbGVDb250ZXh0KHN1aXRlLmZpbGUpO1xuXHRcdGNvbnN0IGZpeHR1cmVkID0gd2l0aEZpeHR1cmVzKHdyYXBwZXIsIHtcblx0XHRcdHN1aXRlSG9vayxcblx0XHRcdGZpeHR1cmVzLFxuXHRcdFx0Y29udGV4dDogZmlsZUNvbnRleHQsXG5cdFx0XHRzdGFja1RyYWNlRXJyb3Jcblx0XHR9KTtcblx0XHRyZXR1cm4gZml4dHVyZWQoKTtcblx0fTtcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEhvb2tUaW1lb3V0KGhvb2spIHtcblx0cmV0dXJuIEFST1VORF9USU1FT1VUX0tFWSBpbiBob29rICYmIHR5cGVvZiBob29rW0FST1VORF9USU1FT1VUX0tFWV0gPT09IFwibnVtYmVyXCIgPyBob29rW0FST1VORF9USU1FT1VUX0tFWV0gOiBnZXREZWZhdWx0SG9va1RpbWVvdXQoKTtcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEhvb2tTdGFja1RyYWNlKGhvb2spIHtcblx0cmV0dXJuIEFST1VORF9TVEFDS19UUkFDRV9LRVkgaW4gaG9vayAmJiBob29rW0FST1VORF9TVEFDS19UUkFDRV9LRVldIGluc3RhbmNlb2YgRXJyb3IgPyBob29rW0FST1VORF9TVEFDS19UUkFDRV9LRVldIDogdW5kZWZpbmVkO1xufVxuZnVuY3Rpb24gY3JlYXRlVGVzdEhvb2sobmFtZSwgaGFuZGxlcikge1xuXHRyZXR1cm4gKGZuLCB0aW1lb3V0KSA9PiB7XG5cdFx0YXNzZXJ0VHlwZXMoZm4sIGBcIiR7bmFtZX1cIiBjYWxsYmFja2AsIFtcImZ1bmN0aW9uXCJdKTtcblx0XHRjb25zdCBjdXJyZW50ID0gZ2V0Q3VycmVudFRlc3QoKTtcblx0XHRpZiAoIWN1cnJlbnQpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcihgSG9vayAke25hbWV9KCkgY2FuIG9ubHkgYmUgY2FsbGVkIGluc2lkZSBhIHRlc3RgKTtcblx0XHR9XG5cdFx0cmV0dXJuIGhhbmRsZXIoY3VycmVudCwgZm4sIHRpbWVvdXQpO1xuXHR9O1xufVxuXG4vKipcbiogSWYgYW55IHRhc2tzIGJlZW4gbWFya2VkIGFzIGBvbmx5YCwgbWFyayBhbGwgb3RoZXIgdGFza3MgYXMgYHNraXBgLlxuKi9cbmZ1bmN0aW9uIGludGVycHJldFRhc2tNb2RlcyhmaWxlLCBuYW1lUGF0dGVybiwgdGVzdExvY2F0aW9ucywgdGVzdElkcywgdGVzdFRhZ3NGaWx0ZXIsIG9ubHlNb2RlLCBwYXJlbnRJc09ubHksIGFsbG93T25seSkge1xuXHRjb25zdCBtYXRjaGVkTG9jYXRpb25zID0gW107XG5cdGNvbnN0IHRyYXZlcnNlU3VpdGUgPSAoc3VpdGUsIHBhcmVudElzT25seSwgcGFyZW50TWF0Y2hlZFdpdGhMb2NhdGlvbikgPT4ge1xuXHRcdGNvbnN0IHN1aXRlSXNPbmx5ID0gcGFyZW50SXNPbmx5IHx8IHN1aXRlLm1vZGUgPT09IFwib25seVwiO1xuXHRcdC8vIENoZWNrIGlmIGFueSB0YXNrcyBpbiB0aGlzIHN1aXRlIGhhdmUgYC5vbmx5YCAtIGlmIHNvLCBvbmx5IHRob3NlIHNob3VsZCBydW5cblx0XHRjb25zdCBoYXNTb21lVGFza3NPbmx5ID0gb25seU1vZGUgJiYgc3VpdGUudGFza3Muc29tZSgodCkgPT4gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpKTtcblx0XHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0XHQvLyBDaGVjayBpZiBlaXRoZXIgdGhlIHBhcmVudCBzdWl0ZSBvciB0aGUgdGFzayBpdHNlbGYgYXJlIG1hcmtlZCBhcyBpbmNsdWRlZFxuXHRcdFx0Ly8gSWYgdGhlcmUgYXJlIHRhc2tzIHdpdGggYC5vbmx5YCBpbiB0aGlzIHN1aXRlLCBvbmx5IGluY2x1ZGUgdGhvc2UgKG5vdCBhbGwgdGFza3MgZnJvbSBkZXNjcmliZS5vbmx5KVxuXHRcdFx0Y29uc3QgaW5jbHVkZVRhc2sgPSBoYXNTb21lVGFza3NPbmx5ID8gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpIDogc3VpdGVJc09ubHkgfHwgdC5tb2RlID09PSBcIm9ubHlcIjtcblx0XHRcdGlmIChvbmx5TW9kZSkge1xuXHRcdFx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIgJiYgKGluY2x1ZGVUYXNrIHx8IHNvbWVUYXNrc0FyZU9ubHkodCkpKSB7XG5cdFx0XHRcdFx0Ly8gRG9uJ3Qgc2tpcCB0aGlzIHN1aXRlXG5cdFx0XHRcdFx0aWYgKHQubW9kZSA9PT0gXCJvbmx5XCIpIHtcblx0XHRcdFx0XHRcdGNoZWNrQWxsb3dPbmx5KHQsIGFsbG93T25seSk7XG5cdFx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIGlmICh0Lm1vZGUgPT09IFwicnVuXCIgJiYgIWluY2x1ZGVUYXNrKSB7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHRcdH0gZWxzZSBpZiAodC5tb2RlID09PSBcIm9ubHlcIikge1xuXHRcdFx0XHRcdGNoZWNrQWxsb3dPbmx5KHQsIGFsbG93T25seSk7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJydW5cIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bGV0IGhhc0xvY2F0aW9uTWF0Y2ggPSBwYXJlbnRNYXRjaGVkV2l0aExvY2F0aW9uO1xuXHRcdFx0Ly8gTWF0Y2ggdGVzdCBsb2NhdGlvbiBhZ2FpbnN0IHByb3ZpZGVkIGxvY2F0aW9ucywgb25seSBydW4gaWYgcHJlc2VudFxuXHRcdFx0Ly8gaW4gYHRlc3RMb2NhdGlvbnNgLiBOb3RlOiBpZiBgaW5jbHVkZVRhc2tMb2NhdGlvbmAgaXMgbm90IGVuYWJsZWQsXG5cdFx0XHQvLyBhbGwgdGVzdCB3aWxsIGJlIHNraXBwZWQuXG5cdFx0XHRpZiAodGVzdExvY2F0aW9ucyAhPT0gdW5kZWZpbmVkICYmIHRlc3RMb2NhdGlvbnMubGVuZ3RoICE9PSAwKSB7XG5cdFx0XHRcdGlmICh0LmxvY2F0aW9uICYmIHRlc3RMb2NhdGlvbnM/LmluY2x1ZGVzKHQubG9jYXRpb24ubGluZSkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHRcdG1hdGNoZWRMb2NhdGlvbnMucHVzaCh0LmxvY2F0aW9uLmxpbmUpO1xuXHRcdFx0XHRcdGhhc0xvY2F0aW9uTWF0Y2ggPSB0cnVlO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHBhcmVudE1hdGNoZWRXaXRoTG9jYXRpb24pIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInJ1blwiO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHQudHlwZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYgKHQudHlwZSA9PT0gXCJ0ZXN0XCIpIHtcblx0XHRcdFx0aWYgKG5hbWVQYXR0ZXJuICYmICFnZXRUYXNrRnVsbE5hbWUodCkubWF0Y2gobmFtZVBhdHRlcm4pKSB7XG5cdFx0XHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHRlc3RJZHMgJiYgIXRlc3RJZHMuaW5jbHVkZXModC5pZCkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGVzdFRhZ3NGaWx0ZXIgJiYgIXRlc3RUYWdzRmlsdGVyKHQudGFncyB8fCBbXSkpIHtcblx0XHRcdFx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmICh0LnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdFx0XHRpZiAodC5tb2RlID09PSBcInNraXBcIikge1xuXHRcdFx0XHRcdHNraXBBbGxUYXNrcyh0KTtcblx0XHRcdFx0fSBlbHNlIGlmICh0Lm1vZGUgPT09IFwidG9kb1wiKSB7XG5cdFx0XHRcdFx0dG9kb0FsbFRhc2tzKHQpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRyYXZlcnNlU3VpdGUodCwgaW5jbHVkZVRhc2ssIGhhc0xvY2F0aW9uTWF0Y2gpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ly8gaWYgYWxsIHN1YnRhc2tzIGFyZSBza2lwcGVkLCBtYXJrIGFzIHNraXBcblx0XHRpZiAoc3VpdGUubW9kZSA9PT0gXCJydW5cIiB8fCBzdWl0ZS5tb2RlID09PSBcInF1ZXVlZFwiKSB7XG5cdFx0XHRpZiAoc3VpdGUudGFza3MubGVuZ3RoICYmIHN1aXRlLnRhc2tzLmV2ZXJ5KChpKSA9PiBpLm1vZGUgIT09IFwicnVuXCIgJiYgaS5tb2RlICE9PSBcInF1ZXVlZFwiKSkge1xuXHRcdFx0XHRzdWl0ZS5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHR0cmF2ZXJzZVN1aXRlKGZpbGUsIHBhcmVudElzT25seSwgZmFsc2UpO1xuXHRjb25zdCBub25NYXRjaGluZyA9IHRlc3RMb2NhdGlvbnM/LmZpbHRlcigobG9jKSA9PiAhbWF0Y2hlZExvY2F0aW9ucy5pbmNsdWRlcyhsb2MpKTtcblx0aWYgKG5vbk1hdGNoaW5nICYmIG5vbk1hdGNoaW5nLmxlbmd0aCAhPT0gMCkge1xuXHRcdGNvbnN0IG1lc3NhZ2UgPSBub25NYXRjaGluZy5sZW5ndGggPT09IDEgPyBgbGluZSAke25vbk1hdGNoaW5nWzBdfWAgOiBgbGluZXMgJHtub25NYXRjaGluZy5qb2luKFwiLCBcIil9YDtcblx0XHRpZiAoZmlsZS5yZXN1bHQgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0ZmlsZS5yZXN1bHQgPSB7XG5cdFx0XHRcdHN0YXRlOiBcImZhaWxcIixcblx0XHRcdFx0ZXJyb3JzOiBbXVxuXHRcdFx0fTtcblx0XHR9XG5cdFx0aWYgKGZpbGUucmVzdWx0LmVycm9ycyA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRmaWxlLnJlc3VsdC5lcnJvcnMgPSBbXTtcblx0XHR9XG5cdFx0ZmlsZS5yZXN1bHQuZXJyb3JzLnB1c2gocHJvY2Vzc0Vycm9yKG5ldyBFcnJvcihgTm8gdGVzdCBmb3VuZCBpbiAke2ZpbGUubmFtZX0gaW4gJHttZXNzYWdlfWApKSk7XG5cdH1cbn1cbmZ1bmN0aW9uIGdldFRhc2tGdWxsTmFtZSh0YXNrKSB7XG5cdHJldHVybiBgJHt0YXNrLnN1aXRlID8gYCR7Z2V0VGFza0Z1bGxOYW1lKHRhc2suc3VpdGUpfSBgIDogXCJcIn0ke3Rhc2submFtZX1gO1xufVxuZnVuY3Rpb24gc29tZVRhc2tzQXJlT25seShzdWl0ZSkge1xuXHRyZXR1cm4gc3VpdGUudGFza3Muc29tZSgodCkgPT4gdC5tb2RlID09PSBcIm9ubHlcIiB8fCB0LnR5cGUgPT09IFwic3VpdGVcIiAmJiBzb21lVGFza3NBcmVPbmx5KHQpKTtcbn1cbmZ1bmN0aW9uIHNraXBBbGxUYXNrcyhzdWl0ZSkge1xuXHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0aWYgKHQubW9kZSA9PT0gXCJydW5cIiB8fCB0Lm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdHQubW9kZSA9IFwic2tpcFwiO1xuXHRcdFx0aWYgKHQudHlwZSA9PT0gXCJzdWl0ZVwiKSB7XG5cdFx0XHRcdHNraXBBbGxUYXNrcyh0KTtcblx0XHRcdH1cblx0XHR9XG5cdH0pO1xufVxuZnVuY3Rpb24gdG9kb0FsbFRhc2tzKHN1aXRlKSB7XG5cdHN1aXRlLnRhc2tzLmZvckVhY2goKHQpID0+IHtcblx0XHRpZiAodC5tb2RlID09PSBcInJ1blwiIHx8IHQubW9kZSA9PT0gXCJxdWV1ZWRcIikge1xuXHRcdFx0dC5tb2RlID0gXCJ0b2RvXCI7XG5cdFx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdFx0dG9kb0FsbFRhc2tzKHQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSk7XG59XG5mdW5jdGlvbiBjaGVja0FsbG93T25seSh0YXNrLCBhbGxvd09ubHkpIHtcblx0aWYgKGFsbG93T25seSkge1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoXCJbVml0ZXN0XSBVbmV4cGVjdGVkIC5vbmx5IG1vZGlmaWVyLiBSZW1vdmUgaXQgb3IgcGFzcyAtLWFsbG93T25seSBhcmd1bWVudCB0byBieXBhc3MgdGhpcyBlcnJvclwiKSk7XG5cdHRhc2sucmVzdWx0ID0ge1xuXHRcdHN0YXRlOiBcImZhaWxcIixcblx0XHRlcnJvcnM6IFtlcnJvcl1cblx0fTtcbn1cbi8qIEBfX05PX1NJREVfRUZGRUNUU19fICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhhc2goc3RyKSB7XG5cdGxldCBoYXNoID0gMDtcblx0aWYgKHN0ci5sZW5ndGggPT09IDApIHtcblx0XHRyZXR1cm4gYCR7aGFzaH1gO1xuXHR9XG5cdGZvciAobGV0IGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG5cdFx0Y29uc3QgY2hhciA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuXHRcdGhhc2ggPSAoaGFzaCA8PCA1KSAtIGhhc2ggKyBjaGFyO1xuXHRcdGhhc2ggPSBoYXNoICYgaGFzaDtcblx0fVxuXHRyZXR1cm4gYCR7aGFzaH1gO1xufVxuZnVuY3Rpb24gY2FsY3VsYXRlU3VpdGVIYXNoKHBhcmVudCkge1xuXHRwYXJlbnQudGFza3MuZm9yRWFjaCgodCwgaWR4KSA9PiB7XG5cdFx0dC5pZCA9IGAke3BhcmVudC5pZH1fJHtpZHh9YDtcblx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdGNhbGN1bGF0ZVN1aXRlSGFzaCh0KTtcblx0XHR9XG5cdH0pO1xufVxuZnVuY3Rpb24gY3JlYXRlRmlsZVRhc2soZmlsZXBhdGgsIHJvb3QsIHByb2plY3ROYW1lLCBwb29sLCB2aXRlRW52aXJvbm1lbnQpIHtcblx0Y29uc3QgcGF0aCA9IHJlbGF0aXZlKHJvb3QsIGZpbGVwYXRoKTtcblx0Y29uc3QgZmlsZSA9IHtcblx0XHRpZDogZ2VuZXJhdGVGaWxlSGFzaChwYXRoLCBwcm9qZWN0TmFtZSksXG5cdFx0bmFtZTogcGF0aCxcblx0XHRmdWxsTmFtZTogcGF0aCxcblx0XHR0eXBlOiBcInN1aXRlXCIsXG5cdFx0bW9kZTogXCJxdWV1ZWRcIixcblx0XHRmaWxlcGF0aCxcblx0XHR0YXNrczogW10sXG5cdFx0bWV0YTogT2JqZWN0LmNyZWF0ZShudWxsKSxcblx0XHRwcm9qZWN0TmFtZSxcblx0XHRmaWxlOiB1bmRlZmluZWQsXG5cdFx0cG9vbCxcblx0XHR2aXRlRW52aXJvbm1lbnRcblx0fTtcblx0ZmlsZS5maWxlID0gZmlsZTtcblx0cmV0dXJuIGZpbGU7XG59XG4vKipcbiogR2VuZXJhdGUgYSB1bmlxdWUgSUQgZm9yIGEgZmlsZSBiYXNlZCBvbiBpdHMgcGF0aCBhbmQgcHJvamVjdCBuYW1lXG4qIEBwYXJhbSBmaWxlIEZpbGUgcmVsYXRpdmUgdG8gdGhlIHJvb3Qgb2YgdGhlIHByb2plY3QgdG8ga2VlcCBJRCB0aGUgc2FtZSBiZXR3ZWVuIGRpZmZlcmVudCBtYWNoaW5lc1xuKiBAcGFyYW0gcHJvamVjdE5hbWUgVGhlIG5hbWUgb2YgdGhlIHRlc3QgcHJvamVjdFxuKi9cbi8qIEBfX05PX1NJREVfRUZGRUNUU19fICovXG5mdW5jdGlvbiBnZW5lcmF0ZUZpbGVIYXNoKGZpbGUsIHByb2plY3ROYW1lKSB7XG5cdHJldHVybiAvKiBAX19QVVJFX18gKi8gZ2VuZXJhdGVIYXNoKGAke2ZpbGV9JHtwcm9qZWN0TmFtZSB8fCBcIlwifWApO1xufVxuZnVuY3Rpb24gZmluZFRlc3RGaWxlU3RhY2tUcmFjZSh0ZXN0RmlsZVBhdGgsIGVycm9yKSB7XG5cdC8vIGZpcnN0IGxpbmUgaXMgdGhlIGVycm9yIG1lc3NhZ2Vcblx0Y29uc3QgbGluZXMgPSBlcnJvci5zcGxpdChcIlxcblwiKS5zbGljZSgxKTtcblx0Zm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG5cdFx0Y29uc3Qgc3RhY2sgPSBwYXJzZVNpbmdsZVN0YWNrKGxpbmUpO1xuXHRcdGlmIChzdGFjayAmJiBzdGFjay5maWxlID09PSB0ZXN0RmlsZVBhdGgpIHtcblx0XHRcdHJldHVybiBzdGFjaztcblx0XHR9XG5cdH1cbn1cblxuLyoqXG4qIFJldHVybiBhIGZ1bmN0aW9uIGZvciBydW5uaW5nIG11bHRpcGxlIGFzeW5jIG9wZXJhdGlvbnMgd2l0aCBsaW1pdGVkIGNvbmN1cnJlbmN5LlxuKi9cbmZ1bmN0aW9uIGxpbWl0Q29uY3VycmVuY3koY29uY3VycmVuY3kgPSBJbmZpbml0eSkge1xuXHQvLyBUaGUgbnVtYmVyIG9mIGN1cnJlbnRseSBhY3RpdmUgKyBwZW5kaW5nIHRhc2tzLlxuXHRsZXQgY291bnQgPSAwO1xuXHQvLyBUaGUgaGVhZCBhbmQgdGFpbCBvZiB0aGUgcGVuZGluZyB0YXNrIHF1ZXVlLCBidWlsdCB1c2luZyBhIHNpbmdseSBsaW5rZWQgbGlzdC5cblx0Ly8gQm90aCBoZWFkIGFuZCB0YWlsIGFyZSBpbml0aWFsbHkgdW5kZWZpbmVkLCBzaWduaWZ5aW5nIGFuIGVtcHR5IHF1ZXVlLlxuXHQvLyBUaGV5IGJvdGggYmVjb21lIHVuZGVmaW5lZCBhZ2FpbiB3aGVuZXZlciB0aGVyZSBhcmUgbm8gcGVuZGluZyB0YXNrcy5cblx0bGV0IGhlYWQ7XG5cdGxldCB0YWlsO1xuXHQvLyBBIGJvb2trZWVwaW5nIGZ1bmN0aW9uIGV4ZWN1dGVkIHdoZW5ldmVyIGEgdGFzayBoYXMgYmVlbiBydW4gdG8gY29tcGxldGlvbi5cblx0Y29uc3QgZmluaXNoID0gKCkgPT4ge1xuXHRcdGNvdW50LS07XG5cdFx0Ly8gQ2hlY2sgaWYgdGhlcmUgYXJlIGZ1cnRoZXIgcGVuZGluZyB0YXNrcyBpbiB0aGUgcXVldWUuXG5cdFx0aWYgKGhlYWQpIHtcblx0XHRcdC8vIEFsbG93IHRoZSBuZXh0IHBlbmRpbmcgdGFzayB0byBydW4gYW5kIHBvcCBpdCBmcm9tIHRoZSBxdWV1ZS5cblx0XHRcdGhlYWRbMF0oKTtcblx0XHRcdGhlYWQgPSBoZWFkWzFdO1xuXHRcdFx0Ly8gVGhlIGhlYWQgbWF5IG5vdyBiZSB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIGZ1cnRoZXIgcGVuZGluZyB0YXNrcy5cblx0XHRcdC8vIEluIHRoYXQgY2FzZSwgc2V0IHRhaWwgdG8gdW5kZWZpbmVkIGFzIHdlbGwuXG5cdFx0XHR0YWlsID0gaGVhZCAmJiB0YWlsO1xuXHRcdH1cblx0fTtcblx0Y29uc3QgYWNxdWlyZSA9ICgpID0+IHtcblx0XHRsZXQgcmVsZWFzZWQgPSBmYWxzZTtcblx0XHRjb25zdCByZWxlYXNlID0gKCkgPT4ge1xuXHRcdFx0aWYgKCFyZWxlYXNlZCkge1xuXHRcdFx0XHRyZWxlYXNlZCA9IHRydWU7XG5cdFx0XHRcdGZpbmlzaCgpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0aWYgKGNvdW50KysgPCBjb25jdXJyZW5jeSkge1xuXHRcdFx0cmV0dXJuIHJlbGVhc2U7XG5cdFx0fVxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuXHRcdFx0aWYgKHRhaWwpIHtcblx0XHRcdFx0Ly8gVGhlcmUgYXJlIHBlbmRpbmcgdGFza3MsIHNvIGFwcGVuZCB0byB0aGUgcXVldWUuXG5cdFx0XHRcdHRhaWwgPSB0YWlsWzFdID0gWygpID0+IHJlc29sdmUocmVsZWFzZSldO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gTm8gb3RoZXIgcGVuZGluZyB0YXNrcywgaW5pdGlhbGl6ZSB0aGUgcXVldWUgd2l0aCBhIG5ldyB0YWlsIGFuZCBoZWFkLlxuXHRcdFx0XHRoZWFkID0gdGFpbCA9IFsoKSA9PiByZXNvbHZlKHJlbGVhc2UpXTtcblx0XHRcdH1cblx0XHR9KTtcblx0fTtcblx0Y29uc3QgbGltaXRlckZuID0gKGZ1bmMsIC4uLmFyZ3MpID0+IHtcblx0XHRmdW5jdGlvbiBydW4ocmVsZWFzZSkge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZnVuYyguLi5hcmdzKTtcblx0XHRcdFx0aWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHtcblx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0LmZpbmFsbHkocmVsZWFzZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmVsZWFzZSgpO1xuXHRcdFx0XHRyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCk7XG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRyZWxlYXNlKCk7XG5cdFx0XHRcdHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcik7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGNvbnN0IHJlbGVhc2UgPSBhY3F1aXJlKCk7XG5cdFx0cmV0dXJuIHJlbGVhc2UgaW5zdGFuY2VvZiBQcm9taXNlID8gcmVsZWFzZS50aGVuKHJ1bikgOiBydW4ocmVsZWFzZSk7XG5cdH07XG5cdHJldHVybiBPYmplY3QuYXNzaWduKGxpbWl0ZXJGbiwgeyBhY3F1aXJlIH0pO1xufVxuXG4vKipcbiogUGFydGl0aW9uIGluIHRhc2tzIGdyb3VwcyBieSBjb25zZWN1dGl2ZSBjb25jdXJyZW50XG4qL1xuZnVuY3Rpb24gcGFydGl0aW9uU3VpdGVDaGlsZHJlbihzdWl0ZSkge1xuXHRsZXQgdGFza3NHcm91cCA9IFtdO1xuXHRjb25zdCB0YXNrc0dyb3VwcyA9IFtdO1xuXHRmb3IgKGNvbnN0IGMgb2Ygc3VpdGUudGFza3MpIHtcblx0XHRpZiAodGFza3NHcm91cC5sZW5ndGggPT09IDAgfHwgYy5jb25jdXJyZW50ID09PSB0YXNrc0dyb3VwWzBdLmNvbmN1cnJlbnQpIHtcblx0XHRcdHRhc2tzR3JvdXAucHVzaChjKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGFza3NHcm91cHMucHVzaCh0YXNrc0dyb3VwKTtcblx0XHRcdHRhc2tzR3JvdXAgPSBbY107XG5cdFx0fVxuXHR9XG5cdGlmICh0YXNrc0dyb3VwLmxlbmd0aCA+IDApIHtcblx0XHR0YXNrc0dyb3Vwcy5wdXNoKHRhc2tzR3JvdXApO1xuXHR9XG5cdHJldHVybiB0YXNrc0dyb3Vwcztcbn1cblxuY29uc3QgZmlsdGVyTWFwID0gbmV3IFdlYWtNYXAoKTtcbi8qKlxuKiBAZXhwZXJpbWVudGFsXG4qL1xuZnVuY3Rpb24gbWF0Y2hlc1RhZ3ModGVzdFRhZ3MpIHtcblx0Y29uc3QgcnVubmVyID0gZ2V0UnVubmVyKCk7XG5cdGNvbnN0IHRhZ3NGaWx0ZXIgPSBydW5uZXIuX2N1cnJlbnRTcGVjaWZpY2F0aW9uPy50ZXN0VGFnc0ZpbHRlciA/PyBydW5uZXIuY29uZmlnLnRhZ3NGaWx0ZXI7XG5cdGlmICghdGFnc0ZpbHRlcikge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cdGxldCB0YWdzRmlsdGVyUHJlZGljYXRlID0gZmlsdGVyTWFwLmdldCh0YWdzRmlsdGVyKTtcblx0aWYgKCF0YWdzRmlsdGVyUHJlZGljYXRlKSB7XG5cdFx0dGFnc0ZpbHRlclByZWRpY2F0ZSA9IGNyZWF0ZVRhZ3NGaWx0ZXIodGFnc0ZpbHRlciwgcnVubmVyLmNvbmZpZy50YWdzKTtcblx0XHRmaWx0ZXJNYXAuc2V0KHRhZ3NGaWx0ZXIsIHRhZ3NGaWx0ZXJQcmVkaWNhdGUpO1xuXHR9XG5cdHJldHVybiB0YWdzRmlsdGVyUHJlZGljYXRlKHRlc3RUYWdzKTtcbn1cbmZ1bmN0aW9uIHZhbGlkYXRlVGFncyhjb25maWcsIHRhZ3MpIHtcblx0aWYgKCFjb25maWcuc3RyaWN0VGFncykge1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBhdmFpbGFibGVUYWdzID0gbmV3IFNldChjb25maWcudGFncy5tYXAoKHRhZykgPT4gdGFnLm5hbWUpKTtcblx0Zm9yIChjb25zdCB0YWcgb2YgdGFncykge1xuXHRcdGlmICghYXZhaWxhYmxlVGFncy5oYXModGFnKSkge1xuXHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IoY29uZmlnLnRhZ3MsIHRhZyk7XG5cdFx0fVxuXHR9XG59XG5mdW5jdGlvbiBjcmVhdGVOb1RhZ3NFcnJvcihhdmFpbGFibGVUYWdzLCB0YWcsIHByZWZpeCA9IFwidGFnXCIpIHtcblx0aWYgKCFhdmFpbGFibGVUYWdzLmxlbmd0aCkge1xuXHRcdHRocm93IG5ldyBFcnJvcihgVGhlIFZpdGVzdCBjb25maWcgZG9lcyd0IGRlZmluZSBhbnkgXCJ0YWdzXCIsIGNhbm5vdCBhcHBseSBcIiR7dGFnfVwiICR7cHJlZml4fSBmb3IgdGhpcyB0ZXN0LiBTZWU6IGh0dHBzOi8vdml0ZXN0LmRldi9ndWlkZS90ZXN0LXRhZ3NgKTtcblx0fVxuXHR0aHJvdyBuZXcgRXJyb3IoYFRoZSAke3ByZWZpeH0gXCIke3RhZ31cIiBpcyBub3QgZGVmaW5lZCBpbiB0aGUgY29uZmlndXJhdGlvbi4gQXZhaWxhYmxlIHRhZ3MgYXJlOlxcbiR7YXZhaWxhYmxlVGFncy5tYXAoKHQpID0+IGAtICR7dC5uYW1lfSR7dC5kZXNjcmlwdGlvbiA/IGA6ICR7dC5kZXNjcmlwdGlvbn1gIDogXCJcIn1gKS5qb2luKFwiXFxuXCIpfWApO1xufVxuZnVuY3Rpb24gY3JlYXRlVGFnc0ZpbHRlcih0YWdzRXhwciwgYXZhaWxhYmxlVGFncykge1xuXHRjb25zdCBtYXRjaGVycyA9IHRhZ3NFeHByLm1hcCgoZXhwcikgPT4gcGFyc2VUYWdzRXhwcmVzc2lvbihleHByLCBhdmFpbGFibGVUYWdzKSk7XG5cdHJldHVybiAodGVzdFRhZ3MpID0+IHtcblx0XHRyZXR1cm4gbWF0Y2hlcnMuZXZlcnkoKG1hdGNoZXIpID0+IG1hdGNoZXIodGVzdFRhZ3MpKTtcblx0fTtcbn1cbmZ1bmN0aW9uIHBhcnNlVGFnc0V4cHJlc3Npb24oZXhwciwgYXZhaWxhYmxlVGFncykge1xuXHRjb25zdCB0b2tlbnMgPSB0b2tlbml6ZShleHByKTtcblx0Y29uc3Qgc3RyZWFtID0gbmV3IFRva2VuU3RyZWFtKHRva2VucywgZXhwcik7XG5cdGNvbnN0IGFzdCA9IHBhcnNlT3JFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdGlmIChzdHJlYW0ucGVlaygpLnR5cGUgIT09IFwiRU9GXCIpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdGFncyBleHByZXNzaW9uOiB1bmV4cGVjdGVkIFwiJHtmb3JtYXRUb2tlbihzdHJlYW0ucGVlaygpKX1cIiBpbiBcIiR7ZXhwcn1cImApO1xuXHR9XG5cdHJldHVybiAodGFncykgPT4gZXZhbHVhdGVOb2RlKGFzdCwgdGFncyk7XG59XG5mdW5jdGlvbiBmb3JtYXRUb2tlbih0b2tlbikge1xuXHRzd2l0Y2ggKHRva2VuLnR5cGUpIHtcblx0XHRjYXNlIFwiVEFHXCI6IHJldHVybiB0b2tlbi52YWx1ZTtcblx0XHRkZWZhdWx0OiByZXR1cm4gZm9ybWF0VG9rZW5UeXBlKHRva2VuLnR5cGUpO1xuXHR9XG59XG5mdW5jdGlvbiB0b2tlbml6ZShleHByKSB7XG5cdGNvbnN0IHRva2VucyA9IFtdO1xuXHRsZXQgaSA9IDA7XG5cdHdoaWxlIChpIDwgZXhwci5sZW5ndGgpIHtcblx0XHRpZiAoZXhwcltpXSA9PT0gXCIgXCIgfHwgZXhwcltpXSA9PT0gXCJcdFwiKSB7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiKFwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTFBBUkVOXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiKVwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiUlBBUkVOXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHJbaV0gPT09IFwiIVwiKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTk9UXCIgfSk7XG5cdFx0XHRpKys7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKGV4cHIuc2xpY2UoaSwgaSArIDIpID09PSBcIiYmXCIpIHtcblx0XHRcdHRva2Vucy5wdXNoKHsgdHlwZTogXCJBTkRcIiB9KTtcblx0XHRcdGkgKz0gMjtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoZXhwci5zbGljZShpLCBpICsgMikgPT09IFwifHxcIikge1xuXHRcdFx0dG9rZW5zLnB1c2goeyB0eXBlOiBcIk9SXCIgfSk7XG5cdFx0XHRpICs9IDI7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0aWYgKC9eYW5kKD86XFxzfFxcKXwkKS9pLnRlc3QoZXhwci5zbGljZShpKSkpIHtcblx0XHRcdHRva2Vucy5wdXNoKHsgdHlwZTogXCJBTkRcIiB9KTtcblx0XHRcdGkgKz0gMztcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoL15vcig/Olxcc3xcXCl8JCkvaS50ZXN0KGV4cHIuc2xpY2UoaSkpKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiT1JcIiB9KTtcblx0XHRcdGkgKz0gMjtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblx0XHRpZiAoL15ub3RcXHMvaS50ZXN0KGV4cHIuc2xpY2UoaSkpKSB7XG5cdFx0XHR0b2tlbnMucHVzaCh7IHR5cGU6IFwiTk9UXCIgfSk7XG5cdFx0XHRpICs9IDM7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdFx0bGV0IHRhZyA9IFwiXCI7XG5cdFx0d2hpbGUgKGkgPCBleHByLmxlbmd0aCAmJiBleHByW2ldICE9PSBcIiBcIiAmJiBleHByW2ldICE9PSBcIlx0XCIgJiYgZXhwcltpXSAhPT0gXCIoXCIgJiYgZXhwcltpXSAhPT0gXCIpXCIgJiYgZXhwcltpXSAhPT0gXCIhXCIgJiYgZXhwcltpXSAhPT0gXCImXCIgJiYgZXhwcltpXSAhPT0gXCJ8XCIpIHtcblx0XHRcdGNvbnN0IHJlbWFpbmluZyA9IGV4cHIuc2xpY2UoaSk7XG5cdFx0XHQvLyBPbmx5IHRyZWF0IGFuZC9vci9ub3QgYXMgb3BlcmF0b3JzIGlmIHdlJ3JlIGF0IHRoZSBzdGFydCBvZiBhIHRhZyAoYWZ0ZXIgd2hpdGVzcGFjZSlcblx0XHRcdC8vIFRoaXMgYWxsb3dzIHRhZ3MgbGlrZSBcImRlbWFuZFwiLCBcImVkaXRvclwiLCBcImNhbm5vdFwiIHRvIHdvcmsgY29ycmVjdGx5XG5cdFx0XHRpZiAodGFnID09PSBcIlwiICYmICgvXmFuZCg/Olxcc3xcXCl8JCkvaS50ZXN0KHJlbWFpbmluZykgfHwgL15vcig/Olxcc3xcXCl8JCkvaS50ZXN0KHJlbWFpbmluZykgfHwgL15ub3RcXHMvaS50ZXN0KHJlbWFpbmluZykpKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0dGFnICs9IGV4cHJbaV07XG5cdFx0XHRpKys7XG5cdFx0fVxuXHRcdGlmICh0YWcpIHtcblx0XHRcdHRva2Vucy5wdXNoKHtcblx0XHRcdFx0dHlwZTogXCJUQUdcIixcblx0XHRcdFx0dmFsdWU6IHRhZ1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cdHRva2Vucy5wdXNoKHsgdHlwZTogXCJFT0ZcIiB9KTtcblx0cmV0dXJuIHRva2Vucztcbn1cbmNsYXNzIFRva2VuU3RyZWFtIHtcblx0cG9zID0gMDtcblx0Y29uc3RydWN0b3IodG9rZW5zLCBleHByKSB7XG5cdFx0dGhpcy50b2tlbnMgPSB0b2tlbnM7XG5cdFx0dGhpcy5leHByID0gZXhwcjtcblx0fVxuXHRwZWVrKCkge1xuXHRcdHJldHVybiB0aGlzLnRva2Vuc1t0aGlzLnBvc107XG5cdH1cblx0bmV4dCgpIHtcblx0XHRyZXR1cm4gdGhpcy50b2tlbnNbdGhpcy5wb3MrK107XG5cdH1cblx0ZXhwZWN0KHR5cGUpIHtcblx0XHRjb25zdCB0b2tlbiA9IHRoaXMubmV4dCgpO1xuXHRcdGlmICh0b2tlbi50eXBlICE9PSB0eXBlKSB7XG5cdFx0XHRpZiAodHlwZSA9PT0gXCJSUEFSRU5cIiAmJiB0b2tlbi50eXBlID09PSBcIkVPRlwiKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0YWdzIGV4cHJlc3Npb246IG1pc3NpbmcgY2xvc2luZyBcIilcIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0XHR9XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdGFncyBleHByZXNzaW9uOiBleHBlY3RlZCBcIiR7Zm9ybWF0VG9rZW5UeXBlKHR5cGUpfVwiIGJ1dCBnb3QgXCIke2Zvcm1hdFRva2VuKHRva2VuKX1cIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0fVxuXHRcdHJldHVybiB0b2tlbjtcblx0fVxuXHR1bmV4cGVjdGVkVG9rZW4oKSB7XG5cdFx0Y29uc3QgdG9rZW4gPSB0aGlzLnBlZWsoKTtcblx0XHRpZiAodG9rZW4udHlwZSA9PT0gXCJFT0ZcIikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRhZ3MgZXhwcmVzc2lvbjogdW5leHBlY3RlZCBlbmQgb2YgZXhwcmVzc2lvbiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdFx0fVxuXHRcdHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0YWdzIGV4cHJlc3Npb246IHVuZXhwZWN0ZWQgXCIke2Zvcm1hdFRva2VuKHRva2VuKX1cIiBpbiBcIiR7dGhpcy5leHByfVwiYCk7XG5cdH1cbn1cbmZ1bmN0aW9uIGZvcm1hdFRva2VuVHlwZSh0eXBlKSB7XG5cdHN3aXRjaCAodHlwZSkge1xuXHRcdGNhc2UgXCJUQUdcIjogcmV0dXJuIFwidGFnXCI7XG5cdFx0Y2FzZSBcIkFORFwiOiByZXR1cm4gXCJhbmRcIjtcblx0XHRjYXNlIFwiT1JcIjogcmV0dXJuIFwib3JcIjtcblx0XHRjYXNlIFwiTk9UXCI6IHJldHVybiBcIm5vdFwiO1xuXHRcdGNhc2UgXCJMUEFSRU5cIjogcmV0dXJuIFwiKFwiO1xuXHRcdGNhc2UgXCJSUEFSRU5cIjogcmV0dXJuIFwiKVwiO1xuXHRcdGNhc2UgXCJFT0ZcIjogcmV0dXJuIFwiZW5kIG9mIGV4cHJlc3Npb25cIjtcblx0fVxufVxuZnVuY3Rpb24gcGFyc2VPckV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGxldCBsZWZ0ID0gcGFyc2VBbmRFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdHdoaWxlIChzdHJlYW0ucGVlaygpLnR5cGUgPT09IFwiT1JcIikge1xuXHRcdHN0cmVhbS5uZXh0KCk7XG5cdFx0Y29uc3QgcmlnaHQgPSBwYXJzZUFuZEV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKTtcblx0XHRsZWZ0ID0ge1xuXHRcdFx0dHlwZTogXCJvclwiLFxuXHRcdFx0bGVmdCxcblx0XHRcdHJpZ2h0XG5cdFx0fTtcblx0fVxuXHRyZXR1cm4gbGVmdDtcbn1cbmZ1bmN0aW9uIHBhcnNlQW5kRXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpIHtcblx0bGV0IGxlZnQgPSBwYXJzZVVuYXJ5RXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHR3aGlsZSAoc3RyZWFtLnBlZWsoKS50eXBlID09PSBcIkFORFwiKSB7XG5cdFx0c3RyZWFtLm5leHQoKTtcblx0XHRjb25zdCByaWdodCA9IHBhcnNlVW5hcnlFeHByZXNzaW9uKHN0cmVhbSwgYXZhaWxhYmxlVGFncyk7XG5cdFx0bGVmdCA9IHtcblx0XHRcdHR5cGU6IFwiYW5kXCIsXG5cdFx0XHRsZWZ0LFxuXHRcdFx0cmlnaHRcblx0XHR9O1xuXHR9XG5cdHJldHVybiBsZWZ0O1xufVxuZnVuY3Rpb24gcGFyc2VVbmFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGlmIChzdHJlYW0ucGVlaygpLnR5cGUgPT09IFwiTk9UXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IG9wZXJhbmQgPSBwYXJzZVVuYXJ5RXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHRcdHJldHVybiB7XG5cdFx0XHR0eXBlOiBcIm5vdFwiLFxuXHRcdFx0b3BlcmFuZFxuXHRcdH07XG5cdH1cblx0cmV0dXJuIHBhcnNlUHJpbWFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKTtcbn1cbmZ1bmN0aW9uIHBhcnNlUHJpbWFyeUV4cHJlc3Npb24oc3RyZWFtLCBhdmFpbGFibGVUYWdzKSB7XG5cdGNvbnN0IHRva2VuID0gc3RyZWFtLnBlZWsoKTtcblx0aWYgKHRva2VuLnR5cGUgPT09IFwiTFBBUkVOXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IGV4cHIgPSBwYXJzZU9yRXhwcmVzc2lvbihzdHJlYW0sIGF2YWlsYWJsZVRhZ3MpO1xuXHRcdHN0cmVhbS5leHBlY3QoXCJSUEFSRU5cIik7XG5cdFx0cmV0dXJuIGV4cHI7XG5cdH1cblx0aWYgKHRva2VuLnR5cGUgPT09IFwiVEFHXCIpIHtcblx0XHRzdHJlYW0ubmV4dCgpO1xuXHRcdGNvbnN0IHRhZ1ZhbHVlID0gdG9rZW4udmFsdWU7XG5cdFx0Y29uc3QgcGF0dGVybiA9IHJlc29sdmVUYWdQYXR0ZXJuKHRhZ1ZhbHVlLCBhdmFpbGFibGVUYWdzKTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0dHlwZTogXCJ0YWdcIixcblx0XHRcdHZhbHVlOiB0YWdWYWx1ZSxcblx0XHRcdHBhdHRlcm5cblx0XHR9O1xuXHR9XG5cdHN0cmVhbS51bmV4cGVjdGVkVG9rZW4oKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVdpbGRjYXJkUmVnZXgocGF0dGVybikge1xuXHRyZXR1cm4gbmV3IFJlZ0V4cChgXiR7cGF0dGVybi5yZXBsYWNlKC9bLis/XiR7fSgpfFtcXF1cXFxcXS9nLCBcIlxcXFwkJlwiKS5yZXBsYWNlKC9cXCovZywgXCIuKlwiKX0kYCk7XG59XG5mdW5jdGlvbiByZXNvbHZlVGFnUGF0dGVybih0YWdQYXR0ZXJuLCBhdmFpbGFibGVUYWdzKSB7XG5cdGlmICh0YWdQYXR0ZXJuLmluY2x1ZGVzKFwiKlwiKSkge1xuXHRcdGNvbnN0IHJlZ2V4ID0gY3JlYXRlV2lsZGNhcmRSZWdleCh0YWdQYXR0ZXJuKTtcblx0XHRjb25zdCBoYXNNYXRjaCA9IGF2YWlsYWJsZVRhZ3Muc29tZSgodGFnKSA9PiByZWdleC50ZXN0KHRhZy5uYW1lKSk7XG5cdFx0aWYgKCFoYXNNYXRjaCkge1xuXHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IoYXZhaWxhYmxlVGFncywgdGFnUGF0dGVybiwgXCJ0YWcgcGF0dGVyblwiKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlZ2V4O1xuXHR9XG5cdGlmICghYXZhaWxhYmxlVGFncy5sZW5ndGggfHwgIWF2YWlsYWJsZVRhZ3Muc29tZSgodGFnKSA9PiB0YWcubmFtZSA9PT0gdGFnUGF0dGVybikpIHtcblx0XHR0aHJvdyBjcmVhdGVOb1RhZ3NFcnJvcihhdmFpbGFibGVUYWdzLCB0YWdQYXR0ZXJuLCBcInRhZyBwYXR0ZXJuXCIpO1xuXHR9XG5cdHJldHVybiBudWxsO1xufVxuZnVuY3Rpb24gZXZhbHVhdGVOb2RlKG5vZGUsIHRhZ3MpIHtcblx0c3dpdGNoIChub2RlLnR5cGUpIHtcblx0XHRjYXNlIFwidGFnXCI6XG5cdFx0XHRpZiAobm9kZS5wYXR0ZXJuKSB7XG5cdFx0XHRcdHJldHVybiB0YWdzLnNvbWUoKHRhZykgPT4gbm9kZS5wYXR0ZXJuLnRlc3QodGFnKSk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGFncy5pbmNsdWRlcyhub2RlLnZhbHVlKTtcblx0XHRjYXNlIFwibm90XCI6IHJldHVybiAhZXZhbHVhdGVOb2RlKG5vZGUub3BlcmFuZCwgdGFncyk7XG5cdFx0Y2FzZSBcImFuZFwiOiByZXR1cm4gZXZhbHVhdGVOb2RlKG5vZGUubGVmdCwgdGFncykgJiYgZXZhbHVhdGVOb2RlKG5vZGUucmlnaHQsIHRhZ3MpO1xuXHRcdGNhc2UgXCJvclwiOiByZXR1cm4gZXZhbHVhdGVOb2RlKG5vZGUubGVmdCwgdGFncykgfHwgZXZhbHVhdGVOb2RlKG5vZGUucmlnaHQsIHRhZ3MpO1xuXHR9XG59XG5cbmZ1bmN0aW9uIGlzVGVzdENhc2Uocykge1xuXHRyZXR1cm4gcy50eXBlID09PSBcInRlc3RcIjtcbn1cbmZ1bmN0aW9uIGdldFRlc3RzKHN1aXRlKSB7XG5cdGNvbnN0IHRlc3RzID0gW107XG5cdGNvbnN0IGFycmF5U3VpdGVzID0gdG9BcnJheShzdWl0ZSk7XG5cdGZvciAoY29uc3QgcyBvZiBhcnJheVN1aXRlcykge1xuXHRcdGlmIChpc1Rlc3RDYXNlKHMpKSB7XG5cdFx0XHR0ZXN0cy5wdXNoKHMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKGNvbnN0IHRhc2sgb2Ygcy50YXNrcykge1xuXHRcdFx0XHRpZiAoaXNUZXN0Q2FzZSh0YXNrKSkge1xuXHRcdFx0XHRcdHRlc3RzLnB1c2godGFzayk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y29uc3QgdGFza1Rlc3RzID0gZ2V0VGVzdHModGFzayk7XG5cdFx0XHRcdFx0Zm9yIChjb25zdCB0ZXN0IG9mIHRhc2tUZXN0cykge1xuXHRcdFx0XHRcdFx0dGVzdHMucHVzaCh0ZXN0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblx0cmV0dXJuIHRlc3RzO1xufVxuZnVuY3Rpb24gZ2V0VGFza3ModGFza3MgPSBbXSkge1xuXHRyZXR1cm4gdG9BcnJheSh0YXNrcykuZmxhdE1hcCgocykgPT4gaXNUZXN0Q2FzZShzKSA/IFtzXSA6IFtzLCAuLi5nZXRUYXNrcyhzLnRhc2tzKV0pO1xufVxuZnVuY3Rpb24gZ2V0U3VpdGVzKHN1aXRlKSB7XG5cdHJldHVybiB0b0FycmF5KHN1aXRlKS5mbGF0TWFwKChzKSA9PiBzLnR5cGUgPT09IFwic3VpdGVcIiA/IFtzLCAuLi5nZXRTdWl0ZXMocy50YXNrcyldIDogW10pO1xufVxuZnVuY3Rpb24gaGFzVGVzdHMoc3VpdGUpIHtcblx0cmV0dXJuIHRvQXJyYXkoc3VpdGUpLnNvbWUoKHMpID0+IHMudGFza3Muc29tZSgoYykgPT4gaXNUZXN0Q2FzZShjKSB8fCBoYXNUZXN0cyhjKSkpO1xufVxuZnVuY3Rpb24gaGFzRmFpbGVkKHN1aXRlKSB7XG5cdHJldHVybiB0b0FycmF5KHN1aXRlKS5zb21lKChzKSA9PiBzLnJlc3VsdD8uc3RhdGUgPT09IFwiZmFpbFwiIHx8IHMudHlwZSA9PT0gXCJzdWl0ZVwiICYmIGhhc0ZhaWxlZChzLnRhc2tzKSk7XG59XG5mdW5jdGlvbiBnZXROYW1lcyh0YXNrKSB7XG5cdGNvbnN0IG5hbWVzID0gW3Rhc2submFtZV07XG5cdGxldCBjdXJyZW50ID0gdGFzaztcblx0d2hpbGUgKGN1cnJlbnQ/LnN1aXRlKSB7XG5cdFx0Y3VycmVudCA9IGN1cnJlbnQuc3VpdGU7XG5cdFx0aWYgKGN1cnJlbnQ/Lm5hbWUpIHtcblx0XHRcdG5hbWVzLnVuc2hpZnQoY3VycmVudC5uYW1lKTtcblx0XHR9XG5cdH1cblx0aWYgKGN1cnJlbnQgIT09IHRhc2suZmlsZSkge1xuXHRcdG5hbWVzLnVuc2hpZnQodGFzay5maWxlLm5hbWUpO1xuXHR9XG5cdHJldHVybiBuYW1lcztcbn1cbmZ1bmN0aW9uIGdldEZ1bGxOYW1lKHRhc2ssIHNlcGFyYXRvciA9IFwiID4gXCIpIHtcblx0cmV0dXJuIGdldE5hbWVzKHRhc2spLmpvaW4oc2VwYXJhdG9yKTtcbn1cbmZ1bmN0aW9uIGdldFRlc3ROYW1lKHRhc2ssIHNlcGFyYXRvciA9IFwiID4gXCIpIHtcblx0cmV0dXJuIGdldE5hbWVzKHRhc2spLnNsaWNlKDEpLmpvaW4oc2VwYXJhdG9yKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRhc2tOYW1lKG5hbWVzLCBzZXBhcmF0b3IgPSBcIiA+IFwiKSB7XG5cdHJldHVybiBuYW1lcy5maWx0ZXIoKG5hbWUpID0+IG5hbWUgIT09IHVuZGVmaW5lZCkuam9pbihzZXBhcmF0b3IpO1xufVxuXG4vKipcbiogQ3JlYXRlcyBhIHN1aXRlIG9mIHRlc3RzLCBhbGxvd2luZyBmb3IgZ3JvdXBpbmcgYW5kIGhpZXJhcmNoaWNhbCBvcmdhbml6YXRpb24gb2YgdGVzdHMuXG4qIFN1aXRlcyBjYW4gY29udGFpbiBib3RoIHRlc3RzIGFuZCBvdGhlciBzdWl0ZXMsIGVuYWJsaW5nIGNvbXBsZXggdGVzdCBzdHJ1Y3R1cmVzLlxuKlxuKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBzdWl0ZSwgdXNlZCBmb3IgaWRlbnRpZmljYXRpb24gYW5kIHJlcG9ydGluZy5cbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBBIGZ1bmN0aW9uIHRoYXQgZGVmaW5lcyB0aGUgdGVzdHMgYW5kIHN1aXRlcyB3aXRoaW4gdGhpcyBzdWl0ZS5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc3VpdGUgd2l0aCB0d28gdGVzdHNcbiogc3VpdGUoJ01hdGggb3BlcmF0aW9ucycsICgpID0+IHtcbiogICB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogICB9KTtcbipcbiogICB0ZXN0KCdzaG91bGQgc3VidHJhY3QgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgICBleHBlY3Qoc3VidHJhY3QoNSwgMikpLnRvQmUoMyk7XG4qICAgfSk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIG5lc3RlZCBzdWl0ZXNcbiogc3VpdGUoJ1N0cmluZyBvcGVyYXRpb25zJywgKCkgPT4ge1xuKiAgIHN1aXRlKCdUcmltbWluZycsICgpID0+IHtcbiogICAgIHRlc3QoJ3Nob3VsZCB0cmltIHdoaXRlc3BhY2UgZnJvbSBzdGFydCBhbmQgZW5kJywgKCkgPT4ge1xuKiAgICAgICBleHBlY3QoJyAgaGVsbG8gICcudHJpbSgpKS50b0JlKCdoZWxsbycpO1xuKiAgICAgfSk7XG4qICAgfSk7XG4qXG4qICAgc3VpdGUoJ0NvbmNhdGVuYXRpb24nLCAoKSA9PiB7XG4qICAgICB0ZXN0KCdzaG91bGQgY29uY2F0ZW5hdGUgdHdvIHN0cmluZ3MnLCAoKSA9PiB7XG4qICAgICAgIGV4cGVjdCgnaGVsbG8nICsgJyAnICsgJ3dvcmxkJykudG9CZSgnaGVsbG8gd29ybGQnKTtcbiogICAgIH0pO1xuKiAgIH0pO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3Qgc3VpdGUgPSBjcmVhdGVTdWl0ZSgpO1xuLyoqXG4qIERlZmluZXMgYSB0ZXN0IGNhc2Ugd2l0aCBhIGdpdmVuIG5hbWUgYW5kIHRlc3QgZnVuY3Rpb24uIFRoZSB0ZXN0IGZ1bmN0aW9uIGNhbiBvcHRpb25hbGx5IGJlIGNvbmZpZ3VyZWQgd2l0aCB0ZXN0IG9wdGlvbnMuXG4qXG4qIEBwYXJhbSB7c3RyaW5nIHwgRnVuY3Rpb259IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGVzdCBvciBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSB1c2VkIGFzIGEgdGVzdCBuYW1lLlxuKiBAcGFyYW0ge1Rlc3RPcHRpb25zIHwgVGVzdEZ1bmN0aW9ufSBbb3B0aW9uc09yRm5dIC0gT3B0aW9uYWwuIFRoZSB0ZXN0IG9wdGlvbnMgb3IgdGhlIHRlc3QgZnVuY3Rpb24gaWYgbm8gZXhwbGljaXQgbmFtZSBpcyBwcm92aWRlZC5cbiogQHBhcmFtIHtudW1iZXIgfCBUZXN0T3B0aW9ucyB8IFRlc3RGdW5jdGlvbn0gW29wdGlvbnNPclRlc3RdIC0gT3B0aW9uYWwuIFRoZSB0ZXN0IGZ1bmN0aW9uIG9yIG9wdGlvbnMsIGRlcGVuZGluZyBvbiB0aGUgcHJldmlvdXMgcGFyYW1ldGVycy5cbiogQHRocm93cyB7RXJyb3J9IElmIGNhbGxlZCBpbnNpZGUgYW5vdGhlciB0ZXN0IGZ1bmN0aW9uLlxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBEZWZpbmUgYSBzaW1wbGUgdGVzdFxuKiB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgIGV4cGVjdChhZGQoMSwgMikpLnRvQmUoMyk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgdGVzdCB3aXRoIG9wdGlvbnNcbiogdGVzdCgnc2hvdWxkIHN1YnRyYWN0IHR3byBudW1iZXJzJywgeyByZXRyeTogMyB9LCAoKSA9PiB7XG4qICAgZXhwZWN0KHN1YnRyYWN0KDUsIDIpKS50b0JlKDMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpIHtcblx0aWYgKGdldEN1cnJlbnRUZXN0KCkpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoXCJDYWxsaW5nIHRoZSB0ZXN0IGZ1bmN0aW9uIGluc2lkZSBhbm90aGVyIHRlc3QgZnVuY3Rpb24gaXMgbm90IGFsbG93ZWQuIFBsZWFzZSBwdXQgaXQgaW5zaWRlIFxcXCJkZXNjcmliZVxcXCIgb3IgXFxcInN1aXRlXFxcIiBzbyBpdCBjYW4gYmUgcHJvcGVybHkgY29sbGVjdGVkLlwiKTtcblx0fVxuXHRnZXRDdXJyZW50U3VpdGUoKS50ZXN0LmZuLmNhbGwodGhpcywgZm9ybWF0TmFtZShuYW1lKSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpO1xufSk7XG4vKipcbiogQ3JlYXRlcyBhIHN1aXRlIG9mIHRlc3RzLCBhbGxvd2luZyBmb3IgZ3JvdXBpbmcgYW5kIGhpZXJhcmNoaWNhbCBvcmdhbml6YXRpb24gb2YgdGVzdHMuXG4qIFN1aXRlcyBjYW4gY29udGFpbiBib3RoIHRlc3RzIGFuZCBvdGhlciBzdWl0ZXMsIGVuYWJsaW5nIGNvbXBsZXggdGVzdCBzdHJ1Y3R1cmVzLlxuKlxuKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBzdWl0ZSwgdXNlZCBmb3IgaWRlbnRpZmljYXRpb24gYW5kIHJlcG9ydGluZy5cbiogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBBIGZ1bmN0aW9uIHRoYXQgZGVmaW5lcyB0aGUgdGVzdHMgYW5kIHN1aXRlcyB3aXRoaW4gdGhpcyBzdWl0ZS5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc3VpdGUgd2l0aCB0d28gdGVzdHNcbiogZGVzY3JpYmUoJ01hdGggb3BlcmF0aW9ucycsICgpID0+IHtcbiogICB0ZXN0KCdzaG91bGQgYWRkIHR3byBudW1iZXJzJywgKCkgPT4ge1xuKiAgICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogICB9KTtcbipcbiogICB0ZXN0KCdzaG91bGQgc3VidHJhY3QgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgICBleHBlY3Qoc3VidHJhY3QoNSwgMikpLnRvQmUoMyk7XG4qICAgfSk7XG4qIH0pO1xuKiBgYGBcbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIG5lc3RlZCBzdWl0ZXNcbiogZGVzY3JpYmUoJ1N0cmluZyBvcGVyYXRpb25zJywgKCkgPT4ge1xuKiAgIGRlc2NyaWJlKCdUcmltbWluZycsICgpID0+IHtcbiogICAgIHRlc3QoJ3Nob3VsZCB0cmltIHdoaXRlc3BhY2UgZnJvbSBzdGFydCBhbmQgZW5kJywgKCkgPT4ge1xuKiAgICAgICBleHBlY3QoJyAgaGVsbG8gICcudHJpbSgpKS50b0JlKCdoZWxsbycpO1xuKiAgICAgfSk7XG4qICAgfSk7XG4qXG4qICAgZGVzY3JpYmUoJ0NvbmNhdGVuYXRpb24nLCAoKSA9PiB7XG4qICAgICB0ZXN0KCdzaG91bGQgY29uY2F0ZW5hdGUgdHdvIHN0cmluZ3MnLCAoKSA9PiB7XG4qICAgICAgIGV4cGVjdCgnaGVsbG8nICsgJyAnICsgJ3dvcmxkJykudG9CZSgnaGVsbG8gd29ybGQnKTtcbiogICAgIH0pO1xuKiAgIH0pO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgZGVzY3JpYmUgPSBzdWl0ZTtcbi8qKlxuKiBEZWZpbmVzIGEgdGVzdCBjYXNlIHdpdGggYSBnaXZlbiBuYW1lIGFuZCB0ZXN0IGZ1bmN0aW9uLiBUaGUgdGVzdCBmdW5jdGlvbiBjYW4gb3B0aW9uYWxseSBiZSBjb25maWd1cmVkIHdpdGggdGVzdCBvcHRpb25zLlxuKlxuKiBAcGFyYW0ge3N0cmluZyB8IEZ1bmN0aW9ufSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRlc3Qgb3IgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgdXNlZCBhcyBhIHRlc3QgbmFtZS5cbiogQHBhcmFtIHtUZXN0T3B0aW9ucyB8IFRlc3RGdW5jdGlvbn0gW29wdGlvbnNPckZuXSAtIE9wdGlvbmFsLiBUaGUgdGVzdCBvcHRpb25zIG9yIHRoZSB0ZXN0IGZ1bmN0aW9uIGlmIG5vIGV4cGxpY2l0IG5hbWUgaXMgcHJvdmlkZWQuXG4qIEBwYXJhbSB7bnVtYmVyIHwgVGVzdE9wdGlvbnMgfCBUZXN0RnVuY3Rpb259IFtvcHRpb25zT3JUZXN0XSAtIE9wdGlvbmFsLiBUaGUgdGVzdCBmdW5jdGlvbiBvciBvcHRpb25zLCBkZXBlbmRpbmcgb24gdGhlIHByZXZpb3VzIHBhcmFtZXRlcnMuXG4qIEB0aHJvd3Mge0Vycm9yfSBJZiBjYWxsZWQgaW5zaWRlIGFub3RoZXIgdGVzdCBmdW5jdGlvbi5cbiogQGV4YW1wbGVcbiogYGBgdHNcbiogLy8gRGVmaW5lIGEgc2ltcGxlIHRlc3RcbiogaXQoJ2FkZHMgdHdvIG51bWJlcnMnLCAoKSA9PiB7XG4qICAgZXhwZWN0KGFkZCgxLCAyKSkudG9CZSgzKTtcbiogfSk7XG4qIGBgYFxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBEZWZpbmUgYSB0ZXN0IHdpdGggb3B0aW9uc1xuKiBpdCgnc3VidHJhY3RzIHR3byBudW1iZXJzJywgeyByZXRyeTogMyB9LCAoKSA9PiB7XG4qICAgZXhwZWN0KHN1YnRyYWN0KDUsIDIpKS50b0JlKDMpO1xuKiB9KTtcbiogYGBgXG4qL1xuY29uc3QgaXQgPSB0ZXN0O1xubGV0IHJ1bm5lcjtcbmxldCBkZWZhdWx0U3VpdGU7XG5sZXQgY3VycmVudFRlc3RGaWxlcGF0aDtcbmZ1bmN0aW9uIGFzc2VydChjb25kaXRpb24sIG1lc3NhZ2UpIHtcblx0aWYgKCFjb25kaXRpb24pIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYFZpdGVzdCBmYWlsZWQgdG8gZmluZCAke21lc3NhZ2V9LiBPbmUgb2YgdGhlIGZvbGxvd2luZyBpcyBwb3NzaWJsZTpgICsgXCJcXG4tIFxcXCJ2aXRlc3RcXFwiIGlzIGltcG9ydGVkIGRpcmVjdGx5IHdpdGhvdXQgcnVubmluZyBcXFwidml0ZXN0XFxcIiBjb21tYW5kXCIgKyBcIlxcbi0gXFxcInZpdGVzdFxcXCIgaXMgaW1wb3J0ZWQgaW5zaWRlIFxcXCJnbG9iYWxTZXR1cFxcXCIgKHRvIGZpeCB0aGlzLCB1c2UgXFxcInNldHVwRmlsZXNcXFwiIGluc3RlYWQsIGJlY2F1c2UgXFxcImdsb2JhbFNldHVwXFxcIiBydW5zIGluIGEgZGlmZmVyZW50IGNvbnRleHQpXCIgKyBcIlxcbi0gXFxcInZpdGVzdFxcXCIgaXMgaW1wb3J0ZWQgaW5zaWRlIFZpdGUgLyBWaXRlc3QgY29uZmlnIGZpbGVcIiArIFwiXFxuLSBPdGhlcndpc2UsIGl0IG1pZ2h0IGJlIGEgVml0ZXN0IGJ1Zy4gUGxlYXNlIHJlcG9ydCBpdCB0byBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvaXNzdWVzXFxuXCIpO1xuXHR9XG59XG5mdW5jdGlvbiBnZXREZWZhdWx0U3VpdGUoKSB7XG5cdGFzc2VydChkZWZhdWx0U3VpdGUsIFwidGhlIGRlZmF1bHQgc3VpdGVcIik7XG5cdHJldHVybiBkZWZhdWx0U3VpdGU7XG59XG5mdW5jdGlvbiBnZXRSdW5uZXIoKSB7XG5cdGFzc2VydChydW5uZXIsIFwidGhlIHJ1bm5lclwiKTtcblx0cmV0dXJuIHJ1bm5lcjtcbn1cbmZ1bmN0aW9uIGNyZWF0ZURlZmF1bHRTdWl0ZShydW5uZXIpIHtcblx0Y29uc3QgY29uZmlnID0gcnVubmVyLmNvbmZpZy5zZXF1ZW5jZTtcblx0Y29uc3Qgb3B0aW9ucyA9IHt9O1xuXHRpZiAoY29uZmlnLmNvbmN1cnJlbnQgIT0gbnVsbCkge1xuXHRcdG9wdGlvbnMuY29uY3VycmVudCA9IGNvbmZpZy5jb25jdXJyZW50O1xuXHR9XG5cdGNvbnN0IGNvbGxlY3RvciA9IHN1aXRlKFwiXCIsIG9wdGlvbnMsICgpID0+IHt9KTtcblx0Ly8gbm8gcGFyZW50IHN1aXRlIGZvciB0b3AtbGV2ZWwgdGVzdHNcblx0ZGVsZXRlIGNvbGxlY3Rvci5zdWl0ZTtcblx0cmV0dXJuIGNvbGxlY3Rvcjtcbn1cbmZ1bmN0aW9uIGNsZWFyQ29sbGVjdG9yQ29udGV4dChmaWxlLCBjdXJyZW50UnVubmVyKSB7XG5cdGN1cnJlbnRUZXN0RmlsZXBhdGggPSBmaWxlLmZpbGVwYXRoO1xuXHRydW5uZXIgPSBjdXJyZW50UnVubmVyO1xuXHRpZiAoIWRlZmF1bHRTdWl0ZSkge1xuXHRcdGRlZmF1bHRTdWl0ZSA9IGNyZWF0ZURlZmF1bHRTdWl0ZShjdXJyZW50UnVubmVyKTtcblx0fVxuXHRkZWZhdWx0U3VpdGUuZmlsZSA9IGZpbGU7XG5cdGNvbGxlY3RvckNvbnRleHQudGFza3MubGVuZ3RoID0gMDtcblx0ZGVmYXVsdFN1aXRlLmNsZWFyKCk7XG5cdGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlID0gZGVmYXVsdFN1aXRlO1xufVxuZnVuY3Rpb24gZ2V0Q3VycmVudFN1aXRlKCkge1xuXHRjb25zdCBjdXJyZW50U3VpdGUgPSBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSB8fCBkZWZhdWx0U3VpdGU7XG5cdGFzc2VydChjdXJyZW50U3VpdGUsIFwidGhlIGN1cnJlbnQgc3VpdGVcIik7XG5cdHJldHVybiBjdXJyZW50U3VpdGU7XG59XG5mdW5jdGlvbiBjcmVhdGVTdWl0ZUhvb2tzKCkge1xuXHRyZXR1cm4ge1xuXHRcdGJlZm9yZUFsbDogW10sXG5cdFx0YWZ0ZXJBbGw6IFtdLFxuXHRcdGJlZm9yZUVhY2g6IFtdLFxuXHRcdGFmdGVyRWFjaDogW10sXG5cdFx0YXJvdW5kRWFjaDogW10sXG5cdFx0YXJvdW5kQWxsOiBbXVxuXHR9O1xufVxuY29uc3QgUE9TSVRJVkVfSU5GSU5JVFkgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7XG5mdW5jdGlvbiBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgdGltZW91dE9yVGVzdCkge1xuXHRpZiAodGltZW91dE9yVGVzdCAhPSBudWxsICYmIHR5cGVvZiB0aW1lb3V0T3JUZXN0ID09PSBcIm9iamVjdFwiKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgU2lnbmF0dXJlIFwidGVzdChuYW1lLCBmbiwgeyAuLi4gfSlcIiB3YXMgZGVwcmVjYXRlZCBpbiBWaXRlc3QgMyBhbmQgcmVtb3ZlZCBpbiBWaXRlc3QgNC4gUGxlYXNlLCBwcm92aWRlIG9wdGlvbnMgYXMgYSBzZWNvbmQgYXJndW1lbnQgaW5zdGVhZC5gKTtcblx0fVxuXHRsZXQgb3B0aW9ucyA9IHt9O1xuXHRsZXQgZm47XG5cdC8vIGl0KCcnLCAoKSA9PiB7fSwgMTAwMClcblx0aWYgKHR5cGVvZiB0aW1lb3V0T3JUZXN0ID09PSBcIm51bWJlclwiKSB7XG5cdFx0b3B0aW9ucyA9IHsgdGltZW91dDogdGltZW91dE9yVGVzdCB9O1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBvcHRpb25zT3JGbiA9PT0gXCJvYmplY3RcIikge1xuXHRcdG9wdGlvbnMgPSBvcHRpb25zT3JGbjtcblx0fVxuXHRpZiAodHlwZW9mIG9wdGlvbnNPckZuID09PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRpZiAodHlwZW9mIHRpbWVvdXRPclRlc3QgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihcIkNhbm5vdCB1c2UgdHdvIGZ1bmN0aW9ucyBhcyBhcmd1bWVudHMuIFBsZWFzZSB1c2UgdGhlIHNlY29uZCBhcmd1bWVudCBmb3Igb3B0aW9ucy5cIik7XG5cdFx0fVxuXHRcdGZuID0gb3B0aW9uc09yRm47XG5cdH0gZWxzZSBpZiAodHlwZW9mIHRpbWVvdXRPclRlc3QgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdGZuID0gdGltZW91dE9yVGVzdDtcblx0fVxuXHRyZXR1cm4ge1xuXHRcdG9wdGlvbnMsXG5cdFx0aGFuZGxlcjogZm5cblx0fTtcbn1cbi8vIGltcGxlbWVudGF0aW9uc1xuZnVuY3Rpb24gY3JlYXRlU3VpdGVDb2xsZWN0b3IobmFtZSwgZmFjdG9yeSA9ICgpID0+IHt9LCBtb2RlLCBlYWNoLCBzdWl0ZU9wdGlvbnMpIHtcblx0Y29uc3QgdGFza3MgPSBbXTtcblx0bGV0IHN1aXRlO1xuXHRpbml0U3VpdGUodHJ1ZSk7XG5cdGNvbnN0IHRhc2sgPSBmdW5jdGlvbihuYW1lID0gXCJcIiwgb3B0aW9ucyA9IHt9KSB7XG5cdFx0Y29uc3QgY3VycmVudFN1aXRlID0gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LnN1aXRlO1xuXHRcdGNvbnN0IHBhcmVudFRhc2sgPSBjdXJyZW50U3VpdGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGU7XG5cdFx0Y29uc3QgcGFyZW50VGFncyA9IHBhcmVudFRhc2s/LnRhZ3MgfHwgW107XG5cdFx0Y29uc3QgdGVzdFRhZ3MgPSB1bmlxdWUoWy4uLnBhcmVudFRhZ3MsIC4uLnRvQXJyYXkob3B0aW9ucy50YWdzKV0pO1xuXHRcdGNvbnN0IHRhZ3NPcHRpb25zID0gdGVzdFRhZ3MubWFwKCh0YWcpID0+IHtcblx0XHRcdGNvbnN0IHRhZ0RlZmluaXRpb24gPSBydW5uZXIuY29uZmlnLnRhZ3M/LmZpbmQoKHQpID0+IHQubmFtZSA9PT0gdGFnKTtcblx0XHRcdGlmICghdGFnRGVmaW5pdGlvbiAmJiBydW5uZXIuY29uZmlnLnN0cmljdFRhZ3MpIHtcblx0XHRcdFx0dGhyb3cgY3JlYXRlTm9UYWdzRXJyb3IocnVubmVyLmNvbmZpZy50YWdzLCB0YWcpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRhZ0RlZmluaXRpb247XG5cdFx0fSkuZmlsdGVyKChyKSA9PiByICE9IG51bGwpLnNvcnQoKHRhZzEsIHRhZzIpID0+ICh0YWcyLnByaW9yaXR5ID8/IFBPU0lUSVZFX0lORklOSVRZKSAtICh0YWcxLnByaW9yaXR5ID8/IFBPU0lUSVZFX0lORklOSVRZKSkucmVkdWNlKChhY2MsIHRhZykgPT4ge1xuXHRcdFx0Y29uc3QgeyBuYW1lLCBkZXNjcmlwdGlvbiwgcHJpb3JpdHksIG1ldGEsIC4uLm9wdGlvbnMgfSA9IHRhZztcblx0XHRcdE9iamVjdC5hc3NpZ24oYWNjLCBvcHRpb25zKTtcblx0XHRcdGlmIChtZXRhKSB7XG5cdFx0XHRcdGFjYy5tZXRhID0gT2JqZWN0LmFzc2lnbihhY2MubWV0YSA/PyBPYmplY3QuY3JlYXRlKG51bGwpLCBtZXRhKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBhY2M7XG5cdFx0fSwge30pO1xuXHRcdGNvbnN0IHRlc3RPd25NZXRhID0gb3B0aW9ucy5tZXRhO1xuXHRcdG9wdGlvbnMgPSB7XG5cdFx0XHQuLi50YWdzT3B0aW9ucyxcblx0XHRcdC4uLm9wdGlvbnNcblx0XHR9O1xuXHRcdGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgPz8gcnVubmVyLmNvbmZpZy50ZXN0VGltZW91dDtcblx0XHRjb25zdCBwYXJlbnRNZXRhID0gY3VycmVudFN1aXRlPy5tZXRhO1xuXHRcdGNvbnN0IHRhZ01ldGEgPSB0YWdzT3B0aW9ucy5tZXRhO1xuXHRcdGNvbnN0IHRlc3RNZXRhID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcblx0XHRpZiAodGFnTWV0YSkge1xuXHRcdFx0T2JqZWN0LmFzc2lnbih0ZXN0TWV0YSwgdGFnTWV0YSk7XG5cdFx0fVxuXHRcdGlmIChwYXJlbnRNZXRhKSB7XG5cdFx0XHRPYmplY3QuYXNzaWduKHRlc3RNZXRhLCBwYXJlbnRNZXRhKTtcblx0XHR9XG5cdFx0aWYgKHRlc3RPd25NZXRhKSB7XG5cdFx0XHRPYmplY3QuYXNzaWduKHRlc3RNZXRhLCB0ZXN0T3duTWV0YSk7XG5cdFx0fVxuXHRcdGNvbnN0IHRhc2sgPSB7XG5cdFx0XHRpZDogXCJcIixcblx0XHRcdG5hbWUsXG5cdFx0XHRmdWxsTmFtZTogY3JlYXRlVGFza05hbWUoW2N1cnJlbnRTdWl0ZT8uZnVsbE5hbWUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGU/LmZ1bGxOYW1lLCBuYW1lXSksXG5cdFx0XHRmdWxsVGVzdE5hbWU6IGNyZWF0ZVRhc2tOYW1lKFtjdXJyZW50U3VpdGU/LmZ1bGxUZXN0TmFtZSwgbmFtZV0pLFxuXHRcdFx0c3VpdGU6IGN1cnJlbnRTdWl0ZSxcblx0XHRcdGVhY2g6IG9wdGlvbnMuZWFjaCxcblx0XHRcdGZhaWxzOiBvcHRpb25zLmZhaWxzLFxuXHRcdFx0Y29udGV4dDogdW5kZWZpbmVkLFxuXHRcdFx0dHlwZTogXCJ0ZXN0XCIsXG5cdFx0XHRmaWxlOiBjdXJyZW50U3VpdGU/LmZpbGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGUsXG5cdFx0XHR0aW1lb3V0LFxuXHRcdFx0cmV0cnk6IG9wdGlvbnMucmV0cnkgPz8gcnVubmVyLmNvbmZpZy5yZXRyeSxcblx0XHRcdHJlcGVhdHM6IG9wdGlvbnMucmVwZWF0cyxcblx0XHRcdG1vZGU6IG9wdGlvbnMub25seSA/IFwib25seVwiIDogb3B0aW9ucy5za2lwID8gXCJza2lwXCIgOiBvcHRpb25zLnRvZG8gPyBcInRvZG9cIiA6IFwicnVuXCIsXG5cdFx0XHRtZXRhOiB0ZXN0TWV0YSxcblx0XHRcdGFubm90YXRpb25zOiBbXSxcblx0XHRcdGFydGlmYWN0czogW10sXG5cdFx0XHR0YWdzOiB0ZXN0VGFnc1xuXHRcdH07XG5cdFx0Y29uc3QgaGFuZGxlciA9IG9wdGlvbnMuaGFuZGxlcjtcblx0XHRpZiAodGFzay5tb2RlID09PSBcInJ1blwiICYmICFoYW5kbGVyKSB7XG5cdFx0XHR0YXNrLm1vZGUgPSBcInRvZG9cIjtcblx0XHR9XG5cdFx0aWYgKG9wdGlvbnMuY29uY3VycmVudCA/PyAoIW9wdGlvbnMuc2VxdWVudGlhbCAmJiBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmNvbmN1cnJlbnQpKSB7XG5cdFx0XHR0YXNrLmNvbmN1cnJlbnQgPSB0cnVlO1xuXHRcdH1cblx0XHR0YXNrLnNodWZmbGUgPSBzdWl0ZU9wdGlvbnM/LnNodWZmbGU7XG5cdFx0Y29uc3QgY29udGV4dCA9IGNyZWF0ZVRlc3RDb250ZXh0KHRhc2ssIHJ1bm5lcik7XG5cdFx0Ly8gY3JlYXRlIHRlc3QgY29udGV4dFxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXNrLCBcImNvbnRleHRcIiwge1xuXHRcdFx0dmFsdWU6IGNvbnRleHQsXG5cdFx0XHRlbnVtZXJhYmxlOiBmYWxzZVxuXHRcdH0pO1xuXHRcdHNldFRlc3RGaXh0dXJlKGNvbnRleHQsIG9wdGlvbnMuZml4dHVyZXMgPz8gbmV3IFRlc3RGaXh0dXJlcygpKTtcblx0XHRjb25zdCBsaW1pdCA9IEVycm9yLnN0YWNrVHJhY2VMaW1pdDtcblx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSAxMDtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRV9FUlJPUlwiKTtcblx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSBsaW1pdDtcblx0XHRpZiAoaGFuZGxlcikge1xuXHRcdFx0c2V0Rm4odGFzaywgd2l0aFRpbWVvdXQod2l0aENhbmNlbCh3aXRoQXdhaXRBc3luY0Fzc2VydGlvbnMod2l0aEZpeHR1cmVzKGhhbmRsZXIsIHsgY29udGV4dCB9KSwgdGFzayksIHRhc2suY29udGV4dC5zaWduYWwpLCB0aW1lb3V0LCBmYWxzZSwgc3RhY2tUcmFjZUVycm9yLCAoXywgZXJyb3IpID0+IGFib3J0SWZUaW1lb3V0KFtjb250ZXh0XSwgZXJyb3IpKSk7XG5cdFx0fVxuXHRcdGlmIChydW5uZXIuY29uZmlnLmluY2x1ZGVUYXNrTG9jYXRpb24pIHtcblx0XHRcdGNvbnN0IGVycm9yID0gc3RhY2tUcmFjZUVycm9yLnN0YWNrO1xuXHRcdFx0Y29uc3Qgc3RhY2sgPSBmaW5kVGVzdEZpbGVTdGFja1RyYWNlKGN1cnJlbnRUZXN0RmlsZXBhdGgsIGVycm9yKTtcblx0XHRcdGlmIChzdGFjaykge1xuXHRcdFx0XHR0YXNrLmxvY2F0aW9uID0ge1xuXHRcdFx0XHRcdGxpbmU6IHN0YWNrLmxpbmUsXG5cdFx0XHRcdFx0Y29sdW1uOiBzdGFjay5jb2x1bW5cblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGFza3MucHVzaCh0YXNrKTtcblx0XHRyZXR1cm4gdGFzaztcblx0fTtcblx0Y29uc3QgdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIHRpbWVvdXRPclRlc3QpIHtcblx0XHRsZXQgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgdGltZW91dE9yVGVzdCk7XG5cdFx0Ly8gaW5oZXJpdCByZXBlYXRzLCByZXRyeSwgdGltZW91dCBmcm9tIHN1aXRlXG5cdFx0aWYgKHR5cGVvZiBzdWl0ZU9wdGlvbnMgPT09IFwib2JqZWN0XCIpIHtcblx0XHRcdG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHt9LCBzdWl0ZU9wdGlvbnMsIG9wdGlvbnMpO1xuXHRcdH1cblx0XHQvLyBpbmhlcml0IGNvbmN1cnJlbnQgLyBzZXF1ZW50aWFsIGZyb20gc3VpdGVcblx0XHRjb25zdCBjb25jdXJyZW50ID0gdGhpcy5jb25jdXJyZW50ID8/ICghdGhpcy5zZXF1ZW50aWFsICYmIG9wdGlvbnM/LmNvbmN1cnJlbnQpO1xuXHRcdGlmIChvcHRpb25zLmNvbmN1cnJlbnQgIT0gbnVsbCAmJiBjb25jdXJyZW50ICE9IG51bGwpIHtcblx0XHRcdG9wdGlvbnMuY29uY3VycmVudCA9IGNvbmN1cnJlbnQ7XG5cdFx0fVxuXHRcdGNvbnN0IHNlcXVlbnRpYWwgPSB0aGlzLnNlcXVlbnRpYWwgPz8gKCF0aGlzLmNvbmN1cnJlbnQgJiYgb3B0aW9ucz8uc2VxdWVudGlhbCk7XG5cdFx0aWYgKG9wdGlvbnMuc2VxdWVudGlhbCAhPSBudWxsICYmIHNlcXVlbnRpYWwgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5zZXF1ZW50aWFsID0gc2VxdWVudGlhbDtcblx0XHR9XG5cdFx0Y29uc3QgdGVzdCA9IHRhc2soZm9ybWF0TmFtZShuYW1lKSwge1xuXHRcdFx0Li4udGhpcyxcblx0XHRcdC4uLm9wdGlvbnMsXG5cdFx0XHRoYW5kbGVyXG5cdFx0fSk7XG5cdFx0dGVzdC50eXBlID0gXCJ0ZXN0XCI7XG5cdH0pO1xuXHRjb25zdCBjb2xsZWN0b3IgPSB7XG5cdFx0dHlwZTogXCJjb2xsZWN0b3JcIixcblx0XHRuYW1lLFxuXHRcdG1vZGUsXG5cdFx0c3VpdGUsXG5cdFx0b3B0aW9uczogc3VpdGVPcHRpb25zLFxuXHRcdHRlc3QsXG5cdFx0ZmlsZTogc3VpdGUuZmlsZSxcblx0XHR0YXNrcyxcblx0XHRjb2xsZWN0LFxuXHRcdHRhc2ssXG5cdFx0Y2xlYXIsXG5cdFx0b246IGFkZEhvb2tcblx0fTtcblx0ZnVuY3Rpb24gYWRkSG9vayhuYW1lLCAuLi5mbikge1xuXHRcdGdldEhvb2tzKHN1aXRlKVtuYW1lXS5wdXNoKC4uLmZuKTtcblx0fVxuXHRmdW5jdGlvbiBpbml0U3VpdGUoaW5jbHVkZUxvY2F0aW9uKSB7XG5cdFx0aWYgKHR5cGVvZiBzdWl0ZU9wdGlvbnMgPT09IFwibnVtYmVyXCIpIHtcblx0XHRcdHN1aXRlT3B0aW9ucyA9IHsgdGltZW91dDogc3VpdGVPcHRpb25zIH07XG5cdFx0fVxuXHRcdGNvbnN0IGN1cnJlbnRTdWl0ZSA9IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlPy5zdWl0ZTtcblx0XHRjb25zdCBwYXJlbnRUYXNrID0gY3VycmVudFN1aXRlID8/IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlPy5maWxlO1xuXHRcdGNvbnN0IHN1aXRlVGFncyA9IHRvQXJyYXkoc3VpdGVPcHRpb25zPy50YWdzKTtcblx0XHR2YWxpZGF0ZVRhZ3MocnVubmVyLmNvbmZpZywgc3VpdGVUYWdzKTtcblx0XHRzdWl0ZSA9IHtcblx0XHRcdGlkOiBcIlwiLFxuXHRcdFx0dHlwZTogXCJzdWl0ZVwiLFxuXHRcdFx0bmFtZSxcblx0XHRcdGZ1bGxOYW1lOiBjcmVhdGVUYXNrTmFtZShbY3VycmVudFN1aXRlPy5mdWxsTmFtZSA/PyBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZT8uZmlsZT8uZnVsbE5hbWUsIG5hbWVdKSxcblx0XHRcdGZ1bGxUZXN0TmFtZTogY3JlYXRlVGFza05hbWUoW2N1cnJlbnRTdWl0ZT8uZnVsbFRlc3ROYW1lLCBuYW1lXSksXG5cdFx0XHRzdWl0ZTogY3VycmVudFN1aXRlLFxuXHRcdFx0bW9kZSxcblx0XHRcdGVhY2gsXG5cdFx0XHRmaWxlOiBjdXJyZW50U3VpdGU/LmZpbGUgPz8gY29sbGVjdG9yQ29udGV4dC5jdXJyZW50U3VpdGU/LmZpbGUsXG5cdFx0XHRzaHVmZmxlOiBzdWl0ZU9wdGlvbnM/LnNodWZmbGUsXG5cdFx0XHR0YXNrczogW10sXG5cdFx0XHRtZXRhOiBzdWl0ZU9wdGlvbnM/Lm1ldGEgPz8gT2JqZWN0LmNyZWF0ZShudWxsKSxcblx0XHRcdGNvbmN1cnJlbnQ6IHN1aXRlT3B0aW9ucz8uY29uY3VycmVudCxcblx0XHRcdHRhZ3M6IHVuaXF1ZShbLi4ucGFyZW50VGFzaz8udGFncyB8fCBbXSwgLi4uc3VpdGVUYWdzXSlcblx0XHR9O1xuXHRcdGlmIChydW5uZXIgJiYgaW5jbHVkZUxvY2F0aW9uICYmIHJ1bm5lci5jb25maWcuaW5jbHVkZVRhc2tMb2NhdGlvbikge1xuXHRcdFx0Y29uc3QgbGltaXQgPSBFcnJvci5zdGFja1RyYWNlTGltaXQ7XG5cdFx0XHRFcnJvci5zdGFja1RyYWNlTGltaXQgPSAxNTtcblx0XHRcdGNvbnN0IGVycm9yID0gbmV3IEVycm9yKFwic3RhY2t0cmFjZVwiKS5zdGFjaztcblx0XHRcdEVycm9yLnN0YWNrVHJhY2VMaW1pdCA9IGxpbWl0O1xuXHRcdFx0Y29uc3Qgc3RhY2sgPSBmaW5kVGVzdEZpbGVTdGFja1RyYWNlKGN1cnJlbnRUZXN0RmlsZXBhdGgsIGVycm9yKTtcblx0XHRcdGlmIChzdGFjaykge1xuXHRcdFx0XHRzdWl0ZS5sb2NhdGlvbiA9IHtcblx0XHRcdFx0XHRsaW5lOiBzdGFjay5saW5lLFxuXHRcdFx0XHRcdGNvbHVtbjogc3RhY2suY29sdW1uXG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHNldEhvb2tzKHN1aXRlLCBjcmVhdGVTdWl0ZUhvb2tzKCkpO1xuXHR9XG5cdGZ1bmN0aW9uIGNsZWFyKCkge1xuXHRcdHRhc2tzLmxlbmd0aCA9IDA7XG5cdFx0aW5pdFN1aXRlKGZhbHNlKTtcblx0fVxuXHRhc3luYyBmdW5jdGlvbiBjb2xsZWN0KGZpbGUpIHtcblx0XHRpZiAoIWZpbGUpIHtcblx0XHRcdHRocm93IG5ldyBUeXBlRXJyb3IoXCJGaWxlIGlzIHJlcXVpcmVkIHRvIGNvbGxlY3QgdGFza3MuXCIpO1xuXHRcdH1cblx0XHRpZiAoZmFjdG9yeSkge1xuXHRcdFx0YXdhaXQgcnVuV2l0aFN1aXRlKGNvbGxlY3RvciwgKCkgPT4gZmFjdG9yeSh0ZXN0KSk7XG5cdFx0fVxuXHRcdGNvbnN0IGFsbENoaWxkcmVuID0gW107XG5cdFx0Zm9yIChjb25zdCBpIG9mIHRhc2tzKSB7XG5cdFx0XHRhbGxDaGlsZHJlbi5wdXNoKGkudHlwZSA9PT0gXCJjb2xsZWN0b3JcIiA/IGF3YWl0IGkuY29sbGVjdChmaWxlKSA6IGkpO1xuXHRcdH1cblx0XHRzdWl0ZS50YXNrcyA9IGFsbENoaWxkcmVuO1xuXHRcdHJldHVybiBzdWl0ZTtcblx0fVxuXHRjb2xsZWN0VGFzayhjb2xsZWN0b3IpO1xuXHRyZXR1cm4gY29sbGVjdG9yO1xufVxuZnVuY3Rpb24gd2l0aEF3YWl0QXN5bmNBc3NlcnRpb25zKGZuLCB0YXNrKSB7XG5cdHJldHVybiAoYXN5bmMgKC4uLmFyZ3MpID0+IHtcblx0XHRjb25zdCBmblJlc3VsdCA9IGF3YWl0IGZuKC4uLmFyZ3MpO1xuXHRcdC8vIHNvbWUgYXN5bmMgZXhwZWN0IHdpbGwgYmUgYWRkZWQgdG8gdGhpcyBhcnJheSwgaW4gY2FzZSB1c2VyIGZvcmdldCB0byBhd2FpdCB0aGVtXG5cdFx0aWYgKHRhc2sucHJvbWlzZXMpIHtcblx0XHRcdGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZCh0YXNrLnByb21pc2VzKTtcblx0XHRcdGNvbnN0IGVycm9ycyA9IHJlc3VsdC5tYXAoKHIpID0+IHIuc3RhdHVzID09PSBcInJlamVjdGVkXCIgPyByLnJlYXNvbiA6IHVuZGVmaW5lZCkuZmlsdGVyKEJvb2xlYW4pO1xuXHRcdFx0aWYgKGVycm9ycy5sZW5ndGgpIHtcblx0XHRcdFx0dGhyb3cgZXJyb3JzO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZm5SZXN1bHQ7XG5cdH0pO1xufVxuZnVuY3Rpb24gY3JlYXRlU3VpdGUoKSB7XG5cdGZ1bmN0aW9uIHN1aXRlRm4obmFtZSwgZmFjdG9yeU9yT3B0aW9ucywgb3B0aW9uc09yRmFjdG9yeSkge1xuXHRcdGlmIChnZXRDdXJyZW50VGVzdCgpKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJDYWxsaW5nIHRoZSBzdWl0ZSBmdW5jdGlvbiBpbnNpZGUgdGVzdCBmdW5jdGlvbiBpcyBub3QgYWxsb3dlZC4gSXQgY2FuIGJlIG9ubHkgY2FsbGVkIGF0IHRoZSB0b3AgbGV2ZWwgb3IgaW5zaWRlIGFub3RoZXIgc3VpdGUgZnVuY3Rpb24uXCIpO1xuXHRcdH1cblx0XHRjb25zdCBjdXJyZW50U3VpdGUgPSBjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSB8fCBkZWZhdWx0U3VpdGU7XG5cdFx0bGV0IHsgb3B0aW9ucywgaGFuZGxlcjogZmFjdG9yeSB9ID0gcGFyc2VBcmd1bWVudHMoZmFjdG9yeU9yT3B0aW9ucywgb3B0aW9uc09yRmFjdG9yeSk7XG5cdFx0Y29uc3QgaXNDb25jdXJyZW50U3BlY2lmaWVkID0gb3B0aW9ucy5jb25jdXJyZW50IHx8IHRoaXMuY29uY3VycmVudCB8fCBvcHRpb25zLnNlcXVlbnRpYWwgPT09IGZhbHNlO1xuXHRcdGNvbnN0IGlzU2VxdWVudGlhbFNwZWNpZmllZCA9IG9wdGlvbnMuc2VxdWVudGlhbCB8fCB0aGlzLnNlcXVlbnRpYWwgfHwgb3B0aW9ucy5jb25jdXJyZW50ID09PSBmYWxzZTtcblx0XHRjb25zdCB7IG1ldGE6IHBhcmVudE1ldGEsIC4uLnBhcmVudE9wdGlvbnMgfSA9IGN1cnJlbnRTdWl0ZT8ub3B0aW9ucyB8fCB7fTtcblx0XHQvLyBpbmhlcml0IG9wdGlvbnMgZnJvbSBjdXJyZW50IHN1aXRlXG5cdFx0b3B0aW9ucyA9IHtcblx0XHRcdC4uLnBhcmVudE9wdGlvbnMsXG5cdFx0XHQuLi5vcHRpb25zXG5cdFx0fTtcblx0XHRjb25zdCBzaHVmZmxlID0gdGhpcy5zaHVmZmxlID8/IG9wdGlvbnMuc2h1ZmZsZSA/PyBjdXJyZW50U3VpdGU/Lm9wdGlvbnM/LnNodWZmbGUgPz8gcnVubmVyPy5jb25maWcuc2VxdWVuY2Uuc2h1ZmZsZTtcblx0XHRpZiAoc2h1ZmZsZSAhPSBudWxsKSB7XG5cdFx0XHRvcHRpb25zLnNodWZmbGUgPSBzaHVmZmxlO1xuXHRcdH1cblx0XHRsZXQgbW9kZSA9IHRoaXMub25seSA/PyBvcHRpb25zLm9ubHkgPyBcIm9ubHlcIiA6IHRoaXMuc2tpcCA/PyBvcHRpb25zLnNraXAgPyBcInNraXBcIiA6IHRoaXMudG9kbyA/PyBvcHRpb25zLnRvZG8gPyBcInRvZG9cIiA6IFwicnVuXCI7XG5cdFx0Ly8gcGFzc2VkIGFzIHRlc3QobmFtZSksIGFzc3VtZSBpdCdzIGEgXCJ0b2RvXCJcblx0XHRpZiAobW9kZSA9PT0gXCJydW5cIiAmJiAhZmFjdG9yeSkge1xuXHRcdFx0bW9kZSA9IFwidG9kb1wiO1xuXHRcdH1cblx0XHQvLyBpbmhlcml0IGNvbmN1cnJlbnQgLyBzZXF1ZW50aWFsIGZyb20gc3VpdGVcblx0XHRjb25zdCBpc0NvbmN1cnJlbnQgPSBpc0NvbmN1cnJlbnRTcGVjaWZpZWQgfHwgb3B0aW9ucy5jb25jdXJyZW50ICYmICFpc1NlcXVlbnRpYWxTcGVjaWZpZWQ7XG5cdFx0Y29uc3QgaXNTZXF1ZW50aWFsID0gaXNTZXF1ZW50aWFsU3BlY2lmaWVkIHx8IG9wdGlvbnMuc2VxdWVudGlhbCAmJiAhaXNDb25jdXJyZW50U3BlY2lmaWVkO1xuXHRcdGlmIChpc0NvbmN1cnJlbnQgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5jb25jdXJyZW50ID0gaXNDb25jdXJyZW50ICYmICFpc1NlcXVlbnRpYWw7XG5cdFx0fVxuXHRcdGlmIChpc1NlcXVlbnRpYWwgIT0gbnVsbCkge1xuXHRcdFx0b3B0aW9ucy5zZXF1ZW50aWFsID0gaXNTZXF1ZW50aWFsICYmICFpc0NvbmN1cnJlbnQ7XG5cdFx0fVxuXHRcdGlmIChwYXJlbnRNZXRhKSB7XG5cdFx0XHRvcHRpb25zLm1ldGEgPSBPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUobnVsbCksIHBhcmVudE1ldGEsIG9wdGlvbnMubWV0YSk7XG5cdFx0fVxuXHRcdHJldHVybiBjcmVhdGVTdWl0ZUNvbGxlY3Rvcihmb3JtYXROYW1lKG5hbWUpLCBmYWN0b3J5LCBtb2RlLCB0aGlzLmVhY2gsIG9wdGlvbnMpO1xuXHR9XG5cdHN1aXRlRm4uZWFjaCA9IGZ1bmN0aW9uKGNhc2VzLCAuLi5hcmdzKSB7XG5cdFx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdFx0Y29uc3Qgc3VpdGUgPSBjb250ZXh0LndpdGhDb250ZXh0KCk7XG5cdFx0Y29udGV4dC5zZXRDb250ZXh0KFwiZWFjaFwiLCB0cnVlKTtcblx0XHRpZiAoQXJyYXkuaXNBcnJheShjYXNlcykgJiYgYXJncy5sZW5ndGgpIHtcblx0XHRcdGNhc2VzID0gZm9ybWF0VGVtcGxhdGVTdHJpbmcoY2FzZXMsIGFyZ3MpO1xuXHRcdH1cblx0XHRyZXR1cm4gKG5hbWUsIG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucykgPT4ge1xuXHRcdFx0Y29uc3QgX25hbWUgPSBmb3JtYXROYW1lKG5hbWUpO1xuXHRcdFx0Y29uc3QgYXJyYXlPbmx5Q2FzZXMgPSBjYXNlcy5ldmVyeShBcnJheS5pc0FycmF5KTtcblx0XHRcdGNvbnN0IHsgb3B0aW9ucywgaGFuZGxlciB9ID0gcGFyc2VBcmd1bWVudHMob3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKTtcblx0XHRcdGNvbnN0IGZuRmlyc3QgPSB0eXBlb2Ygb3B0aW9uc09yRm4gPT09IFwiZnVuY3Rpb25cIjtcblx0XHRcdGNhc2VzLmZvckVhY2goKGksIGlkeCkgPT4ge1xuXHRcdFx0XHRjb25zdCBpdGVtcyA9IEFycmF5LmlzQXJyYXkoaSkgPyBpIDogW2ldO1xuXHRcdFx0XHRpZiAoZm5GaXJzdCkge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0c3VpdGUoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlciguLi5pdGVtcykgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHN1aXRlKGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoaSkgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0c3VpdGUoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlciguLi5pdGVtcykgOiB1bmRlZmluZWQpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRzdWl0ZShmb3JtYXRUaXRsZShfbmFtZSwgaXRlbXMsIGlkeCksIG9wdGlvbnMsIGhhbmRsZXIgPyAoKSA9PiBoYW5kbGVyKGkpIDogdW5kZWZpbmVkKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0Y29udGV4dC5zZXRDb250ZXh0KFwiZWFjaFwiLCB1bmRlZmluZWQpO1xuXHRcdH07XG5cdH07XG5cdHN1aXRlRm4uZm9yID0gZnVuY3Rpb24oY2FzZXMsIC4uLmFyZ3MpIHtcblx0XHRpZiAoQXJyYXkuaXNBcnJheShjYXNlcykgJiYgYXJncy5sZW5ndGgpIHtcblx0XHRcdGNhc2VzID0gZm9ybWF0VGVtcGxhdGVTdHJpbmcoY2FzZXMsIGFyZ3MpO1xuXHRcdH1cblx0XHRyZXR1cm4gKG5hbWUsIG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucykgPT4ge1xuXHRcdFx0Y29uc3QgbmFtZV8gPSBmb3JtYXROYW1lKG5hbWUpO1xuXHRcdFx0Y29uc3QgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgZm5Pck9wdGlvbnMpO1xuXHRcdFx0Y2FzZXMuZm9yRWFjaCgoaXRlbSwgaWR4KSA9PiB7XG5cdFx0XHRcdHN1aXRlKGZvcm1hdFRpdGxlKG5hbWVfLCB0b0FycmF5KGl0ZW0pLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlcihpdGVtKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHR9KTtcblx0XHR9O1xuXHR9O1xuXHRzdWl0ZUZuLnNraXBJZiA9IChjb25kaXRpb24pID0+IGNvbmRpdGlvbiA/IHN1aXRlLnNraXAgOiBzdWl0ZTtcblx0c3VpdGVGbi5ydW5JZiA9IChjb25kaXRpb24pID0+IGNvbmRpdGlvbiA/IHN1aXRlIDogc3VpdGUuc2tpcDtcblx0cmV0dXJuIGNyZWF0ZUNoYWluYWJsZShbXG5cdFx0XCJjb25jdXJyZW50XCIsXG5cdFx0XCJzZXF1ZW50aWFsXCIsXG5cdFx0XCJzaHVmZmxlXCIsXG5cdFx0XCJza2lwXCIsXG5cdFx0XCJvbmx5XCIsXG5cdFx0XCJ0b2RvXCJcblx0XSwgc3VpdGVGbik7XG59XG5mdW5jdGlvbiBjcmVhdGVUYXNrQ29sbGVjdG9yKGZuKSB7XG5cdGNvbnN0IHRhc2tGbiA9IGZuO1xuXHR0YXNrRm4uZWFjaCA9IGZ1bmN0aW9uKGNhc2VzLCAuLi5hcmdzKSB7XG5cdFx0Y29uc3QgY29udGV4dCA9IGdldENoYWluYWJsZUNvbnRleHQodGhpcyk7XG5cdFx0Y29uc3QgdGVzdCA9IGNvbnRleHQud2l0aENvbnRleHQoKTtcblx0XHRjb250ZXh0LnNldENvbnRleHQoXCJlYWNoXCIsIHRydWUpO1xuXHRcdGlmIChBcnJheS5pc0FycmF5KGNhc2VzKSAmJiBhcmdzLmxlbmd0aCkge1xuXHRcdFx0Y2FzZXMgPSBmb3JtYXRUZW1wbGF0ZVN0cmluZyhjYXNlcywgYXJncyk7XG5cdFx0fVxuXHRcdHJldHVybiAobmFtZSwgb3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKSA9PiB7XG5cdFx0XHRjb25zdCBfbmFtZSA9IGZvcm1hdE5hbWUobmFtZSk7XG5cdFx0XHRjb25zdCBhcnJheU9ubHlDYXNlcyA9IGNhc2VzLmV2ZXJ5KEFycmF5LmlzQXJyYXkpO1xuXHRcdFx0Y29uc3QgeyBvcHRpb25zLCBoYW5kbGVyIH0gPSBwYXJzZUFyZ3VtZW50cyhvcHRpb25zT3JGbiwgZm5Pck9wdGlvbnMpO1xuXHRcdFx0Y29uc3QgZm5GaXJzdCA9IHR5cGVvZiBvcHRpb25zT3JGbiA9PT0gXCJmdW5jdGlvblwiO1xuXHRcdFx0Y2FzZXMuZm9yRWFjaCgoaSwgaWR4KSA9PiB7XG5cdFx0XHRcdGNvbnN0IGl0ZW1zID0gQXJyYXkuaXNBcnJheShpKSA/IGkgOiBbaV07XG5cdFx0XHRcdGlmIChmbkZpcnN0KSB7XG5cdFx0XHRcdFx0aWYgKGFycmF5T25seUNhc2VzKSB7XG5cdFx0XHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoLi4uaXRlbXMpIDogdW5kZWZpbmVkLCBvcHRpb25zLnRpbWVvdXQpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCBpdGVtcywgaWR4KSwgaGFuZGxlciA/ICgpID0+IGhhbmRsZXIoaSkgOiB1bmRlZmluZWQsIG9wdGlvbnMudGltZW91dCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmIChhcnJheU9ubHlDYXNlcykge1xuXHRcdFx0XHRcdFx0dGVzdChmb3JtYXRUaXRsZShfbmFtZSwgaXRlbXMsIGlkeCksIG9wdGlvbnMsIGhhbmRsZXIgPyAoKSA9PiBoYW5kbGVyKC4uLml0ZW1zKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRlc3QoZm9ybWF0VGl0bGUoX25hbWUsIGl0ZW1zLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyID8gKCkgPT4gaGFuZGxlcihpKSA6IHVuZGVmaW5lZCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdGNvbnRleHQuc2V0Q29udGV4dChcImVhY2hcIiwgdW5kZWZpbmVkKTtcblx0XHR9O1xuXHR9O1xuXHR0YXNrRm4uZm9yID0gZnVuY3Rpb24oY2FzZXMsIC4uLmFyZ3MpIHtcblx0XHRjb25zdCBjb250ZXh0ID0gZ2V0Q2hhaW5hYmxlQ29udGV4dCh0aGlzKTtcblx0XHRjb25zdCB0ZXN0ID0gY29udGV4dC53aXRoQ29udGV4dCgpO1xuXHRcdGlmIChBcnJheS5pc0FycmF5KGNhc2VzKSAmJiBhcmdzLmxlbmd0aCkge1xuXHRcdFx0Y2FzZXMgPSBmb3JtYXRUZW1wbGF0ZVN0cmluZyhjYXNlcywgYXJncyk7XG5cdFx0fVxuXHRcdHJldHVybiAobmFtZSwgb3B0aW9uc09yRm4sIGZuT3JPcHRpb25zKSA9PiB7XG5cdFx0XHRjb25zdCBfbmFtZSA9IGZvcm1hdE5hbWUobmFtZSk7XG5cdFx0XHRjb25zdCB7IG9wdGlvbnMsIGhhbmRsZXIgfSA9IHBhcnNlQXJndW1lbnRzKG9wdGlvbnNPckZuLCBmbk9yT3B0aW9ucyk7XG5cdFx0XHRjYXNlcy5mb3JFYWNoKChpdGVtLCBpZHgpID0+IHtcblx0XHRcdFx0Ly8gbW9ua2V5LXBhdGNoIGhhbmRsZXIgdG8gYWxsb3cgcGFyc2luZyBmaXh0dXJlXG5cdFx0XHRcdGNvbnN0IGhhbmRsZXJXcmFwcGVyID0gaGFuZGxlciA/IChjdHgpID0+IGhhbmRsZXIoaXRlbSwgY3R4KSA6IHVuZGVmaW5lZDtcblx0XHRcdFx0aWYgKGhhbmRsZXJXcmFwcGVyKSB7XG5cdFx0XHRcdFx0Y29uZmlndXJlUHJvcHMoaGFuZGxlcldyYXBwZXIsIHtcblx0XHRcdFx0XHRcdGluZGV4OiAxLFxuXHRcdFx0XHRcdFx0b3JpZ2luYWw6IGhhbmRsZXJcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0ZXN0KGZvcm1hdFRpdGxlKF9uYW1lLCB0b0FycmF5KGl0ZW0pLCBpZHgpLCBvcHRpb25zLCBoYW5kbGVyV3JhcHBlcik7XG5cdFx0XHR9KTtcblx0XHR9O1xuXHR9O1xuXHR0YXNrRm4uc2tpcElmID0gZnVuY3Rpb24oY29uZGl0aW9uKSB7XG5cdFx0cmV0dXJuIGNvbmRpdGlvbiA/IHRoaXMuc2tpcCA6IHRoaXM7XG5cdH07XG5cdHRhc2tGbi5ydW5JZiA9IGZ1bmN0aW9uKGNvbmRpdGlvbikge1xuXHRcdHJldHVybiBjb25kaXRpb24gPyB0aGlzIDogdGhpcy5za2lwO1xuXHR9O1xuXHQvKipcblx0KiBQYXJzZSBidWlsZGVyIHBhdHRlcm4gYXJndW1lbnRzIGludG8gYSBmaXh0dXJlcyBvYmplY3QuXG5cdCogSGFuZGxlcyBib3RoIGJ1aWxkZXIgcGF0dGVybiAobmFtZSwgb3B0aW9ucz8sIHZhbHVlKSBhbmQgb2JqZWN0IHN5bnRheC5cblx0Ki9cblx0ZnVuY3Rpb24gcGFyc2VCdWlsZGVyRml4dHVyZXMoZml4dHVyZXNPck5hbWUsIG9wdGlvbnNPckZuLCBtYXliZUZuKSB7XG5cdFx0Ly8gT2JqZWN0IHN5bnRheDoganVzdCByZXR1cm4gYXMtaXNcblx0XHRpZiAodHlwZW9mIGZpeHR1cmVzT3JOYW1lICE9PSBcInN0cmluZ1wiKSB7XG5cdFx0XHRyZXR1cm4gZml4dHVyZXNPck5hbWU7XG5cdFx0fVxuXHRcdGNvbnN0IGZpeHR1cmVOYW1lID0gZml4dHVyZXNPck5hbWU7XG5cdFx0bGV0IGZpeHR1cmVPcHRpb25zO1xuXHRcdGxldCBmaXh0dXJlVmFsdWU7XG5cdFx0aWYgKG1heWJlRm4gIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0Ly8gKG5hbWUsIG9wdGlvbnMsIHZhbHVlKSBvciAobmFtZSwgb3B0aW9ucywgZm4pXG5cdFx0XHRmaXh0dXJlT3B0aW9ucyA9IG9wdGlvbnNPckZuO1xuXHRcdFx0Zml4dHVyZVZhbHVlID0gbWF5YmVGbjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gKG5hbWUsIHZhbHVlKSBvciAobmFtZSwgZm4pXG5cdFx0XHQvLyBDaGVjayBpZiBvcHRpb25zT3JGbiBsb29rcyBsaWtlIGZpeHR1cmUgb3B0aW9ucyAoaGFzIHNjb3BlIG9yIGF1dG8pXG5cdFx0XHRpZiAob3B0aW9uc09yRm4gIT09IG51bGwgJiYgdHlwZW9mIG9wdGlvbnNPckZuID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KG9wdGlvbnNPckZuKSAmJiBUZXN0Rml4dHVyZXMuaXNGaXh0dXJlT3B0aW9ucyhvcHRpb25zT3JGbikpIHtcblx0XHRcdFx0Ly8gKG5hbWUsIG9wdGlvbnMpIHdpdGggbm8gdmFsdWUgLSB0cmVhdCBhcyBlbXB0eSBvYmplY3QgZml4dHVyZVxuXHRcdFx0XHRmaXh0dXJlT3B0aW9ucyA9IG9wdGlvbnNPckZuO1xuXHRcdFx0XHRmaXh0dXJlVmFsdWUgPSB7fTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIChuYW1lLCB2YWx1ZSkgb3IgKG5hbWUsIGZuKVxuXHRcdFx0XHRmaXh0dXJlT3B0aW9ucyA9IHVuZGVmaW5lZDtcblx0XHRcdFx0Zml4dHVyZVZhbHVlID0gb3B0aW9uc09yRm47XG5cdFx0XHR9XG5cdFx0fVxuXHRcdC8vIEZ1bmN0aW9uIHZhbHVlOiB3cmFwIHdpdGggb25DbGVhbnVwIHBhdHRlcm5cblx0XHRpZiAodHlwZW9mIGZpeHR1cmVWYWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRjb25zdCBidWlsZGVyRm4gPSBmaXh0dXJlVmFsdWU7XG5cdFx0XHQvLyBXcmFwIGJ1aWxkZXIgcGF0dGVybiBmdW5jdGlvbiAocmV0dXJucyB2YWx1ZSkgdG8gdXNlKCkgcGF0dGVyblxuXHRcdFx0Y29uc3QgZml4dHVyZSA9IGFzeW5jIChjdHgsIHVzZSkgPT4ge1xuXHRcdFx0XHRsZXQgY2xlYW51cDtcblx0XHRcdFx0Y29uc3Qgb25DbGVhbnVwID0gKGZuKSA9PiB7XG5cdFx0XHRcdFx0aWYgKGNsZWFudXAgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKGBvbkNsZWFudXAgY2FuIG9ubHkgYmUgY2FsbGVkIG9uY2UgcGVyIGZpeHR1cmUuIGAgKyBgRGVmaW5lIHNlcGFyYXRlIGZpeHR1cmVzIGlmIHlvdSBuZWVkIG11bHRpcGxlIGNsZWFudXAgZnVuY3Rpb25zLmApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRjbGVhbnVwID0gZm47XG5cdFx0XHRcdH07XG5cdFx0XHRcdGNvbnN0IHZhbHVlID0gYXdhaXQgYnVpbGRlckZuKGN0eCwgeyBvbkNsZWFudXAgfSk7XG5cdFx0XHRcdGF3YWl0IHVzZSh2YWx1ZSk7XG5cdFx0XHRcdGlmIChjbGVhbnVwKSB7XG5cdFx0XHRcdFx0YXdhaXQgY2xlYW51cCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0Y29uZmlndXJlUHJvcHMoZml4dHVyZSwgeyBvcmlnaW5hbDogYnVpbGRlckZuIH0pO1xuXHRcdFx0aWYgKGZpeHR1cmVPcHRpb25zKSB7XG5cdFx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IFtmaXh0dXJlLCBmaXh0dXJlT3B0aW9uc10gfTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IGZpeHR1cmUgfTtcblx0XHR9XG5cdFx0Ly8gTm9uLWZ1bmN0aW9uIHZhbHVlOiB1c2UgZGlyZWN0bHlcblx0XHRpZiAoZml4dHVyZU9wdGlvbnMpIHtcblx0XHRcdHJldHVybiB7IFtmaXh0dXJlTmFtZV06IFtmaXh0dXJlVmFsdWUsIGZpeHR1cmVPcHRpb25zXSB9O1xuXHRcdH1cblx0XHRyZXR1cm4geyBbZml4dHVyZU5hbWVdOiBmaXh0dXJlVmFsdWUgfTtcblx0fVxuXHR0YXNrRm4ub3ZlcnJpZGUgPSBmdW5jdGlvbihmaXh0dXJlc09yTmFtZSwgb3B0aW9uc09yRm4sIG1heWJlRm4pIHtcblx0XHRjb25zdCB1c2VyRml4dHVyZXMgPSBwYXJzZUJ1aWxkZXJGaXh0dXJlcyhmaXh0dXJlc09yTmFtZSwgb3B0aW9uc09yRm4sIG1heWJlRm4pO1xuXHRcdGdldENoYWluYWJsZUNvbnRleHQodGhpcykuZ2V0Rml4dHVyZXMoKS5vdmVycmlkZShydW5uZXIsIHVzZXJGaXh0dXJlcyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH07XG5cdHRhc2tGbi5zY29wZWQgPSBmdW5jdGlvbihmaXh0dXJlcykge1xuXHRcdGNvbnNvbGUud2FybihgdGVzdC5zY29wZWQoKSBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gZnV0dXJlIHZlcnNpb25zLiBQbGVhc2UgdXNlIHRlc3Qub3ZlcnJpZGUoKSBpbnN0ZWFkLmApO1xuXHRcdHJldHVybiB0aGlzLm92ZXJyaWRlKGZpeHR1cmVzKTtcblx0fTtcblx0dGFza0ZuLmV4dGVuZCA9IGZ1bmN0aW9uKGZpeHR1cmVzT3JOYW1lLCBvcHRpb25zT3JGbiwgbWF5YmVGbikge1xuXHRcdGNvbnN0IHVzZXJGaXh0dXJlcyA9IHBhcnNlQnVpbGRlckZpeHR1cmVzKGZpeHR1cmVzT3JOYW1lLCBvcHRpb25zT3JGbiwgbWF5YmVGbik7XG5cdFx0Y29uc3QgZml4dHVyZXMgPSBnZXRDaGFpbmFibGVDb250ZXh0KHRoaXMpLmdldEZpeHR1cmVzKCkuZXh0ZW5kKHJ1bm5lciwgdXNlckZpeHR1cmVzKTtcblx0XHRjb25zdCBfdGVzdCA9IGNyZWF0ZVRlc3QoZnVuY3Rpb24obmFtZSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpIHtcblx0XHRcdGZuLmNhbGwodGhpcywgZm9ybWF0TmFtZShuYW1lKSwgb3B0aW9uc09yRm4sIG9wdGlvbnNPclRlc3QpO1xuXHRcdH0pO1xuXHRcdGdldENoYWluYWJsZUNvbnRleHQoX3Rlc3QpLm1lcmdlQ29udGV4dCh7IGZpeHR1cmVzIH0pO1xuXHRcdHJldHVybiBfdGVzdDtcblx0fTtcblx0dGFza0ZuLmRlc2NyaWJlID0gc3VpdGU7XG5cdHRhc2tGbi5zdWl0ZSA9IHN1aXRlO1xuXHR0YXNrRm4uYmVmb3JlRWFjaCA9IGJlZm9yZUVhY2g7XG5cdHRhc2tGbi5hZnRlckVhY2ggPSBhZnRlckVhY2g7XG5cdHRhc2tGbi5iZWZvcmVBbGwgPSBiZWZvcmVBbGw7XG5cdHRhc2tGbi5hZnRlckFsbCA9IGFmdGVyQWxsO1xuXHR0YXNrRm4uYXJvdW5kRWFjaCA9IGFyb3VuZEVhY2g7XG5cdHRhc2tGbi5hcm91bmRBbGwgPSBhcm91bmRBbGw7XG5cdGNvbnN0IF90ZXN0ID0gY3JlYXRlQ2hhaW5hYmxlKFtcblx0XHRcImNvbmN1cnJlbnRcIixcblx0XHRcInNlcXVlbnRpYWxcIixcblx0XHRcInNraXBcIixcblx0XHRcIm9ubHlcIixcblx0XHRcInRvZG9cIixcblx0XHRcImZhaWxzXCJcblx0XSwgdGFza0ZuLCB7IGZpeHR1cmVzOiBuZXcgVGVzdEZpeHR1cmVzKCkgfSk7XG5cdHJldHVybiBfdGVzdDtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRlc3QoZm4pIHtcblx0cmV0dXJuIGNyZWF0ZVRhc2tDb2xsZWN0b3IoZm4pO1xufVxuZnVuY3Rpb24gZm9ybWF0TmFtZShuYW1lKSB7XG5cdHJldHVybiB0eXBlb2YgbmFtZSA9PT0gXCJzdHJpbmdcIiA/IG5hbWUgOiB0eXBlb2YgbmFtZSA9PT0gXCJmdW5jdGlvblwiID8gbmFtZS5uYW1lIHx8IFwiPGFub255bW91cz5cIiA6IFN0cmluZyhuYW1lKTtcbn1cbmZ1bmN0aW9uIGZvcm1hdFRpdGxlKHRlbXBsYXRlLCBpdGVtcywgaWR4KSB7XG5cdGlmICh0ZW1wbGF0ZS5pbmNsdWRlcyhcIiUjXCIpIHx8IHRlbXBsYXRlLmluY2x1ZGVzKFwiJSRcIikpIHtcblx0XHQvLyAnJSMnIG1hdGNoIGluZGV4IG9mIHRoZSB0ZXN0IGNhc2Vcblx0XHR0ZW1wbGF0ZSA9IHRlbXBsYXRlLnJlcGxhY2UoLyUlL2csIFwiX192aXRlc3RfZXNjYXBlZF8lX19cIikucmVwbGFjZSgvJSMvZywgYCR7aWR4fWApLnJlcGxhY2UoLyVcXCQvZywgYCR7aWR4ICsgMX1gKS5yZXBsYWNlKC9fX3ZpdGVzdF9lc2NhcGVkXyVfXy9nLCBcIiUlXCIpO1xuXHR9XG5cdGNvbnN0IGNvdW50ID0gdGVtcGxhdGUuc3BsaXQoXCIlXCIpLmxlbmd0aCAtIDE7XG5cdGlmICh0ZW1wbGF0ZS5pbmNsdWRlcyhcIiVmXCIpKSB7XG5cdFx0Y29uc3QgcGxhY2Vob2xkZXJzID0gdGVtcGxhdGUubWF0Y2goLyVmL2cpIHx8IFtdO1xuXHRcdHBsYWNlaG9sZGVycy5mb3JFYWNoKChfLCBpKSA9PiB7XG5cdFx0XHRpZiAoaXNOZWdhdGl2ZU5hTihpdGVtc1tpXSkgfHwgT2JqZWN0LmlzKGl0ZW1zW2ldLCAtMCkpIHtcblx0XHRcdFx0Ly8gUmVwbGFjZSB0aGUgaS10aCBvY2N1cnJlbmNlIG9mICclZicgd2l0aCAnLSVmJ1xuXHRcdFx0XHRsZXQgb2NjdXJyZW5jZSA9IDA7XG5cdFx0XHRcdHRlbXBsYXRlID0gdGVtcGxhdGUucmVwbGFjZSgvJWYvZywgKG1hdGNoKSA9PiB7XG5cdFx0XHRcdFx0b2NjdXJyZW5jZSsrO1xuXHRcdFx0XHRcdHJldHVybiBvY2N1cnJlbmNlID09PSBpICsgMSA/IFwiLSVmXCIgOiBtYXRjaDtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblx0Y29uc3QgaXNPYmplY3RJdGVtID0gaXNPYmplY3QoaXRlbXNbMF0pO1xuXHRmdW5jdGlvbiBmb3JtYXRBdHRyaWJ1dGUocykge1xuXHRcdHJldHVybiBzLnJlcGxhY2UoL1xcJChbJFxcdy5dKykvZywgKF8sIGtleSkgPT4ge1xuXHRcdFx0Y29uc3QgaXNBcnJheUtleSA9IC9eXFxkKyQvLnRlc3Qoa2V5KTtcblx0XHRcdGlmICghaXNPYmplY3RJdGVtICYmICFpc0FycmF5S2V5KSB7XG5cdFx0XHRcdHJldHVybiBgJCR7a2V5fWA7XG5cdFx0XHR9XG5cdFx0XHRjb25zdCBhcnJheUVsZW1lbnQgPSBpc0FycmF5S2V5ID8gb2JqZWN0QXR0cihpdGVtcywga2V5KSA6IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IHZhbHVlID0gaXNPYmplY3RJdGVtID8gb2JqZWN0QXR0cihpdGVtc1swXSwga2V5LCBhcnJheUVsZW1lbnQpIDogYXJyYXlFbGVtZW50O1xuXHRcdFx0cmV0dXJuIG9iakRpc3BsYXkodmFsdWUsIHsgdHJ1bmNhdGU6IHJ1bm5lcj8uY29uZmlnPy5jaGFpQ29uZmlnPy50cnVuY2F0ZVRocmVzaG9sZCB9KTtcblx0XHR9KTtcblx0fVxuXHRsZXQgb3V0cHV0ID0gXCJcIjtcblx0bGV0IGkgPSAwO1xuXHRoYW5kbGVSZWdleE1hdGNoKFxuXHRcdHRlbXBsYXRlLFxuXHRcdGZvcm1hdFJlZ0V4cCxcblx0XHQvLyBmb3JtYXQgXCIlXCJcblx0XHQobWF0Y2gpID0+IHtcblx0XHRcdGlmIChpIDwgY291bnQpIHtcblx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdChtYXRjaFswXSwgaXRlbXNbaSsrXSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvdXRwdXQgKz0gbWF0Y2hbMF07XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvLyBmb3JtYXQgXCIkXCJcblx0XHQobm9uTWF0Y2gpID0+IHtcblx0XHRcdG91dHB1dCArPSBmb3JtYXRBdHRyaWJ1dGUobm9uTWF0Y2gpO1xuXHRcdH1cblx0KTtcblx0cmV0dXJuIG91dHB1dDtcbn1cbi8vIGJhc2VkIG9uIGh0dHBzOi8vZ2l0aHViLmNvbS91bm9jc3MvdW5vY3NzL2Jsb2IvMmU3NGIzMTYyNWJiZTNiOWM4MzUxNTcwNzQ5YWEyZDNmNzk5ZDkxOS9wYWNrYWdlcy9hdXRvY29tcGxldGUvc3JjL3BhcnNlLnRzI0wxMVxuZnVuY3Rpb24gaGFuZGxlUmVnZXhNYXRjaChpbnB1dCwgcmVnZXgsIG9uTWF0Y2gsIG9uTm9uTWF0Y2gpIHtcblx0bGV0IGxhc3RJbmRleCA9IDA7XG5cdGZvciAoY29uc3QgbSBvZiBpbnB1dC5tYXRjaEFsbChyZWdleCkpIHtcblx0XHRpZiAobGFzdEluZGV4IDwgbS5pbmRleCkge1xuXHRcdFx0b25Ob25NYXRjaChpbnB1dC5zbGljZShsYXN0SW5kZXgsIG0uaW5kZXgpKTtcblx0XHR9XG5cdFx0b25NYXRjaChtKTtcblx0XHRsYXN0SW5kZXggPSBtLmluZGV4ICsgbVswXS5sZW5ndGg7XG5cdH1cblx0aWYgKGxhc3RJbmRleCA8IGlucHV0Lmxlbmd0aCkge1xuXHRcdG9uTm9uTWF0Y2goaW5wdXQuc2xpY2UobGFzdEluZGV4KSk7XG5cdH1cbn1cbmZ1bmN0aW9uIGZvcm1hdFRlbXBsYXRlU3RyaW5nKGNhc2VzLCBhcmdzKSB7XG5cdGNvbnN0IGhlYWRlciA9IGNhc2VzLmpvaW4oXCJcIikudHJpbSgpLnJlcGxhY2UoLyAvZywgXCJcIikuc3BsaXQoXCJcXG5cIikubWFwKChpKSA9PiBpLnNwbGl0KFwifFwiKSlbMF07XG5cdGNvbnN0IHJlcyA9IFtdO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IE1hdGguZmxvb3IoYXJncy5sZW5ndGggLyBoZWFkZXIubGVuZ3RoKTsgaSsrKSB7XG5cdFx0Y29uc3Qgb25lQ2FzZSA9IHt9O1xuXHRcdGZvciAobGV0IGogPSAwOyBqIDwgaGVhZGVyLmxlbmd0aDsgaisrKSB7XG5cdFx0XHRvbmVDYXNlW2hlYWRlcltqXV0gPSBhcmdzW2kgKiBoZWFkZXIubGVuZ3RoICsgal07XG5cdFx0fVxuXHRcdHJlcy5wdXNoKG9uZUNhc2UpO1xuXHR9XG5cdHJldHVybiByZXM7XG59XG5cbmNvbnN0IG5vdyQyID0gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZSA/IGdsb2JhbFRoaXMucGVyZm9ybWFuY2Uubm93LmJpbmQoZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZSkgOiBEYXRlLm5vdztcbmNvbnN0IGNvbGxlY3RvckNvbnRleHQgPSB7XG5cdHRhc2tzOiBbXSxcblx0Y3VycmVudFN1aXRlOiBudWxsXG59O1xuZnVuY3Rpb24gY29sbGVjdFRhc2sodGFzaykge1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZT8udGFza3MucHVzaCh0YXNrKTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1bldpdGhTdWl0ZShzdWl0ZSwgZm4pIHtcblx0Y29uc3QgcHJldiA9IGNvbGxlY3RvckNvbnRleHQuY3VycmVudFN1aXRlO1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSA9IHN1aXRlO1xuXHRhd2FpdCBmbigpO1xuXHRjb2xsZWN0b3JDb250ZXh0LmN1cnJlbnRTdWl0ZSA9IHByZXY7XG59XG5mdW5jdGlvbiB3aXRoVGltZW91dChmbiwgdGltZW91dCwgaXNIb29rID0gZmFsc2UsIHN0YWNrVHJhY2VFcnJvciwgb25UaW1lb3V0KSB7XG5cdGlmICh0aW1lb3V0IDw9IDAgfHwgdGltZW91dCA9PT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZKSB7XG5cdFx0cmV0dXJuIGZuO1xuXHR9XG5cdGNvbnN0IHsgc2V0VGltZW91dCwgY2xlYXJUaW1lb3V0IH0gPSBnZXRTYWZlVGltZXJzKCk7XG5cdC8vIHRoaXMgZnVuY3Rpb24gbmFtZSBpcyB1c2VkIHRvIGZpbHRlciBlcnJvciBpbiB0ZXN0L2NsaS90ZXN0L2ZhaWxzLnRlc3QudHNcblx0cmV0dXJuIChmdW5jdGlvbiBydW5XaXRoVGltZW91dCguLi5hcmdzKSB7XG5cdFx0Y29uc3Qgc3RhcnRUaW1lID0gbm93JDIoKTtcblx0XHRjb25zdCBydW5uZXIgPSBnZXRSdW5uZXIoKTtcblx0XHRydW5uZXIuX2N1cnJlbnRUYXNrU3RhcnRUaW1lID0gc3RhcnRUaW1lO1xuXHRcdHJ1bm5lci5fY3VycmVudFRhc2tUaW1lb3V0ID0gdGltZW91dDtcblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmVfLCByZWplY3RfKSA9PiB7XG5cdFx0XHRjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRjbGVhclRpbWVvdXQodGltZXIpO1xuXHRcdFx0XHRyZWplY3RUaW1lb3V0RXJyb3IoKTtcblx0XHRcdH0sIHRpbWVvdXQpO1xuXHRcdFx0Ly8gYHVucmVmYCBtaWdodCBub3QgZXhpc3QgaW4gYnJvd3NlclxuXHRcdFx0dGltZXIudW5yZWY/LigpO1xuXHRcdFx0ZnVuY3Rpb24gcmVqZWN0VGltZW91dEVycm9yKCkge1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IG1ha2VUaW1lb3V0RXJyb3IoaXNIb29rLCB0aW1lb3V0LCBzdGFja1RyYWNlRXJyb3IpO1xuXHRcdFx0XHRvblRpbWVvdXQ/LihhcmdzLCBlcnJvcik7XG5cdFx0XHRcdHJlamVjdF8oZXJyb3IpO1xuXHRcdFx0fVxuXHRcdFx0ZnVuY3Rpb24gcmVzb2x2ZShyZXN1bHQpIHtcblx0XHRcdFx0cnVubmVyLl9jdXJyZW50VGFza1N0YXJ0VGltZSA9IHVuZGVmaW5lZDtcblx0XHRcdFx0cnVubmVyLl9jdXJyZW50VGFza1RpbWVvdXQgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aW1lcik7XG5cdFx0XHRcdC8vIGlmIHRlc3QvaG9vayB0b29rIHRvbyBsb25nIGluIG1pY3JvdGFzaywgc2V0VGltZW91dCB3b24ndCBiZSB0cmlnZ2VyZWQsXG5cdFx0XHRcdC8vIGJ1dCB3ZSBzdGlsbCBuZWVkIHRvIGZhaWwgdGhlIHRlc3QsIHNlZVxuXHRcdFx0XHQvLyBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvaXNzdWVzLzI5MjBcblx0XHRcdFx0aWYgKG5vdyQyKCkgLSBzdGFydFRpbWUgPj0gdGltZW91dCkge1xuXHRcdFx0XHRcdHJlamVjdFRpbWVvdXRFcnJvcigpO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXNvbHZlXyhyZXN1bHQpO1xuXHRcdFx0fVxuXHRcdFx0ZnVuY3Rpb24gcmVqZWN0KGVycm9yKSB7XG5cdFx0XHRcdHJ1bm5lci5fY3VycmVudFRhc2tTdGFydFRpbWUgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdHJ1bm5lci5fY3VycmVudFRhc2tUaW1lb3V0ID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRjbGVhclRpbWVvdXQodGltZXIpO1xuXHRcdFx0XHRyZWplY3RfKGVycm9yKTtcblx0XHRcdH1cblx0XHRcdC8vIHN5bmMgdGVzdC9ob29rIHdpbGwgYmUgY2F1Z2h0IGJ5IHRyeS9jYXRjaFxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZm4oLi4uYXJncyk7XG5cdFx0XHRcdC8vIHRoZSByZXN1bHQgaXMgYSB0aGVuYWJsZSwgd2UgZG9uJ3Qgd3JhcCB0aGlzIGluIFByb21pc2UucmVzb2x2ZVxuXHRcdFx0XHQvLyB0byBhdm9pZCBjcmVhdGluZyBuZXcgcHJvbWlzZXNcblx0XHRcdFx0aWYgKHR5cGVvZiByZXN1bHQgPT09IFwib2JqZWN0XCIgJiYgcmVzdWx0ICE9IG51bGwgJiYgdHlwZW9mIHJlc3VsdC50aGVuID09PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRcdFx0XHRyZXN1bHQudGhlbihyZXNvbHZlLCByZWplY3QpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJlc29sdmUocmVzdWx0KTtcblx0XHRcdFx0fVxuXHRcdFx0fSBcblx0XHRcdC8vIHVzZXIgc3luYyB0ZXN0L2hvb2sgdGhyb3dzIGFuIGVycm9yXG5jYXRjaCAoZXJyb3IpIHtcblx0XHRcdFx0cmVqZWN0KGVycm9yKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSk7XG59XG5mdW5jdGlvbiB3aXRoQ2FuY2VsKGZuLCBzaWduYWwpIHtcblx0cmV0dXJuIChmdW5jdGlvbiBydW5XaXRoQ2FuY2VsKC4uLmFyZ3MpIHtcblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuXHRcdFx0c2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCAoKSA9PiByZWplY3Qoc2lnbmFsLnJlYXNvbikpO1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gZm4oLi4uYXJncyk7XG5cdFx0XHRcdGlmICh0eXBlb2YgcmVzdWx0ID09PSBcIm9iamVjdFwiICYmIHJlc3VsdCAhPSBudWxsICYmIHR5cGVvZiByZXN1bHQudGhlbiA9PT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRcdFx0cmVzdWx0LnRoZW4ocmVzb2x2ZSwgcmVqZWN0KTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXNvbHZlKHJlc3VsdCk7XG5cdFx0XHRcdH1cblx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdHJlamVjdChlcnJvcik7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0pO1xufVxuY29uc3QgYWJvcnRDb250cm9sbGVycyA9IG5ldyBXZWFrTWFwKCk7XG5mdW5jdGlvbiBhYm9ydElmVGltZW91dChbY29udGV4dF0sIGVycm9yKSB7XG5cdGlmIChjb250ZXh0KSB7XG5cdFx0YWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKTtcblx0fVxufVxuZnVuY3Rpb24gYWJvcnRDb250ZXh0U2lnbmFsKGNvbnRleHQsIGVycm9yKSB7XG5cdGNvbnN0IGFib3J0Q29udHJvbGxlciA9IGFib3J0Q29udHJvbGxlcnMuZ2V0KGNvbnRleHQpO1xuXHRhYm9ydENvbnRyb2xsZXI/LmFib3J0KGVycm9yKTtcbn1cbmZ1bmN0aW9uIGNyZWF0ZVRlc3RDb250ZXh0KHRlc3QsIHJ1bm5lcikge1xuXHRjb25zdCBjb250ZXh0ID0gZnVuY3Rpb24oKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKFwiZG9uZSgpIGNhbGxiYWNrIGlzIGRlcHJlY2F0ZWQsIHVzZSBwcm9taXNlIGluc3RlYWRcIik7XG5cdH07XG5cdGxldCBhYm9ydENvbnRyb2xsZXIgPSBhYm9ydENvbnRyb2xsZXJzLmdldChjb250ZXh0KTtcblx0aWYgKCFhYm9ydENvbnRyb2xsZXIpIHtcblx0XHRhYm9ydENvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG5cdFx0YWJvcnRDb250cm9sbGVycy5zZXQoY29udGV4dCwgYWJvcnRDb250cm9sbGVyKTtcblx0fVxuXHRjb250ZXh0LnNpZ25hbCA9IGFib3J0Q29udHJvbGxlci5zaWduYWw7XG5cdGNvbnRleHQudGFzayA9IHRlc3Q7XG5cdGNvbnRleHQuc2tpcCA9IChjb25kaXRpb24sIG5vdGUpID0+IHtcblx0XHRpZiAoY29uZGl0aW9uID09PSBmYWxzZSkge1xuXHRcdFx0Ly8gZG8gbm90aGluZ1xuXHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHR9XG5cdFx0dGVzdC5yZXN1bHQgPz89IHsgc3RhdGU6IFwic2tpcFwiIH07XG5cdFx0dGVzdC5yZXN1bHQucGVuZGluZyA9IHRydWU7XG5cdFx0dGhyb3cgbmV3IFBlbmRpbmdFcnJvcihcInRlc3QgaXMgc2tpcHBlZDsgYWJvcnQgZXhlY3V0aW9uXCIsIHRlc3QsIHR5cGVvZiBjb25kaXRpb24gPT09IFwic3RyaW5nXCIgPyBjb25kaXRpb24gOiBub3RlKTtcblx0fTtcblx0Y29udGV4dC5hbm5vdGF0ZSA9ICgobWVzc2FnZSwgdHlwZSwgYXR0YWNobWVudCkgPT4ge1xuXHRcdGlmICh0ZXN0LnJlc3VsdCAmJiB0ZXN0LnJlc3VsdC5zdGF0ZSAhPT0gXCJydW5cIikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYW5ub3RhdGUgdGVzdHMgb3V0c2lkZSBvZiB0aGUgdGVzdCBydW4uIFRoZSB0ZXN0IFwiJHt0ZXN0Lm5hbWV9XCIgZmluaXNoZWQgcnVubmluZyB3aXRoIHRoZSBcIiR7dGVzdC5yZXN1bHQuc3RhdGV9XCIgc3RhdGUgYWxyZWFkeS5gKTtcblx0XHR9XG5cdFx0Y29uc3QgYW5ub3RhdGlvbiA9IHtcblx0XHRcdG1lc3NhZ2UsXG5cdFx0XHR0eXBlOiB0eXBlb2YgdHlwZSA9PT0gXCJvYmplY3RcIiB8fCB0eXBlID09PSB1bmRlZmluZWQgPyBcIm5vdGljZVwiIDogdHlwZVxuXHRcdH07XG5cdFx0Y29uc3QgYW5ub3RhdGlvbkF0dGFjaG1lbnQgPSB0eXBlb2YgdHlwZSA9PT0gXCJvYmplY3RcIiA/IHR5cGUgOiBhdHRhY2htZW50O1xuXHRcdGlmIChhbm5vdGF0aW9uQXR0YWNobWVudCkge1xuXHRcdFx0YW5ub3RhdGlvbi5hdHRhY2htZW50ID0gYW5ub3RhdGlvbkF0dGFjaG1lbnQ7XG5cdFx0XHRtYW5hZ2VBcnRpZmFjdEF0dGFjaG1lbnQoYW5ub3RhdGlvbi5hdHRhY2htZW50KTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlY29yZEFzeW5jT3BlcmF0aW9uKHRlc3QsIHJlY29yZEFydGlmYWN0KHRlc3QsIHtcblx0XHRcdHR5cGU6IFwiaW50ZXJuYWw6YW5ub3RhdGlvblwiLFxuXHRcdFx0YW5ub3RhdGlvblxuXHRcdH0pLnRoZW4oYXN5bmMgKHsgYW5ub3RhdGlvbiB9KSA9PiB7XG5cdFx0XHRpZiAoIXJ1bm5lci5vblRlc3RBbm5vdGF0ZSkge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoYFRlc3QgcnVubmVyIGRvZXNuJ3Qgc3VwcG9ydCB0ZXN0IGFubm90YXRpb25zLmApO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgZmluaXNoU2VuZFRhc2tzVXBkYXRlKHJ1bm5lcik7XG5cdFx0XHRjb25zdCByZXNvbHZlZEFubm90YXRpb24gPSBhd2FpdCBydW5uZXIub25UZXN0QW5ub3RhdGUodGVzdCwgYW5ub3RhdGlvbik7XG5cdFx0XHR0ZXN0LmFubm90YXRpb25zLnB1c2gocmVzb2x2ZWRBbm5vdGF0aW9uKTtcblx0XHRcdHJldHVybiByZXNvbHZlZEFubm90YXRpb247XG5cdFx0fSkpO1xuXHR9KTtcblx0Y29udGV4dC5vblRlc3RGYWlsZWQgPSAoaGFuZGxlciwgdGltZW91dCkgPT4ge1xuXHRcdHRlc3Qub25GYWlsZWQgfHw9IFtdO1xuXHRcdHRlc3Qub25GYWlsZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IHJ1bm5lci5jb25maWcuaG9va1RpbWVvdXQsIHRydWUsIG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpLCAoXywgZXJyb3IpID0+IGFib3J0Q29udHJvbGxlci5hYm9ydChlcnJvcikpKTtcblx0fTtcblx0Y29udGV4dC5vblRlc3RGaW5pc2hlZCA9IChoYW5kbGVyLCB0aW1lb3V0KSA9PiB7XG5cdFx0dGVzdC5vbkZpbmlzaGVkIHx8PSBbXTtcblx0XHR0ZXN0Lm9uRmluaXNoZWQucHVzaCh3aXRoVGltZW91dChoYW5kbGVyLCB0aW1lb3V0ID8/IHJ1bm5lci5jb25maWcuaG9va1RpbWVvdXQsIHRydWUsIG5ldyBFcnJvcihcIlNUQUNLX1RSQUNFX0VSUk9SXCIpLCAoXywgZXJyb3IpID0+IGFib3J0Q29udHJvbGxlci5hYm9ydChlcnJvcikpKTtcblx0fTtcblx0cmV0dXJuIHJ1bm5lci5leHRlbmRUYXNrQ29udGV4dD8uKGNvbnRleHQpIHx8IGNvbnRleHQ7XG59XG5mdW5jdGlvbiBtYWtlVGltZW91dEVycm9yKGlzSG9vaywgdGltZW91dCwgc3RhY2tUcmFjZUVycm9yKSB7XG5cdGNvbnN0IG1lc3NhZ2UgPSBgJHtpc0hvb2sgPyBcIkhvb2tcIiA6IFwiVGVzdFwifSB0aW1lZCBvdXQgaW4gJHt0aW1lb3V0fW1zLlxcbklmIHRoaXMgaXMgYSBsb25nLXJ1bm5pbmcgJHtpc0hvb2sgPyBcImhvb2tcIiA6IFwidGVzdFwifSwgcGFzcyBhIHRpbWVvdXQgdmFsdWUgYXMgdGhlIGxhc3QgYXJndW1lbnQgb3IgY29uZmlndXJlIGl0IGdsb2JhbGx5IHdpdGggXCIke2lzSG9vayA/IFwiaG9va1RpbWVvdXRcIiA6IFwidGVzdFRpbWVvdXRcIn1cIi5gO1xuXHRjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlKTtcblx0aWYgKHN0YWNrVHJhY2VFcnJvcj8uc3RhY2spIHtcblx0XHRlcnJvci5zdGFjayA9IHN0YWNrVHJhY2VFcnJvci5zdGFjay5yZXBsYWNlKGVycm9yLm1lc3NhZ2UsIHN0YWNrVHJhY2VFcnJvci5tZXNzYWdlKTtcblx0fVxuXHRyZXR1cm4gZXJyb3I7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1blNldHVwRmlsZXMoY29uZmlnLCBmaWxlcywgcnVubmVyKSB7XG5cdGlmIChjb25maWcuc2VxdWVuY2Uuc2V0dXBGaWxlcyA9PT0gXCJwYXJhbGxlbFwiKSB7XG5cdFx0YXdhaXQgUHJvbWlzZS5hbGwoZmlsZXMubWFwKGFzeW5jIChmc1BhdGgpID0+IHtcblx0XHRcdGF3YWl0IHJ1bm5lci5pbXBvcnRGaWxlKGZzUGF0aCwgXCJzZXR1cFwiKTtcblx0XHR9KSk7XG5cdH0gZWxzZSB7XG5cdFx0Zm9yIChjb25zdCBmc1BhdGggb2YgZmlsZXMpIHtcblx0XHRcdGF3YWl0IHJ1bm5lci5pbXBvcnRGaWxlKGZzUGF0aCwgXCJzZXR1cFwiKTtcblx0XHR9XG5cdH1cbn1cblxuY29uc3Qgbm93JDEgPSBnbG9iYWxUaGlzLnBlcmZvcm1hbmNlID8gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZS5ub3cuYmluZChnbG9iYWxUaGlzLnBlcmZvcm1hbmNlKSA6IERhdGUubm93O1xuYXN5bmMgZnVuY3Rpb24gY29sbGVjdFRlc3RzKHNwZWNzLCBydW5uZXIpIHtcblx0Y29uc3QgZmlsZXMgPSBbXTtcblx0Y29uc3QgY29uZmlnID0gcnVubmVyLmNvbmZpZztcblx0Y29uc3QgJCA9IHJ1bm5lci50cmFjZTtcblx0bGV0IGRlZmF1bHRUYWdzRmlsdGVyO1xuXHRmb3IgKGNvbnN0IHNwZWMgb2Ygc3BlY3MpIHtcblx0XHRjb25zdCBmaWxlcGF0aCA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8gc3BlYyA6IHNwZWMuZmlsZXBhdGg7XG5cdFx0YXdhaXQgJChcImNvbGxlY3Rfc3BlY1wiLCB7IFwiY29kZS5maWxlLnBhdGhcIjogZmlsZXBhdGggfSwgYXN5bmMgKCkgPT4ge1xuXHRcdFx0cnVubmVyLl9jdXJyZW50U3BlY2lmaWNhdGlvbiA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8geyBmaWxlcGF0aDogc3BlYyB9IDogc3BlYztcblx0XHRcdGNvbnN0IHRlc3RMb2NhdGlvbnMgPSB0eXBlb2Ygc3BlYyA9PT0gXCJzdHJpbmdcIiA/IHVuZGVmaW5lZCA6IHNwZWMudGVzdExvY2F0aW9ucztcblx0XHRcdGNvbnN0IHRlc3ROYW1lUGF0dGVybiA9IHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiID8gdW5kZWZpbmVkIDogc3BlYy50ZXN0TmFtZVBhdHRlcm47XG5cdFx0XHRjb25zdCB0ZXN0SWRzID0gdHlwZW9mIHNwZWMgPT09IFwic3RyaW5nXCIgPyB1bmRlZmluZWQgOiBzcGVjLnRlc3RJZHM7XG5cdFx0XHRjb25zdCB0ZXN0VGFnc0ZpbHRlciA9IHR5cGVvZiBzcGVjID09PSBcIm9iamVjdFwiICYmIHNwZWMudGVzdFRhZ3NGaWx0ZXIgPyBjcmVhdGVUYWdzRmlsdGVyKHNwZWMudGVzdFRhZ3NGaWx0ZXIsIGNvbmZpZy50YWdzKSA6IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGZpbGVUYWdzID0gdHlwZW9mIHNwZWMgPT09IFwic3RyaW5nXCIgPyBbXSA6IHNwZWMuZmlsZVRhZ3MgfHwgW107XG5cdFx0XHRjb25zdCBmaWxlID0gY3JlYXRlRmlsZVRhc2soZmlsZXBhdGgsIGNvbmZpZy5yb290LCBjb25maWcubmFtZSwgcnVubmVyLnBvb2wsIHJ1bm5lci52aXRlRW52aXJvbm1lbnQpO1xuXHRcdFx0ZmlsZS50YWdzID0gZmlsZVRhZ3M7XG5cdFx0XHRmaWxlLnNodWZmbGUgPSBjb25maWcuc2VxdWVuY2Uuc2h1ZmZsZTtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHZhbGlkYXRlVGFncyhydW5uZXIuY29uZmlnLCBmaWxlVGFncyk7XG5cdFx0XHRcdHJ1bm5lci5vbkNvbGxlY3RTdGFydD8uKGZpbGUpO1xuXHRcdFx0XHRjbGVhckNvbGxlY3RvckNvbnRleHQoZmlsZSwgcnVubmVyKTtcblx0XHRcdFx0Y29uc3Qgc2V0dXBGaWxlcyA9IHRvQXJyYXkoY29uZmlnLnNldHVwRmlsZXMpO1xuXHRcdFx0XHRpZiAoc2V0dXBGaWxlcy5sZW5ndGgpIHtcblx0XHRcdFx0XHRjb25zdCBzZXR1cFN0YXJ0ID0gbm93JDEoKTtcblx0XHRcdFx0XHRhd2FpdCBydW5TZXR1cEZpbGVzKGNvbmZpZywgc2V0dXBGaWxlcywgcnVubmVyKTtcblx0XHRcdFx0XHRjb25zdCBzZXR1cEVuZCA9IG5vdyQxKCk7XG5cdFx0XHRcdFx0ZmlsZS5zZXR1cER1cmF0aW9uID0gc2V0dXBFbmQgLSBzZXR1cFN0YXJ0O1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGZpbGUuc2V0dXBEdXJhdGlvbiA9IDA7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y29uc3QgY29sbGVjdFN0YXJ0ID0gbm93JDEoKTtcblx0XHRcdFx0YXdhaXQgcnVubmVyLmltcG9ydEZpbGUoZmlsZXBhdGgsIFwiY29sbGVjdFwiKTtcblx0XHRcdFx0Y29uc3QgZHVyYXRpb25zID0gcnVubmVyLmdldEltcG9ydER1cmF0aW9ucz8uKCk7XG5cdFx0XHRcdGlmIChkdXJhdGlvbnMpIHtcblx0XHRcdFx0XHRmaWxlLmltcG9ydER1cmF0aW9ucyA9IGR1cmF0aW9ucztcblx0XHRcdFx0fVxuXHRcdFx0XHRjb25zdCBkZWZhdWx0VGFza3MgPSBhd2FpdCBnZXREZWZhdWx0U3VpdGUoKS5jb2xsZWN0KGZpbGUpO1xuXHRcdFx0XHRjb25zdCBmaWxlSG9va3MgPSBjcmVhdGVTdWl0ZUhvb2tzKCk7XG5cdFx0XHRcdG1lcmdlSG9va3MoZmlsZUhvb2tzLCBnZXRIb29rcyhkZWZhdWx0VGFza3MpKTtcblx0XHRcdFx0Zm9yIChjb25zdCBjIG9mIFsuLi5kZWZhdWx0VGFza3MudGFza3MsIC4uLmNvbGxlY3RvckNvbnRleHQudGFza3NdKSB7XG5cdFx0XHRcdFx0aWYgKGMudHlwZSA9PT0gXCJ0ZXN0XCIgfHwgYy50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdFx0XHRcdGZpbGUudGFza3MucHVzaChjKTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKGMudHlwZSA9PT0gXCJjb2xsZWN0b3JcIikge1xuXHRcdFx0XHRcdFx0Y29uc3Qgc3VpdGUgPSBhd2FpdCBjLmNvbGxlY3QoZmlsZSk7XG5cdFx0XHRcdFx0XHRpZiAoc3VpdGUubmFtZSB8fCBzdWl0ZS50YXNrcy5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0bWVyZ2VIb29rcyhmaWxlSG9va3MsIGdldEhvb2tzKHN1aXRlKSk7XG5cdFx0XHRcdFx0XHRcdGZpbGUudGFza3MucHVzaChzdWl0ZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdC8vIGNoZWNrIHRoYXQgdHlwZXMgYXJlIGV4aGF1c3RlZFxuXHRcdFx0XHRcdFx0Yztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0c2V0SG9va3MoZmlsZSwgZmlsZUhvb2tzKTtcblx0XHRcdFx0ZmlsZS5jb2xsZWN0RHVyYXRpb24gPSBub3ckMSgpIC0gY29sbGVjdFN0YXJ0O1xuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRjb25zdCBlcnJvcnMgPSBlIGluc3RhbmNlb2YgQWdncmVnYXRlRXJyb3IgPyBlLmVycm9ycy5tYXAoKGUpID0+IHByb2Nlc3NFcnJvcihlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKSkgOiBbcHJvY2Vzc0Vycm9yKGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpXTtcblx0XHRcdFx0ZmlsZS5yZXN1bHQgPSB7XG5cdFx0XHRcdFx0c3RhdGU6IFwiZmFpbFwiLFxuXHRcdFx0XHRcdGVycm9yc1xuXHRcdFx0XHR9O1xuXHRcdFx0XHRjb25zdCBkdXJhdGlvbnMgPSBydW5uZXIuZ2V0SW1wb3J0RHVyYXRpb25zPy4oKTtcblx0XHRcdFx0aWYgKGR1cmF0aW9ucykge1xuXHRcdFx0XHRcdGZpbGUuaW1wb3J0RHVyYXRpb25zID0gZHVyYXRpb25zO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRjYWxjdWxhdGVTdWl0ZUhhc2goZmlsZSk7XG5cdFx0XHRjb25zdCBoYXNPbmx5VGFza3MgPSBzb21lVGFza3NBcmVPbmx5KGZpbGUpO1xuXHRcdFx0aWYgKCF0ZXN0VGFnc0ZpbHRlciAmJiAhZGVmYXVsdFRhZ3NGaWx0ZXIgJiYgY29uZmlnLnRhZ3NGaWx0ZXIpIHtcblx0XHRcdFx0ZGVmYXVsdFRhZ3NGaWx0ZXIgPSBjcmVhdGVUYWdzRmlsdGVyKGNvbmZpZy50YWdzRmlsdGVyLCBjb25maWcudGFncyk7XG5cdFx0XHR9XG5cdFx0XHRpbnRlcnByZXRUYXNrTW9kZXMoZmlsZSwgdGVzdE5hbWVQYXR0ZXJuID8/IGNvbmZpZy50ZXN0TmFtZVBhdHRlcm4sIHRlc3RMb2NhdGlvbnMsIHRlc3RJZHMsIHRlc3RUYWdzRmlsdGVyID8/IGRlZmF1bHRUYWdzRmlsdGVyLCBoYXNPbmx5VGFza3MsIGZhbHNlLCBjb25maWcuYWxsb3dPbmx5KTtcblx0XHRcdGlmIChmaWxlLm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdFx0ZmlsZS5tb2RlID0gXCJydW5cIjtcblx0XHRcdH1cblx0XHRcdGZpbGVzLnB1c2goZmlsZSk7XG5cdFx0fSk7XG5cdH1cblx0cmV0dXJuIGZpbGVzO1xufVxuZnVuY3Rpb24gbWVyZ2VIb29rcyhiYXNlSG9va3MsIGhvb2tzKSB7XG5cdGZvciAoY29uc3QgX2tleSBpbiBob29rcykge1xuXHRcdGNvbnN0IGtleSA9IF9rZXk7XG5cdFx0YmFzZUhvb2tzW2tleV0ucHVzaCguLi5ob29rc1trZXldKTtcblx0fVxuXHRyZXR1cm4gYmFzZUhvb2tzO1xufVxuXG5jb25zdCBub3cgPSBnbG9iYWxUaGlzLnBlcmZvcm1hbmNlID8gZ2xvYmFsVGhpcy5wZXJmb3JtYW5jZS5ub3cuYmluZChnbG9iYWxUaGlzLnBlcmZvcm1hbmNlKSA6IERhdGUubm93O1xuY29uc3QgdW5peE5vdyA9IERhdGUubm93O1xuY29uc3QgeyBjbGVhclRpbWVvdXQsIHNldFRpbWVvdXQgfSA9IGdldFNhZmVUaW1lcnMoKTtcbmxldCBsaW1pdE1heENvbmN1cnJlbmN5O1xuLyoqXG4qIE5vcm1hbGl6ZXMgcmV0cnkgY29uZmlndXJhdGlvbiB0byBleHRyYWN0IGluZGl2aWR1YWwgdmFsdWVzLlxuKiBIYW5kbGVzIGJvdGggbnVtYmVyIGFuZCBvYmplY3QgZm9ybXMuXG4qL1xuZnVuY3Rpb24gZ2V0UmV0cnlDb3VudChyZXRyeSkge1xuXHRpZiAocmV0cnkgPT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiAwO1xuXHR9XG5cdGlmICh0eXBlb2YgcmV0cnkgPT09IFwibnVtYmVyXCIpIHtcblx0XHRyZXR1cm4gcmV0cnk7XG5cdH1cblx0cmV0dXJuIHJldHJ5LmNvdW50ID8/IDA7XG59XG5mdW5jdGlvbiBnZXRSZXRyeURlbGF5KHJldHJ5KSB7XG5cdGlmIChyZXRyeSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0cmV0dXJuIDA7XG5cdH1cblx0aWYgKHR5cGVvZiByZXRyeSA9PT0gXCJudW1iZXJcIikge1xuXHRcdHJldHVybiAwO1xuXHR9XG5cdHJldHVybiByZXRyeS5kZWxheSA/PyAwO1xufVxuZnVuY3Rpb24gZ2V0UmV0cnlDb25kaXRpb24ocmV0cnkpIHtcblx0aWYgKHJldHJ5ID09PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cdGlmICh0eXBlb2YgcmV0cnkgPT09IFwibnVtYmVyXCIpIHtcblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cdHJldHVybiByZXRyeS5jb25kaXRpb247XG59XG5mdW5jdGlvbiB1cGRhdGVTdWl0ZUhvb2tTdGF0ZSh0YXNrLCBuYW1lLCBzdGF0ZSwgcnVubmVyKSB7XG5cdGlmICghdGFzay5yZXN1bHQpIHtcblx0XHR0YXNrLnJlc3VsdCA9IHsgc3RhdGU6IFwicnVuXCIgfTtcblx0fVxuXHRpZiAoIXRhc2sucmVzdWx0Lmhvb2tzKSB7XG5cdFx0dGFzay5yZXN1bHQuaG9va3MgPSB7fTtcblx0fVxuXHRjb25zdCBzdWl0ZUhvb2tzID0gdGFzay5yZXN1bHQuaG9va3M7XG5cdGlmIChzdWl0ZUhvb2tzKSB7XG5cdFx0c3VpdGVIb29rc1tuYW1lXSA9IHN0YXRlO1xuXHRcdGxldCBldmVudCA9IHN0YXRlID09PSBcInJ1blwiID8gXCJiZWZvcmUtaG9vay1zdGFydFwiIDogXCJiZWZvcmUtaG9vay1lbmRcIjtcblx0XHRpZiAobmFtZSA9PT0gXCJhZnRlckFsbFwiIHx8IG5hbWUgPT09IFwiYWZ0ZXJFYWNoXCIpIHtcblx0XHRcdGV2ZW50ID0gc3RhdGUgPT09IFwicnVuXCIgPyBcImFmdGVyLWhvb2stc3RhcnRcIiA6IFwiYWZ0ZXItaG9vay1lbmRcIjtcblx0XHR9XG5cdFx0dXBkYXRlVGFzayhldmVudCwgdGFzaywgcnVubmVyKTtcblx0fVxufVxuZnVuY3Rpb24gZ2V0U3VpdGVIb29rcyhzdWl0ZSwgbmFtZSwgc2VxdWVuY2UpIHtcblx0Y29uc3QgaG9va3MgPSBnZXRIb29rcyhzdWl0ZSlbbmFtZV07XG5cdGlmIChzZXF1ZW5jZSA9PT0gXCJzdGFja1wiICYmIChuYW1lID09PSBcImFmdGVyQWxsXCIgfHwgbmFtZSA9PT0gXCJhZnRlckVhY2hcIikpIHtcblx0XHRyZXR1cm4gaG9va3Muc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0cmV0dXJuIGhvb2tzO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbFRlc3RIb29rcyhydW5uZXIsIHRlc3QsIGhvb2tzLCBzZXF1ZW5jZSkge1xuXHRpZiAoc2VxdWVuY2UgPT09IFwic3RhY2tcIikge1xuXHRcdGhvb2tzID0gaG9va3Muc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0aWYgKCFob29rcy5sZW5ndGgpIHtcblx0XHRyZXR1cm47XG5cdH1cblx0Y29uc3QgY29udGV4dCA9IHRlc3QuY29udGV4dDtcblx0Y29uc3Qgb25UZXN0RmFpbGVkID0gdGVzdC5jb250ZXh0Lm9uVGVzdEZhaWxlZDtcblx0Y29uc3Qgb25UZXN0RmluaXNoZWQgPSB0ZXN0LmNvbnRleHQub25UZXN0RmluaXNoZWQ7XG5cdGNvbnRleHQub25UZXN0RmFpbGVkID0gKCkgPT4ge1xuXHRcdHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGNhbGwgXCJvblRlc3RGYWlsZWRcIiBpbnNpZGUgYSB0ZXN0IGhvb2suYCk7XG5cdH07XG5cdGNvbnRleHQub25UZXN0RmluaXNoZWQgPSAoKSA9PiB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgY2FsbCBcIm9uVGVzdEZpbmlzaGVkXCIgaW5zaWRlIGEgdGVzdCBob29rLmApO1xuXHR9O1xuXHRpZiAoc2VxdWVuY2UgPT09IFwicGFyYWxsZWxcIikge1xuXHRcdHRyeSB7XG5cdFx0XHRhd2FpdCBQcm9taXNlLmFsbChob29rcy5tYXAoKGZuKSA9PiBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKHRlc3QuY29udGV4dCkpKSk7XG5cdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0ZmFpbFRhc2sodGVzdC5yZXN1bHQsIGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdH1cblx0fSBlbHNlIHtcblx0XHRmb3IgKGNvbnN0IGZuIG9mIGhvb2tzKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhd2FpdCBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKHRlc3QuY29udGV4dCkpO1xuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdGNvbnRleHQub25UZXN0RmFpbGVkID0gb25UZXN0RmFpbGVkO1xuXHRjb250ZXh0Lm9uVGVzdEZpbmlzaGVkID0gb25UZXN0RmluaXNoZWQ7XG59XG5hc3luYyBmdW5jdGlvbiBjYWxsU3VpdGVIb29rKHN1aXRlLCBjdXJyZW50VGFzaywgbmFtZSwgcnVubmVyLCBhcmdzKSB7XG5cdGNvbnN0IHNlcXVlbmNlID0gcnVubmVyLmNvbmZpZy5zZXF1ZW5jZS5ob29rcztcblx0Y29uc3QgY2FsbGJhY2tzID0gW107XG5cdC8vIHN0b3AgYXQgZmlsZSBsZXZlbFxuXHRjb25zdCBwYXJlbnRTdWl0ZSA9IFwiZmlsZXBhdGhcIiBpbiBzdWl0ZSA/IG51bGwgOiBzdWl0ZS5zdWl0ZSB8fCBzdWl0ZS5maWxlO1xuXHRpZiAobmFtZSA9PT0gXCJiZWZvcmVFYWNoXCIgJiYgcGFyZW50U3VpdGUpIHtcblx0XHRjYWxsYmFja3MucHVzaCguLi5hd2FpdCBjYWxsU3VpdGVIb29rKHBhcmVudFN1aXRlLCBjdXJyZW50VGFzaywgbmFtZSwgcnVubmVyLCBhcmdzKSk7XG5cdH1cblx0Y29uc3QgaG9va3MgPSBnZXRTdWl0ZUhvb2tzKHN1aXRlLCBuYW1lLCBzZXF1ZW5jZSk7XG5cdGlmIChob29rcy5sZW5ndGggPiAwKSB7XG5cdFx0dXBkYXRlU3VpdGVIb29rU3RhdGUoY3VycmVudFRhc2ssIG5hbWUsIFwicnVuXCIsIHJ1bm5lcik7XG5cdH1cblx0YXN5bmMgZnVuY3Rpb24gcnVuSG9vayhob29rKSB7XG5cdFx0cmV0dXJuIGxpbWl0TWF4Q29uY3VycmVuY3koYXN5bmMgKCkgPT4ge1xuXHRcdFx0cmV0dXJuIGdldEJlZm9yZUhvb2tDbGVhbnVwQ2FsbGJhY2soaG9vaywgYXdhaXQgaG9vayguLi5hcmdzKSwgbmFtZSA9PT0gXCJiZWZvcmVFYWNoXCIgPyBhcmdzWzBdIDogdW5kZWZpbmVkKTtcblx0XHR9KTtcblx0fVxuXHRpZiAoc2VxdWVuY2UgPT09IFwicGFyYWxsZWxcIikge1xuXHRcdGNhbGxiYWNrcy5wdXNoKC4uLmF3YWl0IFByb21pc2UuYWxsKGhvb2tzLm1hcCgoaG9vaykgPT4gcnVuSG9vayhob29rKSkpKTtcblx0fSBlbHNlIHtcblx0XHRmb3IgKGNvbnN0IGhvb2sgb2YgaG9va3MpIHtcblx0XHRcdGNhbGxiYWNrcy5wdXNoKGF3YWl0IHJ1bkhvb2soaG9vaykpO1xuXHRcdH1cblx0fVxuXHRpZiAoaG9va3MubGVuZ3RoID4gMCkge1xuXHRcdHVwZGF0ZVN1aXRlSG9va1N0YXRlKGN1cnJlbnRUYXNrLCBuYW1lLCBcInBhc3NcIiwgcnVubmVyKTtcblx0fVxuXHRpZiAobmFtZSA9PT0gXCJhZnRlckVhY2hcIiAmJiBwYXJlbnRTdWl0ZSkge1xuXHRcdGNhbGxiYWNrcy5wdXNoKC4uLmF3YWl0IGNhbGxTdWl0ZUhvb2socGFyZW50U3VpdGUsIGN1cnJlbnRUYXNrLCBuYW1lLCBydW5uZXIsIGFyZ3MpKTtcblx0fVxuXHRyZXR1cm4gY2FsbGJhY2tzO1xufVxuZnVuY3Rpb24gZ2V0QXJvdW5kRWFjaEhvb2tzKHN1aXRlKSB7XG5cdGNvbnN0IGhvb2tzID0gW107XG5cdGNvbnN0IHBhcmVudFN1aXRlID0gXCJmaWxlcGF0aFwiIGluIHN1aXRlID8gbnVsbCA6IHN1aXRlLnN1aXRlIHx8IHN1aXRlLmZpbGU7XG5cdGlmIChwYXJlbnRTdWl0ZSkge1xuXHRcdGhvb2tzLnB1c2goLi4uZ2V0QXJvdW5kRWFjaEhvb2tzKHBhcmVudFN1aXRlKSk7XG5cdH1cblx0aG9va3MucHVzaCguLi5nZXRIb29rcyhzdWl0ZSkuYXJvdW5kRWFjaCk7XG5cdHJldHVybiBob29rcztcbn1cbmZ1bmN0aW9uIGdldEFyb3VuZEFsbEhvb2tzKHN1aXRlKSB7XG5cdHJldHVybiBnZXRIb29rcyhzdWl0ZSkuYXJvdW5kQWxsO1xufVxuZnVuY3Rpb24gbWFrZUFyb3VuZEhvb2tUaW1lb3V0RXJyb3IoaG9va05hbWUsIHBoYXNlLCB0aW1lb3V0LCBzdGFja1RyYWNlRXJyb3IpIHtcblx0Y29uc3QgbWVzc2FnZSA9IGBUaGUgJHtwaGFzZX0gcGhhc2Ugb2YgXCIke2hvb2tOYW1lfVwiIGhvb2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tcy5gO1xuXHRjb25zdCBFcnJvckNsYXNzID0gcGhhc2UgPT09IFwic2V0dXBcIiA/IEFyb3VuZEhvb2tTZXR1cEVycm9yIDogQXJvdW5kSG9va1RlYXJkb3duRXJyb3I7XG5cdGNvbnN0IGVycm9yID0gbmV3IEVycm9yQ2xhc3MobWVzc2FnZSk7XG5cdGlmIChzdGFja1RyYWNlRXJyb3I/LnN0YWNrKSB7XG5cdFx0ZXJyb3Iuc3RhY2sgPSBzdGFja1RyYWNlRXJyb3Iuc3RhY2sucmVwbGFjZShzdGFja1RyYWNlRXJyb3IubWVzc2FnZSwgZXJyb3IubWVzc2FnZSk7XG5cdH1cblx0cmV0dXJuIGVycm9yO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbEFyb3VuZEhvb2tzKHJ1bklubmVyLCBvcHRpb25zKSB7XG5cdGNvbnN0IHsgaG9va3MsIGhvb2tOYW1lLCBjYWxsYmFja05hbWUsIG9uVGltZW91dCwgaW52b2tlSG9vayB9ID0gb3B0aW9ucztcblx0aWYgKCFob29rcy5sZW5ndGgpIHtcblx0XHRhd2FpdCBydW5Jbm5lcigpO1xuXHRcdHJldHVybjtcblx0fVxuXHRjb25zdCBob29rRXJyb3JzID0gW107XG5cdGNvbnN0IGNyZWF0ZVRpbWVvdXRQcm9taXNlID0gKHRpbWVvdXQsIHBoYXNlLCBzdGFja1RyYWNlRXJyb3IpID0+IHtcblx0XHRsZXQgdGltZXI7XG5cdFx0bGV0IHRpbWVkb3V0ID0gZmFsc2U7XG5cdFx0Y29uc3QgcHJvbWlzZSA9IG5ldyBQcm9taXNlKChfLCByZWplY3QpID0+IHtcblx0XHRcdGlmICh0aW1lb3V0ID4gMCAmJiB0aW1lb3V0ICE9PSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpIHtcblx0XHRcdFx0dGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0XHR0aW1lZG91dCA9IHRydWU7XG5cdFx0XHRcdFx0Y29uc3QgZXJyb3IgPSBtYWtlQXJvdW5kSG9va1RpbWVvdXRFcnJvcihob29rTmFtZSwgcGhhc2UsIHRpbWVvdXQsIHN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHRcdFx0b25UaW1lb3V0Py4oZXJyb3IpO1xuXHRcdFx0XHRcdHJlamVjdChlcnJvcik7XG5cdFx0XHRcdH0sIHRpbWVvdXQpO1xuXHRcdFx0XHR0aW1lci51bnJlZj8uKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Y29uc3QgY2xlYXIgPSAoKSA9PiB7XG5cdFx0XHRpZiAodGltZXIpIHtcblx0XHRcdFx0Y2xlYXJUaW1lb3V0KHRpbWVyKTtcblx0XHRcdFx0dGltZXIgPSB1bmRlZmluZWQ7XG5cdFx0XHR9XG5cdFx0fTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0cHJvbWlzZSxcblx0XHRcdGNsZWFyLFxuXHRcdFx0aXNUaW1lZE91dDogKCkgPT4gdGltZWRvdXRcblx0XHR9O1xuXHR9O1xuXHRjb25zdCBydW5OZXh0SG9vayA9IGFzeW5jIChpbmRleCkgPT4ge1xuXHRcdGlmIChpbmRleCA+PSBob29rcy5sZW5ndGgpIHtcblx0XHRcdHJldHVybiBydW5Jbm5lcigpO1xuXHRcdH1cblx0XHRjb25zdCBob29rID0gaG9va3NbaW5kZXhdO1xuXHRcdGNvbnN0IHRpbWVvdXQgPSBnZXRBcm91bmRIb29rVGltZW91dChob29rKTtcblx0XHRjb25zdCBzdGFja1RyYWNlRXJyb3IgPSBnZXRBcm91bmRIb29rU3RhY2tUcmFjZShob29rKTtcblx0XHRsZXQgdXNlQ2FsbGVkID0gZmFsc2U7XG5cdFx0bGV0IHNldHVwVGltZW91dDtcblx0XHRsZXQgdGVhcmRvd25UaW1lb3V0O1xuXHRcdGxldCBzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlO1xuXHRcdGxldCB0ZWFyZG93bkxpbWl0Q29uY3VycmVuY3lSZWxlYXNlO1xuXHRcdC8vIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHVzZSgpIGlzIGNhbGxlZCAoc2V0dXAgcGhhc2UgY29tcGxldGUpXG5cdFx0bGV0IHJlc29sdmVVc2VDYWxsZWQ7XG5cdFx0Y29uc3QgdXNlQ2FsbGVkUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG5cdFx0XHRyZXNvbHZlVXNlQ2FsbGVkID0gcmVzb2x2ZTtcblx0XHR9KTtcblx0XHQvLyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB1c2UoKSByZXR1cm5zIChpbm5lciBob29rcyBjb21wbGV0ZSwgdGVhcmRvd24gcGhhc2Ugc3RhcnRzKVxuXHRcdGxldCByZXNvbHZlVXNlUmV0dXJuZWQ7XG5cdFx0Y29uc3QgdXNlUmV0dXJuZWRQcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcblx0XHRcdHJlc29sdmVVc2VSZXR1cm5lZCA9IHJlc29sdmU7XG5cdFx0fSk7XG5cdFx0Ly8gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaG9vayBjb21wbGV0ZXNcblx0XHRsZXQgcmVzb2x2ZUhvb2tDb21wbGV0ZTtcblx0XHRsZXQgcmVqZWN0SG9va0NvbXBsZXRlO1xuXHRcdGNvbnN0IGhvb2tDb21wbGV0ZVByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG5cdFx0XHRyZXNvbHZlSG9va0NvbXBsZXRlID0gcmVzb2x2ZTtcblx0XHRcdHJlamVjdEhvb2tDb21wbGV0ZSA9IHJlamVjdDtcblx0XHR9KTtcblx0XHRjb25zdCB1c2UgPSBhc3luYyAoKSA9PiB7XG5cdFx0XHQvLyBzaG91bGRuJ3QgY29udGludWUgdG8gbmV4dCAocnVuVGVzdC9TdWl0ZSBvciBpbm5lciBhcm91bmRFYWNoL0FsbCkgd2hlbiBhcm91bmRFYWNoL0FsbCBzZXR1cCB0aW1lZCBvdXQuXG5cdFx0XHRpZiAoc2V0dXBUaW1lb3V0LmlzVGltZWRPdXQoKSkge1xuXHRcdFx0XHQvLyB3ZSBjYW4gdGhyb3cgYW55IGVycm9yIHRvIGJhaWwgb3V0LlxuXHRcdFx0XHQvLyB0aGlzIGVycm9yIGlzIG5vdCBzZWVuIGJ5IGVuZCB1c2VycyBzaW5jZSBgcnVuTmV4dEhvb2tgIGFscmVhZHkgcmVqZWN0ZWQgd2l0aCB0aW1lb3V0IGVycm9yXG5cdFx0XHRcdC8vIGFuZCB0aGlzIGVycm9yIGlzIGNhdWdodCBieSBgcmVqZWN0SG9va0NvbXBsZXRlYC5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKFwiX19WSVRFU1RfSU5URVJOQUxfQVJPVU5EX0hPT0tfQUJPUlRfX1wiKTtcblx0XHRcdH1cblx0XHRcdGlmICh1c2VDYWxsZWQpIHtcblx0XHRcdFx0dGhyb3cgbmV3IEFyb3VuZEhvb2tNdWx0aXBsZUNhbGxzRXJyb3IoYFRoZSBcXGAke2NhbGxiYWNrTmFtZX1cXGAgY2FsbGJhY2sgd2FzIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBpbiB0aGUgXFxgJHtob29rTmFtZX1cXGAgaG9vay4gYCArIGBUaGUgY2FsbGJhY2sgY2FuIG9ubHkgYmUgY2FsbGVkIG9uY2UgcGVyIGhvb2suYCk7XG5cdFx0XHR9XG5cdFx0XHR1c2VDYWxsZWQgPSB0cnVlO1xuXHRcdFx0cmVzb2x2ZVVzZUNhbGxlZCgpO1xuXHRcdFx0Ly8gU2V0dXAgcGhhc2UgY29tcGxldGVkIC0gY2xlYXIgc2V0dXAgdGltZXJcblx0XHRcdHNldHVwVGltZW91dC5jbGVhcigpO1xuXHRcdFx0c2V0dXBMaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHQvLyBSdW4gaW5uZXIgaG9va3MgLSBkb24ndCB0aW1lIHRoaXMgYWdhaW5zdCBvdXIgdGVhcmRvd24gdGltZW91dFxuXHRcdFx0YXdhaXQgcnVuTmV4dEhvb2soaW5kZXggKyAxKS5jYXRjaCgoZSkgPT4gaG9va0Vycm9ycy5wdXNoKGUpKTtcblx0XHRcdHRlYXJkb3duTGltaXRDb25jdXJyZW5jeVJlbGVhc2UgPSBhd2FpdCBsaW1pdE1heENvbmN1cnJlbmN5LmFjcXVpcmUoKTtcblx0XHRcdC8vIFN0YXJ0IHRlYXJkb3duIHRpbWVyIGFmdGVyIGlubmVyIGhvb2tzIGNvbXBsZXRlIC0gb25seSB0aW1lcyB0aGlzIGhvb2sncyB0ZWFyZG93biBjb2RlXG5cdFx0XHR0ZWFyZG93blRpbWVvdXQgPSBjcmVhdGVUaW1lb3V0UHJvbWlzZSh0aW1lb3V0LCBcInRlYXJkb3duXCIsIHN0YWNrVHJhY2VFcnJvcik7XG5cdFx0XHQvLyBTaWduYWwgdGhhdCB1c2UoKSBpcyByZXR1cm5pbmcgKHRlYXJkb3duIHBoYXNlIHN0YXJ0aW5nKVxuXHRcdFx0cmVzb2x2ZVVzZVJldHVybmVkKCk7XG5cdFx0fTtcblx0XHRzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlID0gYXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeS5hY3F1aXJlKCk7XG5cdFx0Ly8gU3RhcnQgc2V0dXAgdGltZW91dFxuXHRcdHNldHVwVGltZW91dCA9IGNyZWF0ZVRpbWVvdXRQcm9taXNlKHRpbWVvdXQsIFwic2V0dXBcIiwgc3RhY2tUcmFjZUVycm9yKTtcblx0XHQoYXN5bmMgKCkgPT4ge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YXdhaXQgaW52b2tlSG9vayhob29rLCB1c2UpO1xuXHRcdFx0XHRpZiAoIXVzZUNhbGxlZCkge1xuXHRcdFx0XHRcdHRocm93IG5ldyBBcm91bmRIb29rU2V0dXBFcnJvcihgVGhlIFxcYCR7Y2FsbGJhY2tOYW1lfVxcYCBjYWxsYmFjayB3YXMgbm90IGNhbGxlZCBpbiB0aGUgXFxgJHtob29rTmFtZX1cXGAgaG9vay4gYCArIGBNYWtlIHN1cmUgdG8gY2FsbCBcXGAke2NhbGxiYWNrTmFtZX1cXGAgdG8gcnVuIHRoZSAke2hvb2tOYW1lID09PSBcImFyb3VuZEVhY2hcIiA/IFwidGVzdFwiIDogXCJzdWl0ZVwifS5gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXNvbHZlSG9va0NvbXBsZXRlKCk7XG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRyZWplY3RIb29rQ29tcGxldGUoZXJyb3IpO1xuXHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0c2V0dXBMaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHRcdHRlYXJkb3duTGltaXRDb25jdXJyZW5jeVJlbGVhc2U/LigpO1xuXHRcdFx0fVxuXHRcdH0pKCk7XG5cdFx0Ly8gV2FpdCBmb3IgZWl0aGVyOiB1c2UoKSB0byBiZSBjYWxsZWQgT1IgaG9vayB0byBjb21wbGV0ZSAoZXJyb3IpIE9SIHNldHVwIHRpbWVvdXRcblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFtcblx0XHRcdFx0dXNlQ2FsbGVkUHJvbWlzZSxcblx0XHRcdFx0aG9va0NvbXBsZXRlUHJvbWlzZSxcblx0XHRcdFx0c2V0dXBUaW1lb3V0LnByb21pc2Vcblx0XHRcdF0pO1xuXHRcdH0gZmluYWxseSB7XG5cdFx0XHRzZXR1cExpbWl0Q29uY3VycmVuY3lSZWxlYXNlPy4oKTtcblx0XHRcdHNldHVwVGltZW91dC5jbGVhcigpO1xuXHRcdH1cblx0XHQvLyBXYWl0IGZvciB1c2UoKSB0byByZXR1cm4gKGlubmVyIGhvb2tzIGNvbXBsZXRlKSBPUiBob29rIHRvIGNvbXBsZXRlIChlcnJvciBkdXJpbmcgaW5uZXIgaG9va3MpXG5cdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFt1c2VSZXR1cm5lZFByb21pc2UsIGhvb2tDb21wbGV0ZVByb21pc2VdKTtcblx0XHQvLyBOb3cgdGVhcmRvd25UaW1lb3V0IGlzIGd1YXJhbnRlZWQgdG8gYmUgc2V0XG5cdFx0Ly8gV2FpdCBmb3IgaG9vayB0byBjb21wbGV0ZSAodGVhcmRvd24pIE9SIHRlYXJkb3duIHRpbWVvdXRcblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5yYWNlKFtob29rQ29tcGxldGVQcm9taXNlLCB0ZWFyZG93blRpbWVvdXQ/LnByb21pc2VdKTtcblx0XHR9IGZpbmFsbHkge1xuXHRcdFx0dGVhcmRvd25MaW1pdENvbmN1cnJlbmN5UmVsZWFzZT8uKCk7XG5cdFx0XHR0ZWFyZG93blRpbWVvdXQ/LmNsZWFyKCk7XG5cdFx0fVxuXHR9O1xuXHRhd2FpdCBydW5OZXh0SG9vaygwKS5jYXRjaCgoZSkgPT4gaG9va0Vycm9ycy5wdXNoKGUpKTtcblx0aWYgKGhvb2tFcnJvcnMubGVuZ3RoID4gMCkge1xuXHRcdHRocm93IGhvb2tFcnJvcnM7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIGNhbGxBcm91bmRBbGxIb29rcyhzdWl0ZSwgcnVuU3VpdGVJbm5lcikge1xuXHRhd2FpdCBjYWxsQXJvdW5kSG9va3MocnVuU3VpdGVJbm5lciwge1xuXHRcdGhvb2tzOiBnZXRBcm91bmRBbGxIb29rcyhzdWl0ZSksXG5cdFx0aG9va05hbWU6IFwiYXJvdW5kQWxsXCIsXG5cdFx0Y2FsbGJhY2tOYW1lOiBcInJ1blN1aXRlKClcIixcblx0XHRpbnZva2VIb29rOiAoaG9vaywgdXNlKSA9PiBob29rKHVzZSwgc3VpdGUpXG5cdH0pO1xufVxuYXN5bmMgZnVuY3Rpb24gY2FsbEFyb3VuZEVhY2hIb29rcyhzdWl0ZSwgdGVzdCwgcnVuVGVzdCkge1xuXHRhd2FpdCBjYWxsQXJvdW5kSG9va3MoXG5cdFx0Ly8gVGFrZSBjaGVja3BvaW50IHJpZ2h0IGJlZm9yZSBydW5UZXN0IC0gYXQgdGhpcyBwb2ludCBhbGwgYXJvdW5kRWFjaCBmaXh0dXJlc1xuXHRcdC8vIGhhdmUgYmVlbiByZXNvbHZlZCwgc28gd2UgY2FuIGNvcnJlY3RseSBpZGVudGlmeSB3aGljaCBmaXh0dXJlcyBiZWxvbmcgdG9cblx0XHQvLyBhcm91bmRFYWNoIChiZWZvcmUgY2hlY2twb2ludCkgdnMgaW5zaWRlIHJ1blRlc3QgKGFmdGVyIGNoZWNrcG9pbnQpXG5cdFx0KCkgPT4gcnVuVGVzdChnZXRGaXh0dXJlQ2xlYW51cENvdW50KHRlc3QuY29udGV4dCkpLFxuXHRcdHtcblx0XHRcdGhvb2tzOiBnZXRBcm91bmRFYWNoSG9va3Moc3VpdGUpLFxuXHRcdFx0aG9va05hbWU6IFwiYXJvdW5kRWFjaFwiLFxuXHRcdFx0Y2FsbGJhY2tOYW1lOiBcInJ1blRlc3QoKVwiLFxuXHRcdFx0b25UaW1lb3V0OiAoZXJyb3IpID0+IGFib3J0Q29udGV4dFNpZ25hbCh0ZXN0LmNvbnRleHQsIGVycm9yKSxcblx0XHRcdGludm9rZUhvb2s6IChob29rLCB1c2UpID0+IGhvb2sodXNlLCB0ZXN0LmNvbnRleHQsIHN1aXRlKVxuXHRcdH1cblx0KTtcbn1cbmNvbnN0IHBhY2tzID0gbmV3IE1hcCgpO1xuY29uc3QgZXZlbnRzUGFja3MgPSBbXTtcbmNvbnN0IHBlbmRpbmdUYXNrc1VwZGF0ZXMgPSBbXTtcbmZ1bmN0aW9uIHNlbmRUYXNrc1VwZGF0ZShydW5uZXIpIHtcblx0aWYgKHBhY2tzLnNpemUpIHtcblx0XHRjb25zdCB0YXNrUGFja3MgPSBBcnJheS5mcm9tKHBhY2tzKS5tYXAoKFtpZCwgdGFza10pID0+IHtcblx0XHRcdHJldHVybiBbXG5cdFx0XHRcdGlkLFxuXHRcdFx0XHR0YXNrWzBdLFxuXHRcdFx0XHR0YXNrWzFdXG5cdFx0XHRdO1xuXHRcdH0pO1xuXHRcdGNvbnN0IHAgPSBydW5uZXIub25UYXNrVXBkYXRlPy4odGFza1BhY2tzLCBldmVudHNQYWNrcyk7XG5cdFx0aWYgKHApIHtcblx0XHRcdHBlbmRpbmdUYXNrc1VwZGF0ZXMucHVzaChwKTtcblx0XHRcdC8vIHJlbW92ZSBzdWNjZXNzZnVsIHByb21pc2UgdG8gbm90IGdyb3cgYXJyYXkgaW5kZWZpbml0ZWx5LFxuXHRcdFx0Ly8gYnV0IGtlZXAgcmVqZWN0aW9ucyBzbyBmaW5pc2hTZW5kVGFza3NVcGRhdGUgY2FuIGhhbmRsZSB0aGVtXG5cdFx0XHRwLnRoZW4oKCkgPT4gcGVuZGluZ1Rhc2tzVXBkYXRlcy5zcGxpY2UocGVuZGluZ1Rhc2tzVXBkYXRlcy5pbmRleE9mKHApLCAxKSwgKCkgPT4ge30pO1xuXHRcdH1cblx0XHRldmVudHNQYWNrcy5sZW5ndGggPSAwO1xuXHRcdHBhY2tzLmNsZWFyKCk7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIGZpbmlzaFNlbmRUYXNrc1VwZGF0ZShydW5uZXIpIHtcblx0c2VuZFRhc2tzVXBkYXRlKHJ1bm5lcik7XG5cdGF3YWl0IFByb21pc2UuYWxsKHBlbmRpbmdUYXNrc1VwZGF0ZXMpO1xufVxuZnVuY3Rpb24gdGhyb3R0bGUoZm4sIG1zKSB7XG5cdGxldCBsYXN0ID0gMDtcblx0bGV0IHBlbmRpbmdDYWxsO1xuXHRyZXR1cm4gZnVuY3Rpb24gY2FsbCguLi5hcmdzKSB7XG5cdFx0Y29uc3Qgbm93ID0gdW5peE5vdygpO1xuXHRcdGlmIChub3cgLSBsYXN0ID4gbXMpIHtcblx0XHRcdGxhc3QgPSBub3c7XG5cdFx0XHRjbGVhclRpbWVvdXQocGVuZGluZ0NhbGwpO1xuXHRcdFx0cGVuZGluZ0NhbGwgPSB1bmRlZmluZWQ7XG5cdFx0XHRyZXR1cm4gZm4uYXBwbHkodGhpcywgYXJncyk7XG5cdFx0fVxuXHRcdC8vIE1ha2Ugc3VyZSBmbiBpcyBzdGlsbCBjYWxsZWQgZXZlbiBpZiB0aGVyZSBhcmUgbm8gZnVydGhlciBjYWxsc1xuXHRcdHBlbmRpbmdDYWxsID8/PSBzZXRUaW1lb3V0KCgpID0+IGNhbGwuYmluZCh0aGlzKSguLi5hcmdzKSwgbXMpO1xuXHR9O1xufVxuLy8gdGhyb3R0bGUgYmFzZWQgb24gc3VtbWFyeSByZXBvcnRlcidzIERVUkFUSU9OX1VQREFURV9JTlRFUlZBTF9NU1xuY29uc3Qgc2VuZFRhc2tzVXBkYXRlVGhyb3R0bGVkID0gdGhyb3R0bGUoc2VuZFRhc2tzVXBkYXRlLCAxMDApO1xuZnVuY3Rpb24gdXBkYXRlVGFzayhldmVudCwgdGFzaywgcnVubmVyKSB7XG5cdGV2ZW50c1BhY2tzLnB1c2goW1xuXHRcdHRhc2suaWQsXG5cdFx0ZXZlbnQsXG5cdFx0dW5kZWZpbmVkXG5cdF0pO1xuXHRwYWNrcy5zZXQodGFzay5pZCwgW3Rhc2sucmVzdWx0LCB0YXNrLm1ldGFdKTtcblx0c2VuZFRhc2tzVXBkYXRlVGhyb3R0bGVkKHJ1bm5lcik7XG59XG5hc3luYyBmdW5jdGlvbiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgY2xlYW51cHMpIHtcblx0Y29uc3Qgc2VxdWVuY2UgPSBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmhvb2tzO1xuXHRpZiAoc2VxdWVuY2UgPT09IFwic3RhY2tcIikge1xuXHRcdGNsZWFudXBzID0gY2xlYW51cHMuc2xpY2UoKS5yZXZlcnNlKCk7XG5cdH1cblx0aWYgKHNlcXVlbmNlID09PSBcInBhcmFsbGVsXCIpIHtcblx0XHRhd2FpdCBQcm9taXNlLmFsbChjbGVhbnVwcy5tYXAoYXN5bmMgKGZuKSA9PiB7XG5cdFx0XHRpZiAodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBmbigpKTtcblx0XHR9KSk7XG5cdH0gZWxzZSB7XG5cdFx0Zm9yIChjb25zdCBmbiBvZiBjbGVhbnVwcykge1xuXHRcdFx0aWYgKHR5cGVvZiBmbiAhPT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXHRcdFx0YXdhaXQgbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBmbigpKTtcblx0XHR9XG5cdH1cbn1cbi8qKlxuKiBEZXRlcm1pbmVzIGlmIGEgdGVzdCBzaG91bGQgYmUgcmV0cmllZCBiYXNlZCBvbiBpdHMgcmV0cnlDb25kaXRpb24gY29uZmlndXJhdGlvblxuKi9cbmZ1bmN0aW9uIHBhc3Nlc1JldHJ5Q29uZGl0aW9uKHRlc3QsIGVycm9ycykge1xuXHRjb25zdCBjb25kaXRpb24gPSBnZXRSZXRyeUNvbmRpdGlvbih0ZXN0LnJldHJ5KTtcblx0aWYgKCFlcnJvcnMgfHwgZXJyb3JzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXHRpZiAoIWNvbmRpdGlvbikge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cdGNvbnN0IGVycm9yID0gZXJyb3JzW2Vycm9ycy5sZW5ndGggLSAxXTtcblx0aWYgKGNvbmRpdGlvbiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuXHRcdHJldHVybiBjb25kaXRpb24udGVzdChlcnJvci5tZXNzYWdlIHx8IFwiXCIpO1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBjb25kaXRpb24gPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdHJldHVybiBjb25kaXRpb24oZXJyb3IpO1xuXHR9XG5cdHJldHVybiBmYWxzZTtcbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1blRlc3QodGVzdCwgcnVubmVyKSB7XG5cdGF3YWl0IHJ1bm5lci5vbkJlZm9yZVJ1blRhc2s/Lih0ZXN0KTtcblx0aWYgKHRlc3QubW9kZSAhPT0gXCJydW5cIiAmJiB0ZXN0Lm1vZGUgIT09IFwicXVldWVkXCIpIHtcblx0XHR1cGRhdGVUYXNrKFwidGVzdC1wcmVwYXJlXCIsIHRlc3QsIHJ1bm5lcik7XG5cdFx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHRyZXR1cm47XG5cdH1cblx0aWYgKHRlc3QucmVzdWx0Py5zdGF0ZSA9PT0gXCJmYWlsXCIpIHtcblx0XHQvLyBzaG91bGQgbm90IGJlIHBvc3NpYmxlIHRvIGdldCBoZXJlLCBJIHRoaW5rIHRoaXMgaXMganVzdCBjb3B5IHBhc3RlZCBmcm9tIHN1aXRlXG5cdFx0Ly8gVE9ETzogbWF5YmUgc29tZW9uZSBmYWlscyB0ZXN0cyBpbiBgYmVmb3JlQWxsYCBob29rcz9cblx0XHQvLyBodHRwczovL2dpdGh1Yi5jb20vdml0ZXN0LWRldi92aXRlc3QvcHVsbC83MDY5XG5cdFx0dXBkYXRlVGFzayhcInRlc3QtZmFpbGVkLWVhcmx5XCIsIHRlc3QsIHJ1bm5lcik7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGNvbnN0IHN0YXJ0ID0gbm93KCk7XG5cdHRlc3QucmVzdWx0ID0ge1xuXHRcdHN0YXRlOiBcInJ1blwiLFxuXHRcdHN0YXJ0VGltZTogdW5peE5vdygpLFxuXHRcdHJldHJ5Q291bnQ6IDBcblx0fTtcblx0dXBkYXRlVGFzayhcInRlc3QtcHJlcGFyZVwiLCB0ZXN0LCBydW5uZXIpO1xuXHRjb25zdCBjbGVhbnVwUnVubmluZ1Rlc3QgPSBhZGRSdW5uaW5nVGVzdCh0ZXN0KTtcblx0c2V0Q3VycmVudFRlc3QodGVzdCk7XG5cdGNvbnN0IHN1aXRlID0gdGVzdC5zdWl0ZSB8fCB0ZXN0LmZpbGU7XG5cdGNvbnN0ICQgPSBydW5uZXIudHJhY2U7XG5cdGNvbnN0IHJlcGVhdHMgPSB0ZXN0LnJlcGVhdHMgPz8gMDtcblx0Zm9yIChsZXQgcmVwZWF0Q291bnQgPSAwOyByZXBlYXRDb3VudCA8PSByZXBlYXRzOyByZXBlYXRDb3VudCsrKSB7XG5cdFx0Y29uc3QgcmV0cnkgPSBnZXRSZXRyeUNvdW50KHRlc3QucmV0cnkpO1xuXHRcdGZvciAobGV0IHJldHJ5Q291bnQgPSAwOyByZXRyeUNvdW50IDw9IHJldHJ5OyByZXRyeUNvdW50KyspIHtcblx0XHRcdGxldCBiZWZvcmVFYWNoQ2xlYW51cHMgPSBbXTtcblx0XHRcdC8vIGZpeHR1cmVDaGVja3BvaW50IGlzIHBhc3NlZCBieSBjYWxsQXJvdW5kRWFjaEhvb2tzIC0gaXQgcmVwcmVzZW50cyB0aGUgY291bnRcblx0XHRcdC8vIG9mIGZpeHR1cmUgY2xlYW51cCBmdW5jdGlvbnMgQUZURVIgYWxsIGFyb3VuZEVhY2ggZml4dHVyZXMgaGF2ZSBiZWVuIHJlc29sdmVkXG5cdFx0XHQvLyBidXQgQkVGT1JFIHRoZSB0ZXN0IHJ1bnMuIFRoaXMgYWxsb3dzIHVzIHRvIGNsZWFuIHVwIG9ubHkgZml4dHVyZXMgY3JlYXRlZFxuXHRcdFx0Ly8gaW5zaWRlIHJ1blRlc3Qgd2hpbGUgcHJlc2VydmluZyBhcm91bmRFYWNoIGZpeHR1cmVzIGZvciB0ZWFyZG93bi5cblx0XHRcdGF3YWl0IGNhbGxBcm91bmRFYWNoSG9va3Moc3VpdGUsIHRlc3QsIGFzeW5jIChmaXh0dXJlQ2hlY2twb2ludCkgPT4ge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGF3YWl0IHJ1bm5lci5vbkJlZm9yZVRyeVRhc2s/Lih0ZXN0LCB7XG5cdFx0XHRcdFx0XHRyZXRyeTogcmV0cnlDb3VudCxcblx0XHRcdFx0XHRcdHJlcGVhdHM6IHJlcGVhdENvdW50XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0dGVzdC5yZXN1bHQucmVwZWF0Q291bnQgPSByZXBlYXRDb3VudDtcblx0XHRcdFx0XHRiZWZvcmVFYWNoQ2xlYW51cHMgPSBhd2FpdCAkKFwidGVzdC5iZWZvcmVFYWNoXCIsICgpID0+IGNhbGxTdWl0ZUhvb2soc3VpdGUsIHRlc3QsIFwiYmVmb3JlRWFjaFwiLCBydW5uZXIsIFt0ZXN0LmNvbnRleHQsIHN1aXRlXSkpO1xuXHRcdFx0XHRcdGlmIChydW5uZXIucnVuVGFzaykge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInRlc3QuY2FsbGJhY2tcIiwgKCkgPT4gbGltaXRNYXhDb25jdXJyZW5jeSgoKSA9PiBydW5uZXIucnVuVGFzayh0ZXN0KSkpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRjb25zdCBmbiA9IGdldEZuKHRlc3QpO1xuXHRcdFx0XHRcdFx0aWYgKCFmbikge1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJUZXN0IGZ1bmN0aW9uIGlzIG5vdCBmb3VuZC4gRGlkIHlvdSBhZGQgaXQgdXNpbmcgYHNldEZuYD9cIik7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRhd2FpdCAkKFwidGVzdC5jYWxsYmFja1wiLCAoKSA9PiBsaW1pdE1heENvbmN1cnJlbmN5KCgpID0+IGZuKCkpKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YXdhaXQgcnVubmVyLm9uQWZ0ZXJUcnlUYXNrPy4odGVzdCwge1xuXHRcdFx0XHRcdFx0cmV0cnk6IHJldHJ5Q291bnQsXG5cdFx0XHRcdFx0XHRyZXBlYXRzOiByZXBlYXRDb3VudFxuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdGlmICh0ZXN0LnJlc3VsdC5zdGF0ZSAhPT0gXCJmYWlsXCIpIHtcblx0XHRcdFx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJwYXNzXCI7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRcdFx0ZmFpbFRhc2sodGVzdC5yZXN1bHQsIGUsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0YXdhaXQgcnVubmVyLm9uVGFza0ZpbmlzaGVkPy4odGVzdCk7XG5cdFx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRhd2FpdCAkKFwidGVzdC5hZnRlckVhY2hcIiwgKCkgPT4gY2FsbFN1aXRlSG9vayhzdWl0ZSwgdGVzdCwgXCJhZnRlckVhY2hcIiwgcnVubmVyLCBbdGVzdC5jb250ZXh0LCBzdWl0ZV0pKTtcblx0XHRcdFx0XHRpZiAoYmVmb3JlRWFjaENsZWFudXBzLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInRlc3QuY2xlYW51cFwiLCAoKSA9PiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgYmVmb3JlRWFjaENsZWFudXBzKSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdC8vIE9ubHkgY2xlYW4gdXAgZml4dHVyZXMgY3JlYXRlZCBpbnNpZGUgcnVuVGVzdCAoYWZ0ZXIgdGhlIGNoZWNrcG9pbnQpXG5cdFx0XHRcdFx0Ly8gRml4dHVyZXMgY3JlYXRlZCBmb3IgYXJvdW5kRWFjaCB3aWxsIGJlIGNsZWFuZWQgdXAgYWZ0ZXIgYXJvdW5kRWFjaCB0ZWFyZG93blxuXHRcdFx0XHRcdGF3YWl0IGNhbGxGaXh0dXJlQ2xlYW51cEZyb20odGVzdC5jb250ZXh0LCBmaXh0dXJlQ2hlY2twb2ludCk7XG5cdFx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHRlc3Qub25GaW5pc2hlZD8ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0YXdhaXQgJChcInRlc3Qub25GaW5pc2hlZFwiLCAoKSA9PiBjYWxsVGVzdEhvb2tzKHJ1bm5lciwgdGVzdCwgdGVzdC5vbkZpbmlzaGVkLCBcInN0YWNrXCIpKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGVzdC5yZXN1bHQuc3RhdGUgPT09IFwiZmFpbFwiICYmIHRlc3Qub25GYWlsZWQ/Lmxlbmd0aCkge1xuXHRcdFx0XHRcdGF3YWl0ICQoXCJ0ZXN0Lm9uRmFpbGVkXCIsICgpID0+IGNhbGxUZXN0SG9va3MocnVubmVyLCB0ZXN0LCB0ZXN0Lm9uRmFpbGVkLCBydW5uZXIuY29uZmlnLnNlcXVlbmNlLmhvb2tzKSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGVzdC5vbkZhaWxlZCA9IHVuZGVmaW5lZDtcblx0XHRcdFx0dGVzdC5vbkZpbmlzaGVkID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRhd2FpdCBydW5uZXIub25BZnRlclJldHJ5VGFzaz8uKHRlc3QsIHtcblx0XHRcdFx0XHRyZXRyeTogcmV0cnlDb3VudCxcblx0XHRcdFx0XHRyZXBlYXRzOiByZXBlYXRDb3VudFxuXHRcdFx0XHR9KTtcblx0XHRcdH0pLmNhdGNoKChlcnJvcikgPT4ge1xuXHRcdFx0XHRmYWlsVGFzayh0ZXN0LnJlc3VsdCwgZXJyb3IsIHJ1bm5lci5jb25maWcuZGlmZk9wdGlvbnMpO1xuXHRcdFx0fSk7XG5cdFx0XHQvLyBDbGVhbiB1cCBmaXh0dXJlcyB0aGF0IHdlcmUgY3JlYXRlZCBmb3IgYXJvdW5kRWFjaCAoYmVmb3JlIHRoZSBjaGVja3BvaW50KVxuXHRcdFx0Ly8gVGhpcyBydW5zIGFmdGVyIGFyb3VuZEVhY2ggdGVhcmRvd24gaGFzIGNvbXBsZXRlZFxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YXdhaXQgY2FsbEZpeHR1cmVDbGVhbnVwKHRlc3QuY29udGV4dCk7XG5cdFx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRcdGZhaWxUYXNrKHRlc3QucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdH1cblx0XHRcdC8vIHNraXBwZWQgd2l0aCBuZXcgUGVuZGluZ0Vycm9yXG5cdFx0XHRpZiAodGVzdC5yZXN1bHQ/LnBlbmRpbmcgfHwgdGVzdC5yZXN1bHQ/LnN0YXRlID09PSBcInNraXBcIikge1xuXHRcdFx0XHR0ZXN0Lm1vZGUgPSBcInNraXBcIjtcblx0XHRcdFx0dGVzdC5yZXN1bHQgPSB7XG5cdFx0XHRcdFx0c3RhdGU6IFwic2tpcFwiLFxuXHRcdFx0XHRcdG5vdGU6IHRlc3QucmVzdWx0Py5ub3RlLFxuXHRcdFx0XHRcdHBlbmRpbmc6IHRydWUsXG5cdFx0XHRcdFx0ZHVyYXRpb246IG5vdygpIC0gc3RhcnRcblx0XHRcdFx0fTtcblx0XHRcdFx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHRcdFx0c2V0Q3VycmVudFRlc3QodW5kZWZpbmVkKTtcblx0XHRcdFx0Y2xlYW51cFJ1bm5pbmdUZXN0KCk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICh0ZXN0LnJlc3VsdC5zdGF0ZSA9PT0gXCJwYXNzXCIpIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAocmV0cnlDb3VudCA8IHJldHJ5KSB7XG5cdFx0XHRcdGNvbnN0IHNob3VsZFJldHJ5ID0gcGFzc2VzUmV0cnlDb25kaXRpb24odGVzdCwgdGVzdC5yZXN1bHQuZXJyb3JzKTtcblx0XHRcdFx0aWYgKCFzaG91bGRSZXRyeSkge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJydW5cIjtcblx0XHRcdFx0dGVzdC5yZXN1bHQucmV0cnlDb3VudCA9ICh0ZXN0LnJlc3VsdC5yZXRyeUNvdW50ID8/IDApICsgMTtcblx0XHRcdFx0Y29uc3QgZGVsYXkgPSBnZXRSZXRyeURlbGF5KHRlc3QucmV0cnkpO1xuXHRcdFx0XHRpZiAoZGVsYXkgPiAwKSB7XG5cdFx0XHRcdFx0YXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgZGVsYXkpKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0Ly8gdXBkYXRlIHJldHJ5IGluZm9cblx0XHRcdHVwZGF0ZVRhc2soXCJ0ZXN0LXJldHJpZWRcIiwgdGVzdCwgcnVubmVyKTtcblx0XHR9XG5cdH1cblx0Ly8gaWYgdGVzdCBpcyBtYXJrZWQgdG8gYmUgZmFpbGVkLCBmbGlwIHRoZSByZXN1bHRcblx0aWYgKHRlc3QuZmFpbHMpIHtcblx0XHRpZiAodGVzdC5yZXN1bHQuc3RhdGUgPT09IFwicGFzc1wiKSB7XG5cdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoXCJFeHBlY3QgdGVzdCB0byBmYWlsXCIpKTtcblx0XHRcdHRlc3QucmVzdWx0LnN0YXRlID0gXCJmYWlsXCI7XG5cdFx0XHR0ZXN0LnJlc3VsdC5lcnJvcnMgPSBbZXJyb3JdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0ZXN0LnJlc3VsdC5zdGF0ZSA9IFwicGFzc1wiO1xuXHRcdFx0dGVzdC5yZXN1bHQuZXJyb3JzID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0fVxuXHRjbGVhbnVwUnVubmluZ1Rlc3QoKTtcblx0c2V0Q3VycmVudFRlc3QodW5kZWZpbmVkKTtcblx0dGVzdC5yZXN1bHQuZHVyYXRpb24gPSBub3coKSAtIHN0YXJ0O1xuXHRhd2FpdCBydW5uZXIub25BZnRlclJ1blRhc2s/Lih0ZXN0KTtcblx0dXBkYXRlVGFzayhcInRlc3QtZmluaXNoZWRcIiwgdGVzdCwgcnVubmVyKTtcbn1cbmZ1bmN0aW9uIGZhaWxUYXNrKHJlc3VsdCwgZXJyLCBkaWZmT3B0aW9ucykge1xuXHRpZiAoZXJyIGluc3RhbmNlb2YgUGVuZGluZ0Vycm9yKSB7XG5cdFx0cmVzdWx0LnN0YXRlID0gXCJza2lwXCI7XG5cdFx0cmVzdWx0Lm5vdGUgPSBlcnIubm90ZTtcblx0XHRyZXN1bHQucGVuZGluZyA9IHRydWU7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGlmIChlcnIgaW5zdGFuY2VvZiBUZXN0UnVuQWJvcnRFcnJvcikge1xuXHRcdHJlc3VsdC5zdGF0ZSA9IFwic2tpcFwiO1xuXHRcdHJlc3VsdC5ub3RlID0gZXJyLm1lc3NhZ2U7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdHJlc3VsdC5zdGF0ZSA9IFwiZmFpbFwiO1xuXHRjb25zdCBlcnJvcnMgPSBBcnJheS5pc0FycmF5KGVycikgPyBlcnIgOiBbZXJyXTtcblx0Zm9yIChjb25zdCBlIG9mIGVycm9ycykge1xuXHRcdGNvbnN0IGVycm9ycyA9IGUgaW5zdGFuY2VvZiBBZ2dyZWdhdGVFcnJvciA/IGUuZXJyb3JzLm1hcCgoZSkgPT4gcHJvY2Vzc0Vycm9yKGUsIGRpZmZPcHRpb25zKSkgOiBbcHJvY2Vzc0Vycm9yKGUsIGRpZmZPcHRpb25zKV07XG5cdFx0cmVzdWx0LmVycm9ycyA/Pz0gW107XG5cdFx0cmVzdWx0LmVycm9ycy5wdXNoKC4uLmVycm9ycyk7XG5cdH1cbn1cbmZ1bmN0aW9uIG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKSB7XG5cdHN1aXRlLnRhc2tzLmZvckVhY2goKHQpID0+IHtcblx0XHR0Lm1vZGUgPSBcInNraXBcIjtcblx0XHR0LnJlc3VsdCA9IHtcblx0XHRcdC4uLnQucmVzdWx0LFxuXHRcdFx0c3RhdGU6IFwic2tpcFwiXG5cdFx0fTtcblx0XHR1cGRhdGVUYXNrKFwidGVzdC1maW5pc2hlZFwiLCB0LCBydW5uZXIpO1xuXHRcdGlmICh0LnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdFx0bWFya1Rhc2tzQXNTa2lwcGVkKHQsIHJ1bm5lcik7XG5cdFx0fVxuXHR9KTtcbn1cbmZ1bmN0aW9uIG1hcmtQZW5kaW5nVGFza3NBc1NraXBwZWQoc3VpdGUsIHJ1bm5lciwgbm90ZSkge1xuXHRzdWl0ZS50YXNrcy5mb3JFYWNoKCh0KSA9PiB7XG5cdFx0aWYgKCF0LnJlc3VsdCB8fCB0LnJlc3VsdC5zdGF0ZSA9PT0gXCJydW5cIikge1xuXHRcdFx0dC5tb2RlID0gXCJza2lwXCI7XG5cdFx0XHR0LnJlc3VsdCA9IHtcblx0XHRcdFx0Li4udC5yZXN1bHQsXG5cdFx0XHRcdHN0YXRlOiBcInNraXBcIixcblx0XHRcdFx0bm90ZVxuXHRcdFx0fTtcblx0XHRcdHVwZGF0ZVRhc2soXCJ0ZXN0LWNhbmNlbFwiLCB0LCBydW5uZXIpO1xuXHRcdH1cblx0XHRpZiAodC50eXBlID09PSBcInN1aXRlXCIpIHtcblx0XHRcdG1hcmtQZW5kaW5nVGFza3NBc1NraXBwZWQodCwgcnVubmVyLCBub3RlKTtcblx0XHR9XG5cdH0pO1xufVxuYXN5bmMgZnVuY3Rpb24gcnVuU3VpdGUoc3VpdGUsIHJ1bm5lcikge1xuXHRhd2FpdCBydW5uZXIub25CZWZvcmVSdW5TdWl0ZT8uKHN1aXRlKTtcblx0aWYgKHN1aXRlLnJlc3VsdD8uc3RhdGUgPT09IFwiZmFpbFwiKSB7XG5cdFx0bWFya1Rhc2tzQXNTa2lwcGVkKHN1aXRlLCBydW5uZXIpO1xuXHRcdC8vIGZhaWxlZCBkdXJpbmcgY29sbGVjdGlvblxuXHRcdHVwZGF0ZVRhc2soXCJzdWl0ZS1mYWlsZWQtZWFybHlcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGNvbnN0IHN0YXJ0ID0gbm93KCk7XG5cdGNvbnN0IG1vZGUgPSBzdWl0ZS5tb2RlO1xuXHRzdWl0ZS5yZXN1bHQgPSB7XG5cdFx0c3RhdGU6IG1vZGUgPT09IFwic2tpcFwiIHx8IG1vZGUgPT09IFwidG9kb1wiID8gbW9kZSA6IFwicnVuXCIsXG5cdFx0c3RhcnRUaW1lOiB1bml4Tm93KClcblx0fTtcblx0Y29uc3QgJCA9IHJ1bm5lci50cmFjZTtcblx0dXBkYXRlVGFzayhcInN1aXRlLXByZXBhcmVcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdGxldCBiZWZvcmVBbGxDbGVhbnVwcyA9IFtdO1xuXHRpZiAoc3VpdGUubW9kZSA9PT0gXCJza2lwXCIpIHtcblx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcInNraXBcIjtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH0gZWxzZSBpZiAoc3VpdGUubW9kZSA9PT0gXCJ0b2RvXCIpIHtcblx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcInRvZG9cIjtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH0gZWxzZSB7XG5cdFx0bGV0IHN1aXRlUmFuID0gZmFsc2U7XG5cdFx0dHJ5IHtcblx0XHRcdGF3YWl0IGNhbGxBcm91bmRBbGxIb29rcyhzdWl0ZSwgYXN5bmMgKCkgPT4ge1xuXHRcdFx0XHRzdWl0ZVJhbiA9IHRydWU7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0Ly8gYmVmb3JlQWxsXG5cdFx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRcdGJlZm9yZUFsbENsZWFudXBzID0gYXdhaXQgJChcInN1aXRlLmJlZm9yZUFsbFwiLCAoKSA9PiBjYWxsU3VpdGVIb29rKHN1aXRlLCBzdWl0ZSwgXCJiZWZvcmVBbGxcIiwgcnVubmVyLCBbc3VpdGVdKSk7XG5cdFx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdFx0ZmFpbFRhc2soc3VpdGUucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdFx0XHRcdG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Ly8gcnVuIHN1aXRlIGNoaWxkcmVuXG5cdFx0XHRcdFx0aWYgKHJ1bm5lci5ydW5TdWl0ZSkge1xuXHRcdFx0XHRcdFx0YXdhaXQgcnVubmVyLnJ1blN1aXRlKHN1aXRlKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Zm9yIChsZXQgdGFza3NHcm91cCBvZiBwYXJ0aXRpb25TdWl0ZUNoaWxkcmVuKHN1aXRlKSkge1xuXHRcdFx0XHRcdFx0XHRpZiAodGFza3NHcm91cFswXS5jb25jdXJyZW50ID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXBMaW1pdGVyID0gbGltaXRDb25jdXJyZW5jeShydW5uZXIuY29uZmlnLm1heENvbmN1cnJlbmN5KTtcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCBQcm9taXNlLmFsbCh0YXNrc0dyb3VwLm1hcCgoYykgPT4gZ3JvdXBMaW1pdGVyKCgpID0+IHJ1blN1aXRlQ2hpbGQoYywgcnVubmVyKSkpKTtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRjb25zdCB7IHNlcXVlbmNlIH0gPSBydW5uZXIuY29uZmlnO1xuXHRcdFx0XHRcdFx0XHRcdGlmIChzdWl0ZS5zaHVmZmxlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBydW4gZGVzY3JpYmUgYmxvY2sgaW5kZXBlbmRlbnRseSBmcm9tIHRlc3RzXG5cdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBzdWl0ZXMgPSB0YXNrc0dyb3VwLmZpbHRlcigoZ3JvdXApID0+IGdyb3VwLnR5cGUgPT09IFwic3VpdGVcIik7XG5cdFx0XHRcdFx0XHRcdFx0XHRjb25zdCB0ZXN0cyA9IHRhc2tzR3JvdXAuZmlsdGVyKChncm91cCkgPT4gZ3JvdXAudHlwZSA9PT0gXCJ0ZXN0XCIpO1xuXHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXBzID0gc2h1ZmZsZShbc3VpdGVzLCB0ZXN0c10sIHNlcXVlbmNlLnNlZWQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0dGFza3NHcm91cCA9IGdyb3Vwcy5mbGF0TWFwKChncm91cCkgPT4gc2h1ZmZsZShncm91cCwgc2VxdWVuY2Uuc2VlZCkpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRmb3IgKGNvbnN0IGMgb2YgdGFza3NHcm91cCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0YXdhaXQgcnVuU3VpdGVDaGlsZChjLCBydW5uZXIpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0XHQvLyBhZnRlckFsbCBydW5zIGV2ZW4gaWYgYmVmb3JlQWxsIG9yIHN1aXRlIGNoaWxkcmVuIGZhaWxcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0YXdhaXQgJChcInN1aXRlLmFmdGVyQWxsXCIsICgpID0+IGNhbGxTdWl0ZUhvb2soc3VpdGUsIHN1aXRlLCBcImFmdGVyQWxsXCIsIHJ1bm5lciwgW3N1aXRlXSkpO1xuXHRcdFx0XHRcdFx0aWYgKGJlZm9yZUFsbENsZWFudXBzLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRhd2FpdCAkKFwic3VpdGUuY2xlYW51cFwiLCAoKSA9PiBjYWxsQ2xlYW51cEhvb2tzKHJ1bm5lciwgYmVmb3JlQWxsQ2xlYW51cHMpKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmIChzdWl0ZS5maWxlID09PSBzdWl0ZSkge1xuXHRcdFx0XHRcdFx0XHRjb25zdCBjb250ZXh0cyA9IFRlc3RGaXh0dXJlcy5nZXRGaWxlQ29udGV4dHMoc3VpdGUuZmlsZSk7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IFByb21pc2UuYWxsKGNvbnRleHRzLm1hcCgoY29udGV4dCkgPT4gY2FsbEZpeHR1cmVDbGVhbnVwKGNvbnRleHQpKSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdFx0ZmFpbFRhc2soc3VpdGUucmVzdWx0LCBlLCBydW5uZXIuY29uZmlnLmRpZmZPcHRpb25zKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdC8vIG1hcmsgdGFza3MgYXMgc2tpcHBlZCBpZiBhcm91bmRBbGwgZmFpbGVkIGJlZm9yZSB0aGUgc3VpdGUgY2FsbGJhY2sgd2FzIGV4ZWN1dGVkXG5cdFx0XHRpZiAoIXN1aXRlUmFuKSB7XG5cdFx0XHRcdG1hcmtUYXNrc0FzU2tpcHBlZChzdWl0ZSwgcnVubmVyKTtcblx0XHRcdH1cblx0XHRcdGZhaWxUYXNrKHN1aXRlLnJlc3VsdCwgZSwgcnVubmVyLmNvbmZpZy5kaWZmT3B0aW9ucyk7XG5cdFx0fVxuXHRcdGlmIChzdWl0ZS5tb2RlID09PSBcInJ1blwiIHx8IHN1aXRlLm1vZGUgPT09IFwicXVldWVkXCIpIHtcblx0XHRcdGlmICghcnVubmVyLmNvbmZpZy5wYXNzV2l0aE5vVGVzdHMgJiYgIWhhc1Rlc3RzKHN1aXRlKSkge1xuXHRcdFx0XHRzdWl0ZS5yZXN1bHQuc3RhdGUgPSBcImZhaWxcIjtcblx0XHRcdFx0aWYgKCFzdWl0ZS5yZXN1bHQuZXJyb3JzPy5sZW5ndGgpIHtcblx0XHRcdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoYE5vIHRlc3QgZm91bmQgaW4gc3VpdGUgJHtzdWl0ZS5uYW1lfWApKTtcblx0XHRcdFx0XHRzdWl0ZS5yZXN1bHQuZXJyb3JzID0gW2Vycm9yXTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmIChoYXNGYWlsZWQoc3VpdGUpKSB7XG5cdFx0XHRcdHN1aXRlLnJlc3VsdC5zdGF0ZSA9IFwiZmFpbFwiO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c3VpdGUucmVzdWx0LnN0YXRlID0gXCJwYXNzXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHN1aXRlLnJlc3VsdC5kdXJhdGlvbiA9IG5vdygpIC0gc3RhcnQ7XG5cdFx0YXdhaXQgcnVubmVyLm9uQWZ0ZXJSdW5TdWl0ZT8uKHN1aXRlKTtcblx0XHR1cGRhdGVUYXNrKFwic3VpdGUtZmluaXNoZWRcIiwgc3VpdGUsIHJ1bm5lcik7XG5cdH1cbn1cbmFzeW5jIGZ1bmN0aW9uIHJ1blN1aXRlQ2hpbGQoYywgcnVubmVyKSB7XG5cdGNvbnN0ICQgPSBydW5uZXIudHJhY2U7XG5cdGlmIChjLnR5cGUgPT09IFwidGVzdFwiKSB7XG5cdFx0cmV0dXJuICQoXCJydW4udGVzdFwiLCB7XG5cdFx0XHRcInZpdGVzdC50ZXN0LmlkXCI6IGMuaWQsXG5cdFx0XHRcInZpdGVzdC50ZXN0Lm5hbWVcIjogYy5uYW1lLFxuXHRcdFx0XCJ2aXRlc3QudGVzdC5tb2RlXCI6IGMubW9kZSxcblx0XHRcdFwidml0ZXN0LnRlc3QudGltZW91dFwiOiBjLnRpbWVvdXQsXG5cdFx0XHRcImNvZGUuZmlsZS5wYXRoXCI6IGMuZmlsZS5maWxlcGF0aCxcblx0XHRcdFwiY29kZS5saW5lLm51bWJlclwiOiBjLmxvY2F0aW9uPy5saW5lLFxuXHRcdFx0XCJjb2RlLmNvbHVtbi5udW1iZXJcIjogYy5sb2NhdGlvbj8uY29sdW1uXG5cdFx0fSwgKCkgPT4gcnVuVGVzdChjLCBydW5uZXIpKTtcblx0fSBlbHNlIGlmIChjLnR5cGUgPT09IFwic3VpdGVcIikge1xuXHRcdHJldHVybiAkKFwicnVuLnN1aXRlXCIsIHtcblx0XHRcdFwidml0ZXN0LnN1aXRlLmlkXCI6IGMuaWQsXG5cdFx0XHRcInZpdGVzdC5zdWl0ZS5uYW1lXCI6IGMubmFtZSxcblx0XHRcdFwidml0ZXN0LnN1aXRlLm1vZGVcIjogYy5tb2RlLFxuXHRcdFx0XCJjb2RlLmZpbGUucGF0aFwiOiBjLmZpbGUuZmlsZXBhdGgsXG5cdFx0XHRcImNvZGUubGluZS5udW1iZXJcIjogYy5sb2NhdGlvbj8ubGluZSxcblx0XHRcdFwiY29kZS5jb2x1bW4ubnVtYmVyXCI6IGMubG9jYXRpb24/LmNvbHVtblxuXHRcdH0sICgpID0+IHJ1blN1aXRlKGMsIHJ1bm5lcikpO1xuXHR9XG59XG5hc3luYyBmdW5jdGlvbiBydW5GaWxlcyhmaWxlcywgcnVubmVyKSB7XG5cdGxpbWl0TWF4Q29uY3VycmVuY3kgPz89IGxpbWl0Q29uY3VycmVuY3kocnVubmVyLmNvbmZpZy5tYXhDb25jdXJyZW5jeSk7XG5cdGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuXHRcdGlmICghZmlsZS50YXNrcy5sZW5ndGggJiYgIXJ1bm5lci5jb25maWcucGFzc1dpdGhOb1Rlc3RzKSB7XG5cdFx0XHRpZiAoIWZpbGUucmVzdWx0Py5lcnJvcnM/Lmxlbmd0aCkge1xuXHRcdFx0XHRjb25zdCBlcnJvciA9IHByb2Nlc3NFcnJvcihuZXcgRXJyb3IoYE5vIHRlc3Qgc3VpdGUgZm91bmQgaW4gZmlsZSAke2ZpbGUuZmlsZXBhdGh9YCkpO1xuXHRcdFx0XHRmaWxlLnJlc3VsdCA9IHtcblx0XHRcdFx0XHRzdGF0ZTogXCJmYWlsXCIsXG5cdFx0XHRcdFx0ZXJyb3JzOiBbZXJyb3JdXG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGF3YWl0IHJ1bm5lci50cmFjZShcInJ1bi5zcGVjXCIsIHtcblx0XHRcdFwiY29kZS5maWxlLnBhdGhcIjogZmlsZS5maWxlcGF0aCxcblx0XHRcdFwidml0ZXN0LnN1aXRlLnRhc2tzLmxlbmd0aFwiOiBmaWxlLnRhc2tzLmxlbmd0aFxuXHRcdH0sICgpID0+IHJ1blN1aXRlKGZpbGUsIHJ1bm5lcikpO1xuXHR9XG59XG5jb25zdCB3b3JrZXJSdW5uZXJzID0gbmV3IFdlYWtTZXQoKTtcbmZ1bmN0aW9uIGRlZmF1bHRUcmFjZShfLCBhdHRyaWJ1dGVzLCBjYikge1xuXHRpZiAodHlwZW9mIGF0dHJpYnV0ZXMgPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdHJldHVybiBhdHRyaWJ1dGVzKCk7XG5cdH1cblx0cmV0dXJuIGNiKCk7XG59XG5hc3luYyBmdW5jdGlvbiBzdGFydFRlc3RzKHNwZWNzLCBydW5uZXIpIHtcblx0cnVubmVyLnRyYWNlID8/PSBkZWZhdWx0VHJhY2U7XG5cdGNvbnN0IGNhbmNlbCA9IHJ1bm5lci5jYW5jZWw/LmJpbmQocnVubmVyKTtcblx0Ly8gSWRlYWxseSwgd2UgbmVlZCB0byBoYXZlIGFuIGV2ZW50IGxpc3RlbmVyIGZvciB0aGlzLCBidXQgb25seSBoYXZlIGEgcnVubmVyIGhlcmUuXG5cdC8vIEFkZGluZyBhbm90aGVyIG9uQ2FuY2VsIGZlbHQgd3JvbmcgKG1heWJlIGl0IG5lZWRzIHRvIGJlIHJlZmFjdG9yZWQpXG5cdHJ1bm5lci5jYW5jZWwgPSAocmVhc29uKSA9PiB7XG5cdFx0Ly8gV2UgaW50ZW50aW9uYWxseSBjcmVhdGUgb25seSBvbmUgZXJyb3Igc2luY2UgdGhlcmUgaXMgb25seSBvbmUgdGVzdCBydW4gdGhhdCBjYW4gYmUgY2FuY2VsbGVkXG5cdFx0Y29uc3QgZXJyb3IgPSBuZXcgVGVzdFJ1bkFib3J0RXJyb3IoXCJUaGUgdGVzdCBydW4gd2FzIGFib3J0ZWQgYnkgdGhlIHVzZXIuXCIsIHJlYXNvbik7XG5cdFx0Z2V0UnVubmluZ1Rlc3RzKCkuZm9yRWFjaCgodGVzdCkgPT4ge1xuXHRcdFx0YWJvcnRDb250ZXh0U2lnbmFsKHRlc3QuY29udGV4dCwgZXJyb3IpO1xuXHRcdFx0bWFya1BlbmRpbmdUYXNrc0FzU2tpcHBlZCh0ZXN0LmZpbGUsIHJ1bm5lciwgZXJyb3IubWVzc2FnZSk7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIGNhbmNlbD8uKHJlYXNvbik7XG5cdH07XG5cdGlmICghd29ya2VyUnVubmVycy5oYXMocnVubmVyKSkge1xuXHRcdHJ1bm5lci5vbkNsZWFudXBXb3JrZXJDb250ZXh0Py4oYXN5bmMgKCkgPT4ge1xuXHRcdFx0YXdhaXQgUHJvbWlzZS5hbGwoWy4uLlRlc3RGaXh0dXJlcy5nZXRXb3JrZXJDb250ZXh0cygpXS5tYXAoKGNvbnRleHQpID0+IGNhbGxGaXh0dXJlQ2xlYW51cChjb250ZXh0KSkpLmZpbmFsbHkoKCkgPT4ge1xuXHRcdFx0XHRUZXN0Rml4dHVyZXMuY2xlYXJEZWZpbml0aW9ucygpO1xuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdFx0d29ya2VyUnVubmVycy5hZGQocnVubmVyKTtcblx0fVxuXHR0cnkge1xuXHRcdGNvbnN0IHBhdGhzID0gc3BlY3MubWFwKChmKSA9PiB0eXBlb2YgZiA9PT0gXCJzdHJpbmdcIiA/IGYgOiBmLmZpbGVwYXRoKTtcblx0XHRhd2FpdCBydW5uZXIub25CZWZvcmVDb2xsZWN0Py4ocGF0aHMpO1xuXHRcdGNvbnN0IGZpbGVzID0gYXdhaXQgY29sbGVjdFRlc3RzKHNwZWNzLCBydW5uZXIpO1xuXHRcdGF3YWl0IHJ1bm5lci5vbkNvbGxlY3RlZD8uKGZpbGVzKTtcblx0XHRhd2FpdCBydW5uZXIub25CZWZvcmVSdW5GaWxlcz8uKGZpbGVzKTtcblx0XHRhd2FpdCBydW5GaWxlcyhmaWxlcywgcnVubmVyKTtcblx0XHRhd2FpdCBydW5uZXIub25BZnRlclJ1bkZpbGVzPy4oZmlsZXMpO1xuXHRcdGF3YWl0IGZpbmlzaFNlbmRUYXNrc1VwZGF0ZShydW5uZXIpO1xuXHRcdHJldHVybiBmaWxlcztcblx0fSBmaW5hbGx5IHtcblx0XHRydW5uZXIuY2FuY2VsID0gY2FuY2VsO1xuXHR9XG59XG5hc3luYyBmdW5jdGlvbiBwdWJsaWNDb2xsZWN0KHNwZWNzLCBydW5uZXIpIHtcblx0cnVubmVyLnRyYWNlID8/PSBkZWZhdWx0VHJhY2U7XG5cdGNvbnN0IHBhdGhzID0gc3BlY3MubWFwKChmKSA9PiB0eXBlb2YgZiA9PT0gXCJzdHJpbmdcIiA/IGYgOiBmLmZpbGVwYXRoKTtcblx0YXdhaXQgcnVubmVyLm9uQmVmb3JlQ29sbGVjdD8uKHBhdGhzKTtcblx0Y29uc3QgZmlsZXMgPSBhd2FpdCBjb2xsZWN0VGVzdHMoc3BlY3MsIHJ1bm5lcik7XG5cdGF3YWl0IHJ1bm5lci5vbkNvbGxlY3RlZD8uKGZpbGVzKTtcblx0cmV0dXJuIGZpbGVzO1xufVxuXG4vKipcbiogQGV4cGVyaW1lbnRhbFxuKiBAYWR2YW5jZWRcbipcbiogUmVjb3JkcyBhIGN1c3RvbSB0ZXN0IGFydGlmYWN0IGR1cmluZyB0ZXN0IGV4ZWN1dGlvbi5cbipcbiogVGhpcyBmdW5jdGlvbiBhbGxvd3MgeW91IHRvIGF0dGFjaCBzdHJ1Y3R1cmVkIGRhdGEsIGZpbGVzLCBvciBtZXRhZGF0YSB0byBhIHRlc3QuXG4qXG4qIFZpdGVzdCBhdXRvbWF0aWNhbGx5IGluamVjdHMgdGhlIHNvdXJjZSBsb2NhdGlvbiB3aGVyZSB0aGUgYXJ0aWZhY3Qgd2FzIGNyZWF0ZWQgYW5kIG1hbmFnZXMgYW55IGF0dGFjaG1lbnRzIHlvdSBpbmNsdWRlLlxuKlxuKiAqKk5vdGU6KiogYXJ0aWZhY3RzIG11c3QgYmUgcmVjb3JkZWQgYmVmb3JlIHRoZSB0YXNrIGlzIHJlcG9ydGVkLiBBbnkgYXJ0aWZhY3RzIHJlY29yZGVkIGFmdGVyIHRoYXQgd2lsbCBub3QgYmUgaW5jbHVkZWQgaW4gdGhlIHRhc2suXG4qXG4qIEBwYXJhbSB0YXNrIC0gVGhlIHRlc3QgdGFzayBjb250ZXh0LCB0eXBpY2FsbHkgYWNjZXNzZWQgdmlhIGB0aGlzLnRhc2tgIGluIGN1c3RvbSBtYXRjaGVycyBvciBgY29udGV4dC50YXNrYCBpbiB0ZXN0c1xuKiBAcGFyYW0gYXJ0aWZhY3QgLSBUaGUgYXJ0aWZhY3QgdG8gcmVjb3JkLiBNdXN0IGV4dGVuZCB7QGxpbmtjb2RlIFRlc3RBcnRpZmFjdEJhc2V9XG4qXG4qIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZWNvcmRlZCBhcnRpZmFjdCB3aXRoIGxvY2F0aW9uIGluamVjdGVkXG4qXG4qIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdGVzdCBydW5uZXIgZG9lc24ndCBzdXBwb3J0IGFydGlmYWN0c1xuKlxuKiBAZXhhbXBsZVxuKiBgYGB0c1xuKiAvLyBJbiBhIGN1c3RvbSBhc3NlcnRpb25cbiogYXN5bmMgZnVuY3Rpb24gdG9IYXZlVmFsaWRTY2hlbWEodGhpczogTWF0Y2hlclN0YXRlLCBhY3R1YWw6IHVua25vd24pIHtcbiogICBjb25zdCB2YWxpZGF0aW9uID0gdmFsaWRhdGVTY2hlbWEoYWN0dWFsKVxuKlxuKiAgIGF3YWl0IHJlY29yZEFydGlmYWN0KHRoaXMudGFzaywge1xuKiAgICAgdHlwZTogJ215LXBsdWdpbjpzY2hlbWEtdmFsaWRhdGlvbicsXG4qICAgICBwYXNzZWQ6IHZhbGlkYXRpb24udmFsaWQsXG4qICAgICBlcnJvcnM6IHZhbGlkYXRpb24uZXJyb3JzLFxuKiAgIH0pXG4qXG4qICAgcmV0dXJuIHsgcGFzczogdmFsaWRhdGlvbi52YWxpZCwgbWVzc2FnZTogKCkgPT4gJy4uLicgfVxuKiB9XG4qIGBgYFxuKi9cbmFzeW5jIGZ1bmN0aW9uIHJlY29yZEFydGlmYWN0KHRhc2ssIGFydGlmYWN0KSB7XG5cdGNvbnN0IHJ1bm5lciA9IGdldFJ1bm5lcigpO1xuXHRjb25zdCBzdGFjayA9IGZpbmRUZXN0RmlsZVN0YWNrVHJhY2UodGFzay5maWxlLmZpbGVwYXRoLCBuZXcgRXJyb3IoXCJTVEFDS19UUkFDRVwiKS5zdGFjayk7XG5cdGlmIChzdGFjaykge1xuXHRcdGFydGlmYWN0LmxvY2F0aW9uID0ge1xuXHRcdFx0ZmlsZTogc3RhY2suZmlsZSxcblx0XHRcdGxpbmU6IHN0YWNrLmxpbmUsXG5cdFx0XHRjb2x1bW46IHN0YWNrLmNvbHVtblxuXHRcdH07XG5cdFx0aWYgKGFydGlmYWN0LnR5cGUgPT09IFwiaW50ZXJuYWw6YW5ub3RhdGlvblwiKSB7XG5cdFx0XHRhcnRpZmFjdC5hbm5vdGF0aW9uLmxvY2F0aW9uID0gYXJ0aWZhY3QubG9jYXRpb247XG5cdFx0fVxuXHR9XG5cdGlmIChBcnJheS5pc0FycmF5KGFydGlmYWN0LmF0dGFjaG1lbnRzKSkge1xuXHRcdGZvciAoY29uc3QgYXR0YWNobWVudCBvZiBhcnRpZmFjdC5hdHRhY2htZW50cykge1xuXHRcdFx0bWFuYWdlQXJ0aWZhY3RBdHRhY2htZW50KGF0dGFjaG1lbnQpO1xuXHRcdH1cblx0fVxuXHQvLyBhbm5vdGF0aW9ucyB3b24ndCByZXNvbHZlIGFzIGFydGlmYWN0cyBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgdW50aWwgbmV4dCBtYWpvclxuXHRpZiAoYXJ0aWZhY3QudHlwZSA9PT0gXCJpbnRlcm5hbDphbm5vdGF0aW9uXCIpIHtcblx0XHRyZXR1cm4gYXJ0aWZhY3Q7XG5cdH1cblx0aWYgKCFydW5uZXIub25UZXN0QXJ0aWZhY3RSZWNvcmQpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYFRlc3QgcnVubmVyIGRvZXNuJ3Qgc3VwcG9ydCB0ZXN0IGFydGlmYWN0cy5gKTtcblx0fVxuXHRhd2FpdCBmaW5pc2hTZW5kVGFza3NVcGRhdGUocnVubmVyKTtcblx0Y29uc3QgcmVzb2x2ZWRBcnRpZmFjdCA9IGF3YWl0IHJ1bm5lci5vblRlc3RBcnRpZmFjdFJlY29yZCh0YXNrLCBhcnRpZmFjdCk7XG5cdHRhc2suYXJ0aWZhY3RzLnB1c2gocmVzb2x2ZWRBcnRpZmFjdCk7XG5cdHJldHVybiByZXNvbHZlZEFydGlmYWN0O1xufVxuY29uc3QgdGFibGUgPSBbXTtcbmZvciAobGV0IGkgPSA2NTsgaSA8IDkxOyBpKyspIHtcblx0dGFibGUucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGkpKTtcbn1cbmZvciAobGV0IGkgPSA5NzsgaSA8IDEyMzsgaSsrKSB7XG5cdHRhYmxlLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShpKSk7XG59XG5mb3IgKGxldCBpID0gMDsgaSA8IDEwOyBpKyspIHtcblx0dGFibGUucHVzaChpLnRvU3RyaW5nKDEwKSk7XG59XG50YWJsZS5wdXNoKFwiK1wiLCBcIi9cIik7XG5mdW5jdGlvbiBlbmNvZGVVaW50OEFycmF5KGJ5dGVzKSB7XG5cdGxldCBiYXNlNjQgPSBcIlwiO1xuXHRjb25zdCBsZW4gPSBieXRlcy5ieXRlTGVuZ3RoO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSArPSAzKSB7XG5cdFx0aWYgKGxlbiA9PT0gaSArIDEpIHtcblx0XHRcdGNvbnN0IGEgPSAoYnl0ZXNbaV0gJiAyNTIpID4+IDI7XG5cdFx0XHRjb25zdCBiID0gKGJ5dGVzW2ldICYgMykgPDwgNDtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVthXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtiXTtcblx0XHRcdGJhc2U2NCArPSBcIj09XCI7XG5cdFx0fSBlbHNlIGlmIChsZW4gPT09IGkgKyAyKSB7XG5cdFx0XHRjb25zdCBhID0gKGJ5dGVzW2ldICYgMjUyKSA+PiAyO1xuXHRcdFx0Y29uc3QgYiA9IChieXRlc1tpXSAmIDMpIDw8IDQgfCAoYnl0ZXNbaSArIDFdICYgMjQwKSA+PiA0O1xuXHRcdFx0Y29uc3QgYyA9IChieXRlc1tpICsgMV0gJiAxNSkgPDwgMjtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVthXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtiXTtcblx0XHRcdGJhc2U2NCArPSB0YWJsZVtjXTtcblx0XHRcdGJhc2U2NCArPSBcIj1cIjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y29uc3QgYSA9IChieXRlc1tpXSAmIDI1MikgPj4gMjtcblx0XHRcdGNvbnN0IGIgPSAoYnl0ZXNbaV0gJiAzKSA8PCA0IHwgKGJ5dGVzW2kgKyAxXSAmIDI0MCkgPj4gNDtcblx0XHRcdGNvbnN0IGMgPSAoYnl0ZXNbaSArIDFdICYgMTUpIDw8IDIgfCAoYnl0ZXNbaSArIDJdICYgMTkyKSA+PiA2O1xuXHRcdFx0Y29uc3QgZCA9IGJ5dGVzW2kgKyAyXSAmIDYzO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2FdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2JdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2NdO1xuXHRcdFx0YmFzZTY0ICs9IHRhYmxlW2RdO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gYmFzZTY0O1xufVxuLyoqXG4qIFJlY29yZHMgYW4gYXN5bmMgb3BlcmF0aW9uIGFzc29jaWF0ZWQgd2l0aCBhIHRlc3QgdGFzay5cbipcbiogVGhpcyBmdW5jdGlvbiB0cmFja3MgcHJvbWlzZXMgdGhhdCBzaG91bGQgYmUgYXdhaXRlZCBiZWZvcmUgYSB0ZXN0IGNvbXBsZXRlcy5cbiogVGhlIHByb21pc2UgaXMgYXV0b21hdGljYWxseSByZW1vdmVkIGZyb20gdGhlIHRlc3QncyBwcm9taXNlIGxpc3Qgb25jZSBpdCBzZXR0bGVzLlxuKi9cbmZ1bmN0aW9uIHJlY29yZEFzeW5jT3BlcmF0aW9uKHRlc3QsIHByb21pc2UpIHtcblx0Ly8gaWYgcHJvbWlzZSBpcyBleHBsaWNpdGx5IGF3YWl0ZWQsIHJlbW92ZSBpdCBmcm9tIHRoZSBsaXN0XG5cdHByb21pc2UgPSBwcm9taXNlLmZpbmFsbHkoKCkgPT4ge1xuXHRcdGlmICghdGVzdC5wcm9taXNlcykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRjb25zdCBpbmRleCA9IHRlc3QucHJvbWlzZXMuaW5kZXhPZihwcm9taXNlKTtcblx0XHRpZiAoaW5kZXggIT09IC0xKSB7XG5cdFx0XHR0ZXN0LnByb21pc2VzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0fVxuXHR9KTtcblx0Ly8gcmVjb3JkIHByb21pc2Vcblx0aWYgKCF0ZXN0LnByb21pc2VzKSB7XG5cdFx0dGVzdC5wcm9taXNlcyA9IFtdO1xuXHR9XG5cdHRlc3QucHJvbWlzZXMucHVzaChwcm9taXNlKTtcblx0cmV0dXJuIHByb21pc2U7XG59XG4vKipcbiogVmFsaWRhdGVzIGFuZCBwcmVwYXJlcyBhIHRlc3QgYXR0YWNobWVudCBmb3Igc2VyaWFsaXphdGlvbi5cbipcbiogVGhpcyBmdW5jdGlvbiBlbnN1cmVzIGF0dGFjaG1lbnRzIGhhdmUgZWl0aGVyIGBib2R5YCBvciBgcGF0aGAgc2V0IChidXQgbm90IGJvdGgpLCBhbmQgY29udmVydHMgYFVpbnQ4QXJyYXlgIGJvZGllcyB0byBiYXNlNjQtZW5jb2RlZCBzdHJpbmdzIGZvciBlYXNpZXIgc2VyaWFsaXphdGlvbi5cbipcbiogQHBhcmFtIGF0dGFjaG1lbnQgLSBUaGUgYXR0YWNobWVudCB0byB2YWxpZGF0ZSBhbmQgcHJlcGFyZVxuKlxuKiBAdGhyb3dzIHtUeXBlRXJyb3J9IElmIG5laXRoZXIgYGJvZHlgIG5vciBgcGF0aGAgaXMgcHJvdmlkZWRcbiogQHRocm93cyB7VHlwZUVycm9yfSBJZiBib3RoIGBib2R5YCBhbmQgYHBhdGhgIGFyZSBwcm92aWRlZFxuKi9cbmZ1bmN0aW9uIG1hbmFnZUFydGlmYWN0QXR0YWNobWVudChhdHRhY2htZW50KSB7XG5cdGlmIChhdHRhY2htZW50LmJvZHkgPT0gbnVsbCAmJiAhYXR0YWNobWVudC5wYXRoKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgVGVzdCBhdHRhY2htZW50IHJlcXVpcmVzIFwiYm9keVwiIG9yIFwicGF0aFwiIHRvIGJlIHNldC4gQm90aCBhcmUgbWlzc2luZy5gKTtcblx0fVxuXHRpZiAoYXR0YWNobWVudC5ib2R5ICYmIGF0dGFjaG1lbnQucGF0aCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoYFRlc3QgYXR0YWNobWVudCByZXF1aXJlcyBvbmx5IG9uZSBvZiBcImJvZHlcIiBvciBcInBhdGhcIiB0byBiZSBzZXQuIEJvdGggYXJlIHNwZWNpZmllZC5gKTtcblx0fVxuXHRpZiAoYXR0YWNobWVudC5wYXRoICYmIGF0dGFjaG1lbnQuYm9keUVuY29kaW5nKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcihgVGVzdCBhdHRhY2htZW50IHdpdGggXCJwYXRoXCIgc2hvdWxkIG5vdCBoYXZlIFwiYm9keUVuY29kaW5nXCIgc3BlY2lmaWVkLmApO1xuXHR9XG5cdC8vIGNvbnZlcnQgdG8gYSBzdHJpbmcgc28gaXQncyBlYXNpZXIgdG8gc2VyaWFsaXNlXG5cdGlmIChhdHRhY2htZW50LmJvZHkgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG5cdFx0YXR0YWNobWVudC5ib2R5ID0gZW5jb2RlVWludDhBcnJheShhdHRhY2htZW50LmJvZHkpO1xuXHR9XG5cdGlmIChhdHRhY2htZW50LmJvZHkgIT0gbnVsbCkge1xuXHRcdGF0dGFjaG1lbnQuYm9keUVuY29kaW5nID8/PSBcImJhc2U2NFwiO1xuXHR9XG59XG5cbmV4cG9ydCB7IGNyZWF0ZVRhZ3NGaWx0ZXIgYXMgQSwgY3JlYXRlVGFza05hbWUgYXMgQiwgZmluZFRlc3RGaWxlU3RhY2tUcmFjZSBhcyBDLCBnZW5lcmF0ZUZpbGVIYXNoIGFzIEQsIGdlbmVyYXRlSGFzaCBhcyBFLCBnZXRGdWxsTmFtZSBhcyBGLCBnZXROYW1lcyBhcyBHLCBnZXRTdWl0ZXMgYXMgSCwgZ2V0VGFza3MgYXMgSSwgZ2V0VGVzdE5hbWUgYXMgSiwgZ2V0VGVzdHMgYXMgSywgaGFzRmFpbGVkIGFzIEwsIGhhc1Rlc3RzIGFzIE0sIGludGVycHJldFRhc2tNb2RlcyBhcyBOLCBpc1Rlc3RDYXNlIGFzIE8sIGxpbWl0Q29uY3VycmVuY3kgYXMgUCwgbWF0Y2hlc1RhZ3MgYXMgUSwgcGFydGl0aW9uU3VpdGVDaGlsZHJlbiBhcyBSLCBzb21lVGFza3NBcmVPbmx5IGFzIFMsIHZhbGlkYXRlVGFncyBhcyBULCBhZnRlckFsbCBhcyBhLCBhZnRlckVhY2ggYXMgYiwgYXJvdW5kQWxsIGFzIGMsIGFyb3VuZEVhY2ggYXMgZCwgYmVmb3JlQWxsIGFzIGUsIGJlZm9yZUVhY2ggYXMgZiwgY3JlYXRlVGFza0NvbGxlY3RvciBhcyBnLCBkZXNjcmliZSBhcyBoLCBnZXRDdXJyZW50U3VpdGUgYXMgaSwgZ2V0Q3VycmVudFRlc3QgYXMgaiwgZ2V0Rm4gYXMgaywgZ2V0SG9va3MgYXMgbCwgaXQgYXMgbSwgb25UZXN0RmluaXNoZWQgYXMgbiwgb25UZXN0RmFpbGVkIGFzIG8sIHB1YmxpY0NvbGxlY3QgYXMgcCwgc2V0SG9va3MgYXMgcSwgcmVjb3JkQXJ0aWZhY3QgYXMgciwgc2V0Rm4gYXMgcywgc3RhcnRUZXN0cyBhcyB0LCBzdWl0ZSBhcyB1LCB0ZXN0IGFzIHYsIHVwZGF0ZVRhc2sgYXMgdywgY2FsY3VsYXRlU3VpdGVIYXNoIGFzIHgsIGNyZWF0ZUNoYWluYWJsZSBhcyB5LCBjcmVhdGVGaWxlVGFzayBhcyB6IH07XG4iXSwieF9nb29nbGVfaWdub3JlTGlzdCI6WzBdLCJtYXBwaW5n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
|