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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +5 -0
  2. package/dist/attribute-changes.d.ts +5 -0
  3. package/dist/attribute-changes.d.ts.map +1 -0
  4. package/dist/attribute-changes.js +25 -0
  5. package/dist/capabilities.d.ts +35 -2
  6. package/dist/capabilities.d.ts.map +1 -1
  7. package/dist/capabilities.js +74 -5
  8. package/dist/capture-stack.d.ts +1 -1
  9. package/dist/capture-stack.js +2 -2
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +19 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +98 -6
  16. package/dist/context-violation-error.d.ts +5 -5
  17. package/dist/context-violation-error.d.ts.map +1 -1
  18. package/dist/context-violation-error.js +8 -6
  19. package/dist/create-hook.d.ts +72 -7
  20. package/dist/create-hook.d.ts.map +1 -1
  21. package/dist/create-hook.js +1 -1
  22. package/dist/define-hook.js +2 -2
  23. package/dist/describe-error.d.ts +7 -7
  24. package/dist/describe-error.d.ts.map +1 -1
  25. package/dist/describe-error.js +97 -12
  26. package/dist/encryption.d.ts +38 -4
  27. package/dist/encryption.d.ts.map +1 -1
  28. package/dist/encryption.js +96 -14
  29. package/dist/events-consumer.d.ts +297 -0
  30. package/dist/events-consumer.d.ts.map +1 -1
  31. package/dist/events-consumer.js +673 -42
  32. package/dist/flushable-stream.d.ts +97 -1
  33. package/dist/flushable-stream.d.ts.map +1 -1
  34. package/dist/flushable-stream.js +291 -11
  35. package/dist/global.d.ts +36 -2
  36. package/dist/global.d.ts.map +1 -1
  37. package/dist/global.js +21 -6
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -2
  41. package/dist/log-format.d.ts +2 -2
  42. package/dist/log-format.js +19 -12
  43. package/dist/logger.d.ts +1 -0
  44. package/dist/logger.d.ts.map +1 -1
  45. package/dist/logger.js +10 -6
  46. package/dist/private.d.ts +226 -9
  47. package/dist/private.d.ts.map +1 -1
  48. package/dist/private.js +626 -7
  49. package/dist/replay-divergence.d.ts +25 -0
  50. package/dist/replay-divergence.d.ts.map +1 -0
  51. package/dist/replay-divergence.js +61 -0
  52. package/dist/replay-payload-cache.d.ts +64 -0
  53. package/dist/replay-payload-cache.d.ts.map +1 -0
  54. package/dist/replay-payload-cache.js +158 -0
  55. package/dist/runtime/compute-instance.d.ts +13 -0
  56. package/dist/runtime/compute-instance.d.ts.map +1 -0
  57. package/dist/runtime/compute-instance.js +14 -0
  58. package/dist/runtime/constants.d.ts +315 -0
  59. package/dist/runtime/constants.d.ts.map +1 -1
  60. package/dist/runtime/constants.js +502 -16
  61. package/dist/runtime/count-step-started-events.d.ts +52 -0
  62. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  63. package/dist/runtime/count-step-started-events.js +72 -0
  64. package/dist/runtime/deployment-guard.d.ts +99 -0
  65. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  66. package/dist/runtime/deployment-guard.js +154 -0
  67. package/dist/runtime/get-port-lazy.d.ts +15 -0
  68. package/dist/runtime/get-port-lazy.d.ts.map +1 -1
  69. package/dist/runtime/get-port-lazy.js +75 -6
  70. package/dist/runtime/get-world-lazy.d.ts +5 -14
  71. package/dist/runtime/get-world-lazy.d.ts.map +1 -1
  72. package/dist/runtime/get-world-lazy.js +19 -29
  73. package/dist/runtime/helpers.d.ts +415 -29
  74. package/dist/runtime/helpers.d.ts.map +1 -1
  75. package/dist/runtime/helpers.js +686 -57
  76. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  77. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  78. package/dist/runtime/quickjs-assets.generated.js +30 -0
  79. package/dist/runtime/quickjs-entrypoint.d.ts +158 -0
  80. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  81. package/dist/runtime/quickjs-entrypoint.js +1863 -0
  82. package/dist/runtime/quickjs-log-view.d.ts +129 -0
  83. package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
  84. package/dist/runtime/quickjs-log-view.js +229 -0
  85. package/dist/runtime/quickjs-runtime.d.ts +244 -0
  86. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  87. package/dist/runtime/quickjs-runtime.js +2427 -0
  88. package/dist/runtime/quickjs-serde.d.ts +107 -0
  89. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  90. package/dist/runtime/quickjs-serde.js +2159 -0
  91. package/dist/runtime/replay-budget.d.ts +97 -0
  92. package/dist/runtime/replay-budget.d.ts.map +1 -0
  93. package/dist/runtime/replay-budget.js +139 -0
  94. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  95. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  96. package/dist/runtime/replay-recovery-reporter.js +64 -0
  97. package/dist/runtime/resume-hook.d.ts +91 -8
  98. package/dist/runtime/resume-hook.d.ts.map +1 -1
  99. package/dist/runtime/resume-hook.js +512 -89
  100. package/dist/runtime/resume-latency.d.ts +150 -0
  101. package/dist/runtime/resume-latency.d.ts.map +1 -0
  102. package/dist/runtime/resume-latency.js +155 -0
  103. package/dist/runtime/run-id-time.d.ts +19 -0
  104. package/dist/runtime/run-id-time.d.ts.map +1 -0
  105. package/dist/runtime/run-id-time.js +42 -0
  106. package/dist/runtime/run.d.ts +72 -7
  107. package/dist/runtime/run.d.ts.map +1 -1
  108. package/dist/runtime/run.js +280 -53
  109. package/dist/runtime/runs.d.ts +54 -3
  110. package/dist/runtime/runs.d.ts.map +1 -1
  111. package/dist/runtime/runs.js +126 -16
  112. package/dist/runtime/start.d.ts +101 -2
  113. package/dist/runtime/start.d.ts.map +1 -1
  114. package/dist/runtime/start.js +352 -61
  115. package/dist/runtime/step-executor.d.ts +186 -5
  116. package/dist/runtime/step-executor.d.ts.map +1 -1
  117. package/dist/runtime/step-executor.js +768 -130
  118. package/dist/runtime/step-latency.d.ts +220 -0
  119. package/dist/runtime/step-latency.d.ts.map +1 -0
  120. package/dist/runtime/step-latency.js +215 -0
  121. package/dist/runtime/step-ownership.d.ts +72 -0
  122. package/dist/runtime/step-ownership.d.ts.map +1 -0
  123. package/dist/runtime/step-ownership.js +114 -0
  124. package/dist/runtime/step-single-flight.d.ts +12 -0
  125. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  126. package/dist/runtime/step-single-flight.js +75 -0
  127. package/dist/runtime/suspension-handler.d.ts +247 -7
  128. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  129. package/dist/runtime/suspension-handler.js +1304 -125
  130. package/dist/runtime/unserializable-step.d.ts +34 -0
  131. package/dist/runtime/unserializable-step.d.ts.map +1 -0
  132. package/dist/runtime/unserializable-step.js +52 -0
  133. package/dist/runtime/vm-mode.d.ts +44 -0
  134. package/dist/runtime/vm-mode.d.ts.map +1 -0
  135. package/dist/runtime/vm-mode.js +62 -0
  136. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  137. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  138. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  139. package/dist/runtime/wait-continuation.d.ts +106 -0
  140. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  141. package/dist/runtime/wait-continuation.js +136 -0
  142. package/dist/runtime/wait-until.d.ts +18 -0
  143. package/dist/runtime/wait-until.d.ts.map +1 -0
  144. package/dist/runtime/wait-until.js +42 -0
  145. package/dist/runtime/world-compatibility.d.ts +32 -0
  146. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  147. package/dist/runtime/world-compatibility.js +44 -0
  148. package/dist/runtime/world-init.d.ts +17 -42
  149. package/dist/runtime/world-init.d.ts.map +1 -1
  150. package/dist/runtime/world-init.js +18 -43
  151. package/dist/runtime/world.d.ts +14 -2
  152. package/dist/runtime/world.d.ts.map +1 -1
  153. package/dist/runtime/world.js +75 -19
  154. package/dist/runtime.d.ts +10 -6
  155. package/dist/runtime.d.ts.map +1 -1
  156. package/dist/runtime.js +3911 -489
  157. package/dist/sealed-box.d.ts +167 -0
  158. package/dist/sealed-box.d.ts.map +1 -0
  159. package/dist/sealed-box.js +571 -0
  160. package/dist/serialization/client.d.ts +3 -3
  161. package/dist/serialization/client.d.ts.map +1 -1
  162. package/dist/serialization/client.js +8 -4
  163. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  164. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  165. package/dist/serialization/codec-devalue-vm.js +148 -0
  166. package/dist/serialization/codec-devalue.d.ts +1 -1
  167. package/dist/serialization/codec-devalue.d.ts.map +1 -1
  168. package/dist/serialization/codec-devalue.js +24 -6
  169. package/dist/serialization/codec.d.ts +37 -2
  170. package/dist/serialization/codec.d.ts.map +1 -1
  171. package/dist/serialization/codec.js +2 -2
  172. package/dist/serialization/compression.d.ts +105 -0
  173. package/dist/serialization/compression.d.ts.map +1 -0
  174. package/dist/serialization/compression.js +261 -0
  175. package/dist/serialization/encryption.d.ts +119 -17
  176. package/dist/serialization/encryption.d.ts.map +1 -1
  177. package/dist/serialization/encryption.js +152 -17
  178. package/dist/serialization/errors.d.ts +13 -0
  179. package/dist/serialization/errors.d.ts.map +1 -1
  180. package/dist/serialization/errors.js +20 -2
  181. package/dist/serialization/format.d.ts +6 -6
  182. package/dist/serialization/format.js +7 -7
  183. package/dist/serialization/hardened.d.ts +156 -0
  184. package/dist/serialization/hardened.d.ts.map +1 -0
  185. package/dist/serialization/hardened.js +538 -0
  186. package/dist/serialization/index.d.ts +10 -8
  187. package/dist/serialization/index.d.ts.map +1 -1
  188. package/dist/serialization/index.js +10 -8
  189. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  190. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  191. package/dist/serialization/reducers/class-vm.js +77 -0
  192. package/dist/serialization/reducers/class.d.ts.map +1 -1
  193. package/dist/serialization/reducers/class.js +11 -6
  194. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  195. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  196. package/dist/serialization/reducers/common-vm.js +616 -0
  197. package/dist/serialization/reducers/common.d.ts +1 -1
  198. package/dist/serialization/reducers/common.d.ts.map +1 -1
  199. package/dist/serialization/reducers/common.js +202 -62
  200. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  201. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  202. package/dist/serialization/reducers/step-function-vm.js +97 -0
  203. package/dist/serialization/reducers/step-function.d.ts.map +1 -1
  204. package/dist/serialization/reducers/step-function.js +25 -9
  205. package/dist/serialization/step.d.ts +4 -4
  206. package/dist/serialization/step.d.ts.map +1 -1
  207. package/dist/serialization/step.js +9 -5
  208. package/dist/serialization/types.d.ts +80 -1
  209. package/dist/serialization/types.d.ts.map +1 -1
  210. package/dist/serialization/types.js +15 -1
  211. package/dist/serialization/workflow-vm.d.ts +29 -0
  212. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  213. package/dist/serialization/workflow-vm.js +74 -0
  214. package/dist/serialization-format.d.ts +64 -8
  215. package/dist/serialization-format.d.ts.map +1 -1
  216. package/dist/serialization-format.js +225 -73
  217. package/dist/serialization.d.ts +262 -34
  218. package/dist/serialization.d.ts.map +1 -1
  219. package/dist/serialization.js +1885 -277
  220. package/dist/set-attributes.d.ts +13 -0
  221. package/dist/set-attributes.d.ts.map +1 -0
  222. package/dist/set-attributes.js +60 -0
  223. package/dist/source-map.d.ts +25 -0
  224. package/dist/source-map.d.ts.map +1 -1
  225. package/dist/source-map.js +154 -10
  226. package/dist/step/context-storage.d.ts +63 -2
  227. package/dist/step/context-storage.d.ts.map +1 -1
  228. package/dist/step/context-storage.js +7 -5
  229. package/dist/step/writable-stream.d.ts +3 -3
  230. package/dist/step/writable-stream.d.ts.map +1 -1
  231. package/dist/step/writable-stream.js +80 -13
  232. package/dist/step.d.ts.map +1 -1
  233. package/dist/step.js +148 -27
  234. package/dist/symbols.d.ts +50 -0
  235. package/dist/symbols.d.ts.map +1 -1
  236. package/dist/symbols.js +51 -1
  237. package/dist/telemetry/semantic-conventions.d.ts +433 -2
  238. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  239. package/dist/telemetry/semantic-conventions.js +319 -3
  240. package/dist/telemetry.d.ts +91 -0
  241. package/dist/telemetry.d.ts.map +1 -1
  242. package/dist/telemetry.js +244 -17
  243. package/dist/test-support/orchestrator-context.d.ts +25 -0
  244. package/dist/test-support/orchestrator-context.d.ts.map +1 -0
  245. package/dist/test-support/orchestrator-context.js +107 -0
  246. package/dist/types.d.ts +6 -0
  247. package/dist/types.d.ts.map +1 -1
  248. package/dist/types.js +23 -1
  249. package/dist/util.d.ts +0 -5
  250. package/dist/util.d.ts.map +1 -1
  251. package/dist/util.js +1 -15
  252. package/dist/version.d.ts +1 -1
  253. package/dist/version.d.ts.map +1 -1
  254. package/dist/version.js +2 -2
  255. package/dist/vm/index.d.ts.map +1 -1
  256. package/dist/vm/index.js +84 -14
  257. package/dist/vm/script-cache.d.ts +26 -0
  258. package/dist/vm/script-cache.d.ts.map +1 -0
  259. package/dist/vm/script-cache.js +131 -0
  260. package/dist/vm/uint8array-base64.js +1 -1
  261. package/dist/workflow/abort-controller.d.ts +2 -2
  262. package/dist/workflow/abort-controller.d.ts.map +1 -1
  263. package/dist/workflow/abort-controller.js +88 -21
  264. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  265. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  266. package/dist/workflow/attribute-dispatcher.js +45 -0
  267. package/dist/workflow/create-hook.d.ts.map +1 -1
  268. package/dist/workflow/create-hook.js +24 -3
  269. package/dist/workflow/get-workflow-metadata.js +2 -2
  270. package/dist/workflow/hook.d.ts.map +1 -1
  271. package/dist/workflow/hook.js +304 -47
  272. package/dist/workflow/index.d.ts +1 -0
  273. package/dist/workflow/index.d.ts.map +1 -1
  274. package/dist/workflow/index.js +2 -1
  275. package/dist/workflow/set-attributes.d.ts +68 -0
  276. package/dist/workflow/set-attributes.d.ts.map +1 -0
  277. package/dist/workflow/set-attributes.js +60 -0
  278. package/dist/workflow/sleep.d.ts.map +1 -1
  279. package/dist/workflow/sleep.js +58 -12
  280. package/dist/workflow/world-init-stub.d.ts +3 -3
  281. package/dist/workflow/world-init-stub.js +4 -4
  282. package/dist/workflow.d.ts +95 -3
  283. package/dist/workflow.d.ts.map +1 -1
  284. package/dist/workflow.js +900 -561
  285. package/docs/api-reference/create-hook.mdx +89 -10
  286. package/docs/api-reference/create-webhook.mdx +16 -15
  287. package/docs/api-reference/define-hook.mdx +35 -33
  288. package/docs/api-reference/fatal-error.mdx +30 -8
  289. package/docs/api-reference/fetch.mdx +14 -10
  290. package/docs/api-reference/get-step-metadata.mdx +2 -2
  291. package/docs/api-reference/get-workflow-metadata.mdx +3 -3
  292. package/docs/api-reference/get-writable.mdx +7 -7
  293. package/docs/api-reference/index.mdx +4 -1
  294. package/docs/api-reference/retryable-error.mdx +1 -1
  295. package/docs/api-reference/set-attributes.mdx +61 -0
  296. package/docs/api-reference/sleep.mdx +4 -4
  297. package/docs/foundations/cancellation.mdx +31 -32
  298. package/docs/foundations/errors-and-retries.mdx +42 -11
  299. package/docs/foundations/hooks.mdx +64 -35
  300. package/docs/foundations/idempotency.mdx +244 -12
  301. package/docs/foundations/index.mdx +1 -23
  302. package/docs/foundations/meta.json +2 -1
  303. package/docs/foundations/serialization.mdx +21 -22
  304. package/docs/foundations/starting-workflows.mdx +106 -30
  305. package/docs/foundations/streaming.mdx +108 -60
  306. package/docs/foundations/versioning.mdx +263 -0
  307. package/docs/foundations/workflows-and-steps.mdx +9 -9
  308. package/docs/how-it-works/cancellation.mdx +63 -63
  309. package/docs/how-it-works/code-transform.mdx +83 -67
  310. package/docs/how-it-works/encryption.mdx +30 -26
  311. package/docs/how-it-works/event-sourcing.mdx +125 -34
  312. package/docs/how-it-works/framework-integrations.mdx +96 -337
  313. package/docs/how-it-works/understanding-directives.mdx +22 -22
  314. package/package.json +24 -15
  315. package/dist/runtime/step-handler.d.ts +0 -2
  316. package/dist/runtime/step-handler.d.ts.map +0 -1
  317. package/dist/runtime/step-handler.js +0 -776
@@ -0,0 +1,1863 @@
1
+ /**
2
+ * QuickJS WebAssembly (WASM) VM integration with the Workflow DevKit.
3
+ *
4
+ * This module provides the entry point for running workflows in the
5
+ * QuickJS VM engine instead of the `node:vm` engine. Both engines
6
+ * implement the same event-replay execution model, where every invocation:
7
+ *
8
+ * 1. Loads the full event log for the run
9
+ * 2. Runs the workflow function from the top in a fresh QuickJS VM,
10
+ * replaying the event log to resolve awaited primitives
11
+ * 3. On suspension: creates events + queues steps for new pending ops
12
+ * 4. On completion: creates run_completed
13
+ * 5. On failure: creates run_failed
14
+ */
15
+ import { EntityConflictError, HookNotFoundError, MaxEventsExceededError, RunExpiredError, WorkflowNotRegisteredError, } from '@workflow/errors';
16
+ import { parseWorkflowName } from '@workflow/utils/parse-name';
17
+ import { ROOT_RUN_ID_ATTRIBUTE, SPEC_VERSION_CURRENT, SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT, SPEC_VERSION_SUPPORTS_COMPRESSION, } from '@workflow/world';
18
+ import { classifyRunError, isRetryableWorldError } from '../classify-error.js';
19
+ import { runtimeLogger } from '../logger.js';
20
+ import { deriveRunPayloadKeys, encrypt as encryptSerializedData, } from '../serialization/encryption.js';
21
+ import { dehydrateRunError, dehydrateStepArguments, dehydrateStepError, hydrateRunError, maybeEncrypt, } from '../serialization.js';
22
+ import { remapErrorStack, stripInlineSourceMap } from '../source-map.js';
23
+ import * as Attribute from '../telemetry/semantic-conventions.js';
24
+ import { serializeTraceCarrier } from '../telemetry.js';
25
+ import { getInlineOwnershipLeaseSeconds, getMaxInlineSteps, isResilientStepDispatchEnabled, MAX_RESILIENT_STEP_INPUT_BYTES, } from './constants.js';
26
+ import { getPortLazy } from './get-port-lazy.js';
27
+ import { getWorkflowQueueName, queueMessage, runDispatchContext, stepDispatchIdempotencyKey, } from './helpers.js';
28
+ import { QuickJSLogView } from './quickjs-log-view.js';
29
+ import { BASELINE_BUNDLE_FILENAME, startQuickJSWorkflow, } from './quickjs-runtime.js';
30
+ import { ReplayBudget } from './replay-budget.js';
31
+ import { executeStep } from './step-executor.js';
32
+ import { runStepSingleFlight } from './step-single-flight.js';
33
+ import { unserializableStepInputPlaceholder } from './unserializable-step.js';
34
+ import { getWaitContinuationDispatch } from './wait-continuation.js';
35
+ import { getWorld } from './world.js';
36
+ /** Tiny ms timer using performance.now(), already monotonic on Node. */
37
+ function tick() {
38
+ return performance.now();
39
+ }
40
+ /**
41
+ * Returns true when the supplied preloaded events indicate this is the
42
+ * first workflow handler invocation for the run, i.e. the log contains
43
+ * nothing beyond `run_created` / `run_started`. In that case the
44
+ * preloaded events ARE the complete event log and the `events.list`
45
+ * round-trips can be skipped entirely.
46
+ *
47
+ * Crucially, if the world backfilled a missing `run_created` via the
48
+ * resilient start path, `preloadedEvents` contains it even when a fresh
49
+ * `events.list` might not (eventual consistency), so preferring the
50
+ * preloaded events on first invocation is also the more correct choice.
51
+ *
52
+ * Returns false when `preloadedEvents` is missing/empty so the caller
53
+ * falls back to the normal fetch path.
54
+ *
55
+ * Exported for unit testing.
56
+ */
57
+ export function isFirstInvocation(preloadedEvents) {
58
+ if (!Array.isArray(preloadedEvents) || preloadedEvents.length === 0) {
59
+ return false;
60
+ }
61
+ return preloadedEvents.every((e) => e.eventType === 'run_created' || e.eventType === 'run_started');
62
+ }
63
+ /**
64
+ * Queue a step for background execution via the unified workflow queue
65
+ * (V2 architecture). The combined handler in runtime.ts dispatches
66
+ * messages with `stepId` to executeStep, which works for both VM engines.
67
+ * `delaySeconds` supports retry/throttle backoff.
68
+ */
69
+ async function queueStepMessage(params) {
70
+ const { world, runId, workflowRun, step, delaySeconds, namespace, nextTraceCarrier, purpose, stepInput, wfdiag, } = params;
71
+ const traceCarrier = await nextTraceCarrier();
72
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
73
+ runId,
74
+ stepId: step.correlationId,
75
+ stepName: step.stepId,
76
+ traceCarrier,
77
+ requestedAt: new Date(),
78
+ ...(stepInput !== undefined ? { stepInput: { input: stepInput } } : {}),
79
+ // Immutable run identity so the consumer can start the step without a
80
+ // blocking runs.get — see RunDispatchContextSchema.
81
+ runContext: runDispatchContext(workflowRun),
82
+ }, {
83
+ // The 'dispatch' key is step-identity-scoped (correlationId + hashed
84
+ // step name), shared with the node engine's dispatch of the same step
85
+ // so the two stay mutually exclusive, without a revoked resilient
86
+ // message absorbing a reassigned correlation id's legitimate dispatch.
87
+ // See stepDispatchIdempotencyKey.
88
+ idempotencyKey: purpose === 'dispatch'
89
+ ? stepDispatchIdempotencyKey(step.correlationId, step.stepId)
90
+ : `${step.correlationId}:${purpose}`,
91
+ ...(delaySeconds && delaySeconds > 0 ? { delaySeconds } : {}),
92
+ });
93
+ wfdiag('step_queued', {
94
+ stepId: step.stepId,
95
+ correlationId: step.correlationId,
96
+ purpose,
97
+ delaySeconds: delaySeconds ?? 0,
98
+ ...(stepInput !== undefined ? { resilient: true } : {}),
99
+ });
100
+ }
101
+ /**
102
+ * Dispatch durable side effects for a set of pending VM operations:
103
+ * step_created (+ optional queueing), hook_created / hook_received (aborts),
104
+ * attr_set, hook_disposed, and wait_created events.
105
+ *
106
+ * Steps are created but (usually) not queued here: queueing (or inline
107
+ * execution) is the caller's decision. Used both for suspension
108
+ * processing (the inline loop) and for the terminal drain (flushing
109
+ * leftover side effects when the workflow completed or failed, mirroring
110
+ * the node:vm engine's drainPendingQueueItems).
111
+ *
112
+ * The one exception is resilient step dispatch: for step cids named in
113
+ * `queueStepCids` (the caller's overflow steps) that pass the eligibility
114
+ * gates, the step_created write is parallelized with the step's queue
115
+ * publish: the message carries the serialized input (`stepInput`) so the
116
+ * consumer can idempotently re-ensure the event if the direct write failed
117
+ * transiently. Steps queued this way are reported in `queuedStepCids`; the
118
+ * caller queues the rest itself.
119
+ */
120
+ async function dispatchPendingOps(params) {
121
+ const { world, runId, workflowRun, encryptionKey, pendingOperations, namespace, nextTraceCarrier, createEvent, } = params;
122
+ const skipStepCreation = params.skipStepCreation;
123
+ const queueStepCids = params.queueStepCids;
124
+ const wfdiag = params.wfdiag;
125
+ // Step cids published via resilient dispatch below (create + queue in
126
+ // parallel, message carrying `stepInput`). Reported to the caller so it
127
+ // skips them in its own queueing pass.
128
+ const queuedStepCids = new Set();
129
+ // Step cids finalized as step_created + step_failed because their input
130
+ // refused to serialize. See the `finalizeUnserializableSteps` param.
131
+ const failedSerializationStepCids = new Set();
132
+ // Resilient step dispatch eligibility, shared by every step op below (the
133
+ // per-step input-size check is applied inside the op): feature enabled and
134
+ // a binary-safe (CBOR) queue transport for the run.
135
+ //
136
+ // Unlike the node:vm suspension handler's gate (see
137
+ // SuspensionHandlerParams.stepDispatch), there is NO precondition-guard
138
+ // gate here: this engine's step_created writes are unguarded (no snapshot
139
+ // is attached), so a guard-enforcing World can never 412-reject them:
140
+ // the consumer's re-ensure therefore cannot materialize a step the guard
141
+ // rejected. If this engine ever adopts guarded suspension writes, the
142
+ // capability gate from the node:vm handler must be added here too.
143
+ const resilientDispatchEligible = queueStepCids !== undefined &&
144
+ queueStepCids.size > 0 &&
145
+ isResilientStepDispatchEnabled() &&
146
+ (workflowRun.specVersion ?? 0) >=
147
+ SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT;
148
+ // Set when a hook with a parked getConflict() awaiter had its
149
+ // hook_created written this invocation. The workflow must be re-invoked
150
+ // so replay can confirm creation and resolve the awaiter.
151
+ let createdGetConflictHook = false;
152
+ // Set when a new attr_set event is written this invocation. The
153
+ // workflow must be re-invoked to consume it (resolving the pending
154
+ // setAttributes() promise), so the entrypoint requeues immediately,
155
+ // same pattern as an elapsed wait.
156
+ let createdAttributeEvent = false;
157
+ const opsPromises = [];
158
+ const hooksNeedingCreation = pendingOperations.filter((op) => op.type === 'hook' && !op.hasCreatedEvent).length;
159
+ const hookDeltaCursor = hooksNeedingCreation === 1 ? params.deltaCursor : undefined;
160
+ const processHookOp = async (hook) => {
161
+ runtimeLogger.debug('QuickJS runtime: processing hook op', {
162
+ workflowRunId: runId,
163
+ correlationId: hook.correlationId,
164
+ token: hook.token,
165
+ tokenType: typeof hook.token,
166
+ isWebhook: hook.isWebhook,
167
+ isSystem: hook.isSystem,
168
+ hasCreatedEvent: hook.hasCreatedEvent,
169
+ abortRequested: hook.abortRequested,
170
+ });
171
+ if (!hook.hasCreatedEvent) {
172
+ // `hook.metadata` is the format-prefixed devalue bytes
173
+ // produced by `globalThis[Symbol.for('workflow-serialize')]
174
+ // (options.metadata)` inside the VM. Encrypt on the host
175
+ // side before writing, which matches the node:vm engine's
176
+ // `dehydrateStepArguments` flow.
177
+ //
178
+ // No pre-check via hooks.list: with deterministic correlationIds
179
+ // (same VM seed across replays) and per-(runId, correlationId)
180
+ // uniqueness in worlds, the storage layer rejects duplicates as
181
+ // EntityConflictError, which we swallow below. This drops one
182
+ // network round-trip per pending hook.
183
+ try {
184
+ const encryptedMetadata = typeof hook.metadata === 'undefined'
185
+ ? undefined
186
+ : await encryptSerializedData(hook.metadata, encryptionKey);
187
+ const result = await createEvent({
188
+ eventType: 'hook_created',
189
+ specVersion: SPEC_VERSION_CURRENT,
190
+ correlationId: hook.correlationId,
191
+ eventData: {
192
+ token: hook.token,
193
+ tokenRetentionUntil: hook.tokenRetentionUntil === undefined
194
+ ? undefined
195
+ : new Date(hook.tokenRetentionUntil),
196
+ metadata: encryptedMetadata,
197
+ // Always include isWebhook explicitly. Worlds default it to
198
+ // `true` when absent, which would break the public webhook
199
+ // endpoint's 404 guard for hooks created via createHook().
200
+ isWebhook: hook.isWebhook,
201
+ // System hooks (AbortController) are exempt from user
202
+ // token namespace conflict checks.
203
+ ...(hook.isSystem ? { isSystem: true } : {}),
204
+ },
205
+ }, hookDeltaCursor !== undefined
206
+ ? { sinceCursor: hookDeltaCursor }
207
+ : undefined);
208
+ // If storage detected a real token conflict with another
209
+ // workflow's hook, re-queue so the workflow handler can
210
+ // process the conflict event and fail gracefully.
211
+ if (result.event?.eventType === 'hook_conflict') {
212
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
213
+ runId,
214
+ traceCarrier: await nextTraceCarrier(),
215
+ requestedAt: new Date(),
216
+ }, { idempotencyKey: `hook_conflict_${hook.correlationId}` });
217
+ }
218
+ }
219
+ catch (err) {
220
+ // Already created by a concurrent invocation, so fall through
221
+ // to abort processing below (if any) instead of bailing.
222
+ if (!EntityConflictError.is(err))
223
+ throw err;
224
+ }
225
+ if (hook.hasGetConflictAwaiter) {
226
+ createdGetConflictHook = true;
227
+ }
228
+ }
229
+ if (hook.abortRequested) {
230
+ // Record the abort durably: a hook_received event carrying
231
+ // the VM-serialized `{ aborted: true, reason }` payload,
232
+ // plus a best-effort stream packet for real-time step
233
+ // propagation. Mirrors the node:vm engine's suspension
234
+ // handler (hooksNeedingAbort).
235
+ const abortPayload = hook.abortPayload instanceof Uint8Array
236
+ ? (await encryptSerializedData(hook.abortPayload, encryptionKey))
237
+ : undefined;
238
+ try {
239
+ await createEvent({
240
+ eventType: 'hook_received',
241
+ specVersion: SPEC_VERSION_CURRENT,
242
+ correlationId: hook.correlationId,
243
+ eventData: {
244
+ token: hook.token,
245
+ payload: abortPayload,
246
+ },
247
+ });
248
+ }
249
+ catch (err) {
250
+ if (!EntityConflictError.is(err))
251
+ throw err;
252
+ }
253
+ // streamName is derived from the abort hook token
254
+ // (`abrt_{id}` → `strm_{id}_system_abort`).
255
+ if (hook.token.startsWith('abrt_') && abortPayload) {
256
+ const streamName = `strm_${hook.token.slice('abrt_'.length)}_system_abort`;
257
+ try {
258
+ await world.streams.write(runId, streamName, abortPayload);
259
+ await world.streams.close(runId, streamName);
260
+ }
261
+ catch {
262
+ // Best-effort: the hook event provides the durable
263
+ // fallback.
264
+ runtimeLogger.debug('QuickJS runtime: failed to write abort stream packet', {
265
+ workflowRunId: runId,
266
+ correlationId: hook.correlationId,
267
+ });
268
+ }
269
+ }
270
+ wfdiag('abort_recorded', {
271
+ correlationId: hook.correlationId,
272
+ token: hook.token,
273
+ });
274
+ }
275
+ };
276
+ const processHookDisposeOp = async (op) => {
277
+ try {
278
+ await createEvent({
279
+ eventType: 'hook_disposed',
280
+ specVersion: SPEC_VERSION_CURRENT,
281
+ correlationId: op.correlationId,
282
+ // The hook's token, which the node:vm engine has always sent. A world
283
+ // that keys a hook's token claim separately from the hook itself needs
284
+ // it to release both, and the only alternative is for it to look the
285
+ // token up first. Omitted rather than sent as undefined when the op
286
+ // carries none, so a world that reads it cannot tell the difference
287
+ // between this engine and a client too old to send one.
288
+ ...(op.token === undefined ? {} : { eventData: { token: op.token } }),
289
+ });
290
+ }
291
+ catch (err) {
292
+ if (EntityConflictError.is(err))
293
+ return;
294
+ // Disposing a hook whose entity no longer (or never) exists is an
295
+ // idempotent no-op: the entity may have been torn down by a
296
+ // concurrent run cancellation, or the hook may have lost its
297
+ // token claim to a conflict. There is nothing left to release.
298
+ if (HookNotFoundError.is(err))
299
+ return;
300
+ throw err;
301
+ }
302
+ };
303
+ // Hook operations are grouped by token and processed SEQUENTIALLY in
304
+ // code order within each group, mirroring the node:vm suspension
305
+ // handler (hookItemsByToken): a dispose() of an earlier hook must
306
+ // release the token before a later same-token hook's creation is
307
+ // validated by the world: parallel dispatch would otherwise record a
308
+ // spurious hook_conflict against the run's own disposed hook (e.g. a
309
+ // dispose→recreate loop reusing one token). Different tokens have no
310
+ // claim interaction, so token groups run in parallel with each other
311
+ // and with the non-hook ops below.
312
+ const hookOpsByToken = new Map();
313
+ for (const op of pendingOperations) {
314
+ let key;
315
+ if (op.type === 'hook' &&
316
+ (!op.hasCreatedEvent || op.abortRequested)) {
317
+ key = op.token;
318
+ }
319
+ else if (op.type === 'hook_dispose' && !op.hasCreatedEvent) {
320
+ // Per-op fallback group when the token is unknown: no ordering
321
+ // guarantees, matching the previous parallel behavior.
322
+ key = op.token ?? `__cid:${op.correlationId}`;
323
+ }
324
+ if (key === undefined)
325
+ continue;
326
+ const group = hookOpsByToken.get(key);
327
+ if (group) {
328
+ group.push(op);
329
+ }
330
+ else {
331
+ hookOpsByToken.set(key, [op]);
332
+ }
333
+ }
334
+ for (const group of hookOpsByToken.values()) {
335
+ opsPromises.push((async () => {
336
+ for (const op of group) {
337
+ if (op.type === 'hook') {
338
+ await processHookOp(op);
339
+ }
340
+ else {
341
+ await processHookDisposeOp(op);
342
+ }
343
+ }
344
+ })());
345
+ }
346
+ for (const op of pendingOperations) {
347
+ if (op.type === 'step' &&
348
+ !op.hasCreatedEvent &&
349
+ !skipStepCreation?.has(op.correlationId)) {
350
+ const step = op;
351
+ opsPromises.push((async () => {
352
+ // The step's input refused to serialize while dumping the VM's
353
+ // pending ops (see PendingStep.serializationError). Finalize it
354
+ // as step_created (placeholder input, since the world requires the
355
+ // step entity before a terminal event) + step_failed carrying
356
+ // the SerializationError, so the live-VM feed rejects the
357
+ // step's promise and workflow code can catch it. Never queue an
358
+ // execution message for it. Mirrors the node:vm engine's
359
+ // finalizeUnserializableStep. In the terminal drain
360
+ // (finalizeUnserializableSteps unset), skip entirely: see the
361
+ // param docs.
362
+ if (step.serializationError) {
363
+ if (!params.finalizeUnserializableSteps) {
364
+ return;
365
+ }
366
+ runtimeLogger.warn('Step arguments failed to serialize; failing the step so ' +
367
+ 'the workflow can observe the error', {
368
+ workflowRunId: runId,
369
+ correlationId: step.correlationId,
370
+ stepName: step.stepId,
371
+ error: step.serializationError.message,
372
+ });
373
+ try {
374
+ await createEvent({
375
+ eventType: 'step_created',
376
+ specVersion: SPEC_VERSION_CURRENT,
377
+ correlationId: step.correlationId,
378
+ eventData: {
379
+ stepName: step.stepId,
380
+ input: (await dehydrateStepArguments(unserializableStepInputPlaceholder(), runId, encryptionKey, globalThis, false, (workflowRun.specVersion ?? 0) >=
381
+ SPEC_VERSION_SUPPORTS_COMPRESSION)),
382
+ },
383
+ });
384
+ }
385
+ catch (err) {
386
+ // Concurrent invocation hit the same deterministic failure
387
+ // and created it first, or the run already finished.
388
+ if (RunExpiredError.is(err))
389
+ return;
390
+ if (!EntityConflictError.is(err))
391
+ throw err;
392
+ }
393
+ try {
394
+ await createEvent({
395
+ eventType: 'step_failed',
396
+ specVersion: SPEC_VERSION_CURRENT,
397
+ correlationId: step.correlationId,
398
+ eventData: {
399
+ stepName: step.stepId,
400
+ error: await dehydrateStepError(step.serializationError, runId, encryptionKey, [], globalThis, (workflowRun.specVersion ?? 0) >=
401
+ SPEC_VERSION_SUPPORTS_COMPRESSION),
402
+ },
403
+ });
404
+ }
405
+ catch (err) {
406
+ // Step already terminal or run already finished.
407
+ if (!EntityConflictError.is(err) && !RunExpiredError.is(err)) {
408
+ throw err;
409
+ }
410
+ }
411
+ failedSerializationStepCids.add(step.correlationId);
412
+ wfdiag('step_serialization_failed', {
413
+ stepId: step.stepId,
414
+ correlationId: step.correlationId,
415
+ });
416
+ return;
417
+ }
418
+ // Create step_created event. `step.input` is the
419
+ // format-prefixed devalue bytes ("devl" + devalue) produced
420
+ // by `globalThis[Symbol.for('workflow-serialize')]({args,
421
+ // closureVars, thisVal})` inside the VM. The VM has no
422
+ // access to the CryptoKey, so encryption is applied here
423
+ // on the host side, matching what
424
+ // `dehydrateStepArguments` does in the node:vm engine.
425
+ const encryptedInput = await encryptSerializedData(step.input, encryptionKey);
426
+ // Resilient step dispatch: fire the step_created write and the
427
+ // step's queue publish in parallel: the message carries the
428
+ // same serialized input (`stepInput`) so the consumer can
429
+ // idempotently re-ensure the event if the direct write failed
430
+ // transiently. Mirrors the node:vm suspension handler and the
431
+ // resilient start / resilient hook resume patterns. Only for
432
+ // caller-designated overflow steps with inputs the queue
433
+ // message can safely carry (binary, under the VQS size cap).
434
+ if (resilientDispatchEligible &&
435
+ queueStepCids?.has(step.correlationId) &&
436
+ encryptedInput instanceof Uint8Array &&
437
+ encryptedInput.byteLength <= MAX_RESILIENT_STEP_INPUT_BYTES) {
438
+ const [createResult, queueResult] = await Promise.allSettled([
439
+ createEvent({
440
+ eventType: 'step_created',
441
+ specVersion: SPEC_VERSION_CURRENT,
442
+ correlationId: step.correlationId,
443
+ eventData: {
444
+ stepName: step.stepId,
445
+ input: encryptedInput,
446
+ },
447
+ }),
448
+ queueStepMessage({
449
+ world,
450
+ runId,
451
+ workflowRun,
452
+ step,
453
+ namespace,
454
+ nextTraceCarrier,
455
+ purpose: 'dispatch',
456
+ stepInput: encryptedInput,
457
+ wfdiag,
458
+ }),
459
+ ]);
460
+ // Queue failure is always fatal for this dispatch pass:
461
+ // without the message the step would rely on the create
462
+ // alone, and if the create ALSO failed there would be no
463
+ // durable record at all. Propagating redelivers the
464
+ // orchestrator message, which re-creates the (idempotent)
465
+ // step_created and re-dispatches.
466
+ if (queueResult.status === 'rejected') {
467
+ throw queueResult.reason;
468
+ }
469
+ queuedStepCids.add(step.correlationId);
470
+ if (createResult.status === 'rejected') {
471
+ const err = createResult.reason;
472
+ if (EntityConflictError.is(err)) {
473
+ // Concurrent invocation wrote it first: the message is
474
+ // already out; its duplicate publish dedupes on the
475
+ // shared step-identity-scoped idempotency key.
476
+ return;
477
+ }
478
+ if (isRetryableWorldError(err)) {
479
+ // Resilient: the write failed transiently (429 / 5xx /
480
+ // transport) but the step message (carrying the same
481
+ // serialized input) was published, so the consumer
482
+ // idempotently re-ensures the step_created before
483
+ // executing.
484
+ runtimeLogger.warn('Step creation event write failed, but the step was ' +
485
+ 'dispatched via the queue. The step_created event ' +
486
+ 'will be ensured by the queue consumer.', {
487
+ workflowRunId: runId,
488
+ correlationId: step.correlationId,
489
+ stepName: step.stepId,
490
+ error: err instanceof Error ? err.message : String(err),
491
+ });
492
+ wfdiag('step_resilient_dispatch_recovered', {
493
+ stepId: step.stepId,
494
+ correlationId: step.correlationId,
495
+ });
496
+ return;
497
+ }
498
+ throw err;
499
+ }
500
+ return;
501
+ }
502
+ try {
503
+ await createEvent({
504
+ eventType: 'step_created',
505
+ specVersion: SPEC_VERSION_CURRENT,
506
+ correlationId: step.correlationId,
507
+ eventData: {
508
+ stepName: step.stepId,
509
+ input: encryptedInput,
510
+ },
511
+ });
512
+ }
513
+ catch (err) {
514
+ if (EntityConflictError.is(err))
515
+ return;
516
+ throw err;
517
+ }
518
+ // NOTE: step queueing is otherwise the caller's decision: the
519
+ // inline loop executes fresh steps in the live VM and only
520
+ // queues the overflow / retry / backstop cases (see
521
+ // queueStepMessage).
522
+ })());
523
+ }
524
+ else if (op.type === 'attribute' && !op.hasCreatedEvent) {
525
+ const attr = op;
526
+ opsPromises.push((async () => {
527
+ try {
528
+ await createEvent({
529
+ eventType: 'attr_set',
530
+ specVersion: SPEC_VERSION_CURRENT,
531
+ correlationId: attr.correlationId,
532
+ eventData: {
533
+ changes: attr.changes,
534
+ writer: { type: 'workflow' },
535
+ ...(attr.allowReservedAttributes
536
+ ? { allowReservedAttributes: true }
537
+ : {}),
538
+ },
539
+ });
540
+ createdAttributeEvent = true;
541
+ }
542
+ catch (err) {
543
+ if (EntityConflictError.is(err)) {
544
+ // Event already exists (concurrent invocation), but the
545
+ // replay still needs to consume it, so requeue.
546
+ createdAttributeEvent = true;
547
+ return;
548
+ }
549
+ throw err;
550
+ }
551
+ })());
552
+ }
553
+ else if (op.type === 'wait' && !op.hasCreatedEvent) {
554
+ const wait = op;
555
+ opsPromises.push((async () => {
556
+ try {
557
+ await createEvent({
558
+ eventType: 'wait_created',
559
+ specVersion: SPEC_VERSION_CURRENT,
560
+ correlationId: wait.correlationId,
561
+ eventData: {
562
+ resumeAt: new Date(wait.resumeAt),
563
+ },
564
+ });
565
+ }
566
+ catch (err) {
567
+ if (EntityConflictError.is(err))
568
+ return;
569
+ throw err;
570
+ }
571
+ })());
572
+ }
573
+ }
574
+ // Per-op dispatch runs in parallel.
575
+ await Promise.all(opsPromises);
576
+ return {
577
+ createdAttributeEvent,
578
+ createdGetConflictHook,
579
+ queuedStepCids,
580
+ failedSerializationStepCids,
581
+ };
582
+ }
583
+ /**
584
+ * Run a workflow using the QuickJS WASM VM engine.
585
+ *
586
+ * This replaces the `node:vm` replay path (runWorkflow + EventsConsumer)
587
+ * with a QuickJS VM invocation that performs the same full event replay.
588
+ *
589
+ * Log position on writes. This engine follows the same rule as the node:vm
590
+ * replay loop for which writes tell the World where the writer stood (see the
591
+ * "Who names a position" table above `slotSnapshotParams` in `helpers.ts`):
592
+ *
593
+ * - Writes made from this invocation's view of the log (`step_created`,
594
+ * `wait_created`, `hook_created`, `hook_disposed`, `attr_set`, the abort
595
+ * `hook_received`, `wait_completed`, and the `step_created` + `step_failed`
596
+ * pair for an unserializable input) carry `eventCount`, and the page a
597
+ * World hands back is queued for the live VM through {@link QuickJSLogView}.
598
+ * - A single inline step's terminal write asks for the inline delta
599
+ * (`sinceCursor`) through `executeStep`, and so does a lone `hook_created`
600
+ * (see `dispatchPendingOps.deltaCursor`); the delta is queued the same
601
+ * way. The step executor's other writes carry nothing: it holds no log.
602
+ * - Run-terminal writes (`run_completed`, `run_failed`) and the terminal drain
603
+ * of pending ops carry nothing: nothing reads the log afterwards.
604
+ *
605
+ * What differs from the node engine is what "merge into the log" means. The
606
+ * node engine merges a returned page into the array it replays from. This
607
+ * engine holds a live VM that consumes events exactly once, in position
608
+ * order, so a returned page is queued and delivered ahead of the next
609
+ * `events.list`, which then only runs when the queue cannot account for the
610
+ * next position. Both engines fall back to a list for anything a page did
611
+ * not carry.
612
+ */
613
+ export async function runWorkflowWithQuickJS(params) {
614
+ const { workflowCode, workflowName, workflowRun, preloadedEvents, preloadedEventsComplete, preloadedCursor, runInput, parentSpan, maxEventsLimit, deliveryAttempt, ownerMessageId, requestId, namespace, waitContinuation, } = params;
615
+ /**
616
+ * Attempt number for the continuation this invocation is about to arm for
617
+ * `correlationId`. One higher than the incoming continuation's when this
618
+ * invocation IS that continuation and the wait is still pending — the only
619
+ * situation in which the previous key is spent. Every other caller, and
620
+ * every other wait, starts at 0 and keys exactly as it did before attempts
621
+ * existed.
622
+ */
623
+ const nextWaitContinuationAttempt = (correlationId) => waitContinuation?.correlationId === correlationId
624
+ ? waitContinuation.attempt + 1
625
+ : 0;
626
+ // Standalone-caller fallback (tests): without a runtime.ts carrier
627
+ // accessor, fall back to the current invocation context.
628
+ const nextTraceCarrier = params.nextTraceCarrier ?? (() => serializeTraceCarrier());
629
+ const world = await getWorld();
630
+ const runId = workflowRun.runId;
631
+ const invocationStart = tick();
632
+ // Strip the inline source map comment before evaluating the bundle in
633
+ // the QuickJS VM. The map is purely host-side metadata for
634
+ // `remapErrorStack` (called below on workflow failures, against the
635
+ // ORIGINAL `workflowCode`). QuickJS retains source text for
636
+ // stack-trace line lookups, so the few-MB base64 comment would bloat
637
+ // the VM heap for no benefit.
638
+ const workflowCodeForVM = stripInlineSourceMap(workflowCode);
639
+ // Per-invocation diagnostic id so debug logs can be correlated even if
640
+ // the same runId is processed by overlapping invocations on different
641
+ // function instances.
642
+ const invocationId = `inv_${Math.random().toString(36).slice(2, 10)}`;
643
+ // Structured per-checkpoint diagnostic helper, grep-friendly by runId.
644
+ const wfdiag = (checkpoint, fields) => {
645
+ runtimeLogger.debug('QUICKJS_VM_DIAG', {
646
+ checkpoint,
647
+ runId,
648
+ invocationId,
649
+ tElapsedMs: Math.round(tick() - invocationStart),
650
+ ...fields,
651
+ });
652
+ };
653
+ parentSpan?.setAttributes({
654
+ ...Attribute.WorkflowVm('quickjs'),
655
+ });
656
+ wfdiag('enter', {
657
+ workflowName,
658
+ deliveryAttempt,
659
+ hasPreloadedEvents: Array.isArray(preloadedEvents) && preloadedEvents.length > 0,
660
+ preloadedEventCount: preloadedEvents?.length ?? 0,
661
+ hasRunInput: !!runInput,
662
+ });
663
+ // The workflowName from the queue topic is already the full workflow ID
664
+ // (e.g. "workflow//./workflows/1_simple//simple")
665
+ const workflowId = workflowName;
666
+ // Resolve the encryption key up front: needed to decrypt event
667
+ // payloads inside the VM and to encrypt event payloads written below.
668
+ // Resolve the FULL capability (symmetric AES key + X25519 keypair), not
669
+ // just `importKey(rawKey)`: a run reading its own event log can encounter
670
+ // sealed (`encp`) hook payloads that a cross-deployment `resumeHook()`
671
+ // wrote to it (sealing is presence-gated on the run's published
672
+ // encryptionPublicKey, which the shared start() path stamps regardless of
673
+ // engine). A bare symmetric key cannot open those and would wedge the run
674
+ // right after hook_received. The node:vm engine resolves the same full
675
+ // capability via memoizeEncryptionKey.
676
+ const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
677
+ const encryptionKey = rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
678
+ // Load the FULL event log for the run. On first invocation the
679
+ // preloaded events from the run_started response are the complete log
680
+ // and save the events.list round-trips; a caller-attested complete
681
+ // preload (lazy hook fast path) is trusted the same way.
682
+ let events;
683
+ let eventsFetchedPages = 0;
684
+ // Where the log was read to: the cursor after the last page below, or the
685
+ // one the caller read the preload to. Seeds the incremental reads and the
686
+ // inline-delta requests that follow.
687
+ let loadedCursor = null;
688
+ const usePreloaded = (preloadedEventsComplete === true &&
689
+ Array.isArray(preloadedEvents) &&
690
+ preloadedEvents.length > 0) ||
691
+ isFirstInvocation(preloadedEvents);
692
+ if (usePreloaded && preloadedEvents) {
693
+ events = preloadedEvents;
694
+ loadedCursor = preloadedCursor ?? null;
695
+ }
696
+ else {
697
+ const allEvents = [];
698
+ let cursor = null;
699
+ let hasMore = true;
700
+ while (hasMore) {
701
+ const response = await world.events.list({
702
+ runId,
703
+ pagination: {
704
+ sortOrder: 'asc',
705
+ cursor: cursor ?? undefined,
706
+ limit: 1000,
707
+ },
708
+ });
709
+ eventsFetchedPages++;
710
+ allEvents.push(...response.data);
711
+ // Update the cursor to the last successfully fetched page's cursor.
712
+ // Only update when we got results: the final empty-page response
713
+ // returns cursor=null which we must NOT use (it would reset the cursor).
714
+ if (response.cursor) {
715
+ cursor = response.cursor;
716
+ }
717
+ hasMore = response.data.length > 0 && response.cursor != null;
718
+ }
719
+ events = allEvents;
720
+ loadedCursor = cursor;
721
+ }
722
+ // This invocation's view of the log, and the queue of events a World has
723
+ // handed back on a write that the VM has not been given yet. Every write
724
+ // made from this view goes through `createEvent` below so it names the
725
+ // position it was decided against and its response is queued here.
726
+ const logView = new QuickJSLogView(events, loadedCursor);
727
+ const createEvent = async (data, eventParams) => {
728
+ const result = await world.events.create(runId, data, {
729
+ ...eventParams,
730
+ ...logView.snapshotParams(),
731
+ });
732
+ if (typeof eventParams?.sinceCursor === 'string' &&
733
+ result.events !== undefined) {
734
+ // The write asked for the inline delta and got one: everything after
735
+ // the cursor, this write included, read with refs resolved. Taken
736
+ // through the delta path so the cursor moves with it when that is
737
+ // safe; the created event's position is noted either way.
738
+ logView.absorb({ event: result.event });
739
+ const advanced = logView.absorbDelta(eventParams.sinceCursor, {
740
+ events: result.events,
741
+ cursor: result.cursor ?? null,
742
+ hasMore: result.hasMore ?? false,
743
+ });
744
+ wfdiag('inline_delta_absorbed', {
745
+ eventType: data.eventType,
746
+ events: result.events.length,
747
+ hasMore: result.hasMore ?? false,
748
+ cursorAdvanced: advanced,
749
+ });
750
+ return result;
751
+ }
752
+ // The created event is delivered off the response only when it carries
753
+ // no payload a VM reads; every other type waits for a page or a listing,
754
+ // which return it with its refs resolved. See QuickJSLogView.
755
+ const absorbed = logView.absorb(result, {
756
+ deliverEvent: data.eventType === 'wait_completed',
757
+ });
758
+ if (absorbed.truncated) {
759
+ runtimeLogger.debug('QuickJS runtime: dropped a truncated skipped-slot report', {
760
+ workflowRunId: runId,
761
+ eventType: data.eventType,
762
+ eventId: result.event?.eventId,
763
+ offered: result.events?.length ?? 0,
764
+ });
765
+ }
766
+ return result;
767
+ };
768
+ /**
769
+ * The create for writes that end the run (`run_completed`, `run_failed`,
770
+ * and the terminal drain of leftover ops): no position named and no page
771
+ * asked for, because nothing replays a finished run's log. The node
772
+ * engine's `deltaRequestCursor` makes the same exclusion for `sinceCursor`.
773
+ */
774
+ const terminalCreateEvent = (data, eventParams) => world.events.create(runId, data, eventParams);
775
+ // Event-limit guard: fail a runaway run once its log reaches the
776
+ // server-supplied ceiling, the same enforcement point as the node:vm
777
+ // engine's replay loop.
778
+ if (maxEventsLimit !== undefined && events.length >= maxEventsLimit) {
779
+ throw new MaxEventsExceededError(events.length, maxEventsLimit);
780
+ }
781
+ parentSpan?.setAttributes({
782
+ ...Attribute.QuickJSEventsPreloaded(usePreloaded),
783
+ ...Attribute.QuickJSEventsFetchedCount(events.length),
784
+ ...Attribute.QuickJSEventsFetchedPages(eventsFetchedPages),
785
+ });
786
+ wfdiag('events_fetched', {
787
+ eventCount: events.length,
788
+ eventsFetchedPages,
789
+ usePreloaded,
790
+ eventTypes: events.reduce((acc, e) => {
791
+ acc[e.eventType] = (acc[e.eventType] ?? 0) + 1;
792
+ return acc;
793
+ }, {}),
794
+ });
795
+ // Check for elapsed waits
796
+ const now = Date.now();
797
+ const completedWaitIds = new Set(events
798
+ .filter((e) => e.eventType === 'wait_completed')
799
+ .map((e) => e.correlationId));
800
+ for (const event of events) {
801
+ if (event.eventType === 'wait_created' &&
802
+ event.correlationId &&
803
+ !completedWaitIds.has(event.correlationId)) {
804
+ const eventData = 'eventData' in event
805
+ ? event.eventData
806
+ : undefined;
807
+ const resumeAt = eventData?.resumeAt;
808
+ if (resumeAt && now >= new Date(resumeAt).getTime()) {
809
+ try {
810
+ const result = await createEvent({
811
+ eventType: 'wait_completed',
812
+ specVersion: SPEC_VERSION_CURRENT,
813
+ correlationId: event.correlationId,
814
+ });
815
+ if (!logView.tracking && result.event) {
816
+ // No positions to order by (see QuickJSLogView), so the event
817
+ // joins the initial log directly, as it always has.
818
+ events.push(result.event);
819
+ }
820
+ }
821
+ catch (err) {
822
+ if (EntityConflictError.is(err))
823
+ continue;
824
+ throw err;
825
+ }
826
+ }
827
+ }
828
+ }
829
+ // The VM has not started, so whatever those writes handed back (each
830
+ // wait_completed, plus anything another writer appended that they skipped
831
+ // over) joins the initial log instead of waiting for a feed.
832
+ events.push(...logView.takeContiguous());
833
+ // Resolve the workflow server port so `getWorkflowMetadata().url` inside
834
+ // the VM matches what the step-side handler reports. Skipped on Vercel:
835
+ // the VM reads VERCEL_URL directly in that environment.
836
+ const isVercel = process.env.VERCEL_URL !== undefined;
837
+ const port = isVercel ? undefined : await getPortLazy();
838
+ // Run the workflow in the QuickJS VM
839
+ runtimeLogger.debug('QuickJS runtime: invoking VM', {
840
+ workflowRunId: runId,
841
+ workflowId,
842
+ eventCount: events.length,
843
+ });
844
+ const session = await startQuickJSWorkflow({
845
+ // Pass the STRIPPED bundle to the VM so the inline source map
846
+ // doesn't end up in the QuickJS heap. The original (unstripped)
847
+ // `workflowCode` is still kept in this host-side scope and is used
848
+ // by `remapErrorStack` on workflow failures below.
849
+ workflowCode: workflowCodeForVM,
850
+ workflowId,
851
+ workflowRun,
852
+ events,
853
+ worldCapabilities: world.capabilities,
854
+ encryptionKey,
855
+ port,
856
+ runInput,
857
+ });
858
+ let result = session.result;
859
+ runtimeLogger.debug('QuickJS runtime: VM returned', {
860
+ workflowRunId: runId,
861
+ completed: !!result.completed,
862
+ suspended: !!result.suspended,
863
+ failed: !!result.failed,
864
+ pendingOpsCount: result.suspended?.pendingOperations?.length,
865
+ });
866
+ wfdiag('vm_returned', {
867
+ outcome: result.completed
868
+ ? 'completed'
869
+ : result.suspended
870
+ ? 'suspended'
871
+ : result.failed
872
+ ? 'failed'
873
+ : 'unknown',
874
+ pendingOpsCount: result.suspended?.pendingOperations?.length ?? 0,
875
+ pendingOpSummary: result.suspended?.pendingOperations?.map((p) => ({
876
+ type: p.type,
877
+ correlationId: p.correlationId,
878
+ hasCreatedEvent: p.hasCreatedEvent,
879
+ ...(p.type === 'step' ? { stepId: p.stepId } : {}),
880
+ })),
881
+ failureMessage: result.failed?.message,
882
+ failureName: result.failed?.name,
883
+ });
884
+ // ---- Inline continuation loop ----
885
+ //
886
+ // While the workflow is suspended, this loop keeps the VM alive and
887
+ // makes as much forward progress as possible within one invocation:
888
+ //
889
+ // 1. Dispatch durable side effects for the suspension's pending ops
890
+ // (step_created / hook_created / attr_set / wait_created /
891
+ // hook_received for aborts) and complete elapsed waits.
892
+ // 2. Feed all newly recorded events (attr_set, hook_created, elapsed
893
+ // wait_completed, terminals written by concurrent invocations, ...)
894
+ // into the LIVE VM via session.continueWithEvents, resuming
895
+ // execution exactly where it left off, no fresh-VM re-replay.
896
+ // Cheap progress is fed BEFORE running step bodies so promise
897
+ // chains that are not gated on steps (hook.getConflict(),
898
+ // setAttributes(), racing sleeps) advance first and can surface
899
+ // additional pending steps for the same inline batch.
900
+ // 3. Once no cheap progress remains, execute up to
901
+ // getMaxInlineSteps() steps created by THIS invocation inline (no
902
+ // queue round-trip), in parallel, with the replay budget paused
903
+ // during step bodies, mirroring the node:vm engine's inline
904
+ // replay loop. Overflow and retry/throttled steps are queued for
905
+ // background execution. A delayed wait-continuation message is
906
+ // enqueued for the soonest pending wait first, so racing timers
907
+ // fire on time (in a separate invocation) while step bodies block
908
+ // this one.
909
+ //
910
+ // The loop exits when the workflow settles, no forward progress is
911
+ // possible in-process, the replay budget is exhausted, or the run is
912
+ // gone.
913
+ const seenEventIds = new Set();
914
+ for (const e of events) {
915
+ if (e.eventId)
916
+ seenEventIds.add(e.eventId);
917
+ }
918
+ // Step cids already executed inline by this invocation.
919
+ const executedStepIds = new Set();
920
+ // Steps for which THIS invocation already sent a queue message.
921
+ const queuedStepIds = new Set();
922
+ // Aborts THIS invocation already recorded (hook_received written).
923
+ // Guards against re-recording when the VM-side flag has not been
924
+ // cleared yet within the same iteration.
925
+ const recordedAbortIds = new Set();
926
+ // Waits for which THIS invocation already completed/scheduled work.
927
+ const completedWaitIds2 = new Set();
928
+ // Inline-ownership state per step correlationId, derived from every
929
+ // event this invocation observes (initial log + every feed): the
930
+ // quickjs analog of the replay-derived ownership on the node engine's
931
+ // StepInvocationQueueItem (see step-ownership.ts). Latest-wins:
932
+ // events arrive in log order, so a later step_started overwrites the
933
+ // stamp; a step_retrying lapses ownership permanently for the id.
934
+ const stepOwnership = new Map();
935
+ const observeEventsForOwnership = (observed) => {
936
+ for (const e of observed) {
937
+ if (e.correlationId === undefined)
938
+ continue;
939
+ if (e.eventType === 'step_started') {
940
+ const owner = 'eventData' in e &&
941
+ e.eventData &&
942
+ 'ownerMessageId' in e.eventData &&
943
+ typeof e.eventData.ownerMessageId === 'string'
944
+ ? e.eventData.ownerMessageId
945
+ : undefined;
946
+ const prior = stepOwnership.get(e.correlationId);
947
+ stepOwnership.set(e.correlationId, {
948
+ owner,
949
+ startedAtMs: e.createdAt ? +new Date(e.createdAt) : undefined,
950
+ sawRetrying: prior?.sawRetrying ?? false,
951
+ });
952
+ }
953
+ else if (e.eventType === 'step_retrying') {
954
+ const prior = stepOwnership.get(e.correlationId);
955
+ stepOwnership.set(e.correlationId, {
956
+ ...(prior ?? {}),
957
+ sawRetrying: true,
958
+ });
959
+ }
960
+ }
961
+ };
962
+ observeEventsForOwnership(events);
963
+ const scheduledWaitContinuations = new Set();
964
+ const maxInlineSteps = getMaxInlineSteps();
965
+ const budget = new ReplayBudget();
966
+ const workflowStartedAt = workflowRun.startedAt
967
+ ? +workflowRun.startedAt
968
+ : Date.now();
969
+ const rootRunId = workflowRun.attributes?.[ROOT_RUN_ID_ATTRIBUTE] ?? runId;
970
+ let inlineStepsExecuted = 0;
971
+ let runGone = false;
972
+ // Set when this invocation wrote an event the workflow must consume to
973
+ // make progress (attr_set, getConflict-awaited hook_created) and the
974
+ // loop has not yet read it back, since eventually-consistent listings can
975
+ // return 0 new events right after a write. If it is still set when the
976
+ // loop exits suspended, the entrypoint requeues immediately instead of
977
+ // exiting awaiting_external with the unblocking event already written
978
+ // and nothing scheduled to read it.
979
+ let pendingRequeueSignal = false;
980
+ /**
981
+ * Fetch all events not yet processed by the live VM (log order), reading
982
+ * from where the log was last read to. A World's cursor never passes a
983
+ * position whose writer is still in flight, so reading forward from it
984
+ * cannot skip an event; the id set is what makes a re-read of the same
985
+ * span (after a queued page or a delta moved the view ahead of the cursor)
986
+ * harmless.
987
+ */
988
+ const fetchUnseenEvents = async () => {
989
+ const unseen = [];
990
+ let cursor = logView.logCursor;
991
+ let hasMore = true;
992
+ while (hasMore) {
993
+ const response = await world.events.list({
994
+ runId,
995
+ pagination: {
996
+ sortOrder: 'asc',
997
+ cursor: cursor ?? undefined,
998
+ limit: 1000,
999
+ },
1000
+ });
1001
+ for (const e of response.data) {
1002
+ if (e.eventId && seenEventIds.has(e.eventId))
1003
+ continue;
1004
+ if (e.eventId)
1005
+ seenEventIds.add(e.eventId);
1006
+ unseen.push(e);
1007
+ }
1008
+ if (response.cursor)
1009
+ cursor = response.cursor;
1010
+ hasMore = response.data.length > 0 && response.cursor != null;
1011
+ }
1012
+ logView.advanceCursor(cursor);
1013
+ logView.markFed(unseen);
1014
+ observeEventsForOwnership(unseen);
1015
+ return unseen;
1016
+ };
1017
+ /**
1018
+ * Events a World handed back on this invocation's writes that the VM can
1019
+ * take now: the contiguous run above what it has (see
1020
+ * `QuickJSLogView.takeContiguous`). Delivered ahead of `fetchUnseenEvents`
1021
+ * so a write's response, not a listing, is what usually carries the log
1022
+ * forward, which is the round-trip the page exists to save. Empty when
1023
+ * nothing is queued or the next position is not in hand, and the caller
1024
+ * lists.
1025
+ */
1026
+ const takeQueuedEvents = () => {
1027
+ const queued = logView.takeContiguous();
1028
+ for (const e of queued) {
1029
+ if (e.eventId)
1030
+ seenEventIds.add(e.eventId);
1031
+ }
1032
+ observeEventsForOwnership(queued);
1033
+ return queued;
1034
+ };
1035
+ try {
1036
+ let iteration = 0;
1037
+ while (result.suspended && !runGone && !budget.isExhausted()) {
1038
+ iteration++;
1039
+ // Re-check the event ceiling every turn: the loop appends events on
1040
+ // each continueWithEvents, so a single invocation can otherwise grow
1041
+ // the log arbitrarily far past the operator's limit (the node engine
1042
+ // re-checks per replay for the same reason). `seenEventIds` counts
1043
+ // every event this invocation has observed: initial log + all
1044
+ // feeds.
1045
+ if (maxEventsLimit !== undefined && seenEventIds.size >= maxEventsLimit) {
1046
+ throw new MaxEventsExceededError(seenEventIds.size, maxEventsLimit);
1047
+ }
1048
+ const pendingOperations = result.suspended.pendingOperations;
1049
+ // Select this turn's inline candidates BEFORE dispatch: fresh steps
1050
+ // (no step_created yet) that this invocation hasn't already handled.
1051
+ // Their step_created is deliberately NOT written by dispatch: the
1052
+ // inline claim below is a lazy step_started carrying the input,
1053
+ // which the world applies as an atomic create-claim. A concurrent
1054
+ // invocation racing on the same fresh step loses that claim with
1055
+ // EntityConflictError and skips, so step bodies cannot double-run
1056
+ // (previously both invocations bare-started the step after one lost
1057
+ // the swallowed step_created race).
1058
+ const freshSteps = pendingOperations.filter((op) => op.type === 'step' &&
1059
+ !op.hasCreatedEvent &&
1060
+ !executedStepIds.has(op.correlationId) &&
1061
+ !queuedStepIds.has(op.correlationId));
1062
+ // Steps whose input refused to serialize (see
1063
+ // PendingStep.serializationError) never execute: they must not be
1064
+ // inline-claimed (a lazy step_started would need the input that
1065
+ // failed) nor queued. Dispatch below finalizes them as step_created
1066
+ // + step_failed instead; only healthy steps compete for inline
1067
+ // slots and overflow.
1068
+ const healthySteps = freshSteps.filter((step) => !step.serializationError);
1069
+ const inlineCandidates = maxInlineSteps <= 0 ? [] : healthySteps.slice(0, maxInlineSteps);
1070
+ const inlineClaimCids = new Set(inlineCandidates.map((step) => step.correlationId));
1071
+ // 1. Durable side effects for this suspension's pending ops.
1072
+ const opsToDispatch = pendingOperations.map((op) => op.type === 'hook' &&
1073
+ op.abortRequested &&
1074
+ recordedAbortIds.has(op.correlationId)
1075
+ ? { ...op, abortRequested: false }
1076
+ : op);
1077
+ for (const op of pendingOperations) {
1078
+ if (op.type === 'hook' && op.abortRequested) {
1079
+ recordedAbortIds.add(op.correlationId);
1080
+ }
1081
+ }
1082
+ // Steps beyond the inline cap are handed to the queue in the same
1083
+ // turn their step_created is written. Where eligible, the dispatch
1084
+ // below parallelizes each overflow step's step_created write with
1085
+ // its queue publish (resilient step dispatch: the message carries
1086
+ // `stepInput` so the consumer can re-ensure the event); the rest
1087
+ // are queued right after, in parallel. This must all happen BEFORE
1088
+ // the event feed below: the feed always observes those
1089
+ // step_created writes as unseen events and `continue`s, so a
1090
+ // handoff placed after it is unreachable on the only iteration
1091
+ // that still classifies these steps as fresh: next turn they carry
1092
+ // hasCreatedEvent and would never be queued at all (the wedge behind
1093
+ // promiseRaceStressTestWorkflow hanging in the quickjs CI legs). The
1094
+ // step-identity-scoped idempotency key makes repeats harmless.
1095
+ const overflowSteps = healthySteps.slice(inlineCandidates.length);
1096
+ const dispatched = await dispatchPendingOps({
1097
+ world,
1098
+ runId,
1099
+ workflowRun,
1100
+ encryptionKey,
1101
+ namespace,
1102
+ nextTraceCarrier,
1103
+ createEvent,
1104
+ ...(logView.tracking && typeof logView.logCursor === 'string'
1105
+ ? { deltaCursor: logView.logCursor }
1106
+ : {}),
1107
+ pendingOperations: opsToDispatch,
1108
+ skipStepCreation: inlineClaimCids,
1109
+ queueStepCids: new Set(overflowSteps.map((s) => s.correlationId)),
1110
+ finalizeUnserializableSteps: true,
1111
+ wfdiag,
1112
+ });
1113
+ if (dispatched.createdAttributeEvent ||
1114
+ dispatched.createdGetConflictHook) {
1115
+ pendingRequeueSignal = true;
1116
+ }
1117
+ // A finalized unserializable step has terminal events durably
1118
+ // written but no execution message anywhere: if the feed below
1119
+ // doesn't surface them (eventually-consistent listing) and the loop
1120
+ // exits, nothing would ever re-invoke the run to observe the
1121
+ // failure. Raise the requeue signal (same mechanism as inline
1122
+ // terminals) and mark the steps handled so later turns don't
1123
+ // re-finalize or backstop-queue them.
1124
+ if (dispatched.failedSerializationStepCids.size > 0) {
1125
+ pendingRequeueSignal = true;
1126
+ for (const cid of dispatched.failedSerializationStepCids) {
1127
+ executedStepIds.add(cid);
1128
+ }
1129
+ }
1130
+ for (const cid of dispatched.queuedStepCids) {
1131
+ queuedStepIds.add(cid);
1132
+ }
1133
+ await Promise.all(overflowSteps
1134
+ .filter((step) => !dispatched.queuedStepCids.has(step.correlationId))
1135
+ .map((step) => {
1136
+ queuedStepIds.add(step.correlationId);
1137
+ return queueStepMessage({
1138
+ world,
1139
+ runId,
1140
+ workflowRun,
1141
+ step,
1142
+ namespace,
1143
+ nextTraceCarrier,
1144
+ purpose: 'dispatch',
1145
+ wfdiag,
1146
+ });
1147
+ }));
1148
+ // Complete elapsed waits so their wait_completed events are picked
1149
+ // up by the feed below (instead of a queue re-invocation).
1150
+ const waitCompletePromises = [];
1151
+ for (const op of pendingOperations) {
1152
+ if (op.type !== 'wait')
1153
+ continue;
1154
+ const wait = op;
1155
+ if (completedWaitIds2.has(wait.correlationId))
1156
+ continue;
1157
+ if (new Date(wait.resumeAt).getTime() - Date.now() > 0)
1158
+ continue;
1159
+ completedWaitIds2.add(wait.correlationId);
1160
+ waitCompletePromises.push((async () => {
1161
+ try {
1162
+ await createEvent({
1163
+ eventType: 'wait_completed',
1164
+ specVersion: SPEC_VERSION_CURRENT,
1165
+ correlationId: wait.correlationId,
1166
+ });
1167
+ }
1168
+ catch (err) {
1169
+ if (EntityConflictError.is(err))
1170
+ return;
1171
+ throw err;
1172
+ }
1173
+ })());
1174
+ }
1175
+ if (waitCompletePromises.length > 0) {
1176
+ await Promise.all(waitCompletePromises);
1177
+ }
1178
+ // 2. Cheap progress first: feed newly recorded events into the live
1179
+ // VM before blocking on step bodies. What the writes above handed back
1180
+ // is delivered first, and a listing runs when the queue does not reach
1181
+ // the next position. A report changes what is fed first, not whether
1182
+ // this listing happens: after a queued page is fed, this branch
1183
+ // `continue`s, and the next iteration finds the queue empty and lists
1184
+ // from a cursor a report does not advance (re-reading the reported
1185
+ // span, deduped on `seenEventIds`). Only the inline delta below, which
1186
+ // does advance the cursor, saves a listing outright. Same shape as the
1187
+ // node engine.
1188
+ {
1189
+ const queued = takeQueuedEvents();
1190
+ const newEvents = queued.length > 0 ? queued : await fetchUnseenEvents();
1191
+ if (newEvents.length > 0) {
1192
+ // The listing caught up with this invocation's writes, so any
1193
+ // attr_set / getConflict hook_created has been (or is being)
1194
+ // consumed by the live VM, so no external requeue is needed.
1195
+ pendingRequeueSignal = false;
1196
+ result = await session.continueWithEvents(newEvents);
1197
+ wfdiag('inline_iteration', {
1198
+ iteration,
1199
+ phase: 'feed',
1200
+ fedEvents: newEvents.length,
1201
+ fedFrom: queued.length > 0 ? 'write-response' : 'list',
1202
+ outcome: result.completed
1203
+ ? 'completed'
1204
+ : result.failed
1205
+ ? 'failed'
1206
+ : 'suspended',
1207
+ });
1208
+ continue;
1209
+ }
1210
+ }
1211
+ // 3. No cheap progress left, so execute steps inline.
1212
+ const stepOps = pendingOperations.filter((op) => op.type === 'step');
1213
+ // Steps created by an EARLIER invocation (or an earlier turn) that
1214
+ // are still pending, with no work owned by THIS invocation. Mirror
1215
+ // the node engine's ownership decision table (step-ownership.ts),
1216
+ // NOT a deliveryAttempt gate: worlds advance the attempt counter on
1217
+ // routine redeliveries (world-local counts every handled response),
1218
+ // so attempt > 1 is the common case and would fire backstops at
1219
+ // steps actively executing inline in a live invocation.
1220
+ //
1221
+ // - Ownership lease ACTIVE, held by ANOTHER message → the step is
1222
+ // (presumably) executing inline in a live invocation. Arm a
1223
+ // DELAYED backstop for the lease remainder, keyed to the
1224
+ // ownership epoch (a refreshed lease re-arms a fresh backstop
1225
+ // instead of deduping against the in-flight one). If the owner
1226
+ // completes normally, the backstop delivery resolves the step
1227
+ // as 'skipped'.
1228
+ // - Ownership lease ACTIVE, held by THIS message → this delivery
1229
+ // is the owner's redelivery; the claimant crashed
1230
+ // mid-execution. Dispatch immediately for background recovery.
1231
+ // - No stamp / lease EXPIRED / step_retrying observed → the step
1232
+ // is queue-owned or orphaned. Dispatch immediately; the
1233
+ // step-identity-scoped idempotency key dedupes against the
1234
+ // original handoff.
1235
+ const nowMs = Date.now();
1236
+ for (const step of stepOps) {
1237
+ if (!step.hasCreatedEvent)
1238
+ continue;
1239
+ if (executedStepIds.has(step.correlationId))
1240
+ continue;
1241
+ if (queuedStepIds.has(step.correlationId))
1242
+ continue;
1243
+ const ownership = stepOwnership.get(step.correlationId);
1244
+ const ownershipActive = ownership !== undefined &&
1245
+ ownership.owner !== undefined &&
1246
+ !ownership.sawRetrying;
1247
+ let leaseRemainingSeconds = 0;
1248
+ if (ownershipActive && ownership.startedAtMs !== undefined) {
1249
+ const leaseSeconds = getInlineOwnershipLeaseSeconds();
1250
+ leaseRemainingSeconds = Math.min(leaseSeconds, Math.max(0, Math.ceil((ownership.startedAtMs + leaseSeconds * 1000 - nowMs) / 1000)));
1251
+ }
1252
+ if (ownershipActive &&
1253
+ ownership.owner !== ownerMessageId &&
1254
+ leaseRemainingSeconds > 0) {
1255
+ queuedStepIds.add(step.correlationId);
1256
+ await queueStepMessage({
1257
+ world,
1258
+ runId,
1259
+ workflowRun,
1260
+ step,
1261
+ delaySeconds: leaseRemainingSeconds,
1262
+ namespace,
1263
+ nextTraceCarrier,
1264
+ purpose: `backstop:${ownership.startedAtMs}`,
1265
+ wfdiag,
1266
+ });
1267
+ }
1268
+ else {
1269
+ queuedStepIds.add(step.correlationId);
1270
+ await queueStepMessage({
1271
+ world,
1272
+ runId,
1273
+ workflowRun,
1274
+ step,
1275
+ namespace,
1276
+ nextTraceCarrier,
1277
+ purpose: 'dispatch',
1278
+ wfdiag,
1279
+ });
1280
+ }
1281
+ }
1282
+ if (inlineCandidates.length === 0) {
1283
+ // No in-process progress possible: the run awaits an external
1284
+ // stimulus (hook payload, queued step, wait timer).
1285
+ break;
1286
+ }
1287
+ // Racing timers must fire on time while step bodies block this
1288
+ // invocation: enqueue a delayed continuation for the soonest
1289
+ // pending wait (a separate invocation writes its wait_completed at
1290
+ // the right log position, the same mechanism as the node:vm engine's
1291
+ // wait-continuation dispatch).
1292
+ let soonestWait;
1293
+ for (const op of pendingOperations) {
1294
+ if (op.type !== 'wait')
1295
+ continue;
1296
+ const wait = op;
1297
+ if (scheduledWaitContinuations.has(wait.correlationId))
1298
+ continue;
1299
+ // Waits whose wait_completed THIS invocation already wrote (the
1300
+ // elapsed-wait pass above) are done: the event just hasn't fed
1301
+ // back into the VM yet. No continuation needed.
1302
+ if (completedWaitIds2.has(wait.correlationId))
1303
+ continue;
1304
+ const resumeMs = new Date(wait.resumeAt).getTime() - Date.now();
1305
+ // An already-elapsed wait MUST still get a continuation (clamped
1306
+ // to the 1s minimum, exactly like the node engine's
1307
+ // `Math.max(1000, resumeAtMs - now)`), not be skipped: a wait
1308
+ // whose deadline falls between this iteration's elapsed-wait
1309
+ // pass (which saw it as still pending and wrote nothing) and
1310
+ // this sweep would otherwise get NEITHER a wait_completed NOR a
1311
+ // continuation, and the inline batch below then blocks this
1312
+ // invocation for the full step duration with no wake armed
1313
+ // anywhere. For `Promise.race(step, sleep)` that silently hands
1314
+ // the race to the step: the sleep's wait_completed is never
1315
+ // written and the run completes with the wrong winner. The
1316
+ // window between the two checks spans this iteration's dispatch
1317
+ // + feed round-trips, so on network-backed worlds (world-vercel)
1318
+ // a short sleep lands in it routinely, observed as a ~50%
1319
+ // sleepWinsRaceWorkflow failure rate in the Vercel e2e legs,
1320
+ // while world-local's sub-ms round-trips masked it locally. The
1321
+ // continuation invocation's pre-VM elapsed check writes the
1322
+ // wait_completed ~1s later.
1323
+ const seconds = Math.max(1, Math.ceil(resumeMs / 1000));
1324
+ if (!soonestWait || seconds < soonestWait.seconds) {
1325
+ soonestWait = { correlationId: wait.correlationId, seconds };
1326
+ }
1327
+ }
1328
+ if (soonestWait) {
1329
+ scheduledWaitContinuations.add(soonestWait.correlationId);
1330
+ const attempt = nextWaitContinuationAttempt(soonestWait.correlationId);
1331
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
1332
+ runId,
1333
+ traceCarrier: await nextTraceCarrier(),
1334
+ requestedAt: new Date(),
1335
+ waitContinuation: {
1336
+ correlationId: soonestWait.correlationId,
1337
+ attempt,
1338
+ },
1339
+ }, getWaitContinuationDispatch(soonestWait.seconds, soonestWait.correlationId, Date.now(), attempt));
1340
+ wfdiag('wait_continuation_scheduled', {
1341
+ correlationId: soonestWait.correlationId,
1342
+ delaySeconds: soonestWait.seconds,
1343
+ attempt,
1344
+ });
1345
+ }
1346
+ // Execute the inline batch in parallel. The replay budget is
1347
+ // paused while step bodies run: step duration is bounded by the
1348
+ // platform function duration, not the replay timeout. NOTE (by
1349
+ // design): with the budget parked per batch, the only bound on how
1350
+ // many inline steps one invocation can chain is the platform's
1351
+ // function timeout: the SDK deliberately imposes no cap of its
1352
+ // own, matching the node:vm engine, where a long sequential
1353
+ // workflow likewise runs step-by-step until the platform reclaims
1354
+ // the invocation and a redelivery resumes from the log.
1355
+ // Inline delta: a single inline step's terminal write asks the World
1356
+ // for everything after the cursor this view holds, so the step's own
1357
+ // events (and anything interleaved) arrive on the write's response and
1358
+ // the feed below needs no listing. Same gate as the node engine's
1359
+ // `requestInlineDelta` (runtime.ts), translated to this loop's terms:
1360
+ //
1361
+ // - This step is the only step outstanding: no overflow sibling queued
1362
+ // this iteration, no unserializable sibling, no step from an earlier
1363
+ // invocation handed to the queue above. Several writers each diffing
1364
+ // against the same cursor would produce deltas of which only the
1365
+ // first could be taken.
1366
+ // - No wait is pending. A `wait_completed` is a resolution the
1367
+ // workflow is waiting on rather than an event it can observe one
1368
+ // iteration late, so a delta that predates it would settle the
1369
+ // sleep from a view that does not hold its completion; the listing
1370
+ // after the step is what reads it in order.
1371
+ // - The log has a cursor to name (tracking on, something read).
1372
+ const hasPendingWait = pendingOperations.some((op) => op.type === 'wait' &&
1373
+ !completedWaitIds2.has(op.correlationId));
1374
+ const inlineDeltaSinceCursor = stepOps.length === 1 &&
1375
+ freshSteps.length === 1 &&
1376
+ inlineCandidates.length === 1 &&
1377
+ !hasPendingWait &&
1378
+ logView.tracking &&
1379
+ typeof logView.logCursor === 'string'
1380
+ ? logView.logCursor
1381
+ : undefined;
1382
+ budget.pause();
1383
+ let outcomes;
1384
+ try {
1385
+ outcomes = await Promise.all(inlineCandidates.map((step) => runStepSingleFlight(runId, step.correlationId, () => (async () => executeStep({
1386
+ world,
1387
+ workflowRunId: runId,
1388
+ workflowDeploymentId: workflowRun.deploymentId,
1389
+ workflowName: workflowRun.workflowName,
1390
+ workflowStartedAt,
1391
+ requestId,
1392
+ rootRunId,
1393
+ stepId: step.correlationId,
1394
+ stepName: step.stepId,
1395
+ encryptionKey,
1396
+ runSpecVersion: workflowRun.specVersion,
1397
+ // Lazy inline claim: step_created is deferred (dispatch
1398
+ // skipped it) and this step_started carries the input,
1399
+ // so the world creates the step atomically:
1400
+ // exactly-one-owner. A concurrent claimant gets
1401
+ // EntityConflictError → { type: 'skipped' } and never
1402
+ // runs the body. Mirrors the node engine's inline path.
1403
+ lazyStepInput: await encryptSerializedData(step.input, encryptionKey),
1404
+ // Ownership stamp: wake replays see the body as in
1405
+ // flight in this invocation and arm a delayed backstop
1406
+ // instead of immediately requeueing the step.
1407
+ ownerMessageId,
1408
+ // A lazy step is brand-new by construction: first
1409
+ // attempt.
1410
+ authoritativeAttempt: 1,
1411
+ ...(inlineDeltaSinceCursor !== undefined
1412
+ ? { inlineDeltaSinceCursor }
1413
+ : {}),
1414
+ }))())));
1415
+ }
1416
+ finally {
1417
+ budget.resume();
1418
+ }
1419
+ inlineStepsExecuted += inlineCandidates.length;
1420
+ for (let i = 0; i < inlineCandidates.length; i++) {
1421
+ const step = inlineCandidates[i];
1422
+ const outcome = outcomes[i];
1423
+ executedStepIds.add(step.correlationId);
1424
+ if (outcome.type === 'completed' &&
1425
+ outcome.inlineDelta !== undefined &&
1426
+ inlineDeltaSinceCursor !== undefined) {
1427
+ const advanced = logView.absorbDelta(inlineDeltaSinceCursor, outcome.inlineDelta);
1428
+ wfdiag('inline_delta_absorbed', {
1429
+ iteration,
1430
+ correlationId: step.correlationId,
1431
+ events: outcome.inlineDelta.events.length,
1432
+ hasMore: outcome.inlineDelta.hasMore,
1433
+ cursorAdvanced: advanced,
1434
+ });
1435
+ }
1436
+ if (outcome.type === 'retry' || outcome.type === 'throttled') {
1437
+ // Hand the step to the queue with the requested backoff:
1438
+ // background delivery drives the retry from here.
1439
+ queuedStepIds.add(step.correlationId);
1440
+ await queueStepMessage({
1441
+ world,
1442
+ runId,
1443
+ workflowRun,
1444
+ step,
1445
+ delaySeconds: outcome.timeoutSeconds,
1446
+ namespace,
1447
+ nextTraceCarrier,
1448
+ // Suffixed key: this step was inline-claimed, so no dispatch
1449
+ // publish exists under the dispatch key, but suffixing
1450
+ // keeps the retry enqueueable even if a world retired a
1451
+ // historical key for this step (see the purpose docs above).
1452
+ purpose: 'retry:1',
1453
+ wfdiag,
1454
+ });
1455
+ }
1456
+ else if (outcome.type === 'gone') {
1457
+ runGone = true;
1458
+ }
1459
+ // 'skipped': a concurrent invocation won the lazy create-claim and
1460
+ // owns the body. Marked executed above so this invocation never
1461
+ // re-claims it; the winner's terminal events arrive via the feed
1462
+ // (or drive a separate invocation).
1463
+ }
1464
+ wfdiag('inline_steps_executed', {
1465
+ iteration,
1466
+ count: inlineCandidates.length,
1467
+ outcomes: outcomes.map((o) => o.type),
1468
+ });
1469
+ // Feed the inline batch's terminal events into the live VM. When
1470
+ // the eventually-consistent listing has not surfaced them yet,
1471
+ // exiting must NOT ack silently: the terminals this invocation just
1472
+ // caused are durably written with no queue message left to consume
1473
+ // them (inline steps have none), so an awaiting_external exit would
1474
+ // park the run 'running' with all its steps complete. Raise the
1475
+ // requeue signal so the suspended exit schedules a fresh immediate
1476
+ // invocation whose fresh read picks the terminals up. Outcomes that
1477
+ // wrote no terminal ('skipped': a concurrent claimant owns the
1478
+ // body; 'gone', retry/throttled: a queue message exists) don't
1479
+ // need it, but signaling on them too only costs a no-op invocation
1480
+ // in an already-rare lag window.
1481
+ const queued = takeQueuedEvents();
1482
+ const newEvents = queued.length > 0 ? queued : await fetchUnseenEvents();
1483
+ if (newEvents.length === 0) {
1484
+ pendingRequeueSignal = true;
1485
+ break;
1486
+ }
1487
+ result = await session.continueWithEvents(newEvents);
1488
+ wfdiag('inline_iteration', {
1489
+ iteration,
1490
+ phase: 'steps',
1491
+ fedEvents: newEvents.length,
1492
+ outcome: result.completed
1493
+ ? 'completed'
1494
+ : result.failed
1495
+ ? 'failed'
1496
+ : 'suspended',
1497
+ budgetExhausted: budget.isExhausted(),
1498
+ });
1499
+ }
1500
+ }
1501
+ finally {
1502
+ session.dispose();
1503
+ }
1504
+ parentSpan?.setAttributes({
1505
+ ...Attribute.QuickJSInlineSteps(inlineStepsExecuted),
1506
+ });
1507
+ if (result.completed) {
1508
+ // Workflow completed
1509
+ runtimeLogger.info('QuickJS runtime: workflow completed', {
1510
+ workflowRunId: runId,
1511
+ });
1512
+ parentSpan?.setAttributes({
1513
+ ...Attribute.QuickJSOutcome('completed'),
1514
+ });
1515
+ // Flush leftover pending side effects (abort recordings, system-hook
1516
+ // disposals, fire-and-forget attribute/hook events) BEFORE writing
1517
+ // run_completed. Mirrors the node:vm engine's drainPendingQueueItems.
1518
+ // Drain failures are swallowed: the workflow's own outcome is the
1519
+ // source of truth.
1520
+ if (result.completed.drainOperations?.length) {
1521
+ try {
1522
+ await dispatchPendingOps({
1523
+ world,
1524
+ runId,
1525
+ workflowRun,
1526
+ encryptionKey,
1527
+ namespace,
1528
+ nextTraceCarrier,
1529
+ // Plain create: the run is ending, nothing replays its log, so a
1530
+ // page handed back here would be read by no one.
1531
+ createEvent: terminalCreateEvent,
1532
+ pendingOperations: result.completed.drainOperations,
1533
+ wfdiag,
1534
+ });
1535
+ }
1536
+ catch (err) {
1537
+ runtimeLogger.warn('QuickJS runtime: terminal drain failed', {
1538
+ workflowRunId: runId,
1539
+ message: err?.message,
1540
+ });
1541
+ }
1542
+ }
1543
+ // Create run_completed event.
1544
+ // The VM serializes the workflow result as format-prefixed devalue bytes
1545
+ // ("devl" + devalue) with no encryption (the VM has no access to the
1546
+ // CryptoKey). Host-side encryption is applied here so that `run_completed`
1547
+ // events have the same `encr`-prefixed payload shape that the node:vm
1548
+ // engine's `dehydrateWorkflowReturnValue` produces.
1549
+ try {
1550
+ await terminalCreateEvent({
1551
+ eventType: 'run_completed',
1552
+ specVersion: SPEC_VERSION_CURRENT,
1553
+ eventData: {
1554
+ output: await encryptSerializedData(result.completed.result, encryptionKey),
1555
+ },
1556
+ });
1557
+ wfdiag('exit_completed', { result: 'run_completed_written' });
1558
+ }
1559
+ catch (err) {
1560
+ if (EntityConflictError.is(err) || RunExpiredError.is(err)) {
1561
+ runtimeLogger.warn('Workflow already finished, skipping run_completed', { workflowRunId: runId });
1562
+ wfdiag('exit_completed', { result: 'already_finished' });
1563
+ return;
1564
+ }
1565
+ wfdiag('exit_completed_error', {
1566
+ errorName: err?.name,
1567
+ errorMessage: err?.message,
1568
+ });
1569
+ throw err;
1570
+ }
1571
+ }
1572
+ else if (result.suspended) {
1573
+ // Workflow still suspended after the inline loop. All durable side
1574
+ // effects for the final suspension state were already dispatched by
1575
+ // the loop; what remains is deciding how the run gets re-invoked.
1576
+ const { pendingOperations } = result.suspended;
1577
+ runtimeLogger.info('QuickJS runtime: workflow suspended', {
1578
+ workflowRunId: runId,
1579
+ inlineStepsExecuted,
1580
+ pendingSteps: pendingOperations.filter((p) => p.type === 'step').length,
1581
+ pendingWaits: pendingOperations.filter((p) => p.type === 'wait').length,
1582
+ pendingOps: pendingOperations.map((p) => ({
1583
+ type: p.type,
1584
+ correlationId: p.correlationId,
1585
+ hasCreatedEvent: p.hasCreatedEvent,
1586
+ ...(p.type === 'step' ? { stepId: p.stepId } : {}),
1587
+ })),
1588
+ });
1589
+ parentSpan?.setAttributes({
1590
+ ...Attribute.QuickJSOutcome('suspended'),
1591
+ ...Attribute.QuickJSPendingOpsCount(pendingOperations.length),
1592
+ });
1593
+ if (runGone) {
1594
+ // The run no longer exists (expired / deleted), so nothing to drive.
1595
+ wfdiag('exit_suspended', { action: 'run_gone' });
1596
+ return;
1597
+ }
1598
+ // Exit requeues are FRESH messages, never a `{ timeoutSeconds }`
1599
+ // visibility-redelivery of the current message. Redelivering the
1600
+ // CURRENT message is a trap: a hook-resume delivery carries
1601
+ // `hookInput`, and its redelivery re-runs the lazy-resume re-ensure
1602
+ // in the handler prologue: if the workflow disposed that hook
1603
+ // during this invocation (dispose → sleep), a world that rejects
1604
+ // the re-ensure would ack the message as "nothing left to resume"
1605
+ // and the continuation it carried is silently lost. A fresh message
1606
+ // carries only `runId`, so its delivery always reaches replay (and
1607
+ // under turbo a reschedule would re-engage turbo against a stale
1608
+ // preloaded log: see the reinvoke() docs in runtime.ts).
1609
+ const requeueImmediately = async () => {
1610
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
1611
+ runId,
1612
+ traceCarrier: await nextTraceCarrier(),
1613
+ requestedAt: new Date(),
1614
+ });
1615
+ };
1616
+ if (budget.isExhausted()) {
1617
+ // The loop stopped on the replay budget with progress still
1618
+ // possible, so continue in a fresh invocation.
1619
+ wfdiag('exit_suspended', { action: 'budget_exhausted_requeue' });
1620
+ await requeueImmediately();
1621
+ return;
1622
+ }
1623
+ // Exit wait sweep. A wait that elapsed in the window since the
1624
+ // loop's last check requeues immediately (its wait_completed is
1625
+ // written by the next invocation's elapsed-wait pass); pending waits
1626
+ // whose continuation the loop already enqueued are skipped.
1627
+ let soonestWait;
1628
+ let hasElapsedWait = false;
1629
+ for (const op of pendingOperations) {
1630
+ if (op.type !== 'wait')
1631
+ continue;
1632
+ const wait = op;
1633
+ const resumeMs = new Date(wait.resumeAt).getTime() - Date.now();
1634
+ if (resumeMs <= 0) {
1635
+ hasElapsedWait = true;
1636
+ }
1637
+ else if (!scheduledWaitContinuations.has(wait.correlationId)) {
1638
+ const timeoutSeconds = Math.max(1, Math.ceil(resumeMs / 1000));
1639
+ if (!soonestWait || timeoutSeconds < soonestWait.seconds) {
1640
+ soonestWait = {
1641
+ seconds: timeoutSeconds,
1642
+ correlationId: wait.correlationId,
1643
+ };
1644
+ }
1645
+ }
1646
+ }
1647
+ if (hasElapsedWait) {
1648
+ wfdiag('exit_suspended', { action: 'wait_elapsed_requeue' });
1649
+ await requeueImmediately();
1650
+ return;
1651
+ }
1652
+ if (pendingRequeueSignal) {
1653
+ // This invocation wrote events the workflow needs to consume
1654
+ // (attr_set / getConflict-awaited hook_created / inline step
1655
+ // terminals) but the eventually-consistent listing never returned
1656
+ // them before the loop exited. Without a requeue the run would
1657
+ // park awaiting_external with its unblocking events already
1658
+ // durably written and no future invocation coming, so requeue
1659
+ // immediately so a fresh read picks them up. In the common case
1660
+ // the loop's own feed observes the writes and clears this flag, so
1661
+ // this only fires when the read actually lagged.
1662
+ wfdiag('exit_suspended', { action: 'unread_self_write_requeue' });
1663
+ await requeueImmediately();
1664
+ return;
1665
+ }
1666
+ if (soonestWait) {
1667
+ // Delayed continuation for the soonest pending wait the loop has
1668
+ // not already scheduled. The dispatch helper handles delay
1669
+ // clamping (long waits chain across hops) and idempotency-key
1670
+ // dedup of re-observations of the same pending wait. See
1671
+ // runtime/wait-continuation.ts.
1672
+ wfdiag('exit_suspended', {
1673
+ action: 'schedule_wait_timeout',
1674
+ timeoutSeconds: soonestWait.seconds,
1675
+ waitCorrelationId: soonestWait.correlationId,
1676
+ });
1677
+ scheduledWaitContinuations.add(soonestWait.correlationId);
1678
+ const attempt = nextWaitContinuationAttempt(soonestWait.correlationId);
1679
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
1680
+ runId,
1681
+ traceCarrier: await nextTraceCarrier(),
1682
+ requestedAt: new Date(),
1683
+ waitContinuation: {
1684
+ correlationId: soonestWait.correlationId,
1685
+ attempt,
1686
+ },
1687
+ }, getWaitContinuationDispatch(soonestWait.seconds, soonestWait.correlationId, Date.now(), attempt));
1688
+ return;
1689
+ }
1690
+ wfdiag('exit_suspended', {
1691
+ action: 'awaiting_external',
1692
+ pendingOpsCount: pendingOperations.length,
1693
+ });
1694
+ }
1695
+ else if (result.failed) {
1696
+ // Workflow failed, so remap stack trace using inline source maps.
1697
+ // Frames carry the run's workflowId as their filename on the fresh
1698
+ // path, but the workflow-independent BASELINE_BUNDLE_FILENAME on the
1699
+ // snapshot path (the name is baked into the shared baseline's
1700
+ // compiled code at hydrate), so remap against both. remapErrorStack
1701
+ // early-exits on a cheap includes() when a filename has no frames.
1702
+ let errorStack = result.failed.stack;
1703
+ if (errorStack) {
1704
+ const parsedName = parseWorkflowName(workflowName);
1705
+ const filename = parsedName?.moduleSpecifier || workflowName;
1706
+ errorStack = remapErrorStack(errorStack, filename, workflowCode);
1707
+ errorStack = remapErrorStack(errorStack, BASELINE_BUNDLE_FILENAME, workflowCode);
1708
+ }
1709
+ // Classify the error so consumers (`run.returnValue`, observability)
1710
+ // get `USER_ERROR` / `RUNTIME_ERROR` on `error.cause.code`, matching
1711
+ // what the node:vm engine already does in runtime.ts.
1712
+ //
1713
+ // The VM serializes errors as `{ name, message, stack }`, so we
1714
+ // reconstruct a host-side Error of the correct class based on the
1715
+ // VM-side `name`: specific WorkflowRuntimeError subclasses need
1716
+ // to be preserved so classifyRunError() tags them as RUNTIME_ERROR.
1717
+ const reconstructed = result.failed.name === 'WorkflowNotRegisteredError'
1718
+ ? new WorkflowNotRegisteredError(workflowName)
1719
+ : result.failed.name === 'Error'
1720
+ ? new Error(result.failed.message)
1721
+ : Object.assign(new Error(result.failed.message), {
1722
+ name: result.failed.name,
1723
+ });
1724
+ const errorCode = classifyRunError(reconstructed);
1725
+ runtimeLogger.error('QuickJS runtime: workflow failed', {
1726
+ workflowRunId: runId,
1727
+ errorName: result.failed.name,
1728
+ errorMessage: result.failed.message,
1729
+ errorStack,
1730
+ errorCode,
1731
+ });
1732
+ parentSpan?.setAttributes({
1733
+ ...Attribute.QuickJSOutcome('failed'),
1734
+ });
1735
+ // Flush leftover pending side effects before writing run_failed,
1736
+ // same drain semantics as the completed branch.
1737
+ if (result.failed.drainOperations?.length) {
1738
+ try {
1739
+ await dispatchPendingOps({
1740
+ world,
1741
+ runId,
1742
+ workflowRun,
1743
+ encryptionKey,
1744
+ namespace,
1745
+ nextTraceCarrier,
1746
+ createEvent: terminalCreateEvent,
1747
+ pendingOperations: result.failed.drainOperations,
1748
+ wfdiag,
1749
+ });
1750
+ }
1751
+ catch (err) {
1752
+ runtimeLogger.warn('QuickJS runtime: terminal drain failed', {
1753
+ workflowRunId: runId,
1754
+ message: err?.message,
1755
+ });
1756
+ }
1757
+ }
1758
+ // Create run_failed event. Serialize the error through the
1759
+ // first-class dehydration pipeline so consumers (CLI, observability,
1760
+ // run.returnValue) get the same hydrated value shape as the node:vm
1761
+ // engine emits. Two paths:
1762
+ // * Modern (valueBytes present): the VM-side rejection handler
1763
+ // serialized the original thrown value (Error subclass with
1764
+ // cause chain, plain object, primitive, etc.) using the VM's
1765
+ // workflow-serialize. Pass those bytes through directly so
1766
+ // type identity, cause chains, and non-Error throws survive.
1767
+ // Apply encryption if configured (the VM's
1768
+ // serializer doesn't have access to the encryption key).
1769
+ // * Legacy fallback: reconstruct an Error from the host-visible
1770
+ // {name, message, stack} fields and run it through
1771
+ // `dehydrateRunError`. Used when valueBytes is absent (e.g.
1772
+ // extractError pseudo-failures from VM bootstrap).
1773
+ let dehydratedError;
1774
+ if (result.failed.valueBytes) {
1775
+ // Hydrate the VM-side bytes, remap the error stack with the
1776
+ // host-side source map (the VM can't do this: it lacks both the
1777
+ // source map and `remapErrorStack`), and re-dehydrate. This
1778
+ // preserves the original value's type identity / cause chain
1779
+ // while fixing up frames to point at the user's source files.
1780
+ try {
1781
+ const hydrated = await hydrateRunError(result.failed.valueBytes, runId, undefined // VM bytes are unencrypted
1782
+ );
1783
+ if (hydrated &&
1784
+ typeof hydrated === 'object' &&
1785
+ 'stack' in hydrated &&
1786
+ typeof hydrated.stack === 'string') {
1787
+ const parsedName = parseWorkflowName(workflowName);
1788
+ const filename = parsedName?.moduleSpecifier || workflowName;
1789
+ // Both filename spaces. See the failed-branch comment above.
1790
+ hydrated.stack = remapErrorStack(remapErrorStack(hydrated.stack, filename, workflowCode), BASELINE_BUNDLE_FILENAME, workflowCode);
1791
+ }
1792
+ // Walk the cause chain and remap nested stacks too.
1793
+ const seen = new WeakSet();
1794
+ let node = hydrated?.cause;
1795
+ while (node && typeof node === 'object' && !seen.has(node)) {
1796
+ seen.add(node);
1797
+ const nodeStack = node.stack;
1798
+ if (typeof nodeStack === 'string') {
1799
+ const parsedName = parseWorkflowName(workflowName);
1800
+ const filename = parsedName?.moduleSpecifier || workflowName;
1801
+ // Both filename spaces. See the failed-branch comment above.
1802
+ node.stack = remapErrorStack(remapErrorStack(nodeStack, filename, workflowCode), BASELINE_BUNDLE_FILENAME, workflowCode);
1803
+ }
1804
+ node = node.cause;
1805
+ }
1806
+ dehydratedError = await dehydrateRunError(hydrated, runId, encryptionKey);
1807
+ }
1808
+ catch (rehydrateErr) {
1809
+ // If hydration / re-dehydration fails for any reason, fall
1810
+ // back to passing through the original VM bytes (applying
1811
+ // encryption if configured). Better to lose source-mapped
1812
+ // frames than to lose the error entirely.
1813
+ runtimeLogger.warn('QuickJS runtime: failed to remap workflow error stack, passing VM bytes through', {
1814
+ workflowRunId: runId,
1815
+ message: rehydrateErr?.message,
1816
+ });
1817
+ dehydratedError = (await maybeEncrypt(result.failed.valueBytes, encryptionKey));
1818
+ }
1819
+ }
1820
+ else {
1821
+ if (errorStack) {
1822
+ reconstructed.stack = errorStack;
1823
+ }
1824
+ try {
1825
+ dehydratedError = await dehydrateRunError(reconstructed, runId, encryptionKey);
1826
+ }
1827
+ catch (serErr) {
1828
+ // Fall back to a minimal payload so the run still terminates
1829
+ // even when the error itself contains unserializable values.
1830
+ runtimeLogger.warn('QuickJS runtime: failed to dehydrate run error, falling back to bare Error', { workflowRunId: runId, message: serErr?.message });
1831
+ dehydratedError = await dehydrateRunError(Object.assign(new Error(result.failed.message), {
1832
+ name: result.failed.name,
1833
+ }), runId, encryptionKey);
1834
+ }
1835
+ }
1836
+ try {
1837
+ await terminalCreateEvent({
1838
+ eventType: 'run_failed',
1839
+ specVersion: SPEC_VERSION_CURRENT,
1840
+ eventData: {
1841
+ error: dehydratedError,
1842
+ errorCode,
1843
+ },
1844
+ });
1845
+ }
1846
+ catch (err) {
1847
+ if (EntityConflictError.is(err) || RunExpiredError.is(err)) {
1848
+ runtimeLogger.warn('Workflow already finished, skipping run_failed', {
1849
+ workflowRunId: runId,
1850
+ });
1851
+ wfdiag('exit_failed', { result: 'already_finished' });
1852
+ return;
1853
+ }
1854
+ wfdiag('exit_failed_error', {
1855
+ errorName: err?.name,
1856
+ errorMessage: err?.message,
1857
+ });
1858
+ throw err;
1859
+ }
1860
+ wfdiag('exit_failed', { result: 'run_failed_written' });
1861
+ }
1862
+ }
1863
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVpY2tqcy1lbnRyeXBvaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvcXVpY2tqcy1lbnRyeXBvaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFHSCxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsZUFBZSxFQUNmLDBCQUEwQixHQUMzQixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9ELE9BQU8sRUFLTCxxQkFBcUIsRUFFckIsb0JBQW9CLEVBQ3BCLDBDQUEwQyxFQUMxQyxpQ0FBaUMsR0FFbEMsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMvRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsT0FBTyxJQUFJLHFCQUFxQixHQUVqQyxNQUFNLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsc0JBQXNCLEVBQ3RCLGtCQUFrQixFQUNsQixlQUFlLEVBQ2YsWUFBWSxHQUNiLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3pFLE9BQU8sS0FBSyxTQUFTLE1BQU0sc0NBQXNDLENBQUM7QUFDbEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxFQUNMLDhCQUE4QixFQUM5QixpQkFBaUIsRUFDakIsOEJBQThCLEVBQzlCLDhCQUE4QixHQUMvQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNqRCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLFlBQVksRUFDWixrQkFBa0IsRUFDbEIsMEJBQTBCLEdBQzNCLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN2RCxPQUFPLEVBQ0wsd0JBQXdCLEVBT3hCLG9CQUFvQixHQUNyQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsV0FBVyxFQUE0QixNQUFNLG9CQUFvQixDQUFDO0FBQzNFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzlELE9BQU8sRUFBRSxrQ0FBa0MsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFRdEMsd0VBQXdFO0FBQ3hFLFNBQVMsSUFBSTtJQUNYLE9BQU8sV0FBVyxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQzNCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FDL0IsZUFBNkM7SUFFN0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLElBQUksZUFBZSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNwRSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxPQUFPLGVBQWUsQ0FBQyxLQUFLLENBQzFCLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxLQUFLLGFBQWEsSUFBSSxDQUFDLENBQUMsU0FBUyxLQUFLLGFBQWEsQ0FDdEUsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxNQW1DL0I7SUFDQyxNQUFNLEVBQ0osS0FBSyxFQUNMLEtBQUssRUFDTCxXQUFXLEVBQ1gsSUFBSSxFQUNKLFlBQVksRUFDWixTQUFTLEVBQ1QsZ0JBQWdCLEVBQ2hCLE9BQU8sRUFDUCxTQUFTLEVBQ1QsTUFBTSxHQUNQLEdBQUcsTUFBTSxDQUFDO0lBQ1gsTUFBTSxZQUFZLEdBQUcsTUFBTSxnQkFBZ0IsRUFBRSxDQUFDO0lBQzlDLE1BQU0sWUFBWSxDQUNoQixLQUFLLEVBQ0wsb0JBQW9CLENBQUMsV0FBVyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsRUFDekQ7UUFDRSxLQUFLO1FBQ0wsTUFBTSxFQUFFLElBQUksQ0FBQyxhQUFhO1FBQzFCLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTTtRQUNyQixZQUFZO1FBQ1osV0FBVyxFQUFFLElBQUksSUFBSSxFQUFFO1FBQ3ZCLEdBQUcsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdkUsc0VBQXNFO1FBQ3RFLG9EQUFvRDtRQUNwRCxVQUFVLEVBQUUsa0JBQWtCLENBQUMsV0FBVyxDQUFDO0tBQzVDLEVBQ0Q7UUFDRSxxRUFBcUU7UUFDckUsc0VBQXNFO1FBQ3RFLGtFQUFrRTtRQUNsRSx1RUFBdUU7UUFDdkUsa0NBQWtDO1FBQ2xDLGNBQWMsRUFDWixPQUFPLEtBQUssVUFBVTtZQUNwQixDQUFDLENBQUMsMEJBQTBCLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQzdELENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLElBQUksT0FBTyxFQUFFO1FBQ3hDLEdBQUcsQ0FBQyxZQUFZLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQzlELENBQ0YsQ0FBQztJQUNGLE1BQU0sQ0FBQyxhQUFhLEVBQUU7UUFDcEIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1FBQ25CLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtRQUNqQyxPQUFPO1FBQ1AsWUFBWSxFQUFFLFlBQVksSUFBSSxDQUFDO1FBQy9CLEdBQUcsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3hELENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsS0FBSyxVQUFVLGtCQUFrQixDQUFDLE1BZ0VqQztJQWFDLE1BQU0sRUFDSixLQUFLLEVBQ0wsS0FBSyxFQUNMLFdBQVcsRUFDWCxhQUFhLEVBQ2IsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsV0FBVyxHQUNaLEdBQUcsTUFBTSxDQUFDO0lBQ1gsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7SUFDakQsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzdCLHNFQUFzRTtJQUN0RSx3RUFBd0U7SUFDeEUsdUNBQXVDO0lBQ3ZDLE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDekMsd0VBQXdFO0lBQ3hFLHFFQUFxRTtJQUNyRSxNQUFNLDJCQUEyQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDdEQsMEVBQTBFO0lBQzFFLDJFQUEyRTtJQUMzRSxvREFBb0Q7SUFDcEQsRUFBRTtJQUNGLG9EQUFvRDtJQUNwRCx3RUFBd0U7SUFDeEUsMEVBQTBFO0lBQzFFLHNFQUFzRTtJQUN0RSx5RUFBeUU7SUFDekUsc0VBQXNFO0lBQ3RFLG1FQUFtRTtJQUNuRSxNQUFNLHlCQUF5QixHQUM3QixhQUFhLEtBQUssU0FBUztRQUMzQixhQUFhLENBQUMsSUFBSSxHQUFHLENBQUM7UUFDdEIsOEJBQThCLEVBQUU7UUFDaEMsQ0FBQyxXQUFXLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQztZQUM1QiwwQ0FBMEMsQ0FBQztJQUMvQyw4REFBOEQ7SUFDOUQsd0VBQXdFO0lBQ3hFLDBEQUEwRDtJQUMxRCxJQUFJLHNCQUFzQixHQUFHLEtBQUssQ0FBQztJQUNuQyxnRUFBZ0U7SUFDaEUsbUVBQW1FO0lBQ25FLG9FQUFvRTtJQUNwRSxtQ0FBbUM7SUFDbkMsSUFBSSxxQkFBcUIsR0FBRyxLQUFLLENBQUM7SUFDbEMsTUFBTSxXQUFXLEdBQW9CLEVBQUUsQ0FBQztJQUN4QyxNQUFNLG9CQUFvQixHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FDbkQsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FDbEQsQ0FBQyxNQUFNLENBQUM7SUFDVCxNQUFNLGVBQWUsR0FDbkIsb0JBQW9CLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFFOUQsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLElBQWlCLEVBQWlCLEVBQUU7UUFDL0QsYUFBYSxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRTtZQUN6RCxhQUFhLEVBQUUsS0FBSztZQUNwQixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7WUFDakMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO1lBQ2pCLFNBQVMsRUFBRSxPQUFPLElBQUksQ0FBQyxLQUFLO1lBQzVCLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUztZQUN6QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsZUFBZSxFQUFFLElBQUksQ0FBQyxlQUFlO1lBQ3JDLGNBQWMsRUFBRSxJQUFJLENBQUMsY0FBYztTQUNwQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQzFCLHVEQUF1RDtZQUN2RCw0REFBNEQ7WUFDNUQseURBQXlEO1lBQ3pELDBEQUEwRDtZQUMxRCxpQ0FBaUM7WUFDakMsRUFBRTtZQUNGLGlFQUFpRTtZQUNqRSwrREFBK0Q7WUFDL0QsZ0VBQWdFO1lBQ2hFLDhEQUE4RDtZQUM5RCx1Q0FBdUM7WUFDdkMsSUFBSSxDQUFDO2dCQUNILE1BQU0saUJBQWlCLEdBQ3JCLE9BQU8sSUFBSSxDQUFDLFFBQVEsS0FBSyxXQUFXO29CQUNsQyxDQUFDLENBQUMsU0FBUztvQkFDWCxDQUFDLENBQUMsTUFBTSxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxDQUFDO2dCQUNoRSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FDOUI7b0JBQ0UsU0FBUyxFQUFFLGNBQWM7b0JBQ3pCLFdBQVcsRUFBRSxvQkFBb0I7b0JBQ2pDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtvQkFDakMsU0FBUyxFQUFFO3dCQUNULEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSzt3QkFDakIsbUJBQW1CLEVBQ2pCLElBQUksQ0FBQyxtQkFBbUIsS0FBSyxTQUFTOzRCQUNwQyxDQUFDLENBQUMsU0FBUzs0QkFDWCxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDO3dCQUN4QyxRQUFRLEVBQUUsaUJBQWlCO3dCQUMzQiw0REFBNEQ7d0JBQzVELDJEQUEyRDt3QkFDM0QsMkRBQTJEO3dCQUMzRCxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7d0JBQ3pCLHNEQUFzRDt3QkFDdEQsbUNBQW1DO3dCQUNuQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztxQkFDdEM7aUJBQ1QsRUFDRCxlQUFlLEtBQUssU0FBUztvQkFDM0IsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRTtvQkFDbEMsQ0FBQyxDQUFDLFNBQVMsQ0FDZCxDQUFDO2dCQUVGLHlEQUF5RDtnQkFDekQsd0RBQXdEO2dCQUN4RCxrREFBa0Q7Z0JBQ2xELElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxTQUFTLEtBQUssZUFBZSxFQUFFLENBQUM7b0JBQ2hELE1BQU0sWUFBWSxDQUNoQixLQUFLLEVBQ0wsb0JBQW9CLENBQUMsV0FBVyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsRUFDekQ7d0JBQ0UsS0FBSzt3QkFDTCxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsRUFBRTt3QkFDdEMsV0FBVyxFQUFFLElBQUksSUFBSSxFQUFFO3FCQUN4QixFQUNELEVBQUUsY0FBYyxFQUFFLGlCQUFpQixJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FDMUQsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsOERBQThEO2dCQUM5RCx5REFBeUQ7Z0JBQ3pELElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO29CQUFFLE1BQU0sR0FBRyxDQUFDO1lBQzlDLENBQUM7WUFDRCxJQUFJLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO2dCQUMvQixzQkFBc0IsR0FBRyxJQUFJLENBQUM7WUFDaEMsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QiwyREFBMkQ7WUFDM0QseURBQXlEO1lBQ3pELHNEQUFzRDtZQUN0RCx1REFBdUQ7WUFDdkQsK0JBQStCO1lBQy9CLE1BQU0sWUFBWSxHQUNoQixJQUFJLENBQUMsWUFBWSxZQUFZLFVBQVU7Z0JBQ3JDLENBQUMsQ0FBRSxDQUFDLE1BQU0scUJBQXFCLENBQzNCLElBQUksQ0FBQyxZQUFZLEVBQ2pCLGFBQWEsQ0FDZCxDQUFnQjtnQkFDbkIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUNoQixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxXQUFXLENBQUM7b0JBQ2hCLFNBQVMsRUFBRSxlQUFlO29CQUMxQixXQUFXLEVBQUUsb0JBQW9CO29CQUNqQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7b0JBQ2pDLFNBQVMsRUFBRTt3QkFDVCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7d0JBQ2pCLE9BQU8sRUFBRSxZQUFZO3FCQUNmO2lCQUNULENBQUMsQ0FBQztZQUNMLENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO29CQUFFLE1BQU0sR0FBRyxDQUFDO1lBQzlDLENBQUM7WUFDRCxrREFBa0Q7WUFDbEQsNENBQTRDO1lBQzVDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksWUFBWSxFQUFFLENBQUM7Z0JBQ25ELE1BQU0sVUFBVSxHQUFHLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUM7Z0JBQzNFLElBQUksQ0FBQztvQkFDSCxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsWUFBWSxDQUFDLENBQUM7b0JBQzNELE1BQU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUMvQyxDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCxtREFBbUQ7b0JBQ25ELFlBQVk7b0JBQ1osYUFBYSxDQUFDLEtBQUssQ0FDakIsc0RBQXNELEVBQ3REO3dCQUNFLGFBQWEsRUFBRSxLQUFLO3dCQUNwQixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7cUJBQ2xDLENBQ0YsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztZQUNELE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRTtnQkFDdkIsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO2dCQUNqQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDbEIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUMsQ0FBQztJQUVGLE1BQU0sb0JBQW9CLEdBQUcsS0FBSyxFQUNoQyxFQUFzQixFQUNQLEVBQUU7UUFDakIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxXQUFXLENBQUM7Z0JBQ2hCLFNBQVMsRUFBRSxlQUFlO2dCQUMxQixXQUFXLEVBQUUsb0JBQW9CO2dCQUNqQyxhQUFhLEVBQUUsRUFBRSxDQUFDLGFBQWE7Z0JBQy9CLHNFQUFzRTtnQkFDdEUsdUVBQXVFO2dCQUN2RSxxRUFBcUU7Z0JBQ3JFLG9FQUFvRTtnQkFDcEUsb0VBQW9FO2dCQUNwRSx3REFBd0Q7Z0JBQ3hELEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQzthQUN0RSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQztnQkFBRSxPQUFPO1lBQ3hDLGtFQUFrRTtZQUNsRSw0REFBNEQ7WUFDNUQsNkRBQTZEO1lBQzdELCtEQUErRDtZQUMvRCxJQUFJLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUM7Z0JBQUUsT0FBTztZQUN0QyxNQUFNLEdBQUcsQ0FBQztRQUNaLENBQUM7SUFDSCxDQUFDLENBQUM7SUFFRixxRUFBcUU7SUFDckUsaUVBQWlFO0lBQ2pFLGtFQUFrRTtJQUNsRSxpRUFBaUU7SUFDakUscUVBQXFFO0lBQ3JFLHFFQUFxRTtJQUNyRSxxRUFBcUU7SUFDckUscUVBQXFFO0lBQ3JFLG1DQUFtQztJQUNuQyxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFHM0IsQ0FBQztJQUNKLEtBQUssTUFBTSxFQUFFLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLEdBQXVCLENBQUM7UUFDNUIsSUFDRSxFQUFFLENBQUMsSUFBSSxLQUFLLE1BQU07WUFDbEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxlQUFlLElBQUssRUFBa0IsQ0FBQyxjQUFjLENBQUMsRUFDM0QsQ0FBQztZQUNELEdBQUcsR0FBSSxFQUFrQixDQUFDLEtBQUssQ0FBQztRQUNsQyxDQUFDO2FBQU0sSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLGNBQWMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUM3RCwrREFBK0Q7WUFDL0QsdURBQXVEO1lBQ3ZELEdBQUcsR0FBSSxFQUF5QixDQUFDLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN4RSxDQUFDO1FBQ0QsSUFBSSxHQUFHLEtBQUssU0FBUztZQUFFLFNBQVM7UUFDaEMsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0QyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFzQyxDQUFDLENBQUM7UUFDckQsQ0FBQzthQUFNLENBQUM7WUFDTixjQUFjLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQXNDLENBQUMsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7SUFDSCxDQUFDO0lBQ0QsS0FBSyxNQUFNLEtBQUssSUFBSSxjQUFjLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUM1QyxXQUFXLENBQUMsSUFBSSxDQUNkLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDVixLQUFLLE1BQU0sRUFBRSxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUN2QixJQUFJLEVBQUUsQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7b0JBQ3ZCLE1BQU0sYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUMxQixDQUFDO3FCQUFNLENBQUM7b0JBQ04sTUFBTSxvQkFBb0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDakMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDLENBQUMsRUFBRSxDQUNMLENBQUM7SUFDSixDQUFDO0lBRUQsS0FBSyxNQUFNLEVBQUUsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1FBQ25DLElBQ0UsRUFBRSxDQUFDLElBQUksS0FBSyxNQUFNO1lBQ2xCLENBQUMsRUFBRSxDQUFDLGVBQWU7WUFDbkIsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxFQUN4QyxDQUFDO1lBQ0QsTUFBTSxJQUFJLEdBQUcsRUFBaUIsQ0FBQztZQUMvQixXQUFXLENBQUMsSUFBSSxDQUNkLENBQUMsS0FBSyxJQUFJLEVBQUU7Z0JBQ1YsK0RBQStEO2dCQUMvRCxnRUFBZ0U7Z0JBQ2hFLG1FQUFtRTtnQkFDbkUsOERBQThEO2dCQUM5RCwwREFBMEQ7Z0JBQzFELGdFQUFnRTtnQkFDaEUseURBQXlEO2dCQUN6RCxvREFBb0Q7Z0JBQ3BELDhEQUE4RDtnQkFDOUQsY0FBYztnQkFDZCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO29CQUM1QixJQUFJLENBQUMsTUFBTSxDQUFDLDJCQUEyQixFQUFFLENBQUM7d0JBQ3hDLE9BQU87b0JBQ1QsQ0FBQztvQkFDRCxhQUFhLENBQUMsSUFBSSxDQUNoQiwwREFBMEQ7d0JBQ3hELG9DQUFvQyxFQUN0Qzt3QkFDRSxhQUFhLEVBQUUsS0FBSzt3QkFDcEIsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO3dCQUNqQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU07d0JBQ3JCLEtBQUssRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTztxQkFDdkMsQ0FDRixDQUFDO29CQUNGLElBQUksQ0FBQzt3QkFDSCxNQUFNLFdBQVcsQ0FBQzs0QkFDaEIsU0FBUyxFQUFFLGNBQWM7NEJBQ3pCLFdBQVcsRUFBRSxvQkFBb0I7NEJBQ2pDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTs0QkFDakMsU0FBUyxFQUFFO2dDQUNULFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTTtnQ0FDckIsS0FBSyxFQUFFLENBQUMsTUFBTSxzQkFBc0IsQ0FDbEMsa0NBQWtDLEVBQUUsRUFDcEMsS0FBSyxFQUNMLGFBQWEsRUFDYixVQUFVLEVBQ1YsS0FBSyxFQUNMLENBQUMsV0FBVyxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUM7b0NBQzVCLGlDQUFpQyxDQUNwQyxDQUFlOzZCQUNqQjt5QkFDRixDQUFDLENBQUM7b0JBQ0wsQ0FBQztvQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO3dCQUNiLDJEQUEyRDt3QkFDM0QscURBQXFEO3dCQUNyRCxJQUFJLGVBQWUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDOzRCQUFFLE9BQU87d0JBQ3BDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDOzRCQUFFLE1BQU0sR0FBRyxDQUFDO29CQUM5QyxDQUFDO29CQUNELElBQUksQ0FBQzt3QkFDSCxNQUFNLFdBQVcsQ0FBQzs0QkFDaEIsU0FBUyxFQUFFLGFBQWE7NEJBQ3hCLFdBQVcsRUFBRSxvQkFBb0I7NEJBQ2pDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTs0QkFDakMsU0FBUyxFQUFFO2dDQUNULFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTTtnQ0FDckIsS0FBSyxFQUFFLE1BQU0sa0JBQWtCLENBQzdCLElBQUksQ0FBQyxrQkFBa0IsRUFDdkIsS0FBSyxFQUNMLGFBQWEsRUFDYixFQUFFLEVBQ0YsVUFBVSxFQUNWLENBQUMsV0FBVyxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUM7b0NBQzVCLGlDQUFpQyxDQUNwQzs2QkFDRjt5QkFDRixDQUFDLENBQUM7b0JBQ0wsQ0FBQztvQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO3dCQUNiLGlEQUFpRDt3QkFDakQsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQzs0QkFDN0QsTUFBTSxHQUFHLENBQUM7d0JBQ1osQ0FBQztvQkFDSCxDQUFDO29CQUNELDJCQUEyQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQ3BELE1BQU0sQ0FBQywyQkFBMkIsRUFBRTt3QkFDbEMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO3dCQUNuQixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7cUJBQ2xDLENBQUMsQ0FBQztvQkFDSCxPQUFPO2dCQUNULENBQUM7Z0JBRUQsaURBQWlEO2dCQUNqRCw0REFBNEQ7Z0JBQzVELDBEQUEwRDtnQkFDMUQsdURBQXVEO2dCQUN2RCx5REFBeUQ7Z0JBQ3pELGtDQUFrQztnQkFDbEMsdURBQXVEO2dCQUN2RCxNQUFNLGNBQWMsR0FBRyxNQUFNLHFCQUFxQixDQUNoRCxJQUFJLENBQUMsS0FBSyxFQUNWLGFBQWEsQ0FDZCxDQUFDO2dCQUVGLCtEQUErRDtnQkFDL0QsNERBQTREO2dCQUM1RCwwREFBMEQ7Z0JBQzFELDhEQUE4RDtnQkFDOUQsOERBQThEO2dCQUM5RCw2REFBNkQ7Z0JBQzdELHlEQUF5RDtnQkFDekQsNkRBQTZEO2dCQUM3RCxJQUNFLHlCQUF5QjtvQkFDekIsYUFBYSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO29CQUN0QyxjQUFjLFlBQVksVUFBVTtvQkFDcEMsY0FBYyxDQUFDLFVBQVUsSUFBSSw4QkFBOEIsRUFDM0QsQ0FBQztvQkFDRCxNQUFNLENBQUMsWUFBWSxFQUFFLFdBQVcsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQzt3QkFDM0QsV0FBVyxDQUFDOzRCQUNWLFNBQVMsRUFBRSxjQUFjOzRCQUN6QixXQUFXLEVBQUUsb0JBQW9COzRCQUNqQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7NEJBQ2pDLFNBQVMsRUFBRTtnQ0FDVCxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU07Z0NBQ3JCLEtBQUssRUFBRSxjQUFjOzZCQUN0Qjt5QkFDRixDQUFDO3dCQUNGLGdCQUFnQixDQUFDOzRCQUNmLEtBQUs7NEJBQ0wsS0FBSzs0QkFDTCxXQUFXOzRCQUNYLElBQUk7NEJBQ0osU0FBUzs0QkFDVCxnQkFBZ0I7NEJBQ2hCLE9BQU8sRUFBRSxVQUFVOzRCQUNuQixTQUFTLEVBQUUsY0FBYzs0QkFDekIsTUFBTTt5QkFDUCxDQUFDO3FCQUNILENBQUMsQ0FBQztvQkFDSCx3REFBd0Q7b0JBQ3hELHdEQUF3RDtvQkFDeEQseURBQXlEO29CQUN6RCxvREFBb0Q7b0JBQ3BELDBEQUEwRDtvQkFDMUQsa0NBQWtDO29CQUNsQyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7d0JBQ3RDLE1BQU0sV0FBVyxDQUFDLE1BQU0sQ0FBQztvQkFDM0IsQ0FBQztvQkFDRCxjQUFjLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDdkMsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO3dCQUN2QyxNQUFNLEdBQUcsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDO3dCQUNoQyxJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDOzRCQUNoQyx1REFBdUQ7NEJBQ3ZELG9EQUFvRDs0QkFDcEQsK0NBQStDOzRCQUMvQyxPQUFPO3dCQUNULENBQUM7d0JBQ0QsSUFBSSxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDOzRCQUMvQix1REFBdUQ7NEJBQ3ZELHFEQUFxRDs0QkFDckQsbURBQW1EOzRCQUNuRCxrREFBa0Q7NEJBQ2xELGFBQWE7NEJBQ2IsYUFBYSxDQUFDLElBQUksQ0FDaEIscURBQXFEO2dDQUNuRCxtREFBbUQ7Z0NBQ25ELHdDQUF3QyxFQUMxQztnQ0FDRSxhQUFhLEVBQUUsS0FBSztnQ0FDcEIsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO2dDQUNqQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU07Z0NBQ3JCLEtBQUssRUFBRSxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDOzZCQUN4RCxDQUNGLENBQUM7NEJBQ0YsTUFBTSxDQUFDLG1DQUFtQyxFQUFFO2dDQUMxQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07Z0NBQ25CLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTs2QkFDbEMsQ0FBQyxDQUFDOzRCQUNILE9BQU87d0JBQ1QsQ0FBQzt3QkFDRCxNQUFNLEdBQUcsQ0FBQztvQkFDWixDQUFDO29CQUNELE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCxJQUFJLENBQUM7b0JBQ0gsTUFBTSxXQUFXLENBQUM7d0JBQ2hCLFNBQVMsRUFBRSxjQUFjO3dCQUN6QixXQUFXLEVBQUUsb0JBQW9CO3dCQUNqQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7d0JBQ2pDLFNBQVMsRUFBRTs0QkFDVCxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU07NEJBQ3JCLEtBQUssRUFBRSxjQUFjO3lCQUN0QjtxQkFDRixDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO29CQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQzt3QkFBRSxPQUFPO29CQUN4QyxNQUFNLEdBQUcsQ0FBQztnQkFDWixDQUFDO2dCQUVELDhEQUE4RDtnQkFDOUQsMkRBQTJEO2dCQUMzRCxvREFBb0Q7Z0JBQ3BELHFCQUFxQjtZQUN2QixDQUFDLENBQUMsRUFBRSxDQUNMLENBQUM7UUFDSixDQUFDO2FBQU0sSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLFdBQVcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMxRCxNQUFNLElBQUksR0FBRyxFQUFzQixDQUFDO1lBQ3BDLFdBQVcsQ0FBQyxJQUFJLENBQ2QsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDVixJQUFJLENBQUM7b0JBQ0gsTUFBTSxXQUFXLENBQUM7d0JBQ2hCLFNBQVMsRUFBRSxVQUFVO3dCQUNyQixXQUFXLEVBQUUsb0JBQW9CO3dCQUNqQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7d0JBQ2pDLFNBQVMsRUFBRTs0QkFDVCxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87NEJBQ3JCLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7NEJBQzVCLEdBQUcsQ0FBQyxJQUFJLENBQUMsdUJBQXVCO2dDQUM5QixDQUFDLENBQUMsRUFBRSx1QkFBdUIsRUFBRSxJQUFJLEVBQUU7Z0NBQ25DLENBQUMsQ0FBQyxFQUFFLENBQUM7eUJBQ0Q7cUJBQ1QsQ0FBQyxDQUFDO29CQUNILHFCQUFxQixHQUFHLElBQUksQ0FBQztnQkFDL0IsQ0FBQztnQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO29CQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7d0JBQ2hDLHdEQUF3RDt3QkFDeEQsZ0RBQWdEO3dCQUNoRCxxQkFBcUIsR0FBRyxJQUFJLENBQUM7d0JBQzdCLE9BQU87b0JBQ1QsQ0FBQztvQkFDRCxNQUFNLEdBQUcsQ0FBQztnQkFDWixDQUFDO1lBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FDTCxDQUFDO1FBQ0osQ0FBQzthQUFNLElBQUksRUFBRSxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDckQsTUFBTSxJQUFJLEdBQUcsRUFBaUIsQ0FBQztZQUMvQixXQUFXLENBQUMsSUFBSSxDQUNkLENBQUMsS0FBSyxJQUFJLEVBQUU7Z0JBQ1YsSUFBSSxDQUFDO29CQUNILE1BQU0sV0FBVyxDQUFDO3dCQUNoQixTQUFTLEVBQUUsY0FBYzt3QkFDekIsV0FBVyxFQUFFLG9CQUFvQjt3QkFDakMsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO3dCQUNqQyxTQUFTLEVBQUU7NEJBQ1QsUUFBUSxFQUFFLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7eUJBQ2xDO3FCQUNGLENBQUMsQ0FBQztnQkFDTCxDQUFDO2dCQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7b0JBQ2IsSUFBSSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO3dCQUFFLE9BQU87b0JBQ3hDLE1BQU0sR0FBRyxDQUFDO2dCQUNaLENBQUM7WUFDSCxDQUFDLENBQUMsRUFBRSxDQUNMLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELG9DQUFvQztJQUNwQyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7SUFFL0IsT0FBTztRQUNMLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIsY0FBYztRQUNkLDJCQUEyQjtLQUM1QixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTZCRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsc0JBQXNCLENBQUMsTUF1RjVDO0lBQ0MsTUFBTSxFQUNKLFlBQVksRUFDWixZQUFZLEVBQ1osV0FBVyxFQUNYLGVBQWUsRUFDZix1QkFBdUIsRUFDdkIsZUFBZSxFQUNmLFFBQVEsRUFDUixVQUFVLEVBQ1YsY0FBYyxFQUNkLGVBQWUsRUFDZixjQUFjLEVBQ2QsU0FBUyxFQUNULFNBQVMsRUFDVCxnQkFBZ0IsR0FDakIsR0FBRyxNQUFNLENBQUM7SUFFWDs7Ozs7OztPQU9HO0lBQ0gsTUFBTSwyQkFBMkIsR0FBRyxDQUFDLGFBQXFCLEVBQVUsRUFBRSxDQUNwRSxnQkFBZ0IsRUFBRSxhQUFhLEtBQUssYUFBYTtRQUMvQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxHQUFHLENBQUM7UUFDOUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNSLG1FQUFtRTtJQUNuRSx5REFBeUQ7SUFDekQsTUFBTSxnQkFBZ0IsR0FDcEIsTUFBTSxDQUFDLGdCQUFnQixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxDQUFDO0lBQzdELE1BQU0sS0FBSyxHQUFHLE1BQU0sUUFBUSxFQUFFLENBQUM7SUFDL0IsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQztJQUNoQyxNQUFNLGVBQWUsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUUvQixzRUFBc0U7SUFDdEUsMkRBQTJEO0lBQzNELG9FQUFvRTtJQUNwRSw0REFBNEQ7SUFDNUQscUVBQXFFO0lBQ3JFLDhCQUE4QjtJQUM5QixNQUFNLGlCQUFpQixHQUFHLG9CQUFvQixDQUFDLFlBQVksQ0FBQyxDQUFDO0lBRTdELHVFQUF1RTtJQUN2RSxzRUFBc0U7SUFDdEUsc0JBQXNCO0lBQ3RCLE1BQU0sWUFBWSxHQUFHLE9BQU8sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFFdEUsdUVBQXVFO0lBQ3ZFLE1BQU0sTUFBTSxHQUFHLENBQUMsVUFBa0IsRUFBRSxNQUErQixFQUFFLEVBQUU7UUFDckUsYUFBYSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsRUFBRTtZQUNyQyxVQUFVO1lBQ1YsS0FBSztZQUNMLFlBQVk7WUFDWixVQUFVLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxlQUFlLENBQUM7WUFDaEQsR0FBRyxNQUFNO1NBQ1YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0lBRUYsVUFBVSxFQUFFLGFBQWEsQ0FBQztRQUN4QixHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDO0tBQ25DLENBQUMsQ0FBQztJQUVILE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZCxZQUFZO1FBQ1osZUFBZTtRQUNmLGtCQUFrQixFQUNoQixLQUFLLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxJQUFJLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUM5RCxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsTUFBTSxJQUFJLENBQUM7UUFDakQsV0FBVyxFQUFFLENBQUMsQ0FBQyxRQUFRO0tBQ3hCLENBQUMsQ0FBQztJQUVILHdFQUF3RTtJQUN4RSxrREFBa0Q7SUFDbEQsTUFBTSxVQUFVLEdBQUcsWUFBWSxDQUFDO0lBRWhDLCtEQUErRDtJQUMvRCxzRUFBc0U7SUFDdEUsd0VBQXdFO0lBQ3hFLDBFQUEwRTtJQUMxRSx1RUFBdUU7SUFDdkUsZ0VBQWdFO0lBQ2hFLDBFQUEwRTtJQUMxRSwwRUFBMEU7SUFDMUUsdUVBQXVFO0lBQ3ZFLHVDQUF1QztJQUN2QyxNQUFNLE1BQU0sR0FBRyxNQUFNLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBRTlFLCtEQUErRDtJQUMvRCxzRUFBc0U7SUFDdEUsbUVBQW1FO0lBQ25FLHlEQUF5RDtJQUN6RCxJQUFJLE1BQWUsQ0FBQztJQUNwQixJQUFJLGtCQUFrQixHQUFHLENBQUMsQ0FBQztJQUMzQiwwRUFBMEU7SUFDMUUsMEVBQTBFO0lBQzFFLHFDQUFxQztJQUNyQyxJQUFJLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBQ3ZDLE1BQU0sWUFBWSxHQUNoQixDQUFDLHVCQUF1QixLQUFLLElBQUk7UUFDL0IsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7UUFDOUIsZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDN0IsaUJBQWlCLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDckMsSUFBSSxZQUFZLElBQUksZUFBZSxFQUFFLENBQUM7UUFDcEMsTUFBTSxHQUFHLGVBQWUsQ0FBQztRQUN6QixZQUFZLEdBQUcsZUFBZSxJQUFJLElBQUksQ0FBQztJQUN6QyxDQUFDO1NBQU0sQ0FBQztRQUNOLE1BQU0sU0FBUyxHQUFZLEVBQUUsQ0FBQztRQUM5QixJQUFJLE1BQU0sR0FBa0IsSUFBSSxDQUFDO1FBQ2pDLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQztRQUVuQixPQUFPLE9BQU8sRUFBRSxDQUFDO1lBQ2YsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDdkMsS0FBSztnQkFDTCxVQUFVLEVBQUU7b0JBQ1YsU0FBUyxFQUFFLEtBQUs7b0JBQ2hCLE1BQU0sRUFBRSxNQUFNLElBQUksU0FBUztvQkFDM0IsS0FBSyxFQUFFLElBQUk7aUJBQ1o7YUFDRixDQUFDLENBQUM7WUFDSCxrQkFBa0IsRUFBRSxDQUFDO1lBQ3JCLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDakMsb0VBQW9FO1lBQ3BFLGlFQUFpRTtZQUNqRSx5RUFBeUU7WUFDekUsSUFBSSxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQzNCLENBQUM7WUFDRCxPQUFPLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDO1FBQ2hFLENBQUM7UUFFRCxNQUFNLEdBQUcsU0FBUyxDQUFDO1FBQ25CLFlBQVksR0FBRyxNQUFNLENBQUM7SUFDeEIsQ0FBQztJQUVELHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUsdUVBQXVFO0lBQ3ZFLG1FQUFtRTtJQUNuRSxNQUFNLE9BQU8sR0FBRyxJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDekQsTUFBTSxXQUFXLEdBQWlCLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLEVBQUU7UUFDNUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFO1lBQ3BELEdBQUcsV0FBVztZQUNkLEdBQUcsT0FBTyxDQUFDLGNBQWMsRUFBRTtTQUM1QixDQUFDLENBQUM7UUFDSCxJQUNFLE9BQU8sV0FBVyxFQUFFLFdBQVcsS0FBSyxRQUFRO1lBQzVDLE1BQU0sQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUMzQixDQUFDO1lBQ0QscUVBQXFFO1lBQ3JFLGtFQUFrRTtZQUNsRSxrRUFBa0U7WUFDbEUsMERBQTBEO1lBQzFELE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDeEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFO2dCQUM1RCxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07Z0JBQ3JCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUk7Z0JBQzdCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxJQUFJLEtBQUs7YUFDakMsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLHVCQUF1QixFQUFFO2dCQUM5QixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ3pCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU07Z0JBQzVCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxJQUFJLEtBQUs7Z0JBQ2hDLGNBQWMsRUFBRSxRQUFRO2FBQ3pCLENBQUMsQ0FBQztZQUNILE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7UUFDRCx1RUFBdUU7UUFDdkUseUVBQXlFO1FBQ3pFLDhEQUE4RDtRQUM5RCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtZQUN0QyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsS0FBSyxnQkFBZ0I7U0FDbEQsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdkIsYUFBYSxDQUFDLEtBQUssQ0FDakIsMERBQTBELEVBQzFEO2dCQUNFLGFBQWEsRUFBRSxLQUFLO2dCQUNwQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ3pCLE9BQU8sRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFLE9BQU87Z0JBQzlCLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sSUFBSSxDQUFDO2FBQ3BDLENBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7SUFDRjs7Ozs7T0FLRztJQUNILE1BQU0sbUJBQW1CLEdBQWlCLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxFQUFFLENBQzlELEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFFaEQsaUVBQWlFO0lBQ2pFLHFFQUFxRTtJQUNyRSx3QkFBd0I7SUFDeEIsSUFBSSxjQUFjLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxNQUFNLElBQUksY0FBYyxFQUFFLENBQUM7UUFDcEUsTUFBTSxJQUFJLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVELFVBQVUsRUFBRSxhQUFhLENBQUM7UUFDeEIsR0FBRyxTQUFTLENBQUMsc0JBQXNCLENBQUMsWUFBWSxDQUFDO1FBQ2pELEdBQUcsU0FBUyxDQUFDLHlCQUF5QixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDckQsR0FBRyxTQUFTLENBQUMseUJBQXlCLENBQUMsa0JBQWtCLENBQUM7S0FDM0QsQ0FBQyxDQUFDO0lBRUgsTUFBTSxDQUFDLGdCQUFnQixFQUFFO1FBQ3ZCLFVBQVUsRUFBRSxNQUFNLENBQUMsTUFBTTtRQUN6QixrQkFBa0I7UUFDbEIsWUFBWTtRQUNaLFVBQVUsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUF5QixDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMzRCxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDL0MsT0FBTyxHQUFHLENBQUM7UUFDYixDQUFDLEVBQUUsRUFBRSxDQUFDO0tBQ1AsQ0FBQyxDQUFDO0lBRUgsMEJBQTBCO0lBQzFCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN2QixNQUFNLGdCQUFnQixHQUFHLElBQUksR0FBRyxDQUM5QixNQUFNO1NBQ0gsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxLQUFLLGdCQUFnQixDQUFDO1NBQy9DLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUMvQixDQUFDO0lBQ0YsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUMzQixJQUNFLEtBQUssQ0FBQyxTQUFTLEtBQUssY0FBYztZQUNsQyxLQUFLLENBQUMsYUFBYTtZQUNuQixDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLEVBQzFDLENBQUM7WUFDRCxNQUFNLFNBQVMsR0FDYixXQUFXLElBQUksS0FBSztnQkFDbEIsQ0FBQyxDQUFFLEtBQUssQ0FBQyxTQUFxQztnQkFDOUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUNoQixNQUFNLFFBQVEsR0FBRyxTQUFTLEVBQUUsUUFBUSxDQUFDO1lBQ3JDLElBQUksUUFBUSxJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFrQixDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztnQkFDOUQsSUFBSSxDQUFDO29CQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sV0FBVyxDQUFDO3dCQUMvQixTQUFTLEVBQUUsZ0JBQWdCO3dCQUMzQixXQUFXLEVBQUUsb0JBQW9CO3dCQUNqQyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7cUJBQ25DLENBQUMsQ0FBQztvQkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7d0JBQ3RDLDhEQUE4RDt3QkFDOUQsb0RBQW9EO3dCQUNwRCxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDNUIsQ0FBQztnQkFDSCxDQUFDO2dCQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7b0JBQ2IsSUFBSSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO3dCQUFFLFNBQVM7b0JBQzFDLE1BQU0sR0FBRyxDQUFDO2dCQUNaLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCxxRUFBcUU7SUFDckUsMEVBQTBFO0lBQzFFLDZEQUE2RDtJQUM3RCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7SUFFekMseUVBQXlFO0lBQ3pFLHdFQUF3RTtJQUN4RSx3REFBd0Q7SUFDeEQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEtBQUssU0FBUyxDQUFDO0lBQ3RELE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLFdBQVcsRUFBRSxDQUFDO0lBRXhELHFDQUFxQztJQUNyQyxhQUFhLENBQUMsS0FBSyxDQUFDLDhCQUE4QixFQUFFO1FBQ2xELGFBQWEsRUFBRSxLQUFLO1FBQ3BCLFVBQVU7UUFDVixVQUFVLEVBQUUsTUFBTSxDQUFDLE1BQU07S0FDMUIsQ0FBQyxDQUFDO0lBRUgsTUFBTSxPQUFPLEdBQUcsTUFBTSxvQkFBb0IsQ0FBQztRQUN6Qyw4REFBOEQ7UUFDOUQsZ0VBQWdFO1FBQ2hFLG1FQUFtRTtRQUNuRSxtREFBbUQ7UUFDbkQsWUFBWSxFQUFFLGlCQUFpQjtRQUMvQixVQUFVO1FBQ1YsV0FBVztRQUNYLE1BQU07UUFDTixpQkFBaUIsRUFBRSxLQUFLLENBQUMsWUFBWTtRQUNyQyxhQUFhO1FBQ2IsSUFBSTtRQUNKLFFBQVE7S0FDVCxDQUFDLENBQUM7SUFDSCxJQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO0lBRTVCLGFBQWEsQ0FBQyxLQUFLLENBQUMsOEJBQThCLEVBQUU7UUFDbEQsYUFBYSxFQUFFLEtBQUs7UUFDcEIsU0FBUyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUztRQUM3QixTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTO1FBQzdCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU07UUFDdkIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsTUFBTTtLQUM3RCxDQUFDLENBQUM7SUFFSCxNQUFNLENBQUMsYUFBYSxFQUFFO1FBQ3BCLE9BQU8sRUFBRSxNQUFNLENBQUMsU0FBUztZQUN2QixDQUFDLENBQUMsV0FBVztZQUNiLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUztnQkFDaEIsQ0FBQyxDQUFDLFdBQVc7Z0JBQ2IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNO29CQUNiLENBQUMsQ0FBQyxRQUFRO29CQUNWLENBQUMsQ0FBQyxTQUFTO1FBQ2pCLGVBQWUsRUFBRSxNQUFNLENBQUMsU0FBUyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sSUFBSSxDQUFDO1FBQ2pFLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2pFLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSTtZQUNaLGFBQWEsRUFBRSxDQUFDLENBQUMsYUFBYTtZQUM5QixlQUFlLEVBQUUsQ0FBQyxDQUFDLGVBQWU7WUFDbEMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRyxDQUFpQixDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7U0FDcEUsQ0FBQyxDQUFDO1FBQ0gsY0FBYyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTztRQUN0QyxXQUFXLEVBQUUsTUFBTSxDQUFDLE1BQU0sRUFBRSxJQUFJO0tBQ2pDLENBQUMsQ0FBQztJQUVILHFDQUFxQztJQUNyQyxFQUFFO0lBQ0Ysb0VBQW9FO0lBQ3BFLG9FQUFvRTtJQUNwRSxFQUFFO0lBQ0Ysc0VBQXNFO0lBQ3RFLGdFQUFnRTtJQUNoRSw2REFBNkQ7SUFDN0QsdUVBQXVFO0lBQ3ZFLHlFQUF5RTtJQUN6RSxpRUFBaUU7SUFDakUsbUVBQW1FO0lBQ25FLG1FQUFtRTtJQUNuRSwrREFBK0Q7SUFDL0QscUVBQXFFO0lBQ3JFLDJEQUEyRDtJQUMzRCxxREFBcUQ7SUFDckQsdUVBQXVFO0lBQ3ZFLHFFQUFxRTtJQUNyRSxpRUFBaUU7SUFDakUsc0VBQXNFO0lBQ3RFLG9FQUFvRTtJQUNwRSxxRUFBcUU7SUFDckUsdUVBQXVFO0lBQ3ZFLGlCQUFpQjtJQUNqQixFQUFFO0lBQ0YsbUVBQW1FO0lBQ25FLHFFQUFxRTtJQUNyRSxRQUFRO0lBQ1IsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUN2QyxLQUFLLE1BQU0sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxDQUFDLE9BQU87WUFBRSxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBQ0Qsd0RBQXdEO0lBQ3hELE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDMUMsZ0VBQWdFO0lBQ2hFLE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDeEMsbUVBQW1FO0lBQ25FLGlFQUFpRTtJQUNqRSx5Q0FBeUM7SUFDekMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBQzNDLG9FQUFvRTtJQUNwRSxNQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDNUMsb0VBQW9FO0lBQ3BFLGlFQUFpRTtJQUNqRSxzRUFBc0U7SUFDdEUsZ0VBQWdFO0lBQ2hFLHFFQUFxRTtJQUNyRSxrRUFBa0U7SUFDbEUsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLEVBRzFCLENBQUM7SUFDSixNQUFNLHlCQUF5QixHQUFHLENBQUMsUUFBaUIsRUFBUSxFQUFFO1FBQzVELEtBQUssTUFBTSxDQUFDLElBQUksUUFBUSxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLENBQUMsYUFBYSxLQUFLLFNBQVM7Z0JBQUUsU0FBUztZQUM1QyxJQUFJLENBQUMsQ0FBQyxTQUFTLEtBQUssY0FBYyxFQUFFLENBQUM7Z0JBQ25DLE1BQU0sS0FBSyxHQUNULFdBQVcsSUFBSSxDQUFDO29CQUNoQixDQUFDLENBQUMsU0FBUztvQkFDWCxnQkFBZ0IsSUFBSSxDQUFDLENBQUMsU0FBUztvQkFDL0IsT0FBTyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsS0FBSyxRQUFRO29CQUM1QyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxjQUFjO29CQUM1QixDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUNoQixNQUFNLEtBQUssR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDakQsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFO29CQUNqQyxLQUFLO29CQUNMLFdBQVcsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztvQkFDN0QsV0FBVyxFQUFFLEtBQUssRUFBRSxXQUFXLElBQUksS0FBSztpQkFDekMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxJQUFJLENBQUMsQ0FBQyxTQUFTLEtBQUssZUFBZSxFQUFFLENBQUM7Z0JBQzNDLE1BQU0sS0FBSyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUNqRCxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUU7b0JBQ2pDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDO29CQUNoQixXQUFXLEVBQUUsSUFBSTtpQkFDbEIsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDLENBQUM7SUFDRix5QkFBeUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxNQUFNLDBCQUEwQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDckQsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBQ2xDLE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDLFNBQVM7UUFDN0MsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLFNBQVM7UUFDeEIsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNmLE1BQU0sU0FBUyxHQUNaLFdBQVcsQ0FBQyxVQUFpRCxFQUFFLENBQzlELHFCQUFxQixDQUN0QixJQUFJLEtBQUssQ0FBQztJQUNiLElBQUksbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0lBQzVCLElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNwQix1RUFBdUU7SUFDdkUscUVBQXFFO0lBQ3JFLDBFQUEwRTtJQUMxRSx1RUFBdUU7SUFDdkUsdUVBQXVFO0lBQ3ZFLHNFQUFzRTtJQUN0RSxvQ0FBb0M7SUFDcEMsSUFBSSxvQkFBb0IsR0FBRyxLQUFLLENBQUM7SUFFakM7Ozs7Ozs7T0FPRztJQUNILE1BQU0saUJBQWlCLEdBQUcsS0FBSyxJQUFzQixFQUFFO1FBQ3JELE1BQU0sTUFBTSxHQUFZLEVBQUUsQ0FBQztRQUMzQixJQUFJLE1BQU0sR0FBa0IsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUM5QyxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDbkIsT0FBTyxPQUFPLEVBQUUsQ0FBQztZQUNmLE1BQU0sUUFBUSxHQUFHLE1BQU0sS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZDLEtBQUs7Z0JBQ0wsVUFBVSxFQUFFO29CQUNWLFNBQVMsRUFBRSxLQUFLO29CQUNoQixNQUFNLEVBQUUsTUFBTSxJQUFJLFNBQVM7b0JBQzNCLEtBQUssRUFBRSxJQUFJO2lCQUNaO2FBQ0YsQ0FBQyxDQUFDO1lBQ0gsS0FBSyxNQUFNLENBQUMsSUFBSSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQzlCLElBQUksQ0FBQyxDQUFDLE9BQU8sSUFBSSxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7b0JBQUUsU0FBUztnQkFDdkQsSUFBSSxDQUFDLENBQUMsT0FBTztvQkFBRSxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDM0MsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNqQixDQUFDO1lBQ0QsSUFBSSxRQUFRLENBQUMsTUFBTTtnQkFBRSxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQztZQUM5QyxPQUFPLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDO1FBQ2hFLENBQUM7UUFDRCxPQUFPLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlCLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDeEIseUJBQXlCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQyxDQUFDO0lBRUY7Ozs7Ozs7O09BUUc7SUFDSCxNQUFNLGdCQUFnQixHQUFHLEdBQVksRUFBRTtRQUNyQyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDeEMsS0FBSyxNQUFNLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUN2QixJQUFJLENBQUMsQ0FBQyxPQUFPO2dCQUFFLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCx5QkFBeUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsQyxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7SUFFRixJQUFJLENBQUM7UUFDSCxJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFDbEIsT0FBTyxNQUFNLENBQUMsU0FBUyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7WUFDN0QsU0FBUyxFQUFFLENBQUM7WUFDWixvRUFBb0U7WUFDcEUscUVBQXFFO1lBQ3JFLHFFQUFxRTtZQUNyRSxtRUFBbUU7WUFDbkUsOERBQThEO1lBQzlELFNBQVM7WUFDVCxJQUFJLGNBQWMsS0FBSyxTQUFTLElBQUksWUFBWSxDQUFDLElBQUksSUFBSSxjQUFjLEVBQUUsQ0FBQztnQkFDeEUsTUFBTSxJQUFJLHNCQUFzQixDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDdEUsQ0FBQztZQUNELE1BQU0saUJBQWlCLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQztZQUU3RCxvRUFBb0U7WUFDcEUscUVBQXFFO1lBQ3JFLGtFQUFrRTtZQUNsRSxnRUFBZ0U7WUFDaEUsa0VBQWtFO1lBQ2xFLGlFQUFpRTtZQUNqRSxrRUFBa0U7WUFDbEUsb0VBQW9FO1lBQ3BFLG9DQUFvQztZQUNwQyxNQUFNLFVBQVUsR0FBRyxpQkFBaUIsQ0FBQyxNQUFNLENBQ3pDLENBQUMsRUFBRSxFQUFxQixFQUFFLENBQ3hCLEVBQUUsQ0FBQyxJQUFJLEtBQUssTUFBTTtnQkFDbEIsQ0FBQyxFQUFFLENBQUMsZUFBZTtnQkFDbkIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUM7Z0JBQ3RDLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQ3ZDLENBQUM7WUFDRiw4Q0FBOEM7WUFDOUMsa0VBQWtFO1lBQ2xFLGdFQUFnRTtZQUNoRSxvRUFBb0U7WUFDcEUsK0RBQStEO1lBQy9ELHNCQUFzQjtZQUN0QixNQUFNLFlBQVksR0FBRyxVQUFVLENBQUMsTUFBTSxDQUNwQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQ25DLENBQUM7WUFDRixNQUFNLGdCQUFnQixHQUNwQixjQUFjLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ25FLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxDQUM3QixnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FDbkQsQ0FBQztZQUVGLDZEQUE2RDtZQUM3RCxNQUFNLGFBQWEsR0FBRyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUNqRCxFQUFFLENBQUMsSUFBSSxLQUFLLE1BQU07Z0JBQ2pCLEVBQWtCLENBQUMsY0FBYztnQkFDbEMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUM7Z0JBQ3BDLENBQUMsQ0FBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQXVCO2dCQUN4RCxDQUFDLENBQUMsRUFBRSxDQUNQLENBQUM7WUFDRixLQUFLLE1BQU0sRUFBRSxJQUFJLGlCQUFpQixFQUFFLENBQUM7Z0JBQ25DLElBQUksRUFBRSxDQUFDLElBQUksS0FBSyxNQUFNLElBQUssRUFBa0IsQ0FBQyxjQUFjLEVBQUUsQ0FBQztvQkFDN0QsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDekMsQ0FBQztZQUNILENBQUM7WUFDRCxrRUFBa0U7WUFDbEUsbUVBQW1FO1lBQ25FLGtFQUFrRTtZQUNsRSxrRUFBa0U7WUFDbEUsaUVBQWlFO1lBQ2pFLG1FQUFtRTtZQUNuRSx1REFBdUQ7WUFDdkQsNkRBQTZEO1lBQzdELCtEQUErRDtZQUMvRCxtRUFBbUU7WUFDbkUscUVBQXFFO1lBQ3JFLHFFQUFxRTtZQUNyRSwrREFBK0Q7WUFDL0QsTUFBTSxhQUFhLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNsRSxNQUFNLFVBQVUsR0FBRyxNQUFNLGtCQUFrQixDQUFDO2dCQUMxQyxLQUFLO2dCQUNMLEtBQUs7Z0JBQ0wsV0FBVztnQkFDWCxhQUFhO2dCQUNiLFNBQVM7Z0JBQ1QsZ0JBQWdCO2dCQUNoQixXQUFXO2dCQUNYLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLE9BQU8sT0FBTyxDQUFDLFNBQVMsS0FBSyxRQUFRO29CQUMzRCxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLFNBQVMsRUFBRTtvQkFDcEMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDUCxpQkFBaUIsRUFBRSxhQUFhO2dCQUNoQyxnQkFBZ0IsRUFBRSxlQUFlO2dCQUNqQyxhQUFhLEVBQUUsSUFBSSxHQUFHLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUNqRSwyQkFBMkIsRUFBRSxJQUFJO2dCQUNqQyxNQUFNO2FBQ1AsQ0FBQyxDQUFDO1lBQ0gsSUFDRSxVQUFVLENBQUMscUJBQXFCO2dCQUNoQyxVQUFVLENBQUMsc0JBQXNCLEVBQ2pDLENBQUM7Z0JBQ0Qsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO1lBQzlCLENBQUM7WUFDRCw4REFBOEQ7WUFDOUQsK0RBQStEO1lBQy9ELG9FQUFvRTtZQUNwRSw2REFBNkQ7WUFDN0QsOERBQThEO1lBQzlELDZEQUE2RDtZQUM3RCxzQ0FBc0M7WUFDdEMsSUFBSSxVQUFVLENBQUMsMkJBQTJCLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxvQkFBb0IsR0FBRyxJQUFJLENBQUM7Z0JBQzVCLEtBQUssTUFBTSxHQUFHLElBQUksVUFBVSxDQUFDLDJCQUEyQixFQUFFLENBQUM7b0JBQ3pELGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzNCLENBQUM7WUFDSCxDQUFDO1lBRUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxVQUFVLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQzVDLGFBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDekIsQ0FBQztZQUNELE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDZixhQUFhO2lCQUNWLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7aUJBQ3BFLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUNaLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUN0QyxPQUFPLGdCQUFnQixDQUFDO29CQUN0QixLQUFLO29CQUNMLEtBQUs7b0JBQ0wsV0FBVztvQkFDWCxJQUFJO29CQUNKLFNBQVM7b0JBQ1QsZ0JBQWdCO29CQUNoQixPQUFPLEVBQUUsVUFBVTtvQkFDbkIsTUFBTTtpQkFDUCxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FDTCxDQUFDO1lBRUYsbUVBQW1FO1lBQ25FLDJEQUEyRDtZQUMzRCxNQUFNLG9CQUFvQixHQUFvQixFQUFFLENBQUM7WUFDakQsS0FBSyxNQUFNLEVBQUUsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO2dCQUNuQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEtBQUssTUFBTTtvQkFBRSxTQUFTO2dCQUNqQyxNQUFNLElBQUksR0FBRyxFQUFpQixDQUFDO2dCQUMvQixJQUFJLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO29CQUFFLFNBQVM7Z0JBQ3hELElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO29CQUFFLFNBQVM7Z0JBQ2pFLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBQzFDLG9CQUFvQixDQUFDLElBQUksQ0FDdkIsQ0FBQyxLQUFLLElBQUksRUFBRTtvQkFDVixJQUFJLENBQUM7d0JBQ0gsTUFBTSxXQUFXLENBQUM7NEJBQ2hCLFNBQVMsRUFBRSxnQkFBZ0I7NEJBQzNCLFdBQVcsRUFBRSxvQkFBb0I7NEJBQ2pDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTt5QkFDbEMsQ0FBQyxDQUFDO29CQUNMLENBQUM7b0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQzt3QkFDYixJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUM7NEJBQUUsT0FBTzt3QkFDeEMsTUFBTSxHQUFHLENBQUM7b0JBQ1osQ0FBQztnQkFDSCxDQUFDLENBQUMsRUFBRSxDQUNMLENBQUM7WUFDSixDQUFDO1lBQ0QsSUFBSSxvQkFBb0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQzFDLENBQUM7WUFFRCxvRUFBb0U7WUFDcEUsdUVBQXVFO1lBQ3ZFLHVFQUF1RTtZQUN2RSxxRUFBcUU7WUFDckUsZ0VBQWdFO1lBQ2hFLHNFQUFzRTtZQUN0RSxtRUFBbUU7WUFDbkUsdUVBQXVFO1lBQ3ZFLHVFQUF1RTtZQUN2RSxlQUFlO1lBQ2YsQ0FBQztnQkFDQyxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNsQyxNQUFNLFNBQVMsR0FDYixNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3pELElBQUksU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDekIsOERBQThEO29CQUM5RCw2REFBNkQ7b0JBQzdELDZEQUE2RDtvQkFDN0Qsb0JBQW9CLEdBQUcsS0FBSyxDQUFDO29CQUM3QixNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQ3JELE1BQU0sQ0FBQyxrQkFBa0IsRUFBRTt3QkFDekIsU0FBUzt3QkFDVCxLQUFLLEVBQUUsTUFBTTt3QkFDYixTQUFTLEVBQUUsU0FBUyxDQUFDLE1BQU07d0JBQzNCLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLE1BQU07d0JBQ3RELE9BQU8sRUFBRSxNQUFNLENBQUMsU0FBUzs0QkFDdkIsQ0FBQyxDQUFDLFdBQVc7NEJBQ2IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNO2dDQUNiLENBQUMsQ0FBQyxRQUFRO2dDQUNWLENBQUMsQ0FBQyxXQUFXO3FCQUNsQixDQUFDLENBQUM7b0JBQ0gsU0FBUztnQkFDWCxDQUFDO1lBQ0gsQ0FBQztZQUVELHNEQUFzRDtZQUN0RCxNQUFNLE9BQU8sR0FBRyxpQkFBaUIsQ0FBQyxNQUFNLENBQ3RDLENBQUMsRUFBRSxFQUFxQixFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksS0FBSyxNQUFNLENBQzlDLENBQUM7WUFDRixtRUFBbUU7WUFDbkUsbUVBQW1FO1lBQ25FLGtFQUFrRTtZQUNsRSxvRUFBb0U7WUFDcEUsb0VBQW9FO1lBQ3BFLGdFQUFnRTtZQUNoRSx3REFBd0Q7WUFDeEQsRUFBRTtZQUNGLG9FQUFvRTtZQUNwRSxnRUFBZ0U7WUFDaEUsNkRBQTZEO1lBQzdELGtFQUFrRTtZQUNsRSxtRUFBbUU7WUFDbkUsa0VBQWtFO1lBQ2xFLG9CQUFvQjtZQUNwQixtRUFBbUU7WUFDbkUsc0RBQXNEO1lBQ3RELG1FQUFtRTtZQUNuRSxtRUFBbUU7WUFDbkUsNERBQTREO1lBQzVELCtEQUErRDtZQUMvRCx3QkFBd0I7WUFDeEIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3pCLEtBQUssTUFBTSxJQUFJLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZTtvQkFBRSxTQUFTO2dCQUNwQyxJQUFJLGVBQWUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztvQkFBRSxTQUFTO2dCQUN0RCxJQUFJLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztvQkFBRSxTQUFTO2dCQUNwRCxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDeEQsTUFBTSxlQUFlLEdBQ25CLFNBQVMsS0FBSyxTQUFTO29CQUN2QixTQUFTLENBQUMsS0FBSyxLQUFLLFNBQVM7b0JBQzdCLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQztnQkFDekIsSUFBSSxxQkFBcUIsR0FBRyxDQUFDLENBQUM7Z0JBQzlCLElBQUksZUFBZSxJQUFJLFNBQVMsQ0FBQyxXQUFXLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQzNELE1BQU0sWUFBWSxHQUFHLDhCQUE4QixFQUFFLENBQUM7b0JBQ3RELHFCQUFxQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQzlCLFlBQVksRUFDWixJQUFJLENBQUMsR0FBRyxDQUNOLENBQUMsRUFDRCxJQUFJLENBQUMsSUFBSSxDQUNQLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRyxZQUFZLEdBQUcsSUFBSSxHQUFHLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FDN0QsQ0FDRixDQUNGLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxJQUNFLGVBQWU7b0JBQ2YsU0FBUyxDQUFDLEtBQUssS0FBSyxjQUFjO29CQUNsQyxxQkFBcUIsR0FBRyxDQUFDLEVBQ3pCLENBQUM7b0JBQ0QsYUFBYSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQ3RDLE1BQU0sZ0JBQWdCLENBQUM7d0JBQ3JCLEtBQUs7d0JBQ0wsS0FBSzt3QkFDTCxXQUFXO3dCQUNYLElBQUk7d0JBQ0osWUFBWSxFQUFFLHFCQUFxQjt3QkFDbkMsU0FBUzt3QkFDVCxnQkFBZ0I7d0JBQ2hCLE9BQU8sRUFBRSxZQUFZLFNBQVMsQ0FBQyxXQUFXLEVBQUU7d0JBQzVDLE1BQU07cUJBQ1AsQ0FBQyxDQUFDO2dCQUNMLENBQUM7cUJBQU0sQ0FBQztvQkFDTixhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDdEMsTUFBTSxnQkFBZ0IsQ0FBQzt3QkFDckIsS0FBSzt3QkFDTCxLQUFLO3dCQUNMLFdBQVc7d0JBQ1gsSUFBSTt3QkFDSixTQUFTO3dCQUNULGdCQUFnQjt3QkFDaEIsT0FBTyxFQUFFLFVBQVU7d0JBQ25CLE1BQU07cUJBQ1AsQ0FBQyxDQUFDO2dCQUNMLENBQUM7WUFDSCxDQUFDO1lBRUQsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ2xDLDhEQUE4RDtnQkFDOUQsb0RBQW9EO2dCQUNwRCxNQUFNO1lBQ1IsQ0FBQztZQUVELCtEQUErRDtZQUMvRCw2REFBNkQ7WUFDN0QsbUVBQW1FO1lBQ25FLHFFQUFxRTtZQUNyRSwrQkFBK0I7WUFDL0IsSUFBSSxXQUFtRSxDQUFDO1lBQ3hFLEtBQUssTUFBTSxFQUFFLElBQUksaUJBQWlCLEVBQUUsQ0FBQztnQkFDbkMsSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLE1BQU07b0JBQUUsU0FBUztnQkFDakMsTUFBTSxJQUFJLEdBQUcsRUFBaUIsQ0FBQztnQkFDL0IsSUFBSSwwQkFBMEIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztvQkFBRSxTQUFTO2dCQUNqRSxnRUFBZ0U7Z0JBQ2hFLCtEQUErRDtnQkFDL0QsZ0RBQWdEO2dCQUNoRCxJQUFJLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO29CQUFFLFNBQVM7Z0JBQ3hELE1BQU0sUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ2hFLGlFQUFpRTtnQkFDakUsb0RBQW9EO2dCQUNwRCw4REFBOEQ7Z0JBQzlELDZEQUE2RDtnQkFDN0QsNkRBQTZEO2dCQUM3RCxnRUFBZ0U7Z0JBQ2hFLDREQUE0RDtnQkFDNUQsMkRBQTJEO2dCQUMzRCxnRUFBZ0U7Z0JBQ2hFLDREQUE0RDtnQkFDNUQsMkRBQTJEO2dCQUMzRCxnRUFBZ0U7Z0JBQ2hFLGlFQUFpRTtnQkFDakUsMERBQTBEO2dCQUMxRCw2REFBNkQ7Z0JBQzdELGdFQUFnRTtnQkFDaEUsNERBQTREO2dCQUM1RCw0QkFBNEI7Z0JBQzVCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ3hELElBQUksQ0FBQyxXQUFXLElBQUksT0FBTyxHQUFHLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDbEQsV0FBVyxHQUFHLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQy9ELENBQUM7WUFDSCxDQUFDO1lBQ0QsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsMEJBQTBCLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDMUQsTUFBTSxPQUFPLEdBQUcsMkJBQTJCLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUN2RSxNQUFNLFlBQVksQ0FDaEIsS0FBSyxFQUNMLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDLEVBQ3pEO29CQUNFLEtBQUs7b0JBQ0wsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLEVBQUU7b0JBQ3RDLFdBQVcsRUFBRSxJQUFJLElBQUksRUFBRTtvQkFDdkIsZ0JBQWdCLEVBQUU7d0JBQ2hCLGFBQWEsRUFBRSxXQUFXLENBQUMsYUFBYTt3QkFDeEMsT0FBTztxQkFDUjtpQkFDRixFQUNELDJCQUEyQixDQUN6QixXQUFXLENBQUMsT0FBTyxFQUNuQixXQUFXLENBQUMsYUFBYSxFQUN6QixJQUFJLENBQUMsR0FBRyxFQUFFLEVBQ1YsT0FBTyxDQUNSLENBQ0YsQ0FBQztnQkFDRixNQUFNLENBQUMsNkJBQTZCLEVBQUU7b0JBQ3BDLGFBQWEsRUFBRSxXQUFXLENBQUMsYUFBYTtvQkFDeEMsWUFBWSxFQUFFLFdBQVcsQ0FBQyxPQUFPO29CQUNqQyxPQUFPO2lCQUNSLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCw2REFBNkQ7WUFDN0QsZ0VBQWdFO1lBQ2hFLCtEQUErRDtZQUMvRCxtRUFBbUU7WUFDbkUsK0RBQStEO1lBQy9ELCtEQUErRDtZQUMvRCw0REFBNEQ7WUFDNUQsa0VBQWtFO1lBQ2xFLHdEQUF3RDtZQUN4RCxxRUFBcUU7WUFDckUscUVBQXFFO1lBQ3JFLHVFQUF1RTtZQUN2RSxrRUFBa0U7WUFDbEUsc0VBQXNFO1lBQ3RFLEVBQUU7WUFDRix1RUFBdUU7WUFDdkUsdUVBQXVFO1lBQ3ZFLHVFQUF1RTtZQUN2RSxtRUFBbUU7WUFDbkUsMEJBQTBCO1lBQzFCLCtEQUErRDtZQUMvRCxtRUFBbUU7WUFDbkUsaUVBQWlFO1lBQ2pFLHFFQUFxRTtZQUNyRSw4Q0FBOEM7WUFDOUMsZ0VBQWdFO1lBQ2hFLE1BQU0sY0FBYyxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FDM0MsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUNMLEVBQUUsQ0FBQyxJQUFJLEtBQUssTUFBTTtnQkFDbEIsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUUsRUFBa0IsQ0FBQyxhQUFhLENBQUMsQ0FDNUQsQ0FBQztZQUNGLE1BQU0sc0JBQXNCLEdBQzFCLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFDcEIsVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDO2dCQUN2QixnQkFBZ0IsQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFDN0IsQ0FBQyxjQUFjO2dCQUNmLE9BQU8sQ0FBQyxRQUFRO2dCQUNoQixPQUFPLE9BQU8sQ0FBQyxTQUFTLEtBQUssUUFBUTtnQkFDbkMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTO2dCQUNuQixDQUFDLENBQUMsU0FBUyxDQUFDO1lBQ2hCLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksUUFBK0IsQ0FBQztZQUNwQyxJQUFJLENBQUM7Z0JBQ0gsUUFBUSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDMUIsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FDNUIsbUJBQW1CLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFLENBQ2xELENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FDVixXQUFXLENBQUM7b0JBQ1YsS0FBSztvQkFDTCxhQUFhLEVBQUUsS0FBSztvQkFDcEIsb0JBQW9CLEVBQUUsV0FBVyxDQUFDLFlBQVk7b0JBQzlDLFlBQVksRUFBRSxXQUFXLENBQUMsWUFBWTtvQkFDdEMsaUJBQWlCO29CQUNqQixTQUFTO29CQUNULFNBQVM7b0JBQ1QsTUFBTSxFQUFFLElBQUksQ0FBQyxhQUFhO29CQUMxQixRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU07b0JBQ3JCLGFBQWE7b0JBQ2IsY0FBYyxFQUFFLFdBQVcsQ0FBQyxXQUFXO29CQUN2Qyx3REFBd0Q7b0JBQ3hELHVEQUF1RDtvQkFDdkQsNENBQTRDO29CQUM1QyxnREFBZ0Q7b0JBQ2hELHNEQUFzRDtvQkFDdEQsd0RBQXdEO29CQUN4RCxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FDeEMsSUFBSSxDQUFDLEtBQUssRUFDVixhQUFhLENBQ2Q7b0JBQ0QsbURBQW1EO29CQUNuRCx1REFBdUQ7b0JBQ3ZELDhDQUE4QztvQkFDOUMsY0FBYztvQkFDZCxrREFBa0Q7b0JBQ2xELFdBQVc7b0JBQ1gsb0JBQW9CLEVBQUUsQ0FBQztvQkFDdkIsR0FBRyxDQUFDLHNCQUFzQixLQUFLLFNBQVM7d0JBQ3RDLENBQUMsQ0FBQyxFQUFFLHNCQUFzQixFQUFFO3dCQUM1QixDQUFDLENBQUMsRUFBRSxDQUFDO2lCQUNSLENBQUMsQ0FBQyxFQUFFLENBQ1IsQ0FDRixDQUNGLENBQUM7WUFDSixDQUFDO29CQUFTLENBQUM7Z0JBQ1QsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2xCLENBQUM7WUFDRCxtQkFBbUIsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUM7WUFFL0MsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUNqRCxNQUFNLElBQUksR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDakMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUM1QixlQUFlLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDeEMsSUFDRSxPQUFPLENBQUMsSUFBSSxLQUFLLFdBQVc7b0JBQzVCLE9BQU8sQ0FBQyxXQUFXLEtBQUssU0FBUztvQkFDakMsc0JBQXNCLEtBQUssU0FBUyxFQUNwQyxDQUFDO29CQUNELE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQ2xDLHNCQUFzQixFQUN0QixPQUFPLENBQUMsV0FBVyxDQUNwQixDQUFDO29CQUNGLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRTt3QkFDOUIsU0FBUzt3QkFDVCxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7d0JBQ2pDLE1BQU0sRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNO3dCQUN6QyxPQUFPLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxPQUFPO3dCQUNwQyxjQUFjLEVBQUUsUUFBUTtxQkFDekIsQ0FBQyxDQUFDO2dCQUNMLENBQUM7Z0JBQ0QsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFdBQVcsRUFBRSxDQUFDO29CQUM3RCx5REFBeUQ7b0JBQ3pELGtEQUFrRDtvQkFDbEQsYUFBYSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQ3RDLE1BQU0sZ0JBQWdCLENBQUM7d0JBQ3JCLEtBQUs7d0JBQ0wsS0FBSzt3QkFDTCxXQUFXO3dCQUNYLElBQUk7d0JBQ0osWUFBWSxFQUFFLE9BQU8sQ0FBQyxjQUFjO3dCQUNwQyxTQUFTO3dCQUNULGdCQUFnQjt3QkFDaEIsNkRBQTZEO3dCQUM3RCx1REFBdUQ7d0JBQ3ZELHdEQUF3RDt3QkFDeEQsNkRBQTZEO3dCQUM3RCxPQUFPLEVBQUUsU0FBUzt3QkFDbEIsTUFBTTtxQkFDUCxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7b0JBQ25DLE9BQU8sR0FBRyxJQUFJLENBQUM7Z0JBQ2pCLENBQUM7Z0JBQ0QsbUVBQW1FO2dCQUNuRSxnRUFBZ0U7Z0JBQ2hFLGlFQUFpRTtnQkFDakUsb0NBQW9DO1lBQ3RDLENBQUM7WUFDRCxNQUFNLENBQUMsdUJBQXVCLEVBQUU7Z0JBQzlCLFNBQVM7Z0JBQ1QsS0FBSyxFQUFFLGdCQUFnQixDQUFDLE1BQU07Z0JBQzlCLFFBQVEsRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO2FBQ3RDLENBQUMsQ0FBQztZQUVILGlFQUFpRTtZQUNqRSwrREFBK0Q7WUFDL0Qsb0VBQW9FO1lBQ3BFLG1FQUFtRTtZQUNuRSxvRUFBb0U7WUFDcEUsZ0VBQWdFO1lBQ2hFLG1FQUFtRTtZQUNuRSxvRUFBb0U7WUFDcEUsK0RBQStEO1lBQy9ELCtEQUErRDtZQUMvRCxtRUFBbUU7WUFDbkUsaUNBQWlDO1lBQ2pDLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixFQUFFLENBQUM7WUFDbEMsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxpQkFBaUIsRUFBRSxDQUFDO1lBQ3pFLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDM0Isb0JBQW9CLEdBQUcsSUFBSSxDQUFDO2dCQUM1QixNQUFNO1lBQ1IsQ0FBQztZQUNELE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUVyRCxNQUFNLENBQUMsa0JBQWtCLEVBQUU7Z0JBQ3pCLFNBQVM7Z0JBQ1QsS0FBSyxFQUFFLE9BQU87Z0JBQ2QsU0FBUyxFQUFFLFNBQVMsQ0FBQyxNQUFNO2dCQUMzQixPQUFPLEVBQUUsTUFBTSxDQUFDLFNBQVM7b0JBQ3ZCLENBQUMsQ0FBQyxXQUFXO29CQUNiLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTTt3QkFDYixDQUFDLENBQUMsUUFBUTt3QkFDVixDQUFDLENBQUMsV0FBVztnQkFDakIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUU7YUFDdEMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7WUFBUyxDQUFDO1FBQ1QsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFFRCxVQUFVLEVBQUUsYUFBYSxDQUFDO1FBQ3hCLEdBQUcsU0FBUyxDQUFDLGtCQUFrQixDQUFDLG1CQUFtQixDQUFDO0tBQ3JELENBQUMsQ0FBQztJQUVILElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3JCLHFCQUFxQjtRQUNyQixhQUFhLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxFQUFFO1lBQ3hELGFBQWEsRUFBRSxLQUFLO1NBQ3JCLENBQUMsQ0FBQztRQUNILFVBQVUsRUFBRSxhQUFhLENBQUM7WUFDeEIsR0FBRyxTQUFTLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQztTQUN6QyxDQUFDLENBQUM7UUFFSCxxRUFBcUU7UUFDckUsbUVBQW1FO1FBQ25FLHNFQUFzRTtRQUN0RSxrRUFBa0U7UUFDbEUsbUJBQW1CO1FBQ25CLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDN0MsSUFBSSxDQUFDO2dCQUNILE1BQU0sa0JBQWtCLENBQUM7b0JBQ3ZCLEtBQUs7b0JBQ0wsS0FBSztvQkFDTCxXQUFXO29CQUNYLGFBQWE7b0JBQ2IsU0FBUztvQkFDVCxnQkFBZ0I7b0JBQ2hCLGlFQUFpRTtvQkFDakUsaURBQWlEO29CQUNqRCxXQUFXLEVBQUUsbUJBQW1CO29CQUNoQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWU7b0JBQ25ELE1BQU07aUJBQ1AsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsYUFBYSxDQUFDLElBQUksQ0FBQyx3Q0FBd0MsRUFBRTtvQkFDM0QsYUFBYSxFQUFFLEtBQUs7b0JBQ3BCLE9BQU8sRUFBRyxHQUFhLEVBQUUsT0FBTztpQkFDakMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFFRCw4QkFBOEI7UUFDOUIseUVBQXlFO1FBQ3pFLHFFQUFxRTtRQUNyRSwyRUFBMkU7UUFDM0Usc0VBQXNFO1FBQ3RFLG9EQUFvRDtRQUNwRCxJQUFJLENBQUM7WUFDSCxNQUFNLG1CQUFtQixDQUFDO2dCQUN4QixTQUFTLEVBQUUsZUFBZTtnQkFDMUIsV0FBVyxFQUFFLG9CQUFvQjtnQkFDakMsU0FBUyxFQUFFO29CQUNULE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUNqQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFDdkIsYUFBYSxDQUNkO2lCQUNGO2FBQ0YsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsTUFBTSxFQUFFLHVCQUF1QixFQUFFLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLGVBQWUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDM0QsYUFBYSxDQUFDLElBQUksQ0FDaEIsbURBQW1ELEVBQ25ELEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxDQUN6QixDQUFDO2dCQUNGLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7Z0JBQ3pELE9BQU87WUFDVCxDQUFDO1lBQ0QsTUFBTSxDQUFDLHNCQUFzQixFQUFFO2dCQUM3QixTQUFTLEVBQUcsR0FBYSxFQUFFLElBQUk7Z0JBQy9CLFlBQVksRUFBRyxHQUFhLEVBQUUsT0FBTzthQUN0QyxDQUFDLENBQUM7WUFDSCxNQUFNLEdBQUcsQ0FBQztRQUNaLENBQUM7SUFDSCxDQUFDO1NBQU0sSUFBSSxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDNUIsbUVBQW1FO1FBQ25FLG9FQUFvRTtRQUNwRSxrRUFBa0U7UUFDbEUsTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQztRQUUvQyxhQUFhLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxFQUFFO1lBQ3hELGFBQWEsRUFBRSxLQUFLO1lBQ3BCLG1CQUFtQjtZQUNuQixZQUFZLEVBQUUsaUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDLE1BQU07WUFDdkUsWUFBWSxFQUFFLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxNQUFNLENBQUMsQ0FBQyxNQUFNO1lBQ3ZFLFVBQVUsRUFBRSxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3hDLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSTtnQkFDWixhQUFhLEVBQUUsQ0FBQyxDQUFDLGFBQWE7Z0JBQzlCLGVBQWUsRUFBRSxDQUFDLENBQUMsZUFBZTtnQkFDbEMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRyxDQUFpQixDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDcEUsQ0FBQyxDQUFDO1NBQ0osQ0FBQyxDQUFDO1FBRUgsVUFBVSxFQUFFLGFBQWEsQ0FBQztZQUN4QixHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDO1lBQ3hDLEdBQUcsU0FBUyxDQUFDLHNCQUFzQixDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQztTQUM5RCxDQUFDLENBQUM7UUFFSCxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1oscUVBQXFFO1lBQ3JFLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO1lBQ2pELE9BQU87UUFDVCxDQUFDO1FBRUQsaUVBQWlFO1FBQ2pFLGlFQUFpRTtRQUNqRSw0REFBNEQ7UUFDNUQsb0VBQW9FO1FBQ3BFLDhEQUE4RDtRQUM5RCxpRUFBaUU7UUFDakUsa0VBQWtFO1FBQ2xFLG9FQUFvRTtRQUNwRSxtRUFBbUU7UUFDbkUsaUVBQWlFO1FBQ2pFLHlEQUF5RDtRQUN6RCxNQUFNLGtCQUFrQixHQUFHLEtBQUssSUFBbUIsRUFBRTtZQUNuRCxNQUFNLFlBQVksQ0FDaEIsS0FBSyxFQUNMLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDLEVBQ3pEO2dCQUNFLEtBQUs7Z0JBQ0wsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLEVBQUU7Z0JBQ3RDLFdBQVcsRUFBRSxJQUFJLElBQUksRUFBRTthQUN4QixDQUNGLENBQUM7UUFDSixDQUFDLENBQUM7UUFFRixJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ3pCLDREQUE0RDtZQUM1RCwrQ0FBK0M7WUFDL0MsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsTUFBTSxFQUFFLDBCQUEwQixFQUFFLENBQUMsQ0FBQztZQUNqRSxNQUFNLGtCQUFrQixFQUFFLENBQUM7WUFDM0IsT0FBTztRQUNULENBQUM7UUFFRCwrREFBK0Q7UUFDL0QsZ0VBQWdFO1FBQ2hFLHFFQUFxRTtRQUNyRSw0REFBNEQ7UUFDNUQsSUFBSSxXQUFtRSxDQUFDO1FBQ3hFLElBQUksY0FBYyxHQUFHLEtBQUssQ0FBQztRQUMzQixLQUFLLE1BQU0sRUFBRSxJQUFJLGlCQUFpQixFQUFFLENBQUM7WUFDbkMsSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLE1BQU07Z0JBQUUsU0FBUztZQUNqQyxNQUFNLElBQUksR0FBRyxFQUFpQixDQUFDO1lBQy9CLE1BQU0sUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDaEUsSUFBSSxRQUFRLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ2xCLGNBQWMsR0FBRyxJQUFJLENBQUM7WUFDeEIsQ0FBQztpQkFBTSxJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO2dCQUMvRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUMvRCxJQUFJLENBQUMsV0FBVyxJQUFJLGNBQWMsR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ3pELFdBQVcsR0FBRzt3QkFDWixPQUFPLEVBQUUsY0FBYzt3QkFDdkIsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO3FCQUNsQyxDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksY0FBYyxFQUFFLENBQUM7WUFDbkIsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsTUFBTSxFQUFFLHNCQUFzQixFQUFFLENBQUMsQ0FBQztZQUM3RCxNQUFNLGtCQUFrQixFQUFFLENBQUM7WUFDM0IsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLG9CQUFvQixFQUFFLENBQUM7WUFDekIsNkRBQTZEO1lBQzdELDZEQUE2RDtZQUM3RCxrRUFBa0U7WUFDbEUsK0RBQStEO1lBQy9ELDREQUE0RDtZQUM1RCw4REFBOEQ7WUFDOUQsZ0VBQWdFO1lBQ2hFLG1FQUFtRTtZQUNuRSxpREFBaUQ7WUFDakQsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsTUFBTSxFQUFFLDJCQUEyQixFQUFFLENBQUMsQ0FBQztZQUNsRSxNQUFNLGtCQUFrQixFQUFFLENBQUM7WUFDM0IsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ2hCLGlFQUFpRTtZQUNqRSwyREFBMkQ7WUFDM0QsOERBQThEO1lBQzlELHlEQUF5RDtZQUN6RCxnQ0FBZ0M7WUFDaEMsTUFBTSxDQUFDLGdCQUFnQixFQUFFO2dCQUN2QixNQUFNLEVBQUUsdUJBQXVCO2dCQUMvQixjQUFjLEVBQUUsV0FBVyxDQUFDLE9BQU87Z0JBQ25DLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxhQUFhO2FBQzdDLENBQUMsQ0FBQztZQUNILDBCQUEwQixDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDMUQsTUFBTSxPQUFPLEdBQUcsMkJBQTJCLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQ3ZFLE1BQU0sWUFBWSxDQUNoQixLQUFLLEVBQ0wsb0JBQW9CLENBQUMsV0FBVyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsRUFDekQ7Z0JBQ0UsS0FBSztnQkFDTCxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsRUFBRTtnQkFDdEMsV0FBVyxFQUFFLElBQUksSUFBSSxFQUFFO2dCQUN2QixnQkFBZ0IsRUFBRTtvQkFDaEIsYUFBYSxFQUFFLFdBQVcsQ0FBQyxhQUFhO29CQUN4QyxPQUFPO2lCQUNSO2FBQ0YsRUFDRCwyQkFBMkIsQ0FDekIsV0FBVyxDQUFDLE9BQU8sRUFDbkIsV0FBVyxDQUFDLGFBQWEsRUFDekIsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUNWLE9BQU8sQ0FDUixDQUNGLENBQUM7WUFDRixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRTtZQUN2QixNQUFNLEVBQUUsbUJBQW1CO1lBQzNCLGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxNQUFNO1NBQzFDLENBQUMsQ0FBQztJQUNMLENBQUM7U0FBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN6QixrRUFBa0U7UUFDbEUsbUVBQW1FO1FBQ25FLHFFQUFxRTtRQUNyRSw4REFBOEQ7UUFDOUQsb0VBQW9FO1FBQ3BFLG1FQUFtRTtRQUNuRSxJQUFJLFVBQVUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUNyQyxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2YsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDbkQsTUFBTSxRQUFRLEdBQUcsVUFBVSxFQUFFLGVBQWUsSUFBSSxZQUFZLENBQUM7WUFDN0QsVUFBVSxHQUFHLGVBQWUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQ2pFLFVBQVUsR0FBRyxlQUFlLENBQzFCLFVBQVUsRUFDVix3QkFBd0IsRUFDeEIsWUFBWSxDQUNiLENBQUM7UUFDSixDQUFDO1FBRUQscUVBQXFFO1FBQ3JFLHFFQUFxRTtRQUNyRSxzREFBc0Q7UUFDdEQsRUFBRTtRQUNGLGdFQUFnRTtRQUNoRSxrRUFBa0U7UUFDbEUsZ0VBQWdFO1FBQ2hFLG9FQUFvRTtRQUNwRSxNQUFNLGFBQWEsR0FDakIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssNEJBQTRCO1lBQ2pELENBQUMsQ0FBQyxJQUFJLDBCQUEwQixDQUFDLFlBQVksQ0FBQztZQUM5QyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssT0FBTztnQkFDOUIsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO2dCQUNsQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUM5QyxJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJO2lCQUN6QixDQUFDLENBQUM7UUFDWCxNQUFNLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUVsRCxhQUFhLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxFQUFFO1lBQ3RELGFBQWEsRUFBRSxLQUFLO1lBQ3BCLFNBQVMsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUk7WUFDN0IsWUFBWSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTztZQUNuQyxVQUFVO1lBQ1YsU0FBUztTQUNWLENBQUMsQ0FBQztRQUNILFVBQVUsRUFBRSxhQUFhLENBQUM7WUFDeEIsR0FBRyxTQUFTLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQztTQUN0QyxDQUFDLENBQUM7UUFFSCxpRUFBaUU7UUFDakUsZ0RBQWdEO1FBQ2hELElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDMUMsSUFBSSxDQUFDO2dCQUNILE1BQU0sa0JBQWtCLENBQUM7b0JBQ3ZCLEtBQUs7b0JBQ0wsS0FBSztvQkFDTCxXQUFXO29CQUNYLGFBQWE7b0JBQ2IsU0FBUztvQkFDVCxnQkFBZ0I7b0JBQ2hCLFdBQVcsRUFBRSxtQkFBbUI7b0JBQ2hDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsZUFBZTtvQkFDaEQsTUFBTTtpQkFDUCxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixhQUFhLENBQUMsSUFBSSxDQUFDLHdDQUF3QyxFQUFFO29CQUMzRCxhQUFhLEVBQUUsS0FBSztvQkFDcEIsT0FBTyxFQUFHLEdBQWEsRUFBRSxPQUFPO2lCQUNqQyxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUVELDJEQUEyRDtRQUMzRCxxRUFBcUU7UUFDckUsb0VBQW9FO1FBQ3BFLDJCQUEyQjtRQUMzQixpRUFBaUU7UUFDakUsZ0VBQWdFO1FBQ2hFLGlFQUFpRTtRQUNqRSwrREFBK0Q7UUFDL0QsaUVBQWlFO1FBQ2pFLCtDQUErQztRQUMvQyw2REFBNkQ7UUFDN0Qsa0VBQWtFO1FBQ2xFLHVEQUF1RDtRQUN2RCxnRUFBZ0U7UUFDaEUsdURBQXVEO1FBQ3ZELElBQUksZUFBMkIsQ0FBQztRQUNoQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDN0IsNERBQTREO1lBQzVELGdFQUFnRTtZQUNoRSw0REFBNEQ7WUFDNUQsNkRBQTZEO1lBQzdELDhEQUE4RDtZQUM5RCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxlQUFlLENBQ3BDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUN4QixLQUFLLEVBQ0wsU0FBUyxDQUFDLDJCQUEyQjtpQkFDdEMsQ0FBQztnQkFDRixJQUNFLFFBQVE7b0JBQ1IsT0FBTyxRQUFRLEtBQUssUUFBUTtvQkFDNUIsT0FBTyxJQUFLLFFBQW1CO29CQUMvQixPQUFRLFFBQWdDLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFDM0QsQ0FBQztvQkFDRCxNQUFNLFVBQVUsR0FBRyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztvQkFDbkQsTUFBTSxRQUFRLEdBQUcsVUFBVSxFQUFFLGVBQWUsSUFBSSxZQUFZLENBQUM7b0JBQzdELDZEQUE2RDtvQkFDNUQsUUFBK0IsQ0FBQyxLQUFLLEdBQUcsZUFBZSxDQUN0RCxlQUFlLENBQ1osUUFBOEIsQ0FBQyxLQUFLLEVBQ3JDLFFBQVEsRUFDUixZQUFZLENBQ2IsRUFDRCx3QkFBd0IsRUFDeEIsWUFBWSxDQUNiLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxvREFBb0Q7Z0JBQ3BELE1BQU0sSUFBSSxHQUFHLElBQUksT0FBTyxFQUFVLENBQUM7Z0JBQ25DLElBQUksSUFBSSxHQUFJLFFBQWdDLEVBQUUsS0FBSyxDQUFDO2dCQUNwRCxPQUFPLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQWMsQ0FBQyxFQUFFLENBQUM7b0JBQ3JFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBYyxDQUFDLENBQUM7b0JBQ3pCLE1BQU0sU0FBUyxHQUFJLElBQTRCLENBQUMsS0FBSyxDQUFDO29CQUN0RCxJQUFJLE9BQU8sU0FBUyxLQUFLLFFBQVEsRUFBRSxDQUFDO3dCQUNsQyxNQUFNLFVBQVUsR0FBRyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQzt3QkFDbkQsTUFBTSxRQUFRLEdBQUcsVUFBVSxFQUFFLGVBQWUsSUFBSSxZQUFZLENBQUM7d0JBQzdELDZEQUE2RDt3QkFDNUQsSUFBMkIsQ0FBQyxLQUFLLEdBQUcsZUFBZSxDQUNsRCxlQUFlLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxZQUFZLENBQUMsRUFDbEQsd0JBQXdCLEVBQ3hCLFlBQVksQ0FDYixDQUFDO29CQUNKLENBQUM7b0JBQ0QsSUFBSSxHQUFJLElBQTRCLENBQUMsS0FBSyxDQUFDO2dCQUM3QyxDQUFDO2dCQUNELGVBQWUsR0FBRyxNQUFNLGlCQUFpQixDQUN2QyxRQUFRLEVBQ1IsS0FBSyxFQUNMLGFBQWEsQ0FDZCxDQUFDO1lBQ0osQ0FBQztZQUFDLE9BQU8sWUFBWSxFQUFFLENBQUM7Z0JBQ3RCLDJEQUEyRDtnQkFDM0QsMERBQTBEO2dCQUMxRCwwREFBMEQ7Z0JBQzFELDBDQUEwQztnQkFDMUMsYUFBYSxDQUFDLElBQUksQ0FDaEIsaUZBQWlGLEVBQ2pGO29CQUNFLGFBQWEsRUFBRSxLQUFLO29CQUNwQixPQUFPLEVBQUcsWUFBc0IsRUFBRSxPQUFPO2lCQUMxQyxDQUNGLENBQUM7Z0JBQ0YsZUFBZSxHQUFHLENBQUMsTUFBTSxZQUFZLENBQ25DLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUN4QixhQUFhLENBQ2QsQ0FBZSxDQUFDO1lBQ25CLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQ2YsYUFBYSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUM7WUFDbkMsQ0FBQztZQUNELElBQUksQ0FBQztnQkFDSCxlQUFlLEdBQUcsTUFBTSxpQkFBaUIsQ0FDdkMsYUFBYSxFQUNiLEtBQUssRUFDTCxhQUFhLENBQ2QsQ0FBQztZQUNKLENBQUM7WUFBQyxPQUFPLE1BQU0sRUFBRSxDQUFDO2dCQUNoQiw2REFBNkQ7Z0JBQzdELDZEQUE2RDtnQkFDN0QsYUFBYSxDQUFDLElBQUksQ0FDaEIsNEVBQTRFLEVBQzVFLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUcsTUFBZ0IsRUFBRSxPQUFPLEVBQUUsQ0FDOUQsQ0FBQztnQkFDRixlQUFlLEdBQUcsTUFBTSxpQkFBaUIsQ0FDdkMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUM5QyxJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJO2lCQUN6QixDQUFDLEVBQ0YsS0FBSyxFQUNMLGFBQWEsQ0FDZCxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLENBQUM7WUFDSCxNQUFNLG1CQUFtQixDQUFDO2dCQUN4QixTQUFTLEVBQUUsWUFBWTtnQkFDdkIsV0FBVyxFQUFFLG9CQUFvQjtnQkFDakMsU0FBUyxFQUFFO29CQUNULEtBQUssRUFBRSxlQUFlO29CQUN0QixTQUFTO2lCQUNWO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYixJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxlQUFlLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzNELGFBQWEsQ0FBQyxJQUFJLENBQUMsZ0RBQWdELEVBQUU7b0JBQ25FLGFBQWEsRUFBRSxLQUFLO2lCQUNyQixDQUFDLENBQUM7Z0JBQ0gsTUFBTSxDQUFDLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7Z0JBQ3RELE9BQU87WUFDVCxDQUFDO1lBQ0QsTUFBTSxDQUFDLG1CQUFtQixFQUFFO2dCQUMxQixTQUFTLEVBQUcsR0FBYSxFQUFFLElBQUk7Z0JBQy9CLFlBQVksRUFBRyxHQUFhLEVBQUUsT0FBTzthQUN0QyxDQUFDLENBQUM7WUFDSCxNQUFNLEdBQUcsQ0FBQztRQUNaLENBQUM7UUFDRCxNQUFNLENBQUMsYUFBYSxFQUFFLEVBQUUsTUFBTSxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztJQUMxRCxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUXVpY2tKUyBXZWJBc3NlbWJseSAoV0FTTSkgVk0gaW50ZWdyYXRpb24gd2l0aCB0aGUgV29ya2Zsb3cgRGV2S2l0LlxuICpcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIHRoZSBlbnRyeSBwb2ludCBmb3IgcnVubmluZyB3b3JrZmxvd3MgaW4gdGhlXG4gKiBRdWlja0pTIFZNIGVuZ2luZSBpbnN0ZWFkIG9mIHRoZSBgbm9kZTp2bWAgZW5naW5lLiBCb3RoIGVuZ2luZXNcbiAqIGltcGxlbWVudCB0aGUgc2FtZSBldmVudC1yZXBsYXkgZXhlY3V0aW9uIG1vZGVsLCB3aGVyZSBldmVyeSBpbnZvY2F0aW9uOlxuICpcbiAqIDEuIExvYWRzIHRoZSBmdWxsIGV2ZW50IGxvZyBmb3IgdGhlIHJ1blxuICogMi4gUnVucyB0aGUgd29ya2Zsb3cgZnVuY3Rpb24gZnJvbSB0aGUgdG9wIGluIGEgZnJlc2ggUXVpY2tKUyBWTSxcbiAqICAgIHJlcGxheWluZyB0aGUgZXZlbnQgbG9nIHRvIHJlc29sdmUgYXdhaXRlZCBwcmltaXRpdmVzXG4gKiAzLiBPbiBzdXNwZW5zaW9uOiBjcmVhdGVzIGV2ZW50cyArIHF1ZXVlcyBzdGVwcyBmb3IgbmV3IHBlbmRpbmcgb3BzXG4gKiA0LiBPbiBjb21wbGV0aW9uOiBjcmVhdGVzIHJ1bl9jb21wbGV0ZWRcbiAqIDUuIE9uIGZhaWx1cmU6IGNyZWF0ZXMgcnVuX2ZhaWxlZFxuICovXG5cbmltcG9ydCB0eXBlIHsgU3BhbiB9IGZyb20gJ0BvcGVudGVsZW1ldHJ5L2FwaSc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBIb29rTm90Rm91bmRFcnJvcixcbiAgTWF4RXZlbnRzRXhjZWVkZWRFcnJvcixcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgeyBwYXJzZVdvcmtmbG93TmFtZSB9IGZyb20gJ0B3b3JrZmxvdy91dGlscy9wYXJzZS1uYW1lJztcbmltcG9ydCB7XG4gIHR5cGUgQ3JlYXRlRXZlbnRQYXJhbXMsXG4gIHR5cGUgQ3JlYXRlRXZlbnRSZXF1ZXN0LFxuICB0eXBlIEV2ZW50LFxuICB0eXBlIEV2ZW50UmVzdWx0LFxuICBST09UX1JVTl9JRF9BVFRSSUJVVEUsXG4gIHR5cGUgUnVuSW5wdXQsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ0JPUl9RVUVVRV9UUkFOU1BPUlQsXG4gIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTixcbiAgdHlwZSBXb3JrZmxvd1J1bixcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7IGNsYXNzaWZ5UnVuRXJyb3IsIGlzUmV0cnlhYmxlV29ybGRFcnJvciB9IGZyb20gJy4uL2NsYXNzaWZ5LWVycm9yLmpzJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHtcbiAgZGVyaXZlUnVuUGF5bG9hZEtleXMsXG4gIGVuY3J5cHQgYXMgZW5jcnlwdFNlcmlhbGl6ZWREYXRhLFxuICB0eXBlIFJ1blBheWxvYWRLZXlzLFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHtcbiAgZGVoeWRyYXRlUnVuRXJyb3IsXG4gIGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHMsXG4gIGRlaHlkcmF0ZVN0ZXBFcnJvcixcbiAgaHlkcmF0ZVJ1bkVycm9yLFxuICBtYXliZUVuY3J5cHQsXG59IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0IHsgcmVtYXBFcnJvclN0YWNrLCBzdHJpcElubGluZVNvdXJjZU1hcCB9IGZyb20gJy4uL3NvdXJjZS1tYXAuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBzZXJpYWxpemVUcmFjZUNhcnJpZXIgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHtcbiAgZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzLFxuICBnZXRNYXhJbmxpbmVTdGVwcyxcbiAgaXNSZXNpbGllbnRTdGVwRGlzcGF0Y2hFbmFibGVkLFxuICBNQVhfUkVTSUxJRU5UX1NURVBfSU5QVVRfQllURVMsXG59IGZyb20gJy4vY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IGdldFBvcnRMYXp5IH0gZnJvbSAnLi9nZXQtcG9ydC1sYXp5LmpzJztcbmltcG9ydCB7XG4gIGdldFdvcmtmbG93UXVldWVOYW1lLFxuICBxdWV1ZU1lc3NhZ2UsXG4gIHJ1bkRpc3BhdGNoQ29udGV4dCxcbiAgc3RlcERpc3BhdGNoSWRlbXBvdGVuY3lLZXksXG59IGZyb20gJy4vaGVscGVycy5qcyc7XG5pbXBvcnQgeyBRdWlja0pTTG9nVmlldyB9IGZyb20gJy4vcXVpY2tqcy1sb2ctdmlldy5qcyc7XG5pbXBvcnQge1xuICBCQVNFTElORV9CVU5ETEVfRklMRU5BTUUsXG4gIHR5cGUgUGVuZGluZ0F0dHJpYnV0ZSxcbiAgdHlwZSBQZW5kaW5nSG9vayxcbiAgdHlwZSBQZW5kaW5nSG9va0Rpc3Bvc2UsXG4gIHR5cGUgUGVuZGluZ09wZXJhdGlvbixcbiAgdHlwZSBQZW5kaW5nU3RlcCxcbiAgdHlwZSBQZW5kaW5nV2FpdCxcbiAgc3RhcnRRdWlja0pTV29ya2Zsb3csXG59IGZyb20gJy4vcXVpY2tqcy1ydW50aW1lLmpzJztcbmltcG9ydCB7IFJlcGxheUJ1ZGdldCB9IGZyb20gJy4vcmVwbGF5LWJ1ZGdldC5qcyc7XG5pbXBvcnQgeyBleGVjdXRlU3RlcCwgdHlwZSBTdGVwRXhlY3V0aW9uUmVzdWx0IH0gZnJvbSAnLi9zdGVwLWV4ZWN1dG9yLmpzJztcbmltcG9ydCB7IHJ1blN0ZXBTaW5nbGVGbGlnaHQgfSBmcm9tICcuL3N0ZXAtc2luZ2xlLWZsaWdodC5qcyc7XG5pbXBvcnQgeyB1bnNlcmlhbGl6YWJsZVN0ZXBJbnB1dFBsYWNlaG9sZGVyIH0gZnJvbSAnLi91bnNlcmlhbGl6YWJsZS1zdGVwLmpzJztcbmltcG9ydCB7IGdldFdhaXRDb250aW51YXRpb25EaXNwYXRjaCB9IGZyb20gJy4vd2FpdC1jb250aW51YXRpb24uanMnO1xuaW1wb3J0IHsgZ2V0V29ybGQgfSBmcm9tICcuL3dvcmxkLmpzJztcblxuLyoqIEFuIGBldmVudHMuY3JlYXRlYCBib3VuZCB0byB0aGUgcnVuOyBzZWUgYGRpc3BhdGNoUGVuZGluZ09wcy5jcmVhdGVFdmVudGAuICovXG50eXBlIEV2ZW50Q3JlYXRvciA9IChcbiAgZGF0YTogQ3JlYXRlRXZlbnRSZXF1ZXN0LFxuICBwYXJhbXM/OiBDcmVhdGVFdmVudFBhcmFtc1xuKSA9PiBQcm9taXNlPEV2ZW50UmVzdWx0PjtcblxuLyoqIFRpbnkgbXMgdGltZXIgdXNpbmcgcGVyZm9ybWFuY2Uubm93KCksIGFscmVhZHkgbW9ub3RvbmljIG9uIE5vZGUuICovXG5mdW5jdGlvbiB0aWNrKCk6IG51bWJlciB7XG4gIHJldHVybiBwZXJmb3JtYW5jZS5ub3coKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgd2hlbiB0aGUgc3VwcGxpZWQgcHJlbG9hZGVkIGV2ZW50cyBpbmRpY2F0ZSB0aGlzIGlzIHRoZVxuICogZmlyc3Qgd29ya2Zsb3cgaGFuZGxlciBpbnZvY2F0aW9uIGZvciB0aGUgcnVuLCBpLmUuIHRoZSBsb2cgY29udGFpbnNcbiAqIG5vdGhpbmcgYmV5b25kIGBydW5fY3JlYXRlZGAgLyBgcnVuX3N0YXJ0ZWRgLiBJbiB0aGF0IGNhc2UgdGhlXG4gKiBwcmVsb2FkZWQgZXZlbnRzIEFSRSB0aGUgY29tcGxldGUgZXZlbnQgbG9nIGFuZCB0aGUgYGV2ZW50cy5saXN0YFxuICogcm91bmQtdHJpcHMgY2FuIGJlIHNraXBwZWQgZW50aXJlbHkuXG4gKlxuICogQ3J1Y2lhbGx5LCBpZiB0aGUgd29ybGQgYmFja2ZpbGxlZCBhIG1pc3NpbmcgYHJ1bl9jcmVhdGVkYCB2aWEgdGhlXG4gKiByZXNpbGllbnQgc3RhcnQgcGF0aCwgYHByZWxvYWRlZEV2ZW50c2AgY29udGFpbnMgaXQgZXZlbiB3aGVuIGEgZnJlc2hcbiAqIGBldmVudHMubGlzdGAgbWlnaHQgbm90IChldmVudHVhbCBjb25zaXN0ZW5jeSksIHNvIHByZWZlcnJpbmcgdGhlXG4gKiBwcmVsb2FkZWQgZXZlbnRzIG9uIGZpcnN0IGludm9jYXRpb24gaXMgYWxzbyB0aGUgbW9yZSBjb3JyZWN0IGNob2ljZS5cbiAqXG4gKiBSZXR1cm5zIGZhbHNlIHdoZW4gYHByZWxvYWRlZEV2ZW50c2AgaXMgbWlzc2luZy9lbXB0eSBzbyB0aGUgY2FsbGVyXG4gKiBmYWxscyBiYWNrIHRvIHRoZSBub3JtYWwgZmV0Y2ggcGF0aC5cbiAqXG4gKiBFeHBvcnRlZCBmb3IgdW5pdCB0ZXN0aW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNGaXJzdEludm9jYXRpb24oXG4gIHByZWxvYWRlZEV2ZW50czogcmVhZG9ubHkgRXZlbnRbXSB8IHVuZGVmaW5lZFxuKTogYm9vbGVhbiB7XG4gIGlmICghQXJyYXkuaXNBcnJheShwcmVsb2FkZWRFdmVudHMpIHx8IHByZWxvYWRlZEV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIHByZWxvYWRlZEV2ZW50cy5ldmVyeShcbiAgICAoZSkgPT4gZS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCcgfHwgZS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCdcbiAgKTtcbn1cblxuLyoqXG4gKiBRdWV1ZSBhIHN0ZXAgZm9yIGJhY2tncm91bmQgZXhlY3V0aW9uIHZpYSB0aGUgdW5pZmllZCB3b3JrZmxvdyBxdWV1ZVxuICogKFYyIGFyY2hpdGVjdHVyZSkuIFRoZSBjb21iaW5lZCBoYW5kbGVyIGluIHJ1bnRpbWUudHMgZGlzcGF0Y2hlc1xuICogbWVzc2FnZXMgd2l0aCBgc3RlcElkYCB0byBleGVjdXRlU3RlcCwgd2hpY2ggd29ya3MgZm9yIGJvdGggVk0gZW5naW5lcy5cbiAqIGBkZWxheVNlY29uZHNgIHN1cHBvcnRzIHJldHJ5L3Rocm90dGxlIGJhY2tvZmYuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHF1ZXVlU3RlcE1lc3NhZ2UocGFyYW1zOiB7XG4gIHdvcmxkOiBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIGdldFdvcmxkPj47XG4gIHJ1bklkOiBzdHJpbmc7XG4gIHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1bjtcbiAgc3RlcDogUGVuZGluZ1N0ZXA7XG4gIGRlbGF5U2Vjb25kcz86IG51bWJlcjtcbiAgLyoqIFF1ZXVlIG5hbWVzcGFjZSBmb3IgdGhlIHB1Ymxpc2ggKHNlZSBydW50aW1lLnRzKS4gKi9cbiAgbmFtZXNwYWNlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBSdW4tb3JpZ2luIHRyYWNlIGNhcnJpZXIgYWNjZXNzb3IgKHNlZSBydW5Xb3JrZmxvd1dpdGhRdWlja0pTKS4gKi9cbiAgbmV4dFRyYWNlQ2FycmllcjogKCkgPT4gUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+PjtcbiAgLyoqXG4gICAqIFB1Ymxpc2ggcHVycG9zZSwgdXNlZCB0byBidWNrZXQgdGhlIGlkZW1wb3RlbmN5IGtleS4gV29ybGRzIHJldGlyZVxuICAgKiB1c2VkIGtleXMgKFZRUyByZXRlbnRpb24gVFRMLCB3b3JsZC1wb3N0Z3JlcyBjb21wbGV0ZWQta2V5cyBjYWNoZSksXG4gICAqIHNvIGEga2V5IHNoYXJlZCBhY3Jvc3MgcHVycG9zZXMgc2lsZW50bHkgc3dhbGxvd3MgdGhlIHNlY29uZFxuICAgKiBwdWJsaXNoLiBTZWUgd2FpdC1jb250aW51YXRpb24udHMgZm9yIHRoZSBzYW1lIGhhemFyZCBvbiB3YWl0XG4gICAqIGtleXMuIGBkaXNwYXRjaGAgaXMgdGhlIHBsYWluIGJhY2tncm91bmQgaGFuZG9mZiAob3ZlcmZsb3cgLyBjcmFzaFxuICAgKiByZWNvdmVyeSkgYW5kIHVzZXMgdGhlIHN0ZXAtaWRlbnRpdHktc2NvcGVkIGRpc3BhdGNoIGtleVxuICAgKiAoc3RlcERpc3BhdGNoSWRlbXBvdGVuY3lLZXkpIHNvIGl0IHN0YXlzIG11dHVhbGx5XG4gICAqIGV4Y2x1c2l2ZSB3aXRoIHRoZSBub2RlIGVuZ2luZSdzIGRpc3BhdGNoIG9mIHRoZSBzYW1lIHN0ZXA7XG4gICAqIGBiYWNrc3RvcDo8ZXBvY2g+YCBjb3ZlcnMgZGVsYXllZCBjcmFzaCBiYWNrc3RvcHMsIHNjb3BlZCB0byB0aGVcbiAgICogb3duZXJzaGlwIGVwb2NoIHNvIGEgcmVmcmVzaGVkIGxlYXNlIHJlLWFybXMgYSBORVcgYmFja3N0b3AgaW5zdGVhZFxuICAgKiBvZiBiZWluZyBhYnNvcmJlZCBieSB0aGUgaW4tZmxpZ2h0IG9uZTsgYHJldHJ5OjxuPmAgY292ZXJzIGRlbGF5ZWRcbiAgICogcmV0cnkvdGhyb3R0bGUgcmUtZW5xdWV1ZXMsIHNjb3BlZCB0byB0aGUgYXR0ZW1wdCBzbyBlYWNoIGJhY2tvZmZcbiAgICogaG9wIGlzIGVucXVldWVhYmxlLlxuICAgKi9cbiAgcHVycG9zZTogJ2Rpc3BhdGNoJyB8IGBiYWNrc3RvcDoke3N0cmluZ31gIHwgYHJldHJ5OiR7bnVtYmVyfWA7XG4gIC8qKlxuICAgKiBSZXNpbGllbnQgc3RlcCBkaXNwYXRjaDogdGhlIHNlcmlhbGl6ZWQgKHBvc3NpYmx5IGVuY3J5cHRlZCkgc3RlcCBpbnB1dFxuICAgKiB0byBjYXJyeSBvbiB0aGUgbWVzc2FnZSBhcyBgc3RlcElucHV0YCwgc28gdGhlIGNvbnN1bWVyIGNhbiBpZGVtcG90ZW50bHlcbiAgICogcmUtZW5zdXJlIHRoZSBgc3RlcF9jcmVhdGVkYCBldmVudCBpZiB0aGUgcHJvZHVjZXIncyBwYXJhbGxlbCBkaXJlY3RcbiAgICogd3JpdGUgZmFpbGVkIHRyYW5zaWVudGx5LiBPbmx5IHNldCBvbiBgZGlzcGF0Y2hgIHB1Ymxpc2hlcyB0aGF0XG4gICAqIGRpc3BhdGNoUGVuZGluZ09wcyBwYXJhbGxlbGl6ZXMgd2l0aCB0aGUgc3RlcF9jcmVhdGVkIHdyaXRlLlxuICAgKi9cbiAgc3RlcElucHV0PzogVWludDhBcnJheTtcbiAgd2ZkaWFnOiAoY2hlY2twb2ludDogc3RyaW5nLCBmaWVsZHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB2b2lkO1xufSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7XG4gICAgd29ybGQsXG4gICAgcnVuSWQsXG4gICAgd29ya2Zsb3dSdW4sXG4gICAgc3RlcCxcbiAgICBkZWxheVNlY29uZHMsXG4gICAgbmFtZXNwYWNlLFxuICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgcHVycG9zZSxcbiAgICBzdGVwSW5wdXQsXG4gICAgd2ZkaWFnLFxuICB9ID0gcGFyYW1zO1xuICBjb25zdCB0cmFjZUNhcnJpZXIgPSBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCk7XG4gIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICB3b3JsZCxcbiAgICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsIG5hbWVzcGFjZSksXG4gICAge1xuICAgICAgcnVuSWQsXG4gICAgICBzdGVwSWQ6IHN0ZXAuY29ycmVsYXRpb25JZCxcbiAgICAgIHN0ZXBOYW1lOiBzdGVwLnN0ZXBJZCxcbiAgICAgIHRyYWNlQ2FycmllcixcbiAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgLi4uKHN0ZXBJbnB1dCAhPT0gdW5kZWZpbmVkID8geyBzdGVwSW5wdXQ6IHsgaW5wdXQ6IHN0ZXBJbnB1dCB9IH0gOiB7fSksXG4gICAgICAvLyBJbW11dGFibGUgcnVuIGlkZW50aXR5IHNvIHRoZSBjb25zdW1lciBjYW4gc3RhcnQgdGhlIHN0ZXAgd2l0aG91dCBhXG4gICAgICAvLyBibG9ja2luZyBydW5zLmdldCDigJQgc2VlIFJ1bkRpc3BhdGNoQ29udGV4dFNjaGVtYS5cbiAgICAgIHJ1bkNvbnRleHQ6IHJ1bkRpc3BhdGNoQ29udGV4dCh3b3JrZmxvd1J1biksXG4gICAgfSxcbiAgICB7XG4gICAgICAvLyBUaGUgJ2Rpc3BhdGNoJyBrZXkgaXMgc3RlcC1pZGVudGl0eS1zY29wZWQgKGNvcnJlbGF0aW9uSWQgKyBoYXNoZWRcbiAgICAgIC8vIHN0ZXAgbmFtZSksIHNoYXJlZCB3aXRoIHRoZSBub2RlIGVuZ2luZSdzIGRpc3BhdGNoIG9mIHRoZSBzYW1lIHN0ZXBcbiAgICAgIC8vIHNvIHRoZSB0d28gc3RheSBtdXR1YWxseSBleGNsdXNpdmUsIHdpdGhvdXQgYSByZXZva2VkIHJlc2lsaWVudFxuICAgICAgLy8gbWVzc2FnZSBhYnNvcmJpbmcgYSByZWFzc2lnbmVkIGNvcnJlbGF0aW9uIGlkJ3MgbGVnaXRpbWF0ZSBkaXNwYXRjaC5cbiAgICAgIC8vIFNlZSBzdGVwRGlzcGF0Y2hJZGVtcG90ZW5jeUtleS5cbiAgICAgIGlkZW1wb3RlbmN5S2V5OlxuICAgICAgICBwdXJwb3NlID09PSAnZGlzcGF0Y2gnXG4gICAgICAgICAgPyBzdGVwRGlzcGF0Y2hJZGVtcG90ZW5jeUtleShzdGVwLmNvcnJlbGF0aW9uSWQsIHN0ZXAuc3RlcElkKVxuICAgICAgICAgIDogYCR7c3RlcC5jb3JyZWxhdGlvbklkfToke3B1cnBvc2V9YCxcbiAgICAgIC4uLihkZWxheVNlY29uZHMgJiYgZGVsYXlTZWNvbmRzID4gMCA/IHsgZGVsYXlTZWNvbmRzIH0gOiB7fSksXG4gICAgfVxuICApO1xuICB3ZmRpYWcoJ3N0ZXBfcXVldWVkJywge1xuICAgIHN0ZXBJZDogc3RlcC5zdGVwSWQsXG4gICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgIHB1cnBvc2UsXG4gICAgZGVsYXlTZWNvbmRzOiBkZWxheVNlY29uZHMgPz8gMCxcbiAgICAuLi4oc3RlcElucHV0ICE9PSB1bmRlZmluZWQgPyB7IHJlc2lsaWVudDogdHJ1ZSB9IDoge30pLFxuICB9KTtcbn1cblxuLyoqXG4gKiBEaXNwYXRjaCBkdXJhYmxlIHNpZGUgZWZmZWN0cyBmb3IgYSBzZXQgb2YgcGVuZGluZyBWTSBvcGVyYXRpb25zOlxuICogc3RlcF9jcmVhdGVkICgrIG9wdGlvbmFsIHF1ZXVlaW5nKSwgaG9va19jcmVhdGVkIC8gaG9va19yZWNlaXZlZCAoYWJvcnRzKSxcbiAqIGF0dHJfc2V0LCBob29rX2Rpc3Bvc2VkLCBhbmQgd2FpdF9jcmVhdGVkIGV2ZW50cy5cbiAqXG4gKiBTdGVwcyBhcmUgY3JlYXRlZCBidXQgKHVzdWFsbHkpIG5vdCBxdWV1ZWQgaGVyZTogcXVldWVpbmcgKG9yIGlubGluZVxuICogZXhlY3V0aW9uKSBpcyB0aGUgY2FsbGVyJ3MgZGVjaXNpb24uIFVzZWQgYm90aCBmb3Igc3VzcGVuc2lvblxuICogcHJvY2Vzc2luZyAodGhlIGlubGluZSBsb29wKSBhbmQgZm9yIHRoZSB0ZXJtaW5hbCBkcmFpbiAoZmx1c2hpbmdcbiAqIGxlZnRvdmVyIHNpZGUgZWZmZWN0cyB3aGVuIHRoZSB3b3JrZmxvdyBjb21wbGV0ZWQgb3IgZmFpbGVkLCBtaXJyb3JpbmdcbiAqIHRoZSBub2RlOnZtIGVuZ2luZSdzIGRyYWluUGVuZGluZ1F1ZXVlSXRlbXMpLlxuICpcbiAqIFRoZSBvbmUgZXhjZXB0aW9uIGlzIHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoOiBmb3Igc3RlcCBjaWRzIG5hbWVkIGluXG4gKiBgcXVldWVTdGVwQ2lkc2AgKHRoZSBjYWxsZXIncyBvdmVyZmxvdyBzdGVwcykgdGhhdCBwYXNzIHRoZSBlbGlnaWJpbGl0eVxuICogZ2F0ZXMsIHRoZSBzdGVwX2NyZWF0ZWQgd3JpdGUgaXMgcGFyYWxsZWxpemVkIHdpdGggdGhlIHN0ZXAncyBxdWV1ZVxuICogcHVibGlzaDogdGhlIG1lc3NhZ2UgY2FycmllcyB0aGUgc2VyaWFsaXplZCBpbnB1dCAoYHN0ZXBJbnB1dGApIHNvIHRoZVxuICogY29uc3VtZXIgY2FuIGlkZW1wb3RlbnRseSByZS1lbnN1cmUgdGhlIGV2ZW50IGlmIHRoZSBkaXJlY3Qgd3JpdGUgZmFpbGVkXG4gKiB0cmFuc2llbnRseS4gU3RlcHMgcXVldWVkIHRoaXMgd2F5IGFyZSByZXBvcnRlZCBpbiBgcXVldWVkU3RlcENpZHNgOyB0aGVcbiAqIGNhbGxlciBxdWV1ZXMgdGhlIHJlc3QgaXRzZWxmLlxuICovXG5hc3luYyBmdW5jdGlvbiBkaXNwYXRjaFBlbmRpbmdPcHMocGFyYW1zOiB7XG4gIHdvcmxkOiBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIGdldFdvcmxkPj47XG4gIHJ1bklkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgc2VhbSBldmVyeSBldmVudCB3cml0ZSBpbiB0aGlzIHBhc3MgZ29lcyB0aHJvdWdoLiBUaGUgaW5saW5lIGxvb3BcbiAgICogcGFzc2VzIGEgY3JlYXRlIHRoYXQgbmFtZXMgdGhlIGxvZyBwb3NpdGlvbiB0aGlzIGludm9jYXRpb24gaG9sZHNcbiAgICogKGBldmVudENvdW50YCkgYW5kIHF1ZXVlcyB3aGF0IHRoZSBXb3JsZCBoYW5kcyBiYWNrIGZvciB0aGUgbGl2ZSBWTTsgc2VlXG4gICAqIHtAbGluayBRdWlja0pTTG9nVmlld30uIFRoZSB0ZXJtaW5hbCBkcmFpbiBwYXNzZXMgYSBwbGFpbiBjcmVhdGUsIHNpbmNlXG4gICAqIHRoZSBydW4gaXMgZW5kaW5nIGFuZCBub3RoaW5nIHJlYWRzIGl0cyBsb2cgYWZ0ZXJ3YXJkcy5cbiAgICovXG4gIGNyZWF0ZUV2ZW50OiBFdmVudENyZWF0b3I7XG4gIC8qKlxuICAgKiBUaGUgY3Vyc29yIHRoaXMgaW52b2NhdGlvbidzIGxvZyB3YXMgcmVhZCB0bywgd2hlbiB0aGUgY2FsbGVyIHdhbnRzIGEgbG9uZVxuICAgKiBgaG9va19jcmVhdGVkYCB0byBhc2sgZm9yIHRoZSBpbmxpbmUgZGVsdGEgYWdhaW5zdCBpdCAoYHNpbmNlQ3Vyc29yYCkuXG4gICAqIFRoZSBob29rJ3MgYXdhaXRlcnMgYXJlIHNldHRsZWQgYnkgdGhlIGV2ZW50IHRoYXQgd3JpdGUgY29tbWl0cyBhbmQgYnlcbiAgICogbm90aGluZyBlbHNlIChhIGBob29rX2NyZWF0ZWRgLCBvciB0aGUgYGhvb2tfY29uZmxpY3RgIGEgY2xhaW1lZCB0b2tlblxuICAgKiBjb21taXRzIGluc3RlYWQpLCBzbyB0aGUgZGVsdGEgaGFuZHMgdGhlIFZNIHRoYXQgZXZlbnQsIHBsdXMgYW55dGhpbmdcbiAgICogYW5vdGhlciB3cml0ZXIgbGFuZGVkIG1lYW53aGlsZSwgd2l0aG91dCBhIGxpc3RpbmcuIFNhbWUgZ2F0ZSBhcyB0aGUgbm9kZVxuICAgKiBlbmdpbmUncyBgaG9va0RlbHRhQ3Vyc29yYDogYXNrZWQgZm9yIG9ubHkgd2hlbiBleGFjdGx5IG9uZSBob29rIG5lZWRzXG4gICAqIGNyZWF0aW5nLCBzaW5jZSB0d28gY3JlYXRlcyBkaWZmaW5nIGFnYWluc3Qgb25lIGN1cnNvciB3b3VsZCBwcm9kdWNlIHR3b1xuICAgKiBkZWx0YXMgb2Ygd2hpY2ggb25seSB0aGUgZmlyc3QgY291bGQgYmUgdGFrZW4uIE9taXR0ZWQgYnkgdGhlIHRlcm1pbmFsXG4gICAqIGRyYWluLlxuICAgKi9cbiAgZGVsdGFDdXJzb3I/OiBzdHJpbmc7XG4gIHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1bjtcbiAgZW5jcnlwdGlvbktleTogUnVuUGF5bG9hZEtleXMgfCB1bmRlZmluZWQ7XG4gIHBlbmRpbmdPcGVyYXRpb25zOiBQZW5kaW5nT3BlcmF0aW9uW107XG4gIC8qKlxuICAgKiBTdGVwIGNpZHMgd2hvc2UgYHN0ZXBfY3JlYXRlZGAgbXVzdCBOT1QgYmUgd3JpdHRlbiBoZXJlOiB0aGUgaW5saW5lXG4gICAqIGxvb3AgY2xhaW1zIHRoZXNlIGF0b21pY2FsbHkgdmlhIGEgbGF6eSBgc3RlcF9zdGFydGVkYCAoY2FycnlpbmcgdGhlXG4gICAqIGlucHV0KSwgc28gYSBjb25jdXJyZW50IGNsYWltYW50IGxvc2VzIHdpdGggRW50aXR5Q29uZmxpY3RFcnJvclxuICAgKiBpbnN0ZWFkIG9mIGJvdGggaW52b2NhdGlvbnMgYmFyZS1zdGFydGluZyB0aGUgc2FtZSBzdGVwLlxuICAgKi9cbiAgc2tpcFN0ZXBDcmVhdGlvbj86IFNldDxzdHJpbmc+O1xuICAvKipcbiAgICogU3RlcCBjaWRzIHRoZSBjYWxsZXIgaW50ZW5kcyB0byBoYW5kIHRvIHRoZSBxdWV1ZSB0aGlzIHR1cm4gKG92ZXJmbG93XG4gICAqIHN0ZXBzIGJleW9uZCB0aGUgaW5saW5lIGNhcCkuIEVsaWdpYmxlIG9uZXMgYXJlIHB1Ymxpc2hlZCBoZXJlLCBpblxuICAgKiBwYXJhbGxlbCB3aXRoIHRoZWlyIHN0ZXBfY3JlYXRlZCB3cml0ZSAocmVzaWxpZW50IHN0ZXAgZGlzcGF0Y2gpLCBhbmRcbiAgICogcmVwb3J0ZWQgYmFjayBpbiBgcXVldWVkU3RlcENpZHNgLlxuICAgKi9cbiAgcXVldWVTdGVwQ2lkcz86IFNldDxzdHJpbmc+O1xuICAvKiogUXVldWUgbmFtZXNwYWNlIGZvciBhbGwgbWVzc2FnZSBwdWJsaXNoZXMgKHNlZSBydW50aW1lLnRzKS4gKi9cbiAgbmFtZXNwYWNlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBSdW4tb3JpZ2luIHRyYWNlIGNhcnJpZXIgYWNjZXNzb3IgZnJvbSBydW50aW1lLnRzLiBJbiB0aGUgZGVmYXVsdFxuICAgKiBgbGlua2VkYCB0cmFjZSBtb2RlIHRoaXMgcmV0dXJucyB0aGUgY2FycmllciBvZiB0aGUgcnVuJ3MgT1JJR0lOXG4gICAqIGNvbnRleHQgKHdvcmtmbG93LnN0YXJ0KSwgc28gZXZlcnkgaW52b2NhdGlvbiBsaW5rcyBiYWNrIHRvIHRoZVxuICAgKiBzdGFydCBpbiBhIHN0YXIuIENhcHR1cmluZyB0aGUgY3VycmVudCBjb250ZXh0IGhlcmUgaW5zdGVhZCB3b3VsZFxuICAgKiBjaGFpbiBpbnZvY2F0aW9ucyB0byBlYWNoIG90aGVyIGFuZCBmcmFnbWVudCB0aGUgcnVuIHZpZXcgb24gYXN5bmNcbiAgICogcXVldWVzLlxuICAgKi9cbiAgbmV4dFRyYWNlQ2FycmllcjogKCkgPT4gUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+PjtcbiAgLyoqXG4gICAqIFdoZW4gdHJ1ZSAodGhlIGlubGluZSBsb29wKSwgYSBzdGVwIGNhcnJ5aW5nIGBzZXJpYWxpemF0aW9uRXJyb3JgIGlzXG4gICAqIGZpbmFsaXplZCBhcyBzdGVwX2NyZWF0ZWQgKHBsYWNlaG9sZGVyIGlucHV0KSArIHN0ZXBfZmFpbGVkIHNvIHRoZVxuICAgKiBsaXZlLVZNIGZlZWQgcmVqZWN0cyB0aGUgc3RlcCdzIHByb21pc2UgYW5kIHdvcmtmbG93IGNvZGUgY2FuIGNhdGNoXG4gICAqIGl0LCBtaXJyb3JpbmcgdGhlIG5vZGU6dm0gZW5naW5lJ3MgZmluYWxpemVVbnNlcmlhbGl6YWJsZVN0ZXAuIFdoZW5cbiAgICogZmFsc2UgKHRoZSB0ZXJtaW5hbCBkcmFpbiksIHN1Y2ggc3RlcHMgYXJlIHNraXBwZWQgZW50aXJlbHk6IHRoZSBydW5cbiAgICogaXMgYWxyZWFkeSBjb21wbGV0aW5nL2ZhaWxpbmcsIG5vIHJlcGxheSBmb2xsb3dzIHRoZSBkcmFpbiB0byBvYnNlcnZlXG4gICAqIHRoZSBmYWlsdXJlLCBhbmQgYSBjb21wbGV0ZWQgcnVuIGNhcnJ5aW5nIGEgZmFpbGVkIHN0ZXAgd291bGQgcmVhZCBhc1xuICAgKiBhIGJ1ZyBmcm9tIHRoZSBkYXNoYm9hcmQsIG1hdGNoaW5nIHRoZSBub2RlOnZtIGRyYWluJ3MgYmVoYXZpb3IuXG4gICAqL1xuICBmaW5hbGl6ZVVuc2VyaWFsaXphYmxlU3RlcHM/OiBib29sZWFuO1xuICB3ZmRpYWc6IChjaGVja3BvaW50OiBzdHJpbmcsIGZpZWxkczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHZvaWQ7XG59KTogUHJvbWlzZTx7XG4gIGNyZWF0ZWRBdHRyaWJ1dGVFdmVudDogYm9vbGVhbjtcbiAgY3JlYXRlZEdldENvbmZsaWN0SG9vazogYm9vbGVhbjtcbiAgLyoqIFN0ZXAgY2lkcyBhbHJlYWR5IHB1Ymxpc2hlZCB2aWEgcmVzaWxpZW50IGRpc3BhdGNoLiBTZWUgYWJvdmUuICovXG4gIHF1ZXVlZFN0ZXBDaWRzOiBTZXQ8c3RyaW5nPjtcbiAgLyoqXG4gICAqIFN0ZXAgY2lkcyBmaW5hbGl6ZWQgYXMgZmFpbGVkIGJlY2F1c2UgdGhlaXIgaW5wdXQgcmVmdXNlZCB0b1xuICAgKiBzZXJpYWxpemUgKHNlZSBgZmluYWxpemVVbnNlcmlhbGl6YWJsZVN0ZXBzYCkuIE5vIGV4ZWN1dGlvbiBtZXNzYWdlXG4gICAqIGV4aXN0cyBmb3IgdGhlc2U7IHRoZSBjYWxsZXIgbXVzdCBlbnN1cmUgdGhlIHJ1biBvYnNlcnZlcyB0aGVcbiAgICogdGVybWluYWwgZXZlbnQgKHRoZSBpbmxpbmUgbG9vcCdzIGZlZWQsIG9yIHRoZSByZXF1ZXVlIHNpZ25hbCkuXG4gICAqL1xuICBmYWlsZWRTZXJpYWxpemF0aW9uU3RlcENpZHM6IFNldDxzdHJpbmc+O1xufT4ge1xuICBjb25zdCB7XG4gICAgd29ybGQsXG4gICAgcnVuSWQsXG4gICAgd29ya2Zsb3dSdW4sXG4gICAgZW5jcnlwdGlvbktleSxcbiAgICBwZW5kaW5nT3BlcmF0aW9ucyxcbiAgICBuYW1lc3BhY2UsXG4gICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICBjcmVhdGVFdmVudCxcbiAgfSA9IHBhcmFtcztcbiAgY29uc3Qgc2tpcFN0ZXBDcmVhdGlvbiA9IHBhcmFtcy5za2lwU3RlcENyZWF0aW9uO1xuICBjb25zdCBxdWV1ZVN0ZXBDaWRzID0gcGFyYW1zLnF1ZXVlU3RlcENpZHM7XG4gIGNvbnN0IHdmZGlhZyA9IHBhcmFtcy53ZmRpYWc7XG4gIC8vIFN0ZXAgY2lkcyBwdWJsaXNoZWQgdmlhIHJlc2lsaWVudCBkaXNwYXRjaCBiZWxvdyAoY3JlYXRlICsgcXVldWUgaW5cbiAgLy8gcGFyYWxsZWwsIG1lc3NhZ2UgY2FycnlpbmcgYHN0ZXBJbnB1dGApLiBSZXBvcnRlZCB0byB0aGUgY2FsbGVyIHNvIGl0XG4gIC8vIHNraXBzIHRoZW0gaW4gaXRzIG93biBxdWV1ZWluZyBwYXNzLlxuICBjb25zdCBxdWV1ZWRTdGVwQ2lkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAvLyBTdGVwIGNpZHMgZmluYWxpemVkIGFzIHN0ZXBfY3JlYXRlZCArIHN0ZXBfZmFpbGVkIGJlY2F1c2UgdGhlaXIgaW5wdXRcbiAgLy8gcmVmdXNlZCB0byBzZXJpYWxpemUuIFNlZSB0aGUgYGZpbmFsaXplVW5zZXJpYWxpemFibGVTdGVwc2AgcGFyYW0uXG4gIGNvbnN0IGZhaWxlZFNlcmlhbGl6YXRpb25TdGVwQ2lkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAvLyBSZXNpbGllbnQgc3RlcCBkaXNwYXRjaCBlbGlnaWJpbGl0eSwgc2hhcmVkIGJ5IGV2ZXJ5IHN0ZXAgb3AgYmVsb3cgKHRoZVxuICAvLyBwZXItc3RlcCBpbnB1dC1zaXplIGNoZWNrIGlzIGFwcGxpZWQgaW5zaWRlIHRoZSBvcCk6IGZlYXR1cmUgZW5hYmxlZCBhbmRcbiAgLy8gYSBiaW5hcnktc2FmZSAoQ0JPUikgcXVldWUgdHJhbnNwb3J0IGZvciB0aGUgcnVuLlxuICAvL1xuICAvLyBVbmxpa2UgdGhlIG5vZGU6dm0gc3VzcGVuc2lvbiBoYW5kbGVyJ3MgZ2F0ZSAoc2VlXG4gIC8vIFN1c3BlbnNpb25IYW5kbGVyUGFyYW1zLnN0ZXBEaXNwYXRjaCksIHRoZXJlIGlzIE5PIHByZWNvbmRpdGlvbi1ndWFyZFxuICAvLyBnYXRlIGhlcmU6IHRoaXMgZW5naW5lJ3Mgc3RlcF9jcmVhdGVkIHdyaXRlcyBhcmUgdW5ndWFyZGVkIChubyBzbmFwc2hvdFxuICAvLyBpcyBhdHRhY2hlZCksIHNvIGEgZ3VhcmQtZW5mb3JjaW5nIFdvcmxkIGNhbiBuZXZlciA0MTItcmVqZWN0IHRoZW06XG4gIC8vIHRoZSBjb25zdW1lcidzIHJlLWVuc3VyZSB0aGVyZWZvcmUgY2Fubm90IG1hdGVyaWFsaXplIGEgc3RlcCB0aGUgZ3VhcmRcbiAgLy8gcmVqZWN0ZWQuIElmIHRoaXMgZW5naW5lIGV2ZXIgYWRvcHRzIGd1YXJkZWQgc3VzcGVuc2lvbiB3cml0ZXMsIHRoZVxuICAvLyBjYXBhYmlsaXR5IGdhdGUgZnJvbSB0aGUgbm9kZTp2bSBoYW5kbGVyIG11c3QgYmUgYWRkZWQgaGVyZSB0b28uXG4gIGNvbnN0IHJlc2lsaWVudERpc3BhdGNoRWxpZ2libGUgPVxuICAgIHF1ZXVlU3RlcENpZHMgIT09IHVuZGVmaW5lZCAmJlxuICAgIHF1ZXVlU3RlcENpZHMuc2l6ZSA+IDAgJiZcbiAgICBpc1Jlc2lsaWVudFN0ZXBEaXNwYXRjaEVuYWJsZWQoKSAmJlxuICAgICh3b3JrZmxvd1J1bi5zcGVjVmVyc2lvbiA/PyAwKSA+PVxuICAgICAgU1BFQ19WRVJTSU9OX1NVUFBPUlRTX0NCT1JfUVVFVUVfVFJBTlNQT1JUO1xuICAvLyBTZXQgd2hlbiBhIGhvb2sgd2l0aCBhIHBhcmtlZCBnZXRDb25mbGljdCgpIGF3YWl0ZXIgaGFkIGl0c1xuICAvLyBob29rX2NyZWF0ZWQgd3JpdHRlbiB0aGlzIGludm9jYXRpb24uIFRoZSB3b3JrZmxvdyBtdXN0IGJlIHJlLWludm9rZWRcbiAgLy8gc28gcmVwbGF5IGNhbiBjb25maXJtIGNyZWF0aW9uIGFuZCByZXNvbHZlIHRoZSBhd2FpdGVyLlxuICBsZXQgY3JlYXRlZEdldENvbmZsaWN0SG9vayA9IGZhbHNlO1xuICAvLyBTZXQgd2hlbiBhIG5ldyBhdHRyX3NldCBldmVudCBpcyB3cml0dGVuIHRoaXMgaW52b2NhdGlvbi4gVGhlXG4gIC8vIHdvcmtmbG93IG11c3QgYmUgcmUtaW52b2tlZCB0byBjb25zdW1lIGl0IChyZXNvbHZpbmcgdGhlIHBlbmRpbmdcbiAgLy8gc2V0QXR0cmlidXRlcygpIHByb21pc2UpLCBzbyB0aGUgZW50cnlwb2ludCByZXF1ZXVlcyBpbW1lZGlhdGVseSxcbiAgLy8gc2FtZSBwYXR0ZXJuIGFzIGFuIGVsYXBzZWQgd2FpdC5cbiAgbGV0IGNyZWF0ZWRBdHRyaWJ1dGVFdmVudCA9IGZhbHNlO1xuICBjb25zdCBvcHNQcm9taXNlczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gIGNvbnN0IGhvb2tzTmVlZGluZ0NyZWF0aW9uID0gcGVuZGluZ09wZXJhdGlvbnMuZmlsdGVyKFxuICAgIChvcCkgPT4gb3AudHlwZSA9PT0gJ2hvb2snICYmICFvcC5oYXNDcmVhdGVkRXZlbnRcbiAgKS5sZW5ndGg7XG4gIGNvbnN0IGhvb2tEZWx0YUN1cnNvciA9XG4gICAgaG9va3NOZWVkaW5nQ3JlYXRpb24gPT09IDEgPyBwYXJhbXMuZGVsdGFDdXJzb3IgOiB1bmRlZmluZWQ7XG5cbiAgY29uc3QgcHJvY2Vzc0hvb2tPcCA9IGFzeW5jIChob29rOiBQZW5kaW5nSG9vayk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1F1aWNrSlMgcnVudGltZTogcHJvY2Vzc2luZyBob29rIG9wJywge1xuICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICBjb3JyZWxhdGlvbklkOiBob29rLmNvcnJlbGF0aW9uSWQsXG4gICAgICB0b2tlbjogaG9vay50b2tlbixcbiAgICAgIHRva2VuVHlwZTogdHlwZW9mIGhvb2sudG9rZW4sXG4gICAgICBpc1dlYmhvb2s6IGhvb2suaXNXZWJob29rLFxuICAgICAgaXNTeXN0ZW06IGhvb2suaXNTeXN0ZW0sXG4gICAgICBoYXNDcmVhdGVkRXZlbnQ6IGhvb2suaGFzQ3JlYXRlZEV2ZW50LFxuICAgICAgYWJvcnRSZXF1ZXN0ZWQ6IGhvb2suYWJvcnRSZXF1ZXN0ZWQsXG4gICAgfSk7XG5cbiAgICBpZiAoIWhvb2suaGFzQ3JlYXRlZEV2ZW50KSB7XG4gICAgICAvLyBgaG9vay5tZXRhZGF0YWAgaXMgdGhlIGZvcm1hdC1wcmVmaXhlZCBkZXZhbHVlIGJ5dGVzXG4gICAgICAvLyBwcm9kdWNlZCBieSBgZ2xvYmFsVGhpc1tTeW1ib2wuZm9yKCd3b3JrZmxvdy1zZXJpYWxpemUnKV1cbiAgICAgIC8vIChvcHRpb25zLm1ldGFkYXRhKWAgaW5zaWRlIHRoZSBWTS4gRW5jcnlwdCBvbiB0aGUgaG9zdFxuICAgICAgLy8gc2lkZSBiZWZvcmUgd3JpdGluZywgd2hpY2ggbWF0Y2hlcyB0aGUgbm9kZTp2bSBlbmdpbmUnc1xuICAgICAgLy8gYGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHNgIGZsb3cuXG4gICAgICAvL1xuICAgICAgLy8gTm8gcHJlLWNoZWNrIHZpYSBob29rcy5saXN0OiB3aXRoIGRldGVybWluaXN0aWMgY29ycmVsYXRpb25JZHNcbiAgICAgIC8vIChzYW1lIFZNIHNlZWQgYWNyb3NzIHJlcGxheXMpIGFuZCBwZXItKHJ1bklkLCBjb3JyZWxhdGlvbklkKVxuICAgICAgLy8gdW5pcXVlbmVzcyBpbiB3b3JsZHMsIHRoZSBzdG9yYWdlIGxheWVyIHJlamVjdHMgZHVwbGljYXRlcyBhc1xuICAgICAgLy8gRW50aXR5Q29uZmxpY3RFcnJvciwgd2hpY2ggd2Ugc3dhbGxvdyBiZWxvdy4gVGhpcyBkcm9wcyBvbmVcbiAgICAgIC8vIG5ldHdvcmsgcm91bmQtdHJpcCBwZXIgcGVuZGluZyBob29rLlxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZW5jcnlwdGVkTWV0YWRhdGEgPVxuICAgICAgICAgIHR5cGVvZiBob29rLm1ldGFkYXRhID09PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICAgIDogYXdhaXQgZW5jcnlwdFNlcmlhbGl6ZWREYXRhKGhvb2subWV0YWRhdGEsIGVuY3J5cHRpb25LZXkpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjcmVhdGVFdmVudChcbiAgICAgICAgICB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdob29rX2NyZWF0ZWQnLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogaG9vay5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgIHRva2VuOiBob29rLnRva2VuLFxuICAgICAgICAgICAgICB0b2tlblJldGVudGlvblVudGlsOlxuICAgICAgICAgICAgICAgIGhvb2sudG9rZW5SZXRlbnRpb25VbnRpbCA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgOiBuZXcgRGF0ZShob29rLnRva2VuUmV0ZW50aW9uVW50aWwpLFxuICAgICAgICAgICAgICBtZXRhZGF0YTogZW5jcnlwdGVkTWV0YWRhdGEsXG4gICAgICAgICAgICAgIC8vIEFsd2F5cyBpbmNsdWRlIGlzV2ViaG9vayBleHBsaWNpdGx5LiBXb3JsZHMgZGVmYXVsdCBpdCB0b1xuICAgICAgICAgICAgICAvLyBgdHJ1ZWAgd2hlbiBhYnNlbnQsIHdoaWNoIHdvdWxkIGJyZWFrIHRoZSBwdWJsaWMgd2ViaG9va1xuICAgICAgICAgICAgICAvLyBlbmRwb2ludCdzIDQwNCBndWFyZCBmb3IgaG9va3MgY3JlYXRlZCB2aWEgY3JlYXRlSG9vaygpLlxuICAgICAgICAgICAgICBpc1dlYmhvb2s6IGhvb2suaXNXZWJob29rLFxuICAgICAgICAgICAgICAvLyBTeXN0ZW0gaG9va3MgKEFib3J0Q29udHJvbGxlcikgYXJlIGV4ZW1wdCBmcm9tIHVzZXJcbiAgICAgICAgICAgICAgLy8gdG9rZW4gbmFtZXNwYWNlIGNvbmZsaWN0IGNoZWNrcy5cbiAgICAgICAgICAgICAgLi4uKGhvb2suaXNTeXN0ZW0gPyB7IGlzU3lzdGVtOiB0cnVlIH0gOiB7fSksXG4gICAgICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhvb2tEZWx0YUN1cnNvciAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICA/IHsgc2luY2VDdXJzb3I6IGhvb2tEZWx0YUN1cnNvciB9XG4gICAgICAgICAgICA6IHVuZGVmaW5lZFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIElmIHN0b3JhZ2UgZGV0ZWN0ZWQgYSByZWFsIHRva2VuIGNvbmZsaWN0IHdpdGggYW5vdGhlclxuICAgICAgICAvLyB3b3JrZmxvdydzIGhvb2ssIHJlLXF1ZXVlIHNvIHRoZSB3b3JrZmxvdyBoYW5kbGVyIGNhblxuICAgICAgICAvLyBwcm9jZXNzIHRoZSBjb25mbGljdCBldmVudCBhbmQgZmFpbCBncmFjZWZ1bGx5LlxuICAgICAgICBpZiAocmVzdWx0LmV2ZW50Py5ldmVudFR5cGUgPT09ICdob29rX2NvbmZsaWN0Jykge1xuICAgICAgICAgIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHsgaWRlbXBvdGVuY3lLZXk6IGBob29rX2NvbmZsaWN0XyR7aG9vay5jb3JyZWxhdGlvbklkfWAgfVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBBbHJlYWR5IGNyZWF0ZWQgYnkgYSBjb25jdXJyZW50IGludm9jYXRpb24sIHNvIGZhbGwgdGhyb3VnaFxuICAgICAgICAvLyB0byBhYm9ydCBwcm9jZXNzaW5nIGJlbG93IChpZiBhbnkpIGluc3RlYWQgb2YgYmFpbGluZy5cbiAgICAgICAgaWYgKCFFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHRocm93IGVycjtcbiAgICAgIH1cbiAgICAgIGlmIChob29rLmhhc0dldENvbmZsaWN0QXdhaXRlcikge1xuICAgICAgICBjcmVhdGVkR2V0Q29uZmxpY3RIb29rID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaG9vay5hYm9ydFJlcXVlc3RlZCkge1xuICAgICAgLy8gUmVjb3JkIHRoZSBhYm9ydCBkdXJhYmx5OiBhIGhvb2tfcmVjZWl2ZWQgZXZlbnQgY2FycnlpbmdcbiAgICAgIC8vIHRoZSBWTS1zZXJpYWxpemVkIGB7IGFib3J0ZWQ6IHRydWUsIHJlYXNvbiB9YCBwYXlsb2FkLFxuICAgICAgLy8gcGx1cyBhIGJlc3QtZWZmb3J0IHN0cmVhbSBwYWNrZXQgZm9yIHJlYWwtdGltZSBzdGVwXG4gICAgICAvLyBwcm9wYWdhdGlvbi4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUncyBzdXNwZW5zaW9uXG4gICAgICAvLyBoYW5kbGVyIChob29rc05lZWRpbmdBYm9ydCkuXG4gICAgICBjb25zdCBhYm9ydFBheWxvYWQgPVxuICAgICAgICBob29rLmFib3J0UGF5bG9hZCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXlcbiAgICAgICAgICA/ICgoYXdhaXQgZW5jcnlwdFNlcmlhbGl6ZWREYXRhKFxuICAgICAgICAgICAgICBob29rLmFib3J0UGF5bG9hZCxcbiAgICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICAgKSkgYXMgVWludDhBcnJheSlcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGNyZWF0ZUV2ZW50KHtcbiAgICAgICAgICBldmVudFR5cGU6ICdob29rX3JlY2VpdmVkJyxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgY29ycmVsYXRpb25JZDogaG9vay5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgdG9rZW46IGhvb2sudG9rZW4sXG4gICAgICAgICAgICBwYXlsb2FkOiBhYm9ydFBheWxvYWQsXG4gICAgICAgICAgfSBhcyBhbnksXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmICghRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgICAvLyBzdHJlYW1OYW1lIGlzIGRlcml2ZWQgZnJvbSB0aGUgYWJvcnQgaG9vayB0b2tlblxuICAgICAgLy8gKGBhYnJ0X3tpZH1gIOKGkiBgc3RybV97aWR9X3N5c3RlbV9hYm9ydGApLlxuICAgICAgaWYgKGhvb2sudG9rZW4uc3RhcnRzV2l0aCgnYWJydF8nKSAmJiBhYm9ydFBheWxvYWQpIHtcbiAgICAgICAgY29uc3Qgc3RyZWFtTmFtZSA9IGBzdHJtXyR7aG9vay50b2tlbi5zbGljZSgnYWJydF8nLmxlbmd0aCl9X3N5c3RlbV9hYm9ydGA7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShydW5JZCwgc3RyZWFtTmFtZSwgYWJvcnRQYXlsb2FkKTtcbiAgICAgICAgICBhd2FpdCB3b3JsZC5zdHJlYW1zLmNsb3NlKHJ1bklkLCBzdHJlYW1OYW1lKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gQmVzdC1lZmZvcnQ6IHRoZSBob29rIGV2ZW50IHByb3ZpZGVzIHRoZSBkdXJhYmxlXG4gICAgICAgICAgLy8gZmFsbGJhY2suXG4gICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICdRdWlja0pTIHJ1bnRpbWU6IGZhaWxlZCB0byB3cml0ZSBhYm9ydCBzdHJlYW0gcGFja2V0JyxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGhvb2suY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB3ZmRpYWcoJ2Fib3J0X3JlY29yZGVkJywge1xuICAgICAgICBjb3JyZWxhdGlvbklkOiBob29rLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgIHRva2VuOiBob29rLnRva2VuLFxuICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHByb2Nlc3NIb29rRGlzcG9zZU9wID0gYXN5bmMgKFxuICAgIG9wOiBQZW5kaW5nSG9va0Rpc3Bvc2VcbiAgKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNyZWF0ZUV2ZW50KHtcbiAgICAgICAgZXZlbnRUeXBlOiAnaG9va19kaXNwb3NlZCcsXG4gICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgY29ycmVsYXRpb25JZDogb3AuY29ycmVsYXRpb25JZCxcbiAgICAgICAgLy8gVGhlIGhvb2sncyB0b2tlbiwgd2hpY2ggdGhlIG5vZGU6dm0gZW5naW5lIGhhcyBhbHdheXMgc2VudC4gQSB3b3JsZFxuICAgICAgICAvLyB0aGF0IGtleXMgYSBob29rJ3MgdG9rZW4gY2xhaW0gc2VwYXJhdGVseSBmcm9tIHRoZSBob29rIGl0c2VsZiBuZWVkc1xuICAgICAgICAvLyBpdCB0byByZWxlYXNlIGJvdGgsIGFuZCB0aGUgb25seSBhbHRlcm5hdGl2ZSBpcyBmb3IgaXQgdG8gbG9vayB0aGVcbiAgICAgICAgLy8gdG9rZW4gdXAgZmlyc3QuIE9taXR0ZWQgcmF0aGVyIHRoYW4gc2VudCBhcyB1bmRlZmluZWQgd2hlbiB0aGUgb3BcbiAgICAgICAgLy8gY2FycmllcyBub25lLCBzbyBhIHdvcmxkIHRoYXQgcmVhZHMgaXQgY2Fubm90IHRlbGwgdGhlIGRpZmZlcmVuY2VcbiAgICAgICAgLy8gYmV0d2VlbiB0aGlzIGVuZ2luZSBhbmQgYSBjbGllbnQgdG9vIG9sZCB0byBzZW5kIG9uZS5cbiAgICAgICAgLi4uKG9wLnRva2VuID09PSB1bmRlZmluZWQgPyB7fSA6IHsgZXZlbnREYXRhOiB7IHRva2VuOiBvcC50b2tlbiB9IH0pLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSByZXR1cm47XG4gICAgICAvLyBEaXNwb3NpbmcgYSBob29rIHdob3NlIGVudGl0eSBubyBsb25nZXIgKG9yIG5ldmVyKSBleGlzdHMgaXMgYW5cbiAgICAgIC8vIGlkZW1wb3RlbnQgbm8tb3A6IHRoZSBlbnRpdHkgbWF5IGhhdmUgYmVlbiB0b3JuIGRvd24gYnkgYVxuICAgICAgLy8gY29uY3VycmVudCBydW4gY2FuY2VsbGF0aW9uLCBvciB0aGUgaG9vayBtYXkgaGF2ZSBsb3N0IGl0c1xuICAgICAgLy8gdG9rZW4gY2xhaW0gdG8gYSBjb25mbGljdC4gVGhlcmUgaXMgbm90aGluZyBsZWZ0IHRvIHJlbGVhc2UuXG4gICAgICBpZiAoSG9va05vdEZvdW5kRXJyb3IuaXMoZXJyKSkgcmV0dXJuO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfTtcblxuICAvLyBIb29rIG9wZXJhdGlvbnMgYXJlIGdyb3VwZWQgYnkgdG9rZW4gYW5kIHByb2Nlc3NlZCBTRVFVRU5USUFMTFkgaW5cbiAgLy8gY29kZSBvcmRlciB3aXRoaW4gZWFjaCBncm91cCwgbWlycm9yaW5nIHRoZSBub2RlOnZtIHN1c3BlbnNpb25cbiAgLy8gaGFuZGxlciAoaG9va0l0ZW1zQnlUb2tlbik6IGEgZGlzcG9zZSgpIG9mIGFuIGVhcmxpZXIgaG9vayBtdXN0XG4gIC8vIHJlbGVhc2UgdGhlIHRva2VuIGJlZm9yZSBhIGxhdGVyIHNhbWUtdG9rZW4gaG9vaydzIGNyZWF0aW9uIGlzXG4gIC8vIHZhbGlkYXRlZCBieSB0aGUgd29ybGQ6IHBhcmFsbGVsIGRpc3BhdGNoIHdvdWxkIG90aGVyd2lzZSByZWNvcmQgYVxuICAvLyBzcHVyaW91cyBob29rX2NvbmZsaWN0IGFnYWluc3QgdGhlIHJ1bidzIG93biBkaXNwb3NlZCBob29rIChlLmcuIGFcbiAgLy8gZGlzcG9zZeKGknJlY3JlYXRlIGxvb3AgcmV1c2luZyBvbmUgdG9rZW4pLiBEaWZmZXJlbnQgdG9rZW5zIGhhdmUgbm9cbiAgLy8gY2xhaW0gaW50ZXJhY3Rpb24sIHNvIHRva2VuIGdyb3VwcyBydW4gaW4gcGFyYWxsZWwgd2l0aCBlYWNoIG90aGVyXG4gIC8vIGFuZCB3aXRoIHRoZSBub24taG9vayBvcHMgYmVsb3cuXG4gIGNvbnN0IGhvb2tPcHNCeVRva2VuID0gbmV3IE1hcDxcbiAgICBzdHJpbmcsXG4gICAgKFBlbmRpbmdIb29rIHwgUGVuZGluZ0hvb2tEaXNwb3NlKVtdXG4gID4oKTtcbiAgZm9yIChjb25zdCBvcCBvZiBwZW5kaW5nT3BlcmF0aW9ucykge1xuICAgIGxldCBrZXk6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBpZiAoXG4gICAgICBvcC50eXBlID09PSAnaG9vaycgJiZcbiAgICAgICghb3AuaGFzQ3JlYXRlZEV2ZW50IHx8IChvcCBhcyBQZW5kaW5nSG9vaykuYWJvcnRSZXF1ZXN0ZWQpXG4gICAgKSB7XG4gICAgICBrZXkgPSAob3AgYXMgUGVuZGluZ0hvb2spLnRva2VuO1xuICAgIH0gZWxzZSBpZiAob3AudHlwZSA9PT0gJ2hvb2tfZGlzcG9zZScgJiYgIW9wLmhhc0NyZWF0ZWRFdmVudCkge1xuICAgICAgLy8gUGVyLW9wIGZhbGxiYWNrIGdyb3VwIHdoZW4gdGhlIHRva2VuIGlzIHVua25vd246IG5vIG9yZGVyaW5nXG4gICAgICAvLyBndWFyYW50ZWVzLCBtYXRjaGluZyB0aGUgcHJldmlvdXMgcGFyYWxsZWwgYmVoYXZpb3IuXG4gICAgICBrZXkgPSAob3AgYXMgUGVuZGluZ0hvb2tEaXNwb3NlKS50b2tlbiA/PyBgX19jaWQ6JHtvcC5jb3JyZWxhdGlvbklkfWA7XG4gICAgfVxuICAgIGlmIChrZXkgPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgY29uc3QgZ3JvdXAgPSBob29rT3BzQnlUb2tlbi5nZXQoa2V5KTtcbiAgICBpZiAoZ3JvdXApIHtcbiAgICAgIGdyb3VwLnB1c2gob3AgYXMgUGVuZGluZ0hvb2sgfCBQZW5kaW5nSG9va0Rpc3Bvc2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBob29rT3BzQnlUb2tlbi5zZXQoa2V5LCBbb3AgYXMgUGVuZGluZ0hvb2sgfCBQZW5kaW5nSG9va0Rpc3Bvc2VdKTtcbiAgICB9XG4gIH1cbiAgZm9yIChjb25zdCBncm91cCBvZiBob29rT3BzQnlUb2tlbi52YWx1ZXMoKSkge1xuICAgIG9wc1Byb21pc2VzLnB1c2goXG4gICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IG9wIG9mIGdyb3VwKSB7XG4gICAgICAgICAgaWYgKG9wLnR5cGUgPT09ICdob29rJykge1xuICAgICAgICAgICAgYXdhaXQgcHJvY2Vzc0hvb2tPcChvcCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IHByb2Nlc3NIb29rRGlzcG9zZU9wKG9wKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pKClcbiAgICApO1xuICB9XG5cbiAgZm9yIChjb25zdCBvcCBvZiBwZW5kaW5nT3BlcmF0aW9ucykge1xuICAgIGlmIChcbiAgICAgIG9wLnR5cGUgPT09ICdzdGVwJyAmJlxuICAgICAgIW9wLmhhc0NyZWF0ZWRFdmVudCAmJlxuICAgICAgIXNraXBTdGVwQ3JlYXRpb24/LmhhcyhvcC5jb3JyZWxhdGlvbklkKVxuICAgICkge1xuICAgICAgY29uc3Qgc3RlcCA9IG9wIGFzIFBlbmRpbmdTdGVwO1xuICAgICAgb3BzUHJvbWlzZXMucHVzaChcbiAgICAgICAgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAvLyBUaGUgc3RlcCdzIGlucHV0IHJlZnVzZWQgdG8gc2VyaWFsaXplIHdoaWxlIGR1bXBpbmcgdGhlIFZNJ3NcbiAgICAgICAgICAvLyBwZW5kaW5nIG9wcyAoc2VlIFBlbmRpbmdTdGVwLnNlcmlhbGl6YXRpb25FcnJvcikuIEZpbmFsaXplIGl0XG4gICAgICAgICAgLy8gYXMgc3RlcF9jcmVhdGVkIChwbGFjZWhvbGRlciBpbnB1dCwgc2luY2UgdGhlIHdvcmxkIHJlcXVpcmVzIHRoZVxuICAgICAgICAgIC8vIHN0ZXAgZW50aXR5IGJlZm9yZSBhIHRlcm1pbmFsIGV2ZW50KSArIHN0ZXBfZmFpbGVkIGNhcnJ5aW5nXG4gICAgICAgICAgLy8gdGhlIFNlcmlhbGl6YXRpb25FcnJvciwgc28gdGhlIGxpdmUtVk0gZmVlZCByZWplY3RzIHRoZVxuICAgICAgICAgIC8vIHN0ZXAncyBwcm9taXNlIGFuZCB3b3JrZmxvdyBjb2RlIGNhbiBjYXRjaCBpdC4gTmV2ZXIgcXVldWUgYW5cbiAgICAgICAgICAvLyBleGVjdXRpb24gbWVzc2FnZSBmb3IgaXQuIE1pcnJvcnMgdGhlIG5vZGU6dm0gZW5naW5lJ3NcbiAgICAgICAgICAvLyBmaW5hbGl6ZVVuc2VyaWFsaXphYmxlU3RlcC4gSW4gdGhlIHRlcm1pbmFsIGRyYWluXG4gICAgICAgICAgLy8gKGZpbmFsaXplVW5zZXJpYWxpemFibGVTdGVwcyB1bnNldCksIHNraXAgZW50aXJlbHk6IHNlZSB0aGVcbiAgICAgICAgICAvLyBwYXJhbSBkb2NzLlxuICAgICAgICAgIGlmIChzdGVwLnNlcmlhbGl6YXRpb25FcnJvcikge1xuICAgICAgICAgICAgaWYgKCFwYXJhbXMuZmluYWxpemVVbnNlcmlhbGl6YWJsZVN0ZXBzKSB7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgJ1N0ZXAgYXJndW1lbnRzIGZhaWxlZCB0byBzZXJpYWxpemU7IGZhaWxpbmcgdGhlIHN0ZXAgc28gJyArXG4gICAgICAgICAgICAgICAgJ3RoZSB3b3JrZmxvdyBjYW4gb2JzZXJ2ZSB0aGUgZXJyb3InLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIHN0ZXBOYW1lOiBzdGVwLnN0ZXBJZCxcbiAgICAgICAgICAgICAgICBlcnJvcjogc3RlcC5zZXJpYWxpemF0aW9uRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGF3YWl0IGNyZWF0ZUV2ZW50KHtcbiAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2NyZWF0ZWQnLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICBzdGVwTmFtZTogc3RlcC5zdGVwSWQsXG4gICAgICAgICAgICAgICAgICBpbnB1dDogKGF3YWl0IGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHMoXG4gICAgICAgICAgICAgICAgICAgIHVuc2VyaWFsaXphYmxlU3RlcElucHV0UGxhY2Vob2xkZXIoKSxcbiAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgICAgICAgICAgICAgIGdsb2JhbFRoaXMsXG4gICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAod29ya2Zsb3dSdW4uc3BlY1ZlcnNpb24gPz8gMCkgPj1cbiAgICAgICAgICAgICAgICAgICAgICBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ09NUFJFU1NJT05cbiAgICAgICAgICAgICAgICAgICkpIGFzIFVpbnQ4QXJyYXksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgLy8gQ29uY3VycmVudCBpbnZvY2F0aW9uIGhpdCB0aGUgc2FtZSBkZXRlcm1pbmlzdGljIGZhaWx1cmVcbiAgICAgICAgICAgICAgLy8gYW5kIGNyZWF0ZWQgaXQgZmlyc3QsIG9yIHRoZSBydW4gYWxyZWFkeSBmaW5pc2hlZC5cbiAgICAgICAgICAgICAgaWYgKFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSByZXR1cm47XG4gICAgICAgICAgICAgIGlmICghRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB0aHJvdyBlcnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBhd2FpdCBjcmVhdGVFdmVudCh7XG4gICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9mYWlsZWQnLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICBzdGVwTmFtZTogc3RlcC5zdGVwSWQsXG4gICAgICAgICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBzdGVwLnNlcmlhbGl6YXRpb25FcnJvcixcbiAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgICAgICAgICAgICAod29ya2Zsb3dSdW4uc3BlY1ZlcnNpb24gPz8gMCkgPj1cbiAgICAgICAgICAgICAgICAgICAgICBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ09NUFJFU1NJT05cbiAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgLy8gU3RlcCBhbHJlYWR5IHRlcm1pbmFsIG9yIHJ1biBhbHJlYWR5IGZpbmlzaGVkLlxuICAgICAgICAgICAgICBpZiAoIUVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSAmJiAhUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZhaWxlZFNlcmlhbGl6YXRpb25TdGVwQ2lkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICAgIHdmZGlhZygnc3RlcF9zZXJpYWxpemF0aW9uX2ZhaWxlZCcsIHtcbiAgICAgICAgICAgICAgc3RlcElkOiBzdGVwLnN0ZXBJZCxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ3JlYXRlIHN0ZXBfY3JlYXRlZCBldmVudC4gYHN0ZXAuaW5wdXRgIGlzIHRoZVxuICAgICAgICAgIC8vIGZvcm1hdC1wcmVmaXhlZCBkZXZhbHVlIGJ5dGVzIChcImRldmxcIiArIGRldmFsdWUpIHByb2R1Y2VkXG4gICAgICAgICAgLy8gYnkgYGdsb2JhbFRoaXNbU3ltYm9sLmZvcignd29ya2Zsb3ctc2VyaWFsaXplJyldKHthcmdzLFxuICAgICAgICAgIC8vIGNsb3N1cmVWYXJzLCB0aGlzVmFsfSlgIGluc2lkZSB0aGUgVk0uIFRoZSBWTSBoYXMgbm9cbiAgICAgICAgICAvLyBhY2Nlc3MgdG8gdGhlIENyeXB0b0tleSwgc28gZW5jcnlwdGlvbiBpcyBhcHBsaWVkIGhlcmVcbiAgICAgICAgICAvLyBvbiB0aGUgaG9zdCBzaWRlLCBtYXRjaGluZyB3aGF0XG4gICAgICAgICAgLy8gYGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHNgIGRvZXMgaW4gdGhlIG5vZGU6dm0gZW5naW5lLlxuICAgICAgICAgIGNvbnN0IGVuY3J5cHRlZElucHV0ID0gYXdhaXQgZW5jcnlwdFNlcmlhbGl6ZWREYXRhKFxuICAgICAgICAgICAgc3RlcC5pbnB1dCxcbiAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gUmVzaWxpZW50IHN0ZXAgZGlzcGF0Y2g6IGZpcmUgdGhlIHN0ZXBfY3JlYXRlZCB3cml0ZSBhbmQgdGhlXG4gICAgICAgICAgLy8gc3RlcCdzIHF1ZXVlIHB1Ymxpc2ggaW4gcGFyYWxsZWw6IHRoZSBtZXNzYWdlIGNhcnJpZXMgdGhlXG4gICAgICAgICAgLy8gc2FtZSBzZXJpYWxpemVkIGlucHV0IChgc3RlcElucHV0YCkgc28gdGhlIGNvbnN1bWVyIGNhblxuICAgICAgICAgIC8vIGlkZW1wb3RlbnRseSByZS1lbnN1cmUgdGhlIGV2ZW50IGlmIHRoZSBkaXJlY3Qgd3JpdGUgZmFpbGVkXG4gICAgICAgICAgLy8gdHJhbnNpZW50bHkuIE1pcnJvcnMgdGhlIG5vZGU6dm0gc3VzcGVuc2lvbiBoYW5kbGVyIGFuZCB0aGVcbiAgICAgICAgICAvLyByZXNpbGllbnQgc3RhcnQgLyByZXNpbGllbnQgaG9vayByZXN1bWUgcGF0dGVybnMuIE9ubHkgZm9yXG4gICAgICAgICAgLy8gY2FsbGVyLWRlc2lnbmF0ZWQgb3ZlcmZsb3cgc3RlcHMgd2l0aCBpbnB1dHMgdGhlIHF1ZXVlXG4gICAgICAgICAgLy8gbWVzc2FnZSBjYW4gc2FmZWx5IGNhcnJ5IChiaW5hcnksIHVuZGVyIHRoZSBWUVMgc2l6ZSBjYXApLlxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHJlc2lsaWVudERpc3BhdGNoRWxpZ2libGUgJiZcbiAgICAgICAgICAgIHF1ZXVlU3RlcENpZHM/LmhhcyhzdGVwLmNvcnJlbGF0aW9uSWQpICYmXG4gICAgICAgICAgICBlbmNyeXB0ZWRJbnB1dCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgJiZcbiAgICAgICAgICAgIGVuY3J5cHRlZElucHV0LmJ5dGVMZW5ndGggPD0gTUFYX1JFU0lMSUVOVF9TVEVQX0lOUFVUX0JZVEVTXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBbY3JlYXRlUmVzdWx0LCBxdWV1ZVJlc3VsdF0gPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgICAgICAgICAgICBjcmVhdGVFdmVudCh7XG4gICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9jcmVhdGVkJyxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgICAgaW5wdXQ6IGVuY3J5cHRlZElucHV0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBxdWV1ZVN0ZXBNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICAgICAgICBuZXh0VHJhY2VDYXJyaWVyLFxuICAgICAgICAgICAgICAgIHB1cnBvc2U6ICdkaXNwYXRjaCcsXG4gICAgICAgICAgICAgICAgc3RlcElucHV0OiBlbmNyeXB0ZWRJbnB1dCxcbiAgICAgICAgICAgICAgICB3ZmRpYWcsXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAvLyBRdWV1ZSBmYWlsdXJlIGlzIGFsd2F5cyBmYXRhbCBmb3IgdGhpcyBkaXNwYXRjaCBwYXNzOlxuICAgICAgICAgICAgLy8gd2l0aG91dCB0aGUgbWVzc2FnZSB0aGUgc3RlcCB3b3VsZCByZWx5IG9uIHRoZSBjcmVhdGVcbiAgICAgICAgICAgIC8vIGFsb25lLCBhbmQgaWYgdGhlIGNyZWF0ZSBBTFNPIGZhaWxlZCB0aGVyZSB3b3VsZCBiZSBub1xuICAgICAgICAgICAgLy8gZHVyYWJsZSByZWNvcmQgYXQgYWxsLiBQcm9wYWdhdGluZyByZWRlbGl2ZXJzIHRoZVxuICAgICAgICAgICAgLy8gb3JjaGVzdHJhdG9yIG1lc3NhZ2UsIHdoaWNoIHJlLWNyZWF0ZXMgdGhlIChpZGVtcG90ZW50KVxuICAgICAgICAgICAgLy8gc3RlcF9jcmVhdGVkIGFuZCByZS1kaXNwYXRjaGVzLlxuICAgICAgICAgICAgaWYgKHF1ZXVlUmVzdWx0LnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgICAgICAgICB0aHJvdyBxdWV1ZVJlc3VsdC5yZWFzb247XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBxdWV1ZWRTdGVwQ2lkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICAgIGlmIChjcmVhdGVSZXN1bHQuc3RhdHVzID09PSAncmVqZWN0ZWQnKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVyciA9IGNyZWF0ZVJlc3VsdC5yZWFzb247XG4gICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICAvLyBDb25jdXJyZW50IGludm9jYXRpb24gd3JvdGUgaXQgZmlyc3Q6IHRoZSBtZXNzYWdlIGlzXG4gICAgICAgICAgICAgICAgLy8gYWxyZWFkeSBvdXQ7IGl0cyBkdXBsaWNhdGUgcHVibGlzaCBkZWR1cGVzIG9uIHRoZVxuICAgICAgICAgICAgICAgIC8vIHNoYXJlZCBzdGVwLWlkZW50aXR5LXNjb3BlZCBpZGVtcG90ZW5jeSBrZXkuXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChpc1JldHJ5YWJsZVdvcmxkRXJyb3IoZXJyKSkge1xuICAgICAgICAgICAgICAgIC8vIFJlc2lsaWVudDogdGhlIHdyaXRlIGZhaWxlZCB0cmFuc2llbnRseSAoNDI5IC8gNXh4IC9cbiAgICAgICAgICAgICAgICAvLyB0cmFuc3BvcnQpIGJ1dCB0aGUgc3RlcCBtZXNzYWdlIChjYXJyeWluZyB0aGUgc2FtZVxuICAgICAgICAgICAgICAgIC8vIHNlcmlhbGl6ZWQgaW5wdXQpIHdhcyBwdWJsaXNoZWQsIHNvIHRoZSBjb25zdW1lclxuICAgICAgICAgICAgICAgIC8vIGlkZW1wb3RlbnRseSByZS1lbnN1cmVzIHRoZSBzdGVwX2NyZWF0ZWQgYmVmb3JlXG4gICAgICAgICAgICAgICAgLy8gZXhlY3V0aW5nLlxuICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICdTdGVwIGNyZWF0aW9uIGV2ZW50IHdyaXRlIGZhaWxlZCwgYnV0IHRoZSBzdGVwIHdhcyAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2Rpc3BhdGNoZWQgdmlhIHRoZSBxdWV1ZS4gVGhlIHN0ZXBfY3JlYXRlZCBldmVudCAnICtcbiAgICAgICAgICAgICAgICAgICAgJ3dpbGwgYmUgZW5zdXJlZCBieSB0aGUgcXVldWUgY29uc3VtZXIuJyxcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXAuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgd2ZkaWFnKCdzdGVwX3Jlc2lsaWVudF9kaXNwYXRjaF9yZWNvdmVyZWQnLCB7XG4gICAgICAgICAgICAgICAgICBzdGVwSWQ6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGNyZWF0ZUV2ZW50KHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9jcmVhdGVkJyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIHN0ZXBOYW1lOiBzdGVwLnN0ZXBJZCxcbiAgICAgICAgICAgICAgICBpbnB1dDogZW5jcnlwdGVkSW5wdXQsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHJldHVybjtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBOT1RFOiBzdGVwIHF1ZXVlaW5nIGlzIG90aGVyd2lzZSB0aGUgY2FsbGVyJ3MgZGVjaXNpb246IHRoZVxuICAgICAgICAgIC8vIGlubGluZSBsb29wIGV4ZWN1dGVzIGZyZXNoIHN0ZXBzIGluIHRoZSBsaXZlIFZNIGFuZCBvbmx5XG4gICAgICAgICAgLy8gcXVldWVzIHRoZSBvdmVyZmxvdyAvIHJldHJ5IC8gYmFja3N0b3AgY2FzZXMgKHNlZVxuICAgICAgICAgIC8vIHF1ZXVlU3RlcE1lc3NhZ2UpLlxuICAgICAgICB9KSgpXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAob3AudHlwZSA9PT0gJ2F0dHJpYnV0ZScgJiYgIW9wLmhhc0NyZWF0ZWRFdmVudCkge1xuICAgICAgY29uc3QgYXR0ciA9IG9wIGFzIFBlbmRpbmdBdHRyaWJ1dGU7XG4gICAgICBvcHNQcm9taXNlcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBjcmVhdGVFdmVudCh7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogJ2F0dHJfc2V0JyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBhdHRyLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIGNoYW5nZXM6IGF0dHIuY2hhbmdlcyxcbiAgICAgICAgICAgICAgICB3cml0ZXI6IHsgdHlwZTogJ3dvcmtmbG93JyB9LFxuICAgICAgICAgICAgICAgIC4uLihhdHRyLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgICA/IHsgYWxsb3dSZXNlcnZlZEF0dHJpYnV0ZXM6IHRydWUgfVxuICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjcmVhdGVkQXR0cmlidXRlRXZlbnQgPSB0cnVlO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAvLyBFdmVudCBhbHJlYWR5IGV4aXN0cyAoY29uY3VycmVudCBpbnZvY2F0aW9uKSwgYnV0IHRoZVxuICAgICAgICAgICAgICAvLyByZXBsYXkgc3RpbGwgbmVlZHMgdG8gY29uc3VtZSBpdCwgc28gcmVxdWV1ZS5cbiAgICAgICAgICAgICAgY3JlYXRlZEF0dHJpYnV0ZUV2ZW50ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKVxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKG9wLnR5cGUgPT09ICd3YWl0JyAmJiAhb3AuaGFzQ3JlYXRlZEV2ZW50KSB7XG4gICAgICBjb25zdCB3YWl0ID0gb3AgYXMgUGVuZGluZ1dhaXQ7XG4gICAgICBvcHNQcm9taXNlcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBjcmVhdGVFdmVudCh7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3dhaXRfY3JlYXRlZCcsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogd2FpdC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICByZXN1bWVBdDogbmV3IERhdGUod2FpdC5yZXN1bWVBdCksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHJldHVybjtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gUGVyLW9wIGRpc3BhdGNoIHJ1bnMgaW4gcGFyYWxsZWwuXG4gIGF3YWl0IFByb21pc2UuYWxsKG9wc1Byb21pc2VzKTtcblxuICByZXR1cm4ge1xuICAgIGNyZWF0ZWRBdHRyaWJ1dGVFdmVudCxcbiAgICBjcmVhdGVkR2V0Q29uZmxpY3RIb29rLFxuICAgIHF1ZXVlZFN0ZXBDaWRzLFxuICAgIGZhaWxlZFNlcmlhbGl6YXRpb25TdGVwQ2lkcyxcbiAgfTtcbn1cblxuLyoqXG4gKiBSdW4gYSB3b3JrZmxvdyB1c2luZyB0aGUgUXVpY2tKUyBXQVNNIFZNIGVuZ2luZS5cbiAqXG4gKiBUaGlzIHJlcGxhY2VzIHRoZSBgbm9kZTp2bWAgcmVwbGF5IHBhdGggKHJ1bldvcmtmbG93ICsgRXZlbnRzQ29uc3VtZXIpXG4gKiB3aXRoIGEgUXVpY2tKUyBWTSBpbnZvY2F0aW9uIHRoYXQgcGVyZm9ybXMgdGhlIHNhbWUgZnVsbCBldmVudCByZXBsYXkuXG4gKlxuICogTG9nIHBvc2l0aW9uIG9uIHdyaXRlcy4gVGhpcyBlbmdpbmUgZm9sbG93cyB0aGUgc2FtZSBydWxlIGFzIHRoZSBub2RlOnZtXG4gKiByZXBsYXkgbG9vcCBmb3Igd2hpY2ggd3JpdGVzIHRlbGwgdGhlIFdvcmxkIHdoZXJlIHRoZSB3cml0ZXIgc3Rvb2QgKHNlZSB0aGVcbiAqIFwiV2hvIG5hbWVzIGEgcG9zaXRpb25cIiB0YWJsZSBhYm92ZSBgc2xvdFNuYXBzaG90UGFyYW1zYCBpbiBgaGVscGVycy50c2ApOlxuICpcbiAqIC0gV3JpdGVzIG1hZGUgZnJvbSB0aGlzIGludm9jYXRpb24ncyB2aWV3IG9mIHRoZSBsb2cgKGBzdGVwX2NyZWF0ZWRgLFxuICogICBgd2FpdF9jcmVhdGVkYCwgYGhvb2tfY3JlYXRlZGAsIGBob29rX2Rpc3Bvc2VkYCwgYGF0dHJfc2V0YCwgdGhlIGFib3J0XG4gKiAgIGBob29rX3JlY2VpdmVkYCwgYHdhaXRfY29tcGxldGVkYCwgYW5kIHRoZSBgc3RlcF9jcmVhdGVkYCArIGBzdGVwX2ZhaWxlZGBcbiAqICAgcGFpciBmb3IgYW4gdW5zZXJpYWxpemFibGUgaW5wdXQpIGNhcnJ5IGBldmVudENvdW50YCwgYW5kIHRoZSBwYWdlIGFcbiAqICAgV29ybGQgaGFuZHMgYmFjayBpcyBxdWV1ZWQgZm9yIHRoZSBsaXZlIFZNIHRocm91Z2gge0BsaW5rIFF1aWNrSlNMb2dWaWV3fS5cbiAqIC0gQSBzaW5nbGUgaW5saW5lIHN0ZXAncyB0ZXJtaW5hbCB3cml0ZSBhc2tzIGZvciB0aGUgaW5saW5lIGRlbHRhXG4gKiAgIChgc2luY2VDdXJzb3JgKSB0aHJvdWdoIGBleGVjdXRlU3RlcGAsIGFuZCBzbyBkb2VzIGEgbG9uZSBgaG9va19jcmVhdGVkYFxuICogICAoc2VlIGBkaXNwYXRjaFBlbmRpbmdPcHMuZGVsdGFDdXJzb3JgKTsgdGhlIGRlbHRhIGlzIHF1ZXVlZCB0aGUgc2FtZVxuICogICB3YXkuIFRoZSBzdGVwIGV4ZWN1dG9yJ3Mgb3RoZXIgd3JpdGVzIGNhcnJ5IG5vdGhpbmc6IGl0IGhvbGRzIG5vIGxvZy5cbiAqIC0gUnVuLXRlcm1pbmFsIHdyaXRlcyAoYHJ1bl9jb21wbGV0ZWRgLCBgcnVuX2ZhaWxlZGApIGFuZCB0aGUgdGVybWluYWwgZHJhaW5cbiAqICAgb2YgcGVuZGluZyBvcHMgY2Fycnkgbm90aGluZzogbm90aGluZyByZWFkcyB0aGUgbG9nIGFmdGVyd2FyZHMuXG4gKlxuICogV2hhdCBkaWZmZXJzIGZyb20gdGhlIG5vZGUgZW5naW5lIGlzIHdoYXQgXCJtZXJnZSBpbnRvIHRoZSBsb2dcIiBtZWFucy4gVGhlXG4gKiBub2RlIGVuZ2luZSBtZXJnZXMgYSByZXR1cm5lZCBwYWdlIGludG8gdGhlIGFycmF5IGl0IHJlcGxheXMgZnJvbS4gVGhpc1xuICogZW5naW5lIGhvbGRzIGEgbGl2ZSBWTSB0aGF0IGNvbnN1bWVzIGV2ZW50cyBleGFjdGx5IG9uY2UsIGluIHBvc2l0aW9uXG4gKiBvcmRlciwgc28gYSByZXR1cm5lZCBwYWdlIGlzIHF1ZXVlZCBhbmQgZGVsaXZlcmVkIGFoZWFkIG9mIHRoZSBuZXh0XG4gKiBgZXZlbnRzLmxpc3RgLCB3aGljaCB0aGVuIG9ubHkgcnVucyB3aGVuIHRoZSBxdWV1ZSBjYW5ub3QgYWNjb3VudCBmb3IgdGhlXG4gKiBuZXh0IHBvc2l0aW9uLiBCb3RoIGVuZ2luZXMgZmFsbCBiYWNrIHRvIGEgbGlzdCBmb3IgYW55dGhpbmcgYSBwYWdlIGRpZFxuICogbm90IGNhcnJ5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuV29ya2Zsb3dXaXRoUXVpY2tKUyhwYXJhbXM6IHtcbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmc7XG4gIHdvcmtmbG93TmFtZTogc3RyaW5nO1xuICB3b3JrZmxvd1J1bjogV29ya2Zsb3dSdW47XG4gIC8qKlxuICAgKiBFdmVudHMgcmV0dXJuZWQgaW5saW5lIGJ5IGBldmVudHMuY3JlYXRlKCdydW5fc3RhcnRlZCcsIC4uLilgIG9yIGJ5XG4gICAqIHRoZSBsYXp5IGhvb2sgZmFzdCBwYXRoJ3MgYGhvb2tfcmVjZWl2ZWRgIHByZWxvYWQuIFdoZW4gdGhleSBpbmRpY2F0ZVxuICAgKiBhIGZpcnN0IGludm9jYXRpb24sIG9yIHdoZW4gYHByZWxvYWRlZEV2ZW50c0NvbXBsZXRlYCBhdHRlc3RzIHRoZXlcbiAgICogYXJlIHRoZSBjb21wbGV0ZSBsb2csIHRoZXkgYXJlIHVzZWQgYXMgdGhlIGV2ZW50IGxvZyBpbnN0ZWFkIG9mXG4gICAqIGZldGNoaW5nIHZpYSBgZXZlbnRzLmxpc3RgLCBtYXRjaGluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBmYXN0IHBhdGguXG4gICAqL1xuICBwcmVsb2FkZWRFdmVudHM/OiBFdmVudFtdO1xuICAvKipcbiAgICogVHJ1ZSB3aGVuIHRoZSBjYWxsZXIgaGFzIHZhbGlkYXRlZCB0aGF0IGBwcmVsb2FkZWRFdmVudHNgIGlzIHRoZSBydW4nc1xuICAgKiBDT01QTEVURSBldmVudCBsb2cgKGUuZy4gdGhlIGxhenkgaG9vayBmYXN0IHBhdGgncyBoYXNNb3JlLWZhbHNlXG4gICAqIHJlcGxheSBwcmVsb2FkKS4gVGhlIGZpcnN0LWludm9jYXRpb24gaGV1cmlzdGljIGJlbG93IG9ubHkgcmVjb2duaXplc1xuICAgKiBydW5fY3JlYXRlZC9ydW5fc3RhcnRlZC1vbmx5IHByZWxvYWRzLCBzbyB3aXRob3V0IHRoaXMgYXR0ZXN0YXRpb24gYVxuICAgKiBob29rLXJlc3VtZSBwcmVsb2FkIHdvdWxkIGJlIGRpc2NhcmRlZCBhbmQgcmVmZXRjaGVkLlxuICAgKi9cbiAgcHJlbG9hZGVkRXZlbnRzQ29tcGxldGU/OiBib29sZWFuO1xuICAvKipcbiAgICogVGhlIGBldmVudHMubGlzdGAgY3Vyc29yIHBvc2l0aW9uZWQgYWZ0ZXIgdGhlIGxhc3Qgb2YgYHByZWxvYWRlZEV2ZW50c2AsXG4gICAqIHdoZW4gdGhlIGNhbGxlciBoYXMgb25lLiBMZXRzIHRoaXMgaW52b2NhdGlvbiByZWFkIGluY3JlbWVudGFsbHkgZnJvbVxuICAgKiB3aGVyZSB0aGUgcHJlbG9hZCBlbmRlZCBhbmQgYXNrIGZvciBhbiBpbmxpbmUgZGVsdGEgYWdhaW5zdCBpdC4gV2l0aG91dFxuICAgKiBpdCB0aGUgZmlyc3QgcmVhZCBhZnRlciB0aGUgcHJlbG9hZCBzdGFydHMgZnJvbSB0aGUgdG9wIG9mIHRoZSBsb2cuXG4gICAqL1xuICBwcmVsb2FkZWRDdXJzb3I/OiBzdHJpbmcgfCBudWxsO1xuICAvKipcbiAgICogUnVuIGlucHV0IGNhcnJpZWQgdGhyb3VnaCB0aGUgcXVldWUgbWVzc2FnZSBvbiBmaXJzdCBkZWxpdmVyeS4gVXNlZFxuICAgKiBhcyBhIGxhc3QtcmVzb3J0IGZhbGxiYWNrIGZvciBgcnVuX2NyZWF0ZWQuZXZlbnREYXRhLmlucHV0YCB3aGVuXG4gICAqIHRoZSBldmVudCBsb2cgaXMgaW5jb21wbGV0ZS5cbiAgICovXG4gIHJ1bklucHV0PzogUnVuSW5wdXQ7XG4gIC8qKlxuICAgKiBUaGUgcGFyZW50IE9UZWwgc3BhbiAodGhlIG91dGVyIGBXT1JLRkxPVyB7d29ya2Zsb3dOYW1lfWAgc3BhbiBmcm9tXG4gICAqIGBydW50aW1lLnRzYCkuIFdoZW4gc3VwcGxpZWQsIFZNIGxpZmVjeWNsZSBhdHRyaWJ1dGVzIGFyZSBhdHRhY2hlZFxuICAgKiB0byBpdCBmb3IgZW5kLXRvLWVuZCB2aXNpYmlsaXR5LlxuICAgKi9cbiAgcGFyZW50U3Bhbj86IFNwYW47XG4gIC8qKlxuICAgKiBTZXJ2ZXItc3VwcGxpZWQgcGVyLXJ1biBldmVudCBjZWlsaW5nIGZyb20gdGhlIHJ1bl9zdGFydGVkIHJlc3BvbnNlXG4gICAqICh1bmRlZmluZWQg4oeSIG5vIGVuZm9yY2VtZW50KS4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUncyBndWFyZDpcbiAgICogYSBydW5hd2F5IHJ1biBpcyBmYWlsZWQgb25jZSBpdHMgbG9nIHJlYWNoZXMgdGhlIGNlaWxpbmcuIFRoZSB0aHJvd1xuICAgKiBwcm9wYWdhdGVzIHRvIHRoZSByZXBsYXkgbG9vcCdzIGNhdGNoIGluIHJ1bnRpbWUudHMgKHRoZSBRdWlja0pTXG4gICAqIGRpc3BhdGNoIHJ1bnMgaW5zaWRlIHRoYXQgbG9vcCdzIHRyeSksIHdoaWNoIGNsYXNzaWZpZXMgaXQgYW5kXG4gICAqIHJlY29yZHMgcnVuX2ZhaWxlZCB3aXRoIE1BWF9FVkVOVFNfRVhDRUVERUQuXG4gICAqL1xuICBtYXhFdmVudHNMaW1pdD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFF1ZXVlIGRlbGl2ZXJ5IGF0dGVtcHQgb2YgdGhlIG1lc3NhZ2UgZHJpdmluZyB0aGlzIGludm9jYXRpb24gKGZyb21cbiAgICogdGhlIHF1ZXVlIGhhbmRsZXIncyBtZXRhZGF0YTsgMSA9IGZpcnN0IGRlbGl2ZXJ5KS4gU3VyZmFjZWQgaW5cbiAgICogZGlhZ25vc3RpY3M7IGNyYXNoIHJlY292ZXJ5IGl0c2VsZiBpcyBkcml2ZW4gYnkgdGhlIG93bmVyc2hpcC1sZWFzZVxuICAgKiBkZWNpc2lvbiB0YWJsZSBpbiB0aGUgbG9vcCwgbm90IGJ5IHRoZSBhdHRlbXB0IGNvdW50LlxuICAgKi9cbiAgZGVsaXZlcnlBdHRlbXB0PzogbnVtYmVyO1xuICAvKipcbiAgICogUXVldWUgbWVzc2FnZSBJRCBvZiB0aGUgZGVsaXZlcnkgZHJpdmluZyB0aGlzIGludm9jYXRpb24sIHN0YW1wZWQgYXNcbiAgICogYG93bmVyTWVzc2FnZUlkYCBvbiBpbmxpbmUgbGF6eSBzdGVwIGNsYWltcyBzbyB3YWtlIHJlcGxheXMgZGVmZXIgdG9cbiAgICogdGhlIGluLWZsaWdodCBib2R5IGluc3RlYWQgb2YgcmVxdWV1ZWluZyB0aGUgc3RlcC5cbiAgICovXG4gIG93bmVyTWVzc2FnZUlkPzogc3RyaW5nO1xuICAvKiogUmVxdWVzdCBJRCBvZiB0aGUgcXVldWUgaW52b2NhdGlvbiwgd2hlbiB0aGUgcXVldWUgcHJvdmlkZXMgb25lLiAqL1xuICByZXF1ZXN0SWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBRdWV1ZSBuYW1lc3BhY2UgcmVzb2x2ZWQgYXQgcm91dGUgcmVnaXN0cmF0aW9uIChydW50aW1lLnRzKS4gTXVzdCBiZVxuICAgKiB0aHJlYWRlZCBpbnRvIGV2ZXJ5IG1lc3NhZ2UgcHVibGlzaDogdGhlIGJ1aWxkZXJzIGJha2UgdGhlIG5hbWVzcGFjZVxuICAgKiBpbnRvIGdlbmVyYXRlZCByb3V0ZXMsIHNvIGNvbnN1bWVycyBsaXN0ZW4gb24gYF9fPG5zPl93a2Zfd29ya2Zsb3dfKmAuXG4gICAqIEEgcHVibGlzaCB3aXRob3V0IGl0IGxhbmRzIG9uIGBfX3drZl93b3JrZmxvd18qYCBhbmQgaXMgbmV2ZXJcbiAgICogcGlja2VkIHVwLlxuICAgKi9cbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICAvKipcbiAgICogUnVuLW9yaWdpbiB0cmFjZSBjYXJyaWVyIGFjY2Vzc29yIGZyb20gcnVudGltZS50c1xuICAgKiAoZ2V0TmV4dFRyYWNlQ2FycmllcikuIEluIHRoZSBkZWZhdWx0IGBsaW5rZWRgIHRyYWNlIG1vZGUgZXZlcnlcbiAgICogaW52b2NhdGlvbiBtdXN0IGxpbmsgYmFjayB0byB0aGUgcnVuJ3Mgb3JpZ2luICh3b3JrZmxvdy5zdGFydCkgaW4gYVxuICAgKiBzdGFyOyBjYXB0dXJpbmcgdGhlIGN1cnJlbnQgaW52b2NhdGlvbiBjb250ZXh0IGluc3RlYWQgd291bGQgY2hhaW5cbiAgICogaW52b2NhdGlvbnMgdG8gZWFjaCBvdGhlciBhbmQgZnJhZ21lbnQgdGhlIHJ1biB2aWV3IG9uIGFzeW5jIHF1ZXVlcy5cbiAgICovXG4gIG5leHRUcmFjZUNhcnJpZXI/OiAoKSA9PiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+O1xuICAvKipcbiAgICogVGhlIHdhaXQgdGhpcyBpbnZvY2F0aW9uIGlzIHRoZSBkZWxheWVkIGNvbnRpbnVhdGlvbiBmb3IsIGlmIGl0IGlzIG9uZVxuICAgKiAoYFdvcmtmbG93SW52b2tlUGF5bG9hZC53YWl0Q29udGludWF0aW9uYCkuIFJlYWQgb25seSB0byBkZWNpZGUgdGhlIG5leHRcbiAgICogY29udGludWF0aW9uJ3MgaWRlbXBvdGVuY3kga2V5OiBhIGNvbnRpbnVhdGlvbiB0aGF0IGZpbmRzIGl0cyBvd24gd2FpdFxuICAgKiBzdGlsbCBwZW5kaW5nIGhhcyBzcGVudCBpdHMga2V5LCBzbyB0aGUgcmUtYXJtIGhhcyB0byBhZHZhbmNlIHRoZSBhdHRlbXB0XG4gICAqIG9yIHRoZSB3b3JsZCdzIGRlZHVwZSB3aW5kb3cgZHJvcHMgaXQgYW5kIHRoZSB3YWl0IGxvc2VzIGl0cyBvbmx5IHRpbWVyLlxuICAgKi9cbiAgd2FpdENvbnRpbnVhdGlvbj86IHsgY29ycmVsYXRpb25JZDogc3RyaW5nOyBhdHRlbXB0OiBudW1iZXIgfTtcbn0pOiBQcm9taXNlPHsgdGltZW91dFNlY29uZHM/OiBudW1iZXIgfSB8IHZvaWQ+IHtcbiAgY29uc3Qge1xuICAgIHdvcmtmbG93Q29kZSxcbiAgICB3b3JrZmxvd05hbWUsXG4gICAgd29ya2Zsb3dSdW4sXG4gICAgcHJlbG9hZGVkRXZlbnRzLFxuICAgIHByZWxvYWRlZEV2ZW50c0NvbXBsZXRlLFxuICAgIHByZWxvYWRlZEN1cnNvcixcbiAgICBydW5JbnB1dCxcbiAgICBwYXJlbnRTcGFuLFxuICAgIG1heEV2ZW50c0xpbWl0LFxuICAgIGRlbGl2ZXJ5QXR0ZW1wdCxcbiAgICBvd25lck1lc3NhZ2VJZCxcbiAgICByZXF1ZXN0SWQsXG4gICAgbmFtZXNwYWNlLFxuICAgIHdhaXRDb250aW51YXRpb24sXG4gIH0gPSBwYXJhbXM7XG5cbiAgLyoqXG4gICAqIEF0dGVtcHQgbnVtYmVyIGZvciB0aGUgY29udGludWF0aW9uIHRoaXMgaW52b2NhdGlvbiBpcyBhYm91dCB0byBhcm0gZm9yXG4gICAqIGBjb3JyZWxhdGlvbklkYC4gT25lIGhpZ2hlciB0aGFuIHRoZSBpbmNvbWluZyBjb250aW51YXRpb24ncyB3aGVuIHRoaXNcbiAgICogaW52b2NhdGlvbiBJUyB0aGF0IGNvbnRpbnVhdGlvbiBhbmQgdGhlIHdhaXQgaXMgc3RpbGwgcGVuZGluZyDigJQgdGhlIG9ubHlcbiAgICogc2l0dWF0aW9uIGluIHdoaWNoIHRoZSBwcmV2aW91cyBrZXkgaXMgc3BlbnQuIEV2ZXJ5IG90aGVyIGNhbGxlciwgYW5kXG4gICAqIGV2ZXJ5IG90aGVyIHdhaXQsIHN0YXJ0cyBhdCAwIGFuZCBrZXlzIGV4YWN0bHkgYXMgaXQgZGlkIGJlZm9yZSBhdHRlbXB0c1xuICAgKiBleGlzdGVkLlxuICAgKi9cbiAgY29uc3QgbmV4dFdhaXRDb250aW51YXRpb25BdHRlbXB0ID0gKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IG51bWJlciA9PlxuICAgIHdhaXRDb250aW51YXRpb24/LmNvcnJlbGF0aW9uSWQgPT09IGNvcnJlbGF0aW9uSWRcbiAgICAgID8gd2FpdENvbnRpbnVhdGlvbi5hdHRlbXB0ICsgMVxuICAgICAgOiAwO1xuICAvLyBTdGFuZGFsb25lLWNhbGxlciBmYWxsYmFjayAodGVzdHMpOiB3aXRob3V0IGEgcnVudGltZS50cyBjYXJyaWVyXG4gIC8vIGFjY2Vzc29yLCBmYWxsIGJhY2sgdG8gdGhlIGN1cnJlbnQgaW52b2NhdGlvbiBjb250ZXh0LlxuICBjb25zdCBuZXh0VHJhY2VDYXJyaWVyID1cbiAgICBwYXJhbXMubmV4dFRyYWNlQ2FycmllciA/PyAoKCkgPT4gc2VyaWFsaXplVHJhY2VDYXJyaWVyKCkpO1xuICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkKCk7XG4gIGNvbnN0IHJ1bklkID0gd29ya2Zsb3dSdW4ucnVuSWQ7XG4gIGNvbnN0IGludm9jYXRpb25TdGFydCA9IHRpY2soKTtcblxuICAvLyBTdHJpcCB0aGUgaW5saW5lIHNvdXJjZSBtYXAgY29tbWVudCBiZWZvcmUgZXZhbHVhdGluZyB0aGUgYnVuZGxlIGluXG4gIC8vIHRoZSBRdWlja0pTIFZNLiBUaGUgbWFwIGlzIHB1cmVseSBob3N0LXNpZGUgbWV0YWRhdGEgZm9yXG4gIC8vIGByZW1hcEVycm9yU3RhY2tgIChjYWxsZWQgYmVsb3cgb24gd29ya2Zsb3cgZmFpbHVyZXMsIGFnYWluc3QgdGhlXG4gIC8vIE9SSUdJTkFMIGB3b3JrZmxvd0NvZGVgKS4gUXVpY2tKUyByZXRhaW5zIHNvdXJjZSB0ZXh0IGZvclxuICAvLyBzdGFjay10cmFjZSBsaW5lIGxvb2t1cHMsIHNvIHRoZSBmZXctTUIgYmFzZTY0IGNvbW1lbnQgd291bGQgYmxvYXRcbiAgLy8gdGhlIFZNIGhlYXAgZm9yIG5vIGJlbmVmaXQuXG4gIGNvbnN0IHdvcmtmbG93Q29kZUZvclZNID0gc3RyaXBJbmxpbmVTb3VyY2VNYXAod29ya2Zsb3dDb2RlKTtcblxuICAvLyBQZXItaW52b2NhdGlvbiBkaWFnbm9zdGljIGlkIHNvIGRlYnVnIGxvZ3MgY2FuIGJlIGNvcnJlbGF0ZWQgZXZlbiBpZlxuICAvLyB0aGUgc2FtZSBydW5JZCBpcyBwcm9jZXNzZWQgYnkgb3ZlcmxhcHBpbmcgaW52b2NhdGlvbnMgb24gZGlmZmVyZW50XG4gIC8vIGZ1bmN0aW9uIGluc3RhbmNlcy5cbiAgY29uc3QgaW52b2NhdGlvbklkID0gYGludl8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDEwKX1gO1xuXG4gIC8vIFN0cnVjdHVyZWQgcGVyLWNoZWNrcG9pbnQgZGlhZ25vc3RpYyBoZWxwZXIsIGdyZXAtZnJpZW5kbHkgYnkgcnVuSWQuXG4gIGNvbnN0IHdmZGlhZyA9IChjaGVja3BvaW50OiBzdHJpbmcsIGZpZWxkczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHtcbiAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRVUlDS0pTX1ZNX0RJQUcnLCB7XG4gICAgICBjaGVja3BvaW50LFxuICAgICAgcnVuSWQsXG4gICAgICBpbnZvY2F0aW9uSWQsXG4gICAgICB0RWxhcHNlZE1zOiBNYXRoLnJvdW5kKHRpY2soKSAtIGludm9jYXRpb25TdGFydCksXG4gICAgICAuLi5maWVsZHMsXG4gICAgfSk7XG4gIH07XG5cbiAgcGFyZW50U3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93Vm0oJ3F1aWNranMnKSxcbiAgfSk7XG5cbiAgd2ZkaWFnKCdlbnRlcicsIHtcbiAgICB3b3JrZmxvd05hbWUsXG4gICAgZGVsaXZlcnlBdHRlbXB0LFxuICAgIGhhc1ByZWxvYWRlZEV2ZW50czpcbiAgICAgIEFycmF5LmlzQXJyYXkocHJlbG9hZGVkRXZlbnRzKSAmJiBwcmVsb2FkZWRFdmVudHMubGVuZ3RoID4gMCxcbiAgICBwcmVsb2FkZWRFdmVudENvdW50OiBwcmVsb2FkZWRFdmVudHM/Lmxlbmd0aCA/PyAwLFxuICAgIGhhc1J1bklucHV0OiAhIXJ1bklucHV0LFxuICB9KTtcblxuICAvLyBUaGUgd29ya2Zsb3dOYW1lIGZyb20gdGhlIHF1ZXVlIHRvcGljIGlzIGFscmVhZHkgdGhlIGZ1bGwgd29ya2Zsb3cgSURcbiAgLy8gKGUuZy4gXCJ3b3JrZmxvdy8vLi93b3JrZmxvd3MvMV9zaW1wbGUvL3NpbXBsZVwiKVxuICBjb25zdCB3b3JrZmxvd0lkID0gd29ya2Zsb3dOYW1lO1xuXG4gIC8vIFJlc29sdmUgdGhlIGVuY3J5cHRpb24ga2V5IHVwIGZyb250OiBuZWVkZWQgdG8gZGVjcnlwdCBldmVudFxuICAvLyBwYXlsb2FkcyBpbnNpZGUgdGhlIFZNIGFuZCB0byBlbmNyeXB0IGV2ZW50IHBheWxvYWRzIHdyaXR0ZW4gYmVsb3cuXG4gIC8vIFJlc29sdmUgdGhlIEZVTEwgY2FwYWJpbGl0eSAoc3ltbWV0cmljIEFFUyBrZXkgKyBYMjU1MTkga2V5cGFpciksIG5vdFxuICAvLyBqdXN0IGBpbXBvcnRLZXkocmF3S2V5KWA6IGEgcnVuIHJlYWRpbmcgaXRzIG93biBldmVudCBsb2cgY2FuIGVuY291bnRlclxuICAvLyBzZWFsZWQgKGBlbmNwYCkgaG9vayBwYXlsb2FkcyB0aGF0IGEgY3Jvc3MtZGVwbG95bWVudCBgcmVzdW1lSG9vaygpYFxuICAvLyB3cm90ZSB0byBpdCAoc2VhbGluZyBpcyBwcmVzZW5jZS1nYXRlZCBvbiB0aGUgcnVuJ3MgcHVibGlzaGVkXG4gIC8vIGVuY3J5cHRpb25QdWJsaWNLZXksIHdoaWNoIHRoZSBzaGFyZWQgc3RhcnQoKSBwYXRoIHN0YW1wcyByZWdhcmRsZXNzIG9mXG4gIC8vIGVuZ2luZSkuIEEgYmFyZSBzeW1tZXRyaWMga2V5IGNhbm5vdCBvcGVuIHRob3NlIGFuZCB3b3VsZCB3ZWRnZSB0aGUgcnVuXG4gIC8vIHJpZ2h0IGFmdGVyIGhvb2tfcmVjZWl2ZWQuIFRoZSBub2RlOnZtIGVuZ2luZSByZXNvbHZlcyB0aGUgc2FtZSBmdWxsXG4gIC8vIGNhcGFiaWxpdHkgdmlhIG1lbW9pemVFbmNyeXB0aW9uS2V5LlxuICBjb25zdCByYXdLZXkgPSBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4od29ya2Zsb3dSdW4pO1xuICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gcmF3S2V5ID8gYXdhaXQgZGVyaXZlUnVuUGF5bG9hZEtleXMocmF3S2V5KSA6IHVuZGVmaW5lZDtcblxuICAvLyBMb2FkIHRoZSBGVUxMIGV2ZW50IGxvZyBmb3IgdGhlIHJ1bi4gT24gZmlyc3QgaW52b2NhdGlvbiB0aGVcbiAgLy8gcHJlbG9hZGVkIGV2ZW50cyBmcm9tIHRoZSBydW5fc3RhcnRlZCByZXNwb25zZSBhcmUgdGhlIGNvbXBsZXRlIGxvZ1xuICAvLyBhbmQgc2F2ZSB0aGUgZXZlbnRzLmxpc3Qgcm91bmQtdHJpcHM7IGEgY2FsbGVyLWF0dGVzdGVkIGNvbXBsZXRlXG4gIC8vIHByZWxvYWQgKGxhenkgaG9vayBmYXN0IHBhdGgpIGlzIHRydXN0ZWQgdGhlIHNhbWUgd2F5LlxuICBsZXQgZXZlbnRzOiBFdmVudFtdO1xuICBsZXQgZXZlbnRzRmV0Y2hlZFBhZ2VzID0gMDtcbiAgLy8gV2hlcmUgdGhlIGxvZyB3YXMgcmVhZCB0bzogdGhlIGN1cnNvciBhZnRlciB0aGUgbGFzdCBwYWdlIGJlbG93LCBvciB0aGVcbiAgLy8gb25lIHRoZSBjYWxsZXIgcmVhZCB0aGUgcHJlbG9hZCB0by4gU2VlZHMgdGhlIGluY3JlbWVudGFsIHJlYWRzIGFuZCB0aGVcbiAgLy8gaW5saW5lLWRlbHRhIHJlcXVlc3RzIHRoYXQgZm9sbG93LlxuICBsZXQgbG9hZGVkQ3Vyc29yOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgY29uc3QgdXNlUHJlbG9hZGVkID1cbiAgICAocHJlbG9hZGVkRXZlbnRzQ29tcGxldGUgPT09IHRydWUgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkocHJlbG9hZGVkRXZlbnRzKSAmJlxuICAgICAgcHJlbG9hZGVkRXZlbnRzLmxlbmd0aCA+IDApIHx8XG4gICAgaXNGaXJzdEludm9jYXRpb24ocHJlbG9hZGVkRXZlbnRzKTtcbiAgaWYgKHVzZVByZWxvYWRlZCAmJiBwcmVsb2FkZWRFdmVudHMpIHtcbiAgICBldmVudHMgPSBwcmVsb2FkZWRFdmVudHM7XG4gICAgbG9hZGVkQ3Vyc29yID0gcHJlbG9hZGVkQ3Vyc29yID8/IG51bGw7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgYWxsRXZlbnRzOiBFdmVudFtdID0gW107XG4gICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gICAgbGV0IGhhc01vcmUgPSB0cnVlO1xuXG4gICAgd2hpbGUgKGhhc01vcmUpIHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgd29ybGQuZXZlbnRzLmxpc3Qoe1xuICAgICAgICBydW5JZCxcbiAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgIHNvcnRPcmRlcjogJ2FzYycsXG4gICAgICAgICAgY3Vyc29yOiBjdXJzb3IgPz8gdW5kZWZpbmVkLFxuICAgICAgICAgIGxpbWl0OiAxMDAwLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBldmVudHNGZXRjaGVkUGFnZXMrKztcbiAgICAgIGFsbEV2ZW50cy5wdXNoKC4uLnJlc3BvbnNlLmRhdGEpO1xuICAgICAgLy8gVXBkYXRlIHRoZSBjdXJzb3IgdG8gdGhlIGxhc3Qgc3VjY2Vzc2Z1bGx5IGZldGNoZWQgcGFnZSdzIGN1cnNvci5cbiAgICAgIC8vIE9ubHkgdXBkYXRlIHdoZW4gd2UgZ290IHJlc3VsdHM6IHRoZSBmaW5hbCBlbXB0eS1wYWdlIHJlc3BvbnNlXG4gICAgICAvLyByZXR1cm5zIGN1cnNvcj1udWxsIHdoaWNoIHdlIG11c3QgTk9UIHVzZSAoaXQgd291bGQgcmVzZXQgdGhlIGN1cnNvcikuXG4gICAgICBpZiAocmVzcG9uc2UuY3Vyc29yKSB7XG4gICAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvcjtcbiAgICAgIH1cbiAgICAgIGhhc01vcmUgPSByZXNwb25zZS5kYXRhLmxlbmd0aCA+IDAgJiYgcmVzcG9uc2UuY3Vyc29yICE9IG51bGw7XG4gICAgfVxuXG4gICAgZXZlbnRzID0gYWxsRXZlbnRzO1xuICAgIGxvYWRlZEN1cnNvciA9IGN1cnNvcjtcbiAgfVxuXG4gIC8vIFRoaXMgaW52b2NhdGlvbidzIHZpZXcgb2YgdGhlIGxvZywgYW5kIHRoZSBxdWV1ZSBvZiBldmVudHMgYSBXb3JsZCBoYXNcbiAgLy8gaGFuZGVkIGJhY2sgb24gYSB3cml0ZSB0aGF0IHRoZSBWTSBoYXMgbm90IGJlZW4gZ2l2ZW4geWV0LiBFdmVyeSB3cml0ZVxuICAvLyBtYWRlIGZyb20gdGhpcyB2aWV3IGdvZXMgdGhyb3VnaCBgY3JlYXRlRXZlbnRgIGJlbG93IHNvIGl0IG5hbWVzIHRoZVxuICAvLyBwb3NpdGlvbiBpdCB3YXMgZGVjaWRlZCBhZ2FpbnN0IGFuZCBpdHMgcmVzcG9uc2UgaXMgcXVldWVkIGhlcmUuXG4gIGNvbnN0IGxvZ1ZpZXcgPSBuZXcgUXVpY2tKU0xvZ1ZpZXcoZXZlbnRzLCBsb2FkZWRDdXJzb3IpO1xuICBjb25zdCBjcmVhdGVFdmVudDogRXZlbnRDcmVhdG9yID0gYXN5bmMgKGRhdGEsIGV2ZW50UGFyYW1zKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShydW5JZCwgZGF0YSwge1xuICAgICAgLi4uZXZlbnRQYXJhbXMsXG4gICAgICAuLi5sb2dWaWV3LnNuYXBzaG90UGFyYW1zKCksXG4gICAgfSk7XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIGV2ZW50UGFyYW1zPy5zaW5jZUN1cnNvciA9PT0gJ3N0cmluZycgJiZcbiAgICAgIHJlc3VsdC5ldmVudHMgIT09IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgLy8gVGhlIHdyaXRlIGFza2VkIGZvciB0aGUgaW5saW5lIGRlbHRhIGFuZCBnb3Qgb25lOiBldmVyeXRoaW5nIGFmdGVyXG4gICAgICAvLyB0aGUgY3Vyc29yLCB0aGlzIHdyaXRlIGluY2x1ZGVkLCByZWFkIHdpdGggcmVmcyByZXNvbHZlZC4gVGFrZW5cbiAgICAgIC8vIHRocm91Z2ggdGhlIGRlbHRhIHBhdGggc28gdGhlIGN1cnNvciBtb3ZlcyB3aXRoIGl0IHdoZW4gdGhhdCBpc1xuICAgICAgLy8gc2FmZTsgdGhlIGNyZWF0ZWQgZXZlbnQncyBwb3NpdGlvbiBpcyBub3RlZCBlaXRoZXIgd2F5LlxuICAgICAgbG9nVmlldy5hYnNvcmIoeyBldmVudDogcmVzdWx0LmV2ZW50IH0pO1xuICAgICAgY29uc3QgYWR2YW5jZWQgPSBsb2dWaWV3LmFic29yYkRlbHRhKGV2ZW50UGFyYW1zLnNpbmNlQ3Vyc29yLCB7XG4gICAgICAgIGV2ZW50czogcmVzdWx0LmV2ZW50cyxcbiAgICAgICAgY3Vyc29yOiByZXN1bHQuY3Vyc29yID8/IG51bGwsXG4gICAgICAgIGhhc01vcmU6IHJlc3VsdC5oYXNNb3JlID8/IGZhbHNlLFxuICAgICAgfSk7XG4gICAgICB3ZmRpYWcoJ2lubGluZV9kZWx0YV9hYnNvcmJlZCcsIHtcbiAgICAgICAgZXZlbnRUeXBlOiBkYXRhLmV2ZW50VHlwZSxcbiAgICAgICAgZXZlbnRzOiByZXN1bHQuZXZlbnRzLmxlbmd0aCxcbiAgICAgICAgaGFzTW9yZTogcmVzdWx0Lmhhc01vcmUgPz8gZmFsc2UsXG4gICAgICAgIGN1cnNvckFkdmFuY2VkOiBhZHZhbmNlZCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgLy8gVGhlIGNyZWF0ZWQgZXZlbnQgaXMgZGVsaXZlcmVkIG9mZiB0aGUgcmVzcG9uc2Ugb25seSB3aGVuIGl0IGNhcnJpZXNcbiAgICAvLyBubyBwYXlsb2FkIGEgVk0gcmVhZHM7IGV2ZXJ5IG90aGVyIHR5cGUgd2FpdHMgZm9yIGEgcGFnZSBvciBhIGxpc3RpbmcsXG4gICAgLy8gd2hpY2ggcmV0dXJuIGl0IHdpdGggaXRzIHJlZnMgcmVzb2x2ZWQuIFNlZSBRdWlja0pTTG9nVmlldy5cbiAgICBjb25zdCBhYnNvcmJlZCA9IGxvZ1ZpZXcuYWJzb3JiKHJlc3VsdCwge1xuICAgICAgZGVsaXZlckV2ZW50OiBkYXRhLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY29tcGxldGVkJyxcbiAgICB9KTtcbiAgICBpZiAoYWJzb3JiZWQudHJ1bmNhdGVkKSB7XG4gICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKFxuICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBkcm9wcGVkIGEgdHJ1bmNhdGVkIHNraXBwZWQtc2xvdCByZXBvcnQnLFxuICAgICAgICB7XG4gICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgZXZlbnRUeXBlOiBkYXRhLmV2ZW50VHlwZSxcbiAgICAgICAgICBldmVudElkOiByZXN1bHQuZXZlbnQ/LmV2ZW50SWQsXG4gICAgICAgICAgb2ZmZXJlZDogcmVzdWx0LmV2ZW50cz8ubGVuZ3RoID8/IDAsXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG4gIC8qKlxuICAgKiBUaGUgY3JlYXRlIGZvciB3cml0ZXMgdGhhdCBlbmQgdGhlIHJ1biAoYHJ1bl9jb21wbGV0ZWRgLCBgcnVuX2ZhaWxlZGAsXG4gICAqIGFuZCB0aGUgdGVybWluYWwgZHJhaW4gb2YgbGVmdG92ZXIgb3BzKTogbm8gcG9zaXRpb24gbmFtZWQgYW5kIG5vIHBhZ2VcbiAgICogYXNrZWQgZm9yLCBiZWNhdXNlIG5vdGhpbmcgcmVwbGF5cyBhIGZpbmlzaGVkIHJ1bidzIGxvZy4gVGhlIG5vZGVcbiAgICogZW5naW5lJ3MgYGRlbHRhUmVxdWVzdEN1cnNvcmAgbWFrZXMgdGhlIHNhbWUgZXhjbHVzaW9uIGZvciBgc2luY2VDdXJzb3JgLlxuICAgKi9cbiAgY29uc3QgdGVybWluYWxDcmVhdGVFdmVudDogRXZlbnRDcmVhdG9yID0gKGRhdGEsIGV2ZW50UGFyYW1zKSA9PlxuICAgIHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIGRhdGEsIGV2ZW50UGFyYW1zKTtcblxuICAvLyBFdmVudC1saW1pdCBndWFyZDogZmFpbCBhIHJ1bmF3YXkgcnVuIG9uY2UgaXRzIGxvZyByZWFjaGVzIHRoZVxuICAvLyBzZXJ2ZXItc3VwcGxpZWQgY2VpbGluZywgdGhlIHNhbWUgZW5mb3JjZW1lbnQgcG9pbnQgYXMgdGhlIG5vZGU6dm1cbiAgLy8gZW5naW5lJ3MgcmVwbGF5IGxvb3AuXG4gIGlmIChtYXhFdmVudHNMaW1pdCAhPT0gdW5kZWZpbmVkICYmIGV2ZW50cy5sZW5ndGggPj0gbWF4RXZlbnRzTGltaXQpIHtcbiAgICB0aHJvdyBuZXcgTWF4RXZlbnRzRXhjZWVkZWRFcnJvcihldmVudHMubGVuZ3RoLCBtYXhFdmVudHNMaW1pdCk7XG4gIH1cblxuICBwYXJlbnRTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU0V2ZW50c1ByZWxvYWRlZCh1c2VQcmVsb2FkZWQpLFxuICAgIC4uLkF0dHJpYnV0ZS5RdWlja0pTRXZlbnRzRmV0Y2hlZENvdW50KGV2ZW50cy5sZW5ndGgpLFxuICAgIC4uLkF0dHJpYnV0ZS5RdWlja0pTRXZlbnRzRmV0Y2hlZFBhZ2VzKGV2ZW50c0ZldGNoZWRQYWdlcyksXG4gIH0pO1xuXG4gIHdmZGlhZygnZXZlbnRzX2ZldGNoZWQnLCB7XG4gICAgZXZlbnRDb3VudDogZXZlbnRzLmxlbmd0aCxcbiAgICBldmVudHNGZXRjaGVkUGFnZXMsXG4gICAgdXNlUHJlbG9hZGVkLFxuICAgIGV2ZW50VHlwZXM6IGV2ZW50cy5yZWR1Y2U8UmVjb3JkPHN0cmluZywgbnVtYmVyPj4oKGFjYywgZSkgPT4ge1xuICAgICAgYWNjW2UuZXZlbnRUeXBlXSA9IChhY2NbZS5ldmVudFR5cGVdID8/IDApICsgMTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pLFxuICB9KTtcblxuICAvLyBDaGVjayBmb3IgZWxhcHNlZCB3YWl0c1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBjb25zdCBjb21wbGV0ZWRXYWl0SWRzID0gbmV3IFNldChcbiAgICBldmVudHNcbiAgICAgIC5maWx0ZXIoKGUpID0+IGUuZXZlbnRUeXBlID09PSAnd2FpdF9jb21wbGV0ZWQnKVxuICAgICAgLm1hcCgoZSkgPT4gZS5jb3JyZWxhdGlvbklkKVxuICApO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGlmIChcbiAgICAgIGV2ZW50LmV2ZW50VHlwZSA9PT0gJ3dhaXRfY3JlYXRlZCcgJiZcbiAgICAgIGV2ZW50LmNvcnJlbGF0aW9uSWQgJiZcbiAgICAgICFjb21wbGV0ZWRXYWl0SWRzLmhhcyhldmVudC5jb3JyZWxhdGlvbklkKVxuICAgICkge1xuICAgICAgY29uc3QgZXZlbnREYXRhID1cbiAgICAgICAgJ2V2ZW50RGF0YScgaW4gZXZlbnRcbiAgICAgICAgICA/IChldmVudC5ldmVudERhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICBjb25zdCByZXN1bWVBdCA9IGV2ZW50RGF0YT8ucmVzdW1lQXQ7XG4gICAgICBpZiAocmVzdW1lQXQgJiYgbm93ID49IG5ldyBEYXRlKHJlc3VtZUF0IGFzIHN0cmluZykuZ2V0VGltZSgpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY3JlYXRlRXZlbnQoe1xuICAgICAgICAgICAgZXZlbnRUeXBlOiAnd2FpdF9jb21wbGV0ZWQnLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogZXZlbnQuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoIWxvZ1ZpZXcudHJhY2tpbmcgJiYgcmVzdWx0LmV2ZW50KSB7XG4gICAgICAgICAgICAvLyBObyBwb3NpdGlvbnMgdG8gb3JkZXIgYnkgKHNlZSBRdWlja0pTTG9nVmlldyksIHNvIHRoZSBldmVudFxuICAgICAgICAgICAgLy8gam9pbnMgdGhlIGluaXRpYWwgbG9nIGRpcmVjdGx5LCBhcyBpdCBhbHdheXMgaGFzLlxuICAgICAgICAgICAgZXZlbnRzLnB1c2gocmVzdWx0LmV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIGNvbnRpbnVlO1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICAvLyBUaGUgVk0gaGFzIG5vdCBzdGFydGVkLCBzbyB3aGF0ZXZlciB0aG9zZSB3cml0ZXMgaGFuZGVkIGJhY2sgKGVhY2hcbiAgLy8gd2FpdF9jb21wbGV0ZWQsIHBsdXMgYW55dGhpbmcgYW5vdGhlciB3cml0ZXIgYXBwZW5kZWQgdGhhdCB0aGV5IHNraXBwZWRcbiAgLy8gb3Zlcikgam9pbnMgdGhlIGluaXRpYWwgbG9nIGluc3RlYWQgb2Ygd2FpdGluZyBmb3IgYSBmZWVkLlxuICBldmVudHMucHVzaCguLi5sb2dWaWV3LnRha2VDb250aWd1b3VzKCkpO1xuXG4gIC8vIFJlc29sdmUgdGhlIHdvcmtmbG93IHNlcnZlciBwb3J0IHNvIGBnZXRXb3JrZmxvd01ldGFkYXRhKCkudXJsYCBpbnNpZGVcbiAgLy8gdGhlIFZNIG1hdGNoZXMgd2hhdCB0aGUgc3RlcC1zaWRlIGhhbmRsZXIgcmVwb3J0cy4gU2tpcHBlZCBvbiBWZXJjZWw6XG4gIC8vIHRoZSBWTSByZWFkcyBWRVJDRUxfVVJMIGRpcmVjdGx5IGluIHRoYXQgZW52aXJvbm1lbnQuXG4gIGNvbnN0IGlzVmVyY2VsID0gcHJvY2Vzcy5lbnYuVkVSQ0VMX1VSTCAhPT0gdW5kZWZpbmVkO1xuICBjb25zdCBwb3J0ID0gaXNWZXJjZWwgPyB1bmRlZmluZWQgOiBhd2FpdCBnZXRQb3J0TGF6eSgpO1xuXG4gIC8vIFJ1biB0aGUgd29ya2Zsb3cgaW4gdGhlIFF1aWNrSlMgVk1cbiAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBpbnZva2luZyBWTScsIHtcbiAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICB3b3JrZmxvd0lkLFxuICAgIGV2ZW50Q291bnQ6IGV2ZW50cy5sZW5ndGgsXG4gIH0pO1xuXG4gIGNvbnN0IHNlc3Npb24gPSBhd2FpdCBzdGFydFF1aWNrSlNXb3JrZmxvdyh7XG4gICAgLy8gUGFzcyB0aGUgU1RSSVBQRUQgYnVuZGxlIHRvIHRoZSBWTSBzbyB0aGUgaW5saW5lIHNvdXJjZSBtYXBcbiAgICAvLyBkb2Vzbid0IGVuZCB1cCBpbiB0aGUgUXVpY2tKUyBoZWFwLiBUaGUgb3JpZ2luYWwgKHVuc3RyaXBwZWQpXG4gICAgLy8gYHdvcmtmbG93Q29kZWAgaXMgc3RpbGwga2VwdCBpbiB0aGlzIGhvc3Qtc2lkZSBzY29wZSBhbmQgaXMgdXNlZFxuICAgIC8vIGJ5IGByZW1hcEVycm9yU3RhY2tgIG9uIHdvcmtmbG93IGZhaWx1cmVzIGJlbG93LlxuICAgIHdvcmtmbG93Q29kZTogd29ya2Zsb3dDb2RlRm9yVk0sXG4gICAgd29ya2Zsb3dJZCxcbiAgICB3b3JrZmxvd1J1bixcbiAgICBldmVudHMsXG4gICAgd29ybGRDYXBhYmlsaXRpZXM6IHdvcmxkLmNhcGFiaWxpdGllcyxcbiAgICBlbmNyeXB0aW9uS2V5LFxuICAgIHBvcnQsXG4gICAgcnVuSW5wdXQsXG4gIH0pO1xuICBsZXQgcmVzdWx0ID0gc2Vzc2lvbi5yZXN1bHQ7XG5cbiAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBWTSByZXR1cm5lZCcsIHtcbiAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICBjb21wbGV0ZWQ6ICEhcmVzdWx0LmNvbXBsZXRlZCxcbiAgICBzdXNwZW5kZWQ6ICEhcmVzdWx0LnN1c3BlbmRlZCxcbiAgICBmYWlsZWQ6ICEhcmVzdWx0LmZhaWxlZCxcbiAgICBwZW5kaW5nT3BzQ291bnQ6IHJlc3VsdC5zdXNwZW5kZWQ/LnBlbmRpbmdPcGVyYXRpb25zPy5sZW5ndGgsXG4gIH0pO1xuXG4gIHdmZGlhZygndm1fcmV0dXJuZWQnLCB7XG4gICAgb3V0Y29tZTogcmVzdWx0LmNvbXBsZXRlZFxuICAgICAgPyAnY29tcGxldGVkJ1xuICAgICAgOiByZXN1bHQuc3VzcGVuZGVkXG4gICAgICAgID8gJ3N1c3BlbmRlZCdcbiAgICAgICAgOiByZXN1bHQuZmFpbGVkXG4gICAgICAgICAgPyAnZmFpbGVkJ1xuICAgICAgICAgIDogJ3Vua25vd24nLFxuICAgIHBlbmRpbmdPcHNDb3VudDogcmVzdWx0LnN1c3BlbmRlZD8ucGVuZGluZ09wZXJhdGlvbnM/Lmxlbmd0aCA/PyAwLFxuICAgIHBlbmRpbmdPcFN1bW1hcnk6IHJlc3VsdC5zdXNwZW5kZWQ/LnBlbmRpbmdPcGVyYXRpb25zPy5tYXAoKHApID0+ICh7XG4gICAgICB0eXBlOiBwLnR5cGUsXG4gICAgICBjb3JyZWxhdGlvbklkOiBwLmNvcnJlbGF0aW9uSWQsXG4gICAgICBoYXNDcmVhdGVkRXZlbnQ6IHAuaGFzQ3JlYXRlZEV2ZW50LFxuICAgICAgLi4uKHAudHlwZSA9PT0gJ3N0ZXAnID8geyBzdGVwSWQ6IChwIGFzIFBlbmRpbmdTdGVwKS5zdGVwSWQgfSA6IHt9KSxcbiAgICB9KSksXG4gICAgZmFpbHVyZU1lc3NhZ2U6IHJlc3VsdC5mYWlsZWQ/Lm1lc3NhZ2UsXG4gICAgZmFpbHVyZU5hbWU6IHJlc3VsdC5mYWlsZWQ/Lm5hbWUsXG4gIH0pO1xuXG4gIC8vIC0tLS0gSW5saW5lIGNvbnRpbnVhdGlvbiBsb29wIC0tLS1cbiAgLy9cbiAgLy8gV2hpbGUgdGhlIHdvcmtmbG93IGlzIHN1c3BlbmRlZCwgdGhpcyBsb29wIGtlZXBzIHRoZSBWTSBhbGl2ZSBhbmRcbiAgLy8gbWFrZXMgYXMgbXVjaCBmb3J3YXJkIHByb2dyZXNzIGFzIHBvc3NpYmxlIHdpdGhpbiBvbmUgaW52b2NhdGlvbjpcbiAgLy9cbiAgLy8gICAxLiBEaXNwYXRjaCBkdXJhYmxlIHNpZGUgZWZmZWN0cyBmb3IgdGhlIHN1c3BlbnNpb24ncyBwZW5kaW5nIG9wc1xuICAvLyAgICAgIChzdGVwX2NyZWF0ZWQgLyBob29rX2NyZWF0ZWQgLyBhdHRyX3NldCAvIHdhaXRfY3JlYXRlZCAvXG4gIC8vICAgICAgaG9va19yZWNlaXZlZCBmb3IgYWJvcnRzKSBhbmQgY29tcGxldGUgZWxhcHNlZCB3YWl0cy5cbiAgLy8gICAyLiBGZWVkIGFsbCBuZXdseSByZWNvcmRlZCBldmVudHMgKGF0dHJfc2V0LCBob29rX2NyZWF0ZWQsIGVsYXBzZWRcbiAgLy8gICAgICB3YWl0X2NvbXBsZXRlZCwgdGVybWluYWxzIHdyaXR0ZW4gYnkgY29uY3VycmVudCBpbnZvY2F0aW9ucywgLi4uKVxuICAvLyAgICAgIGludG8gdGhlIExJVkUgVk0gdmlhIHNlc3Npb24uY29udGludWVXaXRoRXZlbnRzLCByZXN1bWluZ1xuICAvLyAgICAgIGV4ZWN1dGlvbiBleGFjdGx5IHdoZXJlIGl0IGxlZnQgb2ZmLCBubyBmcmVzaC1WTSByZS1yZXBsYXkuXG4gIC8vICAgICAgQ2hlYXAgcHJvZ3Jlc3MgaXMgZmVkIEJFRk9SRSBydW5uaW5nIHN0ZXAgYm9kaWVzIHNvIHByb21pc2VcbiAgLy8gICAgICBjaGFpbnMgdGhhdCBhcmUgbm90IGdhdGVkIG9uIHN0ZXBzIChob29rLmdldENvbmZsaWN0KCksXG4gIC8vICAgICAgc2V0QXR0cmlidXRlcygpLCByYWNpbmcgc2xlZXBzKSBhZHZhbmNlIGZpcnN0IGFuZCBjYW4gc3VyZmFjZVxuICAvLyAgICAgIGFkZGl0aW9uYWwgcGVuZGluZyBzdGVwcyBmb3IgdGhlIHNhbWUgaW5saW5lIGJhdGNoLlxuICAvLyAgIDMuIE9uY2Ugbm8gY2hlYXAgcHJvZ3Jlc3MgcmVtYWlucywgZXhlY3V0ZSB1cCB0b1xuICAvLyAgICAgIGdldE1heElubGluZVN0ZXBzKCkgc3RlcHMgY3JlYXRlZCBieSBUSElTIGludm9jYXRpb24gaW5saW5lIChub1xuICAvLyAgICAgIHF1ZXVlIHJvdW5kLXRyaXApLCBpbiBwYXJhbGxlbCwgd2l0aCB0aGUgcmVwbGF5IGJ1ZGdldCBwYXVzZWRcbiAgLy8gICAgICBkdXJpbmcgc3RlcCBib2RpZXMsIG1pcnJvcmluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBpbmxpbmVcbiAgLy8gICAgICByZXBsYXkgbG9vcC4gT3ZlcmZsb3cgYW5kIHJldHJ5L3Rocm90dGxlZCBzdGVwcyBhcmUgcXVldWVkIGZvclxuICAvLyAgICAgIGJhY2tncm91bmQgZXhlY3V0aW9uLiBBIGRlbGF5ZWQgd2FpdC1jb250aW51YXRpb24gbWVzc2FnZSBpc1xuICAvLyAgICAgIGVucXVldWVkIGZvciB0aGUgc29vbmVzdCBwZW5kaW5nIHdhaXQgZmlyc3QsIHNvIHJhY2luZyB0aW1lcnNcbiAgLy8gICAgICBmaXJlIG9uIHRpbWUgKGluIGEgc2VwYXJhdGUgaW52b2NhdGlvbikgd2hpbGUgc3RlcCBib2RpZXMgYmxvY2tcbiAgLy8gICAgICB0aGlzIG9uZS5cbiAgLy9cbiAgLy8gVGhlIGxvb3AgZXhpdHMgd2hlbiB0aGUgd29ya2Zsb3cgc2V0dGxlcywgbm8gZm9yd2FyZCBwcm9ncmVzcyBpc1xuICAvLyBwb3NzaWJsZSBpbi1wcm9jZXNzLCB0aGUgcmVwbGF5IGJ1ZGdldCBpcyBleGhhdXN0ZWQsIG9yIHRoZSBydW4gaXNcbiAgLy8gZ29uZS5cbiAgY29uc3Qgc2VlbkV2ZW50SWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGZvciAoY29uc3QgZSBvZiBldmVudHMpIHtcbiAgICBpZiAoZS5ldmVudElkKSBzZWVuRXZlbnRJZHMuYWRkKGUuZXZlbnRJZCk7XG4gIH1cbiAgLy8gU3RlcCBjaWRzIGFscmVhZHkgZXhlY3V0ZWQgaW5saW5lIGJ5IHRoaXMgaW52b2NhdGlvbi5cbiAgY29uc3QgZXhlY3V0ZWRTdGVwSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIC8vIFN0ZXBzIGZvciB3aGljaCBUSElTIGludm9jYXRpb24gYWxyZWFkeSBzZW50IGEgcXVldWUgbWVzc2FnZS5cbiAgY29uc3QgcXVldWVkU3RlcElkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAvLyBBYm9ydHMgVEhJUyBpbnZvY2F0aW9uIGFscmVhZHkgcmVjb3JkZWQgKGhvb2tfcmVjZWl2ZWQgd3JpdHRlbikuXG4gIC8vIEd1YXJkcyBhZ2FpbnN0IHJlLXJlY29yZGluZyB3aGVuIHRoZSBWTS1zaWRlIGZsYWcgaGFzIG5vdCBiZWVuXG4gIC8vIGNsZWFyZWQgeWV0IHdpdGhpbiB0aGUgc2FtZSBpdGVyYXRpb24uXG4gIGNvbnN0IHJlY29yZGVkQWJvcnRJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgLy8gV2FpdHMgZm9yIHdoaWNoIFRISVMgaW52b2NhdGlvbiBhbHJlYWR5IGNvbXBsZXRlZC9zY2hlZHVsZWQgd29yay5cbiAgY29uc3QgY29tcGxldGVkV2FpdElkczIgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgLy8gSW5saW5lLW93bmVyc2hpcCBzdGF0ZSBwZXIgc3RlcCBjb3JyZWxhdGlvbklkLCBkZXJpdmVkIGZyb20gZXZlcnlcbiAgLy8gZXZlbnQgdGhpcyBpbnZvY2F0aW9uIG9ic2VydmVzIChpbml0aWFsIGxvZyArIGV2ZXJ5IGZlZWQpOiB0aGVcbiAgLy8gcXVpY2tqcyBhbmFsb2cgb2YgdGhlIHJlcGxheS1kZXJpdmVkIG93bmVyc2hpcCBvbiB0aGUgbm9kZSBlbmdpbmUnc1xuICAvLyBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSAoc2VlIHN0ZXAtb3duZXJzaGlwLnRzKS4gTGF0ZXN0LXdpbnM6XG4gIC8vIGV2ZW50cyBhcnJpdmUgaW4gbG9nIG9yZGVyLCBzbyBhIGxhdGVyIHN0ZXBfc3RhcnRlZCBvdmVyd3JpdGVzIHRoZVxuICAvLyBzdGFtcDsgYSBzdGVwX3JldHJ5aW5nIGxhcHNlcyBvd25lcnNoaXAgcGVybWFuZW50bHkgZm9yIHRoZSBpZC5cbiAgY29uc3Qgc3RlcE93bmVyc2hpcCA9IG5ldyBNYXA8XG4gICAgc3RyaW5nLFxuICAgIHsgb3duZXI/OiBzdHJpbmc7IHN0YXJ0ZWRBdE1zPzogbnVtYmVyOyBzYXdSZXRyeWluZzogYm9vbGVhbiB9XG4gID4oKTtcbiAgY29uc3Qgb2JzZXJ2ZUV2ZW50c0Zvck93bmVyc2hpcCA9IChvYnNlcnZlZDogRXZlbnRbXSk6IHZvaWQgPT4ge1xuICAgIGZvciAoY29uc3QgZSBvZiBvYnNlcnZlZCkge1xuICAgICAgaWYgKGUuY29ycmVsYXRpb25JZCA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgIGlmIChlLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfc3RhcnRlZCcpIHtcbiAgICAgICAgY29uc3Qgb3duZXIgPVxuICAgICAgICAgICdldmVudERhdGEnIGluIGUgJiZcbiAgICAgICAgICBlLmV2ZW50RGF0YSAmJlxuICAgICAgICAgICdvd25lck1lc3NhZ2VJZCcgaW4gZS5ldmVudERhdGEgJiZcbiAgICAgICAgICB0eXBlb2YgZS5ldmVudERhdGEub3duZXJNZXNzYWdlSWQgPT09ICdzdHJpbmcnXG4gICAgICAgICAgICA/IGUuZXZlbnREYXRhLm93bmVyTWVzc2FnZUlkXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgcHJpb3IgPSBzdGVwT3duZXJzaGlwLmdldChlLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBzdGVwT3duZXJzaGlwLnNldChlLmNvcnJlbGF0aW9uSWQsIHtcbiAgICAgICAgICBvd25lcixcbiAgICAgICAgICBzdGFydGVkQXRNczogZS5jcmVhdGVkQXQgPyArbmV3IERhdGUoZS5jcmVhdGVkQXQpIDogdW5kZWZpbmVkLFxuICAgICAgICAgIHNhd1JldHJ5aW5nOiBwcmlvcj8uc2F3UmV0cnlpbmcgPz8gZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChlLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfcmV0cnlpbmcnKSB7XG4gICAgICAgIGNvbnN0IHByaW9yID0gc3RlcE93bmVyc2hpcC5nZXQoZS5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgc3RlcE93bmVyc2hpcC5zZXQoZS5jb3JyZWxhdGlvbklkLCB7XG4gICAgICAgICAgLi4uKHByaW9yID8/IHt9KSxcbiAgICAgICAgICBzYXdSZXRyeWluZzogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuICBvYnNlcnZlRXZlbnRzRm9yT3duZXJzaGlwKGV2ZW50cyk7XG4gIGNvbnN0IHNjaGVkdWxlZFdhaXRDb250aW51YXRpb25zID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGNvbnN0IG1heElubGluZVN0ZXBzID0gZ2V0TWF4SW5saW5lU3RlcHMoKTtcbiAgY29uc3QgYnVkZ2V0ID0gbmV3IFJlcGxheUJ1ZGdldCgpO1xuICBjb25zdCB3b3JrZmxvd1N0YXJ0ZWRBdCA9IHdvcmtmbG93UnVuLnN0YXJ0ZWRBdFxuICAgID8gK3dvcmtmbG93UnVuLnN0YXJ0ZWRBdFxuICAgIDogRGF0ZS5ub3coKTtcbiAgY29uc3Qgcm9vdFJ1bklkID1cbiAgICAod29ya2Zsb3dSdW4uYXR0cmlidXRlcyBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHwgdW5kZWZpbmVkKT8uW1xuICAgICAgUk9PVF9SVU5fSURfQVRUUklCVVRFXG4gICAgXSA/PyBydW5JZDtcbiAgbGV0IGlubGluZVN0ZXBzRXhlY3V0ZWQgPSAwO1xuICBsZXQgcnVuR29uZSA9IGZhbHNlO1xuICAvLyBTZXQgd2hlbiB0aGlzIGludm9jYXRpb24gd3JvdGUgYW4gZXZlbnQgdGhlIHdvcmtmbG93IG11c3QgY29uc3VtZSB0b1xuICAvLyBtYWtlIHByb2dyZXNzIChhdHRyX3NldCwgZ2V0Q29uZmxpY3QtYXdhaXRlZCBob29rX2NyZWF0ZWQpIGFuZCB0aGVcbiAgLy8gbG9vcCBoYXMgbm90IHlldCByZWFkIGl0IGJhY2ssIHNpbmNlIGV2ZW50dWFsbHktY29uc2lzdGVudCBsaXN0aW5ncyBjYW5cbiAgLy8gcmV0dXJuIDAgbmV3IGV2ZW50cyByaWdodCBhZnRlciBhIHdyaXRlLiBJZiBpdCBpcyBzdGlsbCBzZXQgd2hlbiB0aGVcbiAgLy8gbG9vcCBleGl0cyBzdXNwZW5kZWQsIHRoZSBlbnRyeXBvaW50IHJlcXVldWVzIGltbWVkaWF0ZWx5IGluc3RlYWQgb2ZcbiAgLy8gZXhpdGluZyBhd2FpdGluZ19leHRlcm5hbCB3aXRoIHRoZSB1bmJsb2NraW5nIGV2ZW50IGFscmVhZHkgd3JpdHRlblxuICAvLyBhbmQgbm90aGluZyBzY2hlZHVsZWQgdG8gcmVhZCBpdC5cbiAgbGV0IHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEZldGNoIGFsbCBldmVudHMgbm90IHlldCBwcm9jZXNzZWQgYnkgdGhlIGxpdmUgVk0gKGxvZyBvcmRlciksIHJlYWRpbmdcbiAgICogZnJvbSB3aGVyZSB0aGUgbG9nIHdhcyBsYXN0IHJlYWQgdG8uIEEgV29ybGQncyBjdXJzb3IgbmV2ZXIgcGFzc2VzIGFcbiAgICogcG9zaXRpb24gd2hvc2Ugd3JpdGVyIGlzIHN0aWxsIGluIGZsaWdodCwgc28gcmVhZGluZyBmb3J3YXJkIGZyb20gaXRcbiAgICogY2Fubm90IHNraXAgYW4gZXZlbnQ7IHRoZSBpZCBzZXQgaXMgd2hhdCBtYWtlcyBhIHJlLXJlYWQgb2YgdGhlIHNhbWVcbiAgICogc3BhbiAoYWZ0ZXIgYSBxdWV1ZWQgcGFnZSBvciBhIGRlbHRhIG1vdmVkIHRoZSB2aWV3IGFoZWFkIG9mIHRoZSBjdXJzb3IpXG4gICAqIGhhcm1sZXNzLlxuICAgKi9cbiAgY29uc3QgZmV0Y2hVbnNlZW5FdmVudHMgPSBhc3luYyAoKTogUHJvbWlzZTxFdmVudFtdPiA9PiB7XG4gICAgY29uc3QgdW5zZWVuOiBFdmVudFtdID0gW107XG4gICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCA9IGxvZ1ZpZXcubG9nQ3Vyc29yO1xuICAgIGxldCBoYXNNb3JlID0gdHJ1ZTtcbiAgICB3aGlsZSAoaGFzTW9yZSkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB3b3JsZC5ldmVudHMubGlzdCh7XG4gICAgICAgIHJ1bklkLFxuICAgICAgICBwYWdpbmF0aW9uOiB7XG4gICAgICAgICAgc29ydE9yZGVyOiAnYXNjJyxcbiAgICAgICAgICBjdXJzb3I6IGN1cnNvciA/PyB1bmRlZmluZWQsXG4gICAgICAgICAgbGltaXQ6IDEwMDAsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGZvciAoY29uc3QgZSBvZiByZXNwb25zZS5kYXRhKSB7XG4gICAgICAgIGlmIChlLmV2ZW50SWQgJiYgc2VlbkV2ZW50SWRzLmhhcyhlLmV2ZW50SWQpKSBjb250aW51ZTtcbiAgICAgICAgaWYgKGUuZXZlbnRJZCkgc2VlbkV2ZW50SWRzLmFkZChlLmV2ZW50SWQpO1xuICAgICAgICB1bnNlZW4ucHVzaChlKTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXNwb25zZS5jdXJzb3IpIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvcjtcbiAgICAgIGhhc01vcmUgPSByZXNwb25zZS5kYXRhLmxlbmd0aCA+IDAgJiYgcmVzcG9uc2UuY3Vyc29yICE9IG51bGw7XG4gICAgfVxuICAgIGxvZ1ZpZXcuYWR2YW5jZUN1cnNvcihjdXJzb3IpO1xuICAgIGxvZ1ZpZXcubWFya0ZlZCh1bnNlZW4pO1xuICAgIG9ic2VydmVFdmVudHNGb3JPd25lcnNoaXAodW5zZWVuKTtcbiAgICByZXR1cm4gdW5zZWVuO1xuICB9O1xuXG4gIC8qKlxuICAgKiBFdmVudHMgYSBXb3JsZCBoYW5kZWQgYmFjayBvbiB0aGlzIGludm9jYXRpb24ncyB3cml0ZXMgdGhhdCB0aGUgVk0gY2FuXG4gICAqIHRha2Ugbm93OiB0aGUgY29udGlndW91cyBydW4gYWJvdmUgd2hhdCBpdCBoYXMgKHNlZVxuICAgKiBgUXVpY2tKU0xvZ1ZpZXcudGFrZUNvbnRpZ3VvdXNgKS4gRGVsaXZlcmVkIGFoZWFkIG9mIGBmZXRjaFVuc2VlbkV2ZW50c2BcbiAgICogc28gYSB3cml0ZSdzIHJlc3BvbnNlLCBub3QgYSBsaXN0aW5nLCBpcyB3aGF0IHVzdWFsbHkgY2FycmllcyB0aGUgbG9nXG4gICAqIGZvcndhcmQsIHdoaWNoIGlzIHRoZSByb3VuZC10cmlwIHRoZSBwYWdlIGV4aXN0cyB0byBzYXZlLiBFbXB0eSB3aGVuXG4gICAqIG5vdGhpbmcgaXMgcXVldWVkIG9yIHRoZSBuZXh0IHBvc2l0aW9uIGlzIG5vdCBpbiBoYW5kLCBhbmQgdGhlIGNhbGxlclxuICAgKiBsaXN0cy5cbiAgICovXG4gIGNvbnN0IHRha2VRdWV1ZWRFdmVudHMgPSAoKTogRXZlbnRbXSA9PiB7XG4gICAgY29uc3QgcXVldWVkID0gbG9nVmlldy50YWtlQ29udGlndW91cygpO1xuICAgIGZvciAoY29uc3QgZSBvZiBxdWV1ZWQpIHtcbiAgICAgIGlmIChlLmV2ZW50SWQpIHNlZW5FdmVudElkcy5hZGQoZS5ldmVudElkKTtcbiAgICB9XG4gICAgb2JzZXJ2ZUV2ZW50c0Zvck93bmVyc2hpcChxdWV1ZWQpO1xuICAgIHJldHVybiBxdWV1ZWQ7XG4gIH07XG5cbiAgdHJ5IHtcbiAgICBsZXQgaXRlcmF0aW9uID0gMDtcbiAgICB3aGlsZSAocmVzdWx0LnN1c3BlbmRlZCAmJiAhcnVuR29uZSAmJiAhYnVkZ2V0LmlzRXhoYXVzdGVkKCkpIHtcbiAgICAgIGl0ZXJhdGlvbisrO1xuICAgICAgLy8gUmUtY2hlY2sgdGhlIGV2ZW50IGNlaWxpbmcgZXZlcnkgdHVybjogdGhlIGxvb3AgYXBwZW5kcyBldmVudHMgb25cbiAgICAgIC8vIGVhY2ggY29udGludWVXaXRoRXZlbnRzLCBzbyBhIHNpbmdsZSBpbnZvY2F0aW9uIGNhbiBvdGhlcndpc2UgZ3Jvd1xuICAgICAgLy8gdGhlIGxvZyBhcmJpdHJhcmlseSBmYXIgcGFzdCB0aGUgb3BlcmF0b3IncyBsaW1pdCAodGhlIG5vZGUgZW5naW5lXG4gICAgICAvLyByZS1jaGVja3MgcGVyIHJlcGxheSBmb3IgdGhlIHNhbWUgcmVhc29uKS4gYHNlZW5FdmVudElkc2AgY291bnRzXG4gICAgICAvLyBldmVyeSBldmVudCB0aGlzIGludm9jYXRpb24gaGFzIG9ic2VydmVkOiBpbml0aWFsIGxvZyArIGFsbFxuICAgICAgLy8gZmVlZHMuXG4gICAgICBpZiAobWF4RXZlbnRzTGltaXQgIT09IHVuZGVmaW5lZCAmJiBzZWVuRXZlbnRJZHMuc2l6ZSA+PSBtYXhFdmVudHNMaW1pdCkge1xuICAgICAgICB0aHJvdyBuZXcgTWF4RXZlbnRzRXhjZWVkZWRFcnJvcihzZWVuRXZlbnRJZHMuc2l6ZSwgbWF4RXZlbnRzTGltaXQpO1xuICAgICAgfVxuICAgICAgY29uc3QgcGVuZGluZ09wZXJhdGlvbnMgPSByZXN1bHQuc3VzcGVuZGVkLnBlbmRpbmdPcGVyYXRpb25zO1xuXG4gICAgICAvLyBTZWxlY3QgdGhpcyB0dXJuJ3MgaW5saW5lIGNhbmRpZGF0ZXMgQkVGT1JFIGRpc3BhdGNoOiBmcmVzaCBzdGVwc1xuICAgICAgLy8gKG5vIHN0ZXBfY3JlYXRlZCB5ZXQpIHRoYXQgdGhpcyBpbnZvY2F0aW9uIGhhc24ndCBhbHJlYWR5IGhhbmRsZWQuXG4gICAgICAvLyBUaGVpciBzdGVwX2NyZWF0ZWQgaXMgZGVsaWJlcmF0ZWx5IE5PVCB3cml0dGVuIGJ5IGRpc3BhdGNoOiB0aGVcbiAgICAgIC8vIGlubGluZSBjbGFpbSBiZWxvdyBpcyBhIGxhenkgc3RlcF9zdGFydGVkIGNhcnJ5aW5nIHRoZSBpbnB1dCxcbiAgICAgIC8vIHdoaWNoIHRoZSB3b3JsZCBhcHBsaWVzIGFzIGFuIGF0b21pYyBjcmVhdGUtY2xhaW0uIEEgY29uY3VycmVudFxuICAgICAgLy8gaW52b2NhdGlvbiByYWNpbmcgb24gdGhlIHNhbWUgZnJlc2ggc3RlcCBsb3NlcyB0aGF0IGNsYWltIHdpdGhcbiAgICAgIC8vIEVudGl0eUNvbmZsaWN0RXJyb3IgYW5kIHNraXBzLCBzbyBzdGVwIGJvZGllcyBjYW5ub3QgZG91YmxlLXJ1blxuICAgICAgLy8gKHByZXZpb3VzbHkgYm90aCBpbnZvY2F0aW9ucyBiYXJlLXN0YXJ0ZWQgdGhlIHN0ZXAgYWZ0ZXIgb25lIGxvc3RcbiAgICAgIC8vIHRoZSBzd2FsbG93ZWQgc3RlcF9jcmVhdGVkIHJhY2UpLlxuICAgICAgY29uc3QgZnJlc2hTdGVwcyA9IHBlbmRpbmdPcGVyYXRpb25zLmZpbHRlcihcbiAgICAgICAgKG9wKTogb3AgaXMgUGVuZGluZ1N0ZXAgPT5cbiAgICAgICAgICBvcC50eXBlID09PSAnc3RlcCcgJiZcbiAgICAgICAgICAhb3AuaGFzQ3JlYXRlZEV2ZW50ICYmXG4gICAgICAgICAgIWV4ZWN1dGVkU3RlcElkcy5oYXMob3AuY29ycmVsYXRpb25JZCkgJiZcbiAgICAgICAgICAhcXVldWVkU3RlcElkcy5oYXMob3AuY29ycmVsYXRpb25JZClcbiAgICAgICk7XG4gICAgICAvLyBTdGVwcyB3aG9zZSBpbnB1dCByZWZ1c2VkIHRvIHNlcmlhbGl6ZSAoc2VlXG4gICAgICAvLyBQZW5kaW5nU3RlcC5zZXJpYWxpemF0aW9uRXJyb3IpIG5ldmVyIGV4ZWN1dGU6IHRoZXkgbXVzdCBub3QgYmVcbiAgICAgIC8vIGlubGluZS1jbGFpbWVkIChhIGxhenkgc3RlcF9zdGFydGVkIHdvdWxkIG5lZWQgdGhlIGlucHV0IHRoYXRcbiAgICAgIC8vIGZhaWxlZCkgbm9yIHF1ZXVlZC4gRGlzcGF0Y2ggYmVsb3cgZmluYWxpemVzIHRoZW0gYXMgc3RlcF9jcmVhdGVkXG4gICAgICAvLyArIHN0ZXBfZmFpbGVkIGluc3RlYWQ7IG9ubHkgaGVhbHRoeSBzdGVwcyBjb21wZXRlIGZvciBpbmxpbmVcbiAgICAgIC8vIHNsb3RzIGFuZCBvdmVyZmxvdy5cbiAgICAgIGNvbnN0IGhlYWx0aHlTdGVwcyA9IGZyZXNoU3RlcHMuZmlsdGVyKFxuICAgICAgICAoc3RlcCkgPT4gIXN0ZXAuc2VyaWFsaXphdGlvbkVycm9yXG4gICAgICApO1xuICAgICAgY29uc3QgaW5saW5lQ2FuZGlkYXRlcyA9XG4gICAgICAgIG1heElubGluZVN0ZXBzIDw9IDAgPyBbXSA6IGhlYWx0aHlTdGVwcy5zbGljZSgwLCBtYXhJbmxpbmVTdGVwcyk7XG4gICAgICBjb25zdCBpbmxpbmVDbGFpbUNpZHMgPSBuZXcgU2V0KFxuICAgICAgICBpbmxpbmVDYW5kaWRhdGVzLm1hcCgoc3RlcCkgPT4gc3RlcC5jb3JyZWxhdGlvbklkKVxuICAgICAgKTtcblxuICAgICAgLy8gMS4gRHVyYWJsZSBzaWRlIGVmZmVjdHMgZm9yIHRoaXMgc3VzcGVuc2lvbidzIHBlbmRpbmcgb3BzLlxuICAgICAgY29uc3Qgb3BzVG9EaXNwYXRjaCA9IHBlbmRpbmdPcGVyYXRpb25zLm1hcCgob3ApID0+XG4gICAgICAgIG9wLnR5cGUgPT09ICdob29rJyAmJlxuICAgICAgICAob3AgYXMgUGVuZGluZ0hvb2spLmFib3J0UmVxdWVzdGVkICYmXG4gICAgICAgIHJlY29yZGVkQWJvcnRJZHMuaGFzKG9wLmNvcnJlbGF0aW9uSWQpXG4gICAgICAgICAgPyAoeyAuLi5vcCwgYWJvcnRSZXF1ZXN0ZWQ6IGZhbHNlIH0gYXMgUGVuZGluZ09wZXJhdGlvbilcbiAgICAgICAgICA6IG9wXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCBvcCBvZiBwZW5kaW5nT3BlcmF0aW9ucykge1xuICAgICAgICBpZiAob3AudHlwZSA9PT0gJ2hvb2snICYmIChvcCBhcyBQZW5kaW5nSG9vaykuYWJvcnRSZXF1ZXN0ZWQpIHtcbiAgICAgICAgICByZWNvcmRlZEFib3J0SWRzLmFkZChvcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gU3RlcHMgYmV5b25kIHRoZSBpbmxpbmUgY2FwIGFyZSBoYW5kZWQgdG8gdGhlIHF1ZXVlIGluIHRoZSBzYW1lXG4gICAgICAvLyB0dXJuIHRoZWlyIHN0ZXBfY3JlYXRlZCBpcyB3cml0dGVuLiBXaGVyZSBlbGlnaWJsZSwgdGhlIGRpc3BhdGNoXG4gICAgICAvLyBiZWxvdyBwYXJhbGxlbGl6ZXMgZWFjaCBvdmVyZmxvdyBzdGVwJ3Mgc3RlcF9jcmVhdGVkIHdyaXRlIHdpdGhcbiAgICAgIC8vIGl0cyBxdWV1ZSBwdWJsaXNoIChyZXNpbGllbnQgc3RlcCBkaXNwYXRjaDogdGhlIG1lc3NhZ2UgY2Fycmllc1xuICAgICAgLy8gYHN0ZXBJbnB1dGAgc28gdGhlIGNvbnN1bWVyIGNhbiByZS1lbnN1cmUgdGhlIGV2ZW50KTsgdGhlIHJlc3RcbiAgICAgIC8vIGFyZSBxdWV1ZWQgcmlnaHQgYWZ0ZXIsIGluIHBhcmFsbGVsLiBUaGlzIG11c3QgYWxsIGhhcHBlbiBCRUZPUkVcbiAgICAgIC8vIHRoZSBldmVudCBmZWVkIGJlbG93OiB0aGUgZmVlZCBhbHdheXMgb2JzZXJ2ZXMgdGhvc2VcbiAgICAgIC8vIHN0ZXBfY3JlYXRlZCB3cml0ZXMgYXMgdW5zZWVuIGV2ZW50cyBhbmQgYGNvbnRpbnVlYHMsIHNvIGFcbiAgICAgIC8vIGhhbmRvZmYgcGxhY2VkIGFmdGVyIGl0IGlzIHVucmVhY2hhYmxlIG9uIHRoZSBvbmx5IGl0ZXJhdGlvblxuICAgICAgLy8gdGhhdCBzdGlsbCBjbGFzc2lmaWVzIHRoZXNlIHN0ZXBzIGFzIGZyZXNoOiBuZXh0IHR1cm4gdGhleSBjYXJyeVxuICAgICAgLy8gaGFzQ3JlYXRlZEV2ZW50IGFuZCB3b3VsZCBuZXZlciBiZSBxdWV1ZWQgYXQgYWxsICh0aGUgd2VkZ2UgYmVoaW5kXG4gICAgICAvLyBwcm9taXNlUmFjZVN0cmVzc1Rlc3RXb3JrZmxvdyBoYW5naW5nIGluIHRoZSBxdWlja2pzIENJIGxlZ3MpLiBUaGVcbiAgICAgIC8vIHN0ZXAtaWRlbnRpdHktc2NvcGVkIGlkZW1wb3RlbmN5IGtleSBtYWtlcyByZXBlYXRzIGhhcm1sZXNzLlxuICAgICAgY29uc3Qgb3ZlcmZsb3dTdGVwcyA9IGhlYWx0aHlTdGVwcy5zbGljZShpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aCk7XG4gICAgICBjb25zdCBkaXNwYXRjaGVkID0gYXdhaXQgZGlzcGF0Y2hQZW5kaW5nT3BzKHtcbiAgICAgICAgd29ybGQsXG4gICAgICAgIHJ1bklkLFxuICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICBuZXh0VHJhY2VDYXJyaWVyLFxuICAgICAgICBjcmVhdGVFdmVudCxcbiAgICAgICAgLi4uKGxvZ1ZpZXcudHJhY2tpbmcgJiYgdHlwZW9mIGxvZ1ZpZXcubG9nQ3Vyc29yID09PSAnc3RyaW5nJ1xuICAgICAgICAgID8geyBkZWx0YUN1cnNvcjogbG9nVmlldy5sb2dDdXJzb3IgfVxuICAgICAgICAgIDoge30pLFxuICAgICAgICBwZW5kaW5nT3BlcmF0aW9uczogb3BzVG9EaXNwYXRjaCxcbiAgICAgICAgc2tpcFN0ZXBDcmVhdGlvbjogaW5saW5lQ2xhaW1DaWRzLFxuICAgICAgICBxdWV1ZVN0ZXBDaWRzOiBuZXcgU2V0KG92ZXJmbG93U3RlcHMubWFwKChzKSA9PiBzLmNvcnJlbGF0aW9uSWQpKSxcbiAgICAgICAgZmluYWxpemVVbnNlcmlhbGl6YWJsZVN0ZXBzOiB0cnVlLFxuICAgICAgICB3ZmRpYWcsXG4gICAgICB9KTtcbiAgICAgIGlmIChcbiAgICAgICAgZGlzcGF0Y2hlZC5jcmVhdGVkQXR0cmlidXRlRXZlbnQgfHxcbiAgICAgICAgZGlzcGF0Y2hlZC5jcmVhdGVkR2V0Q29uZmxpY3RIb29rXG4gICAgICApIHtcbiAgICAgICAgcGVuZGluZ1JlcXVldWVTaWduYWwgPSB0cnVlO1xuICAgICAgfVxuICAgICAgLy8gQSBmaW5hbGl6ZWQgdW5zZXJpYWxpemFibGUgc3RlcCBoYXMgdGVybWluYWwgZXZlbnRzIGR1cmFibHlcbiAgICAgIC8vIHdyaXR0ZW4gYnV0IG5vIGV4ZWN1dGlvbiBtZXNzYWdlIGFueXdoZXJlOiBpZiB0aGUgZmVlZCBiZWxvd1xuICAgICAgLy8gZG9lc24ndCBzdXJmYWNlIHRoZW0gKGV2ZW50dWFsbHktY29uc2lzdGVudCBsaXN0aW5nKSBhbmQgdGhlIGxvb3BcbiAgICAgIC8vIGV4aXRzLCBub3RoaW5nIHdvdWxkIGV2ZXIgcmUtaW52b2tlIHRoZSBydW4gdG8gb2JzZXJ2ZSB0aGVcbiAgICAgIC8vIGZhaWx1cmUuIFJhaXNlIHRoZSByZXF1ZXVlIHNpZ25hbCAoc2FtZSBtZWNoYW5pc20gYXMgaW5saW5lXG4gICAgICAvLyB0ZXJtaW5hbHMpIGFuZCBtYXJrIHRoZSBzdGVwcyBoYW5kbGVkIHNvIGxhdGVyIHR1cm5zIGRvbid0XG4gICAgICAvLyByZS1maW5hbGl6ZSBvciBiYWNrc3RvcC1xdWV1ZSB0aGVtLlxuICAgICAgaWYgKGRpc3BhdGNoZWQuZmFpbGVkU2VyaWFsaXphdGlvblN0ZXBDaWRzLnNpemUgPiAwKSB7XG4gICAgICAgIHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gdHJ1ZTtcbiAgICAgICAgZm9yIChjb25zdCBjaWQgb2YgZGlzcGF0Y2hlZC5mYWlsZWRTZXJpYWxpemF0aW9uU3RlcENpZHMpIHtcbiAgICAgICAgICBleGVjdXRlZFN0ZXBJZHMuYWRkKGNpZCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaWQgb2YgZGlzcGF0Y2hlZC5xdWV1ZWRTdGVwQ2lkcykge1xuICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChjaWQpO1xuICAgICAgfVxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIG92ZXJmbG93U3RlcHNcbiAgICAgICAgICAuZmlsdGVyKChzdGVwKSA9PiAhZGlzcGF0Y2hlZC5xdWV1ZWRTdGVwQ2lkcy5oYXMoc3RlcC5jb3JyZWxhdGlvbklkKSlcbiAgICAgICAgICAubWFwKChzdGVwKSA9PiB7XG4gICAgICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChzdGVwLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgICAgcmV0dXJuIHF1ZXVlU3RlcE1lc3NhZ2Uoe1xuICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgICBuYW1lc3BhY2UsXG4gICAgICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICAgIHB1cnBvc2U6ICdkaXNwYXRjaCcsXG4gICAgICAgICAgICAgIHdmZGlhZyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pXG4gICAgICApO1xuXG4gICAgICAvLyBDb21wbGV0ZSBlbGFwc2VkIHdhaXRzIHNvIHRoZWlyIHdhaXRfY29tcGxldGVkIGV2ZW50cyBhcmUgcGlja2VkXG4gICAgICAvLyB1cCBieSB0aGUgZmVlZCBiZWxvdyAoaW5zdGVhZCBvZiBhIHF1ZXVlIHJlLWludm9jYXRpb24pLlxuICAgICAgY29uc3Qgd2FpdENvbXBsZXRlUHJvbWlzZXM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBvcCBvZiBwZW5kaW5nT3BlcmF0aW9ucykge1xuICAgICAgICBpZiAob3AudHlwZSAhPT0gJ3dhaXQnKSBjb250aW51ZTtcbiAgICAgICAgY29uc3Qgd2FpdCA9IG9wIGFzIFBlbmRpbmdXYWl0O1xuICAgICAgICBpZiAoY29tcGxldGVkV2FpdElkczIuaGFzKHdhaXQuY29ycmVsYXRpb25JZCkpIGNvbnRpbnVlO1xuICAgICAgICBpZiAobmV3IERhdGUod2FpdC5yZXN1bWVBdCkuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKSA+IDApIGNvbnRpbnVlO1xuICAgICAgICBjb21wbGV0ZWRXYWl0SWRzMi5hZGQod2FpdC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgd2FpdENvbXBsZXRlUHJvbWlzZXMucHVzaChcbiAgICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgYXdhaXQgY3JlYXRlRXZlbnQoe1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3dhaXRfY29tcGxldGVkJyxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogd2FpdC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSByZXR1cm47XG4gICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAod2FpdENvbXBsZXRlUHJvbWlzZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh3YWl0Q29tcGxldGVQcm9taXNlcyk7XG4gICAgICB9XG5cbiAgICAgIC8vIDIuIENoZWFwIHByb2dyZXNzIGZpcnN0OiBmZWVkIG5ld2x5IHJlY29yZGVkIGV2ZW50cyBpbnRvIHRoZSBsaXZlXG4gICAgICAvLyBWTSBiZWZvcmUgYmxvY2tpbmcgb24gc3RlcCBib2RpZXMuIFdoYXQgdGhlIHdyaXRlcyBhYm92ZSBoYW5kZWQgYmFja1xuICAgICAgLy8gaXMgZGVsaXZlcmVkIGZpcnN0LCBhbmQgYSBsaXN0aW5nIHJ1bnMgd2hlbiB0aGUgcXVldWUgZG9lcyBub3QgcmVhY2hcbiAgICAgIC8vIHRoZSBuZXh0IHBvc2l0aW9uLiBBIHJlcG9ydCBjaGFuZ2VzIHdoYXQgaXMgZmVkIGZpcnN0LCBub3Qgd2hldGhlclxuICAgICAgLy8gdGhpcyBsaXN0aW5nIGhhcHBlbnM6IGFmdGVyIGEgcXVldWVkIHBhZ2UgaXMgZmVkLCB0aGlzIGJyYW5jaFxuICAgICAgLy8gYGNvbnRpbnVlYHMsIGFuZCB0aGUgbmV4dCBpdGVyYXRpb24gZmluZHMgdGhlIHF1ZXVlIGVtcHR5IGFuZCBsaXN0c1xuICAgICAgLy8gZnJvbSBhIGN1cnNvciBhIHJlcG9ydCBkb2VzIG5vdCBhZHZhbmNlIChyZS1yZWFkaW5nIHRoZSByZXBvcnRlZFxuICAgICAgLy8gc3BhbiwgZGVkdXBlZCBvbiBgc2VlbkV2ZW50SWRzYCkuIE9ubHkgdGhlIGlubGluZSBkZWx0YSBiZWxvdywgd2hpY2hcbiAgICAgIC8vIGRvZXMgYWR2YW5jZSB0aGUgY3Vyc29yLCBzYXZlcyBhIGxpc3Rpbmcgb3V0cmlnaHQuIFNhbWUgc2hhcGUgYXMgdGhlXG4gICAgICAvLyBub2RlIGVuZ2luZS5cbiAgICAgIHtcbiAgICAgICAgY29uc3QgcXVldWVkID0gdGFrZVF1ZXVlZEV2ZW50cygpO1xuICAgICAgICBjb25zdCBuZXdFdmVudHMgPVxuICAgICAgICAgIHF1ZXVlZC5sZW5ndGggPiAwID8gcXVldWVkIDogYXdhaXQgZmV0Y2hVbnNlZW5FdmVudHMoKTtcbiAgICAgICAgaWYgKG5ld0V2ZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgLy8gVGhlIGxpc3RpbmcgY2F1Z2h0IHVwIHdpdGggdGhpcyBpbnZvY2F0aW9uJ3Mgd3JpdGVzLCBzbyBhbnlcbiAgICAgICAgICAvLyBhdHRyX3NldCAvIGdldENvbmZsaWN0IGhvb2tfY3JlYXRlZCBoYXMgYmVlbiAob3IgaXMgYmVpbmcpXG4gICAgICAgICAgLy8gY29uc3VtZWQgYnkgdGhlIGxpdmUgVk0sIHNvIG5vIGV4dGVybmFsIHJlcXVldWUgaXMgbmVlZGVkLlxuICAgICAgICAgIHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gZmFsc2U7XG4gICAgICAgICAgcmVzdWx0ID0gYXdhaXQgc2Vzc2lvbi5jb250aW51ZVdpdGhFdmVudHMobmV3RXZlbnRzKTtcbiAgICAgICAgICB3ZmRpYWcoJ2lubGluZV9pdGVyYXRpb24nLCB7XG4gICAgICAgICAgICBpdGVyYXRpb24sXG4gICAgICAgICAgICBwaGFzZTogJ2ZlZWQnLFxuICAgICAgICAgICAgZmVkRXZlbnRzOiBuZXdFdmVudHMubGVuZ3RoLFxuICAgICAgICAgICAgZmVkRnJvbTogcXVldWVkLmxlbmd0aCA+IDAgPyAnd3JpdGUtcmVzcG9uc2UnIDogJ2xpc3QnLFxuICAgICAgICAgICAgb3V0Y29tZTogcmVzdWx0LmNvbXBsZXRlZFxuICAgICAgICAgICAgICA/ICdjb21wbGV0ZWQnXG4gICAgICAgICAgICAgIDogcmVzdWx0LmZhaWxlZFxuICAgICAgICAgICAgICAgID8gJ2ZhaWxlZCdcbiAgICAgICAgICAgICAgICA6ICdzdXNwZW5kZWQnLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIDMuIE5vIGNoZWFwIHByb2dyZXNzIGxlZnQsIHNvIGV4ZWN1dGUgc3RlcHMgaW5saW5lLlxuICAgICAgY29uc3Qgc3RlcE9wcyA9IHBlbmRpbmdPcGVyYXRpb25zLmZpbHRlcihcbiAgICAgICAgKG9wKTogb3AgaXMgUGVuZGluZ1N0ZXAgPT4gb3AudHlwZSA9PT0gJ3N0ZXAnXG4gICAgICApO1xuICAgICAgLy8gU3RlcHMgY3JlYXRlZCBieSBhbiBFQVJMSUVSIGludm9jYXRpb24gKG9yIGFuIGVhcmxpZXIgdHVybikgdGhhdFxuICAgICAgLy8gYXJlIHN0aWxsIHBlbmRpbmcsIHdpdGggbm8gd29yayBvd25lZCBieSBUSElTIGludm9jYXRpb24uIE1pcnJvclxuICAgICAgLy8gdGhlIG5vZGUgZW5naW5lJ3Mgb3duZXJzaGlwIGRlY2lzaW9uIHRhYmxlIChzdGVwLW93bmVyc2hpcC50cyksXG4gICAgICAvLyBOT1QgYSBkZWxpdmVyeUF0dGVtcHQgZ2F0ZTogd29ybGRzIGFkdmFuY2UgdGhlIGF0dGVtcHQgY291bnRlciBvblxuICAgICAgLy8gcm91dGluZSByZWRlbGl2ZXJpZXMgKHdvcmxkLWxvY2FsIGNvdW50cyBldmVyeSBoYW5kbGVkIHJlc3BvbnNlKSxcbiAgICAgIC8vIHNvIGF0dGVtcHQgPiAxIGlzIHRoZSBjb21tb24gY2FzZSBhbmQgd291bGQgZmlyZSBiYWNrc3RvcHMgYXRcbiAgICAgIC8vIHN0ZXBzIGFjdGl2ZWx5IGV4ZWN1dGluZyBpbmxpbmUgaW4gYSBsaXZlIGludm9jYXRpb24uXG4gICAgICAvL1xuICAgICAgLy8gICAtIE93bmVyc2hpcCBsZWFzZSBBQ1RJVkUsIGhlbGQgYnkgQU5PVEhFUiBtZXNzYWdlIOKGkiB0aGUgc3RlcCBpc1xuICAgICAgLy8gICAgIChwcmVzdW1hYmx5KSBleGVjdXRpbmcgaW5saW5lIGluIGEgbGl2ZSBpbnZvY2F0aW9uLiBBcm0gYVxuICAgICAgLy8gICAgIERFTEFZRUQgYmFja3N0b3AgZm9yIHRoZSBsZWFzZSByZW1haW5kZXIsIGtleWVkIHRvIHRoZVxuICAgICAgLy8gICAgIG93bmVyc2hpcCBlcG9jaCAoYSByZWZyZXNoZWQgbGVhc2UgcmUtYXJtcyBhIGZyZXNoIGJhY2tzdG9wXG4gICAgICAvLyAgICAgaW5zdGVhZCBvZiBkZWR1cGluZyBhZ2FpbnN0IHRoZSBpbi1mbGlnaHQgb25lKS4gSWYgdGhlIG93bmVyXG4gICAgICAvLyAgICAgY29tcGxldGVzIG5vcm1hbGx5LCB0aGUgYmFja3N0b3AgZGVsaXZlcnkgcmVzb2x2ZXMgdGhlIHN0ZXBcbiAgICAgIC8vICAgICBhcyAnc2tpcHBlZCcuXG4gICAgICAvLyAgIC0gT3duZXJzaGlwIGxlYXNlIEFDVElWRSwgaGVsZCBieSBUSElTIG1lc3NhZ2Ug4oaSIHRoaXMgZGVsaXZlcnlcbiAgICAgIC8vICAgICBpcyB0aGUgb3duZXIncyByZWRlbGl2ZXJ5OyB0aGUgY2xhaW1hbnQgY3Jhc2hlZFxuICAgICAgLy8gICAgIG1pZC1leGVjdXRpb24uIERpc3BhdGNoIGltbWVkaWF0ZWx5IGZvciBiYWNrZ3JvdW5kIHJlY292ZXJ5LlxuICAgICAgLy8gICAtIE5vIHN0YW1wIC8gbGVhc2UgRVhQSVJFRCAvIHN0ZXBfcmV0cnlpbmcgb2JzZXJ2ZWQg4oaSIHRoZSBzdGVwXG4gICAgICAvLyAgICAgaXMgcXVldWUtb3duZWQgb3Igb3JwaGFuZWQuIERpc3BhdGNoIGltbWVkaWF0ZWx5OyB0aGVcbiAgICAgIC8vICAgICBzdGVwLWlkZW50aXR5LXNjb3BlZCBpZGVtcG90ZW5jeSBrZXkgZGVkdXBlcyBhZ2FpbnN0IHRoZVxuICAgICAgLy8gICAgIG9yaWdpbmFsIGhhbmRvZmYuXG4gICAgICBjb25zdCBub3dNcyA9IERhdGUubm93KCk7XG4gICAgICBmb3IgKGNvbnN0IHN0ZXAgb2Ygc3RlcE9wcykge1xuICAgICAgICBpZiAoIXN0ZXAuaGFzQ3JlYXRlZEV2ZW50KSBjb250aW51ZTtcbiAgICAgICAgaWYgKGV4ZWN1dGVkU3RlcElkcy5oYXMoc3RlcC5jb3JyZWxhdGlvbklkKSkgY29udGludWU7XG4gICAgICAgIGlmIChxdWV1ZWRTdGVwSWRzLmhhcyhzdGVwLmNvcnJlbGF0aW9uSWQpKSBjb250aW51ZTtcbiAgICAgICAgY29uc3Qgb3duZXJzaGlwID0gc3RlcE93bmVyc2hpcC5nZXQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgY29uc3Qgb3duZXJzaGlwQWN0aXZlID1cbiAgICAgICAgICBvd25lcnNoaXAgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgIG93bmVyc2hpcC5vd25lciAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgIW93bmVyc2hpcC5zYXdSZXRyeWluZztcbiAgICAgICAgbGV0IGxlYXNlUmVtYWluaW5nU2Vjb25kcyA9IDA7XG4gICAgICAgIGlmIChvd25lcnNoaXBBY3RpdmUgJiYgb3duZXJzaGlwLnN0YXJ0ZWRBdE1zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb25zdCBsZWFzZVNlY29uZHMgPSBnZXRJbmxpbmVPd25lcnNoaXBMZWFzZVNlY29uZHMoKTtcbiAgICAgICAgICBsZWFzZVJlbWFpbmluZ1NlY29uZHMgPSBNYXRoLm1pbihcbiAgICAgICAgICAgIGxlYXNlU2Vjb25kcyxcbiAgICAgICAgICAgIE1hdGgubWF4KFxuICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICBNYXRoLmNlaWwoXG4gICAgICAgICAgICAgICAgKG93bmVyc2hpcC5zdGFydGVkQXRNcyArIGxlYXNlU2Vjb25kcyAqIDEwMDAgLSBub3dNcykgLyAxMDAwXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChcbiAgICAgICAgICBvd25lcnNoaXBBY3RpdmUgJiZcbiAgICAgICAgICBvd25lcnNoaXAub3duZXIgIT09IG93bmVyTWVzc2FnZUlkICYmXG4gICAgICAgICAgbGVhc2VSZW1haW5pbmdTZWNvbmRzID4gMFxuICAgICAgICApIHtcbiAgICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChzdGVwLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIGF3YWl0IHF1ZXVlU3RlcE1lc3NhZ2Uoe1xuICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgIGRlbGF5U2Vjb25kczogbGVhc2VSZW1haW5pbmdTZWNvbmRzLFxuICAgICAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgICAgIHB1cnBvc2U6IGBiYWNrc3RvcDoke293bmVyc2hpcC5zdGFydGVkQXRNc31gLFxuICAgICAgICAgICAgd2ZkaWFnLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHF1ZXVlZFN0ZXBJZHMuYWRkKHN0ZXAuY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgYXdhaXQgcXVldWVTdGVwTWVzc2FnZSh7XG4gICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgICAgIHB1cnBvc2U6ICdkaXNwYXRjaCcsXG4gICAgICAgICAgICB3ZmRpYWcsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGlubGluZUNhbmRpZGF0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIE5vIGluLXByb2Nlc3MgcHJvZ3Jlc3MgcG9zc2libGU6IHRoZSBydW4gYXdhaXRzIGFuIGV4dGVybmFsXG4gICAgICAgIC8vIHN0aW11bHVzIChob29rIHBheWxvYWQsIHF1ZXVlZCBzdGVwLCB3YWl0IHRpbWVyKS5cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIC8vIFJhY2luZyB0aW1lcnMgbXVzdCBmaXJlIG9uIHRpbWUgd2hpbGUgc3RlcCBib2RpZXMgYmxvY2sgdGhpc1xuICAgICAgLy8gaW52b2NhdGlvbjogZW5xdWV1ZSBhIGRlbGF5ZWQgY29udGludWF0aW9uIGZvciB0aGUgc29vbmVzdFxuICAgICAgLy8gcGVuZGluZyB3YWl0IChhIHNlcGFyYXRlIGludm9jYXRpb24gd3JpdGVzIGl0cyB3YWl0X2NvbXBsZXRlZCBhdFxuICAgICAgLy8gdGhlIHJpZ2h0IGxvZyBwb3NpdGlvbiwgdGhlIHNhbWUgbWVjaGFuaXNtIGFzIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4gICAgICAvLyB3YWl0LWNvbnRpbnVhdGlvbiBkaXNwYXRjaCkuXG4gICAgICBsZXQgc29vbmVzdFdhaXQ6IHsgY29ycmVsYXRpb25JZDogc3RyaW5nOyBzZWNvbmRzOiBudW1iZXIgfSB8IHVuZGVmaW5lZDtcbiAgICAgIGZvciAoY29uc3Qgb3Agb2YgcGVuZGluZ09wZXJhdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wLnR5cGUgIT09ICd3YWl0JykgY29udGludWU7XG4gICAgICAgIGNvbnN0IHdhaXQgPSBvcCBhcyBQZW5kaW5nV2FpdDtcbiAgICAgICAgaWYgKHNjaGVkdWxlZFdhaXRDb250aW51YXRpb25zLmhhcyh3YWl0LmNvcnJlbGF0aW9uSWQpKSBjb250aW51ZTtcbiAgICAgICAgLy8gV2FpdHMgd2hvc2Ugd2FpdF9jb21wbGV0ZWQgVEhJUyBpbnZvY2F0aW9uIGFscmVhZHkgd3JvdGUgKHRoZVxuICAgICAgICAvLyBlbGFwc2VkLXdhaXQgcGFzcyBhYm92ZSkgYXJlIGRvbmU6IHRoZSBldmVudCBqdXN0IGhhc24ndCBmZWRcbiAgICAgICAgLy8gYmFjayBpbnRvIHRoZSBWTSB5ZXQuIE5vIGNvbnRpbnVhdGlvbiBuZWVkZWQuXG4gICAgICAgIGlmIChjb21wbGV0ZWRXYWl0SWRzMi5oYXMod2FpdC5jb3JyZWxhdGlvbklkKSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IHJlc3VtZU1zID0gbmV3IERhdGUod2FpdC5yZXN1bWVBdCkuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKTtcbiAgICAgICAgLy8gQW4gYWxyZWFkeS1lbGFwc2VkIHdhaXQgTVVTVCBzdGlsbCBnZXQgYSBjb250aW51YXRpb24gKGNsYW1wZWRcbiAgICAgICAgLy8gdG8gdGhlIDFzIG1pbmltdW0sIGV4YWN0bHkgbGlrZSB0aGUgbm9kZSBlbmdpbmUnc1xuICAgICAgICAvLyBgTWF0aC5tYXgoMTAwMCwgcmVzdW1lQXRNcyAtIG5vdylgKSwgbm90IGJlIHNraXBwZWQ6IGEgd2FpdFxuICAgICAgICAvLyB3aG9zZSBkZWFkbGluZSBmYWxscyBiZXR3ZWVuIHRoaXMgaXRlcmF0aW9uJ3MgZWxhcHNlZC13YWl0XG4gICAgICAgIC8vIHBhc3MgKHdoaWNoIHNhdyBpdCBhcyBzdGlsbCBwZW5kaW5nIGFuZCB3cm90ZSBub3RoaW5nKSBhbmRcbiAgICAgICAgLy8gdGhpcyBzd2VlcCB3b3VsZCBvdGhlcndpc2UgZ2V0IE5FSVRIRVIgYSB3YWl0X2NvbXBsZXRlZCBOT1IgYVxuICAgICAgICAvLyBjb250aW51YXRpb24sIGFuZCB0aGUgaW5saW5lIGJhdGNoIGJlbG93IHRoZW4gYmxvY2tzIHRoaXNcbiAgICAgICAgLy8gaW52b2NhdGlvbiBmb3IgdGhlIGZ1bGwgc3RlcCBkdXJhdGlvbiB3aXRoIG5vIHdha2UgYXJtZWRcbiAgICAgICAgLy8gYW55d2hlcmUuIEZvciBgUHJvbWlzZS5yYWNlKHN0ZXAsIHNsZWVwKWAgdGhhdCBzaWxlbnRseSBoYW5kc1xuICAgICAgICAvLyB0aGUgcmFjZSB0byB0aGUgc3RlcDogdGhlIHNsZWVwJ3Mgd2FpdF9jb21wbGV0ZWQgaXMgbmV2ZXJcbiAgICAgICAgLy8gd3JpdHRlbiBhbmQgdGhlIHJ1biBjb21wbGV0ZXMgd2l0aCB0aGUgd3Jvbmcgd2lubmVyLiBUaGVcbiAgICAgICAgLy8gd2luZG93IGJldHdlZW4gdGhlIHR3byBjaGVja3Mgc3BhbnMgdGhpcyBpdGVyYXRpb24ncyBkaXNwYXRjaFxuICAgICAgICAvLyArIGZlZWQgcm91bmQtdHJpcHMsIHNvIG9uIG5ldHdvcmstYmFja2VkIHdvcmxkcyAod29ybGQtdmVyY2VsKVxuICAgICAgICAvLyBhIHNob3J0IHNsZWVwIGxhbmRzIGluIGl0IHJvdXRpbmVseSwgb2JzZXJ2ZWQgYXMgYSB+NTAlXG4gICAgICAgIC8vIHNsZWVwV2luc1JhY2VXb3JrZmxvdyBmYWlsdXJlIHJhdGUgaW4gdGhlIFZlcmNlbCBlMmUgbGVncyxcbiAgICAgICAgLy8gd2hpbGUgd29ybGQtbG9jYWwncyBzdWItbXMgcm91bmQtdHJpcHMgbWFza2VkIGl0IGxvY2FsbHkuIFRoZVxuICAgICAgICAvLyBjb250aW51YXRpb24gaW52b2NhdGlvbidzIHByZS1WTSBlbGFwc2VkIGNoZWNrIHdyaXRlcyB0aGVcbiAgICAgICAgLy8gd2FpdF9jb21wbGV0ZWQgfjFzIGxhdGVyLlxuICAgICAgICBjb25zdCBzZWNvbmRzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKHJlc3VtZU1zIC8gMTAwMCkpO1xuICAgICAgICBpZiAoIXNvb25lc3RXYWl0IHx8IHNlY29uZHMgPCBzb29uZXN0V2FpdC5zZWNvbmRzKSB7XG4gICAgICAgICAgc29vbmVzdFdhaXQgPSB7IGNvcnJlbGF0aW9uSWQ6IHdhaXQuY29ycmVsYXRpb25JZCwgc2Vjb25kcyB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoc29vbmVzdFdhaXQpIHtcbiAgICAgICAgc2NoZWR1bGVkV2FpdENvbnRpbnVhdGlvbnMuYWRkKHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBjb25zdCBhdHRlbXB0ID0gbmV4dFdhaXRDb250aW51YXRpb25BdHRlbXB0KHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgICAgd29ybGQsXG4gICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgIHdhaXRDb250aW51YXRpb246IHtcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc29vbmVzdFdhaXQuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgYXR0ZW1wdCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBnZXRXYWl0Q29udGludWF0aW9uRGlzcGF0Y2goXG4gICAgICAgICAgICBzb29uZXN0V2FpdC5zZWNvbmRzLFxuICAgICAgICAgICAgc29vbmVzdFdhaXQuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIERhdGUubm93KCksXG4gICAgICAgICAgICBhdHRlbXB0XG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB3ZmRpYWcoJ3dhaXRfY29udGludWF0aW9uX3NjaGVkdWxlZCcsIHtcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzb29uZXN0V2FpdC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGRlbGF5U2Vjb25kczogc29vbmVzdFdhaXQuc2Vjb25kcyxcbiAgICAgICAgICBhdHRlbXB0LFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgLy8gRXhlY3V0ZSB0aGUgaW5saW5lIGJhdGNoIGluIHBhcmFsbGVsLiBUaGUgcmVwbGF5IGJ1ZGdldCBpc1xuICAgICAgLy8gcGF1c2VkIHdoaWxlIHN0ZXAgYm9kaWVzIHJ1bjogc3RlcCBkdXJhdGlvbiBpcyBib3VuZGVkIGJ5IHRoZVxuICAgICAgLy8gcGxhdGZvcm0gZnVuY3Rpb24gZHVyYXRpb24sIG5vdCB0aGUgcmVwbGF5IHRpbWVvdXQuIE5PVEUgKGJ5XG4gICAgICAvLyBkZXNpZ24pOiB3aXRoIHRoZSBidWRnZXQgcGFya2VkIHBlciBiYXRjaCwgdGhlIG9ubHkgYm91bmQgb24gaG93XG4gICAgICAvLyBtYW55IGlubGluZSBzdGVwcyBvbmUgaW52b2NhdGlvbiBjYW4gY2hhaW4gaXMgdGhlIHBsYXRmb3JtJ3NcbiAgICAgIC8vIGZ1bmN0aW9uIHRpbWVvdXQ6IHRoZSBTREsgZGVsaWJlcmF0ZWx5IGltcG9zZXMgbm8gY2FwIG9mIGl0c1xuICAgICAgLy8gb3duLCBtYXRjaGluZyB0aGUgbm9kZTp2bSBlbmdpbmUsIHdoZXJlIGEgbG9uZyBzZXF1ZW50aWFsXG4gICAgICAvLyB3b3JrZmxvdyBsaWtld2lzZSBydW5zIHN0ZXAtYnktc3RlcCB1bnRpbCB0aGUgcGxhdGZvcm0gcmVjbGFpbXNcbiAgICAgIC8vIHRoZSBpbnZvY2F0aW9uIGFuZCBhIHJlZGVsaXZlcnkgcmVzdW1lcyBmcm9tIHRoZSBsb2cuXG4gICAgICAvLyBJbmxpbmUgZGVsdGE6IGEgc2luZ2xlIGlubGluZSBzdGVwJ3MgdGVybWluYWwgd3JpdGUgYXNrcyB0aGUgV29ybGRcbiAgICAgIC8vIGZvciBldmVyeXRoaW5nIGFmdGVyIHRoZSBjdXJzb3IgdGhpcyB2aWV3IGhvbGRzLCBzbyB0aGUgc3RlcCdzIG93blxuICAgICAgLy8gZXZlbnRzIChhbmQgYW55dGhpbmcgaW50ZXJsZWF2ZWQpIGFycml2ZSBvbiB0aGUgd3JpdGUncyByZXNwb25zZSBhbmRcbiAgICAgIC8vIHRoZSBmZWVkIGJlbG93IG5lZWRzIG5vIGxpc3RpbmcuIFNhbWUgZ2F0ZSBhcyB0aGUgbm9kZSBlbmdpbmUnc1xuICAgICAgLy8gYHJlcXVlc3RJbmxpbmVEZWx0YWAgKHJ1bnRpbWUudHMpLCB0cmFuc2xhdGVkIHRvIHRoaXMgbG9vcCdzIHRlcm1zOlxuICAgICAgLy9cbiAgICAgIC8vIC0gVGhpcyBzdGVwIGlzIHRoZSBvbmx5IHN0ZXAgb3V0c3RhbmRpbmc6IG5vIG92ZXJmbG93IHNpYmxpbmcgcXVldWVkXG4gICAgICAvLyAgIHRoaXMgaXRlcmF0aW9uLCBubyB1bnNlcmlhbGl6YWJsZSBzaWJsaW5nLCBubyBzdGVwIGZyb20gYW4gZWFybGllclxuICAgICAgLy8gICBpbnZvY2F0aW9uIGhhbmRlZCB0byB0aGUgcXVldWUgYWJvdmUuIFNldmVyYWwgd3JpdGVycyBlYWNoIGRpZmZpbmdcbiAgICAgIC8vICAgYWdhaW5zdCB0aGUgc2FtZSBjdXJzb3Igd291bGQgcHJvZHVjZSBkZWx0YXMgb2Ygd2hpY2ggb25seSB0aGVcbiAgICAgIC8vICAgZmlyc3QgY291bGQgYmUgdGFrZW4uXG4gICAgICAvLyAtIE5vIHdhaXQgaXMgcGVuZGluZy4gQSBgd2FpdF9jb21wbGV0ZWRgIGlzIGEgcmVzb2x1dGlvbiB0aGVcbiAgICAgIC8vICAgd29ya2Zsb3cgaXMgd2FpdGluZyBvbiByYXRoZXIgdGhhbiBhbiBldmVudCBpdCBjYW4gb2JzZXJ2ZSBvbmVcbiAgICAgIC8vICAgaXRlcmF0aW9uIGxhdGUsIHNvIGEgZGVsdGEgdGhhdCBwcmVkYXRlcyBpdCB3b3VsZCBzZXR0bGUgdGhlXG4gICAgICAvLyAgIHNsZWVwIGZyb20gYSB2aWV3IHRoYXQgZG9lcyBub3QgaG9sZCBpdHMgY29tcGxldGlvbjsgdGhlIGxpc3RpbmdcbiAgICAgIC8vICAgYWZ0ZXIgdGhlIHN0ZXAgaXMgd2hhdCByZWFkcyBpdCBpbiBvcmRlci5cbiAgICAgIC8vIC0gVGhlIGxvZyBoYXMgYSBjdXJzb3IgdG8gbmFtZSAodHJhY2tpbmcgb24sIHNvbWV0aGluZyByZWFkKS5cbiAgICAgIGNvbnN0IGhhc1BlbmRpbmdXYWl0ID0gcGVuZGluZ09wZXJhdGlvbnMuc29tZShcbiAgICAgICAgKG9wKSA9PlxuICAgICAgICAgIG9wLnR5cGUgPT09ICd3YWl0JyAmJlxuICAgICAgICAgICFjb21wbGV0ZWRXYWl0SWRzMi5oYXMoKG9wIGFzIFBlbmRpbmdXYWl0KS5jb3JyZWxhdGlvbklkKVxuICAgICAgKTtcbiAgICAgIGNvbnN0IGlubGluZURlbHRhU2luY2VDdXJzb3IgPVxuICAgICAgICBzdGVwT3BzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICBmcmVzaFN0ZXBzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICBpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAhaGFzUGVuZGluZ1dhaXQgJiZcbiAgICAgICAgbG9nVmlldy50cmFja2luZyAmJlxuICAgICAgICB0eXBlb2YgbG9nVmlldy5sb2dDdXJzb3IgPT09ICdzdHJpbmcnXG4gICAgICAgICAgPyBsb2dWaWV3LmxvZ0N1cnNvclxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgYnVkZ2V0LnBhdXNlKCk7XG4gICAgICBsZXQgb3V0Y29tZXM6IFN0ZXBFeGVjdXRpb25SZXN1bHRbXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIG91dGNvbWVzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgaW5saW5lQ2FuZGlkYXRlcy5tYXAoKHN0ZXApID0+XG4gICAgICAgICAgICBydW5TdGVwU2luZ2xlRmxpZ2h0KHJ1bklkLCBzdGVwLmNvcnJlbGF0aW9uSWQsICgpID0+XG4gICAgICAgICAgICAgIChhc3luYyAoKSA9PlxuICAgICAgICAgICAgICAgIGV4ZWN1dGVTdGVwKHtcbiAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd0RlcGxveW1lbnRJZDogd29ya2Zsb3dSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiB3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdCxcbiAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgIHJvb3RSdW5JZCxcbiAgICAgICAgICAgICAgICAgIHN0ZXBJZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgIHJ1blNwZWNWZXJzaW9uOiB3b3JrZmxvd1J1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgICAgIC8vIExhenkgaW5saW5lIGNsYWltOiBzdGVwX2NyZWF0ZWQgaXMgZGVmZXJyZWQgKGRpc3BhdGNoXG4gICAgICAgICAgICAgICAgICAvLyBza2lwcGVkIGl0KSBhbmQgdGhpcyBzdGVwX3N0YXJ0ZWQgY2FycmllcyB0aGUgaW5wdXQsXG4gICAgICAgICAgICAgICAgICAvLyBzbyB0aGUgd29ybGQgY3JlYXRlcyB0aGUgc3RlcCBhdG9taWNhbGx5OlxuICAgICAgICAgICAgICAgICAgLy8gZXhhY3RseS1vbmUtb3duZXIuIEEgY29uY3VycmVudCBjbGFpbWFudCBnZXRzXG4gICAgICAgICAgICAgICAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yIOKGkiB7IHR5cGU6ICdza2lwcGVkJyB9IGFuZCBuZXZlclxuICAgICAgICAgICAgICAgICAgLy8gcnVucyB0aGUgYm9keS4gTWlycm9ycyB0aGUgbm9kZSBlbmdpbmUncyBpbmxpbmUgcGF0aC5cbiAgICAgICAgICAgICAgICAgIGxhenlTdGVwSW5wdXQ6IGF3YWl0IGVuY3J5cHRTZXJpYWxpemVkRGF0YShcbiAgICAgICAgICAgICAgICAgICAgc3RlcC5pbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIC8vIE93bmVyc2hpcCBzdGFtcDogd2FrZSByZXBsYXlzIHNlZSB0aGUgYm9keSBhcyBpblxuICAgICAgICAgICAgICAgICAgLy8gZmxpZ2h0IGluIHRoaXMgaW52b2NhdGlvbiBhbmQgYXJtIGEgZGVsYXllZCBiYWNrc3RvcFxuICAgICAgICAgICAgICAgICAgLy8gaW5zdGVhZCBvZiBpbW1lZGlhdGVseSByZXF1ZXVlaW5nIHRoZSBzdGVwLlxuICAgICAgICAgICAgICAgICAgb3duZXJNZXNzYWdlSWQsXG4gICAgICAgICAgICAgICAgICAvLyBBIGxhenkgc3RlcCBpcyBicmFuZC1uZXcgYnkgY29uc3RydWN0aW9uOiBmaXJzdFxuICAgICAgICAgICAgICAgICAgLy8gYXR0ZW1wdC5cbiAgICAgICAgICAgICAgICAgIGF1dGhvcml0YXRpdmVBdHRlbXB0OiAxLFxuICAgICAgICAgICAgICAgICAgLi4uKGlubGluZURlbHRhU2luY2VDdXJzb3IgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICA/IHsgaW5saW5lRGVsdGFTaW5jZUN1cnNvciB9XG4gICAgICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgICAgIH0pKSgpXG4gICAgICAgICAgICApXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYnVkZ2V0LnJlc3VtZSgpO1xuICAgICAgfVxuICAgICAgaW5saW5lU3RlcHNFeGVjdXRlZCArPSBpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aDtcblxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHN0ZXAgPSBpbmxpbmVDYW5kaWRhdGVzW2ldO1xuICAgICAgICBjb25zdCBvdXRjb21lID0gb3V0Y29tZXNbaV07XG4gICAgICAgIGV4ZWN1dGVkU3RlcElkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIG91dGNvbWUudHlwZSA9PT0gJ2NvbXBsZXRlZCcgJiZcbiAgICAgICAgICBvdXRjb21lLmlubGluZURlbHRhICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICBpbmxpbmVEZWx0YVNpbmNlQ3Vyc29yICE9PSB1bmRlZmluZWRcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgYWR2YW5jZWQgPSBsb2dWaWV3LmFic29yYkRlbHRhKFxuICAgICAgICAgICAgaW5saW5lRGVsdGFTaW5jZUN1cnNvcixcbiAgICAgICAgICAgIG91dGNvbWUuaW5saW5lRGVsdGFcbiAgICAgICAgICApO1xuICAgICAgICAgIHdmZGlhZygnaW5saW5lX2RlbHRhX2Fic29yYmVkJywge1xuICAgICAgICAgICAgaXRlcmF0aW9uLFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgZXZlbnRzOiBvdXRjb21lLmlubGluZURlbHRhLmV2ZW50cy5sZW5ndGgsXG4gICAgICAgICAgICBoYXNNb3JlOiBvdXRjb21lLmlubGluZURlbHRhLmhhc01vcmUsXG4gICAgICAgICAgICBjdXJzb3JBZHZhbmNlZDogYWR2YW5jZWQsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG91dGNvbWUudHlwZSA9PT0gJ3JldHJ5JyB8fCBvdXRjb21lLnR5cGUgPT09ICd0aHJvdHRsZWQnKSB7XG4gICAgICAgICAgLy8gSGFuZCB0aGUgc3RlcCB0byB0aGUgcXVldWUgd2l0aCB0aGUgcmVxdWVzdGVkIGJhY2tvZmY6XG4gICAgICAgICAgLy8gYmFja2dyb3VuZCBkZWxpdmVyeSBkcml2ZXMgdGhlIHJldHJ5IGZyb20gaGVyZS5cbiAgICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChzdGVwLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIGF3YWl0IHF1ZXVlU3RlcE1lc3NhZ2Uoe1xuICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgIGRlbGF5U2Vjb25kczogb3V0Y29tZS50aW1lb3V0U2Vjb25kcyxcbiAgICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICAvLyBTdWZmaXhlZCBrZXk6IHRoaXMgc3RlcCB3YXMgaW5saW5lLWNsYWltZWQsIHNvIG5vIGRpc3BhdGNoXG4gICAgICAgICAgICAvLyBwdWJsaXNoIGV4aXN0cyB1bmRlciB0aGUgZGlzcGF0Y2gga2V5LCBidXQgc3VmZml4aW5nXG4gICAgICAgICAgICAvLyBrZWVwcyB0aGUgcmV0cnkgZW5xdWV1ZWFibGUgZXZlbiBpZiBhIHdvcmxkIHJldGlyZWQgYVxuICAgICAgICAgICAgLy8gaGlzdG9yaWNhbCBrZXkgZm9yIHRoaXMgc3RlcCAoc2VlIHRoZSBwdXJwb3NlIGRvY3MgYWJvdmUpLlxuICAgICAgICAgICAgcHVycG9zZTogJ3JldHJ5OjEnLFxuICAgICAgICAgICAgd2ZkaWFnLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKG91dGNvbWUudHlwZSA9PT0gJ2dvbmUnKSB7XG4gICAgICAgICAgcnVuR29uZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gJ3NraXBwZWQnOiBhIGNvbmN1cnJlbnQgaW52b2NhdGlvbiB3b24gdGhlIGxhenkgY3JlYXRlLWNsYWltIGFuZFxuICAgICAgICAvLyBvd25zIHRoZSBib2R5LiBNYXJrZWQgZXhlY3V0ZWQgYWJvdmUgc28gdGhpcyBpbnZvY2F0aW9uIG5ldmVyXG4gICAgICAgIC8vIHJlLWNsYWltcyBpdDsgdGhlIHdpbm5lcidzIHRlcm1pbmFsIGV2ZW50cyBhcnJpdmUgdmlhIHRoZSBmZWVkXG4gICAgICAgIC8vIChvciBkcml2ZSBhIHNlcGFyYXRlIGludm9jYXRpb24pLlxuICAgICAgfVxuICAgICAgd2ZkaWFnKCdpbmxpbmVfc3RlcHNfZXhlY3V0ZWQnLCB7XG4gICAgICAgIGl0ZXJhdGlvbixcbiAgICAgICAgY291bnQ6IGlubGluZUNhbmRpZGF0ZXMubGVuZ3RoLFxuICAgICAgICBvdXRjb21lczogb3V0Y29tZXMubWFwKChvKSA9PiBvLnR5cGUpLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEZlZWQgdGhlIGlubGluZSBiYXRjaCdzIHRlcm1pbmFsIGV2ZW50cyBpbnRvIHRoZSBsaXZlIFZNLiBXaGVuXG4gICAgICAvLyB0aGUgZXZlbnR1YWxseS1jb25zaXN0ZW50IGxpc3RpbmcgaGFzIG5vdCBzdXJmYWNlZCB0aGVtIHlldCxcbiAgICAgIC8vIGV4aXRpbmcgbXVzdCBOT1QgYWNrIHNpbGVudGx5OiB0aGUgdGVybWluYWxzIHRoaXMgaW52b2NhdGlvbiBqdXN0XG4gICAgICAvLyBjYXVzZWQgYXJlIGR1cmFibHkgd3JpdHRlbiB3aXRoIG5vIHF1ZXVlIG1lc3NhZ2UgbGVmdCB0byBjb25zdW1lXG4gICAgICAvLyB0aGVtIChpbmxpbmUgc3RlcHMgaGF2ZSBub25lKSwgc28gYW4gYXdhaXRpbmdfZXh0ZXJuYWwgZXhpdCB3b3VsZFxuICAgICAgLy8gcGFyayB0aGUgcnVuICdydW5uaW5nJyB3aXRoIGFsbCBpdHMgc3RlcHMgY29tcGxldGUuIFJhaXNlIHRoZVxuICAgICAgLy8gcmVxdWV1ZSBzaWduYWwgc28gdGhlIHN1c3BlbmRlZCBleGl0IHNjaGVkdWxlcyBhIGZyZXNoIGltbWVkaWF0ZVxuICAgICAgLy8gaW52b2NhdGlvbiB3aG9zZSBmcmVzaCByZWFkIHBpY2tzIHRoZSB0ZXJtaW5hbHMgdXAuIE91dGNvbWVzIHRoYXRcbiAgICAgIC8vIHdyb3RlIG5vIHRlcm1pbmFsICgnc2tpcHBlZCc6IGEgY29uY3VycmVudCBjbGFpbWFudCBvd25zIHRoZVxuICAgICAgLy8gYm9keTsgJ2dvbmUnLCByZXRyeS90aHJvdHRsZWQ6IGEgcXVldWUgbWVzc2FnZSBleGlzdHMpIGRvbid0XG4gICAgICAvLyBuZWVkIGl0LCBidXQgc2lnbmFsaW5nIG9uIHRoZW0gdG9vIG9ubHkgY29zdHMgYSBuby1vcCBpbnZvY2F0aW9uXG4gICAgICAvLyBpbiBhbiBhbHJlYWR5LXJhcmUgbGFnIHdpbmRvdy5cbiAgICAgIGNvbnN0IHF1ZXVlZCA9IHRha2VRdWV1ZWRFdmVudHMoKTtcbiAgICAgIGNvbnN0IG5ld0V2ZW50cyA9IHF1ZXVlZC5sZW5ndGggPiAwID8gcXVldWVkIDogYXdhaXQgZmV0Y2hVbnNlZW5FdmVudHMoKTtcbiAgICAgIGlmIChuZXdFdmVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gdHJ1ZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICByZXN1bHQgPSBhd2FpdCBzZXNzaW9uLmNvbnRpbnVlV2l0aEV2ZW50cyhuZXdFdmVudHMpO1xuXG4gICAgICB3ZmRpYWcoJ2lubGluZV9pdGVyYXRpb24nLCB7XG4gICAgICAgIGl0ZXJhdGlvbixcbiAgICAgICAgcGhhc2U6ICdzdGVwcycsXG4gICAgICAgIGZlZEV2ZW50czogbmV3RXZlbnRzLmxlbmd0aCxcbiAgICAgICAgb3V0Y29tZTogcmVzdWx0LmNvbXBsZXRlZFxuICAgICAgICAgID8gJ2NvbXBsZXRlZCdcbiAgICAgICAgICA6IHJlc3VsdC5mYWlsZWRcbiAgICAgICAgICAgID8gJ2ZhaWxlZCdcbiAgICAgICAgICAgIDogJ3N1c3BlbmRlZCcsXG4gICAgICAgIGJ1ZGdldEV4aGF1c3RlZDogYnVkZ2V0LmlzRXhoYXVzdGVkKCksXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgc2Vzc2lvbi5kaXNwb3NlKCk7XG4gIH1cblxuICBwYXJlbnRTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU0lubGluZVN0ZXBzKGlubGluZVN0ZXBzRXhlY3V0ZWQpLFxuICB9KTtcblxuICBpZiAocmVzdWx0LmNvbXBsZXRlZCkge1xuICAgIC8vIFdvcmtmbG93IGNvbXBsZXRlZFxuICAgIHJ1bnRpbWVMb2dnZXIuaW5mbygnUXVpY2tKUyBydW50aW1lOiB3b3JrZmxvdyBjb21wbGV0ZWQnLCB7XG4gICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICB9KTtcbiAgICBwYXJlbnRTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5RdWlja0pTT3V0Y29tZSgnY29tcGxldGVkJyksXG4gICAgfSk7XG5cbiAgICAvLyBGbHVzaCBsZWZ0b3ZlciBwZW5kaW5nIHNpZGUgZWZmZWN0cyAoYWJvcnQgcmVjb3JkaW5ncywgc3lzdGVtLWhvb2tcbiAgICAvLyBkaXNwb3NhbHMsIGZpcmUtYW5kLWZvcmdldCBhdHRyaWJ1dGUvaG9vayBldmVudHMpIEJFRk9SRSB3cml0aW5nXG4gICAgLy8gcnVuX2NvbXBsZXRlZC4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUncyBkcmFpblBlbmRpbmdRdWV1ZUl0ZW1zLlxuICAgIC8vIERyYWluIGZhaWx1cmVzIGFyZSBzd2FsbG93ZWQ6IHRoZSB3b3JrZmxvdydzIG93biBvdXRjb21lIGlzIHRoZVxuICAgIC8vIHNvdXJjZSBvZiB0cnV0aC5cbiAgICBpZiAocmVzdWx0LmNvbXBsZXRlZC5kcmFpbk9wZXJhdGlvbnM/Lmxlbmd0aCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZGlzcGF0Y2hQZW5kaW5nT3BzKHtcbiAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICBuZXh0VHJhY2VDYXJyaWVyLFxuICAgICAgICAgIC8vIFBsYWluIGNyZWF0ZTogdGhlIHJ1biBpcyBlbmRpbmcsIG5vdGhpbmcgcmVwbGF5cyBpdHMgbG9nLCBzbyBhXG4gICAgICAgICAgLy8gcGFnZSBoYW5kZWQgYmFjayBoZXJlIHdvdWxkIGJlIHJlYWQgYnkgbm8gb25lLlxuICAgICAgICAgIGNyZWF0ZUV2ZW50OiB0ZXJtaW5hbENyZWF0ZUV2ZW50LFxuICAgICAgICAgIHBlbmRpbmdPcGVyYXRpb25zOiByZXN1bHQuY29tcGxldGVkLmRyYWluT3BlcmF0aW9ucyxcbiAgICAgICAgICB3ZmRpYWcsXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybignUXVpY2tKUyBydW50aW1lOiB0ZXJtaW5hbCBkcmFpbiBmYWlsZWQnLCB7XG4gICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgbWVzc2FnZTogKGVyciBhcyBFcnJvcik/Lm1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBydW5fY29tcGxldGVkIGV2ZW50LlxuICAgIC8vIFRoZSBWTSBzZXJpYWxpemVzIHRoZSB3b3JrZmxvdyByZXN1bHQgYXMgZm9ybWF0LXByZWZpeGVkIGRldmFsdWUgYnl0ZXNcbiAgICAvLyAoXCJkZXZsXCIgKyBkZXZhbHVlKSB3aXRoIG5vIGVuY3J5cHRpb24gKHRoZSBWTSBoYXMgbm8gYWNjZXNzIHRvIHRoZVxuICAgIC8vIENyeXB0b0tleSkuIEhvc3Qtc2lkZSBlbmNyeXB0aW9uIGlzIGFwcGxpZWQgaGVyZSBzbyB0aGF0IGBydW5fY29tcGxldGVkYFxuICAgIC8vIGV2ZW50cyBoYXZlIHRoZSBzYW1lIGBlbmNyYC1wcmVmaXhlZCBwYXlsb2FkIHNoYXBlIHRoYXQgdGhlIG5vZGU6dm1cbiAgICAvLyBlbmdpbmUncyBgZGVoeWRyYXRlV29ya2Zsb3dSZXR1cm5WYWx1ZWAgcHJvZHVjZXMuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRlcm1pbmFsQ3JlYXRlRXZlbnQoe1xuICAgICAgICBldmVudFR5cGU6ICdydW5fY29tcGxldGVkJyxcbiAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICBvdXRwdXQ6IGF3YWl0IGVuY3J5cHRTZXJpYWxpemVkRGF0YShcbiAgICAgICAgICAgIHJlc3VsdC5jb21wbGV0ZWQucmVzdWx0LFxuICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIHdmZGlhZygnZXhpdF9jb21wbGV0ZWQnLCB7IHJlc3VsdDogJ3J1bl9jb21wbGV0ZWRfd3JpdHRlbicgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8IFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAnV29ya2Zsb3cgYWxyZWFkeSBmaW5pc2hlZCwgc2tpcHBpbmcgcnVuX2NvbXBsZXRlZCcsXG4gICAgICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCB9XG4gICAgICAgICk7XG4gICAgICAgIHdmZGlhZygnZXhpdF9jb21wbGV0ZWQnLCB7IHJlc3VsdDogJ2FscmVhZHlfZmluaXNoZWQnIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB3ZmRpYWcoJ2V4aXRfY29tcGxldGVkX2Vycm9yJywge1xuICAgICAgICBlcnJvck5hbWU6IChlcnIgYXMgRXJyb3IpPy5uYW1lLFxuICAgICAgICBlcnJvck1lc3NhZ2U6IChlcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9IGVsc2UgaWYgKHJlc3VsdC5zdXNwZW5kZWQpIHtcbiAgICAvLyBXb3JrZmxvdyBzdGlsbCBzdXNwZW5kZWQgYWZ0ZXIgdGhlIGlubGluZSBsb29wLiBBbGwgZHVyYWJsZSBzaWRlXG4gICAgLy8gZWZmZWN0cyBmb3IgdGhlIGZpbmFsIHN1c3BlbnNpb24gc3RhdGUgd2VyZSBhbHJlYWR5IGRpc3BhdGNoZWQgYnlcbiAgICAvLyB0aGUgbG9vcDsgd2hhdCByZW1haW5zIGlzIGRlY2lkaW5nIGhvdyB0aGUgcnVuIGdldHMgcmUtaW52b2tlZC5cbiAgICBjb25zdCB7IHBlbmRpbmdPcGVyYXRpb25zIH0gPSByZXN1bHQuc3VzcGVuZGVkO1xuXG4gICAgcnVudGltZUxvZ2dlci5pbmZvKCdRdWlja0pTIHJ1bnRpbWU6IHdvcmtmbG93IHN1c3BlbmRlZCcsIHtcbiAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgaW5saW5lU3RlcHNFeGVjdXRlZCxcbiAgICAgIHBlbmRpbmdTdGVwczogcGVuZGluZ09wZXJhdGlvbnMuZmlsdGVyKChwKSA9PiBwLnR5cGUgPT09ICdzdGVwJykubGVuZ3RoLFxuICAgICAgcGVuZGluZ1dhaXRzOiBwZW5kaW5nT3BlcmF0aW9ucy5maWx0ZXIoKHApID0+IHAudHlwZSA9PT0gJ3dhaXQnKS5sZW5ndGgsXG4gICAgICBwZW5kaW5nT3BzOiBwZW5kaW5nT3BlcmF0aW9ucy5tYXAoKHApID0+ICh7XG4gICAgICAgIHR5cGU6IHAudHlwZSxcbiAgICAgICAgY29ycmVsYXRpb25JZDogcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICBoYXNDcmVhdGVkRXZlbnQ6IHAuaGFzQ3JlYXRlZEV2ZW50LFxuICAgICAgICAuLi4ocC50eXBlID09PSAnc3RlcCcgPyB7IHN0ZXBJZDogKHAgYXMgUGVuZGluZ1N0ZXApLnN0ZXBJZCB9IDoge30pLFxuICAgICAgfSkpLFxuICAgIH0pO1xuXG4gICAgcGFyZW50U3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU091dGNvbWUoJ3N1c3BlbmRlZCcpLFxuICAgICAgLi4uQXR0cmlidXRlLlF1aWNrSlNQZW5kaW5nT3BzQ291bnQocGVuZGluZ09wZXJhdGlvbnMubGVuZ3RoKSxcbiAgICB9KTtcblxuICAgIGlmIChydW5Hb25lKSB7XG4gICAgICAvLyBUaGUgcnVuIG5vIGxvbmdlciBleGlzdHMgKGV4cGlyZWQgLyBkZWxldGVkKSwgc28gbm90aGluZyB0byBkcml2ZS5cbiAgICAgIHdmZGlhZygnZXhpdF9zdXNwZW5kZWQnLCB7IGFjdGlvbjogJ3J1bl9nb25lJyB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBFeGl0IHJlcXVldWVzIGFyZSBGUkVTSCBtZXNzYWdlcywgbmV2ZXIgYSBgeyB0aW1lb3V0U2Vjb25kcyB9YFxuICAgIC8vIHZpc2liaWxpdHktcmVkZWxpdmVyeSBvZiB0aGUgY3VycmVudCBtZXNzYWdlLiBSZWRlbGl2ZXJpbmcgdGhlXG4gICAgLy8gQ1VSUkVOVCBtZXNzYWdlIGlzIGEgdHJhcDogYSBob29rLXJlc3VtZSBkZWxpdmVyeSBjYXJyaWVzXG4gICAgLy8gYGhvb2tJbnB1dGAsIGFuZCBpdHMgcmVkZWxpdmVyeSByZS1ydW5zIHRoZSBsYXp5LXJlc3VtZSByZS1lbnN1cmVcbiAgICAvLyBpbiB0aGUgaGFuZGxlciBwcm9sb2d1ZTogaWYgdGhlIHdvcmtmbG93IGRpc3Bvc2VkIHRoYXQgaG9va1xuICAgIC8vIGR1cmluZyB0aGlzIGludm9jYXRpb24gKGRpc3Bvc2Ug4oaSIHNsZWVwKSwgYSB3b3JsZCB0aGF0IHJlamVjdHNcbiAgICAvLyB0aGUgcmUtZW5zdXJlIHdvdWxkIGFjayB0aGUgbWVzc2FnZSBhcyBcIm5vdGhpbmcgbGVmdCB0byByZXN1bWVcIlxuICAgIC8vIGFuZCB0aGUgY29udGludWF0aW9uIGl0IGNhcnJpZWQgaXMgc2lsZW50bHkgbG9zdC4gQSBmcmVzaCBtZXNzYWdlXG4gICAgLy8gY2FycmllcyBvbmx5IGBydW5JZGAsIHNvIGl0cyBkZWxpdmVyeSBhbHdheXMgcmVhY2hlcyByZXBsYXkgKGFuZFxuICAgIC8vIHVuZGVyIHR1cmJvIGEgcmVzY2hlZHVsZSB3b3VsZCByZS1lbmdhZ2UgdHVyYm8gYWdhaW5zdCBhIHN0YWxlXG4gICAgLy8gcHJlbG9hZGVkIGxvZzogc2VlIHRoZSByZWludm9rZSgpIGRvY3MgaW4gcnVudGltZS50cykuXG4gICAgY29uc3QgcmVxdWV1ZUltbWVkaWF0ZWx5ID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgYXdhaXQgcXVldWVNZXNzYWdlKFxuICAgICAgICB3b3JsZCxcbiAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICB7XG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgcmVxdWVzdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfTtcblxuICAgIGlmIChidWRnZXQuaXNFeGhhdXN0ZWQoKSkge1xuICAgICAgLy8gVGhlIGxvb3Agc3RvcHBlZCBvbiB0aGUgcmVwbGF5IGJ1ZGdldCB3aXRoIHByb2dyZXNzIHN0aWxsXG4gICAgICAvLyBwb3NzaWJsZSwgc28gY29udGludWUgaW4gYSBmcmVzaCBpbnZvY2F0aW9uLlxuICAgICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHsgYWN0aW9uOiAnYnVkZ2V0X2V4aGF1c3RlZF9yZXF1ZXVlJyB9KTtcbiAgICAgIGF3YWl0IHJlcXVldWVJbW1lZGlhdGVseSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEV4aXQgd2FpdCBzd2VlcC4gQSB3YWl0IHRoYXQgZWxhcHNlZCBpbiB0aGUgd2luZG93IHNpbmNlIHRoZVxuICAgIC8vIGxvb3AncyBsYXN0IGNoZWNrIHJlcXVldWVzIGltbWVkaWF0ZWx5IChpdHMgd2FpdF9jb21wbGV0ZWQgaXNcbiAgICAvLyB3cml0dGVuIGJ5IHRoZSBuZXh0IGludm9jYXRpb24ncyBlbGFwc2VkLXdhaXQgcGFzcyk7IHBlbmRpbmcgd2FpdHNcbiAgICAvLyB3aG9zZSBjb250aW51YXRpb24gdGhlIGxvb3AgYWxyZWFkeSBlbnF1ZXVlZCBhcmUgc2tpcHBlZC5cbiAgICBsZXQgc29vbmVzdFdhaXQ6IHsgc2Vjb25kczogbnVtYmVyOyBjb3JyZWxhdGlvbklkOiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbiAgICBsZXQgaGFzRWxhcHNlZFdhaXQgPSBmYWxzZTtcbiAgICBmb3IgKGNvbnN0IG9wIG9mIHBlbmRpbmdPcGVyYXRpb25zKSB7XG4gICAgICBpZiAob3AudHlwZSAhPT0gJ3dhaXQnKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHdhaXQgPSBvcCBhcyBQZW5kaW5nV2FpdDtcbiAgICAgIGNvbnN0IHJlc3VtZU1zID0gbmV3IERhdGUod2FpdC5yZXN1bWVBdCkuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKTtcbiAgICAgIGlmIChyZXN1bWVNcyA8PSAwKSB7XG4gICAgICAgIGhhc0VsYXBzZWRXYWl0ID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoIXNjaGVkdWxlZFdhaXRDb250aW51YXRpb25zLmhhcyh3YWl0LmNvcnJlbGF0aW9uSWQpKSB7XG4gICAgICAgIGNvbnN0IHRpbWVvdXRTZWNvbmRzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKHJlc3VtZU1zIC8gMTAwMCkpO1xuICAgICAgICBpZiAoIXNvb25lc3RXYWl0IHx8IHRpbWVvdXRTZWNvbmRzIDwgc29vbmVzdFdhaXQuc2Vjb25kcykge1xuICAgICAgICAgIHNvb25lc3RXYWl0ID0ge1xuICAgICAgICAgICAgc2Vjb25kczogdGltZW91dFNlY29uZHMsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiB3YWl0LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChoYXNFbGFwc2VkV2FpdCkge1xuICAgICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHsgYWN0aW9uOiAnd2FpdF9lbGFwc2VkX3JlcXVldWUnIH0pO1xuICAgICAgYXdhaXQgcmVxdWV1ZUltbWVkaWF0ZWx5KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHBlbmRpbmdSZXF1ZXVlU2lnbmFsKSB7XG4gICAgICAvLyBUaGlzIGludm9jYXRpb24gd3JvdGUgZXZlbnRzIHRoZSB3b3JrZmxvdyBuZWVkcyB0byBjb25zdW1lXG4gICAgICAvLyAoYXR0cl9zZXQgLyBnZXRDb25mbGljdC1hd2FpdGVkIGhvb2tfY3JlYXRlZCAvIGlubGluZSBzdGVwXG4gICAgICAvLyB0ZXJtaW5hbHMpIGJ1dCB0aGUgZXZlbnR1YWxseS1jb25zaXN0ZW50IGxpc3RpbmcgbmV2ZXIgcmV0dXJuZWRcbiAgICAgIC8vIHRoZW0gYmVmb3JlIHRoZSBsb29wIGV4aXRlZC4gV2l0aG91dCBhIHJlcXVldWUgdGhlIHJ1biB3b3VsZFxuICAgICAgLy8gcGFyayBhd2FpdGluZ19leHRlcm5hbCB3aXRoIGl0cyB1bmJsb2NraW5nIGV2ZW50cyBhbHJlYWR5XG4gICAgICAvLyBkdXJhYmx5IHdyaXR0ZW4gYW5kIG5vIGZ1dHVyZSBpbnZvY2F0aW9uIGNvbWluZywgc28gcmVxdWV1ZVxuICAgICAgLy8gaW1tZWRpYXRlbHkgc28gYSBmcmVzaCByZWFkIHBpY2tzIHRoZW0gdXAuIEluIHRoZSBjb21tb24gY2FzZVxuICAgICAgLy8gdGhlIGxvb3AncyBvd24gZmVlZCBvYnNlcnZlcyB0aGUgd3JpdGVzIGFuZCBjbGVhcnMgdGhpcyBmbGFnLCBzb1xuICAgICAgLy8gdGhpcyBvbmx5IGZpcmVzIHdoZW4gdGhlIHJlYWQgYWN0dWFsbHkgbGFnZ2VkLlxuICAgICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHsgYWN0aW9uOiAndW5yZWFkX3NlbGZfd3JpdGVfcmVxdWV1ZScgfSk7XG4gICAgICBhd2FpdCByZXF1ZXVlSW1tZWRpYXRlbHkoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc29vbmVzdFdhaXQpIHtcbiAgICAgIC8vIERlbGF5ZWQgY29udGludWF0aW9uIGZvciB0aGUgc29vbmVzdCBwZW5kaW5nIHdhaXQgdGhlIGxvb3AgaGFzXG4gICAgICAvLyBub3QgYWxyZWFkeSBzY2hlZHVsZWQuIFRoZSBkaXNwYXRjaCBoZWxwZXIgaGFuZGxlcyBkZWxheVxuICAgICAgLy8gY2xhbXBpbmcgKGxvbmcgd2FpdHMgY2hhaW4gYWNyb3NzIGhvcHMpIGFuZCBpZGVtcG90ZW5jeS1rZXlcbiAgICAgIC8vIGRlZHVwIG9mIHJlLW9ic2VydmF0aW9ucyBvZiB0aGUgc2FtZSBwZW5kaW5nIHdhaXQuIFNlZVxuICAgICAgLy8gcnVudGltZS93YWl0LWNvbnRpbnVhdGlvbi50cy5cbiAgICAgIHdmZGlhZygnZXhpdF9zdXNwZW5kZWQnLCB7XG4gICAgICAgIGFjdGlvbjogJ3NjaGVkdWxlX3dhaXRfdGltZW91dCcsXG4gICAgICAgIHRpbWVvdXRTZWNvbmRzOiBzb29uZXN0V2FpdC5zZWNvbmRzLFxuICAgICAgICB3YWl0Q29ycmVsYXRpb25JZDogc29vbmVzdFdhaXQuY29ycmVsYXRpb25JZCxcbiAgICAgIH0pO1xuICAgICAgc2NoZWR1bGVkV2FpdENvbnRpbnVhdGlvbnMuYWRkKHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgY29uc3QgYXR0ZW1wdCA9IG5leHRXYWl0Q29udGludWF0aW9uQXR0ZW1wdChzb29uZXN0V2FpdC5jb3JyZWxhdGlvbklkKTtcbiAgICAgIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICAgICAgd29ybGQsXG4gICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93UnVuLndvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAge1xuICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgIHRyYWNlQ2FycmllcjogYXdhaXQgbmV4dFRyYWNlQ2FycmllcigpLFxuICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIHdhaXRDb250aW51YXRpb246IHtcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBhdHRlbXB0LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGdldFdhaXRDb250aW51YXRpb25EaXNwYXRjaChcbiAgICAgICAgICBzb29uZXN0V2FpdC5zZWNvbmRzLFxuICAgICAgICAgIHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgRGF0ZS5ub3coKSxcbiAgICAgICAgICBhdHRlbXB0XG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHtcbiAgICAgIGFjdGlvbjogJ2F3YWl0aW5nX2V4dGVybmFsJyxcbiAgICAgIHBlbmRpbmdPcHNDb3VudDogcGVuZGluZ09wZXJhdGlvbnMubGVuZ3RoLFxuICAgIH0pO1xuICB9IGVsc2UgaWYgKHJlc3VsdC5mYWlsZWQpIHtcbiAgICAvLyBXb3JrZmxvdyBmYWlsZWQsIHNvIHJlbWFwIHN0YWNrIHRyYWNlIHVzaW5nIGlubGluZSBzb3VyY2UgbWFwcy5cbiAgICAvLyBGcmFtZXMgY2FycnkgdGhlIHJ1bidzIHdvcmtmbG93SWQgYXMgdGhlaXIgZmlsZW5hbWUgb24gdGhlIGZyZXNoXG4gICAgLy8gcGF0aCwgYnV0IHRoZSB3b3JrZmxvdy1pbmRlcGVuZGVudCBCQVNFTElORV9CVU5ETEVfRklMRU5BTUUgb24gdGhlXG4gICAgLy8gc25hcHNob3QgcGF0aCAodGhlIG5hbWUgaXMgYmFrZWQgaW50byB0aGUgc2hhcmVkIGJhc2VsaW5lJ3NcbiAgICAvLyBjb21waWxlZCBjb2RlIGF0IGh5ZHJhdGUpLCBzbyByZW1hcCBhZ2FpbnN0IGJvdGguIHJlbWFwRXJyb3JTdGFja1xuICAgIC8vIGVhcmx5LWV4aXRzIG9uIGEgY2hlYXAgaW5jbHVkZXMoKSB3aGVuIGEgZmlsZW5hbWUgaGFzIG5vIGZyYW1lcy5cbiAgICBsZXQgZXJyb3JTdGFjayA9IHJlc3VsdC5mYWlsZWQuc3RhY2s7XG4gICAgaWYgKGVycm9yU3RhY2spIHtcbiAgICAgIGNvbnN0IHBhcnNlZE5hbWUgPSBwYXJzZVdvcmtmbG93TmFtZSh3b3JrZmxvd05hbWUpO1xuICAgICAgY29uc3QgZmlsZW5hbWUgPSBwYXJzZWROYW1lPy5tb2R1bGVTcGVjaWZpZXIgfHwgd29ya2Zsb3dOYW1lO1xuICAgICAgZXJyb3JTdGFjayA9IHJlbWFwRXJyb3JTdGFjayhlcnJvclN0YWNrLCBmaWxlbmFtZSwgd29ya2Zsb3dDb2RlKTtcbiAgICAgIGVycm9yU3RhY2sgPSByZW1hcEVycm9yU3RhY2soXG4gICAgICAgIGVycm9yU3RhY2ssXG4gICAgICAgIEJBU0VMSU5FX0JVTkRMRV9GSUxFTkFNRSxcbiAgICAgICAgd29ya2Zsb3dDb2RlXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENsYXNzaWZ5IHRoZSBlcnJvciBzbyBjb25zdW1lcnMgKGBydW4ucmV0dXJuVmFsdWVgLCBvYnNlcnZhYmlsaXR5KVxuICAgIC8vIGdldCBgVVNFUl9FUlJPUmAgLyBgUlVOVElNRV9FUlJPUmAgb24gYGVycm9yLmNhdXNlLmNvZGVgLCBtYXRjaGluZ1xuICAgIC8vIHdoYXQgdGhlIG5vZGU6dm0gZW5naW5lIGFscmVhZHkgZG9lcyBpbiBydW50aW1lLnRzLlxuICAgIC8vXG4gICAgLy8gVGhlIFZNIHNlcmlhbGl6ZXMgZXJyb3JzIGFzIGB7IG5hbWUsIG1lc3NhZ2UsIHN0YWNrIH1gLCBzbyB3ZVxuICAgIC8vIHJlY29uc3RydWN0IGEgaG9zdC1zaWRlIEVycm9yIG9mIHRoZSBjb3JyZWN0IGNsYXNzIGJhc2VkIG9uIHRoZVxuICAgIC8vIFZNLXNpZGUgYG5hbWVgOiBzcGVjaWZpYyBXb3JrZmxvd1J1bnRpbWVFcnJvciBzdWJjbGFzc2VzIG5lZWRcbiAgICAvLyB0byBiZSBwcmVzZXJ2ZWQgc28gY2xhc3NpZnlSdW5FcnJvcigpIHRhZ3MgdGhlbSBhcyBSVU5USU1FX0VSUk9SLlxuICAgIGNvbnN0IHJlY29uc3RydWN0ZWQ6IEVycm9yID1cbiAgICAgIHJlc3VsdC5mYWlsZWQubmFtZSA9PT0gJ1dvcmtmbG93Tm90UmVnaXN0ZXJlZEVycm9yJ1xuICAgICAgICA/IG5ldyBXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvcih3b3JrZmxvd05hbWUpXG4gICAgICAgIDogcmVzdWx0LmZhaWxlZC5uYW1lID09PSAnRXJyb3InXG4gICAgICAgICAgPyBuZXcgRXJyb3IocmVzdWx0LmZhaWxlZC5tZXNzYWdlKVxuICAgICAgICAgIDogT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IocmVzdWx0LmZhaWxlZC5tZXNzYWdlKSwge1xuICAgICAgICAgICAgICBuYW1lOiByZXN1bHQuZmFpbGVkLm5hbWUsXG4gICAgICAgICAgICB9KTtcbiAgICBjb25zdCBlcnJvckNvZGUgPSBjbGFzc2lmeVJ1bkVycm9yKHJlY29uc3RydWN0ZWQpO1xuXG4gICAgcnVudGltZUxvZ2dlci5lcnJvcignUXVpY2tKUyBydW50aW1lOiB3b3JrZmxvdyBmYWlsZWQnLCB7XG4gICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgIGVycm9yTmFtZTogcmVzdWx0LmZhaWxlZC5uYW1lLFxuICAgICAgZXJyb3JNZXNzYWdlOiByZXN1bHQuZmFpbGVkLm1lc3NhZ2UsXG4gICAgICBlcnJvclN0YWNrLFxuICAgICAgZXJyb3JDb2RlLFxuICAgIH0pO1xuICAgIHBhcmVudFNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgLi4uQXR0cmlidXRlLlF1aWNrSlNPdXRjb21lKCdmYWlsZWQnKSxcbiAgICB9KTtcblxuICAgIC8vIEZsdXNoIGxlZnRvdmVyIHBlbmRpbmcgc2lkZSBlZmZlY3RzIGJlZm9yZSB3cml0aW5nIHJ1bl9mYWlsZWQsXG4gICAgLy8gc2FtZSBkcmFpbiBzZW1hbnRpY3MgYXMgdGhlIGNvbXBsZXRlZCBicmFuY2guXG4gICAgaWYgKHJlc3VsdC5mYWlsZWQuZHJhaW5PcGVyYXRpb25zPy5sZW5ndGgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGRpc3BhdGNoUGVuZGluZ09wcyh7XG4gICAgICAgICAgd29ybGQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICBuYW1lc3BhY2UsXG4gICAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgICBjcmVhdGVFdmVudDogdGVybWluYWxDcmVhdGVFdmVudCxcbiAgICAgICAgICBwZW5kaW5nT3BlcmF0aW9uczogcmVzdWx0LmZhaWxlZC5kcmFpbk9wZXJhdGlvbnMsXG4gICAgICAgICAgd2ZkaWFnLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oJ1F1aWNrSlMgcnVudGltZTogdGVybWluYWwgZHJhaW4gZmFpbGVkJywge1xuICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgIG1lc3NhZ2U6IChlcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgcnVuX2ZhaWxlZCBldmVudC4gU2VyaWFsaXplIHRoZSBlcnJvciB0aHJvdWdoIHRoZVxuICAgIC8vIGZpcnN0LWNsYXNzIGRlaHlkcmF0aW9uIHBpcGVsaW5lIHNvIGNvbnN1bWVycyAoQ0xJLCBvYnNlcnZhYmlsaXR5LFxuICAgIC8vIHJ1bi5yZXR1cm5WYWx1ZSkgZ2V0IHRoZSBzYW1lIGh5ZHJhdGVkIHZhbHVlIHNoYXBlIGFzIHRoZSBub2RlOnZtXG4gICAgLy8gZW5naW5lIGVtaXRzLiBUd28gcGF0aHM6XG4gICAgLy8gICAqIE1vZGVybiAodmFsdWVCeXRlcyBwcmVzZW50KTogdGhlIFZNLXNpZGUgcmVqZWN0aW9uIGhhbmRsZXJcbiAgICAvLyAgICAgc2VyaWFsaXplZCB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlIChFcnJvciBzdWJjbGFzcyB3aXRoXG4gICAgLy8gICAgIGNhdXNlIGNoYWluLCBwbGFpbiBvYmplY3QsIHByaW1pdGl2ZSwgZXRjLikgdXNpbmcgdGhlIFZNJ3NcbiAgICAvLyAgICAgd29ya2Zsb3ctc2VyaWFsaXplLiBQYXNzIHRob3NlIGJ5dGVzIHRocm91Z2ggZGlyZWN0bHkgc29cbiAgICAvLyAgICAgdHlwZSBpZGVudGl0eSwgY2F1c2UgY2hhaW5zLCBhbmQgbm9uLUVycm9yIHRocm93cyBzdXJ2aXZlLlxuICAgIC8vICAgICBBcHBseSBlbmNyeXB0aW9uIGlmIGNvbmZpZ3VyZWQgKHRoZSBWTSdzXG4gICAgLy8gICAgIHNlcmlhbGl6ZXIgZG9lc24ndCBoYXZlIGFjY2VzcyB0byB0aGUgZW5jcnlwdGlvbiBrZXkpLlxuICAgIC8vICAgKiBMZWdhY3kgZmFsbGJhY2s6IHJlY29uc3RydWN0IGFuIEVycm9yIGZyb20gdGhlIGhvc3QtdmlzaWJsZVxuICAgIC8vICAgICB7bmFtZSwgbWVzc2FnZSwgc3RhY2t9IGZpZWxkcyBhbmQgcnVuIGl0IHRocm91Z2hcbiAgICAvLyAgICAgYGRlaHlkcmF0ZVJ1bkVycm9yYC4gVXNlZCB3aGVuIHZhbHVlQnl0ZXMgaXMgYWJzZW50IChlLmcuXG4gICAgLy8gICAgIGV4dHJhY3RFcnJvciBwc2V1ZG8tZmFpbHVyZXMgZnJvbSBWTSBib290c3RyYXApLlxuICAgIGxldCBkZWh5ZHJhdGVkRXJyb3I6IFVpbnQ4QXJyYXk7XG4gICAgaWYgKHJlc3VsdC5mYWlsZWQudmFsdWVCeXRlcykge1xuICAgICAgLy8gSHlkcmF0ZSB0aGUgVk0tc2lkZSBieXRlcywgcmVtYXAgdGhlIGVycm9yIHN0YWNrIHdpdGggdGhlXG4gICAgICAvLyBob3N0LXNpZGUgc291cmNlIG1hcCAodGhlIFZNIGNhbid0IGRvIHRoaXM6IGl0IGxhY2tzIGJvdGggdGhlXG4gICAgICAvLyBzb3VyY2UgbWFwIGFuZCBgcmVtYXBFcnJvclN0YWNrYCksIGFuZCByZS1kZWh5ZHJhdGUuIFRoaXNcbiAgICAgIC8vIHByZXNlcnZlcyB0aGUgb3JpZ2luYWwgdmFsdWUncyB0eXBlIGlkZW50aXR5IC8gY2F1c2UgY2hhaW5cbiAgICAgIC8vIHdoaWxlIGZpeGluZyB1cCBmcmFtZXMgdG8gcG9pbnQgYXQgdGhlIHVzZXIncyBzb3VyY2UgZmlsZXMuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBoeWRyYXRlZCA9IGF3YWl0IGh5ZHJhdGVSdW5FcnJvcihcbiAgICAgICAgICByZXN1bHQuZmFpbGVkLnZhbHVlQnl0ZXMsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgdW5kZWZpbmVkIC8vIFZNIGJ5dGVzIGFyZSB1bmVuY3J5cHRlZFxuICAgICAgICApO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgaHlkcmF0ZWQgJiZcbiAgICAgICAgICB0eXBlb2YgaHlkcmF0ZWQgPT09ICdvYmplY3QnICYmXG4gICAgICAgICAgJ3N0YWNrJyBpbiAoaHlkcmF0ZWQgYXMgb2JqZWN0KSAmJlxuICAgICAgICAgIHR5cGVvZiAoaHlkcmF0ZWQgYXMgeyBzdGFjaz86IHVua25vd24gfSkuc3RhY2sgPT09ICdzdHJpbmcnXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZE5hbWUgPSBwYXJzZVdvcmtmbG93TmFtZSh3b3JrZmxvd05hbWUpO1xuICAgICAgICAgIGNvbnN0IGZpbGVuYW1lID0gcGFyc2VkTmFtZT8ubW9kdWxlU3BlY2lmaWVyIHx8IHdvcmtmbG93TmFtZTtcbiAgICAgICAgICAvLyBCb3RoIGZpbGVuYW1lIHNwYWNlcy4gU2VlIHRoZSBmYWlsZWQtYnJhbmNoIGNvbW1lbnQgYWJvdmUuXG4gICAgICAgICAgKGh5ZHJhdGVkIGFzIHsgc3RhY2s/OiBzdHJpbmcgfSkuc3RhY2sgPSByZW1hcEVycm9yU3RhY2soXG4gICAgICAgICAgICByZW1hcEVycm9yU3RhY2soXG4gICAgICAgICAgICAgIChoeWRyYXRlZCBhcyB7IHN0YWNrOiBzdHJpbmcgfSkuc3RhY2ssXG4gICAgICAgICAgICAgIGZpbGVuYW1lLFxuICAgICAgICAgICAgICB3b3JrZmxvd0NvZGVcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBCQVNFTElORV9CVU5ETEVfRklMRU5BTUUsXG4gICAgICAgICAgICB3b3JrZmxvd0NvZGVcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFdhbGsgdGhlIGNhdXNlIGNoYWluIGFuZCByZW1hcCBuZXN0ZWQgc3RhY2tzIHRvby5cbiAgICAgICAgY29uc3Qgc2VlbiA9IG5ldyBXZWFrU2V0PG9iamVjdD4oKTtcbiAgICAgICAgbGV0IG5vZGUgPSAoaHlkcmF0ZWQgYXMgeyBjYXVzZT86IHVua25vd24gfSk/LmNhdXNlO1xuICAgICAgICB3aGlsZSAobm9kZSAmJiB0eXBlb2Ygbm9kZSA9PT0gJ29iamVjdCcgJiYgIXNlZW4uaGFzKG5vZGUgYXMgb2JqZWN0KSkge1xuICAgICAgICAgIHNlZW4uYWRkKG5vZGUgYXMgb2JqZWN0KTtcbiAgICAgICAgICBjb25zdCBub2RlU3RhY2sgPSAobm9kZSBhcyB7IHN0YWNrPzogdW5rbm93biB9KS5zdGFjaztcbiAgICAgICAgICBpZiAodHlwZW9mIG5vZGVTdGFjayA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZE5hbWUgPSBwYXJzZVdvcmtmbG93TmFtZSh3b3JrZmxvd05hbWUpO1xuICAgICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBwYXJzZWROYW1lPy5tb2R1bGVTcGVjaWZpZXIgfHwgd29ya2Zsb3dOYW1lO1xuICAgICAgICAgICAgLy8gQm90aCBmaWxlbmFtZSBzcGFjZXMuIFNlZSB0aGUgZmFpbGVkLWJyYW5jaCBjb21tZW50IGFib3ZlLlxuICAgICAgICAgICAgKG5vZGUgYXMgeyBzdGFjaz86IHN0cmluZyB9KS5zdGFjayA9IHJlbWFwRXJyb3JTdGFjayhcbiAgICAgICAgICAgICAgcmVtYXBFcnJvclN0YWNrKG5vZGVTdGFjaywgZmlsZW5hbWUsIHdvcmtmbG93Q29kZSksXG4gICAgICAgICAgICAgIEJBU0VMSU5FX0JVTkRMRV9GSUxFTkFNRSxcbiAgICAgICAgICAgICAgd29ya2Zsb3dDb2RlXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBub2RlID0gKG5vZGUgYXMgeyBjYXVzZT86IHVua25vd24gfSkuY2F1c2U7XG4gICAgICAgIH1cbiAgICAgICAgZGVoeWRyYXRlZEVycm9yID0gYXdhaXQgZGVoeWRyYXRlUnVuRXJyb3IoXG4gICAgICAgICAgaHlkcmF0ZWQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAocmVoeWRyYXRlRXJyKSB7XG4gICAgICAgIC8vIElmIGh5ZHJhdGlvbiAvIHJlLWRlaHlkcmF0aW9uIGZhaWxzIGZvciBhbnkgcmVhc29uLCBmYWxsXG4gICAgICAgIC8vIGJhY2sgdG8gcGFzc2luZyB0aHJvdWdoIHRoZSBvcmlnaW5hbCBWTSBieXRlcyAoYXBwbHlpbmdcbiAgICAgICAgLy8gZW5jcnlwdGlvbiBpZiBjb25maWd1cmVkKS4gQmV0dGVyIHRvIGxvc2Ugc291cmNlLW1hcHBlZFxuICAgICAgICAvLyBmcmFtZXMgdGhhbiB0byBsb3NlIHRoZSBlcnJvciBlbnRpcmVseS5cbiAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAgICdRdWlja0pTIHJ1bnRpbWU6IGZhaWxlZCB0byByZW1hcCB3b3JrZmxvdyBlcnJvciBzdGFjaywgcGFzc2luZyBWTSBieXRlcyB0aHJvdWdoJyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IChyZWh5ZHJhdGVFcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgZGVoeWRyYXRlZEVycm9yID0gKGF3YWl0IG1heWJlRW5jcnlwdChcbiAgICAgICAgICByZXN1bHQuZmFpbGVkLnZhbHVlQnl0ZXMsXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApKSBhcyBVaW50OEFycmF5O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoZXJyb3JTdGFjaykge1xuICAgICAgICByZWNvbnN0cnVjdGVkLnN0YWNrID0gZXJyb3JTdGFjaztcbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGRlaHlkcmF0ZWRFcnJvciA9IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIHJlY29uc3RydWN0ZWQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoc2VyRXJyKSB7XG4gICAgICAgIC8vIEZhbGwgYmFjayB0byBhIG1pbmltYWwgcGF5bG9hZCBzbyB0aGUgcnVuIHN0aWxsIHRlcm1pbmF0ZXNcbiAgICAgICAgLy8gZXZlbiB3aGVuIHRoZSBlcnJvciBpdHNlbGYgY29udGFpbnMgdW5zZXJpYWxpemFibGUgdmFsdWVzLlxuICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAgICAgJ1F1aWNrSlMgcnVudGltZTogZmFpbGVkIHRvIGRlaHlkcmF0ZSBydW4gZXJyb3IsIGZhbGxpbmcgYmFjayB0byBiYXJlIEVycm9yJyxcbiAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBtZXNzYWdlOiAoc2VyRXJyIGFzIEVycm9yKT8ubWVzc2FnZSB9XG4gICAgICAgICk7XG4gICAgICAgIGRlaHlkcmF0ZWRFcnJvciA9IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKHJlc3VsdC5mYWlsZWQubWVzc2FnZSksIHtcbiAgICAgICAgICAgIG5hbWU6IHJlc3VsdC5mYWlsZWQubmFtZSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0ZXJtaW5hbENyZWF0ZUV2ZW50KHtcbiAgICAgICAgZXZlbnRUeXBlOiAncnVuX2ZhaWxlZCcsXG4gICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgZXJyb3I6IGRlaHlkcmF0ZWRFcnJvcixcbiAgICAgICAgICBlcnJvckNvZGUsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikgfHwgUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKCdXb3JrZmxvdyBhbHJlYWR5IGZpbmlzaGVkLCBza2lwcGluZyBydW5fZmFpbGVkJywge1xuICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICB9KTtcbiAgICAgICAgd2ZkaWFnKCdleGl0X2ZhaWxlZCcsIHsgcmVzdWx0OiAnYWxyZWFkeV9maW5pc2hlZCcgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHdmZGlhZygnZXhpdF9mYWlsZWRfZXJyb3InLCB7XG4gICAgICAgIGVycm9yTmFtZTogKGVyciBhcyBFcnJvcik/Lm5hbWUsXG4gICAgICAgIGVycm9yTWVzc2FnZTogKGVyciBhcyBFcnJvcik/Lm1lc3NhZ2UsXG4gICAgICB9KTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gICAgd2ZkaWFnKCdleGl0X2ZhaWxlZCcsIHsgcmVzdWx0OiAncnVuX2ZhaWxlZF93cml0dGVuJyB9KTtcbiAgfVxufVxuIl19