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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +5 -0
  2. package/dist/attribute-changes.d.ts +5 -0
  3. package/dist/attribute-changes.d.ts.map +1 -0
  4. package/dist/attribute-changes.js +25 -0
  5. package/dist/capabilities.d.ts +35 -2
  6. package/dist/capabilities.d.ts.map +1 -1
  7. package/dist/capabilities.js +74 -5
  8. package/dist/capture-stack.d.ts +1 -1
  9. package/dist/capture-stack.js +2 -2
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +19 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +98 -6
  16. package/dist/context-violation-error.d.ts +5 -5
  17. package/dist/context-violation-error.d.ts.map +1 -1
  18. package/dist/context-violation-error.js +8 -6
  19. package/dist/create-hook.d.ts +72 -7
  20. package/dist/create-hook.d.ts.map +1 -1
  21. package/dist/create-hook.js +1 -1
  22. package/dist/define-hook.js +2 -2
  23. package/dist/describe-error.d.ts +7 -7
  24. package/dist/describe-error.d.ts.map +1 -1
  25. package/dist/describe-error.js +97 -12
  26. package/dist/encryption.d.ts +38 -4
  27. package/dist/encryption.d.ts.map +1 -1
  28. package/dist/encryption.js +96 -14
  29. package/dist/events-consumer.d.ts +297 -0
  30. package/dist/events-consumer.d.ts.map +1 -1
  31. package/dist/events-consumer.js +673 -42
  32. package/dist/flushable-stream.d.ts +97 -1
  33. package/dist/flushable-stream.d.ts.map +1 -1
  34. package/dist/flushable-stream.js +291 -11
  35. package/dist/global.d.ts +36 -2
  36. package/dist/global.d.ts.map +1 -1
  37. package/dist/global.js +21 -6
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -2
  41. package/dist/log-format.d.ts +2 -2
  42. package/dist/log-format.js +19 -12
  43. package/dist/logger.d.ts +1 -0
  44. package/dist/logger.d.ts.map +1 -1
  45. package/dist/logger.js +10 -6
  46. package/dist/private.d.ts +226 -9
  47. package/dist/private.d.ts.map +1 -1
  48. package/dist/private.js +626 -7
  49. package/dist/replay-divergence.d.ts +25 -0
  50. package/dist/replay-divergence.d.ts.map +1 -0
  51. package/dist/replay-divergence.js +61 -0
  52. package/dist/replay-payload-cache.d.ts +64 -0
  53. package/dist/replay-payload-cache.d.ts.map +1 -0
  54. package/dist/replay-payload-cache.js +158 -0
  55. package/dist/runtime/compute-instance.d.ts +13 -0
  56. package/dist/runtime/compute-instance.d.ts.map +1 -0
  57. package/dist/runtime/compute-instance.js +14 -0
  58. package/dist/runtime/constants.d.ts +315 -0
  59. package/dist/runtime/constants.d.ts.map +1 -1
  60. package/dist/runtime/constants.js +502 -16
  61. package/dist/runtime/count-step-started-events.d.ts +52 -0
  62. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  63. package/dist/runtime/count-step-started-events.js +72 -0
  64. package/dist/runtime/deployment-guard.d.ts +99 -0
  65. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  66. package/dist/runtime/deployment-guard.js +154 -0
  67. package/dist/runtime/get-port-lazy.d.ts +15 -0
  68. package/dist/runtime/get-port-lazy.d.ts.map +1 -1
  69. package/dist/runtime/get-port-lazy.js +75 -6
  70. package/dist/runtime/get-world-lazy.d.ts +5 -14
  71. package/dist/runtime/get-world-lazy.d.ts.map +1 -1
  72. package/dist/runtime/get-world-lazy.js +19 -29
  73. package/dist/runtime/helpers.d.ts +415 -29
  74. package/dist/runtime/helpers.d.ts.map +1 -1
  75. package/dist/runtime/helpers.js +686 -57
  76. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  77. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  78. package/dist/runtime/quickjs-assets.generated.js +30 -0
  79. package/dist/runtime/quickjs-entrypoint.d.ts +158 -0
  80. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  81. package/dist/runtime/quickjs-entrypoint.js +1863 -0
  82. package/dist/runtime/quickjs-log-view.d.ts +129 -0
  83. package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
  84. package/dist/runtime/quickjs-log-view.js +229 -0
  85. package/dist/runtime/quickjs-runtime.d.ts +244 -0
  86. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  87. package/dist/runtime/quickjs-runtime.js +2427 -0
  88. package/dist/runtime/quickjs-serde.d.ts +107 -0
  89. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  90. package/dist/runtime/quickjs-serde.js +2159 -0
  91. package/dist/runtime/replay-budget.d.ts +97 -0
  92. package/dist/runtime/replay-budget.d.ts.map +1 -0
  93. package/dist/runtime/replay-budget.js +139 -0
  94. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  95. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  96. package/dist/runtime/replay-recovery-reporter.js +64 -0
  97. package/dist/runtime/resume-hook.d.ts +91 -8
  98. package/dist/runtime/resume-hook.d.ts.map +1 -1
  99. package/dist/runtime/resume-hook.js +512 -89
  100. package/dist/runtime/resume-latency.d.ts +150 -0
  101. package/dist/runtime/resume-latency.d.ts.map +1 -0
  102. package/dist/runtime/resume-latency.js +155 -0
  103. package/dist/runtime/run-id-time.d.ts +19 -0
  104. package/dist/runtime/run-id-time.d.ts.map +1 -0
  105. package/dist/runtime/run-id-time.js +42 -0
  106. package/dist/runtime/run.d.ts +72 -7
  107. package/dist/runtime/run.d.ts.map +1 -1
  108. package/dist/runtime/run.js +280 -53
  109. package/dist/runtime/runs.d.ts +54 -3
  110. package/dist/runtime/runs.d.ts.map +1 -1
  111. package/dist/runtime/runs.js +126 -16
  112. package/dist/runtime/start.d.ts +101 -2
  113. package/dist/runtime/start.d.ts.map +1 -1
  114. package/dist/runtime/start.js +352 -61
  115. package/dist/runtime/step-executor.d.ts +186 -5
  116. package/dist/runtime/step-executor.d.ts.map +1 -1
  117. package/dist/runtime/step-executor.js +768 -130
  118. package/dist/runtime/step-latency.d.ts +220 -0
  119. package/dist/runtime/step-latency.d.ts.map +1 -0
  120. package/dist/runtime/step-latency.js +215 -0
  121. package/dist/runtime/step-ownership.d.ts +72 -0
  122. package/dist/runtime/step-ownership.d.ts.map +1 -0
  123. package/dist/runtime/step-ownership.js +114 -0
  124. package/dist/runtime/step-single-flight.d.ts +12 -0
  125. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  126. package/dist/runtime/step-single-flight.js +75 -0
  127. package/dist/runtime/suspension-handler.d.ts +247 -7
  128. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  129. package/dist/runtime/suspension-handler.js +1304 -125
  130. package/dist/runtime/unserializable-step.d.ts +34 -0
  131. package/dist/runtime/unserializable-step.d.ts.map +1 -0
  132. package/dist/runtime/unserializable-step.js +52 -0
  133. package/dist/runtime/vm-mode.d.ts +44 -0
  134. package/dist/runtime/vm-mode.d.ts.map +1 -0
  135. package/dist/runtime/vm-mode.js +62 -0
  136. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  137. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  138. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  139. package/dist/runtime/wait-continuation.d.ts +106 -0
  140. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  141. package/dist/runtime/wait-continuation.js +136 -0
  142. package/dist/runtime/wait-until.d.ts +18 -0
  143. package/dist/runtime/wait-until.d.ts.map +1 -0
  144. package/dist/runtime/wait-until.js +42 -0
  145. package/dist/runtime/world-compatibility.d.ts +32 -0
  146. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  147. package/dist/runtime/world-compatibility.js +44 -0
  148. package/dist/runtime/world-init.d.ts +17 -42
  149. package/dist/runtime/world-init.d.ts.map +1 -1
  150. package/dist/runtime/world-init.js +18 -43
  151. package/dist/runtime/world.d.ts +14 -2
  152. package/dist/runtime/world.d.ts.map +1 -1
  153. package/dist/runtime/world.js +75 -19
  154. package/dist/runtime.d.ts +10 -6
  155. package/dist/runtime.d.ts.map +1 -1
  156. package/dist/runtime.js +3911 -489
  157. package/dist/sealed-box.d.ts +167 -0
  158. package/dist/sealed-box.d.ts.map +1 -0
  159. package/dist/sealed-box.js +571 -0
  160. package/dist/serialization/client.d.ts +3 -3
  161. package/dist/serialization/client.d.ts.map +1 -1
  162. package/dist/serialization/client.js +8 -4
  163. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  164. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  165. package/dist/serialization/codec-devalue-vm.js +148 -0
  166. package/dist/serialization/codec-devalue.d.ts +1 -1
  167. package/dist/serialization/codec-devalue.d.ts.map +1 -1
  168. package/dist/serialization/codec-devalue.js +24 -6
  169. package/dist/serialization/codec.d.ts +37 -2
  170. package/dist/serialization/codec.d.ts.map +1 -1
  171. package/dist/serialization/codec.js +2 -2
  172. package/dist/serialization/compression.d.ts +105 -0
  173. package/dist/serialization/compression.d.ts.map +1 -0
  174. package/dist/serialization/compression.js +261 -0
  175. package/dist/serialization/encryption.d.ts +119 -17
  176. package/dist/serialization/encryption.d.ts.map +1 -1
  177. package/dist/serialization/encryption.js +152 -17
  178. package/dist/serialization/errors.d.ts +13 -0
  179. package/dist/serialization/errors.d.ts.map +1 -1
  180. package/dist/serialization/errors.js +20 -2
  181. package/dist/serialization/format.d.ts +6 -6
  182. package/dist/serialization/format.js +7 -7
  183. package/dist/serialization/hardened.d.ts +156 -0
  184. package/dist/serialization/hardened.d.ts.map +1 -0
  185. package/dist/serialization/hardened.js +538 -0
  186. package/dist/serialization/index.d.ts +10 -8
  187. package/dist/serialization/index.d.ts.map +1 -1
  188. package/dist/serialization/index.js +10 -8
  189. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  190. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  191. package/dist/serialization/reducers/class-vm.js +77 -0
  192. package/dist/serialization/reducers/class.d.ts.map +1 -1
  193. package/dist/serialization/reducers/class.js +11 -6
  194. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  195. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  196. package/dist/serialization/reducers/common-vm.js +616 -0
  197. package/dist/serialization/reducers/common.d.ts +1 -1
  198. package/dist/serialization/reducers/common.d.ts.map +1 -1
  199. package/dist/serialization/reducers/common.js +202 -62
  200. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  201. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  202. package/dist/serialization/reducers/step-function-vm.js +97 -0
  203. package/dist/serialization/reducers/step-function.d.ts.map +1 -1
  204. package/dist/serialization/reducers/step-function.js +25 -9
  205. package/dist/serialization/step.d.ts +4 -4
  206. package/dist/serialization/step.d.ts.map +1 -1
  207. package/dist/serialization/step.js +9 -5
  208. package/dist/serialization/types.d.ts +80 -1
  209. package/dist/serialization/types.d.ts.map +1 -1
  210. package/dist/serialization/types.js +15 -1
  211. package/dist/serialization/workflow-vm.d.ts +29 -0
  212. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  213. package/dist/serialization/workflow-vm.js +74 -0
  214. package/dist/serialization-format.d.ts +64 -8
  215. package/dist/serialization-format.d.ts.map +1 -1
  216. package/dist/serialization-format.js +225 -73
  217. package/dist/serialization.d.ts +262 -34
  218. package/dist/serialization.d.ts.map +1 -1
  219. package/dist/serialization.js +1885 -277
  220. package/dist/set-attributes.d.ts +13 -0
  221. package/dist/set-attributes.d.ts.map +1 -0
  222. package/dist/set-attributes.js +60 -0
  223. package/dist/source-map.d.ts +25 -0
  224. package/dist/source-map.d.ts.map +1 -1
  225. package/dist/source-map.js +154 -10
  226. package/dist/step/context-storage.d.ts +63 -2
  227. package/dist/step/context-storage.d.ts.map +1 -1
  228. package/dist/step/context-storage.js +7 -5
  229. package/dist/step/writable-stream.d.ts +3 -3
  230. package/dist/step/writable-stream.d.ts.map +1 -1
  231. package/dist/step/writable-stream.js +80 -13
  232. package/dist/step.d.ts.map +1 -1
  233. package/dist/step.js +148 -27
  234. package/dist/symbols.d.ts +50 -0
  235. package/dist/symbols.d.ts.map +1 -1
  236. package/dist/symbols.js +51 -1
  237. package/dist/telemetry/semantic-conventions.d.ts +433 -2
  238. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  239. package/dist/telemetry/semantic-conventions.js +319 -3
  240. package/dist/telemetry.d.ts +91 -0
  241. package/dist/telemetry.d.ts.map +1 -1
  242. package/dist/telemetry.js +244 -17
  243. package/dist/test-support/orchestrator-context.d.ts +25 -0
  244. package/dist/test-support/orchestrator-context.d.ts.map +1 -0
  245. package/dist/test-support/orchestrator-context.js +107 -0
  246. package/dist/types.d.ts +6 -0
  247. package/dist/types.d.ts.map +1 -1
  248. package/dist/types.js +23 -1
  249. package/dist/util.d.ts +0 -5
  250. package/dist/util.d.ts.map +1 -1
  251. package/dist/util.js +1 -15
  252. package/dist/version.d.ts +1 -1
  253. package/dist/version.d.ts.map +1 -1
  254. package/dist/version.js +2 -2
  255. package/dist/vm/index.d.ts.map +1 -1
  256. package/dist/vm/index.js +84 -14
  257. package/dist/vm/script-cache.d.ts +26 -0
  258. package/dist/vm/script-cache.d.ts.map +1 -0
  259. package/dist/vm/script-cache.js +131 -0
  260. package/dist/vm/uint8array-base64.js +1 -1
  261. package/dist/workflow/abort-controller.d.ts +2 -2
  262. package/dist/workflow/abort-controller.d.ts.map +1 -1
  263. package/dist/workflow/abort-controller.js +88 -21
  264. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  265. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  266. package/dist/workflow/attribute-dispatcher.js +45 -0
  267. package/dist/workflow/create-hook.d.ts.map +1 -1
  268. package/dist/workflow/create-hook.js +24 -3
  269. package/dist/workflow/get-workflow-metadata.js +2 -2
  270. package/dist/workflow/hook.d.ts.map +1 -1
  271. package/dist/workflow/hook.js +304 -47
  272. package/dist/workflow/index.d.ts +1 -0
  273. package/dist/workflow/index.d.ts.map +1 -1
  274. package/dist/workflow/index.js +2 -1
  275. package/dist/workflow/set-attributes.d.ts +68 -0
  276. package/dist/workflow/set-attributes.d.ts.map +1 -0
  277. package/dist/workflow/set-attributes.js +60 -0
  278. package/dist/workflow/sleep.d.ts.map +1 -1
  279. package/dist/workflow/sleep.js +58 -12
  280. package/dist/workflow/world-init-stub.d.ts +3 -3
  281. package/dist/workflow/world-init-stub.js +4 -4
  282. package/dist/workflow.d.ts +95 -3
  283. package/dist/workflow.d.ts.map +1 -1
  284. package/dist/workflow.js +900 -561
  285. package/docs/api-reference/create-hook.mdx +89 -10
  286. package/docs/api-reference/create-webhook.mdx +16 -15
  287. package/docs/api-reference/define-hook.mdx +35 -33
  288. package/docs/api-reference/fatal-error.mdx +30 -8
  289. package/docs/api-reference/fetch.mdx +14 -10
  290. package/docs/api-reference/get-step-metadata.mdx +2 -2
  291. package/docs/api-reference/get-workflow-metadata.mdx +3 -3
  292. package/docs/api-reference/get-writable.mdx +7 -7
  293. package/docs/api-reference/index.mdx +4 -1
  294. package/docs/api-reference/retryable-error.mdx +1 -1
  295. package/docs/api-reference/set-attributes.mdx +61 -0
  296. package/docs/api-reference/sleep.mdx +4 -4
  297. package/docs/foundations/cancellation.mdx +31 -32
  298. package/docs/foundations/errors-and-retries.mdx +42 -11
  299. package/docs/foundations/hooks.mdx +64 -35
  300. package/docs/foundations/idempotency.mdx +244 -12
  301. package/docs/foundations/index.mdx +1 -23
  302. package/docs/foundations/meta.json +2 -1
  303. package/docs/foundations/serialization.mdx +21 -22
  304. package/docs/foundations/starting-workflows.mdx +106 -30
  305. package/docs/foundations/streaming.mdx +108 -60
  306. package/docs/foundations/versioning.mdx +263 -0
  307. package/docs/foundations/workflows-and-steps.mdx +9 -9
  308. package/docs/how-it-works/cancellation.mdx +63 -63
  309. package/docs/how-it-works/code-transform.mdx +83 -67
  310. package/docs/how-it-works/encryption.mdx +30 -26
  311. package/docs/how-it-works/event-sourcing.mdx +125 -34
  312. package/docs/how-it-works/framework-integrations.mdx +96 -337
  313. package/docs/how-it-works/understanding-directives.mdx +22 -22
  314. package/package.json +24 -15
  315. package/dist/runtime/step-handler.d.ts +0 -2
  316. package/dist/runtime/step-handler.d.ts.map +0 -1
  317. package/dist/runtime/step-handler.js +0 -776
