@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
@@ -1,3 +1,5 @@
1
+ import { envNumber } from '@workflow/world/env-config';
2
+ import { classifyEntityEvent, isSealedNoopEvent, } from '@workflow/world/event-metadata';
1
3
  import { eventsLogger } from './logger.js';
2
4
  /**
3
5
  * Delay before firing the deferred unconsumed-event check after the promise
@@ -6,6 +8,109 @@ import { eventsLogger } from './logger.js';
6
8
  * in host). Any subscribe() arriving during this window cancels the check.
7
9
  */
8
10
  export const DEFERRED_CHECK_DELAY_MS = 100;
11
+ /**
12
+ * Floor for the deferred-check delay, so a too-low override can't manufacture
13
+ * spurious divergence (each false positive burns a divergence-recovery retry
14
+ * and can escalate to a terminal `CorruptedEventLogError`).
15
+ *
16
+ * Exported so tests needing the shortest legal delay can ask for it instead of
17
+ * hardcoding a number this floor would silently clamp up.
18
+ */
19
+ export const MIN_DEFERRED_CHECK_DELAY_MS = 10;
20
+ /**
21
+ * Effective deferred-check delay. Override: `WORKFLOW_DEFERRED_CHECK_DELAY_MS`.
22
+ *
23
+ * Unlike the other timing knobs this is not a polling interval but a
24
+ * determinism safety margin: firing the unconsumed-event check before the
25
+ * cross-VM subscribe() chain has landed rejects a healthy run with
26
+ * `ReplayDivergenceError`.
27
+ */
28
+ const getDeferredCheckDelayMs = () => envNumber('WORKFLOW_DEFERRED_CHECK_DELAY_MS', DEFERRED_CHECK_DELAY_MS, {
29
+ integer: true,
30
+ min: MIN_DEFERRED_CHECK_DELAY_MS,
31
+ });
32
+ /**
33
+ * Event types the ordered walk may step over and deliver later.
34
+ *
35
+ * Membership is not about who wrote the event. It is about whether the event
36
+ * can reach the head of the walk with nothing registered to consume it, which
37
+ * is the only situation parking exists for.
38
+ *
39
+ * Most types cannot. They are replay-origin: a replay emits them, in the order
40
+ * its code reaches them, so their position in the log is the record of what
41
+ * that replay decided. Reaching one of those out of order means this replay
42
+ * decided differently than the log holds, which is divergence and nothing else.
43
+ *
44
+ * Step lifecycle events are not replay-origin, and are still absent, because
45
+ * they always have a claimant. `step()` subscribes its consumer before the
46
+ * step's first event can exist; `step_created` is ordered, so the walk cannot
47
+ * pass it unless a consumer takes it; and that consumer stays subscribed until
48
+ * `step_completed` or `step_failed`, after which the World refuses any further
49
+ * write for that step. There is no window in which a replay knows about a step
50
+ * and has nothing registered to consume its events, so parking them would only
51
+ * defer reports of what is divergence either way. The same holds for
52
+ * `wait_created` and its consumer. `wait_completed` is listed anyway: a sleep
53
+ * can also be completed out of band, by the API that force-completes pending
54
+ * waits, and tolerating a stray one is the cheaper direction to be wrong in.
55
+ *
56
+ * An allowlist rather than the complement of the ordered set, so a type this
57
+ * file has not been taught about keeps the strict old behavior.
58
+ *
59
+ * `hook_disposed` is deliberately absent despite being about a hook: it is
60
+ * written when the workflow's own `using` scope exits, so it is replay-origin.
61
+ *
62
+ * `attr_set` is listed by type even though a given instance of it may be
63
+ * replay-origin, since it is replay-origin when its writer is the workflow.
64
+ * Splitting that out per event was considered and rejected. A replay that
65
+ * reaches one of its own writes out of position has diverged, but a replay that
66
+ * reaches an event it did NOT write, sitting where its own write would go, has
67
+ * not: the writer field says who wrote the event, and not whether this replay
68
+ * is the same one. Guessing wrong in that direction fails healthy runs, which
69
+ * is the failure this file exists to stop, so the whole type is tolerated. The
70
+ * cost is that a divergence involving `attr_set` surfaces at the end of the
71
+ * replay, through `strandedEvent`, rather than at the offending event.
72
+ *
73
+ * Parking here is for an `attr_set` the walk reaches *before* the body has made
74
+ * the call that claims it. A second event under an id already claimed is a
75
+ * different thing: `attr_set` has an entity event class, so the duplicate skip
76
+ * takes it before this set is consulted, and a copy that parked ahead of any
77
+ * consumption is released by {@link dropParkedDuplicates} once one lands.
78
+ */
79
+ const PARKABLE_EVENT_TYPES = new Set([
80
+ 'hook_received',
81
+ 'hook_conflict',
82
+ 'wait_completed',
83
+ 'attr_set',
84
+ 'run_cancelled',
85
+ ]);
86
+ /**
87
+ * Parkable types that can only ever resolve their correlation id once.
88
+ *
89
+ * A second one for the same id is not a delivery this replay has not reached
90
+ * yet: it is a resolution for something already resolved, which no consumer
91
+ * this replay or any later one registers can ever claim. `hook_received` is
92
+ * absent because a hook legitimately fires many times under one id.
93
+ *
94
+ * Must stay a subset of {@link PARKABLE_EVENT_TYPES}: {@link park} is the only
95
+ * reader of what this records, and it rejects a non-parkable type before it
96
+ * looks, so an entry outside that set is dead weight on a hot path.
97
+ */
98
+ const ONE_SHOT_EVENT_TYPES = new Set([
99
+ 'wait_completed',
100
+ ]);
101
+ /** Identifies the thing a one-shot resolution event resolves. */
102
+ function resolutionKey(eventType, correlationId) {
103
+ return `${eventType}:${correlationId}`;
104
+ }
105
+ /**
106
+ * Types that end a run. Once one is in the log, no consumer will ever be
107
+ * registered again, so a parked event still parked here will never be claimed.
108
+ */
109
+ const TERMINAL_EVENT_TYPES = new Set([
110
+ 'run_completed',
111
+ 'run_failed',
112
+ 'run_cancelled',
113
+ ]);
9
114
  export var EventConsumerResult;
