@workflow/world-local 5.0.0-beta.10 → 5.0.0-beta.12
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.
- package/dist/config.d.ts +23 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -14
- package/dist/fs.d.ts +113 -2
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +321 -28
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -6
- package/dist/init.d.ts +91 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +268 -0
- package/dist/instrumentObject.d.ts +8 -0
- package/dist/instrumentObject.d.ts.map +1 -0
- package/dist/instrumentObject.js +66 -0
- package/dist/queue.d.ts +8 -1
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +195 -54
- package/dist/storage/events-storage.d.ts +7 -0
- package/dist/storage/events-storage.d.ts.map +1 -0
- package/dist/storage/events-storage.js +898 -0
- package/dist/storage/filters.d.ts +22 -0
- package/dist/storage/filters.d.ts.map +1 -0
- package/dist/storage/filters.js +33 -0
- package/dist/storage/helpers.d.ts +18 -0
- package/dist/storage/helpers.d.ts.map +1 -0
- package/dist/storage/helpers.js +44 -0
- package/dist/storage/hooks-storage.d.ts +12 -0
- package/dist/storage/hooks-storage.d.ts.map +1 -0
- package/dist/storage/hooks-storage.js +93 -0
- package/dist/storage/index.d.ts +21 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +30 -0
- package/dist/storage/legacy.d.ts +13 -0
- package/dist/storage/legacy.d.ts.map +1 -0
- package/dist/storage/legacy.js +78 -0
- package/dist/storage/runs-storage.d.ts +33 -0
- package/dist/storage/runs-storage.d.ts.map +1 -0
- package/dist/storage/runs-storage.js +130 -0
- package/dist/storage/steps-storage.d.ts +7 -0
- package/dist/storage/steps-storage.d.ts.map +1 -0
- package/dist/storage/steps-storage.js +52 -0
- package/dist/storage.d.ts +9 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +9 -456
- package/dist/streamer.d.ts +4 -2
- package/dist/streamer.d.ts.map +1 -1
- package/dist/streamer.js +467 -107
- package/dist/telemetry.d.ts +28 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +71 -0
- package/dist/test-helpers.d.ts +54 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +118 -0
- package/dist/util.js +1 -1
- package/package.json +12 -11
- package/dist/config.js.map +0 -1
- package/dist/fs.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/queue.js.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/streamer.js.map +0 -1
- package/dist/util.js.map +0 -1
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { EntityConflictError, HookNotFoundError, RunExpiredError, RunNotSupportedError, TooEarlyError, WorkflowRunNotFoundError, WorkflowWorldError, } from '@workflow/errors';
|
|
4
|
+
import { EventSchema, HookSchema, isLegacySpecVersion, requiresNewerWorld, SPEC_VERSION_CURRENT, StepSchema, validateUlidTimestamp, WaitSchema, WorkflowRunSchema, } from '@workflow/world';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { DEFAULT_RESOLVE_DATA_OPTION } from '../config.js';
|
|
7
|
+
import { assertSafeEntityId, deleteJSON, jsonReplacer, listJSONFiles, paginatedFileSystemQuery, readJSON, readJSONWithFallback, resolveWithinBase, taggedPath, writeExclusive, writeJSON, } from '../fs.js';
|
|
8
|
+
import { stripEventDataRefs } from './filters.js';
|
|
9
|
+
import { getObjectCreatedAt, hashToken, monotonicUlid } from './helpers.js';
|
|
10
|
+
import { deleteAllHooksForRun } from './hooks-storage.js';
|
|
11
|
+
import { handleLegacyEvent } from './legacy.js';
|
|
12
|
+
import { withRunFileLock } from './runs-storage.js';
|
|
13
|
+
/**
|
|
14
|
+
* Per-step in-process async mutex. Serializes concurrent `events.create` calls
|
|
15
|
+
* that target the same step, so that the "check terminal state, then write step
|
|
16
|
+
* entity + event" sequence is atomic. Without this, two concurrent step_started
|
|
17
|
+
* calls can both pass the not-terminal check and both write step_started events
|
|
18
|
+
* — or a step_started can land in the log after step_completed has already
|
|
19
|
+
* written, producing unconsumed events on replay.
|
|
20
|
+
*
|
|
21
|
+
* Duplicate step_started events for a non-terminal step are still allowed
|
|
22
|
+
* (retries legitimately re-start a step), only writes to an already-terminal
|
|
23
|
+
* step are rejected.
|
|
24
|
+
*/
|
|
25
|
+
const stepLocks = new Map();
|
|
26
|
+
const HookTokenClaimSchema = z.object({
|
|
27
|
+
runId: z.string(),
|
|
28
|
+
});
|
|
29
|
+
async function readHookTokenClaim(constraintPath) {
|
|
30
|
+
try {
|
|
31
|
+
return await readJSON(constraintPath, HookTokenClaimSchema);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof SyntaxError || error instanceof z.ZodError) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function withStepLock(key, fn) {
|
|
41
|
+
const prev = stepLocks.get(key);
|
|
42
|
+
const taskBox = {};
|
|
43
|
+
const task = (async () => {
|
|
44
|
+
if (prev) {
|
|
45
|
+
// Wait for the previous task to settle; don't inherit its errors.
|
|
46
|
+
await prev.catch(() => undefined);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return await fn();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (stepLocks.get(key) === taskBox.task) {
|
|
53
|
+
stepLocks.delete(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
57
|
+
taskBox.task = task;
|
|
58
|
+
stepLocks.set(key, task);
|
|
59
|
+
return task;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Helper function to delete all waits associated with a workflow run.
|
|
63
|
+
* Called when a run reaches a terminal state.
|
|
64
|
+
*/
|
|
65
|
+
async function deleteAllWaitsForRun(basedir, runId) {
|
|
66
|
+
const waitsDir = path.join(basedir, 'waits');
|
|
67
|
+
const files = await listJSONFiles(waitsDir);
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
// fileIds may contain tag suffixes (e.g., "wrun_ABC-corrId.vitest-0")
|
|
70
|
+
// but startsWith still matches correctly since the tag is a suffix.
|
|
71
|
+
if (file.startsWith(`${runId}-`)) {
|
|
72
|
+
const waitPath = path.join(waitsDir, `${file}.json`);
|
|
73
|
+
await deleteJSON(waitPath);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Persist a lifecycle-driven run update (run_started / run_completed /
|
|
79
|
+
* run_failed / run_cancelled) under the shared per-run file lock,
|
|
80
|
+
* re-reading the on-disk run inside the lock so any attribute writes
|
|
81
|
+
* that landed between the pre-validation `currentRun` read and this
|
|
82
|
+
* write are preserved. Without the re-read, an `experimentalSetAttributes`
|
|
83
|
+
* call sandwiched between the lifecycle read and write would be
|
|
84
|
+
* silently overwritten by the lifecycle write's stale attribute snapshot.
|
|
85
|
+
*
|
|
86
|
+
* `proposed` is the fully-constructed run row the caller wants to
|
|
87
|
+
* write (with the correct discriminated-union status branch). Only the
|
|
88
|
+
* `attributes` field is replaced with the freshest version inside the
|
|
89
|
+
* lock.
|
|
90
|
+
*/
|
|
91
|
+
async function writeRunUnderLifecycleLock(basedir, runId, tag, proposed) {
|
|
92
|
+
return withRunFileLock(runId, async () => {
|
|
93
|
+
const fresh = await readJSON(taggedPath(basedir, 'runs', runId, tag), WorkflowRunSchema);
|
|
94
|
+
const next = {
|
|
95
|
+
...proposed,
|
|
96
|
+
attributes: fresh?.attributes ?? proposed.attributes,
|
|
97
|
+
};
|
|
98
|
+
await writeJSON(taggedPath(basedir, 'runs', runId, tag), next, {
|
|
99
|
+
overwrite: true,
|
|
100
|
+
});
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Creates the events storage implementation using the filesystem.
|
|
106
|
+
* Implements the Storage['events'] interface with create, list, and listByCorrelationId operations.
|
|
107
|
+
*/
|
|
108
|
+
export function createEventsStorage(basedir, tag) {
|
|
109
|
+
return {
|
|
110
|
+
async create(runId, data, params) {
|
|
111
|
+
// Validate request-supplied IDs before they're concatenated into
|
|
112
|
+
// filesystem paths. This is the primary defense against path traversal
|
|
113
|
+
// attacks where a client supplies runId / correlationId values like
|
|
114
|
+
// "../../../package" to read or write files outside the storage root.
|
|
115
|
+
// Run before taking the per-step mutex so malformed inputs fail fast.
|
|
116
|
+
//
|
|
117
|
+
// Empty `correlationId` values are also rejected here: the event
|
|
118
|
+
// schemas only require `z.string()`, so without this check a
|
|
119
|
+
// step_created / hook_created / wait_created request with
|
|
120
|
+
// `correlationId: ''` would silently be written under a malformed
|
|
121
|
+
// composite key like `${runId}-`.
|
|
122
|
+
if (runId != null && runId !== '') {
|
|
123
|
+
assertSafeEntityId('runId', runId);
|
|
124
|
+
}
|
|
125
|
+
if ('correlationId' in data && typeof data.correlationId === 'string') {
|
|
126
|
+
assertSafeEntityId('correlationId', data.correlationId);
|
|
127
|
+
}
|
|
128
|
+
// Step lifecycle events are serialized per-step via an in-process mutex
|
|
129
|
+
// so that the "check state, then write" sequence in step_started /
|
|
130
|
+
// step_completed / step_failed / step_retrying is atomic. step_created
|
|
131
|
+
// is also serialized so duplicate-create races don't leave extra
|
|
132
|
+
// step_created events in the log.
|
|
133
|
+
const isStepEvent = data.eventType === 'step_created' ||
|
|
134
|
+
data.eventType === 'step_started' ||
|
|
135
|
+
data.eventType === 'step_completed' ||
|
|
136
|
+
data.eventType === 'step_failed' ||
|
|
137
|
+
data.eventType === 'step_retrying';
|
|
138
|
+
if (isStepEvent && runId && data.correlationId) {
|
|
139
|
+
const lockKey = tag
|
|
140
|
+
? `${runId}-${data.correlationId}.${tag}`
|
|
141
|
+
: `${runId}-${data.correlationId}`;
|
|
142
|
+
return withStepLock(lockKey, () => createImpl());
|
|
143
|
+
}
|
|
144
|
+
return createImpl();
|
|
145
|
+
async function createImpl() {
|
|
146
|
+
const eventId = `evnt_${monotonicUlid()}`;
|
|
147
|
+
const now = new Date();
|
|
148
|
+
// For run_created events, use client-provided runId or generate one server-side
|
|
149
|
+
let effectiveRunId;
|
|
150
|
+
if (data.eventType === 'run_created' && (!runId || runId === '')) {
|
|
151
|
+
effectiveRunId = `wrun_${monotonicUlid()}`;
|
|
152
|
+
}
|
|
153
|
+
else if (!runId) {
|
|
154
|
+
throw new Error('runId is required for non-run_created events');
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
effectiveRunId = runId;
|
|
158
|
+
}
|
|
159
|
+
// Validate client-provided runId timestamp is within acceptable threshold
|
|
160
|
+
if (data.eventType === 'run_created' && runId && runId !== '') {
|
|
161
|
+
const validationError = validateUlidTimestamp(effectiveRunId, 'wrun_');
|
|
162
|
+
if (validationError) {
|
|
163
|
+
throw new WorkflowWorldError(validationError);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// specVersion is always sent by the runtime, but we provide a fallback for safety
|
|
167
|
+
const effectiveSpecVersion = data.specVersion ?? SPEC_VERSION_CURRENT;
|
|
168
|
+
// Helper to check if run is in terminal state
|
|
169
|
+
const isRunTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
|
|
170
|
+
// Helper to check if step is in terminal state
|
|
171
|
+
const isStepTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
|
|
172
|
+
// Get current run state for validation (if not creating a new run)
|
|
173
|
+
// Skip run validation for step_completed and step_retrying - they only operate
|
|
174
|
+
// on running steps, and running steps are always allowed to modify regardless
|
|
175
|
+
// of run state. This optimization saves filesystem reads per step event.
|
|
176
|
+
let currentRun = null;
|
|
177
|
+
const skipRunValidationEvents = ['step_completed', 'step_retrying'];
|
|
178
|
+
if (data.eventType !== 'run_created' &&
|
|
179
|
+
!skipRunValidationEvents.includes(data.eventType)) {
|
|
180
|
+
currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
|
|
181
|
+
// Resilient start: run_started on non-existent run with eventData
|
|
182
|
+
// creates the run first, so the queue can bootstrap a run that
|
|
183
|
+
// failed to create during start().
|
|
184
|
+
if (data.eventType === 'run_started' &&
|
|
185
|
+
!currentRun &&
|
|
186
|
+
'eventData' in data &&
|
|
187
|
+
data.eventData) {
|
|
188
|
+
const runInputData = data.eventData;
|
|
189
|
+
if (runInputData.deploymentId &&
|
|
190
|
+
runInputData.workflowName &&
|
|
191
|
+
runInputData.input !== undefined) {
|
|
192
|
+
// Atomically try to create the run entity. writeExclusive
|
|
193
|
+
// uses O_CREAT|O_EXCL so only the first writer wins,
|
|
194
|
+
// preventing a TOCTOU race where a concurrent run_created
|
|
195
|
+
// from start() could overwrite a run that was already
|
|
196
|
+
// transitioned to 'running'.
|
|
197
|
+
const createdRun = {
|
|
198
|
+
runId: effectiveRunId,
|
|
199
|
+
deploymentId: runInputData.deploymentId,
|
|
200
|
+
status: 'pending',
|
|
201
|
+
workflowName: runInputData.workflowName,
|
|
202
|
+
specVersion: effectiveSpecVersion,
|
|
203
|
+
executionContext: runInputData.executionContext,
|
|
204
|
+
input: runInputData.input,
|
|
205
|
+
output: undefined,
|
|
206
|
+
error: undefined,
|
|
207
|
+
startedAt: undefined,
|
|
208
|
+
completedAt: undefined,
|
|
209
|
+
attributes: {},
|
|
210
|
+
createdAt: now,
|
|
211
|
+
updatedAt: now,
|
|
212
|
+
};
|
|
213
|
+
const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
|
|
214
|
+
const created = await writeExclusive(runPath, JSON.stringify(createdRun, jsonReplacer));
|
|
215
|
+
if (created) {
|
|
216
|
+
// We created the run — also write the run_created event.
|
|
217
|
+
const runCreatedEventId = `evnt_${monotonicUlid()}`;
|
|
218
|
+
const runCreatedEvent = {
|
|
219
|
+
eventType: 'run_created',
|
|
220
|
+
runId: effectiveRunId,
|
|
221
|
+
eventId: runCreatedEventId,
|
|
222
|
+
createdAt: now,
|
|
223
|
+
specVersion: effectiveSpecVersion,
|
|
224
|
+
eventData: {
|
|
225
|
+
deploymentId: runInputData.deploymentId,
|
|
226
|
+
workflowName: runInputData.workflowName,
|
|
227
|
+
input: runInputData.input,
|
|
228
|
+
executionContext: runInputData.executionContext,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
const createdCompositeKey = `${effectiveRunId}-${runCreatedEventId}`;
|
|
232
|
+
await writeJSON(taggedPath(basedir, 'events', createdCompositeKey, tag), runCreatedEvent);
|
|
233
|
+
currentRun = createdRun;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// Run already exists (concurrent run_created won the
|
|
237
|
+
// race). Re-read it so downstream logic sees the real state.
|
|
238
|
+
currentRun = await readJSONWithFallback(basedir, 'runs', effectiveRunId, WorkflowRunSchema, tag);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// run_failed on a non-existent run is rejected to match the
|
|
244
|
+
// postgres and vercel worlds, which both surface this as a
|
|
245
|
+
// WorkflowRunNotFoundError rather than silently persisting an
|
|
246
|
+
// event for a run that was never created.
|
|
247
|
+
if (data.eventType === 'run_failed' && !currentRun) {
|
|
248
|
+
throw new WorkflowRunNotFoundError(effectiveRunId);
|
|
249
|
+
}
|
|
250
|
+
// ============================================================
|
|
251
|
+
// VERSION COMPATIBILITY: Check run spec version
|
|
252
|
+
// ============================================================
|
|
253
|
+
// For events that have fetched the run, check version compatibility.
|
|
254
|
+
// Skip for run_created (no existing run) and runtime events (step_completed, step_retrying).
|
|
255
|
+
if (currentRun) {
|
|
256
|
+
// Check if run requires a newer world version
|
|
257
|
+
if (requiresNewerWorld(currentRun.specVersion)) {
|
|
258
|
+
throw new RunNotSupportedError(currentRun.specVersion, SPEC_VERSION_CURRENT);
|
|
259
|
+
}
|
|
260
|
+
// Route to legacy handler for pre-event-sourcing runs
|
|
261
|
+
if (isLegacySpecVersion(currentRun.specVersion)) {
|
|
262
|
+
return handleLegacyEvent(basedir, effectiveRunId, data, currentRun, params);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// ============================================================
|
|
266
|
+
// VALIDATION: Terminal state and event ordering checks
|
|
267
|
+
// ============================================================
|
|
268
|
+
// Run terminal state validation
|
|
269
|
+
if (currentRun && isRunTerminal(currentRun.status)) {
|
|
270
|
+
const runTerminalEvents = [
|
|
271
|
+
'run_started',
|
|
272
|
+
'run_completed',
|
|
273
|
+
'run_failed',
|
|
274
|
+
];
|
|
275
|
+
// Idempotent operation: run_cancelled on already cancelled run is allowed
|
|
276
|
+
if (data.eventType === 'run_cancelled' &&
|
|
277
|
+
currentRun.status === 'cancelled') {
|
|
278
|
+
// Return existing state (idempotent)
|
|
279
|
+
const event = {
|
|
280
|
+
...data,
|
|
281
|
+
runId: effectiveRunId,
|
|
282
|
+
eventId,
|
|
283
|
+
createdAt: now,
|
|
284
|
+
specVersion: effectiveSpecVersion,
|
|
285
|
+
};
|
|
286
|
+
const compositeKey = `${effectiveRunId}-${eventId}`;
|
|
287
|
+
await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), event);
|
|
288
|
+
const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
289
|
+
return {
|
|
290
|
+
event: stripEventDataRefs(event, resolveData),
|
|
291
|
+
run: currentRun,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
// For run_started on terminal runs, use RunExpiredError so the
|
|
295
|
+
// runtime knows to exit without retrying.
|
|
296
|
+
if (data.eventType === 'run_started') {
|
|
297
|
+
throw new RunExpiredError(`Workflow run "${effectiveRunId}" is already in terminal state "${currentRun.status}"`);
|
|
298
|
+
}
|
|
299
|
+
// Other run state transitions are not allowed on terminal runs
|
|
300
|
+
if (runTerminalEvents.includes(data.eventType) ||
|
|
301
|
+
data.eventType === 'run_cancelled') {
|
|
302
|
+
throw new EntityConflictError(`Cannot transition run from terminal state "${currentRun.status}"`);
|
|
303
|
+
}
|
|
304
|
+
// Creating new entities on terminal runs is not allowed
|
|
305
|
+
if (data.eventType === 'step_created' ||
|
|
306
|
+
data.eventType === 'hook_created' ||
|
|
307
|
+
data.eventType === 'wait_created') {
|
|
308
|
+
throw new EntityConflictError(`Cannot create new entities on run in terminal state "${currentRun.status}"`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Step-related event validation (ordering and terminal state)
|
|
312
|
+
// Store existingStep so we can reuse it later (avoid double read)
|
|
313
|
+
let validatedStep = null;
|
|
314
|
+
const stepEvents = [
|
|
315
|
+
'step_started',
|
|
316
|
+
'step_completed',
|
|
317
|
+
'step_failed',
|
|
318
|
+
'step_retrying',
|
|
319
|
+
];
|
|
320
|
+
if (stepEvents.includes(data.eventType) && data.correlationId) {
|
|
321
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
322
|
+
validatedStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
|
|
323
|
+
// Event ordering: step must exist before these events
|
|
324
|
+
if (!validatedStep) {
|
|
325
|
+
throw new WorkflowWorldError(`Step "${data.correlationId}" not found`);
|
|
326
|
+
}
|
|
327
|
+
// Step terminal state validation
|
|
328
|
+
if (isStepTerminal(validatedStep.status)) {
|
|
329
|
+
throw new EntityConflictError(`Cannot modify step in terminal state "${validatedStep.status}"`);
|
|
330
|
+
}
|
|
331
|
+
// On terminal runs: only allow completing/failing in-progress steps
|
|
332
|
+
if (currentRun && isRunTerminal(currentRun.status)) {
|
|
333
|
+
if (validatedStep.status !== 'running') {
|
|
334
|
+
throw new RunExpiredError(`Cannot modify non-running step on run in terminal state "${currentRun.status}"`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Hook-related event validation (ordering)
|
|
339
|
+
const hookEventsRequiringExistence = ['hook_disposed', 'hook_received'];
|
|
340
|
+
if (hookEventsRequiringExistence.includes(data.eventType) &&
|
|
341
|
+
data.correlationId) {
|
|
342
|
+
const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
|
|
343
|
+
if (!existingHook) {
|
|
344
|
+
throw new HookNotFoundError(data.correlationId);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const event = {
|
|
348
|
+
...data,
|
|
349
|
+
runId: effectiveRunId,
|
|
350
|
+
eventId,
|
|
351
|
+
createdAt: now,
|
|
352
|
+
specVersion: effectiveSpecVersion,
|
|
353
|
+
};
|
|
354
|
+
// Strip eventData from run_started — it belongs on run_created only.
|
|
355
|
+
if (data.eventType === 'run_started' && 'eventData' in event) {
|
|
356
|
+
delete event.eventData;
|
|
357
|
+
}
|
|
358
|
+
// Track entity created/updated for EventResult
|
|
359
|
+
let run;
|
|
360
|
+
let step;
|
|
361
|
+
let hook;
|
|
362
|
+
let wait;
|
|
363
|
+
// Create/update entity based on event type (event-sourced architecture)
|
|
364
|
+
// Run lifecycle events
|
|
365
|
+
if (data.eventType === 'run_created' && 'eventData' in data) {
|
|
366
|
+
const runData = data.eventData;
|
|
367
|
+
run = {
|
|
368
|
+
runId: effectiveRunId,
|
|
369
|
+
deploymentId: runData.deploymentId,
|
|
370
|
+
status: 'pending',
|
|
371
|
+
workflowName: runData.workflowName,
|
|
372
|
+
// Propagate specVersion from the event to the run entity
|
|
373
|
+
specVersion: effectiveSpecVersion,
|
|
374
|
+
executionContext: runData.executionContext,
|
|
375
|
+
input: runData.input,
|
|
376
|
+
output: undefined,
|
|
377
|
+
error: undefined,
|
|
378
|
+
startedAt: undefined,
|
|
379
|
+
completedAt: undefined,
|
|
380
|
+
attributes: {},
|
|
381
|
+
createdAt: now,
|
|
382
|
+
updatedAt: now,
|
|
383
|
+
};
|
|
384
|
+
// Use writeExclusive (O_CREAT|O_EXCL) to atomically create the
|
|
385
|
+
// run entity file. This prevents a TOCTOU race with the resilient
|
|
386
|
+
// start path (run_started on non-existent run) that could result
|
|
387
|
+
// in duplicate run_created events in the event log.
|
|
388
|
+
const runPath = taggedPath(basedir, 'runs', effectiveRunId, tag);
|
|
389
|
+
const created = await writeExclusive(runPath, JSON.stringify(run, jsonReplacer, 2));
|
|
390
|
+
if (!created) {
|
|
391
|
+
throw new EntityConflictError(`Workflow run "${effectiveRunId}" already exists`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
else if (data.eventType === 'run_started') {
|
|
395
|
+
// Reuse currentRun from validation (already read above)
|
|
396
|
+
if (currentRun) {
|
|
397
|
+
// If already running, return the run without inserting a
|
|
398
|
+
// duplicate event. This makes run_started idempotent for
|
|
399
|
+
// concurrent invocations. We omit preloaded events here
|
|
400
|
+
// because this is a rare race-condition path — the runtime
|
|
401
|
+
// falls back to loadWorkflowRunEvents().
|
|
402
|
+
if (currentRun.status === 'running') {
|
|
403
|
+
return { run: currentRun };
|
|
404
|
+
}
|
|
405
|
+
run = await writeRunUnderLifecycleLock(basedir, effectiveRunId, tag, {
|
|
406
|
+
runId: currentRun.runId,
|
|
407
|
+
deploymentId: currentRun.deploymentId,
|
|
408
|
+
workflowName: currentRun.workflowName,
|
|
409
|
+
specVersion: currentRun.specVersion,
|
|
410
|
+
executionContext: currentRun.executionContext,
|
|
411
|
+
input: currentRun.input,
|
|
412
|
+
createdAt: currentRun.createdAt,
|
|
413
|
+
expiredAt: currentRun.expiredAt,
|
|
414
|
+
status: 'running',
|
|
415
|
+
output: undefined,
|
|
416
|
+
error: undefined,
|
|
417
|
+
completedAt: undefined,
|
|
418
|
+
startedAt: currentRun.startedAt ?? now,
|
|
419
|
+
updatedAt: now,
|
|
420
|
+
attributes: currentRun.attributes,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
else if (data.eventType === 'run_completed' && 'eventData' in data) {
|
|
425
|
+
const completedData = data.eventData;
|
|
426
|
+
// Reuse currentRun from validation (already read above)
|
|
427
|
+
if (currentRun) {
|
|
428
|
+
run = await writeRunUnderLifecycleLock(basedir, effectiveRunId, tag, {
|
|
429
|
+
runId: currentRun.runId,
|
|
430
|
+
deploymentId: currentRun.deploymentId,
|
|
431
|
+
workflowName: currentRun.workflowName,
|
|
432
|
+
specVersion: currentRun.specVersion,
|
|
433
|
+
executionContext: currentRun.executionContext,
|
|
434
|
+
input: currentRun.input,
|
|
435
|
+
createdAt: currentRun.createdAt,
|
|
436
|
+
expiredAt: currentRun.expiredAt,
|
|
437
|
+
startedAt: currentRun.startedAt,
|
|
438
|
+
status: 'completed',
|
|
439
|
+
output: completedData.output,
|
|
440
|
+
error: undefined,
|
|
441
|
+
completedAt: now,
|
|
442
|
+
updatedAt: now,
|
|
443
|
+
attributes: currentRun.attributes,
|
|
444
|
+
});
|
|
445
|
+
await Promise.all([
|
|
446
|
+
deleteAllHooksForRun(basedir, effectiveRunId),
|
|
447
|
+
deleteAllWaitsForRun(basedir, effectiveRunId),
|
|
448
|
+
]);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else if (data.eventType === 'run_failed' && 'eventData' in data) {
|
|
452
|
+
const failedData = data.eventData;
|
|
453
|
+
// Reuse currentRun from validation (already read above)
|
|
454
|
+
if (currentRun) {
|
|
455
|
+
// The error field is SerializedData (Uint8Array) produced by
|
|
456
|
+
// dehydrateRunError. We store it verbatim — consumers hydrate it
|
|
457
|
+
// via hydrateRunError to reconstruct the original thrown value.
|
|
458
|
+
run = await writeRunUnderLifecycleLock(basedir, effectiveRunId, tag, {
|
|
459
|
+
runId: currentRun.runId,
|
|
460
|
+
deploymentId: currentRun.deploymentId,
|
|
461
|
+
workflowName: currentRun.workflowName,
|
|
462
|
+
specVersion: currentRun.specVersion,
|
|
463
|
+
executionContext: currentRun.executionContext,
|
|
464
|
+
input: currentRun.input,
|
|
465
|
+
createdAt: currentRun.createdAt,
|
|
466
|
+
expiredAt: currentRun.expiredAt,
|
|
467
|
+
startedAt: currentRun.startedAt,
|
|
468
|
+
status: 'failed',
|
|
469
|
+
output: undefined,
|
|
470
|
+
error: failedData.error,
|
|
471
|
+
errorCode: failedData.errorCode,
|
|
472
|
+
completedAt: now,
|
|
473
|
+
updatedAt: now,
|
|
474
|
+
attributes: currentRun.attributes,
|
|
475
|
+
});
|
|
476
|
+
await Promise.all([
|
|
477
|
+
deleteAllHooksForRun(basedir, effectiveRunId),
|
|
478
|
+
deleteAllWaitsForRun(basedir, effectiveRunId),
|
|
479
|
+
]);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else if (data.eventType === 'run_cancelled') {
|
|
483
|
+
// Reuse currentRun from validation (already read above)
|
|
484
|
+
if (currentRun) {
|
|
485
|
+
run = await writeRunUnderLifecycleLock(basedir, effectiveRunId, tag, {
|
|
486
|
+
runId: currentRun.runId,
|
|
487
|
+
deploymentId: currentRun.deploymentId,
|
|
488
|
+
workflowName: currentRun.workflowName,
|
|
489
|
+
specVersion: currentRun.specVersion,
|
|
490
|
+
executionContext: currentRun.executionContext,
|
|
491
|
+
input: currentRun.input,
|
|
492
|
+
createdAt: currentRun.createdAt,
|
|
493
|
+
expiredAt: currentRun.expiredAt,
|
|
494
|
+
startedAt: currentRun.startedAt,
|
|
495
|
+
status: 'cancelled',
|
|
496
|
+
output: undefined,
|
|
497
|
+
error: undefined,
|
|
498
|
+
completedAt: now,
|
|
499
|
+
updatedAt: now,
|
|
500
|
+
attributes: currentRun.attributes,
|
|
501
|
+
});
|
|
502
|
+
await Promise.all([
|
|
503
|
+
deleteAllHooksForRun(basedir, effectiveRunId),
|
|
504
|
+
deleteAllWaitsForRun(basedir, effectiveRunId),
|
|
505
|
+
]);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else if (
|
|
509
|
+
// Step lifecycle events
|
|
510
|
+
data.eventType === 'step_created' &&
|
|
511
|
+
'eventData' in data) {
|
|
512
|
+
// step_created: Creates step entity with status 'pending', attempt=0, createdAt set.
|
|
513
|
+
// Two concurrent invocations with identical correlationIds (e.g. the
|
|
514
|
+
// snapshot runtime's deterministic correlationIds across replays)
|
|
515
|
+
// must be deduped — otherwise both writes succeed and the event log
|
|
516
|
+
// ends up with duplicate step_created entries. The outer
|
|
517
|
+
// withStepLock mutex serializes within a single process; this
|
|
518
|
+
// O_CREAT|O_EXCL constraint file additionally protects against
|
|
519
|
+
// cross-process races (two pnpm workers, redelivered queue
|
|
520
|
+
// messages, etc.). The loser throws EntityConflictError so the
|
|
521
|
+
// runtime's existing catch path can swallow it and avoid
|
|
522
|
+
// double-queuing the step.
|
|
523
|
+
const stepCreatedLockName = tag
|
|
524
|
+
? `${effectiveRunId}-${data.correlationId}.created.${tag}`
|
|
525
|
+
: `${effectiveRunId}-${data.correlationId}.created`;
|
|
526
|
+
const stepCreatedLockPath = resolveWithinBase(basedir, '.locks', 'steps', stepCreatedLockName);
|
|
527
|
+
const stepCreatedClaimed = await writeExclusive(stepCreatedLockPath, '');
|
|
528
|
+
if (!stepCreatedClaimed) {
|
|
529
|
+
throw new EntityConflictError(`Step "${data.correlationId}" already created`);
|
|
530
|
+
}
|
|
531
|
+
const stepData = data.eventData;
|
|
532
|
+
step = {
|
|
533
|
+
runId: effectiveRunId,
|
|
534
|
+
stepId: data.correlationId,
|
|
535
|
+
stepName: stepData.stepName,
|
|
536
|
+
status: 'pending',
|
|
537
|
+
input: stepData.input,
|
|
538
|
+
output: undefined,
|
|
539
|
+
error: undefined,
|
|
540
|
+
attempt: 0,
|
|
541
|
+
startedAt: undefined,
|
|
542
|
+
completedAt: undefined,
|
|
543
|
+
createdAt: now,
|
|
544
|
+
updatedAt: now,
|
|
545
|
+
// Propagate specVersion from the event to the step entity
|
|
546
|
+
specVersion: effectiveSpecVersion,
|
|
547
|
+
};
|
|
548
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
549
|
+
await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step);
|
|
550
|
+
}
|
|
551
|
+
else if (data.eventType === 'step_started') {
|
|
552
|
+
// step_started: Increments attempt, sets status to 'running'
|
|
553
|
+
// Sets startedAt only on the first start (not updated on retries)
|
|
554
|
+
// Reuse validatedStep from validation (already read above)
|
|
555
|
+
if (validatedStep) {
|
|
556
|
+
// Check if retryAfter timestamp hasn't been reached yet
|
|
557
|
+
if (validatedStep.retryAfter &&
|
|
558
|
+
validatedStep.retryAfter.getTime() > Date.now()) {
|
|
559
|
+
throw new TooEarlyError(`Cannot start step "${data.correlationId}": retryAfter timestamp has not been reached yet`, {
|
|
560
|
+
retryAfter: Math.ceil((validatedStep.retryAfter.getTime() - Date.now()) / 1000),
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
// Best-effort guard: re-read the step entity to check if it
|
|
564
|
+
// reached terminal state between the validation read and now.
|
|
565
|
+
// This narrows the TOCTOU window but does not fully eliminate it
|
|
566
|
+
// (the local world is single-process / dev-only; the postgres
|
|
567
|
+
// world uses SQL-level atomic guards for production).
|
|
568
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
569
|
+
const freshStep = await readJSONWithFallback(basedir, 'steps', stepCompositeKey, StepSchema, tag);
|
|
570
|
+
if (freshStep && isStepTerminal(freshStep.status)) {
|
|
571
|
+
throw new EntityConflictError(`Cannot modify step in terminal state "${freshStep.status}"`);
|
|
572
|
+
}
|
|
573
|
+
step = {
|
|
574
|
+
...validatedStep,
|
|
575
|
+
status: 'running',
|
|
576
|
+
// Only set startedAt on the first start
|
|
577
|
+
startedAt: validatedStep.startedAt ?? now,
|
|
578
|
+
// Increment attempt counter on every start
|
|
579
|
+
attempt: validatedStep.attempt + 1,
|
|
580
|
+
// Clear retryAfter now that the step has started
|
|
581
|
+
retryAfter: undefined,
|
|
582
|
+
updatedAt: now,
|
|
583
|
+
};
|
|
584
|
+
await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
else if (data.eventType === 'step_completed' && 'eventData' in data) {
|
|
588
|
+
// step_completed: Terminal state with output
|
|
589
|
+
// Uses writeExclusive on a lock file to atomically prevent concurrent
|
|
590
|
+
// invocations from both completing the same step (TOCTOU race).
|
|
591
|
+
const completedData = data.eventData;
|
|
592
|
+
if (validatedStep) {
|
|
593
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
594
|
+
const lockName = tag
|
|
595
|
+
? `${stepCompositeKey}.terminal.${tag}`
|
|
596
|
+
: `${stepCompositeKey}.terminal`;
|
|
597
|
+
const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
|
|
598
|
+
const claimed = await writeExclusive(terminalLockPath, '');
|
|
599
|
+
if (!claimed) {
|
|
600
|
+
throw new EntityConflictError('Cannot modify step in terminal state');
|
|
601
|
+
}
|
|
602
|
+
step = {
|
|
603
|
+
...validatedStep,
|
|
604
|
+
status: 'completed',
|
|
605
|
+
output: completedData.result,
|
|
606
|
+
completedAt: now,
|
|
607
|
+
updatedAt: now,
|
|
608
|
+
};
|
|
609
|
+
await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
else if (data.eventType === 'step_failed' && 'eventData' in data) {
|
|
613
|
+
// step_failed: Terminal state with error
|
|
614
|
+
// Uses writeExclusive on a lock file to atomically prevent concurrent
|
|
615
|
+
// invocations from both failing the same step (TOCTOU race).
|
|
616
|
+
const failedData = data.eventData;
|
|
617
|
+
if (validatedStep) {
|
|
618
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
619
|
+
const lockName = tag
|
|
620
|
+
? `${stepCompositeKey}.terminal.${tag}`
|
|
621
|
+
: `${stepCompositeKey}.terminal`;
|
|
622
|
+
const terminalLockPath = resolveWithinBase(basedir, '.locks', 'steps', lockName);
|
|
623
|
+
const claimed = await writeExclusive(terminalLockPath, '');
|
|
624
|
+
if (!claimed) {
|
|
625
|
+
throw new EntityConflictError('Cannot modify step in terminal state');
|
|
626
|
+
}
|
|
627
|
+
// The error field is SerializedData (Uint8Array) produced by
|
|
628
|
+
// dehydrateStepError. We store it verbatim — consumers hydrate it
|
|
629
|
+
// via hydrateStepError to reconstruct the original thrown value.
|
|
630
|
+
step = {
|
|
631
|
+
...validatedStep,
|
|
632
|
+
status: 'failed',
|
|
633
|
+
error: failedData.error,
|
|
634
|
+
completedAt: now,
|
|
635
|
+
updatedAt: now,
|
|
636
|
+
};
|
|
637
|
+
await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else if (data.eventType === 'step_retrying' && 'eventData' in data) {
|
|
641
|
+
// step_retrying: Sets status back to 'pending', records error
|
|
642
|
+
// Reuse validatedStep from validation (already read above)
|
|
643
|
+
const retryData = data.eventData;
|
|
644
|
+
if (validatedStep) {
|
|
645
|
+
const stepCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
646
|
+
step = {
|
|
647
|
+
...validatedStep,
|
|
648
|
+
status: 'pending',
|
|
649
|
+
error: retryData.error,
|
|
650
|
+
retryAfter: retryData.retryAfter,
|
|
651
|
+
updatedAt: now,
|
|
652
|
+
};
|
|
653
|
+
await writeJSON(taggedPath(basedir, 'steps', stepCompositeKey, tag), step, { overwrite: true });
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
else if (
|
|
657
|
+
// Hook lifecycle events
|
|
658
|
+
data.eventType === 'hook_created' &&
|
|
659
|
+
'eventData' in data) {
|
|
660
|
+
const hookData = data.eventData;
|
|
661
|
+
// Atomically claim the token using an exclusive-create constraint file.
|
|
662
|
+
// This avoids the TOCTOU race of the previous read-all-then-check approach.
|
|
663
|
+
const constraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(hookData.token)}.json`);
|
|
664
|
+
const tokenClaimed = await writeExclusive(constraintPath, JSON.stringify({
|
|
665
|
+
token: hookData.token,
|
|
666
|
+
hookId: data.correlationId,
|
|
667
|
+
runId: effectiveRunId,
|
|
668
|
+
}));
|
|
669
|
+
if (!tokenClaimed) {
|
|
670
|
+
const existingClaim = await readHookTokenClaim(constraintPath);
|
|
671
|
+
// Create hook_conflict event instead of hook_created
|
|
672
|
+
// This allows the workflow to continue and fail gracefully when the hook is awaited
|
|
673
|
+
const conflictEvent = {
|
|
674
|
+
eventType: 'hook_conflict',
|
|
675
|
+
correlationId: data.correlationId,
|
|
676
|
+
eventData: {
|
|
677
|
+
token: hookData.token,
|
|
678
|
+
...(existingClaim
|
|
679
|
+
? { conflictingRunId: existingClaim.runId }
|
|
680
|
+
: {}),
|
|
681
|
+
},
|
|
682
|
+
runId: effectiveRunId,
|
|
683
|
+
eventId,
|
|
684
|
+
createdAt: now,
|
|
685
|
+
specVersion: effectiveSpecVersion,
|
|
686
|
+
};
|
|
687
|
+
// Store the conflict event
|
|
688
|
+
const compositeKey = `${effectiveRunId}-${eventId}`;
|
|
689
|
+
await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), conflictEvent);
|
|
690
|
+
const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
691
|
+
const filteredEvent = stripEventDataRefs(conflictEvent, resolveData);
|
|
692
|
+
// Return EventResult with conflict event (no hook entity created)
|
|
693
|
+
return {
|
|
694
|
+
event: filteredEvent,
|
|
695
|
+
run,
|
|
696
|
+
step,
|
|
697
|
+
hook: undefined,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
hook = {
|
|
701
|
+
runId: effectiveRunId,
|
|
702
|
+
hookId: data.correlationId,
|
|
703
|
+
token: hookData.token,
|
|
704
|
+
metadata: hookData.metadata,
|
|
705
|
+
ownerId: 'local-owner',
|
|
706
|
+
projectId: 'local-project',
|
|
707
|
+
environment: 'local',
|
|
708
|
+
createdAt: now,
|
|
709
|
+
// Propagate specVersion from the event to the hook entity
|
|
710
|
+
specVersion: effectiveSpecVersion,
|
|
711
|
+
isWebhook: hookData.isWebhook ?? false,
|
|
712
|
+
isSystem: hookData.isSystem ?? false,
|
|
713
|
+
};
|
|
714
|
+
await writeJSON(taggedPath(basedir, 'hooks', data.correlationId, tag), hook);
|
|
715
|
+
}
|
|
716
|
+
else if (data.eventType === 'hook_disposed') {
|
|
717
|
+
// hook_disposed: Deletes hook entity, rejects duplicates.
|
|
718
|
+
// Uses writeExclusive on a lock file to atomically prevent concurrent
|
|
719
|
+
// invocations from both disposing the same hook (TOCTOU race).
|
|
720
|
+
const hookLockName = tag
|
|
721
|
+
? `${data.correlationId}.disposed.${tag}`
|
|
722
|
+
: `${data.correlationId}.disposed`;
|
|
723
|
+
const lockPath = resolveWithinBase(basedir, '.locks', 'hooks', hookLockName);
|
|
724
|
+
const claimed = await writeExclusive(lockPath, '');
|
|
725
|
+
if (!claimed) {
|
|
726
|
+
throw new EntityConflictError(`Hook "${data.correlationId}" already disposed`);
|
|
727
|
+
}
|
|
728
|
+
// Read the hook to get its token before deleting
|
|
729
|
+
const hookPath = taggedPath(basedir, 'hooks', data.correlationId, tag);
|
|
730
|
+
const existingHook = await readJSONWithFallback(basedir, 'hooks', data.correlationId, HookSchema, tag);
|
|
731
|
+
if (existingHook) {
|
|
732
|
+
// Delete the token constraint file to free up the token for reuse
|
|
733
|
+
const disposedConstraintPath = path.join(basedir, 'hooks', 'tokens', `${hashToken(existingHook.token)}.json`);
|
|
734
|
+
await deleteJSON(disposedConstraintPath);
|
|
735
|
+
}
|
|
736
|
+
await deleteJSON(hookPath);
|
|
737
|
+
}
|
|
738
|
+
else if (data.eventType === 'wait_created' && 'eventData' in data) {
|
|
739
|
+
// wait_created: Creates wait entity with status 'waiting'.
|
|
740
|
+
// Atomic claim on a per-(runId, correlationId) constraint file
|
|
741
|
+
// ensures duplicate wait_created from concurrent invocations
|
|
742
|
+
// surfaces as EntityConflictError (replaces a prior TOCTOU
|
|
743
|
+
// read-then-check that could let both writers through).
|
|
744
|
+
const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
745
|
+
const waitCreatedLockName = tag
|
|
746
|
+
? `${waitCompositeKey}.created.${tag}`
|
|
747
|
+
: `${waitCompositeKey}.created`;
|
|
748
|
+
const waitCreatedLockPath = resolveWithinBase(basedir, '.locks', 'waits', waitCreatedLockName);
|
|
749
|
+
const waitCreatedClaimed = await writeExclusive(waitCreatedLockPath, '');
|
|
750
|
+
if (!waitCreatedClaimed) {
|
|
751
|
+
throw new EntityConflictError(`Wait "${data.correlationId}" already exists`);
|
|
752
|
+
}
|
|
753
|
+
const waitData = data.eventData;
|
|
754
|
+
wait = {
|
|
755
|
+
waitId: waitCompositeKey,
|
|
756
|
+
runId: effectiveRunId,
|
|
757
|
+
status: 'waiting',
|
|
758
|
+
resumeAt: waitData.resumeAt,
|
|
759
|
+
completedAt: undefined,
|
|
760
|
+
createdAt: now,
|
|
761
|
+
updatedAt: now,
|
|
762
|
+
specVersion: effectiveSpecVersion,
|
|
763
|
+
};
|
|
764
|
+
await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait);
|
|
765
|
+
}
|
|
766
|
+
else if (data.eventType === 'wait_completed') {
|
|
767
|
+
// wait_completed: Transitions wait to 'completed', rejects duplicates.
|
|
768
|
+
// Uses writeExclusive on a lock file to atomically prevent concurrent
|
|
769
|
+
// invocations from both completing the same wait (TOCTOU race).
|
|
770
|
+
const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
|
|
771
|
+
const waitLockName = tag
|
|
772
|
+
? `${waitCompositeKey}.completed.${tag}`
|
|
773
|
+
: `${waitCompositeKey}.completed`;
|
|
774
|
+
const lockPath = resolveWithinBase(basedir, '.locks', 'waits', waitLockName);
|
|
775
|
+
const claimed = await writeExclusive(lockPath, '');
|
|
776
|
+
if (!claimed) {
|
|
777
|
+
throw new EntityConflictError(`Wait "${data.correlationId}" already completed`);
|
|
778
|
+
}
|
|
779
|
+
const existingWait = await readJSONWithFallback(basedir, 'waits', waitCompositeKey, WaitSchema, tag);
|
|
780
|
+
if (!existingWait) {
|
|
781
|
+
// Clean up the lock file we just claimed — the wait doesn't exist
|
|
782
|
+
await fs.unlink(lockPath).catch(() => { });
|
|
783
|
+
throw new WorkflowWorldError(`Wait "${data.correlationId}" not found`);
|
|
784
|
+
}
|
|
785
|
+
// The lock file (writeExclusive above) already prevents concurrent
|
|
786
|
+
// completions — no additional status check needed.
|
|
787
|
+
wait = {
|
|
788
|
+
...existingWait,
|
|
789
|
+
status: 'completed',
|
|
790
|
+
completedAt: now,
|
|
791
|
+
updatedAt: now,
|
|
792
|
+
};
|
|
793
|
+
await writeJSON(taggedPath(basedir, 'waits', waitCompositeKey, tag), wait, { overwrite: true });
|
|
794
|
+
}
|
|
795
|
+
// Note: hook_received events are stored in the event log but don't
|
|
796
|
+
// modify the Hook entity (which doesn't have a payload field)
|
|
797
|
+
// Store event using composite key {runId}-{eventId}
|
|
798
|
+
const compositeKey = `${effectiveRunId}-${eventId}`;
|
|
799
|
+
await writeJSON(taggedPath(basedir, 'events', compositeKey, tag), event);
|
|
800
|
+
const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
801
|
+
const filteredEvent = stripEventDataRefs(event, resolveData);
|
|
802
|
+
// For run_started: preload one page of events so the runtime can skip
|
|
803
|
+
// the initial events.list call when hasMore is false.
|
|
804
|
+
let events;
|
|
805
|
+
let cursor;
|
|
806
|
+
let hasMore;
|
|
807
|
+
if (data.eventType === 'run_started' && run) {
|
|
808
|
+
const allEvents = await paginatedFileSystemQuery({
|
|
809
|
+
directory: path.join(basedir, 'events'),
|
|
810
|
+
schema: EventSchema,
|
|
811
|
+
filePrefix: `${effectiveRunId}-`,
|
|
812
|
+
sortOrder: 'asc',
|
|
813
|
+
limit: 1000,
|
|
814
|
+
getCreatedAt: getObjectCreatedAt('evnt'),
|
|
815
|
+
getId: (e) => e.eventId,
|
|
816
|
+
});
|
|
817
|
+
events = allEvents.data;
|
|
818
|
+
cursor = allEvents.cursor;
|
|
819
|
+
hasMore = allEvents.hasMore;
|
|
820
|
+
}
|
|
821
|
+
// Return EventResult with event and any created/updated entity
|
|
822
|
+
return {
|
|
823
|
+
event: filteredEvent,
|
|
824
|
+
run,
|
|
825
|
+
step,
|
|
826
|
+
hook,
|
|
827
|
+
wait,
|
|
828
|
+
events,
|
|
829
|
+
cursor,
|
|
830
|
+
hasMore,
|
|
831
|
+
};
|
|
832
|
+
} // end createImpl
|
|
833
|
+
},
|
|
834
|
+
async get(runId, eventId, params) {
|
|
835
|
+
assertSafeEntityId('runId', runId);
|
|
836
|
+
assertSafeEntityId('eventId', eventId);
|
|
837
|
+
const compositeKey = `${runId}-${eventId}`;
|
|
838
|
+
const event = await readJSONWithFallback(basedir, 'events', compositeKey, EventSchema, tag);
|
|
839
|
+
if (!event) {
|
|
840
|
+
throw new Error(`Event ${eventId} in run ${runId} not found`);
|
|
841
|
+
}
|
|
842
|
+
const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
843
|
+
return stripEventDataRefs(event, resolveData);
|
|
844
|
+
},
|
|
845
|
+
async list(params) {
|
|
846
|
+
const { runId } = params;
|
|
847
|
+
assertSafeEntityId('runId', runId);
|
|
848
|
+
const resolveData = params.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
849
|
+
const result = await paginatedFileSystemQuery({
|
|
850
|
+
directory: path.join(basedir, 'events'),
|
|
851
|
+
schema: EventSchema,
|
|
852
|
+
filePrefix: `${runId}-`,
|
|
853
|
+
// Events in chronological order (oldest first) by default,
|
|
854
|
+
// different from the default for other list calls.
|
|
855
|
+
sortOrder: params.pagination?.sortOrder ?? 'asc',
|
|
856
|
+
limit: params.pagination?.limit,
|
|
857
|
+
cursor: params.pagination?.cursor,
|
|
858
|
+
getCreatedAt: getObjectCreatedAt('evnt'),
|
|
859
|
+
getId: (event) => event.eventId,
|
|
860
|
+
});
|
|
861
|
+
// If resolveData is "none", remove eventData from events
|
|
862
|
+
if (resolveData === 'none') {
|
|
863
|
+
return {
|
|
864
|
+
...result,
|
|
865
|
+
data: result.data.map((event) => stripEventDataRefs(event, resolveData)),
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
return result;
|
|
869
|
+
},
|
|
870
|
+
async listByCorrelationId(params) {
|
|
871
|
+
const correlationId = params.correlationId;
|
|
872
|
+
assertSafeEntityId('correlationId', correlationId);
|
|
873
|
+
const resolveData = params.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
|
|
874
|
+
const result = await paginatedFileSystemQuery({
|
|
875
|
+
directory: path.join(basedir, 'events'),
|
|
876
|
+
schema: EventSchema,
|
|
877
|
+
// No filePrefix - search all events
|
|
878
|
+
filter: (event) => event.correlationId === correlationId,
|
|
879
|
+
// Events in chronological order (oldest first) by default,
|
|
880
|
+
// different from the default for other list calls.
|
|
881
|
+
sortOrder: params.pagination?.sortOrder ?? 'asc',
|
|
882
|
+
limit: params.pagination?.limit,
|
|
883
|
+
cursor: params.pagination?.cursor,
|
|
884
|
+
getCreatedAt: getObjectCreatedAt('evnt'),
|
|
885
|
+
getId: (event) => event.eventId,
|
|
886
|
+
});
|
|
887
|
+
// If resolveData is "none", remove eventData from events
|
|
888
|
+
if (resolveData === 'none') {
|
|
889
|
+
return {
|
|
890
|
+
...result,
|
|
891
|
+
data: result.data.map((event) => stripEventDataRefs(event, resolveData)),
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
return result;
|
|
895
|
+
},
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLXN0b3JhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9ldmVudHMtc3RvcmFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsQyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixpQkFBaUIsRUFDakIsZUFBZSxFQUNmLG9CQUFvQixFQUNwQixhQUFhLEVBQ2Isd0JBQXdCLEVBQ3hCLGtCQUFrQixHQUNuQixNQUFNLGtCQUFrQixDQUFDO0FBVzFCLE9BQU8sRUFDTCxXQUFXLEVBQ1gsVUFBVSxFQUNWLG1CQUFtQixFQUNuQixrQkFBa0IsRUFDbEIsb0JBQW9CLEVBQ3BCLFVBQVUsRUFDVixxQkFBcUIsRUFDckIsVUFBVSxFQUNWLGlCQUFpQixHQUNsQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDeEIsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzNELE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsVUFBVSxFQUNWLFlBQVksRUFDWixhQUFhLEVBQ2Isd0JBQXdCLEVBQ3hCLFFBQVEsRUFDUixvQkFBb0IsRUFDcEIsaUJBQWlCLEVBQ2pCLFVBQVUsRUFDVixjQUFjLEVBQ2QsU0FBUyxHQUNWLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM1RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUs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Q0FBQyxPQUFPO2FBQ2hDLENBQUMsQ0FBQztZQUVILHlEQUF5RDtZQUN6RCxJQUFJLFdBQVcsS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDM0IsT0FBTztvQkFDTCxHQUFHLE1BQU07b0JBQ1QsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDOUIsa0JBQWtCLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUN2QztpQkFDRixDQUFDO1lBQ0osQ0FBQztZQUVELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdub2RlOmZzL3Byb21pc2VzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBIb29rTm90Rm91bmRFcnJvcixcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBSdW5Ob3RTdXBwb3J0ZWRFcnJvcixcbiAgVG9vRWFybHlFcnJvcixcbiAgV29ya2Zsb3dSdW5Ob3RGb3VuZEVycm9yLFxuICBXb3JrZmxvd1dvcmxkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHR5cGUge1xuICBFdmVudCxcbiAgRXZlbnRSZXN1bHQsXG4gIEhvb2ssXG4gIFNlcmlhbGl6ZWREYXRhLFxuICBTdGVwLFxuICBTdG9yYWdlLFxuICBXYWl0LFxuICBXb3JrZmxvd1J1bixcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7XG4gIEV2ZW50U2NoZW1hLFxuICBIb29rU2NoZW1hLFxuICBpc0xlZ2FjeVNwZWNWZXJzaW9uLFxuICByZXF1aXJlc05ld2VyV29ybGQsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTdGVwU2NoZW1hLFxuICB2YWxpZGF0ZVVsaWRUaW1lc3RhbXAsXG4gIFdhaXRTY2hlbWEsXG4gIFdvcmtmbG93UnVuU2NoZW1hLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgeyBERUZBVUxUX1JFU09MVkVfREFUQV9PUFRJT04gfSBmcm9tICcuLi9jb25maWcuanMnO1xuaW1wb3J0IHtcbiAgYXNzZXJ0U2FmZUVudGl0eUlkLFxuICBkZWxldGVKU09OLFxuICBqc29uUmVwbGFjZXIsXG4gIGxpc3RKU09ORmlsZXMsXG4gIHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSxcbiAgcmVhZEpTT04sXG4gIHJlYWRKU09OV2l0aEZhbGxiYWNrLFxuICByZXNvbHZlV2l0aGluQmFzZSxcbiAgdGFnZ2VkUGF0aCxcbiAgd3JpdGVFeGNsdXNpdmUsXG4gIHdyaXRlSlNPTixcbn0gZnJvbSAnLi4vZnMuanMnO1xuaW1wb3J0IHsgc3RyaXBFdmVudERhdGFSZWZzIH0gZnJvbSAnLi9maWx0ZXJzLmpzJztcbmltcG9ydCB7IGdldE9iamVjdENyZWF0ZWRBdCwgaGFzaFRva2VuLCBtb25vdG9uaWNVbGlkIH0gZnJvbSAnLi9oZWxwZXJzLmpzJztcbmltcG9ydCB7IGRlbGV0ZUFsbEhvb2tzRm9yUnVuIH0gZnJvbSAnLi9ob29rcy1zdG9yYWdlLmpzJztcbmltcG9ydCB7IGhhbmRsZUxlZ2FjeUV2ZW50IH0gZnJvbSAnLi9sZWdhY3kuanMnO1xuaW1wb3J0IHsgd2l0aFJ1bkZpbGVMb2NrIH0gZnJvbSAnLi9ydW5zLXN0b3JhZ2UuanMnO1xuXG4vKipcbiAqIFBlci1zdGVwIGluLXByb2Nlc3MgYXN5bmMgbXV0ZXguIFNlcmlhbGl6ZXMgY29uY3VycmVudCBgZXZlbnRzLmNyZWF0ZWAgY2FsbHNcbiAqIHRoYXQgdGFyZ2V0IHRoZSBzYW1lIHN0ZXAsIHNvIHRoYXQgdGhlIFwiY2hlY2sgdGVybWluYWwgc3RhdGUsIHRoZW4gd3JpdGUgc3RlcFxuICogZW50aXR5ICsgZXZlbnRcIiBzZXF1ZW5jZSBpcyBhdG9taWMuIFdpdGhvdXQgdGhpcywgdHdvIGNvbmN1cnJlbnQgc3RlcF9zdGFydGVkXG4gKiBjYWxscyBjYW4gYm90aCBwYXNzIHRoZSBub3QtdGVybWluYWwgY2hlY2sgYW5kIGJvdGggd3JpdGUgc3RlcF9zdGFydGVkIGV2ZW50c1xuICog4oCUIG9yIGEgc3RlcF9zdGFydGVkIGNhbiBsYW5kIGluIHRoZSBsb2cgYWZ0ZXIgc3RlcF9jb21wbGV0ZWQgaGFzIGFscmVhZHlcbiAqIHdyaXR0ZW4sIHByb2R1Y2luZyB1bmNvbnN1bWVkIGV2ZW50cyBvbiByZXBsYXkuXG4gKlxuICogRHVwbGljYXRlIHN0ZXBfc3RhcnRlZCBldmVudHMgZm9yIGEgbm9uLXRlcm1pbmFsIHN0ZXAgYXJlIHN0aWxsIGFsbG93ZWRcbiAqIChyZXRyaWVzIGxlZ2l0aW1hdGVseSByZS1zdGFydCBhIHN0ZXApLCBvbmx5IHdyaXRlcyB0byBhbiBhbHJlYWR5LXRlcm1pbmFsXG4gKiBzdGVwIGFyZSByZWplY3RlZC5cbiAqL1xuY29uc3Qgc3RlcExvY2tzID0gbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8dW5rbm93bj4+KCk7XG5cbmNvbnN0IEhvb2tUb2tlbkNsYWltU2NoZW1hID0gei5vYmplY3Qoe1xuICBydW5JZDogei5zdHJpbmcoKSxcbn0pO1xuXG5hc3luYyBmdW5jdGlvbiByZWFkSG9va1Rva2VuQ2xhaW0oXG4gIGNvbnN0cmFpbnRQYXRoOiBzdHJpbmdcbik6IFByb21pc2U8ei5pbmZlcjx0eXBlb2YgSG9va1Rva2VuQ2xhaW1TY2hlbWE+IHwgbnVsbD4ge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCByZWFkSlNPTihjb25zdHJhaW50UGF0aCwgSG9va1Rva2VuQ2xhaW1TY2hlbWEpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFN5bnRheEVycm9yIHx8IGVycm9yIGluc3RhbmNlb2Ygei5ab2RFcnJvcikge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbmZ1bmN0aW9uIHdpdGhTdGVwTG9jazxUPihrZXk6IHN0cmluZywgZm46ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgY29uc3QgcHJldiA9IHN0ZXBMb2Nrcy5nZXQoa2V5KTtcbiAgY29uc3QgdGFza0JveDogeyB0YXNrPzogUHJvbWlzZTxUPiB9ID0ge307XG4gIGNvbnN0IHRhc2sgPSAoYXN5bmMgKCkgPT4ge1xuICAgIGlmIChwcmV2KSB7XG4gICAgICAvLyBXYWl0IGZvciB0aGUgcHJldmlvdXMgdGFzayB0byBzZXR0bGU7IGRvbid0IGluaGVyaXQgaXRzIGVycm9ycy5cbiAgICAgIGF3YWl0IHByZXYuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAoc3RlcExvY2tzLmdldChrZXkpID09PSB0YXNrQm94LnRhc2spIHtcbiAgICAgICAgc3RlcExvY2tzLmRlbGV0ZShrZXkpO1xuICAgICAgfVxuICAgIH1cbiAgfSkoKTtcbiAgdGFza0JveC50YXNrID0gdGFzaztcbiAgc3RlcExvY2tzLnNldChrZXksIHRhc2spO1xuICByZXR1cm4gdGFzaztcbn1cblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gZGVsZXRlIGFsbCB3YWl0cyBhc3NvY2lhdGVkIHdpdGggYSB3b3JrZmxvdyBydW4uXG4gKiBDYWxsZWQgd2hlbiBhIHJ1biByZWFjaGVzIGEgdGVybWluYWwgc3RhdGUuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUFsbFdhaXRzRm9yUnVuKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB3YWl0c0RpciA9IHBhdGguam9pbihiYXNlZGlyLCAnd2FpdHMnKTtcbiAgY29uc3QgZmlsZXMgPSBhd2FpdCBsaXN0SlNPTkZpbGVzKHdhaXRzRGlyKTtcblxuICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAvLyBmaWxlSWRzIG1heSBjb250YWluIHRhZyBzdWZmaXhlcyAoZS5nLiwgXCJ3cnVuX0FCQy1jb3JySWQudml0ZXN0LTBcIilcbiAgICAvLyBidXQgc3RhcnRzV2l0aCBzdGlsbCBtYXRjaGVzIGNvcnJlY3RseSBzaW5jZSB0aGUgdGFnIGlzIGEgc3VmZml4LlxuICAgIGlmIChmaWxlLnN0YXJ0c1dpdGgoYCR7cnVuSWR9LWApKSB7XG4gICAgICBjb25zdCB3YWl0UGF0aCA9IHBhdGguam9pbih3YWl0c0RpciwgYCR7ZmlsZX0uanNvbmApO1xuICAgICAgYXdhaXQgZGVsZXRlSlNPTih3YWl0UGF0aCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogUGVyc2lzdCBhIGxpZmVjeWNsZS1kcml2ZW4gcnVuIHVwZGF0ZSAocnVuX3N0YXJ0ZWQgLyBydW5fY29tcGxldGVkIC9cbiAqIHJ1bl9mYWlsZWQgLyBydW5fY2FuY2VsbGVkKSB1bmRlciB0aGUgc2hhcmVkIHBlci1ydW4gZmlsZSBsb2NrLFxuICogcmUtcmVhZGluZyB0aGUgb24tZGlzayBydW4gaW5zaWRlIHRoZSBsb2NrIHNvIGFueSBhdHRyaWJ1dGUgd3JpdGVzXG4gKiB0aGF0IGxhbmRlZCBiZXR3ZWVuIHRoZSBwcmUtdmFsaWRhdGlvbiBgY3VycmVudFJ1bmAgcmVhZCBhbmQgdGhpc1xuICogd3JpdGUgYXJlIHByZXNlcnZlZC4gV2l0aG91dCB0aGUgcmUtcmVhZCwgYW4gYGV4cGVyaW1lbnRhbFNldEF0dHJpYnV0ZXNgXG4gKiBjYWxsIHNhbmR3aWNoZWQgYmV0d2VlbiB0aGUgbGlmZWN5Y2xlIHJlYWQgYW5kIHdyaXRlIHdvdWxkIGJlXG4gKiBzaWxlbnRseSBvdmVyd3JpdHRlbiBieSB0aGUgbGlmZWN5Y2xlIHdyaXRlJ3Mgc3RhbGUgYXR0cmlidXRlIHNuYXBzaG90LlxuICpcbiAqIGBwcm9wb3NlZGAgaXMgdGhlIGZ1bGx5LWNvbnN0cnVjdGVkIHJ1biByb3cgdGhlIGNhbGxlciB3YW50cyB0b1xuICogd3JpdGUgKHdpdGggdGhlIGNvcnJlY3QgZGlzY3JpbWluYXRlZC11bmlvbiBzdGF0dXMgYnJhbmNoKS4gT25seSB0aGVcbiAqIGBhdHRyaWJ1dGVzYCBmaWVsZCBpcyByZXBsYWNlZCB3aXRoIHRoZSBmcmVzaGVzdCB2ZXJzaW9uIGluc2lkZSB0aGVcbiAqIGxvY2suXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHdyaXRlUnVuVW5kZXJMaWZlY3ljbGVMb2NrPFQgZXh0ZW5kcyBXb3JrZmxvd1J1bj4oXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZyxcbiAgdGFnOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHByb3Bvc2VkOiBUXG4pOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIHdpdGhSdW5GaWxlTG9jayhydW5JZCwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGZyZXNoID0gYXdhaXQgcmVhZEpTT04oXG4gICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgcnVuSWQsIHRhZyksXG4gICAgICBXb3JrZmxvd1J1blNjaGVtYVxuICAgICk7XG4gICAgY29uc3QgbmV4dDogVCA9IHtcbiAgICAgIC4uLnByb3Bvc2VkLFxuICAgICAgYXR0cmlidXRlczogZnJlc2g/LmF0dHJpYnV0ZXMgPz8gcHJvcG9zZWQuYXR0cmlidXRlcyxcbiAgICB9O1xuICAgIGF3YWl0IHdyaXRlSlNPTih0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgcnVuSWQsIHRhZyksIG5leHQsIHtcbiAgICAgIG92ZXJ3cml0ZTogdHJ1ZSxcbiAgICB9KTtcbiAgICByZXR1cm4gbmV4dDtcbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgZXZlbnRzIHN0b3JhZ2UgaW1wbGVtZW50YXRpb24gdXNpbmcgdGhlIGZpbGVzeXN0ZW0uXG4gKiBJbXBsZW1lbnRzIHRoZSBTdG9yYWdlWydldmVudHMnXSBpbnRlcmZhY2Ugd2l0aCBjcmVhdGUsIGxpc3QsIGFuZCBsaXN0QnlDb3JyZWxhdGlvbklkIG9wZXJhdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFdmVudHNTdG9yYWdlKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHRhZz86IHN0cmluZ1xuKTogU3RvcmFnZVsnZXZlbnRzJ10ge1xuICByZXR1cm4ge1xuICAgIGFzeW5jIGNyZWF0ZShydW5JZCwgZGF0YSwgcGFyYW1zKTogUHJvbWlzZTxFdmVudFJlc3VsdD4ge1xuICAgICAgLy8gVmFsaWRhdGUgcmVxdWVzdC1zdXBwbGllZCBJRHMgYmVmb3JlIHRoZXkncmUgY29uY2F0ZW5hdGVkIGludG9cbiAgICAgIC8vIGZpbGVzeXN0ZW0gcGF0aHMuIFRoaXMgaXMgdGhlIHByaW1hcnkgZGVmZW5zZSBhZ2FpbnN0IHBhdGggdHJhdmVyc2FsXG4gICAgICAvLyBhdHRhY2tzIHdoZXJlIGEgY2xpZW50IHN1cHBsaWVzIHJ1bklkIC8gY29ycmVsYXRpb25JZCB2YWx1ZXMgbGlrZVxuICAgICAgLy8gXCIuLi8uLi8uLi9wYWNrYWdlXCIgdG8gcmVhZCBvciB3cml0ZSBmaWxlcyBvdXRzaWRlIHRoZSBzdG9yYWdlIHJvb3QuXG4gICAgICAvLyBSdW4gYmVmb3JlIHRha2luZyB0aGUgcGVyLXN0ZXAgbXV0ZXggc28gbWFsZm9ybWVkIGlucHV0cyBmYWlsIGZhc3QuXG4gICAgICAvL1xuICAgICAgLy8gRW1wdHkgYGNvcnJlbGF0aW9uSWRgIHZhbHVlcyBhcmUgYWxzbyByZWplY3RlZCBoZXJlOiB0aGUgZXZlbnRcbiAgICAgIC8vIHNjaGVtYXMgb25seSByZXF1aXJlIGB6LnN0cmluZygpYCwgc28gd2l0aG91dCB0aGlzIGNoZWNrIGFcbiAgICAgIC8vIHN0ZXBfY3JlYXRlZCAvIGhvb2tfY3JlYXRlZCAvIHdhaXRfY3JlYXRlZCByZXF1ZXN0IHdpdGhcbiAgICAgIC8vIGBjb3JyZWxhdGlvbklkOiAnJ2Agd291bGQgc2lsZW50bHkgYmUgd3JpdHRlbiB1bmRlciBhIG1hbGZvcm1lZFxuICAgICAgLy8gY29tcG9zaXRlIGtleSBsaWtlIGAke3J1bklkfS1gLlxuICAgICAgaWYgKHJ1bklkICE9IG51bGwgJiYgcnVuSWQgIT09ICcnKSB7XG4gICAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgncnVuSWQnLCBydW5JZCk7XG4gICAgICB9XG4gICAgICBpZiAoJ2NvcnJlbGF0aW9uSWQnIGluIGRhdGEgJiYgdHlwZW9mIGRhdGEuY29ycmVsYXRpb25JZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdjb3JyZWxhdGlvbklkJywgZGF0YS5jb3JyZWxhdGlvbklkKTtcbiAgICAgIH1cblxuICAgICAgLy8gU3RlcCBsaWZlY3ljbGUgZXZlbnRzIGFyZSBzZXJpYWxpemVkIHBlci1zdGVwIHZpYSBhbiBpbi1wcm9jZXNzIG11dGV4XG4gICAgICAvLyBzbyB0aGF0IHRoZSBcImNoZWNrIHN0YXRlLCB0aGVuIHdyaXRlXCIgc2VxdWVuY2UgaW4gc3RlcF9zdGFydGVkIC9cbiAgICAgIC8vIHN0ZXBfY29tcGxldGVkIC8gc3RlcF9mYWlsZWQgLyBzdGVwX3JldHJ5aW5nIGlzIGF0b21pYy4gc3RlcF9jcmVhdGVkXG4gICAgICAvLyBpcyBhbHNvIHNlcmlhbGl6ZWQgc28gZHVwbGljYXRlLWNyZWF0ZSByYWNlcyBkb24ndCBsZWF2ZSBleHRyYVxuICAgICAgLy8gc3RlcF9jcmVhdGVkIGV2ZW50cyBpbiB0aGUgbG9nLlxuICAgICAgY29uc3QgaXNTdGVwRXZlbnQgPVxuICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfY3JlYXRlZCcgfHxcbiAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX3N0YXJ0ZWQnIHx8XG4gICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9jb21wbGV0ZWQnIHx8XG4gICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9mYWlsZWQnIHx8XG4gICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9yZXRyeWluZyc7XG4gICAgICBpZiAoaXNTdGVwRXZlbnQgJiYgcnVuSWQgJiYgZGF0YS5jb3JyZWxhdGlvbklkKSB7XG4gICAgICAgIGNvbnN0IGxvY2tLZXkgPSB0YWdcbiAgICAgICAgICA/IGAke3J1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH0uJHt0YWd9YFxuICAgICAgICAgIDogYCR7cnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgIHJldHVybiB3aXRoU3RlcExvY2sobG9ja0tleSwgKCkgPT4gY3JlYXRlSW1wbCgpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjcmVhdGVJbXBsKCk7XG5cbiAgICAgIGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUltcGwoKTogUHJvbWlzZTxFdmVudFJlc3VsdD4ge1xuICAgICAgICBjb25zdCBldmVudElkID0gYGV2bnRfJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcblxuICAgICAgICAvLyBGb3IgcnVuX2NyZWF0ZWQgZXZlbnRzLCB1c2UgY2xpZW50LXByb3ZpZGVkIHJ1bklkIG9yIGdlbmVyYXRlIG9uZSBzZXJ2ZXItc2lkZVxuICAgICAgICBsZXQgZWZmZWN0aXZlUnVuSWQ6IHN0cmluZztcbiAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NyZWF0ZWQnICYmICghcnVuSWQgfHwgcnVuSWQgPT09ICcnKSkge1xuICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkID0gYHdydW5fJHttb25vdG9uaWNVbGlkKCl9YDtcbiAgICAgICAgfSBlbHNlIGlmICghcnVuSWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3J1bklkIGlzIHJlcXVpcmVkIGZvciBub24tcnVuX2NyZWF0ZWQgZXZlbnRzJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZWZmZWN0aXZlUnVuSWQgPSBydW5JZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFZhbGlkYXRlIGNsaWVudC1wcm92aWRlZCBydW5JZCB0aW1lc3RhbXAgaXMgd2l0aGluIGFjY2VwdGFibGUgdGhyZXNob2xkXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jcmVhdGVkJyAmJiBydW5JZCAmJiBydW5JZCAhPT0gJycpIHtcbiAgICAgICAgICBjb25zdCB2YWxpZGF0aW9uRXJyb3IgPSB2YWxpZGF0ZVVsaWRUaW1lc3RhbXAoXG4gICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICd3cnVuXydcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICh2YWxpZGF0aW9uRXJyb3IpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBXb3JrZmxvd1dvcmxkRXJyb3IodmFsaWRhdGlvbkVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzcGVjVmVyc2lvbiBpcyBhbHdheXMgc2VudCBieSB0aGUgcnVudGltZSwgYnV0IHdlIHByb3ZpZGUgYSBmYWxsYmFjayBmb3Igc2FmZXR5XG4gICAgICAgIGNvbnN0IGVmZmVjdGl2ZVNwZWNWZXJzaW9uID0gZGF0YS5zcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVDtcblxuICAgICAgICAvLyBIZWxwZXIgdG8gY2hlY2sgaWYgcnVuIGlzIGluIHRlcm1pbmFsIHN0YXRlXG4gICAgICAgIGNvbnN0IGlzUnVuVGVybWluYWwgPSAoc3RhdHVzOiBzdHJpbmcpID0+XG4gICAgICAgICAgWydjb21wbGV0ZWQnLCAnZmFpbGVkJywgJ2NhbmNlbGxlZCddLmluY2x1ZGVzKHN0YXR1cyk7XG5cbiAgICAgICAgLy8gSGVscGVyIHRvIGNoZWNrIGlmIHN0ZXAgaXMgaW4gdGVybWluYWwgc3RhdGVcbiAgICAgICAgY29uc3QgaXNTdGVwVGVybWluYWwgPSAoc3RhdHVzOiBzdHJpbmcpID0+XG4gICAgICAgICAgWydjb21wbGV0ZWQnLCAnZmFpbGVkJywgJ2NhbmNlbGxlZCddLmluY2x1ZGVzKHN0YXR1cyk7XG5cbiAgICAgICAgLy8gR2V0IGN1cnJlbnQgcnVuIHN0YXRlIGZvciB2YWxpZGF0aW9uIChpZiBub3QgY3JlYXRpbmcgYSBuZXcgcnVuKVxuICAgICAgICAvLyBTa2lwIHJ1biB2YWxpZGF0aW9uIGZvciBzdGVwX2NvbXBsZXRlZCBhbmQgc3RlcF9yZXRyeWluZyAtIHRoZXkgb25seSBvcGVyYXRlXG4gICAgICAgIC8vIG9uIHJ1bm5pbmcgc3RlcHMsIGFuZCBydW5uaW5nIHN0ZXBzIGFyZSBhbHdheXMgYWxsb3dlZCB0byBtb2RpZnkgcmVnYXJkbGVzc1xuICAgICAgICAvLyBvZiBydW4gc3RhdGUuIFRoaXMgb3B0aW1pemF0aW9uIHNhdmVzIGZpbGVzeXN0ZW0gcmVhZHMgcGVyIHN0ZXAgZXZlbnQuXG4gICAgICAgIGxldCBjdXJyZW50UnVuOiBXb3JrZmxvd1J1biB8IG51bGwgPSBudWxsO1xuICAgICAgICBjb25zdCBza2lwUnVuVmFsaWRhdGlvbkV2ZW50cyA9IFsnc3RlcF9jb21wbGV0ZWQnLCAnc3RlcF9yZXRyeWluZyddO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgZGF0YS5ldmVudFR5cGUgIT09ICdydW5fY3JlYXRlZCcgJiZcbiAgICAgICAgICAhc2tpcFJ1blZhbGlkYXRpb25FdmVudHMuaW5jbHVkZXMoZGF0YS5ldmVudFR5cGUpXG4gICAgICAgICkge1xuICAgICAgICAgIGN1cnJlbnRSdW4gPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAncnVucycsXG4gICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIFdvcmtmbG93UnVuU2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIFJlc2lsaWVudCBzdGFydDogcnVuX3N0YXJ0ZWQgb24gbm9uLWV4aXN0ZW50IHJ1biB3aXRoIGV2ZW50RGF0YVxuICAgICAgICAgIC8vIGNyZWF0ZXMgdGhlIHJ1biBmaXJzdCwgc28gdGhlIHF1ZXVlIGNhbiBib290c3RyYXAgYSBydW4gdGhhdFxuICAgICAgICAgIC8vIGZhaWxlZCB0byBjcmVhdGUgZHVyaW5nIHN0YXJ0KCkuXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcgJiZcbiAgICAgICAgICAgICFjdXJyZW50UnVuICYmXG4gICAgICAgICAgICAnZXZlbnREYXRhJyBpbiBkYXRhICYmXG4gICAgICAgICAgICBkYXRhLmV2ZW50RGF0YVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgY29uc3QgcnVuSW5wdXREYXRhID0gZGF0YS5ldmVudERhdGEgYXMge1xuICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ/OiBzdHJpbmc7XG4gICAgICAgICAgICAgIHdvcmtmbG93TmFtZT86IHN0cmluZztcbiAgICAgICAgICAgICAgaW5wdXQ/OiBhbnk7XG4gICAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgcnVuSW5wdXREYXRhLmRlcGxveW1lbnRJZCAmJlxuICAgICAgICAgICAgICBydW5JbnB1dERhdGEud29ya2Zsb3dOYW1lICYmXG4gICAgICAgICAgICAgIHJ1bklucHV0RGF0YS5pbnB1dCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgLy8gQXRvbWljYWxseSB0cnkgdG8gY3JlYXRlIHRoZSBydW4gZW50aXR5LiB3cml0ZUV4Y2x1c2l2ZVxuICAgICAgICAgICAgICAvLyB1c2VzIE9fQ1JFQVR8T19FWENMIHNvIG9ubHkgdGhlIGZpcnN0IHdyaXRlciB3aW5zLFxuICAgICAgICAgICAgICAvLyBwcmV2ZW50aW5nIGEgVE9DVE9VIHJhY2Ugd2hlcmUgYSBjb25jdXJyZW50IHJ1bl9jcmVhdGVkXG4gICAgICAgICAgICAgIC8vIGZyb20gc3RhcnQoKSBjb3VsZCBvdmVyd3JpdGUgYSBydW4gdGhhdCB3YXMgYWxyZWFkeVxuICAgICAgICAgICAgICAvLyB0cmFuc2l0aW9uZWQgdG8gJ3J1bm5pbmcnLlxuICAgICAgICAgICAgICBjb25zdCBjcmVhdGVkUnVuOiBXb3JrZmxvd1J1biA9IHtcbiAgICAgICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgZGVwbG95bWVudElkOiBydW5JbnB1dERhdGEuZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuSW5wdXREYXRhLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogcnVuSW5wdXREYXRhLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgICAgaW5wdXQ6IHJ1bklucHV0RGF0YS5pbnB1dCxcbiAgICAgICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHN0YXJ0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlczoge30sXG4gICAgICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIGNvbnN0IHJ1blBhdGggPSB0YWdnZWRQYXRoKGJhc2VkaXIsICdydW5zJywgZWZmZWN0aXZlUnVuSWQsIHRhZyk7XG4gICAgICAgICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICAgICAgICBydW5QYXRoLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNyZWF0ZWRSdW4sIGpzb25SZXBsYWNlcilcbiAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICBpZiAoY3JlYXRlZCkge1xuICAgICAgICAgICAgICAgIC8vIFdlIGNyZWF0ZWQgdGhlIHJ1biDigJQgYWxzbyB3cml0ZSB0aGUgcnVuX2NyZWF0ZWQgZXZlbnQuXG4gICAgICAgICAgICAgICAgY29uc3QgcnVuQ3JlYXRlZEV2ZW50SWQgPSBgZXZudF8ke21vbm90b25pY1VsaWQoKX1gO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ1bkNyZWF0ZWRFdmVudDogRXZlbnQgPSB7XG4gICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fY3JlYXRlZCcsXG4gICAgICAgICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgICBldmVudElkOiBydW5DcmVhdGVkRXZlbnRJZCxcbiAgICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogcnVuSW5wdXREYXRhLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBydW5JbnB1dERhdGEud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICBpbnB1dDogcnVuSW5wdXREYXRhLmlucHV0LFxuICAgICAgICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBydW5JbnB1dERhdGEuZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBjb25zdCBjcmVhdGVkQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7cnVuQ3JlYXRlZEV2ZW50SWR9YDtcbiAgICAgICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdldmVudHMnLCBjcmVhdGVkQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICAgICAgcnVuQ3JlYXRlZEV2ZW50XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjdXJyZW50UnVuID0gY3JlYXRlZFJ1bjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBSdW4gYWxyZWFkeSBleGlzdHMgKGNvbmN1cnJlbnQgcnVuX2NyZWF0ZWQgd29uIHRoZVxuICAgICAgICAgICAgICAgIC8vIHJhY2UpLiBSZS1yZWFkIGl0IHNvIGRvd25zdHJlYW0gbG9naWMgc2VlcyB0aGUgcmVhbCBzdGF0ZS5cbiAgICAgICAgICAgICAgICBjdXJyZW50UnVuID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgICAgICAgJ3J1bnMnLFxuICAgICAgICAgICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgICAgICBXb3JrZmxvd1J1blNjaGVtYSxcbiAgICAgICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBydW5fZmFpbGVkIG9uIGEgbm9uLWV4aXN0ZW50IHJ1biBpcyByZWplY3RlZCB0byBtYXRjaCB0aGVcbiAgICAgICAgLy8gcG9zdGdyZXMgYW5kIHZlcmNlbCB3b3JsZHMsIHdoaWNoIGJvdGggc3VyZmFjZSB0aGlzIGFzIGFcbiAgICAgICAgLy8gV29ya2Zsb3dSdW5Ob3RGb3VuZEVycm9yIHJhdGhlciB0aGFuIHNpbGVudGx5IHBlcnNpc3RpbmcgYW5cbiAgICAgICAgLy8gZXZlbnQgZm9yIGEgcnVuIHRoYXQgd2FzIG5ldmVyIGNyZWF0ZWQuXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9mYWlsZWQnICYmICFjdXJyZW50UnVuKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93UnVuTm90Rm91bmRFcnJvcihlZmZlY3RpdmVSdW5JZCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAgICAgLy8gVkVSU0lPTiBDT01QQVRJQklMSVRZOiBDaGVjayBydW4gc3BlYyB2ZXJzaW9uXG4gICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgICAgICAvLyBGb3IgZXZlbnRzIHRoYXQgaGF2ZSBmZXRjaGVkIHRoZSBydW4sIGNoZWNrIHZlcnNpb24gY29tcGF0aWJpbGl0eS5cbiAgICAgICAgLy8gU2tpcCBmb3IgcnVuX2NyZWF0ZWQgKG5vIGV4aXN0aW5nIHJ1bikgYW5kIHJ1bnRpbWUgZXZlbnRzIChzdGVwX2NvbXBsZXRlZCwgc3RlcF9yZXRyeWluZykuXG4gICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgcnVuIHJlcXVpcmVzIGEgbmV3ZXIgd29ybGQgdmVyc2lvblxuICAgICAgICAgIGlmIChyZXF1aXJlc05ld2VyV29ybGQoY3VycmVudFJ1bi5zcGVjVmVyc2lvbikpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBSdW5Ob3RTdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICAgICAgY3VycmVudFJ1bi5zcGVjVmVyc2lvbiEsXG4gICAgICAgICAgICAgIFNQRUNfVkVSU0lPTl9DVVJSRU5UXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFJvdXRlIHRvIGxlZ2FjeSBoYW5kbGVyIGZvciBwcmUtZXZlbnQtc291cmNpbmcgcnVuc1xuICAgICAgICAgIGlmIChpc0xlZ2FjeVNwZWNWZXJzaW9uKGN1cnJlbnRSdW4uc3BlY1ZlcnNpb24pKSB7XG4gICAgICAgICAgICByZXR1cm4gaGFuZGxlTGVnYWN5RXZlbnQoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgICBjdXJyZW50UnVuLFxuICAgICAgICAgICAgICBwYXJhbXNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgICAgIC8vIFZBTElEQVRJT046IFRlcm1pbmFsIHN0YXRlIGFuZCBldmVudCBvcmRlcmluZyBjaGVja3NcbiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgICAgICAgLy8gUnVuIHRlcm1pbmFsIHN0YXRlIHZhbGlkYXRpb25cbiAgICAgICAgaWYgKGN1cnJlbnRSdW4gJiYgaXNSdW5UZXJtaW5hbChjdXJyZW50UnVuLnN0YXR1cykpIHtcbiAgICAgICAgICBjb25zdCBydW5UZXJtaW5hbEV2ZW50cyA9IFtcbiAgICAgICAgICAgICdydW5fc3RhcnRlZCcsXG4gICAgICAgICAgICAncnVuX2NvbXBsZXRlZCcsXG4gICAgICAgICAgICAncnVuX2ZhaWxlZCcsXG4gICAgICAgICAgXTtcblxuICAgICAgICAgIC8vIElkZW1wb3RlbnQgb3BlcmF0aW9uOiBydW5fY2FuY2VsbGVkIG9uIGFscmVhZHkgY2FuY2VsbGVkIHJ1biBpcyBhbGxvd2VkXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdydW5fY2FuY2VsbGVkJyAmJlxuICAgICAgICAgICAgY3VycmVudFJ1bi5zdGF0dXMgPT09ICdjYW5jZWxsZWQnXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBSZXR1cm4gZXhpc3Rpbmcgc3RhdGUgKGlkZW1wb3RlbnQpXG4gICAgICAgICAgICBjb25zdCBldmVudDogRXZlbnQgPSB7XG4gICAgICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBjb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtldmVudElkfWA7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2V2ZW50cycsIGNvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgICAgZXZlbnRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCByZXNvbHZlRGF0YSA9XG4gICAgICAgICAgICAgIHBhcmFtcz8ucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgZXZlbnQ6IHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpLFxuICAgICAgICAgICAgICBydW46IGN1cnJlbnRSdW4sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEZvciBydW5fc3RhcnRlZCBvbiB0ZXJtaW5hbCBydW5zLCB1c2UgUnVuRXhwaXJlZEVycm9yIHNvIHRoZVxuICAgICAgICAgIC8vIHJ1bnRpbWUga25vd3MgdG8gZXhpdCB3aXRob3V0IHJldHJ5aW5nLlxuICAgICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bkV4cGlyZWRFcnJvcihcbiAgICAgICAgICAgICAgYFdvcmtmbG93IHJ1biBcIiR7ZWZmZWN0aXZlUnVuSWR9XCIgaXMgYWxyZWFkeSBpbiB0ZXJtaW5hbCBzdGF0ZSBcIiR7Y3VycmVudFJ1bi5zdGF0dXN9XCJgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIE90aGVyIHJ1biBzdGF0ZSB0cmFuc2l0aW9ucyBhcmUgbm90IGFsbG93ZWQgb24gdGVybWluYWwgcnVuc1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHJ1blRlcm1pbmFsRXZlbnRzLmluY2x1ZGVzKGRhdGEuZXZlbnRUeXBlKSB8fFxuICAgICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdydW5fY2FuY2VsbGVkJ1xuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBDYW5ub3QgdHJhbnNpdGlvbiBydW4gZnJvbSB0ZXJtaW5hbCBzdGF0ZSBcIiR7Y3VycmVudFJ1bi5zdGF0dXN9XCJgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENyZWF0aW5nIG5ldyBlbnRpdGllcyBvbiB0ZXJtaW5hbCBydW5zIGlzIG5vdCBhbGxvd2VkXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX2NyZWF0ZWQnIHx8XG4gICAgICAgICAgICBkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfY3JlYXRlZCcgfHxcbiAgICAgICAgICAgIGRhdGEuZXZlbnRUeXBlID09PSAnd2FpdF9jcmVhdGVkJ1xuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBDYW5ub3QgY3JlYXRlIG5ldyBlbnRpdGllcyBvbiBydW4gaW4gdGVybWluYWwgc3RhdGUgXCIke2N1cnJlbnRSdW4uc3RhdHVzfVwiYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGVwLXJlbGF0ZWQgZXZlbnQgdmFsaWRhdGlvbiAob3JkZXJpbmcgYW5kIHRlcm1pbmFsIHN0YXRlKVxuICAgICAgICAvLyBTdG9yZSBleGlzdGluZ1N0ZXAgc28gd2UgY2FuIHJldXNlIGl0IGxhdGVyIChhdm9pZCBkb3VibGUgcmVhZClcbiAgICAgICAgbGV0IHZhbGlkYXRlZFN0ZXA6IFN0ZXAgfCBudWxsID0gbnVsbDtcbiAgICAgICAgY29uc3Qgc3RlcEV2ZW50cyA9IFtcbiAgICAgICAgICAnc3RlcF9zdGFydGVkJyxcbiAgICAgICAgICAnc3RlcF9jb21wbGV0ZWQnLFxuICAgICAgICAgICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgJ3N0ZXBfcmV0cnlpbmcnLFxuICAgICAgICBdO1xuICAgICAgICBpZiAoc3RlcEV2ZW50cy5pbmNsdWRlcyhkYXRhLmV2ZW50VHlwZSkgJiYgZGF0YS5jb3JyZWxhdGlvbklkKSB7XG4gICAgICAgICAgY29uc3Qgc3RlcENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICAgIHZhbGlkYXRlZFN0ZXAgPSBhd2FpdCByZWFkSlNPTldpdGhGYWxsYmFjayhcbiAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAnc3RlcHMnLFxuICAgICAgICAgICAgc3RlcENvbXBvc2l0ZUtleSxcbiAgICAgICAgICAgIFN0ZXBTY2hlbWEsXG4gICAgICAgICAgICB0YWdcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gRXZlbnQgb3JkZXJpbmc6IHN0ZXAgbXVzdCBleGlzdCBiZWZvcmUgdGhlc2UgZXZlbnRzXG4gICAgICAgICAgaWYgKCF2YWxpZGF0ZWRTdGVwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dXb3JsZEVycm9yKFxuICAgICAgICAgICAgICBgU3RlcCBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIG5vdCBmb3VuZGBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gU3RlcCB0ZXJtaW5hbCBzdGF0ZSB2YWxpZGF0aW9uXG4gICAgICAgICAgaWYgKGlzU3RlcFRlcm1pbmFsKHZhbGlkYXRlZFN0ZXAuc3RhdHVzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBDYW5ub3QgbW9kaWZ5IHN0ZXAgaW4gdGVybWluYWwgc3RhdGUgXCIke3ZhbGlkYXRlZFN0ZXAuc3RhdHVzfVwiYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBPbiB0ZXJtaW5hbCBydW5zOiBvbmx5IGFsbG93IGNvbXBsZXRpbmcvZmFpbGluZyBpbi1wcm9ncmVzcyBzdGVwc1xuICAgICAgICAgIGlmIChjdXJyZW50UnVuICYmIGlzUnVuVGVybWluYWwoY3VycmVudFJ1bi5zdGF0dXMpKSB7XG4gICAgICAgICAgICBpZiAodmFsaWRhdGVkU3RlcC5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgUnVuRXhwaXJlZEVycm9yKFxuICAgICAgICAgICAgICAgIGBDYW5ub3QgbW9kaWZ5IG5vbi1ydW5uaW5nIHN0ZXAgb24gcnVuIGluIHRlcm1pbmFsIHN0YXRlIFwiJHtjdXJyZW50UnVuLnN0YXR1c31cImBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBIb29rLXJlbGF0ZWQgZXZlbnQgdmFsaWRhdGlvbiAob3JkZXJpbmcpXG4gICAgICAgIGNvbnN0IGhvb2tFdmVudHNSZXF1aXJpbmdFeGlzdGVuY2UgPSBbJ2hvb2tfZGlzcG9zZWQnLCAnaG9va19yZWNlaXZlZCddO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgaG9va0V2ZW50c1JlcXVpcmluZ0V4aXN0ZW5jZS5pbmNsdWRlcyhkYXRhLmV2ZW50VHlwZSkgJiZcbiAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWRcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdIb29rID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJ2hvb2tzJyxcbiAgICAgICAgICAgIGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIEhvb2tTY2hlbWEsXG4gICAgICAgICAgICB0YWdcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKCFleGlzdGluZ0hvb2spIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBIb29rTm90Rm91bmRFcnJvcihkYXRhLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zdCBldmVudDogRXZlbnQgPSB7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgZXZlbnRJZCxcbiAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgIH07XG4gICAgICAgIC8vIFN0cmlwIGV2ZW50RGF0YSBmcm9tIHJ1bl9zdGFydGVkIOKAlCBpdCBiZWxvbmdzIG9uIHJ1bl9jcmVhdGVkIG9ubHkuXG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJyAmJiAnZXZlbnREYXRhJyBpbiBldmVudCkge1xuICAgICAgICAgIGRlbGV0ZSAoZXZlbnQgYXMgYW55KS5ldmVudERhdGE7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUcmFjayBlbnRpdHkgY3JlYXRlZC91cGRhdGVkIGZvciBFdmVudFJlc3VsdFxuICAgICAgICBsZXQgcnVuOiBXb3JrZmxvd1J1biB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHN0ZXA6IFN0ZXAgfCB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBob29rOiBIb29rIHwgdW5kZWZpbmVkO1xuICAgICAgICBsZXQgd2FpdDogV2FpdCB8IHVuZGVmaW5lZDtcblxuICAgICAgICAvLyBDcmVhdGUvdXBkYXRlIGVudGl0eSBiYXNlZCBvbiBldmVudCB0eXBlIChldmVudC1zb3VyY2VkIGFyY2hpdGVjdHVyZSlcbiAgICAgICAgLy8gUnVuIGxpZmVjeWNsZSBldmVudHNcbiAgICAgICAgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NyZWF0ZWQnICYmICdldmVudERhdGEnIGluIGRhdGEpIHtcbiAgICAgICAgICBjb25zdCBydW5EYXRhID0gZGF0YS5ldmVudERhdGEgYXMge1xuICAgICAgICAgICAgZGVwbG95bWVudElkOiBzdHJpbmc7XG4gICAgICAgICAgICB3b3JrZmxvd05hbWU6IHN0cmluZztcbiAgICAgICAgICAgIGlucHV0OiBTZXJpYWxpemVkRGF0YTtcbiAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgICAgICAgIH07XG4gICAgICAgICAgcnVuID0ge1xuICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgZGVwbG95bWVudElkOiBydW5EYXRhLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBydW5EYXRhLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIC8vIFByb3BhZ2F0ZSBzcGVjVmVyc2lvbiBmcm9tIHRoZSBldmVudCB0byB0aGUgcnVuIGVudGl0eVxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogcnVuRGF0YS5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgaW5wdXQ6IHJ1bkRhdGEuaW5wdXQsXG4gICAgICAgICAgICBvdXRwdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBzdGFydGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBhdHRyaWJ1dGVzOiB7fSxcbiAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgfTtcbiAgICAgICAgICAvLyBVc2Ugd3JpdGVFeGNsdXNpdmUgKE9fQ1JFQVR8T19FWENMKSB0byBhdG9taWNhbGx5IGNyZWF0ZSB0aGVcbiAgICAgICAgICAvLyBydW4gZW50aXR5IGZpbGUuIFRoaXMgcHJldmVudHMgYSBUT0NUT1UgcmFjZSB3aXRoIHRoZSByZXNpbGllbnRcbiAgICAgICAgICAvLyBzdGFydCBwYXRoIChydW5fc3RhcnRlZCBvbiBub24tZXhpc3RlbnQgcnVuKSB0aGF0IGNvdWxkIHJlc3VsdFxuICAgICAgICAgIC8vIGluIGR1cGxpY2F0ZSBydW5fY3JlYXRlZCBldmVudHMgaW4gdGhlIGV2ZW50IGxvZy5cbiAgICAgICAgICBjb25zdCBydW5QYXRoID0gdGFnZ2VkUGF0aChiYXNlZGlyLCAncnVucycsIGVmZmVjdGl2ZVJ1bklkLCB0YWcpO1xuICAgICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZShcbiAgICAgICAgICAgIHJ1blBhdGgsXG4gICAgICAgICAgICBKU09OLnN0cmluZ2lmeShydW4sIGpzb25SZXBsYWNlciwgMilcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICghY3JlYXRlZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBXb3JrZmxvdyBydW4gXCIke2VmZmVjdGl2ZVJ1bklkfVwiIGFscmVhZHkgZXhpc3RzYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcpIHtcbiAgICAgICAgICAvLyBSZXVzZSBjdXJyZW50UnVuIGZyb20gdmFsaWRhdGlvbiAoYWxyZWFkeSByZWFkIGFib3ZlKVxuICAgICAgICAgIGlmIChjdXJyZW50UnVuKSB7XG4gICAgICAgICAgICAvLyBJZiBhbHJlYWR5IHJ1bm5pbmcsIHJldHVybiB0aGUgcnVuIHdpdGhvdXQgaW5zZXJ0aW5nIGFcbiAgICAgICAgICAgIC8vIGR1cGxpY2F0ZSBldmVudC4gIFRoaXMgbWFrZXMgcnVuX3N0YXJ0ZWQgaWRlbXBvdGVudCBmb3JcbiAgICAgICAgICAgIC8vIGNvbmN1cnJlbnQgaW52b2NhdGlvbnMuICBXZSBvbWl0IHByZWxvYWRlZCBldmVudHMgaGVyZVxuICAgICAgICAgICAgLy8gYmVjYXVzZSB0aGlzIGlzIGEgcmFyZSByYWNlLWNvbmRpdGlvbiBwYXRoIOKAlCB0aGUgcnVudGltZVxuICAgICAgICAgICAgLy8gZmFsbHMgYmFjayB0byBsb2FkV29ya2Zsb3dSdW5FdmVudHMoKS5cbiAgICAgICAgICAgIGlmIChjdXJyZW50UnVuLnN0YXR1cyA9PT0gJ3J1bm5pbmcnKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7IHJ1bjogY3VycmVudFJ1biB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBydW4gPSBhd2FpdCB3cml0ZVJ1blVuZGVyTGlmZWN5Y2xlTG9jayhcbiAgICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICAgZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICAgIHRhZyxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHJ1bklkOiBjdXJyZW50UnVuLnJ1bklkLFxuICAgICAgICAgICAgICAgIGRlcGxveW1lbnRJZDogY3VycmVudFJ1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBjdXJyZW50UnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogY3VycmVudFJ1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgICBleGVjdXRpb25Db250ZXh0OiBjdXJyZW50UnVuLmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgICAgaW5wdXQ6IGN1cnJlbnRSdW4uaW5wdXQsXG4gICAgICAgICAgICAgICAgY3JlYXRlZEF0OiBjdXJyZW50UnVuLmNyZWF0ZWRBdCxcbiAgICAgICAgICAgICAgICBleHBpcmVkQXQ6IGN1cnJlbnRSdW4uZXhwaXJlZEF0LFxuICAgICAgICAgICAgICAgIHN0YXR1czogJ3J1bm5pbmcnLFxuICAgICAgICAgICAgICAgIG91dHB1dDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzdGFydGVkQXQ6IGN1cnJlbnRSdW4uc3RhcnRlZEF0ID8/IG5vdyxcbiAgICAgICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzOiBjdXJyZW50UnVuLmF0dHJpYnV0ZXMsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAncnVuX2NvbXBsZXRlZCcgJiYgJ2V2ZW50RGF0YScgaW4gZGF0YSkge1xuICAgICAgICAgIGNvbnN0IGNvbXBsZXRlZERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7IG91dHB1dD86IGFueSB9O1xuICAgICAgICAgIC8vIFJldXNlIGN1cnJlbnRSdW4gZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHtcbiAgICAgICAgICAgIHJ1biA9IGF3YWl0IHdyaXRlUnVuVW5kZXJMaWZlY3ljbGVMb2NrKFxuICAgICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgICBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgICAgdGFnLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcnVuSWQ6IGN1cnJlbnRSdW4ucnVuSWQsXG4gICAgICAgICAgICAgICAgZGVwbG95bWVudElkOiBjdXJyZW50UnVuLmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICB3b3JrZmxvd05hbWU6IGN1cnJlbnRSdW4ud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBjdXJyZW50UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ6IGN1cnJlbnRSdW4uZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgICAgICBpbnB1dDogY3VycmVudFJ1bi5pbnB1dCxcbiAgICAgICAgICAgICAgICBjcmVhdGVkQXQ6IGN1cnJlbnRSdW4uY3JlYXRlZEF0LFxuICAgICAgICAgICAgICAgIGV4cGlyZWRBdDogY3VycmVudFJ1bi5leHBpcmVkQXQsXG4gICAgICAgICAgICAgICAgc3RhcnRlZEF0OiBjdXJyZW50UnVuLnN0YXJ0ZWRBdCxcbiAgICAgICAgICAgICAgICBzdGF0dXM6ICdjb21wbGV0ZWQnLFxuICAgICAgICAgICAgICAgIG91dHB1dDogY29tcGxldGVkRGF0YS5vdXRwdXQsXG4gICAgICAgICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM6IGN1cnJlbnRSdW4uYXR0cmlidXRlcyxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdydW5fZmFpbGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgY29uc3QgZmFpbGVkRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIGVycm9yOiB1bmtub3duO1xuICAgICAgICAgICAgZXJyb3JDb2RlPzogc3RyaW5nO1xuICAgICAgICAgIH07XG4gICAgICAgICAgLy8gUmV1c2UgY3VycmVudFJ1biBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgICBpZiAoY3VycmVudFJ1bikge1xuICAgICAgICAgICAgLy8gVGhlIGVycm9yIGZpZWxkIGlzIFNlcmlhbGl6ZWREYXRhIChVaW50OEFycmF5KSBwcm9kdWNlZCBieVxuICAgICAgICAgICAgLy8gZGVoeWRyYXRlUnVuRXJyb3IuIFdlIHN0b3JlIGl0IHZlcmJhdGltIOKAlCBjb25zdW1lcnMgaHlkcmF0ZSBpdFxuICAgICAgICAgICAgLy8gdmlhIGh5ZHJhdGVSdW5FcnJvciB0byByZWNvbnN0cnVjdCB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlLlxuICAgICAgICAgICAgcnVuID0gYXdhaXQgd3JpdGVSdW5VbmRlckxpZmVjeWNsZUxvY2soXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICB0YWcsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBydW5JZDogY3VycmVudFJ1bi5ydW5JZCxcbiAgICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogY3VycmVudFJ1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGN1cnJlbnRSdW4uc3BlY1ZlcnNpb24sXG4gICAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgICAgIGlucHV0OiBjdXJyZW50UnVuLmlucHV0LFxuICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogY3VycmVudFJ1bi5jcmVhdGVkQXQsXG4gICAgICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgICAgICBzdGFydGVkQXQ6IGN1cnJlbnRSdW4uc3RhcnRlZEF0LFxuICAgICAgICAgICAgICAgIHN0YXR1czogJ2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgZXJyb3I6IGZhaWxlZERhdGEuZXJyb3IgYXMgVWludDhBcnJheSxcbiAgICAgICAgICAgICAgICBlcnJvckNvZGU6IGZhaWxlZERhdGEuZXJyb3JDb2RlLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlczogY3VycmVudFJ1bi5hdHRyaWJ1dGVzLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICBkZWxldGVBbGxIb29rc0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICAgIGRlbGV0ZUFsbFdhaXRzRm9yUnVuKGJhc2VkaXIsIGVmZmVjdGl2ZVJ1bklkKSxcbiAgICAgICAgICAgIF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnKSB7XG4gICAgICAgICAgLy8gUmV1c2UgY3VycmVudFJ1biBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgICBpZiAoY3VycmVudFJ1bikge1xuICAgICAgICAgICAgcnVuID0gYXdhaXQgd3JpdGVSdW5VbmRlckxpZmVjeWNsZUxvY2soXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgIGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICB0YWcsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBydW5JZDogY3VycmVudFJ1bi5ydW5JZCxcbiAgICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IGN1cnJlbnRSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogY3VycmVudFJ1bi53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGN1cnJlbnRSdW4uc3BlY1ZlcnNpb24sXG4gICAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogY3VycmVudFJ1bi5leGVjdXRpb25Db250ZXh0LFxuICAgICAgICAgICAgICAgIGlucHV0OiBjdXJyZW50UnVuLmlucHV0LFxuICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogY3VycmVudFJ1bi5jcmVhdGVkQXQsXG4gICAgICAgICAgICAgICAgZXhwaXJlZEF0OiBjdXJyZW50UnVuLmV4cGlyZWRBdCxcbiAgICAgICAgICAgICAgICBzdGFydGVkQXQ6IGN1cnJlbnRSdW4uc3RhcnRlZEF0LFxuICAgICAgICAgICAgICAgIHN0YXR1czogJ2NhbmNlbGxlZCcsXG4gICAgICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM6IGN1cnJlbnRSdW4uYXR0cmlidXRlcyxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgZGVsZXRlQWxsSG9va3NGb3JSdW4oYmFzZWRpciwgZWZmZWN0aXZlUnVuSWQpLFxuICAgICAgICAgICAgICBkZWxldGVBbGxXYWl0c0ZvclJ1bihiYXNlZGlyLCBlZmZlY3RpdmVSdW5JZCksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgLy8gU3RlcCBsaWZlY3ljbGUgZXZlbnRzXG4gICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX2NyZWF0ZWQnICYmXG4gICAgICAgICAgJ2V2ZW50RGF0YScgaW4gZGF0YVxuICAgICAgICApIHtcbiAgICAgICAgICAvLyBzdGVwX2NyZWF0ZWQ6IENyZWF0ZXMgc3RlcCBlbnRpdHkgd2l0aCBzdGF0dXMgJ3BlbmRpbmcnLCBhdHRlbXB0PTAsIGNyZWF0ZWRBdCBzZXQuXG4gICAgICAgICAgLy8gVHdvIGNvbmN1cnJlbnQgaW52b2NhdGlvbnMgd2l0aCBpZGVudGljYWwgY29ycmVsYXRpb25JZHMgKGUuZy4gdGhlXG4gICAgICAgICAgLy8gc25hcHNob3QgcnVudGltZSdzIGRldGVybWluaXN0aWMgY29ycmVsYXRpb25JZHMgYWNyb3NzIHJlcGxheXMpXG4gICAgICAgICAgLy8gbXVzdCBiZSBkZWR1cGVkIOKAlCBvdGhlcndpc2UgYm90aCB3cml0ZXMgc3VjY2VlZCBhbmQgdGhlIGV2ZW50IGxvZ1xuICAgICAgICAgIC8vIGVuZHMgdXAgd2l0aCBkdXBsaWNhdGUgc3RlcF9jcmVhdGVkIGVudHJpZXMuIFRoZSBvdXRlclxuICAgICAgICAgIC8vIHdpdGhTdGVwTG9jayBtdXRleCBzZXJpYWxpemVzIHdpdGhpbiBhIHNpbmdsZSBwcm9jZXNzOyB0aGlzXG4gICAgICAgICAgLy8gT19DUkVBVHxPX0VYQ0wgY29uc3RyYWludCBmaWxlIGFkZGl0aW9uYWxseSBwcm90ZWN0cyBhZ2FpbnN0XG4gICAgICAgICAgLy8gY3Jvc3MtcHJvY2VzcyByYWNlcyAodHdvIHBucG0gd29ya2VycywgcmVkZWxpdmVyZWQgcXVldWVcbiAgICAgICAgICAvLyBtZXNzYWdlcywgZXRjLikuIFRoZSBsb3NlciB0aHJvd3MgRW50aXR5Q29uZmxpY3RFcnJvciBzbyB0aGVcbiAgICAgICAgICAvLyBydW50aW1lJ3MgZXhpc3RpbmcgY2F0Y2ggcGF0aCBjYW4gc3dhbGxvdyBpdCBhbmQgYXZvaWRcbiAgICAgICAgICAvLyBkb3VibGUtcXVldWluZyB0aGUgc3RlcC5cbiAgICAgICAgICBjb25zdCBzdGVwQ3JlYXRlZExvY2tOYW1lID0gdGFnXG4gICAgICAgICAgICA/IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH0uY3JlYXRlZC4ke3RhZ31gXG4gICAgICAgICAgICA6IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH0uY3JlYXRlZGA7XG4gICAgICAgICAgY29uc3Qgc3RlcENyZWF0ZWRMb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgJ3N0ZXBzJyxcbiAgICAgICAgICAgIHN0ZXBDcmVhdGVkTG9ja05hbWVcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IHN0ZXBDcmVhdGVkQ2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKFxuICAgICAgICAgICAgc3RlcENyZWF0ZWRMb2NrUGF0aCxcbiAgICAgICAgICAgICcnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoIXN0ZXBDcmVhdGVkQ2xhaW1lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBTdGVwIFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCIgYWxyZWFkeSBjcmVhdGVkYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgc3RlcERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICBzdGVwTmFtZTogc3RyaW5nO1xuICAgICAgICAgICAgaW5wdXQ6IGFueTtcbiAgICAgICAgICB9O1xuICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICBzdGVwSWQ6IGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIHN0ZXBOYW1lOiBzdGVwRGF0YS5zdGVwTmFtZSxcbiAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgaW5wdXQ6IHN0ZXBEYXRhLmlucHV0LFxuICAgICAgICAgICAgb3V0cHV0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgYXR0ZW1wdDogMCxcbiAgICAgICAgICAgIHN0YXJ0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgY29tcGxldGVkQXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAvLyBQcm9wYWdhdGUgc3BlY1ZlcnNpb24gZnJvbSB0aGUgZXZlbnQgdG8gdGhlIHN0ZXAgZW50aXR5XG4gICAgICAgICAgICBzcGVjVmVyc2lvbjogZWZmZWN0aXZlU3BlY1ZlcnNpb24sXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnc3RlcHMnLCBzdGVwQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgc3RlcFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICdzdGVwX3N0YXJ0ZWQnKSB7XG4gICAgICAgICAgLy8gc3RlcF9zdGFydGVkOiBJbmNyZW1lbnRzIGF0dGVtcHQsIHNldHMgc3RhdHVzIHRvICdydW5uaW5nJ1xuICAgICAgICAgIC8vIFNldHMgc3RhcnRlZEF0IG9ubHkgb24gdGhlIGZpcnN0IHN0YXJ0IChub3QgdXBkYXRlZCBvbiByZXRyaWVzKVxuICAgICAgICAgIC8vIFJldXNlIHZhbGlkYXRlZFN0ZXAgZnJvbSB2YWxpZGF0aW9uIChhbHJlYWR5IHJlYWQgYWJvdmUpXG4gICAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHJldHJ5QWZ0ZXIgdGltZXN0YW1wIGhhc24ndCBiZWVuIHJlYWNoZWQgeWV0XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIHZhbGlkYXRlZFN0ZXAucmV0cnlBZnRlciAmJlxuICAgICAgICAgICAgICB2YWxpZGF0ZWRTdGVwLnJldHJ5QWZ0ZXIuZ2V0VGltZSgpID4gRGF0ZS5ub3coKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBUb29FYXJseUVycm9yKFxuICAgICAgICAgICAgICAgIGBDYW5ub3Qgc3RhcnQgc3RlcCBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiOiByZXRyeUFmdGVyIHRpbWVzdGFtcCBoYXMgbm90IGJlZW4gcmVhY2hlZCB5ZXRgLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIHJldHJ5QWZ0ZXI6IE1hdGguY2VpbChcbiAgICAgICAgICAgICAgICAgICAgKHZhbGlkYXRlZFN0ZXAucmV0cnlBZnRlci5nZXRUaW1lKCkgLSBEYXRlLm5vdygpKSAvIDEwMDBcbiAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBCZXN0LWVmZm9ydCBndWFyZDogcmUtcmVhZCB0aGUgc3RlcCBlbnRpdHkgdG8gY2hlY2sgaWYgaXRcbiAgICAgICAgICAgIC8vIHJlYWNoZWQgdGVybWluYWwgc3RhdGUgYmV0d2VlbiB0aGUgdmFsaWRhdGlvbiByZWFkIGFuZCBub3cuXG4gICAgICAgICAgICAvLyBUaGlzIG5hcnJvd3MgdGhlIFRPQ1RPVSB3aW5kb3cgYnV0IGRvZXMgbm90IGZ1bGx5IGVsaW1pbmF0ZSBpdFxuICAgICAgICAgICAgLy8gKHRoZSBsb2NhbCB3b3JsZCBpcyBzaW5nbGUtcHJvY2VzcyAvIGRldi1vbmx5OyB0aGUgcG9zdGdyZXNcbiAgICAgICAgICAgIC8vIHdvcmxkIHVzZXMgU1FMLWxldmVsIGF0b21pYyBndWFyZHMgZm9yIHByb2R1Y3Rpb24pLlxuICAgICAgICAgICAgY29uc3Qgc3RlcENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICAgICAgY29uc3QgZnJlc2hTdGVwID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICdzdGVwcycsXG4gICAgICAgICAgICAgIHN0ZXBDb21wb3NpdGVLZXksXG4gICAgICAgICAgICAgIFN0ZXBTY2hlbWEsXG4gICAgICAgICAgICAgIHRhZ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChmcmVzaFN0ZXAgJiYgaXNTdGVwVGVybWluYWwoZnJlc2hTdGVwLnN0YXR1cykpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICAgYENhbm5vdCBtb2RpZnkgc3RlcCBpbiB0ZXJtaW5hbCBzdGF0ZSBcIiR7ZnJlc2hTdGVwLnN0YXR1c31cImBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc3RlcCA9IHtcbiAgICAgICAgICAgICAgLi4udmFsaWRhdGVkU3RlcCxcbiAgICAgICAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgICAgICAgIC8vIE9ubHkgc2V0IHN0YXJ0ZWRBdCBvbiB0aGUgZmlyc3Qgc3RhcnRcbiAgICAgICAgICAgICAgc3RhcnRlZEF0OiB2YWxpZGF0ZWRTdGVwLnN0YXJ0ZWRBdCA/PyBub3csXG4gICAgICAgICAgICAgIC8vIEluY3JlbWVudCBhdHRlbXB0IGNvdW50ZXIgb24gZXZlcnkgc3RhcnRcbiAgICAgICAgICAgICAgYXR0ZW1wdDogdmFsaWRhdGVkU3RlcC5hdHRlbXB0ICsgMSxcbiAgICAgICAgICAgICAgLy8gQ2xlYXIgcmV0cnlBZnRlciBub3cgdGhhdCB0aGUgc3RlcCBoYXMgc3RhcnRlZFxuICAgICAgICAgICAgICByZXRyeUFmdGVyOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnc3RlcHMnLCBzdGVwQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfY29tcGxldGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgLy8gc3RlcF9jb21wbGV0ZWQ6IFRlcm1pbmFsIHN0YXRlIHdpdGggb3V0cHV0XG4gICAgICAgICAgLy8gVXNlcyB3cml0ZUV4Y2x1c2l2ZSBvbiBhIGxvY2sgZmlsZSB0byBhdG9taWNhbGx5IHByZXZlbnQgY29uY3VycmVudFxuICAgICAgICAgIC8vIGludm9jYXRpb25zIGZyb20gYm90aCBjb21wbGV0aW5nIHRoZSBzYW1lIHN0ZXAgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgICBjb25zdCBjb21wbGV0ZWREYXRhID0gZGF0YS5ldmVudERhdGEgYXMgeyByZXN1bHQ6IGFueSB9O1xuICAgICAgICAgIGlmICh2YWxpZGF0ZWRTdGVwKSB7XG4gICAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgICBjb25zdCBsb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgICA/IGAke3N0ZXBDb21wb3NpdGVLZXl9LnRlcm1pbmFsLiR7dGFnfWBcbiAgICAgICAgICAgICAgOiBgJHtzdGVwQ29tcG9zaXRlS2V5fS50ZXJtaW5hbGA7XG4gICAgICAgICAgICBjb25zdCB0ZXJtaW5hbExvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgICAnc3RlcHMnLFxuICAgICAgICAgICAgICBsb2NrTmFtZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IGNsYWltZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZSh0ZXJtaW5hbExvY2tQYXRoLCAnJyk7XG4gICAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICAgJ0Nhbm5vdCBtb2RpZnkgc3RlcCBpbiB0ZXJtaW5hbCBzdGF0ZSdcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICAgIC4uLnZhbGlkYXRlZFN0ZXAsXG4gICAgICAgICAgICAgIHN0YXR1czogJ2NvbXBsZXRlZCcsXG4gICAgICAgICAgICAgIG91dHB1dDogY29tcGxldGVkRGF0YS5yZXN1bHQsXG4gICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiBub3csXG4gICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnc3RlcHMnLCBzdGVwQ29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3N0ZXBfZmFpbGVkJyAmJiAnZXZlbnREYXRhJyBpbiBkYXRhKSB7XG4gICAgICAgICAgLy8gc3RlcF9mYWlsZWQ6IFRlcm1pbmFsIHN0YXRlIHdpdGggZXJyb3JcbiAgICAgICAgICAvLyBVc2VzIHdyaXRlRXhjbHVzaXZlIG9uIGEgbG9jayBmaWxlIHRvIGF0b21pY2FsbHkgcHJldmVudCBjb25jdXJyZW50XG4gICAgICAgICAgLy8gaW52b2NhdGlvbnMgZnJvbSBib3RoIGZhaWxpbmcgdGhlIHNhbWUgc3RlcCAoVE9DVE9VIHJhY2UpLlxuICAgICAgICAgIGNvbnN0IGZhaWxlZERhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICBlcnJvcjogdW5rbm93bjtcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmICh2YWxpZGF0ZWRTdGVwKSB7XG4gICAgICAgICAgICBjb25zdCBzdGVwQ29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgICBjb25zdCBsb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgICA/IGAke3N0ZXBDb21wb3NpdGVLZXl9LnRlcm1pbmFsLiR7dGFnfWBcbiAgICAgICAgICAgICAgOiBgJHtzdGVwQ29tcG9zaXRlS2V5fS50ZXJtaW5hbGA7XG4gICAgICAgICAgICBjb25zdCB0ZXJtaW5hbExvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgICAnc3RlcHMnLFxuICAgICAgICAgICAgICBsb2NrTmFtZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IGNsYWltZWQgPSBhd2FpdCB3cml0ZUV4Y2x1c2l2ZSh0ZXJtaW5hbExvY2tQYXRoLCAnJyk7XG4gICAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgICAgJ0Nhbm5vdCBtb2RpZnkgc3RlcCBpbiB0ZXJtaW5hbCBzdGF0ZSdcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFRoZSBlcnJvciBmaWVsZCBpcyBTZXJpYWxpemVkRGF0YSAoVWludDhBcnJheSkgcHJvZHVjZWQgYnlcbiAgICAgICAgICAgIC8vIGRlaHlkcmF0ZVN0ZXBFcnJvci4gV2Ugc3RvcmUgaXQgdmVyYmF0aW0g4oCUIGNvbnN1bWVycyBoeWRyYXRlIGl0XG4gICAgICAgICAgICAvLyB2aWEgaHlkcmF0ZVN0ZXBFcnJvciB0byByZWNvbnN0cnVjdCB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlLlxuICAgICAgICAgICAgc3RlcCA9IHtcbiAgICAgICAgICAgICAgLi4udmFsaWRhdGVkU3RlcCxcbiAgICAgICAgICAgICAgc3RhdHVzOiAnZmFpbGVkJyxcbiAgICAgICAgICAgICAgZXJyb3I6IGZhaWxlZERhdGEuZXJyb3IgYXMgVWludDhBcnJheSxcbiAgICAgICAgICAgICAgY29tcGxldGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdzdGVwcycsIHN0ZXBDb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICAgIHsgb3ZlcndyaXRlOiB0cnVlIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnRUeXBlID09PSAnc3RlcF9yZXRyeWluZycgJiYgJ2V2ZW50RGF0YScgaW4gZGF0YSkge1xuICAgICAgICAgIC8vIHN0ZXBfcmV0cnlpbmc6IFNldHMgc3RhdHVzIGJhY2sgdG8gJ3BlbmRpbmcnLCByZWNvcmRzIGVycm9yXG4gICAgICAgICAgLy8gUmV1c2UgdmFsaWRhdGVkU3RlcCBmcm9tIHZhbGlkYXRpb24gKGFscmVhZHkgcmVhZCBhYm92ZSlcbiAgICAgICAgICBjb25zdCByZXRyeURhdGEgPSBkYXRhLmV2ZW50RGF0YSBhcyB7XG4gICAgICAgICAgICBlcnJvcjogdW5rbm93bjtcbiAgICAgICAgICAgIHJldHJ5QWZ0ZXI/OiBEYXRlO1xuICAgICAgICAgIH07XG4gICAgICAgICAgaWYgKHZhbGlkYXRlZFN0ZXApIHtcbiAgICAgICAgICAgIGNvbnN0IHN0ZXBDb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtkYXRhLmNvcnJlbGF0aW9uSWR9YDtcbiAgICAgICAgICAgIHN0ZXAgPSB7XG4gICAgICAgICAgICAgIC4uLnZhbGlkYXRlZFN0ZXAsXG4gICAgICAgICAgICAgIHN0YXR1czogJ3BlbmRpbmcnLFxuICAgICAgICAgICAgICBlcnJvcjogcmV0cnlEYXRhLmVycm9yIGFzIFVpbnQ4QXJyYXksXG4gICAgICAgICAgICAgIHJldHJ5QWZ0ZXI6IHJldHJ5RGF0YS5yZXRyeUFmdGVyLFxuICAgICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3N0ZXBzJywgc3RlcENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgICAgc3RlcCxcbiAgICAgICAgICAgICAgeyBvdmVyd3JpdGU6IHRydWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgLy8gSG9vayBsaWZlY3ljbGUgZXZlbnRzXG4gICAgICAgICAgZGF0YS5ldmVudFR5cGUgPT09ICdob29rX2NyZWF0ZWQnICYmXG4gICAgICAgICAgJ2V2ZW50RGF0YScgaW4gZGF0YVxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBob29rRGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIHRva2VuOiBzdHJpbmc7XG4gICAgICAgICAgICBtZXRhZGF0YT86IGFueTtcbiAgICAgICAgICAgIGlzV2ViaG9vaz86IGJvb2xlYW47XG4gICAgICAgICAgICBpc1N5c3RlbT86IGJvb2xlYW47XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIC8vIEF0b21pY2FsbHkgY2xhaW0gdGhlIHRva2VuIHVzaW5nIGFuIGV4Y2x1c2l2ZS1jcmVhdGUgY29uc3RyYWludCBmaWxlLlxuICAgICAgICAgIC8vIFRoaXMgYXZvaWRzIHRoZSBUT0NUT1UgcmFjZSBvZiB0aGUgcHJldmlvdXMgcmVhZC1hbGwtdGhlbi1jaGVjayBhcHByb2FjaC5cbiAgICAgICAgICBjb25zdCBjb25zdHJhaW50UGF0aCA9IHBhdGguam9pbihcbiAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAnaG9va3MnLFxuICAgICAgICAgICAgJ3Rva2VucycsXG4gICAgICAgICAgICBgJHtoYXNoVG9rZW4oaG9va0RhdGEudG9rZW4pfS5qc29uYFxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgdG9rZW5DbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUoXG4gICAgICAgICAgICBjb25zdHJhaW50UGF0aCxcbiAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgdG9rZW46IGhvb2tEYXRhLnRva2VuLFxuICAgICAgICAgICAgICBob29rSWQ6IGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKCF0b2tlbkNsYWltZWQpIHtcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nQ2xhaW0gPSBhd2FpdCByZWFkSG9va1Rva2VuQ2xhaW0oY29uc3RyYWludFBhdGgpO1xuXG4gICAgICAgICAgICAvLyBDcmVhdGUgaG9va19jb25mbGljdCBldmVudCBpbnN0ZWFkIG9mIGhvb2tfY3JlYXRlZFxuICAgICAgICAgICAgLy8gVGhpcyBhbGxvd3MgdGhlIHdvcmtmbG93IHRvIGNvbnRpbnVlIGFuZCBmYWlsIGdyYWNlZnVsbHkgd2hlbiB0aGUgaG9vayBpcyBhd2FpdGVkXG4gICAgICAgICAgICBjb25zdCBjb25mbGljdEV2ZW50OiBFdmVudCA9IHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnaG9va19jb25mbGljdCcsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGRhdGEuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgdG9rZW46IGhvb2tEYXRhLnRva2VuLFxuICAgICAgICAgICAgICAgIC4uLihleGlzdGluZ0NsYWltXG4gICAgICAgICAgICAgICAgICA/IHsgY29uZmxpY3RpbmdSdW5JZDogZXhpc3RpbmdDbGFpbS5ydW5JZCB9XG4gICAgICAgICAgICAgICAgICA6IHt9KSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgcnVuSWQ6IGVmZmVjdGl2ZVJ1bklkLFxuICAgICAgICAgICAgICBldmVudElkLFxuICAgICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy8gU3RvcmUgdGhlIGNvbmZsaWN0IGV2ZW50XG4gICAgICAgICAgICBjb25zdCBjb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtldmVudElkfWA7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUpTT04oXG4gICAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ2V2ZW50cycsIGNvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgICAgY29uZmxpY3RFdmVudFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPVxuICAgICAgICAgICAgICBwYXJhbXM/LnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgICAgICAgIGNvbnN0IGZpbHRlcmVkRXZlbnQgPSBzdHJpcEV2ZW50RGF0YVJlZnMoXG4gICAgICAgICAgICAgIGNvbmZsaWN0RXZlbnQsXG4gICAgICAgICAgICAgIHJlc29sdmVEYXRhXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAvLyBSZXR1cm4gRXZlbnRSZXN1bHQgd2l0aCBjb25mbGljdCBldmVudCAobm8gaG9vayBlbnRpdHkgY3JlYXRlZClcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGV2ZW50OiBmaWx0ZXJlZEV2ZW50LFxuICAgICAgICAgICAgICBydW4sXG4gICAgICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgICAgIGhvb2s6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaG9vayA9IHtcbiAgICAgICAgICAgIHJ1bklkOiBlZmZlY3RpdmVSdW5JZCxcbiAgICAgICAgICAgIGhvb2tJZDogZGF0YS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgdG9rZW46IGhvb2tEYXRhLnRva2VuLFxuICAgICAgICAgICAgbWV0YWRhdGE6IGhvb2tEYXRhLm1ldGFkYXRhLFxuICAgICAgICAgICAgb3duZXJJZDogJ2xvY2FsLW93bmVyJyxcbiAgICAgICAgICAgIHByb2plY3RJZDogJ2xvY2FsLXByb2plY3QnLFxuICAgICAgICAgICAgZW52aXJvbm1lbnQ6ICdsb2NhbCcsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIC8vIFByb3BhZ2F0ZSBzcGVjVmVyc2lvbiBmcm9tIHRoZSBldmVudCB0byB0aGUgaG9vayBlbnRpdHlcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBlZmZlY3RpdmVTcGVjVmVyc2lvbixcbiAgICAgICAgICAgIGlzV2ViaG9vazogaG9va0RhdGEuaXNXZWJob29rID8/IGZhbHNlLFxuICAgICAgICAgICAgaXNTeXN0ZW06IGhvb2tEYXRhLmlzU3lzdGVtID8/IGZhbHNlLFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnaG9va3MnLCBkYXRhLmNvcnJlbGF0aW9uSWQsIHRhZyksXG4gICAgICAgICAgICBob29rXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfZGlzcG9zZWQnKSB7XG4gICAgICAgICAgLy8gaG9va19kaXNwb3NlZDogRGVsZXRlcyBob29rIGVudGl0eSwgcmVqZWN0cyBkdXBsaWNhdGVzLlxuICAgICAgICAgIC8vIFVzZXMgd3JpdGVFeGNsdXNpdmUgb24gYSBsb2NrIGZpbGUgdG8gYXRvbWljYWxseSBwcmV2ZW50IGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggZGlzcG9zaW5nIHRoZSBzYW1lIGhvb2sgKFRPQ1RPVSByYWNlKS5cbiAgICAgICAgICBjb25zdCBob29rTG9ja05hbWUgPSB0YWdcbiAgICAgICAgICAgID8gYCR7ZGF0YS5jb3JyZWxhdGlvbklkfS5kaXNwb3NlZC4ke3RhZ31gXG4gICAgICAgICAgICA6IGAke2RhdGEuY29ycmVsYXRpb25JZH0uZGlzcG9zZWRgO1xuICAgICAgICAgIGNvbnN0IGxvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgICAnaG9va3MnLFxuICAgICAgICAgICAgaG9va0xvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUobG9ja1BhdGgsICcnKTtcbiAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgICBgSG9vayBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIGFscmVhZHkgZGlzcG9zZWRgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBSZWFkIHRoZSBob29rIHRvIGdldCBpdHMgdG9rZW4gYmVmb3JlIGRlbGV0aW5nXG4gICAgICAgICAgY29uc3QgaG9va1BhdGggPSB0YWdnZWRQYXRoKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICB0YWdcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IGV4aXN0aW5nSG9vayA9IGF3YWl0IHJlYWRKU09OV2l0aEZhbGxiYWNrKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICBkYXRhLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBIb29rU2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoZXhpc3RpbmdIb29rKSB7XG4gICAgICAgICAgICAvLyBEZWxldGUgdGhlIHRva2VuIGNvbnN0cmFpbnQgZmlsZSB0byBmcmVlIHVwIHRoZSB0b2tlbiBmb3IgcmV1c2VcbiAgICAgICAgICAgIGNvbnN0IGRpc3Bvc2VkQ29uc3RyYWludFBhdGggPSBwYXRoLmpvaW4oXG4gICAgICAgICAgICAgIGJhc2VkaXIsXG4gICAgICAgICAgICAgICdob29rcycsXG4gICAgICAgICAgICAgICd0b2tlbnMnLFxuICAgICAgICAgICAgICBgJHtoYXNoVG9rZW4oZXhpc3RpbmdIb29rLnRva2VuKX0uanNvbmBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhd2FpdCBkZWxldGVKU09OKGRpc3Bvc2VkQ29uc3RyYWludFBhdGgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBhd2FpdCBkZWxldGVKU09OKGhvb2tQYXRoKTtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY3JlYXRlZCcgJiYgJ2V2ZW50RGF0YScgaW4gZGF0YSkge1xuICAgICAgICAgIC8vIHdhaXRfY3JlYXRlZDogQ3JlYXRlcyB3YWl0IGVudGl0eSB3aXRoIHN0YXR1cyAnd2FpdGluZycuXG4gICAgICAgICAgLy8gQXRvbWljIGNsYWltIG9uIGEgcGVyLShydW5JZCwgY29ycmVsYXRpb25JZCkgY29uc3RyYWludCBmaWxlXG4gICAgICAgICAgLy8gZW5zdXJlcyBkdXBsaWNhdGUgd2FpdF9jcmVhdGVkIGZyb20gY29uY3VycmVudCBpbnZvY2F0aW9uc1xuICAgICAgICAgIC8vIHN1cmZhY2VzIGFzIEVudGl0eUNvbmZsaWN0RXJyb3IgKHJlcGxhY2VzIGEgcHJpb3IgVE9DVE9VXG4gICAgICAgICAgLy8gcmVhZC10aGVuLWNoZWNrIHRoYXQgY291bGQgbGV0IGJvdGggd3JpdGVycyB0aHJvdWdoKS5cbiAgICAgICAgICBjb25zdCB3YWl0Q29tcG9zaXRlS2V5ID0gYCR7ZWZmZWN0aXZlUnVuSWR9LSR7ZGF0YS5jb3JyZWxhdGlvbklkfWA7XG4gICAgICAgICAgY29uc3Qgd2FpdENyZWF0ZWRMb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgPyBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jcmVhdGVkLiR7dGFnfWBcbiAgICAgICAgICAgIDogYCR7d2FpdENvbXBvc2l0ZUtleX0uY3JlYXRlZGA7XG4gICAgICAgICAgY29uc3Qgd2FpdENyZWF0ZWRMb2NrUGF0aCA9IHJlc29sdmVXaXRoaW5CYXNlKFxuICAgICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICAgICcubG9ja3MnLFxuICAgICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICAgIHdhaXRDcmVhdGVkTG9ja05hbWVcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IHdhaXRDcmVhdGVkQ2xhaW1lZCA9IGF3YWl0IHdyaXRlRXhjbHVzaXZlKFxuICAgICAgICAgICAgd2FpdENyZWF0ZWRMb2NrUGF0aCxcbiAgICAgICAgICAgICcnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoIXdhaXRDcmVhdGVkQ2xhaW1lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVudGl0eUNvbmZsaWN0RXJyb3IoXG4gICAgICAgICAgICAgIGBXYWl0IFwiJHtkYXRhLmNvcnJlbGF0aW9uSWR9XCIgYWxyZWFkeSBleGlzdHNgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCB3YWl0RGF0YSA9IGRhdGEuZXZlbnREYXRhIGFzIHtcbiAgICAgICAgICAgIHJlc3VtZUF0PzogRGF0ZTtcbiAgICAgICAgICB9O1xuICAgICAgICAgIHdhaXQgPSB7XG4gICAgICAgICAgICB3YWl0SWQ6IHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgICBydW5JZDogZWZmZWN0aXZlUnVuSWQsXG4gICAgICAgICAgICBzdGF0dXM6ICd3YWl0aW5nJyxcbiAgICAgICAgICAgIHJlc3VtZUF0OiB3YWl0RGF0YS5yZXN1bWVBdCxcbiAgICAgICAgICAgIGNvbXBsZXRlZEF0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IGVmZmVjdGl2ZVNwZWNWZXJzaW9uLFxuICAgICAgICAgIH07XG4gICAgICAgICAgYXdhaXQgd3JpdGVKU09OKFxuICAgICAgICAgICAgdGFnZ2VkUGF0aChiYXNlZGlyLCAnd2FpdHMnLCB3YWl0Q29tcG9zaXRlS2V5LCB0YWcpLFxuICAgICAgICAgICAgd2FpdFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudFR5cGUgPT09ICd3YWl0X2NvbXBsZXRlZCcpIHtcbiAgICAgICAgICAvLyB3YWl0X2NvbXBsZXRlZDogVHJhbnNpdGlvbnMgd2FpdCB0byAnY29tcGxldGVkJywgcmVqZWN0cyBkdXBsaWNhdGVzLlxuICAgICAgICAgIC8vIFVzZXMgd3JpdGVFeGNsdXNpdmUgb24gYSBsb2NrIGZpbGUgdG8gYXRvbWljYWxseSBwcmV2ZW50IGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBmcm9tIGJvdGggY29tcGxldGluZyB0aGUgc2FtZSB3YWl0IChUT0NUT1UgcmFjZSkuXG4gICAgICAgICAgY29uc3Qgd2FpdENvbXBvc2l0ZUtleSA9IGAke2VmZmVjdGl2ZVJ1bklkfS0ke2RhdGEuY29ycmVsYXRpb25JZH1gO1xuICAgICAgICAgIGNvbnN0IHdhaXRMb2NrTmFtZSA9IHRhZ1xuICAgICAgICAgICAgPyBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jb21wbGV0ZWQuJHt0YWd9YFxuICAgICAgICAgICAgOiBgJHt3YWl0Q29tcG9zaXRlS2V5fS5jb21wbGV0ZWRgO1xuICAgICAgICAgIGNvbnN0IGxvY2tQYXRoID0gcmVzb2x2ZVdpdGhpbkJhc2UoXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJy5sb2NrcycsXG4gICAgICAgICAgICAnd2FpdHMnLFxuICAgICAgICAgICAgd2FpdExvY2tOYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgd3JpdGVFeGNsdXNpdmUobG9ja1BhdGgsICcnKTtcbiAgICAgICAgICBpZiAoIWNsYWltZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFbnRpdHlDb25mbGljdEVycm9yKFxuICAgICAgICAgICAgICBgV2FpdCBcIiR7ZGF0YS5jb3JyZWxhdGlvbklkfVwiIGFscmVhZHkgY29tcGxldGVkYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdXYWl0ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgICAgICBiYXNlZGlyLFxuICAgICAgICAgICAgJ3dhaXRzJyxcbiAgICAgICAgICAgIHdhaXRDb21wb3NpdGVLZXksXG4gICAgICAgICAgICBXYWl0U2NoZW1hLFxuICAgICAgICAgICAgdGFnXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoIWV4aXN0aW5nV2FpdCkge1xuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGxvY2sgZmlsZSB3ZSBqdXN0IGNsYWltZWQg4oCUIHRoZSB3YWl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgICAgICAgIGF3YWl0IGZzLnVubGluayhsb2NrUGF0aCkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93V29ybGRFcnJvcihcbiAgICAgICAgICAgICAgYFdhaXQgXCIke2RhdGEuY29ycmVsYXRpb25JZH1cIiBub3QgZm91bmRgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBUaGUgbG9jayBmaWxlICh3cml0ZUV4Y2x1c2l2ZSBhYm92ZSkgYWxyZWFkeSBwcmV2ZW50cyBjb25jdXJyZW50XG4gICAgICAgICAgLy8gY29tcGxldGlvbnMg4oCUIG5vIGFkZGl0aW9uYWwgc3RhdHVzIGNoZWNrIG5lZWRlZC5cbiAgICAgICAgICB3YWl0ID0ge1xuICAgICAgICAgICAgLi4uZXhpc3RpbmdXYWl0LFxuICAgICAgICAgICAgc3RhdHVzOiAnY29tcGxldGVkJyxcbiAgICAgICAgICAgIGNvbXBsZXRlZEF0OiBub3csXG4gICAgICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICAgIHRhZ2dlZFBhdGgoYmFzZWRpciwgJ3dhaXRzJywgd2FpdENvbXBvc2l0ZUtleSwgdGFnKSxcbiAgICAgICAgICAgIHdhaXQsXG4gICAgICAgICAgICB7IG92ZXJ3cml0ZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOb3RlOiBob29rX3JlY2VpdmVkIGV2ZW50cyBhcmUgc3RvcmVkIGluIHRoZSBldmVudCBsb2cgYnV0IGRvbid0XG4gICAgICAgIC8vIG1vZGlmeSB0aGUgSG9vayBlbnRpdHkgKHdoaWNoIGRvZXNuJ3QgaGF2ZSBhIHBheWxvYWQgZmllbGQpXG5cbiAgICAgICAgLy8gU3RvcmUgZXZlbnQgdXNpbmcgY29tcG9zaXRlIGtleSB7cnVuSWR9LXtldmVudElkfVxuICAgICAgICBjb25zdCBjb21wb3NpdGVLZXkgPSBgJHtlZmZlY3RpdmVSdW5JZH0tJHtldmVudElkfWA7XG4gICAgICAgIGF3YWl0IHdyaXRlSlNPTihcbiAgICAgICAgICB0YWdnZWRQYXRoKGJhc2VkaXIsICdldmVudHMnLCBjb21wb3NpdGVLZXksIHRhZyksXG4gICAgICAgICAgZXZlbnRcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCByZXNvbHZlRGF0YSA9IHBhcmFtcz8ucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgICBjb25zdCBmaWx0ZXJlZEV2ZW50ID0gc3RyaXBFdmVudERhdGFSZWZzKGV2ZW50LCByZXNvbHZlRGF0YSk7XG5cbiAgICAgICAgLy8gRm9yIHJ1bl9zdGFydGVkOiBwcmVsb2FkIG9uZSBwYWdlIG9mIGV2ZW50cyBzbyB0aGUgcnVudGltZSBjYW4gc2tpcFxuICAgICAgICAvLyB0aGUgaW5pdGlhbCBldmVudHMubGlzdCBjYWxsIHdoZW4gaGFzTW9yZSBpcyBmYWxzZS5cbiAgICAgICAgbGV0IGV2ZW50czogRXZlbnRbXSB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IGhhc01vcmU6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChkYXRhLmV2ZW50VHlwZSA9PT0gJ3J1bl9zdGFydGVkJyAmJiBydW4pIHtcbiAgICAgICAgICBjb25zdCBhbGxFdmVudHMgPSBhd2FpdCBwYWdpbmF0ZWRGaWxlU3lzdGVtUXVlcnkoe1xuICAgICAgICAgICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oYmFzZWRpciwgJ2V2ZW50cycpLFxuICAgICAgICAgICAgc2NoZW1hOiBFdmVudFNjaGVtYSxcbiAgICAgICAgICAgIGZpbGVQcmVmaXg6IGAke2VmZmVjdGl2ZVJ1bklkfS1gLFxuICAgICAgICAgICAgc29ydE9yZGVyOiAnYXNjJyxcbiAgICAgICAgICAgIGxpbWl0OiAxMDAwLFxuICAgICAgICAgICAgZ2V0Q3JlYXRlZEF0OiBnZXRPYmplY3RDcmVhdGVkQXQoJ2V2bnQnKSxcbiAgICAgICAgICAgIGdldElkOiAoZSkgPT4gZS5ldmVudElkLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGV2ZW50cyA9IGFsbEV2ZW50cy5kYXRhO1xuICAgICAgICAgIGN1cnNvciA9IGFsbEV2ZW50cy5jdXJzb3I7XG4gICAgICAgICAgaGFzTW9yZSA9IGFsbEV2ZW50cy5oYXNNb3JlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmV0dXJuIEV2ZW50UmVzdWx0IHdpdGggZXZlbnQgYW5kIGFueSBjcmVhdGVkL3VwZGF0ZWQgZW50aXR5XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZXZlbnQ6IGZpbHRlcmVkRXZlbnQsXG4gICAgICAgICAgcnVuLFxuICAgICAgICAgIHN0ZXAsXG4gICAgICAgICAgaG9vayxcbiAgICAgICAgICB3YWl0LFxuICAgICAgICAgIGV2ZW50cyxcbiAgICAgICAgICBjdXJzb3IsXG4gICAgICAgICAgaGFzTW9yZSxcbiAgICAgICAgfTtcbiAgICAgIH0gLy8gZW5kIGNyZWF0ZUltcGxcbiAgICB9LFxuXG4gICAgYXN5bmMgZ2V0KHJ1bklkLCBldmVudElkLCBwYXJhbXMpIHtcbiAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgncnVuSWQnLCBydW5JZCk7XG4gICAgICBhc3NlcnRTYWZlRW50aXR5SWQoJ2V2ZW50SWQnLCBldmVudElkKTtcbiAgICAgIGNvbnN0IGNvbXBvc2l0ZUtleSA9IGAke3J1bklkfS0ke2V2ZW50SWR9YDtcbiAgICAgIGNvbnN0IGV2ZW50ID0gYXdhaXQgcmVhZEpTT05XaXRoRmFsbGJhY2soXG4gICAgICAgIGJhc2VkaXIsXG4gICAgICAgICdldmVudHMnLFxuICAgICAgICBjb21wb3NpdGVLZXksXG4gICAgICAgIEV2ZW50U2NoZW1hLFxuICAgICAgICB0YWdcbiAgICAgICk7XG4gICAgICBpZiAoIWV2ZW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXZlbnQgJHtldmVudElkfSBpbiBydW4gJHtydW5JZH0gbm90IGZvdW5kYCk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXNvbHZlRGF0YSA9IHBhcmFtcz8ucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgcmV0dXJuIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpO1xuICAgIH0sXG5cbiAgICBhc3luYyBsaXN0KHBhcmFtcykge1xuICAgICAgY29uc3QgeyBydW5JZCB9ID0gcGFyYW1zO1xuICAgICAgYXNzZXJ0U2FmZUVudGl0eUlkKCdydW5JZCcsIHJ1bklkKTtcbiAgICAgIGNvbnN0IHJlc29sdmVEYXRhID0gcGFyYW1zLnJlc29sdmVEYXRhID8/IERFRkFVTFRfUkVTT0xWRV9EQVRBX09QVElPTjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBhZ2luYXRlZEZpbGVTeXN0ZW1RdWVyeSh7XG4gICAgICAgIGRpcmVjdG9yeTogcGF0aC5qb2luKGJhc2VkaXIsICdldmVudHMnKSxcbiAgICAgICAgc2NoZW1hOiBFdmVudFNjaGVtYSxcbiAgICAgICAgZmlsZVByZWZpeDogYCR7cnVuSWR9LWAsXG4gICAgICAgIC8vIEV2ZW50cyBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIChvbGRlc3QgZmlyc3QpIGJ5IGRlZmF1bHQsXG4gICAgICAgIC8vIGRpZmZlcmVudCBmcm9tIHRoZSBkZWZhdWx0IGZvciBvdGhlciBsaXN0IGNhbGxzLlxuICAgICAgICBzb3J0T3JkZXI6IHBhcmFtcy5wYWdpbmF0aW9uPy5zb3J0T3JkZXIgPz8gJ2FzYycsXG4gICAgICAgIGxpbWl0OiBwYXJhbXMucGFnaW5hdGlvbj8ubGltaXQsXG4gICAgICAgIGN1cnNvcjogcGFyYW1zLnBhZ2luYXRpb24/LmN1cnNvcixcbiAgICAgICAgZ2V0Q3JlYXRlZEF0OiBnZXRPYmplY3RDcmVhdGVkQXQoJ2V2bnQnKSxcbiAgICAgICAgZ2V0SWQ6IChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBJZiByZXNvbHZlRGF0YSBpcyBcIm5vbmVcIiwgcmVtb3ZlIGV2ZW50RGF0YSBmcm9tIGV2ZW50c1xuICAgICAgaWYgKHJlc29sdmVEYXRhID09PSAnbm9uZScpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5yZXN1bHQsXG4gICAgICAgICAgZGF0YTogcmVzdWx0LmRhdGEubWFwKChldmVudCkgPT5cbiAgICAgICAgICAgIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpXG4gICAgICAgICAgKSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgYXN5bmMgbGlzdEJ5Q29ycmVsYXRpb25JZChwYXJhbXMpIHtcbiAgICAgIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBwYXJhbXMuY29ycmVsYXRpb25JZDtcbiAgICAgIGFzc2VydFNhZmVFbnRpdHlJZCgnY29ycmVsYXRpb25JZCcsIGNvcnJlbGF0aW9uSWQpO1xuICAgICAgY29uc3QgcmVzb2x2ZURhdGEgPSBwYXJhbXMucmVzb2x2ZURhdGEgPz8gREVGQVVMVF9SRVNPTFZFX0RBVEFfT1BUSU9OO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGFnaW5hdGVkRmlsZVN5c3RlbVF1ZXJ5KHtcbiAgICAgICAgZGlyZWN0b3J5OiBwYXRoLmpvaW4oYmFzZWRpciwgJ2V2ZW50cycpLFxuICAgICAgICBzY2hlbWE6IEV2ZW50U2NoZW1hLFxuICAgICAgICAvLyBObyBmaWxlUHJlZml4IC0gc2VhcmNoIGFsbCBldmVudHNcbiAgICAgICAgZmlsdGVyOiAoZXZlbnQpID0+IGV2ZW50LmNvcnJlbGF0aW9uSWQgPT09IGNvcnJlbGF0aW9uSWQsXG4gICAgICAgIC8vIEV2ZW50cyBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIChvbGRlc3QgZmlyc3QpIGJ5IGRlZmF1bHQsXG4gICAgICAgIC8vIGRpZmZlcmVudCBmcm9tIHRoZSBkZWZhdWx0IGZvciBvdGhlciBsaXN0IGNhbGxzLlxuICAgICAgICBzb3J0T3JkZXI6IHBhcmFtcy5wYWdpbmF0aW9uPy5zb3J0T3JkZXIgPz8gJ2FzYycsXG4gICAgICAgIGxpbWl0OiBwYXJhbXMucGFnaW5hdGlvbj8ubGltaXQsXG4gICAgICAgIGN1cnNvcjogcGFyYW1zLnBhZ2luYXRpb24/LmN1cnNvcixcbiAgICAgICAgZ2V0Q3JlYXRlZEF0OiBnZXRPYmplY3RDcmVhdGVkQXQoJ2V2bnQnKSxcbiAgICAgICAgZ2V0SWQ6IChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBJZiByZXNvbHZlRGF0YSBpcyBcIm5vbmVcIiwgcmVtb3ZlIGV2ZW50RGF0YSBmcm9tIGV2ZW50c1xuICAgICAgaWYgKHJlc29sdmVEYXRhID09PSAnbm9uZScpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5yZXN1bHQsXG4gICAgICAgICAgZGF0YTogcmVzdWx0LmRhdGEubWFwKChldmVudCkgPT5cbiAgICAgICAgICAgIHN0cmlwRXZlbnREYXRhUmVmcyhldmVudCwgcmVzb2x2ZURhdGEpXG4gICAgICAgICAgKSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuICB9O1xufVxuIl19
|