@@ -1,776 +0,0 @@
1
- import { waitUntil } from '@vercel/functions';
2
- import { EntityConflictError, FatalError, RetryableError, RunExpiredError, StepNotRegisteredError, ThrottleError, TooEarlyError, WorkflowRuntimeError, WorkflowWorldError, } from '@workflow/errors';
3
- import { formatStepName, pluralize } from '@workflow/utils';
4
- import { getPort } from '@workflow/utils/get-port';
5
- import { SPEC_VERSION_CURRENT, StepInvokePayloadSchema } from '@workflow/world';
6
- import { describeError } from '../describe-error.js';
7
- import { runtimeLogger, stepLogger } from '../logger.js';
8
- import { getStepFunction } from '../private.js';
9
- import { cancelAbortReaders, dehydrateStepError, dehydrateStepReturnValue, hydrateStepArguments, hydrateStepError, } from '../serialization.js';
10
- import { contextStorage } from '../step/context-storage.js';
11
- import * as Attribute from '../telemetry/semantic-conventions.js';
12
- import { getSpanKind, linkToCurrentContext, serializeTraceCarrier, trace, withTraceContext, } from '../telemetry.js';
13
- import { getErrorName, getErrorStack, normalizeUnknownError, } from '../types.js';
14
- import { MAX_QUEUE_DELIVERIES } from './constants.js';
15
- import { getQueueOverhead, getWorkflowQueueName, handleHealthCheckMessage, memoizeEncryptionKey, parseHealthCheckPayload, queueMessage, withHealthCheck, } from './helpers.js';
16
- import { getWorld, getWorldHandlers } from './world.js';
17
- const DEFAULT_STEP_MAX_RETRIES = 3;
18
- const stepHandler = (worldHandlers) => worldHandlers.createQueueHandler('__wkf_step_', async (message_, metadata) => {
19
- // Check if this is a health check message
20
- // NOTE: Health check messages are intentionally unauthenticated for monitoring purposes.
21
- // They only write a simple status response to a stream and do not expose sensitive data.
22
- // The stream name includes a unique correlationId that must be known by the caller.
23
- const healthCheck = parseHealthCheckPayload(message_);
24
- if (healthCheck) {
25
- await handleHealthCheckMessage(healthCheck, 'step', worldHandlers.specVersion);
26
- return;
27
- }
28
- const { workflowName, workflowRunId, workflowStartedAt, stepId, traceCarrier: traceContext, requestedAt, } = StepInvokePayloadSchema.parse(message_);
29
- const { requestId } = metadata;
30
- // --- Max delivery check ---
31
- // Enforce max delivery limit before any infrastructure calls.
32
- // This prevents runaway steps from consuming infinite queue deliveries.
33
- // At this point, we want to do the minimal amount of work (no fetching
34
- // of the step details, etc. We simply attempt to mark the step as failed
35
- // and enqueue the workflow once, and if either of those fails, the message
36
- // is still consumed but with adequate logging that an error occurred.
37
- // Scoped logger for this step invocation — attaches run/step context to
38
- // every log line below so callers don't repeat it.
39
- const stepNameFromQueue = metadata.queueName.slice('__wkf_step_'.length);
40
- const stepRuntimeLogger = runtimeLogger.forRun(workflowRunId, workflowName, { stepId, stepName: stepNameFromQueue });
41
- if (metadata.attempt > MAX_QUEUE_DELIVERIES) {
42
- stepRuntimeLogger.error(`Step handler exceeded max deliveries (${metadata.attempt}/${MAX_QUEUE_DELIVERIES})`, {
43
- attempt: metadata.attempt,
44
- });
45
- try {
46
- const world = await getWorld();
47
- const getEncryptionKey = memoizeEncryptionKey(world, workflowRunId);
48
- const err = new FatalError(`Step exceeded maximum queue deliveries (${metadata.attempt}/${MAX_QUEUE_DELIVERIES})`);
49
- await world.events.create(workflowRunId, {
50
- eventType: 'step_failed',
51
- specVersion: SPEC_VERSION_CURRENT,
52
- correlationId: stepId,
53
- eventData: {
54
- error: await dehydrateStepError(err, workflowRunId, await getEncryptionKey()),
55
- },
56
- }, { requestId });
57
- // Re-queue the workflow to handle the failed step
58
- await queueMessage(world, getWorkflowQueueName(workflowName), {
59
- runId: workflowRunId,
60
- traceCarrier: await serializeTraceCarrier(),
61
- requestedAt: new Date(),
62
- });
63
- }
64
- catch (err) {
65
- if (EntityConflictError.is(err) || RunExpiredError.is(err)) {
66
- return;
67
- }
68
- // Can't even mark the step as failed. Consume the message to stop
69
- // further retries. The run will remain in its current state.
70
- stepRuntimeLogger.error(`Failed to mark step as failed after ${metadata.attempt} delivery attempts. ` +
71
- `A persistent error is preventing the step from being terminated. ` +
72
- `The run will remain in its current state until manually resolved. ` +
73
- `This is most likely due to a persistent outage of the workflow backend ` +
74
- `or a bug in the workflow runtime and should be reported to the Workflow team.`, {
75
- attempt: metadata.attempt,
76
- errorName: err instanceof Error ? err.name : 'UnknownError',
77
- errorMessage: err instanceof Error ? err.message : String(err),
78
- errorStack: err instanceof Error ? err.stack : undefined,
79
- });
80
- }
81
- return;
82
- }
83
- const spanLinks = await linkToCurrentContext();
84
- // Execute step within the propagated trace context
85
- return await withTraceContext(traceContext, async () => {
86
- // Extract the step name from the topic name
87
- const stepName = metadata.queueName.slice('__wkf_step_'.length);
88
- const world = await getWorld();
89
- const isVercel = process.env.VERCEL_URL !== undefined;
90
- // Memoized accessor for the per-run AES-256 encryption key. The first
91
- // caller (typically `hydrateStepArguments` for input deserialization,
92
- // or one of the early-return dehydrateStepError paths if step_started
93
- // fails) triggers the actual fetch / HKDF derivation; subsequent
94
- // callers await the cached promise. Steps that fail before any
95
- // encryption-aware work happens (e.g. an immediate step_started
96
- // conflict) skip the fetch entirely.
97
- const getEncryptionKey = memoizeEncryptionKey(world, workflowRunId);
98
- // Resolve local async values concurrently before entering the trace span
99
- const [port, spanKind] = await Promise.all([
100
- isVercel ? undefined : getPort(),
101
- getSpanKind('CONSUMER'),
102
- ]);
103
- return trace(`STEP ${stepName}`, { kind: spanKind, links: spanLinks }, async (span) => {
104
- span?.setAttributes({
105
- ...Attribute.StepName(stepName),
106
- ...Attribute.StepAttempt(metadata.attempt),
107
- // Standard OTEL messaging conventions
108
- ...Attribute.MessagingSystem('vercel-queue'),
109
- ...Attribute.MessagingDestinationName(metadata.queueName),
110
- ...Attribute.MessagingMessageId(metadata.messageId),
111
- ...Attribute.MessagingOperationType('process'),
112
- ...getQueueOverhead({ requestedAt }),
113
- });
114
- // Note: Step function validation happens after step_started so we can
115
- // properly fail the step (not the run) if the function is not registered.
116
- // This allows the workflow to handle the step failure gracefully.
117
- const stepFn = getStepFunction(stepName);
118
- span?.setAttributes({
119
- ...Attribute.WorkflowName(workflowName),
120
- ...Attribute.WorkflowRunId(workflowRunId),
121
- ...Attribute.StepId(stepId),
122
- ...Attribute.StepTracePropagated(!!traceContext),
123
- });
124
- // step_started validates state and returns the step entity, so no separate
125
- // world.steps.get() call is needed. The server checks:
126
- // - Step not in terminal state (returns 409)
127
- // - retryAfter timestamp reached (returns 425 with Retry-After header)
128
- // - Workflow still active (returns 410 if completed)
129
- let step;
130
- try {
131
- const startResult = await world.events.create(workflowRunId, {
132
- eventType: 'step_started',
133
- specVersion: SPEC_VERSION_CURRENT,
134
- correlationId: stepId,
135
- }, { requestId });
136
- if (!startResult.step) {
137
- throw new WorkflowRuntimeError(`step_started event for "${stepId}" did not return step entity`);
138
- }
139
- step = startResult.step;
140
- }
141
- catch (err) {
142
- if (ThrottleError.is(err)) {
143
- const retryRetryAfter = Math.max(1, typeof err.retryAfter === 'number' ? err.retryAfter : 1);
144
- stepRuntimeLogger.info('Throttled again on retry, deferring to queue', {
145
- retryAfterSeconds: retryRetryAfter,
146
- });
147
- return { timeoutSeconds: retryRetryAfter };
148
- }
149
- if (RunExpiredError.is(err)) {
150
- // Expected when a run is cancelled while a step is in-flight.
151
- stepRuntimeLogger.info('Workflow run has already completed, skipping step', { errorName: err.name, errorMessage: err.message });
152
- return;
153
- }
154
- if (EntityConflictError.is(err)) {
155
- // Step already in a terminal state — another worker finished
156
- // it or it was retried to completion. Re-enqueue the parent
157
- // workflow so it can observe the outcome.
158
- stepRuntimeLogger.debug('Step in terminal state, re-enqueuing workflow', {
159
- errorName: err.name,
160
- errorMessage: err.message,
161
- });
162
- span?.setAttributes({
163
- ...Attribute.StepSkipped(true),
164
- ...Attribute.StepSkipReason('completed'),
165
- });
166
- span?.addEvent?.('step.skipped', {
167
- 'skip.reason': 'terminal_state',
168
- 'step.name': stepName,
169
- 'step.id': stepId,
170
- });
171
- await queueMessage(world, getWorkflowQueueName(workflowName), {
172
- runId: workflowRunId,
173
- traceCarrier: await serializeTraceCarrier(),
174
- requestedAt: new Date(),
175
- });
176
- return;
177
- }
178
- // Too early: retryAfter timestamp not reached yet
179
- // Return timeout to queue so it retries later
180
- if (TooEarlyError.is(err)) {
181
- const timeoutSeconds = Math.max(1, err.retryAfter ?? 1);
182
- span?.setAttributes({
183
- ...Attribute.StepRetryTimeoutSeconds(timeoutSeconds),
184
- });
185
- // Add span event for delayed retry
186
- span?.addEvent?.('step.delayed', {
187
- 'delay.reason': 'retry_after_not_reached',
188
- 'delay.timeout_seconds': timeoutSeconds,
189
- });
190
- stepRuntimeLogger.debug('Step retryAfter timestamp not yet reached', {
191
- retryAfterSeconds: err.retryAfter,
192
- timeoutSeconds,
193
- });
194
- return { timeoutSeconds };
195
- }
196
- // Re-throw other errors
197
- throw err;
198
- }
199
- stepRuntimeLogger.debug('Step execution details', {
200
- status: step.status,
201
- attempt: step.attempt,
202
- });
203
- span?.setAttributes({
204
- ...Attribute.StepStatus(step.status),
205
- });
206
- // Validate step function exists AFTER step_started so we can
207
- // properly fail the step (not the run) if the function is missing.
208
- // This allows the workflow to handle the step failure gracefully,
209
- // similar to how FatalError is handled.
210
- if (!stepFn || typeof stepFn !== 'function') {
211
- const err = new StepNotRegisteredError(stepName);
212
- stepRuntimeLogger.error('Step function not registered, failing step (not run)', {
213
- errorName: err.name,
214
- errorMessage: err.message,
215
- errorStack: err.stack,
216
- });
217
- // Fail the step via event (event-sourced architecture)
218
- // This matches the FatalError pattern - fail the step and re-queue workflow
219
- try {
220
- await world.events.create(workflowRunId, {
221
- eventType: 'step_failed',
222
- specVersion: SPEC_VERSION_CURRENT,
223
- correlationId: stepId,
224
- eventData: {
225
- error: await dehydrateStepError(err, workflowRunId, await getEncryptionKey()),
226
- },
227
- }, { requestId });
228
- }
229
- catch (stepFailErr) {
230
- if (EntityConflictError.is(stepFailErr)) {
231
- // Step already transitioned to a terminal state — duplicate
232
- // delivery or concurrent cancellation. Drop silently.
233
- stepRuntimeLogger.info('Tried failing step for missing function, but step has already finished.', {
234
- errorName: stepFailErr.name,
235
- errorMessage: stepFailErr.message,
236
- });
237
- return;
238
- }
239
- throw stepFailErr;
240
- }
241
- span?.setAttributes({
242
- ...Attribute.StepStatus('failed'),
243
- ...Attribute.StepFatalError(true),
244
- });
245
- // Re-invoke the workflow to handle the failed step
246
- await queueMessage(world, getWorkflowQueueName(workflowName), {
247
- runId: workflowRunId,
248
- traceCarrier: await serializeTraceCarrier(),
249
- requestedAt: new Date(),
250
- });
251
- return;
252
- }
253
- const maxRetries = stepFn.maxRetries ?? DEFAULT_STEP_MAX_RETRIES;
254
- span?.setAttributes({
255
- ...Attribute.StepMaxRetries(maxRetries),
256
- });
257
- let result;
258
- // Check max retries AFTER step_started (attempt was just incremented)
259
- // step.attempt tracks how many times step_started has been called.
260
- // Note: maxRetries is the number of RETRIES after the first attempt, so total attempts = maxRetries + 1
261
- // Use > here (not >=) because this guards against re-invocation AFTER all attempts are used.
262
- // The post-failure check uses >= to decide whether to retry after a failure.
263
- if (step.attempt > maxRetries + 1) {
264
- const retryCount = step.attempt - 1;
265
- // Persisted message — kept short, no machine `stepName`,
266
- // since observability already attributes the event to a
267
- // specific step.
268
- const errorMessage = `Step exceeded max retries (${retryCount} ${pluralize('retry', 'retries', retryCount)})`;
269
- stepLogger.error(`Step ${formatStepName(stepName)} exceeded max retries (${retryCount} ${pluralize('retry', 'retries', retryCount)})`, {
270
- workflowRunId,
271
- workflowName,
272
- stepId,
273
- stepName,
274
- retryCount,
275
- });
276
- // Fail the step via event (event-sourced architecture).
277
- // Preserve the prior attempt's serialized error as the cause so
278
- // the underlying failure is recoverable from `step.error.cause`
279
- // after hydration, without forcing consumers to walk the
280
- // step_retrying event history. Mirrors the post-failure path
281
- // below that wraps the live `err` as cause.
282
- const wrappedError = new FatalError(errorMessage);
283
- if (step.error != null) {
284
- try {
285
- wrappedError.cause = await hydrateStepError(step.error, workflowRunId, await getEncryptionKey());
286
- }
287
- catch {
288
- // Ignore: best-effort cause attachment, the wrapping
289
- // FatalError stack/message still surface the failure.
290
- }
291
- }
292
- try {
293
- await world.events.create(workflowRunId, {
294
- eventType: 'step_failed',
295
- specVersion: SPEC_VERSION_CURRENT,
296
- correlationId: stepId,
297
- eventData: {
298
- error: await dehydrateStepError(wrappedError, workflowRunId, await getEncryptionKey()),
299
- },
300
- }, { requestId });
301
- }
302
- catch (err) {
303
- if (EntityConflictError.is(err)) {
304
- // Step already transitioned to a terminal state — duplicate
305
- // delivery or concurrent completion. Drop silently.
306
- stepRuntimeLogger.info('Tried failing step, but step has already finished.', {
307
- errorName: err.name,
308
- errorMessage: err.message,
309
- });
310
- return;
311
- }
312
- throw err;
313
- }
314
- span?.setAttributes({
315
- ...Attribute.StepStatus('failed'),
316
- ...Attribute.StepRetryExhausted(true),
317
- });
318
- // Re-invoke the workflow to handle the failed step
319
- await queueMessage(world, getWorkflowQueueName(workflowName), {
320
- runId: workflowRunId,
321
- traceCarrier: await serializeTraceCarrier(),
322
- requestedAt: new Date(),
323
- });
324
- return;
325
- }
326
- // --- Infrastructure: prepare step input ---
327
- // Network/server errors propagate to the queue handler for retry.
328
- // WorkflowRuntimeError (data integrity issues) are fatal — retrying
329
- // won't fix them, so we re-queue the workflow to surface the error.
330
- // step_started already validated the step is in valid state (pending/running)
331
- // and returned the updated step entity with incremented attempt
332
- // step.attempt is now the current attempt number (after increment)
333
- const attempt = step.attempt;
334
- if (!step.startedAt) {
335
- const errorMessage = `Step "${stepId}" has no "startedAt" timestamp`;
336
- stepRuntimeLogger.error('Fatal runtime error during step setup', {
337
- errorMessage,
338
- });
339
- try {
340
- await world.events.create(workflowRunId, {
341
- eventType: 'step_failed',
342
- specVersion: SPEC_VERSION_CURRENT,
343
- correlationId: stepId,
344
- eventData: {
345
- error: await dehydrateStepError(new FatalError(errorMessage), workflowRunId, await getEncryptionKey()),
346
- },
347
- }, { requestId });
348
- }
349
- catch (failErr) {
350
- if (EntityConflictError.is(failErr)) {
351
- return;
352
- }
353
- throw failErr;
354
- }
355
- // Re-queue the workflow so it can process the step failure
356
- await queueMessage(world, getWorkflowQueueName(workflowName), {
357
- runId: workflowRunId,
358
- traceCarrier: await serializeTraceCarrier(),
359
- requestedAt: new Date(),
360
- });
361
- return;
362
- }
363
- // Capture startedAt for use in async callback (TypeScript narrowing doesn't persist)
364
- const stepStartedAt = step.startedAt;
365
- // Resolve the encryption key now that we're committed to running
366
- // user code: input hydration needs it, and `contextStorage` (and
367
- // any user-code paths that run inside it) capture the resolved
368
- // value. Triggers the underlying world / KMS fetch once, with
369
- // subsequent dehydrate paths reusing the memoized result.
370
- const encryptionKey = await getEncryptionKey();
371
- // Hydrate the step input arguments, closure variables, and thisVal
372
- // NOTE: This captures only the synchronous portion of hydration. Any async
373
- // operations (e.g., stream loading) are added to `ops` and executed later
374
- // via Promise.all(ops) - their timing is not included in this measurement.
375
- const ops = [];
376
- const hydratedInput = await trace('step.hydrate', {}, async (hydrateSpan) => {
377
- const startTime = Date.now();
378
- const result = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops);
379
- const durationMs = Date.now() - startTime;
380
- hydrateSpan?.setAttributes({
381
- ...Attribute.StepArgumentsCount(result.args.length),
382
- ...Attribute.QueueDeserializeTimeMs(durationMs),
383
- });
384
- return result;
385
- });
386
- const args = hydratedInput.args;
387
- const thisVal = hydratedInput.thisVal ?? null;
388
- // --- User code execution ---
389
- // Only errors from stepFn.apply() (user step code) should produce
390
- // step_failed/step_retrying. Infrastructure errors (network, server)
391
- // must propagate to the queue handler for automatic retry.
392
- let userCodeError;
393
- let userCodeFailed = false;
394
- const executionStartTime = Date.now();
395
- try {
396
- result = await trace('step.execute', {}, async () => {
397
- return await contextStorage.run({
398
- stepMetadata: {
399
- stepName,
400
- stepId,
401
- stepStartedAt: new Date(+stepStartedAt),
402
- attempt,
403
- },
404
- workflowMetadata: {
405
- workflowName,
406
- workflowRunId,
407
- workflowStartedAt: new Date(+workflowStartedAt),
408
- // TODO: there should be a getUrl method on the world interface itself. This
409
- // solution only works for vercel + local worlds.
410
- url: isVercel
411
- ? `https://${process.env.VERCEL_URL}`
412
- : `http://localhost:${port ?? 3000}`,
413
- features: { encryption: !!encryptionKey },
414
- },
415
- ops,
416
- closureVars: hydratedInput.closureVars,
417
- encryptionKey,
418
- }, () => stepFn.apply(thisVal, args));
419
- });
420
- }
421
- catch (err) {
422
- userCodeError = err;
423
- userCodeFailed = true;
424
- }
425
- const executionTimeMs = Date.now() - executionStartTime;
426
- cancelAbortReaders(...args, thisVal, hydratedInput.closureVars);
427
- span?.setAttributes({
428
- ...Attribute.QueueExecutionTimeMs(executionTimeMs),
429
- });
430
- // --- Dehydrate (serialize) the step's return value ---
431
- // A non-serializable return value is a user-code bug, not an
432
- // infrastructure failure. Route it through the same step-failure
433
- // path as a thrown error so SerializationError (which is marked
434
- // `fatal: true`) short-circuits the retry loop instead of
435
- // bubbling as an HTTP 500 and burning through all 4 queue
436
- // deliveries on a guaranteed-to-fail message.
437
- if (!userCodeFailed) {
438
- try {
439
- result = await trace('step.dehydrate', {}, async (dehydrateSpan) => {
440
- const startTime = Date.now();
441
- const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops);
442
- const durationMs = Date.now() - startTime;
443
- dehydrateSpan?.setAttributes({
444
- ...Attribute.QueueSerializeTimeMs(durationMs),
445
- ...Attribute.StepResultType(typeof dehydrated),
446
- });
447
- return dehydrated;
448
- });
449
- }
450
- catch (err) {
451
- userCodeError = err;
452
- userCodeFailed = true;
453
- }
454
- }
455
- // --- Handle user code errors ---
456
- if (userCodeFailed) {
457
- const err = userCodeError;
458
- // Infrastructure errors that somehow surfaced through user code
459
- // should propagate to the queue handler for retry, not consume
460
- // step attempts.
461
- if (RunExpiredError.is(err)) {
462
- // Workflow has already completed, so no-op
463
- stepLogger.info('Workflow run already completed, skipping step', {
464
- workflowRunId,
465
- stepId,
466
- message: err.message,
467
- });
468
- return;
469
- }
470
- if (WorkflowWorldError.is(err)) {
471
- if (err.status !== undefined && err.status >= 500) {
472
- throw err;
473
- }
474
- }
475
- // Wrap AbortError in FatalError — abort is intentional cancellation, not retryable
476
- let effectiveErr = err;
477
- if (err instanceof Error &&
478
- err.name === 'AbortError' &&
479
- !FatalError.is(err)) {
480
- const fatalErr = new FatalError(`Aborted: ${err.message}`);
481
- fatalErr.stack = err.stack;
482
- effectiveErr = fatalErr;
483
- }
484
- const normalizedError = await normalizeUnknownError(effectiveErr);
485
- const normalizedStack = normalizedError.stack || getErrorStack(effectiveErr) || '';
486
- // Record exception for OTEL error tracking
487
- if (effectiveErr instanceof Error) {
488
- span?.recordException?.(effectiveErr);
489
- }
490
- // Determine error category and retryability
491
- const isFatal = FatalError.is(effectiveErr);
492
- const isRetryable = RetryableError.is(effectiveErr);
493
- const errorCategory = isFatal
494
- ? 'fatal'
495
- : isRetryable
496
- ? 'retryable'
497
- : 'transient';
498
- span?.setAttributes({
499
- ...Attribute.StepErrorName(getErrorName(err)),
500
- ...Attribute.StepErrorMessage(normalizedError.message),
501
- ...Attribute.ErrorType(getErrorName(err)),
502
- ...Attribute.ErrorCategory(errorCategory),
503
- ...Attribute.ErrorRetryable(!isFatal),
504
- });
505
- if (isFatal) {
506
- const description = describeError(err);
507
- const friendlyStep = formatStepName(stepName);
508
- const framing = description.attribution === 'sdk'
509
- ? `Step ${friendlyStep} failed with a FatalError from the SDK runtime — bubbling up to parent workflow`
510
- : `Step ${friendlyStep} threw a FatalError — bubbling up to parent workflow`;
511
- // Mirror the workflow-level log formatting: put the framing +
512
- // stack into the message so console.error renders the stack
513
- // inline, and keep the metadata object small with only the
514
- // structured fields that log drains want to index.
515
- // No `hint` field here — actionable hint text lives on the
516
- // error message itself (so it survives serialization →
517
- // event log → observability rehydrate), and adding it
518
- // again here just duplicates it on stderr.
519
- stepLogger.error(`${framing}\n${normalizedStack || normalizedError.message}`, {
520
- workflowRunId,
521
- stepId,
522
- stepName,
523
- errorAttribution: description.attribution,
524
- errorName: normalizedError.name,
525
- errorMessage: normalizedError.message,
526
- });
527
- // Fail the step via event (event-sourced architecture).
528
- // Serialize the original thrown value so its full type identity
529
- // and custom properties round-trip through the event log.
530
- try {
531
- await world.events.create(workflowRunId, {
532
- eventType: 'step_failed',
533
- specVersion: SPEC_VERSION_CURRENT,
534
- correlationId: stepId,
535
- eventData: {
536
- error: await dehydrateStepError(err, workflowRunId, encryptionKey),
537
- },
538
- }, { requestId });
539
- }
540
- catch (stepFailErr) {
541
- if (EntityConflictError.is(stepFailErr)) {
542
- // Step already in terminal state — idempotent.
543
- stepRuntimeLogger.info('Tried failing step, but step has already finished.', {
544
- errorName: stepFailErr.name,
545
- errorMessage: stepFailErr.message,
546
- });
547
- return;
548
- }
549
- throw stepFailErr;
550
- }
551
- span?.setAttributes({
552
- ...Attribute.StepStatus('failed'),
553
- ...Attribute.StepFatalError(true),
554
- });
555
- }
556
- else {
557
- const maxRetries = stepFn.maxRetries ?? DEFAULT_STEP_MAX_RETRIES;
558
- // step.attempt was incremented by step_started, use it here
559
- const currentAttempt = step.attempt;
560
- span?.setAttributes({
561
- ...Attribute.StepAttempt(currentAttempt),
562
- ...Attribute.StepMaxRetries(maxRetries),
563
- });
564
- // Note: maxRetries is the number of RETRIES after the first attempt, so total attempts = maxRetries + 1
565
- if (currentAttempt >= maxRetries + 1) {
566
- // Max retries reached
567
- const retryCount = step.attempt - 1;
568
- const description = describeError(err);
569
- const friendlyStep = formatStepName(stepName);
570
- const framing = description.attribution === 'sdk'
571
- ? `Step ${friendlyStep} hit max retries on an SDK runtime error — bubbling to parent workflow`
572
- : `Step ${friendlyStep} hit max retries — bubbling error thrown by your step to the parent workflow`;
573
- stepLogger.error(`${framing}\n${normalizedStack || normalizedError.message}`, {
574
- workflowRunId,
575
- workflowName,
576
- stepId,
577
- stepName,
578
- attempt: step.attempt,
579
- retryCount,
580
- errorAttribution: description.attribution,
581
- errorName: normalizedError.name,
582
- errorMessage: normalizedError.message,
583
- });
584
- // Don't include the machine step name in the persisted
585
- // error message — observability already shows which step
586
- // produced the event, and `stepName: 'step//./.../foo'`
587
- // in the title is just noise. The CLI logger renders
588
- // `Step foo (./...) hit max retries` separately.
589
- const errorMessage = `Step failed after ${maxRetries} ${pluralize('retry', 'retries', maxRetries)}: ${normalizedError.message}`;
590
- // Fail the step via event (event-sourced architecture).
591
- // Wrap the original error with a FatalError that preserves
592
- // the wrapped message plus the original thrown value as
593
- // `cause` so it's recoverable after hydration.
594
- const wrappedError = new FatalError(errorMessage);
595
- wrappedError.cause = err;
596
- if (normalizedStack)
597
- wrappedError.stack = normalizedStack;
598
- try {
599
- await world.events.create(workflowRunId, {
600
- eventType: 'step_failed',
601
- specVersion: SPEC_VERSION_CURRENT,
602
- correlationId: stepId,
603
- eventData: {
604
- error: await dehydrateStepError(wrappedError, workflowRunId, encryptionKey),
605
- },
606
- }, { requestId });
607
- }
608
- catch (stepFailErr) {
609
- if (EntityConflictError.is(stepFailErr)) {
610
- // Step already in terminal state — idempotent.
611
- stepRuntimeLogger.info('Tried failing step, but step has already finished.', {
612
- errorName: stepFailErr.name,
613
- errorMessage: stepFailErr.message,
614
- });
615
- return;
616
- }
617
- throw stepFailErr;
618
- }
619
- span?.setAttributes({
620
- ...Attribute.StepStatus('failed'),
621
- ...Attribute.StepRetryExhausted(true),
622
- });
623
- }
624
- else {
625
- // Not at max retries yet - log as a retryable error
626
- if (RetryableError.is(err)) {
627
- stepLogger.info('Encountered RetryableError, step will be retried', {
628
- workflowRunId,
629
- workflowName,
630
- stepId,
631
- stepName,
632
- attempt: currentAttempt,
633
- errorName: err.name,
634
- errorMessage: err.message,
635
- errorStack: normalizedStack,
636
- });
637
- }
638
- else {
639
- stepLogger.info('Encountered Error, step will be retried', {
640
- workflowRunId,
641
- workflowName,
642
- stepId,
643
- stepName,
644
- attempt: currentAttempt,
645
- errorName: normalizedError.name,
646
- errorMessage: normalizedError.message,
647
- errorStack: normalizedStack,
648
- });
649
- }
650
- // Set step to pending for retry via event (event-sourced architecture)
651
- // step_retrying records the error and sets status to pending.
652
- // Serialize the original thrown value so its full type identity
653
- // and custom properties round-trip through the event log.
654
- try {
655
- await world.events.create(workflowRunId, {
656
- eventType: 'step_retrying',
657
- specVersion: SPEC_VERSION_CURRENT,
658
- correlationId: stepId,
659
- eventData: {
660
- error: await dehydrateStepError(err, workflowRunId, encryptionKey),
661
- ...(RetryableError.is(err) && {
662
- retryAfter: err.retryAfter,
663
- }),
664
- },
665
- }, { requestId });
666
- }
667
- catch (stepRetryErr) {
668
- if (EntityConflictError.is(stepRetryErr)) {
669
- // Step already in terminal state — idempotent.
670
- stepRuntimeLogger.info('Tried retrying step, but step has already finished.', {
671
- errorName: stepRetryErr.name,
672
- errorMessage: stepRetryErr.message,
673
- });
674
- return;
675
- }
676
- throw stepRetryErr;
677
- }
678
- const timeoutSeconds = Math.max(1, RetryableError.is(err)
679
- ? Math.ceil((+err.retryAfter.getTime() - Date.now()) / 1000)
680
- : 1);
681
- span?.setAttributes({
682
- ...Attribute.StepRetryTimeoutSeconds(timeoutSeconds),
683
- ...Attribute.StepRetryWillRetry(true),
684
- });
685
- // Add span event for retry scheduling
686
- span?.addEvent?.('retry.scheduled', {
687
- 'retry.timeout_seconds': timeoutSeconds,
688
- 'retry.attempt': currentAttempt,
689
- 'retry.max_retries': maxRetries,
690
- });
691
- // It's a retryable error - so have the queue keep the message visible
692
- // so that it gets retried.
693
- return { timeoutSeconds };
694
- }
695
- }
696
- // Re-invoke the workflow to handle the failed/retrying step
697
- await queueMessage(world, getWorkflowQueueName(workflowName), {
698
- runId: workflowRunId,
699
- traceCarrier: await serializeTraceCarrier(),
700
- requestedAt: new Date(),
701
- });
702
- return;
703
- }
704
- // --- Infrastructure: complete the step ---
705
- // Errors here (network failures, server errors) propagate to the
706
- // queue handler for automatic retry.
707
- //
708
- // NOTE: None of the code from this point is guaranteed to run.
709
- // Since the step might fail or cause a function timeout and the
710
- // process might be SIGKILL'd, the workflow runtime must be
711
- // resilient to the below code not executing on a failed step.
712
- // (Dehydration already happened above and is accounted for in the
713
- // userCodeFailed path.)
714
- waitUntil(Promise.all(ops).catch((err) => {
715
- // Ignore expected client disconnect errors (e.g., browser refresh during streaming)
716
- const isAbortError = err?.name === 'AbortError' || err?.name === 'ResponseAborted';
717
- if (!isAbortError)
718
- throw err;
719
- }));
720
- // Run step_completed and trace serialization concurrently;
721
- // the trace carrier is used in the final queueMessage call below
722
- let stepCompleted409 = false;
723
- const [, traceCarrier] = await Promise.all([
724
- world.events
725
- .create(workflowRunId, {
726
- eventType: 'step_completed',
727
- specVersion: SPEC_VERSION_CURRENT,
728
- correlationId: stepId,
729
- eventData: {
730
- result: result,
731
- },
732
- }, { requestId })
733
- .catch((err) => {
734
- if (EntityConflictError.is(err)) {
735
- // Step already in terminal state — idempotent.
736
- stepRuntimeLogger.info('Tried completing step, but step has already finished.', {
737
- errorName: err.name,
738
- errorMessage: err.message,
739
- });
740
- stepCompleted409 = true;
741
- return;
742
- }
743
- throw err;
744
- }),
745
- serializeTraceCarrier(),
746
- ]);
747
- if (stepCompleted409) {
748
- return;
749
- }
750
- span?.setAttributes({
751
- ...Attribute.StepStatus('completed'),
752
- ...Attribute.StepResultType(typeof result),
753
- });
754
- // Queue the workflow continuation with the concurrently-resolved trace carrier
755
- await queueMessage(world, getWorkflowQueueName(workflowName), {
756
- runId: workflowRunId,
757
- traceCarrier,
758
- requestedAt: new Date(),
759
- });
760
- });
761
- });
762
- });
763
- /**
764
- * A single route that handles any step execution request and routes to the
765
- * appropriate step function. We may eventually want to create different bundles
766
- * for each step, this is temporary.
767
- */
768
- let cachedStepHandler;
769
- export const stepEntrypoint =
770
- /* @__PURE__ */ withHealthCheck(async (req) => {
771
- if (!cachedStepHandler) {
772
- cachedStepHandler = stepHandler(await getWorldHandlers());
773
- }
774
- return cachedStepHandler(req);
775
- });
776
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3RlcC1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM5QyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLFVBQVUsRUFDVixjQUFjLEVBQ2QsZUFBZSxFQUNmLHNCQUFzQixFQUN0QixhQUFhLEVBQ2IsYUFBYSxFQUNiLG9CQUFvQixFQUNwQixrQkFBa0IsR0FDbkIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzVELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDckQsT0FBTyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDekQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRCxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLGtCQUFrQixFQUNsQix3QkFBd0IsRUFDeEIsb0JBQW9CLEVBQ3BCLGdCQUFnQixHQUNqQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFDTCxXQUFXLEVBQ1gsb0JBQW9CLEVBQ3BCLHFCQUFxQixFQUNyQixLQUFLLEVBQ0wsZ0JBQWdCLEdBQ2pCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUNMLFlBQVksRUFDWixhQUFhLEVBQ2IscUJB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InNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHdhaXRVbnRpbCB9IGZyb20gJ0B2ZXJjZWwvZnVuY3Rpb25zJztcbmltcG9ydCB7XG4gIEVudGl0eUNvbmZsaWN0RXJyb3IsXG4gIEZhdGFsRXJyb3IsXG4gIFJldHJ5YWJsZUVycm9yLFxuICBSdW5FeHBpcmVkRXJyb3IsXG4gIFN0ZXBOb3RSZWdpc3RlcmVkRXJyb3IsXG4gIFRocm90dGxlRXJyb3IsXG4gIFRvb0Vhcmx5RXJyb3IsXG4gIFdvcmtmbG93UnVudGltZUVycm9yLFxuICBXb3JrZmxvd1dvcmxkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHsgZm9ybWF0U3RlcE5hbWUsIHBsdXJhbGl6ZSB9IGZyb20gJ0B3b3JrZmxvdy91dGlscyc7XG5pbXBvcnQgeyBnZXRQb3J0IH0gZnJvbSAnQHdvcmtmbG93L3V0aWxzL2dldC1wb3J0JztcbmltcG9ydCB7IFNQRUNfVkVSU0lPTl9DVVJSRU5ULCBTdGVwSW52b2tlUGF5bG9hZFNjaGVtYSB9IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBkZXNjcmliZUVycm9yIH0gZnJvbSAnLi4vZGVzY3JpYmUtZXJyb3IuanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciwgc3RlcExvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBnZXRTdGVwRnVuY3Rpb24gfSBmcm9tICcuLi9wcml2YXRlLmpzJztcbmltcG9ydCB7XG4gIGNhbmNlbEFib3J0UmVhZGVycyxcbiAgZGVoeWRyYXRlU3RlcEVycm9yLFxuICBkZWh5ZHJhdGVTdGVwUmV0dXJuVmFsdWUsXG4gIGh5ZHJhdGVTdGVwQXJndW1lbnRzLFxuICBoeWRyYXRlU3RlcEVycm9yLFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uLmpzJztcbmltcG9ydCB7IGNvbnRleHRTdG9yYWdlIH0gZnJvbSAnLi4vc3RlcC9jb250ZXh0LXN0b3JhZ2UuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQge1xuICBnZXRTcGFuS2luZCxcbiAgbGlua1RvQ3VycmVudENvbnRleHQsXG4gIHNlcmlhbGl6ZVRyYWNlQ2FycmllcixcbiAgdHJhY2UsXG4gIHdpdGhUcmFjZUNvbnRleHQsXG59IGZyb20gJy4uL3RlbGVtZXRyeS5qcyc7XG5pbXBvcnQge1xuICBnZXRFcnJvck5hbWUsXG4gIGdldEVycm9yU3RhY2ssXG4gIG5vcm1hbGl6ZVVua25vd25FcnJvcixcbn0gZnJvbSAnLi4vdHlwZXMuanMnO1xuaW1wb3J0IHsgTUFYX1FVRVVFX0RFTElWRVJJRVMgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQge1xuICBnZXRRdWV1ZU92ZXJoZWFkLFxuICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSxcbiAgaGFuZGxlSGVhbHRoQ2hlY2tNZXNzYWdlLFxuICBtZW1vaXplRW5jcnlwdGlvbktleSxcbiAgcGFyc2VIZWFsdGhDaGVja1BheWxvYWQsXG4gIHF1ZXVlTWVzc2FnZSxcbiAgd2l0aEhlYWx0aENoZWNrLFxufSBmcm9tICcuL2hlbHBlcnMuanMnO1xuaW1wb3J0IHsgZ2V0V29ybGQsIGdldFdvcmxkSGFuZGxlcnMsIHR5cGUgV29ybGRIYW5kbGVycyB9IGZyb20gJy4vd29ybGQuanMnO1xuXG5jb25zdCBERUZBVUxUX1NURVBfTUFYX1JFVFJJRVMgPSAzO1xuXG5jb25zdCBzdGVwSGFuZGxlciA9ICh3b3JsZEhhbmRsZXJzOiBXb3JsZEhhbmRsZXJzKSA9PlxuICB3b3JsZEhhbmRsZXJzLmNyZWF0ZVF1ZXVlSGFuZGxlcihcbiAgICAnX193a2Zfc3RlcF8nLFxuICAgIGFzeW5jIChtZXNzYWdlXywgbWV0YWRhdGEpID0+IHtcbiAgICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZVxuICAgICAgLy8gTk9URTogSGVhbHRoIGNoZWNrIG1lc3NhZ2VzIGFyZSBpbnRlbnRpb25hbGx5IHVuYXV0aGVudGljYXRlZCBmb3IgbW9uaXRvcmluZyBwdXJwb3Nlcy5cbiAgICAgIC8vIFRoZXkgb25seSB3cml0ZSBhIHNpbXBsZSBzdGF0dXMgcmVzcG9uc2UgdG8gYSBzdHJlYW0gYW5kIGRvIG5vdCBleHBvc2Ugc2Vuc2l0aXZlIGRhdGEuXG4gICAgICAvLyBUaGUgc3RyZWFtIG5hbWUgaW5jbHVkZXMgYSB1bmlxdWUgY29ycmVsYXRpb25JZCB0aGF0IG11c3QgYmUga25vd24gYnkgdGhlIGNhbGxlci5cbiAgICAgIGNvbnN0IGhlYWx0aENoZWNrID0gcGFyc2VIZWFsdGhDaGVja1BheWxvYWQobWVzc2FnZV8pO1xuICAgICAgaWYgKGhlYWx0aENoZWNrKSB7XG4gICAgICAgIGF3YWl0IGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgICAgICAgICBoZWFsdGhDaGVjayxcbiAgICAgICAgICAnc3RlcCcsXG4gICAgICAgICAgd29ybGRIYW5kbGVycy5zcGVjVmVyc2lvblxuICAgICAgICApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtcbiAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdCxcbiAgICAgICAgc3RlcElkLFxuICAgICAgICB0cmFjZUNhcnJpZXI6IHRyYWNlQ29udGV4dCxcbiAgICAgICAgcmVxdWVzdGVkQXQsXG4gICAgICB9ID0gU3RlcEludm9rZVBheWxvYWRTY2hlbWEucGFyc2UobWVzc2FnZV8pO1xuICAgICAgY29uc3QgeyByZXF1ZXN0SWQgfSA9IG1ldGFkYXRhO1xuXG4gICAgICAvLyAtLS0gTWF4IGRlbGl2ZXJ5IGNoZWNrIC0tLVxuICAgICAgLy8gRW5mb3JjZSBtYXggZGVsaXZlcnkgbGltaXQgYmVmb3JlIGFueSBpbmZyYXN0cnVjdHVyZSBjYWxscy5cbiAgICAgIC8vIFRoaXMgcHJldmVudHMgcnVuYXdheSBzdGVwcyBmcm9tIGNvbnN1bWluZyBpbmZpbml0ZSBxdWV1ZSBkZWxpdmVyaWVzLlxuICAgICAgLy8gQXQgdGhpcyBwb2ludCwgd2Ugd2FudCB0byBkbyB0aGUgbWluaW1hbCBhbW91bnQgb2Ygd29yayAobm8gZmV0Y2hpbmdcbiAgICAgIC8vIG9mIHRoZSBzdGVwIGRldGFpbHMsIGV0Yy4gV2Ugc2ltcGx5IGF0dGVtcHQgdG8gbWFyayB0aGUgc3RlcCBhcyBmYWlsZWRcbiAgICAgIC8vIGFuZCBlbnF1ZXVlIHRoZSB3b3JrZmxvdyBvbmNlLCBhbmQgaWYgZWl0aGVyIG9mIHRob3NlIGZhaWxzLCB0aGUgbWVzc2FnZVxuICAgICAgLy8gaXMgc3RpbGwgY29uc3VtZWQgYnV0IHdpdGggYWRlcXVhdGUgbG9nZ2luZyB0aGF0IGFuIGVycm9yIG9jY3VycmVkLlxuICAgICAgLy8gU2NvcGVkIGxvZ2dlciBmb3IgdGhpcyBzdGVwIGludm9jYXRpb24g4oCUIGF0dGFjaGVzIHJ1bi9zdGVwIGNvbnRleHQgdG9cbiAgICAgIC8vIGV2ZXJ5IGxvZyBsaW5lIGJlbG93IHNvIGNhbGxlcnMgZG9uJ3QgcmVwZWF0IGl0LlxuICAgICAgY29uc3Qgc3RlcE5hbWVGcm9tUXVldWUgPSBtZXRhZGF0YS5xdWV1ZU5hbWUuc2xpY2UoJ19fd2tmX3N0ZXBfJy5sZW5ndGgpO1xuICAgICAgY29uc3Qgc3RlcFJ1bnRpbWVMb2dnZXIgPSBydW50aW1lTG9nZ2VyLmZvclJ1bihcbiAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICB7IHN0ZXBJZCwgc3RlcE5hbWU6IHN0ZXBOYW1lRnJvbVF1ZXVlIH1cbiAgICAgICk7XG5cbiAgICAgIGlmIChtZXRhZGF0YS5hdHRlbXB0ID4gTUFYX1FVRVVFX0RFTElWRVJJRVMpIHtcbiAgICAgICAgc3RlcFJ1bnRpbWVMb2dnZXIuZXJyb3IoXG4gICAgICAgICAgYFN0ZXAgaGFuZGxlciBleGNlZWRlZCBtYXggZGVsaXZlcmllcyAoJHttZXRhZGF0YS5hdHRlbXB0fS8ke01BWF9RVUVVRV9ERUxJVkVSSUVTfSlgLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGF0dGVtcHQ6IG1ldGFkYXRhLmF0dGVtcHQsXG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGQoKTtcbiAgICAgICAgICBjb25zdCBnZXRFbmNyeXB0aW9uS2V5ID0gbWVtb2l6ZUVuY3J5cHRpb25LZXkod29ybGQsIHdvcmtmbG93UnVuSWQpO1xuICAgICAgICAgIGNvbnN0IGVyciA9IG5ldyBGYXRhbEVycm9yKFxuICAgICAgICAgICAgYFN0ZXAgZXhjZWVkZWQgbWF4aW11bSBxdWV1ZSBkZWxpdmVyaWVzICgke21ldGFkYXRhLmF0dGVtcHR9LyR7TUFYX1FVRVVFX0RFTElWRVJJRVN9KWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgIGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKVxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgLy8gUmUtcXVldWUgdGhlIHdvcmtmbG93IHRvIGhhbmRsZSB0aGUgZmFpbGVkIHN0ZXBcbiAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2Uod29ybGQsIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSksIHtcbiAgICAgICAgICAgIHJ1bklkOiB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBzZXJpYWxpemVUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8IFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIENhbid0IGV2ZW4gbWFyayB0aGUgc3RlcCBhcyBmYWlsZWQuIENvbnN1bWUgdGhlIG1lc3NhZ2UgdG8gc3RvcFxuICAgICAgICAgIC8vIGZ1cnRoZXIgcmV0cmllcy4gVGhlIHJ1biB3aWxsIHJlbWFpbiBpbiBpdHMgY3VycmVudCBzdGF0ZS5cbiAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gbWFyayBzdGVwIGFzIGZhaWxlZCBhZnRlciAke21ldGFkYXRhLmF0dGVtcHR9IGRlbGl2ZXJ5IGF0dGVtcHRzLiBgICtcbiAgICAgICAgICAgICAgYEEgcGVyc2lzdGVudCBlcnJvciBpcyBwcmV2ZW50aW5nIHRoZSBzdGVwIGZyb20gYmVpbmcgdGVybWluYXRlZC4gYCArXG4gICAgICAgICAgICAgIGBUaGUgcnVuIHdpbGwgcmVtYWluIGluIGl0cyBjdXJyZW50IHN0YXRlIHVudGlsIG1hbnVhbGx5IHJlc29sdmVkLiBgICtcbiAgICAgICAgICAgICAgYFRoaXMgaXMgbW9zdCBsaWtlbHkgZHVlIHRvIGEgcGVyc2lzdGVudCBvdXRhZ2Ugb2YgdGhlIHdvcmtmbG93IGJhY2tlbmQgYCArXG4gICAgICAgICAgICAgIGBvciBhIGJ1ZyBpbiB0aGUgd29ya2Zsb3cgcnVudGltZSBhbmQgc2hvdWxkIGJlIHJlcG9ydGVkIHRvIHRoZSBXb3JrZmxvdyB0ZWFtLmAsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGF0dGVtcHQ6IG1ldGFkYXRhLmF0dGVtcHQsXG4gICAgICAgICAgICAgIGVycm9yTmFtZTogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubmFtZSA6ICdVbmtub3duRXJyb3InLFxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICAgICAgICAgICAgZXJyb3JTdGFjazogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIuc3RhY2sgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNwYW5MaW5rcyA9IGF3YWl0IGxpbmtUb0N1cnJlbnRDb250ZXh0KCk7XG4gICAgICAvLyBFeGVjdXRlIHN0ZXAgd2l0aGluIHRoZSBwcm9wYWdhdGVkIHRyYWNlIGNvbnRleHRcbiAgICAgIHJldHVybiBhd2FpdCB3aXRoVHJhY2VDb250ZXh0KHRyYWNlQ29udGV4dCwgYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyBFeHRyYWN0IHRoZSBzdGVwIG5hbWUgZnJvbSB0aGUgdG9waWMgbmFtZVxuICAgICAgICBjb25zdCBzdGVwTmFtZSA9IG1ldGFkYXRhLnF1ZXVlTmFtZS5zbGljZSgnX193a2Zfc3RlcF8nLmxlbmd0aCk7XG4gICAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGQoKTtcbiAgICAgICAgY29uc3QgaXNWZXJjZWwgPSBwcm9jZXNzLmVudi5WRVJDRUxfVVJMICE9PSB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gTWVtb2l6ZWQgYWNjZXNzb3IgZm9yIHRoZSBwZXItcnVuIEFFUy0yNTYgZW5jcnlwdGlvbiBrZXkuIFRoZSBmaXJzdFxuICAgICAgICAvLyBjYWxsZXIgKHR5cGljYWxseSBgaHlkcmF0ZVN0ZXBBcmd1bWVudHNgIGZvciBpbnB1dCBkZXNlcmlhbGl6YXRpb24sXG4gICAgICAgIC8vIG9yIG9uZSBvZiB0aGUgZWFybHktcmV0dXJuIGRlaHlkcmF0ZVN0ZXBFcnJvciBwYXRocyBpZiBzdGVwX3N0YXJ0ZWRcbiAgICAgICAgLy8gZmFpbHMpIHRyaWdnZXJzIHRoZSBhY3R1YWwgZmV0Y2ggLyBIS0RGIGRlcml2YXRpb247IHN1YnNlcXVlbnRcbiAgICAgICAgLy8gY2FsbGVycyBhd2FpdCB0aGUgY2FjaGVkIHByb21pc2UuIFN0ZXBzIHRoYXQgZmFpbCBiZWZvcmUgYW55XG4gICAgICAgIC8vIGVuY3J5cHRpb24tYXdhcmUgd29yayBoYXBwZW5zIChlLmcuIGFuIGltbWVkaWF0ZSBzdGVwX3N0YXJ0ZWRcbiAgICAgICAgLy8gY29uZmxpY3QpIHNraXAgdGhlIGZldGNoIGVudGlyZWx5LlxuICAgICAgICBjb25zdCBnZXRFbmNyeXB0aW9uS2V5ID0gbWVtb2l6ZUVuY3J5cHRpb25LZXkod29ybGQsIHdvcmtmbG93UnVuSWQpO1xuXG4gICAgICAgIC8vIFJlc29sdmUgbG9jYWwgYXN5bmMgdmFsdWVzIGNvbmN1cnJlbnRseSBiZWZvcmUgZW50ZXJpbmcgdGhlIHRyYWNlIHNwYW5cbiAgICAgICAgY29uc3QgW3BvcnQsIHNwYW5LaW5kXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICBpc1ZlcmNlbCA/IHVuZGVmaW5lZCA6IGdldFBvcnQoKSxcbiAgICAgICAgICBnZXRTcGFuS2luZCgnQ09OU1VNRVInKSxcbiAgICAgICAgXSk7XG5cbiAgICAgICAgcmV0dXJuIHRyYWNlKFxuICAgICAgICAgIGBTVEVQICR7c3RlcE5hbWV9YCxcbiAgICAgICAgICB7IGtpbmQ6IHNwYW5LaW5kLCBsaW5rczogc3BhbkxpbmtzIH0sXG4gICAgICAgICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcE5hbWUoc3RlcE5hbWUpLFxuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcEF0dGVtcHQobWV0YWRhdGEuYXR0ZW1wdCksXG4gICAgICAgICAgICAgIC8vIFN0YW5kYXJkIE9URUwgbWVzc2FnaW5nIGNvbnZlbnRpb25zXG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdTeXN0ZW0oJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nRGVzdGluYXRpb25OYW1lKG1ldGFkYXRhLnF1ZXVlTmFtZSksXG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdNZXNzYWdlSWQobWV0YWRhdGEubWVzc2FnZUlkKSxcbiAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ09wZXJhdGlvblR5cGUoJ3Byb2Nlc3MnKSxcbiAgICAgICAgICAgICAgLi4uZ2V0UXVldWVPdmVyaGVhZCh7IHJlcXVlc3RlZEF0IH0pLFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIE5vdGU6IFN0ZXAgZnVuY3Rpb24gdmFsaWRhdGlvbiBoYXBwZW5zIGFmdGVyIHN0ZXBfc3RhcnRlZCBzbyB3ZSBjYW5cbiAgICAgICAgICAgIC8vIHByb3Blcmx5IGZhaWwgdGhlIHN0ZXAgKG5vdCB0aGUgcnVuKSBpZiB0aGUgZnVuY3Rpb24gaXMgbm90IHJlZ2lzdGVyZWQuXG4gICAgICAgICAgICAvLyBUaGlzIGFsbG93cyB0aGUgd29ya2Zsb3cgdG8gaGFuZGxlIHRoZSBzdGVwIGZhaWx1cmUgZ3JhY2VmdWxseS5cbiAgICAgICAgICAgIGNvbnN0IHN0ZXBGbiA9IGdldFN0ZXBGdW5jdGlvbihzdGVwTmFtZSk7XG5cbiAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dOYW1lKHdvcmtmbG93TmFtZSksXG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1bklkKHdvcmtmbG93UnVuSWQpLFxuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcElkKHN0ZXBJZCksXG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwVHJhY2VQcm9wYWdhdGVkKCEhdHJhY2VDb250ZXh0KSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBzdGVwX3N0YXJ0ZWQgdmFsaWRhdGVzIHN0YXRlIGFuZCByZXR1cm5zIHRoZSBzdGVwIGVudGl0eSwgc28gbm8gc2VwYXJhdGVcbiAgICAgICAgICAgIC8vIHdvcmxkLnN0ZXBzLmdldCgpIGNhbGwgaXMgbmVlZGVkLiBUaGUgc2VydmVyIGNoZWNrczpcbiAgICAgICAgICAgIC8vIC0gU3RlcCBub3QgaW4gdGVybWluYWwgc3RhdGUgKHJldHVybnMgNDA5KVxuICAgICAgICAgICAgLy8gLSByZXRyeUFmdGVyIHRpbWVzdGFtcCByZWFjaGVkIChyZXR1cm5zIDQyNSB3aXRoIFJldHJ5LUFmdGVyIGhlYWRlcilcbiAgICAgICAgICAgIC8vIC0gV29ya2Zsb3cgc3RpbGwgYWN0aXZlIChyZXR1cm5zIDQxMCBpZiBjb21wbGV0ZWQpXG4gICAgICAgICAgICBsZXQgc3RlcDtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IHN0YXJ0UmVzdWx0ID0gYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfc3RhcnRlZCcsXG4gICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwSWQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgaWYgKCFzdGFydFJlc3VsdC5zdGVwKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgICAgICAgICAgICAgYHN0ZXBfc3RhcnRlZCBldmVudCBmb3IgXCIke3N0ZXBJZH1cIiBkaWQgbm90IHJldHVybiBzdGVwIGVudGl0eWBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHN0ZXAgPSBzdGFydFJlc3VsdC5zdGVwO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGlmIChUaHJvdHRsZUVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICBjb25zdCByZXRyeVJldHJ5QWZ0ZXIgPSBNYXRoLm1heChcbiAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICB0eXBlb2YgZXJyLnJldHJ5QWZ0ZXIgPT09ICdudW1iZXInID8gZXJyLnJldHJ5QWZ0ZXIgOiAxXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgJ1Rocm90dGxlZCBhZ2FpbiBvbiByZXRyeSwgZGVmZXJyaW5nIHRvIHF1ZXVlJyxcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0cnlBZnRlclNlY29uZHM6IHJldHJ5UmV0cnlBZnRlcixcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiB7IHRpbWVvdXRTZWNvbmRzOiByZXRyeVJldHJ5QWZ0ZXIgfTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICAvLyBFeHBlY3RlZCB3aGVuIGEgcnVuIGlzIGNhbmNlbGxlZCB3aGlsZSBhIHN0ZXAgaXMgaW4tZmxpZ2h0LlxuICAgICAgICAgICAgICAgIHN0ZXBSdW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAnV29ya2Zsb3cgcnVuIGhhcyBhbHJlYWR5IGNvbXBsZXRlZCwgc2tpcHBpbmcgc3RlcCcsXG4gICAgICAgICAgICAgICAgICB7IGVycm9yTmFtZTogZXJyLm5hbWUsIGVycm9yTWVzc2FnZTogZXJyLm1lc3NhZ2UgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICAvLyBTdGVwIGFscmVhZHkgaW4gYSB0ZXJtaW5hbCBzdGF0ZSDigJQgYW5vdGhlciB3b3JrZXIgZmluaXNoZWRcbiAgICAgICAgICAgICAgICAvLyBpdCBvciBpdCB3YXMgcmV0cmllZCB0byBjb21wbGV0aW9uLiBSZS1lbnF1ZXVlIHRoZSBwYXJlbnRcbiAgICAgICAgICAgICAgICAvLyB3b3JrZmxvdyBzbyBpdCBjYW4gb2JzZXJ2ZSB0aGUgb3V0Y29tZS5cbiAgICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICdTdGVwIGluIHRlcm1pbmFsIHN0YXRlLCByZS1lbnF1ZXVpbmcgd29ya2Zsb3cnLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWU6IGVyci5uYW1lLFxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFNraXBwZWQodHJ1ZSksXG4gICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFNraXBSZWFzb24oJ2NvbXBsZXRlZCcpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHNwYW4/LmFkZEV2ZW50Py4oJ3N0ZXAuc2tpcHBlZCcsIHtcbiAgICAgICAgICAgICAgICAgICdza2lwLnJlYXNvbic6ICd0ZXJtaW5hbF9zdGF0ZScsXG4gICAgICAgICAgICAgICAgICAnc3RlcC5uYW1lJzogc3RlcE5hbWUsXG4gICAgICAgICAgICAgICAgICAnc3RlcC5pZCc6IHN0ZXBJZCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2Uod29ybGQsIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSksIHtcbiAgICAgICAgICAgICAgICAgIHJ1bklkOiB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBzZXJpYWxpemVUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIFRvbyBlYXJseTogcmV0cnlBZnRlciB0aW1lc3RhbXAgbm90IHJlYWNoZWQgeWV0XG4gICAgICAgICAgICAgIC8vIFJldHVybiB0aW1lb3V0IHRvIHF1ZXVlIHNvIGl0IHJldHJpZXMgbGF0ZXJcbiAgICAgICAgICAgICAgaWYgKFRvb0Vhcmx5RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVvdXRTZWNvbmRzID0gTWF0aC5tYXgoMSwgZXJyLnJldHJ5QWZ0ZXIgPz8gMSk7XG4gICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFJldHJ5VGltZW91dFNlY29uZHModGltZW91dFNlY29uZHMpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIC8vIEFkZCBzcGFuIGV2ZW50IGZvciBkZWxheWVkIHJldHJ5XG4gICAgICAgICAgICAgICAgc3Bhbj8uYWRkRXZlbnQ/Lignc3RlcC5kZWxheWVkJywge1xuICAgICAgICAgICAgICAgICAgJ2RlbGF5LnJlYXNvbic6ICdyZXRyeV9hZnRlcl9ub3RfcmVhY2hlZCcsXG4gICAgICAgICAgICAgICAgICAnZGVsYXkudGltZW91dF9zZWNvbmRzJzogdGltZW91dFNlY29uZHMsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgc3RlcFJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAnU3RlcCByZXRyeUFmdGVyIHRpbWVzdGFtcCBub3QgeWV0IHJlYWNoZWQnLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICByZXRyeUFmdGVyU2Vjb25kczogZXJyLnJldHJ5QWZ0ZXIsXG4gICAgICAgICAgICAgICAgICAgIHRpbWVvdXRTZWNvbmRzLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgdGltZW91dFNlY29uZHMgfTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBSZS10aHJvdyBvdGhlciBlcnJvcnNcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5kZWJ1ZygnU3RlcCBleGVjdXRpb24gZGV0YWlscycsIHtcbiAgICAgICAgICAgICAgc3RhdHVzOiBzdGVwLnN0YXR1cyxcbiAgICAgICAgICAgICAgYXR0ZW1wdDogc3RlcC5hdHRlbXB0LFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFN0YXR1cyhzdGVwLnN0YXR1cyksXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gVmFsaWRhdGUgc3RlcCBmdW5jdGlvbiBleGlzdHMgQUZURVIgc3RlcF9zdGFydGVkIHNvIHdlIGNhblxuICAgICAgICAgICAgLy8gcHJvcGVybHkgZmFpbCB0aGUgc3RlcCAobm90IHRoZSBydW4pIGlmIHRoZSBmdW5jdGlvbiBpcyBtaXNzaW5nLlxuICAgICAgICAgICAgLy8gVGhpcyBhbGxvd3MgdGhlIHdvcmtmbG93IHRvIGhhbmRsZSB0aGUgc3RlcCBmYWlsdXJlIGdyYWNlZnVsbHksXG4gICAgICAgICAgICAvLyBzaW1pbGFyIHRvIGhvdyBGYXRhbEVycm9yIGlzIGhhbmRsZWQuXG4gICAgICAgICAgICBpZiAoIXN0ZXBGbiB8fCB0eXBlb2Ygc3RlcEZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVyciA9IG5ldyBTdGVwTm90UmVnaXN0ZXJlZEVycm9yKHN0ZXBOYW1lKTtcblxuICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgICAgICAnU3RlcCBmdW5jdGlvbiBub3QgcmVnaXN0ZXJlZCwgZmFpbGluZyBzdGVwIChub3QgcnVuKScsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBlcnIubmFtZSxcbiAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICBlcnJvclN0YWNrOiBlcnIuc3RhY2ssXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgIC8vIEZhaWwgdGhlIHN0ZXAgdmlhIGV2ZW50IChldmVudC1zb3VyY2VkIGFyY2hpdGVjdHVyZSlcbiAgICAgICAgICAgICAgLy8gVGhpcyBtYXRjaGVzIHRoZSBGYXRhbEVycm9yIHBhdHRlcm4gLSBmYWlsIHRoZSBzdGVwIGFuZCByZS1xdWV1ZSB3b3JrZmxvd1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKVxuICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKHN0ZXBGYWlsRXJyKSB7XG4gICAgICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcEZhaWxFcnIpKSB7XG4gICAgICAgICAgICAgICAgICAvLyBTdGVwIGFscmVhZHkgdHJhbnNpdGlvbmVkIHRvIGEgdGVybWluYWwgc3RhdGUg4oCUIGR1cGxpY2F0ZVxuICAgICAgICAgICAgICAgICAgLy8gZGVsaXZlcnkgb3IgY29uY3VycmVudCBjYW5jZWxsYXRpb24uIERyb3Agc2lsZW50bHkuXG4gICAgICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAnVHJpZWQgZmFpbGluZyBzdGVwIGZvciBtaXNzaW5nIGZ1bmN0aW9uLCBidXQgc3RlcCBoYXMgYWxyZWFkeSBmaW5pc2hlZC4nLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBzdGVwRmFpbEVyci5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3RlcEZhaWxFcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgc3RlcEZhaWxFcnI7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFN0YXR1cygnZmFpbGVkJyksXG4gICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBGYXRhbEVycm9yKHRydWUpLFxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAvLyBSZS1pbnZva2UgdGhlIHdvcmtmbG93IHRvIGhhbmRsZSB0aGUgZmFpbGVkIHN0ZXBcbiAgICAgICAgICAgICAgYXdhaXQgcXVldWVNZXNzYWdlKHdvcmxkLCBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd05hbWUpLCB7XG4gICAgICAgICAgICAgICAgcnVuSWQ6IHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBzZXJpYWxpemVUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbWF4UmV0cmllcyA9IHN0ZXBGbi5tYXhSZXRyaWVzID8/IERFRkFVTFRfU1RFUF9NQVhfUkVUUklFUztcblxuICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwTWF4UmV0cmllcyhtYXhSZXRyaWVzKSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBsZXQgcmVzdWx0OiB1bmtub3duO1xuXG4gICAgICAgICAgICAvLyBDaGVjayBtYXggcmV0cmllcyBBRlRFUiBzdGVwX3N0YXJ0ZWQgKGF0dGVtcHQgd2FzIGp1c3QgaW5jcmVtZW50ZWQpXG4gICAgICAgICAgICAvLyBzdGVwLmF0dGVtcHQgdHJhY2tzIGhvdyBtYW55IHRpbWVzIHN0ZXBfc3RhcnRlZCBoYXMgYmVlbiBjYWxsZWQuXG4gICAgICAgICAgICAvLyBOb3RlOiBtYXhSZXRyaWVzIGlzIHRoZSBudW1iZXIgb2YgUkVUUklFUyBhZnRlciB0aGUgZmlyc3QgYXR0ZW1wdCwgc28gdG90YWwgYXR0ZW1wdHMgPSBtYXhSZXRyaWVzICsgMVxuICAgICAgICAgICAgLy8gVXNlID4gaGVyZSAobm90ID49KSBiZWNhdXNlIHRoaXMgZ3VhcmRzIGFnYWluc3QgcmUtaW52b2NhdGlvbiBBRlRFUiBhbGwgYXR0ZW1wdHMgYXJlIHVzZWQuXG4gICAgICAgICAgICAvLyBUaGUgcG9zdC1mYWlsdXJlIGNoZWNrIHVzZXMgPj0gdG8gZGVjaWRlIHdoZXRoZXIgdG8gcmV0cnkgYWZ0ZXIgYSBmYWlsdXJlLlxuICAgICAgICAgICAgaWYgKHN0ZXAuYXR0ZW1wdCA+IG1heFJldHJpZXMgKyAxKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJldHJ5Q291bnQgPSBzdGVwLmF0dGVtcHQgLSAxO1xuICAgICAgICAgICAgICAvLyBQZXJzaXN0ZWQgbWVzc2FnZSDigJQga2VwdCBzaG9ydCwgbm8gbWFjaGluZSBgc3RlcE5hbWVgLFxuICAgICAgICAgICAgICAvLyBzaW5jZSBvYnNlcnZhYmlsaXR5IGFscmVhZHkgYXR0cmlidXRlcyB0aGUgZXZlbnQgdG8gYVxuICAgICAgICAgICAgICAvLyBzcGVjaWZpYyBzdGVwLlxuICAgICAgICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBgU3RlcCBleGNlZWRlZCBtYXggcmV0cmllcyAoJHtyZXRyeUNvdW50fSAke3BsdXJhbGl6ZSgncmV0cnknLCAncmV0cmllcycsIHJldHJ5Q291bnQpfSlgO1xuICAgICAgICAgICAgICBzdGVwTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgIGBTdGVwICR7Zm9ybWF0U3RlcE5hbWUoc3RlcE5hbWUpfSBleGNlZWRlZCBtYXggcmV0cmllcyAoJHtyZXRyeUNvdW50fSAke3BsdXJhbGl6ZSgncmV0cnknLCAncmV0cmllcycsIHJldHJ5Q291bnQpfSlgLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgIHJldHJ5Q291bnQsXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAvLyBGYWlsIHRoZSBzdGVwIHZpYSBldmVudCAoZXZlbnQtc291cmNlZCBhcmNoaXRlY3R1cmUpLlxuICAgICAgICAgICAgICAvLyBQcmVzZXJ2ZSB0aGUgcHJpb3IgYXR0ZW1wdCdzIHNlcmlhbGl6ZWQgZXJyb3IgYXMgdGhlIGNhdXNlIHNvXG4gICAgICAgICAgICAgIC8vIHRoZSB1bmRlcmx5aW5nIGZhaWx1cmUgaXMgcmVjb3ZlcmFibGUgZnJvbSBgc3RlcC5lcnJvci5jYXVzZWBcbiAgICAgICAgICAgICAgLy8gYWZ0ZXIgaHlkcmF0aW9uLCB3aXRob3V0IGZvcmNpbmcgY29uc3VtZXJzIHRvIHdhbGsgdGhlXG4gICAgICAgICAgICAgIC8vIHN0ZXBfcmV0cnlpbmcgZXZlbnQgaGlzdG9yeS4gTWlycm9ycyB0aGUgcG9zdC1mYWlsdXJlIHBhdGhcbiAgICAgICAgICAgICAgLy8gYmVsb3cgdGhhdCB3cmFwcyB0aGUgbGl2ZSBgZXJyYCBhcyBjYXVzZS5cbiAgICAgICAgICAgICAgY29uc3Qgd3JhcHBlZEVycm9yID0gbmV3IEZhdGFsRXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICAgICAgICAgICAgaWYgKHN0ZXAuZXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAod3JhcHBlZEVycm9yIGFzIEVycm9yKS5jYXVzZSA9IGF3YWl0IGh5ZHJhdGVTdGVwRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIHN0ZXAuZXJyb3IsXG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKVxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAgIC8vIElnbm9yZTogYmVzdC1lZmZvcnQgY2F1c2UgYXR0YWNobWVudCwgdGhlIHdyYXBwaW5nXG4gICAgICAgICAgICAgICAgICAvLyBGYXRhbEVycm9yIHN0YWNrL21lc3NhZ2Ugc3RpbGwgc3VyZmFjZSB0aGUgZmFpbHVyZS5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9mYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVN0ZXBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIHdyYXBwZWRFcnJvcixcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBnZXRFbmNyeXB0aW9uS2V5KClcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgICAgICAvLyBTdGVwIGFscmVhZHkgdHJhbnNpdGlvbmVkIHRvIGEgdGVybWluYWwgc3RhdGUg4oCUIGR1cGxpY2F0ZVxuICAgICAgICAgICAgICAgICAgLy8gZGVsaXZlcnkgb3IgY29uY3VycmVudCBjb21wbGV0aW9uLiBEcm9wIHNpbGVudGx5LlxuICAgICAgICAgICAgICAgICAgc3RlcFJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGZhaWxpbmcgc3RlcCwgYnV0IHN0ZXAgaGFzIGFscmVhZHkgZmluaXNoZWQuJyxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgIGVycm9yTmFtZTogZXJyLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBTdGF0dXMoJ2ZhaWxlZCcpLFxuICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwUmV0cnlFeGhhdXN0ZWQodHJ1ZSksXG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIC8vIFJlLWludm9rZSB0aGUgd29ya2Zsb3cgdG8gaGFuZGxlIHRoZSBmYWlsZWQgc3RlcFxuICAgICAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2Uod29ybGQsIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSksIHtcbiAgICAgICAgICAgICAgICBydW5JZDogd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICB0cmFjZUNhcnJpZXI6IGF3YWl0IHNlcmlhbGl6ZVRyYWNlQ2FycmllcigpLFxuICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyAtLS0gSW5mcmFzdHJ1Y3R1cmU6IHByZXBhcmUgc3RlcCBpbnB1dCAtLS1cbiAgICAgICAgICAgIC8vIE5ldHdvcmsvc2VydmVyIGVycm9ycyBwcm9wYWdhdGUgdG8gdGhlIHF1ZXVlIGhhbmRsZXIgZm9yIHJldHJ5LlxuICAgICAgICAgICAgLy8gV29ya2Zsb3dSdW50aW1lRXJyb3IgKGRhdGEgaW50ZWdyaXR5IGlzc3VlcykgYXJlIGZhdGFsIOKAlCByZXRyeWluZ1xuICAgICAgICAgICAgLy8gd29uJ3QgZml4IHRoZW0sIHNvIHdlIHJlLXF1ZXVlIHRoZSB3b3JrZmxvdyB0byBzdXJmYWNlIHRoZSBlcnJvci5cbiAgICAgICAgICAgIC8vIHN0ZXBfc3RhcnRlZCBhbHJlYWR5IHZhbGlkYXRlZCB0aGUgc3RlcCBpcyBpbiB2YWxpZCBzdGF0ZSAocGVuZGluZy9ydW5uaW5nKVxuICAgICAgICAgICAgLy8gYW5kIHJldHVybmVkIHRoZSB1cGRhdGVkIHN0ZXAgZW50aXR5IHdpdGggaW5jcmVtZW50ZWQgYXR0ZW1wdFxuXG4gICAgICAgICAgICAvLyBzdGVwLmF0dGVtcHQgaXMgbm93IHRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyIChhZnRlciBpbmNyZW1lbnQpXG4gICAgICAgICAgICBjb25zdCBhdHRlbXB0ID0gc3RlcC5hdHRlbXB0O1xuXG4gICAgICAgICAgICBpZiAoIXN0ZXAuc3RhcnRlZEF0KSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGBTdGVwIFwiJHtzdGVwSWR9XCIgaGFzIG5vIFwic3RhcnRlZEF0XCIgdGltZXN0YW1wYDtcbiAgICAgICAgICAgICAgc3RlcFJ1bnRpbWVMb2dnZXIuZXJyb3IoJ0ZhdGFsIHJ1bnRpbWUgZXJyb3IgZHVyaW5nIHN0ZXAgc2V0dXAnLCB7XG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9mYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVN0ZXBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBGYXRhbEVycm9yKGVycm9yTWVzc2FnZSksXG4gICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpXG4gICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZmFpbEVycikge1xuICAgICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGZhaWxFcnIpKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IGZhaWxFcnI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgLy8gUmUtcXVldWUgdGhlIHdvcmtmbG93IHNvIGl0IGNhbiBwcm9jZXNzIHRoZSBzdGVwIGZhaWx1cmVcbiAgICAgICAgICAgICAgYXdhaXQgcXVldWVNZXNzYWdlKHdvcmxkLCBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd05hbWUpLCB7XG4gICAgICAgICAgICAgICAgcnVuSWQ6IHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBzZXJpYWxpemVUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIENhcHR1cmUgc3RhcnRlZEF0IGZvciB1c2UgaW4gYXN5bmMgY2FsbGJhY2sgKFR5cGVTY3JpcHQgbmFycm93aW5nIGRvZXNuJ3QgcGVyc2lzdClcbiAgICAgICAgICAgIGNvbnN0IHN0ZXBTdGFydGVkQXQgPSBzdGVwLnN0YXJ0ZWRBdDtcblxuICAgICAgICAgICAgLy8gUmVzb2x2ZSB0aGUgZW5jcnlwdGlvbiBrZXkgbm93IHRoYXQgd2UncmUgY29tbWl0dGVkIHRvIHJ1bm5pbmdcbiAgICAgICAgICAgIC8vIHVzZXIgY29kZTogaW5wdXQgaHlkcmF0aW9uIG5lZWRzIGl0LCBhbmQgYGNvbnRleHRTdG9yYWdlYCAoYW5kXG4gICAgICAgICAgICAvLyBhbnkgdXNlci1jb2RlIHBhdGhzIHRoYXQgcnVuIGluc2lkZSBpdCkgY2FwdHVyZSB0aGUgcmVzb2x2ZWRcbiAgICAgICAgICAgIC8vIHZhbHVlLiBUcmlnZ2VycyB0aGUgdW5kZXJseWluZyB3b3JsZCAvIEtNUyBmZXRjaCBvbmNlLCB3aXRoXG4gICAgICAgICAgICAvLyBzdWJzZXF1ZW50IGRlaHlkcmF0ZSBwYXRocyByZXVzaW5nIHRoZSBtZW1vaXplZCByZXN1bHQuXG4gICAgICAgICAgICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpO1xuXG4gICAgICAgICAgICAvLyBIeWRyYXRlIHRoZSBzdGVwIGlucHV0IGFyZ3VtZW50cywgY2xvc3VyZSB2YXJpYWJsZXMsIGFuZCB0aGlzVmFsXG4gICAgICAgICAgICAvLyBOT1RFOiBUaGlzIGNhcHR1cmVzIG9ubHkgdGhlIHN5bmNocm9ub3VzIHBvcnRpb24gb2YgaHlkcmF0aW9uLiBBbnkgYXN5bmNcbiAgICAgICAgICAgIC8vIG9wZXJhdGlvbnMgKGUuZy4sIHN0cmVhbSBsb2FkaW5nKSBhcmUgYWRkZWQgdG8gYG9wc2AgYW5kIGV4ZWN1dGVkIGxhdGVyXG4gICAgICAgICAgICAvLyB2aWEgUHJvbWlzZS5hbGwob3BzKSAtIHRoZWlyIHRpbWluZyBpcyBub3QgaW5jbHVkZWQgaW4gdGhpcyBtZWFzdXJlbWVudC5cbiAgICAgICAgICAgIGNvbnN0IG9wczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gICAgICAgICAgICBjb25zdCBoeWRyYXRlZElucHV0ID0gYXdhaXQgdHJhY2UoXG4gICAgICAgICAgICAgICdzdGVwLmh5ZHJhdGUnLFxuICAgICAgICAgICAgICB7fSxcbiAgICAgICAgICAgICAgYXN5bmMgKGh5ZHJhdGVTcGFuKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoeWRyYXRlU3RlcEFyZ3VtZW50cyhcbiAgICAgICAgICAgICAgICAgIHN0ZXAuaW5wdXQsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgIG9wc1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgY29uc3QgZHVyYXRpb25NcyA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICAgICAgICAgICAgaHlkcmF0ZVNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBBcmd1bWVudHNDb3VudChyZXN1bHQuYXJncy5sZW5ndGgpLFxuICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlF1ZXVlRGVzZXJpYWxpemVUaW1lTXMoZHVyYXRpb25NcyksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgY29uc3QgYXJncyA9IGh5ZHJhdGVkSW5wdXQuYXJncztcbiAgICAgICAgICAgIGNvbnN0IHRoaXNWYWwgPSBoeWRyYXRlZElucHV0LnRoaXNWYWwgPz8gbnVsbDtcblxuICAgICAgICAgICAgLy8gLS0tIFVzZXIgY29kZSBleGVjdXRpb24gLS0tXG4gICAgICAgICAgICAvLyBPbmx5IGVycm9ycyBmcm9tIHN0ZXBGbi5hcHBseSgpICh1c2VyIHN0ZXAgY29kZSkgc2hvdWxkIHByb2R1Y2VcbiAgICAgICAgICAgIC8vIHN0ZXBfZmFpbGVkL3N0ZXBfcmV0cnlpbmcuIEluZnJhc3RydWN0dXJlIGVycm9ycyAobmV0d29yaywgc2VydmVyKVxuICAgICAgICAgICAgLy8gbXVzdCBwcm9wYWdhdGUgdG8gdGhlIHF1ZXVlIGhhbmRsZXIgZm9yIGF1dG9tYXRpYyByZXRyeS5cbiAgICAgICAgICAgIGxldCB1c2VyQ29kZUVycm9yOiB1bmtub3duO1xuICAgICAgICAgICAgbGV0IHVzZXJDb2RlRmFpbGVkID0gZmFsc2U7XG5cbiAgICAgICAgICAgIGNvbnN0IGV4ZWN1dGlvblN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXN1bHQgPSBhd2FpdCB0cmFjZSgnc3RlcC5leGVjdXRlJywge30sIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgY29udGV4dFN0b3JhZ2UucnVuKFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBzdGVwTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgc3RlcFN0YXJ0ZWRBdDogbmV3IERhdGUoK3N0ZXBTdGFydGVkQXQpLFxuICAgICAgICAgICAgICAgICAgICAgIGF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93TWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdDogbmV3IERhdGUoK3dvcmtmbG93U3RhcnRlZEF0KSxcbiAgICAgICAgICAgICAgICAgICAgICAvLyBUT0RPOiB0aGVyZSBzaG91bGQgYmUgYSBnZXRVcmwgbWV0aG9kIG9uIHRoZSB3b3JsZCBpbnRlcmZhY2UgaXRzZWxmLiBUaGlzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gc29sdXRpb24gb25seSB3b3JrcyBmb3IgdmVyY2VsICsgbG9jYWwgd29ybGRzLlxuICAgICAgICAgICAgICAgICAgICAgIHVybDogaXNWZXJjZWxcbiAgICAgICAgICAgICAgICAgICAgICAgID8gYGh0dHBzOi8vJHtwcm9jZXNzLmVudi5WRVJDRUxfVVJMfWBcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0ID8/IDMwMDB9YCxcbiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlczogeyBlbmNyeXB0aW9uOiAhIWVuY3J5cHRpb25LZXkgfSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgb3BzLFxuICAgICAgICAgICAgICAgICAgICBjbG9zdXJlVmFyczogaHlkcmF0ZWRJbnB1dC5jbG9zdXJlVmFycyxcbiAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAoKSA9PiBzdGVwRm4uYXBwbHkodGhpc1ZhbCwgYXJncylcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICB1c2VyQ29kZUVycm9yID0gZXJyO1xuICAgICAgICAgICAgICB1c2VyQ29kZUZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBleGVjdXRpb25UaW1lTXMgPSBEYXRlLm5vdygpIC0gZXhlY3V0aW9uU3RhcnRUaW1lO1xuXG4gICAgICAgICAgICBjYW5jZWxBYm9ydFJlYWRlcnMoLi4uYXJncywgdGhpc1ZhbCwgaHlkcmF0ZWRJbnB1dC5jbG9zdXJlVmFycyk7XG5cbiAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuUXVldWVFeGVjdXRpb25UaW1lTXMoZXhlY3V0aW9uVGltZU1zKSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyAtLS0gRGVoeWRyYXRlIChzZXJpYWxpemUpIHRoZSBzdGVwJ3MgcmV0dXJuIHZhbHVlIC0tLVxuICAgICAgICAgICAgLy8gQSBub24tc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSBpcyBhIHVzZXItY29kZSBidWcsIG5vdCBhblxuICAgICAgICAgICAgLy8gaW5mcmFzdHJ1Y3R1cmUgZmFpbHVyZS4gUm91dGUgaXQgdGhyb3VnaCB0aGUgc2FtZSBzdGVwLWZhaWx1cmVcbiAgICAgICAgICAgIC8vIHBhdGggYXMgYSB0aHJvd24gZXJyb3Igc28gU2VyaWFsaXphdGlvbkVycm9yICh3aGljaCBpcyBtYXJrZWRcbiAgICAgICAgICAgIC8vIGBmYXRhbDogdHJ1ZWApIHNob3J0LWNpcmN1aXRzIHRoZSByZXRyeSBsb29wIGluc3RlYWQgb2ZcbiAgICAgICAgICAgIC8vIGJ1YmJsaW5nIGFzIGFuIEhUVFAgNTAwIGFuZCBidXJuaW5nIHRocm91Z2ggYWxsIDQgcXVldWVcbiAgICAgICAgICAgIC8vIGRlbGl2ZXJpZXMgb24gYSBndWFyYW50ZWVkLXRvLWZhaWwgbWVzc2FnZS5cbiAgICAgICAgICAgIGlmICghdXNlckNvZGVGYWlsZWQpIHtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBhd2FpdCB0cmFjZShcbiAgICAgICAgICAgICAgICAgICdzdGVwLmRlaHlkcmF0ZScsXG4gICAgICAgICAgICAgICAgICB7fSxcbiAgICAgICAgICAgICAgICAgIGFzeW5jIChkZWh5ZHJhdGVTcGFuKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlaHlkcmF0ZWQgPSBhd2FpdCBkZWh5ZHJhdGVTdGVwUmV0dXJuVmFsdWUoXG4gICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LFxuICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgICAgICBvcHNcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZHVyYXRpb25NcyA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICAgICAgICAgICAgICAgIGRlaHlkcmF0ZVNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5RdWV1ZVNlcmlhbGl6ZVRpbWVNcyhkdXJhdGlvbk1zKSxcbiAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFJlc3VsdFR5cGUodHlwZW9mIGRlaHlkcmF0ZWQpLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRlaHlkcmF0ZWQ7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgdXNlckNvZGVFcnJvciA9IGVycjtcbiAgICAgICAgICAgICAgICB1c2VyQ29kZUZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gLS0tIEhhbmRsZSB1c2VyIGNvZGUgZXJyb3JzIC0tLVxuICAgICAgICAgICAgaWYgKHVzZXJDb2RlRmFpbGVkKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVyciA9IHVzZXJDb2RlRXJyb3I7XG5cbiAgICAgICAgICAgICAgLy8gSW5mcmFzdHJ1Y3R1cmUgZXJyb3JzIHRoYXQgc29tZWhvdyBzdXJmYWNlZCB0aHJvdWdoIHVzZXIgY29kZVxuICAgICAgICAgICAgICAvLyBzaG91bGQgcHJvcGFnYXRlIHRvIHRoZSBxdWV1ZSBoYW5kbGVyIGZvciByZXRyeSwgbm90IGNvbnN1bWVcbiAgICAgICAgICAgICAgLy8gc3RlcCBhdHRlbXB0cy5cbiAgICAgICAgICAgICAgaWYgKFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgICAgLy8gV29ya2Zsb3cgaGFzIGFscmVhZHkgY29tcGxldGVkLCBzbyBuby1vcFxuICAgICAgICAgICAgICAgIHN0ZXBMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICdXb3JrZmxvdyBydW4gYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nIHN0ZXAnLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChXb3JrZmxvd1dvcmxkRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAgIGlmIChlcnIuc3RhdHVzICE9PSB1bmRlZmluZWQgJiYgZXJyLnN0YXR1cyA+PSA1MDApIHtcbiAgICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBXcmFwIEFib3J0RXJyb3IgaW4gRmF0YWxFcnJvciDigJQgYWJvcnQgaXMgaW50ZW50aW9uYWwgY2FuY2VsbGF0aW9uLCBub3QgcmV0cnlhYmxlXG4gICAgICAgICAgICAgIGxldCBlZmZlY3RpdmVFcnI6IHVua25vd24gPSBlcnI7XG4gICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBlcnIgaW5zdGFuY2VvZiBFcnJvciAmJlxuICAgICAgICAgICAgICAgIGVyci5uYW1lID09PSAnQWJvcnRFcnJvcicgJiZcbiAgICAgICAgICAgICAgICAhRmF0YWxFcnJvci5pcyhlcnIpXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZhdGFsRXJyID0gbmV3IEZhdGFsRXJyb3IoYEFib3J0ZWQ6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICAgICAgICAgICAgZmF0YWxFcnIuc3RhY2sgPSBlcnIuc3RhY2s7XG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlRXJyID0gZmF0YWxFcnI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZEVycm9yID0gYXdhaXQgbm9ybWFsaXplVW5rbm93bkVycm9yKGVmZmVjdGl2ZUVycik7XG4gICAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRTdGFjayA9XG4gICAgICAgICAgICAgICAgbm9ybWFsaXplZEVycm9yLnN0YWNrIHx8IGdldEVycm9yU3RhY2soZWZmZWN0aXZlRXJyKSB8fCAnJztcblxuICAgICAgICAgICAgICAvLyBSZWNvcmQgZXhjZXB0aW9uIGZvciBPVEVMIGVycm9yIHRyYWNraW5nXG4gICAgICAgICAgICAgIGlmIChlZmZlY3RpdmVFcnIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgICAgICAgIHNwYW4/LnJlY29yZEV4Y2VwdGlvbj8uKGVmZmVjdGl2ZUVycik7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBEZXRlcm1pbmUgZXJyb3IgY2F0ZWdvcnkgYW5kIHJldHJ5YWJpbGl0eVxuICAgICAgICAgICAgICBjb25zdCBpc0ZhdGFsID0gRmF0YWxFcnJvci5pcyhlZmZlY3RpdmVFcnIpO1xuICAgICAgICAgICAgICBjb25zdCBpc1JldHJ5YWJsZSA9IFJldHJ5YWJsZUVycm9yLmlzKGVmZmVjdGl2ZUVycik7XG4gICAgICAgICAgICAgIGNvbnN0IGVycm9yQ2F0ZWdvcnkgPSBpc0ZhdGFsXG4gICAgICAgICAgICAgICAgPyAnZmF0YWwnXG4gICAgICAgICAgICAgICAgOiBpc1JldHJ5YWJsZVxuICAgICAgICAgICAgICAgICAgPyAncmV0cnlhYmxlJ1xuICAgICAgICAgICAgICAgICAgOiAndHJhbnNpZW50JztcblxuICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcEVycm9yTmFtZShnZXRFcnJvck5hbWUoZXJyKSksXG4gICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBFcnJvck1lc3NhZ2Uobm9ybWFsaXplZEVycm9yLm1lc3NhZ2UpLFxuICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvclR5cGUoZ2V0RXJyb3JOYW1lKGVycikpLFxuICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvckNhdGVnb3J5KGVycm9yQ2F0ZWdvcnkpLFxuICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvclJldHJ5YWJsZSghaXNGYXRhbCksXG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIGlmIChpc0ZhdGFsKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZGVzY3JpcHRpb24gPSBkZXNjcmliZUVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgY29uc3QgZnJpZW5kbHlTdGVwID0gZm9ybWF0U3RlcE5hbWUoc3RlcE5hbWUpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZyYW1pbmcgPVxuICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24uYXR0cmlidXRpb24gPT09ICdzZGsnXG4gICAgICAgICAgICAgICAgICAgID8gYFN0ZXAgJHtmcmllbmRseVN0ZXB9IGZhaWxlZCB3aXRoIGEgRmF0YWxFcnJvciBmcm9tIHRoZSBTREsgcnVudGltZSDigJQgYnViYmxpbmcgdXAgdG8gcGFyZW50IHdvcmtmbG93YFxuICAgICAgICAgICAgICAgICAgICA6IGBTdGVwICR7ZnJpZW5kbHlTdGVwfSB0aHJldyBhIEZhdGFsRXJyb3Ig4oCUIGJ1YmJsaW5nIHVwIHRvIHBhcmVudCB3b3JrZmxvd2A7XG4gICAgICAgICAgICAgICAgLy8gTWlycm9yIHRoZSB3b3JrZmxvdy1sZXZlbCBsb2cgZm9ybWF0dGluZzogcHV0IHRoZSBmcmFtaW5nICtcbiAgICAgICAgICAgICAgICAvLyBzdGFjayBpbnRvIHRoZSBtZXNzYWdlIHNvIGNvbnNvbGUuZXJyb3IgcmVuZGVycyB0aGUgc3RhY2tcbiAgICAgICAgICAgICAgICAvLyBpbmxpbmUsIGFuZCBrZWVwIHRoZSBtZXRhZGF0YSBvYmplY3Qgc21hbGwgd2l0aCBvbmx5IHRoZVxuICAgICAgICAgICAgICAgIC8vIHN0cnVjdHVyZWQgZmllbGRzIHRoYXQgbG9nIGRyYWlucyB3YW50IHRvIGluZGV4LlxuICAgICAgICAgICAgICAgIC8vIE5vIGBoaW50YCBmaWVsZCBoZXJlIOKAlCBhY3Rpb25hYmxlIGhpbnQgdGV4dCBsaXZlcyBvbiB0aGVcbiAgICAgICAgICAgICAgICAvLyBlcnJvciBtZXNzYWdlIGl0c2VsZiAoc28gaXQgc3Vydml2ZXMgc2VyaWFsaXphdGlvbiDihpJcbiAgICAgICAgICAgICAgICAvLyBldmVudCBsb2cg4oaSIG9ic2VydmFiaWxpdHkgcmVoeWRyYXRlKSwgYW5kIGFkZGluZyBpdFxuICAgICAgICAgICAgICAgIC8vIGFnYWluIGhlcmUganVzdCBkdXBsaWNhdGVzIGl0IG9uIHN0ZGVyci5cbiAgICAgICAgICAgICAgICBzdGVwTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgYCR7ZnJhbWluZ31cXG4ke25vcm1hbGl6ZWRTdGFjayB8fCBub3JtYWxpemVkRXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgICAgICAgICAgICBlcnJvckF0dHJpYnV0aW9uOiBkZXNjcmlwdGlvbi5hdHRyaWJ1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBub3JtYWxpemVkRXJyb3IubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBub3JtYWxpemVkRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIC8vIEZhaWwgdGhlIHN0ZXAgdmlhIGV2ZW50IChldmVudC1zb3VyY2VkIGFyY2hpdGVjdHVyZSkuXG4gICAgICAgICAgICAgICAgLy8gU2VyaWFsaXplIHRoZSBvcmlnaW5hbCB0aHJvd24gdmFsdWUgc28gaXRzIGZ1bGwgdHlwZSBpZGVudGl0eVxuICAgICAgICAgICAgICAgIC8vIGFuZCBjdXN0b20gcHJvcGVydGllcyByb3VuZC10cmlwIHRocm91Z2ggdGhlIGV2ZW50IGxvZy5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVN0ZXBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoc3RlcEZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKHN0ZXBGYWlsRXJyKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTdGVwIGFscmVhZHkgaW4gdGVybWluYWwgc3RhdGUg4oCUIGlkZW1wb3RlbnQuXG4gICAgICAgICAgICAgICAgICAgIHN0ZXBSdW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGZhaWxpbmcgc3RlcCwgYnV0IHN0ZXAgaGFzIGFscmVhZHkgZmluaXNoZWQuJyxcbiAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWU6IHN0ZXBGYWlsRXJyLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHN0ZXBGYWlsRXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB0aHJvdyBzdGVwRmFpbEVycjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwRmF0YWxFcnJvcih0cnVlKSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXhSZXRyaWVzID1cbiAgICAgICAgICAgICAgICAgIHN0ZXBGbi5tYXhSZXRyaWVzID8/IERFRkFVTFRfU1RFUF9NQVhfUkVUUklFUztcbiAgICAgICAgICAgICAgICAvLyBzdGVwLmF0dGVtcHQgd2FzIGluY3JlbWVudGVkIGJ5IHN0ZXBfc3RhcnRlZCwgdXNlIGl0IGhlcmVcbiAgICAgICAgICAgICAgICBjb25zdCBjdXJyZW50QXR0ZW1wdCA9IHN0ZXAuYXR0ZW1wdDtcblxuICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBBdHRlbXB0KGN1cnJlbnRBdHRlbXB0KSxcbiAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwTWF4UmV0cmllcyhtYXhSZXRyaWVzKSxcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIC8vIE5vdGU6IG1heFJldHJpZXMgaXMgdGhlIG51bWJlciBvZiBSRVRSSUVTIGFmdGVyIHRoZSBmaXJzdCBhdHRlbXB0LCBzbyB0b3RhbCBhdHRlbXB0cyA9IG1heFJldHJpZXMgKyAxXG4gICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRBdHRlbXB0ID49IG1heFJldHJpZXMgKyAxKSB7XG4gICAgICAgICAgICAgICAgICAvLyBNYXggcmV0cmllcyByZWFjaGVkXG4gICAgICAgICAgICAgICAgICBjb25zdCByZXRyeUNvdW50ID0gc3RlcC5hdHRlbXB0IC0gMTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gZGVzY3JpYmVFcnJvcihlcnIpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgZnJpZW5kbHlTdGVwID0gZm9ybWF0U3RlcE5hbWUoc3RlcE5hbWUpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgZnJhbWluZyA9XG4gICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uLmF0dHJpYnV0aW9uID09PSAnc2RrJ1xuICAgICAgICAgICAgICAgICAgICAgID8gYFN0ZXAgJHtmcmllbmRseVN0ZXB9IGhpdCBtYXggcmV0cmllcyBvbiBhbiBTREsgcnVudGltZSBlcnJvciDigJQgYnViYmxpbmcgdG8gcGFyZW50IHdvcmtmbG93YFxuICAgICAgICAgICAgICAgICAgICAgIDogYFN0ZXAgJHtmcmllbmRseVN0ZXB9IGhpdCBtYXggcmV0cmllcyDigJQgYnViYmxpbmcgZXJyb3IgdGhyb3duIGJ5IHlvdXIgc3RlcCB0byB0aGUgcGFyZW50IHdvcmtmbG93YDtcbiAgICAgICAgICAgICAgICAgIHN0ZXBMb2dnZXIuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIGAke2ZyYW1pbmd9XFxuJHtub3JtYWxpemVkU3RhY2sgfHwgbm9ybWFsaXplZEVycm9yLm1lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBhdHRlbXB0OiBzdGVwLmF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICAgcmV0cnlDb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvckF0dHJpYnV0aW9uOiBkZXNjcmlwdGlvbi5hdHRyaWJ1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWU6IG5vcm1hbGl6ZWRFcnJvci5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogbm9ybWFsaXplZEVycm9yLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAvLyBEb24ndCBpbmNsdWRlIHRoZSBtYWNoaW5lIHN0ZXAgbmFtZSBpbiB0aGUgcGVyc2lzdGVkXG4gICAgICAgICAgICAgICAgICAvLyBlcnJvciBtZXNzYWdlIOKAlCBvYnNlcnZhYmlsaXR5IGFscmVhZHkgc2hvd3Mgd2hpY2ggc3RlcFxuICAgICAgICAgICAgICAgICAgLy8gcHJvZHVjZWQgdGhlIGV2ZW50LCBhbmQgYHN0ZXBOYW1lOiAnc3RlcC8vLi8uLi4vZm9vJ2BcbiAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB0aXRsZSBpcyBqdXN0IG5vaXNlLiBUaGUgQ0xJIGxvZ2dlciByZW5kZXJzXG4gICAgICAgICAgICAgICAgICAvLyBgU3RlcCBmb28gKC4vLi4uKSBoaXQgbWF4IHJldHJpZXNgIHNlcGFyYXRlbHkuXG4gICAgICAgICAgICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBgU3RlcCBmYWlsZWQgYWZ0ZXIgJHttYXhSZXRyaWVzfSAke3BsdXJhbGl6ZSgncmV0cnknLCAncmV0cmllcycsIG1heFJldHJpZXMpfTogJHtub3JtYWxpemVkRXJyb3IubWVzc2FnZX1gO1xuICAgICAgICAgICAgICAgICAgLy8gRmFpbCB0aGUgc3RlcCB2aWEgZXZlbnQgKGV2ZW50LXNvdXJjZWQgYXJjaGl0ZWN0dXJlKS5cbiAgICAgICAgICAgICAgICAgIC8vIFdyYXAgdGhlIG9yaWdpbmFsIGVycm9yIHdpdGggYSBGYXRhbEVycm9yIHRoYXQgcHJlc2VydmVzXG4gICAgICAgICAgICAgICAgICAvLyB0aGUgd3JhcHBlZCBtZXNzYWdlIHBsdXMgdGhlIG9yaWdpbmFsIHRocm93biB2YWx1ZSBhc1xuICAgICAgICAgICAgICAgICAgLy8gYGNhdXNlYCBzbyBpdCdzIHJlY292ZXJhYmxlIGFmdGVyIGh5ZHJhdGlvbi5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IHdyYXBwZWRFcnJvciA9IG5ldyBGYXRhbEVycm9yKGVycm9yTWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAod3JhcHBlZEVycm9yIGFzIEVycm9yKS5jYXVzZSA9IGVycjtcbiAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkU3RhY2spIHdyYXBwZWRFcnJvci5zdGFjayA9IG5vcm1hbGl6ZWRTdGFjaztcbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVN0ZXBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cmFwcGVkRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoc3RlcEZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcEZhaWxFcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gU3RlcCBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlIOKAlCBpZGVtcG90ZW50LlxuICAgICAgICAgICAgICAgICAgICAgIHN0ZXBSdW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAnVHJpZWQgZmFpbGluZyBzdGVwLCBidXQgc3RlcCBoYXMgYWxyZWFkeSBmaW5pc2hlZC4nLFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWU6IHN0ZXBGYWlsRXJyLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3RlcEZhaWxFcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBzdGVwRmFpbEVycjtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXRyeUV4aGF1c3RlZCh0cnVlKSxcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAvLyBOb3QgYXQgbWF4IHJldHJpZXMgeWV0IC0gbG9nIGFzIGEgcmV0cnlhYmxlIGVycm9yXG4gICAgICAgICAgICAgICAgICBpZiAoUmV0cnlhYmxlRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAgICAgICBzdGVwTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgJ0VuY291bnRlcmVkIFJldHJ5YWJsZUVycm9yLCBzdGVwIHdpbGwgYmUgcmV0cmllZCcsXG4gICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXR0ZW1wdDogY3VycmVudEF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWU6IGVyci5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yU3RhY2s6IG5vcm1hbGl6ZWRTdGFjayxcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzdGVwTG9nZ2VyLmluZm8oJ0VuY291bnRlcmVkIEVycm9yLCBzdGVwIHdpbGwgYmUgcmV0cmllZCcsIHtcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgYXR0ZW1wdDogY3VycmVudEF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBub3JtYWxpemVkRXJyb3IubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IG5vcm1hbGl6ZWRFcnJvci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgIGVycm9yU3RhY2s6IG5vcm1hbGl6ZWRTdGFjayxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAvLyBTZXQgc3RlcCB0byBwZW5kaW5nIGZvciByZXRyeSB2aWEgZXZlbnQgKGV2ZW50LXNvdXJjZWQgYXJjaGl0ZWN0dXJlKVxuICAgICAgICAgICAgICAgICAgLy8gc3RlcF9yZXRyeWluZyByZWNvcmRzIHRoZSBlcnJvciBhbmQgc2V0cyBzdGF0dXMgdG8gcGVuZGluZy5cbiAgICAgICAgICAgICAgICAgIC8vIFNlcmlhbGl6ZSB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlIHNvIGl0cyBmdWxsIHR5cGUgaWRlbnRpdHlcbiAgICAgICAgICAgICAgICAgIC8vIGFuZCBjdXN0b20gcHJvcGVydGllcyByb3VuZC10cmlwIHRocm91Z2ggdGhlIGV2ZW50IGxvZy5cbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX3JldHJ5aW5nJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKFJldHJ5YWJsZUVycm9yLmlzKGVycikgJiYge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHJ5QWZ0ZXI6IGVyci5yZXRyeUFmdGVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICB9IGNhdGNoIChzdGVwUmV0cnlFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcFJldHJ5RXJyKSkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFN0ZXAgYWxyZWFkeSBpbiB0ZXJtaW5hbCBzdGF0ZSDigJQgaWRlbXBvdGVudC5cbiAgICAgICAgICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIHJldHJ5aW5nIHN0ZXAsIGJ1dCBzdGVwIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTmFtZTogc3RlcFJldHJ5RXJyLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3RlcFJldHJ5RXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgc3RlcFJldHJ5RXJyO1xuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICBjb25zdCB0aW1lb3V0U2Vjb25kcyA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgICAgICBSZXRyeWFibGVFcnJvci5pcyhlcnIpXG4gICAgICAgICAgICAgICAgICAgICAgPyBNYXRoLmNlaWwoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICgrZXJyLnJldHJ5QWZ0ZXIuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKSkgLyAxMDAwXG4gICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgOiAxXG4gICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXRyeVRpbWVvdXRTZWNvbmRzKHRpbWVvdXRTZWNvbmRzKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXRyeVdpbGxSZXRyeSh0cnVlKSxcbiAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAvLyBBZGQgc3BhbiBldmVudCBmb3IgcmV0cnkgc2NoZWR1bGluZ1xuICAgICAgICAgICAgICAgICAgc3Bhbj8uYWRkRXZlbnQ/LigncmV0cnkuc2NoZWR1bGVkJywge1xuICAgICAgICAgICAgICAgICAgICAncmV0cnkudGltZW91dF9zZWNvbmRzJzogdGltZW91dFNlY29uZHMsXG4gICAgICAgICAgICAgICAgICAgICdyZXRyeS5hdHRlbXB0JzogY3VycmVudEF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICdyZXRyeS5tYXhfcmV0cmllcyc6IG1heFJldHJpZXMsXG4gICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgLy8gSXQncyBhIHJldHJ5YWJsZSBlcnJvciAtIHNvIGhhdmUgdGhlIHF1ZXVlIGtlZXAgdGhlIG1lc3NhZ2UgdmlzaWJsZVxuICAgICAgICAgICAgICAgICAgLy8gc28gdGhhdCBpdCBnZXRzIHJldHJpZWQuXG4gICAgICAgICAgICAgICAgICByZXR1cm4geyB0aW1lb3V0U2Vjb25kcyB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIFJlLWludm9rZSB0aGUgd29ya2Zsb3cgdG8gaGFuZGxlIHRoZSBmYWlsZWQvcmV0cnlpbmcgc3RlcFxuICAgICAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2Uod29ybGQsIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSksIHtcbiAgICAgICAgICAgICAgICBydW5JZDogd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgICB0cmFjZUNhcnJpZXI6IGF3YWl0IHNlcmlhbGl6ZVRyYWNlQ2FycmllcigpLFxuICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyAtLS0gSW5mcmFzdHJ1Y3R1cmU6IGNvbXBsZXRlIHRoZSBzdGVwIC0tLVxuICAgICAgICAgICAgLy8gRXJyb3JzIGhlcmUgKG5ldHdvcmsgZmFpbHVyZXMsIHNlcnZlciBlcnJvcnMpIHByb3BhZ2F0ZSB0byB0aGVcbiAgICAgICAgICAgIC8vIHF1ZXVlIGhhbmRsZXIgZm9yIGF1dG9tYXRpYyByZXRyeS5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBOT1RFOiBOb25lIG9mIHRoZSBjb2RlIGZyb20gdGhpcyBwb2ludCBpcyBndWFyYW50ZWVkIHRvIHJ1bi5cbiAgICAgICAgICAgIC8vIFNpbmNlIHRoZSBzdGVwIG1pZ2h0IGZhaWwgb3IgY2F1c2UgYSBmdW5jdGlvbiB0aW1lb3V0IGFuZCB0aGVcbiAgICAgICAgICAgIC8vIHByb2Nlc3MgbWlnaHQgYmUgU0lHS0lMTCdkLCB0aGUgd29ya2Zsb3cgcnVudGltZSBtdXN0IGJlXG4gICAgICAgICAgICAvLyByZXNpbGllbnQgdG8gdGhlIGJlbG93IGNvZGUgbm90IGV4ZWN1dGluZyBvbiBhIGZhaWxlZCBzdGVwLlxuICAgICAgICAgICAgLy8gKERlaHlkcmF0aW9uIGFscmVhZHkgaGFwcGVuZWQgYWJvdmUgYW5kIGlzIGFjY291bnRlZCBmb3IgaW4gdGhlXG4gICAgICAgICAgICAvLyB1c2VyQ29kZUZhaWxlZCBwYXRoLilcbiAgICAgICAgICAgIHdhaXRVbnRpbChcbiAgICAgICAgICAgICAgUHJvbWlzZS5hbGwob3BzKS5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gSWdub3JlIGV4cGVjdGVkIGNsaWVudCBkaXNjb25uZWN0IGVycm9ycyAoZS5nLiwgYnJvd3NlciByZWZyZXNoIGR1cmluZyBzdHJlYW1pbmcpXG4gICAgICAgICAgICAgICAgY29uc3QgaXNBYm9ydEVycm9yID1cbiAgICAgICAgICAgICAgICAgIGVycj8ubmFtZSA9PT0gJ0Fib3J0RXJyb3InIHx8IGVycj8ubmFtZSA9PT0gJ1Jlc3BvbnNlQWJvcnRlZCc7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0Fib3J0RXJyb3IpIHRocm93IGVycjtcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIC8vIFJ1biBzdGVwX2NvbXBsZXRlZCBhbmQgdHJhY2Ugc2VyaWFsaXphdGlvbiBjb25jdXJyZW50bHk7XG4gICAgICAgICAgICAvLyB0aGUgdHJhY2UgY2FycmllciBpcyB1c2VkIGluIHRoZSBmaW5hbCBxdWV1ZU1lc3NhZ2UgY2FsbCBiZWxvd1xuICAgICAgICAgICAgbGV0IHN0ZXBDb21wbGV0ZWQ0MDkgPSBmYWxzZTtcbiAgICAgICAgICAgIGNvbnN0IFssIHRyYWNlQ2Fycmllcl0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgICAgIHdvcmxkLmV2ZW50c1xuICAgICAgICAgICAgICAgIC5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2NvbXBsZXRlZCcsXG4gICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQ6IHJlc3VsdCBhcyBVaW50OEFycmF5LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgLmNhdGNoKChlcnI6IHVua25vd24pID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gU3RlcCBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlIOKAlCBpZGVtcG90ZW50LlxuICAgICAgICAgICAgICAgICAgICBzdGVwUnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICdUcmllZCBjb21wbGV0aW5nIHN0ZXAsIGJ1dCBzdGVwIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBlcnIubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBzdGVwQ29tcGxldGVkNDA5ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICBzZXJpYWxpemVUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgIF0pO1xuXG4gICAgICAgICAgICBpZiAoc3RlcENvbXBsZXRlZDQwOSkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFN0YXR1cygnY29tcGxldGVkJyksXG4gICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwUmVzdWx0VHlwZSh0eXBlb2YgcmVzdWx0KSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBRdWV1ZSB0aGUgd29ya2Zsb3cgY29udGludWF0aW9uIHdpdGggdGhlIGNvbmN1cnJlbnRseS1yZXNvbHZlZCB0cmFjZSBjYXJyaWVyXG4gICAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2Uod29ybGQsIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSksIHtcbiAgICAgICAgICAgICAgcnVuSWQ6IHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgIHRyYWNlQ2FycmllcixcbiAgICAgICAgICAgICAgcmVxdWVzdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgICB9XG4gICk7XG5cbi8qKlxuICogQSBzaW5nbGUgcm91dGUgdGhhdCBoYW5kbGVzIGFueSBzdGVwIGV4ZWN1dGlvbiByZXF1ZXN0IGFuZCByb3V0ZXMgdG8gdGhlXG4gKiBhcHByb3ByaWF0ZSBzdGVwIGZ1bmN0aW9uLiBXZSBtYXkgZXZlbnR1YWxseSB3YW50IHRvIGNyZWF0ZSBkaWZmZXJlbnQgYnVuZGxlc1xuICogZm9yIGVhY2ggc3RlcCwgdGhpcyBpcyB0ZW1wb3JhcnkuXG4gKi9cbmxldCBjYWNoZWRTdGVwSGFuZGxlcjogKChyZXE6IFJlcXVlc3QpID0+IFByb21pc2U8UmVzcG9uc2U+KSB8IHVuZGVmaW5lZDtcbmV4cG9ydCBjb25zdCBzdGVwRW50cnlwb2ludDogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4gPVxuICAvKiBAX19QVVJFX18gKi8gd2l0aEhlYWx0aENoZWNrKGFzeW5jIChyZXEpID0+IHtcbiAgICBpZiAoIWNhY2hlZFN0ZXBIYW5kbGVyKSB7XG4gICAgICBjYWNoZWRTdGVwSGFuZGxlciA9IHN0ZXBIYW5kbGVyKGF3YWl0IGdldFdvcmxkSGFuZGxlcnMoKSk7XG4gICAgfVxuICAgIHJldHVybiBjYWNoZWRTdGVwSGFuZGxlcihyZXEpO1xuICB9KTtcbiJdfQ==