@cartanova/qgrid-cli 1.0.2 → 1.0.4

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