@workflow/core 5.0.0-beta.39 → 5.0.0-beta.40

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 (95) hide show
  1. package/dist/classify-error.d.ts.map +1 -1
  2. package/dist/classify-error.js +5 -2
  3. package/dist/correlation-id.d.ts +109 -0
  4. package/dist/correlation-id.d.ts.map +1 -0
  5. package/dist/correlation-id.js +139 -0
  6. package/dist/describe-error.d.ts.map +1 -1
  7. package/dist/describe-error.js +14 -1
  8. package/dist/events-consumer.d.ts +1 -0
  9. package/dist/events-consumer.d.ts.map +1 -1
  10. package/dist/events-consumer.js +11 -3
  11. package/dist/private.d.ts +17 -1
  12. package/dist/private.d.ts.map +1 -1
  13. package/dist/private.js +1 -1
  14. package/dist/runtime/constants.d.ts +19 -0
  15. package/dist/runtime/constants.d.ts.map +1 -1
  16. package/dist/runtime/constants.js +30 -1
  17. package/dist/runtime/deployment-guard.d.ts +99 -0
  18. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  19. package/dist/runtime/deployment-guard.js +154 -0
  20. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  21. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  22. package/dist/runtime/quickjs-assets.generated.js +30 -0
  23. package/dist/runtime/quickjs-entrypoint.d.ts +124 -0
  24. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  25. package/dist/runtime/quickjs-entrypoint.js +1429 -0
  26. package/dist/runtime/quickjs-runtime.d.ts +193 -0
  27. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  28. package/dist/runtime/quickjs-runtime.js +1944 -0
  29. package/dist/runtime/run.d.ts +2 -0
  30. package/dist/runtime/run.d.ts.map +1 -1
  31. package/dist/runtime/run.js +9 -4
  32. package/dist/runtime/runs.d.ts +18 -1
  33. package/dist/runtime/runs.d.ts.map +1 -1
  34. package/dist/runtime/runs.js +96 -2
  35. package/dist/runtime/start.d.ts.map +1 -1
  36. package/dist/runtime/start.js +9 -1
  37. package/dist/runtime/suspension-handler.d.ts +7 -0
  38. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  39. package/dist/runtime/suspension-handler.js +29 -2
  40. package/dist/runtime/vm-mode.d.ts +44 -0
  41. package/dist/runtime/vm-mode.d.ts.map +1 -0
  42. package/dist/runtime/vm-mode.js +62 -0
  43. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  44. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  45. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  46. package/dist/runtime.d.ts +1 -1
  47. package/dist/runtime.d.ts.map +1 -1
  48. package/dist/runtime.js +484 -47
  49. package/dist/serialization/codec-devalue-vm.d.ts +9 -0
  50. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  51. package/dist/serialization/codec-devalue-vm.js +137 -0
  52. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  53. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  54. package/dist/serialization/reducers/class-vm.js +77 -0
  55. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  56. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  57. package/dist/serialization/reducers/common-vm.js +579 -0
  58. package/dist/serialization/reducers/common.d.ts.map +1 -1
  59. package/dist/serialization/reducers/common.js +28 -6
  60. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  61. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  62. package/dist/serialization/reducers/step-function-vm.js +97 -0
  63. package/dist/serialization/vm-bundle-entry.d.ts +12 -0
  64. package/dist/serialization/vm-bundle-entry.d.ts.map +1 -0
  65. package/dist/serialization/vm-bundle-entry.js +58 -0
  66. package/dist/serialization/workflow-vm.d.ts +24 -0
  67. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  68. package/dist/serialization/workflow-vm.js +66 -0
  69. package/dist/serialization.d.ts +2 -1
  70. package/dist/serialization.d.ts.map +1 -1
  71. package/dist/serialization.js +26 -21
  72. package/dist/source-map.d.ts +20 -0
  73. package/dist/source-map.d.ts.map +1 -1
  74. package/dist/source-map.js +47 -1
  75. package/dist/step.d.ts.map +1 -1
  76. package/dist/step.js +7 -2
  77. package/dist/telemetry/semantic-conventions.d.ts +78 -0
  78. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  79. package/dist/telemetry/semantic-conventions.js +56 -1
  80. package/dist/telemetry.d.ts +5 -0
  81. package/dist/telemetry.d.ts.map +1 -1
  82. package/dist/telemetry.js +13 -13
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +2 -2
  85. package/dist/workflow/abort-controller.d.ts.map +1 -1
  86. package/dist/workflow/abort-controller.js +6 -4
  87. package/dist/workflow/attribute-dispatcher.js +2 -2
  88. package/dist/workflow/hook.js +2 -2
  89. package/dist/workflow/sleep.js +2 -2
  90. package/dist/workflow.d.ts +49 -2
  91. package/dist/workflow.d.ts.map +1 -1
  92. package/dist/workflow.js +723 -569
  93. package/docs/api-reference/create-hook.mdx +1 -1
  94. package/docs/foundations/starting-workflows.mdx +74 -1
  95. package/package.json +8 -7
