@workflow/core 5.0.0-beta.5 → 5.0.0-beta.51

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 (317) hide show
  1. package/README.md +5 -0
  2. package/dist/attribute-changes.d.ts +5 -0
  3. package/dist/attribute-changes.d.ts.map +1 -0
  4. package/dist/attribute-changes.js +25 -0
  5. package/dist/capabilities.d.ts +35 -2
  6. package/dist/capabilities.d.ts.map +1 -1
  7. package/dist/capabilities.js +74 -5
  8. package/dist/capture-stack.d.ts +1 -1
  9. package/dist/capture-stack.js +2 -2
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +19 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +98 -6
  16. package/dist/context-violation-error.d.ts +5 -5
  17. package/dist/context-violation-error.d.ts.map +1 -1
  18. package/dist/context-violation-error.js +8 -6
  19. package/dist/create-hook.d.ts +72 -7
  20. package/dist/create-hook.d.ts.map +1 -1
  21. package/dist/create-hook.js +1 -1
  22. package/dist/define-hook.js +2 -2
  23. package/dist/describe-error.d.ts +7 -7
  24. package/dist/describe-error.d.ts.map +1 -1
  25. package/dist/describe-error.js +97 -12
  26. package/dist/encryption.d.ts +38 -4
  27. package/dist/encryption.d.ts.map +1 -1
  28. package/dist/encryption.js +96 -14
  29. package/dist/events-consumer.d.ts +297 -0
  30. package/dist/events-consumer.d.ts.map +1 -1
  31. package/dist/events-consumer.js +673 -42
  32. package/dist/flushable-stream.d.ts +97 -1
  33. package/dist/flushable-stream.d.ts.map +1 -1
  34. package/dist/flushable-stream.js +291 -11
  35. package/dist/global.d.ts +36 -2
  36. package/dist/global.d.ts.map +1 -1
  37. package/dist/global.js +21 -6
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -2
  41. package/dist/log-format.d.ts +2 -2
  42. package/dist/log-format.js +19 -12
  43. package/dist/logger.d.ts +1 -0
  44. package/dist/logger.d.ts.map +1 -1
  45. package/dist/logger.js +10 -6
  46. package/dist/private.d.ts +226 -9
  47. package/dist/private.d.ts.map +1 -1
  48. package/dist/private.js +626 -7
  49. package/dist/replay-divergence.d.ts +25 -0
  50. package/dist/replay-divergence.d.ts.map +1 -0
  51. package/dist/replay-divergence.js +61 -0
  52. package/dist/replay-payload-cache.d.ts +64 -0
  53. package/dist/replay-payload-cache.d.ts.map +1 -0
  54. package/dist/replay-payload-cache.js +158 -0
  55. package/dist/runtime/compute-instance.d.ts +13 -0
  56. package/dist/runtime/compute-instance.d.ts.map +1 -0
  57. package/dist/runtime/compute-instance.js +14 -0
  58. package/dist/runtime/constants.d.ts +315 -0
  59. package/dist/runtime/constants.d.ts.map +1 -1
  60. package/dist/runtime/constants.js +502 -16
  61. package/dist/runtime/count-step-started-events.d.ts +52 -0
  62. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  63. package/dist/runtime/count-step-started-events.js +72 -0
  64. package/dist/runtime/deployment-guard.d.ts +99 -0
  65. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  66. package/dist/runtime/deployment-guard.js +154 -0
  67. package/dist/runtime/get-port-lazy.d.ts +15 -0
  68. package/dist/runtime/get-port-lazy.d.ts.map +1 -1
  69. package/dist/runtime/get-port-lazy.js +75 -6
  70. package/dist/runtime/get-world-lazy.d.ts +5 -14
  71. package/dist/runtime/get-world-lazy.d.ts.map +1 -1
  72. package/dist/runtime/get-world-lazy.js +19 -29
  73. package/dist/runtime/helpers.d.ts +415 -29
  74. package/dist/runtime/helpers.d.ts.map +1 -1
  75. package/dist/runtime/helpers.js +686 -57
  76. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  77. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  78. package/dist/runtime/quickjs-assets.generated.js +30 -0
  79. package/dist/runtime/quickjs-entrypoint.d.ts +158 -0
  80. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  81. package/dist/runtime/quickjs-entrypoint.js +1863 -0
  82. package/dist/runtime/quickjs-log-view.d.ts +129 -0
  83. package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
  84. package/dist/runtime/quickjs-log-view.js +229 -0
  85. package/dist/runtime/quickjs-runtime.d.ts +244 -0
  86. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  87. package/dist/runtime/quickjs-runtime.js +2427 -0
  88. package/dist/runtime/quickjs-serde.d.ts +107 -0
  89. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  90. package/dist/runtime/quickjs-serde.js +2159 -0
  91. package/dist/runtime/replay-budget.d.ts +97 -0
  92. package/dist/runtime/replay-budget.d.ts.map +1 -0
  93. package/dist/runtime/replay-budget.js +139 -0
  94. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  95. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  96. package/dist/runtime/replay-recovery-reporter.js +64 -0
  97. package/dist/runtime/resume-hook.d.ts +91 -8
  98. package/dist/runtime/resume-hook.d.ts.map +1 -1
  99. package/dist/runtime/resume-hook.js +512 -89
  100. package/dist/runtime/resume-latency.d.ts +150 -0
  101. package/dist/runtime/resume-latency.d.ts.map +1 -0
  102. package/dist/runtime/resume-latency.js +155 -0
  103. package/dist/runtime/run-id-time.d.ts +19 -0
  104. package/dist/runtime/run-id-time.d.ts.map +1 -0
  105. package/dist/runtime/run-id-time.js +42 -0
  106. package/dist/runtime/run.d.ts +72 -7
  107. package/dist/runtime/run.d.ts.map +1 -1
  108. package/dist/runtime/run.js +280 -53
  109. package/dist/runtime/runs.d.ts +54 -3
  110. package/dist/runtime/runs.d.ts.map +1 -1
  111. package/dist/runtime/runs.js +126 -16
  112. package/dist/runtime/start.d.ts +101 -2
  113. package/dist/runtime/start.d.ts.map +1 -1
  114. package/dist/runtime/start.js +352 -61
  115. package/dist/runtime/step-executor.d.ts +186 -5
  116. package/dist/runtime/step-executor.d.ts.map +1 -1
  117. package/dist/runtime/step-executor.js +768 -130
  118. package/dist/runtime/step-latency.d.ts +220 -0
  119. package/dist/runtime/step-latency.d.ts.map +1 -0
  120. package/dist/runtime/step-latency.js +215 -0
  121. package/dist/runtime/step-ownership.d.ts +72 -0
  122. package/dist/runtime/step-ownership.d.ts.map +1 -0
  123. package/dist/runtime/step-ownership.js +114 -0
  124. package/dist/runtime/step-single-flight.d.ts +12 -0
  125. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  126. package/dist/runtime/step-single-flight.js +75 -0
  127. package/dist/runtime/suspension-handler.d.ts +247 -7
  128. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  129. package/dist/runtime/suspension-handler.js +1304 -125
  130. package/dist/runtime/unserializable-step.d.ts +34 -0
  131. package/dist/runtime/unserializable-step.d.ts.map +1 -0
  132. package/dist/runtime/unserializable-step.js +52 -0
  133. package/dist/runtime/vm-mode.d.ts +44 -0
  134. package/dist/runtime/vm-mode.d.ts.map +1 -0
  135. package/dist/runtime/vm-mode.js +62 -0
  136. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  137. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  138. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  139. package/dist/runtime/wait-continuation.d.ts +106 -0
  140. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  141. package/dist/runtime/wait-continuation.js +136 -0
  142. package/dist/runtime/wait-until.d.ts +18 -0
  143. package/dist/runtime/wait-until.d.ts.map +1 -0
  144. package/dist/runtime/wait-until.js +42 -0
  145. package/dist/runtime/world-compatibility.d.ts +32 -0
  146. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  147. package/dist/runtime/world-compatibility.js +44 -0
  148. package/dist/runtime/world-init.d.ts +17 -42
  149. package/dist/runtime/world-init.d.ts.map +1 -1
  150. package/dist/runtime/world-init.js +18 -43
  151. package/dist/runtime/world.d.ts +14 -2
  152. package/dist/runtime/world.d.ts.map +1 -1
  153. package/dist/runtime/world.js +75 -19
  154. package/dist/runtime.d.ts +10 -6
  155. package/dist/runtime.d.ts.map +1 -1
  156. package/dist/runtime.js +3911 -489
  157. package/dist/sealed-box.d.ts +167 -0
  158. package/dist/sealed-box.d.ts.map +1 -0
  159. package/dist/sealed-box.js +571 -0
  160. package/dist/serialization/client.d.ts +3 -3
  161. package/dist/serialization/client.d.ts.map +1 -1
  162. package/dist/serialization/client.js +8 -4
  163. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  164. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  165. package/dist/serialization/codec-devalue-vm.js +148 -0
  166. package/dist/serialization/codec-devalue.d.ts +1 -1
  167. package/dist/serialization/codec-devalue.d.ts.map +1 -1
  168. package/dist/serialization/codec-devalue.js +24 -6
  169. package/dist/serialization/codec.d.ts +37 -2
  170. package/dist/serialization/codec.d.ts.map +1 -1
  171. package/dist/serialization/codec.js +2 -2
  172. package/dist/serialization/compression.d.ts +105 -0
  173. package/dist/serialization/compression.d.ts.map +1 -0
  174. package/dist/serialization/compression.js +261 -0
  175. package/dist/serialization/encryption.d.ts +119 -17
  176. package/dist/serialization/encryption.d.ts.map +1 -1
  177. package/dist/serialization/encryption.js +152 -17
  178. package/dist/serialization/errors.d.ts +13 -0
  179. package/dist/serialization/errors.d.ts.map +1 -1
  180. package/dist/serialization/errors.js +20 -2
  181. package/dist/serialization/format.d.ts +6 -6
  182. package/dist/serialization/format.js +7 -7
  183. package/dist/serialization/hardened.d.ts +156 -0
  184. package/dist/serialization/hardened.d.ts.map +1 -0
  185. package/dist/serialization/hardened.js +538 -0
  186. package/dist/serialization/index.d.ts +10 -8
  187. package/dist/serialization/index.d.ts.map +1 -1
  188. package/dist/serialization/index.js +10 -8
  189. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  190. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  191. package/dist/serialization/reducers/class-vm.js +77 -0
  192. package/dist/serialization/reducers/class.d.ts.map +1 -1
  193. package/dist/serialization/reducers/class.js +11 -6
  194. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  195. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  196. package/dist/serialization/reducers/common-vm.js +616 -0
  197. package/dist/serialization/reducers/common.d.ts +1 -1
  198. package/dist/serialization/reducers/common.d.ts.map +1 -1
  199. package/dist/serialization/reducers/common.js +202 -62
  200. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  201. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  202. package/dist/serialization/reducers/step-function-vm.js +97 -0
  203. package/dist/serialization/reducers/step-function.d.ts.map +1 -1
  204. package/dist/serialization/reducers/step-function.js +25 -9
  205. package/dist/serialization/step.d.ts +4 -4
  206. package/dist/serialization/step.d.ts.map +1 -1
  207. package/dist/serialization/step.js +9 -5
  208. package/dist/serialization/types.d.ts +80 -1
  209. package/dist/serialization/types.d.ts.map +1 -1
  210. package/dist/serialization/types.js +15 -1
  211. package/dist/serialization/workflow-vm.d.ts +29 -0
  212. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  213. package/dist/serialization/workflow-vm.js +74 -0
  214. package/dist/serialization-format.d.ts +64 -8
  215. package/dist/serialization-format.d.ts.map +1 -1
  216. package/dist/serialization-format.js +225 -73
  217. package/dist/serialization.d.ts +262 -34
  218. package/dist/serialization.d.ts.map +1 -1
  219. package/dist/serialization.js +1885 -277
  220. package/dist/set-attributes.d.ts +13 -0
  221. package/dist/set-attributes.d.ts.map +1 -0
  222. package/dist/set-attributes.js +60 -0
  223. package/dist/source-map.d.ts +25 -0
  224. package/dist/source-map.d.ts.map +1 -1
  225. package/dist/source-map.js +154 -10
  226. package/dist/step/context-storage.d.ts +63 -2
  227. package/dist/step/context-storage.d.ts.map +1 -1
  228. package/dist/step/context-storage.js +7 -5
  229. package/dist/step/writable-stream.d.ts +3 -3
  230. package/dist/step/writable-stream.d.ts.map +1 -1
  231. package/dist/step/writable-stream.js +80 -13
  232. package/dist/step.d.ts.map +1 -1
  233. package/dist/step.js +148 -27
  234. package/dist/symbols.d.ts +50 -0
  235. package/dist/symbols.d.ts.map +1 -1
  236. package/dist/symbols.js +51 -1
  237. package/dist/telemetry/semantic-conventions.d.ts +433 -2
  238. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  239. package/dist/telemetry/semantic-conventions.js +319 -3
  240. package/dist/telemetry.d.ts +91 -0
  241. package/dist/telemetry.d.ts.map +1 -1
  242. package/dist/telemetry.js +244 -17
  243. package/dist/test-support/orchestrator-context.d.ts +25 -0
  244. package/dist/test-support/orchestrator-context.d.ts.map +1 -0
  245. package/dist/test-support/orchestrator-context.js +107 -0
  246. package/dist/types.d.ts +6 -0
  247. package/dist/types.d.ts.map +1 -1
  248. package/dist/types.js +23 -1
  249. package/dist/util.d.ts +0 -5
  250. package/dist/util.d.ts.map +1 -1
  251. package/dist/util.js +1 -15
  252. package/dist/version.d.ts +1 -1
  253. package/dist/version.d.ts.map +1 -1
  254. package/dist/version.js +2 -2
  255. package/dist/vm/index.d.ts.map +1 -1
  256. package/dist/vm/index.js +84 -14
  257. package/dist/vm/script-cache.d.ts +26 -0
  258. package/dist/vm/script-cache.d.ts.map +1 -0
  259. package/dist/vm/script-cache.js +131 -0
  260. package/dist/vm/uint8array-base64.js +1 -1
  261. package/dist/workflow/abort-controller.d.ts +2 -2
  262. package/dist/workflow/abort-controller.d.ts.map +1 -1
  263. package/dist/workflow/abort-controller.js +88 -21
  264. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  265. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  266. package/dist/workflow/attribute-dispatcher.js +45 -0
  267. package/dist/workflow/create-hook.d.ts.map +1 -1
  268. package/dist/workflow/create-hook.js +24 -3
  269. package/dist/workflow/get-workflow-metadata.js +2 -2
  270. package/dist/workflow/hook.d.ts.map +1 -1
  271. package/dist/workflow/hook.js +304 -47
  272. package/dist/workflow/index.d.ts +1 -0
  273. package/dist/workflow/index.d.ts.map +1 -1
  274. package/dist/workflow/index.js +2 -1
  275. package/dist/workflow/set-attributes.d.ts +68 -0
  276. package/dist/workflow/set-attributes.d.ts.map +1 -0
  277. package/dist/workflow/set-attributes.js +60 -0
  278. package/dist/workflow/sleep.d.ts.map +1 -1
  279. package/dist/workflow/sleep.js +58 -12
  280. package/dist/workflow/world-init-stub.d.ts +3 -3
  281. package/dist/workflow/world-init-stub.js +4 -4
  282. package/dist/workflow.d.ts +95 -3
  283. package/dist/workflow.d.ts.map +1 -1
  284. package/dist/workflow.js +900 -561
  285. package/docs/api-reference/create-hook.mdx +89 -10
  286. package/docs/api-reference/create-webhook.mdx +16 -15
  287. package/docs/api-reference/define-hook.mdx +35 -33
  288. package/docs/api-reference/fatal-error.mdx +30 -8
  289. package/docs/api-reference/fetch.mdx +14 -10
  290. package/docs/api-reference/get-step-metadata.mdx +2 -2
  291. package/docs/api-reference/get-workflow-metadata.mdx +3 -3
  292. package/docs/api-reference/get-writable.mdx +7 -7
  293. package/docs/api-reference/index.mdx +4 -1
  294. package/docs/api-reference/retryable-error.mdx +1 -1
  295. package/docs/api-reference/set-attributes.mdx +61 -0
  296. package/docs/api-reference/sleep.mdx +4 -4
  297. package/docs/foundations/cancellation.mdx +31 -32
  298. package/docs/foundations/errors-and-retries.mdx +42 -11
  299. package/docs/foundations/hooks.mdx +64 -35
  300. package/docs/foundations/idempotency.mdx +244 -12
  301. package/docs/foundations/index.mdx +1 -23
  302. package/docs/foundations/meta.json +2 -1
  303. package/docs/foundations/serialization.mdx +21 -22
  304. package/docs/foundations/starting-workflows.mdx +106 -30
  305. package/docs/foundations/streaming.mdx +108 -60
  306. package/docs/foundations/versioning.mdx +263 -0
  307. package/docs/foundations/workflows-and-steps.mdx +9 -9
  308. package/docs/how-it-works/cancellation.mdx +63 -63
  309. package/docs/how-it-works/code-transform.mdx +83 -67
  310. package/docs/how-it-works/encryption.mdx +30 -26
  311. package/docs/how-it-works/event-sourcing.mdx +125 -34
  312. package/docs/how-it-works/framework-integrations.mdx +96 -337
  313. package/docs/how-it-works/understanding-directives.mdx +22 -22
  314. package/package.json +24 -15
  315. package/dist/runtime/step-handler.d.ts +0 -2
  316. package/dist/runtime/step-handler.d.ts.map +0 -1
  317. package/dist/runtime/step-handler.js +0 -776
@@ -0,0 +1,2427 @@
1
+ /**
2
+ * QuickJS WebAssembly (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 and the workflow primitives. (Serialization lives on
19
+ * the host (see quickjs-serde.ts) so no serde code is evaluated
20
+ * in the VM.)
21
+ * 2. Per-run initialization (inline in `runQuickJSWorkflow`): seeded
22
+ * PRNG/ULID host functions, workflow bundle evaluation, run metadata,
23
+ * workflow input, and start.
24
+ * Keeping the phases separate is groundwork for VM-memory snapshotting:
25
+ * a follow-up can persist/restore the VM at the phase boundary (e.g. a
26
+ * build-time initial snapshot) without restructuring this module. Note
27
+ * that bundle evaluation currently sits in the per-run phase so that
28
+ * module-scope user code observes the seeded `Math.random`, matching the
29
+ * `node:vm` engine's replay determinism.
30
+ */
31
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
32
+ if (value !== null && value !== void 0) {
33
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
34
+ var dispose, inner;
35
+ if (async) {
36
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
37
+ dispose = value[Symbol.asyncDispose];
38
+ }
39
+ if (dispose === void 0) {
40
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
41
+ dispose = value[Symbol.dispose];
42
+ if (async) inner = dispose;
43
+ }
44
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
45
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
46
+ env.stack.push({ value: value, dispose: dispose, async: async });
47
+ }
48
+ else if (async) {
49
+ env.stack.push({ async: true });
50
+ }
51
+ return value;
52
+ };
53
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
54
+ return function (env) {
55
+ function fail(e) {
56
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
57
+ env.hasError = true;
58
+ }
59
+ var r, s = 0;
60
+ function next() {
61
+ while (r = env.stack.pop()) {
62
+ try {
63
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
64
+ if (r.dispose) {
65
+ var result = r.dispose.call(r.value);
66
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
67
+ }
68
+ else s |= 1;
69
+ }
70
+ catch (e) {
71
+ fail(e);
72
+ }
73
+ }
74
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
75
+ if (env.hasError) throw env.error;
76
+ }
77
+ return next();
78
+ };
79
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
80
+ var e = new Error(message);
81
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
82
+ });
83
+ import { SerializationError } from '@workflow/errors';
84
+ import { globalSingleton } from '@workflow/utils';
85
+ import { isSealedNoopEvent, } from '@workflow/world';
86
+ import * as nanoid from 'nanoid';
87
+ import { JSException, QuickJS, } from 'quickjs-wasi';
88
+ import seedrandom from 'seedrandom';
89
+ import { monotonicFactory } from 'ulid';
90
+ import { runtimeLogger } from '../logger.js';
91
+ import { decompress } from '../serialization/compression.js';
92
+ import { decrypt } from '../serialization/encryption.js';
93
+ import { formatSerializationError } from '../serialization/errors.js';
94
+ import { getReplayTimeoutMs, isQuickJSBaselineSnapshotEnabled, } from './constants.js';
95
+ import { quickjsExtensions, quickjsWasm } from './quickjs-assets.generated.js';
96
+ import { adoptSerdeRoot, captureSerdeRoot, createQuickJSSerde, exportSerdeRoot, } from './quickjs-serde.js';
97
+ import { runIdCreatedAt } from './run-id-time.js';
98
+ // ---- Host -> VM payload preparation ----
99
+ /**
100
+ * Prepare persisted payload bytes for consumption inside the VM: decrypt
101
+ * (when an encryption key is configured) and decompress (specVersion >= 5
102
+ * payloads may be gzip/zstd-compressed). The VM only understands plain
103
+ * format-prefixed 'devl' bytes: it has neither the key material nor zlib.
104
+ * The key is the run's full DecryptionKey capability (symmetric AES key +
105
+ * X25519 keypair) so sealed `encp` hook payloads from cross-deployment
106
+ * resumeHook() calls open here too, not just symmetric `encr` ones.
107
+ * Both stages are format-prefix dispatched, so plaintext/uncompressed
108
+ * data passes through unchanged. Mirrors `prepareReplayPayload` in
109
+ * serialization.ts (the node:vm engine's equivalent host-side stage).
110
+ */
111
+ async function prepareBytesForVM(data, key) {
112
+ return (await decompress(await decrypt(data, key)));
113
+ }
114
+ // ---- VM Bootstrap Code ----
115
+ /**
116
+ * JavaScript code that runs inside the QuickJS VM to set up the workflow
117
+ * primitives. This sets up:
118
+ * - globalThis.__private_workflows (Map) - workflow registry
119
+ * - globalThis.__resolvers (Object) - pending promise resolve/reject functions
120
+ * - globalThis.__pending (Array) - metadata about pending operations
121
+ * - globalThis[Symbol.for("WORKFLOW_USE_STEP")] - step proxy factory
122
+ * - globalThis[Symbol.for("WORKFLOW_SLEEP")] - sleep function
123
+ */
124
+ const VM_BOOTSTRAP = `
125
+ // Symbol.dispose / Symbol.asyncDispose polyfills for QuickJS
126
+ if (typeof Symbol.dispose === "undefined") {
127
+ Symbol.dispose = Symbol.for("Symbol.dispose");
128
+ }
129
+ if (typeof Symbol.asyncDispose === "undefined") {
130
+ Symbol.asyncDispose = Symbol.for("Symbol.asyncDispose");
131
+ }
132
+
133
+ globalThis.__private_workflows = new Map();
134
+ globalThis.__resolvers = {};
135
+ globalThis.__pending = [];
136
+ globalThis.__workflowResult = undefined;
137
+ globalThis.__workflowError = undefined;
138
+ // Buffer for hook_received payloads that arrive before the hook is awaited.
139
+ // Keyed by correlationId → array of payloads (preserves delivery order).
140
+ // This mirrors the event-replay runtime's payloadsQueue in hook.ts.
141
+ globalThis.__hookPayloadBuffer = {};
142
+
143
+ // Buffer for step/wait/attr terminal outcomes that arrive before this VM
144
+ // has constructed the corresponding awaiting promise. In fresh-VM replay
145
+ // the multi-pass event scan makes this unreachable (awaits are
146
+ // reconstructed before their terminals are re-scanned), but the live
147
+ // continuation path (continueWithEvents) scans each delta exactly once —
148
+ // a concurrent invocation's terminal arriving before this VM reaches the
149
+ // await would otherwise be dropped on the floor and the await would
150
+ // never settle (the feed's seen-set means it is never re-delivered).
151
+ // Mirrors __hookPayloadBuffer, which exists for exactly this reason on
152
+ // the hook path. Keyed by correlationId → single terminal (steps, waits
153
+ // and attrs settle exactly once).
154
+ globalThis.__terminalBuffer = {};
155
+
156
+ // Registers a resolver for an awaited primitive, first draining any
157
+ // buffered terminal recorded for the correlationId. Entries are prepared
158
+ // host-side: bytes are decrypted AND deserialized into VM values by the
159
+ // host serde before buffering (the VM has no in-guest deserializer on
160
+ // the host-serde engine), so draining only forwards the stored value.
161
+ globalThis.__registerResolver = function(correlationId, resolve, reject) {
162
+ var buffered = globalThis.__terminalBuffer[correlationId];
163
+ if (buffered) {
164
+ delete globalThis.__terminalBuffer[correlationId];
165
+ if (buffered.kind === "resolve_value") {
166
+ resolve(buffered.value);
167
+ } else if (buffered.kind === "reject_value") {
168
+ reject(buffered.value);
169
+ } else if (buffered.kind === "reject_error") {
170
+ var e = new Error(buffered.message);
171
+ e.name = "FatalError";
172
+ e.fatal = true;
173
+ if (buffered.stack) e.stack = buffered.stack;
174
+ reject(e);
175
+ } else {
176
+ resolve(undefined);
177
+ }
178
+ return;
179
+ }
180
+ globalThis.__resolvers[correlationId] = { resolve: resolve, reject: reject };
181
+ };
182
+
183
+ // Stubs for Web APIs that the workflow bundle may reference but are not
184
+ // available in QuickJS. Native C extensions (encoding, headers, url,
185
+ // structured-clone) provide the real implementations; these are minimal
186
+ // stubs for APIs that don't have native extensions yet. (btoa/atob and
187
+ // the Uint8Array base64/hex methods are built into quickjs-wasi >= 3.)
188
+
189
+ if (typeof ReadableStream === "undefined") {
190
+ // Minimal ReadableStream that stores body data for Response.json()/text()
191
+ globalThis.ReadableStream = function() {};
192
+ globalThis.ReadableStream.prototype.__bodyData = null;
193
+ }
194
+
195
+ if (typeof WritableStream === "undefined") {
196
+ globalThis.WritableStream = function() {};
197
+ }
198
+
199
+ if (typeof TransformStream === "undefined") {
200
+ globalThis.TransformStream = function() {};
201
+ }
202
+
203
+ if (typeof console === "undefined") {
204
+ globalThis.console = { log: function(){}, error: function(){}, warn: function(){}, info: function(){} };
205
+ }
206
+ // Stub exports/module for CJS bundle format
207
+ globalThis.exports = {};
208
+ globalThis.module = { exports: globalThis.exports };
209
+ // NOTE: TextEncoder/TextDecoder are provided by the native encoding extension.
210
+
211
+ // ---- Deterministic \`crypto\` (parity with the node:vm engine) ----
212
+ // getRandomValues / randomUUID draw from Math.random, which the host
213
+ // replaces with the run's seeded PRNG before any user code runs — so the
214
+ // values replay deterministically and match the node engine, whose
215
+ // implementations draw from the same seeded sequence (see vm/index.ts).
216
+ // Every crypto.subtle method throws with the same guidance as the node
217
+ // engine's non-replayable methods; unlike node, \`digest\` is also
218
+ // unavailable here (no native hash in the VM yet).
219
+ (function() {
220
+ function getRandomValues(array) {
221
+ for (var i = 0; i < array.length; i++) {
222
+ array[i] = Math.floor(Math.random() * 256);
223
+ }
224
+ return array;
225
+ }
226
+ // Mirrors vm/uuid.ts createRandomUUID: identical draw pattern from the
227
+ // seeded PRNG, so both engines produce the same UUID at the same point
228
+ // in a replay.
229
+ function randomUUID() {
230
+ var chars = "0123456789abcdef";
231
+ var uuid = "";
232
+ for (var i = 0; i < 36; i++) {
233
+ if (i === 8 || i === 13 || i === 18 || i === 23) {
234
+ uuid += "-";
235
+ } else if (i === 14) {
236
+ uuid += "4";
237
+ } else if (i === 19) {
238
+ uuid += chars[Math.floor(Math.random() * 4) + 8];
239
+ } else {
240
+ uuid += chars[Math.floor(Math.random() * 16)];
241
+ }
242
+ }
243
+ return uuid;
244
+ }
245
+ function subtleThrow(name) {
246
+ return function() {
247
+ 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.");
248
+ err.name = "WorkflowRuntimeError";
249
+ throw err;
250
+ };
251
+ }
252
+ var subtle = {};
253
+ ["encrypt","decrypt","sign","verify","digest","generateKey","deriveKey","deriveBits","importKey","exportKey","wrapKey","unwrapKey"].forEach(function(m) {
254
+ subtle[m] = subtleThrow(m);
255
+ });
256
+ globalThis.crypto = {
257
+ getRandomValues: getRandomValues,
258
+ randomUUID: randomUUID,
259
+ subtle: subtle,
260
+ };
261
+ })();
262
+
263
+ // ---- Loud Intl / locale guards ----
264
+ // QuickJS has no ICU: \`Intl\` is absent and toLocaleString-family methods
265
+ // silently ignore their locale argument. Silent divergence from the node
266
+ // engine would write different values into a durable event log with no
267
+ // error anywhere — so make the gap loud instead: Intl constructors throw,
268
+ // and toLocale* methods throw ONLY when called with an explicit locale
269
+ // (the no-argument forms keep QuickJS's default behavior).
270
+ (function() {
271
+ function intlThrow(name) {
272
+ return function() {
273
+ 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.");
274
+ err.name = "WorkflowRuntimeError";
275
+ throw err;
276
+ };
277
+ }
278
+ if (typeof Intl === "undefined") {
279
+ var intl = {};
280
+ ["Collator","DateTimeFormat","DisplayNames","DurationFormat","ListFormat","Locale","NumberFormat","PluralRules","RelativeTimeFormat","Segmenter"].forEach(function(n) {
281
+ intl[n] = intlThrow(n);
282
+ });
283
+ intl.getCanonicalLocales = intlThrow("getCanonicalLocales");
284
+ globalThis.Intl = intl;
285
+ }
286
+ function guardLocale(proto, method) {
287
+ var original = proto[method];
288
+ if (typeof original !== "function") return;
289
+ proto[method] = function(locales) {
290
+ if (locales !== undefined) {
291
+ 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.");
292
+ err.name = "WorkflowRuntimeError";
293
+ throw err;
294
+ }
295
+ return original.call(this);
296
+ };
297
+ }
298
+ guardLocale(Number.prototype, "toLocaleString");
299
+ guardLocale(Date.prototype, "toLocaleString");
300
+ guardLocale(Date.prototype, "toLocaleDateString");
301
+ guardLocale(Date.prototype, "toLocaleTimeString");
302
+ guardLocale(String.prototype, "toLocaleLowerCase");
303
+ guardLocale(String.prototype, "toLocaleUpperCase");
304
+ // localeCompare's locales argument is the SECOND parameter.
305
+ (function() {
306
+ var original = String.prototype.localeCompare;
307
+ String.prototype.localeCompare = function(that, locales) {
308
+ if (locales !== undefined) {
309
+ 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.");
310
+ err.name = "WorkflowRuntimeError";
311
+ throw err;
312
+ }
313
+ return original.call(this, that);
314
+ };
315
+ })();
316
+ })();
317
+
318
+ globalThis[Symbol.for("WORKFLOW_USE_STEP")] = function(stepId, closureVarsFn) {
319
+ var fn = function() {
320
+ var args = Array.prototype.slice.call(arguments);
321
+ var correlationId = "step_" + globalThis.__generateUlid();
322
+ // Capture 'this' for method invocations (e.g., MyClass.method())
323
+ var thisVal = (this !== undefined && this !== null && this !== globalThis) ? this : undefined;
324
+ // The RAW input value. Serialization happens on the host, which reads
325
+ // this through a handle when it collects the pending op — no
326
+ // serializer code runs inside the VM.
327
+ var input = {
328
+ args: args,
329
+ closureVars: closureVarsFn ? closureVarsFn() : undefined,
330
+ thisVal: thisVal,
331
+ };
332
+ globalThis.__pending.push({
333
+ type: "step",
334
+ correlationId: correlationId,
335
+ stepId: stepId,
336
+ input: input,
337
+ hasCreatedEvent: false,
338
+ });
339
+ return new Promise(function(resolve, reject) {
340
+ globalThis.__registerResolver(correlationId, resolve, reject);
341
+ });
342
+ };
343
+ // Set stepId on the proxy so the StepFunction reducer can detect and
344
+ // serialize step function references (e.g. when passed as arguments).
345
+ fn.stepId = stepId;
346
+ if (closureVarsFn) fn.__closureVarsFn = closureVarsFn;
347
+ // Override .bind so a bound step proxy (e.g. the SWC plugin's
348
+ // useStep(...).bind(this) for lexical-this arrow steps) keeps its
349
+ // stepId and records the bound receiver / prefilled args — the native
350
+ // bind drops own properties, which would make the StepFunction
351
+ // reducer fail to recognize the proxy when it crosses a serialization
352
+ // boundary. Mirrors the node:vm engine's override in step.ts.
353
+ fn.bind = function(thisArg) {
354
+ var partialArgs = Array.prototype.slice.call(arguments, 1);
355
+ var bound = Function.prototype.bind.apply(this, [thisArg].concat(partialArgs));
356
+ bound.stepId = stepId;
357
+ if (closureVarsFn) bound.__closureVarsFn = closureVarsFn;
358
+ bound.__boundThis = thisArg;
359
+ if (partialArgs.length > 0) bound.__boundArgs = partialArgs;
360
+ return bound;
361
+ };
362
+ return fn;
363
+ };
364
+
365
+ // Parses an "ms" library style duration string into milliseconds.
366
+ // Supports the same units as the replay runtime (which uses the "ms"
367
+ // package): ms / s / m / h / d / w / y, with verbose aliases
368
+ // (seconds, minutes, ...).
369
+ globalThis.__parseDurationMs = function(str) {
370
+ str = String(str);
371
+ if (str.length > 100) return undefined;
372
+ var match = str.match(
373
+ /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i
374
+ );
375
+ if (!match) return undefined;
376
+ var n = parseFloat(match[1]);
377
+ var type = (match[2] || "ms").toLowerCase();
378
+ var s = 1000, m = 60 * s, h = 60 * m, d = 24 * h, w = 7 * d, y = 365.25 * d;
379
+ switch (type) {
380
+ case "years": case "year": case "yrs": case "yr": case "y": return n * y;
381
+ case "weeks": case "week": case "w": return n * w;
382
+ case "days": case "day": case "d": return n * d;
383
+ case "hours": case "hour": case "hrs": case "hr": case "h": return n * h;
384
+ case "minutes": case "minute": case "mins": case "min": case "m": return n * m;
385
+ case "seconds": case "second": case "secs": case "sec": case "s": return n * s;
386
+ case "milliseconds": case "millisecond": case "msecs": case "msec": case "ms": return n;
387
+ default: return undefined;
388
+ }
389
+ };
390
+
391
+ globalThis[Symbol.for("WORKFLOW_SLEEP")] = function(param) {
392
+ var correlationId = "wait_" + globalThis.__generateUlid();
393
+ var resumeAt;
394
+ if (typeof param === "number") {
395
+ resumeAt = new Date(Date.now() + param).toISOString();
396
+ } else if (typeof param === "string") {
397
+ var ms = globalThis.__parseDurationMs(param);
398
+ if (typeof ms === "number" && isFinite(ms)) {
399
+ resumeAt = new Date(Date.now() + ms).toISOString();
400
+ } else {
401
+ // Not a duration string — try as an absolute date string.
402
+ var date = new Date(param);
403
+ if (isNaN(date.getTime())) {
404
+ throw new Error("Invalid sleep parameter: " + param);
405
+ }
406
+ resumeAt = date.toISOString();
407
+ }
408
+ } else if (param instanceof Date) {
409
+ if (isNaN(param.getTime())) {
410
+ throw new Error("Invalid sleep parameter: " + param);
411
+ }
412
+ resumeAt = param.toISOString();
413
+ } else {
414
+ throw new Error("Invalid sleep parameter: " + param);
415
+ }
416
+ globalThis.__pending.push({
417
+ type: "wait",
418
+ correlationId: correlationId,
419
+ resumeAt: resumeAt,
420
+ hasCreatedEvent: false,
421
+ });
422
+ return new Promise(function(resolve, reject) {
423
+ globalThis.__registerResolver(correlationId, resolve, reject);
424
+ });
425
+ };
426
+
427
+ // Response/Request polyfills — .json()/.text()/.arrayBuffer() are useStep
428
+ // proxies that execute on the host side. The proxies are assigned directly
429
+ // to the prototypes so that 'this' (the Response/Request instance) is
430
+ // serialized as thisVal by WORKFLOW_USE_STEP, matching the event-replay
431
+ // runtime's approach (commit dcb0761).
432
+ if (typeof Response === "undefined") {
433
+ var __BODY_INIT = Symbol.for("BODY_INIT");
434
+
435
+ globalThis.Response = function(body, init) {
436
+ init = init || {};
437
+ this.status = init.status || 200;
438
+ this.statusText = init.statusText || "";
439
+ this.headers = new globalThis.Headers(init.headers || []);
440
+ this.type = "default";
441
+ this.url = "";
442
+ this.redirected = false;
443
+ if (body !== null && body !== undefined) {
444
+ this.body = Object.create(globalThis.ReadableStream.prototype);
445
+ this.body[__BODY_INIT] = body;
446
+ } else {
447
+ this.body = null;
448
+ }
449
+ };
450
+ Object.defineProperty(globalThis.Response.prototype, "ok", {
451
+ get: function() { return this.status >= 200 && this.status < 300; }
452
+ });
453
+ Object.defineProperty(globalThis.Response.prototype, "bodyUsed", {
454
+ get: function() { return false; }
455
+ });
456
+ // Assign useStep proxies directly — 'this' binding provides the
457
+ // Response instance, which gets serialized as thisVal by the proxy.
458
+ Object.defineProperties(globalThis.Response.prototype, {
459
+ arrayBuffer: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_array_buffer"), writable: true, configurable: true },
460
+ json: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_json"), writable: true, configurable: true },
461
+ text: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_text"), writable: true, configurable: true },
462
+ });
463
+ globalThis.Response.prototype.bytes = function() {
464
+ return this.arrayBuffer().then(function(buf) { return new Uint8Array(buf); });
465
+ };
466
+ globalThis.Response.prototype.clone = function() {
467
+ var r = Object.create(globalThis.Response.prototype);
468
+ r.status = this.status; r.statusText = this.statusText;
469
+ r.headers = this.headers; r.type = this.type;
470
+ r.url = this.url; r.redirected = this.redirected; r.body = this.body;
471
+ return r;
472
+ };
473
+ globalThis.Response.json = function(data, init) {
474
+ var body = JSON.stringify(data);
475
+ var headers = new globalThis.Headers(init ? init.headers : []);
476
+ if (!headers.has("content-type")) { headers.set("content-type", "application/json"); }
477
+ return new globalThis.Response(body, { status: (init && init.status) || 200, statusText: (init && init.statusText) || "", headers: headers });
478
+ };
479
+ }
480
+ if (typeof Request === "undefined") {
481
+ globalThis.Request = function(input, init) {
482
+ init = init || {};
483
+ if (typeof input === "string") { this.url = input; }
484
+ else if (input && typeof input === "object") {
485
+ this.url = input.url || ""; this.method = input.method;
486
+ this.headers = input.headers; this.body = input.body;
487
+ }
488
+ if (init.method) this.method = init.method.toUpperCase();
489
+ if (!this.method) this.method = "GET";
490
+ if (init.headers) this.headers = new globalThis.Headers(init.headers);
491
+ if (!this.headers) this.headers = new globalThis.Headers();
492
+ if (init.body !== undefined) this.body = init.body;
493
+ if (!this.body) this.body = null;
494
+ this.duplex = init.duplex || "half";
495
+ };
496
+ Object.defineProperty(globalThis.Request.prototype, "bodyUsed", {
497
+ get: function() { return false; }
498
+ });
499
+ Object.defineProperties(globalThis.Request.prototype, {
500
+ arrayBuffer: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_array_buffer"), writable: true, configurable: true },
501
+ json: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_json"), writable: true, configurable: true },
502
+ text: { value: globalThis[Symbol.for("WORKFLOW_USE_STEP")]("__builtin_response_text"), writable: true, configurable: true },
503
+ });
504
+ }
505
+
506
+ // createHook — returns a Hook object that is both a Thenable and AsyncIterable.
507
+ // Each await/yield creates a new promise keyed by the same correlationId.
508
+ // The promise is resolved when a hook_received event arrives.
509
+ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
510
+ options = options || {};
511
+ if (options.isWebhook === true && options.experimental_minRetention !== undefined) {
512
+ throw new Error('Webhook hooks do not support \`experimental_minRetention\`. Use a non-webhook \`createHook()\` with \`resumeHook()\`.');
513
+ }
514
+ if (options.experimental_minRetention !== undefined && globalThis.__worldCapabilities?.hookRetention?.active !== true) {
515
+ var unsupportedRetentionError = new Error('The configured World does not support \`experimental_minRetention\` for Hooks.');
516
+ unsupportedRetentionError.name = "FatalError";
517
+ unsupportedRetentionError.fatal = true;
518
+ throw unsupportedRetentionError;
519
+ }
520
+ var token = options.token || globalThis.__generateNanoid();
521
+ var correlationId = "hook_" + globalThis.__generateUlid();
522
+ var isDisposed = false;
523
+ var hasCreatedEvent = false;
524
+ var tokenRetentionUntil;
525
+ if (options.experimental_minRetention !== undefined) {
526
+ var minRetention = options.experimental_minRetention;
527
+ if (typeof minRetention === "number") {
528
+ if (minRetention < 0 || !isFinite(minRetention)) {
529
+ throw new Error("Invalid duration: " + minRetention + ". Expected a non-negative finite number of milliseconds.");
530
+ }
531
+ tokenRetentionUntil = Date.now() + minRetention;
532
+ } else if (typeof minRetention === "string") {
533
+ var retentionMs = globalThis.__parseDurationMs(minRetention);
534
+ if (typeof retentionMs !== "number" || retentionMs < 0 || !isFinite(retentionMs)) {
535
+ throw new Error('Invalid duration: "' + minRetention + '". Expected a valid duration string like "1s", "1m", "1h", etc.');
536
+ }
537
+ tokenRetentionUntil = Date.now() + retentionMs;
538
+ } else if (minRetention instanceof Date || (minRetention && typeof minRetention.getTime === "function")) {
539
+ // Accept Date-like objects (anything with getTime), matching
540
+ // parseDurationToDate: values that crossed the serde boundary may
541
+ // not be realm-native Date instances.
542
+ tokenRetentionUntil = minRetention.getTime();
543
+ } else {
544
+ throw new Error("Invalid duration parameter. Expected a duration string, number (milliseconds), or Date object.");
545
+ }
546
+ }
547
+
548
+ // Register in pending operations. Metadata stays a RAW value; the host
549
+ // serializes it through a handle when it collects the pending op.
550
+ var pendingOp = {
551
+ type: "hook",
552
+ correlationId: correlationId,
553
+ token: token,
554
+ tokenRetentionUntil: tokenRetentionUntil,
555
+ isWebhook: !!options.isWebhook,
556
+ metadata: options.metadata,
557
+ hasCreatedEvent: false,
558
+ };
559
+ globalThis.__pending.push(pendingOp);
560
+
561
+ // Per-hook lifecycle state backing hook.getConflict(): resolves null
562
+ // once creation is confirmed (hook_created), or resolves with the
563
+ // conflicting Run handle / rejects with HookConflictError on
564
+ // hook_conflict. State transitions are driven by the host during event
565
+ // processing (see processEvents).
566
+ globalThis.__hooks = globalThis.__hooks || {};
567
+ globalThis.__hooks[correlationId] = {
568
+ token: token,
569
+ created: false,
570
+ conflict: null,
571
+ getConflictResolvers: [],
572
+ };
573
+
574
+ // Each await creates a new promise for the next payload.
575
+ // The correlationId stays the same — the resolver is replaced each time.
576
+ function createHookPromise() {
577
+ // Check the payload buffer first — if a hook_received event arrived
578
+ // before this hook was awaited, the payload was buffered in the VM
579
+ // heap. Drain it immediately (matching event-replay payloadsQueue).
580
+ var buf = globalThis.__hookPayloadBuffer[correlationId];
581
+ if (buf && buf.length > 0) {
582
+ return Promise.resolve(buf.shift());
583
+ }
584
+ return new Promise(function(resolve, reject) {
585
+ globalThis.__resolvers[correlationId] = { resolve: resolve, reject: reject };
586
+ });
587
+ }
588
+
589
+ function disposeHook() {
590
+ if (isDisposed) return;
591
+ isDisposed = true;
592
+ // A conflicted hook was never created (the world rejected its claim
593
+ // — the token belongs to another run), so there is no entity to
594
+ // dispose. Mirrors the node:vm engine, where hook_conflict removes
595
+ // the invocation-queue item before dispose can mark it. Emitting a
596
+ // hook_disposed here would be rejected by the world's
597
+ // hook-existence validation.
598
+ var state = globalThis.__hooks[correlationId];
599
+ if (!state || !state.conflict) {
600
+ // Signal to the entrypoint to create a hook_disposed event. The
601
+ // token is carried so the entrypoint can order same-token hook
602
+ // operations sequentially (a dispose must release the token before
603
+ // a later same-token hook's creation is validated).
604
+ globalThis.__pending.push({
605
+ type: "hook_dispose",
606
+ correlationId: correlationId,
607
+ token: token,
608
+ hasCreatedEvent: false,
609
+ });
610
+ }
611
+ // If there's a pending resolver, resolve it with undefined to break the iterator
612
+ if (globalThis.__resolvers[correlationId]) {
613
+ globalThis.__resolvers[correlationId].resolve(undefined);
614
+ delete globalThis.__resolvers[correlationId];
615
+ }
616
+ }
617
+
618
+ function getConflict() {
619
+ var state = globalThis.__hooks[correlationId];
620
+ if (state.conflict) {
621
+ return state.conflict.run
622
+ ? Promise.resolve(state.conflict.run)
623
+ : Promise.reject(state.conflict.error);
624
+ }
625
+ if (state.created) {
626
+ return Promise.resolve(null);
627
+ }
628
+ // Creation not yet confirmed by the event log — park the awaiter and
629
+ // flag the pending op so the entrypoint re-invokes the workflow right
630
+ // after writing hook_created (nothing external resumes a getConflict
631
+ // awaiter; confirmation only comes from replaying the new event).
632
+ pendingOp.hasGetConflictAwaiter = true;
633
+ return new Promise(function(resolve, reject) {
634
+ state.getConflictResolvers.push({ resolve: resolve, reject: reject });
635
+ });
636
+ }
637
+
638
+ var hook = {
639
+ token: token,
640
+ then: function(onFulfilled, onRejected) {
641
+ return createHookPromise().then(onFulfilled, onRejected);
642
+ },
643
+ getConflict: getConflict,
644
+ dispose: disposeHook,
645
+ };
646
+
647
+ // Symbol.dispose for explicit resource management
648
+ hook[Symbol.dispose] = disposeHook;
649
+
650
+ // AsyncIterable — yields payloads until disposed
651
+ hook[Symbol.asyncIterator] = function() {
652
+ return {
653
+ next: function() {
654
+ if (isDisposed) {
655
+ return Promise.resolve({ done: true, value: undefined });
656
+ }
657
+ return createHookPromise().then(function(value) {
658
+ // If disposed while waiting, signal done
659
+ if (isDisposed) return { done: true, value: undefined };
660
+ return { done: false, value: value };
661
+ });
662
+ },
663
+ return: function() {
664
+ disposeHook();
665
+ return Promise.resolve({ done: true, value: undefined });
666
+ },
667
+ };
668
+ };
669
+
670
+ return hook;
671
+ };
672
+
673
+ // setAttributes — attaches plaintext metadata to the current run.
674
+ // Validation happens in library code (normalizeAttributeChanges) before
675
+ // this dispatcher is invoked, so "changes" is already normalized. The
676
+ // returned promise resolves when the matching attr_set event is
677
+ // observed during event processing — mirroring the node:vm engine's
678
+ // createSetAttributes (attribute-dispatcher.ts).
679
+ globalThis[Symbol.for("WORKFLOW_SET_ATTRIBUTES")] = function(changes, options) {
680
+ var correlationId = "attr_" + globalThis.__generateUlid();
681
+ globalThis.__pending.push({
682
+ type: "attribute",
683
+ correlationId: correlationId,
684
+ changes: changes,
685
+ allowReservedAttributes: !!(options && options.allowReservedAttributes),
686
+ hasCreatedEvent: false,
687
+ });
688
+ return new Promise(function(resolve, reject) {
689
+ globalThis.__registerResolver(correlationId, resolve, reject);
690
+ });
691
+ };
692
+
693
+ // ---- AbortController / AbortSignal (hook-backed) ----
694
+ // Port of workflow/abort-controller.ts to the VM pending-op model:
695
+ // the controller registers a system hook; abort() flips the signal
696
+ // synchronously and marks the pending op so the host records the abort
697
+ // (hook_received event + stream packet). On replay, the recorded
698
+ // hook_received event calls _setAborted during event processing and the
699
+ // workflow's own abort() call becomes a no-op.
700
+ var __ABORT_STREAM_NAME = Symbol.for("WORKFLOW_ABORT_STREAM_NAME");
701
+ var __ABORT_HOOK_TOKEN = Symbol.for("WORKFLOW_ABORT_HOOK_TOKEN");
702
+
703
+ function __makeAbortError() {
704
+ if (typeof DOMException !== "undefined") {
705
+ return new DOMException("The operation was aborted.", "AbortError");
706
+ }
707
+ var e = new Error("The operation was aborted.");
708
+ e.name = "AbortError";
709
+ return e;
710
+ }
711
+
712
+ function WorkflowAbortSignal(streamName, hookToken) {
713
+ this.aborted = false;
714
+ this.reason = undefined;
715
+ this[__ABORT_STREAM_NAME] = streamName;
716
+ this[__ABORT_HOOK_TOKEN] = hookToken;
717
+ this.__listeners = [];
718
+ this.__onabort = null;
719
+ }
720
+ Object.defineProperty(WorkflowAbortSignal.prototype, "onabort", {
721
+ get: function() { return this.__onabort; },
722
+ set: function(handler) {
723
+ this.__onabort = handler;
724
+ if (handler && this.aborted) handler.call(this);
725
+ },
726
+ });
727
+ WorkflowAbortSignal.prototype._setAborted = function(reason) {
728
+ if (this.aborted) return;
729
+ this.aborted = true;
730
+ this.reason = reason;
731
+ if (this.__onabort) this.__onabort.call(this);
732
+ var listeners = this.__listeners;
733
+ this.__listeners = [];
734
+ for (var i = 0; i < listeners.length; i++) listeners[i]();
735
+ };
736
+ WorkflowAbortSignal.prototype.addEventListener = function(type, listener) {
737
+ if (type !== "abort") return;
738
+ if (this.aborted) {
739
+ // Fire synchronously (not on a microtask) for deterministic replay —
740
+ // matches the node:vm engine's WorkflowAbortSignal.
741
+ listener();
742
+ return;
743
+ }
744
+ this.__listeners.push(listener);
745
+ };
746
+ WorkflowAbortSignal.prototype.removeEventListener = function(type, listener) {
747
+ if (type !== "abort") return;
748
+ this.__listeners = this.__listeners.filter(function(l) { return l !== listener; });
749
+ };
750
+ WorkflowAbortSignal.prototype.throwIfAborted = function() {
751
+ if (this.aborted) {
752
+ throw this.reason !== undefined && this.reason !== null
753
+ ? this.reason
754
+ : __makeAbortError();
755
+ }
756
+ };
757
+ // Expose for the host serde's revivers (they look the class up lazily,
758
+ // through a handle, at revive time).
759
+ globalThis.__WorkflowAbortSignal = WorkflowAbortSignal;
760
+
761
+ // Registry of live abort signals keyed by their hook correlationId. The
762
+ // host delivers hook_received events for these ids as _setAborted calls.
763
+ globalThis.__abortSignals = {};
764
+
765
+ globalThis.AbortController = function WorkflowAbortController() {
766
+ var id = globalThis.__generateUlid();
767
+ var streamName = "strm_" + id + "_system_abort";
768
+ var hookToken = "abrt_" + id;
769
+ this[__ABORT_STREAM_NAME] = streamName;
770
+ this[__ABORT_HOOK_TOKEN] = hookToken;
771
+ this.signal = new WorkflowAbortSignal(streamName, hookToken);
772
+ var correlationId = "hook_" + globalThis.__generateUlid();
773
+ // Register an internal system hook. isSystem prevents token namespace
774
+ // conflicts with user hooks.
775
+ globalThis.__pending.push({
776
+ type: "hook",
777
+ correlationId: correlationId,
778
+ token: hookToken,
779
+ isWebhook: false,
780
+ isSystem: true,
781
+ hasCreatedEvent: false,
782
+ });
783
+ globalThis.__abortSignals[correlationId] = this.signal;
784
+ };
785
+ globalThis.AbortController.prototype.abort = function(reason) {
786
+ if (this.signal.aborted) return; // already aborted (e.g. from replay)
787
+ this.signal._setAborted(reason);
788
+ // Mark the pending hook op so the host records the abort. The payload
789
+ // stays a RAW value; the host serializes it through a handle with full
790
+ // type fidelity (Errors, DOMException, custom values).
791
+ var token = this[__ABORT_HOOK_TOKEN];
792
+ for (var i = 0; i < globalThis.__pending.length; i++) {
793
+ var item = globalThis.__pending[i];
794
+ if (item.type === "hook" && item.token === token) {
795
+ item.abortRequested = true;
796
+ item.abortPayload = {
797
+ aborted: true,
798
+ reason: reason,
799
+ };
800
+ break;
801
+ }
802
+ }
803
+ };
804
+
805
+ globalThis.AbortSignal = {
806
+ abort: function(reason) {
807
+ var s = new WorkflowAbortSignal("", "");
808
+ s._setAborted(reason !== undefined ? reason : __makeAbortError());
809
+ return s;
810
+ },
811
+ any: function(signals) {
812
+ var composite = new WorkflowAbortSignal("", "");
813
+ var arr = Array.from(signals);
814
+ for (var i = 0; i < arr.length; i++) {
815
+ if (arr[i].aborted) {
816
+ composite._setAborted(arr[i].reason);
817
+ return composite;
818
+ }
819
+ }
820
+ var listeners = [];
821
+ var cleanup = function() {
822
+ for (var j = 0; j < listeners.length; j++) {
823
+ if (listeners[j].signal.removeEventListener) {
824
+ listeners[j].signal.removeEventListener("abort", listeners[j].listener);
825
+ }
826
+ }
827
+ listeners.length = 0;
828
+ };
829
+ arr.forEach(function(signal) {
830
+ if (!signal.addEventListener) return;
831
+ var listener = function() {
832
+ if (!composite.aborted) {
833
+ composite._setAborted(signal.reason);
834
+ cleanup();
835
+ }
836
+ };
837
+ listeners.push({ signal: signal, listener: listener });
838
+ signal.addEventListener("abort", listener);
839
+ });
840
+ return composite;
841
+ },
842
+ timeout: function() {
843
+ throw new Error(
844
+ "AbortSignal.timeout() is not supported in workflow functions. " +
845
+ "Use sleep() with an AbortController instead. " +
846
+ "See: /docs/errors/abort-signal-timeout-in-workflow"
847
+ );
848
+ },
849
+ };
850
+
851
+ // WORKFLOW_GET_STREAM_ID — generates a stream ID for a workflow run.
852
+ // Replicates getWorkflowRunStreamId() from util.ts inside the QuickJS VM.
853
+ // Uses the built-in btoa() for base64url encoding.
854
+ globalThis[Symbol.for("WORKFLOW_GET_STREAM_ID")] = function(namespace) {
855
+ var runId = globalThis[Symbol.for("WORKFLOW_CONTEXT")]
856
+ ? globalThis[Symbol.for("WORKFLOW_CONTEXT")].workflowRunId
857
+ : "";
858
+ var streamId = runId.replace("wrun_", "strm_") + "_user";
859
+ if (!namespace) return streamId;
860
+ // base64url: btoa then replace + with -, / with _, strip =
861
+ var b64 = btoa(namespace).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");
862
+ return streamId + "_" + b64;
863
+ };
864
+ `;
865
+ // ---- Runtime ----
866
+ /**
867
+ * Phase 1: static (run-independent) VM initialization.
868
+ *
869
+ * Creates a QuickJS VM and loads everything that does not depend on a
870
+ * specific workflow run: the workflow-primitive bootstrap (useStep /
871
+ * sleep / createHook / Response-Request polyfills). Serialization is
872
+ * host-side (quickjs-serde.ts) and captures its intrinsics from the VM
873
+ * right after this returns.
874
+ *
875
+ * `getNowMs` backs the VM's WASI clock (`Date.now()` / `new Date()`
876
+ * inside the VM). The callback itself is static: the per-run state it
877
+ * reads lives on the host and is advanced as events are consumed,
878
+ * matching the node:vm engine's deterministic replay clock.
879
+ *
880
+ * This phase is the future boundary for VM-memory snapshotting: a
881
+ * build-time snapshot can capture the VM right after this function and
882
+ * new runs can restore from it instead of paying VM creation + eval cost
883
+ * (`QuickJS.restore` accepts the same wasi override).
884
+ */
885
+ /**
886
+ * Loosely-typed accessor for the `WebAssembly` global. The package
887
+ * tsconfig's `lib: ["es2022"]` does not include the DOM lib where the
888
+ * `WebAssembly` namespace types live; the runtime global is available on
889
+ * every WASM-capable platform this engine targets.
890
+ */
891
+ const WebAssemblyGlobal = globalThis.WebAssembly;
892
+ /**
893
+ * Process-wide cache of the compiled `WebAssembly.Module`s for the main
894
+ * QuickJS runtime and its native extensions. `WebAssembly.compile` of the
895
+ * ~600 KB runtime binary is the most expensive part of VM creation and is
896
+ * pure (no per-VM state: instantiation binds the per-VM memory), so it
897
+ * only needs to happen once per process. The promise is cached (not the
898
+ * result) so concurrent first invocations share a single compilation.
899
+ */
900
+ // On `globalThis` (see `globalSingleton`): the comment above says once per
901
+ // process, and module scope would make it once per bundler layer, recompiling
902
+ // the ~600 KB runtime binary for each.
903
+ const quickjsAssets = globalSingleton('@workflow/core//quickjsCompiledAssets', 1, () => ({
904
+ promise: undefined,
905
+ }));
906
+ function getCompiledAssets() {
907
+ if (!quickjsAssets.promise) {
908
+ quickjsAssets.promise = (async () => {
909
+ const [wasm, ...extensionModules] = await Promise.all([
910
+ WebAssemblyGlobal.compile(quickjsWasm),
911
+ ...quickjsExtensions.map((ext) => WebAssemblyGlobal.compile(ext.wasm)),
912
+ ]);
913
+ return {
914
+ wasm,
915
+ extensions: quickjsExtensions.map((ext, i) => ({
916
+ ...ext,
917
+ wasm: extensionModules[i],
918
+ })),
919
+ };
920
+ })();
921
+ // On failure, clear the cache so a later invocation can retry rather
922
+ // than being stuck with a rejected promise forever.
923
+ quickjsAssets.promise.catch(() => {
924
+ quickjsAssets.promise = undefined;
925
+ });
926
+ }
927
+ return quickjsAssets.promise;
928
+ }
929
+ /**
930
+ * WASI clock override reading the given accessor, shared between fresh
931
+ * boots (initWorkflowVM) and baseline-snapshot restores, so the two
932
+ * paths cannot drift on rounding/encoding.
933
+ *
934
+ * Deterministic replay clock: Date.now() / new Date() inside the VM
935
+ * read the host-controlled clock instead of wall time. Replay
936
+ * re-executes the workflow from the top on every invocation, so the
937
+ * clock must be derived from the event log (not real time) for the
938
+ * workflow to observe stable timestamps across invocations.
939
+ */
940
+ function makeDeterministicClockWasi(getNowMs) {
941
+ return (memory) => ({
942
+ clock_time_get(_clockId, _precision, resultPtr) {
943
+ const timeNs = BigInt(Math.round(getNowMs())) * 1000000n;
944
+ new DataView(memory.buffer).setBigUint64(resultPtr, timeNs, true);
945
+ return 0;
946
+ },
947
+ });
948
+ }
949
+ async function initWorkflowVM(getNowMs, interruptBudget) {
950
+ const assets = await getCompiledAssets();
951
+ const vm = await QuickJS.create({
952
+ wasm: assets.wasm,
953
+ memoryLimit: 256 * 1024 * 1024,
954
+ interruptHandler: createInterruptHandler(interruptBudget),
955
+ extensions: assets.extensions,
956
+ wasi: makeDeterministicClockWasi(getNowMs),
957
+ });
958
+ // Bootstrap workflow primitives
959
+ vm.evalCode(VM_BOOTSTRAP, 'bootstrap.js').dispose();
960
+ return vm;
961
+ }
962
+ // ---- Baseline snapshot (startup optimization) --------------------------
963
+ //
964
+ // Evaluating the workflow bundle dominates VM startup (~74ms of a ~77ms
965
+ // boot for a 1.3MB bundle), and full event replay pays it on EVERY
966
+ // invocation. The bundle is identical across all runs of a deployment, so
967
+ // the engine hydrates one VM per function instance (bootstrap + bundle
968
+ // eval), snapshots its memory, and starts every invocation by restoring
969
+ // the snapshot (~3ms) instead of re-evaluating.
970
+ //
971
+ // Determinism: replay requires module-scope user code to observe the
972
+ // run-seeded PRNG and the run's deterministic clock. A restored heap
973
+ // carries whatever module scope computed at HYDRATE time, so the
974
+ // optimization is only sound when module scope consumed neither
975
+ // randomness nor time. Both are detected during hydrate (the placeholder
976
+ // host fns count draws, the hydrate clock counts reads) and a bundle
977
+ // that used either is marked ineligible: every invocation falls back to
978
+ // fresh evaluation, preserving exact node:vm-parity semantics. When the
979
+ // gate passes, restore is byte-equivalent to fresh eval (verified by the
980
+ // parity tests): the per-run host fns are re-registered by name on the
981
+ // restored VM (quickjs-wasi restore semantics) before the workflow body
982
+ // runs, so the seeded draw sequence (and every correlationId) is
983
+ // identical.
984
+ //
985
+ // The cache is per function instance and keyed on the bundle string
986
+ // (reference-stable: the generated flow route holds it in a module-level
987
+ // const). Capped at a few entries so tests with many distinct bundles
988
+ // don't accumulate 16MB snapshots.
989
+ /**
990
+ * Eval filename used when hydrating the baseline VM. The baseline is
991
+ * shared by EVERY workflow in the bundle, so the filename baked into
992
+ * its compiled code (and therefore into snapshot-path stack frames)
993
+ * must be workflow-independent: hydrating under the first caller's
994
+ * workflowId would break `remapErrorStack`'s filename matching for
995
+ * every other workflow in the bundle. Remap call sites match this
996
+ * constant IN ADDITION to the run's module specifier (which covers
997
+ * fresh-path frames).
998
+ */
999
+ export const BASELINE_BUNDLE_FILENAME = 'workflow-bundle.js';
1000
+ // On `globalThis` (see `globalSingleton`): a snapshot is expensive to build and
1001
+ // is keyed by bundle, so per-copy caches would build the same baseline once per
1002
+ // bundler layer while each enforcing its own bound.
1003
+ const baselines = globalSingleton('@workflow/core//quickjsBaselines', 1, () => ({
1004
+ byKey: new Map(),
1005
+ }));
1006
+ const BASELINE_CACHE_MAX_ENTRIES = 4;
1007
+ /** Test-only: reset the baseline cache between test cases. */
1008
+ export function __clearBaselineSnapshotCacheForTests() {
1009
+ baselines.byKey.clear();
1010
+ }
1011
+ /** Test-only: observe how a bundle was classified. */
1012
+ export async function __peekBaselineEntryForTests(workflowCode) {
1013
+ return baselines.byKey.get(workflowCode);
1014
+ }
1015
+ /**
1016
+ * Hydrate a VM with the workflow bundle and snapshot it, gating on
1017
+ * module-scope nondeterminism (see the section comment above). Returns an
1018
+ * `ineligible` entry instead of throwing on eval failure: the fresh path
1019
+ * re-evaluates and produces the real, source-mapped error.
1020
+ */
1021
+ async function prepareBaselineSnapshot(workflowCode, workflowId) {
1022
+ const hydrateStart = Date.now();
1023
+ let clockReads = 0;
1024
+ const budget = { start: Date.now() };
1025
+ const assets = await getCompiledAssets();
1026
+ const vm = await QuickJS.create({
1027
+ wasm: assets.wasm,
1028
+ memoryLimit: 256 * 1024 * 1024,
1029
+ interruptHandler: createInterruptHandler(budget),
1030
+ extensions: assets.extensions,
1031
+ wasi: ((memory) => ({
1032
+ clock_time_get(_clockId, _precision, resultPtr) {
1033
+ clockReads++;
1034
+ const timeNs = BigInt(hydrateStart) * 1000000n;
1035
+ new DataView(memory.buffer).setBigUint64(resultPtr, timeNs, true);
1036
+ return 0;
1037
+ },
1038
+ })),
1039
+ });
1040
+ try {
1041
+ vm.evalCode(VM_BOOTSTRAP, 'bootstrap.js').dispose();
1042
+ // Placeholder host fns under the SAME NAMES the per-run phase uses.
1043
+ // They exist so module-scope code can execute at hydrate time, and to
1044
+ // detect that it did: any draw means the heap would bake
1045
+ // hydrate-seeded values that per-run fresh eval would compute
1046
+ // differently. runWorkflowInVM re-registers all three names with the
1047
+ // run-seeded closures after restore.
1048
+ let draws = 0;
1049
+ {
1050
+ const env_1 = { stack: [], error: void 0, hasError: false };
1051
+ try {
1052
+ const randomFn = __addDisposableResource(env_1, vm.newFunction('random', () => {
1053
+ draws++;
1054
+ return vm.newNumber(Math.random());
1055
+ }), false);
1056
+ const math = __addDisposableResource(env_1, vm.global.getProp('Math'), false);
1057
+ math.setProp('random', randomFn);
1058
+ const nanoidFn = __addDisposableResource(env_1, vm.newFunction('__generateNanoid', () => {
1059
+ draws++;
1060
+ return vm.newString('baseline-placeholder');
1061
+ }), false);
1062
+ vm.setProp(vm.global, '__generateNanoid', nanoidFn);
1063
+ const ulidFn = __addDisposableResource(env_1, vm.newFunction('__generateUlid', () => {
1064
+ draws++;
1065
+ return vm.newString('00000000000000000000000000');
1066
+ }), false);
1067
+ vm.setProp(vm.global, '__generateUlid', ulidFn);
1068
+ }
1069
+ catch (e_1) {
1070
+ env_1.error = e_1;
1071
+ env_1.hasError = true;
1072
+ }
1073
+ finally {
1074
+ __disposeResources(env_1);
1075
+ }
1076
+ }
1077
+ // Serde capture root: created BEFORE the bundle evaluates, exactly
1078
+ // like the fresh path's capture. Its box pointer rides the
1079
+ // BaselineEntry and each restored VM re-adopts it, so serde
1080
+ // initialization never executes guest code after user code has run.
1081
+ // This is what makes module-scope intrinsic patching (polyfills,
1082
+ // stateful wrappers around Object.getOwnPropertyDescriptor, …)
1083
+ // HARMLESS on the snapshot path rather than merely detectable: the
1084
+ // serde uses the pristine pre-eval captures on both paths, and no
1085
+ // post-eval probe exists whose side effects could bake into the
1086
+ // snapshot. The handle is deliberately NOT disposed before the
1087
+ // snapshot: the box must stay live in the memory image (the
1088
+ // baseline VM's dispose below tears down the whole instance without
1089
+ // freeing individual boxes).
1090
+ const serdeRoot = captureSerdeRoot(vm);
1091
+ clockReads = 0; // only count reads made by the bundle itself
1092
+ try {
1093
+ // Workflow-independent filename. See BASELINE_BUNDLE_FILENAME.
1094
+ vm.evalCode(workflowCode, BASELINE_BUNDLE_FILENAME).dispose();
1095
+ }
1096
+ catch {
1097
+ // Let the fresh path re-evaluate and surface the real error with
1098
+ // proper filename / source-map handling.
1099
+ return {
1100
+ state: 'ineligible',
1101
+ reason: 'module scope threw during hydrate',
1102
+ };
1103
+ }
1104
+ if (draws > 0 || clockReads > 0) {
1105
+ runtimeLogger.info('QuickJS baseline snapshot disabled for this bundle: module scope consumed nondeterministic inputs; every invocation will evaluate the bundle fresh', { workflowId, draws, clockReads });
1106
+ return {
1107
+ state: 'ineligible',
1108
+ reason: `module scope consumed ${draws} PRNG draw(s) and ${clockReads} clock read(s)`,
1109
+ };
1110
+ }
1111
+ const snapshot = vm.snapshot();
1112
+ runtimeLogger.debug('QuickJS baseline snapshot prepared', {
1113
+ workflowId,
1114
+ hydrateMs: Date.now() - hydrateStart,
1115
+ });
1116
+ return {
1117
+ state: 'ready',
1118
+ snapshot,
1119
+ serdeRootPtr: exportSerdeRoot(vm, serdeRoot),
1120
+ };
1121
+ }
1122
+ finally {
1123
+ vm.dispose();
1124
+ }
1125
+ }
1126
+ /**
1127
+ * Cached baseline entry for a bundle, preparing it on first access.
1128
+ * Concurrent first invocations share one hydrate via the cached promise;
1129
+ * a hydrate that REJECTS (infrastructure failure, not bundle eval, which
1130
+ * returns `ineligible`) is evicted so a later invocation can retry.
1131
+ */
1132
+ function getBaselineEntry(workflowCode, workflowId) {
1133
+ let entry = baselines.byKey.get(workflowCode);
1134
+ if (!entry) {
1135
+ if (baselines.byKey.size >= BASELINE_CACHE_MAX_ENTRIES) {
1136
+ const oldest = baselines.byKey.keys().next().value;
1137
+ if (oldest !== undefined)
1138
+ baselines.byKey.delete(oldest);
1139
+ }
1140
+ entry = prepareBaselineSnapshot(workflowCode, workflowId);
1141
+ baselines.byKey.set(workflowCode, entry);
1142
+ entry.catch(() => baselines.byKey.delete(workflowCode));
1143
+ }
1144
+ return entry;
1145
+ }
1146
+ /**
1147
+ * Run a workflow invocation to its first settled state and dispose the
1148
+ * VM. Convenience wrapper over {@link startQuickJSWorkflow} for callers
1149
+ * (and tests) that don't use live-VM continuation.
1150
+ */
1151
+ export async function runQuickJSWorkflow(options) {
1152
+ const session = await startQuickJSWorkflow(options);
1153
+ session.dispose();
1154
+ return session.result;
1155
+ }
1156
+ export async function startQuickJSWorkflow(options) {
1157
+ const { workflowCode, workflowId, workflowRun, events } = options;
1158
+ const startedAt = workflowRun.startedAt ? +workflowRun.startedAt : Date.now();
1159
+ // Deterministic PRNG seed, identical for EVERY invocation of the same
1160
+ // run. Full event replay requires this: each invocation re-executes the
1161
+ // workflow from the top and must regenerate the exact same correlationId
1162
+ // sequence so that pending operations re-created by replay match the
1163
+ // events recorded by earlier invocations. Sequential operations within
1164
+ // one execution still get distinct ids because the PRNG advances as the
1165
+ // workflow draws from it. Identical seeding across CONCURRENT invocations
1166
+ // of the same run is also load-bearing: both produce the same ids, and
1167
+ // the world's per-(runId, correlationId) uniqueness turns the duplicate
1168
+ // `events.create` into an EntityConflictError that the entrypoint
1169
+ // swallows.
1170
+ //
1171
+ // The seed inputs MUST be stable across invocations. Notably
1172
+ // `startedAt` is NOT: under turbo the first invocation runs against a
1173
+ // synthesized run object whose timestamps differ from the durably
1174
+ // stored ones that later invocations load. Matches the node:vm
1175
+ // engine's seed (workflow.ts).
1176
+ const seed = [
1177
+ workflowRun.runId,
1178
+ workflowRun.workflowName,
1179
+ workflowRun.deploymentId,
1180
+ ].join(':');
1181
+ const rng = seedrandom(seed);
1182
+ // Seeded nanoid generator: uses the same nanoid package and seeded PRNG
1183
+ // as the node:vm engine for consistent token generation.
1184
+ const generateNanoid = nanoid.customRandom(nanoid.urlAlphabet, 21, (size) => new Uint8Array(size).map(() => 256 * rng()));
1185
+ // Deterministic replay clock, mirroring the node:vm engine (see
1186
+ // workflow.ts): the initial value is the run's creation time recovered
1187
+ // from the ULID embedded in `runId` (falling back to `createdAt`), and
1188
+ // it advances to each processed event's `createdAt` as the event log is
1189
+ // replayed. Monotonic (Math.max) so the outer processEvents re-scan
1190
+ // loop can't move the clock backwards mid-execution.
1191
+ let vmNowMs = runIdCreatedAt(workflowRun.runId) ?? (+workflowRun.createdAt || startedAt);
1192
+ const advanceClock = (ms) => {
1193
+ if (Number.isFinite(ms))
1194
+ vmNowMs = Math.max(vmNowMs, ms);
1195
+ };
1196
+ // ---- Phase 1: static initialization ----
1197
+ //
1198
+ // Baseline-snapshot fast path (default ON; see the section comment at
1199
+ // prepareBaselineSnapshot): restore a bundle-hydrated VM instead of
1200
+ // booting fresh and re-evaluating the bundle. `ineligible` bundles
1201
+ // (module-scope nondeterminism, eval failure) take the fresh path with
1202
+ // identical semantics.
1203
+ const interruptBudget = { start: Date.now() };
1204
+ let baselineSnapshot;
1205
+ let baselineSerdeRootPtr;
1206
+ if (isQuickJSBaselineSnapshotEnabled()) {
1207
+ try {
1208
+ const entry = await getBaselineEntry(workflowCode, workflowId);
1209
+ if (entry.state === 'ready') {
1210
+ baselineSnapshot = entry.snapshot;
1211
+ baselineSerdeRootPtr = entry.serdeRootPtr;
1212
+ }
1213
+ }
1214
+ catch (err) {
1215
+ // A rejection here is an infrastructure failure during hydrate
1216
+ // (e.g. vm.snapshot() under memory pressure, QuickJS.create or
1217
+ // getCompiledAssets() failing), NOT bundle eval, which returns
1218
+ // an ineligible entry. getBaselineEntry has already evicted the
1219
+ // cached promise so a later invocation can retry. This invocation
1220
+ // must fall back to fresh evaluation (which would have succeeded)
1221
+ // rather than fail the whole run for a snapshot-only failure mode.
1222
+ runtimeLogger.warn('QuickJS baseline snapshot hydrate failed; falling back to fresh evaluation for this invocation', { workflowId, error: err });
1223
+ }
1224
+ }
1225
+ let vm;
1226
+ if (baselineSnapshot) {
1227
+ const assets = await getCompiledAssets();
1228
+ vm = await QuickJS.restore(baselineSnapshot, {
1229
+ wasm: assets.wasm,
1230
+ memoryLimit: 256 * 1024 * 1024,
1231
+ interruptHandler: createInterruptHandler(interruptBudget),
1232
+ extensions: assets.extensions,
1233
+ wasi: makeDeterministicClockWasi(() => vmNowMs),
1234
+ });
1235
+ }
1236
+ else {
1237
+ vm = await initWorkflowVM(() => vmNowMs, interruptBudget);
1238
+ }
1239
+ // Host-side serde: captures the VM's intrinsics (bootstrap included)
1240
+ // before any user code runs. All serialization now happens on the host
1241
+ // through handles: no serializer code is evaluated inside the VM.
1242
+ // Fresh path: capture now (no user code has run, as the bundle evaluates
1243
+ // later in the per-run phase). Snapshot path: re-adopt the capture root
1244
+ // the baseline hydrate created BEFORE the bundle evaluated, since the box
1245
+ // lives in the restored memory image at the recorded offset. Both give
1246
+ // the serde pristine capture-before-user-code intrinsics; neither
1247
+ // executes guest code here.
1248
+ const serde = baselineSnapshot && baselineSerdeRootPtr !== undefined
1249
+ ? createQuickJSSerde(vm, adoptSerdeRoot(vm, baselineSerdeRootPtr))
1250
+ : createQuickJSSerde(vm);
1251
+ // Any throw between here and the terminal paths (which dispose the VM
1252
+ // inside checkWorkflowState / extractError before RETURNING) would leak
1253
+ // a live QuickJS instance and its WASM linear memory for the lifetime
1254
+ // of the compute instance, which is reused. Dispose on the way out of
1255
+ // an exceptional exit and rethrow.
1256
+ try {
1257
+ return await runWorkflowInVM();
1258
+ }
1259
+ catch (err) {
1260
+ try {
1261
+ vm.dispose();
1262
+ }
1263
+ catch {
1264
+ // Already disposed by a terminal path, so ignore.
1265
+ }
1266
+ throw err;
1267
+ }
1268
+ // ---- Phase 2: per-run initialization ----
1269
+ async function runWorkflowInVM() {
1270
+ vm.evalCode(`globalThis.__worldCapabilities = ${JSON.stringify(options.worldCapabilities)};`).dispose();
1271
+ // Seeded Math.random
1272
+ {
1273
+ const env_2 = { stack: [], error: void 0, hasError: false };
1274
+ try {
1275
+ const randomFn = __addDisposableResource(env_2, vm.newFunction('random', () => vm.newNumber(rng())), false);
1276
+ const math = __addDisposableResource(env_2, vm.global.getProp('Math'), false);
1277
+ math.setProp('random', randomFn);
1278
+ }
1279
+ catch (e_2) {
1280
+ env_2.error = e_2;
1281
+ env_2.hasError = true;
1282
+ }
1283
+ finally {
1284
+ __disposeResources(env_2);
1285
+ }
1286
+ }
1287
+ // Seeded nanoid generator
1288
+ {
1289
+ const env_3 = { stack: [], error: void 0, hasError: false };
1290
+ try {
1291
+ const nanoidFn = __addDisposableResource(env_3, vm.newFunction('__generateNanoid', () => vm.newString(generateNanoid())), false);
1292
+ vm.setProp(vm.global, '__generateNanoid', nanoidFn);
1293
+ }
1294
+ catch (e_3) {
1295
+ env_3.error = e_3;
1296
+ env_3.hasError = true;
1297
+ }
1298
+ finally {
1299
+ __disposeResources(env_3);
1300
+ }
1301
+ }
1302
+ // Host-side deterministic ULID generator for correlationIds. Uses the
1303
+ // same `ulid` package and monotonic factory as before, drawing from
1304
+ // the SAME seeded PRNG instance as the VM's Math.random, so the
1305
+ // interleaved draw sequence (and therefore every correlationId) is
1306
+ // byte-identical to what the previous in-VM ULID factory produced for
1307
+ // the same run. The time prefix is derived from the runId's embedded
1308
+ // ULID (stable across invocations by construction, unlike
1309
+ // `startedAt`, which differs between turbo's synthesized run object
1310
+ // and the durably stored run), so two concurrent invocations of the
1311
+ // same run produce IDENTICAL correlationIds and the world's
1312
+ // EntityConflictError on `events.create` dedups one of each pair.
1313
+ {
1314
+ const env_4 = { stack: [], error: void 0, hasError: false };
1315
+ try {
1316
+ const ulidFactory = monotonicFactory(() => rng());
1317
+ const ulidTimestamp = runIdCreatedAt(workflowRun.runId) ??
1318
+ (+workflowRun.createdAt || startedAt);
1319
+ const ulidFn = __addDisposableResource(env_4, vm.newFunction('__generateUlid', () => vm.newString(ulidFactory(ulidTimestamp))), false);
1320
+ vm.setProp(vm.global, '__generateUlid', ulidFn);
1321
+ }
1322
+ catch (e_4) {
1323
+ env_4.error = e_4;
1324
+ env_4.hasError = true;
1325
+ }
1326
+ finally {
1327
+ __disposeResources(env_4);
1328
+ }
1329
+ }
1330
+ // `process.env`: parity with the node:vm engine, which exposes a frozen
1331
+ // copy of the host env (vm/index.ts). Injected per run so the snapshot of
1332
+ // the env is taken at invocation time, same as node. Handle-based (no
1333
+ // guest source evaluated): on the baseline-snapshot path this runs
1334
+ // after user code, and a guest-source injection would execute through
1335
+ // potentially patched globals (JSON.parse, Object.freeze), visible
1336
+ // to module-scope wrappers only on the restore path, diverging
1337
+ // replays.
1338
+ serde.installProcessEnv(process.env);
1339
+ // Execute the workflow bundle: use the workflowId as the eval filename
1340
+ // so QuickJS stack traces reference the workflow name, enabling source map
1341
+ // remapping by remapErrorStack (which matches frames by filename).
1342
+ // Evaluated in the per-run phase (after Math.random seeding) so that
1343
+ // module-scope user code draws from the seeded PRNG, matching the
1344
+ // node:vm engine's replay determinism. Skipped on the
1345
+ // baseline-snapshot path: the restored heap already carries the
1346
+ // evaluated bundle, and the baseline gate guarantees module scope
1347
+ // consumed no PRNG draws or clock reads, so skipping the eval is
1348
+ // observationally identical to re-running it (the run-seeded host
1349
+ // fns registered above rebind the SAME names the restored heap's
1350
+ // function objects dispatch through).
1351
+ if (!baselineSnapshot) {
1352
+ try {
1353
+ vm.evalCode(workflowCode, workflowId || 'workflow.js').dispose();
1354
+ }
1355
+ catch (err) {
1356
+ return makeSettledSession(extractError(vm, err, 'Workflow evaluation failed'));
1357
+ }
1358
+ }
1359
+ // Extract workflow arguments. Prefer the run_created event; fall back
1360
+ // to the queue message's runInput if the event log is incomplete
1361
+ // (eventually-consistent read after start()). Failing to find input
1362
+ // for a first invocation is fatal: running the workflow function
1363
+ // with no args would silently turn typed arguments into `undefined`
1364
+ // and, for recursive workflows, produce exponential fan-out.
1365
+ const runCreatedEvent = events.find((e) => e.eventType === 'run_created');
1366
+ const runCreatedInput = runCreatedEvent && 'eventData' in runCreatedEvent
1367
+ ? runCreatedEvent.eventData?.input
1368
+ : undefined;
1369
+ const runInput = runCreatedInput ?? options.runInput?.input;
1370
+ if (runInput instanceof Uint8Array) {
1371
+ const decryptedInput = await prepareBytesForVM(runInput, options.encryptionKey);
1372
+ runtimeLogger.debug('QuickJS runtime: run input format', {
1373
+ prefix: new TextDecoder().decode(decryptedInput.subarray(0, 4)),
1374
+ byteLength: decryptedInput.byteLength,
1375
+ source: runCreatedInput ? 'run_created' : 'queueMessage.runInput',
1376
+ });
1377
+ // Build the argument value directly in the VM via the host-side
1378
+ // serde (guest code never sees the wire bytes).
1379
+ const inputHandle = serde.deserialize(decryptedInput);
1380
+ vm.setProp(vm.global, '__wdk_input', inputHandle);
1381
+ inputHandle.dispose();
1382
+ }
1383
+ else if (runInput === undefined && events.length > 0) {
1384
+ // The event log is non-empty (we got run_started or similar) but
1385
+ // no run_created event was found and no queue-provided runInput is
1386
+ // available. This is the race condition observed during the fib
1387
+ // incident: silently dropping arguments would turn `n` into
1388
+ // `undefined` and, for recursive workflows, cause exponential
1389
+ // fan-out. Fail loud: the throw escapes the entrypoint into the
1390
+ // replay loop's catch in runtime.ts (the QuickJS dispatch runs
1391
+ // inside that loop's try), which records run_failed. A visible
1392
+ // terminal failure is
1393
+ // preferred over silently executing with undefined arguments. The
1394
+ // queue-provided runInput fallback above makes this path rare.
1395
+ // Empty `events` is allowed because tests that bootstrap a workflow
1396
+ // with no arguments rely on the old permissive behavior.
1397
+ 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()).`);
1398
+ }
1399
+ // Set workflow context metadata (for getWorkflowMetadata()).
1400
+ // Must match the shape that the node:vm engine produces (see
1401
+ // packages/core/src/workflow.ts: runWorkflow → ctx) so user code
1402
+ // that compares `getWorkflowMetadata()` values between a step
1403
+ // (server-side) and the workflow (VM-side) sees identical objects.
1404
+ {
1405
+ const metadata = {
1406
+ workflowName: workflowRun.workflowName,
1407
+ workflowRunId: workflowRun.runId,
1408
+ workflowStartedAt: workflowRun.startedAt
1409
+ ? new Date(+workflowRun.startedAt)
1410
+ : new Date(),
1411
+ url: process.env.VERCEL_URL
1412
+ ? `https://${process.env.VERCEL_URL}`
1413
+ : `http://localhost:${options.port ?? 3000}`,
1414
+ features: { encryption: !!options.encryptionKey },
1415
+ };
1416
+ vm.evalCode(`globalThis[Symbol.for("WORKFLOW_CONTEXT")] = ${JSON.stringify(metadata)};` +
1417
+ `globalThis[Symbol.for("WORKFLOW_CONTEXT")].workflowStartedAt = new Date(${JSON.stringify(metadata.workflowStartedAt.toISOString())});`).dispose();
1418
+ }
1419
+ // Start the workflow function. If the workflow isn't registered,
1420
+ // throw an error tagged with `name = "WorkflowNotRegisteredError"`
1421
+ // so the host-side entrypoint can reconstruct a real
1422
+ // WorkflowNotRegisteredError (a WorkflowRuntimeError subclass that
1423
+ // classifies as RUNTIME_ERROR) rather than a generic user error.
1424
+ // See quickjs-entrypoint.ts's run_failed branch.
1425
+ try {
1426
+ vm.evalCode(`
1427
+ var __wfn = globalThis.__private_workflows.get(${JSON.stringify(workflowId)});
1428
+ if (!__wfn) {
1429
+ var __wfnErr = new Error("Workflow \\"" + ${JSON.stringify(workflowId)} + "\\" is not registered in the current deployment.");
1430
+ __wfnErr.name = "WorkflowNotRegisteredError";
1431
+ throw __wfnErr;
1432
+ }
1433
+ var __args = globalThis.__wdk_input !== undefined
1434
+ ? globalThis.__wdk_input
1435
+ : [];
1436
+ delete globalThis.__wdk_input;
1437
+ if (!Array.isArray(__args)) __args = [__args];
1438
+ __wfn.apply(null, __args).then(
1439
+ function(result) {
1440
+ // Store the RAW result; the host serializes it through a handle.
1441
+ // A separate done flag distinguishes "completed with undefined"
1442
+ // from "not completed".
1443
+ globalThis.__workflowDone = true;
1444
+ globalThis.__workflowResult = result;
1445
+ },
1446
+ function(error) {
1447
+ // Preserve display info on the host-side failed object
1448
+ // (matches the legacy host-visible shape) AND keep the RAW
1449
+ // thrown value so the host can serialize the original
1450
+ // type-identity, cause chain, or non-Error throws verbatim
1451
+ // through the standard error pipeline.
1452
+ globalThis.__workflowError = {
1453
+ message: error && error.message != null ? String(error.message) : String(error),
1454
+ stack: error && error.stack ? error.stack : "",
1455
+ name: error && error.name ? error.name : (error instanceof Error ? "Error" : typeof error),
1456
+ value: error,
1457
+ };
1458
+ }
1459
+ );
1460
+ `).dispose();
1461
+ }
1462
+ catch (err) {
1463
+ return makeSettledSession(extractError(vm, err, 'Failed to start workflow'));
1464
+ }
1465
+ // Process events and drain jobs in a loop. Events may resolve promises
1466
+ // that unblock workflow code, which then creates NEW resolvers for
1467
+ // subsequent events. Re-processing events matches these new resolvers
1468
+ // against events that were already delivered.
1469
+ {
1470
+ let maxIterations = 100;
1471
+ let madeProgress;
1472
+ do {
1473
+ madeProgress = await processEvents(vm, serde, events, advanceClock, options.encryptionKey);
1474
+ let batch;
1475
+ do {
1476
+ batch = vm.executePendingJobs();
1477
+ if (batch > 0)
1478
+ madeProgress = true;
1479
+ } while (batch > 0);
1480
+ } while (madeProgress && --maxIterations > 0);
1481
+ if (madeProgress && maxIterations === 0) {
1482
+ // The drain loop hit its bound while still making progress:
1483
+ // proceeding as if it converged would present as a mysterious
1484
+ // suspension or replay divergence. Make the giving-up visible so
1485
+ // a wedge is attributable to this bound rather than a mystery.
1486
+ runtimeLogger.warn('QuickJS runtime: event drain loop hit its iteration bound before reaching a fixed point', {
1487
+ workflowRunId: workflowRun.runId,
1488
+ eventCount: events.length,
1489
+ });
1490
+ }
1491
+ }
1492
+ // ---- Check result ----
1493
+ return makeLiveSession(vm, serde, interruptBudget, advanceClock, options.encryptionKey);
1494
+ }
1495
+ }
1496
+ /** Session wrapper for a result whose VM is already settled/disposed. */
1497
+ function makeSettledSession(result) {
1498
+ return {
1499
+ result,
1500
+ continueWithEvents: () => {
1501
+ throw new Error('QuickJS workflow session is settled — continueWithEvents is only valid while suspended');
1502
+ },
1503
+ dispose: () => { },
1504
+ };
1505
+ }
1506
+ /**
1507
+ * Evaluate the VM's state and wrap it in a live session. While suspended,
1508
+ * the VM stays alive so `continueWithEvents` can resume it in place;
1509
+ * terminal states dispose the VM immediately (inside checkWorkflowState).
1510
+ */
1511
+ function makeLiveSession(vm, serde, interruptBudget, advanceClock, encryptionKey) {
1512
+ const result = checkWorkflowState(vm, serde, { keepAliveOnSuspend: true });
1513
+ let alive = !!result.suspended;
1514
+ const session = {
1515
+ result,
1516
+ async continueWithEvents(newEvents) {
1517
+ if (!alive) {
1518
+ throw new Error('QuickJS workflow session is not alive — continueWithEvents is only valid while suspended');
1519
+ }
1520
+ // Fresh execution burst: the interrupt budget bounds VM compute,
1521
+ // not wall time spent waiting on inline steps between bursts.
1522
+ interruptBudget.start = Date.now();
1523
+ let maxIterations = 100;
1524
+ let madeProgress;
1525
+ do {
1526
+ madeProgress = await processEvents(vm, serde, newEvents, advanceClock, encryptionKey);
1527
+ let batch;
1528
+ do {
1529
+ batch = vm.executePendingJobs();
1530
+ if (batch > 0)
1531
+ madeProgress = true;
1532
+ } while (batch > 0);
1533
+ } while (madeProgress && --maxIterations > 0);
1534
+ const next = checkWorkflowState(vm, serde, {
1535
+ keepAliveOnSuspend: true,
1536
+ });
1537
+ if (!next.suspended)
1538
+ alive = false;
1539
+ session.result = next;
1540
+ return next;
1541
+ },
1542
+ dispose() {
1543
+ if (alive) {
1544
+ alive = false;
1545
+ try {
1546
+ vm.dispose();
1547
+ }
1548
+ catch {
1549
+ // Already disposed, so ignore.
1550
+ }
1551
+ }
1552
+ },
1553
+ };
1554
+ return session;
1555
+ }
1556
+ // ---- Event Processing ----
1557
+ async function processEvents(vm, serde, events, advanceClock, encryptionKey) {
1558
+ let resolved = false;
1559
+ for (const event of events) {
1560
+ // A sealed-log noop occupies a slot whose writer died; the run never
1561
+ // observed it. Step over it BEFORE the clock line below, not at the
1562
+ // switch: its `createdAt` is the sealer's wall clock and can postdate
1563
+ // every real event around it, so advancing to it would leak the sealer's
1564
+ // schedule into replay. Because the clock is monotonic, every later
1565
+ // Date.now() in the run with it. That would make a log whose hole was
1566
+ // sealed replay differently from the same log whose hole its own writer
1567
+ // filled, and differently from this log on the node:vm engine, which
1568
+ // skips noops in `EventsConsumer` before `onConsumedEvent` feeds the
1569
+ // clock. Same rule, both engines, one predicate.
1570
+ if (isSealedNoopEvent(event))
1571
+ continue;
1572
+ // Advance the VM's deterministic clock to this event's creation time
1573
+ // BEFORE resolving anything, so workflow code unblocked by this event
1574
+ // observes Date.now() at (or after, since the clock is monotonic) the time
1575
+ // the event was recorded. Mirrors the node:vm engine's
1576
+ // `onConsumedEvent → updateTimestamp(+event.createdAt)`.
1577
+ advanceClock(+event.createdAt);
1578
+ const cid = event.correlationId;
1579
+ if (!cid)
1580
+ continue;
1581
+ // JSON.stringify handles quotes, backslashes and control characters;
1582
+ // correlation ids are host-generated ULIDs today, but the eval-string
1583
+ // safety shouldn't depend on that invariant being asserted nowhere.
1584
+ const cidJs = JSON.stringify(cid);
1585
+ const eventData = 'eventData' in event
1586
+ ? event.eventData
1587
+ : undefined;
1588
+ // Log the event and whether the resolver exists
1589
+ switch (event.eventType) {
1590
+ case 'step_completed': {
1591
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1592
+ const rawOutput = eventData?.result ?? eventData?.output;
1593
+ if (hasResolver) {
1594
+ if (rawOutput instanceof Uint8Array) {
1595
+ // Decrypt if encrypted: the VM only understands 'devl' format
1596
+ runtimeLogger.debug('QuickJS runtime: step result raw', {
1597
+ correlationId: cid,
1598
+ rawPrefix: new TextDecoder().decode(rawOutput.subarray(0, 4)),
1599
+ rawByteLength: rawOutput.byteLength,
1600
+ isBuffer: Buffer.isBuffer(rawOutput),
1601
+ });
1602
+ const decryptedOutput = await prepareBytesForVM(rawOutput, encryptionKey);
1603
+ runtimeLogger.debug('QuickJS runtime: step result decrypted', {
1604
+ correlationId: cid,
1605
+ prefix: new TextDecoder().decode(decryptedOutput.subarray(0, 4)),
1606
+ byteLength: decryptedOutput.byteLength,
1607
+ });
1608
+ const valueHandle = serde.deserialize(decryptedOutput);
1609
+ vm.setProp(vm.global, '__tmp_result', valueHandle);
1610
+ valueHandle.dispose();
1611
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(globalThis.__tmp_result);` +
1612
+ `delete globalThis.__resolvers[${cidJs}];` +
1613
+ `delete globalThis.__tmp_result;`).dispose();
1614
+ }
1615
+ else {
1616
+ runtimeLogger.debug('QuickJS runtime: step result non-binary', {
1617
+ correlationId: cid,
1618
+ type: typeof rawOutput,
1619
+ isNull: rawOutput === null,
1620
+ isUndefined: rawOutput === undefined,
1621
+ constructor: rawOutput?.constructor?.name,
1622
+ });
1623
+ const serialized = rawOutput !== undefined ? JSON.stringify(rawOutput) : 'undefined';
1624
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(${serialized});` +
1625
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1626
+ }
1627
+ // Drain ALL microtasks after resolve
1628
+ {
1629
+ resolved = true;
1630
+ let b;
1631
+ do {
1632
+ b = vm.executePendingJobs();
1633
+ } while (b > 0);
1634
+ }
1635
+ }
1636
+ else {
1637
+ // No resolver yet, so buffer the prepared outcome so the promise
1638
+ // settles the moment the VM constructs it (see __terminalBuffer
1639
+ // in the bootstrap). Without this, the live-continuation path
1640
+ // (which scans each delta exactly once) drops the terminal and
1641
+ // the await never settles.
1642
+ if (rawOutput instanceof Uint8Array) {
1643
+ const decryptedOutput = await prepareBytesForVM(rawOutput, encryptionKey);
1644
+ // Host serde: deserialize into a VM value NOW (same path as
1645
+ // the resolver branch above) and buffer the value itself.
1646
+ const valueHandle = serde.deserialize(decryptedOutput);
1647
+ vm.setProp(vm.global, '__tmp_buf', valueHandle);
1648
+ valueHandle.dispose();
1649
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_value", value: globalThis.__tmp_buf };` +
1650
+ `delete globalThis.__tmp_buf;`).dispose();
1651
+ }
1652
+ else {
1653
+ const serialized = rawOutput !== undefined ? JSON.stringify(rawOutput) : 'undefined';
1654
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_value", value: ${serialized} };`).dispose();
1655
+ }
1656
+ }
1657
+ markCreated(vm, cidJs);
1658
+ break;
1659
+ }
1660
+ case 'step_failed': {
1661
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1662
+ if (hasResolver) {
1663
+ const errorData = eventData?.error;
1664
+ if (errorData instanceof Uint8Array) {
1665
+ // Modern path (post-#1851): the step handler dehydrated the
1666
+ // thrown value through the first-class error pipeline. Decrypt
1667
+ // (if encrypted) and pass the bytes to the VM-side deserializer
1668
+ // so the workflow catch sees a properly typed Error subclass
1669
+ // (TypeError, FatalError with original cause chain, etc.) with
1670
+ // the original message and stack preserved.
1671
+ const decrypted = await prepareBytesForVM(errorData, encryptionKey);
1672
+ const errorHandle = serde.deserialize(decrypted);
1673
+ vm.setProp(vm.global, '__tmp_error', errorHandle);
1674
+ errorHandle.dispose();
1675
+ vm.evalCode(`(function(){` +
1676
+ `globalThis.__resolvers[${cidJs}].reject(globalThis.__tmp_error);` +
1677
+ `delete globalThis.__resolvers[${cidJs}];` +
1678
+ `delete globalThis.__tmp_error;` +
1679
+ `})()`).dispose();
1680
+ }
1681
+ else {
1682
+ // Legacy path: pre-pipeline events stored error as
1683
+ // `{ message, stack, code }`. Reconstruct a FatalError so
1684
+ // workflow catch can detect it via FatalError.is(), matching
1685
+ // the original V1 step handler behavior.
1686
+ const isErrorObject = typeof errorData === 'object' && errorData !== null;
1687
+ const msg = isErrorObject
1688
+ ? (errorData.message ??
1689
+ 'Step failed')
1690
+ : typeof errorData === 'string'
1691
+ ? errorData
1692
+ : 'Step failed';
1693
+ const errorStack = (isErrorObject
1694
+ ? errorData.stack
1695
+ : undefined) ?? eventData?.stack;
1696
+ const stackAssignment = errorStack
1697
+ ? `e.stack=${JSON.stringify(errorStack)};`
1698
+ : '';
1699
+ vm.evalCode(`(function(){var e=new Error(${JSON.stringify(msg)});e.name="FatalError";e.fatal=true;${stackAssignment}` +
1700
+ `globalThis.__resolvers[${cidJs}].reject(e);` +
1701
+ `delete globalThis.__resolvers[${cidJs}];})()`).dispose();
1702
+ }
1703
+ {
1704
+ resolved = true;
1705
+ let b;
1706
+ do {
1707
+ b = vm.executePendingJobs();
1708
+ } while (b > 0);
1709
+ }
1710
+ }
1711
+ else {
1712
+ // No resolver yet, so buffer the prepared rejection (see the
1713
+ // step_completed branch above for the rationale).
1714
+ const errorData = eventData?.error;
1715
+ if (errorData instanceof Uint8Array) {
1716
+ const decrypted = await prepareBytesForVM(errorData, encryptionKey);
1717
+ // Host serde: deserialize into the VM error value NOW (same
1718
+ // path as the resolver branch above) and buffer it.
1719
+ const errorHandle = serde.deserialize(decrypted);
1720
+ vm.setProp(vm.global, '__tmp_buf', errorHandle);
1721
+ errorHandle.dispose();
1722
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "reject_value", value: globalThis.__tmp_buf };` +
1723
+ `delete globalThis.__tmp_buf;`).dispose();
1724
+ }
1725
+ else {
1726
+ const isErrorObject = typeof errorData === 'object' && errorData !== null;
1727
+ const msg = isErrorObject
1728
+ ? (errorData.message ??
1729
+ 'Step failed')
1730
+ : typeof errorData === 'string'
1731
+ ? errorData
1732
+ : 'Step failed';
1733
+ const errorStack = (isErrorObject
1734
+ ? errorData.stack
1735
+ : undefined) ?? eventData?.stack;
1736
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "reject_error", message: ${JSON.stringify(msg)}, stack: ${errorStack ? JSON.stringify(errorStack) : 'undefined'} };`).dispose();
1737
+ }
1738
+ }
1739
+ markCreated(vm, cidJs);
1740
+ break;
1741
+ }
1742
+ case 'wait_completed': {
1743
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1744
+ if (hasResolver) {
1745
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve();` +
1746
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1747
+ {
1748
+ resolved = true;
1749
+ let b;
1750
+ do {
1751
+ b = vm.executePendingJobs();
1752
+ } while (b > 0);
1753
+ }
1754
+ }
1755
+ else {
1756
+ // No resolver yet, so buffer (see step_completed above).
1757
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_undefined" };`).dispose();
1758
+ }
1759
+ markCreated(vm, cidJs);
1760
+ break;
1761
+ }
1762
+ case 'attr_set': {
1763
+ // Only workflow-written attribute events resolve a pending
1764
+ // setAttributes() promise; step/system writers share no
1765
+ // correlationIds with VM resolvers, so the guard is defensive.
1766
+ const writer = eventData?.writer
1767
+ ?.type;
1768
+ if (writer !== 'workflow')
1769
+ break;
1770
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1771
+ if (!hasResolver) {
1772
+ // No resolver yet, so buffer (see step_completed above).
1773
+ vm.evalCode(`globalThis.__terminalBuffer[${cidJs}] = { kind: "resolve_undefined" };`).dispose();
1774
+ }
1775
+ if (hasResolver) {
1776
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve();` +
1777
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1778
+ {
1779
+ resolved = true;
1780
+ let b;
1781
+ do {
1782
+ b = vm.executePendingJobs();
1783
+ } while (b > 0);
1784
+ }
1785
+ }
1786
+ markCreated(vm, cidJs);
1787
+ break;
1788
+ }
1789
+ case 'hook_received': {
1790
+ // Check if this event was already processed (delivered or
1791
+ // buffered) within this invocation. Prevents double-delivery when
1792
+ // the outer loop re-scans events.
1793
+ const alreadyProcessed = event.eventId
1794
+ ? vm.dump(vm.evalCode(`!!(globalThis.__hookPayloadBuffer.__processedEventIds && globalThis.__hookPayloadBuffer.__processedEventIds[${JSON.stringify(event.eventId)}])`))
1795
+ : false;
1796
+ if (alreadyProcessed) {
1797
+ runtimeLogger.debug('QuickJS runtime: hook_received already processed', {
1798
+ correlationId: cid,
1799
+ eventId: event.eventId,
1800
+ });
1801
+ markCreated(vm, cidJs);
1802
+ break;
1803
+ }
1804
+ // Resilient-resume dedup (parity with the node engine's
1805
+ // EventsConsumer in workflow/hook.ts): two hook_received rows for
1806
+ // ONE resume attempt share a client-minted `resumeId` (a duplicate
1807
+ // can be committed when the materialization fallback races a
1808
+ // delayed direct write, since hook_received has no storage uniqueness
1809
+ // constraint). Deliver only the first-in-log occurrence. The seen
1810
+ // set lives in the VM heap so it is deterministic per replay and
1811
+ // survives event re-scans within the invocation. Events without a
1812
+ // resumeId (older SDKs) are never deduped.
1813
+ {
1814
+ // Top-level event.resumeId is the canonical location (the backend
1815
+ // hoists it to a first-class column); the nested
1816
+ // eventData.resumeId form is a deprecated legacy fallback.
1817
+ // Mirrors the node engine's dedup in workflow/hook.ts.
1818
+ const resumeId = event.resumeId ??
1819
+ eventData?.resumeId;
1820
+ if (typeof resumeId === 'string') {
1821
+ const resumeIdJs = JSON.stringify(resumeId);
1822
+ const duplicate = vm.dump(vm.evalCode(`(globalThis.__hookSeenResumeIds = globalThis.__hookSeenResumeIds || {})[${resumeIdJs}] === true`));
1823
+ if (duplicate) {
1824
+ runtimeLogger.debug('QuickJS runtime: duplicate hook_received for the same resume attempt, dropping', { correlationId: cid, eventId: event.eventId, resumeId });
1825
+ if (event.eventId) {
1826
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1827
+ }
1828
+ markCreated(vm, cidJs);
1829
+ break;
1830
+ }
1831
+ vm.evalCode(`globalThis.__hookSeenResumeIds[${resumeIdJs}] = true;`).dispose();
1832
+ }
1833
+ }
1834
+ // Abort delivery: hook_received for an AbortController's system
1835
+ // hook flips the registered signal instead of resolving a promise.
1836
+ // The payload is the dehydrated `{ aborted: true, reason }` object.
1837
+ const isAbortHook = vm.dump(vm.evalCode(`!!(globalThis.__abortSignals && globalThis.__abortSignals[${cidJs}])`));
1838
+ if (isAbortHook) {
1839
+ const rawAbortPayload = eventData?.payload;
1840
+ if (rawAbortPayload instanceof Uint8Array) {
1841
+ const decrypted = await prepareBytesForVM(rawAbortPayload, encryptionKey);
1842
+ const payloadHandle = serde.deserialize(decrypted);
1843
+ vm.setProp(vm.global, '__tmp_abort', payloadHandle);
1844
+ payloadHandle.dispose();
1845
+ vm.evalCode(`(function(){` +
1846
+ `var p=globalThis.__tmp_abort;` +
1847
+ `delete globalThis.__tmp_abort;` +
1848
+ `globalThis.__abortSignals[${cidJs}]._setAborted(p&&typeof p==="object"?p.reason:undefined);` +
1849
+ `})()`).dispose();
1850
+ }
1851
+ else {
1852
+ vm.evalCode(`globalThis.__abortSignals[${cidJs}]._setAborted(undefined);`).dispose();
1853
+ }
1854
+ // The abort is durably recorded, so clear the pending op's
1855
+ // abortRequested marker so the host doesn't re-record it (the
1856
+ // workflow's own abort() call can set the flag before this
1857
+ // event is processed when it happens later in replay order,
1858
+ // and hook_received events are not unique per correlationId).
1859
+ vm.evalCode(`(function(){` +
1860
+ `var p=globalThis.__pending.find(function(q){return q.correlationId===${JSON.stringify(cid)}&&q.type==="hook";});` +
1861
+ `if(p)p.abortRequested=false;` +
1862
+ `})()`).dispose();
1863
+ if (event.eventId) {
1864
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1865
+ }
1866
+ {
1867
+ resolved = true;
1868
+ let b;
1869
+ do {
1870
+ b = vm.executePendingJobs();
1871
+ } while (b > 0);
1872
+ }
1873
+ markCreated(vm, cidJs);
1874
+ break;
1875
+ }
1876
+ const hasResolver = vm.dump(vm.evalCode(`!!globalThis.__resolvers[${cidJs}]`));
1877
+ const rawPayload = eventData?.payload ?? eventData?.result;
1878
+ runtimeLogger.debug('QuickJS runtime: processing hook_received', {
1879
+ correlationId: cid,
1880
+ eventId: event.eventId,
1881
+ hasResolver,
1882
+ payloadType: typeof rawPayload,
1883
+ payloadIsUint8Array: rawPayload instanceof Uint8Array,
1884
+ payloadKeys: rawPayload && typeof rawPayload === 'object'
1885
+ ? Object.keys(rawPayload)
1886
+ : undefined,
1887
+ });
1888
+ if (hasResolver) {
1889
+ if (rawPayload instanceof Uint8Array) {
1890
+ // Decrypt if encrypted: the VM only understands 'devl' format
1891
+ const decryptedPayload = await prepareBytesForVM(rawPayload, encryptionKey);
1892
+ const payloadHandle = serde.deserialize(decryptedPayload);
1893
+ vm.setProp(vm.global, '__tmp_result', payloadHandle);
1894
+ payloadHandle.dispose();
1895
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(globalThis.__tmp_result);` +
1896
+ `delete globalThis.__resolvers[${cidJs}];` +
1897
+ `delete globalThis.__tmp_result;`).dispose();
1898
+ }
1899
+ else {
1900
+ const serialized = rawPayload !== undefined
1901
+ ? JSON.stringify(rawPayload)
1902
+ : 'undefined';
1903
+ vm.evalCode(`globalThis.__resolvers[${cidJs}].resolve(${serialized});` +
1904
+ `delete globalThis.__resolvers[${cidJs}];`).dispose();
1905
+ }
1906
+ // Mark this event as processed in the VM heap to prevent
1907
+ // double-delivery when the outer loop re-scans events.
1908
+ if (event.eventId) {
1909
+ vm.evalCode(`(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${JSON.stringify(event.eventId)}] = true;`).dispose();
1910
+ }
1911
+ {
1912
+ resolved = true;
1913
+ let b;
1914
+ do {
1915
+ b = vm.executePendingJobs();
1916
+ } while (b > 0);
1917
+ }
1918
+ }
1919
+ else {
1920
+ // No resolver yet, so buffer the payload in the VM heap. When
1921
+ // createHookPromise() is called later, it will drain this buffer
1922
+ // first (matching the node:vm engine's payloadsQueue behavior).
1923
+ const eventIdJs = event.eventId
1924
+ ? JSON.stringify(event.eventId)
1925
+ : 'null';
1926
+ const bufferAndTrack = `(globalThis.__hookPayloadBuffer[${cidJs}] = globalThis.__hookPayloadBuffer[${cidJs}] || [])` +
1927
+ `.push(%PAYLOAD%);` +
1928
+ (event.eventId
1929
+ ? `(globalThis.__hookPayloadBuffer.__processedEventIds = globalThis.__hookPayloadBuffer.__processedEventIds || {})[${eventIdJs}] = true;`
1930
+ : '');
1931
+ if (rawPayload instanceof Uint8Array) {
1932
+ // Decrypt if encrypted: the VM only understands 'devl' format
1933
+ const decryptedPayload = await prepareBytesForVM(rawPayload, encryptionKey);
1934
+ const payloadHandle = serde.deserialize(decryptedPayload);
1935
+ vm.setProp(vm.global, '__tmp_result', payloadHandle);
1936
+ payloadHandle.dispose();
1937
+ // NOTE: replacement is a function so `$`-sequences in the
1938
+ // substituted JS never get interpreted as String.replace
1939
+ // special replacement patterns.
1940
+ vm.evalCode(bufferAndTrack.replace('%PAYLOAD%', () => 'globalThis.__tmp_result') + 'delete globalThis.__tmp_result;').dispose();
1941
+ }
1942
+ else {
1943
+ const serialized = rawPayload !== undefined
1944
+ ? JSON.stringify(rawPayload)
1945
+ : 'undefined';
1946
+ // Function replacement: a JSON-serialized payload can contain
1947
+ // `$&`, `$'`, `$\``, ... which String.replace would otherwise
1948
+ // expand, silently corrupting the injected code.
1949
+ vm.evalCode(bufferAndTrack.replace('%PAYLOAD%', () => serialized)).dispose();
1950
+ }
1951
+ }
1952
+ markCreated(vm, cidJs);
1953
+ break;
1954
+ }
1955
+ case 'hook_conflict': {
1956
+ // Another workflow owns this hook token. Payload awaiters reject
1957
+ // with HookConflictError; getConflict() awaiters resolve with a
1958
+ // Run handle for the conflicting run (revived through the VM's
1959
+ // class registry so its methods are durable step proxies) or
1960
+ // reject with the error when no handle can be constructed,
1961
+ // mirroring the node:vm engine's hook.ts hook_conflict handling.
1962
+ const conflictToken = eventData?.token ?? 'unknown';
1963
+ const conflictingRunId = eventData?.conflictingRunId;
1964
+ const didSettle = vm.dump(vm.evalCode(`(function(){
1965
+ var cid = ${JSON.stringify(cid)};
1966
+ var token = ${JSON.stringify(conflictToken)};
1967
+ var conflictingRunId = ${JSON.stringify(conflictingRunId ?? null)};
1968
+ var ErrCls = globalThis[Symbol.for('@workflow/errors//HookConflictError')];
1969
+ var err;
1970
+ if (typeof ErrCls === 'function') {
1971
+ err = new ErrCls(token, conflictingRunId || undefined);
1972
+ } else {
1973
+ err = new Error('Hook token "' + token + '" is already in use by another workflow');
1974
+ err.name = 'HookConflictError';
1975
+ err.token = token;
1976
+ if (conflictingRunId) err.conflictingRunId = conflictingRunId;
1977
+ }
1978
+ var run = null;
1979
+ if (conflictingRunId) {
1980
+ var reg = globalThis[Symbol.for('workflow-class-registry')];
1981
+ var RunCls = reg && reg.get('class//workflow//Run');
1982
+ var des = RunCls && RunCls[Symbol.for('workflow-deserialize')];
1983
+ if (typeof des === 'function') {
1984
+ run = des.call(RunCls, { runId: conflictingRunId });
1985
+ }
1986
+ }
1987
+ var settled = false;
1988
+ var state = globalThis.__hooks && globalThis.__hooks[cid];
1989
+ if (state && !state.conflict) {
1990
+ state.conflict = { error: err, run: run };
1991
+ var gc = state.getConflictResolvers;
1992
+ state.getConflictResolvers = [];
1993
+ for (var i = 0; i < gc.length; i++) {
1994
+ if (run) { gc[i].resolve(run); } else { gc[i].reject(err); }
1995
+ settled = true;
1996
+ }
1997
+ }
1998
+ if (globalThis.__resolvers[cid]) {
1999
+ globalThis.__resolvers[cid].reject(err);
2000
+ delete globalThis.__resolvers[cid];
2001
+ settled = true;
2002
+ }
2003
+ return settled;
2004
+ })()`));
2005
+ if (didSettle) {
2006
+ resolved = true;
2007
+ let b;
2008
+ do {
2009
+ b = vm.executePendingJobs();
2010
+ } while (b > 0);
2011
+ }
2012
+ markCreated(vm, cidJs);
2013
+ break;
2014
+ }
2015
+ case 'step_created':
2016
+ case 'step_started':
2017
+ case 'step_retrying':
2018
+ case 'wait_created': {
2019
+ markCreated(vm, cidJs);
2020
+ break;
2021
+ }
2022
+ case 'hook_created': {
2023
+ // Confirm creation for getConflict() awaiters: resolve them with
2024
+ // null (no conflict) once the event log proves the hook exists.
2025
+ const settledGetConflict = vm.dump(vm.evalCode(`(function(){
2026
+ var state = globalThis.__hooks && globalThis.__hooks[${JSON.stringify(cid)}];
2027
+ if (!state) return false;
2028
+ state.created = true;
2029
+ var gc = state.getConflictResolvers;
2030
+ state.getConflictResolvers = [];
2031
+ for (var i = 0; i < gc.length; i++) gc[i].resolve(null);
2032
+ return gc.length > 0;
2033
+ })()`));
2034
+ if (settledGetConflict) {
2035
+ resolved = true;
2036
+ let b;
2037
+ do {
2038
+ b = vm.executePendingJobs();
2039
+ } while (b > 0);
2040
+ }
2041
+ markCreated(vm, cidJs);
2042
+ break;
2043
+ }
2044
+ case 'hook_disposed': {
2045
+ // Disambiguate from the `hook` pending op with the same
2046
+ // correlationId: we want to mark the `hook_dispose` entry.
2047
+ markCreated(vm, cidJs, 'hook_dispose');
2048
+ break;
2049
+ }
2050
+ }
2051
+ }
2052
+ return resolved;
2053
+ }
2054
+ function markCreated(vm, cidJs, opType) {
2055
+ // `cidJs` is the JSON.stringify-quoted correlation id (see processEvents).
2056
+ // `hook` and `hook_dispose` pending ops share the same correlationId,
2057
+ // so when processing `hook_disposed` events we must disambiguate by
2058
+ // type: otherwise `.find()` returns the original `hook` op and the
2059
+ // `hook_dispose` op is never marked, causing the entrypoint to keep
2060
+ // retrying a hook_disposed for an already-deleted entity.
2061
+ const predicate = opType
2062
+ ? `function(p){return p.correlationId===${cidJs}&&p.type===${JSON.stringify(opType)};}`
2063
+ : `function(p){return p.correlationId===${cidJs};}`;
2064
+ vm.evalCode(`var __p=globalThis.__pending.find(${predicate});` +
2065
+ `if(__p)__p.hasCreatedEvent=true;`).dispose();
2066
+ }
2067
+ // ---- State Checking ----
2068
+ /**
2069
+ * Collect leftover pending operations that need durable side effects when
2070
+ * the workflow reaches a terminal state. Mirrors the node:vm engine's
2071
+ * drainPendingQueueItems (workflow.ts): still-alive system hooks
2072
+ * (AbortController) without an abort in flight are implicitly disposed so
2073
+ * they don't leak hook rows; ops without created events (fire-and-forget
2074
+ * attributes/hooks/steps/waits) and pending abort recordings are surfaced
2075
+ * for the entrypoint to flush.
2076
+ */
2077
+ /**
2078
+ * Per-VM cache of serialized pending-op field bytes, keyed
2079
+ * `correlationId:field`. A step's raw input is immutable once pushed, so
2080
+ * its bytes are computed once even though the op is re-collected on every
2081
+ * suspension it stays pending through.
2082
+ */
2083
+ // per-copy-ok: keyed on the VM instance, and a VM is created and driven by one
2084
+ // copy. Another copy holds no reference to the key, so a shared map could never
2085
+ // be read from it.
2086
+ const pendingByteCache = new WeakMap();
2087
+ function ensurePendingByteCache(vm) {
2088
+ let cache = pendingByteCache.get(vm);
2089
+ if (!cache) {
2090
+ cache = new Map();
2091
+ pendingByteCache.set(vm, cache);
2092
+ }
2093
+ return cache;
2094
+ }
2095
+ /**
2096
+ * The pending-op fields that hold RAW guest values (the bootstrap no longer
2097
+ * serializes them in the VM). Collection projects them out of the dumped
2098
+ * plain metadata and serializes each through a handle with the host serde.
2099
+ */
2100
+ const RAW_PENDING_FIELDS = ['input', 'metadata', 'abortPayload'];
2101
+ /**
2102
+ * Dump a filtered view of `globalThis.__pending` to host PendingOperation
2103
+ * objects, serializing the raw-value fields host-side. `filterExpr` is a
2104
+ * guest expression that evaluates to the array of ops to collect.
2105
+ */
2106
+ function dumpPendingOps(vm, serde, filterExpr, byteCache) {
2107
+ const env_5 = { stack: [], error: void 0, hasError: false };
2108
+ try {
2109
+ const projected = __addDisposableResource(env_5, vm.evalCode(`(function(){
2110
+ var ops = ${filterExpr};
2111
+ globalThis.__rawFields = [];
2112
+ // Settled ops — created, resolver-less, no abort in flight — are
2113
+ // never collected again by either the suspension or the drain
2114
+ // filter, so their cached bytes are dead weight; surface their cids
2115
+ // so the host can evict them (see the byte-cache eviction below).
2116
+ var settled = [];
2117
+ globalThis.__pending.forEach(function(p){
2118
+ if (p.hasCreatedEvent && !globalThis.__resolvers[p.correlationId] && !p.abortRequested) {
2119
+ settled.push(p.correlationId);
2120
+ }
2121
+ });
2122
+ return { settled: settled, ops: ops.map(function(p){
2123
+ var q = {};
2124
+ for (var k in p) {
2125
+ if (k === 'input' || k === 'metadata' || k === 'abortPayload') continue;
2126
+ q[k] = p[k];
2127
+ }
2128
+ var raw = {};
2129
+ ['input', 'metadata', 'abortPayload'].forEach(function(f){
2130
+ if (p[f] !== undefined) {
2131
+ raw[f] = globalThis.__rawFields.length;
2132
+ globalThis.__rawFields.push(p[f]);
2133
+ }
2134
+ });
2135
+ q.__rawIndices = raw;
2136
+ return q;
2137
+ }) };
2138
+ })()`), false);
2139
+ const dumped = vm.dump(projected);
2140
+ const plainOps = dumped.ops;
2141
+ // Byte-cache eviction: entries for settled ops can never be read again
2142
+ // (neither collection filter matches a settled op), so dropping them
2143
+ // bounds the cache by the LIVE pending set instead of growing
2144
+ // monotonically for the VM's lifetime, which matters for the inline
2145
+ // loop's long-lived sessions and snapshot-restored VMs.
2146
+ if (byteCache && dumped.settled.length > 0) {
2147
+ for (const cid of dumped.settled) {
2148
+ for (const field of RAW_PENDING_FIELDS) {
2149
+ byteCache.delete(`${cid}:${field}`);
2150
+ }
2151
+ }
2152
+ }
2153
+ const rawFields = __addDisposableResource(env_5, vm.evalCode('globalThis.__rawFields'), false);
2154
+ for (const op of plainOps) {
2155
+ const rawIndices = op.__rawIndices ?? {};
2156
+ delete op.__rawIndices;
2157
+ for (const field of RAW_PENDING_FIELDS) {
2158
+ const index = rawIndices[field];
2159
+ if (index === undefined)
2160
+ continue;
2161
+ const cacheKey = `${op.correlationId}:${field}`;
2162
+ let bytes = byteCache?.get(cacheKey);
2163
+ if (!bytes) {
2164
+ const env_6 = { stack: [], error: void 0, hasError: false };
2165
+ try {
2166
+ const valueHandle = __addDisposableResource(env_6, rawFields.getProp(String(index)), false);
2167
+ try {
2168
+ bytes = serde.serialize(valueHandle);
2169
+ }
2170
+ catch (err) {
2171
+ // A step input that refuses to serialize is a deterministic user
2172
+ // error: failing the whole collection here would fail the run
2173
+ // from the outside, where no workflow code can observe it (and
2174
+ // with a bare DevalueError instead of the framed message the
2175
+ // node:vm engine produces). Reframe it exactly like
2176
+ // `dehydrateStepArguments` does and surface it on the op: the
2177
+ // entrypoint finalizes the step as step_created + step_failed so
2178
+ // the failure rejects into the workflow, catchable. Other raw
2179
+ // fields (hook metadata, abort payloads) keep the throwing
2180
+ // behavior, matching the node:vm engine's scope.
2181
+ if (op.type === 'step' && field === 'input') {
2182
+ const { message, hint } = formatSerializationError('step arguments', err);
2183
+ op.serializationError = new SerializationError(message, { hint, cause: err });
2184
+ continue;
2185
+ }
2186
+ throw err;
2187
+ }
2188
+ byteCache?.set(cacheKey, bytes);
2189
+ }
2190
+ catch (e_5) {
2191
+ env_6.error = e_5;
2192
+ env_6.hasError = true;
2193
+ }
2194
+ finally {
2195
+ __disposeResources(env_6);
2196
+ }
2197
+ }
2198
+ op[field] = bytes;
2199
+ }
2200
+ }
2201
+ vm.evalCode('delete globalThis.__rawFields').dispose();
2202
+ return plainOps;
2203
+ }
2204
+ catch (e_6) {
2205
+ env_5.error = e_6;
2206
+ env_5.hasError = true;
2207
+ }
2208
+ finally {
2209
+ __disposeResources(env_5);
2210
+ }
2211
+ }
2212
+ function collectDrainOperations(vm, serde) {
2213
+ // Share the per-VM byte cache with the suspension path: an op that was
2214
+ // serialized during a suspension pass must reuse those exact bytes at
2215
+ // terminal drain, since re-serializing can invoke getters again and produce
2216
+ // a DIFFERENT byte sequence for what the event log treats as one value.
2217
+ return dumpPendingOps(vm, serde, `(function(){
2218
+ var toDispose = [];
2219
+ globalThis.__pending.forEach(function(p){
2220
+ if (p.type === "hook" && p.isSystem && !p.abortRequested && !p.disposed) {
2221
+ p.disposed = true;
2222
+ // Only dispose hooks that were durably created; a hook that never
2223
+ // reached storage has nothing to clean up.
2224
+ if (p.hasCreatedEvent) {
2225
+ toDispose.push({
2226
+ type: "hook_dispose",
2227
+ correlationId: p.correlationId,
2228
+ // Carried, not dropped: the entrypoint sends it on hook_disposed,
2229
+ // and the node:vm engine does the same for this case — its
2230
+ // completion drain marks the system hook disposed and reuses the
2231
+ // queue item, token and all. Synthesizing a fresh object here is
2232
+ // what makes it easy to lose.
2233
+ token: p.token,
2234
+ hasCreatedEvent: false,
2235
+ });
2236
+ }
2237
+ }
2238
+ });
2239
+ toDispose.forEach(function(d){ globalThis.__pending.push(d); });
2240
+ return globalThis.__pending.filter(function(p){
2241
+ if (p.abortRequested) return true;
2242
+ if (p.hasCreatedEvent) return false;
2243
+ // Skip system hooks that were disposed before ever being created.
2244
+ if (p.type === "hook" && p.disposed) return false;
2245
+ return true;
2246
+ });
2247
+ })()`, ensurePendingByteCache(vm));
2248
+ }
2249
+ function checkWorkflowState(vm, serde, opts = {}) {
2250
+ // Check completed: __workflowResult holds the RAW return value (with a
2251
+ // separate done flag so `undefined` results are distinguishable); the
2252
+ // host serializes it through a handle.
2253
+ {
2254
+ const env_7 = { stack: [], error: void 0, hasError: false };
2255
+ try {
2256
+ const done = __addDisposableResource(env_7, vm.evalCode('globalThis.__workflowDone === true'), false);
2257
+ if (done.toBoolean()) {
2258
+ const env_8 = { stack: [], error: void 0, hasError: false };
2259
+ try {
2260
+ const h = __addDisposableResource(env_8, vm.evalCode('globalThis.__workflowResult'), false);
2261
+ const resultBytes = serde.serialize(h);
2262
+ const drainOperations = collectDrainOperations(vm, serde);
2263
+ vm.dispose();
2264
+ return {
2265
+ completed: {
2266
+ result: resultBytes,
2267
+ ...(drainOperations.length > 0 ? { drainOperations } : {}),
2268
+ },
2269
+ };
2270
+ }
2271
+ catch (e_7) {
2272
+ env_8.error = e_7;
2273
+ env_8.hasError = true;
2274
+ }
2275
+ finally {
2276
+ __disposeResources(env_8);
2277
+ }
2278
+ }
2279
+ }
2280
+ catch (e_8) {
2281
+ env_7.error = e_8;
2282
+ env_7.hasError = true;
2283
+ }
2284
+ finally {
2285
+ __disposeResources(env_7);
2286
+ }
2287
+ }
2288
+ // Check failed
2289
+ {
2290
+ const env_9 = { stack: [], error: void 0, hasError: false };
2291
+ try {
2292
+ const h = __addDisposableResource(env_9, vm.evalCode('globalThis.__workflowError'), false);
2293
+ if (!h.isUndefined) {
2294
+ // The display fields are plain strings; the thrown value itself is
2295
+ // RAW and serialized host-side through a handle.
2296
+ const errorObj = h.isString
2297
+ ? h.toString()
2298
+ : (() => {
2299
+ const env_12 = { stack: [], error: void 0, hasError: false };
2300
+ try {
2301
+ const plain = __addDisposableResource(env_12, vm.evalCode('(function(e){return {message: e.message, stack: e.stack, name: e.name};})(globalThis.__workflowError)'), false);
2302
+ return vm.dump(plain);
2303
+ }
2304
+ catch (e_12) {
2305
+ env_12.error = e_12;
2306
+ env_12.hasError = true;
2307
+ }
2308
+ finally {
2309
+ __disposeResources(env_12);
2310
+ }
2311
+ })();
2312
+ let valueBytes;
2313
+ if (!h.isString) {
2314
+ const env_10 = { stack: [], error: void 0, hasError: false };
2315
+ try {
2316
+ const rawValue = __addDisposableResource(env_10, h.getProp('value'), false);
2317
+ try {
2318
+ valueBytes = serde.serialize(rawValue);
2319
+ }
2320
+ catch (serializeErr) {
2321
+ // A thrown value the codec cannot serialize must not mask the
2322
+ // workflow failure itself, so fall back to the display fields.
2323
+ runtimeLogger.warn('QuickJS runtime: failed to serialize thrown workflow error', {
2324
+ message: serializeErr instanceof Error
2325
+ ? serializeErr.message
2326
+ : String(serializeErr),
2327
+ });
2328
+ }
2329
+ }
2330
+ catch (e_9) {
2331
+ env_10.error = e_9;
2332
+ env_10.hasError = true;
2333
+ }
2334
+ finally {
2335
+ __disposeResources(env_10);
2336
+ }
2337
+ }
2338
+ const failed = typeof errorObj === 'string'
2339
+ ? { message: errorObj }
2340
+ : {
2341
+ message: errorObj.message,
2342
+ stack: errorObj.stack || undefined,
2343
+ name: errorObj.name || undefined,
2344
+ valueBytes,
2345
+ };
2346
+ runtimeLogger.error('QuickJS runtime: workflow failed in VM', {
2347
+ errorMessage: failed.message,
2348
+ errorName: failed.name,
2349
+ errorStack: failed.stack,
2350
+ });
2351
+ const drainOperations = collectDrainOperations(vm, serde);
2352
+ vm.dispose();
2353
+ return {
2354
+ failed: {
2355
+ ...failed,
2356
+ ...(drainOperations.length > 0 ? { drainOperations } : {}),
2357
+ },
2358
+ };
2359
+ }
2360
+ }
2361
+ catch (e_10) {
2362
+ env_9.error = e_10;
2363
+ env_9.hasError = true;
2364
+ }
2365
+ finally {
2366
+ __disposeResources(env_9);
2367
+ }
2368
+ }
2369
+ // Check suspended: the workflow is suspended if there are active resolvers
2370
+ // OR pending operations that haven't been created yet (e.g. hooks created
2371
+ // upfront but not yet awaited)
2372
+ {
2373
+ const env_11 = { stack: [], error: void 0, hasError: false };
2374
+ try {
2375
+ const h = __addDisposableResource(env_11, vm.evalCode('Object.keys(globalThis.__resolvers).length > 0 || globalThis.__pending.some(function(p){return!p.hasCreatedEvent;})'), false);
2376
+ if (vm.dump(h)) {
2377
+ // Ops with an active resolver or without a created event are
2378
+ // pending; abort-requested hooks are also surfaced (even when
2379
+ // already created and unawaited) so the host records the abort.
2380
+ const pendingOps = dumpPendingOps(vm, serde, `globalThis.__pending.filter(function(p){return!!globalThis.__resolvers[p.correlationId] || !p.hasCreatedEvent || p.abortRequested;})`, ensurePendingByteCache(vm));
2381
+ if (!opts.keepAliveOnSuspend)
2382
+ vm.dispose();
2383
+ return {
2384
+ suspended: {
2385
+ pendingOperations: pendingOps,
2386
+ },
2387
+ };
2388
+ }
2389
+ }
2390
+ catch (e_11) {
2391
+ env_11.error = e_11;
2392
+ env_11.hasError = true;
2393
+ }
2394
+ finally {
2395
+ __disposeResources(env_11);
2396
+ }
2397
+ }
2398
+ vm.dispose();
2399
+ return { failed: { message: 'Workflow ended in unknown state' } };
2400
+ }
2401
+ // ---- Helpers ----
2402
+ function extractError(vm, err, fallbackMessage) {
2403
+ let message = fallbackMessage;
2404
+ let stack;
2405
+ let name;
2406
+ if (err instanceof JSException) {
2407
+ const error = vm.dump(err.handle);
2408
+ err.handle.dispose();
2409
+ message = error?.message ?? err.message ?? fallbackMessage;
2410
+ stack = error?.stack ?? err.stack;
2411
+ name = error?.name ?? err.name;
2412
+ }
2413
+ else if (err instanceof Error) {
2414
+ message = err.message ?? fallbackMessage;
2415
+ stack = err.stack;
2416
+ name = err.name;
2417
+ }
2418
+ vm.dispose();
2419
+ return {
2420
+ failed: { message, stack, name },
2421
+ };
2422
+ }
2423
+ function createInterruptHandler(budget) {
2424
+ const timeout = getReplayTimeoutMs();
2425
+ return () => Date.now() - budget.start > timeout;
2426
+ }
2427
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVpY2tqcy1ydW50aW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvcXVpY2tqcy1ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTZCRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDbEQsT0FBTyxFQUVMLGlCQUFpQixHQUlsQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQ2pDLE9BQU8sRUFFTCxXQUFXLEVBQ1gsT0FBTyxHQUdSLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sVUFBVSxNQUFNLFlBQVksQ0FBQztBQUNwQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3RFLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsZ0NBQWdDLEdBQ2pDLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLFdBQVcsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQy9FLE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLGtCQUFrQixFQUNsQixlQUFlLEdBRWhCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLGNB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ZSxDQUFDO0lBQzlCLElBQUksS0FBeUIsQ0FBQztJQUM5QixJQUFJLElBQXdCLENBQUM7SUFFN0IsSUFBSSxHQUFHLFlBQVksV0FBVyxFQUFFLENBQUM7UUFDL0IsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFtQyxDQUFDO1FBQ3BFLEdBQUcsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDckIsT0FBTyxHQUFJLEtBQUssRUFBRSxPQUFrQixJQUFJLEdBQUcsQ0FBQyxPQUFPLElBQUksZUFBZSxDQUFDO1FBQ3ZFLEtBQUssR0FBSSxLQUFLLEVBQUUsS0FBZ0IsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDO1FBQzlDLElBQUksR0FBSSxLQUFLLEVBQUUsSUFBZSxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUM7SUFDN0MsQ0FBQztTQUFNLElBQUksR0FBRyxZQUFZLEtBQUssRUFBRSxDQUFDO1FBQ2hDLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxJQUFJLGVBQWUsQ0FBQztRQUN6QyxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQztRQUNsQixJQUFJLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztJQUNsQixDQUFDO0lBRUQsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2IsT0FBTztRQUNMLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO0tBQ2pDLENBQUM7QUFDSixDQUFDO0FBcUJELFNBQVMsc0JBQXNCLENBQUMsTUFBdUI7SUFDckQsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLEVBQUUsQ0FBQztJQUNyQyxPQUFPLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQztBQUNuRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBRdWlja0pTIFdlYkFzc2VtYmx5IChXQVNNKSB3b3JrZmxvdyBWTS5cbiAqXG4gKiBBbiBhbHRlcm5hdGl2ZSBlbmdpbmUgZm9yIHRoZSBldmVudC1yZXBsYXkgZXhlY3V0aW9uIG1vZGVsOiB0aGUgd29ya2Zsb3dcbiAqIGNvZGUgcnVucyBpbnNpZGUgYSBRdWlja0pTIFdBU00gVk0gKHZpYSBxdWlja2pzLXdhc2kpIGluc3RlYWQgb2YgYVxuICogYG5vZGU6dm1gIGNvbnRleHQuIEV2ZXJ5IGludm9jYXRpb24gY3JlYXRlcyBhIGZyZXNoIFZNLCByZS1leGVjdXRlcyB0aGVcbiAqIHdvcmtmbG93IGZ1bmN0aW9uIGZyb20gdGhlIHRvcCwgYW5kIHJlcGxheXMgdGhlIHJlY29yZGVkIGV2ZW50IGxvZyB0b1xuICogcmVzb2x2ZSBhd2FpdGVkIHByaW1pdGl2ZXM6IHRoZSBzYW1lIHJlcGxheSBzZW1hbnRpY3MgYXMgdGhlIGBub2RlOnZtYFxuICogZW5naW5lLlxuICpcbiAqIFRoZSB3b3JrZmxvdyBwcmltaXRpdmVzICh1c2VTdGVwLCBzbGVlcCwgY3JlYXRlSG9vaykgYXJlIGltcGxlbWVudGVkIGFzXG4gKiBKYXZhU2NyaXB0IGNvZGUgcnVubmluZyBpbnNpZGUgdGhlIFF1aWNrSlMgVk0uIFRoZSBob3N0IGNvbW11bmljYXRlcyB3aXRoXG4gKiB0aGUgVk0gYnkgZXZhbHVhdGluZyBzbWFsbCBKUyBzbmlwcGV0cyB0byByZWFkIHBlbmRpbmcgb3BlcmF0aW9ucyBhbmRcbiAqIHJlc29sdmUvcmVqZWN0IHByb21pc2VzLlxuICpcbiAqIFRoZSBWTSBib290c3RyYXAgaXMgZGVsaWJlcmF0ZWx5IHNwbGl0IGludG8gdHdvIHBoYXNlczpcbiAqICAgMS4gU3RhdGljIGluaXRpYWxpemF0aW9uIChgaW5pdFdvcmtmbG93Vk1gKTogcnVuLWluZGVwZW5kZW50IHNldHVwOlxuICogICAgICBWTSBjcmVhdGlvbiBhbmQgdGhlIHdvcmtmbG93IHByaW1pdGl2ZXMuIChTZXJpYWxpemF0aW9uIGxpdmVzIG9uXG4gKiAgICAgIHRoZSBob3N0IChzZWUgcXVpY2tqcy1zZXJkZS50cykgc28gbm8gc2VyZGUgY29kZSBpcyBldmFsdWF0ZWRcbiAqICAgICAgaW4gdGhlIFZNLilcbiAqICAgMi4gUGVyLXJ1biBpbml0aWFsaXphdGlvbiAoaW5saW5lIGluIGBydW5RdWlja0pTV29ya2Zsb3dgKTogc2VlZGVkXG4gKiAgICAgIFBSTkcvVUxJRCBob3N0IGZ1bmN0aW9ucywgd29ya2Zsb3cgYnVuZGxlIGV2YWx1YXRpb24sIHJ1biBtZXRhZGF0YSxcbiAqICAgICAgd29ya2Zsb3cgaW5wdXQsIGFuZCBzdGFydC5cbiAqIEtlZXBpbmcgdGhlIHBoYXNlcyBzZXBhcmF0ZSBpcyBncm91bmR3b3JrIGZvciBWTS1tZW1vcnkgc25hcHNob3R0aW5nOlxuICogYSBmb2xsb3ctdXAgY2FuIHBlcnNpc3QvcmVzdG9yZSB0aGUgVk0gYXQgdGhlIHBoYXNlIGJvdW5kYXJ5IChlLmcuIGFcbiAqIGJ1aWxkLXRpbWUgaW5pdGlhbCBzbmFwc2hvdCkgd2l0aG91dCByZXN0cnVjdHVyaW5nIHRoaXMgbW9kdWxlLiBOb3RlXG4gKiB0aGF0IGJ1bmRsZSBldmFsdWF0aW9uIGN1cnJlbnRseSBzaXRzIGluIHRoZSBwZXItcnVuIHBoYXNlIHNvIHRoYXRcbiAqIG1vZHVsZS1zY29wZSB1c2VyIGNvZGUgb2JzZXJ2ZXMgdGhlIHNlZWRlZCBgTWF0aC5yYW5kb21gLCBtYXRjaGluZyB0aGVcbiAqIGBub2RlOnZtYCBlbmdpbmUncyByZXBsYXkgZGV0ZXJtaW5pc20uXG4gKi9cblxuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgeyBnbG9iYWxTaW5nbGV0b24gfSBmcm9tICdAd29ya2Zsb3cvdXRpbHMnO1xuaW1wb3J0IHtcbiAgdHlwZSBFdmVudCxcbiAgaXNTZWFsZWROb29wRXZlbnQsXG4gIHR5cGUgUnVuSW5wdXQsXG4gIHR5cGUgV29ya2Zsb3dSdW4sXG4gIHR5cGUgV29ybGRDYXBhYmlsaXRpZXMsXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgKiBhcyBuYW5vaWQgZnJvbSAnbmFub2lkJztcbmltcG9ydCB7XG4gIHR5cGUgRXh0ZW5zaW9uRGVzY3JpcHRvcixcbiAgSlNFeGNlcHRpb24sXG4gIFF1aWNrSlMsXG4gIHR5cGUgU25hcHNob3QsXG4gIHR5cGUgV2FzaU9wdGlvbnMsXG59IGZyb20gJ3F1aWNranMtd2FzaSc7XG5pbXBvcnQgc2VlZHJhbmRvbSBmcm9tICdzZWVkcmFuZG9tJztcbmltcG9ydCB7IG1vbm90b25pY0ZhY3RvcnkgfSBmcm9tICd1bGlkJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZGVjb21wcmVzcyB9IGZyb20gJy4uL3NlcmlhbGl6YXRpb24vY29tcHJlc3Npb24uanMnO1xuaW1wb3J0IHR5cGUgeyBEZWNyeXB0aW9uS2V5IH0gZnJvbSAnLi4vc2VyaWFsaXphdGlvbi9lbmNyeXB0aW9uLmpzJztcbmltcG9ydCB7IGRlY3J5cHQgfSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHsgZm9ybWF0U2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSAnLi4vc2VyaWFsaXphdGlvbi9lcnJvcnMuanMnO1xuaW1wb3J0IHtcbiAgZ2V0UmVwbGF5VGltZW91dE1zLFxuICBpc1F1aWNrSlNCYXNlbGluZVNuYXBzaG90RW5hYmxlZCxcbn0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgcXVpY2tqc0V4dGVuc2lvbnMsIHF1aWNranNXYXNtIH0gZnJvbSAnLi9xdWlja2pzLWFzc2V0cy5nZW5lcmF0ZWQuanMnO1xuaW1wb3J0IHtcbiAgYWRvcHRTZXJkZVJvb3QsXG4gIGNhcHR1cmVTZXJkZVJvb3QsXG4gIGNyZWF0ZVF1aWNrSlNTZXJkZSxcbiAgZXhwb3J0U2VyZGVSb290LFxuICB0eXBlIFF1aWNrSlNTZXJkZSxcbn0gZnJvbSAnLi9xdWlja2pzLXNlcmRlLmpzJztcbmltcG9ydCB7IHJ1bklkQ3JlYXRlZEF0IH0gZnJvbSAnLi9ydW4taWQtdGltZS5qcyc7XG5cbi8vIC0tLS0gSG9zdCAtPiBWTSBwYXlsb2FkIHByZXBhcmF0aW9uIC0tLS1cblxuLyoqXG4gKiBQcmVwYXJlIHBlcnNpc3RlZCBwYXlsb2FkIGJ5dGVzIGZvciBjb25zdW1wdGlvbiBpbnNpZGUgdGhlIFZNOiBkZWNyeXB0XG4gKiAod2hlbiBhbiBlbmNyeXB0aW9uIGtleSBpcyBjb25maWd1cmVkKSBhbmQgZGVjb21wcmVzcyAoc3BlY1ZlcnNpb24gPj0gNVxuICogcGF5bG9hZHMgbWF5IGJlIGd6aXAvenN0ZC1jb21wcmVzc2VkKS4gVGhlIFZNIG9ubHkgdW5kZXJzdGFuZHMgcGxhaW5cbiAqIGZvcm1hdC1wcmVmaXhlZCAnZGV2bCcgYnl0ZXM6IGl0IGhhcyBuZWl0aGVyIHRoZSBrZXkgbWF0ZXJpYWwgbm9yIHpsaWIuXG4gKiBUaGUga2V5IGlzIHRoZSBydW4ncyBmdWxsIERlY3J5cHRpb25LZXkgY2FwYWJpbGl0eSAoc3ltbWV0cmljIEFFUyBrZXkgK1xuICogWDI1NTE5IGtleXBhaXIpIHNvIHNlYWxlZCBgZW5jcGAgaG9vayBwYXlsb2FkcyBmcm9tIGNyb3NzLWRlcGxveW1lbnRcbiAqIHJlc3VtZUhvb2soKSBjYWxscyBvcGVuIGhlcmUgdG9vLCBub3QganVzdCBzeW1tZXRyaWMgYGVuY3JgIG9uZXMuXG4gKiBCb3RoIHN0YWdlcyBhcmUgZm9ybWF0LXByZWZpeCBkaXNwYXRjaGVkLCBzbyBwbGFpbnRleHQvdW5jb21wcmVzc2VkXG4gKiBkYXRhIHBhc3NlcyB0aHJvdWdoIHVuY2hhbmdlZC4gTWlycm9ycyBgcHJlcGFyZVJlcGxheVBheWxvYWRgIGluXG4gKiBzZXJpYWxpemF0aW9uLnRzICh0aGUgbm9kZTp2bSBlbmdpbmUncyBlcXVpdmFsZW50IGhvc3Qtc2lkZSBzdGFnZSkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHByZXBhcmVCeXRlc0ZvclZNKFxuICBkYXRhOiBVaW50OEFycmF5LFxuICBrZXk/OiBEZWNyeXB0aW9uS2V5XG4pOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgcmV0dXJuIChhd2FpdCBkZWNvbXByZXNzKGF3YWl0IGRlY3J5cHQoZGF0YSwga2V5KSkpIGFzIFVpbnQ4QXJyYXk7XG59XG5cbi8vIC0tLS0gVHlwZXMgLS0tLVxuXG5leHBvcnQgaW50ZXJmYWNlIFBlbmRpbmdTdGVwIHtcbiAgdHlwZTogJ3N0ZXAnO1xuICBjb3JyZWxhdGlvbklkOiBzdHJpbmc7XG4gIHN0ZXBJZDogc3RyaW5nO1xuICAvKipcbiAgICogRm9ybWF0LXByZWZpeGVkIGRldmFsdWUtc2VyaWFsaXplZCBzdGVwIGlucHV0IChhcmdzICsgY2xvc3VyZVZhcnMpLlxuICAgKiBBYnNlbnQgd2hlbiB7QGxpbmsgc2VyaWFsaXphdGlvbkVycm9yfSBpcyBzZXQ6IHRoZSBpbnB1dCBpcyBwcmVjaXNlbHlcbiAgICogd2hhdCByZWZ1c2VkIHRvIHNlcmlhbGl6ZS5cbiAgICovXG4gIGlucHV0PzogVWludDhBcnJheTtcbiAgLyoqIFdoZXRoZXIgYSBzdGVwX2NyZWF0ZWQgZXZlbnQgYWxyZWFkeSBleGlzdHMgZm9yIHRoaXMgc3RlcCAqL1xuICBoYXNDcmVhdGVkRXZlbnQ6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTZXQgd2hlbiBob3N0LXNpZGUgc2VyaWFsaXphdGlvbiBvZiB0aGUgc3RlcCdzIHJhdyBpbnB1dCBmYWlsZWQgd2hpbGVcbiAgICogZHVtcGluZyB0aGUgVk0ncyBwZW5kaW5nIG9wcyAoc2VlIGBkdW1wUGVuZGluZ09wc2ApLiBUaGUgZmFpbHVyZSBpc1xuICAgKiBkZXRlcm1pbmlzdGljIChyZXBsYXlpbmcgcmUtZGVyaXZlcyB0aGUgc2FtZSB1bnNlcmlhbGl6YWJsZSB2YWx1ZSksIHNvXG4gICAqIGluc3RlYWQgb2YgZmFpbGluZyB0aGUgd2hvbGUgY29sbGVjdGlvbiB0aGUgb3AgaXMgc3VyZmFjZWQgd2l0aCB0aGVcbiAgICogcmVmcmFtZWQgZXJyb3IgYW5kIG5vIGBpbnB1dGA7IHRoZSBlbnRyeXBvaW50IGZpbmFsaXplcyB0aGUgc3RlcCBhc1xuICAgKiBgc3RlcF9jcmVhdGVkYCAocGxhY2Vob2xkZXIgaW5wdXQpICsgYHN0ZXBfZmFpbGVkYCwgbWlycm9yaW5nIHRoZVxuICAgKiBub2RlOnZtIGVuZ2luZSdzIGBmaW5hbGl6ZVVuc2VyaWFsaXphYmxlU3RlcGAsIHNvIGEgdHJ5L2NhdGNoIGFyb3VuZFxuICAgKiB0aGUgc3RlcCBjYWxsIG9ic2VydmVzIHRoZSBTZXJpYWxpemF0aW9uRXJyb3IuXG4gICAqL1xuICBzZXJpYWxpemF0aW9uRXJyb3I/OiBTZXJpYWxpemF0aW9uRXJyb3I7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGVuZGluZ1dhaXQge1xuICB0eXBlOiAnd2FpdCc7XG4gIGNvcnJlbGF0aW9uSWQ6IHN0cmluZztcbiAgLyoqIElTTyBzdHJpbmcgb2Ygd2hlbiB0byByZXN1bWUgKi9cbiAgcmVzdW1lQXQ6IHN0cmluZztcbiAgLyoqIFdoZXRoZXIgYSB3YWl0X2NyZWF0ZWQgZXZlbnQgYWxyZWFkeSBleGlzdHMgZm9yIHRoaXMgd2FpdCAqL1xuICBoYXNDcmVhdGVkRXZlbnQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGVuZGluZ0hvb2sge1xuICB0eXBlOiAnaG9vayc7XG4gIGNvcnJlbGF0aW9uSWQ6IHN0cmluZztcbiAgdG9rZW46IHN0cmluZztcbiAgLyoqIEVhcmxpZXN0IHRva2VuIHJldXNlIHRpbWUsIGFzIG1pbGxpc2Vjb25kcyBzaW5jZSB0aGUgVW5peCBlcG9jaC4gKi9cbiAgdG9rZW5SZXRlbnRpb25VbnRpbD86IG51bWJlcjtcbiAgaXNXZWJob29rOiBib29sZWFuO1xuICBtZXRhZGF0YT86IHVua25vd247XG4gIGhhc0NyZWF0ZWRFdmVudDogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFRydWUgZm9yIGludGVybmFsIHN5c3RlbSBob29rcyAoZS5nLiBBYm9ydENvbnRyb2xsZXIncyBob29rKSwgd2hpY2hcbiAgICogYXJlIGV4ZW1wdCBmcm9tIHVzZXItaG9vayB0b2tlbiBuYW1lc3BhY2UgY29uZmxpY3QgY2hlY2tzLlxuICAgKi9cbiAgaXNTeXN0ZW0/OiBib29sZWFuO1xuICAvKipcbiAgICogU2V0IHdoZW4gdGhlIHdvcmtmbG93IGNhbGxlZCBBYm9ydENvbnRyb2xsZXIuYWJvcnQoKSBkdXJpbmcgdGhpc1xuICAgKiBpbnZvY2F0aW9uLiBUaGUgaG9zdCBtdXN0IHJlY29yZCB0aGUgYWJvcnQ6IGNyZWF0ZSBhIGhvb2tfcmVjZWl2ZWRcbiAgICogZXZlbnQgY2FycnlpbmcgYGFib3J0UGF5bG9hZGAgYW5kIHdyaXRlL2Nsb3NlIHRoZSBhYm9ydCBzdHJlYW0uXG4gICAqL1xuICBhYm9ydFJlcXVlc3RlZD86IGJvb2xlYW47XG4gIC8qKiBWTS1zZXJpYWxpemVkIGB7IGFib3J0ZWQ6IHRydWUsIHJlYXNvbiB9YCBwYXlsb2FkIGZvciB0aGUgYWJvcnQuICovXG4gIGFib3J0UGF5bG9hZD86IFVpbnQ4QXJyYXk7XG4gIC8qKiBTZXQgYnkgdGhlIGNvbXBsZXRpb24gZHJhaW4gd2hlbiBhIHN5c3RlbSBob29rIGlzIGltcGxpY2l0bHkgZGlzcG9zZWQuICovXG4gIGRpc3Bvc2VkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFRydWUgd2hlbiB0aGUgd29ya2Zsb3cgaXMgYXdhaXRpbmcgaG9vay5nZXRDb25mbGljdCgpIGZvciB0aGlzIGhvb2suXG4gICAqIFRoZSBlbnRyeXBvaW50IHJlLWludm9rZXMgdGhlIHdvcmtmbG93IHJpZ2h0IGFmdGVyIHdyaXRpbmdcbiAgICogaG9va19jcmVhdGVkIHNvIHJlcGxheSBjYW4gY29uZmlybSBjcmVhdGlvbiBhbmQgcmVzb2x2ZSB0aGUgYXdhaXRlci5cbiAgICovXG4gIGhhc0dldENvbmZsaWN0QXdhaXRlcj86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGVuZGluZ0F0dHJpYnV0ZSB7XG4gIHR5cGU6ICdhdHRyaWJ1dGUnO1xuICBjb3JyZWxhdGlvbklkOiBzdHJpbmc7XG4gIC8qKiBOb3JtYWxpemVkIGF0dHJpYnV0ZSBjaGFuZ2VzIChwbGFpbiBKU09OLWFibGUgb2JqZWN0cykgKi9cbiAgY2hhbmdlczogdW5rbm93bltdO1xuICBhbGxvd1Jlc2VydmVkQXR0cmlidXRlcz86IGJvb2xlYW47XG4gIC8qKiBXaGV0aGVyIGFuIGF0dHJfc2V0IGV2ZW50IGFscmVhZHkgZXhpc3RzIGZvciB0aGlzIHdyaXRlICovXG4gIGhhc0NyZWF0ZWRFdmVudDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQZW5kaW5nSG9va0Rpc3Bvc2Uge1xuICB0eXBlOiAnaG9va19kaXNwb3NlJztcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nO1xuICAvKipcbiAgICogVG9rZW4gb2YgdGhlIGhvb2sgYmVpbmcgZGlzcG9zZWQuIFVzZWQgYnkgdGhlIGVudHJ5cG9pbnQgdG8gb3JkZXJcbiAgICogc2FtZS10b2tlbiBob29rIG9wZXJhdGlvbnMgc2VxdWVudGlhbGx5IGluIGNvZGUgb3JkZXIuXG4gICAqL1xuICB0b2tlbj86IHN0cmluZztcbiAgaGFzQ3JlYXRlZEV2ZW50OiBib29sZWFuO1xufVxuXG5leHBvcnQgdHlwZSBQZW5kaW5nT3BlcmF0aW9uID1cbiAgfCBQZW5kaW5nU3RlcFxuICB8IFBlbmRpbmdXYWl0XG4gIHwgUGVuZGluZ0hvb2tcbiAgfCBQZW5kaW5nQXR0cmlidXRlXG4gIHwgUGVuZGluZ0hvb2tEaXNwb3NlO1xuXG5leHBvcnQgaW50ZXJmYWNlIFF1aWNrSlNSdW50aW1lUmVzdWx0IHtcbiAgLyoqIFRoZSB3b3JrZmxvdyBjb21wbGV0ZWQ6IHJlc3VsdCBpcyBmb3JtYXQtcHJlZml4ZWQgZGV2YWx1ZSBieXRlcyAqL1xuICBjb21wbGV0ZWQ/OiB7XG4gICAgcmVzdWx0OiBVaW50OEFycmF5O1xuICAgIC8qKlxuICAgICAqIExlZnRvdmVyIHBlbmRpbmcgb3BlcmF0aW9ucyB0aGF0IHN0aWxsIG5lZWQgZHVyYWJsZSBzaWRlIGVmZmVjdHMgYXRcbiAgICAgKiBjb21wbGV0aW9uOiBhYm9ydCByZWNvcmRpbmdzLCBzeXN0ZW0taG9vayBkaXNwb3NhbHMsIGZpcmUtYW5kLWZvcmdldFxuICAgICAqIGF0dHJpYnV0ZS9ob29rL3N0ZXAgZXZlbnRzLiBNaXJyb3JzIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4gICAgICogZHJhaW5QZW5kaW5nUXVldWVJdGVtcy4gVGhlIGVudHJ5cG9pbnQgZGlzcGF0Y2hlcyB0aGVzZSBXSVRIT1VUXG4gICAgICogcXVldWVpbmcgc3RlcHMgb3IgcmVxdWV1aW5nIHRoZSBydW4uXG4gICAgICovXG4gICAgZHJhaW5PcGVyYXRpb25zPzogUGVuZGluZ09wZXJhdGlvbltdO1xuICB9O1xuICAvKiogVGhlIHdvcmtmbG93IHN1c3BlbmRlZCB3aXRoIHBlbmRpbmcgb3BlcmF0aW9ucyAqL1xuICBzdXNwZW5kZWQ/OiB7XG4gICAgcGVuZGluZ09wZXJhdGlvbnM6IFBlbmRpbmdPcGVyYXRpb25bXTtcbiAgfTtcbiAgLyoqIFRoZSB3b3JrZmxvdyBmYWlsZWQgKi9cbiAgZmFpbGVkPzoge1xuICAgIG1lc3NhZ2U6IHN0cmluZztcbiAgICBzdGFjaz86IHN0cmluZztcbiAgICBuYW1lPzogc3RyaW5nO1xuICAgIC8qKiBTZWUgY29tcGxldGVkLmRyYWluT3BlcmF0aW9uczogc2FtZSBzZW1hbnRpY3Mgb24gZmFpbHVyZS4gKi9cbiAgICBkcmFpbk9wZXJhdGlvbnM/OiBQZW5kaW5nT3BlcmF0aW9uW107XG4gICAgLyoqXG4gICAgICogRm9ybWF0LXByZWZpeGVkIGRldmFsdWUgYnl0ZXMgb2YgdGhlIG9yaWdpbmFsIHRocm93biB2YWx1ZVxuICAgICAqIChFcnJvciBzdWJjbGFzcyB3aXRoIGNhdXNlIGNoYWluLCBwbGFpbiBvYmplY3QsIHByaW1pdGl2ZSwgZXRjLikuXG4gICAgICogU2V0IHdoZW4gdGhlIFZNLXNpZGUgcmVqZWN0aW9uIGhhbmRsZXIgc3VjY2Vzc2Z1bGx5IHNlcmlhbGl6ZXNcbiAgICAgKiB0aGUgdGhyb3duIHZhbHVlLiBUaGUgaG9zdCB1c2VzIHRoZXNlIGJ5dGVzIHRvIHJlY29uc3RydWN0IHRoZVxuICAgICAqIG9yaWdpbmFsIHZhbHVlIHRocm91Z2ggdGhlIHN0YW5kYXJkIGVycm9yIGh5ZHJhdGlvbiBwaXBlbGluZSxcbiAgICAgKiBwcmVzZXJ2aW5nIHR5cGUgaWRlbnRpdHkgKFR5cGVFcnJvciwgRmF0YWxFcnJvcikgYW5kIG5vbi1FcnJvclxuICAgICAqIHRocm93cyB2ZXJiYXRpbS4gRmFsbHMgYmFjayB0byB0aGUgbWVzc2FnZS9zdGFjay9uYW1lIGZpZWxkc1xuICAgICAqIHdoZW4gdGhpcyBpcyB1bmRlZmluZWQgKGUuZy4gZXh0cmFjdEVycm9yIHBzZXVkby1mYWlsdXJlcykuXG4gICAgICovXG4gICAgdmFsdWVCeXRlcz86IFVpbnQ4QXJyYXk7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUXVpY2tKU1J1bnRpbWVPcHRpb25zIHtcbiAgLyoqIFRoZSBjb21waWxlZCB3b3JrZmxvdyBidW5kbGUgY29kZSAod29ya2Zsb3cgbW9kZSBvdXRwdXQgZnJvbSBTV0MpICovXG4gIHdvcmtmbG93Q29kZTogc3RyaW5nO1xuICAvKiogVGhlIHdvcmtmbG93IElEIChlLmcuIFwid29ya2Zsb3cvLy4vd29ya2Zsb3dzLzFfc2ltcGxlLy9zaW1wbGVcIikgKi9cbiAgd29ya2Zsb3dJZDogc3RyaW5nO1xuICAvKiogVGhlIHdvcmtmbG93IHJ1biBlbnRpdHkgKi9cbiAgd29ya2Zsb3dSdW46IFdvcmtmbG93UnVuO1xuICAvKiogRmVhdHVyZXMgc3VwcG9ydGVkIGJ5IHRoZSBXb3JsZCBleGVjdXRpbmcgdGhpcyB3b3JrZmxvdy4gKi9cbiAgd29ybGRDYXBhYmlsaXRpZXM/OiBXb3JsZENhcGFiaWxpdGllcztcbiAgLyoqXG4gICAqIFRoZSBmdWxsIGV2ZW50IGxvZyBmb3IgdGhlIHJ1bi4gRXZlcnkgaW52b2NhdGlvbiByZXBsYXlzIHRoZSBjb21wbGV0ZVxuICAgKiBsb2cgZnJvbSB0aGUgc3RhcnQgKHNhbWUgcmVwbGF5IHNlbWFudGljcyBhcyB0aGUgYG5vZGU6dm1gIGVuZ2luZSkuXG4gICAqL1xuICBldmVudHM6IEV2ZW50W107XG4gIC8qKiBFbmNyeXB0aW9uIGtleSBmb3IgZGVjcnlwdGluZyBldmVudCBwYXlsb2FkcyAodW5kZWZpbmVkIGlmIHVuZW5jcnlwdGVkKSAqL1xuICBlbmNyeXB0aW9uS2V5PzogRGVjcnlwdGlvbktleTtcbiAgLyoqXG4gICAqIFRoZSBsb2NhbCBwb3J0IHRoZSB3b3JrZmxvdyBzZXJ2ZXIgaXMgbGlzdGVuaW5nIG9uLCB1c2VkIHRvIHBvcHVsYXRlXG4gICAqIGB3b3JrZmxvd01ldGFkYXRhLnVybGAuIFJlc29sdmVkIGF0IGNhbGwgdGltZSBvbiB0aGUgaG9zdCBzaWRlIHNvIHRoZVxuICAgKiBWTSBkb2Vzbid0IGhhdmUgdG8gcHJvYmUgdGhlIGZpbGVzeXN0ZW0uIElnbm9yZWQgb24gVmVyY2VsLCB3aGVyZVxuICAgKiBWRVJDRUxfVVJMIHRha2VzIHByZWNlZGVuY2UuXG4gICAqL1xuICBwb3J0PzogbnVtYmVyO1xuICAvKipcbiAgICogRmFsbGJhY2sgd29ya2Zsb3cgaW5wdXQgZnJvbSB0aGUgcXVldWUgbWVzc2FnZSdzIHJlc2lsaWVudC1zdGFydFxuICAgKiBwYXlsb2FkLiBVc2VkIHdoZW4gdGhlIGZldGNoZWQgZXZlbnQgbG9nIGxhY2tzIGEgYHJ1bl9jcmVhdGVkYCBldmVudFxuICAgKiAoZXZlbnR1YWxseS1jb25zaXN0ZW50IHJlYWQgYWZ0ZXIgdGhlIHBhcmVudCdzIHN0YXJ0KCkgd3JvdGUgaXQpLlxuICAgKi9cbiAgcnVuSW5wdXQ/OiBSdW5JbnB1dDtcbn1cblxuLy8gLS0tLSBWTSBCb290c3RyYXAgQ29kZSAtLS0tXG5cbi8qKlxuICogSmF2YVNjcmlwdCBjb2RlIHRoYXQgcnVucyBpbnNpZGUgdGhlIFF1aWNrSlMgVk0gdG8gc2V0IHVwIHRoZSB3b3JrZmxvd1xuICogcHJpbWl0aXZlcy4gVGhpcyBzZXRzIHVwOlxuICogLSBnbG9iYWxUaGlzLl9fcHJpdmF0ZV93b3JrZmxvd3MgKE1hcCkgLSB3b3JrZmxvdyByZWdpc3RyeVxuICogLSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzIChPYmplY3QpIC0gcGVuZGluZyBwcm9taXNlIHJlc29sdmUvcmVqZWN0IGZ1bmN0aW9uc1xuICogLSBnbG9iYWxUaGlzLl9fcGVuZGluZyAoQXJyYXkpIC0gbWV0YWRhdGEgYWJvdXQgcGVuZGluZyBvcGVyYXRpb25zXG4gKiAtIGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1VTRV9TVEVQXCIpXSAtIHN0ZXAgcHJveHkgZmFjdG9yeVxuICogLSBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19TTEVFUFwiKV0gLSBzbGVlcCBmdW5jdGlvblxuICovXG5jb25zdCBWTV9CT09UU1RSQVAgPSBgXG4vLyBTeW1ib2wuZGlzcG9zZSAvIFN5bWJvbC5hc3luY0Rpc3Bvc2UgcG9seWZpbGxzIGZvciBRdWlja0pTXG5pZiAodHlwZW9mIFN5bWJvbC5kaXNwb3NlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gIFN5bWJvbC5kaXNwb3NlID0gU3ltYm9sLmZvcihcIlN5bWJvbC5kaXNwb3NlXCIpO1xufVxuaWYgKHR5cGVvZiBTeW1ib2wuYXN5bmNEaXNwb3NlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gIFN5bWJvbC5hc3luY0Rpc3Bvc2UgPSBTeW1ib2wuZm9yKFwiU3ltYm9sLmFzeW5jRGlzcG9zZVwiKTtcbn1cblxuZ2xvYmFsVGhpcy5fX3ByaXZhdGVfd29ya2Zsb3dzID0gbmV3IE1hcCgpO1xuZ2xvYmFsVGhpcy5fX3Jlc29sdmVycyA9IHt9O1xuZ2xvYmFsVGhpcy5fX3BlbmRpbmcgPSBbXTtcbmdsb2JhbFRoaXMuX193b3JrZmxvd1Jlc3VsdCA9IHVuZGVmaW5lZDtcbmdsb2JhbFRoaXMuX193b3JrZmxvd0Vycm9yID0gdW5kZWZpbmVkO1xuLy8gQnVmZmVyIGZvciBob29rX3JlY2VpdmVkIHBheWxvYWRzIHRoYXQgYXJyaXZlIGJlZm9yZSB0aGUgaG9vayBpcyBhd2FpdGVkLlxuLy8gS2V5ZWQgYnkgY29ycmVsYXRpb25JZCDihpIgYXJyYXkgb2YgcGF5bG9hZHMgKHByZXNlcnZlcyBkZWxpdmVyeSBvcmRlcikuXG4vLyBUaGlzIG1pcnJvcnMgdGhlIGV2ZW50LXJlcGxheSBydW50aW1lJ3MgcGF5bG9hZHNRdWV1ZSBpbiBob29rLnRzLlxuZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyID0ge307XG5cbi8vIEJ1ZmZlciBmb3Igc3RlcC93YWl0L2F0dHIgdGVybWluYWwgb3V0Y29tZXMgdGhhdCBhcnJpdmUgYmVmb3JlIHRoaXMgVk1cbi8vIGhhcyBjb25zdHJ1Y3RlZCB0aGUgY29ycmVzcG9uZGluZyBhd2FpdGluZyBwcm9taXNlLiBJbiBmcmVzaC1WTSByZXBsYXlcbi8vIHRoZSBtdWx0aS1wYXNzIGV2ZW50IHNjYW4gbWFrZXMgdGhpcyB1bnJlYWNoYWJsZSAoYXdhaXRzIGFyZVxuLy8gcmVjb25zdHJ1Y3RlZCBiZWZvcmUgdGhlaXIgdGVybWluYWxzIGFyZSByZS1zY2FubmVkKSwgYnV0IHRoZSBsaXZlXG4vLyBjb250aW51YXRpb24gcGF0aCAoY29udGludWVXaXRoRXZlbnRzKSBzY2FucyBlYWNoIGRlbHRhIGV4YWN0bHkgb25jZSDigJRcbi8vIGEgY29uY3VycmVudCBpbnZvY2F0aW9uJ3MgdGVybWluYWwgYXJyaXZpbmcgYmVmb3JlIHRoaXMgVk0gcmVhY2hlcyB0aGVcbi8vIGF3YWl0IHdvdWxkIG90aGVyd2lzZSBiZSBkcm9wcGVkIG9uIHRoZSBmbG9vciBhbmQgdGhlIGF3YWl0IHdvdWxkXG4vLyBuZXZlciBzZXR0bGUgKHRoZSBmZWVkJ3Mgc2Vlbi1zZXQgbWVhbnMgaXQgaXMgbmV2ZXIgcmUtZGVsaXZlcmVkKS5cbi8vIE1pcnJvcnMgX19ob29rUGF5bG9hZEJ1ZmZlciwgd2hpY2ggZXhpc3RzIGZvciBleGFjdGx5IHRoaXMgcmVhc29uIG9uXG4vLyB0aGUgaG9vayBwYXRoLiBLZXllZCBieSBjb3JyZWxhdGlvbklkIOKGkiBzaW5nbGUgdGVybWluYWwgKHN0ZXBzLCB3YWl0c1xuLy8gYW5kIGF0dHJzIHNldHRsZSBleGFjdGx5IG9uY2UpLlxuZ2xvYmFsVGhpcy5fX3Rlcm1pbmFsQnVmZmVyID0ge307XG5cbi8vIFJlZ2lzdGVycyBhIHJlc29sdmVyIGZvciBhbiBhd2FpdGVkIHByaW1pdGl2ZSwgZmlyc3QgZHJhaW5pbmcgYW55XG4vLyBidWZmZXJlZCB0ZXJtaW5hbCByZWNvcmRlZCBmb3IgdGhlIGNvcnJlbGF0aW9uSWQuIEVudHJpZXMgYXJlIHByZXBhcmVkXG4vLyBob3N0LXNpZGU6IGJ5dGVzIGFyZSBkZWNyeXB0ZWQgQU5EIGRlc2VyaWFsaXplZCBpbnRvIFZNIHZhbHVlcyBieSB0aGVcbi8vIGhvc3Qgc2VyZGUgYmVmb3JlIGJ1ZmZlcmluZyAodGhlIFZNIGhhcyBubyBpbi1ndWVzdCBkZXNlcmlhbGl6ZXIgb25cbi8vIHRoZSBob3N0LXNlcmRlIGVuZ2luZSksIHNvIGRyYWluaW5nIG9ubHkgZm9yd2FyZHMgdGhlIHN0b3JlZCB2YWx1ZS5cbmdsb2JhbFRoaXMuX19yZWdpc3RlclJlc29sdmVyID0gZnVuY3Rpb24oY29ycmVsYXRpb25JZCwgcmVzb2x2ZSwgcmVqZWN0KSB7XG4gIHZhciBidWZmZXJlZCA9IGdsb2JhbFRoaXMuX190ZXJtaW5hbEJ1ZmZlcltjb3JyZWxhdGlvbklkXTtcbiAgaWYgKGJ1ZmZlcmVkKSB7XG4gICAgZGVsZXRlIGdsb2JhbFRoaXMuX190ZXJtaW5hbEJ1ZmZlcltjb3JyZWxhdGlvbklkXTtcbiAgICBpZiAoYnVmZmVyZWQua2luZCA9PT0gXCJyZXNvbHZlX3ZhbHVlXCIpIHtcbiAgICAgIHJlc29sdmUoYnVmZmVyZWQudmFsdWUpO1xuICAgIH0gZWxzZSBpZiAoYnVmZmVyZWQua2luZCA9PT0gXCJyZWplY3RfdmFsdWVcIikge1xuICAgICAgcmVqZWN0KGJ1ZmZlcmVkLnZhbHVlKTtcbiAgICB9IGVsc2UgaWYgKGJ1ZmZlcmVkLmtpbmQgPT09IFwicmVqZWN0X2Vycm9yXCIpIHtcbiAgICAgIHZhciBlID0gbmV3IEVycm9yKGJ1ZmZlcmVkLm1lc3NhZ2UpO1xuICAgICAgZS5uYW1lID0gXCJGYXRhbEVycm9yXCI7XG4gICAgICBlLmZhdGFsID0gdHJ1ZTtcbiAgICAgIGlmIChidWZmZXJlZC5zdGFjaykgZS5zdGFjayA9IGJ1ZmZlcmVkLnN0YWNrO1xuICAgICAgcmVqZWN0KGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXNvbHZlKHVuZGVmaW5lZCk7XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxuICBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NvcnJlbGF0aW9uSWRdID0geyByZXNvbHZlOiByZXNvbHZlLCByZWplY3Q6IHJlamVjdCB9O1xufTtcblxuLy8gU3R1YnMgZm9yIFdlYiBBUElzIHRoYXQgdGhlIHdvcmtmbG93IGJ1bmRsZSBtYXkgcmVmZXJlbmNlIGJ1dCBhcmUgbm90XG4vLyBhdmFpbGFibGUgaW4gUXVpY2tKUy4gTmF0aXZlIEMgZXh0ZW5zaW9ucyAoZW5jb2RpbmcsIGhlYWRlcnMsIHVybCxcbi8vIHN0cnVjdHVyZWQtY2xvbmUpIHByb3ZpZGUgdGhlIHJlYWwgaW1wbGVtZW50YXRpb25zOyB0aGVzZSBhcmUgbWluaW1hbFxuLy8gc3R1YnMgZm9yIEFQSXMgdGhhdCBkb24ndCBoYXZlIG5hdGl2ZSBleHRlbnNpb25zIHlldC4gKGJ0b2EvYXRvYiBhbmRcbi8vIHRoZSBVaW50OEFycmF5IGJhc2U2NC9oZXggbWV0aG9kcyBhcmUgYnVpbHQgaW50byBxdWlja2pzLXdhc2kgPj0gMy4pXG5cbmlmICh0eXBlb2YgUmVhZGFibGVTdHJlYW0gPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgLy8gTWluaW1hbCBSZWFkYWJsZVN0cmVhbSB0aGF0IHN0b3JlcyBib2R5IGRhdGEgZm9yIFJlc3BvbnNlLmpzb24oKS90ZXh0KClcbiAgZ2xvYmFsVGhpcy5SZWFkYWJsZVN0cmVhbSA9IGZ1bmN0aW9uKCkge307XG4gIGdsb2JhbFRoaXMuUmVhZGFibGVTdHJlYW0ucHJvdG90eXBlLl9fYm9keURhdGEgPSBudWxsO1xufVxuXG5pZiAodHlwZW9mIFdyaXRhYmxlU3RyZWFtID09PSBcInVuZGVmaW5lZFwiKSB7XG4gIGdsb2JhbFRoaXMuV3JpdGFibGVTdHJlYW0gPSBmdW5jdGlvbigpIHt9O1xufVxuXG5pZiAodHlwZW9mIFRyYW5zZm9ybVN0cmVhbSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICBnbG9iYWxUaGlzLlRyYW5zZm9ybVN0cmVhbSA9IGZ1bmN0aW9uKCkge307XG59XG5cbmlmICh0eXBlb2YgY29uc29sZSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICBnbG9iYWxUaGlzLmNvbnNvbGUgPSB7IGxvZzogZnVuY3Rpb24oKXt9LCBlcnJvcjogZnVuY3Rpb24oKXt9LCB3YXJuOiBmdW5jdGlvbigpe30sIGluZm86IGZ1bmN0aW9uKCl7fSB9O1xufVxuLy8gU3R1YiBleHBvcnRzL21vZHVsZSBmb3IgQ0pTIGJ1bmRsZSBmb3JtYXRcbmdsb2JhbFRoaXMuZXhwb3J0cyA9IHt9O1xuZ2xvYmFsVGhpcy5tb2R1bGUgPSB7IGV4cG9ydHM6IGdsb2JhbFRoaXMuZXhwb3J0cyB9O1xuLy8gTk9URTogVGV4dEVuY29kZXIvVGV4dERlY29kZXIgYXJlIHByb3ZpZGVkIGJ5IHRoZSBuYXRpdmUgZW5jb2RpbmcgZXh0ZW5zaW9uLlxuXG4vLyAtLS0tIERldGVybWluaXN0aWMgXFxgY3J5cHRvXFxgIChwYXJpdHkgd2l0aCB0aGUgbm9kZTp2bSBlbmdpbmUpIC0tLS1cbi8vIGdldFJhbmRvbVZhbHVlcyAvIHJhbmRvbVVVSUQgZHJhdyBmcm9tIE1hdGgucmFuZG9tLCB3aGljaCB0aGUgaG9zdFxuLy8gcmVwbGFjZXMgd2l0aCB0aGUgcnVuJ3Mgc2VlZGVkIFBSTkcgYmVmb3JlIGFueSB1c2VyIGNvZGUgcnVucyDigJQgc28gdGhlXG4vLyB2YWx1ZXMgcmVwbGF5IGRldGVybWluaXN0aWNhbGx5IGFuZCBtYXRjaCB0aGUgbm9kZSBlbmdpbmUsIHdob3NlXG4vLyBpbXBsZW1lbnRhdGlvbnMgZHJhdyBmcm9tIHRoZSBzYW1lIHNlZWRlZCBzZXF1ZW5jZSAoc2VlIHZtL2luZGV4LnRzKS5cbi8vIEV2ZXJ5IGNyeXB0by5zdWJ0bGUgbWV0aG9kIHRocm93cyB3aXRoIHRoZSBzYW1lIGd1aWRhbmNlIGFzIHRoZSBub2RlXG4vLyBlbmdpbmUncyBub24tcmVwbGF5YWJsZSBtZXRob2RzOyB1bmxpa2Ugbm9kZSwgXFxgZGlnZXN0XFxgIGlzIGFsc29cbi8vIHVuYXZhaWxhYmxlIGhlcmUgKG5vIG5hdGl2ZSBoYXNoIGluIHRoZSBWTSB5ZXQpLlxuKGZ1bmN0aW9uKCkge1xuICBmdW5jdGlvbiBnZXRSYW5kb21WYWx1ZXMoYXJyYXkpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBhcnJheVtpXSA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDI1Nik7XG4gICAgfVxuICAgIHJldHVybiBhcnJheTtcbiAgfVxuICAvLyBNaXJyb3JzIHZtL3V1aWQudHMgY3JlYXRlUmFuZG9tVVVJRDogaWRlbnRpY2FsIGRyYXcgcGF0dGVybiBmcm9tIHRoZVxuICAvLyBzZWVkZWQgUFJORywgc28gYm90aCBlbmdpbmVzIHByb2R1Y2UgdGhlIHNhbWUgVVVJRCBhdCB0aGUgc2FtZSBwb2ludFxuICAvLyBpbiBhIHJlcGxheS5cbiAgZnVuY3Rpb24gcmFuZG9tVVVJRCgpIHtcbiAgICB2YXIgY2hhcnMgPSBcIjAxMjM0NTY3ODlhYmNkZWZcIjtcbiAgICB2YXIgdXVpZCA9IFwiXCI7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAzNjsgaSsrKSB7XG4gICAgICBpZiAoaSA9PT0gOCB8fCBpID09PSAxMyB8fCBpID09PSAxOCB8fCBpID09PSAyMykge1xuICAgICAgICB1dWlkICs9IFwiLVwiO1xuICAgICAgfSBlbHNlIGlmIChpID09PSAxNCkge1xuICAgICAgICB1dWlkICs9IFwiNFwiO1xuICAgICAgfSBlbHNlIGlmIChpID09PSAxOSkge1xuICAgICAgICB1dWlkICs9IGNoYXJzW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDQpICsgOF07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1dWlkICs9IGNoYXJzW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDE2KV07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB1dWlkO1xuICB9XG4gIGZ1bmN0aW9uIHN1YnRsZVRocm93KG5hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgZXJyID0gbmV3IEVycm9yKFwiXFxgY3J5cHRvLnN1YnRsZS5cIiArIG5hbWUgKyBcIigpXFxgIGlzIG5vdCBhdmFpbGFibGUgaW5zaWRlIGEgd29ya2Zsb3cgZnVuY3Rpb24uIE1vdmUgaXQgdG8gYSBzdGVwIGZ1bmN0aW9uIHdoZXJlIGZ1bGwgTm9kZS5qcyBjcnlwdG8gaXMgYXZhaWxhYmxlLlwiKTtcbiAgICAgIGVyci5uYW1lID0gXCJXb3JrZmxvd1J1bnRpbWVFcnJvclwiO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH07XG4gIH1cbiAgdmFyIHN1YnRsZSA9IHt9O1xuICBbXCJlbmNyeXB0XCIsXCJkZWNyeXB0XCIsXCJzaWduXCIsXCJ2ZXJpZnlcIixcImRpZ2VzdFwiLFwiZ2VuZXJhdGVLZXlcIixcImRlcml2ZUtleVwiLFwiZGVyaXZlQml0c1wiLFwiaW1wb3J0S2V5XCIsXCJleHBvcnRLZXlcIixcIndyYXBLZXlcIixcInVud3JhcEtleVwiXS5mb3JFYWNoKGZ1bmN0aW9uKG0pIHtcbiAgICBzdWJ0bGVbbV0gPSBzdWJ0bGVUaHJvdyhtKTtcbiAgfSk7XG4gIGdsb2JhbFRoaXMuY3J5cHRvID0ge1xuICAgIGdldFJhbmRvbVZhbHVlczogZ2V0UmFuZG9tVmFsdWVzLFxuICAgIHJhbmRvbVVVSUQ6IHJhbmRvbVVVSUQsXG4gICAgc3VidGxlOiBzdWJ0bGUsXG4gIH07XG59KSgpO1xuXG4vLyAtLS0tIExvdWQgSW50bCAvIGxvY2FsZSBndWFyZHMgLS0tLVxuLy8gUXVpY2tKUyBoYXMgbm8gSUNVOiBcXGBJbnRsXFxgIGlzIGFic2VudCBhbmQgdG9Mb2NhbGVTdHJpbmctZmFtaWx5IG1ldGhvZHNcbi8vIHNpbGVudGx5IGlnbm9yZSB0aGVpciBsb2NhbGUgYXJndW1lbnQuIFNpbGVudCBkaXZlcmdlbmNlIGZyb20gdGhlIG5vZGVcbi8vIGVuZ2luZSB3b3VsZCB3cml0ZSBkaWZmZXJlbnQgdmFsdWVzIGludG8gYSBkdXJhYmxlIGV2ZW50IGxvZyB3aXRoIG5vXG4vLyBlcnJvciBhbnl3aGVyZSDigJQgc28gbWFrZSB0aGUgZ2FwIGxvdWQgaW5zdGVhZDogSW50bCBjb25zdHJ1Y3RvcnMgdGhyb3csXG4vLyBhbmQgdG9Mb2NhbGUqIG1ldGhvZHMgdGhyb3cgT05MWSB3aGVuIGNhbGxlZCB3aXRoIGFuIGV4cGxpY2l0IGxvY2FsZVxuLy8gKHRoZSBuby1hcmd1bWVudCBmb3JtcyBrZWVwIFF1aWNrSlMncyBkZWZhdWx0IGJlaGF2aW9yKS5cbihmdW5jdGlvbigpIHtcbiAgZnVuY3Rpb24gaW50bFRocm93KG5hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgZXJyID0gbmV3IEVycm9yKFwiXFxgSW50bC5cIiArIG5hbWUgKyBcIlxcYCBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBRdWlja0pTIHdvcmtmbG93IGVuZ2luZSAobm8gSUNVKS4gUGVyZm9ybSBsb2NhbGUtc2Vuc2l0aXZlIGZvcm1hdHRpbmcgaW4gYSBzdGVwIGZ1bmN0aW9uLCBvciB1c2UgV09SS0ZMT1dfVk09bm9kZS5cIik7XG4gICAgICBlcnIubmFtZSA9IFwiV29ya2Zsb3dSdW50aW1lRXJyb3JcIjtcbiAgICAgIHRocm93IGVycjtcbiAgICB9O1xuICB9XG4gIGlmICh0eXBlb2YgSW50bCA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgIHZhciBpbnRsID0ge307XG4gICAgW1wiQ29sbGF0b3JcIixcIkRhdGVUaW1lRm9ybWF0XCIsXCJEaXNwbGF5TmFtZXNcIixcIkR1cmF0aW9uRm9ybWF0XCIsXCJMaXN0Rm9ybWF0XCIsXCJMb2NhbGVcIixcIk51bWJlckZvcm1hdFwiLFwiUGx1cmFsUnVsZXNcIixcIlJlbGF0aXZlVGltZUZvcm1hdFwiLFwiU2VnbWVudGVyXCJdLmZvckVhY2goZnVuY3Rpb24obikge1xuICAgICAgaW50bFtuXSA9IGludGxUaHJvdyhuKTtcbiAgICB9KTtcbiAgICBpbnRsLmdldENhbm9uaWNhbExvY2FsZXMgPSBpbnRsVGhyb3coXCJnZXRDYW5vbmljYWxMb2NhbGVzXCIpO1xuICAgIGdsb2JhbFRoaXMuSW50bCA9IGludGw7XG4gIH1cbiAgZnVuY3Rpb24gZ3VhcmRMb2NhbGUocHJvdG8sIG1ldGhvZCkge1xuICAgIHZhciBvcmlnaW5hbCA9IHByb3RvW21ldGhvZF07XG4gICAgaWYgKHR5cGVvZiBvcmlnaW5hbCAhPT0gXCJmdW5jdGlvblwiKSByZXR1cm47XG4gICAgcHJvdG9bbWV0aG9kXSA9IGZ1bmN0aW9uKGxvY2FsZXMpIHtcbiAgICAgIGlmIChsb2NhbGVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcihcIlxcYFwiICsgbWV0aG9kICsgXCIobG9jYWxlcywgLi4uKVxcYCB3aXRoIGFuIGV4cGxpY2l0IGxvY2FsZSBpcyBub3Qgc3VwcG9ydGVkIGluIHRoZSBRdWlja0pTIHdvcmtmbG93IGVuZ2luZSAobm8gSUNVKSDigJQgaXQgd291bGQgc2lsZW50bHkgaWdub3JlIHRoZSBsb2NhbGUuIEZvcm1hdCBpbiBhIHN0ZXAgZnVuY3Rpb24sIG9yIGNhbGwgd2l0aG91dCBhcmd1bWVudHMgZm9yIHRoZSBlbmdpbmUgZGVmYXVsdC5cIik7XG4gICAgICAgIGVyci5uYW1lID0gXCJXb3JrZmxvd1J1bnRpbWVFcnJvclwiO1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3JpZ2luYWwuY2FsbCh0aGlzKTtcbiAgICB9O1xuICB9XG4gIGd1YXJkTG9jYWxlKE51bWJlci5wcm90b3R5cGUsIFwidG9Mb2NhbGVTdHJpbmdcIik7XG4gIGd1YXJkTG9jYWxlKERhdGUucHJvdG90eXBlLCBcInRvTG9jYWxlU3RyaW5nXCIpO1xuICBndWFyZExvY2FsZShEYXRlLnByb3RvdHlwZSwgXCJ0b0xvY2FsZURhdGVTdHJpbmdcIik7XG4gIGd1YXJkTG9jYWxlKERhdGUucHJvdG90eXBlLCBcInRvTG9jYWxlVGltZVN0cmluZ1wiKTtcbiAgZ3VhcmRMb2NhbGUoU3RyaW5nLnByb3RvdHlwZSwgXCJ0b0xvY2FsZUxvd2VyQ2FzZVwiKTtcbiAgZ3VhcmRMb2NhbGUoU3RyaW5nLnByb3RvdHlwZSwgXCJ0b0xvY2FsZVVwcGVyQ2FzZVwiKTtcbiAgLy8gbG9jYWxlQ29tcGFyZSdzIGxvY2FsZXMgYXJndW1lbnQgaXMgdGhlIFNFQ09ORCBwYXJhbWV0ZXIuXG4gIChmdW5jdGlvbigpIHtcbiAgICB2YXIgb3JpZ2luYWwgPSBTdHJpbmcucHJvdG90eXBlLmxvY2FsZUNvbXBhcmU7XG4gICAgU3RyaW5nLnByb3RvdHlwZS5sb2NhbGVDb21wYXJlID0gZnVuY3Rpb24odGhhdCwgbG9jYWxlcykge1xuICAgICAgaWYgKGxvY2FsZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKFwiXFxgbG9jYWxlQ29tcGFyZSh0aGF0LCBsb2NhbGVzLCAuLi4pXFxgIHdpdGggYW4gZXhwbGljaXQgbG9jYWxlIGlzIG5vdCBzdXBwb3J0ZWQgaW4gdGhlIFF1aWNrSlMgd29ya2Zsb3cgZW5naW5lIChubyBJQ1UpLiBDb21wYXJlIGluIGEgc3RlcCBmdW5jdGlvbiwgb3IgY2FsbCB3aXRob3V0IGEgbG9jYWxlLlwiKTtcbiAgICAgICAgZXJyLm5hbWUgPSBcIldvcmtmbG93UnVudGltZUVycm9yXCI7XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBvcmlnaW5hbC5jYWxsKHRoaXMsIHRoYXQpO1xuICAgIH07XG4gIH0pKCk7XG59KSgpO1xuXG5nbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19VU0VfU1RFUFwiKV0gPSBmdW5jdGlvbihzdGVwSWQsIGNsb3N1cmVWYXJzRm4pIHtcbiAgdmFyIGZuID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIHZhciBjb3JyZWxhdGlvbklkID0gXCJzdGVwX1wiICsgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlVWxpZCgpO1xuICAgIC8vIENhcHR1cmUgJ3RoaXMnIGZvciBtZXRob2QgaW52b2NhdGlvbnMgKGUuZy4sIE15Q2xhc3MubWV0aG9kKCkpXG4gICAgdmFyIHRoaXNWYWwgPSAodGhpcyAhPT0gdW5kZWZpbmVkICYmIHRoaXMgIT09IG51bGwgJiYgdGhpcyAhPT0gZ2xvYmFsVGhpcykgPyB0aGlzIDogdW5kZWZpbmVkO1xuICAgIC8vIFRoZSBSQVcgaW5wdXQgdmFsdWUuIFNlcmlhbGl6YXRpb24gaGFwcGVucyBvbiB0aGUgaG9zdCwgd2hpY2ggcmVhZHNcbiAgICAvLyB0aGlzIHRocm91Z2ggYSBoYW5kbGUgd2hlbiBpdCBjb2xsZWN0cyB0aGUgcGVuZGluZyBvcCDigJQgbm9cbiAgICAvLyBzZXJpYWxpemVyIGNvZGUgcnVucyBpbnNpZGUgdGhlIFZNLlxuICAgIHZhciBpbnB1dCA9IHtcbiAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgICBjbG9zdXJlVmFyczogY2xvc3VyZVZhcnNGbiA/IGNsb3N1cmVWYXJzRm4oKSA6IHVuZGVmaW5lZCxcbiAgICAgIHRoaXNWYWw6IHRoaXNWYWwsXG4gICAgfTtcbiAgICBnbG9iYWxUaGlzLl9fcGVuZGluZy5wdXNoKHtcbiAgICAgIHR5cGU6IFwic3RlcFwiLFxuICAgICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICAgIHN0ZXBJZDogc3RlcElkLFxuICAgICAgaW5wdXQ6IGlucHV0LFxuICAgICAgaGFzQ3JlYXRlZEV2ZW50OiBmYWxzZSxcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBnbG9iYWxUaGlzLl9fcmVnaXN0ZXJSZXNvbHZlcihjb3JyZWxhdGlvbklkLCByZXNvbHZlLCByZWplY3QpO1xuICAgIH0pO1xuICB9O1xuICAvLyBTZXQgc3RlcElkIG9uIHRoZSBwcm94eSBzbyB0aGUgU3RlcEZ1bmN0aW9uIHJlZHVjZXIgY2FuIGRldGVjdCBhbmRcbiAgLy8gc2VyaWFsaXplIHN0ZXAgZnVuY3Rpb24gcmVmZXJlbmNlcyAoZS5nLiB3aGVuIHBhc3NlZCBhcyBhcmd1bWVudHMpLlxuICBmbi5zdGVwSWQgPSBzdGVwSWQ7XG4gIGlmIChjbG9zdXJlVmFyc0ZuKSBmbi5fX2Nsb3N1cmVWYXJzRm4gPSBjbG9zdXJlVmFyc0ZuO1xuICAvLyBPdmVycmlkZSAuYmluZCBzbyBhIGJvdW5kIHN0ZXAgcHJveHkgKGUuZy4gdGhlIFNXQyBwbHVnaW4nc1xuICAvLyB1c2VTdGVwKC4uLikuYmluZCh0aGlzKSBmb3IgbGV4aWNhbC10aGlzIGFycm93IHN0ZXBzKSBrZWVwcyBpdHNcbiAgLy8gc3RlcElkIGFuZCByZWNvcmRzIHRoZSBib3VuZCByZWNlaXZlciAvIHByZWZpbGxlZCBhcmdzIOKAlCB0aGUgbmF0aXZlXG4gIC8vIGJpbmQgZHJvcHMgb3duIHByb3BlcnRpZXMsIHdoaWNoIHdvdWxkIG1ha2UgdGhlIFN0ZXBGdW5jdGlvblxuICAvLyByZWR1Y2VyIGZhaWwgdG8gcmVjb2duaXplIHRoZSBwcm94eSB3aGVuIGl0IGNyb3NzZXMgYSBzZXJpYWxpemF0aW9uXG4gIC8vIGJvdW5kYXJ5LiBNaXJyb3JzIHRoZSBub2RlOnZtIGVuZ2luZSdzIG92ZXJyaWRlIGluIHN0ZXAudHMuXG4gIGZuLmJpbmQgPSBmdW5jdGlvbih0aGlzQXJnKSB7XG4gICAgdmFyIHBhcnRpYWxBcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgYm91bmQgPSBGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5hcHBseSh0aGlzLCBbdGhpc0FyZ10uY29uY2F0KHBhcnRpYWxBcmdzKSk7XG4gICAgYm91bmQuc3RlcElkID0gc3RlcElkO1xuICAgIGlmIChjbG9zdXJlVmFyc0ZuKSBib3VuZC5fX2Nsb3N1cmVWYXJzRm4gPSBjbG9zdXJlVmFyc0ZuO1xuICAgIGJvdW5kLl9fYm91bmRUaGlzID0gdGhpc0FyZztcbiAgICBpZiAocGFydGlhbEFyZ3MubGVuZ3RoID4gMCkgYm91bmQuX19ib3VuZEFyZ3MgPSBwYXJ0aWFsQXJncztcbiAgICByZXR1cm4gYm91bmQ7XG4gIH07XG4gIHJldHVybiBmbjtcbn07XG5cbi8vIFBhcnNlcyBhbiBcIm1zXCIgbGlicmFyeSBzdHlsZSBkdXJhdGlvbiBzdHJpbmcgaW50byBtaWxsaXNlY29uZHMuXG4vLyBTdXBwb3J0cyB0aGUgc2FtZSB1bml0cyBhcyB0aGUgcmVwbGF5IHJ1bnRpbWUgKHdoaWNoIHVzZXMgdGhlIFwibXNcIlxuLy8gcGFja2FnZSk6IG1zIC8gcyAvIG0gLyBoIC8gZCAvIHcgLyB5LCB3aXRoIHZlcmJvc2UgYWxpYXNlc1xuLy8gKHNlY29uZHMsIG1pbnV0ZXMsIC4uLikuXG5nbG9iYWxUaGlzLl9fcGFyc2VEdXJhdGlvbk1zID0gZnVuY3Rpb24oc3RyKSB7XG4gIHN0ciA9IFN0cmluZyhzdHIpO1xuICBpZiAoc3RyLmxlbmd0aCA+IDEwMCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgdmFyIG1hdGNoID0gc3RyLm1hdGNoKFxuICAgIC9eKC0/KD86XFxcXGQrKT9cXFxcLj9cXFxcZCspICoobWlsbGlzZWNvbmRzP3xtc2Vjcz98bXN8c2Vjb25kcz98c2Vjcz98c3xtaW51dGVzP3xtaW5zP3xtfGhvdXJzP3xocnM/fGh8ZGF5cz98ZHx3ZWVrcz98d3x5ZWFycz98eXJzP3x5KT8kL2lcbiAgKTtcbiAgaWYgKCFtYXRjaCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgdmFyIG4gPSBwYXJzZUZsb2F0KG1hdGNoWzFdKTtcbiAgdmFyIHR5cGUgPSAobWF0Y2hbMl0gfHwgXCJtc1wiKS50b0xvd2VyQ2FzZSgpO1xuICB2YXIgcyA9IDEwMDAsIG0gPSA2MCAqIHMsIGggPSA2MCAqIG0sIGQgPSAyNCAqIGgsIHcgPSA3ICogZCwgeSA9IDM2NS4yNSAqIGQ7XG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgXCJ5ZWFyc1wiOiBjYXNlIFwieWVhclwiOiBjYXNlIFwieXJzXCI6IGNhc2UgXCJ5clwiOiBjYXNlIFwieVwiOiByZXR1cm4gbiAqIHk7XG4gICAgY2FzZSBcIndlZWtzXCI6IGNhc2UgXCJ3ZWVrXCI6IGNhc2UgXCJ3XCI6IHJldHVybiBuICogdztcbiAgICBjYXNlIFwiZGF5c1wiOiBjYXNlIFwiZGF5XCI6IGNhc2UgXCJkXCI6IHJldHVybiBuICogZDtcbiAgICBjYXNlIFwiaG91cnNcIjogY2FzZSBcImhvdXJcIjogY2FzZSBcImhyc1wiOiBjYXNlIFwiaHJcIjogY2FzZSBcImhcIjogcmV0dXJuIG4gKiBoO1xuICAgIGNhc2UgXCJtaW51dGVzXCI6IGNhc2UgXCJtaW51dGVcIjogY2FzZSBcIm1pbnNcIjogY2FzZSBcIm1pblwiOiBjYXNlIFwibVwiOiByZXR1cm4gbiAqIG07XG4gICAgY2FzZSBcInNlY29uZHNcIjogY2FzZSBcInNlY29uZFwiOiBjYXNlIFwic2Vjc1wiOiBjYXNlIFwic2VjXCI6IGNhc2UgXCJzXCI6IHJldHVybiBuICogcztcbiAgICBjYXNlIFwibWlsbGlzZWNvbmRzXCI6IGNhc2UgXCJtaWxsaXNlY29uZFwiOiBjYXNlIFwibXNlY3NcIjogY2FzZSBcIm1zZWNcIjogY2FzZSBcIm1zXCI6IHJldHVybiBuO1xuICAgIGRlZmF1bHQ6IHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn07XG5cbmdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1NMRUVQXCIpXSA9IGZ1bmN0aW9uKHBhcmFtKSB7XG4gIHZhciBjb3JyZWxhdGlvbklkID0gXCJ3YWl0X1wiICsgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlVWxpZCgpO1xuICB2YXIgcmVzdW1lQXQ7XG4gIGlmICh0eXBlb2YgcGFyYW0gPT09IFwibnVtYmVyXCIpIHtcbiAgICByZXN1bWVBdCA9IG5ldyBEYXRlKERhdGUubm93KCkgKyBwYXJhbSkudG9JU09TdHJpbmcoKTtcbiAgfSBlbHNlIGlmICh0eXBlb2YgcGFyYW0gPT09IFwic3RyaW5nXCIpIHtcbiAgICB2YXIgbXMgPSBnbG9iYWxUaGlzLl9fcGFyc2VEdXJhdGlvbk1zKHBhcmFtKTtcbiAgICBpZiAodHlwZW9mIG1zID09PSBcIm51bWJlclwiICYmIGlzRmluaXRlKG1zKSkge1xuICAgICAgcmVzdW1lQXQgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgbXMpLnRvSVNPU3RyaW5nKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE5vdCBhIGR1cmF0aW9uIHN0cmluZyDigJQgdHJ5IGFzIGFuIGFic29sdXRlIGRhdGUgc3RyaW5nLlxuICAgICAgdmFyIGRhdGUgPSBuZXcgRGF0ZShwYXJhbSk7XG4gICAgICBpZiAoaXNOYU4oZGF0ZS5nZXRUaW1lKCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgc2xlZXAgcGFyYW1ldGVyOiBcIiArIHBhcmFtKTtcbiAgICAgIH1cbiAgICAgIHJlc3VtZUF0ID0gZGF0ZS50b0lTT1N0cmluZygpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChwYXJhbSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICBpZiAoaXNOYU4ocGFyYW0uZ2V0VGltZSgpKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBzbGVlcCBwYXJhbWV0ZXI6IFwiICsgcGFyYW0pO1xuICAgIH1cbiAgICByZXN1bWVBdCA9IHBhcmFtLnRvSVNPU3RyaW5nKCk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBzbGVlcCBwYXJhbWV0ZXI6IFwiICsgcGFyYW0pO1xuICB9XG4gIGdsb2JhbFRoaXMuX19wZW5kaW5nLnB1c2goe1xuICAgIHR5cGU6IFwid2FpdFwiLFxuICAgIGNvcnJlbGF0aW9uSWQ6IGNvcnJlbGF0aW9uSWQsXG4gICAgcmVzdW1lQXQ6IHJlc3VtZUF0LFxuICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gIH0pO1xuICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgZ2xvYmFsVGhpcy5fX3JlZ2lzdGVyUmVzb2x2ZXIoY29ycmVsYXRpb25JZCwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgfSk7XG59O1xuXG4vLyBSZXNwb25zZS9SZXF1ZXN0IHBvbHlmaWxscyDigJQgLmpzb24oKS8udGV4dCgpLy5hcnJheUJ1ZmZlcigpIGFyZSB1c2VTdGVwXG4vLyBwcm94aWVzIHRoYXQgZXhlY3V0ZSBvbiB0aGUgaG9zdCBzaWRlLiBUaGUgcHJveGllcyBhcmUgYXNzaWduZWQgZGlyZWN0bHlcbi8vIHRvIHRoZSBwcm90b3R5cGVzIHNvIHRoYXQgJ3RoaXMnICh0aGUgUmVzcG9uc2UvUmVxdWVzdCBpbnN0YW5jZSkgaXNcbi8vIHNlcmlhbGl6ZWQgYXMgdGhpc1ZhbCBieSBXT1JLRkxPV19VU0VfU1RFUCwgbWF0Y2hpbmcgdGhlIGV2ZW50LXJlcGxheVxuLy8gcnVudGltZSdzIGFwcHJvYWNoIChjb21taXQgZGNiMDc2MSkuXG5pZiAodHlwZW9mIFJlc3BvbnNlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gIHZhciBfX0JPRFlfSU5JVCA9IFN5bWJvbC5mb3IoXCJCT0RZX0lOSVRcIik7XG5cbiAgZ2xvYmFsVGhpcy5SZXNwb25zZSA9IGZ1bmN0aW9uKGJvZHksIGluaXQpIHtcbiAgICBpbml0ID0gaW5pdCB8fCB7fTtcbiAgICB0aGlzLnN0YXR1cyA9IGluaXQuc3RhdHVzIHx8IDIwMDtcbiAgICB0aGlzLnN0YXR1c1RleHQgPSBpbml0LnN0YXR1c1RleHQgfHwgXCJcIjtcbiAgICB0aGlzLmhlYWRlcnMgPSBuZXcgZ2xvYmFsVGhpcy5IZWFkZXJzKGluaXQuaGVhZGVycyB8fCBbXSk7XG4gICAgdGhpcy50eXBlID0gXCJkZWZhdWx0XCI7XG4gICAgdGhpcy51cmwgPSBcIlwiO1xuICAgIHRoaXMucmVkaXJlY3RlZCA9IGZhbHNlO1xuICAgIGlmIChib2R5ICE9PSBudWxsICYmIGJvZHkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5ib2R5ID0gT2JqZWN0LmNyZWF0ZShnbG9iYWxUaGlzLlJlYWRhYmxlU3RyZWFtLnByb3RvdHlwZSk7XG4gICAgICB0aGlzLmJvZHlbX19CT0RZX0lOSVRdID0gYm9keTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5ib2R5ID0gbnVsbDtcbiAgICB9XG4gIH07XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShnbG9iYWxUaGlzLlJlc3BvbnNlLnByb3RvdHlwZSwgXCJva1wiLCB7XG4gICAgZ2V0OiBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXMuc3RhdHVzID49IDIwMCAmJiB0aGlzLnN0YXR1cyA8IDMwMDsgfVxuICB9KTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGdsb2JhbFRoaXMuUmVzcG9uc2UucHJvdG90eXBlLCBcImJvZHlVc2VkXCIsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgfSk7XG4gIC8vIEFzc2lnbiB1c2VTdGVwIHByb3hpZXMgZGlyZWN0bHkg4oCUICd0aGlzJyBiaW5kaW5nIHByb3ZpZGVzIHRoZVxuICAvLyBSZXNwb25zZSBpbnN0YW5jZSwgd2hpY2ggZ2V0cyBzZXJpYWxpemVkIGFzIHRoaXNWYWwgYnkgdGhlIHByb3h5LlxuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhnbG9iYWxUaGlzLlJlc3BvbnNlLnByb3RvdHlwZSwge1xuICAgIGFycmF5QnVmZmVyOiB7IHZhbHVlOiBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19VU0VfU1RFUFwiKV0oXCJfX2J1aWx0aW5fcmVzcG9uc2VfYXJyYXlfYnVmZmVyXCIpLCB3cml0YWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlIH0sXG4gICAganNvbjogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX2pzb25cIiksIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSxcbiAgICB0ZXh0OiB7IHZhbHVlOiBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19VU0VfU1RFUFwiKV0oXCJfX2J1aWx0aW5fcmVzcG9uc2VfdGV4dFwiKSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9LFxuICB9KTtcbiAgZ2xvYmFsVGhpcy5SZXNwb25zZS5wcm90b3R5cGUuYnl0ZXMgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5hcnJheUJ1ZmZlcigpLnRoZW4oZnVuY3Rpb24oYnVmKSB7IHJldHVybiBuZXcgVWludDhBcnJheShidWYpOyB9KTtcbiAgfTtcbiAgZ2xvYmFsVGhpcy5SZXNwb25zZS5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgciA9IE9iamVjdC5jcmVhdGUoZ2xvYmFsVGhpcy5SZXNwb25zZS5wcm90b3R5cGUpO1xuICAgIHIuc3RhdHVzID0gdGhpcy5zdGF0dXM7IHIuc3RhdHVzVGV4dCA9IHRoaXMuc3RhdHVzVGV4dDtcbiAgICByLmhlYWRlcnMgPSB0aGlzLmhlYWRlcnM7IHIudHlwZSA9IHRoaXMudHlwZTtcbiAgICByLnVybCA9IHRoaXMudXJsOyByLnJlZGlyZWN0ZWQgPSB0aGlzLnJlZGlyZWN0ZWQ7IHIuYm9keSA9IHRoaXMuYm9keTtcbiAgICByZXR1cm4gcjtcbiAgfTtcbiAgZ2xvYmFsVGhpcy5SZXNwb25zZS5qc29uID0gZnVuY3Rpb24oZGF0YSwgaW5pdCkge1xuICAgIHZhciBib2R5ID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgdmFyIGhlYWRlcnMgPSBuZXcgZ2xvYmFsVGhpcy5IZWFkZXJzKGluaXQgPyBpbml0LmhlYWRlcnMgOiBbXSk7XG4gICAgaWYgKCFoZWFkZXJzLmhhcyhcImNvbnRlbnQtdHlwZVwiKSkgeyBoZWFkZXJzLnNldChcImNvbnRlbnQtdHlwZVwiLCBcImFwcGxpY2F0aW9uL2pzb25cIik7IH1cbiAgICByZXR1cm4gbmV3IGdsb2JhbFRoaXMuUmVzcG9uc2UoYm9keSwgeyBzdGF0dXM6IChpbml0ICYmIGluaXQuc3RhdHVzKSB8fCAyMDAsIHN0YXR1c1RleHQ6IChpbml0ICYmIGluaXQuc3RhdHVzVGV4dCkgfHwgXCJcIiwgaGVhZGVyczogaGVhZGVycyB9KTtcbiAgfTtcbn1cbmlmICh0eXBlb2YgUmVxdWVzdCA9PT0gXCJ1bmRlZmluZWRcIikge1xuICBnbG9iYWxUaGlzLlJlcXVlc3QgPSBmdW5jdGlvbihpbnB1dCwgaW5pdCkge1xuICAgIGluaXQgPSBpbml0IHx8IHt9O1xuICAgIGlmICh0eXBlb2YgaW5wdXQgPT09IFwic3RyaW5nXCIpIHsgdGhpcy51cmwgPSBpbnB1dDsgfVxuICAgIGVsc2UgaWYgKGlucHV0ICYmIHR5cGVvZiBpbnB1dCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgdGhpcy51cmwgPSBpbnB1dC51cmwgfHwgXCJcIjsgdGhpcy5tZXRob2QgPSBpbnB1dC5tZXRob2Q7XG4gICAgICB0aGlzLmhlYWRlcnMgPSBpbnB1dC5oZWFkZXJzOyB0aGlzLmJvZHkgPSBpbnB1dC5ib2R5O1xuICAgIH1cbiAgICBpZiAoaW5pdC5tZXRob2QpIHRoaXMubWV0aG9kID0gaW5pdC5tZXRob2QudG9VcHBlckNhc2UoKTtcbiAgICBpZiAoIXRoaXMubWV0aG9kKSB0aGlzLm1ldGhvZCA9IFwiR0VUXCI7XG4gICAgaWYgKGluaXQuaGVhZGVycykgdGhpcy5oZWFkZXJzID0gbmV3IGdsb2JhbFRoaXMuSGVhZGVycyhpbml0LmhlYWRlcnMpO1xuICAgIGlmICghdGhpcy5oZWFkZXJzKSB0aGlzLmhlYWRlcnMgPSBuZXcgZ2xvYmFsVGhpcy5IZWFkZXJzKCk7XG4gICAgaWYgKGluaXQuYm9keSAhPT0gdW5kZWZpbmVkKSB0aGlzLmJvZHkgPSBpbml0LmJvZHk7XG4gICAgaWYgKCF0aGlzLmJvZHkpIHRoaXMuYm9keSA9IG51bGw7XG4gICAgdGhpcy5kdXBsZXggPSBpbml0LmR1cGxleCB8fCBcImhhbGZcIjtcbiAgfTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGdsb2JhbFRoaXMuUmVxdWVzdC5wcm90b3R5cGUsIFwiYm9keVVzZWRcIiwge1xuICAgIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiBmYWxzZTsgfVxuICB9KTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoZ2xvYmFsVGhpcy5SZXF1ZXN0LnByb3RvdHlwZSwge1xuICAgIGFycmF5QnVmZmVyOiB7IHZhbHVlOiBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19VU0VfU1RFUFwiKV0oXCJfX2J1aWx0aW5fcmVzcG9uc2VfYXJyYXlfYnVmZmVyXCIpLCB3cml0YWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlIH0sXG4gICAganNvbjogeyB2YWx1ZTogZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKFwiV09SS0ZMT1dfVVNFX1NURVBcIildKFwiX19idWlsdGluX3Jlc3BvbnNlX2pzb25cIiksIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSxcbiAgICB0ZXh0OiB7IHZhbHVlOiBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19VU0VfU1RFUFwiKV0oXCJfX2J1aWx0aW5fcmVzcG9uc2VfdGV4dFwiKSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9LFxuICB9KTtcbn1cblxuLy8gY3JlYXRlSG9vayDigJQgcmV0dXJucyBhIEhvb2sgb2JqZWN0IHRoYXQgaXMgYm90aCBhIFRoZW5hYmxlIGFuZCBBc3luY0l0ZXJhYmxlLlxuLy8gRWFjaCBhd2FpdC95aWVsZCBjcmVhdGVzIGEgbmV3IHByb21pc2Uga2V5ZWQgYnkgdGhlIHNhbWUgY29ycmVsYXRpb25JZC5cbi8vIFRoZSBwcm9taXNlIGlzIHJlc29sdmVkIHdoZW4gYSBob29rX3JlY2VpdmVkIGV2ZW50IGFycml2ZXMuXG5nbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19DUkVBVEVfSE9PS1wiKV0gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBpZiAob3B0aW9ucy5pc1dlYmhvb2sgPT09IHRydWUgJiYgb3B0aW9ucy5leHBlcmltZW50YWxfbWluUmV0ZW50aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1dlYmhvb2sgaG9va3MgZG8gbm90IHN1cHBvcnQgXFxgZXhwZXJpbWVudGFsX21pblJldGVudGlvblxcYC4gVXNlIGEgbm9uLXdlYmhvb2sgXFxgY3JlYXRlSG9vaygpXFxgIHdpdGggXFxgcmVzdW1lSG9vaygpXFxgLicpO1xuICB9XG4gIGlmIChvcHRpb25zLmV4cGVyaW1lbnRhbF9taW5SZXRlbnRpb24gIT09IHVuZGVmaW5lZCAmJiBnbG9iYWxUaGlzLl9fd29ybGRDYXBhYmlsaXRpZXM/Lmhvb2tSZXRlbnRpb24/LmFjdGl2ZSAhPT0gdHJ1ZSkge1xuICAgIHZhciB1bnN1cHBvcnRlZFJldGVudGlvbkVycm9yID0gbmV3IEVycm9yKCdUaGUgY29uZmlndXJlZCBXb3JsZCBkb2VzIG5vdCBzdXBwb3J0IFxcYGV4cGVyaW1lbnRhbF9taW5SZXRlbnRpb25cXGAgZm9yIEhvb2tzLicpO1xuICAgIHVuc3VwcG9ydGVkUmV0ZW50aW9uRXJyb3IubmFtZSA9IFwiRmF0YWxFcnJvclwiO1xuICAgIHVuc3VwcG9ydGVkUmV0ZW50aW9uRXJyb3IuZmF0YWwgPSB0cnVlO1xuICAgIHRocm93IHVuc3VwcG9ydGVkUmV0ZW50aW9uRXJyb3I7XG4gIH1cbiAgdmFyIHRva2VuID0gb3B0aW9ucy50b2tlbiB8fCBnbG9iYWxUaGlzLl9fZ2VuZXJhdGVOYW5vaWQoKTtcbiAgdmFyIGNvcnJlbGF0aW9uSWQgPSBcImhvb2tfXCIgKyBnbG9iYWxUaGlzLl9fZ2VuZXJhdGVVbGlkKCk7XG4gIHZhciBpc0Rpc3Bvc2VkID0gZmFsc2U7XG4gIHZhciBoYXNDcmVhdGVkRXZlbnQgPSBmYWxzZTtcbiAgdmFyIHRva2VuUmV0ZW50aW9uVW50aWw7XG4gIGlmIChvcHRpb25zLmV4cGVyaW1lbnRhbF9taW5SZXRlbnRpb24gIT09IHVuZGVmaW5lZCkge1xuICAgIHZhciBtaW5SZXRlbnRpb24gPSBvcHRpb25zLmV4cGVyaW1lbnRhbF9taW5SZXRlbnRpb247XG4gICAgaWYgKHR5cGVvZiBtaW5SZXRlbnRpb24gPT09IFwibnVtYmVyXCIpIHtcbiAgICAgIGlmIChtaW5SZXRlbnRpb24gPCAwIHx8ICFpc0Zpbml0ZShtaW5SZXRlbnRpb24pKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZHVyYXRpb246IFwiICsgbWluUmV0ZW50aW9uICsgXCIuIEV4cGVjdGVkIGEgbm9uLW5lZ2F0aXZlIGZpbml0ZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLlwiKTtcbiAgICAgIH1cbiAgICAgIHRva2VuUmV0ZW50aW9uVW50aWwgPSBEYXRlLm5vdygpICsgbWluUmV0ZW50aW9uO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIG1pblJldGVudGlvbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgdmFyIHJldGVudGlvbk1zID0gZ2xvYmFsVGhpcy5fX3BhcnNlRHVyYXRpb25NcyhtaW5SZXRlbnRpb24pO1xuICAgICAgaWYgKHR5cGVvZiByZXRlbnRpb25NcyAhPT0gXCJudW1iZXJcIiB8fCByZXRlbnRpb25NcyA8IDAgfHwgIWlzRmluaXRlKHJldGVudGlvbk1zKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZHVyYXRpb246IFwiJyArIG1pblJldGVudGlvbiArICdcIi4gRXhwZWN0ZWQgYSB2YWxpZCBkdXJhdGlvbiBzdHJpbmcgbGlrZSBcIjFzXCIsIFwiMW1cIiwgXCIxaFwiLCBldGMuJyk7XG4gICAgICB9XG4gICAgICB0b2tlblJldGVudGlvblVudGlsID0gRGF0ZS5ub3coKSArIHJldGVudGlvbk1zO1xuICAgIH0gZWxzZSBpZiAobWluUmV0ZW50aW9uIGluc3RhbmNlb2YgRGF0ZSB8fCAobWluUmV0ZW50aW9uICYmIHR5cGVvZiBtaW5SZXRlbnRpb24uZ2V0VGltZSA9PT0gXCJmdW5jdGlvblwiKSkge1xuICAgICAgLy8gQWNjZXB0IERhdGUtbGlrZSBvYmplY3RzIChhbnl0aGluZyB3aXRoIGdldFRpbWUpLCBtYXRjaGluZ1xuICAgICAgLy8gcGFyc2VEdXJhdGlvblRvRGF0ZTogdmFsdWVzIHRoYXQgY3Jvc3NlZCB0aGUgc2VyZGUgYm91bmRhcnkgbWF5XG4gICAgICAvLyBub3QgYmUgcmVhbG0tbmF0aXZlIERhdGUgaW5zdGFuY2VzLlxuICAgICAgdG9rZW5SZXRlbnRpb25VbnRpbCA9IG1pblJldGVudGlvbi5nZXRUaW1lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZHVyYXRpb24gcGFyYW1ldGVyLiBFeHBlY3RlZCBhIGR1cmF0aW9uIHN0cmluZywgbnVtYmVyIChtaWxsaXNlY29uZHMpLCBvciBEYXRlIG9iamVjdC5cIik7XG4gICAgfVxuICB9XG5cbiAgLy8gUmVnaXN0ZXIgaW4gcGVuZGluZyBvcGVyYXRpb25zLiBNZXRhZGF0YSBzdGF5cyBhIFJBVyB2YWx1ZTsgdGhlIGhvc3RcbiAgLy8gc2VyaWFsaXplcyBpdCB0aHJvdWdoIGEgaGFuZGxlIHdoZW4gaXQgY29sbGVjdHMgdGhlIHBlbmRpbmcgb3AuXG4gIHZhciBwZW5kaW5nT3AgPSB7XG4gICAgdHlwZTogXCJob29rXCIsXG4gICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICB0b2tlbjogdG9rZW4sXG4gICAgdG9rZW5SZXRlbnRpb25VbnRpbDogdG9rZW5SZXRlbnRpb25VbnRpbCxcbiAgICBpc1dlYmhvb2s6ICEhb3B0aW9ucy5pc1dlYmhvb2ssXG4gICAgbWV0YWRhdGE6IG9wdGlvbnMubWV0YWRhdGEsXG4gICAgaGFzQ3JlYXRlZEV2ZW50OiBmYWxzZSxcbiAgfTtcbiAgZ2xvYmFsVGhpcy5fX3BlbmRpbmcucHVzaChwZW5kaW5nT3ApO1xuXG4gIC8vIFBlci1ob29rIGxpZmVjeWNsZSBzdGF0ZSBiYWNraW5nIGhvb2suZ2V0Q29uZmxpY3QoKTogcmVzb2x2ZXMgbnVsbFxuICAvLyBvbmNlIGNyZWF0aW9uIGlzIGNvbmZpcm1lZCAoaG9va19jcmVhdGVkKSwgb3IgcmVzb2x2ZXMgd2l0aCB0aGVcbiAgLy8gY29uZmxpY3RpbmcgUnVuIGhhbmRsZSAvIHJlamVjdHMgd2l0aCBIb29rQ29uZmxpY3RFcnJvciBvblxuICAvLyBob29rX2NvbmZsaWN0LiBTdGF0ZSB0cmFuc2l0aW9ucyBhcmUgZHJpdmVuIGJ5IHRoZSBob3N0IGR1cmluZyBldmVudFxuICAvLyBwcm9jZXNzaW5nIChzZWUgcHJvY2Vzc0V2ZW50cykuXG4gIGdsb2JhbFRoaXMuX19ob29rcyA9IGdsb2JhbFRoaXMuX19ob29rcyB8fCB7fTtcbiAgZ2xvYmFsVGhpcy5fX2hvb2tzW2NvcnJlbGF0aW9uSWRdID0ge1xuICAgIHRva2VuOiB0b2tlbixcbiAgICBjcmVhdGVkOiBmYWxzZSxcbiAgICBjb25mbGljdDogbnVsbCxcbiAgICBnZXRDb25mbGljdFJlc29sdmVyczogW10sXG4gIH07XG5cbiAgLy8gRWFjaCBhd2FpdCBjcmVhdGVzIGEgbmV3IHByb21pc2UgZm9yIHRoZSBuZXh0IHBheWxvYWQuXG4gIC8vIFRoZSBjb3JyZWxhdGlvbklkIHN0YXlzIHRoZSBzYW1lIOKAlCB0aGUgcmVzb2x2ZXIgaXMgcmVwbGFjZWQgZWFjaCB0aW1lLlxuICBmdW5jdGlvbiBjcmVhdGVIb29rUHJvbWlzZSgpIHtcbiAgICAvLyBDaGVjayB0aGUgcGF5bG9hZCBidWZmZXIgZmlyc3Qg4oCUIGlmIGEgaG9va19yZWNlaXZlZCBldmVudCBhcnJpdmVkXG4gICAgLy8gYmVmb3JlIHRoaXMgaG9vayB3YXMgYXdhaXRlZCwgdGhlIHBheWxvYWQgd2FzIGJ1ZmZlcmVkIGluIHRoZSBWTVxuICAgIC8vIGhlYXAuIERyYWluIGl0IGltbWVkaWF0ZWx5IChtYXRjaGluZyBldmVudC1yZXBsYXkgcGF5bG9hZHNRdWV1ZSkuXG4gICAgdmFyIGJ1ZiA9IGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlcltjb3JyZWxhdGlvbklkXTtcbiAgICBpZiAoYnVmICYmIGJ1Zi5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGJ1Zi5zaGlmdCgpKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1tjb3JyZWxhdGlvbklkXSA9IHsgcmVzb2x2ZTogcmVzb2x2ZSwgcmVqZWN0OiByZWplY3QgfTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpc3Bvc2VIb29rKCkge1xuICAgIGlmIChpc0Rpc3Bvc2VkKSByZXR1cm47XG4gICAgaXNEaXNwb3NlZCA9IHRydWU7XG4gICAgLy8gQSBjb25mbGljdGVkIGhvb2sgd2FzIG5ldmVyIGNyZWF0ZWQgKHRoZSB3b3JsZCByZWplY3RlZCBpdHMgY2xhaW1cbiAgICAvLyDigJQgdGhlIHRva2VuIGJlbG9uZ3MgdG8gYW5vdGhlciBydW4pLCBzbyB0aGVyZSBpcyBubyBlbnRpdHkgdG9cbiAgICAvLyBkaXNwb3NlLiBNaXJyb3JzIHRoZSBub2RlOnZtIGVuZ2luZSwgd2hlcmUgaG9va19jb25mbGljdCByZW1vdmVzXG4gICAgLy8gdGhlIGludm9jYXRpb24tcXVldWUgaXRlbSBiZWZvcmUgZGlzcG9zZSBjYW4gbWFyayBpdC4gRW1pdHRpbmcgYVxuICAgIC8vIGhvb2tfZGlzcG9zZWQgaGVyZSB3b3VsZCBiZSByZWplY3RlZCBieSB0aGUgd29ybGQnc1xuICAgIC8vIGhvb2stZXhpc3RlbmNlIHZhbGlkYXRpb24uXG4gICAgdmFyIHN0YXRlID0gZ2xvYmFsVGhpcy5fX2hvb2tzW2NvcnJlbGF0aW9uSWRdO1xuICAgIGlmICghc3RhdGUgfHwgIXN0YXRlLmNvbmZsaWN0KSB7XG4gICAgICAvLyBTaWduYWwgdG8gdGhlIGVudHJ5cG9pbnQgdG8gY3JlYXRlIGEgaG9va19kaXNwb3NlZCBldmVudC4gVGhlXG4gICAgICAvLyB0b2tlbiBpcyBjYXJyaWVkIHNvIHRoZSBlbnRyeXBvaW50IGNhbiBvcmRlciBzYW1lLXRva2VuIGhvb2tcbiAgICAgIC8vIG9wZXJhdGlvbnMgc2VxdWVudGlhbGx5IChhIGRpc3Bvc2UgbXVzdCByZWxlYXNlIHRoZSB0b2tlbiBiZWZvcmVcbiAgICAgIC8vIGEgbGF0ZXIgc2FtZS10b2tlbiBob29rJ3MgY3JlYXRpb24gaXMgdmFsaWRhdGVkKS5cbiAgICAgIGdsb2JhbFRoaXMuX19wZW5kaW5nLnB1c2goe1xuICAgICAgICB0eXBlOiBcImhvb2tfZGlzcG9zZVwiLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBjb3JyZWxhdGlvbklkLFxuICAgICAgICB0b2tlbjogdG9rZW4sXG4gICAgICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9XG4gICAgLy8gSWYgdGhlcmUncyBhIHBlbmRpbmcgcmVzb2x2ZXIsIHJlc29sdmUgaXQgd2l0aCB1bmRlZmluZWQgdG8gYnJlYWsgdGhlIGl0ZXJhdG9yXG4gICAgaWYgKGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbY29ycmVsYXRpb25JZF0pIHtcbiAgICAgIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbY29ycmVsYXRpb25JZF0ucmVzb2x2ZSh1bmRlZmluZWQpO1xuICAgICAgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbY29ycmVsYXRpb25JZF07XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0Q29uZmxpY3QoKSB7XG4gICAgdmFyIHN0YXRlID0gZ2xvYmFsVGhpcy5fX2hvb2tzW2NvcnJlbGF0aW9uSWRdO1xuICAgIGlmIChzdGF0ZS5jb25mbGljdCkge1xuICAgICAgcmV0dXJuIHN0YXRlLmNvbmZsaWN0LnJ1blxuICAgICAgICA/IFByb21pc2UucmVzb2x2ZShzdGF0ZS5jb25mbGljdC5ydW4pXG4gICAgICAgIDogUHJvbWlzZS5yZWplY3Qoc3RhdGUuY29uZmxpY3QuZXJyb3IpO1xuICAgIH1cbiAgICBpZiAoc3RhdGUuY3JlYXRlZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShudWxsKTtcbiAgICB9XG4gICAgLy8gQ3JlYXRpb24gbm90IHlldCBjb25maXJtZWQgYnkgdGhlIGV2ZW50IGxvZyDigJQgcGFyayB0aGUgYXdhaXRlciBhbmRcbiAgICAvLyBmbGFnIHRoZSBwZW5kaW5nIG9wIHNvIHRoZSBlbnRyeXBvaW50IHJlLWludm9rZXMgdGhlIHdvcmtmbG93IHJpZ2h0XG4gICAgLy8gYWZ0ZXIgd3JpdGluZyBob29rX2NyZWF0ZWQgKG5vdGhpbmcgZXh0ZXJuYWwgcmVzdW1lcyBhIGdldENvbmZsaWN0XG4gICAgLy8gYXdhaXRlcjsgY29uZmlybWF0aW9uIG9ubHkgY29tZXMgZnJvbSByZXBsYXlpbmcgdGhlIG5ldyBldmVudCkuXG4gICAgcGVuZGluZ09wLmhhc0dldENvbmZsaWN0QXdhaXRlciA9IHRydWU7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgc3RhdGUuZ2V0Q29uZmxpY3RSZXNvbHZlcnMucHVzaCh7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0IH0pO1xuICAgIH0pO1xuICB9XG5cbiAgdmFyIGhvb2sgPSB7XG4gICAgdG9rZW46IHRva2VuLFxuICAgIHRoZW46IGZ1bmN0aW9uKG9uRnVsZmlsbGVkLCBvblJlamVjdGVkKSB7XG4gICAgICByZXR1cm4gY3JlYXRlSG9va1Byb21pc2UoKS50aGVuKG9uRnVsZmlsbGVkLCBvblJlamVjdGVkKTtcbiAgICB9LFxuICAgIGdldENvbmZsaWN0OiBnZXRDb25mbGljdCxcbiAgICBkaXNwb3NlOiBkaXNwb3NlSG9vayxcbiAgfTtcblxuICAvLyBTeW1ib2wuZGlzcG9zZSBmb3IgZXhwbGljaXQgcmVzb3VyY2UgbWFuYWdlbWVudFxuICBob29rW1N5bWJvbC5kaXNwb3NlXSA9IGRpc3Bvc2VIb29rO1xuXG4gIC8vIEFzeW5jSXRlcmFibGUg4oCUIHlpZWxkcyBwYXlsb2FkcyB1bnRpbCBkaXNwb3NlZFxuICBob29rW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB7XG4gICAgICBuZXh0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKGlzRGlzcG9zZWQpIHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY3JlYXRlSG9va1Byb21pc2UoKS50aGVuKGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgICAgLy8gSWYgZGlzcG9zZWQgd2hpbGUgd2FpdGluZywgc2lnbmFsIGRvbmVcbiAgICAgICAgICBpZiAoaXNEaXNwb3NlZCkgcmV0dXJuIHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9O1xuICAgICAgICAgIHJldHVybiB7IGRvbmU6IGZhbHNlLCB2YWx1ZTogdmFsdWUgfTtcbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgICAgcmV0dXJuOiBmdW5jdGlvbigpIHtcbiAgICAgICAgZGlzcG9zZUhvb2soKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7IGRvbmU6IHRydWUsIHZhbHVlOiB1bmRlZmluZWQgfSk7XG4gICAgICB9LFxuICAgIH07XG4gIH07XG5cbiAgcmV0dXJuIGhvb2s7XG59O1xuXG4vLyBzZXRBdHRyaWJ1dGVzIOKAlCBhdHRhY2hlcyBwbGFpbnRleHQgbWV0YWRhdGEgdG8gdGhlIGN1cnJlbnQgcnVuLlxuLy8gVmFsaWRhdGlvbiBoYXBwZW5zIGluIGxpYnJhcnkgY29kZSAobm9ybWFsaXplQXR0cmlidXRlQ2hhbmdlcykgYmVmb3JlXG4vLyB0aGlzIGRpc3BhdGNoZXIgaXMgaW52b2tlZCwgc28gXCJjaGFuZ2VzXCIgaXMgYWxyZWFkeSBub3JtYWxpemVkLiBUaGVcbi8vIHJldHVybmVkIHByb21pc2UgcmVzb2x2ZXMgd2hlbiB0aGUgbWF0Y2hpbmcgYXR0cl9zZXQgZXZlbnQgaXNcbi8vIG9ic2VydmVkIGR1cmluZyBldmVudCBwcm9jZXNzaW5nIOKAlCBtaXJyb3JpbmcgdGhlIG5vZGU6dm0gZW5naW5lJ3Ncbi8vIGNyZWF0ZVNldEF0dHJpYnV0ZXMgKGF0dHJpYnV0ZS1kaXNwYXRjaGVyLnRzKS5cbmdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX1NFVF9BVFRSSUJVVEVTXCIpXSA9IGZ1bmN0aW9uKGNoYW5nZXMsIG9wdGlvbnMpIHtcbiAgdmFyIGNvcnJlbGF0aW9uSWQgPSBcImF0dHJfXCIgKyBnbG9iYWxUaGlzLl9fZ2VuZXJhdGVVbGlkKCk7XG4gIGdsb2JhbFRoaXMuX19wZW5kaW5nLnB1c2goe1xuICAgIHR5cGU6IFwiYXR0cmlidXRlXCIsXG4gICAgY29ycmVsYXRpb25JZDogY29ycmVsYXRpb25JZCxcbiAgICBjaGFuZ2VzOiBjaGFuZ2VzLFxuICAgIGFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzOiAhIShvcHRpb25zICYmIG9wdGlvbnMuYWxsb3dSZXNlcnZlZEF0dHJpYnV0ZXMpLFxuICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gIH0pO1xuICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgZ2xvYmFsVGhpcy5fX3JlZ2lzdGVyUmVzb2x2ZXIoY29ycmVsYXRpb25JZCwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgfSk7XG59O1xuXG4vLyAtLS0tIEFib3J0Q29udHJvbGxlciAvIEFib3J0U2lnbmFsIChob29rLWJhY2tlZCkgLS0tLVxuLy8gUG9ydCBvZiB3b3JrZmxvdy9hYm9ydC1jb250cm9sbGVyLnRzIHRvIHRoZSBWTSBwZW5kaW5nLW9wIG1vZGVsOlxuLy8gdGhlIGNvbnRyb2xsZXIgcmVnaXN0ZXJzIGEgc3lzdGVtIGhvb2s7IGFib3J0KCkgZmxpcHMgdGhlIHNpZ25hbFxuLy8gc3luY2hyb25vdXNseSBhbmQgbWFya3MgdGhlIHBlbmRpbmcgb3Agc28gdGhlIGhvc3QgcmVjb3JkcyB0aGUgYWJvcnRcbi8vIChob29rX3JlY2VpdmVkIGV2ZW50ICsgc3RyZWFtIHBhY2tldCkuIE9uIHJlcGxheSwgdGhlIHJlY29yZGVkXG4vLyBob29rX3JlY2VpdmVkIGV2ZW50IGNhbGxzIF9zZXRBYm9ydGVkIGR1cmluZyBldmVudCBwcm9jZXNzaW5nIGFuZCB0aGVcbi8vIHdvcmtmbG93J3Mgb3duIGFib3J0KCkgY2FsbCBiZWNvbWVzIGEgbm8tb3AuXG52YXIgX19BQk9SVF9TVFJFQU1fTkFNRSA9IFN5bWJvbC5mb3IoXCJXT1JLRkxPV19BQk9SVF9TVFJFQU1fTkFNRVwiKTtcbnZhciBfX0FCT1JUX0hPT0tfVE9LRU4gPSBTeW1ib2wuZm9yKFwiV09SS0ZMT1dfQUJPUlRfSE9PS19UT0tFTlwiKTtcblxuZnVuY3Rpb24gX19tYWtlQWJvcnRFcnJvcigpIHtcbiAgaWYgKHR5cGVvZiBET01FeGNlcHRpb24gIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICByZXR1cm4gbmV3IERPTUV4Y2VwdGlvbihcIlRoZSBvcGVyYXRpb24gd2FzIGFib3J0ZWQuXCIsIFwiQWJvcnRFcnJvclwiKTtcbiAgfVxuICB2YXIgZSA9IG5ldyBFcnJvcihcIlRoZSBvcGVyYXRpb24gd2FzIGFib3J0ZWQuXCIpO1xuICBlLm5hbWUgPSBcIkFib3J0RXJyb3JcIjtcbiAgcmV0dXJuIGU7XG59XG5cbmZ1bmN0aW9uIFdvcmtmbG93QWJvcnRTaWduYWwoc3RyZWFtTmFtZSwgaG9va1Rva2VuKSB7XG4gIHRoaXMuYWJvcnRlZCA9IGZhbHNlO1xuICB0aGlzLnJlYXNvbiA9IHVuZGVmaW5lZDtcbiAgdGhpc1tfX0FCT1JUX1NUUkVBTV9OQU1FXSA9IHN0cmVhbU5hbWU7XG4gIHRoaXNbX19BQk9SVF9IT09LX1RPS0VOXSA9IGhvb2tUb2tlbjtcbiAgdGhpcy5fX2xpc3RlbmVycyA9IFtdO1xuICB0aGlzLl9fb25hYm9ydCA9IG51bGw7XG59XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoV29ya2Zsb3dBYm9ydFNpZ25hbC5wcm90b3R5cGUsIFwib25hYm9ydFwiLCB7XG4gIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLl9fb25hYm9ydDsgfSxcbiAgc2V0OiBmdW5jdGlvbihoYW5kbGVyKSB7XG4gICAgdGhpcy5fX29uYWJvcnQgPSBoYW5kbGVyO1xuICAgIGlmIChoYW5kbGVyICYmIHRoaXMuYWJvcnRlZCkgaGFuZGxlci5jYWxsKHRoaXMpO1xuICB9LFxufSk7XG5Xb3JrZmxvd0Fib3J0U2lnbmFsLnByb3RvdHlwZS5fc2V0QWJvcnRlZCA9IGZ1bmN0aW9uKHJlYXNvbikge1xuICBpZiAodGhpcy5hYm9ydGVkKSByZXR1cm47XG4gIHRoaXMuYWJvcnRlZCA9IHRydWU7XG4gIHRoaXMucmVhc29uID0gcmVhc29uO1xuICBpZiAodGhpcy5fX29uYWJvcnQpIHRoaXMuX19vbmFib3J0LmNhbGwodGhpcyk7XG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9fbGlzdGVuZXJzO1xuICB0aGlzLl9fbGlzdGVuZXJzID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGlzdGVuZXJzLmxlbmd0aDsgaSsrKSBsaXN0ZW5lcnNbaV0oKTtcbn07XG5Xb3JrZmxvd0Fib3J0U2lnbmFsLnByb3RvdHlwZS5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgaWYgKHR5cGUgIT09IFwiYWJvcnRcIikgcmV0dXJuO1xuICBpZiAodGhpcy5hYm9ydGVkKSB7XG4gICAgLy8gRmlyZSBzeW5jaHJvbm91c2x5IChub3Qgb24gYSBtaWNyb3Rhc2spIGZvciBkZXRlcm1pbmlzdGljIHJlcGxheSDigJRcbiAgICAvLyBtYXRjaGVzIHRoZSBub2RlOnZtIGVuZ2luZSdzIFdvcmtmbG93QWJvcnRTaWduYWwuXG4gICAgbGlzdGVuZXIoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgdGhpcy5fX2xpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcbn07XG5Xb3JrZmxvd0Fib3J0U2lnbmFsLnByb3RvdHlwZS5yZW1vdmVFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgaWYgKHR5cGUgIT09IFwiYWJvcnRcIikgcmV0dXJuO1xuICB0aGlzLl9fbGlzdGVuZXJzID0gdGhpcy5fX2xpc3RlbmVycy5maWx0ZXIoZnVuY3Rpb24obCkgeyByZXR1cm4gbCAhPT0gbGlzdGVuZXI7IH0pO1xufTtcbldvcmtmbG93QWJvcnRTaWduYWwucHJvdG90eXBlLnRocm93SWZBYm9ydGVkID0gZnVuY3Rpb24oKSB7XG4gIGlmICh0aGlzLmFib3J0ZWQpIHtcbiAgICB0aHJvdyB0aGlzLnJlYXNvbiAhPT0gdW5kZWZpbmVkICYmIHRoaXMucmVhc29uICE9PSBudWxsXG4gICAgICA/IHRoaXMucmVhc29uXG4gICAgICA6IF9fbWFrZUFib3J0RXJyb3IoKTtcbiAgfVxufTtcbi8vIEV4cG9zZSBmb3IgdGhlIGhvc3Qgc2VyZGUncyByZXZpdmVycyAodGhleSBsb29rIHRoZSBjbGFzcyB1cCBsYXppbHksXG4vLyB0aHJvdWdoIGEgaGFuZGxlLCBhdCByZXZpdmUgdGltZSkuXG5nbG9iYWxUaGlzLl9fV29ya2Zsb3dBYm9ydFNpZ25hbCA9IFdvcmtmbG93QWJvcnRTaWduYWw7XG5cbi8vIFJlZ2lzdHJ5IG9mIGxpdmUgYWJvcnQgc2lnbmFscyBrZXllZCBieSB0aGVpciBob29rIGNvcnJlbGF0aW9uSWQuIFRoZVxuLy8gaG9zdCBkZWxpdmVycyBob29rX3JlY2VpdmVkIGV2ZW50cyBmb3IgdGhlc2UgaWRzIGFzIF9zZXRBYm9ydGVkIGNhbGxzLlxuZ2xvYmFsVGhpcy5fX2Fib3J0U2lnbmFscyA9IHt9O1xuXG5nbG9iYWxUaGlzLkFib3J0Q29udHJvbGxlciA9IGZ1bmN0aW9uIFdvcmtmbG93QWJvcnRDb250cm9sbGVyKCkge1xuICB2YXIgaWQgPSBnbG9iYWxUaGlzLl9fZ2VuZXJhdGVVbGlkKCk7XG4gIHZhciBzdHJlYW1OYW1lID0gXCJzdHJtX1wiICsgaWQgKyBcIl9zeXN0ZW1fYWJvcnRcIjtcbiAgdmFyIGhvb2tUb2tlbiA9IFwiYWJydF9cIiArIGlkO1xuICB0aGlzW19fQUJPUlRfU1RSRUFNX05BTUVdID0gc3RyZWFtTmFtZTtcbiAgdGhpc1tfX0FCT1JUX0hPT0tfVE9LRU5dID0gaG9va1Rva2VuO1xuICB0aGlzLnNpZ25hbCA9IG5ldyBXb3JrZmxvd0Fib3J0U2lnbmFsKHN0cmVhbU5hbWUsIGhvb2tUb2tlbik7XG4gIHZhciBjb3JyZWxhdGlvbklkID0gXCJob29rX1wiICsgZ2xvYmFsVGhpcy5fX2dlbmVyYXRlVWxpZCgpO1xuICAvLyBSZWdpc3RlciBhbiBpbnRlcm5hbCBzeXN0ZW0gaG9vay4gaXNTeXN0ZW0gcHJldmVudHMgdG9rZW4gbmFtZXNwYWNlXG4gIC8vIGNvbmZsaWN0cyB3aXRoIHVzZXIgaG9va3MuXG4gIGdsb2JhbFRoaXMuX19wZW5kaW5nLnB1c2goe1xuICAgIHR5cGU6IFwiaG9va1wiLFxuICAgIGNvcnJlbGF0aW9uSWQ6IGNvcnJlbGF0aW9uSWQsXG4gICAgdG9rZW46IGhvb2tUb2tlbixcbiAgICBpc1dlYmhvb2s6IGZhbHNlLFxuICAgIGlzU3lzdGVtOiB0cnVlLFxuICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gIH0pO1xuICBnbG9iYWxUaGlzLl9fYWJvcnRTaWduYWxzW2NvcnJlbGF0aW9uSWRdID0gdGhpcy5zaWduYWw7XG59O1xuZ2xvYmFsVGhpcy5BYm9ydENvbnRyb2xsZXIucHJvdG90eXBlLmFib3J0ID0gZnVuY3Rpb24ocmVhc29uKSB7XG4gIGlmICh0aGlzLnNpZ25hbC5hYm9ydGVkKSByZXR1cm47IC8vIGFscmVhZHkgYWJvcnRlZCAoZS5nLiBmcm9tIHJlcGxheSlcbiAgdGhpcy5zaWduYWwuX3NldEFib3J0ZWQocmVhc29uKTtcbiAgLy8gTWFyayB0aGUgcGVuZGluZyBob29rIG9wIHNvIHRoZSBob3N0IHJlY29yZHMgdGhlIGFib3J0LiBUaGUgcGF5bG9hZFxuICAvLyBzdGF5cyBhIFJBVyB2YWx1ZTsgdGhlIGhvc3Qgc2VyaWFsaXplcyBpdCB0aHJvdWdoIGEgaGFuZGxlIHdpdGggZnVsbFxuICAvLyB0eXBlIGZpZGVsaXR5IChFcnJvcnMsIERPTUV4Y2VwdGlvbiwgY3VzdG9tIHZhbHVlcykuXG4gIHZhciB0b2tlbiA9IHRoaXNbX19BQk9SVF9IT09LX1RPS0VOXTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBnbG9iYWxUaGlzLl9fcGVuZGluZy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gZ2xvYmFsVGhpcy5fX3BlbmRpbmdbaV07XG4gICAgaWYgKGl0ZW0udHlwZSA9PT0gXCJob29rXCIgJiYgaXRlbS50b2tlbiA9PT0gdG9rZW4pIHtcbiAgICAgIGl0ZW0uYWJvcnRSZXF1ZXN0ZWQgPSB0cnVlO1xuICAgICAgaXRlbS5hYm9ydFBheWxvYWQgPSB7XG4gICAgICAgIGFib3J0ZWQ6IHRydWUsXG4gICAgICAgIHJlYXNvbjogcmVhc29uLFxuICAgICAgfTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcblxuZ2xvYmFsVGhpcy5BYm9ydFNpZ25hbCA9IHtcbiAgYWJvcnQ6IGZ1bmN0aW9uKHJlYXNvbikge1xuICAgIHZhciBzID0gbmV3IFdvcmtmbG93QWJvcnRTaWduYWwoXCJcIiwgXCJcIik7XG4gICAgcy5fc2V0QWJvcnRlZChyZWFzb24gIT09IHVuZGVmaW5lZCA/IHJlYXNvbiA6IF9fbWFrZUFib3J0RXJyb3IoKSk7XG4gICAgcmV0dXJuIHM7XG4gIH0sXG4gIGFueTogZnVuY3Rpb24oc2lnbmFscykge1xuICAgIHZhciBjb21wb3NpdGUgPSBuZXcgV29ya2Zsb3dBYm9ydFNpZ25hbChcIlwiLCBcIlwiKTtcbiAgICB2YXIgYXJyID0gQXJyYXkuZnJvbShzaWduYWxzKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltpXS5hYm9ydGVkKSB7XG4gICAgICAgIGNvbXBvc2l0ZS5fc2V0QWJvcnRlZChhcnJbaV0ucmVhc29uKTtcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgdmFyIGxpc3RlbmVycyA9IFtdO1xuICAgIHZhciBjbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxpc3RlbmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobGlzdGVuZXJzW2pdLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgbGlzdGVuZXJzW2pdLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgbGlzdGVuZXJzW2pdLmxpc3RlbmVyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbGlzdGVuZXJzLmxlbmd0aCA9IDA7XG4gICAgfTtcbiAgICBhcnIuZm9yRWFjaChmdW5jdGlvbihzaWduYWwpIHtcbiAgICAgIGlmICghc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIpIHJldHVybjtcbiAgICAgIHZhciBsaXN0ZW5lciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAoIWNvbXBvc2l0ZS5hYm9ydGVkKSB7XG4gICAgICAgICAgY29tcG9zaXRlLl9zZXRBYm9ydGVkKHNpZ25hbC5yZWFzb24pO1xuICAgICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGxpc3RlbmVycy5wdXNoKHsgc2lnbmFsOiBzaWduYWwsIGxpc3RlbmVyOiBsaXN0ZW5lciB9KTtcbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgbGlzdGVuZXIpO1xuICAgIH0pO1xuICAgIHJldHVybiBjb21wb3NpdGU7XG4gIH0sXG4gIHRpbWVvdXQ6IGZ1bmN0aW9uKCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIFwiQWJvcnRTaWduYWwudGltZW91dCgpIGlzIG5vdCBzdXBwb3J0ZWQgaW4gd29ya2Zsb3cgZnVuY3Rpb25zLiBcIiArXG4gICAgICAgIFwiVXNlIHNsZWVwKCkgd2l0aCBhbiBBYm9ydENvbnRyb2xsZXIgaW5zdGVhZC4gXCIgK1xuICAgICAgICBcIlNlZTogL2RvY3MvZXJyb3JzL2Fib3J0LXNpZ25hbC10aW1lb3V0LWluLXdvcmtmbG93XCJcbiAgICApO1xuICB9LFxufTtcblxuLy8gV09SS0ZMT1dfR0VUX1NUUkVBTV9JRCDigJQgZ2VuZXJhdGVzIGEgc3RyZWFtIElEIGZvciBhIHdvcmtmbG93IHJ1bi5cbi8vIFJlcGxpY2F0ZXMgZ2V0V29ya2Zsb3dSdW5TdHJlYW1JZCgpIGZyb20gdXRpbC50cyBpbnNpZGUgdGhlIFF1aWNrSlMgVk0uXG4vLyBVc2VzIHRoZSBidWlsdC1pbiBidG9hKCkgZm9yIGJhc2U2NHVybCBlbmNvZGluZy5cbmdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0dFVF9TVFJFQU1fSURcIildID0gZnVuY3Rpb24obmFtZXNwYWNlKSB7XG4gIHZhciBydW5JZCA9IGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0NPTlRFWFRcIildXG4gICAgPyBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19DT05URVhUXCIpXS53b3JrZmxvd1J1bklkXG4gICAgOiBcIlwiO1xuICB2YXIgc3RyZWFtSWQgPSBydW5JZC5yZXBsYWNlKFwid3J1bl9cIiwgXCJzdHJtX1wiKSArIFwiX3VzZXJcIjtcbiAgaWYgKCFuYW1lc3BhY2UpIHJldHVybiBzdHJlYW1JZDtcbiAgLy8gYmFzZTY0dXJsOiBidG9hIHRoZW4gcmVwbGFjZSArIHdpdGggLSwgLyB3aXRoIF8sIHN0cmlwID1cbiAgdmFyIGI2NCA9IGJ0b2EobmFtZXNwYWNlKS5yZXBsYWNlKC9cXFxcKy9nLCBcIi1cIikucmVwbGFjZSgvXFxcXC8vZywgXCJfXCIpLnJlcGxhY2UoLz0rJC8sIFwiXCIpO1xuICByZXR1cm4gc3RyZWFtSWQgKyBcIl9cIiArIGI2NDtcbn07XG5gO1xuXG4vLyAtLS0tIFJ1bnRpbWUgLS0tLVxuXG4vKipcbiAqIFBoYXNlIDE6IHN0YXRpYyAocnVuLWluZGVwZW5kZW50KSBWTSBpbml0aWFsaXphdGlvbi5cbiAqXG4gKiBDcmVhdGVzIGEgUXVpY2tKUyBWTSBhbmQgbG9hZHMgZXZlcnl0aGluZyB0aGF0IGRvZXMgbm90IGRlcGVuZCBvbiBhXG4gKiBzcGVjaWZpYyB3b3JrZmxvdyBydW46IHRoZSB3b3JrZmxvdy1wcmltaXRpdmUgYm9vdHN0cmFwICh1c2VTdGVwIC9cbiAqIHNsZWVwIC8gY3JlYXRlSG9vayAvIFJlc3BvbnNlLVJlcXVlc3QgcG9seWZpbGxzKS4gU2VyaWFsaXphdGlvbiBpc1xuICogaG9zdC1zaWRlIChxdWlja2pzLXNlcmRlLnRzKSBhbmQgY2FwdHVyZXMgaXRzIGludHJpbnNpY3MgZnJvbSB0aGUgVk1cbiAqIHJpZ2h0IGFmdGVyIHRoaXMgcmV0dXJucy5cbiAqXG4gKiBgZ2V0Tm93TXNgIGJhY2tzIHRoZSBWTSdzIFdBU0kgY2xvY2sgKGBEYXRlLm5vdygpYCAvIGBuZXcgRGF0ZSgpYFxuICogaW5zaWRlIHRoZSBWTSkuIFRoZSBjYWxsYmFjayBpdHNlbGYgaXMgc3RhdGljOiB0aGUgcGVyLXJ1biBzdGF0ZSBpdFxuICogcmVhZHMgbGl2ZXMgb24gdGhlIGhvc3QgYW5kIGlzIGFkdmFuY2VkIGFzIGV2ZW50cyBhcmUgY29uc3VtZWQsXG4gKiBtYXRjaGluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBkZXRlcm1pbmlzdGljIHJlcGxheSBjbG9jay5cbiAqXG4gKiBUaGlzIHBoYXNlIGlzIHRoZSBmdXR1cmUgYm91bmRhcnkgZm9yIFZNLW1lbW9yeSBzbmFwc2hvdHRpbmc6IGFcbiAqIGJ1aWxkLXRpbWUgc25hcHNob3QgY2FuIGNhcHR1cmUgdGhlIFZNIHJpZ2h0IGFmdGVyIHRoaXMgZnVuY3Rpb24gYW5kXG4gKiBuZXcgcnVucyBjYW4gcmVzdG9yZSBmcm9tIGl0IGluc3RlYWQgb2YgcGF5aW5nIFZNIGNyZWF0aW9uICsgZXZhbCBjb3N0XG4gKiAoYFF1aWNrSlMucmVzdG9yZWAgYWNjZXB0cyB0aGUgc2FtZSB3YXNpIG92ZXJyaWRlKS5cbiAqL1xuLyoqXG4gKiBMb29zZWx5LXR5cGVkIGFjY2Vzc29yIGZvciB0aGUgYFdlYkFzc2VtYmx5YCBnbG9iYWwuIFRoZSBwYWNrYWdlXG4gKiB0c2NvbmZpZydzIGBsaWI6IFtcImVzMjAyMlwiXWAgZG9lcyBub3QgaW5jbHVkZSB0aGUgRE9NIGxpYiB3aGVyZSB0aGVcbiAqIGBXZWJBc3NlbWJseWAgbmFtZXNwYWNlIHR5cGVzIGxpdmU7IHRoZSBydW50aW1lIGdsb2JhbCBpcyBhdmFpbGFibGUgb25cbiAqIGV2ZXJ5IFdBU00tY2FwYWJsZSBwbGF0Zm9ybSB0aGlzIGVuZ2luZSB0YXJnZXRzLlxuICovXG5jb25zdCBXZWJBc3NlbWJseUdsb2JhbCA9IChnbG9iYWxUaGlzIGFzIGFueSkuV2ViQXNzZW1ibHkgYXMge1xuICBjb21waWxlKGJ5dGVzOiBVaW50OEFycmF5KTogUHJvbWlzZTxvYmplY3Q+O1xufTtcblxudHlwZSBDb21waWxlZEV4dGVuc2lvbiA9IE9taXQ8RXh0ZW5zaW9uRGVzY3JpcHRvciwgJ3dhc20nPiAmIHtcbiAgd2FzbTogRXh0ZW5zaW9uRGVzY3JpcHRvclsnd2FzbSddO1xufTtcblxuLyoqXG4gKiBQcm9jZXNzLXdpZGUgY2FjaGUgb2YgdGhlIGNvbXBpbGVkIGBXZWJBc3NlbWJseS5Nb2R1bGVgcyBmb3IgdGhlIG1haW5cbiAqIFF1aWNrSlMgcnVudGltZSBhbmQgaXRzIG5hdGl2ZSBleHRlbnNpb25zLiBgV2ViQXNzZW1ibHkuY29tcGlsZWAgb2YgdGhlXG4gKiB+NjAwIEtCIHJ1bnRpbWUgYmluYXJ5IGlzIHRoZSBtb3N0IGV4cGVuc2l2ZSBwYXJ0IG9mIFZNIGNyZWF0aW9uIGFuZCBpc1xuICogcHVyZSAobm8gcGVyLVZNIHN0YXRlOiBpbnN0YW50aWF0aW9uIGJpbmRzIHRoZSBwZXItVk0gbWVtb3J5KSwgc28gaXRcbiAqIG9ubHkgbmVlZHMgdG8gaGFwcGVuIG9uY2UgcGVyIHByb2Nlc3MuIFRoZSBwcm9taXNlIGlzIGNhY2hlZCAobm90IHRoZVxuICogcmVzdWx0KSBzbyBjb25jdXJyZW50IGZpcnN0IGludm9jYXRpb25zIHNoYXJlIGEgc2luZ2xlIGNvbXBpbGF0aW9uLlxuICovXG4vLyBPbiBgZ2xvYmFsVGhpc2AgKHNlZSBgZ2xvYmFsU2luZ2xldG9uYCk6IHRoZSBjb21tZW50IGFib3ZlIHNheXMgb25jZSBwZXJcbi8vIHByb2Nlc3MsIGFuZCBtb2R1bGUgc2NvcGUgd291bGQgbWFrZSBpdCBvbmNlIHBlciBidW5kbGVyIGxheWVyLCByZWNvbXBpbGluZ1xuLy8gdGhlIH42MDAgS0IgcnVudGltZSBiaW5hcnkgZm9yIGVhY2guXG5jb25zdCBxdWlja2pzQXNzZXRzID0gZ2xvYmFsU2luZ2xldG9uKFxuICAnQHdvcmtmbG93L2NvcmUvL3F1aWNranNDb21waWxlZEFzc2V0cycsXG4gIDEsXG4gICgpID0+ICh7XG4gICAgcHJvbWlzZTogdW5kZWZpbmVkIGFzXG4gICAgICB8IFByb21pc2U8e1xuICAgICAgICAgIHdhc206IG9iamVjdDtcbiAgICAgICAgICBleHRlbnNpb25zOiBDb21waWxlZEV4dGVuc2lvbltdO1xuICAgICAgICB9PlxuICAgICAgfCB1bmRlZmluZWQsXG4gIH0pXG4pO1xuXG5mdW5jdGlvbiBnZXRDb21waWxlZEFzc2V0cygpIHtcbiAgaWYgKCFxdWlja2pzQXNzZXRzLnByb21pc2UpIHtcbiAgICBxdWlja2pzQXNzZXRzLnByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgW3dhc20sIC4uLmV4dGVuc2lvbk1vZHVsZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBXZWJBc3NlbWJseUdsb2JhbC5jb21waWxlKHF1aWNranNXYXNtKSxcbiAgICAgICAgLi4ucXVpY2tqc0V4dGVuc2lvbnMubWFwKChleHQpID0+XG4gICAgICAgICAgV2ViQXNzZW1ibHlHbG9iYWwuY29tcGlsZShleHQud2FzbSBhcyBVaW50OEFycmF5KVxuICAgICAgICApLFxuICAgICAgXSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB3YXNtLFxuICAgICAgICBleHRlbnNpb25zOiBxdWlja2pzRXh0ZW5zaW9ucy5tYXAoKGV4dCwgaSkgPT4gKHtcbiAgICAgICAgICAuLi5leHQsXG4gICAgICAgICAgd2FzbTogZXh0ZW5zaW9uTW9kdWxlc1tpXSBhcyBFeHRlbnNpb25EZXNjcmlwdG9yWyd3YXNtJ10sXG4gICAgICAgIH0pKSxcbiAgICAgIH07XG4gICAgfSkoKTtcbiAgICAvLyBPbiBmYWlsdXJlLCBjbGVhciB0aGUgY2FjaGUgc28gYSBsYXRlciBpbnZvY2F0aW9uIGNhbiByZXRyeSByYXRoZXJcbiAgICAvLyB0aGFuIGJlaW5nIHN0dWNrIHdpdGggYSByZWplY3RlZCBwcm9taXNlIGZvcmV2ZXIuXG4gICAgcXVpY2tqc0Fzc2V0cy5wcm9taXNlLmNhdGNoKCgpID0+IHtcbiAgICAgIHF1aWNranNBc3NldHMucHJvbWlzZSA9IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gcXVpY2tqc0Fzc2V0cy5wcm9taXNlO1xufVxuXG4vKipcbiAqIFdBU0kgY2xvY2sgb3ZlcnJpZGUgcmVhZGluZyB0aGUgZ2l2ZW4gYWNjZXNzb3IsIHNoYXJlZCBiZXR3ZWVuIGZyZXNoXG4gKiBib290cyAoaW5pdFdvcmtmbG93Vk0pIGFuZCBiYXNlbGluZS1zbmFwc2hvdCByZXN0b3Jlcywgc28gdGhlIHR3b1xuICogcGF0aHMgY2Fubm90IGRyaWZ0IG9uIHJvdW5kaW5nL2VuY29kaW5nLlxuICpcbiAqIERldGVybWluaXN0aWMgcmVwbGF5IGNsb2NrOiBEYXRlLm5vdygpIC8gbmV3IERhdGUoKSBpbnNpZGUgdGhlIFZNXG4gKiByZWFkIHRoZSBob3N0LWNvbnRyb2xsZWQgY2xvY2sgaW5zdGVhZCBvZiB3YWxsIHRpbWUuIFJlcGxheVxuICogcmUtZXhlY3V0ZXMgdGhlIHdvcmtmbG93IGZyb20gdGhlIHRvcCBvbiBldmVyeSBpbnZvY2F0aW9uLCBzbyB0aGVcbiAqIGNsb2NrIG11c3QgYmUgZGVyaXZlZCBmcm9tIHRoZSBldmVudCBsb2cgKG5vdCByZWFsIHRpbWUpIGZvciB0aGVcbiAqIHdvcmtmbG93IHRvIG9ic2VydmUgc3RhYmxlIHRpbWVzdGFtcHMgYWNyb3NzIGludm9jYXRpb25zLlxuICovXG5mdW5jdGlvbiBtYWtlRGV0ZXJtaW5pc3RpY0Nsb2NrV2FzaShnZXROb3dNczogKCkgPT4gbnVtYmVyKTogV2FzaU9wdGlvbnMge1xuICByZXR1cm4gKG1lbW9yeSkgPT4gKHtcbiAgICBjbG9ja190aW1lX2dldChfY2xvY2tJZDogbnVtYmVyLCBfcHJlY2lzaW9uOiBiaWdpbnQsIHJlc3VsdFB0cjogbnVtYmVyKSB7XG4gICAgICBjb25zdCB0aW1lTnMgPSBCaWdJbnQoTWF0aC5yb3VuZChnZXROb3dNcygpKSkgKiAxXzAwMF8wMDBuO1xuICAgICAgbmV3IERhdGFWaWV3KG1lbW9yeS5idWZmZXIpLnNldEJpZ1VpbnQ2NChyZXN1bHRQdHIsIHRpbWVOcywgdHJ1ZSk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9LFxuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaW5pdFdvcmtmbG93Vk0oXG4gIGdldE5vd01zOiAoKSA9PiBudW1iZXIsXG4gIGludGVycnVwdEJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0XG4pOiBQcm9taXNlPFF1aWNrSlM+IHtcbiAgY29uc3QgYXNzZXRzID0gYXdhaXQgZ2V0Q29tcGlsZWRBc3NldHMoKTtcbiAgY29uc3Qgdm0gPSBhd2FpdCBRdWlja0pTLmNyZWF0ZSh7XG4gICAgd2FzbTogYXNzZXRzLndhc20gYXMgbmV2ZXIsXG4gICAgbWVtb3J5TGltaXQ6IDI1NiAqIDEwMjQgKiAxMDI0LFxuICAgIGludGVycnVwdEhhbmRsZXI6IGNyZWF0ZUludGVycnVwdEhhbmRsZXIoaW50ZXJydXB0QnVkZ2V0KSxcbiAgICBleHRlbnNpb25zOiBhc3NldHMuZXh0ZW5zaW9ucyxcbiAgICB3YXNpOiBtYWtlRGV0ZXJtaW5pc3RpY0Nsb2NrV2FzaShnZXROb3dNcyksXG4gIH0pO1xuXG4gIC8vIEJvb3RzdHJhcCB3b3JrZmxvdyBwcmltaXRpdmVzXG4gIHZtLmV2YWxDb2RlKFZNX0JPT1RTVFJBUCwgJ2Jvb3RzdHJhcC5qcycpLmRpc3Bvc2UoKTtcblxuICByZXR1cm4gdm07XG59XG5cbi8vIC0tLS0gQmFzZWxpbmUgc25hcHNob3QgKHN0YXJ0dXAgb3B0aW1pemF0aW9uKSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy9cbi8vIEV2YWx1YXRpbmcgdGhlIHdvcmtmbG93IGJ1bmRsZSBkb21pbmF0ZXMgVk0gc3RhcnR1cCAofjc0bXMgb2YgYSB+Nzdtc1xuLy8gYm9vdCBmb3IgYSAxLjNNQiBidW5kbGUpLCBhbmQgZnVsbCBldmVudCByZXBsYXkgcGF5cyBpdCBvbiBFVkVSWVxuLy8gaW52b2NhdGlvbi4gVGhlIGJ1bmRsZSBpcyBpZGVudGljYWwgYWNyb3NzIGFsbCBydW5zIG9mIGEgZGVwbG95bWVudCwgc29cbi8vIHRoZSBlbmdpbmUgaHlkcmF0ZXMgb25lIFZNIHBlciBmdW5jdGlvbiBpbnN0YW5jZSAoYm9vdHN0cmFwICsgYnVuZGxlXG4vLyBldmFsKSwgc25hcHNob3RzIGl0cyBtZW1vcnksIGFuZCBzdGFydHMgZXZlcnkgaW52b2NhdGlvbiBieSByZXN0b3Jpbmdcbi8vIHRoZSBzbmFwc2hvdCAofjNtcykgaW5zdGVhZCBvZiByZS1ldmFsdWF0aW5nLlxuLy9cbi8vIERldGVybWluaXNtOiByZXBsYXkgcmVxdWlyZXMgbW9kdWxlLXNjb3BlIHVzZXIgY29kZSB0byBvYnNlcnZlIHRoZVxuLy8gcnVuLXNlZWRlZCBQUk5HIGFuZCB0aGUgcnVuJ3MgZGV0ZXJtaW5pc3RpYyBjbG9jay4gQSByZXN0b3JlZCBoZWFwXG4vLyBjYXJyaWVzIHdoYXRldmVyIG1vZHVsZSBzY29wZSBjb21wdXRlZCBhdCBIWURSQVRFIHRpbWUsIHNvIHRoZVxuLy8gb3B0aW1pemF0aW9uIGlzIG9ubHkgc291bmQgd2hlbiBtb2R1bGUgc2NvcGUgY29uc3VtZWQgbmVpdGhlclxuLy8gcmFuZG9tbmVzcyBub3IgdGltZS4gQm90aCBhcmUgZGV0ZWN0ZWQgZHVyaW5nIGh5ZHJhdGUgKHRoZSBwbGFjZWhvbGRlclxuLy8gaG9zdCBmbnMgY291bnQgZHJhd3MsIHRoZSBoeWRyYXRlIGNsb2NrIGNvdW50cyByZWFkcykgYW5kIGEgYnVuZGxlXG4vLyB0aGF0IHVzZWQgZWl0aGVyIGlzIG1hcmtlZCBpbmVsaWdpYmxlOiBldmVyeSBpbnZvY2F0aW9uIGZhbGxzIGJhY2sgdG9cbi8vIGZyZXNoIGV2YWx1YXRpb24sIHByZXNlcnZpbmcgZXhhY3Qgbm9kZTp2bS1wYXJpdHkgc2VtYW50aWNzLiBXaGVuIHRoZVxuLy8gZ2F0ZSBwYXNzZXMsIHJlc3RvcmUgaXMgYnl0ZS1lcXVpdmFsZW50IHRvIGZyZXNoIGV2YWwgKHZlcmlmaWVkIGJ5IHRoZVxuLy8gcGFyaXR5IHRlc3RzKTogdGhlIHBlci1ydW4gaG9zdCBmbnMgYXJlIHJlLXJlZ2lzdGVyZWQgYnkgbmFtZSBvbiB0aGVcbi8vIHJlc3RvcmVkIFZNIChxdWlja2pzLXdhc2kgcmVzdG9yZSBzZW1hbnRpY3MpIGJlZm9yZSB0aGUgd29ya2Zsb3cgYm9keVxuLy8gcnVucywgc28gdGhlIHNlZWRlZCBkcmF3IHNlcXVlbmNlIChhbmQgZXZlcnkgY29ycmVsYXRpb25JZCkgaXNcbi8vIGlkZW50aWNhbC5cbi8vXG4vLyBUaGUgY2FjaGUgaXMgcGVyIGZ1bmN0aW9uIGluc3RhbmNlIGFuZCBrZXllZCBvbiB0aGUgYnVuZGxlIHN0cmluZ1xuLy8gKHJlZmVyZW5jZS1zdGFibGU6IHRoZSBnZW5lcmF0ZWQgZmxvdyByb3V0ZSBob2xkcyBpdCBpbiBhIG1vZHVsZS1sZXZlbFxuLy8gY29uc3QpLiBDYXBwZWQgYXQgYSBmZXcgZW50cmllcyBzbyB0ZXN0cyB3aXRoIG1hbnkgZGlzdGluY3QgYnVuZGxlc1xuLy8gZG9uJ3QgYWNjdW11bGF0ZSAxNk1CIHNuYXBzaG90cy5cblxuLyoqXG4gKiBFdmFsIGZpbGVuYW1lIHVzZWQgd2hlbiBoeWRyYXRpbmcgdGhlIGJhc2VsaW5lIFZNLiBUaGUgYmFzZWxpbmUgaXNcbiAqIHNoYXJlZCBieSBFVkVSWSB3b3JrZmxvdyBpbiB0aGUgYnVuZGxlLCBzbyB0aGUgZmlsZW5hbWUgYmFrZWQgaW50b1xuICogaXRzIGNvbXBpbGVkIGNvZGUgKGFuZCB0aGVyZWZvcmUgaW50byBzbmFwc2hvdC1wYXRoIHN0YWNrIGZyYW1lcylcbiAqIG11c3QgYmUgd29ya2Zsb3ctaW5kZXBlbmRlbnQ6IGh5ZHJhdGluZyB1bmRlciB0aGUgZmlyc3QgY2FsbGVyJ3NcbiAqIHdvcmtmbG93SWQgd291bGQgYnJlYWsgYHJlbWFwRXJyb3JTdGFja2AncyBmaWxlbmFtZSBtYXRjaGluZyBmb3JcbiAqIGV2ZXJ5IG90aGVyIHdvcmtmbG93IGluIHRoZSBidW5kbGUuIFJlbWFwIGNhbGwgc2l0ZXMgbWF0Y2ggdGhpc1xuICogY29uc3RhbnQgSU4gQURESVRJT04gdG8gdGhlIHJ1bidzIG1vZHVsZSBzcGVjaWZpZXIgKHdoaWNoIGNvdmVyc1xuICogZnJlc2gtcGF0aCBmcmFtZXMpLlxuICovXG5leHBvcnQgY29uc3QgQkFTRUxJTkVfQlVORExFX0ZJTEVOQU1FID0gJ3dvcmtmbG93LWJ1bmRsZS5qcyc7XG5cbnR5cGUgQmFzZWxpbmVFbnRyeSA9XG4gIHwge1xuICAgICAgc3RhdGU6ICdyZWFkeSc7XG4gICAgICBzbmFwc2hvdDogU25hcHNob3Q7XG4gICAgICAvKipcbiAgICAgICAqIFJhdyBib3ggcG9pbnRlciBvZiB0aGUgc2VyZGUgY2FwdHVyZSByb290IGNyZWF0ZWQgQkVGT1JFIHRoZVxuICAgICAgICogYnVuZGxlIGV2YWx1YXRlZCAoc2VlIGNhcHR1cmVTZXJkZVJvb3QpLiBUaGUgYm94IGxpdmVzIGluIHRoZVxuICAgICAgICogc25hcHNob3QncyBtZW1vcnkgaW1hZ2UgYXQgdGhpcyBvZmZzZXQ7IGV2ZXJ5IHJlc3RvcmVkIFZNXG4gICAgICAgKiByZS1hZG9wdHMgaXQgc28gc2VyZGUgaW5pdGlhbGl6YXRpb24gZXhlY3V0ZXMgbm8gZ3Vlc3QgY29kZVxuICAgICAgICogYWZ0ZXIgdXNlciBjb2RlIGhhcyBydW46IGNhcHR1cmUtYmVmb3JlLXVzZXItY29kZSBzZW1hbnRpY3MsXG4gICAgICAgKiBpZGVudGljYWwgdG8gdGhlIGZyZXNoIHBhdGguXG4gICAgICAgKi9cbiAgICAgIHNlcmRlUm9vdFB0cjogbnVtYmVyO1xuICAgIH1cbiAgfCB7IHN0YXRlOiAnaW5lbGlnaWJsZSc7IHJlYXNvbjogc3RyaW5nIH07XG5cbi8vIE9uIGBnbG9iYWxUaGlzYCAoc2VlIGBnbG9iYWxTaW5nbGV0b25gKTogYSBzbmFwc2hvdCBpcyBleHBlbnNpdmUgdG8gYnVpbGQgYW5kXG4vLyBpcyBrZXllZCBieSBidW5kbGUsIHNvIHBlci1jb3B5IGNhY2hlcyB3b3VsZCBidWlsZCB0aGUgc2FtZSBiYXNlbGluZSBvbmNlIHBlclxuLy8gYnVuZGxlciBsYXllciB3aGlsZSBlYWNoIGVuZm9yY2luZyBpdHMgb3duIGJvdW5kLlxuY29uc3QgYmFzZWxpbmVzID0gZ2xvYmFsU2luZ2xldG9uKFxuICAnQHdvcmtmbG93L2NvcmUvL3F1aWNranNCYXNlbGluZXMnLFxuICAxLFxuICAoKSA9PiAoe1xuICAgIGJ5S2V5OiBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxCYXNlbGluZUVudHJ5Pj4oKSxcbiAgfSlcbik7XG5jb25zdCBCQVNFTElORV9DQUNIRV9NQVhfRU5UUklFUyA9IDQ7XG5cbi8qKiBUZXN0LW9ubHk6IHJlc2V0IHRoZSBiYXNlbGluZSBjYWNoZSBiZXR3ZWVuIHRlc3QgY2FzZXMuICovXG5leHBvcnQgZnVuY3Rpb24gX19jbGVhckJhc2VsaW5lU25hcHNob3RDYWNoZUZvclRlc3RzKCk6IHZvaWQge1xuICBiYXNlbGluZXMuYnlLZXkuY2xlYXIoKTtcbn1cblxuLyoqIFRlc3Qtb25seTogb2JzZXJ2ZSBob3cgYSBidW5kbGUgd2FzIGNsYXNzaWZpZWQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gX19wZWVrQmFzZWxpbmVFbnRyeUZvclRlc3RzKFxuICB3b3JrZmxvd0NvZGU6IHN0cmluZ1xuKTogUHJvbWlzZTxCYXNlbGluZUVudHJ5IHwgdW5kZWZpbmVkPiB7XG4gIHJldHVybiBiYXNlbGluZXMuYnlLZXkuZ2V0KHdvcmtmbG93Q29kZSk7XG59XG5cbi8qKlxuICogSHlkcmF0ZSBhIFZNIHdpdGggdGhlIHdvcmtmbG93IGJ1bmRsZSBhbmQgc25hcHNob3QgaXQsIGdhdGluZyBvblxuICogbW9kdWxlLXNjb3BlIG5vbmRldGVybWluaXNtIChzZWUgdGhlIHNlY3Rpb24gY29tbWVudCBhYm92ZSkuIFJldHVybnMgYW5cbiAqIGBpbmVsaWdpYmxlYCBlbnRyeSBpbnN0ZWFkIG9mIHRocm93aW5nIG9uIGV2YWwgZmFpbHVyZTogdGhlIGZyZXNoIHBhdGhcbiAqIHJlLWV2YWx1YXRlcyBhbmQgcHJvZHVjZXMgdGhlIHJlYWwsIHNvdXJjZS1tYXBwZWQgZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHByZXBhcmVCYXNlbGluZVNuYXBzaG90KFxuICB3b3JrZmxvd0NvZGU6IHN0cmluZyxcbiAgd29ya2Zsb3dJZDogc3RyaW5nXG4pOiBQcm9taXNlPEJhc2VsaW5lRW50cnk+IHtcbiAgY29uc3QgaHlkcmF0ZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgbGV0IGNsb2NrUmVhZHMgPSAwO1xuICBjb25zdCBidWRnZXQ6IEludGVycnVwdEJ1ZGdldCA9IHsgc3RhcnQ6IERhdGUubm93KCkgfTtcbiAgY29uc3QgYXNzZXRzID0gYXdhaXQgZ2V0Q29tcGlsZWRBc3NldHMoKTtcbiAgY29uc3Qgdm0gPSBhd2FpdCBRdWlja0pTLmNyZWF0ZSh7XG4gICAgd2FzbTogYXNzZXRzLndhc20gYXMgbmV2ZXIsXG4gICAgbWVtb3J5TGltaXQ6IDI1NiAqIDEwMjQgKiAxMDI0LFxuICAgIGludGVycnVwdEhhbmRsZXI6IGNyZWF0ZUludGVycnVwdEhhbmRsZXIoYnVkZ2V0KSxcbiAgICBleHRlbnNpb25zOiBhc3NldHMuZXh0ZW5zaW9ucyxcbiAgICB3YXNpOiAoKG1lbW9yeSkgPT4gKHtcbiAgICAgIGNsb2NrX3RpbWVfZ2V0KF9jbG9ja0lkOiBudW1iZXIsIF9wcmVjaXNpb246IGJpZ2ludCwgcmVzdWx0UHRyOiBudW1iZXIpIHtcbiAgICAgICAgY2xvY2tSZWFkcysrO1xuICAgICAgICBjb25zdCB0aW1lTnMgPSBCaWdJbnQoaHlkcmF0ZVN0YXJ0KSAqIDFfMDAwXzAwMG47XG4gICAgICAgIG5ldyBEYXRhVmlldyhtZW1vcnkuYnVmZmVyKS5zZXRCaWdVaW50NjQocmVzdWx0UHRyLCB0aW1lTnMsIHRydWUpO1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH0sXG4gICAgfSkpIHNhdGlzZmllcyBXYXNpT3B0aW9ucyxcbiAgfSk7XG4gIHRyeSB7XG4gICAgdm0uZXZhbENvZGUoVk1fQk9PVFNUUkFQLCAnYm9vdHN0cmFwLmpzJykuZGlzcG9zZSgpO1xuXG4gICAgLy8gUGxhY2Vob2xkZXIgaG9zdCBmbnMgdW5kZXIgdGhlIFNBTUUgTkFNRVMgdGhlIHBlci1ydW4gcGhhc2UgdXNlcy5cbiAgICAvLyBUaGV5IGV4aXN0IHNvIG1vZHVsZS1zY29wZSBjb2RlIGNhbiBleGVjdXRlIGF0IGh5ZHJhdGUgdGltZSwgYW5kIHRvXG4gICAgLy8gZGV0ZWN0IHRoYXQgaXQgZGlkOiBhbnkgZHJhdyBtZWFucyB0aGUgaGVhcCB3b3VsZCBiYWtlXG4gICAgLy8gaHlkcmF0ZS1zZWVkZWQgdmFsdWVzIHRoYXQgcGVyLXJ1biBmcmVzaCBldmFsIHdvdWxkIGNvbXB1dGVcbiAgICAvLyBkaWZmZXJlbnRseS4gcnVuV29ya2Zsb3dJblZNIHJlLXJlZ2lzdGVycyBhbGwgdGhyZWUgbmFtZXMgd2l0aCB0aGVcbiAgICAvLyBydW4tc2VlZGVkIGNsb3N1cmVzIGFmdGVyIHJlc3RvcmUuXG4gICAgbGV0IGRyYXdzID0gMDtcbiAgICB7XG4gICAgICB1c2luZyByYW5kb21GbiA9IHZtLm5ld0Z1bmN0aW9uKCdyYW5kb20nLCAoKSA9PiB7XG4gICAgICAgIGRyYXdzKys7XG4gICAgICAgIHJldHVybiB2bS5uZXdOdW1iZXIoTWF0aC5yYW5kb20oKSk7XG4gICAgICB9KTtcbiAgICAgIHVzaW5nIG1hdGggPSB2bS5nbG9iYWwuZ2V0UHJvcCgnTWF0aCcpO1xuICAgICAgbWF0aC5zZXRQcm9wKCdyYW5kb20nLCByYW5kb21Gbik7XG4gICAgICB1c2luZyBuYW5vaWRGbiA9IHZtLm5ld0Z1bmN0aW9uKCdfX2dlbmVyYXRlTmFub2lkJywgKCkgPT4ge1xuICAgICAgICBkcmF3cysrO1xuICAgICAgICByZXR1cm4gdm0ubmV3U3RyaW5nKCdiYXNlbGluZS1wbGFjZWhvbGRlcicpO1xuICAgICAgfSk7XG4gICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fZ2VuZXJhdGVOYW5vaWQnLCBuYW5vaWRGbik7XG4gICAgICB1c2luZyB1bGlkRm4gPSB2bS5uZXdGdW5jdGlvbignX19nZW5lcmF0ZVVsaWQnLCAoKSA9PiB7XG4gICAgICAgIGRyYXdzKys7XG4gICAgICAgIHJldHVybiB2bS5uZXdTdHJpbmcoJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyk7XG4gICAgICB9KTtcbiAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX19nZW5lcmF0ZVVsaWQnLCB1bGlkRm4pO1xuICAgIH1cblxuICAgIC8vIFNlcmRlIGNhcHR1cmUgcm9vdDogY3JlYXRlZCBCRUZPUkUgdGhlIGJ1bmRsZSBldmFsdWF0ZXMsIGV4YWN0bHlcbiAgICAvLyBsaWtlIHRoZSBmcmVzaCBwYXRoJ3MgY2FwdHVyZS4gSXRzIGJveCBwb2ludGVyIHJpZGVzIHRoZVxuICAgIC8vIEJhc2VsaW5lRW50cnkgYW5kIGVhY2ggcmVzdG9yZWQgVk0gcmUtYWRvcHRzIGl0LCBzbyBzZXJkZVxuICAgIC8vIGluaXRpYWxpemF0aW9uIG5ldmVyIGV4ZWN1dGVzIGd1ZXN0IGNvZGUgYWZ0ZXIgdXNlciBjb2RlIGhhcyBydW4uXG4gICAgLy8gVGhpcyBpcyB3aGF0IG1ha2VzIG1vZHVsZS1zY29wZSBpbnRyaW5zaWMgcGF0Y2hpbmcgKHBvbHlmaWxscyxcbiAgICAvLyBzdGF0ZWZ1bCB3cmFwcGVycyBhcm91bmQgT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvciwg4oCmKVxuICAgIC8vIEhBUk1MRVNTIG9uIHRoZSBzbmFwc2hvdCBwYXRoIHJhdGhlciB0aGFuIG1lcmVseSBkZXRlY3RhYmxlOiB0aGVcbiAgICAvLyBzZXJkZSB1c2VzIHRoZSBwcmlzdGluZSBwcmUtZXZhbCBjYXB0dXJlcyBvbiBib3RoIHBhdGhzLCBhbmQgbm9cbiAgICAvLyBwb3N0LWV2YWwgcHJvYmUgZXhpc3RzIHdob3NlIHNpZGUgZWZmZWN0cyBjb3VsZCBiYWtlIGludG8gdGhlXG4gICAgLy8gc25hcHNob3QuIFRoZSBoYW5kbGUgaXMgZGVsaWJlcmF0ZWx5IE5PVCBkaXNwb3NlZCBiZWZvcmUgdGhlXG4gICAgLy8gc25hcHNob3Q6IHRoZSBib3ggbXVzdCBzdGF5IGxpdmUgaW4gdGhlIG1lbW9yeSBpbWFnZSAodGhlXG4gICAgLy8gYmFzZWxpbmUgVk0ncyBkaXNwb3NlIGJlbG93IHRlYXJzIGRvd24gdGhlIHdob2xlIGluc3RhbmNlIHdpdGhvdXRcbiAgICAvLyBmcmVlaW5nIGluZGl2aWR1YWwgYm94ZXMpLlxuICAgIGNvbnN0IHNlcmRlUm9vdCA9IGNhcHR1cmVTZXJkZVJvb3Qodm0pO1xuXG4gICAgY2xvY2tSZWFkcyA9IDA7IC8vIG9ubHkgY291bnQgcmVhZHMgbWFkZSBieSB0aGUgYnVuZGxlIGl0c2VsZlxuICAgIHRyeSB7XG4gICAgICAvLyBXb3JrZmxvdy1pbmRlcGVuZGVudCBmaWxlbmFtZS4gU2VlIEJBU0VMSU5FX0JVTkRMRV9GSUxFTkFNRS5cbiAgICAgIHZtLmV2YWxDb2RlKHdvcmtmbG93Q29kZSwgQkFTRUxJTkVfQlVORExFX0ZJTEVOQU1FKS5kaXNwb3NlKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBMZXQgdGhlIGZyZXNoIHBhdGggcmUtZXZhbHVhdGUgYW5kIHN1cmZhY2UgdGhlIHJlYWwgZXJyb3Igd2l0aFxuICAgICAgLy8gcHJvcGVyIGZpbGVuYW1lIC8gc291cmNlLW1hcCBoYW5kbGluZy5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN0YXRlOiAnaW5lbGlnaWJsZScsXG4gICAgICAgIHJlYXNvbjogJ21vZHVsZSBzY29wZSB0aHJldyBkdXJpbmcgaHlkcmF0ZScsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChkcmF3cyA+IDAgfHwgY2xvY2tSZWFkcyA+IDApIHtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgJ1F1aWNrSlMgYmFzZWxpbmUgc25hcHNob3QgZGlzYWJsZWQgZm9yIHRoaXMgYnVuZGxlOiBtb2R1bGUgc2NvcGUgY29uc3VtZWQgbm9uZGV0ZXJtaW5pc3RpYyBpbnB1dHM7IGV2ZXJ5IGludm9jYXRpb24gd2lsbCBldmFsdWF0ZSB0aGUgYnVuZGxlIGZyZXNoJyxcbiAgICAgICAgeyB3b3JrZmxvd0lkLCBkcmF3cywgY2xvY2tSZWFkcyB9XG4gICAgICApO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3RhdGU6ICdpbmVsaWdpYmxlJyxcbiAgICAgICAgcmVhc29uOiBgbW9kdWxlIHNjb3BlIGNvbnN1bWVkICR7ZHJhd3N9IFBSTkcgZHJhdyhzKSBhbmQgJHtjbG9ja1JlYWRzfSBjbG9jayByZWFkKHMpYCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3Qgc25hcHNob3QgPSB2bS5zbmFwc2hvdCgpO1xuICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgYmFzZWxpbmUgc25hcHNob3QgcHJlcGFyZWQnLCB7XG4gICAgICB3b3JrZmxvd0lkLFxuICAgICAgaHlkcmF0ZU1zOiBEYXRlLm5vdygpIC0gaHlkcmF0ZVN0YXJ0LFxuICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICBzdGF0ZTogJ3JlYWR5JyxcbiAgICAgIHNuYXBzaG90LFxuICAgICAgc2VyZGVSb290UHRyOiBleHBvcnRTZXJkZVJvb3Qodm0sIHNlcmRlUm9vdCksXG4gICAgfTtcbiAgfSBmaW5hbGx5IHtcbiAgICB2bS5kaXNwb3NlKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDYWNoZWQgYmFzZWxpbmUgZW50cnkgZm9yIGEgYnVuZGxlLCBwcmVwYXJpbmcgaXQgb24gZmlyc3QgYWNjZXNzLlxuICogQ29uY3VycmVudCBmaXJzdCBpbnZvY2F0aW9ucyBzaGFyZSBvbmUgaHlkcmF0ZSB2aWEgdGhlIGNhY2hlZCBwcm9taXNlO1xuICogYSBoeWRyYXRlIHRoYXQgUkVKRUNUUyAoaW5mcmFzdHJ1Y3R1cmUgZmFpbHVyZSwgbm90IGJ1bmRsZSBldmFsLCB3aGljaFxuICogcmV0dXJucyBgaW5lbGlnaWJsZWApIGlzIGV2aWN0ZWQgc28gYSBsYXRlciBpbnZvY2F0aW9uIGNhbiByZXRyeS5cbiAqL1xuZnVuY3Rpb24gZ2V0QmFzZWxpbmVFbnRyeShcbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmcsXG4gIHdvcmtmbG93SWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxCYXNlbGluZUVudHJ5PiB7XG4gIGxldCBlbnRyeSA9IGJhc2VsaW5lcy5ieUtleS5nZXQod29ya2Zsb3dDb2RlKTtcbiAgaWYgKCFlbnRyeSkge1xuICAgIGlmIChiYXNlbGluZXMuYnlLZXkuc2l6ZSA+PSBCQVNFTElORV9DQUNIRV9NQVhfRU5UUklFUykge1xuICAgICAgY29uc3Qgb2xkZXN0ID0gYmFzZWxpbmVzLmJ5S2V5LmtleXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICBpZiAob2xkZXN0ICE9PSB1bmRlZmluZWQpIGJhc2VsaW5lcy5ieUtleS5kZWxldGUob2xkZXN0KTtcbiAgICB9XG4gICAgZW50cnkgPSBwcmVwYXJlQmFzZWxpbmVTbmFwc2hvdCh3b3JrZmxvd0NvZGUsIHdvcmtmbG93SWQpO1xuICAgIGJhc2VsaW5lcy5ieUtleS5zZXQod29ya2Zsb3dDb2RlLCBlbnRyeSk7XG4gICAgZW50cnkuY2F0Y2goKCkgPT4gYmFzZWxpbmVzLmJ5S2V5LmRlbGV0ZSh3b3JrZmxvd0NvZGUpKTtcbiAgfVxuICByZXR1cm4gZW50cnk7XG59XG5cbi8qKlxuICogQSBsaXZlIFF1aWNrSlMgd29ya2Zsb3cgaW52b2NhdGlvbi4gV2hlbiB0aGUgaW5pdGlhbCBgcmVzdWx0YCBpc1xuICogYHN1c3BlbmRlZGAsIHRoZSBWTSBpcyBrZXB0IGFsaXZlIHNvIHRoZSBjYWxsZXIgY2FuIGZlZWQgbmV3bHkgcmVjb3JkZWRcbiAqIGV2ZW50cyAoZS5nLiB0ZXJtaW5hbCBldmVudHMgb2YgaW5saW5lLWV4ZWN1dGVkIHN0ZXBzKSBpbnRvIHRoZSBTQU1FIFZNXG4gKiB2aWEgYGNvbnRpbnVlV2l0aEV2ZW50c2AsIHJlc3VtaW5nIGV4ZWN1dGlvbiBleGFjdGx5IHdoZXJlIGl0IGxlZnQgb2ZmXG4gKiB3aXRob3V0IGEgZnJlc2gtVk0gcmUtcmVwbGF5LiBUZXJtaW5hbCByZXN1bHRzIGRpc3Bvc2UgdGhlIFZNXG4gKiBhdXRvbWF0aWNhbGx5OyBgZGlzcG9zZSgpYCBtdXN0IGJlIGNhbGxlZCB3aGVuIGFiYW5kb25pbmcgYSBzdXNwZW5kZWRcbiAqIHNlc3Npb24gKGlkZW1wb3RlbnQpLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFF1aWNrSlNXb3JrZmxvd1Nlc3Npb24ge1xuICByZXN1bHQ6IFF1aWNrSlNSdW50aW1lUmVzdWx0O1xuICAvKipcbiAgICogUHJvY2VzcyBuZXdseSByZWNvcmRlZCBldmVudHMgaW4gdGhlIGxpdmUgVk0gYW5kIHJlLWV2YWx1YXRlIHRoZVxuICAgKiB3b3JrZmxvdyBzdGF0ZS4gT25seSB2YWxpZCB3aGlsZSB0aGUgbGFzdCByZXN1bHQgd2FzIGBzdXNwZW5kZWRgLlxuICAgKiBSZXNldHMgdGhlIFZNJ3MgaW50ZXJydXB0IGJ1ZGdldCBmb3IgdGhlIG5ldyBleGVjdXRpb24gYnVyc3QuXG4gICAqL1xuICBjb250aW51ZVdpdGhFdmVudHMobmV3RXZlbnRzOiBFdmVudFtdKTogUHJvbWlzZTxRdWlja0pTUnVudGltZVJlc3VsdD47XG4gIC8qKiBEaXNwb3NlIHRoZSBWTSBpZiBpdCBpcyBzdGlsbCBhbGl2ZS4gU2FmZSB0byBjYWxsIG11bHRpcGxlIHRpbWVzLiAqL1xuICBkaXNwb3NlKCk6IHZvaWQ7XG59XG5cbi8qKlxuICogUnVuIGEgd29ya2Zsb3cgaW52b2NhdGlvbiB0byBpdHMgZmlyc3Qgc2V0dGxlZCBzdGF0ZSBhbmQgZGlzcG9zZSB0aGVcbiAqIFZNLiBDb252ZW5pZW5jZSB3cmFwcGVyIG92ZXIge0BsaW5rIHN0YXJ0UXVpY2tKU1dvcmtmbG93fSBmb3IgY2FsbGVyc1xuICogKGFuZCB0ZXN0cykgdGhhdCBkb24ndCB1c2UgbGl2ZS1WTSBjb250aW51YXRpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5RdWlja0pTV29ya2Zsb3coXG4gIG9wdGlvbnM6IFF1aWNrSlNSdW50aW1lT3B0aW9uc1xuKTogUHJvbWlzZTxRdWlja0pTUnVudGltZVJlc3VsdD4ge1xuICBjb25zdCBzZXNzaW9uID0gYXdhaXQgc3RhcnRRdWlja0pTV29ya2Zsb3cob3B0aW9ucyk7XG4gIHNlc3Npb24uZGlzcG9zZSgpO1xuICByZXR1cm4gc2Vzc2lvbi5yZXN1bHQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFF1aWNrSlNXb3JrZmxvdyhcbiAgb3B0aW9uczogUXVpY2tKU1J1bnRpbWVPcHRpb25zXG4pOiBQcm9taXNlPFF1aWNrSlNXb3JrZmxvd1Nlc3Npb24+IHtcbiAgY29uc3QgeyB3b3JrZmxvd0NvZGUsIHdvcmtmbG93SWQsIHdvcmtmbG93UnVuLCBldmVudHMgfSA9IG9wdGlvbnM7XG5cbiAgY29uc3Qgc3RhcnRlZEF0ID0gd29ya2Zsb3dSdW4uc3RhcnRlZEF0ID8gK3dvcmtmbG93UnVuLnN0YXJ0ZWRBdCA6IERhdGUubm93KCk7XG5cbiAgLy8gRGV0ZXJtaW5pc3RpYyBQUk5HIHNlZWQsIGlkZW50aWNhbCBmb3IgRVZFUlkgaW52b2NhdGlvbiBvZiB0aGUgc2FtZVxuICAvLyBydW4uIEZ1bGwgZXZlbnQgcmVwbGF5IHJlcXVpcmVzIHRoaXM6IGVhY2ggaW52b2NhdGlvbiByZS1leGVjdXRlcyB0aGVcbiAgLy8gd29ya2Zsb3cgZnJvbSB0aGUgdG9wIGFuZCBtdXN0IHJlZ2VuZXJhdGUgdGhlIGV4YWN0IHNhbWUgY29ycmVsYXRpb25JZFxuICAvLyBzZXF1ZW5jZSBzbyB0aGF0IHBlbmRpbmcgb3BlcmF0aW9ucyByZS1jcmVhdGVkIGJ5IHJlcGxheSBtYXRjaCB0aGVcbiAgLy8gZXZlbnRzIHJlY29yZGVkIGJ5IGVhcmxpZXIgaW52b2NhdGlvbnMuIFNlcXVlbnRpYWwgb3BlcmF0aW9ucyB3aXRoaW5cbiAgLy8gb25lIGV4ZWN1dGlvbiBzdGlsbCBnZXQgZGlzdGluY3QgaWRzIGJlY2F1c2UgdGhlIFBSTkcgYWR2YW5jZXMgYXMgdGhlXG4gIC8vIHdvcmtmbG93IGRyYXdzIGZyb20gaXQuIElkZW50aWNhbCBzZWVkaW5nIGFjcm9zcyBDT05DVVJSRU5UIGludm9jYXRpb25zXG4gIC8vIG9mIHRoZSBzYW1lIHJ1biBpcyBhbHNvIGxvYWQtYmVhcmluZzogYm90aCBwcm9kdWNlIHRoZSBzYW1lIGlkcywgYW5kXG4gIC8vIHRoZSB3b3JsZCdzIHBlci0ocnVuSWQsIGNvcnJlbGF0aW9uSWQpIHVuaXF1ZW5lc3MgdHVybnMgdGhlIGR1cGxpY2F0ZVxuICAvLyBgZXZlbnRzLmNyZWF0ZWAgaW50byBhbiBFbnRpdHlDb25mbGljdEVycm9yIHRoYXQgdGhlIGVudHJ5cG9pbnRcbiAgLy8gc3dhbGxvd3MuXG4gIC8vXG4gIC8vIFRoZSBzZWVkIGlucHV0cyBNVVNUIGJlIHN0YWJsZSBhY3Jvc3MgaW52b2NhdGlvbnMuIE5vdGFibHlcbiAgLy8gYHN0YXJ0ZWRBdGAgaXMgTk9UOiB1bmRlciB0dXJibyB0aGUgZmlyc3QgaW52b2NhdGlvbiBydW5zIGFnYWluc3QgYVxuICAvLyBzeW50aGVzaXplZCBydW4gb2JqZWN0IHdob3NlIHRpbWVzdGFtcHMgZGlmZmVyIGZyb20gdGhlIGR1cmFibHlcbiAgLy8gc3RvcmVkIG9uZXMgdGhhdCBsYXRlciBpbnZvY2F0aW9ucyBsb2FkLiBNYXRjaGVzIHRoZSBub2RlOnZtXG4gIC8vIGVuZ2luZSdzIHNlZWQgKHdvcmtmbG93LnRzKS5cbiAgY29uc3Qgc2VlZCA9IFtcbiAgICB3b3JrZmxvd1J1bi5ydW5JZCxcbiAgICB3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsXG4gICAgd29ya2Zsb3dSdW4uZGVwbG95bWVudElkLFxuICBdLmpvaW4oJzonKTtcbiAgY29uc3Qgcm5nID0gc2VlZHJhbmRvbShzZWVkKTtcblxuICAvLyBTZWVkZWQgbmFub2lkIGdlbmVyYXRvcjogdXNlcyB0aGUgc2FtZSBuYW5vaWQgcGFja2FnZSBhbmQgc2VlZGVkIFBSTkdcbiAgLy8gYXMgdGhlIG5vZGU6dm0gZW5naW5lIGZvciBjb25zaXN0ZW50IHRva2VuIGdlbmVyYXRpb24uXG4gIGNvbnN0IGdlbmVyYXRlTmFub2lkID0gbmFub2lkLmN1c3RvbVJhbmRvbShuYW5vaWQudXJsQWxwaGFiZXQsIDIxLCAoc2l6ZSkgPT5cbiAgICBuZXcgVWludDhBcnJheShzaXplKS5tYXAoKCkgPT4gMjU2ICogcm5nKCkpXG4gICk7XG5cbiAgLy8gRGV0ZXJtaW5pc3RpYyByZXBsYXkgY2xvY2ssIG1pcnJvcmluZyB0aGUgbm9kZTp2bSBlbmdpbmUgKHNlZVxuICAvLyB3b3JrZmxvdy50cyk6IHRoZSBpbml0aWFsIHZhbHVlIGlzIHRoZSBydW4ncyBjcmVhdGlvbiB0aW1lIHJlY292ZXJlZFxuICAvLyBmcm9tIHRoZSBVTElEIGVtYmVkZGVkIGluIGBydW5JZGAgKGZhbGxpbmcgYmFjayB0byBgY3JlYXRlZEF0YCksIGFuZFxuICAvLyBpdCBhZHZhbmNlcyB0byBlYWNoIHByb2Nlc3NlZCBldmVudCdzIGBjcmVhdGVkQXRgIGFzIHRoZSBldmVudCBsb2cgaXNcbiAgLy8gcmVwbGF5ZWQuIE1vbm90b25pYyAoTWF0aC5tYXgpIHNvIHRoZSBvdXRlciBwcm9jZXNzRXZlbnRzIHJlLXNjYW5cbiAgLy8gbG9vcCBjYW4ndCBtb3ZlIHRoZSBjbG9jayBiYWNrd2FyZHMgbWlkLWV4ZWN1dGlvbi5cbiAgbGV0IHZtTm93TXMgPVxuICAgIHJ1bklkQ3JlYXRlZEF0KHdvcmtmbG93UnVuLnJ1bklkKSA/PyAoK3dvcmtmbG93UnVuLmNyZWF0ZWRBdCB8fCBzdGFydGVkQXQpO1xuICBjb25zdCBhZHZhbmNlQ2xvY2sgPSAobXM6IG51bWJlcikgPT4ge1xuICAgIGlmIChOdW1iZXIuaXNGaW5pdGUobXMpKSB2bU5vd01zID0gTWF0aC5tYXgodm1Ob3dNcywgbXMpO1xuICB9O1xuXG4gIC8vIC0tLS0gUGhhc2UgMTogc3RhdGljIGluaXRpYWxpemF0aW9uIC0tLS1cbiAgLy9cbiAgLy8gQmFzZWxpbmUtc25hcHNob3QgZmFzdCBwYXRoIChkZWZhdWx0IE9OOyBzZWUgdGhlIHNlY3Rpb24gY29tbWVudCBhdFxuICAvLyBwcmVwYXJlQmFzZWxpbmVTbmFwc2hvdCk6IHJlc3RvcmUgYSBidW5kbGUtaHlkcmF0ZWQgVk0gaW5zdGVhZCBvZlxuICAvLyBib290aW5nIGZyZXNoIGFuZCByZS1ldmFsdWF0aW5nIHRoZSBidW5kbGUuIGBpbmVsaWdpYmxlYCBidW5kbGVzXG4gIC8vIChtb2R1bGUtc2NvcGUgbm9uZGV0ZXJtaW5pc20sIGV2YWwgZmFpbHVyZSkgdGFrZSB0aGUgZnJlc2ggcGF0aCB3aXRoXG4gIC8vIGlkZW50aWNhbCBzZW1hbnRpY3MuXG4gIGNvbnN0IGludGVycnVwdEJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0ID0geyBzdGFydDogRGF0ZS5ub3coKSB9O1xuICBsZXQgYmFzZWxpbmVTbmFwc2hvdDogU25hcHNob3QgfCB1bmRlZmluZWQ7XG4gIGxldCBiYXNlbGluZVNlcmRlUm9vdFB0cjogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBpZiAoaXNRdWlja0pTQmFzZWxpbmVTbmFwc2hvdEVuYWJsZWQoKSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlbnRyeSA9IGF3YWl0IGdldEJhc2VsaW5lRW50cnkod29ya2Zsb3dDb2RlLCB3b3JrZmxvd0lkKTtcbiAgICAgIGlmIChlbnRyeS5zdGF0ZSA9PT0gJ3JlYWR5Jykge1xuICAgICAgICBiYXNlbGluZVNuYXBzaG90ID0gZW50cnkuc25hcHNob3Q7XG4gICAgICAgIGJhc2VsaW5lU2VyZGVSb290UHRyID0gZW50cnkuc2VyZGVSb290UHRyO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gQSByZWplY3Rpb24gaGVyZSBpcyBhbiBpbmZyYXN0cnVjdHVyZSBmYWlsdXJlIGR1cmluZyBoeWRyYXRlXG4gICAgICAvLyAoZS5nLiB2bS5zbmFwc2hvdCgpIHVuZGVyIG1lbW9yeSBwcmVzc3VyZSwgUXVpY2tKUy5jcmVhdGUgb3JcbiAgICAgIC8vIGdldENvbXBpbGVkQXNzZXRzKCkgZmFpbGluZyksIE5PVCBidW5kbGUgZXZhbCwgd2hpY2ggcmV0dXJuc1xuICAgICAgLy8gYW4gaW5lbGlnaWJsZSBlbnRyeS4gZ2V0QmFzZWxpbmVFbnRyeSBoYXMgYWxyZWFkeSBldmljdGVkIHRoZVxuICAgICAgLy8gY2FjaGVkIHByb21pc2Ugc28gYSBsYXRlciBpbnZvY2F0aW9uIGNhbiByZXRyeS4gVGhpcyBpbnZvY2F0aW9uXG4gICAgICAvLyBtdXN0IGZhbGwgYmFjayB0byBmcmVzaCBldmFsdWF0aW9uICh3aGljaCB3b3VsZCBoYXZlIHN1Y2NlZWRlZClcbiAgICAgIC8vIHJhdGhlciB0aGFuIGZhaWwgdGhlIHdob2xlIHJ1biBmb3IgYSBzbmFwc2hvdC1vbmx5IGZhaWx1cmUgbW9kZS5cbiAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgJ1F1aWNrSlMgYmFzZWxpbmUgc25hcHNob3QgaHlkcmF0ZSBmYWlsZWQ7IGZhbGxpbmcgYmFjayB0byBmcmVzaCBldmFsdWF0aW9uIGZvciB0aGlzIGludm9jYXRpb24nLFxuICAgICAgICB7IHdvcmtmbG93SWQsIGVycm9yOiBlcnIgfVxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgbGV0IHZtOiBRdWlja0pTO1xuICBpZiAoYmFzZWxpbmVTbmFwc2hvdCkge1xuICAgIGNvbnN0IGFzc2V0cyA9IGF3YWl0IGdldENvbXBpbGVkQXNzZXRzKCk7XG4gICAgdm0gPSBhd2FpdCBRdWlja0pTLnJlc3RvcmUoYmFzZWxpbmVTbmFwc2hvdCwge1xuICAgICAgd2FzbTogYXNzZXRzLndhc20gYXMgbmV2ZXIsXG4gICAgICBtZW1vcnlMaW1pdDogMjU2ICogMTAyNCAqIDEwMjQsXG4gICAgICBpbnRlcnJ1cHRIYW5kbGVyOiBjcmVhdGVJbnRlcnJ1cHRIYW5kbGVyKGludGVycnVwdEJ1ZGdldCksXG4gICAgICBleHRlbnNpb25zOiBhc3NldHMuZXh0ZW5zaW9ucyxcbiAgICAgIHdhc2k6IG1ha2VEZXRlcm1pbmlzdGljQ2xvY2tXYXNpKCgpID0+IHZtTm93TXMpLFxuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHZtID0gYXdhaXQgaW5pdFdvcmtmbG93Vk0oKCkgPT4gdm1Ob3dNcywgaW50ZXJydXB0QnVkZ2V0KTtcbiAgfVxuXG4gIC8vIEhvc3Qtc2lkZSBzZXJkZTogY2FwdHVyZXMgdGhlIFZNJ3MgaW50cmluc2ljcyAoYm9vdHN0cmFwIGluY2x1ZGVkKVxuICAvLyBiZWZvcmUgYW55IHVzZXIgY29kZSBydW5zLiBBbGwgc2VyaWFsaXphdGlvbiBub3cgaGFwcGVucyBvbiB0aGUgaG9zdFxuICAvLyB0aHJvdWdoIGhhbmRsZXM6IG5vIHNlcmlhbGl6ZXIgY29kZSBpcyBldmFsdWF0ZWQgaW5zaWRlIHRoZSBWTS5cbiAgLy8gRnJlc2ggcGF0aDogY2FwdHVyZSBub3cgKG5vIHVzZXIgY29kZSBoYXMgcnVuLCBhcyB0aGUgYnVuZGxlIGV2YWx1YXRlc1xuICAvLyBsYXRlciBpbiB0aGUgcGVyLXJ1biBwaGFzZSkuIFNuYXBzaG90IHBhdGg6IHJlLWFkb3B0IHRoZSBjYXB0dXJlIHJvb3RcbiAgLy8gdGhlIGJhc2VsaW5lIGh5ZHJhdGUgY3JlYXRlZCBCRUZPUkUgdGhlIGJ1bmRsZSBldmFsdWF0ZWQsIHNpbmNlIHRoZSBib3hcbiAgLy8gbGl2ZXMgaW4gdGhlIHJlc3RvcmVkIG1lbW9yeSBpbWFnZSBhdCB0aGUgcmVjb3JkZWQgb2Zmc2V0LiBCb3RoIGdpdmVcbiAgLy8gdGhlIHNlcmRlIHByaXN0aW5lIGNhcHR1cmUtYmVmb3JlLXVzZXItY29kZSBpbnRyaW5zaWNzOyBuZWl0aGVyXG4gIC8vIGV4ZWN1dGVzIGd1ZXN0IGNvZGUgaGVyZS5cbiAgY29uc3Qgc2VyZGUgPVxuICAgIGJhc2VsaW5lU25hcHNob3QgJiYgYmFzZWxpbmVTZXJkZVJvb3RQdHIgIT09IHVuZGVmaW5lZFxuICAgICAgPyBjcmVhdGVRdWlja0pTU2VyZGUodm0sIGFkb3B0U2VyZGVSb290KHZtLCBiYXNlbGluZVNlcmRlUm9vdFB0cikpXG4gICAgICA6IGNyZWF0ZVF1aWNrSlNTZXJkZSh2bSk7XG5cbiAgLy8gQW55IHRocm93IGJldHdlZW4gaGVyZSBhbmQgdGhlIHRlcm1pbmFsIHBhdGhzICh3aGljaCBkaXNwb3NlIHRoZSBWTVxuICAvLyBpbnNpZGUgY2hlY2tXb3JrZmxvd1N0YXRlIC8gZXh0cmFjdEVycm9yIGJlZm9yZSBSRVRVUk5JTkcpIHdvdWxkIGxlYWtcbiAgLy8gYSBsaXZlIFF1aWNrSlMgaW5zdGFuY2UgYW5kIGl0cyBXQVNNIGxpbmVhciBtZW1vcnkgZm9yIHRoZSBsaWZldGltZVxuICAvLyBvZiB0aGUgY29tcHV0ZSBpbnN0YW5jZSwgd2hpY2ggaXMgcmV1c2VkLiBEaXNwb3NlIG9uIHRoZSB3YXkgb3V0IG9mXG4gIC8vIGFuIGV4Y2VwdGlvbmFsIGV4aXQgYW5kIHJldGhyb3cuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHJ1bldvcmtmbG93SW5WTSgpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0cnkge1xuICAgICAgdm0uZGlzcG9zZSgpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gQWxyZWFkeSBkaXNwb3NlZCBieSBhIHRlcm1pbmFsIHBhdGgsIHNvIGlnbm9yZS5cbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG5cbiAgLy8gLS0tLSBQaGFzZSAyOiBwZXItcnVuIGluaXRpYWxpemF0aW9uIC0tLS1cbiAgYXN5bmMgZnVuY3Rpb24gcnVuV29ya2Zsb3dJblZNKCk6IFByb21pc2U8UXVpY2tKU1dvcmtmbG93U2Vzc2lvbj4ge1xuICAgIHZtLmV2YWxDb2RlKFxuICAgICAgYGdsb2JhbFRoaXMuX193b3JsZENhcGFiaWxpdGllcyA9ICR7SlNPTi5zdHJpbmdpZnkob3B0aW9ucy53b3JsZENhcGFiaWxpdGllcyl9O2BcbiAgICApLmRpc3Bvc2UoKTtcblxuICAgIC8vIFNlZWRlZCBNYXRoLnJhbmRvbVxuICAgIHtcbiAgICAgIHVzaW5nIHJhbmRvbUZuID0gdm0ubmV3RnVuY3Rpb24oJ3JhbmRvbScsICgpID0+IHZtLm5ld051bWJlcihybmcoKSkpO1xuICAgICAgdXNpbmcgbWF0aCA9IHZtLmdsb2JhbC5nZXRQcm9wKCdNYXRoJyk7XG4gICAgICBtYXRoLnNldFByb3AoJ3JhbmRvbScsIHJhbmRvbUZuKTtcbiAgICB9XG5cbiAgICAvLyBTZWVkZWQgbmFub2lkIGdlbmVyYXRvclxuICAgIHtcbiAgICAgIHVzaW5nIG5hbm9pZEZuID0gdm0ubmV3RnVuY3Rpb24oJ19fZ2VuZXJhdGVOYW5vaWQnLCAoKSA9PlxuICAgICAgICB2bS5uZXdTdHJpbmcoZ2VuZXJhdGVOYW5vaWQoKSlcbiAgICAgICk7XG4gICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fZ2VuZXJhdGVOYW5vaWQnLCBuYW5vaWRGbik7XG4gICAgfVxuXG4gICAgLy8gSG9zdC1zaWRlIGRldGVybWluaXN0aWMgVUxJRCBnZW5lcmF0b3IgZm9yIGNvcnJlbGF0aW9uSWRzLiBVc2VzIHRoZVxuICAgIC8vIHNhbWUgYHVsaWRgIHBhY2thZ2UgYW5kIG1vbm90b25pYyBmYWN0b3J5IGFzIGJlZm9yZSwgZHJhd2luZyBmcm9tXG4gICAgLy8gdGhlIFNBTUUgc2VlZGVkIFBSTkcgaW5zdGFuY2UgYXMgdGhlIFZNJ3MgTWF0aC5yYW5kb20sIHNvIHRoZVxuICAgIC8vIGludGVybGVhdmVkIGRyYXcgc2VxdWVuY2UgKGFuZCB0aGVyZWZvcmUgZXZlcnkgY29ycmVsYXRpb25JZCkgaXNcbiAgICAvLyBieXRlLWlkZW50aWNhbCB0byB3aGF0IHRoZSBwcmV2aW91cyBpbi1WTSBVTElEIGZhY3RvcnkgcHJvZHVjZWQgZm9yXG4gICAgLy8gdGhlIHNhbWUgcnVuLiBUaGUgdGltZSBwcmVmaXggaXMgZGVyaXZlZCBmcm9tIHRoZSBydW5JZCdzIGVtYmVkZGVkXG4gICAgLy8gVUxJRCAoc3RhYmxlIGFjcm9zcyBpbnZvY2F0aW9ucyBieSBjb25zdHJ1Y3Rpb24sIHVubGlrZVxuICAgIC8vIGBzdGFydGVkQXRgLCB3aGljaCBkaWZmZXJzIGJldHdlZW4gdHVyYm8ncyBzeW50aGVzaXplZCBydW4gb2JqZWN0XG4gICAgLy8gYW5kIHRoZSBkdXJhYmx5IHN0b3JlZCBydW4pLCBzbyB0d28gY29uY3VycmVudCBpbnZvY2F0aW9ucyBvZiB0aGVcbiAgICAvLyBzYW1lIHJ1biBwcm9kdWNlIElERU5USUNBTCBjb3JyZWxhdGlvbklkcyBhbmQgdGhlIHdvcmxkJ3NcbiAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yIG9uIGBldmVudHMuY3JlYXRlYCBkZWR1cHMgb25lIG9mIGVhY2ggcGFpci5cbiAgICB7XG4gICAgICBjb25zdCB1bGlkRmFjdG9yeSA9IG1vbm90b25pY0ZhY3RvcnkoKCkgPT4gcm5nKCkpO1xuICAgICAgY29uc3QgdWxpZFRpbWVzdGFtcCA9XG4gICAgICAgIHJ1bklkQ3JlYXRlZEF0KHdvcmtmbG93UnVuLnJ1bklkKSA/P1xuICAgICAgICAoK3dvcmtmbG93UnVuLmNyZWF0ZWRBdCB8fCBzdGFydGVkQXQpO1xuICAgICAgdXNpbmcgdWxpZEZuID0gdm0ubmV3RnVuY3Rpb24oJ19fZ2VuZXJhdGVVbGlkJywgKCkgPT5cbiAgICAgICAgdm0ubmV3U3RyaW5nKHVsaWRGYWN0b3J5KHVsaWRUaW1lc3RhbXApKVxuICAgICAgKTtcbiAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX19nZW5lcmF0ZVVsaWQnLCB1bGlkRm4pO1xuICAgIH1cblxuICAgIC8vIGBwcm9jZXNzLmVudmA6IHBhcml0eSB3aXRoIHRoZSBub2RlOnZtIGVuZ2luZSwgd2hpY2ggZXhwb3NlcyBhIGZyb3plblxuICAgIC8vIGNvcHkgb2YgdGhlIGhvc3QgZW52ICh2bS9pbmRleC50cykuIEluamVjdGVkIHBlciBydW4gc28gdGhlIHNuYXBzaG90IG9mXG4gICAgLy8gdGhlIGVudiBpcyB0YWtlbiBhdCBpbnZvY2F0aW9uIHRpbWUsIHNhbWUgYXMgbm9kZS4gSGFuZGxlLWJhc2VkIChub1xuICAgIC8vIGd1ZXN0IHNvdXJjZSBldmFsdWF0ZWQpOiBvbiB0aGUgYmFzZWxpbmUtc25hcHNob3QgcGF0aCB0aGlzIHJ1bnNcbiAgICAvLyBhZnRlciB1c2VyIGNvZGUsIGFuZCBhIGd1ZXN0LXNvdXJjZSBpbmplY3Rpb24gd291bGQgZXhlY3V0ZSB0aHJvdWdoXG4gICAgLy8gcG90ZW50aWFsbHkgcGF0Y2hlZCBnbG9iYWxzIChKU09OLnBhcnNlLCBPYmplY3QuZnJlZXplKSwgdmlzaWJsZVxuICAgIC8vIHRvIG1vZHVsZS1zY29wZSB3cmFwcGVycyBvbmx5IG9uIHRoZSByZXN0b3JlIHBhdGgsIGRpdmVyZ2luZ1xuICAgIC8vIHJlcGxheXMuXG4gICAgc2VyZGUuaW5zdGFsbFByb2Nlc3NFbnYocHJvY2Vzcy5lbnYpO1xuXG4gICAgLy8gRXhlY3V0ZSB0aGUgd29ya2Zsb3cgYnVuZGxlOiB1c2UgdGhlIHdvcmtmbG93SWQgYXMgdGhlIGV2YWwgZmlsZW5hbWVcbiAgICAvLyBzbyBRdWlja0pTIHN0YWNrIHRyYWNlcyByZWZlcmVuY2UgdGhlIHdvcmtmbG93IG5hbWUsIGVuYWJsaW5nIHNvdXJjZSBtYXBcbiAgICAvLyByZW1hcHBpbmcgYnkgcmVtYXBFcnJvclN0YWNrICh3aGljaCBtYXRjaGVzIGZyYW1lcyBieSBmaWxlbmFtZSkuXG4gICAgLy8gRXZhbHVhdGVkIGluIHRoZSBwZXItcnVuIHBoYXNlIChhZnRlciBNYXRoLnJhbmRvbSBzZWVkaW5nKSBzbyB0aGF0XG4gICAgLy8gbW9kdWxlLXNjb3BlIHVzZXIgY29kZSBkcmF3cyBmcm9tIHRoZSBzZWVkZWQgUFJORywgbWF0Y2hpbmcgdGhlXG4gICAgLy8gbm9kZTp2bSBlbmdpbmUncyByZXBsYXkgZGV0ZXJtaW5pc20uIFNraXBwZWQgb24gdGhlXG4gICAgLy8gYmFzZWxpbmUtc25hcHNob3QgcGF0aDogdGhlIHJlc3RvcmVkIGhlYXAgYWxyZWFkeSBjYXJyaWVzIHRoZVxuICAgIC8vIGV2YWx1YXRlZCBidW5kbGUsIGFuZCB0aGUgYmFzZWxpbmUgZ2F0ZSBndWFyYW50ZWVzIG1vZHVsZSBzY29wZVxuICAgIC8vIGNvbnN1bWVkIG5vIFBSTkcgZHJhd3Mgb3IgY2xvY2sgcmVhZHMsIHNvIHNraXBwaW5nIHRoZSBldmFsIGlzXG4gICAgLy8gb2JzZXJ2YXRpb25hbGx5IGlkZW50aWNhbCB0byByZS1ydW5uaW5nIGl0ICh0aGUgcnVuLXNlZWRlZCBob3N0XG4gICAgLy8gZm5zIHJlZ2lzdGVyZWQgYWJvdmUgcmViaW5kIHRoZSBTQU1FIG5hbWVzIHRoZSByZXN0b3JlZCBoZWFwJ3NcbiAgICAvLyBmdW5jdGlvbiBvYmplY3RzIGRpc3BhdGNoIHRocm91Z2gpLlxuICAgIGlmICghYmFzZWxpbmVTbmFwc2hvdCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdm0uZXZhbENvZGUod29ya2Zsb3dDb2RlLCB3b3JrZmxvd0lkIHx8ICd3b3JrZmxvdy5qcycpLmRpc3Bvc2UoKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICByZXR1cm4gbWFrZVNldHRsZWRTZXNzaW9uKFxuICAgICAgICAgIGV4dHJhY3RFcnJvcih2bSwgZXJyLCAnV29ya2Zsb3cgZXZhbHVhdGlvbiBmYWlsZWQnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEV4dHJhY3Qgd29ya2Zsb3cgYXJndW1lbnRzLiBQcmVmZXIgdGhlIHJ1bl9jcmVhdGVkIGV2ZW50OyBmYWxsIGJhY2tcbiAgICAvLyB0byB0aGUgcXVldWUgbWVzc2FnZSdzIHJ1bklucHV0IGlmIHRoZSBldmVudCBsb2cgaXMgaW5jb21wbGV0ZVxuICAgIC8vIChldmVudHVhbGx5LWNvbnNpc3RlbnQgcmVhZCBhZnRlciBzdGFydCgpKS4gRmFpbGluZyB0byBmaW5kIGlucHV0XG4gICAgLy8gZm9yIGEgZmlyc3QgaW52b2NhdGlvbiBpcyBmYXRhbDogcnVubmluZyB0aGUgd29ya2Zsb3cgZnVuY3Rpb25cbiAgICAvLyB3aXRoIG5vIGFyZ3Mgd291bGQgc2lsZW50bHkgdHVybiB0eXBlZCBhcmd1bWVudHMgaW50byBgdW5kZWZpbmVkYFxuICAgIC8vIGFuZCwgZm9yIHJlY3Vyc2l2ZSB3b3JrZmxvd3MsIHByb2R1Y2UgZXhwb25lbnRpYWwgZmFuLW91dC5cbiAgICBjb25zdCBydW5DcmVhdGVkRXZlbnQgPSBldmVudHMuZmluZCgoZSkgPT4gZS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCcpO1xuICAgIGNvbnN0IHJ1bkNyZWF0ZWRJbnB1dCA9XG4gICAgICBydW5DcmVhdGVkRXZlbnQgJiYgJ2V2ZW50RGF0YScgaW4gcnVuQ3JlYXRlZEV2ZW50XG4gICAgICAgID8gKHJ1bkNyZWF0ZWRFdmVudC5ldmVudERhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pPy5pbnB1dFxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBydW5JbnB1dDogdW5rbm93biA9XG4gICAgICBydW5DcmVhdGVkSW5wdXQgPz8gKG9wdGlvbnMucnVuSW5wdXQ/LmlucHV0IGFzIHVua25vd24pO1xuXG4gICAgaWYgKHJ1bklucHV0IGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgY29uc3QgZGVjcnlwdGVkSW5wdXQgPSBhd2FpdCBwcmVwYXJlQnl0ZXNGb3JWTShcbiAgICAgICAgcnVuSW5wdXQsXG4gICAgICAgIG9wdGlvbnMuZW5jcnlwdGlvbktleVxuICAgICAgKTtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgcnVudGltZTogcnVuIGlucHV0IGZvcm1hdCcsIHtcbiAgICAgICAgcHJlZml4OiBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGVjcnlwdGVkSW5wdXQuc3ViYXJyYXkoMCwgNCkpLFxuICAgICAgICBieXRlTGVuZ3RoOiBkZWNyeXB0ZWRJbnB1dC5ieXRlTGVuZ3RoLFxuICAgICAgICBzb3VyY2U6IHJ1bkNyZWF0ZWRJbnB1dCA/ICdydW5fY3JlYXRlZCcgOiAncXVldWVNZXNzYWdlLnJ1bklucHV0JyxcbiAgICAgIH0pO1xuICAgICAgLy8gQnVpbGQgdGhlIGFyZ3VtZW50IHZhbHVlIGRpcmVjdGx5IGluIHRoZSBWTSB2aWEgdGhlIGhvc3Qtc2lkZVxuICAgICAgLy8gc2VyZGUgKGd1ZXN0IGNvZGUgbmV2ZXIgc2VlcyB0aGUgd2lyZSBieXRlcykuXG4gICAgICBjb25zdCBpbnB1dEhhbmRsZSA9IHNlcmRlLmRlc2VyaWFsaXplKGRlY3J5cHRlZElucHV0KTtcbiAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX193ZGtfaW5wdXQnLCBpbnB1dEhhbmRsZSk7XG4gICAgICBpbnB1dEhhbmRsZS5kaXNwb3NlKCk7XG4gICAgfSBlbHNlIGlmIChydW5JbnB1dCA9PT0gdW5kZWZpbmVkICYmIGV2ZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBUaGUgZXZlbnQgbG9nIGlzIG5vbi1lbXB0eSAod2UgZ290IHJ1bl9zdGFydGVkIG9yIHNpbWlsYXIpIGJ1dFxuICAgICAgLy8gbm8gcnVuX2NyZWF0ZWQgZXZlbnQgd2FzIGZvdW5kIGFuZCBubyBxdWV1ZS1wcm92aWRlZCBydW5JbnB1dCBpc1xuICAgICAgLy8gYXZhaWxhYmxlLiBUaGlzIGlzIHRoZSByYWNlIGNvbmRpdGlvbiBvYnNlcnZlZCBkdXJpbmcgdGhlIGZpYlxuICAgICAgLy8gaW5jaWRlbnQ6IHNpbGVudGx5IGRyb3BwaW5nIGFyZ3VtZW50cyB3b3VsZCB0dXJuIGBuYCBpbnRvXG4gICAgICAvLyBgdW5kZWZpbmVkYCBhbmQsIGZvciByZWN1cnNpdmUgd29ya2Zsb3dzLCBjYXVzZSBleHBvbmVudGlhbFxuICAgICAgLy8gZmFuLW91dC4gRmFpbCBsb3VkOiB0aGUgdGhyb3cgZXNjYXBlcyB0aGUgZW50cnlwb2ludCBpbnRvIHRoZVxuICAgICAgLy8gcmVwbGF5IGxvb3AncyBjYXRjaCBpbiBydW50aW1lLnRzICh0aGUgUXVpY2tKUyBkaXNwYXRjaCBydW5zXG4gICAgICAvLyBpbnNpZGUgdGhhdCBsb29wJ3MgdHJ5KSwgd2hpY2ggcmVjb3JkcyBydW5fZmFpbGVkLiBBIHZpc2libGVcbiAgICAgIC8vIHRlcm1pbmFsIGZhaWx1cmUgaXNcbiAgICAgIC8vIHByZWZlcnJlZCBvdmVyIHNpbGVudGx5IGV4ZWN1dGluZyB3aXRoIHVuZGVmaW5lZCBhcmd1bWVudHMuIFRoZVxuICAgICAgLy8gcXVldWUtcHJvdmlkZWQgcnVuSW5wdXQgZmFsbGJhY2sgYWJvdmUgbWFrZXMgdGhpcyBwYXRoIHJhcmUuXG4gICAgICAvLyBFbXB0eSBgZXZlbnRzYCBpcyBhbGxvd2VkIGJlY2F1c2UgdGVzdHMgdGhhdCBib290c3RyYXAgYSB3b3JrZmxvd1xuICAgICAgLy8gd2l0aCBubyBhcmd1bWVudHMgcmVseSBvbiB0aGUgb2xkIHBlcm1pc3NpdmUgYmVoYXZpb3IuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBDYW5ub3Qgc3RhcnQgd29ya2Zsb3cgcnVuIFwiJHt3b3JrZmxvd1J1bi5ydW5JZH1cIjogbm8gcnVuX2NyZWF0ZWQgZXZlbnQgZm91bmQgYW5kIG5vIHJ1bklucHV0IGluIHRoZSBxdWV1ZSBwYXlsb2FkLCBidXQgb3RoZXIgZXZlbnRzIGFyZSBwcmVzZW50IChsaWtlbHkgYSByZWFkLWFmdGVyLXdyaXRlIHJhY2UgZHVyaW5nIHN0YXJ0KCkpLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IHdvcmtmbG93IGNvbnRleHQgbWV0YWRhdGEgKGZvciBnZXRXb3JrZmxvd01ldGFkYXRhKCkpLlxuICAgIC8vIE11c3QgbWF0Y2ggdGhlIHNoYXBlIHRoYXQgdGhlIG5vZGU6dm0gZW5naW5lIHByb2R1Y2VzIChzZWVcbiAgICAvLyBwYWNrYWdlcy9jb3JlL3NyYy93b3JrZmxvdy50czogcnVuV29ya2Zsb3cg4oaSIGN0eCkgc28gdXNlciBjb2RlXG4gICAgLy8gdGhhdCBjb21wYXJlcyBgZ2V0V29ya2Zsb3dNZXRhZGF0YSgpYCB2YWx1ZXMgYmV0d2VlbiBhIHN0ZXBcbiAgICAvLyAoc2VydmVyLXNpZGUpIGFuZCB0aGUgd29ya2Zsb3cgKFZNLXNpZGUpIHNlZXMgaWRlbnRpY2FsIG9iamVjdHMuXG4gICAge1xuICAgICAgY29uc3QgbWV0YWRhdGEgPSB7XG4gICAgICAgIHdvcmtmbG93TmFtZTogd29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLFxuICAgICAgICB3b3JrZmxvd1J1bklkOiB3b3JrZmxvd1J1bi5ydW5JZCxcbiAgICAgICAgd29ya2Zsb3dTdGFydGVkQXQ6IHdvcmtmbG93UnVuLnN0YXJ0ZWRBdFxuICAgICAgICAgID8gbmV3IERhdGUoK3dvcmtmbG93UnVuLnN0YXJ0ZWRBdClcbiAgICAgICAgICA6IG5ldyBEYXRlKCksXG4gICAgICAgIHVybDogcHJvY2Vzcy5lbnYuVkVSQ0VMX1VSTFxuICAgICAgICAgID8gYGh0dHBzOi8vJHtwcm9jZXNzLmVudi5WRVJDRUxfVVJMfWBcbiAgICAgICAgICA6IGBodHRwOi8vbG9jYWxob3N0OiR7b3B0aW9ucy5wb3J0ID8/IDMwMDB9YCxcbiAgICAgICAgZmVhdHVyZXM6IHsgZW5jcnlwdGlvbjogISFvcHRpb25zLmVuY3J5cHRpb25LZXkgfSxcbiAgICAgIH07XG4gICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgYGdsb2JhbFRoaXNbU3ltYm9sLmZvcihcIldPUktGTE9XX0NPTlRFWFRcIildID0gJHtKU09OLnN0cmluZ2lmeShtZXRhZGF0YSl9O2AgK1xuICAgICAgICAgIGBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoXCJXT1JLRkxPV19DT05URVhUXCIpXS53b3JrZmxvd1N0YXJ0ZWRBdCA9IG5ldyBEYXRlKCR7SlNPTi5zdHJpbmdpZnkobWV0YWRhdGEud29ya2Zsb3dTdGFydGVkQXQudG9JU09TdHJpbmcoKSl9KTtgXG4gICAgICApLmRpc3Bvc2UoKTtcbiAgICB9XG5cbiAgICAvLyBTdGFydCB0aGUgd29ya2Zsb3cgZnVuY3Rpb24uIElmIHRoZSB3b3JrZmxvdyBpc24ndCByZWdpc3RlcmVkLFxuICAgIC8vIHRocm93IGFuIGVycm9yIHRhZ2dlZCB3aXRoIGBuYW1lID0gXCJXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvclwiYFxuICAgIC8vIHNvIHRoZSBob3N0LXNpZGUgZW50cnlwb2ludCBjYW4gcmVjb25zdHJ1Y3QgYSByZWFsXG4gICAgLy8gV29ya2Zsb3dOb3RSZWdpc3RlcmVkRXJyb3IgKGEgV29ya2Zsb3dSdW50aW1lRXJyb3Igc3ViY2xhc3MgdGhhdFxuICAgIC8vIGNsYXNzaWZpZXMgYXMgUlVOVElNRV9FUlJPUikgcmF0aGVyIHRoYW4gYSBnZW5lcmljIHVzZXIgZXJyb3IuXG4gICAgLy8gU2VlIHF1aWNranMtZW50cnlwb2ludC50cydzIHJ1bl9mYWlsZWQgYnJhbmNoLlxuICAgIHRyeSB7XG4gICAgICB2bS5ldmFsQ29kZShgXG4gICAgICB2YXIgX193Zm4gPSBnbG9iYWxUaGlzLl9fcHJpdmF0ZV93b3JrZmxvd3MuZ2V0KCR7SlNPTi5zdHJpbmdpZnkod29ya2Zsb3dJZCl9KTtcbiAgICAgIGlmICghX193Zm4pIHtcbiAgICAgICAgdmFyIF9fd2ZuRXJyID0gbmV3IEVycm9yKFwiV29ya2Zsb3cgXFxcXFwiXCIgKyAke0pTT04uc3RyaW5naWZ5KHdvcmtmbG93SWQpfSArIFwiXFxcXFwiIGlzIG5vdCByZWdpc3RlcmVkIGluIHRoZSBjdXJyZW50IGRlcGxveW1lbnQuXCIpO1xuICAgICAgICBfX3dmbkVyci5uYW1lID0gXCJXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvclwiO1xuICAgICAgICB0aHJvdyBfX3dmbkVycjtcbiAgICAgIH1cbiAgICAgIHZhciBfX2FyZ3MgPSBnbG9iYWxUaGlzLl9fd2RrX2lucHV0ICE9PSB1bmRlZmluZWRcbiAgICAgICAgPyBnbG9iYWxUaGlzLl9fd2RrX2lucHV0XG4gICAgICAgIDogW107XG4gICAgICBkZWxldGUgZ2xvYmFsVGhpcy5fX3dka19pbnB1dDtcbiAgICAgIGlmICghQXJyYXkuaXNBcnJheShfX2FyZ3MpKSBfX2FyZ3MgPSBbX19hcmdzXTtcbiAgICAgIF9fd2ZuLmFwcGx5KG51bGwsIF9fYXJncykudGhlbihcbiAgICAgICAgZnVuY3Rpb24ocmVzdWx0KSB7XG4gICAgICAgICAgLy8gU3RvcmUgdGhlIFJBVyByZXN1bHQ7IHRoZSBob3N0IHNlcmlhbGl6ZXMgaXQgdGhyb3VnaCBhIGhhbmRsZS5cbiAgICAgICAgICAvLyBBIHNlcGFyYXRlIGRvbmUgZmxhZyBkaXN0aW5ndWlzaGVzIFwiY29tcGxldGVkIHdpdGggdW5kZWZpbmVkXCJcbiAgICAgICAgICAvLyBmcm9tIFwibm90IGNvbXBsZXRlZFwiLlxuICAgICAgICAgIGdsb2JhbFRoaXMuX193b3JrZmxvd0RvbmUgPSB0cnVlO1xuICAgICAgICAgIGdsb2JhbFRoaXMuX193b3JrZmxvd1Jlc3VsdCA9IHJlc3VsdDtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24oZXJyb3IpIHtcbiAgICAgICAgICAvLyBQcmVzZXJ2ZSBkaXNwbGF5IGluZm8gb24gdGhlIGhvc3Qtc2lkZSBmYWlsZWQgb2JqZWN0XG4gICAgICAgICAgLy8gKG1hdGNoZXMgdGhlIGxlZ2FjeSBob3N0LXZpc2libGUgc2hhcGUpIEFORCBrZWVwIHRoZSBSQVdcbiAgICAgICAgICAvLyB0aHJvd24gdmFsdWUgc28gdGhlIGhvc3QgY2FuIHNlcmlhbGl6ZSB0aGUgb3JpZ2luYWxcbiAgICAgICAgICAvLyB0eXBlLWlkZW50aXR5LCBjYXVzZSBjaGFpbiwgb3Igbm9uLUVycm9yIHRocm93cyB2ZXJiYXRpbVxuICAgICAgICAgIC8vIHRocm91Z2ggdGhlIHN0YW5kYXJkIGVycm9yIHBpcGVsaW5lLlxuICAgICAgICAgIGdsb2JhbFRoaXMuX193b3JrZmxvd0Vycm9yID0ge1xuICAgICAgICAgICAgbWVzc2FnZTogZXJyb3IgJiYgZXJyb3IubWVzc2FnZSAhPSBudWxsID8gU3RyaW5nKGVycm9yLm1lc3NhZ2UpIDogU3RyaW5nKGVycm9yKSxcbiAgICAgICAgICAgIHN0YWNrOiBlcnJvciAmJiBlcnJvci5zdGFjayA/IGVycm9yLnN0YWNrIDogXCJcIixcbiAgICAgICAgICAgIG5hbWU6IGVycm9yICYmIGVycm9yLm5hbWUgPyBlcnJvci5uYW1lIDogKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBcIkVycm9yXCIgOiB0eXBlb2YgZXJyb3IpLFxuICAgICAgICAgICAgdmFsdWU6IGVycm9yLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgYCkuZGlzcG9zZSgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmV0dXJuIG1ha2VTZXR0bGVkU2Vzc2lvbihcbiAgICAgICAgZXh0cmFjdEVycm9yKHZtLCBlcnIsICdGYWlsZWQgdG8gc3RhcnQgd29ya2Zsb3cnKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBQcm9jZXNzIGV2ZW50cyBhbmQgZHJhaW4gam9icyBpbiBhIGxvb3AuIEV2ZW50cyBtYXkgcmVzb2x2ZSBwcm9taXNlc1xuICAgIC8vIHRoYXQgdW5ibG9jayB3b3JrZmxvdyBjb2RlLCB3aGljaCB0aGVuIGNyZWF0ZXMgTkVXIHJlc29sdmVycyBmb3JcbiAgICAvLyBzdWJzZXF1ZW50IGV2ZW50cy4gUmUtcHJvY2Vzc2luZyBldmVudHMgbWF0Y2hlcyB0aGVzZSBuZXcgcmVzb2x2ZXJzXG4gICAgLy8gYWdhaW5zdCBldmVudHMgdGhhdCB3ZXJlIGFscmVhZHkgZGVsaXZlcmVkLlxuICAgIHtcbiAgICAgIGxldCBtYXhJdGVyYXRpb25zID0gMTAwO1xuICAgICAgbGV0IG1hZGVQcm9ncmVzczogYm9vbGVhbjtcbiAgICAgIGRvIHtcbiAgICAgICAgbWFkZVByb2dyZXNzID0gYXdhaXQgcHJvY2Vzc0V2ZW50cyhcbiAgICAgICAgICB2bSxcbiAgICAgICAgICBzZXJkZSxcbiAgICAgICAgICBldmVudHMsXG4gICAgICAgICAgYWR2YW5jZUNsb2NrLFxuICAgICAgICAgIG9wdGlvbnMuZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgICBsZXQgYmF0Y2g6IG51bWJlcjtcbiAgICAgICAgZG8ge1xuICAgICAgICAgIGJhdGNoID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgaWYgKGJhdGNoID4gMCkgbWFkZVByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgfSB3aGlsZSAoYmF0Y2ggPiAwKTtcbiAgICAgIH0gd2hpbGUgKG1hZGVQcm9ncmVzcyAmJiAtLW1heEl0ZXJhdGlvbnMgPiAwKTtcbiAgICAgIGlmIChtYWRlUHJvZ3Jlc3MgJiYgbWF4SXRlcmF0aW9ucyA9PT0gMCkge1xuICAgICAgICAvLyBUaGUgZHJhaW4gbG9vcCBoaXQgaXRzIGJvdW5kIHdoaWxlIHN0aWxsIG1ha2luZyBwcm9ncmVzczpcbiAgICAgICAgLy8gcHJvY2VlZGluZyBhcyBpZiBpdCBjb252ZXJnZWQgd291bGQgcHJlc2VudCBhcyBhIG15c3RlcmlvdXNcbiAgICAgICAgLy8gc3VzcGVuc2lvbiBvciByZXBsYXkgZGl2ZXJnZW5jZS4gTWFrZSB0aGUgZ2l2aW5nLXVwIHZpc2libGUgc29cbiAgICAgICAgLy8gYSB3ZWRnZSBpcyBhdHRyaWJ1dGFibGUgdG8gdGhpcyBib3VuZCByYXRoZXIgdGhhbiBhIG15c3RlcnkuXG4gICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBldmVudCBkcmFpbiBsb29wIGhpdCBpdHMgaXRlcmF0aW9uIGJvdW5kIGJlZm9yZSByZWFjaGluZyBhIGZpeGVkIHBvaW50JyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkOiB3b3JrZmxvd1J1bi5ydW5JZCxcbiAgICAgICAgICAgIGV2ZW50Q291bnQ6IGV2ZW50cy5sZW5ndGgsXG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIC0tLS0gQ2hlY2sgcmVzdWx0IC0tLS1cbiAgICByZXR1cm4gbWFrZUxpdmVTZXNzaW9uKFxuICAgICAgdm0sXG4gICAgICBzZXJkZSxcbiAgICAgIGludGVycnVwdEJ1ZGdldCxcbiAgICAgIGFkdmFuY2VDbG9jayxcbiAgICAgIG9wdGlvbnMuZW5jcnlwdGlvbktleVxuICAgICk7XG4gIH1cbn1cblxuLyoqIFNlc3Npb24gd3JhcHBlciBmb3IgYSByZXN1bHQgd2hvc2UgVk0gaXMgYWxyZWFkeSBzZXR0bGVkL2Rpc3Bvc2VkLiAqL1xuZnVuY3Rpb24gbWFrZVNldHRsZWRTZXNzaW9uKFxuICByZXN1bHQ6IFF1aWNrSlNSdW50aW1lUmVzdWx0XG4pOiBRdWlja0pTV29ya2Zsb3dTZXNzaW9uIHtcbiAgcmV0dXJuIHtcbiAgICByZXN1bHQsXG4gICAgY29udGludWVXaXRoRXZlbnRzOiAoKSA9PiB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdRdWlja0pTIHdvcmtmbG93IHNlc3Npb24gaXMgc2V0dGxlZCDigJQgY29udGludWVXaXRoRXZlbnRzIGlzIG9ubHkgdmFsaWQgd2hpbGUgc3VzcGVuZGVkJ1xuICAgICAgKTtcbiAgICB9LFxuICAgIGRpc3Bvc2U6ICgpID0+IHt9LFxuICB9O1xufVxuXG4vKipcbiAqIEV2YWx1YXRlIHRoZSBWTSdzIHN0YXRlIGFuZCB3cmFwIGl0IGluIGEgbGl2ZSBzZXNzaW9uLiBXaGlsZSBzdXNwZW5kZWQsXG4gKiB0aGUgVk0gc3RheXMgYWxpdmUgc28gYGNvbnRpbnVlV2l0aEV2ZW50c2AgY2FuIHJlc3VtZSBpdCBpbiBwbGFjZTtcbiAqIHRlcm1pbmFsIHN0YXRlcyBkaXNwb3NlIHRoZSBWTSBpbW1lZGlhdGVseSAoaW5zaWRlIGNoZWNrV29ya2Zsb3dTdGF0ZSkuXG4gKi9cbmZ1bmN0aW9uIG1ha2VMaXZlU2Vzc2lvbihcbiAgdm06IFF1aWNrSlMsXG4gIHNlcmRlOiBRdWlja0pTU2VyZGUsXG4gIGludGVycnVwdEJ1ZGdldDogSW50ZXJydXB0QnVkZ2V0LFxuICBhZHZhbmNlQ2xvY2s6IChtczogbnVtYmVyKSA9PiB2b2lkLFxuICBlbmNyeXB0aW9uS2V5PzogRGVjcnlwdGlvbktleVxuKTogUXVpY2tKU1dvcmtmbG93U2Vzc2lvbiB7XG4gIGNvbnN0IHJlc3VsdCA9IGNoZWNrV29ya2Zsb3dTdGF0ZSh2bSwgc2VyZGUsIHsga2VlcEFsaXZlT25TdXNwZW5kOiB0cnVlIH0pO1xuICBsZXQgYWxpdmUgPSAhIXJlc3VsdC5zdXNwZW5kZWQ7XG5cbiAgY29uc3Qgc2Vzc2lvbjogUXVpY2tKU1dvcmtmbG93U2Vzc2lvbiA9IHtcbiAgICByZXN1bHQsXG4gICAgYXN5bmMgY29udGludWVXaXRoRXZlbnRzKFxuICAgICAgbmV3RXZlbnRzOiBFdmVudFtdXG4gICAgKTogUHJvbWlzZTxRdWlja0pTUnVudGltZVJlc3VsdD4ge1xuICAgICAgaWYgKCFhbGl2ZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ1F1aWNrSlMgd29ya2Zsb3cgc2Vzc2lvbiBpcyBub3QgYWxpdmUg4oCUIGNvbnRpbnVlV2l0aEV2ZW50cyBpcyBvbmx5IHZhbGlkIHdoaWxlIHN1c3BlbmRlZCdcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIC8vIEZyZXNoIGV4ZWN1dGlvbiBidXJzdDogdGhlIGludGVycnVwdCBidWRnZXQgYm91bmRzIFZNIGNvbXB1dGUsXG4gICAgICAvLyBub3Qgd2FsbCB0aW1lIHNwZW50IHdhaXRpbmcgb24gaW5saW5lIHN0ZXBzIGJldHdlZW4gYnVyc3RzLlxuICAgICAgaW50ZXJydXB0QnVkZ2V0LnN0YXJ0ID0gRGF0ZS5ub3coKTtcblxuICAgICAgbGV0IG1heEl0ZXJhdGlvbnMgPSAxMDA7XG4gICAgICBsZXQgbWFkZVByb2dyZXNzOiBib29sZWFuO1xuICAgICAgZG8ge1xuICAgICAgICBtYWRlUHJvZ3Jlc3MgPSBhd2FpdCBwcm9jZXNzRXZlbnRzKFxuICAgICAgICAgIHZtLFxuICAgICAgICAgIHNlcmRlLFxuICAgICAgICAgIG5ld0V2ZW50cyxcbiAgICAgICAgICBhZHZhbmNlQ2xvY2ssXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgICBsZXQgYmF0Y2g6IG51bWJlcjtcbiAgICAgICAgZG8ge1xuICAgICAgICAgIGJhdGNoID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgaWYgKGJhdGNoID4gMCkgbWFkZVByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgfSB3aGlsZSAoYmF0Y2ggPiAwKTtcbiAgICAgIH0gd2hpbGUgKG1hZGVQcm9ncmVzcyAmJiAtLW1heEl0ZXJhdGlvbnMgPiAwKTtcblxuICAgICAgY29uc3QgbmV4dCA9IGNoZWNrV29ya2Zsb3dTdGF0ZSh2bSwgc2VyZGUsIHtcbiAgICAgICAga2VlcEFsaXZlT25TdXNwZW5kOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBpZiAoIW5leHQuc3VzcGVuZGVkKSBhbGl2ZSA9IGZhbHNlO1xuICAgICAgc2Vzc2lvbi5yZXN1bHQgPSBuZXh0O1xuICAgICAgcmV0dXJuIG5leHQ7XG4gICAgfSxcbiAgICBkaXNwb3NlKCk6IHZvaWQge1xuICAgICAgaWYgKGFsaXZlKSB7XG4gICAgICAgIGFsaXZlID0gZmFsc2U7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdm0uZGlzcG9zZSgpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBBbHJlYWR5IGRpc3Bvc2VkLCBzbyBpZ25vcmUuXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICB9O1xuICByZXR1cm4gc2Vzc2lvbjtcbn1cblxuLy8gLS0tLSBFdmVudCBQcm9jZXNzaW5nIC0tLS1cblxuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0V2ZW50cyhcbiAgdm06IFF1aWNrSlMsXG4gIHNlcmRlOiBRdWlja0pTU2VyZGUsXG4gIGV2ZW50czogRXZlbnRbXSxcbiAgYWR2YW5jZUNsb2NrOiAobXM6IG51bWJlcikgPT4gdm9pZCxcbiAgZW5jcnlwdGlvbktleT86IERlY3J5cHRpb25LZXlcbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBsZXQgcmVzb2x2ZWQgPSBmYWxzZTtcbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICAvLyBBIHNlYWxlZC1sb2cgbm9vcCBvY2N1cGllcyBhIHNsb3Qgd2hvc2Ugd3JpdGVyIGRpZWQ7IHRoZSBydW4gbmV2ZXJcbiAgICAvLyBvYnNlcnZlZCBpdC4gU3RlcCBvdmVyIGl0IEJFRk9SRSB0aGUgY2xvY2sgbGluZSBiZWxvdywgbm90IGF0IHRoZVxuICAgIC8vIHN3aXRjaDogaXRzIGBjcmVhdGVkQXRgIGlzIHRoZSBzZWFsZXIncyB3YWxsIGNsb2NrIGFuZCBjYW4gcG9zdGRhdGVcbiAgICAvLyBldmVyeSByZWFsIGV2ZW50IGFyb3VuZCBpdCwgc28gYWR2YW5jaW5nIHRvIGl0IHdvdWxkIGxlYWsgdGhlIHNlYWxlcidzXG4gICAgLy8gc2NoZWR1bGUgaW50byByZXBsYXkuIEJlY2F1c2UgdGhlIGNsb2NrIGlzIG1vbm90b25pYywgZXZlcnkgbGF0ZXJcbiAgICAvLyBEYXRlLm5vdygpIGluIHRoZSBydW4gd2l0aCBpdC4gVGhhdCB3b3VsZCBtYWtlIGEgbG9nIHdob3NlIGhvbGUgd2FzXG4gICAgLy8gc2VhbGVkIHJlcGxheSBkaWZmZXJlbnRseSBmcm9tIHRoZSBzYW1lIGxvZyB3aG9zZSBob2xlIGl0cyBvd24gd3JpdGVyXG4gICAgLy8gZmlsbGVkLCBhbmQgZGlmZmVyZW50bHkgZnJvbSB0aGlzIGxvZyBvbiB0aGUgbm9kZTp2bSBlbmdpbmUsIHdoaWNoXG4gICAgLy8gc2tpcHMgbm9vcHMgaW4gYEV2ZW50c0NvbnN1bWVyYCBiZWZvcmUgYG9uQ29uc3VtZWRFdmVudGAgZmVlZHMgdGhlXG4gICAgLy8gY2xvY2suIFNhbWUgcnVsZSwgYm90aCBlbmdpbmVzLCBvbmUgcHJlZGljYXRlLlxuICAgIGlmIChpc1NlYWxlZE5vb3BFdmVudChldmVudCkpIGNvbnRpbnVlO1xuXG4gICAgLy8gQWR2YW5jZSB0aGUgVk0ncyBkZXRlcm1pbmlzdGljIGNsb2NrIHRvIHRoaXMgZXZlbnQncyBjcmVhdGlvbiB0aW1lXG4gICAgLy8gQkVGT1JFIHJlc29sdmluZyBhbnl0aGluZywgc28gd29ya2Zsb3cgY29kZSB1bmJsb2NrZWQgYnkgdGhpcyBldmVudFxuICAgIC8vIG9ic2VydmVzIERhdGUubm93KCkgYXQgKG9yIGFmdGVyLCBzaW5jZSB0aGUgY2xvY2sgaXMgbW9ub3RvbmljKSB0aGUgdGltZVxuICAgIC8vIHRoZSBldmVudCB3YXMgcmVjb3JkZWQuIE1pcnJvcnMgdGhlIG5vZGU6dm0gZW5naW5lJ3NcbiAgICAvLyBgb25Db25zdW1lZEV2ZW50IOKGkiB1cGRhdGVUaW1lc3RhbXAoK2V2ZW50LmNyZWF0ZWRBdClgLlxuICAgIGFkdmFuY2VDbG9jaygrZXZlbnQuY3JlYXRlZEF0KTtcblxuICAgIGNvbnN0IGNpZCA9IGV2ZW50LmNvcnJlbGF0aW9uSWQ7XG4gICAgaWYgKCFjaWQpIGNvbnRpbnVlO1xuXG4gICAgLy8gSlNPTi5zdHJpbmdpZnkgaGFuZGxlcyBxdW90ZXMsIGJhY2tzbGFzaGVzIGFuZCBjb250cm9sIGNoYXJhY3RlcnM7XG4gICAgLy8gY29ycmVsYXRpb24gaWRzIGFyZSBob3N0LWdlbmVyYXRlZCBVTElEcyB0b2RheSwgYnV0IHRoZSBldmFsLXN0cmluZ1xuICAgIC8vIHNhZmV0eSBzaG91bGRuJ3QgZGVwZW5kIG9uIHRoYXQgaW52YXJpYW50IGJlaW5nIGFzc2VydGVkIG5vd2hlcmUuXG4gICAgY29uc3QgY2lkSnMgPSBKU09OLnN0cmluZ2lmeShjaWQpO1xuICAgIGNvbnN0IGV2ZW50RGF0YSA9XG4gICAgICAnZXZlbnREYXRhJyBpbiBldmVudFxuICAgICAgICA/IChldmVudC5ldmVudERhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pXG4gICAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgLy8gTG9nIHRoZSBldmVudCBhbmQgd2hldGhlciB0aGUgcmVzb2x2ZXIgZXhpc3RzXG4gICAgc3dpdGNoIChldmVudC5ldmVudFR5cGUpIHtcbiAgICAgIGNhc2UgJ3N0ZXBfY29tcGxldGVkJzoge1xuICAgICAgICBjb25zdCBoYXNSZXNvbHZlciA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoYCEhZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV1gKVxuICAgICAgICApO1xuICAgICAgICBjb25zdCByYXdPdXRwdXQgPSBldmVudERhdGE/LnJlc3VsdCA/PyBldmVudERhdGE/Lm91dHB1dDtcbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgaWYgKHJhd091dHB1dCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgICAgIC8vIERlY3J5cHQgaWYgZW5jcnlwdGVkOiB0aGUgVk0gb25seSB1bmRlcnN0YW5kcyAnZGV2bCcgZm9ybWF0XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRdWlja0pTIHJ1bnRpbWU6IHN0ZXAgcmVzdWx0IHJhdycsIHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgICAgICByYXdQcmVmaXg6IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShyYXdPdXRwdXQuc3ViYXJyYXkoMCwgNCkpLFxuICAgICAgICAgICAgICByYXdCeXRlTGVuZ3RoOiByYXdPdXRwdXQuYnl0ZUxlbmd0aCxcbiAgICAgICAgICAgICAgaXNCdWZmZXI6IEJ1ZmZlci5pc0J1ZmZlcihyYXdPdXRwdXQpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBkZWNyeXB0ZWRPdXRwdXQgPSBhd2FpdCBwcmVwYXJlQnl0ZXNGb3JWTShcbiAgICAgICAgICAgICAgcmF3T3V0cHV0LFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBzdGVwIHJlc3VsdCBkZWNyeXB0ZWQnLCB7XG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGNpZCxcbiAgICAgICAgICAgICAgcHJlZml4OiBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGVjcnlwdGVkT3V0cHV0LnN1YmFycmF5KDAsIDQpKSxcbiAgICAgICAgICAgICAgYnl0ZUxlbmd0aDogZGVjcnlwdGVkT3V0cHV0LmJ5dGVMZW5ndGgsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlSGFuZGxlID0gc2VyZGUuZGVzZXJpYWxpemUoZGVjcnlwdGVkT3V0cHV0KTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfcmVzdWx0JywgdmFsdWVIYW5kbGUpO1xuICAgICAgICAgICAgdmFsdWVIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XS5yZXNvbHZlKGdsb2JhbFRoaXMuX190bXBfcmVzdWx0KTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3RtcF9yZXN1bHQ7YFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgcnVudGltZTogc3RlcCByZXN1bHQgbm9uLWJpbmFyeScsIHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgICAgICB0eXBlOiB0eXBlb2YgcmF3T3V0cHV0LFxuICAgICAgICAgICAgICBpc051bGw6IHJhd091dHB1dCA9PT0gbnVsbCxcbiAgICAgICAgICAgICAgaXNVbmRlZmluZWQ6IHJhd091dHB1dCA9PT0gdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBjb25zdHJ1Y3RvcjogcmF3T3V0cHV0Py5jb25zdHJ1Y3Rvcj8ubmFtZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9XG4gICAgICAgICAgICAgIHJhd091dHB1dCAhPT0gdW5kZWZpbmVkID8gSlNPTi5zdHJpbmdpZnkocmF3T3V0cHV0KSA6ICd1bmRlZmluZWQnO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XS5yZXNvbHZlKCR7c2VyaWFsaXplZH0pO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV07YFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIERyYWluIEFMTCBtaWNyb3Rhc2tzIGFmdGVyIHJlc29sdmVcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCwgc28gYnVmZmVyIHRoZSBwcmVwYXJlZCBvdXRjb21lIHNvIHRoZSBwcm9taXNlXG4gICAgICAgICAgLy8gc2V0dGxlcyB0aGUgbW9tZW50IHRoZSBWTSBjb25zdHJ1Y3RzIGl0IChzZWUgX190ZXJtaW5hbEJ1ZmZlclxuICAgICAgICAgIC8vIGluIHRoZSBib290c3RyYXApLiBXaXRob3V0IHRoaXMsIHRoZSBsaXZlLWNvbnRpbnVhdGlvbiBwYXRoXG4gICAgICAgICAgLy8gKHdoaWNoIHNjYW5zIGVhY2ggZGVsdGEgZXhhY3RseSBvbmNlKSBkcm9wcyB0aGUgdGVybWluYWwgYW5kXG4gICAgICAgICAgLy8gdGhlIGF3YWl0IG5ldmVyIHNldHRsZXMuXG4gICAgICAgICAgaWYgKHJhd091dHB1dCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZE91dHB1dCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdPdXRwdXQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICAvLyBIb3N0IHNlcmRlOiBkZXNlcmlhbGl6ZSBpbnRvIGEgVk0gdmFsdWUgTk9XIChzYW1lIHBhdGggYXNcbiAgICAgICAgICAgIC8vIHRoZSByZXNvbHZlciBicmFuY2ggYWJvdmUpIGFuZCBidWZmZXIgdGhlIHZhbHVlIGl0c2VsZi5cbiAgICAgICAgICAgIGNvbnN0IHZhbHVlSGFuZGxlID0gc2VyZGUuZGVzZXJpYWxpemUoZGVjcnlwdGVkT3V0cHV0KTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfYnVmJywgdmFsdWVIYW5kbGUpO1xuICAgICAgICAgICAgdmFsdWVIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfdmFsdWVcIiwgdmFsdWU6IGdsb2JhbFRoaXMuX190bXBfYnVmIH07YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fdG1wX2J1ZjtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9XG4gICAgICAgICAgICAgIHJhd091dHB1dCAhPT0gdW5kZWZpbmVkID8gSlNPTi5zdHJpbmdpZnkocmF3T3V0cHV0KSA6ICd1bmRlZmluZWQnO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfdmFsdWVcIiwgdmFsdWU6ICR7c2VyaWFsaXplZH0gfTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdzdGVwX2ZhaWxlZCc6IHtcbiAgICAgICAgY29uc3QgaGFzUmVzb2x2ZXIgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKGAhIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dYClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgY29uc3QgZXJyb3JEYXRhID0gZXZlbnREYXRhPy5lcnJvcjtcbiAgICAgICAgICBpZiAoZXJyb3JEYXRhIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICAgICAgLy8gTW9kZXJuIHBhdGggKHBvc3QtIzE4NTEpOiB0aGUgc3RlcCBoYW5kbGVyIGRlaHlkcmF0ZWQgdGhlXG4gICAgICAgICAgICAvLyB0aHJvd24gdmFsdWUgdGhyb3VnaCB0aGUgZmlyc3QtY2xhc3MgZXJyb3IgcGlwZWxpbmUuIERlY3J5cHRcbiAgICAgICAgICAgIC8vIChpZiBlbmNyeXB0ZWQpIGFuZCBwYXNzIHRoZSBieXRlcyB0byB0aGUgVk0tc2lkZSBkZXNlcmlhbGl6ZXJcbiAgICAgICAgICAgIC8vIHNvIHRoZSB3b3JrZmxvdyBjYXRjaCBzZWVzIGEgcHJvcGVybHkgdHlwZWQgRXJyb3Igc3ViY2xhc3NcbiAgICAgICAgICAgIC8vIChUeXBlRXJyb3IsIEZhdGFsRXJyb3Igd2l0aCBvcmlnaW5hbCBjYXVzZSBjaGFpbiwgZXRjLikgd2l0aFxuICAgICAgICAgICAgLy8gdGhlIG9yaWdpbmFsIG1lc3NhZ2UgYW5kIHN0YWNrIHByZXNlcnZlZC5cbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKGVycm9yRGF0YSwgZW5jcnlwdGlvbktleSk7XG4gICAgICAgICAgICBjb25zdCBlcnJvckhhbmRsZSA9IHNlcmRlLmRlc2VyaWFsaXplKGRlY3J5cHRlZCk7XG4gICAgICAgICAgICB2bS5zZXRQcm9wKHZtLmdsb2JhbCwgJ19fdG1wX2Vycm9yJywgZXJyb3JIYW5kbGUpO1xuICAgICAgICAgICAgZXJyb3JIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGAoZnVuY3Rpb24oKXtgICtcbiAgICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVqZWN0KGdsb2JhbFRoaXMuX190bXBfZXJyb3IpO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV07YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fdG1wX2Vycm9yO2AgK1xuICAgICAgICAgICAgICAgIGB9KSgpYFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIExlZ2FjeSBwYXRoOiBwcmUtcGlwZWxpbmUgZXZlbnRzIHN0b3JlZCBlcnJvciBhc1xuICAgICAgICAgICAgLy8gYHsgbWVzc2FnZSwgc3RhY2ssIGNvZGUgfWAuIFJlY29uc3RydWN0IGEgRmF0YWxFcnJvciBzb1xuICAgICAgICAgICAgLy8gd29ya2Zsb3cgY2F0Y2ggY2FuIGRldGVjdCBpdCB2aWEgRmF0YWxFcnJvci5pcygpLCBtYXRjaGluZ1xuICAgICAgICAgICAgLy8gdGhlIG9yaWdpbmFsIFYxIHN0ZXAgaGFuZGxlciBiZWhhdmlvci5cbiAgICAgICAgICAgIGNvbnN0IGlzRXJyb3JPYmplY3QgPVxuICAgICAgICAgICAgICB0eXBlb2YgZXJyb3JEYXRhID09PSAnb2JqZWN0JyAmJiBlcnJvckRhdGEgIT09IG51bGw7XG4gICAgICAgICAgICBjb25zdCBtc2cgPSBpc0Vycm9yT2JqZWN0XG4gICAgICAgICAgICAgID8gKCgoZXJyb3JEYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5tZXNzYWdlIGFzIHN0cmluZykgPz9cbiAgICAgICAgICAgICAgICAnU3RlcCBmYWlsZWQnKVxuICAgICAgICAgICAgICA6IHR5cGVvZiBlcnJvckRhdGEgPT09ICdzdHJpbmcnXG4gICAgICAgICAgICAgICAgPyBlcnJvckRhdGFcbiAgICAgICAgICAgICAgICA6ICdTdGVwIGZhaWxlZCc7XG4gICAgICAgICAgICBjb25zdCBlcnJvclN0YWNrID1cbiAgICAgICAgICAgICAgKGlzRXJyb3JPYmplY3RcbiAgICAgICAgICAgICAgICA/IChlcnJvckRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLnN0YWNrXG4gICAgICAgICAgICAgICAgOiB1bmRlZmluZWQpID8/IChldmVudERhdGE/LnN0YWNrIGFzIHN0cmluZyB8IHVuZGVmaW5lZCk7XG4gICAgICAgICAgICBjb25zdCBzdGFja0Fzc2lnbm1lbnQgPSBlcnJvclN0YWNrXG4gICAgICAgICAgICAgID8gYGUuc3RhY2s9JHtKU09OLnN0cmluZ2lmeShlcnJvclN0YWNrKX07YFxuICAgICAgICAgICAgICA6ICcnO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGAoZnVuY3Rpb24oKXt2YXIgZT1uZXcgRXJyb3IoJHtKU09OLnN0cmluZ2lmeShtc2cpfSk7ZS5uYW1lPVwiRmF0YWxFcnJvclwiO2UuZmF0YWw9dHJ1ZTske3N0YWNrQXNzaWdubWVudH1gICtcbiAgICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVqZWN0KGUpO2AgK1xuICAgICAgICAgICAgICAgIGBkZWxldGUgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV07fSkoKWBcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCwgc28gYnVmZmVyIHRoZSBwcmVwYXJlZCByZWplY3Rpb24gKHNlZSB0aGVcbiAgICAgICAgICAvLyBzdGVwX2NvbXBsZXRlZCBicmFuY2ggYWJvdmUgZm9yIHRoZSByYXRpb25hbGUpLlxuICAgICAgICAgIGNvbnN0IGVycm9yRGF0YSA9IGV2ZW50RGF0YT8uZXJyb3I7XG4gICAgICAgICAgaWYgKGVycm9yRGF0YSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKGVycm9yRGF0YSwgZW5jcnlwdGlvbktleSk7XG4gICAgICAgICAgICAvLyBIb3N0IHNlcmRlOiBkZXNlcmlhbGl6ZSBpbnRvIHRoZSBWTSBlcnJvciB2YWx1ZSBOT1cgKHNhbWVcbiAgICAgICAgICAgIC8vIHBhdGggYXMgdGhlIHJlc29sdmVyIGJyYW5jaCBhYm92ZSkgYW5kIGJ1ZmZlciBpdC5cbiAgICAgICAgICAgIGNvbnN0IGVycm9ySGFuZGxlID0gc2VyZGUuZGVzZXJpYWxpemUoZGVjcnlwdGVkKTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfYnVmJywgZXJyb3JIYW5kbGUpO1xuICAgICAgICAgICAgZXJyb3JIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlamVjdF92YWx1ZVwiLCB2YWx1ZTogZ2xvYmFsVGhpcy5fX3RtcF9idWYgfTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX190bXBfYnVmO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBpc0Vycm9yT2JqZWN0ID1cbiAgICAgICAgICAgICAgdHlwZW9mIGVycm9yRGF0YSA9PT0gJ29iamVjdCcgJiYgZXJyb3JEYXRhICE9PSBudWxsO1xuICAgICAgICAgICAgY29uc3QgbXNnID0gaXNFcnJvck9iamVjdFxuICAgICAgICAgICAgICA/ICgoKGVycm9yRGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikubWVzc2FnZSBhcyBzdHJpbmcpID8/XG4gICAgICAgICAgICAgICAgJ1N0ZXAgZmFpbGVkJylcbiAgICAgICAgICAgICAgOiB0eXBlb2YgZXJyb3JEYXRhID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgID8gZXJyb3JEYXRhXG4gICAgICAgICAgICAgICAgOiAnU3RlcCBmYWlsZWQnO1xuICAgICAgICAgICAgY29uc3QgZXJyb3JTdGFjayA9XG4gICAgICAgICAgICAgIChpc0Vycm9yT2JqZWN0XG4gICAgICAgICAgICAgICAgPyAoZXJyb3JEYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5zdGFja1xuICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkKSA/PyAoZXZlbnREYXRhPy5zdGFjayBhcyBzdHJpbmcgfCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlamVjdF9lcnJvclwiLCBtZXNzYWdlOiAke0pTT04uc3RyaW5naWZ5KG1zZyl9LCBzdGFjazogJHtlcnJvclN0YWNrID8gSlNPTi5zdHJpbmdpZnkoZXJyb3JTdGFjaykgOiAndW5kZWZpbmVkJ30gfTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICd3YWl0X2NvbXBsZXRlZCc6IHtcbiAgICAgICAgY29uc3QgaGFzUmVzb2x2ZXIgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKGAhIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dYClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVzb2x2ZSgpO2AgK1xuICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO2BcbiAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCwgc28gYnVmZmVyIChzZWUgc3RlcF9jb21wbGV0ZWQgYWJvdmUpLlxuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYGdsb2JhbFRoaXMuX190ZXJtaW5hbEJ1ZmZlclske2NpZEpzfV0gPSB7IGtpbmQ6IFwicmVzb2x2ZV91bmRlZmluZWRcIiB9O2BcbiAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgfVxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ2F0dHJfc2V0Jzoge1xuICAgICAgICAvLyBPbmx5IHdvcmtmbG93LXdyaXR0ZW4gYXR0cmlidXRlIGV2ZW50cyByZXNvbHZlIGEgcGVuZGluZ1xuICAgICAgICAvLyBzZXRBdHRyaWJ1dGVzKCkgcHJvbWlzZTsgc3RlcC9zeXN0ZW0gd3JpdGVycyBzaGFyZSBub1xuICAgICAgICAvLyBjb3JyZWxhdGlvbklkcyB3aXRoIFZNIHJlc29sdmVycywgc28gdGhlIGd1YXJkIGlzIGRlZmVuc2l2ZS5cbiAgICAgICAgY29uc3Qgd3JpdGVyID0gKGV2ZW50RGF0YT8ud3JpdGVyIGFzIHsgdHlwZT86IHN0cmluZyB9IHwgdW5kZWZpbmVkKVxuICAgICAgICAgID8udHlwZTtcbiAgICAgICAgaWYgKHdyaXRlciAhPT0gJ3dvcmtmbG93JykgYnJlYWs7XG4gICAgICAgIGNvbnN0IGhhc1Jlc29sdmVyID0gdm0uZHVtcChcbiAgICAgICAgICB2bS5ldmFsQ29kZShgISFnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XWApXG4gICAgICAgICk7XG4gICAgICAgIGlmICghaGFzUmVzb2x2ZXIpIHtcbiAgICAgICAgICAvLyBObyByZXNvbHZlciB5ZXQsIHNvIGJ1ZmZlciAoc2VlIHN0ZXBfY29tcGxldGVkIGFib3ZlKS5cbiAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9fdGVybWluYWxCdWZmZXJbJHtjaWRKc31dID0geyBraW5kOiBcInJlc29sdmVfdW5kZWZpbmVkXCIgfTtgXG4gICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGhhc1Jlc29sdmVyKSB7XG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVzb2x2ZSgpO2AgK1xuICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dO2BcbiAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAnaG9va19yZWNlaXZlZCc6IHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBldmVudCB3YXMgYWxyZWFkeSBwcm9jZXNzZWQgKGRlbGl2ZXJlZCBvclxuICAgICAgICAvLyBidWZmZXJlZCkgd2l0aGluIHRoaXMgaW52b2NhdGlvbi4gUHJldmVudHMgZG91YmxlLWRlbGl2ZXJ5IHdoZW5cbiAgICAgICAgLy8gdGhlIG91dGVyIGxvb3AgcmUtc2NhbnMgZXZlbnRzLlxuICAgICAgICBjb25zdCBhbHJlYWR5UHJvY2Vzc2VkID0gZXZlbnQuZXZlbnRJZFxuICAgICAgICAgID8gdm0uZHVtcChcbiAgICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgICAgYCEhKGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzICYmIGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzWyR7SlNPTi5zdHJpbmdpZnkoZXZlbnQuZXZlbnRJZCl9XSlgXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IGZhbHNlO1xuICAgICAgICBpZiAoYWxyZWFkeVByb2Nlc3NlZCkge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBob29rX3JlY2VpdmVkIGFscmVhZHkgcHJvY2Vzc2VkJyxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgICAgICBldmVudElkOiBldmVudC5ldmVudElkLFxuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlc2lsaWVudC1yZXN1bWUgZGVkdXAgKHBhcml0eSB3aXRoIHRoZSBub2RlIGVuZ2luZSdzXG4gICAgICAgIC8vIEV2ZW50c0NvbnN1bWVyIGluIHdvcmtmbG93L2hvb2sudHMpOiB0d28gaG9va19yZWNlaXZlZCByb3dzIGZvclxuICAgICAgICAvLyBPTkUgcmVzdW1lIGF0dGVtcHQgc2hhcmUgYSBjbGllbnQtbWludGVkIGByZXN1bWVJZGAgKGEgZHVwbGljYXRlXG4gICAgICAgIC8vIGNhbiBiZSBjb21taXR0ZWQgd2hlbiB0aGUgbWF0ZXJpYWxpemF0aW9uIGZhbGxiYWNrIHJhY2VzIGFcbiAgICAgICAgLy8gZGVsYXllZCBkaXJlY3Qgd3JpdGUsIHNpbmNlIGhvb2tfcmVjZWl2ZWQgaGFzIG5vIHN0b3JhZ2UgdW5pcXVlbmVzc1xuICAgICAgICAvLyBjb25zdHJhaW50KS4gRGVsaXZlciBvbmx5IHRoZSBmaXJzdC1pbi1sb2cgb2NjdXJyZW5jZS4gVGhlIHNlZW5cbiAgICAgICAgLy8gc2V0IGxpdmVzIGluIHRoZSBWTSBoZWFwIHNvIGl0IGlzIGRldGVybWluaXN0aWMgcGVyIHJlcGxheSBhbmRcbiAgICAgICAgLy8gc3Vydml2ZXMgZXZlbnQgcmUtc2NhbnMgd2l0aGluIHRoZSBpbnZvY2F0aW9uLiBFdmVudHMgd2l0aG91dCBhXG4gICAgICAgIC8vIHJlc3VtZUlkIChvbGRlciBTREtzKSBhcmUgbmV2ZXIgZGVkdXBlZC5cbiAgICAgICAge1xuICAgICAgICAgIC8vIFRvcC1sZXZlbCBldmVudC5yZXN1bWVJZCBpcyB0aGUgY2Fub25pY2FsIGxvY2F0aW9uICh0aGUgYmFja2VuZFxuICAgICAgICAgIC8vIGhvaXN0cyBpdCB0byBhIGZpcnN0LWNsYXNzIGNvbHVtbik7IHRoZSBuZXN0ZWRcbiAgICAgICAgICAvLyBldmVudERhdGEucmVzdW1lSWQgZm9ybSBpcyBhIGRlcHJlY2F0ZWQgbGVnYWN5IGZhbGxiYWNrLlxuICAgICAgICAgIC8vIE1pcnJvcnMgdGhlIG5vZGUgZW5naW5lJ3MgZGVkdXAgaW4gd29ya2Zsb3cvaG9vay50cy5cbiAgICAgICAgICBjb25zdCByZXN1bWVJZCA9XG4gICAgICAgICAgICAoZXZlbnQgYXMgeyByZXN1bWVJZD86IHVua25vd24gfSkucmVzdW1lSWQgPz9cbiAgICAgICAgICAgIChldmVudERhdGEgYXMgeyByZXN1bWVJZD86IHVua25vd24gfSB8IHVuZGVmaW5lZCk/LnJlc3VtZUlkO1xuICAgICAgICAgIGlmICh0eXBlb2YgcmVzdW1lSWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBjb25zdCByZXN1bWVJZEpzID0gSlNPTi5zdHJpbmdpZnkocmVzdW1lSWQpO1xuICAgICAgICAgICAgY29uc3QgZHVwbGljYXRlID0gdm0uZHVtcChcbiAgICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1NlZW5SZXN1bWVJZHMgPSBnbG9iYWxUaGlzLl9faG9va1NlZW5SZXN1bWVJZHMgfHwge30pWyR7cmVzdW1lSWRKc31dID09PSB0cnVlYFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKGR1cGxpY2F0ZSkge1xuICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICdRdWlja0pTIHJ1bnRpbWU6IGR1cGxpY2F0ZSBob29rX3JlY2VpdmVkIGZvciB0aGUgc2FtZSByZXN1bWUgYXR0ZW1wdCwgZHJvcHBpbmcnLFxuICAgICAgICAgICAgICAgIHsgY29ycmVsYXRpb25JZDogY2lkLCBldmVudElkOiBldmVudC5ldmVudElkLCByZXN1bWVJZCB9XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGlmIChldmVudC5ldmVudElkKSB7XG4gICAgICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgICAgICBgKGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzID0gZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyLl9fcHJvY2Vzc2VkRXZlbnRJZHMgfHwge30pWyR7SlNPTi5zdHJpbmdpZnkoZXZlbnQuZXZlbnRJZCl9XSA9IHRydWU7YFxuICAgICAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIG1hcmtDcmVhdGVkKHZtLCBjaWRKcyk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGBnbG9iYWxUaGlzLl9faG9va1NlZW5SZXN1bWVJZHNbJHtyZXN1bWVJZEpzfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFib3J0IGRlbGl2ZXJ5OiBob29rX3JlY2VpdmVkIGZvciBhbiBBYm9ydENvbnRyb2xsZXIncyBzeXN0ZW1cbiAgICAgICAgLy8gaG9vayBmbGlwcyB0aGUgcmVnaXN0ZXJlZCBzaWduYWwgaW5zdGVhZCBvZiByZXNvbHZpbmcgYSBwcm9taXNlLlxuICAgICAgICAvLyBUaGUgcGF5bG9hZCBpcyB0aGUgZGVoeWRyYXRlZCBgeyBhYm9ydGVkOiB0cnVlLCByZWFzb24gfWAgb2JqZWN0LlxuICAgICAgICBjb25zdCBpc0Fib3J0SG9vayA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgISEoZ2xvYmFsVGhpcy5fX2Fib3J0U2lnbmFscyAmJiBnbG9iYWxUaGlzLl9fYWJvcnRTaWduYWxzWyR7Y2lkSnN9XSlgXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICBpZiAoaXNBYm9ydEhvb2spIHtcbiAgICAgICAgICBjb25zdCByYXdBYm9ydFBheWxvYWQgPSBldmVudERhdGE/LnBheWxvYWQ7XG4gICAgICAgICAgaWYgKHJhd0Fib3J0UGF5bG9hZCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdBYm9ydFBheWxvYWQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBwYXlsb2FkSGFuZGxlID0gc2VyZGUuZGVzZXJpYWxpemUoZGVjcnlwdGVkKTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfYWJvcnQnLCBwYXlsb2FkSGFuZGxlKTtcbiAgICAgICAgICAgIHBheWxvYWRIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGAoZnVuY3Rpb24oKXtgICtcbiAgICAgICAgICAgICAgICBgdmFyIHA9Z2xvYmFsVGhpcy5fX3RtcF9hYm9ydDtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX190bXBfYWJvcnQ7YCArXG4gICAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19hYm9ydFNpZ25hbHNbJHtjaWRKc31dLl9zZXRBYm9ydGVkKHAmJnR5cGVvZiBwPT09XCJvYmplY3RcIj9wLnJlYXNvbjp1bmRlZmluZWQpO2AgK1xuICAgICAgICAgICAgICAgIGB9KSgpYFxuICAgICAgICAgICAgKS5kaXNwb3NlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX2Fib3J0U2lnbmFsc1ske2NpZEpzfV0uX3NldEFib3J0ZWQodW5kZWZpbmVkKTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gVGhlIGFib3J0IGlzIGR1cmFibHkgcmVjb3JkZWQsIHNvIGNsZWFyIHRoZSBwZW5kaW5nIG9wJ3NcbiAgICAgICAgICAvLyBhYm9ydFJlcXVlc3RlZCBtYXJrZXIgc28gdGhlIGhvc3QgZG9lc24ndCByZS1yZWNvcmQgaXQgKHRoZVxuICAgICAgICAgIC8vIHdvcmtmbG93J3Mgb3duIGFib3J0KCkgY2FsbCBjYW4gc2V0IHRoZSBmbGFnIGJlZm9yZSB0aGlzXG4gICAgICAgICAgLy8gZXZlbnQgaXMgcHJvY2Vzc2VkIHdoZW4gaXQgaGFwcGVucyBsYXRlciBpbiByZXBsYXkgb3JkZXIsXG4gICAgICAgICAgLy8gYW5kIGhvb2tfcmVjZWl2ZWQgZXZlbnRzIGFyZSBub3QgdW5pcXVlIHBlciBjb3JyZWxhdGlvbklkKS5cbiAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgIGAoZnVuY3Rpb24oKXtgICtcbiAgICAgICAgICAgICAgYHZhciBwPWdsb2JhbFRoaXMuX19wZW5kaW5nLmZpbmQoZnVuY3Rpb24ocSl7cmV0dXJuIHEuY29ycmVsYXRpb25JZD09PSR7SlNPTi5zdHJpbmdpZnkoY2lkKX0mJnEudHlwZT09PVwiaG9va1wiO30pO2AgK1xuICAgICAgICAgICAgICBgaWYocClwLmFib3J0UmVxdWVzdGVkPWZhbHNlO2AgK1xuICAgICAgICAgICAgICBgfSkoKWBcbiAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICBpZiAoZXZlbnQuZXZlbnRJZCkge1xuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGAoZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyLl9fcHJvY2Vzc2VkRXZlbnRJZHMgPSBnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyB8fCB7fSlbJHtKU09OLnN0cmluZ2lmeShldmVudC5ldmVudElkKX1dID0gdHJ1ZTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgbGV0IGI6IG51bWJlcjtcbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgYiA9IHZtLmV4ZWN1dGVQZW5kaW5nSm9icygpO1xuICAgICAgICAgICAgfSB3aGlsZSAoYiA+IDApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaGFzUmVzb2x2ZXIgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKGAhIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dYClcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgcmF3UGF5bG9hZCA9IGV2ZW50RGF0YT8ucGF5bG9hZCA/PyBldmVudERhdGE/LnJlc3VsdDtcbiAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBwcm9jZXNzaW5nIGhvb2tfcmVjZWl2ZWQnLCB7XG4gICAgICAgICAgY29ycmVsYXRpb25JZDogY2lkLFxuICAgICAgICAgIGV2ZW50SWQ6IGV2ZW50LmV2ZW50SWQsXG4gICAgICAgICAgaGFzUmVzb2x2ZXIsXG4gICAgICAgICAgcGF5bG9hZFR5cGU6IHR5cGVvZiByYXdQYXlsb2FkLFxuICAgICAgICAgIHBheWxvYWRJc1VpbnQ4QXJyYXk6IHJhd1BheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5LFxuICAgICAgICAgIHBheWxvYWRLZXlzOlxuICAgICAgICAgICAgcmF3UGF5bG9hZCAmJiB0eXBlb2YgcmF3UGF5bG9hZCA9PT0gJ29iamVjdCdcbiAgICAgICAgICAgICAgPyBPYmplY3Qua2V5cyhyYXdQYXlsb2FkKVxuICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChoYXNSZXNvbHZlcikge1xuICAgICAgICAgIGlmIChyYXdQYXlsb2FkIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICAgICAgLy8gRGVjcnlwdCBpZiBlbmNyeXB0ZWQ6IHRoZSBWTSBvbmx5IHVuZGVyc3RhbmRzICdkZXZsJyBmb3JtYXRcbiAgICAgICAgICAgIGNvbnN0IGRlY3J5cHRlZFBheWxvYWQgPSBhd2FpdCBwcmVwYXJlQnl0ZXNGb3JWTShcbiAgICAgICAgICAgICAgcmF3UGF5bG9hZCxcbiAgICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWRIYW5kbGUgPSBzZXJkZS5kZXNlcmlhbGl6ZShkZWNyeXB0ZWRQYXlsb2FkKTtcbiAgICAgICAgICAgIHZtLnNldFByb3Aodm0uZ2xvYmFsLCAnX190bXBfcmVzdWx0JywgcGF5bG9hZEhhbmRsZSk7XG4gICAgICAgICAgICBwYXlsb2FkSGFuZGxlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgICBgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1ske2NpZEpzfV0ucmVzb2x2ZShnbG9iYWxUaGlzLl9fdG1wX3Jlc3VsdCk7YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgICtcbiAgICAgICAgICAgICAgICBgZGVsZXRlIGdsb2JhbFRoaXMuX190bXBfcmVzdWx0O2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBzZXJpYWxpemVkID1cbiAgICAgICAgICAgICAgcmF3UGF5bG9hZCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShyYXdQYXlsb2FkKVxuICAgICAgICAgICAgICAgIDogJ3VuZGVmaW5lZCc7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYGdsb2JhbFRoaXMuX19yZXNvbHZlcnNbJHtjaWRKc31dLnJlc29sdmUoJHtzZXJpYWxpemVkfSk7YCArXG4gICAgICAgICAgICAgICAgYGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzWyR7Y2lkSnN9XTtgXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gTWFyayB0aGlzIGV2ZW50IGFzIHByb2Nlc3NlZCBpbiB0aGUgVk0gaGVhcCB0byBwcmV2ZW50XG4gICAgICAgICAgLy8gZG91YmxlLWRlbGl2ZXJ5IHdoZW4gdGhlIG91dGVyIGxvb3AgcmUtc2NhbnMgZXZlbnRzLlxuICAgICAgICAgIGlmIChldmVudC5ldmVudElkKSB7XG4gICAgICAgICAgICB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXIuX19wcm9jZXNzZWRFdmVudElkcyA9IGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzIHx8IHt9KVske0pTT04uc3RyaW5naWZ5KGV2ZW50LmV2ZW50SWQpfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICkuZGlzcG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICBiID0gdm0uZXhlY3V0ZVBlbmRpbmdKb2JzKCk7XG4gICAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIHJlc29sdmVyIHlldCwgc28gYnVmZmVyIHRoZSBwYXlsb2FkIGluIHRoZSBWTSBoZWFwLiBXaGVuXG4gICAgICAgICAgLy8gY3JlYXRlSG9va1Byb21pc2UoKSBpcyBjYWxsZWQgbGF0ZXIsIGl0IHdpbGwgZHJhaW4gdGhpcyBidWZmZXJcbiAgICAgICAgICAvLyBmaXJzdCAobWF0Y2hpbmcgdGhlIG5vZGU6dm0gZW5naW5lJ3MgcGF5bG9hZHNRdWV1ZSBiZWhhdmlvcikuXG4gICAgICAgICAgY29uc3QgZXZlbnRJZEpzID0gZXZlbnQuZXZlbnRJZFxuICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShldmVudC5ldmVudElkKVxuICAgICAgICAgICAgOiAnbnVsbCc7XG4gICAgICAgICAgY29uc3QgYnVmZmVyQW5kVHJhY2sgPVxuICAgICAgICAgICAgYChnbG9iYWxUaGlzLl9faG9va1BheWxvYWRCdWZmZXJbJHtjaWRKc31dID0gZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyWyR7Y2lkSnN9XSB8fCBbXSlgICtcbiAgICAgICAgICAgIGAucHVzaCglUEFZTE9BRCUpO2AgK1xuICAgICAgICAgICAgKGV2ZW50LmV2ZW50SWRcbiAgICAgICAgICAgICAgPyBgKGdsb2JhbFRoaXMuX19ob29rUGF5bG9hZEJ1ZmZlci5fX3Byb2Nlc3NlZEV2ZW50SWRzID0gZ2xvYmFsVGhpcy5fX2hvb2tQYXlsb2FkQnVmZmVyLl9fcHJvY2Vzc2VkRXZlbnRJZHMgfHwge30pWyR7ZXZlbnRJZEpzfV0gPSB0cnVlO2BcbiAgICAgICAgICAgICAgOiAnJyk7XG4gICAgICAgICAgaWYgKHJhd1BheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICAgICAgICAvLyBEZWNyeXB0IGlmIGVuY3J5cHRlZDogdGhlIFZNIG9ubHkgdW5kZXJzdGFuZHMgJ2RldmwnIGZvcm1hdFxuICAgICAgICAgICAgY29uc3QgZGVjcnlwdGVkUGF5bG9hZCA9IGF3YWl0IHByZXBhcmVCeXRlc0ZvclZNKFxuICAgICAgICAgICAgICByYXdQYXlsb2FkLFxuICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgcGF5bG9hZEhhbmRsZSA9IHNlcmRlLmRlc2VyaWFsaXplKGRlY3J5cHRlZFBheWxvYWQpO1xuICAgICAgICAgICAgdm0uc2V0UHJvcCh2bS5nbG9iYWwsICdfX3RtcF9yZXN1bHQnLCBwYXlsb2FkSGFuZGxlKTtcbiAgICAgICAgICAgIHBheWxvYWRIYW5kbGUuZGlzcG9zZSgpO1xuICAgICAgICAgICAgLy8gTk9URTogcmVwbGFjZW1lbnQgaXMgYSBmdW5jdGlvbiBzbyBgJGAtc2VxdWVuY2VzIGluIHRoZVxuICAgICAgICAgICAgLy8gc3Vic3RpdHV0ZWQgSlMgbmV2ZXIgZ2V0IGludGVycHJldGVkIGFzIFN0cmluZy5yZXBsYWNlXG4gICAgICAgICAgICAvLyBzcGVjaWFsIHJlcGxhY2VtZW50IHBhdHRlcm5zLlxuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGJ1ZmZlckFuZFRyYWNrLnJlcGxhY2UoXG4gICAgICAgICAgICAgICAgJyVQQVlMT0FEJScsXG4gICAgICAgICAgICAgICAgKCkgPT4gJ2dsb2JhbFRoaXMuX190bXBfcmVzdWx0J1xuICAgICAgICAgICAgICApICsgJ2RlbGV0ZSBnbG9iYWxUaGlzLl9fdG1wX3Jlc3VsdDsnXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9XG4gICAgICAgICAgICAgIHJhd1BheWxvYWQgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgID8gSlNPTi5zdHJpbmdpZnkocmF3UGF5bG9hZClcbiAgICAgICAgICAgICAgICA6ICd1bmRlZmluZWQnO1xuICAgICAgICAgICAgLy8gRnVuY3Rpb24gcmVwbGFjZW1lbnQ6IGEgSlNPTi1zZXJpYWxpemVkIHBheWxvYWQgY2FuIGNvbnRhaW5cbiAgICAgICAgICAgIC8vIGAkJmAsIGAkJ2AsIGAkXFxgYCwgLi4uIHdoaWNoIFN0cmluZy5yZXBsYWNlIHdvdWxkIG90aGVyd2lzZVxuICAgICAgICAgICAgLy8gZXhwYW5kLCBzaWxlbnRseSBjb3JydXB0aW5nIHRoZSBpbmplY3RlZCBjb2RlLlxuICAgICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICAgIGJ1ZmZlckFuZFRyYWNrLnJlcGxhY2UoJyVQQVlMT0FEJScsICgpID0+IHNlcmlhbGl6ZWQpXG4gICAgICAgICAgICApLmRpc3Bvc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdob29rX2NvbmZsaWN0Jzoge1xuICAgICAgICAvLyBBbm90aGVyIHdvcmtmbG93IG93bnMgdGhpcyBob29rIHRva2VuLiBQYXlsb2FkIGF3YWl0ZXJzIHJlamVjdFxuICAgICAgICAvLyB3aXRoIEhvb2tDb25mbGljdEVycm9yOyBnZXRDb25mbGljdCgpIGF3YWl0ZXJzIHJlc29sdmUgd2l0aCBhXG4gICAgICAgIC8vIFJ1biBoYW5kbGUgZm9yIHRoZSBjb25mbGljdGluZyBydW4gKHJldml2ZWQgdGhyb3VnaCB0aGUgVk0nc1xuICAgICAgICAvLyBjbGFzcyByZWdpc3RyeSBzbyBpdHMgbWV0aG9kcyBhcmUgZHVyYWJsZSBzdGVwIHByb3hpZXMpIG9yXG4gICAgICAgIC8vIHJlamVjdCB3aXRoIHRoZSBlcnJvciB3aGVuIG5vIGhhbmRsZSBjYW4gYmUgY29uc3RydWN0ZWQsXG4gICAgICAgIC8vIG1pcnJvcmluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBob29rLnRzIGhvb2tfY29uZmxpY3QgaGFuZGxpbmcuXG4gICAgICAgIGNvbnN0IGNvbmZsaWN0VG9rZW4gPSAoZXZlbnREYXRhPy50b2tlbiBhcyBzdHJpbmcpID8/ICd1bmtub3duJztcbiAgICAgICAgY29uc3QgY29uZmxpY3RpbmdSdW5JZCA9IGV2ZW50RGF0YT8uY29uZmxpY3RpbmdSdW5JZCBhc1xuICAgICAgICAgIHwgc3RyaW5nXG4gICAgICAgICAgfCB1bmRlZmluZWQ7XG4gICAgICAgIGNvbnN0IGRpZFNldHRsZSA9IHZtLmR1bXAoXG4gICAgICAgICAgdm0uZXZhbENvZGUoXG4gICAgICAgICAgICBgKGZ1bmN0aW9uKCl7XG4gICAgICAgICAgICAgIHZhciBjaWQgPSAke0pTT04uc3RyaW5naWZ5KGNpZCl9O1xuICAgICAgICAgICAgICB2YXIgdG9rZW4gPSAke0pTT04uc3RyaW5naWZ5KGNvbmZsaWN0VG9rZW4pfTtcbiAgICAgICAgICAgICAgdmFyIGNvbmZsaWN0aW5nUnVuSWQgPSAke0pTT04uc3RyaW5naWZ5KGNvbmZsaWN0aW5nUnVuSWQgPz8gbnVsbCl9O1xuICAgICAgICAgICAgICB2YXIgRXJyQ2xzID0gZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKCdAd29ya2Zsb3cvZXJyb3JzLy9Ib29rQ29uZmxpY3RFcnJvcicpXTtcbiAgICAgICAgICAgICAgdmFyIGVycjtcbiAgICAgICAgICAgICAgaWYgKHR5cGVvZiBFcnJDbHMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBuZXcgRXJyQ2xzKHRva2VuLCBjb25mbGljdGluZ1J1bklkIHx8IHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXJyID0gbmV3IEVycm9yKCdIb29rIHRva2VuIFwiJyArIHRva2VuICsgJ1wiIGlzIGFscmVhZHkgaW4gdXNlIGJ5IGFub3RoZXIgd29ya2Zsb3cnKTtcbiAgICAgICAgICAgICAgICBlcnIubmFtZSA9ICdIb29rQ29uZmxpY3RFcnJvcic7XG4gICAgICAgICAgICAgICAgZXJyLnRva2VuID0gdG9rZW47XG4gICAgICAgICAgICAgICAgaWYgKGNvbmZsaWN0aW5nUnVuSWQpIGVyci5jb25mbGljdGluZ1J1bklkID0gY29uZmxpY3RpbmdSdW5JZDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB2YXIgcnVuID0gbnVsbDtcbiAgICAgICAgICAgICAgaWYgKGNvbmZsaWN0aW5nUnVuSWQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVnID0gZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKCd3b3JrZmxvdy1jbGFzcy1yZWdpc3RyeScpXTtcbiAgICAgICAgICAgICAgICB2YXIgUnVuQ2xzID0gcmVnICYmIHJlZy5nZXQoJ2NsYXNzLy93b3JrZmxvdy8vUnVuJyk7XG4gICAgICAgICAgICAgICAgdmFyIGRlcyA9IFJ1bkNscyAmJiBSdW5DbHNbU3ltYm9sLmZvcignd29ya2Zsb3ctZGVzZXJpYWxpemUnKV07XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBkZXMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgIHJ1biA9IGRlcy5jYWxsKFJ1bkNscywgeyBydW5JZDogY29uZmxpY3RpbmdSdW5JZCB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdmFyIHNldHRsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgdmFyIHN0YXRlID0gZ2xvYmFsVGhpcy5fX2hvb2tzICYmIGdsb2JhbFRoaXMuX19ob29rc1tjaWRdO1xuICAgICAgICAgICAgICBpZiAoc3RhdGUgJiYgIXN0YXRlLmNvbmZsaWN0KSB7XG4gICAgICAgICAgICAgICAgc3RhdGUuY29uZmxpY3QgPSB7IGVycm9yOiBlcnIsIHJ1bjogcnVuIH07XG4gICAgICAgICAgICAgICAgdmFyIGdjID0gc3RhdGUuZ2V0Q29uZmxpY3RSZXNvbHZlcnM7XG4gICAgICAgICAgICAgICAgc3RhdGUuZ2V0Q29uZmxpY3RSZXNvbHZlcnMgPSBbXTtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdjLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICBpZiAocnVuKSB7IGdjW2ldLnJlc29sdmUocnVuKTsgfSBlbHNlIHsgZ2NbaV0ucmVqZWN0KGVycik7IH1cbiAgICAgICAgICAgICAgICAgIHNldHRsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1tjaWRdKSB7XG4gICAgICAgICAgICAgICAgZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1tjaWRdLnJlamVjdChlcnIpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBnbG9iYWxUaGlzLl9fcmVzb2x2ZXJzW2NpZF07XG4gICAgICAgICAgICAgICAgc2V0dGxlZCA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcmV0dXJuIHNldHRsZWQ7XG4gICAgICAgICAgICB9KSgpYFxuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGRpZFNldHRsZSkge1xuICAgICAgICAgIHJlc29sdmVkID0gdHJ1ZTtcbiAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgIGIgPSB2bS5leGVjdXRlUGVuZGluZ0pvYnMoKTtcbiAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdzdGVwX2NyZWF0ZWQnOlxuICAgICAgY2FzZSAnc3RlcF9zdGFydGVkJzpcbiAgICAgIGNhc2UgJ3N0ZXBfcmV0cnlpbmcnOlxuICAgICAgY2FzZSAnd2FpdF9jcmVhdGVkJzoge1xuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ2hvb2tfY3JlYXRlZCc6IHtcbiAgICAgICAgLy8gQ29uZmlybSBjcmVhdGlvbiBmb3IgZ2V0Q29uZmxpY3QoKSBhd2FpdGVyczogcmVzb2x2ZSB0aGVtIHdpdGhcbiAgICAgICAgLy8gbnVsbCAobm8gY29uZmxpY3QpIG9uY2UgdGhlIGV2ZW50IGxvZyBwcm92ZXMgdGhlIGhvb2sgZXhpc3RzLlxuICAgICAgICBjb25zdCBzZXR0bGVkR2V0Q29uZmxpY3QgPSB2bS5kdW1wKFxuICAgICAgICAgIHZtLmV2YWxDb2RlKFxuICAgICAgICAgICAgYChmdW5jdGlvbigpe1xuICAgICAgICAgICAgICB2YXIgc3RhdGUgPSBnbG9iYWxUaGlzLl9faG9va3MgJiYgZ2xvYmFsVGhpcy5fX2hvb2tzWyR7SlNPTi5zdHJpbmdpZnkoY2lkKX1dO1xuICAgICAgICAgICAgICBpZiAoIXN0YXRlKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgIHN0YXRlLmNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICB2YXIgZ2MgPSBzdGF0ZS5nZXRDb25mbGljdFJlc29sdmVycztcbiAgICAgICAgICAgICAgc3RhdGUuZ2V0Q29uZmxpY3RSZXNvbHZlcnMgPSBbXTtcbiAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBnYy5sZW5ndGg7IGkrKykgZ2NbaV0ucmVzb2x2ZShudWxsKTtcbiAgICAgICAgICAgICAgcmV0dXJuIGdjLmxlbmd0aCA+IDA7XG4gICAgICAgICAgICB9KSgpYFxuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHNldHRsZWRHZXRDb25mbGljdCkge1xuICAgICAgICAgIHJlc29sdmVkID0gdHJ1ZTtcbiAgICAgICAgICBsZXQgYjogbnVtYmVyO1xuICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgIGIgPSB2bS5leGVjdXRlUGVuZGluZ0pvYnMoKTtcbiAgICAgICAgICB9IHdoaWxlIChiID4gMCk7XG4gICAgICAgIH1cbiAgICAgICAgbWFya0NyZWF0ZWQodm0sIGNpZEpzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdob29rX2Rpc3Bvc2VkJzoge1xuICAgICAgICAvLyBEaXNhbWJpZ3VhdGUgZnJvbSB0aGUgYGhvb2tgIHBlbmRpbmcgb3Agd2l0aCB0aGUgc2FtZVxuICAgICAgICAvLyBjb3JyZWxhdGlvbklkOiB3ZSB3YW50IHRvIG1hcmsgdGhlIGBob29rX2Rpc3Bvc2VgIGVudHJ5LlxuICAgICAgICBtYXJrQ3JlYXRlZCh2bSwgY2lkSnMsICdob29rX2Rpc3Bvc2UnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiByZXNvbHZlZDtcbn1cblxuZnVuY3Rpb24gbWFya0NyZWF0ZWQodm06IFF1aWNrSlMsIGNpZEpzOiBzdHJpbmcsIG9wVHlwZT86IHN0cmluZyk6IHZvaWQge1xuICAvLyBgY2lkSnNgIGlzIHRoZSBKU09OLnN0cmluZ2lmeS1xdW90ZWQgY29ycmVsYXRpb24gaWQgKHNlZSBwcm9jZXNzRXZlbnRzKS5cbiAgLy8gYGhvb2tgIGFuZCBgaG9va19kaXNwb3NlYCBwZW5kaW5nIG9wcyBzaGFyZSB0aGUgc2FtZSBjb3JyZWxhdGlvbklkLFxuICAvLyBzbyB3aGVuIHByb2Nlc3NpbmcgYGhvb2tfZGlzcG9zZWRgIGV2ZW50cyB3ZSBtdXN0IGRpc2FtYmlndWF0ZSBieVxuICAvLyB0eXBlOiBvdGhlcndpc2UgYC5maW5kKClgIHJldHVybnMgdGhlIG9yaWdpbmFsIGBob29rYCBvcCBhbmQgdGhlXG4gIC8vIGBob29rX2Rpc3Bvc2VgIG9wIGlzIG5ldmVyIG1hcmtlZCwgY2F1c2luZyB0aGUgZW50cnlwb2ludCB0byBrZWVwXG4gIC8vIHJldHJ5aW5nIGEgaG9va19kaXNwb3NlZCBmb3IgYW4gYWxyZWFkeS1kZWxldGVkIGVudGl0eS5cbiAgY29uc3QgcHJlZGljYXRlID0gb3BUeXBlXG4gICAgPyBgZnVuY3Rpb24ocCl7cmV0dXJuIHAuY29ycmVsYXRpb25JZD09PSR7Y2lkSnN9JiZwLnR5cGU9PT0ke0pTT04uc3RyaW5naWZ5KG9wVHlwZSl9O31gXG4gICAgOiBgZnVuY3Rpb24ocCl7cmV0dXJuIHAuY29ycmVsYXRpb25JZD09PSR7Y2lkSnN9O31gO1xuICB2bS5ldmFsQ29kZShcbiAgICBgdmFyIF9fcD1nbG9iYWxUaGlzLl9fcGVuZGluZy5maW5kKCR7cHJlZGljYXRlfSk7YCArXG4gICAgICBgaWYoX19wKV9fcC5oYXNDcmVhdGVkRXZlbnQ9dHJ1ZTtgXG4gICkuZGlzcG9zZSgpO1xufVxuXG4vLyAtLS0tIFN0YXRlIENoZWNraW5nIC0tLS1cblxuLyoqXG4gKiBDb2xsZWN0IGxlZnRvdmVyIHBlbmRpbmcgb3BlcmF0aW9ucyB0aGF0IG5lZWQgZHVyYWJsZSBzaWRlIGVmZmVjdHMgd2hlblxuICogdGhlIHdvcmtmbG93IHJlYWNoZXMgYSB0ZXJtaW5hbCBzdGF0ZS4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUnc1xuICogZHJhaW5QZW5kaW5nUXVldWVJdGVtcyAod29ya2Zsb3cudHMpOiBzdGlsbC1hbGl2ZSBzeXN0ZW0gaG9va3NcbiAqIChBYm9ydENvbnRyb2xsZXIpIHdpdGhvdXQgYW4gYWJvcnQgaW4gZmxpZ2h0IGFyZSBpbXBsaWNpdGx5IGRpc3Bvc2VkIHNvXG4gKiB0aGV5IGRvbid0IGxlYWsgaG9vayByb3dzOyBvcHMgd2l0aG91dCBjcmVhdGVkIGV2ZW50cyAoZmlyZS1hbmQtZm9yZ2V0XG4gKiBhdHRyaWJ1dGVzL2hvb2tzL3N0ZXBzL3dhaXRzKSBhbmQgcGVuZGluZyBhYm9ydCByZWNvcmRpbmdzIGFyZSBzdXJmYWNlZFxuICogZm9yIHRoZSBlbnRyeXBvaW50IHRvIGZsdXNoLlxuICovXG4vKipcbiAqIFBlci1WTSBjYWNoZSBvZiBzZXJpYWxpemVkIHBlbmRpbmctb3AgZmllbGQgYnl0ZXMsIGtleWVkXG4gKiBgY29ycmVsYXRpb25JZDpmaWVsZGAuIEEgc3RlcCdzIHJhdyBpbnB1dCBpcyBpbW11dGFibGUgb25jZSBwdXNoZWQsIHNvXG4gKiBpdHMgYnl0ZXMgYXJlIGNvbXB1dGVkIG9uY2UgZXZlbiB0aG91Z2ggdGhlIG9wIGlzIHJlLWNvbGxlY3RlZCBvbiBldmVyeVxuICogc3VzcGVuc2lvbiBpdCBzdGF5cyBwZW5kaW5nIHRocm91Z2guXG4gKi9cbi8vIHBlci1jb3B5LW9rOiBrZXllZCBvbiB0aGUgVk0gaW5zdGFuY2UsIGFuZCBhIFZNIGlzIGNyZWF0ZWQgYW5kIGRyaXZlbiBieSBvbmVcbi8vIGNvcHkuIEFub3RoZXIgY29weSBob2xkcyBubyByZWZlcmVuY2UgdG8gdGhlIGtleSwgc28gYSBzaGFyZWQgbWFwIGNvdWxkIG5ldmVyXG4vLyBiZSByZWFkIGZyb20gaXQuXG5jb25zdCBwZW5kaW5nQnl0ZUNhY2hlID0gbmV3IFdlYWtNYXA8UXVpY2tKUywgTWFwPHN0cmluZywgVWludDhBcnJheT4+KCk7XG5cbmZ1bmN0aW9uIGVuc3VyZVBlbmRpbmdCeXRlQ2FjaGUodm06IFF1aWNrSlMpOiBNYXA8c3RyaW5nLCBVaW50OEFycmF5PiB7XG4gIGxldCBjYWNoZSA9IHBlbmRpbmdCeXRlQ2FjaGUuZ2V0KHZtKTtcbiAgaWYgKCFjYWNoZSkge1xuICAgIGNhY2hlID0gbmV3IE1hcCgpO1xuICAgIHBlbmRpbmdCeXRlQ2FjaGUuc2V0KHZtLCBjYWNoZSk7XG4gIH1cbiAgcmV0dXJuIGNhY2hlO1xufVxuXG4vKipcbiAqIFRoZSBwZW5kaW5nLW9wIGZpZWxkcyB0aGF0IGhvbGQgUkFXIGd1ZXN0IHZhbHVlcyAodGhlIGJvb3RzdHJhcCBubyBsb25nZXJcbiAqIHNlcmlhbGl6ZXMgdGhlbSBpbiB0aGUgVk0pLiBDb2xsZWN0aW9uIHByb2plY3RzIHRoZW0gb3V0IG9mIHRoZSBkdW1wZWRcbiAqIHBsYWluIG1ldGFkYXRhIGFuZCBzZXJpYWxpemVzIGVhY2ggdGhyb3VnaCBhIGhhbmRsZSB3aXRoIHRoZSBob3N0IHNlcmRlLlxuICovXG5jb25zdCBSQVdfUEVORElOR19GSUVMRFMgPSBbJ2lucHV0JywgJ21ldGFkYXRhJywgJ2Fib3J0UGF5bG9hZCddIGFzIGNvbnN0O1xuXG4vKipcbiAqIER1bXAgYSBmaWx0ZXJlZCB2aWV3IG9mIGBnbG9iYWxUaGlzLl9fcGVuZGluZ2AgdG8gaG9zdCBQZW5kaW5nT3BlcmF0aW9uXG4gKiBvYmplY3RzLCBzZXJpYWxpemluZyB0aGUgcmF3LXZhbHVlIGZpZWxkcyBob3N0LXNpZGUuIGBmaWx0ZXJFeHByYCBpcyBhXG4gKiBndWVzdCBleHByZXNzaW9uIHRoYXQgZXZhbHVhdGVzIHRvIHRoZSBhcnJheSBvZiBvcHMgdG8gY29sbGVjdC5cbiAqL1xuZnVuY3Rpb24gZHVtcFBlbmRpbmdPcHMoXG4gIHZtOiBRdWlja0pTLFxuICBzZXJkZTogUXVpY2tKU1NlcmRlLFxuICBmaWx0ZXJFeHByOiBzdHJpbmcsXG4gIGJ5dGVDYWNoZT86IE1hcDxzdHJpbmcsIFVpbnQ4QXJyYXk+XG4pOiBQZW5kaW5nT3BlcmF0aW9uW10ge1xuICB1c2luZyBwcm9qZWN0ZWQgPSB2bS5ldmFsQ29kZShgKGZ1bmN0aW9uKCl7XG4gICAgdmFyIG9wcyA9ICR7ZmlsdGVyRXhwcn07XG4gICAgZ2xvYmFsVGhpcy5fX3Jhd0ZpZWxkcyA9IFtdO1xuICAgIC8vIFNldHRsZWQgb3BzIOKAlCBjcmVhdGVkLCByZXNvbHZlci1sZXNzLCBubyBhYm9ydCBpbiBmbGlnaHQg4oCUIGFyZVxuICAgIC8vIG5ldmVyIGNvbGxlY3RlZCBhZ2FpbiBieSBlaXRoZXIgdGhlIHN1c3BlbnNpb24gb3IgdGhlIGRyYWluXG4gICAgLy8gZmlsdGVyLCBzbyB0aGVpciBjYWNoZWQgYnl0ZXMgYXJlIGRlYWQgd2VpZ2h0OyBzdXJmYWNlIHRoZWlyIGNpZHNcbiAgICAvLyBzbyB0aGUgaG9zdCBjYW4gZXZpY3QgdGhlbSAoc2VlIHRoZSBieXRlLWNhY2hlIGV2aWN0aW9uIGJlbG93KS5cbiAgICB2YXIgc2V0dGxlZCA9IFtdO1xuICAgIGdsb2JhbFRoaXMuX19wZW5kaW5nLmZvckVhY2goZnVuY3Rpb24ocCl7XG4gICAgICBpZiAocC5oYXNDcmVhdGVkRXZlbnQgJiYgIWdsb2JhbFRoaXMuX19yZXNvbHZlcnNbcC5jb3JyZWxhdGlvbklkXSAmJiAhcC5hYm9ydFJlcXVlc3RlZCkge1xuICAgICAgICBzZXR0bGVkLnB1c2gocC5jb3JyZWxhdGlvbklkKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4geyBzZXR0bGVkOiBzZXR0bGVkLCBvcHM6IG9wcy5tYXAoZnVuY3Rpb24ocCl7XG4gICAgICB2YXIgcSA9IHt9O1xuICAgICAgZm9yICh2YXIgayBpbiBwKSB7XG4gICAgICAgIGlmIChrID09PSAnaW5wdXQnIHx8IGsgPT09ICdtZXRhZGF0YScgfHwgayA9PT0gJ2Fib3J0UGF5bG9hZCcpIGNvbnRpbnVlO1xuICAgICAgICBxW2tdID0gcFtrXTtcbiAgICAgIH1cbiAgICAgIHZhciByYXcgPSB7fTtcbiAgICAgIFsnaW5wdXQnLCAnbWV0YWRhdGEnLCAnYWJvcnRQYXlsb2FkJ10uZm9yRWFjaChmdW5jdGlvbihmKXtcbiAgICAgICAgaWYgKHBbZl0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJhd1tmXSA9IGdsb2JhbFRoaXMuX19yYXdGaWVsZHMubGVuZ3RoO1xuICAgICAgICAgIGdsb2JhbFRoaXMuX19yYXdGaWVsZHMucHVzaChwW2ZdKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBxLl9fcmF3SW5kaWNlcyA9IHJhdztcbiAgICAgIHJldHVybiBxO1xuICAgIH0pIH07XG4gIH0pKClgKTtcbiAgY29uc3QgZHVtcGVkID0gdm0uZHVtcChwcm9qZWN0ZWQpIGFzIHtcbiAgICBzZXR0bGVkOiBzdHJpbmdbXTtcbiAgICBvcHM6IChQZW5kaW5nT3BlcmF0aW9uICYge1xuICAgICAgX19yYXdJbmRpY2VzPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgICB9KVtdO1xuICB9O1xuICBjb25zdCBwbGFpbk9wcyA9IGR1bXBlZC5vcHM7XG4gIC8vIEJ5dGUtY2FjaGUgZXZpY3Rpb246IGVudHJpZXMgZm9yIHNldHRsZWQgb3BzIGNhbiBuZXZlciBiZSByZWFkIGFnYWluXG4gIC8vIChuZWl0aGVyIGNvbGxlY3Rpb24gZmlsdGVyIG1hdGNoZXMgYSBzZXR0bGVkIG9wKSwgc28gZHJvcHBpbmcgdGhlbVxuICAvLyBib3VuZHMgdGhlIGNhY2hlIGJ5IHRoZSBMSVZFIHBlbmRpbmcgc2V0IGluc3RlYWQgb2YgZ3Jvd2luZ1xuICAvLyBtb25vdG9uaWNhbGx5IGZvciB0aGUgVk0ncyBsaWZldGltZSwgd2hpY2ggbWF0dGVycyBmb3IgdGhlIGlubGluZVxuICAvLyBsb29wJ3MgbG9uZy1saXZlZCBzZXNzaW9ucyBhbmQgc25hcHNob3QtcmVzdG9yZWQgVk1zLlxuICBpZiAoYnl0ZUNhY2hlICYmIGR1bXBlZC5zZXR0bGVkLmxlbmd0aCA+IDApIHtcbiAgICBmb3IgKGNvbnN0IGNpZCBvZiBkdW1wZWQuc2V0dGxlZCkge1xuICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiBSQVdfUEVORElOR19GSUVMRFMpIHtcbiAgICAgICAgYnl0ZUNhY2hlLmRlbGV0ZShgJHtjaWR9OiR7ZmllbGR9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHVzaW5nIHJhd0ZpZWxkcyA9IHZtLmV2YWxDb2RlKCdnbG9iYWxUaGlzLl9fcmF3RmllbGRzJyk7XG4gIGZvciAoY29uc3Qgb3Agb2YgcGxhaW5PcHMpIHtcbiAgICBjb25zdCByYXdJbmRpY2VzID0gb3AuX19yYXdJbmRpY2VzID8/IHt9O1xuICAgIGRlbGV0ZSBvcC5fX3Jhd0luZGljZXM7XG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiBSQVdfUEVORElOR19GSUVMRFMpIHtcbiAgICAgIGNvbnN0IGluZGV4ID0gcmF3SW5kaWNlc1tmaWVsZF07XG4gICAgICBpZiAoaW5kZXggPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgICBjb25zdCBjYWNoZUtleSA9IGAke29wLmNvcnJlbGF0aW9uSWR9OiR7ZmllbGR9YDtcbiAgICAgIGxldCBieXRlcyA9IGJ5dGVDYWNoZT8uZ2V0KGNhY2hlS2V5KTtcbiAgICAgIGlmICghYnl0ZXMpIHtcbiAgICAgICAgdXNpbmcgdmFsdWVIYW5kbGUgPSByYXdGaWVsZHMuZ2V0UHJvcChTdHJpbmcoaW5kZXgpKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBieXRlcyA9IHNlcmRlLnNlcmlhbGl6ZSh2YWx1ZUhhbmRsZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIC8vIEEgc3RlcCBpbnB1dCB0aGF0IHJlZnVzZXMgdG8gc2VyaWFsaXplIGlzIGEgZGV0ZXJtaW5pc3RpYyB1c2VyXG4gICAgICAgICAgLy8gZXJyb3I6IGZhaWxpbmcgdGhlIHdob2xlIGNvbGxlY3Rpb24gaGVyZSB3b3VsZCBmYWlsIHRoZSBydW5cbiAgICAgICAgICAvLyBmcm9tIHRoZSBvdXRzaWRlLCB3aGVyZSBubyB3b3JrZmxvdyBjb2RlIGNhbiBvYnNlcnZlIGl0IChhbmRcbiAgICAgICAgICAvLyB3aXRoIGEgYmFyZSBEZXZhbHVlRXJyb3IgaW5zdGVhZCBvZiB0aGUgZnJhbWVkIG1lc3NhZ2UgdGhlXG4gICAgICAgICAgLy8gbm9kZTp2bSBlbmdpbmUgcHJvZHVjZXMpLiBSZWZyYW1lIGl0IGV4YWN0bHkgbGlrZVxuICAgICAgICAgIC8vIGBkZWh5ZHJhdGVTdGVwQXJndW1lbnRzYCBkb2VzIGFuZCBzdXJmYWNlIGl0IG9uIHRoZSBvcDogdGhlXG4gICAgICAgICAgLy8gZW50cnlwb2ludCBmaW5hbGl6ZXMgdGhlIHN0ZXAgYXMgc3RlcF9jcmVhdGVkICsgc3RlcF9mYWlsZWQgc29cbiAgICAgICAgICAvLyB0aGUgZmFpbHVyZSByZWplY3RzIGludG8gdGhlIHdvcmtmbG93LCBjYXRjaGFibGUuIE90aGVyIHJhd1xuICAgICAgICAgIC8vIGZpZWxkcyAoaG9vayBtZXRhZGF0YSwgYWJvcnQgcGF5bG9hZHMpIGtlZXAgdGhlIHRocm93aW5nXG4gICAgICAgICAgLy8gYmVoYXZpb3IsIG1hdGNoaW5nIHRoZSBub2RlOnZtIGVuZ2luZSdzIHNjb3BlLlxuICAgICAgICAgIGlmIChvcC50eXBlID09PSAnc3RlcCcgJiYgZmllbGQgPT09ICdpbnB1dCcpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgbWVzc2FnZSwgaGludCB9ID0gZm9ybWF0U2VyaWFsaXphdGlvbkVycm9yKFxuICAgICAgICAgICAgICAnc3RlcCBhcmd1bWVudHMnLFxuICAgICAgICAgICAgICBlcnJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICAob3AgYXMgUGVuZGluZ1N0ZXApLnNlcmlhbGl6YXRpb25FcnJvciA9IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoXG4gICAgICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgICAgIHsgaGludCwgY2F1c2U6IGVyciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgICBieXRlQ2FjaGU/LnNldChjYWNoZUtleSwgYnl0ZXMpO1xuICAgICAgfVxuICAgICAgKG9wIGFzIHVua25vd24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2ZpZWxkXSA9IGJ5dGVzO1xuICAgIH1cbiAgfVxuICB2bS5ldmFsQ29kZSgnZGVsZXRlIGdsb2JhbFRoaXMuX19yYXdGaWVsZHMnKS5kaXNwb3NlKCk7XG4gIHJldHVybiBwbGFpbk9wcztcbn1cblxuZnVuY3Rpb24gY29sbGVjdERyYWluT3BlcmF0aW9ucyhcbiAgdm06IFF1aWNrSlMsXG4gIHNlcmRlOiBRdWlja0pTU2VyZGVcbik6IFBlbmRpbmdPcGVyYXRpb25bXSB7XG4gIC8vIFNoYXJlIHRoZSBwZXItVk0gYnl0ZSBjYWNoZSB3aXRoIHRoZSBzdXNwZW5zaW9uIHBhdGg6IGFuIG9wIHRoYXQgd2FzXG4gIC8vIHNlcmlhbGl6ZWQgZHVyaW5nIGEgc3VzcGVuc2lvbiBwYXNzIG11c3QgcmV1c2UgdGhvc2UgZXhhY3QgYnl0ZXMgYXRcbiAgLy8gdGVybWluYWwgZHJhaW4sIHNpbmNlIHJlLXNlcmlhbGl6aW5nIGNhbiBpbnZva2UgZ2V0dGVycyBhZ2FpbiBhbmQgcHJvZHVjZVxuICAvLyBhIERJRkZFUkVOVCBieXRlIHNlcXVlbmNlIGZvciB3aGF0IHRoZSBldmVudCBsb2cgdHJlYXRzIGFzIG9uZSB2YWx1ZS5cbiAgcmV0dXJuIGR1bXBQZW5kaW5nT3BzKFxuICAgIHZtLFxuICAgIHNlcmRlLFxuICAgIGAoZnVuY3Rpb24oKXtcbiAgICB2YXIgdG9EaXNwb3NlID0gW107XG4gICAgZ2xvYmFsVGhpcy5fX3BlbmRpbmcuZm9yRWFjaChmdW5jdGlvbihwKXtcbiAgICAgIGlmIChwLnR5cGUgPT09IFwiaG9va1wiICYmIHAuaXNTeXN0ZW0gJiYgIXAuYWJvcnRSZXF1ZXN0ZWQgJiYgIXAuZGlzcG9zZWQpIHtcbiAgICAgICAgcC5kaXNwb3NlZCA9IHRydWU7XG4gICAgICAgIC8vIE9ubHkgZGlzcG9zZSBob29rcyB0aGF0IHdlcmUgZHVyYWJseSBjcmVhdGVkOyBhIGhvb2sgdGhhdCBuZXZlclxuICAgICAgICAvLyByZWFjaGVkIHN0b3JhZ2UgaGFzIG5vdGhpbmcgdG8gY2xlYW4gdXAuXG4gICAgICAgIGlmIChwLmhhc0NyZWF0ZWRFdmVudCkge1xuICAgICAgICAgIHRvRGlzcG9zZS5wdXNoKHtcbiAgICAgICAgICAgIHR5cGU6IFwiaG9va19kaXNwb3NlXCIsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAvLyBDYXJyaWVkLCBub3QgZHJvcHBlZDogdGhlIGVudHJ5cG9pbnQgc2VuZHMgaXQgb24gaG9va19kaXNwb3NlZCxcbiAgICAgICAgICAgIC8vIGFuZCB0aGUgbm9kZTp2bSBlbmdpbmUgZG9lcyB0aGUgc2FtZSBmb3IgdGhpcyBjYXNlIOKAlCBpdHNcbiAgICAgICAgICAgIC8vIGNvbXBsZXRpb24gZHJhaW4gbWFya3MgdGhlIHN5c3RlbSBob29rIGRpc3Bvc2VkIGFuZCByZXVzZXMgdGhlXG4gICAgICAgICAgICAvLyBxdWV1ZSBpdGVtLCB0b2tlbiBhbmQgYWxsLiBTeW50aGVzaXppbmcgYSBmcmVzaCBvYmplY3QgaGVyZSBpc1xuICAgICAgICAgICAgLy8gd2hhdCBtYWtlcyBpdCBlYXN5IHRvIGxvc2UuXG4gICAgICAgICAgICB0b2tlbjogcC50b2tlbixcbiAgICAgICAgICAgIGhhc0NyZWF0ZWRFdmVudDogZmFsc2UsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB0b0Rpc3Bvc2UuZm9yRWFjaChmdW5jdGlvbihkKXsgZ2xvYmFsVGhpcy5fX3BlbmRpbmcucHVzaChkKTsgfSk7XG4gICAgcmV0dXJuIGdsb2JhbFRoaXMuX19wZW5kaW5nLmZpbHRlcihmdW5jdGlvbihwKXtcbiAgICAgIGlmIChwLmFib3J0UmVxdWVzdGVkKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGlmIChwLmhhc0NyZWF0ZWRFdmVudCkgcmV0dXJuIGZhbHNlO1xuICAgICAgLy8gU2tpcCBzeXN0ZW0gaG9va3MgdGhhdCB3ZXJlIGRpc3Bvc2VkIGJlZm9yZSBldmVyIGJlaW5nIGNyZWF0ZWQuXG4gICAgICBpZiAocC50eXBlID09PSBcImhvb2tcIiAmJiBwLmRpc3Bvc2VkKSByZXR1cm4gZmFsc2U7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgfSkoKWAsXG4gICAgZW5zdXJlUGVuZGluZ0J5dGVDYWNoZSh2bSlcbiAgKTtcbn1cblxuZnVuY3Rpb24gY2hlY2tXb3JrZmxvd1N0YXRlKFxuICB2bTogUXVpY2tKUyxcbiAgc2VyZGU6IFF1aWNrSlNTZXJkZSxcbiAgb3B0czogeyBrZWVwQWxpdmVPblN1c3BlbmQ/OiBib29sZWFuIH0gPSB7fVxuKTogUXVpY2tKU1J1bnRpbWVSZXN1bHQge1xuICAvLyBDaGVjayBjb21wbGV0ZWQ6IF9fd29ya2Zsb3dSZXN1bHQgaG9sZHMgdGhlIFJBVyByZXR1cm4gdmFsdWUgKHdpdGggYVxuICAvLyBzZXBhcmF0ZSBkb25lIGZsYWcgc28gYHVuZGVmaW5lZGAgcmVzdWx0cyBhcmUgZGlzdGluZ3Vpc2hhYmxlKTsgdGhlXG4gIC8vIGhvc3Qgc2VyaWFsaXplcyBpdCB0aHJvdWdoIGEgaGFuZGxlLlxuICB7XG4gICAgdXNpbmcgZG9uZSA9IHZtLmV2YWxDb2RlKCdnbG9iYWxUaGlzLl9fd29ya2Zsb3dEb25lID09PSB0cnVlJyk7XG4gICAgaWYgKGRvbmUudG9Cb29sZWFuKCkpIHtcbiAgICAgIHVzaW5nIGggPSB2bS5ldmFsQ29kZSgnZ2xvYmFsVGhpcy5fX3dvcmtmbG93UmVzdWx0Jyk7XG4gICAgICBjb25zdCByZXN1bHRCeXRlcyA9IHNlcmRlLnNlcmlhbGl6ZShoKTtcbiAgICAgIGNvbnN0IGRyYWluT3BlcmF0aW9ucyA9IGNvbGxlY3REcmFpbk9wZXJhdGlvbnModm0sIHNlcmRlKTtcbiAgICAgIHZtLmRpc3Bvc2UoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBsZXRlZDoge1xuICAgICAgICAgIHJlc3VsdDogcmVzdWx0Qnl0ZXMsXG4gICAgICAgICAgLi4uKGRyYWluT3BlcmF0aW9ucy5sZW5ndGggPiAwID8geyBkcmFpbk9wZXJhdGlvbnMgfSA6IHt9KSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgZmFpbGVkXG4gIHtcbiAgICB1c2luZyBoID0gdm0uZXZhbENvZGUoJ2dsb2JhbFRoaXMuX193b3JrZmxvd0Vycm9yJyk7XG4gICAgaWYgKCFoLmlzVW5kZWZpbmVkKSB7XG4gICAgICAvLyBUaGUgZGlzcGxheSBmaWVsZHMgYXJlIHBsYWluIHN0cmluZ3M7IHRoZSB0aHJvd24gdmFsdWUgaXRzZWxmIGlzXG4gICAgICAvLyBSQVcgYW5kIHNlcmlhbGl6ZWQgaG9zdC1zaWRlIHRocm91Z2ggYSBoYW5kbGUuXG4gICAgICBjb25zdCBlcnJvck9iaiA9IGguaXNTdHJpbmdcbiAgICAgICAgPyAoaC50b1N0cmluZygpIGFzIHN0cmluZylcbiAgICAgICAgOiAoKCkgPT4ge1xuICAgICAgICAgICAgdXNpbmcgcGxhaW4gPSB2bS5ldmFsQ29kZShcbiAgICAgICAgICAgICAgJyhmdW5jdGlvbihlKXtyZXR1cm4ge21lc3NhZ2U6IGUubWVzc2FnZSwgc3RhY2s6IGUuc3RhY2ssIG5hbWU6IGUubmFtZX07fSkoZ2xvYmFsVGhpcy5fX3dvcmtmbG93RXJyb3IpJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiB2bS5kdW1wKHBsYWluKSBhcyB7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IHN0cmluZztcbiAgICAgICAgICAgICAgc3RhY2s/OiBzdHJpbmc7XG4gICAgICAgICAgICAgIG5hbWU/OiBzdHJpbmc7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0pKCk7XG4gICAgICBsZXQgdmFsdWVCeXRlczogVWludDhBcnJheSB8IHVuZGVmaW5lZDtcbiAgICAgIGlmICghaC5pc1N0cmluZykge1xuICAgICAgICB1c2luZyByYXdWYWx1ZSA9IGguZ2V0UHJvcCgndmFsdWUnKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB2YWx1ZUJ5dGVzID0gc2VyZGUuc2VyaWFsaXplKHJhd1ZhbHVlKTtcbiAgICAgICAgfSBjYXRjaCAoc2VyaWFsaXplRXJyKSB7XG4gICAgICAgICAgLy8gQSB0aHJvd24gdmFsdWUgdGhlIGNvZGVjIGNhbm5vdCBzZXJpYWxpemUgbXVzdCBub3QgbWFzayB0aGVcbiAgICAgICAgICAvLyB3b3JrZmxvdyBmYWlsdXJlIGl0c2VsZiwgc28gZmFsbCBiYWNrIHRvIHRoZSBkaXNwbGF5IGZpZWxkcy5cbiAgICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBmYWlsZWQgdG8gc2VyaWFsaXplIHRocm93biB3b3JrZmxvdyBlcnJvcicsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgICAgICAgc2VyaWFsaXplRXJyIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgICAgICAgID8gc2VyaWFsaXplRXJyLm1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgIDogU3RyaW5nKHNlcmlhbGl6ZUVyciksXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgZmFpbGVkID1cbiAgICAgICAgdHlwZW9mIGVycm9yT2JqID09PSAnc3RyaW5nJ1xuICAgICAgICAgID8geyBtZXNzYWdlOiBlcnJvck9iaiB9XG4gICAgICAgICAgOiB7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGVycm9yT2JqLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIHN0YWNrOiBlcnJvck9iai5zdGFjayB8fCB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIG5hbWU6IGVycm9yT2JqLm5hbWUgfHwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICB2YWx1ZUJ5dGVzLFxuICAgICAgICAgICAgfTtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoJ1F1aWNrSlMgcnVudGltZTogd29ya2Zsb3cgZmFpbGVkIGluIFZNJywge1xuICAgICAgICBlcnJvck1lc3NhZ2U6IGZhaWxlZC5tZXNzYWdlLFxuICAgICAgICBlcnJvck5hbWU6IGZhaWxlZC5uYW1lLFxuICAgICAgICBlcnJvclN0YWNrOiBmYWlsZWQuc3RhY2ssXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGRyYWluT3BlcmF0aW9ucyA9IGNvbGxlY3REcmFpbk9wZXJhdGlvbnModm0sIHNlcmRlKTtcbiAgICAgIHZtLmRpc3Bvc2UoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZhaWxlZDoge1xuICAgICAgICAgIC4uLmZhaWxlZCxcbiAgICAgICAgICAuLi4oZHJhaW5PcGVyYXRpb25zLmxlbmd0aCA+IDAgPyB7IGRyYWluT3BlcmF0aW9ucyB9IDoge30pLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvLyBDaGVjayBzdXNwZW5kZWQ6IHRoZSB3b3JrZmxvdyBpcyBzdXNwZW5kZWQgaWYgdGhlcmUgYXJlIGFjdGl2ZSByZXNvbHZlcnNcbiAgLy8gT1IgcGVuZGluZyBvcGVyYXRpb25zIHRoYXQgaGF2ZW4ndCBiZWVuIGNyZWF0ZWQgeWV0IChlLmcuIGhvb2tzIGNyZWF0ZWRcbiAgLy8gdXBmcm9udCBidXQgbm90IHlldCBhd2FpdGVkKVxuICB7XG4gICAgdXNpbmcgaCA9IHZtLmV2YWxDb2RlKFxuICAgICAgJ09iamVjdC5rZXlzKGdsb2JhbFRoaXMuX19yZXNvbHZlcnMpLmxlbmd0aCA+IDAgfHwgZ2xvYmFsVGhpcy5fX3BlbmRpbmcuc29tZShmdW5jdGlvbihwKXtyZXR1cm4hcC5oYXNDcmVhdGVkRXZlbnQ7fSknXG4gICAgKTtcbiAgICBpZiAodm0uZHVtcChoKSkge1xuICAgICAgLy8gT3BzIHdpdGggYW4gYWN0aXZlIHJlc29sdmVyIG9yIHdpdGhvdXQgYSBjcmVhdGVkIGV2ZW50IGFyZVxuICAgICAgLy8gcGVuZGluZzsgYWJvcnQtcmVxdWVzdGVkIGhvb2tzIGFyZSBhbHNvIHN1cmZhY2VkIChldmVuIHdoZW5cbiAgICAgIC8vIGFscmVhZHkgY3JlYXRlZCBhbmQgdW5hd2FpdGVkKSBzbyB0aGUgaG9zdCByZWNvcmRzIHRoZSBhYm9ydC5cbiAgICAgIGNvbnN0IHBlbmRpbmdPcHMgPSBkdW1wUGVuZGluZ09wcyhcbiAgICAgICAgdm0sXG4gICAgICAgIHNlcmRlLFxuICAgICAgICBgZ2xvYmFsVGhpcy5fX3BlbmRpbmcuZmlsdGVyKGZ1bmN0aW9uKHApe3JldHVybiEhZ2xvYmFsVGhpcy5fX3Jlc29sdmVyc1twLmNvcnJlbGF0aW9uSWRdIHx8ICFwLmhhc0NyZWF0ZWRFdmVudCB8fCBwLmFib3J0UmVxdWVzdGVkO30pYCxcbiAgICAgICAgZW5zdXJlUGVuZGluZ0J5dGVDYWNoZSh2bSlcbiAgICAgICk7XG4gICAgICBpZiAoIW9wdHMua2VlcEFsaXZlT25TdXNwZW5kKSB2bS5kaXNwb3NlKCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1c3BlbmRlZDoge1xuICAgICAgICAgIHBlbmRpbmdPcGVyYXRpb25zOiBwZW5kaW5nT3BzLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICB2bS5kaXNwb3NlKCk7XG4gIHJldHVybiB7IGZhaWxlZDogeyBtZXNzYWdlOiAnV29ya2Zsb3cgZW5kZWQgaW4gdW5rbm93biBzdGF0ZScgfSB9O1xufVxuXG4vLyAtLS0tIEhlbHBlcnMgLS0tLVxuXG5mdW5jdGlvbiBleHRyYWN0RXJyb3IoXG4gIHZtOiBRdWlja0pTLFxuICBlcnI6IHVua25vd24sXG4gIGZhbGxiYWNrTWVzc2FnZTogc3RyaW5nXG4pOiBRdWlja0pTUnVudGltZVJlc3VsdCB7XG4gIGxldCBtZXNzYWdlID0gZmFsbGJhY2tNZXNzYWdlO1xuICBsZXQgc3RhY2s6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IG5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBpZiAoZXJyIGluc3RhbmNlb2YgSlNFeGNlcHRpb24pIHtcbiAgICBjb25zdCBlcnJvciA9IHZtLmR1bXAoZXJyLmhhbmRsZSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsO1xuICAgIGVyci5oYW5kbGUuZGlzcG9zZSgpO1xuICAgIG1lc3NhZ2UgPSAoZXJyb3I/Lm1lc3NhZ2UgYXMgc3RyaW5nKSA/PyBlcnIubWVzc2FnZSA/PyBmYWxsYmFja01lc3NhZ2U7XG4gICAgc3RhY2sgPSAoZXJyb3I/LnN0YWNrIGFzIHN0cmluZykgPz8gZXJyLnN0YWNrO1xuICAgIG5hbWUgPSAoZXJyb3I/Lm5hbWUgYXMgc3RyaW5nKSA/PyBlcnIubmFtZTtcbiAgfSBlbHNlIGlmIChlcnIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIG1lc3NhZ2UgPSBlcnIubWVzc2FnZSA/PyBmYWxsYmFja01lc3NhZ2U7XG4gICAgc3RhY2sgPSBlcnIuc3RhY2s7XG4gICAgbmFtZSA9IGVyci5uYW1lO1xuICB9XG5cbiAgdm0uZGlzcG9zZSgpO1xuICByZXR1cm4ge1xuICAgIGZhaWxlZDogeyBtZXNzYWdlLCBzdGFjaywgbmFtZSB9LFxuICB9O1xufVxuXG4vKipcbiAqIE11dGFibGUgaW50ZXJydXB0IGJ1ZGdldCBmb3IgYSBWTS4gUXVpY2tKUyBwb2xscyB0aGUgaW50ZXJydXB0IGhhbmRsZXJcbiAqIGR1cmluZyBKUyBleGVjdXRpb247IHdoZW4gaXQgcmV0dXJucyB0cnVlLCBleGVjdXRpb24gYWJvcnRzLiBUaGUgYnVkZ2V0XG4gKiBib3VuZHMgYSBzaW5nbGUgaG9zdC0+Vk0gZXhlY3V0aW9uIGJ1cnN0IChidW5kbGUgZXZhbCArIGV2ZW50XG4gKiBwcm9jZXNzaW5nKSwgbm90IHRvdGFsIFZNIGxpZmV0aW1lOiB0aGUgaW5saW5lLXN0ZXAgbG9vcCBrZWVwcyBhIFZNXG4gKiBhbGl2ZSBhY3Jvc3Mgc3RlcCBleGVjdXRpb25zIHRoYXQgY2FuIGxlZ2l0aW1hdGVseSB0YWtlIG1pbnV0ZXMsIHNvIHRoZVxuICogaG9zdCByZXNldHMgdGhlIGJ1ZGdldCBiZWZvcmUgZWFjaCByZS1lbnRyeSAoc2VlIHJlc2V0QnVkZ2V0IGNhbGxzKS5cbiAqXG4gKiBUaGUgcGVyLWJ1cnN0IGNlaWxpbmcgaXMgdGhlIHNhbWUgY29uZmlndXJhYmxlIGJ1ZGdldCBhcyB0aGUgbm9kZVxuICogZW5naW5lJ3MgUmVwbGF5QnVkZ2V0IChSRVBMQVlfVElNRU9VVF9NUywgZGVmYXVsdCAyNDBzKTogYSB3b3JrZmxvd1xuICogd2hvc2UgcmVwbGF5IHRoZSBub2RlIGVuZ2luZSBoYW5kbGVzIGZpbmUgbXVzdCBub3QgYmUgaW50ZXJydXB0ZWQgaGVyZVxuICogYnkgYSBsb3dlciBoYXJkY29kZWQgY2VpbGluZy4gVGhlIGludGVycnVwdCBlcnJvciBlc2NhcGVzXG4gKiBydW5RdWlja0pTV29ya2Zsb3cgYW5kIHJlYWNoZXMgdGhlIHJlcGxheSBsb29wJ3MgY2F0Y2ggaW4gcnVudGltZS50cyxcbiAqIHdoaWNoIHJlY29yZHMgcnVuX2ZhaWxlZC5cbiAqL1xuaW50ZXJmYWNlIEludGVycnVwdEJ1ZGdldCB7XG4gIHN0YXJ0OiBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUludGVycnVwdEhhbmRsZXIoYnVkZ2V0OiBJbnRlcnJ1cHRCdWRnZXQpOiAoKSA9PiBib29sZWFuIHtcbiAgY29uc3QgdGltZW91dCA9IGdldFJlcGxheVRpbWVvdXRNcygpO1xuICByZXR1cm4gKCkgPT4gRGF0ZS5ub3coKSAtIGJ1ZGdldC5zdGFydCA+IHRpbWVvdXQ7XG59XG4iXX0=