@workflow/core 5.0.0-beta.39 → 5.0.0-beta.40

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 (95) hide show
  1. package/dist/classify-error.d.ts.map +1 -1
  2. package/dist/classify-error.js +5 -2
  3. package/dist/correlation-id.d.ts +109 -0
  4. package/dist/correlation-id.d.ts.map +1 -0
  5. package/dist/correlation-id.js +139 -0
  6. package/dist/describe-error.d.ts.map +1 -1
  7. package/dist/describe-error.js +14 -1
  8. package/dist/events-consumer.d.ts +1 -0
  9. package/dist/events-consumer.d.ts.map +1 -1
  10. package/dist/events-consumer.js +11 -3
  11. package/dist/private.d.ts +17 -1
  12. package/dist/private.d.ts.map +1 -1
  13. package/dist/private.js +1 -1
  14. package/dist/runtime/constants.d.ts +19 -0
  15. package/dist/runtime/constants.d.ts.map +1 -1
  16. package/dist/runtime/constants.js +30 -1
  17. package/dist/runtime/deployment-guard.d.ts +99 -0
  18. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  19. package/dist/runtime/deployment-guard.js +154 -0
  20. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  21. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  22. package/dist/runtime/quickjs-assets.generated.js +30 -0
  23. package/dist/runtime/quickjs-entrypoint.d.ts +124 -0
  24. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  25. package/dist/runtime/quickjs-entrypoint.js +1429 -0
  26. package/dist/runtime/quickjs-runtime.d.ts +193 -0
  27. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  28. package/dist/runtime/quickjs-runtime.js +1944 -0
  29. package/dist/runtime/run.d.ts +2 -0
  30. package/dist/runtime/run.d.ts.map +1 -1
  31. package/dist/runtime/run.js +9 -4
  32. package/dist/runtime/runs.d.ts +18 -1
  33. package/dist/runtime/runs.d.ts.map +1 -1
  34. package/dist/runtime/runs.js +96 -2
  35. package/dist/runtime/start.d.ts.map +1 -1
  36. package/dist/runtime/start.js +9 -1
  37. package/dist/runtime/suspension-handler.d.ts +7 -0
  38. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  39. package/dist/runtime/suspension-handler.js +29 -2
  40. package/dist/runtime/vm-mode.d.ts +44 -0
  41. package/dist/runtime/vm-mode.d.ts.map +1 -0
  42. package/dist/runtime/vm-mode.js +62 -0
  43. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  44. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  45. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  46. package/dist/runtime.d.ts +1 -1
  47. package/dist/runtime.d.ts.map +1 -1
  48. package/dist/runtime.js +484 -47
  49. package/dist/serialization/codec-devalue-vm.d.ts +9 -0
  50. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  51. package/dist/serialization/codec-devalue-vm.js +137 -0
  52. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  53. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  54. package/dist/serialization/reducers/class-vm.js +77 -0
  55. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  56. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  57. package/dist/serialization/reducers/common-vm.js +579 -0
  58. package/dist/serialization/reducers/common.d.ts.map +1 -1
  59. package/dist/serialization/reducers/common.js +28 -6
  60. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  61. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  62. package/dist/serialization/reducers/step-function-vm.js +97 -0
  63. package/dist/serialization/vm-bundle-entry.d.ts +12 -0
  64. package/dist/serialization/vm-bundle-entry.d.ts.map +1 -0
  65. package/dist/serialization/vm-bundle-entry.js +58 -0
  66. package/dist/serialization/workflow-vm.d.ts +24 -0
  67. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  68. package/dist/serialization/workflow-vm.js +66 -0
  69. package/dist/serialization.d.ts +2 -1
  70. package/dist/serialization.d.ts.map +1 -1
  71. package/dist/serialization.js +26 -21
  72. package/dist/source-map.d.ts +20 -0
  73. package/dist/source-map.d.ts.map +1 -1
  74. package/dist/source-map.js +47 -1
  75. package/dist/step.d.ts.map +1 -1
  76. package/dist/step.js +7 -2
  77. package/dist/telemetry/semantic-conventions.d.ts +78 -0
  78. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  79. package/dist/telemetry/semantic-conventions.js +56 -1
  80. package/dist/telemetry.d.ts +5 -0
  81. package/dist/telemetry.d.ts.map +1 -1
  82. package/dist/telemetry.js +13 -13
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +2 -2
  85. package/dist/workflow/abort-controller.d.ts.map +1 -1
  86. package/dist/workflow/abort-controller.js +6 -4
  87. package/dist/workflow/attribute-dispatcher.js +2 -2
  88. package/dist/workflow/hook.js +2 -2
  89. package/dist/workflow/sleep.js +2 -2
  90. package/dist/workflow.d.ts +49 -2
  91. package/dist/workflow.d.ts.map +1 -1
  92. package/dist/workflow.js +723 -569
  93. package/docs/api-reference/create-hook.mdx +1 -1
  94. package/docs/foundations/starting-workflows.mdx +74 -1
  95. package/package.json +8 -7
@@ -0,0 +1,1944 @@
1
+ /**
2
+ * QuickJS WASM workflow VM.
3
+ *
4
+ * An alternative engine for the event-replay execution model: the workflow
5
+ * code runs inside a QuickJS WASM VM (via quickjs-wasi) instead of a
6
+ * `node:vm` context. Every invocation creates a fresh VM, re-executes the
7
+ * workflow function from the top, and replays the recorded event log to
8
+ * resolve awaited primitives — the same replay semantics as the `node:vm`
9
+ * engine.
10
+ *
11
+ * The workflow primitives (useStep, sleep, createHook) are implemented as
12
+ * JavaScript code running inside the QuickJS VM. The host communicates with
13
+ * the VM by evaluating small JS snippets to read pending operations and
14
+ * resolve/reject promises.
15
+ *
16
+ * The VM bootstrap is deliberately split into two phases:
17
+ * 1. Static initialization (`initWorkflowVM`) — run-independent setup:
18
+ * VM creation, the serde bundle, and the workflow primitives.
19
+ * 2. Per-run initialization (inline in `runQuickJSWorkflow`) — seeded
20
+ * PRNG/ULID host functions, workflow bundle evaluation, run metadata,
21
+ * workflow input, and start.
22
+ * Keeping the phases separate is groundwork for VM-memory snapshotting:
23
+ * a follow-up can persist/restore the VM at the phase boundary (e.g. a
24
+ * build-time initial snapshot) without restructuring this module. Note
25
+ * that bundle evaluation currently sits in the per-run phase so that
26
+ * module-scope user code observes the seeded `Math.random`, matching the
27
+ * `node:vm` engine's replay determinism.
28
+ */
29
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
30
+ if (value !== null && value !== void 0) {
31
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
32
+ var dispose, inner;
33
+ if (async) {
34
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
35
+ dispose = value[Symbol.asyncDispose];
36
+ }
37
+ if (dispose === void 0) {
38
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
39
+ dispose = value[Symbol.dispose];
40
+ if (async) inner = dispose;
41
+ }
42
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
43
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
44
+ env.stack.push({ value: value, dispose: dispose, async: async });
45
+ }
46
+ else if (async) {
47
+ env.stack.push({ async: true });
48
+ }
49
+ return value;
50
+ };
51
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
52
+ return function (env) {
53
+ function fail(e) {
54
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
55
+ env.hasError = true;
56
+ }
57
+ var r, s = 0;
58
+ function next() {
59
+ while (r = env.stack.pop()) {
60
+ try {
61
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
62
+ if (r.dispose) {
63
+ var result = r.dispose.call(r.value);
64
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
65
+ }
66
+ else s |= 1;
67
+ }
68
+ catch (e) {
69
+ fail(e);
70
+ }
71
+ }
72
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
73
+ if (env.hasError) throw env.error;
74
+ }
75
+ return next();
76
+ };
77
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
78
+ var e = new Error(message);
79
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
80
+ });
81
+ import * as nanoid from 'nanoid';
82
+ import { JSException, QuickJS, } from 'quickjs-wasi';
83
+ import seedrandom from 'seedrandom';
84
+ import { runtimeLogger } from '../logger.js';
85
+ import { decompress } from '../serialization/compression.js';
86
+ import { decrypt } from '../serialization/encryption.js';
87
+ import { getReplayTimeoutMs } from './constants.js';
88
+ import { quickjsExtensions, quickjsWasm } from './quickjs-assets.generated.js';
89
+ import { runIdCreatedAt } from './run-id-time.js';
90
+ import { VM_SERDE_BUNDLE } from './vm-serde-bundle.generated.js';
91
+ // ---- Host -> VM payload preparation ----
92
+ /**
93
+ * Prepare persisted payload bytes for consumption inside the VM: decrypt
94
+ * (when an encryption key is configured) and decompress (specVersion >= 5
95
+ * payloads may be gzip/zstd-compressed). The VM only understands plain
96
+ * format-prefixed 'devl' bytes — it has neither the key material nor zlib.
97
+ * The key is the run's full DecryptionKey capability (symmetric AES key +
98
+ * X25519 keypair) so sealed `encp` hook payloads from cross-deployment
99
+ * resumeHook() calls open here too, not just symmetric `encr` ones.
100
+ * Both stages are format-prefix dispatched, so plaintext/uncompressed
101
+ * data passes through unchanged. Mirrors `prepareReplayPayload` in
102
+ * serialization.ts (the node:vm engine's equivalent host-side stage).
103
+ */
104
+ async function prepareBytesForVM(data, key) {
105
+ return (await decompress(await decrypt(data, key)));
106
+ }
107
+ // ---- VM Bootstrap Code ----
108
+ /**
109
+ * JavaScript code that runs inside the QuickJS VM to set up the workflow
110
+ * primitives. This sets up:
111
+ * - globalThis.__private_workflows (Map) - workflow registry
112
+ * - globalThis.__resolvers (Object) - pending promise resolve/reject functions
113
+ * - globalThis.__pending (Array) - metadata about pending operations
114
+ * - globalThis[Symbol.for("WORKFLOW_USE_STEP")] - step proxy factory
115
+ * - globalThis[Symbol.for("WORKFLOW_SLEEP")] - sleep function
116
+ */
117
+ const VM_BOOTSTRAP = `
118
+ // Symbol.dispose / Symbol.asyncDispose polyfills for QuickJS
119
+ if (typeof Symbol.dispose === "undefined") {
120
+ Symbol.dispose = Symbol.for("Symbol.dispose");
121
+ }
122
+ if (typeof Symbol.asyncDispose === "undefined") {
123
+ Symbol.asyncDispose = Symbol.for("Symbol.asyncDispose");
124
+ }
125
+
126
+ globalThis.__private_workflows = new Map();
127
+ globalThis.__resolvers = {};
128
+ globalThis.__pending = [];
129
+ globalThis.__workflowResult = undefined;
130
+ globalThis.__workflowError = undefined;
131
+ // Buffer for hook_received payloads that arrive before the hook is awaited.
132
+ // Keyed by correlationId → array of payloads (preserves delivery order).
133
+ // This mirrors the event-replay runtime's payloadsQueue in hook.ts.
134
+ globalThis.__hookPayloadBuffer = {};
135
+
136
+ // Buffer for step/wait/attr terminal outcomes that arrive before this VM
137
+ // has constructed the corresponding awaiting promise. In fresh-VM replay
138
+ // the multi-pass event scan makes this unreachable (awaits are
139
+ // reconstructed before their terminals are re-scanned), but the live
140
+ // continuation path (continueWithEvents) scans each delta exactly once —
141
+ // a concurrent invocation's terminal arriving before this VM reaches the
142
+ // await would otherwise be dropped on the floor and the await would
143
+ // never settle (the feed's seen-set means it is never re-delivered).
144
+ // Mirrors __hookPayloadBuffer, which exists for exactly this reason on
145
+ // the hook path. Keyed by correlationId → single terminal (steps, waits
146
+ // and attrs settle exactly once).
147
+ globalThis.__terminalBuffer = {};
148
+
149
+ // Registers a resolver for an awaited primitive, first draining any
150
+ // buffered terminal recorded for the correlationId. Entries are prepared
151
+ // host-side (bytes already decrypted; see processEvents).
152
+ globalThis.__registerResolver = function(correlationId, resolve, reject) {
153
+ var buffered = globalThis.__terminalBuffer[correlationId];
154
+ if (buffered) {
155
+ delete globalThis.__terminalBuffer[correlationId];
156
+ if (buffered.kind === "resolve_bytes") {
157
+ resolve(globalThis[Symbol.for("workflow-deserialize")](buffered.bytes));
158
+ } else if (buffered.kind === "resolve_value") {
159
+ resolve(buffered.value);
160
+ } else if (buffered.kind === "reject_bytes") {
161
+ reject(globalThis[Symbol.for("workflow-deserialize")](buffered.bytes));
162
+ } else if (buffered.kind === "reject_error") {
163
+ var e = new Error(buffered.message);
164
+ e.name = "FatalError";
165
+ e.fatal = true;
166
+ if (buffered.stack) e.stack = buffered.stack;
167
+ reject(e);
168
+ } else {
169
+ resolve(undefined);
170
+ }
171
+ return;
172
+ }
173
+ globalThis.__resolvers[correlationId] = { resolve: resolve, reject: reject };
174
+ };
175
+
176
+ // Stubs for Web APIs that the workflow bundle may reference but are not
177
+ // available in QuickJS. Native C extensions (encoding, headers, url,
178
+ // structured-clone) provide the real implementations; these are minimal
179
+ // stubs for APIs that don't have native extensions yet. (btoa/atob and
180
+ // the Uint8Array base64/hex methods are built into quickjs-wasi >= 3.)
181
+
182
+ if (typeof ReadableStream === "undefined") {
183
+ // Minimal ReadableStream that stores body data for Response.json()/text()
184
+ globalThis.ReadableStream = function() {};
185
+ globalThis.ReadableStream.prototype.__bodyData = null;
186
+ }
187
+
188
+ if (typeof WritableStream === "undefined") {
189
+ globalThis.WritableStream = function() {};
190
+ }
191
+
192
+ if (typeof TransformStream === "undefined") {
193
+ globalThis.TransformStream = function() {};
194
+ }
195
+
196
+ if (typeof console === "undefined") {
197
+ globalThis.console = { log: function(){}, error: function(){}, warn: function(){}, info: function(){} };
198
+ }
199
+ // Stub exports/module for CJS bundle format
200
+ globalThis.exports = {};
201
+ globalThis.module = { exports: globalThis.exports };
202
+ // NOTE: TextEncoder/TextDecoder are provided by the native encoding extension.
203
+
204
+ // ---- Deterministic \`crypto\` (parity with the node:vm engine) ----
205
+ // getRandomValues / randomUUID draw from Math.random, which the host
206
+ // replaces with the run's seeded PRNG before any user code runs — so the
207
+ // values replay deterministically and match the node engine, whose
208
+ // implementations draw from the same seeded sequence (see vm/index.ts).
209
+ // Every crypto.subtle method throws with the same guidance as the node
210
+ // engine's non-replayable methods; unlike node, \`digest\` is also
211
+ // unavailable here (no native hash in the VM yet).
212
+ (function() {
213
+ function getRandomValues(array) {
214
+ for (var i = 0; i < array.length; i++) {
215
+ array[i] = Math.floor(Math.random() * 256);
216
+ }
217
+ return array;
218
+ }
219
+ // Mirrors vm/uuid.ts createRandomUUID: identical draw pattern from the
220
+ // seeded PRNG, so both engines produce the same UUID at the same point
221
+ // in a replay.
222
+ function randomUUID() {
223
+ var chars = "0123456789abcdef";
224
+ var uuid = "";
225
+ for (var i = 0; i < 36; i++) {
226
+ if (i === 8 || i === 13 || i === 18 || i === 23) {
227
+ uuid += "-";
228
+ } else if (i === 14) {
229
+ uuid += "4";
230
+ } else if (i === 19) {
231
+ uuid += chars[Math.floor(Math.random() * 4) + 8];
232
+ } else {
233
+ uuid += chars[Math.floor(Math.random() * 16)];
234
+ }
235
+ }
236
+ return uuid;
237
+ }
238
+ function subtleThrow(name) {
239
+ return function() {
240
+ var err = new Error("\`crypto.subtle." + name + "()\` is not available inside a workflow function. Move it to a step function where full Node.js crypto is available.");
241
+ err.name = "WorkflowRuntimeError";
242
+ throw err;
243
+ };
244
+ }
245
+ var subtle = {};
246
+ ["encrypt","decrypt","sign","verify","digest","generateKey","deriveKey","deriveBits","importKey","exportKey","wrapKey","unwrapKey"].forEach(function(m) {
247
+ subtle[m] = subtleThrow(m);
248
+ });
249
+ globalThis.crypto = {
250
+ getRandomValues: getRandomValues,
251
+ randomUUID: randomUUID,
252
+ subtle: subtle,
253
+ };
254
+ })();
255
+
256
+ // ---- Loud Intl / locale guards ----
257
+ // QuickJS has no ICU: \`Intl\` is absent and toLocaleString-family methods
258
+ // silently ignore their locale argument. Silent divergence from the node
259
+ // engine would write different values into a durable event log with no
260
+ // error anywhere — so make the gap loud instead: Intl constructors throw,
261
+ // and toLocale* methods throw ONLY when called with an explicit locale
262
+ // (the no-argument forms keep QuickJS's default behavior).
263
+ (function() {
264
+ function intlThrow(name) {
265
+ return function() {
266
+ var err = new Error("\`Intl." + name + "\` is not available in the QuickJS workflow engine (no ICU). Perform locale-sensitive formatting in a step function, or use WORKFLOW_VM=node.");
267
+ err.name = "WorkflowRuntimeError";
268
+ throw err;
269
+ };
270
+ }
271
+ if (typeof Intl === "undefined") {
272
+ var intl = {};
273
+ ["Collator","DateTimeFormat","DisplayNames","DurationFormat","ListFormat","Locale","NumberFormat","PluralRules","RelativeTimeFormat","Segmenter"].forEach(function(n) {
274
+ intl[n] = intlThrow(n);
275
+ });
276
+ intl.getCanonicalLocales = intlThrow("getCanonicalLocales");
277
+ globalThis.Intl = intl;
278
+ }
279
+ function guardLocale(proto, method) {
280
+ var original = proto[method];
281
+ if (typeof original !== "function") return;
282
+ proto[method] = function(locales) {
283
+ if (locales !== undefined) {
284
+ var err = new Error("\`" + method + "(locales, ...)\` with an explicit locale is not supported in the QuickJS workflow engine (no ICU) — it would silently ignore the locale. Format in a step function, or call without arguments for the engine default.");
285
+ err.name = "WorkflowRuntimeError";
286
+ throw err;
287
+ }
288
+ return original.call(this);
289
+ };
290
+ }
291
+ guardLocale(Number.prototype, "toLocaleString");
292
+ guardLocale(Date.prototype, "toLocaleString");
293
+ guardLocale(Date.prototype, "toLocaleDateString");
294
+ guardLocale(Date.prototype, "toLocaleTimeString");
295
+ guardLocale(String.prototype, "toLocaleLowerCase");
296
+ guardLocale(String.prototype, "toLocaleUpperCase");
297
+ // localeCompare's locales argument is the SECOND parameter.
298
+ (function() {
299
+ var original = String.prototype.localeCompare;
300
+ String.prototype.localeCompare = function(that, locales) {
301
+ if (locales !== undefined) {
302
+ var err = new Error("\`localeCompare(that, locales, ...)\` with an explicit locale is not supported in the QuickJS workflow engine (no ICU). Compare in a step function, or call without a locale.");
303
+ err.name = "WorkflowRuntimeError";
304
+ throw err;
305
+ }
306
+ return original.call(this, that);
307
+ };
308
+ })();
309
+ })();
310
+
311
+ globalThis[Symbol.for("WORKFLOW_USE_STEP")] = function(stepId, closureVarsFn) {
312
+ var fn = function() {
313
+ var args = Array.prototype.slice.call(arguments);
314
+ var correlationId = "step_" + globalThis.__generateUlid();
315
+ // Capture 'this' for method invocations (e.g., MyClass.method())
316
+ var thisVal = (this !== undefined && this !== null && this !== globalThis) ? this : undefined;
317
+ // Serialize step input using the host-provided devalue serializer.
318
+ // This produces a format-prefixed Uint8Array ("devl" + devalue.stringify).
319
+ var input = globalThis[Symbol.for("workflow-serialize")]({
320
+ args: args,
321
+ closureVars: closureVarsFn ? closureVarsFn() : undefined,
322
+ thisVal: thisVal,
323
+ });
324
+ globalThis.__pending.push({
325
+ type: "step",
326
+ correlationId: correlationId,
327
+ stepId: stepId,
328
+ input: input,
329
+ hasCreatedEvent: false,
330
+ });
331
+ return new Promise(function(resolve, reject) {
332
+ globalThis.__registerResolver(correlationId, resolve, reject);
333
+ });
334
+ };
335
+ // Set stepId on the proxy so the StepFunction reducer can detect and
336
+ // serialize step function references (e.g. when passed as arguments).
337
+ fn.stepId = stepId;
338
+ if (closureVarsFn) fn.__closureVarsFn = closureVarsFn;
339
+ // Override .bind so a bound step proxy (e.g. the SWC plugin's
340
+ // useStep(...).bind(this) for lexical-this arrow steps) keeps its
341
+ // stepId and records the bound receiver / prefilled args — the native
342
+ // bind drops own properties, which would make the StepFunction
343
+ // reducer fail to recognize the proxy when it crosses a serialization
344
+ // boundary. Mirrors the node:vm engine's override in step.ts.
345
+ fn.bind = function(thisArg) {
346
+ var partialArgs = Array.prototype.slice.call(arguments, 1);
347
+ var bound = Function.prototype.bind.apply(this, [thisArg].concat(partialArgs));
348
+ bound.stepId = stepId;
349
+ if (closureVarsFn) bound.__closureVarsFn = closureVarsFn;
350
+ bound.__boundThis = thisArg;
351
+ if (partialArgs.length > 0) bound.__boundArgs = partialArgs;
352
+ return bound;
353
+ };
354
+ return fn;
355
+ };
356
+
357
+ // Parses an "ms" library style duration string into milliseconds.
358
+ // Supports the same units as the replay runtime (which uses the "ms"
359
+ // package): ms / s / m / h / d / w / y, with verbose aliases
360
+ // (seconds, minutes, ...).
361
+ globalThis.__parseDurationMs = function(str) {
362
+ str = String(str);
363
+ if (str.length > 100) return undefined;
364
+ var match = str.match(
365
+ /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i
366
+ );
367
+ if (!match) return undefined;
368
+ var n = parseFloat(match[1]);
369
+ var type = (match[2] || "ms").toLowerCase();
370
+ var s = 1000, m = 60 * s, h = 60 * m, d = 24 * h, w = 7 * d, y = 365.25 * d;
371
+ switch (type) {
372
+ case "years": case "year": case "yrs": case "yr": case "y": return n * y;
373
+ case "weeks": case "week": case "w": return n * w;
374
+ case "days": case "day": case "d": return n * d;
375
+ case "hours": case "hour": case "hrs": case "hr": case "h": return n * h;
376
+ case "minutes": case "minute": case "mins": case "min": case "m": return n * m;
377
+ case "seconds": case "second": case "secs": case "sec": case "s": return n * s;
378
+ case "milliseconds": case "millisecond": case "msecs": case "msec": case "ms": return n;
379
+ default: return undefined;
380
+ }
381
+ };
382
+
383
+ globalThis[Symbol.for("WORKFLOW_SLEEP")] = function(param) {
384
+ var correlationId = "wait_" + globalThis.__generateUlid();
385
+ var resumeAt;
386
+ if (typeof param === "number") {
387
+ resumeAt = new Date(Date.now() + param).toISOString();
388
+ } else if (typeof param === "string") {
389
+ var ms = globalThis.__parseDurationMs(param);
390
+ if (typeof ms === "number" && isFinite(ms)) {
391
+ resumeAt = new Date(Date.now() + ms).toISOString();
392
+ } else {
393
+ // Not a duration string — try as an absolute date string.
394
+ var date = new Date(param);
395
+ if (isNaN(date.getTime())) {
396
+ throw new Error("Invalid sleep parameter: " + param);
397
+ }
398
+ resumeAt = date.toISOString();
399
+ }
400
+ } else if (param instanceof Date) {
401
+ if (isNaN(param.getTime())) {
402
+ throw new Error("Invalid sleep parameter: " + param);
403
+ }
404
+ resumeAt = param.toISOString();
405
+ } else {
406
+ throw new Error("Invalid sleep parameter: " + param);
407
+ }
408
+ globalThis.__pending.push({
409
+ type: "wait",
410
+ correlationId: correlationId,
411
+ resumeAt: resumeAt,
412
+ hasCreatedEvent: false,
413
+ });
414
+ return new Promise(function(resolve, reject) {
415
+ globalThis.__registerResolver(correlationId, resolve, reject);
416
+ });
417
+ };
418
+
419
+ // Response/Request polyfills — .json()/.text()/.arrayBuffer() are useStep
420
+ // proxies that execute on the host side. The proxies are assigned directly
421
+ // to the prototypes so that 'this' (the Response/Request instance) is
422
+ // serialized as thisVal by WORKFLOW_USE_STEP, matching the event-replay
423
+ // runtime's approach (commit dcb0761).
424
+ if (typeof Response === "undefined") {
425
+ var __BODY_INIT = Symbol.for("BODY_INIT");
426
+
427
+ globalThis.Response = function(body, init) {
428
+ init = init || {};
429
+ this.status = init.status || 200;
430
+ this.statusText = init.statusText || "";
431
+ this.headers = new globalThis.Headers(init.headers || []);
432
+ this.type = "default";
433
+ this.url = "";
434
+ this.redirected = false;
435
+ if (body !== null && body !== undefined) {
436
+ this.body = Object.create(globalThis.ReadableStream.prototype);
437
+ this.body[__BODY_INIT] = body;
438
+ } else {
439
+ this.body = null;
440
+ }
441
+ };
442
+ Object.defineProperty(globalThis.Response.prototype, "ok", {
443
+ get: function() { return this.status >= 200 && this.status < 300; }
444
+ });
445
+ Object.defineProperty(globalThis.Response.prototype, "bodyUsed", {
446
+ get: function() { return false; }
447
+ });
448
+ // Assign useStep proxies directly — 'this' binding provides the
449
+ // Response instance, which gets serialized as thisVal by the proxy.
450
+ Object.defineProperties(globalThis.Response.prototype, {
451
+ arrayBuffer: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_array_buffer"), writable: true, configurable: true },
452
+ json: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_json"), writable: true, configurable: true },
453
+ text: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_text"), writable: true, configurable: true },
454
+ });
455
+ globalThis.Response.prototype.bytes = function() {
456
+ return this.arrayBuffer().then(function(buf) { return new Uint8Array(buf); });
457
+ };
458
+ globalThis.Response.prototype.clone = function() {
459
+ var r = Object.create(globalThis.Response.prototype);
460
+ r.status = this.status; r.statusText = this.statusText;
461
+ r.headers = this.headers; r.type = this.type;
462
+ r.url = this.url; r.redirected = this.redirected; r.body = this.body;
463
+ return r;
464
+ };
465
+ globalThis.Response.json = function(data, init) {
466
+ var body = JSON.stringify(data);
467
+ var headers = new globalThis.Headers(init ? init.headers : []);
468
+ if (!headers.has("content-type")) { headers.set("content-type", "application/json"); }
469
+ return new globalThis.Response(body, { status: (init && init.status) || 200, statusText: (init && init.statusText) || "", headers: headers });
470
+ };
471
+ }
472
+ if (typeof Request === "undefined") {
473
+ globalThis.Request = function(input, init) {
474
+ init = init || {};
475
+ if (typeof input === "string") { this.url = input; }
476
+ else if (input && typeof input === "object") {
477
+ this.url = input.url || ""; this.method = input.method;
478
+ this.headers = input.headers; this.body = input.body;
479
+ }
480
+ if (init.method) this.method = init.method.toUpperCase();
481
+ if (!this.method) this.method = "GET";
482
+ if (init.headers) this.headers = new globalThis.Headers(init.headers);
483
+ if (!this.headers) this.headers = new globalThis.Headers();
484
+ if (init.body !== undefined) this.body = init.body;
485
+ if (!this.body) this.body = null;
486
+ this.duplex = init.duplex || "half";
487
+ };
488
+ Object.defineProperty(globalThis.Request.prototype, "bodyUsed", {
489
+ get: function() { return false; }
490
+ });
491
+ Object.defineProperties(globalThis.Request.prototype, {
492
+ arrayBuffer: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_array_buffer"), writable: true, configurable: true },
493
+ json: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_json"), writable: true, configurable: true },
494
+ text: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_text"), writable: true, configurable: true },
495
+ });
496
+ }
497
+
498
+ // createHook — returns a Hook object that is both a Thenable and AsyncIterable.
499
+ // Each await/yield creates a new promise keyed by the same correlationId.
500
+ // The promise is resolved when a hook_received event arrives.
501
+ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
502
+ options = options || {};
503
+ if (options.isWebhook === true && options.experimental_minRetention !== undefined) {
504
+ throw new Error('Webhook hooks do not support \`experimental_minRetention\`. Use a non-webhook \`createHook()\` with \`resumeHook()\`.');
505
+ }
506
+ if (options.experimental_minRetention !== undefined && globalThis.__worldCapabilities?.hookRetention?.active !== true) {
507
+ var unsupportedRetentionError = new Error('The configured World does not support \`experimental_minRetention\` for Hooks.');
508
+ unsupportedRetentionError.name = "FatalError";
509
+ unsupportedRetentionError.fatal = true;
510
+ throw unsupportedRetentionError;
511
+ }
512
+ var token = options.token || globalThis.__generateNanoid();
513
+ var correlationId = "hook_" + globalThis.__generateUlid();
514
+ var isDisposed = false;
515
+ var hasCreatedEvent = false;
516
+ var tokenRetentionUntil;
517
+ if (options.experimental_minRetention !== undefined) {
518
+ var minRetention = options.experimental_minRetention;
519
+ if (typeof minRetention === "number") {
520
+ if (minRetention < 0 || !isFinite(minRetention)) {
521
+ throw new Error("Invalid duration: " + minRetention + ". Expected a non-negative finite number of milliseconds.");
522
+ }
523
+ tokenRetentionUntil = Date.now() + minRetention;
524
+ } else if (typeof minRetention === "string") {
525
+ var retentionMs = globalThis.__parseDurationMs(minRetention);
526
+ if (typeof retentionMs !== "number" || retentionMs < 0 || !isFinite(retentionMs)) {
527
+ throw new Error('Invalid duration: "' + minRetention + '". Expected a valid duration string like "1s", "1m", "1h", etc.');
528
+ }
529
+ tokenRetentionUntil = Date.now() + retentionMs;
530
+ } else if (minRetention instanceof Date || (minRetention && typeof minRetention.getTime === "function")) {
531
+ // Accept Date-like objects (anything with getTime), matching
532
+ // parseDurationToDate: values that crossed the serde boundary may
533
+ // not be realm-native Date instances.
534
+ tokenRetentionUntil = minRetention.getTime();
535
+ } else {
536
+ throw new Error("Invalid duration parameter. Expected a duration string, number (milliseconds), or Date object.");
537
+ }
538
+ }
539
+
540
+ // Register in pending operations.
541
+ // Serialize metadata inside the VM so Response/Request objects are
542
+ // properly handled by the devalue reducers before crossing the boundary.
543
+ var pendingOp = {
544
+ type: "hook",
545
+ correlationId: correlationId,
546
+ token: token,
547
+ tokenRetentionUntil: tokenRetentionUntil,
548
+ isWebhook: !!options.isWebhook,
549
+ metadata: options.metadata ? globalThis[Symbol.for("workflow-serialize")](options.metadata) : undefined,
550
+ hasCreatedEvent: false,
551
+ };
552
+ globalThis.__pending.push(pendingOp);
553
+
554
+ // Per-hook lifecycle state backing hook.getConflict(): resolves null
555
+ // once creation is confirmed (hook_created), or resolves with the
556
+ // conflicting Run handle / rejects with HookConflictError on
557
+ // hook_conflict. State transitions are driven by the host during event
558
+ // processing (see processEvents).
559
+ globalThis.__hooks = globalThis.__hooks || {};
560
+ globalThis.__hooks[correlationId] = {
561
+ token: token,
562
+ created: false,
563
+ conflict: null,
564
+ getConflictResolvers: [],
565
+ };
566
+
567
+ // Each await creates a new promise for the next payload.
568
+ // The correlationId stays the same — the resolver is replaced each time.
569
+ function createHookPromise() {
570
+ // Check the payload buffer first — if a hook_received event arrived
571
+ // before this hook was awaited, the payload was buffered in the VM
572
+ // heap. Drain it immediately (matching event-replay payloadsQueue).
573
+ var buf = globalThis.__hookPayloadBuffer[correlationId];
574
+ if (buf && buf.length > 0) {
575
+ return Promise.resolve(buf.shift());
576
+ }
577
+ return new Promise(function(resolve, reject) {
578
+ globalThis.__resolvers[correlationId] = { resolve: resolve, reject: reject };
579
+ });
580
+ }
581
+
582
+ function disposeHook() {
583
+ if (isDisposed) return;
584
+ isDisposed = true;
585
+ // A conflicted hook was never created (the world rejected its claim
586
+ // — the token belongs to another run), so there is no entity to
587
+ // dispose. Mirrors the node:vm engine, where hook_conflict removes
588
+ // the invocation-queue item before dispose can mark it. Emitting a
589
+ // hook_disposed here would be rejected by the world's
590
+ // hook-existence validation.
591
+ var state = globalThis.__hooks[correlationId];
592
+ if (!state || !state.conflict) {
593
+ // Signal to the entrypoint to create a hook_disposed event. The
594
+ // token is carried so the entrypoint can order same-token hook
595
+ // operations sequentially (a dispose must release the token before
596
+ // a later same-token hook's creation is validated).
597
+ globalThis.__pending.push({
598
+ type: "hook_dispose",
599
+ correlationId: correlationId,
600
+ token: token,
601
+ hasCreatedEvent: false,
602
+ });
603
+ }
604
+ // If there's a pending resolver, resolve it with undefined to break the iterator
605
+ if (globalThis.__resolvers[correlationId]) {
606
+ globalThis.__resolvers[correlationId].resolve(undefined);
607
+ delete globalThis.__resolvers[correlationId];
608
+ }
609
+ }
610
+
611
+ function getConflict() {
612
+ var state = globalThis.__hooks[correlationId];
613
+ if (state.conflict) {
614
+ return state.conflict.run
615
+ ? Promise.resolve(state.conflict.run)
616
+ : Promise.reject(state.conflict.error);
617
+ }
618
+ if (state.created) {
619
+ return Promise.resolve(null);
620
+ }
621
+ // Creation not yet confirmed by the event log — park the awaiter and
622
+ // flag the pending op so the entrypoint re-invokes the workflow right
623
+ // after writing hook_created (nothing external resumes a getConflict
624
+ // awaiter; confirmation only comes from replaying the new event).
625
+ pendingOp.hasGetConflictAwaiter = true;
626
+ return new Promise(function(resolve, reject) {
627
+ state.getConflictResolvers.push({ resolve: resolve, reject: reject });
628
+ });
629
+ }
630
+
631
+ var hook = {
632
+ token: token,
633
+ then: function(onFulfilled, onRejected) {
634
+ return createHookPromise().then(onFulfilled, onRejected);
635
+ },
636
+ getConflict: getConflict,
637
+ dispose: disposeHook,
638
+ };
639
+
640
+ // Symbol.dispose for explicit resource management
641
+ hook[Symbol.dispose] = disposeHook;
642
+
643
+ // AsyncIterable — yields payloads until disposed
644
+ hook[Symbol.asyncIterator] = function() {
645
+ return {
646
+ next: function() {
647
+ if (isDisposed) {
648
+ return Promise.resolve({ done: true, value: undefined });
649
+ }
650
+ return createHookPromise().then(function(value) {
651
+ // If disposed while waiting, signal done
652
+ if (isDisposed) return { done: true, value: undefined };
653
+ return { done: false, value: value };
654
+ });
655
+ },
656
+ return: function() {
657
+ disposeHook();
658
+ return Promise.resolve({ done: true, value: undefined });
659
+ },
660
+ };
661
+ };
662
+
663
+ return hook;
664
+ };
665
+
666
+ // setAttributes — attaches plaintext metadata to the current run.
667
+ // Validation happens in library code (normalizeAttributeChanges) before
668
+ // this dispatcher is invoked, so "changes" is already normalized. The
669
+ // returned promise resolves when the matching attr_set event is
670
+ // observed during event processing — mirroring the node:vm engine's
671
+ // createSetAttributes (attribute-dispatcher.ts).
672
+ globalThis[Symbol.for("WORKFLOW_SET_ATTRIBUTES")] = function(changes, options) {
673
+ var correlationId = "attr_" + globalThis.__generateUlid();
674
+ globalThis.__pending.push({
675
+ type: "attribute",
676
+ correlationId: correlationId,
677
+ changes: changes,
678
+ allowReservedAttributes: !!(options && options.allowReservedAttributes),
679
+ hasCreatedEvent: false,
680
+ });
681
+ return new Promise(function(resolve, reject) {
682
+ globalThis.__registerResolver(correlationId, resolve, reject);
683
+ });
684
+ };
685
+
686
+ // ---- AbortController / AbortSignal (hook-backed) ----
687
+ // Port of workflow/abort-controller.ts to the VM pending-op model:
688
+ // the controller registers a system hook; abort() flips the signal
689
+ // synchronously and marks the pending op so the host records the abort
690
+ // (hook_received event + stream packet). On replay, the recorded
691
+ // hook_received event calls _setAborted during event processing and the
692
+ // workflow's own abort() call becomes a no-op.
693
+ var __ABORT_STREAM_NAME = Symbol.for("WORKFLOW_ABORT_STREAM_NAME");
694
+ var __ABORT_HOOK_TOKEN = Symbol.for("WORKFLOW_ABORT_HOOK_TOKEN");
695
+
696
+ function __makeAbortError() {
697
+ if (typeof DOMException !== "undefined") {
698
+ return new DOMException("The operation was aborted.", "AbortError");
699
+ }
700
+ var e = new Error("The operation was aborted.");
701
+ e.name = "AbortError";
702
+ return e;
703
+ }
704
+
705
+ function WorkflowAbortSignal(streamName, hookToken) {
706
+ this.aborted = false;
707
+ this.reason = undefined;
708
+ this[__ABORT_STREAM_NAME] = streamName;
709
+ this[__ABORT_HOOK_TOKEN] = hookToken;
710
+ this.__listeners = [];
711
+ this.__onabort = null;
712
+ }
713
+ Object.defineProperty(WorkflowAbortSignal.prototype, "onabort", {
714
+ get: function() { return this.__onabort; },
715
+ set: function(handler) {
716
+ this.__onabort = handler;
717
+ if (handler && this.aborted) handler.call(this);
718
+ },
719
+ });
720
+ WorkflowAbortSignal.prototype._setAborted = function(reason) {
721
+ if (this.aborted) return;
722
+ this.aborted = true;
723
+ this.reason = reason;
724
+ if (this.__onabort) this.__onabort.call(this);
725
+ var listeners = this.__listeners;
726
+ this.__listeners = [];
727
+ for (var i = 0; i < listeners.length; i++) listeners[i]();
728
+ };
729
+ WorkflowAbortSignal.prototype.addEventListener = function(type, listener) {
730
+ if (type !== "abort") return;
731
+ if (this.aborted) {
732
+ // Fire synchronously (not on a microtask) for deterministic replay —
733
+ // matches the node:vm engine's WorkflowAbortSignal.
734
+ listener();
735
+ return;
736
+ }
737
+ this.__listeners.push(listener);
738
+ };
739
+ WorkflowAbortSignal.prototype.removeEventListener = function(type, listener) {
740
+ if (type !== "abort") return;
741
+ this.__listeners = this.__listeners.filter(function(l) { return l !== listener; });
742
+ };
743
+ WorkflowAbortSignal.prototype.throwIfAborted = function() {
744
+ if (this.aborted) {
745
+ throw this.reason !== undefined && this.reason !== null
746
+ ? this.reason
747
+ : __makeAbortError();
748
+ }
749
+ };
750
+ // Expose for the serde bundle's revivers (evaluated before this bootstrap;
751
+ // they look the class up lazily at revive time).
752
+ globalThis.__WorkflowAbortSignal = WorkflowAbortSignal;
753
+
754
+ // Registry of live abort signals keyed by their hook correlationId. The
755
+ // host delivers hook_received events for these ids as _setAborted calls.
756
+ globalThis.__abortSignals = {};
757
+
758
+ globalThis.AbortController = function WorkflowAbortController() {
759
+ var id = globalThis.__generateUlid();
760
+ var streamName = "strm_" + id + "_system_abort";
761
+ var hookToken = "abrt_" + id;
762
+ this[__ABORT_STREAM_NAME] = streamName;
763
+ this[__ABORT_HOOK_TOKEN] = hookToken;
764
+ this.signal = new WorkflowAbortSignal(streamName, hookToken);
765
+ var correlationId = "hook_" + globalThis.__generateUlid();
766
+ // Register an internal system hook. isSystem prevents token namespace
767
+ // conflicts with user hooks.
768
+ globalThis.__pending.push({
769
+ type: "hook",
770
+ correlationId: correlationId,
771
+ token: hookToken,
772
+ isWebhook: false,
773
+ isSystem: true,
774
+ hasCreatedEvent: false,
775
+ });
776
+ globalThis.__abortSignals[correlationId] = this.signal;
777
+ };
778
+ globalThis.AbortController.prototype.abort = function(reason) {
779
+ if (this.signal.aborted) return; // already aborted (e.g. from replay)
780
+ this.signal._setAborted(reason);
781
+ // Mark the pending hook op so the host records the abort. The payload
782
+ // is serialized in the VM so the reason crosses the boundary with
783
+ // type fidelity (Errors, DOMException, custom values).
784
+ var token = this[__ABORT_HOOK_TOKEN];
785
+ for (var i = 0; i < globalThis.__pending.length; i++) {
786
+ var item = globalThis.__pending[i];
787
+ if (item.type === "hook" && item.token === token) {
788
+ item.abortRequested = true;
789
+ item.abortPayload = globalThis[Symbol.for("workflow-serialize")]({
790
+ aborted: true,
791
+ reason: reason,
792
+ });
793
+ break;
794
+ }
795
+ }
796
+ };
797
+
798
+ globalThis.AbortSignal = {
799
+ abort: function(reason) {
800
+ var s = new WorkflowAbortSignal("", "");
801
+ s._setAborted(reason !== undefined ? reason : __makeAbortError());
802
+ return s;
803
+ },
804
+ any: function(signals) {
805
+ var composite = new WorkflowAbortSignal("", "");
806
+ var arr = Array.from(signals);
807
+ for (var i = 0; i < arr.length; i++) {
808
+ if (arr[i].aborted) {
809
+ composite._setAborted(arr[i].reason);
810
+ return composite;
811
+ }
812
+ }
813
+ var listeners = [];
814
+ var cleanup = function() {
815
+ for (var j = 0; j < listeners.length; j++) {
816
+ if (listeners[j].signal.removeEventListener) {
817
+ listeners[j].signal.removeEventListener("abort", listeners[j].listener);
818
+ }
819
+ }
820
+ listeners.length = 0;
821
+ };
822
+ arr.forEach(function(signal) {
823
+ if (!signal.addEventListener) return;
824
+ var listener = function() {
825
+ if (!composite.aborted) {
826
+ composite._setAborted(signal.reason);
827
+ cleanup();
828
+ }
829
+ };
830
+ listeners.push({ signal: signal, listener: listener });
831
+ signal.addEventListener("abort", listener);
832
+ });
833
+ return composite;
834
+ },
835
+ timeout: function() {
836
+ throw new Error(
837
+ "AbortSignal.timeout() is not supported in workflow functions. " +
838
+ "Use sleep() with an AbortController instead. " +
839
+ "See: /docs/errors/abort-signal-timeout-in-workflow"
840
+ );
841
+ },
842
+ };
843
+
844
+ // WORKFLOW_GET_STREAM_ID — generates a stream ID for a workflow run.
845
+ // Replicates getWorkflowRunStreamId() from util.ts inside the QuickJS VM.
846
+ // Uses the built-in btoa() for base64url encoding.
847
+ globalThis[Symbol.for("WORKFLOW_GET_STREAM_ID")] = function(namespace) {
848
+ var runId = globalThis[Symbol.for("WORKFLOW_CONTEXT")]
849
+ ? globalThis[Symbol.for("WORKFLOW_CONTEXT")].workflowRunId
850
+ : "";
851
+ var streamId = runId.replace("wrun_", "strm_") + "_user";
852
+ if (!namespace) return streamId;
853
+ // base64url: btoa then replace + with -, / with _, strip =
854
+ var b64 = btoa(namespace).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");
855
+ return streamId + "_" + b64;
856
+ };
857
+ `;
858
+ // ---- Runtime ----
859
+ /**
860
+ * Phase 1 — static (run-independent) VM initialization.
861
+ *
862
+ * Creates a QuickJS VM and loads everything that does not depend on a
863
+ * specific workflow run: the serde bundle (devalue-based serialization
864
+ * used at the host/VM boundary) and the workflow-primitive bootstrap
865
+ * (useStep / sleep / createHook / Response-Request polyfills).
866
+ *
867
+ * `getNowMs` backs the VM's WASI clock (`Date.now()` / `new Date()`
868
+ * inside the VM). The callback itself is static — the per-run state it
869
+ * reads lives on the host and is advanced as events are consumed,
870
+ * matching the node:vm engine's deterministic replay clock.
871
+ *
872
+ * This phase is the future boundary for VM-memory snapshotting: a
873
+ * build-time snapshot can capture the VM right after this function and
874
+ * new runs can restore from it instead of paying VM creation + eval cost
875
+ * (`QuickJS.restore` accepts the same wasi override).
876
+ */
877
+ /**
878
+ * Loosely-typed accessor for the `WebAssembly` global. The package
879
+ * tsconfig's `lib: ["es2022"]` does not include the DOM lib where the
880
+ * `WebAssembly` namespace types live; the runtime global is available on
881
+ * every WASM-capable platform this engine targets.
882
+ */
883
+ const WebAssemblyGlobal = globalThis.WebAssembly;
884
+ /**
885
+ * Process-wide cache of the compiled `WebAssembly.Module`s for the main
886
+ * QuickJS runtime and its native extensions. `WebAssembly.compile` of the
887
+ * ~600 KB runtime binary is the most expensive part of VM creation and is
888
+ * pure (no per-VM state — instantiation binds the per-VM memory), so it
889
+ * only needs to happen once per process. The promise is cached (not the
890
+ * result) so concurrent first invocations share a single compilation.
891
+ */
892
+ let compiledAssetsPromise;
893
+ function getCompiledAssets() {
894
+ if (!compiledAssetsPromise) {
895
+ compiledAssetsPromise = (async () => {
896
+ const [wasm, ...extensionModules] = await Promise.all([
897
+ WebAssemblyGlobal.compile(quickjsWasm),
898
+ ...quickjsExtensions.map((ext) => WebAssemblyGlobal.compile(ext.wasm)),
899
+ ]);
900
+ return {
901
+ wasm,
902
+ extensions: quickjsExtensions.map((ext, i) => ({
903
+ ...ext,
904
+ wasm: extensionModules[i],
905
+ })),
906
+ };
907
+ })();
908
+ // On failure, clear the cache so a later invocation can retry rather
909
+ // than being stuck with a rejected promise forever.
910
+ compiledAssetsPromise.catch(() => {
911
+ compiledAssetsPromise = undefined;
912
+ });
913
+ }
914
+ return compiledAssetsPromise;
915
+ }
916
+ async function initWorkflowVM(getNowMs, interruptBudget) {
917
+ // Deterministic replay clock: Date.now() / new Date() inside the VM
918
+ // read the host-controlled clock instead of wall time. Replay
919
+ // re-executes the workflow from the top on every invocation, so the
920
+ // clock must be derived from the event log (not real time) for the
921
+ // workflow to observe stable timestamps across invocations.
922
+ const wasi = (memory) => ({
923
+ clock_time_get(_clockId, _precision, resultPtr) {
924
+ const timeNs = BigInt(Math.round(getNowMs())) * 1000000n;
925
+ new DataView(memory.buffer).setBigUint64(resultPtr, timeNs, true);
926
+ return 0;
927
+ },
928
+ });
929
+ const assets = await getCompiledAssets();
930
+ const vm = await QuickJS.create({
931
+ wasm: assets.wasm,
932
+ memoryLimit: 256 * 1024 * 1024,
933
+ interruptHandler: createInterruptHandler(interruptBudget),
934
+ extensions: assets.extensions,
935
+ wasi,
936
+ });
937
+ // Evaluate the VM serde bundle
938
+ vm.evalCode(VM_SERDE_BUNDLE, 'vm-serde.js').dispose();
939
+ // Bootstrap workflow primitives
940
+ vm.evalCode(VM_BOOTSTRAP, 'bootstrap.js').dispose();
941
+ return vm;
942
+ }
943
+ /**
944
+ * Run a workflow invocation to its first settled state and dispose the
945
+ * VM. Convenience wrapper over {@link startQuickJSWorkflow} for callers
946
+ * (and tests) that don't use live-VM continuation.
947
+ */
948
+ export async function runQuickJSWorkflow(options) {
949
+ const session = await startQuickJSWorkflow(options);
950
+ session.dispose();
951
+ return session.result;
952
+ }
953
+ export async function startQuickJSWorkflow(options) {
954
+ const { workflowCode, workflowId, workflowRun, events } = options;
955
+ const startedAt = workflowRun.startedAt ? +workflowRun.startedAt : Date.now();
956
+ // Deterministic PRNG seed — identical for EVERY invocation of the same
957
+ // run. Full event replay requires this: each invocation re-executes the
958
+ // workflow from the top and must regenerate the exact same correlationId
959
+ // sequence so that pending operations re-created by replay match the
960
+ // events recorded by earlier invocations. Sequential operations within
961
+ // one execution still get distinct ids because the PRNG advances as the
962
+ // workflow draws from it. Identical seeding across CONCURRENT invocations
963
+ // of the same run is also load-bearing: both produce the same ids, and
964
+ // the world's per-(runId, correlationId) uniqueness turns the duplicate
965
+ // `events.create` into an EntityConflictError that the entrypoint
966
+ // swallows.
967
+ //
968
+ // The seed inputs MUST be stable across invocations. Notably
969
+ // `startedAt` is NOT: under turbo the first invocation runs against a
970
+ // synthesized run object whose timestamps differ from the durably
971
+ // stored ones that later invocations load. Matches the node:vm
972
+ // engine's seed (workflow.ts).
973
+ const seed = [
974
+ workflowRun.runId,
975
+ workflowRun.workflowName,
976
+ workflowRun.deploymentId,
977
+ ].join(':');
978
+ const rng = seedrandom(seed);
979
+ // Seeded nanoid generator — uses the same nanoid package and seeded PRNG
980
+ // as the node:vm engine for consistent token generation.
981
+ const generateNanoid = nanoid.customRandom(nanoid.urlAlphabet, 21, (size) => new Uint8Array(size).map(() => 256 * rng()));
982
+ // Deterministic replay clock, mirroring the node:vm engine (see
983
+ // workflow.ts): the initial value is the run's creation time recovered
984
+ // from the ULID embedded in `runId` (falling back to `createdAt`), and
985
+ // it advances to each processed event's `createdAt` as the event log is
986
+ // replayed. Monotonic (Math.max) so the outer processEvents re-scan
987
+ // loop can't move the clock backwards mid-execution.
988
+ let vmNowMs = runIdCreatedAt(workflowRun.runId) ?? (+workflowRun.createdAt || startedAt);
989
+ const advanceClock = (ms) => {
990
+ if (Number.isFinite(ms))
991
+ vmNowMs = Math.max(vmNowMs, ms);
992
+ };
993
+ // ---- Phase 1: static initialization ----
994
+ const interruptBudget = { start: Date.now() };
995
+ const vm = await initWorkflowVM(() => vmNowMs, interruptBudget);
996
+ // Any throw between here and the terminal paths (which dispose the VM
997
+ // inside checkWorkflowState / extractError before RETURNING) would leak
998
+ // a live QuickJS instance and its WASM linear memory for the lifetime
999
+ // of the compute instance — which is reused. Dispose on the way out of
1000
+ // an exceptional exit and rethrow.
1001
+ try {
1002
+ return await runWorkflowInVM();
1003
+ }
1004
+ catch (err) {
1005
+ try {
1006
+ vm.dispose();
1007
+ }
1008
+ catch {
1009
+ // Already disposed by a terminal path — ignore.
1010
+ }
1011
+ throw err;
1012
+ }
1013
+ // ---- Phase 2: per-run initialization ----
1014
+ async function runWorkflowInVM() {
1015
+ vm.evalCode(`globalThis.__worldCapabilities = ${JSON.stringify(options.worldCapabilities)};`).dispose();
1016
+ // Seeded Math.random
1017
+ {
1018
+ const env_1 = { stack: [], error: void 0, hasError: false };
1019
+ try {
1020
+ const randomFn = __addDisposableResource(env_1, vm.newFunction('random', () => vm.newNumber(rng())), false);
1021
+ const math = __addDisposableResource(env_1, vm.global.getProp('Math'), false);
1022
+ math.setProp('random', randomFn);
1023
+ }
1024
+ catch (e_1) {
1025
+ env_1.error = e_1;
1026
+ env_1.hasError = true;
1027
+ }
1028
+ finally {
1029
+ __disposeResources(env_1);
1030
+ }
1031
+ }
1032
+ // Seeded nanoid generator
1033
+ {
1034
+ const env_2 = { stack: [], error: void 0, hasError: false };
1035
+ try {
1036
+ const nanoidFn = __addDisposableResource(env_2, vm.newFunction('__generateNanoid', () => vm.newString(generateNanoid())), false);
1037
+ vm.setProp(vm.global, '__generateNanoid', nanoidFn);
1038
+ }
1039
+ catch (e_2) {
1040
+ env_2.error = e_2;
1041
+ env_2.hasError = true;
1042
+ }
1043
+ finally {
1044
+ __disposeResources(env_2);
1045
+ }
1046
+ }
1047
+ // Inject a deterministic timestamp for the VM's ULID factory. ULIDs
1048
+ // produced inside the VM use this as their time prefix instead of
1049
+ // Date.now(), so two concurrent workflow invocations of the same run
1050
+ // produce IDENTICAL correlationIds (the random portion also matches
1051
+ // because the PRNG is seeded the same way) and the world's
1052
+ // EntityConflictError on `events.create` dedups one of each pair.
1053
+ // Derived from the runId's embedded ULID (stable across invocations by
1054
+ // construction — unlike `startedAt`, which differs between turbo's
1055
+ // synthesized run object and the durably stored run).
1056
+ vm.evalCode(`globalThis.__ulidTimestamp = ${runIdCreatedAt(workflowRun.runId) ?? (+workflowRun.createdAt || startedAt)};`).dispose();
1057
+ // `process.env` — parity with the node:vm engine, which exposes a frozen
1058
+ // copy of the host env (vm/index.ts). Injected per run so the snapshot of
1059
+ // the env is taken at invocation time, same as node.
1060
+ {
1061
+ const envHandle = vm.newString(JSON.stringify(process.env));
1062
+ vm.setProp(vm.global, '__wdk_env', envHandle);
1063
+ envHandle.dispose();
1064
+ vm.evalCode('globalThis.process = { env: Object.freeze(JSON.parse(globalThis.__wdk_env)) };' +
1065
+ 'delete globalThis.__wdk_env;').dispose();
1066
+ }
1067
+ // Execute the workflow bundle — use the workflowId as the eval filename
1068
+ // so QuickJS stack traces reference the workflow name, enabling source map
1069
+ // remapping by remapErrorStack (which matches frames by filename).
1070
+ // Evaluated in the per-run phase (after Math.random seeding) so that
1071
+ // module-scope user code draws from the seeded PRNG, matching the
1072
+ // node:vm engine's replay determinism.
1073
+ try {
1074
+ vm.evalCode(workflowCode, workflowId || 'workflow.js').dispose();
1075
+ }
1076
+ catch (err) {
1077
+ return makeSettledSession(extractError(vm, err, 'Workflow evaluation failed'));
1078
+ }
1079
+ // Extract workflow arguments. Prefer the run_created event; fall back
1080
+ // to the queue message's runInput if the event log is incomplete
1081
+ // (eventually-consistent read after start()). Failing to find input
1082
+ // for a first invocation is fatal — running the workflow function
1083
+ // with no args would silently turn typed arguments into `undefined`
1084
+ // and, for recursive workflows, produce exponential fan-out.
1085
+ const runCreatedEvent = events.find((e) => e.eventType === 'run_created');
1086
+ const runCreatedInput = runCreatedEvent && 'eventData' in runCreatedEvent
1087
+ ? runCreatedEvent.eventData?.input
1088
+ : undefined;
1089
+ const runInput = runCreatedInput ?? options.runInput?.input;
1090
+ if (runInput instanceof Uint8Array) {
1091
+ const decryptedInput = await prepareBytesForVM(runInput, options.encryptionKey);
1092
+ runtimeLogger.debug('QuickJS runtime: run input format', {
1093
+ prefix: new TextDecoder().decode(decryptedInput.subarray(0, 4)),
1094
+ byteLength: decryptedInput.byteLength,
1095
+ source: runCreatedInput ? 'run_created' : 'queueMessage.runInput',
1096
+ });
1097
+ const inputHandle = vm.newUint8Array(decryptedInput);
1098
+ vm.setProp(vm.global, '__wdk_input', inputHandle);
1099
+ inputHandle.dispose();
1100
+ }
1101
+ else if (runInput === undefined && events.length > 0) {
1102
+ // The event log is non-empty (we got run_started or similar) but
1103
+ // no run_created event was found and no queue-provided runInput is
1104
+ // available. This is the race condition observed during the fib
1105
+ // incident — silently dropping arguments would turn `n` into
1106
+ // `undefined` and, for recursive workflows, cause exponential
1107
+ // fan-out. Fail loud: the throw escapes the entrypoint into the
1108
+ // replay loop's catch in runtime.ts (the QuickJS dispatch runs
1109
+ // inside that loop's try), which records run_failed. A visible
1110
+ // terminal failure is
1111
+ // preferred over silently executing with undefined arguments — the
1112
+ // queue-provided runInput fallback above makes this path rare.
1113
+ // Empty `events` is allowed because tests that bootstrap a workflow
1114
+ // with no arguments rely on the old permissive behavior.
1115
+ throw new Error(`Cannot start workflow run "${workflowRun.runId}": no run_created event found and no runInput in the queue payload, but other events are present (likely a read-after-write race during start()).`);
1116
+ }
1117
+ // Set workflow context metadata (for getWorkflowMetadata()).
1118
+ // Must match the shape that the node:vm engine produces (see
1119
+ // packages/core/src/workflow.ts: runWorkflow → ctx) so user code
1120
+ // that compares `getWorkflowMetadata()` values between a step
1121
+ // (server-side) and the workflow (VM-side) sees identical objects.
1122
+ {
1123
+ const metadata = {
1124
+ workflowName: workflowRun.workflowName,
1125
+ workflowRunId: workflowRun.runId,
1126
+ workflowStartedAt: workflowRun.startedAt
1127
+ ? new Date(+workflowRun.startedAt)
1128
+ : new Date(),
1129
+ url: process.env.VERCEL_URL
1130
+ ? `https://${process.env.VERCEL_URL}`
1131
+ : `http://localhost:${options.port ?? 3000}`,
1132
+ features: { encryption: !!options.encryptionKey },
1133
+ };
1134
+ vm.evalCode(`globalThis[Symbol.for("WORKFLOW_CONTEXT")] = ${JSON.stringify(metadata)};` +
1135
+ `globalThis[Symbol.for("WORKFLOW_CONTEXT")].workflowStartedAt = new Date(${JSON.stringify(metadata.workflowStartedAt.toISOString())});`).dispose();
1136
+ }
1137
+ // Start the workflow function. If the workflow isn't registered,
1138
+ // throw an error tagged with `name = "WorkflowNotRegisteredError"`
1139
+ // so the host-side entrypoint can reconstruct a real
1140
+ // WorkflowNotRegisteredError (a WorkflowRuntimeError subclass that
1141
+ // classifies as RUNTIME_ERROR) rather than a generic user error.
1142
+ // See quickjs-entrypoint.ts's run_failed branch.
1143
+ try {
1144
+ vm.evalCode(`
1145
+ var __wfn = globalThis.__private_workflows.get(${JSON.stringify(workflowId)});
1146
+ if (!__wfn) {
1147
+ var __wfnErr = new Error("Workflow \\"" + ${JSON.stringify(workflowId)} + "\\" is not registered in the current deployment.");
1148
+ __wfnErr.name = "WorkflowNotRegisteredError";
1149
+ throw __wfnErr;
1150
+ }
1151
+ var __args = globalThis.__wdk_input
1152
+ ? globalThis[Symbol.for("workflow-deserialize")](globalThis.__wdk_input)
1153
+ : [];
1154
+ delete globalThis.__wdk_input;
1155
+ if (!Array.isArray(__args)) __args = [__args];
1156
+ __wfn.apply(null, __args).then(
1157
+ function(result) { globalThis.__workflowResult = globalThis[Symbol.for("workflow-serialize")](result); },
1158
+ function(error) {
1159
+ // Preserve display info on the host-side failed object
1160
+ // (matches the legacy host-visible shape) AND serialize the
1161
+ // entire thrown value so the host can dehydrate the original
1162
+ // type-identity, cause chain, or non-Error throws verbatim
1163
+ // through the standard error pipeline.
1164
+ globalThis.__workflowError = {
1165
+ message: error && error.message != null ? String(error.message) : String(error),
1166
+ stack: error && error.stack ? error.stack : "",
1167
+ name: error && error.name ? error.name : (error instanceof Error ? "Error" : typeof error),
1168
+ valueBytes: globalThis[Symbol.for("workflow-serialize")](error),
1169
+ };
1170
+ }
1171
+ );
1172
+ `).dispose();
1173
+ }
1174
+ catch (err) {
1175
+ return makeSettledSession(extractError(vm, err, 'Failed to start workflow'));
1176
+ }
1177
+ // Process events and drain jobs in a loop. Events may resolve promises
1178
+ // that unblock workflow code, which then creates NEW resolvers for
1179
+ // subsequent events. Re-processing events matches these new resolvers
1180
+ // against events that were already delivered.
1181
+ {
1182
+ let maxIterations = 100;
1183
+ let madeProgress;
1184
+ do {
1185
+ madeProgress = await processEvents(vm, events, advanceClock, options.encryptionKey);
1186
+ let batch;
1187
+ do {
1188
+ batch = vm.executePendingJobs();
1189
+ if (batch > 0)
1190
+ madeProgress = true;
1191
+ } while (batch > 0);
1192
+ } while (madeProgress && --maxIterations > 0);
1193
+ if (madeProgress && maxIterations === 0) {
1194
+ // The drain loop hit its bound while still making progress —
1195
+ // proceeding as if it converged would present as a mysterious
1196
+ // suspension or replay divergence. Make the giving-up visible so
1197
+ // a wedge is attributable to this bound rather than a mystery.
1198
+ runtimeLogger.warn('QuickJS runtime: event drain loop hit its iteration bound before reaching a fixed point', {
1199
+ workflowRunId: workflowRun.runId,
1200
+ eventCount: events.length,
1201
+ });
1202
+ }
1203
+ }
1204
+ // ---- Check result ----
1205
+ return makeLiveSession(vm, interruptBudget, advanceClock, options.encryptionKey);
1206
+ }
1207
+ }
1208
+ /** Session wrapper for a result whose VM is already settled/disposed. */
1209
+ function makeSettledSession(result) {
1210
+ return {
1211
+ result,
1212
+ continueWithEvents: () => {
1213
+ throw new Error('QuickJS workflow session is settled — continueWithEvents is only valid while suspended');
1214
+ },
1215
+ dispose: () => { },
1216
+ };
1217
+ }
1218
+ /**
1219
+ * Evaluate the VM's state and wrap it in a live session. While suspended,
1220
+ * the VM stays alive so `continueWithEvents` can resume it in place;
1221
+ * terminal states dispose the VM immediately (inside checkWorkflowState).
1222
+ */
1223
+ function makeLiveSession(vm, interruptBudget, advanceClock, encryptionKey) {
1224
+ const result = checkWorkflowState(vm, { keepAliveOnSuspend: true });
1225
+ let alive = !!result.suspended;
1226
+ const session = {
1227
+ result,
1228
+ async continueWithEvents(newEvents) {
1229
+ if (!alive) {
1230
+ throw new Error('QuickJS workflow session is not alive — continueWithEvents is only valid while suspended');
1231
+ }
1232
+ // Fresh execution burst — the interrupt budget bounds VM compute,
1233
+ // not wall time spent waiting on inline steps between bursts.
1234
+ interruptBudget.start = Date.now();
1235
+ let maxIterations = 100;
1236
+ let madeProgress;
1237
+ do {
1238
+ madeProgress = await processEvents(vm, newEvents, advanceClock, encryptionKey);
1239
+ let batch;
1240
+ do {
1241
+ batch = vm.executePendingJobs();
1242
+ if (batch > 0)
1243
+ madeProgress = true;
1244
+ } while (batch > 0);
1245
+ } while (madeProgress && --maxIterations > 0);
1246
+ const next = checkWorkflowState(vm, { keepAliveOnSuspend: true });
1247
+ if (!next.suspended)
1248
+ alive = false;
1249
+ session.result = next;
1250
+ return next;
1251
+ },
1252
+ dispose() {
1253
+ if (alive) {
1254
+ alive = false;
1255
+ try {
1256
+ vm.dispose();
1257
+ }
1258
+ catch {
1259
+ // Already disposed — ignore.
1260
+ }
1261
+ }
1262
+ },
1263
+ };
1264
+ return session;
1265
+ }
1266
+ // ---- Event Processing ----
1267
+ async function processEvents(vm, events, advanceClock, encryptionKey) {
1268
+ let resolved = false;
1269
+ for (const event of events) {
1270
+ // Advance the VM's deterministic clock to this event's creation time
1271
+ // BEFORE resolving anything, so workflow code unblocked by this event
1272
+ // observes Date.now() at (or after — the clock is monotonic) the time
1273
+ // the event was recorded. Mirrors the node:vm engine's
1274
+ // `onConsumedEvent → updateTimestamp(+event.createdAt)`.
1275
+ advanceClock(+event.createdAt);
1276
+ const cid = event.correlationId;
1277
+ if (!cid)
1278
+ continue;
1279
+ // JSON.stringify handles quotes, backslashes and control characters;
1280
+ // correlation ids are host-generated ULIDs today, but the eval-string
1281
+ // safety shouldn't depend on that invariant being asserted nowhere.
1282
+ const cidJs = JSON.stringify(cid);
1283
+ const eventData = 'eventData' in event
1284
+ ? event.eventData
1285
+ : undefined;
1286
+ // Log the event and whether the resolver exists
1287
+ switch (event.eventType) {
1288
+ case 'step_completed': {
1289
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1290
+ const rawOutput = eventData?.result ?? eventData?.output;
1291
+ if (hasResolver) {
1292
+ if (rawOutput instanceof Uint8Array) {
1293
+ // Decrypt if encrypted — the VM only understands 'devl' format
1294
+ runtimeLogger.debug('QuickJS runtime: step result raw', {
1295
+ correlationId: cid,
1296
+ rawPrefix: new TextDecoder().decode(rawOutput.subarray(0, 4)),
1297
+ rawByteLength: rawOutput.byteLength,
1298
+ isBuffer: Buffer.isBuffer(rawOutput),
1299
+ });
1300
+ const decryptedOutput = await prepareBytesForVM(rawOutput, encryptionKey);
1301
+ runtimeLogger.debug('QuickJS runtime: step result decrypted', {
1302
+ correlationId: cid,
1303
+ prefix: new TextDecoder().decode(decryptedOutput.subarray(0, 4)),
1304
+ byteLength: decryptedOutput.byteLength,
1305
+ });
1306
+ const bytesHandle = vm.newUint8Array(decryptedOutput);
1307
+ vm.setProp(vm.global, '__tmp_result', bytesHandle);
1308
+ bytesHandle.dispose();
1309
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(globalThis[Symbol.for("workflow-deserialize")](globalThis.__tmp_result));` +
1310
+ `delete globalThis.__resolvers[${cidJs}];` +
1311
+ `delete globalThis.__tmp_result;`).dispose();
1312
+ }
1313
+ else {
1314
+ runtimeLogger.debug('QuickJS runtime: step result non-binary', {
1315
+ correlationId: cid,
1316
+ type: typeof rawOutput,
1317
+ isNull: rawOutput === null,
1318
+ isUndefined: rawOutput === undefined,
1319
+ constructor: rawOutput?.constructor?.name,
1320
+ });
1321
+ const serialized = rawOutput !== undefined ? JSON.stringify(rawOutput) : 'undefined';
1322
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(${serialized});` +
1323
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1324
+ }
1325
+ // Drain ALL microtasks after resolve
1326
+ {
1327
+ resolved = true;
1328
+ let b;
1329
+ do {
1330
+ b = vm.executePendingJobs();
1331
+ } while (b > 0);
1332
+ }
1333
+ }
1334
+ else {
1335
+ // No resolver yet — buffer the prepared outcome so the promise
1336
+ // settles the moment the VM constructs it (see __terminalBuffer
1337
+ // in the bootstrap). Without this, the live-continuation path
1338
+ // (which scans each delta exactly once) drops the terminal and
1339
+ // the await never settles.
1340
+ if (rawOutput instanceof Uint8Array) {
1341
+ const decryptedOutput = await prepareBytesForVM(rawOutput, encryptionKey);
1342
+ const bytesHandle = vm.newUint8Array(decryptedOutput);
1343
+ vm.setProp(vm.global, '__tmp_buf', bytesHandle);
1344
+ bytesHandle.dispose();
1345
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_bytes", bytes: globalThis.__tmp_buf };` +
1346
+ `delete globalThis.__tmp_buf;`).dispose();
1347
+ }
1348
+ else {
1349
+ const serialized = rawOutput !== undefined ? JSON.stringify(rawOutput) : 'undefined';
1350
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_value", value: ${serialized} };`).dispose();
1351
+ }
1352
+ }
1353
+ markCreated(vm, cidJs);
1354
+ break;
1355
+ }
1356
+ case 'step_failed': {
1357
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1358
+ if (hasResolver) {
1359
+ const errorData = eventData?.error;
1360
+ if (errorData instanceof Uint8Array) {
1361
+ // Modern path (post-#1851): the step handler dehydrated the
1362
+ // thrown value through the first-class error pipeline. Decrypt
1363
+ // (if encrypted) and pass the bytes to the VM-side deserializer
1364
+ // so the workflow catch sees a properly typed Error subclass
1365
+ // (TypeError, FatalError with original cause chain, etc.) with
1366
+ // the original message and stack preserved.
1367
+ const decrypted = await prepareBytesForVM(errorData, encryptionKey);
1368
+ const bytesHandle = vm.newUint8Array(decrypted);
1369
+ vm.setProp(vm.global, '__tmp_error', bytesHandle);
1370
+ bytesHandle.dispose();
1371
+ vm.evalCode(`(function(){` +
1372
+ `var e=globalThis[Symbol.for("workflow-deserialize")](globalThis.__tmp_error);` +
1373
+ `globalThis.__resolvers[${cidJs}].reject(e);` +
1374
+ `delete globalThis.__resolvers[${cidJs}];` +
1375
+ `delete globalThis.__tmp_error;` +
1376
+ `})()`).dispose();
1377
+ }
1378
+ else {
1379
+ // Legacy path: pre-pipeline events stored error as
1380
+ // `{ message, stack, code }`. Reconstruct a FatalError so
1381
+ // workflow catch can detect it via FatalError.is(), matching
1382
+ // the original V1 step handler behavior.
1383
+ const isErrorObject = typeof errorData === 'object' && errorData !== null;
1384
+ const msg = isErrorObject
1385
+ ? (errorData.message ??
1386
+ 'Step failed')
1387
+ : typeof errorData === 'string'
1388
+ ? errorData
1389
+ : 'Step failed';
1390
+ const errorStack = (isErrorObject
1391
+ ? errorData.stack
1392
+ : undefined) ?? eventData?.stack;
1393
+ const stackAssignment = errorStack
1394
+ ? `e.stack=${JSON.stringify(errorStack)};`
1395
+ : '';
1396
+ vm.evalCode(`(function(){var e=new Error(${JSON.stringify(msg)});e.name="FatalError";e.fatal=true;${stackAssignment}` +
1397
+ `globalThis.__resolvers[${cidJs}].reject(e);` +
1398
+ `delete globalThis.__resolvers[${cidJs}];})()`).dispose();
1399
+ }
1400
+ {
1401
+ resolved = true;
1402
+ let b;
1403
+ do {
1404
+ b = vm.executePendingJobs();
1405
+ } while (b > 0);
1406
+ }
1407
+ }
1408
+ else {
1409
+ // No resolver yet — buffer the prepared rejection (see the
1410
+ // step_completed branch above for the rationale).
1411
+ const errorData = eventData?.error;
1412
+ if (errorData instanceof Uint8Array) {
1413
+ const decrypted = await prepareBytesForVM(errorData, encryptionKey);
1414
+ const bytesHandle = vm.newUint8Array(decrypted);
1415
+ vm.setProp(vm.global, '__tmp_buf', bytesHandle);
1416
+ bytesHandle.dispose();
1417
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "reject_bytes", bytes: globalThis.__tmp_buf };` +
1418
+ `delete globalThis.__tmp_buf;`).dispose();
1419
+ }
1420
+ else {
1421
+ const isErrorObject = typeof errorData === 'object' && errorData !== null;
1422
+ const msg = isErrorObject
1423
+ ? (errorData.message ??
1424
+ 'Step failed')
1425
+ : typeof errorData === 'string'
1426
+ ? errorData
1427
+ : 'Step failed';
1428
+ const errorStack = (isErrorObject
1429
+ ? errorData.stack
1430
+ : undefined) ?? eventData?.stack;
1431
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "reject_error", message: ${JSON.stringify(msg)}, stack: ${errorStack ? JSON.stringify(errorStack) : 'undefined'} };`).dispose();
1432
+ }
1433
+ }
1434
+ markCreated(vm, cidJs);
1435
+ break;
1436
+ }
1437
+ case 'wait_completed': {
1438
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1439
+ if (hasResolver) {
1440
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve();` +
1441
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1442
+ {
1443
+ resolved = true;
1444
+ let b;
1445
+ do {
1446
+ b = vm.executePendingJobs();
1447
+ } while (b > 0);
1448
+ }
1449
+ }
1450
+ else {
1451
+ // No resolver yet — buffer (see step_completed above).
1452
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_undefined" };`).dispose();
1453
+ }
1454
+ markCreated(vm, cidJs);
1455
+ break;
1456
+ }
1457
+ case 'attr_set': {
1458
+ // Only workflow-written attribute events resolve a pending
1459
+ // setAttributes() promise; step/system writers share no
1460
+ // correlationIds with VM resolvers, so the guard is defensive.
1461
+ const writer = eventData?.writer
1462
+ ?.type;
1463
+ if (writer !== 'workflow')
1464
+ break;
1465
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1466
+ if (!hasResolver) {
1467
+ // No resolver yet — buffer (see step_completed above).
1468
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_undefined" };`).dispose();
1469
+ }
1470
+ if (hasResolver) {
1471
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve();` +
1472
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1473
+ {
1474
+ resolved = true;
1475
+ let b;
1476
+ do {
1477
+ b = vm.executePendingJobs();
1478
+ } while (b > 0);
1479
+ }
1480
+ }
1481
+ markCreated(vm, cidJs);
1482
+ break;
1483
+ }
1484
+ case 'hook_received': {
1485
+ // Check if this event was already processed (delivered or
1486
+ // buffered) within this invocation. Prevents double-delivery when
1487
+ // the outer loop re-scans events.
1488
+ const alreadyProcessed = event.eventId
1489
+ ? vm.dump(vm.evalCode(`!!(globalThis.__hookPayloadBuffer.__processedEventIds && globalThis.__hookPayloadBuffer.__processedEventIds[${JSON.stringify(event.eventId)}])`))
1490
+ : false;
1491
+ if (alreadyProcessed) {
1492
+ runtimeLogger.debug('QuickJS runtime: hook_received already processed', {
1493
+ correlationId: cid,
1494
+ eventId: event.eventId,
1495
+ });
1496
+ markCreated(vm, cidJs);
1497
+ break;
1498
+ }
1499
+ // Resilient-resume dedup (parity with the node engine's
1500
+ // EventsConsumer in workflow/hook.ts): two hook_received rows for
1501
+ // ONE resume attempt share a client-minted `resumeId` (a duplicate
1502
+ // can be committed when the materialization fallback races a
1503
+ // delayed direct write — hook_received has no storage uniqueness
1504
+ // constraint). Deliver only the first-in-log occurrence. The seen
1505
+ // set lives in the VM heap so it is deterministic per replay and
1506
+ // survives event re-scans within the invocation. Events without a
1507
+ // resumeId (older SDKs) are never deduped.
1508
+ {
1509
+ // Top-level event.resumeId is the canonical location (the backend
1510
+ // hoists it to a first-class column); the nested
1511
+ // eventData.resumeId form is a deprecated legacy fallback —
1512
+ // mirrors the node engine's dedup in workflow/hook.ts.
1513
+ const resumeId = event.resumeId ??
1514
+ eventData?.resumeId;
1515
+ if (typeof resumeId === 'string') {
1516
+ const resumeIdJs = JSON.stringify(resumeId);
1517
+ const duplicate = vm.dump(vm.evalCode(`(globalThis.__hookSeenResumeIds = globalThis.__hookSeenResumeIds || {})[${resumeIdJs}] === true`));
1518
+ if (duplicate) {
1519
+ runtimeLogger.debug('QuickJS runtime: duplicate hook_received for the same resume attempt, dropping', { correlationId: cid, eventId: event.eventId, resumeId });
1520
+ if (event.eventId) {
1521
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1522
+ }
1523
+ markCreated(vm, cidJs);
1524
+ break;
1525
+ }
1526
+ vm.evalCode(`globalThis.__hookSeenResumeIds[${resumeIdJs}] = true;`).dispose();
1527
+ }
1528
+ }
1529
+ // Abort delivery: hook_received for an AbortController's system
1530
+ // hook flips the registered signal instead of resolving a promise.
1531
+ // The payload is the dehydrated `{ aborted: true, reason }` object.
1532
+ const isAbortHook = vm.dump(vm.evalCode(`!!(globalThis.__abortSignals && globalThis.__abortSignals[${cidJs}])`));
1533
+ if (isAbortHook) {
1534
+ const rawAbortPayload = eventData?.payload;
1535
+ if (rawAbortPayload instanceof Uint8Array) {
1536
+ const decrypted = await prepareBytesForVM(rawAbortPayload, encryptionKey);
1537
+ const bytesHandle = vm.newUint8Array(decrypted);
1538
+ vm.setProp(vm.global, '__tmp_abort', bytesHandle);
1539
+ bytesHandle.dispose();
1540
+ vm.evalCode(`(function(){` +
1541
+ `var p=globalThis[Symbol.for("workflow-deserialize")](globalThis.__tmp_abort);` +
1542
+ `delete globalThis.__tmp_abort;` +
1543
+ `globalThis.__abortSignals[${cidJs}]._setAborted(p&&typeof p==="object"?p.reason:undefined);` +
1544
+ `})()`).dispose();
1545
+ }
1546
+ else {
1547
+ vm.evalCode(`globalThis.__abortSignals[${cidJs}]._setAborted(undefined);`).dispose();
1548
+ }
1549
+ // The abort is durably recorded — clear the pending op's
1550
+ // abortRequested marker so the host doesn't re-record it (the
1551
+ // workflow's own abort() call can set the flag before this
1552
+ // event is processed when it happens later in replay order,
1553
+ // and hook_received events are not unique per correlationId).
1554
+ vm.evalCode(`(function(){` +
1555
+ `var p=globalThis.__pending.find(function(q){return q.correlationId===${JSON.stringify(cid)}&&q.type==="hook";});` +
1556
+ `if(p)p.abortRequested=false;` +
1557
+ `})()`).dispose();
1558
+ if (event.eventId) {
1559
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1560
+ }
1561
+ {
1562
+ resolved = true;
1563
+ let b;
1564
+ do {
1565
+ b = vm.executePendingJobs();
1566
+ } while (b > 0);
1567
+ }
1568
+ markCreated(vm, cidJs);
1569
+ break;
1570
+ }
1571
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1572
+ const rawPayload = eventData?.payload ?? eventData?.result;
1573
+ runtimeLogger.debug('QuickJS runtime: processing hook_received', {
1574
+ correlationId: cid,
1575
+ eventId: event.eventId,
1576
+ hasResolver,
1577
+ payloadType: typeof rawPayload,
1578
+ payloadIsUint8Array: rawPayload instanceof Uint8Array,
1579
+ payloadKeys: rawPayload && typeof rawPayload === 'object'
1580
+ ? Object.keys(rawPayload)
1581
+ : undefined,
1582
+ });
1583
+ if (hasResolver) {
1584
+ if (rawPayload instanceof Uint8Array) {
1585
+ // Decrypt if encrypted — the VM only understands 'devl' format
1586
+ const decryptedPayload = await prepareBytesForVM(rawPayload, encryptionKey);
1587
+ const bytesHandle = vm.newUint8Array(decryptedPayload);
1588
+ vm.setProp(vm.global, '__tmp_result', bytesHandle);
1589
+ bytesHandle.dispose();
1590
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(globalThis[Symbol.for("workflow-deserialize")](globalThis.__tmp_result));` +
1591
+ `delete globalThis.__resolvers[${cidJs}];` +
1592
+ `delete globalThis.__tmp_result;`).dispose();
1593
+ }
1594
+ else {
1595
+ const serialized = rawPayload !== undefined
1596
+ ? JSON.stringify(rawPayload)
1597
+ : 'undefined';
1598
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(${serialized});` +
1599
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1600
+ }
1601
+ // Mark this event as processed in the VM heap to prevent
1602
+ // double-delivery when the outer loop re-scans events.
1603
+ if (event.eventId) {
1604
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1605
+ }
1606
+ {
1607
+ resolved = true;
1608
+ let b;
1609
+ do {
1610
+ b = vm.executePendingJobs();
1611
+ } while (b > 0);
1612
+ }
1613
+ }
1614
+ else {
1615
+ // No resolver yet — buffer the payload in the VM heap. When
1616
+ // createHookPromise() is called later, it will drain this buffer
1617
+ // first (matching the node:vm engine's payloadsQueue behavior).
1618
+ const eventIdJs = event.eventId
1619
+ ? JSON.stringify(event.eventId)
1620
+ : 'null';
1621
+ const bufferAndTrack = `(globalThis.__hookPayloadBuffer[${cidJs}] = globalThis.__hookPayloadBuffer[${cidJs}] || [])` +
1622
+ `.push(%PAYLOAD%);` +
1623
+ (event.eventId
1624
+ ? `(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${eventIdJs}] = true;`
1625
+ : '');
1626
+ if (rawPayload instanceof Uint8Array) {
1627
+ // Decrypt if encrypted — the VM only understands 'devl' format
1628
+ const decryptedPayload = await prepareBytesForVM(rawPayload, encryptionKey);
1629
+ const bytesHandle = vm.newUint8Array(decryptedPayload);
1630
+ vm.setProp(vm.global, '__tmp_result', bytesHandle);
1631
+ bytesHandle.dispose();
1632
+ // NOTE: replacement is a function so `$`-sequences in the
1633
+ // substituted JS never get interpreted as String.replace
1634
+ // special replacement patterns.
1635
+ vm.evalCode(bufferAndTrack.replace('%PAYLOAD%', () => 'globalThis[Symbol.for("workflow-deserialize")](globalThis.__tmp_result)') + 'delete globalThis.__tmp_result;').dispose();
1636
+ }
1637
+ else {
1638
+ const serialized = rawPayload !== undefined
1639
+ ? JSON.stringify(rawPayload)
1640
+ : 'undefined';
1641
+ // Function replacement: a JSON-serialized payload can contain
1642
+ // `$&`, `$'`, `$\``, ... which String.replace would otherwise
1643
+ // expand, silently corrupting the injected code.
1644
+ vm.evalCode(bufferAndTrack.replace('%PAYLOAD%', () => serialized)).dispose();
1645
+ }
1646
+ }
1647
+ markCreated(vm, cidJs);
1648
+ break;
1649
+ }
1650
+ case 'hook_conflict': {
1651
+ // Another workflow owns this hook token. Payload awaiters reject
1652
+ // with HookConflictError; getConflict() awaiters resolve with a
1653
+ // Run handle for the conflicting run (revived through the VM's
1654
+ // class registry so its methods are durable step proxies) or
1655
+ // reject with the error when no handle can be constructed —
1656
+ // mirroring the node:vm engine's hook.ts hook_conflict handling.
1657
+ const conflictToken = eventData?.token ?? 'unknown';
1658
+ const conflictingRunId = eventData?.conflictingRunId;
1659
+ const didSettle = vm.dump(vm.evalCode(`(function(){
1660
+ var cid = ${JSON.stringify(cid)};
1661
+ var token = ${JSON.stringify(conflictToken)};
1662
+ var conflictingRunId = ${JSON.stringify(conflictingRunId ?? null)};
1663
+ var ErrCls = globalThis[Symbol.for('@workflow/errors//HookConflictError')];
1664
+ var err;
1665
+ if (typeof ErrCls === 'function') {
1666
+ err = new ErrCls(token, conflictingRunId || undefined);
1667
+ } else {
1668
+ err = new Error('Hook token "' + token + '" is already in use by another workflow');
1669
+ err.name = 'HookConflictError';
1670
+ err.token = token;
1671
+ if (conflictingRunId) err.conflictingRunId = conflictingRunId;
1672
+ }
1673
+ var run = null;
1674
+ if (conflictingRunId) {
1675
+ var reg = globalThis[Symbol.for('workflow-class-registry')];
1676
+ var RunCls = reg && reg.get('class//workflow//Run');
1677
+ var des = RunCls && RunCls[Symbol.for('workflow-deserialize')];
1678
+ if (typeof des === 'function') {
1679
+ run = des.call(RunCls, { runId: conflictingRunId });
1680
+ }
1681
+ }
1682
+ var settled = false;
1683
+ var state = globalThis.__hooks && globalThis.__hooks[cid];
1684
+ if (state && !state.conflict) {
1685
+ state.conflict = { error: err, run: run };
1686
+ var gc = state.getConflictResolvers;
1687
+ state.getConflictResolvers = [];
1688
+ for (var i = 0; i < gc.length; i++) {
1689
+ if (run) { gc[i].resolve(run); } else { gc[i].reject(err); }
1690
+ settled = true;
1691
+ }
1692
+ }
1693
+ if (globalThis.__resolvers[cid]) {
1694
+ globalThis.__resolvers[cid].reject(err);
1695
+ delete globalThis.__resolvers[cid];
1696
+ settled = true;
1697
+ }
1698
+ return settled;
1699
+ })()`));
1700
+ if (didSettle) {
1701
+ resolved = true;
1702
+ let b;
1703
+ do {
1704
+ b = vm.executePendingJobs();
1705
+ } while (b > 0);
1706
+ }
1707
+ markCreated(vm, cidJs);
1708
+ break;
1709
+ }
1710
+ case 'step_created':
1711
+ case 'step_started':
1712
+ case 'step_retrying':
1713
+ case 'wait_created': {
1714
+ markCreated(vm, cidJs);
1715
+ break;
1716
+ }
1717
+ case 'hook_created': {
1718
+ // Confirm creation for getConflict() awaiters: resolve them with
1719
+ // null (no conflict) once the event log proves the hook exists.
1720
+ const settledGetConflict = vm.dump(vm.evalCode(`(function(){
1721
+ var state = globalThis.__hooks && globalThis.__hooks[${JSON.stringify(cid)}];
1722
+ if (!state) return false;
1723
+ state.created = true;
1724
+ var gc = state.getConflictResolvers;
1725
+ state.getConflictResolvers = [];
1726
+ for (var i = 0; i < gc.length; i++) gc[i].resolve(null);
1727
+ return gc.length > 0;
1728
+ })()`));
1729
+ if (settledGetConflict) {
1730
+ resolved = true;
1731
+ let b;
1732
+ do {
1733
+ b = vm.executePendingJobs();
1734
+ } while (b > 0);
1735
+ }
1736
+ markCreated(vm, cidJs);
1737
+ break;
1738
+ }
1739
+ case 'hook_disposed': {
1740
+ // Disambiguate from the `hook` pending op with the same
1741
+ // correlationId — we want to mark the `hook_dispose` entry.
1742
+ markCreated(vm, cidJs, 'hook_dispose');
1743
+ break;
1744
+ }
1745
+ }
1746
+ }
1747
+ return resolved;
1748
+ }
1749
+ function markCreated(vm, cidJs, opType) {
1750
+ // `cidJs` is the JSON.stringify-quoted correlation id (see processEvents).
1751
+ // `hook` and `hook_dispose` pending ops share the same correlationId,
1752
+ // so when processing `hook_disposed` events we must disambiguate by
1753
+ // type — otherwise `.find()` returns the original `hook` op and the
1754
+ // `hook_dispose` op is never marked, causing the entrypoint to keep
1755
+ // retrying a hook_disposed for an already-deleted entity.
1756
+ const predicate = opType
1757
+ ? `function(p){return p.correlationId===${cidJs}&&p.type===${JSON.stringify(opType)};}`
1758
+ : `function(p){return p.correlationId===${cidJs};}`;
1759
+ vm.evalCode(`var __p=globalThis.__pending.find(${predicate});` +
1760
+ `if(__p)__p.hasCreatedEvent=true;`).dispose();
1761
+ }
1762
+ // ---- State Checking ----
1763
+ /**
1764
+ * Collect leftover pending operations that need durable side effects when
1765
+ * the workflow reaches a terminal state. Mirrors the node:vm engine's
1766
+ * drainPendingQueueItems (workflow.ts): still-alive system hooks
1767
+ * (AbortController) without an abort in flight are implicitly disposed so
1768
+ * they don't leak hook rows; ops without created events (fire-and-forget
1769
+ * attributes/hooks/steps/waits) and pending abort recordings are surfaced
1770
+ * for the entrypoint to flush.
1771
+ */
1772
+ function collectDrainOperations(vm) {
1773
+ const env_3 = { stack: [], error: void 0, hasError: false };
1774
+ try {
1775
+ const h = __addDisposableResource(env_3, vm.evalCode(`(function(){
1776
+ var toDispose = [];
1777
+ globalThis.__pending.forEach(function(p){
1778
+ if (p.type === "hook" && p.isSystem && !p.abortRequested && !p.disposed) {
1779
+ p.disposed = true;
1780
+ // Only dispose hooks that were durably created; a hook that never
1781
+ // reached storage has nothing to clean up.
1782
+ if (p.hasCreatedEvent) {
1783
+ toDispose.push({
1784
+ type: "hook_dispose",
1785
+ correlationId: p.correlationId,
1786
+ hasCreatedEvent: false,
1787
+ });
1788
+ }
1789
+ }
1790
+ });
1791
+ toDispose.forEach(function(d){ globalThis.__pending.push(d); });
1792
+ return globalThis.__pending.filter(function(p){
1793
+ if (p.abortRequested) return true;
1794
+ if (p.hasCreatedEvent) return false;
1795
+ // Skip system hooks that were disposed before ever being created.
1796
+ if (p.type === "hook" && p.disposed) return false;
1797
+ return true;
1798
+ });
1799
+ })()`), false);
1800
+ return vm.dump(h);
1801
+ }
1802
+ catch (e_3) {
1803
+ env_3.error = e_3;
1804
+ env_3.hasError = true;
1805
+ }
1806
+ finally {
1807
+ __disposeResources(env_3);
1808
+ }
1809
+ }
1810
+ function checkWorkflowState(vm, opts = {}) {
1811
+ // Check completed — __workflowResult is a format-prefixed Uint8Array
1812
+ {
1813
+ const env_4 = { stack: [], error: void 0, hasError: false };
1814
+ try {
1815
+ const h = __addDisposableResource(env_4, vm.evalCode('globalThis.__workflowResult'), false);
1816
+ if (!h.isUndefined) {
1817
+ const resultBytes = h.toUint8Array();
1818
+ const drainOperations = collectDrainOperations(vm);
1819
+ vm.dispose();
1820
+ return {
1821
+ completed: {
1822
+ result: resultBytes,
1823
+ ...(drainOperations.length > 0 ? { drainOperations } : {}),
1824
+ },
1825
+ };
1826
+ }
1827
+ }
1828
+ catch (e_4) {
1829
+ env_4.error = e_4;
1830
+ env_4.hasError = true;
1831
+ }
1832
+ finally {
1833
+ __disposeResources(env_4);
1834
+ }
1835
+ }
1836
+ // Check failed
1837
+ {
1838
+ const env_5 = { stack: [], error: void 0, hasError: false };
1839
+ try {
1840
+ const h = __addDisposableResource(env_5, vm.evalCode('globalThis.__workflowError'), false);
1841
+ if (!h.isUndefined) {
1842
+ const errorObj = vm.dump(h);
1843
+ const failed = typeof errorObj === 'string'
1844
+ ? { message: errorObj }
1845
+ : {
1846
+ message: errorObj.message,
1847
+ stack: errorObj.stack || undefined,
1848
+ name: errorObj.name || undefined,
1849
+ valueBytes: errorObj.valueBytes,
1850
+ };
1851
+ runtimeLogger.error('QuickJS runtime: workflow failed in VM', {
1852
+ errorMessage: failed.message,
1853
+ errorName: failed.name,
1854
+ errorStack: failed.stack,
1855
+ });
1856
+ const drainOperations = collectDrainOperations(vm);
1857
+ vm.dispose();
1858
+ return {
1859
+ failed: {
1860
+ ...failed,
1861
+ ...(drainOperations.length > 0 ? { drainOperations } : {}),
1862
+ },
1863
+ };
1864
+ }
1865
+ }
1866
+ catch (e_5) {
1867
+ env_5.error = e_5;
1868
+ env_5.hasError = true;
1869
+ }
1870
+ finally {
1871
+ __disposeResources(env_5);
1872
+ }
1873
+ }
1874
+ // Check suspended — the workflow is suspended if there are active resolvers
1875
+ // OR pending operations that haven't been created yet (e.g. hooks created
1876
+ // upfront but not yet awaited)
1877
+ {
1878
+ const env_6 = { stack: [], error: void 0, hasError: false };
1879
+ try {
1880
+ const h = __addDisposableResource(env_6, vm.evalCode('Object.keys(globalThis.__resolvers).length > 0 || globalThis.__pending.some(function(p){return!p.hasCreatedEvent;})'), false);
1881
+ if (vm.dump(h)) {
1882
+ const env_7 = { stack: [], error: void 0, hasError: false };
1883
+ try {
1884
+ const pendingH = __addDisposableResource(env_7, vm.evalCode(
1885
+ // Ops with an active resolver or without a created event are
1886
+ // pending; abort-requested hooks are also surfaced (even when
1887
+ // already created and unawaited) so the host records the abort.
1888
+ `globalThis.__pending.filter(function(p){return!!globalThis.__resolvers[p.correlationId] || !p.hasCreatedEvent || p.abortRequested;})`), false);
1889
+ const pendingOps = vm.dump(pendingH);
1890
+ if (!opts.keepAliveOnSuspend)
1891
+ vm.dispose();
1892
+ return {
1893
+ suspended: {
1894
+ pendingOperations: pendingOps,
1895
+ },
1896
+ };
1897
+ }
1898
+ catch (e_6) {
1899
+ env_7.error = e_6;
1900
+ env_7.hasError = true;
1901
+ }
1902
+ finally {
1903
+ __disposeResources(env_7);
1904
+ }
1905
+ }
1906
+ }
1907
+ catch (e_7) {
1908
+ env_6.error = e_7;
1909
+ env_6.hasError = true;
1910
+ }
1911
+ finally {
1912
+ __disposeResources(env_6);
1913
+ }
1914
+ }
1915
+ vm.dispose();
1916
+ return { failed: { message: 'Workflow ended in unknown state' } };
1917
+ }
1918
+ // ---- Helpers ----
1919
+ function extractError(vm, err, fallbackMessage) {
1920
+ let message = fallbackMessage;
1921
+ let stack;
1922
+ let name;
1923
+ if (err instanceof JSException) {
1924
+ const error = vm.dump(err.handle);
1925
+ err.handle.dispose();
1926
+ message = error?.message ?? err.message ?? fallbackMessage;
1927
+ stack = error?.stack ?? err.stack;
1928
+ name = error?.name ?? err.name;
1929
+ }
1930
+ else if (err instanceof Error) {
1931
+ message = err.message ?? fallbackMessage;
1932
+ stack = err.stack;
1933
+ name = err.name;
1934
+ }
1935
+ vm.dispose();
1936
+ return {
1937
+ failed: { message, stack, name },
1938
+ };
1939
+ }
1940
+ function createInterruptHandler(budget) {
1941
+ const timeout = getReplayTimeoutMs();
1942
+ return () => Date.now() - budget.start > timeout;
1943
+ }
1944
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVpY2tqcy1ydW50aW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvcXVpY2tqcy1ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQkc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBUUgsT0FBTyxLQUFLLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDakMsT0FBTyxFQUVMLFdBQVcsRUFDWCxPQUFPLEdBRVIsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRTdELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsV0FBVyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDL0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVqRSwyQ0FBMkM7QUFFM0M7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxLQUFLLFVBQVUsaUJBQWlCLENBQzlCLElBQWdCLEVBQ2hCLEdBQW1CO0lBRW5CLE9BQU8sQ0FBQyxNQUFNLFVBQVUsQ0FBQyxNQUFNLE9BQU8sQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBZSxDQUFDO0FBQ3BFLENBQUM7QUF3SkQsOEJBQThCO0FBRTlCOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxZQUFZLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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LEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNiLE9BQU87UUFDTCxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtLQUNqQyxDQUFDO0FBQ0osQ0FBQztBQXFCRCxTQUFTLHNCQUFzQixDQUFDLE1BQXVCO0lBQ3JELE1BQU0sT0FBTyxHQUFHLGtCQUFrQixFQUFFLENBQUM7SUFDckMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsTUFBTSxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUM7QUFDbkQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUXVpY2tKUyBXQVNNIHdvcmtmbG93IFZNLlxuICpcbiAqIEFuIGFsdGVybmF0aXZlIGVuZ2luZSBmb3IgdGhlIGV2ZW50LXJlcGxheSBleGVjdXRpb24gbW9kZWw6IHRoZSB3b3JrZmxvd1xuICogY29kZSBydW5zIGluc2lkZSBhIFF1aWNrSlMgV0FTTSBWTSAodmlhIHF1aWNranMtd2FzaSkgaW5zdGVhZCBvZiBhXG4gKiBgbm9kZTp2bWAgY29udGV4dC4gRXZlcnkgaW52b2NhdGlvbiBjcmVhdGVzIGEgZnJlc2ggVk0sIHJlLWV4ZWN1dGVzIHRoZVxuICogd29ya2Zsb3cgZnVuY3Rpb24gZnJvbSB0aGUgdG9wLCBhbmQgcmVwbGF5cyB0aGUgcmVjb3JkZWQgZXZlbnQgbG9nIHRvXG4gKiByZXNvbHZlIGF3YWl0ZWQgcHJpbWl0aXZlcyDigJQgdGhlIHNhbWUgcmVwbGF5IHNlbWFudGljcyBhcyB0aGUgYG5vZGU6dm1gXG4gKiBlbmdpbmUuXG4gKlxuICogVGhlIHdvcmtmbG93IHByaW1pdGl2ZXMgKHVzZVN0ZXAsIHNsZWVwLCBjcmVhdGVIb29rKSBhcmUgaW1wbGVtZW50ZWQgYXNcbiAqIEphdmFTY3JpcHQgY29kZSBydW5uaW5nIGluc2lkZSB0aGUgUXVpY2tKUyBWTS4gVGhlIGhvc3QgY29tbXVuaWNhdGVzIHdpdGhcbiAqIHRoZSBWTSBieSBldmFsdWF0aW5nIHNtYWxsIEpTIHNuaXBwZXRzIHRvIHJlYWQgcGVuZGluZyBvcGVyYXRpb25zIGFuZFxuICogcmVzb2x2ZS9yZWplY3QgcHJvbWlzZXMuXG4gKlxuICogVGhlIFZNIGJvb3RzdHJhcCBpcyBkZWxpYmVyYXRlbHkgc3BsaXQgaW50byB0d28gcGhhc2VzOlxuICogICAxLiBTdGF0aWMgaW5pdGlhbGl6YXRpb24gKGBpbml0V29ya2Zsb3dWTWApIOKAlCBydW4taW5kZXBlbmRlbnQgc2V0dXA6XG4gKiAgICAgIFZNIGNyZWF0aW9uLCB0aGUgc2VyZGUgYnVuZGxlLCBhbmQgdGhlIHdvcmtmbG93IHByaW1pdGl2ZXMuXG4gKiAgIDIuIFBlci1ydW4gaW5pdGlhbGl6YXRpb24gKGlubGluZSBpbiBgcnVuUXVpY2tKU1dvcmtmbG93YCkg4oCUIHNlZWRlZFxuICogICAgICBQUk5HL1VMSUQgaG9zdCBmdW5jdGlvbnMsIHdvcmtmbG93IGJ1bmRsZSBldmFsdWF0aW9uLCBydW4gbWV0YWRhdGEsXG4gKiAgICAgIHdvcmtmbG93IGlucHV0LCBhbmQgc3RhcnQuXG4gKiBLZWVwaW5nIHRoZSBwaGFzZXMgc2VwYXJhdGUgaXMgZ3JvdW5kd29yayBmb3IgVk0tbWVtb3J5IHNuYXBzaG90dGluZzpcbiAqIGEgZm9sbG93LXVwIGNhbiBwZXJzaXN0L3Jlc3RvcmUgdGhlIFZNIGF0IHRoZSBwaGFzZSBib3VuZGFyeSAoZS5nLiBhXG4gKiBidWlsZC10aW1lIGluaXRpYWwgc25hcHNob3QpIHdpdGhvdXQgcmVzdHJ1Y3R1cmluZyB0aGlzIG1vZHVsZS4gTm90ZVxuICogdGhhdCBidW5kbGUgZXZhbHVhdGlvbiBjdXJyZW50bHkgc2l0cyBpbiB0aGUgcGVyLXJ1biBwaGFzZSBzbyB0aGF0XG4gKiBtb2R1bGUtc2NvcGUgdXNlciBjb2RlIG9ic2VydmVzIHRoZSBzZWVkZWQgYE1hdGgucmFuZG9tYCwgbWF0Y2hpbmcgdGhlXG4gKiBgbm9kZTp2bWAgZW5naW5lJ3MgcmVwbGF5IGRldGVybWluaXNtLlxuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgRXZlbnQsXG4gIFJ1bklucHV0LFxuICBXb3JrZmxvd1J1bixcbiAgV29ybGRDYXBhYmlsaXRpZXMsXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgKiBhcyBuYW5vaWQgZnJvbSAnbmFub2lkJztcbmltcG9ydCB7XG4gIHR5cGUgRXh0ZW5zaW9uRGVzY3JpcHRvcixcbiAgSlNFeGNlcHRpb24sXG4gIFF1aWNrSlMsXG4gIHR5cGUgV2FzaU9wdGlvbnMsXG59IGZyb20gJ3F1aWNranMtd2FzaSc7XG5pbXBvcnQgc2VlZHJhbmRvbSBmcm9tICdzZWVkcmFuZG9tJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZGVjb21wcmVzcyB9IGZyb20gJy4uL3NlcmlhbGl6YXRpb24vY29tcHJlc3Npb24uanMnO1xuaW1wb3J0IHR5cGUgeyBEZWNyeXB0aW9uS2V5IH0gZnJvbSAnLi4vc2VyaWFsaXphdGlvbi9lbmNyeXB0aW9uLmpzJztcbmltcG9ydCB7IGRlY3J5cHQgfSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHsgZ2V0UmVwbGF5VGltZW91dE1zIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgcXVpY2tqc0V4dGVuc2lvbnMsIHF1aWNranNXYXNtIH0gZnJvbSAnLi9xdWlja2pzLWFzc2V0cy5nZW5lcmF0ZWQuanMnO1xuaW1wb3J0IHsgcnVuSWRDcmVhdGVkQXQgfSBmcm9tICcuL3J1bi1pZC10aW1lLmpzJztcbmltcG9ydCB7IFZNX1NFUkRFX0JVTkRMRSB9IGZyb20gJy4vdm0tc2VyZGUtYnVuZGxlLmdlbmVyYXRlZC5qcyc7XG5cbi8vIC0tLS0gSG9zdCAtPiBWTSBwYXlsb2FkIHByZXBhcmF0aW9uIC0tLS1cblxuLyoqXG4gKiBQcmVwYXJlIHBlcnNpc3RlZCBwYXlsb2FkIGJ5dGVzIGZvciBjb25zdW1wdGlvbiBpbnNpZGUgdGhlIFZNOiBkZWNyeXB0XG4gKiAod2hlbiBhbiBlbmNyeXB0aW9uIGtleSBpcyBjb25maWd1cmVkKSBhbmQgZGVjb21wcmVzcyAoc3BlY1ZlcnNpb24gPj0gNVxuICogcGF5bG9hZHMgbWF5IGJlIGd6aXAvenN0ZC1jb21wcmVzc2VkKS4gVGhlIFZNIG9ubHkgdW5kZXJzdGFuZHMgcGxhaW5cbiAqIGZvcm1hdC1wcmVmaXhlZCAnZGV2bCcgYnl0ZXMg4oCUIGl0IGhhcyBuZWl0aGVyIHRoZSBrZXkgbWF0ZXJpYWwgbm9yIHpsaWIuXG4gKiBUaGUga2V5IGlzIHRoZSBydW4ncyBmdWxsIERlY3J5cHRpb25LZXkgY2FwYWJpbGl0eSAoc3ltbWV0cmljIEFFUyBrZXkgK1xuICogWDI1NTE5IGtleXBhaXIpIHNvIHNlYWxlZCBgZW5jcGAgaG9vayBwYXlsb2FkcyBmcm9tIGNyb3NzLWRlcGxveW1lbnRcbiAqIHJlc3VtZUhvb2soKSBjYWxscyBvcGVuIGhlcmUgdG9vLCBub3QganVzdCBzeW1tZXRyaWMgYGVuY3JgIG9uZXMuXG4gKiBCb3RoIHN0YWdlcyBhcmUgZm9ybWF0LXByZWZpeCBkaXNwYXRjaGVkLCBzbyBwbGFpbnRleHQvdW5jb21wcmVzc2VkXG4gKiBkYXRhIHBhc3NlcyB0aHJvdWdoIHVuY2hhbmdlZC4gTWlycm9ycyBgcHJlcGFyZVJlcGxheVBheWxvYWRgIGluXG4gKiBzZXJpYWxpemF0aW9uLnRzICh0aGUgbm9kZTp2bSBlbmdpbmUncyBlcXVpdmFsZW50IGhvc3Qtc2lkZSBzdGFnZSkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHByZXBhcmVCeXRlc0ZvclZNKFxuICBkYXRhOiBVaW50OEFycmF5LFxuICBrZXk/OiBEZWNyeXB0aW9uS2V5XG4pOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgcmV0dXJuIChhd2FpdCBkZWNvbXByZXNzKGF3YWl0IGRlY3J5cHQoZGF0YSwga2V5KSkpIGFzIFVpbnQ4QXJyYXk7XG59XG5cbi8vIC0tLS0gVHlwZXMgLS0tLVxuXG5leHBvcnQgaW50ZXJmYWNlIFBlbmRpbmdTdGVwIHtcbiAgdHlwZTogJ3N0ZXAnO1xuICBjb3JyZWxhdGlvbklkOiBzdHJpbmc7XG4gIHN0ZXBJZDogc3RyaW5nO1xuICAvKiogRm9ybWF0LXByZWZpeGVkIGRldmFsdWUtc2VyaWFsaXplZCBzdGVwIGlucHV0IChhcmdzICsgY2xvc3VyZVZhcnMpICovXG4gIGlucHV0OiBVaW50OEFycmF5O1xuICAvKiogV2hldGhlciBhIHN0ZXBfY3JlYXRlZCBldmVudCBhbHJlYWR5IGV4aXN0cyBmb3IgdGhpcyBzdGVwICovXG4gIGhhc0NyZWF0ZWRFdmVudDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQZW5kaW5nV2FpdCB7XG4gIHR5cGU6ICd3YWl0JztcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nO1xuICAvKiogSVNPIHN0cmluZyBvZiB3aGVuIHRvIHJlc3VtZSAqL1xuICByZXN1bWVBdDogc3RyaW5nO1xuICAvKiogV2hldGhlciBhIHdhaXRfY3JlYXRlZCBldmVudCBhbHJlYWR5IGV4aXN0cyBmb3IgdGhpcyB3YWl0ICovXG4gIGhhc0NyZWF0ZWRFdmVudDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQZW5kaW5nSG9vayB7XG4gIHR5cGU6ICdob29rJztcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nO1xuICB0b2tlbjogc3RyaW5nO1xuICAvKiogRWFybGllc3QgdG9rZW4gcmV1c2UgdGltZSwgYXMgbWlsbGlzZWNvbmRzIHNpbmNlIHRoZSBVbml4IGVwb2NoLiAqL1xuICB0b2tlblJldGVudGlvblVudGlsPzogbnVtYmVyO1xuICBpc1dlYmhvb2s6IGJvb2xlYW47XG4gIG1ldGFkYXRhPzogdW5rbm93bjtcbiAgaGFzQ3JlYXRlZEV2ZW50OiBib29sZWFuO1xuICAvKipcbiAgICogVHJ1ZSBmb3IgaW50ZXJuYWwgc3lzdGVtIGhvb2tzIChlLmcuIEFib3J0Q29udHJvbGxlcidzIGhvb2spLCB3aGljaFxuICAgKiBhcmUgZXhlbXB0IGZyb20gdXNlci1ob29rIHRva2VuIG5hbWVzcGFjZSBjb25mbGljdCBjaGVja3MuXG4gICAqL1xuICBpc1N5c3RlbT86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTZXQgd2hlbiB0aGUgd29ya2Zsb3cgY2FsbGVkIEFib3J0Q29udHJvbGxlci5hYm9ydCgpIGR1cmluZyB0aGlzXG4gICAqIGludm9jYXRpb24uIFRoZSBob3N0IG11c3QgcmVjb3JkIHRoZSBhYm9ydDogY3JlYXRlIGEgaG9va19yZWNlaXZlZFxuICAgKiBldmVudCBjYXJyeWluZyBgYWJvcnRQYXlsb2FkYCBhbmQgd3JpdGUvY2xvc2UgdGhlIGFib3J0IHN0cmVhbS5cbiAgICovXG4gIGFib3J0UmVxdWVzdGVkPzogYm9vbGVhbjtcbiAgLyoqIFZNLXNlcmlhbGl6ZWQgYHsgYWJvcnRlZDogdHJ1ZSwgcmVhc29uIH1gIHBheWxvYWQgZm9yIHRoZSBhYm9ydC4gKi9cbiAgYWJvcnRQYXlsb2FkPzogVWludDhBcnJheTtcbiAgLyoqIFNldCBieSB0aGUgY29tcGxldGlvbiBkcmFpbiB3aGVuIGEgc3lzdGVtIGhvb2sgaXMgaW1wbGljaXRseSBkaXNwb3NlZC4gKi9cbiAgZGlzcG9zZWQ/OiBib29sZWFuO1xuICAvKipcbiAgICogVHJ1ZSB3aGVuIHRoZSB3b3JrZmxvdyBpcyBhd2FpdGluZyBob29rLmdldENvbmZsaWN0KCkgZm9yIHRoaXMgaG9vay5cbiAgICogVGhlIGVudHJ5cG9pbnQgcmUtaW52b2tlcyB0aGUgd29ya2Zsb3cgcmlnaHQgYWZ0ZXIgd3JpdGluZ1xuICAgKiBob29rX2NyZWF0ZWQgc28gcmVwbGF5IGNhbiBjb25maXJtIGNyZWF0aW9uIGFuZCByZXNvbHZlIHRoZSBhd2FpdGVyLlxuICAgKi9cbiAgaGFzR2V0Q29uZmxpY3RBd2FpdGVyPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQZW5kaW5nQXR0cmlidXRlIHtcbiAgdHlwZTogJ2F0dHJpYnV0ZSc7XG4gIGNvcnJlbGF0aW9uSWQ6IHN0cmluZztcbiAgLyoqIE5vcm1hbGl6ZWQgYXR0cmlidXRlIGNoYW5nZXMgKHBsYWluIEpTT04tYWJsZSBvYmplY3RzKSAqL1xuICBjaGFuZ2VzOiB1bmtub3duW107XG4gIGFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzPzogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgYW4gYXR0cl9zZXQgZXZlbnQgYWxyZWFkeSBleGlzdHMgZm9yIHRoaXMgd3JpdGUgKi9cbiAgaGFzQ3JlYXRlZEV2ZW50OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBlbmRpbmdIb29rRGlzcG9zZSB7XG4gIHR5cGU6ICdob29rX2Rpc3Bvc2UnO1xuICBjb3JyZWxhdGlvbklkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUb2tlbiBvZiB0aGUgaG9vayBiZWluZyBkaXNwb3NlZC4gVXNlZCBieSB0aGUgZW50cnlwb2ludCB0byBvcmRlclxuICAgKiBzYW1lLXRva2VuIGhvb2sgb3BlcmF0aW9ucyBzZXF1ZW50aWFsbHkgaW4gY29kZSBvcmRlci5cbiAgICovXG4gIHRva2VuPzogc3RyaW5nO1xuICBoYXNDcmVhdGVkRXZlbnQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCB0eXBlIFBlbmRpbmdPcGVyYXRpb24gPVxuICB8IFBlbmRpbmdTdGVwXG4gIHwgUGVuZGluZ1dhaXRcbiAgfCBQZW5kaW5nSG9va1xuICB8IFBlbmRpbmdBdHRyaWJ1dGVcbiAgfCBQZW5kaW5nSG9va0Rpc3Bvc2U7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUXVpY2tKU1J1bnRpbWVSZXN1bHQge1xuICAvKiogVGhlIHdvcmtmbG93IGNvbXBsZXRlZCDigJQgcmVzdWx0IGlzIGZvcm1hdC1wcmVmaXhlZCBkZXZhbHVlIGJ5dGVzICovXG4gIGNvbXBsZXRlZD86IHtcbiAgICByZXN1bHQ6IFVpbnQ4QXJyYXk7XG4gICAgLyoqXG4gICAgICogTGVmdG92ZXIgcGVuZGluZyBvcGVyYXRpb25zIHRoYXQgc3RpbGwgbmVlZCBkdXJhYmxlIHNpZGUgZWZmZWN0cyBhdFxuICAgICAqIGNvbXBsZXRpb246IGFib3J0IHJlY29yZGluZ3MsIHN5c3RlbS1ob29rIGRpc3Bvc2FscywgZmlyZS1hbmQtZm9yZ2V0XG4gICAgICogYXR0cmlidXRlL2hvb2svc3RlcCBldmVudHMuIE1pcnJvcnMgdGhlIG5vZGU6dm0gZW5naW5lJ3NcbiAgICAgKiBkcmFpblBlbmRpbmdRdWV1ZUl0ZW1zLiBUaGUgZW50cnlwb2ludCBkaXNwYXRjaGVzIHRoZXNlIFdJVEhPVVRcbiAgICAgKiBxdWV1ZWluZyBzdGVwcyBvciByZXF1ZXVpbmcgdGhlIHJ1bi5cbiAgICAgKi9cbiAgICBkcmFpbk9wZXJhdGlvbnM/OiBQZW5kaW5nT3BlcmF0aW9uW107XG4gIH07XG4gIC8qKiBUaGUgd29ya2Zsb3cgc3VzcGVuZGVkIHdpdGggcGVuZGluZyBvcGVyYXRpb25zICovXG4gIHN1c3BlbmRlZD86IHtcbiAgICBwZW5kaW5nT3BlcmF0aW9uczogUGVuZGluZ09wZXJhdGlvbltdO1xuICB9O1xuICAvKiogVGhlIHdvcmtmbG93IGZhaWxlZCAqL1xuICBmYWlsZWQ/OiB7XG4gICAgbWVzc2FnZTogc3RyaW5nO1xuICAgIHN0YWNrPzogc3RyaW5nO1xuICAgIG5hbWU/OiBzdHJpbmc7XG4gICAgLyoqIFNlZSBjb21wbGV0ZWQuZHJhaW5PcGVyYXRpb25zIOKAlCBzYW1lIHNlbWFudGljcyBvbiBmYWlsdXJlLiAqL1xuICAgIGRyYWluT3BlcmF0aW9ucz86IFBlbmRpbmdPcGVyYXRpb25bXTtcbiAgICAvKipcbiAgICAgKiBGb3JtYXQtcHJlZml4ZWQgZGV2YWx1ZSBieXRlcyBvZiB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlXG4gICAgICogKEVycm9yIHN1YmNsYXNzIHdpdGggY2F1c2UgY2hhaW4sIHBsYWluIG9iamVjdCwgcHJpbWl0aXZlLCBldGMuKS5cbiAgICAgKiBTZXQgd2hlbiB0aGUgVk0tc2lkZSByZWplY3Rpb24gaGFuZGxlciBzdWNjZXNzZnVsbHkgc2VyaWFsaXplc1xuICAgICAqIHRoZSB0aHJvd24gdmFsdWUuIFRoZSBob3N0IHVzZXMgdGhlc2UgYnl0ZXMgdG8gcmVjb25zdHJ1Y3QgdGhlXG4gICAgICogb3JpZ2luYWwgdmFsdWUgdGhyb3VnaCB0aGUgc3RhbmRhcmQgZXJyb3IgaHlkcmF0aW9uIHBpcGVsaW5lLFxuICAgICAqIHByZXNlcnZpbmcgdHlwZSBpZGVudGl0eSAoVHlwZUVycm9yLCBGYXRhbEVycm9yKSBhbmQgbm9uLUVycm9yXG4gICAgICogdGhyb3dzIHZlcmJhdGltLiBGYWxscyBiYWNrIHRvIHRoZSBtZXNzYWdlL3N0YWNrL25hbWUgZmllbGRzXG4gICAgICogd2hlbiB0aGlzIGlzIHVuZGVmaW5lZCAoZS5nLiBleHRyYWN0RXJyb3IgcHNldWRvLWZhaWx1cmVzKS5cbiAgICAgKi9cbiAgICB2YWx1ZUJ5dGVzPzogVWludDhBcnJheTtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBRdWlja0pTUnVudGltZU9wdGlvbnMge1xuICAvKiogVGhlIGNvbXBpbGVkIHdvcmtmbG93IGJ1bmRsZSBjb2RlICh3b3JrZmxvdyBtb2RlIG91dHB1dCBmcm9tIFNXQykgKi9cbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmc7XG4gIC8qKiBUaGUgd29ya2Zsb3cgSUQgKGUuZy4gXCJ3b3JrZmxvdy8vLi93b3JrZmxvd3MvMV9zaW1wbGUvL3NpbXBsZVwiKSAqL1xuICB3b3JrZmxvd0lkOiBzdHJpbmc7XG4gIC8qKiBUaGUgd29ya2Zsb3cgcnVuIGVudGl0eSAqL1xuICB3b3JrZmxvd1J1bjogV29ya2Zsb3dSdW47XG4gIC8qKiBGZWF0dXJlcyBzdXBwb3J0ZWQgYnkgdGhlIFdvcmxkIGV4ZWN1dGluZyB0aGlzIHdvcmtmbG93LiAqL1xuICB3b3JsZENhcGFiaWxpdGllcz86IFdvcmxkQ2FwYWJpbGl0aWVzO1xuICAvKipcbiAgICogVGhlIGZ1bGwgZXZlbnQgbG9nIGZvciB0aGUgcnVuLiBFdmVyeSBpbnZvY2F0aW9uIHJlcGxheXMgdGhlIGNvbXBsZXRlXG4gICAqIGxvZyBmcm9tIHRoZSBzdGFydCAoc2FtZSByZXBsYXkgc2VtYW50aWNzIGFzIHRoZSBgbm9kZTp2bWAgZW5naW5lKS5cbiAgICovXG4gIGV2ZW50czogRXZlbnRbXTtcbiAgLyoqIEVuY3J5cHRpb24ga2V5IGZvciBkZWNyeXB0aW5nIGV2ZW50IHBheWxvYWRzICh1bmRlZmluZWQgaWYgdW5lbmNyeXB0ZWQpICovXG4gIGVuY3J5cHRpb25LZXk/OiBEZWNyeXB0aW9uS2V5O1xuICAvKipcbiAgICogVGhlIGxvY2FsIHBvcnQgdGhlIHdvcmtmbG93IHNlcnZlciBpcyBsaXN0ZW5pbmcgb24sIHVzZWQgdG8gcG9wdWxhdGVcbiAgICogYHdvcmtmbG93TWV0YWRhdGEudXJsYC4gUmVzb2x2ZWQgYXQgY2FsbCB0aW1lIG9uIHRoZSBob3N0IHNpZGUgc28gdGhlXG4gICAqIFZNIGRvZXNuJ3QgaGF2ZSB0byBwcm9iZSB0aGUgZmlsZXN5c3RlbS4gSWdub3JlZCBvbiBWZXJjZWwg4oCUIFZFUkNFTF9VUkxcbiAgICogdGFrZXMgcHJlY2VkZW5jZSB0aGVyZS5cbiAgICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBGYWxsYmFjayB3b3JrZmxvdyBpbnB1dCBmcm9tIHRoZSBxdWV1ZSBtZXNzYWdlJ3MgcmVzaWxpZW50LXN0YXJ0XG4gICAqIHBheWxvYWQuIFVzZWQgd2hlbiB0aGUgZmV0Y2hlZCBldmVudCBsb2cgbGFja3MgYSBgcnVuX2NyZWF0ZWRgIGV2ZW50XG4gICAqIChldmVudHVhbGx5LWNvbnNpc3RlbnQgcmVhZCBhZnRlciB0aGUgcGFyZW50J3Mgc3RhcnQoKSB3cm90ZSBpdCkuXG4gICAqL1xuICBydW5JbnB1dD86IFJ1bklucHV0O1xufVxuXG4vLyAtLS0tIFZNIEJvb3RzdHJhcCBDb2RlIC0tLS1cblxuLyoqXG4gKiBKYXZhU2NyaXB0IGNvZGUgdGhhdCBydW5zIGluc2lkZSB0aGUgUXVpY2tKUyBWTSB0byBzZXQgdXAgdGhlIHdvcmtmbG93XG4gKiBwcmltaXRpdmVzLiBUaGlzIHNldHMgdXA6XG4gKiAtIGdsb2JhbFRoaXMuX19wcml2YXRlX3dvcmtmbG93cyAoTWFwKSAtIHdvcmtmbG93IHJlZ2lzdHJ5XG4gKiAtIGdsb2JhbFRoaXMuX19yZXNvbHZlcnMgKE9iamVjdCkgLSBwZW5kaW5nIHByb21pc2UgcmVzb2x2ZS9yZWplY3QgZnVuY3Rpb25zXG4gKiAtIGdsb2JhbFRoaXMuX19wZW5kaW5nIChBcnJheSkgLSBtZXRhZGF0YSBhYm91dCBwZW5kaW5nIG9wZXJhdGlvbnNcbiAqIC0gZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildIC0gc3RlcCBwcm94eSBmYWN0b3J5XG4gKiAtIGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1NMRUVQXCIpXSAtIHNsZWVwIGZ1bmN0aW9uXG4gKi9cbmNvbnN0IFZNX0JPT1RTVFJBUCA9IGBcbi8vIFN5bWJvbC5kaXNwb3NlIC8gU3ltYm9sLmFzeW5jRGlzcG9zZSBwb2x5ZmlsbHMgZm9yIFF1aWNrSlNcbmlmICh0eXBlb2YgU3ltYm9sLmRpc3Bvc2UgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgU3ltYm9sLmRpc3Bvc2UgPSBTeW1ib2wuZm9yKFwiU3ltYm9sLmRpc3Bvc2VcIik7XG59XG5pZiAodHlwZW9mIFN5bWJvbC5hc3luY0Rpc3Bvc2UgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgU3ltYm9sLmFzeW5jRGlzcG9zZSA9IFN5bWJvbC5mb3IoXCJTeW1ib2wuYXN5bmNEaXNwb3NlXCIpO1xufVxuXG5nbG9iYWxUaGlzLl9fcHJpdmF0ZV93b3JrZmxvd3MgPSBuZXcgTWFwKCk7XG5nbG9iYWxUaGlzLl9fcmVzb2x2ZXJzID0ge307XG5nbG9iYWxUaGlzLl9fcGVuZGluZyA9IFtdO1xuZ2xvYmFsVGhpcy5fX3dvcmtmbG93UmVzdWx0ID0gdW5kZWZpbmVkO1xuZ2xvYmFsVGhpcy5fX3dvcmtmbG93RXJyb3IgPSB1bmRlZmluZWQ7XG4vLyBCdWZmZXIgZm9yIGhvb2tfcmVjZWl2ZWQgcGF5bG9hZHMgdGhhdCBhcnJpdmUgYmVmb3JlIHRoZSBob29rIGlzIGF3YWl0ZWQuXG4vLyBLZXllZCBieSBjb3JyZWxhdGlvbklkIOKGkiBhcnJheSBvZiBwYXlsb2FkcyAocHJlc2VydmVzIGRlbGl2ZXJ5IG9yZGVyKS5cbi8vIFRoaXMgbWlycm9ycyB0aGUgZXZlbnQtcmVwbGF5IHJ1bnRpbWUncyBwYXlsb2Fkc1F1ZXVlIGluIGhvb2sudHMuXG5nbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIgPSB7fTtcblxuLy8gQnVmZmVyIGZvciBzdGVwL3dhaXQvYXR0ciB0ZXJtaW5hbCBvdXRjb21lcyB0aGF0IGFycml2ZSBiZWZvcmUgdGhpcyBWTVxuLy8gaGFzIGNvbnN0cnVjdGVkIHRoZSBjb3JyZXNwb25kaW5nIGF3YWl0aW5nIHByb21pc2UuIEluIGZyZXNoLVZNIHJlcGxheVxuLy8gdGhlIG11bHRpLXBhc3MgZXZlbnQgc2NhbiBtYWtlcyB0aGlzIHVucmVhY2hhYmxlIChhd2FpdHMgYXJlXG4vLyByZWNvbnN0cnVjdGVkIGJlZm9yZSB0aGVpciB0ZXJtaW5hbHMgYXJlIHJlLXNjYW5uZWQpLCBidXQgdGhlIGxpdmVcbi8vIGNvbnRpbnVhdGlvbiBwYXRoIChjb250aW51ZVdpdGhFdmVudHMpIHNjYW5zIGVhY2ggZGVsdGEgZXhhY3RseSBvbmNlIOKAlFxuLy8gYSBjb25jdXJyZW50IGludm9jYXRpb24ncyB0ZXJtaW5hbCBhcnJpdmluZyBiZWZvcmUgdGhpcyBWTSByZWFjaGVzIHRoZVxuLy8gYXdhaXQgd291bGQgb3RoZXJ3aXNlIGJlIGRyb3BwZWQgb24gdGhlIGZsb29yIGFuZCB0aGUgYXdhaXQgd291bGRcbi8vIG5ldmVyIHNldHRsZSAodGhlIGZlZWQncyBzZWVuLXNldCBtZWFucyBpdCBpcyBuZXZlciByZS1kZWxpdmVyZWQpLlxuLy8gTWlycm9ycyBfX2hvb2tQYXlsb2FkQnVmZmVyLCB3aGljaCBleGlzdHMgZm9yIGV4YWN0bHkgdGhpcyByZWFzb24gb25cbi8vIHRoZSBob29rIHBhdGguIEtleWVkIGJ5IGNvcnJlbGF0aW9uSWQg4oaSIHNpbmdsZSB0ZXJtaW5hbCAoc3RlcHMsIHdhaXRzXG4vLyBhbmQgYXR0cnMgc2V0dGxlIGV4YWN0bHkgb25jZSkuXG5nbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXIgPSB7fTtcblxuLy8gUmVnaXN0ZXJzIGEgcmVzb2x2ZXIgZm9yIGFuIGF3YWl0ZWQgcHJpbWl0aXZlLCBmaXJzdCBkcmFpbmluZyBhbnlcbi8vIGJ1ZmZlcmVkIHRlcm1pbmFsIHJlY29yZGVkIGZvciB0aGUgY29ycmVsYXRpb25JZC4gRW50cmllcyBhcmUgcHJlcGFyZWRcbi8vIGhvc3Qtc2lkZSAoYnl0ZXMgYWxyZWFkeSBkZWNyeXB0ZWQ7IHNlZSBwcm9jZXNzRXZlbnRzKS5cbmdsb2JhbFRoaXMuX19yZWdpc3RlclJlc29sdmVyID0gZnVuY3Rpb24oY29ycmVsYXRpb25JZCwgcmVzb2x2ZSwgcmVqZWN0KSB7XG4gIHZhciBidWZmZXJlZCA9IGdsb2JhbFRoaXMuX190ZXJtaW5hbEJ1ZmZlcltjb3JyZWxhdGlvbklkXTtcbiAgaWYgKGJ1ZmZlcmVkKSB7XG4gICAgZGVsZXRlIGdsb2JhbFRoaXMuX190ZXJtaW5hbEJ1ZmZlcltjb3JyZWxhdGlvbklkXTtcbiAgICBpZiAoYnVmZmVyZWQua2luZCA9PT0gXCJyZXNvbHZlX2J5dGVzXCIpIHtcbiAgICAgIHJlc29sdmUoZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwid29ya2Zsb3ctZGVzZXJpYWxpemVcIildKGJ1ZmZlcmVkLmJ5dGVzKSk7XG4gICAgfSBlbHNlIGlmIChidWZmZXJlZC5raW5kID09PSBcInJlc29sdmVfdmFsdWVcIikge1xuICAgICAgcmVzb2x2ZShidWZmZXJlZC52YWx1ZSk7XG4gICAgfSBlbHNlIGlmIChidWZmZXJlZC5raW5kID09PSBcInJlamVjdF9ieXRlc1wiKSB7XG4gICAgICByZWplY3QoZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwid29ya2Zsb3ctZGVzZXJpYWxpemVcIildKGJ1ZmZlcmVkLmJ5dGVzKSk7XG4gICAgfSBlbHNlIGlmIChidWZmZXJlZC5raW5kID09PSBcInJlamVjdF9lcnJvclwiKSB7XG4gICAgICB2YXIgZSA9IG5ldyBFcnJvcihidWZmZXJlZC5tZXNzYWdlKTtcbiAgICAgIGUubmFtZSA9IFwiRmF0YWxFcnJvclwiO1xuICAgICAgZS5mYXRhbCA9IHRydWU7XG4gICAgICBpZiAoYnVmZmVyZWQuc3RhY2spIGUuc3RhY2sgPSBidWZmZXJlZC5zdGFjaztcbiAgICAgIHJlamVjdChlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzb2x2ZSh1bmRlZmluZWQpO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cbiAgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1tjb3JyZWxhdGlvbklkXSA9IHsgcmVzb2x2ZTogcmVzb2x2ZSwgcmVqZWN0OiByZWplY3QgfTtcbn07XG5cbi8vIFN0dWJzIGZvciBXZWIgQVBJcyB0aGF0IHRoZSB3b3JrZmxvdyBidW5kbGUgbWF5IHJlZmVyZW5jZSBidXQgYXJlIG5vdFxuLy8gYXZhaWxhYmxlIGluIFF1aWNrSlMuIE5hdGl2ZSBDIGV4dGVuc2lvbnMgKGVuY29kaW5nLCBoZWFkZXJzLCB1cmwsXG4vLyBzdHJ1Y3R1cmVkLWNsb25lKSBwcm92aWRlIHRoZSByZWFsIGltcGxlbWVudGF0aW9uczsgdGhlc2UgYXJlIG1pbmltYWxcbi8vIHN0dWJzIGZvciBBUElzIHRoYXQgZG9uJ3QgaGF2ZSBuYXRpdmUgZXh0ZW5zaW9ucyB5ZXQuIChidG9hL2F0b2IgYW5kXG4vLyB0aGUgVWludDhBcnJheSBiYXNlNjQvaGV4IG1ldGhvZHMgYXJlIGJ1aWx0IGludG8gcXVpY2tqcy13YXNpID49IDMuKVxuXG5pZiAodHlwZW9mIFJlYWRhYmxlU3RyZWFtID09PSBcInVuZGVmaW5lZFwiKSB7XG4gIC8vIE1pbmltYWwgUmVhZGFibGVTdHJlYW0gdGhhdCBzdG9yZXMgYm9keSBkYXRhIGZvciBSZXNwb25zZS5qc29uKCkvdGV4dCgpXG4gIGdsb2JhbFRoaXMuUmVhZGFibGVTdHJlYW0gPSBmdW5jdGlvbigpIHt9O1xuICBnbG9iYWxUaGlzLlJlYWRhYmxlU3RyZWFtLnByb3RvdHlwZS5fX2JvZHlEYXRhID0gbnVsbDtcbn1cblxuaWYgKHR5cGVvZiBXcml0YWJsZVN0cmVhbSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICBnbG9iYWxUaGlzLldyaXRhYmxlU3RyZWFtID0gZnVuY3Rpb24oKSB7fTtcbn1cblxuaWYgKHR5cGVvZiBUcmFuc2Zvcm1TdHJlYW0gPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgZ2xvYmFsVGhpcy5UcmFuc2Zvcm1TdHJlYW0gPSBmdW5jdGlvbigpIHt9O1xufVxuXG5pZiAodHlwZW9mIGNvbnNvbGUgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgZ2xvYmFsVGhpcy5jb25zb2xlID0geyBsb2c6IGZ1bmN0aW9uKCl7fSwgZXJyb3I6IGZ1bmN0aW9uKCl7fSwgd2FybjogZnVuY3Rpb24oKXt9LCBpbmZvOiBmdW5jdGlvbigpe30gfTtcbn1cbi8vIFN0dWIgZXhwb3J0cy9tb2R1bGUgZm9yIENKUyBidW5kbGUgZm9ybWF0XG5nbG9iYWxUaGlzLmV4cG9ydHMgPSB7fTtcbmdsb2JhbFRoaXMubW9kdWxlID0geyBleHBvcnRzOiBnbG9iYWxUaGlzLmV4cG9ydHMgfTtcbi8vIE5PVEU6IFRleHRFbmNvZGVyL1RleHREZWNvZGVyIGFyZSBwcm92aWRlZCBieSB0aGUgbmF0aXZlIGVuY29kaW5nIGV4dGVuc2lvbi5cblxuLy8gLS0tLSBEZXRlcm1pbmlzdGljIFxcYGNyeXB0b1xcYCAocGFyaXR5IHdpdGggdGhlIG5vZGU6dm0gZW5naW5lKSAtLS0tXG4vLyBnZXRSYW5kb21WYWx1ZXMgLyByYW5kb21VVUlEIGRyYXcgZnJvbSBNYXRoLnJhbmRvbSwgd2hpY2ggdGhlIGhvc3Rcbi8vIHJlcGxhY2VzIHdpdGggdGhlIHJ1bidzIHNlZWRlZCBQUk5HIGJlZm9yZSBhbnkgdXNlciBjb2RlIHJ1bnMg4oCUIHNvIHRoZVxuLy8gdmFsdWVzIHJlcGxheSBkZXRlcm1pbmlzdGljYWxseSBhbmQgbWF0Y2ggdGhlIG5vZGUgZW5naW5lLCB3aG9zZVxuLy8gaW1wbGVtZW50YXRpb25zIGRyYXcgZnJvbSB0aGUgc2FtZSBzZWVkZWQgc2VxdWVuY2UgKHNlZSB2bS9pbmRleC50cykuXG4vLyBFdmVyeSBjcnlwdG8uc3VidGxlIG1ldGhvZCB0aHJvd3Mgd2l0aCB0aGUgc2FtZSBndWlkYW5jZSBhcyB0aGUgbm9kZVxuLy8gZW5naW5lJ3Mgbm9uLXJlcGxheWFibGUgbWV0aG9kczsgdW5saWtlIG5vZGUsIFxcYGRpZ2VzdFxcYCBpcyBhbHNvXG4vLyB1bmF2YWlsYWJsZSBoZXJlIChubyBuYXRpdmUgaGFzaCBpbiB0aGUgVk0geWV0KS5cbihmdW5jdGlvbigpIHtcbiAgZnVuY3Rpb24gZ2V0UmFuZG9tVmFsdWVzKGFycmF5KSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgYXJyYXlbaV0gPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAyNTYpO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXk7XG4gIH1cbiAgLy8gTWlycm9ycyB2bS91dWlkLnRzIGNyZWF0ZVJhbmRvbVVVSUQ6IGlkZW50aWNhbCBkcmF3IHBhdHRlcm4gZnJvbSB0aGVcbiAgLy8gc2VlZGVkIFBSTkcsIHNvIGJvdGggZW5naW5lcyBwcm9kdWNlIHRoZSBzYW1lIFVVSUQgYXQgdGhlIHNhbWUgcG9pbnRcbiAgLy8gaW4gYSByZXBsYXkuXG4gIGZ1bmN0aW9uIHJhbmRvbVVVSUQoKSB7XG4gICAgdmFyIGNoYXJzID0gXCIwMTIzNDU2Nzg5YWJjZGVmXCI7XG4gICAgdmFyIHV1aWQgPSBcIlwiO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMzY7IGkrKykge1xuICAgICAgaWYgKGkgPT09IDggfHwgaSA9PT0gMTMgfHwgaSA9PT0gMTggfHwgaSA9PT0gMjMpIHtcbiAgICAgICAgdXVpZCArPSBcIi1cIjtcbiAgICAgIH0gZWxzZSBpZiAoaSA9PT0gMTQpIHtcbiAgICAgICAgdXVpZCArPSBcIjRcIjtcbiAgICAgIH0gZWxzZSBpZiAoaSA9PT0gMTkpIHtcbiAgICAgICAgdXVpZCArPSBjaGFyc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA0KSArIDhdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdXVpZCArPSBjaGFyc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAxNildO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdXVpZDtcbiAgfVxuICBmdW5jdGlvbiBzdWJ0bGVUaHJvdyhuYW1lKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcihcIlxcYGNyeXB0by5zdWJ0bGUuXCIgKyBuYW1lICsgXCIoKVxcYCBpcyBub3QgYXZhaWxhYmxlIGluc2lkZSBhIHdvcmtmbG93IGZ1bmN0aW9uLiBNb3ZlIGl0IHRvIGEgc3RlcCBmdW5jdGlvbiB3aGVyZSBmdWxsIE5vZGUuanMgY3J5cHRvIGlzIGF2YWlsYWJsZS5cIik7XG4gICAgICBlcnIubmFtZSA9IFwiV29ya2Zsb3dSdW50aW1lRXJyb3JcIjtcbiAgICAgIHRocm93IGVycjtcbiAgICB9O1xuICB9XG4gIHZhciBzdWJ0bGUgPSB7fTtcbiAgW1wiZW5jcnlwdFwiLFwiZGVjcnlwdFwiLFwic2lnblwiLFwidmVyaWZ5XCIsXCJkaWdlc3RcIixcImdlbmVyYXRlS2V5XCIsXCJkZXJpdmVLZXlcIixcImRlcml2ZUJpdHNcIixcImltcG9ydEtleVwiLFwiZXhwb3J0S2V5XCIsXCJ3cmFwS2V5XCIsXCJ1bndyYXBLZXlcIl0uZm9yRWFjaChmdW5jdGlvbihtKSB7XG4gICAgc3VidGxlW21dID0gc3VidGxlVGhyb3cobSk7XG4gIH0pO1xuICBnbG9iYWxUaGlzLmNyeXB0byA9IHtcbiAgICBnZXRSYW5kb21WYWx1ZXM6IGdldFJhbmRvbVZhbHVlcyxcbiAgICByYW5kb21VVUlEOiByYW5kb21VVUlELFxuICAgIHN1YnRsZTogc3VidGxlLFxuICB9O1xufSkoKTtcblxuLy8gLS0tLSBMb3VkIEludGwgLyBsb2NhbGUgZ3VhcmRzIC0tLS1cbi8vIFF1aWNrSlMgaGFzIG5vIElDVTogXFxgSW50bFxcYCBpcyBhYnNlbnQgYW5kIHRvTG9jYWxlU3RyaW5nLWZhbWlseSBtZXRob2RzXG4vLyBzaWxlbnRseSBpZ25vcmUgdGhlaXIgbG9jYWxlIGFyZ3VtZW50LiBTaWxlbnQgZGl2ZXJnZW5jZSBmcm9tIHRoZSBub2RlXG4vLyBlbmdpbmUgd291bGQgd3JpdGUgZGlmZmVyZW50IHZhbHVlcyBpbnRvIGEgZHVyYWJsZSBldmVudCBsb2cgd2l0aCBub1xuLy8gZXJyb3IgYW55d2hlcmUg4oCUIHNvIG1ha2UgdGhlIGdhcCBsb3VkIGluc3RlYWQ6IEludGwgY29uc3RydWN0b3JzIHRocm93LFxuLy8gYW5kIHRvTG9jYWxlKiBtZXRob2RzIHRocm93IE9OTFkgd2hlbiBjYWxsZWQgd2l0aCBhbiBleHBsaWNpdCBsb2NhbGVcbi8vICh0aGUgbm8tYXJndW1lbnQgZm9ybXMga2VlcCBRdWlja0pTJ3MgZGVmYXVsdCBiZWhhdmlvcikuXG4oZnVuY3Rpb24oKSB7XG4gIGZ1bmN0aW9uIGludGxUaHJvdyhuYW1lKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcihcIlxcYEludGwuXCIgKyBuYW1lICsgXCJcXGAgaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgUXVpY2tKUyB3b3JrZmxvdyBlbmdpbmUgKG5vIElDVSkuIFBlcmZvcm0gbG9jYWxlLXNlbnNpdGl2ZSBmb3JtYXR0aW5nIGluIGEgc3RlcCBmdW5jdGlvbiwgb3IgdXNlIFdPUktGTE9XX1ZNPW5vZGUuXCIpO1xuICAgICAgZXJyLm5hbWUgPSBcIldvcmtmbG93UnVudGltZUVycm9yXCI7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfTtcbiAgfVxuICBpZiAodHlwZW9mIEludGwgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICB2YXIgaW50bCA9IHt9O1xuICAgIFtcIkNvbGxhdG9yXCIsXCJEYXRlVGltZUZvcm1hdFwiLFwiRGlzcGxheU5hbWVzXCIsXCJEdXJhdGlvbkZvcm1hdFwiLFwiTGlzdEZvcm1hdFwiLFwiTG9jYWxlXCIsXCJOdW1iZXJGb3JtYXRcIixcIlBsdXJhbFJ1bGVzXCIsXCJSZWxhdGl2ZVRpbWVGb3JtYXRcIixcIlNlZ21lbnRlclwiXS5mb3JFYWNoKGZ1bmN0aW9uKG4pIHtcbiAgICAgIGludGxbbl0gPSBpbnRsVGhyb3cobik7XG4gICAgfSk7XG4gICAgaW50bC5nZXRDYW5vbmljYWxMb2NhbGVzID0gaW50bFRocm93KFwiZ2V0Q2Fub25pY2FsTG9jYWxlc1wiKTtcbiAgICBnbG9iYWxUaGlzLkludGwgPSBpbnRsO1xuICB9XG4gIGZ1bmN0aW9uIGd1YXJkTG9jYWxlKHByb3RvLCBtZXRob2QpIHtcbiAgICB2YXIgb3JpZ2luYWwgPSBwcm90b1ttZXRob2RdO1xuICAgIGlmICh0eXBlb2Ygb3JpZ2luYWwgIT09IFwiZnVuY3Rpb25cIikgcmV0dXJuO1xuICAgIHByb3RvW21ldGhvZF0gPSBmdW5jdGlvbihsb2NhbGVzKSB7XG4gICAgICBpZiAobG9jYWxlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoXCJcXGBcIiArIG1ldGhvZCArIFwiKGxvY2FsZXMsIC4uLilcXGAgd2l0aCBhbiBleHBsaWNpdCBsb2NhbGUgaXMgbm90IHN1cHBvcnRlZCBpbiB0aGUgUXVpY2tKUyB3b3JrZmxvdyBlbmdpbmUgKG5vIElDVSkg4oCUIGl0IHdvdWxkIHNpbGVudGx5IGlnbm9yZSB0aGUgbG9jYWxlLiBGb3JtYXQgaW4gYSBzdGVwIGZ1bmN0aW9uLCBvciBjYWxsIHdpdGhvdXQgYXJndW1lbnRzIGZvciB0aGUgZW5naW5lIGRlZmF1bHQuXCIpO1xuICAgICAgICBlcnIubmFtZSA9IFwiV29ya2Zsb3dSdW50aW1lRXJyb3JcIjtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG9yaWdpbmFsLmNhbGwodGhpcyk7XG4gICAgfTtcbiAgfVxuICBndWFyZExvY2FsZShOdW1iZXIucHJvdG90eXBlLCBcInRvTG9jYWxlU3RyaW5nXCIpO1xuICBndWFyZExvY2FsZShEYXRlLnByb3RvdHlwZSwgXCJ0b0xvY2FsZVN0cmluZ1wiKTtcbiAgZ3VhcmRMb2NhbGUoRGF0ZS5wcm90b3R5cGUsIFwidG9Mb2NhbGVEYXRlU3RyaW5nXCIpO1xuICBndWFyZExvY2FsZShEYXRlLnByb3RvdHlwZSwgXCJ0b0xvY2FsZVRpbWVTdHJpbmdcIik7XG4gIGd1YXJkTG9jYWxlKFN0cmluZy5wcm90b3R5cGUsIFwidG9Mb2NhbGVMb3dlckNhc2VcIik7XG4gIGd1YXJkTG9jYWxlKFN0cmluZy5wcm90b3R5cGUsIFwidG9Mb2NhbGVVcHBlckNhc2VcIik7XG4gIC8vIGxvY2FsZUNvbXBhcmUncyBsb2NhbGVzIGFyZ3VtZW50IGlzIHRoZSBTRUNPTkQgcGFyYW1ldGVyLlxuICAoZnVuY3Rpb24oKSB7XG4gICAgdmFyIG9yaWdpbmFsID0gU3RyaW5nLnByb3RvdHlwZS5sb2NhbGVDb21wYXJlO1xuICAgIFN0cmluZy5wcm90b3R5cGUubG9jYWxlQ29tcGFyZSA9IGZ1bmN0aW9uKHRoYXQsIGxvY2FsZXMpIHtcbiAgICAgIGlmIChsb2NhbGVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcihcIlxcYGxvY2FsZUNvbXBhcmUodGhhdCwgbG9jYWxlcywgLi4uKVxcYCB3aXRoIGFuIGV4cGxpY2l0IGxvY2FsZSBpcyBub3Qgc3VwcG9ydGVkIGluIHRoZSBRdWlja0pTIHdvcmtmbG93IGVuZ2luZSAobm8gSUNVKS4gQ29tcGFyZSBpbiBhIHN0ZXAgZnVuY3Rpb24sIG9yIGNhbGwgd2l0aG91dCBhIGxvY2FsZS5cIik7XG4gICAgICAgIGVyci5uYW1lID0gXCJXb3JrZmxvd1J1bnRpbWVFcnJvclwiO1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3JpZ2luYWwuY2FsbCh0aGlzLCB0aGF0KTtcbiAgICB9O1xuICB9KSgpO1xufSkoKTtcblxuZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildID0gZnVuY3Rpb24oc3RlcElkLCBjbG9zdXJlVmFyc0ZuKSB7XG4gIHZhciBmbiA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB2YXIgY29ycmVsYXRpb25JZCA9IFwic3RlcF9cIiArIGdsb2JhbFRoaXMuX19nZW5lcmF0ZVVsaWQoKTtcbiAgICAvLyBDYXB0dXJlICd0aGlzJyBmb3IgbWV0aG9kIGludm9jYXRpb25zIChlLmcuLCBNeUNsYXNzLm1ldGhvZCgpKVxuICAgIHZhciB0aGlzVmFsID0gKHRoaXMgIT09IHVuZGVmaW5lZCAmJiB0aGlzICE9PSBudWxsICYmIHRoaXMgIT09IGdsb2JhbFRoaXMpID8gdGhpcyA6IHVuZGVmaW5lZDtcbiAgICAvLyBTZXJpYWxpemUgc3RlcCBpbnB1dCB1c2luZyB0aGUgaG9zdC1wcm92aWRlZCBkZXZhbHVlIHNlcmlhbGl6ZXIuXG4gICAgLy8gVGhpcyBwcm9kdWNlcyBhIGZvcm1hdC1wcmVmaXhlZCBVaW50OEFycmF5IChcImRldmxcIiArIGRldmFsdWUuc3RyaW5naWZ5KS5cbiAgICB2YXIgaW5wdXQgPSBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1zZXJpYWxpemVcIildKHtcbiAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgICBjbG9zdXJlVmFyczogY2xvc3VyZVZhcnNGbiA/IGNsb3N1cmVWYXJzRm4oKSA6IHVuZGVmaW5lZCxcbiAgICAgIHRoaXNWYWw6IHRoaXNWYWwsXG4gICAgfSk7XG4gICAgZ2xvYmFsVGhpcy5fX3BlbmRpbmcucHVzaCh7XG4gICAgICB0eXBlOiBcInN0ZXBcIixcbiAgICAgIGNvcnJlbGF0aW9uSWQ6IGNvcnJlbGF0aW9uSWQsXG4gICAgICBzdGVwSWQ6IHN0ZXBJZCxcbiAgICAgIGlucHV0OiBpbnB1dCxcbiAgICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gICAgfSk7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgZ2xvYmFsVGhpcy5fX3JlZ2lzdGVyUmVzb2x2ZXIoY29ycmVsYXRpb25JZCwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICB9KTtcbiAgfTtcbiAgLy8gU2V0IHN0ZXBJZCBvbiB0aGUgcHJveHkgc28gdGhlIFN0ZXBGdW5jdGlvbiByZWR1Y2VyIGNhbiBkZXRlY3QgYW5kXG4gIC8vIHNlcmlhbGl6ZSBzdGVwIGZ1bmN0aW9uIHJlZmVyZW5jZXMgKGUuZy4gd2hlbiBwYXNzZWQgYXMgYXJndW1lbnRzKS5cbiAgZm4uc3RlcElkID0gc3RlcElkO1xuICBpZiAoY2xvc3VyZVZhcnNGbikgZm4uX19jbG9zdXJlVmFyc0ZuID0gY2xvc3VyZVZhcnNGbjtcbiAgLy8gT3ZlcnJpZGUgLmJpbmQgc28gYSBib3VuZCBzdGVwIHByb3h5IChlLmcuIHRoZSBTV0MgcGx1Z2luJ3NcbiAgLy8gdXNlU3RlcCguLi4pLmJpbmQodGhpcykgZm9yIGxleGljYWwtdGhpcyBhcnJvdyBzdGVwcykga2VlcHMgaXRzXG4gIC8vIHN0ZXBJZCBhbmQgcmVjb3JkcyB0aGUgYm91bmQgcmVjZWl2ZXIgLyBwcmVmaWxsZWQgYXJncyDigJQgdGhlIG5hdGl2ZVxuICAvLyBiaW5kIGRyb3BzIG93biBwcm9wZXJ0aWVzLCB3aGljaCB3b3VsZCBtYWtlIHRoZSBTdGVwRnVuY3Rpb25cbiAgLy8gcmVkdWNlciBmYWlsIHRvIHJlY29nbml6ZSB0aGUgcHJveHkgd2hlbiBpdCBjcm9zc2VzIGEgc2VyaWFsaXphdGlvblxuICAvLyBib3VuZGFyeS4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUncyBvdmVycmlkZSBpbiBzdGVwLnRzLlxuICBmbi5iaW5kID0gZnVuY3Rpb24odGhpc0FyZykge1xuICAgIHZhciBwYXJ0aWFsQXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgdmFyIGJvdW5kID0gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQuYXBwbHkodGhpcywgW3RoaXNBcmddLmNvbmNhdChwYXJ0aWFsQXJncykpO1xuICAgIGJvdW5kLnN0ZXBJZCA9IHN0ZXBJZDtcbiAgICBpZiAoY2xvc3VyZVZhcnNGbikgYm91bmQuX19jbG9zdXJlVmFyc0ZuID0gY2xvc3VyZVZhcnNGbjtcbiAgICBib3VuZC5fX2JvdW5kVGhpcyA9IHRoaXNBcmc7XG4gICAgaWYgKHBhcnRpYWxBcmdzLmxlbmd0aCA+IDApIGJvdW5kLl9fYm91bmRBcmdzID0gcGFydGlhbEFyZ3M7XG4gICAgcmV0dXJuIGJvdW5kO1xuICB9O1xuICByZXR1cm4gZm47XG59O1xuXG4vLyBQYXJzZXMgYW4gXCJtc1wiIGxpYnJhcnkgc3R5bGUgZHVyYXRpb24gc3RyaW5nIGludG8gbWlsbGlzZWNvbmRzLlxuLy8gU3VwcG9ydHMgdGhlIHNhbWUgdW5pdHMgYXMgdGhlIHJlcGxheSBydW50aW1lICh3aGljaCB1c2VzIHRoZSBcIm1zXCJcbi8vIHBhY2thZ2UpOiBtcyAvIHMgLyBtIC8gaCAvIGQgLyB3IC8geSwgd2l0aCB2ZXJib3NlIGFsaWFzZXNcbi8vIChzZWNvbmRzLCBtaW51dGVzLCAuLi4pLlxuZ2xvYmFsVGhpcy5fX3BhcnNlRHVyYXRpb25NcyA9IGZ1bmN0aW9uKHN0cikge1xuICBzdHIgPSBTdHJpbmcoc3RyKTtcbiAgaWYgKHN0ci5sZW5ndGggPiAxMDApIHJldHVybiB1bmRlZmluZWQ7XG4gIHZhciBtYXRjaCA9IHN0ci5tYXRjaChcbiAgICAvXigtPyg/OlxcXFxkKyk/XFxcXC4/XFxcXGQrKSAqKG1pbGxpc2Vjb25kcz98bXNlY3M/fG1zfHNlY29uZHM/fHNlY3M/fHN8bWludXRlcz98bWlucz98bXxob3Vycz98aHJzP3xofGRheXM/fGR8d2Vla3M/fHd8eWVhcnM/fHlycz98eSk/JC9pXG4gICk7XG4gIGlmICghbWF0Y2gpIHJldHVybiB1bmRlZmluZWQ7XG4gIHZhciBuID0gcGFyc2VGbG9hdChtYXRjaFsxXSk7XG4gIHZhciB0eXBlID0gKG1hdGNoWzJdIHx8IFwibXNcIikudG9Mb3dlckNhc2UoKTtcbiAgdmFyIHMgPSAxMDAwLCBtID0gNjAgKiBzLCBoID0gNjAgKiBtLCBkID0gMjQgKiBoLCB3ID0gNyAqIGQsIHkgPSAzNjUuMjUgKiBkO1xuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlIFwieWVhcnNcIjogY2FzZSBcInllYXJcIjogY2FzZSBcInlyc1wiOiBjYXNlIFwieXJcIjogY2FzZSBcInlcIjogcmV0dXJuIG4gKiB5O1xuICAgIGNhc2UgXCJ3ZWVrc1wiOiBjYXNlIFwid2Vla1wiOiBjYXNlIFwid1wiOiByZXR1cm4gbiAqIHc7XG4gICAgY2FzZSBcImRheXNcIjogY2FzZSBcImRheVwiOiBjYXNlIFwiZFwiOiByZXR1cm4gbiAqIGQ7XG4gICAgY2FzZSBcImhvdXJzXCI6IGNhc2UgXCJob3VyXCI6IGNhc2UgXCJocnNcIjogY2FzZSBcImhyXCI6IGNhc2UgXCJoXCI6IHJldHVybiBuICogaDtcbiAgICBjYXNlIFwibWludXRlc1wiOiBjYXNlIFwibWludXRlXCI6IGNhc2UgXCJtaW5zXCI6IGNhc2UgXCJtaW5cIjogY2FzZSBcIm1cIjogcmV0dXJuIG4gKiBtO1xuICAgIGNhc2UgXCJzZWNvbmRzXCI6IGNhc2UgXCJzZWNvbmRcIjogY2FzZSBcInNlY3NcIjogY2FzZSBcInNlY1wiOiBjYXNlIFwic1wiOiByZXR1cm4gbiAqIHM7XG4gICAgY2FzZSBcIm1pbGxpc2Vjb25kc1wiOiBjYXNlIFwibWlsbGlzZWNvbmRcIjogY2FzZSBcIm1zZWNzXCI6IGNhc2UgXCJtc2VjXCI6IGNhc2UgXCJtc1wiOiByZXR1cm4gbjtcbiAgICBkZWZhdWx0OiByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59O1xuXG5nbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19TTEVFUFwiKV0gPSBmdW5jdGlvbihwYXJhbSkge1xuICB2YXIgY29ycmVsYXRpb25JZCA9IFwid2FpdF9cIiArIGdsb2JhbFRoaXMuX19nZW5lcmF0ZVVsaWQoKTtcbiAgdmFyIHJlc3VtZUF0O1xuICBpZiAodHlwZW9mIHBhcmFtID09PSBcIm51bWJlclwiKSB7XG4gICAgcmVzdW1lQXQgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgcGFyYW0pLnRvSVNPU3RyaW5nKCk7XG4gIH0gZWxzZSBpZiAodHlwZW9mIHBhcmFtID09PSBcInN0cmluZ1wiKSB7XG4gICAgdmFyIG1zID0gZ2xvYmFsVGhpcy5fX3BhcnNlRHVyYXRpb25NcyhwYXJhbSk7XG4gICAgaWYgKHR5cGVvZiBtcyA9PT0gXCJudW1iZXJcIiAmJiBpc0Zpbml0ZShtcykpIHtcbiAgICAgIHJlc3VtZUF0ID0gbmV3IERhdGUoRGF0ZS5ub3coKSArIG1zKS50b0lTT1N0cmluZygpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBOb3QgYSBkdXJhdGlvbiBzdHJpbmcg4oCUIHRyeSBhcyBhbiBhYnNvbHV0ZSBkYXRlIHN0cmluZy5cbiAgICAgIHZhciBkYXRlID0gbmV3IERhdGUocGFyYW0pO1xuICAgICAgaWYgKGlzTmFOKGRhdGUuZ2V0VGltZSgpKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHNsZWVwIHBhcmFtZXRlcjogXCIgKyBwYXJhbSk7XG4gICAgICB9XG4gICAgICByZXN1bWVBdCA9IGRhdGUudG9JU09TdHJpbmcoKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAocGFyYW0gaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgaWYgKGlzTmFOKHBhcmFtLmdldFRpbWUoKSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgc2xlZXAgcGFyYW1ldGVyOiBcIiArIHBhcmFtKTtcbiAgICB9XG4gICAgcmVzdW1lQXQgPSBwYXJhbS50b0lTT1N0cmluZygpO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgc2xlZXAgcGFyYW1ldGVyOiBcIiArIHBhcmFtKTtcbiAgfVxuICBnbG9iYWxUaGlzLl9fcGVuZGluZy5wdXNoKHtcbiAgICB0eXBlOiBcIndhaXRcIixcbiAgICBjb3JyZWxhdGlvbklkOiBjb3JyZWxhdGlvbklkLFxuICAgIHJlc3VtZUF0OiByZXN1bWVBdCxcbiAgICBoYXNDcmVhdGVkRXZlbnQ6IGZhbHNlLFxuICB9KTtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGdsb2JhbFRoaXMuX19yZWdpc3RlclJlc29sdmVyKGNvcnJlbGF0aW9uSWQsIHJlc29sdmUsIHJlamVjdCk7XG4gIH0pO1xufTtcblxuLy8gUmVzcG9uc2UvUmVxdWVzdCBwb2x5ZmlsbHMg4oCUIC5qc29uKCkvLnRleHQoKS8uYXJyYXlCdWZmZXIoKSBhcmUgdXNlU3RlcFxuLy8gcHJveGllcyB0aGF0IGV4ZWN1dGUgb24gdGhlIGhvc3Qgc2lkZS4gVGhlIHByb3hpZXMgYXJlIGFzc2lnbmVkIGRpcmVjdGx5XG4vLyB0byB0aGUgcHJvdG90eXBlcyBzbyB0aGF0ICd0aGlzJyAodGhlIFJlc3BvbnNlL1JlcXVlc3QgaW5zdGFuY2UpIGlzXG4vLyBzZXJpYWxpemVkIGFzIHRoaXNWYWwgYnkgV09SS0ZMT1dfVVNFX1NURVAsIG1hdGNoaW5nIHRoZSBldmVudC1yZXBsYXlcbi8vIHJ1bnRpbWUncyBhcHByb2FjaCAoY29tbWl0IGRjYjA3NjEpLlxuaWYgKHR5cGVvZiBSZXNwb25zZSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICB2YXIgX19CT0RZX0lOSVQgPSBTeW1ib2wuZm9yKFwiQk9EWV9JTklUXCIpO1xuXG4gIGdsb2JhbFRoaXMuUmVzcG9uc2UgPSBmdW5jdGlvbihib2R5LCBpbml0KSB7XG4gICAgaW5pdCA9IGluaXQgfHwge307XG4gICAgdGhpcy5zdGF0dXMgPSBpbml0LnN0YXR1cyB8fCAyMDA7XG4gICAgdGhpcy5zdGF0dXNUZXh0ID0gaW5pdC5zdGF0dXNUZXh0IHx8IFwiXCI7XG4gICAgdGhpcy5oZWFkZXJzID0gbmV3IGdsb2JhbFRoaXMuSGVhZGVycyhpbml0LmhlYWRlcnMgfHwgW10pO1xuICAgIHRoaXMudHlwZSA9IFwiZGVmYXVsdFwiO1xuICAgIHRoaXMudXJsID0gXCJcIjtcbiAgICB0aGlzLnJlZGlyZWN0ZWQgPSBmYWxzZTtcbiAgICBpZiAoYm9keSAhPT0gbnVsbCAmJiBib2R5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuYm9keSA9IE9iamVjdC5jcmVhdGUoZ2xvYmFsVGhpcy5SZWFkYWJsZVN0cmVhbS5wcm90b3R5cGUpO1xuICAgICAgdGhpcy5ib2R5W19fQk9EWV9JTklUXSA9IGJvZHk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYm9keSA9IG51bGw7XG4gICAgfVxuICB9O1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZ2xvYmFsVGhpcy5SZXNwb25zZS5wcm90b3R5cGUsIFwib2tcIiwge1xuICAgIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLnN0YXR1cyA+PSAyMDAgJiYgdGhpcy5zdGF0dXMgPCAzMDA7IH1cbiAgfSk7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShnbG9iYWxUaGlzLlJlc3BvbnNlLnByb3RvdHlwZSwgXCJib2R5VXNlZFwiLCB7XG4gICAgZ2V0OiBmdW5jdGlvbigpIHsgcmV0dXJuIGZhbHNlOyB9XG4gIH0pO1xuICAvLyBBc3NpZ24gdXNlU3RlcCBwcm94aWVzIGRpcmVjdGx5IOKAlCAndGhpcycgYmluZGluZyBwcm92aWRlcyB0aGVcbiAgLy8gUmVzcG9uc2UgaW5zdGFuY2UsIHdoaWNoIGdldHMgc2VyaWFsaXplZCBhcyB0aGlzVmFsIGJ5IHRoZSBwcm94eS5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoZ2xvYmFsVGhpcy5SZXNwb25zZS5wcm90b3R5cGUsIHtcbiAgICBhcnJheUJ1ZmZlcjogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX2FycmF5X2J1ZmZlclwiKSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9LFxuICAgIGpzb246IHsgdmFsdWU6IGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1VTRV9TVEVQXCIpXShcIl9fYnVpbHRpbl9yZXNwb25zZV9qc29uXCIpLCB3cml0YWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlIH0sXG4gICAgdGV4dDogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX3RleHRcIiksIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSxcbiAgfSk7XG4gIGdsb2JhbFRoaXMuUmVzcG9uc2UucHJvdG90eXBlLmJ5dGVzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuYXJyYXlCdWZmZXIoKS50aGVuKGZ1bmN0aW9uKGJ1ZikgeyByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoYnVmKTsgfSk7XG4gIH07XG4gIGdsb2JhbFRoaXMuUmVzcG9uc2UucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHIgPSBPYmplY3QuY3JlYXRlKGdsb2JhbFRoaXMuUmVzcG9uc2UucHJvdG90eXBlKTtcbiAgICByLnN0YXR1cyA9IHRoaXMuc3RhdHVzOyByLnN0YXR1c1RleHQgPSB0aGlzLnN0YXR1c1RleHQ7XG4gICAgci5oZWFkZXJzID0gdGhpcy5oZWFkZXJzOyByLnR5cGUgPSB0aGlzLnR5cGU7XG4gICAgci51cmwgPSB0aGlzLnVybDsgci5yZWRpcmVjdGVkID0gdGhpcy5yZWRpcmVjdGVkOyByLmJvZHkgPSB0aGlzLmJvZHk7XG4gICAgcmV0dXJuIHI7XG4gIH07XG4gIGdsb2JhbFRoaXMuUmVzcG9uc2UuanNvbiA9IGZ1bmN0aW9uKGRhdGEsIGluaXQpIHtcbiAgICB2YXIgYm9keSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuICAgIHZhciBoZWFkZXJzID0gbmV3IGdsb2JhbFRoaXMuSGVhZGVycyhpbml0ID8gaW5pdC5oZWFkZXJzIDogW10pO1xuICAgIGlmICghaGVhZGVycy5oYXMoXCJjb250ZW50LXR5cGVcIikpIHsgaGVhZGVycy5zZXQoXCJjb250ZW50LXR5cGVcIiwgXCJhcHBsaWNhdGlvbi9qc29uXCIpOyB9XG4gICAgcmV0dXJuIG5ldyBnbG9iYWxUaGlzLlJlc3BvbnNlKGJvZHksIHsgc3RhdHVzOiAoaW5pdCAmJiBpbml0LnN0YXR1cykgfHwgMjAwLCBzdGF0dXNUZXh0OiAoaW5pdCAmJiBpbml0LnN0YXR1c1RleHQpIHx8IFwiXCIsIGhlYWRlcnM6IGhlYWRlcnMgfSk7XG4gIH07XG59XG5pZiAodHlwZW9mIFJlcXVlc3QgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgZ2xvYmFsVGhpcy5SZXF1ZXN0ID0gZnVuY3Rpb24oaW5wdXQsIGluaXQpIHtcbiAgICBpbml0ID0gaW5pdCB8fCB7fTtcbiAgICBpZiAodHlwZW9mIGlucHV0ID09PSBcInN0cmluZ1wiKSB7IHRoaXMudXJsID0gaW5wdXQ7IH1cbiAgICBlbHNlIGlmIChpbnB1dCAmJiB0eXBlb2YgaW5wdXQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMudXJsID0gaW5wdXQudXJsIHx8IFwiXCI7IHRoaXMubWV0aG9kID0gaW5wdXQubWV0aG9kO1xuICAgICAgdGhpcy5oZWFkZXJzID0gaW5wdXQuaGVhZGVyczsgdGhpcy5ib2R5ID0gaW5wdXQuYm9keTtcbiAgICB9XG4gICAgaWYgKGluaXQubWV0aG9kKSB0aGlzLm1ldGhvZCA9IGluaXQubWV0aG9kLnRvVXBwZXJDYXNlKCk7XG4gICAgaWYgKCF0aGlzLm1ldGhvZCkgdGhpcy5tZXRob2QgPSBcIkdFVFwiO1xuICAgIGlmIChpbml0LmhlYWRlcnMpIHRoaXMuaGVhZGVycyA9IG5ldyBnbG9iYWxUaGlzLkhlYWRlcnMoaW5pdC5oZWFkZXJzKTtcbiAgICBpZiAoIXRoaXMuaGVhZGVycykgdGhpcy5oZWFkZXJzID0gbmV3IGdsb2JhbFRoaXMuSGVhZGVycygpO1xuICAgIGlmIChpbml0LmJvZHkgIT09IHVuZGVmaW5lZCkgdGhpcy5ib2R5ID0gaW5pdC5ib2R5O1xuICAgIGlmICghdGhpcy5ib2R5KSB0aGlzLmJvZHkgPSBudWxsO1xuICAgIHRoaXMuZHVwbGV4ID0gaW5pdC5kdXBsZXggfHwgXCJoYWxmXCI7XG4gIH07XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShnbG9iYWxUaGlzLlJlcXVlc3QucHJvdG90eXBlLCBcImJvZHlVc2VkXCIsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgfSk7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGdsb2JhbFRoaXMuUmVxdWVzdC5wcm90b3R5cGUsIHtcbiAgICBhcnJheUJ1ZmZlcjogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX2FycmF5X2J1ZmZlclwiKSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9LFxuICAgIGpzb246IHsgdmFsdWU6IGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1VTRV9TVEVQXCIpXShcIl9fYnVpbHRpbl9yZXNwb25zZV9qc29uXCIpLCB3cml0YWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlIH0sXG4gICAgdGV4dDogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX3RleHRcIiksIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSxcbiAgfSk7XG59XG5cbi8vIGNyZWF0ZUhvb2sg4oCUIHJldHVybnMgYSBIb29rIG9iamVjdCB0aGF0IGlzIGJvdGggYSBUaGVuYWJsZSBhbmQgQXN5bmNJdGVyYWJsZS5cbi8vIEVhY2ggYXdhaXQveWllbGQgY3JlYXRlcyBhIG5ldyBwcm9taXNlIGtleWVkIGJ5IHRoZSBzYW1lIGNvcnJlbGF0aW9uSWQuXG4vLyBUaGUgcHJvbWlzZSBpcyByZXNvbHZlZCB3aGVuIGEgaG9va19yZWNlaXZlZCBldmVudCBhcnJpdmVzLlxuZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfQ1JFQVRFX0hPT0tcIildID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgaWYgKG9wdGlvbnMuaXNXZWJob29rID09PSB0cnVlICYmIG9wdGlvbnMuZXhwZXJpbWVudGFsX21pblJldGVudGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdXZWJob29rIGhvb2tzIGRvIG5vdCBzdXBwb3J0IFxcYGV4cGVyaW1lbnRhbF9taW5SZXRlbnRpb25cXGAuIFVzZSBhIG5vbi13ZWJob29rIFxcYGNyZWF0ZUhvb2soKVxcYCB3aXRoIFxcYHJlc3VtZUhvb2soKVxcYC4nKTtcbiAgfVxuICBpZiAob3B0aW9ucy5leHBlcmltZW50YWxfbWluUmV0ZW50aW9uICE9PSB1bmRlZmluZWQgJiYgZ2xvYmFsVGhpcy5fX3dvcmxkQ2FwYWJpbGl0aWVzPy5ob29rUmV0ZW50aW9uPy5hY3RpdmUgIT09IHRydWUpIHtcbiAgICB2YXIgdW5zdXBwb3J0ZWRSZXRlbnRpb25FcnJvciA9IG5ldyBFcnJvcignVGhlIGNvbmZpZ3VyZWQgV29ybGQgZG9lcyBub3Qgc3VwcG9ydCBcXGBleHBlcmltZW50YWxfbWluUmV0ZW50aW9uXFxgIGZvciBIb29rcy4nKTtcbiAgICB1bnN1cHBvcnRlZFJldGVudGlvbkVycm9yLm5hbWUgPSBcIkZhdGFsRXJyb3JcIjtcbiAgICB1bnN1cHBvcnRlZFJldGVudGlvbkVycm9yLmZhdGFsID0gdHJ1ZTtcbiAgICB0aHJvdyB1bnN1cHBvcnRlZFJldGVudGlvbkVycm9yO1xuICB9XG4gIHZhciB0b2tlbiA9IG9wdGlvbnMudG9rZW4gfHwgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlTmFub2lkKCk7XG4gIHZhciBjb3JyZWxhdGlvbklkID0gXCJob29rX1wiICsgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlVWxpZCgpO1xuICB2YXIgaXNEaXNwb3NlZCA9IGZhbHNlO1xuICB2YXIgaGFzQ3JlYXRlZEV2ZW50ID0gZmFsc2U7XG4gIHZhciB0b2tlblJldGVudGlvblVudGlsO1xuICBpZiAob3B0aW9ucy5leHBlcmltZW50YWxfbWluUmV0ZW50aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YXIgbWluUmV0ZW50aW9uID0gb3B0aW9ucy5leHBlcmltZW50YWxfbWluUmV0ZW50aW9uO1xuICAgIGlmICh0eXBlb2YgbWluUmV0ZW50aW9uID09PSBcIm51bWJlclwiKSB7XG4gICAgICBpZiAobWluUmV0ZW50aW9uIDwgMCB8fCAhaXNGaW5pdGUobWluUmV0ZW50aW9uKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGR1cmF0aW9uOiBcIiArIG1pblJldGVudGlvbiArIFwiLiBFeHBlY3RlZCBhIG5vbi1uZWdhdGl2ZSBmaW5pdGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy5cIik7XG4gICAgICB9XG4gICAgICB0b2tlblJldGVudGlvblVudGlsID0gRGF0ZS5ub3coKSArIG1pblJldGVudGlvbjtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBtaW5SZXRlbnRpb24gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHZhciByZXRlbnRpb25NcyA9IGdsb2JhbFRoaXMuX19wYXJzZUR1cmF0aW9uTXMobWluUmV0ZW50aW9uKTtcbiAgICAgIGlmICh0eXBlb2YgcmV0ZW50aW9uTXMgIT09IFwibnVtYmVyXCIgfHwgcmV0ZW50aW9uTXMgPCAwIHx8ICFpc0Zpbml0ZShyZXRlbnRpb25NcykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGR1cmF0aW9uOiBcIicgKyBtaW5SZXRlbnRpb24gKyAnXCIuIEV4cGVjdGVkIGEgdmFsaWQgZHVyYXRpb24gc3RyaW5nIGxpa2UgXCIxc1wiLCBcIjFtXCIsIFwiMWhcIiwgZXRjLicpO1xuICAgICAgfVxuICAgICAgdG9rZW5SZXRlbnRpb25VbnRpbCA9IERhdGUubm93KCkgKyByZXRlbnRpb25NcztcbiAgICB9IGVsc2UgaWYgKG1pblJldGVudGlvbiBpbnN0YW5jZW9mIERhdGUgfHwgKG1pblJldGVudGlvbiAmJiB0eXBlb2YgbWluUmV0ZW50aW9uLmdldFRpbWUgPT09IFwiZnVuY3Rpb25cIikpIHtcbiAgICAgIC8vIEFjY2VwdCBEYXRlLWxpa2Ugb2JqZWN0cyAoYW55dGhpbmcgd2l0aCBnZXRUaW1lKSwgbWF0Y2hpbmdcbiAgICAgIC8vIHBhcnNlRHVyYXRpb25Ub0RhdGU6IHZhbHVlcyB0aGF0IGNyb3NzZWQgdGhlIHNlcmRlIGJvdW5kYXJ5IG1heVxuICAgICAgLy8gbm90IGJlIHJlYWxtLW5hdGl2ZSBEYXRlIGluc3RhbmNlcy5cbiAgICAgIHRva2VuUmV0ZW50aW9uVW50aWwgPSBtaW5SZXRlbnRpb24uZ2V0VGltZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGR1cmF0aW9uIHBhcmFtZXRlci4gRXhwZWN0ZWQgYSBkdXJhdGlvbiBzdHJpbmcsIG51bWJlciAobWlsbGlzZWNvbmRzKSwgb3IgRGF0ZSBvYmplY3QuXCIpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJlZ2lzdGVyIGluIHBlbmRpbmcgb3BlcmF0aW9ucy5cbiAgLy8gU2VyaWFsaXplIG1ldGFkYXRhIGluc2lkZSB0aGUgVk0gc28gUmVzcG9uc2UvUmVxdWVzdCBvYmplY3RzIGFyZVxuICAvLyBwcm9wZXJseSBoYW5kbGVkIGJ5IHRoZSBkZXZhbHVlIHJlZHVjZXJzIGJlZm9yZSBjcm9zc2luZyB0aGUgYm91bmRhcnkuXG4gIHZhciBwZW5kaW5nT3AgPSB7XG4gICAgdHlwZTogXCJob29rXCIsXG4gICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICB0b2tlbjogdG9rZW4sXG4gICAgdG9rZW5SZXRlbnRpb25VbnRpbDogdG9rZW5SZXRlbnRpb25VbnRpbCxcbiAgICBpc1dlYmhvb2s6ICEhb3B0aW9ucy5pc1dlYmhvb2ssXG4gICAgbWV0YWRhdGE6IG9wdGlvbnMubWV0YWRhdGEgPyBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1zZXJpYWxpemVcIildKG9wdGlvbnMubWV0YWRhdGEpIDogdW5kZWZpbmVkLFxuICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gIH07XG4gIGdsb2JhbFRoaXMuX19wZW5kaW5nLnB1c2gocGVuZGluZ09wKTtcblxuICAvLyBQZXItaG9vayBsaWZlY3ljbGUgc3RhdGUgYmFja2luZyBob29rLmdldENvbmZsaWN0KCk6IHJlc29sdmVzIG51bGxcbiAgLy8gb25jZSBjcmVhdGlvbiBpcyBjb25maXJtZWQgKGhvb2tfY3JlYXRlZCksIG9yIHJlc29sdmVzIHdpdGggdGhlXG4gIC8vIGNvbmZsaWN0aW5nIFJ1biBoYW5kbGUgLyByZWplY3RzIHdpdGggSG9va0NvbmZsaWN0RXJyb3Igb25cbiAgLy8gaG9va19jb25mbGljdC4gU3RhdGUgdHJhbnNpdGlvbnMgYXJlIGRyaXZlbiBieSB0aGUgaG9zdCBkdXJpbmcgZXZlbnRcbiAgLy8gcHJvY2Vzc2luZyAoc2VlIHByb2Nlc3NFdmVudHMpLlxuICBnbG9iYWxUaGlzLl9faG9va3MgPSBnbG9iYWxUaGlzLl9faG9va3MgfHwge307XG4gIGdsb2JhbFRoaXMuX19ob29rc1tjb3JyZWxhdGlvbklkXSA9IHtcbiAgICB0b2tlbjogdG9rZW4sXG4gICAgY3JlYXRlZDogZmFsc2UsXG4gICAgY29uZmxpY3Q6IG51bGwsXG4gICAgZ2V0Q29uZmxpY3RSZXNvbHZlcnM6IFtdLFxuICB9O1xuXG4gIC8vIEVhY2ggYXdhaXQgY3JlYXRlcyBhIG5ldyBwcm9taXNlIGZvciB0aGUgbmV4dCBwYXlsb2FkLlxuICAvLyBUaGUgY29ycmVsYXRpb25JZCBzdGF5cyB0aGUgc2FtZSDigJQgdGhlIHJlc29sdmVyIGlzIHJlcGxhY2VkIGVhY2ggdGltZS5cbiAgZnVuY3Rpb24gY3JlYXRlSG9va1Byb21pc2UoKSB7XG4gICAgLy8gQ2hlY2sgdGhlIHBheWxvYWQgYnVmZmVyIGZpcnN0IOKAlCBpZiBhIGhvb2tfcmVjZWl2ZWQgZXZlbnQgYXJyaXZlZFxuICAgIC8vIGJlZm9yZSB0aGlzIGhvb2sgd2FzIGF3YWl0ZWQsIHRoZSBwYXlsb2FkIHdhcyBidWZmZXJlZCBpbiB0aGUgVk1cbiAgICAvLyBoZWFwLiBEcmFpbiBpdCBpbW1lZGlhdGVseSAobWF0Y2hpbmcgZXZlbnQtcmVwbGF5IHBheWxvYWRzUXVldWUpLlxuICAgIHZhciBidWYgPSBnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXJbY29ycmVsYXRpb25JZF07XG4gICAgaWYgKGJ1ZiAmJiBidWYubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShidWYuc2hpZnQoKSk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbY29ycmVsYXRpb25JZF0gPSB7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0IH07XG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiBkaXNwb3NlSG9vaygpIHtcbiAgICBpZiAoaXNEaXNwb3NlZCkgcmV0dXJuO1xuICAgIGlzRGlzcG9zZWQgPSB0cnVlO1xuICAgIC8vIEEgY29uZmxpY3RlZCBob29rIHdhcyBuZXZlciBjcmVhdGVkICh0aGUgd29ybGQgcmVqZWN0ZWQgaXRzIGNsYWltXG4gICAgLy8g4oCUIHRoZSB0b2tlbiBiZWxvbmdzIHRvIGFub3RoZXIgcnVuKSwgc28gdGhlcmUgaXMgbm8gZW50aXR5IHRvXG4gICAgLy8gZGlzcG9zZS4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUsIHdoZXJlIGhvb2tfY29uZmxpY3QgcmVtb3Zlc1xuICAgIC8vIHRoZSBpbnZvY2F0aW9uLXF1ZXVlIGl0ZW0gYmVmb3JlIGRpc3Bvc2UgY2FuIG1hcmsgaXQuIEVtaXR0aW5nIGFcbiAgICAvLyBob29rX2Rpc3Bvc2VkIGhlcmUgd291bGQgYmUgcmVqZWN0ZWQgYnkgdGhlIHdvcmxkJ3NcbiAgICAvLyBob29rLWV4aXN0ZW5jZSB2YWxpZGF0aW9uLlxuICAgIHZhciBzdGF0ZSA9IGdsb2JhbFRoaXMuX19ob29rc1tjb3JyZWxhdGlvbklkXTtcbiAgICBpZiAoIXN0YXRlIHx8ICFzdGF0ZS5jb25mbGljdCkge1xuICAgICAgLy8gU2lnbmFsIHRvIHRoZSBlbnRyeXBvaW50IHRvIGNyZWF0ZSBhIGhvb2tfZGlzcG9zZWQgZXZlbnQuIFRoZVxuICAgICAgLy8gdG9rZW4gaXMgY2FycmllZCBzbyB0aGUgZW50cnlwb2ludCBjYW4gb3JkZXIgc2FtZS10b2tlbiBob29rXG4gICAgICAvLyBvcGVyYXRpb25zIHNlcXVlbnRpYWxseSAoYSBkaXNwb3NlIG11c3QgcmVsZWFzZSB0aGUgdG9rZW4gYmVmb3JlXG4gICAgICAvLyBhIGxhdGVyIHNhbWUtdG9rZW4gaG9vaydzIGNyZWF0aW9uIGlzIHZhbGlkYXRlZCkuXG4gICAgICBnbG9iYWxUaGlzLl9fcGVuZGluZy5wdXNoKHtcbiAgICAgICAgdHlwZTogXCJob29rX2Rpc3Bvc2VcIixcbiAgICAgICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICAgICAgdG9rZW46IHRva2VuLFxuICAgICAgICBoYXNDcmVhdGVkRXZlbnQ6IGZhbHNlLFxuICAgICAgfSk7XG4gICAgfVxuICAgIC8vIElmIHRoZXJlJ3MgYSBwZW5kaW5nIHJlc29sdmVyLCByZXNvbHZlIGl0IHdpdGggdW5kZWZpbmVkIHRvIGJyZWFrIHRoZSBpdGVyYXRvclxuICAgIGlmIChnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NvcnJlbGF0aW9uSWRdKSB7XG4gICAgICBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NvcnJlbGF0aW9uSWRdLnJlc29sdmUodW5kZWZpbmVkKTtcbiAgICAgIGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NvcnJlbGF0aW9uSWRdO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGdldENvbmZsaWN0KCkge1xuICAgIHZhciBzdGF0ZSA9IGdsb2JhbFRoaXMuX19ob29rc1tjb3JyZWxhdGlvbklkXTtcbiAgICBpZiAoc3RhdGUuY29uZmxpY3QpIHtcbiAgICAgIHJldHVybiBzdGF0ZS5jb25mbGljdC5ydW5cbiAgICAgICAgPyBQcm9taXNlLnJlc29sdmUoc3RhdGUuY29uZmxpY3QucnVuKVxuICAgICAgICA6IFByb21pc2UucmVqZWN0KHN0YXRlLmNvbmZsaWN0LmVycm9yKTtcbiAgICB9XG4gICAgaWYgKHN0YXRlLmNyZWF0ZWQpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobnVsbCk7XG4gICAgfVxuICAgIC8vIENyZWF0aW9uIG5vdCB5ZXQgY29uZmlybWVkIGJ5IHRoZSBldmVudCBsb2cg4oCUIHBhcmsgdGhlIGF3YWl0ZXIgYW5kXG4gICAgLy8gZmxhZyB0aGUgcGVuZGluZyBvcCBzbyB0aGUgZW50cnlwb2ludCByZS1pbnZva2VzIHRoZSB3b3JrZmxvdyByaWdodFxuICAgIC8vIGFmdGVyIHdyaXRpbmcgaG9va19jcmVhdGVkIChub3RoaW5nIGV4dGVybmFsIHJlc3VtZXMgYSBnZXRDb25mbGljdFxuICAgIC8vIGF3YWl0ZXI7IGNvbmZpcm1hdGlvbiBvbmx5IGNvbWVzIGZyb20gcmVwbGF5aW5nIHRoZSBuZXcgZXZlbnQpLlxuICAgIHBlbmRpbmdPcC5oYXNHZXRDb25mbGljdEF3YWl0ZXIgPSB0cnVlO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIHN0YXRlLmdldENvbmZsaWN0UmVzb2x2ZXJzLnB1c2goeyByZXNvbHZlOiByZXNvbHZlLCByZWplY3Q6IHJlamVjdCB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHZhciBob29rID0ge1xuICAgIHRva2VuOiB0b2tlbixcbiAgICB0aGVuOiBmdW5jdGlvbihvbkZ1bGZpbGxlZCwgb25SZWplY3RlZCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZUhvb2tQcm9taXNlKCkudGhlbihvbkZ1bGZpbGxlZCwgb25SZWplY3RlZCk7XG4gICAgfSxcbiAgICBnZXRDb25mbGljdDogZ2V0Q29uZmxpY3QsXG4gICAgZGlzcG9zZTogZGlzcG9zZUhvb2ssXG4gIH07XG5cbiAgLy8gU3ltYm9sLmRpc3Bvc2UgZm9yIGV4cGxpY2l0IHJlc291cmNlIG1hbmFnZW1lbnRcbiAgaG9va1tTeW1ib2wuZGlzcG9zZV0gPSBkaXNwb3NlSG9vaztcblxuICAvLyBBc3luY0l0ZXJhYmxlIOKAlCB5aWVsZHMgcGF5bG9hZHMgdW50aWwgZGlzcG9zZWRcbiAgaG9va1tTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmV4dDogZnVuY3Rpb24oKSB7XG4gICAgICAgIGlmIChpc0Rpc3Bvc2VkKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7IGRvbmU6IHRydWUsIHZhbHVlOiB1bmRlZmluZWQgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNyZWF0ZUhvb2tQcm9taXNlKCkudGhlbihmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgIC8vIElmIGRpc3Bvc2VkIHdoaWxlIHdhaXRpbmcsIHNpZ25hbCBkb25lXG4gICAgICAgICAgaWYgKGlzRGlzcG9zZWQpIHJldHVybiB7IGRvbmU6IHRydWUsIHZhbHVlOiB1bmRlZmluZWQgfTtcbiAgICAgICAgICByZXR1cm4geyBkb25lOiBmYWxzZSwgdmFsdWU6IHZhbHVlIH07XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIHJldHVybjogZnVuY3Rpb24oKSB7XG4gICAgICAgIGRpc3Bvc2VIb29rKCk7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBkb25lOiB0cnVlLCB2YWx1ZTogdW5kZWZpbmVkIH0pO1xuICAgICAgfSxcbiAgICB9O1xuICB9O1xuXG4gIHJldHVybiBob29rO1xufTtcblxuLy8gc2V0QXR0cmlidXRlcyDigJQgYXR0YWNoZXMgcGxhaW50ZXh0IG1ldGFkYXRhIHRvIHRoZSBjdXJyZW50IHJ1bi5cbi8vIFZhbGlkYXRpb24gaGFwcGVucyBpbiBsaWJyYXJ5IGNvZGUgKG5vcm1hbGl6ZUF0dHJpYnV0ZUNoYW5nZXMpIGJlZm9yZVxuLy8gdGhpcyBkaXNwYXRjaGVyIGlzIGludm9rZWQsIHNvIFwiY2hhbmdlc1wiIGlzIGFscmVhZHkgbm9ybWFsaXplZC4gVGhlXG4vLyByZXR1cm5lZCBwcm9taXNlIHJlc29sdmVzIHdoZW4gdGhlIG1hdGNoaW5nIGF0dHJfc2V0IGV2ZW50IGlzXG4vLyBvYnNlcnZlZCBkdXJpbmcgZXZlbnQgcHJvY2Vzc2luZyDigJQgbWlycm9yaW5nIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4vLyBjcmVhdGVTZXRBdHRyaWJ1dGVzIChhdHRyaWJ1dGUtZGlzcGF0Y2hlci50cykuXG5nbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19TRVRfQVRUUklCVVRFU1wiKV0gPSBmdW5jdGlvbihjaGFuZ2VzLCBvcHRpb25zKSB7XG4gIHZhciBjb3JyZWxhdGlvbklkID0gXCJhdHRyX1wiICsgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlVWxpZCgpO1xuICBnbG9iYWxUaGlzLl9fcGVuZGluZy5wdXNoKHtcbiAgICB0eXBlOiBcImF0dHJpYnV0ZVwiLFxuICAgIGNvcnJlbGF0aW9uSWQ6IGNvcnJlbGF0aW9uSWQsXG4gICAgY2hhbmdlczogY2hhbmdlcyxcbiAgICBhbGxvd1Jlc2VydmVkQXR0cmlidXRlczogISEob3B0aW9ucyAmJiBvcHRpb25zLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzKSxcbiAgICBoYXNDcmVhdGVkRXZlbnQ6IGZhbHNlLFxuICB9KTtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgIGdsb2JhbFRoaXMuX19yZWdpc3RlclJlc29sdmVyKGNvcnJlbGF0aW9uSWQsIHJlc29sdmUsIHJlamVjdCk7XG4gIH0pO1xufTtcblxuLy8gLS0tLSBBYm9ydENvbnRyb2xsZXIgLyBBYm9ydFNpZ25hbCAoaG9vay1iYWNrZWQpIC0tLS1cbi8vIFBvcnQgb2Ygd29ya2Zsb3cvYWJvcnQtY29udHJvbGxlci50cyB0byB0aGUgVk0gcGVuZGluZy1vcCBtb2RlbDpcbi8vIHRoZSBjb250cm9sbGVyIHJlZ2lzdGVycyBhIHN5c3RlbSBob29rOyBhYm9ydCgpIGZsaXBzIHRoZSBzaWduYWxcbi8vIHN5bmNocm9ub3VzbHkgYW5kIG1hcmtzIHRoZSBwZW5kaW5nIG9wIHNvIHRoZSBob3N0IHJlY29yZHMgdGhlIGFib3J0XG4vLyAoaG9va19yZWNlaXZlZCBldmVudCArIHN0cmVhbSBwYWNrZXQpLiBPbiByZXBsYXksIHRoZSByZWNvcmRlZFxuLy8gaG9va19yZWNlaXZlZCBldmVudCBjYWxscyBfc2V0QWJvcnRlZCBkdXJpbmcgZXZlbnQgcHJvY2Vzc2luZyBhbmQgdGhlXG4vLyB3b3JrZmxvdydzIG93biBhYm9ydCgpIGNhbGwgYmVjb21lcyBhIG5vLW9wLlxudmFyIF9fQUJPUlRfU1RSRUFNX05BTUUgPSBTeW1ib2wuZm9yKFwiV09SS0ZMT1dfQUJPUlRfU1RSRUFNX05BTUVcIik7XG52YXIgX19BQk9SVF9IT09LX1RPS0VOID0gU3ltYm9sLmZvcihcIldPUktGTE9XX0FCT1JUX0hPT0tfVE9LRU5cIik7XG5cbmZ1bmN0aW9uIF9fbWFrZUFib3J0RXJyb3IoKSB7XG4gIGlmICh0eXBlb2YgRE9NRXhjZXB0aW9uICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgcmV0dXJuIG5ldyBET01FeGNlcHRpb24oXCJUaGUgb3BlcmF0aW9uIHdhcyBhYm9ydGVkLlwiLCBcIkFib3J0RXJyb3JcIik7XG4gIH1cbiAgdmFyIGUgPSBuZXcgRXJyb3IoXCJUaGUgb3BlcmF0aW9uIHdhcyBhYm9ydGVkLlwiKTtcbiAgZS5uYW1lID0gXCJBYm9ydEVycm9yXCI7XG4gIHJldHVybiBlO1xufVxuXG5mdW5jdGlvbiBXb3JrZmxvd0Fib3J0U2lnbmFsKHN0cmVhbU5hbWUsIGhvb2tUb2tlbikge1xuICB0aGlzLmFib3J0ZWQgPSBmYWxzZTtcbiAgdGhpcy5yZWFzb24gPSB1bmRlZmluZWQ7XG4gIHRoaXNbX19BQk9SVF9TVFJFQU1fTkFNRV0gPSBzdHJlYW1OYW1lO1xuICB0aGlzW19fQUJPUlRfSE9PS19UT0tFTl0gPSBob29rVG9rZW47XG4gIHRoaXMuX19saXN0ZW5lcnMgPSBbXTtcbiAgdGhpcy5fX29uYWJvcnQgPSBudWxsO1xufVxuT2JqZWN0LmRlZmluZVByb3BlcnR5KFdvcmtmbG93QWJvcnRTaWduYWwucHJvdG90eXBlLCBcIm9uYWJvcnRcIiwge1xuICBnZXQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5fX29uYWJvcnQ7IH0sXG4gIHNldDogZnVuY3Rpb24oaGFuZGxlcikge1xuICAgIHRoaXMuX19vbmFib3J0ID0gaGFuZGxlcjtcbiAgICBpZiAoaGFuZGxlciAmJiB0aGlzLmFib3J0ZWQpIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgfSxcbn0pO1xuV29ya2Zsb3dBYm9ydFNpZ25hbC5wcm90b3R5cGUuX3NldEFib3J0ZWQgPSBmdW5jdGlvbihyZWFzb24pIHtcbiAgaWYgKHRoaXMuYWJvcnRlZCkgcmV0dXJuO1xuICB0aGlzLmFib3J0ZWQgPSB0cnVlO1xuICB0aGlzLnJlYXNvbiA9IHJlYXNvbjtcbiAgaWYgKHRoaXMuX19vbmFib3J0KSB0aGlzLl9fb25hYm9ydC5jYWxsKHRoaXMpO1xuICB2YXIgbGlzdGVuZXJzID0gdGhpcy5fX2xpc3RlbmVycztcbiAgdGhpcy5fX2xpc3RlbmVycyA9IFtdO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxpc3RlbmVycy5sZW5ndGg7IGkrKykgbGlzdGVuZXJzW2ldKCk7XG59O1xuV29ya2Zsb3dBYm9ydFNpZ25hbC5wcm90b3R5cGUuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICh0eXBlICE9PSBcImFib3J0XCIpIHJldHVybjtcbiAgaWYgKHRoaXMuYWJvcnRlZCkge1xuICAgIC8vIEZpcmUgc3luY2hyb25vdXNseSAobm90IG9uIGEgbWljcm90YXNrKSBmb3IgZGV0ZXJtaW5pc3RpYyByZXBsYXkg4oCUXG4gICAgLy8gbWF0Y2hlcyB0aGUgbm9kZTp2bSBlbmdpbmUncyBXb3JrZmxvd0Fib3J0U2lnbmFsLlxuICAgIGxpc3RlbmVyKCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRoaXMuX19saXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG59O1xuV29ya2Zsb3dBYm9ydFNpZ25hbC5wcm90b3R5cGUucmVtb3ZlRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICh0eXBlICE9PSBcImFib3J0XCIpIHJldHVybjtcbiAgdGhpcy5fX2xpc3RlbmVycyA9IHRoaXMuX19saXN0ZW5lcnMuZmlsdGVyKGZ1bmN0aW9uKGwpIHsgcmV0dXJuIGwgIT09IGxpc3RlbmVyOyB9KTtcbn07XG5Xb3JrZmxvd0Fib3J0U2lnbmFsLnByb3RvdHlwZS50aHJvd0lmQWJvcnRlZCA9IGZ1bmN0aW9uKCkge1xuICBpZiAodGhpcy5hYm9ydGVkKSB7XG4gICAgdGhyb3cgdGhpcy5yZWFzb24gIT09IHVuZGVmaW5lZCAmJiB0aGlzLnJlYXNvbiAhPT0gbnVsbFxuICAgICAgPyB0aGlzLnJlYXNvblxuICAgICAgOiBfX21ha2VBYm9ydEVycm9yKCk7XG4gIH1cbn07XG4vLyBFeHBvc2UgZm9yIHRoZSBzZXJkZSBidW5kbGUncyByZXZpdmVycyAoZXZhbHVhdGVkIGJlZm9yZSB0aGlzIGJvb3RzdHJhcDtcbi8vIHRoZXkgbG9vayB0aGUgY2xhc3MgdXAgbGF6aWx5IGF0IHJldml2ZSB0aW1lKS5cbmdsb2JhbFRoaXMuX19Xb3JrZmxvd0Fib3J0U2lnbmFsID0gV29ya2Zsb3dBYm9ydFNpZ25hbDtcblxuLy8gUmVnaXN0cnkgb2YgbGl2ZSBhYm9ydCBzaWduYWxzIGtleWVkIGJ5IHRoZWlyIGhvb2sgY29ycmVsYXRpb25JZC4gVGhlXG4vLyBob3N0IGRlbGl2ZXJzIGhvb2tfcmVjZWl2ZWQgZXZlbnRzIGZvciB0aGVzZSBpZHMgYXMgX3NldEFib3J0ZWQgY2FsbHMuXG5nbG9iYWxUaGlzLl9fYWJvcnRTaWduYWxzID0ge307XG5cbmdsb2JhbFRoaXMuQWJvcnRDb250cm9sbGVyID0gZnVuY3Rpb24gV29ya2Zsb3dBYm9ydENvbnRyb2xsZXIoKSB7XG4gIHZhciBpZCA9IGdsb2JhbFRoaXMuX19nZW5lcmF0ZVVsaWQoKTtcbiAgdmFyIHN0cmVhbU5hbWUgPSBcInN0cm1fXCIgKyBpZCArIFwiX3N5c3RlbV9hYm9ydFwiO1xuICB2YXIgaG9va1Rva2VuID0gXCJhYnJ0X1wiICsgaWQ7XG4gIHRoaXNbX19BQk9SVF9TVFJFQU1fTkFNRV0gPSBzdHJlYW1OYW1lO1xuICB0aGlzW19fQUJPUlRfSE9PS19UT0tFTl0gPSBob29rVG9rZW47XG4gIHRoaXMuc2lnbmFsID0gbmV3IFdvcmtmbG93QWJvcnRTaWduYWwoc3RyZWFtTmFtZSwgaG9va1Rva2VuKTtcbiAgdmFyIGNvcnJlbGF0aW9uSWQgPSBcImhvb2tfXCIgKyBnbG9iYWxUaGlzLl9fZ2VuZXJhdGVVbGlkKCk7XG4gIC8vIFJlZ2lzdGVyIGFuIGludGVybmFsIHN5c3RlbSBob29rLiBpc1N5c3RlbSBwcmV2ZW50cyB0b2tlbiBuYW1lc3BhY2VcbiAgLy8gY29uZmxpY3RzIHdpdGggdXNlciBob29rcy5cbiAgZ2xvYmFsVGhpcy5fX3BlbmRpbmcucHVzaCh7XG4gICAgdHlwZTogXCJob29rXCIsXG4gICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICB0b2tlbjogaG9va1Rva2VuLFxuICAgIGlzV2ViaG9vazogZmFsc2UsXG4gICAgaXNTeXN0ZW06IHRydWUsXG4gICAgaGFzQ3JlYXRlZEV2ZW50OiBmYWxzZSxcbiAgfSk7XG4gIGdsb2JhbFRoaXMuX19hYm9ydFNpZ25hbHNbY29ycmVsYXRpb25JZF0gPSB0aGlzLnNpZ25hbDtcbn07XG5nbG9iYWxUaGlzLkFib3J0Q29udHJvbGxlci5wcm90b3R5cGUuYWJvcnQgPSBmdW5jdGlvbihyZWFzb24pIHtcbiAgaWYgKHRoaXMuc2lnbmFsLmFib3J0ZWQpIHJldHVybjsgLy8gYWxyZWFkeSBhYm9ydGVkIChlLmcuIGZyb20gcmVwbGF5KVxuICB0aGlzLnNpZ25hbC5fc2V0QWJvcnRlZChyZWFzb24pO1xuICAvLyBNYXJrIHRoZSBwZW5kaW5nIGhvb2sgb3Agc28gdGhlIGhvc3QgcmVjb3JkcyB0aGUgYWJvcnQuIFRoZSBwYXlsb2FkXG4gIC8vIGlzIHNlcmlhbGl6ZWQgaW4gdGhlIFZNIHNvIHRoZSByZWFzb24gY3Jvc3NlcyB0aGUgYm91bmRhcnkgd2l0aFxuICAvLyB0eXBlIGZpZGVsaXR5IChFcnJvcnMsIERPTUV4Y2VwdGlvbiwgY3VzdG9tIHZhbHVlcykuXG4gIHZhciB0b2tlbiA9IHRoaXNbX19BQk9SVF9IT09LX1RPS0VOXTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBnbG9iYWxUaGlzLl9fcGVuZGluZy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gZ2xvYmFsVGhpcy5fX3BlbmRpbmdbaV07XG4gICAgaWYgKGl0ZW0udHlwZSA9PT0gXCJob29rXCIgJiYgaXRlbS50b2tlbiA9PT0gdG9rZW4pIHtcbiAgICAgIGl0ZW0uYWJvcnRSZXF1ZXN0ZWQgPSB0cnVlO1xuICAgICAgaXRlbS5hYm9ydFBheWxvYWQgPSBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1zZXJpYWxpemVcIildKHtcbiAgICAgICAgYWJvcnRlZDogdHJ1ZSxcbiAgICAgICAgcmVhc29uOiByZWFzb24sXG4gICAgICB9KTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcblxuZ2xvYmFsVGhpcy5BYm9ydFNpZ25hbCA9IHtcbiAgYWJvcnQ6IGZ1bmN0aW9uKHJlYXNvbikge1xuICAgIHZhciBzID0gbmV3IFdvcmtmbG93QWJvcnRTaWduYWwoXCJcIiwgXCJcIik7XG4gICAgcy5fc2V0QWJvcnRlZChyZWFzb24gIT09IHVuZGVmaW5lZCA/IHJlYXNvbiA6IF9fbWFrZUFib3J0RXJyb3IoKSk7XG4gICAgcmV0dXJuIHM7XG4gIH0sXG4gIGFueTogZnVuY3Rpb24oc2lnbmFscykge1xuICAgIHZhciBjb21wb3NpdGUgPSBuZXcgV29ya2Zsb3dBYm9ydFNpZ25hbChcIlwiLCBcIlwiKTtcbiAgICB2YXIgYXJyID0gQXJyYXkuZnJvbShzaWduYWxzKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltpXS5hYm9ydGVkKSB7XG4gICAgICAgIGNvbXBvc2l0ZS5fc2V0QWJvcnRlZChhcnJbaV0ucmVhc29uKTtcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgdmFyIGxpc3RlbmVycyA9IFtdO1xuICAgIHZhciBjbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxpc3RlbmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobGlzdGVuZXJzW2pdLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgbGlzdGVuZXJzW2pdLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgbGlzdGVuZXJzW2pdLmxpc3RlbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbGlzdGVuZXJzLmxlbmd0aCA9IDA7XG4gICAgfTtcbiAgICBhcnIuZm9yRWFjaChmdW5jdGlvbihzaWduYWwpIHtcbiAgICAgIGlmICghc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIpIHJldHVybjtcbiAgICAgIHZhciBsaXN0ZW5lciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAoIWNvbXBvc2l0ZS5hYm9ydGVkKSB7XG4gICAgICAgICAgY29tcG9zaXRlLl9zZXRBYm9ydGVkKHNpZ25hbC5yZWFzb24pO1xuICAgICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGxpc3RlbmVycy5wdXNoKHsgc2lnbmFsOiBzaWduYWwsIGxpc3RlbmVyOiBsaXN0ZW5lciB9KTtcbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgbGlzdGVuZXIpO1xuICAgIH0pO1xuICAgIHJldHVybiBjb21wb3NpdGU7XG4gIH0sXG4gIHRpbWVvdXQ6IGZ1bmN0aW9uKCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIFwiQWJvcnRTaWduYWwudGltZW91dCgpIGlzIG5vdCBzdXBwb3J0ZWQgaW4gd29ya2Zsb3cgZnVuY3Rpb25zLiBcIiArXG4gICAgICAgIFwiVXNlIHNsZWVwKCkgd2l0aCBhbiBBYm9ydENvbnRyb2xsZXIgaW5zdGVhZC4gXCIgK1xuICAgICAgICBcIlNlZTogL2RvY3MvZXJyb3JzL2Fib3J0LXNpZ25hbC10aW1lb3V0LWluLXdvcmtmbG93XCJcbiAgICApO1xuICB9LFxufTtcblxuLy8gV09SS0ZMT1dfR0VUX1NUUkVBTV9JRCDigJQgZ2VuZXJhdGVzIGEgc3RyZWFtIElEIGZvciBhIHdvcmtmbG93IHJ1bi5cbi8vIFJlcGxpY2F0ZXMgZ2V0V29ya2Zsb3dSdW5TdHJlYW1JZCgpIGZyb20gdXRpbC50cyBpbnNpZGUgdGhlIFF1aWNrSlMgVk0uXG4vLyBVc2VzIHRoZSBidWlsdC1pbiBidG9hKCkgZm9yIGJhc2U2NHVybCBlbmNvZGluZy5cbmdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0dFVF9TVFJFQU1fSURcIildID0gZnVuY3Rpb24obmFtZXNwYWNlKSB7XG4gIHZhciBydW5JZCA9IGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0NPTlRFWFRcIildXG4gICAgPyBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19DT05URVhUXCIpXS53b3JrZmxvd1J1bklkXG4gICAgOiBcIlwiO1xuICB2YXIgc3RyZWFtSWQgPSBydW5JZC5yZXBsYWNlKFwid3J1bl9cIiwgXCJzdHJtX1wiKSArIFwiX3VzZXJcIjtcbiAgaWYgKCFuYW1lc3BhY2UpIHJldHVybiBzdHJlYW1JZDtcbiAgLy8gYmFzZTY0dXJsOiBidG9hIHRoZW4gcmVwbGFjZSArIHdpdGggLSwgLyB3aXRoIF8sIHN0cmlwID1cbiAgdmFyIGI2NCA9IGJ0b2EobmFtZXNwYWNlKS5yZXBsYWNlKC9cXFxcKy9nLCBcIi1cIikucmVwbGFjZSgvXFxcXC8vZywgXCJfXCIpLnJlcGxhY2UoLz0rJC8sIFwiXCIpO1xuICByZXR1cm4gc3RyZWFtSWQgKyBcIl9cIiArIGI2NDtcbn07XG5gO1xuXG4vLyAtLS0tIFJ1bnRpbWUgLS0tLVxuXG4vKipcbiAqIFBoYXNlIDEg4oCUIHN0YXRpYyAocnVuLWluZGVwZW5kZW50KSBWTSBpbml0aWFsaXphdGlvbi5cbiAqXG4gKiBDcmVhdGVzIGEgUXVpY2tKUyBWTSBhbmQgbG9hZHMgZXZlcnl0aGluZyB0aGF0IGRvZXMgbm90IGRlcGVuZCBvbiBhXG4gKiBzcGVjaWZpYyB3b3JrZmxvdyBydW46IHRoZSBzZXJkZSBidW5kbGUgKGRldmFsdWUtYmFzZWQgc2VyaWFsaXphdGlvblxuICogdXNlZCBhdCB0aGUgaG9zdC9WTSBib3VuZGFyeSkgYW5kIHRoZSB3b3JrZmxvdy1wcmltaXRpdmUgYm9vdHN0cmFwXG4gKiAodXNlU3RlcCAvIHNsZWVwIC8gY3JlYXRlSG9vayAvIFJlc3BvbnNlLVJlcXVlc3QgcG9seWZpbGxzKS5cbiAqXG4gKiBgZ2V0Tm93TXNgIGJhY2tzIHRoZSBWTSdzIFdBU0kgY2xvY2sgKGBEYXRlLm5vdygpYCAvIGBuZXcgRGF0ZSgpYFxuICogaW5zaWRlIHRoZSBWTSkuIFRoZSBjYWxsYmFjayBpdHNlbGYgaXMgc3RhdGljIOKAlCB0aGUgcGVyLXJ1biBzdGF0ZSBpdFxuICogcmVhZHMgbGl2ZXMgb24gdGhlIGhvc3QgYW5kIGlzIGFkdmFuY2VkIGFzIGV2ZW50cyBhcmUgY29uc3VtZWQsXG4gKiBtYXRjaGluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBkZXRlcm1pbmlzdGljIHJlcGxheSBjbG9jay5cbiAqXG4gKiBUaGlzIHBoYXNlIGlzIHRoZSBmdXR1cmUgYm91bmRhcnkgZm9yIFZNLW1lbW9yeSBzbmFwc2hvdHRpbmc6IGFcbiAqIGJ1aWxkLXRpbWUgc25hcHNob3QgY2FuIGNhcHR1cmUgdGhlIFZNIHJpZ2h0IGFmdGVyIHRoaXMgZnVuY3Rpb24gYW5kXG4gKiBuZXcgcnVucyBjYW4gcmVzdG9yZSBmcm9tIGl0IGluc3RlYWQgb2YgcGF5aW5nIFZNIGNyZWF0aW9uICsgZXZhbCBjb3N0XG4gKiAoYFF1aWNrSlMucmVzdG9yZWAgYWNjZXB0cyB0aGUgc2FtZSB3YXNpIG92ZXJyaWRlKS5cbiAqL1xuLyoqXG4gKiBMb29zZWx5LXR5cGVkIGFjY2Vzc29yIGZvciB0aGUgYFdlYkFzc2VtYmx5YCBnbG9iYWwuIFRoZSBwYWNrYWdlXG4gKiB0c2NvbmZpZydzIGBsaWI6IFtcImVzMjAyMlwiXWAgZG9lcyBub3QgaW5jbHVkZSB0aGUgRE9NIGxpYiB3aGVyZSB0aGVcbiAqIGBXZWJBc3NlbWJseWAgbmFtZXNwYWNlIHR5cGVzIGxpdmU7IHRoZSBydW50aW1lIGdsb2JhbCBpcyBhdmFpbGFibGUgb25cbiAqIGV2ZXJ5IFdBU00tY2FwYWJsZSBwbGF0Zm9ybSB0aGlzIGVuZ2luZSB0YXJnZXRzLlxuICovXG5jb25zdCBXZWJBc3NlbWJseUdsb2JhbCA9IChnbG9iYWxUaGlzIGFzIGFueSkuV2ViQXNzZW1ibHkgYXMge1xuICBjb21waWxlKGJ5dGVzOiBVaW50OEFycmF5KTogUHJvbWlzZTxvYmplY3Q+O1xufTtcblxudHlwZSBDb21waWxlZEV4dGVuc2lvbiA9IE9taXQ8RXh0ZW5zaW9uRGVzY3JpcHRvciwgJ3dhc20nPiAmIHtcbiAgd2FzbTogRXh0ZW5zaW9uRGVzY3JpcHRvclsnd2FzbSddO1xufTtcblxuLyoqXG4gKiBQcm9jZXNzLXdpZGUgY2FjaGUgb2YgdGhlIGNvbXBpbGVkIGBXZWJBc3NlbWJseS5Nb2R1bGVgcyBmb3IgdGhlIG1haW5cbiAqIFF1aWNrSlMgcnVudGltZSBhbmQgaXRzIG5hdGl2ZSBleHRlbnNpb25zLiBgV2ViQXNzZW1ibHkuY29tcGlsZWAgb2YgdGhlXG4gKiB+NjAwIEtCIHJ1bnRpbWUgYmluYXJ5IGlzIHRoZSBtb3N0IGV4cGVuc2l2ZSBwYXJ0IG9mIFZNIGNyZWF0aW9uIGFuZCBpc1xuICogcHVyZSAobm8gcGVyLVZNIHN0YXRlIOKAlCBpbnN0YW50aWF0aW9uIGJpbmRzIHRoZSBwZXItVk0gbWVtb3J5KSwgc28gaXRcbiAqIG9ubHkgbmVlZHMgdG8gaGFwcGVuIG9uY2UgcGVyIHByb2Nlc3MuIFRoZSBwcm9taXNlIGlzIGNhY2hlZCAobm90IHRoZVxuICogcmVzdWx0KSBzbyBjb25jdXJyZW50IGZpcnN0IGludm9jYXRpb25zIHNoYXJlIGEgc2luZ2xlIGNvbXBpbGF0aW9uLlxuICovXG5sZXQgY29tcGlsZWRBc3NldHNQcm9taXNlOlxuICB8IFByb21pc2U8e1xuICAgICAgd2FzbTogb2JqZWN0O1xuICAgICAgZXh0ZW5zaW9uczogQ29tcGlsZWRFeHRlbnNpb25bXTtcbiAgICB9PlxuICB8IHVuZGVmaW5lZDtcblxuZnVuY3Rpb24gZ2V0Q29tcGlsZWRBc3NldHMoKSB7XG4gIGlmICghY29tcGlsZWRBc3NldHNQcm9taXNlKSB7XG4gICAgY29tcGlsZWRBc3NldHNQcm9taXNlID0gKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IFt3YXNtLCAuLi5leHRlbnNpb25Nb2R1bGVzXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgV2ViQXNzZW1ibHlHbG9iYWwuY29tcGlsZShxdWlja2pzV2FzbSksXG4gICAgICAgIC4uLnF1aWNranNFeHRlbnNpb25zLm1hcCgoZXh0KSA9PlxuICAgICAgICAgIFdlYkFzc2VtYmx5R2xvYmFsLmNvbXBpbGUoZXh0Lndhc20gYXMgVWludDhBcnJheSlcbiAgICAgICAgKSxcbiAgICAgIF0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgd2FzbSxcbiAgICAgICAgZXh0ZW5zaW9uczogcXVpY2tqc0V4dGVuc2lvbnMubWFwKChleHQsIGkpID0+ICh7XG4gICAgICAgICAgLi4uZXh0LFxuICAgICAgICAgIHdhc206IGV4dGVuc2lvbk1vZHVsZXNbaV0gYXMgRXh0ZW5zaW9uRGVzY3JpcHRvclsnd2FzbSddLFxuICAgICAgICB9KSksXG4gICAgICB9O1xuICAgIH0pKCk7XG4gICAgLy8gT24gZmFpbHVyZSwgY2xlYXIgdGhlIGNhY2hlIHNvIGEgbGF0ZXIgaW52b2NhdGlvbiBjYW4gcmV0cnkgcmF0aGVyXG4gICAgLy8gdGhhbiBiZWluZyBzdHVjayB3aXRoIGEgcmVqZWN0ZWQgcHJvbWlzZSBmb3JldmVyLlxuICAgIGNvbXBpbGVkQXNzZXRzUHJvbWlzZS5jYXRjaCgoKSA9PiB7XG4gICAgICBjb21waWxlZEFzc2V0c1Byb21pc2UgPSB1bmRlZmluZWQ7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGNvbXBpbGVkQXNzZXRzUHJvbWlzZTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaW5pdFdvcmtmbG93Vk0oXG4gIGdldE5vd01zOiAoKSA9PiBudW1iZXIsXG4gIGludGVycnVwdEJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0XG4pOiBQcm9taXNlPFF1aWNrSlM+IHtcbiAgLy8gRGV0ZXJtaW5pc3RpYyByZXBsYXkgY2xvY2s6IERhdGUubm93KCkgLyBuZXcgRGF0ZSgpIGluc2lkZSB0aGUgVk1cbiAgLy8gcmVhZCB0aGUgaG9zdC1jb250cm9sbGVkIGNsb2NrIGluc3RlYWQgb2Ygd2FsbCB0aW1lLiBSZXBsYXlcbiAgLy8gcmUtZXhlY3V0ZXMgdGhlIHdvcmtmbG93IGZyb20gdGhlIHRvcCBvbiBldmVyeSBpbnZvY2F0aW9uLCBzbyB0aGVcbiAgLy8gY2xvY2sgbXVzdCBiZSBkZXJpdmVkIGZyb20gdGhlIGV2ZW50IGxvZyAobm90IHJlYWwgdGltZSkgZm9yIHRoZVxuICAvLyB3b3JrZmxvdyB0byBvYnNlcnZlIHN0YWJsZSB0aW1lc3RhbXBzIGFjcm9zcyBpbnZvY2F0aW9ucy5cbiAgY29uc3Qgd2FzaTogV2FzaU9wdGlvbnMgPSAobWVtb3J5KSA9PiAoe1xuICAgIGNsb2NrX3RpbWVfZ2V0KF9jbG9ja0lkOiBudW1iZXIsIF9wcmVjaXNpb246IGJpZ2ludCwgcmVzdWx0UHRyOiBudW1iZXIpIHtcbiAgICAgIGNvbnN0IHRpbWVOcyA9IEJpZ0ludChNYXRoLnJvdW5kKGdldE5vd01zKCkpKSAqIDFfMDAwXzAwMG47XG4gICAgICBuZXcgRGF0YVZpZXcobWVtb3J5LmJ1ZmZlcikuc2V0QmlnVWludDY0KHJlc3VsdFB0ciwgdGltZU5zLCB0cnVlKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH0sXG4gIH0pO1xuXG4gIGNvbnN0IGFzc2V0cyA9IGF3YWl0IGdldENvbXBpbGVkQXNzZXRzKCk7XG4gIGNvbnN0IHZtID0gYXdhaXQgUXVpY2tKUy5jcmVhdGUoe1xuICAgIHdhc206IGFzc2V0cy53YXNtIGFzIG5ldmVyLFxuICAgIG1lbW9yeUxpbWl0OiAyNTYgKiAxMDI0ICogMTAyNCxcbiAgICBpbnRlcnJ1cHRIYW5kbGVyOiBjcmVhdGVJbnRlcnJ1cHRIYW5kbGVyKGludGVycnVwdEJ1ZGdldCksXG4gICAgZXh0ZW5zaW9uczogYXNzZXRzLmV4dGVuc2lvbnMsXG4gICAgd2FzaSxcbiAgfSk7XG5cbiAgLy8gRXZhbHVhdGUgdGhlIFZNIHNlcmRlIGJ1bmRsZVxuICB2bS5ldmFsQ29kZShWTV9TRVJERV9CVU5ETEUsICd2bS1zZXJkZS5qcycpLmRpc3Bvc2UoKTtcblxuICAvLyBCb290c3RyYXAgd29ya2Zsb3cgcHJpbWl0aXZlc1xuICB2bS5ldmFsQ29kZShWTV9CT09UU1RSQVAsICdib290c3RyYXAuanMnKS5kaXNwb3NlKCk7XG5cbiAgcmV0dXJuIHZtO1xufVxuXG4vKipcbiAqIEEgbGl2ZSBRdWlja0pTIHdvcmtmbG93IGludm9jYXRpb24uIFdoZW4gdGhlIGluaXRpYWwgYHJlc3VsdGAgaXNcbiAqIGBzdXNwZW5kZWRgLCB0aGUgVk0gaXMga2VwdCBhbGl2ZSBzbyB0aGUgY2FsbGVyIGNhbiBmZWVkIG5ld2x5IHJlY29yZGVkXG4gKiBldmVudHMgKGUuZy4gdGVybWluYWwgZXZlbnRzIG9mIGlubGluZS1leGVjdXRlZCBzdGVwcykgaW50byB0aGUgU0FNRSBWTVxuICogdmlhIGBjb250aW51ZVdpdGhFdmVudHNgIOKAlCByZXN1bWluZyBleGVjdXRpb24gZXhhY3RseSB3aGVyZSBpdCBsZWZ0IG9mZlxuICogd2l0aG91dCBhIGZyZXNoLVZNIHJlLXJlcGxheS4gVGVybWluYWwgcmVzdWx0cyBkaXNwb3NlIHRoZSBWTVxuICogYXV0b21hdGljYWxseTsgYGRpc3Bvc2UoKWAgbXVzdCBiZSBjYWxsZWQgd2hlbiBhYmFuZG9uaW5nIGEgc3VzcGVuZGVkXG4gKiBzZXNzaW9uIChpZGVtcG90ZW50KS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBRdWlja0pTV29ya2Zsb3dTZXNzaW9uIHtcbiAgcmVzdWx0OiBRdWlja0pTUnVudGltZVJlc3VsdDtcbiAgLyoqXG4gICAqIFByb2Nlc3MgbmV3bHkgcmVjb3JkZWQgZXZlbnRzIGluIHRoZSBsaXZlIFZNIGFuZCByZS1ldmFsdWF0ZSB0aGVcbiAgICogd29ya2Zsb3cgc3RhdGUuIE9ubHkgdmFsaWQgd2hpbGUgdGhlIGxhc3QgcmVzdWx0IHdhcyBgc3VzcGVuZGVkYC5cbiAgICogUmVzZXRzIHRoZSBWTSdzIGludGVycnVwdCBidWRnZXQgZm9yIHRoZSBuZXcgZXhlY3V0aW9uIGJ1cnN0LlxuICAgKi9cbiAgY29udGludWVXaXRoRXZlbnRzKG5ld0V2ZW50czogRXZlbnRbXSk6IFByb21pc2U8UXVpY2tKU1J1bnRpbWVSZXN1bHQ+O1xuICAvKiogRGlzcG9zZSB0aGUgVk0gaWYgaXQgaXMgc3RpbGwgYWxpdmUuIFNhZmUgdG8gY2FsbCBtdWx0aXBsZSB0aW1lcy4gKi9cbiAgZGlzcG9zZSgpOiB2b2lkO1xufVxuXG4vKipcbiAqIFJ1biBhIHdvcmtmbG93IGludm9jYXRpb24gdG8gaXRzIGZpcnN0IHNldHRsZWQgc3RhdGUgYW5kIGRpc3Bvc2UgdGhlXG4gKiBWTS4gQ29udmVuaWVuY2Ugd3JhcHBlciBvdmVyIHtAbGluayBzdGFydFF1aWNrSlNXb3JrZmxvd30gZm9yIGNhbGxlcnNcbiAqIChhbmQgdGVzdHMpIHRoYXQgZG9uJ3QgdXNlIGxpdmUtVk0gY29udGludWF0aW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuUXVpY2tKU1dvcmtmbG93KFxuICBvcHRpb25zOiBRdWlja0pTUnVudGltZU9wdGlvbnNcbik6IFByb21pc2U8UXVpY2tKU1J1bnRpbWVSZXN1bHQ+IHtcbiAgY29uc3Qgc2Vzc2lvbiA9IGF3YWl0IHN0YXJ0UXVpY2tKU1dvcmtmbG93KG9wdGlvbnMpO1xuICBzZXNzaW9uLmRpc3Bvc2UoKTtcbiAgcmV0dXJuIHNlc3Npb24ucmVzdWx0O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRRdWlja0pTV29ya2Zsb3coXG4gIG9wdGlvbnM6IFF1aWNrSlNSdW50aW1lT3B0aW9uc1xuKTogUHJvbWlzZTxRdWlja0pTV29ya2Zsb3dTZXNzaW9uPiB7XG4gIGNvbnN0IHsgd29ya2Zsb3dDb2RlLCB3b3JrZmxvd0lkLCB3b3JrZmxvd1J1biwgZXZlbnRzIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IHN0YXJ0ZWRBdCA9IHdvcmtmbG93UnVuLnN0YXJ0ZWRBdCA/ICt3b3JrZmxvd1J1bi5zdGFydGVkQXQgOiBEYXRlLm5vdygpO1xuXG4gIC8vIERldGVybWluaXN0aWMgUFJORyBzZWVkIOKAlCBpZGVudGljYWwgZm9yIEVWRVJZIGludm9jYXRpb24gb2YgdGhlIHNhbWVcbiAgLy8gcnVuLiBGdWxsIGV2ZW50IHJlcGxheSByZXF1aXJlcyB0aGlzOiBlYWNoIGludm9jYXRpb24gcmUtZXhlY3V0ZXMgdGhlXG4gIC8vIHdvcmtmbG93IGZyb20gdGhlIHRvcCBhbmQgbXVzdCByZWdlbmVyYXRlIHRoZSBleGFjdCBzYW1lIGNvcnJlbGF0aW9uSWRcbiAgLy8gc2VxdWVuY2Ugc28gdGhhdCBwZW5kaW5nIG9wZXJhdGlvbnMgcmUtY3JlYXRlZCBieSByZXBsYXkgbWF0Y2ggdGhlXG4gIC8vIGV2ZW50cyByZWNvcmRlZCBieSBlYXJsaWVyIGludm9jYXRpb25zLiBTZXF1ZW50aWFsIG9wZXJhdGlvbnMgd2l0aGluXG4gIC8vIG9uZSBleGVjdXRpb24gc3RpbGwgZ2V0IGRpc3RpbmN0IGlkcyBiZWNhdXNlIHRoZSBQUk5HIGFkdmFuY2VzIGFzIHRoZVxuICAvLyB3b3JrZmxvdyBkcmF3cyBmcm9tIGl0LiBJZGVudGljYWwgc2VlZGluZyBhY3Jvc3MgQ09OQ1VSUkVOVCBpbnZvY2F0aW9uc1xuICAvLyBvZiB0aGUgc2FtZSBydW4gaXMgYWxzbyBsb2FkLWJlYXJpbmc6IGJvdGggcHJvZHVjZSB0aGUgc2FtZSBpZHMsIGFuZFxuICAvLyB0aGUgd29ybGQncyBwZXItKHJ1bklkLCBjb3JyZWxhdGlvbklkKSB1bmlxdWVuZXNzIHR1cm5zIHRoZSBkdXBsaWNhdGVcbiAgLy8gYGV2ZW50cy5jcmVhdGVgIGludG8gYW4gRW50aXR5Q29uZmxpY3RFcnJvciB0aGF0IHRoZSBlbnRyeXBvaW50XG4gIC8vIHN3YWxsb3dzLlxuICAvL1xuICAvLyBUaGUgc2VlZCBpbnB1dHMgTVVTVCBiZSBzdGFibGUgYWNyb3NzIGludm9jYXRpb25zLiBOb3RhYmx5XG4gIC8vIGBzdGFydGVkQXRgIGlzIE5PVDogdW5kZXIgdHVyYm8gdGhlIGZpcnN0IGludm9jYXRpb24gcnVucyBhZ2FpbnN0IGFcbiAgLy8gc3ludGhlc2l6ZWQgcnVuIG9iamVjdCB3aG9zZSB0aW1lc3RhbXBzIGRpZmZlciBmcm9tIHRoZSBkdXJhYmx5XG4gIC8vIHN0b3JlZCBvbmVzIHRoYXQgbGF0ZXIgaW52b2NhdGlvbnMgbG9hZC4gTWF0Y2hlcyB0aGUgbm9kZTp2bVxuICAvLyBlbmdpbmUncyBzZWVkICh3b3JrZmxvdy50cykuXG4gIGNvbnN0IHNlZWQgPSBbXG4gICAgd29ya2Zsb3dSdW4ucnVuSWQsXG4gICAgd29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLFxuICAgIHdvcmtmbG93UnVuLmRlcGxveW1lbnRJZCxcbiAgXS5qb2luKCc6Jyk7XG4gIGNvbnN0IHJuZyA9IHNlZWRyYW5kb20oc2VlZCk7XG5cbiAgLy8gU2VlZGVkIG5hbm9pZCBnZW5lcmF0b3Ig4oCUIHVzZXMgdGhlIHNhbWUgbmFub2lkIHBhY2thZ2UgYW5kIHNlZWRlZCBQUk5HXG4gIC8vIGFzIHRoZSBub2RlOnZtIGVuZ2luZSBmb3IgY29uc2lzdGVudCB0b2tlbiBnZW5lcmF0aW9uLlxuICBjb25zdCBnZW5lcmF0ZU5hbm9pZCA9IG5hbm9pZC5jdXN0b21SYW5kb20obmFub2lkLnVybEFscGhhYmV0LCAyMSwgKHNpemUpID0+XG4gICAgbmV3IFVpbnQ4QXJyYXkoc2l6ZSkubWFwKCgpID0+IDI1NiAqIHJuZygpKVxuICApO1xuXG4gIC8vIERldGVybWluaXN0aWMgcmVwbGF5IGNsb2NrLCBtaXJyb3JpbmcgdGhlIG5vZGU6dm0gZW5naW5lIChzZWVcbiAgLy8gd29ya2Zsb3cudHMpOiB0aGUgaW5pdGlhbCB2YWx1ZSBpcyB0aGUgcnVuJ3MgY3JlYXRpb24gdGltZSByZWNvdmVyZWRcbiAgLy8gZnJvbSB0aGUgVUxJRCBlbWJlZGRlZCBpbiBgcnVuSWRgIChmYWxsaW5nIGJhY2sgdG8gYGNyZWF0ZWRBdGApLCBhbmRcbiAgLy8gaXQgYWR2YW5jZXMgdG8gZWFjaCBwcm9jZXNzZWQgZXZlbnQncyBgY3JlYXRlZEF0YCBhcyB0aGUgZXZlbnQgbG9nIGlzXG4gIC8vIHJlcGxheWVkLiBNb25vdG9uaWMgKE1hdGgubWF4KSBzbyB0aGUgb3V0ZXIgcHJvY2Vzc0V2ZW50cyByZS1zY2FuXG4gIC8vIGxvb3AgY2FuJ3QgbW92ZSB0aGUgY2xvY2sgYmFja3dhcmRzIG1pZC1leGVjdXRpb24uXG4gIGxldCB2bU5vd01zID1cbiAgICBydW5JZENyZWF0ZWRBdCh3b3JrZmxvd1J1bi5ydW5JZCkgPz8gKCt3b3JrZmxvd1J1bi5jcmVhdGVkQXQgfHwgc3RhcnRlZEF0KTtcbiAgY29uc3QgYWR2YW5jZUNsb2NrID0gKG1zOiBudW1iZXIpID0+IHtcbiAgICBpZiAoTnVtYmVyLmlzRmluaXRlKG1zKSkgdm1Ob3dNcyA9IE1hdGgubWF4KHZtTm93TXMsIG1zKTtcbiAgfTtcblxuICAvLyAtLS0tIFBoYXNlIDE6IHN0YXRpYyBpbml0aWFsaXphdGlvbiAtLS0tXG4gIGNvbnN0IGludGVycnVwdEJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0ID0geyBzdGFydDogRGF0ZS5ub3coKSB9O1xuICBjb25zdCB2bSA9IGF3YWl0IGluaXRXb3JrZmxvd1ZNKCgpID0+IHZtTm93TXMsIGludGVycnVwdEJ1ZGdldCk7XG5cbiAgLy8gQW55IHRocm93IGJldHdlZW4gaGVyZSBhbmQgdGhlIHRlcm1pbmFsIHBhdGhzICh3aGljaCBkaXNwb3NlIHRoZSBWTVxuICAvLyBpbnNpZGUgY2hlY2tXb3JrZmxvd1N0YXRlIC8gZXh0cmFjdEVycm9yIGJlZm9yZSBSRVRVUk5JTkcpIHdvdWxkIGxlYWtcbiAgLy8gYSBsaXZlIFF1aWNrSlMgaW5zdGFuY2UgYW5kIGl0cyBXQVNNIGxpbmVhciBtZW1vcnkgZm9yIHRoZSBsaWZldGltZVxuICAvLyBvZiB0aGUgY29tcHV0ZSBpbnN0YW5jZSDigJQgd2hpY2ggaXMgcmV1c2VkLiBEaXNwb3NlIG9uIHRoZSB3YXkgb3V0IG9mXG4gIC8vIGFuIGV4Y2VwdGlvbmFsIGV4aXQgYW5kIHJldGhyb3cuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHJ1bldvcmtmbG93SW5WTSgpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0cnkge1xuICAgICAgdm0uZGlzcG9zZSgpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gQWxyZWFkeSBkaXNwb3NlZCBieSBhIHRlcm1pbmFsIHBhdGgg4oCUIGlnbm9yZS5cbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG5cbiAgLy8gLS0tLSBQaGFzZSAyOiBwZXItcnVuIGluaXRpYWxpemF0aW9uIC0tLS1cbiAgYXN5bmMgZnVuY3Rpb24gcnVuV29ya2Zsb3dJblZNKCk6IFByb21pc2U8UXVpY2tKU1dvcmtmbG93U2Vzc2lvbj4ge1xuICAgIHZtLmV2YWxDb2RlKFxuICAgICAgYGdsb2JhbFRoaXMuX193b3JsZENhcGFiaWxpdGllcyA9ICR7SlNPTi5zdHJpbmdpZnkob3B0aW9ucy53b3JsZENhcGFiaWxpdGllcyl9O2BcbiAgICApLmRpc3Bvc2UoKTtcblxuICAgIC8vIFNlZWRlZCBNYXRoLnJhbmRvbVxuICAgIHtcbiAgICAgIHVzaW5nIHJhbmRvbUZuID0gdm0ubmV3RnVuY3Rpb24oJ3JhbmRvbScsICgpID0+IHZtLm5ld051bWJlcihybmcoKSkpO1xuICAgICAgdXNpbmcgbWF0aCA9IHZtLmdsb2JhbC5nZXRQcm9wKCdNYXRoJyk7XG4gICAgICBtYXRoLnNldFByb3AoJ3JhbmRvbScsIHJhbmRvbUZuKTtcbiAgICB9XG5cbiAgICAvLyBTZWVkZWQgbmFub2lkIGdlbmVyYXRvclxuICAgIHtcbiAgICAgIHVzaW5nIG5hbm9pZEZuID0gdm0ubmV3RnVuY3Rpb24oJ19fZ2VuZXJhdGVOYW5vaWQnLCAoKSA9PlxuICAgICAgICB2bS5uZXdTdHJpbmcoZ2VuZXJhdGVOYW5vaWQoKSlcbiAgICAgICk7XG4gICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fZ2VuZXJhdGVOYW5vaWQnLCBuYW5vaWRGbik7XG4gICAgfVxuXG4gICAgLy8gSW5qZWN0IGEgZGV0ZXJtaW5pc3RpYyB0aW1lc3RhbXAgZm9yIHRoZSBWTSdzIFVMSUQgZmFjdG9yeS4gVUxJRHNcbiAgICAvLyBwcm9kdWNlZCBpbnNpZGUgdGhlIFZNIHVzZSB0aGlzIGFzIHRoZWlyIHRpbWUgcHJlZml4IGluc3RlYWQgb2ZcbiAgICAvLyBEYXRlLm5vdygpLCBzbyB0d28gY29uY3VycmVudCB3b3JrZmxvdyBpbnZvY2F0aW9ucyBvZiB0aGUgc2FtZSBydW5cbiAgICAvLyBwcm9kdWNlIElERU5USUNBTCBjb3JyZWxhdGlvbklkcyAodGhlIHJhbmRvbSBwb3J0aW9uIGFsc28gbWF0Y2hlc1xuICAgIC8vIGJlY2F1c2UgdGhlIFBSTkcgaXMgc2VlZGVkIHRoZSBzYW1lIHdheSkgYW5kIHRoZSB3b3JsZCdzXG4gICAgLy8gRW50aXR5Q29uZmxpY3RFcnJvciBvbiBgZXZlbnRzLmNyZWF0ZWAgZGVkdXBzIG9uZSBvZiBlYWNoIHBhaXIuXG4gICAgLy8gRGVyaXZlZCBmcm9tIHRoZSBydW5JZCdzIGVtYmVkZGVkIFVMSUQgKHN0YWJsZSBhY3Jvc3MgaW52b2NhdGlvbnMgYnlcbiAgICAvLyBjb25zdHJ1Y3Rpb24g4oCUIHVubGlrZSBgc3RhcnRlZEF0YCwgd2hpY2ggZGlmZmVycyBiZXR3ZWVuIHR1cmJvJ3NcbiAgICAvLyBzeW50aGVzaXplZCBydW4gb2JqZWN0IGFuZCB0aGUgZHVyYWJseSBzdG9yZWQgcnVuKS5cbiAgICB2bS5ldmFsQ29kZShcbiAgICAgIGBnbG9iYWxUaGlzLl9fdWxpZFRpbWVzdGFtcCA9ICR7cnVuSWRDcmVhdGVkQXQod29ya2Zsb3dSdW4ucnVuSWQpID8/ICgrd29ya2Zsb3dSdW4uY3JlYXRlZEF0IHx8IHN0YXJ0ZWRBdCl9O2BcbiAgICApLmRpc3Bvc2UoKTtcblxuICAgIC8vIGBwcm9jZXNzLmVudmAg4oCUIHBhcml0eSB3aXRoIHRoZSBub2RlOnZtIGVuZ2luZSwgd2hpY2ggZXhwb3NlcyBhIGZyb3plblxuICAgIC8vIGNvcHkgb2YgdGhlIGhvc3QgZW52ICh2bS9pbmRleC50cykuIEluamVjdGVkIHBlciBydW4gc28gdGhlIHNuYXBzaG90IG9mXG4gICAgLy8gdGhlIGVudiBpcyB0YWtlbiBhdCBpbnZvY2F0aW9uIHRpbWUsIHNhbWUgYXMgbm9kZS5cbiAgICB7XG4gICAgICBjb25zdCBlbnZIYW5kbGUgPSB2bS5uZXdTdHJpbmcoSlNPTi5zdHJpbmdpZnkocHJvY2Vzcy5lbnYpKTtcbiAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX193ZGtfZW52JywgZW52SGFuZGxlKTtcbiAgICAgIGVudkhhbmRsZS5kaXNwb3NlKCk7XG4gICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgJ2dsb2JhbFRoaXMucHJvY2VzcyA9IHsgZW52OiBPYmplY3QuZnJlZXplKEpTT04ucGFyc2UoZ2xvYmFsVGhpcy5fX3dka19lbnYpKSB9OycgK1xuICAgICAgICAgICdkZWxldGUgZ2xvYmFsVGhpcy5fX3dka19lbnY7J1xuICAgICAgKS5kaXNwb3NlKCk7XG4gICAgfVxuXG4gICAgLy8gRXhlY3V0ZSB0aGUgd29ya2Zsb3cgYnVuZGxlIOKAlCB1c2UgdGhlIHdvcmtmbG93SWQgYXMgdGhlIGV2YWwgZmlsZW5hbWVcbiAgICAvLyBzbyBRdWlja0pTIHN0YWNrIHRyYWNlcyByZWZlcmVuY2UgdGhlIHdvcmtmbG93IG5hbWUsIGVuYWJsaW5nIHNvdXJjZSBtYXBcbiAgICAvLyByZW1hcHBpbmcgYnkgcmVtYXBFcnJvclN0YWNrICh3aGljaCBtYXRjaGVzIGZyYW1lcyBieSBmaWxlbmFtZSkuXG4gICAgLy8gRXZhbHVhdGVkIGluIHRoZSBwZXItcnVuIHBoYXNlIChhZnRlciBNYXRoLnJhbmRvbSBzZWVkaW5nKSBzbyB0aGF0XG4gICAgLy8gbW9kdWxlLXNjb3BlIHVzZXIgY29kZSBkcmF3cyBmcm9tIHRoZSBzZWVkZWQgUFJORywgbWF0Y2hpbmcgdGhlXG4gICAgLy8gbm9kZTp2bSBlbmdpbmUncyByZXBsYXkgZGV0ZXJtaW5pc20uXG4gICAgdHJ5IHtcbiAgICAgIHZtLmV2YWxDb2RlKHdvcmtmbG93Q29kZSwgd29ya2Zsb3dJZCB8fCAnd29ya2Zsb3cuanMnKS5kaXNwb3NlKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICByZXR1cm4gbWFrZVNldHRsZWRTZXNzaW9uKFxuICAgICAgICBleHRyYWN0RXJyb3Iodm0sIGVyciwgJ1dvcmtmbG93IGV2YWx1YXRpb24gZmFpbGVkJylcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gRXh0cmFjdCB3b3JrZmxvdyBhcmd1bWVudHMuIFByZWZlciB0aGUgcnVuX2NyZWF0ZWQgZXZlbnQ7IGZhbGwgYmFja1xuICAgIC8vIHRvIHRoZSBxdWV1ZSBtZXNzYWdlJ3MgcnVuSW5wdXQgaWYgdGhlIGV2ZW50IGxvZyBpcyBpbmNvbXBsZXRlXG4gICAgLy8gKGV2ZW50dWFsbHktY29uc2lzdGVudCByZWFkIGFmdGVyIHN0YXJ0KCkpLiBGYWlsaW5nIHRvIGZpbmQgaW5wdXRcbiAgICAvLyBmb3IgYSBmaXJzdCBpbnZvY2F0aW9uIGlzIGZhdGFsIOKAlCBydW5uaW5nIHRoZSB3b3JrZmxvdyBmdW5jdGlvblxuICAgIC8vIHdpdGggbm8gYXJncyB3b3VsZCBzaWxlbnRseSB0dXJuIHR5cGVkIGFyZ3VtZW50cyBpbnRvIGB1bmRlZmluZWRgXG4gICAgLy8gYW5kLCBmb3IgcmVjdXJzaXZlIHdvcmtmbG93cywgcHJvZHVjZSBleHBvbmVudGlhbCBmYW4tb3V0LlxuICAgIGNvbnN0IHJ1bkNyZWF0ZWRFdmVudCA9IGV2ZW50cy5maW5kKChlKSA9PiBlLmV2ZW50VHlwZSA9PT0gJ3J1bl9jcmVhdGVkJyk7XG4gICAgY29uc3QgcnVuQ3JlYXRlZElucHV0ID1cbiAgICAgIHJ1bkNyZWF0ZWRFdmVudCAmJiAnZXZlbnREYXRhJyBpbiBydW5DcmVhdGVkRXZlbnRcbiAgICAgICAgPyAocnVuQ3JlYXRlZEV2ZW50LmV2ZW50RGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik/LmlucHV0XG4gICAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IHJ1bklucHV0OiB1bmtub3duID1cbiAgICAgIHJ1bkNyZWF0ZWRJbnB1dCA/PyAob3B0aW9ucy5ydW5JbnB1dD8uaW5wdXQgYXMgdW5rbm93bik7XG5cbiAgICBpZiAocnVuSW5wdXQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICBjb25zdCBkZWNyeXB0ZWRJbnB1dCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICBydW5JbnB1dCxcbiAgICAgICAgb3B0aW9ucy5lbmNyeXB0aW9uS2V5XG4gICAgICApO1xuICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBydW4gaW5wdXQgZm9ybWF0Jywge1xuICAgICAgICBwcmVmaXg6IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkZWNyeXB0ZWRJbnB1dC5zdWJhcnJheSgwLCA0KSksXG4gICAgICAgIGJ5dGVMZW5ndGg6IGRlY3J5cHRlZElucHV0LmJ5dGVMZW5ndGgsXG4gICAgICAgIHNvdXJjZTogcnVuQ3JlYXRlZElucHV0ID8gJ3J1bl9jcmVhdGVkJyA6ICdxdWV1ZU1lc3NhZ2UucnVuSW5wdXQnLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBpbnB1dEhhbmRsZSA9IHZtLm5ld1VpbnQ4QXJyYXkoZGVjcnlwdGVkSW5wdXQpO1xuICAgICAgdm0uc2V0UHJvcCh2bS5nbG9iYWwsICdfX3dka19pbnB1dCcsIGlucHV0SGFuZGxlKTtcbiAgICAgIGlucHV0SGFuZGxlLmRpc3Bvc2UoKTtcbiAgICB9IGVsc2UgaWYgKHJ1bklucHV0ID09PSB1bmRlZmluZWQgJiYgZXZlbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIFRoZSBldmVudCBsb2cgaXMgbm9uLWVtcHR5ICh3ZSBnb3QgcnVuX3N0YXJ0ZWQgb3Igc2ltaWxhcikgYnV0XG4gICAgICAvLyBubyBydW5fY3JlYXRlZCBldmVudCB3YXMgZm91bmQgYW5kIG5vIHF1ZXVlLXByb3ZpZGVkIHJ1bklucHV0IGlzXG4gICAgICAvLyBhdmFpbGFibGUuIFRoaXMgaXMgdGhlIHJhY2UgY29uZGl0aW9uIG9ic2VydmVkIGR1cmluZyB0aGUgZmliXG4gICAgICAvLyBpbmNpZGVudCDigJQgc2lsZW50bHkgZHJvcHBpbmcgYXJndW1lbnRzIHdvdWxkIHR1cm4gYG5gIGludG9cbiAgICAgIC8vIGB1bmRlZmluZWRgIGFuZCwgZm9yIHJlY3Vyc2l2ZSB3b3JrZmxvd3MsIGNhdXNlIGV4cG9uZW50aWFsXG4gICAgICAvLyBmYW4tb3V0LiBGYWlsIGxvdWQ6IHRoZSB0aHJvdyBlc2NhcGVzIHRoZSBlbnRyeXBvaW50IGludG8gdGhlXG4gICAgICAvLyByZXBsYXkgbG9vcCdzIGNhdGNoIGluIHJ1bnRpbWUudHMgKHRoZSBRdWlja0pTIGRpc3BhdGNoIHJ1bnNcbiAgICAgIC8vIGluc2lkZSB0aGF0IGxvb3AncyB0cnkpLCB3aGljaCByZWNvcmRzIHJ1bl9mYWlsZWQuIEEgdmlzaWJsZVxuICAgICAgLy8gdGVybWluYWwgZmFpbHVyZSBpc1xuICAgICAgLy8gcHJlZmVycmVkIG92ZXIgc2lsZW50bHkgZXhlY3V0aW5nIHdpdGggdW5kZWZpbmVkIGFyZ3VtZW50cyDigJQgdGhlXG4gICAgICAvLyBxdWV1ZS1wcm92aWRlZCBydW5JbnB1dCBmYWxsYmFjayBhYm92ZSBtYWtlcyB0aGlzIHBhdGggcmFyZS5cbiAgICAgIC8vIEVtcHR5IGBldmVudHNgIGlzIGFsbG93ZWQgYmVjYXVzZSB0ZXN0cyB0aGF0IGJvb3RzdHJhcCBhIHdvcmtmbG93XG4gICAgICAvLyB3aXRoIG5vIGFyZ3VtZW50cyByZWx5IG9uIHRoZSBvbGQgcGVybWlzc2l2ZSBiZWhhdmlvci5cbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCBzdGFydCB3b3JrZmxvdyBydW4gXCIke3dvcmtmbG93UnVuLnJ1bklkfVwiOiBubyBydW5fY3JlYXRlZCBldmVudCBmb3VuZCBhbmQgbm8gcnVuSW5wdXQgaW4gdGhlIHF1ZXVlIHBheWxvYWQsIGJ1dCBvdGhlciBldmVudHMgYXJlIHByZXNlbnQgKGxpa2VseSBhIHJlYWQtYWZ0ZXItd3JpdGUgcmFjZSBkdXJpbmcgc3RhcnQoKSkuYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTZXQgd29ya2Zsb3cgY29udGV4dCBtZXRhZGF0YSAoZm9yIGdldFdvcmtmbG93TWV0YWRhdGEoKSkuXG4gICAgLy8gTXVzdCBtYXRjaCB0aGUgc2hhcGUgdGhhdCB0aGUgbm9kZTp2bSBlbmdpbmUgcHJvZHVjZXMgKHNlZVxuICAgIC8vIHBhY2thZ2VzL2NvcmUvc3JjL3dvcmtmbG93LnRzOiBydW5Xb3JrZmxvdyDihpIgY3R4KSBzbyB1c2VyIGNvZGVcbiAgICAvLyB0aGF0IGNvbXBhcmVzIGBnZXRXb3JrZmxvd01ldGFkYXRhKClgIHZhbHVlcyBiZXR3ZWVuIGEgc3RlcFxuICAgIC8vIChzZXJ2ZXItc2lkZSkgYW5kIHRoZSB3b3JrZmxvdyAoVk0tc2lkZSkgc2VlcyBpZGVudGljYWwgb2JqZWN0cy5cbiAgICB7XG4gICAgICBjb25zdCBtZXRhZGF0YSA9IHtcbiAgICAgICAgd29ya2Zsb3dOYW1lOiB3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsXG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHdvcmtmbG93UnVuLnJ1bklkLFxuICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdDogd29ya2Zsb3dSdW4uc3RhcnRlZEF0XG4gICAgICAgICAgPyBuZXcgRGF0ZSgrd29ya2Zsb3dSdW4uc3RhcnRlZEF0KVxuICAgICAgICAgIDogbmV3IERhdGUoKSxcbiAgICAgICAgdXJsOiBwcm9jZXNzLmVudi5WRVJDRUxfVVJMXG4gICAgICAgICAgPyBgaHR0cHM6Ly8ke3Byb2Nlc3MuZW52LlZFUkNFTF9VUkx9YFxuICAgICAgICAgIDogYGh0dHA6Ly9sb2NhbGhvc3Q6JHtvcHRpb25zLnBvcnQgPz8gMzAwMH1gLFxuICAgICAgICBmZWF0dXJlczogeyBlbmNyeXB0aW9uOiAhIW9wdGlvbnMuZW5jcnlwdGlvbktleSB9LFxuICAgICAgfTtcbiAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICBgZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfQ09OVEVYVFwiKV0gPSAke0pTT04uc3RyaW5naWZ5KG1ldGFkYXRhKX07YCArXG4gICAgICAgICAgYGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0NPTlRFWFRcIildLndvcmtmbG93U3RhcnRlZEF0ID0gbmV3IERhdGUoJHtKU09OLnN0cmluZ2lmeShtZXRhZGF0YS53b3JrZmxvd1N0YXJ0ZWRBdC50b0lTT1N0cmluZygpKX0pO2BcbiAgICAgICkuZGlzcG9zZSgpO1xuICAgIH1cblxuICAgIC8vIFN0YXJ0IHRoZSB3b3JrZmxvdyBmdW5jdGlvbi4gSWYgdGhlIHdvcmtmbG93IGlzbid0IHJlZ2lzdGVyZWQsXG4gICAgLy8gdGhyb3cgYW4gZXJyb3IgdGFnZ2VkIHdpdGggYG5hbWUgPSBcIldvcmtmbG93Tm90UmVnaXN0ZXJlZEVycm9yXCJgXG4gICAgLy8gc28gdGhlIGhvc3Qtc2lkZSBlbnRyeXBvaW50IGNhbiByZWNvbnN0cnVjdCBhIHJlYWxcbiAgICAvLyBXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvciAoYSBXb3JrZmxvd1J1bnRpbWVFcnJvciBzdWJjbGFzcyB0aGF0XG4gICAgLy8gY2xhc3NpZmllcyBhcyBSVU5USU1FX0VSUk9SKSByYXRoZXIgdGhhbiBhIGdlbmVyaWMgdXNlciBlcnJvci5cbiAgICAvLyBTZWUgcXVpY2tqcy1lbnRyeXBvaW50LnRzJ3MgcnVuX2ZhaWxlZCBicmFuY2guXG4gICAgdHJ5IHtcbiAgICAgIHZtLmV2YWxDb2RlKGBcbiAgICAgIHZhciBfX3dmbiA9IGdsb2JhbFRoaXMuX19wcml2YXRlX3dvcmtmbG93cy5nZXQoJHtKU09OLnN0cmluZ2lmeSh3b3JrZmxvd0lkKX0pO1xuICAgICAgaWYgKCFfX3dmbikge1xuICAgICAgICB2YXIgX193Zm5FcnIgPSBuZXcgRXJyb3IoXCJXb3JrZmxvdyBcXFxcXCJcIiArICR7SlNPTi5zdHJpbmdpZnkod29ya2Zsb3dJZCl9ICsgXCJcXFxcXCIgaXMgbm90IHJlZ2lzdGVyZWQgaW4gdGhlIGN1cnJlbnQgZGVwbG95bWVudC5cIik7XG4gICAgICAgIF9fd2ZuRXJyLm5hbWUgPSBcIldvcmtmbG93Tm90UmVnaXN0ZXJlZEVycm9yXCI7XG4gICAgICAgIHRocm93IF9fd2ZuRXJyO1xuICAgICAgfVxuICAgICAgdmFyIF9fYXJncyA9IGdsb2JhbFRoaXMuX193ZGtfaW5wdXRcbiAgICAgICAgPyBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1kZXNlcmlhbGl6ZVwiKV0oZ2xvYmFsVGhpcy5fX3dka19pbnB1dClcbiAgICAgICAgOiBbXTtcbiAgICAgIGRlbGV0ZSBnbG9iYWxUaGlzLl9fd2RrX2lucHV0O1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KF9fYXJncykpIF9fYXJncyA9IFtfX2FyZ3NdO1xuICAgICAgX193Zm4uYXBwbHkobnVsbCwgX19hcmdzKS50aGVuKFxuICAgICAgICBmdW5jdGlvbihyZXN1bHQpIHsgZ2xvYmFsVGhpcy5fX3dvcmtmbG93UmVzdWx0ID0gZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwid29ya2Zsb3ctc2VyaWFsaXplXCIpXShyZXN1bHQpOyB9LFxuICAgICAgICBmdW5jdGlvbihlcnJvcikge1xuICAgICAgICAgIC8vIFByZXNlcnZlIGRpc3BsYXkgaW5mbyBvbiB0aGUgaG9zdC1zaWRlIGZhaWxlZCBvYmplY3RcbiAgICAgICAgICAvLyAobWF0Y2hlcyB0aGUgbGVnYWN5IGhvc3QtdmlzaWJsZSBzaGFwZSkgQU5EIHNlcmlhbGl6ZSB0aGVcbiAgICAgICAgICAvLyBlbnRpcmUgdGhyb3duIHZhbHVlIHNvIHRoZSBob3N0IGNhbiBkZWh5ZHJhdGUgdGhlIG9yaWdpbmFsXG4gICAgICAgICAgLy8gdHlwZS1pZGVudGl0eSwgY2F1c2UgY2hhaW4sIG9yIG5vbi1FcnJvciB0aHJvd3MgdmVyYmF0aW1cbiAgICAgICAgICAvLyB0aHJvdWdoIHRoZSBzdGFuZGFyZCBlcnJvciBwaXBlbGluZS5cbiAgICAgICAgICBnbG9iYWxUaGlzLl9fd29ya2Zsb3dFcnJvciA9IHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IGVycm9yICYmIGVycm9yLm1lc3NhZ2UgIT0gbnVsbCA/IFN0cmluZyhlcnJvci5tZXNzYWdlKSA6IFN0cmluZyhlcnJvciksXG4gICAgICAgICAgICBzdGFjazogZXJyb3IgJiYgZXJyb3Iuc3RhY2sgPyBlcnJvci5zdGFjayA6IFwiXCIsXG4gICAgICAgICAgICBuYW1lOiBlcnJvciAmJiBlcnJvci5uYW1lID8gZXJyb3IubmFtZSA6IChlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gXCJFcnJvclwiIDogdHlwZW9mIGVycm9yKSxcbiAgICAgICAgICAgIHZhbHVlQnl0ZXM6IGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIndvcmtmbG93LXNlcmlhbGl6ZVwiKV0oZXJyb3IpLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgYCkuZGlzcG9zZSgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmV0dXJuIG1ha2VTZXR0bGVkU2Vzc2lvbihcbiAgICAgICAgZXh0cmFjdEVycm9yKHZtLCBlcnIsICdGYWlsZWQgdG8gc3RhcnQgd29ya2Zsb3cnKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBQcm9jZXNzIGV2ZW50cyBhbmQgZHJhaW4gam9icyBpbiBhIGxvb3AuIEV2ZW50cyBtYXkgcmVzb2x2ZSBwcm9taXNlc1xuICAgIC8vIHRoYXQgdW5ibG9jayB3b3JrZmxvdyBjb2RlLCB3aGljaCB0aGVuIGNyZWF0ZXMgTkVXIHJlc29sdmVycyBmb3JcbiAgICAvLyBzdWJzZXF1ZW50IGV2ZW50cy4gUmUtcHJvY2Vzc2luZyBldmVudHMgbWF0Y2hlcyB0aGVzZSBuZXcgcmVzb2x2ZXJzXG4gICAgLy8gYWdhaW5zdCBldmVudHMgdGhhdCB3ZXJlIGFscmVhZHkgZGVsaXZlcmVkLlxuICAgIHtcbiAgICAgIGxldCBtYXhJdGVyYXRpb25zID0gMTAwO1xuICAgICAgbGV0IG1hZGVQcm9ncmVzczogYm9vbGVhbjtcbiAgICAgIGRvIHtcbiAgICAgICAgbWFkZVByb2dyZXNzID0gYXdhaXQgcHJvY2Vzc0V2ZW50cyhcbiAgICAgICAgICB2bSxcbiAgICAgICAgICBldmVudHMsXG4gICAgICAgICAgYWR2YW5jZUNsb2NrLFxuICAgICAgICAgIG9wdGlvbnMuZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgICBsZXQgYmF0Y2g6IG51bWJlcjtcbiAgICAgICAgZG8ge1xuICAgICAgICAgIGJhdGNoID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgaWYgKGJhdGNoID4gMCkgbWFkZVByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgfSB3aGlsZSAoYmF0Y2ggPiAwKTtcbiAgICAgIH0gd2hpbGUgKG1hZGVQcm9ncmVzcyAmJiAtLW1heEl0ZXJhdGlvbnMgPiAwKTtcbiAgICAgIGlmIChtYWRlUHJvZ3Jlc3MgJiYgbWF4SXRlcmF0aW9ucyA9PT0gMCkge1xuICAgICAgICAvLyBUaGUgZHJhaW4gbG9vcCBoaXQgaXRzIGJvdW5kIHdoaWxlIHN0aWxsIG1ha2luZyBwcm9ncmVzcyDigJRcbiAgICAgICAgLy8gcHJvY2VlZGluZyBhcyBpZiBpdCBjb252ZXJnZWQgd291bGQgcHJlc2VudCBhcyBhIG15c3RlcmlvdXNcbiAgICAgICAgLy8gc3VzcGVuc2lvbiBvciByZXBsYXkgZGl2ZXJnZW5jZS4gTWFrZSB0aGUgZ2l2aW5nLXVwIHZpc2libGUgc29cbiAgICAgICAgLy8gYSB3ZWRnZSBpcyBhdHRyaWJ1dGFibGUgdG8gdGhpcyBib3VuZCByYXRoZXIgdGhhbiBhIG15c3RlcnkuXG4gICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBldmVudCBkcmFpbiBsb29wIGhpdCBpdHMgaXRlcmF0aW9uIGJvdW5kIGJlZm9yZSByZWFjaGluZyBhIGZpeGVkIHBvaW50JyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkOiB3b3JrZmxvd1J1bi5ydW5JZCxcbiAgICAgICAgICAgIGV2ZW50Q291bnQ6IGV2ZW50cy5sZW5ndGgsXG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIC0tLS0gQ2hlY2sgcmVzdWx0IC0tLS1cbiAgICByZXR1cm4gbWFrZUxpdmVTZXNzaW9uKFxuICAgICAgdm0sXG4gICAgICBpbnRlcnJ1cHRCdWRnZXQsXG4gICAgICBhZHZhbmNlQ2xvY2ssXG4gICAgICBvcHRpb25zLmVuY3J5cHRpb25LZXlcbiAgICApO1xuICB9XG59XG5cbi8qKiBTZXNzaW9uIHdyYXBwZXIgZm9yIGEgcmVzdWx0IHdob3NlIFZNIGlzIGFscmVhZHkgc2V0dGxlZC9kaXNwb3NlZC4gKi9cbmZ1bmN0aW9uIG1ha2VTZXR0bGVkU2Vzc2lvbihcbiAgcmVzdWx0OiBRdWlja0pTUnVudGltZVJlc3VsdFxuKTogUXVpY2tKU1dvcmtmbG93U2Vzc2lvbiB7XG4gIHJldHVybiB7XG4gICAgcmVzdWx0LFxuICAgIGNvbnRpbnVlV2l0aEV2ZW50czogKCkgPT4ge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnUXVpY2tKUyB3b3JrZmxvdyBzZXNzaW9uIGlzIHNldHRsZWQg4oCUIGNvbnRpbnVlV2l0aEV2ZW50cyBpcyBvbmx5IHZhbGlkIHdoaWxlIHN1c3BlbmRlZCdcbiAgICAgICk7XG4gICAgfSxcbiAgICBkaXNwb3NlOiAoKSA9PiB7fSxcbiAgfTtcbn1cblxuLyoqXG4gKiBFdmFsdWF0ZSB0aGUgVk0ncyBzdGF0ZSBhbmQgd3JhcCBpdCBpbiBhIGxpdmUgc2Vzc2lvbi4gV2hpbGUgc3VzcGVuZGVkLFxuICogdGhlIFZNIHN0YXlzIGFsaXZlIHNvIGBjb250aW51ZVdpdGhFdmVudHNgIGNhbiByZXN1bWUgaXQgaW4gcGxhY2U7XG4gKiB0ZXJtaW5hbCBzdGF0ZXMgZGlzcG9zZSB0aGUgVk0gaW1tZWRpYXRlbHkgKGluc2lkZSBjaGVja1dvcmtmbG93U3RhdGUpLlxuICovXG5mdW5jdGlvbiBtYWtlTGl2ZVNlc3Npb24oXG4gIHZtOiBRdWlja0pTLFxuICBpbnRlcnJ1cHRCdWRnZXQ6IEludGVycnVwdEJ1ZGdldCxcbiAgYWR2YW5jZUNsb2NrOiAobXM6IG51bWJlcikgPT4gdm9pZCxcbiAgZW5jcnlwdGlvbktleT86IERlY3J5cHRpb25LZXlcbik6IFF1aWNrSlNXb3JrZmxvd1Nlc3Npb24ge1xuICBjb25zdCByZXN1bHQgPSBjaGVja1dvcmtmbG93U3RhdGUodm0sIHsga2VlcEFsaXZlT25TdXNwZW5kOiB0cnVlIH0pO1xuICBsZXQgYWxpdmUgPSAhIXJlc3VsdC5zdXNwZW5kZWQ7XG5cbiAgY29uc3Qgc2Vzc2lvbjogUXVpY2tKU1dvcmtmbG93U2Vzc2lvbiA9IHtcbiAgICByZXN1bHQsXG4gICAgYXN5bmMgY29udGludWVXaXRoRXZlbnRzKFxuICAgICAgbmV3RXZlbnRzOiBFdmVudFtdXG4gICAgKTogUHJvbWlzZTxRdWlja0pTUnVudGltZVJlc3VsdD4ge1xuICAgICAgaWYgKCFhbGl2ZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ1F1aWNrSlMgd29ya2Zsb3cgc2Vzc2lvbiBpcyBub3QgYWxpdmUg4oCUIGNvbnRpbnVlV2l0aEV2ZW50cyBpcyBvbmx5IHZhbGlkIHdoaWxlIHN1c3BlbmRlZCdcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIC8vIEZyZXNoIGV4ZWN1dGlvbiBidXJzdCDigJQgdGhlIGludGVycnVwdCBidWRnZXQgYm91bmRzIFZNIGNvbXB1dGUsXG4gICAgICAvLyBub3Qgd2FsbCB0aW1lIHNwZW50IHdhaXRpbmcgb24gaW5saW5lIHN0ZXBzIGJldHdlZW4gYnVyc3RzLlxuICAgICAgaW50ZXJydXB0QnVkZ2V0LnN0YXJ0ID0gRGF0ZS5ub3coKTtcblxuICAgICAgbGV0IG1heEl0ZXJhdGlvbnMgPSAxMDA7XG4gICAgICBsZXQgbWFkZVByb2dyZXNzOiBib29sZWFuO1xuICAgICAgZG8ge1xuICAgICAgICBtYWRlUHJvZ3Jlc3MgPSBhd2FpdCBwcm9jZXNzRXZlbnRzKFxuICAgICAgICAgIHZtLFxuICAgICAgICAgIG5ld0V2ZW50cyxcbiAgICAgICAgICBhZHZhbmNlQ2xvY2ssXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgICBsZXQgYmF0Y2g6IG51bWJlcjtcbiAgICAgICAgZG8ge1xuICAgICAgICAgIGJhdGNoID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgaWYgKGJhdGNoID4gMCkgbWFkZVByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgfSB3aGlsZSAoYmF0Y2ggPiAwKTtcbiAgICAgIH0gd2hpbGUgKG1hZGVQcm9ncmVzcyAmJiAtLW1heEl0ZXJhdGlvbnMgPiAwKTtcblxuICAgICAgY29uc3QgbmV4dCA9IGNoZWNrV29ya2Zsb3dTdGF0ZSh2bSwgeyBrZWVwQWxpdmVPblN1c3BlbmQ6IHRydWUgfSk7XG4gICAgICBpZiAoIW5leHQuc3VzcGVuZGVkKSBhbGl2ZSA9IGZhbHNlO1xuICAgICAgc2Vzc2lvbi5yZXN1bHQgPSBuZXh0O1xuICAgICAgcmV0dXJuIG5leHQ7XG4gICAgfSxcbiAgICBkaXNwb3NlKCk6IHZvaWQge1xuICAgICAgaWYgKGFsaXZlKSB7XG4gICAgICAgIGFsaXZlID0gZmFsc2U7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdm0uZGlzcG9zZSgpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBBbHJlYWR5IGRpc3Bvc2VkIOKAlCBpZ25vcmUuXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICB9O1xuICByZXR1cm4gc2Vzc2lvbjtcbn1cblxuLy8gLS0tLSBFdmVudCBQcm9jZXNzaW5nIC0tLS1cblxuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0V2ZW50cyhcbiAgdm06IFF1aWNrSlMsXG4gIGV2ZW50czogRXZlbnRbXSxcbiAgYWR2YW5jZUNsb2NrOiAobXM6IG51bWJlcikgPT4gdm9pZCxcbiAgZW5jcnlwdGlvbktleT86IERlY3J5cHRpb25LZXlcbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBsZXQgcmVzb2x2ZWQgPSBmYWxzZTtcbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICAvLyBBZHZhbmNlIHRoZSBWTSdzIGRldGVybWluaXN0aWMgY2xvY2sgdG8gdGhpcyBldmVudCdzIGNyZWF0aW9uIHRpbWVcbiAgICAvLyBCRUZPUkUgcmVzb2x2aW5nIGFueXRoaW5nLCBzbyB3b3JrZmxvdyBjb2RlIHVuYmxvY2tlZCBieSB0aGlzIGV2ZW50XG4gICAgLy8gb2JzZXJ2ZXMgRGF0ZS5ub3coKSBhdCAob3IgYWZ0ZXIg4oCUIHRoZSBjbG9jayBpcyBtb25vdG9uaWMpIHRoZSB0aW1lXG4gICAgLy8gdGhlIGV2ZW50IHdhcyByZWNvcmRlZC4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUnc1xuICAgIC8vIGBvbkNvbnN1bWVkRXZlbnQg4oaSIHVwZGF0ZVRpbWVzdGFtcCgrZXZlbnQuY3JlYXRlZEF0KWAuXG4gICAgYWR2YW5jZUNsb2NrKCtldmVudC5jcmVhdGVkQXQpO1xuXG4gICAgY29uc3QgY2lkID0gZXZlbnQuY29ycmVsYXRpb25JZDtcbiAgICBpZiAoIWNpZCkgY29udGludWU7XG5cbiAgICAvLyBKU09OLnN0cmluZ2lmeSBoYW5kbGVzIHF1b3RlcywgYmFja3NsYXNoZXMgYW5kIGNvbnRyb2wgY2hhcmFjdGVycztcbiAgICAvLyBjb3JyZWxhdGlvbiBpZHMgYXJlIGhvc3QtZ2VuZXJhdGVkIFVMSURzIHRvZGF5LCBidXQgdGhlIGV2YWwtc3RyaW5nXG4gICAgLy8gc2FmZXR5IHNob3VsZG4ndCBkZXBlbmQgb24gdGhhdCBpbnZhcmlhbnQgYmVpbmcgYXNzZXJ0ZWQgbm93aGVyZS5cbiAgICBjb25zdCBjaWRKcyA9IEpTT04uc3RyaW5naWZ5KGNpZCk7XG4gICAgY29uc3QgZXZlbnREYXRhID1cbiAgICAgICdldmVudERhdGEnIGluIGV2ZW50XG4gICAgICAgID8gKGV2ZW50LmV2ZW50RGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilcbiAgICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICAvLyBMb2cgdGhlIGV2ZW50IGFuZCB3aGV0aGVyIHRoZSByZXNvbHZlciBleGlzdHNcbiAgICBzd2l0Y2ggKGV2ZW50LmV2ZW50VHlwZSkge1xuICAgICAgY2FzZSAnc3RlcF9jb21wbGV0ZWQnOiB7XG4gICAgICAgIGNvbnN0IGhhc1Jlc29sdmVyID0gdm0uZHVtcChcbiAgICAgICAgICB2bS5ldmFsQ29kZShgISFnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XWApXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJhd091dHB1dCA9IGV2ZW50RGF0YT8ucmVzdWx0ID8/IGV2ZW50RGF0YT8ub3V0cHV0O1xuICAgICAgICBpZiAoaGFzUmVzb2x2ZXIpIHtcbiAgICAgICAgICBpZiAocmF3T3V0cHV0IGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICAgICAgLy8gRGVjcnlwdCBpZiBlbmNyeXB0ZWQg4oCUIHRoZSBWTSBvbmx5IHVuZGVyc3RhbmRzICdkZXZsJyBmb3JtYXRcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgcnVudGltZTogc3RlcCByZXN1bHQgcmF3Jywge1xuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBjaWQsXG4gICAgICAgICAgICAgIHJhd1ByZWZpeDogbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKHJhd091dHB1dC5zdWJhcnJheSgwLCA0KSksXG4gICAgICAgICAgICAgIHJhd0J5dGVMZW5ndGg6IHJhd091dHB1dC5ieXRlTGVuZ3RoLFxuICAgICAgICAgICAgICBpc0J1ZmZlcjogQnVmZmVyLmlzQnVmZmVyKHJhd091dHB1dCksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZE91dHB1dCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdPdXRwdXQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRdWlja0pTIHJ1bnRpbWU6IHN0ZXAgcmVzdWx0IGRlY3J5cHRlZCcsIHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgICAgICBwcmVmaXg6IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkZWNyeXB0ZWRPdXRwdXQuc3ViYXJyYXkoMCwgNCkpLFxuICAgICAgICAgICAgICBieXRlTGVuZ3RoOiBkZWNyeXB0ZWRPdXRwdXQuYnl0ZUxlbmd0aCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgYnl0ZXNIYW5kbGUgPSB2bS5uZXdVaW50OEFycmF5KGRlY3J5cHRlZE91dHB1dCk7XG4gICAgICAgICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fdG1wX3Jlc3VsdCcsIGJ5dGVzSGFuZGxlKTtcbiAgICAgICAgICAgIGJ5dGVzSGFuZGxlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVzb2x2ZShnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1kZXNlcmlhbGl6ZVwiKV0oZ2xvYmFsVGhpcy5fX3RtcF9yZXN1bHQpKTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3RtcF9yZXN1bHQ7YFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgcnVudGltZTogc3RlcCByZXN1bHQgbm9uLWJpbmFyeScsIHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgICAgICB0eXBlOiB0eXBlb2YgcmF3T3V0cHV0LFxuICAgICAgICAgICAgICBpc051bGw6IHJhd091dHB1dCA9PT0gbnVsbCxcbiAgICAgICAgICAgICAgaXNVbmRlZmluZWQ6IHJhd091dHB1dCA9PT0gdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBjb25zdHJ1Y3RvcjogcmF3T3V0cHV0Py5jb25zdHJ1Y3Rvcj8ubmFtZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9XG4gICAgICAgICAgICAgIHJhd091dHB1dCAhPT0gdW5kZWZpbmVkID8gSlNPTi5zdHJpbmdpZnkocmF3T3V0cHV0KSA6ICd1bmRlZmluZWQnO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XS5yZXNvbHZlKCR7c2VyaWFsaXplZH0pO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV07YFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIERyYWluIEFMTCBtaWNyb3Rhc2tzIGFmdGVyIHJlc29sdmVcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCDigJQgYnVmZmVyIHRoZSBwcmVwYXJlZCBvdXRjb21lIHNvIHRoZSBwcm9taXNlXG4gICAgICAgICAgLy8gc2V0dGxlcyB0aGUgbW9tZW50IHRoZSBWTSBjb25zdHJ1Y3RzIGl0IChzZWUgX190ZXJtaW5hbEJ1ZmZlclxuICAgICAgICAgIC8vIGluIHRoZSBib290c3RyYXApLiBXaXRob3V0IHRoaXMsIHRoZSBsaXZlLWNvbnRpbnVhdGlvbiBwYXRoXG4gICAgICAgICAgLy8gKHdoaWNoIHNjYW5zIGVhY2ggZGVsdGEgZXhhY3RseSBvbmNlKSBkcm9wcyB0aGUgdGVybWluYWwgYW5kXG4gICAgICAgICAgLy8gdGhlIGF3YWl0IG5ldmVyIHNldHRsZXMuXG4gICAgICAgICAgaWYgKHJhd091dHB1dCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZE91dHB1dCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdPdXRwdXQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBieXRlc0hhbmRsZSA9IHZtLm5ld1VpbnQ4QXJyYXkoZGVjcnlwdGVkT3V0cHV0KTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfYnVmJywgYnl0ZXNIYW5kbGUpO1xuICAgICAgICAgICAgYnl0ZXNIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfYnl0ZXNcIiwgYnl0ZXM6IGdsb2JhbFRoaXMuX190bXBfYnVmIH07YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fdG1wX2J1ZjtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9XG4gICAgICAgICAgICAgIHJhd091dHB1dCAhPT0gdW5kZWZpbmVkID8gSlNPTi5zdHJpbmdpZnkocmF3T3V0cHV0KSA6ICd1bmRlZmluZWQnO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfdmFsdWVcIiwgdmFsdWU6ICR7c2VyaWFsaXplZH0gfTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdzdGVwX2ZhaWxlZCc6IHtcbiAgICAgICAgY29uc3QgaGFzUmVzb2x2ZXIgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKGAhIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dYClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgY29uc3QgZXJyb3JEYXRhID0gZXZlbnREYXRhPy5lcnJvcjtcbiAgICAgICAgICBpZiAoZXJyb3JEYXRhIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICAgICAgLy8gTW9kZXJuIHBhdGggKHBvc3QtIzE4NTEpOiB0aGUgc3RlcCBoYW5kbGVyIGRlaHlkcmF0ZWQgdGhlXG4gICAgICAgICAgICAvLyB0aHJvd24gdmFsdWUgdGhyb3VnaCB0aGUgZmlyc3QtY2xhc3MgZXJyb3IgcGlwZWxpbmUuIERlY3J5cHRcbiAgICAgICAgICAgIC8vIChpZiBlbmNyeXB0ZWQpIGFuZCBwYXNzIHRoZSBieXRlcyB0byB0aGUgVk0tc2lkZSBkZXNlcmlhbGl6ZXJcbiAgICAgICAgICAgIC8vIHNvIHRoZSB3b3JrZmxvdyBjYXRjaCBzZWVzIGEgcHJvcGVybHkgdHlwZWQgRXJyb3Igc3ViY2xhc3NcbiAgICAgICAgICAgIC8vIChUeXBlRXJyb3IsIEZhdGFsRXJyb3Igd2l0aCBvcmlnaW5hbCBjYXVzZSBjaGFpbiwgZXRjLikgd2l0aFxuICAgICAgICAgICAgLy8gdGhlIG9yaWdpbmFsIG1lc3NhZ2UgYW5kIHN0YWNrIHByZXNlcnZlZC5cbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKGVycm9yRGF0YSwgZW5jcnlwdGlvbktleSk7XG4gICAgICAgICAgICBjb25zdCBieXRlc0hhbmRsZSA9IHZtLm5ld1VpbnQ4QXJyYXkoZGVjcnlwdGVkKTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfZXJyb3InLCBieXRlc0hhbmRsZSk7XG4gICAgICAgICAgICBieXRlc0hhbmRsZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYChmdW5jdGlvbigpe2AgK1xuICAgICAgICAgICAgICAgIGB2YXIgZT1nbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJ3b3JrZmxvdy1kZXNlcmlhbGl6ZVwiKV0oZ2xvYmFsVGhpcy5fX3RtcF9lcnJvcik7YCArXG4gICAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlamVjdChlKTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3RtcF9lcnJvcjtgICtcbiAgICAgICAgICAgICAgICBgfSkoKWBcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBMZWdhY3kgcGF0aDogcHJlLXBpcGVsaW5lIGV2ZW50cyBzdG9yZWQgZXJyb3IgYXNcbiAgICAgICAgICAgIC8vIGB7IG1lc3NhZ2UsIHN0YWNrLCBjb2RlIH1gLiBSZWNvbnN0cnVjdCBhIEZhdGFsRXJyb3Igc29cbiAgICAgICAgICAgIC8vIHdvcmtmbG93IGNhdGNoIGNhbiBkZXRlY3QgaXQgdmlhIEZhdGFsRXJyb3IuaXMoKSwgbWF0Y2hpbmdcbiAgICAgICAgICAgIC8vIHRoZSBvcmlnaW5hbCBWMSBzdGVwIGhhbmRsZXIgYmVoYXZpb3IuXG4gICAgICAgICAgICBjb25zdCBpc0Vycm9yT2JqZWN0ID1cbiAgICAgICAgICAgICAgdHlwZW9mIGVycm9yRGF0YSA9PT0gJ29iamVjdCcgJiYgZXJyb3JEYXRhICE9PSBudWxsO1xuICAgICAgICAgICAgY29uc3QgbXNnID0gaXNFcnJvck9iamVjdFxuICAgICAgICAgICAgICA/ICgoKGVycm9yRGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikubWVzc2FnZSBhcyBzdHJpbmcpID8/XG4gICAgICAgICAgICAgICAgJ1N0ZXAgZmFpbGVkJylcbiAgICAgICAgICAgICAgOiB0eXBlb2YgZXJyb3JEYXRhID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgID8gZXJyb3JEYXRhXG4gICAgICAgICAgICAgICAgOiAnU3RlcCBmYWlsZWQnO1xuICAgICAgICAgICAgY29uc3QgZXJyb3JTdGFjayA9XG4gICAgICAgICAgICAgIChpc0Vycm9yT2JqZWN0XG4gICAgICAgICAgICAgICAgPyAoZXJyb3JEYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5zdGFja1xuICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkKSA/PyAoZXZlbnREYXRhPy5zdGFjayBhcyBzdHJpbmcgfCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgY29uc3Qgc3RhY2tBc3NpZ25tZW50ID0gZXJyb3JTdGFja1xuICAgICAgICAgICAgICA/IGBlLnN0YWNrPSR7SlNPTi5zdHJpbmdpZnkoZXJyb3JTdGFjayl9O2BcbiAgICAgICAgICAgICAgOiAnJztcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgKGZ1bmN0aW9uKCl7dmFyIGU9bmV3IEVycm9yKCR7SlNPTi5zdHJpbmdpZnkobXNnKX0pO2UubmFtZT1cIkZhdGFsRXJyb3JcIjtlLmZhdGFsPXRydWU7JHtzdGFja0Fzc2lnbm1lbnR9YCArXG4gICAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlamVjdChlKTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO30pKClgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgbGV0IGI6IG51bWJlcjtcbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgICAgfSB3aGlsZSAoYiA+IDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBObyByZXNvbHZlciB5ZXQg4oCUIGJ1ZmZlciB0aGUgcHJlcGFyZWQgcmVqZWN0aW9uIChzZWUgdGhlXG4gICAgICAgICAgLy8gc3RlcF9jb21wbGV0ZWQgYnJhbmNoIGFib3ZlIGZvciB0aGUgcmF0aW9uYWxlKS5cbiAgICAgICAgICBjb25zdCBlcnJvckRhdGEgPSBldmVudERhdGE/LmVycm9yO1xuICAgICAgICAgIGlmIChlcnJvckRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgICBjb25zdCBkZWNyeXB0ZWQgPSBhd2FpdCBwcmVwYXJlQnl0ZXNGb3JWTShlcnJvckRhdGEsIGVuY3J5cHRpb25LZXkpO1xuICAgICAgICAgICAgY29uc3QgYnl0ZXNIYW5kbGUgPSB2bS5uZXdVaW50OEFycmF5KGRlY3J5cHRlZCk7XG4gICAgICAgICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fdG1wX2J1ZicsIGJ5dGVzSGFuZGxlKTtcbiAgICAgICAgICAgIGJ5dGVzSGFuZGxlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Rlcm1pbmFsQnVmZmVyWyR7Y2lkSnN9XSA9IHsga2luZDogXCJyZWplY3RfYnl0ZXNcIiwgYnl0ZXM6IGdsb2JhbFRoaXMuX190bXBfYnVmIH07YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fdG1wX2J1ZjtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgaXNFcnJvck9iamVjdCA9XG4gICAgICAgICAgICAgIHR5cGVvZiBlcnJvckRhdGEgPT09ICdvYmplY3QnICYmIGVycm9yRGF0YSAhPT0gbnVsbDtcbiAgICAgICAgICAgIGNvbnN0IG1zZyA9IGlzRXJyb3JPYmplY3RcbiAgICAgICAgICAgICAgPyAoKChlcnJvckRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLm1lc3NhZ2UgYXMgc3RyaW5nKSA/P1xuICAgICAgICAgICAgICAgICdTdGVwIGZhaWxlZCcpXG4gICAgICAgICAgICAgIDogdHlwZW9mIGVycm9yRGF0YSA9PT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICA/IGVycm9yRGF0YVxuICAgICAgICAgICAgICAgIDogJ1N0ZXAgZmFpbGVkJztcbiAgICAgICAgICAgIGNvbnN0IGVycm9yU3RhY2sgPVxuICAgICAgICAgICAgICAoaXNFcnJvck9iamVjdFxuICAgICAgICAgICAgICAgID8gKGVycm9yRGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikuc3RhY2tcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCkgPz8gKGV2ZW50RGF0YT8uc3RhY2sgYXMgc3RyaW5nIHwgdW5kZWZpbmVkKTtcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Rlcm1pbmFsQnVmZmVyWyR7Y2lkSnN9XSA9IHsga2luZDogXCJyZWplY3RfZXJyb3JcIiwgbWVzc2FnZTogJHtKU09OLnN0cmluZ2lmeShtc2cpfSwgc3RhY2s6ICR7ZXJyb3JTdGFjayA/IEpTT04uc3RyaW5naWZ5KGVycm9yU3RhY2spIDogJ3VuZGVmaW5lZCd9IH07YFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAnd2FpdF9jb21wbGV0ZWQnOiB7XG4gICAgICAgIGNvbnN0IGhhc1Jlc29sdmVyID0gdm0uZHVtcChcbiAgICAgICAgICB2bS5ldmFsQ29kZShgISFnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XWApXG4gICAgICAgICk7XG4gICAgICAgIGlmIChoYXNSZXNvbHZlcikge1xuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlc29sdmUoKTtgICtcbiAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgXG4gICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgbGV0IGI6IG51bWJlcjtcbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgICAgfSB3aGlsZSAoYiA+IDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBObyByZXNvbHZlciB5ZXQg4oCUIGJ1ZmZlciAoc2VlIHN0ZXBfY29tcGxldGVkIGFib3ZlKS5cbiAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfdW5kZWZpbmVkXCIgfTtgXG4gICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdhdHRyX3NldCc6IHtcbiAgICAgICAgLy8gT25seSB3b3JrZmxvdy13cml0dGVuIGF0dHJpYnV0ZSBldmVudHMgcmVzb2x2ZSBhIHBlbmRpbmdcbiAgICAgICAgLy8gc2V0QXR0cmlidXRlcygpIHByb21pc2U7IHN0ZXAvc3lzdGVtIHdyaXRlcnMgc2hhcmUgbm9cbiAgICAgICAgLy8gY29ycmVsYXRpb25JZHMgd2l0aCBWTSByZXNvbHZlcnMsIHNvIHRoZSBndWFyZCBpcyBkZWZlbnNpdmUuXG4gICAgICAgIGNvbnN0IHdyaXRlciA9IChldmVudERhdGE/LndyaXRlciBhcyB7IHR5cGU/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZClcbiAgICAgICAgICA/LnR5cGU7XG4gICAgICAgIGlmICh3cml0ZXIgIT09ICd3b3JrZmxvdycpIGJyZWFrO1xuICAgICAgICBjb25zdCBoYXNSZXNvbHZlciA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoYCEhZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV1gKVxuICAgICAgICApO1xuICAgICAgICBpZiAoIWhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgLy8gTm8gcmVzb2x2ZXIgeWV0IOKAlCBidWZmZXIgKHNlZSBzdGVwX2NvbXBsZXRlZCBhYm92ZSkuXG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Rlcm1pbmFsQnVmZmVyWyR7Y2lkSnN9XSA9IHsga2luZDogXCJyZXNvbHZlX3VuZGVmaW5lZFwiIH07YFxuICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChoYXNSZXNvbHZlcikge1xuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlc29sdmUoKTtgICtcbiAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgXG4gICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgbGV0IGI6IG51bWJlcjtcbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgICAgfSB3aGlsZSAoYiA+IDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ2hvb2tfcmVjZWl2ZWQnOiB7XG4gICAgICAgIC8vIENoZWNrIGlmIHRoaXMgZXZlbnQgd2FzIGFscmVhZHkgcHJvY2Vzc2VkIChkZWxpdmVyZWQgb3JcbiAgICAgICAgLy8gYnVmZmVyZWQpIHdpdGhpbiB0aGlzIGludm9jYXRpb24uIFByZXZlbnRzIGRvdWJsZS1kZWxpdmVyeSB3aGVuXG4gICAgICAgIC8vIHRoZSBvdXRlciBsb29wIHJlLXNjYW5zIGV2ZW50cy5cbiAgICAgICAgY29uc3QgYWxyZWFkeVByb2Nlc3NlZCA9IGV2ZW50LmV2ZW50SWRcbiAgICAgICAgICA/IHZtLmR1bXAoXG4gICAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICAgIGAhIShnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyAmJiBnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkc1ske0pTT04uc3RyaW5naWZ5KGV2ZW50LmV2ZW50SWQpfV0pYFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApXG4gICAgICAgICAgOiBmYWxzZTtcbiAgICAgICAgaWYgKGFscmVhZHlQcm9jZXNzZWQpIHtcbiAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgJ1F1aWNrSlMgcnVudGltZTogaG9va19yZWNlaXZlZCBhbHJlYWR5IHByb2Nlc3NlZCcsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGNpZCxcbiAgICAgICAgICAgICAgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCxcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZXNpbGllbnQtcmVzdW1lIGRlZHVwIChwYXJpdHkgd2l0aCB0aGUgbm9kZSBlbmdpbmUnc1xuICAgICAgICAvLyBFdmVudHNDb25zdW1lciBpbiB3b3JrZmxvdy9ob29rLnRzKTogdHdvIGhvb2tfcmVjZWl2ZWQgcm93cyBmb3JcbiAgICAgICAgLy8gT05FIHJlc3VtZSBhdHRlbXB0IHNoYXJlIGEgY2xpZW50LW1pbnRlZCBgcmVzdW1lSWRgIChhIGR1cGxpY2F0ZVxuICAgICAgICAvLyBjYW4gYmUgY29tbWl0dGVkIHdoZW4gdGhlIG1hdGVyaWFsaXphdGlvbiBmYWxsYmFjayByYWNlcyBhXG4gICAgICAgIC8vIGRlbGF5ZWQgZGlyZWN0IHdyaXRlIOKAlCBob29rX3JlY2VpdmVkIGhhcyBubyBzdG9yYWdlIHVuaXF1ZW5lc3NcbiAgICAgICAgLy8gY29uc3RyYWludCkuIERlbGl2ZXIgb25seSB0aGUgZmlyc3QtaW4tbG9nIG9jY3VycmVuY2UuIFRoZSBzZWVuXG4gICAgICAgIC8vIHNldCBsaXZlcyBpbiB0aGUgVk0gaGVhcCBzbyBpdCBpcyBkZXRlcm1pbmlzdGljIHBlciByZXBsYXkgYW5kXG4gICAgICAgIC8vIHN1cnZpdmVzIGV2ZW50IHJlLXNjYW5zIHdpdGhpbiB0aGUgaW52b2NhdGlvbi4gRXZlbnRzIHdpdGhvdXQgYVxuICAgICAgICAvLyByZXN1bWVJZCAob2xkZXIgU0RLcykgYXJlIG5ldmVyIGRlZHVwZWQuXG4gICAgICAgIHtcbiAgICAgICAgICAvLyBUb3AtbGV2ZWwgZXZlbnQucmVzdW1lSWQgaXMgdGhlIGNhbm9uaWNhbCBsb2NhdGlvbiAodGhlIGJhY2tlbmRcbiAgICAgICAgICAvLyBob2lzdHMgaXQgdG8gYSBmaXJzdC1jbGFzcyBjb2x1bW4pOyB0aGUgbmVzdGVkXG4gICAgICAgICAgLy8gZXZlbnREYXRhLnJlc3VtZUlkIGZvcm0gaXMgYSBkZXByZWNhdGVkIGxlZ2FjeSBmYWxsYmFjayDigJRcbiAgICAgICAgICAvLyBtaXJyb3JzIHRoZSBub2RlIGVuZ2luZSdzIGRlZHVwIGluIHdvcmtmbG93L2hvb2sudHMuXG4gICAgICAgICAgY29uc3QgcmVzdW1lSWQgPVxuICAgICAgICAgICAgKGV2ZW50IGFzIHsgcmVzdW1lSWQ/OiB1bmtub3duIH0pLnJlc3VtZUlkID8/XG4gICAgICAgICAgICAoZXZlbnREYXRhIGFzIHsgcmVzdW1lSWQ/OiB1bmtub3duIH0gfCB1bmRlZmluZWQpPy5yZXN1bWVJZDtcbiAgICAgICAgICBpZiAodHlwZW9mIHJlc3VtZUlkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgY29uc3QgcmVzdW1lSWRKcyA9IEpTT04uc3RyaW5naWZ5KHJlc3VtZUlkKTtcbiAgICAgICAgICAgIGNvbnN0IGR1cGxpY2F0ZSA9IHZtLmR1bXAoXG4gICAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICAgIGAoZ2xvYmFsVGhpcy5fX2hvb2tTZWVuUmVzdW1lSWRzID0gZ2xvYmFsVGhpcy5fX2hvb2tTZWVuUmVzdW1lSWRzIHx8IHt9KVske3Jlc3VtZUlkSnN9XSA9PT0gdHJ1ZWBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChkdXBsaWNhdGUpIHtcbiAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBkdXBsaWNhdGUgaG9va19yZWNlaXZlZCBmb3IgdGhlIHNhbWUgcmVzdW1lIGF0dGVtcHQsIGRyb3BwaW5nJyxcbiAgICAgICAgICAgICAgICB7IGNvcnJlbGF0aW9uSWQ6IGNpZCwgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCwgcmVzdW1lSWQgfVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBpZiAoZXZlbnQuZXZlbnRJZCkge1xuICAgICAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyA9IGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzIHx8IHt9KVske0pTT04uc3RyaW5naWZ5KGV2ZW50LmV2ZW50SWQpfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX2hvb2tTZWVuUmVzdW1lSWRzWyR7cmVzdW1lSWRKc31dID0gdHJ1ZTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBYm9ydCBkZWxpdmVyeTogaG9va19yZWNlaXZlZCBmb3IgYW4gQWJvcnRDb250cm9sbGVyJ3Mgc3lzdGVtXG4gICAgICAgIC8vIGhvb2sgZmxpcHMgdGhlIHJlZ2lzdGVyZWQgc2lnbmFsIGluc3RlYWQgb2YgcmVzb2x2aW5nIGEgcHJvbWlzZS5cbiAgICAgICAgLy8gVGhlIHBheWxvYWQgaXMgdGhlIGRlaHlkcmF0ZWQgYHsgYWJvcnRlZDogdHJ1ZSwgcmVhc29uIH1gIG9iamVjdC5cbiAgICAgICAgY29uc3QgaXNBYm9ydEhvb2sgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYCEhKGdsb2JhbFRoaXMuX19hYm9ydFNpZ25hbHMgJiYgZ2xvYmFsVGhpcy5fX2Fib3J0U2lnbmFsc1ske2NpZEpzfV0pYFxuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGlzQWJvcnRIb29rKSB7XG4gICAgICAgICAgY29uc3QgcmF3QWJvcnRQYXlsb2FkID0gZXZlbnREYXRhPy5wYXlsb2FkO1xuICAgICAgICAgIGlmIChyYXdBYm9ydFBheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgICBjb25zdCBkZWNyeXB0ZWQgPSBhd2FpdCBwcmVwYXJlQnl0ZXNGb3JWTShcbiAgICAgICAgICAgICAgcmF3QWJvcnRQYXlsb2FkLFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgYnl0ZXNIYW5kbGUgPSB2bS5uZXdVaW50OEFycmF5KGRlY3J5cHRlZCk7XG4gICAgICAgICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fdG1wX2Fib3J0JywgYnl0ZXNIYW5kbGUpO1xuICAgICAgICAgICAgYnl0ZXNIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGAoZnVuY3Rpb24oKXtgICtcbiAgICAgICAgICAgICAgICBgdmFyIHA9Z2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwid29ya2Zsb3ctZGVzZXJpYWxpemVcIildKGdsb2JhbFRoaXMuX190bXBfYWJvcnQpO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3RtcF9hYm9ydDtgICtcbiAgICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX2Fib3J0U2lnbmFsc1ske2NpZEpzfV0uX3NldEFib3J0ZWQocCYmdHlwZW9mIHA9PT1cIm9iamVjdFwiP3AucmVhc29uOnVuZGVmaW5lZCk7YCArXG4gICAgICAgICAgICAgICAgYH0pKClgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fYWJvcnRTaWduYWxzWyR7Y2lkSnN9XS5fc2V0QWJvcnRlZCh1bmRlZmluZWQpO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBUaGUgYWJvcnQgaXMgZHVyYWJseSByZWNvcmRlZCDigJQgY2xlYXIgdGhlIHBlbmRpbmcgb3Anc1xuICAgICAgICAgIC8vIGFib3J0UmVxdWVzdGVkIG1hcmtlciBzbyB0aGUgaG9zdCBkb2Vzbid0IHJlLXJlY29yZCBpdCAodGhlXG4gICAgICAgICAgLy8gd29ya2Zsb3cncyBvd24gYWJvcnQoKSBjYWxsIGNhbiBzZXQgdGhlIGZsYWcgYmVmb3JlIHRoaXNcbiAgICAgICAgICAvLyBldmVudCBpcyBwcm9jZXNzZWQgd2hlbiBpdCBoYXBwZW5zIGxhdGVyIGluIHJlcGxheSBvcmRlcixcbiAgICAgICAgICAvLyBhbmQgaG9va19yZWNlaXZlZCBldmVudHMgYXJlIG5vdCB1bmlxdWUgcGVyIGNvcnJlbGF0aW9uSWQpLlxuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYChmdW5jdGlvbigpe2AgK1xuICAgICAgICAgICAgICBgdmFyIHA9Z2xvYmFsVGhpcy5fX3BlbmRpbmcuZmluZChmdW5jdGlvbihxKXtyZXR1cm4gcS5jb3JyZWxhdGlvbklkPT09JHtKU09OLnN0cmluZ2lmeShjaWQpfSYmcS50eXBlPT09XCJob29rXCI7fSk7YCArXG4gICAgICAgICAgICAgIGBpZihwKXAuYWJvcnRSZXF1ZXN0ZWQ9ZmFsc2U7YCArXG4gICAgICAgICAgICAgIGB9KSgpYFxuICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIGlmIChldmVudC5ldmVudElkKSB7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyA9IGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzIHx8IHt9KVske0pTT04uc3RyaW5naWZ5KGV2ZW50LmV2ZW50SWQpfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBoYXNSZXNvbHZlciA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoYCEhZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV1gKVxuICAgICAgICApO1xuICAgICAgICBjb25zdCByYXdQYXlsb2FkID0gZXZlbnREYXRhPy5wYXlsb2FkID8/IGV2ZW50RGF0YT8ucmVzdWx0O1xuICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRdWlja0pTIHJ1bnRpbWU6IHByb2Nlc3NpbmcgaG9va19yZWNlaXZlZCcsIHtcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBjaWQsXG4gICAgICAgICAgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCxcbiAgICAgICAgICBoYXNSZXNvbHZlcixcbiAgICAgICAgICBwYXlsb2FkVHlwZTogdHlwZW9mIHJhd1BheWxvYWQsXG4gICAgICAgICAgcGF5bG9hZElzVWludDhBcnJheTogcmF3UGF5bG9hZCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXksXG4gICAgICAgICAgcGF5bG9hZEtleXM6XG4gICAgICAgICAgICByYXdQYXlsb2FkICYmIHR5cGVvZiByYXdQYXlsb2FkID09PSAnb2JqZWN0J1xuICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHJhd1BheWxvYWQpXG4gICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgaWYgKHJhd1BheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgICAvLyBEZWNyeXB0IGlmIGVuY3J5cHRlZCDigJQgdGhlIFZNIG9ubHkgdW5kZXJzdGFuZHMgJ2RldmwnIGZvcm1hdFxuICAgICAgICAgICAgY29uc3QgZGVjcnlwdGVkUGF5bG9hZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdQYXlsb2FkLFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgYnl0ZXNIYW5kbGUgPSB2bS5uZXdVaW50OEFycmF5KGRlY3J5cHRlZFBheWxvYWQpO1xuICAgICAgICAgICAgdm0uc2V0UHJvcCh2bS5nbG9iYWwsICdfX3RtcF9yZXN1bHQnLCBieXRlc0hhbmRsZSk7XG4gICAgICAgICAgICBieXRlc0hhbmRsZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlc29sdmUoZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwid29ya2Zsb3ctZGVzZXJpYWxpemVcIildKGdsb2JhbFRoaXMuX190bXBfcmVzdWx0KSk7YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX190bXBfcmVzdWx0O2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBzZXJpYWxpemVkID1cbiAgICAgICAgICAgICAgcmF3UGF5bG9hZCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShyYXdQYXlsb2FkKVxuICAgICAgICAgICAgICAgIDogJ3VuZGVmaW5lZCc7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlc29sdmUoJHtzZXJpYWxpemVkfSk7YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gTWFyayB0aGlzIGV2ZW50IGFzIHByb2Nlc3NlZCBpbiB0aGUgVk0gaGVhcCB0byBwcmV2ZW50XG4gICAgICAgICAgLy8gZG91YmxlLWRlbGl2ZXJ5IHdoZW4gdGhlIG91dGVyIGxvb3AgcmUtc2NhbnMgZXZlbnRzLlxuICAgICAgICAgIGlmIChldmVudC5ldmVudElkKSB7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyA9IGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzIHx8IHt9KVske0pTT04uc3RyaW5naWZ5KGV2ZW50LmV2ZW50SWQpfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCDigJQgYnVmZmVyIHRoZSBwYXlsb2FkIGluIHRoZSBWTSBoZWFwLiBXaGVuXG4gICAgICAgICAgLy8gY3JlYXRlSG9va1Byb21pc2UoKSBpcyBjYWxsZWQgbGF0ZXIsIGl0IHdpbGwgZHJhaW4gdGhpcyBidWZmZXJcbiAgICAgICAgICAvLyBmaXJzdCAobWF0Y2hpbmcgdGhlIG5vZGU6dm0gZW5naW5lJ3MgcGF5bG9hZHNRdWV1ZSBiZWhhdmlvcikuXG4gICAgICAgICAgY29uc3QgZXZlbnRJZEpzID0gZXZlbnQuZXZlbnRJZFxuICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShldmVudC5ldmVudElkKVxuICAgICAgICAgICAgOiAnbnVsbCc7XG4gICAgICAgICAgY29uc3QgYnVmZmVyQW5kVHJhY2sgPVxuICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXJbJHtjaWRKc31dID0gZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyWyR7Y2lkSnN9XSB8fCBbXSlgICtcbiAgICAgICAgICAgIGAucHVzaCglUEFZTE9BRCUpO2AgK1xuICAgICAgICAgICAgKGV2ZW50LmV2ZW50SWRcbiAgICAgICAgICAgICAgPyBgKGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzID0gZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyLl9fcHJvY2Vzc2VkRXZlbnRJZHMgfHwge30pWyR7ZXZlbnRJZEpzfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICAgOiAnJyk7XG4gICAgICAgICAgaWYgKHJhd1BheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgICAvLyBEZWNyeXB0IGlmIGVuY3J5cHRlZCDigJQgdGhlIFZNIG9ubHkgdW5kZXJzdGFuZHMgJ2RldmwnIGZvcm1hdFxuICAgICAgICAgICAgY29uc3QgZGVjcnlwdGVkUGF5bG9hZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdQYXlsb2FkLFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgYnl0ZXNIYW5kbGUgPSB2bS5uZXdVaW50OEFycmF5KGRlY3J5cHRlZFBheWxvYWQpO1xuICAgICAgICAgICAgdm0uc2V0UHJvcCh2bS5nbG9iYWwsICdfX3RtcF9yZXN1bHQnLCBieXRlc0hhbmRsZSk7XG4gICAgICAgICAgICBieXRlc0hhbmRsZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAvLyBOT1RFOiByZXBsYWNlbWVudCBpcyBhIGZ1bmN0aW9uIHNvIGAkYC1zZXF1ZW5jZXMgaW4gdGhlXG4gICAgICAgICAgICAvLyBzdWJzdGl0dXRlZCBKUyBuZXZlciBnZXQgaW50ZXJwcmV0ZWQgYXMgU3RyaW5nLnJlcGxhY2VcbiAgICAgICAgICAgIC8vIHNwZWNpYWwgcmVwbGFjZW1lbnQgcGF0dGVybnMuXG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYnVmZmVyQW5kVHJhY2sucmVwbGFjZShcbiAgICAgICAgICAgICAgICAnJVBBWUxPQUQlJyxcbiAgICAgICAgICAgICAgICAoKSA9PlxuICAgICAgICAgICAgICAgICAgJ2dsb2JhbFRoaXNbU3ltYm9sLmZvcihcIndvcmtmbG93LWRlc2VyaWFsaXplXCIpXShnbG9iYWxUaGlzLl9fdG1wX3Jlc3VsdCknXG4gICAgICAgICAgICAgICkgKyAnZGVsZXRlIGdsb2JhbFRoaXMuX190bXBfcmVzdWx0OydcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBzZXJpYWxpemVkID1cbiAgICAgICAgICAgICAgcmF3UGF5bG9hZCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShyYXdQYXlsb2FkKVxuICAgICAgICAgICAgICAgIDogJ3VuZGVmaW5lZCc7XG4gICAgICAgICAgICAvLyBGdW5jdGlvbiByZXBsYWNlbWVudDogYSBKU09OLXNlcmlhbGl6ZWQgcGF5bG9hZCBjYW4gY29udGFpblxuICAgICAgICAgICAgLy8gYCQmYCwgYCQnYCwgYCRcXGBgLCAuLi4gd2hpY2ggU3RyaW5nLnJlcGxhY2Ugd291bGQgb3RoZXJ3aXNlXG4gICAgICAgICAgICAvLyBleHBhbmQsIHNpbGVudGx5IGNvcnJ1cHRpbmcgdGhlIGluamVjdGVkIGNvZGUuXG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYnVmZmVyQW5kVHJhY2sucmVwbGFjZSgnJVBBWUxPQUQlJywgKCkgPT4gc2VyaWFsaXplZClcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ2hvb2tfY29uZmxpY3QnOiB7XG4gICAgICAgIC8vIEFub3RoZXIgd29ya2Zsb3cgb3ducyB0aGlzIGhvb2sgdG9rZW4uIFBheWxvYWQgYXdhaXRlcnMgcmVqZWN0XG4gICAgICAgIC8vIHdpdGggSG9va0NvbmZsaWN0RXJyb3I7IGdldENvbmZsaWN0KCkgYXdhaXRlcnMgcmVzb2x2ZSB3aXRoIGFcbiAgICAgICAgLy8gUnVuIGhhbmRsZSBmb3IgdGhlIGNvbmZsaWN0aW5nIHJ1biAocmV2aXZlZCB0aHJvdWdoIHRoZSBWTSdzXG4gICAgICAgIC8vIGNsYXNzIHJlZ2lzdHJ5IHNvIGl0cyBtZXRob2RzIGFyZSBkdXJhYmxlIHN0ZXAgcHJveGllcykgb3JcbiAgICAgICAgLy8gcmVqZWN0IHdpdGggdGhlIGVycm9yIHdoZW4gbm8gaGFuZGxlIGNhbiBiZSBjb25zdHJ1Y3RlZCDigJRcbiAgICAgICAgLy8gbWlycm9yaW5nIHRoZSBub2RlOnZtIGVuZ2luZSdzIGhvb2sudHMgaG9va19jb25mbGljdCBoYW5kbGluZy5cbiAgICAgICAgY29uc3QgY29uZmxpY3RUb2tlbiA9IChldmVudERhdGE/LnRva2VuIGFzIHN0cmluZykgPz8gJ3Vua25vd24nO1xuICAgICAgICBjb25zdCBjb25mbGljdGluZ1J1bklkID0gZXZlbnREYXRhPy5jb25mbGljdGluZ1J1bklkIGFzXG4gICAgICAgICAgfCBzdHJpbmdcbiAgICAgICAgICB8IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgZGlkU2V0dGxlID0gdm0uZHVtcChcbiAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgIGAoZnVuY3Rpb24oKXtcbiAgICAgICAgICAgICAgdmFyIGNpZCA9ICR7SlNPTi5zdHJpbmdpZnkoY2lkKX07XG4gICAgICAgICAgICAgIHZhciB0b2tlbiA9ICR7SlNPTi5zdHJpbmdpZnkoY29uZmxpY3RUb2tlbil9O1xuICAgICAgICAgICAgICB2YXIgY29uZmxpY3RpbmdSdW5JZCA9ICR7SlNPTi5zdHJpbmdpZnkoY29uZmxpY3RpbmdSdW5JZCA/PyBudWxsKX07XG4gICAgICAgICAgICAgIHZhciBFcnJDbHMgPSBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoJ0B3b3JrZmxvdy9lcnJvcnMvL0hvb2tDb25mbGljdEVycm9yJyldO1xuICAgICAgICAgICAgICB2YXIgZXJyO1xuICAgICAgICAgICAgICBpZiAodHlwZW9mIEVyckNscyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIGVyciA9IG5ldyBFcnJDbHModG9rZW4sIGNvbmZsaWN0aW5nUnVuSWQgfHwgdW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBuZXcgRXJyb3IoJ0hvb2sgdG9rZW4gXCInICsgdG9rZW4gKyAnXCIgaXMgYWxyZWFkeSBpbiB1c2UgYnkgYW5vdGhlciB3b3JrZmxvdycpO1xuICAgICAgICAgICAgICAgIGVyci5uYW1lID0gJ0hvb2tDb25mbGljdEVycm9yJztcbiAgICAgICAgICAgICAgICBlcnIudG9rZW4gPSB0b2tlbjtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmxpY3RpbmdSdW5JZCkgZXJyLmNvbmZsaWN0aW5nUnVuSWQgPSBjb25mbGljdGluZ1J1bklkO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHZhciBydW4gPSBudWxsO1xuICAgICAgICAgICAgICBpZiAoY29uZmxpY3RpbmdSdW5JZCkge1xuICAgICAgICAgICAgICAgIHZhciByZWcgPSBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoJ3dvcmtmbG93LWNsYXNzLXJlZ2lzdHJ5JyldO1xuICAgICAgICAgICAgICAgIHZhciBSdW5DbHMgPSByZWcgJiYgcmVnLmdldCgnY2xhc3MvL3dvcmtmbG93Ly9SdW4nKTtcbiAgICAgICAgICAgICAgICB2YXIgZGVzID0gUnVuQ2xzICYmIFJ1bkNsc1tTeW1ib2wuZm9yKCd3b3JrZmxvdy1kZXNlcmlhbGl6ZScpXTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGRlcyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgcnVuID0gZGVzLmNhbGwoUnVuQ2xzLCB7IHJ1bklkOiBjb25mbGljdGluZ1J1bklkIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB2YXIgc2V0dGxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICB2YXIgc3RhdGUgPSBnbG9iYWxUaGlzLl9faG9va3MgJiYgZ2xvYmFsVGhpcy5fX2hvb2tzW2NpZF07XG4gICAgICAgICAgICAgIGlmIChzdGF0ZSAmJiAhc3RhdGUuY29uZmxpY3QpIHtcbiAgICAgICAgICAgICAgICBzdGF0ZS5jb25mbGljdCA9IHsgZXJyb3I6IGVyciwgcnVuOiBydW4gfTtcbiAgICAgICAgICAgICAgICB2YXIgZ2MgPSBzdGF0ZS5nZXRDb25mbGljdFJlc29sdmVycztcbiAgICAgICAgICAgICAgICBzdGF0ZS5nZXRDb25mbGljdFJlc29sdmVycyA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZ2MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgIGlmIChydW4pIHsgZ2NbaV0ucmVzb2x2ZShydW4pOyB9IGVsc2UgeyBnY1tpXS5yZWplY3QoZXJyKTsgfVxuICAgICAgICAgICAgICAgICAgc2V0dGxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NpZF0pIHtcbiAgICAgICAgICAgICAgICBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NpZF0ucmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbY2lkXTtcbiAgICAgICAgICAgICAgICBzZXR0bGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gc2V0dGxlZDtcbiAgICAgICAgICAgIH0pKClgXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICBpZiAoZGlkU2V0dGxlKSB7XG4gICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgIGxldCBiOiBudW1iZXI7XG4gICAgICAgICAgZG8ge1xuICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgIH0gd2hpbGUgKGIgPiAwKTtcbiAgICAgICAgfVxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ3N0ZXBfY3JlYXRlZCc6XG4gICAgICBjYXNlICdzdGVwX3N0YXJ0ZWQnOlxuICAgICAgY2FzZSAnc3RlcF9yZXRyeWluZyc6XG4gICAgICBjYXNlICd3YWl0X2NyZWF0ZWQnOiB7XG4gICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAnaG9va19jcmVhdGVkJzoge1xuICAgICAgICAvLyBDb25maXJtIGNyZWF0aW9uIGZvciBnZXRDb25mbGljdCgpIGF3YWl0ZXJzOiByZXNvbHZlIHRoZW0gd2l0aFxuICAgICAgICAvLyBudWxsIChubyBjb25mbGljdCkgb25jZSB0aGUgZXZlbnQgbG9nIHByb3ZlcyB0aGUgaG9vayBleGlzdHMuXG4gICAgICAgIGNvbnN0IHNldHRsZWRHZXRDb25mbGljdCA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgKGZ1bmN0aW9uKCl7XG4gICAgICAgICAgICAgIHZhciBzdGF0ZSA9IGdsb2JhbFRoaXMuX19ob29rcyAmJiBnbG9iYWxUaGlzLl9faG9va3NbJHtKU09OLnN0cmluZ2lmeShjaWQpfV07XG4gICAgICAgICAgICAgIGlmICghc3RhdGUpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgc3RhdGUuY3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgIHZhciBnYyA9IHN0YXRlLmdldENvbmZsaWN0UmVzb2x2ZXJzO1xuICAgICAgICAgICAgICBzdGF0ZS5nZXRDb25mbGljdFJlc29sdmVycyA9IFtdO1xuICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdjLmxlbmd0aDsgaSsrKSBnY1tpXS5yZXNvbHZlKG51bGwpO1xuICAgICAgICAgICAgICByZXR1cm4gZ2MubGVuZ3RoID4gMDtcbiAgICAgICAgICAgIH0pKClgXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICBpZiAoc2V0dGxlZEdldENvbmZsaWN0KSB7XG4gICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgIGxldCBiOiBudW1iZXI7XG4gICAgICAgICAgZG8ge1xuICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgIH0gd2hpbGUgKGIgPiAwKTtcbiAgICAgICAgfVxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ2hvb2tfZGlzcG9zZWQnOiB7XG4gICAgICAgIC8vIERpc2FtYmlndWF0ZSBmcm9tIHRoZSBgaG9va2AgcGVuZGluZyBvcCB3aXRoIHRoZSBzYW1lXG4gICAgICAgIC8vIGNvcnJlbGF0aW9uSWQg4oCUIHdlIHdhbnQgdG8gbWFyayB0aGUgYGhvb2tfZGlzcG9zZWAgZW50cnkuXG4gICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcywgJ2hvb2tfZGlzcG9zZScpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc29sdmVkO1xufVxuXG5mdW5jdGlvbiBtYXJrQ3JlYXRlZCh2bTogUXVpY2tKUywgY2lkSnM6IHN0cmluZywgb3BUeXBlPzogc3RyaW5nKTogdm9pZCB7XG4gIC8vIGBjaWRKc2AgaXMgdGhlIEpTT04uc3RyaW5naWZ5LXF1b3RlZCBjb3JyZWxhdGlvbiBpZCAoc2VlIHByb2Nlc3NFdmVudHMpLlxuICAvLyBgaG9va2AgYW5kIGBob29rX2Rpc3Bvc2VgIHBlbmRpbmcgb3BzIHNoYXJlIHRoZSBzYW1lIGNvcnJlbGF0aW9uSWQsXG4gIC8vIHNvIHdoZW4gcHJvY2Vzc2luZyBgaG9va19kaXNwb3NlZGAgZXZlbnRzIHdlIG11c3QgZGlzYW1iaWd1YXRlIGJ5XG4gIC8vIHR5cGUg4oCUIG90aGVyd2lzZSBgLmZpbmQoKWAgcmV0dXJucyB0aGUgb3JpZ2luYWwgYGhvb2tgIG9wIGFuZCB0aGVcbiAgLy8gYGhvb2tfZGlzcG9zZWAgb3AgaXMgbmV2ZXIgbWFya2VkLCBjYXVzaW5nIHRoZSBlbnRyeXBvaW50IHRvIGtlZXBcbiAgLy8gcmV0cnlpbmcgYSBob29rX2Rpc3Bvc2VkIGZvciBhbiBhbHJlYWR5LWRlbGV0ZWQgZW50aXR5LlxuICBjb25zdCBwcmVkaWNhdGUgPSBvcFR5cGVcbiAgICA/IGBmdW5jdGlvbihwKXtyZXR1cm4gcC5jb3JyZWxhdGlvbklkPT09JHtjaWRKc30mJnAudHlwZT09PSR7SlNPTi5zdHJpbmdpZnkob3BUeXBlKX07fWBcbiAgICA6IGBmdW5jdGlvbihwKXtyZXR1cm4gcC5jb3JyZWxhdGlvbklkPT09JHtjaWRKc307fWA7XG4gIHZtLmV2YWxDb2RlKFxuICAgIGB2YXIgX19wPWdsb2JhbFRoaXMuX19wZW5kaW5nLmZpbmQoJHtwcmVkaWNhdGV9KTtgICtcbiAgICAgIGBpZihfX3ApX19wLmhhc0NyZWF0ZWRFdmVudD10cnVlO2BcbiAgKS5kaXNwb3NlKCk7XG59XG5cbi8vIC0tLS0gU3RhdGUgQ2hlY2tpbmcgLS0tLVxuXG4vKipcbiAqIENvbGxlY3QgbGVmdG92ZXIgcGVuZGluZyBvcGVyYXRpb25zIHRoYXQgbmVlZCBkdXJhYmxlIHNpZGUgZWZmZWN0cyB3aGVuXG4gKiB0aGUgd29ya2Zsb3cgcmVhY2hlcyBhIHRlcm1pbmFsIHN0YXRlLiBNaXJyb3JzIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4gKiBkcmFpblBlbmRpbmdRdWV1ZUl0ZW1zICh3b3JrZmxvdy50cyk6IHN0aWxsLWFsaXZlIHN5c3RlbSBob29rc1xuICogKEFib3J0Q29udHJvbGxlcikgd2l0aG91dCBhbiBhYm9ydCBpbiBmbGlnaHQgYXJlIGltcGxpY2l0bHkgZGlzcG9zZWQgc29cbiAqIHRoZXkgZG9uJ3QgbGVhayBob29rIHJvd3M7IG9wcyB3aXRob3V0IGNyZWF0ZWQgZXZlbnRzIChmaXJlLWFuZC1mb3JnZXRcbiAqIGF0dHJpYnV0ZXMvaG9va3Mvc3RlcHMvd2FpdHMpIGFuZCBwZW5kaW5nIGFib3J0IHJlY29yZGluZ3MgYXJlIHN1cmZhY2VkXG4gKiBmb3IgdGhlIGVudHJ5cG9pbnQgdG8gZmx1c2guXG4gKi9cbmZ1bmN0aW9uIGNvbGxlY3REcmFpbk9wZXJhdGlvbnModm06IFF1aWNrSlMpOiBQZW5kaW5nT3BlcmF0aW9uW10ge1xuICB1c2luZyBoID0gdm0uZXZhbENvZGUoYChmdW5jdGlvbigpe1xuICAgIHZhciB0b0Rpc3Bvc2UgPSBbXTtcbiAgICBnbG9iYWxUaGlzLl9fcGVuZGluZy5mb3JFYWNoKGZ1bmN0aW9uKHApe1xuICAgICAgaWYgKHAudHlwZSA9PT0gXCJob29rXCIgJiYgcC5pc1N5c3RlbSAmJiAhcC5hYm9ydFJlcXVlc3RlZCAmJiAhcC5kaXNwb3NlZCkge1xuICAgICAgICBwLmRpc3Bvc2VkID0gdHJ1ZTtcbiAgICAgICAgLy8gT25seSBkaXNwb3NlIGhvb2tzIHRoYXQgd2VyZSBkdXJhYmx5IGNyZWF0ZWQ7IGEgaG9vayB0aGF0IG5ldmVyXG4gICAgICAgIC8vIHJlYWNoZWQgc3RvcmFnZSBoYXMgbm90aGluZyB0byBjbGVhbiB1cC5cbiAgICAgICAgaWYgKHAuaGFzQ3JlYXRlZEV2ZW50KSB7XG4gICAgICAgICAgdG9EaXNwb3NlLnB1c2goe1xuICAgICAgICAgICAgdHlwZTogXCJob29rX2Rpc3Bvc2VcIixcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHAuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB0b0Rpc3Bvc2UuZm9yRWFjaChmdW5jdGlvbihkKXsgZ2xvYmFsVGhpcy5fX3BlbmRpbmcucHVzaChkKTsgfSk7XG4gICAgcmV0dXJuIGdsb2JhbFRoaXMuX19wZW5kaW5nLmZpbHRlcihmdW5jdGlvbihwKXtcbiAgICAgIGlmIChwLmFib3J0UmVxdWVzdGVkKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGlmIChwLmhhc0NyZWF0ZWRFdmVudCkgcmV0dXJuIGZhbHNlO1xuICAgICAgLy8gU2tpcCBzeXN0ZW0gaG9va3MgdGhhdCB3ZXJlIGRpc3Bvc2VkIGJlZm9yZSBldmVyIGJlaW5nIGNyZWF0ZWQuXG4gICAgICBpZiAocC50eXBlID09PSBcImhvb2tcIiAmJiBwLmRpc3Bvc2VkKSByZXR1cm4gZmFsc2U7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgfSkoKWApO1xuICByZXR1cm4gdm0uZHVtcChoKSBhcyBQZW5kaW5nT3BlcmF0aW9uW107XG59XG5cbmZ1bmN0aW9uIGNoZWNrV29ya2Zsb3dTdGF0ZShcbiAgdm06IFF1aWNrSlMsXG4gIG9wdHM6IHsga2VlcEFsaXZlT25TdXNwZW5kPzogYm9vbGVhbiB9ID0ge31cbik6IFF1aWNrSlNSdW50aW1lUmVzdWx0IHtcbiAgLy8gQ2hlY2sgY29tcGxldGVkIOKAlCBfX3dvcmtmbG93UmVzdWx0IGlzIGEgZm9ybWF0LXByZWZpeGVkIFVpbnQ4QXJyYXlcbiAge1xuICAgIHVzaW5nIGggPSB2bS5ldmFsQ29kZSgnZ2xvYmFsVGhpcy5fX3dvcmtmbG93UmVzdWx0Jyk7XG4gICAgaWYgKCFoLmlzVW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCByZXN1bHRCeXRlcyA9IGgudG9VaW50OEFycmF5KCk7XG4gICAgICBjb25zdCBkcmFpbk9wZXJhdGlvbnMgPSBjb2xsZWN0RHJhaW5PcGVyYXRpb25zKHZtKTtcbiAgICAgIHZtLmRpc3Bvc2UoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBsZXRlZDoge1xuICAgICAgICAgIHJlc3VsdDogcmVzdWx0Qnl0ZXMsXG4gICAgICAgICAgLi4uKGRyYWluT3BlcmF0aW9ucy5sZW5ndGggPiAwID8geyBkcmFpbk9wZXJhdGlvbnMgfSA6IHt9KSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgZmFpbGVkXG4gIHtcbiAgICB1c2luZyBoID0gdm0uZXZhbENvZGUoJ2dsb2JhbFRoaXMuX193b3JrZmxvd0Vycm9yJyk7XG4gICAgaWYgKCFoLmlzVW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBlcnJvck9iaiA9IHZtLmR1bXAoaCkgYXNcbiAgICAgICAgfCB7XG4gICAgICAgICAgICBtZXNzYWdlOiBzdHJpbmc7XG4gICAgICAgICAgICBzdGFjaz86IHN0cmluZztcbiAgICAgICAgICAgIG5hbWU/OiBzdHJpbmc7XG4gICAgICAgICAgICB2YWx1ZUJ5dGVzPzogVWludDhBcnJheTtcbiAgICAgICAgICB9XG4gICAgICAgIHwgc3RyaW5nO1xuICAgICAgY29uc3QgZmFpbGVkID1cbiAgICAgICAgdHlwZW9mIGVycm9yT2JqID09PSAnc3RyaW5nJ1xuICAgICAgICAgID8geyBtZXNzYWdlOiBlcnJvck9iaiB9XG4gICAgICAgICAgOiB7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGVycm9yT2JqLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIHN0YWNrOiBlcnJvck9iai5zdGFjayB8fCB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIG5hbWU6IGVycm9yT2JqLm5hbWUgfHwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICB2YWx1ZUJ5dGVzOiBlcnJvck9iai52YWx1ZUJ5dGVzLFxuICAgICAgICAgICAgfTtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoJ1F1aWNrSlMgcnVudGltZTogd29ya2Zsb3cgZmFpbGVkIGluIFZNJywge1xuICAgICAgICBlcnJvck1lc3NhZ2U6IGZhaWxlZC5tZXNzYWdlLFxuICAgICAgICBlcnJvck5hbWU6IGZhaWxlZC5uYW1lLFxuICAgICAgICBlcnJvclN0YWNrOiBmYWlsZWQuc3RhY2ssXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGRyYWluT3BlcmF0aW9ucyA9IGNvbGxlY3REcmFpbk9wZXJhdGlvbnModm0pO1xuICAgICAgdm0uZGlzcG9zZSgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmFpbGVkOiB7XG4gICAgICAgICAgLi4uZmFpbGVkLFxuICAgICAgICAgIC4uLihkcmFpbk9wZXJhdGlvbnMubGVuZ3RoID4gMCA/IHsgZHJhaW5PcGVyYXRpb25zIH0gOiB7fSksXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIHN1c3BlbmRlZCDigJQgdGhlIHdvcmtmbG93IGlzIHN1c3BlbmRlZCBpZiB0aGVyZSBhcmUgYWN0aXZlIHJlc29sdmVyc1xuICAvLyBPUiBwZW5kaW5nIG9wZXJhdGlvbnMgdGhhdCBoYXZlbid0IGJlZW4gY3JlYXRlZCB5ZXQgKGUuZy4gaG9va3MgY3JlYXRlZFxuICAvLyB1cGZyb250IGJ1dCBub3QgeWV0IGF3YWl0ZWQpXG4gIHtcbiAgICB1c2luZyBoID0gdm0uZXZhbENvZGUoXG4gICAgICAnT2JqZWN0LmtleXMoZ2xvYmFsVGhpcy5fX3Jlc29sdmVycykubGVuZ3RoID4gMCB8fCBnbG9iYWxUaGlzLl9fcGVuZGluZy5zb21lKGZ1bmN0aW9uKHApe3JldHVybiFwLmhhc0NyZWF0ZWRFdmVudDt9KSdcbiAgICApO1xuICAgIGlmICh2bS5kdW1wKGgpKSB7XG4gICAgICB1c2luZyBwZW5kaW5nSCA9IHZtLmV2YWxDb2RlKFxuICAgICAgICAvLyBPcHMgd2l0aCBhbiBhY3RpdmUgcmVzb2x2ZXIgb3Igd2l0aG91dCBhIGNyZWF0ZWQgZXZlbnQgYXJlXG4gICAgICAgIC8vIHBlbmRpbmc7IGFib3J0LXJlcXVlc3RlZCBob29rcyBhcmUgYWxzbyBzdXJmYWNlZCAoZXZlbiB3aGVuXG4gICAgICAgIC8vIGFscmVhZHkgY3JlYXRlZCBhbmQgdW5hd2FpdGVkKSBzbyB0aGUgaG9zdCByZWNvcmRzIHRoZSBhYm9ydC5cbiAgICAgICAgYGdsb2JhbFRoaXMuX19wZW5kaW5nLmZpbHRlcihmdW5jdGlvbihwKXtyZXR1cm4hIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbcC5jb3JyZWxhdGlvbklkXSB8fCAhcC5oYXNDcmVhdGVkRXZlbnQgfHwgcC5hYm9ydFJlcXVlc3RlZDt9KWBcbiAgICAgICk7XG4gICAgICBjb25zdCBwZW5kaW5nT3BzID0gdm0uZHVtcChwZW5kaW5nSCkgYXMgUGVuZGluZ09wZXJhdGlvbltdO1xuICAgICAgaWYgKCFvcHRzLmtlZXBBbGl2ZU9uU3VzcGVuZCkgdm0uZGlzcG9zZSgpO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdXNwZW5kZWQ6IHtcbiAgICAgICAgICBwZW5kaW5nT3BlcmF0aW9uczogcGVuZGluZ09wcyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgdm0uZGlzcG9zZSgpO1xuICByZXR1cm4geyBmYWlsZWQ6IHsgbWVzc2FnZTogJ1dvcmtmbG93IGVuZGVkIGluIHVua25vd24gc3RhdGUnIH0gfTtcbn1cblxuLy8gLS0tLSBIZWxwZXJzIC0tLS1cblxuZnVuY3Rpb24gZXh0cmFjdEVycm9yKFxuICB2bTogUXVpY2tKUyxcbiAgZXJyOiB1bmtub3duLFxuICBmYWxsYmFja01lc3NhZ2U6IHN0cmluZ1xuKTogUXVpY2tKU1J1bnRpbWVSZXN1bHQge1xuICBsZXQgbWVzc2FnZSA9IGZhbGxiYWNrTWVzc2FnZTtcbiAgbGV0IHN0YWNrOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBuYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgaWYgKGVyciBpbnN0YW5jZW9mIEpTRXhjZXB0aW9uKSB7XG4gICAgY29uc3QgZXJyb3IgPSB2bS5kdW1wKGVyci5oYW5kbGUpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbDtcbiAgICBlcnIuaGFuZGxlLmRpc3Bvc2UoKTtcbiAgICBtZXNzYWdlID0gKGVycm9yPy5tZXNzYWdlIGFzIHN0cmluZykgPz8gZXJyLm1lc3NhZ2UgPz8gZmFsbGJhY2tNZXNzYWdlO1xuICAgIHN0YWNrID0gKGVycm9yPy5zdGFjayBhcyBzdHJpbmcpID8/IGVyci5zdGFjaztcbiAgICBuYW1lID0gKGVycm9yPy5uYW1lIGFzIHN0cmluZykgPz8gZXJyLm5hbWU7XG4gIH0gZWxzZSBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICBtZXNzYWdlID0gZXJyLm1lc3NhZ2UgPz8gZmFsbGJhY2tNZXNzYWdlO1xuICAgIHN0YWNrID0gZXJyLnN0YWNrO1xuICAgIG5hbWUgPSBlcnIubmFtZTtcbiAgfVxuXG4gIHZtLmRpc3Bvc2UoKTtcbiAgcmV0dXJuIHtcbiAgICBmYWlsZWQ6IHsgbWVzc2FnZSwgc3RhY2ssIG5hbWUgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBNdXRhYmxlIGludGVycnVwdCBidWRnZXQgZm9yIGEgVk0uIFF1aWNrSlMgcG9sbHMgdGhlIGludGVycnVwdCBoYW5kbGVyXG4gKiBkdXJpbmcgSlMgZXhlY3V0aW9uOyB3aGVuIGl0IHJldHVybnMgdHJ1ZSwgZXhlY3V0aW9uIGFib3J0cy4gVGhlIGJ1ZGdldFxuICogYm91bmRzIGEgc2luZ2xlIGhvc3QtPlZNIGV4ZWN1dGlvbiBidXJzdCAoYnVuZGxlIGV2YWwgKyBldmVudFxuICogcHJvY2Vzc2luZyksIG5vdCB0b3RhbCBWTSBsaWZldGltZSDigJQgdGhlIGlubGluZS1zdGVwIGxvb3Aga2VlcHMgYSBWTVxuICogYWxpdmUgYWNyb3NzIHN0ZXAgZXhlY3V0aW9ucyB0aGF0IGNhbiBsZWdpdGltYXRlbHkgdGFrZSBtaW51dGVzLCBzbyB0aGVcbiAqIGhvc3QgcmVzZXRzIHRoZSBidWRnZXQgYmVmb3JlIGVhY2ggcmUtZW50cnkgKHNlZSByZXNldEJ1ZGdldCBjYWxscykuXG4gKlxuICogVGhlIHBlci1idXJzdCBjZWlsaW5nIGlzIHRoZSBzYW1lIGNvbmZpZ3VyYWJsZSBidWRnZXQgYXMgdGhlIG5vZGVcbiAqIGVuZ2luZSdzIFJlcGxheUJ1ZGdldCAoUkVQTEFZX1RJTUVPVVRfTVMsIGRlZmF1bHQgMjQwcyk6IGEgd29ya2Zsb3dcbiAqIHdob3NlIHJlcGxheSB0aGUgbm9kZSBlbmdpbmUgaGFuZGxlcyBmaW5lIG11c3Qgbm90IGJlIGludGVycnVwdGVkIGhlcmVcbiAqIGJ5IGEgbG93ZXIgaGFyZGNvZGVkIGNlaWxpbmcuIFRoZSBpbnRlcnJ1cHQgZXJyb3IgZXNjYXBlc1xuICogcnVuUXVpY2tKU1dvcmtmbG93IGFuZCByZWFjaGVzIHRoZSByZXBsYXkgbG9vcCdzIGNhdGNoIGluIHJ1bnRpbWUudHMsXG4gKiB3aGljaCByZWNvcmRzIHJ1bl9mYWlsZWQuXG4gKi9cbmludGVyZmFjZSBJbnRlcnJ1cHRCdWRnZXQge1xuICBzdGFydDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVJbnRlcnJ1cHRIYW5kbGVyKGJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0KTogKCkgPT4gYm9vbGVhbiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBnZXRSZXBsYXlUaW1lb3V0TXMoKTtcbiAgcmV0dXJuICgpID0+IERhdGUubm93KCkgLSBidWRnZXQuc3RhcnQgPiB0aW1lb3V0O1xufVxuIl19