@workflow/core 5.0.0-beta.2 → 5.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attribute-changes.d.ts +7 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +22 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +41 -4
- package/dist/capture-stack.d.ts +16 -0
- package/dist/capture-stack.d.ts.map +1 -0
- package/dist/capture-stack.js +21 -0
- package/dist/class-serialization.d.ts +32 -0
- package/dist/class-serialization.d.ts.map +1 -1
- package/dist/class-serialization.js +37 -1
- package/dist/classify-error.d.ts +11 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +59 -6
- package/dist/context-errors.d.ts +27 -0
- package/dist/context-errors.d.ts.map +1 -0
- package/dist/context-errors.js +101 -0
- package/dist/context-violation-error.d.ts +97 -0
- package/dist/context-violation-error.d.ts.map +1 -0
- package/dist/context-violation-error.js +147 -0
- package/dist/create-hook.d.ts +40 -1
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +4 -3
- package/dist/define-hook.d.ts.map +1 -1
- package/dist/define-hook.js +20 -5
- package/dist/describe-error.d.ts +70 -0
- package/dist/describe-error.d.ts.map +1 -0
- package/dist/describe-error.js +165 -0
- package/dist/encryption.d.ts +22 -1
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +72 -27
- package/dist/events-consumer.d.ts +24 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +79 -16
- package/dist/flushable-stream.d.ts +10 -10
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +18 -13
- package/dist/global.d.ts +15 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/log-format.d.ts +25 -0
- package/dist/log-format.d.ts.map +1 -0
- package/dist/log-format.js +250 -0
- package/dist/logger.d.ts +28 -30
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +77 -31
- package/dist/private.d.ts +107 -2
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +80 -3
- package/dist/runtime/constants.d.ts +121 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +206 -8
- package/dist/runtime/get-port-lazy.d.ts +25 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -0
- package/dist/runtime/get-port-lazy.js +92 -0
- package/dist/runtime/get-world-lazy.d.ts +32 -0
- package/dist/runtime/get-world-lazy.d.ts.map +1 -0
- package/dist/runtime/get-world-lazy.js +56 -0
- package/dist/runtime/helpers.d.ts +50 -7
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +149 -31
- package/dist/runtime/replay-budget.d.ts +98 -0
- package/dist/runtime/replay-budget.d.ts.map +1 -0
- package/dist/runtime/replay-budget.js +191 -0
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +39 -23
- package/dist/runtime/run-id-time.d.ts +10 -0
- package/dist/runtime/run-id-time.d.ts.map +1 -0
- package/dist/runtime/run-id-time.js +31 -0
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +44 -9
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +4 -1
- package/dist/runtime/start.d.ts +30 -1
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +138 -20
- package/dist/runtime/step-executor.d.ts +108 -0
- package/dist/runtime/step-executor.d.ts.map +1 -0
- package/dist/runtime/step-executor.js +715 -0
- package/dist/runtime/step-handler.d.ts.map +1 -1
- package/dist/runtime/step-handler.js +715 -556
- package/dist/runtime/suspension-handler.d.ts +74 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +308 -116
- package/dist/runtime/wait-continuation.d.ts +84 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +92 -0
- package/dist/runtime/wait-until.d.ts +18 -0
- package/dist/runtime/wait-until.d.ts.map +1 -0
- package/dist/runtime/wait-until.js +42 -0
- package/dist/runtime/world-init.d.ts +75 -0
- package/dist/runtime/world-init.d.ts.map +1 -0
- package/dist/runtime/world-init.js +75 -0
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +47 -18
- package/dist/runtime.d.ts +11 -8
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1395 -319
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +1 -1
- package/dist/serialization/client.d.ts +17 -0
- package/dist/serialization/client.d.ts.map +1 -0
- package/dist/serialization/client.js +48 -0
- package/dist/serialization/codec-devalue.d.ts +14 -0
- package/dist/serialization/codec-devalue.d.ts.map +1 -0
- package/dist/serialization/codec-devalue.js +98 -0
- package/dist/serialization/codec.d.ts +106 -0
- package/dist/serialization/codec.d.ts.map +1 -0
- package/dist/serialization/codec.js +17 -0
- package/dist/serialization/compression.d.ts +104 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +260 -0
- package/dist/serialization/encryption.d.ts +33 -0
- package/dist/serialization/encryption.d.ts.map +1 -0
- package/dist/serialization/encryption.js +70 -0
- package/dist/serialization/errors.d.ts +34 -0
- package/dist/serialization/errors.d.ts.map +1 -0
- package/dist/serialization/errors.js +59 -0
- package/dist/serialization/format.d.ts +60 -0
- package/dist/serialization/format.d.ts.map +1 -0
- package/dist/serialization/format.js +97 -0
- package/dist/serialization/index.d.ts +19 -0
- package/dist/serialization/index.d.ts.map +1 -0
- package/dist/serialization/index.js +22 -0
- package/dist/serialization/reducers/class.d.ts +11 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -0
- package/dist/serialization/reducers/class.js +68 -0
- package/dist/serialization/reducers/common.d.ts +16 -0
- package/dist/serialization/reducers/common.d.ts.map +1 -0
- package/dist/serialization/reducers/common.js +417 -0
- package/dist/serialization/reducers/step-function.d.ts +35 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function.js +88 -0
- package/dist/serialization/step.d.ts +17 -0
- package/dist/serialization/step.d.ts.map +1 -0
- package/dist/serialization/step.js +48 -0
- package/dist/serialization/types.d.ts +253 -0
- package/dist/serialization/types.d.ts.map +1 -0
- package/dist/serialization/types.js +25 -0
- package/dist/serialization/workflow.d.ts +29 -0
- package/dist/serialization/workflow.d.ts.map +1 -0
- package/dist/serialization/workflow.js +54 -0
- package/dist/serialization-format.d.ts +15 -0
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +209 -11
- package/dist/serialization.d.ts +313 -214
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1430 -658
- package/dist/set-attributes.d.ts +13 -0
- package/dist/set-attributes.d.ts.map +1 -0
- package/dist/set-attributes.js +42 -0
- package/dist/sleep.d.ts.map +1 -1
- package/dist/sleep.js +3 -2
- package/dist/source-map.d.ts +5 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +102 -10
- package/dist/step/context-storage.d.ts +43 -0
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +1 -1
- package/dist/step/get-closure-vars.d.ts.map +1 -1
- package/dist/step/get-closure-vars.js +3 -2
- package/dist/step/get-step-metadata.d.ts.map +1 -1
- package/dist/step/get-step-metadata.js +3 -2
- package/dist/step/get-workflow-metadata.d.ts.map +1 -1
- package/dist/step/get-workflow-metadata.js +3 -2
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +49 -5
- package/dist/step-hydration-cache.d.ts +148 -0
- package/dist/step-hydration-cache.d.ts.map +1 -0
- package/dist/step-hydration-cache.js +171 -0
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +115 -21
- package/dist/symbols.d.ts +28 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +29 -1
- package/dist/telemetry/semantic-conventions.d.ts +30 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +21 -1
- package/dist/telemetry.d.ts +60 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +82 -4
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -1
- package/dist/util.d.ts +16 -6
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +25 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +3 -2
- package/dist/vm/script-cache.d.ts +28 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +140 -0
- package/dist/workflow/abort-controller.d.ts +65 -0
- package/dist/workflow/abort-controller.d.ts.map +1 -0
- package/dist/workflow/abort-controller.js +277 -0
- package/dist/workflow/attribute-dispatcher.d.ts +6 -0
- package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
- package/dist/workflow/attribute-dispatcher.js +48 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +23 -2
- package/dist/workflow/define-hook.d.ts +1 -1
- package/dist/workflow/define-hook.d.ts.map +1 -1
- package/dist/workflow/define-hook.js +8 -4
- package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
- package/dist/workflow/get-workflow-metadata.js +14 -3
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +207 -33
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +5 -3
- package/dist/workflow/set-attributes.d.ts +73 -0
- package/dist/workflow/set-attributes.d.ts.map +1 -0
- package/dist/workflow/set-attributes.js +65 -0
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +45 -8
- package/dist/workflow/world-init-stub.d.ts +15 -0
- package/dist/workflow/world-init-stub.d.ts.map +1 -0
- package/dist/workflow/world-init-stub.js +15 -0
- package/dist/workflow.d.ts +10 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +168 -49
- package/docs/api-reference/create-hook.mdx +38 -0
- package/docs/api-reference/create-webhook.mdx +1 -0
- package/docs/api-reference/experimental-set-attributes.mdx +65 -0
- package/docs/api-reference/fetch.mdx +5 -0
- package/docs/api-reference/index.mdx +3 -0
- package/docs/foundations/cancellation.mdx +459 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/idempotency.mdx +236 -11
- package/docs/foundations/index.mdx +3 -3
- package/docs/foundations/meta.json +3 -2
- package/docs/foundations/serialization.mdx +78 -42
- package/docs/foundations/starting-workflows.mdx +6 -2
- package/docs/foundations/streaming.mdx +14 -23
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +2 -2
- package/docs/how-it-works/encryption.mdx +2 -2
- package/docs/how-it-works/event-sourcing.mdx +2 -2
- package/docs/how-it-works/meta.json +2 -1
- package/package.json +22 -10
- package/docs/foundations/common-patterns.mdx +0 -265
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
import { types } from 'node:util';
|
|
2
|
+
import { EntityConflictError, FatalError, RetryableError, RunExpiredError, ThrottleError, TooEarlyError, WorkflowRuntimeError, } from '@workflow/errors';
|
|
3
|
+
import { pluralize, stepDisplayName } from '@workflow/utils';
|
|
4
|
+
import { SPEC_VERSION_CURRENT, SPEC_VERSION_SUPPORTS_COMPRESSION, } from '@workflow/world';
|
|
5
|
+
import { runtimeLogger, stepLogger } from '../logger.js';
|
|
6
|
+
import { getStepFunction } from '../private.js';
|
|
7
|
+
import { dehydrateStepError, dehydrateStepReturnValue, hydrateStepArguments, hydrateStepError, } from '../serialization.js';
|
|
8
|
+
import { contextStorage } from '../step/context-storage.js';
|
|
9
|
+
import * as Attribute from '../telemetry/semantic-conventions.js';
|
|
10
|
+
import { trace } from '../telemetry.js';
|
|
11
|
+
import { getErrorName, getErrorStack, normalizeUnknownError, promoteAbortErrorToFatal, } from '../types.js';
|
|
12
|
+
import { isOptimisticInlineStartEnabled, isOptimisticInlineStartExplicitlyDisabled, } from './constants.js';
|
|
13
|
+
import { getPortLazy } from './get-port-lazy.js';
|
|
14
|
+
import { memoizeEncryptionKey } from './helpers.js';
|
|
15
|
+
import { safeWaitUntil } from './wait-until.js';
|
|
16
|
+
const DEFAULT_STEP_MAX_RETRIES = 3;
|
|
17
|
+
/**
|
|
18
|
+
* Extract the inline delta from a step-terminal `events.create` result,
|
|
19
|
+
* if the World populated one. A delta is only meaningful when the caller
|
|
20
|
+
* requested it (`sinceCursor` was passed) and the World returned both
|
|
21
|
+
* `events` and a `cursor`; otherwise we return undefined and the caller
|
|
22
|
+
* falls back to the normal incremental `events.list`. `hasMore` defaults
|
|
23
|
+
* to false (single page) when the World omits it.
|
|
24
|
+
*/
|
|
25
|
+
function extractInlineDelta(result, requested) {
|
|
26
|
+
if (!requested)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (!result.events || result.cursor === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
return {
|
|
31
|
+
events: result.events,
|
|
32
|
+
cursor: result.cursor,
|
|
33
|
+
hasMore: result.hasMore ?? false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Executes a single step: creates step_started event, hydrates input,
|
|
38
|
+
* runs the step function, creates step_completed/step_failed/step_retrying events.
|
|
39
|
+
*
|
|
40
|
+
* Does NOT queue workflow continuation messages — the caller decides what to do next.
|
|
41
|
+
* Used by both the V1 step handler and the V2 combined handler.
|
|
42
|
+
*/
|
|
43
|
+
export async function executeStep(params) {
|
|
44
|
+
const { world, workflowRunId, workflowName, workflowStartedAt, stepId, stepName, } = params;
|
|
45
|
+
const isVercel = process.env.VERCEL_URL !== undefined;
|
|
46
|
+
// Gate payload compression on the run's specVersion: only runs marked
|
|
47
|
+
// as possibly containing compressed payloads (spec >= 5) get gzip data.
|
|
48
|
+
const compression = (params.runSpecVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION;
|
|
49
|
+
const spanName = `step.execute ${stepDisplayName(stepName)}`;
|
|
50
|
+
return trace(spanName, {}, async (span) => {
|
|
51
|
+
span?.setAttributes({
|
|
52
|
+
...Attribute.StepName(stepName),
|
|
53
|
+
...Attribute.WorkflowName(workflowName),
|
|
54
|
+
...Attribute.WorkflowRunId(workflowRunId),
|
|
55
|
+
...Attribute.StepId(stepId),
|
|
56
|
+
});
|
|
57
|
+
// Memoized accessor for the per-run encryption key. The first caller
|
|
58
|
+
// (input hydration on the success path, or one of the early-return
|
|
59
|
+
// dehydrateStepError paths if step_started fails) triggers the actual
|
|
60
|
+
// fetch / HKDF derivation; subsequent callers await the cached promise.
|
|
61
|
+
const getEncryptionKey = memoizeEncryptionKey(world, workflowRunId);
|
|
62
|
+
const stepFn = getStepFunction(stepName);
|
|
63
|
+
if (!stepFn || typeof stepFn !== 'function') {
|
|
64
|
+
// Step function not registered — fail the step immediately (not the run).
|
|
65
|
+
// This matches the V1 step handler pattern: create step_failed event so
|
|
66
|
+
// the workflow can handle it gracefully via try/catch in user code.
|
|
67
|
+
const errorMessage = `Step "${stepName}" is not registered in the current deployment. This usually indicates a build or bundling issue that caused the step to not be included in the deployment.`;
|
|
68
|
+
runtimeLogger.error('Step function not registered, failing step', {
|
|
69
|
+
workflowRunId,
|
|
70
|
+
stepName,
|
|
71
|
+
stepId,
|
|
72
|
+
});
|
|
73
|
+
// On the lazy inline path the suspension handler deferred this step's
|
|
74
|
+
// `step_created`, expecting executeStep to materialize the step via a
|
|
75
|
+
// lazy `step_started` carrying its input. We never get that far for an
|
|
76
|
+
// unregistered step, so the step entity does not exist yet — writing
|
|
77
|
+
// `step_failed` straight away would hit the world's "step must exist"
|
|
78
|
+
// ordering guard and wedge the run. Send the lazy `step_started` first
|
|
79
|
+
// (it creates the step + synthetic `step_created` atomically and keeps
|
|
80
|
+
// replay correct), then fail it below. This also preserves the
|
|
81
|
+
// exactly-one-owner guarantee: a concurrent handler that won the create
|
|
82
|
+
// makes our lazy `step_started` reject with EntityConflictError → we
|
|
83
|
+
// return `skipped` and never write the failure twice.
|
|
84
|
+
if (params.lazyStepInput !== undefined) {
|
|
85
|
+
try {
|
|
86
|
+
// Turbo: this lazy `step_started` must not precede the backgrounded
|
|
87
|
+
// `run_started`. Order it after the run-ready barrier (best-effort —
|
|
88
|
+
// a barrier rejection means the run doesn't exist, and the create
|
|
89
|
+
// below surfaces the real error). No-op outside turbo.
|
|
90
|
+
if (params.runReadyBarrier) {
|
|
91
|
+
await params.runReadyBarrier.catch(() => { });
|
|
92
|
+
}
|
|
93
|
+
await world.events.create(workflowRunId, {
|
|
94
|
+
eventType: 'step_started',
|
|
95
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
96
|
+
correlationId: stepId,
|
|
97
|
+
eventData: { stepName, workflowName, input: params.lazyStepInput },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (startErr) {
|
|
101
|
+
if (EntityConflictError.is(startErr)) {
|
|
102
|
+
return { type: 'skipped' };
|
|
103
|
+
}
|
|
104
|
+
if (RunExpiredError.is(startErr)) {
|
|
105
|
+
return { type: 'gone' };
|
|
106
|
+
}
|
|
107
|
+
throw startErr;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await world.events.create(workflowRunId, {
|
|
112
|
+
eventType: 'step_failed',
|
|
113
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
114
|
+
correlationId: stepId,
|
|
115
|
+
eventData: {
|
|
116
|
+
stepName,
|
|
117
|
+
error: await dehydrateStepError(new FatalError(errorMessage), workflowRunId, await getEncryptionKey(), [], globalThis, compression),
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (stepFailErr) {
|
|
122
|
+
if (EntityConflictError.is(stepFailErr)) {
|
|
123
|
+
return { type: 'skipped' };
|
|
124
|
+
}
|
|
125
|
+
throw stepFailErr;
|
|
126
|
+
}
|
|
127
|
+
span?.setAttributes({
|
|
128
|
+
...Attribute.StepStatus('failed'),
|
|
129
|
+
...Attribute.StepFatalError(true),
|
|
130
|
+
});
|
|
131
|
+
return { type: 'failed' };
|
|
132
|
+
}
|
|
133
|
+
const maxRetries = stepFn.maxRetries ?? DEFAULT_STEP_MAX_RETRIES;
|
|
134
|
+
span?.setAttributes({
|
|
135
|
+
...Attribute.StepMaxRetries(maxRetries),
|
|
136
|
+
});
|
|
137
|
+
// Maps a `step_started` rejection to a terminal StepExecutionResult,
|
|
138
|
+
// shared by the await path (below) and the optimistic-start reconciliation.
|
|
139
|
+
// Returns undefined when the error is not one we translate (caller rethrows).
|
|
140
|
+
const startErrorToResult = (err) => {
|
|
141
|
+
if (ThrottleError.is(err)) {
|
|
142
|
+
const retryAfter = Math.max(1, typeof err.retryAfter === 'number' ? err.retryAfter : 1);
|
|
143
|
+
runtimeLogger.info('Throttled on step_started, deferring', {
|
|
144
|
+
retryAfterSeconds: retryAfter,
|
|
145
|
+
});
|
|
146
|
+
return { type: 'throttled', timeoutSeconds: retryAfter };
|
|
147
|
+
}
|
|
148
|
+
if (RunExpiredError.is(err)) {
|
|
149
|
+
runtimeLogger.info(`Workflow run "${workflowRunId}" has already completed, skipping step "${stepId}": ${err.message}`);
|
|
150
|
+
return { type: 'gone' };
|
|
151
|
+
}
|
|
152
|
+
if (EntityConflictError.is(err)) {
|
|
153
|
+
runtimeLogger.debug('Step in terminal state, skipping', {
|
|
154
|
+
stepName,
|
|
155
|
+
stepId,
|
|
156
|
+
workflowRunId,
|
|
157
|
+
error: err instanceof Error ? err.message : String(err),
|
|
158
|
+
});
|
|
159
|
+
span?.setAttributes({
|
|
160
|
+
...Attribute.StepSkipped(true),
|
|
161
|
+
...Attribute.StepSkipReason('completed'),
|
|
162
|
+
});
|
|
163
|
+
return { type: 'skipped' };
|
|
164
|
+
}
|
|
165
|
+
if (TooEarlyError.is(err)) {
|
|
166
|
+
const timeoutSeconds = Math.max(1, err.retryAfter ?? 1);
|
|
167
|
+
runtimeLogger.debug('Step retryAfter timestamp not yet reached', {
|
|
168
|
+
stepName,
|
|
169
|
+
stepId,
|
|
170
|
+
timeoutSeconds,
|
|
171
|
+
});
|
|
172
|
+
return { type: 'retry', timeoutSeconds };
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
};
|
|
176
|
+
// Optimistic inline start: when we hold the step input locally (lazy inline
|
|
177
|
+
// path) and the optimization is enabled, fire `step_started` WITHOUT
|
|
178
|
+
// awaiting and run the body against locally-synthesized state. A lazy step
|
|
179
|
+
// is always brand-new ⇒ attempt 1, no prior error, started now — so we
|
|
180
|
+
// don't need the server round-trip to begin. We reconcile the in-flight
|
|
181
|
+
// `step_started` before any terminal write (`reconcileOptimisticStart`): if
|
|
182
|
+
// it lost the atomic create-claim (409) or the run is gone/throttled, we
|
|
183
|
+
// discard the body result. Running the body before confirming ownership can
|
|
184
|
+
// execute a step more than once when handlers race — inline step bodies
|
|
185
|
+
// must be idempotent; disable via WORKFLOW_OPTIMISTIC_INLINE_START=0.
|
|
186
|
+
//
|
|
187
|
+
// Turbo mode passes `forceOptimisticStart` to enable this regardless of the
|
|
188
|
+
// env flag (its single-handler guarantee removes the race). But it still
|
|
189
|
+
// defers to an *explicit* `WORKFLOW_OPTIMISTIC_INLINE_START=0`: forced
|
|
190
|
+
// optimistic start runs the body before `step_started`/`run_started` is
|
|
191
|
+
// confirmed, which is exactly the property an operator opts out of with that
|
|
192
|
+
// flag, so an explicit opt-out wins over turbo's force.
|
|
193
|
+
const optimisticStart = params.lazyStepInput !== undefined &&
|
|
194
|
+
(isOptimisticInlineStartEnabled() ||
|
|
195
|
+
(params.forceOptimisticStart === true &&
|
|
196
|
+
!isOptimisticInlineStartExplicitlyDisabled()));
|
|
197
|
+
let step;
|
|
198
|
+
// Settled outcome of the in-flight optimistic `step_started`. Handlers are
|
|
199
|
+
// attached synchronously (`.then(ok, err)`) so a fast rejection never
|
|
200
|
+
// surfaces as an unhandledRejection while the body runs.
|
|
201
|
+
let optimisticStartSettled;
|
|
202
|
+
// Await the optimistic `step_started` outcome and translate a lost race /
|
|
203
|
+
// terminal run / throttle into a result that short-circuits the body
|
|
204
|
+
// output. Returns undefined when we own the step and may write its terminal
|
|
205
|
+
// event. A non-translatable rejection is rethrown (so a transient
|
|
206
|
+
// step_started failure propagates to the queue handler for redelivery,
|
|
207
|
+
// exactly as on the await path). Idempotent — safe to call more than once.
|
|
208
|
+
const reconcileOptimisticStart = async () => {
|
|
209
|
+
if (!optimisticStartSettled)
|
|
210
|
+
return undefined;
|
|
211
|
+
const settled = await optimisticStartSettled;
|
|
212
|
+
if (settled.ok)
|
|
213
|
+
return undefined;
|
|
214
|
+
const mapped = startErrorToResult(settled.err);
|
|
215
|
+
if (!mapped)
|
|
216
|
+
throw settled.err;
|
|
217
|
+
return mapped;
|
|
218
|
+
};
|
|
219
|
+
if (optimisticStart) {
|
|
220
|
+
// Chain the lazy `step_started` on the run-ready barrier (turbo mode):
|
|
221
|
+
// the step can't be created before its run exists, but the body below
|
|
222
|
+
// runs immediately against synthesized state, so the `run_started`
|
|
223
|
+
// round-trip overlaps the body rather than blocking it. Outside turbo the
|
|
224
|
+
// barrier is undefined and this is a plain create.
|
|
225
|
+
const startedPromise = (params.runReadyBarrier ?? Promise.resolve()).then(() => world.events.create(workflowRunId, {
|
|
226
|
+
eventType: 'step_started',
|
|
227
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
228
|
+
correlationId: stepId,
|
|
229
|
+
eventData: { stepName, workflowName, input: params.lazyStepInput },
|
|
230
|
+
}));
|
|
231
|
+
optimisticStartSettled = startedPromise.then(() => ({ ok: true }), (err) => ({ ok: false, err }));
|
|
232
|
+
const now = new Date();
|
|
233
|
+
step = {
|
|
234
|
+
runId: workflowRunId,
|
|
235
|
+
stepId,
|
|
236
|
+
stepName,
|
|
237
|
+
status: 'running',
|
|
238
|
+
input: params.lazyStepInput,
|
|
239
|
+
attempt: 1,
|
|
240
|
+
startedAt: now,
|
|
241
|
+
createdAt: now,
|
|
242
|
+
updatedAt: now,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// step_started validates state and returns the step entity. On the lazy
|
|
247
|
+
// inline path we also carry the step `input` so the world creates the
|
|
248
|
+
// step on the fly (no separate step_created round-trip). The world's
|
|
249
|
+
// atomic create-claim makes this exactly-one-owner: a concurrent loser
|
|
250
|
+
// gets EntityConflictError, mapped to `{ type: 'skipped' }`, so it never
|
|
251
|
+
// runs the body. When `lazyStepInput` is absent this is the legacy
|
|
252
|
+
// step_started (step already created, no payload).
|
|
253
|
+
try {
|
|
254
|
+
const startResult = await world.events.create(workflowRunId, {
|
|
255
|
+
eventType: 'step_started',
|
|
256
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
257
|
+
correlationId: stepId,
|
|
258
|
+
eventData: params.lazyStepInput !== undefined
|
|
259
|
+
? { stepName, workflowName, input: params.lazyStepInput }
|
|
260
|
+
: { stepName },
|
|
261
|
+
});
|
|
262
|
+
if (!startResult.step) {
|
|
263
|
+
throw new WorkflowRuntimeError(`step_started event for "${stepId}" did not return step entity`);
|
|
264
|
+
}
|
|
265
|
+
step = startResult.step;
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
const mapped = startErrorToResult(err);
|
|
269
|
+
if (mapped)
|
|
270
|
+
return mapped;
|
|
271
|
+
throw err;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
runtimeLogger.debug('Step execution details', {
|
|
275
|
+
stepName,
|
|
276
|
+
stepId: step.stepId,
|
|
277
|
+
status: step.status,
|
|
278
|
+
attempt: step.attempt,
|
|
279
|
+
});
|
|
280
|
+
span?.setAttributes({
|
|
281
|
+
...Attribute.StepStatus(step.status),
|
|
282
|
+
});
|
|
283
|
+
let result;
|
|
284
|
+
// Check max retries AFTER step_started (attempt was just incremented).
|
|
285
|
+
// Only enforce when the step has a previous error — this distinguishes
|
|
286
|
+
// actual retries (failed → retry) from concurrent starts (V2 inline
|
|
287
|
+
// execution loop can cause multiple handlers to step_started the same
|
|
288
|
+
// step simultaneously, inflating the attempt counter without any failure).
|
|
289
|
+
if (step.attempt > maxRetries + 1 && step.error) {
|
|
290
|
+
const retryCount = step.attempt - 1;
|
|
291
|
+
const errorMessage = `Step "${stepName}" exceeded max retries (${retryCount} ${pluralize('retry', 'retries', retryCount)})`;
|
|
292
|
+
stepLogger.error('Step exceeded max retries', {
|
|
293
|
+
workflowRunId,
|
|
294
|
+
stepName,
|
|
295
|
+
retryCount,
|
|
296
|
+
});
|
|
297
|
+
// Preserve the prior attempt's serialized error as the cause so the
|
|
298
|
+
// underlying failure is recoverable from `step.error.cause` after
|
|
299
|
+
// hydration, without forcing consumers to walk the step_retrying
|
|
300
|
+
// event history. Best-effort: if hydration of the prior `step.error`
|
|
301
|
+
// throws, fall back to a FatalError without cause.
|
|
302
|
+
const wrappedError = new FatalError(errorMessage);
|
|
303
|
+
if (step.error != null) {
|
|
304
|
+
try {
|
|
305
|
+
wrappedError.cause = await hydrateStepError(step.error, workflowRunId, await getEncryptionKey());
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Ignore — best-effort cause attachment.
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
await world.events.create(workflowRunId, {
|
|
313
|
+
eventType: 'step_failed',
|
|
314
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
315
|
+
correlationId: stepId,
|
|
316
|
+
eventData: {
|
|
317
|
+
stepName,
|
|
318
|
+
error: await dehydrateStepError(wrappedError, workflowRunId, await getEncryptionKey(), [], globalThis, compression),
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
if (EntityConflictError.is(err)) {
|
|
324
|
+
runtimeLogger.info('Tried failing step, but step has already finished.', {
|
|
325
|
+
workflowRunId,
|
|
326
|
+
stepId,
|
|
327
|
+
stepName,
|
|
328
|
+
message: err.message,
|
|
329
|
+
});
|
|
330
|
+
return { type: 'skipped' };
|
|
331
|
+
}
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
span?.setAttributes({
|
|
335
|
+
...Attribute.StepStatus('failed'),
|
|
336
|
+
...Attribute.StepRetryExhausted(true),
|
|
337
|
+
});
|
|
338
|
+
return { type: 'failed' };
|
|
339
|
+
}
|
|
340
|
+
// Ops that must be durably committed before step completion (e.g. a
|
|
341
|
+
// step-initiated abort's hook_received event). See StepContext. Declared
|
|
342
|
+
// outside the try so the failure path below can also drain them.
|
|
343
|
+
const preCompletionOps = [];
|
|
344
|
+
try {
|
|
345
|
+
const attempt = step.attempt;
|
|
346
|
+
if (!step.startedAt) {
|
|
347
|
+
throw new WorkflowRuntimeError(`Step "${stepId}" has no "startedAt" timestamp`);
|
|
348
|
+
}
|
|
349
|
+
const stepStartedAt = step.startedAt;
|
|
350
|
+
const ops = [];
|
|
351
|
+
// Use the provided encryption key when available, otherwise resolve
|
|
352
|
+
// through the memoized accessor declared at the top of this trace.
|
|
353
|
+
const encryptionKey = params.encryptionKey ?? (await getEncryptionKey());
|
|
354
|
+
const hydratedInput = await trace('step.hydrate', {}, async (hydrateSpan) => {
|
|
355
|
+
const startTime = Date.now();
|
|
356
|
+
const hydrated = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops, globalThis, {}, params.workflowDeploymentId);
|
|
357
|
+
const durationMs = Date.now() - startTime;
|
|
358
|
+
hydrateSpan?.setAttributes({
|
|
359
|
+
...Attribute.StepArgumentsCount(hydrated.args.length),
|
|
360
|
+
...Attribute.QueueDeserializeTimeMs(durationMs),
|
|
361
|
+
});
|
|
362
|
+
return hydrated;
|
|
363
|
+
});
|
|
364
|
+
const args = hydratedInput.args;
|
|
365
|
+
const thisVal = hydratedInput.thisVal ?? null;
|
|
366
|
+
const port = isVercel ? undefined : await getPortLazy();
|
|
367
|
+
const executionStartTime = Date.now();
|
|
368
|
+
result = await trace('step.execute', {}, async () => {
|
|
369
|
+
return await contextStorage.run({
|
|
370
|
+
stepMetadata: {
|
|
371
|
+
stepName,
|
|
372
|
+
stepId,
|
|
373
|
+
stepStartedAt: new Date(+stepStartedAt),
|
|
374
|
+
attempt,
|
|
375
|
+
},
|
|
376
|
+
workflowMetadata: {
|
|
377
|
+
workflowName,
|
|
378
|
+
workflowRunId,
|
|
379
|
+
workflowStartedAt: new Date(+workflowStartedAt),
|
|
380
|
+
url: isVercel
|
|
381
|
+
? `https://${process.env.VERCEL_URL}`
|
|
382
|
+
: `http://localhost:${port ?? 3000}`,
|
|
383
|
+
features: { encryption: !!encryptionKey },
|
|
384
|
+
},
|
|
385
|
+
workflowDeploymentId: params.workflowDeploymentId,
|
|
386
|
+
ops,
|
|
387
|
+
preCompletionOps,
|
|
388
|
+
closureVars: hydratedInput.closureVars,
|
|
389
|
+
encryptionKey,
|
|
390
|
+
}, () => stepFn.apply(thisVal, args));
|
|
391
|
+
});
|
|
392
|
+
const executionTimeMs = Date.now() - executionStartTime;
|
|
393
|
+
span?.setAttributes({
|
|
394
|
+
...Attribute.QueueExecutionTimeMs(executionTimeMs),
|
|
395
|
+
});
|
|
396
|
+
result = await trace('step.dehydrate', {}, async (dehydrateSpan) => {
|
|
397
|
+
const startTime = Date.now();
|
|
398
|
+
const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops, globalThis, false, false, compression);
|
|
399
|
+
const durationMs = Date.now() - startTime;
|
|
400
|
+
dehydrateSpan?.setAttributes({
|
|
401
|
+
...Attribute.QueueSerializeTimeMs(durationMs),
|
|
402
|
+
...Attribute.StepResultType(typeof dehydrated),
|
|
403
|
+
});
|
|
404
|
+
return dehydrated;
|
|
405
|
+
});
|
|
406
|
+
// Flush pending ops (stream writes, etc.) with a short inline wait.
|
|
407
|
+
// Now that WorkflowServerWritableStream flushes synchronously on
|
|
408
|
+
// each write (not via setTimeout), the flushablePipe's pendingOps
|
|
409
|
+
// accurately reflects whether data has reached the server. Most ops
|
|
410
|
+
// settle within ~200ms (100ms lock-release polling + HTTP flush).
|
|
411
|
+
// If ops don't settle in 500ms (e.g., WritableStream kept open
|
|
412
|
+
// across steps), waitUntil handles the rest.
|
|
413
|
+
let opsSettled = true;
|
|
414
|
+
if (ops.length > 0) {
|
|
415
|
+
const opsPromise = Promise.all(ops);
|
|
416
|
+
// The race below surfaces failures inline when ops settle quickly;
|
|
417
|
+
// if the 500ms timeout wins, the failure is only observed here. The
|
|
418
|
+
// promise handed to waitUntil must never reject (an unconsumed
|
|
419
|
+
// waitUntil rejection crashes the process as unhandledRejection),
|
|
420
|
+
// so unexpected failures are logged instead.
|
|
421
|
+
safeWaitUntil(opsPromise, (err) => {
|
|
422
|
+
runtimeLogger.warn('Background flush of step stream ops failed', {
|
|
423
|
+
workflowRunId,
|
|
424
|
+
stepId,
|
|
425
|
+
error: err instanceof Error ? err.message : String(err),
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
opsSettled = await Promise.race([
|
|
429
|
+
opsPromise.then(() => true, (err) => {
|
|
430
|
+
// Ignore expected client disconnect errors (e.g., browser
|
|
431
|
+
// refresh during streaming)
|
|
432
|
+
const isAbortError = err?.name === 'AbortError' || err?.name === 'ResponseAborted';
|
|
433
|
+
if (isAbortError)
|
|
434
|
+
return true;
|
|
435
|
+
throw err;
|
|
436
|
+
}),
|
|
437
|
+
new Promise((r) => setTimeout(() => r(false), 500)),
|
|
438
|
+
]);
|
|
439
|
+
}
|
|
440
|
+
// Optimistic start: the body ran before `step_started` was confirmed.
|
|
441
|
+
// Reconcile it now — if we lost the create-claim (or the run is
|
|
442
|
+
// gone/throttled) discard this result and don't write step_completed.
|
|
443
|
+
// Reconcile before draining preCompletionOps: a discarded result means
|
|
444
|
+
// the winning handler owns the outcome (and re-fires any abort
|
|
445
|
+
// idempotently), so there's no point paying the abort-commit latency.
|
|
446
|
+
if (optimisticStart) {
|
|
447
|
+
const reconcile = await reconcileOptimisticStart();
|
|
448
|
+
if (reconcile)
|
|
449
|
+
return reconcile;
|
|
450
|
+
}
|
|
451
|
+
// Commit must-be-durable ops (e.g. a step-initiated abort's
|
|
452
|
+
// hook_received event) before writing step_completed, so any workflow
|
|
453
|
+
// continuation triggered by that event observes the abort rather than
|
|
454
|
+
// racing it. These ops swallow their own errors, so awaiting only
|
|
455
|
+
// enforces ordering (the `.catch()` defends the no-reject contract on
|
|
456
|
+
// StepContext.preCompletionOps).
|
|
457
|
+
//
|
|
458
|
+
// Tradeoff: correctness requires the hook be durable before completion,
|
|
459
|
+
// so — unlike the background `ops` flush above — this cannot be capped
|
|
460
|
+
// with a resolve-on-timeout race. A slow resume therefore adds its
|
|
461
|
+
// latency to a step that aborts a controller, and a true hang holds
|
|
462
|
+
// completion until the platform/queue execution timeout fires; the queue
|
|
463
|
+
// then redelivers and the step retries, re-firing the abort idempotently.
|
|
464
|
+
if (preCompletionOps.length > 0) {
|
|
465
|
+
await Promise.all(preCompletionOps).catch(() => { });
|
|
466
|
+
}
|
|
467
|
+
// Create step_completed event. When the caller supplied a
|
|
468
|
+
// sinceCursor (inline sequential execution), thread it through so a
|
|
469
|
+
// supporting World returns the event-log delta on the result,
|
|
470
|
+
// letting the inline loop skip the next events.list round-trip.
|
|
471
|
+
let stepCompleted409 = false;
|
|
472
|
+
const completedResult = await world.events
|
|
473
|
+
.create(workflowRunId, {
|
|
474
|
+
eventType: 'step_completed',
|
|
475
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
476
|
+
correlationId: stepId,
|
|
477
|
+
eventData: {
|
|
478
|
+
stepName,
|
|
479
|
+
workflowName,
|
|
480
|
+
result: result,
|
|
481
|
+
},
|
|
482
|
+
}, params.inlineDeltaSinceCursor !== undefined
|
|
483
|
+
? { sinceCursor: params.inlineDeltaSinceCursor }
|
|
484
|
+
: undefined)
|
|
485
|
+
.catch((err) => {
|
|
486
|
+
if (EntityConflictError.is(err)) {
|
|
487
|
+
runtimeLogger.info('Tried completing step, but step has already finished.', {
|
|
488
|
+
workflowRunId,
|
|
489
|
+
stepId,
|
|
490
|
+
stepName,
|
|
491
|
+
message: err.message,
|
|
492
|
+
});
|
|
493
|
+
stepCompleted409 = true;
|
|
494
|
+
return undefined;
|
|
495
|
+
}
|
|
496
|
+
throw err;
|
|
497
|
+
});
|
|
498
|
+
if (stepCompleted409) {
|
|
499
|
+
return { type: 'skipped' };
|
|
500
|
+
}
|
|
501
|
+
const inlineDelta = completedResult
|
|
502
|
+
? extractInlineDelta(completedResult, params.inlineDeltaSinceCursor !== undefined)
|
|
503
|
+
: undefined;
|
|
504
|
+
span?.setAttributes({
|
|
505
|
+
...Attribute.StepStatus('completed'),
|
|
506
|
+
...Attribute.StepResultType(typeof result),
|
|
507
|
+
});
|
|
508
|
+
if (ops.length > 0) {
|
|
509
|
+
stepLogger.debug('Step has pending ops', {
|
|
510
|
+
workflowRunId,
|
|
511
|
+
stepName,
|
|
512
|
+
opsCount: ops.length,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
// hasPendingOps signals the V2 handler to break the loop
|
|
516
|
+
// and queue a continuation so waitUntil can flush them.
|
|
517
|
+
return { type: 'completed', hasPendingOps: !opsSettled, inlineDelta };
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
// Optimistic start: the body threw before `step_started` was confirmed.
|
|
521
|
+
// Reconcile first — if we lost the create-claim (or the run is
|
|
522
|
+
// gone/throttled) the body error is moot; discard it and don't write a
|
|
523
|
+
// terminal event (the winning handler owns the outcome). Reconcile
|
|
524
|
+
// before draining preCompletionOps for the same reason as the success
|
|
525
|
+
// path: a discarded outcome doesn't need the abort committed here.
|
|
526
|
+
if (optimisticStart) {
|
|
527
|
+
const reconcile = await reconcileOptimisticStart();
|
|
528
|
+
if (reconcile)
|
|
529
|
+
return reconcile;
|
|
530
|
+
}
|
|
531
|
+
// Order any must-be-durable ops (e.g. a step-initiated abort's
|
|
532
|
+
// hook_received event) ahead of step_failed too — a step that aborts and
|
|
533
|
+
// then throws must still have the abort recorded before the failure
|
|
534
|
+
// continuation observes it. Same latency tradeoff and no-reject contract
|
|
535
|
+
// as the success path above. See StepContext.preCompletionOps.
|
|
536
|
+
if (preCompletionOps.length > 0) {
|
|
537
|
+
await Promise.all(preCompletionOps).catch(() => { });
|
|
538
|
+
}
|
|
539
|
+
const effectiveErr = promoteAbortErrorToFatal(err);
|
|
540
|
+
const normalizedError = await normalizeUnknownError(effectiveErr);
|
|
541
|
+
const normalizedStack = normalizedError.stack || getErrorStack(effectiveErr) || '';
|
|
542
|
+
if (effectiveErr instanceof Error) {
|
|
543
|
+
span?.recordException?.(effectiveErr);
|
|
544
|
+
}
|
|
545
|
+
const isFatal = FatalError.is(effectiveErr);
|
|
546
|
+
span?.setAttributes({
|
|
547
|
+
...Attribute.StepErrorName(getErrorName(effectiveErr)),
|
|
548
|
+
...Attribute.StepErrorMessage(normalizedError.message),
|
|
549
|
+
...Attribute.ErrorType(getErrorName(effectiveErr)),
|
|
550
|
+
...Attribute.ErrorCategory(isFatal
|
|
551
|
+
? 'fatal'
|
|
552
|
+
: RetryableError.is(effectiveErr)
|
|
553
|
+
? 'retryable'
|
|
554
|
+
: 'transient'),
|
|
555
|
+
...Attribute.ErrorRetryable(!isFatal),
|
|
556
|
+
});
|
|
557
|
+
if (RunExpiredError.is(err)) {
|
|
558
|
+
stepLogger.info('Workflow run already completed, skipping step', {
|
|
559
|
+
workflowRunId,
|
|
560
|
+
stepId,
|
|
561
|
+
message: err.message,
|
|
562
|
+
});
|
|
563
|
+
return { type: 'gone' };
|
|
564
|
+
}
|
|
565
|
+
if (isFatal) {
|
|
566
|
+
stepLogger.error('Encountered FatalError while executing step, bubbling up to parent workflow', { workflowRunId, stepName, errorStack: normalizedStack });
|
|
567
|
+
// Apply the normalized stack to the thrown value so the serialized
|
|
568
|
+
// error preserves it for consumers. `types.isNativeError()` works
|
|
569
|
+
// across VM realms (a workflow-thrown error is an instance of the
|
|
570
|
+
// VM's Error class, not the host's).
|
|
571
|
+
if (types.isNativeError(effectiveErr) && normalizedStack) {
|
|
572
|
+
effectiveErr.stack = normalizedStack;
|
|
573
|
+
}
|
|
574
|
+
try {
|
|
575
|
+
await world.events.create(workflowRunId, {
|
|
576
|
+
eventType: 'step_failed',
|
|
577
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
578
|
+
correlationId: stepId,
|
|
579
|
+
eventData: {
|
|
580
|
+
stepName,
|
|
581
|
+
error: await dehydrateStepError(effectiveErr, workflowRunId, await getEncryptionKey(), [], globalThis, compression),
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
catch (stepFailErr) {
|
|
586
|
+
if (EntityConflictError.is(stepFailErr)) {
|
|
587
|
+
runtimeLogger.info('Tried failing step, but step has already finished.', {
|
|
588
|
+
workflowRunId,
|
|
589
|
+
stepId,
|
|
590
|
+
stepName,
|
|
591
|
+
message: stepFailErr.message,
|
|
592
|
+
});
|
|
593
|
+
return { type: 'skipped' };
|
|
594
|
+
}
|
|
595
|
+
throw stepFailErr;
|
|
596
|
+
}
|
|
597
|
+
span?.setAttributes({
|
|
598
|
+
...Attribute.StepStatus('failed'),
|
|
599
|
+
...Attribute.StepFatalError(true),
|
|
600
|
+
});
|
|
601
|
+
return { type: 'failed' };
|
|
602
|
+
}
|
|
603
|
+
// Non-fatal error: check if retries remaining
|
|
604
|
+
const currentAttempt = step.attempt;
|
|
605
|
+
span?.setAttributes({
|
|
606
|
+
...Attribute.StepAttempt(currentAttempt),
|
|
607
|
+
...Attribute.StepMaxRetries(maxRetries),
|
|
608
|
+
});
|
|
609
|
+
if (currentAttempt >= maxRetries + 1) {
|
|
610
|
+
// Max retries reached
|
|
611
|
+
const retryCount = step.attempt - 1;
|
|
612
|
+
stepLogger.error('Max retries reached, bubbling error to parent workflow', {
|
|
613
|
+
workflowRunId,
|
|
614
|
+
stepName,
|
|
615
|
+
attempt: step.attempt,
|
|
616
|
+
retryCount,
|
|
617
|
+
errorStack: normalizedStack,
|
|
618
|
+
});
|
|
619
|
+
const errorMessage = `Step "${stepName}" failed after ${maxRetries} ${pluralize('retry', 'retries', maxRetries)}: ${normalizedError.message}`;
|
|
620
|
+
// Wrap the original thrown value as `cause` on a fresh FatalError
|
|
621
|
+
// so the wrapping message + retry-count framing is the user-facing
|
|
622
|
+
// error while the original failure remains recoverable from
|
|
623
|
+
// `err.cause` after hydration.
|
|
624
|
+
const wrappedError = new FatalError(errorMessage);
|
|
625
|
+
wrappedError.cause = err;
|
|
626
|
+
if (normalizedStack)
|
|
627
|
+
wrappedError.stack = normalizedStack;
|
|
628
|
+
try {
|
|
629
|
+
await world.events.create(workflowRunId, {
|
|
630
|
+
eventType: 'step_failed',
|
|
631
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
632
|
+
correlationId: stepId,
|
|
633
|
+
eventData: {
|
|
634
|
+
stepName,
|
|
635
|
+
error: await dehydrateStepError(wrappedError, workflowRunId, await getEncryptionKey(), [], globalThis, compression),
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
catch (stepFailErr) {
|
|
640
|
+
if (EntityConflictError.is(stepFailErr)) {
|
|
641
|
+
runtimeLogger.info('Tried failing step, but step has already finished.', {
|
|
642
|
+
workflowRunId,
|
|
643
|
+
stepId,
|
|
644
|
+
stepName,
|
|
645
|
+
message: stepFailErr.message,
|
|
646
|
+
});
|
|
647
|
+
return { type: 'skipped' };
|
|
648
|
+
}
|
|
649
|
+
throw stepFailErr;
|
|
650
|
+
}
|
|
651
|
+
span?.setAttributes({
|
|
652
|
+
...Attribute.StepStatus('failed'),
|
|
653
|
+
...Attribute.StepRetryExhausted(true),
|
|
654
|
+
});
|
|
655
|
+
return { type: 'failed' };
|
|
656
|
+
}
|
|
657
|
+
// Retries remaining
|
|
658
|
+
if (RetryableError.is(err)) {
|
|
659
|
+
stepLogger.info('Encountered RetryableError, step will be retried', {
|
|
660
|
+
workflowRunId,
|
|
661
|
+
stepName,
|
|
662
|
+
attempt: currentAttempt,
|
|
663
|
+
message: err.message,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
stepLogger.info('Encountered Error, step will be retried', {
|
|
668
|
+
workflowRunId,
|
|
669
|
+
stepName,
|
|
670
|
+
attempt: currentAttempt,
|
|
671
|
+
errorStack: normalizedStack,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// Apply the normalized stack to the thrown value so it survives
|
|
675
|
+
// serialization. See the FatalError site above for why we use
|
|
676
|
+
// `types.isNativeError` instead of `err instanceof Error`.
|
|
677
|
+
if (types.isNativeError(err) && normalizedStack) {
|
|
678
|
+
err.stack = normalizedStack;
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
await world.events.create(workflowRunId, {
|
|
682
|
+
eventType: 'step_retrying',
|
|
683
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
684
|
+
correlationId: stepId,
|
|
685
|
+
eventData: {
|
|
686
|
+
stepName,
|
|
687
|
+
error: await dehydrateStepError(err, workflowRunId, await getEncryptionKey(), [], globalThis, compression),
|
|
688
|
+
...(RetryableError.is(err) && { retryAfter: err.retryAfter }),
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
catch (stepRetryErr) {
|
|
693
|
+
if (EntityConflictError.is(stepRetryErr)) {
|
|
694
|
+
runtimeLogger.info('Tried retrying step, but step has already finished.', {
|
|
695
|
+
workflowRunId,
|
|
696
|
+
stepId,
|
|
697
|
+
stepName,
|
|
698
|
+
message: stepRetryErr.message,
|
|
699
|
+
});
|
|
700
|
+
return { type: 'skipped' };
|
|
701
|
+
}
|
|
702
|
+
throw stepRetryErr;
|
|
703
|
+
}
|
|
704
|
+
const timeoutSeconds = Math.max(1, RetryableError.is(err)
|
|
705
|
+
? Math.ceil((+err.retryAfter.getTime() - Date.now()) / 1000)
|
|
706
|
+
: 1);
|
|
707
|
+
span?.setAttributes({
|
|
708
|
+
...Attribute.StepRetryTimeoutSeconds(timeoutSeconds),
|
|
709
|
+
...Attribute.StepRetryWillRetry(true),
|
|
710
|
+
});
|
|
711
|
+
return { type: 'retry', timeoutSeconds };
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1leGVjdXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL3N0ZXAtZXhlY3V0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLFVBQVUsRUFDVixjQUFjLEVBQ2QsZUFBZSxFQUNmLGFBQWEsRUFDYixhQUFhLEVBQ2Isb0JBQW9CLEdBQ3JCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU3RCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLGlDQUFpQyxHQUNsQyxNQUFNLGlCQUFpQixDQUFDO0FBRXpCLE9BQU8sRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEQsT0FBTyxFQUNMLGtCQUFrQixFQUNsQix3QkFBd0IsRUFDeEIsb0JBQW9CLEVBQ3BCLGdCQUFnQixHQUNqQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4QyxPQUFPLEVBQ0wsWUFBWSxFQUNaLGFBQWEsRUFDYixxQkFBcUIsRUFDckIsd0JBQXdCLEdBQ3pCLE1BQU0sYUFBYSxDQUFDO0FBRXJCLE9BQU8sRUFDTCw4QkFBOEIsRUFDOUIseUNBQXlDLEdBQzFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNwRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFaEQsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLENBQUM7QUFFbkM7Ozs7Ozs7R0FPRztBQUNILFNBQVMsa0JBQWtCLENBQ3pCLE1BQXVFLEVBQ3ZFLFNBQWtCO0lBRWxCLElBQUksQ0FBQyxTQUFTO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDakMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxTQUFTO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDcEUsT0FBTztRQUNMLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTTtRQUNyQixNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDckIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLElBQUksS0FBSztLQUNqQyxDQUFDO0FBQ0osQ0FBQztBQWdHRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLFdBQVcsQ0FDL0IsTUFBMEI7SUFFMUIsTUFBTSxFQUNKLEtBQUssRUFDTCxhQUFhLEVBQ2IsWUFBWSxFQUNaLGlCQUFpQixFQUNqQixNQUFNLEVBQ04sUUFBUSxHQUNULEdBQUcsTUFBTSxDQUFDO0lBQ1gsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEtBQUssU0FBUyxDQUFDO0lBQ3RELHNFQUFzRTtJQUN0RSx3RUFBd0U7SUFDeEUsTUFBTSxXQUFXLEdBQ2YsQ0FBQyxNQUFNLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQyxJQUFJLGlDQUFpQyxDQUFDO0lBRXBFLE1BQU0sUUFBUSxHQUFHLGdCQUFnQixlQUFlLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztJQUM3RCxPQUFPLEtBQUssQ0FBQyxRQUFRLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUN4QyxJQUFJLEVBQUUsYUFBYSxDQUFDO1lBQ2xCLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7WUFDL0IsR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQztZQUN2QyxHQUFHLFNBQVMsQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDO1lBQ3pDLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7U0FDNUIsQ0FBQyxDQUFDO1FBRUgscUVBQXFFO1FBQ3JFLG1FQUFtRTtRQUNuRSxzRUFBc0U7UUFDdEUsd0VBQXdFO1FBQ3hFLE1BQU0sZ0JBQWdCLEdBQUcsb0JBQW9CLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRXBFLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsTUFBTSxJQUFJLE9BQU8sTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzVDLDBFQUEwRTtZQUMxRSx3RUFBd0U7WUFDeEUsb0VBQW9FO1lBQ3BFLE1BQU0sWUFBWSxHQUFHLFNBQVMsUUFBUSw0SkFBNEosQ0FBQztZQUNuTSxhQUFhLENBQUMsS0FBSyxDQUFDLDRDQUE0QyxFQUFFO2dCQUNoRSxhQUFhO2dCQUNiLFFBQVE7Z0JBQ1IsTUFBTTthQUNQLENBQUMsQ0FBQztZQUNILHNFQUFzRTtZQUN0RSxzRUFBc0U7WUFDdEUsdUVBQXVFO1lBQ3ZFLHFFQUFxRTtZQUNyRSxzRUFBc0U7WUFDdEUsdUVBQXVFO1lBQ3ZFLHVFQUF1RTtZQUN2RSwrREFBK0Q7WUFDL0Qsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxzREFBc0Q7WUFDdEQsSUFBSSxNQUFNLENBQUMsYUFBYSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUN2QyxJQUFJLENBQUM7b0JBQ0gsb0VBQW9FO29CQUNwRSxxRUFBcUU7b0JBQ3JFLGtFQUFrRTtvQkFDbEUsdURBQXVEO29CQUN2RCxJQUFJLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQzt3QkFDM0IsTUFBTSxNQUFNLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztvQkFDL0MsQ0FBQztvQkFDRCxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRTt3QkFDdkMsU0FBUyxFQUFFLGNBQWM7d0JBQ3pCLFdBQVcsRUFBRSxvQkFBb0I7d0JBQ2pDLGFBQWEsRUFBRSxNQUFNO3dCQUNyQixTQUFTLEVBQUUsRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsYUFBYSxFQUFFO3FCQUNuRSxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO29CQUNsQixJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO3dCQUNyQyxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO29CQUM3QixDQUFDO29CQUNELElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO3dCQUNqQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO29CQUMxQixDQUFDO29CQUNELE1BQU0sUUFBUSxDQUFDO2dCQUNqQixDQUFDO1lBQ0gsQ0FBQztZQUNELElBQUksQ0FBQztnQkFDSCxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRTtvQkFDdkMsU0FBUyxFQUFFLGFBQWE7b0JBQ3hCLFdBQVcsRUFBRSxvQkFBb0I7b0JBQ2pDLGFBQWEsRUFBRSxNQUFNO29CQUNyQixTQUFTLEVBQUU7d0JBQ1QsUUFBUTt3QkFDUixLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FDN0IsSUFBSSxVQUFVLENBQUMsWUFBWSxDQUFDLEVBQzVCLGFBQWEsRUFDYixNQUFNLGdCQUFnQixFQUFFLEVBQ3hCLEVBQUUsRUFDRixVQUFVLEVBQ1YsV0FBVyxDQUNaO3FCQUNGO2lCQUNGLENBQUMsQ0FBQztZQUNMLENBQUM7WUFBQyxPQUFPLFdBQVcsRUFBRSxDQUFDO2dCQUNyQixJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO29CQUN4QyxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO2dCQUM3QixDQUFDO2dCQUNELE1BQU0sV0FBVyxDQUFDO1lBQ3BCLENBQUM7WUFDRCxJQUFJLEVBQUUsYUFBYSxDQUFDO2dCQUNsQixHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDO2dCQUNqQyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO2FBQ2xDLENBQUMsQ0FBQztZQUNILE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7UUFDNUIsQ0FBQztRQUVELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLElBQUksd0JBQXdCLENBQUM7UUFFakUsSUFBSSxFQUFFLGFBQWEsQ0FBQztZQUNsQixHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDO1NBQ3hDLENBQUMsQ0FBQztRQUVILHFFQUFxRTtRQUNyRSw0RUFBNEU7UUFDNUUsOEVBQThFO1FBQzlFLE1BQU0sa0JBQWtCLEdBQUcsQ0FDekIsR0FBWSxFQUNxQixFQUFFO1lBQ25DLElBQUksYUFBYSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxQixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUN6QixDQUFDLEVBQ0QsT0FBTyxHQUFHLENBQUMsVUFBVSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUN4RCxDQUFDO2dCQUNGLGFBQWEsQ0FBQyxJQUFJLENBQUMsc0NBQXNDLEVBQUU7b0JBQ3pELGlCQUFpQixFQUFFLFVBQVU7aUJBQzlCLENBQUMsQ0FBQztnQkFDSCxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsVUFBVSxFQUFFLENBQUM7WUFDM0QsQ0FBQztZQUNELElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUM1QixhQUFhLENBQUMsSUFBSSxDQUNoQixpQkFBaUIsYUFBYSwyQ0FBMkMsTUFBTSxNQUFNLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FDbkcsQ0FBQztnQkFDRixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO1lBQzFCLENBQUM7WUFDRCxJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxhQUFhLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxFQUFFO29CQUN0RCxRQUFRO29CQUNSLE1BQU07b0JBQ04sYUFBYTtvQkFDYixLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztpQkFDeEQsQ0FBQyxDQUFDO2dCQUNILElBQUksRUFBRSxhQUFhLENBQUM7b0JBQ2xCLEdBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7b0JBQzlCLEdBQUcsU0FBUyxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUM7aUJBQ3pDLENBQUMsQ0FBQztnQkFDSCxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO1lBQzdCLENBQUM7WUFDRCxJQUFJLGFBQWEsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDMUIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDeEQsYUFBYSxDQUFDLEtBQUssQ0FBQywyQ0FBMkMsRUFBRTtvQkFDL0QsUUFBUTtvQkFDUixNQUFNO29CQUNOLGNBQWM7aUJBQ2YsQ0FBQyxDQUFDO2dCQUNILE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxDQUFDO1lBQzNDLENBQUM7WUFDRCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQUM7UUFFRiw0RUFBNEU7UUFDNUUscUVBQXFFO1FBQ3JFLDJFQUEyRTtRQUMzRSx1RUFBdUU7UUFDdkUsd0VBQXdFO1FBQ3hFLDRFQUE0RTtRQUM1RSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLHdFQUF3RTtRQUN4RSxzRUFBc0U7UUFDdEUsRUFBRTtRQUNGLDRFQUE0RTtRQUM1RSx5RUFBeUU7UUFDekUsdUVBQXVFO1FBQ3ZFLHdFQUF3RTtRQUN4RSw2RUFBNkU7UUFDN0Usd0RBQXdEO1FBQ3hELE1BQU0sZUFBZSxHQUNuQixNQUFNLENBQUMsYUFBYSxLQUFLLFNBQVM7WUFDbEMsQ0FBQyw4QkFBOEIsRUFBRTtnQkFDL0IsQ0FBQyxNQUFNLENBQUMsb0JBQW9CLEtBQUssSUFBSTtvQkFDbkMsQ0FBQyx5Q0FBeUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUVyRCxJQUFJLElBQVUsQ0FBQztRQUNmLDJFQUEyRTtRQUMzRSxzRUFBc0U7UUFDdEUseURBQXlEO1FBQ3pELElBQUksc0JBRVMsQ0FBQztRQUNkLDBFQUEwRTtRQUMxRSxxRUFBcUU7UUFDckUsNEVBQTRFO1FBQzVFLGtFQUFrRTtRQUNsRSx1RUFBdUU7UUFDdkUsMkVBQTJFO1FBQzNFLE1BQU0sd0JBQXdCLEdBQUcsS0FBSyxJQUVwQyxFQUFFO1lBQ0YsSUFBSSxDQUFDLHNCQUFzQjtnQkFBRSxPQUFPLFNBQVMsQ0FBQztZQUM5QyxNQUFNLE9BQU8sR0FBRyxNQUFNLHNCQUFzQixDQUFDO1lBQzdDLElBQUksT0FBTyxDQUFDLEVBQUU7Z0JBQUUsT0FBTyxTQUFTLENBQUM7WUFDakMsTUFBTSxNQUFNLEdBQUcsa0JBQWtCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxNQUFNO2dCQUFFLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUMvQixPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDLENBQUM7UUFFRixJQUFJLGVBQWUsRUFBRSxDQUFDO1lBQ3BCLHVFQUF1RTtZQUN2RSxzRUFBc0U7WUFDdEUsbUVBQW1FO1lBQ25FLDBFQUEwRTtZQUMxRSxtREFBbUQ7WUFDbkQsTUFBTSxjQUFjLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FDdkUsR0FBRyxFQUFFLENBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO2dCQUNqQyxTQUFTLEVBQUUsY0FBYztnQkFDekIsV0FBVyxFQUFFLG9CQUFvQjtnQkFDakMsYUFBYSxFQUFFLE1BQU07Z0JBQ3JCLFNBQVMsRUFBRSxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxhQUFhLEVBQUU7YUFDbkUsQ0FBQyxDQUNMLENBQUM7WUFDRixzQkFBc0IsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUMxQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQWEsRUFBRSxDQUFDLEVBQzdCLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLEtBQWMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUN2QyxDQUFDO1lBQ0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUN2QixJQUFJLEdBQUc7Z0JBQ0wsS0FBSyxFQUFFLGFBQWE7Z0JBQ3BCLE1BQU07Z0JBQ04sUUFBUTtnQkFDUixNQUFNLEVBQUUsU0FBUztnQkFDakIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxhQUFhO2dCQUMzQixPQUFPLEVBQUUsQ0FBQztnQkFDVixTQUFTLEVBQUUsR0FBRztnQkFDZCxTQUFTLEVBQUUsR0FBRztnQkFDZCxTQUFTLEVBQUUsR0FBRzthQUNmLENBQUM7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLHdFQUF3RTtZQUN4RSxzRUFBc0U7WUFDdEUscUVBQXFFO1lBQ3JFLHVFQUF1RTtZQUN2RSx5RUFBeUU7WUFDekUsbUVBQW1FO1lBQ25FLG1EQUFtRDtZQUNuRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxXQUFXLEdBQUcsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUU7b0JBQzNELFNBQVMsRUFBRSxjQUFjO29CQUN6QixXQUFXLEVBQUUsb0JBQW9CO29CQUNqQyxhQUFhLEVBQUUsTUFBTTtvQkFDckIsU0FBUyxFQUNQLE1BQU0sQ0FBQyxhQUFhLEtBQUssU0FBUzt3QkFDaEMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLGFBQWEsRUFBRTt3QkFDekQsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFO2lCQUNuQixDQUFDLENBQUM7Z0JBRUgsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDdEIsTUFBTSxJQUFJLG9CQUFvQixDQUM1QiwyQkFBMkIsTUFBTSw4QkFBOEIsQ0FDaEUsQ0FBQztnQkFDSixDQUFDO2dCQUNELElBQUksR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDO1lBQzFCLENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE1BQU0sTUFBTSxHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN2QyxJQUFJLE1BQU07b0JBQUUsT0FBTyxNQUFNLENBQUM7Z0JBQzFCLE1BQU0sR0FBRyxDQUFDO1lBQ1osQ0FBQztRQUNILENBQUM7UUFFRCxhQUFhLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFO1lBQzVDLFFBQVE7WUFDUixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztTQUN0QixDQUFDLENBQUM7UUFFSCxJQUFJLEVBQUUsYUFBYSxDQUFDO1lBQ2xCLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1NBQ3JDLENBQUMsQ0FBQztRQUVILElBQUksTUFBZSxDQUFDO1FBRXBCLHVFQUF1RTtRQUN2RSx1RUFBdUU7UUFDdkUsb0VBQW9FO1FBQ3BFLHNFQUFzRTtRQUN0RSwyRUFBMkU7UUFDM0UsSUFBSSxJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2hELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO1lBQ3BDLE1BQU0sWUFBWSxHQUFHLFNBQVMsUUFBUSwyQkFBMkIsVUFBVSxJQUFJLFNBQVMsQ0FBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxHQUFHLENBQUM7WUFDNUgsVUFBVSxDQUFDLEtBQUssQ0FBQywyQkFBMkIsRUFBRTtnQkFDNUMsYUFBYTtnQkFDYixRQUFRO2dCQUNSLFVBQVU7YUFDWCxDQUFDLENBQUM7WUFDSCxvRUFBb0U7WUFDcEUsa0VBQWtFO1lBQ2xFLGlFQUFpRTtZQUNqRSxxRUFBcUU7WUFDckUsbURBQW1EO1lBQ25ELE1BQU0sWUFBWSxHQUFHLElBQUksVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2xELElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDO29CQUNGLFlBQXNCLENBQUMsS0FBSyxHQUFHLE1BQU0sZ0JBQWdCLENBQ3BELElBQUksQ0FBQyxLQUFLLEVBQ1YsYUFBYSxFQUNiLE1BQU0sZ0JBQWdCLEVBQUUsQ0FDekIsQ0FBQztnQkFDSixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCx5Q0FBeUM7Z0JBQzNDLENBQUM7WUFDSCxDQUFDO1lBQ0QsSUFBSSxDQUFDO2dCQUNILE1BQU0sS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO29CQUN2QyxTQUFTLEVBQUUsYUFBYTtvQkFDeEIsV0FBVyxFQUFFLG9CQUFvQjtvQkFDakMsYUFBYSxFQUFFLE1BQU07b0JBQ3JCLFNBQVMsRUFBRTt3QkFDVCxRQUFRO3dCQUNSLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUM3QixZQUFZLEVBQ1osYUFBYSxFQUNiLE1BQU0sZ0JBQWdCLEVBQUUsRUFDeEIsRUFBRSxFQUNGLFVBQVUsRUFDVixXQUFXLENBQ1o7cUJBQ0Y7aUJBQ0YsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsSUFBSSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDaEMsYUFBYSxDQUFDLElBQUksQ0FDaEIsb0RBQW9ELEVBQ3BEO3dCQUNFLGFBQWE7d0JBQ2IsTUFBTTt3QkFDTixRQUFRO3dCQUNSLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztxQkFDckIsQ0FDRixDQUFDO29CQUNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7Z0JBQzdCLENBQUM7Z0JBQ0QsTUFBTSxHQUFHLENBQUM7WUFDWixDQUFDO1lBQ0QsSUFBSSxFQUFFLGFBQWEsQ0FBQztnQkFDbEIsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQztnQkFDakMsR0FBRyxTQUFTLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO2FBQ3RDLENBQUMsQ0FBQztZQUNILE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7UUFDNUIsQ0FBQztRQUVELG9FQUFvRTtRQUNwRSx5RUFBeUU7UUFDekUsaUVBQWlFO1FBQ2pFLE1BQU0sZ0JBQWdCLEdBQW9CLEVBQUUsQ0FBQztRQUU3QyxJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1lBRTdCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sSUFBSSxvQkFBb0IsQ0FDNUIsU0FBUyxNQUFNLGdDQUFnQyxDQUNoRCxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7WUFDckMsTUFBTSxHQUFHLEdBQW9CLEVBQUUsQ0FBQztZQUNoQyxvRUFBb0U7WUFDcEUsbUVBQW1FO1lBQ25FLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxhQUFhLElBQUksQ0FBQyxNQUFNLGdCQUFnQixFQUFFLENBQUMsQ0FBQztZQUN6RSxNQUFNLGFBQWEsR0FBRyxNQUFNLEtBQUssQ0FDL0IsY0FBYyxFQUNkLEVBQUUsRUFDRixLQUFLLEVBQUUsV0FBVyxFQUFFLEVBQUU7Z0JBQ3BCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxvQkFBb0IsQ0FDekMsSUFBSSxDQUFDLEtBQUssRUFDVixhQUFhLEVBQ2IsYUFBYSxFQUNiLEdBQUcsRUFDSCxVQUFVLEVBQ1YsRUFBRSxFQUNGLE1BQU0sQ0FBQyxvQkFBb0IsQ0FDNUIsQ0FBQztnQkFDRixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO2dCQUMxQyxXQUFXLEVBQUUsYUFBYSxDQUFDO29CQUN6QixHQUFHLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztvQkFDckQsR0FBRyxTQUFTLENBQUMsc0JBQXNCLENBQUMsVUFBVSxDQUFDO2lCQUNoRCxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxRQUFRLENBQUM7WUFDbEIsQ0FBQyxDQUNGLENBQUM7WUFFRixNQUFNLElBQUksR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFDO1lBQ2hDLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDO1lBQzlDLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLFdBQVcsRUFBRSxDQUFDO1lBRXhELE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sR0FBRyxNQUFNLEtBQUssQ0FBQyxjQUFjLEVBQUUsRUFBRSxFQUFFLEtBQUssSUFBSSxFQUFFO2dCQUNsRCxPQUFPLE1BQU0sY0FBYyxDQUFDLEdBQUcsQ0FDN0I7b0JBQ0UsWUFBWSxFQUFFO3dCQUNaLFFBQVE7d0JBQ1IsTUFBTTt3QkFDTixhQUFhLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQyxhQUFhLENBQUM7d0JBQ3ZDLE9BQU87cUJBQ1I7b0JBQ0QsZ0JBQWdCLEVBQUU7d0JBQ2hCLFlBQVk7d0JBQ1osYUFBYTt3QkFDYixpQkFBaUIsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLGlCQUFpQixDQUFDO3dCQUMvQyxHQUFHLEVBQUUsUUFBUTs0QkFDWCxDQUFDLENBQUMsV0FBVyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTs0QkFDckMsQ0FBQyxDQUFDLG9CQUFvQixJQUFJLElBQUksSUFBSSxFQUFFO3dCQUN0QyxRQUFRLEVBQUUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLGFBQWEsRUFBRTtxQkFDMUM7b0JBQ0Qsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLG9CQUFvQjtvQkFDakQsR0FBRztvQkFDSCxnQkFBZ0I7b0JBQ2hCLFdBQVcsRUFBRSxhQUFhLENBQUMsV0FBVztvQkFDdEMsYUFBYTtpQkFDZCxFQUNELEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUNsQyxDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsa0JBQWtCLENBQUM7WUFFeEQsSUFBSSxFQUFFLGFBQWEsQ0FBQztnQkFDbEIsR0FBRyxTQUFTLENBQUMsb0JBQW9CLENBQUMsZUFBZSxDQUFDO2FBQ25ELENBQUMsQ0FBQztZQUVILE1BQU0sR0FBRyxNQUFNLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxFQUFFO2dCQUNqRSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sVUFBVSxHQUFHLE1BQU0sd0JBQXdCLENBQy9DLE1BQU0sRUFDTixhQUFhLEVBQ2IsYUFBYSxFQUNiLEdBQUcsRUFDSCxVQUFVLEVBQ1YsS0FBSyxFQUNMLEtBQUssRUFDTCxXQUFXLENBQ1osQ0FBQztnQkFDRixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO2dCQUMxQyxhQUFhLEVBQUUsYUFBYSxDQUFDO29CQUMzQixHQUFHLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUM7b0JBQzdDLEdBQUcsU0FBUyxDQUFDLGNBQWMsQ0FBQyxPQUFPLFVBQVUsQ0FBQztpQkFDL0MsQ0FBQyxDQUFDO2dCQUNILE9BQU8sVUFBVSxDQUFDO1lBQ3BCLENBQUMsQ0FBQyxDQUFDO1lBRUgsb0VBQW9FO1lBQ3BFLGlFQUFpRTtZQUNqRSxrRUFBa0U7WUFDbEUsb0VBQW9FO1lBQ3BFLGtFQUFrRTtZQUNsRSwrREFBK0Q7WUFDL0QsNkNBQTZDO1lBQzdDLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQztZQUN0QixJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ25CLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ3BDLG1FQUFtRTtnQkFDbkUsb0VBQW9FO2dCQUNwRSwrREFBK0Q7Z0JBQy9ELGtFQUFrRTtnQkFDbEUsNkNBQTZDO2dCQUM3QyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7b0JBQ2hDLGFBQWEsQ0FBQyxJQUFJLENBQUMsNENBQTRDLEVBQUU7d0JBQy9ELGFBQWE7d0JBQ2IsTUFBTTt3QkFDTixLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztxQkFDeEQsQ0FBQyxDQUFDO2dCQUNMLENBQUMsQ0FBQyxDQUFDO2dCQUNILFVBQVUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUM7b0JBQzlCLFVBQVUsQ0FBQyxJQUFJLENBQ2IsR0FBRyxFQUFFLENBQUMsSUFBYSxFQUNuQixDQUFDLEdBQUcsRUFBRSxFQUFFO3dCQUNOLDBEQUEwRDt3QkFDMUQsNEJBQTRCO3dCQUM1QixNQUFNLFlBQVksR0FDaEIsR0FBRyxFQUFFLElBQUksS0FBSyxZQUFZLElBQUksR0FBRyxFQUFFLElBQUksS0FBSyxpQkFBaUIsQ0FBQzt3QkFDaEUsSUFBSSxZQUFZOzRCQUFFLE9BQU8sSUFBYSxDQUFDO3dCQUN2QyxNQUFNLEdBQUcsQ0FBQztvQkFDWixDQUFDLENBQ0Y7b0JBQ0QsSUFBSSxPQUFPLENBQVEsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7aUJBQzNELENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxzRUFBc0U7WUFDdEUsZ0VBQWdFO1lBQ2hFLHNFQUFzRTtZQUN0RSx1RUFBdUU7WUFDdkUsK0RBQStEO1lBQy9ELHNFQUFzRTtZQUN0RSxJQUFJLGVBQWUsRUFBRSxDQUFDO2dCQUNwQixNQUFNLFNBQVMsR0FBRyxNQUFNLHdCQUF3QixFQUFFLENBQUM7Z0JBQ25ELElBQUksU0FBUztvQkFBRSxPQUFPLFNBQVMsQ0FBQztZQUNsQyxDQUFDO1lBRUQsNERBQTREO1lBQzVELHNFQUFzRTtZQUN0RSxzRUFBc0U7WUFDdEUsa0VBQWtFO1lBQ2xFLHNFQUFzRTtZQUN0RSxpQ0FBaUM7WUFDakMsRUFBRTtZQUNGLHdFQUF3RTtZQUN4RSx1RUFBdUU7WUFDdkUsbUVBQW1FO1lBQ25FLG9FQUFvRTtZQUNwRSx5RUFBeUU7WUFDekUsMEVBQTBFO1lBQzFFLElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdEQsQ0FBQztZQUVELDBEQUEwRDtZQUMxRCxvRUFBb0U7WUFDcEUsOERBQThEO1lBQzlELGdFQUFnRTtZQUNoRSxJQUFJLGdCQUFnQixHQUFHLEtBQUssQ0FBQztZQUM3QixNQUFNLGVBQWUsR0FBRyxNQUFNLEtBQUssQ0FBQyxNQUFNO2lCQUN2QyxNQUFNLENBQ0wsYUFBYSxFQUNiO2dCQUNFLFNBQVMsRUFBRSxnQkFBZ0I7Z0JBQzNCLFdBQVcsRUFBRSxvQkFBb0I7Z0JBQ2pDLGFBQWEsRUFBRSxNQUFNO2dCQUNyQixTQUFTLEVBQUU7b0JBQ1QsUUFBUTtvQkFDUixZQUFZO29CQUNaLE1BQU0sRUFBRSxNQUFvQjtpQkFDN0I7YUFDRixFQUNELE1BQU0sQ0FBQyxzQkFBc0IsS0FBSyxTQUFTO2dCQUN6QyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDLHNCQUFzQixFQUFFO2dCQUNoRCxDQUFDLENBQUMsU0FBUyxDQUNkO2lCQUNBLEtBQUssQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUNiLElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ2hDLGFBQWEsQ0FBQyxJQUFJLENBQ2hCLHVEQUF1RCxFQUN2RDt3QkFDRSxhQUFhO3dCQUNiLE1BQU07d0JBQ04sUUFBUTt3QkFDUixPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87cUJBQ3JCLENBQ0YsQ0FBQztvQkFDRixnQkFBZ0IsR0FBRyxJQUFJLENBQUM7b0JBQ3hCLE9BQU8sU0FBUyxDQUFDO2dCQUNuQixDQUFDO2dCQUNELE1BQU0sR0FBRyxDQUFDO1lBQ1osQ0FBQyxDQUFDLENBQUM7WUFFTCxJQUFJLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3JCLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7WUFDN0IsQ0FBQztZQUVELE1BQU0sV0FBVyxHQUFHLGVBQWU7Z0JBQ2pDLENBQUMsQ0FBQyxrQkFBa0IsQ0FDaEIsZUFBZSxFQUNmLE1BQU0sQ0FBQyxzQkFBc0IsS0FBSyxTQUFTLENBQzVDO2dCQUNILENBQUMsQ0FBQyxTQUFTLENBQUM7WUFFZCxJQUFJLEVBQUUsYUFBYSxDQUFDO2dCQUNsQixHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDO2dCQUNwQyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUMsT0FBTyxNQUFNLENBQUM7YUFDM0MsQ0FBQyxDQUFDO1lBRUgsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNuQixVQUFVLENBQUMsS0FBSyxDQUFDLHNCQUFzQixFQUFFO29CQUN2QyxhQUFhO29CQUNiLFFBQVE7b0JBQ1IsUUFBUSxFQUFFLEdBQUcsQ0FBQyxNQUFNO2lCQUNyQixDQUFDLENBQUM7WUFDTCxDQUFDO1lBQ0QseURBQXlEO1lBQ3pELHdEQUF3RDtZQUN4RCxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLENBQUM7UUFDeEUsQ0FBQztRQUFDLE9BQU8sR0FBWSxFQUFFLENBQUM7WUFDdEIsd0VBQXdFO1lBQ3hFLCtEQUErRDtZQUMvRCx1RUFBdUU7WUFDdkUsbUVBQW1FO1lBQ25FLHNFQUFzRTtZQUN0RSxtRUFBbUU7WUFDbkUsSUFBSSxlQUFlLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxTQUFTLEdBQUcsTUFBTSx3QkFBd0IsRUFBRSxDQUFDO2dCQUNuRCxJQUFJLFNBQVM7b0JBQUUsT0FBTyxTQUFTLENBQUM7WUFDbEMsQ0FBQztZQUVELCtEQUErRDtZQUMvRCx5RUFBeUU7WUFDekUsb0VBQW9FO1lBQ3BFLHlFQUF5RTtZQUN6RSwrREFBK0Q7WUFDL0QsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztZQUN0RCxDQUFDO1lBRUQsTUFBTSxZQUFZLEdBQUcsd0JBQXdCLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFbkQsTUFBTSxlQUFlLEdBQUcsTUFBTSxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNsRSxNQUFNLGVBQWUsR0FDbkIsZUFBZSxDQUFDLEtBQUssSUFBSSxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO1lBRTdELElBQUksWUFBWSxZQUFZLEtBQUssRUFBRSxDQUFDO2dCQUNsQyxJQUFJLEVBQUUsZUFBZSxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDeEMsQ0FBQztZQUVELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUM7WUFFNUMsSUFBSSxFQUFFLGFBQWEsQ0FBQztnQkFDbEIsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDdEQsR0FBRyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQztnQkFDdEQsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDbEQsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUN4QixPQUFPO29CQUNMLENBQUMsQ0FBQyxPQUFPO29CQUNULENBQUMsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQzt3QkFDL0IsQ0FBQyxDQUFDLFdBQVc7d0JBQ2IsQ0FBQyxDQUFDLFdBQVcsQ0FDbEI7Z0JBQ0QsR0FBRyxTQUFTLENBQUMsY0FBYyxDQUFDLENBQUMsT0FBTyxDQUFDO2FBQ3RDLENBQUMsQ0FBQztZQUVILElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUM1QixVQUFVLENBQUMsSUFBSSxDQUFDLCtDQUErQyxFQUFFO29CQUMvRCxhQUFhO29CQUNiLE1BQU07b0JBQ04sT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO2lCQUNyQixDQUFDLENBQUM7Z0JBQ0gsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztZQUMxQixDQUFDO1lBRUQsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixVQUFVLENBQUMsS0FBSyxDQUNkLDZFQUE2RSxFQUM3RSxFQUFFLGFBQWEsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxDQUN6RCxDQUFDO2dCQUNGLG1FQUFtRTtnQkFDbkUsa0VBQWtFO2dCQUNsRSxrRUFBa0U7Z0JBQ2xFLHFDQUFxQztnQkFDckMsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxJQUFJLGVBQWUsRUFBRSxDQUFDO29CQUN4RCxZQUFzQixDQUFDLEtBQUssR0FBRyxlQUFlLENBQUM7Z0JBQ2xELENBQUM7Z0JBQ0QsSUFBSSxDQUFDO29CQUNILE1BQU0sS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO3dCQUN2QyxTQUFTLEVBQUUsYUFBYTt3QkFDeEIsV0FBVyxFQUFFLG9CQUFvQjt3QkFDakMsYUFBYSxFQUFFLE1BQU07d0JBQ3JCLFNBQVMsRUFBRTs0QkFDVCxRQUFROzRCQUNSLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUM3QixZQUFZLEVBQ1osYUFBYSxFQUNiLE1BQU0sZ0JBQWdCLEVBQUUsRUFDeEIsRUFBRSxFQUNGLFVBQVUsRUFDVixXQUFXLENBQ1o7eUJBQ0Y7cUJBQ0YsQ0FBQyxDQUFDO2dCQUNMLENBQUM7Z0JBQUMsT0FBTyxXQUFXLEVBQUUsQ0FBQztvQkFDckIsSUFBSSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQzt3QkFDeEMsYUFBYSxDQUFDLElBQUksQ0FDaEIsb0RBQW9ELEVBQ3BEOzRCQUNFLGFBQWE7NEJBQ2IsTUFBTTs0QkFDTixRQUFROzRCQUNSLE9BQU8sRUFBRSxXQUFXLENBQUMsT0FBTzt5QkFDN0IsQ0FDRixDQUFDO3dCQUNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7b0JBQzdCLENBQUM7b0JBQ0QsTUFBTSxXQUFXLENBQUM7Z0JBQ3BCLENBQUM7Z0JBQ0QsSUFBSSxFQUFFLGFBQWEsQ0FBQztvQkFDbEIsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQztvQkFDakMsR0FBRyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQztpQkFDbEMsQ0FBQyxDQUFDO2dCQUNILE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7WUFDNUIsQ0FBQztZQUVELDhDQUE4QztZQUM5QyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1lBRXBDLElBQUksRUFBRSxhQUFhLENBQUM7Z0JBQ2xCLEdBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUM7Z0JBQ3hDLEdBQUcsU0FBUyxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUM7YUFDeEMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxjQUFjLElBQUksVUFBVSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNyQyxzQkFBc0I7Z0JBQ3RCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO2dCQUNwQyxVQUFVLENBQUMsS0FBSyxDQUNkLHdEQUF3RCxFQUN4RDtvQkFDRSxhQUFhO29CQUNiLFFBQVE7b0JBQ1IsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO29CQUNyQixVQUFVO29CQUNWLFVBQVUsRUFBRSxlQUFlO2lCQUM1QixDQUNGLENBQUM7Z0JBQ0YsTUFBTSxZQUFZLEdBQUcsU0FBUyxRQUFRLGtCQUFrQixVQUFVLElBQUksU0FBUyxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLEtBQUssZUFBZSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM5SSxrRUFBa0U7Z0JBQ2xFLG1FQUFtRTtnQkFDbkUsNERBQTREO2dCQUM1RCwrQkFBK0I7Z0JBQy9CLE1BQU0sWUFBWSxHQUFHLElBQUksVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUNqRCxZQUFzQixDQUFDLEtBQUssR0FBRyxHQUFHLENBQUM7Z0JBQ3BDLElBQUksZUFBZTtvQkFBRSxZQUFZLENBQUMsS0FBSyxHQUFHLGVBQWUsQ0FBQztnQkFDMUQsSUFBSSxDQUFDO29CQUNILE1BQU0sS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO3dCQUN2QyxTQUFTLEVBQUUsYUFBYTt3QkFDeEIsV0FBVyxFQUFFLG9CQUFvQjt3QkFDakMsYUFBYSxFQUFFLE1BQU07d0JBQ3JCLFNBQVMsRUFBRTs0QkFDVCxRQUFROzRCQUNSLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUM3QixZQUFZLEVBQ1osYUFBYSxFQUNiLE1BQU0sZ0JBQWdCLEVBQUUsRUFDeEIsRUFBRSxFQUNGLFVBQVUsRUFDVixXQUFXLENBQ1o7eUJBQ0Y7cUJBQ0YsQ0FBQyxDQUFDO2dCQUNMLENBQUM7Z0JBQUMsT0FBTyxXQUFXLEVBQUUsQ0FBQztvQkFDckIsSUFBSSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQzt3QkFDeEMsYUFBYSxDQUFDLElBQUksQ0FDaEIsb0RBQW9ELEVBQ3BEOzRCQUNFLGFBQWE7NEJBQ2IsTUFBTTs0QkFDTixRQUFROzRCQUNSLE9BQU8sRUFBRSxXQUFXLENBQUMsT0FBTzt5QkFDN0IsQ0FDRixDQUFDO3dCQUNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7b0JBQzdCLENBQUM7b0JBQ0QsTUFBTSxXQUFXLENBQUM7Z0JBQ3BCLENBQUM7Z0JBQ0QsSUFBSSxFQUFFLGFBQWEsQ0FBQztvQkFDbEIsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQztvQkFDakMsR0FBRyxTQUFTLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO2lCQUN0QyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQztZQUM1QixDQUFDO1lBRUQsb0JBQW9CO1lBQ3BCLElBQUksY0FBYyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMzQixVQUFVLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxFQUFFO29CQUNsRSxhQUFhO29CQUNiLFFBQVE7b0JBQ1IsT0FBTyxFQUFFLGNBQWM7b0JBQ3ZCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztpQkFDckIsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFVBQVUsQ0FBQyxJQUFJLENBQUMseUNBQXlDLEVBQUU7b0JBQ3pELGFBQWE7b0JBQ2IsUUFBUTtvQkFDUixPQUFPLEVBQUUsY0FBYztvQkFDdkIsVUFBVSxFQUFFLGVBQWU7aUJBQzVCLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxnRUFBZ0U7WUFDaEUsOERBQThEO1lBQzlELDJEQUEyRDtZQUMzRCxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksZUFBZSxFQUFFLENBQUM7Z0JBQy9DLEdBQWEsQ0FBQyxLQUFLLEdBQUcsZUFBZSxDQUFDO1lBQ3pDLENBQUM7WUFDRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUU7b0JBQ3ZDLFNBQVMsRUFBRSxlQUFlO29CQUMxQixXQUFXLEVBQUUsb0JBQW9CO29CQUNqQyxhQUFhLEVBQUUsTUFBTTtvQkFDckIsU0FBUyxFQUFFO3dCQUNULFFBQVE7d0JBQ1IsS0FBSyxFQUFFLE1BQU0sa0JBQWtCLENBQzdCLEdBQUcsRUFDSCxhQUFhLEVBQ2IsTUFBTSxnQkFBZ0IsRUFBRSxFQUN4QixFQUFFLEVBQ0YsVUFBVSxFQUNWLFdBQVcsQ0FDWjt3QkFDRCxHQUFHLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUM7cUJBQzlEO2lCQUNGLENBQUMsQ0FBQztZQUNMLENBQUM7WUFBQyxPQUFPLFlBQVksRUFBRSxDQUFDO2dCQUN0QixJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO29CQUN6QyxhQUFhLENBQUMsSUFBSSxDQUNoQixxREFBcUQsRUFDckQ7d0JBQ0UsYUFBYTt3QkFDYixNQUFNO3dCQUNOLFFBQVE7d0JBQ1IsT0FBTyxFQUFFLFlBQVksQ0FBQyxPQUFPO3FCQUM5QixDQUNGLENBQUM7b0JBQ0YsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztnQkFDN0IsQ0FBQztnQkFDRCxNQUFNLFlBQVksQ0FBQztZQUNyQixDQUFDO1lBRUQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDN0IsQ0FBQyxFQUNELGNBQWMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO2dCQUNwQixDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUM7Z0JBQzVELENBQUMsQ0FBQyxDQUFDLENBQ04sQ0FBQztZQUVGLElBQUksRUFBRSxhQUFhLENBQUM7Z0JBQ2xCLEdBQUcsU0FBUyxDQUFDLHVCQUF1QixDQUFDLGNBQWMsQ0FBQztnQkFDcEQsR0FBRyxTQUFTLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO2FBQ3RDLENBQUMsQ0FBQztZQUVILE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxDQUFDO1FBQzNDLENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB0eXBlcyB9IGZyb20gJ25vZGU6dXRpbCc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBGYXRhbEVycm9yLFxuICBSZXRyeWFibGVFcnJvcixcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBUaHJvdHRsZUVycm9yLFxuICBUb29FYXJseUVycm9yLFxuICBXb3JrZmxvd1J1bnRpbWVFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgeyBwbHVyYWxpemUsIHN0ZXBEaXNwbGF5TmFtZSB9IGZyb20gJ0B3b3JrZmxvdy91dGlscyc7XG5pbXBvcnQgdHlwZSB7IEV2ZW50LCBTZXJpYWxpemVkRGF0YSwgU3RlcCwgV29ybGQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHtcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTixcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB0eXBlIHsgQ3J5cHRvS2V5IH0gZnJvbSAnLi4vZW5jcnlwdGlvbi5qcyc7XG5pbXBvcnQgeyBydW50aW1lTG9nZ2VyLCBzdGVwTG9nZ2VyIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGdldFN0ZXBGdW5jdGlvbiB9IGZyb20gJy4uL3ByaXZhdGUuanMnO1xuaW1wb3J0IHtcbiAgZGVoeWRyYXRlU3RlcEVycm9yLFxuICBkZWh5ZHJhdGVTdGVwUmV0dXJuVmFsdWUsXG4gIGh5ZHJhdGVTdGVwQXJndW1lbnRzLFxuICBoeWRyYXRlU3RlcEVycm9yLFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uLmpzJztcbmltcG9ydCB7IGNvbnRleHRTdG9yYWdlIH0gZnJvbSAnLi4vc3RlcC9jb250ZXh0LXN0b3JhZ2UuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyB0cmFjZSB9IGZyb20gJy4uL3RlbGVtZXRyeS5qcyc7XG5pbXBvcnQge1xuICBnZXRFcnJvck5hbWUsXG4gIGdldEVycm9yU3RhY2ssXG4gIG5vcm1hbGl6ZVVua25vd25FcnJvcixcbiAgcHJvbW90ZUFib3J0RXJyb3JUb0ZhdGFsLFxufSBmcm9tICcuLi90eXBlcy5qcyc7XG5cbmltcG9ydCB7XG4gIGlzT3B0aW1pc3RpY0lubGluZVN0YXJ0RW5hYmxlZCxcbiAgaXNPcHRpbWlzdGljSW5saW5lU3RhcnRFeHBsaWNpdGx5RGlzYWJsZWQsXG59IGZyb20gJy4vY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IGdldFBvcnRMYXp5IH0gZnJvbSAnLi9nZXQtcG9ydC1sYXp5LmpzJztcbmltcG9ydCB7IG1lbW9pemVFbmNyeXB0aW9uS2V5IH0gZnJvbSAnLi9oZWxwZXJzLmpzJztcbmltcG9ydCB7IHNhZmVXYWl0VW50aWwgfSBmcm9tICcuL3dhaXQtdW50aWwuanMnO1xuXG5jb25zdCBERUZBVUxUX1NURVBfTUFYX1JFVFJJRVMgPSAzO1xuXG4vKipcbiAqIEV4dHJhY3QgdGhlIGlubGluZSBkZWx0YSBmcm9tIGEgc3RlcC10ZXJtaW5hbCBgZXZlbnRzLmNyZWF0ZWAgcmVzdWx0LFxuICogaWYgdGhlIFdvcmxkIHBvcHVsYXRlZCBvbmUuIEEgZGVsdGEgaXMgb25seSBtZWFuaW5nZnVsIHdoZW4gdGhlIGNhbGxlclxuICogcmVxdWVzdGVkIGl0IChgc2luY2VDdXJzb3JgIHdhcyBwYXNzZWQpIGFuZCB0aGUgV29ybGQgcmV0dXJuZWQgYm90aFxuICogYGV2ZW50c2AgYW5kIGEgYGN1cnNvcmA7IG90aGVyd2lzZSB3ZSByZXR1cm4gdW5kZWZpbmVkIGFuZCB0aGUgY2FsbGVyXG4gKiBmYWxscyBiYWNrIHRvIHRoZSBub3JtYWwgaW5jcmVtZW50YWwgYGV2ZW50cy5saXN0YC4gYGhhc01vcmVgIGRlZmF1bHRzXG4gKiB0byBmYWxzZSAoc2luZ2xlIHBhZ2UpIHdoZW4gdGhlIFdvcmxkIG9taXRzIGl0LlxuICovXG5mdW5jdGlvbiBleHRyYWN0SW5saW5lRGVsdGEoXG4gIHJlc3VsdDogeyBldmVudHM/OiBFdmVudFtdOyBjdXJzb3I/OiBzdHJpbmcgfCBudWxsOyBoYXNNb3JlPzogYm9vbGVhbiB9LFxuICByZXF1ZXN0ZWQ6IGJvb2xlYW5cbik6IElubGluZUV2ZW50RGVsdGEgfCB1bmRlZmluZWQge1xuICBpZiAoIXJlcXVlc3RlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgaWYgKCFyZXN1bHQuZXZlbnRzIHx8IHJlc3VsdC5jdXJzb3IgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHtcbiAgICBldmVudHM6IHJlc3VsdC5ldmVudHMsXG4gICAgY3Vyc29yOiByZXN1bHQuY3Vyc29yLFxuICAgIGhhc01vcmU6IHJlc3VsdC5oYXNNb3JlID8/IGZhbHNlLFxuICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0ZXBFeGVjdXRvclBhcmFtcyB7XG4gIHdvcmxkOiBXb3JsZDtcbiAgd29ya2Zsb3dSdW5JZDogc3RyaW5nO1xuICAvKiogRGVwbG95bWVudCB0aGF0IG93bnMgdGhlIHdvcmtmbG93IHJ1biwgZm9yIGZvcndhcmRlZCB3cml0YWJsZSBzdHJlYW1zLiAqL1xuICB3b3JrZmxvd0RlcGxveW1lbnRJZD86IHN0cmluZztcbiAgd29ya2Zsb3dOYW1lOiBzdHJpbmc7XG4gIHdvcmtmbG93U3RhcnRlZEF0OiBudW1iZXI7XG4gIHN0ZXBJZDogc3RyaW5nO1xuICBzdGVwTmFtZTogc3RyaW5nO1xuICBlbmNyeXB0aW9uS2V5PzogQ3J5cHRvS2V5O1xuICAvKipcbiAgICogVGhlIHdvcmtmbG93IHJ1bidzIHNwZWNWZXJzaW9uLCB1c2VkIHRvIGdhdGUgcGF5bG9hZCBjb21wcmVzc2lvbi5cbiAgICogU3RlcCBvdXRwdXRzL2Vycm9ycyBhcmUgb25seSBnemlwLWNvbXByZXNzZWQgd2hlbiB0aGUgcnVuIGlzIG1hcmtlZFxuICAgKiBhcyBwb3NzaWJseSBjb250YWluaW5nIGNvbXByZXNzZWQgcGF5bG9hZHMgKHNwZWNWZXJzaW9uID49IDUpLlxuICAgKi9cbiAgcnVuU3BlY1ZlcnNpb24/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBMYXp5IHN0ZXAgc3RhcnQ6IHRoZSBhbHJlYWR5LWRlaHlkcmF0ZWQgc3RlcCBpbnB1dC4gV2hlbiBwcm92aWRlZCwgdGhlXG4gICAqIGBzdGVwX3N0YXJ0ZWRgIGV2ZW50IGNhcnJpZXMgdGhpcyBpbnB1dCBzbyB0aGUgd29ybGQgY3JlYXRlcyB0aGUgc3RlcCBvblxuICAgKiB0aGUgZmx5IChubyBzZXBhcmF0ZSBgc3RlcF9jcmVhdGVkYCByb3VuZC10cmlwKS4gU2V0IGJ5IHRoZSBvd25lZC1pbmxpbmVcbiAgICogcGF0aCBmb3IgdGhlIHN0ZXAgd2hvc2UgYHN0ZXBfY3JlYXRlZGAgdGhlIHN1c3BlbnNpb24gaGFuZGxlciBkZWZlcnJlZC5cbiAgICogVGhlIHdvcmxkJ3MgYXRvbWljIGNyZWF0ZS1jbGFpbSBpcyB0aGUgZXhhY3RseS1vbmUtb3duZXIgZ2F0ZTogbG9zaW5nIGl0XG4gICAqIHN1cmZhY2VzIGFzIGBFbnRpdHlDb25mbGljdEVycm9yYCDihpIgYHsgdHlwZTogJ3NraXBwZWQnIH1gLCBzbyBhIGhhbmRsZXJcbiAgICogdGhhdCBkaWQgbm90IHdpbiB0aGUgY3JlYXRlIG5ldmVyIHJ1bnMgdGhlIGJvZHkuIE9taXR0ZWQgb24gZXZlcnkgb3RoZXJcbiAgICogcGF0aCwgd2hlcmUgdGhlIHN0ZXAgYWxyZWFkeSBoYXMgYSBgc3RlcF9jcmVhdGVkYCBhbmQgYHN0ZXBfc3RhcnRlZGBcbiAgICogY2FycmllcyBubyBwYXlsb2FkICh0aGUgbGVnYWN5IGNvbnRyYWN0KS5cbiAgICovXG4gIGxhenlTdGVwSW5wdXQ/OiBTZXJpYWxpemVkRGF0YTtcbiAgLyoqXG4gICAqIElubGluZS1kZWx0YSBvcHRpbWl6YXRpb24gKG9wdC1pbikuIFdoZW4gcHJvdmlkZWQsIHRoZSBjdXJzb3Igb2YgdGhlXG4gICAqIGV2ZW50IGxvZyBhcyBvYnNlcnZlZCBieSB0aGUgY2FsbGVyICpiZWZvcmUqIHRoaXMgc3RlcCdzIGV2ZW50cyB3ZXJlXG4gICAqIHdyaXR0ZW4uIEl0IGlzIHRocmVhZGVkIGludG8gdGhlIHN0ZXAtdGVybWluYWwgYGV2ZW50cy5jcmVhdGVgIHNvIGFcbiAgICogc3VwcG9ydGluZyBXb3JsZCBjYW4gcmV0dXJuIHRoZSBkZWx0YSBvZiBldmVudHMgd3JpdHRlbiBzaW5jZSAoc2VlXG4gICAqIHtAbGluayBpbXBvcnQoJ0B3b3JrZmxvdy93b3JsZCcpLkNyZWF0ZUV2ZW50UGFyYW1zLnNpbmNlQ3Vyc29yfSkuXG4gICAqIE9ubHkgc2V0IHRoaXMgd2hlbiBgY29ycmVsYXRpb25JZGAtYmFzZWQgb3duZXJzaGlwIGd1YXJhbnRlZXMgdGhpc1xuICAgKiBoYW5kbGVyIGlzIHRoZSBzb2xlIGlubGluZSB3cml0ZXIgZm9yIHRoZSBydW4gb24gdGhpcyBpdGVyYXRpb24uXG4gICAqL1xuICBpbmxpbmVEZWx0YVNpbmNlQ3Vyc29yPzogc3RyaW5nO1xuICAvKipcbiAgICogRm9yY2Ugb3B0aW1pc3RpYyBpbmxpbmUgc3RhcnQgcmVnYXJkbGVzcyBvZlxuICAgKiBgV09SS0ZMT1dfT1BUSU1JU1RJQ19JTkxJTkVfU1RBUlRgLiBTZXQgYnkgdHVyYm8gbW9kZSBvbiB0aGUgZmlyc3QgZGVsaXZlcnlcbiAgICogb2YgdGhlIGZpcnN0IGludm9jYXRpb24sIHdoZXJlIGZvcmNpbmcgaXQgaXMgc2FmZTogdGhlcmUgaXMgbm8gY29uY3VycmVudFxuICAgKiBwZWVyIGhhbmRsZXIgdG8gcmFjZSB0aGUgY3JlYXRlLWNsYWltLCBzbyB0aGUgYm9keSBydW5zIGV4YWN0bHkgb25jZS4gT25seVxuICAgKiBtZWFuaW5nZnVsIHRvZ2V0aGVyIHdpdGggYGxhenlTdGVwSW5wdXRgIChhIGJyYW5kLW5ldyBsYXp5IHN0ZXApLlxuICAgKi9cbiAgZm9yY2VPcHRpbWlzdGljU3RhcnQ/OiBib29sZWFuO1xuICAvKipcbiAgICogVHVyYm8gbW9kZSBvbmx5OiBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYWNrZ3JvdW5kZWRcbiAgICogYHJ1bl9zdGFydGVkYCBoYXMgbGFuZGVkLiBXaGVuIHNldCwgdGhlIGxhenkvb3B0aW1pc3RpYyBgc3RlcF9zdGFydGVkYCBpc1xuICAgKiBjaGFpbmVkIG9uIGl0IHNvIHRoZSBzdGVwIGlzIG5ldmVyIGNyZWF0ZWQgYmVmb3JlIGl0cyBydW4gZXhpc3RzLiBUaGUgYm9keVxuICAgKiBzdGlsbCBydW5zIGltbWVkaWF0ZWx5IGFnYWluc3QgbG9jYWxseS1zeW50aGVzaXplZCBzdGF0ZSDigJQgb25seSB0aGUgbmV0d29ya1xuICAgKiB3cml0ZSB3YWl0cyDigJQgc28gdGhlIGBydW5fc3RhcnRlZGAgcm91bmQtdHJpcCBvdmVybGFwcyB0aGUgYm9keS4gYHVuZGVmaW5lZGBcbiAgICogb3V0c2lkZSB0dXJibywgd2hlcmUgYHJ1bl9zdGFydGVkYCB3YXMgYWxyZWFkeSBhd2FpdGVkIHVwIGZyb250LlxuICAgKi9cbiAgcnVuUmVhZHlCYXJyaWVyPzogUHJvbWlzZTx1bmtub3duPjtcbn1cblxuLyoqXG4gKiBJbmxpbmUtZGVsdGEgcmV0dXJuZWQgYnkgYSBzdGVwLXRlcm1pbmFsIHdyaXRlIHdoZW4gdGhlIGNhbGxlciBwYXNzZWRcbiAqIHtAbGluayBTdGVwRXhlY3V0b3JQYXJhbXMuaW5saW5lRGVsdGFTaW5jZUN1cnNvcn0gYW5kIHRoZSBXb3JsZCBzdXBwb3J0c1xuICogdGhlIG9wdGltaXphdGlvbi4gYGV2ZW50c2AgYXJlIHRoZSBldmVudHMgd3JpdHRlbiBzdHJpY3RseSBhZnRlciB0aGF0XG4gKiBjdXJzb3IgKHRoaXMgc3RlcCdzIGV2ZW50cyBwbHVzIGFueXRoaW5nIGludGVybGVhdmVkIGluLWJhbmQpLCBgY3Vyc29yYFxuICogaXMgdGhlIHBvc2l0aW9uIHBhc3QgdGhlIGxhc3Qgb25lLCBhbmQgYGhhc01vcmVgIHNpZ25hbHMgYSBmdXJ0aGVyIHBhZ2VcbiAqICh0aGUgY2FsbGVyIHRoZW4gZmFsbHMgYmFjayB0byBhIGZ1bGwgaW5jcmVtZW50YWwgZmV0Y2gpLiBBYnNlbnQgd2hlblxuICogdGhlIFdvcmxkIGRpZCBub3QgcmV0dXJuIGEgZGVsdGEuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW5saW5lRXZlbnREZWx0YSB7XG4gIGV2ZW50czogRXZlbnRbXTtcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsO1xuICBoYXNNb3JlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBhIHN0ZXAgZXhlY3V0aW9uIGF0dGVtcHQuIFRoZSBjYWxsZXIgZGVjaWRlcyB3aGF0IHRvIGRvXG4gKiBiYXNlZCBvbiB0aGUgcmVzdWx0IHR5cGUgKGUuZy4sIHF1ZXVlIHdvcmtmbG93IGNvbnRpbnVhdGlvbiwgcmVwbGF5IGlubGluZSwgZXRjLikuXG4gKlxuICogYGlubGluZURlbHRhYCBpcyBhdHRhY2hlZCB0byBhIGBjb21wbGV0ZWRgIHJlc3VsdCB3aGVuIHRoZSBjYWxsZXJcbiAqIHJlcXVlc3RlZCBpdCB2aWEge0BsaW5rIFN0ZXBFeGVjdXRvclBhcmFtcy5pbmxpbmVEZWx0YVNpbmNlQ3Vyc29yfSBhbmRcbiAqIHRoZSBXb3JsZCByZXR1cm5lZCBvbmUuIFN0ZXAgZmFpbHVyZXMgYXJlIHJhcmUgYW5kIG5vdCB0aGUgaW5saW5lXG4gKiBvcHRpbWl6YXRpb24ncyB0YXJnZXQsIHNvIHRoZSBgZmFpbGVkYCBwYXRoIGxlYXZlcyBpdCB0byB0aGUgbm9ybWFsXG4gKiBpbmNyZW1lbnRhbCBmZXRjaC5cbiAqL1xuZXhwb3J0IHR5cGUgU3RlcEV4ZWN1dGlvblJlc3VsdCA9XG4gIHwge1xuICAgICAgdHlwZTogJ2NvbXBsZXRlZCc7XG4gICAgICBoYXNQZW5kaW5nT3BzPzogYm9vbGVhbjtcbiAgICAgIGlubGluZURlbHRhPzogSW5saW5lRXZlbnREZWx0YTtcbiAgICB9XG4gIHwgeyB0eXBlOiAnZmFpbGVkJyB9XG4gIHwgeyB0eXBlOiAncmV0cnknOyB0aW1lb3V0U2Vjb25kczogbnVtYmVyIH1cbiAgfCB7IHR5cGU6ICdza2lwcGVkJyB9XG4gIHwgeyB0eXBlOiAnZ29uZScgfVxuICB8IHsgdHlwZTogJ3Rocm90dGxlZCc7IHRpbWVvdXRTZWNvbmRzOiBudW1iZXIgfTtcblxuLyoqXG4gKiBFeGVjdXRlcyBhIHNpbmdsZSBzdGVwOiBjcmVhdGVzIHN0ZXBfc3RhcnRlZCBldmVudCwgaHlkcmF0ZXMgaW5wdXQsXG4gKiBydW5zIHRoZSBzdGVwIGZ1bmN0aW9uLCBjcmVhdGVzIHN0ZXBfY29tcGxldGVkL3N0ZXBfZmFpbGVkL3N0ZXBfcmV0cnlpbmcgZXZlbnRzLlxuICpcbiAqIERvZXMgTk9UIHF1ZXVlIHdvcmtmbG93IGNvbnRpbnVhdGlvbiBtZXNzYWdlcyDigJQgdGhlIGNhbGxlciBkZWNpZGVzIHdoYXQgdG8gZG8gbmV4dC5cbiAqIFVzZWQgYnkgYm90aCB0aGUgVjEgc3RlcCBoYW5kbGVyIGFuZCB0aGUgVjIgY29tYmluZWQgaGFuZGxlci5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV4ZWN1dGVTdGVwKFxuICBwYXJhbXM6IFN0ZXBFeGVjdXRvclBhcmFtc1xuKTogUHJvbWlzZTxTdGVwRXhlY3V0aW9uUmVzdWx0PiB7XG4gIGNvbnN0IHtcbiAgICB3b3JsZCxcbiAgICB3b3JrZmxvd1J1bklkLFxuICAgIHdvcmtmbG93TmFtZSxcbiAgICB3b3JrZmxvd1N0YXJ0ZWRBdCxcbiAgICBzdGVwSWQsXG4gICAgc3RlcE5hbWUsXG4gIH0gPSBwYXJhbXM7XG4gIGNvbnN0IGlzVmVyY2VsID0gcHJvY2Vzcy5lbnYuVkVSQ0VMX1VSTCAhPT0gdW5kZWZpbmVkO1xuICAvLyBHYXRlIHBheWxvYWQgY29tcHJlc3Npb24gb24gdGhlIHJ1bidzIHNwZWNWZXJzaW9uOiBvbmx5IHJ1bnMgbWFya2VkXG4gIC8vIGFzIHBvc3NpYmx5IGNvbnRhaW5pbmcgY29tcHJlc3NlZCBwYXlsb2FkcyAoc3BlYyA+PSA1KSBnZXQgZ3ppcCBkYXRhLlxuICBjb25zdCBjb21wcmVzc2lvbiA9XG4gICAgKHBhcmFtcy5ydW5TcGVjVmVyc2lvbiA/PyAwKSA+PSBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ09NUFJFU1NJT047XG5cbiAgY29uc3Qgc3Bhbk5hbWUgPSBgc3RlcC5leGVjdXRlICR7c3RlcERpc3BsYXlOYW1lKHN0ZXBOYW1lKX1gO1xuICByZXR1cm4gdHJhY2Uoc3Bhbk5hbWUsIHt9LCBhc3luYyAoc3BhbikgPT4ge1xuICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgLi4uQXR0cmlidXRlLlN0ZXBOYW1lKHN0ZXBOYW1lKSxcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd05hbWUod29ya2Zsb3dOYW1lKSxcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1bklkKHdvcmtmbG93UnVuSWQpLFxuICAgICAgLi4uQXR0cmlidXRlLlN0ZXBJZChzdGVwSWQpLFxuICAgIH0pO1xuXG4gICAgLy8gTWVtb2l6ZWQgYWNjZXNzb3IgZm9yIHRoZSBwZXItcnVuIGVuY3J5cHRpb24ga2V5LiBUaGUgZmlyc3QgY2FsbGVyXG4gICAgLy8gKGlucHV0IGh5ZHJhdGlvbiBvbiB0aGUgc3VjY2VzcyBwYXRoLCBvciBvbmUgb2YgdGhlIGVhcmx5LXJldHVyblxuICAgIC8vIGRlaHlkcmF0ZVN0ZXBFcnJvciBwYXRocyBpZiBzdGVwX3N0YXJ0ZWQgZmFpbHMpIHRyaWdnZXJzIHRoZSBhY3R1YWxcbiAgICAvLyBmZXRjaCAvIEhLREYgZGVyaXZhdGlvbjsgc3Vic2VxdWVudCBjYWxsZXJzIGF3YWl0IHRoZSBjYWNoZWQgcHJvbWlzZS5cbiAgICBjb25zdCBnZXRFbmNyeXB0aW9uS2V5ID0gbWVtb2l6ZUVuY3J5cHRpb25LZXkod29ybGQsIHdvcmtmbG93UnVuSWQpO1xuXG4gICAgY29uc3Qgc3RlcEZuID0gZ2V0U3RlcEZ1bmN0aW9uKHN0ZXBOYW1lKTtcbiAgICBpZiAoIXN0ZXBGbiB8fCB0eXBlb2Ygc3RlcEZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyBTdGVwIGZ1bmN0aW9uIG5vdCByZWdpc3RlcmVkIOKAlCBmYWlsIHRoZSBzdGVwIGltbWVkaWF0ZWx5IChub3QgdGhlIHJ1bikuXG4gICAgICAvLyBUaGlzIG1hdGNoZXMgdGhlIFYxIHN0ZXAgaGFuZGxlciBwYXR0ZXJuOiBjcmVhdGUgc3RlcF9mYWlsZWQgZXZlbnQgc29cbiAgICAgIC8vIHRoZSB3b3JrZmxvdyBjYW4gaGFuZGxlIGl0IGdyYWNlZnVsbHkgdmlhIHRyeS9jYXRjaCBpbiB1c2VyIGNvZGUuXG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBgU3RlcCBcIiR7c3RlcE5hbWV9XCIgaXMgbm90IHJlZ2lzdGVyZWQgaW4gdGhlIGN1cnJlbnQgZGVwbG95bWVudC4gVGhpcyB1c3VhbGx5IGluZGljYXRlcyBhIGJ1aWxkIG9yIGJ1bmRsaW5nIGlzc3VlIHRoYXQgY2F1c2VkIHRoZSBzdGVwIHRvIG5vdCBiZSBpbmNsdWRlZCBpbiB0aGUgZGVwbG95bWVudC5gO1xuICAgICAgcnVudGltZUxvZ2dlci5lcnJvcignU3RlcCBmdW5jdGlvbiBub3QgcmVnaXN0ZXJlZCwgZmFpbGluZyBzdGVwJywge1xuICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgc3RlcElkLFxuICAgICAgfSk7XG4gICAgICAvLyBPbiB0aGUgbGF6eSBpbmxpbmUgcGF0aCB0aGUgc3VzcGVuc2lvbiBoYW5kbGVyIGRlZmVycmVkIHRoaXMgc3RlcCdzXG4gICAgICAvLyBgc3RlcF9jcmVhdGVkYCwgZXhwZWN0aW5nIGV4ZWN1dGVTdGVwIHRvIG1hdGVyaWFsaXplIHRoZSBzdGVwIHZpYSBhXG4gICAgICAvLyBsYXp5IGBzdGVwX3N0YXJ0ZWRgIGNhcnJ5aW5nIGl0cyBpbnB1dC4gV2UgbmV2ZXIgZ2V0IHRoYXQgZmFyIGZvciBhblxuICAgICAgLy8gdW5yZWdpc3RlcmVkIHN0ZXAsIHNvIHRoZSBzdGVwIGVudGl0eSBkb2VzIG5vdCBleGlzdCB5ZXQg4oCUIHdyaXRpbmdcbiAgICAgIC8vIGBzdGVwX2ZhaWxlZGAgc3RyYWlnaHQgYXdheSB3b3VsZCBoaXQgdGhlIHdvcmxkJ3MgXCJzdGVwIG11c3QgZXhpc3RcIlxuICAgICAgLy8gb3JkZXJpbmcgZ3VhcmQgYW5kIHdlZGdlIHRoZSBydW4uIFNlbmQgdGhlIGxhenkgYHN0ZXBfc3RhcnRlZGAgZmlyc3RcbiAgICAgIC8vIChpdCBjcmVhdGVzIHRoZSBzdGVwICsgc3ludGhldGljIGBzdGVwX2NyZWF0ZWRgIGF0b21pY2FsbHkgYW5kIGtlZXBzXG4gICAgICAvLyByZXBsYXkgY29ycmVjdCksIHRoZW4gZmFpbCBpdCBiZWxvdy4gVGhpcyBhbHNvIHByZXNlcnZlcyB0aGVcbiAgICAgIC8vIGV4YWN0bHktb25lLW93bmVyIGd1YXJhbnRlZTogYSBjb25jdXJyZW50IGhhbmRsZXIgdGhhdCB3b24gdGhlIGNyZWF0ZVxuICAgICAgLy8gbWFrZXMgb3VyIGxhenkgYHN0ZXBfc3RhcnRlZGAgcmVqZWN0IHdpdGggRW50aXR5Q29uZmxpY3RFcnJvciDihpIgd2VcbiAgICAgIC8vIHJldHVybiBgc2tpcHBlZGAgYW5kIG5ldmVyIHdyaXRlIHRoZSBmYWlsdXJlIHR3aWNlLlxuICAgICAgaWYgKHBhcmFtcy5sYXp5U3RlcElucHV0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBUdXJibzogdGhpcyBsYXp5IGBzdGVwX3N0YXJ0ZWRgIG11c3Qgbm90IHByZWNlZGUgdGhlIGJhY2tncm91bmRlZFxuICAgICAgICAgIC8vIGBydW5fc3RhcnRlZGAuIE9yZGVyIGl0IGFmdGVyIHRoZSBydW4tcmVhZHkgYmFycmllciAoYmVzdC1lZmZvcnQg4oCUXG4gICAgICAgICAgLy8gYSBiYXJyaWVyIHJlamVjdGlvbiBtZWFucyB0aGUgcnVuIGRvZXNuJ3QgZXhpc3QsIGFuZCB0aGUgY3JlYXRlXG4gICAgICAgICAgLy8gYmVsb3cgc3VyZmFjZXMgdGhlIHJlYWwgZXJyb3IpLiBOby1vcCBvdXRzaWRlIHR1cmJvLlxuICAgICAgICAgIGlmIChwYXJhbXMucnVuUmVhZHlCYXJyaWVyKSB7XG4gICAgICAgICAgICBhd2FpdCBwYXJhbXMucnVuUmVhZHlCYXJyaWVyLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX3N0YXJ0ZWQnLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgZXZlbnREYXRhOiB7IHN0ZXBOYW1lLCB3b3JrZmxvd05hbWUsIGlucHV0OiBwYXJhbXMubGF6eVN0ZXBJbnB1dCB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChzdGFydEVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKHN0YXJ0RXJyKSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChSdW5FeHBpcmVkRXJyb3IuaXMoc3RhcnRFcnIpKSB7XG4gICAgICAgICAgICByZXR1cm4geyB0eXBlOiAnZ29uZScgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgc3RhcnRFcnI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUod29ya2Zsb3dSdW5JZCwge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfZmFpbGVkJyxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICBuZXcgRmF0YWxFcnJvcihlcnJvck1lc3NhZ2UpLFxuICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICBhd2FpdCBnZXRFbmNyeXB0aW9uS2V5KCksXG4gICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgICAgICBjb21wcmVzc2lvblxuICAgICAgICAgICAgKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKHN0ZXBGYWlsRXJyKSB7XG4gICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKHN0ZXBGYWlsRXJyKSkge1xuICAgICAgICAgIHJldHVybiB7IHR5cGU6ICdza2lwcGVkJyB9O1xuICAgICAgICB9XG4gICAgICAgIHRocm93IHN0ZXBGYWlsRXJyO1xuICAgICAgfVxuICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBGYXRhbEVycm9yKHRydWUpLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4geyB0eXBlOiAnZmFpbGVkJyB9O1xuICAgIH1cblxuICAgIGNvbnN0IG1heFJldHJpZXMgPSBzdGVwRm4ubWF4UmV0cmllcyA/PyBERUZBVUxUX1NURVBfTUFYX1JFVFJJRVM7XG5cbiAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwTWF4UmV0cmllcyhtYXhSZXRyaWVzKSxcbiAgICB9KTtcblxuICAgIC8vIE1hcHMgYSBgc3RlcF9zdGFydGVkYCByZWplY3Rpb24gdG8gYSB0ZXJtaW5hbCBTdGVwRXhlY3V0aW9uUmVzdWx0LFxuICAgIC8vIHNoYXJlZCBieSB0aGUgYXdhaXQgcGF0aCAoYmVsb3cpIGFuZCB0aGUgb3B0aW1pc3RpYy1zdGFydCByZWNvbmNpbGlhdGlvbi5cbiAgICAvLyBSZXR1cm5zIHVuZGVmaW5lZCB3aGVuIHRoZSBlcnJvciBpcyBub3Qgb25lIHdlIHRyYW5zbGF0ZSAoY2FsbGVyIHJldGhyb3dzKS5cbiAgICBjb25zdCBzdGFydEVycm9yVG9SZXN1bHQgPSAoXG4gICAgICBlcnI6IHVua25vd25cbiAgICApOiBTdGVwRXhlY3V0aW9uUmVzdWx0IHwgdW5kZWZpbmVkID0+IHtcbiAgICAgIGlmIChUaHJvdHRsZUVycm9yLmlzKGVycikpIHtcbiAgICAgICAgY29uc3QgcmV0cnlBZnRlciA9IE1hdGgubWF4KFxuICAgICAgICAgIDEsXG4gICAgICAgICAgdHlwZW9mIGVyci5yZXRyeUFmdGVyID09PSAnbnVtYmVyJyA/IGVyci5yZXRyeUFmdGVyIDogMVxuICAgICAgICApO1xuICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1Rocm90dGxlZCBvbiBzdGVwX3N0YXJ0ZWQsIGRlZmVycmluZycsIHtcbiAgICAgICAgICByZXRyeUFmdGVyU2Vjb25kczogcmV0cnlBZnRlcixcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB7IHR5cGU6ICd0aHJvdHRsZWQnLCB0aW1lb3V0U2Vjb25kczogcmV0cnlBZnRlciB9O1xuICAgICAgfVxuICAgICAgaWYgKFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICBgV29ya2Zsb3cgcnVuIFwiJHt3b3JrZmxvd1J1bklkfVwiIGhhcyBhbHJlYWR5IGNvbXBsZXRlZCwgc2tpcHBpbmcgc3RlcCBcIiR7c3RlcElkfVwiOiAke2Vyci5tZXNzYWdlfWBcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHsgdHlwZTogJ2dvbmUnIH07XG4gICAgICB9XG4gICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1N0ZXAgaW4gdGVybWluYWwgc3RhdGUsIHNraXBwaW5nJywge1xuICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gICAgICAgIH0pO1xuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFNraXBwZWQodHJ1ZSksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBTa2lwUmVhc29uKCdjb21wbGV0ZWQnKSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB7IHR5cGU6ICdza2lwcGVkJyB9O1xuICAgICAgfVxuICAgICAgaWYgKFRvb0Vhcmx5RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICBjb25zdCB0aW1lb3V0U2Vjb25kcyA9IE1hdGgubWF4KDEsIGVyci5yZXRyeUFmdGVyID8/IDEpO1xuICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdTdGVwIHJldHJ5QWZ0ZXIgdGltZXN0YW1wIG5vdCB5ZXQgcmVhY2hlZCcsIHtcbiAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgdGltZW91dFNlY29uZHMsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4geyB0eXBlOiAncmV0cnknLCB0aW1lb3V0U2Vjb25kcyB9O1xuICAgICAgfVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9O1xuXG4gICAgLy8gT3B0aW1pc3RpYyBpbmxpbmUgc3RhcnQ6IHdoZW4gd2UgaG9sZCB0aGUgc3RlcCBpbnB1dCBsb2NhbGx5IChsYXp5IGlubGluZVxuICAgIC8vIHBhdGgpIGFuZCB0aGUgb3B0aW1pemF0aW9uIGlzIGVuYWJsZWQsIGZpcmUgYHN0ZXBfc3RhcnRlZGAgV0lUSE9VVFxuICAgIC8vIGF3YWl0aW5nIGFuZCBydW4gdGhlIGJvZHkgYWdhaW5zdCBsb2NhbGx5LXN5bnRoZXNpemVkIHN0YXRlLiBBIGxhenkgc3RlcFxuICAgIC8vIGlzIGFsd2F5cyBicmFuZC1uZXcg4oeSIGF0dGVtcHQgMSwgbm8gcHJpb3IgZXJyb3IsIHN0YXJ0ZWQgbm93IOKAlCBzbyB3ZVxuICAgIC8vIGRvbid0IG5lZWQgdGhlIHNlcnZlciByb3VuZC10cmlwIHRvIGJlZ2luLiBXZSByZWNvbmNpbGUgdGhlIGluLWZsaWdodFxuICAgIC8vIGBzdGVwX3N0YXJ0ZWRgIGJlZm9yZSBhbnkgdGVybWluYWwgd3JpdGUgKGByZWNvbmNpbGVPcHRpbWlzdGljU3RhcnRgKTogaWZcbiAgICAvLyBpdCBsb3N0IHRoZSBhdG9taWMgY3JlYXRlLWNsYWltICg0MDkpIG9yIHRoZSBydW4gaXMgZ29uZS90aHJvdHRsZWQsIHdlXG4gICAgLy8gZGlzY2FyZCB0aGUgYm9keSByZXN1bHQuIFJ1bm5pbmcgdGhlIGJvZHkgYmVmb3JlIGNvbmZpcm1pbmcgb3duZXJzaGlwIGNhblxuICAgIC8vIGV4ZWN1dGUgYSBzdGVwIG1vcmUgdGhhbiBvbmNlIHdoZW4gaGFuZGxlcnMgcmFjZSDigJQgaW5saW5lIHN0ZXAgYm9kaWVzXG4gICAgLy8gbXVzdCBiZSBpZGVtcG90ZW50OyBkaXNhYmxlIHZpYSBXT1JLRkxPV19PUFRJTUlTVElDX0lOTElORV9TVEFSVD0wLlxuICAgIC8vXG4gICAgLy8gVHVyYm8gbW9kZSBwYXNzZXMgYGZvcmNlT3B0aW1pc3RpY1N0YXJ0YCB0byBlbmFibGUgdGhpcyByZWdhcmRsZXNzIG9mIHRoZVxuICAgIC8vIGVudiBmbGFnIChpdHMgc2luZ2xlLWhhbmRsZXIgZ3VhcmFudGVlIHJlbW92ZXMgdGhlIHJhY2UpLiBCdXQgaXQgc3RpbGxcbiAgICAvLyBkZWZlcnMgdG8gYW4gKmV4cGxpY2l0KiBgV09SS0ZMT1dfT1BUSU1JU1RJQ19JTkxJTkVfU1RBUlQ9MGA6IGZvcmNlZFxuICAgIC8vIG9wdGltaXN0aWMgc3RhcnQgcnVucyB0aGUgYm9keSBiZWZvcmUgYHN0ZXBfc3RhcnRlZGAvYHJ1bl9zdGFydGVkYCBpc1xuICAgIC8vIGNvbmZpcm1lZCwgd2hpY2ggaXMgZXhhY3RseSB0aGUgcHJvcGVydHkgYW4gb3BlcmF0b3Igb3B0cyBvdXQgb2Ygd2l0aCB0aGF0XG4gICAgLy8gZmxhZywgc28gYW4gZXhwbGljaXQgb3B0LW91dCB3aW5zIG92ZXIgdHVyYm8ncyBmb3JjZS5cbiAgICBjb25zdCBvcHRpbWlzdGljU3RhcnQgPVxuICAgICAgcGFyYW1zLmxhenlTdGVwSW5wdXQgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgKGlzT3B0aW1pc3RpY0lubGluZVN0YXJ0RW5hYmxlZCgpIHx8XG4gICAgICAgIChwYXJhbXMuZm9yY2VPcHRpbWlzdGljU3RhcnQgPT09IHRydWUgJiZcbiAgICAgICAgICAhaXNPcHRpbWlzdGljSW5saW5lU3RhcnRFeHBsaWNpdGx5RGlzYWJsZWQoKSkpO1xuXG4gICAgbGV0IHN0ZXA6IFN0ZXA7XG4gICAgLy8gU2V0dGxlZCBvdXRjb21lIG9mIHRoZSBpbi1mbGlnaHQgb3B0aW1pc3RpYyBgc3RlcF9zdGFydGVkYC4gSGFuZGxlcnMgYXJlXG4gICAgLy8gYXR0YWNoZWQgc3luY2hyb25vdXNseSAoYC50aGVuKG9rLCBlcnIpYCkgc28gYSBmYXN0IHJlamVjdGlvbiBuZXZlclxuICAgIC8vIHN1cmZhY2VzIGFzIGFuIHVuaGFuZGxlZFJlamVjdGlvbiB3aGlsZSB0aGUgYm9keSBydW5zLlxuICAgIGxldCBvcHRpbWlzdGljU3RhcnRTZXR0bGVkOlxuICAgICAgfCBQcm9taXNlPHsgb2s6IHRydWUgfSB8IHsgb2s6IGZhbHNlOyBlcnI6IHVua25vd24gfT5cbiAgICAgIHwgdW5kZWZpbmVkO1xuICAgIC8vIEF3YWl0IHRoZSBvcHRpbWlzdGljIGBzdGVwX3N0YXJ0ZWRgIG91dGNvbWUgYW5kIHRyYW5zbGF0ZSBhIGxvc3QgcmFjZSAvXG4gICAgLy8gdGVybWluYWwgcnVuIC8gdGhyb3R0bGUgaW50byBhIHJlc3VsdCB0aGF0IHNob3J0LWNpcmN1aXRzIHRoZSBib2R5XG4gICAgLy8gb3V0cHV0LiBSZXR1cm5zIHVuZGVmaW5lZCB3aGVuIHdlIG93biB0aGUgc3RlcCBhbmQgbWF5IHdyaXRlIGl0cyB0ZXJtaW5hbFxuICAgIC8vIGV2ZW50LiBBIG5vbi10cmFuc2xhdGFibGUgcmVqZWN0aW9uIGlzIHJldGhyb3duIChzbyBhIHRyYW5zaWVudFxuICAgIC8vIHN0ZXBfc3RhcnRlZCBmYWlsdXJlIHByb3BhZ2F0ZXMgdG8gdGhlIHF1ZXVlIGhhbmRsZXIgZm9yIHJlZGVsaXZlcnksXG4gICAgLy8gZXhhY3RseSBhcyBvbiB0aGUgYXdhaXQgcGF0aCkuIElkZW1wb3RlbnQg4oCUIHNhZmUgdG8gY2FsbCBtb3JlIHRoYW4gb25jZS5cbiAgICBjb25zdCByZWNvbmNpbGVPcHRpbWlzdGljU3RhcnQgPSBhc3luYyAoKTogUHJvbWlzZTxcbiAgICAgIFN0ZXBFeGVjdXRpb25SZXN1bHQgfCB1bmRlZmluZWRcbiAgICA+ID0+IHtcbiAgICAgIGlmICghb3B0aW1pc3RpY1N0YXJ0U2V0dGxlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBvcHRpbWlzdGljU3RhcnRTZXR0bGVkO1xuICAgICAgaWYgKHNldHRsZWQub2spIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBtYXBwZWQgPSBzdGFydEVycm9yVG9SZXN1bHQoc2V0dGxlZC5lcnIpO1xuICAgICAgaWYgKCFtYXBwZWQpIHRocm93IHNldHRsZWQuZXJyO1xuICAgICAgcmV0dXJuIG1hcHBlZDtcbiAgICB9O1xuXG4gICAgaWYgKG9wdGltaXN0aWNTdGFydCkge1xuICAgICAgLy8gQ2hhaW4gdGhlIGxhenkgYHN0ZXBfc3RhcnRlZGAgb24gdGhlIHJ1bi1yZWFkeSBiYXJyaWVyICh0dXJibyBtb2RlKTpcbiAgICAgIC8vIHRoZSBzdGVwIGNhbid0IGJlIGNyZWF0ZWQgYmVmb3JlIGl0cyBydW4gZXhpc3RzLCBidXQgdGhlIGJvZHkgYmVsb3dcbiAgICAgIC8vIHJ1bnMgaW1tZWRpYXRlbHkgYWdhaW5zdCBzeW50aGVzaXplZCBzdGF0ZSwgc28gdGhlIGBydW5fc3RhcnRlZGBcbiAgICAgIC8vIHJvdW5kLXRyaXAgb3ZlcmxhcHMgdGhlIGJvZHkgcmF0aGVyIHRoYW4gYmxvY2tpbmcgaXQuIE91dHNpZGUgdHVyYm8gdGhlXG4gICAgICAvLyBiYXJyaWVyIGlzIHVuZGVmaW5lZCBhbmQgdGhpcyBpcyBhIHBsYWluIGNyZWF0ZS5cbiAgICAgIGNvbnN0IHN0YXJ0ZWRQcm9taXNlID0gKHBhcmFtcy5ydW5SZWFkeUJhcnJpZXIgPz8gUHJvbWlzZS5yZXNvbHZlKCkpLnRoZW4oXG4gICAgICAgICgpID0+XG4gICAgICAgICAgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX3N0YXJ0ZWQnLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogc3RlcElkLFxuICAgICAgICAgICAgZXZlbnREYXRhOiB7IHN0ZXBOYW1lLCB3b3JrZmxvd05hbWUsIGlucHV0OiBwYXJhbXMubGF6eVN0ZXBJbnB1dCB9LFxuICAgICAgICAgIH0pXG4gICAgICApO1xuICAgICAgb3B0aW1pc3RpY1N0YXJ0U2V0dGxlZCA9IHN0YXJ0ZWRQcm9taXNlLnRoZW4oXG4gICAgICAgICgpID0+ICh7IG9rOiB0cnVlIGFzIGNvbnN0IH0pLFxuICAgICAgICAoZXJyKSA9PiAoeyBvazogZmFsc2UgYXMgY29uc3QsIGVyciB9KVxuICAgICAgKTtcbiAgICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgICBzdGVwID0ge1xuICAgICAgICBydW5JZDogd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgc3RlcElkLFxuICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgIGlucHV0OiBwYXJhbXMubGF6eVN0ZXBJbnB1dCxcbiAgICAgICAgYXR0ZW1wdDogMSxcbiAgICAgICAgc3RhcnRlZEF0OiBub3csXG4gICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIHN0ZXBfc3RhcnRlZCB2YWxpZGF0ZXMgc3RhdGUgYW5kIHJldHVybnMgdGhlIHN0ZXAgZW50aXR5LiBPbiB0aGUgbGF6eVxuICAgICAgLy8gaW5saW5lIHBhdGggd2UgYWxzbyBjYXJyeSB0aGUgc3RlcCBgaW5wdXRgIHNvIHRoZSB3b3JsZCBjcmVhdGVzIHRoZVxuICAgICAgLy8gc3RlcCBvbiB0aGUgZmx5IChubyBzZXBhcmF0ZSBzdGVwX2NyZWF0ZWQgcm91bmQtdHJpcCkuIFRoZSB3b3JsZCdzXG4gICAgICAvLyBhdG9taWMgY3JlYXRlLWNsYWltIG1ha2VzIHRoaXMgZXhhY3RseS1vbmUtb3duZXI6IGEgY29uY3VycmVudCBsb3NlclxuICAgICAgLy8gZ2V0cyBFbnRpdHlDb25mbGljdEVycm9yLCBtYXBwZWQgdG8gYHsgdHlwZTogJ3NraXBwZWQnIH1gLCBzbyBpdCBuZXZlclxuICAgICAgLy8gcnVucyB0aGUgYm9keS4gV2hlbiBgbGF6eVN0ZXBJbnB1dGAgaXMgYWJzZW50IHRoaXMgaXMgdGhlIGxlZ2FjeVxuICAgICAgLy8gc3RlcF9zdGFydGVkIChzdGVwIGFscmVhZHkgY3JlYXRlZCwgbm8gcGF5bG9hZCkuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzdGFydFJlc3VsdCA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUod29ya2Zsb3dSdW5JZCwge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfc3RhcnRlZCcsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICBldmVudERhdGE6XG4gICAgICAgICAgICBwYXJhbXMubGF6eVN0ZXBJbnB1dCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgID8geyBzdGVwTmFtZSwgd29ya2Zsb3dOYW1lLCBpbnB1dDogcGFyYW1zLmxhenlTdGVwSW5wdXQgfVxuICAgICAgICAgICAgICA6IHsgc3RlcE5hbWUgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKCFzdGFydFJlc3VsdC5zdGVwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgICAgICAgYHN0ZXBfc3RhcnRlZCBldmVudCBmb3IgXCIke3N0ZXBJZH1cIiBkaWQgbm90IHJldHVybiBzdGVwIGVudGl0eWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHN0ZXAgPSBzdGFydFJlc3VsdC5zdGVwO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnN0IG1hcHBlZCA9IHN0YXJ0RXJyb3JUb1Jlc3VsdChlcnIpO1xuICAgICAgICBpZiAobWFwcGVkKSByZXR1cm4gbWFwcGVkO1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnU3RlcCBleGVjdXRpb24gZGV0YWlscycsIHtcbiAgICAgIHN0ZXBOYW1lLFxuICAgICAgc3RlcElkOiBzdGVwLnN0ZXBJZCxcbiAgICAgIHN0YXR1czogc3RlcC5zdGF0dXMsXG4gICAgICBhdHRlbXB0OiBzdGVwLmF0dGVtcHQsXG4gICAgfSk7XG5cbiAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKHN0ZXAuc3RhdHVzKSxcbiAgICB9KTtcblxuICAgIGxldCByZXN1bHQ6IHVua25vd247XG5cbiAgICAvLyBDaGVjayBtYXggcmV0cmllcyBBRlRFUiBzdGVwX3N0YXJ0ZWQgKGF0dGVtcHQgd2FzIGp1c3QgaW5jcmVtZW50ZWQpLlxuICAgIC8vIE9ubHkgZW5mb3JjZSB3aGVuIHRoZSBzdGVwIGhhcyBhIHByZXZpb3VzIGVycm9yIOKAlCB0aGlzIGRpc3Rpbmd1aXNoZXNcbiAgICAvLyBhY3R1YWwgcmV0cmllcyAoZmFpbGVkIOKGkiByZXRyeSkgZnJvbSBjb25jdXJyZW50IHN0YXJ0cyAoVjIgaW5saW5lXG4gICAgLy8gZXhlY3V0aW9uIGxvb3AgY2FuIGNhdXNlIG11bHRpcGxlIGhhbmRsZXJzIHRvIHN0ZXBfc3RhcnRlZCB0aGUgc2FtZVxuICAgIC8vIHN0ZXAgc2ltdWx0YW5lb3VzbHksIGluZmxhdGluZyB0aGUgYXR0ZW1wdCBjb3VudGVyIHdpdGhvdXQgYW55IGZhaWx1cmUpLlxuICAgIGlmIChzdGVwLmF0dGVtcHQgPiBtYXhSZXRyaWVzICsgMSAmJiBzdGVwLmVycm9yKSB7XG4gICAgICBjb25zdCByZXRyeUNvdW50ID0gc3RlcC5hdHRlbXB0IC0gMTtcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGBTdGVwIFwiJHtzdGVwTmFtZX1cIiBleGNlZWRlZCBtYXggcmV0cmllcyAoJHtyZXRyeUNvdW50fSAke3BsdXJhbGl6ZSgncmV0cnknLCAncmV0cmllcycsIHJldHJ5Q291bnQpfSlgO1xuICAgICAgc3RlcExvZ2dlci5lcnJvcignU3RlcCBleGNlZWRlZCBtYXggcmV0cmllcycsIHtcbiAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgIHJldHJ5Q291bnQsXG4gICAgICB9KTtcbiAgICAgIC8vIFByZXNlcnZlIHRoZSBwcmlvciBhdHRlbXB0J3Mgc2VyaWFsaXplZCBlcnJvciBhcyB0aGUgY2F1c2Ugc28gdGhlXG4gICAgICAvLyB1bmRlcmx5aW5nIGZhaWx1cmUgaXMgcmVjb3ZlcmFibGUgZnJvbSBgc3RlcC5lcnJvci5jYXVzZWAgYWZ0ZXJcbiAgICAgIC8vIGh5ZHJhdGlvbiwgd2l0aG91dCBmb3JjaW5nIGNvbnN1bWVycyB0byB3YWxrIHRoZSBzdGVwX3JldHJ5aW5nXG4gICAgICAvLyBldmVudCBoaXN0b3J5LiBCZXN0LWVmZm9ydDogaWYgaHlkcmF0aW9uIG9mIHRoZSBwcmlvciBgc3RlcC5lcnJvcmBcbiAgICAgIC8vIHRocm93cywgZmFsbCBiYWNrIHRvIGEgRmF0YWxFcnJvciB3aXRob3V0IGNhdXNlLlxuICAgICAgY29uc3Qgd3JhcHBlZEVycm9yID0gbmV3IEZhdGFsRXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICAgIGlmIChzdGVwLmVycm9yICE9IG51bGwpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAod3JhcHBlZEVycm9yIGFzIEVycm9yKS5jYXVzZSA9IGF3YWl0IGh5ZHJhdGVTdGVwRXJyb3IoXG4gICAgICAgICAgICBzdGVwLmVycm9yLFxuICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgIGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIElnbm9yZSDigJQgYmVzdC1lZmZvcnQgY2F1c2UgYXR0YWNobWVudC5cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9mYWlsZWQnLFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwSWQsXG4gICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgIGVycm9yOiBhd2FpdCBkZWh5ZHJhdGVTdGVwRXJyb3IoXG4gICAgICAgICAgICAgIHdyYXBwZWRFcnJvcixcbiAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgICAgYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpLFxuICAgICAgICAgICAgICBbXSxcbiAgICAgICAgICAgICAgZ2xvYmFsVGhpcyxcbiAgICAgICAgICAgICAgY29tcHJlc3Npb25cbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICdUcmllZCBmYWlsaW5nIHN0ZXAsIGJ1dCBzdGVwIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXRyeUV4aGF1c3RlZCh0cnVlKSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHsgdHlwZTogJ2ZhaWxlZCcgfTtcbiAgICB9XG5cbiAgICAvLyBPcHMgdGhhdCBtdXN0IGJlIGR1cmFibHkgY29tbWl0dGVkIGJlZm9yZSBzdGVwIGNvbXBsZXRpb24gKGUuZy4gYVxuICAgIC8vIHN0ZXAtaW5pdGlhdGVkIGFib3J0J3MgaG9va19yZWNlaXZlZCBldmVudCkuIFNlZSBTdGVwQ29udGV4dC4gRGVjbGFyZWRcbiAgICAvLyBvdXRzaWRlIHRoZSB0cnkgc28gdGhlIGZhaWx1cmUgcGF0aCBiZWxvdyBjYW4gYWxzbyBkcmFpbiB0aGVtLlxuICAgIGNvbnN0IHByZUNvbXBsZXRpb25PcHM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGF0dGVtcHQgPSBzdGVwLmF0dGVtcHQ7XG5cbiAgICAgIGlmICghc3RlcC5zdGFydGVkQXQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgICAgIGBTdGVwIFwiJHtzdGVwSWR9XCIgaGFzIG5vIFwic3RhcnRlZEF0XCIgdGltZXN0YW1wYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3Qgc3RlcFN0YXJ0ZWRBdCA9IHN0ZXAuc3RhcnRlZEF0O1xuICAgICAgY29uc3Qgb3BzOiBQcm9taXNlPHZvaWQ+W10gPSBbXTtcbiAgICAgIC8vIFVzZSB0aGUgcHJvdmlkZWQgZW5jcnlwdGlvbiBrZXkgd2hlbiBhdmFpbGFibGUsIG90aGVyd2lzZSByZXNvbHZlXG4gICAgICAvLyB0aHJvdWdoIHRoZSBtZW1vaXplZCBhY2Nlc3NvciBkZWNsYXJlZCBhdCB0aGUgdG9wIG9mIHRoaXMgdHJhY2UuXG4gICAgICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gcGFyYW1zLmVuY3J5cHRpb25LZXkgPz8gKGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKSk7XG4gICAgICBjb25zdCBoeWRyYXRlZElucHV0ID0gYXdhaXQgdHJhY2UoXG4gICAgICAgICdzdGVwLmh5ZHJhdGUnLFxuICAgICAgICB7fSxcbiAgICAgICAgYXN5bmMgKGh5ZHJhdGVTcGFuKSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBjb25zdCBoeWRyYXRlZCA9IGF3YWl0IGh5ZHJhdGVTdGVwQXJndW1lbnRzKFxuICAgICAgICAgICAgc3RlcC5pbnB1dCxcbiAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgICAgb3BzLFxuICAgICAgICAgICAgZ2xvYmFsVGhpcyxcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgcGFyYW1zLndvcmtmbG93RGVwbG95bWVudElkXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBkdXJhdGlvbk1zID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICAgICAgICBoeWRyYXRlU3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcEFyZ3VtZW50c0NvdW50KGh5ZHJhdGVkLmFyZ3MubGVuZ3RoKSxcbiAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5RdWV1ZURlc2VyaWFsaXplVGltZU1zKGR1cmF0aW9uTXMpLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiBoeWRyYXRlZDtcbiAgICAgICAgfVxuICAgICAgKTtcblxuICAgICAgY29uc3QgYXJncyA9IGh5ZHJhdGVkSW5wdXQuYXJncztcbiAgICAgIGNvbnN0IHRoaXNWYWwgPSBoeWRyYXRlZElucHV0LnRoaXNWYWwgPz8gbnVsbDtcbiAgICAgIGNvbnN0IHBvcnQgPSBpc1ZlcmNlbCA/IHVuZGVmaW5lZCA6IGF3YWl0IGdldFBvcnRMYXp5KCk7XG5cbiAgICAgIGNvbnN0IGV4ZWN1dGlvblN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICByZXN1bHQgPSBhd2FpdCB0cmFjZSgnc3RlcC5leGVjdXRlJywge30sIGFzeW5jICgpID0+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGNvbnRleHRTdG9yYWdlLnJ1bihcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzdGVwTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgc3RlcFN0YXJ0ZWRBdDogbmV3IERhdGUoK3N0ZXBTdGFydGVkQXQpLFxuICAgICAgICAgICAgICBhdHRlbXB0LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHdvcmtmbG93TWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdDogbmV3IERhdGUoK3dvcmtmbG93U3RhcnRlZEF0KSxcbiAgICAgICAgICAgICAgdXJsOiBpc1ZlcmNlbFxuICAgICAgICAgICAgICAgID8gYGh0dHBzOi8vJHtwcm9jZXNzLmVudi5WRVJDRUxfVVJMfWBcbiAgICAgICAgICAgICAgICA6IGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydCA/PyAzMDAwfWAsXG4gICAgICAgICAgICAgIGZlYXR1cmVzOiB7IGVuY3J5cHRpb246ICEhZW5jcnlwdGlvbktleSB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHdvcmtmbG93RGVwbG95bWVudElkOiBwYXJhbXMud29ya2Zsb3dEZXBsb3ltZW50SWQsXG4gICAgICAgICAgICBvcHMsXG4gICAgICAgICAgICBwcmVDb21wbGV0aW9uT3BzLFxuICAgICAgICAgICAgY2xvc3VyZVZhcnM6IGh5ZHJhdGVkSW5wdXQuY2xvc3VyZVZhcnMsXG4gICAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgKCkgPT4gc3RlcEZuLmFwcGx5KHRoaXNWYWwsIGFyZ3MpXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGV4ZWN1dGlvblRpbWVNcyA9IERhdGUubm93KCkgLSBleGVjdXRpb25TdGFydFRpbWU7XG5cbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuUXVldWVFeGVjdXRpb25UaW1lTXMoZXhlY3V0aW9uVGltZU1zKSxcbiAgICAgIH0pO1xuXG4gICAgICByZXN1bHQgPSBhd2FpdCB0cmFjZSgnc3RlcC5kZWh5ZHJhdGUnLCB7fSwgYXN5bmMgKGRlaHlkcmF0ZVNwYW4pID0+IHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgZGVoeWRyYXRlZCA9IGF3YWl0IGRlaHlkcmF0ZVN0ZXBSZXR1cm5WYWx1ZShcbiAgICAgICAgICByZXN1bHQsXG4gICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgIG9wcyxcbiAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgIGNvbXByZXNzaW9uXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgICBkZWh5ZHJhdGVTcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuUXVldWVTZXJpYWxpemVUaW1lTXMoZHVyYXRpb25NcyksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXN1bHRUeXBlKHR5cGVvZiBkZWh5ZHJhdGVkKSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBkZWh5ZHJhdGVkO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIEZsdXNoIHBlbmRpbmcgb3BzIChzdHJlYW0gd3JpdGVzLCBldGMuKSB3aXRoIGEgc2hvcnQgaW5saW5lIHdhaXQuXG4gICAgICAvLyBOb3cgdGhhdCBXb3JrZmxvd1NlcnZlcldyaXRhYmxlU3RyZWFtIGZsdXNoZXMgc3luY2hyb25vdXNseSBvblxuICAgICAgLy8gZWFjaCB3cml0ZSAobm90IHZpYSBzZXRUaW1lb3V0KSwgdGhlIGZsdXNoYWJsZVBpcGUncyBwZW5kaW5nT3BzXG4gICAgICAvLyBhY2N1cmF0ZWx5IHJlZmxlY3RzIHdoZXRoZXIgZGF0YSBoYXMgcmVhY2hlZCB0aGUgc2VydmVyLiBNb3N0IG9wc1xuICAgICAgLy8gc2V0dGxlIHdpdGhpbiB+MjAwbXMgKDEwMG1zIGxvY2stcmVsZWFzZSBwb2xsaW5nICsgSFRUUCBmbHVzaCkuXG4gICAgICAvLyBJZiBvcHMgZG9uJ3Qgc2V0dGxlIGluIDUwMG1zIChlLmcuLCBXcml0YWJsZVN0cmVhbSBrZXB0IG9wZW5cbiAgICAgIC8vIGFjcm9zcyBzdGVwcyksIHdhaXRVbnRpbCBoYW5kbGVzIHRoZSByZXN0LlxuICAgICAgbGV0IG9wc1NldHRsZWQgPSB0cnVlO1xuICAgICAgaWYgKG9wcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IG9wc1Byb21pc2UgPSBQcm9taXNlLmFsbChvcHMpO1xuICAgICAgICAvLyBUaGUgcmFjZSBiZWxvdyBzdXJmYWNlcyBmYWlsdXJlcyBpbmxpbmUgd2hlbiBvcHMgc2V0dGxlIHF1aWNrbHk7XG4gICAgICAgIC8vIGlmIHRoZSA1MDBtcyB0aW1lb3V0IHdpbnMsIHRoZSBmYWlsdXJlIGlzIG9ubHkgb2JzZXJ2ZWQgaGVyZS4gVGhlXG4gICAgICAgIC8vIHByb21pc2UgaGFuZGVkIHRvIHdhaXRVbnRpbCBtdXN0IG5ldmVyIHJlamVjdCAoYW4gdW5jb25zdW1lZFxuICAgICAgICAvLyB3YWl0VW50aWwgcmVqZWN0aW9uIGNyYXNoZXMgdGhlIHByb2Nlc3MgYXMgdW5oYW5kbGVkUmVqZWN0aW9uKSxcbiAgICAgICAgLy8gc28gdW5leHBlY3RlZCBmYWlsdXJlcyBhcmUgbG9nZ2VkIGluc3RlYWQuXG4gICAgICAgIHNhZmVXYWl0VW50aWwob3BzUHJvbWlzZSwgKGVycikgPT4ge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybignQmFja2dyb3VuZCBmbHVzaCBvZiBzdGVwIHN0cmVhbSBvcHMgZmFpbGVkJywge1xuICAgICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBvcHNTZXR0bGVkID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICBvcHNQcm9taXNlLnRoZW4oXG4gICAgICAgICAgICAoKSA9PiB0cnVlIGFzIGNvbnN0LFxuICAgICAgICAgICAgKGVycikgPT4ge1xuICAgICAgICAgICAgICAvLyBJZ25vcmUgZXhwZWN0ZWQgY2xpZW50IGRpc2Nvbm5lY3QgZXJyb3JzIChlLmcuLCBicm93c2VyXG4gICAgICAgICAgICAgIC8vIHJlZnJlc2ggZHVyaW5nIHN0cmVhbWluZylcbiAgICAgICAgICAgICAgY29uc3QgaXNBYm9ydEVycm9yID1cbiAgICAgICAgICAgICAgICBlcnI/Lm5hbWUgPT09ICdBYm9ydEVycm9yJyB8fCBlcnI/Lm5hbWUgPT09ICdSZXNwb25zZUFib3J0ZWQnO1xuICAgICAgICAgICAgICBpZiAoaXNBYm9ydEVycm9yKSByZXR1cm4gdHJ1ZSBhcyBjb25zdDtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICksXG4gICAgICAgICAgbmV3IFByb21pc2U8ZmFsc2U+KChyKSA9PiBzZXRUaW1lb3V0KCgpID0+IHIoZmFsc2UpLCA1MDApKSxcbiAgICAgICAgXSk7XG4gICAgICB9XG5cbiAgICAgIC8vIE9wdGltaXN0aWMgc3RhcnQ6IHRoZSBib2R5IHJhbiBiZWZvcmUgYHN0ZXBfc3RhcnRlZGAgd2FzIGNvbmZpcm1lZC5cbiAgICAgIC8vIFJlY29uY2lsZSBpdCBub3cg4oCUIGlmIHdlIGxvc3QgdGhlIGNyZWF0ZS1jbGFpbSAob3IgdGhlIHJ1biBpc1xuICAgICAgLy8gZ29uZS90aHJvdHRsZWQpIGRpc2NhcmQgdGhpcyByZXN1bHQgYW5kIGRvbid0IHdyaXRlIHN0ZXBfY29tcGxldGVkLlxuICAgICAgLy8gUmVjb25jaWxlIGJlZm9yZSBkcmFpbmluZyBwcmVDb21wbGV0aW9uT3BzOiBhIGRpc2NhcmRlZCByZXN1bHQgbWVhbnNcbiAgICAgIC8vIHRoZSB3aW5uaW5nIGhhbmRsZXIgb3ducyB0aGUgb3V0Y29tZSAoYW5kIHJlLWZpcmVzIGFueSBhYm9ydFxuICAgICAgLy8gaWRlbXBvdGVudGx5KSwgc28gdGhlcmUncyBubyBwb2ludCBwYXlpbmcgdGhlIGFib3J0LWNvbW1pdCBsYXRlbmN5LlxuICAgICAgaWYgKG9wdGltaXN0aWNTdGFydCkge1xuICAgICAgICBjb25zdCByZWNvbmNpbGUgPSBhd2FpdCByZWNvbmNpbGVPcHRpbWlzdGljU3RhcnQoKTtcbiAgICAgICAgaWYgKHJlY29uY2lsZSkgcmV0dXJuIHJlY29uY2lsZTtcbiAgICAgIH1cblxuICAgICAgLy8gQ29tbWl0IG11c3QtYmUtZHVyYWJsZSBvcHMgKGUuZy4gYSBzdGVwLWluaXRpYXRlZCBhYm9ydCdzXG4gICAgICAvLyBob29rX3JlY2VpdmVkIGV2ZW50KSBiZWZvcmUgd3JpdGluZyBzdGVwX2NvbXBsZXRlZCwgc28gYW55IHdvcmtmbG93XG4gICAgICAvLyBjb250aW51YXRpb24gdHJpZ2dlcmVkIGJ5IHRoYXQgZXZlbnQgb2JzZXJ2ZXMgdGhlIGFib3J0IHJhdGhlciB0aGFuXG4gICAgICAvLyByYWNpbmcgaXQuIFRoZXNlIG9wcyBzd2FsbG93IHRoZWlyIG93biBlcnJvcnMsIHNvIGF3YWl0aW5nIG9ubHlcbiAgICAgIC8vIGVuZm9yY2VzIG9yZGVyaW5nICh0aGUgYC5jYXRjaCgpYCBkZWZlbmRzIHRoZSBuby1yZWplY3QgY29udHJhY3Qgb25cbiAgICAgIC8vIFN0ZXBDb250ZXh0LnByZUNvbXBsZXRpb25PcHMpLlxuICAgICAgLy9cbiAgICAgIC8vIFRyYWRlb2ZmOiBjb3JyZWN0bmVzcyByZXF1aXJlcyB0aGUgaG9vayBiZSBkdXJhYmxlIGJlZm9yZSBjb21wbGV0aW9uLFxuICAgICAgLy8gc28g4oCUIHVubGlrZSB0aGUgYmFja2dyb3VuZCBgb3BzYCBmbHVzaCBhYm92ZSDigJQgdGhpcyBjYW5ub3QgYmUgY2FwcGVkXG4gICAgICAvLyB3aXRoIGEgcmVzb2x2ZS1vbi10aW1lb3V0IHJhY2UuIEEgc2xvdyByZXN1bWUgdGhlcmVmb3JlIGFkZHMgaXRzXG4gICAgICAvLyBsYXRlbmN5IHRvIGEgc3RlcCB0aGF0IGFib3J0cyBhIGNvbnRyb2xsZXIsIGFuZCBhIHRydWUgaGFuZyBob2xkc1xuICAgICAgLy8gY29tcGxldGlvbiB1bnRpbCB0aGUgcGxhdGZvcm0vcXVldWUgZXhlY3V0aW9uIHRpbWVvdXQgZmlyZXM7IHRoZSBxdWV1ZVxuICAgICAgLy8gdGhlbiByZWRlbGl2ZXJzIGFuZCB0aGUgc3RlcCByZXRyaWVzLCByZS1maXJpbmcgdGhlIGFib3J0IGlkZW1wb3RlbnRseS5cbiAgICAgIGlmIChwcmVDb21wbGV0aW9uT3BzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwocHJlQ29tcGxldGlvbk9wcykuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgfVxuXG4gICAgICAvLyBDcmVhdGUgc3RlcF9jb21wbGV0ZWQgZXZlbnQuIFdoZW4gdGhlIGNhbGxlciBzdXBwbGllZCBhXG4gICAgICAvLyBzaW5jZUN1cnNvciAoaW5saW5lIHNlcXVlbnRpYWwgZXhlY3V0aW9uKSwgdGhyZWFkIGl0IHRocm91Z2ggc28gYVxuICAgICAgLy8gc3VwcG9ydGluZyBXb3JsZCByZXR1cm5zIHRoZSBldmVudC1sb2cgZGVsdGEgb24gdGhlIHJlc3VsdCxcbiAgICAgIC8vIGxldHRpbmcgdGhlIGlubGluZSBsb29wIHNraXAgdGhlIG5leHQgZXZlbnRzLmxpc3Qgcm91bmQtdHJpcC5cbiAgICAgIGxldCBzdGVwQ29tcGxldGVkNDA5ID0gZmFsc2U7XG4gICAgICBjb25zdCBjb21wbGV0ZWRSZXN1bHQgPSBhd2FpdCB3b3JsZC5ldmVudHNcbiAgICAgICAgLmNyZWF0ZShcbiAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfY29tcGxldGVkJyxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICByZXN1bHQ6IHJlc3VsdCBhcyBVaW50OEFycmF5LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBhcmFtcy5pbmxpbmVEZWx0YVNpbmNlQ3Vyc29yICE9PSB1bmRlZmluZWRcbiAgICAgICAgICAgID8geyBzaW5jZUN1cnNvcjogcGFyYW1zLmlubGluZURlbHRhU2luY2VDdXJzb3IgfVxuICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgKVxuICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgJ1RyaWVkIGNvbXBsZXRpbmcgc3RlcCwgYnV0IHN0ZXAgaGFzIGFscmVhZHkgZmluaXNoZWQuJyxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgc3RlcElkLFxuICAgICAgICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgc3RlcENvbXBsZXRlZDQwOSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH0pO1xuXG4gICAgICBpZiAoc3RlcENvbXBsZXRlZDQwOSkge1xuICAgICAgICByZXR1cm4geyB0eXBlOiAnc2tpcHBlZCcgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaW5saW5lRGVsdGEgPSBjb21wbGV0ZWRSZXN1bHRcbiAgICAgICAgPyBleHRyYWN0SW5saW5lRGVsdGEoXG4gICAgICAgICAgICBjb21wbGV0ZWRSZXN1bHQsXG4gICAgICAgICAgICBwYXJhbXMuaW5saW5lRGVsdGFTaW5jZUN1cnNvciAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgKVxuICAgICAgICA6IHVuZGVmaW5lZDtcblxuICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdjb21wbGV0ZWQnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBSZXN1bHRUeXBlKHR5cGVvZiByZXN1bHQpLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChvcHMubGVuZ3RoID4gMCkge1xuICAgICAgICBzdGVwTG9nZ2VyLmRlYnVnKCdTdGVwIGhhcyBwZW5kaW5nIG9wcycsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgIG9wc0NvdW50OiBvcHMubGVuZ3RoLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIC8vIGhhc1BlbmRpbmdPcHMgc2lnbmFscyB0aGUgVjIgaGFuZGxlciB0byBicmVhayB0aGUgbG9vcFxuICAgICAgLy8gYW5kIHF1ZXVlIGEgY29udGludWF0aW9uIHNvIHdhaXRVbnRpbCBjYW4gZmx1c2ggdGhlbS5cbiAgICAgIHJldHVybiB7IHR5cGU6ICdjb21wbGV0ZWQnLCBoYXNQZW5kaW5nT3BzOiAhb3BzU2V0dGxlZCwgaW5saW5lRGVsdGEgfTtcbiAgICB9IGNhdGNoIChlcnI6IHVua25vd24pIHtcbiAgICAgIC8vIE9wdGltaXN0aWMgc3RhcnQ6IHRoZSBib2R5IHRocmV3IGJlZm9yZSBgc3RlcF9zdGFydGVkYCB3YXMgY29uZmlybWVkLlxuICAgICAgLy8gUmVjb25jaWxlIGZpcnN0IOKAlCBpZiB3ZSBsb3N0IHRoZSBjcmVhdGUtY2xhaW0gKG9yIHRoZSBydW4gaXNcbiAgICAgIC8vIGdvbmUvdGhyb3R0bGVkKSB0aGUgYm9keSBlcnJvciBpcyBtb290OyBkaXNjYXJkIGl0IGFuZCBkb24ndCB3cml0ZSBhXG4gICAgICAvLyB0ZXJtaW5hbCBldmVudCAodGhlIHdpbm5pbmcgaGFuZGxlciBvd25zIHRoZSBvdXRjb21lKS4gUmVjb25jaWxlXG4gICAgICAvLyBiZWZvcmUgZHJhaW5pbmcgcHJlQ29tcGxldGlvbk9wcyBmb3IgdGhlIHNhbWUgcmVhc29uIGFzIHRoZSBzdWNjZXNzXG4gICAgICAvLyBwYXRoOiBhIGRpc2NhcmRlZCBvdXRjb21lIGRvZXNuJ3QgbmVlZCB0aGUgYWJvcnQgY29tbWl0dGVkIGhlcmUuXG4gICAgICBpZiAob3B0aW1pc3RpY1N0YXJ0KSB7XG4gICAgICAgIGNvbnN0IHJlY29uY2lsZSA9IGF3YWl0IHJlY29uY2lsZU9wdGltaXN0aWNTdGFydCgpO1xuICAgICAgICBpZiAocmVjb25jaWxlKSByZXR1cm4gcmVjb25jaWxlO1xuICAgICAgfVxuXG4gICAgICAvLyBPcmRlciBhbnkgbXVzdC1iZS1kdXJhYmxlIG9wcyAoZS5nLiBhIHN0ZXAtaW5pdGlhdGVkIGFib3J0J3NcbiAgICAgIC8vIGhvb2tfcmVjZWl2ZWQgZXZlbnQpIGFoZWFkIG9mIHN0ZXBfZmFpbGVkIHRvbyDigJQgYSBzdGVwIHRoYXQgYWJvcnRzIGFuZFxuICAgICAgLy8gdGhlbiB0aHJvd3MgbXVzdCBzdGlsbCBoYXZlIHRoZSBhYm9ydCByZWNvcmRlZCBiZWZvcmUgdGhlIGZhaWx1cmVcbiAgICAgIC8vIGNvbnRpbnVhdGlvbiBvYnNlcnZlcyBpdC4gU2FtZSBsYXRlbmN5IHRyYWRlb2ZmIGFuZCBuby1yZWplY3QgY29udHJhY3RcbiAgICAgIC8vIGFzIHRoZSBzdWNjZXNzIHBhdGggYWJvdmUuIFNlZSBTdGVwQ29udGV4dC5wcmVDb21wbGV0aW9uT3BzLlxuICAgICAgaWYgKHByZUNvbXBsZXRpb25PcHMubGVuZ3RoID4gMCkge1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcmVDb21wbGV0aW9uT3BzKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGVmZmVjdGl2ZUVyciA9IHByb21vdGVBYm9ydEVycm9yVG9GYXRhbChlcnIpO1xuXG4gICAgICBjb25zdCBub3JtYWxpemVkRXJyb3IgPSBhd2FpdCBub3JtYWxpemVVbmtub3duRXJyb3IoZWZmZWN0aXZlRXJyKTtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRTdGFjayA9XG4gICAgICAgIG5vcm1hbGl6ZWRFcnJvci5zdGFjayB8fCBnZXRFcnJvclN0YWNrKGVmZmVjdGl2ZUVycikgfHwgJyc7XG5cbiAgICAgIGlmIChlZmZlY3RpdmVFcnIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICBzcGFuPy5yZWNvcmRFeGNlcHRpb24/LihlZmZlY3RpdmVFcnIpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpc0ZhdGFsID0gRmF0YWxFcnJvci5pcyhlZmZlY3RpdmVFcnIpO1xuXG4gICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgLi4uQXR0cmlidXRlLlN0ZXBFcnJvck5hbWUoZ2V0RXJyb3JOYW1lKGVmZmVjdGl2ZUVycikpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcEVycm9yTWVzc2FnZShub3JtYWxpemVkRXJyb3IubWVzc2FnZSksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvclR5cGUoZ2V0RXJyb3JOYW1lKGVmZmVjdGl2ZUVycikpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuRXJyb3JDYXRlZ29yeShcbiAgICAgICAgICBpc0ZhdGFsXG4gICAgICAgICAgICA/ICdmYXRhbCdcbiAgICAgICAgICAgIDogUmV0cnlhYmxlRXJyb3IuaXMoZWZmZWN0aXZlRXJyKVxuICAgICAgICAgICAgICA/ICdyZXRyeWFibGUnXG4gICAgICAgICAgICAgIDogJ3RyYW5zaWVudCdcbiAgICAgICAgKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLkVycm9yUmV0cnlhYmxlKCFpc0ZhdGFsKSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgc3RlcExvZ2dlci5pbmZvKCdXb3JrZmxvdyBydW4gYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nIHN0ZXAnLCB7XG4gICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4geyB0eXBlOiAnZ29uZScgfTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzRmF0YWwpIHtcbiAgICAgICAgc3RlcExvZ2dlci5lcnJvcihcbiAgICAgICAgICAnRW5jb3VudGVyZWQgRmF0YWxFcnJvciB3aGlsZSBleGVjdXRpbmcgc3RlcCwgYnViYmxpbmcgdXAgdG8gcGFyZW50IHdvcmtmbG93JyxcbiAgICAgICAgICB7IHdvcmtmbG93UnVuSWQsIHN0ZXBOYW1lLCBlcnJvclN0YWNrOiBub3JtYWxpemVkU3RhY2sgfVxuICAgICAgICApO1xuICAgICAgICAvLyBBcHBseSB0aGUgbm9ybWFsaXplZCBzdGFjayB0byB0aGUgdGhyb3duIHZhbHVlIHNvIHRoZSBzZXJpYWxpemVkXG4gICAgICAgIC8vIGVycm9yIHByZXNlcnZlcyBpdCBmb3IgY29uc3VtZXJzLiBgdHlwZXMuaXNOYXRpdmVFcnJvcigpYCB3b3Jrc1xuICAgICAgICAvLyBhY3Jvc3MgVk0gcmVhbG1zIChhIHdvcmtmbG93LXRocm93biBlcnJvciBpcyBhbiBpbnN0YW5jZSBvZiB0aGVcbiAgICAgICAgLy8gVk0ncyBFcnJvciBjbGFzcywgbm90IHRoZSBob3N0J3MpLlxuICAgICAgICBpZiAodHlwZXMuaXNOYXRpdmVFcnJvcihlZmZlY3RpdmVFcnIpICYmIG5vcm1hbGl6ZWRTdGFjaykge1xuICAgICAgICAgIChlZmZlY3RpdmVFcnIgYXMgRXJyb3IpLnN0YWNrID0gbm9ybWFsaXplZFN0YWNrO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwSWQsXG4gICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICAgIGVycm9yOiBhd2FpdCBkZWh5ZHJhdGVTdGVwRXJyb3IoXG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlRXJyLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpLFxuICAgICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICAgIGdsb2JhbFRoaXMsXG4gICAgICAgICAgICAgICAgY29tcHJlc3Npb25cbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKHN0ZXBGYWlsRXJyKSB7XG4gICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcEZhaWxFcnIpKSB7XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICdUcmllZCBmYWlsaW5nIHN0ZXAsIGJ1dCBzdGVwIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBzdGVwRmFpbEVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IHN0ZXBGYWlsRXJyO1xuICAgICAgICB9XG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcEZhdGFsRXJyb3IodHJ1ZSksXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4geyB0eXBlOiAnZmFpbGVkJyB9O1xuICAgICAgfVxuXG4gICAgICAvLyBOb24tZmF0YWwgZXJyb3I6IGNoZWNrIGlmIHJldHJpZXMgcmVtYWluaW5nXG4gICAgICBjb25zdCBjdXJyZW50QXR0ZW1wdCA9IHN0ZXAuYXR0ZW1wdDtcblxuICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwQXR0ZW1wdChjdXJyZW50QXR0ZW1wdCksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwTWF4UmV0cmllcyhtYXhSZXRyaWVzKSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoY3VycmVudEF0dGVtcHQgPj0gbWF4UmV0cmllcyArIDEpIHtcbiAgICAgICAgLy8gTWF4IHJldHJpZXMgcmVhY2hlZFxuICAgICAgICBjb25zdCByZXRyeUNvdW50ID0gc3RlcC5hdHRlbXB0IC0gMTtcbiAgICAgICAgc3RlcExvZ2dlci5lcnJvcihcbiAgICAgICAgICAnTWF4IHJldHJpZXMgcmVhY2hlZCwgYnViYmxpbmcgZXJyb3IgdG8gcGFyZW50IHdvcmtmbG93JyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICBhdHRlbXB0OiBzdGVwLmF0dGVtcHQsXG4gICAgICAgICAgICByZXRyeUNvdW50LFxuICAgICAgICAgICAgZXJyb3JTdGFjazogbm9ybWFsaXplZFN0YWNrLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gYFN0ZXAgXCIke3N0ZXBOYW1lfVwiIGZhaWxlZCBhZnRlciAke21heFJldHJpZXN9ICR7cGx1cmFsaXplKCdyZXRyeScsICdyZXRyaWVzJywgbWF4UmV0cmllcyl9OiAke25vcm1hbGl6ZWRFcnJvci5tZXNzYWdlfWA7XG4gICAgICAgIC8vIFdyYXAgdGhlIG9yaWdpbmFsIHRocm93biB2YWx1ZSBhcyBgY2F1c2VgIG9uIGEgZnJlc2ggRmF0YWxFcnJvclxuICAgICAgICAvLyBzbyB0aGUgd3JhcHBpbmcgbWVzc2FnZSArIHJldHJ5LWNvdW50IGZyYW1pbmcgaXMgdGhlIHVzZXItZmFjaW5nXG4gICAgICAgIC8vIGVycm9yIHdoaWxlIHRoZSBvcmlnaW5hbCBmYWlsdXJlIHJlbWFpbnMgcmVjb3ZlcmFibGUgZnJvbVxuICAgICAgICAvLyBgZXJyLmNhdXNlYCBhZnRlciBoeWRyYXRpb24uXG4gICAgICAgIGNvbnN0IHdyYXBwZWRFcnJvciA9IG5ldyBGYXRhbEVycm9yKGVycm9yTWVzc2FnZSk7XG4gICAgICAgICh3cmFwcGVkRXJyb3IgYXMgRXJyb3IpLmNhdXNlID0gZXJyO1xuICAgICAgICBpZiAobm9ybWFsaXplZFN0YWNrKSB3cmFwcGVkRXJyb3Iuc3RhY2sgPSBub3JtYWxpemVkU3RhY2s7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2ZhaWxlZCcsXG4gICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBzdGVwSWQsXG4gICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgICAgIGVycm9yOiBhd2FpdCBkZWh5ZHJhdGVTdGVwRXJyb3IoXG4gICAgICAgICAgICAgICAgd3JhcHBlZEVycm9yLFxuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgICAgICAgYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpLFxuICAgICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICAgIGdsb2JhbFRoaXMsXG4gICAgICAgICAgICAgICAgY29tcHJlc3Npb25cbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKHN0ZXBGYWlsRXJyKSB7XG4gICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcEZhaWxFcnIpKSB7XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICdUcmllZCBmYWlsaW5nIHN0ZXAsIGJ1dCBzdGVwIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICAgIHN0ZXBJZCxcbiAgICAgICAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBzdGVwRmFpbEVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3NraXBwZWQnIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IHN0ZXBGYWlsRXJyO1xuICAgICAgICB9XG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuU3RlcFJldHJ5RXhoYXVzdGVkKHRydWUpLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHsgdHlwZTogJ2ZhaWxlZCcgfTtcbiAgICAgIH1cblxuICAgICAgLy8gUmV0cmllcyByZW1haW5pbmdcbiAgICAgIGlmIChSZXRyeWFibGVFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgIHN0ZXBMb2dnZXIuaW5mbygnRW5jb3VudGVyZWQgUmV0cnlhYmxlRXJyb3IsIHN0ZXAgd2lsbCBiZSByZXRyaWVkJywge1xuICAgICAgICAgIHdvcmtmbG93UnVuSWQsXG4gICAgICAgICAgc3RlcE5hbWUsXG4gICAgICAgICAgYXR0ZW1wdDogY3VycmVudEF0dGVtcHQsXG4gICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RlcExvZ2dlci5pbmZvKCdFbmNvdW50ZXJlZCBFcnJvciwgc3RlcCB3aWxsIGJlIHJldHJpZWQnLCB7XG4gICAgICAgICAgd29ya2Zsb3dSdW5JZCxcbiAgICAgICAgICBzdGVwTmFtZSxcbiAgICAgICAgICBhdHRlbXB0OiBjdXJyZW50QXR0ZW1wdCxcbiAgICAgICAgICBlcnJvclN0YWNrOiBub3JtYWxpemVkU3RhY2ssXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBBcHBseSB0aGUgbm9ybWFsaXplZCBzdGFjayB0byB0aGUgdGhyb3duIHZhbHVlIHNvIGl0IHN1cnZpdmVzXG4gICAgICAvLyBzZXJpYWxpemF0aW9uLiBTZWUgdGhlIEZhdGFsRXJyb3Igc2l0ZSBhYm92ZSBmb3Igd2h5IHdlIHVzZVxuICAgICAgLy8gYHR5cGVzLmlzTmF0aXZlRXJyb3JgIGluc3RlYWQgb2YgYGVyciBpbnN0YW5jZW9mIEVycm9yYC5cbiAgICAgIGlmICh0eXBlcy5pc05hdGl2ZUVycm9yKGVycikgJiYgbm9ybWFsaXplZFN0YWNrKSB7XG4gICAgICAgIChlcnIgYXMgRXJyb3IpLnN0YWNrID0gbm9ybWFsaXplZFN0YWNrO1xuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZSh3b3JrZmxvd1J1bklkLCB7XG4gICAgICAgICAgZXZlbnRUeXBlOiAnc3RlcF9yZXRyeWluZycsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0ZXBJZCxcbiAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVN0ZXBFcnJvcihcbiAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICBhd2FpdCBnZXRFbmNyeXB0aW9uS2V5KCksXG4gICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgICAgICBjb21wcmVzc2lvblxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIC4uLihSZXRyeWFibGVFcnJvci5pcyhlcnIpICYmIHsgcmV0cnlBZnRlcjogZXJyLnJldHJ5QWZ0ZXIgfSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChzdGVwUmV0cnlFcnIpIHtcbiAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoc3RlcFJldHJ5RXJyKSkge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICdUcmllZCByZXRyeWluZyBzdGVwLCBidXQgc3RlcCBoYXMgYWxyZWFkeSBmaW5pc2hlZC4nLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkLFxuICAgICAgICAgICAgICBzdGVwSWQsXG4gICAgICAgICAgICAgIHN0ZXBOYW1lLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBzdGVwUmV0cnlFcnIubWVzc2FnZSxcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiB7IHR5cGU6ICdza2lwcGVkJyB9O1xuICAgICAgICB9XG4gICAgICAgIHRocm93IHN0ZXBSZXRyeUVycjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdGltZW91dFNlY29uZHMgPSBNYXRoLm1heChcbiAgICAgICAgMSxcbiAgICAgICAgUmV0cnlhYmxlRXJyb3IuaXMoZXJyKVxuICAgICAgICAgID8gTWF0aC5jZWlsKCgrZXJyLnJldHJ5QWZ0ZXIuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKSkgLyAxMDAwKVxuICAgICAgICAgIDogMVxuICAgICAgKTtcblxuICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwUmV0cnlUaW1lb3V0U2Vjb25kcyh0aW1lb3V0U2Vjb25kcyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5TdGVwUmV0cnlXaWxsUmV0cnkodHJ1ZSksXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIHsgdHlwZTogJ3JldHJ5JywgdGltZW91dFNlY29uZHMgfTtcbiAgICB9XG4gIH0pO1xufVxuIl19
|