@workflow/world-local 4.2.0 → 4.2.1

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.
@@ -1,16 +1,52 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { EntityConflictError, HookNotFoundError, RunExpiredError, RunNotSupportedError, TooEarlyError, WorkflowWorldError, } from '@workflow/errors';
4
- import { EventSchema, HookSchema, isLegacySpecVersion, requiresNewerWorld, SPEC_VERSION_CURRENT, StepSchema, validateUlidTimestamp, WaitSchema, WorkflowRunSchema, } from '@workflow/world';
4
+ import { EventSchema, HookSchema, isLegacySpecVersion, isTerminalStepStatus, isTerminalWorkflowRunStatus, requiresNewerWorld, SPEC_VERSION_CURRENT, StepSchema, ulidToDate, validateUlidTimestamp, WaitSchema, WorkflowRunSchema, } from '@workflow/world';
5
5
  import { z } from 'zod';
6
6
  import { DEFAULT_RESOLVE_DATA_OPTION } from '../config.js';
7
7
  import { assertSafeEntityId, deleteJSON, jsonReplacer, listJSONFiles, paginatedFileSystemQuery, readJSON, readJSONWithFallback, resolveWithinBase, taggedPath, writeExclusive, writeJSON, } from '../fs.js';
8
8
  import { stripEventDataRefs } from './filters.js';
9
- import { getObjectCreatedAt, hashToken, monotonicUlid } from './helpers.js';
10
- import { deleteAllHooksForRun } from './hooks-storage.js';
9
+ import { getObjectCreatedAt, hashToken, hookRecoveryMarkerPath, monotonicUlid, } from './helpers.js';
10
+ import { deleteAllHooksForRun, rebuildLiveHookByTokenFromEventLog, } from './hooks-storage.js';
11
11
  import { handleLegacyEvent } from './legacy.js';
12
12
  const HookTokenClaimSchema = z.object({
13
+ // The token-claim writer below has always persisted `hookId`, but
14
+ // this read schema previously omitted it, which is the bug fixed
15
+ // by https://github.com/vercel/workflow/issues/2283. `optional()`
16
+ // is defensive: any claim file that somehow lacks the field still
17
+ // parses (yielding `undefined`) and falls through to the cross-
18
+ // hook conflict branch, matching pre-fix behavior.
19
+ hookId: z.string().optional(),
13
20
  runId: z.string(),
21
+ // `eventId` is the canonical hook_created event ID the claiming
22
+ // worker committed to publishing. Persisting it here turns the
23
+ // claim file into a durable convergence key for cross-worker /
24
+ // cross-process retries (see comment on the hook_created branch).
25
+ // `optional()` for backward compatibility: a legacy claim file
26
+ // written before this field existed falls through to the recovery-
27
+ // marker upgrade path, which atomically pins a canonical eventId
28
+ // via a sidecar marker (also a `writeExclusive`).
29
+ eventId: z.string().optional(),
30
+ });
31
+ /**
32
+ * Sidecar recovery marker that pins a canonical `hook_created`
33
+ * eventId for a legacy token claim — one written by a version of
34
+ * this storage that did not yet persist `eventId` inline in the
35
+ * claim file. Without this marker, two cross-process retries
36
+ * reading a legacy claim each generate their own eventId, land
37
+ * their `writeExclusive(eventPath)` calls at different paths, and
38
+ * append two `hook_created` events for the same `(runId, hookId)`.
39
+ *
40
+ * The marker is written via `writeExclusive` — the first retry to
41
+ * land it pins its candidate eventId as canonical, and every
42
+ * subsequent retry reads and adopts that eventId before the common
43
+ * event publish. Schema is just `{ eventId }` because identity is
44
+ * already encoded in the marker's filename hash, so different token
45
+ * lifetimes can never share one marker (see
46
+ * `hookRecoveryMarkerPath`).
47
+ */
48
+ const HookRecoveryMarkerSchema = z.object({
49
+ eventId: z.string(),
14
50
  });
