@workflow/core 5.0.0-beta.5 → 5.0.0-beta.51
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/README.md +5 -0
- package/dist/attribute-changes.d.ts +5 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +35 -2
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +74 -5
- package/dist/capture-stack.d.ts +1 -1
- package/dist/capture-stack.js +2 -2
- 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 +19 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +98 -6
- package/dist/context-violation-error.d.ts +5 -5
- package/dist/context-violation-error.d.ts.map +1 -1
- package/dist/context-violation-error.js +8 -6
- package/dist/create-hook.d.ts +72 -7
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +1 -1
- package/dist/define-hook.js +2 -2
- package/dist/describe-error.d.ts +7 -7
- package/dist/describe-error.d.ts.map +1 -1
- package/dist/describe-error.js +97 -12
- package/dist/encryption.d.ts +38 -4
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +96 -14
- package/dist/events-consumer.d.ts +297 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +673 -42
- package/dist/flushable-stream.d.ts +97 -1
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +291 -11
- package/dist/global.d.ts +36 -2
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -6
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/log-format.d.ts +2 -2
- package/dist/log-format.js +19 -12
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +10 -6
- package/dist/private.d.ts +226 -9
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +626 -7
- package/dist/replay-divergence.d.ts +25 -0
- package/dist/replay-divergence.d.ts.map +1 -0
- package/dist/replay-divergence.js +61 -0
- package/dist/replay-payload-cache.d.ts +64 -0
- package/dist/replay-payload-cache.d.ts.map +1 -0
- package/dist/replay-payload-cache.js +158 -0
- package/dist/runtime/compute-instance.d.ts +13 -0
- package/dist/runtime/compute-instance.d.ts.map +1 -0
- package/dist/runtime/compute-instance.js +14 -0
- package/dist/runtime/constants.d.ts +315 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +502 -16
- package/dist/runtime/count-step-started-events.d.ts +52 -0
- package/dist/runtime/count-step-started-events.d.ts.map +1 -0
- package/dist/runtime/count-step-started-events.js +72 -0
- package/dist/runtime/deployment-guard.d.ts +99 -0
- package/dist/runtime/deployment-guard.d.ts.map +1 -0
- package/dist/runtime/deployment-guard.js +154 -0
- package/dist/runtime/get-port-lazy.d.ts +15 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -1
- package/dist/runtime/get-port-lazy.js +75 -6
- package/dist/runtime/get-world-lazy.d.ts +5 -14
- package/dist/runtime/get-world-lazy.d.ts.map +1 -1
- package/dist/runtime/get-world-lazy.js +19 -29
- package/dist/runtime/helpers.d.ts +415 -29
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +686 -57
- package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
- package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
- package/dist/runtime/quickjs-assets.generated.js +30 -0
- package/dist/runtime/quickjs-entrypoint.d.ts +158 -0
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
- package/dist/runtime/quickjs-entrypoint.js +1863 -0
- package/dist/runtime/quickjs-log-view.d.ts +129 -0
- package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
- package/dist/runtime/quickjs-log-view.js +229 -0
- package/dist/runtime/quickjs-runtime.d.ts +244 -0
- package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
- package/dist/runtime/quickjs-runtime.js +2427 -0
- package/dist/runtime/quickjs-serde.d.ts +107 -0
- package/dist/runtime/quickjs-serde.d.ts.map +1 -0
- package/dist/runtime/quickjs-serde.js +2159 -0
- package/dist/runtime/replay-budget.d.ts +97 -0
- package/dist/runtime/replay-budget.d.ts.map +1 -0
- package/dist/runtime/replay-budget.js +139 -0
- package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
- package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
- package/dist/runtime/replay-recovery-reporter.js +64 -0
- package/dist/runtime/resume-hook.d.ts +91 -8
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +512 -89
- package/dist/runtime/resume-latency.d.ts +150 -0
- package/dist/runtime/resume-latency.d.ts.map +1 -0
- package/dist/runtime/resume-latency.js +155 -0
- package/dist/runtime/run-id-time.d.ts +19 -0
- package/dist/runtime/run-id-time.d.ts.map +1 -0
- package/dist/runtime/run-id-time.js +42 -0
- package/dist/runtime/run.d.ts +72 -7
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +280 -53
- package/dist/runtime/runs.d.ts +54 -3
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +126 -16
- package/dist/runtime/start.d.ts +101 -2
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +352 -61
- package/dist/runtime/step-executor.d.ts +186 -5
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +768 -130
- package/dist/runtime/step-latency.d.ts +220 -0
- package/dist/runtime/step-latency.d.ts.map +1 -0
- package/dist/runtime/step-latency.js +215 -0
- package/dist/runtime/step-ownership.d.ts +72 -0
- package/dist/runtime/step-ownership.d.ts.map +1 -0
- package/dist/runtime/step-ownership.js +114 -0
- package/dist/runtime/step-single-flight.d.ts +12 -0
- package/dist/runtime/step-single-flight.d.ts.map +1 -0
- package/dist/runtime/step-single-flight.js +75 -0
- package/dist/runtime/suspension-handler.d.ts +247 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +1304 -125
- package/dist/runtime/unserializable-step.d.ts +34 -0
- package/dist/runtime/unserializable-step.d.ts.map +1 -0
- package/dist/runtime/unserializable-step.js +52 -0
- package/dist/runtime/vm-mode.d.ts +44 -0
- package/dist/runtime/vm-mode.d.ts.map +1 -0
- package/dist/runtime/vm-mode.js +62 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
- package/dist/runtime/vm-serde-bundle.generated.js +16 -0
- package/dist/runtime/wait-continuation.d.ts +106 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +136 -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-compatibility.d.ts +32 -0
- package/dist/runtime/world-compatibility.d.ts.map +1 -0
- package/dist/runtime/world-compatibility.js +44 -0
- package/dist/runtime/world-init.d.ts +17 -42
- package/dist/runtime/world-init.d.ts.map +1 -1
- package/dist/runtime/world-init.js +18 -43
- package/dist/runtime/world.d.ts +14 -2
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +75 -19
- package/dist/runtime.d.ts +10 -6
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +3911 -489
- package/dist/sealed-box.d.ts +167 -0
- package/dist/sealed-box.d.ts.map +1 -0
- package/dist/sealed-box.js +571 -0
- package/dist/serialization/client.d.ts +3 -3
- package/dist/serialization/client.d.ts.map +1 -1
- package/dist/serialization/client.js +8 -4
- package/dist/serialization/codec-devalue-vm.d.ts +16 -0
- package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
- package/dist/serialization/codec-devalue-vm.js +148 -0
- package/dist/serialization/codec-devalue.d.ts +1 -1
- package/dist/serialization/codec-devalue.d.ts.map +1 -1
- package/dist/serialization/codec-devalue.js +24 -6
- package/dist/serialization/codec.d.ts +37 -2
- package/dist/serialization/codec.d.ts.map +1 -1
- package/dist/serialization/codec.js +2 -2
- package/dist/serialization/compression.d.ts +105 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +261 -0
- package/dist/serialization/encryption.d.ts +119 -17
- package/dist/serialization/encryption.d.ts.map +1 -1
- package/dist/serialization/encryption.js +152 -17
- package/dist/serialization/errors.d.ts +13 -0
- package/dist/serialization/errors.d.ts.map +1 -1
- package/dist/serialization/errors.js +20 -2
- package/dist/serialization/format.d.ts +6 -6
- package/dist/serialization/format.js +7 -7
- package/dist/serialization/hardened.d.ts +156 -0
- package/dist/serialization/hardened.d.ts.map +1 -0
- package/dist/serialization/hardened.js +538 -0
- package/dist/serialization/index.d.ts +10 -8
- package/dist/serialization/index.d.ts.map +1 -1
- package/dist/serialization/index.js +10 -8
- package/dist/serialization/reducers/class-vm.d.ts +20 -0
- package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/class-vm.js +77 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -1
- package/dist/serialization/reducers/class.js +11 -6
- package/dist/serialization/reducers/common-vm.d.ts +15 -0
- package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/common-vm.js +616 -0
- package/dist/serialization/reducers/common.d.ts +1 -1
- package/dist/serialization/reducers/common.d.ts.map +1 -1
- package/dist/serialization/reducers/common.js +202 -62
- package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
- package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function-vm.js +97 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -1
- package/dist/serialization/reducers/step-function.js +25 -9
- package/dist/serialization/step.d.ts +4 -4
- package/dist/serialization/step.d.ts.map +1 -1
- package/dist/serialization/step.js +9 -5
- package/dist/serialization/types.d.ts +80 -1
- package/dist/serialization/types.d.ts.map +1 -1
- package/dist/serialization/types.js +15 -1
- package/dist/serialization/workflow-vm.d.ts +29 -0
- package/dist/serialization/workflow-vm.d.ts.map +1 -0
- package/dist/serialization/workflow-vm.js +74 -0
- package/dist/serialization-format.d.ts +64 -8
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +225 -73
- package/dist/serialization.d.ts +262 -34
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1885 -277
- package/dist/set-attributes.d.ts +13 -0
- package/dist/set-attributes.d.ts.map +1 -0
- package/dist/set-attributes.js +60 -0
- package/dist/source-map.d.ts +25 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +154 -10
- package/dist/step/context-storage.d.ts +63 -2
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +7 -5
- package/dist/step/writable-stream.d.ts +3 -3
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +80 -13
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +148 -27
- package/dist/symbols.d.ts +50 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +51 -1
- package/dist/telemetry/semantic-conventions.d.ts +433 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +319 -3
- package/dist/telemetry.d.ts +91 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +244 -17
- package/dist/test-support/orchestrator-context.d.ts +25 -0
- package/dist/test-support/orchestrator-context.d.ts.map +1 -0
- package/dist/test-support/orchestrator-context.js +107 -0
- 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 +0 -5
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -15
- 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 +84 -14
- package/dist/vm/script-cache.d.ts +26 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +131 -0
- package/dist/vm/uint8array-base64.js +1 -1
- package/dist/workflow/abort-controller.d.ts +2 -2
- package/dist/workflow/abort-controller.d.ts.map +1 -1
- package/dist/workflow/abort-controller.js +88 -21
- 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 +45 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +24 -3
- package/dist/workflow/get-workflow-metadata.js +2 -2
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +304 -47
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -1
- package/dist/workflow/set-attributes.d.ts +68 -0
- package/dist/workflow/set-attributes.d.ts.map +1 -0
- package/dist/workflow/set-attributes.js +60 -0
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +58 -12
- package/dist/workflow/world-init-stub.d.ts +3 -3
- package/dist/workflow/world-init-stub.js +4 -4
- package/dist/workflow.d.ts +95 -3
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +900 -561
- package/docs/api-reference/create-hook.mdx +89 -10
- package/docs/api-reference/create-webhook.mdx +16 -15
- package/docs/api-reference/define-hook.mdx +35 -33
- package/docs/api-reference/fatal-error.mdx +30 -8
- package/docs/api-reference/fetch.mdx +14 -10
- package/docs/api-reference/get-step-metadata.mdx +2 -2
- package/docs/api-reference/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/get-writable.mdx +7 -7
- package/docs/api-reference/index.mdx +4 -1
- package/docs/api-reference/retryable-error.mdx +1 -1
- package/docs/api-reference/set-attributes.mdx +61 -0
- package/docs/api-reference/sleep.mdx +4 -4
- package/docs/foundations/cancellation.mdx +31 -32
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +64 -35
- package/docs/foundations/idempotency.mdx +244 -12
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +2 -1
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +106 -30
- package/docs/foundations/streaming.mdx +108 -60
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/how-it-works/cancellation.mdx +63 -63
- package/docs/how-it-works/code-transform.mdx +83 -67
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +125 -34
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/understanding-directives.mdx +22 -22
- package/package.json +24 -15
- package/dist/runtime/step-handler.d.ts +0 -2
- package/dist/runtime/step-handler.d.ts.map +0 -1
- package/dist/runtime/step-handler.js +0 -776
|
@@ -1,135 +1,386 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { EntityConflictError, FatalError, HookNotFoundError, PreconditionFailedError, RunExpiredError, SerializationError, WorkflowWorldError, } from '@workflow/errors';
|
|
2
|
+
import { AttributeValidationError, SPEC_VERSION_CURRENT, SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT, SPEC_VERSION_SUPPORTS_COMPRESSION, SPEC_VERSION_SUPPORTS_SLOT_IDENTITY, } from '@workflow/world';
|
|
3
|
+
import { isRetryableWorldError } from '../classify-error.js';
|
|
4
4
|
import { importKey } from '../encryption.js';
|
|
5
5
|
import { runtimeLogger } from '../logger.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { GUEST_CODE_EXECUTION_SAMPLE_LIMIT, } from '../serialization/hardened.js';
|
|
7
|
+
import { dehydrateStepArguments, dehydrateStepError, } from '../serialization.js';
|
|
8
8
|
import * as Attribute from '../telemetry/semantic-conventions.js';
|
|
9
|
+
import { getAbortStreamIdFromToken } from '../util.js';
|
|
10
|
+
import { COMPUTE_INSTANCE_ID } from './compute-instance.js';
|
|
11
|
+
import { getMaxInlineSteps, isBatchTransitionsEnabled, isResilientStepDispatchEnabled, MAX_BATCH_FANOUT_EVENTS, MAX_RESILIENT_STEP_INPUT_BYTES, } from './constants.js';
|
|
12
|
+
import { absorbSkippedSlotReport, appendEventLog, maxEventSlot, queueMessage, queueMessages, runDispatchContext, slotSnapshotParams, stepDispatchIdempotencyKey, } from './helpers.js';
|
|
13
|
+
import { ReplayRecoveryReporter } from './replay-recovery-reporter.js';
|
|
14
|
+
import { unserializableStepInputPlaceholder } from './unserializable-step.js';
|
|
15
|
+
async function createHookEvent({ runId, hookEvent, queueItem, requestId, sinceCursor, createEvent, }) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await createEvent(hookEvent, {
|
|
18
|
+
requestId,
|
|
19
|
+
...(sinceCursor === undefined ? {} : { sinceCursor }),
|
|
20
|
+
});
|
|
21
|
+
// Check if the world returned a hook_conflict event instead of hook_created.
|
|
22
|
+
// The hook_conflict event is stored in the event log and is what the next
|
|
23
|
+
// pass consumes to settle the hook's awaiters — rejecting a payload await,
|
|
24
|
+
// resolving a `hook.getConflict()` with the conflicting run. An inline
|
|
25
|
+
// delta asked for above carries it just as it would have carried the
|
|
26
|
+
// hook_created, so the caller can advance over it without a re-invocation.
|
|
27
|
+
if (result.event?.eventType === 'hook_conflict') {
|
|
28
|
+
return {
|
|
29
|
+
hasHookConflict: true,
|
|
30
|
+
hasAwaitedHookCreation: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
hasHookConflict: false,
|
|
35
|
+
hasAwaitedHookCreation: queueItem.hasConflictAwaiter === true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (EntityConflictError.is(err)) {
|
|
40
|
+
runtimeLogger.info('Hook already exists, continuing', {
|
|
41
|
+
workflowRunId: runId,
|
|
42
|
+
message: err.message,
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
hasHookConflict: false,
|
|
46
|
+
hasAwaitedHookCreation: queueItem.hasConflictAwaiter === true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (RunExpiredError.is(err)) {
|
|
50
|
+
runtimeLogger.info('Workflow run already completed, skipping hook', {
|
|
51
|
+
workflowRunId: runId,
|
|
52
|
+
message: err.message,
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
hasHookConflict: false,
|
|
56
|
+
hasAwaitedHookCreation: false,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (isWorldValidationFailure(err)) {
|
|
60
|
+
const fatal = new FatalError(`createHook failed World validation: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
+
fatal.cause = err;
|
|
62
|
+
throw fatal;
|
|
63
|
+
}
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
9
67
|
/**
|
|
10
68
|
* Handles a workflow suspension by processing all pending operations (hooks, steps, waits).
|
|
11
|
-
* Creates events for all operations but does NOT queue step messages
|
|
69
|
+
* Creates events for all operations but does NOT queue step messages; returns the pending
|
|
12
70
|
* steps so the caller can decide which to execute inline vs queue to background.
|
|
13
71
|
*
|
|
14
72
|
* Processing order:
|
|
15
73
|
* 1. Hooks are processed first to prevent race conditions with webhook receivers
|
|
16
74
|
* 2. Step events and wait events are created in parallel
|
|
17
75
|
*/
|
|
18
|
-
export async function handleSuspension({ suspension, world, run, span, requestId, }) {
|
|
76
|
+
export async function handleSuspension({ suspension, world, run, span, requestId, eventLog, runReadyBarrier, replayRecoveryReporter, stepDispatch, ownerMessageId, allowDeferredBatchWork, }) {
|
|
19
77
|
const runId = run.runId;
|
|
78
|
+
// Turbo mode: hold every world write below until the backgrounded
|
|
79
|
+
// `run_started` has *settled*, so we never write a step/hook/wait event for a
|
|
80
|
+
// run that does not exist yet. A no-op outside turbo (barrier undefined) and
|
|
81
|
+
// on the pure inline hot path, which defers all steps and writes nothing.
|
|
82
|
+
// Awaiting the same (usually already-settled) promise more than once is cheap.
|
|
83
|
+
// A barrier rejection is swallowed for ordering only: if `run_started` truly
|
|
84
|
+
// failed the run does not exist, so the subsequent write surfaces the real
|
|
85
|
+
// error (run not found / gone) and the message redelivers.
|
|
86
|
+
const ensureRunReady = async () => {
|
|
87
|
+
if (runReadyBarrier) {
|
|
88
|
+
try {
|
|
89
|
+
await runReadyBarrier;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// intentional: ordering barrier only, see above.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Await every operation in a suspension phase before letting a failure
|
|
98
|
+
* escape, preferring a stale-snapshot (412) rejection when one occurred.
|
|
99
|
+
*
|
|
100
|
+
* `Promise.all` rejects as soon as one operation does and leaves its siblings
|
|
101
|
+
* in flight. That matters for a 412: the caller reacts by reloading the event
|
|
102
|
+
* log and restarting the replay, so a sibling create that lands after the
|
|
103
|
+
* rejection escaped commits an event whose correlation id came from the
|
|
104
|
+
* abandoned replay's seeded sequence (an event the fresh replay never
|
|
105
|
+
* produces), and it races the restart's reload while doing so. Settling first
|
|
106
|
+
* makes this phase's write set final before the caller acts on the failure.
|
|
107
|
+
* It mirrors the runtime's inline step claim, which settles the in-flight
|
|
108
|
+
* step executions before escalating a 412.
|
|
109
|
+
*
|
|
110
|
+
* A 412 is preferred over any other rejection in the same phase because it
|
|
111
|
+
* has a defined, cheap recovery (replay from a corrected log) while the
|
|
112
|
+
* others do not. A deterministic failure such as an attribute-validation
|
|
113
|
+
* `FatalError` recurs on the restart and fails the run then, at the cost of
|
|
114
|
+
* one extra replay.
|
|
115
|
+
*/
|
|
116
|
+
const settlePhase = async (ops) => {
|
|
117
|
+
const reasons = (await Promise.allSettled(ops))
|
|
118
|
+
.filter((r) => r.status === 'rejected')
|
|
119
|
+
.map((r) => r.reason);
|
|
120
|
+
if (reasons.length === 0)
|
|
121
|
+
return;
|
|
122
|
+
throw reasons.find((r) => PreconditionFailedError.is(r)) ?? reasons[0];
|
|
123
|
+
};
|
|
124
|
+
// Every suspension write carries replay-recovery telemetry on the first one
|
|
125
|
+
// that commits after replay recovered. All suspension events are
|
|
126
|
+
// non-run_created events on this run's `runId`.
|
|
127
|
+
const reporter = replayRecoveryReporter ?? ReplayRecoveryReporter.inert();
|
|
128
|
+
const createEvent = (data, params) => reporter.withEventCreate(params, (p) => world.events.create(runId, data, p));
|
|
129
|
+
// Adds the optimistic-concurrency guard when the caller supplied a loaded
|
|
130
|
+
// event log; without one it creates directly (callers with no replay
|
|
131
|
+
// snapshot, e.g. tests). A stale (412) rejection propagates to the caller,
|
|
132
|
+
// which restarts the replay from a corrected log. It is not retried here,
|
|
133
|
+
// because the event's correlation id was minted by *this* replay's seeded
|
|
134
|
+
// sequence, so re-committing it against a corrected log would persist an
|
|
135
|
+
// event no correct replay produces.
|
|
136
|
+
let reportedEvents = 0;
|
|
137
|
+
// Writes this suspension issued, and whether one of them handed back a
|
|
138
|
+
// complete inline delta that was folded into the caller's log. Together they
|
|
139
|
+
// answer `eventLogCarriedForward`: the delta covers the log up to the write
|
|
140
|
+
// that returned it, so it accounts for every event this suspension committed
|
|
141
|
+
// only if that write was the only one.
|
|
142
|
+
let guardedWrites = 0;
|
|
143
|
+
let deltaAbsorbed = false;
|
|
144
|
+
const createGuarded = async (data, params) => {
|
|
145
|
+
guardedWrites++;
|
|
146
|
+
if (!eventLog) {
|
|
147
|
+
return createEvent(data, params);
|
|
148
|
+
}
|
|
149
|
+
const log = eventLog;
|
|
150
|
+
const result = await createEvent(data, {
|
|
151
|
+
...params,
|
|
152
|
+
...slotSnapshotParams(log.events),
|
|
153
|
+
});
|
|
154
|
+
// An inline delta this call asked for (`sinceCursor`) is everything the
|
|
155
|
+
// log gained since that cursor, this write included, so it is folded onto
|
|
156
|
+
// the tail and carries the cursor with it — unlike a skipped-slot report,
|
|
157
|
+
// which is a window strictly below the write and has to be sorted back
|
|
158
|
+
// into place. A World returns one or the other, never both (the delta is a
|
|
159
|
+
// strict superset), so the two are handled apart rather than merged.
|
|
160
|
+
//
|
|
161
|
+
// Declining is always safe — an unabsorbed delta is one the next read
|
|
162
|
+
// returns — so the guards match the replay loop's `absorbCreateDelta`: a
|
|
163
|
+
// truncated page (`hasMore`) is dropped whole rather than advancing the
|
|
164
|
+
// cursor past events it did not carry, and the log must still be where the
|
|
165
|
+
// request was computed from, since appending does not re-sort.
|
|
166
|
+
if (typeof params?.sinceCursor === 'string') {
|
|
167
|
+
if (log.cursor === params.sinceCursor &&
|
|
168
|
+
result.events !== undefined &&
|
|
169
|
+
result.hasMore !== true) {
|
|
170
|
+
appendEventLog(log, { events: result.events, cursor: result.cursor });
|
|
171
|
+
deltaAbsorbed = true;
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
// Bump-and-report: the write landed above the slot it asked for, so the
|
|
176
|
+
// report holds the events it was decided without. Absorbing here rather
|
|
177
|
+
// than at each call site means the rest of this phase's writes (which read
|
|
178
|
+
// the same array to build their own snapshot) ask for a slot above them,
|
|
179
|
+
// and the replay that resumes from this log sees them without a reload.
|
|
180
|
+
const report = absorbSkippedSlotReport(log.events, result);
|
|
181
|
+
reportedEvents += report.added;
|
|
182
|
+
if (report.truncated) {
|
|
183
|
+
runtimeLogger.debug('Dropped a truncated skipped-slot report', {
|
|
184
|
+
workflowRunId: runId,
|
|
185
|
+
eventType: data.eventType,
|
|
186
|
+
eventId: result.event?.eventId,
|
|
187
|
+
offered: report.offered,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
else if (report.added > 0) {
|
|
191
|
+
runtimeLogger.debug('Suspension write skipped occupied slots', {
|
|
192
|
+
workflowRunId: runId,
|
|
193
|
+
eventType: data.eventType,
|
|
194
|
+
eventId: result.event?.eventId,
|
|
195
|
+
reported: report.added,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
};
|
|
20
200
|
// Separate queue items by type
|
|
21
|
-
const stepItems = suspension.
|
|
22
|
-
const allHookItems = suspension.
|
|
23
|
-
const waitItems = suspension.
|
|
24
|
-
|
|
201
|
+
const stepItems = suspension.items.filter((item) => item.type === 'step');
|
|
202
|
+
const allHookItems = suspension.items.filter((item) => item.type === 'hook');
|
|
203
|
+
const waitItems = suspension.items.filter((item) => item.type === 'wait');
|
|
204
|
+
const attributeItems = suspension.items.filter((item) => item.type === 'attribute');
|
|
25
205
|
const hooksNeedingCreation = allHookItems.filter((item) => !item.hasCreatedEvent);
|
|
26
|
-
|
|
206
|
+
// Group hook items that need work by token, preserving queue-insertion
|
|
207
|
+
// (workflow code) order within each token. Operations on one token must
|
|
208
|
+
// apply in code order: a dispose() of an earlier hook releases the token
|
|
209
|
+
// before a later same-token hook's creation is validated (otherwise the
|
|
210
|
+
// new hook records a spurious hook_conflict against the run's own
|
|
211
|
+
// disposed hook), while a hook created and disposed within the same
|
|
212
|
+
// suspension is still created before it is disposed. Different tokens
|
|
213
|
+
// have no claim interaction, so token groups are processed in parallel.
|
|
214
|
+
const hookItemsByToken = new Map();
|
|
215
|
+
for (const item of allHookItems) {
|
|
216
|
+
if (item.hasCreatedEvent && !item.disposed) {
|
|
217
|
+
continue; // already committed and still live: nothing to do
|
|
218
|
+
}
|
|
219
|
+
const group = hookItemsByToken.get(item.token);
|
|
220
|
+
if (group) {
|
|
221
|
+
group.push(item);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
hookItemsByToken.set(item.token, [item]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
27
227
|
// Resolve encryption key for this run
|
|
28
228
|
const rawKey = await world.getEncryptionKeyForRun?.(run);
|
|
29
229
|
const encryptionKey = rawKey ? await importKey(rawKey) : undefined;
|
|
30
|
-
//
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
230
|
+
// Gate payload compression on the run's specVersion.
|
|
231
|
+
const compression = (run.specVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION;
|
|
232
|
+
let serializationBlockerCount = 0;
|
|
233
|
+
const serializationBlockers = [];
|
|
234
|
+
async function dehydrateInput(value, context) {
|
|
235
|
+
const stats = { executions: [] };
|
|
236
|
+
try {
|
|
237
|
+
return (await dehydrateStepArguments(value, runId, encryptionKey, suspension.globalThis, false, compression, stats));
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
serializationBlockerCount +=
|
|
241
|
+
stats.totalExecutions ?? stats.executions.length;
|
|
242
|
+
serializationBlockers.push(...stats.executions
|
|
243
|
+
.slice(0, GUEST_CODE_EXECUTION_SAMPLE_LIMIT - serializationBlockers.length)
|
|
244
|
+
.map((execution) => ({ ...context, ...execution })));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function disposeHook(queueItem) {
|
|
248
|
+
const hookDisposedEvent = {
|
|
249
|
+
eventType: 'hook_disposed',
|
|
37
250
|
specVersion: SPEC_VERSION_CURRENT,
|
|
38
251
|
correlationId: queueItem.correlationId,
|
|
39
252
|
eventData: {
|
|
40
253
|
token: queueItem.token,
|
|
41
|
-
metadata: hookMetadata,
|
|
42
|
-
isWebhook: queueItem.isWebhook ?? false,
|
|
43
|
-
...(queueItem.isSystem && { isSystem: true }),
|
|
44
254
|
},
|
|
45
255
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
requestId,
|
|
256
|
+
try {
|
|
257
|
+
await createGuarded(hookDisposedEvent, { requestId });
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
if (EntityConflictError.is(err)) {
|
|
261
|
+
// Hook was already disposed by a concurrent invocation, safe to skip
|
|
262
|
+
runtimeLogger.info('Hook already disposed, skipping duplicate disposal', {
|
|
263
|
+
workflowRunId: runId,
|
|
264
|
+
correlationId: queueItem.correlationId,
|
|
265
|
+
message: err.message,
|
|
57
266
|
});
|
|
58
|
-
// Check if the world returned a hook_conflict event instead of hook_created.
|
|
59
|
-
// The hook_conflict event is stored in the event log and will be replayed
|
|
60
|
-
// on the next workflow invocation, causing the hook's promise to reject.
|
|
61
|
-
// Note: hook events always create an event (legacy runs throw, not return undefined)
|
|
62
|
-
if (result.event.eventType === 'hook_conflict') {
|
|
63
|
-
hasHookConflict = true;
|
|
64
|
-
}
|
|
65
267
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
throw err;
|
|
75
|
-
}
|
|
268
|
+
else if (RunExpiredError.is(err)) {
|
|
269
|
+
runtimeLogger.info('Workflow run already completed, skipping hook disposal', {
|
|
270
|
+
workflowRunId: runId,
|
|
271
|
+
correlationId: queueItem.correlationId,
|
|
272
|
+
message: err.message,
|
|
273
|
+
});
|
|
76
274
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
specVersion: SPEC_VERSION_CURRENT,
|
|
85
|
-
correlationId: queueItem.correlationId,
|
|
86
|
-
};
|
|
87
|
-
try {
|
|
88
|
-
await world.events.create(runId, hookDisposedEvent, { requestId });
|
|
275
|
+
else if (HookNotFoundError.is(err)) {
|
|
276
|
+
// Hook may have already been disposed or never created
|
|
277
|
+
runtimeLogger.info('Hook not found for disposal, continuing', {
|
|
278
|
+
workflowRunId: runId,
|
|
279
|
+
correlationId: queueItem.correlationId,
|
|
280
|
+
message: err.message,
|
|
281
|
+
});
|
|
89
282
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
283
|
+
else {
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Process hooks first to prevent race conditions with webhook receivers.
|
|
289
|
+
// Track any hook conflicts that occur — these are returned to the caller so
|
|
290
|
+
// it can advance the workflow over the committed `hook_conflict` before
|
|
291
|
+
// anything else this suspension scheduled runs.
|
|
292
|
+
const hookConflictCorrelationIds = [];
|
|
293
|
+
const awaitedHookCorrelationIds = [];
|
|
294
|
+
let hookCreationMs = 0;
|
|
295
|
+
// Ask the hook create for the event-log delta since the cursor the caller's
|
|
296
|
+
// log was read at. The hook's awaiters are settled by the event this write
|
|
297
|
+
// commits and by nothing else — a `hook_created` for a clean registration,
|
|
298
|
+
// a `hook_conflict` when the token was already claimed — so the caller can
|
|
299
|
+
// continue the workflow in its own process on either outcome, but only over
|
|
300
|
+
// a log that holds that event, and this write is the one request that can
|
|
301
|
+
// hand it back together with anything another writer landed in the meantime.
|
|
302
|
+
// Optional by contract: a World that ignores `sinceCursor` returns no delta
|
|
303
|
+
// and the caller reads instead.
|
|
304
|
+
//
|
|
305
|
+
// Asked for on the single-hook suspension only. Two creates issued from one
|
|
306
|
+
// snapshot each diff against the same cursor, and only the first delta back
|
|
307
|
+
// can be folded in (the cursor moves with it), so the log would end up short
|
|
308
|
+
// of the other's event with nothing to say so.
|
|
309
|
+
const hookDeltaCursor = hooksNeedingCreation.length === 1 && typeof eventLog?.cursor === 'string'
|
|
310
|
+
? eventLog.cursor
|
|
311
|
+
: undefined;
|
|
312
|
+
if (hookItemsByToken.size > 0) {
|
|
313
|
+
const hookPhaseStart = Date.now();
|
|
314
|
+
await ensureRunReady();
|
|
315
|
+
await settlePhase([...hookItemsByToken.values()].map(async (items) => {
|
|
316
|
+
for (const queueItem of items) {
|
|
317
|
+
let creationConflicted = false;
|
|
318
|
+
if (!queueItem.hasCreatedEvent) {
|
|
319
|
+
const hookMetadata = typeof queueItem.metadata === 'undefined'
|
|
320
|
+
? undefined
|
|
321
|
+
: await dehydrateInput(queueItem.metadata, {
|
|
322
|
+
source: 'hook_metadata',
|
|
323
|
+
correlationId: queueItem.correlationId,
|
|
324
|
+
});
|
|
325
|
+
const hookEvent = {
|
|
326
|
+
eventType: 'hook_created',
|
|
327
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
110
328
|
correlationId: queueItem.correlationId,
|
|
111
|
-
|
|
329
|
+
eventData: {
|
|
330
|
+
token: queueItem.token,
|
|
331
|
+
tokenRetentionUntil: queueItem.tokenRetentionUntil,
|
|
332
|
+
metadata: hookMetadata,
|
|
333
|
+
isWebhook: queueItem.isWebhook ?? false,
|
|
334
|
+
...(queueItem.isSystem && { isSystem: true }),
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
const result = await createHookEvent({
|
|
338
|
+
runId,
|
|
339
|
+
hookEvent,
|
|
340
|
+
queueItem,
|
|
341
|
+
requestId,
|
|
342
|
+
sinceCursor: hookDeltaCursor,
|
|
343
|
+
createEvent: createGuarded,
|
|
112
344
|
});
|
|
345
|
+
if (result.hasHookConflict) {
|
|
346
|
+
hookConflictCorrelationIds.push(queueItem.correlationId);
|
|
347
|
+
}
|
|
348
|
+
if (result.hasAwaitedHookCreation) {
|
|
349
|
+
awaitedHookCorrelationIds.push(queueItem.correlationId);
|
|
350
|
+
}
|
|
351
|
+
creationConflicted = result.hasHookConflict;
|
|
113
352
|
}
|
|
114
|
-
|
|
115
|
-
|
|
353
|
+
// Dispose after creation for hooks born and disposed within this
|
|
354
|
+
// batch. A hook whose creation conflicted was never created, so
|
|
355
|
+
// there is nothing to dispose.
|
|
356
|
+
if (queueItem.disposed && !creationConflicted) {
|
|
357
|
+
await disposeHook(queueItem);
|
|
116
358
|
}
|
|
117
359
|
}
|
|
118
360
|
}));
|
|
361
|
+
hookCreationMs = Date.now() - hookPhaseStart;
|
|
119
362
|
}
|
|
120
|
-
// Process abort requests
|
|
363
|
+
// Process abort requests: resume the hook with abort payload and write stream packet
|
|
121
364
|
const hooksNeedingAbort = allHookItems.filter((item) => item.abortRequested && !item.disposed);
|
|
122
365
|
if (hooksNeedingAbort.length > 0) {
|
|
123
|
-
await
|
|
366
|
+
await ensureRunReady();
|
|
367
|
+
await settlePhase(hooksNeedingAbort.map(async (queueItem) => {
|
|
124
368
|
try {
|
|
125
369
|
// Dehydrate the abort payload for storage
|
|
126
|
-
const abortPayload = await
|
|
370
|
+
const abortPayload = await dehydrateInput({
|
|
371
|
+
aborted: true,
|
|
372
|
+
reason: queueItem.abortReason,
|
|
373
|
+
}, {
|
|
374
|
+
source: 'hook_abort',
|
|
375
|
+
correlationId: queueItem.correlationId,
|
|
376
|
+
});
|
|
127
377
|
// Create hook_received event with abort payload
|
|
128
|
-
await
|
|
378
|
+
await createGuarded({
|
|
129
379
|
eventType: 'hook_received',
|
|
130
380
|
specVersion: SPEC_VERSION_CURRENT,
|
|
131
381
|
correlationId: queueItem.correlationId,
|
|
132
382
|
eventData: {
|
|
383
|
+
token: queueItem.token,
|
|
133
384
|
payload: abortPayload,
|
|
134
385
|
},
|
|
135
386
|
});
|
|
@@ -146,7 +397,7 @@ export async function handleSuspension({ suspension, world, run, span, requestId
|
|
|
146
397
|
await world.streams.close(runId, streamName);
|
|
147
398
|
}
|
|
148
399
|
catch {
|
|
149
|
-
// Best-effort stream write
|
|
400
|
+
// Best-effort stream write: hook event provides the durable fallback
|
|
150
401
|
runtimeLogger.debug('Failed to write abort stream packet, hook event will provide fallback', {
|
|
151
402
|
workflowRunId: runId,
|
|
152
403
|
correlationId: queueItem.correlationId,
|
|
@@ -168,7 +419,7 @@ export async function handleSuspension({ suspension, world, run, span, requestId
|
|
|
168
419
|
}));
|
|
169
420
|
}
|
|
170
421
|
// Create step events for steps that don't have them yet.
|
|
171
|
-
// Unlike V1, we do NOT queue step messages from here
|
|
422
|
+
// Unlike V1, we do NOT queue step messages from here: the caller
|
|
172
423
|
// decides which steps to execute inline vs. queue to background.
|
|
173
424
|
// Wait events are also created in parallel below.
|
|
174
425
|
const stepsNeedingCreation = new Set(stepItems
|
|
@@ -176,30 +427,422 @@ export async function handleSuspension({ suspension, world, run, span, requestId
|
|
|
176
427
|
.map((queueItem) => queueItem.correlationId));
|
|
177
428
|
// Correlation IDs for which THIS suspension call actually wrote the
|
|
178
429
|
// step_created event. Populated by the ops below after a successful
|
|
179
|
-
// events.create
|
|
430
|
+
// events.create, used by the caller to claim ownership and avoid
|
|
180
431
|
// racing with concurrent handlers on step execution.
|
|
181
432
|
const createdStepCorrelationIds = new Set();
|
|
433
|
+
// Correlation IDs of steps finalized as failed because their arguments
|
|
434
|
+
// refused to serialize: see finalizeUnserializableStep below.
|
|
435
|
+
const failedStepCorrelationIds = new Set();
|
|
436
|
+
/**
|
|
437
|
+
* A step whose arguments fail to serialize is deterministic: every replay
|
|
438
|
+
* re-derives the same unserializable value, so redelivering the
|
|
439
|
+
* orchestrator message can never succeed. Instead of rejecting the whole
|
|
440
|
+
* suspension (which fails the run from the outside, where no user code can
|
|
441
|
+
* observe it), treat it exactly like a step-body failure: write
|
|
442
|
+
* `step_created` with a placeholder input (every World requires the step
|
|
443
|
+
* entity to exist before a terminal step event, and the real input is
|
|
444
|
+
* precisely what refused to serialize) followed by `step_failed` carrying
|
|
445
|
+
* the SerializationError. The next replay rejects the step's promise with
|
|
446
|
+
* it, so a try/catch around the step call observes the error; uncaught, it
|
|
447
|
+
* propagates out of the workflow body and fails the run as a USER_ERROR,
|
|
448
|
+
* without burning queue redeliveries either way.
|
|
449
|
+
*/
|
|
450
|
+
const finalizeUnserializableStep = async (queueItem, error) => {
|
|
451
|
+
runtimeLogger.warn('Step arguments failed to serialize; failing the step so the ' +
|
|
452
|
+
'workflow can observe the error', {
|
|
453
|
+
workflowRunId: runId,
|
|
454
|
+
correlationId: queueItem.correlationId,
|
|
455
|
+
stepName: queueItem.stepName,
|
|
456
|
+
error: error.message,
|
|
457
|
+
});
|
|
458
|
+
await ensureRunReady();
|
|
459
|
+
// Marker placeholder (not empty args): byte-identical-to-zero-args would
|
|
460
|
+
// make `workflow inspect steps` show "no arguments" for the one step
|
|
461
|
+
// whose entire problem was its arguments.
|
|
462
|
+
const placeholderInput = (await dehydrateStepArguments(unserializableStepInputPlaceholder(), runId, encryptionKey, suspension.globalThis, false, compression));
|
|
463
|
+
try {
|
|
464
|
+
await createGuarded({
|
|
465
|
+
eventType: 'step_created',
|
|
466
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
467
|
+
correlationId: queueItem.correlationId,
|
|
468
|
+
eventData: {
|
|
469
|
+
stepName: queueItem.stepName,
|
|
470
|
+
workflowName: run.workflowName,
|
|
471
|
+
input: placeholderInput,
|
|
472
|
+
},
|
|
473
|
+
}, { requestId });
|
|
474
|
+
}
|
|
475
|
+
catch (createErr) {
|
|
476
|
+
if (EntityConflictError.is(createErr)) {
|
|
477
|
+
// A concurrent handler already created the step: the failure is
|
|
478
|
+
// deterministic, so it is racing toward the same step_failed below.
|
|
479
|
+
runtimeLogger.info('Step already exists, continuing', {
|
|
480
|
+
workflowRunId: runId,
|
|
481
|
+
correlationId: queueItem.correlationId,
|
|
482
|
+
message: createErr.message,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else if (RunExpiredError.is(createErr)) {
|
|
486
|
+
// Run already finished: nothing to observe the failure.
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
throw createErr;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
await createGuarded({
|
|
495
|
+
eventType: 'step_failed',
|
|
496
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
497
|
+
correlationId: queueItem.correlationId,
|
|
498
|
+
eventData: {
|
|
499
|
+
stepName: queueItem.stepName,
|
|
500
|
+
// The error itself is a plain WorkflowError (name, message with
|
|
501
|
+
// framed hint, cause chain), serializable even though the step
|
|
502
|
+
// input was not. Error detection is realm-independent
|
|
503
|
+
// (types.isNativeError), so the host-created error serializes
|
|
504
|
+
// the same under either global; the VM global is passed for
|
|
505
|
+
// consistency with every other dehydration in this file and so
|
|
506
|
+
// any VM-realm values guest code threw into the cause chain
|
|
507
|
+
// (getters/proxies executed during the failed dehydration) are
|
|
508
|
+
// detected by the realm-sensitive reducers.
|
|
509
|
+
error: await dehydrateStepError(error, runId, encryptionKey, [], suspension.globalThis, compression),
|
|
510
|
+
},
|
|
511
|
+
}, { requestId });
|
|
512
|
+
}
|
|
513
|
+
catch (failErr) {
|
|
514
|
+
if (EntityConflictError.is(failErr) || RunExpiredError.is(failErr)) {
|
|
515
|
+
// Step already terminal (a concurrent handler wrote the same
|
|
516
|
+
// deterministic failure) or the run already finished.
|
|
517
|
+
runtimeLogger.info('Tried failing step, but step or run has already finished.', {
|
|
518
|
+
workflowRunId: runId,
|
|
519
|
+
correlationId: queueItem.correlationId,
|
|
520
|
+
message: failErr.message,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
throw failErr;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
failedStepCorrelationIds.add(queueItem.correlationId);
|
|
528
|
+
// Release the inline slot bookkeeping: the step never runs, so it must
|
|
529
|
+
// not appear in the rebuilt `lazyInlineSteps`. (Its slot in the first-N
|
|
530
|
+
// selection and in `inlinePairFoldEligible`'s count was consumed
|
|
531
|
+
// before dehydration could reveal the failure, inherent to selecting
|
|
532
|
+
// before serializing, and bounded to one wasted slot on a pass that
|
|
533
|
+
// ends in a forced replay anyway.)
|
|
534
|
+
lazyInlineCorrelationIds.delete(queueItem.correlationId);
|
|
535
|
+
};
|
|
536
|
+
// Lazy inline start: defer the step_created write for up to
|
|
537
|
+
// `getMaxInlineSteps()` steps the caller will run inline (in parallel). Each
|
|
538
|
+
// step is created on the fly by the lazy `step_started` executeStep sends
|
|
539
|
+
// (saving a round-trip per step). We never defer when a `hook.getConflict()`
|
|
540
|
+
// awaiter is present, because in that case the caller executes nothing inline
|
|
541
|
+
// (it continues the workflow to resolve the awaiter instead), so deferring
|
|
542
|
+
// would leave the steps uncreated and unqueued. We pick the first N uncreated
|
|
543
|
+
// steps — matching the caller's inline-candidate selection — and dehydrate
|
|
544
|
+
// their input here so executeStep can ship it as the step_started payload.
|
|
545
|
+
const lazyInlineCorrelationIds = new Set(awaitedHookCorrelationIds.length === 0
|
|
546
|
+
? stepItems
|
|
547
|
+
.filter((item) => stepsNeedingCreation.has(item.correlationId))
|
|
548
|
+
.slice(0, getMaxInlineSteps())
|
|
549
|
+
.map((item) => item.correlationId)
|
|
550
|
+
: []);
|
|
551
|
+
// Collected by correlationId because the per-step ops below run concurrently
|
|
552
|
+
// and settle out of order. We rebuild the array in deterministic
|
|
553
|
+
// `lazyInlineCorrelationIds` order (the ordered slice above) after the ops
|
|
554
|
+
// settle, so the inline batch order is stable regardless of dehydration timing.
|
|
555
|
+
const lazyInlineByCorrelationId = new Map();
|
|
182
556
|
const ops = [];
|
|
183
|
-
//
|
|
557
|
+
// Correlation IDs of steps whose step-execution queue message was already
|
|
558
|
+
// published by the resilient-dispatch ops below (alongside the step_created
|
|
559
|
+
// write). Reported to the caller so its dispatch pass skips them.
|
|
560
|
+
const queuedStepCorrelationIds = new Set();
|
|
561
|
+
// Resilient step dispatch eligibility, shared by every step op below (the
|
|
562
|
+
// per-step input-size check is applied inside the op). All must hold:
|
|
563
|
+
//
|
|
564
|
+
// - The caller provided a dispatch target (`stepDispatch`): terminal
|
|
565
|
+
// drains and other create-only callers never queue.
|
|
566
|
+
// - The feature is enabled (`WORKFLOW_RESILIENT_STEP_DISPATCH` opt-in).
|
|
567
|
+
// It is off by default because the publish races the create's verdict,
|
|
568
|
+
// and a create can come back refused: as a duplicate the replay should
|
|
569
|
+
// stop pursuing, or (on a World that would rather refuse a stale write
|
|
570
|
+
// than report what it missed) as a 412. Either way the queue message
|
|
571
|
+
// carrying the payload is already out, and the consumer can materialize a
|
|
572
|
+
// step whose create was refused. Nothing orders that verdict before the
|
|
573
|
+
// consumer's redelivery re-ensure, so no backend-side revocation
|
|
574
|
+
// bookkeeping can close the window: a best-effort marker that fails open
|
|
575
|
+
// cannot carry a correctness property. The sequential path is the only
|
|
576
|
+
// thing that gives the message a happens-after edge over the verdict.
|
|
577
|
+
// - The run's queue transport preserves binary payloads (CBOR,
|
|
578
|
+
// specVersion >= 3): `stepInput.input` is the serialized (possibly
|
|
579
|
+
// encrypted) input bytes, which the JSON transport would mangle.
|
|
580
|
+
const resilientDispatchEligible = stepDispatch !== undefined &&
|
|
581
|
+
isResilientStepDispatchEnabled() &&
|
|
582
|
+
(run.specVersion ?? 0) >= SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT;
|
|
583
|
+
// Batched fan-out: fold this suspension's step_created + wait_created
|
|
584
|
+
// writes into one `events.createBatch` call (one durable write, per-event
|
|
585
|
+
// outcomes) instead of one write per event. Engages only for a CLEAN
|
|
586
|
+
// fan-out (no attribute writes, no hook writes, no resilient dispatch
|
|
587
|
+
// whose creates are each paired with a queue publish) on a World that
|
|
588
|
+
// implements the optional method and a run whose events are slot-numbered.
|
|
589
|
+
// Everything outside the gate keeps the single-event path byte-for-byte.
|
|
590
|
+
const batchFanoutEligible = isBatchTransitionsEnabled() &&
|
|
591
|
+
typeof world.events.createBatch === 'function' &&
|
|
592
|
+
(run.specVersion ?? 0) >= SPEC_VERSION_SUPPORTS_SLOT_IDENTITY &&
|
|
593
|
+
!resilientDispatchEligible &&
|
|
594
|
+
allHookItems.length === 0 &&
|
|
595
|
+
attributeItems.length === 0;
|
|
596
|
+
/**
|
|
597
|
+
* The fold's collection, in scheduling order (steps in stepItems order,
|
|
598
|
+
* then waits). Step entries are enqueued by their prep promises (input
|
|
599
|
+
* dehydration runs concurrently, so entries are ordered by `order`, not by
|
|
600
|
+
* completion); the single flush op below awaits every prep, sorts, and
|
|
601
|
+
* commits the whole set through `createBatch`.
|
|
602
|
+
*/
|
|
603
|
+
const batchQueue = [];
|
|
604
|
+
const batchPreps = [];
|
|
605
|
+
// Pre-claimed inline pairs: fold each lazy-inline step's deferred
|
|
606
|
+
// `step_created` (carrying its input) AND its `step_started` claim (bare,
|
|
607
|
+
// ownership-stamped) into the batch, so the inline steps' claims commit in
|
|
608
|
+
// one durable write (the pair chunk, see the flush below) and the caller
|
|
609
|
+
// starts the bodies straight off that commit instead of posting one claim
|
|
610
|
+
// per inline step. Requires TWO or more inline steps, and nothing else:
|
|
611
|
+
// the pairs commit in a chunk of their own, so plain creates alongside
|
|
612
|
+
// them share no round trip with the pairs and cannot make a lone pair
|
|
613
|
+
// worth folding. A lone inline step is better served by the lazy
|
|
614
|
+
// `step_started`: one row instead of two, optimistic-start capable (the
|
|
615
|
+
// claim overlaps the body), with the slot-snapshot params and
|
|
616
|
+
// bump-and-report `createGuarded` provides, all of which a pair-only
|
|
617
|
+
// batch of one pair gives up for the same round trip. Two or more inline
|
|
618
|
+
// steps become ONE pair chunk instead of N parallel lazy claims, which is
|
|
619
|
+
// the saving. A lone inline step alongside eager creates therefore takes
|
|
620
|
+
// the lazy path while the creates still batch. Also requires the caller's
|
|
621
|
+
// `ownerMessageId`: the started row must stamp ownership exactly like the
|
|
622
|
+
// lazy claim it replaces (and a caller that does not inline-execute never
|
|
623
|
+
// provides one).
|
|
624
|
+
const inlinePairFoldEligible = batchFanoutEligible &&
|
|
625
|
+
ownerMessageId !== undefined &&
|
|
626
|
+
lazyInlineCorrelationIds.size >= 2;
|
|
627
|
+
const inlineClaims = new Map();
|
|
628
|
+
// The trace carrier for resilient step dispatches, resolved at most once per
|
|
629
|
+
// suspension (the per-step ops run concurrently and share it).
|
|
630
|
+
let stepDispatchTraceCarrier;
|
|
631
|
+
const getStepDispatchTraceCarrier = () => {
|
|
632
|
+
stepDispatchTraceCarrier ??=
|
|
633
|
+
stepDispatch?.getTraceCarrier() ?? Promise.resolve({});
|
|
634
|
+
return stepDispatchTraceCarrier;
|
|
635
|
+
};
|
|
636
|
+
// Producer-side resilient recovery count for the suspension span attribute.
|
|
637
|
+
let resilientDispatchRecovered = 0;
|
|
638
|
+
// Steps: create step_created events (no queuing, V2 returns pending steps
|
|
639
|
+
// to caller, EXCEPT on the resilient dispatch path, which parallelizes the
|
|
640
|
+
// create with the step's queue publish and reports it in
|
|
641
|
+
// `queuedStepCorrelationIds`).
|
|
642
|
+
let batchOrderCounter = 0;
|
|
184
643
|
for (const queueItem of stepItems) {
|
|
185
644
|
if (stepsNeedingCreation.has(queueItem.correlationId)) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
645
|
+
// Deterministic position in the batched fold (assigned in stepItems
|
|
646
|
+
// order, before the concurrent dehydration runs). A pair-folded inline
|
|
647
|
+
// step occupies two consecutive positions (created row then started
|
|
648
|
+
// row), which the flush keeps adjacent, never splits across chunks,
|
|
649
|
+
// and commits in a pair-only chunk ahead of the plain creates, so a
|
|
650
|
+
// World can fold them into one born-running create.
|
|
651
|
+
const pairFolded = inlinePairFoldEligible &&
|
|
652
|
+
lazyInlineCorrelationIds.has(queueItem.correlationId);
|
|
653
|
+
const stepOrder = batchOrderCounter;
|
|
654
|
+
batchOrderCounter += pairFolded ? 2 : 1;
|
|
655
|
+
const stepOp = (async () => {
|
|
656
|
+
let dehydratedInput;
|
|
657
|
+
try {
|
|
658
|
+
dehydratedInput = await dehydrateInput({
|
|
659
|
+
args: queueItem.args,
|
|
660
|
+
closureVars: queueItem.closureVars,
|
|
661
|
+
thisVal: queueItem.thisVal,
|
|
662
|
+
}, {
|
|
663
|
+
source: 'step_input',
|
|
664
|
+
correlationId: queueItem.correlationId,
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
catch (err) {
|
|
668
|
+
if (!SerializationError.is(err)) {
|
|
669
|
+
// e.g. RuntimeDecryptionError: an SDK fault, not a user value
|
|
670
|
+
// problem. Keep its identity (RUNTIME_ERROR) and current
|
|
671
|
+
// fail-the-suspension behavior.
|
|
672
|
+
throw err;
|
|
673
|
+
}
|
|
674
|
+
if (!stepDispatch) {
|
|
675
|
+
// No dispatch target means no replay will observe a
|
|
676
|
+
// finalization: this is the terminal drain (or a create-only
|
|
677
|
+
// test caller). The run is already completing/failing, so
|
|
678
|
+
// writing step_created + step_failed here would leave e.g. a
|
|
679
|
+
// COMPLETED run carrying a failed step nothing can ever
|
|
680
|
+
// observe, reading as a bug from the dashboard. Rethrow
|
|
681
|
+
// instead; the drain's own catch swallows it, preserving its
|
|
682
|
+
// pre-existing behavior (no rows for the unawaited step).
|
|
683
|
+
throw err;
|
|
684
|
+
}
|
|
685
|
+
await finalizeUnserializableStep(queueItem, err);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
// Deferred (lazy) inline step: skip the step_created write — the
|
|
689
|
+
// caller's inline executeStep will send a lazy step_started carrying
|
|
690
|
+
// this input, and the world creates the step (entity + synthetic
|
|
691
|
+
// step_created event) atomically. We do NOT add it to
|
|
692
|
+
// createdStepCorrelationIds; ownership is decided by that lazy
|
|
693
|
+
// step_started's atomic create-claim instead.
|
|
694
|
+
if (lazyInlineCorrelationIds.has(queueItem.correlationId)) {
|
|
695
|
+
lazyInlineByCorrelationId.set(queueItem.correlationId, {
|
|
696
|
+
correlationId: queueItem.correlationId,
|
|
697
|
+
stepName: queueItem.stepName,
|
|
698
|
+
dehydratedInput,
|
|
699
|
+
});
|
|
700
|
+
if (pairFolded) {
|
|
701
|
+
// Enqueue the pair the deferral would otherwise leave to the
|
|
702
|
+
// caller's lazy `step_started`: the created row carries the
|
|
703
|
+
// input (payloads ride creates in a batch), the started row is
|
|
704
|
+
// bare and stamps this invocation's ownership, the same claim
|
|
705
|
+
// shape the lazy start would have sent, settled by the batch.
|
|
706
|
+
batchQueue.push({
|
|
707
|
+
order: stepOrder,
|
|
708
|
+
kind: 'inline-created',
|
|
709
|
+
correlationId: queueItem.correlationId,
|
|
710
|
+
event: {
|
|
711
|
+
eventType: 'step_created',
|
|
712
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
713
|
+
correlationId: queueItem.correlationId,
|
|
714
|
+
eventData: {
|
|
715
|
+
stepName: queueItem.stepName,
|
|
716
|
+
workflowName: run.workflowName,
|
|
717
|
+
input: dehydratedInput,
|
|
718
|
+
},
|
|
719
|
+
},
|
|
720
|
+
});
|
|
721
|
+
batchQueue.push({
|
|
722
|
+
order: stepOrder + 1,
|
|
723
|
+
kind: 'inline-started',
|
|
724
|
+
correlationId: queueItem.correlationId,
|
|
725
|
+
event: {
|
|
726
|
+
eventType: 'step_started',
|
|
727
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
728
|
+
correlationId: queueItem.correlationId,
|
|
729
|
+
eventData: {
|
|
730
|
+
stepName: queueItem.stepName,
|
|
731
|
+
// Checked by inlinePairFoldEligible; spread keeps the
|
|
732
|
+
// narrow-through-closure problem away from the type.
|
|
733
|
+
...(ownerMessageId !== undefined ? { ownerMessageId } : {}),
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
192
740
|
const stepEvent = {
|
|
193
741
|
eventType: 'step_created',
|
|
194
742
|
specVersion: SPEC_VERSION_CURRENT,
|
|
195
743
|
correlationId: queueItem.correlationId,
|
|
196
744
|
eventData: {
|
|
197
745
|
stepName: queueItem.stepName,
|
|
746
|
+
workflowName: run.workflowName,
|
|
198
747
|
input: dehydratedInput,
|
|
199
748
|
},
|
|
200
749
|
};
|
|
750
|
+
// Resilient step dispatch: fire the step_created write and the
|
|
751
|
+
// step-execution queue publish in parallel: the message carries the
|
|
752
|
+
// same serialized input (`stepInput`) so the consumer can
|
|
753
|
+
// idempotently re-ensure the event if the direct write failed
|
|
754
|
+
// transiently. Mirrors the resilient start (`runInput`) and
|
|
755
|
+
// resilient hook resume (`hookInput`) patterns. Only for inputs the
|
|
756
|
+
// queue message can safely carry (binary, under the VQS size cap).
|
|
757
|
+
if (resilientDispatchEligible &&
|
|
758
|
+
dehydratedInput instanceof Uint8Array &&
|
|
759
|
+
dehydratedInput.byteLength <= MAX_RESILIENT_STEP_INPUT_BYTES) {
|
|
760
|
+
await ensureRunReady();
|
|
761
|
+
const traceCarrier = await getStepDispatchTraceCarrier();
|
|
762
|
+
const [createResult, queueResult] = await Promise.allSettled([
|
|
763
|
+
createGuarded(stepEvent, { requestId }),
|
|
764
|
+
queueMessage(world,
|
|
765
|
+
// biome-ignore lint/style/noNonNullAssertion: implied by resilientDispatchEligible
|
|
766
|
+
stepDispatch.queueName, {
|
|
767
|
+
runId,
|
|
768
|
+
stepId: queueItem.correlationId,
|
|
769
|
+
stepName: queueItem.stepName,
|
|
770
|
+
traceCarrier,
|
|
771
|
+
requestedAt: new Date(),
|
|
772
|
+
stepInput: { input: dehydratedInput },
|
|
773
|
+
runContext: runDispatchContext(run),
|
|
774
|
+
},
|
|
775
|
+
// Same key as the caller's dispatch pass and any concurrent
|
|
776
|
+
// handler's, so redundant publishes for this step dedupe. The
|
|
777
|
+
// key is step-identity-scoped so a revoked message for a
|
|
778
|
+
// reassigned correlation id cannot absorb the corrected
|
|
779
|
+
// schedule's dispatch: see stepDispatchIdempotencyKey.
|
|
780
|
+
{
|
|
781
|
+
idempotencyKey: stepDispatchIdempotencyKey(queueItem.correlationId, queueItem.stepName),
|
|
782
|
+
}),
|
|
783
|
+
]);
|
|
784
|
+
// Queue failure is always fatal for this suspension pass: without
|
|
785
|
+
// the message the step would rely on the create alone, and if the
|
|
786
|
+
// create ALSO failed there would be no durable record at all.
|
|
787
|
+
// Propagating redelivers the orchestrator message, which
|
|
788
|
+
// re-creates the (idempotent) step_created and re-dispatches,
|
|
789
|
+
// the same recovery as the sequential path.
|
|
790
|
+
if (queueResult.status === 'rejected') {
|
|
791
|
+
throw queueResult.reason;
|
|
792
|
+
}
|
|
793
|
+
queuedStepCorrelationIds.add(queueItem.correlationId);
|
|
794
|
+
if (createResult.status === 'rejected') {
|
|
795
|
+
const err = createResult.reason;
|
|
796
|
+
if (EntityConflictError.is(err)) {
|
|
797
|
+
// Concurrent handler wrote it first, same as the sequential
|
|
798
|
+
// path. The step message is already out; a duplicate publish
|
|
799
|
+
// by that handler dedupes on the shared idempotency key.
|
|
800
|
+
runtimeLogger.info('Step already exists, continuing', {
|
|
801
|
+
workflowRunId: runId,
|
|
802
|
+
correlationId: queueItem.correlationId,
|
|
803
|
+
message: err.message,
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
else if (isRetryableWorldError(err)) {
|
|
807
|
+
// Resilient: the write failed transiently (429 / 5xx /
|
|
808
|
+
// transport) but the step message (carrying the same
|
|
809
|
+
// serialized input) was published, so the consumer
|
|
810
|
+
// idempotently re-ensures the step_created before executing.
|
|
811
|
+
resilientDispatchRecovered++;
|
|
812
|
+
runtimeLogger.warn('Step creation event write failed, but the step was ' +
|
|
813
|
+
'dispatched via the queue. The step_created event will ' +
|
|
814
|
+
'be ensured by the queue consumer.', {
|
|
815
|
+
workflowRunId: runId,
|
|
816
|
+
correlationId: queueItem.correlationId,
|
|
817
|
+
stepName: queueItem.stepName,
|
|
818
|
+
error: err instanceof Error ? err.message : String(err),
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
throw err;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
createdStepCorrelationIds.add(queueItem.correlationId);
|
|
827
|
+
}
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
if (batchFanoutEligible) {
|
|
831
|
+
// Fold into the batch instead of writing here. The enclosing
|
|
832
|
+
// promise joins `batchPreps` (see the loop below), so the flush
|
|
833
|
+
// op cannot run before this step's input finished dehydrating.
|
|
834
|
+
batchQueue.push({
|
|
835
|
+
order: stepOrder,
|
|
836
|
+
kind: 'step',
|
|
837
|
+
correlationId: queueItem.correlationId,
|
|
838
|
+
stepName: queueItem.stepName,
|
|
839
|
+
event: stepEvent,
|
|
840
|
+
});
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
201
843
|
try {
|
|
202
|
-
await
|
|
844
|
+
await ensureRunReady();
|
|
845
|
+
await createGuarded(stepEvent, { requestId });
|
|
203
846
|
createdStepCorrelationIds.add(queueItem.correlationId);
|
|
204
847
|
}
|
|
205
848
|
catch (err) {
|
|
@@ -214,23 +857,44 @@ export async function handleSuspension({ suspension, world, run, span, requestId
|
|
|
214
857
|
throw err;
|
|
215
858
|
}
|
|
216
859
|
}
|
|
217
|
-
})()
|
|
860
|
+
})();
|
|
861
|
+
ops.push(stepOp);
|
|
862
|
+
if (batchFanoutEligible) {
|
|
863
|
+
// The flush op waits for every prep before committing; a prep that
|
|
864
|
+
// rejected already surfaces through `ops`, so the flush's own wait
|
|
865
|
+
// swallows it and commits whatever was successfully enqueued,
|
|
866
|
+
// preserving today's per-op independence.
|
|
867
|
+
batchPreps.push(stepOp.catch(() => { }));
|
|
868
|
+
}
|
|
218
869
|
}
|
|
219
870
|
}
|
|
220
871
|
// Create wait events (same as V1)
|
|
221
872
|
for (const queueItem of waitItems) {
|
|
222
873
|
if (!queueItem.hasCreatedEvent) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
874
|
+
const waitEvent = {
|
|
875
|
+
eventType: 'wait_created',
|
|
876
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
877
|
+
correlationId: queueItem.correlationId,
|
|
878
|
+
eventData: {
|
|
879
|
+
resumeAt: queueItem.resumeAt,
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
if (batchFanoutEligible) {
|
|
883
|
+
// Waits need no dehydration, so they enqueue synchronously, after
|
|
884
|
+
// every step's order slot, preserving steps-then-waits scheduling
|
|
885
|
+
// order in the log.
|
|
886
|
+
batchQueue.push({
|
|
887
|
+
order: batchOrderCounter++,
|
|
888
|
+
kind: 'wait',
|
|
227
889
|
correlationId: queueItem.correlationId,
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
890
|
+
event: waitEvent,
|
|
891
|
+
});
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
ops.push((async () => {
|
|
232
895
|
try {
|
|
233
|
-
await
|
|
896
|
+
await ensureRunReady();
|
|
897
|
+
await createGuarded(waitEvent, { requestId });
|
|
234
898
|
}
|
|
235
899
|
catch (err) {
|
|
236
900
|
if (EntityConflictError.is(err)) {
|
|
@@ -247,33 +911,548 @@ export async function handleSuspension({ suspension, world, run, span, requestId
|
|
|
247
911
|
})());
|
|
248
912
|
}
|
|
249
913
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
//
|
|
914
|
+
// The batched fold's flush: the clean fan-out commits through
|
|
915
|
+
// `createBatch` in chunks of MAX_BATCH_FANOUT_EVENTS, all chunks IN
|
|
916
|
+
// FLIGHT CONCURRENTLY. Slot assignment is the server's, so parallel
|
|
917
|
+
// chunks race for slot ranges exactly like the pre-fold path's parallel
|
|
918
|
+
// single writes did; entity conditions, not commit order, carry
|
|
919
|
+
// correctness (sibling fan-out events have no cross-order the replay
|
|
920
|
+
// depends on; it matches by correlation id). Each event reports the
|
|
921
|
+
// outcome its own single create would have had: a 409 is the same
|
|
922
|
+
// already-exists tolerance as the single path, anything else fails the
|
|
923
|
+
// delivery the way a single-path rejection would.
|
|
924
|
+
//
|
|
925
|
+
// Latency shape: only the chunk carrying the pre-claimed inline pairs
|
|
926
|
+
// gates the handler's return (the caller starts bodies off its claims),
|
|
927
|
+
// and that chunk carries NOTHING else, so its commit is as small as the
|
|
928
|
+
// inline slice (see the chunking below).
|
|
929
|
+
// Every other chunk's commit (and every chunk's step-message publishes,
|
|
930
|
+
// which fire the moment ITS creates are durable) rides
|
|
931
|
+
// `deferredBatchWork` when the caller opted in, joined before ack. A slow
|
|
932
|
+
// sibling chunk therefore delays neither the inline bodies nor another
|
|
933
|
+
// chunk's queue messages, while publish-after-create still holds per
|
|
934
|
+
// step: a step's message is only ever sent after the chunk carrying its
|
|
935
|
+
// create has committed.
|
|
936
|
+
let deferredBatchWork;
|
|
937
|
+
if (batchFanoutEligible) {
|
|
938
|
+
ops.push((async () => {
|
|
939
|
+
// Preps that rejected already surface through their own `ops`
|
|
940
|
+
// entries; the fold commits whatever was successfully enqueued,
|
|
941
|
+
// preserving today's per-op independence.
|
|
942
|
+
await Promise.all(batchPreps);
|
|
943
|
+
if (batchQueue.length === 0) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
const entries = [...batchQueue].sort((a, b) => a.order - b.order);
|
|
947
|
+
await ensureRunReady();
|
|
948
|
+
// The ordinary single path for a lone plain entry: a batch of ONE
|
|
949
|
+
// gains nothing over the single write (same round trip) and loses
|
|
950
|
+
// the slot-snapshot params + bump-and-report that createGuarded
|
|
951
|
+
// provides, so a lone eager event is written the way it would have
|
|
952
|
+
// been without the fold, with the same conflict tolerance and
|
|
953
|
+
// ownership bookkeeping. Used when the whole fold is one entry
|
|
954
|
+
// (below) and when the plain partition beside the pairs is one
|
|
955
|
+
// entry (the chunking further down). Beside a pair chunk it commits
|
|
956
|
+
// concurrently with the handler's return, like a trailing chunk; the
|
|
957
|
+
// inline bodies do not depend on it (executor writes carry no slot
|
|
958
|
+
// snapshot, so there is no position for it to move).
|
|
959
|
+
const commitSingle = async (entry) => {
|
|
960
|
+
try {
|
|
961
|
+
await createGuarded(entry.event, { requestId });
|
|
962
|
+
if (entry.kind === 'step') {
|
|
963
|
+
createdStepCorrelationIds.add(entry.correlationId);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
catch (err) {
|
|
967
|
+
if (EntityConflictError.is(err)) {
|
|
968
|
+
runtimeLogger.info(entry.kind === 'step'
|
|
969
|
+
? 'Step already exists, continuing'
|
|
970
|
+
: 'Wait already exists, continuing', {
|
|
971
|
+
workflowRunId: runId,
|
|
972
|
+
correlationId: entry.correlationId,
|
|
973
|
+
message: err.message,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
throw err;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
if (entries.length === 1) {
|
|
982
|
+
await commitSingle(entries[0]);
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
// Seed for the foreign-interleaving diagnostic below. With chunks
|
|
986
|
+
// committing in parallel there is no per-chunk "expected next slot";
|
|
987
|
+
// the whole fold's committed span is compared against the seed
|
|
988
|
+
// once every chunk has settled: committed slots are dense per the
|
|
989
|
+
// World's invariant, so any excess of (max committed slot − seed +
|
|
990
|
+
// 1) over the fold's own committed count is events OTHER writers
|
|
991
|
+
// landed in between.
|
|
992
|
+
const expectedFirstSlot = eventLog
|
|
993
|
+
? (maxEventSlot(eventLog.events) ?? 0) + 1
|
|
994
|
+
: undefined;
|
|
995
|
+
// Pair-aware chunking. Two rules:
|
|
996
|
+
//
|
|
997
|
+
// 1. A pre-claimed pair's two rows must land in the same createBatch
|
|
998
|
+
// call (adjacent, so a World can fold them into one born-running
|
|
999
|
+
// create) and never straddle a chunk boundary, which would turn
|
|
1000
|
+
// the started row into a standalone claim racing its own
|
|
1001
|
+
// create's commit.
|
|
1002
|
+
// 2. The pairs commit in chunk(s) of THEIR OWN, ahead of the plain
|
|
1003
|
+
// `step`/`wait` creates, which fill the subsequent chunks. The
|
|
1004
|
+
// pair chunk is the one commit the inline bodies wait for (see
|
|
1005
|
+
// `pairCommits` below), and on the Vercel backend its latency
|
|
1006
|
+
// scales with the transaction's item count: measured on 32-branch
|
|
1007
|
+
// fan-outs, batches of <=8 events commit in ~56 ms p50 server-side
|
|
1008
|
+
// where batches of 24-32 events take ~110 ms. Padding the pair
|
|
1009
|
+
// chunk with plain creates up to the cap therefore held the
|
|
1010
|
+
// bodies for the plain creates' commit, which nothing else
|
|
1011
|
+
// needed: a plain create gates only its own queue publish, and
|
|
1012
|
+
// that fires off whichever sibling chunk carries it. Splitting
|
|
1013
|
+
// them keeps the pair chunk small (two rows per inline step) and
|
|
1014
|
+
// lets the plain creates commit concurrently beside it.
|
|
1015
|
+
const chunkEntries = (list) => {
|
|
1016
|
+
const out = [];
|
|
1017
|
+
let current = [];
|
|
1018
|
+
for (let index = 0; index < list.length; index++) {
|
|
1019
|
+
const entry = list[index];
|
|
1020
|
+
const next = list[index + 1];
|
|
1021
|
+
const pairLead = entry.kind === 'inline-created' &&
|
|
1022
|
+
next?.kind === 'inline-started' &&
|
|
1023
|
+
next.correlationId === entry.correlationId;
|
|
1024
|
+
const take = pairLead ? 2 : 1;
|
|
1025
|
+
if (current.length > 0 &&
|
|
1026
|
+
current.length + take > MAX_BATCH_FANOUT_EVENTS) {
|
|
1027
|
+
out.push(current);
|
|
1028
|
+
current = [];
|
|
1029
|
+
}
|
|
1030
|
+
current.push(entry);
|
|
1031
|
+
if (pairLead) {
|
|
1032
|
+
current.push(next);
|
|
1033
|
+
index++;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (current.length > 0)
|
|
1037
|
+
out.push(current);
|
|
1038
|
+
return out;
|
|
1039
|
+
};
|
|
1040
|
+
// Both partitions keep `entries`' order, so a pair's two rows
|
|
1041
|
+
// (consecutive `order` values, enqueued together) stay adjacent in
|
|
1042
|
+
// the pair partition.
|
|
1043
|
+
const isPairRow = (entry) => entry.kind === 'inline-created' || entry.kind === 'inline-started';
|
|
1044
|
+
const pairChunks = chunkEntries(entries.filter((entry) => isPairRow(entry)));
|
|
1045
|
+
const plainEntries = entries.filter((entry) => !isPairRow(entry));
|
|
1046
|
+
// A plain partition of exactly ONE entry is the batch-of-one case
|
|
1047
|
+
// again, now that the pairs no longer share its chunk: it takes the
|
|
1048
|
+
// single path (`commitSingle`) rather than a one-row createBatch,
|
|
1049
|
+
// and is carried as a one-entry chunk so the per-chunk publish and
|
|
1050
|
+
// settle machinery below treats it like any sibling. (A one-row
|
|
1051
|
+
// remainder of a LARGER plain partition still batches: it is the
|
|
1052
|
+
// pre-split behavior, unchanged here.)
|
|
1053
|
+
const plainChunks = plainEntries.length === 1
|
|
1054
|
+
? [plainEntries]
|
|
1055
|
+
: chunkEntries(plainEntries);
|
|
1056
|
+
const singleChunk = plainEntries.length === 1 ? plainChunks[0] : undefined;
|
|
1057
|
+
const chunks = [...pairChunks, ...plainChunks];
|
|
1058
|
+
// Steps whose queue messages THIS FLUSH will publish (the eager
|
|
1059
|
+
// creates), recorded before any chunk settles so the caller's
|
|
1060
|
+
// dispatch pass (which runs off the handler's return) skips them.
|
|
1061
|
+
// The sends are guaranteed-or-failed by the trailing work the
|
|
1062
|
+
// caller joins before acking, so "will be published by this flush"
|
|
1063
|
+
// and "already published" are equivalent from the caller's side.
|
|
1064
|
+
const publishEagerSteps = stepDispatch !== undefined;
|
|
1065
|
+
if (publishEagerSteps) {
|
|
1066
|
+
for (const entry of entries) {
|
|
1067
|
+
if (entry.kind === 'step') {
|
|
1068
|
+
queuedStepCorrelationIds.add(entry.correlationId);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
// Tallies for the foreign-interleaving diagnostic, folded across
|
|
1073
|
+
// the concurrent chunks and read once all of them settled.
|
|
1074
|
+
let committedCount = 0;
|
|
1075
|
+
let maxCommittedSlot;
|
|
1076
|
+
const commitChunk = async (chunk) => {
|
|
1077
|
+
// Anchors for the pre-claimed steps' telemetry: the POST instant
|
|
1078
|
+
// is the claim's "start POST sent" (RSFS's end), the return is the
|
|
1079
|
+
// claim's completion (TTR's T6), the same two instants the lazy
|
|
1080
|
+
// claim's own POST would have produced.
|
|
1081
|
+
const batchPostSentAtMs = Date.now();
|
|
1082
|
+
// biome-ignore lint/style/noNonNullAssertion: batchFanoutEligible implies presence
|
|
1083
|
+
const { results } = await world.events.createBatch(runId, chunk.map((entry) => ({
|
|
1084
|
+
event: entry.event,
|
|
1085
|
+
// The started row is the step's executing claim, so it carries
|
|
1086
|
+
// the compute-instance attribution the single claim sends via
|
|
1087
|
+
// CreateEventParams.
|
|
1088
|
+
...(entry.kind === 'inline-started'
|
|
1089
|
+
? { computeInstanceId: COMPUTE_INSTANCE_ID }
|
|
1090
|
+
: {}),
|
|
1091
|
+
})),
|
|
1092
|
+
// Per-write request attribution, same as the single path's
|
|
1093
|
+
// createGuarded(…, { requestId }).
|
|
1094
|
+
{ requestId });
|
|
1095
|
+
const claimCompletedAtMs = Date.now();
|
|
1096
|
+
for (const [index, item] of results.entries()) {
|
|
1097
|
+
const entry = chunk[index];
|
|
1098
|
+
if (item.error === undefined) {
|
|
1099
|
+
if (entry.kind === 'step') {
|
|
1100
|
+
createdStepCorrelationIds.add(entry.correlationId);
|
|
1101
|
+
}
|
|
1102
|
+
else if (entry.kind === 'inline-started') {
|
|
1103
|
+
// The pair committed: this invocation owns the step and the
|
|
1104
|
+
// caller runs the body with no claim of its own. The
|
|
1105
|
+
// readback entity is authoritative where present; a World
|
|
1106
|
+
// that omitted it gets the same locally synthesized running
|
|
1107
|
+
// attempt-1 the optimistic path executes against. Either
|
|
1108
|
+
// way the input is re-attached locally: batch responses
|
|
1109
|
+
// return refs lazily, and the body's hydration wants the
|
|
1110
|
+
// exact bytes the pair's created row carried. (The created
|
|
1111
|
+
// row's success is deliberately NOT membership in
|
|
1112
|
+
// createdStepCorrelationIds: for inline steps ownership is
|
|
1113
|
+
// the started row's verdict, and the caller's dispatch pass
|
|
1114
|
+
// skips inline correlation ids regardless.)
|
|
1115
|
+
const dehydrated = lazyInlineByCorrelationId.get(entry.correlationId);
|
|
1116
|
+
if (dehydrated === undefined) {
|
|
1117
|
+
// Unreachable: the same prep op that enqueued the pair set
|
|
1118
|
+
// this entry, and the flush awaited every prep above.
|
|
1119
|
+
//
|
|
1120
|
+
// Not free if it ever fires, though: the pair is already
|
|
1121
|
+
// durable here, so this throws with the step claimed and
|
|
1122
|
+
// its body never run. The delivery fails, and redelivery
|
|
1123
|
+
// recovers it through owned-recovery (the step carries this
|
|
1124
|
+
// message's ownership stamp) rather than the request just
|
|
1125
|
+
// failing cleanly.
|
|
1126
|
+
throw new WorkflowWorldError(`no dehydrated input for pre-claimed step ${entry.correlationId}`, { status: 500 });
|
|
1127
|
+
}
|
|
1128
|
+
const now = new Date();
|
|
1129
|
+
const startedStep = item.step?.startedAt
|
|
1130
|
+
? { ...item.step, startedAt: item.step.startedAt }
|
|
1131
|
+
: {
|
|
1132
|
+
runId,
|
|
1133
|
+
stepId: entry.correlationId,
|
|
1134
|
+
stepName: dehydrated.stepName,
|
|
1135
|
+
status: 'running',
|
|
1136
|
+
attempt: 1,
|
|
1137
|
+
createdAt: now,
|
|
1138
|
+
updatedAt: now,
|
|
1139
|
+
startedAt: now,
|
|
1140
|
+
};
|
|
1141
|
+
inlineClaims.set(entry.correlationId, {
|
|
1142
|
+
owned: true,
|
|
1143
|
+
step: {
|
|
1144
|
+
...startedStep,
|
|
1145
|
+
input: dehydrated.dehydratedInput,
|
|
1146
|
+
},
|
|
1147
|
+
batchPostSentAtMs,
|
|
1148
|
+
claimCompletedAtMs,
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
continue;
|
|
1152
|
+
}
|
|
1153
|
+
if (item.status === 409) {
|
|
1154
|
+
if (entry.kind === 'inline-created' ||
|
|
1155
|
+
entry.kind === 'inline-started') {
|
|
1156
|
+
// The pair lost its atomic create-claim: a concurrent writer
|
|
1157
|
+
// already owns this step (an earlier delivery's create, or a
|
|
1158
|
+
// racing handler's claim). Recorded as a lost claim: the
|
|
1159
|
+
// caller's executeStep returns `skipped` without running the
|
|
1160
|
+
// body, the same outcome as losing the lazy claim. A World
|
|
1161
|
+
// that folds the pair reports the 409 on both rows (set
|
|
1162
|
+
// twice, harmless); one that evaluates rows independently
|
|
1163
|
+
// has the started row (processed second) decide, which is
|
|
1164
|
+
// exactly the single path's semantics (create lost + claim
|
|
1165
|
+
// won still runs the body; create won + claim lost skips).
|
|
1166
|
+
inlineClaims.set(entry.correlationId, { owned: false });
|
|
1167
|
+
runtimeLogger.info('Inline step pre-claim lost, continuing', {
|
|
1168
|
+
workflowRunId: runId,
|
|
1169
|
+
correlationId: entry.correlationId,
|
|
1170
|
+
message: item.message,
|
|
1171
|
+
});
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
// Same tolerance as the single path's EntityConflictError: a
|
|
1175
|
+
// concurrent or earlier delivery already created it.
|
|
1176
|
+
runtimeLogger.info(entry.kind === 'step'
|
|
1177
|
+
? 'Step already exists, continuing'
|
|
1178
|
+
: 'Wait already exists, continuing', {
|
|
1179
|
+
workflowRunId: runId,
|
|
1180
|
+
correlationId: entry.correlationId,
|
|
1181
|
+
message: item.message,
|
|
1182
|
+
});
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
throw new WorkflowWorldError(`batched ${entry.event.eventType} for ${entry.correlationId} ` +
|
|
1186
|
+
`failed: ${item.error}: ${item.message}`, { status: item.status });
|
|
1187
|
+
}
|
|
1188
|
+
// Highest slot this chunk committed: one input of the interleaving
|
|
1189
|
+
// diagnostic.
|
|
1190
|
+
const chunkMaxSlot = maxEventSlot(results.flatMap((item) => item.error === undefined && item.event ? [item.event] : []));
|
|
1191
|
+
committedCount += results.filter((item) => item.error === undefined).length;
|
|
1192
|
+
if (chunkMaxSlot !== undefined &&
|
|
1193
|
+
(maxCommittedSlot === undefined || chunkMaxSlot > maxCommittedSlot)) {
|
|
1194
|
+
maxCommittedSlot = chunkMaxSlot;
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
// Publish the chunk's eager steps' queue messages the moment ITS
|
|
1198
|
+
// creates are durable, the per-chunk half of publish-after-create.
|
|
1199
|
+
// Same message shape and step-identity-scoped idempotency key as the
|
|
1200
|
+
// caller's dispatch pass, so anything double-published dedupes.
|
|
1201
|
+
const publishChunkSteps = async (chunk) => {
|
|
1202
|
+
if (!publishEagerSteps)
|
|
1203
|
+
return;
|
|
1204
|
+
const stepEntries = chunk.filter((entry) => entry.kind === 'step');
|
|
1205
|
+
if (stepEntries.length === 0)
|
|
1206
|
+
return;
|
|
1207
|
+
const traceCarrier = await getStepDispatchTraceCarrier();
|
|
1208
|
+
// One batched publish per chunk instead of one round trip per step.
|
|
1209
|
+
// The publishes are the fan-out's serialization point: they ride the
|
|
1210
|
+
// shared 8-connection HTTP/1.1 agent (see `getQueueDispatcher` in
|
|
1211
|
+
// world-vercel), and the caller awaits all of them before running
|
|
1212
|
+
// the first inline step body, so N round trips land directly on
|
|
1213
|
+
// time-to-first-step. `queueMessages` falls back to concurrent
|
|
1214
|
+
// single sends on a World with no batch support.
|
|
1215
|
+
await queueMessages(world,
|
|
1216
|
+
// biome-ignore lint/style/noNonNullAssertion: publishEagerSteps implies presence
|
|
1217
|
+
stepDispatch.queueName, stepEntries.map((entry) => ({
|
|
1218
|
+
message: {
|
|
1219
|
+
runId,
|
|
1220
|
+
stepId: entry.correlationId,
|
|
1221
|
+
// biome-ignore lint/style/noNonNullAssertion: set on every 'step' entry at enqueue
|
|
1222
|
+
stepName: entry.stepName,
|
|
1223
|
+
traceCarrier,
|
|
1224
|
+
requestedAt: new Date(),
|
|
1225
|
+
runContext: runDispatchContext(run),
|
|
1226
|
+
},
|
|
1227
|
+
opts: {
|
|
1228
|
+
idempotencyKey: stepDispatchIdempotencyKey(entry.correlationId,
|
|
1229
|
+
// biome-ignore lint/style/noNonNullAssertion: set on every 'step' entry at enqueue
|
|
1230
|
+
entry.stepName),
|
|
1231
|
+
},
|
|
1232
|
+
})));
|
|
1233
|
+
};
|
|
1234
|
+
// Launch every chunk's POST now (the lone plain entry's guarded
|
|
1235
|
+
// single create included); chain each chunk's publishes on its OWN
|
|
1236
|
+
// commit, so publish-after-create holds for the single too. A chunk
|
|
1237
|
+
// whose commit rejected keeps its messages unsent (the rejection
|
|
1238
|
+
// fails the delivery; redelivery re-creates and re-dispatches,
|
|
1239
|
+
// deduped by the idempotency keys).
|
|
1240
|
+
const commits = chunks.map((chunk) => chunk === singleChunk ? commitSingle(chunk[0]) : commitChunk(chunk));
|
|
1241
|
+
const publishes = chunks.map(async (chunk, index) => {
|
|
1242
|
+
await commits[index];
|
|
1243
|
+
await publishChunkSteps(chunk);
|
|
1244
|
+
});
|
|
1245
|
+
const trailing = (async () => {
|
|
1246
|
+
// Let every sibling settle before surfacing the first failure: a
|
|
1247
|
+
// chunk that committed must still get its publishes out even when
|
|
1248
|
+
// another chunk failed, and the caller acks only after this
|
|
1249
|
+
// resolves.
|
|
1250
|
+
const settled = await Promise.allSettled([...commits, ...publishes]);
|
|
1251
|
+
// Foreign-interleaving visibility: the batch endpoint has no
|
|
1252
|
+
// bump-and-report, so events other writers landed between the
|
|
1253
|
+
// snapshot and these commits pushed the fold to higher slots
|
|
1254
|
+
// WITHOUT handing us the skipped events. Same accepted exposure
|
|
1255
|
+
// as a dropped truncated report on the single path: the local
|
|
1256
|
+
// log stays a strict prefix and the next reload observes them.
|
|
1257
|
+
// Logged so a bump is diagnosable rather than silent.
|
|
1258
|
+
if (expectedFirstSlot !== undefined &&
|
|
1259
|
+
maxCommittedSlot !== undefined) {
|
|
1260
|
+
const interleaved = maxCommittedSlot - expectedFirstSlot + 1 - committedCount;
|
|
1261
|
+
if (interleaved > 0) {
|
|
1262
|
+
runtimeLogger.debug('Batched fan-out committed above snapshot', {
|
|
1263
|
+
workflowRunId: runId,
|
|
1264
|
+
expectedFirstSlot,
|
|
1265
|
+
maxCommittedSlot,
|
|
1266
|
+
committedCount,
|
|
1267
|
+
interleaved,
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
const failure = settled.find((outcome) => outcome.status === 'rejected');
|
|
1272
|
+
if (failure)
|
|
1273
|
+
throw failure.reason;
|
|
1274
|
+
})();
|
|
1275
|
+
// EVERY chunk carrying pairs gates the return, not just the first:
|
|
1276
|
+
// a pair whose commit the caller has not seen yields no
|
|
1277
|
+
// `inlineClaims` entry, so the caller falls back to a lazy
|
|
1278
|
+
// `step_started` that would race this same fold's still-in-flight
|
|
1279
|
+
// pair for the same step. The pairs occupy their own leading
|
|
1280
|
+
// chunk(s), and today that is exactly ONE chunk (two rows per
|
|
1281
|
+
// inline step fit inside one chunk, pinned by constants.test.ts),
|
|
1282
|
+
// so this is at most one commit; the filter is what keeps the
|
|
1283
|
+
// property true if either cap moves.
|
|
1284
|
+
const pairCommits = chunks.flatMap((chunk, index) => chunk.some((entry) => entry.kind === 'inline-started')
|
|
1285
|
+
? [commits[index]]
|
|
1286
|
+
: []);
|
|
1287
|
+
if (allowDeferredBatchWork) {
|
|
1288
|
+
// The trailing work is the caller's to join before ack. Attach a
|
|
1289
|
+
// handler now so a rejection that races that join (or a foreground
|
|
1290
|
+
// failure that prevents the caller from ever reaching it) is never
|
|
1291
|
+
// an unhandledRejection; awaiting the promise still observes it.
|
|
1292
|
+
trailing.catch(() => { });
|
|
1293
|
+
deferredBatchWork = trailing;
|
|
1294
|
+
// Only the pair chunks gate the return: their claims are what the
|
|
1295
|
+
// caller starts the inline bodies from. With no pairs there is
|
|
1296
|
+
// nothing the caller's post-return work reads from the commits,
|
|
1297
|
+
// so nothing gates.
|
|
1298
|
+
if (pairCommits.length > 0) {
|
|
1299
|
+
try {
|
|
1300
|
+
await Promise.all(pairCommits);
|
|
1301
|
+
}
|
|
1302
|
+
catch (err) {
|
|
1303
|
+
// A pair chunk failed, so this phase's write set is NOT the
|
|
1304
|
+
// caller's to join any more: `deferredBatchWork` never
|
|
1305
|
+
// reaches it once handleSuspension throws. Settle the rest
|
|
1306
|
+
// before the rejection escapes, for the reason `settlePhase`
|
|
1307
|
+
// gives: a sibling create landing after the throw commits an
|
|
1308
|
+
// event from the abandoned replay's seeded sequence and races
|
|
1309
|
+
// the caller's restart reload while doing so.
|
|
1310
|
+
await trailing.catch(() => { });
|
|
1311
|
+
throw err;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
else {
|
|
1316
|
+
await trailing;
|
|
1317
|
+
}
|
|
1318
|
+
})());
|
|
1319
|
+
}
|
|
1320
|
+
for (const queueItem of attributeItems) {
|
|
1321
|
+
ops.push((async () => {
|
|
1322
|
+
try {
|
|
1323
|
+
await ensureRunReady();
|
|
1324
|
+
// Guarded like every other suspension write: an attr_set is a
|
|
1325
|
+
// replay-derived event with a correlation id from this replay's
|
|
1326
|
+
// seeded sequence, so it must not land on a log the replay never
|
|
1327
|
+
// saw. Rejecting it is cheap: a run with attribute events already
|
|
1328
|
+
// forces an in-process replay, so the restart costs the replay it
|
|
1329
|
+
// was going to do anyway.
|
|
1330
|
+
await createGuarded({
|
|
1331
|
+
eventType: 'attr_set',
|
|
1332
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
1333
|
+
correlationId: queueItem.correlationId,
|
|
1334
|
+
eventData: {
|
|
1335
|
+
changes: queueItem.changes,
|
|
1336
|
+
writer: { type: 'workflow' },
|
|
1337
|
+
...(queueItem.allowReservedAttributes
|
|
1338
|
+
? { allowReservedAttributes: true }
|
|
1339
|
+
: {}),
|
|
1340
|
+
},
|
|
1341
|
+
}, { requestId });
|
|
1342
|
+
}
|
|
1343
|
+
catch (err) {
|
|
1344
|
+
if (EntityConflictError.is(err)) {
|
|
1345
|
+
runtimeLogger.info('Workflow attribute event already exists, continuing', {
|
|
1346
|
+
workflowRunId: runId,
|
|
1347
|
+
correlationId: queueItem.correlationId,
|
|
1348
|
+
message: err.message,
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
else if (isWorldValidationFailure(err)) {
|
|
1352
|
+
// Deterministic validation rejection from the World, e.g. the
|
|
1353
|
+
// cumulative per-run attribute cap, which only the World can
|
|
1354
|
+
// check against the run's existing attributes. Redelivering the
|
|
1355
|
+
// orchestrator message replays the workflow into the exact same
|
|
1356
|
+
// write and the exact same rejection, so retrying can never
|
|
1357
|
+
// succeed. Surface it as a FatalError so the caller fails the
|
|
1358
|
+
// run with a clear error instead of wedging it in redelivery.
|
|
1359
|
+
const fatal = new FatalError(`setAttributes failed World validation: ${err instanceof Error ? err.message : String(err)}`);
|
|
1360
|
+
fatal.cause = err;
|
|
1361
|
+
throw fatal;
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
throw err;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
})());
|
|
1368
|
+
}
|
|
1369
|
+
// Await the step_created / wait_created event creates before returning.
|
|
1370
|
+
// The caller (workflowEntrypoint) only enqueues the step-dispatch queue
|
|
1371
|
+
// messages AFTER handleSuspension resolves, and the queue handler acks
|
|
1372
|
+
// the orchestrator message only after the caller resolves. So the step_created
|
|
1373
|
+
// events must be durable here, and the dispatch sends must complete in the caller,
|
|
1374
|
+
// all before ack. If the process crashes before this resolves, the orchestrator
|
|
1375
|
+
// message is not acked and VQS redelivers, re-creates the (idempotent)
|
|
1376
|
+
// step_created and re-dispatches, and recovers the run instead of orphaning it.
|
|
1377
|
+
await settlePhase(ops);
|
|
1378
|
+
// Rebuild the inline batch in deterministic order. `lazyInlineCorrelationIds`
|
|
1379
|
+
// is a Set seeded from the ordered first-N slice, so iterating it preserves
|
|
1380
|
+
// stepItems order; every id in it was set by the lazy branch above.
|
|
1381
|
+
const lazyInlineSteps = [];
|
|
1382
|
+
for (const correlationId of lazyInlineCorrelationIds) {
|
|
1383
|
+
const lazyStep = lazyInlineByCorrelationId.get(correlationId);
|
|
1384
|
+
if (lazyStep)
|
|
1385
|
+
lazyInlineSteps.push(lazyStep);
|
|
1386
|
+
}
|
|
1387
|
+
// Find the soonest pending wait (minimum timeout)
|
|
257
1388
|
const now = Date.now();
|
|
258
|
-
|
|
1389
|
+
let soonestWait;
|
|
1390
|
+
for (const queueItem of waitItems) {
|
|
259
1391
|
const resumeAtMs = queueItem.resumeAt.getTime();
|
|
260
1392
|
const delayMs = Math.max(1000, resumeAtMs - now);
|
|
261
1393
|
const timeoutSeconds = Math.ceil(delayMs / 1000);
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
1394
|
+
if (!soonestWait || timeoutSeconds < soonestWait.seconds) {
|
|
1395
|
+
soonestWait = {
|
|
1396
|
+
seconds: timeoutSeconds,
|
|
1397
|
+
correlationId: queueItem.correlationId,
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
266
1401
|
span?.setAttributes({
|
|
267
1402
|
...Attribute.WorkflowRunStatus('workflow_suspended'),
|
|
268
1403
|
...Attribute.WorkflowStepsCreated(stepItems.length),
|
|
269
1404
|
...Attribute.WorkflowHooksCreated(hooksNeedingCreation.length),
|
|
270
1405
|
...Attribute.WorkflowWaitsCreated(waitItems.length),
|
|
1406
|
+
...(failedStepCorrelationIds.size > 0
|
|
1407
|
+
? Attribute.WorkflowStepsFailedSerialization(failedStepCorrelationIds.size)
|
|
1408
|
+
: {}),
|
|
1409
|
+
...(resilientDispatchRecovered > 0
|
|
1410
|
+
? Attribute.StepResilientDispatchRecovered(resilientDispatchRecovered)
|
|
1411
|
+
: {}),
|
|
271
1412
|
});
|
|
272
1413
|
return {
|
|
273
1414
|
pendingSteps: stepItems,
|
|
274
1415
|
createdStepCorrelationIds,
|
|
275
|
-
|
|
276
|
-
|
|
1416
|
+
failedStepCorrelationIds,
|
|
1417
|
+
queuedStepCorrelationIds,
|
|
1418
|
+
lazyInlineSteps,
|
|
1419
|
+
inlineClaims,
|
|
1420
|
+
deferredBatchWork,
|
|
1421
|
+
// On hook conflict the caller advances the workflow over the conflict
|
|
1422
|
+
// before scheduling anything and never reads the wait timeout, so don't
|
|
1423
|
+
// report one. The next pass, which sees the conflict settled, reports it.
|
|
1424
|
+
waitTimeout: hookConflictCorrelationIds.length > 0 ? undefined : soonestWait,
|
|
1425
|
+
hasHookConflict: hookConflictCorrelationIds.length > 0,
|
|
1426
|
+
hookConflictCorrelationIds,
|
|
1427
|
+
hasAwaitedHookCreation: awaitedHookCorrelationIds.length > 0,
|
|
1428
|
+
awaitedHookCorrelationIds,
|
|
1429
|
+
// The delta accounts for the whole log only if the write that returned it
|
|
1430
|
+
// was this suspension's only one — anything written after it landed above
|
|
1431
|
+
// the delta and is missing from the caller's log.
|
|
1432
|
+
eventLogCarriedForward: deltaAbsorbed && guardedWrites === 1,
|
|
1433
|
+
hasAttributeEvents: attributeItems.length > 0,
|
|
1434
|
+
hasHookEvents: hooksNeedingCreation.length > 0,
|
|
1435
|
+
hookCreationMs,
|
|
1436
|
+
serializationBlockerCount,
|
|
1437
|
+
serializationBlockers,
|
|
1438
|
+
reportedEventCount: reportedEvents,
|
|
277
1439
|
};
|
|
278
1440
|
}
|
|
279
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VzcGVuc2lvbi1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3VzcGVuc2lvbi1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM5QyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQixlQUFlLEdBQ2hCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUdMLG9CQUFvQixHQUdyQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQU83QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN2RCxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBZ0NsRTs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsZ0JBQWdCLENBQUMsRUFDckMsVUFBVSxFQUNWLEtBQUssRUFDTCxHQUFHLEVBQ0gsSUFBSSxFQUNKLFNBQVMsR0FDZTtJQUN4QixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDO0lBQ3hCLCtCQUErQjtJQUMvQixNQUFNLFNBQVMsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FDdkMsQ0FBQyxJQUFJLEVBQW1DLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FDaEUsQ0FBQztJQUNGLE1BQU0sWUFBWSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUMxQyxDQUFDLElBQUksRUFBbUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUNoRSxDQUFDO0lB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LENBQUM7UUFDakQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFDakQsSUFBSSxHQUFHLEtBQUssSUFBSTtZQUFFLE9BQU8sY0FBYyxDQUFDO1FBQ3hDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDdkMsQ0FBQyxFQUNELElBQUksQ0FDTCxDQUFDO0lBRUYsSUFBSSxFQUFFLGFBQWEsQ0FBQztRQUNsQixHQUFHLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxvQkFBb0IsQ0FBQztRQUNwRCxHQUFHLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ25ELEdBQUcsU0FBUyxDQUFDLG9CQUFvQixDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQztRQUM5RCxHQUFHLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO0tBQ3BELENBQUMsQ0FBQztJQUVILE9BQU87UUFDTCxZQUFZLEVBQUUsU0FBUztRQUN2Qix5QkFBeUI7UUFDekIsY0FBYyxFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixJQUFJLFNBQVMsQ0FBQztRQUN0RSxlQUFlO0tBQ2hCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBTcGFuIH0gZnJvbSAnQG9wZW50ZWxlbWV0cnkvYXBpJztcbmltcG9ydCB7IHdhaXRVbnRpbCB9IGZyb20gJ0B2ZXJjZWwvZnVuY3Rpb25zJztcbmltcG9ydCB7XG4gIEVudGl0eUNvbmZsaWN0RXJyb3IsXG4gIEhvb2tOb3RGb3VuZEVycm9yLFxuICBSdW5FeHBpcmVkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHtcbiAgdHlwZSBDcmVhdGVFdmVudFJlcXVlc3QsXG4gIHR5cGUgU2VyaWFsaXplZERhdGEsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICB0eXBlIFdvcmtmbG93UnVuLFxuICB0eXBlIFdvcmxkLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgaW1wb3J0S2V5IH0gZnJvbSAnLi4vZW5jcnlwdGlvbi5qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIEhvb2tJbnZvY2F0aW9uUXVldWVJdGVtLFxuICBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgV2FpdEludm9jYXRpb25RdWV1ZUl0ZW0sXG4gIFdvcmtmbG93U3VzcGVuc2lvbixcbn0gZnJvbSAnLi4vZ2xvYmFsLmpzJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZGVoeWRyYXRlU3RlcEFyZ3VtZW50cyB9IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0IHsgZ2V0QWJvcnRTdHJlYW1JZEZyb21Ub2tlbiB9IGZyb20gJy4uL3V0aWwuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3VzcGVuc2lvbkhhbmRsZXJQYXJhbXMge1xuICBzdXNwZW5zaW9uOiBXb3JrZmxvd1N1c3BlbnNpb247XG4gIHdvcmxkOiBXb3JsZDtcbiAgcnVuOiBXb3JrZmxvd1J1bjtcbiAgc3Bhbj86IFNwYW47XG4gIHJlcXVlc3RJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgaGFuZGxpbmcgYSBzdXNwZW5zaW9uLiBSZXR1cm5zIHBlbmRpbmcgc3RlcCBpdGVtcyBzbyB0aGUgY2FsbGVyXG4gKiBjYW4gZGVjaWRlIHdoaWNoIHRvIGV4ZWN1dGUgaW5saW5lIHZzIHF1ZXVlIHRvIGJhY2tncm91bmQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3VzcGVuc2lvbkhhbmRsZXJSZXN1bHQge1xuICAvKiogUGVuZGluZyBzdGVwIGl0ZW1zIHdpdGggZXZlbnRzIGNyZWF0ZWQgYnV0IE5PVCBxdWV1ZWQgKi9cbiAgcGVuZGluZ1N0ZXBzOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbVtdO1xuICAvKipcbiAgICogQ29ycmVsYXRpb24gSURzIGZvciB3aGljaCB0aGlzIHN1c3BlbnNpb24gY2FsbCBhY3R1YWxseSB3cm90ZSB0aGVcbiAgICogc3RlcF9jcmVhdGVkIGV2ZW50IChhcyBvcHBvc2VkIHRvIGNhdGNoaW5nIEVudGl0eUNvbmZsaWN0RXJyb3IgYmVjYXVzZVxuICAgKiBhIGNvbmN1cnJlbnQgaGFuZGxlciB3cm90ZSBpdCBmaXJzdCkuIE9ubHkgdGhlIGhhbmRsZXIgdGhhdCB3cm90ZSB0aGVcbiAgICogc3RlcF9jcmVhdGVkIGV2ZW50IHNob3VsZCBxdWV1ZSAvIGlubGluZS1leGVjdXRlIHRoZSBzdGVwIOKAlCB0aGlzXG4gICAqIGd1YXJhbnRlZXMgYSBzaW5nbGUgb3duZXIgcGVyIHN0ZXAsIGV2ZW4gd2hlbiBtdWx0aXBsZSBoYW5kbGVycyByYWNlXG4gICAqIGludG8gdGhlIHNhbWUgYmF0Y2ggYm91bmRhcnkuXG4gICAqL1xuICBjcmVhdGVkU3RlcENvcnJlbGF0aW9uSWRzOiBTZXQ8c3RyaW5nPjtcbiAgLyoqIFRpbWVvdXQgZnJvbSB3YWl0cywgaWYgYW55ICovXG4gIHRpbWVvdXRTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogV2hldGhlciBhIGhvb2sgY29uZmxpY3Qgd2FzIGRldGVjdGVkIChzaG91bGQgcmUtaW52b2tlIGltbWVkaWF0ZWx5KSAqL1xuICBoYXNIb29rQ29uZmxpY3Q6IGJvb2xlYW47XG59XG5cbi8qKlxuICogSGFuZGxlcyBhIHdvcmtmbG93IHN1c3BlbnNpb24gYnkgcHJvY2Vzc2luZyBhbGwgcGVuZGluZyBvcGVyYXRpb25zIChob29rcywgc3RlcHMsIHdhaXRzKS5cbiAqIENyZWF0ZXMgZXZlbnRzIGZvciBhbGwgb3BlcmF0aW9ucyBidXQgZG9lcyBOT1QgcXVldWUgc3RlcCBtZXNzYWdlcyDigJQgcmV0dXJucyB0aGUgcGVuZGluZ1xuICogc3RlcHMgc28gdGhlIGNhbGxlciBjYW4gZGVjaWRlIHdoaWNoIHRvIGV4ZWN1dGUgaW5saW5lIHZzIHF1ZXVlIHRvIGJhY2tncm91bmQuXG4gKlxuICogUHJvY2Vzc2luZyBvcmRlcjpcbiAqIDEuIEhvb2tzIGFyZSBwcm9jZXNzZWQgZmlyc3QgdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnMgd2l0aCB3ZWJob29rIHJlY2VpdmVyc1xuICogMi4gU3RlcCBldmVudHMgYW5kIHdhaXQgZXZlbnRzIGFyZSBjcmVhdGVkIGluIHBhcmFsbGVsXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVTdXNwZW5zaW9uKHtcbiAgc3VzcGVuc2lvbixcbiAgd29ybGQsXG4gIHJ1bixcbiAgc3BhbixcbiAgcmVxdWVzdElkLFxufTogU3VzcGVuc2lvbkhhbmRsZXJQYXJhbXMpOiBQcm9taXNlPFN1c3BlbnNpb25IYW5kbGVyUmVzdWx0PiB7XG4gIGNvbnN0IHJ1bklkID0gcnVuLnJ1bklkO1xuICAvLyBTZXBhcmF0ZSBxdWV1ZSBpdGVtcyBieSB0eXBlXG4gIGNvbnN0IHN0ZXBJdGVtcyA9IHN1c3BlbnNpb24uc3RlcHMuZmlsdGVyKFxuICAgIChpdGVtKTogaXRlbSBpcyBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSA9PiBpdGVtLnR5cGUgPT09ICdzdGVwJ1xuICApO1xuICBjb25zdCBhbGxIb29rSXRlbXMgPSBzdXNwZW5zaW9uLnN0ZXBzLmZpbHRlcihcbiAgICAoaXRlbSk6IGl0ZW0gaXMgSG9va0ludm9jYXRpb25RdWV1ZUl0ZW0gPT4gaXRlbS50eXBlID09PSAnaG9vaydcbiAgKTtcbiAgY29uc3Qgd2FpdEl0ZW1zID0gc3VzcGVuc2lvbi5zdGVwcy5maWx0ZXIoXG4gICAgKGl0ZW0pOiBpdGVtIGlzIFdhaXRJbnZvY2F0aW9uUXVldWVJdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3dhaXQnXG4gICk7XG5cbiAgLy8gU3BsaXQgaG9va3MgYnkgd2hhdCBhY3Rpb25zIHRoZXkgbmVlZFxuICBjb25zdCBob29rc05lZWRpbmdDcmVhdGlvbiA9IGFsbEhvb2tJdGVtcy5maWx0ZXIoXG4gICAgKGl0ZW0pID0+ICFpdGVtLmhhc0NyZWF0ZWRFdmVudFxuICApO1xuICBjb25zdCBob29rc05lZWRpbmdEaXNwb3NhbCA9IGFsbEhvb2tJdGVtcy5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0uZGlzcG9zZWQpO1xuXG4gIC8vIFJlc29sdmUgZW5jcnlwdGlvbiBrZXkgZm9yIHRoaXMgcnVuXG4gIGNvbnN0IHJhd0tleSA9IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihydW4pO1xuICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gcmF3S2V5ID8gYXdhaXQgaW1wb3J0S2V5KHJhd0tleSkgOiB1bmRlZmluZWQ7XG5cbiAgLy8gQnVpbGQgYW5kIHByb2Nlc3MgaG9va19jcmVhdGVkIGV2ZW50cyAoc2FtZSBhcyBWMSlcbiAgY29uc3QgaG9va0V2ZW50czogQ3JlYXRlRXZlbnRSZXF1ZXN0W10gPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICBob29rc05lZWRpbmdDcmVhdGlvbi5tYXAoYXN5bmMgKHF1ZXVlSXRlbSkgPT4ge1xuICAgICAgY29uc3QgaG9va01ldGFkYXRhOiBTZXJpYWxpemVkRGF0YSB8IHVuZGVmaW5lZCA9XG4gICAgICAgIHR5cGVvZiBxdWV1ZUl0ZW0ubWV0YWRhdGEgPT09ICd1bmRlZmluZWQnXG4gICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICA6ICgoYXdhaXQgZGVoeWRyYXRlU3RlcEFyZ3VtZW50cyhcbiAgICAgICAgICAgICAgcXVldWVJdGVtLm1ldGFkYXRhLFxuICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgc3VzcGVuc2lvbi5nbG9iYWxUaGlzXG4gICAgICAgICAgICApKSBhcyBTZXJpYWxpemVkRGF0YSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBldmVudFR5cGU6ICdob29rX2NyZWF0ZWQnIGFzIGNvbnN0LFxuICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICB0b2tlbjogcXVldWVJdGVtLnRva2VuLFxuICAgICAgICAgIG1ldGFkYXRhOiBob29rTWV0YWRhdGEsXG4gICAgICAgICAgaXNXZWJob29rOiBxdWV1ZUl0ZW0uaXNXZWJob29rID8/IGZhbHNlLFxuICAgICAgICAgIC4uLihxdWV1ZUl0ZW0uaXNTeXN0ZW0gJiYgeyBpc1N5c3RlbTogdHJ1ZSB9KSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSlcbiAgKTtcblxuICAvLyBQcm9jZXNzIGhvb2tzIGZpcnN0IHRvIHByZXZlbnQgcmFjZSBjb25kaXRpb25zIHdpdGggd2ViaG9vayByZWNlaXZlcnMuXG4gIC8vIEFsbCBob29rIGNyZWF0aW9ucyBydW4gaW4gcGFyYWxsZWwuXG4gIC8vIFRyYWNrIGFueSBob29rIGNvbmZsaWN0cyB0aGF0IG9jY3VyIOKAlCB0aGVzZSBhcmUgcmV0dXJuZWQgdG8gdGhlIGNhbGxlclxuICAvLyBzbyB0aGUgVjIgaGFuZGxlciBjYW4gcmUtaW52b2tlIGltbWVkaWF0ZWx5LlxuICBsZXQgaGFzSG9va0NvbmZsaWN0ID0gZmFsc2U7XG5cbiAgaWYgKGhvb2tFdmVudHMubGVuZ3RoID4gMCkge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgaG9va0V2ZW50cy5tYXAoYXN5bmMgKGhvb2tFdmVudCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIGhvb2tFdmVudCwge1xuICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSB3b3JsZCByZXR1cm5lZCBhIGhvb2tfY29uZmxpY3QgZXZlbnQgaW5zdGVhZCBvZiBob29rX2NyZWF0ZWQuXG4gICAgICAgICAgLy8gVGhlIGhvb2tfY29uZmxpY3QgZXZlbnQgaXMgc3RvcmVkIGluIHRoZSBldmVudCBsb2cgYW5kIHdpbGwgYmUgcmVwbGF5ZWRcbiAgICAgICAgICAvLyBvbiB0aGUgbmV4dCB3b3JrZmxvdyBpbnZvY2F0aW9uLCBjYXVzaW5nIHRoZSBob29rJ3MgcHJvbWlzZSB0byByZWplY3QuXG4gICAgICAgICAgLy8gTm90ZTogaG9vayBldmVudHMgYWx3YXlzIGNyZWF0ZSBhbiBldmVudCAobGVnYWN5IHJ1bnMgdGhyb3csIG5vdCByZXR1cm4gdW5kZWZpbmVkKVxuICAgICAgICAgIGlmIChyZXN1bHQuZXZlbnQhLmV2ZW50VHlwZSA9PT0gJ2hvb2tfY29uZmxpY3QnKSB7XG4gICAgICAgICAgICBoYXNIb29rQ29uZmxpY3QgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSB8fCBSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAnV29ya2Zsb3cgcnVuIGFscmVhZHkgY29tcGxldGVkLCBza2lwcGluZyBob29rJyxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICAvLyBQcm9jZXNzIGhvb2sgZGlzcG9zYWxzIOKAlCB0aGVzZSByZWxlYXNlIGhvb2sgdG9rZW5zIGZvciByZXVzZSBieSBvdGhlciB3b3JrZmxvd3MuXG4gIGlmIChob29rc05lZWRpbmdEaXNwb3NhbC5sZW5ndGggPiAwKSB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBob29rc05lZWRpbmdEaXNwb3NhbC5tYXAoYXN5bmMgKHF1ZXVlSXRlbSkgPT4ge1xuICAgICAgICBjb25zdCBob29rRGlzcG9zZWRFdmVudDogQ3JlYXRlRXZlbnRSZXF1ZXN0ID0ge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfZGlzcG9zZWQnIGFzIGNvbnN0LFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgfTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCBob29rRGlzcG9zZWRFdmVudCwgeyByZXF1ZXN0SWQgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgIC8vIEhvb2sgd2FzIGFscmVhZHkgZGlzcG9zZWQgYnkgYSBjb25jdXJyZW50IGludm9jYXRpb24g4oCUIHNhZmUgdG8gc2tpcFxuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAnSG9vayBhbHJlYWR5IGRpc3Bvc2VkLCBza2lwcGluZyBkdXBsaWNhdGUgZGlzcG9zYWwnLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIGlmIChSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAnV29ya2Zsb3cgcnVuIGFscmVhZHkgY29tcGxldGVkLCBza2lwcGluZyBob29rIGRpc3Bvc2FsJyxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoSG9va05vdEZvdW5kRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgLy8gSG9vayBtYXkgaGF2ZSBhbHJlYWR5IGJlZW4gZGlzcG9zZWQgb3IgbmV2ZXIgY3JlYXRlZFxuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKCdIb29rIG5vdCBmb3VuZCBmb3IgZGlzcG9zYWwsIGNvbnRpbnVpbmcnLCB7XG4gICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLy8gUHJvY2VzcyBhYm9ydCByZXF1ZXN0cyDigJQgcmVzdW1lIHRoZSBob29rIHdpdGggYWJvcnQgcGF5bG9hZCBhbmQgd3JpdGUgc3RyZWFtIHBhY2tldFxuICBjb25zdCBob29rc05lZWRpbmdBYm9ydCA9IGFsbEhvb2tJdGVtcy5maWx0ZXIoXG4gICAgKGl0ZW0pID0+IGl0ZW0uYWJvcnRSZXF1ZXN0ZWQgJiYgIWl0ZW0uZGlzcG9zZWRcbiAgKTtcblxuICBpZiAoaG9va3NOZWVkaW5nQWJvcnQubGVuZ3RoID4gMCkge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgaG9va3NOZWVkaW5nQWJvcnQubWFwKGFzeW5jIChxdWV1ZUl0ZW0pID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBEZWh5ZHJhdGUgdGhlIGFib3J0IHBheWxvYWQgZm9yIHN0b3JhZ2VcbiAgICAgICAgICBjb25zdCBhYm9ydFBheWxvYWQgPSBhd2FpdCBkZWh5ZHJhdGVTdGVwQXJndW1lbnRzKFxuICAgICAgICAgICAgeyBhYm9ydGVkOiB0cnVlLCByZWFzb246IHF1ZXVlSXRlbS5hYm9ydFJlYXNvbiB9LFxuICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgICAgc3VzcGVuc2lvbi5nbG9iYWxUaGlzXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIENyZWF0ZSBob29rX3JlY2VpdmVkIGV2ZW50IHdpdGggYWJvcnQgcGF5bG9hZFxuICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfcmVjZWl2ZWQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgcGF5bG9hZDogYWJvcnRQYXlsb2FkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIFdyaXRlIHN0cmVhbSBjYW5jZWxsYXRpb24gcGFja2V0IGZvciByZWFsLXRpbWUgc3RlcCBwcm9wYWdhdGlvbi5cbiAgICAgICAgICAvLyBSZXVzZSB0aGUgc2FtZSBkZWh5ZHJhdGVkIHBheWxvYWQgYXMgdGhlIGhvb2sgZXZlbnQgc28gdGhlIHJlYXNvblxuICAgICAgICAgIC8vIHJvdW5kLXRyaXBzIHRocm91Z2ggYGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHNgIC8gYGh5ZHJhdGVTdGVwQXJndW1lbnRzYFxuICAgICAgICAgIC8vIChoYW5kbGVzIERPTUV4Y2VwdGlvbiwgY3VzdG9tIGVycm9ycywgZW5jcnlwdGlvbiwgZXRjLikgaW5zdGVhZCBvZlxuICAgICAgICAgIC8vIGJhcmUgSlNPTi5zdHJpbmdpZnkgd2hpY2ggbG9zZXMgdHlwZSBpbmZvcm1hdGlvbiBhbmQgZHJvcHMgdW5kZWZpbmVkLlxuICAgICAgICAgIC8vIHN0cmVhbU5hbWUgaXMgc2V0IG9uIHRoZSBxdWV1ZSBpdGVtIGF0IGNvbnRyb2xsZXIgY29uc3RydWN0aW9uIHRpbWVcbiAgICAgICAgICAvLyAoc2VlIHdvcmtmbG93L2Fib3J0LWNvbnRyb2xsZXIudHMpLlxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBzdHJlYW1OYW1lID0gZ2V0QWJvcnRTdHJlYW1JZEZyb21Ub2tlbihxdWV1ZUl0ZW0udG9rZW4pO1xuICAgICAgICAgICAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShcbiAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgIHN0cmVhbU5hbWUsXG4gICAgICAgICAgICAgIGFib3J0UGF5bG9hZCBhcyBVaW50OEFycmF5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShydW5JZCwgc3RyZWFtTmFtZSk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvLyBCZXN0LWVmZm9ydCBzdHJlYW0gd3JpdGUg4oCUIGhvb2sgZXZlbnQgcHJvdmlkZXMgdGhlIGR1cmFibGUgZmFsbGJhY2tcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICdGYWlsZWQgdG8gd3JpdGUgYWJvcnQgc3RyZWFtIHBhY2tldCwgaG9vayBldmVudCB3aWxsIHByb3ZpZGUgZmFsbGJhY2snLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8IFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICdXb3JrZmxvdyBydW4gYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nIGFib3J0JyxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICAvLyBDcmVhdGUgc3RlcCBldmVudHMgZm9yIHN0ZXBzIHRoYXQgZG9uJ3QgaGF2ZSB0aGVtIHlldC5cbiAgLy8gVW5saWtlIFYxLCB3ZSBkbyBOT1QgcXVldWUgc3RlcCBtZXNzYWdlcyBmcm9tIGhlcmUg4oCUIHRoZSBjYWxsZXJcbiAgLy8gZGVjaWRlcyB3aGljaCBzdGVwcyB0byBleGVjdXRlIGlubGluZSB2cy4gcXVldWUgdG8gYmFja2dyb3VuZC5cbiAgLy8gV2FpdCBldmVudHMgYXJlIGFsc28gY3JlYXRlZCBpbiBwYXJhbGxlbCBiZWxvdy5cbiAgY29uc3Qgc3RlcHNOZWVkaW5nQ3JlYXRpb24gPSBuZXcgU2V0KFxuICAgIHN0ZXBJdGVtc1xuICAgICAgLmZpbHRlcigocXVldWVJdGVtKSA9PiAhcXVldWVJdGVtLmhhc0NyZWF0ZWRFdmVudClcbiAgICAgIC5tYXAoKHF1ZXVlSXRlbSkgPT4gcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQpXG4gICk7XG5cbiAgLy8gQ29ycmVsYXRpb24gSURzIGZvciB3aGljaCBUSElTIHN1c3BlbnNpb24gY2FsbCBhY3R1YWxseSB3cm90ZSB0aGVcbiAgLy8gc3RlcF9jcmVhdGVkIGV2ZW50LiBQb3B1bGF0ZWQgYnkgdGhlIG9wcyBiZWxvdyBhZnRlciBhIHN1Y2Nlc3NmdWxcbiAgLy8gZXZlbnRzLmNyZWF0ZSDigJQgdXNlZCBieSB0aGUgY2FsbGVyIHRvIGNsYWltIG93bmVyc2hpcCBhbmQgYXZvaWRcbiAgLy8gcmFjaW5nIHdpdGggY29uY3VycmVudCBoYW5kbGVycyBvbiBzdGVwIGV4ZWN1dGlvbi5cbiAgY29uc3QgY3JlYXRlZFN0ZXBDb3JyZWxhdGlvbklkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGNvbnN0IG9wczogUHJvbWlzZTx2b2lkPltdID0gW107XG5cbiAgLy8gU3RlcHM6IGNyZWF0ZSBzdGVwX2NyZWF0ZWQgZXZlbnRzIChubyBxdWV1aW5nIOKAlCBWMiByZXR1cm5zIHBlbmRpbmcgc3RlcHMgdG8gY2FsbGVyKVxuICBmb3IgKGNvbnN0IHF1ZXVlSXRlbSBvZiBzdGVwSXRlbXMpIHtcbiAgICBpZiAoc3RlcHNOZWVkaW5nQ3JlYXRpb24uaGFzKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKSkge1xuICAgICAgb3BzLnB1c2goXG4gICAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgZGVoeWRyYXRlZElucHV0ID0gYXdhaXQgZGVoeWRyYXRlU3RlcEFyZ3VtZW50cyhcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgYXJnczogcXVldWVJdGVtLmFyZ3MsXG4gICAgICAgICAgICAgIGNsb3N1cmVWYXJzOiBxdWV1ZUl0ZW0uY2xvc3VyZVZhcnMsXG4gICAgICAgICAgICAgIHRoaXNWYWw6IHF1ZXVlSXRlbS50aGlzVmFsLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgIHN1c3BlbnNpb24uZ2xvYmFsVGhpc1xuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3Qgc3RlcEV2ZW50OiBDcmVhdGVFdmVudFJlcXVlc3QgPSB7XG4gICAgICAgICAgICBldmVudFR5cGU6ICdzdGVwX2NyZWF0ZWQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgaW5wdXQ6IGRlaHlkcmF0ZWRJbnB1dCBhcyBTZXJpYWxpemVkRGF0YSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShydW5JZCwgc3RlcEV2ZW50LCB7IHJlcXVlc3RJZCB9KTtcbiAgICAgICAgICAgIGNyZWF0ZWRTdGVwQ29ycmVsYXRpb25JZHMuYWRkKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKCdTdGVwIGFscmVhZHkgZXhpc3RzLCBjb250aW51aW5nJywge1xuICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pKClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ3JlYXRlIHdhaXQgZXZlbnRzIChzYW1lIGFzIFYxKVxuICBmb3IgKGNvbnN0IHF1ZXVlSXRlbSBvZiB3YWl0SXRlbXMpIHtcbiAgICBpZiAoIXF1ZXVlSXRlbS5oYXNDcmVhdGVkRXZlbnQpIHtcbiAgICAgIG9wcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHdhaXRFdmVudDogQ3JlYXRlRXZlbnRSZXF1ZXN0ID0ge1xuICAgICAgICAgICAgZXZlbnRUeXBlOiAnd2FpdF9jcmVhdGVkJyBhcyBjb25zdCxcbiAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgIHJlc3VtZUF0OiBxdWV1ZUl0ZW0ucmVzdW1lQXQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH07XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUocnVuSWQsIHdhaXRFdmVudCwgeyByZXF1ZXN0SWQgfSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbygnV2FpdCBhbHJlYWR5IGV4aXN0cywgY29udGludWluZycsIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHdhaXRVbnRpbChcbiAgICBQcm9taXNlLmFsbChvcHMpLmNhdGNoKChvcEVycikgPT4ge1xuICAgICAgY29uc3QgaXNBYm9ydEVycm9yID1cbiAgICAgICAgb3BFcnI/Lm5hbWUgPT09ICdBYm9ydEVycm9yJyB8fCBvcEVycj8ubmFtZSA9PT0gJ1Jlc3BvbnNlQWJvcnRlZCc7XG4gICAgICBpZiAoIWlzQWJvcnRFcnJvcikgdGhyb3cgb3BFcnI7XG4gICAgfSlcbiAgKTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwob3BzKTtcblxuICAvLyBDYWxjdWxhdGUgbWluaW11bSB0aW1lb3V0IGZyb20gd2FpdHNcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgbWluVGltZW91dFNlY29uZHMgPSB3YWl0SXRlbXMucmVkdWNlPG51bWJlciB8IG51bGw+KFxuICAgIChtaW4sIHF1ZXVlSXRlbSkgPT4ge1xuICAgICAgY29uc3QgcmVzdW1lQXRNcyA9IHF1ZXVlSXRlbS5yZXN1bWVBdC5nZXRUaW1lKCk7XG4gICAgICBjb25zdCBkZWxheU1zID0gTWF0aC5tYXgoMTAwMCwgcmVzdW1lQXRNcyAtIG5vdyk7XG4gICAgICBjb25zdCB0aW1lb3V0U2Vjb25kcyA9IE1hdGguY2VpbChkZWxheU1zIC8gMTAwMCk7XG4gICAgICBpZiAobWluID09PSBudWxsKSByZXR1cm4gdGltZW91dFNlY29uZHM7XG4gICAgICByZXR1cm4gTWF0aC5taW4obWluLCB0aW1lb3V0U2Vjb25kcyk7XG4gICAgfSxcbiAgICBudWxsXG4gICk7XG5cbiAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKCd3b3JrZmxvd19zdXNwZW5kZWQnKSxcbiAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dTdGVwc0NyZWF0ZWQoc3RlcEl0ZW1zLmxlbmd0aCksXG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93SG9va3NDcmVhdGVkKGhvb2tzTmVlZGluZ0NyZWF0aW9uLmxlbmd0aCksXG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93V2FpdHNDcmVhdGVkKHdhaXRJdGVtcy5sZW5ndGgpLFxuICB9KTtcblxuICByZXR1cm4ge1xuICAgIHBlbmRpbmdTdGVwczogc3RlcEl0ZW1zLFxuICAgIGNyZWF0ZWRTdGVwQ29ycmVsYXRpb25JZHMsXG4gICAgdGltZW91dFNlY29uZHM6IGhhc0hvb2tDb25mbGljdCA/IDAgOiAobWluVGltZW91dFNlY29uZHMgPz8gdW5kZWZpbmVkKSxcbiAgICBoYXNIb29rQ29uZmxpY3QsXG4gIH07XG59XG4iXX0=
|
|
1441
|
+
/**
|
|
1442
|
+
* Whether an `events.create` rejection is deterministic World validation
|
|
1443
|
+
* rather than a transient/storage error. Local Worlds
|
|
1444
|
+
* (world-local, world-postgres) throw `AttributeValidationError` directly;
|
|
1445
|
+
* remote Worlds surface the equivalent server-side rejection as a
|
|
1446
|
+
* `WorkflowWorldError` with HTTP status 400. The name check covers
|
|
1447
|
+
* `AttributeValidationError` instances from a different copy of
|
|
1448
|
+
* `@workflow/world` than the one this package resolved.
|
|
1449
|
+
*/
|
|
1450
|
+
function isWorldValidationFailure(err) {
|
|
1451
|
+
if (err instanceof AttributeValidationError)
|
|
1452
|
+
return true;
|
|
1453
|
+
if (err instanceof Error && err.name === 'AttributeValidationError') {
|
|
1454
|
+
return true;
|
|
1455
|
+
}
|
|
1456
|
+
return WorkflowWorldError.is(err) && err.status === 400;
|
|
1457
|
+
}
|
|
1458
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VzcGVuc2lvbi1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvc3VzcGVuc2lvbi1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsVUFBVSxFQUNWLGlCQUFpQixFQUNqQix1QkFBdUIsRUFDdkIsZUFBZSxFQUNmLGtCQUFrQixFQUNsQixrQkFBa0IsR0FDbkIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQ0wsd0JBQXdCLEVBS3hCLG9CQUFvQixFQUNwQiwwQ0FBMEMsRUFDMUMsaUNBQWlDLEVBQ2pDLG1DQUFtQyxHQU1wQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzdELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQVE3QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFDTCxpQ0FBaUMsR0FHbEMsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLGtCQUFrQixHQUNuQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sS0FBSyxTQUFTLE1BQU0sc0NBQXNDLENBQUM7QUFDbEUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFDTCxpQkFBaUIsRUFDakIseUJBQXlCLEVBQ3pCLDhCQUE4QixFQUM5Qix1QkFBdUIsRUFDdkIsOEJBQThCLEdBQy9CLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixjQUFjLEVBR2QsWUFBWSxFQUNaLFlBQVksRUFDWixhQUFhLEVBQ2Isa0JBQWtCLEVBQ2xCLGtCQUFrQixF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QUFDO0lBQ0QsT0FBTyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUM7QUFDMUQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgU3BhbiB9IGZyb20gJ0BvcGVudGVsZW1ldHJ5L2FwaSc7XG5pbXBvcnQge1xuICBFbnRpdHlDb25mbGljdEVycm9yLFxuICBGYXRhbEVycm9yLFxuICBIb29rTm90Rm91bmRFcnJvcixcbiAgUHJlY29uZGl0aW9uRmFpbGVkRXJyb3IsXG4gIFJ1bkV4cGlyZWRFcnJvcixcbiAgU2VyaWFsaXphdGlvbkVycm9yLFxuICBXb3JrZmxvd1dvcmxkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHtcbiAgQXR0cmlidXRlVmFsaWRhdGlvbkVycm9yLFxuICB0eXBlIENyZWF0ZUV2ZW50UGFyYW1zLFxuICB0eXBlIENyZWF0ZUV2ZW50UmVxdWVzdCxcbiAgdHlwZSBFdmVudFJlc3VsdCxcbiAgdHlwZSBTZXJpYWxpemVkRGF0YSxcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DQk9SX1FVRVVFX1RSQU5TUE9SVCxcbiAgU1BFQ19WRVJTSU9OX1NVUFBPUlRTX0NPTVBSRVNTSU9OLFxuICBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfU0xPVF9JREVOVElUWSxcbiAgdHlwZSBTdGFydGVkU3RlcCxcbiAgdHlwZSBUcmFjZUNhcnJpZXIsXG4gIHR5cGUgVmFsaWRRdWV1ZU5hbWUsXG4gIHR5cGUgV29ya2Zsb3dSdW4sXG4gIHR5cGUgV29ybGQsXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBpc1JldHJ5YWJsZVdvcmxkRXJyb3IgfSBmcm9tICcuLi9jbGFzc2lmeS1lcnJvci5qcyc7XG5pbXBvcnQgeyBpbXBvcnRLZXkgfSBmcm9tICcuLi9lbmNyeXB0aW9uLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgQXR0cmlidXRlSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgSG9va0ludm9jYXRpb25RdWV1ZUl0ZW0sXG4gIFN0ZXBJbnZvY2F0aW9uUXVldWVJdGVtLFxuICBXYWl0SW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgV29ya2Zsb3dTdXNwZW5zaW9uLFxufSBmcm9tICcuLi9nbG9iYWwuanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBHVUVTVF9DT0RFX0VYRUNVVElPTl9TQU1QTEVfTElNSVQsXG4gIHR5cGUgR3Vlc3RDb2RlRXhlY3V0aW9uLFxuICB0eXBlIEd1ZXN0Q29kZVN0YXRzLFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2hhcmRlbmVkLmpzJztcbmltcG9ydCB7XG4gIGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHMsXG4gIGRlaHlkcmF0ZVN0ZXBFcnJvcixcbn0gZnJvbSAnLi4vc2VyaWFsaXphdGlvbi5qcyc7XG5pbXBvcnQgKiBhcyBBdHRyaWJ1dGUgZnJvbSAnLi4vdGVsZW1ldHJ5L3NlbWFudGljLWNvbnZlbnRpb25zLmpzJztcbmltcG9ydCB7IGdldEFib3J0U3RyZWFtSWRGcm9tVG9rZW4gfSBmcm9tICcuLi91dGlsLmpzJztcbmltcG9ydCB7IENPTVBVVEVfSU5TVEFOQ0VfSUQgfSBmcm9tICcuL2NvbXB1dGUtaW5zdGFuY2UuanMnO1xuaW1wb3J0IHtcbiAgZ2V0TWF4SW5saW5lU3RlcHMsXG4gIGlzQmF0Y2hUcmFuc2l0aW9uc0VuYWJsZWQsXG4gIGlzUmVzaWxpZW50U3RlcERpc3BhdGNoRW5hYmxlZCxcbiAgTUFYX0JBVENIX0ZBTk9VVF9FVkVOVFMsXG4gIE1BWF9SRVNJTElFTlRfU1RFUF9JTlBVVF9CWVRFUyxcbn0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuaW1wb3J0IHtcbiAgYWJzb3JiU2tpcHBlZFNsb3RSZXBvcnQsXG4gIGFwcGVuZEV2ZW50TG9nLFxuICB0eXBlIEV2ZW50Q3JlYXRvcixcbiAgdHlwZSBMb2FkZWRFdmVudExvZyxcbiAgbWF4RXZlbnRTbG90LFxuICBxdWV1ZU1lc3NhZ2UsXG4gIHF1ZXVlTWVzc2FnZXMsXG4gIHJ1bkRpc3BhdGNoQ29udGV4dCxcbiAgc2xvdFNuYXBzaG90UGFyYW1zLFxuICBzdGVwRGlzcGF0Y2hJZGVtcG90ZW5jeUtleSxcbn0gZnJvbSAnLi9oZWxwZXJzLmpzJztcbmltcG9ydCB7IFJlcGxheVJlY292ZXJ5UmVwb3J0ZXIgfSBmcm9tICcuL3JlcGxheS1yZWNvdmVyeS1yZXBvcnRlci5qcyc7XG5pbXBvcnQgdHlwZSB7IFByZWNsYWltZWRJbmxpbmVTdGFydCB9IGZyb20gJy4vc3RlcC1leGVjdXRvci5qcyc7XG5pbXBvcnQgeyB1bnNlcmlhbGl6YWJsZVN0ZXBJbnB1dFBsYWNlaG9sZGVyIH0gZnJvbSAnLi91bnNlcmlhbGl6YWJsZS1zdGVwLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBTdXNwZW5zaW9uSGFuZGxlclBhcmFtcyB7XG4gIHN1c3BlbnNpb246IFdvcmtmbG93U3VzcGVuc2lvbjtcbiAgd29ybGQ6IFdvcmxkO1xuICBydW46IFdvcmtmbG93UnVuO1xuICBzcGFuPzogU3BhbjtcbiAgcmVxdWVzdElkPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHJ1bnRpbWUncyBsb2FkZWQgZXZlbnQgbG9nLiBFdmVyeSBldmVudCBjcmVhdGlvbiB0aGlzIHN1c3BlbnNpb24gbWFrZXNcbiAgICogbmFtZXMgdGhlIHBvc2l0aW9uIGl0IHdhcyBkZXJpdmVkIGZyb20sIHNvIGEgYmFja2VuZCB0aGF0IGhhcyByZWNvcmRlZFxuICAgKiBldmVudHMgdGhlIHJlcGxheSBkaWQgbm90IHNlZSBjYW4gcmVwb3J0IHRoZW0gYmFjayBvbiB0aGUgd3JpdGUsIG9yLCBpZlxuICAgKiBpdCB3b3VsZCByYXRoZXIgcmVmdXNlIHRoYW4gcmVwb3J0LCByZWplY3QgaXQgd2l0aCBhIDQxMi4gQSByZWplY3Rpb24gaXNcbiAgICogbm90IHJldHJpZWQgaGVyZTogdGhlIGV2ZW50J3MgY29ycmVsYXRpb24gaWQgd2FzIG1pbnRlZCBieSAqdGhpcyogcmVwbGF5J3NcbiAgICogc2VlZGVkIHNlcXVlbmNlLCBzbyByZS1jb21taXR0aW5nIGl0IGFnYWluc3QgYSBjb3JyZWN0ZWQgbG9nIHdvdWxkIHBlcnNpc3RcbiAgICogYW4gZXZlbnQgbm8gY29ycmVjdCByZXBsYXkgcHJvZHVjZXMuIFRoZSBjYWxsZXIgcmVzdGFydHMgdGhlIHJlcGxheVxuICAgKiBpbnN0ZWFkLlxuICAgKlxuICAgKiBFeHRlbmRlZCBpbiBwbGFjZSBieSB3aGF0IHRob3NlIHdyaXRlcyByZXBvcnQgYmFjayDigJQgdGhlIGV2ZW50cyBvbiBzbG90c1xuICAgKiB0aGV5IHNraXBwZWQgb3ZlciwgYW5kIChvbiB0aGUgaG9vayBjcmVhdGUpIHRoZSBpbmxpbmUgZGVsdGEgc2luY2UgaXRzXG4gICAqIGN1cnNvci4gV2hldGhlciB0aGUgbG9nIGlzIGNvbXBsZXRlIGFmdGVyd2FyZHMgaXMgYW5zd2VyZWQgYnlcbiAgICoge0BsaW5rIFN1c3BlbnNpb25IYW5kbGVyUmVzdWx0LmV2ZW50TG9nQ2FycmllZEZvcndhcmR9LlxuICAgKi9cbiAgZXZlbnRMb2c/OiBMb2FkZWRFdmVudExvZztcbiAgLyoqXG4gICAqIFR1cmJvIG1vZGUgb25seTogYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmFja2dyb3VuZGVkXG4gICAqIGBydW5fc3RhcnRlZGAgaGFzIGxhbmRlZCAodGhlIHJ1biBleGlzdHMpLiBXaGVuIHByZXNlbnQsIGV2ZXJ5IHdvcmxkIHdyaXRlXG4gICAqIHRoaXMgc3VzcGVuc2lvbiBwZXJmb3JtcyAoYGhvb2tfY3JlYXRlZGAsIGB3YWl0X2NyZWF0ZWRgLCBlYWdlciBvdmVyZmxvd1xuICAgKiBgc3RlcF9jcmVhdGVkYCwg4oCmKSBpcyBnYXRlZCBvbiBpdCBzbyB0aGUgd3JpdGUgbmV2ZXIgcmFjZXMgYWhlYWQgb2YgdGhlXG4gICAqIHJ1bidzIGNyZWF0aW9uLiBUaGUgcHVyZSBpbmxpbmUgaG90IHBhdGggZGVmZXJzIGFsbCBvZiBpdHMgc3RlcHMgYW5kIHdyaXRlc1xuICAgKiBub3RoaW5nIGhlcmUsIHNvIGl0IG5ldmVyIGF3YWl0cyB0aGlzIGJhcnJpZXIuIGB1bmRlZmluZWRgIG91dHNpZGUgdHVyYm8sXG4gICAqIHdoZXJlIGBydW5fc3RhcnRlZGAgd2FzIGFscmVhZHkgYXdhaXRlZCB1cCBmcm9udC5cbiAgICovXG4gIHJ1blJlYWR5QmFycmllcj86IFByb21pc2U8dW5rbm93bj47XG4gIC8qKiBPbmUtc2hvdCB0ZWxlbWV0cnkgcmVwb3J0ZXIsIGFjdGl2YXRlZCBvbmx5IGFmdGVyIHJlcGxheSBoYXMgcmVjb3ZlcmVkLiAqL1xuICByZXBsYXlSZWNvdmVyeVJlcG9ydGVyPzogUmVwbGF5UmVjb3ZlcnlSZXBvcnRlcjtcbiAgLyoqXG4gICAqIFJlc2lsaWVudCBzdGVwIGRpc3BhdGNoOiB3aGVuIHByb3ZpZGVkIChhbmQgdGhlIHBlci1zdGVwIGVsaWdpYmlsaXR5IGdhdGVzXG4gICAqIHBhc3MsIHNlZSB0aGUgc3RlcCBvcHMgYmVsb3cpLCBlYWNoIG5ld2x5IGNyZWF0ZWQgbm9uLWlubGluZSBzdGVwJ3NcbiAgICogYHN0ZXBfY3JlYXRlZGAgd3JpdGUgaXMgcGFyYWxsZWxpemVkIHdpdGggaXRzIHN0ZXAtZXhlY3V0aW9uIHF1ZXVlXG4gICAqIHB1Ymxpc2gsIGFuZCB0aGUgcXVldWUgbWVzc2FnZSBjYXJyaWVzIHRoZSBzZXJpYWxpemVkIHN0ZXAgaW5wdXRcbiAgICogKGBzdGVwSW5wdXRgKSBzbyB0aGUgY29uc3VtZXIgY2FuIGlkZW1wb3RlbnRseSByZS1lbnN1cmUgdGhlIGV2ZW50IGlmIHRoZVxuICAgKiBkaXJlY3Qgd3JpdGUgZmFpbGVkIHRyYW5zaWVudGx5LiBTdGVwcyBxdWV1ZWQgdGhpcyB3YXkgYXJlIHJlcG9ydGVkIGluXG4gICAqIHtAbGluayBTdXNwZW5zaW9uSGFuZGxlclJlc3VsdC5xdWV1ZWRTdGVwQ29ycmVsYXRpb25JZHN9IHNvIHRoZSBjYWxsZXJcbiAgICogc2tpcHMgdGhlbSBpbiBpdHMgb3duIGRpc3BhdGNoIHBhc3MuIE9taXR0ZWQgYnkgY2FsbGVycyB0aGF0IG11c3Qgbm90XG4gICAqIHF1ZXVlICh0ZXJtaW5hbCBkcmFpbiwgdGVzdHMpOyBjcmVhdGVzIHRoZW4gYmVoYXZlIGV4YWN0bHkgYXMgYmVmb3JlLlxuICAgKi9cbiAgc3RlcERpc3BhdGNoPzoge1xuICAgIC8qKiBUaGUgdW5pZmllZCB3b3JrZmxvdyBxdWV1ZSB0aGlzIHJ1bidzIHN0ZXAgbWVzc2FnZXMgYXJlIHB1Ymxpc2hlZCB0by4gKi9cbiAgICBxdWV1ZU5hbWU6IFZhbGlkUXVldWVOYW1lO1xuICAgIC8qKlxuICAgICAqIExhemlseSByZXNvbHZlcyB0aGUgdHJhY2UgY2FycmllciB0byBzdGFtcCBvbiB0aGUgc3RlcCBtZXNzYWdlcy5cbiAgICAgKiBDYWxsZWQgYXQgbW9zdCBvbmNlIHBlciBzdXNwZW5zaW9uIChtZW1vaXplZCBoZXJlKS5cbiAgICAgKi9cbiAgICBnZXRUcmFjZUNhcnJpZXI6ICgpID0+IFByb21pc2U8VHJhY2VDYXJyaWVyPjtcbiAgfTtcbiAgLyoqXG4gICAqIElubGluZSBzdGVwIG93bmVyc2hpcDogdGhlIHF1ZXVlIG1lc3NhZ2UgSUQgb2YgdGhlIGludm9jYXRpb24gdGhpc1xuICAgKiBzdXNwZW5zaW9uIHJ1bnMgaW4gKHRoZSBxdWV1ZSBoYW5kbGVyJ3MgbWV0YSkuIFdoZW4gcHJlc2VudCBBTkQgdGhlXG4gICAqIGJhdGNoZWQgZmFuLW91dCBlbmdhZ2VzLCB0aGUgbGF6eS1pbmxpbmUgc3RlcHMnIGRlZmVycmVkIHdyaXRlcyBhcmVcbiAgICogZm9sZGVkIGludG8gdGhlIGJhdGNoIGFzIGBzdGVwX2NyZWF0ZWRgICsgYHN0ZXBfc3RhcnRlZGAgcGFpcnMgKHRoZVxuICAgKiBzdGFydGVkIHJvdyBzdGFtcGVkIHdpdGggdGhpcyBJRCwgZXhhY3RseSBsaWtlIHRoZSBsYXp5IGNsYWltIGl0XG4gICAqIHJlcGxhY2VzKSwgcHJlLWNsYWltaW5nIHRoZSBzdGVwcyB0aGUgY2FsbGVyIGlzIGFib3V0IHRvIHJ1biBpbmxpbmUuIFNlZVxuICAgKiB7QGxpbmsgU3VzcGVuc2lvbkhhbmRsZXJSZXN1bHQuaW5saW5lQ2xhaW1zfS4gQ2FsbGVycyB0aGF0IG5ldmVyXG4gICAqIGlubGluZS1leGVjdXRlICh0ZXJtaW5hbCBkcmFpbikgb21pdCBpdCwga2VlcGluZyB0aGVpciBsYXp5IHN0ZXBzIG9uIHRoZVxuICAgKiBwbGFpbiBkZWZlcnJlZCBwYXRoLlxuICAgKi9cbiAgb3duZXJNZXNzYWdlSWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBMZXRzIHRoZSBiYXRjaGVkIGZhbi1vdXQgcmV0dXJuIGJlZm9yZSBldmVyeSBjaHVuayBoYXMgY29tbWl0dGVkOiBvbmx5XG4gICAqIHRoZSBjaHVuayBjYXJyeWluZyB0aGUgcHJlLWNsYWltZWQgaW5saW5lIHBhaXJzIGdhdGVzIHRoZSBoYW5kbGVyJ3NcbiAgICogcmV0dXJuIChpdHMgY2xhaW1zIGFyZSB3aGF0IHRoZSBjYWxsZXIgc3RhcnRzIGJvZGllcyBmcm9tKSwgd2hpbGUgdGhlXG4gICAqIHRyYWlsaW5nIGNodW5rcycgY29tbWl0cyAoYW5kIGV2ZXJ5IGNodW5rJ3MgaW4tZmx1c2ggc3RlcC1tZXNzYWdlXG4gICAqIHB1Ymxpc2hlcykgcmlkZSB7QGxpbmsgU3VzcGVuc2lvbkhhbmRsZXJSZXN1bHQuZGVmZXJyZWRCYXRjaFdvcmt9LiBBXG4gICAqIGNhbGxlciB0aGF0IG9wdHMgaW4gTVVTVCBhd2FpdCB0aGF0IHByb21pc2UgYmVmb3JlIGFja2luZyBpdHMgZGVsaXZlcnk6XG4gICAqIHRoZSBkdXJhYmlsaXR5IGNvbnRyYWN0IChcImV2ZXJ5IGNyZWF0ZSBkdXJhYmxlIGJlZm9yZSBhY2tcIikgbW92ZXMgZnJvbVxuICAgKiB0aGUgaGFuZGxlcidzIHJldHVybiB0byB0aGF0IGpvaW4sIGFuZCBub3RoaW5nIGVsc2UgcmUtZHJpdmVzIGEgbG9zdFxuICAgKiB0cmFpbGluZyBjaHVuay4gQ2FsbGVycyB0aGF0IGRvbid0IG9wdCBpbiAodGVybWluYWwgZHJhaW4sIGRlZmF1bHQpXG4gICAqIGtlZXAgdGhlIGV2ZXJ5dGhpbmctZHVyYWJsZS1hdC1yZXR1cm4gYmVoYXZpb3IuXG4gICAqL1xuICBhbGxvd0RlZmVycmVkQmF0Y2hXb3JrPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgaGFuZGxpbmcgYSBzdXNwZW5zaW9uLiBSZXR1cm5zIHBlbmRpbmcgc3RlcCBpdGVtcyBzbyB0aGUgY2FsbGVyXG4gKiBjYW4gZGVjaWRlIHdoaWNoIHRvIGV4ZWN1dGUgaW5saW5lIHZzIHF1ZXVlIHRvIGJhY2tncm91bmQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3VzcGVuc2lvbkhhbmRsZXJSZXN1bHQge1xuICAvKiogUGVuZGluZyBzdGVwIGl0ZW1zIHdpdGggZXZlbnRzIGNyZWF0ZWQgYnV0IE5PVCBxdWV1ZWQgKi9cbiAgcGVuZGluZ1N0ZXBzOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbVtdO1xuICAvKipcbiAgICogQ29ycmVsYXRpb24gSURzIGZvciB3aGljaCB0aGlzIHN1c3BlbnNpb24gY2FsbCBhY3R1YWxseSB3cm90ZSB0aGVcbiAgICogc3RlcF9jcmVhdGVkIGV2ZW50IChhcyBvcHBvc2VkIHRvIGNhdGNoaW5nIEVudGl0eUNvbmZsaWN0RXJyb3IgYmVjYXVzZVxuICAgKiBhIGNvbmN1cnJlbnQgaGFuZGxlciB3cm90ZSBpdCBmaXJzdCkuIE9ubHkgdGhlIGhhbmRsZXIgdGhhdCB3cm90ZSB0aGVcbiAgICogc3RlcF9jcmVhdGVkIGV2ZW50IHNob3VsZCBxdWV1ZSAvIGlubGluZS1leGVjdXRlIHRoZSBzdGVwOyB0aGlzXG4gICAqIGd1YXJhbnRlZXMgYSBzaW5nbGUgb3duZXIgcGVyIHN0ZXAsIGV2ZW4gd2hlbiBtdWx0aXBsZSBoYW5kbGVycyByYWNlXG4gICAqIGludG8gdGhlIHNhbWUgYmF0Y2ggYm91bmRhcnkuXG4gICAqL1xuICBjcmVhdGVkU3RlcENvcnJlbGF0aW9uSWRzOiBTZXQ8c3RyaW5nPjtcbiAgLyoqXG4gICAqIENvcnJlbGF0aW9uIElEcyBvZiBzdGVwcyB3aG9zZSBhcmd1bWVudHMgZmFpbGVkIHRvIHNlcmlhbGl6ZS4gRWFjaCB3YXNcbiAgICogZmluYWxpemVkIGhlcmUgYXMgYHN0ZXBfY3JlYXRlZGAgKHdpdGggYSBwbGFjZWhvbGRlciBpbnB1dDsgdGhlIHJlYWxcbiAgICogaW5wdXQgaXMgcHJlY2lzZWx5IHdoYXQgcmVmdXNlZCB0byBzZXJpYWxpemUpIGZvbGxvd2VkIGJ5IGBzdGVwX2ZhaWxlZGBcbiAgICogY2FycnlpbmcgdGhlIFNlcmlhbGl6YXRpb25FcnJvciwgc28gdGhlIG5leHQgcmVwbGF5IHJlamVjdHMgdGhlIHN0ZXAnc1xuICAgKiBwcm9taXNlIGFuZCBhIHRyeS9jYXRjaCBhcm91bmQgdGhlIHN0ZXAgY2FsbCBvYnNlcnZlcyB0aGUgZXJyb3IsXG4gICAqIGV4YWN0bHkgbGlrZSBhIHN0ZXAtYm9keSBmYWlsdXJlLiBObyBzdGVwLWV4ZWN1dGlvbiBtZXNzYWdlIGlzXG4gICAqIGRpc3BhdGNoZWQgZm9yIHRoZXNlLCBzbyB0aGUgY2FsbGVyIE1VU1QgZm9yY2UgYW4gaW4tcHJvY2VzcyByZXBsYXk6XG4gICAqIHdoZW4gdGhlIGZhaWxlZCBzdGVwIHdhcyB0aGUgb25seSBwZW5kaW5nIHdvcmssIG5vdGhpbmcgZWxzZSB3aWxsIGV2ZXJcbiAgICogcmUtaW52b2tlIHRoZSBydW4gdG8gb2JzZXJ2ZSB0aGUgdGVybWluYWwgZXZlbnQuXG4gICAqL1xuICBmYWlsZWRTdGVwQ29ycmVsYXRpb25JZHM6IFNldDxzdHJpbmc+O1xuICAvKipcbiAgICogQ29ycmVsYXRpb24gSURzIG9mIHN0ZXBzIHRoaXMgc3VzcGVuc2lvbiBjYWxsIGFscmVhZHkgcHVibGlzaGVkXG4gICAqIHN0ZXAtZXhlY3V0aW9uIHF1ZXVlIG1lc3NhZ2VzIGZvciwgdmlhIHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoICh0aGVcbiAgICogYHN0ZXBfY3JlYXRlZGAgd3JpdGUgcGFyYWxsZWxpemVkIHdpdGggYSBgc3RlcElucHV0YC1jYXJyeWluZyBxdWV1ZVxuICAgKiBwdWJsaXNoKS4gVGhlIGNhbGxlciBNVVNUIE5PVCBkaXNwYXRjaCB0aGVzZSBhZ2FpbjogdGhlIG1lc3NhZ2UgaXNcbiAgICogYWxyZWFkeSBvdXQgKGEgZHVwbGljYXRlIHdvdWxkIGJlIGRlZHVwZWQgYnkgaXRzIGlkZW1wb3RlbmN5IGtleSwgYnV0XG4gICAqIGNvc3RzIGEgd2FzdGVkIHJvdW5kLXRyaXApLiBFbXB0eSB3aGVuIHtAbGluayBTdXNwZW5zaW9uSGFuZGxlclBhcmFtcy5zdGVwRGlzcGF0Y2h9XG4gICAqIHdhcyBub3QgcHJvdmlkZWQgb3Igbm8gc3RlcCB3YXMgZWxpZ2libGUuXG4gICAqL1xuICBxdWV1ZWRTdGVwQ29ycmVsYXRpb25JZHM6IFNldDxzdHJpbmc+O1xuICAvKipcbiAgICogSG93IG1hbnkgZXZlbnRzIHRoaXMgcGhhc2UncyB3cml0ZXMgcmVwb3J0ZWQgYmFjayBhcyBvY2N1cHlpbmcgc2xvdHMgdGhleVxuICAgKiBza2lwcGVkIG92ZXIsIGFscmVhZHkgbWVyZ2VkIGludG8gdGhlIGNhbGxlcidzIGBldmVudExvZy5ldmVudHNgLiBOb256ZXJvXG4gICAqIG1lYW5zIHRoZSBhcnJheSB3YXMgcmVvcmRlcmVkIHRvIHJlc3RvcmUgc2xvdCBvcmRlciwgc28gYW55IGluZGV4IHRoZVxuICAgKiBjYWxsZXIgY2FjaGVkIGludG8gaXQgKHBheWxvYWQgcHJld2FybSBzY2FuIHBvc2l0aW9uKSBpcyBzdGFsZS5cbiAgICovXG4gIHJlcG9ydGVkRXZlbnRDb3VudDogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIHN0ZXBzIHdob3NlIGBzdGVwX2NyZWF0ZWRgIHdyaXRlcyB3ZXJlIGludGVudGlvbmFsbHkgZGVmZXJyZWQgc28gdGhlXG4gICAqIGNhbGxlciBjYW4gcnVuIHRoZW0gaW5saW5lIHZpYSBsYXp5IGBzdGVwX3N0YXJ0ZWRgIGV2ZW50cyAod2hpY2ggY3JlYXRlXG4gICAqIHRoZSBzdGVwIG9uIHRoZSBmbHkpLCBzYXZpbmcgb25lIHdvcmxkIHJvdW5kLXRyaXAgcGVyIGlubGluZSBzdGVwLiBVcCB0b1xuICAgKiBgZ2V0TWF4SW5saW5lU3RlcHMoKWAgc3RlcHMgYXJlIGRlZmVycmVkOyB0aGUgY2FsbGVyIHJ1bnMgdGhlbSBpbmxpbmUgaW5cbiAgICogcGFyYWxsZWwgYW5kIHF1ZXVlcyB0aGUgcmVzdC4gRW1wdHkgd2hlbiBubyBzdGVwIHdhcyBkZWZlcnJlZCAobm90aGluZ1xuICAgKiBwZW5kaW5nLCBvciBhIGBob29rLmdldENvbmZsaWN0KClgIGF3YWl0ZXIgaXMgcHJlc2VudCBzbyBub3RoaW5nIGlzXG4gICAqIGV4ZWN1dGVkIGlubGluZSkuIFRoZSBjYWxsZXIgcGFzc2VzIGVhY2ggYGRlaHlkcmF0ZWRJbnB1dGAgc3RyYWlnaHQgdG9cbiAgICogYGV4ZWN1dGVTdGVwYCwgd2hpY2ggc2VuZHMgaXQgYXMgdGhlIGBzdGVwX3N0YXJ0ZWRgIHBheWxvYWQuIFRoZSBhdG9taWNcbiAgICogY3JlYXRlLWNsYWltIGluc2lkZSBlYWNoIGBzdGVwX3N0YXJ0ZWRgIGlzIHRoZSBleGFjdGx5LW9uZS1vd25lciBnYXRlIHRoYXRcbiAgICogdGhlIHN0YW5kYWxvbmUgYHN0ZXBfY3JlYXRlZGAgcHJvdmlkZWQgYmVmb3JlOiB0aGUgbG9zZXIgb2YgdGhlIHJhY2UgZ2V0c1xuICAgKiBgRW50aXR5Q29uZmxpY3RFcnJvcmAg4oaSIGBza2lwcGVkYCBhbmQgZG9lcyBub3QgcnVuIHRoZSBib2R5LlxuICAgKi9cbiAgbGF6eUlubGluZVN0ZXBzOiBBcnJheTx7XG4gICAgY29ycmVsYXRpb25JZDogc3RyaW5nO1xuICAgIHN0ZXBOYW1lOiBzdHJpbmc7XG4gICAgZGVoeWRyYXRlZElucHV0OiBTZXJpYWxpemVkRGF0YTtcbiAgfT47XG4gIC8qKlxuICAgKiBQcmUtY2xhaW1lZCBpbmxpbmUgc3RhcnRzLCBieSBjb3JyZWxhdGlvbiBpZDogdGhlIHBlci1zdGVwIHZlcmRpY3RzIG9mXG4gICAqIHRoZSBgc3RlcF9jcmVhdGVkYCArIGBzdGVwX3N0YXJ0ZWRgIHBhaXJzIHRoZSBiYXRjaGVkIGZhbi1vdXQgY29tbWl0dGVkXG4gICAqIGZvciB0aGUgbGF6eS1pbmxpbmUgc3RlcHMuIEEgc3RlcCB3aXRoIGFuIGVudHJ5IGhlcmUgaXMgcGFzc2VkIHRvXG4gICAqIGBleGVjdXRlU3RlcGAgYXMgYHByZWNsYWltZWRTdGFydGAgSU5TVEVBRCBvZiBgbGF6eVN0ZXBJbnB1dGA6IGl0c1xuICAgKiBpbnB1dCBhbHJlYWR5IHJvZGUgdGhlIHBhaXIsIGFuZCB0aGUgY2xhaW0gaXMgc2V0dGxlZDogYG93bmVkOiB0cnVlYFxuICAgKiBjYXJyaWVzIHRoZSBzdGFydGVkIGF0dGVtcHQtMSBlbnRpdHkgKGlucHV0IHJlLWF0dGFjaGVkKSBzbyB0aGUgYm9keVxuICAgKiBydW5zIHN0cmFpZ2h0IG9mZiB0aGUgYmF0Y2ggY29tbWl0IHdpdGggbm8gc3RhcnQgd3JpdGUgb2YgaXRzIG93bjtcbiAgICogYG93bmVkOiBmYWxzZWAgbG9zdCB0aGUgcGFpcidzIGF0b21pYyBjcmVhdGUtY2xhaW0gdG8gYSBjb25jdXJyZW50XG4gICAqIHdyaXRlciwgYW5kIGV4ZWN1dGVTdGVwIHJldHVybnMgYHNraXBwZWRgIHdpdGhvdXQgcnVubmluZyB0aGUgYm9keSxcbiAgICogdGhlIHNhbWUgb3V0Y29tZSBhcyBsb3NpbmcgdGhlIGxhenkgY2xhaW0uIEVtcHR5IHdoZW5ldmVyIHRoZSBmb2xkIGRpZFxuICAgKiBub3QgZW5nYWdlIChiYXRjaGluZyBvZmYsIG5vIGBvd25lck1lc3NhZ2VJZGAsIG9yIHRoZSBsb25lLWlubGluZSBjYXNlLFxuICAgKiB3aGljaCBrZWVwcyB0aGUgb3B0aW1pc3RpYyBsYXp5IHBhdGggYW5kIGl0cyBjbGFpbS9ib2R5IG92ZXJsYXApLlxuICAgKlxuICAgKiBDcmFzaCB3aW5kb3c6IHRoZSBwYWlyIGNvbW1pdHMgYmVmb3JlIHRoZSBjYWxsZXIgcnVucyB0aGUgYm9keSwgc28gYVxuICAgKiBjcmFzaCBiZXR3ZWVuIHRoZW0gbGVhdmVzIGEgc3RhcnRlZCBzdGVwIHN0YW1wZWQgd2l0aCB0aGlzIG1lc3NhZ2Unc1xuICAgKiBJRC4gUmVkZWxpdmVyeSBvZiB0aGUgc2FtZSBtZXNzYWdlIHJlLWV4ZWN1dGVzIGl0IHZpYSB0aGUgb3duZWQtcmVjb3ZlcnlcbiAgICogcGF0aCwgdGhlIGV4YWN0IG1hY2hpbmVyeSB0aGUgbGF6eSBjbGFpbSdzIGNyYXNoIHdpbmRvdyBhbHJlYWR5IHVzZXMuXG4gICAqL1xuICBpbmxpbmVDbGFpbXM6IE1hcDxzdHJpbmcsIFByZWNsYWltZWRJbmxpbmVTdGFydD47XG4gIC8qKlxuICAgKiBUaGUgYmF0Y2hlZCBmYW4tb3V0J3MgZGVmZXJyZWQgd29yaywgcHJlc2VudCBvbmx5IHdoZW4gdGhlIGNhbGxlciBvcHRlZFxuICAgKiBpbiB2aWEge0BsaW5rIFN1c3BlbnNpb25IYW5kbGVyUGFyYW1zLmFsbG93RGVmZXJyZWRCYXRjaFdvcmt9IGFuZFxuICAgKiB0cmFpbGluZyB3b3JrIGV4aXN0czogdGhlIGNvbW1pdHMgb2YgZXZlcnkgY2h1bmsgZXhjZXB0IHRoZSBwYWlyIGNodW5rLFxuICAgKiBwbHVzIGV2ZXJ5IGNodW5rJ3Mgc3RlcC1tZXNzYWdlIHB1Ymxpc2hlcyAoZWFjaCBjaGFpbmVkIG9uIElUUyBPV05cbiAgICogY2h1bmsncyBjb21taXQsIHNvIHB1Ymxpc2gtYWZ0ZXItY3JlYXRlIGhvbGRzIHBlciBzdGVwKS4gVGhlIGNhbGxlclxuICAgKiBNVVNUIGF3YWl0IGl0IGJlZm9yZSBhY2tpbmc6IGEgcmVqZWN0aW9uIGhlcmUgaXMgYSBmYWlsZWQgc3VzcGVuc2lvblxuICAgKiB3cml0ZSBhbmQgZmFpbHMgdGhlIGRlbGl2ZXJ5IGV4YWN0bHkgYXMgaXQgd291bGQgaGF2ZSBhdCB0aGUgaGFuZGxlcidzXG4gICAqIHJldHVybi4gU3RlcHMgd2hvc2UgbWVzc2FnZXMgdGhpcyB3b3JrIHB1Ymxpc2hlcyBhcmUgYWxyZWFkeSBpblxuICAgKiB7QGxpbmsgcXVldWVkU3RlcENvcnJlbGF0aW9uSWRzfSBhdCByZXR1cm4gdGltZS5cbiAgICovXG4gIGRlZmVycmVkQmF0Y2hXb3JrPzogUHJvbWlzZTx2b2lkPjtcbiAgLyoqXG4gICAqIFRoZSBzb29uZXN0IHBlbmRpbmcgd2FpdCwgaWYgYW55OiBzZWNvbmRzIHVudGlsIGl0IGVsYXBzZXMgYW5kIHRoZVxuICAgKiBjb3JyZWxhdGlvbklkIG9mIHRoZSB3YWl0IHRoYXQgcHJvZHVjZWQgdGhhdCB0aW1lb3V0LiBUaGVcbiAgICogY29ycmVsYXRpb25JZCBzZWVkcyB0aGUgaWRlbXBvdGVuY3kga2V5IGZvciB0aGUgd2FpdC1jb250aW51YXRpb25cbiAgICogcXVldWUgbWVzc2FnZSBzbyB0aGF0IHJlcGVhdGVkIHN1c3BlbnNpb24gcGFzc2VzIG92ZXIgdGhlIHNhbWVcbiAgICogcGVuZGluZyB3YWl0IGNvbGxhcHNlIGludG8gYSBzaW5nbGUgZGVsYXllZCBjb250aW51YXRpb24uXG4gICAqL1xuICB3YWl0VGltZW91dD86IHsgc2Vjb25kczogbnVtYmVyOyBjb3JyZWxhdGlvbklkOiBzdHJpbmcgfTtcbiAgLyoqXG4gICAqIFdoZXRoZXIgYSBob29rIGNyZWF0ZSBjb21taXR0ZWQgYSBgaG9va19jb25mbGljdGAg4oCUIHRoZSB0b2tlbiB3YXMgYWxyZWFkeVxuICAgKiBjbGFpbWVkLCBzbyB0aGlzIHJ1bidzIGhvb2sgd2FzIG5ldmVyIGNyZWF0ZWQgYW5kIHRoZSB3b3JrZmxvdyBtdXN0XG4gICAqIG9ic2VydmUgdGhlIGNvbmZsaWN0IGJlZm9yZSBhbnl0aGluZyBlbHNlIHRoaXMgc3VzcGVuc2lvbiBzY2hlZHVsZWQgcnVucy5cbiAgICogVGhlIGNhbGxlciBhbnN3ZXJzIGl0IGJ5IGFkdmFuY2luZyB0aGUgd29ya2Zsb3cgb3ZlciB0aGUgY29tbWl0dGVkIGV2ZW50LlxuICAgKi9cbiAgaGFzSG9va0NvbmZsaWN0OiBib29sZWFuO1xuICAvKiogV2hldGhlciBhIGBob29rLmdldENvbmZsaWN0KClgIGF3YWl0ZXIgbmVlZHMgdGhlIHdvcmtmbG93IHRvIGNvbnRpbnVlIGltbWVkaWF0ZWx5ICovXG4gIGhhc0F3YWl0ZWRIb29rQ3JlYXRpb246IGJvb2xlYW47XG4gIC8qKlxuICAgKiBDb3JyZWxhdGlvbiBpZHMgb2YgdGhlIGhvb2tzIHRoaXMgc3VzcGVuc2lvbiBjb21taXR0ZWQgYSBgaG9va19jcmVhdGVkYFxuICAgKiBmb3Igd2hpbGUgYSBgaG9vay5nZXRDb25mbGljdCgpYCBhd2FpdGVyIHdhcyB3YWl0aW5nIG9uIGl0IOKAlCB0aGUgZXZlbnRzXG4gICAqIHRoYXQgcmVzb2x2ZSB0aG9zZSBhd2FpdGVycyBvbiB0aGUgbmV4dCBwYXNzLiBFbXB0eSBleGFjdGx5IHdoZW5cbiAgICoge0BsaW5rIGhhc0F3YWl0ZWRIb29rQ3JlYXRpb259IGlzIGZhbHNlLlxuICAgKlxuICAgKiBSZXBvcnRlZCBieSBpZCwgbm90IGp1c3QgY291bnRlZCwgc28gYSBjYWxsZXIgdGhhdCBjb250aW51ZXMgaW4gdGhpc1xuICAgKiBwcm9jZXNzIGNhbiB0ZWxsIGEgY29udGludWF0aW9uIHRoYXQgZ290IHNvbWV3aGVyZSBmcm9tIG9uZSB0aGF0IGlzXG4gICAqIHJlcGVhdGluZzogYSB3b3JrZmxvdyBtYXkgY3JlYXRlIG9uZSBhd2FpdGVkIGhvb2sgYWZ0ZXIgYW5vdGhlciwgYW5kIGVhY2hcbiAgICogbmV3IGlkIGlzIGEgcGFzcyB0aGF0IG1hZGUgcHJvZ3Jlc3MsIHdoaWxlIHRoZSBzYW1lIGlkIGNvbWluZyBiYWNrIG1lYW5zXG4gICAqIHRoZSBwYXNzIHJhbiBvdmVyIGEgbG9nIHRoYXQgc3RpbGwgZGlkIG5vdCBob2xkIGl0cyBldmVudCBhbmQgY29udGludWluZ1xuICAgKiBhZ2FpbiBjYW5ub3QgY2hhbmdlIHRoYXQuXG4gICAqL1xuICBhd2FpdGVkSG9va0NvcnJlbGF0aW9uSWRzOiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIENvcnJlbGF0aW9uIGlkcyBvZiB0aGUgaG9va3Mgd2hvc2UgY3JlYXRlIGNvbW1pdHRlZCBhIGBob29rX2NvbmZsaWN0YC5cbiAgICogRW1wdHkgZXhhY3RseSB3aGVuIHtAbGluayBoYXNIb29rQ29uZmxpY3R9IGlzIGZhbHNlLlxuICAgKlxuICAgKiBCeSBpZCBmb3IgdGhlIHNhbWUgcmVhc29uIGFzIHtAbGluayBhd2FpdGVkSG9va0NvcnJlbGF0aW9uSWRzfSwgYW5kXG4gICAqIGFnYWluc3QgdGhlIHNhbWUgaGF6YXJkOiBhIGNvbmZsaWN0IGlzIHJlc29sdmVkIGJ5IHRoZSBgaG9va19jb25mbGljdGBcbiAgICogdGhpcyBzdXNwZW5zaW9uIGNvbW1pdHRlZCwgYW5kIHVudGlsIHRoZSB3b3JrZmxvdyBvYnNlcnZlcyBpdCB0aGUgaG9va1xuICAgKiBzdGF5cyBpbiB0aGUgaW52b2NhdGlvbnMgcXVldWUgYW5kIHRoZSBuZXh0IHBhc3Mgd3JpdGVzIHRoZSBjcmVhdGUgYWdhaW4uXG4gICAqIEEgZnJlc2ggaWQgaXMgcHJvZ3Jlc3M7IHRoZSBzYW1lIGlkIGNvbWluZyBiYWNrIGlzIGEgcGFzcyB0aGF0IHJhbiBvdmVyIGFcbiAgICogbG9nIHdoaWNoIHN0aWxsIGRpZCBub3QgaG9sZCB0aGUgZXZlbnQsIHNvIGNvbnRpbnVpbmcgYWdhaW4gY2Fubm90IGNoYW5nZVxuICAgKiB0aGF0LlxuICAgKi9cbiAgaG9va0NvbmZsaWN0Q29ycmVsYXRpb25JZHM6IHN0cmluZ1tdO1xuICAvKipcbiAgICogV2hldGhlciB0aGUgY2FsbGVyJ3MgYGV2ZW50TG9nYCBub3cgaG9sZHMgZXZlcnkgZXZlbnQgdGhpcyBzdXNwZW5zaW9uXG4gICAqIGNvbW1pdHRlZCwgc28gYSBjYWxsZXIgdGhhdCBjb250aW51ZXMgaW4gdGhpcyBwcm9jZXNzIGNhbiByZXBsYXkg4oCUIG9yXG4gICAqIHJlc3VtZSBhIHJldGFpbmVkIFZNIOKAlCBzdHJhaWdodCBvZmYgaXQgd2l0aCBubyByZWFkLlxuICAgKlxuICAgKiBUcnVlIG9ubHkgd2hlbiB0aGUgaG9vayBjcmVhdGUncyBpbmxpbmUgZGVsdGEgY2FtZSBiYWNrIGNvbXBsZXRlIGFuZCB3YXNcbiAgICogZm9sZGVkIGluIChzZWUgYGhvb2tEZWx0YUN1cnNvcmAgYmVsb3cpLCBhbmQgbm90aGluZyBlbHNlIGluIHRoaXNcbiAgICogc3VzcGVuc2lvbiB3cm90ZSBhbiBldmVudC4gRmFsc2Ugd2hlbmV2ZXIgYSByZWFkIGlzIG5lZWRlZCBmaXJzdDogbm9cbiAgICogZGVsdGEgd2FzIGFza2VkIGZvciBvciByZXR1cm5lZCwgaXQgd2FzIHRydW5jYXRlZCwgb3IgYSBzdGVwIC8gd2FpdCAvXG4gICAqIGF0dHJpYnV0ZSAvIGFib3J0IHdyaXRlIGxhbmRlZCBhYm92ZSBpdCBhbmQgaXMgdGhlcmVmb3JlIG5vdCBpbiBpdC5cbiAgICpcbiAgICogSW5kaWZmZXJlbnQgdG8gd2hpY2ggZXZlbnQgdGhlIGNyZWF0ZSBjb21taXR0ZWQ6IHRoZSBkZWx0YSBpcyB0aGUgc2xpY2VcbiAgICogb2YgdGhlIGxvZyBhZnRlciB0aGUgY2FsbGVyJ3MgY3Vyc29yIGVpdGhlciB3YXksIHNvIGl0IGNhcnJpZXMgYVxuICAgKiBgaG9va19jb25mbGljdGAgZXhhY3RseSBhcyBpdCBjYXJyaWVzIGEgYGhvb2tfY3JlYXRlZGAuXG4gICAqL1xuICBldmVudExvZ0NhcnJpZWRGb3J3YXJkOiBib29sZWFuO1xuICAvKiogV2hldGhlciBuYXRpdmUgd29ya2Zsb3cgYXR0cmlidXRlIGV2ZW50cyB3ZXJlIHdyaXR0ZW4gZm9yIHJlcGxheS4gKi9cbiAgaGFzQXR0cmlidXRlRXZlbnRzOiBib29sZWFuO1xuICAvKipcbiAgICogV2hldGhlciB0aGlzIHN1c3BlbnNpb24gY3JlYXRlZCBhbnkgaG9vayAoYGhvb2tfY3JlYXRlZGApIGV2ZW50cy4gVW5saWtlXG4gICAqIGBoYXNIb29rQ29uZmxpY3RgIC8gYGhhc0F3YWl0ZWRIb29rQ3JlYXRpb25gLCB0aGlzIGlzIHRydWUgZXZlbiBmb3IgYSBwbGFpblxuICAgKiBmaXJlLWFuZC1mb3JnZXQgaG9vayB3aXRoIG5vIGNvbmZsaWN0IGFuZCBubyBhd2FpdGVyLiBUdXJibyBtb2RlIHVzZXMgaXQgdG9cbiAgICogZGV0ZWN0IFwiYSBob29rIHdhcyBjcmVhdGVkIHRoaXMgc3VzcGVuc2lvblwiIGFuZCBzdG9wIGZvcmNpbmcgb3B0aW1pc3RpY1xuICAgKiBpbmxpbmUgc3RhcnQgKGEgaG9vayBpbnRyb2R1Y2VzIGxhdGVyIHJlc3VtZSBpbnZvY2F0aW9ucyB0aGF0IGNvdWxkIHJhY2UpLlxuICAgKi9cbiAgaGFzSG9va0V2ZW50czogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdhbGwtY2xvY2sgbXMgc3BlbnQgY29tbWl0dGluZyB0aGlzIHN1c3BlbnNpb24ncyBgaG9va19jcmVhdGVkYCBldmVudHNcbiAgICogKDAgd2hlbiBpdCBjcmVhdGVkIG5vbmUpLiBUaGUgY2FsbGVyIGFjY3VtdWxhdGVzIHRoaXMgYWNyb3NzIGl0ZXJhdGlvbnNcbiAgICogYW5kIHN1YnRyYWN0cyBpdCBmcm9tIHRoZSBUVEZTIGxhdGVuY3kgbWVhc3VyZW1lbnQsIHNvIHRpbWUgc3BlbnRcbiAgICogZHVyYWJseSBjcmVhdGluZyB0aGUgdXNlcidzIGhvb2tzIGRvZXNuJ3QgY291bnQgYXMgcnVudGltZSBvdmVyaGVhZC5cbiAgICovXG4gIGhvb2tDcmVhdGlvbk1zOiBudW1iZXI7XG4gIC8qKiBFeGFjdCBudW1iZXIgb2Ygd29ya2Zsb3ctY29kZSBleGVjdXRpb25zIG9ic2VydmVkIGR1cmluZyBzZXJpYWxpemF0aW9uLiAqL1xuICBzZXJpYWxpemF0aW9uQmxvY2tlckNvdW50OiBudW1iZXI7XG4gIC8qKiBCb3VuZGVkIHNhbXBsZSB1c2VkIG9ubHkgZm9yIHJldGVudGlvbiBkaWFnbm9zdGljcy4gKi9cbiAgc2VyaWFsaXphdGlvbkJsb2NrZXJzOiBTdXNwZW5zaW9uU2VyaWFsaXphdGlvbkJsb2NrZXJbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdXNwZW5zaW9uU2VyaWFsaXphdGlvbkJsb2NrZXIgZXh0ZW5kcyBHdWVzdENvZGVFeGVjdXRpb24ge1xuICBzb3VyY2U6ICdzdGVwX2lucHV0JyB8ICdob29rX21ldGFkYXRhJyB8ICdob29rX2Fib3J0JztcbiAgY29ycmVsYXRpb25JZDogc3RyaW5nO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjcmVhdGVIb29rRXZlbnQoe1xuICBydW5JZCxcbiAgaG9va0V2ZW50LFxuICBxdWV1ZUl0ZW0sXG4gIHJlcXVlc3RJZCxcbiAgc2luY2VDdXJzb3IsXG4gIGNyZWF0ZUV2ZW50LFxufToge1xuICBydW5JZDogc3RyaW5nO1xuICBob29rRXZlbnQ6IENyZWF0ZUV2ZW50UmVxdWVzdDtcbiAgcXVldWVJdGVtOiBIb29rSW52b2NhdGlvblF1ZXVlSXRlbTtcbiAgcmVxdWVzdElkPzogc3RyaW5nO1xuICAvKipcbiAgICogQ3Vyc29yIHRvIGFzayB0aGUgV29ybGQgZm9yIHRoZSBldmVudC1sb2cgZGVsdGEgYWdhaW5zdCwgb3IgdW5kZWZpbmVkIHRvXG4gICAqIG5vdCBhc2suIFNlZSBgaG9va0RlbHRhQ3Vyc29yYCBpbiB7QGxpbmsgaGFuZGxlU3VzcGVuc2lvbn0gZm9yIHdoZW4gaXQgaXNcbiAgICogc2V0IGFuZCB3aHkgaXQgaXMgYXQgbW9zdCBvbmUgd3JpdGUgcGVyIHN1c3BlbnNpb24uXG4gICAqL1xuICBzaW5jZUN1cnNvcj86IHN0cmluZztcbiAgY3JlYXRlRXZlbnQ6IChcbiAgICBkYXRhOiBDcmVhdGVFdmVudFJlcXVlc3QsXG4gICAgcGFyYW1zPzogQ3JlYXRlRXZlbnRQYXJhbXNcbiAgKSA9PiBQcm9taXNlPEV2ZW50UmVzdWx0Pjtcbn0pOiBQcm9taXNlPHtcbiAgaGFzSG9va0NvbmZsaWN0OiBib29sZWFuO1xuICBoYXNBd2FpdGVkSG9va0NyZWF0aW9uOiBib29sZWFuO1xufT4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNyZWF0ZUV2ZW50KGhvb2tFdmVudCwge1xuICAgICAgcmVxdWVzdElkLFxuICAgICAgLi4uKHNpbmNlQ3Vyc29yID09PSB1bmRlZmluZWQgPyB7fSA6IHsgc2luY2VDdXJzb3IgfSksXG4gICAgfSk7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgd29ybGQgcmV0dXJuZWQgYSBob29rX2NvbmZsaWN0IGV2ZW50IGluc3RlYWQgb2YgaG9va19jcmVhdGVkLlxuICAgIC8vIFRoZSBob29rX2NvbmZsaWN0IGV2ZW50IGlzIHN0b3JlZCBpbiB0aGUgZXZlbnQgbG9nIGFuZCBpcyB3aGF0IHRoZSBuZXh0XG4gICAgLy8gcGFzcyBjb25zdW1lcyB0byBzZXR0bGUgdGhlIGhvb2sncyBhd2FpdGVycyDigJQgcmVqZWN0aW5nIGEgcGF5bG9hZCBhd2FpdCxcbiAgICAvLyByZXNvbHZpbmcgYSBgaG9vay5nZXRDb25mbGljdCgpYCB3aXRoIHRoZSBjb25mbGljdGluZyBydW4uIEFuIGlubGluZVxuICAgIC8vIGRlbHRhIGFza2VkIGZvciBhYm92ZSBjYXJyaWVzIGl0IGp1c3QgYXMgaXQgd291bGQgaGF2ZSBjYXJyaWVkIHRoZVxuICAgIC8vIGhvb2tfY3JlYXRlZCwgc28gdGhlIGNhbGxlciBjYW4gYWR2YW5jZSBvdmVyIGl0IHdpdGhvdXQgYSByZS1pbnZvY2F0aW9uLlxuICAgIGlmIChyZXN1bHQuZXZlbnQ/LmV2ZW50VHlwZSA9PT0gJ2hvb2tfY29uZmxpY3QnKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBoYXNIb29rQ29uZmxpY3Q6IHRydWUsXG4gICAgICAgIGhhc0F3YWl0ZWRIb29rQ3JlYXRpb246IGZhbHNlLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaGFzSG9va0NvbmZsaWN0OiBmYWxzZSxcbiAgICAgIGhhc0F3YWl0ZWRIb29rQ3JlYXRpb246IHF1ZXVlSXRlbS5oYXNDb25mbGljdEF3YWl0ZXIgPT09IHRydWUsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgcnVudGltZUxvZ2dlci5pbmZvKCdIb29rIGFscmVhZHkgZXhpc3RzLCBjb250aW51aW5nJywge1xuICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGhhc0hvb2tDb25mbGljdDogZmFsc2UsXG4gICAgICAgIGhhc0F3YWl0ZWRIb29rQ3JlYXRpb246IHF1ZXVlSXRlbS5oYXNDb25mbGljdEF3YWl0ZXIgPT09IHRydWUsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKSkge1xuICAgICAgcnVudGltZUxvZ2dlci5pbmZvKCdXb3JrZmxvdyBydW4gYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nIGhvb2snLCB7XG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaGFzSG9va0NvbmZsaWN0OiBmYWxzZSxcbiAgICAgICAgaGFzQXdhaXRlZEhvb2tDcmVhdGlvbjogZmFsc2UsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChpc1dvcmxkVmFsaWRhdGlvbkZhaWx1cmUoZXJyKSkge1xuICAgICAgY29uc3QgZmF0YWwgPSBuZXcgRmF0YWxFcnJvcihcbiAgICAgICAgYGNyZWF0ZUhvb2sgZmFpbGVkIFdvcmxkIHZhbGlkYXRpb246ICR7XG4gICAgICAgICAgZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpXG4gICAgICAgIH1gXG4gICAgICApO1xuICAgICAgZmF0YWwuY2F1c2UgPSBlcnI7XG4gICAgICB0aHJvdyBmYXRhbDtcbiAgICB9XG5cbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cblxuLyoqXG4gKiBIYW5kbGVzIGEgd29ya2Zsb3cgc3VzcGVuc2lvbiBieSBwcm9jZXNzaW5nIGFsbCBwZW5kaW5nIG9wZXJhdGlvbnMgKGhvb2tzLCBzdGVwcywgd2FpdHMpLlxuICogQ3JlYXRlcyBldmVudHMgZm9yIGFsbCBvcGVyYXRpb25zIGJ1dCBkb2VzIE5PVCBxdWV1ZSBzdGVwIG1lc3NhZ2VzOyByZXR1cm5zIHRoZSBwZW5kaW5nXG4gKiBzdGVwcyBzbyB0aGUgY2FsbGVyIGNhbiBkZWNpZGUgd2hpY2ggdG8gZXhlY3V0ZSBpbmxpbmUgdnMgcXVldWUgdG8gYmFja2dyb3VuZC5cbiAqXG4gKiBQcm9jZXNzaW5nIG9yZGVyOlxuICogMS4gSG9va3MgYXJlIHByb2Nlc3NlZCBmaXJzdCB0byBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyB3aXRoIHdlYmhvb2sgcmVjZWl2ZXJzXG4gKiAyLiBTdGVwIGV2ZW50cyBhbmQgd2FpdCBldmVudHMgYXJlIGNyZWF0ZWQgaW4gcGFyYWxsZWxcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZVN1c3BlbnNpb24oe1xuICBzdXNwZW5zaW9uLFxuICB3b3JsZCxcbiAgcnVuLFxuICBzcGFuLFxuICByZXF1ZXN0SWQsXG4gIGV2ZW50TG9nLFxuICBydW5SZWFkeUJhcnJpZXIsXG4gIHJlcGxheVJlY292ZXJ5UmVwb3J0ZXIsXG4gIHN0ZXBEaXNwYXRjaCxcbiAgb3duZXJNZXNzYWdlSWQsXG4gIGFsbG93RGVmZXJyZWRCYXRjaFdvcmssXG59OiBTdXNwZW5zaW9uSGFuZGxlclBhcmFtcyk6IFByb21pc2U8U3VzcGVuc2lvbkhhbmRsZXJSZXN1bHQ+IHtcbiAgY29uc3QgcnVuSWQgPSBydW4ucnVuSWQ7XG5cbiAgLy8gVHVyYm8gbW9kZTogaG9sZCBldmVyeSB3b3JsZCB3cml0ZSBiZWxvdyB1bnRpbCB0aGUgYmFja2dyb3VuZGVkXG4gIC8vIGBydW5fc3RhcnRlZGAgaGFzICpzZXR0bGVkKiwgc28gd2UgbmV2ZXIgd3JpdGUgYSBzdGVwL2hvb2svd2FpdCBldmVudCBmb3IgYVxuICAvLyBydW4gdGhhdCBkb2VzIG5vdCBleGlzdCB5ZXQuIEEgbm8tb3Agb3V0c2lkZSB0dXJibyAoYmFycmllciB1bmRlZmluZWQpIGFuZFxuICAvLyBvbiB0aGUgcHVyZSBpbmxpbmUgaG90IHBhdGgsIHdoaWNoIGRlZmVycyBhbGwgc3RlcHMgYW5kIHdyaXRlcyBub3RoaW5nLlxuICAvLyBBd2FpdGluZyB0aGUgc2FtZSAodXN1YWxseSBhbHJlYWR5LXNldHRsZWQpIHByb21pc2UgbW9yZSB0aGFuIG9uY2UgaXMgY2hlYXAuXG4gIC8vIEEgYmFycmllciByZWplY3Rpb24gaXMgc3dhbGxvd2VkIGZvciBvcmRlcmluZyBvbmx5OiBpZiBgcnVuX3N0YXJ0ZWRgIHRydWx5XG4gIC8vIGZhaWxlZCB0aGUgcnVuIGRvZXMgbm90IGV4aXN0LCBzbyB0aGUgc3Vic2VxdWVudCB3cml0ZSBzdXJmYWNlcyB0aGUgcmVhbFxuICAvLyBlcnJvciAocnVuIG5vdCBmb3VuZCAvIGdvbmUpIGFuZCB0aGUgbWVzc2FnZSByZWRlbGl2ZXJzLlxuICBjb25zdCBlbnN1cmVSdW5SZWFkeSA9IGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICBpZiAocnVuUmVhZHlCYXJyaWVyKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBydW5SZWFkeUJhcnJpZXI7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gaW50ZW50aW9uYWw6IG9yZGVyaW5nIGJhcnJpZXIgb25seSwgc2VlIGFib3ZlLlxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogQXdhaXQgZXZlcnkgb3BlcmF0aW9uIGluIGEgc3VzcGVuc2lvbiBwaGFzZSBiZWZvcmUgbGV0dGluZyBhIGZhaWx1cmVcbiAgICogZXNjYXBlLCBwcmVmZXJyaW5nIGEgc3RhbGUtc25hcHNob3QgKDQxMikgcmVqZWN0aW9uIHdoZW4gb25lIG9jY3VycmVkLlxuICAgKlxuICAgKiBgUHJvbWlzZS5hbGxgIHJlamVjdHMgYXMgc29vbiBhcyBvbmUgb3BlcmF0aW9uIGRvZXMgYW5kIGxlYXZlcyBpdHMgc2libGluZ3NcbiAgICogaW4gZmxpZ2h0LiBUaGF0IG1hdHRlcnMgZm9yIGEgNDEyOiB0aGUgY2FsbGVyIHJlYWN0cyBieSByZWxvYWRpbmcgdGhlIGV2ZW50XG4gICAqIGxvZyBhbmQgcmVzdGFydGluZyB0aGUgcmVwbGF5LCBzbyBhIHNpYmxpbmcgY3JlYXRlIHRoYXQgbGFuZHMgYWZ0ZXIgdGhlXG4gICAqIHJlamVjdGlvbiBlc2NhcGVkIGNvbW1pdHMgYW4gZXZlbnQgd2hvc2UgY29ycmVsYXRpb24gaWQgY2FtZSBmcm9tIHRoZVxuICAgKiBhYmFuZG9uZWQgcmVwbGF5J3Mgc2VlZGVkIHNlcXVlbmNlIChhbiBldmVudCB0aGUgZnJlc2ggcmVwbGF5IG5ldmVyXG4gICAqIHByb2R1Y2VzKSwgYW5kIGl0IHJhY2VzIHRoZSByZXN0YXJ0J3MgcmVsb2FkIHdoaWxlIGRvaW5nIHNvLiBTZXR0bGluZyBmaXJzdFxuICAgKiBtYWtlcyB0aGlzIHBoYXNlJ3Mgd3JpdGUgc2V0IGZpbmFsIGJlZm9yZSB0aGUgY2FsbGVyIGFjdHMgb24gdGhlIGZhaWx1cmUuXG4gICAqIEl0IG1pcnJvcnMgdGhlIHJ1bnRpbWUncyBpbmxpbmUgc3RlcCBjbGFpbSwgd2hpY2ggc2V0dGxlcyB0aGUgaW4tZmxpZ2h0XG4gICAqIHN0ZXAgZXhlY3V0aW9ucyBiZWZvcmUgZXNjYWxhdGluZyBhIDQxMi5cbiAgICpcbiAgICogQSA0MTIgaXMgcHJlZmVycmVkIG92ZXIgYW55IG90aGVyIHJlamVjdGlvbiBpbiB0aGUgc2FtZSBwaGFzZSBiZWNhdXNlIGl0XG4gICAqIGhhcyBhIGRlZmluZWQsIGNoZWFwIHJlY292ZXJ5IChyZXBsYXkgZnJvbSBhIGNvcnJlY3RlZCBsb2cpIHdoaWxlIHRoZVxuICAgKiBvdGhlcnMgZG8gbm90LiBBIGRldGVybWluaXN0aWMgZmFpbHVyZSBzdWNoIGFzIGFuIGF0dHJpYnV0ZS12YWxpZGF0aW9uXG4gICAqIGBGYXRhbEVycm9yYCByZWN1cnMgb24gdGhlIHJlc3RhcnQgYW5kIGZhaWxzIHRoZSBydW4gdGhlbiwgYXQgdGhlIGNvc3Qgb2ZcbiAgICogb25lIGV4dHJhIHJlcGxheS5cbiAgICovXG4gIGNvbnN0IHNldHRsZVBoYXNlID0gYXN5bmMgKG9wczogUHJvbWlzZTx1bmtub3duPltdKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgY29uc3QgcmVhc29ucyA9IChhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQob3BzKSlcbiAgICAgIC5maWx0ZXIoKHIpOiByIGlzIFByb21pc2VSZWplY3RlZFJlc3VsdCA9PiByLnN0YXR1cyA9PT0gJ3JlamVjdGVkJylcbiAgICAgIC5tYXAoKHIpID0+IHIucmVhc29uKTtcbiAgICBpZiAocmVhc29ucy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICB0aHJvdyByZWFzb25zLmZpbmQoKHIpID0+IFByZWNvbmRpdGlvbkZhaWxlZEVycm9yLmlzKHIpKSA/PyByZWFzb25zWzBdO1xuICB9O1xuXG4gIC8vIEV2ZXJ5IHN1c3BlbnNpb24gd3JpdGUgY2FycmllcyByZXBsYXktcmVjb3ZlcnkgdGVsZW1ldHJ5IG9uIHRoZSBmaXJzdCBvbmVcbiAgLy8gdGhhdCBjb21taXRzIGFmdGVyIHJlcGxheSByZWNvdmVyZWQuIEFsbCBzdXNwZW5zaW9uIGV2ZW50cyBhcmVcbiAgLy8gbm9uLXJ1bl9jcmVhdGVkIGV2ZW50cyBvbiB0aGlzIHJ1bidzIGBydW5JZGAuXG4gIGNvbnN0IHJlcG9ydGVyID0gcmVwbGF5UmVjb3ZlcnlSZXBvcnRlciA/PyBSZXBsYXlSZWNvdmVyeVJlcG9ydGVyLmluZXJ0KCk7XG4gIGNvbnN0IGNyZWF0ZUV2ZW50ID0gKGRhdGE6IENyZWF0ZUV2ZW50UmVxdWVzdCwgcGFyYW1zPzogQ3JlYXRlRXZlbnRQYXJhbXMpID0+XG4gICAgcmVwb3J0ZXIud2l0aEV2ZW50Q3JlYXRlKHBhcmFtcywgKHApID0+XG4gICAgICB3b3JsZC5ldmVudHMuY3JlYXRlKHJ1bklkLCBkYXRhLCBwKVxuICAgICk7XG4gIC8vIEFkZHMgdGhlIG9wdGltaXN0aWMtY29uY3VycmVuY3kgZ3VhcmQgd2hlbiB0aGUgY2FsbGVyIHN1cHBsaWVkIGEgbG9hZGVkXG4gIC8vIGV2ZW50IGxvZzsgd2l0aG91dCBvbmUgaXQgY3JlYXRlcyBkaXJlY3RseSAoY2FsbGVycyB3aXRoIG5vIHJlcGxheVxuICAvLyBzbmFwc2hvdCwgZS5nLiB0ZXN0cykuIEEgc3RhbGUgKDQxMikgcmVqZWN0aW9uIHByb3BhZ2F0ZXMgdG8gdGhlIGNhbGxlcixcbiAgLy8gd2hpY2ggcmVzdGFydHMgdGhlIHJlcGxheSBmcm9tIGEgY29ycmVjdGVkIGxvZy4gSXQgaXMgbm90IHJldHJpZWQgaGVyZSxcbiAgLy8gYmVjYXVzZSB0aGUgZXZlbnQncyBjb3JyZWxhdGlvbiBpZCB3YXMgbWludGVkIGJ5ICp0aGlzKiByZXBsYXkncyBzZWVkZWRcbiAgLy8gc2VxdWVuY2UsIHNvIHJlLWNvbW1pdHRpbmcgaXQgYWdhaW5zdCBhIGNvcnJlY3RlZCBsb2cgd291bGQgcGVyc2lzdCBhblxuICAvLyBldmVudCBubyBjb3JyZWN0IHJlcGxheSBwcm9kdWNlcy5cbiAgbGV0IHJlcG9ydGVkRXZlbnRzID0gMDtcbiAgLy8gV3JpdGVzIHRoaXMgc3VzcGVuc2lvbiBpc3N1ZWQsIGFuZCB3aGV0aGVyIG9uZSBvZiB0aGVtIGhhbmRlZCBiYWNrIGFcbiAgLy8gY29tcGxldGUgaW5saW5lIGRlbHRhIHRoYXQgd2FzIGZvbGRlZCBpbnRvIHRoZSBjYWxsZXIncyBsb2cuIFRvZ2V0aGVyIHRoZXlcbiAgLy8gYW5zd2VyIGBldmVudExvZ0NhcnJpZWRGb3J3YXJkYDogdGhlIGRlbHRhIGNvdmVycyB0aGUgbG9nIHVwIHRvIHRoZSB3cml0ZVxuICAvLyB0aGF0IHJldHVybmVkIGl0LCBzbyBpdCBhY2NvdW50cyBmb3IgZXZlcnkgZXZlbnQgdGhpcyBzdXNwZW5zaW9uIGNvbW1pdHRlZFxuICAvLyBvbmx5IGlmIHRoYXQgd3JpdGUgd2FzIHRoZSBvbmx5IG9uZS5cbiAgbGV0IGd1YXJkZWRXcml0ZXMgPSAwO1xuICBsZXQgZGVsdGFBYnNvcmJlZCA9IGZhbHNlO1xuICBjb25zdCBjcmVhdGVHdWFyZGVkOiBFdmVudENyZWF0b3IgPSBhc3luYyAoZGF0YSwgcGFyYW1zKSA9PiB7XG4gICAgZ3VhcmRlZFdyaXRlcysrO1xuICAgIGlmICghZXZlbnRMb2cpIHtcbiAgICAgIHJldHVybiBjcmVhdGVFdmVudChkYXRhLCBwYXJhbXMpO1xuICAgIH1cbiAgICBjb25zdCBsb2cgPSBldmVudExvZztcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjcmVhdGVFdmVudChkYXRhLCB7XG4gICAgICAuLi5wYXJhbXMsXG4gICAgICAuLi5zbG90U25hcHNob3RQYXJhbXMobG9nLmV2ZW50cyksXG4gICAgfSk7XG4gICAgLy8gQW4gaW5saW5lIGRlbHRhIHRoaXMgY2FsbCBhc2tlZCBmb3IgKGBzaW5jZUN1cnNvcmApIGlzIGV2ZXJ5dGhpbmcgdGhlXG4gICAgLy8gbG9nIGdhaW5lZCBzaW5jZSB0aGF0IGN1cnNvciwgdGhpcyB3cml0ZSBpbmNsdWRlZCwgc28gaXQgaXMgZm9sZGVkIG9udG9cbiAgICAvLyB0aGUgdGFpbCBhbmQgY2FycmllcyB0aGUgY3Vyc29yIHdpdGggaXQg4oCUIHVubGlrZSBhIHNraXBwZWQtc2xvdCByZXBvcnQsXG4gICAgLy8gd2hpY2ggaXMgYSB3aW5kb3cgc3RyaWN0bHkgYmVsb3cgdGhlIHdyaXRlIGFuZCBoYXMgdG8gYmUgc29ydGVkIGJhY2tcbiAgICAvLyBpbnRvIHBsYWNlLiBBIFdvcmxkIHJldHVybnMgb25lIG9yIHRoZSBvdGhlciwgbmV2ZXIgYm90aCAodGhlIGRlbHRhIGlzIGFcbiAgICAvLyBzdHJpY3Qgc3VwZXJzZXQpLCBzbyB0aGUgdHdvIGFyZSBoYW5kbGVkIGFwYXJ0IHJhdGhlciB0aGFuIG1lcmdlZC5cbiAgICAvL1xuICAgIC8vIERlY2xpbmluZyBpcyBhbHdheXMgc2FmZSDigJQgYW4gdW5hYnNvcmJlZCBkZWx0YSBpcyBvbmUgdGhlIG5leHQgcmVhZFxuICAgIC8vIHJldHVybnMg4oCUIHNvIHRoZSBndWFyZHMgbWF0Y2ggdGhlIHJlcGxheSBsb29wJ3MgYGFic29yYkNyZWF0ZURlbHRhYDogYVxuICAgIC8vIHRydW5jYXRlZCBwYWdlIChgaGFzTW9yZWApIGlzIGRyb3BwZWQgd2hvbGUgcmF0aGVyIHRoYW4gYWR2YW5jaW5nIHRoZVxuICAgIC8vIGN1cnNvciBwYXN0IGV2ZW50cyBpdCBkaWQgbm90IGNhcnJ5LCBhbmQgdGhlIGxvZyBtdXN0IHN0aWxsIGJlIHdoZXJlIHRoZVxuICAgIC8vIHJlcXVlc3Qgd2FzIGNvbXB1dGVkIGZyb20sIHNpbmNlIGFwcGVuZGluZyBkb2VzIG5vdCByZS1zb3J0LlxuICAgIGlmICh0eXBlb2YgcGFyYW1zPy5zaW5jZUN1cnNvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGlmIChcbiAgICAgICAgbG9nLmN1cnNvciA9PT0gcGFyYW1zLnNpbmNlQ3Vyc29yICYmXG4gICAgICAgIHJlc3VsdC5ldmVudHMgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICByZXN1bHQuaGFzTW9yZSAhPT0gdHJ1ZVxuICAgICAgKSB7XG4gICAgICAgIGFwcGVuZEV2ZW50TG9nKGxvZywgeyBldmVudHM6IHJlc3VsdC5ldmVudHMsIGN1cnNvcjogcmVzdWx0LmN1cnNvciB9KTtcbiAgICAgICAgZGVsdGFBYnNvcmJlZCA9IHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICAvLyBCdW1wLWFuZC1yZXBvcnQ6IHRoZSB3cml0ZSBsYW5kZWQgYWJvdmUgdGhlIHNsb3QgaXQgYXNrZWQgZm9yLCBzbyB0aGVcbiAgICAvLyByZXBvcnQgaG9sZHMgdGhlIGV2ZW50cyBpdCB3YXMgZGVjaWRlZCB3aXRob3V0LiBBYnNvcmJpbmcgaGVyZSByYXRoZXJcbiAgICAvLyB0aGFuIGF0IGVhY2ggY2FsbCBzaXRlIG1lYW5zIHRoZSByZXN0IG9mIHRoaXMgcGhhc2UncyB3cml0ZXMgKHdoaWNoIHJlYWRcbiAgICAvLyB0aGUgc2FtZSBhcnJheSB0byBidWlsZCB0aGVpciBvd24gc25hcHNob3QpIGFzayBmb3IgYSBzbG90IGFib3ZlIHRoZW0sXG4gICAgLy8gYW5kIHRoZSByZXBsYXkgdGhhdCByZXN1bWVzIGZyb20gdGhpcyBsb2cgc2VlcyB0aGVtIHdpdGhvdXQgYSByZWxvYWQuXG4gICAgY29uc3QgcmVwb3J0ID0gYWJzb3JiU2tpcHBlZFNsb3RSZXBvcnQobG9nLmV2ZW50cywgcmVzdWx0KTtcbiAgICByZXBvcnRlZEV2ZW50cyArPSByZXBvcnQuYWRkZWQ7XG4gICAgaWYgKHJlcG9ydC50cnVuY2F0ZWQpIHtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ0Ryb3BwZWQgYSB0cnVuY2F0ZWQgc2tpcHBlZC1zbG90IHJlcG9ydCcsIHtcbiAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgIGV2ZW50VHlwZTogZGF0YS5ldmVudFR5cGUsXG4gICAgICAgIGV2ZW50SWQ6IHJlc3VsdC5ldmVudD8uZXZlbnRJZCxcbiAgICAgICAgb2ZmZXJlZDogcmVwb3J0Lm9mZmVyZWQsXG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKHJlcG9ydC5hZGRlZCA+IDApIHtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1N1c3BlbnNpb24gd3JpdGUgc2tpcHBlZCBvY2N1cGllZCBzbG90cycsIHtcbiAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgIGV2ZW50VHlwZTogZGF0YS5ldmVudFR5cGUsXG4gICAgICAgIGV2ZW50SWQ6IHJlc3VsdC5ldmVudD8uZXZlbnRJZCxcbiAgICAgICAgcmVwb3J0ZWQ6IHJlcG9ydC5hZGRlZCxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuICAvLyBTZXBhcmF0ZSBxdWV1ZSBpdGVtcyBieSB0eXBlXG4gIGNvbnN0IHN0ZXBJdGVtcyA9IHN1c3BlbnNpb24uaXRlbXMuZmlsdGVyKFxuICAgIChpdGVtKTogaXRlbSBpcyBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSA9PiBpdGVtLnR5cGUgPT09ICdzdGVwJ1xuICApO1xuICBjb25zdCBhbGxIb29rSXRlbXMgPSBzdXNwZW5zaW9uLml0ZW1zLmZpbHRlcihcbiAgICAoaXRlbSk6IGl0ZW0gaXMgSG9va0ludm9jYXRpb25RdWV1ZUl0ZW0gPT4gaXRlbS50eXBlID09PSAnaG9vaydcbiAgKTtcbiAgY29uc3Qgd2FpdEl0ZW1zID0gc3VzcGVuc2lvbi5pdGVtcy5maWx0ZXIoXG4gICAgKGl0ZW0pOiBpdGVtIGlzIFdhaXRJbnZvY2F0aW9uUXVldWVJdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3dhaXQnXG4gICk7XG4gIGNvbnN0IGF0dHJpYnV0ZUl0ZW1zID0gc3VzcGVuc2lvbi5pdGVtcy5maWx0ZXIoXG4gICAgKGl0ZW0pOiBpdGVtIGlzIEF0dHJpYnV0ZUludm9jYXRpb25RdWV1ZUl0ZW0gPT4gaXRlbS50eXBlID09PSAnYXR0cmlidXRlJ1xuICApO1xuXG4gIGNvbnN0IGhvb2tzTmVlZGluZ0NyZWF0aW9uID0gYWxsSG9va0l0ZW1zLmZpbHRlcihcbiAgICAoaXRlbSkgPT4gIWl0ZW0uaGFzQ3JlYXRlZEV2ZW50XG4gICk7XG5cbiAgLy8gR3JvdXAgaG9vayBpdGVtcyB0aGF0IG5lZWQgd29yayBieSB0b2tlbiwgcHJlc2VydmluZyBxdWV1ZS1pbnNlcnRpb25cbiAgLy8gKHdvcmtmbG93IGNvZGUpIG9yZGVyIHdpdGhpbiBlYWNoIHRva2VuLiBPcGVyYXRpb25zIG9uIG9uZSB0b2tlbiBtdXN0XG4gIC8vIGFwcGx5IGluIGNvZGUgb3JkZXI6IGEgZGlzcG9zZSgpIG9mIGFuIGVhcmxpZXIgaG9vayByZWxlYXNlcyB0aGUgdG9rZW5cbiAgLy8gYmVmb3JlIGEgbGF0ZXIgc2FtZS10b2tlbiBob29rJ3MgY3JlYXRpb24gaXMgdmFsaWRhdGVkIChvdGhlcndpc2UgdGhlXG4gIC8vIG5ldyBob29rIHJlY29yZHMgYSBzcHVyaW91cyBob29rX2NvbmZsaWN0IGFnYWluc3QgdGhlIHJ1bidzIG93blxuICAvLyBkaXNwb3NlZCBob29rKSwgd2hpbGUgYSBob29rIGNyZWF0ZWQgYW5kIGRpc3Bvc2VkIHdpdGhpbiB0aGUgc2FtZVxuICAvLyBzdXNwZW5zaW9uIGlzIHN0aWxsIGNyZWF0ZWQgYmVmb3JlIGl0IGlzIGRpc3Bvc2VkLiBEaWZmZXJlbnQgdG9rZW5zXG4gIC8vIGhhdmUgbm8gY2xhaW0gaW50ZXJhY3Rpb24sIHNvIHRva2VuIGdyb3VwcyBhcmUgcHJvY2Vzc2VkIGluIHBhcmFsbGVsLlxuICBjb25zdCBob29rSXRlbXNCeVRva2VuID0gbmV3IE1hcDxzdHJpbmcsIEhvb2tJbnZvY2F0aW9uUXVldWVJdGVtW10+KCk7XG4gIGZvciAoY29uc3QgaXRlbSBvZiBhbGxIb29rSXRlbXMpIHtcbiAgICBpZiAoaXRlbS5oYXNDcmVhdGVkRXZlbnQgJiYgIWl0ZW0uZGlzcG9zZWQpIHtcbiAgICAgIGNvbnRpbnVlOyAvLyBhbHJlYWR5IGNvbW1pdHRlZCBhbmQgc3RpbGwgbGl2ZTogbm90aGluZyB0byBkb1xuICAgIH1cbiAgICBjb25zdCBncm91cCA9IGhvb2tJdGVtc0J5VG9rZW4uZ2V0KGl0ZW0udG9rZW4pO1xuICAgIGlmIChncm91cCkge1xuICAgICAgZ3JvdXAucHVzaChpdGVtKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaG9va0l0ZW1zQnlUb2tlbi5zZXQoaXRlbS50b2tlbiwgW2l0ZW1dKTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXNvbHZlIGVuY3J5cHRpb24ga2V5IGZvciB0aGlzIHJ1blxuICBjb25zdCByYXdLZXkgPSBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4ocnVuKTtcbiAgY29uc3QgZW5jcnlwdGlvbktleSA9IHJhd0tleSA/IGF3YWl0IGltcG9ydEtleShyYXdLZXkpIDogdW5kZWZpbmVkO1xuXG4gIC8vIEdhdGUgcGF5bG9hZCBjb21wcmVzc2lvbiBvbiB0aGUgcnVuJ3Mgc3BlY1ZlcnNpb24uXG4gIGNvbnN0IGNvbXByZXNzaW9uID1cbiAgICAocnVuLnNwZWNWZXJzaW9uID8/IDApID49IFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTjtcblxuICBsZXQgc2VyaWFsaXphdGlvbkJsb2NrZXJDb3VudCA9IDA7XG4gIGNvbnN0IHNlcmlhbGl6YXRpb25CbG9ja2VyczogU3VzcGVuc2lvblNlcmlhbGl6YXRpb25CbG9ja2VyW10gPSBbXTtcbiAgYXN5bmMgZnVuY3Rpb24gZGVoeWRyYXRlSW5wdXQoXG4gICAgdmFsdWU6IHVua25vd24sXG4gICAgY29udGV4dDogUGljazxTdXNwZW5zaW9uU2VyaWFsaXphdGlvbkJsb2NrZXIsICdzb3VyY2UnIHwgJ2NvcnJlbGF0aW9uSWQnPlxuICApOiBQcm9taXNlPFNlcmlhbGl6ZWREYXRhPiB7XG4gICAgY29uc3Qgc3RhdHM6IEd1ZXN0Q29kZVN0YXRzID0geyBleGVjdXRpb25zOiBbXSB9O1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gKGF3YWl0IGRlaHlkcmF0ZVN0ZXBBcmd1bWVudHMoXG4gICAgICAgIHZhbHVlLFxuICAgICAgICBydW5JZCxcbiAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgc3VzcGVuc2lvbi5nbG9iYWxUaGlzLFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgY29tcHJlc3Npb24sXG4gICAgICAgIHN0YXRzXG4gICAgICApKSBhcyBTZXJpYWxpemVkRGF0YTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgc2VyaWFsaXphdGlvbkJsb2NrZXJDb3VudCArPVxuICAgICAgICBzdGF0cy50b3RhbEV4ZWN1dGlvbnMgPz8gc3RhdHMuZXhlY3V0aW9ucy5sZW5ndGg7XG4gICAgICBzZXJpYWxpemF0aW9uQmxvY2tlcnMucHVzaChcbiAgICAgICAgLi4uc3RhdHMuZXhlY3V0aW9uc1xuICAgICAgICAgIC5zbGljZShcbiAgICAgICAgICAgIDAsXG4gICAgICAgICAgICBHVUVTVF9DT0RFX0VYRUNVVElPTl9TQU1QTEVfTElNSVQgLSBzZXJpYWxpemF0aW9uQmxvY2tlcnMubGVuZ3RoXG4gICAgICAgICAgKVxuICAgICAgICAgIC5tYXAoKGV4ZWN1dGlvbikgPT4gKHsgLi4uY29udGV4dCwgLi4uZXhlY3V0aW9uIH0pKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBkaXNwb3NlSG9vayhcbiAgICBxdWV1ZUl0ZW06IEhvb2tJbnZvY2F0aW9uUXVldWVJdGVtXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGhvb2tEaXNwb3NlZEV2ZW50OiBDcmVhdGVFdmVudFJlcXVlc3QgPSB7XG4gICAgICBldmVudFR5cGU6ICdob29rX2Rpc3Bvc2VkJyBhcyBjb25zdCxcbiAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgIHRva2VuOiBxdWV1ZUl0ZW0udG9rZW4sXG4gICAgICB9LFxuICAgIH07XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNyZWF0ZUd1YXJkZWQoaG9va0Rpc3Bvc2VkRXZlbnQsIHsgcmVxdWVzdElkIH0pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAvLyBIb29rIHdhcyBhbHJlYWR5IGRpc3Bvc2VkIGJ5IGEgY29uY3VycmVudCBpbnZvY2F0aW9uLCBzYWZlIHRvIHNraXBcbiAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICdIb29rIGFscmVhZHkgZGlzcG9zZWQsIHNraXBwaW5nIGR1cGxpY2F0ZSBkaXNwb3NhbCcsXG4gICAgICAgICAge1xuICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAoUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICdXb3JrZmxvdyBydW4gYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nIGhvb2sgZGlzcG9zYWwnLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9IGVsc2UgaWYgKEhvb2tOb3RGb3VuZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgLy8gSG9vayBtYXkgaGF2ZSBhbHJlYWR5IGJlZW4gZGlzcG9zZWQgb3IgbmV2ZXIgY3JlYXRlZFxuICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ0hvb2sgbm90IGZvdW5kIGZvciBkaXNwb3NhbCwgY29udGludWluZycsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUHJvY2VzcyBob29rcyBmaXJzdCB0byBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyB3aXRoIHdlYmhvb2sgcmVjZWl2ZXJzLlxuICAvLyBUcmFjayBhbnkgaG9vayBjb25mbGljdHMgdGhhdCBvY2N1ciDigJQgdGhlc2UgYXJlIHJldHVybmVkIHRvIHRoZSBjYWxsZXIgc29cbiAgLy8gaXQgY2FuIGFkdmFuY2UgdGhlIHdvcmtmbG93IG92ZXIgdGhlIGNvbW1pdHRlZCBgaG9va19jb25mbGljdGAgYmVmb3JlXG4gIC8vIGFueXRoaW5nIGVsc2UgdGhpcyBzdXNwZW5zaW9uIHNjaGVkdWxlZCBydW5zLlxuICBjb25zdCBob29rQ29uZmxpY3RDb3JyZWxhdGlvbklkczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgYXdhaXRlZEhvb2tDb3JyZWxhdGlvbklkczogc3RyaW5nW10gPSBbXTtcbiAgbGV0IGhvb2tDcmVhdGlvbk1zID0gMDtcblxuICAvLyBBc2sgdGhlIGhvb2sgY3JlYXRlIGZvciB0aGUgZXZlbnQtbG9nIGRlbHRhIHNpbmNlIHRoZSBjdXJzb3IgdGhlIGNhbGxlcidzXG4gIC8vIGxvZyB3YXMgcmVhZCBhdC4gVGhlIGhvb2sncyBhd2FpdGVycyBhcmUgc2V0dGxlZCBieSB0aGUgZXZlbnQgdGhpcyB3cml0ZVxuICAvLyBjb21taXRzIGFuZCBieSBub3RoaW5nIGVsc2Ug4oCUIGEgYGhvb2tfY3JlYXRlZGAgZm9yIGEgY2xlYW4gcmVnaXN0cmF0aW9uLFxuICAvLyBhIGBob29rX2NvbmZsaWN0YCB3aGVuIHRoZSB0b2tlbiB3YXMgYWxyZWFkeSBjbGFpbWVkIOKAlCBzbyB0aGUgY2FsbGVyIGNhblxuICAvLyBjb250aW51ZSB0aGUgd29ya2Zsb3cgaW4gaXRzIG93biBwcm9jZXNzIG9uIGVpdGhlciBvdXRjb21lLCBidXQgb25seSBvdmVyXG4gIC8vIGEgbG9nIHRoYXQgaG9sZHMgdGhhdCBldmVudCwgYW5kIHRoaXMgd3JpdGUgaXMgdGhlIG9uZSByZXF1ZXN0IHRoYXQgY2FuXG4gIC8vIGhhbmQgaXQgYmFjayB0b2dldGhlciB3aXRoIGFueXRoaW5nIGFub3RoZXIgd3JpdGVyIGxhbmRlZCBpbiB0aGUgbWVhbnRpbWUuXG4gIC8vIE9wdGlvbmFsIGJ5IGNvbnRyYWN0OiBhIFdvcmxkIHRoYXQgaWdub3JlcyBgc2luY2VDdXJzb3JgIHJldHVybnMgbm8gZGVsdGFcbiAgLy8gYW5kIHRoZSBjYWxsZXIgcmVhZHMgaW5zdGVhZC5cbiAgLy9cbiAgLy8gQXNrZWQgZm9yIG9uIHRoZSBzaW5nbGUtaG9vayBzdXNwZW5zaW9uIG9ubHkuIFR3byBjcmVhdGVzIGlzc3VlZCBmcm9tIG9uZVxuICAvLyBzbmFwc2hvdCBlYWNoIGRpZmYgYWdhaW5zdCB0aGUgc2FtZSBjdXJzb3IsIGFuZCBvbmx5IHRoZSBmaXJzdCBkZWx0YSBiYWNrXG4gIC8vIGNhbiBiZSBmb2xkZWQgaW4gKHRoZSBjdXJzb3IgbW92ZXMgd2l0aCBpdCksIHNvIHRoZSBsb2cgd291bGQgZW5kIHVwIHNob3J0XG4gIC8vIG9mIHRoZSBvdGhlcidzIGV2ZW50IHdpdGggbm90aGluZyB0byBzYXkgc28uXG4gIGNvbnN0IGhvb2tEZWx0YUN1cnNvciA9XG4gICAgaG9va3NOZWVkaW5nQ3JlYXRpb24ubGVuZ3RoID09PSAxICYmIHR5cGVvZiBldmVudExvZz8uY3Vyc29yID09PSAnc3RyaW5nJ1xuICAgICAgPyBldmVudExvZy5jdXJzb3JcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gIGlmIChob29rSXRlbXNCeVRva2VuLnNpemUgPiAwKSB7XG4gICAgY29uc3QgaG9va1BoYXNlU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIGF3YWl0IGVuc3VyZVJ1blJlYWR5KCk7XG4gICAgYXdhaXQgc2V0dGxlUGhhc2UoXG4gICAgICBbLi4uaG9va0l0ZW1zQnlUb2tlbi52YWx1ZXMoKV0ubWFwKGFzeW5jIChpdGVtcykgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IHF1ZXVlSXRlbSBvZiBpdGVtcykge1xuICAgICAgICAgIGxldCBjcmVhdGlvbkNvbmZsaWN0ZWQgPSBmYWxzZTtcblxuICAgICAgICAgIGlmICghcXVldWVJdGVtLmhhc0NyZWF0ZWRFdmVudCkge1xuICAgICAgICAgICAgY29uc3QgaG9va01ldGFkYXRhID1cbiAgICAgICAgICAgICAgdHlwZW9mIHF1ZXVlSXRlbS5tZXRhZGF0YSA9PT0gJ3VuZGVmaW5lZCdcbiAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIDogYXdhaXQgZGVoeWRyYXRlSW5wdXQocXVldWVJdGVtLm1ldGFkYXRhLCB7XG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZTogJ2hvb2tfbWV0YWRhdGEnLFxuICAgICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgaG9va0V2ZW50OiBDcmVhdGVFdmVudFJlcXVlc3QgPSB7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfY3JlYXRlZCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIHRva2VuOiBxdWV1ZUl0ZW0udG9rZW4sXG4gICAgICAgICAgICAgICAgdG9rZW5SZXRlbnRpb25VbnRpbDogcXVldWVJdGVtLnRva2VuUmV0ZW50aW9uVW50aWwsXG4gICAgICAgICAgICAgICAgbWV0YWRhdGE6IGhvb2tNZXRhZGF0YSxcbiAgICAgICAgICAgICAgICBpc1dlYmhvb2s6IHF1ZXVlSXRlbS5pc1dlYmhvb2sgPz8gZmFsc2UsXG4gICAgICAgICAgICAgICAgLi4uKHF1ZXVlSXRlbS5pc1N5c3RlbSAmJiB7IGlzU3lzdGVtOiB0cnVlIH0pLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNyZWF0ZUhvb2tFdmVudCh7XG4gICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICBob29rRXZlbnQsXG4gICAgICAgICAgICAgIHF1ZXVlSXRlbSxcbiAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICBzaW5jZUN1cnNvcjogaG9va0RlbHRhQ3Vyc29yLFxuICAgICAgICAgICAgICBjcmVhdGVFdmVudDogY3JlYXRlR3VhcmRlZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKHJlc3VsdC5oYXNIb29rQ29uZmxpY3QpIHtcbiAgICAgICAgICAgICAgaG9va0NvbmZsaWN0Q29ycmVsYXRpb25JZHMucHVzaChxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocmVzdWx0Lmhhc0F3YWl0ZWRIb29rQ3JlYXRpb24pIHtcbiAgICAgICAgICAgICAgYXdhaXRlZEhvb2tDb3JyZWxhdGlvbklkcy5wdXNoKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNyZWF0aW9uQ29uZmxpY3RlZCA9IHJlc3VsdC5oYXNIb29rQ29uZmxpY3Q7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gRGlzcG9zZSBhZnRlciBjcmVhdGlvbiBmb3IgaG9va3MgYm9ybiBhbmQgZGlzcG9zZWQgd2l0aGluIHRoaXNcbiAgICAgICAgICAvLyBiYXRjaC4gQSBob29rIHdob3NlIGNyZWF0aW9uIGNvbmZsaWN0ZWQgd2FzIG5ldmVyIGNyZWF0ZWQsIHNvXG4gICAgICAgICAgLy8gdGhlcmUgaXMgbm90aGluZyB0byBkaXNwb3NlLlxuICAgICAgICAgIGlmIChxdWV1ZUl0ZW0uZGlzcG9zZWQgJiYgIWNyZWF0aW9uQ29uZmxpY3RlZCkge1xuICAgICAgICAgICAgYXdhaXQgZGlzcG9zZUhvb2socXVldWVJdGVtKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKTtcbiAgICBob29rQ3JlYXRpb25NcyA9IERhdGUubm93KCkgLSBob29rUGhhc2VTdGFydDtcbiAgfVxuXG4gIC8vIFByb2Nlc3MgYWJvcnQgcmVxdWVzdHM6IHJlc3VtZSB0aGUgaG9vayB3aXRoIGFib3J0IHBheWxvYWQgYW5kIHdyaXRlIHN0cmVhbSBwYWNrZXRcbiAgY29uc3QgaG9va3NOZWVkaW5nQWJvcnQgPSBhbGxIb29rSXRlbXMuZmlsdGVyKFxuICAgIChpdGVtKSA9PiBpdGVtLmFib3J0UmVxdWVzdGVkICYmICFpdGVtLmRpc3Bvc2VkXG4gICk7XG5cbiAgaWYgKGhvb2tzTmVlZGluZ0Fib3J0Lmxlbmd0aCA+IDApIHtcbiAgICBhd2FpdCBlbnN1cmVSdW5SZWFkeSgpO1xuICAgIGF3YWl0IHNldHRsZVBoYXNlKFxuICAgICAgaG9va3NOZWVkaW5nQWJvcnQubWFwKGFzeW5jIChxdWV1ZUl0ZW0pID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBEZWh5ZHJhdGUgdGhlIGFib3J0IHBheWxvYWQgZm9yIHN0b3JhZ2VcbiAgICAgICAgICBjb25zdCBhYm9ydFBheWxvYWQgPSBhd2FpdCBkZWh5ZHJhdGVJbnB1dChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgYWJvcnRlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgcmVhc29uOiBxdWV1ZUl0ZW0uYWJvcnRSZWFzb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBzb3VyY2U6ICdob29rX2Fib3J0JyxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIENyZWF0ZSBob29rX3JlY2VpdmVkIGV2ZW50IHdpdGggYWJvcnQgcGF5bG9hZFxuICAgICAgICAgIGF3YWl0IGNyZWF0ZUd1YXJkZWQoe1xuICAgICAgICAgICAgZXZlbnRUeXBlOiAnaG9va19yZWNlaXZlZCcgYXMgY29uc3QsXG4gICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICB0b2tlbjogcXVldWVJdGVtLnRva2VuLFxuICAgICAgICAgICAgICBwYXlsb2FkOiBhYm9ydFBheWxvYWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gV3JpdGUgc3RyZWFtIGNhbmNlbGxhdGlvbiBwYWNrZXQgZm9yIHJlYWwtdGltZSBzdGVwIHByb3BhZ2F0aW9uLlxuICAgICAgICAgIC8vIFJldXNlIHRoZSBzYW1lIGRlaHlkcmF0ZWQgcGF5bG9hZCBhcyB0aGUgaG9vayBldmVudCBzbyB0aGUgcmVhc29uXG4gICAgICAgICAgLy8gcm91bmQtdHJpcHMgdGhyb3VnaCBgZGVoeWRyYXRlU3RlcEFyZ3VtZW50c2AgLyBgaHlkcmF0ZVN0ZXBBcmd1bWVudHNgXG4gICAgICAgICAgLy8gKGhhbmRsZXMgRE9NRXhjZXB0aW9uLCBjdXN0b20gZXJyb3JzLCBlbmNyeXB0aW9uLCBldGMuKSBpbnN0ZWFkIG9mXG4gICAgICAgICAgLy8gYmFyZSBKU09OLnN0cmluZ2lmeSB3aGljaCBsb3NlcyB0eXBlIGluZm9ybWF0aW9uIGFuZCBkcm9wcyB1bmRlZmluZWQuXG4gICAgICAgICAgLy8gc3RyZWFtTmFtZSBpcyBzZXQgb24gdGhlIHF1ZXVlIGl0ZW0gYXQgY29udHJvbGxlciBjb25zdHJ1Y3Rpb24gdGltZVxuICAgICAgICAgIC8vIChzZWUgd29ya2Zsb3cvYWJvcnQtY29udHJvbGxlci50cykuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRBYm9ydFN0cmVhbUlkRnJvbVRva2VuKHF1ZXVlSXRlbS50b2tlbik7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5zdHJlYW1zLndyaXRlKFxuICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgc3RyZWFtTmFtZSxcbiAgICAgICAgICAgICAgYWJvcnRQYXlsb2FkIGFzIFVpbnQ4QXJyYXlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5zdHJlYW1zLmNsb3NlKHJ1bklkLCBzdHJlYW1OYW1lKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8vIEJlc3QtZWZmb3J0IHN0cmVhbSB3cml0ZTogaG9vayBldmVudCBwcm92aWRlcyB0aGUgZHVyYWJsZSBmYWxsYmFja1xuICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgJ0ZhaWxlZCB0byB3cml0ZSBhYm9ydCBzdHJlYW0gcGFja2V0LCBob29rIGV2ZW50IHdpbGwgcHJvdmlkZSBmYWxsYmFjaycsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikgfHwgUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgJ1dvcmtmbG93IHJ1biBhbHJlYWR5IGNvbXBsZXRlZCwgc2tpcHBpbmcgYWJvcnQnLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBzdGVwIGV2ZW50cyBmb3Igc3RlcHMgdGhhdCBkb24ndCBoYXZlIHRoZW0geWV0LlxuICAvLyBVbmxpa2UgVjEsIHdlIGRvIE5PVCBxdWV1ZSBzdGVwIG1lc3NhZ2VzIGZyb20gaGVyZTogdGhlIGNhbGxlclxuICAvLyBkZWNpZGVzIHdoaWNoIHN0ZXBzIHRvIGV4ZWN1dGUgaW5saW5lIHZzLiBxdWV1ZSB0byBiYWNrZ3JvdW5kLlxuICAvLyBXYWl0IGV2ZW50cyBhcmUgYWxzbyBjcmVhdGVkIGluIHBhcmFsbGVsIGJlbG93LlxuICBjb25zdCBzdGVwc05lZWRpbmdDcmVhdGlvbiA9IG5ldyBTZXQoXG4gICAgc3RlcEl0ZW1zXG4gICAgICAuZmlsdGVyKChxdWV1ZUl0ZW0pID0+ICFxdWV1ZUl0ZW0uaGFzQ3JlYXRlZEV2ZW50KVxuICAgICAgLm1hcCgocXVldWVJdGVtKSA9PiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZClcbiAgKTtcblxuICAvLyBDb3JyZWxhdGlvbiBJRHMgZm9yIHdoaWNoIFRISVMgc3VzcGVuc2lvbiBjYWxsIGFjdHVhbGx5IHdyb3RlIHRoZVxuICAvLyBzdGVwX2NyZWF0ZWQgZXZlbnQuIFBvcHVsYXRlZCBieSB0aGUgb3BzIGJlbG93IGFmdGVyIGEgc3VjY2Vzc2Z1bFxuICAvLyBldmVudHMuY3JlYXRlLCB1c2VkIGJ5IHRoZSBjYWxsZXIgdG8gY2xhaW0gb3duZXJzaGlwIGFuZCBhdm9pZFxuICAvLyByYWNpbmcgd2l0aCBjb25jdXJyZW50IGhhbmRsZXJzIG9uIHN0ZXAgZXhlY3V0aW9uLlxuICBjb25zdCBjcmVhdGVkU3RlcENvcnJlbGF0aW9uSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLy8gQ29ycmVsYXRpb24gSURzIG9mIHN0ZXBzIGZpbmFsaXplZCBhcyBmYWlsZWQgYmVjYXVzZSB0aGVpciBhcmd1bWVudHNcbiAgLy8gcmVmdXNlZCB0byBzZXJpYWxpemU6IHNlZSBmaW5hbGl6ZVVuc2VyaWFsaXphYmxlU3RlcCBiZWxvdy5cbiAgY29uc3QgZmFpbGVkU3RlcENvcnJlbGF0aW9uSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLyoqXG4gICAqIEEgc3RlcCB3aG9zZSBhcmd1bWVudHMgZmFpbCB0byBzZXJpYWxpemUgaXMgZGV0ZXJtaW5pc3RpYzogZXZlcnkgcmVwbGF5XG4gICAqIHJlLWRlcml2ZXMgdGhlIHNhbWUgdW5zZXJpYWxpemFibGUgdmFsdWUsIHNvIHJlZGVsaXZlcmluZyB0aGVcbiAgICogb3JjaGVzdHJhdG9yIG1lc3NhZ2UgY2FuIG5ldmVyIHN1Y2NlZWQuIEluc3RlYWQgb2YgcmVqZWN0aW5nIHRoZSB3aG9sZVxuICAgKiBzdXNwZW5zaW9uICh3aGljaCBmYWlscyB0aGUgcnVuIGZyb20gdGhlIG91dHNpZGUsIHdoZXJlIG5vIHVzZXIgY29kZSBjYW5cbiAgICogb2JzZXJ2ZSBpdCksIHRyZWF0IGl0IGV4YWN0bHkgbGlrZSBhIHN0ZXAtYm9keSBmYWlsdXJlOiB3cml0ZVxuICAgKiBgc3RlcF9jcmVhdGVkYCB3aXRoIGEgcGxhY2Vob2xkZXIgaW5wdXQgKGV2ZXJ5IFdvcmxkIHJlcXVpcmVzIHRoZSBzdGVwXG4gICAqIGVudGl0eSB0byBleGlzdCBiZWZvcmUgYSB0ZXJtaW5hbCBzdGVwIGV2ZW50LCBhbmQgdGhlIHJlYWwgaW5wdXQgaXNcbiAgICogcHJlY2lzZWx5IHdoYXQgcmVmdXNlZCB0byBzZXJpYWxpemUpIGZvbGxvd2VkIGJ5IGBzdGVwX2ZhaWxlZGAgY2FycnlpbmdcbiAgICogdGhlIFNlcmlhbGl6YXRpb25FcnJvci4gVGhlIG5leHQgcmVwbGF5IHJlamVjdHMgdGhlIHN0ZXAncyBwcm9taXNlIHdpdGhcbiAgICogaXQsIHNvIGEgdHJ5L2NhdGNoIGFyb3VuZCB0aGUgc3RlcCBjYWxsIG9ic2VydmVzIHRoZSBlcnJvcjsgdW5jYXVnaHQsIGl0XG4gICAqIHByb3BhZ2F0ZXMgb3V0IG9mIHRoZSB3b3JrZmxvdyBib2R5IGFuZCBmYWlscyB0aGUgcnVuIGFzIGEgVVNFUl9FUlJPUixcbiAgICogd2l0aG91dCBidXJuaW5nIHF1ZXVlIHJlZGVsaXZlcmllcyBlaXRoZXIgd2F5LlxuICAgKi9cbiAgY29uc3QgZmluYWxpemVVbnNlcmlhbGl6YWJsZVN0ZXAgPSBhc3luYyAoXG4gICAgcXVldWVJdGVtOiBTdGVwSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgICBlcnJvcjogU2VyaWFsaXphdGlvbkVycm9yXG4gICk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICdTdGVwIGFyZ3VtZW50cyBmYWlsZWQgdG8gc2VyaWFsaXplOyBmYWlsaW5nIHRoZSBzdGVwIHNvIHRoZSAnICtcbiAgICAgICAgJ3dvcmtmbG93IGNhbiBvYnNlcnZlIHRoZSBlcnJvcicsXG4gICAgICB7XG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UsXG4gICAgICB9XG4gICAgKTtcbiAgICBhd2FpdCBlbnN1cmVSdW5SZWFkeSgpO1xuICAgIC8vIE1hcmtlciBwbGFjZWhvbGRlciAobm90IGVtcHR5IGFyZ3MpOiBieXRlLWlkZW50aWNhbC10by16ZXJvLWFyZ3Mgd291bGRcbiAgICAvLyBtYWtlIGB3b3JrZmxvdyBpbnNwZWN0IHN0ZXBzYCBzaG93IFwibm8gYXJndW1lbnRzXCIgZm9yIHRoZSBvbmUgc3RlcFxuICAgIC8vIHdob3NlIGVudGlyZSBwcm9ibGVtIHdhcyBpdHMgYXJndW1lbnRzLlxuICAgIGNvbnN0IHBsYWNlaG9sZGVySW5wdXQgPSAoYXdhaXQgZGVoeWRyYXRlU3RlcEFyZ3VtZW50cyhcbiAgICAgIHVuc2VyaWFsaXphYmxlU3RlcElucHV0UGxhY2Vob2xkZXIoKSxcbiAgICAgIHJ1bklkLFxuICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgIHN1c3BlbnNpb24uZ2xvYmFsVGhpcyxcbiAgICAgIGZhbHNlLFxuICAgICAgY29tcHJlc3Npb25cbiAgICApKSBhcyBTZXJpYWxpemVkRGF0YTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY3JlYXRlR3VhcmRlZChcbiAgICAgICAge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfY3JlYXRlZCcgYXMgY29uc3QsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIGlucHV0OiBwbGFjZWhvbGRlcklucHV0LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICk7XG4gICAgfSBjYXRjaCAoY3JlYXRlRXJyKSB7XG4gICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhjcmVhdGVFcnIpKSB7XG4gICAgICAgIC8vIEEgY29uY3VycmVudCBoYW5kbGVyIGFscmVhZHkgY3JlYXRlZCB0aGUgc3RlcDogdGhlIGZhaWx1cmUgaXNcbiAgICAgICAgLy8gZGV0ZXJtaW5pc3RpYywgc28gaXQgaXMgcmFjaW5nIHRvd2FyZCB0aGUgc2FtZSBzdGVwX2ZhaWxlZCBiZWxvdy5cbiAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKCdTdGVwIGFscmVhZHkgZXhpc3RzLCBjb250aW51aW5nJywge1xuICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIG1lc3NhZ2U6IGNyZWF0ZUVyci5tZXNzYWdlLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoUnVuRXhwaXJlZEVycm9yLmlzKGNyZWF0ZUVycikpIHtcbiAgICAgICAgLy8gUnVuIGFscmVhZHkgZmluaXNoZWQ6IG5vdGhpbmcgdG8gb2JzZXJ2ZSB0aGUgZmFpbHVyZS5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgY3JlYXRlRXJyO1xuICAgICAgfVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgYXdhaXQgY3JlYXRlR3VhcmRlZChcbiAgICAgICAge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfZmFpbGVkJyBhcyBjb25zdCxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICBzdGVwTmFtZTogcXVldWVJdGVtLnN0ZXBOYW1lLFxuICAgICAgICAgICAgLy8gVGhlIGVycm9yIGl0c2VsZiBpcyBhIHBsYWluIFdvcmtmbG93RXJyb3IgKG5hbWUsIG1lc3NhZ2Ugd2l0aFxuICAgICAgICAgICAgLy8gZnJhbWVkIGhpbnQsIGNhdXNlIGNoYWluKSwgc2VyaWFsaXphYmxlIGV2ZW4gdGhvdWdoIHRoZSBzdGVwXG4gICAgICAgICAgICAvLyBpbnB1dCB3YXMgbm90LiBFcnJvciBkZXRlY3Rpb24gaXMgcmVhbG0taW5kZXBlbmRlbnRcbiAgICAgICAgICAgIC8vICh0eXBlcy5pc05hdGl2ZUVycm9yKSwgc28gdGhlIGhvc3QtY3JlYXRlZCBlcnJvciBzZXJpYWxpemVzXG4gICAgICAgICAgICAvLyB0aGUgc2FtZSB1bmRlciBlaXRoZXIgZ2xvYmFsOyB0aGUgVk0gZ2xvYmFsIGlzIHBhc3NlZCBmb3JcbiAgICAgICAgICAgIC8vIGNvbnNpc3RlbmN5IHdpdGggZXZlcnkgb3RoZXIgZGVoeWRyYXRpb24gaW4gdGhpcyBmaWxlIGFuZCBzb1xuICAgICAgICAgICAgLy8gYW55IFZNLXJlYWxtIHZhbHVlcyBndWVzdCBjb2RlIHRocmV3IGludG8gdGhlIGNhdXNlIGNoYWluXG4gICAgICAgICAgICAvLyAoZ2V0dGVycy9wcm94aWVzIGV4ZWN1dGVkIGR1cmluZyB0aGUgZmFpbGVkIGRlaHlkcmF0aW9uKSBhcmVcbiAgICAgICAgICAgIC8vIGRldGVjdGVkIGJ5IHRoZSByZWFsbS1zZW5zaXRpdmUgcmVkdWNlcnMuXG4gICAgICAgICAgICBlcnJvcjogYXdhaXQgZGVoeWRyYXRlU3RlcEVycm9yKFxuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICBzdXNwZW5zaW9uLmdsb2JhbFRoaXMsXG4gICAgICAgICAgICAgIGNvbXByZXNzaW9uXG4gICAgICAgICAgICApLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZmFpbEVycikge1xuICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZmFpbEVycikgfHwgUnVuRXhwaXJlZEVycm9yLmlzKGZhaWxFcnIpKSB7XG4gICAgICAgIC8vIFN0ZXAgYWxyZWFkeSB0ZXJtaW5hbCAoYSBjb25jdXJyZW50IGhhbmRsZXIgd3JvdGUgdGhlIHNhbWVcbiAgICAgICAgLy8gZGV0ZXJtaW5pc3RpYyBmYWlsdXJlKSBvciB0aGUgcnVuIGFscmVhZHkgZmluaXNoZWQuXG4gICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAnVHJpZWQgZmFpbGluZyBzdGVwLCBidXQgc3RlcCBvciBydW4gaGFzIGFscmVhZHkgZmluaXNoZWQuJyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgbWVzc2FnZTogZmFpbEVyci5tZXNzYWdlLFxuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IGZhaWxFcnI7XG4gICAgICB9XG4gICAgfVxuICAgIGZhaWxlZFN0ZXBDb3JyZWxhdGlvbklkcy5hZGQocXVldWVJdGVtLmNvcnJlbGF0aW9uSWQpO1xuICAgIC8vIFJlbGVhc2UgdGhlIGlubGluZSBzbG90IGJvb2trZWVwaW5nOiB0aGUgc3RlcCBuZXZlciBydW5zLCBzbyBpdCBtdXN0XG4gICAgLy8gbm90IGFwcGVhciBpbiB0aGUgcmVidWlsdCBgbGF6eUlubGluZVN0ZXBzYC4gKEl0cyBzbG90IGluIHRoZSBmaXJzdC1OXG4gICAgLy8gc2VsZWN0aW9uIGFuZCBpbiBgaW5saW5lUGFpckZvbGRFbGlnaWJsZWAncyBjb3VudCB3YXMgY29uc3VtZWRcbiAgICAvLyBiZWZvcmUgZGVoeWRyYXRpb24gY291bGQgcmV2ZWFsIHRoZSBmYWlsdXJlLCBpbmhlcmVudCB0byBzZWxlY3RpbmdcbiAgICAvLyBiZWZvcmUgc2VyaWFsaXppbmcsIGFuZCBib3VuZGVkIHRvIG9uZSB3YXN0ZWQgc2xvdCBvbiBhIHBhc3MgdGhhdFxuICAgIC8vIGVuZHMgaW4gYSBmb3JjZWQgcmVwbGF5IGFueXdheS4pXG4gICAgbGF6eUlubGluZUNvcnJlbGF0aW9uSWRzLmRlbGV0ZShxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCk7XG4gIH07XG5cbiAgLy8gTGF6eSBpbmxpbmUgc3RhcnQ6IGRlZmVyIHRoZSBzdGVwX2NyZWF0ZWQgd3JpdGUgZm9yIHVwIHRvXG4gIC8vIGBnZXRNYXhJbmxpbmVTdGVwcygpYCBzdGVwcyB0aGUgY2FsbGVyIHdpbGwgcnVuIGlubGluZSAoaW4gcGFyYWxsZWwpLiBFYWNoXG4gIC8vIHN0ZXAgaXMgY3JlYXRlZCBvbiB0aGUgZmx5IGJ5IHRoZSBsYXp5IGBzdGVwX3N0YXJ0ZWRgIGV4ZWN1dGVTdGVwIHNlbmRzXG4gIC8vIChzYXZpbmcgYSByb3VuZC10cmlwIHBlciBzdGVwKS4gV2UgbmV2ZXIgZGVmZXIgd2hlbiBhIGBob29rLmdldENvbmZsaWN0KClgXG4gIC8vIGF3YWl0ZXIgaXMgcHJlc2VudCwgYmVjYXVzZSBpbiB0aGF0IGNhc2UgdGhlIGNhbGxlciBleGVjdXRlcyBub3RoaW5nIGlubGluZVxuICAvLyAoaXQgY29udGludWVzIHRoZSB3b3JrZmxvdyB0byByZXNvbHZlIHRoZSBhd2FpdGVyIGluc3RlYWQpLCBzbyBkZWZlcnJpbmdcbiAgLy8gd291bGQgbGVhdmUgdGhlIHN0ZXBzIHVuY3JlYXRlZCBhbmQgdW5xdWV1ZWQuIFdlIHBpY2sgdGhlIGZpcnN0IE4gdW5jcmVhdGVkXG4gIC8vIHN0ZXBzIOKAlCBtYXRjaGluZyB0aGUgY2FsbGVyJ3MgaW5saW5lLWNhbmRpZGF0ZSBzZWxlY3Rpb24g4oCUIGFuZCBkZWh5ZHJhdGVcbiAgLy8gdGhlaXIgaW5wdXQgaGVyZSBzbyBleGVjdXRlU3RlcCBjYW4gc2hpcCBpdCBhcyB0aGUgc3RlcF9zdGFydGVkIHBheWxvYWQuXG4gIGNvbnN0IGxhenlJbmxpbmVDb3JyZWxhdGlvbklkcyA9IG5ldyBTZXQ8c3RyaW5nPihcbiAgICBhd2FpdGVkSG9va0NvcnJlbGF0aW9uSWRzLmxlbmd0aCA9PT0gMFxuICAgICAgPyBzdGVwSXRlbXNcbiAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBzdGVwc05lZWRpbmdDcmVhdGlvbi5oYXMoaXRlbS5jb3JyZWxhdGlvbklkKSlcbiAgICAgICAgICAuc2xpY2UoMCwgZ2V0TWF4SW5saW5lU3RlcHMoKSlcbiAgICAgICAgICAubWFwKChpdGVtKSA9PiBpdGVtLmNvcnJlbGF0aW9uSWQpXG4gICAgICA6IFtdXG4gICk7XG4gIC8vIENvbGxlY3RlZCBieSBjb3JyZWxhdGlvbklkIGJlY2F1c2UgdGhlIHBlci1zdGVwIG9wcyBiZWxvdyBydW4gY29uY3VycmVudGx5XG4gIC8vIGFuZCBzZXR0bGUgb3V0IG9mIG9yZGVyLiBXZSByZWJ1aWxkIHRoZSBhcnJheSBpbiBkZXRlcm1pbmlzdGljXG4gIC8vIGBsYXp5SW5saW5lQ29ycmVsYXRpb25JZHNgIG9yZGVyICh0aGUgb3JkZXJlZCBzbGljZSBhYm92ZSkgYWZ0ZXIgdGhlIG9wc1xuICAvLyBzZXR0bGUsIHNvIHRoZSBpbmxpbmUgYmF0Y2ggb3JkZXIgaXMgc3RhYmxlIHJlZ2FyZGxlc3Mgb2YgZGVoeWRyYXRpb24gdGltaW5nLlxuICBjb25zdCBsYXp5SW5saW5lQnlDb3JyZWxhdGlvbklkID0gbmV3IE1hcDxcbiAgICBzdHJpbmcsXG4gICAgU3VzcGVuc2lvbkhhbmRsZXJSZXN1bHRbJ2xhenlJbmxpbmVTdGVwcyddW251bWJlcl1cbiAgPigpO1xuXG4gIGNvbnN0IG9wczogUHJvbWlzZTx2b2lkPltdID0gW107XG5cbiAgLy8gQ29ycmVsYXRpb24gSURzIG9mIHN0ZXBzIHdob3NlIHN0ZXAtZXhlY3V0aW9uIHF1ZXVlIG1lc3NhZ2Ugd2FzIGFscmVhZHlcbiAgLy8gcHVibGlzaGVkIGJ5IHRoZSByZXNpbGllbnQtZGlzcGF0Y2ggb3BzIGJlbG93IChhbG9uZ3NpZGUgdGhlIHN0ZXBfY3JlYXRlZFxuICAvLyB3cml0ZSkuIFJlcG9ydGVkIHRvIHRoZSBjYWxsZXIgc28gaXRzIGRpc3BhdGNoIHBhc3Mgc2tpcHMgdGhlbS5cbiAgY29uc3QgcXVldWVkU3RlcENvcnJlbGF0aW9uSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLy8gUmVzaWxpZW50IHN0ZXAgZGlzcGF0Y2ggZWxpZ2liaWxpdHksIHNoYXJlZCBieSBldmVyeSBzdGVwIG9wIGJlbG93ICh0aGVcbiAgLy8gcGVyLXN0ZXAgaW5wdXQtc2l6ZSBjaGVjayBpcyBhcHBsaWVkIGluc2lkZSB0aGUgb3ApLiBBbGwgbXVzdCBob2xkOlxuICAvL1xuICAvLyAgLSBUaGUgY2FsbGVyIHByb3ZpZGVkIGEgZGlzcGF0Y2ggdGFyZ2V0IChgc3RlcERpc3BhdGNoYCk6IHRlcm1pbmFsXG4gIC8vICAgIGRyYWlucyBhbmQgb3RoZXIgY3JlYXRlLW9ubHkgY2FsbGVycyBuZXZlciBxdWV1ZS5cbiAgLy8gIC0gVGhlIGZlYXR1cmUgaXMgZW5hYmxlZCAoYFdPUktGTE9XX1JFU0lMSUVOVF9TVEVQX0RJU1BBVENIYCBvcHQtaW4pLlxuICAvLyAgICBJdCBpcyBvZmYgYnkgZGVmYXVsdCBiZWNhdXNlIHRoZSBwdWJsaXNoIHJhY2VzIHRoZSBjcmVhdGUncyB2ZXJkaWN0LFxuICAvLyAgICBhbmQgYSBjcmVhdGUgY2FuIGNvbWUgYmFjayByZWZ1c2VkOiBhcyBhIGR1cGxpY2F0ZSB0aGUgcmVwbGF5IHNob3VsZFxuICAvLyAgICBzdG9wIHB1cnN1aW5nLCBvciAob24gYSBXb3JsZCB0aGF0IHdvdWxkIHJhdGhlciByZWZ1c2UgYSBzdGFsZSB3cml0ZVxuICAvLyAgICB0aGFuIHJlcG9ydCB3aGF0IGl0IG1pc3NlZCkgYXMgYSA0MTIuIEVpdGhlciB3YXkgdGhlIHF1ZXVlIG1lc3NhZ2VcbiAgLy8gICAgY2FycnlpbmcgdGhlIHBheWxvYWQgaXMgYWxyZWFkeSBvdXQsIGFuZCB0aGUgY29uc3VtZXIgY2FuIG1hdGVyaWFsaXplIGFcbiAgLy8gICAgc3RlcCB3aG9zZSBjcmVhdGUgd2FzIHJlZnVzZWQuIE5vdGhpbmcgb3JkZXJzIHRoYXQgdmVyZGljdCBiZWZvcmUgdGhlXG4gIC8vICAgIGNvbnN1bWVyJ3MgcmVkZWxpdmVyeSByZS1lbnN1cmUsIHNvIG5vIGJhY2tlbmQtc2lkZSByZXZvY2F0aW9uXG4gIC8vICAgIGJvb2trZWVwaW5nIGNhbiBjbG9zZSB0aGUgd2luZG93OiBhIGJlc3QtZWZmb3J0IG1hcmtlciB0aGF0IGZhaWxzIG9wZW5cbiAgLy8gICAgY2Fubm90IGNhcnJ5IGEgY29ycmVjdG5lc3MgcHJvcGVydHkuIFRoZSBzZXF1ZW50aWFsIHBhdGggaXMgdGhlIG9ubHlcbiAgLy8gICAgdGhpbmcgdGhhdCBnaXZlcyB0aGUgbWVzc2FnZSBhIGhhcHBlbnMtYWZ0ZXIgZWRnZSBvdmVyIHRoZSB2ZXJkaWN0LlxuICAvLyAgLSBUaGUgcnVuJ3MgcXVldWUgdHJhbnNwb3J0IHByZXNlcnZlcyBiaW5hcnkgcGF5bG9hZHMgKENCT1IsXG4gIC8vICAgIHNwZWNWZXJzaW9uID49IDMpOiBgc3RlcElucHV0LmlucHV0YCBpcyB0aGUgc2VyaWFsaXplZCAocG9zc2libHlcbiAgLy8gICAgZW5jcnlwdGVkKSBpbnB1dCBieXRlcywgd2hpY2ggdGhlIEpTT04gdHJhbnNwb3J0IHdvdWxkIG1hbmdsZS5cbiAgY29uc3QgcmVzaWxpZW50RGlzcGF0Y2hFbGlnaWJsZSA9XG4gICAgc3RlcERpc3BhdGNoICE9PSB1bmRlZmluZWQgJiZcbiAgICBpc1Jlc2lsaWVudFN0ZXBEaXNwYXRjaEVuYWJsZWQoKSAmJlxuICAgIChydW4uc3BlY1ZlcnNpb24gPz8gMCkgPj0gU1BFQ19WRVJTSU9OX1NVUFBPUlRTX0NCT1JfUVVFVUVfVFJBTlNQT1JUO1xuXG4gIC8vIEJhdGNoZWQgZmFuLW91dDogZm9sZCB0aGlzIHN1c3BlbnNpb24ncyBzdGVwX2NyZWF0ZWQgKyB3YWl0X2NyZWF0ZWRcbiAgLy8gd3JpdGVzIGludG8gb25lIGBldmVudHMuY3JlYXRlQmF0Y2hgIGNhbGwgKG9uZSBkdXJhYmxlIHdyaXRlLCBwZXItZXZlbnRcbiAgLy8gb3V0Y29tZXMpIGluc3RlYWQgb2Ygb25lIHdyaXRlIHBlciBldmVudC4gRW5nYWdlcyBvbmx5IGZvciBhIENMRUFOXG4gIC8vIGZhbi1vdXQgKG5vIGF0dHJpYnV0ZSB3cml0ZXMsIG5vIGhvb2sgd3JpdGVzLCBubyByZXNpbGllbnQgZGlzcGF0Y2hcbiAgLy8gd2hvc2UgY3JlYXRlcyBhcmUgZWFjaCBwYWlyZWQgd2l0aCBhIHF1ZXVlIHB1Ymxpc2gpIG9uIGEgV29ybGQgdGhhdFxuICAvLyBpbXBsZW1lbnRzIHRoZSBvcHRpb25hbCBtZXRob2QgYW5kIGEgcnVuIHdob3NlIGV2ZW50cyBhcmUgc2xvdC1udW1iZXJlZC5cbiAgLy8gRXZlcnl0aGluZyBvdXRzaWRlIHRoZSBnYXRlIGtlZXBzIHRoZSBzaW5nbGUtZXZlbnQgcGF0aCBieXRlLWZvci1ieXRlLlxuICBjb25zdCBiYXRjaEZhbm91dEVsaWdpYmxlID1cbiAgICBpc0JhdGNoVHJhbnNpdGlvbnNFbmFibGVkKCkgJiZcbiAgICB0eXBlb2Ygd29ybGQuZXZlbnRzLmNyZWF0ZUJhdGNoID09PSAnZnVuY3Rpb24nICYmXG4gICAgKHJ1bi5zcGVjVmVyc2lvbiA/PyAwKSA+PSBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfU0xPVF9JREVOVElUWSAmJlxuICAgICFyZXNpbGllbnREaXNwYXRjaEVsaWdpYmxlICYmXG4gICAgYWxsSG9va0l0ZW1zLmxlbmd0aCA9PT0gMCAmJlxuICAgIGF0dHJpYnV0ZUl0ZW1zLmxlbmd0aCA9PT0gMDtcbiAgLyoqXG4gICAqIFRoZSBmb2xkJ3MgY29sbGVjdGlvbiwgaW4gc2NoZWR1bGluZyBvcmRlciAoc3RlcHMgaW4gc3RlcEl0ZW1zIG9yZGVyLFxuICAgKiB0aGVuIHdhaXRzKS4gU3RlcCBlbnRyaWVzIGFyZSBlbnF1ZXVlZCBieSB0aGVpciBwcmVwIHByb21pc2VzIChpbnB1dFxuICAgKiBkZWh5ZHJhdGlvbiBydW5zIGNvbmN1cnJlbnRseSwgc28gZW50cmllcyBhcmUgb3JkZXJlZCBieSBgb3JkZXJgLCBub3QgYnlcbiAgICogY29tcGxldGlvbik7IHRoZSBzaW5nbGUgZmx1c2ggb3AgYmVsb3cgYXdhaXRzIGV2ZXJ5IHByZXAsIHNvcnRzLCBhbmRcbiAgICogY29tbWl0cyB0aGUgd2hvbGUgc2V0IHRocm91Z2ggYGNyZWF0ZUJhdGNoYC5cbiAgICovXG4gIGNvbnN0IGJhdGNoUXVldWU6IHtcbiAgICBvcmRlcjogbnVtYmVyO1xuICAgIGtpbmQ6ICdzdGVwJyB8ICd3YWl0JyB8ICdpbmxpbmUtY3JlYXRlZCcgfCAnaW5saW5lLXN0YXJ0ZWQnO1xuICAgIGNvcnJlbGF0aW9uSWQ6IHN0cmluZztcbiAgICAvKiogVGhlIHN0ZXAncyBuYW1lLCBzZXQgb24gc3RlcC1jYXJyeWluZyBraW5kcyAodGhlIGluLWZsdXNoIHB1Ymxpc2hlc1xuICAgICAqICBhbmQgdGhlIGRpc3BhdGNoIGlkZW1wb3RlbmN5IGtleSBuZWVkIGl0KS4gKi9cbiAgICBzdGVwTmFtZT86IHN0cmluZztcbiAgICBldmVudDogQ3JlYXRlRXZlbnRSZXF1ZXN0O1xuICB9W10gPSBbXTtcbiAgY29uc3QgYmF0Y2hQcmVwczogUHJvbWlzZTx2b2lkPltdID0gW107XG5cbiAgLy8gUHJlLWNsYWltZWQgaW5saW5lIHBhaXJzOiBmb2xkIGVhY2ggbGF6eS1pbmxpbmUgc3RlcCdzIGRlZmVycmVkXG4gIC8vIGBzdGVwX2NyZWF0ZWRgIChjYXJyeWluZyBpdHMgaW5wdXQpIEFORCBpdHMgYHN0ZXBfc3RhcnRlZGAgY2xhaW0gKGJhcmUsXG4gIC8vIG93bmVyc2hpcC1zdGFtcGVkKSBpbnRvIHRoZSBiYXRjaCwgc28gdGhlIGlubGluZSBzdGVwcycgY2xhaW1zIGNvbW1pdCBpblxuICAvLyBvbmUgZHVyYWJsZSB3cml0ZSAodGhlIHBhaXIgY2h1bmssIHNlZSB0aGUgZmx1c2ggYmVsb3cpIGFuZCB0aGUgY2FsbGVyXG4gIC8vIHN0YXJ0cyB0aGUgYm9kaWVzIHN0cmFpZ2h0IG9mZiB0aGF0IGNvbW1pdCBpbnN0ZWFkIG9mIHBvc3Rpbmcgb25lIGNsYWltXG4gIC8vIHBlciBpbmxpbmUgc3RlcC4gUmVxdWlyZXMgVFdPIG9yIG1vcmUgaW5saW5lIHN0ZXBzLCBhbmQgbm90aGluZyBlbHNlOlxuICAvLyB0aGUgcGFpcnMgY29tbWl0IGluIGEgY2h1bmsgb2YgdGhlaXIgb3duLCBzbyBwbGFpbiBjcmVhdGVzIGFsb25nc2lkZVxuICAvLyB0aGVtIHNoYXJlIG5vIHJvdW5kIHRyaXAgd2l0aCB0aGUgcGFpcnMgYW5kIGNhbm5vdCBtYWtlIGEgbG9uZSBwYWlyXG4gIC8vIHdvcnRoIGZvbGRpbmcuIEEgbG9uZSBpbmxpbmUgc3RlcCBpcyBiZXR0ZXIgc2VydmVkIGJ5IHRoZSBsYXp5XG4gIC8vIGBzdGVwX3N0YXJ0ZWRgOiBvbmUgcm93IGluc3RlYWQgb2YgdHdvLCBvcHRpbWlzdGljLXN0YXJ0IGNhcGFibGUgKHRoZVxuICAvLyBjbGFpbSBvdmVybGFwcyB0aGUgYm9keSksIHdpdGggdGhlIHNsb3Qtc25hcHNob3QgcGFyYW1zIGFuZFxuICAvLyBidW1wLWFuZC1yZXBvcnQgYGNyZWF0ZUd1YXJkZWRgIHByb3ZpZGVzLCBhbGwgb2Ygd2hpY2ggYSBwYWlyLW9ubHlcbiAgLy8gYmF0Y2ggb2Ygb25lIHBhaXIgZ2l2ZXMgdXAgZm9yIHRoZSBzYW1lIHJvdW5kIHRyaXAuIFR3byBvciBtb3JlIGlubGluZVxuICAvLyBzdGVwcyBiZWNvbWUgT05FIHBhaXIgY2h1bmsgaW5zdGVhZCBvZiBOIHBhcmFsbGVsIGxhenkgY2xhaW1zLCB3aGljaCBpc1xuICAvLyB0aGUgc2F2aW5nLiBBIGxvbmUgaW5saW5lIHN0ZXAgYWxvbmdzaWRlIGVhZ2VyIGNyZWF0ZXMgdGhlcmVmb3JlIHRha2VzXG4gIC8vIHRoZSBsYXp5IHBhdGggd2hpbGUgdGhlIGNyZWF0ZXMgc3RpbGwgYmF0Y2guIEFsc28gcmVxdWlyZXMgdGhlIGNhbGxlcidzXG4gIC8vIGBvd25lck1lc3NhZ2VJZGA6IHRoZSBzdGFydGVkIHJvdyBtdXN0IHN0YW1wIG93bmVyc2hpcCBleGFjdGx5IGxpa2UgdGhlXG4gIC8vIGxhenkgY2xhaW0gaXQgcmVwbGFjZXMgKGFuZCBhIGNhbGxlciB0aGF0IGRvZXMgbm90IGlubGluZS1leGVjdXRlIG5ldmVyXG4gIC8vIHByb3ZpZGVzIG9uZSkuXG4gIGNvbnN0IGlubGluZVBhaXJGb2xkRWxpZ2libGUgPVxuICAgIGJhdGNoRmFub3V0RWxpZ2libGUgJiZcbiAgICBvd25lck1lc3NhZ2VJZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgbGF6eUlubGluZUNvcnJlbGF0aW9uSWRzLnNpemUgPj0gMjtcbiAgY29uc3QgaW5saW5lQ2xhaW1zOiBTdXNwZW5zaW9uSGFuZGxlclJlc3VsdFsnaW5saW5lQ2xhaW1zJ10gPSBuZXcgTWFwKCk7XG5cbiAgLy8gVGhlIHRyYWNlIGNhcnJpZXIgZm9yIHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoZXMsIHJlc29sdmVkIGF0IG1vc3Qgb25jZSBwZXJcbiAgLy8gc3VzcGVuc2lvbiAodGhlIHBlci1zdGVwIG9wcyBydW4gY29uY3VycmVudGx5IGFuZCBzaGFyZSBpdCkuXG4gIGxldCBzdGVwRGlzcGF0Y2hUcmFjZUNhcnJpZXI6IFByb21pc2U8VHJhY2VDYXJyaWVyPiB8IHVuZGVmaW5lZDtcbiAgY29uc3QgZ2V0U3RlcERpc3BhdGNoVHJhY2VDYXJyaWVyID0gKCk6IFByb21pc2U8VHJhY2VDYXJyaWVyPiA9PiB7XG4gICAgc3RlcERpc3BhdGNoVHJhY2VDYXJyaWVyID8/PVxuICAgICAgc3RlcERpc3BhdGNoPy5nZXRUcmFjZUNhcnJpZXIoKSA/PyBQcm9taXNlLnJlc29sdmUoe30pO1xuICAgIHJldHVybiBzdGVwRGlzcGF0Y2hUcmFjZUNhcnJpZXI7XG4gIH07XG5cbiAgLy8gUHJvZHVjZXItc2lkZSByZXNpbGllbnQgcmVjb3ZlcnkgY291bnQgZm9yIHRoZSBzdXNwZW5zaW9uIHNwYW4gYXR0cmlidXRlLlxuICBsZXQgcmVzaWxpZW50RGlzcGF0Y2hSZWNvdmVyZWQgPSAwO1xuXG4gIC8vIFN0ZXBzOiBjcmVhdGUgc3RlcF9jcmVhdGVkIGV2ZW50cyAobm8gcXVldWluZywgVjIgcmV0dXJucyBwZW5kaW5nIHN0ZXBzXG4gIC8vIHRvIGNhbGxlciwgRVhDRVBUIG9uIHRoZSByZXNpbGllbnQgZGlzcGF0Y2ggcGF0aCwgd2hpY2ggcGFyYWxsZWxpemVzIHRoZVxuICAvLyBjcmVhdGUgd2l0aCB0aGUgc3RlcCdzIHF1ZXVlIHB1Ymxpc2ggYW5kIHJlcG9ydHMgaXQgaW5cbiAgLy8gYHF1ZXVlZFN0ZXBDb3JyZWxhdGlvbklkc2ApLlxuICBsZXQgYmF0Y2hPcmRlckNvdW50ZXIgPSAwO1xuICBmb3IgKGNvbnN0IHF1ZXVlSXRlbSBvZiBzdGVwSXRlbXMpIHtcbiAgICBpZiAoc3RlcHNOZWVkaW5nQ3JlYXRpb24uaGFzKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKSkge1xuICAgICAgLy8gRGV0ZXJtaW5pc3RpYyBwb3NpdGlvbiBpbiB0aGUgYmF0Y2hlZCBmb2xkIChhc3NpZ25lZCBpbiBzdGVwSXRlbXNcbiAgICAgIC8vIG9yZGVyLCBiZWZvcmUgdGhlIGNvbmN1cnJlbnQgZGVoeWRyYXRpb24gcnVucykuIEEgcGFpci1mb2xkZWQgaW5saW5lXG4gICAgICAvLyBzdGVwIG9jY3VwaWVzIHR3byBjb25zZWN1dGl2ZSBwb3NpdGlvbnMgKGNyZWF0ZWQgcm93IHRoZW4gc3RhcnRlZFxuICAgICAgLy8gcm93KSwgd2hpY2ggdGhlIGZsdXNoIGtlZXBzIGFkamFjZW50LCBuZXZlciBzcGxpdHMgYWNyb3NzIGNodW5rcyxcbiAgICAgIC8vIGFuZCBjb21taXRzIGluIGEgcGFpci1vbmx5IGNodW5rIGFoZWFkIG9mIHRoZSBwbGFpbiBjcmVhdGVzLCBzbyBhXG4gICAgICAvLyBXb3JsZCBjYW4gZm9sZCB0aGVtIGludG8gb25lIGJvcm4tcnVubmluZyBjcmVhdGUuXG4gICAgICBjb25zdCBwYWlyRm9sZGVkID1cbiAgICAgICAgaW5saW5lUGFpckZvbGRFbGlnaWJsZSAmJlxuICAgICAgICBsYXp5SW5saW5lQ29ycmVsYXRpb25JZHMuaGFzKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKTtcbiAgICAgIGNvbnN0IHN0ZXBPcmRlciA9IGJhdGNoT3JkZXJDb3VudGVyO1xuICAgICAgYmF0Y2hPcmRlckNvdW50ZXIgKz0gcGFpckZvbGRlZCA/IDIgOiAxO1xuICAgICAgY29uc3Qgc3RlcE9wID0gKGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGRlaHlkcmF0ZWRJbnB1dDogU2VyaWFsaXplZERhdGE7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgZGVoeWRyYXRlZElucHV0ID0gYXdhaXQgZGVoeWRyYXRlSW5wdXQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGFyZ3M6IHF1ZXVlSXRlbS5hcmdzLFxuICAgICAgICAgICAgICBjbG9zdXJlVmFyczogcXVldWVJdGVtLmNsb3N1cmVWYXJzLFxuICAgICAgICAgICAgICB0aGlzVmFsOiBxdWV1ZUl0ZW0udGhpc1ZhbCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHNvdXJjZTogJ3N0ZXBfaW5wdXQnLFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBpZiAoIVNlcmlhbGl6YXRpb25FcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAvLyBlLmcuIFJ1bnRpbWVEZWNyeXB0aW9uRXJyb3I6IGFuIFNESyBmYXVsdCwgbm90IGEgdXNlciB2YWx1ZVxuICAgICAgICAgICAgLy8gcHJvYmxlbS4gS2VlcCBpdHMgaWRlbnRpdHkgKFJVTlRJTUVfRVJST1IpIGFuZCBjdXJyZW50XG4gICAgICAgICAgICAvLyBmYWlsLXRoZS1zdXNwZW5zaW9uIGJlaGF2aW9yLlxuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoIXN0ZXBEaXNwYXRjaCkge1xuICAgICAgICAgICAgLy8gTm8gZGlzcGF0Y2ggdGFyZ2V0IG1lYW5zIG5vIHJlcGxheSB3aWxsIG9ic2VydmUgYVxuICAgICAgICAgICAgLy8gZmluYWxpemF0aW9uOiB0aGlzIGlzIHRoZSB0ZXJtaW5hbCBkcmFpbiAob3IgYSBjcmVhdGUtb25seVxuICAgICAgICAgICAgLy8gdGVzdCBjYWxsZXIpLiBUaGUgcnVuIGlzIGFscmVhZHkgY29tcGxldGluZy9mYWlsaW5nLCBzb1xuICAgICAgICAgICAgLy8gd3JpdGluZyBzdGVwX2NyZWF0ZWQgKyBzdGVwX2ZhaWxlZCBoZXJlIHdvdWxkIGxlYXZlIGUuZy4gYVxuICAgICAgICAgICAgLy8gQ09NUExFVEVEIHJ1biBjYXJyeWluZyBhIGZhaWxlZCBzdGVwIG5vdGhpbmcgY2FuIGV2ZXJcbiAgICAgICAgICAgIC8vIG9ic2VydmUsIHJlYWRpbmcgYXMgYSBidWcgZnJvbSB0aGUgZGFzaGJvYXJkLiBSZXRocm93XG4gICAgICAgICAgICAvLyBpbnN0ZWFkOyB0aGUgZHJhaW4ncyBvd24gY2F0Y2ggc3dhbGxvd3MgaXQsIHByZXNlcnZpbmcgaXRzXG4gICAgICAgICAgICAvLyBwcmUtZXhpc3RpbmcgYmVoYXZpb3IgKG5vIHJvd3MgZm9yIHRoZSB1bmF3YWl0ZWQgc3RlcCkuXG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICAgIGF3YWl0IGZpbmFsaXplVW5zZXJpYWxpemFibGVTdGVwKHF1ZXVlSXRlbSwgZXJyKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gRGVmZXJyZWQgKGxhenkpIGlubGluZSBzdGVwOiBza2lwIHRoZSBzdGVwX2NyZWF0ZWQgd3JpdGUg4oCUIHRoZVxuICAgICAgICAvLyBjYWxsZXIncyBpbmxpbmUgZXhlY3V0ZVN0ZXAgd2lsbCBzZW5kIGEgbGF6eSBzdGVwX3N0YXJ0ZWQgY2FycnlpbmdcbiAgICAgICAgLy8gdGhpcyBpbnB1dCwgYW5kIHRoZSB3b3JsZCBjcmVhdGVzIHRoZSBzdGVwIChlbnRpdHkgKyBzeW50aGV0aWNcbiAgICAgICAgLy8gc3RlcF9jcmVhdGVkIGV2ZW50KSBhdG9taWNhbGx5LiBXZSBkbyBOT1QgYWRkIGl0IHRvXG4gICAgICAgIC8vIGNyZWF0ZWRTdGVwQ29ycmVsYXRpb25JZHM7IG93bmVyc2hpcCBpcyBkZWNpZGVkIGJ5IHRoYXQgbGF6eVxuICAgICAgICAvLyBzdGVwX3N0YXJ0ZWQncyBhdG9taWMgY3JlYXRlLWNsYWltIGluc3RlYWQuXG4gICAgICAgIGlmIChsYXp5SW5saW5lQ29ycmVsYXRpb25JZHMuaGFzKHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkKSkge1xuICAgICAgICAgIGxhenlJbmxpbmVCeUNvcnJlbGF0aW9uSWQuc2V0KHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLCB7XG4gICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgIHN0ZXBOYW1lOiBxdWV1ZUl0ZW0uc3RlcE5hbWUsXG4gICAgICAgICAgICBkZWh5ZHJhdGVkSW5wdXQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHBhaXJGb2xkZWQpIHtcbiAgICAgICAgICAgIC8vIEVucXVldWUgdGhlIHBhaXIgdGhlIGRlZmVycmFsIHdvdWxkIG90aGVyd2lzZSBsZWF2ZSB0byB0aGVcbiAgICAgICAgICAgIC8vIGNhbGxlcidzIGxhenkgYHN0ZXBfc3RhcnRlZGA6IHRoZSBjcmVhdGVkIHJvdyBjYXJyaWVzIHRoZVxuICAgICAgICAgICAgLy8gaW5wdXQgKHBheWxvYWRzIHJpZGUgY3JlYXRlcyBpbiBhIGJhdGNoKSwgdGhlIHN0YXJ0ZWQgcm93IGlzXG4gICAgICAgICAgICAvLyBiYXJlIGFuZCBzdGFtcHMgdGhpcyBpbnZvY2F0aW9uJ3Mgb3duZXJzaGlwLCB0aGUgc2FtZSBjbGFpbVxuICAgICAgICAgICAgLy8gc2hhcGUgdGhlIGxhenkgc3RhcnQgd291bGQgaGF2ZSBzZW50LCBzZXR0bGVkIGJ5IHRoZSBiYXRjaC5cbiAgICAgICAgICAgIGJhdGNoUXVldWUucHVzaCh7XG4gICAgICAgICAgICAgIG9yZGVyOiBzdGVwT3JkZXIsXG4gICAgICAgICAgICAgIGtpbmQ6ICdpbmxpbmUtY3JlYXRlZCcsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICBldmVudDoge1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfY3JlYXRlZCcsXG4gICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgIGlucHV0OiBkZWh5ZHJhdGVkSW5wdXQgYXMgU2VyaWFsaXplZERhdGEsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgYmF0Y2hRdWV1ZS5wdXNoKHtcbiAgICAgICAgICAgICAgb3JkZXI6IHN0ZXBPcmRlciArIDEsXG4gICAgICAgICAgICAgIGtpbmQ6ICdpbmxpbmUtc3RhcnRlZCcsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICBldmVudDoge1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfc3RhcnRlZCcsXG4gICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgIC8vIENoZWNrZWQgYnkgaW5saW5lUGFpckZvbGRFbGlnaWJsZTsgc3ByZWFkIGtlZXBzIHRoZVxuICAgICAgICAgICAgICAgICAgLy8gbmFycm93LXRocm91Z2gtY2xvc3VyZSBwcm9ibGVtIGF3YXkgZnJvbSB0aGUgdHlwZS5cbiAgICAgICAgICAgICAgICAgIC4uLihvd25lck1lc3NhZ2VJZCAhPT0gdW5kZWZpbmVkID8geyBvd25lck1lc3NhZ2VJZCB9IDoge30pLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHN0ZXBFdmVudDogQ3JlYXRlRXZlbnRSZXF1ZXN0ID0ge1xuICAgICAgICAgIGV2ZW50VHlwZTogJ3N0ZXBfY3JlYXRlZCcgYXMgY29uc3QsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuLndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgIGlucHV0OiBkZWh5ZHJhdGVkSW5wdXQgYXMgU2VyaWFsaXplZERhdGEsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBSZXNpbGllbnQgc3RlcCBkaXNwYXRjaDogZmlyZSB0aGUgc3RlcF9jcmVhdGVkIHdyaXRlIGFuZCB0aGVcbiAgICAgICAgLy8gc3RlcC1leGVjdXRpb24gcXVldWUgcHVibGlzaCBpbiBwYXJhbGxlbDogdGhlIG1lc3NhZ2UgY2FycmllcyB0aGVcbiAgICAgICAgLy8gc2FtZSBzZXJpYWxpemVkIGlucHV0IChgc3RlcElucHV0YCkgc28gdGhlIGNvbnN1bWVyIGNhblxuICAgICAgICAvLyBpZGVtcG90ZW50bHkgcmUtZW5zdXJlIHRoZSBldmVudCBpZiB0aGUgZGlyZWN0IHdyaXRlIGZhaWxlZFxuICAgICAgICAvLyB0cmFuc2llbnRseS4gTWlycm9ycyB0aGUgcmVzaWxpZW50IHN0YXJ0IChgcnVuSW5wdXRgKSBhbmRcbiAgICAgICAgLy8gcmVzaWxpZW50IGhvb2sgcmVzdW1lIChgaG9va0lucHV0YCkgcGF0dGVybnMuIE9ubHkgZm9yIGlucHV0cyB0aGVcbiAgICAgICAgLy8gcXVldWUgbWVzc2FnZSBjYW4gc2FmZWx5IGNhcnJ5IChiaW5hcnksIHVuZGVyIHRoZSBWUVMgc2l6ZSBjYXApLlxuICAgICAgICBpZiAoXG4gICAgICAgICAgcmVzaWxpZW50RGlzcGF0Y2hFbGlnaWJsZSAmJlxuICAgICAgICAgIGRlaHlkcmF0ZWRJbnB1dCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgJiZcbiAgICAgICAgICBkZWh5ZHJhdGVkSW5wdXQuYnl0ZUxlbmd0aCA8PSBNQVhfUkVTSUxJRU5UX1NURVBfSU5QVVRfQllURVNcbiAgICAgICAgKSB7XG4gICAgICAgICAgYXdhaXQgZW5zdXJlUnVuUmVhZHkoKTtcbiAgICAgICAgICBjb25zdCB0cmFjZUNhcnJpZXIgPSBhd2FpdCBnZXRTdGVwRGlzcGF0Y2hUcmFjZUNhcnJpZXIoKTtcbiAgICAgICAgICBjb25zdCBbY3JlYXRlUmVzdWx0LCBxdWV1ZVJlc3VsdF0gPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgICAgICAgICAgY3JlYXRlR3VhcmRlZChzdGVwRXZlbnQsIHsgcmVxdWVzdElkIH0pLFxuICAgICAgICAgICAgcXVldWVNZXNzYWdlKFxuICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3R5bGUvbm9Ob25OdWxsQXNzZXJ0aW9uOiBpbXBsaWVkIGJ5IHJlc2lsaWVudERpc3BhdGNoRWxpZ2libGVcbiAgICAgICAgICAgICAgc3RlcERpc3BhdGNoIS5xdWV1ZU5hbWUsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICBzdGVwSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgIHN0ZXBOYW1lOiBxdWV1ZUl0ZW0uc3RlcE5hbWUsXG4gICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyLFxuICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgIHN0ZXBJbnB1dDogeyBpbnB1dDogZGVoeWRyYXRlZElucHV0IH0sXG4gICAgICAgICAgICAgICAgcnVuQ29udGV4dDogcnVuRGlzcGF0Y2hDb250ZXh0KHJ1biksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIC8vIFNhbWUga2V5IGFzIHRoZSBjYWxsZXIncyBkaXNwYXRjaCBwYXNzIGFuZCBhbnkgY29uY3VycmVudFxuICAgICAgICAgICAgICAvLyBoYW5kbGVyJ3MsIHNvIHJlZHVuZGFudCBwdWJsaXNoZXMgZm9yIHRoaXMgc3RlcCBkZWR1cGUuIFRoZVxuICAgICAgICAgICAgICAvLyBrZXkgaXMgc3RlcC1pZGVudGl0eS1zY29wZWQgc28gYSByZXZva2VkIG1lc3NhZ2UgZm9yIGFcbiAgICAgICAgICAgICAgLy8gcmVhc3NpZ25lZCBjb3JyZWxhdGlvbiBpZCBjYW5ub3QgYWJzb3JiIHRoZSBjb3JyZWN0ZWRcbiAgICAgICAgICAgICAgLy8gc2NoZWR1bGUncyBkaXNwYXRjaDogc2VlIHN0ZXBEaXNwYXRjaElkZW1wb3RlbmN5S2V5LlxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaWRlbXBvdGVuY3lLZXk6IHN0ZXBEaXNwYXRjaElkZW1wb3RlbmN5S2V5KFxuICAgICAgICAgICAgICAgICAgcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICBxdWV1ZUl0ZW0uc3RlcE5hbWVcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApLFxuICAgICAgICAgIF0pO1xuICAgICAgICAgIC8vIFF1ZXVlIGZhaWx1cmUgaXMgYWx3YXlzIGZhdGFsIGZvciB0aGlzIHN1c3BlbnNpb24gcGFzczogd2l0aG91dFxuICAgICAgICAgIC8vIHRoZSBtZXNzYWdlIHRoZSBzdGVwIHdvdWxkIHJlbHkgb24gdGhlIGNyZWF0ZSBhbG9uZSwgYW5kIGlmIHRoZVxuICAgICAgICAgIC8vIGNyZWF0ZSBBTFNPIGZhaWxlZCB0aGVyZSB3b3VsZCBiZSBubyBkdXJhYmxlIHJlY29yZCBhdCBhbGwuXG4gICAgICAgICAgLy8gUHJvcGFnYXRpbmcgcmVkZWxpdmVycyB0aGUgb3JjaGVzdHJhdG9yIG1lc3NhZ2UsIHdoaWNoXG4gICAgICAgICAgLy8gcmUtY3JlYXRlcyB0aGUgKGlkZW1wb3RlbnQpIHN0ZXBfY3JlYXRlZCBhbmQgcmUtZGlzcGF0Y2hlcyxcbiAgICAgICAgICAvLyB0aGUgc2FtZSByZWNvdmVyeSBhcyB0aGUgc2VxdWVudGlhbCBwYXRoLlxuICAgICAgICAgIGlmIChxdWV1ZVJlc3VsdC5zdGF0dXMgPT09ICdyZWplY3RlZCcpIHtcbiAgICAgICAgICAgIHRocm93IHF1ZXVlUmVzdWx0LnJlYXNvbjtcbiAgICAgICAgICB9XG4gICAgICAgICAgcXVldWVkU3RlcENvcnJlbGF0aW9uSWRzLmFkZChxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgaWYgKGNyZWF0ZVJlc3VsdC5zdGF0dXMgPT09ICdyZWplY3RlZCcpIHtcbiAgICAgICAgICAgIGNvbnN0IGVyciA9IGNyZWF0ZVJlc3VsdC5yZWFzb247XG4gICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgIC8vIENvbmN1cnJlbnQgaGFuZGxlciB3cm90ZSBpdCBmaXJzdCwgc2FtZSBhcyB0aGUgc2VxdWVudGlhbFxuICAgICAgICAgICAgICAvLyBwYXRoLiBUaGUgc3RlcCBtZXNzYWdlIGlzIGFscmVhZHkgb3V0OyBhIGR1cGxpY2F0ZSBwdWJsaXNoXG4gICAgICAgICAgICAgIC8vIGJ5IHRoYXQgaGFuZGxlciBkZWR1cGVzIG9uIHRoZSBzaGFyZWQgaWRlbXBvdGVuY3kga2V5LlxuICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1N0ZXAgYWxyZWFkeSBleGlzdHMsIGNvbnRpbnVpbmcnLCB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc1JldHJ5YWJsZVdvcmxkRXJyb3IoZXJyKSkge1xuICAgICAgICAgICAgICAvLyBSZXNpbGllbnQ6IHRoZSB3cml0ZSBmYWlsZWQgdHJhbnNpZW50bHkgKDQyOSAvIDV4eCAvXG4gICAgICAgICAgICAgIC8vIHRyYW5zcG9ydCkgYnV0IHRoZSBzdGVwIG1lc3NhZ2UgKGNhcnJ5aW5nIHRoZSBzYW1lXG4gICAgICAgICAgICAgIC8vIHNlcmlhbGl6ZWQgaW5wdXQpIHdhcyBwdWJsaXNoZWQsIHNvIHRoZSBjb25zdW1lclxuICAgICAgICAgICAgICAvLyBpZGVtcG90ZW50bHkgcmUtZW5zdXJlcyB0aGUgc3RlcF9jcmVhdGVkIGJlZm9yZSBleGVjdXRpbmcuXG4gICAgICAgICAgICAgIHJlc2lsaWVudERpc3BhdGNoUmVjb3ZlcmVkKys7XG4gICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAnU3RlcCBjcmVhdGlvbiBldmVudCB3cml0ZSBmYWlsZWQsIGJ1dCB0aGUgc3RlcCB3YXMgJyArXG4gICAgICAgICAgICAgICAgICAnZGlzcGF0Y2hlZCB2aWEgdGhlIHF1ZXVlLiBUaGUgc3RlcF9jcmVhdGVkIGV2ZW50IHdpbGwgJyArXG4gICAgICAgICAgICAgICAgICAnYmUgZW5zdXJlZCBieSB0aGUgcXVldWUgY29uc3VtZXIuJyxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjcmVhdGVkU3RlcENvcnJlbGF0aW9uSWRzLmFkZChxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChiYXRjaEZhbm91dEVsaWdpYmxlKSB7XG4gICAgICAgICAgLy8gRm9sZCBpbnRvIHRoZSBiYXRjaCBpbnN0ZWFkIG9mIHdyaXRpbmcgaGVyZS4gVGhlIGVuY2xvc2luZ1xuICAgICAgICAgIC8vIHByb21pc2Ugam9pbnMgYGJhdGNoUHJlcHNgIChzZWUgdGhlIGxvb3AgYmVsb3cpLCBzbyB0aGUgZmx1c2hcbiAgICAgICAgICAvLyBvcCBjYW5ub3QgcnVuIGJlZm9yZSB0aGlzIHN0ZXAncyBpbnB1dCBmaW5pc2hlZCBkZWh5ZHJhdGluZy5cbiAgICAgICAgICBiYXRjaFF1ZXVlLnB1c2goe1xuICAgICAgICAgICAgb3JkZXI6IHN0ZXBPcmRlcixcbiAgICAgICAgICAgIGtpbmQ6ICdzdGVwJyxcbiAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgc3RlcE5hbWU6IHF1ZXVlSXRlbS5zdGVwTmFtZSxcbiAgICAgICAgICAgIGV2ZW50OiBzdGVwRXZlbnQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBlbnN1cmVSdW5SZWFkeSgpO1xuICAgICAgICAgIGF3YWl0IGNyZWF0ZUd1YXJkZWQoc3RlcEV2ZW50LCB7IHJlcXVlc3RJZCB9KTtcbiAgICAgICAgICBjcmVhdGVkU3RlcENvcnJlbGF0aW9uSWRzLmFkZChxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbygnU3RlcCBhbHJlYWR5IGV4aXN0cywgY29udGludWluZycsIHtcbiAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSgpO1xuICAgICAgb3BzLnB1c2goc3RlcE9wKTtcbiAgICAgIGlmIChiYXRjaEZhbm91dEVsaWdpYmxlKSB7XG4gICAgICAgIC8vIFRoZSBmbHVzaCBvcCB3YWl0cyBmb3IgZXZlcnkgcHJlcCBiZWZvcmUgY29tbWl0dGluZzsgYSBwcmVwIHRoYXRcbiAgICAgICAgLy8gcmVqZWN0ZWQgYWxyZWFkeSBzdXJmYWNlcyB0aHJvdWdoIGBvcHNgLCBzbyB0aGUgZmx1c2gncyBvd24gd2FpdFxuICAgICAgICAvLyBzd2FsbG93cyBpdCBhbmQgY29tbWl0cyB3aGF0ZXZlciB3YXMgc3VjY2Vzc2Z1bGx5IGVucXVldWVkLFxuICAgICAgICAvLyBwcmVzZXJ2aW5nIHRvZGF5J3MgcGVyLW9wIGluZGVwZW5kZW5jZS5cbiAgICAgICAgYmF0Y2hQcmVwcy5wdXNoKHN0ZXBPcC5jYXRjaCgoKSA9PiB7fSkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIENyZWF0ZSB3YWl0IGV2ZW50cyAoc2FtZSBhcyBWMSlcbiAgZm9yIChjb25zdCBxdWV1ZUl0ZW0gb2Ygd2FpdEl0ZW1zKSB7XG4gICAgaWYgKCFxdWV1ZUl0ZW0uaGFzQ3JlYXRlZEV2ZW50KSB7XG4gICAgICBjb25zdCB3YWl0RXZlbnQ6IENyZWF0ZUV2ZW50UmVxdWVzdCA9IHtcbiAgICAgICAgZXZlbnRUeXBlOiAnd2FpdF9jcmVhdGVkJyBhcyBjb25zdCxcbiAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgcmVzdW1lQXQ6IHF1ZXVlSXRlbS5yZXN1bWVBdCxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBpZiAoYmF0Y2hGYW5vdXRFbGlnaWJsZSkge1xuICAgICAgICAvLyBXYWl0cyBuZWVkIG5vIGRlaHlkcmF0aW9uLCBzbyB0aGV5IGVucXVldWUgc3luY2hyb25vdXNseSwgYWZ0ZXJcbiAgICAgICAgLy8gZXZlcnkgc3RlcCdzIG9yZGVyIHNsb3QsIHByZXNlcnZpbmcgc3RlcHMtdGhlbi13YWl0cyBzY2hlZHVsaW5nXG4gICAgICAgIC8vIG9yZGVyIGluIHRoZSBsb2cuXG4gICAgICAgIGJhdGNoUXVldWUucHVzaCh7XG4gICAgICAgICAgb3JkZXI6IGJhdGNoT3JkZXJDb3VudGVyKyssXG4gICAgICAgICAga2luZDogJ3dhaXQnLFxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHF1ZXVlSXRlbS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGV2ZW50OiB3YWl0RXZlbnQsXG4gICAgICAgIH0pO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIG9wcy5wdXNoKFxuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBlbnN1cmVSdW5SZWFkeSgpO1xuICAgICAgICAgICAgYXdhaXQgY3JlYXRlR3VhcmRlZCh3YWl0RXZlbnQsIHsgcmVxdWVzdElkIH0pO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1dhaXQgYWxyZWFkeSBleGlzdHMsIGNvbnRpbnVpbmcnLCB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogcXVldWVJdGVtLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSkoKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBUaGUgYmF0Y2hlZCBmb2xkJ3MgZmx1c2g6IHRoZSBjbGVhbiBmYW4tb3V0IGNvbW1pdHMgdGhyb3VnaFxuICAvLyBgY3JlYXRlQmF0Y2hgIGluIGNodW5rcyBvZiBNQVhfQkFUQ0hfRkFOT1VUX0VWRU5UUywgYWxsIGNodW5rcyBJTlxuICAvLyBGTElHSFQgQ09OQ1VSUkVOVExZLiBTbG90IGFzc2lnbm1lbnQgaXMgdGhlIHNlcnZlcidzLCBzbyBwYXJhbGxlbFxuICAvLyBjaHVua3MgcmFjZSBmb3Igc2xvdCByYW5nZXMgZXhhY3RseSBsaWtlIHRoZSBwcmUtZm9sZCBwYXRoJ3MgcGFyYWxsZWxcbiAgLy8gc2luZ2xlIHdyaXRlcyBkaWQ7IGVudGl0eSBjb25kaXRpb25zLCBub3QgY29tbWl0IG9yZGVyLCBjYXJyeVxuICAvLyBjb3JyZWN0bmVzcyAoc2libGluZyBmYW4tb3V0IGV2ZW50cyBoYXZlIG5vIGNyb3NzLW9yZGVyIHRoZSByZXBsYXlcbiAgLy8gZGVwZW5kcyBvbjsgaXQgbWF0Y2hlcyBieSBjb3JyZWxhdGlvbiBpZCkuIEVhY2ggZXZlbnQgcmVwb3J0cyB0aGVcbiAgLy8gb3V0Y29tZSBpdHMgb3duIHNpbmdsZSBjcmVhdGUgd291bGQgaGF2ZSBoYWQ6IGEgNDA5IGlzIHRoZSBzYW1lXG4gIC8vIGFscmVhZHktZXhpc3RzIHRvbGVyYW5jZSBhcyB0aGUgc2luZ2xlIHBhdGgsIGFueXRoaW5nIGVsc2UgZmFpbHMgdGhlXG4gIC8vIGRlbGl2ZXJ5IHRoZSB3YXkgYSBzaW5nbGUtcGF0aCByZWplY3Rpb24gd291bGQuXG4gIC8vXG4gIC8vIExhdGVuY3kgc2hhcGU6IG9ubHkgdGhlIGNodW5rIGNhcnJ5aW5nIHRoZSBwcmUtY2xhaW1lZCBpbmxpbmUgcGFpcnNcbiAgLy8gZ2F0ZXMgdGhlIGhhbmRsZXIncyByZXR1cm4gKHRoZSBjYWxsZXIgc3RhcnRzIGJvZGllcyBvZmYgaXRzIGNsYWltcyksXG4gIC8vIGFuZCB0aGF0IGNodW5rIGNhcnJpZXMgTk9USElORyBlbHNlLCBzbyBpdHMgY29tbWl0IGlzIGFzIHNtYWxsIGFzIHRoZVxuICAvLyBpbmxpbmUgc2xpY2UgKHNlZSB0aGUgY2h1bmtpbmcgYmVsb3cpLlxuICAvLyBFdmVyeSBvdGhlciBjaHVuaydzIGNvbW1pdCAoYW5kIGV2ZXJ5IGNodW5rJ3Mgc3RlcC1tZXNzYWdlIHB1Ymxpc2hlcyxcbiAgLy8gd2hpY2ggZmlyZSB0aGUgbW9tZW50IElUUyBjcmVhdGVzIGFyZSBkdXJhYmxlKSByaWRlc1xuICAvLyBgZGVmZXJyZWRCYXRjaFdvcmtgIHdoZW4gdGhlIGNhbGxlciBvcHRlZCBpbiwgam9pbmVkIGJlZm9yZSBhY2suIEEgc2xvd1xuICAvLyBzaWJsaW5nIGNodW5rIHRoZXJlZm9yZSBkZWxheXMgbmVpdGhlciB0aGUgaW5saW5lIGJvZGllcyBub3IgYW5vdGhlclxuICAvLyBjaHVuaydzIHF1ZXVlIG1lc3NhZ2VzLCB3aGlsZSBwdWJsaXNoLWFmdGVyLWNyZWF0ZSBzdGlsbCBob2xkcyBwZXJcbiAgLy8gc3RlcDogYSBzdGVwJ3MgbWVzc2FnZSBpcyBvbmx5IGV2ZXIgc2VudCBhZnRlciB0aGUgY2h1bmsgY2FycnlpbmcgaXRzXG4gIC8vIGNyZWF0ZSBoYXMgY29tbWl0dGVkLlxuICBsZXQgZGVmZXJyZWRCYXRjaFdvcms6IFByb21pc2U8dm9pZD4gfCB1bmRlZmluZWQ7XG4gIGlmIChiYXRjaEZhbm91dEVsaWdpYmxlKSB7XG4gICAgb3BzLnB1c2goXG4gICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyBQcmVwcyB0aGF0IHJlamVjdGVkIGFscmVhZHkgc3VyZmFjZSB0aHJvdWdoIHRoZWlyIG93biBgb3BzYFxuICAgICAgICAvLyBlbnRyaWVzOyB0aGUgZm9sZCBjb21taXRzIHdoYXRldmVyIHdhcyBzdWNjZXNzZnVsbHkgZW5xdWV1ZWQsXG4gICAgICAgIC8vIHByZXNlcnZpbmcgdG9kYXkncyBwZXItb3AgaW5kZXBlbmRlbmNlLlxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaFByZXBzKTtcbiAgICAgICAgaWYgKGJhdGNoUXVldWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBbLi4uYmF0Y2hRdWV1ZV0uc29ydCgoYSwgYikgPT4gYS5vcmRlciAtIGIub3JkZXIpO1xuICAgICAgICBhd2FpdCBlbnN1cmVSdW5SZWFkeSgpO1xuICAgICAgICAvLyBUaGUgb3JkaW5hcnkgc2luZ2xlIHBhdGggZm9yIGEgbG9uZSBwbGFpbiBlbnRyeTogYSBiYXRjaCBvZiBPTkVcbiAgICAgICAgLy8gZ2FpbnMgbm90aGluZyBvdmVyIHRoZSBzaW5nbGUgd3JpdGUgKHNhbWUgcm91bmQgdHJpcCkgYW5kIGxvc2VzXG4gICAgICAgIC8vIHRoZSBzbG90LXNuYXBzaG90IHBhcmFtcyArIGJ1bXAtYW5kLXJlcG9ydCB0aGF0IGNyZWF0ZUd1YXJkZWRcbiAgICAgICAgLy8gcHJvdmlkZXMsIHNvIGEgbG9uZSBlYWdlciBldmVudCBpcyB3cml0dGVuIHRoZSB3YXkgaXQgd291bGQgaGF2ZVxuICAgICAgICAvLyBiZWVuIHdpdGhvdXQgdGhlIGZvbGQsIHdpdGggdGhlIHNhbWUgY29uZmxpY3QgdG9sZXJhbmNlIGFuZFxuICAgICAgICAvLyBvd25lcnNoaXAgYm9va2tlZXBpbmcuIFVzZWQgd2hlbiB0aGUgd2hvbGUgZm9sZCBpcyBvbmUgZW50cnlcbiAgICAgICAgLy8gKGJlbG93KSBhbmQgd2hlbiB0aGUgcGxhaW4gcGFydGl0aW9uIGJlc2lkZSB0aGUgcGFpcnMgaXMgb25lXG4gICAgICAgIC8vIGVudHJ5ICh0aGUgY2h1bmtpbmcgZnVydGhlciBkb3duKS4gQmVzaWRlIGEgcGFpciBjaHVuayBpdCBjb21taXRzXG4gICAgICAgIC8vIGNvbmN1cnJlbnRseSB3aXRoIHRoZSBoYW5kbGVyJ3MgcmV0dXJuLCBsaWtlIGEgdHJhaWxpbmcgY2h1bms7IHRoZVxuICAgICAgICAvLyBpbmxpbmUgYm9kaWVzIGRvIG5vdCBkZXBlbmQgb24gaXQgKGV4ZWN1dG9yIHdyaXRlcyBjYXJyeSBubyBzbG90XG4gICAgICAgIC8vIHNuYXBzaG90LCBzbyB0aGVyZSBpcyBubyBwb3NpdGlvbiBmb3IgaXQgdG8gbW92ZSkuXG4gICAgICAgIGNvbnN0IGNvbW1pdFNpbmdsZSA9IGFzeW5jIChcbiAgICAgICAgICBlbnRyeTogKHR5cGVvZiBlbnRyaWVzKVtudW1iZXJdXG4gICAgICAgICk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBjcmVhdGVHdWFyZGVkKGVudHJ5LmV2ZW50LCB7IHJlcXVlc3RJZCB9KTtcbiAgICAgICAgICAgIGlmIChlbnRyeS5raW5kID09PSAnc3RlcCcpIHtcbiAgICAgICAgICAgICAgY3JlYXRlZFN0ZXBDb3JyZWxhdGlvbklkcy5hZGQoZW50cnkuY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICBlbnRyeS5raW5kID09PSAnc3RlcCdcbiAgICAgICAgICAgICAgICAgID8gJ1N0ZXAgYWxyZWFkeSBleGlzdHMsIGNvbnRpbnVpbmcnXG4gICAgICAgICAgICAgICAgICA6ICdXYWl0IGFscmVhZHkgZXhpc3RzLCBjb250aW51aW5nJyxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGVudHJ5LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBpZiAoZW50cmllcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBhd2FpdCBjb21taXRTaW5nbGUoZW50cmllc1swXSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNlZWQgZm9yIHRoZSBmb3JlaWduLWludGVybGVhdmluZyBkaWFnbm9zdGljIGJlbG93LiBXaXRoIGNodW5rc1xuICAgICAgICAvLyBjb21taXR0aW5nIGluIHBhcmFsbGVsIHRoZXJlIGlzIG5vIHBlci1jaHVuayBcImV4cGVjdGVkIG5leHQgc2xvdFwiO1xuICAgICAgICAvLyB0aGUgd2hvbGUgZm9sZCdzIGNvbW1pdHRlZCBzcGFuIGlzIGNvbXBhcmVkIGFnYWluc3QgdGhlIHNlZWRcbiAgICAgICAgLy8gb25jZSBldmVyeSBjaHVuayBoYXMgc2V0dGxlZDogY29tbWl0dGVkIHNsb3RzIGFyZSBkZW5zZSBwZXIgdGhlXG4gICAgICAgIC8vIFdvcmxkJ3MgaW52YXJpYW50LCBzbyBhbnkgZXhjZXNzIG9mIChtYXggY29tbWl0dGVkIHNsb3Qg4oiSIHNlZWQgK1xuICAgICAgICAvLyAxKSBvdmVyIHRoZSBmb2xkJ3Mgb3duIGNvbW1pdHRlZCBjb3VudCBpcyBldmVudHMgT1RIRVIgd3JpdGVyc1xuICAgICAgICAvLyBsYW5kZWQgaW4gYmV0d2Vlbi5cbiAgICAgICAgY29uc3QgZXhwZWN0ZWRGaXJzdFNsb3QgPSBldmVudExvZ1xuICAgICAgICAgID8gKG1heEV2ZW50U2xvdChldmVudExvZy5ldmVudHMpID8/IDApICsgMVxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAvLyBQYWlyLWF3YXJlIGNodW5raW5nLiBUd28gcnVsZXM6XG4gICAgICAgIC8vXG4gICAgICAgIC8vIDEuIEEgcHJlLWNsYWltZWQgcGFpcidzIHR3byByb3dzIG11c3QgbGFuZCBpbiB0aGUgc2FtZSBjcmVhdGVCYXRjaFxuICAgICAgICAvLyAgICBjYWxsIChhZGphY2VudCwgc28gYSBXb3JsZCBjYW4gZm9sZCB0aGVtIGludG8gb25lIGJvcm4tcnVubmluZ1xuICAgICAgICAvLyAgICBjcmVhdGUpIGFuZCBuZXZlciBzdHJhZGRsZSBhIGNodW5rIGJvdW5kYXJ5LCB3aGljaCB3b3VsZCB0dXJuXG4gICAgICAgIC8vICAgIHRoZSBzdGFydGVkIHJvdyBpbnRvIGEgc3RhbmRhbG9uZSBjbGFpbSByYWNpbmcgaXRzIG93blxuICAgICAgICAvLyAgICBjcmVhdGUncyBjb21taXQuXG4gICAgICAgIC8vIDIuIFRoZSBwYWlycyBjb21taXQgaW4gY2h1bmsocykgb2YgVEhFSVIgT1dOLCBhaGVhZCBvZiB0aGUgcGxhaW5cbiAgICAgICAgLy8gICAgYHN0ZXBgL2B3YWl0YCBjcmVhdGVzLCB3aGljaCBmaWxsIHRoZSBzdWJzZXF1ZW50IGNodW5rcy4gVGhlXG4gICAgICAgIC8vICAgIHBhaXIgY2h1bmsgaXMgdGhlIG9uZSBjb21taXQgdGhlIGlubGluZSBib2RpZXMgd2FpdCBmb3IgKHNlZVxuICAgICAgICAvLyAgICBgcGFpckNvbW1pdHNgIGJlbG93KSwgYW5kIG9uIHRoZSBWZXJjZWwgYmFja2VuZCBpdHMgbGF0ZW5jeVxuICAgICAgICAvLyAgICBzY2FsZXMgd2l0aCB0aGUgdHJhbnNhY3Rpb24ncyBpdGVtIGNvdW50OiBtZWFzdXJlZCBvbiAzMi1icmFuY2hcbiAgICAgICAgLy8gICAgZmFuLW91dHMsIGJhdGNoZXMgb2YgPD04IGV2ZW50cyBjb21taXQgaW4gfjU2IG1zIHA1MCBzZXJ2ZXItc2lkZVxuICAgICAgICAvLyAgICB3aGVyZSBiYXRjaGVzIG9mIDI0LTMyIGV2ZW50cyB0YWtlIH4xMTAgbXMuIFBhZGRpbmcgdGhlIHBhaXJcbiAgICAgICAgLy8gICAgY2h1bmsgd2l0aCBwbGFpbiBjcmVhdGVzIHVwIHRvIHRoZSBjYXAgdGhlcmVmb3JlIGhlbGQgdGhlXG4gICAgICAgIC8vICAgIGJvZGllcyBmb3IgdGhlIHBsYWluIGNyZWF0ZXMnIGNvbW1pdCwgd2hpY2ggbm90aGluZyBlbHNlXG4gICAgICAgIC8vICAgIG5lZWRlZDogYSBwbGFpbiBjcmVhdGUgZ2F0ZXMgb25seSBpdHMgb3duIHF1ZXVlIHB1Ymxpc2gsIGFuZFxuICAgICAgICAvLyAgICB0aGF0IGZpcmVzIG9mZiB3aGljaGV2ZXIgc2libGluZyBjaHVuayBjYXJyaWVzIGl0LiBTcGxpdHRpbmdcbiAgICAgICAgLy8gICAgdGhlbSBrZWVwcyB0aGUgcGFpciBjaHVuayBzbWFsbCAodHdvIHJvd3MgcGVyIGlubGluZSBzdGVwKSBhbmRcbiAgICAgICAgLy8gICAgbGV0cyB0aGUgcGxhaW4gY3JlYXRlcyBjb21taXQgY29uY3VycmVudGx5IGJlc2lkZSBpdC5cbiAgICAgICAgY29uc3QgY2h1bmtFbnRyaWVzID0gKGxpc3Q6IHR5cGVvZiBlbnRyaWVzKTogKHR5cGVvZiBlbnRyaWVzKVtdID0+IHtcbiAgICAgICAgICBjb25zdCBvdXQ6ICh0eXBlb2YgZW50cmllcylbXSA9IFtdO1xuICAgICAgICAgIGxldCBjdXJyZW50OiB0eXBlb2YgZW50cmllcyA9IFtdO1xuICAgICAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBsaXN0Lmxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgICAgICAgY29uc3QgZW50cnkgPSBsaXN0W2luZGV4XTtcbiAgICAgICAgICAgIGNvbnN0IG5leHQgPSBsaXN0W2luZGV4ICsgMV07XG4gICAgICAgICAgICBjb25zdCBwYWlyTGVhZCA9XG4gICAgICAgICAgICAgIGVudHJ5LmtpbmQgPT09ICdpbmxpbmUtY3JlYXRlZCcgJiZcbiAgICAgICAgICAgICAgbmV4dD8ua2luZCA9PT0gJ2lubGluZS1zdGFydGVkJyAmJlxuICAgICAgICAgICAgICBuZXh0LmNvcnJlbGF0aW9uSWQgPT09IGVudHJ5LmNvcnJlbGF0aW9uSWQ7XG4gICAgICAgICAgICBjb25zdCB0YWtlID0gcGFpckxlYWQgPyAyIDogMTtcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgY3VycmVudC5sZW5ndGggPiAwICYmXG4gICAgICAgICAgICAgIGN1cnJlbnQubGVuZ3RoICsgdGFrZSA+IE1BWF9CQVRDSF9GQU5PVVRfRVZFTlRTXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgb3V0LnB1c2goY3VycmVudCk7XG4gICAgICAgICAgICAgIGN1cnJlbnQgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGN1cnJlbnQucHVzaChlbnRyeSk7XG4gICAgICAgICAgICBpZiAocGFpckxlYWQpIHtcbiAgICAgICAgICAgICAgY3VycmVudC5wdXNoKG5leHQpO1xuICAgICAgICAgICAgICBpbmRleCsrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoY3VycmVudC5sZW5ndGggPiAwKSBvdXQucHVzaChjdXJyZW50KTtcbiAgICAgICAgICByZXR1cm4gb3V0O1xuICAgICAgICB9O1xuICAgICAgICAvLyBCb3RoIHBhcnRpdGlvbnMga2VlcCBgZW50cmllc2AnIG9yZGVyLCBzbyBhIHBhaXIncyB0d28gcm93c1xuICAgICAgICAvLyAoY29uc2VjdXRpdmUgYG9yZGVyYCB2YWx1ZXMsIGVucXVldWVkIHRvZ2V0aGVyKSBzdGF5IGFkamFjZW50IGluXG4gICAgICAgIC8vIHRoZSBwYWlyIHBhcnRpdGlvbi5cbiAgICAgICAgY29uc3QgaXNQYWlyUm93ID0gKGVudHJ5OiAodHlwZW9mIGVudHJpZXMpW251bWJlcl0pOiBib29sZWFuID0+XG4gICAgICAgICAgZW50cnkua2luZCA9PT0gJ2lubGluZS1jcmVhdGVkJyB8fCBlbnRyeS5raW5kID09PSAnaW5saW5lLXN0YXJ0ZWQnO1xuICAgICAgICBjb25zdCBwYWlyQ2h1bmtzID0gY2h1bmtFbnRyaWVzKFxuICAgICAgICAgIGVudHJpZXMuZmlsdGVyKChlbnRyeSkgPT4gaXNQYWlyUm93KGVudHJ5KSlcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgcGxhaW5FbnRyaWVzID0gZW50cmllcy5maWx0ZXIoKGVudHJ5KSA9PiAhaXNQYWlyUm93KGVudHJ5KSk7XG4gICAgICAgIC8vIEEgcGxhaW4gcGFydGl0aW9uIG9mIGV4YWN0bHkgT05FIGVudHJ5IGlzIHRoZSBiYXRjaC1vZi1vbmUgY2FzZVxuICAgICAgICAvLyBhZ2Fpbiwgbm93IHRoYXQgdGhlIHBhaXJzIG5vIGxvbmdlciBzaGFyZSBpdHMgY2h1bms6IGl0IHRha2VzIHRoZVxuICAgICAgICAvLyBzaW5nbGUgcGF0aCAoYGNvbW1pdFNpbmdsZWApIHJhdGhlciB0aGFuIGEgb25lLXJvdyBjcmVhdGVCYXRjaCxcbiAgICAgICAgLy8gYW5kIGlzIGNhcnJpZWQgYXMgYSBvbmUtZW50cnkgY2h1bmsgc28gdGhlIHBlci1jaHVuayBwdWJsaXNoIGFuZFxuICAgICAgICAvLyBzZXR0bGUgbWFjaGluZXJ5IGJlbG93IHRyZWF0cyBpdCBsaWtlIGFueSBzaWJsaW5nLiAoQSBvbmUtcm93XG4gICAgICAgIC8vIHJlbWFpbmRlciBvZiBhIExBUkdFUiBwbGFpbiBwYXJ0aXRpb24gc3RpbGwgYmF0Y2hlczogaXQgaXMgdGhlXG4gICAgICAgIC8vIHByZS1zcGxpdCBiZWhhdmlvciwgdW5jaGFuZ2VkIGhlcmUuKVxuICAgICAgICBjb25zdCBwbGFpbkNodW5rcyA9XG4gICAgICAgICAgcGxhaW5FbnRyaWVzLmxlbmd0aCA9PT0gMVxuICAgICAgICAgICAgPyBbcGxhaW5FbnRyaWVzXVxuICAgICAgICAgICAgOiBjaHVua0VudHJpZXMocGxhaW5FbnRyaWVzKTtcbiAgICAgICAgY29uc3Qgc2luZ2xlQ2h1bmsgPVxuICAgICAgICAgIHBsYWluRW50cmllcy5sZW5ndGggPT09IDEgPyBwbGFpbkNodW5rc1swXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgY2h1bmtzOiAodHlwZW9mIGVudHJpZXMpW10gPSBbLi4ucGFpckNodW5rcywgLi4ucGxhaW5DaHVua3NdO1xuICAgICAgICAvLyBTdGVwcyB3aG9zZSBxdWV1ZSBtZXNzYWdlcyBUSElTIEZMVVNIIHdpbGwgcHVibGlzaCAodGhlIGVhZ2VyXG4gICAgICAgIC8vIGNyZWF0ZXMpLCByZWNvcmRlZCBiZWZvcmUgYW55IGNodW5rIHNldHRsZXMgc28gdGhlIGNhbGxlcidzXG4gICAgICAgIC8vIGRpc3BhdGNoIHBhc3MgKHdoaWNoIHJ1bnMgb2ZmIHRoZSBoYW5kbGVyJ3MgcmV0dXJuKSBza2lwcyB0aGVtLlxuICAgICAgICAvLyBUaGUgc2VuZHMgYXJlIGd1YXJhbnRlZWQtb3ItZmFpbGVkIGJ5IHRoZSB0cmFpbGluZyB3b3JrIHRoZVxuICAgICAgICAvLyBjYWxsZXIgam9pbnMgYmVmb3JlIGFja2luZywgc28gXCJ3aWxsIGJlIHB1Ymxpc2hlZCBieSB0aGlzIGZsdXNoXCJcbiAgICAgICAgLy8gYW5kIFwiYWxyZWFkeSBwdWJsaXNoZWRcIiBhcmUgZXF1aXZhbGVudCBmcm9tIHRoZSBjYWxsZXIncyBzaWRlLlxuICAgICAgICBjb25zdCBwdWJsaXNoRWFnZXJTdGVwcyA9IHN0ZXBEaXNwYXRjaCAhPT0gdW5kZWZpbmVkO1xuICAgICAgICBpZiAocHVibGlzaEVhZ2VyU3RlcHMpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5raW5kID09PSAnc3RlcCcpIHtcbiAgICAgICAgICAgICAgcXVldWVkU3RlcENvcnJlbGF0aW9uSWRzLmFkZChlbnRyeS5jb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUYWxsaWVzIGZvciB0aGUgZm9yZWlnbi1pbnRlcmxlYXZpbmcgZGlhZ25vc3RpYywgZm9sZGVkIGFjcm9zc1xuICAgICAgICAvLyB0aGUgY29uY3VycmVudCBjaHVua3MgYW5kIHJlYWQgb25jZSBhbGwgb2YgdGhlbSBzZXR0bGVkLlxuICAgICAgICBsZXQgY29tbWl0dGVkQ291bnQgPSAwO1xuICAgICAgICBsZXQgbWF4Q29tbWl0dGVkU2xvdDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuXG4gICAgICAgIGNvbnN0IGNvbW1pdENodW5rID0gYXN5bmMgKGNodW5rOiB0eXBlb2YgZW50cmllcyk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgIC8vIEFuY2hvcnMgZm9yIHRoZSBwcmUtY2xhaW1lZCBzdGVwcycgdGVsZW1ldHJ5OiB0aGUgUE9TVCBpbnN0YW50XG4gICAgICAgICAgLy8gaXMgdGhlIGNsYWltJ3MgXCJzdGFydCBQT1NUIHNlbnRcIiAoUlNGUydzIGVuZCksIHRoZSByZXR1cm4gaXMgdGhlXG4gICAgICAgICAgLy8gY2xhaW0ncyBjb21wbGV0aW9uIChUVFIncyBUNiksIHRoZSBzYW1lIHR3byBpbnN0YW50cyB0aGUgbGF6eVxuICAgICAgICAgIC8vIGNsYWltJ3Mgb3duIFBPU1Qgd291bGQgaGF2ZSBwcm9kdWNlZC5cbiAgICAgICAgICBjb25zdCBiYXRjaFBvc3RTZW50QXRNcyA9IERhdGUubm93KCk7XG4gICAgICAgICAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3R5bGUvbm9Ob25OdWxsQXNzZXJ0aW9uOiBiYXRjaEZhbm91dEVsaWdpYmxlIGltcGxpZXMgcHJlc2VuY2VcbiAgICAgICAgICBjb25zdCB7IHJlc3VsdHMgfSA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGVCYXRjaCEoXG4gICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgIGNodW5rLm1hcCgoZW50cnkpID0+ICh7XG4gICAgICAgICAgICAgIGV2ZW50OiBlbnRyeS5ldmVudCxcbiAgICAgICAgICAgICAgLy8gVGhlIHN0YXJ0ZWQgcm93IGlzIHRoZSBzdGVwJ3MgZXhlY3V0aW5nIGNsYWltLCBzbyBpdCBjYXJyaWVzXG4gICAgICAgICAgICAgIC8vIHRoZSBjb21wdXRlLWluc3RhbmNlIGF0dHJpYnV0aW9uIHRoZSBzaW5nbGUgY2xhaW0gc2VuZHMgdmlhXG4gICAgICAgICAgICAgIC8vIENyZWF0ZUV2ZW50UGFyYW1zLlxuICAgICAgICAgICAgICAuLi4oZW50cnkua2luZCA9PT0gJ2lubGluZS1zdGFydGVkJ1xuICAgICAgICAgICAgICAgID8geyBjb21wdXRlSW5zdGFuY2VJZDogQ09NUFVURV9JTlNUQU5DRV9JRCB9XG4gICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAvLyBQZXItd3JpdGUgcmVxdWVzdCBhdHRyaWJ1dGlvbiwgc2FtZSBhcyB0aGUgc2luZ2xlIHBhdGgnc1xuICAgICAgICAgICAgLy8gY3JlYXRlR3VhcmRlZCjigKYsIHsgcmVxdWVzdElkIH0pLlxuICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgY2xhaW1Db21wbGV0ZWRBdE1zID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBmb3IgKGNvbnN0IFtpbmRleCwgaXRlbV0gb2YgcmVzdWx0cy5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGVudHJ5ID0gY2h1bmtbaW5kZXhdO1xuICAgICAgICAgICAgaWYgKGl0ZW0uZXJyb3IgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICBpZiAoZW50cnkua2luZCA9PT0gJ3N0ZXAnKSB7XG4gICAgICAgICAgICAgICAgY3JlYXRlZFN0ZXBDb3JyZWxhdGlvbklkcy5hZGQoZW50cnkuY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAoZW50cnkua2luZCA9PT0gJ2lubGluZS1zdGFydGVkJykge1xuICAgICAgICAgICAgICAgIC8vIFRoZSBwYWlyIGNvbW1pdHRlZDogdGhpcyBpbnZvY2F0aW9uIG93bnMgdGhlIHN0ZXAgYW5kIHRoZVxuICAgICAgICAgICAgICAgIC8vIGNhbGxlciBydW5zIHRoZSBib2R5IHdpdGggbm8gY2xhaW0gb2YgaXRzIG93bi4gVGhlXG4gICAgICAgICAgICAgICAgLy8gcmVhZGJhY2sgZW50aXR5IGlzIGF1dGhvcml0YXRpdmUgd2hlcmUgcHJlc2VudDsgYSBXb3JsZFxuICAgICAgICAgICAgICAgIC8vIHRoYXQgb21pdHRlZCBpdCBnZXRzIHRoZSBzYW1lIGxvY2FsbHkgc3ludGhlc2l6ZWQgcnVubmluZ1xuICAgICAgICAgICAgICAgIC8vIGF0dGVtcHQtMSB0aGUgb3B0aW1pc3RpYyBwYXRoIGV4ZWN1dGVzIGFnYWluc3QuIEVpdGhlclxuICAgICAgICAgICAgICAgIC8vIHdheSB0aGUgaW5wdXQgaXMgcmUtYXR0YWNoZWQgbG9jYWxseTogYmF0Y2ggcmVzcG9uc2VzXG4gICAgICAgICAgICAgICAgLy8gcmV0dXJuIHJlZnMgbGF6aWx5LCBhbmQgdGhlIGJvZHkncyBoeWRyYXRpb24gd2FudHMgdGhlXG4gICAgICAgICAgICAgICAgLy8gZXhhY3QgYnl0ZXMgdGhlIHBhaXIncyBjcmVhdGVkIHJvdyBjYXJyaWVkLiAoVGhlIGNyZWF0ZWRcbiAgICAgICAgICAgICAgICAvLyByb3cncyBzdWNjZXNzIGlzIGRlbGliZXJhdGVseSBOT1QgbWVtYmVyc2hpcCBpblxuICAgICAgICAgICAgICAgIC8vIGNyZWF0ZWRTdGVwQ29ycmVsYXRpb25JZHM6IGZvciBpbmxpbmUgc3RlcHMgb3duZXJzaGlwIGlzXG4gICAgICAgICAgICAgICAgLy8gdGhlIHN0YXJ0ZWQgcm93J3MgdmVyZGljdCwgYW5kIHRoZSBjYWxsZXIncyBkaXNwYXRjaCBwYXNzXG4gICAgICAgICAgICAgICAgLy8gc2tpcHMgaW5saW5lIGNvcnJlbGF0aW9uIGlkcyByZWdhcmRsZXNzLilcbiAgICAgICAgICAgICAgICBjb25zdCBkZWh5ZHJhdGVkID0gbGF6eUlubGluZUJ5Q29ycmVsYXRpb25JZC5nZXQoXG4gICAgICAgICAgICAgICAgICBlbnRyeS5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZiAoZGVoeWRyYXRlZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAvLyBVbnJlYWNoYWJsZTogdGhlIHNhbWUgcHJlcCBvcCB0aGF0IGVucXVldWVkIHRoZSBwYWlyIHNldFxuICAgICAgICAgICAgICAgICAgLy8gdGhpcyBlbnRyeSwgYW5kIHRoZSBmbHVzaCBhd2FpdGVkIGV2ZXJ5IHByZXAgYWJvdmUuXG4gICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgLy8gTm90IGZyZWUgaWYgaXQgZXZlciBmaXJlcywgdGhvdWdoOiB0aGUgcGFpciBpcyBhbHJlYWR5XG4gICAgICAgICAgICAgICAgICAvLyBkdXJhYmxlIGhlcmUsIHNvIHRoaXMgdGhyb3dzIHdpdGggdGhlIHN0ZXAgY2xhaW1lZCBhbmRcbiAgICAgICAgICAgICAgICAgIC8vIGl0cyBib2R5IG5ldmVyIHJ1bi4gVGhlIGRlbGl2ZXJ5IGZhaWxzLCBhbmQgcmVkZWxpdmVyeVxuICAgICAgICAgICAgICAgICAgLy8gcmVjb3ZlcnMgaXQgdGhyb3VnaCBvd25lZC1yZWNvdmVyeSAodGhlIHN0ZXAgY2FycmllcyB0aGlzXG4gICAgICAgICAgICAgICAgICAvLyBtZXNzYWdlJ3Mgb3duZXJzaGlwIHN0YW1wKSByYXRoZXIgdGhhbiB0aGUgcmVxdWVzdCBqdXN0XG4gICAgICAgICAgICAgICAgICAvLyBmYWlsaW5nIGNsZWFubHkuXG4gICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dXb3JsZEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBgbm8gZGVoeWRyYXRlZCBpbnB1dCBmb3IgcHJlLWNsYWltZWQgc3RlcCAke2VudHJ5LmNvcnJlbGF0aW9uSWR9YCxcbiAgICAgICAgICAgICAgICAgICAgeyBzdGF0dXM6IDUwMCB9XG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0YXJ0ZWRTdGVwOiBTdGFydGVkU3RlcCA9IGl0ZW0uc3RlcD8uc3RhcnRlZEF0XG4gICAgICAgICAgICAgICAgICA/IHsgLi4uaXRlbS5zdGVwLCBzdGFydGVkQXQ6IGl0ZW0uc3RlcC5zdGFydGVkQXQgfVxuICAgICAgICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgc3RlcElkOiBlbnRyeS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICAgIHN0ZXBOYW1lOiBkZWh5ZHJhdGVkLnN0ZXBOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgIHN0YXR1czogJ3J1bm5pbmcnLFxuICAgICAgICAgICAgICAgICAgICAgIGF0dGVtcHQ6IDEsXG4gICAgICAgICAgICAgICAgICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgICAgICAgc3RhcnRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgaW5saW5lQ2xhaW1zLnNldChlbnRyeS5jb3JyZWxhdGlvbklkLCB7XG4gICAgICAgICAgICAgICAgICBvd25lZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgIHN0ZXA6IHtcbiAgICAgICAgICAgICAgICAgICAgLi4uc3RhcnRlZFN0ZXAsXG4gICAgICAgICAgICAgICAgICAgIGlucHV0OiBkZWh5ZHJhdGVkLmRlaHlkcmF0ZWRJbnB1dCxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICBiYXRjaFBvc3RTZW50QXRNcyxcbiAgICAgICAgICAgICAgICAgIGNsYWltQ29tcGxldGVkQXRNcyxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChpdGVtLnN0YXR1cyA9PT0gNDA5KSB7XG4gICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBlbnRyeS5raW5kID09PSAnaW5saW5lLWNyZWF0ZWQnIHx8XG4gICAgICAgICAgICAgICAgZW50cnkua2luZCA9PT0gJ2lubGluZS1zdGFydGVkJ1xuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgcGFpciBsb3N0IGl0cyBhdG9taWMgY3JlYXRlLWNsYWltOiBhIGNvbmN1cnJlbnQgd3JpdGVyXG4gICAgICAgICAgICAgICAgLy8gYWxyZWFkeSBvd25zIHRoaXMgc3RlcCAoYW4gZWFybGllciBkZWxpdmVyeSdzIGNyZWF0ZSwgb3IgYVxuICAgICAgICAgICAgICAgIC8vIHJhY2luZyBoYW5kbGVyJ3MgY2xhaW0pLiBSZWNvcmRlZCBhcyBhIGxvc3QgY2xhaW06IHRoZVxuICAgICAgICAgICAgICAgIC8vIGNhbGxlcidzIGV4ZWN1dGVTdGVwIHJldHVybnMgYHNraXBwZWRgIHdpdGhvdXQgcnVubmluZyB0aGVcbiAgICAgICAgICAgICAgICAvLyBib2R5LCB0aGUgc2FtZSBvdXRjb21lIGFzIGxvc2luZyB0aGUgbGF6eSBjbGFpbS4gQSBXb3JsZFxuICAgICAgICAgICAgICAgIC8vIHRoYXQgZm9sZHMgdGhlIHBhaXIgcmVwb3J0cyB0aGUgNDA5IG9uIGJvdGggcm93cyAoc2V0XG4gICAgICAgICAgICAgICAgLy8gdHdpY2UsIGhhcm1sZXNzKTsgb25lIHRoYXQgZXZhbHVhdGVzIHJvd3MgaW5kZXBlbmRlbnRseVxuICAgICAgICAgICAgICAgIC8vIGhhcyB0aGUgc3RhcnRlZCByb3cgKHByb2Nlc3NlZCBzZWNvbmQpIGRlY2lkZSwgd2hpY2ggaXNcbiAgICAgICAgICAgICAgICAvLyBleGFjdGx5IHRoZSBzaW5nbGUgcGF0aCdzIHNlbWFudGljcyAoY3JlYXRlIGxvc3QgKyBjbGFpbVxuICAgICAgICAgICAgICAgIC8vIHdvbiBzdGlsbCBydW5zIHRoZSBib2R5OyBjcmVhdGUgd29uICsgY2xhaW0gbG9zdCBza2lwcykuXG4gICAgICAgICAgICAgICAgaW5saW5lQ2xhaW1zLnNldChlbnRyeS5jb3JyZWxhdGlvbklkLCB7IG93bmVkOiBmYWxzZSB9KTtcbiAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ0lubGluZSBzdGVwIHByZS1jbGFpbSBsb3N0LCBjb250aW51aW5nJywge1xuICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBlbnRyeS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgbWVzc2FnZTogaXRlbS5tZXNzYWdlLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIFNhbWUgdG9sZXJhbmNlIGFzIHRoZSBzaW5nbGUgcGF0aCdzIEVudGl0eUNvbmZsaWN0RXJyb3I6IGFcbiAgICAgICAgICAgICAgLy8gY29uY3VycmVudCBvciBlYXJsaWVyIGRlbGl2ZXJ5IGFscmVhZHkgY3JlYXRlZCBpdC5cbiAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgIGVudHJ5LmtpbmQgPT09ICdzdGVwJ1xuICAgICAgICAgICAgICAgICAgPyAnU3RlcCBhbHJlYWR5IGV4aXN0cywgY29udGludWluZydcbiAgICAgICAgICAgICAgICAgIDogJ1dhaXQgYWxyZWFkeSBleGlzdHMsIGNvbnRpbnVpbmcnLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogZW50cnkuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGl0ZW0ubWVzc2FnZSxcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93V29ybGRFcnJvcihcbiAgICAgICAgICAgICAgYGJhdGNoZWQgJHtlbnRyeS5ldmVudC5ldmVudFR5cGV9IGZvciAke2VudHJ5LmNvcnJlbGF0aW9uSWR9IGAgK1xuICAgICAgICAgICAgICAgIGBmYWlsZWQ6ICR7aXRlbS5lcnJvcn06ICR7aXRlbS5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgIHsgc3RhdHVzOiBpdGVtLnN0YXR1cyB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBIaWdoZXN0IHNsb3QgdGhpcyBjaHVuayBjb21taXR0ZWQ6IG9uZSBpbnB1dCBvZiB0aGUgaW50ZXJsZWF2aW5nXG4gICAgICAgICAgLy8gZGlhZ25vc3RpYy5cbiAgICAgICAgICBjb25zdCBjaHVua01heFNsb3QgPSBtYXhFdmVudFNsb3QoXG4gICAgICAgICAgICByZXN1bHRzLmZsYXRNYXAoKGl0ZW0pID0+XG4gICAgICAgICAgICAgIGl0ZW0uZXJyb3IgPT09IHVuZGVmaW5lZCAmJiBpdGVtLmV2ZW50ID8gW2l0ZW0uZXZlbnRdIDogW11cbiAgICAgICAgICAgIClcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbW1pdHRlZENvdW50ICs9IHJlc3VsdHMuZmlsdGVyKFxuICAgICAgICAgICAgKGl0ZW0pID0+IGl0ZW0uZXJyb3IgPT09IHVuZGVmaW5lZFxuICAgICAgICAgICkubGVuZ3RoO1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGNodW5rTWF4U2xvdCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICAobWF4Q29tbWl0dGVkU2xvdCA9PT0gdW5kZWZpbmVkIHx8IGNodW5rTWF4U2xvdCA+IG1heENvbW1pdHRlZFNsb3QpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBtYXhDb21taXR0ZWRTbG90ID0gY2h1bmtNYXhTbG90O1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvLyBQdWJsaXNoIHRoZSBjaHVuaydzIGVhZ2VyIHN0ZXBzJyBxdWV1ZSBtZXNzYWdlcyB0aGUgbW9tZW50IElUU1xuICAgICAgICAvLyBjcmVhdGVzIGFyZSBkdXJhYmxlLCB0aGUgcGVyLWNodW5rIGhhbGYgb2YgcHVibGlzaC1hZnRlci1jcmVhdGUuXG4gICAgICAgIC8vIFNhbWUgbWVzc2FnZSBzaGFwZSBhbmQgc3RlcC1pZGVudGl0eS1zY29wZWQgaWRlbXBvdGVuY3kga2V5IGFzIHRoZVxuICAgICAgICAvLyBjYWxsZXIncyBkaXNwYXRjaCBwYXNzLCBzbyBhbnl0aGluZyBkb3VibGUtcHVibGlzaGVkIGRlZHVwZXMuXG4gICAgICAgIGNvbnN0IHB1Ymxpc2hDaHVua1N0ZXBzID0gYXN5bmMgKFxuICAgICAgICAgIGNodW5rOiB0eXBlb2YgZW50cmllc1xuICAgICAgICApOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICBpZiAoIXB1Ymxpc2hFYWdlclN0ZXBzKSByZXR1cm47XG4gICAgICAgICAgY29uc3Qgc3RlcEVudHJpZXMgPSBjaHVuay5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS5raW5kID09PSAnc3RlcCcpO1xuICAgICAgICAgIGlmIChzdGVwRW50cmllcy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICAgICAgICBjb25zdCB0cmFjZUNhcnJpZXIgPSBhd2FpdCBnZXRTdGVwRGlzcGF0Y2hUcmFjZUNhcnJpZXIoKTtcbiAgICAgICAgICAvLyBPbmUgYmF0Y2hlZCBwdWJsaXNoIHBlciBjaHVuayBpbnN0ZWFkIG9mIG9uZSByb3VuZCB0cmlwIHBlciBzdGVwLlxuICAgICAgICAgIC8vIFRoZSBwdWJsaXNoZXMgYXJlIHRoZSBmYW4tb3V0J3Mgc2VyaWFsaXphdGlvbiBwb2ludDogdGhleSByaWRlIHRoZVxuICAgICAgICAgIC8vIHNoYXJlZCA4LWNvbm5lY3Rpb24gSFRUUC8xLjEgYWdlbnQgKHNlZSBgZ2V0UXVldWVEaXNwYXRjaGVyYCBpblxuICAgICAgICAgIC8vIHdvcmxkLXZlcmNlbCksIGFuZCB0aGUgY2FsbGVyIGF3YWl0cyBhbGwgb2YgdGhlbSBiZWZvcmUgcnVubmluZ1xuICAgICAgICAgIC8vIHRoZSBmaXJzdCBpbmxpbmUgc3RlcCBib2R5LCBzbyBOIHJvdW5kIHRyaXBzIGxhbmQgZGlyZWN0bHkgb25cbiAgICAgICAgICAvLyB0aW1lLXRvLWZpcnN0LXN0ZXAuIGBxdWV1ZU1lc3NhZ2VzYCBmYWxscyBiYWNrIHRvIGNvbmN1cnJlbnRcbiAgICAgICAgICAvLyBzaW5nbGUgc2VuZHMgb24gYSBXb3JsZCB3aXRoIG5vIGJhdGNoIHN1cHBvcnQuXG4gICAgICAgICAgYXdhaXQgcXVldWVNZXNzYWdlcyhcbiAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3R5bGUvbm9Ob25OdWxsQXNzZXJ0aW9uOiBwdWJsaXNoRWFnZXJTdGVwcyBpbXBsaWVzIHByZXNlbmNlXG4gICAgICAgICAgICBzdGVwRGlzcGF0Y2ghLnF1ZXVlTmFtZSxcbiAgICAgICAgICAgIHN0ZXBFbnRyaWVzLm1hcCgoZW50cnkpID0+ICh7XG4gICAgICAgICAgICAgIG1lc3NhZ2U6IHtcbiAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICBzdGVwSWQ6IGVudHJ5LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgLy8gYmlvbWUtaWdub3JlIGxpbnQvc3R5bGUvbm9Ob25OdWxsQXNzZXJ0aW9uOiBzZXQgb24gZXZlcnkgJ3N0ZXAnIGVudHJ5IGF0IGVucXVldWVcbiAgICAgICAgICAgICAgICBzdGVwTmFtZTogZW50cnkuc3RlcE5hbWUhLFxuICAgICAgICAgICAgICAgIHRyYWNlQ2FycmllcixcbiAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgICBydW5Db250ZXh0OiBydW5EaXNwYXRjaENvbnRleHQocnVuKSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgb3B0czoge1xuICAgICAgICAgICAgICAgIGlkZW1wb3RlbmN5S2V5OiBzdGVwRGlzcGF0Y2hJZGVtcG90ZW5jeUtleShcbiAgICAgICAgICAgICAgICAgIGVudHJ5LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAvLyBiaW9tZS1pZ25vcmUgbGludC9zdHlsZS9ub05vbk51bGxBc3NlcnRpb246IHNldCBvbiBldmVyeSAnc3RlcCcgZW50cnkgYXQgZW5xdWV1ZVxuICAgICAgICAgICAgICAgICAgZW50cnkuc3RlcE5hbWUhXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pKVxuICAgICAgICAgICk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gTGF1bmNoIGV2ZXJ5IGNodW5rJ3MgUE9TVCBub3cgKHRoZSBsb25lIHBsYWluIGVudHJ5J3MgZ3VhcmRlZFxuICAgICAgICAvLyBzaW5nbGUgY3JlYXRlIGluY2x1ZGVkKTsgY2hhaW4gZWFjaCBjaHVuaydzIHB1Ymxpc2hlcyBvbiBpdHMgT1dOXG4gICAgICAgIC8vIGNvbW1pdCwgc28gcHVibGlzaC1hZnRlci1jcmVhdGUgaG9sZHMgZm9yIHRoZSBzaW5nbGUgdG9vLiBBIGNodW5rXG4gICAgICAgIC8vIHdob3NlIGNvbW1pdCByZWplY3RlZCBrZWVwcyBpdHMgbWVzc2FnZXMgdW5zZW50ICh0aGUgcmVqZWN0aW9uXG4gICAgICAgIC8vIGZhaWxzIHRoZSBkZWxpdmVyeTsgcmVkZWxpdmVyeSByZS1jcmVhdGVzIGFuZCByZS1kaXNwYXRjaGVzLFxuICAgICAgICAvLyBkZWR1cGVkIGJ5IHRoZSBpZGVtcG90ZW5jeSBrZXlzKS5cbiAgICAgICAgY29uc3QgY29tbWl0cyA9IGNodW5rcy5tYXAoKGNodW5rKSA9PlxuICAgICAgICAgIGNodW5rID09PSBzaW5nbGVDaHVuayA/IGNvbW1pdFNpbmdsZShjaHVua1swXSkgOiBjb21taXRDaHVuayhjaHVuaylcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgcHVibGlzaGVzID0gY2h1bmtzLm1hcChhc3luYyAoY2h1bmssIGluZGV4KSA9PiB7XG4gICAgICAgICAgYXdhaXQgY29tbWl0c1tpbmRleF07XG4gICAgICAgICAgYXdhaXQgcHVibGlzaENodW5rU3RlcHMoY2h1bmspO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCB0cmFpbGluZyA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgLy8gTGV0IGV2ZXJ5IHNpYmxpbmcgc2V0dGxlIGJlZm9yZSBzdXJmYWNpbmcgdGhlIGZpcnN0IGZhaWx1cmU6IGFcbiAgICAgICAgICAvLyBjaHVuayB0aGF0IGNvbW1pdHRlZCBtdXN0IHN0aWxsIGdldCBpdHMgcHVibGlzaGVzIG91dCBldmVuIHdoZW5cbiAgICAgICAgICAvLyBhbm90aGVyIGNodW5rIGZhaWxlZCwgYW5kIHRoZSBjYWxsZXIgYWNrcyBvbmx5IGFmdGVyIHRoaXNcbiAgICAgICAgICAvLyByZXNvbHZlcy5cbiAgICAgICAgICBjb25zdCBzZXR0bGVkID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFsuLi5jb21taXRzLCAuLi5wdWJsaXNoZXNdKTtcbiAgICAgICAgICAvLyBGb3JlaWduLWludGVybGVhdmluZyB2aXNpYmlsaXR5OiB0aGUgYmF0Y2ggZW5kcG9pbnQgaGFzIG5vXG4gICAgICAgICAgLy8gYnVtcC1hbmQtcmVwb3J0LCBzbyBldmVudHMgb3RoZXIgd3JpdGVycyBsYW5kZWQgYmV0d2VlbiB0aGVcbiAgICAgICAgICAvLyBzbmFwc2hvdCBhbmQgdGhlc2UgY29tbWl0cyBwdXNoZWQgdGhlIGZvbGQgdG8gaGlnaGVyIHNsb3RzXG4gICAgICAgICAgLy8gV0lUSE9VVCBoYW5kaW5nIHVzIHRoZSBza2lwcGVkIGV2ZW50cy4gU2FtZSBhY2NlcHRlZCBleHBvc3VyZVxuICAgICAgICAgIC8vIGFzIGEgZHJvcHBlZCB0cnVuY2F0ZWQgcmVwb3J0IG9uIHRoZSBzaW5nbGUgcGF0aDogdGhlIGxvY2FsXG4gICAgICAgICAgLy8gbG9nIHN0YXlzIGEgc3RyaWN0IHByZWZpeCBhbmQgdGhlIG5leHQgcmVsb2FkIG9ic2VydmVzIHRoZW0uXG4gICAgICAgICAgLy8gTG9nZ2VkIHNvIGEgYnVtcCBpcyBkaWFnbm9zYWJsZSByYXRoZXIgdGhhbiBzaWxlbnQuXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgZXhwZWN0ZWRGaXJzdFNsb3QgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgbWF4Q29tbWl0dGVkU2xvdCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBpbnRlcmxlYXZlZCA9XG4gICAgICAgICAgICAgIG1heENvbW1pdHRlZFNsb3QgLSBleHBlY3RlZEZpcnN0U2xvdCArIDEgLSBjb21taXR0ZWRDb3VudDtcbiAgICAgICAgICAgIGlmIChpbnRlcmxlYXZlZCA+IDApIHtcbiAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnQmF0Y2hlZCBmYW4tb3V0IGNvbW1pdHRlZCBhYm92ZSBzbmFwc2hvdCcsIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICBleHBlY3RlZEZpcnN0U2xvdCxcbiAgICAgICAgICAgICAgICBtYXhDb21taXR0ZWRTbG90LFxuICAgICAgICAgICAgICAgIGNvbW1pdHRlZENvdW50LFxuICAgICAgICAgICAgICAgIGludGVybGVhdmVkLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgZmFpbHVyZSA9IHNldHRsZWQuZmluZChcbiAgICAgICAgICAgIChvdXRjb21lKTogb3V0Y29tZSBpcyBQcm9taXNlUmVqZWN0ZWRSZXN1bHQgPT5cbiAgICAgICAgICAgICAgb3V0Y29tZS5zdGF0dXMgPT09ICdyZWplY3RlZCdcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmIChmYWlsdXJlKSB0aHJvdyBmYWlsdXJlLnJlYXNvbjtcbiAgICAgICAgfSkoKTtcblxuICAgICAgICAvLyBFVkVSWSBjaHVuayBjYXJyeWluZyBwYWlycyBnYXRlcyB0aGUgcmV0dXJuLCBub3QganVzdCB0aGUgZmlyc3Q6XG4gICAgICAgIC8vIGEgcGFpciB3aG9zZSBjb21taXQgdGhlIGNhbGxlciBoYXMgbm90IHNlZW4geWllbGRzIG5vXG4gICAgICAgIC8vIGBpbmxpbmVDbGFpbXNgIGVudHJ5LCBzbyB0aGUgY2FsbGVyIGZhbGxzIGJhY2sgdG8gYSBsYXp5XG4gICAgICAgIC8vIGBzdGVwX3N0YXJ0ZWRgIHRoYXQgd291bGQgcmFjZSB0aGlzIHNhbWUgZm9sZCdzIHN0aWxsLWluLWZsaWdodFxuICAgICAgICAvLyBwYWlyIGZvciB0aGUgc2FtZSBzdGVwLiBUaGUgcGFpcnMgb2NjdXB5IHRoZWlyIG93biBsZWFkaW5nXG4gICAgICAgIC8vIGNodW5rKHMpLCBhbmQgdG9kYXkgdGhhdCBpcyBleGFjdGx5IE9ORSBjaHVuayAodHdvIHJvd3MgcGVyXG4gICAgICAgIC8vIGlubGluZSBzdGVwIGZpdCBpbnNpZGUgb25lIGNodW5rLCBwaW5uZWQgYnkgY29uc3RhbnRzLnRlc3QudHMpLFxuICAgICAgICAvLyBzbyB0aGlzIGlzIGF0IG1vc3Qgb25lIGNvbW1pdDsgdGhlIGZpbHRlciBpcyB3aGF0IGtlZXBzIHRoZVxuICAgICAgICAvLyBwcm9wZXJ0eSB0cnVlIGlmIGVpdGhlciBjYXAgbW92ZXMuXG4gICAgICAgIGNvbnN0IHBhaXJDb21taXRzID0gY2h1bmtzLmZsYXRNYXAoKGNodW5rLCBpbmRleCkgPT5cbiAgICAgICAgICBjaHVuay5zb21lKChlbnRyeSkgPT4gZW50cnkua2luZCA9PT0gJ2lubGluZS1zdGFydGVkJylcbiAgICAgICAgICAgID8gW2NvbW1pdHNbaW5kZXhdXVxuICAgICAgICAgICAgOiBbXVxuICAgICAgICApO1xuICAgICAgICBpZiAoYWxsb3dEZWZlcnJlZEJhdGNoV29yaykge1xuICAgICAgICAgIC8vIFRoZSB0cmFpbGluZyB3b3JrIGlzIHRoZSBjYWxsZXIncyB0byBqb2luIGJlZm9yZSBhY2suIEF0dGFjaCBhXG4gICAgICAgICAgLy8gaGFuZGxlciBub3cgc28gYSByZWplY3Rpb24gdGhhdCByYWNlcyB0aGF0IGpvaW4gKG9yIGEgZm9yZWdyb3VuZFxuICAgICAgICAgIC8vIGZhaWx1cmUgdGhhdCBwcmV2ZW50cyB0aGUgY2FsbGVyIGZyb20gZXZlciByZWFjaGluZyBpdCkgaXMgbmV2ZXJcbiAgICAgICAgICAvLyBhbiB1bmhhbmRsZWRSZWplY3Rpb247IGF3YWl0aW5nIHRoZSBwcm9taXNlIHN0aWxsIG9ic2VydmVzIGl0LlxuICAgICAgICAgIHRyYWlsaW5nLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgICAgICBkZWZlcnJlZEJhdGNoV29yayA9IHRyYWlsaW5nO1xuICAgICAgICAgIC8vIE9ubHkgdGhlIHBhaXIgY2h1bmtzIGdhdGUgdGhlIHJldHVybjogdGhlaXIgY2xhaW1zIGFyZSB3aGF0IHRoZVxuICAgICAgICAgIC8vIGNhbGxlciBzdGFydHMgdGhlIGlubGluZSBib2RpZXMgZnJvbS4gV2l0aCBubyBwYWlycyB0aGVyZSBpc1xuICAgICAgICAgIC8vIG5vdGhpbmcgdGhlIGNhbGxlcidzIHBvc3QtcmV0dXJuIHdvcmsgcmVhZHMgZnJvbSB0aGUgY29tbWl0cyxcbiAgICAgICAgICAvLyBzbyBub3RoaW5nIGdhdGVzLlxuICAgICAgICAgIGlmIChwYWlyQ29tbWl0cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwYWlyQ29tbWl0cyk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgLy8gQSBwYWlyIGNodW5rIGZhaWxlZCwgc28gdGhpcyBwaGFzZSdzIHdyaXRlIHNldCBpcyBOT1QgdGhlXG4gICAgICAgICAgICAgIC8vIGNhbGxlcidzIHRvIGpvaW4gYW55IG1vcmU6IGBkZWZlcnJlZEJhdGNoV29ya2AgbmV2ZXJcbiAgICAgICAgICAgICAgLy8gcmVhY2hlcyBpdCBvbmNlIGhhbmRsZVN1c3BlbnNpb24gdGhyb3dzLiBTZXR0bGUgdGhlIHJlc3RcbiAgICAgICAgICAgICAgLy8gYmVmb3JlIHRoZSByZWplY3Rpb24gZXNjYXBlcywgZm9yIHRoZSByZWFzb24gYHNldHRsZVBoYXNlYFxuICAgICAgICAgICAgICAvLyBnaXZlczogYSBzaWJsaW5nIGNyZWF0ZSBsYW5kaW5nIGFmdGVyIHRoZSB0aHJvdyBjb21taXRzIGFuXG4gICAgICAgICAgICAgIC8vIGV2ZW50IGZyb20gdGhlIGFiYW5kb25lZCByZXBsYXkncyBzZWVkZWQgc2VxdWVuY2UgYW5kIHJhY2VzXG4gICAgICAgICAgICAgIC8vIHRoZSBjYWxsZXIncyByZXN0YXJ0IHJlbG9hZCB3aGlsZSBkb2luZyBzby5cbiAgICAgICAgICAgICAgYXdhaXQgdHJhaWxpbmcuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGF3YWl0IHRyYWlsaW5nO1xuICAgICAgICB9XG4gICAgICB9KSgpXG4gICAgKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgcXVldWVJdGVtIG9mIGF0dHJpYnV0ZUl0ZW1zKSB7XG4gICAgb3BzLnB1c2goXG4gICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGVuc3VyZVJ1blJlYWR5KCk7XG4gICAgICAgICAgLy8gR3VhcmRlZCBsaWtlIGV2ZXJ5IG90aGVyIHN1c3BlbnNpb24gd3JpdGU6IGFuIGF0dHJfc2V0IGlzIGFcbiAgICAgICAgICAvLyByZXBsYXktZGVyaXZlZCBldmVudCB3aXRoIGEgY29ycmVsYXRpb24gaWQgZnJvbSB0aGlzIHJlcGxheSdzXG4gICAgICAgICAgLy8gc2VlZGVkIHNlcXVlbmNlLCBzbyBpdCBtdXN0IG5vdCBsYW5kIG9uIGEgbG9nIHRoZSByZXBsYXkgbmV2ZXJcbiAgICAgICAgICAvLyBzYXcuIFJlamVjdGluZyBpdCBpcyBjaGVhcDogYSBydW4gd2l0aCBhdHRyaWJ1dGUgZXZlbnRzIGFscmVhZHlcbiAgICAgICAgICAvLyBmb3JjZXMgYW4gaW4tcHJvY2VzcyByZXBsYXksIHNvIHRoZSByZXN0YXJ0IGNvc3RzIHRoZSByZXBsYXkgaXRcbiAgICAgICAgICAvLyB3YXMgZ29pbmcgdG8gZG8gYW55d2F5LlxuICAgICAgICAgIGF3YWl0IGNyZWF0ZUd1YXJkZWQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogJ2F0dHJfc2V0JyxcbiAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgY2hhbmdlczogcXVldWVJdGVtLmNoYW5nZXMsXG4gICAgICAgICAgICAgICAgd3JpdGVyOiB7IHR5cGU6ICd3b3JrZmxvdycgfSxcbiAgICAgICAgICAgICAgICAuLi4ocXVldWVJdGVtLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgICA/IHsgYWxsb3dSZXNlcnZlZEF0dHJpYnV0ZXM6IHRydWUgfVxuICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgJ1dvcmtmbG93IGF0dHJpYnV0ZSBldmVudCBhbHJlYWR5IGV4aXN0cywgY29udGludWluZycsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGlzV29ybGRWYWxpZGF0aW9uRmFpbHVyZShlcnIpKSB7XG4gICAgICAgICAgICAvLyBEZXRlcm1pbmlzdGljIHZhbGlkYXRpb24gcmVqZWN0aW9uIGZyb20gdGhlIFdvcmxkLCBlLmcuIHRoZVxuICAgICAgICAgICAgLy8gY3VtdWxhdGl2ZSBwZXItcnVuIGF0dHJpYnV0ZSBjYXAsIHdoaWNoIG9ubHkgdGhlIFdvcmxkIGNhblxuICAgICAgICAgICAgLy8gY2hlY2sgYWdhaW5zdCB0aGUgcnVuJ3MgZXhpc3RpbmcgYXR0cmlidXRlcy4gUmVkZWxpdmVyaW5nIHRoZVxuICAgICAgICAgICAgLy8gb3JjaGVzdHJhdG9yIG1lc3NhZ2UgcmVwbGF5cyB0aGUgd29ya2Zsb3cgaW50byB0aGUgZXhhY3Qgc2FtZVxuICAgICAgICAgICAgLy8gd3JpdGUgYW5kIHRoZSBleGFjdCBzYW1lIHJlamVjdGlvbiwgc28gcmV0cnlpbmcgY2FuIG5ldmVyXG4gICAgICAgICAgICAvLyBzdWNjZWVkLiBTdXJmYWNlIGl0IGFzIGEgRmF0YWxFcnJvciBzbyB0aGUgY2FsbGVyIGZhaWxzIHRoZVxuICAgICAgICAgICAgLy8gcnVuIHdpdGggYSBjbGVhciBlcnJvciBpbnN0ZWFkIG9mIHdlZGdpbmcgaXQgaW4gcmVkZWxpdmVyeS5cbiAgICAgICAgICAgIGNvbnN0IGZhdGFsID0gbmV3IEZhdGFsRXJyb3IoXG4gICAgICAgICAgICAgIGBzZXRBdHRyaWJ1dGVzIGZhaWxlZCBXb3JsZCB2YWxpZGF0aW9uOiAke1xuICAgICAgICAgICAgICAgIGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKVxuICAgICAgICAgICAgICB9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGZhdGFsLmNhdXNlID0gZXJyO1xuICAgICAgICAgICAgdGhyb3cgZmF0YWw7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pKClcbiAgICApO1xuICB9XG5cbiAgLy8gQXdhaXQgdGhlIHN0ZXBfY3JlYXRlZCAvIHdhaXRfY3JlYXRlZCBldmVudCBjcmVhdGVzIGJlZm9yZSByZXR1cm5pbmcuXG4gIC8vIFRoZSBjYWxsZXIgKHdvcmtmbG93RW50cnlwb2ludCkgb25seSBlbnF1ZXVlcyB0aGUgc3RlcC1kaXNwYXRjaCBxdWV1ZVxuICAvLyBtZXNzYWdlcyBBRlRFUiBoYW5kbGVTdXNwZW5zaW9uIHJlc29sdmVzLCBhbmQgdGhlIHF1ZXVlIGhhbmRsZXIgYWNrc1xuICAvLyB0aGUgb3JjaGVzdHJhdG9yIG1lc3NhZ2Ugb25seSBhZnRlciB0aGUgY2FsbGVyIHJlc29sdmVzLiBTbyB0aGUgc3RlcF9jcmVhdGVkXG4gIC8vIGV2ZW50cyBtdXN0IGJlIGR1cmFibGUgaGVyZSwgYW5kIHRoZSBkaXNwYXRjaCBzZW5kcyBtdXN0IGNvbXBsZXRlIGluIHRoZSBjYWxsZXIsXG4gIC8vIGFsbCBiZWZvcmUgYWNrLiBJZiB0aGUgcHJvY2VzcyBjcmFzaGVzIGJlZm9yZSB0aGlzIHJlc29sdmVzLCB0aGUgb3JjaGVzdHJhdG9yXG4gIC8vIG1lc3NhZ2UgaXMgbm90IGFja2VkIGFuZCBWUVMgcmVkZWxpdmVycywgcmUtY3JlYXRlcyB0aGUgKGlkZW1wb3RlbnQpXG4gIC8vIHN0ZXBfY3JlYXRlZCBhbmQgcmUtZGlzcGF0Y2hlcywgYW5kIHJlY292ZXJzIHRoZSBydW4gaW5zdGVhZCBvZiBvcnBoYW5pbmcgaXQuXG4gIGF3YWl0IHNldHRsZVBoYXNlKG9wcyk7XG5cbiAgLy8gUmVidWlsZCB0aGUgaW5saW5lIGJhdGNoIGluIGRldGVybWluaXN0aWMgb3JkZXIuIGBsYXp5SW5saW5lQ29ycmVsYXRpb25JZHNgXG4gIC8vIGlzIGEgU2V0IHNlZWRlZCBmcm9tIHRoZSBvcmRlcmVkIGZpcnN0LU4gc2xpY2UsIHNvIGl0ZXJhdGluZyBpdCBwcmVzZXJ2ZXNcbiAgLy8gc3RlcEl0ZW1zIG9yZGVyOyBldmVyeSBpZCBpbiBpdCB3YXMgc2V0IGJ5IHRoZSBsYXp5IGJyYW5jaCBhYm92ZS5cbiAgY29uc3QgbGF6eUlubGluZVN0ZXBzOiBTdXNwZW5zaW9uSGFuZGxlclJlc3VsdFsnbGF6eUlubGluZVN0ZXBzJ10gPSBbXTtcbiAgZm9yIChjb25zdCBjb3JyZWxhdGlvbklkIG9mIGxhenlJbmxpbmVDb3JyZWxhdGlvbklkcykge1xuICAgIGNvbnN0IGxhenlTdGVwID0gbGF6eUlubGluZUJ5Q29ycmVsYXRpb25JZC5nZXQoY29ycmVsYXRpb25JZCk7XG4gICAgaWYgKGxhenlTdGVwKSBsYXp5SW5saW5lU3RlcHMucHVzaChsYXp5U3RlcCk7XG4gIH1cblxuICAvLyBGaW5kIHRoZSBzb29uZXN0IHBlbmRpbmcgd2FpdCAobWluaW11bSB0aW1lb3V0KVxuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBsZXQgc29vbmVzdFdhaXQ6IHsgc2Vjb25kczogbnVtYmVyOyBjb3JyZWxhdGlvbklkOiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbiAgZm9yIChjb25zdCBxdWV1ZUl0ZW0gb2Ygd2FpdEl0ZW1zKSB7XG4gICAgY29uc3QgcmVzdW1lQXRNcyA9IHF1ZXVlSXRlbS5yZXN1bWVBdC5nZXRUaW1lKCk7XG4gICAgY29uc3QgZGVsYXlNcyA9IE1hdGgubWF4KDEwMDAsIHJlc3VtZUF0TXMgLSBub3cpO1xuICAgIGNvbnN0IHRpbWVvdXRTZWNvbmRzID0gTWF0aC5jZWlsKGRlbGF5TXMgLyAxMDAwKTtcbiAgICBpZiAoIXNvb25lc3RXYWl0IHx8IHRpbWVvdXRTZWNvbmRzIDwgc29vbmVzdFdhaXQuc2Vjb25kcykge1xuICAgICAgc29vbmVzdFdhaXQgPSB7XG4gICAgICAgIHNlY29uZHM6IHRpbWVvdXRTZWNvbmRzLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBxdWV1ZUl0ZW0uY29ycmVsYXRpb25JZCxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKCd3b3JrZmxvd19zdXNwZW5kZWQnKSxcbiAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dTdGVwc0NyZWF0ZWQoc3RlcEl0ZW1zLmxlbmd0aCksXG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93SG9va3NDcmVhdGVkKGhvb2tzTmVlZGluZ0NyZWF0aW9uLmxlbmd0aCksXG4gICAgLi4uQXR0cmlidXRlLldvcmtmbG93V2FpdHNDcmVhdGVkKHdhaXRJdGVtcy5sZW5ndGgpLFxuICAgIC4uLihmYWlsZWRTdGVwQ29ycmVsYXRpb25JZHMuc2l6ZSA+IDBcbiAgICAgID8gQXR0cmlidXRlLldvcmtmbG93U3RlcHNGYWlsZWRTZXJpYWxpemF0aW9uKFxuICAgICAgICAgIGZhaWxlZFN0ZXBDb3JyZWxhdGlvbklkcy5zaXplXG4gICAgICAgIClcbiAgICAgIDoge30pLFxuICAgIC4uLihyZXNpbGllbnREaXNwYXRjaFJlY292ZXJlZCA+IDBcbiAgICAgID8gQXR0cmlidXRlLlN0ZXBSZXNpbGllbnREaXNwYXRjaFJlY292ZXJlZChyZXNpbGllbnREaXNwYXRjaFJlY292ZXJlZClcbiAgICAgIDoge30pLFxuICB9KTtcblxuICByZXR1cm4ge1xuICAgIHBlbmRpbmdTdGVwczogc3RlcEl0ZW1zLFxuICAgIGNyZWF0ZWRTdGVwQ29ycmVsYXRpb25JZHMsXG4gICAgZmFpbGVkU3RlcENvcnJlbGF0aW9uSWRzLFxuICAgIHF1ZXVlZFN0ZXBDb3JyZWxhdGlvbklkcyxcbiAgICBsYXp5SW5saW5lU3RlcHMsXG4gICAgaW5saW5lQ2xhaW1zLFxuICAgIGRlZmVycmVkQmF0Y2hXb3JrLFxuICAgIC8vIE9uIGhvb2sgY29uZmxpY3QgdGhlIGNhbGxlciBhZHZhbmNlcyB0aGUgd29ya2Zsb3cgb3ZlciB0aGUgY29uZmxpY3RcbiAgICAvLyBiZWZvcmUgc2NoZWR1bGluZyBhbnl0aGluZyBhbmQgbmV2ZXIgcmVhZHMgdGhlIHdhaXQgdGltZW91dCwgc28gZG9uJ3RcbiAgICAvLyByZXBvcnQgb25lLiBUaGUgbmV4dCBwYXNzLCB3aGljaCBzZWVzIHRoZSBjb25mbGljdCBzZXR0bGVkLCByZXBvcnRzIGl0LlxuICAgIHdhaXRUaW1lb3V0OlxuICAgICAgaG9va0NvbmZsaWN0Q29ycmVsYXRpb25JZHMubGVuZ3RoID4gMCA/IHVuZGVmaW5lZCA6IHNvb25lc3RXYWl0LFxuICAgIGhhc0hvb2tDb25mbGljdDogaG9va0NvbmZsaWN0Q29ycmVsYXRpb25JZHMubGVuZ3RoID4gMCxcbiAgICBob29rQ29uZmxpY3RDb3JyZWxhdGlvbklkcyxcbiAgICBoYXNBd2FpdGVkSG9va0NyZWF0aW9uOiBhd2FpdGVkSG9va0NvcnJlbGF0aW9uSWRzLmxlbmd0aCA+IDAsXG4gICAgYXdhaXRlZEhvb2tDb3JyZWxhdGlvbklkcyxcbiAgICAvLyBUaGUgZGVsdGEgYWNjb3VudHMgZm9yIHRoZSB3aG9sZSBsb2cgb25seSBpZiB0aGUgd3JpdGUgdGhhdCByZXR1cm5lZCBpdFxuICAgIC8vIHdhcyB0aGlzIHN1c3BlbnNpb24ncyBvbmx5IG9uZSDigJQgYW55dGhpbmcgd3JpdHRlbiBhZnRlciBpdCBsYW5kZWQgYWJvdmVcbiAgICAvLyB0aGUgZGVsdGEgYW5kIGlzIG1pc3NpbmcgZnJvbSB0aGUgY2FsbGVyJ3MgbG9nLlxuICAgIGV2ZW50TG9nQ2FycmllZEZvcndhcmQ6IGRlbHRhQWJzb3JiZWQgJiYgZ3VhcmRlZFdyaXRlcyA9PT0gMSxcbiAgICBoYXNBdHRyaWJ1dGVFdmVudHM6IGF0dHJpYnV0ZUl0ZW1zLmxlbmd0aCA+IDAsXG4gICAgaGFzSG9va0V2ZW50czogaG9va3NOZWVkaW5nQ3JlYXRpb24ubGVuZ3RoID4gMCxcbiAgICBob29rQ3JlYXRpb25NcyxcbiAgICBzZXJpYWxpemF0aW9uQmxvY2tlckNvdW50LFxuICAgIHNlcmlhbGl6YXRpb25CbG9ja2VycyxcbiAgICByZXBvcnRlZEV2ZW50Q291bnQ6IHJlcG9ydGVkRXZlbnRzLFxuICB9O1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYW4gYGV2ZW50cy5jcmVhdGVgIHJlamVjdGlvbiBpcyBkZXRlcm1pbmlzdGljIFdvcmxkIHZhbGlkYXRpb25cbiAqIHJhdGhlciB0aGFuIGEgdHJhbnNpZW50L3N0b3JhZ2UgZXJyb3IuIExvY2FsIFdvcmxkc1xuICogKHdvcmxkLWxvY2FsLCB3b3JsZC1wb3N0Z3JlcykgdGhyb3cgYEF0dHJpYnV0ZVZhbGlkYXRpb25FcnJvcmAgZGlyZWN0bHk7XG4gKiByZW1vdGUgV29ybGRzIHN1cmZhY2UgdGhlIGVxdWl2YWxlbnQgc2VydmVyLXNpZGUgcmVqZWN0aW9uIGFzIGFcbiAqIGBXb3JrZmxvd1dvcmxkRXJyb3JgIHdpdGggSFRUUCBzdGF0dXMgNDAwLiBUaGUgbmFtZSBjaGVjayBjb3ZlcnNcbiAqIGBBdHRyaWJ1dGVWYWxpZGF0aW9uRXJyb3JgIGluc3RhbmNlcyBmcm9tIGEgZGlmZmVyZW50IGNvcHkgb2ZcbiAqIGBAd29ya2Zsb3cvd29ybGRgIHRoYW4gdGhlIG9uZSB0aGlzIHBhY2thZ2UgcmVzb2x2ZWQuXG4gKi9cbmZ1bmN0aW9uIGlzV29ybGRWYWxpZGF0aW9uRmFpbHVyZShlcnI6IHVua25vd24pOiBib29sZWFuIHtcbiAgaWYgKGVyciBpbnN0YW5jZW9mIEF0dHJpYnV0ZVZhbGlkYXRpb25FcnJvcikgcmV0dXJuIHRydWU7XG4gIGlmIChlcnIgaW5zdGFuY2VvZiBFcnJvciAmJiBlcnIubmFtZSA9PT0gJ0F0dHJpYnV0ZVZhbGlkYXRpb25FcnJvcicpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICByZXR1cm4gV29ya2Zsb3dXb3JsZEVycm9yLmlzKGVycikgJiYgZXJyLnN0YXR1cyA9PT0gNDAwO1xufVxuIl19
|