@workflow/core 5.0.0-beta.2 → 5.0.0-beta.21

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