15
51
  async function readHookTokenClaim(constraintPath) {
16
52
  try {
@@ -23,6 +59,156 @@ async function readHookTokenClaim(constraintPath) {
23
59
  throw error;
24
60
  }
25
61
  }
62
+ async function readHookRecoveryMarker(markerPath) {
63
+ try {
64
+ return await readJSON(markerPath, HookRecoveryMarkerSchema);
65
+ }
66
+ catch (error) {
67
+ if (error instanceof SyntaxError || error instanceof z.ZodError) {
68
+ return null;
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+ /**
74
+ * Probe the run's event log for an existing `hook_created` event
75
+ * with the given correlationId. Used by the legacy-claim recovery
76
+ * path to detect "already published by a pre-upgrade write" before
77
+ * pinning a canonical eventId — without this check, a post-upgrade
78
+ * retry encountering a legacy claim whose `hook_created` was
79
+ * already written (with the pre-upgrade writer's own eventId) would
80
+ * pin a *different* eventId via the marker and publish a duplicate
81
+ * event at the marker's path.
82
+ *
83
+ * The inline-`eventId` fast path does NOT need this probe: the
84
+ * canonical eventId is durable in the claim file, so the existing
85
+ * publish (`writeExclusive(eventPath)`) will fail iff the event
86
+ * already exists at that exact path — which is the correct
87
+ * "already-published" semantic.
88
+ */
89
+ async function findExistingHookCreatedEventId(basedir, runId, correlationId) {
90
+ const result = await paginatedFileSystemQuery({
91
+ directory: path.join(basedir, 'events'),
92
+ schema: EventSchema,
93
+ filePrefix: `${runId}-`,
94
+ filter: (event) => event.eventType === 'hook_created' &&
95
+ event.correlationId === correlationId,
96
+ limit: 1,
97
+ getCreatedAt: getObjectCreatedAt('evnt'),
98
+ getId: (event) => event.eventId,
99
+ });
100
+ return result.data[0]?.eventId ?? null;
101
+ }
102
+ /**
103
+ * Repair an "event-first orphan": the hook entity write is deferred
104
+ * until after the `hook_created` event publish commits (so a failed
105
+ * publish cannot mutate already-committed state — see the comment on
106
+ * the deferred write), which opens the inverse crash window — a
107
+ * crash AFTER the event publish but BEFORE the deferred entity write
108
+ * leaves the event in the log with the hook entity missing. A retry
109
+ * then collides at the event publish and throws
110
+ * `EntityConflictError` (correct — the event IS committed), but
111
+ * without this repair the entity would stay missing forever and the
112
+ * hook would be unresolvable.
113
+ *
114
+ * The entity MUST be reconstructed from the persisted canonical
115
+ * event's payload — NOT the retry's `eventData` — otherwise a retry
116
+ * carrying different `metadata` / `isWebhook` would silently change
117
+ * committed state. The write uses `writeExclusive` (create-if-absent)
118
+ * so a concurrent writer racing this repair cannot be overwritten;
119
+ * whichever write lands first, the content is identical because both
120
+ * derive from the same persisted event.
121
+ */
122
+ async function repairHookEntityFromPersistedEvent(basedir, runId, hookId, persistedEventId, tag) {
123
+ const compositeKey = `${runId}-${persistedEventId}`;
124
+ const persistedEvent = await readJSONWithFallback(basedir, 'events', compositeKey, EventSchema, tag);
125
+ if (!persistedEvent ||
126
+ persistedEvent.eventType !== 'hook_created' ||
127
+ persistedEvent.correlationId !== hookId) {
128
+ // Nothing trustworthy to repair from.
129
+ return;
130
+ }
131
+ const existingHook = await readJSONWithFallback(basedir, 'hooks', hookId, HookSchema, tag);
132
+ if (existingHook) {
133
+ // Entity already present — not an orphan, leave it untouched.
134
+ return;
135
+ }
136
+ const eventData = (persistedEvent.eventData ?? {});
137
+ if (typeof eventData.token !== 'string') {
138
+ return;
139
+ }
140
+ const hook = {
141
+ runId,
142
+ hookId,
143
+ token: eventData.token,
144
+ metadata: eventData.metadata,
145
+ ownerId: 'local-owner',
146
+ projectId: 'local-project',
147
+ environment: 'local',
148
+ createdAt: persistedEvent.createdAt,
149
+ specVersion: persistedEvent.specVersion,
150
+ isWebhook: eventData.isWebhook ?? true,
151
+ };
152
+ await writeExclusive(taggedPath(basedir, 'hooks', hookId, tag), JSON.stringify(hook, jsonReplacer, 2));
153
+ }
154
+ /**
155
+ * Atomically pin a canonical `hook_created` eventId for a legacy
156
+ * claim (one without an inline `eventId`). The first retry to
157
+ * `writeExclusive` the recovery marker wins; its `candidateEventId`
158
+ * becomes canonical. Subsequent retries read the marker and adopt
159
+ * its `eventId`. Together with the `writeExclusive(eventPath)` in
160
+ * the outer event publish, this gives the legacy-fallback path the
161
+ * same single-event convergence guarantee as the inline-`eventId`
162
+ * fast path.
163
+ *
164
+ * Returns the canonical eventId for the caller to adopt, or `null`
165
+ * if we lost the marker race AND the resulting marker file is
166
+ * unreadable (extremely rare; corrupted disk). Callers treat `null`
167
+ * as "give up, throw `EntityConflictError`" so the runtime's
168
+ * concurrent-replay catch path swallows this attempt and lets
169
+ * another one through.
170
+ */
171
+ async function pinCanonicalEventIdForLegacyClaim(basedir, token, runId, hookId, candidateEventId) {
172
+ const markerPath = hookRecoveryMarkerPath(basedir, token, runId, hookId);
173
+ const markerContent = JSON.stringify({ eventId: candidateEventId });
174
+ const won = await writeExclusive(markerPath, markerContent);
175
+ if (won) {
176
+ return candidateEventId;
177
+ }
178
+ const existing = await readHookRecoveryMarker(markerPath);
179
+ return existing?.eventId ?? null;
180
+ }
181
+ /**
182
+ * In-process per-key async mutex backed by a caller-supplied `Map`.
183
+ * Used by `createEventsStorage` to serialize same-key event writes
184
+ * (`step_*` for the same step, `hook_created` for the same hook).
185
+ * The map is instantiated per-storage-instance — different
186
+ * instances do NOT share locks, so two instances sharing one data
187
+ * directory behave exactly like two separate OS processes from the
188
+ * locking standpoint. Cross-instance / cross-process arbitration
189
+ * relies on the on-disk constraint / claim files instead.
190
+ */
191
+ function withInProcessLock(locks, key, fn) {
192
+ const prev = locks.get(key);
193
+ const taskBox = {};
194
+ const task = (async () => {
195
+ if (prev) {
196
+ // Wait for the previous task to settle; don't inherit its errors.
197
+ await prev.catch(() => undefined);
198
+ }
199
+ try {
200
+ return await fn();
201
+ }
202
+ finally {
203
+ if (locks.get(key) === taskBox.task) {
204
+ locks.delete(key);
205
+ }
206
+ }
207
+ })();
208
+ taskBox.task = task;
209
+ locks.set(key, task);
210
+ return task;
211
+ }
26
212
  /**
27
213
  * Helper function to delete all waits associated with a workflow run.
28
214
  * Called when a run reaches a terminal state.
@@ -44,10 +230,21 @@ async function deleteAllWaitsForRun(basedir, runId) {
44
230
  * Implements the Storage['events'] interface with create, list, and listByCorrelationId operations.
45
231
  */
46
232
  export function createEventsStorage(basedir, tag) {
233
+ // Per-instance in-process mutex. Two storage instances sharing
234
+ // one data directory get independent lock maps, which makes them
235
+ // behave like two separate OS processes from the locking
236
+ // standpoint — cross-instance arbitration relies on the on-disk
237
+ // `writeExclusive` constraint / claim files instead. Tests use
238
+ // this to exercise cross-process convergence without spawning
239
+ // subprocesses.
240
+ //
241
+ // `hookLocks` serializes `hook_created` calls for the same
242
+ // (runId, correlationId) so the "claim token, then write hook
243
+ // entity + event" sequence runs to completion before another
244
+ // in-process invocation enters the dedup branch.
245
+ const hookLocks = new Map();
47
246
  return {
48
247
  async create(runId, data, params) {
49
- const eventId = `evnt_${monotonicUlid()}`;
50
- const now = new Date();
51
248
  // Validate request-supplied IDs before they're concatenated into
52
249
  // filesystem paths. This is the primary defense against path traversal
53
250
  // attacks where a client supplies runId / correlationId values like
@@ -64,663 +261,899 @@ export function createEventsStorage(basedir, tag) {
64
261
  if ('correlationId' in data && typeof data.correlationId === 'string') {
65
262
  assertSafeEntityId('correlationId', data.correlationId);
66
263
  }
67
- // For run_created events, use client-provided runId or generate one server-side
68
- let effectiveRunId;
69
- if (data.eventType === 'run_created' && (!runId || runId === '')) {
70
- effectiveRunId = `wrun_${monotonicUlid()}`;
71
- }
72
- else if (!runId) {
73
- throw new Error('runId is required for non-run_created events');
264
+ // `hook_created` is serialized per-(runId, hookId) so the
265
+ // "claim token, write hook entity, write event" sequence runs to
266
+ // completion before another in-process invocation enters the
267
+ // same-hook dedup branch. Without this, two same-tick concurrent
268
+ // callers can race between the winner's `writeExclusive(claim)`
269
+ // and `writeJSON(hook)`, making the second caller momentarily
270
+ // observe a claim with no matching hook entity — which the
271
+ // crash-recovery path below would misinterpret as a prior crash
272
+ // and incorrectly fall through to a second hook entity write.
273
+ if (data.eventType === 'hook_created' && runId && data.correlationId) {
274
+ const lockKey = tag
275
+ ? `${runId}-${data.correlationId}.hook.${tag}`
276
+ : `${runId}-${data.correlationId}.hook`;
277
+ return withInProcessLock(hookLocks, lockKey, () => createImpl());
74
278
  }
75
- else {
76
- effectiveRunId = runId;
77
- }
78
- // Validate client-provided runId timestamp is within acceptable threshold
79
- if (data.eventType === 'run_created' && runId && runId !== '') {
80
- const validationError = validateUlidTimestamp(effectiveRunId, 'wrun_');
81
- if (validationError) {
82
- throw new WorkflowWorldError(validationError);
279
+ return createImpl();
280
+ async function createImpl() {
281
+ // Most paths use the freshly-generated candidate eventId. The
282
+ // hook_created dedup-recovery path below may reassign it to
283
+ // the canonical eventId persisted in the durable token claim
284
+ // so concurrent / cross-process workers converge on a single
285
+ // event in the log.
286
+ let eventId = `evnt_${monotonicUlid()}`;
287
+ const now = new Date();
288
+ // For run_created events, use client-provided runId or generate one server-side
289
+ let effectiveRunId;
290
+ if (data.eventType === 'run_created' && (!runId || runId === '')) {
291
+ effectiveRunId = `wrun_${monotonicUlid()}`;
83
292
  }
84
- }
85
- // specVersion is always sent by the runtime, but we provide a fallback for safety
86
- const effectiveSpecVersion = data.specVersion ?? SPEC_VERSION_CURRENT;
87
- // Helper to check if run is in terminal state
88
- const isRunTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
89
- // Helper to check if step is in terminal state
90
- const isStepTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
91
- // Get current run state for validation (if not creating a new run)
92
- // Skip run validation for step_completed and step_retrying - they only operate
93
- // on running steps, and running steps are always allowed to modify regardless
94
- // of run state. This optimization saves filesystem reads per step event.
95
- let currentRun = null;
96
- const skipRunValidationEvents = ['step_completed', 'step_retrying'];
97
- if (data.eventType !== 'run_created' &&
98
- !skipRunValidationEvents.includes(data.eventType)) {
99
- currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
100
- // Resilient start: run_started on non-existent run with eventData
101
- // creates the run first, so the queue can bootstrap a run that
102
- // failed to create during start().
103
- if (data.eventType === 'run_started' &&
104
- !currentRun &&
105
- 'eventData' in data &&
106
- data.eventData) {
107
- const runInputData = data.eventData;
108
- if (runInputData.deploymentId &&
109
- runInputData.workflowName &&
110
- runInputData.input !== undefined) {
111
- // Atomically try to publish the run entity so only the first
112
- // writer wins, preventing a TOCTOU race where a concurrent
113
- // run_created from start() could overwrite a run that was
114
- // already transitioned to 'running'.
115
- const createdRun = {
116
- runId: effectiveRunId,
117
- deploymentId: runInputData.deploymentId,
118
- status: 'pending',
119
- workflowName: runInputData.workflowName,
120
- specVersion: effectiveSpecVersion,
121
- executionContext: runInputData.executionContext,
122
- input: runInputData.input,
123
- output: undefined,
124
- error: undefined,
125
- startedAt: undefined,
126
- completedAt: undefined,
127
- createdAt: now,
128
- updatedAt: now,
129
- };
130
- const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
131
- const created = await writeExclusive(runPath, JSON.stringify(createdRun, jsonReplacer));
132
- if (created) {
133
- // We created the run — also write the run_created event.
134
- const runCreatedEventId = `evnt_${monotonicUlid()}`;
135
- const runCreatedEvent = {
136
- eventType: 'run_created',
293
+ else if (!runId) {
294
+ throw new Error('runId is required for non-run_created events');
295
+ }
296
+ else {
297
+ effectiveRunId = runId;
298
+ }
299
+ // Validate client-provided runId timestamp is within acceptable threshold
300
+ if (data.eventType === 'run_created' && runId && runId !== '') {
301
+ const validationError = validateUlidTimestamp(effectiveRunId, 'wrun_');
302
+ if (validationError) {
303
+ throw new WorkflowWorldError(validationError);
304
+ }
305
+ }
306
+ // specVersion is always sent by the runtime, but we provide a fallback for safety
307
+ const effectiveSpecVersion = data.specVersion ?? SPEC_VERSION_CURRENT;
308
+ // Get current run state for validation (if not creating a new run)
309
+ // Skip run validation for step_completed and step_retrying - they only operate
310
+ // on running steps, and running steps are always allowed to modify regardless
311
+ // of run state. This optimization saves filesystem reads per step event.
312
+ let currentRun = null;
313
+ const skipRunValidationEvents = ['step_completed', 'step_retrying'];
314
+ if (data.eventType !== 'run_created' &&
315
+ !skipRunValidationEvents.includes(data.eventType)) {
316
+ currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
317
+ // Resilient start: run_started on non-existent run with eventData
318
+ // creates the run first, so the queue can bootstrap a run that
319
+ // failed to create during start().
320
+ if (data.eventType === 'run_started' &&
321
+ !currentRun &&
322
+ 'eventData' in data &&
323
+ data.eventData) {
324
+ const runInputData = data.eventData;
325
+ if (runInputData.deploymentId &&
326
+ runInputData.workflowName &&
327
+ runInputData.input !== undefined) {
328
+ // Atomically try to publish the run entity so only the first
329
+ // writer wins, preventing a TOCTOU race where a concurrent
330
+ // run_created from start() could overwrite a run that was
331
+ // already transitioned to 'running'.
332
+ const createdRun = {
137
333
  runId: effectiveRunId,
138
- eventId: runCreatedEventId,
139
- createdAt: now,
334
+ deploymentId: runInputData.deploymentId,
335
+ status: 'pending',
336
+ workflowName: runInputData.workflowName,
140
337
  specVersion: effectiveSpecVersion,
141
- eventData: {
142
- deploymentId: runInputData.deploymentId,
143
- workflowName: runInputData.workflowName,
144
- input: runInputData.input,
145
- executionContext: runInputData.executionContext,
146
- },
338
+ executionContext: runInputData.executionContext,
339
+ input: runInputData.input,
340
+ output: undefined,
341
+ error: undefined,
342
+ startedAt: undefined,
343
+ completedAt: undefined,
344
+ createdAt: now,
345
+ updatedAt: now,
147
346
  };
148
- const createdCompositeKey = `${effectiveRunId}-${runCreatedEventId}`;
149
- await writeJSON(taggedPath(basedir, 'events', createdCompositeKey, tag), runCreatedEvent);
150
- currentRun = createdRun;
151
- }
152
- else {
153
- // Run already exists (concurrent run_created won the
154
- // race). Re-read it so downstream logic sees the real state.
155
- currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
347
+ const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
348
+ const created = await writeExclusive(runPath, JSON.stringify(createdRun, jsonReplacer));
349
+ if (created) {
350
+ // We created the run — also write the run_created event.
351
+ const runCreatedEventId = `evnt_${monotonicUlid()}`;
352
+ const runCreatedEvent = {
353
+ eventType: 'run_created',
354
+ runId: effectiveRunId,
355
+ eventId: runCreatedEventId,
356
+ createdAt: now,
357
+ specVersion: effectiveSpecVersion,
358
+ eventData: {
359
+ deploymentId: runInputData.deploymentId,
360
+ workflowName: runInputData.workflowName,
361
+ input: runInputData.input,
362
+ executionContext: runInputData.executionContext,
363
+ },
364
+ };
365
+ const createdCompositeKey = `${effectiveRunId}-${runCreatedEventId}`;
366
+ await writeJSON(taggedPath(basedir, 'events', createdCompositeKey, tag), runCreatedEvent);
367
+ currentRun = createdRun;
368
+ }
369
+ else {
370
+ // Run already exists (concurrent run_created won the
371
+ // race). Re-read it so downstream logic sees the real state.
372
+ currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
373
+ }
156
374
  }
157
375
  }
158
376
  }
159
- }
160
- // ============================================================
161
- // VERSION COMPATIBILITY: Check run spec version
162
- // ============================================================
163
- // For events that have fetched the run, check version compatibility.
164
- // Skip for run_created (no existing run) and runtime events (step_completed, step_retrying).
165
- if (currentRun) {
166
- // Check if run requires a newer world version
167
- if (requiresNewerWorld(currentRun.specVersion)) {
168
- throw new RunNotSupportedError(currentRun.specVersion, SPEC_VERSION_CURRENT);
377
+ // ============================================================
378
+ // VERSION COMPATIBILITY: Check run spec version
379
+ // ============================================================
380
+ // For events that have fetched the run, check version compatibility.
381
+ // Skip for run_created (no existing run) and runtime events (step_completed, step_retrying).
382
+ if (currentRun) {
383
+ // Check if run requires a newer world version
384
+ if (requiresNewerWorld(currentRun.specVersion)) {
385
+ throw new RunNotSupportedError(currentRun.specVersion, SPEC_VERSION_CURRENT);
386
+ }
387
+ // Route to legacy handler for pre-event-sourcing runs
388
+ if (isLegacySpecVersion(currentRun.specVersion)) {
389
+ return handleLegacyEvent(basedir, effectiveRunId, data, currentRun, params);
390
+ }
169
391
  }
170
- // Route to legacy handler for pre-event-sourcing runs
171
- if (isLegacySpecVersion(currentRun.specVersion)) {
172
- return handleLegacyEvent(basedir, effectiveRunId, data, currentRun, params);
392
+ // ============================================================
393
+ // VALIDATION: Terminal state and event ordering checks
394
+ // ============================================================
395
+ // Run terminal state validation
396
+ if (currentRun && isTerminalWorkflowRunStatus(currentRun.status)) {
397
+ const runTerminalEvents = [
398
+ 'run_started',
399
+ 'run_completed',
400
+ 'run_failed',
401
+ ];
402
+ // Idempotent operation: run_cancelled on already cancelled run is allowed
403
+ if (data.eventType === 'run_cancelled' &&
404
+ currentRun.status === 'cancelled') {
405
+ // Return existing state (idempotent)
406
+ const event = {
407
+ ...data,
408
+ runId: effectiveRunId,
409
+ eventId,
410
+ createdAt: now,
411
+ specVersion: effectiveSpecVersion,
412
+ };
413
+ const compositeKey = `${effectiveRunId}-${eventId}`;
414
+ await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), event);
415
+ const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
416
+ return {
417
+ event: stripEventDataRefs(event, resolveData),
418
+ run: currentRun,
419
+ };
420
+ }
421
+ // For run_started on terminal runs, use RunExpiredError so the
422
+ // runtime knows to exit without retrying.
423
+ if (data.eventType === 'run_started') {
424
+ throw new RunExpiredError(`Workflow run "${effectiveRunId}" is already in terminal state "${currentRun.status}"`);
425
+ }
426
+ // Other run state transitions are not allowed on terminal runs
427
+ if (runTerminalEvents.includes(data.eventType) ||
428
+ data.eventType === 'run_cancelled') {
429
+ throw new EntityConflictError(`Cannot transition run from terminal state "${currentRun.status}"`);
430
+ }
431
+ // Creating new entities on terminal runs is not allowed
432
+ if (data.eventType === 'step_created' ||
433
+ data.eventType === 'hook_created' ||
434
+ data.eventType === 'wait_created') {
435
+ throw new EntityConflictError(`Cannot create new entities on run in terminal state "${currentRun.status}"`);
436
+ }
173
437
  }
174
- }
175
- // ============================================================
176
- // VALIDATION: Terminal state and event ordering checks
177
- // ============================================================
178
- // Run terminal state validation
179
- if (currentRun && isRunTerminal(currentRun.status)) {
180
- const runTerminalEvents = [
181
- 'run_started',
182
- 'run_completed',
183
- 'run_failed',
438
+ // Step-related event validation (ordering and terminal state)
439
+ // Store existingStep so we can reuse it later (avoid double read)
440
+ let validatedStep = null;
441
+ const stepEvents = [
442
+ 'step_started',
443
+ 'step_completed',
444
+ 'step_failed',
445
+ 'step_retrying',
184
446
  ];
185
- // Idempotent operation: run_cancelled on already cancelled run is allowed
186
- if (data.eventType === 'run_cancelled' &&
187
- currentRun.status === 'cancelled') {
188
- // Return existing state (idempotent)
189
- const event = {
190
- ...data,
191
- runId: effectiveRunId,
192
- eventId,
193
- createdAt: now,
194
- specVersion: effectiveSpecVersion,
195
- };
196
- const compositeKey = `${effectiveRunId}-${eventId}`;
197
- await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), event);
198
- const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
199
- return {
200
- event: stripEventDataRefs(event, resolveData),
201
- run: currentRun,
202
- };
203
- }
204
- // For run_started on terminal runs, use RunExpiredError so the
205
- // runtime knows to exit without retrying.
206
- if (data.eventType === 'run_started') {
207
- throw new RunExpiredError(`Workflow run "${effectiveRunId}" is already in terminal state "${currentRun.status}"`);
208
- }
209
- // Other run state transitions are not allowed on terminal runs
210
- if (runTerminalEvents.includes(data.eventType) ||
211
- data.eventType === 'run_cancelled') {
212
- throw new EntityConflictError(`Cannot transition run from terminal state "${currentRun.status}"`);
213
- }
214
- // Creating new entities on terminal runs is not allowed
215
- if (data.eventType === 'step_created' ||
216
- data.eventType === 'hook_created' ||
217
- data.eventType === 'wait_created') {
218
- throw new EntityConflictError(`Cannot create new entities on run in terminal state "${currentRun.status}"`);
219
- }
220
- }
221
- // Step-related event validation (ordering and terminal state)
222
- // Store existingStep so we can reuse it later (avoid double read)
223
- let validatedStep = null;
224
- const stepEvents = [
225
- 'step_started',
226
- 'step_completed',
227
- 'step_failed',
228
- 'step_retrying',
229
- ];
230
- if (stepEvents.includes(data.eventType) && data.correlationId) {
231
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
232
- validatedStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
233
- // Event ordering: step must exist before these events
234
- if (!validatedStep) {
235
- throw new WorkflowWorldError(`Step "${data.correlationId}" not found`);
236
- }
237
- // Step terminal state validation
238
- if (isStepTerminal(validatedStep.status)) {
239
- throw new EntityConflictError(`Cannot modify step in terminal state "${validatedStep.status}"`);
240
- }
241
- // On terminal runs: only allow completing/failing in-progress steps
242
- if (currentRun && isRunTerminal(currentRun.status)) {
243
- if (validatedStep.status !== 'running') {
244
- throw new RunExpiredError(`Cannot modify non-running step on run in terminal state "${currentRun.status}"`);
447
+ if (stepEvents.includes(data.eventType) && data.correlationId) {
448
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
449
+ validatedStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
450
+ // Event ordering: step must exist before these events
451
+ if (!validatedStep) {
452
+ throw new WorkflowWorldError(`Step "${data.correlationId}" not found`);
453
+ }
454
+ // Step terminal state validation
455
+ if (isTerminalStepStatus(validatedStep.status)) {
456
+ throw new EntityConflictError(`Cannot modify step in terminal state "${validatedStep.status}"`);
457
+ }
458
+ // On terminal runs: only allow completing/failing in-progress steps
459
+ if (currentRun && isTerminalWorkflowRunStatus(currentRun.status)) {
460
+ if (validatedStep.status !== 'running') {
461
+ throw new RunExpiredError(`Cannot modify non-running step on run in terminal state "${currentRun.status}"`);
462
+ }
245
463
  }
246
464
  }
247
- }
248
- // Hook-related event validation (ordering)
249
- const hookEventsRequiringExistence = ['hook_disposed', 'hook_received'];
250
- if (hookEventsRequiringExistence.includes(data.eventType) &&
251
- data.correlationId) {
252
- const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
253
- if (!existingHook) {
254
- throw new HookNotFoundError(data.correlationId);
465
+ // Hook-related event validation (ordering)
466
+ const hookEventsRequiringExistence = ['hook_disposed', 'hook_received'];
467
+ if (hookEventsRequiringExistence.includes(data.eventType) &&
468
+ data.correlationId) {
469
+ const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
470
+ if (!existingHook) {
471
+ throw new HookNotFoundError(data.correlationId);
472
+ }
255
473
  }
256
- }
257
- const event = {
258
- ...data,
259
- runId: effectiveRunId,
260
- eventId,
261
- createdAt: now,
262
- specVersion: effectiveSpecVersion,
263
- };
264
- // Strip eventData from run_started — it belongs on run_created only.
265
- if (data.eventType === 'run_started' && 'eventData' in event) {
266
- delete event.eventData;
267
- }
268
- // Track entity created/updated for EventResult
269
- let run;
270
- let step;
271
- let hook;
272
- let wait;
273
- // Create/update entity based on event type (event-sourced architecture)
274
- // Run lifecycle events
275
- if (data.eventType === 'run_created' && 'eventData' in data) {
276
- const runData = data.eventData;
277
- run = {
474
+ // `event` may be reassigned later in the `hook_created`
475
+ // dedup-recovery branch to swap in a canonical eventId /
476
+ // createdAt persisted in the durable token claim so
477
+ // concurrent / cross-process workers converge on a single
478
+ // event in the log.
479
+ let event = {
480
+ ...data,
278
481
  runId: effectiveRunId,
279
- deploymentId: runData.deploymentId,
280
- status: 'pending',
281
- workflowName: runData.workflowName,
282
- // Propagate specVersion from the event to the run entity
283
- specVersion: effectiveSpecVersion,
284
- executionContext: runData.executionContext,
285
- input: runData.input,
286
- output: undefined,
287
- error: undefined,
288
- startedAt: undefined,
289
- completedAt: undefined,
482
+ eventId,
290
483
  createdAt: now,
291
- updatedAt: now,
484
+ specVersion: effectiveSpecVersion,
292
485
  };
293
- // Atomically publish the run entity file without overwriting an
294
- // existing winner. This prevents a TOCTOU race with the resilient
295
- // start path (run_started on non-existent run) that could result in
296
- // duplicate run_created events in the event log.
297
- const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
298
- const created = await writeExclusive(runPath, JSON.stringify(run, jsonReplacer, 2));
299
- if (!created) {
300
- throw new EntityConflictError(`Workflow run "${effectiveRunId}" already exists`);
486
+ // Strip eventData from run_started it belongs on run_created only.
487
+ if (data.eventType === 'run_started' && 'eventData' in event) {
488
+ delete event.eventData;
301
489
  }
302
- }
303
- else if (data.eventType === 'run_started') {
304
- // Reuse currentRun from validation (already read above)
305
- if (currentRun) {
306
- // If already running, return the run without inserting a
307
- // duplicate event. This makes run_started idempotent for
308
- // concurrent invocations. We omit preloaded events here
309
- // because this is a rare race-condition path the runtime
310
- // falls back to loading events separately.
311
- if (currentRun.status === 'running') {
312
- return { run: currentRun };
313
- }
490
+ // Track entity created/updated for EventResult
491
+ let run;
492
+ let step;
493
+ let hook;
494
+ let wait;
495
+ // For `hook_created`, the hook entity write is deferred until
496
+ // AFTER the outer event publish succeeds, so a retry that
497
+ // collides with an already-published `hook_created` does not
498
+ // mutate the durable hook entity with the retry's payload.
499
+ // `hookEntityWriteOptions` carries the `{ overwrite }` mode
500
+ // chosen by the dedup-recovery branch above (undefined for
501
+ // first writers, `{ overwrite: true }` for retries that may
502
+ // be repairing an orphaned partial write).
503
+ let hookEntityWriteOptions;
504
+ // Create/update entity based on event type (event-sourced architecture)
505
+ // Run lifecycle events
506
+ if (data.eventType === 'run_created' && 'eventData' in data) {
507
+ const runData = data.eventData;
314
508
  run = {
315
- runId: currentRun.runId,
316
- deploymentId: currentRun.deploymentId,
317
- workflowName: currentRun.workflowName,
318
- specVersion: currentRun.specVersion,
319
- executionContext: currentRun.executionContext,
320
- input: currentRun.input,
321
- createdAt: currentRun.createdAt,
322
- expiredAt: currentRun.expiredAt,
323
- status: 'running',
509
+ runId: effectiveRunId,
510
+ deploymentId: runData.deploymentId,
511
+ status: 'pending',
512
+ workflowName: runData.workflowName,
513
+ // Propagate specVersion from the event to the run entity
514
+ specVersion: effectiveSpecVersion,
515
+ executionContext: runData.executionContext,
516
+ input: runData.input,
324
517
  output: undefined,
325
518
  error: undefined,
519
+ startedAt: undefined,
326
520
  completedAt: undefined,
327
- startedAt: currentRun.startedAt ?? now,
521
+ createdAt: now,
328
522
  updatedAt: now,
329
523
  };
330
- await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
524
+ // Atomically publish the run entity file without overwriting an
525
+ // existing winner. This prevents a TOCTOU race with the resilient
526
+ // start path (run_started on non-existent run) that could result in
527
+ // duplicate run_created events in the event log.
528
+ const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
529
+ const created = await writeExclusive(runPath, JSON.stringify(run, jsonReplacer, 2));
530
+ if (!created) {
531
+ throw new EntityConflictError(`Workflow run "${effectiveRunId}" already exists`);
532
+ }
331
533
  }
332
- }
333
- else if (data.eventType === 'run_completed' && 'eventData' in data) {
334
- const completedData = data.eventData;
335
- // Reuse currentRun from validation (already read above)
336
- if (currentRun) {
337
- run = {
338
- runId: currentRun.runId,
339
- deploymentId: currentRun.deploymentId,
340
- workflowName: currentRun.workflowName,
341
- specVersion: currentRun.specVersion,
342
- executionContext: currentRun.executionContext,
343
- input: currentRun.input,
344
- createdAt: currentRun.createdAt,
345
- expiredAt: currentRun.expiredAt,
346
- startedAt: currentRun.startedAt,
347
- status: 'completed',
348
- output: completedData.output,
534
+ else if (data.eventType === 'run_started') {
535
+ // Reuse currentRun from validation (already read above)
536
+ if (currentRun) {
537
+ // If already running, return the run without inserting a
538
+ // duplicate event. This makes run_started idempotent for
539
+ // concurrent invocations. We omit preloaded events here
540
+ // because this is a rare race-condition path — the runtime
541
+ // falls back to loading events separately.
542
+ if (currentRun.status === 'running') {
543
+ return { run: currentRun };
544
+ }
545
+ run = {
546
+ runId: currentRun.runId,
547
+ deploymentId: currentRun.deploymentId,
548
+ workflowName: currentRun.workflowName,
549
+ specVersion: currentRun.specVersion,
550
+ executionContext: currentRun.executionContext,
551
+ input: currentRun.input,
552
+ createdAt: currentRun.createdAt,
553
+ expiredAt: currentRun.expiredAt,
554
+ status: 'running',
555
+ output: undefined,
556
+ error: undefined,
557
+ completedAt: undefined,
558
+ startedAt: currentRun.startedAt ?? now,
559
+ updatedAt: now,
560
+ };
561
+ await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
562
+ }
563
+ }
564
+ else if (data.eventType === 'run_completed' && 'eventData' in data) {
565
+ const completedData = data.eventData;
566
+ // Reuse currentRun from validation (already read above)
567
+ if (currentRun) {
568
+ run = {
569
+ runId: currentRun.runId,
570
+ deploymentId: currentRun.deploymentId,
571
+ workflowName: currentRun.workflowName,
572
+ specVersion: currentRun.specVersion,
573
+ executionContext: currentRun.executionContext,
574
+ input: currentRun.input,
575
+ createdAt: currentRun.createdAt,
576
+ expiredAt: currentRun.expiredAt,
577
+ startedAt: currentRun.startedAt,
578
+ status: 'completed',
579
+ output: completedData.output,
580
+ error: undefined,
581
+ completedAt: now,
582
+ updatedAt: now,
583
+ };
584
+ await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
585
+ await Promise.all([
586
+ deleteAllHooksForRun(basedir, effectiveRunId),
587
+ deleteAllWaitsForRun(basedir, effectiveRunId),
588
+ ]);
589
+ }
590
+ }
591
+ else if (data.eventType === 'run_failed' && 'eventData' in data) {
592
+ const failedData = data.eventData;
593
+ // Reuse currentRun from validation (already read above)
594
+ if (currentRun) {
595
+ run = {
596
+ runId: currentRun.runId,
597
+ deploymentId: currentRun.deploymentId,
598
+ workflowName: currentRun.workflowName,
599
+ specVersion: currentRun.specVersion,
600
+ executionContext: currentRun.executionContext,
601
+ input: currentRun.input,
602
+ createdAt: currentRun.createdAt,
603
+ expiredAt: currentRun.expiredAt,
604
+ startedAt: currentRun.startedAt,
605
+ status: 'failed',
606
+ output: undefined,
607
+ error: {
608
+ message: typeof failedData.error === 'string'
609
+ ? failedData.error
610
+ : (failedData.error?.message ?? 'Unknown error'),
611
+ stack: failedData.error?.stack,
612
+ code: failedData.errorCode,
613
+ },
614
+ completedAt: now,
615
+ updatedAt: now,
616
+ };
617
+ await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
618
+ await Promise.all([
619
+ deleteAllHooksForRun(basedir, effectiveRunId),
620
+ deleteAllWaitsForRun(basedir, effectiveRunId),
621
+ ]);
622
+ }
623
+ }
624
+ else if (data.eventType === 'run_cancelled') {
625
+ // Reuse currentRun from validation (already read above)
626
+ if (currentRun) {
627
+ run = {
628
+ runId: currentRun.runId,
629
+ deploymentId: currentRun.deploymentId,
630
+ workflowName: currentRun.workflowName,
631
+ specVersion: currentRun.specVersion,
632
+ executionContext: currentRun.executionContext,
633
+ input: currentRun.input,
634
+ createdAt: currentRun.createdAt,
635
+ expiredAt: currentRun.expiredAt,
636
+ startedAt: currentRun.startedAt,
637
+ status: 'cancelled',
638
+ output: undefined,
639
+ error: undefined,
640
+ completedAt: now,
641
+ updatedAt: now,
642
+ };
643
+ await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
644
+ await Promise.all([
645
+ deleteAllHooksForRun(basedir, effectiveRunId),
646
+ deleteAllWaitsForRun(basedir, effectiveRunId),
647
+ ]);
648
+ }
649
+ }
650
+ else if (
651
+ // Step lifecycle events
652
+ data.eventType === 'step_created' &&
653
+ 'eventData' in data) {
654
+ // step_created: Creates step entity with status 'pending', attempt=0, createdAt set
655
+ const stepData = data.eventData;
656
+ step = {
657
+ runId: effectiveRunId,
658
+ stepId: data.correlationId,
659
+ stepName: stepData.stepName,
660
+ status: 'pending',
661
+ input: stepData.input,
662
+ output: undefined,
349
663
  error: undefined,
350
- completedAt: now,
664
+ attempt: 0,
665
+ startedAt: undefined,
666
+ completedAt: undefined,
667
+ createdAt: now,
351
668
  updatedAt: now,
669
+ // Propagate specVersion from the event to the step entity
670
+ specVersion: effectiveSpecVersion,
352
671
  };
353
- await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
354
- await Promise.all([
355
- deleteAllHooksForRun(basedir, effectiveRunId),
356
- deleteAllWaitsForRun(basedir, effectiveRunId),
357
- ]);
672
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
673
+ await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step);
358
674
  }
359
- }
360
- else if (data.eventType === 'run_failed' && 'eventData' in data) {
361
- const failedData = data.eventData;
362
- // Reuse currentRun from validation (already read above)
363
- if (currentRun) {
364
- run = {
365
- runId: currentRun.runId,
366
- deploymentId: currentRun.deploymentId,
367
- workflowName: currentRun.workflowName,
368
- specVersion: currentRun.specVersion,
369
- executionContext: currentRun.executionContext,
370
- input: currentRun.input,
371
- createdAt: currentRun.createdAt,
372
- expiredAt: currentRun.expiredAt,
373
- startedAt: currentRun.startedAt,
374
- status: 'failed',
375
- output: undefined,
376
- error: {
675
+ else if (data.eventType === 'step_started') {
676
+ // step_started: Increments attempt, sets status to 'running'
677
+ // Sets startedAt only on the first start (not updated on retries)
678
+ // Reuse validatedStep from validation (already read above)
679
+ if (validatedStep) {
680
+ // Check if retryAfter timestamp hasn't been reached yet
681
+ if (validatedStep.retryAfter &&
682
+ validatedStep.retryAfter.getTime() > Date.now()) {
683
+ throw new TooEarlyError(`Cannot start step "${data.correlationId}": retryAfter timestamp has not been reached yet`, {
684
+ retryAfter: Math.ceil((validatedStep.retryAfter.getTime() - Date.now()) / 1000),
685
+ });
686
+ }
687
+ // Best-effort guard: re-read the step entity to check if it
688
+ // reached terminal state between the validation read and now.
689
+ // This narrows the TOCTOU window but does not fully eliminate it
690
+ // (the local world is single-process / dev-only; the postgres
691
+ // world uses SQL-level atomic guards for production).
692
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
693
+ const freshStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
694
+ if (freshStep && isTerminalStepStatus(freshStep.status)) {
695
+ throw new EntityConflictError(`Cannot modify step in terminal state "${freshStep.status}"`);
696
+ }
697
+ step = {
698
+ ...validatedStep,
699
+ status: 'running',
700
+ // Only set startedAt on the first start
701
+ startedAt: validatedStep.startedAt ?? now,
702
+ // Increment attempt counter on every start
703
+ attempt: validatedStep.attempt + 1,
704
+ // Clear retryAfter now that the step has started
705
+ retryAfter: undefined,
706
+ updatedAt: now,
707
+ };
708
+ await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
709
+ }
710
+ }
711
+ else if (data.eventType === 'step_completed' && 'eventData' in data) {
712
+ // step_completed: Terminal state with output
713
+ // Uses writeExclusive on a lock file to atomically prevent concurrent
714
+ // invocations from both completing the same step (TOCTOU race).
715
+ const completedData = data.eventData;
716
+ if (validatedStep) {
717
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
718
+ const lockName = tag
719
+ ? `${stepCompositeKey}.terminal.${tag}`
720
+ : `${stepCompositeKey}.terminal`;
721
+ const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
722
+ const claimed = await writeExclusive(terminalLockPath, '');
723
+ if (!claimed) {
724
+ throw new EntityConflictError('Cannot modify step in terminal state');
725
+ }
726
+ step = {
727
+ ...validatedStep,
728
+ status: 'completed',
729
+ output: completedData.result,
730
+ completedAt: now,
731
+ updatedAt: now,
732
+ };
733
+ await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
734
+ }
735
+ }
736
+ else if (data.eventType === 'step_failed' && 'eventData' in data) {
737
+ // step_failed: Terminal state with error
738
+ // Uses writeExclusive on a lock file to atomically prevent concurrent
739
+ // invocations from both failing the same step (TOCTOU race).
740
+ const failedData = data.eventData;
741
+ if (validatedStep) {
742
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
743
+ const lockName = tag
744
+ ? `${stepCompositeKey}.terminal.${tag}`
745
+ : `${stepCompositeKey}.terminal`;
746
+ const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
747
+ const claimed = await writeExclusive(terminalLockPath, '');
748
+ if (!claimed) {
749
+ throw new EntityConflictError('Cannot modify step in terminal state');
750
+ }
751
+ const error = {
377
752
  message: typeof failedData.error === 'string'
378
753
  ? failedData.error
379
754
  : (failedData.error?.message ?? 'Unknown error'),
380
- stack: failedData.error?.stack,
381
- code: failedData.errorCode,
382
- },
383
- completedAt: now,
384
- updatedAt: now,
385
- };
386
- await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
387
- await Promise.all([
388
- deleteAllHooksForRun(basedir, effectiveRunId),
389
- deleteAllWaitsForRun(basedir, effectiveRunId),
390
- ]);
755
+ stack: failedData.stack,
756
+ };
757
+ step = {
758
+ ...validatedStep,
759
+ status: 'failed',
760
+ error,
761
+ completedAt: now,
762
+ updatedAt: now,
763
+ };
764
+ await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
765
+ }
391
766
  }
392
- }
393
- else if (data.eventType === 'run_cancelled') {
394
- // Reuse currentRun from validation (already read above)
395
- if (currentRun) {
396
- run = {
397
- runId: currentRun.runId,
398
- deploymentId: currentRun.deploymentId,
399
- workflowName: currentRun.workflowName,
400
- specVersion: currentRun.specVersion,
401
- executionContext: currentRun.executionContext,
402
- input: currentRun.input,
403
- createdAt: currentRun.createdAt,
404
- expiredAt: currentRun.expiredAt,
405
- startedAt: currentRun.startedAt,
406
- status: 'cancelled',
407
- output: undefined,
408
- error: undefined,
409
- completedAt: now,
410
- updatedAt: now,
411
- };
412
- await writeJSON(taggedPath(basedir, 'runs', effectiveRunId, tag), run, { overwrite: true });
413
- await Promise.all([
414
- deleteAllHooksForRun(basedir, effectiveRunId),
415
- deleteAllWaitsForRun(basedir, effectiveRunId),
416
- ]);
767
+ else if (data.eventType === 'step_retrying' && 'eventData' in data) {
768
+ // step_retrying: Sets status back to 'pending', records error
769
+ // Reuse validatedStep from validation (already read above)
770
+ const retryData = data.eventData;
771
+ if (validatedStep) {
772
+ const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
773
+ step = {
774
+ ...validatedStep,
775
+ status: 'pending',
776
+ error: {
777
+ message: typeof retryData.error === 'string'
778
+ ? retryData.error
779
+ : (retryData.error?.message ?? 'Unknown error'),
780
+ stack: retryData.stack,
781
+ },
782
+ retryAfter: retryData.retryAfter,
783
+ updatedAt: now,
784
+ };
785
+ await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
786
+ }
417
787
  }
418
- }
419
- else if (
420
- // Step lifecycle events
421
- data.eventType === 'step_created' &&
422
- 'eventData' in data) {
423
- // step_created: Creates step entity with status 'pending', attempt=0, createdAt set
424
- const stepData = data.eventData;
425
- step = {
426
- runId: effectiveRunId,
427
- stepId: data.correlationId,
428
- stepName: stepData.stepName,
429
- status: 'pending',
430
- input: stepData.input,
431
- output: undefined,
432
- error: undefined,
433
- attempt: 0,
434
- startedAt: undefined,
435
- completedAt: undefined,
436
- createdAt: now,
437
- updatedAt: now,
438
- // Propagate specVersion from the event to the step entity
439
- specVersion: effectiveSpecVersion,
440
- };
441
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
442
- await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step);
443
- }
444
- else if (data.eventType === 'step_started') {
445
- // step_started: Increments attempt, sets status to 'running'
446
- // Sets startedAt only on the first start (not updated on retries)
447
- // Reuse validatedStep from validation (already read above)
448
- if (validatedStep) {
449
- // Check if retryAfter timestamp hasn't been reached yet
450
- if (validatedStep.retryAfter &&
451
- validatedStep.retryAfter.getTime() > Date.now()) {
452
- throw new TooEarlyError(`Cannot start step "${data.correlationId}": retryAfter timestamp has not been reached yet`, {
453
- retryAfter: Math.ceil((validatedStep.retryAfter.getTime() - Date.now()) / 1000),
454
- });
788
+ else if (
789
+ // Hook lifecycle events
790
+ data.eventType === 'hook_created' &&
791
+ 'eventData' in data) {
792
+ const hookData = data.eventData;
793
+ // Atomically claim the token using an exclusive-create constraint file.
794
+ // This avoids the TOCTOU race of the previous read-all-then-check approach.
795
+ const constraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(hookData.token)}.json`);
796
+ // When the claim is absent, the event log is the only durable source
797
+ // that can distinguish a first hook from a crash-lost token cache.
798
+ if (!(await readHookTokenClaim(constraintPath))) {
799
+ await rebuildLiveHookByTokenFromEventLog(basedir, hookData.token, tag);
455
800
  }
456
- // Best-effort guard: re-read the step entity to check if it
457
- // reached terminal state between the validation read and now.
458
- // This narrows the TOCTOU window but does not fully eliminate it
459
- // (the local world is single-process / dev-only; the postgres
460
- // world uses SQL-level atomic guards for production).
461
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
462
- const freshStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
463
- if (freshStep && isStepTerminal(freshStep.status)) {
464
- throw new EntityConflictError(`Cannot modify step in terminal state "${freshStep.status}"`);
801
+ // Persist `eventId` in the claim so concurrent / cross-
802
+ // process retries can converge on a single canonical
803
+ // `hook_created` event path. See the recovery comment
804
+ // below.
805
+ const tokenClaimed = await writeExclusive(constraintPath, JSON.stringify({
806
+ token: hookData.token,
807
+ hookId: data.correlationId,
808
+ runId: effectiveRunId,
809
+ eventId,
810
+ }));
811
+ // Recovery shape: the durable record of a successful hook
812
+ // creation is the `hook_created` event in the event log. The
813
+ // claim file and hook entity are written before the event,
814
+ // and the three writes are NOT atomic, so a crash at any
815
+ // point can leave one or two of them on disk without the
816
+ // event. Treating those as "completed" would have the
817
+ // suspension handler swallow the retry and permanently lose
818
+ // the `hook_created` event from the log.
819
+ //
820
+ // When the dedup branch fires for the same `(runId, hookId)`,
821
+ // we converge on the canonical `eventId` persisted in the
822
+ // claim file by the original (winning) `writeExclusive`. By
823
+ // adopting that eventId for this retry's event write — and
824
+ // letting the outer no-overwrite `writeJSON` for the event
825
+ // throw `EntityConflictError` on collision — concurrent /
826
+ // cross-process workers either:
827
+ // - publish the same event at the same path exactly once
828
+ // (the loser's `writeJSON` throws EntityConflictError,
829
+ // which the runtime's existing concurrent-replay catch
830
+ // path at suspension-handler.ts:142 swallows), or
831
+ // - converge on a single recovery write when the prior
832
+ // claim was orphaned by a crash before the event landed.
833
+ //
834
+ // The legacy fallback (`existingClaim.eventId` undefined)
835
+ // is for claim files written before this field was added —
836
+ // those probe the event log directly and fall through to a
837
+ // fresh-eventId recovery write. The legacy path does not
838
+ // converge across workers but cannot regress behavior for
839
+ // freshly-written claims.
840
+ //
841
+ // The `withHookLock` in-process mutex above keeps two same-
842
+ // tick in-process callers from racing into this branch with
843
+ // the winner mid-write, but is not sufficient across
844
+ // processes — the durable convergence key (`claim.eventId`)
845
+ // is what closes the cross-process race.
846
+ let writeHookEntityWithOverwrite = false;
847
+ if (!tokenClaimed) {
848
+ const existingClaim = await readHookTokenClaim(constraintPath);
849
+ if (existingClaim?.runId === effectiveRunId &&
850
+ existingClaim.hookId === data.correlationId) {
851
+ // Adopt a canonical eventId for the recovery write. The
852
+ // outer event publish (`writeExclusive(eventPath)`)
853
+ // either succeeds (we publish the canonical event,
854
+ // repairing a partial write left by the original
855
+ // claimant) or returns `false` and we throw
856
+ // `EntityConflictError` (the event was already
857
+ // published — a real duplicate). Either way the log
858
+ // ends with exactly one `hook_created` event for this
859
+ // `(runId, hookId)`.
860
+ //
861
+ // The canonical eventId comes from one of two places:
862
+ //
863
+ // - `existingClaim.eventId` for claims written by
864
+ // this version (the writer above persists the
865
+ // candidate eventId atomically with the claim).
866
+ // The eventId is durable, so the outer
867
+ // `writeExclusive(eventPath)` alone is enough to
868
+ // arbitrate publication: it fails iff the event
869
+ // was already published at that exact path.
870
+ //
871
+ // - The recovery-marker sidecar for legacy claims
872
+ // written before `eventId` was persisted inline
873
+ // in the claim. The marker is itself a
874
+ // `writeExclusive`, so the first retry pins its
875
+ // candidate eventId as canonical and subsequent
876
+ // retries adopt it. Without this, two processes
877
+ // both reading the same legacy claim would each
878
+ // generate their own eventId, land their
879
+ // `writeExclusive(eventPath)` calls at different
880
+ // paths, and append two events.
881
+ //
882
+ // For legacy claims we also must probe the event
883
+ // log for an existing `hook_created` event BEFORE
884
+ // pinning a canonical eventId: the pre-upgrade
885
+ // writer may have already published the event
886
+ // with its own eventId, and the marker has no way
887
+ // of knowing that eventId after the fact. Without
888
+ // this probe, a post-upgrade retry would pin a
889
+ // different eventId, write a hook entity, and
890
+ // publish a duplicate event at the marker's path.
891
+ let canonicalEventId;
892
+ if (existingClaim.eventId) {
893
+ canonicalEventId = existingClaim.eventId;
894
+ }
895
+ else {
896
+ const alreadyPublishedEventId = await findExistingHookCreatedEventId(basedir, effectiveRunId, data.correlationId);
897
+ if (alreadyPublishedEventId !== null) {
898
+ // The pre-upgrade writer may have crashed between
899
+ // its event publish and its hook entity write —
900
+ // repair the entity from the persisted event's
901
+ // payload before surfacing the benign duplicate.
902
+ await repairHookEntityFromPersistedEvent(basedir, effectiveRunId, data.correlationId, alreadyPublishedEventId, tag);
903
+ throw new EntityConflictError(`Hook "${data.correlationId}" already created`);
904
+ }
905
+ const pinned = await pinCanonicalEventIdForLegacyClaim(basedir, hookData.token, effectiveRunId, data.correlationId, eventId);
906
+ if (pinned === null) {
907
+ // Lost the marker race and the marker file is
908
+ // unreadable (extremely rare; corrupted disk).
909
+ // Treat as a real duplicate so the runtime's
910
+ // concurrent-replay catch path swallows this
911
+ // attempt instead of risking divergent
912
+ // publication.
913
+ throw new EntityConflictError(`Hook "${data.correlationId}" already created`);
914
+ }
915
+ canonicalEventId = pinned;
916
+ }
917
+ // Rebuild `event` with the canonical eventId and a
918
+ // deterministic `createdAt` derived from the eventId
919
+ // (a ULID) so two workers writing the same event
920
+ // produce byte-identical content.
921
+ eventId = canonicalEventId;
922
+ const canonicalCreatedAt = ulidToDate(eventId.replace(/^evnt_/, '')) ?? now;
923
+ event = {
924
+ ...data,
925
+ runId: effectiveRunId,
926
+ eventId,
927
+ createdAt: canonicalCreatedAt,
928
+ specVersion: effectiveSpecVersion,
929
+ };
930
+ writeHookEntityWithOverwrite = true;
931
+ }
932
+ else {
933
+ // Cross-hook / cross-run conflict: a different
934
+ // (runId, hookId) holds this token. Create a
935
+ // hook_conflict event so the workflow can fail
936
+ // gracefully when the hook is awaited.
937
+ const conflictEvent = {
938
+ eventType: 'hook_conflict',
939
+ correlationId: data.correlationId,
940
+ eventData: {
941
+ token: hookData.token,
942
+ ...(existingClaim
943
+ ? { conflictingRunId: existingClaim.runId }
944
+ : {}),
945
+ },
946
+ runId: effectiveRunId,
947
+ eventId,
948
+ createdAt: now,
949
+ specVersion: effectiveSpecVersion,
950
+ };
951
+ const compositeKey = `${effectiveRunId}-${eventId}`;
952
+ await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), conflictEvent);
953
+ const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
954
+ const filteredEvent = stripEventDataRefs(conflictEvent, resolveData);
955
+ // Return EventResult with conflict event (no hook entity created)
956
+ return {
957
+ event: filteredEvent,
958
+ run,
959
+ step,
960
+ hook: undefined,
961
+ };
962
+ }
465
963
  }
466
- step = {
467
- ...validatedStep,
468
- status: 'running',
469
- // Only set startedAt on the first start
470
- startedAt: validatedStep.startedAt ?? now,
471
- // Increment attempt counter on every start
472
- attempt: validatedStep.attempt + 1,
473
- // Clear retryAfter now that the step has started
474
- retryAfter: undefined,
475
- updatedAt: now,
964
+ // Compute the hook entity now, but defer its write until
965
+ // AFTER the outer event publish at the bottom of this
966
+ // function commits. The retry path can reach this branch
967
+ // for a hook whose `hook_created` event was already
968
+ // published successfully (an "already-committed
969
+ // duplicate"); in that case the outer `writeExclusive`
970
+ // for the event will return false and we will throw
971
+ // `EntityConflictError`. Writing the hook entity here
972
+ // first would mutate already-committed durable state with
973
+ // the retry's payload (e.g. different `metadata` or
974
+ // `isWebhook`) before the event publish proved which
975
+ // outcome we are in — leaving the entity and event log
976
+ // inconsistent. By deferring, the entity is only written
977
+ // when the publish actually succeeds (first writer or
978
+ // orphan recovery). See pranaygp's review on PR #2295 for
979
+ // the karthikscale3 repro.
980
+ hook = {
981
+ runId: effectiveRunId,
982
+ hookId: data.correlationId,
983
+ token: hookData.token,
984
+ metadata: hookData.metadata,
985
+ ownerId: 'local-owner',
986
+ projectId: 'local-project',
987
+ environment: 'local',
988
+ // Use the (possibly canonical) event's createdAt so two
989
+ // workers writing the same hook entity produce byte-
990
+ // identical content during convergence.
991
+ createdAt: event.createdAt,
992
+ // Propagate specVersion from the event to the hook entity
993
+ specVersion: effectiveSpecVersion,
994
+ isWebhook: hookData.isWebhook ?? false,
476
995
  };
477
- await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
996
+ hookEntityWriteOptions = writeHookEntityWithOverwrite
997
+ ? { overwrite: true }
998
+ : undefined;
478
999
  }
479
- }
480
- else if (data.eventType === 'step_completed' && 'eventData' in data) {
481
- // step_completed: Terminal state with output
482
- // Uses writeExclusive on a lock file to atomically prevent concurrent
483
- // invocations from both completing the same step (TOCTOU race).
484
- const completedData = data.eventData;
485
- if (validatedStep) {
486
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
487
- const lockName = tag
488
- ? `${stepCompositeKey}.terminal.${tag}`
489
- : `${stepCompositeKey}.terminal`;
490
- const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
491
- const claimed = await writeExclusive(terminalLockPath, '');
1000
+ else if (data.eventType === 'hook_disposed') {
1001
+ // hook_disposed: Deletes hook entity, rejects duplicates.
1002
+ // Uses writeExclusive on a lock file to atomically prevent concurrent
1003
+ // invocations from both disposing the same hook (TOCTOU race).
1004
+ const hookLockName = tag
1005
+ ? `${data.correlationId}.disposed.${tag}`
1006
+ : `${data.correlationId}.disposed`;
1007
+ const lockPath = resolveWithinBase(basedir, '.locks', 'hooks', hookLockName);
1008
+ const claimed = await writeExclusive(lockPath, '');
492
1009
  if (!claimed) {
493
- throw new EntityConflictError('Cannot modify step in terminal state');
1010
+ throw new EntityConflictError(`Hook "${data.correlationId}" already disposed`);
494
1011
  }
495
- step = {
496
- ...validatedStep,
497
- status: 'completed',
498
- output: completedData.result,
499
- completedAt: now,
1012
+ // Read the hook to get its token before deleting
1013
+ const hookPath = taggedPath(basedir, 'hooks', data.correlationId, tag);
1014
+ const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
1015
+ if (existingHook) {
1016
+ // Delete the token constraint file to free up the token
1017
+ // for reuse, and delete this hook's recovery marker (if
1018
+ // any) for disk hygiene. The marker's filename hash
1019
+ // includes `(token, runId, hookId)` so different
1020
+ // lifetimes never collide, but cleaning up reduces disk
1021
+ // leak for hooks that go through the recovery path.
1022
+ const disposedConstraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(existingHook.token)}.json`);
1023
+ await deleteJSON(disposedConstraintPath);
1024
+ await deleteJSON(hookRecoveryMarkerPath(basedir, existingHook.token, existingHook.runId, existingHook.hookId));
1025
+ }
1026
+ await deleteJSON(hookPath);
1027
+ }
1028
+ else if (data.eventType === 'wait_created' && 'eventData' in data) {
1029
+ // wait_created: Creates wait entity with status 'waiting'
1030
+ const waitData = data.eventData;
1031
+ const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
1032
+ const existingWait = await readJSONWithFallback(basedir, 'waits', waitCompositeKey, WaitSchema, tag);
1033
+ if (existingWait) {
1034
+ throw new EntityConflictError(`Wait "${data.correlationId}" already exists`);
1035
+ }
1036
+ wait = {
1037
+ waitId: waitCompositeKey,
1038
+ runId: effectiveRunId,
1039
+ status: 'waiting',
1040
+ resumeAt: waitData.resumeAt,
1041
+ completedAt: undefined,
1042
+ createdAt: now,
500
1043
  updatedAt: now,
1044
+ specVersion: effectiveSpecVersion,
501
1045
  };
502
- await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
1046
+ await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait);
503
1047
  }
504
- }
505
- else if (data.eventType === 'step_failed' && 'eventData' in data) {
506
- // step_failed: Terminal state with error
507
- // Uses writeExclusive on a lock file to atomically prevent concurrent
508
- // invocations from both failing the same step (TOCTOU race).
509
- const failedData = data.eventData;
510
- if (validatedStep) {
511
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
512
- const lockName = tag
513
- ? `${stepCompositeKey}.terminal.${tag}`
514
- : `${stepCompositeKey}.terminal`;
515
- const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
516
- const claimed = await writeExclusive(terminalLockPath, '');
1048
+ else if (data.eventType === 'wait_completed') {
1049
+ // wait_completed: Transitions wait to 'completed', rejects duplicates.
1050
+ // Uses writeExclusive on a lock file to atomically prevent concurrent
1051
+ // invocations from both completing the same wait (TOCTOU race).
1052
+ const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
1053
+ const waitLockName = tag
1054
+ ? `${waitCompositeKey}.completed.${tag}`
1055
+ : `${waitCompositeKey}.completed`;
1056
+ const lockPath = resolveWithinBase(basedir, '.locks', 'waits', waitLockName);
1057
+ const claimed = await writeExclusive(lockPath, '');
517
1058
  if (!claimed) {
518
- throw new EntityConflictError('Cannot modify step in terminal state');
1059
+ throw new EntityConflictError(`Wait "${data.correlationId}" already completed`);
519
1060
  }
520
- const error = {
521
- message: typeof failedData.error === 'string'
522
- ? failedData.error
523
- : (failedData.error?.message ?? 'Unknown error'),
524
- stack: failedData.stack,
525
- };
526
- step = {
527
- ...validatedStep,
528
- status: 'failed',
529
- error,
1061
+ const existingWait = await readJSONWithFallback(basedir, 'waits', waitCompositeKey, WaitSchema, tag);
1062
+ if (!existingWait) {
1063
+ // Clean up the lock file we just claimed — the wait doesn't exist
1064
+ await fs.unlink(lockPath).catch(() => { });
1065
+ throw new WorkflowWorldError(`Wait "${data.correlationId}" not found`);
1066
+ }
1067
+ // The lock file (writeExclusive above) already prevents concurrent
1068
+ // completions — no additional status check needed.
1069
+ wait = {
1070
+ ...existingWait,
1071
+ status: 'completed',
530
1072
  completedAt: now,
531
1073
  updatedAt: now,
532
1074
  };
533
- await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
534
- }
535
- }
536
- else if (data.eventType === 'step_retrying' && 'eventData' in data) {
537
- // step_retrying: Sets status back to 'pending', records error
538
- // Reuse validatedStep from validation (already read above)
539
- const retryData = data.eventData;
540
- if (validatedStep) {
541
- const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
542
- step = {
543
- ...validatedStep,
544
- status: 'pending',
545
- error: {
546
- message: typeof retryData.error === 'string'
547
- ? retryData.error
548
- : (retryData.error?.message ?? 'Unknown error'),
549
- stack: retryData.stack,
550
- },
551
- retryAfter: retryData.retryAfter,
552
- updatedAt: now,
553
- };
554
- await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
555
- }
556
- }
557
- else if (
558
- // Hook lifecycle events
559
- data.eventType === 'hook_created' &&
560
- 'eventData' in data) {
561
- const hookData = data.eventData;
562
- // Atomically claim the token using an exclusive-create constraint file.
563
- // This avoids the TOCTOU race of the previous read-all-then-check approach.
564
- const constraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(hookData.token)}.json`);
565
- const tokenClaimed = await writeExclusive(constraintPath, JSON.stringify({
566
- token: hookData.token,
567
- hookId: data.correlationId,
568
- runId: effectiveRunId,
569
- }));
570
- if (!tokenClaimed) {
571
- const existingClaim = await readHookTokenClaim(constraintPath);
572
- // Create hook_conflict event instead of hook_created
573
- // This allows the workflow to continue and fail gracefully when the hook is awaited
574
- const conflictEvent = {
575
- eventType: 'hook_conflict',
576
- correlationId: data.correlationId,
577
- eventData: {
578
- token: hookData.token,
579
- ...(existingClaim
580
- ? { conflictingRunId: existingClaim.runId }
581
- : {}),
582
- },
583
- runId: effectiveRunId,
584
- eventId,
585
- createdAt: now,
586
- specVersion: effectiveSpecVersion,
587
- };
588
- // Store the conflict event
589
- const compositeKey = `${effectiveRunId}-${eventId}`;
590
- await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), conflictEvent);
591
- const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
592
- const filteredEvent = stripEventDataRefs(conflictEvent, resolveData);
593
- // Return EventResult with conflict event (no hook entity created)
594
- return {
595
- event: filteredEvent,
596
- run,
597
- step,
598
- hook: undefined,
599
- };
1075
+ await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait, { overwrite: true });
600
1076
  }
601
- hook = {
602
- runId: effectiveRunId,
603
- hookId: data.correlationId,
604
- token: hookData.token,
605
- metadata: hookData.metadata,
606
- ownerId: 'local-owner',
607
- projectId: 'local-project',
608
- environment: 'local',
609
- createdAt: now,
610
- // Propagate specVersion from the event to the hook entity
611
- specVersion: effectiveSpecVersion,
612
- isWebhook: hookData.isWebhook ?? false,
613
- };
614
- await writeJSON(taggedPath(basedir, 'hooks', data.correlationId, tag), hook);
615
- }
616
- else if (data.eventType === 'hook_disposed') {
617
- // hook_disposed: Deletes hook entity, rejects duplicates.
618
- // Uses writeExclusive on a lock file to atomically prevent concurrent
619
- // invocations from both disposing the same hook (TOCTOU race).
620
- const hookLockName = tag
621
- ? `${data.correlationId}.disposed.${tag}`
622
- : `${data.correlationId}.disposed`;
623
- const lockPath = resolveWithinBase(basedir, '.locks', 'hooks', hookLockName);
624
- const claimed = await writeExclusive(lockPath, '');
625
- if (!claimed) {
626
- throw new EntityConflictError(`Hook "${data.correlationId}" already disposed`);
1077
+ // Note: hook_received events are stored in the event log but don't
1078
+ // modify the Hook entity (which doesn't have a payload field)
1079
+ // Store event using composite key {runId}-{eventId}.
1080
+ //
1081
+ // `writeExclusive` (O_CREAT|O_EXCL via temp-file + hard-link)
1082
+ // is the cross-process atomic publish primitive: if the file
1083
+ // already exists, returns false instead of overwriting. This
1084
+ // is critical for the hook_created dedup-recovery convergence
1085
+ // (above) — two workers that adopt the same canonical eventId
1086
+ // race here; whoever links the file first wins, the loser
1087
+ // throws EntityConflictError, and the runtime's existing
1088
+ // concurrent-replay catch path at suspension-handler.ts:142
1089
+ // swallows it. For all other event types, eventIds are
1090
+ // monotonic ULIDs (globally unique by construction) so a
1091
+ // collision indicates a real bug and EntityConflictError is
1092
+ // also the right surface — same shape as step_created's
1093
+ // claim-file behavior.
1094
+ const compositeKey = `${effectiveRunId}-${eventId}`;
1095
+ const eventPublished = await writeExclusive(taggedPath(basedir, 'events', compositeKey, tag), JSON.stringify(event, jsonReplacer, 2));
1096
+ if (!eventPublished) {
1097
+ // For `hook_created`, losing the event publish means the
1098
+ // event was already committed at this exact (canonical)
1099
+ // path. The original publisher may have crashed between
1100
+ // its event publish and its deferred hook-entity write
1101
+ // (the inverse of the crash window the deferral closes),
1102
+ // leaving an event-first orphan: the event is in the log
1103
+ // but the entity is missing and the hook is unresolvable.
1104
+ // Repair the entity from the PERSISTED event's payload
1105
+ // (never the retry's — different retry metadata must not
1106
+ // change committed state) before surfacing the benign
1107
+ // duplicate to the runtime's concurrent-replay catch path.
1108
+ if (data.eventType === 'hook_created' && data.correlationId) {
1109
+ await repairHookEntityFromPersistedEvent(basedir, effectiveRunId, data.correlationId, eventId, tag);
1110
+ }
1111
+ throw new EntityConflictError(`Event "${eventId}" already exists for run "${effectiveRunId}"`);
627
1112
  }
628
- // Read the hook to get its token before deleting
629
- const hookPath = taggedPath(basedir, 'hooks', data.correlationId, tag);
630
- const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
631
- if (existingHook) {
632
- // Delete the token constraint file to free up the token for reuse
633
- const disposedConstraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(existingHook.token)}.json`);
634
- await deleteJSON(disposedConstraintPath);
1113
+ // Write the hook entity ONLY now that the event publish has
1114
+ // committed. Doing this earlier (in the `hook_created`
1115
+ // branch above) would mutate an already-committed hook
1116
+ // entity with the retry's payload before the event publish
1117
+ // proved whether this attempt was repairing a missing event
1118
+ // or just colliding with an already-published `hook_created`.
1119
+ // The branch sets `hookEntityWriteOptions` iff this event
1120
+ // type writes an entity.
1121
+ if (hook && data.eventType === 'hook_created') {
1122
+ await writeJSON(taggedPath(basedir, 'hooks', hook.hookId, tag), hook, hookEntityWriteOptions);
635
1123
  }
636
- await deleteJSON(hookPath);
637
- }
638
- else if (data.eventType === 'wait_created' && 'eventData' in data) {
639
- // wait_created: Creates wait entity with status 'waiting'
640
- const waitData = data.eventData;
641
- const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
642
- const existingWait = await readJSONWithFallback(basedir, 'waits', waitCompositeKey, WaitSchema, tag);
643
- if (existingWait) {
644
- throw new EntityConflictError(`Wait "${data.correlationId}" already exists`);
1124
+ const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
1125
+ const filteredEvent = stripEventDataRefs(event, resolveData);
1126
+ // For run_started: include all events so the runtime can skip
1127
+ // the initial events.list call and reduce TTFB.
1128
+ let events;
1129
+ let cursor;
1130
+ let hasMore;
1131
+ if (data.eventType === 'run_started' && run) {
1132
+ const allEvents = await paginatedFileSystemQuery({
1133
+ directory: path.join(basedir, 'events'),
1134
+ schema: EventSchema,
1135
+ filePrefix: `${effectiveRunId}-`,
1136
+ sortOrder: 'asc',
1137
+ limit: 1000,
1138
+ getCreatedAt: getObjectCreatedAt('evnt'),
1139
+ getId: (e) => e.eventId,
1140
+ });
1141
+ events = allEvents.data;
1142
+ cursor = allEvents.cursor;
1143
+ hasMore = allEvents.hasMore;
645
1144
  }
646
- wait = {
647
- waitId: waitCompositeKey,
648
- runId: effectiveRunId,
649
- status: 'waiting',
650
- resumeAt: waitData.resumeAt,
651
- completedAt: undefined,
652
- createdAt: now,
653
- updatedAt: now,
654
- specVersion: effectiveSpecVersion,
655
- };
656
- await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait);
657
- }
658
- else if (data.eventType === 'wait_completed') {
659
- // wait_completed: Transitions wait to 'completed', rejects duplicates.
660
- // Uses writeExclusive on a lock file to atomically prevent concurrent
661
- // invocations from both completing the same wait (TOCTOU race).
662
- const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
663
- const waitLockName = tag
664
- ? `${waitCompositeKey}.completed.${tag}`
665
- : `${waitCompositeKey}.completed`;
666
- const lockPath = resolveWithinBase(basedir, '.locks', 'waits', waitLockName);
667
- const claimed = await writeExclusive(lockPath, '');
668
- if (!claimed) {
669
- throw new EntityConflictError(`Wait "${data.correlationId}" already completed`);
670
- }
671
- const existingWait = await readJSONWithFallback(basedir, 'waits', waitCompositeKey, WaitSchema, tag);
672
- if (!existingWait) {
673
- // Clean up the lock file we just claimed — the wait doesn't exist
674
- await fs.unlink(lockPath).catch(() => { });
675
- throw new WorkflowWorldError(`Wait "${data.correlationId}" not found`);
676
- }
677
- // The lock file (writeExclusive above) already prevents concurrent
678
- // completions — no additional status check needed.
679
- wait = {
680
- ...existingWait,
681
- status: 'completed',
682
- completedAt: now,
683
- updatedAt: now,
1145
+ // Return EventResult with event and any created/updated entity
1146
+ return {
1147
+ event: filteredEvent,
1148
+ run,
1149
+ step,
1150
+ hook,
1151
+ wait,
1152
+ events,
1153
+ cursor,
1154
+ hasMore,
684
1155
  };
685
- await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait, { overwrite: true });
686
- }
687
- // Note: hook_received events are stored in the event log but don't
688
- // modify the Hook entity (which doesn't have a payload field)
689
- // Store event using composite key {runId}-{eventId}
690
- const compositeKey = `${effectiveRunId}-${eventId}`;
691
- await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), event);
692
- const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
693
- const filteredEvent = stripEventDataRefs(event, resolveData);
694
- // For run_started: include all events so the runtime can skip
695
- // the initial events.list call and reduce TTFB.
696
- let events;
697
- let cursor;
698
- let hasMore;
699
- if (data.eventType === 'run_started' && run) {
700
- const allEvents = await paginatedFileSystemQuery({
701
- directory: path.join(basedir, 'events'),
702
- schema: EventSchema,
703
- filePrefix: `${effectiveRunId}-`,
704
- sortOrder: 'asc',
705
- limit: 1000,
706
- getCreatedAt: getObjectCreatedAt('evnt'),
707
- getId: (e) => e.eventId,
708
- });
709
- events = allEvents.data;
710
- cursor = allEvents.cursor;
711
- hasMore = allEvents.hasMore;
712
- }
713
- // Return EventResult with event and any created/updated entity
714
- return {
715
- event: filteredEvent,
716
- run,
717
- step,
718
- hook,
719
- wait,
720
- events,
721
- cursor,
722
- hasMore,
723
- };
1156
+ } // end createImpl
724
1157
  },
725
1158
  async get(runId, eventId, params) {
726
1159
  assertSafeEntityId('runId', runId);
@@ -786,4 +1219,4 @@ export function createEventsStorage(basedir, tag) {
786
1219
  },
787
1220
  };
788
1221
  }
789
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLXN0b3JhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9ldmVudHMtc3RvcmFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsQyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixpQkFBaUIsRUFDakIsZUFBZSxFQUNmLG9CQUFvQixFQUNwQixhQUFhLEVBQ2Isa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFXMUIsT0FBTyxFQUNMLFdBQVcsRUFDWCxVQUFVLEVBQ1YsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixvQkFBb0IsRUFDcEIsVUFBVSxFQUNWLHFCQUFxQixFQUNyQixVQUFVLEVBQ1YsaUJBQWlCLEdBQ2xCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUN4QixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0QsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixVQUFVLEVBQ1YsWUFBWSxFQUNaLGFBQWEsRUFDYix3QkFBd0IsRUFDeEIsUUFBUSxFQUNSLG9CQUFvQixFQUNwQixpQkFBaUIsRUFDakIsVUFBVSxFQUNWLGNBQWMsRUFDZCxTQUFTLEdBQ1YsTUFBTSxVQUFVLENBQUM7QUFDbEIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVoRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQyxN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RSxDQUFDLEtBQUssQ0FBQyxhQUFhLEtBQUssYUFBYTtnQkFDeEQsMkRBQTJEO2dCQUMzRCxtREFBbUQ7Z0JBQ25ELFNBQVMsRUFBRSxNQUFNLENBQUMsVUFBVSxFQUFFLFNBQVMsSUFBSSxLQUFLO2dCQUNoRCxLQUFLLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxLQUFLO2dCQUMvQixNQUFNLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxNQUFNO2dCQUNqQyxZQUFZLEVBQUUsa0JBQWtCLENBQUMsTUFBTSxDQUFDO2dCQUN4QyxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPO2FBQ2hDLENBQUMsQ0FBQztZQUVILHlEQUF5RDtZQUN6RCxJQUFJLFdBQVcsS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDM0IsT0FBTztvQkFDTCxHQUFHLE1BQU07b0JBQ1QsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDOUIsa0JBQWtCLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUN2QztpQkFDRixDQUFDO1lBQ0osQ0FBQztZQUVELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdub2RlOmZzL3Byb21pc2VzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBIb29rTm90Rm91bmRFcnJvcixcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBSdW5Ob3RTdXBwb3J0ZWRFcnJvcixcbiAgVG9vRWFybHlFcnJvcixcbiAgV29ya2Zsb3dXb3JsZEVycm9yLFxufSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB0eXBlIHtcbiAgRXZlbnQsXG4gIEV2ZW50UmVzdWx0LFxuICBIb29rLFxuICBTZXJpYWxpemVkRGF0YSxcbiAgU3RlcCxcbiAgU3RvcmFnZSxcbiAgV2FpdCxcbiAgV29ya2Zsb3dSdW4sXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQge1xuICBFdmVudFNjaGVtYSxcbiAgSG9va1NjaGVtYSxcbiAgaXNMZWdhY3lTcGVjVmVyc2lvbixcbiAgcmVxdWlyZXNOZXdlcldvcmxkLFxuICBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgU3RlcFNjaGVtYSxcbiAgdmFsaWRhdGVVbGlkVGltZXN0YW1wLFxuICBXYWl0U2NoZW1hLFxuICBXb3JrZmxvd1J1blNjaGVtYSxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHsgREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OIH0gZnJvbSAnLi4vY29uZmlnLmpzJztcbmltcG9ydCB7XG4gIGFzc2VydFNhZmVFbnRpdHlJZCxcbiAgZGVsZXRlSlNPTixcbiAganNvblJlcGxhY2VyLFxuICBsaXN0SlNPTkZpbGVzLFxuICBwYWdpbmF0ZWRGaWxlU3lzdGVtUXVlcnksXG4gIHJlYWRKU09OLFxuICByZWFkSlNPTldpdGhGYWxsYmFjayxcbiAgcmVzb2x2ZVdpdGhpbkJhc2UsXG4gIHRhZ2dlZFBhdGgsXG4gIHdyaXRlRXhjbHVzaXZlLFxuICB3cml0ZUpTT04sXG59IGZyb20gJy4uL2ZzLmpzJztcbmltcG9ydCB7IHN0cmlwRXZlbnREYXRhUmVmcyB9IGZyb20gJy4vZmlsdGVycy5qcyc7XG5pbXBvcnQgeyBnZXRPYmplY3RDcmVhdGVkQXQsIGhhc2hUb2tlbiwgbW9ub3RvbmljVWxpZCB9IGZyb20gJy4vaGVscGVycy5qcyc7XG5pbXBvcnQgeyBkZWxldGVBbGxIb29rc0ZvclJ1biB9IGZyb20gJy4vaG9va3Mtc3RvcmFnZS5qcyc7XG5pbXBvcnQgeyBoYW5kbGVMZWdhY3lFdmVudCB9IGZyb20gJy4vbGVnYWN5LmpzJztcblxuY29uc3QgSG9va1Rva2VuQ2xhaW1TY2hlbWEgPSB6Lm9iamVjdCh7XG4gIHJ1bklkOiB6LnN0cmluZygpLFxufSk7XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRIb29rVG9rZW5DbGFpbShcbiAgY29uc3RyYWludFBhdGg6IHN0cmluZ1xuKTogUHJvbWlzZTx6LmluZmVyPHR5cGVvZiBIb29rVG9rZW5DbGFpbVNjaGVtYT4gfCBudWxsPiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHJlYWRKU09OKGNvbnN0cmFpbnRQYXRoLCBIb29rVG9rZW5DbGFpbVNjaGVtYSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU3ludGF4RXJyb3IgfHwgZXJyb3IgaW5zdGFuY2VvZiB6LlpvZEVycm9yKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gZGVsZXRlIGFsbCB3YWl0cyBhc3NvY2lhdGVkIHdpdGggYSB3b3JrZmxvdyBydW4uXG4gKiBDYWxsZWQgd2hlbiBhIHJ1biByZWFjaGVzIGEgdGVybWluYWwgc3RhdGUuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUFsbFdhaXRzRm9yUnVuKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB3YWl0c0RpciA9IHBhdGguam9pbihiYXNlZGlyLCAnd2FpdHMnKTtcbiAgY29uc3QgZmlsZXMgPSBhd2FpdCBsaXN0SlNPTkZpbGVzKHdhaXRzRGlyKTtcblxuICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAvLyBmaWxlSWRzIG1heSBjb250YWluIHRhZyBzdWZmaXhlcyAoZS5nLiwgXCJ3cnVuX0FCQy1jb3JySWQudml0ZXN0LTBcIilcbiAgICAvLyBidXQgc3RhcnRzV2l0aCBzdGlsbCBtYXRjaGVzIGNvcnJlY3RseSBzaW5jZSB0aGUgdGFnIGlzIGEgc3VmZml4LlxuICAgIGlmIChmaWxlLnN0YXJ0c1dpdGgoYCR7cnVuSWR9LWApKSB7XG4gICAgICBjb25zdCB3YWl0UGF0aCA9IHBhdGguam9pbih3YWl0c0RpciwgYCR7ZmlsZX0uanNvbmApO1xuICAgICAgYXdhaXQgZGVsZXRlSlNPTih3YWl0UGF0aCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgZXZlbnRzIHN0b3JhZ2UgaW1wbGVtZW50YXRpb24gdXNpbmcgdGhlIGZpbGVzeXN0ZW0uXG4gKiBJbXBsZW1lbnRzIHRoZSBTdG9yYWdlWydldmVudHMnXSBpbnRlcmZhY2Ugd2l0aCBjcmVhdGUsIGxpc3QsIGFuZCBsaXN0QnlDb3JyZWxhdGlvbklkIG9wZXJhdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFdmVudHNTdG9yYWdlKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHRhZz86IHN0cmluZ1xuKTogU3RvcmFnZVsnZXZlbnRzJ10ge1xuICByZXR1cm4ge1xuICAgIGFzeW5jIGNyZWF0ZShydW5JZCwgZGF0YSwgcGFyYW1zKTogUHJvbWlzZTxFdmVudFJlc3VsdD4ge1xuICAgICAgY29uc3QgZXZlbnRJZCA9IGBldm50XyR7bW9ub3RvbmljVWxpZCgpfWA7XG4gICAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuXG4gICAgICAvLyBWYWxpZGF0ZSByZXF1ZXN0LXN1cHBsaWVkIElEcyBiZWZvcmUgdGhleSdyZSBjb25jYXRlbmF0ZWQgaW50b1xuICAgICAgLy8gZmlsZXN5c3RlbSBwYXRocy4gVGhpcyBpcyB0aGUgcHJpbWFyeSBkZWZlbnNlIGFnYWluc3QgcGF0aCB0cmF2ZXJzYWxcbiAgICAgIC8vIGF0dGFja3Mgd2hlcmUgYSBjbGllbnQgc3VwcGxpZXMgcnVuSWQgLyBjb3JyZWxhdGlvbklkIHZhbHVlcyBsaWtlXG4gICAgICAvLyBcIi4uLy4uLy4uL3BhY2thZ2VcIiB0byByZWFkIG9yIHdyaXRlIGZpbGVzIG91dHNpZGUgdGhlIHN0b3JhZ2Ugcm9vdC5cbiAgICAgIC8vXG4gICAgICAvLyBFbXB0eSBgY29ycmVsYXRpb25JZGAgdmFsdWVzIGFyZSBhbHNvIHJlamVjdGVkIGhlcmU6IHRoZSBldmVudFxuICAgICAgLy8gc2NoZW1hcyBvbmx5IHJlcXVpcmUgYHouc3RyaW5nKClgLCBzbyB3aXRob3V0IHRoaXMgY2hlY2sgYVxuICAgICAgLy8gc3RlcF9jcmVhdGVkIC8gaG9va19jcmVhdGVkIC8gd2FpdF9jcmVhdGVkIHJlcXVlc3Qgd2l0aFxuICAgICAgLy8gYGNvcnJlbGF0aW9uSWQ6ICcnYCB3b3VsZCBzaWxlbnRseSBiZSB3cml0dGVuIHVuZGVyIGEgbWFsZm9ybWVkXG4gICAgICAvLyBjb21wb3NpdGUga2V5IGxpa2UgYCR7cnVuSWR9LWAuXG4gICAgICBpZiAocnVuSWQgIT0gbnVsbCAmJiBydW5JZCAhPT0gJycpIHtcbiAgICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdydW5JZCcsIHJ1bklkKTtcbiAgICAgIH1cbiAgICAgIGlmICgnY29ycmVsYXRpb25JZCcgaW4gZGF0YSAmJiB0eXBlb2YgZGF0YS5jb3JyZWxhdGlvbklkID09PSAnc3RyaW5nJykge1xuICAgICAgICBhc3NlcnRTYWZlRW50aXR5SWQoJ2NvcnJlbGF0aW9uSWQnLCBkYXRhLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgfVxuXG4gICAgICAvLyBGb3IgcnVuX2NyZWF0ZWQgZXZlbnRzLCB1c2UgY2xpZW50LXByb3ZpZGVkIHJ1bklkIG9yIGdlbmVyYXRlIG9uZSBzZXJ2ZXItc2lkZVxuICAgICAgbGV0IGVmZmVjdGl2ZVJ1bklkOiBzdHJpbmc7XG4gICAgICBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCcgJiYgKCFydW5JZCB8fCBydW5JZCA9PT0gJycpKSB7XG4gICAgICAgIGVmZmVjdGl2ZVJ1bklkID0gYHdydW5fJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgIH0gZWxzZSBpZiAoIXJ1bklkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncnVuSWQgaXMgcmVxdWlyZWQgZm9yIG5vbi1ydW5fY3JlYXRlZCBldmVudHMnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVmZmVjdGl2ZVJ1bklkID0gcnVuSWQ7XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGNsaWVudC1wcm92aWRlZCBydW5JZCB0aW1lc3RhbXAgaXMgd2l0aGluIGFjY2VwdGFibGUgdGhyZXNob2xkXG4gICAgICBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCcgJiYgcnVuSWQgJiYgcnVuSWQgIT09ICcnKSB7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25FcnJvciA9IHZhbGlkYXRlVWxpZFRpbWVzdGFtcChlZmZlY3RpdmVSdW5JZCwgJ3dydW5fJyk7XG4gICAgICAgIGlmICh2YWxpZGF0aW9uRXJyb3IpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dXb3JsZEVycm9yKHZhbGlkYXRpb25FcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gc3BlY1ZlcnNpb24gaXMgYWx3YXlzIHNlbnQgYnkgdGhlIHJ1bnRpbWUsIGJ1dCB3ZSBwcm92aWRlIGEgZmFsbGJhY2sgZm9yIHNhZmV0eVxuICAgICAgY29uc3QgZWZmZWN0aXZlU3BlY1ZlcnNpb24gPSBkYXRhLnNwZWNWZXJzaW9uID8/IFNQRUNfVkVSU0lPTl9DVVJSRU5UO1xuXG4gICAgICAvLyBIZWxwZXIgdG8gY2hlY2sgaWYgcnVuIGlzIGluIHRlcm1pbmFsIHN0YXRlXG4gICAgICBjb25zdCBpc1J1blRlcm1pbmFsID0gKHN0YXR1czogc3RyaW5nKSA9PlxuICAgICAgICBbJ2NvbXBsZXRlZCcsICdmYWlsZWQnLCAnY2FuY2VsbGVkJ10uaW5jbHVkZXMoc3RhdHVzKTtcblxuICAgICAgLy8gSGVscGVyIHRvIGNoZWNrIGlmIHN0ZXAgaXMgaW4gdGVybWluYWwgc3RhdGVcbiAgICAgIGNvbnN0IGlzU3RlcFRlcm1pbmFsID0gKHN0YXR1czogc3RyaW5nKSA9PlxuICAgICAgICBbJ2NvbXBsZXRlZCcsICdmYWlsZWQnLCAnY2FuY2VsbGVkJ10uaW5jbHVkZXMoc3RhdHVzKTtcblxuICAgICAgLy8gR2V0IGN1cnJlbnQgcnVuIHN0YXRlIGZvciB2YWxpZGF0aW9uIChpZiBub3QgY3JlYXRpbmcgYSBuZXcgcnVuKVxuICAgICAgLy8gU2tpcCBydW4gdmFsaWRhdGlvbiBmb3Igc3RlcF9jb21wbGV0ZWQgYW5kIHN0ZXBfcmV0cnlpbmcgLSB0aGV5IG9ubHkgb3BlcmF0ZVxuICAgICAgLy8gb24gcnVubmluZyBzdGVwcywgYW5kIHJ1bm5pbmcgc3RlcHMgYXJlIGFsd2F5cyBhbGxvd2VkIHRvIG1vZGlmeSByZWdhcmRsZXNzXG4gICAgICAvLyBvZiBydW4gc3RhdGUuIFRoaXMgb3B0aW1pemF0aW9uIHNhdmVzIGZpbGVzeXN0ZW0gcmVhZHMgcGVyIHN0ZXAgZXZlbnQuXG4gICAgICBsZXQgY3VycmVudFJ1bjogV29ya2Zsb3dSdW4gfCBudWxsID0gbnVsbDtcbiAgICAgIGNvbnN0IHNraXBSdW5WYWxpZGF0aW9uRXZlbnRzID0gWydzdGVwX2NvbXBsZXRlZCcsICdzdGVwX3JldHJ5aW5nJ107XG4gICAgICBpZiAoXG4gICAgICAgIGRhdGEuZXZlbnRUeXBlICE9PSAncnVuX2NyZWF0ZWQnICYmXG4gICAgICAgICFza2lwUnVuVmFsaWRhdGlvbkV2ZW50cy5pbmNsdWRlcyhkYXRhLmV2ZW50VHlwZSlcbiAgICAgICkge1xuICAgICAgICBjdXJyZW50UnVuID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAncnVucycsXG4gICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgV29ya2Zsb3dSdW5TY2hlbWEsXG4gICAgICAgICAgdGFnXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUmVzaWxpZW50IHN0YXJ0OiBydW5fc3RhcnRlZCBvbiBub24tZXhpc3RlbnQgcnVuIHdpdGggZXZlbnREYXRhXG4gICAgICAgIC8vIGNyZWF0ZXMgdGhlIHJ1biBmaXJzdCwgc28gdGhlIHF1ZXVlIGNhbiBib290c3RyYXAgYSBydW4gdGhhdFxuICAgICAgICAvLyBmYWlsZWQgdG8gY3JlYXRlIGR1cmluZyBzdGFydCgpLlxuICAgICAgICBpZiAoXG4gICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcgJiZcbiAgICAgICAgICAhY3VycmVudFJ1biAmJlxuICAgICAgICAgICdldmVudERhdGEnIGluIGRhdGEgJiZcbiAgICAgICAgICBkYXRhLmV2ZW50RGF0YVxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBydW5JbnB1dERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICBkZXBsb3ltZW50SWQ/OiBzdHJpbmc7XG4gICAgICAgICAgICB3b3JrZmxvd05hbWU/OiBzdHJpbmc7XG4gICAgICAgICAgICBpbnB1dD86IGFueTtcbiAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgICAgICAgIH07XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgcnVuSW5wdXREYXRhLmRlcGxveW1lbnRJZCAmJlxuICAgICAgICAgICAgcnVuSW5wdXREYXRhLndvcmtmbG93TmFtZSAmJlxuICAgICAgICAgICAgcnVuSW5wdXREYXRhLmlucHV0ICE9PSB1bmRlZmluZWRcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIEF0b21pY2FsbHkgdHJ5IHRvIHB1Ymxpc2ggdGhlIHJ1biBlbnRpdHkgc28gb25seSB0aGUgZmlyc3RcbiAgICAgICAgICAgIC8vIHdyaXRlciB3aW5zLCBwcmV2ZW50aW5nIGEgVE9DVE9VIHJhY2Ugd2hlcmUgYSBjb25jdXJyZW50XG4gICAgICAgICAgICAvLyBydW5fY3JlYXRlZCBmcm9tIHN0YXJ0KCkgY291bGQgb3ZlcndyaXRlIGEgcnVuIHRoYXQgd2FzXG4gICAgICAgICAgICAvLyBhbHJlYWR5IHRyYW5zaXRpb25lZCB0byAncnVubmluZycuXG4gICAgICAgICAgICBjb25zdCBjcmVhdGVkUnVuOiBXb3JrZmxvd1J1biA9IHtcbiAgICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IHJ1bklucHV0RGF0YS5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgICB3b3JrZmxvd05hbWU6IHJ1bklucHV0RGF0YS53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogcnVuSW5wdXREYXRhLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgIGlucHV0OiBydW5JbnB1dERhdGEuaW5wdXQsXG4gICAgICAgICAgICAgIG91dHB1dDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBzdGFydGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHJ1blBhdGggPSB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyk7XG4gICAgICAgICAgICBjb25zdCBjcmVhdGVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUoXG4gICAgICAgICAgICAgIHJ1blBhdGgsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNyZWF0ZWRSdW4sIGpzb25SZXBsYWNlcilcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGlmIChjcmVhdGVkKSB7XG4gICAgICAgICAgICAgIC8vIFdlIGNyZWF0ZWQgdGhlIHJ1biDigJQgYWxzbyB3cml0ZSB0aGUgcnVuX2NyZWF0ZWQgZXZlbnQuXG4gICAgICAgICAgICAgIGNvbnN0IHJ1bkNyZWF0ZWRFdmVudElkID0gYGV2bnRfJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgICAgICAgICAgY29uc3QgcnVuQ3JlYXRlZEV2ZW50OiBFdmVudCA9IHtcbiAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fY3JlYXRlZCcsXG4gICAgICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICAgIGV2ZW50SWQ6IHJ1bkNyZWF0ZWRFdmVudElkLFxuICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogcnVuSW5wdXREYXRhLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuSW5wdXREYXRhLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgIGlucHV0OiBydW5JbnB1dERhdGEuaW5wdXQsXG4gICAgICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBydW5JbnB1dERhdGEuZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICBjb25zdCBjcmVhdGVkQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7cnVuQ3JlYXRlZEV2ZW50SWR9YDtcbiAgICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2V2ZW50cycsIGNyZWF0ZWRDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICAgICAgcnVuQ3JlYXRlZEV2ZW50XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGN1cnJlbnRSdW4gPSBjcmVhdGVkUnVuO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gUnVuIGFscmVhZHkgZXhpc3RzIChjb25jdXJyZW50IHJ1bl9jcmVhdGVkIHdvbiB0aGVcbiAgICAgICAgICAgICAgLy8gcmFjZSkuIFJlLXJlYWQgaXQgc28gZG93bnN0cmVhbSBsb2dpYyBzZWVzIHRoZSByZWFsIHN0YXRlLlxuICAgICAgICAgICAgICBjdXJyZW50UnVuID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgICAncnVucycsXG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgV29ya2Zsb3dSdW5TY2hlbWEsXG4gICAgICAgICAgICAgICAgdGFnXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgICAgLy8gVkVSU0lPTiBDT01QQVRJQklMSVRZOiBDaGVjayBydW4gc3BlYyB2ZXJzaW9uXG4gICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAgIC8vIEZvciBldmVudHMgdGhhdCBoYXZlIGZldGNoZWQgdGhlIHJ1biwgY2hlY2sgdmVyc2lvbiBjb21wYXRpYmlsaXR5LlxuICAgICAgLy8gU2tpcCBmb3IgcnVuX2NyZWF0ZWQgKG5vIGV4aXN0aW5nIHJ1bikgYW5kIHJ1bnRpbWUgZXZlbnRzIChzdGVwX2NvbXBsZXRlZCwgc3RlcF9yZXRyeWluZykuXG4gICAgICBpZiAoY3VycmVudFJ1bikge1xuICAgICAgICAvLyBDaGVjayBpZiBydW4gcmVxdWlyZXMgYSBuZXdlciB3b3JsZCB2ZXJzaW9uXG4gICAgICAgIGlmIChyZXF1aXJlc05ld2VyV29ybGQoY3VycmVudFJ1bi5zcGVjVmVyc2lvbikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgUnVuTm90U3VwcG9ydGVkRXJyb3IoXG4gICAgICAgICAgICBjdXJyZW50UnVuLnNwZWNWZXJzaW9uISxcbiAgICAgICAgICAgIFNQRUNfVkVSU0lPTl9DVVJSRU5UXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJvdXRlIHRvIGxlZ2FjeSBoYW5kbGVyIGZvciBwcmUtZXZlbnQtc291cmNpbmcgcnVuc1xuICAgICAgICBpZiAoaXNMZWdhY3lTcGVjVmVyc2lvbihjdXJyZW50UnVuLnNwZWNWZXJzaW9uKSkge1xuICAgICAgICAgIHJldHVybiBoYW5kbGVMZWdhY3lFdmVudChcbiAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgICBjdXJyZW50UnVuLFxuICAgICAgICAgICAgcGFyYW1zXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAgIC8vIFZBTElEQVRJT046IFRlcm1pbmFsIHN0YXRlIGFuZCBldmVudCBvcmRlcmluZyBjaGVja3NcbiAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gICAgICAvLyBSdW4gdGVybWluYWwgc3RhdGUgdmFsaWRhdGlvblxuICAgICAgaWYgKGN1cnJlbnRSdW4gJiYgaXNSdW5UZXJtaW5hbChjdXJyZW50UnVuLnN0YXR1cykpIHtcbiAgICAgICAgY29uc3QgcnVuVGVybWluYWxFdmVudHMgPSBbXG4gICAgICAgICAgJ3J1bl9zdGFydGVkJyxcbiAgICAgICAgICAncnVuX2NvbXBsZXRlZCcsXG4gICAgICAgICAgJ3J1bl9mYWlsZWQnLFxuICAgICAgICBdO1xuXG4gICAgICAgIC8vIElkZW1wb3RlbnQgb3BlcmF0aW9uOiBydW5fY2FuY2VsbGVkIG9uIGFscmVhZHkgY2FuY2VsbGVkIHJ1biBpcyBhbGxvd2VkXG4gICAgICAgIGlmIChcbiAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnICYmXG4gICAgICAgICAgY3VycmVudFJ1bi5zdGF0dXMgPT09ICdjYW5jZWxsZWQnXG4gICAgICAgICkge1xuICAgICAgICAgIC8vIFJldHVybiBleGlzdGluZyBzdGF0ZSAoaWRlbXBvdGVudClcbiAgICAgICAgICBjb25zdCBldmVudDogRXZlbnQgPSB7XG4gICAgICAgICAgICAuLi5kYXRhLFxuICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgIH07XG4gICAgICAgICAgY29uc3QgY29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZXZlbnRJZH1gO1xuICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2V2ZW50cycsIGNvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgIGV2ZW50XG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCByZXNvbHZlRGF0YSA9XG4gICAgICAgICAgICBwYXJhbXM/LnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXZlbnQ6IHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpLFxuICAgICAgICAgICAgcnVuOiBjdXJyZW50UnVuLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGb3IgcnVuX3N0YXJ0ZWQgb24gdGVybWluYWwgcnVucywgdXNlIFJ1bkV4cGlyZWRFcnJvciBzbyB0aGVcbiAgICAgICAgLy8gcnVudGltZSBrbm93cyB0byBleGl0IHdpdGhvdXQgcmV0cnlpbmcuXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJykge1xuICAgICAgICAgIHRocm93IG5ldyBSdW5FeHBpcmVkRXJyb3IoXG4gICAgICAgICAgICBgV29ya2Zsb3cgcnVuIFwiJHtlZmZlY3RpdmVSdW5JZH1cIiBpcyBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlIFwiJHtjdXJyZW50UnVuLnN0YXR1c31cImBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gT3RoZXIgcnVuIHN0YXRlIHRyYW5zaXRpb25zIGFyZSBub3QgYWxsb3dlZCBvbiB0ZXJtaW5hbCBydW5zXG4gICAgICAgIGlmIChcbiAgICAgICAgICBydW5UZXJtaW5hbEV2ZW50cy5pbmNsdWRlcyhkYXRhLmV2ZW50VHlwZSkgfHxcbiAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnXG4gICAgICAgICkge1xuICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgYENhbm5vdCB0cmFuc2l0aW9uIHJ1biBmcm9tIHRlcm1pbmFsIHN0YXRlIFwiJHtjdXJyZW50UnVuLnN0YXR1c31cImBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ3JlYXRpbmcgbmV3IGVudGl0aWVzIG9uIHRlcm1pbmFsIHJ1bnMgaXMgbm90IGFsbG93ZWRcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9jcmVhdGVkJyB8fFxuICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnaG9va19jcmVhdGVkJyB8fFxuICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnd2FpdF9jcmVhdGVkJ1xuICAgICAgICApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgIGBDYW5ub3QgY3JlYXRlIG5ldyBlbnRpdGllcyBvbiBydW4gaW4gdGVybWluYWwgc3RhdGUgXCIke2N1cnJlbnRSdW4uc3RhdHVzfVwiYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gU3RlcC1yZWxhdGVkIGV2ZW50IHZhbGlkYXRpb24gKG9yZGVyaW5nIGFuZCB0ZXJtaW5hbCBzdGF0ZSlcbiAgICAgIC8vIFN0b3JlIGV4aXN0aW5nU3RlcCBzbyB3ZSBjYW4gcmV1c2UgaXQgbGF0ZXIgKGF2b2lkIGRvdWJsZSByZWFkKVxuICAgICAgbGV0IHZhbGlkYXRlZFN0ZXA6IFN0ZXAgfCBudWxsID0gbnVsbDtcbiAgICAgIGNvbnN0IHN0ZXBFdmVudHMgPSBbXG4gICAgICAgICdzdGVwX3N0YXJ0ZWQnLFxuICAgICAgICAnc3RlcF9jb21wbGV0ZWQnLFxuICAgICAgICAnc3RlcF9mYWlsZWQnLFxuICAgICAgICAnc3RlcF9yZXRyeWluZycsXG4gICAgICBdO1xuICAgICAgaWYgKHN0ZXBFdmVudHMuaW5jbHVkZXMoZGF0YS5ldmVudFR5cGUpICYmIGRhdGEuY29ycmVsYXRpb25JZCkge1xuICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgIHZhbGlkYXRlZFN0ZXAgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICdzdGVwcycsXG4gICAgICAgICAgc3RlcENvbXBvc2l0ZUtleSxcbiAgICAgICAgICBTdGVwU2NoZW1hLFxuICAgICAgICAgIHRhZ1xuICAgICAgICApO1xuXG4gICAgICAgIC8vIEV2ZW50IG9yZGVyaW5nOiBzdGVwIG11c3QgZXhpc3QgYmVmb3JlIHRoZXNlIGV2ZW50c1xuICAgICAgICBpZiAoIXZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dXb3JsZEVycm9yKFxuICAgICAgICAgICAgYFN0ZXAgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBub3QgZm91bmRgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFN0ZXAgdGVybWluYWwgc3RhdGUgdmFsaWRhdGlvblxuICAgICAgICBpZiAoaXNTdGVwVGVybWluYWwodmFsaWRhdGVkU3RlcC5zdGF0dXMpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICBgQ2Fubm90IG1vZGlmeSBzdGVwIGluIHRlcm1pbmFsIHN0YXRlIFwiJHt2YWxpZGF0ZWRTdGVwLnN0YXR1c31cImBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gT24gdGVybWluYWwgcnVuczogb25seSBhbGxvdyBjb21wbGV0aW5nL2ZhaWxpbmcgaW4tcHJvZ3Jlc3Mgc3RlcHNcbiAgICAgICAgaWYgKGN1cnJlbnRSdW4gJiYgaXNSdW5UZXJtaW5hbChjdXJyZW50UnVuLnN0YXR1cykpIHtcbiAgICAgICAgICBpZiAodmFsaWRhdGVkU3RlcC5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bkV4cGlyZWRFcnJvcihcbiAgICAgICAgICAgICAgYENhbm5vdCBtb2RpZnkgbm9uLXJ1bm5pbmcgc3RlcCBvbiBydW4gaW4gdGVybWluYWwgc3RhdGUgXCIke2N1cnJlbnRSdW4uc3RhdHVzfVwiYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gSG9vay1yZWxhdGVkIGV2ZW50IHZhbGlkYXRpb24gKG9yZGVyaW5nKVxuICAgICAgY29uc3QgaG9va0V2ZW50c1JlcXVpcmluZ0V4aXN0ZW5jZSA9IFsnaG9va19kaXNwb3NlZCcsICdob29rX3JlY2VpdmVkJ107XG4gICAgICBpZiAoXG4gICAgICAgIGhvb2tFdmVudHNSZXF1aXJpbmdFeGlzdGVuY2UuaW5jbHVkZXMoZGF0YS5ldmVudFR5cGUpICYmXG4gICAgICAgIGRhdGEuY29ycmVsYXRpb25JZFxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGV4aXN0aW5nSG9vayA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgJ2hvb2tzJyxcbiAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgSG9va1NjaGVtYSxcbiAgICAgICAgICB0YWdcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIWV4aXN0aW5nSG9vaykge1xuICAgICAgICAgIHRocm93IG5ldyBIb29rTm90Rm91bmRFcnJvcihkYXRhLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdCBldmVudDogRXZlbnQgPSB7XG4gICAgICAgIC4uLmRhdGEsXG4gICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgIH07XG4gICAgICAvLyBTdHJpcCBldmVudERhdGEgZnJvbSBydW5fc3RhcnRlZCDigJQgaXQgYmVsb25ncyBvbiBydW5fY3JlYXRlZCBvbmx5LlxuICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX3N0YXJ0ZWQnICYmICdldmVudERhdGEnIGluIGV2ZW50KSB7XG4gICAgICAgIGRlbGV0ZSAoZXZlbnQgYXMgYW55KS5ldmVudERhdGE7XG4gICAgICB9XG5cbiAgICAgIC8vIFRyYWNrIGVudGl0eSBjcmVhdGVkL3VwZGF0ZWQgZm9yIEV2ZW50UmVzdWx0XG4gICAgICBsZXQgcnVuOiBXb3JrZmxvd1J1biB8IHVuZGVmaW5lZDtcbiAgICAgIGxldCBzdGVwOiBTdGVwIHwgdW5kZWZpbmVkO1xuICAgICAgbGV0IGhvb2s6IEhvb2sgfCB1bmRlZmluZWQ7XG4gICAgICBsZXQgd2FpdDogV2FpdCB8IHVuZGVmaW5lZDtcblxuICAgICAgLy8gQ3JlYXRlL3VwZGF0ZSBlbnRpdHkgYmFzZWQgb24gZXZlbnQgdHlwZSAoZXZlbnQtc291cmNlZCBhcmNoaXRlY3R1cmUpXG4gICAgICAvLyBSdW4gbGlmZWN5Y2xlIGV2ZW50c1xuICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NyZWF0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgY29uc3QgcnVuRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICBkZXBsb3ltZW50SWQ6IHN0cmluZztcbiAgICAgICAgICB3b3JrZmxvd05hbWU6IHN0cmluZztcbiAgICAgICAgICBpbnB1dDogU2VyaWFsaXplZERhdGE7XG4gICAgICAgICAgZXhlY3V0aW9uQ29udGV4dD86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgICAgIH07XG4gICAgICAgIHJ1biA9IHtcbiAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgZGVwbG95bWVudElkOiBydW5EYXRhLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICBzdGF0dXM6ICdwZW5kaW5nJyxcbiAgICAgICAgICB3b3JrZmxvd05hbWU6IHJ1bkRhdGEud29ya2Zsb3dOYW1lLFxuICAgICAgICAgIC8vIFByb3BhZ2F0ZSBzcGVjVmVyc2lvbiBmcm9tIHRoZSBldmVudCB0byB0aGUgcnVuIGVudGl0eVxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBydW5EYXRhLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgaW5wdXQ6IHJ1bkRhdGEuaW5wdXQsXG4gICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICBzdGFydGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICBjb21wbGV0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICB9O1xuICAgICAgICAvLyBBdG9taWNhbGx5IHB1Ymxpc2ggdGhlIHJ1biBlbnRpdHkgZmlsZSB3aXRob3V0IG92ZXJ3cml0aW5nIGFuXG4gICAgICAgIC8vIGV4aXN0aW5nIHdpbm5lci4gVGhpcyBwcmV2ZW50cyBhIFRPQ1RPVSByYWNlIHdpdGggdGhlIHJlc2lsaWVudFxuICAgICAgICAvLyBzdGFydCBwYXRoIChydW5fc3RhcnRlZCBvbiBub24tZXhpc3RlbnQgcnVuKSB0aGF0IGNvdWxkIHJlc3VsdCBpblxuICAgICAgICAvLyBkdXBsaWNhdGUgcnVuX2NyZWF0ZWQgZXZlbnRzIGluIHRoZSBldmVudCBsb2cuXG4gICAgICAgIGNvbnN0IHJ1blBhdGggPSB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyk7XG4gICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICBydW5QYXRoLFxuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHJ1biwganNvblJlcGxhY2VyLCAyKVxuICAgICAgICApO1xuICAgICAgICBpZiAoIWNyZWF0ZWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgIGBXb3JrZmxvdyBydW4gXCIke2VmZmVjdGl2ZVJ1bklkfVwiIGFscmVhZHkgZXhpc3RzYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcpIHtcbiAgICAgICAgLy8gUmV1c2UgY3VycmVudFJ1biBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHtcbiAgICAgICAgICAvLyBJZiBhbHJlYWR5IHJ1bm5pbmcsIHJldHVybiB0aGUgcnVuIHdpdGhvdXQgaW5zZXJ0aW5nIGFcbiAgICAgICAgICAvLyBkdXBsaWNhdGUgZXZlbnQuICBUaGlzIG1ha2VzIHJ1bl9zdGFydGVkIGlkZW1wb3RlbnQgZm9yXG4gICAgICAgICAgLy8gY29uY3VycmVudCBpbnZvY2F0aW9ucy4gIFdlIG9taXQgcHJlbG9hZGVkIGV2ZW50cyBoZXJlXG4gICAgICAgICAgLy8gYmVjYXVzZSB0aGlzIGlzIGEgcmFyZSByYWNlLWNvbmRpdGlvbiBwYXRoIOKAlCB0aGUgcnVudGltZVxuICAgICAgICAgIC8vIGZhbGxzIGJhY2sgdG8gbG9hZGluZyBldmVudHMgc2VwYXJhdGVseS5cbiAgICAgICAgICBpZiAoY3VycmVudFJ1bi5zdGF0dXMgPT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIHsgcnVuOiBjdXJyZW50UnVuIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcnVuID0ge1xuICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBjdXJyZW50UnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgaW5wdXQ6IGN1cnJlbnRSdW4uaW5wdXQsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgIHN0YXR1czogJ3J1bm5pbmcnLFxuICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgY29tcGxldGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIHN0YXJ0ZWRBdDogY3VycmVudFJ1bi5zdGFydGVkQXQgPz8gbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICBydW4sXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jb21wbGV0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgY29uc3QgY29tcGxldGVkRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHsgb3V0cHV0PzogYW55IH07XG4gICAgICAgIC8vIFJldXNlIGN1cnJlbnRSdW4gZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgcnVuID0ge1xuICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBjdXJyZW50UnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgaW5wdXQ6IGN1cnJlbnRSdW4uaW5wdXQsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgIHN0YXJ0ZWRBdDogY3VycmVudFJ1bi5zdGFydGVkQXQsXG4gICAgICAgICAgICBzdGF0dXM6ICdjb21wbGV0ZWQnLFxuICAgICAgICAgICAgb3V0cHV0OiBjb21wbGV0ZWREYXRhLm91dHB1dCxcbiAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICBydW4sXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgICBkZWxldGVBbGxIb29rc0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgXSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fZmFpbGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgIGNvbnN0IGZhaWxlZERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgZXJyb3I6IGFueTtcbiAgICAgICAgICBlcnJvckNvZGU/OiBzdHJpbmc7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFJldXNlIGN1cnJlbnRSdW4gZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgcnVuID0ge1xuICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBjdXJyZW50UnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgaW5wdXQ6IGN1cnJlbnRSdW4uaW5wdXQsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgIHN0YXJ0ZWRBdDogY3VycmVudFJ1bi5zdGFydGVkQXQsXG4gICAgICAgICAgICBzdGF0dXM6ICdmYWlsZWQnLFxuICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBlcnJvcjoge1xuICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgIHR5cGVvZiBmYWlsZWREYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgICAgPyBmYWlsZWREYXRhLmVycm9yXG4gICAgICAgICAgICAgICAgICA6IChmYWlsZWREYXRhLmVycm9yPy5tZXNzYWdlID8/ICdVbmtub3duIGVycm9yJyksXG4gICAgICAgICAgICAgIHN0YWNrOiBmYWlsZWREYXRhLmVycm9yPy5zdGFjayxcbiAgICAgICAgICAgICAgY29kZTogZmFpbGVkRGF0YS5lcnJvckNvZGUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAncnVucycsIGVmZmVjdGl2ZVJ1bklkLCB0YWcpLFxuICAgICAgICAgICAgcnVuLFxuICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgZGVsZXRlQWxsV2FpdHNGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NhbmNlbGxlZCcpIHtcbiAgICAgICAgLy8gUmV1c2UgY3VycmVudFJ1biBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHtcbiAgICAgICAgICBydW4gPSB7XG4gICAgICAgICAgICBydW5JZDogY3VycmVudFJ1bi5ydW5JZCxcbiAgICAgICAgICAgIGRlcGxveW1lbnRJZDogY3VycmVudFJ1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICB3b3JrZmxvd05hbWU6IGN1cnJlbnRSdW4ud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGN1cnJlbnRSdW4uc3BlY1ZlcnNpb24sXG4gICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBjdXJyZW50UnVuLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICBpbnB1dDogY3VycmVudFJ1bi5pbnB1dCxcbiAgICAgICAgICAgIGNyZWF0ZWRBdDogY3VycmVudFJ1bi5jcmVhdGVkQXQsXG4gICAgICAgICAgICBleHBpcmVkQXQ6IGN1cnJlbnRSdW4uZXhwaXJlZEF0LFxuICAgICAgICAgICAgc3RhcnRlZEF0OiBjdXJyZW50UnVuLnN0YXJ0ZWRBdCxcbiAgICAgICAgICAgIHN0YXR1czogJ2NhbmNlbGxlZCcsXG4gICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICBydW4sXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgICBkZWxldGVBbGxIb29rc0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgXSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIC8vIFN0ZXAgbGlmZWN5Y2xlIGV2ZW50c1xuICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfY3JlYXRlZCcgJiZcbiAgICAgICAgJ2V2ZW50RGF0YScgaW4gZGF0YVxuICAgICAgKSB7XG4gICAgICAgIC8vIHN0ZXBfY3JlYXRlZDogQ3JlYXRlcyBzdGVwIGVudGl0eSB3aXRoIHN0YXR1cyAncGVuZGluZycsIGF0dGVtcHQ9MCwgY3JlYXRlZEF0IHNldFxuICAgICAgICBjb25zdCBzdGVwRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICBzdGVwTmFtZTogc3RyaW5nO1xuICAgICAgICAgIGlucHV0OiBhbnk7XG4gICAgICAgIH07XG4gICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgIHN0ZXBJZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIHN0ZXBOYW1lOiBzdGVwRGF0YS5zdGVwTmFtZSxcbiAgICAgICAgICBzdGF0dXM6ICdwZW5kaW5nJyxcbiAgICAgICAgICBpbnB1dDogc3RlcERhdGEuaW5wdXQsXG4gICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICBhdHRlbXB0OiAwLFxuICAgICAgICAgIHN0YXJ0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgLy8gUHJvcGFnYXRlIHNwZWNWZXJzaW9uIGZyb20gdGhlIGV2ZW50IHRvIHRoZSBzdGVwIGVudGl0eVxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3Qgc3RlcENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnc3RlcHMnLCBzdGVwQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgIHN0ZXBcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX3N0YXJ0ZWQnKSB7XG4gICAgICAgIC8vIHN0ZXBfc3RhcnRlZDogSW5jcmVtZW50cyBhdHRlbXB0LCBzZXRzIHN0YXR1cyB0byAncnVubmluZydcbiAgICAgICAgLy8gU2V0cyBzdGFydGVkQXQgb25seSBvbiB0aGUgZmlyc3Qgc3RhcnQgKG5vdCB1cGRhdGVkIG9uIHJldHJpZXMpXG4gICAgICAgIC8vIFJldXNlIHZhbGlkYXRlZFN0ZXAgZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgIGlmICh2YWxpZGF0ZWRTdGVwKSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgcmV0cnlBZnRlciB0aW1lc3RhbXAgaGFzbid0IGJlZW4gcmVhY2hlZCB5ZXRcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICB2YWxpZGF0ZWRTdGVwLnJldHJ5QWZ0ZXIgJiZcbiAgICAgICAgICAgIHZhbGlkYXRlZFN0ZXAucmV0cnlBZnRlci5nZXRUaW1lKCkgPiBEYXRlLm5vdygpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVG9vRWFybHlFcnJvcihcbiAgICAgICAgICAgICAgYENhbm5vdCBzdGFydCBzdGVwIFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCI6IHJldHJ5QWZ0ZXIgdGltZXN0YW1wIGhhcyBub3QgYmVlbiByZWFjaGVkIHlldGAsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXRyeUFmdGVyOiBNYXRoLmNlaWwoXG4gICAgICAgICAgICAgICAgICAodmFsaWRhdGVkU3RlcC5yZXRyeUFmdGVyLmdldFRpbWUoKSAtIERhdGUubm93KCkpIC8gMTAwMFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQmVzdC1lZmZvcnQgZ3VhcmQ6IHJlLXJlYWQgdGhlIHN0ZXAgZW50aXR5IHRvIGNoZWNrIGlmIGl0XG4gICAgICAgICAgLy8gcmVhY2hlZCB0ZXJtaW5hbCBzdGF0ZSBiZXR3ZWVuIHRoZSB2YWxpZGF0aW9uIHJlYWQgYW5kIG5vdy5cbiAgICAgICAgICAvLyBUaGlzIG5hcnJvd3MgdGhlIFRPQ1RPVSB3aW5kb3cgYnV0IGRvZXMgbm90IGZ1bGx5IGVsaW1pbmF0ZSBpdFxuICAgICAgICAgIC8vICh0aGUgbG9jYWwgd29ybGQgaXMgc2luZ2xlLXByb2Nlc3MgLyBkZXYtb25seTsgdGhlIHBvc3RncmVzXG4gICAgICAgICAgLy8gd29ybGQgdXNlcyBTUUwtbGV2ZWwgYXRvbWljIGd1YXJkcyBmb3IgcHJvZHVjdGlvbikuXG4gICAgICAgICAgY29uc3Qgc3RlcENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICAgIGNvbnN0IGZyZXNoU3RlcCA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdzdGVwcycsXG4gICAgICAgICAgICBzdGVwQ29tcG9zaXRlS2V5LFxuICAgICAgICAgICAgU3RlcFNjaGVtYSxcbiAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKGZyZXNoU3RlcCAmJiBpc1N0ZXBUZXJtaW5hbChmcmVzaFN0ZXAuc3RhdHVzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBDYW5ub3QgbW9kaWZ5IHN0ZXAgaW4gdGVybWluYWwgc3RhdGUgXCIke2ZyZXNoU3RlcC5zdGF0dXN9XCJgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICAuLi52YWxpZGF0ZWRTdGVwLFxuICAgICAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgICAgICAvLyBPbmx5IHNldCBzdGFydGVkQXQgb24gdGhlIGZpcnN0IHN0YXJ0XG4gICAgICAgICAgICBzdGFydGVkQXQ6IHZhbGlkYXRlZFN0ZXAuc3RhcnRlZEF0ID8/IG5vdyxcbiAgICAgICAgICAgIC8vIEluY3JlbWVudCBhdHRlbXB0IGNvdW50ZXIgb24gZXZlcnkgc3RhcnRcbiAgICAgICAgICAgIGF0dGVtcHQ6IHZhbGlkYXRlZFN0ZXAuYXR0ZW1wdCArIDEsXG4gICAgICAgICAgICAvLyBDbGVhciByZXRyeUFmdGVyIG5vdyB0aGF0IHRoZSBzdGVwIGhhcyBzdGFydGVkXG4gICAgICAgICAgICByZXRyeUFmdGVyOiB1bmRlZmluZWQsXG4gICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3N0ZXBzJywgc3RlcENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfY29tcGxldGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgIC8vIHN0ZXBfY29tcGxldGVkOiBUZXJtaW5hbCBzdGF0ZSB3aXRoIG91dHB1dFxuICAgICAgICAvLyBVc2VzIHdyaXRlRXhjbHVzaXZlIG9uIGEgbG9jayBmaWxlIHRvIGF0b21pY2FsbHkgcHJldmVudCBjb25jdXJyZW50XG4gICAgICAgIC8vIGludm9jYXRpb25zIGZyb20gYm90aCBjb21wbGV0aW5nIHRoZSBzYW1lIHN0ZXAgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgY29uc3QgY29tcGxldGVkRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHsgcmVzdWx0OiBhbnkgfTtcbiAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgY29uc3QgbG9ja05hbWUgPSB0YWdcbiAgICAgICAgICAgID8gYCR7c3RlcENvbXBvc2l0ZUtleX0udGVybWluYWwuJHt0YWd9YFxuICAgICAgICAgICAgOiBgJHtzdGVwQ29tcG9zaXRlS2V5fS50ZXJtaW5hbGA7XG4gICAgICAgICAgY29uc3QgdGVybWluYWxMb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgJ3N0ZXBzJyxcbiAgICAgICAgICAgIGxvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUodGVybWluYWxMb2NrUGF0aCwgJycpO1xuICAgICAgICAgIGlmICghY2xhaW1lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICdDYW5ub3QgbW9kaWZ5IHN0ZXAgaW4gdGVybWluYWwgc3RhdGUnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBzdGVwID0ge1xuICAgICAgICAgICAgLi4udmFsaWRhdGVkU3RlcCxcbiAgICAgICAgICAgIHN0YXR1czogJ2NvbXBsZXRlZCcsXG4gICAgICAgICAgICBvdXRwdXQ6IGNvbXBsZXRlZERhdGEucmVzdWx0LFxuICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnc3RlcHMnLCBzdGVwQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9mYWlsZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgLy8gc3RlcF9mYWlsZWQ6IFRlcm1pbmFsIHN0YXRlIHdpdGggZXJyb3JcbiAgICAgICAgLy8gVXNlcyB3cml0ZUV4Y2x1c2l2ZSBvbiBhIGxvY2sgZmlsZSB0byBhdG9taWNhbGx5IHByZXZlbnQgY29uY3VycmVudFxuICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggZmFpbGluZyB0aGUgc2FtZSBzdGVwIChUT0NUT1UgcmFjZSkuXG4gICAgICAgIGNvbnN0IGZhaWxlZERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgZXJyb3I6IGFueTtcbiAgICAgICAgICBzdGFjaz86IHN0cmluZztcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgY29uc3QgbG9ja05hbWUgPSB0YWdcbiAgICAgICAgICAgID8gYCR7c3RlcENvbXBvc2l0ZUtleX0udGVybWluYWwuJHt0YWd9YFxuICAgICAgICAgICAgOiBgJHtzdGVwQ29tcG9zaXRlS2V5fS50ZXJtaW5hbGA7XG4gICAgICAgICAgY29uc3QgdGVybWluYWxMb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgJ3N0ZXBzJyxcbiAgICAgICAgICAgIGxvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUodGVybWluYWxMb2NrUGF0aCwgJycpO1xuICAgICAgICAgIGlmICghY2xhaW1lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICdDYW5ub3QgbW9kaWZ5IHN0ZXAgaW4gdGVybWluYWwgc3RhdGUnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBlcnJvciA9IHtcbiAgICAgICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgICAgIHR5cGVvZiBmYWlsZWREYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgID8gZmFpbGVkRGF0YS5lcnJvclxuICAgICAgICAgICAgICAgIDogKGZhaWxlZERhdGEuZXJyb3I/Lm1lc3NhZ2UgPz8gJ1Vua25vd24gZXJyb3InKSxcbiAgICAgICAgICAgIHN0YWNrOiBmYWlsZWREYXRhLnN0YWNrLFxuICAgICAgICAgIH07XG4gICAgICAgICAgc3RlcCA9IHtcbiAgICAgICAgICAgIC4uLnZhbGlkYXRlZFN0ZXAsXG4gICAgICAgICAgICBzdGF0dXM6ICdmYWlsZWQnLFxuICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX3JldHJ5aW5nJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgIC8vIHN0ZXBfcmV0cnlpbmc6IFNldHMgc3RhdHVzIGJhY2sgdG8gJ3BlbmRpbmcnLCByZWNvcmRzIGVycm9yXG4gICAgICAgIC8vIFJldXNlIHZhbGlkYXRlZFN0ZXAgZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgIGNvbnN0IHJldHJ5RGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICBlcnJvcjogYW55O1xuICAgICAgICAgIHN0YWNrPzogc3RyaW5nO1xuICAgICAgICAgIHJldHJ5QWZ0ZXI/OiBEYXRlO1xuICAgICAgICB9O1xuICAgICAgICBpZiAodmFsaWRhdGVkU3RlcCkge1xuICAgICAgICAgIGNvbnN0IHN0ZXBDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgICBzdGVwID0ge1xuICAgICAgICAgICAgLi4udmFsaWRhdGVkU3RlcCxcbiAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICB0eXBlb2YgcmV0cnlEYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgICAgPyByZXRyeURhdGEuZXJyb3JcbiAgICAgICAgICAgICAgICAgIDogKHJldHJ5RGF0YS5lcnJvcj8ubWVzc2FnZSA/PyAnVW5rbm93biBlcnJvcicpLFxuICAgICAgICAgICAgICBzdGFjazogcmV0cnlEYXRhLnN0YWNrLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJldHJ5QWZ0ZXI6IHJldHJ5RGF0YS5yZXRyeUFmdGVyLFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIC8vIEhvb2sgbGlmZWN5Y2xlIGV2ZW50c1xuICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfY3JlYXRlZCcgJiZcbiAgICAgICAgJ2V2ZW50RGF0YScgaW4gZGF0YVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGhvb2tEYXRhID0gZGF0YS5ldmVudERhdGEgYXMge1xuICAgICAgICAgIHRva2VuOiBzdHJpbmc7XG4gICAgICAgICAgbWV0YWRhdGE/OiBhbnk7XG4gICAgICAgICAgaXNXZWJob29rPzogYm9vbGVhbjtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBBdG9taWNhbGx5IGNsYWltIHRoZSB0b2tlbiB1c2luZyBhbiBleGNsdXNpdmUtY3JlYXRlIGNvbnN0cmFpbnQgZmlsZS5cbiAgICAgICAgLy8gVGhpcyBhdm9pZHMgdGhlIFRPQ1RPVSByYWNlIG9mIHRoZSBwcmV2aW91cyByZWFkLWFsbC10aGVuLWNoZWNrIGFwcHJvYWNoLlxuICAgICAgICBjb25zdCBjb25zdHJhaW50UGF0aCA9IHBhdGguam9pbihcbiAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgJ3Rva2VucycsXG4gICAgICAgICAgYCR7aGFzaFRva2VuKGhvb2tEYXRhLnRva2VuKX0uanNvbmBcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdG9rZW5DbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUoXG4gICAgICAgICAgY29uc3RyYWludFBhdGgsXG4gICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgdG9rZW46IGhvb2tEYXRhLnRva2VuLFxuICAgICAgICAgICAgaG9va0lkOiBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIXRva2VuQ2xhaW1lZCkge1xuICAgICAgICAgIGNvbnN0IGV4aXN0aW5nQ2xhaW0gPSBhd2FpdCByZWFkSG9va1Rva2VuQ2xhaW0oY29uc3RyYWludFBhdGgpO1xuXG4gICAgICAgICAgLy8gQ3JlYXRlIGhvb2tfY29uZmxpY3QgZXZlbnQgaW5zdGVhZCBvZiBob29rX2NyZWF0ZWRcbiAgICAgICAgICAvLyBUaGlzIGFsbG93cyB0aGUgd29ya2Zsb3cgdG8gY29udGludWUgYW5kIGZhaWwgZ3JhY2VmdWxseSB3aGVuIHRoZSBob29rIGlzIGF3YWl0ZWRcbiAgICAgICAgICBjb25zdCBjb25mbGljdEV2ZW50OiBFdmVudCA9IHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfY29uZmxpY3QnLFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgIHRva2VuOiBob29rRGF0YS50b2tlbixcbiAgICAgICAgICAgICAgLi4uKGV4aXN0aW5nQ2xhaW1cbiAgICAgICAgICAgICAgICA/IHsgY29uZmxpY3RpbmdSdW5JZDogZXhpc3RpbmdDbGFpbS5ydW5JZCB9XG4gICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICAvLyBTdG9yZSB0aGUgY29uZmxpY3QgZXZlbnRcbiAgICAgICAgICBjb25zdCBjb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtldmVudElkfWA7XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnZXZlbnRzJywgY29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgY29uZmxpY3RFdmVudFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCByZXNvbHZlRGF0YSA9XG4gICAgICAgICAgICBwYXJhbXM/LnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgICAgICBjb25zdCBmaWx0ZXJlZEV2ZW50ID0gc3RyaXBFdmVudERhdGFSZWZzKGNvbmZsaWN0RXZlbnQsIHJlc29sdmVEYXRhKTtcblxuICAgICAgICAgIC8vIFJldHVybiBFdmVudFJlc3VsdCB3aXRoIGNvbmZsaWN0IGV2ZW50IChubyBob29rIGVudGl0eSBjcmVhdGVkKVxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBldmVudDogZmlsdGVyZWRFdmVudCxcbiAgICAgICAgICAgIHJ1bixcbiAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICBob29rOiB1bmRlZmluZWQsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGhvb2sgPSB7XG4gICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgIGhvb2tJZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIHRva2VuOiBob29rRGF0YS50b2tlbixcbiAgICAgICAgICBtZXRhZGF0YTogaG9va0RhdGEubWV0YWRhdGEsXG4gICAgICAgICAgb3duZXJJZDogJ2xvY2FsLW93bmVyJyxcbiAgICAgICAgICBwcm9qZWN0SWQ6ICdsb2NhbC1wcm9qZWN0JyxcbiAgICAgICAgICBlbnZpcm9ubWVudDogJ2xvY2FsJyxcbiAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAvLyBQcm9wYWdhdGUgc3BlY1ZlcnNpb24gZnJvbSB0aGUgZXZlbnQgdG8gdGhlIGhvb2sgZW50aXR5XG4gICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgIGlzV2ViaG9vazogaG9va0RhdGEuaXNXZWJob29rID8/IGZhbHNlLFxuICAgICAgICB9O1xuICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnaG9va3MnLCBkYXRhLmNvcnJlbGF0aW9uSWQsIHRhZyksXG4gICAgICAgICAgaG9va1xuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfZGlzcG9zZWQnKSB7XG4gICAgICAgIC8vIGhvb2tfZGlzcG9zZWQ6IERlbGV0ZXMgaG9vayBlbnRpdHksIHJlamVjdHMgZHVwbGljYXRlcy5cbiAgICAgICAgLy8gVXNlcyB3cml0ZUV4Y2x1c2l2ZSBvbiBhIGxvY2sgZmlsZSB0byBhdG9taWNhbGx5IHByZXZlbnQgY29uY3VycmVudFxuICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggZGlzcG9zaW5nIHRoZSBzYW1lIGhvb2sgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgY29uc3QgaG9va0xvY2tOYW1lID0gdGFnXG4gICAgICAgICAgPyBgJHtkYXRhLmNvcnJlbGF0aW9uSWR9LmRpc3Bvc2VkLiR7dGFnfWBcbiAgICAgICAgICA6IGAke2RhdGEuY29ycmVsYXRpb25JZH0uZGlzcG9zZWRgO1xuICAgICAgICBjb25zdCBsb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgJ2hvb2tzJyxcbiAgICAgICAgICBob29rTG9ja05hbWVcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKGxvY2tQYXRoLCAnJyk7XG4gICAgICAgIGlmICghY2xhaW1lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgYEhvb2sgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBhbHJlYWR5IGRpc3Bvc2VkYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUmVhZCB0aGUgaG9vayB0byBnZXQgaXRzIHRva2VuIGJlZm9yZSBkZWxldGluZ1xuICAgICAgICBjb25zdCBob29rUGF0aCA9IHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2hvb2tzJywgZGF0YS5jb3JyZWxhdGlvbklkLCB0YWcpO1xuICAgICAgICBjb25zdCBleGlzdGluZ0hvb2sgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIEhvb2tTY2hlbWEsXG4gICAgICAgICAgdGFnXG4gICAgICAgICk7XG4gICAgICAgIGlmIChleGlzdGluZ0hvb2spIHtcbiAgICAgICAgICAvLyBEZWxldGUgdGhlIHRva2VuIGNvbnN0cmFpbnQgZmlsZSB0byBmcmVlIHVwIHRoZSB0b2tlbiBmb3IgcmV1c2VcbiAgICAgICAgICBjb25zdCBkaXNwb3NlZENvbnN0cmFpbnRQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICAndG9rZW5zJyxcbiAgICAgICAgICAgIGAke2hhc2hUb2tlbihleGlzdGluZ0hvb2sudG9rZW4pfS5qc29uYFxuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgZGVsZXRlSlNPTihkaXNwb3NlZENvbnN0cmFpbnRQYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBkZWxldGVKU09OKGhvb2tQYXRoKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICd3YWl0X2NyZWF0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgLy8gd2FpdF9jcmVhdGVkOiBDcmVhdGVzIHdhaXQgZW50aXR5IHdpdGggc3RhdHVzICd3YWl0aW5nJ1xuICAgICAgICBjb25zdCB3YWl0RGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICByZXN1bWVBdD86IERhdGU7XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHdhaXRDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgY29uc3QgZXhpc3RpbmdXYWl0ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAnd2FpdHMnLFxuICAgICAgICAgIHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgV2FpdFNjaGVtYSxcbiAgICAgICAgICB0YWdcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGV4aXN0aW5nV2FpdCkge1xuICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBhbHJlYWR5IGV4aXN0c2BcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHdhaXQgPSB7XG4gICAgICAgICAgd2FpdElkOiB3YWl0Q29tcG9zaXRlS2V5LFxuICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICBzdGF0dXM6ICd3YWl0aW5nJyxcbiAgICAgICAgICByZXN1bWVBdDogd2FpdERhdGEucmVzdW1lQXQsXG4gICAgICAgICAgY29tcGxldGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgIH07XG4gICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICd3YWl0cycsIHdhaXRDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgd2FpdFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY29tcGxldGVkJykge1xuICAgICAgICAvLyB3YWl0X2NvbXBsZXRlZDogVHJhbnNpdGlvbnMgd2FpdCB0byAnY29tcGxldGVkJywgcmVqZWN0cyBkdXBsaWNhdGVzLlxuICAgICAgICAvLyBVc2VzIHdyaXRlRXhjbHVzaXZlIG9uIGEgbG9jayBmaWxlIHRvIGF0b21pY2FsbHkgcHJldmVudCBjb25jdXJyZW50XG4gICAgICAgIC8vIGludm9jYXRpb25zIGZyb20gYm90aCBjb21wbGV0aW5nIHRoZSBzYW1lIHdhaXQgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgY29uc3Qgd2FpdENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICBjb25zdCB3YWl0TG9ja05hbWUgPSB0YWdcbiAgICAgICAgICA/IGAke3dhaXRDb21wb3NpdGVLZXl9LmNvbXBsZXRlZC4ke3RhZ31gXG4gICAgICAgICAgOiBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jb21wbGV0ZWRgO1xuICAgICAgICBjb25zdCBsb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICB3YWl0TG9ja05hbWVcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKGxvY2tQYXRoLCAnJyk7XG4gICAgICAgIGlmICghY2xhaW1lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBhbHJlYWR5IGNvbXBsZXRlZGBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGV4aXN0aW5nV2FpdCA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICB3YWl0Q29tcG9zaXRlS2V5LFxuICAgICAgICAgIFdhaXRTY2hlbWEsXG4gICAgICAgICAgdGFnXG4gICAgICAgICk7XG4gICAgICAgIGlmICghZXhpc3RpbmdXYWl0KSB7XG4gICAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGxvY2sgZmlsZSB3ZSBqdXN0IGNsYWltZWQg4oCUIHRoZSB3YWl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgICAgICBhd2FpdCBmcy51bmxpbmsobG9ja1BhdGgpLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dXb3JsZEVycm9yKFxuICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBub3QgZm91bmRgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUaGUgbG9jayBmaWxlICh3cml0ZUV4Y2x1c2l2ZSBhYm92ZSkgYWxyZWFkeSBwcmV2ZW50cyBjb25jdXJyZW50XG4gICAgICAgIC8vIGNvbXBsZXRpb25zIOKAlCBubyBhZGRpdGlvbmFsIHN0YXR1cyBjaGVjayBuZWVkZWQuXG4gICAgICAgIHdhaXQgPSB7XG4gICAgICAgICAgLi4uZXhpc3RpbmdXYWl0LFxuICAgICAgICAgIHN0YXR1czogJ2NvbXBsZXRlZCcsXG4gICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgfTtcbiAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3dhaXRzJywgd2FpdENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICB3YWl0LFxuICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIC8vIE5vdGU6IGhvb2tfcmVjZWl2ZWQgZXZlbnRzIGFyZSBzdG9yZWQgaW4gdGhlIGV2ZW50IGxvZyBidXQgZG9uJ3RcbiAgICAgIC8vIG1vZGlmeSB0aGUgSG9vayBlbnRpdHkgKHdoaWNoIGRvZXNuJ3QgaGF2ZSBhIHBheWxvYWQgZmllbGQpXG5cbiAgICAgIC8vIFN0b3JlIGV2ZW50IHVzaW5nIGNvbXBvc2l0ZSBrZXkge3J1bklkfS17ZXZlbnRJZH1cbiAgICAgIGNvbnN0IGNvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2V2ZW50SWR9YDtcbiAgICAgIGF3YWl0IHdyaXRlSlNPTih0YWdnZWRQYXRoKGJhc2VkaXIsICdldmVudHMnLCBjb21wb3NpdGVLZXksIHRhZyksIGV2ZW50KTtcblxuICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPSBwYXJhbXM/LnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgIGNvbnN0IGZpbHRlcmVkRXZlbnQgPSBzdHJpcEV2ZW50RGF0YVJlZnMoZXZlbnQsIHJlc29sdmVEYXRhKTtcblxuICAgICAgLy8gRm9yIHJ1bl9zdGFydGVkOiBpbmNsdWRlIGFsbCBldmVudHMgc28gdGhlIHJ1bnRpbWUgY2FuIHNraXBcbiAgICAgIC8vIHRoZSBpbml0aWFsIGV2ZW50cy5saXN0IGNhbGwgYW5kIHJlZHVjZSBUVEZCLlxuICAgICAgbGV0IGV2ZW50czogRXZlbnRbXSB8IHVuZGVmaW5lZDtcbiAgICAgIGxldCBjdXJzb3I6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQ7XG4gICAgICBsZXQgaGFzTW9yZTogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJyAmJiBydW4pIHtcbiAgICAgICAgY29uc3QgYWxsRXZlbnRzID0gYXdhaXQgcGFnaW5hdGVkRmlsZVN5c3RlbVF1ZXJ5KHtcbiAgICAgICAgICBkaXJlY3Rvcnk6IHBhdGguam9pbihiYXNlZGlyLCAnZXZlbnRzJyksXG4gICAgICAgICAgc2NoZW1hOiBFdmVudFNjaGVtYSxcbiAgICAgICAgICBmaWxlUHJlZml4OiBgJHtlZmZlY3RpdmVSdW5JZH0tYCxcbiAgICAgICAgICBzb3J0T3JkZXI6ICdhc2MnLFxuICAgICAgICAgIGxpbWl0OiAxMDAwLFxuICAgICAgICAgIGdldENyZWF0ZWRBdDogZ2V0T2JqZWN0Q3JlYXRlZEF0KCdldm50JyksXG4gICAgICAgICAgZ2V0SWQ6IChlKSA9PiBlLmV2ZW50SWQsXG4gICAgICAgIH0pO1xuICAgICAgICBldmVudHMgPSBhbGxFdmVudHMuZGF0YTtcbiAgICAgICAgY3Vyc29yID0gYWxsRXZlbnRzLmN1cnNvcjtcbiAgICAgICAgaGFzTW9yZSA9IGFsbEV2ZW50cy5oYXNNb3JlO1xuICAgICAgfVxuXG4gICAgICAvLyBSZXR1cm4gRXZlbnRSZXN1bHQgd2l0aCBldmVudCBhbmQgYW55IGNyZWF0ZWQvdXBkYXRlZCBlbnRpdHlcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGV2ZW50OiBmaWx0ZXJlZEV2ZW50LFxuICAgICAgICBydW4sXG4gICAgICAgIHN0ZXAsXG4gICAgICAgIGhvb2ssXG4gICAgICAgIHdhaXQsXG4gICAgICAgIGV2ZW50cyxcbiAgICAgICAgY3Vyc29yLFxuICAgICAgICBoYXNNb3JlLFxuICAgICAgfTtcbiAgICB9LFxuXG4gICAgYXN5bmMgZ2V0KHJ1bklkLCBldmVudElkLCBwYXJhbXMpIHtcbiAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgncnVuSWQnLCBydW5JZCk7XG4gICAgICBhc3NlcnRTYWZlRW50aXR5SWQoJ2V2ZW50SWQnLCBldmVudElkKTtcbiAgICAgIGNvbnN0IGNvbXBvc2l0ZUtleSA9IGAke3J1bklkfS0ke2V2ZW50SWR9YDtcbiAgICAgIGNvbnN0IGV2ZW50ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgIGJhc2VkaXIsXG4gICAgICAgICdldmVudHMnLFxuICAgICAgICBjb21wb3NpdGVLZXksXG4gICAgICAgIEV2ZW50U2NoZW1hLFxuICAgICAgICB0YWdcbiAgICAgICk7XG4gICAgICBpZiAoIWV2ZW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXZlbnQgJHtldmVudElkfSBpbiBydW4gJHtydW5JZH0gbm90IGZvdW5kYCk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXNvbHZlRGF0YSA9IHBhcmFtcz8ucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgcmV0dXJuIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpO1xuICAgIH0sXG5cbiAgICBhc3luYyBsaXN0KHBhcmFtcykge1xuICAgICAgY29uc3QgeyBydW5JZCB9ID0gcGFyYW1zO1xuICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdydW5JZCcsIHJ1bklkKTtcbiAgICAgIGNvbnN0IHJlc29sdmVEYXRhID0gcGFyYW1zLnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSh7XG4gICAgICAgIGRpcmVjdG9yeTogcGF0aC5qb2luKGJhc2VkaXIsICdldmVudHMnKSxcbiAgICAgICAgc2NoZW1hOiBFdmVudFNjaGVtYSxcbiAgICAgICAgZmlsZVByZWZpeDogYCR7cnVuSWR9LWAsXG4gICAgICAgIC8vIEV2ZW50cyBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIChvbGRlc3QgZmlyc3QpIGJ5IGRlZmF1bHQsXG4gICAgICAgIC8vIGRpZmZlcmVudCBmcm9tIHRoZSBkZWZhdWx0IGZvciBvdGhlciBsaXN0IGNhbGxzLlxuICAgICAgICBzb3J0T3JkZXI6IHBhcmFtcy5wYWdpbmF0aW9uPy5zb3J0T3JkZXIgPz8gJ2FzYycsXG4gICAgICAgIGxpbWl0OiBwYXJhbXMucGFnaW5hdGlvbj8ubGltaXQsXG4gICAgICAgIGN1cnNvcjogcGFyYW1zLnBhZ2luYXRpb24/LmN1cnNvcixcbiAgICAgICAgZ2V0Q3JlYXRlZEF0OiBnZXRPYmplY3RDcmVhdGVkQXQoJ2V2bnQnKSxcbiAgICAgICAgZ2V0SWQ6IChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBJZiByZXNvbHZlRGF0YSBpcyBcIm5vbmVcIiwgcmVtb3ZlIGV2ZW50RGF0YSBmcm9tIGV2ZW50c1xuICAgICAgaWYgKHJlc29sdmVEYXRhID09PSAnbm9uZScpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5yZXN1bHQsXG4gICAgICAgICAgZGF0YTogcmVzdWx0LmRhdGEubWFwKChldmVudCkgPT5cbiAgICAgICAgICAgIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpXG4gICAgICAgICAgKSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgYXN5bmMgbGlzdEJ5Q29ycmVsYXRpb25JZChwYXJhbXMpIHtcbiAgICAgIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBwYXJhbXMuY29ycmVsYXRpb25JZDtcbiAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgnY29ycmVsYXRpb25JZCcsIGNvcnJlbGF0aW9uSWQpO1xuICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPSBwYXJhbXMucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGFnaW5hdGVkRmlsZVN5c3RlbVF1ZXJ5KHtcbiAgICAgICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oYmFzZWRpciwgJ2V2ZW50cycpLFxuICAgICAgICBzY2hlbWE6IEV2ZW50U2NoZW1hLFxuICAgICAgICAvLyBObyBmaWxlUHJlZml4IC0gc2VhcmNoIGFsbCBldmVudHNcbiAgICAgICAgZmlsdGVyOiAoZXZlbnQpID0+IGV2ZW50LmNvcnJlbGF0aW9uSWQgPT09IGNvcnJlbGF0aW9uSWQsXG4gICAgICAgIC8vIEV2ZW50cyBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIChvbGRlc3QgZmlyc3QpIGJ5IGRlZmF1bHQsXG4gICAgICAgIC8vIGRpZmZlcmVudCBmcm9tIHRoZSBkZWZhdWx0IGZvciBvdGhlciBsaXN0IGNhbGxzLlxuICAgICAgICBzb3J0T3JkZXI6IHBhcmFtcy5wYWdpbmF0aW9uPy5zb3J0T3JkZXIgPz8gJ2FzYycsXG4gICAgICAgIGxpbWl0OiBwYXJhbXMucGFnaW5hdGlvbj8ubGltaXQsXG4gICAgICAgIGN1cnNvcjogcGFyYW1zLnBhZ2luYXRpb24/LmN1cnNvcixcbiAgICAgICAgZ2V0Q3JlYXRlZEF0OiBnZXRPYmplY3RDcmVhdGVkQXQoJ2V2bnQnKSxcbiAgICAgICAgZ2V0SWQ6IChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBJZiByZXNvbHZlRGF0YSBpcyBcIm5vbmVcIiwgcmVtb3ZlIGV2ZW50RGF0YSBmcm9tIGV2ZW50c1xuICAgICAgaWYgKHJlc29sdmVEYXRhID09PSAnbm9uZScpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5yZXN1bHQsXG4gICAgICAgICAgZGF0YTogcmVzdWx0LmRhdGEubWFwKChldmVudCkgPT5cbiAgICAgICAgICAgIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpXG4gICAgICAgICAgKSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuICB9O1xufVxuIl19
1222
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLXN0b3JhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9ldmVudHMtc3RvcmFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsQyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixpQkFBaUIsRUFDakIsZUFBZSxFQUNmLG9CQUFvQixFQUNwQixhQUFhLEVBQ2Isa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFXMUIsT0FBTyxFQUNMLFdBQVcsRUFDWCxVQUFVLEVBQ1YsbUJBQW1CLEVBQ25CLG9CQUFvQixFQUNwQiwyQkFBMkIsRUFDM0Isa0JBQWtCLEVBQ2xCLG9CQUFvQixFQUNwQixVQUFVLEVBQ1YsVUFBVSxFQUNWLHFCQUFxQixFQUNyQixVQUFVLEVBQ1YsaUJBQWlCLEdBQ2xCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUN4QixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0QsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixVQUFVLEVBQ1YsWUFBWSxFQUNaLGFBQWEsRUFDYix3QkFBd0IsRUFDeEIsUUFBUSxFQUNSLG9CQUFvQixFQUNwQixpQkFBaUIsRUFDakIsVUFBVSxFQUNWLGNBQWMsRUFDZCxTQUFTLEdBQ1YsTUFBTSxVQUFVLENBQUM7QUFDbEIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsU0FBUyxFQUNULHNCQUFzQixFQUN0QixhQUFhLEdBQ2QsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixrQ0FBa0MsR0FDbkMsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVB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LGVBQWUsRUFBRSxhQUFhLENBQUMsQ0FBQztZQUNuRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxJQUFJLDJCQUEyQixDQUFDO1lBQ3RFLE1BQU0sTUFBTSxHQUFHLE1BQU0sd0JBQXdCLENBQUM7Z0JBQzVDLFNBQVMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUM7Z0JBQ3ZDLE1BQU0sRUFBRSxXQUFXO2dCQUNuQixvQ0FBb0M7Z0JBQ3BDLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLGFBQWEsS0FBSyxhQUFhO2dCQUN4RCwyREFBMkQ7Z0JBQzNELG1EQUFtRDtnQkFDbkQsU0FBUyxFQUFFLE1BQU0sQ0FBQyxVQUFVLEVBQUUsU0FBUyxJQUFJLEtBQUs7Z0JBQ2hELEtBQUssRUFBRSxNQUFNLENBQUMsVUFBVSxFQUFFLEtBQUs7Z0JBQy9CLE1BQU0sRUFBRSxNQUFNLENBQUMsVUFBVSxFQUFFLE1BQU07Z0JBQ2pDLFlBQVksRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLENBQUM7Z0JBQ3hDLEtBQUssRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU87YUFDaEMsQ0FBQyxDQUFDO1lBRUgseURBQXlEO1lBQ3pELElBQUksV0FBVyxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUMzQixPQUFPO29CQUNMLEdBQUcsTUFBTTtvQkFDVCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUM5QixrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQ3ZDO2lCQUNGLENBQUM7WUFDSixDQUFDO1lBRUQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7XG4gIEVudGl0eUNvbmZsaWN0RXJyb3IsXG4gIEhvb2tOb3RGb3VuZEVycm9yLFxuICBSdW5FeHBpcmVkRXJyb3IsXG4gIFJ1bk5vdFN1cHBvcnRlZEVycm9yLFxuICBUb29FYXJseUVycm9yLFxuICBXb3JrZmxvd1dvcmxkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHR5cGUge1xuICBFdmVudCxcbiAgRXZlbnRSZXN1bHQsXG4gIEhvb2ssXG4gIFNlcmlhbGl6ZWREYXRhLFxuICBTdGVwLFxuICBTdG9yYWdlLFxuICBXYWl0LFxuICBXb3JrZmxvd1J1bixcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7XG4gIEV2ZW50U2NoZW1hLFxuICBIb29rU2NoZW1hLFxuICBpc0xlZ2FjeVNwZWNWZXJzaW9uLFxuICBpc1Rlcm1pbmFsU3RlcFN0YXR1cyxcbiAgaXNUZXJtaW5hbFdvcmtmbG93UnVuU3RhdHVzLFxuICByZXF1aXJlc05ld2VyV29ybGQsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTdGVwU2NoZW1hLFxuICB1bGlkVG9EYXRlLFxuICB2YWxpZGF0ZVVsaWRUaW1lc3RhbXAsXG4gIFdhaXRTY2hlbWEsXG4gIFdvcmtmbG93UnVuU2NoZW1hLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgeyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT04gfSBmcm9tICcuLi9jb25maWcuanMnO1xuaW1wb3J0IHtcbiAgYXNzZXJ0U2FmZUVudGl0eUlkLFxuICBkZWxldGVKU09OLFxuICBqc29uUmVwbGFjZXIsXG4gIGxpc3RKU09ORmlsZXMsXG4gIHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSxcbiAgcmVhZEpTT04sXG4gIHJlYWRKU09OV2l0aEZhbGxiYWNrLFxuICByZXNvbHZlV2l0aGluQmFzZSxcbiAgdGFnZ2VkUGF0aCxcbiAgd3JpdGVFeGNsdXNpdmUsXG4gIHdyaXRlSlNPTixcbn0gZnJvbSAnLi4vZnMuanMnO1xuaW1wb3J0IHsgc3RyaXBFdmVudERhdGFSZWZzIH0gZnJvbSAnLi9maWx0ZXJzLmpzJztcbmltcG9ydCB7XG4gIGdldE9iamVjdENyZWF0ZWRBdCxcbiAgaGFzaFRva2VuLFxuICBob29rUmVjb3ZlcnlNYXJrZXJQYXRoLFxuICBtb25vdG9uaWNVbGlkLFxufSBmcm9tICcuL2hlbHBlcnMuanMnO1xuaW1wb3J0IHtcbiAgZGVsZXRlQWxsSG9va3NGb3JSdW4sXG4gIHJlYnVpbGRMaXZlSG9va0J5VG9rZW5Gcm9tRXZlbnRMb2csXG59IGZyb20gJy4vaG9va3Mtc3RvcmFnZS5qcyc7XG5pbXBvcnQgeyBoYW5kbGVMZWdhY3lFdmVudCB9IGZyb20gJy4vbGVnYWN5LmpzJztcblxuY29uc3QgSG9va1Rva2VuQ2xhaW1TY2hlbWEgPSB6Lm9iamVjdCh7XG4gIC8vIFRoZSB0b2tlbi1jbGFpbSB3cml0ZXIgYmVsb3cgaGFzIGFsd2F5cyBwZXJzaXN0ZWQgYGhvb2tJZGAsIGJ1dFxuICAvLyB0aGlzIHJlYWQgc2NoZW1hIHByZXZpb3VzbHkgb21pdHRlZCBpdCwgd2hpY2ggaXMgdGhlIGJ1ZyBmaXhlZFxuICAvLyBieSBodHRwczovL2dpdGh1Yi5jb20vdmVyY2VsL3dvcmtmbG93L2lzc3Vlcy8yMjgzLiBgb3B0aW9uYWwoKWBcbiAgLy8gaXMgZGVmZW5zaXZlOiBhbnkgY2xhaW0gZmlsZSB0aGF0IHNvbWVob3cgbGFja3MgdGhlIGZpZWxkIHN0aWxsXG4gIC8vIHBhcnNlcyAoeWllbGRpbmcgYHVuZGVmaW5lZGApIGFuZCBmYWxscyB0aHJvdWdoIHRvIHRoZSBjcm9zcy1cbiAgLy8gaG9vayBjb25mbGljdCBicmFuY2gsIG1hdGNoaW5nIHByZS1maXggYmVoYXZpb3IuXG4gIGhvb2tJZDogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBydW5JZDogei5zdHJpbmcoKSxcbiAgLy8gYGV2ZW50SWRgIGlzIHRoZSBjYW5vbmljYWwgaG9va19jcmVhdGVkIGV2ZW50IElEIHRoZSBjbGFpbWluZ1xuICAvLyB3b3JrZXIgY29tbWl0dGVkIHRvIHB1Ymxpc2hpbmcuIFBlcnNpc3RpbmcgaXQgaGVyZSB0dXJucyB0aGVcbiAgLy8gY2xhaW0gZmlsZSBpbnRvIGEgZHVyYWJsZSBjb252ZXJnZW5jZSBrZXkgZm9yIGNyb3NzLXdvcmtlciAvXG4gIC8vIGNyb3NzLXByb2Nlc3MgcmV0cmllcyAoc2VlIGNvbW1lbnQgb24gdGhlIGhvb2tfY3JlYXRlZCBicmFuY2gpLlxuICAvLyBgb3B0aW9uYWwoKWAgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHk6IGEgbGVnYWN5IGNsYWltIGZpbGVcbiAgLy8gd3JpdHRlbiBiZWZvcmUgdGhpcyBmaWVsZCBleGlzdGVkIGZhbGxzIHRocm91Z2ggdG8gdGhlIHJlY292ZXJ5LVxuICAvLyBtYXJrZXIgdXBncmFkZSBwYXRoLCB3aGljaCBhdG9taWNhbGx5IHBpbnMgYSBjYW5vbmljYWwgZXZlbnRJZFxuICAvLyB2aWEgYSBzaWRlY2FyIG1hcmtlciAoYWxzbyBhIGB3cml0ZUV4Y2x1c2l2ZWApLlxuICBldmVudElkOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG59KTtcblxuLyoqXG4gKiBTaWRlY2FyIHJlY292ZXJ5IG1hcmtlciB0aGF0IHBpbnMgYSBjYW5vbmljYWwgYGhvb2tfY3JlYXRlZGBcbiAqIGV2ZW50SWQgZm9yIGEgbGVnYWN5IHRva2VuIGNsYWltIOKAlCBvbmUgd3JpdHRlbiBieSBhIHZlcnNpb24gb2ZcbiAqIHRoaXMgc3RvcmFnZSB0aGF0IGRpZCBub3QgeWV0IHBlcnNpc3QgYGV2ZW50SWRgIGlubGluZSBpbiB0aGVcbiAqIGNsYWltIGZpbGUuIFdpdGhvdXQgdGhpcyBtYXJrZXIsIHR3byBjcm9zcy1wcm9jZXNzIHJldHJpZXNcbiAqIHJlYWRpbmcgYSBsZWdhY3kgY2xhaW0gZWFjaCBnZW5lcmF0ZSB0aGVpciBvd24gZXZlbnRJZCwgbGFuZFxuICogdGhlaXIgYHdyaXRlRXhjbHVzaXZlKGV2ZW50UGF0aClgIGNhbGxzIGF0IGRpZmZlcmVudCBwYXRocywgYW5kXG4gKiBhcHBlbmQgdHdvIGBob29rX2NyZWF0ZWRgIGV2ZW50cyBmb3IgdGhlIHNhbWUgYChydW5JZCwgaG9va0lkKWAuXG4gKlxuICogVGhlIG1hcmtlciBpcyB3cml0dGVuIHZpYSBgd3JpdGVFeGNsdXNpdmVgIOKAlCB0aGUgZmlyc3QgcmV0cnkgdG9cbiAqIGxhbmQgaXQgcGlucyBpdHMgY2FuZGlkYXRlIGV2ZW50SWQgYXMgY2Fub25pY2FsLCBhbmQgZXZlcnlcbiAqIHN1YnNlcXVlbnQgcmV0cnkgcmVhZHMgYW5kIGFkb3B0cyB0aGF0IGV2ZW50SWQgYmVmb3JlIHRoZSBjb21tb25cbiAqIGV2ZW50IHB1Ymxpc2guIFNjaGVtYSBpcyBqdXN0IGB7IGV2ZW50SWQgfWAgYmVjYXVzZSBpZGVudGl0eSBpc1xuICogYWxyZWFkeSBlbmNvZGVkIGluIHRoZSBtYXJrZXIncyBmaWxlbmFtZSBoYXNoLCBzbyBkaWZmZXJlbnQgdG9rZW5cbiAqIGxpZmV0aW1lcyBjYW4gbmV2ZXIgc2hhcmUgb25lIG1hcmtlciAoc2VlXG4gKiBgaG9va1JlY292ZXJ5TWFya2VyUGF0aGApLlxuICovXG5jb25zdCBIb29rUmVjb3ZlcnlNYXJrZXJTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGV2ZW50SWQ6IHouc3RyaW5nKCksXG59KTtcblxuYXN5bmMgZnVuY3Rpb24gcmVhZEhvb2tUb2tlbkNsYWltKFxuICBjb25zdHJhaW50UGF0aDogc3RyaW5nXG4pOiBQcm9taXNlPHouaW5mZXI8dHlwZW9mIEhvb2tUb2tlbkNsYWltU2NoZW1hPiB8IG51bGw+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgcmVhZEpTT04oY29uc3RyYWludFBhdGgsIEhvb2tUb2tlbkNsYWltU2NoZW1hKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTeW50YXhFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIHouWm9kRXJyb3IpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkSG9va1JlY292ZXJ5TWFya2VyKFxuICBtYXJrZXJQYXRoOiBzdHJpbmdcbik6IFByb21pc2U8ei5pbmZlcjx0eXBlb2YgSG9va1JlY292ZXJ5TWFya2VyU2NoZW1hPiB8IG51bGw+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgcmVhZEpTT04obWFya2VyUGF0aCwgSG9va1JlY292ZXJ5TWFya2VyU2NoZW1hKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTeW50YXhFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIHouWm9kRXJyb3IpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG4vKipcbiAqIFByb2JlIHRoZSBydW4ncyBldmVudCBsb2cgZm9yIGFuIGV4aXN0aW5nIGBob29rX2NyZWF0ZWRgIGV2ZW50XG4gKiB3aXRoIHRoZSBnaXZlbiBjb3JyZWxhdGlvbklkLiBVc2VkIGJ5IHRoZSBsZWdhY3ktY2xhaW0gcmVjb3ZlcnlcbiAqIHBhdGggdG8gZGV0ZWN0IFwiYWxyZWFkeSBwdWJsaXNoZWQgYnkgYSBwcmUtdXBncmFkZSB3cml0ZVwiIGJlZm9yZVxuICogcGlubmluZyBhIGNhbm9uaWNhbCBldmVudElkIOKAlCB3aXRob3V0IHRoaXMgY2hlY2ssIGEgcG9zdC11cGdyYWRlXG4gKiByZXRyeSBlbmNvdW50ZXJpbmcgYSBsZWdhY3kgY2xhaW0gd2hvc2UgYGhvb2tfY3JlYXRlZGAgd2FzXG4gKiBhbHJlYWR5IHdyaXR0ZW4gKHdpdGggdGhlIHByZS11cGdyYWRlIHdyaXRlcidzIG93biBldmVudElkKSB3b3VsZFxuICogcGluIGEgKmRpZmZlcmVudCogZXZlbnRJZCB2aWEgdGhlIG1hcmtlciBhbmQgcHVibGlzaCBhIGR1cGxpY2F0ZVxuICogZXZlbnQgYXQgdGhlIG1hcmtlcidzIHBhdGguXG4gKlxuICogVGhlIGlubGluZS1gZXZlbnRJZGAgZmFzdCBwYXRoIGRvZXMgTk9UIG5lZWQgdGhpcyBwcm9iZTogdGhlXG4gKiBjYW5vbmljYWwgZXZlbnRJZCBpcyBkdXJhYmxlIGluIHRoZSBjbGFpbSBmaWxlLCBzbyB0aGUgZXhpc3RpbmdcbiAqIHB1Ymxpc2ggKGB3cml0ZUV4Y2x1c2l2ZShldmVudFBhdGgpYCkgd2lsbCBmYWlsIGlmZiB0aGUgZXZlbnRcbiAqIGFscmVhZHkgZXhpc3RzIGF0IHRoYXQgZXhhY3QgcGF0aCDigJQgd2hpY2ggaXMgdGhlIGNvcnJlY3RcbiAqIFwiYWxyZWFkeS1wdWJsaXNoZWRcIiBzZW1hbnRpYy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmluZEV4aXN0aW5nSG9va0NyZWF0ZWRFdmVudElkKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGNvcnJlbGF0aW9uSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSh7XG4gICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oYmFzZWRpciwgJ2V2ZW50cycpLFxuICAgIHNjaGVtYTogRXZlbnRTY2hlbWEsXG4gICAgZmlsZVByZWZpeDogYCR7cnVuSWR9LWAsXG4gICAgZmlsdGVyOiAoZXZlbnQpID0+XG4gICAgICBldmVudC5ldmVudFR5cGUgPT09ICdob29rX2NyZWF0ZWQnICYmXG4gICAgICBldmVudC5jb3JyZWxhdGlvbklkID09PSBjb3JyZWxhdGlvbklkLFxuICAgIGxpbWl0OiAxLFxuICAgIGdldENyZWF0ZWRBdDogZ2V0T2JqZWN0Q3JlYXRlZEF0KCdldm50JyksXG4gICAgZ2V0SWQ6IChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCxcbiAgfSk7XG4gIHJldHVybiByZXN1bHQuZGF0YVswXT8uZXZlbnRJZCA/PyBudWxsO1xufVxuXG4vKipcbiAqIFJlcGFpciBhbiBcImV2ZW50LWZpcnN0IG9ycGhhblwiOiB0aGUgaG9vayBlbnRpdHkgd3JpdGUgaXMgZGVmZXJyZWRcbiAqIHVudGlsIGFmdGVyIHRoZSBgaG9va19jcmVhdGVkYCBldmVudCBwdWJsaXNoIGNvbW1pdHMgKHNvIGEgZmFpbGVkXG4gKiBwdWJsaXNoIGNhbm5vdCBtdXRhdGUgYWxyZWFkeS1jb21taXR0ZWQgc3RhdGUg4oCUIHNlZSB0aGUgY29tbWVudCBvblxuICogdGhlIGRlZmVycmVkIHdyaXRlKSwgd2hpY2ggb3BlbnMgdGhlIGludmVyc2UgY3Jhc2ggd2luZG93IOKAlCBhXG4gKiBjcmFzaCBBRlRFUiB0aGUgZXZlbnQgcHVibGlzaCBidXQgQkVGT1JFIHRoZSBkZWZlcnJlZCBlbnRpdHkgd3JpdGVcbiAqIGxlYXZlcyB0aGUgZXZlbnQgaW4gdGhlIGxvZyB3aXRoIHRoZSBob29rIGVudGl0eSBtaXNzaW5nLiBBIHJldHJ5XG4gKiB0aGVuIGNvbGxpZGVzIGF0IHRoZSBldmVudCBwdWJsaXNoIGFuZCB0aHJvd3NcbiAqIGBFbnRpdHlDb25mbGljdEVycm9yYCAoY29ycmVjdCDigJQgdGhlIGV2ZW50IElTIGNvbW1pdHRlZCksIGJ1dFxuICogd2l0aG91dCB0aGlzIHJlcGFpciB0aGUgZW50aXR5IHdvdWxkIHN0YXkgbWlzc2luZyBmb3JldmVyIGFuZCB0aGVcbiAqIGhvb2sgd291bGQgYmUgdW5yZXNvbHZhYmxlLlxuICpcbiAqIFRoZSBlbnRpdHkgTVVTVCBiZSByZWNvbnN0cnVjdGVkIGZyb20gdGhlIHBlcnNpc3RlZCBjYW5vbmljYWxcbiAqIGV2ZW50J3MgcGF5bG9hZCDigJQgTk9UIHRoZSByZXRyeSdzIGBldmVudERhdGFgIOKAlCBvdGhlcndpc2UgYSByZXRyeVxuICogY2FycnlpbmcgZGlmZmVyZW50IGBtZXRhZGF0YWAgLyBgaXNXZWJob29rYCB3b3VsZCBzaWxlbnRseSBjaGFuZ2VcbiAqIGNvbW1pdHRlZCBzdGF0ZS4gVGhlIHdyaXRlIHVzZXMgYHdyaXRlRXhjbHVzaXZlYCAoY3JlYXRlLWlmLWFic2VudClcbiAqIHNvIGEgY29uY3VycmVudCB3cml0ZXIgcmFjaW5nIHRoaXMgcmVwYWlyIGNhbm5vdCBiZSBvdmVyd3JpdHRlbjtcbiAqIHdoaWNoZXZlciB3cml0ZSBsYW5kcyBmaXJzdCwgdGhlIGNvbnRlbnQgaXMgaWRlbnRpY2FsIGJlY2F1c2UgYm90aFxuICogZGVyaXZlIGZyb20gdGhlIHNhbWUgcGVyc2lzdGVkIGV2ZW50LlxuICovXG5hc3luYyBmdW5jdGlvbiByZXBhaXJIb29rRW50aXR5RnJvbVBlcnNpc3RlZEV2ZW50KFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhvb2tJZDogc3RyaW5nLFxuICBwZXJzaXN0ZWRFdmVudElkOiBzdHJpbmcsXG4gIHRhZzogc3RyaW5nIHwgdW5kZWZpbmVkXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY29tcG9zaXRlS2V5ID0gYCR7cnVuSWR9LSR7cGVyc2lzdGVkRXZlbnRJZH1gO1xuICBjb25zdCBwZXJzaXN0ZWRFdmVudCA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgIGJhc2VkaXIsXG4gICAgJ2V2ZW50cycsXG4gICAgY29tcG9zaXRlS2V5LFxuICAgIEV2ZW50U2NoZW1hLFxuICAgIHRhZ1xuICApO1xuICBpZiAoXG4gICAgIXBlcnNpc3RlZEV2ZW50IHx8XG4gICAgcGVyc2lzdGVkRXZlbnQuZXZlbnRUeXBlICE9PSAnaG9va19jcmVhdGVkJyB8fFxuICAgIHBlcnNpc3RlZEV2ZW50LmNvcnJlbGF0aW9uSWQgIT09IGhvb2tJZFxuICApIHtcbiAgICAvLyBOb3RoaW5nIHRydXN0d29ydGh5IHRvIHJlcGFpciBmcm9tLlxuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBleGlzdGluZ0hvb2sgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICBiYXNlZGlyLFxuICAgICdob29rcycsXG4gICAgaG9va0lkLFxuICAgIEhvb2tTY2hlbWEsXG4gICAgdGFnXG4gICk7XG4gIGlmIChleGlzdGluZ0hvb2spIHtcbiAgICAvLyBFbnRpdHkgYWxyZWFkeSBwcmVzZW50IOKAlCBub3QgYW4gb3JwaGFuLCBsZWF2ZSBpdCB1bnRvdWNoZWQuXG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IGV2ZW50RGF0YSA9IChwZXJzaXN0ZWRFdmVudC5ldmVudERhdGEgPz8ge30pIGFzIHtcbiAgICB0b2tlbj86IHN0cmluZztcbiAgICBtZXRhZGF0YT86IFNlcmlhbGl6ZWREYXRhO1xuICAgIGlzV2ViaG9vaz86IGJvb2xlYW47XG4gIH07XG4gIGlmICh0eXBlb2YgZXZlbnREYXRhLnRva2VuICE9PSAnc3RyaW5nJykge1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBob29rOiBIb29rID0ge1xuICAgIHJ1bklkLFxuICAgIGhvb2tJZCxcbiAgICB0b2tlbjogZXZlbnREYXRhLnRva2VuLFxuICAgIG1ldGFkYXRhOiBldmVudERhdGEubWV0YWRhdGEsXG4gICAgb3duZXJJZDogJ2xvY2FsLW93bmVyJyxcbiAgICBwcm9qZWN0SWQ6ICdsb2NhbC1wcm9qZWN0JyxcbiAgICBlbnZpcm9ubWVudDogJ2xvY2FsJyxcbiAgICBjcmVhdGVkQXQ6IHBlcnNpc3RlZEV2ZW50LmNyZWF0ZWRBdCxcbiAgICBzcGVjVmVyc2lvbjogcGVyc2lzdGVkRXZlbnQuc3BlY1ZlcnNpb24sXG4gICAgaXNXZWJob29rOiBldmVudERhdGEuaXNXZWJob29rID8/IHRydWUsXG4gIH07XG4gIGF3YWl0IHdyaXRlRXhjbHVzaXZlKFxuICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2hvb2tzJywgaG9va0lkLCB0YWcpLFxuICAgIEpTT04uc3RyaW5naWZ5KGhvb2ssIGpzb25SZXBsYWNlciwgMilcbiAgKTtcbn1cblxuLyoqXG4gKiBBdG9taWNhbGx5IHBpbiBhIGNhbm9uaWNhbCBgaG9va19jcmVhdGVkYCBldmVudElkIGZvciBhIGxlZ2FjeVxuICogY2xhaW0gKG9uZSB3aXRob3V0IGFuIGlubGluZSBgZXZlbnRJZGApLiBUaGUgZmlyc3QgcmV0cnkgdG9cbiAqIGB3cml0ZUV4Y2x1c2l2ZWAgdGhlIHJlY292ZXJ5IG1hcmtlciB3aW5zOyBpdHMgYGNhbmRpZGF0ZUV2ZW50SWRgXG4gKiBiZWNvbWVzIGNhbm9uaWNhbC4gU3Vic2VxdWVudCByZXRyaWVzIHJlYWQgdGhlIG1hcmtlciBhbmQgYWRvcHRcbiAqIGl0cyBgZXZlbnRJZGAuIFRvZ2V0aGVyIHdpdGggdGhlIGB3cml0ZUV4Y2x1c2l2ZShldmVudFBhdGgpYCBpblxuICogdGhlIG91dGVyIGV2ZW50IHB1Ymxpc2gsIHRoaXMgZ2l2ZXMgdGhlIGxlZ2FjeS1mYWxsYmFjayBwYXRoIHRoZVxuICogc2FtZSBzaW5nbGUtZXZlbnQgY29udmVyZ2VuY2UgZ3VhcmFudGVlIGFzIHRoZSBpbmxpbmUtYGV2ZW50SWRgXG4gKiBmYXN0IHBhdGguXG4gKlxuICogUmV0dXJucyB0aGUgY2Fub25pY2FsIGV2ZW50SWQgZm9yIHRoZSBjYWxsZXIgdG8gYWRvcHQsIG9yIGBudWxsYFxuICogaWYgd2UgbG9zdCB0aGUgbWFya2VyIHJhY2UgQU5EIHRoZSByZXN1bHRpbmcgbWFya2VyIGZpbGUgaXNcbiAqIHVucmVhZGFibGUgKGV4dHJlbWVseSByYXJlOyBjb3JydXB0ZWQgZGlzaykuIENhbGxlcnMgdHJlYXQgYG51bGxgXG4gKiBhcyBcImdpdmUgdXAsIHRocm93IGBFbnRpdHlDb25mbGljdEVycm9yYFwiIHNvIHRoZSBydW50aW1lJ3NcbiAqIGNvbmN1cnJlbnQtcmVwbGF5IGNhdGNoIHBhdGggc3dhbGxvd3MgdGhpcyBhdHRlbXB0IGFuZCBsZXRzXG4gKiBhbm90aGVyIG9uZSB0aHJvdWdoLlxuICovXG5hc3luYyBmdW5jdGlvbiBwaW5DYW5vbmljYWxFdmVudElkRm9yTGVnYWN5Q2xhaW0oXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgdG9rZW46IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZyxcbiAgaG9va0lkOiBzdHJpbmcsXG4gIGNhbmRpZGF0ZUV2ZW50SWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gIGNvbnN0IG1hcmtlclBhdGggPSBob29rUmVjb3ZlcnlNYXJrZXJQYXRoKGJhc2VkaXIsIHRva2VuLCBydW5JZCwgaG9va0lkKTtcbiAgY29uc3QgbWFya2VyQ29udGVudCA9IEpTT04uc3RyaW5naWZ5KHsgZXZlbnRJZDogY2FuZGlkYXRlRXZlbnRJZCB9KTtcbiAgY29uc3Qgd29uID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUobWFya2VyUGF0aCwgbWFya2VyQ29udGVudCk7XG4gIGlmICh3b24pIHtcbiAgICByZXR1cm4gY2FuZGlkYXRlRXZlbnRJZDtcbiAgfVxuICBjb25zdCBleGlzdGluZyA9IGF3YWl0IHJlYWRIb29rUmVjb3ZlcnlNYXJrZXIobWFya2VyUGF0aCk7XG4gIHJldHVybiBleGlzdGluZz8uZXZlbnRJZCA/PyBudWxsO1xufVxuXG4vKipcbiAqIEluLXByb2Nlc3MgcGVyLWtleSBhc3luYyBtdXRleCBiYWNrZWQgYnkgYSBjYWxsZXItc3VwcGxpZWQgYE1hcGAuXG4gKiBVc2VkIGJ5IGBjcmVhdGVFdmVudHNTdG9yYWdlYCB0byBzZXJpYWxpemUgc2FtZS1rZXkgZXZlbnQgd3JpdGVzXG4gKiAoYHN0ZXBfKmAgZm9yIHRoZSBzYW1lIHN0ZXAsIGBob29rX2NyZWF0ZWRgIGZvciB0aGUgc2FtZSBob29rKS5cbiAqIFRoZSBtYXAgaXMgaW5zdGFudGlhdGVkIHBlci1zdG9yYWdlLWluc3RhbmNlIOKAlCBkaWZmZXJlbnRcbiAqIGluc3RhbmNlcyBkbyBOT1Qgc2hhcmUgbG9ja3MsIHNvIHR3byBpbnN0YW5jZXMgc2hhcmluZyBvbmUgZGF0YVxuICogZGlyZWN0b3J5IGJlaGF2ZSBleGFjdGx5IGxpa2UgdHdvIHNlcGFyYXRlIE9TIHByb2Nlc3NlcyBmcm9tIHRoZVxuICogbG9ja2luZyBzdGFuZHBvaW50LiBDcm9zcy1pbnN0YW5jZSAvIGNyb3NzLXByb2Nlc3MgYXJiaXRyYXRpb25cbiAqIHJlbGllcyBvbiB0aGUgb24tZGlzayBjb25zdHJhaW50IC8gY2xhaW0gZmlsZXMgaW5zdGVhZC5cbiAqL1xuZnVuY3Rpb24gd2l0aEluUHJvY2Vzc0xvY2s8VD4oXG4gIGxvY2tzOiBNYXA8c3RyaW5nLCBQcm9taXNlPHVua25vd24+PixcbiAga2V5OiBzdHJpbmcsXG4gIGZuOiAoKSA9PiBQcm9taXNlPFQ+XG4pOiBQcm9taXNlPFQ+IHtcbiAgY29uc3QgcHJldiA9IGxvY2tzLmdldChrZXkpO1xuICBjb25zdCB0YXNrQm94OiB7IHRhc2s/OiBQcm9taXNlPFQ+IH0gPSB7fTtcbiAgY29uc3QgdGFzayA9IChhc3luYyAoKSA9PiB7XG4gICAgaWYgKHByZXYpIHtcbiAgICAgIC8vIFdhaXQgZm9yIHRoZSBwcmV2aW91cyB0YXNrIHRvIHNldHRsZTsgZG9uJ3QgaW5oZXJpdCBpdHMgZXJyb3JzLlxuICAgICAgYXdhaXQgcHJldi5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IGZuKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGlmIChsb2Nrcy5nZXQoa2V5KSA9PT0gdGFza0JveC50YXNrKSB7XG4gICAgICAgIGxvY2tzLmRlbGV0ZShrZXkpO1xuICAgICAgfVxuICAgIH1cbiAgfSkoKTtcbiAgdGFza0JveC50YXNrID0gdGFzaztcbiAgbG9ja3Muc2V0KGtleSwgdGFzayk7XG4gIHJldHVybiB0YXNrO1xufVxuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0byBkZWxldGUgYWxsIHdhaXRzIGFzc29jaWF0ZWQgd2l0aCBhIHdvcmtmbG93IHJ1bi5cbiAqIENhbGxlZCB3aGVuIGEgcnVuIHJlYWNoZXMgYSB0ZXJtaW5hbCBzdGF0ZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGVsZXRlQWxsV2FpdHNGb3JSdW4oXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHdhaXRzRGlyID0gcGF0aC5qb2luKGJhc2VkaXIsICd3YWl0cycpO1xuICBjb25zdCBmaWxlcyA9IGF3YWl0IGxpc3RKU09ORmlsZXMod2FpdHNEaXIpO1xuXG4gIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgIC8vIGZpbGVJZHMgbWF5IGNvbnRhaW4gdGFnIHN1ZmZpeGVzIChlLmcuLCBcIndydW5fQUJDLWNvcnJJZC52aXRlc3QtMFwiKVxuICAgIC8vIGJ1dCBzdGFydHNXaXRoIHN0aWxsIG1hdGNoZXMgY29ycmVjdGx5IHNpbmNlIHRoZSB0YWcgaXMgYSBzdWZmaXguXG4gICAgaWYgKGZpbGUuc3RhcnRzV2l0aChgJHtydW5JZH0tYCkpIHtcbiAgICAgIGNvbnN0IHdhaXRQYXRoID0gcGF0aC5qb2luKHdhaXRzRGlyLCBgJHtmaWxlfS5qc29uYCk7XG4gICAgICBhd2FpdCBkZWxldGVKU09OKHdhaXRQYXRoKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBldmVudHMgc3RvcmFnZSBpbXBsZW1lbnRhdGlvbiB1c2luZyB0aGUgZmlsZXN5c3RlbS5cbiAqIEltcGxlbWVudHMgdGhlIFN0b3JhZ2VbJ2V2ZW50cyddIGludGVyZmFjZSB3aXRoIGNyZWF0ZSwgbGlzdCwgYW5kIGxpc3RCeUNvcnJlbGF0aW9uSWQgb3BlcmF0aW9ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUV2ZW50c1N0b3JhZ2UoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgdGFnPzogc3RyaW5nXG4pOiBTdG9yYWdlWydldmVudHMnXSB7XG4gIC8vIFBlci1pbnN0YW5jZSBpbi1wcm9jZXNzIG11dGV4LiBUd28gc3RvcmFnZSBpbnN0YW5jZXMgc2hhcmluZ1xuICAvLyBvbmUgZGF0YSBkaXJlY3RvcnkgZ2V0IGluZGVwZW5kZW50IGxvY2sgbWFwcywgd2hpY2ggbWFrZXMgdGhlbVxuICAvLyBiZWhhdmUgbGlrZSB0d28gc2VwYXJhdGUgT1MgcHJvY2Vzc2VzIGZyb20gdGhlIGxvY2tpbmdcbiAgLy8gc3RhbmRwb2ludCDigJQgY3Jvc3MtaW5zdGFuY2UgYXJiaXRyYXRpb24gcmVsaWVzIG9uIHRoZSBvbi1kaXNrXG4gIC8vIGB3cml0ZUV4Y2x1c2l2ZWAgY29uc3RyYWludCAvIGNsYWltIGZpbGVzIGluc3RlYWQuIFRlc3RzIHVzZVxuICAvLyB0aGlzIHRvIGV4ZXJjaXNlIGNyb3NzLXByb2Nlc3MgY29udmVyZ2VuY2Ugd2l0aG91dCBzcGF3bmluZ1xuICAvLyBzdWJwcm9jZXNzZXMuXG4gIC8vXG4gIC8vIGBob29rTG9ja3NgIHNlcmlhbGl6ZXMgYGhvb2tfY3JlYXRlZGAgY2FsbHMgZm9yIHRoZSBzYW1lXG4gIC8vIChydW5JZCwgY29ycmVsYXRpb25JZCkgc28gdGhlIFwiY2xhaW0gdG9rZW4sIHRoZW4gd3JpdGUgaG9va1xuICAvLyBlbnRpdHkgKyBldmVudFwiIHNlcXVlbmNlIHJ1bnMgdG8gY29tcGxldGlvbiBiZWZvcmUgYW5vdGhlclxuICAvLyBpbi1wcm9jZXNzIGludm9jYXRpb24gZW50ZXJzIHRoZSBkZWR1cCBicmFuY2guXG4gIGNvbnN0IGhvb2tMb2NrcyA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPHVua25vd24+PigpO1xuXG4gIHJldHVybiB7XG4gICAgYXN5bmMgY3JlYXRlKHJ1bklkLCBkYXRhLCBwYXJhbXMpOiBQcm9taXNlPEV2ZW50UmVzdWx0PiB7XG4gICAgICAvLyBWYWxpZGF0ZSByZXF1ZXN0LXN1cHBsaWVkIElEcyBiZWZvcmUgdGhleSdyZSBjb25jYXRlbmF0ZWQgaW50b1xuICAgICAgLy8gZmlsZXN5c3RlbSBwYXRocy4gVGhpcyBpcyB0aGUgcHJpbWFyeSBkZWZlbnNlIGFnYWluc3QgcGF0aCB0cmF2ZXJzYWxcbiAgICAgIC8vIGF0dGFja3Mgd2hlcmUgYSBjbGllbnQgc3VwcGxpZXMgcnVuSWQgLyBjb3JyZWxhdGlvbklkIHZhbHVlcyBsaWtlXG4gICAgICAvLyBcIi4uLy4uLy4uL3BhY2thZ2VcIiB0byByZWFkIG9yIHdyaXRlIGZpbGVzIG91dHNpZGUgdGhlIHN0b3JhZ2Ugcm9vdC5cbiAgICAgIC8vXG4gICAgICAvLyBFbXB0eSBgY29ycmVsYXRpb25JZGAgdmFsdWVzIGFyZSBhbHNvIHJlamVjdGVkIGhlcmU6IHRoZSBldmVudFxuICAgICAgLy8gc2NoZW1hcyBvbmx5IHJlcXVpcmUgYHouc3RyaW5nKClgLCBzbyB3aXRob3V0IHRoaXMgY2hlY2sgYVxuICAgICAgLy8gc3RlcF9jcmVhdGVkIC8gaG9va19jcmVhdGVkIC8gd2FpdF9jcmVhdGVkIHJlcXVlc3Qgd2l0aFxuICAgICAgLy8gYGNvcnJlbGF0aW9uSWQ6ICcnYCB3b3VsZCBzaWxlbnRseSBiZSB3cml0dGVuIHVuZGVyIGEgbWFsZm9ybWVkXG4gICAgICAvLyBjb21wb3NpdGUga2V5IGxpa2UgYCR7cnVuSWR9LWAuXG4gICAgICBpZiAocnVuSWQgIT0gbnVsbCAmJiBydW5JZCAhPT0gJycpIHtcbiAgICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdydW5JZCcsIHJ1bklkKTtcbiAgICAgIH1cbiAgICAgIGlmICgnY29ycmVsYXRpb25JZCcgaW4gZGF0YSAmJiB0eXBlb2YgZGF0YS5jb3JyZWxhdGlvbklkID09PSAnc3RyaW5nJykge1xuICAgICAgICBhc3NlcnRTYWZlRW50aXR5SWQoJ2NvcnJlbGF0aW9uSWQnLCBkYXRhLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgfVxuXG4gICAgICAvLyBgaG9va19jcmVhdGVkYCBpcyBzZXJpYWxpemVkIHBlci0ocnVuSWQsIGhvb2tJZCkgc28gdGhlXG4gICAgICAvLyBcImNsYWltIHRva2VuLCB3cml0ZSBob29rIGVudGl0eSwgd3JpdGUgZXZlbnRcIiBzZXF1ZW5jZSBydW5zIHRvXG4gICAgICAvLyBjb21wbGV0aW9uIGJlZm9yZSBhbm90aGVyIGluLXByb2Nlc3MgaW52b2NhdGlvbiBlbnRlcnMgdGhlXG4gICAgICAvLyBzYW1lLWhvb2sgZGVkdXAgYnJhbmNoLiBXaXRob3V0IHRoaXMsIHR3byBzYW1lLXRpY2sgY29uY3VycmVudFxuICAgICAgLy8gY2FsbGVycyBjYW4gcmFjZSBiZXR3ZWVuIHRoZSB3aW5uZXIncyBgd3JpdGVFeGNsdXNpdmUoY2xhaW0pYFxuICAgICAgLy8gYW5kIGB3cml0ZUpTT04oaG9vaylgLCBtYWtpbmcgdGhlIHNlY29uZCBjYWxsZXIgbW9tZW50YXJpbHlcbiAgICAgIC8vIG9ic2VydmUgYSBjbGFpbSB3aXRoIG5vIG1hdGNoaW5nIGhvb2sgZW50aXR5IOKAlCB3aGljaCB0aGVcbiAgICAgIC8vIGNyYXNoLXJlY292ZXJ5IHBhdGggYmVsb3cgd291bGQgbWlzaW50ZXJwcmV0IGFzIGEgcHJpb3IgY3Jhc2hcbiAgICAgIC8vIGFuZCBpbmNvcnJlY3RseSBmYWxsIHRocm91Z2ggdG8gYSBzZWNvbmQgaG9vayBlbnRpdHkgd3JpdGUuXG4gICAgICBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdob29rX2NyZWF0ZWQnICYmIHJ1bklkICYmIGRhdGEuY29ycmVsYXRpb25JZCkge1xuICAgICAgICBjb25zdCBsb2NrS2V5ID0gdGFnXG4gICAgICAgICAgPyBgJHtydW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9Lmhvb2suJHt0YWd9YFxuICAgICAgICAgIDogYCR7cnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfS5ob29rYDtcbiAgICAgICAgcmV0dXJuIHdpdGhJblByb2Nlc3NMb2NrKGhvb2tMb2NrcywgbG9ja0tleSwgKCkgPT4gY3JlYXRlSW1wbCgpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjcmVhdGVJbXBsKCk7XG5cbiAgICAgIGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUltcGwoKTogUHJvbWlzZTxFdmVudFJlc3VsdD4ge1xuICAgICAgICAvLyBNb3N0IHBhdGhzIHVzZSB0aGUgZnJlc2hseS1nZW5lcmF0ZWQgY2FuZGlkYXRlIGV2ZW50SWQuIFRoZVxuICAgICAgICAvLyBob29rX2NyZWF0ZWQgZGVkdXAtcmVjb3ZlcnkgcGF0aCBiZWxvdyBtYXkgcmVhc3NpZ24gaXQgdG9cbiAgICAgICAgLy8gdGhlIGNhbm9uaWNhbCBldmVudElkIHBlcnNpc3RlZCBpbiB0aGUgZHVyYWJsZSB0b2tlbiBjbGFpbVxuICAgICAgICAvLyBzbyBjb25jdXJyZW50IC8gY3Jvc3MtcHJvY2VzcyB3b3JrZXJzIGNvbnZlcmdlIG9uIGEgc2luZ2xlXG4gICAgICAgIC8vIGV2ZW50IGluIHRoZSBsb2cuXG4gICAgICAgIGxldCBldmVudElkID0gYGV2bnRfJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcblxuICAgICAgICAvLyBGb3IgcnVuX2NyZWF0ZWQgZXZlbnRzLCB1c2UgY2xpZW50LXByb3ZpZGVkIHJ1bklkIG9yIGdlbmVyYXRlIG9uZSBzZXJ2ZXItc2lkZVxuICAgICAgICBsZXQgZWZmZWN0aXZlUnVuSWQ6IHN0cmluZztcbiAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NyZWF0ZWQnICYmICghcnVuSWQgfHwgcnVuSWQgPT09ICcnKSkge1xuICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkID0gYHdydW5fJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgICAgfSBlbHNlIGlmICghcnVuSWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3J1bklkIGlzIHJlcXVpcmVkIGZvciBub24tcnVuX2NyZWF0ZWQgZXZlbnRzJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZWZmZWN0aXZlUnVuSWQgPSBydW5JZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFZhbGlkYXRlIGNsaWVudC1wcm92aWRlZCBydW5JZCB0aW1lc3RhbXAgaXMgd2l0aGluIGFjY2VwdGFibGUgdGhyZXNob2xkXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jcmVhdGVkJyAmJiBydW5JZCAmJiBydW5JZCAhPT0gJycpIHtcbiAgICAgICAgICBjb25zdCB2YWxpZGF0aW9uRXJyb3IgPSB2YWxpZGF0ZVVsaWRUaW1lc3RhbXAoXG4gICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICd3cnVuXydcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICh2YWxpZGF0aW9uRXJyb3IpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBXb3JrZmxvd1dvcmxkRXJyb3IodmFsaWRhdGlvbkVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzcGVjVmVyc2lvbiBpcyBhbHdheXMgc2VudCBieSB0aGUgcnVudGltZSwgYnV0IHdlIHByb3ZpZGUgYSBmYWxsYmFjayBmb3Igc2FmZXR5XG4gICAgICAgIGNvbnN0IGVmZmVjdGl2ZVNwZWNWZXJzaW9uID0gZGF0YS5zcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVDtcblxuICAgICAgICAvLyBHZXQgY3VycmVudCBydW4gc3RhdGUgZm9yIHZhbGlkYXRpb24gKGlmIG5vdCBjcmVhdGluZyBhIG5ldyBydW4pXG4gICAgICAgIC8vIFNraXAgcnVuIHZhbGlkYXRpb24gZm9yIHN0ZXBfY29tcGxldGVkIGFuZCBzdGVwX3JldHJ5aW5nIC0gdGhleSBvbmx5IG9wZXJhdGVcbiAgICAgICAgLy8gb24gcnVubmluZyBzdGVwcywgYW5kIHJ1bm5pbmcgc3RlcHMgYXJlIGFsd2F5cyBhbGxvd2VkIHRvIG1vZGlmeSByZWdhcmRsZXNzXG4gICAgICAgIC8vIG9mIHJ1biBzdGF0ZS4gVGhpcyBvcHRpbWl6YXRpb24gc2F2ZXMgZmlsZXN5c3RlbSByZWFkcyBwZXIgc3RlcCBldmVudC5cbiAgICAgICAgbGV0IGN1cnJlbnRSdW46IFdvcmtmbG93UnVuIHwgbnVsbCA9IG51bGw7XG4gICAgICAgIGNvbnN0IHNraXBSdW5WYWxpZGF0aW9uRXZlbnRzID0gWydzdGVwX2NvbXBsZXRlZCcsICdzdGVwX3JldHJ5aW5nJ107XG4gICAgICAgIGlmIChcbiAgICAgICAgICBkYXRhLmV2ZW50VHlwZSAhPT0gJ3J1bl9jcmVhdGVkJyAmJlxuICAgICAgICAgICFza2lwUnVuVmFsaWRhdGlvbkV2ZW50cy5pbmNsdWRlcyhkYXRhLmV2ZW50VHlwZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgY3VycmVudFJ1biA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdydW5zJyxcbiAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgV29ya2Zsb3dSdW5TY2hlbWEsXG4gICAgICAgICAgICB0YWdcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gUmVzaWxpZW50IHN0YXJ0OiBydW5fc3RhcnRlZCBvbiBub24tZXhpc3RlbnQgcnVuIHdpdGggZXZlbnREYXRhXG4gICAgICAgICAgLy8gY3JlYXRlcyB0aGUgcnVuIGZpcnN0LCBzbyB0aGUgcXVldWUgY2FuIGJvb3RzdHJhcCBhIHJ1biB0aGF0XG4gICAgICAgICAgLy8gZmFpbGVkIHRvIGNyZWF0ZSBkdXJpbmcgc3RhcnQoKS5cbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJyAmJlxuICAgICAgICAgICAgIWN1cnJlbnRSdW4gJiZcbiAgICAgICAgICAgICdldmVudERhdGEnIGluIGRhdGEgJiZcbiAgICAgICAgICAgIGRhdGEuZXZlbnREYXRhXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBydW5JbnB1dERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICAgIGRlcGxveW1lbnRJZD86IHN0cmluZztcbiAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lPzogc3RyaW5nO1xuICAgICAgICAgICAgICBpbnB1dD86IGFueTtcbiAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dD86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICBydW5JbnB1dERhdGEuZGVwbG95bWVudElkICYmXG4gICAgICAgICAgICAgIHJ1bklucHV0RGF0YS53b3JrZmxvd05hbWUgJiZcbiAgICAgICAgICAgICAgcnVuSW5wdXREYXRhLmlucHV0ICE9PSB1bmRlZmluZWRcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAvLyBBdG9taWNhbGx5IHRyeSB0byBwdWJsaXNoIHRoZSBydW4gZW50aXR5IHNvIG9ubHkgdGhlIGZpcnN0XG4gICAgICAgICAgICAgIC8vIHdyaXRlciB3aW5zLCBwcmV2ZW50aW5nIGEgVE9DVE9VIHJhY2Ugd2hlcmUgYSBjb25jdXJyZW50XG4gICAgICAgICAgICAgIC8vIHJ1bl9jcmVhdGVkIGZyb20gc3RhcnQoKSBjb3VsZCBvdmVyd3JpdGUgYSBydW4gdGhhdCB3YXNcbiAgICAgICAgICAgICAgLy8gYWxyZWFkeSB0cmFuc2l0aW9uZWQgdG8gJ3J1bm5pbmcnLlxuICAgICAgICAgICAgICBjb25zdCBjcmVhdGVkUnVuOiBXb3JrZmxvd1J1biA9IHtcbiAgICAgICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgZGVwbG95bWVudElkOiBydW5JbnB1dERhdGEuZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuSW5wdXREYXRhLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogcnVuSW5wdXREYXRhLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgICAgaW5wdXQ6IHJ1bklucHV0RGF0YS5pbnB1dCxcbiAgICAgICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHN0YXJ0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIGNvbnN0IHJ1blBhdGggPSB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyk7XG4gICAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICAgICAgICBydW5QYXRoLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNyZWF0ZWRSdW4sIGpzb25SZXBsYWNlcilcbiAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICBpZiAoY3JlYXRlZCkge1xuICAgICAgICAgICAgICAgIC8vIFdlIGNyZWF0ZWQgdGhlIHJ1biDigJQgYWxzbyB3cml0ZSB0aGUgcnVuX2NyZWF0ZWQgZXZlbnQuXG4gICAgICAgICAgICAgICAgY29uc3QgcnVuQ3JlYXRlZEV2ZW50SWQgPSBgZXZudF8ke21vbm90b25pY1VsaWQoKX1gO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ1bkNyZWF0ZWRFdmVudDogRXZlbnQgPSB7XG4gICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fY3JlYXRlZCcsXG4gICAgICAgICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgICBldmVudElkOiBydW5DcmVhdGVkRXZlbnRJZCxcbiAgICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogcnVuSW5wdXREYXRhLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBydW5JbnB1dERhdGEud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICBpbnB1dDogcnVuSW5wdXREYXRhLmlucHV0LFxuICAgICAgICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBydW5JbnB1dERhdGEuZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBjb25zdCBjcmVhdGVkQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7cnVuQ3JlYXRlZEV2ZW50SWR9YDtcbiAgICAgICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdldmVudHMnLCBjcmVhdGVkQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICAgICAgcnVuQ3JlYXRlZEV2ZW50XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjdXJyZW50UnVuID0gY3JlYXRlZFJ1bjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBSdW4gYWxyZWFkeSBleGlzdHMgKGNvbmN1cnJlbnQgcnVuX2NyZWF0ZWQgd29uIHRoZVxuICAgICAgICAgICAgICAgIC8vIHJhY2UpLiBSZS1yZWFkIGl0IHNvIGRvd25zdHJlYW0gbG9naWMgc2VlcyB0aGUgcmVhbCBzdGF0ZS5cbiAgICAgICAgICAgICAgICBjdXJyZW50UnVuID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgICAgICAgJ3J1bnMnLFxuICAgICAgICAgICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgICBXb3JrZmxvd1J1blNjaGVtYSxcbiAgICAgICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAgICAgLy8gVkVSU0lPTiBDT01QQVRJQklMSVRZOiBDaGVjayBydW4gc3BlYyB2ZXJzaW9uXG4gICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgICAgICAvLyBGb3IgZXZlbnRzIHRoYXQgaGF2ZSBmZXRjaGVkIHRoZSBydW4sIGNoZWNrIHZlcnNpb24gY29tcGF0aWJpbGl0eS5cbiAgICAgICAgLy8gU2tpcCBmb3IgcnVuX2NyZWF0ZWQgKG5vIGV4aXN0aW5nIHJ1bikgYW5kIHJ1bnRpbWUgZXZlbnRzIChzdGVwX2NvbXBsZXRlZCwgc3RlcF9yZXRyeWluZykuXG4gICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgcnVuIHJlcXVpcmVzIGEgbmV3ZXIgd29ybGQgdmVyc2lvblxuICAgICAgICAgIGlmIChyZXF1aXJlc05ld2VyV29ybGQoY3VycmVudFJ1bi5zcGVjVmVyc2lvbikpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBSdW5Ob3RTdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICAgICAgY3VycmVudFJ1bi5zcGVjVmVyc2lvbiEsXG4gICAgICAgICAgICAgIFNQRUNfVkVSU0lPTl9DVVJSRU5UXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFJvdXRlIHRvIGxlZ2FjeSBoYW5kbGVyIGZvciBwcmUtZXZlbnQtc291cmNpbmcgcnVuc1xuICAgICAgICAgIGlmIChpc0xlZ2FjeVNwZWNWZXJzaW9uKGN1cnJlbnRSdW4uc3BlY1ZlcnNpb24pKSB7XG4gICAgICAgICAgICByZXR1cm4gaGFuZGxlTGVnYWN5RXZlbnQoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgICBjdXJyZW50UnVuLFxuICAgICAgICAgICAgICBwYXJhbXNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgICAgIC8vIFZBTElEQVRJT046IFRlcm1pbmFsIHN0YXRlIGFuZCBldmVudCBvcmRlcmluZyBjaGVja3NcbiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgICAgICAgLy8gUnVuIHRlcm1pbmFsIHN0YXRlIHZhbGlkYXRpb25cbiAgICAgICAgaWYgKGN1cnJlbnRSdW4gJiYgaXNUZXJtaW5hbFdvcmtmbG93UnVuU3RhdHVzKGN1cnJlbnRSdW4uc3RhdHVzKSkge1xuICAgICAgICAgIGNvbnN0IHJ1blRlcm1pbmFsRXZlbnRzID0gW1xuICAgICAgICAgICAgJ3J1bl9zdGFydGVkJyxcbiAgICAgICAgICAgICdydW5fY29tcGxldGVkJyxcbiAgICAgICAgICAgICdydW5fZmFpbGVkJyxcbiAgICAgICAgICBdO1xuXG4gICAgICAgICAgLy8gSWRlbXBvdGVudCBvcGVyYXRpb246IHJ1bl9jYW5jZWxsZWQgb24gYWxyZWFkeSBjYW5jZWxsZWQgcnVuIGlzIGFsbG93ZWRcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnICYmXG4gICAgICAgICAgICBjdXJyZW50UnVuLnN0YXR1cyA9PT0gJ2NhbmNlbGxlZCdcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIFJldHVybiBleGlzdGluZyBzdGF0ZSAoaWRlbXBvdGVudClcbiAgICAgICAgICAgIGNvbnN0IGV2ZW50OiBFdmVudCA9IHtcbiAgICAgICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBldmVudElkLFxuICAgICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IGNvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2V2ZW50SWR9YDtcbiAgICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnZXZlbnRzJywgY29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICBldmVudFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc29sdmVEYXRhID1cbiAgICAgICAgICAgICAgcGFyYW1zPy5yZXNvbHZlRGF0YSA/PyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT047XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBldmVudDogc3RyaXBFdmVudERhdGFSZWZzKGV2ZW50LCByZXNvbHZlRGF0YSksXG4gICAgICAgICAgICAgIHJ1bjogY3VycmVudFJ1bixcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gRm9yIHJ1bl9zdGFydGVkIG9uIHRlcm1pbmFsIHJ1bnMsIHVzZSBSdW5FeHBpcmVkRXJyb3Igc28gdGhlXG4gICAgICAgICAgLy8gcnVudGltZSBrbm93cyB0byBleGl0IHdpdGhvdXQgcmV0cnlpbmcuXG4gICAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX3N0YXJ0ZWQnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUnVuRXhwaXJlZEVycm9yKFxuICAgICAgICAgICAgICBgV29ya2Zsb3cgcnVuIFwiJHtlZmZlY3RpdmVSdW5JZH1cIiBpcyBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlIFwiJHtjdXJyZW50UnVuLnN0YXR1c31cImBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gT3RoZXIgcnVuIHN0YXRlIHRyYW5zaXRpb25zIGFyZSBub3QgYWxsb3dlZCBvbiB0ZXJtaW5hbCBydW5zXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgcnVuVGVybWluYWxFdmVudHMuaW5jbHVkZXMoZGF0YS5ldmVudFR5cGUpIHx8XG4gICAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgYENhbm5vdCB0cmFuc2l0aW9uIHJ1biBmcm9tIHRlcm1pbmFsIHN0YXRlIFwiJHtjdXJyZW50UnVuLnN0YXR1c31cImBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ3JlYXRpbmcgbmV3IGVudGl0aWVzIG9uIHRlcm1pbmFsIHJ1bnMgaXMgbm90IGFsbG93ZWRcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfY3JlYXRlZCcgfHxcbiAgICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnaG9va19jcmVhdGVkJyB8fFxuICAgICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICd3YWl0X2NyZWF0ZWQnXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgYENhbm5vdCBjcmVhdGUgbmV3IGVudGl0aWVzIG9uIHJ1biBpbiB0ZXJtaW5hbCBzdGF0ZSBcIiR7Y3VycmVudFJ1bi5zdGF0dXN9XCJgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFN0ZXAtcmVsYXRlZCBldmVudCB2YWxpZGF0aW9uIChvcmRlcmluZyBhbmQgdGVybWluYWwgc3RhdGUpXG4gICAgICAgIC8vIFN0b3JlIGV4aXN0aW5nU3RlcCBzbyB3ZSBjYW4gcmV1c2UgaXQgbGF0ZXIgKGF2b2lkIGRvdWJsZSByZWFkKVxuICAgICAgICBsZXQgdmFsaWRhdGVkU3RlcDogU3RlcCB8IG51bGwgPSBudWxsO1xuICAgICAgICBjb25zdCBzdGVwRXZlbnRzID0gW1xuICAgICAgICAgICdzdGVwX3N0YXJ0ZWQnLFxuICAgICAgICAgICdzdGVwX2NvbXBsZXRlZCcsXG4gICAgICAgICAgJ3N0ZXBfZmFpbGVkJyxcbiAgICAgICAgICAnc3RlcF9yZXRyeWluZycsXG4gICAgICAgIF07XG4gICAgICAgIGlmIChzdGVwRXZlbnRzLmluY2x1ZGVzKGRhdGEuZXZlbnRUeXBlKSAmJiBkYXRhLmNvcnJlbGF0aW9uSWQpIHtcbiAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgdmFsaWRhdGVkU3RlcCA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdzdGVwcycsXG4gICAgICAgICAgICBzdGVwQ29tcG9zaXRlS2V5LFxuICAgICAgICAgICAgU3RlcFNjaGVtYSxcbiAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBFdmVudCBvcmRlcmluZzogc3RlcCBtdXN0IGV4aXN0IGJlZm9yZSB0aGVzZSBldmVudHNcbiAgICAgICAgICBpZiAoIXZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBXb3JrZmxvd1dvcmxkRXJyb3IoXG4gICAgICAgICAgICAgIGBTdGVwIFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCIgbm90IGZvdW5kYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBTdGVwIHRlcm1pbmFsIHN0YXRlIHZhbGlkYXRpb25cbiAgICAgICAgICBpZiAoaXNUZXJtaW5hbFN0ZXBTdGF0dXModmFsaWRhdGVkU3RlcC5zdGF0dXMpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgYENhbm5vdCBtb2RpZnkgc3RlcCBpbiB0ZXJtaW5hbCBzdGF0ZSBcIiR7dmFsaWRhdGVkU3RlcC5zdGF0dXN9XCJgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIE9uIHRlcm1pbmFsIHJ1bnM6IG9ubHkgYWxsb3cgY29tcGxldGluZy9mYWlsaW5nIGluLXByb2dyZXNzIHN0ZXBzXG4gICAgICAgICAgaWYgKGN1cnJlbnRSdW4gJiYgaXNUZXJtaW5hbFdvcmtmbG93UnVuU3RhdHVzKGN1cnJlbnRSdW4uc3RhdHVzKSkge1xuICAgICAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXAuc3RhdHVzICE9PSAncnVubmluZycpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bkV4cGlyZWRFcnJvcihcbiAgICAgICAgICAgICAgICBgQ2Fubm90IG1vZGlmeSBub24tcnVubmluZyBzdGVwIG9uIHJ1biBpbiB0ZXJtaW5hbCBzdGF0ZSBcIiR7Y3VycmVudFJ1bi5zdGF0dXN9XCJgXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gSG9vay1yZWxhdGVkIGV2ZW50IHZhbGlkYXRpb24gKG9yZGVyaW5nKVxuICAgICAgICBjb25zdCBob29rRXZlbnRzUmVxdWlyaW5nRXhpc3RlbmNlID0gWydob29rX2Rpc3Bvc2VkJywgJ2hvb2tfcmVjZWl2ZWQnXTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGhvb2tFdmVudHNSZXF1aXJpbmdFeGlzdGVuY2UuaW5jbHVkZXMoZGF0YS5ldmVudFR5cGUpICYmXG4gICAgICAgICAgZGF0YS5jb3JyZWxhdGlvbklkXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IGV4aXN0aW5nSG9vayA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBIb29rU2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmICghZXhpc3RpbmdIb29rKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgSG9va05vdEZvdW5kRXJyb3IoZGF0YS5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gYGV2ZW50YCBtYXkgYmUgcmVhc3NpZ25lZCBsYXRlciBpbiB0aGUgYGhvb2tfY3JlYXRlZGBcbiAgICAgICAgLy8gZGVkdXAtcmVjb3ZlcnkgYnJhbmNoIHRvIHN3YXAgaW4gYSBjYW5vbmljYWwgZXZlbnRJZCAvXG4gICAgICAgIC8vIGNyZWF0ZWRBdCBwZXJzaXN0ZWQgaW4gdGhlIGR1cmFibGUgdG9rZW4gY2xhaW0gc29cbiAgICAgICAgLy8gY29uY3VycmVudCAvIGNyb3NzLXByb2Nlc3Mgd29ya2VycyBjb252ZXJnZSBvbiBhIHNpbmdsZVxuICAgICAgICAvLyBldmVudCBpbiB0aGUgbG9nLlxuICAgICAgICBsZXQgZXZlbnQ6IEV2ZW50ID0ge1xuICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgIGV2ZW50SWQsXG4gICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICB9O1xuICAgICAgICAvLyBTdHJpcCBldmVudERhdGEgZnJvbSBydW5fc3RhcnRlZCDigJQgaXQgYmVsb25ncyBvbiBydW5fY3JlYXRlZCBvbmx5LlxuICAgICAgICBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcgJiYgJ2V2ZW50RGF0YScgaW4gZXZlbnQpIHtcbiAgICAgICAgICBkZWxldGUgKGV2ZW50IGFzIGFueSkuZXZlbnREYXRhO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJhY2sgZW50aXR5IGNyZWF0ZWQvdXBkYXRlZCBmb3IgRXZlbnRSZXN1bHRcbiAgICAgICAgbGV0IHJ1bjogV29ya2Zsb3dSdW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBzdGVwOiBTdGVwIHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgaG9vazogSG9vayB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHdhaXQ6IFdhaXQgfCB1bmRlZmluZWQ7XG4gICAgICAgIC8vIEZvciBgaG9va19jcmVhdGVkYCwgdGhlIGhvb2sgZW50aXR5IHdyaXRlIGlzIGRlZmVycmVkIHVudGlsXG4gICAgICAgIC8vIEFGVEVSIHRoZSBvdXRlciBldmVudCBwdWJsaXNoIHN1Y2NlZWRzLCBzbyBhIHJldHJ5IHRoYXRcbiAgICAgICAgLy8gY29sbGlkZXMgd2l0aCBhbiBhbHJlYWR5LXB1Ymxpc2hlZCBgaG9va19jcmVhdGVkYCBkb2VzIG5vdFxuICAgICAgICAvLyBtdXRhdGUgdGhlIGR1cmFibGUgaG9vayBlbnRpdHkgd2l0aCB0aGUgcmV0cnkncyBwYXlsb2FkLlxuICAgICAgICAvLyBgaG9va0VudGl0eVdyaXRlT3B0aW9uc2AgY2FycmllcyB0aGUgYHsgb3ZlcndyaXRlIH1gIG1vZGVcbiAgICAgICAgLy8gY2hvc2VuIGJ5IHRoZSBkZWR1cC1yZWNvdmVyeSBicmFuY2ggYWJvdmUgKHVuZGVmaW5lZCBmb3JcbiAgICAgICAgLy8gZmlyc3Qgd3JpdGVycywgYHsgb3ZlcndyaXRlOiB0cnVlIH1gIGZvciByZXRyaWVzIHRoYXQgbWF5XG4gICAgICAgIC8vIGJlIHJlcGFpcmluZyBhbiBvcnBoYW5lZCBwYXJ0aWFsIHdyaXRlKS5cbiAgICAgICAgbGV0IGhvb2tFbnRpdHlXcml0ZU9wdGlvbnM6IHsgb3ZlcndyaXRlOiBib29sZWFuIH0gfCB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gQ3JlYXRlL3VwZGF0ZSBlbnRpdHkgYmFzZWQgb24gZXZlbnQgdHlwZSAoZXZlbnQtc291cmNlZCBhcmNoaXRlY3R1cmUpXG4gICAgICAgIC8vIFJ1biBsaWZlY3ljbGUgZXZlbnRzXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jcmVhdGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgY29uc3QgcnVuRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIGRlcGxveW1lbnRJZDogc3RyaW5nO1xuICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICBpbnB1dDogU2VyaWFsaXplZERhdGE7XG4gICAgICAgICAgICBleGVjdXRpb25Db250ZXh0PzogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICAgICAgICB9O1xuICAgICAgICAgIHJ1biA9IHtcbiAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIGRlcGxveW1lbnRJZDogcnVuRGF0YS5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICBzdGF0dXM6ICdwZW5kaW5nJyxcbiAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuRGF0YS53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAvLyBQcm9wYWdhdGUgc3BlY1ZlcnNpb24gZnJvbSB0aGUgZXZlbnQgdG8gdGhlIHJ1biBlbnRpdHlcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ6IHJ1bkRhdGEuZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgIGlucHV0OiBydW5EYXRhLmlucHV0LFxuICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgc3RhcnRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb21wbGV0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICB9O1xuICAgICAgICAgIC8vIEF0b21pY2FsbHkgcHVibGlzaCB0aGUgcnVuIGVudGl0eSBmaWxlIHdpdGhvdXQgb3ZlcndyaXRpbmcgYW5cbiAgICAgICAgICAvLyBleGlzdGluZyB3aW5uZXIuIFRoaXMgcHJldmVudHMgYSBUT0NUT1UgcmFjZSB3aXRoIHRoZSByZXNpbGllbnRcbiAgICAgICAgICAvLyBzdGFydCBwYXRoIChydW5fc3RhcnRlZCBvbiBub24tZXhpc3RlbnQgcnVuKSB0aGF0IGNvdWxkIHJlc3VsdCBpblxuICAgICAgICAgIC8vIGR1cGxpY2F0ZSBydW5fY3JlYXRlZCBldmVudHMgaW4gdGhlIGV2ZW50IGxvZy5cbiAgICAgICAgICBjb25zdCBydW5QYXRoID0gdGFnZ2VkUGF0aChiYXNlZGlyLCAncnVucycsIGVmZmVjdGl2ZVJ1bklkLCB0YWcpO1xuICAgICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICAgIHJ1blBhdGgsXG4gICAgICAgICAgICBKU09OLnN0cmluZ2lmeShydW4sIGpzb25SZXBsYWNlciwgMilcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICghY3JlYXRlZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBXb3JrZmxvdyBydW4gXCIke2VmZmVjdGl2ZVJ1bklkfVwiIGFscmVhZHkgZXhpc3RzYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcpIHtcbiAgICAgICAgICAvLyBSZXVzZSBjdXJyZW50UnVuIGZyb20gdmFsaWRhdGlvbiAoYWxyZWFkeSByZWFkIGFib3ZlKVxuICAgICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgICAvLyBJZiBhbHJlYWR5IHJ1bm5pbmcsIHJldHVybiB0aGUgcnVuIHdpdGhvdXQgaW5zZXJ0aW5nIGFcbiAgICAgICAgICAgIC8vIGR1cGxpY2F0ZSBldmVudC4gIFRoaXMgbWFrZXMgcnVuX3N0YXJ0ZWQgaWRlbXBvdGVudCBmb3JcbiAgICAgICAgICAgIC8vIGNvbmN1cnJlbnQgaW52b2NhdGlvbnMuICBXZSBvbWl0IHByZWxvYWRlZCBldmVudHMgaGVyZVxuICAgICAgICAgICAgLy8gYmVjYXVzZSB0aGlzIGlzIGEgcmFyZSByYWNlLWNvbmRpdGlvbiBwYXRoIOKAlCB0aGUgcnVudGltZVxuICAgICAgICAgICAgLy8gZmFsbHMgYmFjayB0byBsb2FkaW5nIGV2ZW50cyBzZXBhcmF0ZWx5LlxuICAgICAgICAgICAgaWYgKGN1cnJlbnRSdW4uc3RhdHVzID09PSAncnVubmluZycpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgcnVuOiBjdXJyZW50UnVuIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJ1biA9IHtcbiAgICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogY3VycmVudFJ1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogY3VycmVudFJ1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBjdXJyZW50UnVuLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgIGlucHV0OiBjdXJyZW50UnVuLmlucHV0LFxuICAgICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgICBleHBpcmVkQXQ6IGN1cnJlbnRSdW4uZXhwaXJlZEF0LFxuICAgICAgICAgICAgICBzdGF0dXM6ICdydW5uaW5nJyxcbiAgICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIHN0YXJ0ZWRBdDogY3VycmVudFJ1bi5zdGFydGVkQXQgPz8gbm93LFxuICAgICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3J1bnMnLCBlZmZlY3RpdmVSdW5JZCwgdGFnKSxcbiAgICAgICAgICAgICAgcnVuLFxuICAgICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jb21wbGV0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgICBjb25zdCBjb21wbGV0ZWREYXRhID0gZGF0YS5ldmVudERhdGEgYXMgeyBvdXRwdXQ/OiBhbnkgfTtcbiAgICAgICAgICAvLyBSZXVzZSBjdXJyZW50UnVuIGZyb20gdmFsaWRhdGlvbiAoYWxyZWFkeSByZWFkIGFib3ZlKVxuICAgICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgICBydW4gPSB7XG4gICAgICAgICAgICAgIHJ1bklkOiBjdXJyZW50UnVuLnJ1bklkLFxuICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICB3b3JrZmxvd05hbWU6IGN1cnJlbnRSdW4ud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogY3VycmVudFJ1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgICBpbnB1dDogY3VycmVudFJ1bi5pbnB1dCxcbiAgICAgICAgICAgICAgY3JlYXRlZEF0OiBjdXJyZW50UnVuLmNyZWF0ZWRBdCxcbiAgICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgICAgc3RhcnRlZEF0OiBjdXJyZW50UnVuLnN0YXJ0ZWRBdCxcbiAgICAgICAgICAgICAgc3RhdHVzOiAnY29tcGxldGVkJyxcbiAgICAgICAgICAgICAgb3V0cHV0OiBjb21wbGV0ZWREYXRhLm91dHB1dCxcbiAgICAgICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICAgIHJ1bixcbiAgICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fZmFpbGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgY29uc3QgZmFpbGVkRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIGVycm9yOiBhbnk7XG4gICAgICAgICAgICBlcnJvckNvZGU/OiBzdHJpbmc7XG4gICAgICAgICAgfTtcbiAgICAgICAgICAvLyBSZXVzZSBjdXJyZW50UnVuIGZyb20gdmFsaWRhdGlvbiAoYWxyZWFkeSByZWFkIGFib3ZlKVxuICAgICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgICBydW4gPSB7XG4gICAgICAgICAgICAgIHJ1bklkOiBjdXJyZW50UnVuLnJ1bklkLFxuICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICB3b3JrZmxvd05hbWU6IGN1cnJlbnRSdW4ud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogY3VycmVudFJ1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgICBpbnB1dDogY3VycmVudFJ1bi5pbnB1dCxcbiAgICAgICAgICAgICAgY3JlYXRlZEF0OiBjdXJyZW50UnVuLmNyZWF0ZWRBdCxcbiAgICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgICAgc3RhcnRlZEF0OiBjdXJyZW50UnVuLnN0YXJ0ZWRBdCxcbiAgICAgICAgICAgICAgc3RhdHVzOiAnZmFpbGVkJyxcbiAgICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICAgIHR5cGVvZiBmYWlsZWREYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgICAgICA/IGZhaWxlZERhdGEuZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgOiAoZmFpbGVkRGF0YS5lcnJvcj8ubWVzc2FnZSA/PyAnVW5rbm93biBlcnJvcicpLFxuICAgICAgICAgICAgICAgIHN0YWNrOiBmYWlsZWREYXRhLmVycm9yPy5zdGFjayxcbiAgICAgICAgICAgICAgICBjb2RlOiBmYWlsZWREYXRhLmVycm9yQ29kZSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICAgIHJ1bixcbiAgICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fY2FuY2VsbGVkJykge1xuICAgICAgICAgIC8vIFJldXNlIGN1cnJlbnRSdW4gZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHtcbiAgICAgICAgICAgIHJ1biA9IHtcbiAgICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogY3VycmVudFJ1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogY3VycmVudFJ1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBjdXJyZW50UnVuLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgIGlucHV0OiBjdXJyZW50UnVuLmlucHV0LFxuICAgICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgICBleHBpcmVkQXQ6IGN1cnJlbnRSdW4uZXhwaXJlZEF0LFxuICAgICAgICAgICAgICBzdGFydGVkQXQ6IGN1cnJlbnRSdW4uc3RhcnRlZEF0LFxuICAgICAgICAgICAgICBzdGF0dXM6ICdjYW5jZWxsZWQnLFxuICAgICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyksXG4gICAgICAgICAgICAgIHJ1bixcbiAgICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgLy8gU3RlcCBsaWZlY3ljbGUgZXZlbnRzXG4gICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX2NyZWF0ZWQnICYmXG4gICAgICAgICAgJ2V2ZW50RGF0YScgaW4gZGF0YVxuICAgICAgICApIHtcbiAgICAgICAgICAvLyBzdGVwX2NyZWF0ZWQ6IENyZWF0ZXMgc3RlcCBlbnRpdHkgd2l0aCBzdGF0dXMgJ3BlbmRpbmcnLCBhdHRlbXB0PTAsIGNyZWF0ZWRBdCBzZXRcbiAgICAgICAgICBjb25zdCBzdGVwRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIHN0ZXBOYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICBpbnB1dDogYW55O1xuICAgICAgICAgIH07XG4gICAgICAgICAgc3RlcCA9IHtcbiAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIHN0ZXBJZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgc3RlcE5hbWU6IHN0ZXBEYXRhLnN0ZXBOYW1lLFxuICAgICAgICAgICAgc3RhdHVzOiAncGVuZGluZycsXG4gICAgICAgICAgICBpbnB1dDogc3RlcERhdGEuaW5wdXQsXG4gICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBhdHRlbXB0OiAwLFxuICAgICAgICAgICAgc3RhcnRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb21wbGV0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIC8vIFByb3BhZ2F0ZSBzcGVjVmVyc2lvbiBmcm9tIHRoZSBldmVudCB0byB0aGUgc3RlcCBlbnRpdHlcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IHN0ZXBDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICBzdGVwXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfc3RhcnRlZCcpIHtcbiAgICAgICAgICAvLyBzdGVwX3N0YXJ0ZWQ6IEluY3JlbWVudHMgYXR0ZW1wdCwgc2V0cyBzdGF0dXMgdG8gJ3J1bm5pbmcnXG4gICAgICAgICAgLy8gU2V0cyBzdGFydGVkQXQgb25seSBvbiB0aGUgZmlyc3Qgc3RhcnQgKG5vdCB1cGRhdGVkIG9uIHJldHJpZXMpXG4gICAgICAgICAgLy8gUmV1c2UgdmFsaWRhdGVkU3RlcCBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgICBpZiAodmFsaWRhdGVkU3RlcCkge1xuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgcmV0cnlBZnRlciB0aW1lc3RhbXAgaGFzbid0IGJlZW4gcmVhY2hlZCB5ZXRcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgdmFsaWRhdGVkU3RlcC5yZXRyeUFmdGVyICYmXG4gICAgICAgICAgICAgIHZhbGlkYXRlZFN0ZXAucmV0cnlBZnRlci5nZXRUaW1lKCkgPiBEYXRlLm5vdygpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IFRvb0Vhcmx5RXJyb3IoXG4gICAgICAgICAgICAgICAgYENhbm5vdCBzdGFydCBzdGVwIFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCI6IHJldHJ5QWZ0ZXIgdGltZXN0YW1wIGhhcyBub3QgYmVlbiByZWFjaGVkIHlldGAsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgcmV0cnlBZnRlcjogTWF0aC5jZWlsKFxuICAgICAgICAgICAgICAgICAgICAodmFsaWRhdGVkU3RlcC5yZXRyeUFmdGVyLmdldFRpbWUoKSAtIERhdGUubm93KCkpIC8gMTAwMFxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEJlc3QtZWZmb3J0IGd1YXJkOiByZS1yZWFkIHRoZSBzdGVwIGVudGl0eSB0byBjaGVjayBpZiBpdFxuICAgICAgICAgICAgLy8gcmVhY2hlZCB0ZXJtaW5hbCBzdGF0ZSBiZXR3ZWVuIHRoZSB2YWxpZGF0aW9uIHJlYWQgYW5kIG5vdy5cbiAgICAgICAgICAgIC8vIFRoaXMgbmFycm93cyB0aGUgVE9DVE9VIHdpbmRvdyBidXQgZG9lcyBub3QgZnVsbHkgZWxpbWluYXRlIGl0XG4gICAgICAgICAgICAvLyAodGhlIGxvY2FsIHdvcmxkIGlzIHNpbmdsZS1wcm9jZXNzIC8gZGV2LW9ubHk7IHRoZSBwb3N0Z3Jlc1xuICAgICAgICAgICAgLy8gd29ybGQgdXNlcyBTUUwtbGV2ZWwgYXRvbWljIGd1YXJkcyBmb3IgcHJvZHVjdGlvbikuXG4gICAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgICBjb25zdCBmcmVzaFN0ZXAgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgJ3N0ZXBzJyxcbiAgICAgICAgICAgICAgc3RlcENvbXBvc2l0ZUtleSxcbiAgICAgICAgICAgICAgU3RlcFNjaGVtYSxcbiAgICAgICAgICAgICAgdGFnXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKGZyZXNoU3RlcCAmJiBpc1Rlcm1pbmFsU3RlcFN0YXR1cyhmcmVzaFN0ZXAuc3RhdHVzKSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgICBgQ2Fubm90IG1vZGlmeSBzdGVwIGluIHRlcm1pbmFsIHN0YXRlIFwiJHtmcmVzaFN0ZXAuc3RhdHVzfVwiYFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzdGVwID0ge1xuICAgICAgICAgICAgICAuLi52YWxpZGF0ZWRTdGVwLFxuICAgICAgICAgICAgICBzdGF0dXM6ICdydW5uaW5nJyxcbiAgICAgICAgICAgICAgLy8gT25seSBzZXQgc3RhcnRlZEF0IG9uIHRoZSBmaXJzdCBzdGFydFxuICAgICAgICAgICAgICBzdGFydGVkQXQ6IHZhbGlkYXRlZFN0ZXAuc3RhcnRlZEF0ID8/IG5vdyxcbiAgICAgICAgICAgICAgLy8gSW5jcmVtZW50IGF0dGVtcHQgY291bnRlciBvbiBldmVyeSBzdGFydFxuICAgICAgICAgICAgICBhdHRlbXB0OiB2YWxpZGF0ZWRTdGVwLmF0dGVtcHQgKyAxLFxuICAgICAgICAgICAgICAvLyBDbGVhciByZXRyeUFmdGVyIG5vdyB0aGF0IHRoZSBzdGVwIGhhcyBzdGFydGVkXG4gICAgICAgICAgICAgIHJldHJ5QWZ0ZXI6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9jb21wbGV0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgICAvLyBzdGVwX2NvbXBsZXRlZDogVGVybWluYWwgc3RhdGUgd2l0aCBvdXRwdXRcbiAgICAgICAgICAvLyBVc2VzIHdyaXRlRXhjbHVzaXZlIG9uIGEgbG9jayBmaWxlIHRvIGF0b21pY2FsbHkgcHJldmVudCBjb25jdXJyZW50XG4gICAgICAgICAgLy8gaW52b2NhdGlvbnMgZnJvbSBib3RoIGNvbXBsZXRpbmcgdGhlIHNhbWUgc3RlcCAoVE9DVE9VIHJhY2UpLlxuICAgICAgICAgIGNvbnN0IGNvbXBsZXRlZERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7IHJlc3VsdDogYW55IH07XG4gICAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICAgIGNvbnN0IHN0ZXBDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgICAgIGNvbnN0IGxvY2tOYW1lID0gdGFnXG4gICAgICAgICAgICAgID8gYCR7c3RlcENvbXBvc2l0ZUtleX0udGVybWluYWwuJHt0YWd9YFxuICAgICAgICAgICAgICA6IGAke3N0ZXBDb21wb3NpdGVLZXl9LnRlcm1pbmFsYDtcbiAgICAgICAgICAgIGNvbnN0IHRlcm1pbmFsTG9ja1BhdGggPSByZXNvbHZlV2l0aGluQmFzZShcbiAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgICAgICdzdGVwcycsXG4gICAgICAgICAgICAgIGxvY2tOYW1lXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgY2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKHRlcm1pbmFsTG9ja1BhdGgsICcnKTtcbiAgICAgICAgICAgIGlmICghY2xhaW1lZCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgICAnQ2Fubm90IG1vZGlmeSBzdGVwIGluIHRlcm1pbmFsIHN0YXRlJ1xuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RlcCA9IHtcbiAgICAgICAgICAgICAgLi4udmFsaWRhdGVkU3RlcCxcbiAgICAgICAgICAgICAgc3RhdHVzOiAnY29tcGxldGVkJyxcbiAgICAgICAgICAgICAgb3V0cHV0OiBjb21wbGV0ZWREYXRhLnJlc3VsdCxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9mYWlsZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgICAvLyBzdGVwX2ZhaWxlZDogVGVybWluYWwgc3RhdGUgd2l0aCBlcnJvclxuICAgICAgICAgIC8vIFVzZXMgd3JpdGVFeGNsdXNpdmUgb24gYSBsb2NrIGZpbGUgdG8gYXRvbWljYWxseSBwcmV2ZW50IGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggZmFpbGluZyB0aGUgc2FtZSBzdGVwIChUT0NUT1UgcmFjZSkuXG4gICAgICAgICAgY29uc3QgZmFpbGVkRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIGVycm9yOiBhbnk7XG4gICAgICAgICAgICBzdGFjaz86IHN0cmluZztcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmICh2YWxpZGF0ZWRTdGVwKSB7XG4gICAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgICBjb25zdCBsb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgICA/IGAke3N0ZXBDb21wb3NpdGVLZXl9LnRlcm1pbmFsLiR7dGFnfWBcbiAgICAgICAgICAgICAgOiBgJHtzdGVwQ29tcG9zaXRlS2V5fS50ZXJtaW5hbGA7XG4gICAgICAgICAgICBjb25zdCB0ZXJtaW5hbExvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgICAnc3RlcHMnLFxuICAgICAgICAgICAgICBsb2NrTmFtZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IGNsYWltZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZSh0ZXJtaW5hbExvY2tQYXRoLCAnJyk7XG4gICAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICAgJ0Nhbm5vdCBtb2RpZnkgc3RlcCBpbiB0ZXJtaW5hbCBzdGF0ZSdcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGVycm9yID0ge1xuICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgIHR5cGVvZiBmYWlsZWREYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgICAgPyBmYWlsZWREYXRhLmVycm9yXG4gICAgICAgICAgICAgICAgICA6IChmYWlsZWREYXRhLmVycm9yPy5tZXNzYWdlID8/ICdVbmtub3duIGVycm9yJyksXG4gICAgICAgICAgICAgIHN0YWNrOiBmYWlsZWREYXRhLnN0YWNrLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICAgIC4uLnZhbGlkYXRlZFN0ZXAsXG4gICAgICAgICAgICAgIHN0YXR1czogJ2ZhaWxlZCcsXG4gICAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3N0ZXBzJywgc3RlcENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX3JldHJ5aW5nJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgLy8gc3RlcF9yZXRyeWluZzogU2V0cyBzdGF0dXMgYmFjayB0byAncGVuZGluZycsIHJlY29yZHMgZXJyb3JcbiAgICAgICAgICAvLyBSZXVzZSB2YWxpZGF0ZWRTdGVwIGZyb20gdmFsaWRhdGlvbiAoYWxyZWFkeSByZWFkIGFib3ZlKVxuICAgICAgICAgIGNvbnN0IHJldHJ5RGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIGVycm9yOiBhbnk7XG4gICAgICAgICAgICBzdGFjaz86IHN0cmluZztcbiAgICAgICAgICAgIHJldHJ5QWZ0ZXI/OiBEYXRlO1xuICAgICAgICAgIH07XG4gICAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICAgIGNvbnN0IHN0ZXBDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICAgIC4uLnZhbGlkYXRlZFN0ZXAsXG4gICAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgICBlcnJvcjoge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgICAgICAgICB0eXBlb2YgcmV0cnlEYXRhLmVycm9yID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgICAgICAgICA/IHJldHJ5RGF0YS5lcnJvclxuICAgICAgICAgICAgICAgICAgICA6IChyZXRyeURhdGEuZXJyb3I/Lm1lc3NhZ2UgPz8gJ1Vua25vd24gZXJyb3InKSxcbiAgICAgICAgICAgICAgICBzdGFjazogcmV0cnlEYXRhLnN0YWNrLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICByZXRyeUFmdGVyOiByZXRyeURhdGEucmV0cnlBZnRlcixcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIC8vIEhvb2sgbGlmZWN5Y2xlIGV2ZW50c1xuICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnaG9va19jcmVhdGVkJyAmJlxuICAgICAgICAgICdldmVudERhdGEnIGluIGRhdGFcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgaG9va0RhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICB0b2tlbjogc3RyaW5nO1xuICAgICAgICAgICAgbWV0YWRhdGE/OiBhbnk7XG4gICAgICAgICAgICBpc1dlYmhvb2s/OiBib29sZWFuO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICAvLyBBdG9taWNhbGx5IGNsYWltIHRoZSB0b2tlbiB1c2luZyBhbiBleGNsdXNpdmUtY3JlYXRlIGNvbnN0cmFpbnQgZmlsZS5cbiAgICAgICAgICAvLyBUaGlzIGF2b2lkcyB0aGUgVE9DVE9VIHJhY2Ugb2YgdGhlIHByZXZpb3VzIHJlYWQtYWxsLXRoZW4tY2hlY2sgYXBwcm9hY2guXG4gICAgICAgICAgY29uc3QgY29uc3RyYWludFBhdGggPSBwYXRoLmpvaW4oXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJ2hvb2tzJyxcbiAgICAgICAgICAgICd0b2tlbnMnLFxuICAgICAgICAgICAgYCR7aGFzaFRva2VuKGhvb2tEYXRhLnRva2VuKX0uanNvbmBcbiAgICAgICAgICApO1xuICAgICAgICAgIC8vIFdoZW4gdGhlIGNsYWltIGlzIGFic2VudCwgdGhlIGV2ZW50IGxvZyBpcyB0aGUgb25seSBkdXJhYmxlIHNvdXJjZVxuICAgICAgICAgIC8vIHRoYXQgY2FuIGRpc3Rpbmd1aXNoIGEgZmlyc3QgaG9vayBmcm9tIGEgY3Jhc2gtbG9zdCB0b2tlbiBjYWNoZS5cbiAgICAgICAgICBpZiAoIShhd2FpdCByZWFkSG9va1Rva2VuQ2xhaW0oY29uc3RyYWludFBhdGgpKSkge1xuICAgICAgICAgICAgYXdhaXQgcmVidWlsZExpdmVIb29rQnlUb2tlbkZyb21FdmVudExvZyhcbiAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgaG9va0RhdGEudG9rZW4sXG4gICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gUGVyc2lzdCBgZXZlbnRJZGAgaW4gdGhlIGNsYWltIHNvIGNvbmN1cnJlbnQgLyBjcm9zcy1cbiAgICAgICAgICAvLyBwcm9jZXNzIHJldHJpZXMgY2FuIGNvbnZlcmdlIG9uIGEgc2luZ2xlIGNhbm9uaWNhbFxuICAgICAgICAgIC8vIGBob29rX2NyZWF0ZWRgIGV2ZW50IHBhdGguIFNlZSB0aGUgcmVjb3ZlcnkgY29tbWVudFxuICAgICAgICAgIC8vIGJlbG93LlxuICAgICAgICAgIGNvbnN0IHRva2VuQ2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKFxuICAgICAgICAgICAgY29uc3RyYWludFBhdGgsXG4gICAgICAgICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgIHRva2VuOiBob29rRGF0YS50b2tlbixcbiAgICAgICAgICAgICAgaG9va0lkOiBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIFJlY292ZXJ5IHNoYXBlOiB0aGUgZHVyYWJsZSByZWNvcmQgb2YgYSBzdWNjZXNzZnVsIGhvb2tcbiAgICAgICAgICAvLyBjcmVhdGlvbiBpcyB0aGUgYGhvb2tfY3JlYXRlZGAgZXZlbnQgaW4gdGhlIGV2ZW50IGxvZy4gVGhlXG4gICAgICAgICAgLy8gY2xhaW0gZmlsZSBhbmQgaG9vayBlbnRpdHkgYXJlIHdyaXR0ZW4gYmVmb3JlIHRoZSBldmVudCxcbiAgICAgICAgICAvLyBhbmQgdGhlIHRocmVlIHdyaXRlcyBhcmUgTk9UIGF0b21pYywgc28gYSBjcmFzaCBhdCBhbnlcbiAgICAgICAgICAvLyBwb2ludCBjYW4gbGVhdmUgb25lIG9yIHR3byBvZiB0aGVtIG9uIGRpc2sgd2l0aG91dCB0aGVcbiAgICAgICAgICAvLyBldmVudC4gVHJlYXRpbmcgdGhvc2UgYXMgXCJjb21wbGV0ZWRcIiB3b3VsZCBoYXZlIHRoZVxuICAgICAgICAgIC8vIHN1c3BlbnNpb24gaGFuZGxlciBzd2FsbG93IHRoZSByZXRyeSBhbmQgcGVybWFuZW50bHkgbG9zZVxuICAgICAgICAgIC8vIHRoZSBgaG9va19jcmVhdGVkYCBldmVudCBmcm9tIHRoZSBsb2cuXG4gICAgICAgICAgLy9cbiAgICAgICAgICAvLyBXaGVuIHRoZSBkZWR1cCBicmFuY2ggZmlyZXMgZm9yIHRoZSBzYW1lIGAocnVuSWQsIGhvb2tJZClgLFxuICAgICAgICAgIC8vIHdlIGNvbnZlcmdlIG9uIHRoZSBjYW5vbmljYWwgYGV2ZW50SWRgIHBlcnNpc3RlZCBpbiB0aGVcbiAgICAgICAgICAvLyBjbGFpbSBmaWxlIGJ5IHRoZSBvcmlnaW5hbCAod2lubmluZykgYHdyaXRlRXhjbHVzaXZlYC4gQnlcbiAgICAgICAgICAvLyBhZG9wdGluZyB0aGF0IGV2ZW50SWQgZm9yIHRoaXMgcmV0cnkncyBldmVudCB3cml0ZSDigJQgYW5kXG4gICAgICAgICAgLy8gbGV0dGluZyB0aGUgb3V0ZXIgbm8tb3ZlcndyaXRlIGB3cml0ZUpTT05gIGZvciB0aGUgZXZlbnRcbiAgICAgICAgICAvLyB0aHJvdyBgRW50aXR5Q29uZmxpY3RFcnJvcmAgb24gY29sbGlzaW9uIOKAlCBjb25jdXJyZW50IC9cbiAgICAgICAgICAvLyBjcm9zcy1wcm9jZXNzIHdvcmtlcnMgZWl0aGVyOlxuICAgICAgICAgIC8vICAgLSBwdWJsaXNoIHRoZSBzYW1lIGV2ZW50IGF0IHRoZSBzYW1lIHBhdGggZXhhY3RseSBvbmNlXG4gICAgICAgICAgLy8gICAgICh0aGUgbG9zZXIncyBgd3JpdGVKU09OYCB0aHJvd3MgRW50aXR5Q29uZmxpY3RFcnJvcixcbiAgICAgICAgICAvLyAgICAgd2hpY2ggdGhlIHJ1bnRpbWUncyBleGlzdGluZyBjb25jdXJyZW50LXJlcGxheSBjYXRjaFxuICAgICAgICAgIC8vICAgICBwYXRoIGF0IHN1c3BlbnNpb24taGFuZGxlci50czoxNDIgc3dhbGxvd3MpLCBvclxuICAgICAgICAgIC8vICAgLSBjb252ZXJnZSBvbiBhIHNpbmdsZSByZWNvdmVyeSB3cml0ZSB3aGVuIHRoZSBwcmlvclxuICAgICAgICAgIC8vICAgICBjbGFpbSB3YXMgb3JwaGFuZWQgYnkgYSBjcmFzaCBiZWZvcmUgdGhlIGV2ZW50IGxhbmRlZC5cbiAgICAgICAgICAvL1xuICAgICAgICAgIC8vIFRoZSBsZWdhY3kgZmFsbGJhY2sgKGBleGlzdGluZ0NsYWltLmV2ZW50SWRgIHVuZGVmaW5lZClcbiAgICAgICAgICAvLyBpcyBmb3IgY2xhaW0gZmlsZXMgd3JpdHRlbiBiZWZvcmUgdGhpcyBmaWVsZCB3YXMgYWRkZWQg4oCUXG4gICAgICAgICAgLy8gdGhvc2UgcHJvYmUgdGhlIGV2ZW50IGxvZyBkaXJlY3RseSBhbmQgZmFsbCB0aHJvdWdoIHRvIGFcbiAgICAgICAgICAvLyBmcmVzaC1ldmVudElkIHJlY292ZXJ5IHdyaXRlLiBUaGUgbGVnYWN5IHBhdGggZG9lcyBub3RcbiAgICAgICAgICAvLyBjb252ZXJnZSBhY3Jvc3Mgd29ya2VycyBidXQgY2Fubm90IHJlZ3Jlc3MgYmVoYXZpb3IgZm9yXG4gICAgICAgICAgLy8gZnJlc2hseS13cml0dGVuIGNsYWltcy5cbiAgICAgICAgICAvL1xuICAgICAgICAgIC8vIFRoZSBgd2l0aEhvb2tMb2NrYCBpbi1wcm9jZXNzIG11dGV4IGFib3ZlIGtlZXBzIHR3byBzYW1lLVxuICAgICAgICAgIC8vIHRpY2sgaW4tcHJvY2VzcyBjYWxsZXJzIGZyb20gcmFjaW5nIGludG8gdGhpcyBicmFuY2ggd2l0aFxuICAgICAgICAgIC8vIHRoZSB3aW5uZXIgbWlkLXdyaXRlLCBidXQgaXMgbm90IHN1ZmZpY2llbnQgYWNyb3NzXG4gICAgICAgICAgLy8gcHJvY2Vzc2VzIOKAlCB0aGUgZHVyYWJsZSBjb252ZXJnZW5jZSBrZXkgKGBjbGFpbS5ldmVudElkYClcbiAgICAgICAgICAvLyBpcyB3aGF0IGNsb3NlcyB0aGUgY3Jvc3MtcHJvY2VzcyByYWNlLlxuICAgICAgICAgIGxldCB3cml0ZUhvb2tFbnRpdHlXaXRoT3ZlcndyaXRlID0gZmFsc2U7XG5cbiAgICAgICAgICBpZiAoIXRva2VuQ2xhaW1lZCkge1xuICAgICAgICAgICAgY29uc3QgZXhpc3RpbmdDbGFpbSA9IGF3YWl0IHJlYWRIb29rVG9rZW5DbGFpbShjb25zdHJhaW50UGF0aCk7XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgZXhpc3RpbmdDbGFpbT8ucnVuSWQgPT09IGVmZmVjdGl2ZVJ1bklkICYmXG4gICAgICAgICAgICAgIGV4aXN0aW5nQ2xhaW0uaG9va0lkID09PSBkYXRhLmNvcnJlbGF0aW9uSWRcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAvLyBBZG9wdCBhIGNhbm9uaWNhbCBldmVudElkIGZvciB0aGUgcmVjb3Zlcnkgd3JpdGUuIFRoZVxuICAgICAgICAgICAgICAvLyBvdXRlciBldmVudCBwdWJsaXNoIChgd3JpdGVFeGNsdXNpdmUoZXZlbnRQYXRoKWApXG4gICAgICAgICAgICAgIC8vIGVpdGhlciBzdWNjZWVkcyAod2UgcHVibGlzaCB0aGUgY2Fub25pY2FsIGV2ZW50LFxuICAgICAgICAgICAgICAvLyByZXBhaXJpbmcgYSBwYXJ0aWFsIHdyaXRlIGxlZnQgYnkgdGhlIG9yaWdpbmFsXG4gICAgICAgICAgICAgIC8vIGNsYWltYW50KSBvciByZXR1cm5zIGBmYWxzZWAgYW5kIHdlIHRocm93XG4gICAgICAgICAgICAgIC8vIGBFbnRpdHlDb25mbGljdEVycm9yYCAodGhlIGV2ZW50IHdhcyBhbHJlYWR5XG4gICAgICAgICAgICAgIC8vIHB1Ymxpc2hlZCDigJQgYSByZWFsIGR1cGxpY2F0ZSkuIEVpdGhlciB3YXkgdGhlIGxvZ1xuICAgICAgICAgICAgICAvLyBlbmRzIHdpdGggZXhhY3RseSBvbmUgYGhvb2tfY3JlYXRlZGAgZXZlbnQgZm9yIHRoaXNcbiAgICAgICAgICAgICAgLy8gYChydW5JZCwgaG9va0lkKWAuXG4gICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgIC8vIFRoZSBjYW5vbmljYWwgZXZlbnRJZCBjb21lcyBmcm9tIG9uZSBvZiB0d28gcGxhY2VzOlxuICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAvLyAgIC0gYGV4aXN0aW5nQ2xhaW0uZXZlbnRJZGAgZm9yIGNsYWltcyB3cml0dGVuIGJ5XG4gICAgICAgICAgICAgIC8vICAgICB0aGlzIHZlcnNpb24gKHRoZSB3cml0ZXIgYWJvdmUgcGVyc2lzdHMgdGhlXG4gICAgICAgICAgICAgIC8vICAgICBjYW5kaWRhdGUgZXZlbnRJZCBhdG9taWNhbGx5IHdpdGggdGhlIGNsYWltKS5cbiAgICAgICAgICAgICAgLy8gICAgIFRoZSBldmVudElkIGlzIGR1cmFibGUsIHNvIHRoZSBvdXRlclxuICAgICAgICAgICAgICAvLyAgICAgYHdyaXRlRXhjbHVzaXZlKGV2ZW50UGF0aClgIGFsb25lIGlzIGVub3VnaCB0b1xuICAgICAgICAgICAgICAvLyAgICAgYXJiaXRyYXRlIHB1YmxpY2F0aW9uOiBpdCBmYWlscyBpZmYgdGhlIGV2ZW50XG4gICAgICAgICAgICAgIC8vICAgICB3YXMgYWxyZWFkeSBwdWJsaXNoZWQgYXQgdGhhdCBleGFjdCBwYXRoLlxuICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAvLyAgIC0gVGhlIHJlY292ZXJ5LW1hcmtlciBzaWRlY2FyIGZvciBsZWdhY3kgY2xhaW1zXG4gICAgICAgICAgICAgIC8vICAgICB3cml0dGVuIGJlZm9yZSBgZXZlbnRJZGAgd2FzIHBlcnNpc3RlZCBpbmxpbmVcbiAgICAgICAgICAgICAgLy8gICAgIGluIHRoZSBjbGFpbS4gVGhlIG1hcmtlciBpcyBpdHNlbGYgYVxuICAgICAgICAgICAgICAvLyAgICAgYHdyaXRlRXhjbHVzaXZlYCwgc28gdGhlIGZpcnN0IHJldHJ5IHBpbnMgaXRzXG4gICAgICAgICAgICAgIC8vICAgICBjYW5kaWRhdGUgZXZlbnRJZCBhcyBjYW5vbmljYWwgYW5kIHN1YnNlcXVlbnRcbiAgICAgICAgICAgICAgLy8gICAgIHJldHJpZXMgYWRvcHQgaXQuIFdpdGhvdXQgdGhpcywgdHdvIHByb2Nlc3Nlc1xuICAgICAgICAgICAgICAvLyAgICAgYm90aCByZWFkaW5nIHRoZSBzYW1lIGxlZ2FjeSBjbGFpbSB3b3VsZCBlYWNoXG4gICAgICAgICAgICAgIC8vICAgICBnZW5lcmF0ZSB0aGVpciBvd24gZXZlbnRJZCwgbGFuZCB0aGVpclxuICAgICAgICAgICAgICAvLyAgICAgYHdyaXRlRXhjbHVzaXZlKGV2ZW50UGF0aClgIGNhbGxzIGF0IGRpZmZlcmVudFxuICAgICAgICAgICAgICAvLyAgICAgcGF0aHMsIGFuZCBhcHBlbmQgdHdvIGV2ZW50cy5cbiAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgLy8gICAgIEZvciBsZWdhY3kgY2xhaW1zIHdlIGFsc28gbXVzdCBwcm9iZSB0aGUgZXZlbnRcbiAgICAgICAgICAgICAgLy8gICAgIGxvZyBmb3IgYW4gZXhpc3RpbmcgYGhvb2tfY3JlYXRlZGAgZXZlbnQgQkVGT1JFXG4gICAgICAgICAgICAgIC8vICAgICBwaW5uaW5nIGEgY2Fub25pY2FsIGV2ZW50SWQ6IHRoZSBwcmUtdXBncmFkZVxuICAgICAgICAgICAgICAvLyAgICAgd3JpdGVyIG1heSBoYXZlIGFscmVhZHkgcHVibGlzaGVkIHRoZSBldmVudFxuICAgICAgICAgICAgICAvLyAgICAgd2l0aCBpdHMgb3duIGV2ZW50SWQsIGFuZCB0aGUgbWFya2VyIGhhcyBubyB3YXlcbiAgICAgICAgICAgICAgLy8gICAgIG9mIGtub3dpbmcgdGhhdCBldmVudElkIGFmdGVyIHRoZSBmYWN0LiBXaXRob3V0XG4gICAgICAgICAgICAgIC8vICAgICB0aGlzIHByb2JlLCBhIHBvc3QtdXBncmFkZSByZXRyeSB3b3VsZCBwaW4gYVxuICAgICAgICAgICAgICAvLyAgICAgZGlmZmVyZW50IGV2ZW50SWQsIHdyaXRlIGEgaG9vayBlbnRpdHksIGFuZFxuICAgICAgICAgICAgICAvLyAgICAgcHVibGlzaCBhIGR1cGxpY2F0ZSBldmVudCBhdCB0aGUgbWFya2VyJ3MgcGF0aC5cbiAgICAgICAgICAgICAgbGV0IGNhbm9uaWNhbEV2ZW50SWQ6IHN0cmluZztcbiAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nQ2xhaW0uZXZlbnRJZCkge1xuICAgICAgICAgICAgICAgIGNhbm9uaWNhbEV2ZW50SWQgPSBleGlzdGluZ0NsYWltLmV2ZW50SWQ7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYWxyZWFkeVB1Ymxpc2hlZEV2ZW50SWQgPVxuICAgICAgICAgICAgICAgICAgYXdhaXQgZmluZEV4aXN0aW5nSG9va0NyZWF0ZWRFdmVudElkKFxuICAgICAgICAgICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGlmIChhbHJlYWR5UHVibGlzaGVkRXZlbnRJZCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgLy8gVGhlIHByZS11cGdyYWRlIHdyaXRlciBtYXkgaGF2ZSBjcmFzaGVkIGJldHdlZW5cbiAgICAgICAgICAgICAgICAgIC8vIGl0cyBldmVudCBwdWJsaXNoIGFuZCBpdHMgaG9vayBlbnRpdHkgd3JpdGUg4oCUXG4gICAgICAgICAgICAgICAgICAvLyByZXBhaXIgdGhlIGVudGl0eSBmcm9tIHRoZSBwZXJzaXN0ZWQgZXZlbnQnc1xuICAgICAgICAgICAgICAgICAgLy8gcGF5bG9hZCBiZWZvcmUgc3VyZmFjaW5nIHRoZSBiZW5pZ24gZHVwbGljYXRlLlxuICAgICAgICAgICAgICAgICAgYXdhaXQgcmVwYWlySG9va0VudGl0eUZyb21QZXJzaXN0ZWRFdmVudChcbiAgICAgICAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgICAgIGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgYWxyZWFkeVB1Ymxpc2hlZEV2ZW50SWQsXG4gICAgICAgICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBgSG9vayBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIGFscmVhZHkgY3JlYXRlZGBcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHBpbm5lZCA9IGF3YWl0IHBpbkNhbm9uaWNhbEV2ZW50SWRGb3JMZWdhY3lDbGFpbShcbiAgICAgICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICAgICBob29rRGF0YS50b2tlbixcbiAgICAgICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICAgICAgZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgZXZlbnRJZFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWYgKHBpbm5lZCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgLy8gTG9zdCB0aGUgbWFya2VyIHJhY2UgYW5kIHRoZSBtYXJrZXIgZmlsZSBpc1xuICAgICAgICAgICAgICAgICAgLy8gdW5yZWFkYWJsZSAoZXh0cmVtZWx5IHJhcmU7IGNvcnJ1cHRlZCBkaXNrKS5cbiAgICAgICAgICAgICAgICAgIC8vIFRyZWF0IGFzIGEgcmVhbCBkdXBsaWNhdGUgc28gdGhlIHJ1bnRpbWUnc1xuICAgICAgICAgICAgICAgICAgLy8gY29uY3VycmVudC1yZXBsYXkgY2F0Y2ggcGF0aCBzd2FsbG93cyB0aGlzXG4gICAgICAgICAgICAgICAgICAvLyBhdHRlbXB0IGluc3RlYWQgb2Ygcmlza2luZyBkaXZlcmdlbnRcbiAgICAgICAgICAgICAgICAgIC8vIHB1YmxpY2F0aW9uLlxuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIGBIb29rIFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCIgYWxyZWFkeSBjcmVhdGVkYFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2Fub25pY2FsRXZlbnRJZCA9IHBpbm5lZDtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIFJlYnVpbGQgYGV2ZW50YCB3aXRoIHRoZSBjYW5vbmljYWwgZXZlbnRJZCBhbmQgYVxuICAgICAgICAgICAgICAvLyBkZXRlcm1pbmlzdGljIGBjcmVhdGVkQXRgIGRlcml2ZWQgZnJvbSB0aGUgZXZlbnRJZFxuICAgICAgICAgICAgICAvLyAoYSBVTElEKSBzbyB0d28gd29ya2VycyB3cml0aW5nIHRoZSBzYW1lIGV2ZW50XG4gICAgICAgICAgICAgIC8vIHByb2R1Y2UgYnl0ZS1pZGVudGljYWwgY29udGVudC5cbiAgICAgICAgICAgICAgZXZlbnRJZCA9IGNhbm9uaWNhbEV2ZW50SWQ7XG4gICAgICAgICAgICAgIGNvbnN0IGNhbm9uaWNhbENyZWF0ZWRBdCA9XG4gICAgICAgICAgICAgICAgdWxpZFRvRGF0ZShldmVudElkLnJlcGxhY2UoL15ldm50Xy8sICcnKSkgPz8gbm93O1xuICAgICAgICAgICAgICBldmVudCA9IHtcbiAgICAgICAgICAgICAgICAuLi5kYXRhLFxuICAgICAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICAgICBldmVudElkLFxuICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogY2Fub25pY2FsQ3JlYXRlZEF0LFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgd3JpdGVIb29rRW50aXR5V2l0aE92ZXJ3cml0ZSA9IHRydWU7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBDcm9zcy1ob29rIC8gY3Jvc3MtcnVuIGNvbmZsaWN0OiBhIGRpZmZlcmVudFxuICAgICAgICAgICAgICAvLyAocnVuSWQsIGhvb2tJZCkgaG9sZHMgdGhpcyB0b2tlbi4gQ3JlYXRlIGFcbiAgICAgICAgICAgICAgLy8gaG9va19jb25mbGljdCBldmVudCBzbyB0aGUgd29ya2Zsb3cgY2FuIGZhaWxcbiAgICAgICAgICAgICAgLy8gZ3JhY2VmdWxseSB3aGVuIHRoZSBob29rIGlzIGF3YWl0ZWQuXG4gICAgICAgICAgICAgIGNvbnN0IGNvbmZsaWN0RXZlbnQ6IEV2ZW50ID0ge1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfY29uZmxpY3QnLFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgIHRva2VuOiBob29rRGF0YS50b2tlbixcbiAgICAgICAgICAgICAgICAgIC4uLihleGlzdGluZ0NsYWltXG4gICAgICAgICAgICAgICAgICAgID8geyBjb25mbGljdGluZ1J1bklkOiBleGlzdGluZ0NsYWltLnJ1bklkIH1cbiAgICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgY29uc3QgY29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZXZlbnRJZH1gO1xuICAgICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnZXZlbnRzJywgY29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICAgIGNvbmZsaWN0RXZlbnRcbiAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICBjb25zdCByZXNvbHZlRGF0YSA9XG4gICAgICAgICAgICAgICAgcGFyYW1zPy5yZXNvbHZlRGF0YSA/PyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT047XG4gICAgICAgICAgICAgIGNvbnN0IGZpbHRlcmVkRXZlbnQgPSBzdHJpcEV2ZW50RGF0YVJlZnMoXG4gICAgICAgICAgICAgICAgY29uZmxpY3RFdmVudCxcbiAgICAgICAgICAgICAgICByZXNvbHZlRGF0YVxuICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgIC8vIFJldHVybiBFdmVudFJlc3VsdCB3aXRoIGNvbmZsaWN0IGV2ZW50IChubyBob29rIGVudGl0eSBjcmVhdGVkKVxuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGV2ZW50OiBmaWx0ZXJlZEV2ZW50LFxuICAgICAgICAgICAgICAgIHJ1bixcbiAgICAgICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgICAgIGhvb2s6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDb21wdXRlIHRoZSBob29rIGVudGl0eSBub3csIGJ1dCBkZWZlciBpdHMgd3JpdGUgdW50aWxcbiAgICAgICAgICAvLyBBRlRFUiB0aGUgb3V0ZXIgZXZlbnQgcHVibGlzaCBhdCB0aGUgYm90dG9tIG9mIHRoaXNcbiAgICAgICAgICAvLyBmdW5jdGlvbiBjb21taXRzLiBUaGUgcmV0cnkgcGF0aCBjYW4gcmVhY2ggdGhpcyBicmFuY2hcbiAgICAgICAgICAvLyBmb3IgYSBob29rIHdob3NlIGBob29rX2NyZWF0ZWRgIGV2ZW50IHdhcyBhbHJlYWR5XG4gICAgICAgICAgLy8gcHVibGlzaGVkIHN1Y2Nlc3NmdWxseSAoYW4gXCJhbHJlYWR5LWNvbW1pdHRlZFxuICAgICAgICAgIC8vIGR1cGxpY2F0ZVwiKTsgaW4gdGhhdCBjYXNlIHRoZSBvdXRlciBgd3JpdGVFeGNsdXNpdmVgXG4gICAgICAgICAgLy8gZm9yIHRoZSBldmVudCB3aWxsIHJldHVybiBmYWxzZSBhbmQgd2Ugd2lsbCB0aHJvd1xuICAgICAgICAgIC8vIGBFbnRpdHlDb25mbGljdEVycm9yYC4gV3JpdGluZyB0aGUgaG9vayBlbnRpdHkgaGVyZVxuICAgICAgICAgIC8vIGZpcnN0IHdvdWxkIG11dGF0ZSBhbHJlYWR5LWNvbW1pdHRlZCBkdXJhYmxlIHN0YXRlIHdpdGhcbiAgICAgICAgICAvLyB0aGUgcmV0cnkncyBwYXlsb2FkIChlLmcuIGRpZmZlcmVudCBgbWV0YWRhdGFgIG9yXG4gICAgICAgICAgLy8gYGlzV2ViaG9va2ApIGJlZm9yZSB0aGUgZXZlbnQgcHVibGlzaCBwcm92ZWQgd2hpY2hcbiAgICAgICAgICAvLyBvdXRjb21lIHdlIGFyZSBpbiDigJQgbGVhdmluZyB0aGUgZW50aXR5IGFuZCBldmVudCBsb2dcbiAgICAgICAgICAvLyBpbmNvbnNpc3RlbnQuIEJ5IGRlZmVycmluZywgdGhlIGVudGl0eSBpcyBvbmx5IHdyaXR0ZW5cbiAgICAgICAgICAvLyB3aGVuIHRoZSBwdWJsaXNoIGFjdHVhbGx5IHN1Y2NlZWRzIChmaXJzdCB3cml0ZXIgb3JcbiAgICAgICAgICAvLyBvcnBoYW4gcmVjb3ZlcnkpLiBTZWUgcHJhbmF5Z3AncyByZXZpZXcgb24gUFIgIzIyOTUgZm9yXG4gICAgICAgICAgLy8gdGhlIGthcnRoaWtzY2FsZTMgcmVwcm8uXG4gICAgICAgICAgaG9vayA9IHtcbiAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIGhvb2tJZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgdG9rZW46IGhvb2tEYXRhLnRva2VuLFxuICAgICAgICAgICAgbWV0YWRhdGE6IGhvb2tEYXRhLm1ldGFkYXRhLFxuICAgICAgICAgICAgb3duZXJJZDogJ2xvY2FsLW93bmVyJyxcbiAgICAgICAgICAgIHByb2plY3RJZDogJ2xvY2FsLXByb2plY3QnLFxuICAgICAgICAgICAgZW52aXJvbm1lbnQ6ICdsb2NhbCcsXG4gICAgICAgICAgICAvLyBVc2UgdGhlIChwb3NzaWJseSBjYW5vbmljYWwpIGV2ZW50J3MgY3JlYXRlZEF0IHNvIHR3b1xuICAgICAgICAgICAgLy8gd29ya2VycyB3cml0aW5nIHRoZSBzYW1lIGhvb2sgZW50aXR5IHByb2R1Y2UgYnl0ZS1cbiAgICAgICAgICAgIC8vIGlkZW50aWNhbCBjb250ZW50IGR1cmluZyBjb252ZXJnZW5jZS5cbiAgICAgICAgICAgIGNyZWF0ZWRBdDogZXZlbnQuY3JlYXRlZEF0LFxuICAgICAgICAgICAgLy8gUHJvcGFnYXRlIHNwZWNWZXJzaW9uIGZyb20gdGhlIGV2ZW50IHRvIHRoZSBob29rIGVudGl0eVxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgaXNXZWJob29rOiBob29rRGF0YS5pc1dlYmhvb2sgPz8gZmFsc2UsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBob29rRW50aXR5V3JpdGVPcHRpb25zID0gd3JpdGVIb29rRW50aXR5V2l0aE92ZXJ3cml0ZVxuICAgICAgICAgICAgPyB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfZGlzcG9zZWQnKSB7XG4gICAgICAgICAgLy8gaG9va19kaXNwb3NlZDogRGVsZXRlcyBob29rIGVudGl0eSwgcmVqZWN0cyBkdXBsaWNhdGVzLlxuICAgICAgICAgIC8vIFVzZXMgd3JpdGVFeGNsdXNpdmUgb24gYSBsb2NrIGZpbGUgdG8gYXRvbWljYWxseSBwcmV2ZW50IGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggZGlzcG9zaW5nIHRoZSBzYW1lIGhvb2sgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgICBjb25zdCBob29rTG9ja05hbWUgPSB0YWdcbiAgICAgICAgICAgID8gYCR7ZGF0YS5jb3JyZWxhdGlvbklkfS5kaXNwb3NlZC4ke3RhZ31gXG4gICAgICAgICAgICA6IGAke2RhdGEuY29ycmVsYXRpb25JZH0uZGlzcG9zZWRgO1xuICAgICAgICAgIGNvbnN0IGxvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgICAnaG9va3MnLFxuICAgICAgICAgICAgaG9va0xvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUobG9ja1BhdGgsICcnKTtcbiAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgICBgSG9vayBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIGFscmVhZHkgZGlzcG9zZWRgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBSZWFkIHRoZSBob29rIHRvIGdldCBpdHMgdG9rZW4gYmVmb3JlIGRlbGV0aW5nXG4gICAgICAgICAgY29uc3QgaG9va1BhdGggPSB0YWdnZWRQYXRoKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICB0YWdcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IGV4aXN0aW5nSG9vayA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBIb29rU2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoZXhpc3RpbmdIb29rKSB7XG4gICAgICAgICAgICAvLyBEZWxldGUgdGhlIHRva2VuIGNvbnN0cmFpbnQgZmlsZSB0byBmcmVlIHVwIHRoZSB0b2tlblxuICAgICAgICAgICAgLy8gZm9yIHJldXNlLCBhbmQgZGVsZXRlIHRoaXMgaG9vaydzIHJlY292ZXJ5IG1hcmtlciAoaWZcbiAgICAgICAgICAgIC8vIGFueSkgZm9yIGRpc2sgaHlnaWVuZS4gVGhlIG1hcmtlcidzIGZpbGVuYW1lIGhhc2hcbiAgICAgICAgICAgIC8vIGluY2x1ZGVzIGAodG9rZW4sIHJ1bklkLCBob29rSWQpYCBzbyBkaWZmZXJlbnRcbiAgICAgICAgICAgIC8vIGxpZmV0aW1lcyBuZXZlciBjb2xsaWRlLCBidXQgY2xlYW5pbmcgdXAgcmVkdWNlcyBkaXNrXG4gICAgICAgICAgICAvLyBsZWFrIGZvciBob29rcyB0aGF0IGdvIHRocm91Z2ggdGhlIHJlY292ZXJ5IHBhdGguXG4gICAgICAgICAgICBjb25zdCBkaXNwb3NlZENvbnN0cmFpbnRQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgICAnaG9va3MnLFxuICAgICAgICAgICAgICAndG9rZW5zJyxcbiAgICAgICAgICAgICAgYCR7aGFzaFRva2VuKGV4aXN0aW5nSG9vay50b2tlbil9Lmpzb25gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgZGVsZXRlSlNPTihkaXNwb3NlZENvbnN0cmFpbnRQYXRoKTtcbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZUpTT04oXG4gICAgICAgICAgICAgIGhvb2tSZWNvdmVyeU1hcmtlclBhdGgoXG4gICAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgICBleGlzdGluZ0hvb2sudG9rZW4sXG4gICAgICAgICAgICAgICAgZXhpc3RpbmdIb29rLnJ1bklkLFxuICAgICAgICAgICAgICAgIGV4aXN0aW5nSG9vay5ob29rSWRcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgZGVsZXRlSlNPTihob29rUGF0aCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICd3YWl0X2NyZWF0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgICAvLyB3YWl0X2NyZWF0ZWQ6IENyZWF0ZXMgd2FpdCBlbnRpdHkgd2l0aCBzdGF0dXMgJ3dhaXRpbmcnXG4gICAgICAgICAgY29uc3Qgd2FpdERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICByZXN1bWVBdD86IERhdGU7XG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCB3YWl0Q29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdXYWl0ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICAgIHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgICBXYWl0U2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoZXhpc3RpbmdXYWl0KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRW50aXR5Q29uZmxpY3RFcnJvcihcbiAgICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBhbHJlYWR5IGV4aXN0c2BcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHdhaXQgPSB7XG4gICAgICAgICAgICB3YWl0SWQ6IHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICBzdGF0dXM6ICd3YWl0aW5nJyxcbiAgICAgICAgICAgIHJlc3VtZUF0OiB3YWl0RGF0YS5yZXN1bWVBdCxcbiAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnd2FpdHMnLCB3YWl0Q29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgd2FpdFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICd3YWl0X2NvbXBsZXRlZCcpIHtcbiAgICAgICAgICAvLyB3YWl0X2NvbXBsZXRlZDogVHJhbnNpdGlvbnMgd2FpdCB0byAnY29tcGxldGVkJywgcmVqZWN0cyBkdXBsaWNhdGVzLlxuICAgICAgICAgIC8vIFVzZXMgd3JpdGVFeGNsdXNpdmUgb24gYSBsb2NrIGZpbGUgdG8gYXRvbWljYWxseSBwcmV2ZW50IGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggY29tcGxldGluZyB0aGUgc2FtZSB3YWl0IChUT0NUT1UgcmFjZSkuXG4gICAgICAgICAgY29uc3Qgd2FpdENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICAgIGNvbnN0IHdhaXRMb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgPyBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jb21wbGV0ZWQuJHt0YWd9YFxuICAgICAgICAgICAgOiBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jb21wbGV0ZWRgO1xuICAgICAgICAgIGNvbnN0IGxvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgICAnd2FpdHMnLFxuICAgICAgICAgICAgd2FpdExvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUobG9ja1BhdGgsICcnKTtcbiAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgICBgV2FpdCBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIGFscmVhZHkgY29tcGxldGVkYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdXYWl0ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICAgIHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgICBXYWl0U2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoIWV4aXN0aW5nV2FpdCkge1xuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGxvY2sgZmlsZSB3ZSBqdXN0IGNsYWltZWQg4oCUIHRoZSB3YWl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgICAgICAgIGF3YWl0IGZzLnVubGluayhsb2NrUGF0aCkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93V29ybGRFcnJvcihcbiAgICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBub3QgZm91bmRgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBUaGUgbG9jayBmaWxlICh3cml0ZUV4Y2x1c2l2ZSBhYm92ZSkgYWxyZWFkeSBwcmV2ZW50cyBjb25jdXJyZW50XG4gICAgICAgICAgLy8gY29tcGxldGlvbnMg4oCUIG5vIGFkZGl0aW9uYWwgc3RhdHVzIGNoZWNrIG5lZWRlZC5cbiAgICAgICAgICB3YWl0ID0ge1xuICAgICAgICAgICAgLi4uZXhpc3RpbmdXYWl0LFxuICAgICAgICAgICAgc3RhdHVzOiAnY29tcGxldGVkJyxcbiAgICAgICAgICAgIGNvbXBsZXRlZEF0OiBub3csXG4gICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3dhaXRzJywgd2FpdENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgIHdhaXQsXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOb3RlOiBob29rX3JlY2VpdmVkIGV2ZW50cyBhcmUgc3RvcmVkIGluIHRoZSBldmVudCBsb2cgYnV0IGRvbid0XG4gICAgICAgIC8vIG1vZGlmeSB0aGUgSG9vayBlbnRpdHkgKHdoaWNoIGRvZXNuJ3QgaGF2ZSBhIHBheWxvYWQgZmllbGQpXG5cbiAgICAgICAgLy8gU3RvcmUgZXZlbnQgdXNpbmcgY29tcG9zaXRlIGtleSB7cnVuSWR9LXtldmVudElkfS5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gYHdyaXRlRXhjbHVzaXZlYCAoT19DUkVBVHxPX0VYQ0wgdmlhIHRlbXAtZmlsZSArIGhhcmQtbGluaylcbiAgICAgICAgLy8gaXMgdGhlIGNyb3NzLXByb2Nlc3MgYXRvbWljIHB1Ymxpc2ggcHJpbWl0aXZlOiBpZiB0aGUgZmlsZVxuICAgICAgICAvLyBhbHJlYWR5IGV4aXN0cywgcmV0dXJucyBmYWxzZSBpbnN0ZWFkIG9mIG92ZXJ3cml0aW5nLiBUaGlzXG4gICAgICAgIC8vIGlzIGNyaXRpY2FsIGZvciB0aGUgaG9va19jcmVhdGVkIGRlZHVwLXJlY292ZXJ5IGNvbnZlcmdlbmNlXG4gICAgICAgIC8vIChhYm92ZSkg4oCUIHR3byB3b3JrZXJzIHRoYXQgYWRvcHQgdGhlIHNhbWUgY2Fub25pY2FsIGV2ZW50SWRcbiAgICAgICAgLy8gcmFjZSBoZXJlOyB3aG9ldmVyIGxpbmtzIHRoZSBmaWxlIGZpcnN0IHdpbnMsIHRoZSBsb3NlclxuICAgICAgICAvLyB0aHJvd3MgRW50aXR5Q29uZmxpY3RFcnJvciwgYW5kIHRoZSBydW50aW1lJ3MgZXhpc3RpbmdcbiAgICAgICAgLy8gY29uY3VycmVudC1yZXBsYXkgY2F0Y2ggcGF0aCBhdCBzdXNwZW5zaW9uLWhhbmRsZXIudHM6MTQyXG4gICAgICAgIC8vIHN3YWxsb3dzIGl0LiBGb3IgYWxsIG90aGVyIGV2ZW50IHR5cGVzLCBldmVudElkcyBhcmVcbiAgICAgICAgLy8gbW9ub3RvbmljIFVMSURzIChnbG9iYWxseSB1bmlxdWUgYnkgY29uc3RydWN0aW9uKSBzbyBhXG4gICAgICAgIC8vIGNvbGxpc2lvbiBpbmRpY2F0ZXMgYSByZWFsIGJ1ZyBhbmQgRW50aXR5Q29uZmxpY3RFcnJvciBpc1xuICAgICAgICAvLyBhbHNvIHRoZSByaWdodCBzdXJmYWNlIOKAlCBzYW1lIHNoYXBlIGFzIHN0ZXBfY3JlYXRlZCdzXG4gICAgICAgIC8vIGNsYWltLWZpbGUgYmVoYXZpb3IuXG4gICAgICAgIGNvbnN0IGNvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2V2ZW50SWR9YDtcbiAgICAgICAgY29uc3QgZXZlbnRQdWJsaXNoZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdldmVudHMnLCBjb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgSlNPTi5zdHJpbmdpZnkoZXZlbnQsIGpzb25SZXBsYWNlciwgMilcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKCFldmVudFB1Ymxpc2hlZCkge1xuICAgICAgICAgIC8vIEZvciBgaG9va19jcmVhdGVkYCwgbG9zaW5nIHRoZSBldmVudCBwdWJsaXNoIG1lYW5zIHRoZVxuICAgICAgICAgIC8vIGV2ZW50IHdhcyBhbHJlYWR5IGNvbW1pdHRlZCBhdCB0aGlzIGV4YWN0IChjYW5vbmljYWwpXG4gICAgICAgICAgLy8gcGF0aC4gVGhlIG9yaWdpbmFsIHB1Ymxpc2hlciBtYXkgaGF2ZSBjcmFzaGVkIGJldHdlZW5cbiAgICAgICAgICAvLyBpdHMgZXZlbnQgcHVibGlzaCBhbmQgaXRzIGRlZmVycmVkIGhvb2stZW50aXR5IHdyaXRlXG4gICAgICAgICAgLy8gKHRoZSBpbnZlcnNlIG9mIHRoZSBjcmFzaCB3aW5kb3cgdGhlIGRlZmVycmFsIGNsb3NlcyksXG4gICAgICAgICAgLy8gbGVhdmluZyBhbiBldmVudC1maXJzdCBvcnBoYW46IHRoZSBldmVudCBpcyBpbiB0aGUgbG9nXG4gICAgICAgICAgLy8gYnV0IHRoZSBlbnRpdHkgaXMgbWlzc2luZyBhbmQgdGhlIGhvb2sgaXMgdW5yZXNvbHZhYmxlLlxuICAgICAgICAgIC8vIFJlcGFpciB0aGUgZW50aXR5IGZyb20gdGhlIFBFUlNJU1RFRCBldmVudCdzIHBheWxvYWRcbiAgICAgICAgICAvLyAobmV2ZXIgdGhlIHJldHJ5J3Mg4oCUIGRpZmZlcmVudCByZXRyeSBtZXRhZGF0YSBtdXN0IG5vdFxuICAgICAgICAgIC8vIGNoYW5nZSBjb21taXR0ZWQgc3RhdGUpIGJlZm9yZSBzdXJmYWNpbmcgdGhlIGJlbmlnblxuICAgICAgICAgIC8vIGR1cGxpY2F0ZSB0byB0aGUgcnVudGltZSdzIGNvbmN1cnJlbnQtcmVwbGF5IGNhdGNoIHBhdGguXG4gICAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAnaG9va19jcmVhdGVkJyAmJiBkYXRhLmNvcnJlbGF0aW9uSWQpIHtcbiAgICAgICAgICAgIGF3YWl0IHJlcGFpckhvb2tFbnRpdHlGcm9tUGVyc2lzdGVkRXZlbnQoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50SWQsXG4gICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICBgRXZlbnQgXCIke2V2ZW50SWR9XCIgYWxyZWFkeSBleGlzdHMgZm9yIHJ1biBcIiR7ZWZmZWN0aXZlUnVuSWR9XCJgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdyaXRlIHRoZSBob29rIGVudGl0eSBPTkxZIG5vdyB0aGF0IHRoZSBldmVudCBwdWJsaXNoIGhhc1xuICAgICAgICAvLyBjb21taXR0ZWQuIERvaW5nIHRoaXMgZWFybGllciAoaW4gdGhlIGBob29rX2NyZWF0ZWRgXG4gICAgICAgIC8vIGJyYW5jaCBhYm92ZSkgd291bGQgbXV0YXRlIGFuIGFscmVhZHktY29tbWl0dGVkIGhvb2tcbiAgICAgICAgLy8gZW50aXR5IHdpdGggdGhlIHJldHJ5J3MgcGF5bG9hZCBiZWZvcmUgdGhlIGV2ZW50IHB1Ymxpc2hcbiAgICAgICAgLy8gcHJvdmVkIHdoZXRoZXIgdGhpcyBhdHRlbXB0IHdhcyByZXBhaXJpbmcgYSBtaXNzaW5nIGV2ZW50XG4gICAgICAgIC8vIG9yIGp1c3QgY29sbGlkaW5nIHdpdGggYW4gYWxyZWFkeS1wdWJsaXNoZWQgYGhvb2tfY3JlYXRlZGAuXG4gICAgICAgIC8vIFRoZSBicmFuY2ggc2V0cyBgaG9va0VudGl0eVdyaXRlT3B0aW9uc2AgaWZmIHRoaXMgZXZlbnRcbiAgICAgICAgLy8gdHlwZSB3cml0ZXMgYW4gZW50aXR5LlxuICAgICAgICBpZiAoaG9vayAmJiBkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfY3JlYXRlZCcpIHtcbiAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdob29rcycsIGhvb2suaG9va0lkLCB0YWcpLFxuICAgICAgICAgICAgaG9vayxcbiAgICAgICAgICAgIGhvb2tFbnRpdHlXcml0ZU9wdGlvbnNcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPSBwYXJhbXM/LnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgICAgY29uc3QgZmlsdGVyZWRFdmVudCA9IHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpO1xuXG4gICAgICAgIC8vIEZvciBydW5fc3RhcnRlZDogaW5jbHVkZSBhbGwgZXZlbnRzIHNvIHRoZSBydW50aW1lIGNhbiBza2lwXG4gICAgICAgIC8vIHRoZSBpbml0aWFsIGV2ZW50cy5saXN0IGNhbGwgYW5kIHJlZHVjZSBUVEZCLlxuICAgICAgICBsZXQgZXZlbnRzOiBFdmVudFtdIHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgY3Vyc29yOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgaGFzTW9yZTogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX3N0YXJ0ZWQnICYmIHJ1bikge1xuICAgICAgICAgIGNvbnN0IGFsbEV2ZW50cyA9IGF3YWl0IHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSh7XG4gICAgICAgICAgICBkaXJlY3Rvcnk6IHBhdGguam9pbihiYXNlZGlyLCAnZXZlbnRzJyksXG4gICAgICAgICAgICBzY2hlbWE6IEV2ZW50U2NoZW1hLFxuICAgICAgICAgICAgZmlsZVByZWZpeDogYCR7ZWZmZWN0aXZlUnVuSWR9LWAsXG4gICAgICAgICAgICBzb3J0T3JkZXI6ICdhc2MnLFxuICAgICAgICAgICAgbGltaXQ6IDEwMDAsXG4gICAgICAgICAgICBnZXRDcmVhdGVkQXQ6IGdldE9iamVjdENyZWF0ZWRBdCgnZXZudCcpLFxuICAgICAgICAgICAgZ2V0SWQ6IChlKSA9PiBlLmV2ZW50SWQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZXZlbnRzID0gYWxsRXZlbnRzLmRhdGE7XG4gICAgICAgICAgY3Vyc29yID0gYWxsRXZlbnRzLmN1cnNvcjtcbiAgICAgICAgICBoYXNNb3JlID0gYWxsRXZlbnRzLmhhc01vcmU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZXR1cm4gRXZlbnRSZXN1bHQgd2l0aCBldmVudCBhbmQgYW55IGNyZWF0ZWQvdXBkYXRlZCBlbnRpdHlcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBldmVudDogZmlsdGVyZWRFdmVudCxcbiAgICAgICAgICBydW4sXG4gICAgICAgICAgc3RlcCxcbiAgICAgICAgICBob29rLFxuICAgICAgICAgIHdhaXQsXG4gICAgICAgICAgZXZlbnRzLFxuICAgICAgICAgIGN1cnNvcixcbiAgICAgICAgICBoYXNNb3JlLFxuICAgICAgICB9O1xuICAgICAgfSAvLyBlbmQgY3JlYXRlSW1wbFxuICAgIH0sXG5cbiAgICBhc3luYyBnZXQocnVuSWQsIGV2ZW50SWQsIHBhcmFtcykge1xuICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdydW5JZCcsIHJ1bklkKTtcbiAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgnZXZlbnRJZCcsIGV2ZW50SWQpO1xuICAgICAgY29uc3QgY29tcG9zaXRlS2V5ID0gYCR7cnVuSWR9LSR7ZXZlbnRJZH1gO1xuICAgICAgY29uc3QgZXZlbnQgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgYmFzZWRpcixcbiAgICAgICAgJ2V2ZW50cycsXG4gICAgICAgIGNvbXBvc2l0ZUtleSxcbiAgICAgICAgRXZlbnRTY2hlbWEsXG4gICAgICAgIHRhZ1xuICAgICAgKTtcbiAgICAgIGlmICghZXZlbnQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFdmVudCAke2V2ZW50SWR9IGluIHJ1biAke3J1bklkfSBub3QgZm91bmRgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc29sdmVEYXRhID0gcGFyYW1zPy5yZXNvbHZlRGF0YSA/PyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT047XG4gICAgICByZXR1cm4gc3RyaXBFdmVudERhdGFSZWZzKGV2ZW50LCByZXNvbHZlRGF0YSk7XG4gICAgfSxcblxuICAgIGFzeW5jIGxpc3QocGFyYW1zKSB7XG4gICAgICBjb25zdCB7IHJ1bklkIH0gPSBwYXJhbXM7XG4gICAgICBhc3NlcnRTYWZlRW50aXR5SWQoJ3J1bklkJywgcnVuSWQpO1xuICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPSBwYXJhbXMucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGFnaW5hdGVkRmlsZVN5c3RlbVF1ZXJ5KHtcbiAgICAgICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oYmFzZWRpciwgJ2V2ZW50cycpLFxuICAgICAgICBzY2hlbWE6IEV2ZW50U2NoZW1hLFxuICAgICAgICBmaWxlUHJlZml4OiBgJHtydW5JZH0tYCxcbiAgICAgICAgLy8gRXZlbnRzIGluIGNocm9ub2xvZ2ljYWwgb3JkZXIgKG9sZGVzdCBmaXJzdCkgYnkgZGVmYXVsdCxcbiAgICAgICAgLy8gZGlmZmVyZW50IGZyb20gdGhlIGRlZmF1bHQgZm9yIG90aGVyIGxpc3QgY2FsbHMuXG4gICAgICAgIHNvcnRPcmRlcjogcGFyYW1zLnBhZ2luYXRpb24/LnNvcnRPcmRlciA/PyAnYXNjJyxcbiAgICAgICAgbGltaXQ6IHBhcmFtcy5wYWdpbmF0aW9uPy5saW1pdCxcbiAgICAgICAgY3Vyc29yOiBwYXJhbXMucGFnaW5hdGlvbj8uY3Vyc29yLFxuICAgICAgICBnZXRDcmVhdGVkQXQ6IGdldE9iamVjdENyZWF0ZWRBdCgnZXZudCcpLFxuICAgICAgICBnZXRJZDogKGV2ZW50KSA9PiBldmVudC5ldmVudElkLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIElmIHJlc29sdmVEYXRhIGlzIFwibm9uZVwiLCByZW1vdmUgZXZlbnREYXRhIGZyb20gZXZlbnRzXG4gICAgICBpZiAocmVzb2x2ZURhdGEgPT09ICdub25lJykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIC4uLnJlc3VsdCxcbiAgICAgICAgICBkYXRhOiByZXN1bHQuZGF0YS5tYXAoKGV2ZW50KSA9PlxuICAgICAgICAgICAgc3RyaXBFdmVudERhdGFSZWZzKGV2ZW50LCByZXNvbHZlRGF0YSlcbiAgICAgICAgICApLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG5cbiAgICBhc3luYyBsaXN0QnlDb3JyZWxhdGlvbklkKHBhcmFtcykge1xuICAgICAgY29uc3QgY29ycmVsYXRpb25JZCA9IHBhcmFtcy5jb3JyZWxhdGlvbklkO1xuICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdjb3JyZWxhdGlvbklkJywgY29ycmVsYXRpb25JZCk7XG4gICAgICBjb25zdCByZXNvbHZlRGF0YSA9IHBhcmFtcy5yZXNvbHZlRGF0YSA/PyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT047XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwYWdpbmF0ZWRGaWxlU3lzdGVtUXVlcnkoe1xuICAgICAgICBkaXJlY3Rvcnk6IHBhdGguam9pbihiYXNlZGlyLCAnZXZlbnRzJyksXG4gICAgICAgIHNjaGVtYTogRXZlbnRTY2hlbWEsXG4gICAgICAgIC8vIE5vIGZpbGVQcmVmaXggLSBzZWFyY2ggYWxsIGV2ZW50c1xuICAgICAgICBmaWx0ZXI6IChldmVudCkgPT4gZXZlbnQuY29ycmVsYXRpb25JZCA9PT0gY29ycmVsYXRpb25JZCxcbiAgICAgICAgLy8gRXZlbnRzIGluIGNocm9ub2xvZ2ljYWwgb3JkZXIgKG9sZGVzdCBmaXJzdCkgYnkgZGVmYXVsdCxcbiAgICAgICAgLy8gZGlmZmVyZW50IGZyb20gdGhlIGRlZmF1bHQgZm9yIG90aGVyIGxpc3QgY2FsbHMuXG4gICAgICAgIHNvcnRPcmRlcjogcGFyYW1zLnBhZ2luYXRpb24/LnNvcnRPcmRlciA/PyAnYXNjJyxcbiAgICAgICAgbGltaXQ6IHBhcmFtcy5wYWdpbmF0aW9uPy5saW1pdCxcbiAgICAgICAgY3Vyc29yOiBwYXJhbXMucGFnaW5hdGlvbj8uY3Vyc29yLFxuICAgICAgICBnZXRDcmVhdGVkQXQ6IGdldE9iamVjdENyZWF0ZWRBdCgnZXZudCcpLFxuICAgICAgICBnZXRJZDogKGV2ZW50KSA9PiBldmVudC5ldmVudElkLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIElmIHJlc29sdmVEYXRhIGlzIFwibm9uZVwiLCByZW1vdmUgZXZlbnREYXRhIGZyb20gZXZlbnRzXG4gICAgICBpZiAocmVzb2x2ZURhdGEgPT09ICdub25lJykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIC4uLnJlc3VsdCxcbiAgICAgICAgICBkYXRhOiByZXN1bHQuZGF0YS5tYXAoKGV2ZW50KSA9PlxuICAgICAgICAgICAgc3RyaXBFdmVudERhdGFSZWZzKGV2ZW50LCByZXNvbHZlRGF0YSlcbiAgICAgICAgICApLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG4gIH07XG59XG4iXX0=