10
115
  (function (EventConsumerResult) {
11
116
  /**
@@ -23,18 +128,114 @@ export var EventConsumerResult;
23
128
  })(EventConsumerResult || (EventConsumerResult = {}));
24
129
  export class EventsConsumer {
25
130
  eventIndex;
26
- events = [];
131
+ events;
27
132
  callbacks = [];
133
+ /**
134
+ * Events the ordered walk stepped over because nobody claimed them and their
135
+ * type carries no ordering claim. Each keeps the index it held in the log:
136
+ * consumers read {@link eventIndex} at consumption time to order their
137
+ * delivery against the rest of the log, and a late delivery must still make
138
+ * the claim its position gave it.
139
+ *
140
+ * Held in log order, drained in log order, and drained before every offer so
141
+ * a consumer registered after the walk passed the event still receives it.
142
+ */
143
+ parked = [];
144
+ /**
145
+ * Correlation ids of the {@link ONE_SHOT_EVENT_TYPES} events consumed so
146
+ * far, so a second resolution for one of them is recognized as unclaimable
147
+ * rather than parked for a consumer that cannot exist.
148
+ */
149
+ resolved = new Set();
150
+ /**
151
+ * `<class>:<correlationId>` for every event class the walk has already
152
+ * consumed, mapped to the event type that recorded it. The type is kept so a
153
+ * repeat that decided the same class *differently* (a `step_failed` behind a
154
+ * `step_completed`) can be reported as more than a re-commit. See
155
+ * {@link EventsConsumer.firstEventTypeOfClass}.
156
+ */
157
+ seenEventClasses = new Map();
158
+ onConsumedEvent;
28
159
  onUnconsumedEvent;
160
+ onDuplicateEvent;
29
161
  getPromiseQueue;
162
+ isDeliveryIdle;
30
163
  pendingUnconsumedCheck = null;
31
164
  pendingUnconsumedTimeout = null;
32
165
  unconsumedCheckVersion = 0;
166
+ /**
167
+ * The event a callback most recently claimed, for {@link describe}. Tracked
168
+ * separately from {@link eventIndex} because the walk also steps over events
169
+ * (parked, sealed no-ops, duplicates) without anyone consuming them, so
170
+ * `events[eventIndex - 1]` does not say what replay last acted on.
171
+ */
172
+ lastConsumed;
33
173
  constructor(events, options) {
34
- this.events = events;
174
+ // Own copy: the runtime mutates its event array in place, and a retained
175
+ // session must only observe new events through append() so resume()'s
176
+ // strict-extension check stays meaningful.
177
+ this.events = [...events];
35
178
  this.eventIndex = 0;
179
+ this.onConsumedEvent = options.onConsumedEvent;
36
180
  this.onUnconsumedEvent = options.onUnconsumedEvent;
181
+ this.onDuplicateEvent = options.onDuplicateEvent;
37
182
  this.getPromiseQueue = options.getPromiseQueue;
183
+ this.isDeliveryIdle = options.isDeliveryIdle;
184
+ }
185
+ /**
186
+ * The oldest event the walk stepped over that no consumer has claimed yet,
187
+ * if any. Parking is a bet that a consumer will be registered later, so at
188
+ * any point where no consumer ever will be again (the replay finishing is
189
+ * the definitive one), this answers which event the bet lost on.
190
+ */
191
+ get strandedEvent() {
192
+ return this.parked[0]?.event;
193
+ }
194
+ /**
195
+ * What the walk is still holding, or `undefined` when it holds nothing.
196
+ *
197
+ * Read at every point a replay stops, including the suspensions that are not
198
+ * settling points, so the held state reaches telemetry. A replay cannot tell
199
+ * a delivery awaiting a later consumer from one no consumer will ever
200
+ * register, so it reports rather than decides: the same `eventId` reported on
201
+ * suspension after suspension of one run is the shape that says the bet
202
+ * parking made is not going to pay off, and that shape is only visible across
203
+ * replays.
204
+ */
205
+ get parkedSummary() {
206
+ const oldest = this.parked[0]?.event;
207
+ if (!oldest) {
208
+ return undefined;
209
+ }
210
+ return {
211
+ count: this.parked.length,
212
+ eventId: oldest.eventId,
213
+ eventType: oldest.eventType,
214
+ };
215
+ }
216
+ /**
217
+ * Where the walk stands, for a divergence message. Everything here is
218
+ * already known to the consumer; the point of the method is that the
219
+ * orchestrator can print it without reaching into private state.
220
+ *
221
+ * `index` is the ordered walk's position (the offset of the event it is
222
+ * stuck on, when it is stuck), `length` the log as this consumer holds it,
223
+ * `parked` how many events the walk stepped over and still holds, and
224
+ * `lastConsumedEventId` the id of the event a callback most recently
225
+ * claimed, `undefined` before the first claim.
226
+ */
227
+ describe() {
228
+ return {
229
+ index: this.eventIndex,
230
+ length: this.events.length,
231
+ parked: this.parked.length,
232
+ lastConsumedEventId: this.lastConsumed?.eventId,
233
+ };
234
+ }
235
+ append(events) {
236
+ for (const event of events)
237
+ this.events.push(event);
238
+ process.nextTick(this.consume);
38
239
  }
39
240
  /**
40
241
  * Registers a callback function to be called after an event has been consumed
@@ -60,8 +261,83 @@ export class EventsConsumer {
60
261
  }
61
262
  process.nextTick(this.consume);
62
263
  }
264
+ notifyConsumedEvent(event) {
265
+ if (!this.onConsumedEvent) {
266
+ return;
267
+ }
268
+ try {
269
+ this.onConsumedEvent(event);
270
+ }
271
+ catch (error) {
272
+ eventsLogger.error('onConsumedEvent callback threw an error', {
273
+ error,
274
+ });
275
+ }
276
+ }
63
277
  consume = () => {
64
- const currentEvent = this.events[this.eventIndex] ?? null;
278
+ // Drain consecutively consumable events synchronously within a single
279
+ // pass instead of paying one `process.nextTick` per consumed event.
280
+ //
281
+ // Why this is safe: a callback only consumes an event using a consumer
282
+ // that is ALREADY registered (e.g. a long-lived step consumer walking
283
+ // `step_created` → `step_started` → `step_completed`, or the structural
284
+ // lifecycle consumer). New consumers are only ever registered by workflow
285
+ // VM body code that runs asynchronously off `ctx.promiseQueue` after a
286
+ // delivery `resolve()`; none of the callbacks here call `subscribe()`
287
+ // synchronously. So within one pass `this.callbacks` is mutated only by
288
+ // this loop (the `Finished` splice), and the next event's consumer is
289
+ // either already present (advance now) or not yet registered, in which
290
+ // case no callback consumes the event and we fall through to the
291
+ // cross-VM-safe deferred unconsumed-event check below, exactly as before.
292
+ while (true) {
293
+ // Before every offer, not just on subscribe: a callback registered by
294
+ // the work this same pass kicked off may be the owner of something
295
+ // parked, and the parked event's delivery is ordered ahead of the head
296
+ // event's by the index it holds.
297
+ this.drainParked();
298
+ const currentEvent = this.events[this.eventIndex] ?? null;
299
+ if (currentEvent !== null && isSealedNoopEvent(currentEvent)) {
300
+ this.skipSealedNoop(currentEvent);
301
+ continue;
302
+ }
303
+ const consumed = this.offer(currentEvent);
304
+ if (consumed) {
305
+ this.eventIndex++;
306
+ }
307
+ if (currentEvent === null) {
308
+ // End of log. Consumers return NotConsumed for the `null` sentinel
309
+ // (the one that recognizes it as its own boundary schedules the
310
+ // suspension as a side effect and still declines it), so the drain
311
+ // stops here rather than spinning past the end. `consumed` is only
312
+ // true for a callback that claims the sentinel outright, which no
313
+ // production consumer does.
314
+ if (!consumed) {
315
+ this.handleEndOfLog();
316
+ }
317
+ return;
318
+ }
319
+ if (!consumed) {
320
+ // Nobody wanted it. If it repeats a class this walk already consumed
321
+ // for the same entity it is a straggler from a concurrent replay:
322
+ // step over it in this pass rather than paying the deferred window for
323
+ // a consumer that cannot come (see `firstEventTypeOfClass`).
324
+ const firstType = this.firstEventTypeOfClass(currentEvent);
325
+ if (firstType !== undefined) {
326
+ this.skipDuplicateEvent(currentEvent, firstType);
327
+ continue;
328
+ }
329
+ this.scheduleUnconsumedCheck(currentEvent, true);
330
+ return;
331
+ }
332
+ // A real event was consumed, so advance to the next in the same pass.
333
+ }
334
+ };
335
+ /**
336
+ * Offer `currentEvent` to each registered callback in turn. Returns true
337
+ * when a callback consumed it. Does not move {@link eventIndex}: the ordered
338
+ * walk and the parked drain advance differently, so each does its own.
339
+ */
340
+ offer(currentEvent) {
65
341
  for (let i = 0; i < this.callbacks.length; i++) {
66
342
  const callback = this.callbacks[i];
67
343
  let handled = EventConsumerResult.NotConsumed;
@@ -71,53 +347,408 @@ export class EventsConsumer {
71
347
  catch (error) {
72
348
  eventsLogger.error('EventConsumer callback threw an error', { error });
73
349
  }
74
- if (handled === EventConsumerResult.Consumed ||
75
- handled === EventConsumerResult.Finished) {
76
- // consumer handled this event, so increase the event index
77
- this.eventIndex++;
78
- // remove the callback if it has finished
79
- if (handled === EventConsumerResult.Finished) {
80
- this.callbacks.splice(i, 1);
350
+ if (handled !== EventConsumerResult.Consumed &&
351
+ handled !== EventConsumerResult.Finished) {
352
+ continue;
353
+ }
354
+ if (currentEvent !== null) {
355
+ if (currentEvent.correlationId &&
356
+ ONE_SHOT_EVENT_TYPES.has(currentEvent.eventType)) {
357
+ this.resolved.add(resolutionKey(currentEvent.eventType, currentEvent.correlationId));
81
358
  }
82
- // continue to the next event
83
- process.nextTick(this.consume);
84
- return;
359
+ this.recordEventClass(currentEvent);
360
+ this.lastConsumed = currentEvent;
361
+ this.notifyConsumedEvent(currentEvent);
362
+ }
363
+ // remove the callback if it has finished
364
+ if (handled === EventConsumerResult.Finished) {
365
+ this.callbacks.splice(i, 1);
85
366
  }
367
+ return true;
86
368
  }
87
- // If we reach here, all callbacks returned NotConsumed.
88
- // If the current event is non-null (a real event, not end-of-events),
89
- // schedule a deferred check. We chain onto the promiseQueue so that any
369
+ return false;
370
+ }
371
+ /**
372
+ * Offer everything parked, oldest first, until a pass claims nothing.
373
+ *
374
+ * Each offer runs with {@link eventIndex} moved back to the position the
375
+ * parked event held in the log, because that is the position its consumer
376
+ * will register a delivery barrier under. Restoring the walk pointer
377
+ * afterwards is what keeps the two pointers from interfering.
378
+ */
379
+ drainParked() {
380
+ let progressed = this.parked.length > 0;
381
+ while (progressed) {
382
+ progressed = false;
383
+ this.dropParkedDuplicates();
384
+ for (let i = 0; i < this.parked.length; i++) {
385
+ const entry = this.parked[i];
386
+ const walkIndex = this.eventIndex;
387
+ this.eventIndex = entry.index;
388
+ let consumed;
389
+ try {
390
+ consumed = this.offer(entry.event);
391
+ }
392
+ finally {
393
+ this.eventIndex = walkIndex;
394
+ }
395
+ if (consumed) {
396
+ this.parked.splice(i, 1);
397
+ // A `Finished` callback was spliced out of the list this pass, so
398
+ // restart rather than keep walking a mutated array.
399
+ progressed = this.parked.length > 0;
400
+ break;
401
+ }
402
+ }
403
+ }
404
+ }
405
+ /**
406
+ * Release anything parked whose class a consumption has since recorded for
407
+ * the same entity, on the same terms as {@link skipDuplicateEvent}.
408
+ *
409
+ * The ordered walk decides a straggler at the event, but only for one of the
410
+ * two orders the copies can arrive in. When neither copy has a consumer yet,
411
+ * both park — the walk steps over the first and re-enters immediately, so
412
+ * the second is offered in the same tick, with no class recorded because
413
+ * nothing has been *consumed*. The drain then claims the first and the
414
+ * second is left held by a consumer list that will never grow the callback
415
+ * it needs, which the workflow function returning reports through
416
+ * {@link strandedEvent} as a replay divergence.
417
+ *
418
+ * Run before each offer pass rather than once, because the consumption that
419
+ * records the class happens inside the drain itself.
420
+ *
421
+ * Not specific to `attr_set`: `wait_completed` reaches the same state, and
422
+ * {@link ONE_SHOT_EVENT_TYPES} only covers it in the order where the
423
+ * consumption came first.
424
+ */
425
+ dropParkedDuplicates() {
426
+ for (let i = this.parked.length - 1; i >= 0; i--) {
427
+ const event = this.parked[i].event;
428
+ const firstType = this.firstEventTypeOfClass(event);
429
+ if (firstType === undefined) {
430
+ continue;
431
+ }
432
+ this.parked.splice(i, 1);
433
+ // The walk index moved past this event when it was parked, so unlike
434
+ // `skipDuplicateEvent` there is nothing to advance here.
435
+ eventsLogger.debug('Releasing a parked event that repeats a class already in the log', {
436
+ eventId: event.eventId,
437
+ eventType: event.eventType,
438
+ firstEventType: firstType,
439
+ correlationId: event.correlationId,
440
+ });
441
+ try {
442
+ this.onDuplicateEvent?.(event, firstType);
443
+ }
444
+ catch (error) {
445
+ eventsLogger.error('onDuplicateEvent callback threw an error', {
446
+ error,
447
+ });
448
+ }
449
+ }
450
+ }
451
+ /**
452
+ * Step the ordered walk over an event nobody claimed, holding on to it for a
453
+ * later consumer. Returns false when the event's type makes its position a
454
+ * decision record, which is the one case where nobody claiming it means the
455
+ * replay diverged.
456
+ */
457
+ park(event) {
458
+ if (!PARKABLE_EVENT_TYPES.has(event.eventType)) {
459
+ return false;
460
+ }
461
+ if (event.correlationId &&
462
+ this.resolved.has(resolutionKey(event.eventType, event.correlationId))) {
463
+ return false;
464
+ }
465
+ this.parked.push({ event, index: this.eventIndex });
466
+ this.eventIndex++;
467
+ eventsLogger.debug('Parked an unclaimed event for later delivery', {
468
+ eventId: event.eventId,
469
+ eventType: event.eventType,
470
+ correlationId: event.correlationId,
471
+ parked: this.parked.length,
472
+ });
473
+ return true;
474
+ }
475
+ /**
476
+ * The key `event`'s class is tracked under, or `undefined` for the events
477
+ * that belong to no class and are therefore never skipped: the types with no
478
+ * entry at all (`hook_received`, `hook_conflict`, `run_created`), and a
479
+ * classed type carrying no entity to track it under.
480
+ *
481
+ * {@link classifyEntityEvent} owns that rule, because the observability UI
482
+ * decides the same question about the same log and the two must not drift.
483
+ */
484
+ eventClassKey(event) {
485
+ const classification = classifyEntityEvent(event);
486
+ return classification === undefined
487
+ ? undefined
488
+ : `${classification.eventClass}:${classification.entity}`;
489
+ }
490
+ /**
491
+ * Remembers that `event`'s class is now decided for its entity, if the type
492
+ * belongs to a class. First writer wins: the recorded type is the one the
493
+ * workflow observed, and a later repeat is measured against it.
494
+ */
495
+ recordEventClass(event) {
496
+ const key = this.eventClassKey(event);
497
+ if (key !== undefined && !this.seenEventClasses.has(key)) {
498
+ this.seenEventClasses.set(key, event.eventType);
499
+ }
500
+ }
501
+ /**
502
+ * The type that already decided `event`'s class for the same entity, or
503
+ * `undefined` when nothing has: a second `step_created` for one step, a
504
+ * second terminal outcome, a second `step_started` after the step's result is
505
+ * already in the log.
506
+ *
507
+ * Such an event is committed but inert. Concurrent replays write into one
508
+ * log without a currency guard, so a replay working from a prefix that
509
+ * predates another replay's write can commit its own copy of work the log
510
+ * already records. That copy cannot change what the workflow observed: the
511
+ * outcome was decided by the first event of the class and every later replay
512
+ * reads that same event at the same log position, so ignoring the straggler
513
+ * is deterministic across replays.
514
+ *
515
+ * Classes are tracked separately, so passing one does not suppress another.
516
+ * A step whose result is in the log still reaches its `step_created` and
517
+ * `step_started` consumers if it has yet to see those classes.
518
+ *
519
+ * Consulted only after every registered callback has declined the event, so
520
+ * it can never take an event a consumer wanted. A retry's `step_started` is
521
+ * claimed by the step's live consumer and counts as an attempt exactly as
522
+ * before, and a second `step_created` reaching a step that has not finished
523
+ * is likewise consumed rather than skipped; only the copies nobody claims are
524
+ * skipped.
525
+ *
526
+ * Unlike the divergence report, this does *not* wait out the deferred window
527
+ * first, and it does not need to. The window buys time for a consumer that
528
+ * has yet to register, and no such consumer can want this event: the class
529
+ * was recorded by a consumption in this same replay, which means the entity's
530
+ * consumer was registered and took an event of this class, and correlation
531
+ * ids are minted from a monotonic ULID per body position, so nothing later in
532
+ * the body registers a second consumer under this id. Waiting would cost
533
+ * `getDeferredCheckDelayMs()` per straggler per replay for information that
534
+ * cannot arrive: 0.75% of production runs carry at least one straggler, and
535
+ * the p99 among those carries 155.
536
+ *
537
+ * The invariant to preserve if hook identity ever becomes caller-supplied
538
+ * (an idempotency key rather than a minted id): two `createHook` calls in one
539
+ * body could then share a correlation id, and the second consumer's
540
+ * `hook_created` would be a repeat of a class this replay already recorded.
541
+ * That would make skipping wrong for `hook_created`, and is the reason the
542
+ * class map lives next to the event types rather than being inferred.
543
+ */
544
+ firstEventTypeOfClass(event) {
545
+ const key = this.eventClassKey(event);
546
+ return key === undefined ? undefined : this.seenEventClasses.get(key);
547
+ }
548
+ /**
549
+ * Steps the walk over a sealed-log `noop` (specVersion >= 7): the World's
550
+ * backend wrote it to occupy a slot whose writer allocated the position and
551
+ * died, so the log's density arithmetic holds. It is invisible to the
552
+ * workflow: no consumer is offered it, no event class is recorded, and the
553
+ * deterministic clock does not advance, exactly as with
554
+ * {@link skipDuplicateEvent}, so a log that happens to contain one produces the same
555
+ * timestamps as a log that does not. (Its `createdAt` is the seal time,
556
+ * which can even postdate later slots' events; letting it touch the clock
557
+ * would leak the sealer's wall clock into replay.)
558
+ */
559
+ skipSealedNoop(event) {
560
+ this.eventIndex++;
561
+ eventsLogger.debug('Skipping sealed-log noop event', {
562
+ eventId: event.eventId,
563
+ });
564
+ }
565
+ /** Steps the walk over a repeat of an already-consumed class. */
566
+ skipDuplicateEvent(event, firstType) {
567
+ this.eventIndex++;
568
+ // Deliberately not routed through `notifyConsumedEvent`: the deterministic
569
+ // clock advances only on events the workflow actually observed. A skipped
570
+ // event is invisible to the workflow body, and a log that happens to
571
+ // contain one must produce the same timestamps as a log that does not.
572
+ eventsLogger.debug('Skipping event that repeats a class already in the log', {
573
+ eventId: event.eventId,
574
+ eventType: event.eventType,
575
+ firstEventType: firstType,
576
+ correlationId: event.correlationId,
577
+ });
578
+ try {
579
+ this.onDuplicateEvent?.(event, firstType);
580
+ }
581
+ catch (error) {
582
+ eventsLogger.error('onDuplicateEvent callback threw an error', {
583
+ error,
584
+ });
585
+ }
586
+ }
587
+ handleEndOfLog() {
588
+ // Everything still parked is waiting for a consumer some later replay will
589
+ // register, which is the whole point of parking, except once the log
590
+ // already holds the run's terminal event, because then there is no later
591
+ // replay and no consumer will ever come.
592
+ if (this.parked.length === 0) {
593
+ return;
594
+ }
595
+ const last = this.events.at(-1);
596
+ if (!last || !TERMINAL_EVENT_TYPES.has(last.eventType)) {
597
+ // A later replay is still expected, so nothing here is decidable and
598
+ // escalating would fail the healthy runs parking exists to keep alive.
599
+ // Reaching the end of the log holding something is not by itself a fault,
600
+ // so this stays at `debug`; {@link parkedSummary} is what carries the
601
+ // state to the span, where a run that keeps stopping on the same held
602
+ // event is visible and a single replay's view is not.
603
+ eventsLogger.debug('Reached the end of the log still holding events', {
604
+ eventId: this.parked[0].event.eventId,
605
+ eventType: this.parked[0].event.eventType,
606
+ correlationId: this.parked[0].event.correlationId,
607
+ parked: this.parked.length,
608
+ });
609
+ return;
610
+ }
611
+ this.scheduleUnconsumedCheck(this.parked[0].event, false);
612
+ }
613
+ scheduleUnconsumedCheck(currentEvent, mayPark) {
614
+ // All callbacks returned NotConsumed for the current event.
615
+ // Schedule a deferred check. We chain onto the promiseQueue so that any
90
616
  // pending async work (e.g., deserialization/decryption that triggers
91
617
  // resolve() → user code → subscribe()) completes first. If the event
92
- // is still unconsumed after the queue drains, it's truly orphaned.
93
- if (currentEvent !== null) {
94
- const checkVersion = ++this.unconsumedCheckVersion;
95
- this.pendingUnconsumedCheck = this.getPromiseQueue()
96
- .then(
97
- // Yield once after the first queue drain so promise chains resumed by
98
- // that drain can run across the VM boundary and append any follow-up
99
- // async work (for example: step_completed resolves -> for-await loop
100
- // resumes -> the next hook payload starts hydrating).
101
- () => new Promise((resolve) => setTimeout(resolve, 0)))
102
- .then(() => this.getPromiseQueue())
103
- .then(() => {
104
- // Use a delayed setTimeout after the queue drains. The delay must be
105
- // long enough for promise chains to propagate across the VM boundary
106
- // (from resolve() in the host context through to the workflow code
107
- // calling subscribe() in the VM context). Node.js does not guarantee
108
- // that setTimeout(0) fires after all cross-context microtasks settle,
109
- // so we use a small but non-zero delay. Any subscribe() call that
110
- // arrives during this window will cancel the check via version
111
- // invalidation + clearTimeout.
618
+ // is still unconsumed after the queue drains, it's truly orphaned, or,
619
+ // when its type carries no ordering claim, parked for a later consumer.
620
+ const checkVersion = ++this.unconsumedCheckVersion;
621
+ this.pendingUnconsumedCheck = this.getPromiseQueue()
622
+ .then(
623
+ // Yield once after the first queue drain so promise chains resumed by
624
+ // that drain can run across the VM boundary and append any follow-up
625
+ // async work (for example: step_completed resolves -> for-await loop
626
+ // resumes -> the next hook payload starts hydrating).
627
+ () => new Promise((resolve) => setTimeout(resolve, 0)))
628
+ .then(() => this.getPromiseQueue())
629
+ .then(() => {
630
+ // Wait out any delivery still in flight before starting the timer.
631
+ // The queue draining says the host has no hydration work left; it
632
+ // does not say the VM has finished reacting to what was hydrated.
633
+ this.whenDeliveryIdle(checkVersion, () => {
634
+ // Use a delayed setTimeout once deliveries are idle. The delay must
635
+ // be long enough for promise chains to propagate across the VM
636
+ // boundary (from resolve() in the host context through to the
637
+ // workflow code calling subscribe() in the VM context). Node.js does
638
+ // not guarantee that setTimeout(0) fires after all cross-context
639
+ // microtasks settle, so we use a small but non-zero delay. Any
640
+ // subscribe() call that arrives during this window will cancel the
641
+ // check via version invalidation + clearTimeout.
112
642
  this.pendingUnconsumedTimeout = setTimeout(() => {
113
643
  this.pendingUnconsumedTimeout = null;
114
- if (this.unconsumedCheckVersion === checkVersion) {
115
- this.pendingUnconsumedCheck = null;
116
- this.onUnconsumedEvent(currentEvent);
644
+ if (this.unconsumedCheckVersion !== checkVersion) {
645
+ return;
117
646
  }
118
- }, DEFERRED_CHECK_DELAY_MS);
647
+ this.pendingUnconsumedCheck = null;
648
+ this.resolveUnconsumedEvent(currentEvent, mayPark);
649
+ }, getDeferredCheckDelayMs());
119
650
  });
651
+ });
652
+ }
653
+ /**
654
+ * Decide what a still-unconsumed event is, now that the promise queue has
655
+ * drained and the delivery gate says the VM is not mid-reaction.
656
+ *
657
+ * `mayPark` is false only for the end-of-log recheck of an event {@link park}
658
+ * already holds. Nothing in the first branch applies to one of those: it is
659
+ * not the event at the cursor, so the identity guard is not meaningful, and
660
+ * it is parked already.
661
+ *
662
+ * A duplicate class never arrives here. {@link consume} steps over one in the
663
+ * pass that offered it, before this check is ever scheduled, and a class
664
+ * recorded while the check was in flight can only have been recorded by a
665
+ * consumption inside {@link consume}, whose next pass re-offers this event
666
+ * and steps over it there, leaving the identity guard above to drop the
667
+ * in-flight check. One that parks before any consumption records its class
668
+ * is released later by {@link dropParkedDuplicates} instead.
669
+ */
670
+ resolveUnconsumedEvent(currentEvent, mayPark) {
671
+ if (mayPark) {
672
+ if (this.events[this.eventIndex] !== currentEvent) {
673
+ // An append() drain claimed it while the check was in flight.
674
+ // Only subscribe() cancels the check, so this is reachable.
675
+ return;
676
+ }
677
+ if (this.park(currentEvent)) {
678
+ this.consume();
679
+ return;
680
+ }
120
681
  }
121
- };
682
+ this.onUnconsumedEvent(currentEvent);
683
+ }
684
+ /**
685
+ * Run `fn` once no data delivery is in flight, polling the way
686
+ * `scheduleWhenIdle` does: let the promise queue drain, re-check a timer
687
+ * tick later, repeat.
688
+ *
689
+ * Without this the check is a bet that every delivery the walk is running
690
+ * ahead of lands inside a fixed window. Consumption is synchronous while the
691
+ * resolution it triggers is not: a step result hydrates in the host, resolves
692
+ * from a detached continuation behind `awaitEarlierDeliveries`, and only then
693
+ * does VM code run far enough to subscribe the next consumer. Replaying a
694
+ * batch of N parallel step results leaves N-1 of them on that detached path
695
+ * with the queue already drained, so the walk sits on the ordered event the
696
+ * VM is about to draw and the window is the only thing standing between a
697
+ * healthy run and `ReplayDivergenceError`.
698
+ *
699
+ * Shortening the window shows that mechanism directly: on identical event logs
700
+ * the local race repro corrupts 34 of 42 runs at a 10ms window and 0 of 114 at
701
+ * the 100ms default. That measures how the bet loses, not that the default
702
+ * loses it, and no measurement of a delivery outrunning 100ms exists either
703
+ * way. So read this as retiring the bet rather than as repairing an observed
704
+ * failure of that number: the delay is a user-settable env override, which
705
+ * leaves the old behavior one configuration away from losing on any backend.
706
+ *
707
+ * Termination is `hasParkedCommittedDelivery`'s: it counts only deliveries
708
+ * that resolve on their own, so nothing here can gate its own retirement. A
709
+ * genuinely orphaned event has no delivery to wait on and reaches `fn` on the
710
+ * first poll.
711
+ *
712
+ * What the gate gives up: for the ordered events that still reach
713
+ * `onUnconsumedEvent` rather than {@link park}, this stops being the thing
714
+ * that catches a diverged log while a delivery is in flight. The suspension
715
+ * and this check now wake from the same `isDeliveryIdle` edge, and
716
+ * `scheduleWhenIdle` fires on the first timer tick after idle while this waits
717
+ * a further `getDeferredCheckDelayMs()`. So a run with a pending `sleep()`
718
+ * suspends first, and `onWorkflowError` drops the divergence arriving second
719
+ * (its `'suspended'` branch demotes to `'replay'` and surfaces nothing),
720
+ * leaving a later `resume()` to decline into a cold replay. Pre-gate the
721
+ * suspension already won that race whenever the delivery landed inside the
722
+ * fixed window, so what changed is that the outcome stopped depending on
723
+ * timing. Nothing should treat this check as the mechanism that reports
724
+ * divergence on a log the run is still delivering into.
725
+ */
726
+ whenDeliveryIdle(checkVersion, fn) {
727
+ const poll = () => {
728
+ this.pendingUnconsumedTimeout = null;
729
+ if (this.unconsumedCheckVersion !== checkVersion) {
730
+ return;
731
+ }
732
+ if (this.isDeliveryIdle()) {
733
+ fn();
734
+ return;
735
+ }
736
+ this.getPromiseQueue().then(() => {
737
+ if (this.unconsumedCheckVersion !== checkVersion) {
738
+ return;
739
+ }
740
+ // Held in the same field the fired check uses so subscribe() cancels a
741
+ // poll in progress too. The two cancellations are not identical: for the
742
+ // poll it is the version bump that does the work and the clearTimeout is
743
+ // belt-and-braces. Two state machines write this one field, so a poll
744
+ // invalidated between scheduling and firing can null out a handle the
745
+ // live chain has since stored, which is why every path out of `poll` and
746
+ // out of the fired check re-checks the version rather than trusting the
747
+ // handle.
748
+ this.pendingUnconsumedTimeout = setTimeout(poll, 0);
749
+ });
750
+ };
751
+ poll();
752
+ }
122
753
  }
123
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLWNvbnN1bWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2V2ZW50cy1jb25zdW1lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTNDOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsR0FBRyxDQUFDO0FBRTNDLE1BQU0sQ0FBTixJQUFZLG1CQWFYO0FBYkQsV0FBWSxtQkFBbUI7SUFDN0I7O09BRUc7SUFDSCxxRUFBUSxDQUFBO0lBQ1I7O09BRUc7SUFDSCwyRUFBVyxDQUFBO0lBQ1g7O09BRUc7SUFDSCxxRUFBUSxDQUFBO0FBQ1YsQ0FBQyxFQWJXLG1CQUFtQixLQUFuQixtQkFBbUIsUUFhOUI7QUFzQkQsTUFBTSxPQUFPLGNBQWM7SUFDekIsVUFBVSxDQUFTO0lBQ1YsTUFBTSxHQUFZLEVBQUUsQ0FBQztJQUNyQixTQUFTLEdBQTRCLEVBQUUsQ0FBQztJQUN6QyxpQkFBaUIsQ0FBeUI7SUFDMUMsZUFBZSxDQUFzQjtJQUNyQyxzQkFBc0IsR0FBeUIsSUFBSSxDQUFDO0lBQ3BELHdCQUF3QixHQUF5QyxJQUFJLENBQUM7SUFDdEUsc0JBQXNCLEdBQUcsQ0FBQyxDQUFDO0lBRW5DLFlBQVksTUFBZSxFQUFFLE9BQThCO1FBQ3pELElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUM7UUFDbkQsSUFBSSxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDO0lBQ2pELENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILFNBQVMsQ0FBQyxFQUF5QjtRQUNqQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN4QixrRkFB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RTtvQkFDOUMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLElBQUksQ0FBQztvQkFDckMsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEtBQUssWUFBWSxFQUFFLENBQUM7d0JBQ2pELElBQUksQ0FBQyxzQkFBc0IsR0FBRyxJQUFJLENBQUM7d0JBQ25DLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztvQkFDdkMsQ0FBQztnQkFDSCxDQUFDLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztZQUM5QixDQUFDLENBQUMsQ0FBQztRQUNQLENBQUM7SUFDSCxDQUFDLENBQUM7Q0FDSCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRXZlbnQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgZXZlbnRzTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG4vKipcbiAqIERlbGF5IGJlZm9yZSBmaXJpbmcgdGhlIGRlZmVycmVkIHVuY29uc3VtZWQtZXZlbnQgY2hlY2sgYWZ0ZXIgdGhlIHByb21pc2VcbiAqIHF1ZXVlIGhhcyBkcmFpbmVkLiBNdXN0IGJlIGxvbmcgZW5vdWdoIGZvciBjcm9zcy1WTSBtaWNyb3Rhc2sgY2hhaW5zIHRvXG4gKiBwcm9wYWdhdGUgKHJlc29sdmUgaW4gaG9zdCDihpIgd29ya2Zsb3cgY29kZSBpbiBWTSDihpIgc3Vic2NyaWJlIGNhbGwgYmFja1xuICogaW4gaG9zdCkuIEFueSBzdWJzY3JpYmUoKSBhcnJpdmluZyBkdXJpbmcgdGhpcyB3aW5kb3cgY2FuY2VscyB0aGUgY2hlY2suXG4gKi9cbmV4cG9ydCBjb25zdCBERUZFUlJFRF9DSEVDS19ERUxBWV9NUyA9IDEwMDtcblxuZXhwb3J0IGVudW0gRXZlbnRDb25zdW1lclJlc3VsdCB7XG4gIC8qKlxuICAgKiBDYWxsYmFjayBjb25zdW1lZCB0aGUgZXZlbnQsIGJ1dCBzaG91bGQgbm90IGJlIHJlbW92ZWQgZnJvbSB0aGUgY2FsbGJhY2tzIGxpc3RcbiAgICovXG4gIENvbnN1bWVkLFxuICAvKipcbiAgICogQ2FsbGJhY2sgZGlkIG5vdCBjb25zdW1lIHRoZSBldmVudCwgc28gaXQgc2hvdWxkIGJlIHBhc3NlZCB0byB0aGUgbmV4dCBjYWxsYmFja1xuICAgKi9cbiAgTm90Q29uc3VtZWQsXG4gIC8qKlxuICAgKiBDYWxsYmFjayBjb25zdW1lZCB0aGUgZXZlbnQsIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCBmcm9tIHRoZSBjYWxsYmFja3MgbGlzdFxuICAgKi9cbiAgRmluaXNoZWQsXG59XG5cbnR5cGUgRXZlbnRDb25zdW1lckNhbGxiYWNrID0gKGV2ZW50OiBFdmVudCB8IG51bGwpID0+IEV2ZW50Q29uc3VtZXJSZXN1bHQ7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRzQ29uc3VtZXJPcHRpb25zIHtcbiAgLyoqXG4gICAqIENhbGxiYWNrIGludm9rZWQgd2hlbiBhIG5vbi1udWxsIGV2ZW50IGNhbm5vdCBiZSBjb25zdW1lZCBieSBhbnkgcmVnaXN0ZXJlZFxuICAgKiBjYWxsYmFjaywgaW5kaWNhdGluZyBhbiBvcnBoYW5lZCBvciBpbnZhbGlkIGV2ZW50IGluIHRoZSBldmVudCBsb2cuIFRoZVxuICAgKiBjaGVjayBpcyBkZWZlcnJlZCB1bnRpbCBhZnRlciB0aGUgcHJvbWlzZSBxdWV1ZSBoYXMgZHJhaW5lZCwgZW5zdXJpbmcgdGhhdFxuICAgKiBhbnkgcGVuZGluZyBhc3luYyB3b3JrIChlLmcuLCBkZXNlcmlhbGl6YXRpb24vZGVjcnlwdGlvbikgY29tcGxldGVzIGFuZFxuICAgKiBkb3duc3RyZWFtIHN1YnNjcmliZSgpIGNhbGxzIGhhdmUgYSBjaGFuY2UgdG8gY2FuY2VsIHRoZSBjaGVjayBmaXJzdC5cbiAgICovXG4gIG9uVW5jb25zdW1lZEV2ZW50OiAoZXZlbnQ6IEV2ZW50KSA9PiB2b2lkO1xuICAvKipcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCBwcm9taXNlIHF1ZXVlLiBUaGUgdW5jb25zdW1lZCBldmVudCBjaGVjayBpcyBjaGFpbmVkXG4gICAqIG9udG8gdGhpcyBxdWV1ZSBzbyBpdCBvbmx5IGZpcmVzIGFmdGVyIGFsbCBwZW5kaW5nIGFzeW5jIHdvcmsgKGUuZy4sXG4gICAqIGRlc2VyaWFsaXphdGlvbikgaGFzIGNvbXBsZXRlZC4gVGhpcyBwcmV2ZW50cyBmYWxzZSBwb3NpdGl2ZXMgd2hlbiBhc3luY1xuICAgKiBkZXNlcmlhbGl6YXRpb24gZGVsYXlzIHRoZSByZXNvbHZlKCkgdGhhdCB0cmlnZ2VycyB0aGUgbmV4dCBzdWJzY3JpYmUoKS5cbiAgICovXG4gIGdldFByb21pc2VRdWV1ZTogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGNsYXNzIEV2ZW50c0NvbnN1bWVyIHtcbiAgZXZlbnRJbmRleDogbnVtYmVyO1xuICByZWFkb25seSBldmVudHM6IEV2ZW50W10gPSBbXTtcbiAgcmVhZG9ubHkgY2FsbGJhY2tzOiBFdmVudENvbnN1bWVyQ2FsbGJhY2tbXSA9IFtdO1xuICBwcml2YXRlIG9uVW5jb25zdW1lZEV2ZW50OiAoZXZlbnQ6IEV2ZW50KSA9PiB2b2lkO1xuICBwcml2YXRlIGdldFByb21pc2VRdWV1ZTogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgcHJpdmF0ZSBwZW5kaW5nVW5jb25zdW1lZENoZWNrOiBQcm9taXNlPHZvaWQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcGVuZGluZ1VuY29uc3VtZWRUaW1lb3V0OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHVuY29uc3VtZWRDaGVja1ZlcnNpb24gPSAwO1xuXG4gIGNvbnN0cnVjdG9yKGV2ZW50czogRXZlbnRbXSwgb3B0aW9uczogRXZlbnRzQ29uc3VtZXJPcHRpb25zKSB7XG4gICAgdGhpcy5ldmVudHMgPSBldmVudHM7XG4gICAgdGhpcy5ldmVudEluZGV4ID0gMDtcbiAgICB0aGlzLm9uVW5jb25zdW1lZEV2ZW50ID0gb3B0aW9ucy5vblVuY29uc3VtZWRFdmVudDtcbiAgICB0aGlzLmdldFByb21pc2VRdWV1ZSA9IG9wdGlvbnMuZ2V0UHJvbWlzZVF1ZXVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciBhbiBldmVudCBoYXMgYmVlbiBjb25zdW1lZFxuICAgKiBieSBhIGRpZmZlcmVudCBjYWxsYmFjay4gVGhlIGNhbGxiYWNrIGNhbiByZXR1cm46XG4gICAqICAtIGBFdmVudENvbnN1bWVyUmVzdWx0LkNvbnN1bWVkYCB0aGUgZXZlbnQgaXMgY29uc2lkZXJlZCBjb25zdW1lZCBhbmQgd2lsbCBub3QgYmUgcGFzc2VkIHRvIGFueSBvdGhlciBjYWxsYmFjaywgYnV0IHRoZSBjYWxsYmFjayB3aWxsIHJlbWFpbiBpbiB0aGUgY2FsbGJhY2tzIGxpc3RcbiAgICogIC0gYEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWRgIHRoZSBldmVudCBpcyBwYXNzZWQgdG8gdGhlIG5leHQgY2FsbGJhY2tcbiAgICogIC0gYEV2ZW50Q29uc3VtZXJSZXN1bHQuRmluaXNoZWRgIHRoZSBldmVudCBpcyBjb25zaWRlcmVkIGNvbnN1bWVkIGFuZCB0aGUgY2FsbGJhY2sgaXMgcmVtb3ZlZCBmcm9tIHRoZSBjYWxsYmFja3MgbGlzdFxuICAgKlxuICAgKiBAcGFyYW0gZm4gLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gcmVnaXN0ZXIuXG4gICAqL1xuICBzdWJzY3JpYmUoZm46IEV2ZW50Q29uc3VtZXJDYWxsYmFjaykge1xuICAgIHRoaXMuY2FsbGJhY2tzLnB1c2goZm4pO1xuICAgIC8vIENhbmNlbCBhbnkgcGVuZGluZyB1bmNvbnN1bWVkIGNoZWNrIHNpbmNlIGEgbmV3IGNhbGxiYWNrIG1heSBjb25zdW1lIHRoZSBldmVudC5cbiAgICAvLyBJbmNyZW1lbnRpbmcgdGhlIHZlcnNpb24gY2F1c2VzIGFueSBpbi1mbGlnaHQgcHJvbWlzZSBjaGFpbiBjaGVjayB0byBuby1vcC5cbiAgICAvLyBBbHNvIGNsZWFyIHRoZSBwZW5kaW5nIHNldFRpbWVvdXQgaWYgaXQgaGFzbid0IGZpcmVkIHlldC5cbiAgICBpZiAodGhpcy5wZW5kaW5nVW5jb25zdW1lZENoZWNrICE9PSBudWxsKSB7XG4gICAgICB0aGlzLnVuY29uc3VtZWRDaGVja1ZlcnNpb24rKztcbiAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRDaGVjayA9IG51bGw7XG4gICAgICBpZiAodGhpcy5wZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQgIT09IG51bGwpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMucGVuZGluZ1VuY29uc3VtZWRUaW1lb3V0KTtcbiAgICAgICAgdGhpcy5wZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQgPSBudWxsO1xuICAgICAgfVxuICAgIH1cbiAgICBwcm9jZXNzLm5leHRUaWNrKHRoaXMuY29uc3VtZSk7XG4gIH1cblxuICBwcml2YXRlIGNvbnN1bWUgPSAoKSA9PiB7XG4gICAgY29uc3QgY3VycmVudEV2ZW50ID0gdGhpcy5ldmVudHNbdGhpcy5ldmVudEluZGV4XSA/PyBudWxsO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5jYWxsYmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNhbGxiYWNrID0gdGhpcy5jYWxsYmFja3NbaV07XG4gICAgICBsZXQgaGFuZGxlZCA9IEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBoYW5kbGVkID0gY2FsbGJhY2soY3VycmVudEV2ZW50KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGV2ZW50c0xvZ2dlci5lcnJvcignRXZlbnRDb25zdW1lciBjYWxsYmFjayB0aHJldyBhbiBlcnJvcicsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIGhhbmRsZWQgPT09IEV2ZW50Q29uc3VtZXJSZXN1bHQuQ29uc3VtZWQgfHxcbiAgICAgICAgaGFuZGxlZCA9PT0gRXZlbnRDb25zdW1lclJlc3VsdC5GaW5pc2hlZFxuICAgICAgKSB7XG4gICAgICAgIC8vIGNvbnN1bWVyIGhhbmRsZWQgdGhpcyBldmVudCwgc28gaW5jcmVhc2UgdGhlIGV2ZW50IGluZGV4XG4gICAgICAgIHRoaXMuZXZlbnRJbmRleCsrO1xuXG4gICAgICAgIC8vIHJlbW92ZSB0aGUgY2FsbGJhY2sgaWYgaXQgaGFzIGZpbmlzaGVkXG4gICAgICAgIGlmIChoYW5kbGVkID09PSBFdmVudENvbnN1bWVyUmVzdWx0LkZpbmlzaGVkKSB7XG4gICAgICAgICAgdGhpcy5jYWxsYmFja3Muc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY29udGludWUgdG8gdGhlIG5leHQgZXZlbnRcbiAgICAgICAgcHJvY2Vzcy5uZXh0VGljayh0aGlzLmNvbnN1bWUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSWYgd2UgcmVhY2ggaGVyZSwgYWxsIGNhbGxiYWNrcyByZXR1cm5lZCBOb3RDb25zdW1lZC5cbiAgICAvLyBJZiB0aGUgY3VycmVudCBldmVudCBpcyBub24tbnVsbCAoYSByZWFsIGV2ZW50LCBub3QgZW5kLW9mLWV2ZW50cyksXG4gICAgLy8gc2NoZWR1bGUgYSBkZWZlcnJlZCBjaGVjay4gV2UgY2hhaW4gb250byB0aGUgcHJvbWlzZVF1ZXVlIHNvIHRoYXQgYW55XG4gICAgLy8gcGVuZGluZyBhc3luYyB3b3JrIChlLmcuLCBkZXNlcmlhbGl6YXRpb24vZGVjcnlwdGlvbiB0aGF0IHRyaWdnZXJzXG4gICAgLy8gcmVzb2x2ZSgpIOKGkiB1c2VyIGNvZGUg4oaSIHN1YnNjcmliZSgpKSBjb21wbGV0ZXMgZmlyc3QuIElmIHRoZSBldmVudFxuICAgIC8vIGlzIHN0aWxsIHVuY29uc3VtZWQgYWZ0ZXIgdGhlIHF1ZXVlIGRyYWlucywgaXQncyB0cnVseSBvcnBoYW5lZC5cbiAgICBpZiAoY3VycmVudEV2ZW50ICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBjaGVja1ZlcnNpb24gPSArK3RoaXMudW5jb25zdW1lZENoZWNrVmVyc2lvbjtcbiAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRDaGVjayA9IHRoaXMuZ2V0UHJvbWlzZVF1ZXVlKClcbiAgICAgICAgLnRoZW4oXG4gICAgICAgICAgLy8gWWllbGQgb25jZSBhZnRlciB0aGUgZmlyc3QgcXVldWUgZHJhaW4gc28gcHJvbWlzZSBjaGFpbnMgcmVzdW1lZCBieVxuICAgICAgICAgIC8vIHRoYXQgZHJhaW4gY2FuIHJ1biBhY3Jvc3MgdGhlIFZNIGJvdW5kYXJ5IGFuZCBhcHBlbmQgYW55IGZvbGxvdy11cFxuICAgICAgICAgIC8vIGFzeW5jIHdvcmsgKGZvciBleGFtcGxlOiBzdGVwX2NvbXBsZXRlZCByZXNvbHZlcyAtPiBmb3ItYXdhaXQgbG9vcFxuICAgICAgICAgIC8vIHJlc3VtZXMgLT4gdGhlIG5leHQgaG9vayBwYXlsb2FkIHN0YXJ0cyBoeWRyYXRpbmcpLlxuICAgICAgICAgICgpID0+IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDApKVxuICAgICAgICApXG4gICAgICAgIC50aGVuKCgpID0+IHRoaXMuZ2V0UHJvbWlzZVF1ZXVlKCkpXG4gICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAvLyBVc2UgYSBkZWxheWVkIHNldFRpbWVvdXQgYWZ0ZXIgdGhlIHF1ZXVlIGRyYWlucy4gVGhlIGRlbGF5IG11c3QgYmVcbiAgICAgICAgICAvLyBsb25nIGVub3VnaCBmb3IgcHJvbWlzZSBjaGFpbnMgdG8gcHJvcGFnYXRlIGFjcm9zcyB0aGUgVk0gYm91bmRhcnlcbiAgICAgICAgICAvLyAoZnJvbSByZXNvbHZlKCkgaW4gdGhlIGhvc3QgY29udGV4dCB0aHJvdWdoIHRvIHRoZSB3b3JrZmxvdyBjb2RlXG4gICAgICAgICAgLy8gY2FsbGluZyBzdWJzY3JpYmUoKSBpbiB0aGUgVk0gY29udGV4dCkuIE5vZGUuanMgZG9lcyBub3QgZ3VhcmFudGVlXG4gICAgICAgICAgLy8gdGhhdCBzZXRUaW1lb3V0KDApIGZpcmVzIGFmdGVyIGFsbCBjcm9zcy1jb250ZXh0IG1pY3JvdGFza3Mgc2V0dGxlLFxuICAgICAgICAgIC8vIHNvIHdlIHVzZSBhIHNtYWxsIGJ1dCBub24temVybyBkZWxheS4gQW55IHN1YnNjcmliZSgpIGNhbGwgdGhhdFxuICAgICAgICAgIC8vIGFycml2ZXMgZHVyaW5nIHRoaXMgd2luZG93IHdpbGwgY2FuY2VsIHRoZSBjaGVjayB2aWEgdmVyc2lvblxuICAgICAgICAgIC8vIGludmFsaWRhdGlvbiArIGNsZWFyVGltZW91dC5cbiAgICAgICAgICB0aGlzLnBlbmRpbmdVbmNvbnN1bWVkVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKHRoaXMudW5jb25zdW1lZENoZWNrVmVyc2lvbiA9PT0gY2hlY2tWZXJzaW9uKSB7XG4gICAgICAgICAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRDaGVjayA9IG51bGw7XG4gICAgICAgICAgICAgIHRoaXMub25VbmNvbnN1bWVkRXZlbnQoY3VycmVudEV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCBERUZFUlJFRF9DSEVDS19ERUxBWV9NUyk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfTtcbn1cbiJdfQ==
754
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLWNvbnN1bWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2V2ZW50cy1jb25zdW1lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdkQsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixpQkFBaUIsR0FDbEIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTNDOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsR0FBRyxDQUFDO0FBRTNDOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBRyxFQUFFLENBQUM7QUFFOUM7Ozs7Ozs7R0FPRztBQUNILE1BQU0sdUJBQXVCLEdBQUcsR0FBVyxFQUFFLENBQzNDLFNBQVMsQ0FBQyxrQ0FBa0MsRUFBRSx1QkFBdUIsRUFBRTtJQUNyRSxPQUFPLEVBQUUsSUFBSTtJQUNiLEdBQUcsRUFBRSwyQkFBMkI7Q0FDakMsQ0FBQyxDQUFDO0FBRUw7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4Q0c7QUFDSCxNQUFNLG9CQUFvQixHQUFvQyxJQUFJLEdBQUcsQ0FBQztJQUNwRSxlQUFlO0lBQ2YsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixVQUFVO0lBQ1YsZUFBZTtDQUNoQixDQUFDLENBQUM7QUFFSDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sb0JBQW9CLEdBQW9DLElBQUksR0FBRyxDQUFDO0lBQ3BFLGdCQUFnQjtDQUNqQixDQUFDLENBQUM7QUFFSCxpRUFBaUU7QUFDakUsU0FBUyxhQUFhLENBQUMsU0FBaUIsRUFBRSxhQUFxQjtJQUM3RCxPQUFPLEdBQUcsU0FBUyxJQUFJLGFBQWEsRUFBRSxDQUFDO0FBQ3pDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFN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LEVBQUUsQ0FBQztnQkFDakQsT0FBTztZQUNULENBQUM7WUFDRCxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO2dCQUMxQixFQUFFLEVBQUUsQ0FBQztnQkFDTCxPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO2dCQUMvQixJQUFJLElBQUksQ0FBQyxzQkFBc0IsS0FBSyxZQUFZLEVBQUUsQ0FBQztvQkFDakQsT0FBTztnQkFDVCxDQUFDO2dCQUNELHVFQUF1RTtnQkFDdkUseUVBQXlFO2dCQUN6RSx5RUFBeUU7Z0JBQ3pFLHNFQUFzRTtnQkFDdEUsc0VBQXNFO2dCQUN0RSx5RUFBeUU7Z0JBQ3pFLHdFQUF3RTtnQkFDeEUsVUFBVTtnQkFDVixJQUFJLENBQUMsd0JBQXdCLEdBQUcsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN0RCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNGLElBQUksRUFBRSxDQUFDO0lBQ1QsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBFdmVudCB9IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBlbnZOdW1iZXIgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQvZW52LWNvbmZpZyc7XG5pbXBvcnQge1xuICBjbGFzc2lmeUVudGl0eUV2ZW50LFxuICBpc1NlYWxlZE5vb3BFdmVudCxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkL2V2ZW50LW1ldGFkYXRhJztcbmltcG9ydCB7IGV2ZW50c0xvZ2dlciB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBEZWxheSBiZWZvcmUgZmlyaW5nIHRoZSBkZWZlcnJlZCB1bmNvbnN1bWVkLWV2ZW50IGNoZWNrIGFmdGVyIHRoZSBwcm9taXNlXG4gKiBxdWV1ZSBoYXMgZHJhaW5lZC4gTXVzdCBiZSBsb25nIGVub3VnaCBmb3IgY3Jvc3MtVk0gbWljcm90YXNrIGNoYWlucyB0b1xuICogcHJvcGFnYXRlIChyZXNvbHZlIGluIGhvc3Qg4oaSIHdvcmtmbG93IGNvZGUgaW4gVk0g4oaSIHN1YnNjcmliZSBjYWxsIGJhY2tcbiAqIGluIGhvc3QpLiBBbnkgc3Vic2NyaWJlKCkgYXJyaXZpbmcgZHVyaW5nIHRoaXMgd2luZG93IGNhbmNlbHMgdGhlIGNoZWNrLlxuICovXG5leHBvcnQgY29uc3QgREVGRVJSRURfQ0hFQ0tfREVMQVlfTVMgPSAxMDA7XG5cbi8qKlxuICogRmxvb3IgZm9yIHRoZSBkZWZlcnJlZC1jaGVjayBkZWxheSwgc28gYSB0b28tbG93IG92ZXJyaWRlIGNhbid0IG1hbnVmYWN0dXJlXG4gKiBzcHVyaW91cyBkaXZlcmdlbmNlIChlYWNoIGZhbHNlIHBvc2l0aXZlIGJ1cm5zIGEgZGl2ZXJnZW5jZS1yZWNvdmVyeSByZXRyeVxuICogYW5kIGNhbiBlc2NhbGF0ZSB0byBhIHRlcm1pbmFsIGBDb3JydXB0ZWRFdmVudExvZ0Vycm9yYCkuXG4gKlxuICogRXhwb3J0ZWQgc28gdGVzdHMgbmVlZGluZyB0aGUgc2hvcnRlc3QgbGVnYWwgZGVsYXkgY2FuIGFzayBmb3IgaXQgaW5zdGVhZCBvZlxuICogaGFyZGNvZGluZyBhIG51bWJlciB0aGlzIGZsb29yIHdvdWxkIHNpbGVudGx5IGNsYW1wIHVwLlxuICovXG5leHBvcnQgY29uc3QgTUlOX0RFRkVSUkVEX0NIRUNLX0RFTEFZX01TID0gMTA7XG5cbi8qKlxuICogRWZmZWN0aXZlIGRlZmVycmVkLWNoZWNrIGRlbGF5LiBPdmVycmlkZTogYFdPUktGTE9XX0RFRkVSUkVEX0NIRUNLX0RFTEFZX01TYC5cbiAqXG4gKiBVbmxpa2UgdGhlIG90aGVyIHRpbWluZyBrbm9icyB0aGlzIGlzIG5vdCBhIHBvbGxpbmcgaW50ZXJ2YWwgYnV0IGFcbiAqIGRldGVybWluaXNtIHNhZmV0eSBtYXJnaW46IGZpcmluZyB0aGUgdW5jb25zdW1lZC1ldmVudCBjaGVjayBiZWZvcmUgdGhlXG4gKiBjcm9zcy1WTSBzdWJzY3JpYmUoKSBjaGFpbiBoYXMgbGFuZGVkIHJlamVjdHMgYSBoZWFsdGh5IHJ1biB3aXRoXG4gKiBgUmVwbGF5RGl2ZXJnZW5jZUVycm9yYC5cbiAqL1xuY29uc3QgZ2V0RGVmZXJyZWRDaGVja0RlbGF5TXMgPSAoKTogbnVtYmVyID0+XG4gIGVudk51bWJlcignV09SS0ZMT1dfREVGRVJSRURfQ0hFQ0tfREVMQVlfTVMnLCBERUZFUlJFRF9DSEVDS19ERUxBWV9NUywge1xuICAgIGludGVnZXI6IHRydWUsXG4gICAgbWluOiBNSU5fREVGRVJSRURfQ0hFQ0tfREVMQVlfTVMsXG4gIH0pO1xuXG4vKipcbiAqIEV2ZW50IHR5cGVzIHRoZSBvcmRlcmVkIHdhbGsgbWF5IHN0ZXAgb3ZlciBhbmQgZGVsaXZlciBsYXRlci5cbiAqXG4gKiBNZW1iZXJzaGlwIGlzIG5vdCBhYm91dCB3aG8gd3JvdGUgdGhlIGV2ZW50LiBJdCBpcyBhYm91dCB3aGV0aGVyIHRoZSBldmVudFxuICogY2FuIHJlYWNoIHRoZSBoZWFkIG9mIHRoZSB3YWxrIHdpdGggbm90aGluZyByZWdpc3RlcmVkIHRvIGNvbnN1bWUgaXQsIHdoaWNoXG4gKiBpcyB0aGUgb25seSBzaXR1YXRpb24gcGFya2luZyBleGlzdHMgZm9yLlxuICpcbiAqIE1vc3QgdHlwZXMgY2Fubm90LiBUaGV5IGFyZSByZXBsYXktb3JpZ2luOiBhIHJlcGxheSBlbWl0cyB0aGVtLCBpbiB0aGUgb3JkZXJcbiAqIGl0cyBjb2RlIHJlYWNoZXMgdGhlbSwgc28gdGhlaXIgcG9zaXRpb24gaW4gdGhlIGxvZyBpcyB0aGUgcmVjb3JkIG9mIHdoYXRcbiAqIHRoYXQgcmVwbGF5IGRlY2lkZWQuIFJlYWNoaW5nIG9uZSBvZiB0aG9zZSBvdXQgb2Ygb3JkZXIgbWVhbnMgdGhpcyByZXBsYXlcbiAqIGRlY2lkZWQgZGlmZmVyZW50bHkgdGhhbiB0aGUgbG9nIGhvbGRzLCB3aGljaCBpcyBkaXZlcmdlbmNlIGFuZCBub3RoaW5nIGVsc2UuXG4gKlxuICogU3RlcCBsaWZlY3ljbGUgZXZlbnRzIGFyZSBub3QgcmVwbGF5LW9yaWdpbiwgYW5kIGFyZSBzdGlsbCBhYnNlbnQsIGJlY2F1c2VcbiAqIHRoZXkgYWx3YXlzIGhhdmUgYSBjbGFpbWFudC4gYHN0ZXAoKWAgc3Vic2NyaWJlcyBpdHMgY29uc3VtZXIgYmVmb3JlIHRoZVxuICogc3RlcCdzIGZpcnN0IGV2ZW50IGNhbiBleGlzdDsgYHN0ZXBfY3JlYXRlZGAgaXMgb3JkZXJlZCwgc28gdGhlIHdhbGsgY2Fubm90XG4gKiBwYXNzIGl0IHVubGVzcyBhIGNvbnN1bWVyIHRha2VzIGl0OyBhbmQgdGhhdCBjb25zdW1lciBzdGF5cyBzdWJzY3JpYmVkIHVudGlsXG4gKiBgc3RlcF9jb21wbGV0ZWRgIG9yIGBzdGVwX2ZhaWxlZGAsIGFmdGVyIHdoaWNoIHRoZSBXb3JsZCByZWZ1c2VzIGFueSBmdXJ0aGVyXG4gKiB3cml0ZSBmb3IgdGhhdCBzdGVwLiBUaGVyZSBpcyBubyB3aW5kb3cgaW4gd2hpY2ggYSByZXBsYXkga25vd3MgYWJvdXQgYSBzdGVwXG4gKiBhbmQgaGFzIG5vdGhpbmcgcmVnaXN0ZXJlZCB0byBjb25zdW1lIGl0cyBldmVudHMsIHNvIHBhcmtpbmcgdGhlbSB3b3VsZCBvbmx5XG4gKiBkZWZlciByZXBvcnRzIG9mIHdoYXQgaXMgZGl2ZXJnZW5jZSBlaXRoZXIgd2F5LiBUaGUgc2FtZSBob2xkcyBmb3JcbiAqIGB3YWl0X2NyZWF0ZWRgIGFuZCBpdHMgY29uc3VtZXIuIGB3YWl0X2NvbXBsZXRlZGAgaXMgbGlzdGVkIGFueXdheTogYSBzbGVlcFxuICogY2FuIGFsc28gYmUgY29tcGxldGVkIG91dCBvZiBiYW5kLCBieSB0aGUgQVBJIHRoYXQgZm9yY2UtY29tcGxldGVzIHBlbmRpbmdcbiAqIHdhaXRzLCBhbmQgdG9sZXJhdGluZyBhIHN0cmF5IG9uZSBpcyB0aGUgY2hlYXBlciBkaXJlY3Rpb24gdG8gYmUgd3JvbmcgaW4uXG4gKlxuICogQW4gYWxsb3dsaXN0IHJhdGhlciB0aGFuIHRoZSBjb21wbGVtZW50IG9mIHRoZSBvcmRlcmVkIHNldCwgc28gYSB0eXBlIHRoaXNcbiAqIGZpbGUgaGFzIG5vdCBiZWVuIHRhdWdodCBhYm91dCBrZWVwcyB0aGUgc3RyaWN0IG9sZCBiZWhhdmlvci5cbiAqXG4gKiBgaG9va19kaXNwb3NlZGAgaXMgZGVsaWJlcmF0ZWx5IGFic2VudCBkZXNwaXRlIGJlaW5nIGFib3V0IGEgaG9vazogaXQgaXNcbiAqIHdyaXR0ZW4gd2hlbiB0aGUgd29ya2Zsb3cncyBvd24gYHVzaW5nYCBzY29wZSBleGl0cywgc28gaXQgaXMgcmVwbGF5LW9yaWdpbi5cbiAqXG4gKiBgYXR0cl9zZXRgIGlzIGxpc3RlZCBieSB0eXBlIGV2ZW4gdGhvdWdoIGEgZ2l2ZW4gaW5zdGFuY2Ugb2YgaXQgbWF5IGJlXG4gKiByZXBsYXktb3JpZ2luLCBzaW5jZSBpdCBpcyByZXBsYXktb3JpZ2luIHdoZW4gaXRzIHdyaXRlciBpcyB0aGUgd29ya2Zsb3cuXG4gKiBTcGxpdHRpbmcgdGhhdCBvdXQgcGVyIGV2ZW50IHdhcyBjb25zaWRlcmVkIGFuZCByZWplY3RlZC4gQSByZXBsYXkgdGhhdFxuICogcmVhY2hlcyBvbmUgb2YgaXRzIG93biB3cml0ZXMgb3V0IG9mIHBvc2l0aW9uIGhhcyBkaXZlcmdlZCwgYnV0IGEgcmVwbGF5IHRoYXRcbiAqIHJlYWNoZXMgYW4gZXZlbnQgaXQgZGlkIE5PVCB3cml0ZSwgc2l0dGluZyB3aGVyZSBpdHMgb3duIHdyaXRlIHdvdWxkIGdvLCBoYXNcbiAqIG5vdDogdGhlIHdyaXRlciBmaWVsZCBzYXlzIHdobyB3cm90ZSB0aGUgZXZlbnQsIGFuZCBub3Qgd2hldGhlciB0aGlzIHJlcGxheVxuICogaXMgdGhlIHNhbWUgb25lLiBHdWVzc2luZyB3cm9uZyBpbiB0aGF0IGRpcmVjdGlvbiBmYWlscyBoZWFsdGh5IHJ1bnMsIHdoaWNoXG4gKiBpcyB0aGUgZmFpbHVyZSB0aGlzIGZpbGUgZXhpc3RzIHRvIHN0b3AsIHNvIHRoZSB3aG9sZSB0eXBlIGlzIHRvbGVyYXRlZC4gVGhlXG4gKiBjb3N0IGlzIHRoYXQgYSBkaXZlcmdlbmNlIGludm9sdmluZyBgYXR0cl9zZXRgIHN1cmZhY2VzIGF0IHRoZSBlbmQgb2YgdGhlXG4gKiByZXBsYXksIHRocm91Z2ggYHN0cmFuZGVkRXZlbnRgLCByYXRoZXIgdGhhbiBhdCB0aGUgb2ZmZW5kaW5nIGV2ZW50LlxuICpcbiAqIFBhcmtpbmcgaGVyZSBpcyBmb3IgYW4gYGF0dHJfc2V0YCB0aGUgd2FsayByZWFjaGVzICpiZWZvcmUqIHRoZSBib2R5IGhhcyBtYWRlXG4gKiB0aGUgY2FsbCB0aGF0IGNsYWltcyBpdC4gQSBzZWNvbmQgZXZlbnQgdW5kZXIgYW4gaWQgYWxyZWFkeSBjbGFpbWVkIGlzIGFcbiAqIGRpZmZlcmVudCB0aGluZzogYGF0dHJfc2V0YCBoYXMgYW4gZW50aXR5IGV2ZW50IGNsYXNzLCBzbyB0aGUgZHVwbGljYXRlIHNraXBcbiAqIHRha2VzIGl0IGJlZm9yZSB0aGlzIHNldCBpcyBjb25zdWx0ZWQsIGFuZCBhIGNvcHkgdGhhdCBwYXJrZWQgYWhlYWQgb2YgYW55XG4gKiBjb25zdW1wdGlvbiBpcyByZWxlYXNlZCBieSB7QGxpbmsgZHJvcFBhcmtlZER1cGxpY2F0ZXN9IG9uY2Ugb25lIGxhbmRzLlxuICovXG5jb25zdCBQQVJLQUJMRV9FVkVOVF9UWVBFUzogUmVhZG9ubHlTZXQ8RXZlbnRbJ2V2ZW50VHlwZSddPiA9IG5ldyBTZXQoW1xuICAnaG9va19yZWNlaXZlZCcsXG4gICdob29rX2NvbmZsaWN0JyxcbiAgJ3dhaXRfY29tcGxldGVkJyxcbiAgJ2F0dHJfc2V0JyxcbiAgJ3J1bl9jYW5jZWxsZWQnLFxuXSk7XG5cbi8qKlxuICogUGFya2FibGUgdHlwZXMgdGhhdCBjYW4gb25seSBldmVyIHJlc29sdmUgdGhlaXIgY29ycmVsYXRpb24gaWQgb25jZS5cbiAqXG4gKiBBIHNlY29uZCBvbmUgZm9yIHRoZSBzYW1lIGlkIGlzIG5vdCBhIGRlbGl2ZXJ5IHRoaXMgcmVwbGF5IGhhcyBub3QgcmVhY2hlZFxuICogeWV0OiBpdCBpcyBhIHJlc29sdXRpb24gZm9yIHNvbWV0aGluZyBhbHJlYWR5IHJlc29sdmVkLCB3aGljaCBubyBjb25zdW1lclxuICogdGhpcyByZXBsYXkgb3IgYW55IGxhdGVyIG9uZSByZWdpc3RlcnMgY2FuIGV2ZXIgY2xhaW0uIGBob29rX3JlY2VpdmVkYCBpc1xuICogYWJzZW50IGJlY2F1c2UgYSBob29rIGxlZ2l0aW1hdGVseSBmaXJlcyBtYW55IHRpbWVzIHVuZGVyIG9uZSBpZC5cbiAqXG4gKiBNdXN0IHN0YXkgYSBzdWJzZXQgb2Yge0BsaW5rIFBBUktBQkxFX0VWRU5UX1RZUEVTfToge0BsaW5rIHBhcmt9IGlzIHRoZSBvbmx5XG4gKiByZWFkZXIgb2Ygd2hhdCB0aGlzIHJlY29yZHMsIGFuZCBpdCByZWplY3RzIGEgbm9uLXBhcmthYmxlIHR5cGUgYmVmb3JlIGl0XG4gKiBsb29rcywgc28gYW4gZW50cnkgb3V0c2lkZSB0aGF0IHNldCBpcyBkZWFkIHdlaWdodCBvbiBhIGhvdCBwYXRoLlxuICovXG5jb25zdCBPTkVfU0hPVF9FVkVOVF9UWVBFUzogUmVhZG9ubHlTZXQ8RXZlbnRbJ2V2ZW50VHlwZSddPiA9IG5ldyBTZXQoW1xuICAnd2FpdF9jb21wbGV0ZWQnLFxuXSk7XG5cbi8qKiBJZGVudGlmaWVzIHRoZSB0aGluZyBhIG9uZS1zaG90IHJlc29sdXRpb24gZXZlbnQgcmVzb2x2ZXMuICovXG5mdW5jdGlvbiByZXNvbHV0aW9uS2V5KGV2ZW50VHlwZTogc3RyaW5nLCBjb3JyZWxhdGlvbklkOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYCR7ZXZlbnRUeXBlfToke2NvcnJlbGF0aW9uSWR9YDtcbn1cblxuLyoqXG4gKiBUeXBlcyB0aGF0IGVuZCBhIHJ1bi4gT25jZSBvbmUgaXMgaW4gdGhlIGxvZywgbm8gY29uc3VtZXIgd2lsbCBldmVyIGJlXG4gKiByZWdpc3RlcmVkIGFnYWluLCBzbyBhIHBhcmtlZCBldmVudCBzdGlsbCBwYXJrZWQgaGVyZSB3aWxsIG5ldmVyIGJlIGNsYWltZWQuXG4gKi9cbmNvbnN0IFRFUk1JTkFMX0VWRU5UX1RZUEVTOiBSZWFkb25seVNldDxFdmVudFsnZXZlbnRUeXBlJ10+ID0gbmV3IFNldChbXG4gICdydW5fY29tcGxldGVkJyxcbiAgJ3J1bl9mYWlsZWQnLFxuICAncnVuX2NhbmNlbGxlZCcsXG5dKTtcblxuZXhwb3J0IGVudW0gRXZlbnRDb25zdW1lclJlc3VsdCB7XG4gIC8qKlxuICAgKiBDYWxsYmFjayBjb25zdW1lZCB0aGUgZXZlbnQsIGJ1dCBzaG91bGQgbm90IGJlIHJlbW92ZWQgZnJvbSB0aGUgY2FsbGJhY2tzIGxpc3RcbiAgICovXG4gIENvbnN1bWVkLFxuICAvKipcbiAgICogQ2FsbGJhY2sgZGlkIG5vdCBjb25zdW1lIHRoZSBldmVudCwgc28gaXQgc2hvdWxkIGJlIHBhc3NlZCB0byB0aGUgbmV4dCBjYWxsYmFja1xuICAgKi9cbiAgTm90Q29uc3VtZWQsXG4gIC8qKlxuICAgKiBDYWxsYmFjayBjb25zdW1lZCB0aGUgZXZlbnQsIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCBmcm9tIHRoZSBjYWxsYmFja3MgbGlzdFxuICAgKi9cbiAgRmluaXNoZWQsXG59XG5cbnR5cGUgRXZlbnRDb25zdW1lckNhbGxiYWNrID0gKGV2ZW50OiBFdmVudCB8IG51bGwpID0+IEV2ZW50Q29uc3VtZXJSZXN1bHQ7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRzQ29uc3VtZXJPcHRpb25zIHtcbiAgLyoqXG4gICAqIENhbGxiYWNrIGludm9rZWQgYWZ0ZXIgYW4gZXZlbnQgaGFzIGJlZW4gY29uc3VtZWQuIENvbnN1bWVycyBzdWNoIGFzIHRoZVxuICAgKiBkZXRlcm1pbmlzdGljIHdvcmtmbG93IGNsb2NrIG11c3Qgbm90IG9ic2VydmUgZXZlbnRzIHRoYXQgYXJlIG1lcmVseVxuICAgKiBpbnNwZWN0ZWQgd2hpbGUgd2FpdGluZyBmb3IgdXNlciBjb2RlIHRvIHN1YnNjcmliZSB0byB0aGUgbmV4dCBvcGVyYXRpb24uXG4gICAqL1xuICBvbkNvbnN1bWVkRXZlbnQ/OiAoZXZlbnQ6IEV2ZW50KSA9PiB2b2lkO1xuICAvKipcbiAgICogQ2FsbGJhY2sgaW52b2tlZCB3aGVuIGEgbm9uLW51bGwgZXZlbnQgY2Fubm90IGJlIGNvbnN1bWVkIGJ5IGFueSByZWdpc3RlcmVkXG4gICAqIGNhbGxiYWNrLCBpbmRpY2F0aW5nIGFuIG9ycGhhbmVkIG9yIGludmFsaWQgZXZlbnQgaW4gdGhlIGV2ZW50IGxvZy4gVGhlXG4gICAqIGNoZWNrIGlzIGRlZmVycmVkIHVudGlsIGFmdGVyIHRoZSBwcm9taXNlIHF1ZXVlIGhhcyBkcmFpbmVkLCBlbnN1cmluZyB0aGF0XG4gICAqIGFueSBwZW5kaW5nIGFzeW5jIHdvcmsgKGUuZy4sIGRlc2VyaWFsaXphdGlvbi9kZWNyeXB0aW9uKSBjb21wbGV0ZXMgYW5kXG4gICAqIGRvd25zdHJlYW0gc3Vic2NyaWJlKCkgY2FsbHMgaGF2ZSBhIGNoYW5jZSB0byBjYW5jZWwgdGhlIGNoZWNrIGZpcnN0LlxuICAgKi9cbiAgb25VbmNvbnN1bWVkRXZlbnQ6IChldmVudDogRXZlbnQpID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBDYWxsYmFjayBpbnZva2VkIHdoZW4gYW4gZXZlbnQgaXMgc2tpcHBlZCBiZWNhdXNlIGl0IHJlcGVhdHMgYW4gZXZlbnRcbiAgICogY2xhc3MgdGhlIHdhbGsgYWxyZWFkeSBjb25zdW1lZCBmb3IgdGhlIHNhbWUgZW50aXR5LiBgZmlyc3RFdmVudFR5cGVgIGlzXG4gICAqIHRoZSB0eXBlIHRoYXQgcmVjb3JkZWQgdGhlIGNsYXNzLCB3aGljaCBpcyB0aGUgb25lIHRoZSB3b3JrZmxvdyBvYnNlcnZlZC5cbiAgICogRGlhZ25vc3RpY3Mgb25seTogc2tpcHBpbmcgaXMgYSBub3JtYWwgb3V0Y29tZSwgbm90IGFuIGVycm9yLCB0aG91Z2ggYVxuICAgKiBgZmlyc3RFdmVudFR5cGVgIGRpZmZlcmluZyBmcm9tIGBldmVudC5ldmVudFR5cGVgIHNheXMgdGhlIHR3byB3cml0ZXJzXG4gICAqIGRlY2lkZWQgdGhlIGVudGl0eSdzIG91dGNvbWUgZGlmZmVyZW50bHksIHdoaWNoIGlzIHdvcnRoIG1vcmUgdGhhbiBhblxuICAgKiBpbmZvIGxvZy5cbiAgICovXG4gIG9uRHVwbGljYXRlRXZlbnQ/OiAoZXZlbnQ6IEV2ZW50LCBmaXJzdEV2ZW50VHlwZTogRXZlbnRbJ2V2ZW50VHlwZSddKSA9PiB2b2lkO1xuICAvKipcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCBwcm9taXNlIHF1ZXVlLiBUaGUgdW5jb25zdW1lZCBldmVudCBjaGVjayBpcyBjaGFpbmVkXG4gICAqIG9udG8gdGhpcyBxdWV1ZSBzbyBpdCBvbmx5IGZpcmVzIGFmdGVyIGFsbCBwZW5kaW5nIGFzeW5jIHdvcmsgKGUuZy4sXG4gICAqIGRlc2VyaWFsaXphdGlvbikgaGFzIGNvbXBsZXRlZC4gVGhpcyBwcmV2ZW50cyBmYWxzZSBwb3NpdGl2ZXMgd2hlbiBhc3luY1xuICAgKiBkZXNlcmlhbGl6YXRpb24gZGVsYXlzIHRoZSByZXNvbHZlKCkgdGhhdCB0cmlnZ2VycyB0aGUgbmV4dCBzdWJzY3JpYmUoKS5cbiAgICovXG4gIGdldFByb21pc2VRdWV1ZTogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqXG4gICAqIFdoZXRoZXIgbm8gZGF0YSBkZWxpdmVyeSBpcyBpbiBmbGlnaHQgKGBpc0RlbGl2ZXJ5SWRsZWAgaW4gcHJpdmF0ZS50cykuXG4gICAqIFRoZSB1bmNvbnN1bWVkLWV2ZW50IGNoZWNrIHdhaXRzIGZvciB0aGlzIGJlZm9yZSBpdCBmaXJlczogYSBkZWxpdmVyeSBpblxuICAgKiBmbGlnaHQgbWVhbnMgdGhlIHdvcmtmbG93IFZNIGlzIG1pZC1yZWFjdGlvbiwgYW5kIGFuIGV2ZW50IGl0IGhhcyBub3RcbiAgICogY2xhaW1lZCB5ZXQgaXMgYW4gZXZlbnQgaXQgaGFzIG5vdCByZWFjaGVkIHlldC5cbiAgICpcbiAgICogUmVxdWlyZWQgcmF0aGVyIHRoYW4gZGVmYXVsdGluZyB0byBhbHdheXMtaWRsZTogYWx3YXlzLWlkbGUgaXMgZXhhY3RseSB0aGVcbiAgICogcHJlLWdhdGUgYmVoYXZpb3IsIHNvIGEgZGVmYXVsdGVkIG9wdGlvbiB3b3VsZCBsZXQgYSBjb25zdHJ1Y3Rpb24gc2l0ZSBvcHRcbiAgICogYSB3aG9sZSByZXBsYXkgcGF0aCBiYWNrIG91dCB3aXRob3V0IHNheWluZyBzby4gVGVzdHMgdGhhdCBkcml2ZSBhIGNvbnN1bWVyXG4gICAqIHdpdGggbm8gb3JjaGVzdHJhdG9yIGNvbnRleHQgcGFzcyBgKCkgPT4gdHJ1ZWAgdG8ga2VlcCB0aGUgcHJlLWV4aXN0aW5nXG4gICAqIHRpbWluZywgYW5kIHNheSBzbyBhdCB0aGUgY2FsbCBzaXRlLlxuICAgKi9cbiAgaXNEZWxpdmVyeUlkbGU6ICgpID0+IGJvb2xlYW47XG59XG5cbi8qKiBTZWUge0BsaW5rIEV2ZW50c0NvbnN1bWVyLmRlc2NyaWJlfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRzQ29uc3VtZXJTbmFwc2hvdCB7XG4gIGluZGV4OiBudW1iZXI7XG4gIGxlbmd0aDogbnVtYmVyO1xuICBwYXJrZWQ6IG51bWJlcjtcbiAgbGFzdENvbnN1bWVkRXZlbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgY2xhc3MgRXZlbnRzQ29uc3VtZXIge1xuICBldmVudEluZGV4OiBudW1iZXI7XG4gIHJlYWRvbmx5IGV2ZW50czogRXZlbnRbXTtcbiAgcmVhZG9ubHkgY2FsbGJhY2tzOiBFdmVudENvbnN1bWVyQ2FsbGJhY2tbXSA9IFtdO1xuICAvKipcbiAgICogRXZlbnRzIHRoZSBvcmRlcmVkIHdhbGsgc3RlcHBlZCBvdmVyIGJlY2F1c2Ugbm9ib2R5IGNsYWltZWQgdGhlbSBhbmQgdGhlaXJcbiAgICogdHlwZSBjYXJyaWVzIG5vIG9yZGVyaW5nIGNsYWltLiBFYWNoIGtlZXBzIHRoZSBpbmRleCBpdCBoZWxkIGluIHRoZSBsb2c6XG4gICAqIGNvbnN1bWVycyByZWFkIHtAbGluayBldmVudEluZGV4fSBhdCBjb25zdW1wdGlvbiB0aW1lIHRvIG9yZGVyIHRoZWlyXG4gICAqIGRlbGl2ZXJ5IGFnYWluc3QgdGhlIHJlc3Qgb2YgdGhlIGxvZywgYW5kIGEgbGF0ZSBkZWxpdmVyeSBtdXN0IHN0aWxsIG1ha2VcbiAgICogdGhlIGNsYWltIGl0cyBwb3NpdGlvbiBnYXZlIGl0LlxuICAgKlxuICAgKiBIZWxkIGluIGxvZyBvcmRlciwgZHJhaW5lZCBpbiBsb2cgb3JkZXIsIGFuZCBkcmFpbmVkIGJlZm9yZSBldmVyeSBvZmZlciBzb1xuICAgKiBhIGNvbnN1bWVyIHJlZ2lzdGVyZWQgYWZ0ZXIgdGhlIHdhbGsgcGFzc2VkIHRoZSBldmVudCBzdGlsbCByZWNlaXZlcyBpdC5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcGFya2VkOiB7IGV2ZW50OiBFdmVudDsgaW5kZXg6IG51bWJlciB9W10gPSBbXTtcbiAgLyoqXG4gICAqIENvcnJlbGF0aW9uIGlkcyBvZiB0aGUge0BsaW5rIE9ORV9TSE9UX0VWRU5UX1RZUEVTfSBldmVudHMgY29uc3VtZWQgc29cbiAgICogZmFyLCBzbyBhIHNlY29uZCByZXNvbHV0aW9uIGZvciBvbmUgb2YgdGhlbSBpcyByZWNvZ25pemVkIGFzIHVuY2xhaW1hYmxlXG4gICAqIHJhdGhlciB0aGFuIHBhcmtlZCBmb3IgYSBjb25zdW1lciB0aGF0IGNhbm5vdCBleGlzdC5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVzb2x2ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgLyoqXG4gICAqIGA8Y2xhc3M+Ojxjb3JyZWxhdGlvbklkPmAgZm9yIGV2ZXJ5IGV2ZW50IGNsYXNzIHRoZSB3YWxrIGhhcyBhbHJlYWR5XG4gICAqIGNvbnN1bWVkLCBtYXBwZWQgdG8gdGhlIGV2ZW50IHR5cGUgdGhhdCByZWNvcmRlZCBpdC4gVGhlIHR5cGUgaXMga2VwdCBzbyBhXG4gICAqIHJlcGVhdCB0aGF0IGRlY2lkZWQgdGhlIHNhbWUgY2xhc3MgKmRpZmZlcmVudGx5KiAoYSBgc3RlcF9mYWlsZWRgIGJlaGluZCBhXG4gICAqIGBzdGVwX2NvbXBsZXRlZGApIGNhbiBiZSByZXBvcnRlZCBhcyBtb3JlIHRoYW4gYSByZS1jb21taXQuIFNlZVxuICAgKiB7QGxpbmsgRXZlbnRzQ29uc3VtZXIuZmlyc3RFdmVudFR5cGVPZkNsYXNzfS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc2VlbkV2ZW50Q2xhc3NlcyA9IG5ldyBNYXA8c3RyaW5nLCBFdmVudFsnZXZlbnRUeXBlJ10+KCk7XG4gIHByaXZhdGUgb25Db25zdW1lZEV2ZW50PzogKGV2ZW50OiBFdmVudCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBvblVuY29uc3VtZWRFdmVudDogKGV2ZW50OiBFdmVudCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBvbkR1cGxpY2F0ZUV2ZW50PzogKFxuICAgIGV2ZW50OiBFdmVudCxcbiAgICBmaXJzdFR5cGU6IEV2ZW50WydldmVudFR5cGUnXVxuICApID0+IHZvaWQ7XG4gIHByaXZhdGUgZ2V0UHJvbWlzZVF1ZXVlOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBwcml2YXRlIGlzRGVsaXZlcnlJZGxlOiAoKSA9PiBib29sZWFuO1xuICBwcml2YXRlIHBlbmRpbmdVbmNvbnN1bWVkQ2hlY2s6IFByb21pc2U8dm9pZD4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBwZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgdW5jb25zdW1lZENoZWNrVmVyc2lvbiA9IDA7XG4gIC8qKlxuICAgKiBUaGUgZXZlbnQgYSBjYWxsYmFjayBtb3N0IHJlY2VudGx5IGNsYWltZWQsIGZvciB7QGxpbmsgZGVzY3JpYmV9LiBUcmFja2VkXG4gICAqIHNlcGFyYXRlbHkgZnJvbSB7QGxpbmsgZXZlbnRJbmRleH0gYmVjYXVzZSB0aGUgd2FsayBhbHNvIHN0ZXBzIG92ZXIgZXZlbnRzXG4gICAqIChwYXJrZWQsIHNlYWxlZCBuby1vcHMsIGR1cGxpY2F0ZXMpIHdpdGhvdXQgYW55b25lIGNvbnN1bWluZyB0aGVtLCBzb1xuICAgKiBgZXZlbnRzW2V2ZW50SW5kZXggLSAxXWAgZG9lcyBub3Qgc2F5IHdoYXQgcmVwbGF5IGxhc3QgYWN0ZWQgb24uXG4gICAqL1xuICBwcml2YXRlIGxhc3RDb25zdW1lZDogRXZlbnQgfCB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3IoZXZlbnRzOiBFdmVudFtdLCBvcHRpb25zOiBFdmVudHNDb25zdW1lck9wdGlvbnMpIHtcbiAgICAvLyBPd24gY29weTogdGhlIHJ1bnRpbWUgbXV0YXRlcyBpdHMgZXZlbnQgYXJyYXkgaW4gcGxhY2UsIGFuZCBhIHJldGFpbmVkXG4gICAgLy8gc2Vzc2lvbiBtdXN0IG9ubHkgb2JzZXJ2ZSBuZXcgZXZlbnRzIHRocm91Z2ggYXBwZW5kKCkgc28gcmVzdW1lKCknc1xuICAgIC8vIHN0cmljdC1leHRlbnNpb24gY2hlY2sgc3RheXMgbWVhbmluZ2Z1bC5cbiAgICB0aGlzLmV2ZW50cyA9IFsuLi5ldmVudHNdO1xuICAgIHRoaXMuZXZlbnRJbmRleCA9IDA7XG4gICAgdGhpcy5vbkNvbnN1bWVkRXZlbnQgPSBvcHRpb25zLm9uQ29uc3VtZWRFdmVudDtcbiAgICB0aGlzLm9uVW5jb25zdW1lZEV2ZW50ID0gb3B0aW9ucy5vblVuY29uc3VtZWRFdmVudDtcbiAgICB0aGlzLm9uRHVwbGljYXRlRXZlbnQgPSBvcHRpb25zLm9uRHVwbGljYXRlRXZlbnQ7XG4gICAgdGhpcy5nZXRQcm9taXNlUXVldWUgPSBvcHRpb25zLmdldFByb21pc2VRdWV1ZTtcbiAgICB0aGlzLmlzRGVsaXZlcnlJZGxlID0gb3B0aW9ucy5pc0RlbGl2ZXJ5SWRsZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgb2xkZXN0IGV2ZW50IHRoZSB3YWxrIHN0ZXBwZWQgb3ZlciB0aGF0IG5vIGNvbnN1bWVyIGhhcyBjbGFpbWVkIHlldCxcbiAgICogaWYgYW55LiBQYXJraW5nIGlzIGEgYmV0IHRoYXQgYSBjb25zdW1lciB3aWxsIGJlIHJlZ2lzdGVyZWQgbGF0ZXIsIHNvIGF0XG4gICAqIGFueSBwb2ludCB3aGVyZSBubyBjb25zdW1lciBldmVyIHdpbGwgYmUgYWdhaW4gKHRoZSByZXBsYXkgZmluaXNoaW5nIGlzXG4gICAqIHRoZSBkZWZpbml0aXZlIG9uZSksIHRoaXMgYW5zd2VycyB3aGljaCBldmVudCB0aGUgYmV0IGxvc3Qgb24uXG4gICAqL1xuICBnZXQgc3RyYW5kZWRFdmVudCgpOiBFdmVudCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucGFya2VkWzBdPy5ldmVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGF0IHRoZSB3YWxrIGlzIHN0aWxsIGhvbGRpbmcsIG9yIGB1bmRlZmluZWRgIHdoZW4gaXQgaG9sZHMgbm90aGluZy5cbiAgICpcbiAgICogUmVhZCBhdCBldmVyeSBwb2ludCBhIHJlcGxheSBzdG9wcywgaW5jbHVkaW5nIHRoZSBzdXNwZW5zaW9ucyB0aGF0IGFyZSBub3RcbiAgICogc2V0dGxpbmcgcG9pbnRzLCBzbyB0aGUgaGVsZCBzdGF0ZSByZWFjaGVzIHRlbGVtZXRyeS4gQSByZXBsYXkgY2Fubm90IHRlbGxcbiAgICogYSBkZWxpdmVyeSBhd2FpdGluZyBhIGxhdGVyIGNvbnN1bWVyIGZyb20gb25lIG5vIGNvbnN1bWVyIHdpbGwgZXZlclxuICAgKiByZWdpc3Rlciwgc28gaXQgcmVwb3J0cyByYXRoZXIgdGhhbiBkZWNpZGVzOiB0aGUgc2FtZSBgZXZlbnRJZGAgcmVwb3J0ZWQgb25cbiAgICogc3VzcGVuc2lvbiBhZnRlciBzdXNwZW5zaW9uIG9mIG9uZSBydW4gaXMgdGhlIHNoYXBlIHRoYXQgc2F5cyB0aGUgYmV0XG4gICAqIHBhcmtpbmcgbWFkZSBpcyBub3QgZ29pbmcgdG8gcGF5IG9mZiwgYW5kIHRoYXQgc2hhcGUgaXMgb25seSB2aXNpYmxlIGFjcm9zc1xuICAgKiByZXBsYXlzLlxuICAgKi9cbiAgZ2V0IHBhcmtlZFN1bW1hcnkoKTpcbiAgICB8IHsgY291bnQ6IG51bWJlcjsgZXZlbnRJZDogc3RyaW5nOyBldmVudFR5cGU6IEV2ZW50WydldmVudFR5cGUnXSB9XG4gICAgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IG9sZGVzdCA9IHRoaXMucGFya2VkWzBdPy5ldmVudDtcbiAgICBpZiAoIW9sZGVzdCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvdW50OiB0aGlzLnBhcmtlZC5sZW5ndGgsXG4gICAgICBldmVudElkOiBvbGRlc3QuZXZlbnRJZCxcbiAgICAgIGV2ZW50VHlwZTogb2xkZXN0LmV2ZW50VHlwZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXJlIHRoZSB3YWxrIHN0YW5kcywgZm9yIGEgZGl2ZXJnZW5jZSBtZXNzYWdlLiBFdmVyeXRoaW5nIGhlcmUgaXNcbiAgICogYWxyZWFkeSBrbm93biB0byB0aGUgY29uc3VtZXI7IHRoZSBwb2ludCBvZiB0aGUgbWV0aG9kIGlzIHRoYXQgdGhlXG4gICAqIG9yY2hlc3RyYXRvciBjYW4gcHJpbnQgaXQgd2l0aG91dCByZWFjaGluZyBpbnRvIHByaXZhdGUgc3RhdGUuXG4gICAqXG4gICAqIGBpbmRleGAgaXMgdGhlIG9yZGVyZWQgd2FsaydzIHBvc2l0aW9uICh0aGUgb2Zmc2V0IG9mIHRoZSBldmVudCBpdCBpc1xuICAgKiBzdHVjayBvbiwgd2hlbiBpdCBpcyBzdHVjayksIGBsZW5ndGhgIHRoZSBsb2cgYXMgdGhpcyBjb25zdW1lciBob2xkcyBpdCxcbiAgICogYHBhcmtlZGAgaG93IG1hbnkgZXZlbnRzIHRoZSB3YWxrIHN0ZXBwZWQgb3ZlciBhbmQgc3RpbGwgaG9sZHMsIGFuZFxuICAgKiBgbGFzdENvbnN1bWVkRXZlbnRJZGAgdGhlIGlkIG9mIHRoZSBldmVudCBhIGNhbGxiYWNrIG1vc3QgcmVjZW50bHlcbiAgICogY2xhaW1lZCwgYHVuZGVmaW5lZGAgYmVmb3JlIHRoZSBmaXJzdCBjbGFpbS5cbiAgICovXG4gIGRlc2NyaWJlKCk6IEV2ZW50c0NvbnN1bWVyU25hcHNob3Qge1xuICAgIHJldHVybiB7XG4gICAgICBpbmRleDogdGhpcy5ldmVudEluZGV4LFxuICAgICAgbGVuZ3RoOiB0aGlzLmV2ZW50cy5sZW5ndGgsXG4gICAgICBwYXJrZWQ6IHRoaXMucGFya2VkLmxlbmd0aCxcbiAgICAgIGxhc3RDb25zdW1lZEV2ZW50SWQ6IHRoaXMubGFzdENvbnN1bWVkPy5ldmVudElkLFxuICAgIH07XG4gIH1cblxuICBhcHBlbmQoZXZlbnRzOiBFdmVudFtdKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHRoaXMuZXZlbnRzLnB1c2goZXZlbnQpO1xuICAgIHByb2Nlc3MubmV4dFRpY2sodGhpcy5jb25zdW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlcnMgYSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgYW4gZXZlbnQgaGFzIGJlZW4gY29uc3VtZWRcbiAgICogYnkgYSBkaWZmZXJlbnQgY2FsbGJhY2suIFRoZSBjYWxsYmFjayBjYW4gcmV0dXJuOlxuICAgKiAgLSBgRXZlbnRDb25zdW1lclJlc3VsdC5Db25zdW1lZGAgdGhlIGV2ZW50IGlzIGNvbnNpZGVyZWQgY29uc3VtZWQgYW5kIHdpbGwgbm90IGJlIHBhc3NlZCB0byBhbnkgb3RoZXIgY2FsbGJhY2ssIGJ1dCB0aGUgY2FsbGJhY2sgd2lsbCByZW1haW4gaW4gdGhlIGNhbGxiYWNrcyBsaXN0XG4gICAqICAtIGBFdmVudENvbnN1bWVyUmVzdWx0Lk5vdENvbnN1bWVkYCB0aGUgZXZlbnQgaXMgcGFzc2VkIHRvIHRoZSBuZXh0IGNhbGxiYWNrXG4gICAqICAtIGBFdmVudENvbnN1bWVyUmVzdWx0LkZpbmlzaGVkYCB0aGUgZXZlbnQgaXMgY29uc2lkZXJlZCBjb25zdW1lZCBhbmQgdGhlIGNhbGxiYWNrIGlzIHJlbW92ZWQgZnJvbSB0aGUgY2FsbGJhY2tzIGxpc3RcbiAgICpcbiAgICogQHBhcmFtIGZuIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIHJlZ2lzdGVyLlxuICAgKi9cbiAgc3Vic2NyaWJlKGZuOiBFdmVudENvbnN1bWVyQ2FsbGJhY2spIHtcbiAgICB0aGlzLmNhbGxiYWNrcy5wdXNoKGZuKTtcbiAgICAvLyBDYW5jZWwgYW55IHBlbmRpbmcgdW5jb25zdW1lZCBjaGVjayBzaW5jZSBhIG5ldyBjYWxsYmFjayBtYXkgY29uc3VtZSB0aGUgZXZlbnQuXG4gICAgLy8gSW5jcmVtZW50aW5nIHRoZSB2ZXJzaW9uIGNhdXNlcyBhbnkgaW4tZmxpZ2h0IHByb21pc2UgY2hhaW4gY2hlY2sgdG8gbm8tb3AuXG4gICAgLy8gQWxzbyBjbGVhciB0aGUgcGVuZGluZyBzZXRUaW1lb3V0IGlmIGl0IGhhc24ndCBmaXJlZCB5ZXQuXG4gICAgaWYgKHRoaXMucGVuZGluZ1VuY29uc3VtZWRDaGVjayAhPT0gbnVsbCkge1xuICAgICAgdGhpcy51bmNvbnN1bWVkQ2hlY2tWZXJzaW9uKys7XG4gICAgICB0aGlzLnBlbmRpbmdVbmNvbnN1bWVkQ2hlY2sgPSBudWxsO1xuICAgICAgaWYgKHRoaXMucGVuZGluZ1VuY29uc3VtZWRUaW1lb3V0ICE9PSBudWxsKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnBlbmRpbmdVbmNvbnN1bWVkVGltZW91dCk7XG4gICAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRUaW1lb3V0ID0gbnVsbDtcbiAgICAgIH1cbiAgICB9XG4gICAgcHJvY2Vzcy5uZXh0VGljayh0aGlzLmNvbnN1bWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBub3RpZnlDb25zdW1lZEV2ZW50KGV2ZW50OiBFdmVudCkge1xuICAgIGlmICghdGhpcy5vbkNvbnN1bWVkRXZlbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMub25Db25zdW1lZEV2ZW50KGV2ZW50KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXZlbnRzTG9nZ2VyLmVycm9yKCdvbkNvbnN1bWVkRXZlbnQgY2FsbGJhY2sgdGhyZXcgYW4gZXJyb3InLCB7XG4gICAgICAgIGVycm9yLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjb25zdW1lID0gKCkgPT4ge1xuICAgIC8vIERyYWluIGNvbnNlY3V0aXZlbHkgY29uc3VtYWJsZSBldmVudHMgc3luY2hyb25vdXNseSB3aXRoaW4gYSBzaW5nbGVcbiAgICAvLyBwYXNzIGluc3RlYWQgb2YgcGF5aW5nIG9uZSBgcHJvY2Vzcy5uZXh0VGlja2AgcGVyIGNvbnN1bWVkIGV2ZW50LlxuICAgIC8vXG4gICAgLy8gV2h5IHRoaXMgaXMgc2FmZTogYSBjYWxsYmFjayBvbmx5IGNvbnN1bWVzIGFuIGV2ZW50IHVzaW5nIGEgY29uc3VtZXJcbiAgICAvLyB0aGF0IGlzIEFMUkVBRFkgcmVnaXN0ZXJlZCAoZS5nLiBhIGxvbmctbGl2ZWQgc3RlcCBjb25zdW1lciB3YWxraW5nXG4gICAgLy8gYHN0ZXBfY3JlYXRlZGAg4oaSIGBzdGVwX3N0YXJ0ZWRgIOKGkiBgc3RlcF9jb21wbGV0ZWRgLCBvciB0aGUgc3RydWN0dXJhbFxuICAgIC8vIGxpZmVjeWNsZSBjb25zdW1lcikuIE5ldyBjb25zdW1lcnMgYXJlIG9ubHkgZXZlciByZWdpc3RlcmVkIGJ5IHdvcmtmbG93XG4gICAgLy8gVk0gYm9keSBjb2RlIHRoYXQgcnVucyBhc3luY2hyb25vdXNseSBvZmYgYGN0eC5wcm9taXNlUXVldWVgIGFmdGVyIGFcbiAgICAvLyBkZWxpdmVyeSBgcmVzb2x2ZSgpYDsgbm9uZSBvZiB0aGUgY2FsbGJhY2tzIGhlcmUgY2FsbCBgc3Vic2NyaWJlKClgXG4gICAgLy8gc3luY2hyb25vdXNseS4gU28gd2l0aGluIG9uZSBwYXNzIGB0aGlzLmNhbGxiYWNrc2AgaXMgbXV0YXRlZCBvbmx5IGJ5XG4gICAgLy8gdGhpcyBsb29wICh0aGUgYEZpbmlzaGVkYCBzcGxpY2UpLCBhbmQgdGhlIG5leHQgZXZlbnQncyBjb25zdW1lciBpc1xuICAgIC8vIGVpdGhlciBhbHJlYWR5IHByZXNlbnQgKGFkdmFuY2Ugbm93KSBvciBub3QgeWV0IHJlZ2lzdGVyZWQsIGluIHdoaWNoXG4gICAgLy8gY2FzZSBubyBjYWxsYmFjayBjb25zdW1lcyB0aGUgZXZlbnQgYW5kIHdlIGZhbGwgdGhyb3VnaCB0byB0aGVcbiAgICAvLyBjcm9zcy1WTS1zYWZlIGRlZmVycmVkIHVuY29uc3VtZWQtZXZlbnQgY2hlY2sgYmVsb3csIGV4YWN0bHkgYXMgYmVmb3JlLlxuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAvLyBCZWZvcmUgZXZlcnkgb2ZmZXIsIG5vdCBqdXN0IG9uIHN1YnNjcmliZTogYSBjYWxsYmFjayByZWdpc3RlcmVkIGJ5XG4gICAgICAvLyB0aGUgd29yayB0aGlzIHNhbWUgcGFzcyBraWNrZWQgb2ZmIG1heSBiZSB0aGUgb3duZXIgb2Ygc29tZXRoaW5nXG4gICAgICAvLyBwYXJrZWQsIGFuZCB0aGUgcGFya2VkIGV2ZW50J3MgZGVsaXZlcnkgaXMgb3JkZXJlZCBhaGVhZCBvZiB0aGUgaGVhZFxuICAgICAgLy8gZXZlbnQncyBieSB0aGUgaW5kZXggaXQgaG9sZHMuXG4gICAgICB0aGlzLmRyYWluUGFya2VkKCk7XG4gICAgICBjb25zdCBjdXJyZW50RXZlbnQgPSB0aGlzLmV2ZW50c1t0aGlzLmV2ZW50SW5kZXhdID8/IG51bGw7XG4gICAgICBpZiAoY3VycmVudEV2ZW50ICE9PSBudWxsICYmIGlzU2VhbGVkTm9vcEV2ZW50KGN1cnJlbnRFdmVudCkpIHtcbiAgICAgICAgdGhpcy5za2lwU2VhbGVkTm9vcChjdXJyZW50RXZlbnQpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNvbnN1bWVkID0gdGhpcy5vZmZlcihjdXJyZW50RXZlbnQpO1xuICAgICAgaWYgKGNvbnN1bWVkKSB7XG4gICAgICAgIHRoaXMuZXZlbnRJbmRleCsrO1xuICAgICAgfVxuICAgICAgaWYgKGN1cnJlbnRFdmVudCA9PT0gbnVsbCkge1xuICAgICAgICAvLyBFbmQgb2YgbG9nLiBDb25zdW1lcnMgcmV0dXJuIE5vdENvbnN1bWVkIGZvciB0aGUgYG51bGxgIHNlbnRpbmVsXG4gICAgICAgIC8vICh0aGUgb25lIHRoYXQgcmVjb2duaXplcyBpdCBhcyBpdHMgb3duIGJvdW5kYXJ5IHNjaGVkdWxlcyB0aGVcbiAgICAgICAgLy8gc3VzcGVuc2lvbiBhcyBhIHNpZGUgZWZmZWN0IGFuZCBzdGlsbCBkZWNsaW5lcyBpdCksIHNvIHRoZSBkcmFpblxuICAgICAgICAvLyBzdG9wcyBoZXJlIHJhdGhlciB0aGFuIHNwaW5uaW5nIHBhc3QgdGhlIGVuZC4gYGNvbnN1bWVkYCBpcyBvbmx5XG4gICAgICAgIC8vIHRydWUgZm9yIGEgY2FsbGJhY2sgdGhhdCBjbGFpbXMgdGhlIHNlbnRpbmVsIG91dHJpZ2h0LCB3aGljaCBub1xuICAgICAgICAvLyBwcm9kdWN0aW9uIGNvbnN1bWVyIGRvZXMuXG4gICAgICAgIGlmICghY29uc3VtZWQpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVuZE9mTG9nKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKCFjb25zdW1lZCkge1xuICAgICAgICAvLyBOb2JvZHkgd2FudGVkIGl0LiBJZiBpdCByZXBlYXRzIGEgY2xhc3MgdGhpcyB3YWxrIGFscmVhZHkgY29uc3VtZWRcbiAgICAgICAgLy8gZm9yIHRoZSBzYW1lIGVudGl0eSBpdCBpcyBhIHN0cmFnZ2xlciBmcm9tIGEgY29uY3VycmVudCByZXBsYXk6XG4gICAgICAgIC8vIHN0ZXAgb3ZlciBpdCBpbiB0aGlzIHBhc3MgcmF0aGVyIHRoYW4gcGF5aW5nIHRoZSBkZWZlcnJlZCB3aW5kb3cgZm9yXG4gICAgICAgIC8vIGEgY29uc3VtZXIgdGhhdCBjYW5ub3QgY29tZSAoc2VlIGBmaXJzdEV2ZW50VHlwZU9mQ2xhc3NgKS5cbiAgICAgICAgY29uc3QgZmlyc3RUeXBlID0gdGhpcy5maXJzdEV2ZW50VHlwZU9mQ2xhc3MoY3VycmVudEV2ZW50KTtcbiAgICAgICAgaWYgKGZpcnN0VHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgdGhpcy5za2lwRHVwbGljYXRlRXZlbnQoY3VycmVudEV2ZW50LCBmaXJzdFR5cGUpO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2NoZWR1bGVVbmNvbnN1bWVkQ2hlY2soY3VycmVudEV2ZW50LCB0cnVlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgLy8gQSByZWFsIGV2ZW50IHdhcyBjb25zdW1lZCwgc28gYWR2YW5jZSB0byB0aGUgbmV4dCBpbiB0aGUgc2FtZSBwYXNzLlxuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogT2ZmZXIgYGN1cnJlbnRFdmVudGAgdG8gZWFjaCByZWdpc3RlcmVkIGNhbGxiYWNrIGluIHR1cm4uIFJldHVybnMgdHJ1ZVxuICAgKiB3aGVuIGEgY2FsbGJhY2sgY29uc3VtZWQgaXQuIERvZXMgbm90IG1vdmUge0BsaW5rIGV2ZW50SW5kZXh9OiB0aGUgb3JkZXJlZFxuICAgKiB3YWxrIGFuZCB0aGUgcGFya2VkIGRyYWluIGFkdmFuY2UgZGlmZmVyZW50bHksIHNvIGVhY2ggZG9lcyBpdHMgb3duLlxuICAgKi9cbiAgcHJpdmF0ZSBvZmZlcihjdXJyZW50RXZlbnQ6IEV2ZW50IHwgbnVsbCk6IGJvb2xlYW4ge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5jYWxsYmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNhbGxiYWNrID0gdGhpcy5jYWxsYmFja3NbaV07XG4gICAgICBsZXQgaGFuZGxlZCA9IEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBoYW5kbGVkID0gY2FsbGJhY2soY3VycmVudEV2ZW50KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGV2ZW50c0xvZ2dlci5lcnJvcignRXZlbnRDb25zdW1lciBjYWxsYmFjayB0aHJldyBhbiBlcnJvcicsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIGhhbmRsZWQgIT09IEV2ZW50Q29uc3VtZXJSZXN1bHQuQ29uc3VtZWQgJiZcbiAgICAgICAgaGFuZGxlZCAhPT0gRXZlbnRDb25zdW1lclJlc3VsdC5GaW5pc2hlZFxuICAgICAgKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKGN1cnJlbnRFdmVudCAhPT0gbnVsbCkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgY3VycmVudEV2ZW50LmNvcnJlbGF0aW9uSWQgJiZcbiAgICAgICAgICBPTkVfU0hPVF9FVkVOVF9UWVBFUy5oYXMoY3VycmVudEV2ZW50LmV2ZW50VHlwZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhpcy5yZXNvbHZlZC5hZGQoXG4gICAgICAgICAgICByZXNvbHV0aW9uS2V5KGN1cnJlbnRFdmVudC5ldmVudFR5cGUsIGN1cnJlbnRFdmVudC5jb3JyZWxhdGlvbklkKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZWNvcmRFdmVudENsYXNzKGN1cnJlbnRFdmVudCk7XG4gICAgICAgIHRoaXMubGFzdENvbnN1bWVkID0gY3VycmVudEV2ZW50O1xuICAgICAgICB0aGlzLm5vdGlmeUNvbnN1bWVkRXZlbnQoY3VycmVudEV2ZW50KTtcbiAgICAgIH1cbiAgICAgIC8vIHJlbW92ZSB0aGUgY2FsbGJhY2sgaWYgaXQgaGFzIGZpbmlzaGVkXG4gICAgICBpZiAoaGFuZGxlZCA9PT0gRXZlbnRDb25zdW1lclJlc3VsdC5GaW5pc2hlZCkge1xuICAgICAgICB0aGlzLmNhbGxiYWNrcy5zcGxpY2UoaSwgMSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIE9mZmVyIGV2ZXJ5dGhpbmcgcGFya2VkLCBvbGRlc3QgZmlyc3QsIHVudGlsIGEgcGFzcyBjbGFpbXMgbm90aGluZy5cbiAgICpcbiAgICogRWFjaCBvZmZlciBydW5zIHdpdGgge0BsaW5rIGV2ZW50SW5kZXh9IG1vdmVkIGJhY2sgdG8gdGhlIHBvc2l0aW9uIHRoZVxuICAgKiBwYXJrZWQgZXZlbnQgaGVsZCBpbiB0aGUgbG9nLCBiZWNhdXNlIHRoYXQgaXMgdGhlIHBvc2l0aW9uIGl0cyBjb25zdW1lclxuICAgKiB3aWxsIHJlZ2lzdGVyIGEgZGVsaXZlcnkgYmFycmllciB1bmRlci4gUmVzdG9yaW5nIHRoZSB3YWxrIHBvaW50ZXJcbiAgICogYWZ0ZXJ3YXJkcyBpcyB3aGF0IGtlZXBzIHRoZSB0d28gcG9pbnRlcnMgZnJvbSBpbnRlcmZlcmluZy5cbiAgICovXG4gIHByaXZhdGUgZHJhaW5QYXJrZWQoKTogdm9pZCB7XG4gICAgbGV0IHByb2dyZXNzZWQgPSB0aGlzLnBhcmtlZC5sZW5ndGggPiAwO1xuICAgIHdoaWxlIChwcm9ncmVzc2VkKSB7XG4gICAgICBwcm9ncmVzc2VkID0gZmFsc2U7XG4gICAgICB0aGlzLmRyb3BQYXJrZWREdXBsaWNhdGVzKCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucGFya2VkLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5wYXJrZWRbaV07XG4gICAgICAgIGNvbnN0IHdhbGtJbmRleCA9IHRoaXMuZXZlbnRJbmRleDtcbiAgICAgICAgdGhpcy5ldmVudEluZGV4ID0gZW50cnkuaW5kZXg7XG4gICAgICAgIGxldCBjb25zdW1lZDogYm9vbGVhbjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdW1lZCA9IHRoaXMub2ZmZXIoZW50cnkuZXZlbnQpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHRoaXMuZXZlbnRJbmRleCA9IHdhbGtJbmRleDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29uc3VtZWQpIHtcbiAgICAgICAgICB0aGlzLnBhcmtlZC5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgLy8gQSBgRmluaXNoZWRgIGNhbGxiYWNrIHdhcyBzcGxpY2VkIG91dCBvZiB0aGUgbGlzdCB0aGlzIHBhc3MsIHNvXG4gICAgICAgICAgLy8gcmVzdGFydCByYXRoZXIgdGhhbiBrZWVwIHdhbGtpbmcgYSBtdXRhdGVkIGFycmF5LlxuICAgICAgICAgIHByb2dyZXNzZWQgPSB0aGlzLnBhcmtlZC5sZW5ndGggPiAwO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlbGVhc2UgYW55dGhpbmcgcGFya2VkIHdob3NlIGNsYXNzIGEgY29uc3VtcHRpb24gaGFzIHNpbmNlIHJlY29yZGVkIGZvclxuICAgKiB0aGUgc2FtZSBlbnRpdHksIG9uIHRoZSBzYW1lIHRlcm1zIGFzIHtAbGluayBza2lwRHVwbGljYXRlRXZlbnR9LlxuICAgKlxuICAgKiBUaGUgb3JkZXJlZCB3YWxrIGRlY2lkZXMgYSBzdHJhZ2dsZXIgYXQgdGhlIGV2ZW50LCBidXQgb25seSBmb3Igb25lIG9mIHRoZVxuICAgKiB0d28gb3JkZXJzIHRoZSBjb3BpZXMgY2FuIGFycml2ZSBpbi4gV2hlbiBuZWl0aGVyIGNvcHkgaGFzIGEgY29uc3VtZXIgeWV0LFxuICAgKiBib3RoIHBhcmsg4oCUIHRoZSB3YWxrIHN0ZXBzIG92ZXIgdGhlIGZpcnN0IGFuZCByZS1lbnRlcnMgaW1tZWRpYXRlbHksIHNvXG4gICAqIHRoZSBzZWNvbmQgaXMgb2ZmZXJlZCBpbiB0aGUgc2FtZSB0aWNrLCB3aXRoIG5vIGNsYXNzIHJlY29yZGVkIGJlY2F1c2VcbiAgICogbm90aGluZyBoYXMgYmVlbiAqY29uc3VtZWQqLiBUaGUgZHJhaW4gdGhlbiBjbGFpbXMgdGhlIGZpcnN0IGFuZCB0aGVcbiAgICogc2Vjb25kIGlzIGxlZnQgaGVsZCBieSBhIGNvbnN1bWVyIGxpc3QgdGhhdCB3aWxsIG5ldmVyIGdyb3cgdGhlIGNhbGxiYWNrXG4gICAqIGl0IG5lZWRzLCB3aGljaCB0aGUgd29ya2Zsb3cgZnVuY3Rpb24gcmV0dXJuaW5nIHJlcG9ydHMgdGhyb3VnaFxuICAgKiB7QGxpbmsgc3RyYW5kZWRFdmVudH0gYXMgYSByZXBsYXkgZGl2ZXJnZW5jZS5cbiAgICpcbiAgICogUnVuIGJlZm9yZSBlYWNoIG9mZmVyIHBhc3MgcmF0aGVyIHRoYW4gb25jZSwgYmVjYXVzZSB0aGUgY29uc3VtcHRpb24gdGhhdFxuICAgKiByZWNvcmRzIHRoZSBjbGFzcyBoYXBwZW5zIGluc2lkZSB0aGUgZHJhaW4gaXRzZWxmLlxuICAgKlxuICAgKiBOb3Qgc3BlY2lmaWMgdG8gYGF0dHJfc2V0YDogYHdhaXRfY29tcGxldGVkYCByZWFjaGVzIHRoZSBzYW1lIHN0YXRlLCBhbmRcbiAgICoge0BsaW5rIE9ORV9TSE9UX0VWRU5UX1RZUEVTfSBvbmx5IGNvdmVycyBpdCBpbiB0aGUgb3JkZXIgd2hlcmUgdGhlXG4gICAqIGNvbnN1bXB0aW9uIGNhbWUgZmlyc3QuXG4gICAqL1xuICBwcml2YXRlIGRyb3BQYXJrZWREdXBsaWNhdGVzKCk6IHZvaWQge1xuICAgIGZvciAobGV0IGkgPSB0aGlzLnBhcmtlZC5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgY29uc3QgZXZlbnQgPSB0aGlzLnBhcmtlZFtpXS5ldmVudDtcbiAgICAgIGNvbnN0IGZpcnN0VHlwZSA9IHRoaXMuZmlyc3RFdmVudFR5cGVPZkNsYXNzKGV2ZW50KTtcbiAgICAgIGlmIChmaXJzdFR5cGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRoaXMucGFya2VkLnNwbGljZShpLCAxKTtcbiAgICAgIC8vIFRoZSB3YWxrIGluZGV4IG1vdmVkIHBhc3QgdGhpcyBldmVudCB3aGVuIGl0IHdhcyBwYXJrZWQsIHNvIHVubGlrZVxuICAgICAgLy8gYHNraXBEdXBsaWNhdGVFdmVudGAgdGhlcmUgaXMgbm90aGluZyB0byBhZHZhbmNlIGhlcmUuXG4gICAgICBldmVudHNMb2dnZXIuZGVidWcoXG4gICAgICAgICdSZWxlYXNpbmcgYSBwYXJrZWQgZXZlbnQgdGhhdCByZXBlYXRzIGEgY2xhc3MgYWxyZWFkeSBpbiB0aGUgbG9nJyxcbiAgICAgICAge1xuICAgICAgICAgIGV2ZW50SWQ6IGV2ZW50LmV2ZW50SWQsXG4gICAgICAgICAgZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsXG4gICAgICAgICAgZmlyc3RFdmVudFR5cGU6IGZpcnN0VHlwZSxcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBldmVudC5jb3JyZWxhdGlvbklkLFxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5vbkR1cGxpY2F0ZUV2ZW50Py4oZXZlbnQsIGZpcnN0VHlwZSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBldmVudHNMb2dnZXIuZXJyb3IoJ29uRHVwbGljYXRlRXZlbnQgY2FsbGJhY2sgdGhyZXcgYW4gZXJyb3InLCB7XG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGVwIHRoZSBvcmRlcmVkIHdhbGsgb3ZlciBhbiBldmVudCBub2JvZHkgY2xhaW1lZCwgaG9sZGluZyBvbiB0byBpdCBmb3IgYVxuICAgKiBsYXRlciBjb25zdW1lci4gUmV0dXJucyBmYWxzZSB3aGVuIHRoZSBldmVudCdzIHR5cGUgbWFrZXMgaXRzIHBvc2l0aW9uIGFcbiAgICogZGVjaXNpb24gcmVjb3JkLCB3aGljaCBpcyB0aGUgb25lIGNhc2Ugd2hlcmUgbm9ib2R5IGNsYWltaW5nIGl0IG1lYW5zIHRoZVxuICAgKiByZXBsYXkgZGl2ZXJnZWQuXG4gICAqL1xuICBwcml2YXRlIHBhcmsoZXZlbnQ6IEV2ZW50KTogYm9vbGVhbiB7XG4gICAgaWYgKCFQQVJLQUJMRV9FVkVOVF9UWVBFUy5oYXMoZXZlbnQuZXZlbnRUeXBlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICBldmVudC5jb3JyZWxhdGlvbklkICYmXG4gICAgICB0aGlzLnJlc29sdmVkLmhhcyhyZXNvbHV0aW9uS2V5KGV2ZW50LmV2ZW50VHlwZSwgZXZlbnQuY29ycmVsYXRpb25JZCkpXG4gICAgKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHRoaXMucGFya2VkLnB1c2goeyBldmVudCwgaW5kZXg6IHRoaXMuZXZlbnRJbmRleCB9KTtcbiAgICB0aGlzLmV2ZW50SW5kZXgrKztcbiAgICBldmVudHNMb2dnZXIuZGVidWcoJ1BhcmtlZCBhbiB1bmNsYWltZWQgZXZlbnQgZm9yIGxhdGVyIGRlbGl2ZXJ5Jywge1xuICAgICAgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCxcbiAgICAgIGV2ZW50VHlwZTogZXZlbnQuZXZlbnRUeXBlLFxuICAgICAgY29ycmVsYXRpb25JZDogZXZlbnQuY29ycmVsYXRpb25JZCxcbiAgICAgIHBhcmtlZDogdGhpcy5wYXJrZWQubGVuZ3RoLFxuICAgIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBrZXkgYGV2ZW50YCdzIGNsYXNzIGlzIHRyYWNrZWQgdW5kZXIsIG9yIGB1bmRlZmluZWRgIGZvciB0aGUgZXZlbnRzXG4gICAqIHRoYXQgYmVsb25nIHRvIG5vIGNsYXNzIGFuZCBhcmUgdGhlcmVmb3JlIG5ldmVyIHNraXBwZWQ6IHRoZSB0eXBlcyB3aXRoIG5vXG4gICAqIGVudHJ5IGF0IGFsbCAoYGhvb2tfcmVjZWl2ZWRgLCBgaG9va19jb25mbGljdGAsIGBydW5fY3JlYXRlZGApLCBhbmQgYVxuICAgKiBjbGFzc2VkIHR5cGUgY2Fycnlpbmcgbm8gZW50aXR5IHRvIHRyYWNrIGl0IHVuZGVyLlxuICAgKlxuICAgKiB7QGxpbmsgY2xhc3NpZnlFbnRpdHlFdmVudH0gb3ducyB0aGF0IHJ1bGUsIGJlY2F1c2UgdGhlIG9ic2VydmFiaWxpdHkgVUlcbiAgICogZGVjaWRlcyB0aGUgc2FtZSBxdWVzdGlvbiBhYm91dCB0aGUgc2FtZSBsb2cgYW5kIHRoZSB0d28gbXVzdCBub3QgZHJpZnQuXG4gICAqL1xuICBwcml2YXRlIGV2ZW50Q2xhc3NLZXkoZXZlbnQ6IEV2ZW50KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBjbGFzc2lmaWNhdGlvbiA9IGNsYXNzaWZ5RW50aXR5RXZlbnQoZXZlbnQpO1xuICAgIHJldHVybiBjbGFzc2lmaWNhdGlvbiA9PT0gdW5kZWZpbmVkXG4gICAgICA/IHVuZGVmaW5lZFxuICAgICAgOiBgJHtjbGFzc2lmaWNhdGlvbi5ldmVudENsYXNzfToke2NsYXNzaWZpY2F0aW9uLmVudGl0eX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbWVtYmVycyB0aGF0IGBldmVudGAncyBjbGFzcyBpcyBub3cgZGVjaWRlZCBmb3IgaXRzIGVudGl0eSwgaWYgdGhlIHR5cGVcbiAgICogYmVsb25ncyB0byBhIGNsYXNzLiBGaXJzdCB3cml0ZXIgd2luczogdGhlIHJlY29yZGVkIHR5cGUgaXMgdGhlIG9uZSB0aGVcbiAgICogd29ya2Zsb3cgb2JzZXJ2ZWQsIGFuZCBhIGxhdGVyIHJlcGVhdCBpcyBtZWFzdXJlZCBhZ2FpbnN0IGl0LlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRFdmVudENsYXNzKGV2ZW50OiBFdmVudCkge1xuICAgIGNvbnN0IGtleSA9IHRoaXMuZXZlbnRDbGFzc0tleShldmVudCk7XG4gICAgaWYgKGtleSAhPT0gdW5kZWZpbmVkICYmICF0aGlzLnNlZW5FdmVudENsYXNzZXMuaGFzKGtleSkpIHtcbiAgICAgIHRoaXMuc2VlbkV2ZW50Q2xhc3Nlcy5zZXQoa2V5LCBldmVudC5ldmVudFR5cGUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgdHlwZSB0aGF0IGFscmVhZHkgZGVjaWRlZCBgZXZlbnRgJ3MgY2xhc3MgZm9yIHRoZSBzYW1lIGVudGl0eSwgb3JcbiAgICogYHVuZGVmaW5lZGAgd2hlbiBub3RoaW5nIGhhczogYSBzZWNvbmQgYHN0ZXBfY3JlYXRlZGAgZm9yIG9uZSBzdGVwLCBhXG4gICAqIHNlY29uZCB0ZXJtaW5hbCBvdXRjb21lLCBhIHNlY29uZCBgc3RlcF9zdGFydGVkYCBhZnRlciB0aGUgc3RlcCdzIHJlc3VsdCBpc1xuICAgKiBhbHJlYWR5IGluIHRoZSBsb2cuXG4gICAqXG4gICAqIFN1Y2ggYW4gZXZlbnQgaXMgY29tbWl0dGVkIGJ1dCBpbmVydC4gQ29uY3VycmVudCByZXBsYXlzIHdyaXRlIGludG8gb25lXG4gICAqIGxvZyB3aXRob3V0IGEgY3VycmVuY3kgZ3VhcmQsIHNvIGEgcmVwbGF5IHdvcmtpbmcgZnJvbSBhIHByZWZpeCB0aGF0XG4gICAqIHByZWRhdGVzIGFub3RoZXIgcmVwbGF5J3Mgd3JpdGUgY2FuIGNvbW1pdCBpdHMgb3duIGNvcHkgb2Ygd29yayB0aGUgbG9nXG4gICAqIGFscmVhZHkgcmVjb3Jkcy4gVGhhdCBjb3B5IGNhbm5vdCBjaGFuZ2Ugd2hhdCB0aGUgd29ya2Zsb3cgb2JzZXJ2ZWQ6IHRoZVxuICAgKiBvdXRjb21lIHdhcyBkZWNpZGVkIGJ5IHRoZSBmaXJzdCBldmVudCBvZiB0aGUgY2xhc3MgYW5kIGV2ZXJ5IGxhdGVyIHJlcGxheVxuICAgKiByZWFkcyB0aGF0IHNhbWUgZXZlbnQgYXQgdGhlIHNhbWUgbG9nIHBvc2l0aW9uLCBzbyBpZ25vcmluZyB0aGUgc3RyYWdnbGVyXG4gICAqIGlzIGRldGVybWluaXN0aWMgYWNyb3NzIHJlcGxheXMuXG4gICAqXG4gICAqIENsYXNzZXMgYXJlIHRyYWNrZWQgc2VwYXJhdGVseSwgc28gcGFzc2luZyBvbmUgZG9lcyBub3Qgc3VwcHJlc3MgYW5vdGhlci5cbiAgICogQSBzdGVwIHdob3NlIHJlc3VsdCBpcyBpbiB0aGUgbG9nIHN0aWxsIHJlYWNoZXMgaXRzIGBzdGVwX2NyZWF0ZWRgIGFuZFxuICAgKiBgc3RlcF9zdGFydGVkYCBjb25zdW1lcnMgaWYgaXQgaGFzIHlldCB0byBzZWUgdGhvc2UgY2xhc3Nlcy5cbiAgICpcbiAgICogQ29uc3VsdGVkIG9ubHkgYWZ0ZXIgZXZlcnkgcmVnaXN0ZXJlZCBjYWxsYmFjayBoYXMgZGVjbGluZWQgdGhlIGV2ZW50LCBzb1xuICAgKiBpdCBjYW4gbmV2ZXIgdGFrZSBhbiBldmVudCBhIGNvbnN1bWVyIHdhbnRlZC4gQSByZXRyeSdzIGBzdGVwX3N0YXJ0ZWRgIGlzXG4gICAqIGNsYWltZWQgYnkgdGhlIHN0ZXAncyBsaXZlIGNvbnN1bWVyIGFuZCBjb3VudHMgYXMgYW4gYXR0ZW1wdCBleGFjdGx5IGFzXG4gICAqIGJlZm9yZSwgYW5kIGEgc2Vjb25kIGBzdGVwX2NyZWF0ZWRgIHJlYWNoaW5nIGEgc3RlcCB0aGF0IGhhcyBub3QgZmluaXNoZWRcbiAgICogaXMgbGlrZXdpc2UgY29uc3VtZWQgcmF0aGVyIHRoYW4gc2tpcHBlZDsgb25seSB0aGUgY29waWVzIG5vYm9keSBjbGFpbXMgYXJlXG4gICAqIHNraXBwZWQuXG4gICAqXG4gICAqIFVubGlrZSB0aGUgZGl2ZXJnZW5jZSByZXBvcnQsIHRoaXMgZG9lcyAqbm90KiB3YWl0IG91dCB0aGUgZGVmZXJyZWQgd2luZG93XG4gICAqIGZpcnN0LCBhbmQgaXQgZG9lcyBub3QgbmVlZCB0by4gVGhlIHdpbmRvdyBidXlzIHRpbWUgZm9yIGEgY29uc3VtZXIgdGhhdFxuICAgKiBoYXMgeWV0IHRvIHJlZ2lzdGVyLCBhbmQgbm8gc3VjaCBjb25zdW1lciBjYW4gd2FudCB0aGlzIGV2ZW50OiB0aGUgY2xhc3NcbiAgICogd2FzIHJlY29yZGVkIGJ5IGEgY29uc3VtcHRpb24gaW4gdGhpcyBzYW1lIHJlcGxheSwgd2hpY2ggbWVhbnMgdGhlIGVudGl0eSdzXG4gICAqIGNvbnN1bWVyIHdhcyByZWdpc3RlcmVkIGFuZCB0b29rIGFuIGV2ZW50IG9mIHRoaXMgY2xhc3MsIGFuZCBjb3JyZWxhdGlvblxuICAgKiBpZHMgYXJlIG1pbnRlZCBmcm9tIGEgbW9ub3RvbmljIFVMSUQgcGVyIGJvZHkgcG9zaXRpb24sIHNvIG5vdGhpbmcgbGF0ZXIgaW5cbiAgICogdGhlIGJvZHkgcmVnaXN0ZXJzIGEgc2Vjb25kIGNvbnN1bWVyIHVuZGVyIHRoaXMgaWQuIFdhaXRpbmcgd291bGQgY29zdFxuICAgKiBgZ2V0RGVmZXJyZWRDaGVja0RlbGF5TXMoKWAgcGVyIHN0cmFnZ2xlciBwZXIgcmVwbGF5IGZvciBpbmZvcm1hdGlvbiB0aGF0XG4gICAqIGNhbm5vdCBhcnJpdmU6IDAuNzUlIG9mIHByb2R1Y3Rpb24gcnVucyBjYXJyeSBhdCBsZWFzdCBvbmUgc3RyYWdnbGVyLCBhbmRcbiAgICogdGhlIHA5OSBhbW9uZyB0aG9zZSBjYXJyaWVzIDE1NS5cbiAgICpcbiAgICogVGhlIGludmFyaWFudCB0byBwcmVzZXJ2ZSBpZiBob29rIGlkZW50aXR5IGV2ZXIgYmVjb21lcyBjYWxsZXItc3VwcGxpZWRcbiAgICogKGFuIGlkZW1wb3RlbmN5IGtleSByYXRoZXIgdGhhbiBhIG1pbnRlZCBpZCk6IHR3byBgY3JlYXRlSG9va2AgY2FsbHMgaW4gb25lXG4gICAqIGJvZHkgY291bGQgdGhlbiBzaGFyZSBhIGNvcnJlbGF0aW9uIGlkLCBhbmQgdGhlIHNlY29uZCBjb25zdW1lcidzXG4gICAqIGBob29rX2NyZWF0ZWRgIHdvdWxkIGJlIGEgcmVwZWF0IG9mIGEgY2xhc3MgdGhpcyByZXBsYXkgYWxyZWFkeSByZWNvcmRlZC5cbiAgICogVGhhdCB3b3VsZCBtYWtlIHNraXBwaW5nIHdyb25nIGZvciBgaG9va19jcmVhdGVkYCwgYW5kIGlzIHRoZSByZWFzb24gdGhlXG4gICAqIGNsYXNzIG1hcCBsaXZlcyBuZXh0IHRvIHRoZSBldmVudCB0eXBlcyByYXRoZXIgdGhhbiBiZWluZyBpbmZlcnJlZC5cbiAgICovXG4gIHByaXZhdGUgZmlyc3RFdmVudFR5cGVPZkNsYXNzKGV2ZW50OiBFdmVudCk6IEV2ZW50WydldmVudFR5cGUnXSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3Qga2V5ID0gdGhpcy5ldmVudENsYXNzS2V5KGV2ZW50KTtcbiAgICByZXR1cm4ga2V5ID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB0aGlzLnNlZW5FdmVudENsYXNzZXMuZ2V0KGtleSk7XG4gIH1cblxuICAvKipcbiAgICogU3RlcHMgdGhlIHdhbGsgb3ZlciBhIHNlYWxlZC1sb2cgYG5vb3BgIChzcGVjVmVyc2lvbiA+PSA3KTogdGhlIFdvcmxkJ3NcbiAgICogYmFja2VuZCB3cm90ZSBpdCB0byBvY2N1cHkgYSBzbG90IHdob3NlIHdyaXRlciBhbGxvY2F0ZWQgdGhlIHBvc2l0aW9uIGFuZFxuICAgKiBkaWVkLCBzbyB0aGUgbG9nJ3MgZGVuc2l0eSBhcml0aG1ldGljIGhvbGRzLiBJdCBpcyBpbnZpc2libGUgdG8gdGhlXG4gICAqIHdvcmtmbG93OiBubyBjb25zdW1lciBpcyBvZmZlcmVkIGl0LCBubyBldmVudCBjbGFzcyBpcyByZWNvcmRlZCwgYW5kIHRoZVxuICAgKiBkZXRlcm1pbmlzdGljIGNsb2NrIGRvZXMgbm90IGFkdmFuY2UsIGV4YWN0bHkgYXMgd2l0aFxuICAgKiB7QGxpbmsgc2tpcER1cGxpY2F0ZUV2ZW50fSwgc28gYSBsb2cgdGhhdCBoYXBwZW5zIHRvIGNvbnRhaW4gb25lIHByb2R1Y2VzIHRoZSBzYW1lXG4gICAqIHRpbWVzdGFtcHMgYXMgYSBsb2cgdGhhdCBkb2VzIG5vdC4gKEl0cyBgY3JlYXRlZEF0YCBpcyB0aGUgc2VhbCB0aW1lLFxuICAgKiB3aGljaCBjYW4gZXZlbiBwb3N0ZGF0ZSBsYXRlciBzbG90cycgZXZlbnRzOyBsZXR0aW5nIGl0IHRvdWNoIHRoZSBjbG9ja1xuICAgKiB3b3VsZCBsZWFrIHRoZSBzZWFsZXIncyB3YWxsIGNsb2NrIGludG8gcmVwbGF5LilcbiAgICovXG4gIHByaXZhdGUgc2tpcFNlYWxlZE5vb3AoZXZlbnQ6IEV2ZW50KSB7XG4gICAgdGhpcy5ldmVudEluZGV4Kys7XG4gICAgZXZlbnRzTG9nZ2VyLmRlYnVnKCdTa2lwcGluZyBzZWFsZWQtbG9nIG5vb3AgZXZlbnQnLCB7XG4gICAgICBldmVudElkOiBldmVudC5ldmVudElkLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFN0ZXBzIHRoZSB3YWxrIG92ZXIgYSByZXBlYXQgb2YgYW4gYWxyZWFkeS1jb25zdW1lZCBjbGFzcy4gKi9cbiAgcHJpdmF0ZSBza2lwRHVwbGljYXRlRXZlbnQoZXZlbnQ6IEV2ZW50LCBmaXJzdFR5cGU6IEV2ZW50WydldmVudFR5cGUnXSkge1xuICAgIHRoaXMuZXZlbnRJbmRleCsrO1xuICAgIC8vIERlbGliZXJhdGVseSBub3Qgcm91dGVkIHRocm91Z2ggYG5vdGlmeUNvbnN1bWVkRXZlbnRgOiB0aGUgZGV0ZXJtaW5pc3RpY1xuICAgIC8vIGNsb2NrIGFkdmFuY2VzIG9ubHkgb24gZXZlbnRzIHRoZSB3b3JrZmxvdyBhY3R1YWxseSBvYnNlcnZlZC4gQSBza2lwcGVkXG4gICAgLy8gZXZlbnQgaXMgaW52aXNpYmxlIHRvIHRoZSB3b3JrZmxvdyBib2R5LCBhbmQgYSBsb2cgdGhhdCBoYXBwZW5zIHRvXG4gICAgLy8gY29udGFpbiBvbmUgbXVzdCBwcm9kdWNlIHRoZSBzYW1lIHRpbWVzdGFtcHMgYXMgYSBsb2cgdGhhdCBkb2VzIG5vdC5cbiAgICBldmVudHNMb2dnZXIuZGVidWcoXG4gICAgICAnU2tpcHBpbmcgZXZlbnQgdGhhdCByZXBlYXRzIGEgY2xhc3MgYWxyZWFkeSBpbiB0aGUgbG9nJyxcbiAgICAgIHtcbiAgICAgICAgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCxcbiAgICAgICAgZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsXG4gICAgICAgIGZpcnN0RXZlbnRUeXBlOiBmaXJzdFR5cGUsXG4gICAgICAgIGNvcnJlbGF0aW9uSWQ6IGV2ZW50LmNvcnJlbGF0aW9uSWQsXG4gICAgICB9XG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgdGhpcy5vbkR1cGxpY2F0ZUV2ZW50Py4oZXZlbnQsIGZpcnN0VHlwZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGV2ZW50c0xvZ2dlci5lcnJvcignb25EdXBsaWNhdGVFdmVudCBjYWxsYmFjayB0aHJldyBhbiBlcnJvcicsIHtcbiAgICAgICAgZXJyb3IsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVuZE9mTG9nKCkge1xuICAgIC8vIEV2ZXJ5dGhpbmcgc3RpbGwgcGFya2VkIGlzIHdhaXRpbmcgZm9yIGEgY29uc3VtZXIgc29tZSBsYXRlciByZXBsYXkgd2lsbFxuICAgIC8vIHJlZ2lzdGVyLCB3aGljaCBpcyB0aGUgd2hvbGUgcG9pbnQgb2YgcGFya2luZywgZXhjZXB0IG9uY2UgdGhlIGxvZ1xuICAgIC8vIGFscmVhZHkgaG9sZHMgdGhlIHJ1bidzIHRlcm1pbmFsIGV2ZW50LCBiZWNhdXNlIHRoZW4gdGhlcmUgaXMgbm8gbGF0ZXJcbiAgICAvLyByZXBsYXkgYW5kIG5vIGNvbnN1bWVyIHdpbGwgZXZlciBjb21lLlxuICAgIGlmICh0aGlzLnBhcmtlZC5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbGFzdCA9IHRoaXMuZXZlbnRzLmF0KC0xKTtcbiAgICBpZiAoIWxhc3QgfHwgIVRFUk1JTkFMX0VWRU5UX1RZUEVTLmhhcyhsYXN0LmV2ZW50VHlwZSkpIHtcbiAgICAgIC8vIEEgbGF0ZXIgcmVwbGF5IGlzIHN0aWxsIGV4cGVjdGVkLCBzbyBub3RoaW5nIGhlcmUgaXMgZGVjaWRhYmxlIGFuZFxuICAgICAgLy8gZXNjYWxhdGluZyB3b3VsZCBmYWlsIHRoZSBoZWFsdGh5IHJ1bnMgcGFya2luZyBleGlzdHMgdG8ga2VlcCBhbGl2ZS5cbiAgICAgIC8vIFJlYWNoaW5nIHRoZSBlbmQgb2YgdGhlIGxvZyBob2xkaW5nIHNvbWV0aGluZyBpcyBub3QgYnkgaXRzZWxmIGEgZmF1bHQsXG4gICAgICAvLyBzbyB0aGlzIHN0YXlzIGF0IGBkZWJ1Z2A7IHtAbGluayBwYXJrZWRTdW1tYXJ5fSBpcyB3aGF0IGNhcnJpZXMgdGhlXG4gICAgICAvLyBzdGF0ZSB0byB0aGUgc3Bhbiwgd2hlcmUgYSBydW4gdGhhdCBrZWVwcyBzdG9wcGluZyBvbiB0aGUgc2FtZSBoZWxkXG4gICAgICAvLyBldmVudCBpcyB2aXNpYmxlIGFuZCBhIHNpbmdsZSByZXBsYXkncyB2aWV3IGlzIG5vdC5cbiAgICAgIGV2ZW50c0xvZ2dlci5kZWJ1ZygnUmVhY2hlZCB0aGUgZW5kIG9mIHRoZSBsb2cgc3RpbGwgaG9sZGluZyBldmVudHMnLCB7XG4gICAgICAgIGV2ZW50SWQ6IHRoaXMucGFya2VkWzBdLmV2ZW50LmV2ZW50SWQsXG4gICAgICAgIGV2ZW50VHlwZTogdGhpcy5wYXJrZWRbMF0uZXZlbnQuZXZlbnRUeXBlLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiB0aGlzLnBhcmtlZFswXS5ldmVudC5jb3JyZWxhdGlvbklkLFxuICAgICAgICBwYXJrZWQ6IHRoaXMucGFya2VkLmxlbmd0aCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnNjaGVkdWxlVW5jb25zdW1lZENoZWNrKHRoaXMucGFya2VkWzBdLmV2ZW50LCBmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIHNjaGVkdWxlVW5jb25zdW1lZENoZWNrKGN1cnJlbnRFdmVudDogRXZlbnQsIG1heVBhcms6IGJvb2xlYW4pIHtcbiAgICAvLyBBbGwgY2FsbGJhY2tzIHJldHVybmVkIE5vdENvbnN1bWVkIGZvciB0aGUgY3VycmVudCBldmVudC5cbiAgICAvLyBTY2hlZHVsZSBhIGRlZmVycmVkIGNoZWNrLiBXZSBjaGFpbiBvbnRvIHRoZSBwcm9taXNlUXVldWUgc28gdGhhdCBhbnlcbiAgICAvLyBwZW5kaW5nIGFzeW5jIHdvcmsgKGUuZy4sIGRlc2VyaWFsaXphdGlvbi9kZWNyeXB0aW9uIHRoYXQgdHJpZ2dlcnNcbiAgICAvLyByZXNvbHZlKCkg4oaSIHVzZXIgY29kZSDihpIgc3Vic2NyaWJlKCkpIGNvbXBsZXRlcyBmaXJzdC4gSWYgdGhlIGV2ZW50XG4gICAgLy8gaXMgc3RpbGwgdW5jb25zdW1lZCBhZnRlciB0aGUgcXVldWUgZHJhaW5zLCBpdCdzIHRydWx5IG9ycGhhbmVkLCBvcixcbiAgICAvLyB3aGVuIGl0cyB0eXBlIGNhcnJpZXMgbm8gb3JkZXJpbmcgY2xhaW0sIHBhcmtlZCBmb3IgYSBsYXRlciBjb25zdW1lci5cbiAgICBjb25zdCBjaGVja1ZlcnNpb24gPSArK3RoaXMudW5jb25zdW1lZENoZWNrVmVyc2lvbjtcbiAgICB0aGlzLnBlbmRpbmdVbmNvbnN1bWVkQ2hlY2sgPSB0aGlzLmdldFByb21pc2VRdWV1ZSgpXG4gICAgICAudGhlbihcbiAgICAgICAgLy8gWWllbGQgb25jZSBhZnRlciB0aGUgZmlyc3QgcXVldWUgZHJhaW4gc28gcHJvbWlzZSBjaGFpbnMgcmVzdW1lZCBieVxuICAgICAgICAvLyB0aGF0IGRyYWluIGNhbiBydW4gYWNyb3NzIHRoZSBWTSBib3VuZGFyeSBhbmQgYXBwZW5kIGFueSBmb2xsb3ctdXBcbiAgICAgICAgLy8gYXN5bmMgd29yayAoZm9yIGV4YW1wbGU6IHN0ZXBfY29tcGxldGVkIHJlc29sdmVzIC0+IGZvci1hd2FpdCBsb29wXG4gICAgICAgIC8vIHJlc3VtZXMgLT4gdGhlIG5leHQgaG9vayBwYXlsb2FkIHN0YXJ0cyBoeWRyYXRpbmcpLlxuICAgICAgICAoKSA9PiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAwKSlcbiAgICAgIClcbiAgICAgIC50aGVuKCgpID0+IHRoaXMuZ2V0UHJvbWlzZVF1ZXVlKCkpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIC8vIFdhaXQgb3V0IGFueSBkZWxpdmVyeSBzdGlsbCBpbiBmbGlnaHQgYmVmb3JlIHN0YXJ0aW5nIHRoZSB0aW1lci5cbiAgICAgICAgLy8gVGhlIHF1ZXVlIGRyYWluaW5nIHNheXMgdGhlIGhvc3QgaGFzIG5vIGh5ZHJhdGlvbiB3b3JrIGxlZnQ7IGl0XG4gICAgICAgIC8vIGRvZXMgbm90IHNheSB0aGUgVk0gaGFzIGZpbmlzaGVkIHJlYWN0aW5nIHRvIHdoYXQgd2FzIGh5ZHJhdGVkLlxuICAgICAgICB0aGlzLndoZW5EZWxpdmVyeUlkbGUoY2hlY2tWZXJzaW9uLCAoKSA9PiB7XG4gICAgICAgICAgLy8gVXNlIGEgZGVsYXllZCBzZXRUaW1lb3V0IG9uY2UgZGVsaXZlcmllcyBhcmUgaWRsZS4gVGhlIGRlbGF5IG11c3RcbiAgICAgICAgICAvLyBiZSBsb25nIGVub3VnaCBmb3IgcHJvbWlzZSBjaGFpbnMgdG8gcHJvcGFnYXRlIGFjcm9zcyB0aGUgVk1cbiAgICAgICAgICAvLyBib3VuZGFyeSAoZnJvbSByZXNvbHZlKCkgaW4gdGhlIGhvc3QgY29udGV4dCB0aHJvdWdoIHRvIHRoZVxuICAgICAgICAgIC8vIHdvcmtmbG93IGNvZGUgY2FsbGluZyBzdWJzY3JpYmUoKSBpbiB0aGUgVk0gY29udGV4dCkuIE5vZGUuanMgZG9lc1xuICAgICAgICAgIC8vIG5vdCBndWFyYW50ZWUgdGhhdCBzZXRUaW1lb3V0KDApIGZpcmVzIGFmdGVyIGFsbCBjcm9zcy1jb250ZXh0XG4gICAgICAgICAgLy8gbWljcm90YXNrcyBzZXR0bGUsIHNvIHdlIHVzZSBhIHNtYWxsIGJ1dCBub24temVybyBkZWxheS4gQW55XG4gICAgICAgICAgLy8gc3Vic2NyaWJlKCkgY2FsbCB0aGF0IGFycml2ZXMgZHVyaW5nIHRoaXMgd2luZG93IHdpbGwgY2FuY2VsIHRoZVxuICAgICAgICAgIC8vIGNoZWNrIHZpYSB2ZXJzaW9uIGludmFsaWRhdGlvbiArIGNsZWFyVGltZW91dC5cbiAgICAgICAgICB0aGlzLnBlbmRpbmdVbmNvbnN1bWVkVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKHRoaXMudW5jb25zdW1lZENoZWNrVmVyc2lvbiAhPT0gY2hlY2tWZXJzaW9uKSB7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRDaGVjayA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLnJlc29sdmVVbmNvbnN1bWVkRXZlbnQoY3VycmVudEV2ZW50LCBtYXlQYXJrKTtcbiAgICAgICAgICB9LCBnZXREZWZlcnJlZENoZWNrRGVsYXlNcygpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNpZGUgd2hhdCBhIHN0aWxsLXVuY29uc3VtZWQgZXZlbnQgaXMsIG5vdyB0aGF0IHRoZSBwcm9taXNlIHF1ZXVlIGhhc1xuICAgKiBkcmFpbmVkIGFuZCB0aGUgZGVsaXZlcnkgZ2F0ZSBzYXlzIHRoZSBWTSBpcyBub3QgbWlkLXJlYWN0aW9uLlxuICAgKlxuICAgKiBgbWF5UGFya2AgaXMgZmFsc2Ugb25seSBmb3IgdGhlIGVuZC1vZi1sb2cgcmVjaGVjayBvZiBhbiBldmVudCB7QGxpbmsgcGFya31cbiAgICogYWxyZWFkeSBob2xkcy4gTm90aGluZyBpbiB0aGUgZmlyc3QgYnJhbmNoIGFwcGxpZXMgdG8gb25lIG9mIHRob3NlOiBpdCBpc1xuICAgKiBub3QgdGhlIGV2ZW50IGF0IHRoZSBjdXJzb3IsIHNvIHRoZSBpZGVudGl0eSBndWFyZCBpcyBub3QgbWVhbmluZ2Z1bCwgYW5kXG4gICAqIGl0IGlzIHBhcmtlZCBhbHJlYWR5LlxuICAgKlxuICAgKiBBIGR1cGxpY2F0ZSBjbGFzcyBuZXZlciBhcnJpdmVzIGhlcmUuIHtAbGluayBjb25zdW1lfSBzdGVwcyBvdmVyIG9uZSBpbiB0aGVcbiAgICogcGFzcyB0aGF0IG9mZmVyZWQgaXQsIGJlZm9yZSB0aGlzIGNoZWNrIGlzIGV2ZXIgc2NoZWR1bGVkLCBhbmQgYSBjbGFzc1xuICAgKiByZWNvcmRlZCB3aGlsZSB0aGUgY2hlY2sgd2FzIGluIGZsaWdodCBjYW4gb25seSBoYXZlIGJlZW4gcmVjb3JkZWQgYnkgYVxuICAgKiBjb25zdW1wdGlvbiBpbnNpZGUge0BsaW5rIGNvbnN1bWV9LCB3aG9zZSBuZXh0IHBhc3MgcmUtb2ZmZXJzIHRoaXMgZXZlbnRcbiAgICogYW5kIHN0ZXBzIG92ZXIgaXQgdGhlcmUsIGxlYXZpbmcgdGhlIGlkZW50aXR5IGd1YXJkIGFib3ZlIHRvIGRyb3AgdGhlXG4gICAqIGluLWZsaWdodCBjaGVjay4gT25lIHRoYXQgcGFya3MgYmVmb3JlIGFueSBjb25zdW1wdGlvbiByZWNvcmRzIGl0cyBjbGFzc1xuICAgKiBpcyByZWxlYXNlZCBsYXRlciBieSB7QGxpbmsgZHJvcFBhcmtlZER1cGxpY2F0ZXN9IGluc3RlYWQuXG4gICAqL1xuICBwcml2YXRlIHJlc29sdmVVbmNvbnN1bWVkRXZlbnQoY3VycmVudEV2ZW50OiBFdmVudCwgbWF5UGFyazogYm9vbGVhbikge1xuICAgIGlmIChtYXlQYXJrKSB7XG4gICAgICBpZiAodGhpcy5ldmVudHNbdGhpcy5ldmVudEluZGV4XSAhPT0gY3VycmVudEV2ZW50KSB7XG4gICAgICAgIC8vIEFuIGFwcGVuZCgpIGRyYWluIGNsYWltZWQgaXQgd2hpbGUgdGhlIGNoZWNrIHdhcyBpbiBmbGlnaHQuXG4gICAgICAgIC8vIE9ubHkgc3Vic2NyaWJlKCkgY2FuY2VscyB0aGUgY2hlY2ssIHNvIHRoaXMgaXMgcmVhY2hhYmxlLlxuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5wYXJrKGN1cnJlbnRFdmVudCkpIHtcbiAgICAgICAgdGhpcy5jb25zdW1lKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5vblVuY29uc3VtZWRFdmVudChjdXJyZW50RXZlbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBgZm5gIG9uY2Ugbm8gZGF0YSBkZWxpdmVyeSBpcyBpbiBmbGlnaHQsIHBvbGxpbmcgdGhlIHdheVxuICAgKiBgc2NoZWR1bGVXaGVuSWRsZWAgZG9lczogbGV0IHRoZSBwcm9taXNlIHF1ZXVlIGRyYWluLCByZS1jaGVjayBhIHRpbWVyXG4gICAqIHRpY2sgbGF0ZXIsIHJlcGVhdC5cbiAgICpcbiAgICogV2l0aG91dCB0aGlzIHRoZSBjaGVjayBpcyBhIGJldCB0aGF0IGV2ZXJ5IGRlbGl2ZXJ5IHRoZSB3YWxrIGlzIHJ1bm5pbmdcbiAgICogYWhlYWQgb2YgbGFuZHMgaW5zaWRlIGEgZml4ZWQgd2luZG93LiBDb25zdW1wdGlvbiBpcyBzeW5jaHJvbm91cyB3aGlsZSB0aGVcbiAgICogcmVzb2x1dGlvbiBpdCB0cmlnZ2VycyBpcyBub3Q6IGEgc3RlcCByZXN1bHQgaHlkcmF0ZXMgaW4gdGhlIGhvc3QsIHJlc29sdmVzXG4gICAqIGZyb20gYSBkZXRhY2hlZCBjb250aW51YXRpb24gYmVoaW5kIGBhd2FpdEVhcmxpZXJEZWxpdmVyaWVzYCwgYW5kIG9ubHkgdGhlblxuICAgKiBkb2VzIFZNIGNvZGUgcnVuIGZhciBlbm91Z2ggdG8gc3Vic2NyaWJlIHRoZSBuZXh0IGNvbnN1bWVyLiBSZXBsYXlpbmcgYVxuICAgKiBiYXRjaCBvZiBOIHBhcmFsbGVsIHN0ZXAgcmVzdWx0cyBsZWF2ZXMgTi0xIG9mIHRoZW0gb24gdGhhdCBkZXRhY2hlZCBwYXRoXG4gICAqIHdpdGggdGhlIHF1ZXVlIGFscmVhZHkgZHJhaW5lZCwgc28gdGhlIHdhbGsgc2l0cyBvbiB0aGUgb3JkZXJlZCBldmVudCB0aGVcbiAgICogVk0gaXMgYWJvdXQgdG8gZHJhdyBhbmQgdGhlIHdpbmRvdyBpcyB0aGUgb25seSB0aGluZyBzdGFuZGluZyBiZXR3ZWVuIGFcbiAgICogaGVhbHRoeSBydW4gYW5kIGBSZXBsYXlEaXZlcmdlbmNlRXJyb3JgLlxuICAgKlxuICAgKiBTaG9ydGVuaW5nIHRoZSB3aW5kb3cgc2hvd3MgdGhhdCBtZWNoYW5pc20gZGlyZWN0bHk6IG9uIGlkZW50aWNhbCBldmVudCBsb2dzXG4gICAqIHRoZSBsb2NhbCByYWNlIHJlcHJvIGNvcnJ1cHRzIDM0IG9mIDQyIHJ1bnMgYXQgYSAxMG1zIHdpbmRvdyBhbmQgMCBvZiAxMTQgYXRcbiAgICogdGhlIDEwMG1zIGRlZmF1bHQuIFRoYXQgbWVhc3VyZXMgaG93IHRoZSBiZXQgbG9zZXMsIG5vdCB0aGF0IHRoZSBkZWZhdWx0XG4gICAqIGxvc2VzIGl0LCBhbmQgbm8gbWVhc3VyZW1lbnQgb2YgYSBkZWxpdmVyeSBvdXRydW5uaW5nIDEwMG1zIGV4aXN0cyBlaXRoZXJcbiAgICogd2F5LiBTbyByZWFkIHRoaXMgYXMgcmV0aXJpbmcgdGhlIGJldCByYXRoZXIgdGhhbiBhcyByZXBhaXJpbmcgYW4gb2JzZXJ2ZWRcbiAgICogZmFpbHVyZSBvZiB0aGF0IG51bWJlcjogdGhlIGRlbGF5IGlzIGEgdXNlci1zZXR0YWJsZSBlbnYgb3ZlcnJpZGUsIHdoaWNoXG4gICAqIGxlYXZlcyB0aGUgb2xkIGJlaGF2aW9yIG9uZSBjb25maWd1cmF0aW9uIGF3YXkgZnJvbSBsb3Npbmcgb24gYW55IGJhY2tlbmQuXG4gICAqXG4gICAqIFRlcm1pbmF0aW9uIGlzIGBoYXNQYXJrZWRDb21taXR0ZWREZWxpdmVyeWAnczogaXQgY291bnRzIG9ubHkgZGVsaXZlcmllc1xuICAgKiB0aGF0IHJlc29sdmUgb24gdGhlaXIgb3duLCBzbyBub3RoaW5nIGhlcmUgY2FuIGdhdGUgaXRzIG93biByZXRpcmVtZW50LiBBXG4gICAqIGdlbnVpbmVseSBvcnBoYW5lZCBldmVudCBoYXMgbm8gZGVsaXZlcnkgdG8gd2FpdCBvbiBhbmQgcmVhY2hlcyBgZm5gIG9uIHRoZVxuICAgKiBmaXJzdCBwb2xsLlxuICAgKlxuICAgKiBXaGF0IHRoZSBnYXRlIGdpdmVzIHVwOiBmb3IgdGhlIG9yZGVyZWQgZXZlbnRzIHRoYXQgc3RpbGwgcmVhY2hcbiAgICogYG9uVW5jb25zdW1lZEV2ZW50YCByYXRoZXIgdGhhbiB7QGxpbmsgcGFya30sIHRoaXMgc3RvcHMgYmVpbmcgdGhlIHRoaW5nXG4gICAqIHRoYXQgY2F0Y2hlcyBhIGRpdmVyZ2VkIGxvZyB3aGlsZSBhIGRlbGl2ZXJ5IGlzIGluIGZsaWdodC4gVGhlIHN1c3BlbnNpb25cbiAgICogYW5kIHRoaXMgY2hlY2sgbm93IHdha2UgZnJvbSB0aGUgc2FtZSBgaXNEZWxpdmVyeUlkbGVgIGVkZ2UsIGFuZFxuICAgKiBgc2NoZWR1bGVXaGVuSWRsZWAgZmlyZXMgb24gdGhlIGZpcnN0IHRpbWVyIHRpY2sgYWZ0ZXIgaWRsZSB3aGlsZSB0aGlzIHdhaXRzXG4gICAqIGEgZnVydGhlciBgZ2V0RGVmZXJyZWRDaGVja0RlbGF5TXMoKWAuIFNvIGEgcnVuIHdpdGggYSBwZW5kaW5nIGBzbGVlcCgpYFxuICAgKiBzdXNwZW5kcyBmaXJzdCwgYW5kIGBvbldvcmtmbG93RXJyb3JgIGRyb3BzIHRoZSBkaXZlcmdlbmNlIGFycml2aW5nIHNlY29uZFxuICAgKiAoaXRzIGAnc3VzcGVuZGVkJ2AgYnJhbmNoIGRlbW90ZXMgdG8gYCdyZXBsYXknYCBhbmQgc3VyZmFjZXMgbm90aGluZyksXG4gICAqIGxlYXZpbmcgYSBsYXRlciBgcmVzdW1lKClgIHRvIGRlY2xpbmUgaW50byBhIGNvbGQgcmVwbGF5LiBQcmUtZ2F0ZSB0aGVcbiAgICogc3VzcGVuc2lvbiBhbHJlYWR5IHdvbiB0aGF0IHJhY2Ugd2hlbmV2ZXIgdGhlIGRlbGl2ZXJ5IGxhbmRlZCBpbnNpZGUgdGhlXG4gICAqIGZpeGVkIHdpbmRvdywgc28gd2hhdCBjaGFuZ2VkIGlzIHRoYXQgdGhlIG91dGNvbWUgc3RvcHBlZCBkZXBlbmRpbmcgb25cbiAgICogdGltaW5nLiBOb3RoaW5nIHNob3VsZCB0cmVhdCB0aGlzIGNoZWNrIGFzIHRoZSBtZWNoYW5pc20gdGhhdCByZXBvcnRzXG4gICAqIGRpdmVyZ2VuY2Ugb24gYSBsb2cgdGhlIHJ1biBpcyBzdGlsbCBkZWxpdmVyaW5nIGludG8uXG4gICAqL1xuICBwcml2YXRlIHdoZW5EZWxpdmVyeUlkbGUoY2hlY2tWZXJzaW9uOiBudW1iZXIsIGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgY29uc3QgcG9sbCA9ICgpID0+IHtcbiAgICAgIHRoaXMucGVuZGluZ1VuY29uc3VtZWRUaW1lb3V0ID0gbnVsbDtcbiAgICAgIGlmICh0aGlzLnVuY29uc3VtZWRDaGVja1ZlcnNpb24gIT09IGNoZWNrVmVyc2lvbikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5pc0RlbGl2ZXJ5SWRsZSgpKSB7XG4gICAgICAgIGZuKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMuZ2V0UHJvbWlzZVF1ZXVlKCkudGhlbigoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLnVuY29uc3VtZWRDaGVja1ZlcnNpb24gIT09IGNoZWNrVmVyc2lvbikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBIZWxkIGluIHRoZSBzYW1lIGZpZWxkIHRoZSBmaXJlZCBjaGVjayB1c2VzIHNvIHN1YnNjcmliZSgpIGNhbmNlbHMgYVxuICAgICAgICAvLyBwb2xsIGluIHByb2dyZXNzIHRvby4gVGhlIHR3byBjYW5jZWxsYXRpb25zIGFyZSBub3QgaWRlbnRpY2FsOiBmb3IgdGhlXG4gICAgICAgIC8vIHBvbGwgaXQgaXMgdGhlIHZlcnNpb24gYnVtcCB0aGF0IGRvZXMgdGhlIHdvcmsgYW5kIHRoZSBjbGVhclRpbWVvdXQgaXNcbiAgICAgICAgLy8gYmVsdC1hbmQtYnJhY2VzLiBUd28gc3RhdGUgbWFjaGluZXMgd3JpdGUgdGhpcyBvbmUgZmllbGQsIHNvIGEgcG9sbFxuICAgICAgICAvLyBpbnZhbGlkYXRlZCBiZXR3ZWVuIHNjaGVkdWxpbmcgYW5kIGZpcmluZyBjYW4gbnVsbCBvdXQgYSBoYW5kbGUgdGhlXG4gICAgICAgIC8vIGxpdmUgY2hhaW4gaGFzIHNpbmNlIHN0b3JlZCwgd2hpY2ggaXMgd2h5IGV2ZXJ5IHBhdGggb3V0IG9mIGBwb2xsYCBhbmRcbiAgICAgICAgLy8gb3V0IG9mIHRoZSBmaXJlZCBjaGVjayByZS1jaGVja3MgdGhlIHZlcnNpb24gcmF0aGVyIHRoYW4gdHJ1c3RpbmcgdGhlXG4gICAgICAgIC8vIGhhbmRsZS5cbiAgICAgICAgdGhpcy5wZW5kaW5nVW5jb25zdW1lZFRpbWVvdXQgPSBzZXRUaW1lb3V0KHBvbGwsIDApO1xuICAgICAgfSk7XG4gICAgfTtcbiAgICBwb2xsKCk7XG4gIH1cbn1cbiJdfQ==