footprintjs 9.40.0 → 9.41.0
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/CLAUDE.md +3 -3
- package/dist/esm/lib/builder/FlowChartBuilder.d.ts +10 -3
- package/dist/esm/lib/builder/FlowChartBuilder.js +93 -86
- package/dist/esm/lib/capture/freeze.d.ts +1 -1
- package/dist/esm/lib/capture/freeze.js +2 -2
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +12 -0
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +49 -15
- package/dist/esm/lib/memory/StageContext.d.ts +16 -0
- package/dist/esm/lib/memory/StageContext.js +35 -40
- package/dist/esm/lib/reactive/types.js +4 -4
- package/dist/esm/lib/recorder/hooks.d.ts +2 -2
- package/dist/esm/lib/recorder/hooks.js +2 -2
- package/dist/esm/lib/recorder/snapshot.d.ts +1 -1
- package/dist/esm/lib/recorder/snapshot.js +2 -2
- package/dist/esm/lib/runner/FlowChartExecutor.d.ts +93 -377
- package/dist/esm/lib/runner/FlowChartExecutor.js +184 -1059
- package/dist/esm/lib/runner/attach.d.ts +95 -0
- package/dist/esm/lib/runner/attach.js +247 -0
- package/dist/esm/lib/runner/checkpoint.d.ts +69 -0
- package/dist/esm/lib/runner/checkpoint.js +254 -0
- package/dist/esm/lib/runner/index.d.ts +1 -1
- package/dist/esm/lib/runner/index.js +1 -1
- package/dist/esm/lib/runner/options.d.ts +79 -0
- package/dist/esm/lib/runner/options.js +31 -0
- package/dist/esm/lib/runner/resume.d.ts +73 -0
- package/dist/esm/lib/runner/resume.js +301 -0
- package/dist/esm/lib/runner/snapshot.d.ts +41 -0
- package/dist/esm/lib/runner/snapshot.js +93 -0
- package/dist/lib/builder/FlowChartBuilder.js +93 -86
- package/dist/lib/capture/freeze.js +2 -2
- package/dist/lib/engine/traversal/FlowchartTraverser.js +49 -15
- package/dist/lib/memory/StageContext.js +35 -40
- package/dist/lib/reactive/types.js +4 -4
- package/dist/lib/recorder/hooks.js +2 -2
- package/dist/lib/recorder/snapshot.js +2 -2
- package/dist/lib/runner/FlowChartExecutor.js +182 -1057
- package/dist/lib/runner/attach.js +251 -0
- package/dist/lib/runner/checkpoint.js +258 -0
- package/dist/lib/runner/index.js +1 -1
- package/dist/lib/runner/options.js +35 -0
- package/dist/lib/runner/resume.js +307 -0
- package/dist/lib/runner/snapshot.js +98 -0
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +10 -3
- package/dist/types/lib/capture/freeze.d.ts +1 -1
- package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +12 -0
- package/dist/types/lib/memory/StageContext.d.ts +16 -0
- package/dist/types/lib/recorder/hooks.d.ts +2 -2
- package/dist/types/lib/recorder/snapshot.d.ts +1 -1
- package/dist/types/lib/runner/FlowChartExecutor.d.ts +93 -377
- package/dist/types/lib/runner/attach.d.ts +95 -0
- package/dist/types/lib/runner/checkpoint.d.ts +69 -0
- package/dist/types/lib/runner/index.d.ts +1 -1
- package/dist/types/lib/runner/options.d.ts +79 -0
- package/dist/types/lib/runner/resume.d.ts +73 -0
- package/dist/types/lib/runner/snapshot.d.ts +41 -0
- package/package.json +1 -1
- package/dist/esm/lib/runner/checkpointSanitize.d.ts +0 -44
- package/dist/esm/lib/runner/checkpointSanitize.js +0 -133
- package/dist/lib/runner/checkpointSanitize.js +0 -138
- package/dist/types/lib/runner/checkpointSanitize.d.ts +0 -44
|
@@ -14,139 +14,55 @@
|
|
|
14
14
|
* // 2-param form (accepts a ScopeFactory directly, for backward compatibility):
|
|
15
15
|
* const executor = new FlowChartExecutor(chart, myFactory);
|
|
16
16
|
*
|
|
17
|
+
*
|
|
18
|
+
* The executor composes four modules, one job each (F9): `attach.ts` (who
|
|
19
|
+
* observes a run), `resume.ts` (plan and announce a re-entry), `checkpoint.ts`
|
|
20
|
+
* (the pause checkpoint), `snapshot.ts` (what `getSnapshot()` serves). What
|
|
21
|
+
* stays here is the per-run state and the run lifecycle that threads it.
|
|
17
22
|
* const result = await executor.run({ input: data, env: { traceId: 'req-123' } });
|
|
18
23
|
*/
|
|
19
|
-
import { deepFreeze } from '../capture/freeze.js';
|
|
20
24
|
import { detachAndForget as _detachAndForget, detachAndJoinLater as _detachAndJoinLater } from '../detach/spawn.js';
|
|
21
|
-
import { isDevMode } from '../devMode.js';
|
|
22
|
-
import { ResumeEntry } from '../engine/handlers/ResumeEntry.js';
|
|
23
|
-
import { servedSubflowResults } from '../engine/handlers/servedSubflowResults.js';
|
|
24
|
-
import { CombinedNarrativeRecorder } from '../engine/narrative/CombinedNarrativeRecorder.js';
|
|
25
25
|
import { ManifestFlowRecorder } from '../engine/narrative/recorders/ManifestFlowRecorder.js';
|
|
26
26
|
import { FlowchartTraverser } from '../engine/traversal/FlowchartTraverser.js';
|
|
27
|
-
import { resumeTraversalContext } from '../engine/traversalContext.js';
|
|
28
27
|
import { defaultLogger, } from '../engine/types.js';
|
|
29
|
-
import { buildRuntimeStageId, isExecutionKey } from '../ids/runtimeStageId.js';
|
|
30
28
|
import { RedactionRule } from '../memory/redaction.js';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import { hasEmitRecorderMethods, hasFlowRecorderMethods, hasRecorderMethods } from '../recorder/CombinedRecorder.js';
|
|
36
|
-
import { fire, recorderFailureEvent, warnInDevMode } from '../recorder/hooks.js';
|
|
37
|
-
import { copyBundle } from '../recorder/snapshot.js';
|
|
38
|
-
import { ScopeFacade } from '../scope/ScopeFacade.js';
|
|
39
|
-
import { describeCheckpointCloneFailure, sanitizeDiagnosticBags } from './checkpointSanitize.js';
|
|
40
|
-
import { DeferredObserverTier } from './DeferredObserverTier.js';
|
|
29
|
+
import { runPolicy } from '../memory/runPolicy.js';
|
|
30
|
+
import { isPauseSignal } from '../pause/types.js';
|
|
31
|
+
import { RunObservers } from './attach.js';
|
|
32
|
+
import { buildPauseCheckpoint } from './checkpoint.js';
|
|
41
33
|
import { ExecutionRuntime } from './ExecutionRuntime.js';
|
|
34
|
+
import { resolveExecutorArgs } from './options.js';
|
|
35
|
+
import { announceResume, planResume, seedCounters } from './resume.js';
|
|
42
36
|
import { generateRunId } from './runId.js';
|
|
37
|
+
import { servedSnapshot } from './snapshot.js';
|
|
43
38
|
import { validateInput } from './validateInput.js';
|
|
44
|
-
/** Default scope factory — creates a plain ScopeFacade for each stage. */
|
|
45
|
-
const defaultScopeFactory = (ctx, stageName, readOnly, env) => new ScopeFacade(ctx, stageName, readOnly, env);
|
|
46
|
-
/**
|
|
47
|
-
* The paused stage's stand-in for a resume: the stage's OWN node — so it keeps
|
|
48
|
-
* its shape (a decider's or selector's branches, a fork parent's children,
|
|
49
|
-
* its `next`) and its name, description and declared tags — with `fn` swapped
|
|
50
|
-
* for the resume half.
|
|
51
|
-
*
|
|
52
|
-
* Dropped: `resumeFn` and `isPausable` (the resume half must not pause
|
|
53
|
-
* because it returned a value — the original pausable contract); and, on the
|
|
54
|
-
* `addPausableFunction` re-entry, the policies declared for the stage's OWN
|
|
55
|
-
* function (`retry`, streaming) — that re-entry runs a different function
|
|
56
|
-
* (`resumeFn`) under a different contract. The `interrupt()` re-entry re-runs
|
|
57
|
-
* the stage's own function, so it keeps them.
|
|
58
|
-
*
|
|
59
|
-
* Tags follow the stage on BOTH re-entries (9.21.0): a tag is the stage's
|
|
60
|
-
* NAME, not a policy over its function, and the resumed execution is that
|
|
61
|
-
* stage running again — its bundle must carry it, or a chained axis would
|
|
62
|
-
* show the paused leg tagged and the resumed leg silently not.
|
|
63
|
-
*/
|
|
64
|
-
function standInFor(pausedNode, fn, isInterruptResume) {
|
|
65
|
-
const standIn = { ...pausedNode, fn };
|
|
66
|
-
delete standIn.resumeFn;
|
|
67
|
-
delete standIn.isPausable;
|
|
68
|
-
if (!isInterruptResume) {
|
|
69
|
-
delete standIn.retry;
|
|
70
|
-
delete standIn.isStreaming;
|
|
71
|
-
delete standIn.streamId;
|
|
72
|
-
}
|
|
73
|
-
return standIn;
|
|
74
|
-
}
|
|
75
|
-
/** The flow channel's isolation for the executor-made `onResume` (dev-mode warning, then skip). */
|
|
76
|
-
const RESUME_FLOW_FAILURE = warnInDevMode('FlowChartExecutor');
|
|
77
|
-
/**
|
|
78
|
-
* The resume event's link, read off the checkpoint itself — so a resume records
|
|
79
|
-
* the same wherever its checkpoint came from. `undefined` for a checkpoint
|
|
80
|
-
* without `pausedExecution` (made before 9.37.0) or with a malformed one: the
|
|
81
|
-
* link is a record, never used to plan the re-entry, so it is left out rather
|
|
82
|
-
* than guessed.
|
|
83
|
-
*/
|
|
84
|
-
function resumeLinkOf(checkpoint) {
|
|
85
|
-
const paused = checkpoint.pausedExecution;
|
|
86
|
-
return isPausedExecution(paused) ? { runId: paused.runId, runtimeStageId: paused.runtimeStageId } : undefined;
|
|
87
|
-
}
|
|
88
39
|
export class FlowChartExecutor {
|
|
89
40
|
traverser;
|
|
90
|
-
/** Shared execution counter
|
|
41
|
+
/** Shared execution counter and per-stage visit counts (loopIteration) — shared BY
|
|
42
|
+
* REFERENCE with every traverser of the run; survive pause/resume, reset on run(). */
|
|
91
43
|
_executionCounter = { value: 0 };
|
|
92
|
-
/** Shared per-run visit counts (by stageId) driving TraversalContext.loopIteration.
|
|
93
|
-
* Twin of _executionCounter: survives pause/resume, reset on fresh run(). */
|
|
94
44
|
_visitCounts = new Map();
|
|
95
|
-
/**
|
|
96
|
-
* through every TraversalContext so recorders can scope state to a single
|
|
97
|
-
* run. See `runId.ts`. */
|
|
45
|
+
/** Fresh per run() and per resume() — stamped on every TraversalContext (`runId.ts`). */
|
|
98
46
|
_currentRunId = '';
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
combinedRecorder;
|
|
102
|
-
flowRecorders = [];
|
|
103
|
-
scopeRecorders = [];
|
|
104
|
-
/**
|
|
105
|
-
* RFC-001 deferred-observer wiring — created LAZILY on the first
|
|
106
|
-
* `delivery: 'deferred'` attach. `undefined` for every executor that never
|
|
107
|
-
* opts in: zero allocation, zero per-event cost, byte-identical behavior
|
|
108
|
-
* (the emit fast-path precedent).
|
|
109
|
-
*/
|
|
110
|
-
deferredTier;
|
|
47
|
+
/** Who observes the run — narrative, inline lists, deferred tier (`attach.ts`). */
|
|
48
|
+
observers = new RunObservers();
|
|
111
49
|
redactionPolicy;
|
|
112
|
-
/**
|
|
113
|
-
* The run's ONE redaction rule (`memory/redaction.ts`): built fresh per
|
|
114
|
-
* `createTraverser` (per-call marks reset per run and per resume, as the
|
|
115
|
-
* shared set always did), installed on the runtime root so every context
|
|
116
|
-
* retains under it, and read by every `ScopeFacade` through its context.
|
|
117
|
-
*/
|
|
50
|
+
/** The run's ONE redaction rule (`memory/redaction.ts`), built fresh per leg. */
|
|
118
51
|
redactionRule = new RedactionRule();
|
|
119
52
|
lastCheckpoint;
|
|
120
53
|
/**
|
|
121
|
-
* `true` once
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* continuity: execution tree, recorders, narrative
|
|
126
|
-
* accumulate across pause/resume cycles)
|
|
127
|
-
* • false → seed a fresh runtime from `checkpoint.sharedState`
|
|
128
|
-
* (cross-executor / cross-process resume: new instance
|
|
129
|
-
* reconstructed from a serialized checkpoint)
|
|
130
|
-
*
|
|
131
|
-
* Without this flag, fresh executors silently discarded the
|
|
132
|
-
* checkpoint's sharedState and resume handlers couldn't read pre-pause
|
|
133
|
-
* scope. See `test/lib/pause/cross-executor-resume.test.ts`.
|
|
54
|
+
* `true` once run() (or a resume) executed here. `resume()` branches on it:
|
|
55
|
+
* true → reuse the runtime (execution tree, recorders, narrative accumulate);
|
|
56
|
+
* false → seed a fresh runtime from `checkpoint.sharedState` (cross-executor
|
|
57
|
+
* resume). See `test/lib/pause/cross-executor-resume.test.ts`.
|
|
134
58
|
*/
|
|
135
59
|
_hasRunBefore = false;
|
|
136
60
|
/**
|
|
137
|
-
* Re-entrancy guard
|
|
138
|
-
*
|
|
139
|
-
* recorders — a second concurrent entry on the SAME executor would
|
|
140
|
-
* interleave runIds and cross-contaminate recorder/narrative state, and
|
|
141
|
-
* `getCheckpoint()` would return whichever run paused last. One executor =
|
|
142
|
-
* one in-flight execution; create an executor per concurrent run.
|
|
61
|
+
* Re-entrancy guard: run()/resume() mutate per-run state (traverser, runId,
|
|
62
|
+
* counters, checkpoint, recorders) — one executor = one in-flight execution.
|
|
143
63
|
* See docs/guides/execution-model.md.
|
|
144
64
|
*/
|
|
145
65
|
_isExecuting = false;
|
|
146
|
-
// SYNC REQUIRED: every optional field here must mirror FlowChartExecutorOptions
|
|
147
|
-
// AND be assigned in the constructor's options-resolution block (the `else if` branch).
|
|
148
|
-
// Adding a field to only one of the three places causes silent omission.
|
|
149
|
-
// (The dials ride `dials` whole — `pickDials` reads every one RunDials declares.)
|
|
150
66
|
flowChartArgs;
|
|
151
67
|
/**
|
|
152
68
|
* Create a FlowChartExecutor.
|
|
@@ -165,142 +81,28 @@ export class FlowChartExecutor {
|
|
|
165
81
|
* @param factoryOrOptions - A `ScopeFactory<TScope>` OR a `FlowChartExecutorOptions<TScope>` options object.
|
|
166
82
|
*/
|
|
167
83
|
constructor(flowChart, factoryOrOptions) {
|
|
168
|
-
|
|
169
|
-
let scopeFactory;
|
|
170
|
-
let defaultValuesForContext;
|
|
171
|
-
let initialContext;
|
|
172
|
-
let readOnlyContext;
|
|
173
|
-
let throttlingErrorChecker;
|
|
174
|
-
let streamHandlers;
|
|
175
|
-
let scopeProtectionMode;
|
|
176
|
-
let dials = {};
|
|
177
|
-
if (typeof factoryOrOptions === 'function') {
|
|
178
|
-
// 2-param form: new FlowChartExecutor(chart, scopeFactory)
|
|
179
|
-
scopeFactory = factoryOrOptions;
|
|
180
|
-
}
|
|
181
|
-
else if (factoryOrOptions !== undefined) {
|
|
182
|
-
// Options object form
|
|
183
|
-
const opts = factoryOrOptions;
|
|
184
|
-
scopeFactory = opts.scopeFactory;
|
|
185
|
-
defaultValuesForContext = opts.defaultValuesForContext;
|
|
186
|
-
initialContext = opts.initialContext;
|
|
187
|
-
readOnlyContext = opts.readOnlyContext;
|
|
188
|
-
throttlingErrorChecker = opts.throttlingErrorChecker;
|
|
189
|
-
streamHandlers = opts.streamHandlers;
|
|
190
|
-
scopeProtectionMode = opts.scopeProtectionMode;
|
|
191
|
-
dials = pickDials(opts);
|
|
192
|
-
}
|
|
193
|
-
this.flowChartArgs = {
|
|
194
|
-
flowChart,
|
|
195
|
-
scopeFactory: scopeFactory ?? flowChart.scopeFactory ?? defaultScopeFactory,
|
|
196
|
-
defaultValuesForContext,
|
|
197
|
-
initialContext,
|
|
198
|
-
readOnlyContext,
|
|
199
|
-
throttlingErrorChecker,
|
|
200
|
-
streamHandlers,
|
|
201
|
-
scopeProtectionMode,
|
|
202
|
-
dials,
|
|
203
|
-
};
|
|
84
|
+
this.flowChartArgs = resolveExecutorArgs(flowChart, factoryOrOptions);
|
|
204
85
|
this.traverser = this.createTraverser();
|
|
205
86
|
}
|
|
206
87
|
createTraverser(signal, readOnlyContextOverride, env, maxDepth, maxIterations, overrides) {
|
|
207
88
|
const args = this.flowChartArgs;
|
|
208
89
|
const fc = args.flowChart;
|
|
209
|
-
const narrativeFlag = this.
|
|
210
|
-
// ── Composed scope factory ─────────────────────────────────────────
|
|
211
|
-
// Collect all scope modifiers (recorders, redaction) into a single list,
|
|
212
|
-
// then create ONE factory that applies them in a loop. Replaces the
|
|
213
|
-
// previous 4-deep closure nesting with a flat, debuggable composition.
|
|
214
|
-
if (overrides?.preserveRecorders) {
|
|
215
|
-
// Resume mode: keep existing combinedRecorder so narrative accumulates
|
|
216
|
-
}
|
|
217
|
-
else if (narrativeFlag) {
|
|
218
|
-
this.combinedRecorder = new CombinedNarrativeRecorder(this.narrativeOptions);
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
this.combinedRecorder = undefined;
|
|
222
|
-
}
|
|
90
|
+
const narrativeFlag = this.observers.startLeg(fc.enableNarrative ?? false, overrides?.preserveRecorders === true);
|
|
223
91
|
this.redactionRule = new RedactionRule(this.redactionPolicy);
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
const recorder = this.combinedRecorder;
|
|
228
|
-
modifiers.push((scope) => {
|
|
229
|
-
if (typeof scope.attachScopeRecorder === 'function')
|
|
230
|
-
scope.attachScopeRecorder(recorder);
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
// 2. User-provided scope recorders
|
|
234
|
-
if (this.scopeRecorders.length > 0) {
|
|
235
|
-
const recorders = this.scopeRecorders;
|
|
236
|
-
modifiers.push((scope) => {
|
|
237
|
-
if (typeof scope.attachScopeRecorder === 'function') {
|
|
238
|
-
for (const r of recorders)
|
|
239
|
-
scope.attachScopeRecorder(r);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
// 2b. Deferred-observer scope tap (RFC-001 Block 7) — a synthetic
|
|
244
|
-
// recorder whose hooks CAPTURE into the bounded queue instead of doing
|
|
245
|
-
// observer work. It rides the same per-stage recorder list as inline
|
|
246
|
-
// recorders, so it receives exactly the post-redaction events they do.
|
|
247
|
-
// Absent (zero work, identical list) when nobody opted into deferral.
|
|
248
|
-
const scopeTap = this.deferredTier?.buildScopeTap();
|
|
249
|
-
if (scopeTap) {
|
|
250
|
-
modifiers.push((scope) => {
|
|
251
|
-
if (typeof scope.attachScopeRecorder === 'function')
|
|
252
|
-
scope.attachScopeRecorder(scopeTap);
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
// 3. Redaction policy (conditional — only when policy is set). A
|
|
256
|
-
// `ScopeFacade` already reads the run's rule through its context (the
|
|
257
|
-
// rule is installed on the runtime root below); this call is the legacy
|
|
258
|
-
// protocol for custom scopes that are not facades, and on a facade it
|
|
259
|
-
// re-states the executor's policy on the shared rule (a no-op).
|
|
260
|
-
if (this.redactionPolicy) {
|
|
261
|
-
const policy = this.redactionPolicy;
|
|
262
|
-
modifiers.push((scope) => {
|
|
263
|
-
if (typeof scope.useRedactionPolicy === 'function') {
|
|
264
|
-
scope.useRedactionPolicy(policy);
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
// Compose: base factory + modifiers in a single pass.
|
|
269
|
-
// The marked-keys set is ALWAYS wired up (unconditional — ensures cross-stage
|
|
270
|
-
// propagation even without a policy, because stages can call setValue(key, val, true)
|
|
271
|
-
// for per-call redaction). Optional modifiers (recorders, policy) are in the list.
|
|
272
|
-
const baseFactory = args.scopeFactory;
|
|
273
|
-
const sharedRedactedKeys = this.redactionRule.markedKeys();
|
|
274
|
-
const scopeFactory = ((ctx, stageName, readOnly, envArg) => {
|
|
275
|
-
const scope = baseFactory(ctx, stageName, readOnly, envArg);
|
|
276
|
-
// Always wire shared redaction state
|
|
277
|
-
if (typeof scope.useSharedRedactedKeys === 'function') {
|
|
278
|
-
scope.useSharedRedactedKeys(sharedRedactedKeys);
|
|
279
|
-
}
|
|
280
|
-
// Apply optional modifiers
|
|
281
|
-
for (const mod of modifiers)
|
|
282
|
-
mod(scope);
|
|
283
|
-
return scope;
|
|
284
|
-
});
|
|
92
|
+
// ONE factory: the base factory, then every scope modifier (recorders,
|
|
93
|
+
// deferred tap, redaction) in a flat pass — see `RunObservers`.
|
|
94
|
+
const scopeFactory = this.observers.composeScopeFactory(args.scopeFactory, this.redactionPolicy, this.redactionRule.markedKeys());
|
|
285
95
|
// The first stage this traversal runs: the resume's entry, else the chart root.
|
|
286
96
|
const effectiveRoot = overrides?.resume?.start ?? fc.root;
|
|
287
97
|
const effectiveInitialContext = overrides?.initialContext ?? args.initialContext;
|
|
288
|
-
// The run's policy (F5): the
|
|
289
|
-
//
|
|
290
|
-
// (a
|
|
291
|
-
//
|
|
292
|
-
// included, holds the same reference. The rule is installed even without
|
|
293
|
-
// a policy: a per-call `setValue(key, value, true)` marks the key on it,
|
|
294
|
-
// and the paths that bypass the facade (subflow seed, outputMapper
|
|
295
|
-
// merge-back, resume re-seed) honour that mark through it. The mirror —
|
|
296
|
-
// a parallel redacted heap, so `getSnapshot({ redact: true })` is served
|
|
297
|
-
// at zero post-pass cost — is kept only under a policy.
|
|
98
|
+
// The run's policy (F5): the dials, the rule (installed even without a
|
|
99
|
+
// policy — per-call `setValue(k, v, true)` marks live on it) and the mirror
|
|
100
|
+
// flag (a redacted heap, kept only under a policy), ONE frozen object per
|
|
101
|
+
// leg that every frame of the run holds by reference.
|
|
298
102
|
const policy = runPolicy(args.dials, this.redactionRule, this.redactionPolicy !== undefined);
|
|
299
103
|
let runtime;
|
|
300
104
|
if (overrides?.existingRuntime) {
|
|
301
|
-
//
|
|
302
|
-
// Preserve the original root for getSnapshot() (full tree), then advance
|
|
303
|
-
// rootStageContext to a continuation from the leaf (for traversal).
|
|
105
|
+
// Same-executor resume: the tree continues from the leaf; getSnapshot() keeps the full tree.
|
|
304
106
|
runtime = overrides.existingRuntime;
|
|
305
107
|
runtime.preserveSnapshotRoot();
|
|
306
108
|
let leaf = runtime.rootStageContext;
|
|
@@ -313,9 +115,7 @@ export class FlowChartExecutor {
|
|
|
313
115
|
runtime = new ExecutionRuntime(effectiveRoot.name, effectiveRoot.id, args.defaultValuesForContext, effectiveInitialContext, policy);
|
|
314
116
|
}
|
|
315
117
|
return new FlowchartTraverser({
|
|
316
|
-
// Always the REAL chart
|
|
317
|
-
// paused stage) resolves against it. A resume only moves where the
|
|
318
|
-
// traversal STARTS (`entry`), once.
|
|
118
|
+
// Always the REAL chart; a resume only moves where the traversal STARTS, once.
|
|
319
119
|
root: fc.root,
|
|
320
120
|
...(overrides?.resume?.start && { entry: overrides.resume.start }),
|
|
321
121
|
...(overrides?.resume?.startPendingPauses && { pendingPauses: overrides.resume.startPendingPauses }),
|
|
@@ -333,7 +133,7 @@ export class FlowChartExecutor {
|
|
|
333
133
|
logger: fc.logger ?? defaultLogger,
|
|
334
134
|
signal,
|
|
335
135
|
executionEnv: env,
|
|
336
|
-
flowRecorders: this.
|
|
136
|
+
flowRecorders: this.observers.flowRecordersList(),
|
|
337
137
|
executionCounter: this._executionCounter,
|
|
338
138
|
visitCounts: this._visitCounts,
|
|
339
139
|
runId: this._currentRunId,
|
|
@@ -342,9 +142,7 @@ export class FlowChartExecutor {
|
|
|
342
142
|
});
|
|
343
143
|
}
|
|
344
144
|
enableNarrative(options) {
|
|
345
|
-
this.
|
|
346
|
-
if (options)
|
|
347
|
-
this.narrativeOptions = options;
|
|
145
|
+
this.observers.enableNarrative(options);
|
|
348
146
|
}
|
|
349
147
|
/**
|
|
350
148
|
* Set a declarative redaction policy that applies to all stages.
|
|
@@ -354,32 +152,15 @@ export class FlowChartExecutor {
|
|
|
354
152
|
this.redactionPolicy = policy;
|
|
355
153
|
this.redactionRule = new RedactionRule(policy);
|
|
356
154
|
}
|
|
357
|
-
/**
|
|
358
|
-
* Set the read-tracking policy for `StageSnapshot.stageReads` (#14).
|
|
359
|
-
* Must be called before run(). Equivalent to the `readTracking`
|
|
360
|
-
* constructor option — see {@link FlowChartExecutorOptions.readTracking}
|
|
361
|
-
* for the mode semantics ('full' default / 'summary' / 'off').
|
|
362
|
-
*/
|
|
155
|
+
/** The `readTracking` dial (see {@link FlowChartExecutorOptions.readTracking}). Call before run(). */
|
|
363
156
|
setReadTracking(mode) {
|
|
364
157
|
this.flowChartArgs.dials = { ...this.flowChartArgs.dials, readTracking: mode };
|
|
365
158
|
}
|
|
366
|
-
/**
|
|
367
|
-
* Set the write-tracking policy for `StageSnapshot.stageWrites` (#13c-A).
|
|
368
|
-
* Must be called before run(). Equivalent to the `writeTracking`
|
|
369
|
-
* constructor option — see {@link FlowChartExecutorOptions.writeTracking}
|
|
370
|
-
* for the mode semantics ('full' default / 'summary' / 'off'), the
|
|
371
|
-
* onCommit-payload consequence, and the redaction-precedence rule.
|
|
372
|
-
*/
|
|
159
|
+
/** The `writeTracking` dial (see {@link FlowChartExecutorOptions.writeTracking}). Call before run(). */
|
|
373
160
|
setWriteTracking(mode) {
|
|
374
161
|
this.flowChartArgs.dials = { ...this.flowChartArgs.dials, writeTracking: mode };
|
|
375
162
|
}
|
|
376
|
-
/**
|
|
377
|
-
* Set the commit-values encoding policy for the commit log (#13c-B).
|
|
378
|
-
* Must be called before run(). Equivalent to the `commitValues`
|
|
379
|
-
* constructor option — see {@link FlowChartExecutorOptions.commitValues}
|
|
380
|
-
* for the mode semantics ('full' default / 'delta'), the verb-qualified
|
|
381
|
-
* `overwrite` consequence, and the `commitValueAt` migration helper.
|
|
382
|
-
*/
|
|
163
|
+
/** The `commitValues` dial (see {@link FlowChartExecutorOptions.commitValues}). Call before run(). */
|
|
383
164
|
setCommitValues(mode) {
|
|
384
165
|
this.flowChartArgs.dials = { ...this.flowChartArgs.dials, commitValues: mode };
|
|
385
166
|
}
|
|
@@ -395,12 +176,9 @@ export class FlowChartExecutor {
|
|
|
395
176
|
* Returns the checkpoint from the most recent paused execution, or `undefined`
|
|
396
177
|
* if the last run completed without pausing.
|
|
397
178
|
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* pause time (see `buildPauseCheckpoint`). Holding, mutating, or persisting
|
|
402
|
-
* it cannot affect the executor, and a later same-executor resume cannot
|
|
403
|
-
* mutate a checkpoint you already stored.
|
|
179
|
+
* JSON-serializable (store it in Redis, Postgres, localStorage…) and fully
|
|
180
|
+
* DETACHED from engine state (`checkpoint.ts`): mutating or persisting it
|
|
181
|
+
* cannot affect the executor, nor a later resume a checkpoint you stored.
|
|
404
182
|
*
|
|
405
183
|
* @example
|
|
406
184
|
* ```typescript
|
|
@@ -427,14 +205,8 @@ export class FlowChartExecutor {
|
|
|
427
205
|
*
|
|
428
206
|
* Returns 0 before any run; after, returns the cumulative commit
|
|
429
207
|
* count across the executor's lifetime (including resumes).
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* which is the same value as `getSnapshot().commitLog.length`. The
|
|
433
|
-
* naming asymmetry is historical — the underlying `EventLog` field
|
|
434
|
-
* is named `executionHistory` but stores the `CommitBundle[]` that
|
|
435
|
-
* `commitLog` exposes. They always report the same LENGTH (verified by the
|
|
436
|
-
* "matches commitLog.length" integration test); since 9.17.0 the snapshot
|
|
437
|
-
* serves a detached frozen COPY of the array, not the live one.
|
|
208
|
+
* Always equals `getSnapshot().commitLog.length` (the log is the
|
|
209
|
+
* `EventLog`'s `executionHistory`; the snapshot serves a frozen copy).
|
|
438
210
|
*/
|
|
439
211
|
getCommitCount() {
|
|
440
212
|
const runtime = this.traverser.getRuntime();
|
|
@@ -443,25 +215,16 @@ export class FlowChartExecutor {
|
|
|
443
215
|
/**
|
|
444
216
|
* Resume a paused flowchart from a checkpoint.
|
|
445
217
|
*
|
|
446
|
-
* Restores the scope state,
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
* (`checkpoint.pendingPauses`), the run pauses again with the next sibling's
|
|
453
|
-
* question once this one's branch is done; the fan-out's join runs after the
|
|
454
|
-
* last answer. See `ResumeEntry` (`footprintjs/advanced`).
|
|
455
|
-
*
|
|
456
|
-
* The checkpoint can come from `getCheckpoint()` on a previous run, or from
|
|
457
|
-
* a serialized checkpoint stored in Redis/Postgres/localStorage.
|
|
218
|
+
* Restores the scope state, runs the paused stage's `resumeFn` with the input
|
|
219
|
+
* (an `interrupt()` pause re-runs the stage with the answer), then continues
|
|
220
|
+
* with whatever ran after that stage on the run — its `next`, or its
|
|
221
|
+
* dispatcher's continuation, at every level of the pause path. Parallel
|
|
222
|
+
* siblings that paused together (`checkpoint.pendingPauses`) are asked in
|
|
223
|
+
* turn; the join runs after the last answer. See `ResumeEntry`.
|
|
458
224
|
*
|
|
459
|
-
*
|
|
460
|
-
* executor
|
|
461
|
-
*
|
|
462
|
-
* (reconstructed from a stored checkpoint) starts with empty recorder state —
|
|
463
|
-
* collect what you need before discarding the paused executor. A fresh `runId`
|
|
464
|
-
* is generated either way.
|
|
225
|
+
* The checkpoint comes from `getCheckpoint()` or from storage. On the SAME
|
|
226
|
+
* executor, narrative/recorder state accumulates across the pause; on a
|
|
227
|
+
* FRESH executor it starts empty. A fresh `runId` either way.
|
|
465
228
|
*
|
|
466
229
|
* @example
|
|
467
230
|
* ```typescript
|
|
@@ -476,602 +239,125 @@ export class FlowChartExecutor {
|
|
|
476
239
|
* ```
|
|
477
240
|
*/
|
|
478
241
|
async resume(checkpoint, resumeInput, options) {
|
|
479
|
-
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
// ── Decode the checkpoint (may come from untrusted external storage, from
|
|
488
|
-
// any release) — the ONE codec: upcast, then check every pause record
|
|
489
|
-
// (`pause/record.ts`). (lastCheckpoint is wiped AFTER this — a rejected
|
|
490
|
-
// checkpoint must not destroy the executor's existing checkpoint state.)
|
|
491
|
-
checkpoint = decodeCheckpoint(checkpoint);
|
|
492
|
-
// Find the paused node in the graph
|
|
493
|
-
const pausedNode = this.findNodeInGraph(checkpoint.pausedStageId, checkpoint.subflowPath);
|
|
494
|
-
if (!pausedNode) {
|
|
495
|
-
throw new Error(`Cannot resume: stage '${checkpoint.pausedStageId}' not found in flowchart. ` +
|
|
496
|
-
'The chart may have changed since the checkpoint was created.');
|
|
497
|
-
}
|
|
498
|
-
// Two re-entry shapes, chosen by HOW the pause was raised:
|
|
499
|
-
//
|
|
500
|
-
// • interrupt() → RE-RUN THE STAGE'S OWN FUNCTION FROM ITS TOP.
|
|
501
|
-
// Stages are atomic (the same law `resumeOnError` states): a stage that
|
|
502
|
-
// stopped mid-body has no half to resume into, so the whole body runs
|
|
503
|
-
// again and the answer comes back out of the `interrupt()` call itself.
|
|
504
|
-
// Everything the body did before the interrupt is re-done — which is
|
|
505
|
-
// why the docs tell you to keep that half idempotent.
|
|
506
|
-
// • addPausableFunction → run the declared `resumeFn`.
|
|
507
|
-
//
|
|
508
|
-
// The discriminant is on the checkpoint, so this works cross-executor
|
|
509
|
-
// (a checkpoint restored from Redis on a fresh process resumes the same way).
|
|
510
|
-
const isInterruptResume = checkpoint.pausedBy === 'interrupt';
|
|
511
|
-
if (!pausedNode.resumeFn && !isInterruptResume) {
|
|
512
|
-
throw new Error(`Cannot resume: stage '${pausedNode.name}' (${pausedNode.id}) has no resumeFn. ` +
|
|
513
|
-
'Only stages created with addPausableFunction(), or stages that paused via interrupt(), can be resumed.');
|
|
514
|
-
}
|
|
515
|
-
// The resume half — what the paused stage's stand-in runs.
|
|
516
|
-
// resumeFn signature is (scope, input) per PausableHandler — wrap to match StageFunction(scope, breakFn).
|
|
517
|
-
let resumeStageFn;
|
|
518
|
-
if (isInterruptResume) {
|
|
519
|
-
const originalFn = pausedNode.fn ??
|
|
520
|
-
this.flowChartArgs.flowChart.stageMap.get(pausedNode.id) ??
|
|
521
|
-
this.flowChartArgs.flowChart.stageMap.get(pausedNode.name);
|
|
522
|
-
if (!originalFn) {
|
|
523
|
-
throw new Error(`Cannot resume: stage '${pausedNode.name}' (${pausedNode.id}) paused via interrupt() but its ` +
|
|
524
|
-
'stage function is no longer in the chart. The chart may have changed since the checkpoint ' +
|
|
525
|
-
'was created.');
|
|
526
|
-
}
|
|
527
|
-
resumeStageFn = (scope, breakFn, streamCallback) => {
|
|
528
|
-
// Deposit the answer for THIS scope instance before the body runs, so
|
|
529
|
-
// the `interrupt()` call that threw last time returns it this time.
|
|
530
|
-
// Keyed by scope identity — safe when several branches resume at once.
|
|
531
|
-
provideInterruptAnswer(scope, resumeInput);
|
|
532
|
-
return originalFn(scope, breakFn, streamCallback);
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
else {
|
|
536
|
-
const resumeFn = pausedNode.resumeFn;
|
|
537
|
-
resumeStageFn = (scope) => {
|
|
538
|
-
return resumeFn(scope, resumeInput);
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
// The paused stage's STAND-IN: the stage's OWN node — id, name,
|
|
542
|
-
// description, tags, and its shape (a decider's branches, a selector's, a
|
|
543
|
-
// fork parent's children, its `next`) — with its function swapped for the
|
|
544
|
-
// resume half. Built from the whole node so an `interrupt()` raised inside
|
|
545
|
-
// a decider, selector or fork-parent function DISPATCHES on resume, as the
|
|
546
|
-
// stage did on the run (before 9.28.0 only fn/next/tags/retry were copied
|
|
547
|
-
// and the dispatch was silently skipped). It is where the resumed
|
|
548
|
-
// traversal starts — and nothing else: it is never in a node map or the
|
|
549
|
-
// subflow dictionary, so a loop back to the paused id finds the REAL
|
|
550
|
-
// stage, which pauses again (see ResumeEntry). What runs after it — its
|
|
551
|
-
// own `next`, else its dispatcher's continuation — is attached by
|
|
552
|
-
// `ResumeEntry.plan`, from the chart.
|
|
553
|
-
const standIn = standInFor(pausedNode, resumeStageFn, isInterruptResume);
|
|
554
|
-
// Where the resume re-enters, planned against the chart as built:
|
|
555
|
-
//
|
|
556
|
-
// • TOP-LEVEL PAUSE (subflowPath empty): the resumed traversal starts
|
|
557
|
-
// at the stand-in.
|
|
558
|
-
// • PAUSE INSIDE SUBFLOWS: it starts at the mount of the first subflow
|
|
559
|
-
// on the path, so the outputMappers and the parent's continuation
|
|
560
|
-
// run. Each subflow on the path is entered ONCE through its hop: its
|
|
561
|
-
// nested runtime is seeded from its capture (in place of the
|
|
562
|
-
// inputMapper's values) and its traversal starts at the mount of the
|
|
563
|
-
// next subflow — or, at the leaf, at the stand-in. An outer subflow's
|
|
564
|
-
// stages before that mount do not run again.
|
|
565
|
-
// • AT EVERY LEVEL the entry carries what its dispatcher would have run
|
|
566
|
-
// after it — a decider's `next`, a selector's, a fork's join — so a
|
|
567
|
-
// subflow mounted as a branch or a fork child hands control back to
|
|
568
|
-
// its parent's continuation at the parent's level.
|
|
569
|
-
// • Parallel siblings that paused in the same fan-out wait in
|
|
570
|
-
// `checkpoint.pendingPauses`: each is raised again in turn, and the
|
|
571
|
-
// join runs only once the last one is resumed.
|
|
572
|
-
//
|
|
573
|
-
// Everything else walks the REAL chart: `fc.root` and `fc.subflows` are
|
|
574
|
-
// untouched, so every later loop target and every later subflow entry
|
|
575
|
-
// (real root, inputMapper) resolves as it would on a run. Refused HERE —
|
|
576
|
-
// before any state is touched — when the checkpoint's path does not fit
|
|
577
|
-
// this chart.
|
|
578
|
-
//
|
|
579
|
-
// Clone-in: the captures seed nested runtimes (shallow-merged into each
|
|
580
|
-
// nested SharedMemory), so without a copy the engine would hold live
|
|
581
|
-
// references into the caller's checkpoint object — caller mutations would
|
|
582
|
-
// bleed into the resumed run and engine writes would reach a checkpoint
|
|
583
|
-
// the caller may have already persisted. The same for the waiting
|
|
584
|
-
// siblings' captures.
|
|
585
|
-
const fc = this.flowChartArgs.flowChart;
|
|
586
|
-
const resumeEntry = ResumeEntry.plan({
|
|
587
|
-
root: fc.root,
|
|
588
|
-
subflows: fc.subflows,
|
|
589
|
-
path: checkpoint.subflowPath,
|
|
590
|
-
captures: structuredClone(checkpoint.subflowStates),
|
|
591
|
-
standIn,
|
|
592
|
-
...(checkpoint.pendingPauses !== undefined && { pendingPauses: structuredClone(checkpoint.pendingPauses) }),
|
|
593
|
-
});
|
|
594
|
-
// ── Seed the shared execution counter + per-stage visit counts ──
|
|
595
|
-
//
|
|
596
|
-
// Only now — every refusal above (the checkpoint's shape, the paused
|
|
597
|
-
// stage, the plan) leaves the executor exactly as it was. MUST run before
|
|
598
|
-
// the counter is READ below (the stand-in's runtimeStageId for
|
|
599
|
-
// `onResume`) AND before createTraverser() hands the traverser these
|
|
600
|
-
// objects BY REFERENCE. Seeding keeps runtimeStageIds unique and
|
|
601
|
-
// loopIteration monotonic across a CROSS-executor resume (a fresh
|
|
602
|
-
// executor starts both at 0/empty; the checkpoint carries the pause-time
|
|
603
|
-
// values).
|
|
604
|
-
//
|
|
605
|
-
// MUTATE, never REPLACE: `_executionCounter` and `_visitCounts` are shared
|
|
606
|
-
// by reference into the traverser (and, transitively, every subflow
|
|
607
|
-
// traverser — see FlowchartTraverser's sub-traverser factory). Assigning a
|
|
608
|
-
// fresh object here would sever that shared reference. Both fields are
|
|
609
|
-
// optional on the checkpoint (older persisted checkpoints omit them) — skip
|
|
610
|
-
// seeding when absent, preserving the previous behavior. Same-executor
|
|
611
|
-
// resume is idempotent: at pause the instance values already equal the
|
|
612
|
-
// checkpoint's, so re-seeding them changes nothing.
|
|
613
|
-
if (checkpoint.executionCount !== undefined) {
|
|
614
|
-
this._executionCounter.value = checkpoint.executionCount;
|
|
615
|
-
}
|
|
616
|
-
if (checkpoint.visitCounts) {
|
|
617
|
-
this._visitCounts.clear();
|
|
618
|
-
for (const [stageId, count] of Object.entries(checkpoint.visitCounts)) {
|
|
619
|
-
this._visitCounts.set(stageId, count);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
// (Wiped only now: every refusal above leaves the executor's existing
|
|
623
|
-
// checkpoint untouched.)
|
|
242
|
+
this.assertIdle('resume');
|
|
243
|
+
// Every refusal happens in the plan — before any state below is touched,
|
|
244
|
+
// so a rejected checkpoint leaves the executor (and its checkpoint) as it was.
|
|
245
|
+
const plan = planResume(this.flowChartArgs.flowChart, checkpoint, resumeInput);
|
|
246
|
+
// MUST precede the counter read in `announceResume` and the traverser,
|
|
247
|
+
// which takes both counters BY REFERENCE.
|
|
248
|
+
seedCounters(plan.checkpoint, this._executionCounter, this._visitCounts);
|
|
624
249
|
this.lastCheckpoint = undefined;
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
|
|
628
|
-
// Two-mode resume:
|
|
629
|
-
// • Same-executor (run() previously called on THIS instance):
|
|
630
|
-
// reuse the existing runtime so the execution tree continues
|
|
631
|
-
// from the pause point and recorders/narrative accumulate.
|
|
632
|
-
// • Cross-executor (fresh executor reconstructed from a stored
|
|
633
|
-
// checkpoint): seed a NEW runtime from `checkpoint.sharedState`
|
|
634
|
-
// so resume handlers can read pre-pause scope. The execution
|
|
635
|
-
// tree starts at the resume entry — we don't have the previous
|
|
636
|
-
// traversal's tree on a fresh process anyway.
|
|
637
|
-
const sameExecutor = this._hasRunBefore;
|
|
638
|
-
const existingRuntime = sameExecutor
|
|
250
|
+
// Same executor: reuse the runtime. Fresh executor: seed a NEW one from
|
|
251
|
+
// `checkpoint.sharedState`. Either way a NEW runId (a distinct logical run).
|
|
252
|
+
const existingRuntime = this._hasRunBefore
|
|
639
253
|
? this.traverser.getRuntime()
|
|
640
254
|
: undefined;
|
|
641
255
|
this._hasRunBefore = true; // any path that resumes counts as a run
|
|
642
|
-
// Resume gets a NEW runId — resume is logically a distinct run.
|
|
643
|
-
// Original runId is recoverable from checkpoint metadata if a consumer
|
|
644
|
-
// needs cross-run audit (we don't store it on the checkpoint today;
|
|
645
|
-
// future enhancement). See `runId.ts`.
|
|
646
256
|
this._currentRunId = generateRunId();
|
|
647
|
-
// Initial context: `checkpoint.sharedState` — the top level's view at the
|
|
648
|
-
// pause (a subflow's outputMapper writes back into it). Same-executor, the
|
|
649
|
-
// existing runtime is reused and this is moot, but passed for consistency.
|
|
650
|
-
// Clone-in for the same reason as the captures: `initialContext` seeds
|
|
651
|
-
// the fresh SharedMemory via `mergeContextWins`, which copies only the TOP
|
|
652
|
-
// level — nested objects would alias the caller's checkpoint.
|
|
653
|
-
const resumeInitialContext = structuredClone(checkpoint.sharedState);
|
|
654
257
|
this.traverser = this.createTraverser(options?.signal, undefined, options?.env, options?.maxDepth, options?.maxIterations, {
|
|
655
|
-
|
|
258
|
+
// Clone-in: `initialContext` seeds the fresh SharedMemory with a
|
|
259
|
+
// top-level-only merge — nested objects would alias the caller's checkpoint.
|
|
260
|
+
initialContext: structuredClone(plan.checkpoint.sharedState),
|
|
656
261
|
preserveRecorders: true,
|
|
657
262
|
...(existingRuntime ? { existingRuntime } : {}),
|
|
658
|
-
resume:
|
|
263
|
+
resume: plan.entry,
|
|
264
|
+
});
|
|
265
|
+
// Before the traversal on purpose: `onResume` precedes `onRunStart`.
|
|
266
|
+
announceResume(plan, resumeInput, {
|
|
267
|
+
runId: this._currentRunId,
|
|
268
|
+
executionCount: this._executionCounter.value,
|
|
269
|
+
observers: this.observers,
|
|
659
270
|
});
|
|
660
|
-
// Fire onResume event on all recorders (flow + scope). Stamp the
|
|
661
|
-
// synthetic TraversalContext for the resumed stage with the NEW
|
|
662
|
-
// runId so consumers detect "this is a fresh logical run" via
|
|
663
|
-
// the same runId-change pattern they use for `onRunStart`. The stamp is
|
|
664
|
-
// built by the one constructor (`engine/traversalContext.ts`): it names the
|
|
665
|
-
// REAL subflow the stand-in runs in and its depth, and LINKS to the paused
|
|
666
|
-
// execution (`resumedFrom`, read off `checkpoint.pausedExecution`) — 9.37.0.
|
|
667
|
-
//
|
|
668
|
-
// The runtimeStageId is the STAND-IN's own: it runs after one mount per
|
|
669
|
-
// subflow on the path (each entered at its mount), so its execution index
|
|
670
|
-
// is the counter plus the path's length — the event and the stand-in's
|
|
671
|
-
// commit name the same execution. (Fired before the traversal on purpose:
|
|
672
|
-
// `onResume` precedes `onRunStart`, which recorders rely on to adopt the
|
|
673
|
-
// new runId without resetting.) The one shape where the index cannot be
|
|
674
|
-
// known up front — a degraded checkpoint missing an OUTER subflow's
|
|
675
|
-
// capture, whose opening stages then re-run — names the planned position.
|
|
676
|
-
const hasInput = resumeInput !== undefined;
|
|
677
|
-
const stepsBeforeStandIn = resumeEntry.stepsBeforeStandIn ?? checkpoint.subflowPath.length;
|
|
678
|
-
const resumeRuntimeStageId = buildRuntimeStageId(pausedNode.id, this._executionCounter.value + stepsBeforeStandIn);
|
|
679
|
-
const resumedFrom = resumeLinkOf(checkpoint);
|
|
680
|
-
const flowResumeEvent = {
|
|
681
|
-
stageName: pausedNode.name,
|
|
682
|
-
stageId: pausedNode.id,
|
|
683
|
-
hasInput,
|
|
684
|
-
traversalContext: resumeTraversalContext({
|
|
685
|
-
runId: this._currentRunId,
|
|
686
|
-
stageId: pausedNode.id,
|
|
687
|
-
stageName: pausedNode.name,
|
|
688
|
-
runtimeStageId: resumeRuntimeStageId,
|
|
689
|
-
subflowPath: checkpoint.subflowPath,
|
|
690
|
-
resumedFrom,
|
|
691
|
-
}),
|
|
692
|
-
channel: 'flow',
|
|
693
|
-
};
|
|
694
|
-
// Executor-made (`HOOKS.onResume.executorMade`): fired through the same `fire` loop as every
|
|
695
|
-
// engine event, so a throwing recorder is isolated instead of rejecting `resume()` (R10).
|
|
696
|
-
const flowListeners = this.combinedRecorder ? [this.combinedRecorder, ...this.flowRecorders] : this.flowRecorders;
|
|
697
|
-
fire(flowListeners, 'onResume', flowResumeEvent, RESUME_FLOW_FAILURE);
|
|
698
|
-
const scopeResumeEvent = {
|
|
699
|
-
stageName: pausedNode.name,
|
|
700
|
-
stageId: pausedNode.id,
|
|
701
|
-
runtimeStageId: resumeRuntimeStageId,
|
|
702
|
-
hasInput,
|
|
703
|
-
...(resumedFrom && { resumedFrom }),
|
|
704
|
-
pipelineId: '',
|
|
705
|
-
timestamp: Date.now(),
|
|
706
|
-
channel: 'scope',
|
|
707
|
-
};
|
|
708
|
-
fire(this.scopeRecorders, 'onResume', scopeResumeEvent, (error, _recorder, hook) =>
|
|
709
|
-
// The scope channel's policy (as `ScopeFacade` routes a stage's hook failure): the throw
|
|
710
|
-
// becomes an `onError` on every scope recorder, whose own throw is dropped.
|
|
711
|
-
fire(this.scopeRecorders, 'onError', recorderFailureEvent(scopeResumeEvent, error, hook)));
|
|
712
|
-
// Deferred tier (RFC-001): these executor-synthesized onResume events
|
|
713
|
-
// bypass the per-stage dispatch sites, so capture them directly.
|
|
714
|
-
if (this.deferredTier) {
|
|
715
|
-
this.deferredTier.capture('flow', 'onResume', resumeRuntimeStageId, this._currentRunId, flowResumeEvent);
|
|
716
|
-
this.deferredTier.capture('scope', 'onResume', scopeResumeEvent.runtimeStageId, scopeResumeEvent.pipelineId, scopeResumeEvent);
|
|
717
|
-
}
|
|
718
271
|
// Set AFTER all sync validation/lookup throws above (nothing can leak the
|
|
719
272
|
// flag); no await between the top-of-method check and here, so race-free.
|
|
720
273
|
this._isExecuting = true;
|
|
721
274
|
try {
|
|
722
275
|
const result = await this.traverser.execute();
|
|
723
276
|
// Terminal flush (RFC-001 Block 8) — same boundary contract as run().
|
|
724
|
-
this.deferredTier?.terminalFlush();
|
|
277
|
+
this.observers.deferredTier?.terminalFlush();
|
|
725
278
|
return result;
|
|
726
279
|
}
|
|
727
280
|
catch (error) {
|
|
728
|
-
this.
|
|
729
|
-
if (isPauseSignal(error)) {
|
|
730
|
-
this.lastCheckpoint = this.buildPauseCheckpoint(error);
|
|
731
|
-
return { paused: true, checkpoint: this.lastCheckpoint };
|
|
732
|
-
}
|
|
733
|
-
throw error;
|
|
281
|
+
return this.pausedOrThrow(error);
|
|
734
282
|
}
|
|
735
283
|
finally {
|
|
736
284
|
this._isExecuting = false;
|
|
737
285
|
}
|
|
738
286
|
}
|
|
739
287
|
/**
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
* checkpoint
|
|
744
|
-
*
|
|
745
|
-
* - `sharedState` IS `SharedMemory`'s current generation — never edited,
|
|
746
|
-
* but (copy-on-write, 9.29.0) every later generation shares its
|
|
747
|
-
* unchanged subtrees, so a checkpoint that aliased it would alias the
|
|
748
|
-
* resumed run's state too.
|
|
749
|
-
* - `executionTree` nodes are fresh, but their `logs`/`errors`/`metrics`/
|
|
750
|
-
* `evals`/`stageReads`/`flowMessages` fields reference live
|
|
751
|
-
* `DiagnosticCollector` bags that keep accumulating on same-executor
|
|
752
|
-
* resume.
|
|
753
|
-
* - `subflowStates` values are shallow copies whose NESTED objects alias
|
|
754
|
-
* subflow memory, and they get seeded back into live runtimes on resume.
|
|
755
|
-
* - `subflowResults` values stay referenced by the traverser's results map.
|
|
756
|
-
*
|
|
757
|
-
* The checkpoint is persisted by contract ("store in Redis/Postgres") — it
|
|
758
|
-
* must never share structure with the engine. Pause is not a hot path; the
|
|
759
|
-
* clone cost is irrelevant.
|
|
760
|
-
*
|
|
761
|
-
* The JSON-safe checkpoint contract (no functions, no class instances)
|
|
762
|
-
* governs CONSUMER-owned data — but the executionTree's diagnostic bags
|
|
763
|
-
* accept ANY value at write time without cloning ($debug/$error/$metric/
|
|
764
|
-
* $eval store raw references), so a contract-compliant run can still carry
|
|
765
|
-
* a non-cloneable diagnostic. Observability side-bags never abort traversal
|
|
766
|
-
* anywhere else in the library, so they must not abort the pause either:
|
|
767
|
-
* on clone failure we sanitize the diagnostic bags (non-cloneable values
|
|
768
|
-
* become '[non-serializable: …]' markers — the live engine bags are never
|
|
769
|
-
* touched) and retry. If the retry STILL fails, the violation is in
|
|
770
|
-
* consumer-owned data (realistically `pauseData` — a function can never
|
|
771
|
-
* reach shared state in the first place: TransactionBuffer clones every
|
|
772
|
-
* written value at write time, so the offending write already rejected)
|
|
773
|
-
* and we throw a DESCRIPTIVE contract error naming the offending
|
|
774
|
-
* checkpoint field(s). A naked DataCloneError never escapes.
|
|
775
|
-
*
|
|
776
|
-
* Subflow scope capture (`subflowStates`) survives ONLY on the signal — the
|
|
777
|
-
* nested runtimes are GC'd as the stack unwinds. Promoting it onto the
|
|
778
|
-
* checkpoint here lets cross-executor resume restore pre-pause subflow
|
|
779
|
-
* scope (e.g. an Agent's `scope.history`). Empty `{}` for root-level pauses.
|
|
780
|
-
*/
|
|
781
|
-
buildPauseCheckpoint(signal) {
|
|
782
|
-
// Every pause that paused in THIS run is named by it; a sibling raised again
|
|
783
|
-
// on resume keeps the run it originally paused in.
|
|
784
|
-
signal.completeExecution(this._currentRunId);
|
|
785
|
-
const snapshot = this.traverser.getSnapshot();
|
|
786
|
-
const sfResults = this.traverser.getSubflowResults();
|
|
787
|
-
// Lean subflowResults for the checkpoint (design: docs/design/subflow-commit-visibility.md):
|
|
788
|
-
// • DROP the per-iteration mount-runtimeStageId keys ('#') that the snapshot dual-keys —
|
|
789
|
-
// they would DOUBLE the checkpoint, and resume restores scope from `subflowStates`, not these.
|
|
790
|
-
// • STRIP each subflow's `treeContext.history` — resume NEVER reads `subflowResults` (it
|
|
791
|
-
// restores from `subflowStates` + `sharedState`), so the per-subflow commit log is pure
|
|
792
|
-
// checkpoint bloat. The flat agent's checkpoint carries no commit history either → symmetric.
|
|
793
|
-
const leanSubflowResults = {};
|
|
794
|
-
for (const [key, value] of sfResults) {
|
|
795
|
-
if (isExecutionKey(key))
|
|
796
|
-
continue; // per-iteration keys are snapshot-only
|
|
797
|
-
const v = value;
|
|
798
|
-
if (v?.treeContext) {
|
|
799
|
-
const treeCtxRest = {};
|
|
800
|
-
for (const ck of Object.keys(v.treeContext)) {
|
|
801
|
-
if (ck !== 'history')
|
|
802
|
-
treeCtxRest[ck] = v.treeContext[ck]; // strip the per-subflow commit log
|
|
803
|
-
}
|
|
804
|
-
leanSubflowResults[key] = { ...value, treeContext: treeCtxRest };
|
|
805
|
-
}
|
|
806
|
-
else {
|
|
807
|
-
leanSubflowResults[key] = value;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
const checkpoint = {
|
|
811
|
-
// The format (9.39.0) — read back by `pause/record.ts · decodeCheckpoint`.
|
|
812
|
-
checkpointVersion: CHECKPOINT_VERSION,
|
|
813
|
-
sharedState: snapshot.sharedState,
|
|
814
|
-
executionTree: snapshot.executionTree,
|
|
815
|
-
pausedStageId: signal.stageId,
|
|
816
|
-
// The paused EXECUTION (9.37.0) — a queued sibling raised on resume
|
|
817
|
-
// carries the run it ORIGINALLY paused in.
|
|
818
|
-
...(signal.pausedExecution && { pausedExecution: signal.pausedExecution }),
|
|
819
|
-
subflowPath: signal.subflowPath,
|
|
820
|
-
pauseData: signal.pauseData,
|
|
821
|
-
subflowStates: signal.subflowStates,
|
|
822
|
-
// Counter continuity — seeded back in resume() so runtimeStageIds stay
|
|
823
|
-
// unique and loopIteration stays monotonic across a CROSS-executor resume
|
|
824
|
-
// (both are plain number/record, so they ride the single structuredClone
|
|
825
|
-
// below untouched). See test/lib/pause/resume-execution-counter-continuity.test.ts.
|
|
826
|
-
executionCount: this._executionCounter.value,
|
|
827
|
-
visitCounts: Object.fromEntries(this._visitCounts),
|
|
828
|
-
...(Object.keys(leanSubflowResults).length > 0 && { subflowResults: leanSubflowResults }),
|
|
829
|
-
// Invoker context — collected during traversal bubble-up (not tree-walked).
|
|
830
|
-
// (`continuationStageId` is legacy-only since 9.39.0: no longer written.)
|
|
831
|
-
...(signal.invokerStageId && { invokerStageId: signal.invokerStageId }),
|
|
832
|
-
// Parallel siblings' pauses from the same fan-out, waiting their turn
|
|
833
|
-
// (9.28.0). Absent when only one child paused — the shape every
|
|
834
|
-
// earlier checkpoint has.
|
|
835
|
-
...(signal.pendingPauses.length > 0 && { pendingPauses: signal.pendingPauses }),
|
|
836
|
-
// HOW the pause was raised. One checkpoint shape, one extra optional
|
|
837
|
-
// field — an interrupt() pause is not a second kind of checkpoint, it is
|
|
838
|
-
// the same checkpoint that resume() re-enters differently (stage top vs
|
|
839
|
-
// resumeFn). Absent for every pre-9.14.0 checkpoint, which is correct.
|
|
840
|
-
...(signal.pausedBy && { pausedBy: signal.pausedBy }),
|
|
841
|
-
pausedAt: Date.now(),
|
|
842
|
-
};
|
|
843
|
-
try {
|
|
844
|
-
return structuredClone(checkpoint);
|
|
845
|
-
}
|
|
846
|
-
catch {
|
|
847
|
-
// Non-cloneable diagnostics must not swallow the pause — sanitize the
|
|
848
|
-
// executionTree's bags (markers replace the offenders) and retry.
|
|
849
|
-
try {
|
|
850
|
-
checkpoint.executionTree = sanitizeDiagnosticBags(checkpoint.executionTree);
|
|
851
|
-
return structuredClone(checkpoint);
|
|
852
|
-
}
|
|
853
|
-
catch (retryError) {
|
|
854
|
-
// Genuine JSON-safe contract violation in consumer-owned data.
|
|
855
|
-
throw describeCheckpointCloneFailure(checkpoint, retryError);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
/**
|
|
860
|
-
* Find a StageNode in the compiled graph by ID.
|
|
861
|
-
* Handles subflow paths by drilling into registered subflows.
|
|
288
|
+
* The settle of a leg that threw: flush the deferred tier (the OUTERMOST
|
|
289
|
+
* handler — a pause re-throws through subflow traversers without exit
|
|
290
|
+
* events, so per-traverser hooks would miss it), then turn a pause into a
|
|
291
|
+
* detached checkpoint (`checkpoint.ts`) and a `PausedResult`; anything else
|
|
292
|
+
* is rethrown.
|
|
862
293
|
*/
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
if (
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
const subflow = fc.subflows?.[sfId];
|
|
873
|
-
if (!subflow)
|
|
874
|
-
return undefined;
|
|
875
|
-
subflowRoot = subflow.root;
|
|
294
|
+
pausedOrThrow(error) {
|
|
295
|
+
this.observers.deferredTier?.terminalFlush();
|
|
296
|
+
if (isPauseSignal(error)) {
|
|
297
|
+
this.lastCheckpoint = buildPauseCheckpoint(error, this.traverser, {
|
|
298
|
+
runId: this._currentRunId,
|
|
299
|
+
executionCount: this._executionCounter.value,
|
|
300
|
+
visitCounts: this._visitCounts,
|
|
301
|
+
});
|
|
302
|
+
return { paused: true, checkpoint: this.lastCheckpoint };
|
|
876
303
|
}
|
|
877
|
-
|
|
878
|
-
return undefined;
|
|
879
|
-
return this.dfsFind(subflowRoot, stageId);
|
|
304
|
+
throw error;
|
|
880
305
|
}
|
|
881
|
-
/**
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
return undefined;
|
|
888
|
-
visited.add(node.id);
|
|
889
|
-
if (node.id === targetId)
|
|
890
|
-
return node;
|
|
891
|
-
if (node.children) {
|
|
892
|
-
for (const child of node.children) {
|
|
893
|
-
const found = this.dfsFind(child, targetId, visited);
|
|
894
|
-
if (found)
|
|
895
|
-
return found;
|
|
896
|
-
}
|
|
306
|
+
/** The re-entrancy guard: one executor = one in-flight execution. */
|
|
307
|
+
assertIdle(method) {
|
|
308
|
+
if (this._isExecuting) {
|
|
309
|
+
throw new Error(`FlowChartExecutor: ${method}() called while another run()/resume() is in flight on this ` +
|
|
310
|
+
'executor. An executor holds per-run state (runId, recorders, checkpoint) — create ' +
|
|
311
|
+
'one executor per concurrent run. See docs/guides/execution-model.md.');
|
|
897
312
|
}
|
|
898
|
-
if (node.next)
|
|
899
|
-
return this.dfsFind(node.next, targetId, visited);
|
|
900
|
-
return undefined;
|
|
901
313
|
}
|
|
902
|
-
// ───
|
|
314
|
+
// ─── Recorders (the register lives in `attach.ts`) ───
|
|
903
315
|
/**
|
|
904
|
-
* Attach a
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
* it is replaced (not duplicated). This prevents double-counting when both
|
|
910
|
-
* a framework and the user attach the same recorder type.
|
|
911
|
-
*
|
|
912
|
-
* Built-in recorders use auto-increment IDs (`metrics-1`, `debug-1`, ...) by
|
|
913
|
-
* default, so multiple instances with different configs coexist. To override
|
|
914
|
-
* a framework-attached recorder, pass the same well-known ID.
|
|
316
|
+
* Attach a ScopeRecorder to observe data operations (reads, writes, commits)
|
|
317
|
+
* on every stage scope. Call before run(). **Idempotent by `id`** (replaced,
|
|
318
|
+
* never duplicated). `{ delivery: 'deferred' }` moves it off the hot path —
|
|
319
|
+
* delivered at the next microtask checkpoint; re-attaching an id on the
|
|
320
|
+
* other tier SWAPS tiers (`docs/guides/observers-deferred.md`).
|
|
915
321
|
*
|
|
916
322
|
* @example
|
|
917
323
|
* ```typescript
|
|
918
|
-
* // Multiple recorders with different configs — each gets a unique ID
|
|
919
324
|
* executor.attachScopeRecorder(new MetricRecorder());
|
|
920
|
-
* executor.attachScopeRecorder(new
|
|
921
|
-
*
|
|
922
|
-
* // Override a framework-attached recorder by passing its well-known ID
|
|
923
|
-
* executor.attachScopeRecorder(new MetricRecorder('metrics'));
|
|
924
|
-
*
|
|
925
|
-
* // Attaching twice with same ID replaces (no double-counting)
|
|
926
|
-
* executor.attachScopeRecorder(new MetricRecorder('my-metrics'));
|
|
927
|
-
* executor.attachScopeRecorder(new MetricRecorder('my-metrics')); // replaces previous
|
|
325
|
+
* executor.attachScopeRecorder(new MetricRecorder('my-metrics')); // replaces same id
|
|
928
326
|
* ```
|
|
929
|
-
*
|
|
930
|
-
* **Delivery tier (RFC-001):** pass `{ delivery: 'deferred' }` to take the
|
|
931
|
-
* recorder out of the engine's hot path — events are captured into a
|
|
932
|
-
* bounded queue and delivered at the next microtask checkpoint ("one beat
|
|
933
|
-
* behind"). Omitting `delivery` keeps the historical synchronous call,
|
|
934
|
-
* byte-identical to previous releases. Re-attaching the same `id` with a
|
|
935
|
-
* different tier SWAPS tiers cleanly — never double delivery. See
|
|
936
|
-
* `docs/guides/observers-deferred.md`.
|
|
937
327
|
*/
|
|
938
328
|
attachScopeRecorder(recorder, options) {
|
|
939
|
-
|
|
940
|
-
this.scopeRecorders = this.scopeRecorders.filter((r) => r.id !== recorder.id);
|
|
941
|
-
if (options?.delivery === 'deferred') {
|
|
942
|
-
this.ensureDeferredTier(options).register(recorder, { scope: true }, options);
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
this.deferredTier?.removeFromLists(recorder.id, { scope: true });
|
|
946
|
-
this.scopeRecorders.push(recorder);
|
|
947
|
-
}
|
|
948
|
-
/**
|
|
949
|
-
* Lazily create the executor's ONE deferred-observer tier (one merged
|
|
950
|
-
* queue, total event order across all three channels). The FIRST deferred
|
|
951
|
-
* attach's options configure the dispatcher; later differing options are
|
|
952
|
-
* dev-warned and ignored (see `AttachRecorderOptions`).
|
|
953
|
-
*/
|
|
954
|
-
ensureDeferredTier(options) {
|
|
955
|
-
if (!this.deferredTier)
|
|
956
|
-
this.deferredTier = new DeferredObserverTier(options);
|
|
957
|
-
return this.deferredTier;
|
|
958
|
-
}
|
|
959
|
-
// ─── Detach (T4) ─────────────────────────────────────────────────────────
|
|
960
|
-
//
|
|
961
|
-
// Bare-executor entry point for fire-and-forget child flowchart execution.
|
|
962
|
-
// Use from outside any chart (consumer code that wants to detach work
|
|
963
|
-
// without first running a parent chart). For detach FROM INSIDE a stage,
|
|
964
|
-
// use `scope.$detachAndJoinLater(...)` / `scope.$detachAndForget(...)` —
|
|
965
|
-
// those mint refIds from the calling stage's runtimeStageId for trace
|
|
966
|
-
// correlation; the bare-executor entries use a synthetic prefix
|
|
967
|
-
// (`__executor__`) instead.
|
|
968
|
-
/**
|
|
969
|
-
* Detach a child flowchart on the given driver and return a `DetachHandle`
|
|
970
|
-
* the caller can `wait()` on (Promise) or read `.status` from (sync).
|
|
971
|
-
*
|
|
972
|
-
* The driver is a REQUIRED first argument — there is no library-default,
|
|
973
|
-
* to keep the engine free of driver imports and to make the choice of
|
|
974
|
-
* scheduling algorithm explicit at the call site.
|
|
975
|
-
*
|
|
976
|
-
* @example
|
|
977
|
-
* ```typescript
|
|
978
|
-
* import { microtaskBatchDriver } from 'footprintjs/detach';
|
|
979
|
-
*
|
|
980
|
-
* const exec = new FlowChartExecutor(parentChart);
|
|
981
|
-
* const handle = exec.detachAndJoinLater(microtaskBatchDriver, telemetryChart, { event: 'x' });
|
|
982
|
-
* await handle.wait(); // optional
|
|
983
|
-
* ```
|
|
984
|
-
*/
|
|
985
|
-
detachAndJoinLater(driver, child, input) {
|
|
986
|
-
return _detachAndJoinLater(driver, child, input, '__executor__');
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Detach a child flowchart on the given driver and DISCARD the handle.
|
|
990
|
-
* Use for telemetry exports / fire-and-forget side effects where the
|
|
991
|
-
* caller doesn't care about the result.
|
|
992
|
-
*
|
|
993
|
-
* Errors raised by the child still land on the (discarded) handle — they
|
|
994
|
-
* go silent unless surfaced through a recorder. For observable detach,
|
|
995
|
-
* prefer `detachAndJoinLater` and surface failures via `.wait().catch()`.
|
|
996
|
-
*/
|
|
997
|
-
detachAndForget(driver, child, input) {
|
|
998
|
-
_detachAndForget(driver, child, input, '__executor__');
|
|
329
|
+
this.observers.attachScope(recorder, options);
|
|
999
330
|
}
|
|
1000
331
|
/** Detach all scope Recorders with the given ID — both delivery tiers. */
|
|
1001
332
|
detachScopeRecorder(id) {
|
|
1002
|
-
this.
|
|
1003
|
-
this.deferredTier?.removeFromLists(id, { scope: true });
|
|
333
|
+
this.observers.detachScope(id);
|
|
1004
334
|
}
|
|
1005
335
|
/** Returns a defensive copy of attached scope Recorders (both tiers). */
|
|
1006
336
|
getScopeRecorders() {
|
|
1007
|
-
return
|
|
337
|
+
return this.observers.scopeList();
|
|
1008
338
|
}
|
|
1009
|
-
// ─── FlowRecorder Management ───
|
|
1010
339
|
/**
|
|
1011
|
-
* Attach a FlowRecorder to observe control flow events.
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
* **Idempotent by ID:** replaces existing recorder with same `id`.
|
|
1016
|
-
*
|
|
1017
|
-
* **Delivery tier (RFC-001):** pass `{ delivery: 'deferred' }` for
|
|
1018
|
-
* next-checkpoint delivery off the hot path — see `attachScopeRecorder`.
|
|
340
|
+
* Attach a FlowRecorder to observe control flow events. Automatically
|
|
341
|
+
* enables narrative. Must be called before run(). Idempotent by `id`;
|
|
342
|
+
* `{ delivery: 'deferred' }` as for `attachScopeRecorder`.
|
|
1019
343
|
*/
|
|
1020
344
|
attachFlowRecorder(recorder, options) {
|
|
1021
|
-
|
|
1022
|
-
this.flowRecorders = this.flowRecorders.filter((r) => r.id !== recorder.id);
|
|
1023
|
-
this.narrativeEnabled = true;
|
|
1024
|
-
if (options?.delivery === 'deferred') {
|
|
1025
|
-
this.ensureDeferredTier(options).register(recorder, { flow: true }, options);
|
|
1026
|
-
return;
|
|
1027
|
-
}
|
|
1028
|
-
this.deferredTier?.removeFromLists(recorder.id, { flow: true });
|
|
1029
|
-
this.flowRecorders.push(recorder);
|
|
345
|
+
this.observers.attachFlow(recorder, options);
|
|
1030
346
|
}
|
|
1031
347
|
/** Detach all FlowRecorders with the given ID — both delivery tiers. */
|
|
1032
348
|
detachFlowRecorder(id) {
|
|
1033
|
-
this.
|
|
1034
|
-
this.deferredTier?.removeFromLists(id, { flow: true });
|
|
349
|
+
this.observers.detachFlow(id);
|
|
1035
350
|
}
|
|
1036
351
|
/** Returns a defensive copy of attached FlowRecorders (both tiers). */
|
|
1037
352
|
getFlowRecorders() {
|
|
1038
|
-
return
|
|
353
|
+
return this.observers.flowList();
|
|
1039
354
|
}
|
|
1040
|
-
// ─── Combined ScopeRecorder Management ───
|
|
1041
355
|
/**
|
|
1042
|
-
* Attach a recorder
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
* separately, because forgetting one of the two is a silent foot-gun —
|
|
1048
|
-
* half your events never fire and there is no runtime warning. With
|
|
1049
|
-
* `attachCombinedRecorder` the library guarantees the recorder's declared
|
|
1050
|
-
* methods all fire, and adds no overhead versus two explicit calls.
|
|
1051
|
-
*
|
|
1052
|
-
* ## Idempotency
|
|
1053
|
-
*
|
|
1054
|
-
* Idempotent by `id` across ALL channels — re-attaching with the same `id`
|
|
1055
|
-
* replaces the previous instance everywhere it was registered. Mixing
|
|
1056
|
-
* `attachCombinedRecorder(x)` with a prior `attachScopeRecorder(y)` or
|
|
1057
|
-
* `attachFlowRecorder(y)` that share `x.id === y.id` is also safe: the
|
|
1058
|
-
* combined attach replaces the single-channel registration on whichever
|
|
1059
|
-
* channel(s) `x` has methods for. No duplicate firings occur.
|
|
1060
|
-
*
|
|
1061
|
-
* ## Narrative activation
|
|
1062
|
-
*
|
|
1063
|
-
* If the recorder has any control-flow methods, `enableNarrative()` is
|
|
1064
|
-
* called as a side effect (the narrative subsystem is required to emit
|
|
1065
|
-
* control-flow events). Data-flow-only recorders do NOT activate the
|
|
1066
|
-
* narrative.
|
|
1067
|
-
*
|
|
1068
|
-
* ## Detection rule
|
|
1069
|
-
*
|
|
1070
|
-
* Only **own** event methods count (see `hasRecorderMethods`). Methods
|
|
1071
|
-
* inherited via the prototype chain are ignored — this protects against
|
|
1072
|
-
* accidental `Object.prototype` pollution attaching handlers you never
|
|
1073
|
-
* declared. A recorder that provides only `clear`/`toSnapshot` is a
|
|
1074
|
-
* no-op and emits a dev-mode warning to surface the likely mistake.
|
|
356
|
+
* Attach a recorder to every channel (scope, flow, emit) it has OWN `on*`
|
|
357
|
+
* methods for — preferred over single-channel calls, where forgetting one
|
|
358
|
+
* silently loses events. Idempotent by `id` across all channels; a flow
|
|
359
|
+
* method enables the narrative; `delivery` comes from the options or the
|
|
360
|
+
* recorder's own field.
|
|
1075
361
|
*
|
|
1076
362
|
* @example
|
|
1077
363
|
* ```typescript
|
|
@@ -1084,60 +370,16 @@ export class FlowChartExecutor {
|
|
|
1084
370
|
* ```
|
|
1085
371
|
*/
|
|
1086
372
|
attachCombinedRecorder(recorder, options) {
|
|
1087
|
-
|
|
1088
|
-
const hasFlow = hasFlowRecorderMethods(recorder);
|
|
1089
|
-
const hasEmit = hasEmitRecorderMethods(recorder);
|
|
1090
|
-
// Delivery tier (RFC-001): options bag OR the recorder's own
|
|
1091
|
-
// `delivery: 'deferred'` field. The field is a string — channel routing
|
|
1092
|
-
// above counts event-METHOD properties only, so declaring it never
|
|
1093
|
-
// changes which channels the recorder lands on.
|
|
1094
|
-
const delivery = options?.delivery ?? recorder.delivery;
|
|
1095
|
-
const tierOptions = delivery === undefined ? options : { ...options, delivery };
|
|
1096
|
-
// Emit recorders live on the SAME channel as data-flow recorders
|
|
1097
|
-
// (ScopeFacade iterates `_recorders` for onEmit dispatch). So
|
|
1098
|
-
// attachEmitRecorder internally calls attachScopeRecorder — but we want to
|
|
1099
|
-
// avoid double-attach when the recorder implements BOTH onEmit AND
|
|
1100
|
-
// other ScopeRecorder methods. Short-circuit: if hasData OR hasEmit, the
|
|
1101
|
-
// recorder lands on the scope-recorder list exactly once.
|
|
1102
|
-
if (hasData || hasEmit)
|
|
1103
|
-
this.attachScopeRecorder(recorder, tierOptions);
|
|
1104
|
-
if (hasFlow)
|
|
1105
|
-
this.attachFlowRecorder(recorder, tierOptions);
|
|
1106
|
-
if (!hasData && !hasFlow && !hasEmit && isDevMode()) {
|
|
1107
|
-
// Dev-mode only: silent skips are invisible and produce hard-to-debug
|
|
1108
|
-
// "why didn't my recorder fire" reports. Per library convention, gated
|
|
1109
|
-
// on the central isDevMode() flag (not process.env) so consumers can
|
|
1110
|
-
// control dev tooling centrally via enableDevMode()/disableDevMode().
|
|
1111
|
-
// eslint-disable-next-line no-console
|
|
1112
|
-
console.warn(`[footprintjs] attachCombinedRecorder: recorder '${recorder.id}' has ` +
|
|
1113
|
-
'no observer event methods — nothing to attach. Did you forget to ' +
|
|
1114
|
-
'add an on* handler (onWrite, onDecision, onSubflowEntry, ...)? ' +
|
|
1115
|
-
'Note: only OWN properties count; methods on the prototype chain ' +
|
|
1116
|
-
'are ignored on purpose.');
|
|
1117
|
-
}
|
|
373
|
+
this.observers.attachCombined(recorder, options);
|
|
1118
374
|
}
|
|
1119
|
-
/**
|
|
1120
|
-
* Detach a combined recorder from all channels it was attached to.
|
|
1121
|
-
* Safe to call if the recorder was only on one channel or never attached.
|
|
1122
|
-
*/
|
|
375
|
+
/** Detach a combined recorder from every channel it was attached to (safe if never attached). */
|
|
1123
376
|
detachCombinedRecorder(id) {
|
|
1124
377
|
this.detachScopeRecorder(id);
|
|
1125
378
|
this.detachFlowRecorder(id);
|
|
1126
379
|
}
|
|
1127
|
-
// ─── Emit ScopeRecorder Management (Phase 3) ───
|
|
1128
380
|
/**
|
|
1129
|
-
* Attach an `EmitRecorder`
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
* Internally, emit recorders share the scope-recorder channel because
|
|
1133
|
-
* emit events fire from inside `ScopeFacade` during stage execution,
|
|
1134
|
-
* same timing as `onRead`/`onWrite`. This method is a convenience that
|
|
1135
|
-
* delegates to `attachScopeRecorder` — consumers can also use
|
|
1136
|
-
* `attachScopeRecorder` directly for a recorder that implements BOTH
|
|
1137
|
-
* `onWrite` and `onEmit`. Either approach places the recorder on the
|
|
1138
|
-
* same underlying list, so `onEmit` fires exactly once per event.
|
|
1139
|
-
*
|
|
1140
|
-
* **Idempotent by `id`:** replaces existing recorder with same `id`.
|
|
381
|
+
* Attach an `EmitRecorder` for `scope.$emit(name, payload)` events. It rides
|
|
382
|
+
* the scope list, so `onEmit` fires exactly once per event. Idempotent by `id`.
|
|
1141
383
|
*
|
|
1142
384
|
* @example
|
|
1143
385
|
* ```typescript
|
|
@@ -1156,45 +398,49 @@ export class FlowChartExecutor {
|
|
|
1156
398
|
detachEmitRecorder(id) {
|
|
1157
399
|
this.detachScopeRecorder(id);
|
|
1158
400
|
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Returns a defensive copy of attached recorders (both delivery tiers)
|
|
1161
|
-
* filtered to those that implement `onEmit`. Useful for inspection during
|
|
1162
|
-
* testing.
|
|
1163
|
-
*/
|
|
401
|
+
/** Returns a defensive copy of attached recorders (both tiers) that implement `onEmit`. */
|
|
1164
402
|
getEmitRecorders() {
|
|
1165
403
|
return this.getScopeRecorders().filter((r) => typeof r.onEmit === 'function');
|
|
1166
404
|
}
|
|
405
|
+
// ─── Detach (T4) ───
|
|
406
|
+
// Bare-executor entry points for fire-and-forget child charts. From inside a
|
|
407
|
+
// stage use `scope.$detachAndJoinLater(...)` / `scope.$detachAndForget(...)`,
|
|
408
|
+
// which mint refIds from the calling stage; these use `__executor__`.
|
|
1167
409
|
/**
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
410
|
+
* Detach a child flowchart on the given driver and return a `DetachHandle`
|
|
411
|
+
* the caller can `wait()` on (Promise) or read `.status` from (sync). The
|
|
412
|
+
* driver is REQUIRED — there is no library default.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```typescript
|
|
416
|
+
* import { microtaskBatchDriver } from 'footprintjs/detach';
|
|
417
|
+
*
|
|
418
|
+
* const exec = new FlowChartExecutor(parentChart);
|
|
419
|
+
* const handle = exec.detachAndJoinLater(microtaskBatchDriver, telemetryChart, { event: 'x' });
|
|
420
|
+
* await handle.wait(); // optional
|
|
421
|
+
* ```
|
|
1172
422
|
*/
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
423
|
+
detachAndJoinLater(driver, child, input) {
|
|
424
|
+
return _detachAndJoinLater(driver, child, input, '__executor__');
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Detach a child flowchart on the given driver and DISCARD the handle — for
|
|
428
|
+
* fire-and-forget side effects. A child's error lands on the discarded handle;
|
|
429
|
+
* for observable detach prefer `detachAndJoinLater` + `.wait().catch()`.
|
|
430
|
+
*/
|
|
431
|
+
detachAndForget(driver, child, input) {
|
|
432
|
+
_detachAndForget(driver, child, input, '__executor__');
|
|
1179
433
|
}
|
|
1180
434
|
/**
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
1183
|
-
* entries inline). Plus any user-attached recorders.
|
|
435
|
+
* Structured narrative entries (type, text, depth) — the one public narrative
|
|
436
|
+
* API; `.map(e => e.text)` for a flat `string[]`.
|
|
1184
437
|
*/
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
recorders.push(this.combinedRecorder);
|
|
438
|
+
getNarrativeEntries() {
|
|
439
|
+
if (this.observers.combinedRecorder) {
|
|
440
|
+
return this.observers.combinedRecorder.getEntries();
|
|
1189
441
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
// event for deferred listeners. Appended like any other flow recorder,
|
|
1193
|
-
// so the FlowRecorderDispatcher site needs no tier logic of its own.
|
|
1194
|
-
const flowTap = this.deferredTier?.buildFlowTap();
|
|
1195
|
-
if (flowTap)
|
|
1196
|
-
recorders.push(flowTap);
|
|
1197
|
-
return recorders.length > 0 ? recorders : undefined;
|
|
442
|
+
const flowSentences = this.traverser.getNarrative();
|
|
443
|
+
return flowSentences.map((text) => ({ type: 'stage', text, depth: 0 }));
|
|
1198
444
|
}
|
|
1199
445
|
/**
|
|
1200
446
|
* Execute the chart. Resolves when the run finishes — or pauses, if a
|
|
@@ -1214,73 +460,37 @@ export class FlowChartExecutor {
|
|
|
1214
460
|
* checkpoint). Create one executor per concurrent run.
|
|
1215
461
|
*/
|
|
1216
462
|
async run(options) {
|
|
1217
|
-
//
|
|
1218
|
-
//
|
|
1219
|
-
|
|
1220
|
-
if (this._isExecuting) {
|
|
1221
|
-
throw new Error('FlowChartExecutor: run() called while another run()/resume() is in flight on this ' +
|
|
1222
|
-
'executor. An executor holds per-run state (runId, recorders, checkpoint) — create ' +
|
|
1223
|
-
'one executor per concurrent run. See docs/guides/execution-model.md.');
|
|
1224
|
-
}
|
|
1225
|
-
// Validate input against inputSchema if both are present. Validation runs
|
|
1226
|
-
// BEFORE the timeout timer is created so a rejected input can't leak a
|
|
1227
|
-
// pending timer (same "failed entry leaves no side effects" rule as the
|
|
1228
|
-
// re-entrancy guard above).
|
|
463
|
+
// A failed entry leaves no side effects: the guard FIRST (the in-flight
|
|
464
|
+
// run stays untouched), validation before the timeout timer exists.
|
|
465
|
+
this.assertIdle('run');
|
|
1229
466
|
let validatedInput = options?.input;
|
|
1230
467
|
if (validatedInput && this.flowChartArgs.flowChart.inputSchema) {
|
|
1231
468
|
validatedInput = validateInput(this.flowChartArgs.flowChart.inputSchema, validatedInput);
|
|
1232
469
|
}
|
|
1233
470
|
let signal = options?.signal;
|
|
1234
471
|
let timeoutId;
|
|
1235
|
-
// Create an internal AbortController for timeoutMs
|
|
1236
472
|
if (options?.timeoutMs && !signal) {
|
|
1237
473
|
const controller = new AbortController();
|
|
1238
474
|
signal = controller.signal;
|
|
1239
475
|
timeoutId = setTimeout(() => controller.abort(new Error(`Execution timed out after ${options.timeoutMs}ms`)), options.timeoutMs);
|
|
1240
476
|
}
|
|
1241
|
-
|
|
1242
|
-
// cross-run accumulation. The combinedRecorder is NOT cleared here — createTraverser() always
|
|
1243
|
-
// creates a fresh CombinedNarrativeRecorder instance on each run, so stale state is never an issue.
|
|
1244
|
-
for (const r of this.flowRecorders) {
|
|
1245
|
-
r.clear?.();
|
|
1246
|
-
}
|
|
1247
|
-
for (const r of this.scopeRecorders) {
|
|
1248
|
-
r.clear?.();
|
|
1249
|
-
}
|
|
1250
|
-
this.deferredTier?.clearRecorders();
|
|
477
|
+
this.observers.clearForRun(); // no cross-run accumulation
|
|
1251
478
|
this.lastCheckpoint = undefined;
|
|
1252
|
-
this._executionCounter = { value: 0 };
|
|
1253
|
-
this._visitCounts = new Map();
|
|
1254
|
-
this._currentRunId = generateRunId();
|
|
1255
|
-
this._hasRunBefore = true; //
|
|
1256
|
-
// same-executor branch (reuse runtime, accumulate execution tree).
|
|
479
|
+
this._executionCounter = { value: 0 };
|
|
480
|
+
this._visitCounts = new Map();
|
|
481
|
+
this._currentRunId = generateRunId();
|
|
482
|
+
this._hasRunBefore = true; // a later resume() reuses this runtime
|
|
1257
483
|
this.traverser = this.createTraverser(signal, validatedInput, options?.env, options?.maxDepth, options?.maxIterations);
|
|
1258
|
-
//
|
|
1259
|
-
// no await between the top-of-method check and here, so this is race-free.
|
|
484
|
+
// After every sync throw, with no await since the guard: race-free.
|
|
1260
485
|
this._isExecuting = true;
|
|
1261
486
|
try {
|
|
1262
487
|
const result = await this.traverser.execute();
|
|
1263
|
-
// Terminal flush (RFC-001 Block 8)
|
|
1264
|
-
|
|
1265
|
-
// before run() returns — "one beat behind" never becomes "lost at exit".
|
|
1266
|
-
this.deferredTier?.terminalFlush();
|
|
488
|
+
// Terminal flush (RFC-001 Block 8): "one beat behind" never becomes "lost at exit".
|
|
489
|
+
this.observers.deferredTier?.terminalFlush();
|
|
1267
490
|
return result;
|
|
1268
491
|
}
|
|
1269
492
|
catch (error) {
|
|
1270
|
-
|
|
1271
|
-
// OUTERMOST handler (a pause re-throws through subflow traversers
|
|
1272
|
-
// without exit events, so per-traverser hooks would miss it). Runs
|
|
1273
|
-
// before the checkpoint is exposed and before the error reaches the
|
|
1274
|
-
// caller.
|
|
1275
|
-
this.deferredTier?.terminalFlush();
|
|
1276
|
-
if (isPauseSignal(error)) {
|
|
1277
|
-
// Build a detached checkpoint from current execution state — see
|
|
1278
|
-
// buildPauseCheckpoint() for the deep-copy rationale.
|
|
1279
|
-
this.lastCheckpoint = this.buildPauseCheckpoint(error);
|
|
1280
|
-
// Return a PauseResult-shaped value so callers can check without try/catch
|
|
1281
|
-
return { paused: true, checkpoint: this.lastCheckpoint };
|
|
1282
|
-
}
|
|
1283
|
-
throw error;
|
|
493
|
+
return this.pausedOrThrow(error);
|
|
1284
494
|
}
|
|
1285
495
|
finally {
|
|
1286
496
|
this._isExecuting = false;
|
|
@@ -1289,116 +499,31 @@ export class FlowChartExecutor {
|
|
|
1289
499
|
}
|
|
1290
500
|
}
|
|
1291
501
|
/**
|
|
1292
|
-
* Flush the deferred-observer backlog, then await async listener
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
* when no deferred observer was ever attached. `pending === 0` means a
|
|
1297
|
-
* full drain; a non-zero `pending` reports continuations (plus any queued
|
|
1298
|
-
* events) still outstanding at the deadline — honest, never silent.
|
|
502
|
+
* Flush the deferred-observer backlog, then await async listener completions
|
|
503
|
+
* under a deadline — call before a serverless process freezes or exits.
|
|
504
|
+
* Zeros when no deferred observer was attached; `pending > 0` reports what
|
|
505
|
+
* was still outstanding at the deadline.
|
|
1299
506
|
*/
|
|
1300
507
|
drainObservers(opts) {
|
|
1301
|
-
|
|
508
|
+
const tier = this.observers.deferredTier;
|
|
509
|
+
if (!tier)
|
|
1302
510
|
return Promise.resolve({ done: 0, failed: 0, pending: 0 });
|
|
1303
|
-
return
|
|
511
|
+
return tier.drain(opts);
|
|
1304
512
|
}
|
|
1305
513
|
// ─── Introspection ───
|
|
1306
514
|
/**
|
|
1307
515
|
* Returns the runtime snapshot.
|
|
1308
516
|
*
|
|
1309
|
-
* @param options.redact
|
|
1310
|
-
* redacted mirror
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
* redacted mirror is not maintained, so this flag is a no-op —
|
|
1314
|
-
* `sharedState` is the raw working memory either way. Default `false`.
|
|
1315
|
-
*
|
|
1316
|
-
* The commit log is already redacted at write-time regardless of this
|
|
1317
|
-
* flag, and the execution tree carries only structural metadata.
|
|
1318
|
-
* `subflowResults[*].treeContext.globalContext` follows the flag too
|
|
1319
|
-
* (9.20.0): under `redact: true` it is each subflow's own redacted
|
|
1320
|
-
* mirror; plain, the subflow's live heap.
|
|
517
|
+
* @param options.redact `true` serves `sharedState` (and each subflow's
|
|
518
|
+
* `globalContext`) from the redacted mirror — the safe view to export. A
|
|
519
|
+
* no-op without a redaction policy. The commit log is redacted at write
|
|
520
|
+
* time regardless. Default `false`.
|
|
1321
521
|
*
|
|
1322
522
|
* **Treat `sharedState` as READ-ONLY.** In production it is a live view of
|
|
1323
|
-
*
|
|
1324
|
-
* engine state. In dev mode (`enableDevMode()`) it is a deep-frozen CLONE,
|
|
1325
|
-
* so any consumer mutation throws loudly instead of corrupting silently.
|
|
523
|
+
* engine memory; in dev mode a deep-frozen clone, so a mutation throws.
|
|
1326
524
|
*/
|
|
1327
525
|
getSnapshot(options) {
|
|
1328
|
-
|
|
1329
|
-
if (isDevMode()) {
|
|
1330
|
-
// Dev-mode mutation guard: freeze a CLONE, never the live engine
|
|
1331
|
-
// state — `snapshot.sharedState` IS SharedMemory's current generation,
|
|
1332
|
-
// whose unchanged subtrees every later generation shares
|
|
1333
|
-
// (copy-on-write, 9.29.0).
|
|
1334
|
-
// Production stays zero-copy; clone-always is a measured decision
|
|
1335
|
-
// deferred until the bench says it's affordable (BACKLOG #8).
|
|
1336
|
-
// NOTE: deepFreeze (capture/freeze.ts — the one walk) cannot reach
|
|
1337
|
-
// Map/Set INTERNALS (`map.set()` on the frozen clone won't throw) and
|
|
1338
|
-
// skips typed arrays. The CLONE still isolates the engine.
|
|
1339
|
-
snapshot.sharedState = deepFreeze(structuredClone(snapshot.sharedState));
|
|
1340
|
-
}
|
|
1341
|
-
const sfResults = this.traverser.getSubflowResults();
|
|
1342
|
-
if (sfResults.size > 0) {
|
|
1343
|
-
// Under `redact: true` each subflow's `globalContext` is its own mirror
|
|
1344
|
-
// (9.20.0) — served, never written into the record (see
|
|
1345
|
-
// engine/handlers/servedSubflowResults.ts). Plain: the records as they are.
|
|
1346
|
-
snapshot.subflowResults = servedSubflowResults(sfResults, options?.redact === true);
|
|
1347
|
-
}
|
|
1348
|
-
const recorderSnapshots = this.collectRecorderSnapshots();
|
|
1349
|
-
if (recorderSnapshots.length > 0) {
|
|
1350
|
-
snapshot.recorders = recorderSnapshots;
|
|
1351
|
-
}
|
|
1352
|
-
// RFC-001 Block 9: the deferred-observer accounting surface. Present
|
|
1353
|
-
// ONLY when a deferred observer was attached on this executor —
|
|
1354
|
-
// zero-cost discipline for everyone else.
|
|
1355
|
-
if (this.deferredTier) {
|
|
1356
|
-
snapshot.observerStats = this.deferredTier.getStats();
|
|
1357
|
-
}
|
|
1358
|
-
return snapshot;
|
|
1359
|
-
}
|
|
1360
|
-
/**
|
|
1361
|
-
* Collect `toSnapshot()` bundles from every attached recorder — ONE entry
|
|
1362
|
-
* per recorder id, across all channels and both delivery tiers.
|
|
1363
|
-
*
|
|
1364
|
-
* The dedupe is load-bearing, not tidiness. A recorder that implements a
|
|
1365
|
-
* shared-name hook (`onError` / `onPause` / `onResume` — declared on BOTH
|
|
1366
|
-
* the scope and flow interfaces) is legitimately registered on BOTH inline
|
|
1367
|
-
* lists by `attachCombinedRecorder`, and that is by design: each channel
|
|
1368
|
-
* calls the hook with its own payload variant. `MetricRecorder.onPause` is
|
|
1369
|
-
* the everyday case. Walking the lists without a shared `seen` set turned
|
|
1370
|
-
* that into a DUPLICATED snapshot entry (same id twice), which breaks every
|
|
1371
|
-
* consumer that indexes `snapshot.recorders` by id.
|
|
1372
|
-
*
|
|
1373
|
-
* Ordering is scope list → flow list → deferred tier, and the FIRST bundle
|
|
1374
|
-
* for an id wins. A recorder with no `toSnapshot` never claims an id, so it
|
|
1375
|
-
* cannot shadow a same-id recorder that does have one.
|
|
1376
|
-
*
|
|
1377
|
-
* The row is REBUILT field by field by the one copier (`recorder/snapshot.ts
|
|
1378
|
-
* · copyBundle`, shared with `CompositeRecorder`) rather than spread, so a
|
|
1379
|
-
* recorder cannot smuggle an `id` of its own choosing into the snapshot (the
|
|
1380
|
-
* id is the executor's, and consumers index by it).
|
|
1381
|
-
*/
|
|
1382
|
-
collectRecorderSnapshots() {
|
|
1383
|
-
const out = [];
|
|
1384
|
-
const seen = new Set();
|
|
1385
|
-
const collect = (r) => {
|
|
1386
|
-
if (!r.toSnapshot || seen.has(r.id))
|
|
1387
|
-
return;
|
|
1388
|
-
seen.add(r.id);
|
|
1389
|
-
out.push(copyBundle(r.id, r.toSnapshot()));
|
|
1390
|
-
};
|
|
1391
|
-
for (const r of this.scopeRecorders)
|
|
1392
|
-
collect(r);
|
|
1393
|
-
for (const r of this.flowRecorders)
|
|
1394
|
-
collect(r);
|
|
1395
|
-
if (this.deferredTier) {
|
|
1396
|
-
for (const r of this.deferredTier.scopeListRecorders())
|
|
1397
|
-
collect(r);
|
|
1398
|
-
for (const r of this.deferredTier.flowListRecorders())
|
|
1399
|
-
collect(r);
|
|
1400
|
-
}
|
|
1401
|
-
return out;
|
|
526
|
+
return servedSnapshot(this.traverser, this.observers, options);
|
|
1402
527
|
}
|
|
1403
528
|
/** @internal */
|
|
1404
529
|
getRuntime() {
|
|
@@ -1429,7 +554,7 @@ export class FlowChartExecutor {
|
|
|
1429
554
|
* Returns empty array if no ManifestFlowRecorder is attached.
|
|
1430
555
|
*/
|
|
1431
556
|
getSubflowManifest() {
|
|
1432
|
-
const recorder = this.flowRecorders.find((r) => r instanceof ManifestFlowRecorder);
|
|
557
|
+
const recorder = this.observers.flowRecorders.find((r) => r instanceof ManifestFlowRecorder);
|
|
1433
558
|
return recorder?.getManifest() ?? [];
|
|
1434
559
|
}
|
|
1435
560
|
/**
|
|
@@ -1437,8 +562,8 @@ export class FlowChartExecutor {
|
|
|
1437
562
|
* Requires an attached ManifestFlowRecorder that observed the registration.
|
|
1438
563
|
*/
|
|
1439
564
|
getSubflowSpec(subflowId) {
|
|
1440
|
-
const recorder = this.flowRecorders.find((r) => r instanceof ManifestFlowRecorder);
|
|
565
|
+
const recorder = this.observers.flowRecorders.find((r) => r instanceof ManifestFlowRecorder);
|
|
1441
566
|
return recorder?.getSpec(subflowId);
|
|
1442
567
|
}
|
|
1443
568
|
}
|
|
1444
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmxvd0NoYXJ0RXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3J1bm5lci9GbG93Q2hhcnRFeGVjdXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFHSCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGVBQWUsSUFBSSxnQkFBZ0IsRUFBRSxrQkFBa0IsSUFBSSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRWxGLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGtEQUFrRCxDQUFDO0FBRzdGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHVEQUF1RCxDQUFDO0FBRTdGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQy9FLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ3ZFLE9BQU8sRUFXTCxhQUFhLEdBQ2QsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDL0UsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXZELE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFF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SSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO0lBQzlDLENBQUM7SUFFRCxnQkFBZ0I7SUFDaEIsaUJBQWlCO1FBQ2YsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDNUMsQ0FBQztJQUVEOzs7T0FHRztJQUNILGtCQUFrQjtRQUNoQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxZQUFZLG9CQUFvQixDQUVwRSxDQUFDO1FBQ2QsT0FBTyxRQUFRLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxjQUFjLENBQUMsU0FBaUI7UUFDOUIsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsWUFBWSxvQkFBb0IsQ0FFcEUsQ0FBQztRQUNkLE9BQU8sUUFBUSxFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZsb3dDaGFydEV4ZWN1dG9yIOKAlCBQdWJsaWMgQVBJIGZvciBleGVjdXRpbmcgYSBjb21waWxlZCBGbG93Q2hhcnQuXG4gKlxuICogV3JhcHMgRmxvd2NoYXJ0VHJhdmVyc2VyLiBCdWlsZCBhIGNoYXJ0IHdpdGggZmxvd0NoYXJ0KCkgYW5kIHBhc3MgdGhlIHJlc3VsdCBoZXJlOlxuICpcbiAqICAgY29uc3QgY2hhcnQgPSBmbG93Q2hhcnQoJ2VudHJ5JywgZW50cnlGbikuYWRkRnVuY3Rpb24oJ3Byb2Nlc3MnLCBwcm9jZXNzRm4pLmJ1aWxkKCk7XG4gKlxuICogICAvLyBOby1vcHRpb25zIGZvcm0gKHVzZXMgYXV0by1kZXRlY3RlZCBUeXBlZFNjb3BlIGZhY3RvcnkgZnJvbSB0aGUgY2hhcnQpOlxuICogICBjb25zdCBleGVjdXRvciA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCk7XG4gKlxuICogICAvLyBPcHRpb25zLW9iamVjdCBmb3JtIChwcmVmZXJyZWQgd2hlbiB5b3UgbmVlZCB0byBjdXN0b21pemUgYmVoYXZpb3IpOlxuICogICBjb25zdCBleGVjdXRvciA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCwgeyBzY29wZUZhY3Rvcnk6IG15RmFjdG9yeSB9KTtcbiAqXG4gKiAgIC8vIDItcGFyYW0gZm9ybSAoYWNjZXB0cyBhIFNjb3BlRmFjdG9yeSBkaXJlY3RseSwgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkpOlxuICogICBjb25zdCBleGVjdXRvciA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCwgbXlGYWN0b3J5KTtcbiAqXG4gKiAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWN1dG9yLnJ1bih7IGlucHV0OiBkYXRhLCBlbnY6IHsgdHJhY2VJZDogJ3JlcS0xMjMnIH0gfSk7XG4gKi9cblxuaW1wb3J0IHR5cGUgeyBGbG93Q2hhcnQgfSBmcm9tICcuLi9idWlsZGVyL3R5cGVzLmpzJztcbmltcG9ydCB7IGRlZXBGcmVlemUgfSBmcm9tICcuLi9jYXB0dXJlL2ZyZWV6ZS5qcyc7XG5pbXBvcnQgeyBkZXRhY2hBbmRGb3JnZXQgYXMgX2RldGFjaEFuZEZvcmdldCwgZGV0YWNoQW5kSm9pbkxhdGVyIGFzIF9kZXRhY2hBbmRKb2luTGF0ZXIgfSBmcm9tICcuLi9kZXRhY2gvc3Bhd24uanMnO1xuaW1wb3J0IHsgaXNEZXZNb2RlIH0gZnJvbSAnLi4vZGV2TW9kZS5qcyc7XG5pbXBvcnQgeyBSZXN1bWVFbnRyeSB9IGZyb20gJy4uL2VuZ2luZS9oYW5kbGVycy9SZXN1bWVFbnRyeS5qcyc7XG5pbXBvcnQgeyBzZXJ2ZWRTdWJmbG93UmVzdWx0cyB9IGZyb20gJy4uL2VuZ2luZS9oYW5kbGVycy9zZXJ2ZWRTdWJmbG93UmVzdWx0cy5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbWJpbmVkTmFycmF0aXZlUmVjb3JkZXJPcHRpb25zIH0gZnJvbSAnLi4vZW5naW5lL25hcnJhdGl2ZS9Db21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyLmpzJztcbmltcG9ydCB7IENvbWJpbmVkTmFycmF0aXZlUmVjb3JkZXIgfSBmcm9tICcuLi9lbmdpbmUvbmFycmF0aXZlL0NvbWJpbmVkTmFycmF0aXZlUmVjb3JkZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBDb21iaW5lZE5hcnJhdGl2ZUVudHJ5IH0gZnJvbSAnLi4vZW5naW5lL25hcnJhdGl2ZS9uYXJyYXRpdmVUeXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7IE1hbmlmZXN0RW50cnkgfSBmcm9tICcuLi9lbmdpbmUvbmFycmF0aXZlL3JlY29yZGVycy9NYW5pZmVzdEZsb3dSZWNvcmRlci5qcyc7XG5pbXBvcnQgeyBNYW5pZmVzdEZsb3dSZWNvcmRlciB9IGZyb20gJy4uL2VuZ2luZS9uYXJyYXRpdmUvcmVjb3JkZXJzL01hbmlmZXN0Rmxvd1JlY29yZGVyLmpzJztcbmltcG9ydCB0eXBlIHsgRmxvd1JlY29yZGVyLCBSZXN1bWVMaW5rIH0gZnJvbSAnLi4vZW5naW5lL25hcnJhdGl2ZS90eXBlcy5qcyc7XG5pbXBvcnQgeyBGbG93Y2hhcnRUcmF2ZXJzZXIgfSBmcm9tICcuLi9lbmdpbmUvdHJhdmVyc2FsL0Zsb3djaGFydFRyYXZlcnNlci5qcyc7XG5pbXBvcnQgeyByZXN1bWVUcmF2ZXJzYWxDb250ZXh0IH0gZnJvbSAnLi4vZW5naW5lL3RyYXZlcnNhbENvbnRleHQuanMnO1xuaW1wb3J0IHtcbiAgdHlwZSBFeGVjdXRvclJlc3VsdCxcbiAgdHlwZSBQYXVzZWRSZXN1bHQsXG4gIHR5cGUgUnVuT3B0aW9ucyxcbiAgdHlwZSBTY29wZUZhY3RvcnksXG4gIHR5cGUgU2VyaWFsaXplZFBpcGVsaW5lU3RydWN0dXJlLFxuICB0eXBlIFN0YWdlRnVuY3Rpb24sXG4gIHR5cGUgU3RhZ2VOb2RlLFxuICB0eXBlIFN0cmVhbUhhbmRsZXJzLFxuICB0eXBlIFN1YmZsb3dSZXN1bHQsXG4gIHR5cGUgVHJhdmVyc2FsUmVzdWx0LFxuICBkZWZhdWx0TG9nZ2VyLFxufSBmcm9tICcuLi9lbmdpbmUvdHlwZXMuanMnO1xuaW1wb3J0IHsgYnVpbGRSdW50aW1lU3RhZ2VJZCwgaXNFeGVjdXRpb25LZXkgfSBmcm9tICcuLi9pZHMvcnVudGltZVN0YWdlSWQuanMnO1xuaW1wb3J0IHsgUmVkYWN0aW9uUnVsZSB9IGZyb20gJy4uL21lbW9yeS9yZWRhY3Rpb24uanMnO1xuaW1wb3J0IHR5cGUgeyBSdW5EaWFscyB9IGZyb20gJy4uL21lbW9yeS9ydW5Qb2xpY3kuanMnO1xuaW1wb3J0IHsgcGlja0RpYWxzLCBydW5Qb2xpY3kgfSBmcm9tICcuLi9tZW1vcnkvcnVuUG9saWN5LmpzJztcbmltcG9ydCB0eXBlIHsgQ29tbWl0VmFsdWVzTW9kZSwgUmVhZFRyYWNraW5nTW9kZSwgU3RhZ2VTbmFwc2hvdCwgV3JpdGVUcmFja2luZ01vZGUgfSBmcm9tICcuLi9tZW1vcnkvdHlwZXMuanMnO1xuaW1wb3J0IHsgcHJvdmlkZUludGVycnVwdEFuc3dlciB9IGZyb20gJy4uL3BhdXNlL2ludGVycnVwdC5qcyc7XG5pbXBvcnQgeyBDSEVDS1BPSU5UX1ZFUlNJT04sIGRlY29kZUNoZWNrcG9pbnQgfSBmcm9tICcuLi9wYXVzZS9yZWNvcmQuanMnO1xuaW1wb3J0IHR5cGUgeyBGbG93Y2hhcnRDaGVja3BvaW50LCBQYXVzZVNpZ25hbCB9IGZyb20gJy4uL3BhdXNlL3R5cGVzLmpzJztcbmltcG9ydCB7IGlzUGF1c2VkRXhlY3V0aW9uLCBpc1BhdXNlU2lnbmFsIH0gZnJvbSAnLi4vcGF1c2UvdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBDb21iaW5lZFJlY29yZGVyIH0gZnJvbSAnLi4vcmVjb3JkZXIvQ29tYmluZWRSZWNvcmRlci5qcyc7XG5pbXBvcnQgeyBoYXNFbWl0UmVjb3JkZXJNZXRob2RzLCBoYXNGbG93UmVjb3JkZXJNZXRob2RzLCBoYXNSZWNvcmRlck1ldGhvZHMgfSBmcm9tICcuLi9yZWNvcmRlci9Db21iaW5lZFJlY29yZGVyLmpzJztcbmltcG9ydCB0eXBlIHsgRW1pdFJlY29yZGVyIH0gZnJvbSAnLi4vcmVjb3JkZXIvRW1pdFJlY29yZGVyLmpzJztcbmltcG9ydCB7IGZpcmUsIHJlY29yZGVyRmFpbHVyZUV2ZW50LCB3YXJuSW5EZXZNb2RlIH0gZnJvbSAnLi4vcmVjb3JkZXIvaG9va3MuanMnO1xuaW1wb3J0IHsgY29weUJ1bmRsZSB9IGZyb20gJy4uL3JlY29yZGVyL3NuYXBzaG90LmpzJztcbmltcG9ydCB0eXBlIHsgU2NvcGVQcm90ZWN0aW9uTW9kZSB9IGZyb20gJy4uL3Njb3BlL3Byb3RlY3Rpb24vdHlwZXMuanMnO1xuaW1wb3J0IHsgU2NvcGVGYWNhZGUgfSBmcm9tICcuLi9zY29wZS9TY29wZUZhY2FkZS5qcyc7XG5pbXBvcnQgdHlwZSB7IFJlZGFjdGlvblBvbGljeSwgUmVkYWN0aW9uUmVwb3J0LCBTY29wZVJlY29yZGVyIH0gZnJvbSAnLi4vc2NvcGUvdHlwZXMuanMnO1xuaW1wb3J0IHsgZGVzY3JpYmVDaGVja3BvaW50Q2xvbmVGYWlsdXJlLCBzYW5pdGl6ZURpYWdub3N0aWNCYWdzIH0gZnJvbSAnLi9jaGVja3BvaW50U2FuaXRpemUuanMnO1xuaW1wb3J0IHsgdHlwZSBBdHRhY2hSZWNvcmRlck9wdGlvbnMsIHR5cGUgT2JzZXJ2ZXJEcmFpblJlc3VsdCwgRGVmZXJyZWRPYnNlcnZlclRpZXIgfSBmcm9tICcuL0RlZmVycmVkT2JzZXJ2ZXJUaWVyLmpzJztcbmltcG9ydCB7IHR5cGUgUmVjb3JkZXJTbmFwc2hvdCwgdHlwZSBSdW50aW1lU25hcHNob3QsIEV4ZWN1dGlvblJ1bnRpbWUgfSBmcm9tICcuL0V4ZWN1dGlvblJ1bnRpbWUuanMnO1xuaW1wb3J0IHsgZ2VuZXJhdGVSdW5JZCB9IGZyb20gJy4vcnVuSWQuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVJbnB1dCB9IGZyb20gJy4vdmFsaWRhdGVJbnB1dC5qcyc7XG5cbi8qKiBEZWZhdWx0IHNjb3BlIGZhY3Rvcnkg4oCUIGNyZWF0ZXMgYSBwbGFpbiBTY29wZUZhY2FkZSBmb3IgZWFjaCBzdGFnZS4gKi9cbmNvbnN0IGRlZmF1bHRTY29wZUZhY3Rvcnk6IFNjb3BlRmFjdG9yeSA9IChjdHgsIHN0YWdlTmFtZSwgcmVhZE9ubHksIGVudikgPT5cbiAgbmV3IFNjb3BlRmFjYWRlKGN0eCwgc3RhZ2VOYW1lLCByZWFkT25seSwgZW52KTtcblxuLyoqXG4gKiBUaGUgcGF1c2VkIHN0YWdlJ3Mgc3RhbmQtaW4gZm9yIGEgcmVzdW1lOiB0aGUgc3RhZ2UncyBPV04gbm9kZSDigJQgc28gaXQga2VlcHNcbiAqIGl0cyBzaGFwZSAoYSBkZWNpZGVyJ3Mgb3Igc2VsZWN0b3IncyBicmFuY2hlcywgYSBmb3JrIHBhcmVudCdzIGNoaWxkcmVuLFxuICogaXRzIGBuZXh0YCkgYW5kIGl0cyBuYW1lLCBkZXNjcmlwdGlvbiBhbmQgZGVjbGFyZWQgdGFncyDigJQgd2l0aCBgZm5gIHN3YXBwZWRcbiAqIGZvciB0aGUgcmVzdW1lIGhhbGYuXG4gKlxuICogRHJvcHBlZDogYHJlc3VtZUZuYCBhbmQgYGlzUGF1c2FibGVgICh0aGUgcmVzdW1lIGhhbGYgbXVzdCBub3QgcGF1c2VcbiAqIGJlY2F1c2UgaXQgcmV0dXJuZWQgYSB2YWx1ZSDigJQgdGhlIG9yaWdpbmFsIHBhdXNhYmxlIGNvbnRyYWN0KTsgYW5kLCBvbiB0aGVcbiAqIGBhZGRQYXVzYWJsZUZ1bmN0aW9uYCByZS1lbnRyeSwgdGhlIHBvbGljaWVzIGRlY2xhcmVkIGZvciB0aGUgc3RhZ2UncyBPV05cbiAqIGZ1bmN0aW9uIChgcmV0cnlgLCBzdHJlYW1pbmcpIOKAlCB0aGF0IHJlLWVudHJ5IHJ1bnMgYSBkaWZmZXJlbnQgZnVuY3Rpb25cbiAqIChgcmVzdW1lRm5gKSB1bmRlciBhIGRpZmZlcmVudCBjb250cmFjdC4gVGhlIGBpbnRlcnJ1cHQoKWAgcmUtZW50cnkgcmUtcnVuc1xuICogdGhlIHN0YWdlJ3Mgb3duIGZ1bmN0aW9uLCBzbyBpdCBrZWVwcyB0aGVtLlxuICpcbiAqIFRhZ3MgZm9sbG93IHRoZSBzdGFnZSBvbiBCT1RIIHJlLWVudHJpZXMgKDkuMjEuMCk6IGEgdGFnIGlzIHRoZSBzdGFnZSdzXG4gKiBOQU1FLCBub3QgYSBwb2xpY3kgb3ZlciBpdHMgZnVuY3Rpb24sIGFuZCB0aGUgcmVzdW1lZCBleGVjdXRpb24gaXMgdGhhdFxuICogc3RhZ2UgcnVubmluZyBhZ2FpbiDigJQgaXRzIGJ1bmRsZSBtdXN0IGNhcnJ5IGl0LCBvciBhIGNoYWluZWQgYXhpcyB3b3VsZFxuICogc2hvdyB0aGUgcGF1c2VkIGxlZyB0YWdnZWQgYW5kIHRoZSByZXN1bWVkIGxlZyBzaWxlbnRseSBub3QuXG4gKi9cbmZ1bmN0aW9uIHN0YW5kSW5Gb3I8VE91dCwgVFNjb3BlPihcbiAgcGF1c2VkTm9kZTogU3RhZ2VOb2RlPFRPdXQsIFRTY29wZT4sXG4gIGZuOiBTdGFnZUZ1bmN0aW9uPFRPdXQsIFRTY29wZT4sXG4gIGlzSW50ZXJydXB0UmVzdW1lOiBib29sZWFuLFxuKTogU3RhZ2VOb2RlPFRPdXQsIFRTY29wZT4ge1xuICBjb25zdCBzdGFuZEluOiBTdGFnZU5vZGU8VE91dCwgVFNjb3BlPiA9IHsgLi4ucGF1c2VkTm9kZSwgZm4gfTtcbiAgZGVsZXRlIHN0YW5kSW4ucmVzdW1lRm47XG4gIGRlbGV0ZSBzdGFuZEluLmlzUGF1c2FibGU7XG4gIGlmICghaXNJbnRlcnJ1cHRSZXN1bWUpIHtcbiAgICBkZWxldGUgc3RhbmRJbi5yZXRyeTtcbiAgICBkZWxldGUgc3RhbmRJbi5pc1N0cmVhbWluZztcbiAgICBkZWxldGUgc3RhbmRJbi5zdHJlYW1JZDtcbiAgfVxuICByZXR1cm4gc3RhbmRJbjtcbn1cblxuLyoqIFRoZSBmbG93IGNoYW5uZWwncyBpc29sYXRpb24gZm9yIHRoZSBleGVjdXRvci1tYWRlIGBvblJlc3VtZWAgKGRldi1tb2RlIHdhcm5pbmcsIHRoZW4gc2tpcCkuICovXG5jb25zdCBSRVNVTUVfRkxPV19GQUlMVVJFID0gd2FybkluRGV2TW9kZSgnRmxvd0NoYXJ0RXhlY3V0b3InKTtcblxuLyoqXG4gKiBUaGUgcmVzdW1lIGV2ZW50J3MgbGluaywgcmVhZCBvZmYgdGhlIGNoZWNrcG9pbnQgaXRzZWxmIOKAlCBzbyBhIHJlc3VtZSByZWNvcmRzXG4gKiB0aGUgc2FtZSB3aGVyZXZlciBpdHMgY2hlY2twb2ludCBjYW1lIGZyb20uIGB1bmRlZmluZWRgIGZvciBhIGNoZWNrcG9pbnRcbiAqIHdpdGhvdXQgYHBhdXNlZEV4ZWN1dGlvbmAgKG1hZGUgYmVmb3JlIDkuMzcuMCkgb3Igd2l0aCBhIG1hbGZvcm1lZCBvbmU6IHRoZVxuICogbGluayBpcyBhIHJlY29yZCwgbmV2ZXIgdXNlZCB0byBwbGFuIHRoZSByZS1lbnRyeSwgc28gaXQgaXMgbGVmdCBvdXQgcmF0aGVyXG4gKiB0aGFuIGd1ZXNzZWQuXG4gKi9cbmZ1bmN0aW9uIHJlc3VtZUxpbmtPZihjaGVja3BvaW50OiBGbG93Y2hhcnRDaGVja3BvaW50KTogUmVzdW1lTGluayB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhdXNlZDogdW5rbm93biA9IGNoZWNrcG9pbnQucGF1c2VkRXhlY3V0aW9uO1xuICByZXR1cm4gaXNQYXVzZWRFeGVjdXRpb24ocGF1c2VkKSA/IHsgcnVuSWQ6IHBhdXNlZC5ydW5JZCwgcnVudGltZVN0YWdlSWQ6IHBhdXNlZC5ydW50aW1lU3RhZ2VJZCB9IDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgb2JqZWN0IGZvciBgRmxvd0NoYXJ0RXhlY3V0b3JgIOKAlCBwcmVmZXJyZWQgb3ZlciBwb3NpdGlvbmFsIHBhcmFtcy5cbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBleCA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCwge1xuICogICBzY29wZUZhY3Rvcnk6IG15RmFjdG9yeSxcbiAqICAgZGVmYXVsdFZhbHVlc0ZvckNvbnRleHQ6IHsgLi4uIH0sXG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqICoqU3luYyBub3RlIGZvciBtYWludGFpbmVyczoqKiBFdmVyeSBmaWVsZCBhZGRlZCBoZXJlIG11c3QgYWxzbyBhcHBlYXIgaW4gdGhlXG4gKiBgZmxvd0NoYXJ0QXJnc2AgcHJpdmF0ZSBmaWVsZCB0eXBlIGFuZCBpbiB0aGUgY29uc3RydWN0b3IncyBvcHRpb25zLXJlc29sdXRpb25cbiAqIGJsb2NrICh0aGUgYGVsc2UgaWZgIGJyYW5jaCB0aGF0IHJlYWRzIGZyb20gYG9wdHNgKS4gTWlzc2luZyBhbnkgb25lIG9mIHRoZVxuICogdGhyZWUgY2F1c2VzIHNpbGVudCBvbWlzc2lvbiDigJQgdGhlIG9wdGlvbiBpcyBhY2NlcHRlZCBidXQgbmV2ZXIgYXBwbGllZC5cbiAqIFRoZSBvYnNlcnZhYmlsaXR5IERJQUxTIGFyZSB0aGUgZXhjZXB0aW9uOiB0aGV5IGNvbWUgZnJvbSBgUnVuRGlhbHNgXG4gKiAobWVtb3J5L3J1blBvbGljeS50cykgYW5kIHRyYXZlbCBhcyBvbmUgYGRpYWxzYCBmaWVsZCwgc28gYSBuZXcgZGlhbCBpc1xuICogYWRkZWQgdGhlcmUgYW5kIG5vd2hlcmUgaGVyZS5cbiAqXG4gKiAqKlRTY29wZSBpbmZlcmVuY2Ugbm90ZToqKiBXaGVuIHVzaW5nIHRoZSBvcHRpb25zLW9iamVjdCBmb3JtIHdpdGggYSBjdXN0b20gc2NvcGUsXG4gKiBUeXBlU2NyaXB0IGNhbm5vdCBpbmZlciBgVFNjb3BlYCB0aHJvdWdoIHRoZSBvcHRpb25zIG9iamVjdC4gUGFzcyB0aGUgdHlwZVxuICogZXhwbGljaXRseTogYG5ldyBGbG93Q2hhcnRFeGVjdXRvcjxUT3V0LCBNeVNjb3BlPihjaGFydCwgeyBzY29wZUZhY3RvcnkgfSlgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZsb3dDaGFydEV4ZWN1dG9yT3B0aW9uczxUU2NvcGUgPSBhbnk+IGV4dGVuZHMgUnVuRGlhbHMge1xuICAvLyDilIDilIAgQ29tbW9uIG9wdGlvbnMgKG1vc3QgY2FsbGVycyBuZWVkIG9ubHkgdGhlc2UpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBDdXN0b20gc2NvcGUgZmFjdG9yeS4gRGVmYXVsdHMgdG8gVHlwZWRTY29wZSBvciBTY29wZUZhY2FkZSBhdXRvLWRldGVjdGlvbi4gKi9cbiAgc2NvcGVGYWN0b3J5PzogU2NvcGVGYWN0b3J5PFRTY29wZT47XG5cbiAgLy8g4pSA4pSAIENvbnRleHQgb3B0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogRGVmYXVsdCB2YWx1ZXMgcHJlLXBvcHVsYXRlZCBpbnRvIHRoZSBzaGFyZWQgY29udGV4dCBiZWZvcmUgKiplYWNoKiogc3RhZ2VcbiAgICogKHJlLWFwcGxpZWQgZXZlcnkgc3RhZ2UsIGFjdGluZyBhcyBiYXNlbGluZSBkZWZhdWx0cykuXG4gICAqL1xuICBkZWZhdWx0VmFsdWVzRm9yQ29udGV4dD86IHVua25vd247XG4gIC8qKlxuICAgKiBJbml0aWFsIGNvbnRleHQgdmFsdWVzIG1lcmdlZCBpbnRvIHRoZSBzaGFyZWQgY29udGV4dCAqKm9uY2UqKiBhdCBzdGFydHVwXG4gICAqIChhcHBsaWVkIGJlZm9yZSB0aGUgZmlyc3Qgc3RhZ2UsIG5vdCByZXBlYXRlZCBvbiBzdWJzZXF1ZW50IHN0YWdlcykuXG4gICAqIERpc3RpbmN0IGZyb20gYGRlZmF1bHRWYWx1ZXNGb3JDb250ZXh0YCwgd2hpY2ggaXMgcmUtYXBwbGllZCBldmVyeSBzdGFnZS5cbiAgICovXG4gIGluaXRpYWxDb250ZXh0PzogdW5rbm93bjtcbiAgLyoqIFJlYWQtb25seSBpbnB1dCBhY2Nlc3NpYmxlIHZpYSBgc2NvcGUuZ2V0QXJncygpYCDigJQgbmV2ZXIgdHJhY2tlZCBvciB3cml0dGVuLiAqL1xuICByZWFkT25seUNvbnRleHQ/OiB1bmtub3duO1xuXG4gIC8vIOKUgOKUgCBPYnNlcnZhYmlsaXR5IGNvc3Qgb3B0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVGhlIGZvdXIgZGlhbHMg4oCUIGByZWFkVHJhY2tpbmdgLCBgd3JpdGVUcmFja2luZ2AsIGBjb21taXRWYWx1ZXNgLFxuICAvLyBgd3JpdGVQcm92ZW5hbmNlYCDigJQgYXJlIGluaGVyaXRlZCBmcm9tIGBSdW5EaWFsc2AgKG1lbW9yeS9ydW5Qb2xpY3kudHMsXG4gIC8vIHdoZXJlIGVhY2ggaXMgZG9jdW1lbnRlZCk6IHRoZSBleGVjdXRvciBwaWNrcyB0aGVtIG9mZiB0aGlzIG9iamVjdCBhbmRcbiAgLy8gYnVpbGRzIHRoZSBydW4ncyBPTkUgcG9saWN5IGZyb20gdGhlbSAoRjUpLlxuXG4gIC8vIOKUgOKUgCBBZHZhbmNlZCAvIGVzY2FwZS1oYXRjaCBvcHRpb25zIChtb3N0IGNhbGxlcnMgZG8gbm90IG5lZWQgdGhlc2UpIOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBDdXN0b20gZXJyb3IgY2xhc3NpZmllciBmb3IgdGhyb3R0bGluZyBkZXRlY3Rpb24uIFJldHVybiBgdHJ1ZWAgaWYgYSBmb3JrXG4gICAqIGNoaWxkJ3MgZXJyb3IgcmVwcmVzZW50cyBhIHJhdGUtbGltaXQgb3IgYmFja3ByZXNzdXJlIGNvbmRpdGlvbjsgdGhlXG4gICAqIGV4ZWN1dG9yIHRoZW4gZmlyZXMgYEZsb3dSZWNvcmRlci5vblRocm90dGxlZGAgZm9yIHRoYXQgY2hpbGQgKDkuMzkuMCDigJRcbiAgICogYW4gRVZFTlQsIG5vdCBhIHN0YXRlIGtleTogdGhlIGBtb25pdG9yLmlzVGhyb3R0bGVkYCB3cml0ZSBpdCByZXBsYWNlZFxuICAgKiBuZXZlciBsYW5kZWQpLiBUaGUgY2hpbGQncyBmYWlsdXJlIGlzIG90aGVyd2lzZSBoYW5kbGVkIGFzIGJlZm9yZS5cbiAgICogRGVmYXVsdHMgdG8gbm8gdGhyb3R0bGluZyBjbGFzc2lmaWNhdGlvbi5cbiAgICovXG4gIHRocm90dGxpbmdFcnJvckNoZWNrZXI/OiAoZXJyb3I6IHVua25vd24pID0+IGJvb2xlYW47XG4gIC8qKiBIYW5kbGVycyBmb3Igc3RyZWFtaW5nIHN0YWdlIGxpZmVjeWNsZSBldmVudHMgKHNlZSBgYWRkU3RyZWFtaW5nRnVuY3Rpb25gKS4gKi9cbiAgc3RyZWFtSGFuZGxlcnM/OiBTdHJlYW1IYW5kbGVycztcbiAgLyoqIFNjb3BlIHByb3RlY3Rpb24gbW9kZSBmb3IgVHlwZWRTY29wZSBkaXJlY3QtYXNzaWdubWVudCBkZXRlY3Rpb24uICovXG4gIHNjb3BlUHJvdGVjdGlvbk1vZGU/OiBTY29wZVByb3RlY3Rpb25Nb2RlO1xufVxuXG5leHBvcnQgY2xhc3MgRmxvd0NoYXJ0RXhlY3V0b3I8VE91dCA9IGFueSwgVFNjb3BlID0gYW55PiB7XG4gIHByaXZhdGUgdHJhdmVyc2VyOiBGbG93Y2hhcnRUcmF2ZXJzZXI8VE91dCwgVFNjb3BlPjtcbiAgLyoqIFNoYXJlZCBleGVjdXRpb24gY291bnRlciDigJQgc3Vydml2ZXMgcGF1c2UvcmVzdW1lLiBSZXNldCBvbiBmcmVzaCBydW4oKS4gKi9cbiAgcHJpdmF0ZSBfZXhlY3V0aW9uQ291bnRlciA9IHsgdmFsdWU6IDAgfTtcbiAgLyoqIFNoYXJlZCBwZXItcnVuIHZpc2l0IGNvdW50cyAoYnkgc3RhZ2VJZCkgZHJpdmluZyBUcmF2ZXJzYWxDb250ZXh0Lmxvb3BJdGVyYXRpb24uXG4gICAqICBUd2luIG9mIF9leGVjdXRpb25Db3VudGVyOiBzdXJ2aXZlcyBwYXVzZS9yZXN1bWUsIHJlc2V0IG9uIGZyZXNoIHJ1bigpLiAqL1xuICBwcml2YXRlIF92aXNpdENvdW50cyA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIC8qKiBQZXItYHJ1bigpYCBpZGVudGlmaWVyIOKAlCBnZW5lcmF0ZWQgZnJlc2ggcGVyIHJ1biArIHBlciByZXN1bWUuIFRocmVhZGVkXG4gICAqICB0aHJvdWdoIGV2ZXJ5IFRyYXZlcnNhbENvbnRleHQgc28gcmVjb3JkZXJzIGNhbiBzY29wZSBzdGF0ZSB0byBhIHNpbmdsZVxuICAgKiAgcnVuLiBTZWUgYHJ1bklkLnRzYC4gKi9cbiAgcHJpdmF0ZSBfY3VycmVudFJ1bklkID0gJyc7XG4gIHByaXZhdGUgbmFycmF0aXZlRW5hYmxlZCA9IGZhbHNlO1xuICBwcml2YXRlIG5hcnJhdGl2ZU9wdGlvbnM/OiBDb21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyT3B0aW9ucztcbiAgcHJpdmF0ZSBjb21iaW5lZFJlY29yZGVyOiBDb21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGZsb3dSZWNvcmRlcnM6IEZsb3dSZWNvcmRlcltdID0gW107XG4gIHByaXZhdGUgc2NvcGVSZWNvcmRlcnM6IFNjb3BlUmVjb3JkZXJbXSA9IFtdO1xuICAvKipcbiAgICogUkZDLTAwMSBkZWZlcnJlZC1vYnNlcnZlciB3aXJpbmcg4oCUIGNyZWF0ZWQgTEFaSUxZIG9uIHRoZSBmaXJzdFxuICAgKiBgZGVsaXZlcnk6ICdkZWZlcnJlZCdgIGF0dGFjaC4gYHVuZGVmaW5lZGAgZm9yIGV2ZXJ5IGV4ZWN1dG9yIHRoYXQgbmV2ZXJcbiAgICogb3B0cyBpbjogemVybyBhbGxvY2F0aW9uLCB6ZXJvIHBlci1ldmVudCBjb3N0LCBieXRlLWlkZW50aWNhbCBiZWhhdmlvclxuICAgKiAodGhlIGVtaXQgZmFzdC1wYXRoIHByZWNlZGVudCkuXG4gICAqL1xuICBwcml2YXRlIGRlZmVycmVkVGllcj86IERlZmVycmVkT2JzZXJ2ZXJUaWVyO1xuICBwcml2YXRlIHJlZGFjdGlvblBvbGljeTogUmVkYWN0aW9uUG9saWN5IHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogVGhlIHJ1bidzIE9ORSByZWRhY3Rpb24gcnVsZSAoYG1lbW9yeS9yZWRhY3Rpb24udHNgKTogYnVpbHQgZnJlc2ggcGVyXG4gICAqIGBjcmVhdGVUcmF2ZXJzZXJgIChwZXItY2FsbCBtYXJrcyByZXNldCBwZXIgcnVuIGFuZCBwZXIgcmVzdW1lLCBhcyB0aGVcbiAgICogc2hhcmVkIHNldCBhbHdheXMgZGlkKSwgaW5zdGFsbGVkIG9uIHRoZSBydW50aW1lIHJvb3Qgc28gZXZlcnkgY29udGV4dFxuICAgKiByZXRhaW5zIHVuZGVyIGl0LCBhbmQgcmVhZCBieSBldmVyeSBgU2NvcGVGYWNhZGVgIHRocm91Z2ggaXRzIGNvbnRleHQuXG4gICAqL1xuICBwcml2YXRlIHJlZGFjdGlvblJ1bGUgPSBuZXcgUmVkYWN0aW9uUnVsZSgpO1xuICBwcml2YXRlIGxhc3RDaGVja3BvaW50OiBGbG93Y2hhcnRDaGVja3BvaW50IHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogYHRydWVgIG9uY2UgYHJ1bigpYCAob3IgYSBwcmV2aW91cyBgcmVzdW1lKClgKSBoYXMgZXhlY3V0ZWQgb25cbiAgICogdGhpcyBpbnN0YW5jZS4gYHJlc3VtZSgpYCBicmFuY2hlcyBvbiBpdDpcbiAgICpcbiAgICogICDigKIgdHJ1ZSAg4oaSIHJldXNlIHRoZSBjb25zdHJ1Y3Rvci10aW1lIHJ1bnRpbWUgKHNhbWUtZXhlY3V0b3JcbiAgICogICAgICAgICAgICAgY29udGludWl0eTogZXhlY3V0aW9uIHRyZWUsIHJlY29yZGVycywgbmFycmF0aXZlXG4gICAqICAgICAgICAgICAgIGFjY3VtdWxhdGUgYWNyb3NzIHBhdXNlL3Jlc3VtZSBjeWNsZXMpXG4gICAqICAg4oCiIGZhbHNlIOKGkiBzZWVkIGEgZnJlc2ggcnVudGltZSBmcm9tIGBjaGVja3BvaW50LnNoYXJlZFN0YXRlYFxuICAgKiAgICAgICAgICAgICAoY3Jvc3MtZXhlY3V0b3IgLyBjcm9zcy1wcm9jZXNzIHJlc3VtZTogbmV3IGluc3RhbmNlXG4gICAqICAgICAgICAgICAgIHJlY29uc3RydWN0ZWQgZnJvbSBhIHNlcmlhbGl6ZWQgY2hlY2twb2ludClcbiAgICpcbiAgICogV2l0aG91dCB0aGlzIGZsYWcsIGZyZXNoIGV4ZWN1dG9ycyBzaWxlbnRseSBkaXNjYXJkZWQgdGhlXG4gICAqIGNoZWNrcG9pbnQncyBzaGFyZWRTdGF0ZSBhbmQgcmVzdW1lIGhhbmRsZXJzIGNvdWxkbid0IHJlYWQgcHJlLXBhdXNlXG4gICAqIHNjb3BlLiBTZWUgYHRlc3QvbGliL3BhdXNlL2Nyb3NzLWV4ZWN1dG9yLXJlc3VtZS50ZXN0LnRzYC5cbiAgICovXG4gIHByaXZhdGUgX2hhc1J1bkJlZm9yZSA9IGZhbHNlO1xuICAvKipcbiAgICogUmUtZW50cmFuY3kgZ3VhcmQuIGBydW4oKWAgYW5kIGByZXN1bWUoKWAgbXV0YXRlIHBlci1ydW4gaW5zdGFuY2Ugc3RhdGVcbiAgICogKHRyYXZlcnNlciwgcnVuSWQsIGV4ZWN1dGlvbiBjb3VudGVyLCBjaGVja3BvaW50KSBhbmQgY2xlYXIgYXR0YWNoZWRcbiAgICogcmVjb3JkZXJzIOKAlCBhIHNlY29uZCBjb25jdXJyZW50IGVudHJ5IG9uIHRoZSBTQU1FIGV4ZWN1dG9yIHdvdWxkXG4gICAqIGludGVybGVhdmUgcnVuSWRzIGFuZCBjcm9zcy1jb250YW1pbmF0ZSByZWNvcmRlci9uYXJyYXRpdmUgc3RhdGUsIGFuZFxuICAgKiBgZ2V0Q2hlY2twb2ludCgpYCB3b3VsZCByZXR1cm4gd2hpY2hldmVyIHJ1biBwYXVzZWQgbGFzdC4gT25lIGV4ZWN1dG9yID1cbiAgICogb25lIGluLWZsaWdodCBleGVjdXRpb247IGNyZWF0ZSBhbiBleGVjdXRvciBwZXIgY29uY3VycmVudCBydW4uXG4gICAqIFNlZSBkb2NzL2d1aWRlcy9leGVjdXRpb24tbW9kZWwubWQuXG4gICAqL1xuICBwcml2YXRlIF9pc0V4ZWN1dGluZyA9IGZhbHNlO1xuXG4gIC8vIFNZTkMgUkVRVUlSRUQ6IGV2ZXJ5IG9wdGlvbmFsIGZpZWxkIGhlcmUgbXVzdCBtaXJyb3IgRmxvd0NoYXJ0RXhlY3V0b3JPcHRpb25zXG4gIC8vIEFORCBiZSBhc3NpZ25lZCBpbiB0aGUgY29uc3RydWN0b3IncyBvcHRpb25zLXJlc29sdXRpb24gYmxvY2sgKHRoZSBgZWxzZSBpZmAgYnJhbmNoKS5cbiAgLy8gQWRkaW5nIGEgZmllbGQgdG8gb25seSBvbmUgb2YgdGhlIHRocmVlIHBsYWNlcyBjYXVzZXMgc2lsZW50IG9taXNzaW9uLlxuICAvLyAoVGhlIGRpYWxzIHJpZGUgYGRpYWxzYCB3aG9sZSDigJQgYHBpY2tEaWFsc2AgcmVhZHMgZXZlcnkgb25lIFJ1bkRpYWxzIGRlY2xhcmVzLilcbiAgcHJpdmF0ZSByZWFkb25seSBmbG93Q2hhcnRBcmdzOiB7XG4gICAgZmxvd0NoYXJ0OiBGbG93Q2hhcnQ8VE91dCwgVFNjb3BlPjtcbiAgICBzY29wZUZhY3Rvcnk6IFNjb3BlRmFjdG9yeTxUU2NvcGU+O1xuICAgIGRlZmF1bHRWYWx1ZXNGb3JDb250ZXh0PzogdW5rbm93bjtcbiAgICBpbml0aWFsQ29udGV4dD86IHVua25vd247XG4gICAgcmVhZE9ubHlDb250ZXh0PzogdW5rbm93bjtcbiAgICB0aHJvdHRsaW5nRXJyb3JDaGVja2VyPzogKGVycm9yOiB1bmtub3duKSA9PiBib29sZWFuO1xuICAgIHN0cmVhbUhhbmRsZXJzPzogU3RyZWFtSGFuZGxlcnM7XG4gICAgc2NvcGVQcm90ZWN0aW9uTW9kZT86IFNjb3BlUHJvdGVjdGlvbk1vZGU7XG4gICAgLyoqIFRoZSBkaWFscyBhcyBnaXZlbiAoYWJzZW50ID0gZGVmYXVsdCkg4oCUIHRoZSBydW4ncyBwb2xpY3kgaXMgYnVpbHQgZnJvbSB0aGVtIHBlciBsZWcuICovXG4gICAgZGlhbHM6IFJ1bkRpYWxzO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBGbG93Q2hhcnRFeGVjdXRvci5cbiAgICpcbiAgICogKipPcHRpb25zIG9iamVjdCBmb3JtKiogKHByZWZlcnJlZCk6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogbmV3IEZsb3dDaGFydEV4ZWN1dG9yKGNoYXJ0LCB7IHNjb3BlRmFjdG9yeSwgZGVmYXVsdFZhbHVlc0ZvckNvbnRleHQgfSlcbiAgICogYGBgXG4gICAqXG4gICAqICoqMi1wYXJhbSBmb3JtKiogKGFsc28gc3VwcG9ydGVkKTpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBuZXcgRmxvd0NoYXJ0RXhlY3V0b3IoY2hhcnQsIHNjb3BlRmFjdG9yeSlcbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSBmbG93Q2hhcnQgLSBUaGUgY29tcGlsZWQgRmxvd0NoYXJ0IHJldHVybmVkIGJ5IGBmbG93Q2hhcnQoLi4uKS5idWlsZCgpYFxuICAgKiBAcGFyYW0gZmFjdG9yeU9yT3B0aW9ucyAtIEEgYFNjb3BlRmFjdG9yeTxUU2NvcGU+YCBPUiBhIGBGbG93Q2hhcnRFeGVjdXRvck9wdGlvbnM8VFNjb3BlPmAgb3B0aW9ucyBvYmplY3QuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBmbG93Q2hhcnQ6IEZsb3dDaGFydDxUT3V0LCBUU2NvcGU+LFxuICAgIGZhY3RvcnlPck9wdGlvbnM/OiBTY29wZUZhY3Rvcnk8VFNjb3BlPiB8IEZsb3dDaGFydEV4ZWN1dG9yT3B0aW9uczxUU2NvcGU+LFxuICApIHtcbiAgICAvLyBEZXRlY3Qgb3B0aW9ucy1vYmplY3QgZm9ybSB2cyBmYWN0b3J5IGZvcm1cbiAgICBsZXQgc2NvcGVGYWN0b3J5OiBTY29wZUZhY3Rvcnk8VFNjb3BlPiB8IHVuZGVmaW5lZDtcbiAgICBsZXQgZGVmYXVsdFZhbHVlc0ZvckNvbnRleHQ6IHVua25vd247XG4gICAgbGV0IGluaXRpYWxDb250ZXh0OiB1bmtub3duO1xuICAgIGxldCByZWFkT25seUNvbnRleHQ6IHVua25vd247XG4gICAgbGV0IHRocm90dGxpbmdFcnJvckNoZWNrZXI6ICgoZXJyb3I6IHVua25vd24pID0+IGJvb2xlYW4pIHwgdW5kZWZpbmVkO1xuICAgIGxldCBzdHJlYW1IYW5kbGVyczogU3RyZWFtSGFuZGxlcnMgfCB1bmRlZmluZWQ7XG4gICAgbGV0IHNjb3BlUHJvdGVjdGlvbk1vZGU6IFNjb3BlUHJvdGVjdGlvbk1vZGUgfCB1bmRlZmluZWQ7XG4gICAgbGV0IGRpYWxzOiBSdW5EaWFscyA9IHt9O1xuXG4gICAgaWYgKHR5cGVvZiBmYWN0b3J5T3JPcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyAyLXBhcmFtIGZvcm06IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCwgc2NvcGVGYWN0b3J5KVxuICAgICAgc2NvcGVGYWN0b3J5ID0gZmFjdG9yeU9yT3B0aW9ucztcbiAgICB9IGVsc2UgaWYgKGZhY3RvcnlPck9wdGlvbnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gT3B0aW9ucyBvYmplY3QgZm9ybVxuICAgICAgY29uc3Qgb3B0cyA9IGZhY3RvcnlPck9wdGlvbnM7XG4gICAgICBzY29wZUZhY3RvcnkgPSBvcHRzLnNjb3BlRmFjdG9yeTtcbiAgICAgIGRlZmF1bHRWYWx1ZXNGb3JDb250ZXh0ID0gb3B0cy5kZWZhdWx0VmFsdWVzRm9yQ29udGV4dDtcbiAgICAgIGluaXRpYWxDb250ZXh0ID0gb3B0cy5pbml0aWFsQ29udGV4dDtcbiAgICAgIHJlYWRPbmx5Q29udGV4dCA9IG9wdHMucmVhZE9ubHlDb250ZXh0O1xuICAgICAgdGhyb3R0bGluZ0Vycm9yQ2hlY2tlciA9IG9wdHMudGhyb3R0bGluZ0Vycm9yQ2hlY2tlcjtcbiAgICAgIHN0cmVhbUhhbmRsZXJzID0gb3B0cy5zdHJlYW1IYW5kbGVycztcbiAgICAgIHNjb3BlUHJvdGVjdGlvbk1vZGUgPSBvcHRzLnNjb3BlUHJvdGVjdGlvbk1vZGU7XG4gICAgICBkaWFscyA9IHBpY2tEaWFscyhvcHRzKTtcbiAgICB9XG4gICAgdGhpcy5mbG93Q2hhcnRBcmdzID0ge1xuICAgICAgZmxvd0NoYXJ0LFxuICAgICAgc2NvcGVGYWN0b3J5OiBzY29wZUZhY3RvcnkgPz8gZmxvd0NoYXJ0LnNjb3BlRmFjdG9yeSA/PyAoZGVmYXVsdFNjb3BlRmFjdG9yeSBhcyBTY29wZUZhY3Rvcnk8VFNjb3BlPiksXG4gICAgICBkZWZhdWx0VmFsdWVzRm9yQ29udGV4dCxcbiAgICAgIGluaXRpYWxDb250ZXh0LFxuICAgICAgcmVhZE9ubHlDb250ZXh0LFxuICAgICAgdGhyb3R0bGluZ0Vycm9yQ2hlY2tlcixcbiAgICAgIHN0cmVhbUhhbmRsZXJzLFxuICAgICAgc2NvcGVQcm90ZWN0aW9uTW9kZSxcbiAgICAgIGRpYWxzLFxuICAgIH07XG4gICAgdGhpcy50cmF2ZXJzZXIgPSB0aGlzLmNyZWF0ZVRyYXZlcnNlcigpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVUcmF2ZXJzZXIoXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICAgcmVhZE9ubHlDb250ZXh0T3ZlcnJpZGU/OiB1bmtub3duLFxuICAgIGVudj86IGltcG9ydCgnLi4vZW5naW5lL3R5cGVzLmpzJykuRXhlY3V0aW9uRW52LFxuICAgIG1heERlcHRoPzogbnVtYmVyLFxuICAgIG1heEl0ZXJhdGlvbnM/OiBudW1iZXIsXG4gICAgb3ZlcnJpZGVzPzoge1xuICAgICAgaW5pdGlhbENvbnRleHQ/OiB1bmtub3duO1xuICAgICAgcHJlc2VydmVSZWNvcmRlcnM/OiBib29sZWFuO1xuICAgICAgZXhpc3RpbmdSdW50aW1lPzogSW5zdGFuY2VUeXBlPHR5cGVvZiBFeGVjdXRpb25SdW50aW1lPjtcbiAgICAgIC8qKiBUaGUgcmVzdW1lJ3Mgb25lLXNob3QgcmUtZW50cnkg4oCUIHdoZXJlIHRoZSByZXN1bWVkIHRyYXZlcnNhbFxuICAgICAgICogIHN0YXJ0cyAoYHJlc3VtZS5zdGFydGApIGFuZCB3aGF0IGVhY2ggc3ViZmxvdyBvbiB0aGUgcGF1c2UgcGF0aFxuICAgICAgICogIHRha2VzIG9uIGl0cyBmaXJzdCBlbnRyeS4gVGhlIHRyYXZlcnNlciBzdGlsbCB3YWxrcyB0aGUgUkVBTCBjaGFydFxuICAgICAgICogIChgZmMucm9vdGAsIGBmYy5zdWJmbG93c2ApOiB0aGUgcmUtZW50cnkgaXMgbmV2ZXIgYSBub2RlIGFuIGlkIGNhblxuICAgICAgICogIHJlc29sdmUgdG8uIFVuZGVmaW5lZCBvbiBub3JtYWwgcnVuKCkgcGF0aHMuICovXG4gICAgICByZXN1bWU/OiBSZXN1bWVFbnRyeTxUT3V0LCBUU2NvcGU+O1xuICAgIH0sXG4gICk6IEZsb3djaGFydFRyYXZlcnNlcjxUT3V0LCBUU2NvcGU+IHtcbiAgICBjb25zdCBhcmdzID0gdGhpcy5mbG93Q2hhcnRBcmdzO1xuICAgIGNvbnN0IGZjID0gYXJncy5mbG93Q2hhcnQ7XG4gICAgY29uc3QgbmFycmF0aXZlRmxhZyA9IHRoaXMubmFycmF0aXZlRW5hYmxlZCB8fCAoZmMuZW5hYmxlTmFycmF0aXZlID8/IGZhbHNlKTtcblxuICAgIC8vIOKUgOKUgCBDb21wb3NlZCBzY29wZSBmYWN0b3J5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAgIC8vIENvbGxlY3QgYWxsIHNjb3BlIG1vZGlmaWVycyAocmVjb3JkZXJzLCByZWRhY3Rpb24pIGludG8gYSBzaW5nbGUgbGlzdCxcbiAgICAvLyB0aGVuIGNyZWF0ZSBPTkUgZmFjdG9yeSB0aGF0IGFwcGxpZXMgdGhlbSBpbiBhIGxvb3AuIFJlcGxhY2VzIHRoZVxuICAgIC8vIHByZXZpb3VzIDQtZGVlcCBjbG9zdXJlIG5lc3Rpbmcgd2l0aCBhIGZsYXQsIGRlYnVnZ2FibGUgY29tcG9zaXRpb24uXG5cbiAgICBpZiAob3ZlcnJpZGVzPy5wcmVzZXJ2ZVJlY29yZGVycykge1xuICAgICAgLy8gUmVzdW1lIG1vZGU6IGtlZXAgZXhpc3RpbmcgY29tYmluZWRSZWNvcmRlciBzbyBuYXJyYXRpdmUgYWNjdW11bGF0ZXNcbiAgICB9IGVsc2UgaWYgKG5hcnJhdGl2ZUZsYWcpIHtcbiAgICAgIHRoaXMuY29tYmluZWRSZWNvcmRlciA9IG5ldyBDb21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyKHRoaXMubmFycmF0aXZlT3B0aW9ucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY29tYmluZWRSZWNvcmRlciA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICB0aGlzLnJlZGFjdGlvblJ1bGUgPSBuZXcgUmVkYWN0aW9uUnVsZSh0aGlzLnJlZGFjdGlvblBvbGljeSk7XG5cbiAgICAvLyBCdWlsZCBtb2RpZmllciBsaXN0IOKAlCBlYWNoIG1vZGlmaWVyIHJlY2VpdmVzIHRoZSBzY29wZSBhZnRlciBjcmVhdGlvblxuICAgIHR5cGUgU2NvcGVNb2RpZmllciA9IChzY29wZTogYW55KSA9PiB2b2lkO1xuICAgIGNvbnN0IG1vZGlmaWVyczogU2NvcGVNb2RpZmllcltdID0gW107XG5cbiAgICAvLyAxLiBOYXJyYXRpdmUgcmVjb3JkZXIgKGlmIGVuYWJsZWQpXG4gICAgaWYgKHRoaXMuY29tYmluZWRSZWNvcmRlcikge1xuICAgICAgY29uc3QgcmVjb3JkZXIgPSB0aGlzLmNvbWJpbmVkUmVjb3JkZXI7XG4gICAgICBtb2RpZmllcnMucHVzaCgoc2NvcGUpID0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzY29wZS5hdHRhY2hTY29wZVJlY29yZGVyID09PSAnZnVuY3Rpb24nKSBzY29wZS5hdHRhY2hTY29wZVJlY29yZGVyKHJlY29yZGVyKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIDIuIFVzZXItcHJvdmlkZWQgc2NvcGUgcmVjb3JkZXJzXG4gICAgaWYgKHRoaXMuc2NvcGVSZWNvcmRlcnMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgcmVjb3JkZXJzID0gdGhpcy5zY29wZVJlY29yZGVycztcbiAgICAgIG1vZGlmaWVycy5wdXNoKChzY29wZSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHNjb3BlLmF0dGFjaFNjb3BlUmVjb3JkZXIgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHIgb2YgcmVjb3JkZXJzKSBzY29wZS5hdHRhY2hTY29wZVJlY29yZGVyKHIpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyAyYi4gRGVmZXJyZWQtb2JzZXJ2ZXIgc2NvcGUgdGFwIChSRkMtMDAxIEJsb2NrIDcpIOKAlCBhIHN5bnRoZXRpY1xuICAgIC8vIHJlY29yZGVyIHdob3NlIGhvb2tzIENBUFRVUkUgaW50byB0aGUgYm91bmRlZCBxdWV1ZSBpbnN0ZWFkIG9mIGRvaW5nXG4gICAgLy8gb2JzZXJ2ZXIgd29yay4gSXQgcmlkZXMgdGhlIHNhbWUgcGVyLXN0YWdlIHJlY29yZGVyIGxpc3QgYXMgaW5saW5lXG4gICAgLy8gcmVjb3JkZXJzLCBzbyBpdCByZWNlaXZlcyBleGFjdGx5IHRoZSBwb3N0LXJlZGFjdGlvbiBldmVudHMgdGhleSBkby5cbiAgICAvLyBBYnNlbnQgKHplcm8gd29yaywgaWRlbnRpY2FsIGxpc3QpIHdoZW4gbm9ib2R5IG9wdGVkIGludG8gZGVmZXJyYWwuXG4gICAgY29uc3Qgc2NvcGVUYXAgPSB0aGlzLmRlZmVycmVkVGllcj8uYnVpbGRTY29wZVRhcCgpO1xuICAgIGlmIChzY29wZVRhcCkge1xuICAgICAgbW9kaWZpZXJzLnB1c2goKHNjb3BlKSA9PiB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2NvcGUuYXR0YWNoU2NvcGVSZWNvcmRlciA9PT0gJ2Z1bmN0aW9uJykgc2NvcGUuYXR0YWNoU2NvcGVSZWNvcmRlcihzY29wZVRhcCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyAzLiBSZWRhY3Rpb24gcG9saWN5IChjb25kaXRpb25hbCDigJQgb25seSB3aGVuIHBvbGljeSBpcyBzZXQpLiBBXG4gICAgLy8gYFNjb3BlRmFjYWRlYCBhbHJlYWR5IHJlYWRzIHRoZSBydW4ncyBydWxlIHRocm91Z2ggaXRzIGNvbnRleHQgKHRoZVxuICAgIC8vIHJ1bGUgaXMgaW5zdGFsbGVkIG9uIHRoZSBydW50aW1lIHJvb3QgYmVsb3cpOyB0aGlzIGNhbGwgaXMgdGhlIGxlZ2FjeVxuICAgIC8vIHByb3RvY29sIGZvciBjdXN0b20gc2NvcGVzIHRoYXQgYXJlIG5vdCBmYWNhZGVzLCBhbmQgb24gYSBmYWNhZGUgaXRcbiAgICAvLyByZS1zdGF0ZXMgdGhlIGV4ZWN1dG9yJ3MgcG9saWN5IG9uIHRoZSBzaGFyZWQgcnVsZSAoYSBuby1vcCkuXG4gICAgaWYgKHRoaXMucmVkYWN0aW9uUG9saWN5KSB7XG4gICAgICBjb25zdCBwb2xpY3kgPSB0aGlzLnJlZGFjdGlvblBvbGljeTtcbiAgICAgIG1vZGlmaWVycy5wdXNoKChzY29wZSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHNjb3BlLnVzZVJlZGFjdGlvblBvbGljeSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHNjb3BlLnVzZVJlZGFjdGlvblBvbGljeShwb2xpY3kpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBDb21wb3NlOiBiYXNlIGZhY3RvcnkgKyBtb2RpZmllcnMgaW4gYSBzaW5nbGUgcGFzcy5cbiAgICAvLyBUaGUgbWFya2VkLWtleXMgc2V0IGlzIEFMV0FZUyB3aXJlZCB1cCAodW5jb25kaXRpb25hbCDigJQgZW5zdXJlcyBjcm9zcy1zdGFnZVxuICAgIC8vIHByb3BhZ2F0aW9uIGV2ZW4gd2l0aG91dCBhIHBvbGljeSwgYmVjYXVzZSBzdGFnZXMgY2FuIGNhbGwgc2V0VmFsdWUoa2V5LCB2YWwsIHRydWUpXG4gICAgLy8gZm9yIHBlci1jYWxsIHJlZGFjdGlvbikuIE9wdGlvbmFsIG1vZGlmaWVycyAocmVjb3JkZXJzLCBwb2xpY3kpIGFyZSBpbiB0aGUgbGlzdC5cbiAgICBjb25zdCBiYXNlRmFjdG9yeSA9IGFyZ3Muc2NvcGVGYWN0b3J5O1xuICAgIGNvbnN0IHNoYXJlZFJlZGFjdGVkS2V5cyA9IHRoaXMucmVkYWN0aW9uUnVsZS5tYXJrZWRLZXlzKCk7XG4gICAgY29uc3Qgc2NvcGVGYWN0b3J5ID0gKChjdHg6IGFueSwgc3RhZ2VOYW1lOiBzdHJpbmcsIHJlYWRPbmx5PzogdW5rbm93biwgZW52QXJnPzogYW55KSA9PiB7XG4gICAgICBjb25zdCBzY29wZSA9IGJhc2VGYWN0b3J5KGN0eCwgc3RhZ2VOYW1lLCByZWFkT25seSwgZW52QXJnKTtcbiAgICAgIC8vIEFsd2F5cyB3aXJlIHNoYXJlZCByZWRhY3Rpb24gc3RhdGVcbiAgICAgIGlmICh0eXBlb2YgKHNjb3BlIGFzIGFueSkudXNlU2hhcmVkUmVkYWN0ZWRLZXlzID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIChzY29wZSBhcyBhbnkpLnVzZVNoYXJlZFJlZGFjdGVkS2V5cyhzaGFyZWRSZWRhY3RlZEtleXMpO1xuICAgICAgfVxuICAgICAgLy8gQXBwbHkgb3B0aW9uYWwgbW9kaWZpZXJzXG4gICAgICBmb3IgKGNvbnN0IG1vZCBvZiBtb2RpZmllcnMpIG1vZChzY29wZSk7XG4gICAgICByZXR1cm4gc2NvcGU7XG4gICAgfSkgYXMgU2NvcGVGYWN0b3J5PFRTY29wZT47XG5cbiAgICAvLyBUaGUgZmlyc3Qgc3RhZ2UgdGhpcyB0cmF2ZXJzYWwgcnVuczogdGhlIHJlc3VtZSdzIGVudHJ5LCBlbHNlIHRoZSBjaGFydCByb290LlxuICAgIGNvbnN0IGVmZmVjdGl2ZVJvb3QgPSBvdmVycmlkZXM/LnJlc3VtZT8uc3RhcnQgPz8gZmMucm9vdDtcbiAgICBjb25zdCBlZmZlY3RpdmVJbml0aWFsQ29udGV4dCA9IG92ZXJyaWRlcz8uaW5pdGlhbENvbnRleHQgPz8gYXJncy5pbml0aWFsQ29udGV4dDtcblxuICAgIC8vIFRoZSBydW4ncyBwb2xpY3kgKEY1KTogdGhlIGZvdXIgZGlhbHMsIHRoZSByZWRhY3Rpb24gcnVsZSBhbmQgdGhlXG4gICAgLy8gbWlycm9yIGZsYWcgYXMgT05FIGZyb3plbiBvYmplY3QsIGJ1aWx0IG9uY2UgcGVyIGxlZyDigJQgcnVuIEFORCByZXN1bWVcbiAgICAvLyAoYSByZXN1bWUgYnJpbmdzIGEgZnJlc2ggcnVsZSwgYXMgcGVyLWNhbGwgbWFya3MgcmVzZXQgcGVyIGxlZykuIFRoZVxuICAgIC8vIHJ1bnRpbWUgaW5zdGFsbHMgaXQgb24gaXRzIHJvb3Q7IGV2ZXJ5IGZyYW1lIG9mIHRoZSBydW4sIGEgc3ViZmxvdydzXG4gICAgLy8gaW5jbHVkZWQsIGhvbGRzIHRoZSBzYW1lIHJlZmVyZW5jZS4gVGhlIHJ1bGUgaXMgaW5zdGFsbGVkIGV2ZW4gd2l0aG91dFxuICAgIC8vIGEgcG9saWN5OiBhIHBlci1jYWxsIGBzZXRWYWx1ZShrZXksIHZhbHVlLCB0cnVlKWAgbWFya3MgdGhlIGtleSBvbiBpdCxcbiAgICAvLyBhbmQgdGhlIHBhdGhzIHRoYXQgYnlwYXNzIHRoZSBmYWNhZGUgKHN1YmZsb3cgc2VlZCwgb3V0cHV0TWFwcGVyXG4gICAgLy8gbWVyZ2UtYmFjaywgcmVzdW1lIHJlLXNlZWQpIGhvbm91ciB0aGF0IG1hcmsgdGhyb3VnaCBpdC4gVGhlIG1pcnJvciDigJRcbiAgICAvLyBhIHBhcmFsbGVsIHJlZGFjdGVkIGhlYXAsIHNvIGBnZXRTbmFwc2hvdCh7IHJlZGFjdDogdHJ1ZSB9KWAgaXMgc2VydmVkXG4gICAgLy8gYXQgemVybyBwb3N0LXBhc3MgY29zdCDigJQgaXMga2VwdCBvbmx5IHVuZGVyIGEgcG9saWN5LlxuICAgIGNvbnN0IHBvbGljeSA9IHJ1blBvbGljeShhcmdzLmRpYWxzLCB0aGlzLnJlZGFjdGlvblJ1bGUsIHRoaXMucmVkYWN0aW9uUG9saWN5ICE9PSB1bmRlZmluZWQpO1xuXG4gICAgbGV0IHJ1bnRpbWU6IEV4ZWN1dGlvblJ1bnRpbWU7XG4gICAgaWYgKG92ZXJyaWRlcz8uZXhpc3RpbmdSdW50aW1lKSB7XG4gICAgICAvLyBSZXN1bWUgbW9kZTogcmV1c2UgZXhpc3RpbmcgcnVudGltZSBzbyBleGVjdXRpb24gdHJlZSBjb250aW51ZXMgZnJvbSBwYXVzZSBwb2ludC5cbiAgICAgIC8vIFByZXNlcnZlIHRoZSBvcmlnaW5hbCByb290IGZvciBnZXRTbmFwc2hvdCgpIChmdWxsIHRyZWUpLCB0aGVuIGFkdmFuY2VcbiAgICAgIC8vIHJvb3RTdGFnZUNvbnRleHQgdG8gYSBjb250aW51YXRpb24gZnJvbSB0aGUgbGVhZiAoZm9yIHRyYXZlcnNhbCkuXG4gICAgICBydW50aW1lID0gb3ZlcnJpZGVzLmV4aXN0aW5nUnVudGltZTtcbiAgICAgIHJ1bnRpbWUucHJlc2VydmVTbmFwc2hvdFJvb3QoKTtcbiAgICAgIGxldCBsZWFmID0gcnVudGltZS5yb290U3RhZ2VDb250ZXh0O1xuICAgICAgd2hpbGUgKGxlYWYubmV4dCkgbGVhZiA9IGxlYWYubmV4dDtcbiAgICAgIHJ1bnRpbWUucm9vdFN0YWdlQ29udGV4dCA9IGxlYWYuY3JlYXRlTmV4dCgnJywgZWZmZWN0aXZlUm9vdC5uYW1lLCBlZmZlY3RpdmVSb290LmlkKTtcbiAgICAgIHJ1bnRpbWUudXNlUG9saWN5KHBvbGljeSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJ1bnRpbWUgPSBuZXcgRXhlY3V0aW9uUnVudGltZShcbiAgICAgICAgZWZmZWN0aXZlUm9vdC5uYW1lLFxuICAgICAgICBlZmZlY3RpdmVSb290LmlkLFxuICAgICAgICBhcmdzLmRlZmF1bHRWYWx1ZXNGb3JDb250ZXh0LFxuICAgICAgICBlZmZlY3RpdmVJbml0aWFsQ29udGV4dCxcbiAgICAgICAgcG9saWN5LFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEZsb3djaGFydFRyYXZlcnNlcjxUT3V0LCBUU2NvcGU+KHtcbiAgICAgIC8vIEFsd2F5cyB0aGUgUkVBTCBjaGFydCDigJQgZXZlcnkgaWQgKGxvb3AgdGFyZ2V0cywgYSByZS12aXNpdCBvZiB0aGVcbiAgICAgIC8vIHBhdXNlZCBzdGFnZSkgcmVzb2x2ZXMgYWdhaW5zdCBpdC4gQSByZXN1bWUgb25seSBtb3ZlcyB3aGVyZSB0aGVcbiAgICAgIC8vIHRyYXZlcnNhbCBTVEFSVFMgKGBlbnRyeWApLCBvbmNlLlxuICAgICAgcm9vdDogZmMucm9vdCxcbiAgICAgIC4uLihvdmVycmlkZXM/LnJlc3VtZT8uc3RhcnQgJiYgeyBlbnRyeTogb3ZlcnJpZGVzLnJlc3VtZS5zdGFydCB9KSxcbiAgICAgIC4uLihvdmVycmlkZXM/LnJlc3VtZT8uc3RhcnRQZW5kaW5nUGF1c2VzICYmIHsgcGVuZGluZ1BhdXNlczogb3ZlcnJpZGVzLnJlc3VtZS5zdGFydFBlbmRpbmdQYXVzZXMgfSksXG4gICAgICAuLi4ob3ZlcnJpZGVzPy5yZXN1bWUgJiYgeyByZXN1bWU6IG92ZXJyaWRlcy5yZXN1bWUgfSksXG4gICAgICBzdGFnZU1hcDogZmMuc3RhZ2VNYXAsXG4gICAgICBzY29wZUZhY3RvcnksXG4gICAgICBleGVjdXRpb25SdW50aW1lOiBydW50aW1lLFxuICAgICAgcmVhZE9ubHlDb250ZXh0OiByZWFkT25seUNvbnRleHRPdmVycmlkZSA/PyBhcmdzLnJlYWRPbmx5Q29udGV4dCxcbiAgICAgIHRocm90dGxpbmdFcnJvckNoZWNrZXI6IGFyZ3MudGhyb3R0bGluZ0Vycm9yQ2hlY2tlcixcbiAgICAgIHN0cmVhbUhhbmRsZXJzOiBhcmdzLnN0cmVhbUhhbmRsZXJzLFxuICAgICAgc2NvcGVQcm90ZWN0aW9uTW9kZTogYXJncy5zY29wZVByb3RlY3Rpb25Nb2RlLFxuICAgICAgc3ViZmxvd3M6IGZjLnN1YmZsb3dzLFxuICAgICAgbmFycmF0aXZlRW5hYmxlZDogbmFycmF0aXZlRmxhZyxcbiAgICAgIGJ1aWxkVGltZVN0cnVjdHVyZTogZmMuYnVpbGRUaW1lU3RydWN0dXJlLFxuICAgICAgbG9nZ2VyOiBmYy5sb2dnZXIgPz8gZGVmYXVsdExvZ2dlcixcbiAgICAgIHNpZ25hbCxcbiAgICAgIGV4ZWN1dGlvbkVudjogZW52LFxuICAgICAgZmxvd1JlY29yZGVyczogdGhpcy5idWlsZEZsb3dSZWNvcmRlcnNMaXN0KCksXG4gICAgICBleGVjdXRpb25Db3VudGVyOiB0aGlzLl9leGVjdXRpb25Db3VudGVyLFxuICAgICAgdmlzaXRDb3VudHM6IHRoaXMuX3Zpc2l0Q291bnRzLFxuICAgICAgcnVuSWQ6IHRoaXMuX2N1cnJlbnRSdW5JZCxcbiAgICAgIC4uLihtYXhEZXB0aCAhPT0gdW5kZWZpbmVkICYmIHsgbWF4RGVwdGggfSksXG4gICAgICAuLi4obWF4SXRlcmF0aW9ucyAhPT0gdW5kZWZpbmVkICYmIHsgbWF4SXRlcmF0aW9ucyB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIGVuYWJsZU5hcnJhdGl2ZShvcHRpb25zPzogQ29tYmluZWROYXJyYXRpdmVSZWNvcmRlck9wdGlvbnMpOiB2b2lkIHtcbiAgICB0aGlzLm5hcnJhdGl2ZUVuYWJsZWQgPSB0cnVlO1xuICAgIGlmIChvcHRpb25zKSB0aGlzLm5hcnJhdGl2ZU9wdGlvbnMgPSBvcHRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhIGRlY2xhcmF0aXZlIHJlZGFjdGlvbiBwb2xpY3kgdGhhdCBhcHBsaWVzIHRvIGFsbCBzdGFnZXMuXG4gICAqIE11c3QgYmUgY2FsbGVkIGJlZm9yZSBydW4oKS5cbiAgICovXG4gIHNldFJlZGFjdGlvblBvbGljeShwb2xpY3k6IFJlZGFjdGlvblBvbGljeSk6IHZvaWQge1xuICAgIHRoaXMucmVkYWN0aW9uUG9saWN5ID0gcG9saWN5O1xuICAgIHRoaXMucmVkYWN0aW9uUnVsZSA9IG5ldyBSZWRhY3Rpb25SdWxlKHBvbGljeSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSByZWFkLXRyYWNraW5nIHBvbGljeSBmb3IgYFN0YWdlU25hcHNob3Quc3RhZ2VSZWFkc2AgKCMxNCkuXG4gICAqIE11c3QgYmUgY2FsbGVkIGJlZm9yZSBydW4oKS4gRXF1aXZhbGVudCB0byB0aGUgYHJlYWRUcmFja2luZ2BcbiAgICogY29uc3RydWN0b3Igb3B0aW9uIOKAlCBzZWUge0BsaW5rIEZsb3dDaGFydEV4ZWN1dG9yT3B0aW9ucy5yZWFkVHJhY2tpbmd9XG4gICAqIGZvciB0aGUgbW9kZSBzZW1hbnRpY3MgKCdmdWxsJyBkZWZhdWx0IC8gJ3N1bW1hcnknIC8gJ29mZicpLlxuICAgKi9cbiAgc2V0UmVhZFRyYWNraW5nKG1vZGU6IFJlYWRUcmFja2luZ01vZGUpOiB2b2lkIHtcbiAgICB0aGlzLmZsb3dDaGFydEFyZ3MuZGlhbHMgPSB7IC4uLnRoaXMuZmxvd0NoYXJ0QXJncy5kaWFscywgcmVhZFRyYWNraW5nOiBtb2RlIH07XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSB3cml0ZS10cmFja2luZyBwb2xpY3kgZm9yIGBTdGFnZVNuYXBzaG90LnN0YWdlV3JpdGVzYCAoIzEzYy1BKS5cbiAgICogTXVzdCBiZSBjYWxsZWQgYmVmb3JlIHJ1bigpLiBFcXVpdmFsZW50IHRvIHRoZSBgd3JpdGVUcmFja2luZ2BcbiAgICogY29uc3RydWN0b3Igb3B0aW9uIOKAlCBzZWUge0BsaW5rIEZsb3dDaGFydEV4ZWN1dG9yT3B0aW9ucy53cml0ZVRyYWNraW5nfVxuICAgKiBmb3IgdGhlIG1vZGUgc2VtYW50aWNzICgnZnVsbCcgZGVmYXVsdCAvICdzdW1tYXJ5JyAvICdvZmYnKSwgdGhlXG4gICAqIG9uQ29tbWl0LXBheWxvYWQgY29uc2VxdWVuY2UsIGFuZCB0aGUgcmVkYWN0aW9uLXByZWNlZGVuY2UgcnVsZS5cbiAgICovXG4gIHNldFdyaXRlVHJhY2tpbmcobW9kZTogV3JpdGVUcmFja2luZ01vZGUpOiB2b2lkIHtcbiAgICB0aGlzLmZsb3dDaGFydEFyZ3MuZGlhbHMgPSB7IC4uLnRoaXMuZmxvd0NoYXJ0QXJncy5kaWFscywgd3JpdGVUcmFja2luZzogbW9kZSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgY29tbWl0LXZhbHVlcyBlbmNvZGluZyBwb2xpY3kgZm9yIHRoZSBjb21taXQgbG9nICgjMTNjLUIpLlxuICAgKiBNdXN0IGJlIGNhbGxlZCBiZWZvcmUgcnVuKCkuIEVxdWl2YWxlbnQgdG8gdGhlIGBjb21taXRWYWx1ZXNgXG4gICAqIGNvbnN0cnVjdG9yIG9wdGlvbiDigJQgc2VlIHtAbGluayBGbG93Q2hhcnRFeGVjdXRvck9wdGlvbnMuY29tbWl0VmFsdWVzfVxuICAgKiBmb3IgdGhlIG1vZGUgc2VtYW50aWNzICgnZnVsbCcgZGVmYXVsdCAvICdkZWx0YScpLCB0aGUgdmVyYi1xdWFsaWZpZWRcbiAgICogYG92ZXJ3cml0ZWAgY29uc2VxdWVuY2UsIGFuZCB0aGUgYGNvbW1pdFZhbHVlQXRgIG1pZ3JhdGlvbiBoZWxwZXIuXG4gICAqL1xuICBzZXRDb21taXRWYWx1ZXMobW9kZTogQ29tbWl0VmFsdWVzTW9kZSk6IHZvaWQge1xuICAgIHRoaXMuZmxvd0NoYXJ0QXJncy5kaWFscyA9IHsgLi4udGhpcy5mbG93Q2hhcnRBcmdzLmRpYWxzLCBjb21taXRWYWx1ZXM6IG1vZGUgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgY29tcGxpYW5jZS1mcmllbmRseSByZXBvcnQgb2YgYWxsIHJlZGFjdGlvbiBhY3Rpdml0eSBmcm9tIHRoZVxuICAgKiBtb3N0IHJlY2VudCBydW4uIE5ldmVyIGluY2x1ZGVzIGFjdHVhbCB2YWx1ZXMuXG4gICAqL1xuICBnZXRSZWRhY3Rpb25SZXBvcnQoKTogUmVkYWN0aW9uUmVwb3J0IHtcbiAgICByZXR1cm4gdGhpcy5yZWRhY3Rpb25SdWxlLnJlcG9ydCgpO1xuICB9XG5cbiAgLy8g4pSA4pSA4pSAIFBhdXNlL1Jlc3VtZSDilIDilIDilIBcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgY2hlY2twb2ludCBmcm9tIHRoZSBtb3N0IHJlY2VudCBwYXVzZWQgZXhlY3V0aW9uLCBvciBgdW5kZWZpbmVkYFxuICAgKiBpZiB0aGUgbGFzdCBydW4gY29tcGxldGVkIHdpdGhvdXQgcGF1c2luZy5cbiAgICpcbiAgICogVGhlIGNoZWNrcG9pbnQgaXMgSlNPTi1zZXJpYWxpemFibGUg4oCUIHN0b3JlIGl0IGluIFJlZGlzLCBQb3N0Z3JlcywgbG9jYWxTdG9yYWdlLCBldGMuXG4gICAqXG4gICAqIEl0IGlzIGZ1bGx5IERFVEFDSEVEIGZyb20gZW5naW5lIHN0YXRlOiBldmVyeSBmaWVsZCB3YXMgZGVlcC1jb3BpZWQgYXRcbiAgICogcGF1c2UgdGltZSAoc2VlIGBidWlsZFBhdXNlQ2hlY2twb2ludGApLiBIb2xkaW5nLCBtdXRhdGluZywgb3IgcGVyc2lzdGluZ1xuICAgKiBpdCBjYW5ub3QgYWZmZWN0IHRoZSBleGVjdXRvciwgYW5kIGEgbGF0ZXIgc2FtZS1leGVjdXRvciByZXN1bWUgY2Fubm90XG4gICAqIG11dGF0ZSBhIGNoZWNrcG9pbnQgeW91IGFscmVhZHkgc3RvcmVkLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWN1dG9yLnJ1bih7IGlucHV0IH0pO1xuICAgKiBpZiAoZXhlY3V0b3IuaXNQYXVzZWQoKSkge1xuICAgKiAgIGNvbnN0IGNoZWNrcG9pbnQgPSBleGVjdXRvci5nZXRDaGVja3BvaW50KCkhO1xuICAgKiAgIGF3YWl0IHJlZGlzLnNldChgc2Vzc2lvbjoke2lkfWAsIEpTT04uc3RyaW5naWZ5KGNoZWNrcG9pbnQpKTtcbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGdldENoZWNrcG9pbnQoKTogRmxvd2NoYXJ0Q2hlY2twb2ludCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubGFzdENoZWNrcG9pbnQ7XG4gIH1cblxuICAvKiogUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIG1vc3QgcmVjZW50IHJ1bigpIHdhcyBwYXVzZWQgKGNoZWNrcG9pbnQgYXZhaWxhYmxlKS4gKi9cbiAgaXNQYXVzZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubGFzdENoZWNrcG9pbnQgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBOdW1iZXIgb2YgY29tbWl0cyBpbiB0aGUgcnVuJ3MgY29tbWl0IGxvZy4gTygxKSDigJQgZGlyZWN0IGxlbmd0aFxuICAgKiByZWFkLCBubyBzbmFwc2hvdCBtYXRlcmlhbGl6YXRpb24uIFVzZSB0aGlzIHRvIHN0YW1wIGNvbW1pdFxuICAgKiBpbmRpY2VzIG9uIG9ic2VydmVyIGV2ZW50cyAoZS5nLiwgYEJvdW5kYXJ5UmVjb3JkZXJgIHN0b3JpbmdcbiAgICogYGNvbW1pdElkeEJlZm9yZWAgLyBgY29tbWl0SWR4QWZ0ZXJgIHBlciBkb21haW4gZXZlbnQgZm9yXG4gICAqIGBDb21taXRSYW5nZUluZGV4YCBxdWVyaWVzIOKAlCBzZWUgYGZvb3RwcmludGpzL3RyYWNlYCkuXG4gICAqXG4gICAqIFJldHVybnMgMCBiZWZvcmUgYW55IHJ1bjsgYWZ0ZXIsIHJldHVybnMgdGhlIGN1bXVsYXRpdmUgY29tbWl0XG4gICAqIGNvdW50IGFjcm9zcyB0aGUgZXhlY3V0b3IncyBsaWZldGltZSAoaW5jbHVkaW5nIHJlc3VtZXMpLlxuICAgKlxuICAgKiBJTVBMRU1FTlRBVElPTiBOT1RFOiB0aGlzIHJldHVybnMgYHJ1bnRpbWUuZXhlY3V0aW9uSGlzdG9yeS5sZW5ndGhgLFxuICAgKiB3aGljaCBpcyB0aGUgc2FtZSB2YWx1ZSBhcyBgZ2V0U25hcHNob3QoKS5jb21taXRMb2cubGVuZ3RoYC4gVGhlXG4gICAqIG5hbWluZyBhc3ltbWV0cnkgaXMgaGlzdG9yaWNhbCDigJQgdGhlIHVuZGVybHlpbmcgYEV2ZW50TG9nYCBmaWVsZFxuICAgKiBpcyBuYW1lZCBgZXhlY3V0aW9uSGlzdG9yeWAgYnV0IHN0b3JlcyB0aGUgYENvbW1pdEJ1bmRsZVtdYCB0aGF0XG4gICAqIGBjb21taXRMb2dgIGV4cG9zZXMuIFRoZXkgYWx3YXlzIHJlcG9ydCB0aGUgc2FtZSBMRU5HVEggKHZlcmlmaWVkIGJ5IHRoZVxuICAgKiBcIm1hdGNoZXMgY29tbWl0TG9nLmxlbmd0aFwiIGludGVncmF0aW9uIHRlc3QpOyBzaW5jZSA5LjE3LjAgdGhlIHNuYXBzaG90XG4gICAqIHNlcnZlcyBhIGRldGFjaGVkIGZyb3plbiBDT1BZIG9mIHRoZSBhcnJheSwgbm90IHRoZSBsaXZlIG9uZS5cbiAgICovXG4gIGdldENvbW1pdENvdW50KCk6IG51bWJlciB7XG4gICAgY29uc3QgcnVudGltZSA9IHRoaXMudHJhdmVyc2VyLmdldFJ1bnRpbWUoKSBhcyBJbnN0YW5jZVR5cGU8dHlwZW9mIEV4ZWN1dGlvblJ1bnRpbWU+IHwgdW5kZWZpbmVkO1xuICAgIHJldHVybiBydW50aW1lPy5leGVjdXRpb25IaXN0b3J5Lmxlbmd0aCA/PyAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc3VtZSBhIHBhdXNlZCBmbG93Y2hhcnQgZnJvbSBhIGNoZWNrcG9pbnQuXG4gICAqXG4gICAqIFJlc3RvcmVzIHRoZSBzY29wZSBzdGF0ZSwgY2FsbHMgdGhlIHBhdXNlZCBzdGFnZSdzIGByZXN1bWVGbmAgd2l0aCB0aGVcbiAgICogcHJvdmlkZWQgaW5wdXQgKG9yLCBmb3IgYW4gYGludGVycnVwdCgpYCBwYXVzZSwgcmUtcnVucyB0aGUgc3RhZ2Ugd2l0aCB0aGVcbiAgICogYW5zd2VyKSwgdGhlbiBjb250aW51ZXMgd2l0aCB3aGF0ZXZlciByYW4gYWZ0ZXIgdGhhdCBzdGFnZSBvbiB0aGUgcnVuIOKAlFxuICAgKiBpdHMgb3duIGBuZXh0YCwgb3IgdGhlIGNvbnRpbnVhdGlvbiBvZiB0aGUgZGVjaWRlciwgc2VsZWN0b3Igb3IgZm9yayB0aGF0XG4gICAqIGRpc3BhdGNoZWQgaXQsIGF0IGV2ZXJ5IGxldmVsIG9mIHRoZSBwYXVzZSBwYXRoIOKAlCBhbmQgZnJvbSB0aGVyZSB3YWxrcyB0aGVcbiAgICogY2hhcnQgYXMgYnVpbHQuIFdoZW4gcGFyYWxsZWwgc2libGluZ3MgcGF1c2VkIGluIHRoZSBzYW1lIGZhbi1vdXRcbiAgICogKGBjaGVja3BvaW50LnBlbmRpbmdQYXVzZXNgKSwgdGhlIHJ1biBwYXVzZXMgYWdhaW4gd2l0aCB0aGUgbmV4dCBzaWJsaW5nJ3NcbiAgICogcXVlc3Rpb24gb25jZSB0aGlzIG9uZSdzIGJyYW5jaCBpcyBkb25lOyB0aGUgZmFuLW91dCdzIGpvaW4gcnVucyBhZnRlciB0aGVcbiAgICogbGFzdCBhbnN3ZXIuIFNlZSBgUmVzdW1lRW50cnlgIChgZm9vdHByaW50anMvYWR2YW5jZWRgKS5cbiAgICpcbiAgICogVGhlIGNoZWNrcG9pbnQgY2FuIGNvbWUgZnJvbSBgZ2V0Q2hlY2twb2ludCgpYCBvbiBhIHByZXZpb3VzIHJ1biwgb3IgZnJvbVxuICAgKiBhIHNlcmlhbGl6ZWQgY2hlY2twb2ludCBzdG9yZWQgaW4gUmVkaXMvUG9zdGdyZXMvbG9jYWxTdG9yYWdlLlxuICAgKlxuICAgKiAqKlJlY29yZGVyL25hcnJhdGl2ZSBzdGF0ZSBkZXBlbmRzIG9uIHRoZSByZXN1bWUgbW9kZS4qKiBSZXN1bWluZyBvbiB0aGUgU0FNRVxuICAgKiBleGVjdXRvciB0aGF0IHJhbiBwcmVzZXJ2ZXMgYW5kIGFjY3VtdWxhdGVzIG5hcnJhdGl2ZS9tZXRyaWNzL2RlYnVnIGFjcm9zcyB0aGVcbiAgICogcGF1c2UvcmVzdW1lIGN5Y2xlIChwcmVzZXJ2ZVJlY29yZGVycykuIFJlc3VtaW5nIG9uIGEgRlJFU0ggZXhlY3V0b3JcbiAgICogKHJlY29uc3RydWN0ZWQgZnJvbSBhIHN0b3JlZCBjaGVja3BvaW50KSBzdGFydHMgd2l0aCBlbXB0eSByZWNvcmRlciBzdGF0ZSDigJRcbiAgICogY29sbGVjdCB3aGF0IHlvdSBuZWVkIGJlZm9yZSBkaXNjYXJkaW5nIHRoZSBwYXVzZWQgZXhlY3V0b3IuIEEgZnJlc2ggYHJ1bklkYFxuICAgKiBpcyBnZW5lcmF0ZWQgZWl0aGVyIHdheS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBQcm9jZXNzIEEg4oCUIGFmdGVyIGEgcGF1c2UsIHBlcnNpc3QgdGhlIGNoZWNrcG9pbnQ6XG4gICAqIGNvbnN0IGNoZWNrcG9pbnQgPSBleGVjdXRvci5nZXRDaGVja3BvaW50KCkhO1xuICAgKiBhd2FpdCByZWRpcy5zZXQoYHNlc3Npb246JHtpZH1gLCBKU09OLnN0cmluZ2lmeShjaGVja3BvaW50KSk7XG4gICAqXG4gICAqIC8vIFByb2Nlc3MgQiAocG9zc2libHkgZGlmZmVyZW50IHNlcnZlciwgc2FtZSBjaGFydCkg4oCUIHJlc3RvcmUgYW5kIHJlc3VtZTpcbiAgICogY29uc3QgcmVzdG9yZWQgPSBKU09OLnBhcnNlKGF3YWl0IHJlZGlzLmdldChgc2Vzc2lvbjoke2lkfWApKTtcbiAgICogY29uc3QgZXhlY3V0b3IgPSBuZXcgRmxvd0NoYXJ0RXhlY3V0b3IoY2hhcnQpO1xuICAgKiBjb25zdCByZXN1bHQgPSBhd2FpdCBleGVjdXRvci5yZXN1bWUocmVzdG9yZWQsIHsgYXBwcm92ZWQ6IHRydWUgfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgcmVzdW1lKFxuICAgIGNoZWNrcG9pbnQ6IEZsb3djaGFydENoZWNrcG9pbnQsXG4gICAgcmVzdW1lSW5wdXQ/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBQaWNrPFJ1bk9wdGlvbnMsICdzaWduYWwnIHwgJ2VudicgfCAnbWF4RGVwdGgnIHwgJ21heEl0ZXJhdGlvbnMnPixcbiAgKTogUHJvbWlzZTxFeGVjdXRvclJlc3VsdD4ge1xuICAgIC8vIFJlLWVudHJhbmN5IGd1YXJkIEZJUlNUIOKAlCByZXN1bWUoKSBtdXRhdGVzIHRoZSBzYW1lIHBlci1ydW4gc3RhdGUgcnVuKClcbiAgICAvLyBkb2VzICh0cmF2ZXJzZXIsIHJ1bklkLCBjaGVja3BvaW50KSwgc28gcmVzdW1lLWR1cmluZy1ydW4gYW5kXG4gICAgLy8gZG91YmxlLXJlc3VtZSBhcmUgdGhlIHNhbWUgY29ycnVwdGlvbiBjbGFzcyBhcyBjb25jdXJyZW50IHJ1bigpLlxuICAgIGlmICh0aGlzLl9pc0V4ZWN1dGluZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnRmxvd0NoYXJ0RXhlY3V0b3I6IHJlc3VtZSgpIGNhbGxlZCB3aGlsZSBhbm90aGVyIHJ1bigpL3Jlc3VtZSgpIGlzIGluIGZsaWdodCBvbiB0aGlzICcgK1xuICAgICAgICAgICdleGVjdXRvci4gQW4gZXhlY3V0b3IgaG9sZHMgcGVyLXJ1biBzdGF0ZSAocnVuSWQsIHJlY29yZGVycywgY2hlY2twb2ludCkg4oCUIGNyZWF0ZSAnICtcbiAgICAgICAgICAnb25lIGV4ZWN1dG9yIHBlciBjb25jdXJyZW50IHJ1bi4gU2VlIGRvY3MvZ3VpZGVzL2V4ZWN1dGlvbi1tb2RlbC5tZC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgLy8g4pSA4pSAIERlY29kZSB0aGUgY2hlY2twb2ludCAobWF5IGNvbWUgZnJvbSB1bnRydXN0ZWQgZXh0ZXJuYWwgc3RvcmFnZSwgZnJvbVxuICAgIC8vIGFueSByZWxlYXNlKSDigJQgdGhlIE9ORSBjb2RlYzogdXBjYXN0LCB0aGVuIGNoZWNrIGV2ZXJ5IHBhdXNlIHJlY29yZFxuICAgIC8vIChgcGF1c2UvcmVjb3JkLnRzYCkuIChsYXN0Q2hlY2twb2ludCBpcyB3aXBlZCBBRlRFUiB0aGlzIOKAlCBhIHJlamVjdGVkXG4gICAgLy8gY2hlY2twb2ludCBtdXN0IG5vdCBkZXN0cm95IHRoZSBleGVjdXRvcidzIGV4aXN0aW5nIGNoZWNrcG9pbnQgc3RhdGUuKVxuICAgIGNoZWNrcG9pbnQgPSBkZWNvZGVDaGVja3BvaW50KGNoZWNrcG9pbnQpO1xuXG4gICAgLy8gRmluZCB0aGUgcGF1c2VkIG5vZGUgaW4gdGhlIGdyYXBoXG4gICAgY29uc3QgcGF1c2VkTm9kZSA9IHRoaXMuZmluZE5vZGVJbkdyYXBoKGNoZWNrcG9pbnQucGF1c2VkU3RhZ2VJZCwgY2hlY2twb2ludC5zdWJmbG93UGF0aCk7XG4gICAgaWYgKCFwYXVzZWROb2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBDYW5ub3QgcmVzdW1lOiBzdGFnZSAnJHtjaGVja3BvaW50LnBhdXNlZFN0YWdlSWR9JyBub3QgZm91bmQgaW4gZmxvd2NoYXJ0LiBgICtcbiAgICAgICAgICAnVGhlIGNoYXJ0IG1heSBoYXZlIGNoYW5nZWQgc2luY2UgdGhlIGNoZWNrcG9pbnQgd2FzIGNyZWF0ZWQuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIFR3byByZS1lbnRyeSBzaGFwZXMsIGNob3NlbiBieSBIT1cgdGhlIHBhdXNlIHdhcyByYWlzZWQ6XG4gICAgLy9cbiAgICAvLyAgIOKAoiBpbnRlcnJ1cHQoKSAgICAgIOKGkiBSRS1SVU4gVEhFIFNUQUdFJ1MgT1dOIEZVTkNUSU9OIEZST00gSVRTIFRPUC5cbiAgICAvLyAgICAgU3RhZ2VzIGFyZSBhdG9taWMgKHRoZSBzYW1lIGxhdyBgcmVzdW1lT25FcnJvcmAgc3RhdGVzKTogYSBzdGFnZSB0aGF0XG4gICAgLy8gICAgIHN0b3BwZWQgbWlkLWJvZHkgaGFzIG5vIGhhbGYgdG8gcmVzdW1lIGludG8sIHNvIHRoZSB3aG9sZSBib2R5IHJ1bnNcbiAgICAvLyAgICAgYWdhaW4gYW5kIHRoZSBhbnN3ZXIgY29tZXMgYmFjayBvdXQgb2YgdGhlIGBpbnRlcnJ1cHQoKWAgY2FsbCBpdHNlbGYuXG4gICAgLy8gICAgIEV2ZXJ5dGhpbmcgdGhlIGJvZHkgZGlkIGJlZm9yZSB0aGUgaW50ZXJydXB0IGlzIHJlLWRvbmUg4oCUIHdoaWNoIGlzXG4gICAgLy8gICAgIHdoeSB0aGUgZG9jcyB0ZWxsIHlvdSB0byBrZWVwIHRoYXQgaGFsZiBpZGVtcG90ZW50LlxuICAgIC8vICAg4oCiIGFkZFBhdXNhYmxlRnVuY3Rpb24g4oaSIHJ1biB0aGUgZGVjbGFyZWQgYHJlc3VtZUZuYC5cbiAgICAvL1xuICAgIC8vIFRoZSBkaXNjcmltaW5hbnQgaXMgb24gdGhlIGNoZWNrcG9pbnQsIHNvIHRoaXMgd29ya3MgY3Jvc3MtZXhlY3V0b3JcbiAgICAvLyAoYSBjaGVja3BvaW50IHJlc3RvcmVkIGZyb20gUmVkaXMgb24gYSBmcmVzaCBwcm9jZXNzIHJlc3VtZXMgdGhlIHNhbWUgd2F5KS5cbiAgICBjb25zdCBpc0ludGVycnVwdFJlc3VtZSA9IGNoZWNrcG9pbnQucGF1c2VkQnkgPT09ICdpbnRlcnJ1cHQnO1xuICAgIGlmICghcGF1c2VkTm9kZS5yZXN1bWVGbiAmJiAhaXNJbnRlcnJ1cHRSZXN1bWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENhbm5vdCByZXN1bWU6IHN0YWdlICcke3BhdXNlZE5vZGUubmFtZX0nICgke3BhdXNlZE5vZGUuaWR9KSBoYXMgbm8gcmVzdW1lRm4uIGAgK1xuICAgICAgICAgICdPbmx5IHN0YWdlcyBjcmVhdGVkIHdpdGggYWRkUGF1c2FibGVGdW5jdGlvbigpLCBvciBzdGFnZXMgdGhhdCBwYXVzZWQgdmlhIGludGVycnVwdCgpLCBjYW4gYmUgcmVzdW1lZC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgLy8gVGhlIHJlc3VtZSBoYWxmIOKAlCB3aGF0IHRoZSBwYXVzZWQgc3RhZ2UncyBzdGFuZC1pbiBydW5zLlxuICAgIC8vIHJlc3VtZUZuIHNpZ25hdHVyZSBpcyAoc2NvcGUsIGlucHV0KSBwZXIgUGF1c2FibGVIYW5kbGVyIOKAlCB3cmFwIHRvIG1hdGNoIFN0YWdlRnVuY3Rpb24oc2NvcGUsIGJyZWFrRm4pLlxuICAgIGxldCByZXN1bWVTdGFnZUZuOiBTdGFnZUZ1bmN0aW9uPFRPdXQsIFRTY29wZT47XG4gICAgaWYgKGlzSW50ZXJydXB0UmVzdW1lKSB7XG4gICAgICBjb25zdCBvcmlnaW5hbEZuID1cbiAgICAgICAgcGF1c2VkTm9kZS5mbiA/P1xuICAgICAgICB0aGlzLmZsb3dDaGFydEFyZ3MuZmxvd0NoYXJ0LnN0YWdlTWFwLmdldChwYXVzZWROb2RlLmlkKSA/P1xuICAgICAgICB0aGlzLmZsb3dDaGFydEFyZ3MuZmxvd0NoYXJ0LnN0YWdlTWFwLmdldChwYXVzZWROb2RlLm5hbWUpO1xuICAgICAgaWYgKCFvcmlnaW5hbEZuKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgQ2Fubm90IHJlc3VtZTogc3RhZ2UgJyR7cGF1c2VkTm9kZS5uYW1lfScgKCR7cGF1c2VkTm9kZS5pZH0pIHBhdXNlZCB2aWEgaW50ZXJydXB0KCkgYnV0IGl0cyBgICtcbiAgICAgICAgICAgICdzdGFnZSBmdW5jdGlvbiBpcyBubyBsb25nZXIgaW4gdGhlIGNoYXJ0LiBUaGUgY2hhcnQgbWF5IGhhdmUgY2hhbmdlZCBzaW5jZSB0aGUgY2hlY2twb2ludCAnICtcbiAgICAgICAgICAgICd3YXMgY3JlYXRlZC4nLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmVzdW1lU3RhZ2VGbiA9IChzY29wZSwgYnJlYWtGbiwgc3RyZWFtQ2FsbGJhY2spID0+IHtcbiAgICAgICAgLy8gRGVwb3NpdCB0aGUgYW5zd2VyIGZvciBUSElTIHNjb3BlIGluc3RhbmNlIGJlZm9yZSB0aGUgYm9keSBydW5zLCBzb1xuICAgICAgICAvLyB0aGUgYGludGVycnVwdCgpYCBjYWxsIHRoYXQgdGhyZXcgbGFzdCB0aW1lIHJldHVybnMgaXQgdGhpcyB0aW1lLlxuICAgICAgICAvLyBLZXllZCBieSBzY29wZSBpZGVudGl0eSDigJQgc2FmZSB3aGVuIHNldmVyYWwgYnJhbmNoZXMgcmVzdW1lIGF0IG9uY2UuXG4gICAgICAgIHByb3ZpZGVJbnRlcnJ1cHRBbnN3ZXIoc2NvcGUsIHJlc3VtZUlucHV0KTtcbiAgICAgICAgcmV0dXJuIG9yaWdpbmFsRm4oc2NvcGUsIGJyZWFrRm4sIHN0cmVhbUNhbGxiYWNrKTtcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHJlc3VtZUZuID0gcGF1c2VkTm9kZS5yZXN1bWVGbiE7XG4gICAgICByZXN1bWVTdGFnZUZuID0gKHNjb3BlOiBUU2NvcGUpID0+IHtcbiAgICAgICAgcmV0dXJuIHJlc3VtZUZuKHNjb3BlLCByZXN1bWVJbnB1dCkgYXMgVE91dCB8IFByb21pc2U8VE91dD47XG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIFRoZSBwYXVzZWQgc3RhZ2UncyBTVEFORC1JTjogdGhlIHN0YWdlJ3MgT1dOIG5vZGUg4oCUIGlkLCBuYW1lLFxuICAgIC8vIGRlc2NyaXB0aW9uLCB0YWdzLCBhbmQgaXRzIHNoYXBlIChhIGRlY2lkZXIncyBicmFuY2hlcywgYSBzZWxlY3RvcidzLCBhXG4gICAgLy8gZm9yayBwYXJlbnQncyBjaGlsZHJlbiwgaXRzIGBuZXh0YCkg4oCUIHdpdGggaXRzIGZ1bmN0aW9uIHN3YXBwZWQgZm9yIHRoZVxuICAgIC8vIHJlc3VtZSBoYWxmLiBCdWlsdCBmcm9tIHRoZSB3aG9sZSBub2RlIHNvIGFuIGBpbnRlcnJ1cHQoKWAgcmFpc2VkIGluc2lkZVxuICAgIC8vIGEgZGVjaWRlciwgc2VsZWN0b3Igb3IgZm9yay1wYXJlbnQgZnVuY3Rpb24gRElTUEFUQ0hFUyBvbiByZXN1bWUsIGFzIHRoZVxuICAgIC8vIHN0YWdlIGRpZCBvbiB0aGUgcnVuIChiZWZvcmUgOS4yOC4wIG9ubHkgZm4vbmV4dC90YWdzL3JldHJ5IHdlcmUgY29waWVkXG4gICAgLy8gYW5kIHRoZSBkaXNwYXRjaCB3YXMgc2lsZW50bHkgc2tpcHBlZCkuIEl0IGlzIHdoZXJlIHRoZSByZXN1bWVkXG4gICAgLy8gdHJhdmVyc2FsIHN0YXJ0cyDigJQgYW5kIG5vdGhpbmcgZWxzZTogaXQgaXMgbmV2ZXIgaW4gYSBub2RlIG1hcCBvciB0aGVcbiAgICAvLyBzdWJmbG93IGRpY3Rpb25hcnksIHNvIGEgbG9vcCBiYWNrIHRvIHRoZSBwYXVzZWQgaWQgZmluZHMgdGhlIFJFQUxcbiAgICAvLyBzdGFnZSwgd2hpY2ggcGF1c2VzIGFnYWluIChzZWUgUmVzdW1lRW50cnkpLiBXaGF0IHJ1bnMgYWZ0ZXIgaXQg4oCUIGl0c1xuICAgIC8vIG93biBgbmV4dGAsIGVsc2UgaXRzIGRpc3BhdGNoZXIncyBjb250aW51YXRpb24g4oCUIGlzIGF0dGFjaGVkIGJ5XG4gICAgLy8gYFJlc3VtZUVudHJ5LnBsYW5gLCBmcm9tIHRoZSBjaGFydC5cbiAgICBjb25zdCBzdGFuZEluID0gc3RhbmRJbkZvcihwYXVzZWROb2RlLCByZXN1bWVTdGFnZUZuLCBpc0ludGVycnVwdFJlc3VtZSk7XG5cbiAgICAvLyBXaGVyZSB0aGUgcmVzdW1lIHJlLWVudGVycywgcGxhbm5lZCBhZ2FpbnN0IHRoZSBjaGFydCBhcyBidWlsdDpcbiAgICAvL1xuICAgIC8vICAg4oCiIFRPUC1MRVZFTCBQQVVTRSAoc3ViZmxvd1BhdGggZW1wdHkpOiB0aGUgcmVzdW1lZCB0cmF2ZXJzYWwgc3RhcnRzXG4gICAgLy8gICAgIGF0IHRoZSBzdGFuZC1pbi5cbiAgICAvLyAgIOKAoiBQQVVTRSBJTlNJREUgU1VCRkxPV1M6IGl0IHN0YXJ0cyBhdCB0aGUgbW91bnQgb2YgdGhlIGZpcnN0IHN1YmZsb3dcbiAgICAvLyAgICAgb24gdGhlIHBhdGgsIHNvIHRoZSBvdXRwdXRNYXBwZXJzIGFuZCB0aGUgcGFyZW50J3MgY29udGludWF0aW9uXG4gICAgLy8gICAgIHJ1bi4gRWFjaCBzdWJmbG93IG9uIHRoZSBwYXRoIGlzIGVudGVyZWQgT05DRSB0aHJvdWdoIGl0cyBob3A6IGl0c1xuICAgIC8vICAgICBuZXN0ZWQgcnVudGltZSBpcyBzZWVkZWQgZnJvbSBpdHMgY2FwdHVyZSAoaW4gcGxhY2Ugb2YgdGhlXG4gICAgLy8gICAgIGlucHV0TWFwcGVyJ3MgdmFsdWVzKSBhbmQgaXRzIHRyYXZlcnNhbCBzdGFydHMgYXQgdGhlIG1vdW50IG9mIHRoZVxuICAgIC8vICAgICBuZXh0IHN1YmZsb3cg4oCUIG9yLCBhdCB0aGUgbGVhZiwgYXQgdGhlIHN0YW5kLWluLiBBbiBvdXRlciBzdWJmbG93J3NcbiAgICAvLyAgICAgc3RhZ2VzIGJlZm9yZSB0aGF0IG1vdW50IGRvIG5vdCBydW4gYWdhaW4uXG4gICAgLy8gICDigKIgQVQgRVZFUlkgTEVWRUwgdGhlIGVudHJ5IGNhcnJpZXMgd2hhdCBpdHMgZGlzcGF0Y2hlciB3b3VsZCBoYXZlIHJ1blxuICAgIC8vICAgICBhZnRlciBpdCDigJQgYSBkZWNpZGVyJ3MgYG5leHRgLCBhIHNlbGVjdG9yJ3MsIGEgZm9yaydzIGpvaW4g4oCUIHNvIGFcbiAgICAvLyAgICAgc3ViZmxvdyBtb3VudGVkIGFzIGEgYnJhbmNoIG9yIGEgZm9yayBjaGlsZCBoYW5kcyBjb250cm9sIGJhY2sgdG9cbiAgICAvLyAgICAgaXRzIHBhcmVudCdzIGNvbnRpbnVhdGlvbiBhdCB0aGUgcGFyZW50J3MgbGV2ZWwuXG4gICAgLy8gICDigKIgUGFyYWxsZWwgc2libGluZ3MgdGhhdCBwYXVzZWQgaW4gdGhlIHNhbWUgZmFuLW91dCB3YWl0IGluXG4gICAgLy8gICAgIGBjaGVja3BvaW50LnBlbmRpbmdQYXVzZXNgOiBlYWNoIGlzIHJhaXNlZCBhZ2FpbiBpbiB0dXJuLCBhbmQgdGhlXG4gICAgLy8gICAgIGpvaW4gcnVucyBvbmx5IG9uY2UgdGhlIGxhc3Qgb25lIGlzIHJlc3VtZWQuXG4gICAgLy9cbiAgICAvLyBFdmVyeXRoaW5nIGVsc2Ugd2Fsa3MgdGhlIFJFQUwgY2hhcnQ6IGBmYy5yb290YCBhbmQgYGZjLnN1YmZsb3dzYCBhcmVcbiAgICAvLyB1bnRvdWNoZWQsIHNvIGV2ZXJ5IGxhdGVyIGxvb3AgdGFyZ2V0IGFuZCBldmVyeSBsYXRlciBzdWJmbG93IGVudHJ5XG4gICAgLy8gKHJlYWwgcm9vdCwgaW5wdXRNYXBwZXIpIHJlc29sdmVzIGFzIGl0IHdvdWxkIG9uIGEgcnVuLiBSZWZ1c2VkIEhFUkUg4oCUXG4gICAgLy8gYmVmb3JlIGFueSBzdGF0ZSBpcyB0b3VjaGVkIOKAlCB3aGVuIHRoZSBjaGVja3BvaW50J3MgcGF0aCBkb2VzIG5vdCBmaXRcbiAgICAvLyB0aGlzIGNoYXJ0LlxuICAgIC8vXG4gICAgLy8gQ2xvbmUtaW46IHRoZSBjYXB0dXJlcyBzZWVkIG5lc3RlZCBydW50aW1lcyAoc2hhbGxvdy1tZXJnZWQgaW50byBlYWNoXG4gICAgLy8gbmVzdGVkIFNoYXJlZE1lbW9yeSksIHNvIHdpdGhvdXQgYSBjb3B5IHRoZSBlbmdpbmUgd291bGQgaG9sZCBsaXZlXG4gICAgLy8gcmVmZXJlbmNlcyBpbnRvIHRoZSBjYWxsZXIncyBjaGVja3BvaW50IG9iamVjdCDigJQgY2FsbGVyIG11dGF0aW9ucyB3b3VsZFxuICAgIC8vIGJsZWVkIGludG8gdGhlIHJlc3VtZWQgcnVuIGFuZCBlbmdpbmUgd3JpdGVzIHdvdWxkIHJlYWNoIGEgY2hlY2twb2ludFxuICAgIC8vIHRoZSBjYWxsZXIgbWF5IGhhdmUgYWxyZWFkeSBwZXJzaXN0ZWQuIFRoZSBzYW1lIGZvciB0aGUgd2FpdGluZ1xuICAgIC8vIHNpYmxpbmdzJyBjYXB0dXJlcy5cbiAgICBjb25zdCBmYyA9IHRoaXMuZmxvd0NoYXJ0QXJncy5mbG93Q2hhcnQ7XG4gICAgY29uc3QgcmVzdW1lRW50cnkgPSBSZXN1bWVFbnRyeS5wbGFuPFRPdXQsIFRTY29wZT4oe1xuICAgICAgcm9vdDogZmMucm9vdCxcbiAgICAgIHN1YmZsb3dzOiBmYy5zdWJmbG93cyxcbiAgICAgIHBhdGg6IGNoZWNrcG9pbnQuc3ViZmxvd1BhdGgsXG4gICAgICBjYXB0dXJlczogc3RydWN0dXJlZENsb25lKGNoZWNrcG9pbnQuc3ViZmxvd1N0YXRlcyksXG4gICAgICBzdGFuZEluLFxuICAgICAgLi4uKGNoZWNrcG9pbnQucGVuZGluZ1BhdXNlcyAhPT0gdW5kZWZpbmVkICYmIHsgcGVuZGluZ1BhdXNlczogc3RydWN0dXJlZENsb25lKGNoZWNrcG9pbnQucGVuZGluZ1BhdXNlcykgfSksXG4gICAgfSk7XG5cbiAgICAvLyDilIDilIAgU2VlZCB0aGUgc2hhcmVkIGV4ZWN1dGlvbiBjb3VudGVyICsgcGVyLXN0YWdlIHZpc2l0IGNvdW50cyDilIDilIBcbiAgICAvL1xuICAgIC8vIE9ubHkgbm93IOKAlCBldmVyeSByZWZ1c2FsIGFib3ZlICh0aGUgY2hlY2twb2ludCdzIHNoYXBlLCB0aGUgcGF1c2VkXG4gICAgLy8gc3RhZ2UsIHRoZSBwbGFuKSBsZWF2ZXMgdGhlIGV4ZWN1dG9yIGV4YWN0bHkgYXMgaXQgd2FzLiBNVVNUIHJ1biBiZWZvcmVcbiAgICAvLyB0aGUgY291bnRlciBpcyBSRUFEIGJlbG93ICh0aGUgc3RhbmQtaW4ncyBydW50aW1lU3RhZ2VJZCBmb3JcbiAgICAvLyBgb25SZXN1bWVgKSBBTkQgYmVmb3JlIGNyZWF0ZVRyYXZlcnNlcigpIGhhbmRzIHRoZSB0cmF2ZXJzZXIgdGhlc2VcbiAgICAvLyBvYmplY3RzIEJZIFJFRkVSRU5DRS4gU2VlZGluZyBrZWVwcyBydW50aW1lU3RhZ2VJZHMgdW5pcXVlIGFuZFxuICAgIC8vIGxvb3BJdGVyYXRpb24gbW9ub3RvbmljIGFjcm9zcyBhIENST1NTLWV4ZWN1dG9yIHJlc3VtZSAoYSBmcmVzaFxuICAgIC8vIGV4ZWN1dG9yIHN0YXJ0cyBib3RoIGF0IDAvZW1wdHk7IHRoZSBjaGVja3BvaW50IGNhcnJpZXMgdGhlIHBhdXNlLXRpbWVcbiAgICAvLyB2YWx1ZXMpLlxuICAgIC8vXG4gICAgLy8gTVVUQVRFLCBuZXZlciBSRVBMQUNFOiBgX2V4ZWN1dGlvbkNvdW50ZXJgIGFuZCBgX3Zpc2l0Q291bnRzYCBhcmUgc2hhcmVkXG4gICAgLy8gYnkgcmVmZXJlbmNlIGludG8gdGhlIHRyYXZlcnNlciAoYW5kLCB0cmFuc2l0aXZlbHksIGV2ZXJ5IHN1YmZsb3dcbiAgICAvLyB0cmF2ZXJzZXIg4oCUIHNlZSBGbG93Y2hhcnRUcmF2ZXJzZXIncyBzdWItdHJhdmVyc2VyIGZhY3RvcnkpLiBBc3NpZ25pbmcgYVxuICAgIC8vIGZyZXNoIG9iamVjdCBoZXJlIHdvdWxkIHNldmVyIHRoYXQgc2hhcmVkIHJlZmVyZW5jZS4gQm90aCBmaWVsZHMgYXJlXG4gICAgLy8gb3B0aW9uYWwgb24gdGhlIGNoZWNrcG9pbnQgKG9sZGVyIHBlcnNpc3RlZCBjaGVja3BvaW50cyBvbWl0IHRoZW0pIOKAlCBza2lwXG4gICAgLy8gc2VlZGluZyB3aGVuIGFic2VudCwgcHJlc2VydmluZyB0aGUgcHJldmlvdXMgYmVoYXZpb3IuIFNhbWUtZXhlY3V0b3JcbiAgICAvLyByZXN1bWUgaXMgaWRlbXBvdGVudDogYXQgcGF1c2UgdGhlIGluc3RhbmNlIHZhbHVlcyBhbHJlYWR5IGVxdWFsIHRoZVxuICAgIC8vIGNoZWNrcG9pbnQncywgc28gcmUtc2VlZGluZyB0aGVtIGNoYW5nZXMgbm90aGluZy5cbiAgICBpZiAoY2hlY2twb2ludC5leGVjdXRpb25Db3VudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl9leGVjdXRpb25Db3VudGVyLnZhbHVlID0gY2hlY2twb2ludC5leGVjdXRpb25Db3VudDtcbiAgICB9XG4gICAgaWYgKGNoZWNrcG9pbnQudmlzaXRDb3VudHMpIHtcbiAgICAgIHRoaXMuX3Zpc2l0Q291bnRzLmNsZWFyKCk7XG4gICAgICBmb3IgKGNvbnN0IFtzdGFnZUlkLCBjb3VudF0gb2YgT2JqZWN0LmVudHJpZXMoY2hlY2twb2ludC52aXNpdENvdW50cykpIHtcbiAgICAgICAgdGhpcy5fdmlzaXRDb3VudHMuc2V0KHN0YWdlSWQsIGNvdW50KTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gKFdpcGVkIG9ubHkgbm93OiBldmVyeSByZWZ1c2FsIGFib3ZlIGxlYXZlcyB0aGUgZXhlY3V0b3IncyBleGlzdGluZ1xuICAgIC8vIGNoZWNrcG9pbnQgdW50b3VjaGVkLilcbiAgICB0aGlzLmxhc3RDaGVja3BvaW50ID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gRG9uJ3QgY2xlYXIgcmVjb3JkZXJzIOKAlCByZXN1bWUgY29udGludWVzIGZyb20gcHJldmlvdXMgc3RhdGUuXG4gICAgLy8gTmFycmF0aXZlLCBtZXRyaWNzLCBkZWJ1ZyBlbnRyaWVzIGFjY3VtdWxhdGUgYWNyb3NzIHBhdXNlL3Jlc3VtZS5cbiAgICAvL1xuICAgIC8vIFR3by1tb2RlIHJlc3VtZTpcbiAgICAvLyAgIOKAoiBTYW1lLWV4ZWN1dG9yIChydW4oKSBwcmV2aW91c2x5IGNhbGxlZCBvbiBUSElTIGluc3RhbmNlKTpcbiAgICAvLyAgICAgcmV1c2UgdGhlIGV4aXN0aW5nIHJ1bnRpbWUgc28gdGhlIGV4ZWN1dGlvbiB0cmVlIGNvbnRpbnVlc1xuICAgIC8vICAgICBmcm9tIHRoZSBwYXVzZSBwb2ludCBhbmQgcmVjb3JkZXJzL25hcnJhdGl2ZSBhY2N1bXVsYXRlLlxuICAgIC8vICAg4oCiIENyb3NzLWV4ZWN1dG9yIChmcmVzaCBleGVjdXRvciByZWNvbnN0cnVjdGVkIGZyb20gYSBzdG9yZWRcbiAgICAvLyAgICAgY2hlY2twb2ludCk6IHNlZWQgYSBORVcgcnVudGltZSBmcm9tIGBjaGVja3BvaW50LnNoYXJlZFN0YXRlYFxuICAgIC8vICAgICBzbyByZXN1bWUgaGFuZGxlcnMgY2FuIHJlYWQgcHJlLXBhdXNlIHNjb3BlLiBUaGUgZXhlY3V0aW9uXG4gICAgLy8gICAgIHRyZWUgc3RhcnRzIGF0IHRoZSByZXN1bWUgZW50cnkg4oCUIHdlIGRvbid0IGhhdmUgdGhlIHByZXZpb3VzXG4gICAgLy8gICAgIHRyYXZlcnNhbCdzIHRyZWUgb24gYSBmcmVzaCBwcm9jZXNzIGFueXdheS5cbiAgICBjb25zdCBzYW1lRXhlY3V0b3IgPSB0aGlzLl9oYXNSdW5CZWZvcmU7XG4gICAgY29uc3QgZXhpc3RpbmdSdW50aW1lID0gc2FtZUV4ZWN1dG9yXG4gICAgICA/ICh0aGlzLnRyYXZlcnNlci5nZXRSdW50aW1lKCkgYXMgSW5zdGFuY2VUeXBlPHR5cGVvZiBFeGVjdXRpb25SdW50aW1lPilcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIHRoaXMuX2hhc1J1bkJlZm9yZSA9IHRydWU7IC8vIGFueSBwYXRoIHRoYXQgcmVzdW1lcyBjb3VudHMgYXMgYSBydW5cbiAgICAvLyBSZXN1bWUgZ2V0cyBhIE5FVyBydW5JZCDigJQgcmVzdW1lIGlzIGxvZ2ljYWxseSBhIGRpc3RpbmN0IHJ1bi5cbiAgICAvLyBPcmlnaW5hbCBydW5JZCBpcyByZWNvdmVyYWJsZSBmcm9tIGNoZWNrcG9pbnQgbWV0YWRhdGEgaWYgYSBjb25zdW1lclxuICAgIC8vIG5lZWRzIGNyb3NzLXJ1biBhdWRpdCAod2UgZG9uJ3Qgc3RvcmUgaXQgb24gdGhlIGNoZWNrcG9pbnQgdG9kYXk7XG4gICAgLy8gZnV0dXJlIGVuaGFuY2VtZW50KS4gU2VlIGBydW5JZC50c2AuXG4gICAgdGhpcy5fY3VycmVudFJ1bklkID0gZ2VuZXJhdGVSdW5JZCgpO1xuXG4gICAgLy8gSW5pdGlhbCBjb250ZXh0OiBgY2hlY2twb2ludC5zaGFyZWRTdGF0ZWAg4oCUIHRoZSB0b3AgbGV2ZWwncyB2aWV3IGF0IHRoZVxuICAgIC8vIHBhdXNlIChhIHN1YmZsb3cncyBvdXRwdXRNYXBwZXIgd3JpdGVzIGJhY2sgaW50byBpdCkuIFNhbWUtZXhlY3V0b3IsIHRoZVxuICAgIC8vIGV4aXN0aW5nIHJ1bnRpbWUgaXMgcmV1c2VkIGFuZCB0aGlzIGlzIG1vb3QsIGJ1dCBwYXNzZWQgZm9yIGNvbnNpc3RlbmN5LlxuICAgIC8vIENsb25lLWluIGZvciB0aGUgc2FtZSByZWFzb24gYXMgdGhlIGNhcHR1cmVzOiBgaW5pdGlhbENvbnRleHRgIHNlZWRzXG4gICAgLy8gdGhlIGZyZXNoIFNoYXJlZE1lbW9yeSB2aWEgYG1lcmdlQ29udGV4dFdpbnNgLCB3aGljaCBjb3BpZXMgb25seSB0aGUgVE9QXG4gICAgLy8gbGV2ZWwg4oCUIG5lc3RlZCBvYmplY3RzIHdvdWxkIGFsaWFzIHRoZSBjYWxsZXIncyBjaGVja3BvaW50LlxuICAgIGNvbnN0IHJlc3VtZUluaXRpYWxDb250ZXh0ID0gc3RydWN0dXJlZENsb25lKGNoZWNrcG9pbnQuc2hhcmVkU3RhdGUpO1xuXG4gICAgdGhpcy50cmF2ZXJzZXIgPSB0aGlzLmNyZWF0ZVRyYXZlcnNlcihcbiAgICAgIG9wdGlvbnM/LnNpZ25hbCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIG9wdGlvbnM/LmVudixcbiAgICAgIG9wdGlvbnM/Lm1heERlcHRoLFxuICAgICAgb3B0aW9ucz8ubWF4SXRlcmF0aW9ucyxcbiAgICAgIHtcbiAgICAgICAgaW5pdGlhbENvbnRleHQ6IHJlc3VtZUluaXRpYWxDb250ZXh0LFxuICAgICAgICBwcmVzZXJ2ZVJlY29yZGVyczogdHJ1ZSxcbiAgICAgICAgLi4uKGV4aXN0aW5nUnVudGltZSA/IHsgZXhpc3RpbmdSdW50aW1lIH0gOiB7fSksXG4gICAgICAgIHJlc3VtZTogcmVzdW1lRW50cnksXG4gICAgICB9LFxuICAgICk7XG5cbiAgICAvLyBGaXJlIG9uUmVzdW1lIGV2ZW50IG9uIGFsbCByZWNvcmRlcnMgKGZsb3cgKyBzY29wZSkuIFN0YW1wIHRoZVxuICAgIC8vIHN5bnRoZXRpYyBUcmF2ZXJzYWxDb250ZXh0IGZvciB0aGUgcmVzdW1lZCBzdGFnZSB3aXRoIHRoZSBORVdcbiAgICAvLyBydW5JZCBzbyBjb25zdW1lcnMgZGV0ZWN0IFwidGhpcyBpcyBhIGZyZXNoIGxvZ2ljYWwgcnVuXCIgdmlhXG4gICAgLy8gdGhlIHNhbWUgcnVuSWQtY2hhbmdlIHBhdHRlcm4gdGhleSB1c2UgZm9yIGBvblJ1blN0YXJ0YC4gVGhlIHN0YW1wIGlzXG4gICAgLy8gYnVpbHQgYnkgdGhlIG9uZSBjb25zdHJ1Y3RvciAoYGVuZ2luZS90cmF2ZXJzYWxDb250ZXh0LnRzYCk6IGl0IG5hbWVzIHRoZVxuICAgIC8vIFJFQUwgc3ViZmxvdyB0aGUgc3RhbmQtaW4gcnVucyBpbiBhbmQgaXRzIGRlcHRoLCBhbmQgTElOS1MgdG8gdGhlIHBhdXNlZFxuICAgIC8vIGV4ZWN1dGlvbiAoYHJlc3VtZWRGcm9tYCwgcmVhZCBvZmYgYGNoZWNrcG9pbnQucGF1c2VkRXhlY3V0aW9uYCkg4oCUIDkuMzcuMC5cbiAgICAvL1xuICAgIC8vIFRoZSBydW50aW1lU3RhZ2VJZCBpcyB0aGUgU1RBTkQtSU4ncyBvd246IGl0IHJ1bnMgYWZ0ZXIgb25lIG1vdW50IHBlclxuICAgIC8vIHN1YmZsb3cgb24gdGhlIHBhdGggKGVhY2ggZW50ZXJlZCBhdCBpdHMgbW91bnQpLCBzbyBpdHMgZXhlY3V0aW9uIGluZGV4XG4gICAgLy8gaXMgdGhlIGNvdW50ZXIgcGx1cyB0aGUgcGF0aCdzIGxlbmd0aCDigJQgdGhlIGV2ZW50IGFuZCB0aGUgc3RhbmQtaW4nc1xuICAgIC8vIGNvbW1pdCBuYW1lIHRoZSBzYW1lIGV4ZWN1dGlvbi4gKEZpcmVkIGJlZm9yZSB0aGUgdHJhdmVyc2FsIG9uIHB1cnBvc2U6XG4gICAgLy8gYG9uUmVzdW1lYCBwcmVjZWRlcyBgb25SdW5TdGFydGAsIHdoaWNoIHJlY29yZGVycyByZWx5IG9uIHRvIGFkb3B0IHRoZVxuICAgIC8vIG5ldyBydW5JZCB3aXRob3V0IHJlc2V0dGluZy4pIFRoZSBvbmUgc2hhcGUgd2hlcmUgdGhlIGluZGV4IGNhbm5vdCBiZVxuICAgIC8vIGtub3duIHVwIGZyb250IOKAlCBhIGRlZ3JhZGVkIGNoZWNrcG9pbnQgbWlzc2luZyBhbiBPVVRFUiBzdWJmbG93J3NcbiAgICAvLyBjYXB0dXJlLCB3aG9zZSBvcGVuaW5nIHN0YWdlcyB0aGVuIHJlLXJ1biDigJQgbmFtZXMgdGhlIHBsYW5uZWQgcG9zaXRpb24uXG4gICAgY29uc3QgaGFzSW5wdXQgPSByZXN1bWVJbnB1dCAhPT0gdW5kZWZpbmVkO1xuICAgIGNvbnN0IHN0ZXBzQmVmb3JlU3RhbmRJbiA9IHJlc3VtZUVudHJ5LnN0ZXBzQmVmb3JlU3RhbmRJbiA/PyBjaGVja3BvaW50LnN1YmZsb3dQYXRoLmxlbmd0aDtcbiAgICBjb25zdCByZXN1bWVSdW50aW1lU3RhZ2VJZCA9IGJ1aWxkUnVudGltZVN0YWdlSWQocGF1c2VkTm9kZS5pZCwgdGhpcy5fZXhlY3V0aW9uQ291bnRlci52YWx1ZSArIHN0ZXBzQmVmb3JlU3RhbmRJbik7XG4gICAgY29uc3QgcmVzdW1lZEZyb20gPSByZXN1bWVMaW5rT2YoY2hlY2twb2ludCk7XG4gICAgY29uc3QgZmxvd1Jlc3VtZUV2ZW50ID0ge1xuICAgICAgc3RhZ2VOYW1lOiBwYXVzZWROb2RlLm5hbWUsXG4gICAgICBzdGFnZUlkOiBwYXVzZWROb2RlLmlkLFxuICAgICAgaGFzSW5wdXQsXG4gICAgICB0cmF2ZXJzYWxDb250ZXh0OiByZXN1bWVUcmF2ZXJzYWxDb250ZXh0KHtcbiAgICAgICAgcnVuSWQ6IHRoaXMuX2N1cnJlbnRSdW5JZCxcbiAgICAgICAgc3RhZ2VJZDogcGF1c2VkTm9kZS5pZCxcbiAgICAgICAgc3RhZ2VOYW1lOiBwYXVzZWROb2RlLm5hbWUsXG4gICAgICAgIHJ1bnRpbWVTdGFnZUlkOiByZXN1bWVSdW50aW1lU3RhZ2VJZCxcbiAgICAgICAgc3ViZmxvd1BhdGg6IGNoZWNrcG9pbnQuc3ViZmxvd1BhdGgsXG4gICAgICAgIHJlc3VtZWRGcm9tLFxuICAgICAgfSksXG4gICAgICBjaGFubmVsOiAnZmxvdycgYXMgY29uc3QsXG4gICAgfTtcbiAgICAvLyBFeGVjdXRvci1tYWRlIChgSE9PS1Mub25SZXN1bWUuZXhlY3V0b3JNYWRlYCk6IGZpcmVkIHRocm91Z2ggdGhlIHNhbWUgYGZpcmVgIGxvb3AgYXMgZXZlcnlcbiAgICAvLyBlbmdpbmUgZXZlbnQsIHNvIGEgdGhyb3dpbmcgcmVjb3JkZXIgaXMgaXNvbGF0ZWQgaW5zdGVhZCBvZiByZWplY3RpbmcgYHJlc3VtZSgpYCAoUjEwKS5cbiAgICBjb25zdCBmbG93TGlzdGVuZXJzID0gdGhpcy5jb21iaW5lZFJlY29yZGVyID8gW3RoaXMuY29tYmluZWRSZWNvcmRlciwgLi4udGhpcy5mbG93UmVjb3JkZXJzXSA6IHRoaXMuZmxvd1JlY29yZGVycztcbiAgICBmaXJlKGZsb3dMaXN0ZW5lcnMsICdvblJlc3VtZScsIGZsb3dSZXN1bWVFdmVudCwgUkVTVU1FX0ZMT1dfRkFJTFVSRSk7XG5cbiAgICBjb25zdCBzY29wZVJlc3VtZUV2ZW50ID0ge1xuICAgICAgc3RhZ2VOYW1lOiBwYXVzZWROb2RlLm5hbWUsXG4gICAgICBzdGFnZUlkOiBwYXVzZWROb2RlLmlkLFxuICAgICAgcnVudGltZVN0YWdlSWQ6IHJlc3VtZVJ1bnRpbWVTdGFnZUlkLFxuICAgICAgaGFzSW5wdXQsXG4gICAgICAuLi4ocmVzdW1lZEZyb20gJiYgeyByZXN1bWVkRnJvbSB9KSxcbiAgICAgIHBpcGVsaW5lSWQ6ICcnLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgY2hhbm5lbDogJ3Njb3BlJyBhcyBjb25zdCxcbiAgICB9O1xuICAgIGZpcmUodGhpcy5zY29wZVJlY29yZGVycywgJ29uUmVzdW1lJywgc2NvcGVSZXN1bWVFdmVudCwgKGVycm9yLCBfcmVjb3JkZXIsIGhvb2spID0+XG4gICAgICAvLyBUaGUgc2NvcGUgY2hhbm5lbCdzIHBvbGljeSAoYXMgYFNjb3BlRmFjYWRlYCByb3V0ZXMgYSBzdGFnZSdzIGhvb2sgZmFpbHVyZSk6IHRoZSB0aHJvd1xuICAgICAgLy8gYmVjb21lcyBhbiBgb25FcnJvcmAgb24gZXZlcnkgc2NvcGUgcmVjb3JkZXIsIHdob3NlIG93biB0aHJvdyBpcyBkcm9wcGVkLlxuICAgICAgZmlyZSh0aGlzLnNjb3BlUmVjb3JkZXJzLCAnb25FcnJvcicsIHJlY29yZGVyRmFpbHVyZUV2ZW50KHNjb3BlUmVzdW1lRXZlbnQsIGVycm9yLCBob29rKSksXG4gICAgKTtcblxuICAgIC8vIERlZmVycmVkIHRpZXIgKFJGQy0wMDEpOiB0aGVzZSBleGVjdXRvci1zeW50aGVzaXplZCBvblJlc3VtZSBldmVudHNcbiAgICAvLyBieXBhc3MgdGhlIHBlci1zdGFnZSBkaXNwYXRjaCBzaXRlcywgc28gY2FwdHVyZSB0aGVtIGRpcmVjdGx5LlxuICAgIGlmICh0aGlzLmRlZmVycmVkVGllcikge1xuICAgICAgdGhpcy5kZWZlcnJlZFRpZXIuY2FwdHVyZSgnZmxvdycsICdvblJlc3VtZScsIHJlc3VtZVJ1bnRpbWVTdGFnZUlkLCB0aGlzLl9jdXJyZW50UnVuSWQsIGZsb3dSZXN1bWVFdmVudCk7XG4gICAgICB0aGlzLmRlZmVycmVkVGllci5jYXB0dXJlKFxuICAgICAgICAnc2NvcGUnLFxuICAgICAgICAnb25SZXN1bWUnLFxuICAgICAgICBzY29wZVJlc3VtZUV2ZW50LnJ1bnRpbWVTdGFnZUlkLFxuICAgICAgICBzY29wZVJlc3VtZUV2ZW50LnBpcGVsaW5lSWQsXG4gICAgICAgIHNjb3BlUmVzdW1lRXZlbnQsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFNldCBBRlRFUiBhbGwgc3luYyB2YWxpZGF0aW9uL2xvb2t1cCB0aHJvd3MgYWJvdmUgKG5vdGhpbmcgY2FuIGxlYWsgdGhlXG4gICAgLy8gZmxhZyk7IG5vIGF3YWl0IGJldHdlZW4gdGhlIHRvcC1vZi1tZXRob2QgY2hlY2sgYW5kIGhlcmUsIHNvIHJhY2UtZnJlZS5cbiAgICB0aGlzLl9pc0V4ZWN1dGluZyA9IHRydWU7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudHJhdmVyc2VyLmV4ZWN1dGUoKTtcbiAgICAgIC8vIFRlcm1pbmFsIGZsdXNoIChSRkMtMDAxIEJsb2NrIDgpIOKAlCBzYW1lIGJvdW5kYXJ5IGNvbnRyYWN0IGFzIHJ1bigpLlxuICAgICAgdGhpcy5kZWZlcnJlZFRpZXI/LnRlcm1pbmFsRmx1c2goKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIHRoaXMuZGVmZXJyZWRUaWVyPy50ZXJtaW5hbEZsdXNoKCk7XG4gICAgICBpZiAoaXNQYXVzZVNpZ25hbChlcnJvcikpIHtcbiAgICAgICAgdGhpcy5sYXN0Q2hlY2twb2ludCA9IHRoaXMuYnVpbGRQYXVzZUNoZWNrcG9pbnQoZXJyb3IpO1xuICAgICAgICByZXR1cm4geyBwYXVzZWQ6IHRydWUsIGNoZWNrcG9pbnQ6IHRoaXMubGFzdENoZWNrcG9pbnQgfSBzYXRpc2ZpZXMgUGF1c2VkUmVzdWx0O1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuX2lzRXhlY3V0aW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgZnVsbHkgREVUQUNIRUQgY2hlY2twb2ludCBmcm9tIGEgY2F1Z2h0IFBhdXNlU2lnbmFsLlxuICAgKlxuICAgKiBFdmVyeSBmaWVsZCBpcyBkZWVwLWNvcGllZCB2aWEgb25lIGBzdHJ1Y3R1cmVkQ2xvbmVgIG9mIHRoZSBhc3NlbWJsZWRcbiAgICogY2hlY2twb2ludCwgYmVjYXVzZSB0aGUgcmF3IHBpZWNlcyBhbGlhcyBsaXZlIGVuZ2luZSBzdGF0ZTpcbiAgICpcbiAgICogICAtIGBzaGFyZWRTdGF0ZWAgSVMgYFNoYXJlZE1lbW9yeWAncyBjdXJyZW50IGdlbmVyYXRpb24g4oCUIG5ldmVyIGVkaXRlZCxcbiAgICogICAgIGJ1dCAoY29weS1vbi13cml0ZSwgOS4yOS4wKSBldmVyeSBsYXRlciBnZW5lcmF0aW9uIHNoYXJlcyBpdHNcbiAgICogICAgIHVuY2hhbmdlZCBzdWJ0cmVlcywgc28gYSBjaGVja3BvaW50IHRoYXQgYWxpYXNlZCBpdCB3b3VsZCBhbGlhcyB0aGVcbiAgICogICAgIHJlc3VtZWQgcnVuJ3Mgc3RhdGUgdG9vLlxuICAgKiAgIC0gYGV4ZWN1dGlvblRyZWVgIG5vZGVzIGFyZSBmcmVzaCwgYnV0IHRoZWlyIGBsb2dzYC9gZXJyb3JzYC9gbWV0cmljc2AvXG4gICAqICAgICBgZXZhbHNgL2BzdGFnZVJlYWRzYC9gZmxvd01lc3NhZ2VzYCBmaWVsZHMgcmVmZXJlbmNlIGxpdmVcbiAgICogICAgIGBEaWFnbm9zdGljQ29sbGVjdG9yYCBiYWdzIHRoYXQga2VlcCBhY2N1bXVsYXRpbmcgb24gc2FtZS1leGVjdXRvclxuICAgKiAgICAgcmVzdW1lLlxuICAgKiAgIC0gYHN1YmZsb3dTdGF0ZXNgIHZhbHVlcyBhcmUgc2hhbGxvdyBjb3BpZXMgd2hvc2UgTkVTVEVEIG9iamVjdHMgYWxpYXNcbiAgICogICAgIHN1YmZsb3cgbWVtb3J5LCBhbmQgdGhleSBnZXQgc2VlZGVkIGJhY2sgaW50byBsaXZlIHJ1bnRpbWVzIG9uIHJlc3VtZS5cbiAgICogICAtIGBzdWJmbG93UmVzdWx0c2AgdmFsdWVzIHN0YXkgcmVmZXJlbmNlZCBieSB0aGUgdHJhdmVyc2VyJ3MgcmVzdWx0cyBtYXAuXG4gICAqXG4gICAqIFRoZSBjaGVja3BvaW50IGlzIHBlcnNpc3RlZCBieSBjb250cmFjdCAoXCJzdG9yZSBpbiBSZWRpcy9Qb3N0Z3Jlc1wiKSDigJQgaXRcbiAgICogbXVzdCBuZXZlciBzaGFyZSBzdHJ1Y3R1cmUgd2l0aCB0aGUgZW5naW5lLiBQYXVzZSBpcyBub3QgYSBob3QgcGF0aDsgdGhlXG4gICAqIGNsb25lIGNvc3QgaXMgaXJyZWxldmFudC5cbiAgICpcbiAgICogVGhlIEpTT04tc2FmZSBjaGVja3BvaW50IGNvbnRyYWN0IChubyBmdW5jdGlvbnMsIG5vIGNsYXNzIGluc3RhbmNlcylcbiAgICogZ292ZXJucyBDT05TVU1FUi1vd25lZCBkYXRhIOKAlCBidXQgdGhlIGV4ZWN1dGlvblRyZWUncyBkaWFnbm9zdGljIGJhZ3NcbiAgICogYWNjZXB0IEFOWSB2YWx1ZSBhdCB3cml0ZSB0aW1lIHdpdGhvdXQgY2xvbmluZyAoJGRlYnVnLyRlcnJvci8kbWV0cmljL1xuICAgKiAkZXZhbCBzdG9yZSByYXcgcmVmZXJlbmNlcyksIHNvIGEgY29udHJhY3QtY29tcGxpYW50IHJ1biBjYW4gc3RpbGwgY2FycnlcbiAgICogYSBub24tY2xvbmVhYmxlIGRpYWdub3N0aWMuIE9ic2VydmFiaWxpdHkgc2lkZS1iYWdzIG5ldmVyIGFib3J0IHRyYXZlcnNhbFxuICAgKiBhbnl3aGVyZSBlbHNlIGluIHRoZSBsaWJyYXJ5LCBzbyB0aGV5IG11c3Qgbm90IGFib3J0IHRoZSBwYXVzZSBlaXRoZXI6XG4gICAqIG9uIGNsb25lIGZhaWx1cmUgd2Ugc2FuaXRpemUgdGhlIGRpYWdub3N0aWMgYmFncyAobm9uLWNsb25lYWJsZSB2YWx1ZXNcbiAgICogYmVjb21lICdbbm9uLXNlcmlhbGl6YWJsZTog4oCmXScgbWFya2VycyDigJQgdGhlIGxpdmUgZW5naW5lIGJhZ3MgYXJlIG5ldmVyXG4gICAqIHRvdWNoZWQpIGFuZCByZXRyeS4gSWYgdGhlIHJldHJ5IFNUSUxMIGZhaWxzLCB0aGUgdmlvbGF0aW9uIGlzIGluXG4gICAqIGNvbnN1bWVyLW93bmVkIGRhdGEgKHJlYWxpc3RpY2FsbHkgYHBhdXNlRGF0YWAg4oCUIGEgZnVuY3Rpb24gY2FuIG5ldmVyXG4gICAqIHJlYWNoIHNoYXJlZCBzdGF0ZSBpbiB0aGUgZmlyc3QgcGxhY2U6IFRyYW5zYWN0aW9uQnVmZmVyIGNsb25lcyBldmVyeVxuICAgKiB3cml0dGVuIHZhbHVlIGF0IHdyaXRlIHRpbWUsIHNvIHRoZSBvZmZlbmRpbmcgd3JpdGUgYWxyZWFkeSByZWplY3RlZClcbiAgICogYW5kIHdlIHRocm93IGEgREVTQ1JJUFRJVkUgY29udHJhY3QgZXJyb3IgbmFtaW5nIHRoZSBvZmZlbmRpbmdcbiAgICogY2hlY2twb2ludCBmaWVsZChzKS4gQSBuYWtlZCBEYXRhQ2xvbmVFcnJvciBuZXZlciBlc2NhcGVzLlxuICAgKlxuICAgKiBTdWJmbG93IHNjb3BlIGNhcHR1cmUgKGBzdWJmbG93U3RhdGVzYCkgc3Vydml2ZXMgT05MWSBvbiB0aGUgc2lnbmFsIOKAlCB0aGVcbiAgICogbmVzdGVkIHJ1bnRpbWVzIGFyZSBHQydkIGFzIHRoZSBzdGFjayB1bndpbmRzLiBQcm9tb3RpbmcgaXQgb250byB0aGVcbiAgICogY2hlY2twb2ludCBoZXJlIGxldHMgY3Jvc3MtZXhlY3V0b3IgcmVzdW1lIHJlc3RvcmUgcHJlLXBhdXNlIHN1YmZsb3dcbiAgICogc2NvcGUgKGUuZy4gYW4gQWdlbnQncyBgc2NvcGUuaGlzdG9yeWApLiBFbXB0eSBge31gIGZvciByb290LWxldmVsIHBhdXNlcy5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRQYXVzZUNoZWNrcG9pbnQoc2lnbmFsOiBQYXVzZVNpZ25hbCk6IEZsb3djaGFydENoZWNrcG9pbnQge1xuICAgIC8vIEV2ZXJ5IHBhdXNlIHRoYXQgcGF1c2VkIGluIFRISVMgcnVuIGlzIG5hbWVkIGJ5IGl0OyBhIHNpYmxpbmcgcmFpc2VkIGFnYWluXG4gICAgLy8gb24gcmVzdW1lIGtlZXBzIHRoZSBydW4gaXQgb3JpZ2luYWxseSBwYXVzZWQgaW4uXG4gICAgc2lnbmFsLmNvbXBsZXRlRXhlY3V0aW9uKHRoaXMuX2N1cnJlbnRSdW5JZCk7XG4gICAgY29uc3Qgc25hcHNob3QgPSB0aGlzLnRyYXZlcnNlci5nZXRTbmFwc2hvdCgpO1xuICAgIGNvbnN0IHNmUmVzdWx0cyA9IHRoaXMudHJhdmVyc2VyLmdldFN1YmZsb3dSZXN1bHRzKCk7XG4gICAgLy8gTGVhbiBzdWJmbG93UmVzdWx0cyBmb3IgdGhlIGNoZWNrcG9pbnQgKGRlc2lnbjogZG9jcy9kZXNpZ24vc3ViZmxvdy1jb21taXQtdmlzaWJpbGl0eS5tZCk6XG4gICAgLy8gICDigKIgRFJPUCB0aGUgcGVyLWl0ZXJhdGlvbiBtb3VudC1ydW50aW1lU3RhZ2VJZCBrZXlzICgnIycpIHRoYXQgdGhlIHNuYXBzaG90IGR1YWwta2V5cyDigJRcbiAgICAvLyAgICAgdGhleSB3b3VsZCBET1VCTEUgdGhlIGNoZWNrcG9pbnQsIGFuZCByZXN1bWUgcmVzdG9yZXMgc2NvcGUgZnJvbSBgc3ViZmxvd1N0YXRlc2AsIG5vdCB0aGVzZS5cbiAgICAvLyAgIOKAoiBTVFJJUCBlYWNoIHN1YmZsb3cncyBgdHJlZUNvbnRleHQuaGlzdG9yeWAg4oCUIHJlc3VtZSBORVZFUiByZWFkcyBgc3ViZmxvd1Jlc3VsdHNgIChpdFxuICAgIC8vICAgICByZXN0b3JlcyBmcm9tIGBzdWJmbG93U3RhdGVzYCArIGBzaGFyZWRTdGF0ZWApLCBzbyB0aGUgcGVyLXN1YmZsb3cgY29tbWl0IGxvZyBpcyBwdXJlXG4gICAgLy8gICAgIGNoZWNrcG9pbnQgYmxvYXQuIFRoZSBmbGF0IGFnZW50J3MgY2hlY2twb2ludCBjYXJyaWVzIG5vIGNvbW1pdCBoaXN0b3J5IGVpdGhlciDihpIgc3ltbWV0cmljLlxuICAgIGNvbnN0IGxlYW5TdWJmbG93UmVzdWx0czogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBzZlJlc3VsdHMpIHtcbiAgICAgIGlmIChpc0V4ZWN1dGlvbktleShrZXkpKSBjb250aW51ZTsgLy8gcGVyLWl0ZXJhdGlvbiBrZXlzIGFyZSBzbmFwc2hvdC1vbmx5XG4gICAgICBjb25zdCB2ID0gdmFsdWUgYXMgdW5rbm93biBhcyB7IHRyZWVDb250ZXh0PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfTtcbiAgICAgIGlmICh2Py50cmVlQ29udGV4dCkge1xuICAgICAgICBjb25zdCB0cmVlQ3R4UmVzdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBjayBvZiBPYmplY3Qua2V5cyh2LnRyZWVDb250ZXh0KSkge1xuICAgICAgICAgIGlmIChjayAhPT0gJ2hpc3RvcnknKSB0cmVlQ3R4UmVzdFtja10gPSB2LnRyZWVDb250ZXh0W2NrXTsgLy8gc3RyaXAgdGhlIHBlci1zdWJmbG93IGNvbW1pdCBsb2dcbiAgICAgICAgfVxuICAgICAgICBsZWFuU3ViZmxvd1Jlc3VsdHNba2V5XSA9IHsgLi4uKHZhbHVlIGFzIHVua25vd24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLCB0cmVlQ29udGV4dDogdHJlZUN0eFJlc3QgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxlYW5TdWJmbG93UmVzdWx0c1trZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGNoZWNrcG9pbnQgPSB7XG4gICAgICAvLyBUaGUgZm9ybWF0ICg5LjM5LjApIOKAlCByZWFkIGJhY2sgYnkgYHBhdXNlL3JlY29yZC50cyDCtyBkZWNvZGVDaGVja3BvaW50YC5cbiAgICAgIGNoZWNrcG9pbnRWZXJzaW9uOiBDSEVDS1BPSU5UX1ZFUlNJT04sXG4gICAgICBzaGFyZWRTdGF0ZTogc25hcHNob3Quc2hhcmVkU3RhdGUsXG4gICAgICBleGVjdXRpb25UcmVlOiBzbmFwc2hvdC5leGVjdXRpb25UcmVlLFxuICAgICAgcGF1c2VkU3RhZ2VJZDogc2lnbmFsLnN0YWdlSWQsXG4gICAgICAvLyBUaGUgcGF1c2VkIEVYRUNVVElPTiAoOS4zNy4wKSDigJQgYSBxdWV1ZWQgc2libGluZyByYWlzZWQgb24gcmVzdW1lXG4gICAgICAvLyBjYXJyaWVzIHRoZSBydW4gaXQgT1JJR0lOQUxMWSBwYXVzZWQgaW4uXG4gICAgICAuLi4oc2lnbmFsLnBhdXNlZEV4ZWN1dGlvbiAmJiB7IHBhdXNlZEV4ZWN1dGlvbjogc2lnbmFsLnBhdXNlZEV4ZWN1dGlvbiB9KSxcbiAgICAgIHN1YmZsb3dQYXRoOiBzaWduYWwuc3ViZmxvd1BhdGgsXG4gICAgICBwYXVzZURhdGE6IHNpZ25hbC5wYXVzZURhdGEsXG4gICAgICBzdWJmbG93U3RhdGVzOiBzaWduYWwuc3ViZmxvd1N0YXRlcyxcbiAgICAgIC8vIENvdW50ZXIgY29udGludWl0eSDigJQgc2VlZGVkIGJhY2sgaW4gcmVzdW1lKCkgc28gcnVudGltZVN0YWdlSWRzIHN0YXlcbiAgICAgIC8vIHVuaXF1ZSBhbmQgbG9vcEl0ZXJhdGlvbiBzdGF5cyBtb25vdG9uaWMgYWNyb3NzIGEgQ1JPU1MtZXhlY3V0b3IgcmVzdW1lXG4gICAgICAvLyAoYm90aCBhcmUgcGxhaW4gbnVtYmVyL3JlY29yZCwgc28gdGhleSByaWRlIHRoZSBzaW5nbGUgc3RydWN0dXJlZENsb25lXG4gICAgICAvLyBiZWxvdyB1bnRvdWNoZWQpLiBTZWUgdGVzdC9saWIvcGF1c2UvcmVzdW1lLWV4ZWN1dGlvbi1jb3VudGVyLWNvbnRpbnVpdHkudGVzdC50cy5cbiAgICAgIGV4ZWN1dGlvbkNvdW50OiB0aGlzLl9leGVjdXRpb25Db3VudGVyLnZhbHVlLFxuICAgICAgdmlzaXRDb3VudHM6IE9iamVjdC5mcm9tRW50cmllcyh0aGlzLl92aXNpdENvdW50cyksXG4gICAgICAuLi4oT2JqZWN0LmtleXMobGVhblN1YmZsb3dSZXN1bHRzKS5sZW5ndGggPiAwICYmIHsgc3ViZmxvd1Jlc3VsdHM6IGxlYW5TdWJmbG93UmVzdWx0cyB9KSxcbiAgICAgIC8vIEludm9rZXIgY29udGV4dCDigJQgY29sbGVjdGVkIGR1cmluZyB0cmF2ZXJzYWwgYnViYmxlLXVwIChub3QgdHJlZS13YWxrZWQpLlxuICAgICAgLy8gKGBjb250aW51YXRpb25TdGFnZUlkYCBpcyBsZWdhY3ktb25seSBzaW5jZSA5LjM5LjA6IG5vIGxvbmdlciB3cml0dGVuLilcbiAgICAgIC4uLihzaWduYWwuaW52b2tlclN0YWdlSWQgJiYgeyBpbnZva2VyU3RhZ2VJZDogc2lnbmFsLmludm9rZXJTdGFnZUlkIH0pLFxuICAgICAgLy8gUGFyYWxsZWwgc2libGluZ3MnIHBhdXNlcyBmcm9tIHRoZSBzYW1lIGZhbi1vdXQsIHdhaXRpbmcgdGhlaXIgdHVyblxuICAgICAgLy8gKDkuMjguMCkuIEFic2VudCB3aGVuIG9ubHkgb25lIGNoaWxkIHBhdXNlZCDigJQgdGhlIHNoYXBlIGV2ZXJ5XG4gICAgICAvLyBlYXJsaWVyIGNoZWNrcG9pbnQgaGFzLlxuICAgICAgLi4uKHNpZ25hbC5wZW5kaW5nUGF1c2VzLmxlbmd0aCA+IDAgJiYgeyBwZW5kaW5nUGF1c2VzOiBzaWduYWwucGVuZGluZ1BhdXNlcyB9KSxcbiAgICAgIC8vIEhPVyB0aGUgcGF1c2Ugd2FzIHJhaXNlZC4gT25lIGNoZWNrcG9pbnQgc2hhcGUsIG9uZSBleHRyYSBvcHRpb25hbFxuICAgICAgLy8gZmllbGQg4oCUIGFuIGludGVycnVwdCgpIHBhdXNlIGlzIG5vdCBhIHNlY29uZCBraW5kIG9mIGNoZWNrcG9pbnQsIGl0IGlzXG4gICAgICAvLyB0aGUgc2FtZSBjaGVja3BvaW50IHRoYXQgcmVzdW1lKCkgcmUtZW50ZXJzIGRpZmZlcmVudGx5IChzdGFnZSB0b3AgdnNcbiAgICAgIC8vIHJlc3VtZUZuKS4gQWJzZW50IGZvciBldmVyeSBwcmUtOS4xNC4wIGNoZWNrcG9pbnQsIHdoaWNoIGlzIGNvcnJlY3QuXG4gICAgICAuLi4oc2lnbmFsLnBhdXNlZEJ5ICYmIHsgcGF1c2VkQnk6IHNpZ25hbC5wYXVzZWRCeSB9KSxcbiAgICAgIHBhdXNlZEF0OiBEYXRlLm5vdygpLFxuICAgIH07XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBzdHJ1Y3R1cmVkQ2xvbmUoY2hlY2twb2ludCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb24tY2xvbmVhYmxlIGRpYWdub3N0aWNzIG11c3Qgbm90IHN3YWxsb3cgdGhlIHBhdXNlIOKAlCBzYW5pdGl6ZSB0aGVcbiAgICAgIC8vIGV4ZWN1dGlvblRyZWUncyBiYWdzIChtYXJrZXJzIHJlcGxhY2UgdGhlIG9mZmVuZGVycykgYW5kIHJldHJ5LlxuICAgICAgdHJ5IHtcbiAgICAgICAgY2hlY2twb2ludC5leGVjdXRpb25UcmVlID0gc2FuaXRpemVEaWFnbm9zdGljQmFncyhjaGVja3BvaW50LmV4ZWN1dGlvblRyZWUgYXMgU3RhZ2VTbmFwc2hvdCk7XG4gICAgICAgIHJldHVybiBzdHJ1Y3R1cmVkQ2xvbmUoY2hlY2twb2ludCk7XG4gICAgICB9IGNhdGNoIChyZXRyeUVycm9yKSB7XG4gICAgICAgIC8vIEdlbnVpbmUgSlNPTi1zYWZlIGNvbnRyYWN0IHZpb2xhdGlvbiBpbiBjb25zdW1lci1vd25lZCBkYXRhLlxuICAgICAgICB0aHJvdyBkZXNjcmliZUNoZWNrcG9pbnRDbG9uZUZhaWx1cmUoY2hlY2twb2ludCwgcmV0cnlFcnJvcik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgYSBTdGFnZU5vZGUgaW4gdGhlIGNvbXBpbGVkIGdyYXBoIGJ5IElELlxuICAgKiBIYW5kbGVzIHN1YmZsb3cgcGF0aHMgYnkgZHJpbGxpbmcgaW50byByZWdpc3RlcmVkIHN1YmZsb3dzLlxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kTm9kZUluR3JhcGgoc3RhZ2VJZDogc3RyaW5nLCBzdWJmbG93UGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiBTdGFnZU5vZGU8VE91dCwgVFNjb3BlPiB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgZmMgPSB0aGlzLmZsb3dDaGFydEFyZ3MuZmxvd0NoYXJ0O1xuXG4gICAgaWYgKHN1YmZsb3dQYXRoLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gVG9wLWxldmVsOiBERlMgZnJvbSByb290XG4gICAgICByZXR1cm4gdGhpcy5kZnNGaW5kKGZjLnJvb3QsIHN0YWdlSWQpO1xuICAgIH1cblxuICAgIC8vIFN1YmZsb3c6IGRyaWxsIGludG8gdGhlIHN1YmZsb3cgY2hhaW4sIHRoZW4gc2VhcmNoIGZyb20gdGhlIGxhc3Qgc3ViZmxvdydzIHJvb3RcbiAgICBsZXQgc3ViZmxvd1Jvb3Q6IFN0YWdlTm9kZTxUT3V0LCBUU2NvcGU+IHwgdW5kZWZpbmVkO1xuICAgIGZvciAoY29uc3Qgc2ZJZCBvZiBzdWJmbG93UGF0aCkge1xuICAgICAgY29uc3Qgc3ViZmxvdyA9IGZjLnN1YmZsb3dzPy5bc2ZJZF07XG4gICAgICBpZiAoIXN1YmZsb3cpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICBzdWJmbG93Um9vdCA9IHN1YmZsb3cucm9vdDtcbiAgICB9XG4gICAgaWYgKCFzdWJmbG93Um9vdCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICByZXR1cm4gdGhpcy5kZnNGaW5kKHN1YmZsb3dSb290LCBzdGFnZUlkKTtcbiAgfVxuXG4gIC8qKiBERlMgc2VhcmNoIGZvciBhIG5vZGUgYnkgSUQgaW4gdGhlIFN0YWdlTm9kZSBncmFwaC4gQ3ljbGUtc2FmZSB2aWEgdmlzaXRlZCBzZXQuICovXG4gIHByaXZhdGUgZGZzRmluZChcbiAgICBub2RlOiBTdGFnZU5vZGU8VE91dCwgVFNjb3BlPixcbiAgICB0YXJnZXRJZDogc3RyaW5nLFxuICAgIHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKSxcbiAgKTogU3RhZ2VOb2RlPFRPdXQsIFRTY29wZT4gfCB1bmRlZmluZWQge1xuICAgIC8vIFNraXAgbG9vcCBiYWNrLWVkZ2UgcmVmZXJlbmNlcyAodGhleSBzaGFyZSB0aGUgdGFyZ2V0J3MgSUQgYnV0IGhhdmUgbm8gZm4vcmVzdW1lRm4pXG4gICAgaWYgKG5vZGUuaXNMb29wUmVmKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGlmICh2aXNpdGVkLmhhcyhub2RlLmlkKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB2aXNpdGVkLmFkZChub2RlLmlkKTtcbiAgICBpZiAobm9kZS5pZCA9PT0gdGFyZ2V0SWQpIHJldHVybiBub2RlO1xuICAgIGlmIChub2RlLmNoaWxkcmVuKSB7XG4gICAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIG5vZGUuY2hpbGRyZW4pIHtcbiAgICAgICAgY29uc3QgZm91bmQgPSB0aGlzLmRmc0ZpbmQoY2hpbGQsIHRhcmdldElkLCB2aXNpdGVkKTtcbiAgICAgICAgaWYgKGZvdW5kKSByZXR1cm4gZm91bmQ7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChub2RlLm5leHQpIHJldHVybiB0aGlzLmRmc0ZpbmQobm9kZS5uZXh0LCB0YXJnZXRJZCwgdmlzaXRlZCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBTY29wZVJlY29yZGVyIE1hbmFnZW1lbnQg4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIEF0dGFjaCBhIHNjb3BlIFNjb3BlUmVjb3JkZXIgdG8gb2JzZXJ2ZSBkYXRhIG9wZXJhdGlvbnMgKHJlYWRzLCB3cml0ZXMsIGNvbW1pdHMpLlxuICAgKiBBdXRvbWF0aWNhbGx5IGF0dGFjaGVkIHRvIGV2ZXJ5IFNjb3BlRmFjYWRlIGNyZWF0ZWQgZHVyaW5nIHRyYXZlcnNhbC5cbiAgICogTXVzdCBiZSBjYWxsZWQgYmVmb3JlIHJ1bigpLlxuICAgKlxuICAgKiAqKklkZW1wb3RlbnQgYnkgSUQ6KiogSWYgYSByZWNvcmRlciB3aXRoIHRoZSBzYW1lIGBpZGAgaXMgYWxyZWFkeSBhdHRhY2hlZCxcbiAgICogaXQgaXMgcmVwbGFjZWQgKG5vdCBkdXBsaWNhdGVkKS4gVGhpcyBwcmV2ZW50cyBkb3VibGUtY291bnRpbmcgd2hlbiBib3RoXG4gICAqIGEgZnJhbWV3b3JrIGFuZCB0aGUgdXNlciBhdHRhY2ggdGhlIHNhbWUgcmVjb3JkZXIgdHlwZS5cbiAgICpcbiAgICogQnVpbHQtaW4gcmVjb3JkZXJzIHVzZSBhdXRvLWluY3JlbWVudCBJRHMgKGBtZXRyaWNzLTFgLCBgZGVidWctMWAsIC4uLikgYnlcbiAgICogZGVmYXVsdCwgc28gbXVsdGlwbGUgaW5zdGFuY2VzIHdpdGggZGlmZmVyZW50IGNvbmZpZ3MgY29leGlzdC4gVG8gb3ZlcnJpZGVcbiAgICogYSBmcmFtZXdvcmstYXR0YWNoZWQgcmVjb3JkZXIsIHBhc3MgdGhlIHNhbWUgd2VsbC1rbm93biBJRC5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBNdWx0aXBsZSByZWNvcmRlcnMgd2l0aCBkaWZmZXJlbnQgY29uZmlncyDigJQgZWFjaCBnZXRzIGEgdW5pcXVlIElEXG4gICAqIGV4ZWN1dG9yLmF0dGFjaFNjb3BlUmVjb3JkZXIobmV3IE1ldHJpY1JlY29yZGVyKCkpO1xuICAgKiBleGVjdXRvci5hdHRhY2hTY29wZVJlY29yZGVyKG5ldyBEZWJ1Z1JlY29yZGVyKHsgdmVyYm9zaXR5OiAnbWluaW1hbCcgfSkpO1xuICAgKlxuICAgKiAvLyBPdmVycmlkZSBhIGZyYW1ld29yay1hdHRhY2hlZCByZWNvcmRlciBieSBwYXNzaW5nIGl0cyB3ZWxsLWtub3duIElEXG4gICAqIGV4ZWN1dG9yLmF0dGFjaFNjb3BlUmVjb3JkZXIobmV3IE1ldHJpY1JlY29yZGVyKCdtZXRyaWNzJykpO1xuICAgKlxuICAgKiAvLyBBdHRhY2hpbmcgdHdpY2Ugd2l0aCBzYW1lIElEIHJlcGxhY2VzIChubyBkb3VibGUtY291bnRpbmcpXG4gICAqIGV4ZWN1dG9yLmF0dGFjaFNjb3BlUmVjb3JkZXIobmV3IE1ldHJpY1JlY29yZGVyKCdteS1tZXRyaWNzJykpO1xuICAgKiBleGVjdXRvci5hdHRhY2hTY29wZVJlY29yZGVyKG5ldyBNZXRyaWNSZWNvcmRlcignbXktbWV0cmljcycpKTsgLy8gcmVwbGFjZXMgcHJldmlvdXNcbiAgICogYGBgXG4gICAqXG4gICAqICoqRGVsaXZlcnkgdGllciAoUkZDLTAwMSk6KiogcGFzcyBgeyBkZWxpdmVyeTogJ2RlZmVycmVkJyB9YCB0byB0YWtlIHRoZVxuICAgKiByZWNvcmRlciBvdXQgb2YgdGhlIGVuZ2luZSdzIGhvdCBwYXRoIOKAlCBldmVudHMgYXJlIGNhcHR1cmVkIGludG8gYVxuICAgKiBib3VuZGVkIHF1ZXVlIGFuZCBkZWxpdmVyZWQgYXQgdGhlIG5leHQgbWljcm90YXNrIGNoZWNrcG9pbnQgKFwib25lIGJlYXRcbiAgICogYmVoaW5kXCIpLiBPbWl0dGluZyBgZGVsaXZlcnlgIGtlZXBzIHRoZSBoaXN0b3JpY2FsIHN5bmNocm9ub3VzIGNhbGwsXG4gICAqIGJ5dGUtaWRlbnRpY2FsIHRvIHByZXZpb3VzIHJlbGVhc2VzLiBSZS1hdHRhY2hpbmcgdGhlIHNhbWUgYGlkYCB3aXRoIGFcbiAgICogZGlmZmVyZW50IHRpZXIgU1dBUFMgdGllcnMgY2xlYW5seSDigJQgbmV2ZXIgZG91YmxlIGRlbGl2ZXJ5LiBTZWVcbiAgICogYGRvY3MvZ3VpZGVzL29ic2VydmVycy1kZWZlcnJlZC5tZGAuXG4gICAqL1xuICBhdHRhY2hTY29wZVJlY29yZGVyKHJlY29yZGVyOiBTY29wZVJlY29yZGVyLCBvcHRpb25zPzogQXR0YWNoUmVjb3JkZXJPcHRpb25zKTogdm9pZCB7XG4gICAgLy8gVGllciBzd2FwLCBib3RoIGRpcmVjdGlvbnM6IGFuIGlkIGxpdmVzIG9uIGV4YWN0bHkgT05FIHRpZXIgcGVyIGxpc3QuXG4gICAgdGhpcy5zY29wZVJlY29yZGVycyA9IHRoaXMuc2NvcGVSZWNvcmRlcnMuZmlsdGVyKChyKSA9PiByLmlkICE9PSByZWNvcmRlci5pZCk7XG4gICAgaWYgKG9wdGlvbnM/LmRlbGl2ZXJ5ID09PSAnZGVmZXJyZWQnKSB7XG4gICAgICB0aGlzLmVuc3VyZURlZmVycmVkVGllcihvcHRpb25zKS5yZWdpc3RlcihyZWNvcmRlciwgeyBzY29wZTogdHJ1ZSB9LCBvcHRpb25zKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5kZWZlcnJlZFRpZXI/LnJlbW92ZUZyb21MaXN0cyhyZWNvcmRlci5pZCwgeyBzY29wZTogdHJ1ZSB9KTtcbiAgICB0aGlzLnNjb3BlUmVjb3JkZXJzLnB1c2gocmVjb3JkZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIExhemlseSBjcmVhdGUgdGhlIGV4ZWN1dG9yJ3MgT05FIGRlZmVycmVkLW9ic2VydmVyIHRpZXIgKG9uZSBtZXJnZWRcbiAgICogcXVldWUsIHRvdGFsIGV2ZW50IG9yZGVyIGFjcm9zcyBhbGwgdGhyZWUgY2hhbm5lbHMpLiBUaGUgRklSU1QgZGVmZXJyZWRcbiAgICogYXR0YWNoJ3Mgb3B0aW9ucyBjb25maWd1cmUgdGhlIGRpc3BhdGNoZXI7IGxhdGVyIGRpZmZlcmluZyBvcHRpb25zIGFyZVxuICAgKiBkZXYtd2FybmVkIGFuZCBpZ25vcmVkIChzZWUgYEF0dGFjaFJlY29yZGVyT3B0aW9uc2ApLlxuICAgKi9cbiAgcHJpdmF0ZSBlbnN1cmVEZWZlcnJlZFRpZXIob3B0aW9ucz86IEF0dGFjaFJlY29yZGVyT3B0aW9ucyk6IERlZmVycmVkT2JzZXJ2ZXJUaWVyIHtcbiAgICBpZiAoIXRoaXMuZGVmZXJyZWRUaWVyKSB0aGlzLmRlZmVycmVkVGllciA9IG5ldyBEZWZlcnJlZE9ic2VydmVyVGllcihvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5kZWZlcnJlZFRpZXI7XG4gIH1cblxuICAvLyDilIDilIDilIAgRGV0YWNoIChUNCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vXG4gIC8vIEJhcmUtZXhlY3V0b3IgZW50cnkgcG9pbnQgZm9yIGZpcmUtYW5kLWZvcmdldCBjaGlsZCBmbG93Y2hhcnQgZXhlY3V0aW9uLlxuICAvLyBVc2UgZnJvbSBvdXRzaWRlIGFueSBjaGFydCAoY29uc3VtZXIgY29kZSB0aGF0IHdhbnRzIHRvIGRldGFjaCB3b3JrXG4gIC8vIHdpdGhvdXQgZmlyc3QgcnVubmluZyBhIHBhcmVudCBjaGFydCkuIEZvciBkZXRhY2ggRlJPTSBJTlNJREUgYSBzdGFnZSxcbiAgLy8gdXNlIGBzY29wZS4kZGV0YWNoQW5kSm9pbkxhdGVyKC4uLilgIC8gYHNjb3BlLiRkZXRhY2hBbmRGb3JnZXQoLi4uKWAg4oCUXG4gIC8vIHRob3NlIG1pbnQgcmVmSWRzIGZyb20gdGhlIGNhbGxpbmcgc3RhZ2UncyBydW50aW1lU3RhZ2VJZCBmb3IgdHJhY2VcbiAgLy8gY29ycmVsYXRpb247IHRoZSBiYXJlLWV4ZWN1dG9yIGVudHJpZXMgdXNlIGEgc3ludGhldGljIHByZWZpeFxuICAvLyAoYF9fZXhlY3V0b3JfX2ApIGluc3RlYWQuXG5cbiAgLyoqXG4gICAqIERldGFjaCBhIGNoaWxkIGZsb3djaGFydCBvbiB0aGUgZ2l2ZW4gZHJpdmVyIGFuZCByZXR1cm4gYSBgRGV0YWNoSGFuZGxlYFxuICAgKiB0aGUgY2FsbGVyIGNhbiBgd2FpdCgpYCBvbiAoUHJvbWlzZSkgb3IgcmVhZCBgLnN0YXR1c2AgZnJvbSAoc3luYykuXG4gICAqXG4gICAqIFRoZSBkcml2ZXIgaXMgYSBSRVFVSVJFRCBmaXJzdCBhcmd1bWVudCDigJQgdGhlcmUgaXMgbm8gbGlicmFyeS1kZWZhdWx0LFxuICAgKiB0byBrZWVwIHRoZSBlbmdpbmUgZnJlZSBvZiBkcml2ZXIgaW1wb3J0cyBhbmQgdG8gbWFrZSB0aGUgY2hvaWNlIG9mXG4gICAqIHNjaGVkdWxpbmcgYWxnb3JpdGhtIGV4cGxpY2l0IGF0IHRoZSBjYWxsIHNpdGUuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogaW1wb3J0IHsgbWljcm90YXNrQmF0Y2hEcml2ZXIgfSBmcm9tICdmb290cHJpbnRqcy9kZXRhY2gnO1xuICAgKlxuICAgKiBjb25zdCBleGVjID0gbmV3IEZsb3dDaGFydEV4ZWN1dG9yKHBhcmVudENoYXJ0KTtcbiAgICogY29uc3QgaGFuZGxlID0gZXhlYy5kZXRhY2hBbmRKb2luTGF0ZXIobWljcm90YXNrQmF0Y2hEcml2ZXIsIHRlbGVtZXRyeUNoYXJ0LCB7IGV2ZW50OiAneCcgfSk7XG4gICAqIGF3YWl0IGhhbmRsZS53YWl0KCk7IC8vIG9wdGlvbmFsXG4gICAqIGBgYFxuICAgKi9cbiAgZGV0YWNoQW5kSm9pbkxhdGVyKFxuICAgIGRyaXZlcjogaW1wb3J0KCcuLi9kZXRhY2gvdHlwZXMuanMnKS5EZXRhY2hEcml2ZXIsXG4gICAgY2hpbGQ6IGltcG9ydCgnLi4vYnVpbGRlci90eXBlcy5qcycpLkZsb3dDaGFydCxcbiAgICBpbnB1dD86IHVua25vd24sXG4gICk6IGltcG9ydCgnLi4vZGV0YWNoL3R5cGVzLmpzJykuRGV0YWNoSGFuZGxlIHtcbiAgICByZXR1cm4gX2RldGFjaEFuZEpvaW5MYXRlcihkcml2ZXIsIGNoaWxkLCBpbnB1dCwgJ19fZXhlY3V0b3JfXycpO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGFjaCBhIGNoaWxkIGZsb3djaGFydCBvbiB0aGUgZ2l2ZW4gZHJpdmVyIGFuZCBESVNDQVJEIHRoZSBoYW5kbGUuXG4gICAqIFVzZSBmb3IgdGVsZW1ldHJ5IGV4cG9ydHMgLyBmaXJlLWFuZC1mb3JnZXQgc2lkZSBlZmZlY3RzIHdoZXJlIHRoZVxuICAgKiBjYWxsZXIgZG9lc24ndCBjYXJlIGFib3V0IHRoZSByZXN1bHQuXG4gICAqXG4gICAqIEVycm9ycyByYWlzZWQgYnkgdGhlIGNoaWxkIHN0aWxsIGxhbmQgb24gdGhlIChkaXNjYXJkZWQpIGhhbmRsZSDigJQgdGhleVxuICAgKiBnbyBzaWxlbnQgdW5sZXNzIHN1cmZhY2VkIHRocm91Z2ggYSByZWNvcmRlci4gRm9yIG9ic2VydmFibGUgZGV0YWNoLFxuICAgKiBwcmVmZXIgYGRldGFjaEFuZEpvaW5MYXRlcmAgYW5kIHN1cmZhY2UgZmFpbHVyZXMgdmlhIGAud2FpdCgpLmNhdGNoKClgLlxuICAgKi9cbiAgZGV0YWNoQW5kRm9yZ2V0KFxuICAgIGRyaXZlcjogaW1wb3J0KCcuLi9kZXRhY2gvdHlwZXMuanMnKS5EZXRhY2hEcml2ZXIsXG4gICAgY2hpbGQ6IGltcG9ydCgnLi4vYnVpbGRlci90eXBlcy5qcycpLkZsb3dDaGFydCxcbiAgICBpbnB1dD86IHVua25vd24sXG4gICk6IHZvaWQge1xuICAgIF9kZXRhY2hBbmRGb3JnZXQoZHJpdmVyLCBjaGlsZCwgaW5wdXQsICdfX2V4ZWN1dG9yX18nKTtcbiAgfVxuXG4gIC8qKiBEZXRhY2ggYWxsIHNjb3BlIFJlY29yZGVycyB3aXRoIHRoZSBnaXZlbiBJRCDigJQgYm90aCBkZWxpdmVyeSB0aWVycy4gKi9cbiAgZGV0YWNoU2NvcGVSZWNvcmRlcihpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zY29wZVJlY29yZGVycyA9IHRoaXMuc2NvcGVSZWNvcmRlcnMuZmlsdGVyKChyKSA9PiByLmlkICE9PSBpZCk7XG4gICAgdGhpcy5kZWZlcnJlZFRpZXI/LnJlbW92ZUZyb21MaXN0cyhpZCwgeyBzY29wZTogdHJ1ZSB9KTtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIGEgZGVmZW5zaXZlIGNvcHkgb2YgYXR0YWNoZWQgc2NvcGUgUmVjb3JkZXJzIChib3RoIHRpZXJzKS4gKi9cbiAgZ2V0U2NvcGVSZWNvcmRlcnMoKTogU2NvcGVSZWNvcmRlcltdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMuc2NvcGVSZWNvcmRlcnMsIC4uLih0aGlzLmRlZmVycmVkVGllcj8uc2NvcGVMaXN0UmVjb3JkZXJzKCkgPz8gW10pXTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBGbG93UmVjb3JkZXIgTWFuYWdlbWVudCDilIDilIDilIBcblxuICAvKipcbiAgICogQXR0YWNoIGEgRmxvd1JlY29yZGVyIHRvIG9ic2VydmUgY29udHJvbCBmbG93IGV2ZW50cy5cbiAgICogQXV0b21hdGljYWxseSBlbmFibGVzIG5hcnJhdGl2ZSBpZiBub3QgYWxyZWFkeSBlbmFibGVkLlxuICAgKiBNdXN0IGJlIGNhbGxlZCBiZWZvcmUgcnVuKCkg4oCUIHJlY29yZGVycyBhcmUgcGFzc2VkIHRvIHRoZSB0cmF2ZXJzZXIgYXQgY3JlYXRpb24gdGltZS5cbiAgICpcbiAgICogKipJZGVtcG90ZW50IGJ5IElEOioqIHJlcGxhY2VzIGV4aXN0aW5nIHJlY29yZGVyIHdpdGggc2FtZSBgaWRgLlxuICAgKlxuICAgKiAqKkRlbGl2ZXJ5IHRpZXIgKFJGQy0wMDEpOioqIHBhc3MgYHsgZGVsaXZlcnk6ICdkZWZlcnJlZCcgfWAgZm9yXG4gICAqIG5leHQtY2hlY2twb2ludCBkZWxpdmVyeSBvZmYgdGhlIGhvdCBwYXRoIOKAlCBzZWUgYGF0dGFjaFNjb3BlUmVjb3JkZXJgLlxuICAgKi9cbiAgYXR0YWNoRmxvd1JlY29yZGVyKHJlY29yZGVyOiBGbG93UmVjb3JkZXIsIG9wdGlvbnM/OiBBdHRhY2hSZWNvcmRlck9wdGlvbnMpOiB2b2lkIHtcbiAgICAvLyBUaWVyIHN3YXAsIGJvdGggZGlyZWN0aW9uczogYW4gaWQgbGl2ZXMgb24gZXhhY3RseSBPTkUgdGllciBwZXIgbGlzdC5cbiAgICB0aGlzLmZsb3dSZWNvcmRlcnMgPSB0aGlzLmZsb3dSZWNvcmRlcnMuZmlsdGVyKChyKSA9PiByLmlkICE9PSByZWNvcmRlci5pZCk7XG4gICAgdGhpcy5uYXJyYXRpdmVFbmFibGVkID0gdHJ1ZTtcbiAgICBpZiAob3B0aW9ucz8uZGVsaXZlcnkgPT09ICdkZWZlcnJlZCcpIHtcbiAgICAgIHRoaXMuZW5zdXJlRGVmZXJyZWRUaWVyKG9wdGlvbnMpLnJlZ2lzdGVyKHJlY29yZGVyLCB7IGZsb3c6IHRydWUgfSwgb3B0aW9ucyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuZGVmZXJyZWRUaWVyPy5yZW1vdmVGcm9tTGlzdHMocmVjb3JkZXIuaWQsIHsgZmxvdzogdHJ1ZSB9KTtcbiAgICB0aGlzLmZsb3dSZWNvcmRlcnMucHVzaChyZWNvcmRlcik7XG4gIH1cblxuICAvKiogRGV0YWNoIGFsbCBGbG93UmVjb3JkZXJzIHdpdGggdGhlIGdpdmVuIElEIOKAlCBib3RoIGRlbGl2ZXJ5IHRpZXJzLiAqL1xuICBkZXRhY2hGbG93UmVjb3JkZXIoaWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuZmxvd1JlY29yZGVycyA9IHRoaXMuZmxvd1JlY29yZGVycy5maWx0ZXIoKHIpID0+IHIuaWQgIT09IGlkKTtcbiAgICB0aGlzLmRlZmVycmVkVGllcj8ucmVtb3ZlRnJvbUxpc3RzKGlkLCB7IGZsb3c6IHRydWUgfSk7XG4gIH1cblxuICAvKiogUmV0dXJucyBhIGRlZmVuc2l2ZSBjb3B5IG9mIGF0dGFjaGVkIEZsb3dSZWNvcmRlcnMgKGJvdGggdGllcnMpLiAqL1xuICBnZXRGbG93UmVjb3JkZXJzKCk6IEZsb3dSZWNvcmRlcltdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMuZmxvd1JlY29yZGVycywgLi4uKHRoaXMuZGVmZXJyZWRUaWVyPy5mbG93TGlzdFJlY29yZGVycygpID8/IFtdKV07XG4gIH1cblxuICAvLyDilIDilIDilIAgQ29tYmluZWQgU2NvcGVSZWNvcmRlciBNYW5hZ2VtZW50IOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBBdHRhY2ggYSByZWNvcmRlciB0aGF0IG1heSBvYnNlcnZlIG11bHRpcGxlIGV2ZW50IHN0cmVhbXMgKHNjb3BlXG4gICAqIGRhdGEtZmxvdywgY29udHJvbC1mbG93LCBvciBib3RoKS4gRGV0ZWN0cyBhdCBydW50aW1lIHdoaWNoIHN0cmVhbXMgdGhlXG4gICAqIHJlY29yZGVyIGhhcyBtZXRob2RzIGZvciBhbmQgcm91dGVzIGl0IHRvIHRoZSBjb3JyZWN0IGludGVybmFsIGNoYW5uZWxzLlxuICAgKlxuICAgKiBQcmVmZXJyZWQgb3ZlciBjYWxsaW5nIGBhdHRhY2hTY29wZVJlY29yZGVyYCBhbmQgYGF0dGFjaEZsb3dSZWNvcmRlcmBcbiAgICogc2VwYXJhdGVseSwgYmVjYXVzZSBmb3JnZXR0aW5nIG9uZSBvZiB0aGUgdHdvIGlzIGEgc2lsZW50IGZvb3QtZ3VuIOKAlFxuICAgKiBoYWxmIHlvdXIgZXZlbnRzIG5ldmVyIGZpcmUgYW5kIHRoZXJlIGlzIG5vIHJ1bnRpbWUgd2FybmluZy4gV2l0aFxuICAgKiBgYXR0YWNoQ29tYmluZWRSZWNvcmRlcmAgdGhlIGxpYnJhcnkgZ3VhcmFudGVlcyB0aGUgcmVjb3JkZXIncyBkZWNsYXJlZFxuICAgKiBtZXRob2RzIGFsbCBmaXJlLCBhbmQgYWRkcyBubyBvdmVyaGVhZCB2ZXJzdXMgdHdvIGV4cGxpY2l0IGNhbGxzLlxuICAgKlxuICAgKiAjIyBJZGVtcG90ZW5jeVxuICAgKlxuICAgKiBJZGVtcG90ZW50IGJ5IGBpZGAgYWNyb3NzIEFMTCBjaGFubmVscyDigJQgcmUtYXR0YWNoaW5nIHdpdGggdGhlIHNhbWUgYGlkYFxuICAgKiByZXBsYWNlcyB0aGUgcHJldmlvdXMgaW5zdGFuY2UgZXZlcnl3aGVyZSBpdCB3YXMgcmVnaXN0ZXJlZC4gTWl4aW5nXG4gICAqIGBhdHRhY2hDb21iaW5lZFJlY29yZGVyKHgpYCB3aXRoIGEgcHJpb3IgYGF0dGFjaFNjb3BlUmVjb3JkZXIoeSlgIG9yXG4gICAqIGBhdHRhY2hGbG93UmVjb3JkZXIoeSlgIHRoYXQgc2hhcmUgYHguaWQgPT09IHkuaWRgIGlzIGFsc28gc2FmZTogdGhlXG4gICAqIGNvbWJpbmVkIGF0dGFjaCByZXBsYWNlcyB0aGUgc2luZ2xlLWNoYW5uZWwgcmVnaXN0cmF0aW9uIG9uIHdoaWNoZXZlclxuICAgKiBjaGFubmVsKHMpIGB4YCBoYXMgbWV0aG9kcyBmb3IuIE5vIGR1cGxpY2F0ZSBmaXJpbmdzIG9jY3VyLlxuICAgKlxuICAgKiAjIyBOYXJyYXRpdmUgYWN0aXZhdGlvblxuICAgKlxuICAgKiBJZiB0aGUgcmVjb3JkZXIgaGFzIGFueSBjb250cm9sLWZsb3cgbWV0aG9kcywgYGVuYWJsZU5hcnJhdGl2ZSgpYCBpc1xuICAgKiBjYWxsZWQgYXMgYSBzaWRlIGVmZmVjdCAodGhlIG5hcnJhdGl2ZSBzdWJzeXN0ZW0gaXMgcmVxdWlyZWQgdG8gZW1pdFxuICAgKiBjb250cm9sLWZsb3cgZXZlbnRzKS4gRGF0YS1mbG93LW9ubHkgcmVjb3JkZXJzIGRvIE5PVCBhY3RpdmF0ZSB0aGVcbiAgICogbmFycmF0aXZlLlxuICAgKlxuICAgKiAjIyBEZXRlY3Rpb24gcnVsZVxuICAgKlxuICAgKiBPbmx5ICoqb3duKiogZXZlbnQgbWV0aG9kcyBjb3VudCAoc2VlIGBoYXNSZWNvcmRlck1ldGhvZHNgKS4gTWV0aG9kc1xuICAgKiBpbmhlcml0ZWQgdmlhIHRoZSBwcm90b3R5cGUgY2hhaW4gYXJlIGlnbm9yZWQg4oCUIHRoaXMgcHJvdGVjdHMgYWdhaW5zdFxuICAgKiBhY2NpZGVudGFsIGBPYmplY3QucHJvdG90eXBlYCBwb2xsdXRpb24gYXR0YWNoaW5nIGhhbmRsZXJzIHlvdSBuZXZlclxuICAgKiBkZWNsYXJlZC4gQSByZWNvcmRlciB0aGF0IHByb3ZpZGVzIG9ubHkgYGNsZWFyYC9gdG9TbmFwc2hvdGAgaXMgYVxuICAgKiBuby1vcCBhbmQgZW1pdHMgYSBkZXYtbW9kZSB3YXJuaW5nIHRvIHN1cmZhY2UgdGhlIGxpa2VseSBtaXN0YWtlLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGF1ZGl0OiBDb21iaW5lZFJlY29yZGVyID0ge1xuICAgKiAgIGlkOiAnYXVkaXQnLFxuICAgKiAgIG9uV3JpdGU6IChlKSA9PiBsb2coJ3Njb3BlIHdyaXRlJywgZS5rZXkpLFxuICAgKiAgIG9uRGVjaXNpb246IChlKSA9PiBsb2coJ3JvdXRlZCB0bycsIGUuY2hvc2VuKSxcbiAgICogfTtcbiAgICogZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcihhdWRpdCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXR0YWNoQ29tYmluZWRSZWNvcmRlcihyZWNvcmRlcjogQ29tYmluZWRSZWNvcmRlciwgb3B0aW9ucz86IEF0dGFjaFJlY29yZGVyT3B0aW9ucyk6IHZvaWQge1xuICAgIGNvbnN0IGhhc0RhdGEgPSBoYXNSZWNvcmRlck1ldGhvZHMocmVjb3JkZXIpO1xuICAgIGNvbnN0IGhhc0Zsb3cgPSBoYXNGbG93UmVjb3JkZXJNZXRob2RzKHJlY29yZGVyKTtcbiAgICBjb25zdCBoYXNFbWl0ID0gaGFzRW1pdFJlY29yZGVyTWV0aG9kcyhyZWNvcmRlcik7XG5cbiAgICAvLyBEZWxpdmVyeSB0aWVyIChSRkMtMDAxKTogb3B0aW9ucyBiYWcgT1IgdGhlIHJlY29yZGVyJ3Mgb3duXG4gICAgLy8gYGRlbGl2ZXJ5OiAnZGVmZXJyZWQnYCBmaWVsZC4gVGhlIGZpZWxkIGlzIGEgc3RyaW5nIOKAlCBjaGFubmVsIHJvdXRpbmdcbiAgICAvLyBhYm92ZSBjb3VudHMgZXZlbnQtTUVUSE9EIHByb3BlcnRpZXMgb25seSwgc28gZGVjbGFyaW5nIGl0IG5ldmVyXG4gICAgLy8gY2hhbmdlcyB3aGljaCBjaGFubmVscyB0aGUgcmVjb3JkZXIgbGFuZHMgb24uXG4gICAgY29uc3QgZGVsaXZlcnkgPSBvcHRpb25zPy5kZWxpdmVyeSA/PyByZWNvcmRlci5kZWxpdmVyeTtcbiAgICBjb25zdCB0aWVyT3B0aW9uczogQXR0YWNoUmVjb3JkZXJPcHRpb25zIHwgdW5kZWZpbmVkID0gZGVsaXZlcnkgPT09IHVuZGVmaW5lZCA/IG9wdGlvbnMgOiB7IC4uLm9wdGlvbnMsIGRlbGl2ZXJ5IH07XG5cbiAgICAvLyBFbWl0IHJlY29yZGVycyBsaXZlIG9uIHRoZSBTQU1FIGNoYW5uZWwgYXMgZGF0YS1mbG93IHJlY29yZGVyc1xuICAgIC8vIChTY29wZUZhY2FkZSBpdGVyYXRlcyBgX3JlY29yZGVyc2AgZm9yIG9uRW1pdCBkaXNwYXRjaCkuIFNvXG4gICAgLy8gYXR0YWNoRW1pdFJlY29yZGVyIGludGVybmFsbHkgY2FsbHMgYXR0YWNoU2NvcGVSZWNvcmRlciDigJQgYnV0IHdlIHdhbnQgdG9cbiAgICAvLyBhdm9pZCBkb3VibGUtYXR0YWNoIHdoZW4gdGhlIHJlY29yZGVyIGltcGxlbWVudHMgQk9USCBvbkVtaXQgQU5EXG4gICAgLy8gb3RoZXIgU2NvcGVSZWNvcmRlciBtZXRob2RzLiBTaG9ydC1jaXJjdWl0OiBpZiBoYXNEYXRhIE9SIGhhc0VtaXQsIHRoZVxuICAgIC8vIHJlY29yZGVyIGxhbmRzIG9uIHRoZSBzY29wZS1yZWNvcmRlciBsaXN0IGV4YWN0bHkgb25jZS5cbiAgICBpZiAoaGFzRGF0YSB8fCBoYXNFbWl0KSB0aGlzLmF0dGFjaFNjb3BlUmVjb3JkZXIocmVjb3JkZXIgYXMgU2NvcGVSZWNvcmRlciwgdGllck9wdGlvbnMpO1xuICAgIGlmIChoYXNGbG93KSB0aGlzLmF0dGFjaEZsb3dSZWNvcmRlcihyZWNvcmRlciBhcyBGbG93UmVjb3JkZXIsIHRpZXJPcHRpb25zKTtcblxuICAgIGlmICghaGFzRGF0YSAmJiAhaGFzRmxvdyAmJiAhaGFzRW1pdCAmJiBpc0Rldk1vZGUoKSkge1xuICAgICAgLy8gRGV2LW1vZGUgb25seTogc2lsZW50IHNraXBzIGFyZSBpbnZpc2libGUgYW5kIHByb2R1Y2UgaGFyZC10by1kZWJ1Z1xuICAgICAgLy8gXCJ3aHkgZGlkbid0IG15IHJlY29yZGVyIGZpcmVcIiByZXBvcnRzLiBQZXIgbGlicmFyeSBjb252ZW50aW9uLCBnYXRlZFxuICAgICAgLy8gb24gdGhlIGNlbnRyYWwgaXNEZXZNb2RlKCkgZmxhZyAobm90IHByb2Nlc3MuZW52KSBzbyBjb25zdW1lcnMgY2FuXG4gICAgICAvLyBjb250cm9sIGRldiB0b29saW5nIGNlbnRyYWxseSB2aWEgZW5hYmxlRGV2TW9kZSgpL2Rpc2FibGVEZXZNb2RlKCkuXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgW2Zvb3RwcmludGpzXSBhdHRhY2hDb21iaW5lZFJlY29yZGVyOiByZWNvcmRlciAnJHtyZWNvcmRlci5pZH0nIGhhcyBgICtcbiAgICAgICAgICAnbm8gb2JzZXJ2ZXIgZXZlbnQgbWV0aG9kcyDigJQgbm90aGluZyB0byBhdHRhY2guIERpZCB5b3UgZm9yZ2V0IHRvICcgK1xuICAgICAgICAgICdhZGQgYW4gb24qIGhhbmRsZXIgKG9uV3JpdGUsIG9uRGVjaXNpb24sIG9uU3ViZmxvd0VudHJ5LCAuLi4pPyAnICtcbiAgICAgICAgICAnTm90ZTogb25seSBPV04gcHJvcGVydGllcyBjb3VudDsgbWV0aG9kcyBvbiB0aGUgcHJvdG90eXBlIGNoYWluICcgK1xuICAgICAgICAgICdhcmUgaWdub3JlZCBvbiBwdXJwb3NlLicsXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRhY2ggYSBjb21iaW5lZCByZWNvcmRlciBmcm9tIGFsbCBjaGFubmVscyBpdCB3YXMgYXR0YWNoZWQgdG8uXG4gICAqIFNhZmUgdG8gY2FsbCBpZiB0aGUgcmVjb3JkZXIgd2FzIG9ubHkgb24gb25lIGNoYW5uZWwgb3IgbmV2ZXIgYXR0YWNoZWQuXG4gICAqL1xuICBkZXRhY2hDb21iaW5lZFJlY29yZGVyKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmRldGFjaFNjb3BlUmVjb3JkZXIoaWQpO1xuICAgIHRoaXMuZGV0YWNoRmxvd1JlY29yZGVyKGlkKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBFbWl0IFNjb3BlUmVjb3JkZXIgTWFuYWdlbWVudCAoUGhhc2UgMykg4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIEF0dGFjaCBhbiBgRW1pdFJlY29yZGVyYCDigJQgYW4gb2JzZXJ2ZXIgZm9yIGNvbnN1bWVyLWVtaXR0ZWQgc3RydWN0dXJlZFxuICAgKiBldmVudHMgZmlyZWQgdmlhIGBzY29wZS4kZW1pdChuYW1lLCBwYXlsb2FkKWAuXG4gICAqXG4gICAqIEludGVybmFsbHksIGVtaXQgcmVjb3JkZXJzIHNoYXJlIHRoZSBzY29wZS1yZWNvcmRlciBjaGFubmVsIGJlY2F1c2VcbiAgICogZW1pdCBldmVudHMgZmlyZSBmcm9tIGluc2lkZSBgU2NvcGVGYWNhZGVgIGR1cmluZyBzdGFnZSBleGVjdXRpb24sXG4gICAqIHNhbWUgdGltaW5nIGFzIGBvblJlYWRgL2BvbldyaXRlYC4gVGhpcyBtZXRob2QgaXMgYSBjb252ZW5pZW5jZSB0aGF0XG4gICAqIGRlbGVnYXRlcyB0byBgYXR0YWNoU2NvcGVSZWNvcmRlcmAg4oCUIGNvbnN1bWVycyBjYW4gYWxzbyB1c2VcbiAgICogYGF0dGFjaFNjb3BlUmVjb3JkZXJgIGRpcmVjdGx5IGZvciBhIHJlY29yZGVyIHRoYXQgaW1wbGVtZW50cyBCT1RIXG4gICAqIGBvbldyaXRlYCBhbmQgYG9uRW1pdGAuIEVpdGhlciBhcHByb2FjaCBwbGFjZXMgdGhlIHJlY29yZGVyIG9uIHRoZVxuICAgKiBzYW1lIHVuZGVybHlpbmcgbGlzdCwgc28gYG9uRW1pdGAgZmlyZXMgZXhhY3RseSBvbmNlIHBlciBldmVudC5cbiAgICpcbiAgICogKipJZGVtcG90ZW50IGJ5IGBpZGA6KiogcmVwbGFjZXMgZXhpc3RpbmcgcmVjb3JkZXIgd2l0aCBzYW1lIGBpZGAuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogZXhlY3V0b3IuYXR0YWNoRW1pdFJlY29yZGVyKHtcbiAgICogICBpZDogJ3Rva2VuLW1ldGVyJyxcbiAgICogICBvbkVtaXQ6IChlKSA9PiB7XG4gICAqICAgICBpZiAoZS5uYW1lID09PSAnYWdlbnRmb290cHJpbnQubGxtLnRva2VucycpIHRyYWNrVG9rZW5zKGUucGF5bG9hZCk7XG4gICAqICAgfSxcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXR0YWNoRW1pdFJlY29yZGVyKHJlY29yZGVyOiBFbWl0UmVjb3JkZXIsIG9wdGlvbnM/OiBBdHRhY2hSZWNvcmRlck9wdGlvbnMpOiB2b2lkIHtcbiAgICB0aGlzLmF0dGFjaFNjb3BlUmVjb3JkZXIocmVjb3JkZXIgYXMgU2NvcGVSZWNvcmRlciwgb3B0aW9ucyk7XG4gIH1cblxuICAvKiogRGV0YWNoIGFuIGBFbWl0UmVjb3JkZXJgIGJ5IGlkLiBTYWZlIHRvIGNhbGwgaWYgbmV2ZXIgYXR0YWNoZWQuICovXG4gIGRldGFjaEVtaXRSZWNvcmRlcihpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5kZXRhY2hTY29wZVJlY29yZGVyKGlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgZGVmZW5zaXZlIGNvcHkgb2YgYXR0YWNoZWQgcmVjb3JkZXJzIChib3RoIGRlbGl2ZXJ5IHRpZXJzKVxuICAgKiBmaWx0ZXJlZCB0byB0aG9zZSB0aGF0IGltcGxlbWVudCBgb25FbWl0YC4gVXNlZnVsIGZvciBpbnNwZWN0aW9uIGR1cmluZ1xuICAgKiB0ZXN0aW5nLlxuICAgKi9cbiAgZ2V0RW1pdFJlY29yZGVycygpOiBFbWl0UmVjb3JkZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U2NvcGVSZWNvcmRlcnMoKS5maWx0ZXIoXG4gICAgICAocik6IHIgaXMgRW1pdFJlY29yZGVyID0+IHR5cGVvZiAociBhcyB7IG9uRW1pdD86IHVua25vd24gfSkub25FbWl0ID09PSAnZnVuY3Rpb24nLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzdHJ1Y3R1cmVkIG5hcnJhdGl2ZSBlbnRyaWVzIOKAlCB0aGUgc2luZ2xlIHB1YmxpYyBuYXJyYXRpdmUgQVBJLlxuICAgKiBFYWNoIGVudHJ5IGhhcyBhIHR5cGUgKHN0YWdlLCBzdGVwLCBjb25kaXRpb24sIGZvcmssIGV0Yy4pLCB0ZXh0LCBhbmRcbiAgICogZGVwdGguIENvbnN1bWVycyByZW5kZXIgaG93ZXZlciB0aGV5IHdhbnQ7IGNhbGwgYC5tYXAoZSA9PiBlLnRleHQpYFxuICAgKiBpZiBhIGZsYXQgYHN0cmluZ1tdYCBpcyBuZWVkZWQgbG9jYWxseS5cbiAgICovXG4gIGdldE5hcnJhdGl2ZUVudHJpZXMoKTogQ29tYmluZWROYXJyYXRpdmVFbnRyeVtdIHtcbiAgICBpZiAodGhpcy5jb21iaW5lZFJlY29yZGVyKSB7XG4gICAgICByZXR1cm4gdGhpcy5jb21iaW5lZFJlY29yZGVyLmdldEVudHJpZXMoKTtcbiAgICB9XG4gICAgY29uc3QgZmxvd1NlbnRlbmNlcyA9IHRoaXMudHJhdmVyc2VyLmdldE5hcnJhdGl2ZSgpO1xuICAgIHJldHVybiBmbG93U2VudGVuY2VzLm1hcCgodGV4dCkgPT4gKHsgdHlwZTogJ3N0YWdlJyBhcyBjb25zdCwgdGV4dCwgZGVwdGg6IDAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGNvbWJpbmVkIEZsb3dSZWNvcmRlcnMgbGlzdC4gV2hlbiBuYXJyYXRpdmUgaXMgZW5hYmxlZCxcbiAgICogaW5jbHVkZXMgdGhlIENvbWJpbmVkTmFycmF0aXZlUmVjb3JkZXIgKHdoaWNoIGJ1aWxkcyBtZXJnZWQgZmxvdytkYXRhXG4gICAqIGVudHJpZXMgaW5saW5lKS4gUGx1cyBhbnkgdXNlci1hdHRhY2hlZCByZWNvcmRlcnMuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkRmxvd1JlY29yZGVyc0xpc3QoKTogRmxvd1JlY29yZGVyW10gfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHJlY29yZGVyczogRmxvd1JlY29yZGVyW10gPSBbXTtcbiAgICBpZiAodGhpcy5jb21iaW5lZFJlY29yZGVyKSB7XG4gICAgICByZWNvcmRlcnMucHVzaCh0aGlzLmNvbWJpbmVkUmVjb3JkZXIpO1xuICAgIH1cbiAgICByZWNvcmRlcnMucHVzaCguLi50aGlzLmZsb3dSZWNvcmRlcnMpO1xuICAgIC8vIERlZmVycmVkLW9ic2VydmVyIGZsb3cgdGFwIChSRkMtMDAxIEJsb2NrIDcpIOKAlCBjYXB0dXJlcyBldmVyeSBmbG93XG4gICAgLy8gZXZlbnQgZm9yIGRlZmVycmVkIGxpc3RlbmVycy4gQXBwZW5kZWQgbGlrZSBhbnkgb3RoZXIgZmxvdyByZWNvcmRlcixcbiAgICAvLyBzbyB0aGUgRmxvd1JlY29yZGVyRGlzcGF0Y2hlciBzaXRlIG5lZWRzIG5vIHRpZXIgbG9naWMgb2YgaXRzIG93bi5cbiAgICBjb25zdCBmbG93VGFwID0gdGhpcy5kZWZlcnJlZFRpZXI/LmJ1aWxkRmxvd1RhcCgpO1xuICAgIGlmIChmbG93VGFwKSByZWNvcmRlcnMucHVzaChmbG93VGFwKTtcbiAgICByZXR1cm4gcmVjb3JkZXJzLmxlbmd0aCA+IDAgPyByZWNvcmRlcnMgOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSB0aGUgY2hhcnQuIFJlc29sdmVzIHdoZW4gdGhlIHJ1biBmaW5pc2hlcyDigJQgb3IgcGF1c2VzLCBpZiBhXG4gICAqIHBhdXNhYmxlIHN0YWdlIHJldHVybmVkIGRhdGEgKGNoZWNrIGBpc1BhdXNlZCgpYCBhZnRlcndhcmQpLlxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyBgeyBpbnB1dCwgZW52IH1gIOKAlCBgaW5wdXRgIGlzIHRoZSBmcm96ZW4gYnVzaW5lc3MgaW5wdXRcbiAgICogICAocmVhZCBpbiBhIHN0YWdlIHZpYSBgc2NvcGUuJGdldEFyZ3MoKWApOyBgZW52YCBpcyBpbmZyYXN0cnVjdHVyZSBjb250ZXh0XG4gICAqICAgbGlrZSBgeyBzaWduYWwsIHRpbWVvdXRNcywgdHJhY2VJZCB9YCAocmVhZCB2aWEgYHNjb3BlLiRnZXRFbnYoKWApLlxuICAgKlxuICAgKiBBZnRlciBpdCByZXNvbHZlcywgcmVhZCByZXN1bHRzIG9mZiB0aGUgZXhlY3V0b3I6XG4gICAqIC0gYGdldFNuYXBzaG90KClgIOKAlCBmdWxsIHN0YXRlLCBjb21taXQgbG9nLCBleGVjdXRpb24gdHJlZS5cbiAgICogLSBgZ2V0TmFycmF0aXZlRW50cmllcygpYCDigJQgdGhlIHBsYWluLUVuZ2xpc2ggdHJhY2UgKGNhbGwgYGVuYWJsZU5hcnJhdGl2ZSgpYFxuICAgKiAgIG9yIGF0dGFjaCBhIGBuYXJyYXRpdmUoKWAgcmVjb3JkZXIgZmlyc3QpLlxuICAgKiAtIGBpc1BhdXNlZCgpYCDigJQgdHJ1ZSBpZiBhIHN0YWdlIHBhdXNlZDsgdGhlbiB1c2UgYGdldENoZWNrcG9pbnQoKWAgLyBgcmVzdW1lKClgLlxuICAgKlxuICAgKiBPbmUgcnVuIGF0IGEgdGltZSBwZXIgZXhlY3V0b3Ig4oCUIGl0IGhvbGRzIHBlci1ydW4gc3RhdGUgKHJ1bklkLCByZWNvcmRlcnMsXG4gICAqIGNoZWNrcG9pbnQpLiBDcmVhdGUgb25lIGV4ZWN1dG9yIHBlciBjb25jdXJyZW50IHJ1bi5cbiAgICovXG4gIGFzeW5jIHJ1bihvcHRpb25zPzogUnVuT3B0aW9ucyk6IFByb21pc2U8RXhlY3V0b3JSZXN1bHQ+IHtcbiAgICAvLyBSZS1lbnRyYW5jeSBndWFyZCBGSVJTVCDigJQgYmVmb3JlIGNsZWFyaW5nIHJlY29yZGVycyBvciB0b3VjaGluZyBhbnlcbiAgICAvLyBwZXItcnVuIGZpZWxkLCBzbyBhIHJlamVjdGVkIGNvbmN1cnJlbnQgY2FsbCBsZWF2ZXMgdGhlIGluLWZsaWdodCBydW5cbiAgICAvLyBjb21wbGV0ZWx5IHVudG91Y2hlZC5cbiAgICBpZiAodGhpcy5faXNFeGVjdXRpbmcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0Zsb3dDaGFydEV4ZWN1dG9yOiBydW4oKSBjYWxsZWQgd2hpbGUgYW5vdGhlciBydW4oKS9yZXN1bWUoKSBpcyBpbiBmbGlnaHQgb24gdGhpcyAnICtcbiAgICAgICAgICAnZXhlY3V0b3IuIEFuIGV4ZWN1dG9yIGhvbGRzIHBlci1ydW4gc3RhdGUgKHJ1bklkLCByZWNvcmRlcnMsIGNoZWNrcG9pbnQpIOKAlCBjcmVhdGUgJyArXG4gICAgICAgICAgJ29uZSBleGVjdXRvciBwZXIgY29uY3VycmVudCBydW4uIFNlZSBkb2NzL2d1aWRlcy9leGVjdXRpb24tbW9kZWwubWQuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIFZhbGlkYXRlIGlucHV0IGFnYWluc3QgaW5wdXRTY2hlbWEgaWYgYm90aCBhcmUgcHJlc2VudC4gVmFsaWRhdGlvbiBydW5zXG4gICAgLy8gQkVGT1JFIHRoZSB0aW1lb3V0IHRpbWVyIGlzIGNyZWF0ZWQgc28gYSByZWplY3RlZCBpbnB1dCBjYW4ndCBsZWFrIGFcbiAgICAvLyBwZW5kaW5nIHRpbWVyIChzYW1lIFwiZmFpbGVkIGVudHJ5IGxlYXZlcyBubyBzaWRlIGVmZmVjdHNcIiBydWxlIGFzIHRoZVxuICAgIC8vIHJlLWVudHJhbmN5IGd1YXJkIGFib3ZlKS5cbiAgICBsZXQgdmFsaWRhdGVkSW5wdXQgPSBvcHRpb25zPy5pbnB1dDtcbiAgICBpZiAodmFsaWRhdGVkSW5wdXQgJiYgdGhpcy5mbG93Q2hhcnRBcmdzLmZsb3dDaGFydC5pbnB1dFNjaGVtYSkge1xuICAgICAgdmFsaWRhdGVkSW5wdXQgPSB2YWxpZGF0ZUlucHV0KHRoaXMuZmxvd0NoYXJ0QXJncy5mbG93Q2hhcnQuaW5wdXRTY2hlbWEsIHZhbGlkYXRlZElucHV0KTtcbiAgICB9XG5cbiAgICBsZXQgc2lnbmFsID0gb3B0aW9ucz8uc2lnbmFsO1xuICAgIGxldCB0aW1lb3V0SWQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuXG4gICAgLy8gQ3JlYXRlIGFuIGludGVybmFsIEFib3J0Q29udHJvbGxlciBmb3IgdGltZW91dE1zXG4gICAgaWYgKG9wdGlvbnM/LnRpbWVvdXRNcyAmJiAhc2lnbmFsKSB7XG4gICAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgICAgc2lnbmFsID0gY29udHJvbGxlci5zaWduYWw7XG4gICAgICB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiBjb250cm9sbGVyLmFib3J0KG5ldyBFcnJvcihgRXhlY3V0aW9uIHRpbWVkIG91dCBhZnRlciAke29wdGlvbnMudGltZW91dE1zfW1zYCkpLFxuICAgICAgICBvcHRpb25zLnRpbWVvdXRNcyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gVXNlci1hdHRhY2hlZCByZWNvcmRlcnMgKGZsb3dSZWNvcmRlcnMgKyBzY29wZVJlY29yZGVycykgYXJlIGNsZWFyZWQgdmlhIGNsZWFyKCkgdG8gcHJldmVudFxuICAgIC8vIGNyb3NzLXJ1biBhY2N1bXVsYXRpb24uIFRoZSBjb21iaW5lZFJlY29yZGVyIGlzIE5PVCBjbGVhcmVkIGhlcmUg4oCUIGNyZWF0ZVRyYXZlcnNlcigpIGFsd2F5c1xuICAgIC8vIGNyZWF0ZXMgYSBmcmVzaCBDb21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyIGluc3RhbmNlIG9uIGVhY2ggcnVuLCBzbyBzdGFsZSBzdGF0ZSBpcyBuZXZlciBhbiBpc3N1ZS5cbiAgICBmb3IgKGNvbnN0IHIgb2YgdGhpcy5mbG93UmVjb3JkZXJzKSB7XG4gICAgICByLmNsZWFyPy4oKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCByIG9mIHRoaXMuc2NvcGVSZWNvcmRlcnMpIHtcbiAgICAgIHIuY2xlYXI/LigpO1xuICAgIH1cbiAgICB0aGlzLmRlZmVycmVkVGllcj8uY2xlYXJSZWNvcmRlcnMoKTtcblxuICAgIHRoaXMubGFzdENoZWNrcG9pbnQgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5fZXhlY3V0aW9uQ291bnRlciA9IHsgdmFsdWU6IDAgfTsgLy8gUmVzZXQgY291bnRlciBvbiBmcmVzaCBydW5cbiAgICB0aGlzLl92aXNpdENvdW50cyA9IG5ldyBNYXAoKTsgLy8gUmVzZXQgbG9vcC1pdGVyYXRpb24gY291bnRzIG9uIGZyZXNoIHJ1biAodHdpbiBvZiBfZXhlY3V0aW9uQ291bnRlcilcbiAgICB0aGlzLl9jdXJyZW50UnVuSWQgPSBnZW5lcmF0ZVJ1bklkKCk7IC8vIEZyZXNoIHJ1bklkIHBlciBydW4oKSBjYWxsXG4gICAgdGhpcy5faGFzUnVuQmVmb3JlID0gdHJ1ZTsgLy8gbWFyayBzbyBhIGxhdGVyIHJlc3VtZSgpIHRha2VzIHRoZVxuICAgIC8vIHNhbWUtZXhlY3V0b3IgYnJhbmNoIChyZXVzZSBydW50aW1lLCBhY2N1bXVsYXRlIGV4ZWN1dGlvbiB0cmVlKS5cbiAgICB0aGlzLnRyYXZlcnNlciA9IHRoaXMuY3JlYXRlVHJhdmVyc2VyKFxuICAgICAgc2lnbmFsLFxuICAgICAgdmFsaWRhdGVkSW5wdXQsXG4gICAgICBvcHRpb25zPy5lbnYsXG4gICAgICBvcHRpb25zPy5tYXhEZXB0aCxcbiAgICAgIG9wdGlvbnM/Lm1heEl0ZXJhdGlvbnMsXG4gICAgKTtcbiAgICAvLyBTZXQgQUZURVIgYWxsIHN5bmMgdmFsaWRhdGlvbiB0aHJvd3MgKG5vdGhpbmcgYWJvdmUgY2FuIGxlYWsgdGhlIGZsYWcpO1xuICAgIC8vIG5vIGF3YWl0IGJldHdlZW4gdGhlIHRvcC1vZi1tZXRob2QgY2hlY2sgYW5kIGhlcmUsIHNvIHRoaXMgaXMgcmFjZS1mcmVlLlxuICAgIHRoaXMuX2lzRXhlY3V0aW5nID0gdHJ1ZTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy50cmF2ZXJzZXIuZXhlY3V0ZSgpO1xuICAgICAgLy8gVGVybWluYWwgZmx1c2ggKFJGQy0wMDEgQmxvY2sgOCkgYXQgdGhlIFJFU09MVkUgYm91bmRhcnk6IGV2ZXJ5XG4gICAgICAvLyBjYXB0dXJlZC1idXQtdW5kZWxpdmVyZWQgb2JzZXJ2ZXIgZXZlbnQgaXMgZGVsaXZlcmVkIHN5bmNocm9ub3VzbHlcbiAgICAgIC8vIGJlZm9yZSBydW4oKSByZXR1cm5zIOKAlCBcIm9uZSBiZWF0IGJlaGluZFwiIG5ldmVyIGJlY29tZXMgXCJsb3N0IGF0IGV4aXRcIi5cbiAgICAgIHRoaXMuZGVmZXJyZWRUaWVyPy50ZXJtaW5hbEZsdXNoKCk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICAvLyBUZXJtaW5hbCBmbHVzaCBhdCB0aGUgUEFVU0UgYW5kIFJFSkVDVCBib3VuZGFyaWVzIOKAlCB0aGlzIGlzIHRoZVxuICAgICAgLy8gT1VURVJNT1NUIGhhbmRsZXIgKGEgcGF1c2UgcmUtdGhyb3dzIHRocm91Z2ggc3ViZmxvdyB0cmF2ZXJzZXJzXG4gICAgICAvLyB3aXRob3V0IGV4aXQgZXZlbnRzLCBzbyBwZXItdHJhdmVyc2VyIGhvb2tzIHdvdWxkIG1pc3MgaXQpLiBSdW5zXG4gICAgICAvLyBiZWZvcmUgdGhlIGNoZWNrcG9pbnQgaXMgZXhwb3NlZCBhbmQgYmVmb3JlIHRoZSBlcnJvciByZWFjaGVzIHRoZVxuICAgICAgLy8gY2FsbGVyLlxuICAgICAgdGhpcy5kZWZlcnJlZFRpZXI/LnRlcm1pbmFsRmx1c2goKTtcbiAgICAgIGlmIChpc1BhdXNlU2lnbmFsKGVycm9yKSkge1xuICAgICAgICAvLyBCdWlsZCBhIGRldGFjaGVkIGNoZWNrcG9pbnQgZnJvbSBjdXJyZW50IGV4ZWN1dGlvbiBzdGF0ZSDigJQgc2VlXG4gICAgICAgIC8vIGJ1aWxkUGF1c2VDaGVja3BvaW50KCkgZm9yIHRoZSBkZWVwLWNvcHkgcmF0aW9uYWxlLlxuICAgICAgICB0aGlzLmxhc3RDaGVja3BvaW50ID0gdGhpcy5idWlsZFBhdXNlQ2hlY2twb2ludChlcnJvcik7XG4gICAgICAgIC8vIFJldHVybiBhIFBhdXNlUmVzdWx0LXNoYXBlZCB2YWx1ZSBzbyBjYWxsZXJzIGNhbiBjaGVjayB3aXRob3V0IHRyeS9jYXRjaFxuICAgICAgICByZXR1cm4geyBwYXVzZWQ6IHRydWUsIGNoZWNrcG9pbnQ6IHRoaXMubGFzdENoZWNrcG9pbnQgfSBzYXRpc2ZpZXMgUGF1c2VkUmVzdWx0O1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuX2lzRXhlY3V0aW5nID0gZmFsc2U7XG4gICAgICBpZiAodGltZW91dElkICE9PSB1bmRlZmluZWQpIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGbHVzaCB0aGUgZGVmZXJyZWQtb2JzZXJ2ZXIgYmFja2xvZywgdGhlbiBhd2FpdCBhc3luYyBsaXN0ZW5lclxuICAgKiBjb21wbGV0aW9ucyB1bmRlciBhIGRlYWRsaW5lIChSRkMtMDAxIEJsb2NrIDgg4oCUIHRoZSBzZXJ2ZXJsZXNzIC9cbiAgICogZ3JhY2VmdWwtc2h1dGRvd24gcGF0dGVybjogY2FsbCBiZWZvcmUgdGhlIHByb2Nlc3MgZnJlZXplcyBvciBleGl0cyBzb1xuICAgKiBcIm9uZSBiZWF0IGJlaGluZFwiIHdvcmsgaXMgbm90IGxvc3QpLiBSZXNvbHZlcyBpbW1lZGlhdGVseSB3aXRoIHplcm9zXG4gICAqIHdoZW4gbm8gZGVmZXJyZWQgb2JzZXJ2ZXIgd2FzIGV2ZXIgYXR0YWNoZWQuIGBwZW5kaW5nID09PSAwYCBtZWFucyBhXG4gICAqIGZ1bGwgZHJhaW47IGEgbm9uLXplcm8gYHBlbmRpbmdgIHJlcG9ydHMgY29udGludWF0aW9ucyAocGx1cyBhbnkgcXVldWVkXG4gICAqIGV2ZW50cykgc3RpbGwgb3V0c3RhbmRpbmcgYXQgdGhlIGRlYWRsaW5lIOKAlCBob25lc3QsIG5ldmVyIHNpbGVudC5cbiAgICovXG4gIGRyYWluT2JzZXJ2ZXJzKG9wdHM/OiB7IHRpbWVvdXRNcz86IG51bWJlciB9KTogUHJvbWlzZTxPYnNlcnZlckRyYWluUmVzdWx0PiB7XG4gICAgaWYgKCF0aGlzLmRlZmVycmVkVGllcikgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7IGRvbmU6IDAsIGZhaWxlZDogMCwgcGVuZGluZzogMCB9KTtcbiAgICByZXR1cm4gdGhpcy5kZWZlcnJlZFRpZXIuZHJhaW4ob3B0cyk7XG4gIH1cblxuICAvLyDilIDilIDilIAgSW50cm9zcGVjdGlvbiDilIDilIDilIBcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcnVudGltZSBzbmFwc2hvdC5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMucmVkYWN0ICBXaGVuIGB0cnVlYCwgYHNoYXJlZFN0YXRlYCBjb21lcyBmcm9tIHRoZSBwYXJhbGxlbFxuICAgKiAgIHJlZGFjdGVkIG1pcnJvciAoaWYgbWFpbnRhaW5lZCDigJQgc2VlIGBzZXRSZWRhY3Rpb25Qb2xpY3lgKS4gVGhpcyBpc1xuICAgKiAgIHRoZSBzYWZlIHZpZXcgZm9yIGV4cG9ydGluZyB0cmFjZXMgZXh0ZXJuYWxseSAocGFzdGUgaW50byBhIHZpZXdlcixcbiAgICogICBzaGFyZSB3aXRoIHN1cHBvcnQpLiBXaGVuIG5vIHJlZGFjdGlvbiBwb2xpY3kgaXMgY29uZmlndXJlZCB0aGVcbiAgICogICByZWRhY3RlZCBtaXJyb3IgaXMgbm90IG1haW50YWluZWQsIHNvIHRoaXMgZmxhZyBpcyBhIG5vLW9wIOKAlFxuICAgKiAgIGBzaGFyZWRTdGF0ZWAgaXMgdGhlIHJhdyB3b3JraW5nIG1lbW9yeSBlaXRoZXIgd2F5LiBEZWZhdWx0IGBmYWxzZWAuXG4gICAqXG4gICAqICAgVGhlIGNvbW1pdCBsb2cgaXMgYWxyZWFkeSByZWRhY3RlZCBhdCB3cml0ZS10aW1lIHJlZ2FyZGxlc3Mgb2YgdGhpc1xuICAgKiAgIGZsYWcsIGFuZCB0aGUgZXhlY3V0aW9uIHRyZWUgY2FycmllcyBvbmx5IHN0cnVjdHVyYWwgbWV0YWRhdGEuXG4gICAqICAgYHN1YmZsb3dSZXN1bHRzWypdLnRyZWVDb250ZXh0Lmdsb2JhbENvbnRleHRgIGZvbGxvd3MgdGhlIGZsYWcgdG9vXG4gICAqICAgKDkuMjAuMCk6IHVuZGVyIGByZWRhY3Q6IHRydWVgIGl0IGlzIGVhY2ggc3ViZmxvdydzIG93biByZWRhY3RlZFxuICAgKiAgIG1pcnJvcjsgcGxhaW4sIHRoZSBzdWJmbG93J3MgbGl2ZSBoZWFwLlxuICAgKlxuICAgKiAqKlRyZWF0IGBzaGFyZWRTdGF0ZWAgYXMgUkVBRC1PTkxZLioqIEluIHByb2R1Y3Rpb24gaXQgaXMgYSBsaXZlIHZpZXcgb2ZcbiAgICogdGhlIGVuZ2luZSdzIHdvcmtpbmcgbWVtb3J5ICh6ZXJvIGNvcHkgY29zdCkg4oCUIG11dGF0aW5nIGl0IGNvcnJ1cHRzXG4gICAqIGVuZ2luZSBzdGF0ZS4gSW4gZGV2IG1vZGUgKGBlbmFibGVEZXZNb2RlKClgKSBpdCBpcyBhIGRlZXAtZnJvemVuIENMT05FLFxuICAgKiBzbyBhbnkgY29uc3VtZXIgbXV0YXRpb24gdGhyb3dzIGxvdWRseSBpbnN0ZWFkIG9mIGNvcnJ1cHRpbmcgc2lsZW50bHkuXG4gICAqL1xuICBnZXRTbmFwc2hvdChvcHRpb25zPzogeyByZWRhY3Q/OiBib29sZWFuIH0pOiBSdW50aW1lU25hcHNob3Qge1xuICAgIGNvbnN0IHNuYXBzaG90ID0gdGhpcy50cmF2ZXJzZXIuZ2V0U25hcHNob3Qob3B0aW9ucykgYXMgUnVudGltZVNuYXBzaG90O1xuICAgIGlmIChpc0Rldk1vZGUoKSkge1xuICAgICAgLy8gRGV2LW1vZGUgbXV0YXRpb24gZ3VhcmQ6IGZyZWV6ZSBhIENMT05FLCBuZXZlciB0aGUgbGl2ZSBlbmdpbmVcbiAgICAgIC8vIHN0YXRlIOKAlCBgc25hcHNob3Quc2hhcmVkU3RhdGVgIElTIFNoYXJlZE1lbW9yeSdzIGN1cnJlbnQgZ2VuZXJhdGlvbixcbiAgICAgIC8vIHdob3NlIHVuY2hhbmdlZCBzdWJ0cmVlcyBldmVyeSBsYXRlciBnZW5lcmF0aW9uIHNoYXJlc1xuICAgICAgLy8gKGNvcHktb24td3JpdGUsIDkuMjkuMCkuXG4gICAgICAvLyBQcm9kdWN0aW9uIHN0YXlzIHplcm8tY29weTsgY2xvbmUtYWx3YXlzIGlzIGEgbWVhc3VyZWQgZGVjaXNpb25cbiAgICAgIC8vIGRlZmVycmVkIHVudGlsIHRoZSBiZW5jaCBzYXlzIGl0J3MgYWZmb3JkYWJsZSAoQkFDS0xPRyAjOCkuXG4gICAgICAvLyBOT1RFOiBkZWVwRnJlZXplIChjYXB0dXJlL2ZyZWV6ZS50cyDigJQgdGhlIG9uZSB3YWxrKSBjYW5ub3QgcmVhY2hcbiAgICAgIC8vIE1hcC9TZXQgSU5URVJOQUxTIChgbWFwLnNldCgpYCBvbiB0aGUgZnJvemVuIGNsb25lIHdvbid0IHRocm93KSBhbmRcbiAgICAgIC8vIHNraXBzIHR5cGVkIGFycmF5cy4gVGhlIENMT05FIHN0aWxsIGlzb2xhdGVzIHRoZSBlbmdpbmUuXG4gICAgICBzbmFwc2hvdC5zaGFyZWRTdGF0ZSA9IGRlZXBGcmVlemUoc3RydWN0dXJlZENsb25lKHNuYXBzaG90LnNoYXJlZFN0YXRlKSk7XG4gICAgfVxuICAgIGNvbnN0IHNmUmVzdWx0cyA9IHRoaXMudHJhdmVyc2VyLmdldFN1YmZsb3dSZXN1bHRzKCk7XG4gICAgaWYgKHNmUmVzdWx0cy5zaXplID4gMCkge1xuICAgICAgLy8gVW5kZXIgYHJlZGFjdDogdHJ1ZWAgZWFjaCBzdWJmbG93J3MgYGdsb2JhbENvbnRleHRgIGlzIGl0cyBvd24gbWlycm9yXG4gICAgICAvLyAoOS4yMC4wKSDigJQgc2VydmVkLCBuZXZlciB3cml0dGVuIGludG8gdGhlIHJlY29yZCAoc2VlXG4gICAgICAvLyBlbmdpbmUvaGFuZGxlcnMvc2VydmVkU3ViZmxvd1Jlc3VsdHMudHMpLiBQbGFpbjogdGhlIHJlY29yZHMgYXMgdGhleSBhcmUuXG4gICAgICBzbmFwc2hvdC5zdWJmbG93UmVzdWx0cyA9IHNlcnZlZFN1YmZsb3dSZXN1bHRzKHNmUmVzdWx0cywgb3B0aW9ucz8ucmVkYWN0ID09PSB0cnVlKTtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmRlclNuYXBzaG90cyA9IHRoaXMuY29sbGVjdFJlY29yZGVyU25hcHNob3RzKCk7XG4gICAgaWYgKHJlY29yZGVyU25hcHNob3RzLmxlbmd0aCA+IDApIHtcbiAgICAgIHNuYXBzaG90LnJlY29yZGVycyA9IHJlY29yZGVyU25hcHNob3RzO1xuICAgIH1cblxuICAgIC8vIFJGQy0wMDEgQmxvY2sgOTogdGhlIGRlZmVycmVkLW9ic2VydmVyIGFjY291bnRpbmcgc3VyZmFjZS4gUHJlc2VudFxuICAgIC8vIE9OTFkgd2hlbiBhIGRlZmVycmVkIG9ic2VydmVyIHdhcyBhdHRhY2hlZCBvbiB0aGlzIGV4ZWN1dG9yIOKAlFxuICAgIC8vIHplcm8tY29zdCBkaXNjaXBsaW5lIGZvciBldmVyeW9uZSBlbHNlLlxuICAgIGlmICh0aGlzLmRlZmVycmVkVGllcikge1xuICAgICAgc25hcHNob3Qub2JzZXJ2ZXJTdGF0cyA9IHRoaXMuZGVmZXJyZWRUaWVyLmdldFN0YXRzKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNuYXBzaG90O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbGxlY3QgYHRvU25hcHNob3QoKWAgYnVuZGxlcyBmcm9tIGV2ZXJ5IGF0dGFjaGVkIHJlY29yZGVyIOKAlCBPTkUgZW50cnlcbiAgICogcGVyIHJlY29yZGVyIGlkLCBhY3Jvc3MgYWxsIGNoYW5uZWxzIGFuZCBib3RoIGRlbGl2ZXJ5IHRpZXJzLlxuICAgKlxuICAgKiBUaGUgZGVkdXBlIGlzIGxvYWQtYmVhcmluZywgbm90IHRpZGluZXNzLiBBIHJlY29yZGVyIHRoYXQgaW1wbGVtZW50cyBhXG4gICAqIHNoYXJlZC1uYW1lIGhvb2sgKGBvbkVycm9yYCAvIGBvblBhdXNlYCAvIGBvblJlc3VtZWAg4oCUIGRlY2xhcmVkIG9uIEJPVEhcbiAgICogdGhlIHNjb3BlIGFuZCBmbG93IGludGVyZmFjZXMpIGlzIGxlZ2l0aW1hdGVseSByZWdpc3RlcmVkIG9uIEJPVEggaW5saW5lXG4gICAqIGxpc3RzIGJ5IGBhdHRhY2hDb21iaW5lZFJlY29yZGVyYCwgYW5kIHRoYXQgaXMgYnkgZGVzaWduOiBlYWNoIGNoYW5uZWxcbiAgICogY2FsbHMgdGhlIGhvb2sgd2l0aCBpdHMgb3duIHBheWxvYWQgdmFyaWFudC4gYE1ldHJpY1JlY29yZGVyLm9uUGF1c2VgIGlzXG4gICAqIHRoZSBldmVyeWRheSBjYXNlLiBXYWxraW5nIHRoZSBsaXN0cyB3aXRob3V0IGEgc2hhcmVkIGBzZWVuYCBzZXQgdHVybmVkXG4gICAqIHRoYXQgaW50byBhIERVUExJQ0FURUQgc25hcHNob3QgZW50cnkgKHNhbWUgaWQgdHdpY2UpLCB3aGljaCBicmVha3MgZXZlcnlcbiAgICogY29uc3VtZXIgdGhhdCBpbmRleGVzIGBzbmFwc2hvdC5yZWNvcmRlcnNgIGJ5IGlkLlxuICAgKlxuICAgKiBPcmRlcmluZyBpcyBzY29wZSBsaXN0IOKGkiBmbG93IGxpc3Qg4oaSIGRlZmVycmVkIHRpZXIsIGFuZCB0aGUgRklSU1QgYnVuZGxlXG4gICAqIGZvciBhbiBpZCB3aW5zLiBBIHJlY29yZGVyIHdpdGggbm8gYHRvU25hcHNob3RgIG5ldmVyIGNsYWltcyBhbiBpZCwgc28gaXRcbiAgICogY2Fubm90IHNoYWRvdyBhIHNhbWUtaWQgcmVjb3JkZXIgdGhhdCBkb2VzIGhhdmUgb25lLlxuICAgKlxuICAgKiBUaGUgcm93IGlzIFJFQlVJTFQgZmllbGQgYnkgZmllbGQgYnkgdGhlIG9uZSBjb3BpZXIgKGByZWNvcmRlci9zbmFwc2hvdC50c1xuICAgKiDCtyBjb3B5QnVuZGxlYCwgc2hhcmVkIHdpdGggYENvbXBvc2l0ZVJlY29yZGVyYCkgcmF0aGVyIHRoYW4gc3ByZWFkLCBzbyBhXG4gICAqIHJlY29yZGVyIGNhbm5vdCBzbXVnZ2xlIGFuIGBpZGAgb2YgaXRzIG93biBjaG9vc2luZyBpbnRvIHRoZSBzbmFwc2hvdCAodGhlXG4gICAqIGlkIGlzIHRoZSBleGVjdXRvcidzLCBhbmQgY29uc3VtZXJzIGluZGV4IGJ5IGl0KS5cbiAgICovXG4gIHByaXZhdGUgY29sbGVjdFJlY29yZGVyU25hcHNob3RzKCk6IFJlY29yZGVyU25hcHNob3RbXSB7XG4gICAgY29uc3Qgb3V0OiBSZWNvcmRlclNuYXBzaG90W10gPSBbXTtcbiAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3QgY29sbGVjdCA9IChyOiBTY29wZVJlY29yZGVyIHwgRmxvd1JlY29yZGVyKTogdm9pZCA9PiB7XG4gICAgICBpZiAoIXIudG9TbmFwc2hvdCB8fCBzZWVuLmhhcyhyLmlkKSkgcmV0dXJuO1xuICAgICAgc2Vlbi5hZGQoci5pZCk7XG4gICAgICBvdXQucHVzaChjb3B5QnVuZGxlKHIuaWQsIHIudG9TbmFwc2hvdCgpKSk7XG4gICAgfTtcbiAgICBmb3IgKGNvbnN0IHIgb2YgdGhpcy5zY29wZVJlY29yZGVycykgY29sbGVjdChyKTtcbiAgICBmb3IgKGNvbnN0IHIgb2YgdGhpcy5mbG93UmVjb3JkZXJzKSBjb2xsZWN0KHIpO1xuICAgIGlmICh0aGlzLmRlZmVycmVkVGllcikge1xuICAgICAgZm9yIChjb25zdCByIG9mIHRoaXMuZGVmZXJyZWRUaWVyLnNjb3BlTGlzdFJlY29yZGVycygpKSBjb2xsZWN0KHIpO1xuICAgICAgZm9yIChjb25zdCByIG9mIHRoaXMuZGVmZXJyZWRUaWVyLmZsb3dMaXN0UmVjb3JkZXJzKCkpIGNvbGxlY3Qocik7XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldFJ1bnRpbWUoKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhdmVyc2VyLmdldFJ1bnRpbWUoKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgc2V0Um9vdE9iamVjdChwYXRoOiBzdHJpbmdbXSwga2V5OiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogdm9pZCB7XG4gICAgdGhpcy50cmF2ZXJzZXIuc2V0Um9vdE9iamVjdChwYXRoLCBrZXksIHZhbHVlKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgZ2V0QnJhbmNoSWRzKCkge1xuICAgIHJldHVybiB0aGlzLnRyYXZlcnNlci5nZXRCcmFuY2hJZHMoKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgZ2V0UnVudGltZVJvb3QoKTogU3RhZ2VOb2RlIHtcbiAgICByZXR1cm4gdGhpcy50cmF2ZXJzZXIuZ2V0UnVudGltZVJvb3QoKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgZ2V0UnVudGltZVN0cnVjdHVyZSgpOiBTZXJpYWxpemVkUGlwZWxpbmVTdHJ1Y3R1cmUgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnRyYXZlcnNlci5nZXRSdW50aW1lU3RydWN0dXJlKCk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldFN1YmZsb3dSZXN1bHRzKCk6IE1hcDxzdHJpbmcsIFN1YmZsb3dSZXN1bHQ+IHtcbiAgICByZXR1cm4gdGhpcy50cmF2ZXJzZXIuZ2V0U3ViZmxvd1Jlc3VsdHMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBzdWJmbG93IG1hbmlmZXN0IGZyb20gYW4gYXR0YWNoZWQgTWFuaWZlc3RGbG93UmVjb3JkZXIuXG4gICAqIFJldHVybnMgZW1wdHkgYXJyYXkgaWYgbm8gTWFuaWZlc3RGbG93UmVjb3JkZXIgaXMgYXR0YWNoZWQuXG4gICAqL1xuICBnZXRTdWJmbG93TWFuaWZlc3QoKTogTWFuaWZlc3RFbnRyeVtdIHtcbiAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmxvd1JlY29yZGVycy5maW5kKChyKSA9PiByIGluc3RhbmNlb2YgTWFuaWZlc3RGbG93UmVjb3JkZXIpIGFzXG4gICAgICB8IE1hbmlmZXN0Rmxvd1JlY29yZGVyXG4gICAgICB8IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVjb3JkZXI/LmdldE1hbmlmZXN0KCkgPz8gW107XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgZnVsbCBzcGVjIGZvciBhIGR5bmFtaWNhbGx5LXJlZ2lzdGVyZWQgc3ViZmxvdy5cbiAgICogUmVxdWlyZXMgYW4gYXR0YWNoZWQgTWFuaWZlc3RGbG93UmVjb3JkZXIgdGhhdCBvYnNlcnZlZCB0aGUgcmVnaXN0cmF0aW9uLlxuICAgKi9cbiAgZ2V0U3ViZmxvd1NwZWMoc3ViZmxvd0lkOiBzdHJpbmcpOiB1bmtub3duIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByZWNvcmRlciA9IHRoaXMuZmxvd1JlY29yZGVycy5maW5kKChyKSA9PiByIGluc3RhbmNlb2YgTWFuaWZlc3RGbG93UmVjb3JkZXIpIGFzXG4gICAgICB8IE1hbmlmZXN0Rmxvd1JlY29yZGVyXG4gICAgICB8IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVjb3JkZXI/LmdldFNwZWMoc3ViZmxvd0lkKTtcbiAgfVxufVxuIl19
|
|
569
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmxvd0NoYXJ0RXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3J1bm5lci9GbG93Q2hhcnRFeGVjdXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUdILE9BQU8sRUFBRSxlQUFlLElBQUksZ0JBQWdCLEVBQUUsa0JBQWtCLElBQUksbUJBQW1CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUtwSCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx1REFBdUQsQ0FBQztBQUU3RixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUMvRSxPQUFPLEVBUUwsYUFBYSxHQUNkLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUduRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFJbEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV2RCxPQUFPLEVBQXdCLGdCQUFnQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDL0UsT0FBTyxFQUFvRCxtQkFBbUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNyRyxPQUFPLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDdkUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVuRCxNQUFNLE9BQU8saUJBQWlC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QixDQUU5RSxDQUFDO1FBQ2QsT0FBTyxRQUFRLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmxvd0NoYXJ0RXhlY3V0b3Ig4oCUIFB1YmxpYyBBUEkgZm9yIGV4ZWN1dGluZyBhIGNvbXBpbGVkIEZsb3dDaGFydC5cbiAqXG4gKiBXcmFwcyBGbG93Y2hhcnRUcmF2ZXJzZXIuIEJ1aWxkIGEgY2hhcnQgd2l0aCBmbG93Q2hhcnQoKSBhbmQgcGFzcyB0aGUgcmVzdWx0IGhlcmU6XG4gKlxuICogICBjb25zdCBjaGFydCA9IGZsb3dDaGFydCgnZW50cnknLCBlbnRyeUZuKS5hZGRGdW5jdGlvbigncHJvY2VzcycsIHByb2Nlc3NGbikuYnVpbGQoKTtcbiAqXG4gKiAgIC8vIE5vLW9wdGlvbnMgZm9ybSAodXNlcyBhdXRvLWRldGVjdGVkIFR5cGVkU2NvcGUgZmFjdG9yeSBmcm9tIHRoZSBjaGFydCk6XG4gKiAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IEZsb3dDaGFydEV4ZWN1dG9yKGNoYXJ0KTtcbiAqXG4gKiAgIC8vIE9wdGlvbnMtb2JqZWN0IGZvcm0gKHByZWZlcnJlZCB3aGVuIHlvdSBuZWVkIHRvIGN1c3RvbWl6ZSBiZWhhdmlvcik6XG4gKiAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IEZsb3dDaGFydEV4ZWN1dG9yKGNoYXJ0LCB7IHNjb3BlRmFjdG9yeTogbXlGYWN0b3J5IH0pO1xuICpcbiAqICAgLy8gMi1wYXJhbSBmb3JtIChhY2NlcHRzIGEgU2NvcGVGYWN0b3J5IGRpcmVjdGx5LCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSk6XG4gKiAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IEZsb3dDaGFydEV4ZWN1dG9yKGNoYXJ0LCBteUZhY3RvcnkpO1xuICpcbiAqXG4gKiBUaGUgZXhlY3V0b3IgY29tcG9zZXMgZm91ciBtb2R1bGVzLCBvbmUgam9iIGVhY2ggKEY5KTogYGF0dGFjaC50c2AgKHdob1xuICogb2JzZXJ2ZXMgYSBydW4pLCBgcmVzdW1lLnRzYCAocGxhbiBhbmQgYW5ub3VuY2UgYSByZS1lbnRyeSksIGBjaGVja3BvaW50LnRzYFxuICogKHRoZSBwYXVzZSBjaGVja3BvaW50KSwgYHNuYXBzaG90LnRzYCAod2hhdCBgZ2V0U25hcHNob3QoKWAgc2VydmVzKS4gV2hhdFxuICogc3RheXMgaGVyZSBpcyB0aGUgcGVyLXJ1biBzdGF0ZSBhbmQgdGhlIHJ1biBsaWZlY3ljbGUgdGhhdCB0aHJlYWRzIGl0LlxuICogICBjb25zdCByZXN1bHQgPSBhd2FpdCBleGVjdXRvci5ydW4oeyBpbnB1dDogZGF0YSwgZW52OiB7IHRyYWNlSWQ6ICdyZXEtMTIzJyB9IH0pO1xuICovXG5cbmltcG9ydCB0eXBlIHsgRmxvd0NoYXJ0IH0gZnJvbSAnLi4vYnVpbGRlci90eXBlcy5qcyc7XG5pbXBvcnQgeyBkZXRhY2hBbmRGb3JnZXQgYXMgX2RldGFjaEFuZEZvcmdldCwgZGV0YWNoQW5kSm9pbkxhdGVyIGFzIF9kZXRhY2hBbmRKb2luTGF0ZXIgfSBmcm9tICcuLi9kZXRhY2gvc3Bhd24uanMnO1xuaW1wb3J0IHR5cGUgeyBSZXN1bWVFbnRyeSB9IGZyb20gJy4uL2VuZ2luZS9oYW5kbGVycy9SZXN1bWVFbnRyeS5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbWJpbmVkTmFycmF0aXZlUmVjb3JkZXJPcHRpb25zIH0gZnJvbSAnLi4vZW5naW5lL25hcnJhdGl2ZS9Db21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyLmpzJztcbmltcG9ydCB0eXBlIHsgQ29tYmluZWROYXJyYXRpdmVFbnRyeSB9IGZyb20gJy4uL2VuZ2luZS9uYXJyYXRpdmUvbmFycmF0aXZlVHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNYW5pZmVzdEVudHJ5IH0gZnJvbSAnLi4vZW5naW5lL25hcnJhdGl2ZS9yZWNvcmRlcnMvTWFuaWZlc3RGbG93UmVjb3JkZXIuanMnO1xuaW1wb3J0IHsgTWFuaWZlc3RGbG93UmVjb3JkZXIgfSBmcm9tICcuLi9lbmdpbmUvbmFycmF0aXZlL3JlY29yZGVycy9NYW5pZmVzdEZsb3dSZWNvcmRlci5qcyc7XG5pbXBvcnQgdHlwZSB7IEZsb3dSZWNvcmRlciB9IGZyb20gJy4uL2VuZ2luZS9uYXJyYXRpdmUvdHlwZXMuanMnO1xuaW1wb3J0IHsgRmxvd2NoYXJ0VHJhdmVyc2VyIH0gZnJvbSAnLi4vZW5naW5lL3RyYXZlcnNhbC9GbG93Y2hhcnRUcmF2ZXJzZXIuanMnO1xuaW1wb3J0IHtcbiAgdHlwZSBFeGVjdXRvclJlc3VsdCxcbiAgdHlwZSBQYXVzZWRSZXN1bHQsXG4gIHR5cGUgUnVuT3B0aW9ucyxcbiAgdHlwZSBTY29wZUZhY3RvcnksXG4gIHR5cGUgU2VyaWFsaXplZFBpcGVsaW5lU3RydWN0dXJlLFxuICB0eXBlIFN0YWdlTm9kZSxcbiAgdHlwZSBTdWJmbG93UmVzdWx0LFxuICBkZWZhdWx0TG9nZ2VyLFxufSBmcm9tICcuLi9lbmdpbmUvdHlwZXMuanMnO1xuaW1wb3J0IHsgUmVkYWN0aW9uUnVsZSB9IGZyb20gJy4uL21lbW9yeS9yZWRhY3Rpb24uanMnO1xuaW1wb3J0IHsgcnVuUG9saWN5IH0gZnJvbSAnLi4vbWVtb3J5L3J1blBvbGljeS5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbW1pdFZhbHVlc01vZGUsIFJlYWRUcmFja2luZ01vZGUsIFdyaXRlVHJhY2tpbmdNb2RlIH0gZnJvbSAnLi4vbWVtb3J5L3R5cGVzLmpzJztcbmltcG9ydCB0eXBlIHsgRmxvd2NoYXJ0Q2hlY2twb2ludCB9IGZyb20gJy4uL3BhdXNlL3R5cGVzLmpzJztcbmltcG9ydCB7IGlzUGF1c2VTaWduYWwgfSBmcm9tICcuLi9wYXVzZS90eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbWJpbmVkUmVjb3JkZXIgfSBmcm9tICcuLi9yZWNvcmRlci9Db21iaW5lZFJlY29yZGVyLmpzJztcbmltcG9ydCB0eXBlIHsgRW1pdFJlY29yZGVyIH0gZnJvbSAnLi4vcmVjb3JkZXIvRW1pdFJlY29yZGVyLmpzJztcbmltcG9ydCB0eXBlIHsgUmVkYWN0aW9uUG9saWN5LCBSZWRhY3Rpb25SZXBvcnQsIFNjb3BlUmVjb3JkZXIgfSBmcm9tICcuLi9zY29wZS90eXBlcy5qcyc7XG5pbXBvcnQgeyBSdW5PYnNlcnZlcnMgfSBmcm9tICcuL2F0dGFjaC5qcyc7XG5pbXBvcnQgeyBidWlsZFBhdXNlQ2hlY2twb2ludCB9IGZyb20gJy4vY2hlY2twb2ludC5qcyc7XG5pbXBvcnQgdHlwZSB7IEF0dGFjaFJlY29yZGVyT3B0aW9ucywgT2JzZXJ2ZXJEcmFpblJlc3VsdCB9IGZyb20gJy4vRGVmZXJyZWRPYnNlcnZlclRpZXIuanMnO1xuaW1wb3J0IHsgdHlwZSBSdW50aW1lU25hcHNob3QsIEV4ZWN1dGlvblJ1bnRpbWUgfSBmcm9tICcuL0V4ZWN1dGlvblJ1bnRpbWUuanMnO1xuaW1wb3J0IHsgdHlwZSBFeGVjdXRvckFyZ3MsIHR5cGUgRmxvd0NoYXJ0RXhlY3V0b3JPcHRpb25zLCByZXNvbHZlRXhlY3V0b3JBcmdzIH0gZnJvbSAnLi9vcHRpb25zLmpzJztcbmltcG9ydCB7IGFubm91bmNlUmVzdW1lLCBwbGFuUmVzdW1lLCBzZWVkQ291bnRlcnMgfSBmcm9tICcuL3Jlc3VtZS5qcyc7XG5pbXBvcnQgeyBnZW5lcmF0ZVJ1bklkIH0gZnJvbSAnLi9ydW5JZC5qcyc7XG5pbXBvcnQgeyBzZXJ2ZWRTbmFwc2hvdCB9IGZyb20gJy4vc25hcHNob3QuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVJbnB1dCB9IGZyb20gJy4vdmFsaWRhdGVJbnB1dC5qcyc7XG5cbmV4cG9ydCBjbGFzcyBGbG93Q2hhcnRFeGVjdXRvcjxUT3V0ID0gYW55LCBUU2NvcGUgPSBhbnk+IHtcbiAgcHJpdmF0ZSB0cmF2ZXJzZXI6IEZsb3djaGFydFRyYXZlcnNlcjxUT3V0LCBUU2NvcGU+O1xuICAvKiogU2hhcmVkIGV4ZWN1dGlvbiBjb3VudGVyIGFuZCBwZXItc3RhZ2UgdmlzaXQgY291bnRzIChsb29wSXRlcmF0aW9uKSDigJQgc2hhcmVkIEJZXG4gICAqICBSRUZFUkVOQ0Ugd2l0aCBldmVyeSB0cmF2ZXJzZXIgb2YgdGhlIHJ1bjsgc3Vydml2ZSBwYXVzZS9yZXN1bWUsIHJlc2V0IG9uIHJ1bigpLiAqL1xuICBwcml2YXRlIF9leGVjdXRpb25Db3VudGVyID0geyB2YWx1ZTogMCB9O1xuICBwcml2YXRlIF92aXNpdENvdW50cyA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIC8qKiBGcmVzaCBwZXIgcnVuKCkgYW5kIHBlciByZXN1bWUoKSDigJQgc3RhbXBlZCBvbiBldmVyeSBUcmF2ZXJzYWxDb250ZXh0IChgcnVuSWQudHNgKS4gKi9cbiAgcHJpdmF0ZSBfY3VycmVudFJ1bklkID0gJyc7XG4gIC8qKiBXaG8gb2JzZXJ2ZXMgdGhlIHJ1biDigJQgbmFycmF0aXZlLCBpbmxpbmUgbGlzdHMsIGRlZmVycmVkIHRpZXIgKGBhdHRhY2gudHNgKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBvYnNlcnZlcnMgPSBuZXcgUnVuT2JzZXJ2ZXJzKCk7XG4gIHByaXZhdGUgcmVkYWN0aW9uUG9saWN5OiBSZWRhY3Rpb25Qb2xpY3kgfCB1bmRlZmluZWQ7XG4gIC8qKiBUaGUgcnVuJ3MgT05FIHJlZGFjdGlvbiBydWxlIChgbWVtb3J5L3JlZGFjdGlvbi50c2ApLCBidWlsdCBmcmVzaCBwZXIgbGVnLiAqL1xuICBwcml2YXRlIHJlZGFjdGlvblJ1bGUgPSBuZXcgUmVkYWN0aW9uUnVsZSgpO1xuICBwcml2YXRlIGxhc3RDaGVja3BvaW50OiBGbG93Y2hhcnRDaGVja3BvaW50IHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogYHRydWVgIG9uY2UgcnVuKCkgKG9yIGEgcmVzdW1lKSBleGVjdXRlZCBoZXJlLiBgcmVzdW1lKClgIGJyYW5jaGVzIG9uIGl0OlxuICAgKiB0cnVlIOKGkiByZXVzZSB0aGUgcnVudGltZSAoZXhlY3V0aW9uIHRyZWUsIHJlY29yZGVycywgbmFycmF0aXZlIGFjY3VtdWxhdGUpO1xuICAgKiBmYWxzZSDihpIgc2VlZCBhIGZyZXNoIHJ1bnRpbWUgZnJvbSBgY2hlY2twb2ludC5zaGFyZWRTdGF0ZWAgKGNyb3NzLWV4ZWN1dG9yXG4gICAqIHJlc3VtZSkuIFNlZSBgdGVzdC9saWIvcGF1c2UvY3Jvc3MtZXhlY3V0b3ItcmVzdW1lLnRlc3QudHNgLlxuICAgKi9cbiAgcHJpdmF0ZSBfaGFzUnVuQmVmb3JlID0gZmFsc2U7XG4gIC8qKlxuICAgKiBSZS1lbnRyYW5jeSBndWFyZDogcnVuKCkvcmVzdW1lKCkgbXV0YXRlIHBlci1ydW4gc3RhdGUgKHRyYXZlcnNlciwgcnVuSWQsXG4gICAqIGNvdW50ZXJzLCBjaGVja3BvaW50LCByZWNvcmRlcnMpIOKAlCBvbmUgZXhlY3V0b3IgPSBvbmUgaW4tZmxpZ2h0IGV4ZWN1dGlvbi5cbiAgICogU2VlIGRvY3MvZ3VpZGVzL2V4ZWN1dGlvbi1tb2RlbC5tZC5cbiAgICovXG4gIHByaXZhdGUgX2lzRXhlY3V0aW5nID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBmbG93Q2hhcnRBcmdzOiBFeGVjdXRvckFyZ3M8VE91dCwgVFNjb3BlPjtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgRmxvd0NoYXJ0RXhlY3V0b3IuXG4gICAqXG4gICAqICoqT3B0aW9ucyBvYmplY3QgZm9ybSoqIChwcmVmZXJyZWQpOlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCwgeyBzY29wZUZhY3RvcnksIGRlZmF1bHRWYWx1ZXNGb3JDb250ZXh0IH0pXG4gICAqIGBgYFxuICAgKlxuICAgKiAqKjItcGFyYW0gZm9ybSoqIChhbHNvIHN1cHBvcnRlZCk6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogbmV3IEZsb3dDaGFydEV4ZWN1dG9yKGNoYXJ0LCBzY29wZUZhY3RvcnkpXG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gZmxvd0NoYXJ0IC0gVGhlIGNvbXBpbGVkIEZsb3dDaGFydCByZXR1cm5lZCBieSBgZmxvd0NoYXJ0KC4uLikuYnVpbGQoKWBcbiAgICogQHBhcmFtIGZhY3RvcnlPck9wdGlvbnMgLSBBIGBTY29wZUZhY3Rvcnk8VFNjb3BlPmAgT1IgYSBgRmxvd0NoYXJ0RXhlY3V0b3JPcHRpb25zPFRTY29wZT5gIG9wdGlvbnMgb2JqZWN0LlxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgZmxvd0NoYXJ0OiBGbG93Q2hhcnQ8VE91dCwgVFNjb3BlPixcbiAgICBmYWN0b3J5T3JPcHRpb25zPzogU2NvcGVGYWN0b3J5PFRTY29wZT4gfCBGbG93Q2hhcnRFeGVjdXRvck9wdGlvbnM8VFNjb3BlPixcbiAgKSB7XG4gICAgdGhpcy5mbG93Q2hhcnRBcmdzID0gcmVzb2x2ZUV4ZWN1dG9yQXJncyhmbG93Q2hhcnQsIGZhY3RvcnlPck9wdGlvbnMpO1xuICAgIHRoaXMudHJhdmVyc2VyID0gdGhpcy5jcmVhdGVUcmF2ZXJzZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlVHJhdmVyc2VyKFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICAgIHJlYWRPbmx5Q29udGV4dE92ZXJyaWRlPzogdW5rbm93bixcbiAgICBlbnY/OiBpbXBvcnQoJy4uL2VuZ2luZS90eXBlcy5qcycpLkV4ZWN1dGlvbkVudixcbiAgICBtYXhEZXB0aD86IG51bWJlcixcbiAgICBtYXhJdGVyYXRpb25zPzogbnVtYmVyLFxuICAgIG92ZXJyaWRlcz86IHtcbiAgICAgIGluaXRpYWxDb250ZXh0PzogdW5rbm93bjtcbiAgICAgIHByZXNlcnZlUmVjb3JkZXJzPzogYm9vbGVhbjtcbiAgICAgIGV4aXN0aW5nUnVudGltZT86IEluc3RhbmNlVHlwZTx0eXBlb2YgRXhlY3V0aW9uUnVudGltZT47XG4gICAgICAvKiogVGhlIHJlc3VtZSdzIG9uZS1zaG90IHJlLWVudHJ5IChgcmVzdW1lLnRzYCk7IHRoZSB0cmF2ZXJzZXIgc3RpbGwgd2Fsa3MgdGhlIFJFQUwgY2hhcnQuICovXG4gICAgICByZXN1bWU/OiBSZXN1bWVFbnRyeTxUT3V0LCBUU2NvcGU+O1xuICAgIH0sXG4gICk6IEZsb3djaGFydFRyYXZlcnNlcjxUT3V0LCBUU2NvcGU+IHtcbiAgICBjb25zdCBhcmdzID0gdGhpcy5mbG93Q2hhcnRBcmdzO1xuICAgIGNvbnN0IGZjID0gYXJncy5mbG93Q2hhcnQ7XG4gICAgY29uc3QgbmFycmF0aXZlRmxhZyA9IHRoaXMub2JzZXJ2ZXJzLnN0YXJ0TGVnKGZjLmVuYWJsZU5hcnJhdGl2ZSA/PyBmYWxzZSwgb3ZlcnJpZGVzPy5wcmVzZXJ2ZVJlY29yZGVycyA9PT0gdHJ1ZSk7XG5cbiAgICB0aGlzLnJlZGFjdGlvblJ1bGUgPSBuZXcgUmVkYWN0aW9uUnVsZSh0aGlzLnJlZGFjdGlvblBvbGljeSk7XG4gICAgLy8gT05FIGZhY3Rvcnk6IHRoZSBiYXNlIGZhY3RvcnksIHRoZW4gZXZlcnkgc2NvcGUgbW9kaWZpZXIgKHJlY29yZGVycyxcbiAgICAvLyBkZWZlcnJlZCB0YXAsIHJlZGFjdGlvbikgaW4gYSBmbGF0IHBhc3Mg4oCUIHNlZSBgUnVuT2JzZXJ2ZXJzYC5cbiAgICBjb25zdCBzY29wZUZhY3RvcnkgPSB0aGlzLm9ic2VydmVycy5jb21wb3NlU2NvcGVGYWN0b3J5KFxuICAgICAgYXJncy5zY29wZUZhY3RvcnksXG4gICAgICB0aGlzLnJlZGFjdGlvblBvbGljeSxcbiAgICAgIHRoaXMucmVkYWN0aW9uUnVsZS5tYXJrZWRLZXlzKCksXG4gICAgKTtcblxuICAgIC8vIFRoZSBmaXJzdCBzdGFnZSB0aGlzIHRyYXZlcnNhbCBydW5zOiB0aGUgcmVzdW1lJ3MgZW50cnksIGVsc2UgdGhlIGNoYXJ0IHJvb3QuXG4gICAgY29uc3QgZWZmZWN0aXZlUm9vdCA9IG92ZXJyaWRlcz8ucmVzdW1lPy5zdGFydCA/PyBmYy5yb290O1xuICAgIGNvbnN0IGVmZmVjdGl2ZUluaXRpYWxDb250ZXh0ID0gb3ZlcnJpZGVzPy5pbml0aWFsQ29udGV4dCA/PyBhcmdzLmluaXRpYWxDb250ZXh0O1xuXG4gICAgLy8gVGhlIHJ1bidzIHBvbGljeSAoRjUpOiB0aGUgZGlhbHMsIHRoZSBydWxlIChpbnN0YWxsZWQgZXZlbiB3aXRob3V0IGFcbiAgICAvLyBwb2xpY3kg4oCUIHBlci1jYWxsIGBzZXRWYWx1ZShrLCB2LCB0cnVlKWAgbWFya3MgbGl2ZSBvbiBpdCkgYW5kIHRoZSBtaXJyb3JcbiAgICAvLyBmbGFnIChhIHJlZGFjdGVkIGhlYXAsIGtlcHQgb25seSB1bmRlciBhIHBvbGljeSksIE9ORSBmcm96ZW4gb2JqZWN0IHBlclxuICAgIC8vIGxlZyB0aGF0IGV2ZXJ5IGZyYW1lIG9mIHRoZSBydW4gaG9sZHMgYnkgcmVmZXJlbmNlLlxuICAgIGNvbnN0IHBvbGljeSA9IHJ1blBvbGljeShhcmdzLmRpYWxzLCB0aGlzLnJlZGFjdGlvblJ1bGUsIHRoaXMucmVkYWN0aW9uUG9saWN5ICE9PSB1bmRlZmluZWQpO1xuXG4gICAgbGV0IHJ1bnRpbWU6IEV4ZWN1dGlvblJ1bnRpbWU7XG4gICAgaWYgKG92ZXJyaWRlcz8uZXhpc3RpbmdSdW50aW1lKSB7XG4gICAgICAvLyBTYW1lLWV4ZWN1dG9yIHJlc3VtZTogdGhlIHRyZWUgY29udGludWVzIGZyb20gdGhlIGxlYWY7IGdldFNuYXBzaG90KCkga2VlcHMgdGhlIGZ1bGwgdHJlZS5cbiAgICAgIHJ1bnRpbWUgPSBvdmVycmlkZXMuZXhpc3RpbmdSdW50aW1lO1xuICAgICAgcnVudGltZS5wcmVzZXJ2ZVNuYXBzaG90Um9vdCgpO1xuICAgICAgbGV0IGxlYWYgPSBydW50aW1lLnJvb3RTdGFnZUNvbnRleHQ7XG4gICAgICB3aGlsZSAobGVhZi5uZXh0KSBsZWFmID0gbGVhZi5uZXh0O1xuICAgICAgcnVudGltZS5yb290U3RhZ2VDb250ZXh0ID0gbGVhZi5jcmVhdGVOZXh0KCcnLCBlZmZlY3RpdmVSb290Lm5hbWUsIGVmZmVjdGl2ZVJvb3QuaWQpO1xuICAgICAgcnVudGltZS51c2VQb2xpY3kocG9saWN5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcnVudGltZSA9IG5ldyBFeGVjdXRpb25SdW50aW1lKFxuICAgICAgICBlZmZlY3RpdmVSb290Lm5hbWUsXG4gICAgICAgIGVmZmVjdGl2ZVJvb3QuaWQsXG4gICAgICAgIGFyZ3MuZGVmYXVsdFZhbHVlc0ZvckNvbnRleHQsXG4gICAgICAgIGVmZmVjdGl2ZUluaXRpYWxDb250ZXh0LFxuICAgICAgICBwb2xpY3ksXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgRmxvd2NoYXJ0VHJhdmVyc2VyPFRPdXQsIFRTY29wZT4oe1xuICAgICAgLy8gQWx3YXlzIHRoZSBSRUFMIGNoYXJ0OyBhIHJlc3VtZSBvbmx5IG1vdmVzIHdoZXJlIHRoZSB0cmF2ZXJzYWwgU1RBUlRTLCBvbmNlLlxuICAgICAgcm9vdDogZmMucm9vdCxcbiAgICAgIC4uLihvdmVycmlkZXM/LnJlc3VtZT8uc3RhcnQgJiYgeyBlbnRyeTogb3ZlcnJpZGVzLnJlc3VtZS5zdGFydCB9KSxcbiAgICAgIC4uLihvdmVycmlkZXM/LnJlc3VtZT8uc3RhcnRQZW5kaW5nUGF1c2VzICYmIHsgcGVuZGluZ1BhdXNlczogb3ZlcnJpZGVzLnJlc3VtZS5zdGFydFBlbmRpbmdQYXVzZXMgfSksXG4gICAgICAuLi4ob3ZlcnJpZGVzPy5yZXN1bWUgJiYgeyByZXN1bWU6IG92ZXJyaWRlcy5yZXN1bWUgfSksXG4gICAgICBzdGFnZU1hcDogZmMuc3RhZ2VNYXAsXG4gICAgICBzY29wZUZhY3RvcnksXG4gICAgICBleGVjdXRpb25SdW50aW1lOiBydW50aW1lLFxuICAgICAgcmVhZE9ubHlDb250ZXh0OiByZWFkT25seUNvbnRleHRPdmVycmlkZSA/PyBhcmdzLnJlYWRPbmx5Q29udGV4dCxcbiAgICAgIHRocm90dGxpbmdFcnJvckNoZWNrZXI6IGFyZ3MudGhyb3R0bGluZ0Vycm9yQ2hlY2tlcixcbiAgICAgIHN0cmVhbUhhbmRsZXJzOiBhcmdzLnN0cmVhbUhhbmRsZXJzLFxuICAgICAgc2NvcGVQcm90ZWN0aW9uTW9kZTogYXJncy5zY29wZVByb3RlY3Rpb25Nb2RlLFxuICAgICAgc3ViZmxvd3M6IGZjLnN1YmZsb3dzLFxuICAgICAgbmFycmF0aXZlRW5hYmxlZDogbmFycmF0aXZlRmxhZyxcbiAgICAgIGJ1aWxkVGltZVN0cnVjdHVyZTogZmMuYnVpbGRUaW1lU3RydWN0dXJlLFxuICAgICAgbG9nZ2VyOiBmYy5sb2dnZXIgPz8gZGVmYXVsdExvZ2dlcixcbiAgICAgIHNpZ25hbCxcbiAgICAgIGV4ZWN1dGlvbkVudjogZW52LFxuICAgICAgZmxvd1JlY29yZGVyczogdGhpcy5vYnNlcnZlcnMuZmxvd1JlY29yZGVyc0xpc3QoKSxcbiAgICAgIGV4ZWN1dGlvbkNvdW50ZXI6IHRoaXMuX2V4ZWN1dGlvbkNvdW50ZXIsXG4gICAgICB2aXNpdENvdW50czogdGhpcy5fdmlzaXRDb3VudHMsXG4gICAgICBydW5JZDogdGhpcy5fY3VycmVudFJ1bklkLFxuICAgICAgLi4uKG1heERlcHRoICE9PSB1bmRlZmluZWQgJiYgeyBtYXhEZXB0aCB9KSxcbiAgICAgIC4uLihtYXhJdGVyYXRpb25zICE9PSB1bmRlZmluZWQgJiYgeyBtYXhJdGVyYXRpb25zIH0pLFxuICAgIH0pO1xuICB9XG5cbiAgZW5hYmxlTmFycmF0aXZlKG9wdGlvbnM/OiBDb21iaW5lZE5hcnJhdGl2ZVJlY29yZGVyT3B0aW9ucyk6IHZvaWQge1xuICAgIHRoaXMub2JzZXJ2ZXJzLmVuYWJsZU5hcnJhdGl2ZShvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgYSBkZWNsYXJhdGl2ZSByZWRhY3Rpb24gcG9saWN5IHRoYXQgYXBwbGllcyB0byBhbGwgc3RhZ2VzLlxuICAgKiBNdXN0IGJlIGNhbGxlZCBiZWZvcmUgcnVuKCkuXG4gICAqL1xuICBzZXRSZWRhY3Rpb25Qb2xpY3kocG9saWN5OiBSZWRhY3Rpb25Qb2xpY3kpOiB2b2lkIHtcbiAgICB0aGlzLnJlZGFjdGlvblBvbGljeSA9IHBvbGljeTtcbiAgICB0aGlzLnJlZGFjdGlvblJ1bGUgPSBuZXcgUmVkYWN0aW9uUnVsZShwb2xpY3kpO1xuICB9XG5cbiAgLyoqIFRoZSBgcmVhZFRyYWNraW5nYCBkaWFsIChzZWUge0BsaW5rIEZsb3dDaGFydEV4ZWN1dG9yT3B0aW9ucy5yZWFkVHJhY2tpbmd9KS4gQ2FsbCBiZWZvcmUgcnVuKCkuICovXG4gIHNldFJlYWRUcmFja2luZyhtb2RlOiBSZWFkVHJhY2tpbmdNb2RlKTogdm9pZCB7XG4gICAgdGhpcy5mbG93Q2hhcnRBcmdzLmRpYWxzID0geyAuLi50aGlzLmZsb3dDaGFydEFyZ3MuZGlhbHMsIHJlYWRUcmFja2luZzogbW9kZSB9O1xuICB9XG5cbiAgLyoqIFRoZSBgd3JpdGVUcmFja2luZ2AgZGlhbCAoc2VlIHtAbGluayBGbG93Q2hhcnRFeGVjdXRvck9wdGlvbnMud3JpdGVUcmFja2luZ30pLiBDYWxsIGJlZm9yZSBydW4oKS4gKi9cbiAgc2V0V3JpdGVUcmFja2luZyhtb2RlOiBXcml0ZVRyYWNraW5nTW9kZSk6IHZvaWQge1xuICAgIHRoaXMuZmxvd0NoYXJ0QXJncy5kaWFscyA9IHsgLi4udGhpcy5mbG93Q2hhcnRBcmdzLmRpYWxzLCB3cml0ZVRyYWNraW5nOiBtb2RlIH07XG4gIH1cblxuICAvKiogVGhlIGBjb21taXRWYWx1ZXNgIGRpYWwgKHNlZSB7QGxpbmsgRmxvd0NoYXJ0RXhlY3V0b3JPcHRpb25zLmNvbW1pdFZhbHVlc30pLiBDYWxsIGJlZm9yZSBydW4oKS4gKi9cbiAgc2V0Q29tbWl0VmFsdWVzKG1vZGU6IENvbW1pdFZhbHVlc01vZGUpOiB2b2lkIHtcbiAgICB0aGlzLmZsb3dDaGFydEFyZ3MuZGlhbHMgPSB7IC4uLnRoaXMuZmxvd0NoYXJ0QXJncy5kaWFscywgY29tbWl0VmFsdWVzOiBtb2RlIH07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGNvbXBsaWFuY2UtZnJpZW5kbHkgcmVwb3J0IG9mIGFsbCByZWRhY3Rpb24gYWN0aXZpdHkgZnJvbSB0aGVcbiAgICogbW9zdCByZWNlbnQgcnVuLiBOZXZlciBpbmNsdWRlcyBhY3R1YWwgdmFsdWVzLlxuICAgKi9cbiAgZ2V0UmVkYWN0aW9uUmVwb3J0KCk6IFJlZGFjdGlvblJlcG9ydCB7XG4gICAgcmV0dXJuIHRoaXMucmVkYWN0aW9uUnVsZS5yZXBvcnQoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBQYXVzZS9SZXN1bWUg4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGNoZWNrcG9pbnQgZnJvbSB0aGUgbW9zdCByZWNlbnQgcGF1c2VkIGV4ZWN1dGlvbiwgb3IgYHVuZGVmaW5lZGBcbiAgICogaWYgdGhlIGxhc3QgcnVuIGNvbXBsZXRlZCB3aXRob3V0IHBhdXNpbmcuXG4gICAqXG4gICAqIEpTT04tc2VyaWFsaXphYmxlIChzdG9yZSBpdCBpbiBSZWRpcywgUG9zdGdyZXMsIGxvY2FsU3RvcmFnZeKApikgYW5kIGZ1bGx5XG4gICAqIERFVEFDSEVEIGZyb20gZW5naW5lIHN0YXRlIChgY2hlY2twb2ludC50c2ApOiBtdXRhdGluZyBvciBwZXJzaXN0aW5nIGl0XG4gICAqIGNhbm5vdCBhZmZlY3QgdGhlIGV4ZWN1dG9yLCBub3IgYSBsYXRlciByZXN1bWUgYSBjaGVja3BvaW50IHlvdSBzdG9yZWQuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgcmVzdWx0ID0gYXdhaXQgZXhlY3V0b3IucnVuKHsgaW5wdXQgfSk7XG4gICAqIGlmIChleGVjdXRvci5pc1BhdXNlZCgpKSB7XG4gICAqICAgY29uc3QgY2hlY2twb2ludCA9IGV4ZWN1dG9yLmdldENoZWNrcG9pbnQoKSE7XG4gICAqICAgYXdhaXQgcmVkaXMuc2V0KGBzZXNzaW9uOiR7aWR9YCwgSlNPTi5zdHJpbmdpZnkoY2hlY2twb2ludCkpO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgZ2V0Q2hlY2twb2ludCgpOiBGbG93Y2hhcnRDaGVja3BvaW50IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5sYXN0Q2hlY2twb2ludDtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgbW9zdCByZWNlbnQgcnVuKCkgd2FzIHBhdXNlZCAoY2hlY2twb2ludCBhdmFpbGFibGUpLiAqL1xuICBpc1BhdXNlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5sYXN0Q2hlY2twb2ludCAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIE51bWJlciBvZiBjb21taXRzIGluIHRoZSBydW4ncyBjb21taXQgbG9nLiBPKDEpIOKAlCBkaXJlY3QgbGVuZ3RoXG4gICAqIHJlYWQsIG5vIHNuYXBzaG90IG1hdGVyaWFsaXphdGlvbi4gVXNlIHRoaXMgdG8gc3RhbXAgY29tbWl0XG4gICAqIGluZGljZXMgb24gb2JzZXJ2ZXIgZXZlbnRzIChlLmcuLCBgQm91bmRhcnlSZWNvcmRlcmAgc3RvcmluZ1xuICAgKiBgY29tbWl0SWR4QmVmb3JlYCAvIGBjb21taXRJZHhBZnRlcmAgcGVyIGRvbWFpbiBldmVudCBmb3JcbiAgICogYENvbW1pdFJhbmdlSW5kZXhgIHF1ZXJpZXMg4oCUIHNlZSBgZm9vdHByaW50anMvdHJhY2VgKS5cbiAgICpcbiAgICogUmV0dXJucyAwIGJlZm9yZSBhbnkgcnVuOyBhZnRlciwgcmV0dXJucyB0aGUgY3VtdWxhdGl2ZSBjb21taXRcbiAgICogY291bnQgYWNyb3NzIHRoZSBleGVjdXRvcidzIGxpZmV0aW1lIChpbmNsdWRpbmcgcmVzdW1lcykuXG4gICAqIEFsd2F5cyBlcXVhbHMgYGdldFNuYXBzaG90KCkuY29tbWl0TG9nLmxlbmd0aGAgKHRoZSBsb2cgaXMgdGhlXG4gICAqIGBFdmVudExvZ2AncyBgZXhlY3V0aW9uSGlzdG9yeWA7IHRoZSBzbmFwc2hvdCBzZXJ2ZXMgYSBmcm96ZW4gY29weSkuXG4gICAqL1xuICBnZXRDb21taXRDb3VudCgpOiBudW1iZXIge1xuICAgIGNvbnN0IHJ1bnRpbWUgPSB0aGlzLnRyYXZlcnNlci5nZXRSdW50aW1lKCkgYXMgSW5zdGFuY2VUeXBlPHR5cGVvZiBFeGVjdXRpb25SdW50aW1lPiB8IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcnVudGltZT8uZXhlY3V0aW9uSGlzdG9yeS5sZW5ndGggPz8gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXN1bWUgYSBwYXVzZWQgZmxvd2NoYXJ0IGZyb20gYSBjaGVja3BvaW50LlxuICAgKlxuICAgKiBSZXN0b3JlcyB0aGUgc2NvcGUgc3RhdGUsIHJ1bnMgdGhlIHBhdXNlZCBzdGFnZSdzIGByZXN1bWVGbmAgd2l0aCB0aGUgaW5wdXRcbiAgICogKGFuIGBpbnRlcnJ1cHQoKWAgcGF1c2UgcmUtcnVucyB0aGUgc3RhZ2Ugd2l0aCB0aGUgYW5zd2VyKSwgdGhlbiBjb250aW51ZXNcbiAgICogd2l0aCB3aGF0ZXZlciByYW4gYWZ0ZXIgdGhhdCBzdGFnZSBvbiB0aGUgcnVuIOKAlCBpdHMgYG5leHRgLCBvciBpdHNcbiAgICogZGlzcGF0Y2hlcidzIGNvbnRpbnVhdGlvbiwgYXQgZXZlcnkgbGV2ZWwgb2YgdGhlIHBhdXNlIHBhdGguIFBhcmFsbGVsXG4gICAqIHNpYmxpbmdzIHRoYXQgcGF1c2VkIHRvZ2V0aGVyIChgY2hlY2twb2ludC5wZW5kaW5nUGF1c2VzYCkgYXJlIGFza2VkIGluXG4gICAqIHR1cm47IHRoZSBqb2luIHJ1bnMgYWZ0ZXIgdGhlIGxhc3QgYW5zd2VyLiBTZWUgYFJlc3VtZUVudHJ5YC5cbiAgICpcbiAgICogVGhlIGNoZWNrcG9pbnQgY29tZXMgZnJvbSBgZ2V0Q2hlY2twb2ludCgpYCBvciBmcm9tIHN0b3JhZ2UuIE9uIHRoZSBTQU1FXG4gICAqIGV4ZWN1dG9yLCBuYXJyYXRpdmUvcmVjb3JkZXIgc3RhdGUgYWNjdW11bGF0ZXMgYWNyb3NzIHRoZSBwYXVzZTsgb24gYVxuICAgKiBGUkVTSCBleGVjdXRvciBpdCBzdGFydHMgZW1wdHkuIEEgZnJlc2ggYHJ1bklkYCBlaXRoZXIgd2F5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIFByb2Nlc3MgQSDigJQgYWZ0ZXIgYSBwYXVzZSwgcGVyc2lzdCB0aGUgY2hlY2twb2ludDpcbiAgICogY29uc3QgY2hlY2twb2ludCA9IGV4ZWN1dG9yLmdldENoZWNrcG9pbnQoKSE7XG4gICAqIGF3YWl0IHJlZGlzLnNldChgc2Vzc2lvbjoke2lkfWAsIEpTT04uc3RyaW5naWZ5KGNoZWNrcG9pbnQpKTtcbiAgICpcbiAgICogLy8gUHJvY2VzcyBCIChwb3NzaWJseSBkaWZmZXJlbnQgc2VydmVyLCBzYW1lIGNoYXJ0KSDigJQgcmVzdG9yZSBhbmQgcmVzdW1lOlxuICAgKiBjb25zdCByZXN0b3JlZCA9IEpTT04ucGFyc2UoYXdhaXQgcmVkaXMuZ2V0KGBzZXNzaW9uOiR7aWR9YCkpO1xuICAgKiBjb25zdCBleGVjdXRvciA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihjaGFydCk7XG4gICAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWN1dG9yLnJlc3VtZShyZXN0b3JlZCwgeyBhcHByb3ZlZDogdHJ1ZSB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyByZXN1bWUoXG4gICAgY2hlY2twb2ludDogRmxvd2NoYXJ0Q2hlY2twb2ludCxcbiAgICByZXN1bWVJbnB1dD86IHVua25vd24sXG4gICAgb3B0aW9ucz86IFBpY2s8UnVuT3B0aW9ucywgJ3NpZ25hbCcgfCAnZW52JyB8ICdtYXhEZXB0aCcgfCAnbWF4SXRlcmF0aW9ucyc+LFxuICApOiBQcm9taXNlPEV4ZWN1dG9yUmVzdWx0PiB7XG4gICAgdGhpcy5hc3NlcnRJZGxlKCdyZXN1bWUnKTtcbiAgICAvLyBFdmVyeSByZWZ1c2FsIGhhcHBlbnMgaW4gdGhlIHBsYW4g4oCUIGJlZm9yZSBhbnkgc3RhdGUgYmVsb3cgaXMgdG91Y2hlZCxcbiAgICAvLyBzbyBhIHJlamVjdGVkIGNoZWNrcG9pbnQgbGVhdmVzIHRoZSBleGVjdXRvciAoYW5kIGl0cyBjaGVja3BvaW50KSBhcyBpdCB3YXMuXG4gICAgY29uc3QgcGxhbiA9IHBsYW5SZXN1bWUodGhpcy5mbG93Q2hhcnRBcmdzLmZsb3dDaGFydCwgY2hlY2twb2ludCwgcmVzdW1lSW5wdXQpO1xuICAgIC8vIE1VU1QgcHJlY2VkZSB0aGUgY291bnRlciByZWFkIGluIGBhbm5vdW5jZVJlc3VtZWAgYW5kIHRoZSB0cmF2ZXJzZXIsXG4gICAgLy8gd2hpY2ggdGFrZXMgYm90aCBjb3VudGVycyBCWSBSRUZFUkVOQ0UuXG4gICAgc2VlZENvdW50ZXJzKHBsYW4uY2hlY2twb2ludCwgdGhpcy5fZXhlY3V0aW9uQ291bnRlciwgdGhpcy5fdmlzaXRDb3VudHMpO1xuICAgIHRoaXMubGFzdENoZWNrcG9pbnQgPSB1bmRlZmluZWQ7XG5cbiAgICAvLyBTYW1lIGV4ZWN1dG9yOiByZXVzZSB0aGUgcnVudGltZS4gRnJlc2ggZXhlY3V0b3I6IHNlZWQgYSBORVcgb25lIGZyb21cbiAgICAvLyBgY2hlY2twb2ludC5zaGFyZWRTdGF0ZWAuIEVpdGhlciB3YXkgYSBORVcgcnVuSWQgKGEgZGlzdGluY3QgbG9naWNhbCBydW4pLlxuICAgIGNvbnN0IGV4aXN0aW5nUnVudGltZSA9IHRoaXMuX2hhc1J1bkJlZm9yZVxuICAgICAgPyAodGhpcy50cmF2ZXJzZXIuZ2V0UnVudGltZSgpIGFzIEluc3RhbmNlVHlwZTx0eXBlb2YgRXhlY3V0aW9uUnVudGltZT4pXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICB0aGlzLl9oYXNSdW5CZWZvcmUgPSB0cnVlOyAvLyBhbnkgcGF0aCB0aGF0IHJlc3VtZXMgY291bnRzIGFzIGEgcnVuXG4gICAgdGhpcy5fY3VycmVudFJ1bklkID0gZ2VuZXJhdGVSdW5JZCgpO1xuXG4gICAgdGhpcy50cmF2ZXJzZXIgPSB0aGlzLmNyZWF0ZVRyYXZlcnNlcihcbiAgICAgIG9wdGlvbnM/LnNpZ25hbCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIG9wdGlvbnM/LmVudixcbiAgICAgIG9wdGlvbnM/Lm1heERlcHRoLFxuICAgICAgb3B0aW9ucz8ubWF4SXRlcmF0aW9ucyxcbiAgICAgIHtcbiAgICAgICAgLy8gQ2xvbmUtaW46IGBpbml0aWFsQ29udGV4dGAgc2VlZHMgdGhlIGZyZXNoIFNoYXJlZE1lbW9yeSB3aXRoIGFcbiAgICAgICAgLy8gdG9wLWxldmVsLW9ubHkgbWVyZ2Ug4oCUIG5lc3RlZCBvYmplY3RzIHdvdWxkIGFsaWFzIHRoZSBjYWxsZXIncyBjaGVja3BvaW50LlxuICAgICAgICBpbml0aWFsQ29udGV4dDogc3RydWN0dXJlZENsb25lKHBsYW4uY2hlY2twb2ludC5zaGFyZWRTdGF0ZSksXG4gICAgICAgIHByZXNlcnZlUmVjb3JkZXJzOiB0cnVlLFxuICAgICAgICAuLi4oZXhpc3RpbmdSdW50aW1lID8geyBleGlzdGluZ1J1bnRpbWUgfSA6IHt9KSxcbiAgICAgICAgcmVzdW1lOiBwbGFuLmVudHJ5LFxuICAgICAgfSxcbiAgICApO1xuICAgIC8vIEJlZm9yZSB0aGUgdHJhdmVyc2FsIG9uIHB1cnBvc2U6IGBvblJlc3VtZWAgcHJlY2VkZXMgYG9uUnVuU3RhcnRgLlxuICAgIGFubm91bmNlUmVzdW1lKHBsYW4sIHJlc3VtZUlucHV0LCB7XG4gICAgICBydW5JZDogdGhpcy5fY3VycmVudFJ1bklkLFxuICAgICAgZXhlY3V0aW9uQ291bnQ6IHRoaXMuX2V4ZWN1dGlvbkNvdW50ZXIudmFsdWUsXG4gICAgICBvYnNlcnZlcnM6IHRoaXMub2JzZXJ2ZXJzLFxuICAgIH0pO1xuXG4gICAgLy8gU2V0IEFGVEVSIGFsbCBzeW5jIHZhbGlkYXRpb24vbG9va3VwIHRocm93cyBhYm92ZSAobm90aGluZyBjYW4gbGVhayB0aGVcbiAgICAvLyBmbGFnKTsgbm8gYXdhaXQgYmV0d2VlbiB0aGUgdG9wLW9mLW1ldGhvZCBjaGVjayBhbmQgaGVyZSwgc28gcmFjZS1mcmVlLlxuICAgIHRoaXMuX2lzRXhlY3V0aW5nID0gdHJ1ZTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy50cmF2ZXJzZXIuZXhlY3V0ZSgpO1xuICAgICAgLy8gVGVybWluYWwgZmx1c2ggKFJGQy0wMDEgQmxvY2sgOCkg4oCUIHNhbWUgYm91bmRhcnkgY29udHJhY3QgYXMgcnVuKCkuXG4gICAgICB0aGlzLm9ic2VydmVycy5kZWZlcnJlZFRpZXI/LnRlcm1pbmFsRmx1c2goKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIHJldHVybiB0aGlzLnBhdXNlZE9yVGhyb3coZXJyb3IpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLl9pc0V4ZWN1dGluZyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc2V0dGxlIG9mIGEgbGVnIHRoYXQgdGhyZXc6IGZsdXNoIHRoZSBkZWZlcnJlZCB0aWVyICh0aGUgT1VURVJNT1NUXG4gICAqIGhhbmRsZXIg4oCUIGEgcGF1c2UgcmUtdGhyb3dzIHRocm91Z2ggc3ViZmxvdyB0cmF2ZXJzZXJzIHdpdGhvdXQgZXhpdFxuICAgKiBldmVudHMsIHNvIHBlci10cmF2ZXJzZXIgaG9va3Mgd291bGQgbWlzcyBpdCksIHRoZW4gdHVybiBhIHBhdXNlIGludG8gYVxuICAgKiBkZXRhY2hlZCBjaGVja3BvaW50IChgY2hlY2twb2ludC50c2ApIGFuZCBhIGBQYXVzZWRSZXN1bHRgOyBhbnl0aGluZyBlbHNlXG4gICAqIGlzIHJldGhyb3duLlxuICAgKi9cbiAgcHJpdmF0ZSBwYXVzZWRPclRocm93KGVycm9yOiB1bmtub3duKTogUGF1c2VkUmVzdWx0IHtcbiAgICB0aGlzLm9ic2VydmVycy5kZWZlcnJlZFRpZXI/LnRlcm1pbmFsRmx1c2goKTtcbiAgICBpZiAoaXNQYXVzZVNpZ25hbChlcnJvcikpIHtcbiAgICAgIHRoaXMubGFzdENoZWNrcG9pbnQgPSBidWlsZFBhdXNlQ2hlY2twb2ludChlcnJvciwgdGhpcy50cmF2ZXJzZXIsIHtcbiAgICAgICAgcnVuSWQ6IHRoaXMuX2N1cnJlbnRSdW5JZCxcbiAgICAgICAgZXhlY3V0aW9uQ291bnQ6IHRoaXMuX2V4ZWN1dGlvbkNvdW50ZXIudmFsdWUsXG4gICAgICAgIHZpc2l0Q291bnRzOiB0aGlzLl92aXNpdENvdW50cyxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHsgcGF1c2VkOiB0cnVlLCBjaGVja3BvaW50OiB0aGlzLmxhc3RDaGVja3BvaW50IH0gc2F0aXNmaWVzIFBhdXNlZFJlc3VsdDtcbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cblxuICAvKiogVGhlIHJlLWVudHJhbmN5IGd1YXJkOiBvbmUgZXhlY3V0b3IgPSBvbmUgaW4tZmxpZ2h0IGV4ZWN1dGlvbi4gKi9cbiAgcHJpdmF0ZSBhc3NlcnRJZGxlKG1ldGhvZDogJ3J1bicgfCAncmVzdW1lJyk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9pc0V4ZWN1dGluZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgRmxvd0NoYXJ0RXhlY3V0b3I6ICR7bWV0aG9kfSgpIGNhbGxlZCB3aGlsZSBhbm90aGVyIHJ1bigpL3Jlc3VtZSgpIGlzIGluIGZsaWdodCBvbiB0aGlzIGAgK1xuICAgICAgICAgICdleGVjdXRvci4gQW4gZXhlY3V0b3IgaG9sZHMgcGVyLXJ1biBzdGF0ZSAocnVuSWQsIHJlY29yZGVycywgY2hlY2twb2ludCkg4oCUIGNyZWF0ZSAnICtcbiAgICAgICAgICAnb25lIGV4ZWN1dG9yIHBlciBjb25jdXJyZW50IHJ1bi4gU2VlIGRvY3MvZ3VpZGVzL2V4ZWN1dGlvbi1tb2RlbC5tZC4nLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIDilIAgUmVjb3JkZXJzICh0aGUgcmVnaXN0ZXIgbGl2ZXMgaW4gYGF0dGFjaC50c2ApIOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBBdHRhY2ggYSBTY29wZVJlY29yZGVyIHRvIG9ic2VydmUgZGF0YSBvcGVyYXRpb25zIChyZWFkcywgd3JpdGVzLCBjb21taXRzKVxuICAgKiBvbiBldmVyeSBzdGFnZSBzY29wZS4gQ2FsbCBiZWZvcmUgcnVuKCkuICoqSWRlbXBvdGVudCBieSBgaWRgKiogKHJlcGxhY2VkLFxuICAgKiBuZXZlciBkdXBsaWNhdGVkKS4gYHsgZGVsaXZlcnk6ICdkZWZlcnJlZCcgfWAgbW92ZXMgaXQgb2ZmIHRoZSBob3QgcGF0aCDigJRcbiAgICogZGVsaXZlcmVkIGF0IHRoZSBuZXh0IG1pY3JvdGFzayBjaGVja3BvaW50OyByZS1hdHRhY2hpbmcgYW4gaWQgb24gdGhlXG4gICAqIG90aGVyIHRpZXIgU1dBUFMgdGllcnMgKGBkb2NzL2d1aWRlcy9vYnNlcnZlcnMtZGVmZXJyZWQubWRgKS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBleGVjdXRvci5hdHRhY2hTY29wZVJlY29yZGVyKG5ldyBNZXRyaWNSZWNvcmRlcigpKTtcbiAgICogZXhlY3V0b3IuYXR0YWNoU2NvcGVSZWNvcmRlcihuZXcgTWV0cmljUmVjb3JkZXIoJ215LW1ldHJpY3MnKSk7IC8vIHJlcGxhY2VzIHNhbWUgaWRcbiAgICogYGBgXG4gICAqL1xuICBhdHRhY2hTY29wZVJlY29yZGVyKHJlY29yZGVyOiBTY29wZVJlY29yZGVyLCBvcHRpb25zPzogQXR0YWNoUmVjb3JkZXJPcHRpb25zKTogdm9pZCB7XG4gICAgdGhpcy5vYnNlcnZlcnMuYXR0YWNoU2NvcGUocmVjb3JkZXIsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqIERldGFjaCBhbGwgc2NvcGUgUmVjb3JkZXJzIHdpdGggdGhlIGdpdmVuIElEIOKAlCBib3RoIGRlbGl2ZXJ5IHRpZXJzLiAqL1xuICBkZXRhY2hTY29wZVJlY29yZGVyKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLm9ic2VydmVycy5kZXRhY2hTY29wZShpZCk7XG4gIH1cblxuICAvKiogUmV0dXJucyBhIGRlZmVuc2l2ZSBjb3B5IG9mIGF0dGFjaGVkIHNjb3BlIFJlY29yZGVycyAoYm90aCB0aWVycykuICovXG4gIGdldFNjb3BlUmVjb3JkZXJzKCk6IFNjb3BlUmVjb3JkZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMub2JzZXJ2ZXJzLnNjb3BlTGlzdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCBhIEZsb3dSZWNvcmRlciB0byBvYnNlcnZlIGNvbnRyb2wgZmxvdyBldmVudHMuIEF1dG9tYXRpY2FsbHlcbiAgICogZW5hYmxlcyBuYXJyYXRpdmUuIE11c3QgYmUgY2FsbGVkIGJlZm9yZSBydW4oKS4gSWRlbXBvdGVudCBieSBgaWRgO1xuICAgKiBgeyBkZWxpdmVyeTogJ2RlZmVycmVkJyB9YCBhcyBmb3IgYGF0dGFjaFNjb3BlUmVjb3JkZXJgLlxuICAgKi9cbiAgYXR0YWNoRmxvd1JlY29yZGVyKHJlY29yZGVyOiBGbG93UmVjb3JkZXIsIG9wdGlvbnM/OiBBdHRhY2hSZWNvcmRlck9wdGlvbnMpOiB2b2lkIHtcbiAgICB0aGlzLm9ic2VydmVycy5hdHRhY2hGbG93KHJlY29yZGVyLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKiBEZXRhY2ggYWxsIEZsb3dSZWNvcmRlcnMgd2l0aCB0aGUgZ2l2ZW4gSUQg4oCUIGJvdGggZGVsaXZlcnkgdGllcnMuICovXG4gIGRldGFjaEZsb3dSZWNvcmRlcihpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5vYnNlcnZlcnMuZGV0YWNoRmxvdyhpZCk7XG4gIH1cblxuICAvKiogUmV0dXJucyBhIGRlZmVuc2l2ZSBjb3B5IG9mIGF0dGFjaGVkIEZsb3dSZWNvcmRlcnMgKGJvdGggdGllcnMpLiAqL1xuICBnZXRGbG93UmVjb3JkZXJzKCk6IEZsb3dSZWNvcmRlcltdIHtcbiAgICByZXR1cm4gdGhpcy5vYnNlcnZlcnMuZmxvd0xpc3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggYSByZWNvcmRlciB0byBldmVyeSBjaGFubmVsIChzY29wZSwgZmxvdywgZW1pdCkgaXQgaGFzIE9XTiBgb24qYFxuICAgKiBtZXRob2RzIGZvciDigJQgcHJlZmVycmVkIG92ZXIgc2luZ2xlLWNoYW5uZWwgY2FsbHMsIHdoZXJlIGZvcmdldHRpbmcgb25lXG4gICAqIHNpbGVudGx5IGxvc2VzIGV2ZW50cy4gSWRlbXBvdGVudCBieSBgaWRgIGFjcm9zcyBhbGwgY2hhbm5lbHM7IGEgZmxvd1xuICAgKiBtZXRob2QgZW5hYmxlcyB0aGUgbmFycmF0aXZlOyBgZGVsaXZlcnlgIGNvbWVzIGZyb20gdGhlIG9wdGlvbnMgb3IgdGhlXG4gICAqIHJlY29yZGVyJ3Mgb3duIGZpZWxkLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGF1ZGl0OiBDb21iaW5lZFJlY29yZGVyID0ge1xuICAgKiAgIGlkOiAnYXVkaXQnLFxuICAgKiAgIG9uV3JpdGU6IChlKSA9PiBsb2coJ3Njb3BlIHdyaXRlJywgZS5rZXkpLFxuICAgKiAgIG9uRGVjaXNpb246IChlKSA9PiBsb2coJ3JvdXRlZCB0bycsIGUuY2hvc2VuKSxcbiAgICogfTtcbiAgICogZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcihhdWRpdCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXR0YWNoQ29tYmluZWRSZWNvcmRlcihyZWNvcmRlcjogQ29tYmluZWRSZWNvcmRlciwgb3B0aW9ucz86IEF0dGFjaFJlY29yZGVyT3B0aW9ucyk6IHZvaWQge1xuICAgIHRoaXMub2JzZXJ2ZXJzLmF0dGFjaENvbWJpbmVkKHJlY29yZGVyLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKiBEZXRhY2ggYSBjb21iaW5lZCByZWNvcmRlciBmcm9tIGV2ZXJ5IGNoYW5uZWwgaXQgd2FzIGF0dGFjaGVkIHRvIChzYWZlIGlmIG5ldmVyIGF0dGFjaGVkKS4gKi9cbiAgZGV0YWNoQ29tYmluZWRSZWNvcmRlcihpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5kZXRhY2hTY29wZVJlY29yZGVyKGlkKTtcbiAgICB0aGlzLmRldGFjaEZsb3dSZWNvcmRlcihpZCk7XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIGFuIGBFbWl0UmVjb3JkZXJgIGZvciBgc2NvcGUuJGVtaXQobmFtZSwgcGF5bG9hZClgIGV2ZW50cy4gSXQgcmlkZXNcbiAgICogdGhlIHNjb3BlIGxpc3QsIHNvIGBvbkVtaXRgIGZpcmVzIGV4YWN0bHkgb25jZSBwZXIgZXZlbnQuIElkZW1wb3RlbnQgYnkgYGlkYC5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBleGVjdXRvci5hdHRhY2hFbWl0UmVjb3JkZXIoe1xuICAgKiAgIGlkOiAndG9rZW4tbWV0ZXInLFxuICAgKiAgIG9uRW1pdDogKGUpID0+IHtcbiAgICogICAgIGlmIChlLm5hbWUgPT09ICdhZ2VudGZvb3RwcmludC5sbG0udG9rZW5zJykgdHJhY2tUb2tlbnMoZS5wYXlsb2FkKTtcbiAgICogICB9LFxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhdHRhY2hFbWl0UmVjb3JkZXIocmVjb3JkZXI6IEVtaXRSZWNvcmRlciwgb3B0aW9ucz86IEF0dGFjaFJlY29yZGVyT3B0aW9ucyk6IHZvaWQge1xuICAgIHRoaXMuYXR0YWNoU2NvcGVSZWNvcmRlcihyZWNvcmRlciBhcyBTY29wZVJlY29yZGVyLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKiBEZXRhY2ggYW4gYEVtaXRSZWNvcmRlcmAgYnkgaWQuIFNhZmUgdG8gY2FsbCBpZiBuZXZlciBhdHRhY2hlZC4gKi9cbiAgZGV0YWNoRW1pdFJlY29yZGVyKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmRldGFjaFNjb3BlUmVjb3JkZXIoaWQpO1xuICB9XG5cbiAgLyoqIFJldHVybnMgYSBkZWZlbnNpdmUgY29weSBvZiBhdHRhY2hlZCByZWNvcmRlcnMgKGJvdGggdGllcnMpIHRoYXQgaW1wbGVtZW50IGBvbkVtaXRgLiAqL1xuICBnZXRFbWl0UmVjb3JkZXJzKCk6IEVtaXRSZWNvcmRlcltdIHtcbiAgICByZXR1cm4gdGhpcy5nZXRTY29wZVJlY29yZGVycygpLmZpbHRlcihcbiAgICAgIChyKTogciBpcyBFbWl0UmVjb3JkZXIgPT4gdHlwZW9mIChyIGFzIHsgb25FbWl0PzogdW5rbm93biB9KS5vbkVtaXQgPT09ICdmdW5jdGlvbicsXG4gICAgKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBEZXRhY2ggKFQ0KSDilIDilIDilIBcbiAgLy8gQmFyZS1leGVjdXRvciBlbnRyeSBwb2ludHMgZm9yIGZpcmUtYW5kLWZvcmdldCBjaGlsZCBjaGFydHMuIEZyb20gaW5zaWRlIGFcbiAgLy8gc3RhZ2UgdXNlIGBzY29wZS4kZGV0YWNoQW5kSm9pbkxhdGVyKC4uLilgIC8gYHNjb3BlLiRkZXRhY2hBbmRGb3JnZXQoLi4uKWAsXG4gIC8vIHdoaWNoIG1pbnQgcmVmSWRzIGZyb20gdGhlIGNhbGxpbmcgc3RhZ2U7IHRoZXNlIHVzZSBgX19leGVjdXRvcl9fYC5cblxuICAvKipcbiAgICogRGV0YWNoIGEgY2hpbGQgZmxvd2NoYXJ0IG9uIHRoZSBnaXZlbiBkcml2ZXIgYW5kIHJldHVybiBhIGBEZXRhY2hIYW5kbGVgXG4gICAqIHRoZSBjYWxsZXIgY2FuIGB3YWl0KClgIG9uIChQcm9taXNlKSBvciByZWFkIGAuc3RhdHVzYCBmcm9tIChzeW5jKS4gVGhlXG4gICAqIGRyaXZlciBpcyBSRVFVSVJFRCDigJQgdGhlcmUgaXMgbm8gbGlicmFyeSBkZWZhdWx0LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGltcG9ydCB7IG1pY3JvdGFza0JhdGNoRHJpdmVyIH0gZnJvbSAnZm9vdHByaW50anMvZGV0YWNoJztcbiAgICpcbiAgICogY29uc3QgZXhlYyA9IG5ldyBGbG93Q2hhcnRFeGVjdXRvcihwYXJlbnRDaGFydCk7XG4gICAqIGNvbnN0IGhhbmRsZSA9IGV4ZWMuZGV0YWNoQW5kSm9pbkxhdGVyKG1pY3JvdGFza0JhdGNoRHJpdmVyLCB0ZWxlbWV0cnlDaGFydCwgeyBldmVudDogJ3gnIH0pO1xuICAgKiBhd2FpdCBoYW5kbGUud2FpdCgpOyAvLyBvcHRpb25hbFxuICAgKiBgYGBcbiAgICovXG4gIGRldGFjaEFuZEpvaW5MYXRlcihcbiAgICBkcml2ZXI6IGltcG9ydCgnLi4vZGV0YWNoL3R5cGVzLmpzJykuRGV0YWNoRHJpdmVyLFxuICAgIGNoaWxkOiBpbXBvcnQoJy4uL2J1aWxkZXIvdHlwZXMuanMnKS5GbG93Q2hhcnQsXG4gICAgaW5wdXQ/OiB1bmtub3duLFxuICApOiBpbXBvcnQoJy4uL2RldGFjaC90eXBlcy5qcycpLkRldGFjaEhhbmRsZSB7XG4gICAgcmV0dXJuIF9kZXRhY2hBbmRKb2luTGF0ZXIoZHJpdmVyLCBjaGlsZCwgaW5wdXQsICdfX2V4ZWN1dG9yX18nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRhY2ggYSBjaGlsZCBmbG93Y2hhcnQgb24gdGhlIGdpdmVuIGRyaXZlciBhbmQgRElTQ0FSRCB0aGUgaGFuZGxlIOKAlCBmb3JcbiAgICogZmlyZS1hbmQtZm9yZ2V0IHNpZGUgZWZmZWN0cy4gQSBjaGlsZCdzIGVycm9yIGxhbmRzIG9uIHRoZSBkaXNjYXJkZWQgaGFuZGxlO1xuICAgKiBmb3Igb2JzZXJ2YWJsZSBkZXRhY2ggcHJlZmVyIGBkZXRhY2hBbmRKb2luTGF0ZXJgICsgYC53YWl0KCkuY2F0Y2goKWAuXG4gICAqL1xuICBkZXRhY2hBbmRGb3JnZXQoXG4gICAgZHJpdmVyOiBpbXBvcnQoJy4uL2RldGFjaC90eXBlcy5qcycpLkRldGFjaERyaXZlcixcbiAgICBjaGlsZDogaW1wb3J0KCcuLi9idWlsZGVyL3R5cGVzLmpzJykuRmxvd0NoYXJ0LFxuICAgIGlucHV0PzogdW5rbm93bixcbiAgKTogdm9pZCB7XG4gICAgX2RldGFjaEFuZEZvcmdldChkcml2ZXIsIGNoaWxkLCBpbnB1dCwgJ19fZXhlY3V0b3JfXycpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cnVjdHVyZWQgbmFycmF0aXZlIGVudHJpZXMgKHR5cGUsIHRleHQsIGRlcHRoKSDigJQgdGhlIG9uZSBwdWJsaWMgbmFycmF0aXZlXG4gICAqIEFQSTsgYC5tYXAoZSA9PiBlLnRleHQpYCBmb3IgYSBmbGF0IGBzdHJpbmdbXWAuXG4gICAqL1xuICBnZXROYXJyYXRpdmVFbnRyaWVzKCk6IENvbWJpbmVkTmFycmF0aXZlRW50cnlbXSB7XG4gICAgaWYgKHRoaXMub2JzZXJ2ZXJzLmNvbWJpbmVkUmVjb3JkZXIpIHtcbiAgICAgIHJldHVybiB0aGlzLm9ic2VydmVycy5jb21iaW5lZFJlY29yZGVyLmdldEVudHJpZXMoKTtcbiAgICB9XG4gICAgY29uc3QgZmxvd1NlbnRlbmNlcyA9IHRoaXMudHJhdmVyc2VyLmdldE5hcnJhdGl2ZSgpO1xuICAgIHJldHVybiBmbG93U2VudGVuY2VzLm1hcCgodGV4dCkgPT4gKHsgdHlwZTogJ3N0YWdlJyBhcyBjb25zdCwgdGV4dCwgZGVwdGg6IDAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgdGhlIGNoYXJ0LiBSZXNvbHZlcyB3aGVuIHRoZSBydW4gZmluaXNoZXMg4oCUIG9yIHBhdXNlcywgaWYgYVxuICAgKiBwYXVzYWJsZSBzdGFnZSByZXR1cm5lZCBkYXRhIChjaGVjayBgaXNQYXVzZWQoKWAgYWZ0ZXJ3YXJkKS5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgYHsgaW5wdXQsIGVudiB9YCDigJQgYGlucHV0YCBpcyB0aGUgZnJvemVuIGJ1c2luZXNzIGlucHV0XG4gICAqICAgKHJlYWQgaW4gYSBzdGFnZSB2aWEgYHNjb3BlLiRnZXRBcmdzKClgKTsgYGVudmAgaXMgaW5mcmFzdHJ1Y3R1cmUgY29udGV4dFxuICAgKiAgIGxpa2UgYHsgc2lnbmFsLCB0aW1lb3V0TXMsIHRyYWNlSWQgfWAgKHJlYWQgdmlhIGBzY29wZS4kZ2V0RW52KClgKS5cbiAgICpcbiAgICogQWZ0ZXIgaXQgcmVzb2x2ZXMsIHJlYWQgcmVzdWx0cyBvZmYgdGhlIGV4ZWN1dG9yOlxuICAgKiAtIGBnZXRTbmFwc2hvdCgpYCDigJQgZnVsbCBzdGF0ZSwgY29tbWl0IGxvZywgZXhlY3V0aW9uIHRyZWUuXG4gICAqIC0gYGdldE5hcnJhdGl2ZUVudHJpZXMoKWAg4oCUIHRoZSBwbGFpbi1FbmdsaXNoIHRyYWNlIChjYWxsIGBlbmFibGVOYXJyYXRpdmUoKWBcbiAgICogICBvciBhdHRhY2ggYSBgbmFycmF0aXZlKClgIHJlY29yZGVyIGZpcnN0KS5cbiAgICogLSBgaXNQYXVzZWQoKWAg4oCUIHRydWUgaWYgYSBzdGFnZSBwYXVzZWQ7IHRoZW4gdXNlIGBnZXRDaGVja3BvaW50KClgIC8gYHJlc3VtZSgpYC5cbiAgICpcbiAgICogT25lIHJ1biBhdCBhIHRpbWUgcGVyIGV4ZWN1dG9yIOKAlCBpdCBob2xkcyBwZXItcnVuIHN0YXRlIChydW5JZCwgcmVjb3JkZXJzLFxuICAgKiBjaGVja3BvaW50KS4gQ3JlYXRlIG9uZSBleGVjdXRvciBwZXIgY29uY3VycmVudCBydW4uXG4gICAqL1xuICBhc3luYyBydW4ob3B0aW9ucz86IFJ1bk9wdGlvbnMpOiBQcm9taXNlPEV4ZWN1dG9yUmVzdWx0PiB7XG4gICAgLy8gQSBmYWlsZWQgZW50cnkgbGVhdmVzIG5vIHNpZGUgZWZmZWN0czogdGhlIGd1YXJkIEZJUlNUICh0aGUgaW4tZmxpZ2h0XG4gICAgLy8gcnVuIHN0YXlzIHVudG91Y2hlZCksIHZhbGlkYXRpb24gYmVmb3JlIHRoZSB0aW1lb3V0IHRpbWVyIGV4aXN0cy5cbiAgICB0aGlzLmFzc2VydElkbGUoJ3J1bicpO1xuICAgIGxldCB2YWxpZGF0ZWRJbnB1dCA9IG9wdGlvbnM/LmlucHV0O1xuICAgIGlmICh2YWxpZGF0ZWRJbnB1dCAmJiB0aGlzLmZsb3dDaGFydEFyZ3MuZmxvd0NoYXJ0LmlucHV0U2NoZW1hKSB7XG4gICAgICB2YWxpZGF0ZWRJbnB1dCA9IHZhbGlkYXRlSW5wdXQodGhpcy5mbG93Q2hhcnRBcmdzLmZsb3dDaGFydC5pbnB1dFNjaGVtYSwgdmFsaWRhdGVkSW5wdXQpO1xuICAgIH1cblxuICAgIGxldCBzaWduYWwgPSBvcHRpb25zPy5zaWduYWw7XG4gICAgbGV0IHRpbWVvdXRJZDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgaWYgKG9wdGlvbnM/LnRpbWVvdXRNcyAmJiAhc2lnbmFsKSB7XG4gICAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgICAgc2lnbmFsID0gY29udHJvbGxlci5zaWduYWw7XG4gICAgICB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiBjb250cm9sbGVyLmFib3J0KG5ldyBFcnJvcihgRXhlY3V0aW9uIHRpbWVkIG91dCBhZnRlciAke29wdGlvbnMudGltZW91dE1zfW1zYCkpLFxuICAgICAgICBvcHRpb25zLnRpbWVvdXRNcyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5vYnNlcnZlcnMuY2xlYXJGb3JSdW4oKTsgLy8gbm8gY3Jvc3MtcnVuIGFjY3VtdWxhdGlvblxuICAgIHRoaXMubGFzdENoZWNrcG9pbnQgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5fZXhlY3V0aW9uQ291bnRlciA9IHsgdmFsdWU6IDAgfTtcbiAgICB0aGlzLl92aXNpdENvdW50cyA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLl9jdXJyZW50UnVuSWQgPSBnZW5lcmF0ZVJ1bklkKCk7XG4gICAgdGhpcy5faGFzUnVuQmVmb3JlID0gdHJ1ZTsgLy8gYSBsYXRlciByZXN1bWUoKSByZXVzZXMgdGhpcyBydW50aW1lXG4gICAgdGhpcy50cmF2ZXJzZXIgPSB0aGlzLmNyZWF0ZVRyYXZlcnNlcihcbiAgICAgIHNpZ25hbCxcbiAgICAgIHZhbGlkYXRlZElucHV0LFxuICAgICAgb3B0aW9ucz8uZW52LFxuICAgICAgb3B0aW9ucz8ubWF4RGVwdGgsXG4gICAgICBvcHRpb25zPy5tYXhJdGVyYXRpb25zLFxuICAgICk7XG4gICAgLy8gQWZ0ZXIgZXZlcnkgc3luYyB0aHJvdywgd2l0aCBubyBhd2FpdCBzaW5jZSB0aGUgZ3VhcmQ6IHJhY2UtZnJlZS5cbiAgICB0aGlzLl9pc0V4ZWN1dGluZyA9IHRydWU7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudHJhdmVyc2VyLmV4ZWN1dGUoKTtcbiAgICAgIC8vIFRlcm1pbmFsIGZsdXNoIChSRkMtMDAxIEJsb2NrIDgpOiBcIm9uZSBiZWF0IGJlaGluZFwiIG5ldmVyIGJlY29tZXMgXCJsb3N0IGF0IGV4aXRcIi5cbiAgICAgIHRoaXMub2JzZXJ2ZXJzLmRlZmVycmVkVGllcj8udGVybWluYWxGbHVzaCgpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgcmV0dXJuIHRoaXMucGF1c2VkT3JUaHJvdyhlcnJvcik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuX2lzRXhlY3V0aW5nID0gZmFsc2U7XG4gICAgICBpZiAodGltZW91dElkICE9PSB1bmRlZmluZWQpIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGbHVzaCB0aGUgZGVmZXJyZWQtb2JzZXJ2ZXIgYmFja2xvZywgdGhlbiBhd2FpdCBhc3luYyBsaXN0ZW5lciBjb21wbGV0aW9uc1xuICAgKiB1bmRlciBhIGRlYWRsaW5lIOKAlCBjYWxsIGJlZm9yZSBhIHNlcnZlcmxlc3MgcHJvY2VzcyBmcmVlemVzIG9yIGV4aXRzLlxuICAgKiBaZXJvcyB3aGVuIG5vIGRlZmVycmVkIG9ic2VydmVyIHdhcyBhdHRhY2hlZDsgYHBlbmRpbmcgPiAwYCByZXBvcnRzIHdoYXRcbiAgICogd2FzIHN0aWxsIG91dHN0YW5kaW5nIGF0IHRoZSBkZWFkbGluZS5cbiAgICovXG4gIGRyYWluT2JzZXJ2ZXJzKG9wdHM/OiB7IHRpbWVvdXRNcz86IG51bWJlciB9KTogUHJvbWlzZTxPYnNlcnZlckRyYWluUmVzdWx0PiB7XG4gICAgY29uc3QgdGllciA9IHRoaXMub2JzZXJ2ZXJzLmRlZmVycmVkVGllcjtcbiAgICBpZiAoIXRpZXIpIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBkb25lOiAwLCBmYWlsZWQ6IDAsIHBlbmRpbmc6IDAgfSk7XG4gICAgcmV0dXJuIHRpZXIuZHJhaW4ob3B0cyk7XG4gIH1cblxuICAvLyDilIDilIDilIAgSW50cm9zcGVjdGlvbiDilIDilIDilIBcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcnVudGltZSBzbmFwc2hvdC5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMucmVkYWN0ICBgdHJ1ZWAgc2VydmVzIGBzaGFyZWRTdGF0ZWAgKGFuZCBlYWNoIHN1YmZsb3cnc1xuICAgKiAgIGBnbG9iYWxDb250ZXh0YCkgZnJvbSB0aGUgcmVkYWN0ZWQgbWlycm9yIOKAlCB0aGUgc2FmZSB2aWV3IHRvIGV4cG9ydC4gQVxuICAgKiAgIG5vLW9wIHdpdGhvdXQgYSByZWRhY3Rpb24gcG9saWN5LiBUaGUgY29tbWl0IGxvZyBpcyByZWRhY3RlZCBhdCB3cml0ZVxuICAgKiAgIHRpbWUgcmVnYXJkbGVzcy4gRGVmYXVsdCBgZmFsc2VgLlxuICAgKlxuICAgKiAqKlRyZWF0IGBzaGFyZWRTdGF0ZWAgYXMgUkVBRC1PTkxZLioqIEluIHByb2R1Y3Rpb24gaXQgaXMgYSBsaXZlIHZpZXcgb2ZcbiAgICogZW5naW5lIG1lbW9yeTsgaW4gZGV2IG1vZGUgYSBkZWVwLWZyb3plbiBjbG9uZSwgc28gYSBtdXRhdGlvbiB0aHJvd3MuXG4gICAqL1xuICBnZXRTbmFwc2hvdChvcHRpb25zPzogeyByZWRhY3Q/OiBib29sZWFuIH0pOiBSdW50aW1lU25hcHNob3Qge1xuICAgIHJldHVybiBzZXJ2ZWRTbmFwc2hvdCh0aGlzLnRyYXZlcnNlciwgdGhpcy5vYnNlcnZlcnMsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBnZXRSdW50aW1lKCkge1xuICAgIHJldHVybiB0aGlzLnRyYXZlcnNlci5nZXRSdW50aW1lKCk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIHNldFJvb3RPYmplY3QocGF0aDogc3RyaW5nW10sIGtleTogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMudHJhdmVyc2VyLnNldFJvb3RPYmplY3QocGF0aCwga2V5LCB2YWx1ZSk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldEJyYW5jaElkcygpIHtcbiAgICByZXR1cm4gdGhpcy50cmF2ZXJzZXIuZ2V0QnJhbmNoSWRzKCk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldFJ1bnRpbWVSb290KCk6IFN0YWdlTm9kZSB7XG4gICAgcmV0dXJuIHRoaXMudHJhdmVyc2VyLmdldFJ1bnRpbWVSb290KCk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGdldFJ1bnRpbWVTdHJ1Y3R1cmUoKTogU2VyaWFsaXplZFBpcGVsaW5lU3RydWN0dXJlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy50cmF2ZXJzZXIuZ2V0UnVudGltZVN0cnVjdHVyZSgpO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBnZXRTdWJmbG93UmVzdWx0cygpOiBNYXA8c3RyaW5nLCBTdWJmbG93UmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMudHJhdmVyc2VyLmdldFN1YmZsb3dSZXN1bHRzKCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc3ViZmxvdyBtYW5pZmVzdCBmcm9tIGFuIGF0dGFjaGVkIE1hbmlmZXN0Rmxvd1JlY29yZGVyLlxuICAgKiBSZXR1cm5zIGVtcHR5IGFycmF5IGlmIG5vIE1hbmlmZXN0Rmxvd1JlY29yZGVyIGlzIGF0dGFjaGVkLlxuICAgKi9cbiAgZ2V0U3ViZmxvd01hbmlmZXN0KCk6IE1hbmlmZXN0RW50cnlbXSB7XG4gICAgY29uc3QgcmVjb3JkZXIgPSB0aGlzLm9ic2VydmVycy5mbG93UmVjb3JkZXJzLmZpbmQoKHIpID0+IHIgaW5zdGFuY2VvZiBNYW5pZmVzdEZsb3dSZWNvcmRlcikgYXNcbiAgICAgIHwgTWFuaWZlc3RGbG93UmVjb3JkZXJcbiAgICAgIHwgdW5kZWZpbmVkO1xuICAgIHJldHVybiByZWNvcmRlcj8uZ2V0TWFuaWZlc3QoKSA/PyBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBmdWxsIHNwZWMgZm9yIGEgZHluYW1pY2FsbHktcmVnaXN0ZXJlZCBzdWJmbG93LlxuICAgKiBSZXF1aXJlcyBhbiBhdHRhY2hlZCBNYW5pZmVzdEZsb3dSZWNvcmRlciB0aGF0IG9ic2VydmVkIHRoZSByZWdpc3RyYXRpb24uXG4gICAqL1xuICBnZXRTdWJmbG93U3BlYyhzdWJmbG93SWQ6IHN0cmluZyk6IHVua25vd24gfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5vYnNlcnZlcnMuZmxvd1JlY29yZGVycy5maW5kKChyKSA9PiByIGluc3RhbmNlb2YgTWFuaWZlc3RGbG93UmVjb3JkZXIpIGFzXG4gICAgICB8IE1hbmlmZXN0Rmxvd1JlY29yZGVyXG4gICAgICB8IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVjb3JkZXI/LmdldFNwZWMoc3ViZmxvd0lkKTtcbiAgfVxufVxuIl19
|