@@ -0,0 +1,1429 @@
1
+ /**
2
+ * QuickJS VM integration with the Workflow DevKit.
3
+ *
4
+ * This module provides the entry point for running workflows in the
5
+ * QuickJS WASM VM engine instead of the `node:vm` engine. Both engines
6
+ * implement the same event-replay execution model — every invocation:
7
+ *
8
+ * 1. Loads the full event log for the run
9
+ * 2. Runs the workflow function from the top in a fresh QuickJS VM,
10
+ * replaying the event log to resolve awaited primitives
11
+ * 3. On suspension: creates events + queues steps for new pending ops
12
+ * 4. On completion: creates run_completed
13
+ * 5. On failure: creates run_failed
14
+ */
15
+ import { EntityConflictError, HookNotFoundError, MaxEventsExceededError, RunExpiredError, WorkflowNotRegisteredError, } from '@workflow/errors';
16
+ import { parseWorkflowName } from '@workflow/utils/parse-name';
17
+ import { ROOT_RUN_ID_ATTRIBUTE, SPEC_VERSION_CURRENT, } from '@workflow/world';
18
+ import { classifyRunError } from '../classify-error.js';
19
+ import { runtimeLogger } from '../logger.js';
20
+ import { deriveRunPayloadKeys, encrypt as encryptSerializedData, } from '../serialization/encryption.js';
21
+ import { dehydrateRunError, hydrateRunError, maybeEncrypt, } from '../serialization.js';
22
+ import { remapErrorStack, stripInlineSourceMap } from '../source-map.js';
23
+ import * as Attribute from '../telemetry/semantic-conventions.js';
24
+ import { serializeTraceCarrier } from '../telemetry.js';
25
+ import { getInlineOwnershipLeaseSeconds, getMaxInlineSteps, } from './constants.js';
26
+ import { getPortLazy } from './get-port-lazy.js';
27
+ import { getWorkflowQueueName, queueMessage } from './helpers.js';
28
+ import { startQuickJSWorkflow, } from './quickjs-runtime.js';
29
+ import { ReplayBudget } from './replay-budget.js';
30
+ import { executeStep } from './step-executor.js';
31
+ import { runStepSingleFlight } from './step-single-flight.js';
32
+ import { getWaitContinuationDispatch } from './wait-continuation.js';
33
+ import { getWorld } from './world.js';
34
+ /** Tiny ms timer using performance.now() — already monotonic on Node. */
35
+ function tick() {
36
+ return performance.now();
37
+ }
38
+ /**
39
+ * Returns true when the supplied preloaded events indicate this is the
40
+ * first workflow handler invocation for the run — i.e. the log contains
41
+ * nothing beyond `run_created` / `run_started`. In that case the
42
+ * preloaded events ARE the complete event log and the `events.list`
43
+ * round-trips can be skipped entirely.
44
+ *
45
+ * Crucially, if the world backfilled a missing `run_created` via the
46
+ * resilient start path, `preloadedEvents` contains it even when a fresh
47
+ * `events.list` might not (eventual consistency), so preferring the
48
+ * preloaded events on first invocation is also the more correct choice.
49
+ *
50
+ * Returns false when `preloadedEvents` is missing/empty so the caller
51
+ * falls back to the normal fetch path.
52
+ *
53
+ * Exported for unit testing.
54
+ */
55
+ export function isFirstInvocation(preloadedEvents) {
56
+ if (!Array.isArray(preloadedEvents) || preloadedEvents.length === 0) {
57
+ return false;
58
+ }
59
+ return preloadedEvents.every((e) => e.eventType === 'run_created' || e.eventType === 'run_started');
60
+ }
61
+ /**
62
+ * Queue a step for background execution via the unified workflow queue
63
+ * (V2 architecture). The combined handler in runtime.ts dispatches
64
+ * messages with `stepId` to executeStep, which works for both VM engines.
65
+ * `delaySeconds` supports retry/throttle backoff.
66
+ */
67
+ async function queueStepMessage(params) {
68
+ const { world, runId, workflowRun, step, delaySeconds, namespace, nextTraceCarrier, purpose, wfdiag, } = params;
69
+ const traceCarrier = await nextTraceCarrier();
70
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
71
+ runId,
72
+ stepId: step.correlationId,
73
+ stepName: step.stepId,
74
+ traceCarrier,
75
+ requestedAt: new Date(),
76
+ }, {
77
+ idempotencyKey: purpose === 'dispatch'
78
+ ? step.correlationId
79
+ : `${step.correlationId}:${purpose}`,
80
+ ...(delaySeconds && delaySeconds > 0 ? { delaySeconds } : {}),
81
+ });
82
+ wfdiag('step_queued', {
83
+ stepId: step.stepId,
84
+ correlationId: step.correlationId,
85
+ purpose,
86
+ delaySeconds: delaySeconds ?? 0,
87
+ });
88
+ }
89
+ /**
90
+ * Dispatch durable side effects for a set of pending VM operations:
91
+ * step_created (+ optional queueing), hook_created / hook_received (aborts),
92
+ * attr_set, hook_disposed, and wait_created events.
93
+ *
94
+ * Steps are created but never queued here — queueing (or inline
95
+ * execution) is the caller's decision. Used both for suspension
96
+ * processing (the inline loop) and for the terminal drain (flushing
97
+ * leftover side effects when the workflow completed or failed, mirroring
98
+ * the node:vm engine's drainPendingQueueItems).
99
+ */
100
+ async function dispatchPendingOps(params) {
101
+ const { world, runId, workflowRun, encryptionKey, pendingOperations, namespace, nextTraceCarrier, } = params;
102
+ const skipStepCreation = params.skipStepCreation;
103
+ const wfdiag = params.wfdiag;
104
+ // Set when a hook with a parked getConflict() awaiter had its
105
+ // hook_created written this invocation. The workflow must be re-invoked
106
+ // so replay can confirm creation and resolve the awaiter.
107
+ let createdGetConflictHook = false;
108
+ // Set when a new attr_set event is written this invocation. The
109
+ // workflow must be re-invoked to consume it (resolving the pending
110
+ // setAttributes() promise), so the entrypoint requeues immediately —
111
+ // same pattern as an elapsed wait.
112
+ let createdAttributeEvent = false;
113
+ const opsPromises = [];
114
+ const processHookOp = async (hook) => {
115
+ runtimeLogger.debug('QuickJS runtime: processing hook op', {
116
+ workflowRunId: runId,
117
+ correlationId: hook.correlationId,
118
+ token: hook.token,
119
+ tokenType: typeof hook.token,
120
+ isWebhook: hook.isWebhook,
121
+ isSystem: hook.isSystem,
122
+ hasCreatedEvent: hook.hasCreatedEvent,
123
+ abortRequested: hook.abortRequested,
124
+ });
125
+ if (!hook.hasCreatedEvent) {
126
+ // `hook.metadata` is the format-prefixed devalue bytes
127
+ // produced by `globalThis[Symbol.for('workflow-serialize')]
128
+ // (options.metadata)` inside the VM. Encrypt on the host
129
+ // side before writing — matches the node:vm engine's
130
+ // `dehydrateStepArguments` flow.
131
+ //
132
+ // No pre-check via hooks.list: with deterministic correlationIds
133
+ // (same VM seed across replays) and per-(runId, correlationId)
134
+ // uniqueness in worlds, the storage layer rejects duplicates as
135
+ // EntityConflictError, which we swallow below. This drops one
136
+ // network round-trip per pending hook.
137
+ try {
138
+ const encryptedMetadata = typeof hook.metadata === 'undefined'
139
+ ? undefined
140
+ : await encryptSerializedData(hook.metadata, encryptionKey);
141
+ const result = await world.events.create(runId, {
142
+ eventType: 'hook_created',
143
+ specVersion: SPEC_VERSION_CURRENT,
144
+ correlationId: hook.correlationId,
145
+ eventData: {
146
+ token: hook.token,
147
+ tokenRetentionUntil: hook.tokenRetentionUntil === undefined
148
+ ? undefined
149
+ : new Date(hook.tokenRetentionUntil),
150
+ metadata: encryptedMetadata,
151
+ // Always include isWebhook explicitly. Worlds default it to
152
+ // `true` when absent, which would break the public webhook
153
+ // endpoint's 404 guard for hooks created via createHook().
154
+ isWebhook: hook.isWebhook,
155
+ // System hooks (AbortController) are exempt from user
156
+ // token namespace conflict checks.
157
+ ...(hook.isSystem ? { isSystem: true } : {}),
158
+ },
159
+ });
160
+ // If storage detected a real token conflict with another
161
+ // workflow's hook, re-queue so the workflow handler can
162
+ // process the conflict event and fail gracefully.
163
+ if (result.event?.eventType === 'hook_conflict') {
164
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
165
+ runId,
166
+ traceCarrier: await nextTraceCarrier(),
167
+ requestedAt: new Date(),
168
+ }, { idempotencyKey: `hook_conflict_${hook.correlationId}` });
169
+ }
170
+ }
171
+ catch (err) {
172
+ // Already created by a concurrent invocation — fall through
173
+ // to abort processing below (if any) instead of bailing.
174
+ if (!EntityConflictError.is(err))
175
+ throw err;
176
+ }
177
+ if (hook.hasGetConflictAwaiter) {
178
+ createdGetConflictHook = true;
179
+ }
180
+ }
181
+ if (hook.abortRequested) {
182
+ // Record the abort durably: a hook_received event carrying
183
+ // the VM-serialized `{ aborted: true, reason }` payload,
184
+ // plus a best-effort stream packet for real-time step
185
+ // propagation. Mirrors the node:vm engine's suspension
186
+ // handler (hooksNeedingAbort).
187
+ const abortPayload = hook.abortPayload instanceof Uint8Array
188
+ ? (await encryptSerializedData(hook.abortPayload, encryptionKey))
189
+ : undefined;
190
+ try {
191
+ await world.events.create(runId, {
192
+ eventType: 'hook_received',
193
+ specVersion: SPEC_VERSION_CURRENT,
194
+ correlationId: hook.correlationId,
195
+ eventData: {
196
+ token: hook.token,
197
+ payload: abortPayload,
198
+ },
199
+ });
200
+ }
201
+ catch (err) {
202
+ if (!EntityConflictError.is(err))
203
+ throw err;
204
+ }
205
+ // streamName is derived from the abort hook token
206
+ // (`abrt_{id}` → `strm_{id}_system_abort`).
207
+ if (hook.token.startsWith('abrt_') && abortPayload) {
208
+ const streamName = `strm_${hook.token.slice('abrt_'.length)}_system_abort`;
209
+ try {
210
+ await world.streams.write(runId, streamName, abortPayload);
211
+ await world.streams.close(runId, streamName);
212
+ }
213
+ catch {
214
+ // Best-effort — the hook event provides the durable
215
+ // fallback.
216
+ runtimeLogger.debug('QuickJS runtime: failed to write abort stream packet', {
217
+ workflowRunId: runId,
218
+ correlationId: hook.correlationId,
219
+ });
220
+ }
221
+ }
222
+ wfdiag('abort_recorded', {
223
+ correlationId: hook.correlationId,
224
+ token: hook.token,
225
+ });
226
+ }
227
+ };
228
+ const processHookDisposeOp = async (op) => {
229
+ try {
230
+ await world.events.create(runId, {
231
+ eventType: 'hook_disposed',
232
+ specVersion: SPEC_VERSION_CURRENT,
233
+ correlationId: op.correlationId,
234
+ });
235
+ }
236
+ catch (err) {
237
+ if (EntityConflictError.is(err))
238
+ return;
239
+ // Disposing a hook whose entity no longer (or never) exists is an
240
+ // idempotent no-op: the entity may have been torn down by a
241
+ // concurrent run cancellation, or the hook may have lost its
242
+ // token claim to a conflict. There is nothing left to release.
243
+ if (HookNotFoundError.is(err))
244
+ return;
245
+ throw err;
246
+ }
247
+ };
248
+ // Hook operations are grouped by token and processed SEQUENTIALLY in
249
+ // code order within each group, mirroring the node:vm suspension
250
+ // handler (hookItemsByToken): a dispose() of an earlier hook must
251
+ // release the token before a later same-token hook's creation is
252
+ // validated by the world — parallel dispatch would otherwise record a
253
+ // spurious hook_conflict against the run's own disposed hook (e.g. a
254
+ // dispose→recreate loop reusing one token). Different tokens have no
255
+ // claim interaction, so token groups run in parallel with each other
256
+ // and with the non-hook ops below.
257
+ const hookOpsByToken = new Map();
258
+ for (const op of pendingOperations) {
259
+ let key;
260
+ if (op.type === 'hook' &&
261
+ (!op.hasCreatedEvent || op.abortRequested)) {
262
+ key = op.token;
263
+ }
264
+ else if (op.type === 'hook_dispose' && !op.hasCreatedEvent) {
265
+ // Per-op fallback group when the token is unknown — no ordering
266
+ // guarantees, matching the previous parallel behavior.
267
+ key = op.token ?? `__cid:${op.correlationId}`;
268
+ }
269
+ if (key === undefined)
270
+ continue;
271
+ const group = hookOpsByToken.get(key);
272
+ if (group) {
273
+ group.push(op);
274
+ }
275
+ else {
276
+ hookOpsByToken.set(key, [op]);
277
+ }
278
+ }
279
+ for (const group of hookOpsByToken.values()) {
280
+ opsPromises.push((async () => {
281
+ for (const op of group) {
282
+ if (op.type === 'hook') {
283
+ await processHookOp(op);
284
+ }
285
+ else {
286
+ await processHookDisposeOp(op);
287
+ }
288
+ }
289
+ })());
290
+ }
291
+ for (const op of pendingOperations) {
292
+ if (op.type === 'step' &&
293
+ !op.hasCreatedEvent &&
294
+ !skipStepCreation?.has(op.correlationId)) {
295
+ const step = op;
296
+ opsPromises.push((async () => {
297
+ // Create step_created event. `step.input` is the
298
+ // format-prefixed devalue bytes ("devl" + devalue) produced
299
+ // by `globalThis[Symbol.for('workflow-serialize')]({args,
300
+ // closureVars, thisVal})` inside the VM. The VM has no
301
+ // access to the CryptoKey, so encryption is applied here
302
+ // on the host side — matching what
303
+ // `dehydrateStepArguments` does in the node:vm engine.
304
+ try {
305
+ await world.events.create(runId, {
306
+ eventType: 'step_created',
307
+ specVersion: SPEC_VERSION_CURRENT,
308
+ correlationId: step.correlationId,
309
+ eventData: {
310
+ stepName: step.stepId,
311
+ input: await encryptSerializedData(step.input, encryptionKey),
312
+ },
313
+ });
314
+ }
315
+ catch (err) {
316
+ if (EntityConflictError.is(err))
317
+ return;
318
+ throw err;
319
+ }
320
+ // NOTE: step queueing is the caller's decision — the inline
321
+ // loop executes fresh steps in the live VM and only queues the
322
+ // overflow / retry / backstop cases (see queueStepMessage).
323
+ })());
324
+ }
325
+ else if (op.type === 'attribute' && !op.hasCreatedEvent) {
326
+ const attr = op;
327
+ opsPromises.push((async () => {
328
+ try {
329
+ await world.events.create(runId, {
330
+ eventType: 'attr_set',
331
+ specVersion: SPEC_VERSION_CURRENT,
332
+ correlationId: attr.correlationId,
333
+ eventData: {
334
+ changes: attr.changes,
335
+ writer: { type: 'workflow' },
336
+ ...(attr.allowReservedAttributes
337
+ ? { allowReservedAttributes: true }
338
+ : {}),
339
+ },
340
+ });
341
+ createdAttributeEvent = true;
342
+ }
343
+ catch (err) {
344
+ if (EntityConflictError.is(err)) {
345
+ // Event already exists (concurrent invocation) — the
346
+ // replay still needs to consume it, so requeue.
347
+ createdAttributeEvent = true;
348
+ return;
349
+ }
350
+ throw err;
351
+ }
352
+ })());
353
+ }
354
+ else if (op.type === 'wait' && !op.hasCreatedEvent) {
355
+ const wait = op;
356
+ opsPromises.push((async () => {
357
+ try {
358
+ await world.events.create(runId, {
359
+ eventType: 'wait_created',
360
+ specVersion: SPEC_VERSION_CURRENT,
361
+ correlationId: wait.correlationId,
362
+ eventData: {
363
+ resumeAt: new Date(wait.resumeAt),
364
+ },
365
+ });
366
+ }
367
+ catch (err) {
368
+ if (EntityConflictError.is(err))
369
+ return;
370
+ throw err;
371
+ }
372
+ })());
373
+ }
374
+ }
375
+ // Per-op dispatch runs in parallel.
376
+ await Promise.all(opsPromises);
377
+ return { createdAttributeEvent, createdGetConflictHook };
378
+ }
379
+ /**
380
+ * Run a workflow using the QuickJS WASM VM engine.
381
+ *
382
+ * This replaces the `node:vm` replay path (runWorkflow + EventsConsumer)
383
+ * with a QuickJS VM invocation that performs the same full event replay.
384
+ *
385
+ * KNOWN GAP — precondition guard: unlike the node:vm path, no event write
386
+ * in this file participates in the optimistic-concurrency precondition
387
+ * guard (`withPreconditionRetry` + `stateUpdatedAtForCreate`), which
388
+ * protects a writer holding a stale event-log snapshot from clobbering a
389
+ * concurrent one. The engine currently relies on per-(runId,
390
+ * correlationId) event uniqueness (EntityConflictError dedup) alone. This
391
+ * is a deliberate simplification while the engine is experimental — wiring
392
+ * the guard is tracked follow-up work; anyone adding new write paths here
393
+ * should not assume parity with the node engine on this axis.
394
+ */
395
+ export async function runWorkflowWithQuickJS(params) {
396
+ const { workflowCode, workflowName, workflowRun, preloadedEvents, preloadedEventsComplete, runInput, parentSpan, maxEventsLimit, deliveryAttempt, ownerMessageId, namespace, } = params;
397
+ // Standalone-caller fallback (tests): without a runtime.ts carrier
398
+ // accessor, fall back to the current invocation context.
399
+ const nextTraceCarrier = params.nextTraceCarrier ?? (() => serializeTraceCarrier());
400
+ const world = await getWorld();
401
+ const runId = workflowRun.runId;
402
+ const invocationStart = tick();
403
+ // Strip the inline source map comment before evaluating the bundle in
404
+ // the QuickJS VM. The map is purely host-side metadata for
405
+ // `remapErrorStack` (called below on workflow failures, against the
406
+ // ORIGINAL `workflowCode`). QuickJS retains source text for
407
+ // stack-trace line lookups, so the few-MB base64 comment would bloat
408
+ // the VM heap for no benefit.
409
+ const workflowCodeForVM = stripInlineSourceMap(workflowCode);
410
+ // Per-invocation diagnostic id so debug logs can be correlated even if
411
+ // the same runId is processed by overlapping invocations on different
412
+ // function instances.
413
+ const invocationId = `inv_${Math.random().toString(36).slice(2, 10)}`;
414
+ // Structured per-checkpoint diagnostic helper, grep-friendly by runId.
415
+ const wfdiag = (checkpoint, fields) => {
416
+ runtimeLogger.debug('QUICKJS_VM_DIAG', {
417
+ checkpoint,
418
+ runId,
419
+ invocationId,
420
+ tElapsedMs: Math.round(tick() - invocationStart),
421
+ ...fields,
422
+ });
423
+ };
424
+ parentSpan?.setAttributes({
425
+ ...Attribute.WorkflowVm('quickjs'),
426
+ });
427
+ wfdiag('enter', {
428
+ workflowName,
429
+ deliveryAttempt,
430
+ hasPreloadedEvents: Array.isArray(preloadedEvents) && preloadedEvents.length > 0,
431
+ preloadedEventCount: preloadedEvents?.length ?? 0,
432
+ hasRunInput: !!runInput,
433
+ });
434
+ // The workflowName from the queue topic is already the full workflow ID
435
+ // (e.g. "workflow//./workflows/1_simple//simple")
436
+ const workflowId = workflowName;
437
+ // Resolve the encryption key up front — needed to decrypt event
438
+ // payloads inside the VM and to encrypt event payloads written below.
439
+ // Resolve the FULL capability (symmetric AES key + X25519 keypair), not
440
+ // just `importKey(rawKey)`: a run reading its own event log can encounter
441
+ // sealed (`encp`) hook payloads that a cross-deployment `resumeHook()`
442
+ // wrote to it (sealing is presence-gated on the run's published
443
+ // encryptionPublicKey, which the shared start() path stamps regardless of
444
+ // engine). A bare symmetric key cannot open those and would wedge the run
445
+ // right after hook_received — the node:vm engine resolves the same full
446
+ // capability via memoizeEncryptionKey.
447
+ const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
448
+ const encryptionKey = rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
449
+ // Load the FULL event log for the run. On first invocation the
450
+ // preloaded events from the run_started response are the complete log
451
+ // and save the events.list round-trips; a caller-attested complete
452
+ // preload (lazy hook fast path) is trusted the same way.
453
+ let events;
454
+ let eventsFetchedPages = 0;
455
+ const usePreloaded = (preloadedEventsComplete === true &&
456
+ Array.isArray(preloadedEvents) &&
457
+ preloadedEvents.length > 0) ||
458
+ isFirstInvocation(preloadedEvents);
459
+ if (usePreloaded && preloadedEvents) {
460
+ events = preloadedEvents;
461
+ }
462
+ else {
463
+ const allEvents = [];
464
+ let cursor = null;
465
+ let hasMore = true;
466
+ while (hasMore) {
467
+ const response = await world.events.list({
468
+ runId,
469
+ pagination: {
470
+ sortOrder: 'asc',
471
+ cursor: cursor ?? undefined,
472
+ limit: 1000,
473
+ },
474
+ });
475
+ eventsFetchedPages++;
476
+ allEvents.push(...response.data);
477
+ // Update the cursor to the last successfully fetched page's cursor.
478
+ // Only update when we got results — the final empty-page response
479
+ // returns cursor=null which we must NOT use (it would reset the cursor).
480
+ if (response.cursor) {
481
+ cursor = response.cursor;
482
+ }
483
+ hasMore = response.data.length > 0 && response.cursor != null;
484
+ }
485
+ events = allEvents;
486
+ }
487
+ // Event-limit guard: fail a runaway run once its log reaches the
488
+ // server-supplied ceiling — same enforcement point as the node:vm
489
+ // engine's replay loop.
490
+ if (maxEventsLimit !== undefined && events.length >= maxEventsLimit) {
491
+ throw new MaxEventsExceededError(events.length, maxEventsLimit);
492
+ }
493
+ parentSpan?.setAttributes({
494
+ ...Attribute.QuickJSEventsPreloaded(usePreloaded),
495
+ ...Attribute.QuickJSEventsFetchedCount(events.length),
496
+ ...Attribute.QuickJSEventsFetchedPages(eventsFetchedPages),
497
+ });
498
+ wfdiag('events_fetched', {
499
+ eventCount: events.length,
500
+ eventsFetchedPages,
501
+ usePreloaded,
502
+ eventTypes: events.reduce((acc, e) => {
503
+ acc[e.eventType] = (acc[e.eventType] ?? 0) + 1;
504
+ return acc;
505
+ }, {}),
506
+ });
507
+ // Check for elapsed waits
508
+ const now = Date.now();
509
+ const completedWaitIds = new Set(events
510
+ .filter((e) => e.eventType === 'wait_completed')
511
+ .map((e) => e.correlationId));
512
+ for (const event of events) {
513
+ if (event.eventType === 'wait_created' &&
514
+ event.correlationId &&
515
+ !completedWaitIds.has(event.correlationId)) {
516
+ const eventData = 'eventData' in event
517
+ ? event.eventData
518
+ : undefined;
519
+ const resumeAt = eventData?.resumeAt;
520
+ if (resumeAt && now >= new Date(resumeAt).getTime()) {
521
+ try {
522
+ const result = await world.events.create(runId, {
523
+ eventType: 'wait_completed',
524
+ specVersion: SPEC_VERSION_CURRENT,
525
+ correlationId: event.correlationId,
526
+ });
527
+ if (result.event)
528
+ events.push(result.event);
529
+ }
530
+ catch (err) {
531
+ if (EntityConflictError.is(err))
532
+ continue;
533
+ throw err;
534
+ }
535
+ }
536
+ }
537
+ }
538
+ // Resolve the workflow server port so `getWorkflowMetadata().url` inside
539
+ // the VM matches what the step-side handler reports. Skipped on Vercel —
540
+ // the VM reads VERCEL_URL directly in that environment.
541
+ const isVercel = process.env.VERCEL_URL !== undefined;
542
+ const port = isVercel ? undefined : await getPortLazy();
543
+ // Run the workflow in the QuickJS VM
544
+ runtimeLogger.debug('QuickJS runtime: invoking VM', {
545
+ workflowRunId: runId,
546
+ workflowId,
547
+ eventCount: events.length,
548
+ });
549
+ const session = await startQuickJSWorkflow({
550
+ // Pass the STRIPPED bundle to the VM so the inline source map
551
+ // doesn't end up in the QuickJS heap. The original (unstripped)
552
+ // `workflowCode` is still kept in this host-side scope and is used
553
+ // by `remapErrorStack` on workflow failures below.
554
+ workflowCode: workflowCodeForVM,
555
+ workflowId,
556
+ workflowRun,
557
+ events,
558
+ worldCapabilities: world.capabilities,
559
+ encryptionKey,
560
+ port,
561
+ runInput,
562
+ });
563
+ let result = session.result;
564
+ runtimeLogger.debug('QuickJS runtime: VM returned', {
565
+ workflowRunId: runId,
566
+ completed: !!result.completed,
567
+ suspended: !!result.suspended,
568
+ failed: !!result.failed,
569
+ pendingOpsCount: result.suspended?.pendingOperations?.length,
570
+ });
571
+ wfdiag('vm_returned', {
572
+ outcome: result.completed
573
+ ? 'completed'
574
+ : result.suspended
575
+ ? 'suspended'
576
+ : result.failed
577
+ ? 'failed'
578
+ : 'unknown',
579
+ pendingOpsCount: result.suspended?.pendingOperations?.length ?? 0,
580
+ pendingOpSummary: result.suspended?.pendingOperations?.map((p) => ({
581
+ type: p.type,
582
+ correlationId: p.correlationId,
583
+ hasCreatedEvent: p.hasCreatedEvent,
584
+ ...(p.type === 'step' ? { stepId: p.stepId } : {}),
585
+ })),
586
+ failureMessage: result.failed?.message,
587
+ failureName: result.failed?.name,
588
+ });
589
+ // ---- Inline continuation loop ----
590
+ //
591
+ // While the workflow is suspended, this loop keeps the VM alive and
592
+ // makes as much forward progress as possible within one invocation:
593
+ //
594
+ // 1. Dispatch durable side effects for the suspension's pending ops
595
+ // (step_created / hook_created / attr_set / wait_created /
596
+ // hook_received for aborts) and complete elapsed waits.
597
+ // 2. Feed all newly recorded events (attr_set, hook_created, elapsed
598
+ // wait_completed, terminals written by concurrent invocations, ...)
599
+ // into the LIVE VM via session.continueWithEvents — resuming
600
+ // execution exactly where it left off, no fresh-VM re-replay.
601
+ // Cheap progress is fed BEFORE running step bodies so promise
602
+ // chains that are not gated on steps (hook.getConflict(),
603
+ // setAttributes(), racing sleeps) advance first and can surface
604
+ // additional pending steps for the same inline batch.
605
+ // 3. Once no cheap progress remains, execute up to
606
+ // getMaxInlineSteps() steps created by THIS invocation inline (no
607
+ // queue round-trip), in parallel, with the replay budget paused
608
+ // during step bodies — mirroring the node:vm engine's inline
609
+ // replay loop. Overflow and retry/throttled steps are queued for
610
+ // background execution. A delayed wait-continuation message is
611
+ // enqueued for the soonest pending wait first, so racing timers
612
+ // fire on time (in a separate invocation) while step bodies block
613
+ // this one.
614
+ //
615
+ // The loop exits when the workflow settles, no forward progress is
616
+ // possible in-process, the replay budget is exhausted, or the run is
617
+ // gone.
618
+ const seenEventIds = new Set();
619
+ for (const e of events) {
620
+ if (e.eventId)
621
+ seenEventIds.add(e.eventId);
622
+ }
623
+ // Step cids already executed inline by this invocation.
624
+ const executedStepIds = new Set();
625
+ // Steps for which THIS invocation already sent a queue message.
626
+ const queuedStepIds = new Set();
627
+ // Aborts THIS invocation already recorded (hook_received written) —
628
+ // guards against re-recording when the VM-side flag has not been
629
+ // cleared yet within the same iteration.
630
+ const recordedAbortIds = new Set();
631
+ // Waits for which THIS invocation already completed/scheduled work.
632
+ const completedWaitIds2 = new Set();
633
+ // Inline-ownership state per step correlationId, derived from every
634
+ // event this invocation observes (initial log + every feed) — the
635
+ // quickjs analog of the replay-derived ownership on the node engine's
636
+ // StepInvocationQueueItem (see step-ownership.ts). Latest-wins:
637
+ // events arrive in log order, so a later step_started overwrites the
638
+ // stamp; a step_retrying lapses ownership permanently for the id.
639
+ const stepOwnership = new Map();
640
+ const observeEventsForOwnership = (observed) => {
641
+ for (const e of observed) {
642
+ if (e.correlationId === undefined)
643
+ continue;
644
+ if (e.eventType === 'step_started') {
645
+ const owner = 'eventData' in e &&
646
+ e.eventData &&
647
+ 'ownerMessageId' in e.eventData &&
648
+ typeof e.eventData.ownerMessageId === 'string'
649
+ ? e.eventData.ownerMessageId
650
+ : undefined;
651
+ const prior = stepOwnership.get(e.correlationId);
652
+ stepOwnership.set(e.correlationId, {
653
+ owner,
654
+ startedAtMs: e.createdAt ? +new Date(e.createdAt) : undefined,
655
+ sawRetrying: prior?.sawRetrying ?? false,
656
+ });
657
+ }
658
+ else if (e.eventType === 'step_retrying') {
659
+ const prior = stepOwnership.get(e.correlationId);
660
+ stepOwnership.set(e.correlationId, {
661
+ ...(prior ?? {}),
662
+ sawRetrying: true,
663
+ });
664
+ }
665
+ }
666
+ };
667
+ observeEventsForOwnership(events);
668
+ const scheduledWaitContinuations = new Set();
669
+ const maxInlineSteps = getMaxInlineSteps();
670
+ const budget = new ReplayBudget();
671
+ const workflowStartedAt = workflowRun.startedAt
672
+ ? +workflowRun.startedAt
673
+ : Date.now();
674
+ const rootRunId = workflowRun.attributes?.[ROOT_RUN_ID_ATTRIBUTE] ?? runId;
675
+ let inlineStepsExecuted = 0;
676
+ let runGone = false;
677
+ // Set when this invocation wrote an event the workflow must consume to
678
+ // make progress (attr_set, getConflict-awaited hook_created) and the
679
+ // loop has not yet read it back — eventually-consistent listings can
680
+ // return 0 new events right after a write. If it is still set when the
681
+ // loop exits suspended, the entrypoint requeues immediately instead of
682
+ // exiting awaiting_external with the unblocking event already written
683
+ // and nothing scheduled to read it.
684
+ let pendingRequeueSignal = false;
685
+ /** Fetch all events not yet processed by the live VM (log order). */
686
+ const fetchUnseenEvents = async () => {
687
+ const unseen = [];
688
+ let cursor = null;
689
+ let hasMore = true;
690
+ while (hasMore) {
691
+ const response = await world.events.list({
692
+ runId,
693
+ pagination: {
694
+ sortOrder: 'asc',
695
+ cursor: cursor ?? undefined,
696
+ limit: 1000,
697
+ },
698
+ });
699
+ for (const e of response.data) {
700
+ if (e.eventId && seenEventIds.has(e.eventId))
701
+ continue;
702
+ if (e.eventId)
703
+ seenEventIds.add(e.eventId);
704
+ unseen.push(e);
705
+ }
706
+ if (response.cursor)
707
+ cursor = response.cursor;
708
+ hasMore = response.data.length > 0 && response.cursor != null;
709
+ }
710
+ observeEventsForOwnership(unseen);
711
+ return unseen;
712
+ };
713
+ try {
714
+ let iteration = 0;
715
+ while (result.suspended && !runGone && !budget.isExhausted()) {
716
+ iteration++;
717
+ // Re-check the event ceiling every turn: the loop appends events on
718
+ // each continueWithEvents, so a single invocation can otherwise grow
719
+ // the log arbitrarily far past the operator's limit (the node engine
720
+ // re-checks per replay for the same reason). `seenEventIds` counts
721
+ // every event this invocation has observed — initial log + all
722
+ // feeds.
723
+ if (maxEventsLimit !== undefined && seenEventIds.size >= maxEventsLimit) {
724
+ throw new MaxEventsExceededError(seenEventIds.size, maxEventsLimit);
725
+ }
726
+ const pendingOperations = result.suspended.pendingOperations;
727
+ // Select this turn's inline candidates BEFORE dispatch: fresh steps
728
+ // (no step_created yet) that this invocation hasn't already handled.
729
+ // Their step_created is deliberately NOT written by dispatch — the
730
+ // inline claim below is a lazy step_started carrying the input,
731
+ // which the world applies as an atomic create-claim. A concurrent
732
+ // invocation racing on the same fresh step loses that claim with
733
+ // EntityConflictError and skips, so step bodies cannot double-run
734
+ // (previously both invocations bare-started the step after one lost
735
+ // the swallowed step_created race).
736
+ const freshSteps = pendingOperations.filter((op) => op.type === 'step' &&
737
+ !op.hasCreatedEvent &&
738
+ !executedStepIds.has(op.correlationId) &&
739
+ !queuedStepIds.has(op.correlationId));
740
+ const inlineCandidates = maxInlineSteps <= 0 ? [] : freshSteps.slice(0, maxInlineSteps);
741
+ const inlineClaimCids = new Set(inlineCandidates.map((step) => step.correlationId));
742
+ // 1. Durable side effects for this suspension's pending ops.
743
+ const opsToDispatch = pendingOperations.map((op) => op.type === 'hook' &&
744
+ op.abortRequested &&
745
+ recordedAbortIds.has(op.correlationId)
746
+ ? { ...op, abortRequested: false }
747
+ : op);
748
+ for (const op of pendingOperations) {
749
+ if (op.type === 'hook' && op.abortRequested) {
750
+ recordedAbortIds.add(op.correlationId);
751
+ }
752
+ }
753
+ const dispatched = await dispatchPendingOps({
754
+ world,
755
+ runId,
756
+ workflowRun,
757
+ encryptionKey,
758
+ namespace,
759
+ nextTraceCarrier,
760
+ pendingOperations: opsToDispatch,
761
+ skipStepCreation: inlineClaimCids,
762
+ wfdiag,
763
+ });
764
+ if (dispatched.createdAttributeEvent ||
765
+ dispatched.createdGetConflictHook) {
766
+ pendingRequeueSignal = true;
767
+ }
768
+ // Hand steps beyond the inline cap to the queue NOW — in the same
769
+ // turn their step_created was written by the dispatch above. This
770
+ // must happen BEFORE the event feed below: the feed always observes
771
+ // those very step_created writes as unseen events and `continue`s,
772
+ // so a handoff placed after it is unreachable on the only iteration
773
+ // that still classifies these steps as fresh — next turn they carry
774
+ // hasCreatedEvent and would never be queued at all (the wedge behind
775
+ // promiseRaceStressTestWorkflow hanging in the quickjs CI legs). The
776
+ // bare-correlationId idempotency key makes repeats harmless.
777
+ const overflowSteps = freshSteps.slice(inlineCandidates.length);
778
+ for (const step of overflowSteps) {
779
+ queuedStepIds.add(step.correlationId);
780
+ await queueStepMessage({
781
+ world,
782
+ runId,
783
+ workflowRun,
784
+ step,
785
+ namespace,
786
+ nextTraceCarrier,
787
+ purpose: 'dispatch',
788
+ wfdiag,
789
+ });
790
+ }
791
+ // Complete elapsed waits so their wait_completed events are picked
792
+ // up by the feed below (instead of a queue re-invocation).
793
+ const waitCompletePromises = [];
794
+ for (const op of pendingOperations) {
795
+ if (op.type !== 'wait')
796
+ continue;
797
+ const wait = op;
798
+ if (completedWaitIds2.has(wait.correlationId))
799
+ continue;
800
+ if (new Date(wait.resumeAt).getTime() - Date.now() > 0)
801
+ continue;
802
+ completedWaitIds2.add(wait.correlationId);
803
+ waitCompletePromises.push((async () => {
804
+ try {
805
+ await world.events.create(runId, {
806
+ eventType: 'wait_completed',
807
+ specVersion: SPEC_VERSION_CURRENT,
808
+ correlationId: wait.correlationId,
809
+ });
810
+ }
811
+ catch (err) {
812
+ if (EntityConflictError.is(err))
813
+ return;
814
+ throw err;
815
+ }
816
+ })());
817
+ }
818
+ if (waitCompletePromises.length > 0) {
819
+ await Promise.all(waitCompletePromises);
820
+ }
821
+ // 2. Cheap progress first: feed newly recorded events into the live
822
+ // VM before blocking on step bodies.
823
+ {
824
+ const newEvents = await fetchUnseenEvents();
825
+ if (newEvents.length > 0) {
826
+ // The listing caught up with this invocation's writes — any
827
+ // attr_set / getConflict hook_created has been (or is being)
828
+ // consumed by the live VM, so no external requeue is needed.
829
+ pendingRequeueSignal = false;
830
+ result = await session.continueWithEvents(newEvents);
831
+ wfdiag('inline_iteration', {
832
+ iteration,
833
+ phase: 'feed',
834
+ fedEvents: newEvents.length,
835
+ outcome: result.completed
836
+ ? 'completed'
837
+ : result.failed
838
+ ? 'failed'
839
+ : 'suspended',
840
+ });
841
+ continue;
842
+ }
843
+ }
844
+ // 3. No cheap progress left — execute steps inline.
845
+ const stepOps = pendingOperations.filter((op) => op.type === 'step');
846
+ // Steps created by an EARLIER invocation (or an earlier turn) that
847
+ // are still pending, with no work owned by THIS invocation. Mirror
848
+ // the node engine's ownership decision table (step-ownership.ts) —
849
+ // NOT a deliveryAttempt gate: worlds advance the attempt counter on
850
+ // routine redeliveries (world-local counts every handled response),
851
+ // so attempt > 1 is the common case and would fire backstops at
852
+ // steps actively executing inline in a live invocation.
853
+ //
854
+ // - Ownership lease ACTIVE, held by ANOTHER message → the step is
855
+ // (presumably) executing inline in a live invocation. Arm a
856
+ // DELAYED backstop for the lease remainder, keyed to the
857
+ // ownership epoch (a refreshed lease re-arms a fresh backstop
858
+ // instead of deduping against the in-flight one). If the owner
859
+ // completes normally, the backstop delivery resolves the step
860
+ // as 'skipped'.
861
+ // - Ownership lease ACTIVE, held by THIS message → this delivery
862
+ // is the owner's redelivery; the claimant crashed
863
+ // mid-execution. Dispatch immediately for background recovery.
864
+ // - No stamp / lease EXPIRED / step_retrying observed → the step
865
+ // is queue-owned or orphaned. Dispatch immediately; the
866
+ // bare-correlationId idempotency key dedupes against the
867
+ // original handoff.
868
+ const nowMs = Date.now();
869
+ for (const step of stepOps) {
870
+ if (!step.hasCreatedEvent)
871
+ continue;
872
+ if (executedStepIds.has(step.correlationId))
873
+ continue;
874
+ if (queuedStepIds.has(step.correlationId))
875
+ continue;
876
+ const ownership = stepOwnership.get(step.correlationId);
877
+ const ownershipActive = ownership !== undefined &&
878
+ ownership.owner !== undefined &&
879
+ !ownership.sawRetrying;
880
+ let leaseRemainingSeconds = 0;
881
+ if (ownershipActive && ownership.startedAtMs !== undefined) {
882
+ const leaseSeconds = getInlineOwnershipLeaseSeconds();
883
+ leaseRemainingSeconds = Math.min(leaseSeconds, Math.max(0, Math.ceil((ownership.startedAtMs + leaseSeconds * 1000 - nowMs) / 1000)));
884
+ }
885
+ if (ownershipActive &&
886
+ ownership.owner !== ownerMessageId &&
887
+ leaseRemainingSeconds > 0) {
888
+ queuedStepIds.add(step.correlationId);
889
+ await queueStepMessage({
890
+ world,
891
+ runId,
892
+ workflowRun,
893
+ step,
894
+ delaySeconds: leaseRemainingSeconds,
895
+ namespace,
896
+ nextTraceCarrier,
897
+ purpose: `backstop:${ownership.startedAtMs}`,
898
+ wfdiag,
899
+ });
900
+ }
901
+ else {
902
+ queuedStepIds.add(step.correlationId);
903
+ await queueStepMessage({
904
+ world,
905
+ runId,
906
+ workflowRun,
907
+ step,
908
+ namespace,
909
+ nextTraceCarrier,
910
+ purpose: 'dispatch',
911
+ wfdiag,
912
+ });
913
+ }
914
+ }
915
+ if (inlineCandidates.length === 0) {
916
+ // No in-process progress possible — the run awaits an external
917
+ // stimulus (hook payload, queued step, wait timer).
918
+ break;
919
+ }
920
+ // Racing timers must fire on time while step bodies block this
921
+ // invocation: enqueue a delayed continuation for the soonest
922
+ // pending wait (a separate invocation writes its wait_completed at
923
+ // the right log position — same mechanism as the node:vm engine's
924
+ // wait-continuation dispatch).
925
+ let soonestWait;
926
+ for (const op of pendingOperations) {
927
+ if (op.type !== 'wait')
928
+ continue;
929
+ const wait = op;
930
+ if (scheduledWaitContinuations.has(wait.correlationId))
931
+ continue;
932
+ // Waits whose wait_completed THIS invocation already wrote (the
933
+ // elapsed-wait pass above) are done — the event just hasn't fed
934
+ // back into the VM yet. No continuation needed.
935
+ if (completedWaitIds2.has(wait.correlationId))
936
+ continue;
937
+ const resumeMs = new Date(wait.resumeAt).getTime() - Date.now();
938
+ // An already-elapsed wait MUST still get a continuation (clamped
939
+ // to the 1s minimum, exactly like the node engine's
940
+ // `Math.max(1000, resumeAtMs - now)`), not be skipped: a wait
941
+ // whose deadline falls between this iteration's elapsed-wait
942
+ // pass (which saw it as still pending and wrote nothing) and
943
+ // this sweep would otherwise get NEITHER a wait_completed NOR a
944
+ // continuation — and the inline batch below then blocks this
945
+ // invocation for the full step duration with no wake armed
946
+ // anywhere. For `Promise.race(step, sleep)` that silently hands
947
+ // the race to the step: the sleep's wait_completed is never
948
+ // written and the run completes with the wrong winner. The
949
+ // window between the two checks spans this iteration's dispatch
950
+ // + feed round-trips, so on network-backed worlds (world-vercel)
951
+ // a short sleep lands in it routinely — observed as a ~50%
952
+ // sleepWinsRaceWorkflow failure rate in the Vercel e2e legs,
953
+ // while world-local's sub-ms round-trips masked it locally. The
954
+ // continuation invocation's pre-VM elapsed check writes the
955
+ // wait_completed ~1s later.
956
+ const seconds = Math.max(1, Math.ceil(resumeMs / 1000));
957
+ if (!soonestWait || seconds < soonestWait.seconds) {
958
+ soonestWait = { correlationId: wait.correlationId, seconds };
959
+ }
960
+ }
961
+ if (soonestWait) {
962
+ scheduledWaitContinuations.add(soonestWait.correlationId);
963
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
964
+ runId,
965
+ traceCarrier: await nextTraceCarrier(),
966
+ requestedAt: new Date(),
967
+ }, getWaitContinuationDispatch(soonestWait.seconds, soonestWait.correlationId));
968
+ wfdiag('wait_continuation_scheduled', {
969
+ correlationId: soonestWait.correlationId,
970
+ delaySeconds: soonestWait.seconds,
971
+ });
972
+ }
973
+ // Execute the inline batch in parallel. The replay budget is
974
+ // paused while step bodies run — step duration is bounded by the
975
+ // platform function duration, not the replay timeout. NOTE (by
976
+ // design): with the budget parked per batch, the only bound on how
977
+ // many inline steps one invocation can chain is the platform's
978
+ // function timeout — the SDK deliberately imposes no cap of its
979
+ // own, matching the node:vm engine, where a long sequential
980
+ // workflow likewise runs step-by-step until the platform reclaims
981
+ // the invocation and a redelivery resumes from the log.
982
+ budget.pause();
983
+ let outcomes;
984
+ try {
985
+ outcomes = await Promise.all(inlineCandidates.map((step) => runStepSingleFlight(runId, step.correlationId, () => (async () => executeStep({
986
+ world,
987
+ workflowRunId: runId,
988
+ workflowDeploymentId: workflowRun.deploymentId,
989
+ workflowName: workflowRun.workflowName,
990
+ workflowStartedAt,
991
+ rootRunId,
992
+ stepId: step.correlationId,
993
+ stepName: step.stepId,
994
+ encryptionKey,
995
+ runSpecVersion: workflowRun.specVersion,
996
+ // Lazy inline claim: step_created is deferred (dispatch
997
+ // skipped it) and this step_started carries the input,
998
+ // so the world creates the step atomically —
999
+ // exactly-one-owner. A concurrent claimant gets
1000
+ // EntityConflictError → { type: 'skipped' } and never
1001
+ // runs the body. Mirrors the node engine's inline path.
1002
+ lazyStepInput: await encryptSerializedData(step.input, encryptionKey),
1003
+ // Ownership stamp: wake replays see the body as in
1004
+ // flight in this invocation and arm a delayed backstop
1005
+ // instead of immediately requeueing the step.
1006
+ ownerMessageId,
1007
+ // A lazy step is brand-new by construction — first
1008
+ // attempt.
1009
+ authoritativeAttempt: 1,
1010
+ }))())));
1011
+ }
1012
+ finally {
1013
+ budget.resume();
1014
+ }
1015
+ inlineStepsExecuted += inlineCandidates.length;
1016
+ for (let i = 0; i < inlineCandidates.length; i++) {
1017
+ const step = inlineCandidates[i];
1018
+ const outcome = outcomes[i];
1019
+ executedStepIds.add(step.correlationId);
1020
+ if (outcome.type === 'retry' || outcome.type === 'throttled') {
1021
+ // Hand the step to the queue with the requested backoff —
1022
+ // background delivery drives the retry from here.
1023
+ queuedStepIds.add(step.correlationId);
1024
+ await queueStepMessage({
1025
+ world,
1026
+ runId,
1027
+ workflowRun,
1028
+ step,
1029
+ delaySeconds: outcome.timeoutSeconds,
1030
+ namespace,
1031
+ nextTraceCarrier,
1032
+ // Suffixed key: this step was inline-claimed, so no dispatch
1033
+ // publish exists under the bare correlationId — but suffixing
1034
+ // keeps the retry enqueueable even if a world retired a
1035
+ // historical key for this step (see the purpose docs above).
1036
+ purpose: 'retry:1',
1037
+ wfdiag,
1038
+ });
1039
+ }
1040
+ else if (outcome.type === 'gone') {
1041
+ runGone = true;
1042
+ }
1043
+ // 'skipped': a concurrent invocation won the lazy create-claim and
1044
+ // owns the body. Marked executed above so this invocation never
1045
+ // re-claims it; the winner's terminal events arrive via the feed
1046
+ // (or drive a separate invocation).
1047
+ }
1048
+ wfdiag('inline_steps_executed', {
1049
+ iteration,
1050
+ count: inlineCandidates.length,
1051
+ outcomes: outcomes.map((o) => o.type),
1052
+ });
1053
+ // Feed the inline batch's terminal events into the live VM. When
1054
+ // the eventually-consistent listing has not surfaced them yet,
1055
+ // exiting must NOT ack silently: the terminals this invocation just
1056
+ // caused are durably written with no queue message left to consume
1057
+ // them (inline steps have none), so an awaiting_external exit would
1058
+ // park the run 'running' with all its steps complete. Raise the
1059
+ // requeue signal so the suspended exit schedules a fresh immediate
1060
+ // invocation whose fresh read picks the terminals up. Outcomes that
1061
+ // wrote no terminal ('skipped' — a concurrent claimant owns the
1062
+ // body; 'gone', retry/throttled — a queue message exists) don't
1063
+ // need it, but signaling on them too only costs a no-op invocation
1064
+ // in an already-rare lag window.
1065
+ const newEvents = await fetchUnseenEvents();
1066
+ if (newEvents.length === 0) {
1067
+ pendingRequeueSignal = true;
1068
+ break;
1069
+ }
1070
+ result = await session.continueWithEvents(newEvents);
1071
+ wfdiag('inline_iteration', {
1072
+ iteration,
1073
+ phase: 'steps',
1074
+ fedEvents: newEvents.length,
1075
+ outcome: result.completed
1076
+ ? 'completed'
1077
+ : result.failed
1078
+ ? 'failed'
1079
+ : 'suspended',
1080
+ budgetExhausted: budget.isExhausted(),
1081
+ });
1082
+ }
1083
+ }
1084
+ finally {
1085
+ session.dispose();
1086
+ }
1087
+ parentSpan?.setAttributes({
1088
+ ...Attribute.QuickJSInlineSteps(inlineStepsExecuted),
1089
+ });
1090
+ if (result.completed) {
1091
+ // Workflow completed
1092
+ runtimeLogger.info('QuickJS runtime: workflow completed', {
1093
+ workflowRunId: runId,
1094
+ });
1095
+ parentSpan?.setAttributes({
1096
+ ...Attribute.QuickJSOutcome('completed'),
1097
+ });
1098
+ // Flush leftover pending side effects (abort recordings, system-hook
1099
+ // disposals, fire-and-forget attribute/hook events) BEFORE writing
1100
+ // run_completed — mirrors the node:vm engine's drainPendingQueueItems.
1101
+ // Drain failures are swallowed: the workflow's own outcome is the
1102
+ // source of truth.
1103
+ if (result.completed.drainOperations?.length) {
1104
+ try {
1105
+ await dispatchPendingOps({
1106
+ world,
1107
+ runId,
1108
+ workflowRun,
1109
+ encryptionKey,
1110
+ namespace,
1111
+ nextTraceCarrier,
1112
+ pendingOperations: result.completed.drainOperations,
1113
+ wfdiag,
1114
+ });
1115
+ }
1116
+ catch (err) {
1117
+ runtimeLogger.warn('QuickJS runtime: terminal drain failed', {
1118
+ workflowRunId: runId,
1119
+ message: err?.message,
1120
+ });
1121
+ }
1122
+ }
1123
+ // Create run_completed event.
1124
+ // The VM serializes the workflow result as format-prefixed devalue bytes
1125
+ // ("devl" + devalue) with no encryption (the VM has no access to the
1126
+ // CryptoKey). Host-side encryption is applied here so that `run_completed`
1127
+ // events have the same `encr`-prefixed payload shape that the node:vm
1128
+ // engine's `dehydrateWorkflowReturnValue` produces.
1129
+ try {
1130
+ await world.events.create(runId, {
1131
+ eventType: 'run_completed',
1132
+ specVersion: SPEC_VERSION_CURRENT,
1133
+ eventData: {
1134
+ output: await encryptSerializedData(result.completed.result, encryptionKey),
1135
+ },
1136
+ });
1137
+ wfdiag('exit_completed', { result: 'run_completed_written' });
1138
+ }
1139
+ catch (err) {
1140
+ if (EntityConflictError.is(err) || RunExpiredError.is(err)) {
1141
+ runtimeLogger.warn('Workflow already finished, skipping run_completed', { workflowRunId: runId });
1142
+ wfdiag('exit_completed', { result: 'already_finished' });
1143
+ return;
1144
+ }
1145
+ wfdiag('exit_completed_error', {
1146
+ errorName: err?.name,
1147
+ errorMessage: err?.message,
1148
+ });
1149
+ throw err;
1150
+ }
1151
+ }
1152
+ else if (result.suspended) {
1153
+ // Workflow still suspended after the inline loop. All durable side
1154
+ // effects for the final suspension state were already dispatched by
1155
+ // the loop; what remains is deciding how the run gets re-invoked.
1156
+ const { pendingOperations } = result.suspended;
1157
+ runtimeLogger.info('QuickJS runtime: workflow suspended', {
1158
+ workflowRunId: runId,
1159
+ inlineStepsExecuted,
1160
+ pendingSteps: pendingOperations.filter((p) => p.type === 'step').length,
1161
+ pendingWaits: pendingOperations.filter((p) => p.type === 'wait').length,
1162
+ pendingOps: pendingOperations.map((p) => ({
1163
+ type: p.type,
1164
+ correlationId: p.correlationId,
1165
+ hasCreatedEvent: p.hasCreatedEvent,
1166
+ ...(p.type === 'step' ? { stepId: p.stepId } : {}),
1167
+ })),
1168
+ });
1169
+ parentSpan?.setAttributes({
1170
+ ...Attribute.QuickJSOutcome('suspended'),
1171
+ ...Attribute.QuickJSPendingOpsCount(pendingOperations.length),
1172
+ });
1173
+ if (runGone) {
1174
+ // The run no longer exists (expired / deleted) — nothing to drive.
1175
+ wfdiag('exit_suspended', { action: 'run_gone' });
1176
+ return;
1177
+ }
1178
+ // Exit requeues are FRESH messages, never a `{ timeoutSeconds }`
1179
+ // visibility-redelivery of the current message. Redelivering the
1180
+ // CURRENT message is a trap: a hook-resume delivery carries
1181
+ // `hookInput`, and its redelivery re-runs the lazy-resume re-ensure
1182
+ // in the handler prologue — if the workflow disposed that hook
1183
+ // during this invocation (dispose → sleep), a world that rejects
1184
+ // the re-ensure would ack the message as "nothing left to resume"
1185
+ // and the continuation it carried is silently lost. A fresh message
1186
+ // carries only `runId`, so its delivery always reaches replay (and
1187
+ // under turbo a reschedule would re-engage turbo against a stale
1188
+ // preloaded log — see the reinvoke() docs in runtime.ts).
1189
+ const requeueImmediately = async () => {
1190
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
1191
+ runId,
1192
+ traceCarrier: await nextTraceCarrier(),
1193
+ requestedAt: new Date(),
1194
+ });
1195
+ };
1196
+ if (budget.isExhausted()) {
1197
+ // The loop stopped on the replay budget with progress still
1198
+ // possible — continue in a fresh invocation.
1199
+ wfdiag('exit_suspended', { action: 'budget_exhausted_requeue' });
1200
+ await requeueImmediately();
1201
+ return;
1202
+ }
1203
+ // Exit wait sweep. A wait that elapsed in the window since the
1204
+ // loop's last check requeues immediately (its wait_completed is
1205
+ // written by the next invocation's elapsed-wait pass); pending waits
1206
+ // whose continuation the loop already enqueued are skipped.
1207
+ let soonestWait;
1208
+ let hasElapsedWait = false;
1209
+ for (const op of pendingOperations) {
1210
+ if (op.type !== 'wait')
1211
+ continue;
1212
+ const wait = op;
1213
+ const resumeMs = new Date(wait.resumeAt).getTime() - Date.now();
1214
+ if (resumeMs <= 0) {
1215
+ hasElapsedWait = true;
1216
+ }
1217
+ else if (!scheduledWaitContinuations.has(wait.correlationId)) {
1218
+ const timeoutSeconds = Math.max(1, Math.ceil(resumeMs / 1000));
1219
+ if (!soonestWait || timeoutSeconds < soonestWait.seconds) {
1220
+ soonestWait = {
1221
+ seconds: timeoutSeconds,
1222
+ correlationId: wait.correlationId,
1223
+ };
1224
+ }
1225
+ }
1226
+ }
1227
+ if (hasElapsedWait) {
1228
+ wfdiag('exit_suspended', { action: 'wait_elapsed_requeue' });
1229
+ await requeueImmediately();
1230
+ return;
1231
+ }
1232
+ if (pendingRequeueSignal) {
1233
+ // This invocation wrote events the workflow needs to consume
1234
+ // (attr_set / getConflict-awaited hook_created / inline step
1235
+ // terminals) but the eventually-consistent listing never returned
1236
+ // them before the loop exited. Without a requeue the run would
1237
+ // park awaiting_external with its unblocking events already
1238
+ // durably written and no future invocation coming — requeue
1239
+ // immediately so a fresh read picks them up. In the common case
1240
+ // the loop's own feed observes the writes and clears this flag, so
1241
+ // this only fires when the read actually lagged.
1242
+ wfdiag('exit_suspended', { action: 'unread_self_write_requeue' });
1243
+ await requeueImmediately();
1244
+ return;
1245
+ }
1246
+ if (soonestWait) {
1247
+ // Delayed continuation for the soonest pending wait the loop has
1248
+ // not already scheduled. The dispatch helper handles delay
1249
+ // clamping (long waits chain across hops) and idempotency-key
1250
+ // dedup of re-observations of the same pending wait — see
1251
+ // runtime/wait-continuation.ts.
1252
+ wfdiag('exit_suspended', {
1253
+ action: 'schedule_wait_timeout',
1254
+ timeoutSeconds: soonestWait.seconds,
1255
+ waitCorrelationId: soonestWait.correlationId,
1256
+ });
1257
+ scheduledWaitContinuations.add(soonestWait.correlationId);
1258
+ await queueMessage(world, getWorkflowQueueName(workflowRun.workflowName, namespace), {
1259
+ runId,
1260
+ traceCarrier: await nextTraceCarrier(),
1261
+ requestedAt: new Date(),
1262
+ }, getWaitContinuationDispatch(soonestWait.seconds, soonestWait.correlationId));
1263
+ return;
1264
+ }
1265
+ wfdiag('exit_suspended', {
1266
+ action: 'awaiting_external',
1267
+ pendingOpsCount: pendingOperations.length,
1268
+ });
1269
+ }
1270
+ else if (result.failed) {
1271
+ // Workflow failed — remap stack trace using inline source maps
1272
+ let errorStack = result.failed.stack;
1273
+ if (errorStack) {
1274
+ const parsedName = parseWorkflowName(workflowName);
1275
+ const filename = parsedName?.moduleSpecifier || workflowName;
1276
+ errorStack = remapErrorStack(errorStack, filename, workflowCode);
1277
+ }
1278
+ // Classify the error so consumers (`run.returnValue`, observability)
1279
+ // get `USER_ERROR` / `RUNTIME_ERROR` on `error.cause.code`, matching
1280
+ // what the node:vm engine already does in runtime.ts.
1281
+ //
1282
+ // The VM serializes errors as `{ name, message, stack }`, so we
1283
+ // reconstruct a host-side Error of the correct class based on the
1284
+ // VM-side `name` — specific WorkflowRuntimeError subclasses need
1285
+ // to be preserved so classifyRunError() tags them as RUNTIME_ERROR.
1286
+ const reconstructed = result.failed.name === 'WorkflowNotRegisteredError'
1287
+ ? new WorkflowNotRegisteredError(workflowName)
1288
+ : result.failed.name === 'Error'
1289
+ ? new Error(result.failed.message)
1290
+ : Object.assign(new Error(result.failed.message), {
1291
+ name: result.failed.name,
1292
+ });
1293
+ const errorCode = classifyRunError(reconstructed);
1294
+ runtimeLogger.error('QuickJS runtime: workflow failed', {
1295
+ workflowRunId: runId,
1296
+ errorName: result.failed.name,
1297
+ errorMessage: result.failed.message,
1298
+ errorStack,
1299
+ errorCode,
1300
+ });
1301
+ parentSpan?.setAttributes({
1302
+ ...Attribute.QuickJSOutcome('failed'),
1303
+ });
1304
+ // Flush leftover pending side effects before writing run_failed —
1305
+ // same drain semantics as the completed branch.
1306
+ if (result.failed.drainOperations?.length) {
1307
+ try {
1308
+ await dispatchPendingOps({
1309
+ world,
1310
+ runId,
1311
+ workflowRun,
1312
+ encryptionKey,
1313
+ namespace,
1314
+ nextTraceCarrier,
1315
+ pendingOperations: result.failed.drainOperations,
1316
+ wfdiag,
1317
+ });
1318
+ }
1319
+ catch (err) {
1320
+ runtimeLogger.warn('QuickJS runtime: terminal drain failed', {
1321
+ workflowRunId: runId,
1322
+ message: err?.message,
1323
+ });
1324
+ }
1325
+ }
1326
+ // Create run_failed event. Serialize the error through the
1327
+ // first-class dehydration pipeline so consumers (CLI, observability,
1328
+ // run.returnValue) get the same hydrated value shape as the node:vm
1329
+ // engine emits. Two paths:
1330
+ // * Modern (valueBytes present): the VM-side rejection handler
1331
+ // serialized the original thrown value (Error subclass with
1332
+ // cause chain, plain object, primitive, etc.) using the VM's
1333
+ // workflow-serialize. Pass those bytes through directly so
1334
+ // type identity, cause chains, and non-Error throws survive.
1335
+ // We just need to apply encryption if configured (the VM's
1336
+ // serializer doesn't have access to the encryption key).
1337
+ // * Legacy fallback: reconstruct an Error from the host-visible
1338
+ // {name, message, stack} fields and run it through
1339
+ // `dehydrateRunError`. Used when valueBytes is absent (e.g.
1340
+ // extractError pseudo-failures from VM bootstrap).
1341
+ let dehydratedError;
1342
+ if (result.failed.valueBytes) {
1343
+ // Hydrate the VM-side bytes, remap the error stack with the
1344
+ // host-side source map (the VM can't do this — it lacks both the
1345
+ // source map and `remapErrorStack`), and re-dehydrate. This
1346
+ // preserves the original value's type identity / cause chain
1347
+ // while fixing up frames to point at the user's source files.
1348
+ try {
1349
+ const hydrated = await hydrateRunError(result.failed.valueBytes, runId, undefined // VM bytes are unencrypted
1350
+ );
1351
+ if (hydrated &&
1352
+ typeof hydrated === 'object' &&
1353
+ 'stack' in hydrated &&
1354
+ typeof hydrated.stack === 'string') {
1355
+ const parsedName = parseWorkflowName(workflowName);
1356
+ const filename = parsedName?.moduleSpecifier || workflowName;
1357
+ hydrated.stack = remapErrorStack(hydrated.stack, filename, workflowCode);
1358
+ }
1359
+ // Walk the cause chain and remap nested stacks too.
1360
+ const seen = new WeakSet();
1361
+ let node = hydrated?.cause;
1362
+ while (node && typeof node === 'object' && !seen.has(node)) {
1363
+ seen.add(node);
1364
+ const nodeStack = node.stack;
1365
+ if (typeof nodeStack === 'string') {
1366
+ const parsedName = parseWorkflowName(workflowName);
1367
+ const filename = parsedName?.moduleSpecifier || workflowName;
1368
+ node.stack = remapErrorStack(nodeStack, filename, workflowCode);
1369
+ }
1370
+ node = node.cause;
1371
+ }
1372
+ dehydratedError = await dehydrateRunError(hydrated, runId, encryptionKey);
1373
+ }
1374
+ catch (rehydrateErr) {
1375
+ // If hydration / re-dehydration fails for any reason, fall
1376
+ // back to passing through the original VM bytes (just apply
1377
+ // encryption if configured). Better to lose source-mapped
1378
+ // frames than to lose the error entirely.
1379
+ runtimeLogger.warn('QuickJS runtime: failed to remap workflow error stack, passing VM bytes through', {
1380
+ workflowRunId: runId,
1381
+ message: rehydrateErr?.message,
1382
+ });
1383
+ dehydratedError = (await maybeEncrypt(result.failed.valueBytes, encryptionKey));
1384
+ }
1385
+ }
1386
+ else {
1387
+ if (errorStack) {
1388
+ reconstructed.stack = errorStack;
1389
+ }
1390
+ try {
1391
+ dehydratedError = await dehydrateRunError(reconstructed, runId, encryptionKey);
1392
+ }
1393
+ catch (serErr) {
1394
+ // Fall back to a minimal payload so the run still terminates
1395
+ // even when the error itself contains unserializable values.
1396
+ runtimeLogger.warn('QuickJS runtime: failed to dehydrate run error, falling back to bare Error', { workflowRunId: runId, message: serErr?.message });
1397
+ dehydratedError = await dehydrateRunError(Object.assign(new Error(result.failed.message), {
1398
+ name: result.failed.name,
1399
+ }), runId, encryptionKey);
1400
+ }
1401
+ }
1402
+ try {
1403
+ await world.events.create(runId, {
1404
+ eventType: 'run_failed',
1405
+ specVersion: SPEC_VERSION_CURRENT,
1406
+ eventData: {
1407
+ error: dehydratedError,
1408
+ errorCode,
1409
+ },
1410
+ });
1411
+ }
1412
+ catch (err) {
1413
+ if (EntityConflictError.is(err) || RunExpiredError.is(err)) {
1414
+ runtimeLogger.warn('Workflow already finished, skipping run_failed', {
1415
+ workflowRunId: runId,
1416
+ });
1417
+ wfdiag('exit_failed', { result: 'already_finished' });
1418
+ return;
1419
+ }
1420
+ wfdiag('exit_failed_error', {
1421
+ errorName: err?.name,
1422
+ errorMessage: err?.message,
1423
+ });
1424
+ throw err;
1425
+ }
1426
+ wfdiag('exit_failed', { result: 'run_failed_written' });
1427
+ }
1428
+ }
1429
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVpY2tqcy1lbnRyeXBvaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvcXVpY2tqcy1lbnRyeXBvaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFHSCxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsZUFBZSxFQUNmLDBCQUEwQixHQUMzQixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9ELE9BQU8sRUFFTCxxQkFBcUIsRUFFckIsb0JBQW9CLEdBRXJCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLE9BQU8sSUFBSSxxQkFBcUIsR0FFakMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4QyxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGVBQWUsRUFDZixZQUFZLEdBQ2IsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsZUFBZSxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDekUsT0FBTyxLQUFLLFNBQVMsTUFBTSxzQ0FBc0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RCxPQUFPLEVBQ0wsOEJBQThCLEVBQzlCLGlCQUFpQixHQUNsQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNqRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xFLE9BQU8sRUFPTCxvQkFBb0IsR0FDckIs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S0FBSyxFQUFFLGVBQWU7b0JBQ3RCLFNBQVM7aUJBQ1Y7YUFDRixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLGVBQWUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDM0QsYUFBYSxDQUFDLElBQUksQ0FBQyxnREFBZ0QsRUFBRTtvQkFDbkUsYUFBYSxFQUFFLEtBQUs7aUJBQ3JCLENBQUMsQ0FBQztnQkFDSCxNQUFNLENBQUMsYUFBYSxFQUFFLEVBQUUsTUFBTSxFQUFFLGtCQUFrQixFQUFFLENBQUMsQ0FBQztnQkFDdEQsT0FBTztZQUNULENBQUM7WUFDRCxNQUFNLENBQUMsbUJBQW1CLEVBQUU7Z0JBQzFCLFNBQVMsRUFBRyxHQUFhLEVBQUUsSUFBSTtnQkFDL0IsWUFBWSxFQUFHLEdBQWEsRUFBRSxPQUFPO2FBQ3RDLENBQUMsQ0FBQztZQUNILE1BQU0sR0FBRyxDQUFDO1FBQ1osQ0FBQztRQUNELE1BQU0sQ0FBQyxhQUFhLEVBQUUsRUFBRSxNQUFNLEVBQUUsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO0lBQzFELENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBRdWlja0pTIFZNIGludGVncmF0aW9uIHdpdGggdGhlIFdvcmtmbG93IERldktpdC5cbiAqXG4gKiBUaGlzIG1vZHVsZSBwcm92aWRlcyB0aGUgZW50cnkgcG9pbnQgZm9yIHJ1bm5pbmcgd29ya2Zsb3dzIGluIHRoZVxuICogUXVpY2tKUyBXQVNNIFZNIGVuZ2luZSBpbnN0ZWFkIG9mIHRoZSBgbm9kZTp2bWAgZW5naW5lLiBCb3RoIGVuZ2luZXNcbiAqIGltcGxlbWVudCB0aGUgc2FtZSBldmVudC1yZXBsYXkgZXhlY3V0aW9uIG1vZGVsIOKAlCBldmVyeSBpbnZvY2F0aW9uOlxuICpcbiAqIDEuIExvYWRzIHRoZSBmdWxsIGV2ZW50IGxvZyBmb3IgdGhlIHJ1blxuICogMi4gUnVucyB0aGUgd29ya2Zsb3cgZnVuY3Rpb24gZnJvbSB0aGUgdG9wIGluIGEgZnJlc2ggUXVpY2tKUyBWTSxcbiAqICAgIHJlcGxheWluZyB0aGUgZXZlbnQgbG9nIHRvIHJlc29sdmUgYXdhaXRlZCBwcmltaXRpdmVzXG4gKiAzLiBPbiBzdXNwZW5zaW9uOiBjcmVhdGVzIGV2ZW50cyArIHF1ZXVlcyBzdGVwcyBmb3IgbmV3IHBlbmRpbmcgb3BzXG4gKiA0LiBPbiBjb21wbGV0aW9uOiBjcmVhdGVzIHJ1bl9jb21wbGV0ZWRcbiAqIDUuIE9uIGZhaWx1cmU6IGNyZWF0ZXMgcnVuX2ZhaWxlZFxuICovXG5cbmltcG9ydCB0eXBlIHsgU3BhbiB9IGZyb20gJ0BvcGVudGVsZW1ldHJ5L2FwaSc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBIb29rTm90Rm91bmRFcnJvcixcbiAgTWF4RXZlbnRzRXhjZWVkZWRFcnJvcixcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgeyBwYXJzZVdvcmtmbG93TmFtZSB9IGZyb20gJ0B3b3JrZmxvdy91dGlscy9wYXJzZS1uYW1lJztcbmltcG9ydCB7XG4gIHR5cGUgRXZlbnQsXG4gIFJPT1RfUlVOX0lEX0FUVFJJQlVURSxcbiAgdHlwZSBSdW5JbnB1dCxcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIHR5cGUgV29ya2Zsb3dSdW4sXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBjbGFzc2lmeVJ1bkVycm9yIH0gZnJvbSAnLi4vY2xhc3NpZnktZXJyb3IuanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBkZXJpdmVSdW5QYXlsb2FkS2V5cyxcbiAgZW5jcnlwdCBhcyBlbmNyeXB0U2VyaWFsaXplZERhdGEsXG4gIHR5cGUgUnVuUGF5bG9hZEtleXMsXG59IGZyb20gJy4uL3NlcmlhbGl6YXRpb24vZW5jcnlwdGlvbi5qcyc7XG5pbXBvcnQge1xuICBkZWh5ZHJhdGVSdW5FcnJvcixcbiAgaHlkcmF0ZVJ1bkVycm9yLFxuICBtYXliZUVuY3J5cHQsXG59IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0IHsgcmVtYXBFcnJvclN0YWNrLCBzdHJpcElubGluZVNvdXJjZU1hcCB9IGZyb20gJy4uL3NvdXJjZS1tYXAuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBzZXJpYWxpemVUcmFjZUNhcnJpZXIgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHtcbiAgZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzLFxuICBnZXRNYXhJbmxpbmVTdGVwcyxcbn0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgZ2V0UG9ydExhenkgfSBmcm9tICcuL2dldC1wb3J0LWxhenkuanMnO1xuaW1wb3J0IHsgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUsIHF1ZXVlTWVzc2FnZSB9IGZyb20gJy4vaGVscGVycy5qcyc7XG5pbXBvcnQge1xuICB0eXBlIFBlbmRpbmdBdHRyaWJ1dGUsXG4gIHR5cGUgUGVuZGluZ0hvb2ssXG4gIHR5cGUgUGVuZGluZ0hvb2tEaXNwb3NlLFxuICB0eXBlIFBlbmRpbmdPcGVyYXRpb24sXG4gIHR5cGUgUGVuZGluZ1N0ZXAsXG4gIHR5cGUgUGVuZGluZ1dhaXQsXG4gIHN0YXJ0UXVpY2tKU1dvcmtmbG93LFxufSBmcm9tICcuL3F1aWNranMtcnVudGltZS5qcyc7XG5pbXBvcnQgeyBSZXBsYXlCdWRnZXQgfSBmcm9tICcuL3JlcGxheS1idWRnZXQuanMnO1xuaW1wb3J0IHsgZXhlY3V0ZVN0ZXAsIHR5cGUgU3RlcEV4ZWN1dGlvblJlc3VsdCB9IGZyb20gJy4vc3RlcC1leGVjdXRvci5qcyc7XG5pbXBvcnQgeyBydW5TdGVwU2luZ2xlRmxpZ2h0IH0gZnJvbSAnLi9zdGVwLXNpbmdsZS1mbGlnaHQuanMnO1xuaW1wb3J0IHsgZ2V0V2FpdENvbnRpbnVhdGlvbkRpc3BhdGNoIH0gZnJvbSAnLi93YWl0LWNvbnRpbnVhdGlvbi5qcyc7XG5pbXBvcnQgeyBnZXRXb3JsZCB9IGZyb20gJy4vd29ybGQuanMnO1xuXG4vKiogVGlueSBtcyB0aW1lciB1c2luZyBwZXJmb3JtYW5jZS5ub3coKSDigJQgYWxyZWFkeSBtb25vdG9uaWMgb24gTm9kZS4gKi9cbmZ1bmN0aW9uIHRpY2soKTogbnVtYmVyIHtcbiAgcmV0dXJuIHBlcmZvcm1hbmNlLm5vdygpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSB3aGVuIHRoZSBzdXBwbGllZCBwcmVsb2FkZWQgZXZlbnRzIGluZGljYXRlIHRoaXMgaXMgdGhlXG4gKiBmaXJzdCB3b3JrZmxvdyBoYW5kbGVyIGludm9jYXRpb24gZm9yIHRoZSBydW4g4oCUIGkuZS4gdGhlIGxvZyBjb250YWluc1xuICogbm90aGluZyBiZXlvbmQgYHJ1bl9jcmVhdGVkYCAvIGBydW5fc3RhcnRlZGAuIEluIHRoYXQgY2FzZSB0aGVcbiAqIHByZWxvYWRlZCBldmVudHMgQVJFIHRoZSBjb21wbGV0ZSBldmVudCBsb2cgYW5kIHRoZSBgZXZlbnRzLmxpc3RgXG4gKiByb3VuZC10cmlwcyBjYW4gYmUgc2tpcHBlZCBlbnRpcmVseS5cbiAqXG4gKiBDcnVjaWFsbHksIGlmIHRoZSB3b3JsZCBiYWNrZmlsbGVkIGEgbWlzc2luZyBgcnVuX2NyZWF0ZWRgIHZpYSB0aGVcbiAqIHJlc2lsaWVudCBzdGFydCBwYXRoLCBgcHJlbG9hZGVkRXZlbnRzYCBjb250YWlucyBpdCBldmVuIHdoZW4gYSBmcmVzaFxuICogYGV2ZW50cy5saXN0YCBtaWdodCBub3QgKGV2ZW50dWFsIGNvbnNpc3RlbmN5KSwgc28gcHJlZmVycmluZyB0aGVcbiAqIHByZWxvYWRlZCBldmVudHMgb24gZmlyc3QgaW52b2NhdGlvbiBpcyBhbHNvIHRoZSBtb3JlIGNvcnJlY3QgY2hvaWNlLlxuICpcbiAqIFJldHVybnMgZmFsc2Ugd2hlbiBgcHJlbG9hZGVkRXZlbnRzYCBpcyBtaXNzaW5nL2VtcHR5IHNvIHRoZSBjYWxsZXJcbiAqIGZhbGxzIGJhY2sgdG8gdGhlIG5vcm1hbCBmZXRjaCBwYXRoLlxuICpcbiAqIEV4cG9ydGVkIGZvciB1bml0IHRlc3RpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0ZpcnN0SW52b2NhdGlvbihcbiAgcHJlbG9hZGVkRXZlbnRzOiByZWFkb25seSBFdmVudFtdIHwgdW5kZWZpbmVkXG4pOiBib29sZWFuIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHByZWxvYWRlZEV2ZW50cykgfHwgcHJlbG9hZGVkRXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gcHJlbG9hZGVkRXZlbnRzLmV2ZXJ5KFxuICAgIChlKSA9PiBlLmV2ZW50VHlwZSA9PT0gJ3J1bl9jcmVhdGVkJyB8fCBlLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJ1xuICApO1xufVxuXG4vKipcbiAqIFF1ZXVlIGEgc3RlcCBmb3IgYmFja2dyb3VuZCBleGVjdXRpb24gdmlhIHRoZSB1bmlmaWVkIHdvcmtmbG93IHF1ZXVlXG4gKiAoVjIgYXJjaGl0ZWN0dXJlKS4gVGhlIGNvbWJpbmVkIGhhbmRsZXIgaW4gcnVudGltZS50cyBkaXNwYXRjaGVzXG4gKiBtZXNzYWdlcyB3aXRoIGBzdGVwSWRgIHRvIGV4ZWN1dGVTdGVwLCB3aGljaCB3b3JrcyBmb3IgYm90aCBWTSBlbmdpbmVzLlxuICogYGRlbGF5U2Vjb25kc2Agc3VwcG9ydHMgcmV0cnkvdGhyb3R0bGUgYmFja29mZi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcXVldWVTdGVwTWVzc2FnZShwYXJhbXM6IHtcbiAgd29ybGQ6IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgZ2V0V29ybGQ+PjtcbiAgcnVuSWQ6IHN0cmluZztcbiAgd29ya2Zsb3dSdW46IFdvcmtmbG93UnVuO1xuICBzdGVwOiBQZW5kaW5nU3RlcDtcbiAgZGVsYXlTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogUXVldWUgbmFtZXNwYWNlIGZvciB0aGUgcHVibGlzaCAoc2VlIHJ1bnRpbWUudHMpLiAqL1xuICBuYW1lc3BhY2U6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqIFJ1bi1vcmlnaW4gdHJhY2UgY2FycmllciBhY2Nlc3NvciAoc2VlIHJ1bldvcmtmbG93V2l0aFF1aWNrSlMpLiAqL1xuICBuZXh0VHJhY2VDYXJyaWVyOiAoKSA9PiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+O1xuICAvKipcbiAgICogUHVibGlzaCBwdXJwb3NlLCB1c2VkIHRvIGJ1Y2tldCB0aGUgaWRlbXBvdGVuY3kga2V5LiBXb3JsZHMgcmV0aXJlXG4gICAqIHVzZWQga2V5cyAoVlFTIHJldGVudGlvbiBUVEwsIHdvcmxkLXBvc3RncmVzIGNvbXBsZXRlZC1rZXlzIGNhY2hlKSxcbiAgICogc28gYSBrZXkgc2hhcmVkIGFjcm9zcyBwdXJwb3NlcyBzaWxlbnRseSBzd2FsbG93cyB0aGUgc2Vjb25kXG4gICAqIHB1Ymxpc2gg4oCUIHNlZSB3YWl0LWNvbnRpbnVhdGlvbi50cyBmb3IgdGhlIHNhbWUgaGF6YXJkIG9uIHdhaXRcbiAgICoga2V5cy4gYGRpc3BhdGNoYCBpcyB0aGUgcGxhaW4gYmFja2dyb3VuZCBoYW5kb2ZmIChvdmVyZmxvdyAvIGNyYXNoXG4gICAqIHJlY292ZXJ5KSBhbmQga2VlcHMgdGhlIGJhcmUgY29ycmVsYXRpb25JZCBzbyBpdCBzdGF5cyBtdXR1YWxseVxuICAgKiBleGNsdXNpdmUgd2l0aCB0aGUgbm9kZSBlbmdpbmUncyBkaXNwYXRjaCBvZiB0aGUgc2FtZSBzdGVwO1xuICAgKiBgYmFja3N0b3A6PGVwb2NoPmAgY292ZXJzIGRlbGF5ZWQgY3Jhc2ggYmFja3N0b3BzLCBzY29wZWQgdG8gdGhlXG4gICAqIG93bmVyc2hpcCBlcG9jaCBzbyBhIHJlZnJlc2hlZCBsZWFzZSByZS1hcm1zIGEgTkVXIGJhY2tzdG9wIGluc3RlYWRcbiAgICogb2YgYmVpbmcgYWJzb3JiZWQgYnkgdGhlIGluLWZsaWdodCBvbmU7IGByZXRyeTo8bj5gIGNvdmVycyBkZWxheWVkXG4gICAqIHJldHJ5L3Rocm90dGxlIHJlLWVucXVldWVzLCBzY29wZWQgdG8gdGhlIGF0dGVtcHQgc28gZWFjaCBiYWNrb2ZmXG4gICAqIGhvcCBpcyBlbnF1ZXVlYWJsZS5cbiAgICovXG4gIHB1cnBvc2U6ICdkaXNwYXRjaCcgfCBgYmFja3N0b3A6JHtzdHJpbmd9YCB8IGByZXRyeToke251bWJlcn1gO1xuICB3ZmRpYWc6IChjaGVja3BvaW50OiBzdHJpbmcsIGZpZWxkczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHZvaWQ7XG59KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHtcbiAgICB3b3JsZCxcbiAgICBydW5JZCxcbiAgICB3b3JrZmxvd1J1bixcbiAgICBzdGVwLFxuICAgIGRlbGF5U2Vjb25kcyxcbiAgICBuYW1lc3BhY2UsXG4gICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICBwdXJwb3NlLFxuICAgIHdmZGlhZyxcbiAgfSA9IHBhcmFtcztcbiAgY29uc3QgdHJhY2VDYXJyaWVyID0gYXdhaXQgbmV4dFRyYWNlQ2FycmllcigpO1xuICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgd29ybGQsXG4gICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgIHtcbiAgICAgIHJ1bklkLFxuICAgICAgc3RlcElkOiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICBzdGVwTmFtZTogc3RlcC5zdGVwSWQsXG4gICAgICB0cmFjZUNhcnJpZXIsXG4gICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkZW1wb3RlbmN5S2V5OlxuICAgICAgICBwdXJwb3NlID09PSAnZGlzcGF0Y2gnXG4gICAgICAgICAgPyBzdGVwLmNvcnJlbGF0aW9uSWRcbiAgICAgICAgICA6IGAke3N0ZXAuY29ycmVsYXRpb25JZH06JHtwdXJwb3NlfWAsXG4gICAgICAuLi4oZGVsYXlTZWNvbmRzICYmIGRlbGF5U2Vjb25kcyA+IDAgPyB7IGRlbGF5U2Vjb25kcyB9IDoge30pLFxuICAgIH1cbiAgKTtcbiAgd2ZkaWFnKCdzdGVwX3F1ZXVlZCcsIHtcbiAgICBzdGVwSWQ6IHN0ZXAuc3RlcElkLFxuICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXAuY29ycmVsYXRpb25JZCxcbiAgICBwdXJwb3NlLFxuICAgIGRlbGF5U2Vjb25kczogZGVsYXlTZWNvbmRzID8/IDAsXG4gIH0pO1xufVxuXG4vKipcbiAqIERpc3BhdGNoIGR1cmFibGUgc2lkZSBlZmZlY3RzIGZvciBhIHNldCBvZiBwZW5kaW5nIFZNIG9wZXJhdGlvbnM6XG4gKiBzdGVwX2NyZWF0ZWQgKCsgb3B0aW9uYWwgcXVldWVpbmcpLCBob29rX2NyZWF0ZWQgLyBob29rX3JlY2VpdmVkIChhYm9ydHMpLFxuICogYXR0cl9zZXQsIGhvb2tfZGlzcG9zZWQsIGFuZCB3YWl0X2NyZWF0ZWQgZXZlbnRzLlxuICpcbiAqIFN0ZXBzIGFyZSBjcmVhdGVkIGJ1dCBuZXZlciBxdWV1ZWQgaGVyZSDigJQgcXVldWVpbmcgKG9yIGlubGluZVxuICogZXhlY3V0aW9uKSBpcyB0aGUgY2FsbGVyJ3MgZGVjaXNpb24uIFVzZWQgYm90aCBmb3Igc3VzcGVuc2lvblxuICogcHJvY2Vzc2luZyAodGhlIGlubGluZSBsb29wKSBhbmQgZm9yIHRoZSB0ZXJtaW5hbCBkcmFpbiAoZmx1c2hpbmdcbiAqIGxlZnRvdmVyIHNpZGUgZWZmZWN0cyB3aGVuIHRoZSB3b3JrZmxvdyBjb21wbGV0ZWQgb3IgZmFpbGVkLCBtaXJyb3JpbmdcbiAqIHRoZSBub2RlOnZtIGVuZ2luZSdzIGRyYWluUGVuZGluZ1F1ZXVlSXRlbXMpLlxuICovXG5hc3luYyBmdW5jdGlvbiBkaXNwYXRjaFBlbmRpbmdPcHMocGFyYW1zOiB7XG4gIHdvcmxkOiBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIGdldFdvcmxkPj47XG4gIHJ1bklkOiBzdHJpbmc7XG4gIHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1bjtcbiAgZW5jcnlwdGlvbktleTogUnVuUGF5bG9hZEtleXMgfCB1bmRlZmluZWQ7XG4gIHBlbmRpbmdPcGVyYXRpb25zOiBQZW5kaW5nT3BlcmF0aW9uW107XG4gIC8qKlxuICAgKiBTdGVwIGNpZHMgd2hvc2UgYHN0ZXBfY3JlYXRlZGAgbXVzdCBOT1QgYmUgd3JpdHRlbiBoZXJlOiB0aGUgaW5saW5lXG4gICAqIGxvb3AgY2xhaW1zIHRoZXNlIGF0b21pY2FsbHkgdmlhIGEgbGF6eSBgc3RlcF9zdGFydGVkYCAoY2FycnlpbmcgdGhlXG4gICAqIGlucHV0KSwgc28gYSBjb25jdXJyZW50IGNsYWltYW50IGxvc2VzIHdpdGggRW50aXR5Q29uZmxpY3RFcnJvclxuICAgKiBpbnN0ZWFkIG9mIGJvdGggaW52b2NhdGlvbnMgYmFyZS1zdGFydGluZyB0aGUgc2FtZSBzdGVwLlxuICAgKi9cbiAgc2tpcFN0ZXBDcmVhdGlvbj86IFNldDxzdHJpbmc+O1xuICAvKiogUXVldWUgbmFtZXNwYWNlIGZvciBhbGwgbWVzc2FnZSBwdWJsaXNoZXMgKHNlZSBydW50aW1lLnRzKS4gKi9cbiAgbmFtZXNwYWNlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBSdW4tb3JpZ2luIHRyYWNlIGNhcnJpZXIgYWNjZXNzb3IgZnJvbSBydW50aW1lLnRzLiBJbiB0aGUgZGVmYXVsdFxuICAgKiBgbGlua2VkYCB0cmFjZSBtb2RlIHRoaXMgcmV0dXJucyB0aGUgY2FycmllciBvZiB0aGUgcnVuJ3MgT1JJR0lOXG4gICAqIGNvbnRleHQgKHdvcmtmbG93LnN0YXJ0KSwgc28gZXZlcnkgaW52b2NhdGlvbiBsaW5rcyBiYWNrIHRvIHRoZVxuICAgKiBzdGFydCBpbiBhIHN0YXIg4oCUIGNhcHR1cmluZyB0aGUgY3VycmVudCBjb250ZXh0IGhlcmUgaW5zdGVhZCB3b3VsZFxuICAgKiBjaGFpbiBpbnZvY2F0aW9ucyB0byBlYWNoIG90aGVyIGFuZCBmcmFnbWVudCB0aGUgcnVuIHZpZXcgb24gYXN5bmNcbiAgICogcXVldWVzLlxuICAgKi9cbiAgbmV4dFRyYWNlQ2FycmllcjogKCkgPT4gUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+PjtcbiAgd2ZkaWFnOiAoY2hlY2twb2ludDogc3RyaW5nLCBmaWVsZHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB2b2lkO1xufSk6IFByb21pc2U8e1xuICBjcmVhdGVkQXR0cmlidXRlRXZlbnQ6IGJvb2xlYW47XG4gIGNyZWF0ZWRHZXRDb25mbGljdEhvb2s6IGJvb2xlYW47XG59PiB7XG4gIGNvbnN0IHtcbiAgICB3b3JsZCxcbiAgICBydW5JZCxcbiAgICB3b3JrZmxvd1J1bixcbiAgICBlbmNyeXB0aW9uS2V5LFxuICAgIHBlbmRpbmdPcGVyYXRpb25zLFxuICAgIG5hbWVzcGFjZSxcbiAgICBuZXh0VHJhY2VDYXJyaWVyLFxuICB9ID0gcGFyYW1zO1xuICBjb25zdCBza2lwU3RlcENyZWF0aW9uID0gcGFyYW1zLnNraXBTdGVwQ3JlYXRpb247XG4gIGNvbnN0IHdmZGlhZyA9IHBhcmFtcy53ZmRpYWc7XG4gIC8vIFNldCB3aGVuIGEgaG9vayB3aXRoIGEgcGFya2VkIGdldENvbmZsaWN0KCkgYXdhaXRlciBoYWQgaXRzXG4gIC8vIGhvb2tfY3JlYXRlZCB3cml0dGVuIHRoaXMgaW52b2NhdGlvbi4gVGhlIHdvcmtmbG93IG11c3QgYmUgcmUtaW52b2tlZFxuICAvLyBzbyByZXBsYXkgY2FuIGNvbmZpcm0gY3JlYXRpb24gYW5kIHJlc29sdmUgdGhlIGF3YWl0ZXIuXG4gIGxldCBjcmVhdGVkR2V0Q29uZmxpY3RIb29rID0gZmFsc2U7XG4gIC8vIFNldCB3aGVuIGEgbmV3IGF0dHJfc2V0IGV2ZW50IGlzIHdyaXR0ZW4gdGhpcyBpbnZvY2F0aW9uLiBUaGVcbiAgLy8gd29ya2Zsb3cgbXVzdCBiZSByZS1pbnZva2VkIHRvIGNvbnN1bWUgaXQgKHJlc29sdmluZyB0aGUgcGVuZGluZ1xuICAvLyBzZXRBdHRyaWJ1dGVzKCkgcHJvbWlzZSksIHNvIHRoZSBlbnRyeXBvaW50IHJlcXVldWVzIGltbWVkaWF0ZWx5IOKAlFxuICAvLyBzYW1lIHBhdHRlcm4gYXMgYW4gZWxhcHNlZCB3YWl0LlxuICBsZXQgY3JlYXRlZEF0dHJpYnV0ZUV2ZW50ID0gZmFsc2U7XG4gIGNvbnN0IG9wc1Byb21pc2VzOiBQcm9taXNlPHZvaWQ+W10gPSBbXTtcblxuICBjb25zdCBwcm9jZXNzSG9va09wID0gYXN5bmMgKGhvb2s6IFBlbmRpbmdIb29rKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUXVpY2tKUyBydW50aW1lOiBwcm9jZXNzaW5nIGhvb2sgb3AnLCB7XG4gICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgIGNvcnJlbGF0aW9uSWQ6IGhvb2suY29ycmVsYXRpb25JZCxcbiAgICAgIHRva2VuOiBob29rLnRva2VuLFxuICAgICAgdG9rZW5UeXBlOiB0eXBlb2YgaG9vay50b2tlbixcbiAgICAgIGlzV2ViaG9vazogaG9vay5pc1dlYmhvb2ssXG4gICAgICBpc1N5c3RlbTogaG9vay5pc1N5c3RlbSxcbiAgICAgIGhhc0NyZWF0ZWRFdmVudDogaG9vay5oYXNDcmVhdGVkRXZlbnQsXG4gICAgICBhYm9ydFJlcXVlc3RlZDogaG9vay5hYm9ydFJlcXVlc3RlZCxcbiAgICB9KTtcblxuICAgIGlmICghaG9vay5oYXNDcmVhdGVkRXZlbnQpIHtcbiAgICAgIC8vIGBob29rLm1ldGFkYXRhYCBpcyB0aGUgZm9ybWF0LXByZWZpeGVkIGRldmFsdWUgYnl0ZXNcbiAgICAgIC8vIHByb2R1Y2VkIGJ5IGBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoJ3dvcmtmbG93LXNlcmlhbGl6ZScpXVxuICAgICAgLy8gKG9wdGlvbnMubWV0YWRhdGEpYCBpbnNpZGUgdGhlIFZNLiBFbmNyeXB0IG9uIHRoZSBob3N0XG4gICAgICAvLyBzaWRlIGJlZm9yZSB3cml0aW5nIOKAlCBtYXRjaGVzIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4gICAgICAvLyBgZGVoeWRyYXRlU3RlcEFyZ3VtZW50c2AgZmxvdy5cbiAgICAgIC8vXG4gICAgICAvLyBObyBwcmUtY2hlY2sgdmlhIGhvb2tzLmxpc3Q6IHdpdGggZGV0ZXJtaW5pc3RpYyBjb3JyZWxhdGlvbklkc1xuICAgICAgLy8gKHNhbWUgVk0gc2VlZCBhY3Jvc3MgcmVwbGF5cykgYW5kIHBlci0ocnVuSWQsIGNvcnJlbGF0aW9uSWQpXG4gICAgICAvLyB1bmlxdWVuZXNzIGluIHdvcmxkcywgdGhlIHN0b3JhZ2UgbGF5ZXIgcmVqZWN0cyBkdXBsaWNhdGVzIGFzXG4gICAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yLCB3aGljaCB3ZSBzd2FsbG93IGJlbG93LiBUaGlzIGRyb3BzIG9uZVxuICAgICAgLy8gbmV0d29yayByb3VuZC10cmlwIHBlciBwZW5kaW5nIGhvb2suXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBlbmNyeXB0ZWRNZXRhZGF0YSA9XG4gICAgICAgICAgdHlwZW9mIGhvb2subWV0YWRhdGEgPT09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgOiBhd2FpdCBlbmNyeXB0U2VyaWFsaXplZERhdGEoaG9vay5tZXRhZGF0YSwgZW5jcnlwdGlvbktleSk7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIHtcbiAgICAgICAgICBldmVudFR5cGU6ICdob29rX2NyZWF0ZWQnLFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBob29rLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICB0b2tlbjogaG9vay50b2tlbixcbiAgICAgICAgICAgIHRva2VuUmV0ZW50aW9uVW50aWw6XG4gICAgICAgICAgICAgIGhvb2sudG9rZW5SZXRlbnRpb25VbnRpbCA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICA6IG5ldyBEYXRlKGhvb2sudG9rZW5SZXRlbnRpb25VbnRpbCksXG4gICAgICAgICAgICBtZXRhZGF0YTogZW5jcnlwdGVkTWV0YWRhdGEsXG4gICAgICAgICAgICAvLyBBbHdheXMgaW5jbHVkZSBpc1dlYmhvb2sgZXhwbGljaXRseS4gV29ybGRzIGRlZmF1bHQgaXQgdG9cbiAgICAgICAgICAgIC8vIGB0cnVlYCB3aGVuIGFic2VudCwgd2hpY2ggd291bGQgYnJlYWsgdGhlIHB1YmxpYyB3ZWJob29rXG4gICAgICAgICAgICAvLyBlbmRwb2ludCdzIDQwNCBndWFyZCBmb3IgaG9va3MgY3JlYXRlZCB2aWEgY3JlYXRlSG9vaygpLlxuICAgICAgICAgICAgaXNXZWJob29rOiBob29rLmlzV2ViaG9vayxcbiAgICAgICAgICAgIC8vIFN5c3RlbSBob29rcyAoQWJvcnRDb250cm9sbGVyKSBhcmUgZXhlbXB0IGZyb20gdXNlclxuICAgICAgICAgICAgLy8gdG9rZW4gbmFtZXNwYWNlIGNvbmZsaWN0IGNoZWNrcy5cbiAgICAgICAgICAgIC4uLihob29rLmlzU3lzdGVtID8geyBpc1N5c3RlbTogdHJ1ZSB9IDoge30pLFxuICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJZiBzdG9yYWdlIGRldGVjdGVkIGEgcmVhbCB0b2tlbiBjb25mbGljdCB3aXRoIGFub3RoZXJcbiAgICAgICAgLy8gd29ya2Zsb3cncyBob29rLCByZS1xdWV1ZSBzbyB0aGUgd29ya2Zsb3cgaGFuZGxlciBjYW5cbiAgICAgICAgLy8gcHJvY2VzcyB0aGUgY29uZmxpY3QgZXZlbnQgYW5kIGZhaWwgZ3JhY2VmdWxseS5cbiAgICAgICAgaWYgKHJlc3VsdC5ldmVudD8uZXZlbnRUeXBlID09PSAnaG9va19jb25mbGljdCcpIHtcbiAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93UnVuLndvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgIHRyYWNlQ2FycmllcjogYXdhaXQgbmV4dFRyYWNlQ2FycmllcigpLFxuICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7IGlkZW1wb3RlbmN5S2V5OiBgaG9va19jb25mbGljdF8ke2hvb2suY29ycmVsYXRpb25JZH1gIH1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gQWxyZWFkeSBjcmVhdGVkIGJ5IGEgY29uY3VycmVudCBpbnZvY2F0aW9uIOKAlCBmYWxsIHRocm91Z2hcbiAgICAgICAgLy8gdG8gYWJvcnQgcHJvY2Vzc2luZyBiZWxvdyAoaWYgYW55KSBpbnN0ZWFkIG9mIGJhaWxpbmcuXG4gICAgICAgIGlmICghRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgICBpZiAoaG9vay5oYXNHZXRDb25mbGljdEF3YWl0ZXIpIHtcbiAgICAgICAgY3JlYXRlZEdldENvbmZsaWN0SG9vayA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGhvb2suYWJvcnRSZXF1ZXN0ZWQpIHtcbiAgICAgIC8vIFJlY29yZCB0aGUgYWJvcnQgZHVyYWJseTogYSBob29rX3JlY2VpdmVkIGV2ZW50IGNhcnJ5aW5nXG4gICAgICAvLyB0aGUgVk0tc2VyaWFsaXplZCBgeyBhYm9ydGVkOiB0cnVlLCByZWFzb24gfWAgcGF5bG9hZCxcbiAgICAgIC8vIHBsdXMgYSBiZXN0LWVmZm9ydCBzdHJlYW0gcGFja2V0IGZvciByZWFsLXRpbWUgc3RlcFxuICAgICAgLy8gcHJvcGFnYXRpb24uIE1pcnJvcnMgdGhlIG5vZGU6dm0gZW5naW5lJ3Mgc3VzcGVuc2lvblxuICAgICAgLy8gaGFuZGxlciAoaG9va3NOZWVkaW5nQWJvcnQpLlxuICAgICAgY29uc3QgYWJvcnRQYXlsb2FkID1cbiAgICAgICAgaG9vay5hYm9ydFBheWxvYWQgaW5zdGFuY2VvZiBVaW50OEFycmF5XG4gICAgICAgICAgPyAoKGF3YWl0IGVuY3J5cHRTZXJpYWxpemVkRGF0YShcbiAgICAgICAgICAgICAgaG9vay5hYm9ydFBheWxvYWQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICkpIGFzIFVpbnQ4QXJyYXkpXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgICAgZXZlbnRUeXBlOiAnaG9va19yZWNlaXZlZCcsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGhvb2suY29ycmVsYXRpb25JZCxcbiAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgIHRva2VuOiBob29rLnRva2VuLFxuICAgICAgICAgICAgcGF5bG9hZDogYWJvcnRQYXlsb2FkLFxuICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBpZiAoIUVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgICAgLy8gc3RyZWFtTmFtZSBpcyBkZXJpdmVkIGZyb20gdGhlIGFib3J0IGhvb2sgdG9rZW5cbiAgICAgIC8vIChgYWJydF97aWR9YCDihpIgYHN0cm1fe2lkfV9zeXN0ZW1fYWJvcnRgKS5cbiAgICAgIGlmIChob29rLnRva2VuLnN0YXJ0c1dpdGgoJ2FicnRfJykgJiYgYWJvcnRQYXlsb2FkKSB7XG4gICAgICAgIGNvbnN0IHN0cmVhbU5hbWUgPSBgc3RybV8ke2hvb2sudG9rZW4uc2xpY2UoJ2FicnRfJy5sZW5ndGgpfV9zeXN0ZW1fYWJvcnRgO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHdvcmxkLnN0cmVhbXMud3JpdGUocnVuSWQsIHN0cmVhbU5hbWUsIGFib3J0UGF5bG9hZCk7XG4gICAgICAgICAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShydW5JZCwgc3RyZWFtTmFtZSk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIEJlc3QtZWZmb3J0IOKAlCB0aGUgaG9vayBldmVudCBwcm92aWRlcyB0aGUgZHVyYWJsZVxuICAgICAgICAgIC8vIGZhbGxiYWNrLlxuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAnUXVpY2tKUyBydW50aW1lOiBmYWlsZWQgdG8gd3JpdGUgYWJvcnQgc3RyZWFtIHBhY2tldCcsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBob29rLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgd2ZkaWFnKCdhYm9ydF9yZWNvcmRlZCcsIHtcbiAgICAgICAgY29ycmVsYXRpb25JZDogaG9vay5jb3JyZWxhdGlvbklkLFxuICAgICAgICB0b2tlbjogaG9vay50b2tlbixcbiAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBwcm9jZXNzSG9va0Rpc3Bvc2VPcCA9IGFzeW5jIChcbiAgICBvcDogUGVuZGluZ0hvb2tEaXNwb3NlXG4gICk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfZGlzcG9zZWQnLFxuICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgIGNvcnJlbGF0aW9uSWQ6IG9wLmNvcnJlbGF0aW9uSWQsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHJldHVybjtcbiAgICAgIC8vIERpc3Bvc2luZyBhIGhvb2sgd2hvc2UgZW50aXR5IG5vIGxvbmdlciAob3IgbmV2ZXIpIGV4aXN0cyBpcyBhblxuICAgICAgLy8gaWRlbXBvdGVudCBuby1vcDogdGhlIGVudGl0eSBtYXkgaGF2ZSBiZWVuIHRvcm4gZG93biBieSBhXG4gICAgICAvLyBjb25jdXJyZW50IHJ1biBjYW5jZWxsYXRpb24sIG9yIHRoZSBob29rIG1heSBoYXZlIGxvc3QgaXRzXG4gICAgICAvLyB0b2tlbiBjbGFpbSB0byBhIGNvbmZsaWN0LiBUaGVyZSBpcyBub3RoaW5nIGxlZnQgdG8gcmVsZWFzZS5cbiAgICAgIGlmIChIb29rTm90Rm91bmRFcnJvci5pcyhlcnIpKSByZXR1cm47XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9O1xuXG4gIC8vIEhvb2sgb3BlcmF0aW9ucyBhcmUgZ3JvdXBlZCBieSB0b2tlbiBhbmQgcHJvY2Vzc2VkIFNFUVVFTlRJQUxMWSBpblxuICAvLyBjb2RlIG9yZGVyIHdpdGhpbiBlYWNoIGdyb3VwLCBtaXJyb3JpbmcgdGhlIG5vZGU6dm0gc3VzcGVuc2lvblxuICAvLyBoYW5kbGVyIChob29rSXRlbXNCeVRva2VuKTogYSBkaXNwb3NlKCkgb2YgYW4gZWFybGllciBob29rIG11c3RcbiAgLy8gcmVsZWFzZSB0aGUgdG9rZW4gYmVmb3JlIGEgbGF0ZXIgc2FtZS10b2tlbiBob29rJ3MgY3JlYXRpb24gaXNcbiAgLy8gdmFsaWRhdGVkIGJ5IHRoZSB3b3JsZCDigJQgcGFyYWxsZWwgZGlzcGF0Y2ggd291bGQgb3RoZXJ3aXNlIHJlY29yZCBhXG4gIC8vIHNwdXJpb3VzIGhvb2tfY29uZmxpY3QgYWdhaW5zdCB0aGUgcnVuJ3Mgb3duIGRpc3Bvc2VkIGhvb2sgKGUuZy4gYVxuICAvLyBkaXNwb3Nl4oaScmVjcmVhdGUgbG9vcCByZXVzaW5nIG9uZSB0b2tlbikuIERpZmZlcmVudCB0b2tlbnMgaGF2ZSBub1xuICAvLyBjbGFpbSBpbnRlcmFjdGlvbiwgc28gdG9rZW4gZ3JvdXBzIHJ1biBpbiBwYXJhbGxlbCB3aXRoIGVhY2ggb3RoZXJcbiAgLy8gYW5kIHdpdGggdGhlIG5vbi1ob29rIG9wcyBiZWxvdy5cbiAgY29uc3QgaG9va09wc0J5VG9rZW4gPSBuZXcgTWFwPFxuICAgIHN0cmluZyxcbiAgICAoUGVuZGluZ0hvb2sgfCBQZW5kaW5nSG9va0Rpc3Bvc2UpW11cbiAgPigpO1xuICBmb3IgKGNvbnN0IG9wIG9mIHBlbmRpbmdPcGVyYXRpb25zKSB7XG4gICAgbGV0IGtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmIChcbiAgICAgIG9wLnR5cGUgPT09ICdob29rJyAmJlxuICAgICAgKCFvcC5oYXNDcmVhdGVkRXZlbnQgfHwgKG9wIGFzIFBlbmRpbmdIb29rKS5hYm9ydFJlcXVlc3RlZClcbiAgICApIHtcbiAgICAgIGtleSA9IChvcCBhcyBQZW5kaW5nSG9vaykudG9rZW47XG4gICAgfSBlbHNlIGlmIChvcC50eXBlID09PSAnaG9va19kaXNwb3NlJyAmJiAhb3AuaGFzQ3JlYXRlZEV2ZW50KSB7XG4gICAgICAvLyBQZXItb3AgZmFsbGJhY2sgZ3JvdXAgd2hlbiB0aGUgdG9rZW4gaXMgdW5rbm93biDigJQgbm8gb3JkZXJpbmdcbiAgICAgIC8vIGd1YXJhbnRlZXMsIG1hdGNoaW5nIHRoZSBwcmV2aW91cyBwYXJhbGxlbCBiZWhhdmlvci5cbiAgICAgIGtleSA9IChvcCBhcyBQZW5kaW5nSG9va0Rpc3Bvc2UpLnRva2VuID8/IGBfX2NpZDoke29wLmNvcnJlbGF0aW9uSWR9YDtcbiAgICB9XG4gICAgaWYgKGtleSA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICBjb25zdCBncm91cCA9IGhvb2tPcHNCeVRva2VuLmdldChrZXkpO1xuICAgIGlmIChncm91cCkge1xuICAgICAgZ3JvdXAucHVzaChvcCBhcyBQZW5kaW5nSG9vayB8IFBlbmRpbmdIb29rRGlzcG9zZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGhvb2tPcHNCeVRva2VuLnNldChrZXksIFtvcCBhcyBQZW5kaW5nSG9vayB8IFBlbmRpbmdIb29rRGlzcG9zZV0pO1xuICAgIH1cbiAgfVxuICBmb3IgKGNvbnN0IGdyb3VwIG9mIGhvb2tPcHNCeVRva2VuLnZhbHVlcygpKSB7XG4gICAgb3BzUHJvbWlzZXMucHVzaChcbiAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3Qgb3Agb2YgZ3JvdXApIHtcbiAgICAgICAgICBpZiAob3AudHlwZSA9PT0gJ2hvb2snKSB7XG4gICAgICAgICAgICBhd2FpdCBwcm9jZXNzSG9va09wKG9wKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgcHJvY2Vzc0hvb2tEaXNwb3NlT3Aob3ApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSkoKVxuICAgICk7XG4gIH1cblxuICBmb3IgKGNvbnN0IG9wIG9mIHBlbmRpbmdPcGVyYXRpb25zKSB7XG4gICAgaWYgKFxuICAgICAgb3AudHlwZSA9PT0gJ3N0ZXAnICYmXG4gICAgICAhb3AuaGFzQ3JlYXRlZEV2ZW50ICYmXG4gICAgICAhc2tpcFN0ZXBDcmVhdGlvbj8uaGFzKG9wLmNvcnJlbGF0aW9uSWQpXG4gICAgKSB7XG4gICAgICBjb25zdCBzdGVwID0gb3AgYXMgUGVuZGluZ1N0ZXA7XG4gICAgICBvcHNQcm9taXNlcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIC8vIENyZWF0ZSBzdGVwX2NyZWF0ZWQgZXZlbnQuIGBzdGVwLmlucHV0YCBpcyB0aGVcbiAgICAgICAgICAvLyBmb3JtYXQtcHJlZml4ZWQgZGV2YWx1ZSBieXRlcyAoXCJkZXZsXCIgKyBkZXZhbHVlKSBwcm9kdWNlZFxuICAgICAgICAgIC8vIGJ5IGBnbG9iYWxUaGlzW1N5bWJvbC5mb3IoJ3dvcmtmbG93LXNlcmlhbGl6ZScpXSh7YXJncyxcbiAgICAgICAgICAvLyBjbG9zdXJlVmFycywgdGhpc1ZhbH0pYCBpbnNpZGUgdGhlIFZNLiBUaGUgVk0gaGFzIG5vXG4gICAgICAgICAgLy8gYWNjZXNzIHRvIHRoZSBDcnlwdG9LZXksIHNvIGVuY3J5cHRpb24gaXMgYXBwbGllZCBoZXJlXG4gICAgICAgICAgLy8gb24gdGhlIGhvc3Qgc2lkZSDigJQgbWF0Y2hpbmcgd2hhdFxuICAgICAgICAgIC8vIGBkZWh5ZHJhdGVTdGVwQXJndW1lbnRzYCBkb2VzIGluIHRoZSBub2RlOnZtIGVuZ2luZS5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShydW5JZCwge1xuICAgICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2NyZWF0ZWQnLFxuICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXAuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgIGlucHV0OiBhd2FpdCBlbmNyeXB0U2VyaWFsaXplZERhdGEoc3RlcC5pbnB1dCwgZW5jcnlwdGlvbktleSksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHJldHVybjtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBOT1RFOiBzdGVwIHF1ZXVlaW5nIGlzIHRoZSBjYWxsZXIncyBkZWNpc2lvbiDigJQgdGhlIGlubGluZVxuICAgICAgICAgIC8vIGxvb3AgZXhlY3V0ZXMgZnJlc2ggc3RlcHMgaW4gdGhlIGxpdmUgVk0gYW5kIG9ubHkgcXVldWVzIHRoZVxuICAgICAgICAgIC8vIG92ZXJmbG93IC8gcmV0cnkgLyBiYWNrc3RvcCBjYXNlcyAoc2VlIHF1ZXVlU3RlcE1lc3NhZ2UpLlxuICAgICAgICB9KSgpXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAob3AudHlwZSA9PT0gJ2F0dHJpYnV0ZScgJiYgIW9wLmhhc0NyZWF0ZWRFdmVudCkge1xuICAgICAgY29uc3QgYXR0ciA9IG9wIGFzIFBlbmRpbmdBdHRyaWJ1dGU7XG4gICAgICBvcHNQcm9taXNlcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogJ2F0dHJfc2V0JyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBhdHRyLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIGNoYW5nZXM6IGF0dHIuY2hhbmdlcyxcbiAgICAgICAgICAgICAgICB3cml0ZXI6IHsgdHlwZTogJ3dvcmtmbG93JyB9LFxuICAgICAgICAgICAgICAgIC4uLihhdHRyLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgICA/IHsgYWxsb3dSZXNlcnZlZEF0dHJpYnV0ZXM6IHRydWUgfVxuICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjcmVhdGVkQXR0cmlidXRlRXZlbnQgPSB0cnVlO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAvLyBFdmVudCBhbHJlYWR5IGV4aXN0cyAoY29uY3VycmVudCBpbnZvY2F0aW9uKSDigJQgdGhlXG4gICAgICAgICAgICAgIC8vIHJlcGxheSBzdGlsbCBuZWVkcyB0byBjb25zdW1lIGl0LCBzbyByZXF1ZXVlLlxuICAgICAgICAgICAgICBjcmVhdGVkQXR0cmlidXRlRXZlbnQgPSB0cnVlO1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAob3AudHlwZSA9PT0gJ3dhaXQnICYmICFvcC5oYXNDcmVhdGVkRXZlbnQpIHtcbiAgICAgIGNvbnN0IHdhaXQgPSBvcCBhcyBQZW5kaW5nV2FpdDtcbiAgICAgIG9wc1Byb21pc2VzLnB1c2goXG4gICAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnd2FpdF9jcmVhdGVkJyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiB3YWl0LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIHJlc3VtZUF0OiBuZXcgRGF0ZSh3YWl0LnJlc3VtZUF0KSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkgcmV0dXJuO1xuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBQZXItb3AgZGlzcGF0Y2ggcnVucyBpbiBwYXJhbGxlbC5cbiAgYXdhaXQgUHJvbWlzZS5hbGwob3BzUHJvbWlzZXMpO1xuXG4gIHJldHVybiB7IGNyZWF0ZWRBdHRyaWJ1dGVFdmVudCwgY3JlYXRlZEdldENvbmZsaWN0SG9vayB9O1xufVxuXG4vKipcbiAqIFJ1biBhIHdvcmtmbG93IHVzaW5nIHRoZSBRdWlja0pTIFdBU00gVk0gZW5naW5lLlxuICpcbiAqIFRoaXMgcmVwbGFjZXMgdGhlIGBub2RlOnZtYCByZXBsYXkgcGF0aCAocnVuV29ya2Zsb3cgKyBFdmVudHNDb25zdW1lcilcbiAqIHdpdGggYSBRdWlja0pTIFZNIGludm9jYXRpb24gdGhhdCBwZXJmb3JtcyB0aGUgc2FtZSBmdWxsIGV2ZW50IHJlcGxheS5cbiAqXG4gKiBLTk9XTiBHQVAg4oCUIHByZWNvbmRpdGlvbiBndWFyZDogdW5saWtlIHRoZSBub2RlOnZtIHBhdGgsIG5vIGV2ZW50IHdyaXRlXG4gKiBpbiB0aGlzIGZpbGUgcGFydGljaXBhdGVzIGluIHRoZSBvcHRpbWlzdGljLWNvbmN1cnJlbmN5IHByZWNvbmRpdGlvblxuICogZ3VhcmQgKGB3aXRoUHJlY29uZGl0aW9uUmV0cnlgICsgYHN0YXRlVXBkYXRlZEF0Rm9yQ3JlYXRlYCksIHdoaWNoXG4gKiBwcm90ZWN0cyBhIHdyaXRlciBob2xkaW5nIGEgc3RhbGUgZXZlbnQtbG9nIHNuYXBzaG90IGZyb20gY2xvYmJlcmluZyBhXG4gKiBjb25jdXJyZW50IG9uZS4gVGhlIGVuZ2luZSBjdXJyZW50bHkgcmVsaWVzIG9uIHBlci0ocnVuSWQsXG4gKiBjb3JyZWxhdGlvbklkKSBldmVudCB1bmlxdWVuZXNzIChFbnRpdHlDb25mbGljdEVycm9yIGRlZHVwKSBhbG9uZS4gVGhpc1xuICogaXMgYSBkZWxpYmVyYXRlIHNpbXBsaWZpY2F0aW9uIHdoaWxlIHRoZSBlbmdpbmUgaXMgZXhwZXJpbWVudGFsIOKAlCB3aXJpbmdcbiAqIHRoZSBndWFyZCBpcyB0cmFja2VkIGZvbGxvdy11cCB3b3JrOyBhbnlvbmUgYWRkaW5nIG5ldyB3cml0ZSBwYXRocyBoZXJlXG4gKiBzaG91bGQgbm90IGFzc3VtZSBwYXJpdHkgd2l0aCB0aGUgbm9kZSBlbmdpbmUgb24gdGhpcyBheGlzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuV29ya2Zsb3dXaXRoUXVpY2tKUyhwYXJhbXM6IHtcbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmc7XG4gIHdvcmtmbG93TmFtZTogc3RyaW5nO1xuICB3b3JrZmxvd1J1bjogV29ya2Zsb3dSdW47XG4gIC8qKlxuICAgKiBFdmVudHMgcmV0dXJuZWQgaW5saW5lIGJ5IGBldmVudHMuY3JlYXRlKCdydW5fc3RhcnRlZCcsIC4uLilgIG9yIGJ5XG4gICAqIHRoZSBsYXp5IGhvb2sgZmFzdCBwYXRoJ3MgYGhvb2tfcmVjZWl2ZWRgIHByZWxvYWQuIFdoZW4gdGhleSBpbmRpY2F0ZVxuICAgKiBhIGZpcnN0IGludm9jYXRpb24g4oCUIG9yIHdoZW4gYHByZWxvYWRlZEV2ZW50c0NvbXBsZXRlYCBhdHRlc3RzIHRoZXlcbiAgICogYXJlIHRoZSBjb21wbGV0ZSBsb2cg4oCUIHRoZXkgYXJlIHVzZWQgYXMgdGhlIGV2ZW50IGxvZyBpbnN0ZWFkIG9mXG4gICAqIGZldGNoaW5nIHZpYSBgZXZlbnRzLmxpc3RgLCBtYXRjaGluZyB0aGUgbm9kZTp2bSBlbmdpbmUncyBmYXN0IHBhdGguXG4gICAqL1xuICBwcmVsb2FkZWRFdmVudHM/OiBFdmVudFtdO1xuICAvKipcbiAgICogVHJ1ZSB3aGVuIHRoZSBjYWxsZXIgaGFzIHZhbGlkYXRlZCB0aGF0IGBwcmVsb2FkZWRFdmVudHNgIGlzIHRoZSBydW4nc1xuICAgKiBDT01QTEVURSBldmVudCBsb2cgKGUuZy4gdGhlIGxhenkgaG9vayBmYXN0IHBhdGgncyBoYXNNb3JlLWZhbHNlXG4gICAqIHJlcGxheSBwcmVsb2FkKS4gVGhlIGZpcnN0LWludm9jYXRpb24gaGV1cmlzdGljIGJlbG93IG9ubHkgcmVjb2duaXplc1xuICAgKiBydW5fY3JlYXRlZC9ydW5fc3RhcnRlZC1vbmx5IHByZWxvYWRzLCBzbyB3aXRob3V0IHRoaXMgYXR0ZXN0YXRpb24gYVxuICAgKiBob29rLXJlc3VtZSBwcmVsb2FkIHdvdWxkIGJlIGRpc2NhcmRlZCBhbmQgcmVmZXRjaGVkLlxuICAgKi9cbiAgcHJlbG9hZGVkRXZlbnRzQ29tcGxldGU/OiBib29sZWFuO1xuICAvKipcbiAgICogUnVuIGlucHV0IGNhcnJpZWQgdGhyb3VnaCB0aGUgcXVldWUgbWVzc2FnZSBvbiBmaXJzdCBkZWxpdmVyeS4gVXNlZFxuICAgKiBhcyBhIGxhc3QtcmVzb3J0IGZhbGxiYWNrIGZvciBgcnVuX2NyZWF0ZWQuZXZlbnREYXRhLmlucHV0YCB3aGVuXG4gICAqIHRoZSBldmVudCBsb2cgaXMgaW5jb21wbGV0ZS5cbiAgICovXG4gIHJ1bklucHV0PzogUnVuSW5wdXQ7XG4gIC8qKlxuICAgKiBUaGUgcGFyZW50IE9UZWwgc3BhbiAodGhlIG91dGVyIGBXT1JLRkxPVyB7d29ya2Zsb3dOYW1lfWAgc3BhbiBmcm9tXG4gICAqIGBydW50aW1lLnRzYCkuIFdoZW4gc3VwcGxpZWQsIFZNIGxpZmVjeWNsZSBhdHRyaWJ1dGVzIGFyZSBhdHRhY2hlZFxuICAgKiB0byBpdCBmb3IgZW5kLXRvLWVuZCB2aXNpYmlsaXR5LlxuICAgKi9cbiAgcGFyZW50U3Bhbj86IFNwYW47XG4gIC8qKlxuICAgKiBTZXJ2ZXItc3VwcGxpZWQgcGVyLXJ1biBldmVudCBjZWlsaW5nIGZyb20gdGhlIHJ1bl9zdGFydGVkIHJlc3BvbnNlXG4gICAqICh1bmRlZmluZWQg4oeSIG5vIGVuZm9yY2VtZW50KS4gTWlycm9ycyB0aGUgbm9kZTp2bSBlbmdpbmUncyBndWFyZDpcbiAgICogYSBydW5hd2F5IHJ1biBpcyBmYWlsZWQgb25jZSBpdHMgbG9nIHJlYWNoZXMgdGhlIGNlaWxpbmcuIFRoZSB0aHJvd1xuICAgKiBwcm9wYWdhdGVzIHRvIHRoZSByZXBsYXkgbG9vcCdzIGNhdGNoIGluIHJ1bnRpbWUudHMgKHRoZSBRdWlja0pTXG4gICAqIGRpc3BhdGNoIHJ1bnMgaW5zaWRlIHRoYXQgbG9vcCdzIHRyeSksIHdoaWNoIGNsYXNzaWZpZXMgaXQgYW5kXG4gICAqIHJlY29yZHMgcnVuX2ZhaWxlZCB3aXRoIE1BWF9FVkVOVFNfRVhDRUVERUQuXG4gICAqL1xuICBtYXhFdmVudHNMaW1pdD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFF1ZXVlIGRlbGl2ZXJ5IGF0dGVtcHQgb2YgdGhlIG1lc3NhZ2UgZHJpdmluZyB0aGlzIGludm9jYXRpb24gKGZyb21cbiAgICogdGhlIHF1ZXVlIGhhbmRsZXIncyBtZXRhZGF0YTsgMSA9IGZpcnN0IGRlbGl2ZXJ5KS4gU3VyZmFjZWQgaW5cbiAgICogZGlhZ25vc3RpY3M7IGNyYXNoIHJlY292ZXJ5IGl0c2VsZiBpcyBkcml2ZW4gYnkgdGhlIG93bmVyc2hpcC1sZWFzZVxuICAgKiBkZWNpc2lvbiB0YWJsZSBpbiB0aGUgbG9vcCwgbm90IGJ5IHRoZSBhdHRlbXB0IGNvdW50LlxuICAgKi9cbiAgZGVsaXZlcnlBdHRlbXB0PzogbnVtYmVyO1xuICAvKipcbiAgICogUXVldWUgbWVzc2FnZSBJRCBvZiB0aGUgZGVsaXZlcnkgZHJpdmluZyB0aGlzIGludm9jYXRpb24sIHN0YW1wZWQgYXNcbiAgICogYG93bmVyTWVzc2FnZUlkYCBvbiBpbmxpbmUgbGF6eSBzdGVwIGNsYWltcyBzbyB3YWtlIHJlcGxheXMgZGVmZXIgdG9cbiAgICogdGhlIGluLWZsaWdodCBib2R5IGluc3RlYWQgb2YgcmVxdWV1ZWluZyB0aGUgc3RlcC5cbiAgICovXG4gIG93bmVyTWVzc2FnZUlkPzogc3RyaW5nO1xuICAvKipcbiAgICogUXVldWUgbmFtZXNwYWNlIHJlc29sdmVkIGF0IHJvdXRlIHJlZ2lzdHJhdGlvbiAocnVudGltZS50cykuIE11c3QgYmVcbiAgICogdGhyZWFkZWQgaW50byBldmVyeSBtZXNzYWdlIHB1Ymxpc2g6IHRoZSBidWlsZGVycyBiYWtlIHRoZSBuYW1lc3BhY2VcbiAgICogaW50byBnZW5lcmF0ZWQgcm91dGVzLCBzbyBjb25zdW1lcnMgbGlzdGVuIG9uIGBfXzxucz5fd2tmX3dvcmtmbG93XypgXG4gICAqIOKAlCBhIHB1Ymxpc2ggd2l0aG91dCBpdCBsYW5kcyBvbiBgX193a2Zfd29ya2Zsb3dfKmAgYW5kIGlzIG5ldmVyXG4gICAqIHBpY2tlZCB1cC5cbiAgICovXG4gIG5hbWVzcGFjZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFJ1bi1vcmlnaW4gdHJhY2UgY2FycmllciBhY2Nlc3NvciBmcm9tIHJ1bnRpbWUudHNcbiAgICogKGdldE5leHRUcmFjZUNhcnJpZXIpLiBJbiB0aGUgZGVmYXVsdCBgbGlua2VkYCB0cmFjZSBtb2RlIGV2ZXJ5XG4gICAqIGludm9jYXRpb24gbXVzdCBsaW5rIGJhY2sgdG8gdGhlIHJ1bidzIG9yaWdpbiAod29ya2Zsb3cuc3RhcnQpIGluIGFcbiAgICogc3RhcjsgY2FwdHVyaW5nIHRoZSBjdXJyZW50IGludm9jYXRpb24gY29udGV4dCBpbnN0ZWFkIHdvdWxkIGNoYWluXG4gICAqIGludm9jYXRpb25zIHRvIGVhY2ggb3RoZXIgYW5kIGZyYWdtZW50IHRoZSBydW4gdmlldyBvbiBhc3luYyBxdWV1ZXMuXG4gICAqL1xuICBuZXh0VHJhY2VDYXJyaWVyPzogKCkgPT4gUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+Pjtcbn0pOiBQcm9taXNlPHsgdGltZW91dFNlY29uZHM/OiBudW1iZXIgfSB8IHZvaWQ+IHtcbiAgY29uc3Qge1xuICAgIHdvcmtmbG93Q29kZSxcbiAgICB3b3JrZmxvd05hbWUsXG4gICAgd29ya2Zsb3dSdW4sXG4gICAgcHJlbG9hZGVkRXZlbnRzLFxuICAgIHByZWxvYWRlZEV2ZW50c0NvbXBsZXRlLFxuICAgIHJ1bklucHV0LFxuICAgIHBhcmVudFNwYW4sXG4gICAgbWF4RXZlbnRzTGltaXQsXG4gICAgZGVsaXZlcnlBdHRlbXB0LFxuICAgIG93bmVyTWVzc2FnZUlkLFxuICAgIG5hbWVzcGFjZSxcbiAgfSA9IHBhcmFtcztcbiAgLy8gU3RhbmRhbG9uZS1jYWxsZXIgZmFsbGJhY2sgKHRlc3RzKTogd2l0aG91dCBhIHJ1bnRpbWUudHMgY2FycmllclxuICAvLyBhY2Nlc3NvciwgZmFsbCBiYWNrIHRvIHRoZSBjdXJyZW50IGludm9jYXRpb24gY29udGV4dC5cbiAgY29uc3QgbmV4dFRyYWNlQ2FycmllciA9XG4gICAgcGFyYW1zLm5leHRUcmFjZUNhcnJpZXIgPz8gKCgpID0+IHNlcmlhbGl6ZVRyYWNlQ2FycmllcigpKTtcbiAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZCgpO1xuICBjb25zdCBydW5JZCA9IHdvcmtmbG93UnVuLnJ1bklkO1xuICBjb25zdCBpbnZvY2F0aW9uU3RhcnQgPSB0aWNrKCk7XG5cbiAgLy8gU3RyaXAgdGhlIGlubGluZSBzb3VyY2UgbWFwIGNvbW1lbnQgYmVmb3JlIGV2YWx1YXRpbmcgdGhlIGJ1bmRsZSBpblxuICAvLyB0aGUgUXVpY2tKUyBWTS4gVGhlIG1hcCBpcyBwdXJlbHkgaG9zdC1zaWRlIG1ldGFkYXRhIGZvclxuICAvLyBgcmVtYXBFcnJvclN0YWNrYCAoY2FsbGVkIGJlbG93IG9uIHdvcmtmbG93IGZhaWx1cmVzLCBhZ2FpbnN0IHRoZVxuICAvLyBPUklHSU5BTCBgd29ya2Zsb3dDb2RlYCkuIFF1aWNrSlMgcmV0YWlucyBzb3VyY2UgdGV4dCBmb3JcbiAgLy8gc3RhY2stdHJhY2UgbGluZSBsb29rdXBzLCBzbyB0aGUgZmV3LU1CIGJhc2U2NCBjb21tZW50IHdvdWxkIGJsb2F0XG4gIC8vIHRoZSBWTSBoZWFwIGZvciBubyBiZW5lZml0LlxuICBjb25zdCB3b3JrZmxvd0NvZGVGb3JWTSA9IHN0cmlwSW5saW5lU291cmNlTWFwKHdvcmtmbG93Q29kZSk7XG5cbiAgLy8gUGVyLWludm9jYXRpb24gZGlhZ25vc3RpYyBpZCBzbyBkZWJ1ZyBsb2dzIGNhbiBiZSBjb3JyZWxhdGVkIGV2ZW4gaWZcbiAgLy8gdGhlIHNhbWUgcnVuSWQgaXMgcHJvY2Vzc2VkIGJ5IG92ZXJsYXBwaW5nIGludm9jYXRpb25zIG9uIGRpZmZlcmVudFxuICAvLyBmdW5jdGlvbiBpbnN0YW5jZXMuXG4gIGNvbnN0IGludm9jYXRpb25JZCA9IGBpbnZfJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zbGljZSgyLCAxMCl9YDtcblxuICAvLyBTdHJ1Y3R1cmVkIHBlci1jaGVja3BvaW50IGRpYWdub3N0aWMgaGVscGVyLCBncmVwLWZyaWVuZGx5IGJ5IHJ1bklkLlxuICBjb25zdCB3ZmRpYWcgPSAoY2hlY2twb2ludDogc3RyaW5nLCBmaWVsZHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB7XG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnUVVJQ0tKU19WTV9ESUFHJywge1xuICAgICAgY2hlY2twb2ludCxcbiAgICAgIHJ1bklkLFxuICAgICAgaW52b2NhdGlvbklkLFxuICAgICAgdEVsYXBzZWRNczogTWF0aC5yb3VuZCh0aWNrKCkgLSBpbnZvY2F0aW9uU3RhcnQpLFxuICAgICAgLi4uZmllbGRzLFxuICAgIH0pO1xuICB9O1xuXG4gIHBhcmVudFNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1ZtKCdxdWlja2pzJyksXG4gIH0pO1xuXG4gIHdmZGlhZygnZW50ZXInLCB7XG4gICAgd29ya2Zsb3dOYW1lLFxuICAgIGRlbGl2ZXJ5QXR0ZW1wdCxcbiAgICBoYXNQcmVsb2FkZWRFdmVudHM6XG4gICAgICBBcnJheS5pc0FycmF5KHByZWxvYWRlZEV2ZW50cykgJiYgcHJlbG9hZGVkRXZlbnRzLmxlbmd0aCA+IDAsXG4gICAgcHJlbG9hZGVkRXZlbnRDb3VudDogcHJlbG9hZGVkRXZlbnRzPy5sZW5ndGggPz8gMCxcbiAgICBoYXNSdW5JbnB1dDogISFydW5JbnB1dCxcbiAgfSk7XG5cbiAgLy8gVGhlIHdvcmtmbG93TmFtZSBmcm9tIHRoZSBxdWV1ZSB0b3BpYyBpcyBhbHJlYWR5IHRoZSBmdWxsIHdvcmtmbG93IElEXG4gIC8vIChlLmcuIFwid29ya2Zsb3cvLy4vd29ya2Zsb3dzLzFfc2ltcGxlLy9zaW1wbGVcIilcbiAgY29uc3Qgd29ya2Zsb3dJZCA9IHdvcmtmbG93TmFtZTtcblxuICAvLyBSZXNvbHZlIHRoZSBlbmNyeXB0aW9uIGtleSB1cCBmcm9udCDigJQgbmVlZGVkIHRvIGRlY3J5cHQgZXZlbnRcbiAgLy8gcGF5bG9hZHMgaW5zaWRlIHRoZSBWTSBhbmQgdG8gZW5jcnlwdCBldmVudCBwYXlsb2FkcyB3cml0dGVuIGJlbG93LlxuICAvLyBSZXNvbHZlIHRoZSBGVUxMIGNhcGFiaWxpdHkgKHN5bW1ldHJpYyBBRVMga2V5ICsgWDI1NTE5IGtleXBhaXIpLCBub3RcbiAgLy8ganVzdCBgaW1wb3J0S2V5KHJhd0tleSlgOiBhIHJ1biByZWFkaW5nIGl0cyBvd24gZXZlbnQgbG9nIGNhbiBlbmNvdW50ZXJcbiAgLy8gc2VhbGVkIChgZW5jcGApIGhvb2sgcGF5bG9hZHMgdGhhdCBhIGNyb3NzLWRlcGxveW1lbnQgYHJlc3VtZUhvb2soKWBcbiAgLy8gd3JvdGUgdG8gaXQgKHNlYWxpbmcgaXMgcHJlc2VuY2UtZ2F0ZWQgb24gdGhlIHJ1bidzIHB1Ymxpc2hlZFxuICAvLyBlbmNyeXB0aW9uUHVibGljS2V5LCB3aGljaCB0aGUgc2hhcmVkIHN0YXJ0KCkgcGF0aCBzdGFtcHMgcmVnYXJkbGVzcyBvZlxuICAvLyBlbmdpbmUpLiBBIGJhcmUgc3ltbWV0cmljIGtleSBjYW5ub3Qgb3BlbiB0aG9zZSBhbmQgd291bGQgd2VkZ2UgdGhlIHJ1blxuICAvLyByaWdodCBhZnRlciBob29rX3JlY2VpdmVkIOKAlCB0aGUgbm9kZTp2bSBlbmdpbmUgcmVzb2x2ZXMgdGhlIHNhbWUgZnVsbFxuICAvLyBjYXBhYmlsaXR5IHZpYSBtZW1vaXplRW5jcnlwdGlvbktleS5cbiAgY29uc3QgcmF3S2V5ID0gYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHdvcmtmbG93UnVuKTtcbiAgY29uc3QgZW5jcnlwdGlvbktleSA9IHJhd0tleSA/IGF3YWl0IGRlcml2ZVJ1blBheWxvYWRLZXlzKHJhd0tleSkgOiB1bmRlZmluZWQ7XG5cbiAgLy8gTG9hZCB0aGUgRlVMTCBldmVudCBsb2cgZm9yIHRoZSBydW4uIE9uIGZpcnN0IGludm9jYXRpb24gdGhlXG4gIC8vIHByZWxvYWRlZCBldmVudHMgZnJvbSB0aGUgcnVuX3N0YXJ0ZWQgcmVzcG9uc2UgYXJlIHRoZSBjb21wbGV0ZSBsb2dcbiAgLy8gYW5kIHNhdmUgdGhlIGV2ZW50cy5saXN0IHJvdW5kLXRyaXBzOyBhIGNhbGxlci1hdHRlc3RlZCBjb21wbGV0ZVxuICAvLyBwcmVsb2FkIChsYXp5IGhvb2sgZmFzdCBwYXRoKSBpcyB0cnVzdGVkIHRoZSBzYW1lIHdheS5cbiAgbGV0IGV2ZW50czogRXZlbnRbXTtcbiAgbGV0IGV2ZW50c0ZldGNoZWRQYWdlcyA9IDA7XG4gIGNvbnN0IHVzZVByZWxvYWRlZCA9XG4gICAgKHByZWxvYWRlZEV2ZW50c0NvbXBsZXRlID09PSB0cnVlICYmXG4gICAgICBBcnJheS5pc0FycmF5KHByZWxvYWRlZEV2ZW50cykgJiZcbiAgICAgIHByZWxvYWRlZEV2ZW50cy5sZW5ndGggPiAwKSB8fFxuICAgIGlzRmlyc3RJbnZvY2F0aW9uKHByZWxvYWRlZEV2ZW50cyk7XG4gIGlmICh1c2VQcmVsb2FkZWQgJiYgcHJlbG9hZGVkRXZlbnRzKSB7XG4gICAgZXZlbnRzID0gcHJlbG9hZGVkRXZlbnRzO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IGFsbEV2ZW50czogRXZlbnRbXSA9IFtdO1xuICAgIGxldCBjdXJzb3I6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgIGxldCBoYXNNb3JlID0gdHJ1ZTtcblxuICAgIHdoaWxlIChoYXNNb3JlKSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHdvcmxkLmV2ZW50cy5saXN0KHtcbiAgICAgICAgcnVuSWQsXG4gICAgICAgIHBhZ2luYXRpb246IHtcbiAgICAgICAgICBzb3J0T3JkZXI6ICdhc2MnLFxuICAgICAgICAgIGN1cnNvcjogY3Vyc29yID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICBsaW1pdDogMTAwMCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgZXZlbnRzRmV0Y2hlZFBhZ2VzKys7XG4gICAgICBhbGxFdmVudHMucHVzaCguLi5yZXNwb25zZS5kYXRhKTtcbiAgICAgIC8vIFVwZGF0ZSB0aGUgY3Vyc29yIHRvIHRoZSBsYXN0IHN1Y2Nlc3NmdWxseSBmZXRjaGVkIHBhZ2UncyBjdXJzb3IuXG4gICAgICAvLyBPbmx5IHVwZGF0ZSB3aGVuIHdlIGdvdCByZXN1bHRzIOKAlCB0aGUgZmluYWwgZW1wdHktcGFnZSByZXNwb25zZVxuICAgICAgLy8gcmV0dXJucyBjdXJzb3I9bnVsbCB3aGljaCB3ZSBtdXN0IE5PVCB1c2UgKGl0IHdvdWxkIHJlc2V0IHRoZSBjdXJzb3IpLlxuICAgICAgaWYgKHJlc3BvbnNlLmN1cnNvcikge1xuICAgICAgICBjdXJzb3IgPSByZXNwb25zZS5jdXJzb3I7XG4gICAgICB9XG4gICAgICBoYXNNb3JlID0gcmVzcG9uc2UuZGF0YS5sZW5ndGggPiAwICYmIHJlc3BvbnNlLmN1cnNvciAhPSBudWxsO1xuICAgIH1cblxuICAgIGV2ZW50cyA9IGFsbEV2ZW50cztcbiAgfVxuXG4gIC8vIEV2ZW50LWxpbWl0IGd1YXJkOiBmYWlsIGEgcnVuYXdheSBydW4gb25jZSBpdHMgbG9nIHJlYWNoZXMgdGhlXG4gIC8vIHNlcnZlci1zdXBwbGllZCBjZWlsaW5nIOKAlCBzYW1lIGVuZm9yY2VtZW50IHBvaW50IGFzIHRoZSBub2RlOnZtXG4gIC8vIGVuZ2luZSdzIHJlcGxheSBsb29wLlxuICBpZiAobWF4RXZlbnRzTGltaXQgIT09IHVuZGVmaW5lZCAmJiBldmVudHMubGVuZ3RoID49IG1heEV2ZW50c0xpbWl0KSB7XG4gICAgdGhyb3cgbmV3IE1heEV2ZW50c0V4Y2VlZGVkRXJyb3IoZXZlbnRzLmxlbmd0aCwgbWF4RXZlbnRzTGltaXQpO1xuICB9XG5cbiAgcGFyZW50U3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgLi4uQXR0cmlidXRlLlF1aWNrSlNFdmVudHNQcmVsb2FkZWQodXNlUHJlbG9hZGVkKSxcbiAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU0V2ZW50c0ZldGNoZWRDb3VudChldmVudHMubGVuZ3RoKSxcbiAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU0V2ZW50c0ZldGNoZWRQYWdlcyhldmVudHNGZXRjaGVkUGFnZXMpLFxuICB9KTtcblxuICB3ZmRpYWcoJ2V2ZW50c19mZXRjaGVkJywge1xuICAgIGV2ZW50Q291bnQ6IGV2ZW50cy5sZW5ndGgsXG4gICAgZXZlbnRzRmV0Y2hlZFBhZ2VzLFxuICAgIHVzZVByZWxvYWRlZCxcbiAgICBldmVudFR5cGVzOiBldmVudHMucmVkdWNlPFJlY29yZDxzdHJpbmcsIG51bWJlcj4+KChhY2MsIGUpID0+IHtcbiAgICAgIGFjY1tlLmV2ZW50VHlwZV0gPSAoYWNjW2UuZXZlbnRUeXBlXSA/PyAwKSArIDE7XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHt9KSxcbiAgfSk7XG5cbiAgLy8gQ2hlY2sgZm9yIGVsYXBzZWQgd2FpdHNcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgY29tcGxldGVkV2FpdElkcyA9IG5ldyBTZXQoXG4gICAgZXZlbnRzXG4gICAgICAuZmlsdGVyKChlKSA9PiBlLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY29tcGxldGVkJylcbiAgICAgIC5tYXAoKGUpID0+IGUuY29ycmVsYXRpb25JZClcbiAgKTtcbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICBpZiAoXG4gICAgICBldmVudC5ldmVudFR5cGUgPT09ICd3YWl0X2NyZWF0ZWQnICYmXG4gICAgICBldmVudC5jb3JyZWxhdGlvbklkICYmXG4gICAgICAhY29tcGxldGVkV2FpdElkcy5oYXMoZXZlbnQuY29ycmVsYXRpb25JZClcbiAgICApIHtcbiAgICAgIGNvbnN0IGV2ZW50RGF0YSA9XG4gICAgICAgICdldmVudERhdGEnIGluIGV2ZW50XG4gICAgICAgICAgPyAoZXZlbnQuZXZlbnREYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3QgcmVzdW1lQXQgPSBldmVudERhdGE/LnJlc3VtZUF0O1xuICAgICAgaWYgKHJlc3VtZUF0ICYmIG5vdyA+PSBuZXcgRGF0ZShyZXN1bWVBdCBhcyBzdHJpbmcpLmdldFRpbWUoKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogJ3dhaXRfY29tcGxldGVkJyxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGV2ZW50LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHJlc3VsdC5ldmVudCkgZXZlbnRzLnB1c2gocmVzdWx0LmV2ZW50KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkgY29udGludWU7XG4gICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmVzb2x2ZSB0aGUgd29ya2Zsb3cgc2VydmVyIHBvcnQgc28gYGdldFdvcmtmbG93TWV0YWRhdGEoKS51cmxgIGluc2lkZVxuICAvLyB0aGUgVk0gbWF0Y2hlcyB3aGF0IHRoZSBzdGVwLXNpZGUgaGFuZGxlciByZXBvcnRzLiBTa2lwcGVkIG9uIFZlcmNlbCDigJRcbiAgLy8gdGhlIFZNIHJlYWRzIFZFUkNFTF9VUkwgZGlyZWN0bHkgaW4gdGhhdCBlbnZpcm9ubWVudC5cbiAgY29uc3QgaXNWZXJjZWwgPSBwcm9jZXNzLmVudi5WRVJDRUxfVVJMICE9PSB1bmRlZmluZWQ7XG4gIGNvbnN0IHBvcnQgPSBpc1ZlcmNlbCA/IHVuZGVmaW5lZCA6IGF3YWl0IGdldFBvcnRMYXp5KCk7XG5cbiAgLy8gUnVuIHRoZSB3b3JrZmxvdyBpbiB0aGUgUXVpY2tKUyBWTVxuICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRdWlja0pTIHJ1bnRpbWU6IGludm9raW5nIFZNJywge1xuICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgIHdvcmtmbG93SWQsXG4gICAgZXZlbnRDb3VudDogZXZlbnRzLmxlbmd0aCxcbiAgfSk7XG5cbiAgY29uc3Qgc2Vzc2lvbiA9IGF3YWl0IHN0YXJ0UXVpY2tKU1dvcmtmbG93KHtcbiAgICAvLyBQYXNzIHRoZSBTVFJJUFBFRCBidW5kbGUgdG8gdGhlIFZNIHNvIHRoZSBpbmxpbmUgc291cmNlIG1hcFxuICAgIC8vIGRvZXNuJ3QgZW5kIHVwIGluIHRoZSBRdWlja0pTIGhlYXAuIFRoZSBvcmlnaW5hbCAodW5zdHJpcHBlZClcbiAgICAvLyBgd29ya2Zsb3dDb2RlYCBpcyBzdGlsbCBrZXB0IGluIHRoaXMgaG9zdC1zaWRlIHNjb3BlIGFuZCBpcyB1c2VkXG4gICAgLy8gYnkgYHJlbWFwRXJyb3JTdGFja2Agb24gd29ya2Zsb3cgZmFpbHVyZXMgYmVsb3cuXG4gICAgd29ya2Zsb3dDb2RlOiB3b3JrZmxvd0NvZGVGb3JWTSxcbiAgICB3b3JrZmxvd0lkLFxuICAgIHdvcmtmbG93UnVuLFxuICAgIGV2ZW50cyxcbiAgICB3b3JsZENhcGFiaWxpdGllczogd29ybGQuY2FwYWJpbGl0aWVzLFxuICAgIGVuY3J5cHRpb25LZXksXG4gICAgcG9ydCxcbiAgICBydW5JbnB1dCxcbiAgfSk7XG4gIGxldCByZXN1bHQgPSBzZXNzaW9uLnJlc3VsdDtcblxuICBydW50aW1lTG9nZ2VyLmRlYnVnKCdRdWlja0pTIHJ1bnRpbWU6IFZNIHJldHVybmVkJywge1xuICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgIGNvbXBsZXRlZDogISFyZXN1bHQuY29tcGxldGVkLFxuICAgIHN1c3BlbmRlZDogISFyZXN1bHQuc3VzcGVuZGVkLFxuICAgIGZhaWxlZDogISFyZXN1bHQuZmFpbGVkLFxuICAgIHBlbmRpbmdPcHNDb3VudDogcmVzdWx0LnN1c3BlbmRlZD8ucGVuZGluZ09wZXJhdGlvbnM/Lmxlbmd0aCxcbiAgfSk7XG5cbiAgd2ZkaWFnKCd2bV9yZXR1cm5lZCcsIHtcbiAgICBvdXRjb21lOiByZXN1bHQuY29tcGxldGVkXG4gICAgICA/ICdjb21wbGV0ZWQnXG4gICAgICA6IHJlc3VsdC5zdXNwZW5kZWRcbiAgICAgICAgPyAnc3VzcGVuZGVkJ1xuICAgICAgICA6IHJlc3VsdC5mYWlsZWRcbiAgICAgICAgICA/ICdmYWlsZWQnXG4gICAgICAgICAgOiAndW5rbm93bicsXG4gICAgcGVuZGluZ09wc0NvdW50OiByZXN1bHQuc3VzcGVuZGVkPy5wZW5kaW5nT3BlcmF0aW9ucz8ubGVuZ3RoID8/IDAsXG4gICAgcGVuZGluZ09wU3VtbWFyeTogcmVzdWx0LnN1c3BlbmRlZD8ucGVuZGluZ09wZXJhdGlvbnM/Lm1hcCgocCkgPT4gKHtcbiAgICAgIHR5cGU6IHAudHlwZSxcbiAgICAgIGNvcnJlbGF0aW9uSWQ6IHAuY29ycmVsYXRpb25JZCxcbiAgICAgIGhhc0NyZWF0ZWRFdmVudDogcC5oYXNDcmVhdGVkRXZlbnQsXG4gICAgICAuLi4ocC50eXBlID09PSAnc3RlcCcgPyB7IHN0ZXBJZDogKHAgYXMgUGVuZGluZ1N0ZXApLnN0ZXBJZCB9IDoge30pLFxuICAgIH0pKSxcbiAgICBmYWlsdXJlTWVzc2FnZTogcmVzdWx0LmZhaWxlZD8ubWVzc2FnZSxcbiAgICBmYWlsdXJlTmFtZTogcmVzdWx0LmZhaWxlZD8ubmFtZSxcbiAgfSk7XG5cbiAgLy8gLS0tLSBJbmxpbmUgY29udGludWF0aW9uIGxvb3AgLS0tLVxuICAvL1xuICAvLyBXaGlsZSB0aGUgd29ya2Zsb3cgaXMgc3VzcGVuZGVkLCB0aGlzIGxvb3Aga2VlcHMgdGhlIFZNIGFsaXZlIGFuZFxuICAvLyBtYWtlcyBhcyBtdWNoIGZvcndhcmQgcHJvZ3Jlc3MgYXMgcG9zc2libGUgd2l0aGluIG9uZSBpbnZvY2F0aW9uOlxuICAvL1xuICAvLyAgIDEuIERpc3BhdGNoIGR1cmFibGUgc2lkZSBlZmZlY3RzIGZvciB0aGUgc3VzcGVuc2lvbidzIHBlbmRpbmcgb3BzXG4gIC8vICAgICAgKHN0ZXBfY3JlYXRlZCAvIGhvb2tfY3JlYXRlZCAvIGF0dHJfc2V0IC8gd2FpdF9jcmVhdGVkIC9cbiAgLy8gICAgICBob29rX3JlY2VpdmVkIGZvciBhYm9ydHMpIGFuZCBjb21wbGV0ZSBlbGFwc2VkIHdhaXRzLlxuICAvLyAgIDIuIEZlZWQgYWxsIG5ld2x5IHJlY29yZGVkIGV2ZW50cyAoYXR0cl9zZXQsIGhvb2tfY3JlYXRlZCwgZWxhcHNlZFxuICAvLyAgICAgIHdhaXRfY29tcGxldGVkLCB0ZXJtaW5hbHMgd3JpdHRlbiBieSBjb25jdXJyZW50IGludm9jYXRpb25zLCAuLi4pXG4gIC8vICAgICAgaW50byB0aGUgTElWRSBWTSB2aWEgc2Vzc2lvbi5jb250aW51ZVdpdGhFdmVudHMg4oCUIHJlc3VtaW5nXG4gIC8vICAgICAgZXhlY3V0aW9uIGV4YWN0bHkgd2hlcmUgaXQgbGVmdCBvZmYsIG5vIGZyZXNoLVZNIHJlLXJlcGxheS5cbiAgLy8gICAgICBDaGVhcCBwcm9ncmVzcyBpcyBmZWQgQkVGT1JFIHJ1bm5pbmcgc3RlcCBib2RpZXMgc28gcHJvbWlzZVxuICAvLyAgICAgIGNoYWlucyB0aGF0IGFyZSBub3QgZ2F0ZWQgb24gc3RlcHMgKGhvb2suZ2V0Q29uZmxpY3QoKSxcbiAgLy8gICAgICBzZXRBdHRyaWJ1dGVzKCksIHJhY2luZyBzbGVlcHMpIGFkdmFuY2UgZmlyc3QgYW5kIGNhbiBzdXJmYWNlXG4gIC8vICAgICAgYWRkaXRpb25hbCBwZW5kaW5nIHN0ZXBzIGZvciB0aGUgc2FtZSBpbmxpbmUgYmF0Y2guXG4gIC8vICAgMy4gT25jZSBubyBjaGVhcCBwcm9ncmVzcyByZW1haW5zLCBleGVjdXRlIHVwIHRvXG4gIC8vICAgICAgZ2V0TWF4SW5saW5lU3RlcHMoKSBzdGVwcyBjcmVhdGVkIGJ5IFRISVMgaW52b2NhdGlvbiBpbmxpbmUgKG5vXG4gIC8vICAgICAgcXVldWUgcm91bmQtdHJpcCksIGluIHBhcmFsbGVsLCB3aXRoIHRoZSByZXBsYXkgYnVkZ2V0IHBhdXNlZFxuICAvLyAgICAgIGR1cmluZyBzdGVwIGJvZGllcyDigJQgbWlycm9yaW5nIHRoZSBub2RlOnZtIGVuZ2luZSdzIGlubGluZVxuICAvLyAgICAgIHJlcGxheSBsb29wLiBPdmVyZmxvdyBhbmQgcmV0cnkvdGhyb3R0bGVkIHN0ZXBzIGFyZSBxdWV1ZWQgZm9yXG4gIC8vICAgICAgYmFja2dyb3VuZCBleGVjdXRpb24uIEEgZGVsYXllZCB3YWl0LWNvbnRpbnVhdGlvbiBtZXNzYWdlIGlzXG4gIC8vICAgICAgZW5xdWV1ZWQgZm9yIHRoZSBzb29uZXN0IHBlbmRpbmcgd2FpdCBmaXJzdCwgc28gcmFjaW5nIHRpbWVyc1xuICAvLyAgICAgIGZpcmUgb24gdGltZSAoaW4gYSBzZXBhcmF0ZSBpbnZvY2F0aW9uKSB3aGlsZSBzdGVwIGJvZGllcyBibG9ja1xuICAvLyAgICAgIHRoaXMgb25lLlxuICAvL1xuICAvLyBUaGUgbG9vcCBleGl0cyB3aGVuIHRoZSB3b3JrZmxvdyBzZXR0bGVzLCBubyBmb3J3YXJkIHByb2dyZXNzIGlzXG4gIC8vIHBvc3NpYmxlIGluLXByb2Nlc3MsIHRoZSByZXBsYXkgYnVkZ2V0IGlzIGV4aGF1c3RlZCwgb3IgdGhlIHJ1biBpc1xuICAvLyBnb25lLlxuICBjb25zdCBzZWVuRXZlbnRJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgZm9yIChjb25zdCBlIG9mIGV2ZW50cykge1xuICAgIGlmIChlLmV2ZW50SWQpIHNlZW5FdmVudElkcy5hZGQoZS5ldmVudElkKTtcbiAgfVxuICAvLyBTdGVwIGNpZHMgYWxyZWFkeSBleGVjdXRlZCBpbmxpbmUgYnkgdGhpcyBpbnZvY2F0aW9uLlxuICBjb25zdCBleGVjdXRlZFN0ZXBJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgLy8gU3RlcHMgZm9yIHdoaWNoIFRISVMgaW52b2NhdGlvbiBhbHJlYWR5IHNlbnQgYSBxdWV1ZSBtZXNzYWdlLlxuICBjb25zdCBxdWV1ZWRTdGVwSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIC8vIEFib3J0cyBUSElTIGludm9jYXRpb24gYWxyZWFkeSByZWNvcmRlZCAoaG9va19yZWNlaXZlZCB3cml0dGVuKSDigJRcbiAgLy8gZ3VhcmRzIGFnYWluc3QgcmUtcmVjb3JkaW5nIHdoZW4gdGhlIFZNLXNpZGUgZmxhZyBoYXMgbm90IGJlZW5cbiAgLy8gY2xlYXJlZCB5ZXQgd2l0aGluIHRoZSBzYW1lIGl0ZXJhdGlvbi5cbiAgY29uc3QgcmVjb3JkZWRBYm9ydElkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAvLyBXYWl0cyBmb3Igd2hpY2ggVEhJUyBpbnZvY2F0aW9uIGFscmVhZHkgY29tcGxldGVkL3NjaGVkdWxlZCB3b3JrLlxuICBjb25zdCBjb21wbGV0ZWRXYWl0SWRzMiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAvLyBJbmxpbmUtb3duZXJzaGlwIHN0YXRlIHBlciBzdGVwIGNvcnJlbGF0aW9uSWQsIGRlcml2ZWQgZnJvbSBldmVyeVxuICAvLyBldmVudCB0aGlzIGludm9jYXRpb24gb2JzZXJ2ZXMgKGluaXRpYWwgbG9nICsgZXZlcnkgZmVlZCkg4oCUIHRoZVxuICAvLyBxdWlja2pzIGFuYWxvZyBvZiB0aGUgcmVwbGF5LWRlcml2ZWQgb3duZXJzaGlwIG9uIHRoZSBub2RlIGVuZ2luZSdzXG4gIC8vIFN0ZXBJbnZvY2F0aW9uUXVldWVJdGVtIChzZWUgc3RlcC1vd25lcnNoaXAudHMpLiBMYXRlc3Qtd2luczpcbiAgLy8gZXZlbnRzIGFycml2ZSBpbiBsb2cgb3JkZXIsIHNvIGEgbGF0ZXIgc3RlcF9zdGFydGVkIG92ZXJ3cml0ZXMgdGhlXG4gIC8vIHN0YW1wOyBhIHN0ZXBfcmV0cnlpbmcgbGFwc2VzIG93bmVyc2hpcCBwZXJtYW5lbnRseSBmb3IgdGhlIGlkLlxuICBjb25zdCBzdGVwT3duZXJzaGlwID0gbmV3IE1hcDxcbiAgICBzdHJpbmcsXG4gICAgeyBvd25lcj86IHN0cmluZzsgc3RhcnRlZEF0TXM/OiBudW1iZXI7IHNhd1JldHJ5aW5nOiBib29sZWFuIH1cbiAgPigpO1xuICBjb25zdCBvYnNlcnZlRXZlbnRzRm9yT3duZXJzaGlwID0gKG9ic2VydmVkOiBFdmVudFtdKTogdm9pZCA9PiB7XG4gICAgZm9yIChjb25zdCBlIG9mIG9ic2VydmVkKSB7XG4gICAgICBpZiAoZS5jb3JyZWxhdGlvbklkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgaWYgKGUuZXZlbnRUeXBlID09PSAnc3RlcF9zdGFydGVkJykge1xuICAgICAgICBjb25zdCBvd25lciA9XG4gICAgICAgICAgJ2V2ZW50RGF0YScgaW4gZSAmJlxuICAgICAgICAgIGUuZXZlbnREYXRhICYmXG4gICAgICAgICAgJ293bmVyTWVzc2FnZUlkJyBpbiBlLmV2ZW50RGF0YSAmJlxuICAgICAgICAgIHR5cGVvZiBlLmV2ZW50RGF0YS5vd25lck1lc3NhZ2VJZCA9PT0gJ3N0cmluZydcbiAgICAgICAgICAgID8gZS5ldmVudERhdGEub3duZXJNZXNzYWdlSWRcbiAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBwcmlvciA9IHN0ZXBPd25lcnNoaXAuZ2V0KGUuY29ycmVsYXRpb25JZCk7XG4gICAgICAgIHN0ZXBPd25lcnNoaXAuc2V0KGUuY29ycmVsYXRpb25JZCwge1xuICAgICAgICAgIG93bmVyLFxuICAgICAgICAgIHN0YXJ0ZWRBdE1zOiBlLmNyZWF0ZWRBdCA/ICtuZXcgRGF0ZShlLmNyZWF0ZWRBdCkgOiB1bmRlZmluZWQsXG4gICAgICAgICAgc2F3UmV0cnlpbmc6IHByaW9yPy5zYXdSZXRyeWluZyA/PyBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKGUuZXZlbnRUeXBlID09PSAnc3RlcF9yZXRyeWluZycpIHtcbiAgICAgICAgY29uc3QgcHJpb3IgPSBzdGVwT3duZXJzaGlwLmdldChlLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBzdGVwT3duZXJzaGlwLnNldChlLmNvcnJlbGF0aW9uSWQsIHtcbiAgICAgICAgICAuLi4ocHJpb3IgPz8ge30pLFxuICAgICAgICAgIHNhd1JldHJ5aW5nOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIG9ic2VydmVFdmVudHNGb3JPd25lcnNoaXAoZXZlbnRzKTtcbiAgY29uc3Qgc2NoZWR1bGVkV2FpdENvbnRpbnVhdGlvbnMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3QgbWF4SW5saW5lU3RlcHMgPSBnZXRNYXhJbmxpbmVTdGVwcygpO1xuICBjb25zdCBidWRnZXQgPSBuZXcgUmVwbGF5QnVkZ2V0KCk7XG4gIGNvbnN0IHdvcmtmbG93U3RhcnRlZEF0ID0gd29ya2Zsb3dSdW4uc3RhcnRlZEF0XG4gICAgPyArd29ya2Zsb3dSdW4uc3RhcnRlZEF0XG4gICAgOiBEYXRlLm5vdygpO1xuICBjb25zdCByb290UnVuSWQgPVxuICAgICh3b3JrZmxvd1J1bi5hdHRyaWJ1dGVzIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQpPy5bXG4gICAgICBST09UX1JVTl9JRF9BVFRSSUJVVEVcbiAgICBdID8/IHJ1bklkO1xuICBsZXQgaW5saW5lU3RlcHNFeGVjdXRlZCA9IDA7XG4gIGxldCBydW5Hb25lID0gZmFsc2U7XG4gIC8vIFNldCB3aGVuIHRoaXMgaW52b2NhdGlvbiB3cm90ZSBhbiBldmVudCB0aGUgd29ya2Zsb3cgbXVzdCBjb25zdW1lIHRvXG4gIC8vIG1ha2UgcHJvZ3Jlc3MgKGF0dHJfc2V0LCBnZXRDb25mbGljdC1hd2FpdGVkIGhvb2tfY3JlYXRlZCkgYW5kIHRoZVxuICAvLyBsb29wIGhhcyBub3QgeWV0IHJlYWQgaXQgYmFjayDigJQgZXZlbnR1YWxseS1jb25zaXN0ZW50IGxpc3RpbmdzIGNhblxuICAvLyByZXR1cm4gMCBuZXcgZXZlbnRzIHJpZ2h0IGFmdGVyIGEgd3JpdGUuIElmIGl0IGlzIHN0aWxsIHNldCB3aGVuIHRoZVxuICAvLyBsb29wIGV4aXRzIHN1c3BlbmRlZCwgdGhlIGVudHJ5cG9pbnQgcmVxdWV1ZXMgaW1tZWRpYXRlbHkgaW5zdGVhZCBvZlxuICAvLyBleGl0aW5nIGF3YWl0aW5nX2V4dGVybmFsIHdpdGggdGhlIHVuYmxvY2tpbmcgZXZlbnQgYWxyZWFkeSB3cml0dGVuXG4gIC8vIGFuZCBub3RoaW5nIHNjaGVkdWxlZCB0byByZWFkIGl0LlxuICBsZXQgcGVuZGluZ1JlcXVldWVTaWduYWwgPSBmYWxzZTtcblxuICAvKiogRmV0Y2ggYWxsIGV2ZW50cyBub3QgeWV0IHByb2Nlc3NlZCBieSB0aGUgbGl2ZSBWTSAobG9nIG9yZGVyKS4gKi9cbiAgY29uc3QgZmV0Y2hVbnNlZW5FdmVudHMgPSBhc3luYyAoKTogUHJvbWlzZTxFdmVudFtdPiA9PiB7XG4gICAgY29uc3QgdW5zZWVuOiBFdmVudFtdID0gW107XG4gICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gICAgbGV0IGhhc01vcmUgPSB0cnVlO1xuICAgIHdoaWxlIChoYXNNb3JlKSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHdvcmxkLmV2ZW50cy5saXN0KHtcbiAgICAgICAgcnVuSWQsXG4gICAgICAgIHBhZ2luYXRpb246IHtcbiAgICAgICAgICBzb3J0T3JkZXI6ICdhc2MnLFxuICAgICAgICAgIGN1cnNvcjogY3Vyc29yID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICBsaW1pdDogMTAwMCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgZm9yIChjb25zdCBlIG9mIHJlc3BvbnNlLmRhdGEpIHtcbiAgICAgICAgaWYgKGUuZXZlbnRJZCAmJiBzZWVuRXZlbnRJZHMuaGFzKGUuZXZlbnRJZCkpIGNvbnRpbnVlO1xuICAgICAgICBpZiAoZS5ldmVudElkKSBzZWVuRXZlbnRJZHMuYWRkKGUuZXZlbnRJZCk7XG4gICAgICAgIHVuc2Vlbi5wdXNoKGUpO1xuICAgICAgfVxuICAgICAgaWYgKHJlc3BvbnNlLmN1cnNvcikgY3Vyc29yID0gcmVzcG9uc2UuY3Vyc29yO1xuICAgICAgaGFzTW9yZSA9IHJlc3BvbnNlLmRhdGEubGVuZ3RoID4gMCAmJiByZXNwb25zZS5jdXJzb3IgIT0gbnVsbDtcbiAgICB9XG4gICAgb2JzZXJ2ZUV2ZW50c0Zvck93bmVyc2hpcCh1bnNlZW4pO1xuICAgIHJldHVybiB1bnNlZW47XG4gIH07XG5cbiAgdHJ5IHtcbiAgICBsZXQgaXRlcmF0aW9uID0gMDtcbiAgICB3aGlsZSAocmVzdWx0LnN1c3BlbmRlZCAmJiAhcnVuR29uZSAmJiAhYnVkZ2V0LmlzRXhoYXVzdGVkKCkpIHtcbiAgICAgIGl0ZXJhdGlvbisrO1xuICAgICAgLy8gUmUtY2hlY2sgdGhlIGV2ZW50IGNlaWxpbmcgZXZlcnkgdHVybjogdGhlIGxvb3AgYXBwZW5kcyBldmVudHMgb25cbiAgICAgIC8vIGVhY2ggY29udGludWVXaXRoRXZlbnRzLCBzbyBhIHNpbmdsZSBpbnZvY2F0aW9uIGNhbiBvdGhlcndpc2UgZ3Jvd1xuICAgICAgLy8gdGhlIGxvZyBhcmJpdHJhcmlseSBmYXIgcGFzdCB0aGUgb3BlcmF0b3IncyBsaW1pdCAodGhlIG5vZGUgZW5naW5lXG4gICAgICAvLyByZS1jaGVja3MgcGVyIHJlcGxheSBmb3IgdGhlIHNhbWUgcmVhc29uKS4gYHNlZW5FdmVudElkc2AgY291bnRzXG4gICAgICAvLyBldmVyeSBldmVudCB0aGlzIGludm9jYXRpb24gaGFzIG9ic2VydmVkIOKAlCBpbml0aWFsIGxvZyArIGFsbFxuICAgICAgLy8gZmVlZHMuXG4gICAgICBpZiAobWF4RXZlbnRzTGltaXQgIT09IHVuZGVmaW5lZCAmJiBzZWVuRXZlbnRJZHMuc2l6ZSA+PSBtYXhFdmVudHNMaW1pdCkge1xuICAgICAgICB0aHJvdyBuZXcgTWF4RXZlbnRzRXhjZWVkZWRFcnJvcihzZWVuRXZlbnRJZHMuc2l6ZSwgbWF4RXZlbnRzTGltaXQpO1xuICAgICAgfVxuICAgICAgY29uc3QgcGVuZGluZ09wZXJhdGlvbnMgPSByZXN1bHQuc3VzcGVuZGVkLnBlbmRpbmdPcGVyYXRpb25zO1xuXG4gICAgICAvLyBTZWxlY3QgdGhpcyB0dXJuJ3MgaW5saW5lIGNhbmRpZGF0ZXMgQkVGT1JFIGRpc3BhdGNoOiBmcmVzaCBzdGVwc1xuICAgICAgLy8gKG5vIHN0ZXBfY3JlYXRlZCB5ZXQpIHRoYXQgdGhpcyBpbnZvY2F0aW9uIGhhc24ndCBhbHJlYWR5IGhhbmRsZWQuXG4gICAgICAvLyBUaGVpciBzdGVwX2NyZWF0ZWQgaXMgZGVsaWJlcmF0ZWx5IE5PVCB3cml0dGVuIGJ5IGRpc3BhdGNoIOKAlCB0aGVcbiAgICAgIC8vIGlubGluZSBjbGFpbSBiZWxvdyBpcyBhIGxhenkgc3RlcF9zdGFydGVkIGNhcnJ5aW5nIHRoZSBpbnB1dCxcbiAgICAgIC8vIHdoaWNoIHRoZSB3b3JsZCBhcHBsaWVzIGFzIGFuIGF0b21pYyBjcmVhdGUtY2xhaW0uIEEgY29uY3VycmVudFxuICAgICAgLy8gaW52b2NhdGlvbiByYWNpbmcgb24gdGhlIHNhbWUgZnJlc2ggc3RlcCBsb3NlcyB0aGF0IGNsYWltIHdpdGhcbiAgICAgIC8vIEVudGl0eUNvbmZsaWN0RXJyb3IgYW5kIHNraXBzLCBzbyBzdGVwIGJvZGllcyBjYW5ub3QgZG91YmxlLXJ1blxuICAgICAgLy8gKHByZXZpb3VzbHkgYm90aCBpbnZvY2F0aW9ucyBiYXJlLXN0YXJ0ZWQgdGhlIHN0ZXAgYWZ0ZXIgb25lIGxvc3RcbiAgICAgIC8vIHRoZSBzd2FsbG93ZWQgc3RlcF9jcmVhdGVkIHJhY2UpLlxuICAgICAgY29uc3QgZnJlc2hTdGVwcyA9IHBlbmRpbmdPcGVyYXRpb25zLmZpbHRlcihcbiAgICAgICAgKG9wKTogb3AgaXMgUGVuZGluZ1N0ZXAgPT5cbiAgICAgICAgICBvcC50eXBlID09PSAnc3RlcCcgJiZcbiAgICAgICAgICAhb3AuaGFzQ3JlYXRlZEV2ZW50ICYmXG4gICAgICAgICAgIWV4ZWN1dGVkU3RlcElkcy5oYXMob3AuY29ycmVsYXRpb25JZCkgJiZcbiAgICAgICAgICAhcXVldWVkU3RlcElkcy5oYXMob3AuY29ycmVsYXRpb25JZClcbiAgICAgICk7XG4gICAgICBjb25zdCBpbmxpbmVDYW5kaWRhdGVzID1cbiAgICAgICAgbWF4SW5saW5lU3RlcHMgPD0gMCA/IFtdIDogZnJlc2hTdGVwcy5zbGljZSgwLCBtYXhJbmxpbmVTdGVwcyk7XG4gICAgICBjb25zdCBpbmxpbmVDbGFpbUNpZHMgPSBuZXcgU2V0KFxuICAgICAgICBpbmxpbmVDYW5kaWRhdGVzLm1hcCgoc3RlcCkgPT4gc3RlcC5jb3JyZWxhdGlvbklkKVxuICAgICAgKTtcblxuICAgICAgLy8gMS4gRHVyYWJsZSBzaWRlIGVmZmVjdHMgZm9yIHRoaXMgc3VzcGVuc2lvbidzIHBlbmRpbmcgb3BzLlxuICAgICAgY29uc3Qgb3BzVG9EaXNwYXRjaCA9IHBlbmRpbmdPcGVyYXRpb25zLm1hcCgob3ApID0+XG4gICAgICAgIG9wLnR5cGUgPT09ICdob29rJyAmJlxuICAgICAgICAob3AgYXMgUGVuZGluZ0hvb2spLmFib3J0UmVxdWVzdGVkICYmXG4gICAgICAgIHJlY29yZGVkQWJvcnRJZHMuaGFzKG9wLmNvcnJlbGF0aW9uSWQpXG4gICAgICAgICAgPyAoeyAuLi5vcCwgYWJvcnRSZXF1ZXN0ZWQ6IGZhbHNlIH0gYXMgUGVuZGluZ09wZXJhdGlvbilcbiAgICAgICAgICA6IG9wXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCBvcCBvZiBwZW5kaW5nT3BlcmF0aW9ucykge1xuICAgICAgICBpZiAob3AudHlwZSA9PT0gJ2hvb2snICYmIChvcCBhcyBQZW5kaW5nSG9vaykuYWJvcnRSZXF1ZXN0ZWQpIHtcbiAgICAgICAgICByZWNvcmRlZEFib3J0SWRzLmFkZChvcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgZGlzcGF0Y2hlZCA9IGF3YWl0IGRpc3BhdGNoUGVuZGluZ09wcyh7XG4gICAgICAgIHdvcmxkLFxuICAgICAgICBydW5JZCxcbiAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgcGVuZGluZ09wZXJhdGlvbnM6IG9wc1RvRGlzcGF0Y2gsXG4gICAgICAgIHNraXBTdGVwQ3JlYXRpb246IGlubGluZUNsYWltQ2lkcyxcbiAgICAgICAgd2ZkaWFnLFxuICAgICAgfSk7XG4gICAgICBpZiAoXG4gICAgICAgIGRpc3BhdGNoZWQuY3JlYXRlZEF0dHJpYnV0ZUV2ZW50IHx8XG4gICAgICAgIGRpc3BhdGNoZWQuY3JlYXRlZEdldENvbmZsaWN0SG9va1xuICAgICAgKSB7XG4gICAgICAgIHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gSGFuZCBzdGVwcyBiZXlvbmQgdGhlIGlubGluZSBjYXAgdG8gdGhlIHF1ZXVlIE5PVyDigJQgaW4gdGhlIHNhbWVcbiAgICAgIC8vIHR1cm4gdGhlaXIgc3RlcF9jcmVhdGVkIHdhcyB3cml0dGVuIGJ5IHRoZSBkaXNwYXRjaCBhYm92ZS4gVGhpc1xuICAgICAgLy8gbXVzdCBoYXBwZW4gQkVGT1JFIHRoZSBldmVudCBmZWVkIGJlbG93OiB0aGUgZmVlZCBhbHdheXMgb2JzZXJ2ZXNcbiAgICAgIC8vIHRob3NlIHZlcnkgc3RlcF9jcmVhdGVkIHdyaXRlcyBhcyB1bnNlZW4gZXZlbnRzIGFuZCBgY29udGludWVgcyxcbiAgICAgIC8vIHNvIGEgaGFuZG9mZiBwbGFjZWQgYWZ0ZXIgaXQgaXMgdW5yZWFjaGFibGUgb24gdGhlIG9ubHkgaXRlcmF0aW9uXG4gICAgICAvLyB0aGF0IHN0aWxsIGNsYXNzaWZpZXMgdGhlc2Ugc3RlcHMgYXMgZnJlc2gg4oCUIG5leHQgdHVybiB0aGV5IGNhcnJ5XG4gICAgICAvLyBoYXNDcmVhdGVkRXZlbnQgYW5kIHdvdWxkIG5ldmVyIGJlIHF1ZXVlZCBhdCBhbGwgKHRoZSB3ZWRnZSBiZWhpbmRcbiAgICAgIC8vIHByb21pc2VSYWNlU3RyZXNzVGVzdFdvcmtmbG93IGhhbmdpbmcgaW4gdGhlIHF1aWNranMgQ0kgbGVncykuIFRoZVxuICAgICAgLy8gYmFyZS1jb3JyZWxhdGlvbklkIGlkZW1wb3RlbmN5IGtleSBtYWtlcyByZXBlYXRzIGhhcm1sZXNzLlxuICAgICAgY29uc3Qgb3ZlcmZsb3dTdGVwcyA9IGZyZXNoU3RlcHMuc2xpY2UoaW5saW5lQ2FuZGlkYXRlcy5sZW5ndGgpO1xuICAgICAgZm9yIChjb25zdCBzdGVwIG9mIG92ZXJmbG93U3RlcHMpIHtcbiAgICAgICAgcXVldWVkU3RlcElkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgYXdhaXQgcXVldWVTdGVwTWVzc2FnZSh7XG4gICAgICAgICAgd29ybGQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgc3RlcCxcbiAgICAgICAgICBuYW1lc3BhY2UsXG4gICAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgICBwdXJwb3NlOiAnZGlzcGF0Y2gnLFxuICAgICAgICAgIHdmZGlhZyxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIENvbXBsZXRlIGVsYXBzZWQgd2FpdHMgc28gdGhlaXIgd2FpdF9jb21wbGV0ZWQgZXZlbnRzIGFyZSBwaWNrZWRcbiAgICAgIC8vIHVwIGJ5IHRoZSBmZWVkIGJlbG93IChpbnN0ZWFkIG9mIGEgcXVldWUgcmUtaW52b2NhdGlvbikuXG4gICAgICBjb25zdCB3YWl0Q29tcGxldGVQcm9taXNlczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gICAgICBmb3IgKGNvbnN0IG9wIG9mIHBlbmRpbmdPcGVyYXRpb25zKSB7XG4gICAgICAgIGlmIChvcC50eXBlICE9PSAnd2FpdCcpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCB3YWl0ID0gb3AgYXMgUGVuZGluZ1dhaXQ7XG4gICAgICAgIGlmIChjb21wbGV0ZWRXYWl0SWRzMi5oYXMod2FpdC5jb3JyZWxhdGlvbklkKSkgY29udGludWU7XG4gICAgICAgIGlmIChuZXcgRGF0ZSh3YWl0LnJlc3VtZUF0KS5nZXRUaW1lKCkgLSBEYXRlLm5vdygpID4gMCkgY29udGludWU7XG4gICAgICAgIGNvbXBsZXRlZFdhaXRJZHMyLmFkZCh3YWl0LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICB3YWl0Q29tcGxldGVQcm9taXNlcy5wdXNoKFxuICAgICAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnd2FpdF9jb21wbGV0ZWQnLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiB3YWl0LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHJldHVybjtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pKClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmICh3YWl0Q29tcGxldGVQcm9taXNlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHdhaXRDb21wbGV0ZVByb21pc2VzKTtcbiAgICAgIH1cblxuICAgICAgLy8gMi4gQ2hlYXAgcHJvZ3Jlc3MgZmlyc3Q6IGZlZWQgbmV3bHkgcmVjb3JkZWQgZXZlbnRzIGludG8gdGhlIGxpdmVcbiAgICAgIC8vIFZNIGJlZm9yZSBibG9ja2luZyBvbiBzdGVwIGJvZGllcy5cbiAgICAgIHtcbiAgICAgICAgY29uc3QgbmV3RXZlbnRzID0gYXdhaXQgZmV0Y2hVbnNlZW5FdmVudHMoKTtcbiAgICAgICAgaWYgKG5ld0V2ZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgLy8gVGhlIGxpc3RpbmcgY2F1Z2h0IHVwIHdpdGggdGhpcyBpbnZvY2F0aW9uJ3Mgd3JpdGVzIOKAlCBhbnlcbiAgICAgICAgICAvLyBhdHRyX3NldCAvIGdldENvbmZsaWN0IGhvb2tfY3JlYXRlZCBoYXMgYmVlbiAob3IgaXMgYmVpbmcpXG4gICAgICAgICAgLy8gY29uc3VtZWQgYnkgdGhlIGxpdmUgVk0sIHNvIG5vIGV4dGVybmFsIHJlcXVldWUgaXMgbmVlZGVkLlxuICAgICAgICAgIHBlbmRpbmdSZXF1ZXVlU2lnbmFsID0gZmFsc2U7XG4gICAgICAgICAgcmVzdWx0ID0gYXdhaXQgc2Vzc2lvbi5jb250aW51ZVdpdGhFdmVudHMobmV3RXZlbnRzKTtcbiAgICAgICAgICB3ZmRpYWcoJ2lubGluZV9pdGVyYXRpb24nLCB7XG4gICAgICAgICAgICBpdGVyYXRpb24sXG4gICAgICAgICAgICBwaGFzZTogJ2ZlZWQnLFxuICAgICAgICAgICAgZmVkRXZlbnRzOiBuZXdFdmVudHMubGVuZ3RoLFxuICAgICAgICAgICAgb3V0Y29tZTogcmVzdWx0LmNvbXBsZXRlZFxuICAgICAgICAgICAgICA/ICdjb21wbGV0ZWQnXG4gICAgICAgICAgICAgIDogcmVzdWx0LmZhaWxlZFxuICAgICAgICAgICAgICAgID8gJ2ZhaWxlZCdcbiAgICAgICAgICAgICAgICA6ICdzdXNwZW5kZWQnLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIDMuIE5vIGNoZWFwIHByb2dyZXNzIGxlZnQg4oCUIGV4ZWN1dGUgc3RlcHMgaW5saW5lLlxuICAgICAgY29uc3Qgc3RlcE9wcyA9IHBlbmRpbmdPcGVyYXRpb25zLmZpbHRlcihcbiAgICAgICAgKG9wKTogb3AgaXMgUGVuZGluZ1N0ZXAgPT4gb3AudHlwZSA9PT0gJ3N0ZXAnXG4gICAgICApO1xuICAgICAgLy8gU3RlcHMgY3JlYXRlZCBieSBhbiBFQVJMSUVSIGludm9jYXRpb24gKG9yIGFuIGVhcmxpZXIgdHVybikgdGhhdFxuICAgICAgLy8gYXJlIHN0aWxsIHBlbmRpbmcsIHdpdGggbm8gd29yayBvd25lZCBieSBUSElTIGludm9jYXRpb24uIE1pcnJvclxuICAgICAgLy8gdGhlIG5vZGUgZW5naW5lJ3Mgb3duZXJzaGlwIGRlY2lzaW9uIHRhYmxlIChzdGVwLW93bmVyc2hpcC50cykg4oCUXG4gICAgICAvLyBOT1QgYSBkZWxpdmVyeUF0dGVtcHQgZ2F0ZTogd29ybGRzIGFkdmFuY2UgdGhlIGF0dGVtcHQgY291bnRlciBvblxuICAgICAgLy8gcm91dGluZSByZWRlbGl2ZXJpZXMgKHdvcmxkLWxvY2FsIGNvdW50cyBldmVyeSBoYW5kbGVkIHJlc3BvbnNlKSxcbiAgICAgIC8vIHNvIGF0dGVtcHQgPiAxIGlzIHRoZSBjb21tb24gY2FzZSBhbmQgd291bGQgZmlyZSBiYWNrc3RvcHMgYXRcbiAgICAgIC8vIHN0ZXBzIGFjdGl2ZWx5IGV4ZWN1dGluZyBpbmxpbmUgaW4gYSBsaXZlIGludm9jYXRpb24uXG4gICAgICAvL1xuICAgICAgLy8gICAtIE93bmVyc2hpcCBsZWFzZSBBQ1RJVkUsIGhlbGQgYnkgQU5PVEhFUiBtZXNzYWdlIOKGkiB0aGUgc3RlcCBpc1xuICAgICAgLy8gICAgIChwcmVzdW1hYmx5KSBleGVjdXRpbmcgaW5saW5lIGluIGEgbGl2ZSBpbnZvY2F0aW9uLiBBcm0gYVxuICAgICAgLy8gICAgIERFTEFZRUQgYmFja3N0b3AgZm9yIHRoZSBsZWFzZSByZW1haW5kZXIsIGtleWVkIHRvIHRoZVxuICAgICAgLy8gICAgIG93bmVyc2hpcCBlcG9jaCAoYSByZWZyZXNoZWQgbGVhc2UgcmUtYXJtcyBhIGZyZXNoIGJhY2tzdG9wXG4gICAgICAvLyAgICAgaW5zdGVhZCBvZiBkZWR1cGluZyBhZ2FpbnN0IHRoZSBpbi1mbGlnaHQgb25lKS4gSWYgdGhlIG93bmVyXG4gICAgICAvLyAgICAgY29tcGxldGVzIG5vcm1hbGx5LCB0aGUgYmFja3N0b3AgZGVsaXZlcnkgcmVzb2x2ZXMgdGhlIHN0ZXBcbiAgICAgIC8vICAgICBhcyAnc2tpcHBlZCcuXG4gICAgICAvLyAgIC0gT3duZXJzaGlwIGxlYXNlIEFDVElWRSwgaGVsZCBieSBUSElTIG1lc3NhZ2Ug4oaSIHRoaXMgZGVsaXZlcnlcbiAgICAgIC8vICAgICBpcyB0aGUgb3duZXIncyByZWRlbGl2ZXJ5OyB0aGUgY2xhaW1hbnQgY3Jhc2hlZFxuICAgICAgLy8gICAgIG1pZC1leGVjdXRpb24uIERpc3BhdGNoIGltbWVkaWF0ZWx5IGZvciBiYWNrZ3JvdW5kIHJlY292ZXJ5LlxuICAgICAgLy8gICAtIE5vIHN0YW1wIC8gbGVhc2UgRVhQSVJFRCAvIHN0ZXBfcmV0cnlpbmcgb2JzZXJ2ZWQg4oaSIHRoZSBzdGVwXG4gICAgICAvLyAgICAgaXMgcXVldWUtb3duZWQgb3Igb3JwaGFuZWQuIERpc3BhdGNoIGltbWVkaWF0ZWx5OyB0aGVcbiAgICAgIC8vICAgICBiYXJlLWNvcnJlbGF0aW9uSWQgaWRlbXBvdGVuY3kga2V5IGRlZHVwZXMgYWdhaW5zdCB0aGVcbiAgICAgIC8vICAgICBvcmlnaW5hbCBoYW5kb2ZmLlxuICAgICAgY29uc3Qgbm93TXMgPSBEYXRlLm5vdygpO1xuICAgICAgZm9yIChjb25zdCBzdGVwIG9mIHN0ZXBPcHMpIHtcbiAgICAgICAgaWYgKCFzdGVwLmhhc0NyZWF0ZWRFdmVudCkgY29udGludWU7XG4gICAgICAgIGlmIChleGVjdXRlZFN0ZXBJZHMuaGFzKHN0ZXAuY29ycmVsYXRpb25JZCkpIGNvbnRpbnVlO1xuICAgICAgICBpZiAocXVldWVkU3RlcElkcy5oYXMoc3RlcC5jb3JyZWxhdGlvbklkKSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IG93bmVyc2hpcCA9IHN0ZXBPd25lcnNoaXAuZ2V0KHN0ZXAuY29ycmVsYXRpb25JZCk7XG4gICAgICAgIGNvbnN0IG93bmVyc2hpcEFjdGl2ZSA9XG4gICAgICAgICAgb3duZXJzaGlwICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICBvd25lcnNoaXAub3duZXIgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICFvd25lcnNoaXAuc2F3UmV0cnlpbmc7XG4gICAgICAgIGxldCBsZWFzZVJlbWFpbmluZ1NlY29uZHMgPSAwO1xuICAgICAgICBpZiAob3duZXJzaGlwQWN0aXZlICYmIG93bmVyc2hpcC5zdGFydGVkQXRNcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY29uc3QgbGVhc2VTZWNvbmRzID0gZ2V0SW5saW5lT3duZXJzaGlwTGVhc2VTZWNvbmRzKCk7XG4gICAgICAgICAgbGVhc2VSZW1haW5pbmdTZWNvbmRzID0gTWF0aC5taW4oXG4gICAgICAgICAgICBsZWFzZVNlY29uZHMsXG4gICAgICAgICAgICBNYXRoLm1heChcbiAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgTWF0aC5jZWlsKFxuICAgICAgICAgICAgICAgIChvd25lcnNoaXAuc3RhcnRlZEF0TXMgKyBsZWFzZVNlY29uZHMgKiAxMDAwIC0gbm93TXMpIC8gMTAwMFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoXG4gICAgICAgICAgb3duZXJzaGlwQWN0aXZlICYmXG4gICAgICAgICAgb3duZXJzaGlwLm93bmVyICE9PSBvd25lck1lc3NhZ2VJZCAmJlxuICAgICAgICAgIGxlYXNlUmVtYWluaW5nU2Vjb25kcyA+IDBcbiAgICAgICAgKSB7XG4gICAgICAgICAgcXVldWVkU3RlcElkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICBhd2FpdCBxdWV1ZVN0ZXBNZXNzYWdlKHtcbiAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICBkZWxheVNlY29uZHM6IGxlYXNlUmVtYWluaW5nU2Vjb25kcyxcbiAgICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICBwdXJwb3NlOiBgYmFja3N0b3A6JHtvd25lcnNoaXAuc3RhcnRlZEF0TXN9YCxcbiAgICAgICAgICAgIHdmZGlhZyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChzdGVwLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIGF3YWl0IHF1ZXVlU3RlcE1lc3NhZ2Uoe1xuICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICBwdXJwb3NlOiAnZGlzcGF0Y2gnLFxuICAgICAgICAgICAgd2ZkaWFnLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAvLyBObyBpbi1wcm9jZXNzIHByb2dyZXNzIHBvc3NpYmxlIOKAlCB0aGUgcnVuIGF3YWl0cyBhbiBleHRlcm5hbFxuICAgICAgICAvLyBzdGltdWx1cyAoaG9vayBwYXlsb2FkLCBxdWV1ZWQgc3RlcCwgd2FpdCB0aW1lcikuXG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyBSYWNpbmcgdGltZXJzIG11c3QgZmlyZSBvbiB0aW1lIHdoaWxlIHN0ZXAgYm9kaWVzIGJsb2NrIHRoaXNcbiAgICAgIC8vIGludm9jYXRpb246IGVucXVldWUgYSBkZWxheWVkIGNvbnRpbnVhdGlvbiBmb3IgdGhlIHNvb25lc3RcbiAgICAgIC8vIHBlbmRpbmcgd2FpdCAoYSBzZXBhcmF0ZSBpbnZvY2F0aW9uIHdyaXRlcyBpdHMgd2FpdF9jb21wbGV0ZWQgYXRcbiAgICAgIC8vIHRoZSByaWdodCBsb2cgcG9zaXRpb24g4oCUIHNhbWUgbWVjaGFuaXNtIGFzIHRoZSBub2RlOnZtIGVuZ2luZSdzXG4gICAgICAvLyB3YWl0LWNvbnRpbnVhdGlvbiBkaXNwYXRjaCkuXG4gICAgICBsZXQgc29vbmVzdFdhaXQ6IHsgY29ycmVsYXRpb25JZDogc3RyaW5nOyBzZWNvbmRzOiBudW1iZXIgfSB8IHVuZGVmaW5lZDtcbiAgICAgIGZvciAoY29uc3Qgb3Agb2YgcGVuZGluZ09wZXJhdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wLnR5cGUgIT09ICd3YWl0JykgY29udGludWU7XG4gICAgICAgIGNvbnN0IHdhaXQgPSBvcCBhcyBQZW5kaW5nV2FpdDtcbiAgICAgICAgaWYgKHNjaGVkdWxlZFdhaXRDb250aW51YXRpb25zLmhhcyh3YWl0LmNvcnJlbGF0aW9uSWQpKSBjb250aW51ZTtcbiAgICAgICAgLy8gV2FpdHMgd2hvc2Ugd2FpdF9jb21wbGV0ZWQgVEhJUyBpbnZvY2F0aW9uIGFscmVhZHkgd3JvdGUgKHRoZVxuICAgICAgICAvLyBlbGFwc2VkLXdhaXQgcGFzcyBhYm92ZSkgYXJlIGRvbmUg4oCUIHRoZSBldmVudCBqdXN0IGhhc24ndCBmZWRcbiAgICAgICAgLy8gYmFjayBpbnRvIHRoZSBWTSB5ZXQuIE5vIGNvbnRpbnVhdGlvbiBuZWVkZWQuXG4gICAgICAgIGlmIChjb21wbGV0ZWRXYWl0SWRzMi5oYXMod2FpdC5jb3JyZWxhdGlvbklkKSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IHJlc3VtZU1zID0gbmV3IERhdGUod2FpdC5yZXN1bWVBdCkuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKTtcbiAgICAgICAgLy8gQW4gYWxyZWFkeS1lbGFwc2VkIHdhaXQgTVVTVCBzdGlsbCBnZXQgYSBjb250aW51YXRpb24gKGNsYW1wZWRcbiAgICAgICAgLy8gdG8gdGhlIDFzIG1pbmltdW0sIGV4YWN0bHkgbGlrZSB0aGUgbm9kZSBlbmdpbmUnc1xuICAgICAgICAvLyBgTWF0aC5tYXgoMTAwMCwgcmVzdW1lQXRNcyAtIG5vdylgKSwgbm90IGJlIHNraXBwZWQ6IGEgd2FpdFxuICAgICAgICAvLyB3aG9zZSBkZWFkbGluZSBmYWxscyBiZXR3ZWVuIHRoaXMgaXRlcmF0aW9uJ3MgZWxhcHNlZC13YWl0XG4gICAgICAgIC8vIHBhc3MgKHdoaWNoIHNhdyBpdCBhcyBzdGlsbCBwZW5kaW5nIGFuZCB3cm90ZSBub3RoaW5nKSBhbmRcbiAgICAgICAgLy8gdGhpcyBzd2VlcCB3b3VsZCBvdGhlcndpc2UgZ2V0IE5FSVRIRVIgYSB3YWl0X2NvbXBsZXRlZCBOT1IgYVxuICAgICAgICAvLyBjb250aW51YXRpb24g4oCUIGFuZCB0aGUgaW5saW5lIGJhdGNoIGJlbG93IHRoZW4gYmxvY2tzIHRoaXNcbiAgICAgICAgLy8gaW52b2NhdGlvbiBmb3IgdGhlIGZ1bGwgc3RlcCBkdXJhdGlvbiB3aXRoIG5vIHdha2UgYXJtZWRcbiAgICAgICAgLy8gYW55d2hlcmUuIEZvciBgUHJvbWlzZS5yYWNlKHN0ZXAsIHNsZWVwKWAgdGhhdCBzaWxlbnRseSBoYW5kc1xuICAgICAgICAvLyB0aGUgcmFjZSB0byB0aGUgc3RlcDogdGhlIHNsZWVwJ3Mgd2FpdF9jb21wbGV0ZWQgaXMgbmV2ZXJcbiAgICAgICAgLy8gd3JpdHRlbiBhbmQgdGhlIHJ1biBjb21wbGV0ZXMgd2l0aCB0aGUgd3Jvbmcgd2lubmVyLiBUaGVcbiAgICAgICAgLy8gd2luZG93IGJldHdlZW4gdGhlIHR3byBjaGVja3Mgc3BhbnMgdGhpcyBpdGVyYXRpb24ncyBkaXNwYXRjaFxuICAgICAgICAvLyArIGZlZWQgcm91bmQtdHJpcHMsIHNvIG9uIG5ldHdvcmstYmFja2VkIHdvcmxkcyAod29ybGQtdmVyY2VsKVxuICAgICAgICAvLyBhIHNob3J0IHNsZWVwIGxhbmRzIGluIGl0IHJvdXRpbmVseSDigJQgb2JzZXJ2ZWQgYXMgYSB+NTAlXG4gICAgICAgIC8vIHNsZWVwV2luc1JhY2VXb3JrZmxvdyBmYWlsdXJlIHJhdGUgaW4gdGhlIFZlcmNlbCBlMmUgbGVncyxcbiAgICAgICAgLy8gd2hpbGUgd29ybGQtbG9jYWwncyBzdWItbXMgcm91bmQtdHJpcHMgbWFza2VkIGl0IGxvY2FsbHkuIFRoZVxuICAgICAgICAvLyBjb250aW51YXRpb24gaW52b2NhdGlvbidzIHByZS1WTSBlbGFwc2VkIGNoZWNrIHdyaXRlcyB0aGVcbiAgICAgICAgLy8gd2FpdF9jb21wbGV0ZWQgfjFzIGxhdGVyLlxuICAgICAgICBjb25zdCBzZWNvbmRzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKHJlc3VtZU1zIC8gMTAwMCkpO1xuICAgICAgICBpZiAoIXNvb25lc3RXYWl0IHx8IHNlY29uZHMgPCBzb29uZXN0V2FpdC5zZWNvbmRzKSB7XG4gICAgICAgICAgc29vbmVzdFdhaXQgPSB7IGNvcnJlbGF0aW9uSWQ6IHdhaXQuY29ycmVsYXRpb25JZCwgc2Vjb25kcyB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoc29vbmVzdFdhaXQpIHtcbiAgICAgICAgc2NoZWR1bGVkV2FpdENvbnRpbnVhdGlvbnMuYWRkKHNvb25lc3RXYWl0LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgICAgd29ybGQsXG4gICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dSdW4ud29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGdldFdhaXRDb250aW51YXRpb25EaXNwYXRjaChcbiAgICAgICAgICAgIHNvb25lc3RXYWl0LnNlY29uZHMsXG4gICAgICAgICAgICBzb29uZXN0V2FpdC5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB3ZmRpYWcoJ3dhaXRfY29udGludWF0aW9uX3NjaGVkdWxlZCcsIHtcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzb29uZXN0V2FpdC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGRlbGF5U2Vjb25kczogc29vbmVzdFdhaXQuc2Vjb25kcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIEV4ZWN1dGUgdGhlIGlubGluZSBiYXRjaCBpbiBwYXJhbGxlbC4gVGhlIHJlcGxheSBidWRnZXQgaXNcbiAgICAgIC8vIHBhdXNlZCB3aGlsZSBzdGVwIGJvZGllcyBydW4g4oCUIHN0ZXAgZHVyYXRpb24gaXMgYm91bmRlZCBieSB0aGVcbiAgICAgIC8vIHBsYXRmb3JtIGZ1bmN0aW9uIGR1cmF0aW9uLCBub3QgdGhlIHJlcGxheSB0aW1lb3V0LiBOT1RFIChieVxuICAgICAgLy8gZGVzaWduKTogd2l0aCB0aGUgYnVkZ2V0IHBhcmtlZCBwZXIgYmF0Y2gsIHRoZSBvbmx5IGJvdW5kIG9uIGhvd1xuICAgICAgLy8gbWFueSBpbmxpbmUgc3RlcHMgb25lIGludm9jYXRpb24gY2FuIGNoYWluIGlzIHRoZSBwbGF0Zm9ybSdzXG4gICAgICAvLyBmdW5jdGlvbiB0aW1lb3V0IOKAlCB0aGUgU0RLIGRlbGliZXJhdGVseSBpbXBvc2VzIG5vIGNhcCBvZiBpdHNcbiAgICAgIC8vIG93biwgbWF0Y2hpbmcgdGhlIG5vZGU6dm0gZW5naW5lLCB3aGVyZSBhIGxvbmcgc2VxdWVudGlhbFxuICAgICAgLy8gd29ya2Zsb3cgbGlrZXdpc2UgcnVucyBzdGVwLWJ5LXN0ZXAgdW50aWwgdGhlIHBsYXRmb3JtIHJlY2xhaW1zXG4gICAgICAvLyB0aGUgaW52b2NhdGlvbiBhbmQgYSByZWRlbGl2ZXJ5IHJlc3VtZXMgZnJvbSB0aGUgbG9nLlxuICAgICAgYnVkZ2V0LnBhdXNlKCk7XG4gICAgICBsZXQgb3V0Y29tZXM6IFN0ZXBFeGVjdXRpb25SZXN1bHRbXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIG91dGNvbWVzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgaW5saW5lQ2FuZGlkYXRlcy5tYXAoKHN0ZXApID0+XG4gICAgICAgICAgICBydW5TdGVwU2luZ2xlRmxpZ2h0KHJ1bklkLCBzdGVwLmNvcnJlbGF0aW9uSWQsICgpID0+XG4gICAgICAgICAgICAgIChhc3luYyAoKSA9PlxuICAgICAgICAgICAgICAgIGV4ZWN1dGVTdGVwKHtcbiAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd0RlcGxveW1lbnRJZDogd29ya2Zsb3dSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiB3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdCxcbiAgICAgICAgICAgICAgICAgIHJvb3RSdW5JZCxcbiAgICAgICAgICAgICAgICAgIHN0ZXBJZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXAuc3RlcElkLFxuICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgIHJ1blNwZWNWZXJzaW9uOiB3b3JrZmxvd1J1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgICAgIC8vIExhenkgaW5saW5lIGNsYWltOiBzdGVwX2NyZWF0ZWQgaXMgZGVmZXJyZWQgKGRpc3BhdGNoXG4gICAgICAgICAgICAgICAgICAvLyBza2lwcGVkIGl0KSBhbmQgdGhpcyBzdGVwX3N0YXJ0ZWQgY2FycmllcyB0aGUgaW5wdXQsXG4gICAgICAgICAgICAgICAgICAvLyBzbyB0aGUgd29ybGQgY3JlYXRlcyB0aGUgc3RlcCBhdG9taWNhbGx5IOKAlFxuICAgICAgICAgICAgICAgICAgLy8gZXhhY3RseS1vbmUtb3duZXIuIEEgY29uY3VycmVudCBjbGFpbWFudCBnZXRzXG4gICAgICAgICAgICAgICAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yIOKGkiB7IHR5cGU6ICdza2lwcGVkJyB9IGFuZCBuZXZlclxuICAgICAgICAgICAgICAgICAgLy8gcnVucyB0aGUgYm9keS4gTWlycm9ycyB0aGUgbm9kZSBlbmdpbmUncyBpbmxpbmUgcGF0aC5cbiAgICAgICAgICAgICAgICAgIGxhenlTdGVwSW5wdXQ6IGF3YWl0IGVuY3J5cHRTZXJpYWxpemVkRGF0YShcbiAgICAgICAgICAgICAgICAgICAgc3RlcC5pbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIC8vIE93bmVyc2hpcCBzdGFtcDogd2FrZSByZXBsYXlzIHNlZSB0aGUgYm9keSBhcyBpblxuICAgICAgICAgICAgICAgICAgLy8gZmxpZ2h0IGluIHRoaXMgaW52b2NhdGlvbiBhbmQgYXJtIGEgZGVsYXllZCBiYWNrc3RvcFxuICAgICAgICAgICAgICAgICAgLy8gaW5zdGVhZCBvZiBpbW1lZGlhdGVseSByZXF1ZXVlaW5nIHRoZSBzdGVwLlxuICAgICAgICAgICAgICAgICAgb3duZXJNZXNzYWdlSWQsXG4gICAgICAgICAgICAgICAgICAvLyBBIGxhenkgc3RlcCBpcyBicmFuZC1uZXcgYnkgY29uc3RydWN0aW9uIOKAlCBmaXJzdFxuICAgICAgICAgICAgICAgICAgLy8gYXR0ZW1wdC5cbiAgICAgICAgICAgICAgICAgIGF1dGhvcml0YXRpdmVBdHRlbXB0OiAxLFxuICAgICAgICAgICAgICAgIH0pKSgpXG4gICAgICAgICAgICApXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYnVkZ2V0LnJlc3VtZSgpO1xuICAgICAgfVxuICAgICAgaW5saW5lU3RlcHNFeGVjdXRlZCArPSBpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aDtcblxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbmxpbmVDYW5kaWRhdGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHN0ZXAgPSBpbmxpbmVDYW5kaWRhdGVzW2ldO1xuICAgICAgICBjb25zdCBvdXRjb21lID0gb3V0Y29tZXNbaV07XG4gICAgICAgIGV4ZWN1dGVkU3RlcElkcy5hZGQoc3RlcC5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgaWYgKG91dGNvbWUudHlwZSA9PT0gJ3JldHJ5JyB8fCBvdXRjb21lLnR5cGUgPT09ICd0aHJvdHRsZWQnKSB7XG4gICAgICAgICAgLy8gSGFuZCB0aGUgc3RlcCB0byB0aGUgcXVldWUgd2l0aCB0aGUgcmVxdWVzdGVkIGJhY2tvZmYg4oCUXG4gICAgICAgICAgLy8gYmFja2dyb3VuZCBkZWxpdmVyeSBkcml2ZXMgdGhlIHJldHJ5IGZyb20gaGVyZS5cbiAgICAgICAgICBxdWV1ZWRTdGVwSWRzLmFkZChzdGVwLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIGF3YWl0IHF1ZXVlU3RlcE1lc3NhZ2Uoe1xuICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgIGRlbGF5U2Vjb25kczogb3V0Y29tZS50aW1lb3V0U2Vjb25kcyxcbiAgICAgICAgICAgIG5hbWVzcGFjZSxcbiAgICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICAvLyBTdWZmaXhlZCBrZXk6IHRoaXMgc3RlcCB3YXMgaW5saW5lLWNsYWltZWQsIHNvIG5vIGRpc3BhdGNoXG4gICAgICAgICAgICAvLyBwdWJsaXNoIGV4aXN0cyB1bmRlciB0aGUgYmFyZSBjb3JyZWxhdGlvbklkIOKAlCBidXQgc3VmZml4aW5nXG4gICAgICAgICAgICAvLyBrZWVwcyB0aGUgcmV0cnkgZW5xdWV1ZWFibGUgZXZlbiBpZiBhIHdvcmxkIHJldGlyZWQgYVxuICAgICAgICAgICAgLy8gaGlzdG9yaWNhbCBrZXkgZm9yIHRoaXMgc3RlcCAoc2VlIHRoZSBwdXJwb3NlIGRvY3MgYWJvdmUpLlxuICAgICAgICAgICAgcHVycG9zZTogJ3JldHJ5OjEnLFxuICAgICAgICAgICAgd2ZkaWFnLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKG91dGNvbWUudHlwZSA9PT0gJ2dvbmUnKSB7XG4gICAgICAgICAgcnVuR29uZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gJ3NraXBwZWQnOiBhIGNvbmN1cnJlbnQgaW52b2NhdGlvbiB3b24gdGhlIGxhenkgY3JlYXRlLWNsYWltIGFuZFxuICAgICAgICAvLyBvd25zIHRoZSBib2R5LiBNYXJrZWQgZXhlY3V0ZWQgYWJvdmUgc28gdGhpcyBpbnZvY2F0aW9uIG5ldmVyXG4gICAgICAgIC8vIHJlLWNsYWltcyBpdDsgdGhlIHdpbm5lcidzIHRlcm1pbmFsIGV2ZW50cyBhcnJpdmUgdmlhIHRoZSBmZWVkXG4gICAgICAgIC8vIChvciBkcml2ZSBhIHNlcGFyYXRlIGludm9jYXRpb24pLlxuICAgICAgfVxuICAgICAgd2ZkaWFnKCdpbmxpbmVfc3RlcHNfZXhlY3V0ZWQnLCB7XG4gICAgICAgIGl0ZXJhdGlvbixcbiAgICAgICAgY291bnQ6IGlubGluZUNhbmRpZGF0ZXMubGVuZ3RoLFxuICAgICAgICBvdXRjb21lczogb3V0Y29tZXMubWFwKChvKSA9PiBvLnR5cGUpLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEZlZWQgdGhlIGlubGluZSBiYXRjaCdzIHRlcm1pbmFsIGV2ZW50cyBpbnRvIHRoZSBsaXZlIFZNLiBXaGVuXG4gICAgICAvLyB0aGUgZXZlbnR1YWxseS1jb25zaXN0ZW50IGxpc3RpbmcgaGFzIG5vdCBzdXJmYWNlZCB0aGVtIHlldCxcbiAgICAgIC8vIGV4aXRpbmcgbXVzdCBOT1QgYWNrIHNpbGVudGx5OiB0aGUgdGVybWluYWxzIHRoaXMgaW52b2NhdGlvbiBqdXN0XG4gICAgICAvLyBjYXVzZWQgYXJlIGR1cmFibHkgd3JpdHRlbiB3aXRoIG5vIHF1ZXVlIG1lc3NhZ2UgbGVmdCB0byBjb25zdW1lXG4gICAgICAvLyB0aGVtIChpbmxpbmUgc3RlcHMgaGF2ZSBub25lKSwgc28gYW4gYXdhaXRpbmdfZXh0ZXJuYWwgZXhpdCB3b3VsZFxuICAgICAgLy8gcGFyayB0aGUgcnVuICdydW5uaW5nJyB3aXRoIGFsbCBpdHMgc3RlcHMgY29tcGxldGUuIFJhaXNlIHRoZVxuICAgICAgLy8gcmVxdWV1ZSBzaWduYWwgc28gdGhlIHN1c3BlbmRlZCBleGl0IHNjaGVkdWxlcyBhIGZyZXNoIGltbWVkaWF0ZVxuICAgICAgLy8gaW52b2NhdGlvbiB3aG9zZSBmcmVzaCByZWFkIHBpY2tzIHRoZSB0ZXJtaW5hbHMgdXAuIE91dGNvbWVzIHRoYXRcbiAgICAgIC8vIHdyb3RlIG5vIHRlcm1pbmFsICgnc2tpcHBlZCcg4oCUIGEgY29uY3VycmVudCBjbGFpbWFudCBvd25zIHRoZVxuICAgICAgLy8gYm9keTsgJ2dvbmUnLCByZXRyeS90aHJvdHRsZWQg4oCUIGEgcXVldWUgbWVzc2FnZSBleGlzdHMpIGRvbid0XG4gICAgICAvLyBuZWVkIGl0LCBidXQgc2lnbmFsaW5nIG9uIHRoZW0gdG9vIG9ubHkgY29zdHMgYSBuby1vcCBpbnZvY2F0aW9uXG4gICAgICAvLyBpbiBhbiBhbHJlYWR5LXJhcmUgbGFnIHdpbmRvdy5cbiAgICAgIGNvbnN0IG5ld0V2ZW50cyA9IGF3YWl0IGZldGNoVW5zZWVuRXZlbnRzKCk7XG4gICAgICBpZiAobmV3RXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBwZW5kaW5nUmVxdWV1ZVNpZ25hbCA9IHRydWU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgcmVzdWx0ID0gYXdhaXQgc2Vzc2lvbi5jb250aW51ZVdpdGhFdmVudHMobmV3RXZlbnRzKTtcblxuICAgICAgd2ZkaWFnKCdpbmxpbmVfaXRlcmF0aW9uJywge1xuICAgICAgICBpdGVyYXRpb24sXG4gICAgICAgIHBoYXNlOiAnc3RlcHMnLFxuICAgICAgICBmZWRFdmVudHM6IG5ld0V2ZW50cy5sZW5ndGgsXG4gICAgICAgIG91dGNvbWU6IHJlc3VsdC5jb21wbGV0ZWRcbiAgICAgICAgICA/ICdjb21wbGV0ZWQnXG4gICAgICAgICAgOiByZXN1bHQuZmFpbGVkXG4gICAgICAgICAgICA/ICdmYWlsZWQnXG4gICAgICAgICAgICA6ICdzdXNwZW5kZWQnLFxuICAgICAgICBidWRnZXRFeGhhdXN0ZWQ6IGJ1ZGdldC5pc0V4aGF1c3RlZCgpLFxuICAgICAgfSk7XG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIHNlc3Npb24uZGlzcG9zZSgpO1xuICB9XG5cbiAgcGFyZW50U3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgLi4uQXR0cmlidXRlLlF1aWNrSlNJbmxpbmVTdGVwcyhpbmxpbmVTdGVwc0V4ZWN1dGVkKSxcbiAgfSk7XG5cbiAgaWYgKHJlc3VsdC5jb21wbGV0ZWQpIHtcbiAgICAvLyBXb3JrZmxvdyBjb21wbGV0ZWRcbiAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1F1aWNrSlMgcnVudGltZTogd29ya2Zsb3cgY29tcGxldGVkJywge1xuICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgfSk7XG4gICAgcGFyZW50U3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU091dGNvbWUoJ2NvbXBsZXRlZCcpLFxuICAgIH0pO1xuXG4gICAgLy8gRmx1c2ggbGVmdG92ZXIgcGVuZGluZyBzaWRlIGVmZmVjdHMgKGFib3J0IHJlY29yZGluZ3MsIHN5c3RlbS1ob29rXG4gICAgLy8gZGlzcG9zYWxzLCBmaXJlLWFuZC1mb3JnZXQgYXR0cmlidXRlL2hvb2sgZXZlbnRzKSBCRUZPUkUgd3JpdGluZ1xuICAgIC8vIHJ1bl9jb21wbGV0ZWQg4oCUIG1pcnJvcnMgdGhlIG5vZGU6dm0gZW5naW5lJ3MgZHJhaW5QZW5kaW5nUXVldWVJdGVtcy5cbiAgICAvLyBEcmFpbiBmYWlsdXJlcyBhcmUgc3dhbGxvd2VkOiB0aGUgd29ya2Zsb3cncyBvd24gb3V0Y29tZSBpcyB0aGVcbiAgICAvLyBzb3VyY2Ugb2YgdHJ1dGguXG4gICAgaWYgKHJlc3VsdC5jb21wbGV0ZWQuZHJhaW5PcGVyYXRpb25zPy5sZW5ndGgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGRpc3BhdGNoUGVuZGluZ09wcyh7XG4gICAgICAgICAgd29ybGQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICBuYW1lc3BhY2UsXG4gICAgICAgICAgbmV4dFRyYWNlQ2FycmllcixcbiAgICAgICAgICBwZW5kaW5nT3BlcmF0aW9uczogcmVzdWx0LmNvbXBsZXRlZC5kcmFpbk9wZXJhdGlvbnMsXG4gICAgICAgICAgd2ZkaWFnLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oJ1F1aWNrSlMgcnVudGltZTogdGVybWluYWwgZHJhaW4gZmFpbGVkJywge1xuICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgIG1lc3NhZ2U6IChlcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgcnVuX2NvbXBsZXRlZCBldmVudC5cbiAgICAvLyBUaGUgVk0gc2VyaWFsaXplcyB0aGUgd29ya2Zsb3cgcmVzdWx0IGFzIGZvcm1hdC1wcmVmaXhlZCBkZXZhbHVlIGJ5dGVzXG4gICAgLy8gKFwiZGV2bFwiICsgZGV2YWx1ZSkgd2l0aCBubyBlbmNyeXB0aW9uICh0aGUgVk0gaGFzIG5vIGFjY2VzcyB0byB0aGVcbiAgICAvLyBDcnlwdG9LZXkpLiBIb3N0LXNpZGUgZW5jcnlwdGlvbiBpcyBhcHBsaWVkIGhlcmUgc28gdGhhdCBgcnVuX2NvbXBsZXRlZGBcbiAgICAvLyBldmVudHMgaGF2ZSB0aGUgc2FtZSBgZW5jcmAtcHJlZml4ZWQgcGF5bG9hZCBzaGFwZSB0aGF0IHRoZSBub2RlOnZtXG4gICAgLy8gZW5naW5lJ3MgYGRlaHlkcmF0ZVdvcmtmbG93UmV0dXJuVmFsdWVgIHByb2R1Y2VzLlxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgIGV2ZW50VHlwZTogJ3J1bl9jb21wbGV0ZWQnLFxuICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgIG91dHB1dDogYXdhaXQgZW5jcnlwdFNlcmlhbGl6ZWREYXRhKFxuICAgICAgICAgICAgcmVzdWx0LmNvbXBsZXRlZC5yZXN1bHQsXG4gICAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICAgKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgd2ZkaWFnKCdleGl0X2NvbXBsZXRlZCcsIHsgcmVzdWx0OiAncnVuX2NvbXBsZXRlZF93cml0dGVuJyB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikgfHwgUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAgICdXb3JrZmxvdyBhbHJlYWR5IGZpbmlzaGVkLCBza2lwcGluZyBydW5fY29tcGxldGVkJyxcbiAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkIH1cbiAgICAgICAgKTtcbiAgICAgICAgd2ZkaWFnKCdleGl0X2NvbXBsZXRlZCcsIHsgcmVzdWx0OiAnYWxyZWFkeV9maW5pc2hlZCcgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHdmZGlhZygnZXhpdF9jb21wbGV0ZWRfZXJyb3InLCB7XG4gICAgICAgIGVycm9yTmFtZTogKGVyciBhcyBFcnJvcik/Lm5hbWUsXG4gICAgICAgIGVycm9yTWVzc2FnZTogKGVyciBhcyBFcnJvcik/Lm1lc3NhZ2UsXG4gICAgICB9KTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH0gZWxzZSBpZiAocmVzdWx0LnN1c3BlbmRlZCkge1xuICAgIC8vIFdvcmtmbG93IHN0aWxsIHN1c3BlbmRlZCBhZnRlciB0aGUgaW5saW5lIGxvb3AuIEFsbCBkdXJhYmxlIHNpZGVcbiAgICAvLyBlZmZlY3RzIGZvciB0aGUgZmluYWwgc3VzcGVuc2lvbiBzdGF0ZSB3ZXJlIGFscmVhZHkgZGlzcGF0Y2hlZCBieVxuICAgIC8vIHRoZSBsb29wOyB3aGF0IHJlbWFpbnMgaXMgZGVjaWRpbmcgaG93IHRoZSBydW4gZ2V0cyByZS1pbnZva2VkLlxuICAgIGNvbnN0IHsgcGVuZGluZ09wZXJhdGlvbnMgfSA9IHJlc3VsdC5zdXNwZW5kZWQ7XG5cbiAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1F1aWNrSlMgcnVudGltZTogd29ya2Zsb3cgc3VzcGVuZGVkJywge1xuICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICBpbmxpbmVTdGVwc0V4ZWN1dGVkLFxuICAgICAgcGVuZGluZ1N0ZXBzOiBwZW5kaW5nT3BlcmF0aW9ucy5maWx0ZXIoKHApID0+IHAudHlwZSA9PT0gJ3N0ZXAnKS5sZW5ndGgsXG4gICAgICBwZW5kaW5nV2FpdHM6IHBlbmRpbmdPcGVyYXRpb25zLmZpbHRlcigocCkgPT4gcC50eXBlID09PSAnd2FpdCcpLmxlbmd0aCxcbiAgICAgIHBlbmRpbmdPcHM6IHBlbmRpbmdPcGVyYXRpb25zLm1hcCgocCkgPT4gKHtcbiAgICAgICAgdHlwZTogcC50eXBlLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgIGhhc0NyZWF0ZWRFdmVudDogcC5oYXNDcmVhdGVkRXZlbnQsXG4gICAgICAgIC4uLihwLnR5cGUgPT09ICdzdGVwJyA/IHsgc3RlcElkOiAocCBhcyBQZW5kaW5nU3RlcCkuc3RlcElkIH0gOiB7fSksXG4gICAgICB9KSksXG4gICAgfSk7XG5cbiAgICBwYXJlbnRTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5RdWlja0pTT3V0Y29tZSgnc3VzcGVuZGVkJyksXG4gICAgICAuLi5BdHRyaWJ1dGUuUXVpY2tKU1BlbmRpbmdPcHNDb3VudChwZW5kaW5nT3BlcmF0aW9ucy5sZW5ndGgpLFxuICAgIH0pO1xuXG4gICAgaWYgKHJ1bkdvbmUpIHtcbiAgICAgIC8vIFRoZSBydW4gbm8gbG9uZ2VyIGV4aXN0cyAoZXhwaXJlZCAvIGRlbGV0ZWQpIOKAlCBub3RoaW5nIHRvIGRyaXZlLlxuICAgICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHsgYWN0aW9uOiAncnVuX2dvbmUnIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEV4aXQgcmVxdWV1ZXMgYXJlIEZSRVNIIG1lc3NhZ2VzLCBuZXZlciBhIGB7IHRpbWVvdXRTZWNvbmRzIH1gXG4gICAgLy8gdmlzaWJpbGl0eS1yZWRlbGl2ZXJ5IG9mIHRoZSBjdXJyZW50IG1lc3NhZ2UuIFJlZGVsaXZlcmluZyB0aGVcbiAgICAvLyBDVVJSRU5UIG1lc3NhZ2UgaXMgYSB0cmFwOiBhIGhvb2stcmVzdW1lIGRlbGl2ZXJ5IGNhcnJpZXNcbiAgICAvLyBgaG9va0lucHV0YCwgYW5kIGl0cyByZWRlbGl2ZXJ5IHJlLXJ1bnMgdGhlIGxhenktcmVzdW1lIHJlLWVuc3VyZVxuICAgIC8vIGluIHRoZSBoYW5kbGVyIHByb2xvZ3VlIOKAlCBpZiB0aGUgd29ya2Zsb3cgZGlzcG9zZWQgdGhhdCBob29rXG4gICAgLy8gZHVyaW5nIHRoaXMgaW52b2NhdGlvbiAoZGlzcG9zZSDihpIgc2xlZXApLCBhIHdvcmxkIHRoYXQgcmVqZWN0c1xuICAgIC8vIHRoZSByZS1lbnN1cmUgd291bGQgYWNrIHRoZSBtZXNzYWdlIGFzIFwibm90aGluZyBsZWZ0IHRvIHJlc3VtZVwiXG4gICAgLy8gYW5kIHRoZSBjb250aW51YXRpb24gaXQgY2FycmllZCBpcyBzaWxlbnRseSBsb3N0LiBBIGZyZXNoIG1lc3NhZ2VcbiAgICAvLyBjYXJyaWVzIG9ubHkgYHJ1bklkYCwgc28gaXRzIGRlbGl2ZXJ5IGFsd2F5cyByZWFjaGVzIHJlcGxheSAoYW5kXG4gICAgLy8gdW5kZXIgdHVyYm8gYSByZXNjaGVkdWxlIHdvdWxkIHJlLWVuZ2FnZSB0dXJibyBhZ2FpbnN0IGEgc3RhbGVcbiAgICAvLyBwcmVsb2FkZWQgbG9nIOKAlCBzZWUgdGhlIHJlaW52b2tlKCkgZG9jcyBpbiBydW50aW1lLnRzKS5cbiAgICBjb25zdCByZXF1ZXVlSW1tZWRpYXRlbHkgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgIHdvcmxkLFxuICAgICAgICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsIG5hbWVzcGFjZSksXG4gICAgICAgIHtcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICB0cmFjZUNhcnJpZXI6IGF3YWl0IG5leHRUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9O1xuXG4gICAgaWYgKGJ1ZGdldC5pc0V4aGF1c3RlZCgpKSB7XG4gICAgICAvLyBUaGUgbG9vcCBzdG9wcGVkIG9uIHRoZSByZXBsYXkgYnVkZ2V0IHdpdGggcHJvZ3Jlc3Mgc3RpbGxcbiAgICAgIC8vIHBvc3NpYmxlIOKAlCBjb250aW51ZSBpbiBhIGZyZXNoIGludm9jYXRpb24uXG4gICAgICB3ZmRpYWcoJ2V4aXRfc3VzcGVuZGVkJywgeyBhY3Rpb246ICdidWRnZXRfZXhoYXVzdGVkX3JlcXVldWUnIH0pO1xuICAgICAgYXdhaXQgcmVxdWV1ZUltbWVkaWF0ZWx5KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gRXhpdCB3YWl0IHN3ZWVwLiBBIHdhaXQgdGhhdCBlbGFwc2VkIGluIHRoZSB3aW5kb3cgc2luY2UgdGhlXG4gICAgLy8gbG9vcCdzIGxhc3QgY2hlY2sgcmVxdWV1ZXMgaW1tZWRpYXRlbHkgKGl0cyB3YWl0X2NvbXBsZXRlZCBpc1xuICAgIC8vIHdyaXR0ZW4gYnkgdGhlIG5leHQgaW52b2NhdGlvbidzIGVsYXBzZWQtd2FpdCBwYXNzKTsgcGVuZGluZyB3YWl0c1xuICAgIC8vIHdob3NlIGNvbnRpbnVhdGlvbiB0aGUgbG9vcCBhbHJlYWR5IGVucXVldWVkIGFyZSBza2lwcGVkLlxuICAgIGxldCBzb29uZXN0V2FpdDogeyBzZWNvbmRzOiBudW1iZXI7IGNvcnJlbGF0aW9uSWQ6IHN0cmluZyB9IHwgdW5kZWZpbmVkO1xuICAgIGxldCBoYXNFbGFwc2VkV2FpdCA9IGZhbHNlO1xuICAgIGZvciAoY29uc3Qgb3Agb2YgcGVuZGluZ09wZXJhdGlvbnMpIHtcbiAgICAgIGlmIChvcC50eXBlICE9PSAnd2FpdCcpIGNvbnRpbnVlO1xuICAgICAgY29uc3Qgd2FpdCA9IG9wIGFzIFBlbmRpbmdXYWl0O1xuICAgICAgY29uc3QgcmVzdW1lTXMgPSBuZXcgRGF0ZSh3YWl0LnJlc3VtZUF0KS5nZXRUaW1lKCkgLSBEYXRlLm5vdygpO1xuICAgICAgaWYgKHJlc3VtZU1zIDw9IDApIHtcbiAgICAgICAgaGFzRWxhcHNlZFdhaXQgPSB0cnVlO1xuICAgICAgfSBlbHNlIGlmICghc2NoZWR1bGVkV2FpdENvbnRpbnVhdGlvbnMuaGFzKHdhaXQuY29ycmVsYXRpb25JZCkpIHtcbiAgICAgICAgY29uc3QgdGltZW91dFNlY29uZHMgPSBNYXRoLm1heCgxLCBNYXRoLmNlaWwocmVzdW1lTXMgLyAxMDAwKSk7XG4gICAgICAgIGlmICghc29vbmVzdFdhaXQgfHwgdGltZW91dFNlY29uZHMgPCBzb29uZXN0V2FpdC5zZWNvbmRzKSB7XG4gICAgICAgICAgc29vbmVzdFdhaXQgPSB7XG4gICAgICAgICAgICBzZWNvbmRzOiB0aW1lb3V0U2Vjb25kcyxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHdhaXQuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGhhc0VsYXBzZWRXYWl0KSB7XG4gICAgICB3ZmRpYWcoJ2V4aXRfc3VzcGVuZGVkJywgeyBhY3Rpb246ICd3YWl0X2VsYXBzZWRfcmVxdWV1ZScgfSk7XG4gICAgICBhd2FpdCByZXF1ZXVlSW1tZWRpYXRlbHkoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocGVuZGluZ1JlcXVldWVTaWduYWwpIHtcbiAgICAgIC8vIFRoaXMgaW52b2NhdGlvbiB3cm90ZSBldmVudHMgdGhlIHdvcmtmbG93IG5lZWRzIHRvIGNvbnN1bWVcbiAgICAgIC8vIChhdHRyX3NldCAvIGdldENvbmZsaWN0LWF3YWl0ZWQgaG9va19jcmVhdGVkIC8gaW5saW5lIHN0ZXBcbiAgICAgIC8vIHRlcm1pbmFscykgYnV0IHRoZSBldmVudHVhbGx5LWNvbnNpc3RlbnQgbGlzdGluZyBuZXZlciByZXR1cm5lZFxuICAgICAgLy8gdGhlbSBiZWZvcmUgdGhlIGxvb3AgZXhpdGVkLiBXaXRob3V0IGEgcmVxdWV1ZSB0aGUgcnVuIHdvdWxkXG4gICAgICAvLyBwYXJrIGF3YWl0aW5nX2V4dGVybmFsIHdpdGggaXRzIHVuYmxvY2tpbmcgZXZlbnRzIGFscmVhZHlcbiAgICAgIC8vIGR1cmFibHkgd3JpdHRlbiBhbmQgbm8gZnV0dXJlIGludm9jYXRpb24gY29taW5nIOKAlCByZXF1ZXVlXG4gICAgICAvLyBpbW1lZGlhdGVseSBzbyBhIGZyZXNoIHJlYWQgcGlja3MgdGhlbSB1cC4gSW4gdGhlIGNvbW1vbiBjYXNlXG4gICAgICAvLyB0aGUgbG9vcCdzIG93biBmZWVkIG9ic2VydmVzIHRoZSB3cml0ZXMgYW5kIGNsZWFycyB0aGlzIGZsYWcsIHNvXG4gICAgICAvLyB0aGlzIG9ubHkgZmlyZXMgd2hlbiB0aGUgcmVhZCBhY3R1YWxseSBsYWdnZWQuXG4gICAgICB3ZmRpYWcoJ2V4aXRfc3VzcGVuZGVkJywgeyBhY3Rpb246ICd1bnJlYWRfc2VsZl93cml0ZV9yZXF1ZXVlJyB9KTtcbiAgICAgIGF3YWl0IHJlcXVldWVJbW1lZGlhdGVseSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzb29uZXN0V2FpdCkge1xuICAgICAgLy8gRGVsYXllZCBjb250aW51YXRpb24gZm9yIHRoZSBzb29uZXN0IHBlbmRpbmcgd2FpdCB0aGUgbG9vcCBoYXNcbiAgICAgIC8vIG5vdCBhbHJlYWR5IHNjaGVkdWxlZC4gVGhlIGRpc3BhdGNoIGhlbHBlciBoYW5kbGVzIGRlbGF5XG4gICAgICAvLyBjbGFtcGluZyAobG9uZyB3YWl0cyBjaGFpbiBhY3Jvc3MgaG9wcykgYW5kIGlkZW1wb3RlbmN5LWtleVxuICAgICAgLy8gZGVkdXAgb2YgcmUtb2JzZXJ2YXRpb25zIG9mIHRoZSBzYW1lIHBlbmRpbmcgd2FpdCDigJQgc2VlXG4gICAgICAvLyBydW50aW1lL3dhaXQtY29udGludWF0aW9uLnRzLlxuICAgICAgd2ZkaWFnKCdleGl0X3N1c3BlbmRlZCcsIHtcbiAgICAgICAgYWN0aW9uOiAnc2NoZWR1bGVfd2FpdF90aW1lb3V0JyxcbiAgICAgICAgdGltZW91dFNlY29uZHM6IHNvb25lc3RXYWl0LnNlY29uZHMsXG4gICAgICAgIHdhaXRDb3JyZWxhdGlvbklkOiBzb29uZXN0V2FpdC5jb3JyZWxhdGlvbklkLFxuICAgICAgfSk7XG4gICAgICBzY2hlZHVsZWRXYWl0Q29udGludWF0aW9ucy5hZGQoc29vbmVzdFdhaXQuY29ycmVsYXRpb25JZCk7XG4gICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgIHdvcmxkLFxuICAgICAgICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUsIG5hbWVzcGFjZSksXG4gICAgICAgIHtcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICB0cmFjZUNhcnJpZXI6IGF3YWl0IG5leHRUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0V2FpdENvbnRpbnVhdGlvbkRpc3BhdGNoKFxuICAgICAgICAgIHNvb25lc3RXYWl0LnNlY29uZHMsXG4gICAgICAgICAgc29vbmVzdFdhaXQuY29ycmVsYXRpb25JZFxuICAgICAgICApXG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdmZGlhZygnZXhpdF9zdXNwZW5kZWQnLCB7XG4gICAgICBhY3Rpb246ICdhd2FpdGluZ19leHRlcm5hbCcsXG4gICAgICBwZW5kaW5nT3BzQ291bnQ6IHBlbmRpbmdPcGVyYXRpb25zLmxlbmd0aCxcbiAgICB9KTtcbiAgfSBlbHNlIGlmIChyZXN1bHQuZmFpbGVkKSB7XG4gICAgLy8gV29ya2Zsb3cgZmFpbGVkIOKAlCByZW1hcCBzdGFjayB0cmFjZSB1c2luZyBpbmxpbmUgc291cmNlIG1hcHNcbiAgICBsZXQgZXJyb3JTdGFjayA9IHJlc3VsdC5mYWlsZWQuc3RhY2s7XG4gICAgaWYgKGVycm9yU3RhY2spIHtcbiAgICAgIGNvbnN0IHBhcnNlZE5hbWUgPSBwYXJzZVdvcmtmbG93TmFtZSh3b3JrZmxvd05hbWUpO1xuICAgICAgY29uc3QgZmlsZW5hbWUgPSBwYXJzZWROYW1lPy5tb2R1bGVTcGVjaWZpZXIgfHwgd29ya2Zsb3dOYW1lO1xuICAgICAgZXJyb3JTdGFjayA9IHJlbWFwRXJyb3JTdGFjayhlcnJvclN0YWNrLCBmaWxlbmFtZSwgd29ya2Zsb3dDb2RlKTtcbiAgICB9XG5cbiAgICAvLyBDbGFzc2lmeSB0aGUgZXJyb3Igc28gY29uc3VtZXJzIChgcnVuLnJldHVyblZhbHVlYCwgb2JzZXJ2YWJpbGl0eSlcbiAgICAvLyBnZXQgYFVTRVJfRVJST1JgIC8gYFJVTlRJTUVfRVJST1JgIG9uIGBlcnJvci5jYXVzZS5jb2RlYCwgbWF0Y2hpbmdcbiAgICAvLyB3aGF0IHRoZSBub2RlOnZtIGVuZ2luZSBhbHJlYWR5IGRvZXMgaW4gcnVudGltZS50cy5cbiAgICAvL1xuICAgIC8vIFRoZSBWTSBzZXJpYWxpemVzIGVycm9ycyBhcyBgeyBuYW1lLCBtZXNzYWdlLCBzdGFjayB9YCwgc28gd2VcbiAgICAvLyByZWNvbnN0cnVjdCBhIGhvc3Qtc2lkZSBFcnJvciBvZiB0aGUgY29ycmVjdCBjbGFzcyBiYXNlZCBvbiB0aGVcbiAgICAvLyBWTS1zaWRlIGBuYW1lYCDigJQgc3BlY2lmaWMgV29ya2Zsb3dSdW50aW1lRXJyb3Igc3ViY2xhc3NlcyBuZWVkXG4gICAgLy8gdG8gYmUgcHJlc2VydmVkIHNvIGNsYXNzaWZ5UnVuRXJyb3IoKSB0YWdzIHRoZW0gYXMgUlVOVElNRV9FUlJPUi5cbiAgICBjb25zdCByZWNvbnN0cnVjdGVkOiBFcnJvciA9XG4gICAgICByZXN1bHQuZmFpbGVkLm5hbWUgPT09ICdXb3JrZmxvd05vdFJlZ2lzdGVyZWRFcnJvcidcbiAgICAgICAgPyBuZXcgV29ya2Zsb3dOb3RSZWdpc3RlcmVkRXJyb3Iod29ya2Zsb3dOYW1lKVxuICAgICAgICA6IHJlc3VsdC5mYWlsZWQubmFtZSA9PT0gJ0Vycm9yJ1xuICAgICAgICAgID8gbmV3IEVycm9yKHJlc3VsdC5mYWlsZWQubWVzc2FnZSlcbiAgICAgICAgICA6IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKHJlc3VsdC5mYWlsZWQubWVzc2FnZSksIHtcbiAgICAgICAgICAgICAgbmFtZTogcmVzdWx0LmZhaWxlZC5uYW1lLFxuICAgICAgICAgICAgfSk7XG4gICAgY29uc3QgZXJyb3JDb2RlID0gY2xhc3NpZnlSdW5FcnJvcihyZWNvbnN0cnVjdGVkKTtcblxuICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoJ1F1aWNrSlMgcnVudGltZTogd29ya2Zsb3cgZmFpbGVkJywge1xuICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICBlcnJvck5hbWU6IHJlc3VsdC5mYWlsZWQubmFtZSxcbiAgICAgIGVycm9yTWVzc2FnZTogcmVzdWx0LmZhaWxlZC5tZXNzYWdlLFxuICAgICAgZXJyb3JTdGFjayxcbiAgICAgIGVycm9yQ29kZSxcbiAgICB9KTtcbiAgICBwYXJlbnRTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5RdWlja0pTT3V0Y29tZSgnZmFpbGVkJyksXG4gICAgfSk7XG5cbiAgICAvLyBGbHVzaCBsZWZ0b3ZlciBwZW5kaW5nIHNpZGUgZWZmZWN0cyBiZWZvcmUgd3JpdGluZyBydW5fZmFpbGVkIOKAlFxuICAgIC8vIHNhbWUgZHJhaW4gc2VtYW50aWNzIGFzIHRoZSBjb21wbGV0ZWQgYnJhbmNoLlxuICAgIGlmIChyZXN1bHQuZmFpbGVkLmRyYWluT3BlcmF0aW9ucz8ubGVuZ3RoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBkaXNwYXRjaFBlbmRpbmdPcHMoe1xuICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICAgIG5leHRUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgcGVuZGluZ09wZXJhdGlvbnM6IHJlc3VsdC5mYWlsZWQuZHJhaW5PcGVyYXRpb25zLFxuICAgICAgICAgIHdmZGlhZyxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKCdRdWlja0pTIHJ1bnRpbWU6IHRlcm1pbmFsIGRyYWluIGZhaWxlZCcsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICBtZXNzYWdlOiAoZXJyIGFzIEVycm9yKT8ubWVzc2FnZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIHJ1bl9mYWlsZWQgZXZlbnQuIFNlcmlhbGl6ZSB0aGUgZXJyb3IgdGhyb3VnaCB0aGVcbiAgICAvLyBmaXJzdC1jbGFzcyBkZWh5ZHJhdGlvbiBwaXBlbGluZSBzbyBjb25zdW1lcnMgKENMSSwgb2JzZXJ2YWJpbGl0eSxcbiAgICAvLyBydW4ucmV0dXJuVmFsdWUpIGdldCB0aGUgc2FtZSBoeWRyYXRlZCB2YWx1ZSBzaGFwZSBhcyB0aGUgbm9kZTp2bVxuICAgIC8vIGVuZ2luZSBlbWl0cy4gVHdvIHBhdGhzOlxuICAgIC8vICAgKiBNb2Rlcm4gKHZhbHVlQnl0ZXMgcHJlc2VudCk6IHRoZSBWTS1zaWRlIHJlamVjdGlvbiBoYW5kbGVyXG4gICAgLy8gICAgIHNlcmlhbGl6ZWQgdGhlIG9yaWdpbmFsIHRocm93biB2YWx1ZSAoRXJyb3Igc3ViY2xhc3Mgd2l0aFxuICAgIC8vICAgICBjYXVzZSBjaGFpbiwgcGxhaW4gb2JqZWN0LCBwcmltaXRpdmUsIGV0Yy4pIHVzaW5nIHRoZSBWTSdzXG4gICAgLy8gICAgIHdvcmtmbG93LXNlcmlhbGl6ZS4gUGFzcyB0aG9zZSBieXRlcyB0aHJvdWdoIGRpcmVjdGx5IHNvXG4gICAgLy8gICAgIHR5cGUgaWRlbnRpdHksIGNhdXNlIGNoYWlucywgYW5kIG5vbi1FcnJvciB0aHJvd3Mgc3Vydml2ZS5cbiAgICAvLyAgICAgV2UganVzdCBuZWVkIHRvIGFwcGx5IGVuY3J5cHRpb24gaWYgY29uZmlndXJlZCAodGhlIFZNJ3NcbiAgICAvLyAgICAgc2VyaWFsaXplciBkb2Vzbid0IGhhdmUgYWNjZXNzIHRvIHRoZSBlbmNyeXB0aW9uIGtleSkuXG4gICAgLy8gICAqIExlZ2FjeSBmYWxsYmFjazogcmVjb25zdHJ1Y3QgYW4gRXJyb3IgZnJvbSB0aGUgaG9zdC12aXNpYmxlXG4gICAgLy8gICAgIHtuYW1lLCBtZXNzYWdlLCBzdGFja30gZmllbGRzIGFuZCBydW4gaXQgdGhyb3VnaFxuICAgIC8vICAgICBgZGVoeWRyYXRlUnVuRXJyb3JgLiBVc2VkIHdoZW4gdmFsdWVCeXRlcyBpcyBhYnNlbnQgKGUuZy5cbiAgICAvLyAgICAgZXh0cmFjdEVycm9yIHBzZXVkby1mYWlsdXJlcyBmcm9tIFZNIGJvb3RzdHJhcCkuXG4gICAgbGV0IGRlaHlkcmF0ZWRFcnJvcjogVWludDhBcnJheTtcbiAgICBpZiAocmVzdWx0LmZhaWxlZC52YWx1ZUJ5dGVzKSB7XG4gICAgICAvLyBIeWRyYXRlIHRoZSBWTS1zaWRlIGJ5dGVzLCByZW1hcCB0aGUgZXJyb3Igc3RhY2sgd2l0aCB0aGVcbiAgICAgIC8vIGhvc3Qtc2lkZSBzb3VyY2UgbWFwICh0aGUgVk0gY2FuJ3QgZG8gdGhpcyDigJQgaXQgbGFja3MgYm90aCB0aGVcbiAgICAgIC8vIHNvdXJjZSBtYXAgYW5kIGByZW1hcEVycm9yU3RhY2tgKSwgYW5kIHJlLWRlaHlkcmF0ZS4gVGhpc1xuICAgICAgLy8gcHJlc2VydmVzIHRoZSBvcmlnaW5hbCB2YWx1ZSdzIHR5cGUgaWRlbnRpdHkgLyBjYXVzZSBjaGFpblxuICAgICAgLy8gd2hpbGUgZml4aW5nIHVwIGZyYW1lcyB0byBwb2ludCBhdCB0aGUgdXNlcidzIHNvdXJjZSBmaWxlcy5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGh5ZHJhdGVkID0gYXdhaXQgaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIHJlc3VsdC5mYWlsZWQudmFsdWVCeXRlcyxcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICB1bmRlZmluZWQgLy8gVk0gYnl0ZXMgYXJlIHVuZW5jcnlwdGVkXG4gICAgICAgICk7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBoeWRyYXRlZCAmJlxuICAgICAgICAgIHR5cGVvZiBoeWRyYXRlZCA9PT0gJ29iamVjdCcgJiZcbiAgICAgICAgICAnc3RhY2snIGluIChoeWRyYXRlZCBhcyBvYmplY3QpICYmXG4gICAgICAgICAgdHlwZW9mIChoeWRyYXRlZCBhcyB7IHN0YWNrPzogdW5rbm93biB9KS5zdGFjayA9PT0gJ3N0cmluZydcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgcGFyc2VkTmFtZSA9IHBhcnNlV29ya2Zsb3dOYW1lKHdvcmtmbG93TmFtZSk7XG4gICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBwYXJzZWROYW1lPy5tb2R1bGVTcGVjaWZpZXIgfHwgd29ya2Zsb3dOYW1lO1xuICAgICAgICAgIChoeWRyYXRlZCBhcyB7IHN0YWNrPzogc3RyaW5nIH0pLnN0YWNrID0gcmVtYXBFcnJvclN0YWNrKFxuICAgICAgICAgICAgKGh5ZHJhdGVkIGFzIHsgc3RhY2s6IHN0cmluZyB9KS5zdGFjayxcbiAgICAgICAgICAgIGZpbGVuYW1lLFxuICAgICAgICAgICAgd29ya2Zsb3dDb2RlXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBXYWxrIHRoZSBjYXVzZSBjaGFpbiBhbmQgcmVtYXAgbmVzdGVkIHN0YWNrcyB0b28uXG4gICAgICAgIGNvbnN0IHNlZW4gPSBuZXcgV2Vha1NldDxvYmplY3Q+KCk7XG4gICAgICAgIGxldCBub2RlID0gKGh5ZHJhdGVkIGFzIHsgY2F1c2U/OiB1bmtub3duIH0pPy5jYXVzZTtcbiAgICAgICAgd2hpbGUgKG5vZGUgJiYgdHlwZW9mIG5vZGUgPT09ICdvYmplY3QnICYmICFzZWVuLmhhcyhub2RlIGFzIG9iamVjdCkpIHtcbiAgICAgICAgICBzZWVuLmFkZChub2RlIGFzIG9iamVjdCk7XG4gICAgICAgICAgY29uc3Qgbm9kZVN0YWNrID0gKG5vZGUgYXMgeyBzdGFjaz86IHVua25vd24gfSkuc3RhY2s7XG4gICAgICAgICAgaWYgKHR5cGVvZiBub2RlU3RhY2sgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBjb25zdCBwYXJzZWROYW1lID0gcGFyc2VXb3JrZmxvd05hbWUod29ya2Zsb3dOYW1lKTtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVuYW1lID0gcGFyc2VkTmFtZT8ubW9kdWxlU3BlY2lmaWVyIHx8IHdvcmtmbG93TmFtZTtcbiAgICAgICAgICAgIChub2RlIGFzIHsgc3RhY2s/OiBzdHJpbmcgfSkuc3RhY2sgPSByZW1hcEVycm9yU3RhY2soXG4gICAgICAgICAgICAgIG5vZGVTdGFjayxcbiAgICAgICAgICAgICAgZmlsZW5hbWUsXG4gICAgICAgICAgICAgIHdvcmtmbG93Q29kZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbm9kZSA9IChub2RlIGFzIHsgY2F1c2U/OiB1bmtub3duIH0pLmNhdXNlO1xuICAgICAgICB9XG4gICAgICAgIGRlaHlkcmF0ZWRFcnJvciA9IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIGh5ZHJhdGVkLFxuICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKHJlaHlkcmF0ZUVycikge1xuICAgICAgICAvLyBJZiBoeWRyYXRpb24gLyByZS1kZWh5ZHJhdGlvbiBmYWlscyBmb3IgYW55IHJlYXNvbiwgZmFsbFxuICAgICAgICAvLyBiYWNrIHRvIHBhc3NpbmcgdGhyb3VnaCB0aGUgb3JpZ2luYWwgVk0gYnl0ZXMgKGp1c3QgYXBwbHlcbiAgICAgICAgLy8gZW5jcnlwdGlvbiBpZiBjb25maWd1cmVkKS4gQmV0dGVyIHRvIGxvc2Ugc291cmNlLW1hcHBlZFxuICAgICAgICAvLyBmcmFtZXMgdGhhbiB0byBsb3NlIHRoZSBlcnJvciBlbnRpcmVseS5cbiAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAgICdRdWlja0pTIHJ1bnRpbWU6IGZhaWxlZCB0byByZW1hcCB3b3JrZmxvdyBlcnJvciBzdGFjaywgcGFzc2luZyBWTSBieXRlcyB0aHJvdWdoJyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IChyZWh5ZHJhdGVFcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgZGVoeWRyYXRlZEVycm9yID0gKGF3YWl0IG1heWJlRW5jcnlwdChcbiAgICAgICAgICByZXN1bHQuZmFpbGVkLnZhbHVlQnl0ZXMsXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApKSBhcyBVaW50OEFycmF5O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoZXJyb3JTdGFjaykge1xuICAgICAgICByZWNvbnN0cnVjdGVkLnN0YWNrID0gZXJyb3JTdGFjaztcbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGRlaHlkcmF0ZWRFcnJvciA9IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIHJlY29uc3RydWN0ZWQsXG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoc2VyRXJyKSB7XG4gICAgICAgIC8vIEZhbGwgYmFjayB0byBhIG1pbmltYWwgcGF5bG9hZCBzbyB0aGUgcnVuIHN0aWxsIHRlcm1pbmF0ZXNcbiAgICAgICAgLy8gZXZlbiB3aGVuIHRoZSBlcnJvciBpdHNlbGYgY29udGFpbnMgdW5zZXJpYWxpemFibGUgdmFsdWVzLlxuICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAgICAgJ1F1aWNrSlMgcnVudGltZTogZmFpbGVkIHRvIGRlaHlkcmF0ZSBydW4gZXJyb3IsIGZhbGxpbmcgYmFjayB0byBiYXJlIEVycm9yJyxcbiAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBtZXNzYWdlOiAoc2VyRXJyIGFzIEVycm9yKT8ubWVzc2FnZSB9XG4gICAgICAgICk7XG4gICAgICAgIGRlaHlkcmF0ZWRFcnJvciA9IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKHJlc3VsdC5mYWlsZWQubWVzc2FnZSksIHtcbiAgICAgICAgICAgIG5hbWU6IHJlc3VsdC5mYWlsZWQubmFtZSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICBlbmNyeXB0aW9uS2V5XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCB7XG4gICAgICAgIGV2ZW50VHlwZTogJ3J1bl9mYWlsZWQnLFxuICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgIGVycm9yOiBkZWh5ZHJhdGVkRXJyb3IsXG4gICAgICAgICAgZXJyb3JDb2RlLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8IFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybignV29ya2Zsb3cgYWxyZWFkeSBmaW5pc2hlZCwgc2tpcHBpbmcgcnVuX2ZhaWxlZCcsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgfSk7XG4gICAgICAgIHdmZGlhZygnZXhpdF9mYWlsZWQnLCB7IHJlc3VsdDogJ2FscmVhZHlfZmluaXNoZWQnIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB3ZmRpYWcoJ2V4aXRfZmFpbGVkX2Vycm9yJywge1xuICAgICAgICBlcnJvck5hbWU6IChlcnIgYXMgRXJyb3IpPy5uYW1lLFxuICAgICAgICBlcnJvck1lc3NhZ2U6IChlcnIgYXMgRXJyb3IpPy5tZXNzYWdlLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIHdmZGlhZygnZXhpdF9mYWlsZWQnLCB7IHJlc3VsdDogJ3J1bl9mYWlsZWRfd3JpdHRlbicgfSk7XG4gIH1cbn1cbiJdfQ==