@cartanova/qgrid-cli 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/bundle/dist/application/qgrid/pool.js +15 -6
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +17 -22
  3. package/bundle/dist/application/qgrid/qgrid.types.js +5 -2
  4. package/bundle/dist/application/request-log/request-log.model.js +2 -2
  5. package/bundle/dist/sonamu.config.js +5 -2
  6. package/bundle/src/application/qgrid/pool.ts +17 -7
  7. package/bundle/src/application/qgrid/qgrid.frame.ts +18 -25
  8. package/bundle/src/application/qgrid/qgrid.types.ts +1 -1
  9. package/bundle/src/application/request-log/request-log.model.ts +2 -2
  10. package/bundle/src/sonamu.config.ts +1 -1
  11. package/bundle/web-dist/{web-dist/client/assets/index-DlPchHBY.js → client/assets/index-C0m8rRjO.js} +2 -2
  12. package/bundle/web-dist/client/assets/{routes-CagDz23B.js → routes-B1eOXnpo.js} +1 -1
  13. package/bundle/web-dist/client/assets/{show-aXUGa0gm.js → show-BztN6MXO.js} +1 -1
  14. package/bundle/web-dist/client/assets/tokens-rR2_-Pte.js +1 -0
  15. package/bundle/web-dist/client/index.html +1 -1
  16. package/bundle/web-dist/server/assets/{tokens-JH6FsnWZ.js → tokens-ARL5AOAh.js} +4 -1
  17. package/bundle/web-dist/server/entry-server.generated.js +1 -1
  18. package/dist/cli.js +34 -25
  19. package/package.json +10 -10
  20. package/bundle/dist/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js +0 -9
  21. package/bundle/dist/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js +0 -6
  22. package/bundle/dist/dist/_virtual/_rolldown/runtime.js +0 -15
  23. package/bundle/dist/dist/application/qgrid/oauth.js +0 -140
  24. package/bundle/dist/dist/application/qgrid/pool.js +0 -100
  25. package/bundle/dist/dist/application/qgrid/qgrid.frame.js +0 -280
  26. package/bundle/dist/dist/application/qgrid/qgrid.types.js +0 -79
  27. package/bundle/dist/dist/application/qgrid/worker.js +0 -183
  28. package/bundle/dist/dist/application/queries.generated.js +0 -31
  29. package/bundle/dist/dist/application/request-log/request-log.model.js +0 -113
  30. package/bundle/dist/dist/application/request-log/request-log.types.js +0 -13
  31. package/bundle/dist/dist/application/sonamu.generated.js +0 -99
  32. package/bundle/dist/dist/application/sonamu.generated.sso.js +0 -34
  33. package/bundle/dist/dist/application/token/token.model.js +0 -157
  34. package/bundle/dist/dist/application/token/token.types.js +0 -22
  35. package/bundle/dist/dist/i18n/en.js +0 -63
  36. package/bundle/dist/dist/i18n/ko.js +0 -62
  37. package/bundle/dist/dist/i18n/sd.generated.js +0 -272
  38. package/bundle/dist/dist/index.js +0 -11
  39. package/bundle/dist/dist/migrations/20260410171405_create__request_logs.js +0 -26
  40. package/bundle/dist/dist/migrations/20260410171406_create__tokens.js +0 -24
  41. package/bundle/dist/dist/migrations/20260411120624_alter_tokens_alter2.js +0 -16
  42. package/bundle/dist/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -155
  43. package/bundle/dist/dist/node_modules/.pnpm/@vitest_expect@4.1.2/node_modules/@vitest/expect/dist/index.js +0 -1484
  44. package/bundle/dist/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.2/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  45. package/bundle/dist/dist/node_modules/.pnpm/@vitest_runner@4.1.2/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2746
  46. package/bundle/dist/dist/node_modules/.pnpm/@vitest_runner@4.1.2/node_modules/@vitest/runner/dist/index.js +0 -8
  47. package/bundle/dist/dist/node_modules/.pnpm/@vitest_runner@4.1.2/node_modules/@vitest/runner/dist/utils.js +0 -8
  48. package/bundle/dist/dist/node_modules/.pnpm/@vitest_snapshot@4.1.2/node_modules/@vitest/snapshot/dist/index.js +0 -662
  49. package/bundle/dist/dist/node_modules/.pnpm/@vitest_spy@4.1.2/node_modules/@vitest/spy/dist/index.js +0 -386
  50. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -82
  51. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/constants.js +0 -48
  52. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/diff.js +0 -1307
  53. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/display.js +0 -558
  54. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/error.js +0 -33
  55. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/helpers.js +0 -226
  56. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/offset.js +0 -27
  57. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/serialize.js +0 -77
  58. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/source-map.js +0 -374
  59. package/bundle/dist/dist/node_modules/.pnpm/@vitest_utils@4.1.2/node_modules/@vitest/utils/dist/timers.js +0 -37
  60. package/bundle/dist/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2886
  61. package/bundle/dist/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  62. package/bundle/dist/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  63. package/bundle/dist/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  64. package/bundle/dist/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  65. package/bundle/dist/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  66. package/bundle/dist/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1127
  67. package/bundle/dist/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  68. package/bundle/dist/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  69. package/bundle/dist/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -506
  70. package/bundle/dist/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -86
  71. 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 +0 -426
  72. 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 +0 -6
  73. 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 +0 -41
  74. 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 +0 -19
  75. 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 +0 -202
  76. 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 +0 -16
  77. 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 +0 -59
  78. 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 +0 -2910
  79. 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 +0 -44
  80. 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 +0 -28
  81. package/bundle/dist/dist/sonamu.config.js +0 -196
  82. package/bundle/dist/dist/testing/fixture.js +0 -8
  83. package/bundle/dist/dist/testing/global.js +0 -9
  84. package/bundle/dist/dist/testing/setup-mocks.js +0 -17
  85. package/bundle/dist/dist/utils/subset-loaders.js +0 -12
  86. package/bundle/src/src/application/qgrid/oauth.ts +0 -181
  87. package/bundle/src/src/application/qgrid/pool.ts +0 -132
  88. package/bundle/src/src/application/qgrid/qgrid.frame.ts +0 -275
  89. package/bundle/src/src/application/qgrid/qgrid.types.ts +0 -117
  90. package/bundle/src/src/application/qgrid/worker.ts +0 -234
  91. package/bundle/src/src/application/queries.generated.ts +0 -59
  92. package/bundle/src/src/application/request-log/request-log.entity.json +0 -75
  93. package/bundle/src/src/application/request-log/request-log.model.ts +0 -155
  94. package/bundle/src/src/application/request-log/request-log.types.ts +0 -15
  95. package/bundle/src/src/application/sonamu.generated.http +0 -187
  96. package/bundle/src/src/application/sonamu.generated.sso.ts +0 -66
  97. package/bundle/src/src/application/sonamu.generated.ts +0 -135
  98. package/bundle/src/src/application/token/token.entity.json +0 -37
  99. package/bundle/src/src/application/token/token.model.ts +0 -160
  100. package/bundle/src/src/application/token/token.types.ts +0 -26
  101. package/bundle/src/src/i18n/en.ts +0 -59
  102. package/bundle/src/src/i18n/ko.ts +0 -59
  103. package/bundle/src/src/i18n/sd.generated.ts +0 -384
  104. package/bundle/src/src/index.ts +0 -6
  105. package/bundle/src/src/migrations/20260410171405_create__request_logs.ts +0 -23
  106. package/bundle/src/src/migrations/20260410171406_create__tokens.ts +0 -21
  107. package/bundle/src/src/migrations/20260411120624_alter_tokens_alter2.ts +0 -15
  108. package/bundle/src/src/sonamu.config.ts +0 -248
  109. package/bundle/src/src/testing/fixture.ts +0 -6
  110. package/bundle/src/src/testing/global.ts +0 -6
  111. package/bundle/src/src/testing/setup-mocks.ts +0 -44
  112. package/bundle/src/src/typings/fastify.d.ts +0 -8
  113. package/bundle/src/src/typings/sonamu.d.ts +0 -17
  114. package/bundle/src/src/utils/subset-loaders.ts +0 -11
  115. package/bundle/web-dist/client/assets/index-DlPchHBY.js +0 -116
  116. package/bundle/web-dist/client/assets/tokens-DRkXtZ3Q.js +0 -1
  117. package/bundle/web-dist/web-dist/client/assets/index-vZsvyuFn.css +0 -1
  118. package/bundle/web-dist/web-dist/client/assets/rolldown-runtime-Dw2cE7zH.js +0 -1
  119. package/bundle/web-dist/web-dist/client/assets/routes-CagDz23B.js +0 -1
  120. package/bundle/web-dist/web-dist/client/assets/sd.generated-BrQoQXvv.js +0 -47
  121. package/bundle/web-dist/web-dist/client/assets/services.generated-BspO2L0j.js +0 -1
  122. package/bundle/web-dist/web-dist/client/assets/show-aXUGa0gm.js +0 -29
  123. package/bundle/web-dist/web-dist/client/assets/tokens-DRkXtZ3Q.js +0 -1
  124. package/bundle/web-dist/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  125. package/bundle/web-dist/web-dist/client/assets/vendor-tanstack-CUxlo6YN.js +0 -1
  126. package/bundle/web-dist/web-dist/client/index.html +0 -18
  127. package/bundle/web-dist/web-dist/server/assets/react-dom-CGIzOSuj.js +0 -335
  128. package/bundle/web-dist/web-dist/server/assets/routes-ClzReRep.js +0 -490
  129. package/bundle/web-dist/web-dist/server/assets/sd.generated-BnonqqKr.js +0 -21694
  130. package/bundle/web-dist/web-dist/server/assets/services.generated-D5ABD5fr.js +0 -836
  131. package/bundle/web-dist/web-dist/server/assets/show-C9pcdSxc.js +0 -23364
  132. package/bundle/web-dist/web-dist/server/assets/tokens-JH6FsnWZ.js +0 -860
  133. package/bundle/web-dist/web-dist/server/entry-server.generated.js +0 -44646
@@ -1,2746 +0,0 @@
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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