@workflow/core 5.0.0-beta.4 → 5.0.0-beta.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attribute-changes.d.ts +7 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +33 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +71 -4
- package/dist/capture-stack.d.ts +16 -0
- package/dist/capture-stack.d.ts.map +1 -0
- package/dist/capture-stack.js +21 -0
- package/dist/class-serialization.d.ts +32 -0
- package/dist/class-serialization.d.ts.map +1 -1
- package/dist/class-serialization.js +37 -1
- package/dist/classify-error.d.ts +26 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +109 -6
- package/dist/context-errors.d.ts +27 -0
- package/dist/context-errors.d.ts.map +1 -0
- package/dist/context-errors.js +101 -0
- package/dist/context-violation-error.d.ts +97 -0
- package/dist/context-violation-error.d.ts.map +1 -0
- package/dist/context-violation-error.js +149 -0
- package/dist/create-hook.d.ts +62 -4
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +4 -3
- package/dist/define-hook.d.ts.map +1 -1
- package/dist/define-hook.js +20 -5
- package/dist/describe-error.d.ts +70 -0
- package/dist/describe-error.d.ts.map +1 -0
- package/dist/describe-error.js +189 -0
- package/dist/encryption.d.ts +37 -3
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +97 -31
- package/dist/events-consumer.d.ts +147 -1
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +444 -43
- package/dist/flushable-stream.d.ts +65 -10
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +131 -18
- package/dist/global.d.ts +37 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/log-format.d.ts +25 -0
- package/dist/log-format.d.ts.map +1 -0
- package/dist/log-format.js +250 -0
- package/dist/logger.d.ts +29 -30
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +82 -32
- package/dist/private.d.ts +246 -8
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +345 -9
- package/dist/replay-payload-cache.d.ts +68 -0
- package/dist/replay-payload-cache.d.ts.map +1 -0
- package/dist/replay-payload-cache.js +160 -0
- package/dist/runtime/compute-instance.d.ts +12 -0
- package/dist/runtime/compute-instance.d.ts.map +1 -0
- package/dist/runtime/compute-instance.js +13 -0
- package/dist/runtime/constants.d.ts +251 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +425 -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 +25 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -0
- package/dist/runtime/get-port-lazy.js +92 -0
- package/dist/runtime/get-world-lazy.d.ts +23 -0
- package/dist/runtime/get-world-lazy.d.ts.map +1 -0
- package/dist/runtime/get-world-lazy.js +46 -0
- package/dist/runtime/helpers.d.ts +327 -10
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +586 -40
- 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 +124 -0
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
- package/dist/runtime/quickjs-entrypoint.js +1437 -0
- package/dist/runtime/quickjs-runtime.d.ts +228 -0
- package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
- package/dist/runtime/quickjs-runtime.js +2372 -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 +2098 -0
- package/dist/runtime/replay-budget.d.ts +89 -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 +27 -4
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +452 -76
- 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 +8 -2
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +62 -15
- package/dist/runtime/runs.d.ts +54 -3
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +119 -13
- package/dist/runtime/start.d.ts +70 -1
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +313 -60
- package/dist/runtime/step-executor.d.ts +177 -0
- package/dist/runtime/step-executor.d.ts.map +1 -0
- package/dist/runtime/step-executor.js +946 -0
- package/dist/runtime/step-latency.d.ts +197 -0
- package/dist/runtime/step-latency.d.ts.map +1 -0
- package/dist/runtime/step-latency.js +207 -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 +69 -0
- package/dist/runtime/suspension-handler.d.ts +109 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +486 -140
- 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 +84 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +105 -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 +20 -0
- package/dist/runtime/world-compatibility.d.ts.map +1 -0
- package/dist/runtime/world-compatibility.js +32 -0
- package/dist/runtime/world-init.d.ts +50 -0
- package/dist/runtime/world-init.d.ts.map +1 -0
- package/dist/runtime/world-init.js +50 -0
- package/dist/runtime/world.d.ts +14 -2
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +101 -26
- package/dist/runtime.d.ts +17 -12
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +3135 -328
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +1 -1
- 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 +17 -0
- package/dist/serialization/client.d.ts.map +1 -0
- package/dist/serialization/client.js +48 -0
- 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 +14 -0
- package/dist/serialization/codec-devalue.d.ts.map +1 -0
- package/dist/serialization/codec-devalue.js +105 -0
- package/dist/serialization/codec.d.ts +125 -0
- package/dist/serialization/codec.d.ts.map +1 -0
- package/dist/serialization/codec.js +17 -0
- package/dist/serialization/compression.d.ts +104 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +260 -0
- package/dist/serialization/encryption.d.ts +134 -0
- package/dist/serialization/encryption.d.ts.map +1 -0
- package/dist/serialization/encryption.js +186 -0
- package/dist/serialization/errors.d.ts +34 -0
- package/dist/serialization/errors.d.ts.map +1 -0
- package/dist/serialization/errors.js +59 -0
- package/dist/serialization/format.d.ts +60 -0
- package/dist/serialization/format.d.ts.map +1 -0
- package/dist/serialization/format.js +97 -0
- package/dist/serialization/hardened.d.ts +155 -0
- package/dist/serialization/hardened.d.ts.map +1 -0
- package/dist/serialization/hardened.js +523 -0
- package/dist/serialization/index.d.ts +20 -0
- package/dist/serialization/index.d.ts.map +1 -0
- package/dist/serialization/index.js +22 -0
- 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 +11 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -0
- package/dist/serialization/reducers/class.js +73 -0
- 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 +579 -0
- package/dist/serialization/reducers/common.d.ts +16 -0
- package/dist/serialization/reducers/common.d.ts.map +1 -0
- package/dist/serialization/reducers/common.js +478 -0
- 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 +35 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function.js +104 -0
- package/dist/serialization/step.d.ts +17 -0
- package/dist/serialization/step.d.ts.map +1 -0
- package/dist/serialization/step.js +48 -0
- package/dist/serialization/types.d.ts +273 -0
- package/dist/serialization/types.d.ts.map +1 -0
- package/dist/serialization/types.js +35 -0
- 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 +71 -0
- package/dist/serialization/workflow.d.ts +29 -0
- package/dist/serialization/workflow.d.ts.map +1 -0
- package/dist/serialization/workflow.js +54 -0
- package/dist/serialization-format.d.ts +60 -4
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +276 -56
- package/dist/serialization.d.ts +374 -221
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +2300 -783
- 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/sleep.d.ts.map +1 -1
- package/dist/sleep.js +3 -2
- package/dist/source-map.d.ts +25 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +148 -10
- package/dist/step/context-storage.d.ts +61 -2
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +7 -5
- package/dist/step/get-closure-vars.d.ts.map +1 -1
- package/dist/step/get-closure-vars.js +3 -2
- package/dist/step/get-step-metadata.d.ts.map +1 -1
- package/dist/step/get-step-metadata.js +3 -2
- package/dist/step/get-workflow-metadata.d.ts.map +1 -1
- package/dist/step/get-workflow-metadata.js +3 -2
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +71 -7
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +225 -29
- package/dist/symbols.d.ts +54 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +55 -1
- package/dist/telemetry/semantic-conventions.d.ts +265 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +190 -1
- package/dist/telemetry.d.ts +73 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +153 -16
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -1
- package/dist/util.d.ts +16 -6
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +25 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +85 -14
- package/dist/vm/script-cache.d.ts +28 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +140 -0
- package/dist/workflow/abort-controller.d.ts +65 -0
- package/dist/workflow/abort-controller.d.ts.map +1 -0
- package/dist/workflow/abort-controller.js +312 -0
- package/dist/workflow/attribute-dispatcher.d.ts +6 -0
- package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
- package/dist/workflow/attribute-dispatcher.js +48 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +25 -3
- package/dist/workflow/define-hook.d.ts +1 -1
- package/dist/workflow/define-hook.d.ts.map +1 -1
- package/dist/workflow/define-hook.js +8 -4
- package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
- package/dist/workflow/get-workflow-metadata.js +14 -3
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +302 -36
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +5 -3
- package/dist/workflow/set-attributes.d.ts +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 +57 -8
- package/dist/workflow/world-init-stub.d.ts +15 -0
- package/dist/workflow/world-init-stub.d.ts.map +1 -0
- package/dist/workflow/world-init-stub.js +15 -0
- package/dist/workflow.d.ts +79 -3
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +831 -553
- package/docs/api-reference/create-hook.mdx +79 -0
- package/docs/api-reference/create-webhook.mdx +1 -0
- package/docs/api-reference/define-hook.mdx +26 -24
- package/docs/api-reference/fatal-error.mdx +29 -7
- package/docs/api-reference/fetch.mdx +8 -4
- package/docs/api-reference/index.mdx +3 -0
- package/docs/api-reference/set-attributes.mdx +61 -0
- package/docs/api-reference/sleep.mdx +1 -1
- package/docs/foundations/cancellation.mdx +459 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/idempotency.mdx +243 -11
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +3 -1
- package/docs/foundations/serialization.mdx +77 -41
- package/docs/foundations/starting-workflows.mdx +79 -2
- package/docs/foundations/streaming.mdx +14 -23
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +21 -17
- package/docs/how-it-works/encryption.mdx +5 -5
- package/docs/how-it-works/event-sourcing.mdx +17 -9
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/meta.json +2 -1
- package/package.json +31 -13
- 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 -678
package/dist/runtime.js
CHANGED
|
@@ -1,69 +1,418 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { types } from 'node:util';
|
|
3
|
+
import { CorruptedEventLogError, EntityConflictError, FatalError, HookNotFoundError, MaxEventsExceededError, PreconditionFailedError, ReplayDivergenceError, RUN_ERROR_CODES, RunExpiredError, WorkflowRuntimeError, } from '@workflow/errors';
|
|
4
|
+
import { once, setWorkflowBasePath } from '@workflow/utils';
|
|
5
|
+
import { parseWorkflowName, workflowDisplayName, } from '@workflow/utils/parse-name';
|
|
6
|
+
import { getQueueTopicPrefix, isLegacySpecVersion, isTerminalRunEventType, ROOT_RUN_ID_ATTRIBUTE, resolveQueueNamespace, SPEC_VERSION_CURRENT, SPEC_VERSION_SUPPORTS_COMPRESSION, WorkflowInvokePayloadSchema, } from '@workflow/world';
|
|
7
|
+
import ms from 'ms';
|
|
8
|
+
import { decodeTime } from 'ulid';
|
|
9
|
+
import { classifyRunError, isRetryableWorldError, isWorldContractError, } from './classify-error.js';
|
|
10
|
+
import { describeError } from './describe-error.js';
|
|
6
11
|
import { WorkflowSuspension } from './global.js';
|
|
7
12
|
import { runtimeLogger } from './logger.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
13
|
+
import { getStepFunction } from './private.js';
|
|
14
|
+
import { ReplayPayloadCache } from './replay-payload-cache.js';
|
|
15
|
+
import { COMPUTE_INSTANCE_ID } from './runtime/compute-instance.js';
|
|
16
|
+
import { getMaxEventsOverride, getMaxQueueDeliveries, getPreconditionMaxInProcessRestarts, getPreconditionMaxReinvocations, getPreconditionReinvokeDelaySeconds, getReplayDivergenceMaxRetries, isInlineOwnershipEnabled, isTurboEnabled, isVmRetentionEnabled, } from './runtime/constants.js';
|
|
17
|
+
import { countStepStartedEvents } from './runtime/count-step-started-events.js';
|
|
18
|
+
import { guardDeploymentAffinity, } from './runtime/deployment-guard.js';
|
|
19
|
+
import { appendUniqueEvents, getQueueOverhead, getWorkflowQueueName, handleHealthCheckMessage, insertEventByEventId, isPreconditionGuardEnabled, isSlotGapCheckEnabled, loadWorkflowRunEvents, memoizeEncryptionKey, mergeReportedEvents, parseHealthCheckPayload, preconditionEventDelta, preconditionSnapshotParams, queueMessage, settleEventSlotGap, withHealthCheck, } from './runtime/helpers.js';
|
|
20
|
+
import { handleReplayBudgetExhausted, ReplayBudget, } from './runtime/replay-budget.js';
|
|
21
|
+
import { ReplayRecoveryReporter } from './runtime/replay-recovery-reporter.js';
|
|
22
|
+
import { runIdCreatedAt } from './runtime/run-id-time.js';
|
|
23
|
+
import { DEFAULT_STEP_MAX_RETRIES, executeStep, } from './runtime/step-executor.js';
|
|
24
|
+
import { computeStepLatencyTracking } from './runtime/step-latency.js';
|
|
25
|
+
import { backstopIdempotencyKey, hasPendingStepOwnedByMessage, isStepOwnershipActive, stepLeaseRemainingSeconds, } from './runtime/step-ownership.js';
|
|
26
|
+
import { runStepSingleFlight } from './runtime/step-single-flight.js';
|
|
10
27
|
import { handleSuspension } from './runtime/suspension-handler.js';
|
|
28
|
+
import { useQuickJSVm } from './runtime/vm-mode.js';
|
|
29
|
+
import { getWaitContinuationDispatch } from './runtime/wait-continuation.js';
|
|
11
30
|
import { getWorld, getWorldHandlers, } from './runtime/world.js';
|
|
31
|
+
import { dehydrateRunError } from './serialization.js';
|
|
12
32
|
import { remapErrorStack } from './source-map.js';
|
|
13
33
|
import * as Attribute from './telemetry/semantic-conventions.js';
|
|
14
|
-
import {
|
|
34
|
+
import { buildInvocationSpanLinks, getNextTraceCarrier, getSpanKind, getWorkflowTraceMode, isUsableTraceCarrier, trace, withTraceContext, withWorkflowBaggage, } from './telemetry.js';
|
|
15
35
|
import { getErrorName, getErrorStack, normalizeUnknownError } from './types.js';
|
|
16
36
|
import { buildWorkflowSuspensionMessage } from './util.js';
|
|
17
|
-
import {
|
|
37
|
+
import { replayWorkflow, resumeWorkflow, } from './workflow.js';
|
|
18
38
|
export { WorkflowSuspension } from './global.js';
|
|
19
39
|
export { healthCheck, } from './runtime/helpers.js';
|
|
20
40
|
export { getHookByToken, resumeHook, resumeWebhook, } from './runtime/resume-hook.js';
|
|
21
41
|
export { getRun, Run, } from './runtime/run.js';
|
|
22
|
-
export { cancelRun, listStreams, readStream, recreateRunFromExisting, reenqueueRun, wakeUpRun, } from './runtime/runs.js';
|
|
42
|
+
export { cancelRun, cancelRuns, listStreams, readStream, recreateRunFromExisting, reenqueueRun, wakeUpRun, } from './runtime/runs.js';
|
|
23
43
|
export { start, } from './runtime/start.js';
|
|
24
|
-
export {
|
|
25
|
-
export { createWorld, getWorld, getWorldHandlers, setWorld, } from './runtime/world.js';
|
|
44
|
+
export { createWorld, createWorldFromModule, getWorld, getWorldHandlers, setWorld, } from './runtime/world.js';
|
|
26
45
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
46
|
+
* Apply the optional client-side event-limit override.
|
|
47
|
+
* `WORKFLOW_MAX_EVENTS_OVERRIDE`, when set to a positive integer, clamps the
|
|
48
|
+
* server-supplied per-run event ceiling to a smaller value so enforcement can
|
|
49
|
+
* be exercised without a server-side change. Clamp-down only: it never raises
|
|
50
|
+
* the server's limit, and it takes effect even when the server returns none.
|
|
51
|
+
* Unset ⇒ server value passes through unchanged.
|
|
52
|
+
*/
|
|
53
|
+
function clampMaxEvents(serverValue) {
|
|
54
|
+
const override = getMaxEventsOverride();
|
|
55
|
+
if (override === undefined)
|
|
56
|
+
return serverValue;
|
|
57
|
+
return serverValue === undefined ? override : Math.min(serverValue, override);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Refuse a queue delivery whose run was created in a different environment than
|
|
61
|
+
* this deployment runs in.
|
|
62
|
+
*
|
|
63
|
+
* `start()` performs two writes that must land in the same tenant: the
|
|
64
|
+
* `run_created` event, attributed to whatever environment the *caller*
|
|
65
|
+
* authenticates as, and the queue message, pinned to a *deployment*. A
|
|
66
|
+
* misconfigured caller can split them — writing the run to one environment
|
|
67
|
+
* while addressing the message to a deployment in another. The consumer then
|
|
68
|
+
* finds no run under its own tenant and the backend's resilient start
|
|
69
|
+
* (`run_started` creates the run when `run_created` was never seen) mints a
|
|
70
|
+
* SECOND copy of the same run id in this environment. Both copies are real: the
|
|
71
|
+
* creator's sits pending forever, this one executes, and every subsequent
|
|
72
|
+
* cross-tenant queue ack fails to find its message.
|
|
73
|
+
*
|
|
74
|
+
* Nothing external is needed to catch this: the creator's environment rides the
|
|
75
|
+
* message in `runInput.environment` and this process already knows its own. So
|
|
76
|
+
* compare them and stop BEFORE `run_started` — the write that would create the
|
|
77
|
+
* fork. Refusing after it would be too late.
|
|
78
|
+
*
|
|
79
|
+
* Returns `true` when the caller must abandon the delivery. Skipped whenever
|
|
80
|
+
* either side is unknown, which keeps every existing setup on its current
|
|
81
|
+
* behavior: worlds with no environment dimension (`world-local`,
|
|
82
|
+
* `world-postgres`) don't implement `getEnvironment`, and runs started by an
|
|
83
|
+
* older SDK carry no `environment` field.
|
|
84
|
+
*/
|
|
85
|
+
function refuseCrossEnvironmentDelivery({ world, runInput, runId, runLogger, }) {
|
|
86
|
+
const creatorEnvironment = runInput?.environment;
|
|
87
|
+
if (!creatorEnvironment)
|
|
88
|
+
return false;
|
|
89
|
+
const currentEnvironment = world.getEnvironment?.();
|
|
90
|
+
if (!currentEnvironment || currentEnvironment === creatorEnvironment) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
runLogger.error(`Refusing to run this workflow: it was created in the "${creatorEnvironment}" ` +
|
|
94
|
+
`environment but this deployment runs in "${currentEnvironment}". ` +
|
|
95
|
+
'Executing it here would create a second copy of the same run id in ' +
|
|
96
|
+
'both environments — one pending forever, one running — so the queue ' +
|
|
97
|
+
'message is being discarded without executing and without retrying. ' +
|
|
98
|
+
'The client that called start() wrote the run to its own environment ' +
|
|
99
|
+
'but addressed the queue message to a deployment in another one. Check ' +
|
|
100
|
+
'that the environment that client authenticates as (WORKFLOW_VERCEL_ENV ' +
|
|
101
|
+
"for CLI and CI clients, or the OIDC token's environment inside a " +
|
|
102
|
+
'deployment) matches the environment of the deployment it targets. The ' +
|
|
103
|
+
`run it created is still pending in "${creatorEnvironment}" and will ` +
|
|
104
|
+
'not run.', {
|
|
105
|
+
workflowRunId: runId,
|
|
106
|
+
creatorEnvironment,
|
|
107
|
+
currentEnvironment,
|
|
108
|
+
pinnedDeploymentId: runInput?.deploymentId,
|
|
109
|
+
});
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Log when a `start()`-enqueued message pinned to one deployment is delivered
|
|
114
|
+
* to a different one.
|
|
115
|
+
*
|
|
116
|
+
* A first-delivery message carries `runInput.deploymentId` — the deployment
|
|
117
|
+
* `start()` addressed it to — so comparing that against this handler's own
|
|
118
|
+
* deployment detects mis-delivery directly. This is a DIAGNOSTIC, not a gate:
|
|
119
|
+
* it warns and lets the invocation proceed, deliberately.
|
|
29
120
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
121
|
+
* Why this one only warns while its environment sibling above refuses: a
|
|
122
|
+
* differing deployment id is not by itself evidence of the fork we care about.
|
|
123
|
+
* The environment pair is exact — two named environments that disagree — and it
|
|
124
|
+
* is the dimension the run's tenant is keyed on. Deployment ids disagree for
|
|
125
|
+
* benign reasons too: `world-local` derives its id from the installed package
|
|
126
|
+
* version (`dpl_local@<version>`), so upgrading the SDK mid-run changes it with
|
|
127
|
+
* nothing wrong. Refusing on that signal would strand correct runs, and
|
|
128
|
+
* refusing before `run_started` leaves no server-side record to explain why.
|
|
129
|
+
* Anyone tempted to promote this to a hard failure has to handle that first.
|
|
130
|
+
*
|
|
131
|
+
* Skipped unless BOTH ids are known — `getDeploymentId()` throws in worlds that
|
|
132
|
+
* require a deployment and have none, and a re-enqueued message carries no
|
|
133
|
+
* `runInput` at all.
|
|
33
134
|
*/
|
|
34
|
-
|
|
35
|
-
const
|
|
135
|
+
async function warnOnDeploymentPinningMismatch({ world, runInput, runId, runLogger, }) {
|
|
136
|
+
const pinnedDeploymentId = runInput?.deploymentId;
|
|
137
|
+
if (!pinnedDeploymentId)
|
|
138
|
+
return;
|
|
139
|
+
let currentDeploymentId;
|
|
140
|
+
try {
|
|
141
|
+
currentDeploymentId = await world.getDeploymentId();
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Worlds that require a deployment id throw when there isn't one. That is
|
|
145
|
+
// not a mismatch — there is simply nothing to compare against.
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (!currentDeploymentId || currentDeploymentId === pinnedDeploymentId) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
runLogger.error('Queue message was delivered to a deployment it was not pinned to. ' +
|
|
152
|
+
'The run was created targeting a different deployment, so this ' +
|
|
153
|
+
'invocation may be replaying against code the run was not started on. ' +
|
|
154
|
+
'Continuing — this is expected if the Workflow SDK version changed ' +
|
|
155
|
+
'mid-run in local development, where the deployment id is derived from ' +
|
|
156
|
+
'that version.', {
|
|
157
|
+
workflowRunId: runId,
|
|
158
|
+
pinnedDeploymentId,
|
|
159
|
+
currentDeploymentId,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function getWorkflowSetupErrorCode(err) {
|
|
163
|
+
if (WorkflowRuntimeError.is(err)) {
|
|
164
|
+
return RUN_ERROR_CODES.RUNTIME_ERROR;
|
|
165
|
+
}
|
|
166
|
+
if (isWorldContractError(err)) {
|
|
167
|
+
return RUN_ERROR_CODES.WORLD_CONTRACT_ERROR;
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
async function recordFatalRunError({ world, workflowRun, runId, requestId, err, errorCode, logMessage, }) {
|
|
172
|
+
runtimeLogger.error(logMessage, {
|
|
173
|
+
workflowRunId: runId,
|
|
174
|
+
errorCode,
|
|
175
|
+
error: err instanceof Error ? err.message : String(err),
|
|
176
|
+
});
|
|
177
|
+
try {
|
|
178
|
+
const getEncryptionKey = memoizeEncryptionKey(world, workflowRun ?? runId);
|
|
179
|
+
await world.events.create(runId, {
|
|
180
|
+
eventType: 'run_failed',
|
|
181
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
182
|
+
eventData: {
|
|
183
|
+
error: await dehydrateRunError(err, runId, await getEncryptionKey(), globalThis, (workflowRun?.specVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION),
|
|
184
|
+
errorCode,
|
|
185
|
+
},
|
|
186
|
+
}, { requestId });
|
|
187
|
+
}
|
|
188
|
+
catch (failErr) {
|
|
189
|
+
if (EntityConflictError.is(failErr) || RunExpiredError.is(failErr)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (isWorldContractError(failErr)) {
|
|
193
|
+
runtimeLogger.error('Fatal world contract error while recording workflow failure', {
|
|
194
|
+
workflowRunId: runId,
|
|
195
|
+
errorCode: RUN_ERROR_CODES.WORLD_CONTRACT_ERROR,
|
|
196
|
+
error: failErr instanceof Error ? failErr.message : String(failErr),
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
throw failErr;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function hasRecordedTerminalRunEvent(events, runId) {
|
|
204
|
+
// Terminal run events are always last by construction (no event creation
|
|
205
|
+
// succeeds against a terminal run), but scan the full array for
|
|
206
|
+
// defense-in-depth: a World/backend ordering bug shouldn't make us miss an
|
|
207
|
+
// actual termination signal.
|
|
208
|
+
const terminalRunEvent = events.find((e) => e.runId === runId &&
|
|
209
|
+
(e.eventType === 'run_completed' ||
|
|
210
|
+
e.eventType === 'run_failed' ||
|
|
211
|
+
e.eventType === 'run_cancelled'));
|
|
212
|
+
if (!terminalRunEvent) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
runtimeLogger.debug('Run reached terminal event, exiting', {
|
|
216
|
+
workflowRunId: runId,
|
|
217
|
+
eventType: terminalRunEvent.eventType,
|
|
218
|
+
eventId: terminalRunEvent.eventId,
|
|
219
|
+
});
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
/** How many of `ids` are absent from `present`. */
|
|
223
|
+
function countMissingIds(ids, present) {
|
|
224
|
+
let missing = 0;
|
|
225
|
+
for (const id of ids) {
|
|
226
|
+
if (!present.has(id))
|
|
227
|
+
missing++;
|
|
228
|
+
}
|
|
229
|
+
return missing;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The lineage root of a loaded run: its `$rootRunId` attribute, or its own id
|
|
233
|
+
* when it is itself a root.
|
|
234
|
+
*/
|
|
235
|
+
function rootRunIdFrom(attributes, runId) {
|
|
236
|
+
return attributes?.[ROOT_RUN_ID_ATTRIBUTE] ?? runId;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Whether the run has a hook and/or wait that an out-of-band writer could
|
|
240
|
+
* append an event for between an inline step's `step_completed` write and
|
|
241
|
+
* the next replay — namely an open hook (a `hook_created` not yet
|
|
242
|
+
* `hook_disposed`, which a webhook receiver can resolve with
|
|
243
|
+
* `hook_received`) or an open wait (a `wait_created` not yet
|
|
244
|
+
* `wait_completed`, which the wait timer can resolve with
|
|
245
|
+
* `wait_completed`).
|
|
246
|
+
*
|
|
247
|
+
* This gates VM retention, the inline-delta fast path, and turbo's forced
|
|
248
|
+
* optimistic start. A terminal-step delta can omit an event appended
|
|
249
|
+
* concurrently after that write. With no open hook or wait, only cancellation
|
|
250
|
+
* can do so, and observing it one replay late is safe because the next entity
|
|
251
|
+
* write is rejected.
|
|
252
|
+
*
|
|
253
|
+
* Step-body `attr_set` writes are NOT a concern: they land before the
|
|
254
|
+
* step's terminal write and are therefore already inside the returned
|
|
255
|
+
* delta.
|
|
256
|
+
*/
|
|
257
|
+
function openHookAndWaitState(events) {
|
|
258
|
+
const hooks = new Set();
|
|
259
|
+
const waits = new Set();
|
|
260
|
+
for (const event of events) {
|
|
261
|
+
switch (event.eventType) {
|
|
262
|
+
case 'hook_created':
|
|
263
|
+
hooks.add(event.correlationId);
|
|
264
|
+
break;
|
|
265
|
+
case 'hook_disposed':
|
|
266
|
+
hooks.delete(event.correlationId);
|
|
267
|
+
break;
|
|
268
|
+
case 'wait_created':
|
|
269
|
+
waits.add(event.correlationId);
|
|
270
|
+
break;
|
|
271
|
+
case 'wait_completed':
|
|
272
|
+
waits.delete(event.correlationId);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { openHook: hooks.size > 0, openWait: waits.size > 0 };
|
|
277
|
+
}
|
|
278
|
+
function nextEventLogLoad(log) {
|
|
279
|
+
if (log.cursor === null) {
|
|
280
|
+
return { type: 'loadAll' };
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
type: 'loadAfter',
|
|
284
|
+
events: log.events,
|
|
285
|
+
cursor: log.cursor,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function appendEventLog(log, appended) {
|
|
289
|
+
appendUniqueEvents(log.events, appended.events);
|
|
290
|
+
log.cursor = appended.cursor ?? log.cursor;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The whole retention predicate: keep the session only for a pure step
|
|
294
|
+
* boundary (every suspension item is a step — any other item type, present
|
|
295
|
+
* or future, is unretainable by default) whose new step inputs serialized
|
|
296
|
+
* without executing workflow code, with no out-of-band continuation source:
|
|
297
|
+
* attributes require replay; hooks and waits can wake another invocation.
|
|
298
|
+
* `WORKFLOW_RETAINED_VM=0` disables retention entirely.
|
|
299
|
+
*
|
|
300
|
+
* The open hook/wait scan is O(events), so it is taken through a lazy getter
|
|
301
|
+
* and consulted last, after every cheap check has passed.
|
|
302
|
+
*
|
|
303
|
+
* INVARIANT this predicate leans on: every suspension signaler that does NOT
|
|
304
|
+
* carry the step-consumer generation guard (sleep, hook, attribute — see
|
|
305
|
+
* `suspensionGeneration` in private.ts) must be unretainable here, either via
|
|
306
|
+
* a non-step queue item or the open hook/wait scan. A new signaler that
|
|
307
|
+
* satisfies neither would let a stale signal be accepted as a fresh
|
|
308
|
+
* suspension on a resumed session.
|
|
309
|
+
*
|
|
310
|
+
* Quiescence assumes workflow code stays inside the sandbox's determinism
|
|
311
|
+
* contract. Escaping to the host realm (e.g. recovering the host `Function`
|
|
312
|
+
* constructor from an exposed host class to schedule real timers) makes a
|
|
313
|
+
* workflow nondeterministic under ordinary replay too, and is not defended
|
|
314
|
+
* here.
|
|
315
|
+
*/
|
|
316
|
+
function canRetainWorkflowSession(suspension, stepInputsSafe, openHookWait) {
|
|
317
|
+
if (!isVmRetentionEnabled() ||
|
|
318
|
+
!stepInputsSafe ||
|
|
319
|
+
suspension.steps.length === 0 ||
|
|
320
|
+
!suspension.steps.every((item) => item.type === 'step')) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
const { openHook, openWait } = openHookWait.value;
|
|
324
|
+
return !openHook && !openWait;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Maximum inline-execution duration for a single handler invocation.
|
|
328
|
+
*
|
|
329
|
+
* Order of precedence:
|
|
330
|
+
* 1. `WORKFLOW_V2_TIMEOUT_MS` env var
|
|
331
|
+
* 2. Tiered budget derived from `world.getRuntimeDeadline()`
|
|
332
|
+
* 3. Default of 2 minutes
|
|
333
|
+
*/
|
|
334
|
+
async function getMaxInlineDurationMs(world, invocationStartTime) {
|
|
335
|
+
const rawEnvOverride = process.env.WORKFLOW_V2_TIMEOUT_MS;
|
|
336
|
+
if (rawEnvOverride !== undefined && rawEnvOverride !== '') {
|
|
337
|
+
const parsed = Number(rawEnvOverride);
|
|
338
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
339
|
+
return parsed;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const runtimeDeadline = await world.getRuntimeDeadline?.();
|
|
343
|
+
if (runtimeDeadline !== undefined) {
|
|
344
|
+
const deadlineMs = runtimeDeadline.getTime();
|
|
345
|
+
if (!Number.isNaN(deadlineMs)) {
|
|
346
|
+
const maxDurationMs = Math.floor(deadlineMs - invocationStartTime);
|
|
347
|
+
if (maxDurationMs >= ms('25m')) {
|
|
348
|
+
return ms('10m');
|
|
349
|
+
}
|
|
350
|
+
if (maxDurationMs >= ms('10m')) {
|
|
351
|
+
return ms('5m');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return ms('2m');
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Creates a single route which handles workflow execution requests,
|
|
359
|
+
* executing steps inline when possible to reduce function invocations
|
|
360
|
+
* and queue overhead.
|
|
361
|
+
*
|
|
362
|
+
* The handler loops: replay workflow → execute step inline → replay → ...
|
|
363
|
+
* until the workflow completes, times out, or encounters non-step suspensions.
|
|
364
|
+
*
|
|
365
|
+
* @param workflowCode - The workflow bundle code containing all workflow functions
|
|
366
|
+
* @returns A function that can be used as a Vercel API route
|
|
367
|
+
*/
|
|
368
|
+
export function workflowEntrypoint(workflowCode, options) {
|
|
369
|
+
setWorkflowBasePath(options?.basePath);
|
|
370
|
+
const namespace = resolveQueueNamespace(options?.namespace);
|
|
371
|
+
const workflowPrefix = getQueueTopicPrefix('workflow', namespace);
|
|
372
|
+
const handler = (worldHandlers) => worldHandlers.createQueueHandler(workflowPrefix, async (message_, metadata) => {
|
|
36
373
|
// Check if this is a health check message
|
|
37
374
|
// NOTE: Health check messages are intentionally unauthenticated for monitoring purposes.
|
|
38
375
|
// They only write a simple status response to a stream and do not expose sensitive data.
|
|
39
376
|
// The stream name includes a unique correlationId that must be known by the caller.
|
|
40
377
|
const healthCheck = parseHealthCheckPayload(message_);
|
|
41
378
|
if (healthCheck) {
|
|
42
|
-
await handleHealthCheckMessage(healthCheck,
|
|
379
|
+
await handleHealthCheckMessage(healthCheck, worldHandlers.specVersion);
|
|
43
380
|
return;
|
|
44
381
|
}
|
|
45
|
-
const { runId, traceCarrier:
|
|
382
|
+
const { runId, traceCarrier: incomingTraceCarrier, requestedAt, stepId: incomingStepId, stepName: incomingStepName, replayDivergence, preconditionReinvocations, deploymentMismatchRetryCount, runInput, hookInput, } = WorkflowInvokePayloadSchema.parse(message_);
|
|
383
|
+
// `start()` always attaches a trace carrier, but
|
|
384
|
+
// serializeTraceCarrier() returns `{}` when no OTEL SDK is registered
|
|
385
|
+
// or no span is active — treat an empty carrier the same as an
|
|
386
|
+
// absent one so linked mode falls back to a fresh origin instead of
|
|
387
|
+
// forwarding a useless `{}` forever.
|
|
388
|
+
const traceContext = isUsableTraceCarrier(incomingTraceCarrier)
|
|
389
|
+
? incomingTraceCarrier
|
|
390
|
+
: undefined;
|
|
46
391
|
const { requestId } = metadata;
|
|
47
|
-
|
|
48
|
-
const workflowName = metadata.queueName.slice('__wkf_workflow_'.length);
|
|
392
|
+
const workflowName = metadata.queueName.slice(workflowPrefix.length);
|
|
49
393
|
// --- Max delivery check ---
|
|
50
394
|
// Enforce max delivery limit before any infrastructure calls.
|
|
51
395
|
// This prevents runaway workflows from consuming infinite queue deliveries.
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (metadata.attempt >
|
|
57
|
-
|
|
396
|
+
// Scoped logger for this run — attaches runId/workflowName to every
|
|
397
|
+
// log line and child loggers below, so callers don't repeat it.
|
|
398
|
+
const runLogger = runtimeLogger.forRun(runId, workflowName);
|
|
399
|
+
const maxQueueDeliveries = getMaxQueueDeliveries();
|
|
400
|
+
if (metadata.attempt > maxQueueDeliveries) {
|
|
401
|
+
const maxDeliveriesDescription = describeError(undefined, RUN_ERROR_CODES.MAX_DELIVERIES_EXCEEDED);
|
|
402
|
+
runLogger.error(`Workflow handler exceeded max deliveries (${metadata.attempt}/${maxQueueDeliveries})`, {
|
|
403
|
+
attempt: metadata.attempt,
|
|
404
|
+
errorCode: maxDeliveriesDescription.errorCode,
|
|
405
|
+
errorAttribution: maxDeliveriesDescription.attribution,
|
|
406
|
+
});
|
|
58
407
|
try {
|
|
59
408
|
const world = await getWorld();
|
|
409
|
+
const getEncryptionKey = memoizeEncryptionKey(world, runId);
|
|
410
|
+
const err = new FatalError(`Workflow exceeded maximum queue deliveries (${metadata.attempt}/${maxQueueDeliveries})`);
|
|
60
411
|
await world.events.create(runId, {
|
|
61
412
|
eventType: 'run_failed',
|
|
62
413
|
specVersion: SPEC_VERSION_CURRENT,
|
|
63
414
|
eventData: {
|
|
64
|
-
error:
|
|
65
|
-
message: `Workflow exceeded maximum queue deliveries (${metadata.attempt}/${MAX_QUEUE_DELIVERIES})`,
|
|
66
|
-
},
|
|
415
|
+
error: await dehydrateRunError(err, runId, await getEncryptionKey()),
|
|
67
416
|
errorCode: RUN_ERROR_CODES.MAX_DELIVERIES_EXCEEDED,
|
|
68
417
|
},
|
|
69
418
|
}, { requestId });
|
|
@@ -73,97 +422,974 @@ export function workflowEntrypoint(workflowCode) {
|
|
|
73
422
|
// Run already finished, consume the message silently
|
|
74
423
|
return;
|
|
75
424
|
}
|
|
76
|
-
|
|
425
|
+
runLogger.error(`Failed to mark run as failed after ${metadata.attempt} delivery attempts. ` +
|
|
77
426
|
`A persistent error is preventing the run from being terminated. ` +
|
|
78
427
|
`The run will remain in its current state until manually resolved. ` +
|
|
79
428
|
`This is most likely due to a persistent outage of the workflow backend ` +
|
|
80
429
|
`or a bug in the workflow runtime and should be reported to the Workflow team.`, {
|
|
81
|
-
workflowRunId: runId,
|
|
82
|
-
error: err instanceof Error ? err.message : String(err),
|
|
83
430
|
attempt: metadata.attempt,
|
|
431
|
+
errorName: err instanceof Error ? err.name : 'UnknownError',
|
|
432
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
433
|
+
errorStack: err instanceof Error ? err.stack : undefined,
|
|
84
434
|
});
|
|
85
435
|
}
|
|
86
436
|
return;
|
|
87
437
|
}
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
// Best effort — process exits regardless
|
|
122
|
-
}
|
|
123
|
-
// Note that this also prevents the runtime from acking the queue message,
|
|
124
|
-
// so the queue will call back once, after which a 410 will get it to exit early.
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}, REPLAY_TIMEOUT_MS);
|
|
127
|
-
replayTimeout.unref();
|
|
128
|
-
}
|
|
129
|
-
// Invoke user workflow within the propagated trace context and baggage
|
|
130
|
-
return await withTraceContext(traceContext, async () => {
|
|
131
|
-
// Set workflow context as baggage for automatic propagation
|
|
438
|
+
// --- Trace correlation mode ---
|
|
439
|
+
// 'linked' (default): the workflow.execute span below stays a CHILD
|
|
440
|
+
// of the local delivery (flow-route) context, so one invocation —
|
|
441
|
+
// route handler, workflow replay, inline steps, event writes — is a
|
|
442
|
+
// single bounded trace. The run-origin context travels as a span
|
|
443
|
+
// LINK (not a parent), and re-enqueues forward the original carrier
|
|
444
|
+
// unchanged, so a (potentially hours-long) run is never stitched
|
|
445
|
+
// into one giant trace across invocations.
|
|
446
|
+
// 'continuous': legacy behavior — the restored run-origin context
|
|
447
|
+
// becomes the parent of this invocation's spans.
|
|
448
|
+
const traceMode = getWorkflowTraceMode();
|
|
449
|
+
// Trace carrier to attach to messages this invocation enqueues —
|
|
450
|
+
// see getNextTraceCarrier for the linked/continuous semantics.
|
|
451
|
+
const nextTraceCarrier = () => getNextTraceCarrier(traceMode, traceContext);
|
|
452
|
+
// Span links to the incoming delivery context and (in linked mode)
|
|
453
|
+
// the run-origin context from the trace carrier.
|
|
454
|
+
const spanLinks = await buildInvocationSpanLinks(traceMode, traceContext);
|
|
455
|
+
// The replay budget covers orchestration work between steps, not inline
|
|
456
|
+
// step bodies. It is checked between loop iterations; step bodies use
|
|
457
|
+
// the platform timeout and NO_INLINE_REPLAY_AFTER_MS guard instead.
|
|
458
|
+
const replayBudget = new ReplayBudget();
|
|
459
|
+
// In linked mode the run-origin context is NOT restored as the
|
|
460
|
+
// active (parent) context — passing `undefined` makes
|
|
461
|
+
// withTraceContext a passthrough, so the workflow.execute span below
|
|
462
|
+
// stays a child of the local delivery (flow-route) context and the
|
|
463
|
+
// run-origin travels as a span link instead.
|
|
464
|
+
const parentTraceCarrier = traceMode === 'continuous' ? traceContext : undefined;
|
|
465
|
+
// Queue-delivered invocation: CONSUMER kind, matching the
|
|
466
|
+
// queue-delivered step.execute span.
|
|
467
|
+
const spanKind = await getSpanKind('CONSUMER');
|
|
468
|
+
return await withTraceContext(parentTraceCarrier, async () => {
|
|
132
469
|
return await withWorkflowBaggage({ workflowRunId: runId, workflowName }, async () => {
|
|
133
|
-
const world = await getWorld();
|
|
134
|
-
|
|
470
|
+
const world = await trace('workflow.route.get_world', async () => getWorld());
|
|
471
|
+
// Both checks below look at `runInput`, so both are no-ops on a
|
|
472
|
+
// re-enqueued message (which carries none) — they only ever run on
|
|
473
|
+
// a first delivery, the one that could create the run.
|
|
474
|
+
//
|
|
475
|
+
// Returning acks the message. That is deliberate: the mismatch is
|
|
476
|
+
// baked into this message, so every redelivery would reach the
|
|
477
|
+
// same verdict, and throwing would just hot-loop the handler until
|
|
478
|
+
// MAX_QUEUE_DELIVERIES with the same error each time. It matches
|
|
479
|
+
// how the run_started path already discards deliveries whose
|
|
480
|
+
// verdict cannot change (EntityConflictError, RunExpiredError).
|
|
481
|
+
if (refuseCrossEnvironmentDelivery({
|
|
482
|
+
world,
|
|
483
|
+
runInput,
|
|
484
|
+
runId,
|
|
485
|
+
runLogger,
|
|
486
|
+
})) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
// Diagnostic only — see the helper for why this warns instead of
|
|
490
|
+
// refusing the invocation.
|
|
491
|
+
await warnOnDeploymentPinningMismatch({
|
|
492
|
+
world,
|
|
493
|
+
runInput,
|
|
494
|
+
runId,
|
|
495
|
+
runLogger,
|
|
496
|
+
});
|
|
497
|
+
return trace(`workflow.execute ${workflowDisplayName(workflowName)}`, { kind: spanKind, links: spanLinks }, async (span) => {
|
|
135
498
|
span?.setAttributes({
|
|
136
499
|
...Attribute.WorkflowName(workflowName),
|
|
137
|
-
...Attribute.WorkflowOperation('
|
|
138
|
-
// Standard OTEL messaging conventions
|
|
500
|
+
...Attribute.WorkflowOperation('execute_v2'),
|
|
139
501
|
...Attribute.MessagingSystem('vercel-queue'),
|
|
140
502
|
...Attribute.MessagingDestinationName(metadata.queueName),
|
|
141
503
|
...Attribute.MessagingMessageId(metadata.messageId),
|
|
142
504
|
...Attribute.MessagingOperationType('process'),
|
|
143
505
|
...getQueueOverhead({ requestedAt }),
|
|
144
|
-
});
|
|
145
|
-
// TODO: validate `workflowName` exists before consuming message?
|
|
146
|
-
span?.setAttributes({
|
|
147
506
|
...Attribute.WorkflowRunId(runId),
|
|
148
507
|
...Attribute.WorkflowTracePropagated(!!traceContext),
|
|
508
|
+
...Attribute.WorkflowTraceMode(traceMode),
|
|
149
509
|
});
|
|
150
|
-
|
|
510
|
+
const invocationStartTime = Date.now();
|
|
511
|
+
const noInlineReplayAfterMs = await getMaxInlineDurationMs(world, invocationStartTime);
|
|
512
|
+
let loopIteration = 0;
|
|
513
|
+
const replayRecoveryReporter = replayDivergence
|
|
514
|
+
? new ReplayRecoveryReporter(replayDivergence.count)
|
|
515
|
+
: ReplayRecoveryReporter.inert();
|
|
516
|
+
// Every write this loop makes carries the cursor of the log
|
|
517
|
+
// it was computed against, and folds a complete returned
|
|
518
|
+
// delta into that log.
|
|
519
|
+
const createEvent = async (data, params) => {
|
|
520
|
+
const sinceCursor = deltaRequestCursor(data, params);
|
|
521
|
+
const result = await replayRecoveryReporter.withEventCreate(sinceCursor === undefined
|
|
522
|
+
? params
|
|
523
|
+
: { ...params, sinceCursor }, (p) => world.events.create(runId, data, p));
|
|
524
|
+
if (sinceCursor !== undefined) {
|
|
525
|
+
absorbCreateDelta(sinceCursor, result);
|
|
526
|
+
}
|
|
527
|
+
return result;
|
|
528
|
+
};
|
|
529
|
+
/**
|
|
530
|
+
* The cursor to ask for an inline delta against, or
|
|
531
|
+
* undefined to not ask.
|
|
532
|
+
*
|
|
533
|
+
* Turbo is excluded on purpose: it exists to make the first
|
|
534
|
+
* invocation's writes as cheap as possible, and it has no
|
|
535
|
+
* loaded log to extend. Run-terminal writes are excluded
|
|
536
|
+
* because nothing reads the log afterwards, so the delta
|
|
537
|
+
* would be work the World does for no one. A caller that
|
|
538
|
+
* set its own `sinceCursor` (or asked for the `run_started`
|
|
539
|
+
* / `hook_received` preload, which owns the same response
|
|
540
|
+
* fields) keeps what it asked for.
|
|
541
|
+
*/
|
|
542
|
+
const deltaRequestCursor = (data, params) => {
|
|
543
|
+
if (turbo ||
|
|
544
|
+
eventLog.type !== 'ready' ||
|
|
545
|
+
params?.sinceCursor !== undefined ||
|
|
546
|
+
params?.preloadEvents === true ||
|
|
547
|
+
isTerminalRunEventType(data.eventType)) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
return eventLog.cursor ?? undefined;
|
|
551
|
+
};
|
|
552
|
+
/**
|
|
553
|
+
* Fold an inline delta returned by `events.create` into the
|
|
554
|
+
* in-memory event log.
|
|
555
|
+
*
|
|
556
|
+
* The delta is what `events.list({ cursor: sentCursor })`
|
|
557
|
+
* would have returned right after the write, so it carries
|
|
558
|
+
* back both our own event and anything another writer
|
|
559
|
+
* appended in band. Absorbing it here means the next reader
|
|
560
|
+
* already has the log and the loop's incremental
|
|
561
|
+
* `events.list` finds nothing left to fetch.
|
|
562
|
+
*
|
|
563
|
+
* Declining is always safe — an unabsorbed delta is a delta
|
|
564
|
+
* the next `events.list` returns — so the guards are free to
|
|
565
|
+
* be strict:
|
|
566
|
+
*
|
|
567
|
+
* - `hasMore` means the World truncated the page. Taking it
|
|
568
|
+
* while advancing the cursor to the page end would be
|
|
569
|
+
* fine, but taking it and NOT advancing would duplicate,
|
|
570
|
+
* and the truncated case is rare enough not to special-case.
|
|
571
|
+
* - The cursor must be exactly where it was when the request
|
|
572
|
+
* went out. Concurrent writes each diff against the cursor
|
|
573
|
+
* they saw, and `appendUniqueEvents` deliberately does not
|
|
574
|
+
* re-sort, so absorbing a second delta computed from an
|
|
575
|
+
* older cursor could append events behind ones already
|
|
576
|
+
* taken. First response back wins; the rest are dropped.
|
|
577
|
+
*/
|
|
578
|
+
const absorbCreateDelta = (sentCursor, result) => {
|
|
579
|
+
if (eventLog.type !== 'ready' ||
|
|
580
|
+
eventLog.cursor !== sentCursor ||
|
|
581
|
+
result.events === undefined ||
|
|
582
|
+
result.hasMore === true) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
appendEventLog(eventLog, {
|
|
586
|
+
events: result.events,
|
|
587
|
+
cursor: result.cursor,
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
// `ready` can replay once without a read. The other states
|
|
591
|
+
// describe the next load exactly.
|
|
592
|
+
let eventLog = { type: 'loadAll' };
|
|
593
|
+
// Shared state: set by either the background step path
|
|
594
|
+
// or the run_started setup below.
|
|
151
595
|
let workflowRun;
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
let
|
|
596
|
+
// Server-supplied per-run event ceiling from the run_started
|
|
597
|
+
// response. Undefined ⇒ no enforcement (older servers, turbo).
|
|
598
|
+
let maxEventsLimit;
|
|
599
|
+
let workflowStartedAt = -1;
|
|
600
|
+
// Latency telemetry (TTFS) state — see runtime/step-latency.ts.
|
|
601
|
+
// Whether this invocation's FIRST event snapshot contained
|
|
602
|
+
// nothing beyond run_created/run_started: anything else was
|
|
603
|
+
// written by an earlier invocation, whose contribution to
|
|
604
|
+
// time-to-first-step (including the queue hop back here)
|
|
605
|
+
// cannot be measured wall-clock, so TTFS is not reported.
|
|
606
|
+
// Set once, on the first iteration's loaded snapshot.
|
|
607
|
+
let invocationStartedClean;
|
|
608
|
+
// Epoch ms the `run_started` response was received/parsed
|
|
609
|
+
// by the SDK — anchors RSFS (run_started → first step's
|
|
610
|
+
// start POST). Set once, in the run_started setup below.
|
|
611
|
+
// Under turbo, run_started is backgrounded rather than
|
|
612
|
+
// awaited, so this is stamped at the point the run is
|
|
613
|
+
// synthesized locally instead of the real response — see
|
|
614
|
+
// StepLatencyTracking.rsfsAnchorMs.
|
|
615
|
+
let runStartedReceivedAtMs;
|
|
616
|
+
// Wall-clock ms spent committing hook_created events before
|
|
617
|
+
// the first step ran, accumulated across suspension passes
|
|
618
|
+
// and subtracted from TTFS. Accumulators here survive an
|
|
619
|
+
// in-process replay restart (a stale-snapshot rejection, or
|
|
620
|
+
// the attribute-event restart below), so a restarted
|
|
621
|
+
// invocation over-counts by the abandoned pass's hook time —
|
|
622
|
+
// the same slight over-count either restart has always had.
|
|
623
|
+
let preStepBlockingMs = 0;
|
|
624
|
+
// Snapshot of the accumulator as of the suspension that
|
|
625
|
+
// wrote the run's first attr_set (whose hook phase ran
|
|
626
|
+
// before its attr writes). When a pre-step setAttributes
|
|
627
|
+
// ends the TTFS measurement at the attr write, only hook
|
|
628
|
+
// time from BEFORE that point may be subtracted — later
|
|
629
|
+
// hook writes fall outside the measured window.
|
|
630
|
+
let preStepBlockingBeforeAttrMs;
|
|
631
|
+
// Turbo mode fast-paths the very first delivery of the very
|
|
632
|
+
// first invocation, where it is provably safe to: background
|
|
633
|
+
// `run_started`, skip the initial event-log load (nothing has
|
|
634
|
+
// been written yet), and force optimistic inline start (no
|
|
635
|
+
// concurrent peer handler exists to race the create-claim).
|
|
636
|
+
// `runInput` is only present on the start()-enqueued message,
|
|
637
|
+
// and `attempt === 1` (1-based) means this is the first
|
|
638
|
+
// delivery; `incomingStepId` would mark a background-step
|
|
639
|
+
// invocation and `replayDivergence` a recovery replay — both
|
|
640
|
+
// ineligible. The single-handler guarantee that makes forced
|
|
641
|
+
// optimistic start safe ends once a hook or wait is created
|
|
642
|
+
// (they introduce resume invocations), so turbo exits at that
|
|
643
|
+
// point (see `forceOptimisticStart`). Workflow attribute
|
|
644
|
+
// writes introduce no such invocation source — they resolve
|
|
645
|
+
// via an in-process replay and don't end turbo.
|
|
646
|
+
// NOTE: `metadata.attempt === 1` is also load-bearing for
|
|
647
|
+
// inline step ownership: owned-recovery steps (a step
|
|
648
|
+
// stamped by a PREVIOUS delivery of this message) can only
|
|
649
|
+
// exist on attempt ≥ 2, so turbo and owned recovery are
|
|
650
|
+
// mutually exclusive. The turbo `reinvoke()` paths (hook
|
|
651
|
+
// conflict, throttle backoff) ack this message and continue
|
|
652
|
+
// under a NEW message id — safe only because no
|
|
653
|
+
// non-terminal step can be inline-owned by the acked id
|
|
654
|
+
// when turbo is on. If turbo ever engages on redeliveries,
|
|
655
|
+
// those paths must first check for owned pending steps and
|
|
656
|
+
// fall back to `{ timeoutSeconds }` redelivery.
|
|
657
|
+
const turbo = isTurboEnabled() &&
|
|
658
|
+
runInput !== undefined &&
|
|
659
|
+
metadata.attempt === 1 &&
|
|
660
|
+
incomingStepId === undefined &&
|
|
661
|
+
!replayDivergence;
|
|
662
|
+
span?.setAttributes(Attribute.WorkflowTurbo(turbo));
|
|
663
|
+
// Turbo mode only: resolves once the backgrounded
|
|
664
|
+
// `run_started` has landed (or rejects if it failed). Threaded
|
|
665
|
+
// into handleSuspension and executeStep so no step/hook/wait
|
|
666
|
+
// write races ahead of the run's creation. Undefined outside
|
|
667
|
+
// turbo, where `run_started` is awaited up front.
|
|
668
|
+
let runReadyBarrier;
|
|
669
|
+
// Order a terminal run write (run_completed / run_failed) after
|
|
670
|
+
// the backgrounded run_started in turbo mode — a no-step
|
|
671
|
+
// workflow can otherwise reach run_completed before the run
|
|
672
|
+
// exists. Best-effort: a barrier rejection is swallowed for
|
|
673
|
+
// ordering only; if run_started truly failed the terminal write
|
|
674
|
+
// surfaces the real error (run not found / gone) and the message
|
|
675
|
+
// redelivers. No-op outside turbo.
|
|
676
|
+
const awaitRunReady = async () => {
|
|
677
|
+
if (runReadyBarrier) {
|
|
678
|
+
try {
|
|
679
|
+
await runReadyBarrier;
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
// intentional: ordering barrier only — see above.
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
// Re-invoke the orchestrator. Outside turbo this returns
|
|
687
|
+
// `{ timeoutSeconds }`, which makes the queue reschedule the
|
|
688
|
+
// CURRENT delivery's message. In turbo that is a trap: the
|
|
689
|
+
// current message carries `runInput`, and on async queues
|
|
690
|
+
// (e.g. graphile-worker) a reschedule comes back as delivery
|
|
691
|
+
// attempt 1 — so turbo re-engages, skips the event-log load
|
|
692
|
+
// again, replays against an empty log, never observes the
|
|
693
|
+
// hook event this invocation just wrote, and re-suspends
|
|
694
|
+
// forever (the run wedges). Under turbo we instead enqueue an
|
|
695
|
+
// explicit continuation that carries NO `runInput`, so the
|
|
696
|
+
// next delivery is a normal (non-turbo) load-and-replay that
|
|
697
|
+
// observes the committed events and makes progress; we then
|
|
698
|
+
// return `undefined` so the queue treats this delivery as done
|
|
699
|
+
// rather than also rescheduling it.
|
|
700
|
+
// Inline-ownership invariant guard: correlation IDs of
|
|
701
|
+
// steps whose bodies this invocation is executing under an
|
|
702
|
+
// ownership stamp (lazy inline + owned recovery), while the
|
|
703
|
+
// body is in flight. Crash recovery depends on the owning
|
|
704
|
+
// message NOT being acked while such a step is non-terminal
|
|
705
|
+
// (ack = handler return or reinvoke, which acks + enqueues
|
|
706
|
+
// under a NEW message id — the redelivery of the old id is
|
|
707
|
+
// what re-executes an orphaned owned step). All executeStep
|
|
708
|
+
// calls are awaited before any ack path runs, so this set
|
|
709
|
+
// is empty at every ack by construction; the check exists
|
|
710
|
+
// to catch future refactors that break that ordering.
|
|
711
|
+
const inFlightOwnedSteps = new Set();
|
|
712
|
+
const assertNoInFlightOwnedSteps = (ackPath) => {
|
|
713
|
+
if (inFlightOwnedSteps.size > 0) {
|
|
714
|
+
runtimeLogger.error('Invariant violation: acking the workflow message while owned inline steps are still executing — crash recovery for these steps is broken', {
|
|
715
|
+
workflowRunId: runId,
|
|
716
|
+
ackPath,
|
|
717
|
+
stepIds: [...inFlightOwnedSteps],
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
// A plain orchestrator-replay message. Omits `runInput` (it
|
|
722
|
+
// re-engages turbo on the next delivery and wedges the run —
|
|
723
|
+
// see `reinvoke` below) and `replayDivergence` /
|
|
724
|
+
// `serverErrorRetryCount` (this delivery chain's budgets).
|
|
725
|
+
const replayMessage = async () => ({
|
|
726
|
+
runId,
|
|
727
|
+
traceCarrier: await nextTraceCarrier(),
|
|
728
|
+
requestedAt: new Date(),
|
|
729
|
+
});
|
|
730
|
+
const reinvoke = async (delaySeconds,
|
|
731
|
+
/**
|
|
732
|
+
* Extra fields to carry on the new message. Only reaches the
|
|
733
|
+
* next invocation on the turbo path: without turbo no
|
|
734
|
+
* message is enqueued at all — the handler returns a
|
|
735
|
+
* visibility timeout and the queue redelivers the CURRENT
|
|
736
|
+
* message, whose body (and therefore any counter on it)
|
|
737
|
+
* cannot be changed.
|
|
738
|
+
*/
|
|
739
|
+
extraPayload) => {
|
|
740
|
+
assertNoInFlightOwnedSteps('reinvoke');
|
|
741
|
+
if (!turbo)
|
|
742
|
+
return { timeoutSeconds: delaySeconds };
|
|
743
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), { ...(await replayMessage()), ...extraPayload }, delaySeconds > 0 ? { delaySeconds } : undefined);
|
|
744
|
+
return undefined;
|
|
745
|
+
};
|
|
746
|
+
// Precondition (412) recovery: how many times this invocation
|
|
747
|
+
// has thrown away its replay and started over in-process.
|
|
748
|
+
let preconditionRestarts = 0;
|
|
749
|
+
/**
|
|
750
|
+
* Event ids the discarded replay held, kept until the next
|
|
751
|
+
* load resolves so a restart can report what its reload
|
|
752
|
+
* actually found. Without this a 412 only ever tells you that
|
|
753
|
+
* a restart happened, which conflates two very different
|
|
754
|
+
* situations: a log that grew (expected — the fence did its
|
|
755
|
+
* job) and a log that came back identical, which means client
|
|
756
|
+
* and backend disagree about the count for the same set of
|
|
757
|
+
* events and the restart will re-derive the same snapshot and
|
|
758
|
+
* be rejected again.
|
|
759
|
+
*/
|
|
760
|
+
let preconditionRestartBaseline = null;
|
|
761
|
+
/**
|
|
762
|
+
* Report what a stale-snapshot restart's reload found, once
|
|
763
|
+
* the log this replay will actually consume is in hand.
|
|
764
|
+
*
|
|
765
|
+
* `grew` is the expected case and gives 412 volume a
|
|
766
|
+
* denominator. `unchanged` means the reload disagreed with
|
|
767
|
+
* the rejection, so this replay re-derives the same snapshot
|
|
768
|
+
* and is rejected again until the budget is spent. `shrank`
|
|
769
|
+
* should be impossible: every load path only adds to a run's
|
|
770
|
+
* log.
|
|
771
|
+
*/
|
|
772
|
+
const reportPreconditionRestartReload = (events) => {
|
|
773
|
+
const baseline = preconditionRestartBaseline;
|
|
774
|
+
if (!baseline)
|
|
775
|
+
return;
|
|
776
|
+
preconditionRestartBaseline = null;
|
|
777
|
+
const reloadedIds = new Set(events.map((event) => event.eventId));
|
|
778
|
+
const added = countMissingIds(reloadedIds, baseline.ids);
|
|
779
|
+
const dropped = countMissingIds(baseline.ids, reloadedIds);
|
|
780
|
+
const outcome = dropped > 0 ? 'shrank' : added > 0 ? 'grew' : 'unchanged';
|
|
781
|
+
runtimeLogger.warn('Restarted replay reloaded its event log after a stale-snapshot rejection', {
|
|
782
|
+
workflowRunId: runId,
|
|
783
|
+
outcome,
|
|
784
|
+
added,
|
|
785
|
+
dropped,
|
|
786
|
+
eventsBefore: baseline.ids.size,
|
|
787
|
+
eventsAfter: reloadedIds.size,
|
|
788
|
+
preconditionRestarts: baseline.restart,
|
|
789
|
+
reason: baseline.reason,
|
|
790
|
+
source: baseline.source,
|
|
791
|
+
loopIteration,
|
|
792
|
+
});
|
|
793
|
+
};
|
|
794
|
+
/**
|
|
795
|
+
* Recover from a stale-snapshot rejection by restarting the
|
|
796
|
+
* replay inside this invocation, returning false when the
|
|
797
|
+
* per-invocation budget is spent (the caller then falls back
|
|
798
|
+
* to a fresh invocation).
|
|
799
|
+
*
|
|
800
|
+
* A 412 means the log this replay derived its events from was
|
|
801
|
+
* missing an event the backend had already recorded. The
|
|
802
|
+
* rejected write cannot simply be retried: correlation ids
|
|
803
|
+
* are positional ordinals of one seeded sequence, so a replay
|
|
804
|
+
* over the corrected log mints a different id for the same
|
|
805
|
+
* logical event, and re-posting this one would persist an
|
|
806
|
+
* event no correct replay ever produces. The whole replay has
|
|
807
|
+
* to be re-derived — which the loop does by discarding its
|
|
808
|
+
* cached log, since `runWorkflow` then builds a fresh VM,
|
|
809
|
+
* seed and correlation-id sequence from the reloaded events.
|
|
810
|
+
*/
|
|
811
|
+
const restartReplayInProcess = (reason, error,
|
|
812
|
+
/**
|
|
813
|
+
* Set false when writes this invocation made concurrently
|
|
814
|
+
* with the rejected one may be missing from the 412's
|
|
815
|
+
* delta: the World computed that delta against the
|
|
816
|
+
* rejected request's snapshot, so it cannot contain an
|
|
817
|
+
* event a sibling committed afterwards, and merging it
|
|
818
|
+
* would restart the replay on a log that is still
|
|
819
|
+
* incomplete. Only a full reload is authoritative then.
|
|
820
|
+
*/
|
|
821
|
+
{ allowDelta = true } = {}) => {
|
|
822
|
+
if (preconditionRestarts >=
|
|
823
|
+
getPreconditionMaxInProcessRestarts()) {
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
preconditionRestarts++;
|
|
827
|
+
// Every stale-snapshot restart invalidates the parked VM:
|
|
828
|
+
// the log it consumed was missing events, so only a fresh
|
|
829
|
+
// replay over the corrected log is authoritative. This
|
|
830
|
+
// also covers the suspension-create 412, which fires
|
|
831
|
+
// before the retention decision (kill switch + step-input
|
|
832
|
+
// gate) ever ran, and the run_completed 412, where a
|
|
833
|
+
// completed session must not be resumed again.
|
|
834
|
+
retainedSession = null;
|
|
835
|
+
// A World MAY return the events we were missing on the 412.
|
|
836
|
+
// Trust it only on the FIRST restart: its completeness proof
|
|
837
|
+
// leans on the backend's own bookkeeping, so if that
|
|
838
|
+
// under-counts, a "complete" delta can still leave a hole.
|
|
839
|
+
// Bounding it to one attempt caps that at a single wasted
|
|
840
|
+
// restart; every later restart does the authoritative load.
|
|
841
|
+
const delta = allowDelta && preconditionRestarts === 1
|
|
842
|
+
? preconditionEventDelta(error, runId)
|
|
843
|
+
: null;
|
|
844
|
+
// A delta is only usable if there is a loaded log to merge
|
|
845
|
+
// it into; without one the restart must load everything.
|
|
846
|
+
const usedDelta = delta !== null && eventLog.type !== 'loadAll';
|
|
847
|
+
// Snapshot the set being discarded while it is still in
|
|
848
|
+
// hand; the comparison happens once the next load resolves.
|
|
849
|
+
preconditionRestartBaseline =
|
|
850
|
+
eventLog.type !== 'loadAll'
|
|
851
|
+
? {
|
|
852
|
+
ids: new Set(eventLog.events.map((event) => event.eventId)),
|
|
853
|
+
restart: preconditionRestarts,
|
|
854
|
+
reason,
|
|
855
|
+
source: usedDelta ? 'inline-delta' : 'full-reload',
|
|
856
|
+
}
|
|
857
|
+
: null;
|
|
858
|
+
if (delta && eventLog.type !== 'loadAll') {
|
|
859
|
+
appendEventLog(eventLog, delta);
|
|
860
|
+
eventLog = { ...eventLog, type: 'ready' };
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
// MUST be a full, cursor-less reload. The cursor filters
|
|
864
|
+
// by lexicographic event id while a hole is defined by
|
|
865
|
+
// ULID *time*: an event in the same millisecond sorts
|
|
866
|
+
// either side of the cursor depending on its random
|
|
867
|
+
// component, and an event minted in an earlier
|
|
868
|
+
// millisecond but committed later always sorts below it.
|
|
869
|
+
// An incremental load therefore heals the hole only by
|
|
870
|
+
// luck.
|
|
871
|
+
eventLog = { type: 'loadAll' };
|
|
872
|
+
// The corrected log inserts the missing events BELOW the
|
|
873
|
+
// length already scanned for payload prewarming, shifting
|
|
874
|
+
// every later position. Only a full rescan sees them.
|
|
875
|
+
replayPayloadCache.resetScan();
|
|
876
|
+
}
|
|
877
|
+
runtimeLogger.warn('Event creation rejected as stale; restarting replay in-process', {
|
|
878
|
+
workflowRunId: runId,
|
|
879
|
+
reason,
|
|
880
|
+
loopIteration,
|
|
881
|
+
preconditionRestarts,
|
|
882
|
+
source: usedDelta ? 'inline-delta' : 'full-reload',
|
|
883
|
+
});
|
|
884
|
+
span?.setAttributes({
|
|
885
|
+
'workflow.precondition_restarts': preconditionRestarts,
|
|
886
|
+
});
|
|
887
|
+
return true;
|
|
888
|
+
};
|
|
889
|
+
/**
|
|
890
|
+
* Escalate a stale-snapshot rejection that survived the
|
|
891
|
+
* in-process restart budget to a fresh invocation, or give up
|
|
892
|
+
* on the run when the per-run budget is also spent.
|
|
893
|
+
*
|
|
894
|
+
* The in-process budget is a closure variable and the queue's
|
|
895
|
+
* delivery count restarts at 1 whenever a new message is
|
|
896
|
+
* enqueued, so a run that is permanently unable to catch up
|
|
897
|
+
* with its own event log would otherwise cycle restarts →
|
|
898
|
+
* re-invoke → restarts with no run-level bound. The chain is
|
|
899
|
+
* therefore counted on the message itself, in the same way
|
|
900
|
+
* replay divergences are, and fails the run once exhausted.
|
|
901
|
+
*
|
|
902
|
+
* The counter only advances on hops that enqueue a new message
|
|
903
|
+
* (see `reinvoke`). A redelivery-based hop keeps the same body
|
|
904
|
+
* and so the same count, but it also keeps advancing
|
|
905
|
+
* `metadata.attempt`, which the max-delivery check at the top
|
|
906
|
+
* of the handler already bounds — and the delay below is what
|
|
907
|
+
* makes that budget span real time rather than being burned in
|
|
908
|
+
* a tight loop.
|
|
909
|
+
*/
|
|
910
|
+
const reinvokeAfterStaleRejection = async (reason, error) => {
|
|
911
|
+
const attempt = (preconditionReinvocations ?? 0) + 1;
|
|
912
|
+
const maxReinvocations = getPreconditionMaxReinvocations();
|
|
913
|
+
if (attempt > maxReinvocations) {
|
|
914
|
+
return {
|
|
915
|
+
reinvoked: false,
|
|
916
|
+
error: new WorkflowRuntimeError(`Event creation was rejected as stale after ${maxReinvocations} re-invocations of ${getPreconditionMaxInProcessRestarts()} in-process replay restarts each: this run cannot observe its own event log completely enough to make progress. Last rejection (${reason}): ${error instanceof Error ? error.message : String(error)}`, { cause: error }),
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
runtimeLogger.warn('Event creation rejected as stale after in-process restarts; re-invoking run for a fresh replay', {
|
|
920
|
+
workflowRunId: runId,
|
|
921
|
+
reason,
|
|
922
|
+
loopIteration,
|
|
923
|
+
preconditionReinvocations: attempt,
|
|
924
|
+
maxReinvocations,
|
|
925
|
+
});
|
|
926
|
+
span?.setAttributes({
|
|
927
|
+
'workflow.precondition_reinvocations': attempt,
|
|
928
|
+
});
|
|
929
|
+
// Delayed, unlike the other reinvoke() callers: the
|
|
930
|
+
// in-process restarts already reloaded the log several times
|
|
931
|
+
// without catching up, so the writers this replay is racing
|
|
932
|
+
// are still active. Retrying instantly just burns the
|
|
933
|
+
// per-run budget at full speed.
|
|
934
|
+
return {
|
|
935
|
+
reinvoked: true,
|
|
936
|
+
result: await reinvoke(getPreconditionReinvokeDelaySeconds(), { preconditionReinvocations: attempt }),
|
|
937
|
+
};
|
|
938
|
+
};
|
|
939
|
+
// Deployment-affinity guard, shared by the two paths that
|
|
940
|
+
// execute a run: queued step executions and flow replays.
|
|
941
|
+
const guardDeployment = async (run, reenqueuePayload, beforeStop) => {
|
|
942
|
+
const { outcome, spanAttributes } = await guardDeploymentAffinity({
|
|
943
|
+
world,
|
|
944
|
+
run,
|
|
945
|
+
requestId,
|
|
946
|
+
retryCount: deploymentMismatchRetryCount,
|
|
947
|
+
beforeStop,
|
|
948
|
+
isDeploymentUnavailableError: world.isDeploymentUnavailableError,
|
|
949
|
+
reenqueue: async ({ deploymentId, specVersion, deploymentMismatchRetryCount: retryCount, delaySeconds, }) => {
|
|
950
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
951
|
+
...(await reenqueuePayload()),
|
|
952
|
+
deploymentMismatchRetryCount: retryCount,
|
|
953
|
+
}, { deploymentId, specVersion, delaySeconds });
|
|
954
|
+
},
|
|
955
|
+
});
|
|
956
|
+
if (spanAttributes)
|
|
957
|
+
span?.setAttributes(spanAttributes);
|
|
958
|
+
return outcome;
|
|
959
|
+
};
|
|
960
|
+
// If incoming message has a stepId, this is a background step
|
|
961
|
+
// execution. Execute the step, then check if all parallel steps
|
|
962
|
+
// from the batch are done. If so, replay inline (saving a queue
|
|
963
|
+
// roundtrip). If not, return — the last handler to complete
|
|
964
|
+
// will pick up the replay.
|
|
965
|
+
if (incomingStepId && incomingStepName) {
|
|
966
|
+
try {
|
|
967
|
+
const bgRun = await world.runs.get(runId, {
|
|
968
|
+
resolveData: 'none',
|
|
969
|
+
});
|
|
970
|
+
if (bgRun.status !== 'running') {
|
|
971
|
+
runtimeLogger.debug('Run already finished, skipping background step', { workflowRunId: runId, status: bgRun.status });
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
// Covers every queued step execution — first dispatch and
|
|
975
|
+
// redeliveries/retries alike.
|
|
976
|
+
if ((await guardDeployment(bgRun, async () => ({
|
|
977
|
+
...(await replayMessage()),
|
|
978
|
+
stepId: incomingStepId,
|
|
979
|
+
stepName: incomingStepName,
|
|
980
|
+
}))) !== 'continue') {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
const bgStartedAt = bgRun.startedAt
|
|
984
|
+
? +bgRun.startedAt
|
|
985
|
+
: Date.now();
|
|
986
|
+
// Retry ceiling for a backgrounded step. `metadata.attempt`
|
|
987
|
+
// (the queue delivery count) is a cheap upper bound, but it
|
|
988
|
+
// over-counts: a ThrottleError / TooEarlyError — or any
|
|
989
|
+
// redelivery that never ran the body — still advances it, so
|
|
990
|
+
// trusting it directly could fail a step as "exceeded max
|
|
991
|
+
// retries" before the body ever ran (a user-visible
|
|
992
|
+
// regression under transient backend pressure). Use it only
|
|
993
|
+
// as a fast gate: while it is at or under the ceiling the
|
|
994
|
+
// step cannot be exhausted, so proceed without touching the
|
|
995
|
+
// log. Only once it crosses the ceiling do we load the full
|
|
996
|
+
// event log and derive the authoritative attempt from the
|
|
997
|
+
// recorded `step_started` count — scoped to the lifecycle
|
|
998
|
+
// attempt total (bare starts plus the largest single
|
|
999
|
+
// owner's starts): throttle/too-early redeliveries write
|
|
1000
|
+
// no start at all, racing invocations' one-off stamped
|
|
1001
|
+
// duplicates don't accumulate (counting them falsely
|
|
1002
|
+
// exhausted healthy steps — see countStepStartedEvents),
|
|
1003
|
+
// and attempts burned under a prior inline-ownership
|
|
1004
|
+
// phase still count, so a step that times out under
|
|
1005
|
+
// owned recovery and then transitions to queued/bare
|
|
1006
|
+
// retries trips the combined ceiling. This still bounds
|
|
1007
|
+
// timeouts, which write no error for the post-body guard
|
|
1008
|
+
// to catch.
|
|
1009
|
+
let bgAuthoritativeAttempt = metadata.attempt;
|
|
1010
|
+
const bgMaxRetries = getStepFunction(incomingStepName)?.maxRetries ??
|
|
1011
|
+
DEFAULT_STEP_MAX_RETRIES;
|
|
1012
|
+
if (metadata.attempt > bgMaxRetries + 1) {
|
|
1013
|
+
const loaded = await loadWorkflowRunEvents(runId);
|
|
1014
|
+
bgAuthoritativeAttempt =
|
|
1015
|
+
countStepStartedEvents(loaded.events, incomingStepId, { type: 'totalAttempts' }) + 1;
|
|
1016
|
+
}
|
|
1017
|
+
// Pause the replay budget while the step body runs —
|
|
1018
|
+
// step duration is bounded by the platform's function
|
|
1019
|
+
// maxDuration, not by the replay timeout. See the
|
|
1020
|
+
// ReplayBudget docs for the contract.
|
|
1021
|
+
replayBudget.pause();
|
|
1022
|
+
let stepResult;
|
|
1023
|
+
try {
|
|
1024
|
+
// Single-flight: a delayed backstop (or retry) message
|
|
1025
|
+
// can arrive while another execution of this same step
|
|
1026
|
+
// is mid-body in this process — most importantly on
|
|
1027
|
+
// worlds with no invocation kill bound (world-local),
|
|
1028
|
+
// where the ownership lease is not a death proof. The
|
|
1029
|
+
// loser awaits the winner's settlement, then acks
|
|
1030
|
+
// without executing. No ownerMessageId here: the bare
|
|
1031
|
+
// step_started of a queue-driven execution
|
|
1032
|
+
// intentionally clears inline ownership (the step is
|
|
1033
|
+
// queue-owned from this point).
|
|
1034
|
+
stepResult = await runStepSingleFlight(runId, incomingStepId, () => executeStep({
|
|
1035
|
+
world,
|
|
1036
|
+
workflowRunId: runId,
|
|
1037
|
+
workflowDeploymentId: bgRun.deploymentId,
|
|
1038
|
+
workflowName,
|
|
1039
|
+
workflowStartedAt: bgStartedAt,
|
|
1040
|
+
rootRunId: rootRunIdFrom(bgRun.attributes, runId),
|
|
1041
|
+
stepId: incomingStepId,
|
|
1042
|
+
stepName: incomingStepName,
|
|
1043
|
+
runSpecVersion: bgRun.specVersion,
|
|
1044
|
+
// Retry ceiling: the queue delivery count as a fast
|
|
1045
|
+
// gate, verified against the recorded step_started
|
|
1046
|
+
// count once it crosses the ceiling (see above).
|
|
1047
|
+
authoritativeAttempt: bgAuthoritativeAttempt,
|
|
1048
|
+
}));
|
|
1049
|
+
}
|
|
1050
|
+
finally {
|
|
1051
|
+
replayBudget.resume();
|
|
1052
|
+
}
|
|
1053
|
+
if (stepResult.type === 'retry') {
|
|
1054
|
+
return { timeoutSeconds: stepResult.timeoutSeconds };
|
|
1055
|
+
}
|
|
1056
|
+
if (stepResult.type === 'throttled') {
|
|
1057
|
+
return { timeoutSeconds: stepResult.timeoutSeconds };
|
|
1058
|
+
}
|
|
1059
|
+
// If step had pending ops (stream writes), break and let
|
|
1060
|
+
// waitUntil flush them — can't continue inline.
|
|
1061
|
+
if (stepResult.type === 'completed' &&
|
|
1062
|
+
stepResult.hasPendingOps) {
|
|
1063
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
1064
|
+
runId,
|
|
1065
|
+
traceCarrier: await nextTraceCarrier(),
|
|
1066
|
+
requestedAt: new Date(),
|
|
1067
|
+
});
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
if (stepResult.type === 'completed' ||
|
|
1071
|
+
stepResult.type === 'failed' ||
|
|
1072
|
+
stepResult.type === 'skipped') {
|
|
1073
|
+
// Load events to check if all parallel steps are done.
|
|
1074
|
+
// Use cursor-based loading so the main loop can continue
|
|
1075
|
+
// incrementally from here.
|
|
1076
|
+
const loaded = await loadWorkflowRunEvents(runId);
|
|
1077
|
+
eventLog = nextEventLogLoad(loaded);
|
|
1078
|
+
// Check for pending steps: any step_created without
|
|
1079
|
+
// a matching step_completed or step_failed.
|
|
1080
|
+
const stepCreatedIds = new Set();
|
|
1081
|
+
const stepTerminalIds = new Set();
|
|
1082
|
+
for (const e of loaded.events) {
|
|
1083
|
+
if (e.eventType === 'step_created') {
|
|
1084
|
+
stepCreatedIds.add(e.correlationId);
|
|
1085
|
+
}
|
|
1086
|
+
else if (e.eventType === 'step_completed' ||
|
|
1087
|
+
e.eventType === 'step_failed') {
|
|
1088
|
+
stepTerminalIds.add(e.correlationId);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
const pendingStepIds = new Set();
|
|
1092
|
+
for (const id of stepCreatedIds) {
|
|
1093
|
+
if (!stepTerminalIds.has(id)) {
|
|
1094
|
+
pendingStepIds.add(id);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
if (pendingStepIds.size > 0) {
|
|
1098
|
+
// A pending step that THIS message inline-owns (a
|
|
1099
|
+
// previous delivery of this message stamped its
|
|
1100
|
+
// step_started and then crashed mid-body) must be
|
|
1101
|
+
// recovered here: only the owning message may
|
|
1102
|
+
// re-execute it before the ownership lease expires,
|
|
1103
|
+
// and wake replays merely ensure a delayed
|
|
1104
|
+
// backstop. Fall through to the main loop, whose
|
|
1105
|
+
// dispatch table routes it to owned recovery.
|
|
1106
|
+
if (isInlineOwnershipEnabled() &&
|
|
1107
|
+
hasPendingStepOwnedByMessage(loaded.events, pendingStepIds, metadata.messageId)) {
|
|
1108
|
+
runtimeLogger.debug('Background step done; falling through to recover an inline step owned by this message', { workflowRunId: runId });
|
|
1109
|
+
}
|
|
1110
|
+
else {
|
|
1111
|
+
// Other steps still in progress. Return without
|
|
1112
|
+
// queuing — the last handler to complete will see
|
|
1113
|
+
// all steps done and replay inline.
|
|
1114
|
+
runtimeLogger.debug('Background step done but other steps pending, returning', { workflowRunId: runId });
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
// All steps done — fall through to the main replay loop.
|
|
1119
|
+
// Set up shared state so the loop can continue.
|
|
1120
|
+
runtimeLogger.debug('All parallel steps done, replaying inline after background step', { workflowRunId: runId });
|
|
1121
|
+
const runCreatedEvent = loaded.events.find((event) => event.eventType === 'run_created');
|
|
1122
|
+
let replayInput;
|
|
1123
|
+
if (runCreatedEvent) {
|
|
1124
|
+
replayInput = runCreatedEvent.eventData.input;
|
|
1125
|
+
}
|
|
1126
|
+
else {
|
|
1127
|
+
if (!isLegacySpecVersion(bgRun.specVersion)) {
|
|
1128
|
+
throw new WorkflowRuntimeError(`Workflow run "${runId}" has no "run_created" event`);
|
|
1129
|
+
}
|
|
1130
|
+
// Legacy runs predate the event-sourced run_created
|
|
1131
|
+
// invariant, so retain the resolved GET only for them.
|
|
1132
|
+
const legacyRun = await world.runs.get(runId, {
|
|
1133
|
+
resolveData: 'all',
|
|
1134
|
+
});
|
|
1135
|
+
if (legacyRun.status !== 'running') {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
replayInput = legacyRun.input;
|
|
1139
|
+
}
|
|
1140
|
+
workflowRun = {
|
|
1141
|
+
...bgRun,
|
|
1142
|
+
input: replayInput,
|
|
1143
|
+
status: 'running',
|
|
1144
|
+
output: undefined,
|
|
1145
|
+
error: undefined,
|
|
1146
|
+
completedAt: undefined,
|
|
1147
|
+
};
|
|
1148
|
+
workflowStartedAt = bgStartedAt;
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
catch (err) {
|
|
1155
|
+
const errorCode = getWorkflowSetupErrorCode(err);
|
|
1156
|
+
if (!errorCode) {
|
|
1157
|
+
throw err;
|
|
1158
|
+
}
|
|
1159
|
+
await recordFatalRunError({
|
|
1160
|
+
world,
|
|
1161
|
+
workflowRun,
|
|
1162
|
+
runId,
|
|
1163
|
+
requestId,
|
|
1164
|
+
err,
|
|
1165
|
+
errorCode,
|
|
1166
|
+
logMessage: 'Fatal error while preparing background workflow step',
|
|
1167
|
+
});
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
// Deployment-affinity pre-check for the lazy hook fast
|
|
1172
|
+
// path below. New lazy-resume messages carry the run's
|
|
1173
|
+
// pinned deployment (`hookInput.deploymentId`), so a
|
|
1174
|
+
// misrouted delivery is detectable with a cheap ambient
|
|
1175
|
+
// deployment-id comparison BEFORE the fast path's
|
|
1176
|
+
// hook_received write — the correctly-routed common case
|
|
1177
|
+
// pays no run fetch and no latency. Only a detected
|
|
1178
|
+
// mismatch fetches the authoritative run and hands it to
|
|
1179
|
+
// the existing guard (which owns re-route/fail policy);
|
|
1180
|
+
// the re-routed message keeps the complete `hookInput`,
|
|
1181
|
+
// since it may hold the only copy of the resume payload.
|
|
1182
|
+
// When the pinned or ambient id is unavailable (older
|
|
1183
|
+
// producer message, a world without deployment affinity,
|
|
1184
|
+
// or a getDeploymentId failure), behavior is unchanged:
|
|
1185
|
+
// the authoritative guard after run setup — which remains
|
|
1186
|
+
// the protection before replay and step execution — still
|
|
1187
|
+
// covers the delivery; the fast path's write is idempotent
|
|
1188
|
+
// per (runId, resumeId), so a pre-guard write from an
|
|
1189
|
+
// older message stays convergent.
|
|
1190
|
+
if (!workflowRun &&
|
|
1191
|
+
hookInput?.deploymentId !== undefined &&
|
|
1192
|
+
// Same eligibility as guardDeploymentAffinity: without
|
|
1193
|
+
// atomic, immutable deployments the ids legitimately
|
|
1194
|
+
// differ (e.g. dpl_local@<version>) and comparing them
|
|
1195
|
+
// would trigger spurious run fetches.
|
|
1196
|
+
world.capabilities?.deploymentAffinity === true) {
|
|
1197
|
+
const pinnedDeploymentId = hookInput.deploymentId;
|
|
1198
|
+
let currentDeploymentId;
|
|
1199
|
+
try {
|
|
1200
|
+
currentDeploymentId = await world.getDeploymentId();
|
|
1201
|
+
}
|
|
1202
|
+
catch {
|
|
1203
|
+
currentDeploymentId = undefined;
|
|
1204
|
+
}
|
|
1205
|
+
if (currentDeploymentId !== undefined &&
|
|
1206
|
+
currentDeploymentId !== pinnedDeploymentId) {
|
|
1207
|
+
const run = await world.runs.get(runId, {
|
|
1208
|
+
resolveData: 'none',
|
|
1209
|
+
});
|
|
1210
|
+
if ((await guardDeployment(run, async () => ({
|
|
1211
|
+
...(await replayMessage()),
|
|
1212
|
+
hookInput,
|
|
1213
|
+
}), awaitRunReady)) !== 'continue') {
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
// --- Lazy hook resume fast path ---
|
|
1219
|
+
// A lazy hook delivery (resumeId + digest on the queue
|
|
1220
|
+
// message) hoists the consumer's idempotent hook_received
|
|
1221
|
+
// re-ensure above run_started and asks the World to return
|
|
1222
|
+
// the current replay log with the write (preloadEvents). A
|
|
1223
|
+
// supporting World answers with the reconstructed run, the
|
|
1224
|
+
// complete replay log, and the run's event ceiling —
|
|
1225
|
+
// everything the generic setup below would spend a
|
|
1226
|
+
// run_started POST and an events.list on. Any other result
|
|
1227
|
+
// (older server, a World that ignores the param, or a
|
|
1228
|
+
// preload that fails validation, including a bounded
|
|
1229
|
+
// hasMore page) falls back to that generic setup; the
|
|
1230
|
+
// hook_received write itself has still succeeded either
|
|
1231
|
+
// way, so the re-ensure block below is skipped via
|
|
1232
|
+
// `hookEnsured`. Never taken on turbo (turbo deliveries
|
|
1233
|
+
// carry runInput, not hookInput) or after the background
|
|
1234
|
+
// step path already loaded the run.
|
|
1235
|
+
let hookEnsured = false;
|
|
1236
|
+
if (!workflowRun &&
|
|
1237
|
+
hookInput &&
|
|
1238
|
+
hookInput.resumeId !== undefined &&
|
|
1239
|
+
hookInput.payloadDigest !== undefined) {
|
|
1240
|
+
const hookResumeInput = hookInput;
|
|
1241
|
+
// Date the materialized event to when the resume actually
|
|
1242
|
+
// occurred — same derivation as the re-ensure below (the
|
|
1243
|
+
// resumeId is a ULID minted by resumeHook() at resume
|
|
1244
|
+
// time).
|
|
1245
|
+
let occurredAt;
|
|
1246
|
+
try {
|
|
1247
|
+
occurredAt = new Date(decodeTime(hookResumeInput.resumeId));
|
|
1248
|
+
}
|
|
1249
|
+
catch {
|
|
1250
|
+
occurredAt = undefined;
|
|
1251
|
+
}
|
|
1252
|
+
try {
|
|
1253
|
+
span?.addEvent('workflow.hook_received.create.start', {
|
|
1254
|
+
'workflow.hook_received.preload_events': true,
|
|
1255
|
+
});
|
|
1256
|
+
const result = await createEvent({
|
|
1257
|
+
eventType: 'hook_received',
|
|
1258
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
1259
|
+
correlationId: hookResumeInput.hookId,
|
|
1260
|
+
eventData: {
|
|
1261
|
+
token: hookResumeInput.token,
|
|
1262
|
+
payload: hookResumeInput.payload,
|
|
1263
|
+
},
|
|
1264
|
+
}, {
|
|
1265
|
+
requestId,
|
|
1266
|
+
occurredAt,
|
|
1267
|
+
resumeId: hookResumeInput.resumeId,
|
|
1268
|
+
resumePayloadDigest: hookResumeInput.payloadDigest,
|
|
1269
|
+
preloadEvents: true,
|
|
1270
|
+
});
|
|
1271
|
+
hookEnsured = true;
|
|
1272
|
+
// Note: unlike the re-ensure below, this hoisted write
|
|
1273
|
+
// does NOT set HookResilientResumeMaterialized — it
|
|
1274
|
+
// runs on every fast-path resume, including the common
|
|
1275
|
+
// case where the producer's direct write already landed
|
|
1276
|
+
// and this call merely converged on it, so it carries
|
|
1277
|
+
// no recovery signal. workflow.resume_setup_source
|
|
1278
|
+
// (below) describes this path instead.
|
|
1279
|
+
// The preload is usable as replay input only when it is
|
|
1280
|
+
// demonstrably the complete picture: a reconstructed
|
|
1281
|
+
// run with a start time, a non-empty COMPLETE log
|
|
1282
|
+
// (hasMore false — this path has no cursor-continuation
|
|
1283
|
+
// machinery, so a bounded page must not be trusted),
|
|
1284
|
+
// the server's event ceiling (this response plays
|
|
1285
|
+
// run_started's role, so a missing ceiling would leave
|
|
1286
|
+
// event-limit enforcement disabled for the run),
|
|
1287
|
+
// both run lifecycle events, the canonical event this
|
|
1288
|
+
// write converged on, and the hook_received matching
|
|
1289
|
+
// THIS resume (so we never replay against a log that is
|
|
1290
|
+
// missing the very event that triggered this delivery).
|
|
1291
|
+
const usableReplayPreload = result.run !== undefined &&
|
|
1292
|
+
result.run.startedAt !== undefined &&
|
|
1293
|
+
result.event !== undefined &&
|
|
1294
|
+
result.events !== undefined &&
|
|
1295
|
+
result.events.length > 0 &&
|
|
1296
|
+
result.cursor != null &&
|
|
1297
|
+
result.hasMore === false &&
|
|
1298
|
+
typeof result.maxEvents === 'number' &&
|
|
1299
|
+
result.events.some((e) => e.eventType === 'run_created') &&
|
|
1300
|
+
result.events.some((e) => e.eventType === 'run_started') &&
|
|
1301
|
+
result.events.some((e) => e.eventType === 'hook_received' &&
|
|
1302
|
+
e.resumeId === hookResumeInput.resumeId);
|
|
1303
|
+
if (usableReplayPreload &&
|
|
1304
|
+
result.run?.startedAt &&
|
|
1305
|
+
result.events) {
|
|
1306
|
+
// The reconstructed run always reads 'running', but a
|
|
1307
|
+
// terminal event committed concurrently rides in the
|
|
1308
|
+
// log itself. The node replay loop would catch it, but
|
|
1309
|
+
// QuickJS dispatches before that check — so consume
|
|
1310
|
+
// the delivery here, before any engine runs. Same
|
|
1311
|
+
// outcome as the run_started path's non-running
|
|
1312
|
+
// status check.
|
|
1313
|
+
const terminalEvent = result.events.find((e) => e.runId === runId &&
|
|
1314
|
+
(e.eventType === 'run_completed' ||
|
|
1315
|
+
e.eventType === 'run_failed' ||
|
|
1316
|
+
e.eventType === 'run_cancelled'));
|
|
1317
|
+
if (terminalEvent) {
|
|
1318
|
+
// The preload still initialized this delivery (it
|
|
1319
|
+
// is how the terminal state was observed), so the
|
|
1320
|
+
// setup-source and the run's actual terminal
|
|
1321
|
+
// status are recorded before consuming.
|
|
1322
|
+
span?.setAttributes({
|
|
1323
|
+
...Attribute.WorkflowRunStatus(terminalEvent.eventType === 'run_completed'
|
|
1324
|
+
? 'completed'
|
|
1325
|
+
: terminalEvent.eventType === 'run_failed'
|
|
1326
|
+
? 'failed'
|
|
1327
|
+
: 'cancelled'),
|
|
1328
|
+
...Attribute.HookResumeSetupSource('hook_received_stream'),
|
|
1329
|
+
});
|
|
1330
|
+
runtimeLogger.info('Run already finished during lazy hook setup, skipping', {
|
|
1331
|
+
workflowRunId: runId,
|
|
1332
|
+
eventType: terminalEvent.eventType,
|
|
1333
|
+
});
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
workflowRun = result.run;
|
|
1337
|
+
maxEventsLimit = clampMaxEvents(result.maxEvents);
|
|
1338
|
+
// Anchors RSFS — see the declaration above. This
|
|
1339
|
+
// response plays run_started's role on this path.
|
|
1340
|
+
runStartedReceivedAtMs = Date.now();
|
|
1341
|
+
eventLog = {
|
|
1342
|
+
type: 'ready',
|
|
1343
|
+
events: result.events,
|
|
1344
|
+
cursor: result.cursor,
|
|
1345
|
+
};
|
|
1346
|
+
workflowStartedAt = +result.run.startedAt;
|
|
1347
|
+
span?.setAttributes({
|
|
1348
|
+
...Attribute.WorkflowRunStatus(result.run.status),
|
|
1349
|
+
...Attribute.WorkflowStartedAt(workflowStartedAt),
|
|
1350
|
+
...Attribute.HookResumeSetupSource('hook_received_stream'),
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
else {
|
|
1354
|
+
// Successful write, no usable preload (CBOR response
|
|
1355
|
+
// from an older server, a World that ignored the
|
|
1356
|
+
// opt-in, a bounded hasMore page, or a preload that
|
|
1357
|
+
// failed validation): take the generic run_started
|
|
1358
|
+
// setup below. Its preload is loaded after this write
|
|
1359
|
+
// committed, so the canonical hook_received is part
|
|
1360
|
+
// of whatever log that setup reads — no splice
|
|
1361
|
+
// needed.
|
|
1362
|
+
span?.setAttributes(Attribute.HookResumeSetupSource('hook_received_fallback'));
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
catch (err) {
|
|
1366
|
+
// Same classification as the re-ensure below:
|
|
1367
|
+
// - HookNotFound / RunExpired: the run went terminal;
|
|
1368
|
+
// nothing left to resume, consume the message.
|
|
1369
|
+
// - anything else (EntityConflict, a truncated preload
|
|
1370
|
+
// stream, transport failures): transient — rethrow so
|
|
1371
|
+
// the queue redelivers and the idempotent
|
|
1372
|
+
// (runId, resumeId) claim converges on retry.
|
|
1373
|
+
if (HookNotFoundError.is(err) ||
|
|
1374
|
+
RunExpiredError.is(err)) {
|
|
1375
|
+
runtimeLogger.info('Run already finished during lazy hook setup, skipping', { workflowRunId: runId, message: err.message });
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
throw err;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
155
1381
|
// --- Infrastructure: prepare the run state ---
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
1382
|
+
// Skip if workflowRun was already set by the background
|
|
1383
|
+
// step path (inline replay after all parallel steps done)
|
|
1384
|
+
// or by the lazy hook fast path above.
|
|
1385
|
+
if (!workflowRun) {
|
|
1386
|
+
// Always call run_started directly — this both transitions
|
|
1387
|
+
// the run to 'running' AND returns the run entity, saving
|
|
1388
|
+
// a separate runs.get round-trip.
|
|
1389
|
+
// Contract: events.create('run_started') must be idempotent
|
|
1390
|
+
// for runs already in 'running' status (return the run
|
|
1391
|
+
// without error), not just for pending → running transitions.
|
|
1392
|
+
const runStartedEvent = {
|
|
167
1393
|
eventType: 'run_started',
|
|
168
1394
|
// Use the spec version from the original start() call
|
|
169
1395
|
// when available, so the resilient start path creates
|
|
@@ -180,208 +1406,1805 @@ export function workflowEntrypoint(workflowCode) {
|
|
|
180
1406
|
deploymentId: runInput.deploymentId,
|
|
181
1407
|
workflowName: runInput.workflowName,
|
|
182
1408
|
executionContext: runInput.executionContext,
|
|
1409
|
+
attributes: runInput.attributes,
|
|
1410
|
+
allowReservedAttributes: runInput.allowReservedAttributes,
|
|
183
1411
|
},
|
|
184
1412
|
}
|
|
185
1413
|
: {}),
|
|
186
|
-
}
|
|
187
|
-
if (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
1414
|
+
};
|
|
1415
|
+
if (turbo && runInput) {
|
|
1416
|
+
// Turbo: background `run_started` and synthesize the run
|
|
1417
|
+
// entity locally so replay can begin without waiting for
|
|
1418
|
+
// the round-trip. Safe here because this is the first
|
|
1419
|
+
// delivery of the first invocation — start() created the
|
|
1420
|
+
// run moments ago and no events have been written yet. The
|
|
1421
|
+
// barrier is consumed by every downstream write (suspension
|
|
1422
|
+
// handler, optimistic step_started, terminal run writes) so
|
|
1423
|
+
// nothing is written before the run exists.
|
|
1424
|
+
span?.addEvent('workflow.run_started.create.start', {
|
|
1425
|
+
'workflow.run_started.skip_preload': true,
|
|
1426
|
+
});
|
|
1427
|
+
const startedPromise = createEvent(runStartedEvent,
|
|
1428
|
+
// We background this purely as a write barrier and
|
|
1429
|
+
// never read its preloaded events, so skip the
|
|
1430
|
+
// run_started event-log preload. That trims the
|
|
1431
|
+
// run_started request the chained first step_started
|
|
1432
|
+
// waits on — shortening time-to-second-step — and the
|
|
1433
|
+
// wasted list+resolve it would otherwise compute.
|
|
1434
|
+
{ requestId, skipPreload: true });
|
|
1435
|
+
runReadyBarrier = startedPromise;
|
|
1436
|
+
// Turbo backgrounds run_started, so the non-turbo assignment
|
|
1437
|
+
// below never runs — thread the per-run event ceiling off the
|
|
1438
|
+
// backgrounded response here instead. The guard re-checks
|
|
1439
|
+
// maxEventsLimit every loop iteration, so a value that lands
|
|
1440
|
+
// shortly after start still enforces well before a runaway
|
|
1441
|
+
// log approaches the ceiling.
|
|
1442
|
+
void startedPromise
|
|
1443
|
+
.then((r) => {
|
|
1444
|
+
const limit = clampMaxEvents(r.maxEvents);
|
|
1445
|
+
if (limit !== undefined)
|
|
1446
|
+
maxEventsLimit = limit;
|
|
1447
|
+
})
|
|
1448
|
+
// Prevent an early failure from surfacing as an
|
|
1449
|
+
// unhandledRejection; runReadyBarrier still observes it.
|
|
1450
|
+
.catch(() => { });
|
|
1451
|
+
// Skip the initial events.list: nothing has been written to
|
|
1452
|
+
// the log yet on a first delivery (run_started is still in
|
|
1453
|
+
// flight). An empty preload routes iteration 1 through
|
|
1454
|
+
// the no-load preloaded branch; iteration 2 then takes the
|
|
1455
|
+
// existing post-preloaded full reload to pick up a cursor
|
|
1456
|
+
// without a spurious "cursor missing" warning.
|
|
1457
|
+
eventLog = {
|
|
1458
|
+
type: 'ready',
|
|
1459
|
+
events: [],
|
|
1460
|
+
cursor: null,
|
|
1461
|
+
};
|
|
1462
|
+
const now = new Date();
|
|
1463
|
+
workflowRun = {
|
|
1464
|
+
runId,
|
|
1465
|
+
status: 'running',
|
|
1466
|
+
deploymentId: runInput.deploymentId,
|
|
1467
|
+
workflowName: runInput.workflowName,
|
|
1468
|
+
specVersion: runInput.specVersion,
|
|
1469
|
+
executionContext: runInput.executionContext,
|
|
1470
|
+
input: runInput.input,
|
|
1471
|
+
// Seed attributes from start() ride along in `runInput`
|
|
1472
|
+
// (they live in `run_created`'s eventData, not separate
|
|
1473
|
+
// `attr_set` events), so the synthesized snapshot carries
|
|
1474
|
+
// them even though we skip the initial events.list. This
|
|
1475
|
+
// is correct ONLY while attributes are write-only:
|
|
1476
|
+
// there is no in-workflow read API today (see workflow.ts
|
|
1477
|
+
// "structural until a read API is introduced"), so the
|
|
1478
|
+
// empty preloaded log can't diverge on a read. If a read
|
|
1479
|
+
// API is ever added it MUST read from this snapshot, not
|
|
1480
|
+
// by replaying run_created/attr_set events — otherwise
|
|
1481
|
+
// turbo's empty initial log would surface seed attributes
|
|
1482
|
+
// as `{}` on the first delivery only.
|
|
1483
|
+
attributes: runInput.attributes ?? {},
|
|
1484
|
+
startedAt: now,
|
|
1485
|
+
createdAt: now,
|
|
1486
|
+
updatedAt: now,
|
|
1487
|
+
};
|
|
1488
|
+
workflowStartedAt = +now;
|
|
1489
|
+
// See the `runStartedReceivedAtMs` declaration above:
|
|
1490
|
+
// turbo synthesizes the run before the real
|
|
1491
|
+
// `run_started` response lands, so anchor RSFS here
|
|
1492
|
+
// rather than at an actual response instant.
|
|
1493
|
+
runStartedReceivedAtMs = +now;
|
|
1494
|
+
span?.setAttributes({
|
|
1495
|
+
...Attribute.WorkflowRunStatus('running'),
|
|
1496
|
+
...Attribute.WorkflowStartedAt(workflowStartedAt),
|
|
1497
|
+
});
|
|
198
1498
|
}
|
|
1499
|
+
else {
|
|
1500
|
+
try {
|
|
1501
|
+
span?.addEvent('workflow.run_started.create.start', {
|
|
1502
|
+
'workflow.run_started.skip_preload': false,
|
|
1503
|
+
});
|
|
1504
|
+
const result = await createEvent(runStartedEvent, {
|
|
1505
|
+
requestId,
|
|
1506
|
+
});
|
|
1507
|
+
workflowRun = result.run;
|
|
1508
|
+
maxEventsLimit = clampMaxEvents(result.maxEvents);
|
|
1509
|
+
// Anchors RSFS — see the declaration above.
|
|
1510
|
+
runStartedReceivedAtMs = Date.now();
|
|
1511
|
+
if (result.events?.length) {
|
|
1512
|
+
const loaded = {
|
|
1513
|
+
events: [...result.events],
|
|
1514
|
+
cursor: result.cursor ?? null,
|
|
1515
|
+
};
|
|
1516
|
+
eventLog = result.hasMore
|
|
1517
|
+
? nextEventLogLoad(loaded)
|
|
1518
|
+
: { ...loaded, type: 'ready' };
|
|
1519
|
+
}
|
|
1520
|
+
workflowStartedAt = +result.run.startedAt;
|
|
1521
|
+
span?.setAttributes({
|
|
1522
|
+
...Attribute.WorkflowRunStatus(result.run.status),
|
|
1523
|
+
...Attribute.WorkflowStartedAt(workflowStartedAt),
|
|
1524
|
+
});
|
|
1525
|
+
if (result.run.status !== 'running') {
|
|
1526
|
+
runtimeLogger.info('Workflow already completed or failed, skipping', {
|
|
1527
|
+
workflowRunId: runId,
|
|
1528
|
+
status: result.run.status,
|
|
1529
|
+
});
|
|
1530
|
+
// TODO: for `cancel`, we actually want to propagate a WorkflowCancelled event
|
|
1531
|
+
// inside the workflow context so the user can gracefully exit. this is SIGTERM
|
|
1532
|
+
// TODO: furthermore, there should be a timeout or a way to force cancel SIGKILL
|
|
1533
|
+
// so that we actually exit here without replaying the workflow at all, in the case
|
|
1534
|
+
// the replaying the workflow is itself failing.
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
catch (err) {
|
|
1539
|
+
// Run was concurrently completed/failed/cancelled
|
|
1540
|
+
if (EntityConflictError.is(err) ||
|
|
1541
|
+
RunExpiredError.is(err)) {
|
|
1542
|
+
// EntityConflictError: run was concurrently
|
|
1543
|
+
// completed/failed/cancelled during setup.
|
|
1544
|
+
// RunExpiredError: run already in terminal state.
|
|
1545
|
+
// In both cases, skip processing this message.
|
|
1546
|
+
runtimeLogger.info('Run already finished during setup, skipping', { workflowRunId: runId, message: err.message });
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
const errorCode = getWorkflowSetupErrorCode(err);
|
|
1551
|
+
if (!errorCode) {
|
|
1552
|
+
throw err;
|
|
1553
|
+
}
|
|
1554
|
+
await recordFatalRunError({
|
|
1555
|
+
world,
|
|
1556
|
+
workflowRun,
|
|
1557
|
+
runId,
|
|
1558
|
+
requestId,
|
|
1559
|
+
err,
|
|
1560
|
+
errorCode,
|
|
1561
|
+
logMessage: 'Fatal runtime error during workflow setup',
|
|
1562
|
+
});
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
} // end else (non-turbo run_started)
|
|
1567
|
+
} // end if (!workflowRun)
|
|
1568
|
+
assert(workflowRun, 'Workflow run must be loaded before replay');
|
|
1569
|
+
// Covers every flow replay — initial start, step completions,
|
|
1570
|
+
// hook resumptions, wait completions — and stops before any
|
|
1571
|
+
// workflow code or inline step executes when the run is not
|
|
1572
|
+
// pinned here (see `guardDeploymentAffinity`). This remains
|
|
1573
|
+
// the AUTHORITATIVE protection before replay and step
|
|
1574
|
+
// execution. `awaitRunReady` orders turbo's `run_started`
|
|
1575
|
+
// before either stopping action.
|
|
1576
|
+
//
|
|
1577
|
+
// Lazy hook resumes are additionally pre-checked above the
|
|
1578
|
+
// fast path: a new message's `hookInput.deploymentId` is
|
|
1579
|
+
// compared against the ambient deployment id for free, and
|
|
1580
|
+
// only a detected mismatch fetches the authoritative run —
|
|
1581
|
+
// so a misrouted modern resume re-routes with zero event
|
|
1582
|
+
// writes. Older messages (no `hookInput.deploymentId`) reach
|
|
1583
|
+
// the fast path's idempotent hook_received write before this
|
|
1584
|
+
// guard; that write converges per (runId, resumeId) on the
|
|
1585
|
+
// pinned deployment, so it is safe, just not free. Either
|
|
1586
|
+
// way the re-routed message must carry `hookInput`, or a
|
|
1587
|
+
// resume whose producer write had not yet landed would be
|
|
1588
|
+
// lost.
|
|
1589
|
+
if ((await guardDeployment(workflowRun, async () => ({
|
|
1590
|
+
...(await replayMessage()),
|
|
1591
|
+
...(hookInput ? { hookInput } : {}),
|
|
1592
|
+
}), awaitRunReady)) !== 'continue') {
|
|
1593
|
+
return;
|
|
199
1594
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
1595
|
+
// Lazy hook resume: the producer (resumeHook fast path)
|
|
1596
|
+
// parallelized the `hook_received` write with this queue
|
|
1597
|
+
// publish, so the event may not be persisted yet. Idempotently
|
|
1598
|
+
// ensure it before replay — keyed by `resumeId` so a
|
|
1599
|
+
// concurrent producer write converges on exactly one event
|
|
1600
|
+
// (the server resolves a matching claim as success, not an
|
|
1601
|
+
// error). `hookInput` never rides a turbo first-delivery
|
|
1602
|
+
// (that path carries `runInput`, not `hookInput`), so this
|
|
1603
|
+
// only runs on the normal load-and-replay path. Skipped
|
|
1604
|
+
// entirely when the fast path above already ensured the
|
|
1605
|
+
// event (`hookEnsured`) — successfully or via its fallback,
|
|
1606
|
+
// whose run_started preload was loaded after the write and
|
|
1607
|
+
// therefore already contains the canonical event.
|
|
1608
|
+
if (hookInput && !hookEnsured) {
|
|
1609
|
+
// Perf (Option A): if the producer's concurrent direct
|
|
1610
|
+
// write already landed in the run_started preload, the
|
|
1611
|
+
// canonical event is in the log and the re-ensure round trip
|
|
1612
|
+
// is pure overhead. Skip it when the preload already carries
|
|
1613
|
+
// a `hook_received` with this resume's persisted `resumeId`
|
|
1614
|
+
// (unique per resume, so we never skip on an unrelated
|
|
1615
|
+
// hook_received). Best-effort: the win lands only when the
|
|
1616
|
+
// producer's write beat this consumer's load; otherwise we
|
|
1617
|
+
// fall through to the idempotent re-ensure below.
|
|
1618
|
+
//
|
|
1619
|
+
// Intentionally unreachable for atomic lazy resumes
|
|
1620
|
+
// (resumeId + digest): those set `hookEnsured` in the
|
|
1621
|
+
// hoisted fast path above — on success AND on its
|
|
1622
|
+
// fallback — so this block (and the skip check) now only
|
|
1623
|
+
// serves hookInput shapes without the full idempotency
|
|
1624
|
+
// pair.
|
|
1625
|
+
const alreadyPreloaded = hookInput.resumeId !== undefined &&
|
|
1626
|
+
eventLog.type !== 'loadAll' &&
|
|
1627
|
+
eventLog.events.some((e) => e.eventType === 'hook_received' &&
|
|
1628
|
+
e.resumeId === hookInput.resumeId);
|
|
1629
|
+
if (alreadyPreloaded) {
|
|
1630
|
+
// Event already visible in the preloaded log — nothing to
|
|
1631
|
+
// ensure or splice.
|
|
210
1632
|
}
|
|
211
|
-
else
|
|
212
|
-
|
|
1633
|
+
else {
|
|
1634
|
+
// Date the materialized event to when the resume actually
|
|
1635
|
+
// occurred, not when this queue delivery ran. `resumeId`
|
|
1636
|
+
// is the ULID minted by `resumeHook()` at resume time, so
|
|
1637
|
+
// its embedded timestamp is the honest `occurredAt` and
|
|
1638
|
+
// keeps latency attribution off the queue round trip. A
|
|
1639
|
+
// non-ULID resumeId (legacy / test) simply leaves it
|
|
1640
|
+
// undefined, so the World falls back to `createdAt`.
|
|
1641
|
+
let occurredAt;
|
|
1642
|
+
try {
|
|
1643
|
+
occurredAt =
|
|
1644
|
+
hookInput.resumeId !== undefined
|
|
1645
|
+
? new Date(decodeTime(hookInput.resumeId))
|
|
1646
|
+
: undefined;
|
|
1647
|
+
}
|
|
1648
|
+
catch {
|
|
1649
|
+
occurredAt = undefined;
|
|
1650
|
+
}
|
|
1651
|
+
let ensuredEvent;
|
|
213
1652
|
try {
|
|
214
|
-
await world.events.create(runId, {
|
|
215
|
-
eventType: '
|
|
1653
|
+
const ensured = await world.events.create(runId, {
|
|
1654
|
+
eventType: 'hook_received',
|
|
216
1655
|
specVersion: SPEC_VERSION_CURRENT,
|
|
1656
|
+
correlationId: hookInput.hookId,
|
|
217
1657
|
eventData: {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
stack: err.stack,
|
|
221
|
-
},
|
|
222
|
-
errorCode: RUN_ERROR_CODES.RUNTIME_ERROR,
|
|
1658
|
+
token: hookInput.token,
|
|
1659
|
+
payload: hookInput.payload,
|
|
223
1660
|
},
|
|
224
|
-
}, {
|
|
1661
|
+
}, {
|
|
1662
|
+
requestId,
|
|
1663
|
+
occurredAt,
|
|
1664
|
+
resumeId: hookInput.resumeId,
|
|
1665
|
+
resumePayloadDigest: hookInput.payloadDigest,
|
|
1666
|
+
});
|
|
1667
|
+
// Consumer-side completion of the recovery path: this
|
|
1668
|
+
// replay materialized the event because the producer's
|
|
1669
|
+
// direct write had not landed in the preload.
|
|
1670
|
+
span?.setAttributes(Attribute.HookResilientResumeMaterialized(true));
|
|
1671
|
+
// The canonical event — whether this call committed it or
|
|
1672
|
+
// converged on the producer's concurrent write — so we can
|
|
1673
|
+
// splice it into the preloaded log instead of discarding
|
|
1674
|
+
// the preload (see below).
|
|
1675
|
+
//
|
|
1676
|
+
// Reconstruct `eventData` from `hookInput` rather than
|
|
1677
|
+
// trusting the POST response's payload: world-vercel posts
|
|
1678
|
+
// hook_received with `remoteRefBehavior: 'lazy'`, so the
|
|
1679
|
+
// returned event's payload is a RemoteRef *descriptor*, not
|
|
1680
|
+
// the serialized bytes replay needs. `hookInput` carries
|
|
1681
|
+
// the real token + payload bytes (they rode the queue
|
|
1682
|
+
// message), so splice those onto the returned event's
|
|
1683
|
+
// stable eventId/metadata.
|
|
1684
|
+
// The re-ensure always returns a `hook_received` event, so
|
|
1685
|
+
// the splice is safe. The cast is needed because spreading
|
|
1686
|
+
// the raw `Event` union and overriding `eventData` collapses
|
|
1687
|
+
// to a non-`hook_received` member (whose `eventData` is a
|
|
1688
|
+
// different shape); the object is a genuine `hook_received`
|
|
1689
|
+
// event by construction.
|
|
1690
|
+
const base = ensured.event;
|
|
1691
|
+
ensuredEvent = base
|
|
1692
|
+
? {
|
|
1693
|
+
...base,
|
|
1694
|
+
eventData: {
|
|
1695
|
+
token: hookInput.token,
|
|
1696
|
+
payload: hookInput.payload,
|
|
1697
|
+
},
|
|
1698
|
+
}
|
|
1699
|
+
: undefined;
|
|
225
1700
|
}
|
|
226
|
-
catch (
|
|
227
|
-
|
|
228
|
-
|
|
1701
|
+
catch (err) {
|
|
1702
|
+
// A matching concurrent claim (same resumeId + digest) is
|
|
1703
|
+
// resolved as success server-side and never throws, so
|
|
1704
|
+
// anything caught here is a genuine terminal or transient
|
|
1705
|
+
// condition:
|
|
1706
|
+
//
|
|
1707
|
+
// - HookNotFound / RunExpired: the producer's direct write
|
|
1708
|
+
// already ended this resume's eligibility (the run went
|
|
1709
|
+
// terminal). There is nothing left to resume, so consume
|
|
1710
|
+
// the message and stop. Continuing to replay would be
|
|
1711
|
+
// wasted work — and, worse, would ack a delivery that may
|
|
1712
|
+
// carry the only copy of the payload.
|
|
1713
|
+
if (HookNotFoundError.is(err) ||
|
|
1714
|
+
RunExpiredError.is(err)) {
|
|
229
1715
|
return;
|
|
230
1716
|
}
|
|
231
|
-
|
|
1717
|
+
// - EntityConflict (and any other unexpected error): the
|
|
1718
|
+
// resumeId constraint exists but the matching event is
|
|
1719
|
+
// not yet observable — the producer's parallel write is
|
|
1720
|
+
// still in flight, or a redrive raced the claim. This is
|
|
1721
|
+
// transient: rethrow so the queue redelivers and a later
|
|
1722
|
+
// attempt converges on the committed event instead of
|
|
1723
|
+
// replaying (and acking) without the payload.
|
|
1724
|
+
throw err;
|
|
232
1725
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
// TODO: for `cancel`, we actually want to propagate a WorkflowCancelled event
|
|
251
|
-
// inside the workflow context so the user can gracefully exit. this is SIGTERM
|
|
252
|
-
// TODO: furthermore, there should be a timeout or a way to force cancel SIGKILL
|
|
253
|
-
// so that we actually exit here without replaying the workflow at all, in the case
|
|
254
|
-
// the replaying the workflow is itself failing.
|
|
255
|
-
return;
|
|
1726
|
+
// The run_started response preloaded the log BEFORE this
|
|
1727
|
+
// ensure, so it cannot include the hook_received. Rather
|
|
1728
|
+
// than discard the preload (which would cost a fresh
|
|
1729
|
+
// events.list round trip on the first replay iteration),
|
|
1730
|
+
// splice in the canonical event reconstructed above. It
|
|
1731
|
+
// carries a stable eventId, so `insertEventByEventId` keeps
|
|
1732
|
+
// it in ascending eventId order and is idempotent if a later
|
|
1733
|
+
// list re-observes it. Only when the World returns no event
|
|
1734
|
+
// do we fall back to reloading the complete log.
|
|
1735
|
+
if (eventLog.type !== 'loadAll' && ensuredEvent) {
|
|
1736
|
+
insertEventByEventId(eventLog.events, ensuredEvent);
|
|
1737
|
+
}
|
|
1738
|
+
else {
|
|
1739
|
+
eventLog = { type: 'loadAll' };
|
|
1740
|
+
}
|
|
1741
|
+
} // end else (re-ensure needed)
|
|
256
1742
|
}
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
//
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
//
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
1743
|
+
// Resolve the encryption key for this run's deployment.
|
|
1744
|
+
// Used eagerly here since both workflow execution (input
|
|
1745
|
+
// hydration / hook payload decryption) and the run_failed
|
|
1746
|
+
// dehydrate path below need it. Memoized accessor: first
|
|
1747
|
+
// call triggers the actual fetch / HKDF derivation,
|
|
1748
|
+
// subsequent calls await the cached promise.
|
|
1749
|
+
const getEncryptionKey = memoizeEncryptionKey(world, workflowRun);
|
|
1750
|
+
const encryptionKey = await getEncryptionKey();
|
|
1751
|
+
// Invocation-scoped cache of VM-independent prepared payloads
|
|
1752
|
+
// and immutable final values. It survives the fresh workflow
|
|
1753
|
+
// VM created by each inline replay, but never crosses runs or
|
|
1754
|
+
// queue deliveries.
|
|
1755
|
+
const replayPayloadCache = new ReplayPayloadCache(encryptionKey);
|
|
1756
|
+
// The live VM parked at the previous boundary, when the
|
|
1757
|
+
// retention decision kept it. null → this iteration cold-
|
|
1758
|
+
// replays. Invocation-scoped: dies with this delivery.
|
|
1759
|
+
let retainedSession = null;
|
|
1760
|
+
// Main replay loop
|
|
1761
|
+
// biome-ignore lint/correctness/noConstantCondition: intentional loop
|
|
1762
|
+
while (true) {
|
|
1763
|
+
loopIteration++;
|
|
1764
|
+
// Replay-budget check: bail out (retry or fail) if
|
|
1765
|
+
// non-step time within this invocation has exceeded
|
|
1766
|
+
// the configured budget. Step bodies are excluded
|
|
1767
|
+
// because replayBudget.pause()/resume() bracket every
|
|
1768
|
+
// `executeStep` call.
|
|
1769
|
+
if (replayBudget.isExhausted()) {
|
|
1770
|
+
await handleReplayBudgetExhausted({
|
|
1771
|
+
runId,
|
|
1772
|
+
workflowName,
|
|
283
1773
|
requestId,
|
|
1774
|
+
attempt: metadata.attempt,
|
|
1775
|
+
limitMs: replayBudget.configuredLimitMs,
|
|
284
1776
|
});
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
catch (err) {
|
|
289
|
-
if (EntityConflictError.is(err)) {
|
|
290
|
-
runtimeLogger.info('Wait already completed, skipping', {
|
|
291
|
-
workflowRunId: runId,
|
|
292
|
-
correlationId: waitEvent.correlationId,
|
|
293
|
-
});
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
throw err;
|
|
1777
|
+
// Only the terminal attempt returns, after run_failed is
|
|
1778
|
+
// durable. Earlier attempts reject for queue redelivery.
|
|
1779
|
+
return;
|
|
297
1780
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// Only errors from runWorkflow() (user workflow code) should
|
|
306
|
-
// produce run_failed. Infrastructure errors (network, server)
|
|
307
|
-
// must propagate to the queue handler for automatic retry.
|
|
308
|
-
let workflowResult;
|
|
309
|
-
try {
|
|
310
|
-
workflowResult = await trace('workflow.replay', {}, async (replaySpan) => {
|
|
311
|
-
replaySpan?.setAttributes({
|
|
312
|
-
...Attribute.WorkflowEventsCount(events.length),
|
|
1781
|
+
// Check timeout before replay
|
|
1782
|
+
if (Date.now() - invocationStartTime >=
|
|
1783
|
+
noInlineReplayAfterMs) {
|
|
1784
|
+
runtimeLogger.info('V2 timeout reached, re-scheduling workflow', {
|
|
1785
|
+
workflowRunId: runId,
|
|
1786
|
+
loopIteration,
|
|
1787
|
+
elapsedMs: Date.now() - invocationStartTime,
|
|
313
1788
|
});
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// WorkflowSuspension is normal control flow — not an error
|
|
319
|
-
if (WorkflowSuspension.is(err)) {
|
|
320
|
-
const suspensionMessage = buildWorkflowSuspensionMessage(runId, err.stepCount, err.hookCount, err.waitCount);
|
|
321
|
-
if (suspensionMessage) {
|
|
322
|
-
runtimeLogger.debug(suspensionMessage);
|
|
323
|
-
}
|
|
324
|
-
const result = await handleSuspension({
|
|
325
|
-
suspension: err,
|
|
326
|
-
world,
|
|
327
|
-
run: workflowRun,
|
|
328
|
-
span,
|
|
329
|
-
requestId,
|
|
1789
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
1790
|
+
runId,
|
|
1791
|
+
traceCarrier: await nextTraceCarrier(),
|
|
1792
|
+
requestedAt: new Date(),
|
|
330
1793
|
});
|
|
331
|
-
if (result.timeoutSeconds !== undefined) {
|
|
332
|
-
return { timeoutSeconds: result.timeoutSeconds };
|
|
333
|
-
}
|
|
334
|
-
// Suspension handled, no further work needed
|
|
335
1794
|
return;
|
|
336
1795
|
}
|
|
337
|
-
|
|
338
|
-
// (e.g., corrupted event log). Fail the workflow run.
|
|
339
|
-
// Record exception for OTEL error tracking
|
|
340
|
-
if (err instanceof Error) {
|
|
341
|
-
span?.recordException?.(err);
|
|
342
|
-
}
|
|
343
|
-
const normalizedError = await normalizeUnknownError(err);
|
|
344
|
-
const errorName = normalizedError.name || getErrorName(err);
|
|
345
|
-
const errorMessage = normalizedError.message;
|
|
346
|
-
let errorStack = normalizedError.stack || getErrorStack(err);
|
|
347
|
-
// Remap error stack using source maps to show original source locations
|
|
348
|
-
if (errorStack) {
|
|
349
|
-
const parsedName = parseWorkflowName(workflowName);
|
|
350
|
-
const filename = parsedName?.moduleSpecifier || workflowName;
|
|
351
|
-
errorStack = remapErrorStack(errorStack, filename, workflowCode);
|
|
352
|
-
}
|
|
353
|
-
// Classify the error: WorkflowRuntimeError indicates an
|
|
354
|
-
// internal issue (corrupted event log, missing data);
|
|
355
|
-
// everything else is a user code error.
|
|
356
|
-
const errorCode = classifyRunError(err);
|
|
357
|
-
runtimeLogger.error('Error while running workflow', {
|
|
358
|
-
workflowRunId: runId,
|
|
359
|
-
errorCode,
|
|
360
|
-
errorName,
|
|
361
|
-
errorStack,
|
|
362
|
-
});
|
|
363
|
-
// Fail the workflow run via event (event-sourced architecture)
|
|
1796
|
+
let replayStart = 0;
|
|
364
1797
|
try {
|
|
365
|
-
|
|
366
|
-
|
|
1798
|
+
// --- QuickJS VM engine dispatch ---
|
|
1799
|
+
// The QuickJS engine (opt-in via WORKFLOW_VM=quickjs
|
|
1800
|
+
// or executionContext.workflowVm) is a self-contained
|
|
1801
|
+
// alternative to the node:vm inline-replay logic
|
|
1802
|
+
// below. It performs the same full event replay, but
|
|
1803
|
+
// runs the workflow code in a QuickJS WASM VM, queues
|
|
1804
|
+
// steps via the same combined route (so they hit
|
|
1805
|
+
// executeStep below on re-entry), and manages its own
|
|
1806
|
+
// run_completed / run_failed lifecycle for workflow
|
|
1807
|
+
// outcomes. When the QuickJS engine is in effect,
|
|
1808
|
+
// return immediately after dispatch.
|
|
1809
|
+
//
|
|
1810
|
+
// Deliberately INSIDE this try: engine failures that
|
|
1811
|
+
// escape the entrypoint (MaxEventsExceededError, a
|
|
1812
|
+
// WASM OOM at the memory ceiling, a bundle-eval
|
|
1813
|
+
// failure) must reach this loop's catch so they are
|
|
1814
|
+
// classified and recorded as run_failed — outside the
|
|
1815
|
+
// try they would nack the message and burn all queue
|
|
1816
|
+
// redeliveries before dying as
|
|
1817
|
+
// MAX_DELIVERIES_EXCEEDED. Transient world errors
|
|
1818
|
+
// still rethrow out of the catch for redelivery, same
|
|
1819
|
+
// as node-engine replay failures.
|
|
1820
|
+
if (useQuickJSVm(workflowRun)) {
|
|
1821
|
+
runtimeLogger.debug('Using QuickJS VM engine', {
|
|
1822
|
+
workflowRunId: runId,
|
|
1823
|
+
loopIteration,
|
|
1824
|
+
});
|
|
1825
|
+
// Under turbo, run_started is backgrounded. The
|
|
1826
|
+
// QuickJS entrypoint fetches the event log and
|
|
1827
|
+
// writes events directly, so wait for the run to be
|
|
1828
|
+
// durably started first — it does not thread the
|
|
1829
|
+
// turbo runReadyBarrier the way handleSuspension
|
|
1830
|
+
// does.
|
|
1831
|
+
await awaitRunReady();
|
|
1832
|
+
if (eventLog.type === 'loadAfter') {
|
|
1833
|
+
appendEventLog(eventLog, await loadWorkflowRunEvents(runId, eventLog.cursor));
|
|
1834
|
+
eventLog = { ...eventLog, type: 'ready' };
|
|
1835
|
+
}
|
|
1836
|
+
// Lazy import: the QuickJS entrypoint's import chain
|
|
1837
|
+
// embeds the base64 WASM binary + extensions
|
|
1838
|
+
// (~1.3 MB decoded at module scope). Loading it here
|
|
1839
|
+
// keeps that out of node-engine deployments entirely
|
|
1840
|
+
// — only the opt-in path pays, on first dispatch.
|
|
1841
|
+
const { runWorkflowWithQuickJS } = await import('./runtime/quickjs-entrypoint.js');
|
|
1842
|
+
const quickjsResult = await runWorkflowWithQuickJS({
|
|
1843
|
+
workflowCode,
|
|
1844
|
+
workflowName,
|
|
1845
|
+
workflowRun,
|
|
1846
|
+
preloadedEvents: eventLog.type === 'ready'
|
|
1847
|
+
? eventLog.events
|
|
1848
|
+
: undefined,
|
|
1849
|
+
preloadedEventsComplete: eventLog.type === 'ready',
|
|
1850
|
+
runInput,
|
|
1851
|
+
parentSpan: span,
|
|
1852
|
+
maxEventsLimit,
|
|
1853
|
+
namespace,
|
|
1854
|
+
nextTraceCarrier,
|
|
1855
|
+
// Inline-step ownership plumbing: redeliveries of
|
|
1856
|
+
// this message drive crash recovery for steps an
|
|
1857
|
+
// earlier invocation claimed inline (see the
|
|
1858
|
+
// backstop pass in the entrypoint's loop), and
|
|
1859
|
+
// the message id is stamped as `ownerMessageId`
|
|
1860
|
+
// on inline lazy step claims so wake replays
|
|
1861
|
+
// defer to the in-flight body instead of
|
|
1862
|
+
// requeueing the step.
|
|
1863
|
+
deliveryAttempt: metadata.attempt,
|
|
1864
|
+
ownerMessageId: metadata.messageId,
|
|
1865
|
+
});
|
|
1866
|
+
if (quickjsResult?.timeoutSeconds !== undefined) {
|
|
1867
|
+
// Use `reinvoke` rather than returning
|
|
1868
|
+
// `{ timeoutSeconds }` directly: under turbo the
|
|
1869
|
+
// current message carries `runInput` and a
|
|
1870
|
+
// reschedule would re-engage turbo on redelivery
|
|
1871
|
+
// (replaying against a stale preloaded log and
|
|
1872
|
+
// wedging the run — see the reinvoke() docs
|
|
1873
|
+
// above). reinvoke enqueues an explicit
|
|
1874
|
+
// continuation without `runInput` in that case.
|
|
1875
|
+
return await reinvoke(quickjsResult.timeoutSeconds);
|
|
1876
|
+
}
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (eventLog.type !== 'ready') {
|
|
1880
|
+
const page = await loadWorkflowRunEvents(runId, eventLog.type === 'loadAfter'
|
|
1881
|
+
? eventLog.cursor
|
|
1882
|
+
: undefined);
|
|
1883
|
+
if (eventLog.type === 'loadAfter') {
|
|
1884
|
+
appendEventLog(eventLog, page);
|
|
1885
|
+
eventLog = { ...eventLog, type: 'ready' };
|
|
1886
|
+
}
|
|
1887
|
+
else {
|
|
1888
|
+
eventLog = { ...page, type: 'ready' };
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
assert(eventLog.type === 'ready');
|
|
1892
|
+
reportPreconditionRestartReload(eventLog.events);
|
|
1893
|
+
// Detect concurrent completion via the event log: if
|
|
1894
|
+
// any other handler wrote a terminal run event, exit
|
|
1895
|
+
// before doing replay work. The run entity's status is
|
|
1896
|
+
// derived from these events, so checking the log here
|
|
1897
|
+
// gives us the same signal as a runs.get() round-trip
|
|
1898
|
+
// without the extra request per loop iteration.
|
|
1899
|
+
if (hasRecordedTerminalRunEvent(eventLog.events, runId)) {
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
// Complete elapsed waits
|
|
1903
|
+
const now = Date.now();
|
|
1904
|
+
const completedWaitIds = new Set(eventLog.events
|
|
1905
|
+
.filter((e) => e.eventType === 'wait_completed')
|
|
1906
|
+
.map((e) => e.correlationId));
|
|
1907
|
+
const waitsToComplete = eventLog.events
|
|
1908
|
+
.filter((e) => e.eventType === 'wait_created' &&
|
|
1909
|
+
e.correlationId !== undefined &&
|
|
1910
|
+
!completedWaitIds.has(e.correlationId) &&
|
|
1911
|
+
now >= e.eventData.resumeAt.getTime())
|
|
1912
|
+
.map((e) => ({
|
|
1913
|
+
eventType: 'wait_completed',
|
|
367
1914
|
specVersion: SPEC_VERSION_CURRENT,
|
|
1915
|
+
correlationId: e.correlationId,
|
|
368
1916
|
eventData: {
|
|
369
|
-
|
|
370
|
-
message: errorMessage,
|
|
371
|
-
stack: errorStack,
|
|
372
|
-
},
|
|
373
|
-
errorCode,
|
|
1917
|
+
resumeAt: e.eventData.resumeAt,
|
|
374
1918
|
},
|
|
375
|
-
}
|
|
1919
|
+
}));
|
|
1920
|
+
for (const waitEvent of waitsToComplete) {
|
|
1921
|
+
try {
|
|
1922
|
+
const created = await createEvent(waitEvent, {
|
|
1923
|
+
requestId,
|
|
1924
|
+
...preconditionSnapshotParams(eventLog.events, eventLog.cursor),
|
|
1925
|
+
});
|
|
1926
|
+
// Bump-and-report: fold what this write skipped over
|
|
1927
|
+
// into the snapshot the remaining waits are guarded
|
|
1928
|
+
// against, so each asks for a slot above it.
|
|
1929
|
+
//
|
|
1930
|
+
// Only a complete answer. `hasMore` means the World
|
|
1931
|
+
// returned part of what it was asked for, and the
|
|
1932
|
+
// missing-completion check below is what decides
|
|
1933
|
+
// whether this handler still has to fetch. Folding in
|
|
1934
|
+
// a partial page would make the log look like it
|
|
1935
|
+
// holds the completion when the rest of the page is
|
|
1936
|
+
// still unread, so the fetch would be skipped on a
|
|
1937
|
+
// snapshot that is short of the World's.
|
|
1938
|
+
if (created.events?.length &&
|
|
1939
|
+
created.hasMore !== true) {
|
|
1940
|
+
mergeReportedEvents(eventLog.events, created.events);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
catch (err) {
|
|
1944
|
+
if (EntityConflictError.is(err)) {
|
|
1945
|
+
runtimeLogger.info('Wait already completed, skipping', {
|
|
1946
|
+
workflowRunId: runId,
|
|
1947
|
+
correlationId: waitEvent.correlationId,
|
|
1948
|
+
});
|
|
1949
|
+
continue;
|
|
1950
|
+
}
|
|
1951
|
+
throw err;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
assert(eventLog.type === 'ready');
|
|
1955
|
+
// The event list above may be stale by the time an
|
|
1956
|
+
// elapsed wait is committed, and this replay has to see
|
|
1957
|
+
// its own wait_completed before it can advance past the
|
|
1958
|
+
// sleep. Each write asked the World for the delta since
|
|
1959
|
+
// our cursor and folded it in (see createEvent), so a
|
|
1960
|
+
// supporting World has already handed those events back
|
|
1961
|
+
// and there is nothing left to do. Only fetch for the
|
|
1962
|
+
// completions still missing locally: a World that
|
|
1963
|
+
// ignores `sinceCursor`, a truncated delta, a concurrent
|
|
1964
|
+
// absorb that lost the cursor race, or an
|
|
1965
|
+
// EntityConflictError, whose rejection carries no delta.
|
|
1966
|
+
const completedWaitIdsAfterWrites = new Set(eventLog.events
|
|
1967
|
+
.filter((e) => e.eventType === 'wait_completed')
|
|
1968
|
+
.map((e) => e.correlationId));
|
|
1969
|
+
const missingWaitCompletions = waitsToComplete.filter((waitEvent) => !completedWaitIdsAfterWrites.has(waitEvent.correlationId));
|
|
1970
|
+
if (missingWaitCompletions.length > 0) {
|
|
1971
|
+
// Load only events after the original snapshot cursor
|
|
1972
|
+
// so concurrent durable events, such as hook_received,
|
|
1973
|
+
// keep their ordering relative to wait_completed. Fall
|
|
1974
|
+
// back to a full reload for older worlds that cannot
|
|
1975
|
+
// give us a stable cursor, or if the cursor delta does
|
|
1976
|
+
// not include the wait completion this handler just
|
|
1977
|
+
// attempted.
|
|
1978
|
+
if (eventLog.cursor) {
|
|
1979
|
+
const page = await loadWorkflowRunEvents(runId, eventLog.cursor);
|
|
1980
|
+
const completedWaitIdsAfterCursor = new Set(page.events
|
|
1981
|
+
.filter((e) => e.eventType === 'wait_completed')
|
|
1982
|
+
.map((e) => e.correlationId));
|
|
1983
|
+
const sawAllWaitCompletions = missingWaitCompletions.every((waitEvent) => completedWaitIdsAfterCursor.has(waitEvent.correlationId));
|
|
1984
|
+
if (sawAllWaitCompletions) {
|
|
1985
|
+
appendEventLog(eventLog, page);
|
|
1986
|
+
}
|
|
1987
|
+
else {
|
|
1988
|
+
eventLog = {
|
|
1989
|
+
...(await loadWorkflowRunEvents(runId)),
|
|
1990
|
+
type: 'ready',
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
else {
|
|
1995
|
+
eventLog = {
|
|
1996
|
+
...(await loadWorkflowRunEvents(runId)),
|
|
1997
|
+
type: 'ready',
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
// A replay reads the log as the complete record of what
|
|
2002
|
+
// has happened, so a position nothing occupies is
|
|
2003
|
+
// indistinguishable from an event that never occurred and
|
|
2004
|
+
// the branch it would have decided gets decided the other
|
|
2005
|
+
// way. Failing here is the difference between a run that
|
|
2006
|
+
// reports its own corruption and one that silently
|
|
2007
|
+
// returns the wrong answer.
|
|
2008
|
+
//
|
|
2009
|
+
// A hole that is merely a write mid-commit fills in on
|
|
2010
|
+
// its own, so settleEventSlotGap re-reads before
|
|
2011
|
+
// concluding, and adopts whichever log it settled on.
|
|
2012
|
+
if (isSlotGapCheckEnabled()) {
|
|
2013
|
+
const settled = await settleEventSlotGap(runId, {
|
|
2014
|
+
events: eventLog.events,
|
|
2015
|
+
cursor: eventLog.cursor,
|
|
2016
|
+
});
|
|
2017
|
+
eventLog = { ...settled.log, type: 'ready' };
|
|
2018
|
+
if (settled.gap !== undefined) {
|
|
2019
|
+
throw new CorruptedEventLogError(`Event log for run ${runId} has a hole at slot ${settled.gap.firstMissingSlot}: ${settled.gap.missingCount} of the ${settled.gap.maxSlot} slots up to the log's maximum hold no event.`);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
// Completing elapsed waits refreshes the event snapshot.
|
|
2023
|
+
// A concurrent handler may have written the terminal run
|
|
2024
|
+
// event after the initial snapshot but before this
|
|
2025
|
+
// replay. Once the event log records that outcome, this
|
|
2026
|
+
// delivery is done.
|
|
2027
|
+
if (hasRecordedTerminalRunEvent(eventLog.events, runId)) {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
// Event-limit guard: fail a runaway run once its log
|
|
2031
|
+
// reaches the server-supplied ceiling (undefined ⇒ no
|
|
2032
|
+
// enforcement). The throw is caught below and written as
|
|
2033
|
+
// run_failed / MAX_EVENTS_EXCEEDED.
|
|
2034
|
+
if (maxEventsLimit !== undefined &&
|
|
2035
|
+
eventLog.events.length >= maxEventsLimit) {
|
|
2036
|
+
throw new MaxEventsExceededError(eventLog.events.length, maxEventsLimit);
|
|
2037
|
+
}
|
|
2038
|
+
// Latency telemetry: judge TTFS eligibility against the
|
|
2039
|
+
// invocation's first snapshot. Waits completed above
|
|
2040
|
+
// would already disqualify via the event-type check, so
|
|
2041
|
+
// evaluating after the wait pass is equivalent.
|
|
2042
|
+
// attr_set is permitted: a redelivery can land after a
|
|
2043
|
+
// committed pre-step attr_set, and the detour it marks
|
|
2044
|
+
// is subtracted via preStepAttrStartMs regardless of
|
|
2045
|
+
// which invocation wrote it (see runtime/step-latency.ts).
|
|
2046
|
+
invocationStartedClean ??= eventLog.events.every((e) => e.eventType === 'run_created' ||
|
|
2047
|
+
e.eventType === 'run_started' ||
|
|
2048
|
+
e.eventType === 'attr_set');
|
|
2049
|
+
runtimeLogger.debug('Starting workflow execution', {
|
|
2050
|
+
workflowRunId: runId,
|
|
2051
|
+
loopIteration,
|
|
2052
|
+
eventCount: eventLog.events.length,
|
|
2053
|
+
executionMode: retainedSession ? 'retained' : 'replay',
|
|
2054
|
+
});
|
|
2055
|
+
replayStart = Date.now();
|
|
2056
|
+
// Start every missing decrypt/decompress operation up
|
|
2057
|
+
// front (already-prepared payloads are skipped). Web
|
|
2058
|
+
// Crypto work overlaps VM setup on the replay path and
|
|
2059
|
+
// the appended events' consumption on the resume path;
|
|
2060
|
+
// consumers still deserialize and resolve in event order.
|
|
2061
|
+
const payloadPrewarm = replayPayloadCache.prewarm(workflowRun, eventLog.events);
|
|
2062
|
+
let workflowResult = retainedSession
|
|
2063
|
+
? await resumeWorkflow(retainedSession, eventLog.events)
|
|
2064
|
+
: { type: 'replay' };
|
|
2065
|
+
if (workflowResult.type === 'replay') {
|
|
2066
|
+
retainedSession = null;
|
|
2067
|
+
workflowResult = await replayWorkflow({
|
|
2068
|
+
workflowCode,
|
|
2069
|
+
workflowRun,
|
|
2070
|
+
events: eventLog.events,
|
|
2071
|
+
encryptionKey,
|
|
2072
|
+
replayPayloadCache,
|
|
2073
|
+
// Turbo: the end-of-run drain inside workflow
|
|
2074
|
+
// execution commits fire-and-forget `*_created`
|
|
2075
|
+
// events before the terminal `awaitRunReady()` below.
|
|
2076
|
+
runReadyBarrier,
|
|
2077
|
+
worldCapabilities: world.capabilities,
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
await payloadPrewarm;
|
|
2081
|
+
if (workflowResult.type === 'suspended') {
|
|
2082
|
+
// Park the live session; the suspension catch below
|
|
2083
|
+
// makes the one retention decision — keep it for the
|
|
2084
|
+
// next iteration or discard it for a fresh replay.
|
|
2085
|
+
retainedSession = workflowResult.session;
|
|
2086
|
+
throw workflowResult.suspension;
|
|
2087
|
+
}
|
|
2088
|
+
const result = workflowResult.output;
|
|
2089
|
+
runtimeLogger.debug('Workflow execution completed', {
|
|
2090
|
+
workflowRunId: runId,
|
|
2091
|
+
loopIteration,
|
|
2092
|
+
replayMs: Date.now() - replayStart,
|
|
2093
|
+
executionMode: retainedSession ? 'retained' : 'replay',
|
|
2094
|
+
});
|
|
2095
|
+
replayRecoveryReporter.activate();
|
|
2096
|
+
// Workflow completed. Send the snapshot but do NOT
|
|
2097
|
+
// reload-and-retry the create in place: `result` was
|
|
2098
|
+
// computed by this replay, so a stale (412) rejection must
|
|
2099
|
+
// force a *fresh replay* (which may observe the new event
|
|
2100
|
+
// and produce a different result), not re-commit the stale
|
|
2101
|
+
// result. The catch below restarts the replay in-process.
|
|
2102
|
+
try {
|
|
2103
|
+
// Turbo: a workflow that finishes with no steps reaches
|
|
2104
|
+
// here before the backgrounded run_started; order the
|
|
2105
|
+
// terminal write after it so the run exists.
|
|
2106
|
+
await awaitRunReady();
|
|
2107
|
+
await createEvent({
|
|
2108
|
+
eventType: 'run_completed',
|
|
2109
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
2110
|
+
eventData: { output: result },
|
|
2111
|
+
}, {
|
|
2112
|
+
requestId,
|
|
2113
|
+
...preconditionSnapshotParams(eventLog.events, eventLog.cursor),
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
catch (err) {
|
|
2117
|
+
if (EntityConflictError.is(err) ||
|
|
2118
|
+
RunExpiredError.is(err)) {
|
|
2119
|
+
runtimeLogger.info('Tried completing workflow run, but run has already finished.', { workflowRunId: runId, message: err.message });
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2122
|
+
throw err;
|
|
2123
|
+
}
|
|
2124
|
+
span?.setAttributes({
|
|
2125
|
+
...Attribute.WorkflowRunStatus('completed'),
|
|
2126
|
+
});
|
|
2127
|
+
return;
|
|
376
2128
|
}
|
|
377
|
-
catch (
|
|
378
|
-
if (
|
|
379
|
-
|
|
380
|
-
|
|
2129
|
+
catch (err) {
|
|
2130
|
+
if (WorkflowSuspension.is(err)) {
|
|
2131
|
+
replayRecoveryReporter.activate();
|
|
2132
|
+
// Synchronous workflow-execution duration for THIS
|
|
2133
|
+
// suspension only — anchors the `finalSchedulingReplay`
|
|
2134
|
+
// telemetry field below (see
|
|
2135
|
+
// StepLatencyTracking.replayMs). This is the FINAL
|
|
2136
|
+
// replay pass, the one that reached and scheduled the
|
|
2137
|
+
// first step: valid rsfs paths can replay more than
|
|
2138
|
+
// once before the first step (e.g. a workflow-body
|
|
2139
|
+
// `setAttributes()` detour replays twice), and a
|
|
2140
|
+
// redelivery omits earlier invocations' replay work
|
|
2141
|
+
// entirely. This value is NOT accumulated across
|
|
2142
|
+
// those earlier passes, so it must not be read as
|
|
2143
|
+
// "the replay portion of rsfs" — rsfs covers the
|
|
2144
|
+
// whole run_started-to-first-step window;
|
|
2145
|
+
// finalSchedulingReplay covers only this last pass.
|
|
2146
|
+
// Captured here, before `handleSuspension`'s awaited
|
|
2147
|
+
// I/O, so it excludes that I/O.
|
|
2148
|
+
//
|
|
2149
|
+
// This duplicates what OTEL already captures on the
|
|
2150
|
+
// run/invocation span, but is collected as client
|
|
2151
|
+
// telemetry so the server can emit it as an
|
|
2152
|
+
// UNSAMPLED, full-population metric: workflow-server's
|
|
2153
|
+
// server spans are heavily sampled in production
|
|
2154
|
+
// (~7%), and client spans can't be filtered by SDK
|
|
2155
|
+
// version, so neither can serve as the dashboard's
|
|
2156
|
+
// exact TTFS decomposition. On a retained-VM
|
|
2157
|
+
// resume this measures the resume (typically ~0ms),
|
|
2158
|
+
// not a replay, so the field's distribution is
|
|
2159
|
+
// bimodal once retention is active.
|
|
2160
|
+
const replayDurationMs = Date.now() - replayStart;
|
|
2161
|
+
runtimeLogger.debug('Workflow suspended', {
|
|
381
2162
|
workflowRunId: runId,
|
|
382
|
-
|
|
2163
|
+
loopIteration,
|
|
2164
|
+
replayMs: replayDurationMs,
|
|
2165
|
+
steps: err.stepCount,
|
|
2166
|
+
hooks: err.hookCount,
|
|
2167
|
+
waits: err.waitCount,
|
|
2168
|
+
});
|
|
2169
|
+
const suspensionMessage = buildWorkflowSuspensionMessage(err.stepCount, err.hookCount, err.waitCount);
|
|
2170
|
+
if (suspensionMessage) {
|
|
2171
|
+
runtimeLogger.debug(suspensionMessage);
|
|
2172
|
+
}
|
|
2173
|
+
// V2: handle suspension without queuing steps.
|
|
2174
|
+
// Each event creation inside handleSuspension carries the
|
|
2175
|
+
// precondition snapshot of the loaded event log, so a
|
|
2176
|
+
// backend holding an event this replay never saw rejects
|
|
2177
|
+
// the write (412) instead of accepting a divergent one.
|
|
2178
|
+
// The rejection is handled here, by restarting the
|
|
2179
|
+
// replay — never by re-posting the same event.
|
|
2180
|
+
const suspensionStart = Date.now();
|
|
2181
|
+
assert(eventLog.type === 'ready', 'Workflow suspended before its event log was loaded');
|
|
2182
|
+
let suspensionResult;
|
|
2183
|
+
try {
|
|
2184
|
+
suspensionResult = await handleSuspension({
|
|
2185
|
+
suspension: err,
|
|
2186
|
+
world,
|
|
2187
|
+
run: workflowRun,
|
|
2188
|
+
span,
|
|
2189
|
+
requestId,
|
|
2190
|
+
eventLog,
|
|
2191
|
+
runReadyBarrier,
|
|
2192
|
+
replayRecoveryReporter,
|
|
2193
|
+
});
|
|
2194
|
+
}
|
|
2195
|
+
catch (suspensionError) {
|
|
2196
|
+
// A suspension create was rejected as stale: re-derive
|
|
2197
|
+
// the replay from a corrected log in this invocation.
|
|
2198
|
+
// Once the in-process budget is spent, fall back to an
|
|
2199
|
+
// explicit immediate re-invocation (a rethrow relies
|
|
2200
|
+
// on redelivery of a message the turbo path already
|
|
2201
|
+
// acked — the run would stall for the queue's ~300s
|
|
2202
|
+
// default visibility timeout).
|
|
2203
|
+
if (PreconditionFailedError.is(suspensionError)) {
|
|
2204
|
+
if (restartReplayInProcess('suspension-create', suspensionError)) {
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
const escalation = await reinvokeAfterStaleRejection('suspension-create', suspensionError);
|
|
2208
|
+
if (escalation.reinvoked)
|
|
2209
|
+
return escalation.result;
|
|
2210
|
+
// Per-run budget spent: fail the run rather than
|
|
2211
|
+
// hand it back to the queue to spin again.
|
|
2212
|
+
throw escalation.error;
|
|
2213
|
+
}
|
|
2214
|
+
if (!FatalError.is(suspensionError)) {
|
|
2215
|
+
// Transient failures propagate to the queue
|
|
2216
|
+
// handler so the message is redelivered.
|
|
2217
|
+
throw suspensionError;
|
|
2218
|
+
}
|
|
2219
|
+
// Non-retryable failure while committing the
|
|
2220
|
+
// suspension's events — e.g. an attribute write
|
|
2221
|
+
// the World rejected as invalid (the cumulative
|
|
2222
|
+
// per-run cap can only be checked World-side).
|
|
2223
|
+
// Redelivery would replay the workflow into the
|
|
2224
|
+
// same write and the same rejection, so fail the
|
|
2225
|
+
// run with the error instead of wedging the
|
|
2226
|
+
// message in redelivery.
|
|
2227
|
+
const errorCode = classifyRunError(suspensionError);
|
|
2228
|
+
runtimeLogger.error('Non-retryable error while committing workflow suspension; failing run', {
|
|
2229
|
+
workflowRunId: runId,
|
|
2230
|
+
errorCode,
|
|
2231
|
+
errorName: suspensionError.name,
|
|
2232
|
+
errorMessage: suspensionError.message,
|
|
2233
|
+
});
|
|
2234
|
+
try {
|
|
2235
|
+
// Turbo: order the terminal write after the
|
|
2236
|
+
// backgrounded run_started so the run exists.
|
|
2237
|
+
await awaitRunReady();
|
|
2238
|
+
await createEvent({
|
|
2239
|
+
eventType: 'run_failed',
|
|
2240
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
2241
|
+
eventData: {
|
|
2242
|
+
error: await dehydrateRunError(suspensionError, runId, encryptionKey, globalThis, (workflowRun?.specVersion ?? 0) >=
|
|
2243
|
+
SPEC_VERSION_SUPPORTS_COMPRESSION),
|
|
2244
|
+
errorCode,
|
|
2245
|
+
},
|
|
2246
|
+
}, { requestId });
|
|
2247
|
+
}
|
|
2248
|
+
catch (failErr) {
|
|
2249
|
+
if (EntityConflictError.is(failErr) ||
|
|
2250
|
+
RunExpiredError.is(failErr)) {
|
|
2251
|
+
runtimeLogger.info('Tried failing workflow run, but run has already finished.', {
|
|
2252
|
+
workflowRunId: runId,
|
|
2253
|
+
message: failErr.message,
|
|
2254
|
+
});
|
|
2255
|
+
return;
|
|
2256
|
+
}
|
|
2257
|
+
throw failErr;
|
|
2258
|
+
}
|
|
2259
|
+
span?.setAttributes({
|
|
2260
|
+
...Attribute.WorkflowRunStatus('failed'),
|
|
2261
|
+
...Attribute.WorkflowErrorCode(errorCode),
|
|
2262
|
+
...Attribute.WorkflowErrorName(suspensionError.name),
|
|
2263
|
+
...Attribute.WorkflowErrorMessage(suspensionError.message),
|
|
2264
|
+
...Attribute.ErrorType(suspensionError.name),
|
|
2265
|
+
});
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
if (suspensionResult.reportedEventCount > 0) {
|
|
2269
|
+
// Bump-and-report merged events BELOW the tail and
|
|
2270
|
+
// re-sorted the array to slot order, shifting every
|
|
2271
|
+
// position the prewarm scan had already recorded.
|
|
2272
|
+
// The cursor is deliberately left alone: the report
|
|
2273
|
+
// is a lower bound on what was skipped, so the next
|
|
2274
|
+
// incremental read still has to cover the same range.
|
|
2275
|
+
replayPayloadCache.resetScan();
|
|
2276
|
+
}
|
|
2277
|
+
// Open hooks/waits in the log as loaded for this
|
|
2278
|
+
// replay. This suspension's own hook/wait writes are
|
|
2279
|
+
// NOT in it — they never reach retention anyway,
|
|
2280
|
+
// because a suspension containing a non-step item
|
|
2281
|
+
// fails canRetainWorkflowSession's type check before
|
|
2282
|
+
// the scan is consulted. Computed
|
|
2283
|
+
// lazily, at most once, and shared between the
|
|
2284
|
+
// retention decision here and the delta/turbo gates
|
|
2285
|
+
// below — the attr-detour and hook-conflict paths
|
|
2286
|
+
// return/continue before the gates and usually
|
|
2287
|
+
// short-circuit before ever scanning the log.
|
|
2288
|
+
const openHookWait = once(() => {
|
|
2289
|
+
assert(eventLog.type === 'ready');
|
|
2290
|
+
return openHookAndWaitState(eventLog.events);
|
|
383
2291
|
});
|
|
2292
|
+
// The single retention decision: keep the parked
|
|
2293
|
+
// session only across a pure step boundary with no
|
|
2294
|
+
// out-of-band continuation source and provably
|
|
2295
|
+
// passive step inputs.
|
|
2296
|
+
if (retainedSession &&
|
|
2297
|
+
!canRetainWorkflowSession(err, suspensionResult.retainedStepInputsSafe, openHookWait)) {
|
|
2298
|
+
retainedSession = null;
|
|
2299
|
+
}
|
|
2300
|
+
preStepBlockingMs += suspensionResult.hookCreationMs;
|
|
2301
|
+
if (suspensionResult.hasAttributeEvents &&
|
|
2302
|
+
preStepBlockingBeforeAttrMs === undefined) {
|
|
2303
|
+
preStepBlockingBeforeAttrMs = preStepBlockingMs;
|
|
2304
|
+
}
|
|
2305
|
+
runtimeLogger.debug('Suspension handled', {
|
|
2306
|
+
workflowRunId: runId,
|
|
2307
|
+
suspensionMs: Date.now() - suspensionStart,
|
|
2308
|
+
pendingSteps: suspensionResult.pendingSteps.length,
|
|
2309
|
+
timeoutSeconds: suspensionResult.waitTimeout?.seconds,
|
|
2310
|
+
hasHookConflict: suspensionResult.hasHookConflict,
|
|
2311
|
+
hasAwaitedHookCreation: suspensionResult.hasAwaitedHookCreation,
|
|
2312
|
+
hasAttributeEvents: suspensionResult.hasAttributeEvents,
|
|
2313
|
+
});
|
|
2314
|
+
// Hook conflict: break loop, re-invoke via queue
|
|
2315
|
+
if (suspensionResult.hasHookConflict) {
|
|
2316
|
+
return await reinvoke(0);
|
|
2317
|
+
}
|
|
2318
|
+
// Native workflow attribute events are resolved
|
|
2319
|
+
// through replay: the next loop iteration reloads the
|
|
2320
|
+
// log (now holding the just-committed attr_set) and
|
|
2321
|
+
// replays, resolving the setAttributes promise. Skip
|
|
2322
|
+
// step processing for this pass so that replay decides
|
|
2323
|
+
// races first — in Promise.race([setAttributes(),
|
|
2324
|
+
// step()]), the durable attribute event must be able
|
|
2325
|
+
// to win without executing the losing step. The replay
|
|
2326
|
+
// happens in-process rather than via a queue
|
|
2327
|
+
// re-invocation: unlike hooks and waits, an attr_set
|
|
2328
|
+
// introduces no out-of-band invocation source that the
|
|
2329
|
+
// handler would need to yield the message for, so
|
|
2330
|
+
// paying a delivery round-trip here would only add
|
|
2331
|
+
// latency before the workflow's next step.
|
|
2332
|
+
if (suspensionResult.hasAttributeEvents) {
|
|
2333
|
+
eventLog = nextEventLogLoad(eventLog);
|
|
2334
|
+
continue;
|
|
2335
|
+
}
|
|
2336
|
+
const pendingSteps = suspensionResult.pendingSteps;
|
|
2337
|
+
// Inline execution is gated on ownership. The
|
|
2338
|
+
// suspension handler deferred the step_created write for
|
|
2339
|
+
// up to `getMaxInlineSteps()` steps (`lazyInlineSteps`)
|
|
2340
|
+
// so we can run them inline — in parallel — via lazy
|
|
2341
|
+
// `step_started` events that create each step on the fly,
|
|
2342
|
+
// saving one world round-trip per inline step. Ownership
|
|
2343
|
+
// is still atomic and exactly-one per step: the world's
|
|
2344
|
+
// create-claim inside each step_started returns
|
|
2345
|
+
// `EntityConflictError` (→ executeStep `skipped`) to any
|
|
2346
|
+
// concurrent loser, so only one handler ever runs a given
|
|
2347
|
+
// body. Every other pending step keeps its eager
|
|
2348
|
+
// step_created (in `createdStepCorrelationIds`) and is
|
|
2349
|
+
// queued below.
|
|
2350
|
+
//
|
|
2351
|
+
// The suspension handler only designates
|
|
2352
|
+
// `lazyInlineSteps` when no `hook.getConflict()` awaiter
|
|
2353
|
+
// is present. That awaiter case must execute nothing
|
|
2354
|
+
// inline: an inline `await executeStep(...)` blocks this
|
|
2355
|
+
// handler for the full step duration, so the awaiter's
|
|
2356
|
+
// continuation (which only advances on the next replay)
|
|
2357
|
+
// would be serialized behind the step — defeating work
|
|
2358
|
+
// the workflow expressed as parallel (e.g.
|
|
2359
|
+
// `hook.getConflict().then(() => stepB())` racing `await
|
|
2360
|
+
// stepA()`). In that case `lazyInlineSteps` is empty and
|
|
2361
|
+
// every step is queued for re-invocation, which replays
|
|
2362
|
+
// over the just-committed hook_created and resolves the
|
|
2363
|
+
// awaiter while queued steps run in parallel invocations.
|
|
2364
|
+
const lazyInlineSteps = suspensionResult.lazyInlineSteps;
|
|
2365
|
+
const inlineCorrelationIds = new Set(lazyInlineSteps.map((s) => s.correlationId));
|
|
2366
|
+
// Unified queue dispatch for everything we are NOT
|
|
2367
|
+
// inline-executing. Steps are queued with stepId so
|
|
2368
|
+
// the receiver runs them; the wait timer is queued
|
|
2369
|
+
// as a generic continuation that fires after the
|
|
2370
|
+
// wait elapses and lets the next replay observe the
|
|
2371
|
+
// elapsed wait via the "complete elapsed waits"
|
|
2372
|
+
// pass.
|
|
2373
|
+
//
|
|
2374
|
+
// Step dispatch decision table (per pending step not
|
|
2375
|
+
// designated lazy-inline):
|
|
2376
|
+
//
|
|
2377
|
+
// - Inline-owned, owner === this message →
|
|
2378
|
+
// execute in THIS invocation (owned recovery: a
|
|
2379
|
+
// redelivery of the owning message re-executes
|
|
2380
|
+
// the step it crashed on, via a payload-less
|
|
2381
|
+
// step_started re-stamped with its
|
|
2382
|
+
// ownerMessageId — not a bare start).
|
|
2383
|
+
// - Inline-owned, owner !== this message →
|
|
2384
|
+
// ensure a DELAYED backstop wake exists
|
|
2385
|
+
// (delaySeconds = ownership lease remaining)
|
|
2386
|
+
// instead of enqueueing the step. The owning
|
|
2387
|
+
// invocation is (likely) still running the body;
|
|
2388
|
+
// an immediate step message would bare-start the
|
|
2389
|
+
// running step and execute it a second time
|
|
2390
|
+
// (workflow#2780). The backstop is a plain run
|
|
2391
|
+
// continuation, NOT a step message: when it
|
|
2392
|
+
// fires, this same decision table handles
|
|
2393
|
+
// whatever state the step is in by then
|
|
2394
|
+
// (terminal → nothing pending; queue-owned after
|
|
2395
|
+
// step_retrying → normal keyed dispatch; owner
|
|
2396
|
+
// dead with lease expired → immediate dispatch,
|
|
2397
|
+
// preserving step-level failure semantics for
|
|
2398
|
+
// poison steps; lease refreshed by owner
|
|
2399
|
+
// recovery → re-arm). The backstop's
|
|
2400
|
+
// idempotencyKey is scoped to the ownership
|
|
2401
|
+
// EPOCH (latest step_started timestamp), NOT
|
|
2402
|
+
// just the correlation ID, and must never be
|
|
2403
|
+
// the step message's own key — see
|
|
2404
|
+
// backstopIdempotencyKey for both invariants
|
|
2405
|
+
// (fixed keys either absorb the retry handoff
|
|
2406
|
+
// or dedupe the refreshed-lease re-arm against
|
|
2407
|
+
// the in-flight backstop itself).
|
|
2408
|
+
// - Not owned (never stamped / eager / ownership
|
|
2409
|
+
// lapsed at step_retrying / lease expired /
|
|
2410
|
+
// kill-switched) → immediate enqueue, exactly as
|
|
2411
|
+
// before. This covers crash recovery: if a prior
|
|
2412
|
+
// handler wrote step_created but crashed before
|
|
2413
|
+
// queueing, a later handler queues it;
|
|
2414
|
+
// idempotencyKey on correlationId dedupes
|
|
2415
|
+
// redundant queues across concurrent handlers.
|
|
2416
|
+
//
|
|
2417
|
+
// The wait continuation is what makes
|
|
2418
|
+
// `Promise.race(step, sleep)` behave correctly with
|
|
2419
|
+
// inline step execution: even if the inline step
|
|
2420
|
+
// blocks this handler for the full step duration,
|
|
2421
|
+
// the wait timer fires in a separate function
|
|
2422
|
+
// invocation. If the sleep wins, that parallel
|
|
2423
|
+
// invocation completes the run; if the step wins,
|
|
2424
|
+
// the wait continuation fires later and no-ops on
|
|
2425
|
+
// the terminal run.
|
|
2426
|
+
//
|
|
2427
|
+
// The continuation's delay is clamped to the
|
|
2428
|
+
// maximum queue delay (long waits chain across
|
|
2429
|
+
// multiple hops) and its idempotency key dedupes
|
|
2430
|
+
// re-observations of the same pending wait across
|
|
2431
|
+
// suspension passes — see
|
|
2432
|
+
// runtime/wait-continuation.ts for the full
|
|
2433
|
+
// delay/key selection rationale.
|
|
2434
|
+
const traceCarrier = await nextTraceCarrier();
|
|
2435
|
+
const dispatches = [];
|
|
2436
|
+
const inlineOwnership = isInlineOwnershipEnabled();
|
|
2437
|
+
const dispatchNowMs = Date.now();
|
|
2438
|
+
const ownedRecoverySteps = [];
|
|
2439
|
+
let backstopWakesArmed = 0;
|
|
2440
|
+
for (const step of pendingSteps) {
|
|
2441
|
+
if (inlineCorrelationIds.has(step.correlationId)) {
|
|
2442
|
+
continue;
|
|
2443
|
+
}
|
|
2444
|
+
const ownershipActive = inlineOwnership && isStepOwnershipActive(step);
|
|
2445
|
+
if (ownershipActive &&
|
|
2446
|
+
step.ownerMessageId === metadata.messageId) {
|
|
2447
|
+
// Owned recovery: this delivery IS the owning
|
|
2448
|
+
// message; re-execute the step in this
|
|
2449
|
+
// invocation instead of queueing it.
|
|
2450
|
+
ownedRecoverySteps.push(step);
|
|
2451
|
+
continue;
|
|
2452
|
+
}
|
|
2453
|
+
// Delayed backstop wake while another invocation's
|
|
2454
|
+
// ownership lease is live; immediate step enqueue
|
|
2455
|
+
// otherwise (lease expired ⇒ remaining 0 ⇒ same as
|
|
2456
|
+
// today, which is also the degraded mode for
|
|
2457
|
+
// worlds with unstable message IDs — the owner
|
|
2458
|
+
// check above never matches there).
|
|
2459
|
+
const backstopDelaySeconds = ownershipActive
|
|
2460
|
+
? stepLeaseRemainingSeconds(step, dispatchNowMs)
|
|
2461
|
+
: 0;
|
|
2462
|
+
if (backstopDelaySeconds > 0) {
|
|
2463
|
+
backstopWakesArmed++;
|
|
2464
|
+
runtimeLogger.debug('Pending step is inline-owned by a live invocation; ensuring delayed backstop wake instead of immediate requeue', {
|
|
2465
|
+
workflowRunId: runId,
|
|
2466
|
+
stepId: step.correlationId,
|
|
2467
|
+
ownerMessageId: step.ownerMessageId,
|
|
2468
|
+
backstopDelaySeconds,
|
|
2469
|
+
});
|
|
2470
|
+
dispatches.push(queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
2471
|
+
runId,
|
|
2472
|
+
traceCarrier,
|
|
2473
|
+
requestedAt: new Date(),
|
|
2474
|
+
}, {
|
|
2475
|
+
delaySeconds: backstopDelaySeconds,
|
|
2476
|
+
idempotencyKey: backstopIdempotencyKey(step),
|
|
2477
|
+
}));
|
|
2478
|
+
continue;
|
|
2479
|
+
}
|
|
2480
|
+
dispatches.push(queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
2481
|
+
runId,
|
|
2482
|
+
stepId: step.correlationId,
|
|
2483
|
+
stepName: step.stepName,
|
|
2484
|
+
traceCarrier,
|
|
2485
|
+
requestedAt: new Date(),
|
|
2486
|
+
}, {
|
|
2487
|
+
idempotencyKey: step.correlationId,
|
|
2488
|
+
}));
|
|
2489
|
+
}
|
|
2490
|
+
if (suspensionResult.waitTimeout) {
|
|
2491
|
+
dispatches.push(queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
2492
|
+
runId,
|
|
2493
|
+
traceCarrier,
|
|
2494
|
+
requestedAt: new Date(),
|
|
2495
|
+
}, getWaitContinuationDispatch(suspensionResult.waitTimeout.seconds, suspensionResult.waitTimeout.correlationId)));
|
|
2496
|
+
}
|
|
2497
|
+
await Promise.all(dispatches);
|
|
2498
|
+
// The set of steps THIS invocation executes: the
|
|
2499
|
+
// deferred lazy-inline batch plus any owned-recovery
|
|
2500
|
+
// steps (this message's redelivery re-executing a
|
|
2501
|
+
// step it crashed on — no lazyStepInput; the input
|
|
2502
|
+
// hydrates from the step entity like the background
|
|
2503
|
+
// path, and the payload-less step_started re-stamps
|
|
2504
|
+
// ownership — unlike the background path's start it
|
|
2505
|
+
// is NOT bare: it carries this message's
|
|
2506
|
+
// ownerMessageId, which is also what the
|
|
2507
|
+
// owned-recovery retry ceiling counts).
|
|
2508
|
+
const inlineExecutions = [
|
|
2509
|
+
...lazyInlineSteps.map((s) => ({
|
|
2510
|
+
correlationId: s.correlationId,
|
|
2511
|
+
stepName: s.stepName,
|
|
2512
|
+
lazyStepInput: s.dehydratedInput,
|
|
2513
|
+
})),
|
|
2514
|
+
...ownedRecoverySteps.map((s) => ({
|
|
2515
|
+
correlationId: s.correlationId,
|
|
2516
|
+
stepName: s.stepName,
|
|
2517
|
+
})),
|
|
2518
|
+
];
|
|
2519
|
+
// Ownership telemetry (design doc Phase 7): span
|
|
2520
|
+
// attributes so production traces show when crash
|
|
2521
|
+
// recovery ran or a wake was converted into a
|
|
2522
|
+
// backstop, and a warn (always printed, unlike
|
|
2523
|
+
// debug/info) for owned recovery — it means a prior
|
|
2524
|
+
// delivery of this message died mid-step-body.
|
|
2525
|
+
if (backstopWakesArmed > 0 ||
|
|
2526
|
+
ownedRecoverySteps.length > 0) {
|
|
2527
|
+
span?.setAttributes({
|
|
2528
|
+
...(ownedRecoverySteps.length > 0
|
|
2529
|
+
? Attribute.WorkflowOwnedRecoverySteps(ownedRecoverySteps.length)
|
|
2530
|
+
: {}),
|
|
2531
|
+
...(backstopWakesArmed > 0
|
|
2532
|
+
? Attribute.WorkflowBackstopWakesArmed(backstopWakesArmed)
|
|
2533
|
+
: {}),
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
if (ownedRecoverySteps.length > 0) {
|
|
2537
|
+
runtimeLogger.warn('Re-executing inline steps owned by this queue message — a previous delivery crashed mid-body and this redelivery is recovering them', {
|
|
2538
|
+
workflowRunId: runId,
|
|
2539
|
+
stepIds: ownedRecoverySteps.map((s) => s.correlationId),
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
// Nothing to execute inline — everything has been
|
|
2543
|
+
// queued (or no work needs scheduling). Exit and let
|
|
2544
|
+
// the queue drive subsequent replays.
|
|
2545
|
+
if (inlineExecutions.length === 0) {
|
|
2546
|
+
// A `hook.getConflict()` awaiter needs an immediate
|
|
2547
|
+
// re-invocation: the replay consumes the
|
|
2548
|
+
// just-committed hook_created and resolves the
|
|
2549
|
+
// awaiter. Without it (no inline step, all work
|
|
2550
|
+
// queued or none pending) the run would sit idle
|
|
2551
|
+
// until some unrelated message woke it.
|
|
2552
|
+
if (suspensionResult.hasAwaitedHookCreation) {
|
|
2553
|
+
return await reinvoke(0);
|
|
2554
|
+
}
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2557
|
+
// Open hooks/waits are consulted by all three gates
|
|
2558
|
+
// below; resolve the memoized scan once here.
|
|
2559
|
+
const openHookWaitState = openHookWait.value;
|
|
2560
|
+
// Inline-delta fast path gate. We request the delta —
|
|
2561
|
+
// and on the next iteration consume it in place of the
|
|
2562
|
+
// events.list — only when ALL hold:
|
|
2563
|
+
//
|
|
2564
|
+
// - We have a real prior cursor to diff against (a
|
|
2565
|
+
// World may return none on the initial load).
|
|
2566
|
+
// - This is the clean single-step sequential case:
|
|
2567
|
+
// this suspension produced exactly one step and no
|
|
2568
|
+
// waits (`err.{step,wait}Count`), that one step is
|
|
2569
|
+
// the lone pending step (`pendingSteps.length === 1`)
|
|
2570
|
+
// and the lone inline step
|
|
2571
|
+
// (`lazyInlineSteps.length === 1` — no parallel
|
|
2572
|
+
// siblings queued to background handlers, and no other
|
|
2573
|
+
// inline step writing its own events out of band).
|
|
2574
|
+
// - No pending wait timer from THIS suspension, and no
|
|
2575
|
+
// open wait in the cumulative log: a concurrent
|
|
2576
|
+
// `wait_completed` landing after the delta snapshot
|
|
2577
|
+
// does not bump the outside-event marker, so nothing
|
|
2578
|
+
// fences a replay from the stale delta.
|
|
2579
|
+
// - No open (or this-suspension-created) hook — UNLESS
|
|
2580
|
+
// the precondition guard is enabled AND the World
|
|
2581
|
+
// declares it actually enforces the guard
|
|
2582
|
+
// (`capabilities.preconditionGuard`; the env flag
|
|
2583
|
+
// alone only makes the runtime SEND snapshots, which
|
|
2584
|
+
// an unsupporting backend ignores — no fence). The
|
|
2585
|
+
// delta snapshots the log at the step_completed
|
|
2586
|
+
// write but is consumed on the next replay, so an
|
|
2587
|
+
// out-of-band `hook_received` landing in that window
|
|
2588
|
+
// is absent from the delta and observed one
|
|
2589
|
+
// iteration later than a real fetch would observe
|
|
2590
|
+
// it. That staleness is qualitatively the same
|
|
2591
|
+
// read-to-write race the fetch path already has (an
|
|
2592
|
+
// event can land right after `events.list` returns
|
|
2593
|
+
// and before the suspension's writes); with an
|
|
2594
|
+
// enforced guard it is also fenced: `hook_received`
|
|
2595
|
+
// bumps the per-run outside-event marker, so every
|
|
2596
|
+
// durable write the stale replay attempts is
|
|
2597
|
+
// rejected with 412 — its guarded suspension creates
|
|
2598
|
+
// (retried over the reloaded log, or exhausted into
|
|
2599
|
+
// a queue re-invocation), AND the lazy step_started
|
|
2600
|
+
// claim of its next inline step, which carries the
|
|
2601
|
+
// snapshot too (threaded below via
|
|
2602
|
+
// `stateUpdatedAt`; on rejection the batch is
|
|
2603
|
+
// abandoned and re-invoked for a fresh replay, so a
|
|
2604
|
+
// stale view can never commit a step). Hooks created
|
|
2605
|
+
// by THIS suspension are inside the delta (their
|
|
2606
|
+
// `hook_created` lands before the step-terminal
|
|
2607
|
+
// write), so only their `hook_received` responses
|
|
2608
|
+
// are subject to the same fenced window. Without an
|
|
2609
|
+
// enforced guard there is no fence, so keep the
|
|
2610
|
+
// conservative gate.
|
|
2611
|
+
// - With no hook or wait open at all, the only
|
|
2612
|
+
// out-of-band writer is cancellation, which is safe
|
|
2613
|
+
// to observe one iteration late. See
|
|
2614
|
+
// openHookAndWaitState.
|
|
2615
|
+
//
|
|
2616
|
+
// When more than one step runs inline, each writes its
|
|
2617
|
+
// own events and the per-write delta would be partial, so
|
|
2618
|
+
// the delta is not requested (the gate below is false for
|
|
2619
|
+
// multi-step) and the next iteration does a normal fetch.
|
|
2620
|
+
// Whether the precondition guard is actually in force:
|
|
2621
|
+
// enabled by env AND enforced by the World. The env
|
|
2622
|
+
// flag alone only makes the runtime send snapshots,
|
|
2623
|
+
// which an unsupporting backend ignores (no fence).
|
|
2624
|
+
const guardEnforced = isPreconditionGuardEnabled() &&
|
|
2625
|
+
world.capabilities?.preconditionGuard === true;
|
|
2626
|
+
const requestInlineDelta = typeof eventLog.cursor === 'string' &&
|
|
2627
|
+
err.stepCount === 1 &&
|
|
2628
|
+
err.waitCount === 0 &&
|
|
2629
|
+
pendingSteps.length === 1 &&
|
|
2630
|
+
lazyInlineSteps.length === 1 &&
|
|
2631
|
+
ownedRecoverySteps.length === 0 &&
|
|
2632
|
+
!suspensionResult.waitTimeout &&
|
|
2633
|
+
!openHookWaitState.openWait &&
|
|
2634
|
+
(guardEnforced ||
|
|
2635
|
+
(err.hookCount === 0 &&
|
|
2636
|
+
!openHookWaitState.openHook));
|
|
2637
|
+
// Stale-sensitive batch: a hook is open in the run (or
|
|
2638
|
+
// was created by this suspension, so its hook_received
|
|
2639
|
+
// can land any moment) — an out-of-band event can make
|
|
2640
|
+
// the view this batch was scheduled from stale. With
|
|
2641
|
+
// the guard in force, the fence rejects a stale
|
|
2642
|
+
// claim's durable writes — but it cannot un-run a step
|
|
2643
|
+
// BODY that optimistic start began before the claim
|
|
2644
|
+
// settled. Suppress optimistic start for these batches
|
|
2645
|
+
// (take await-then-run) so a 412-fenced step never
|
|
2646
|
+
// executes user code at all: the fence then covers
|
|
2647
|
+
// side effects, not just the event log. Costs one
|
|
2648
|
+
// claim round-trip per step while a hook is open, only
|
|
2649
|
+
// on guard-enforcing deployments. Without the guard
|
|
2650
|
+
// nothing 412s, so suppression would buy nothing —
|
|
2651
|
+
// stale-view exposure there is the pre-existing
|
|
2652
|
+
// optimistic-start contract (idempotent side effects).
|
|
2653
|
+
const suppressOptimisticStart = guardEnforced &&
|
|
2654
|
+
(openHookWaitState.openHook ||
|
|
2655
|
+
err.hookCount > 0 ||
|
|
2656
|
+
suspensionResult.hasHookEvents);
|
|
2657
|
+
// Turbo mode forces optimistic inline start for this
|
|
2658
|
+
// batch — but only while the run is still "clean" (a pure
|
|
2659
|
+
// step suspension). The moment a hook or wait is
|
|
2660
|
+
// created, later resume/parallel invocations become
|
|
2661
|
+
// possible, so the single-handler guarantee that makes
|
|
2662
|
+
// forced optimistic start safe no longer holds — turbo
|
|
2663
|
+
// exits and the steps take the normal (env-gated)
|
|
2664
|
+
// await-then-run path. The hook-conflict case already
|
|
2665
|
+
// returned early above, the attr case continued into a
|
|
2666
|
+
// fresh replay (so a batch-scheduling suspension never
|
|
2667
|
+
// carries attr events), and the awaited-hook case
|
|
2668
|
+
// emptied lazyInlineSteps; the checks below are
|
|
2669
|
+
// defensive.
|
|
2670
|
+
//
|
|
2671
|
+
// The `suspensionResult.*` flags only reflect what THIS
|
|
2672
|
+
// batch created, so they do not catch a hook/wait opened
|
|
2673
|
+
// in an earlier iteration of the same delivery (e.g. a
|
|
2674
|
+
// fire-and-forget `createHook(...)` that doesn't block the
|
|
2675
|
+
// workflow, letting the replay loop continue to later pure
|
|
2676
|
+
// step suspensions). Once any hook or wait is open in the
|
|
2677
|
+
// cumulative log, resume/parallel invocations are possible
|
|
2678
|
+
// for the rest of the run, so turbo must latch off
|
|
2679
|
+
// permanently — checked here via `openHookAndWaitState`
|
|
2680
|
+
// over the cumulative event log.
|
|
2681
|
+
//
|
|
2682
|
+
// NOTE: `WORKFLOW_SEQUENTIAL_REPLAYS=1` (per-run flow
|
|
2683
|
+
// topics consumed with `maxConcurrency: 1`) would in
|
|
2684
|
+
// principle waive this latch — serialized orchestrator
|
|
2685
|
+
// invocations restore the single-handler guarantee for
|
|
2686
|
+
// the whole delivery. The waiver is intentionally NOT
|
|
2687
|
+
// taken: the env var is a runtime-process setting that
|
|
2688
|
+
// cannot prove the BUILT flow trigger actually carries
|
|
2689
|
+
// `maxConcurrency: 1` (it must be set at build time
|
|
2690
|
+
// too, and some integrations write their own trigger
|
|
2691
|
+
// config), and `capabilities.maxConcurrency` only
|
|
2692
|
+
// declares queue support, not deployed configuration.
|
|
2693
|
+
// Until the build emits a verifiable signal that the
|
|
2694
|
+
// deployed trigger is serialized, the conservative
|
|
2695
|
+
// latch stays.
|
|
2696
|
+
const forceOptimisticStart = turbo &&
|
|
2697
|
+
!suspensionResult.hasAttributeEvents &&
|
|
2698
|
+
!suspensionResult.waitTimeout &&
|
|
2699
|
+
!suspensionResult.hasHookEvents &&
|
|
2700
|
+
!suspensionResult.hasAwaitedHookCreation &&
|
|
2701
|
+
!openHookWaitState.openHook &&
|
|
2702
|
+
!openHookWaitState.openWait;
|
|
2703
|
+
// Execute the inline steps in parallel. The replay
|
|
2704
|
+
// budget is paused for the whole batch — step duration is
|
|
2705
|
+
// bounded by the platform's function maxDuration, not the
|
|
2706
|
+
// replay timeout — so the budget check at the top of the
|
|
2707
|
+
// next loop iteration doesn't charge the step bodies.
|
|
2708
|
+
// Latency telemetry: decide whether this batch's first
|
|
2709
|
+
// step qualifies for TTFS/STSO measurement. Only the
|
|
2710
|
+
// batch's first step carries the tracking so a
|
|
2711
|
+
// parallel batch emits one sample per scheduling gap,
|
|
2712
|
+
// not one per sibling. Turbo's synthesized run
|
|
2713
|
+
// snapshot has a local-clock createdAt, so under
|
|
2714
|
+
// turbo only the run-id ULID timestamp is trusted.
|
|
2715
|
+
const latencyTracking = computeStepLatencyTracking({
|
|
2716
|
+
events: eventLog.events,
|
|
2717
|
+
invocationStartedClean: invocationStartedClean === true,
|
|
2718
|
+
runCreatedAtMs: runIdCreatedAt(runId) ??
|
|
2719
|
+
(turbo ? undefined : +workflowRun.createdAt),
|
|
2720
|
+
runStartedReceivedAtMs,
|
|
2721
|
+
replayMs: replayDurationMs,
|
|
2722
|
+
preStepBlockingMs,
|
|
2723
|
+
preStepBlockingBeforeAttrMs,
|
|
2724
|
+
// This suspension's own hook/wait writes are not in
|
|
2725
|
+
// the loaded event log yet, so report them explicitly.
|
|
2726
|
+
suspensionHasWaits: err.waitCount > 0 ||
|
|
2727
|
+
suspensionResult.waitTimeout !== undefined,
|
|
2728
|
+
suspensionCreatedHooks: err.hookCount > 0 || suspensionResult.hasHookEvents,
|
|
2729
|
+
turbo,
|
|
2730
|
+
});
|
|
2731
|
+
// Precondition-guard snapshot for the inline
|
|
2732
|
+
// step_started claims: the lazy claim is the first
|
|
2733
|
+
// durable write of a hot-path step (its step_created
|
|
2734
|
+
// is deferred), so without a snapshot it would bypass
|
|
2735
|
+
// the guard entirely and a stale replay could claim —
|
|
2736
|
+
// and commit — a step scheduled off a view that misses
|
|
2737
|
+
// an event it never loaded.
|
|
2738
|
+
// `preconditionSnapshotParams` returns an empty object
|
|
2739
|
+
// when the guard env flag is off, so this is a no-op
|
|
2740
|
+
// outside guarded deployments; Worlds that don't
|
|
2741
|
+
// enforce the guard ignore it.
|
|
2742
|
+
const inlineClaimSnapshot = preconditionSnapshotParams(eventLog.events, eventLog.cursor);
|
|
2743
|
+
replayBudget.pause();
|
|
2744
|
+
let stepResults;
|
|
2745
|
+
const stepExecutionPromises = inlineExecutions.map((s, stepIndex) => {
|
|
2746
|
+
const run = () => {
|
|
2747
|
+
assert(eventLog.type === 'ready');
|
|
2748
|
+
return executeStep({
|
|
2749
|
+
world,
|
|
2750
|
+
workflowRunId: runId,
|
|
2751
|
+
workflowDeploymentId: workflowRun.deploymentId,
|
|
2752
|
+
workflowName,
|
|
2753
|
+
workflowStartedAt,
|
|
2754
|
+
rootRunId: rootRunIdFrom(workflowRun.attributes, runId),
|
|
2755
|
+
stepId: s.correlationId,
|
|
2756
|
+
stepName: s.stepName,
|
|
2757
|
+
runSpecVersion: workflowRun.specVersion,
|
|
2758
|
+
// Attempt number = prior step_started count + 1
|
|
2759
|
+
// (this execution's start), counting only THIS
|
|
2760
|
+
// message's own starts: the owned-recovery
|
|
2761
|
+
// ceiling bounds how many times this owning
|
|
2762
|
+
// message re-runs a step it crashed/timed out
|
|
2763
|
+
// on, and each of those (re)starts stamps
|
|
2764
|
+
// metadata.messageId. Starts written by racing
|
|
2765
|
+
// invocations (stale/wake replays, a step
|
|
2766
|
+
// message dispatched off a lost create-claim)
|
|
2767
|
+
// carry other IDs — or none — and must not
|
|
2768
|
+
// count, or the ceiling falsely exhausts a
|
|
2769
|
+
// healthy step (see countStepStartedEvents).
|
|
2770
|
+
// A lazy step is brand-new by construction (it
|
|
2771
|
+
// enters the batch only when it has no
|
|
2772
|
+
// step_created yet), so it has zero prior
|
|
2773
|
+
// starts and is always attempt 1 — skip the
|
|
2774
|
+
// log scan entirely. Only an owned-recovery
|
|
2775
|
+
// re-run can have prior starts, and that path
|
|
2776
|
+
// is uncommon, so reserve the O(n) scan for it
|
|
2777
|
+
// rather than walking the growing log for
|
|
2778
|
+
// every inline step (which would be O(n²)
|
|
2779
|
+
// across a long sequential workflow).
|
|
2780
|
+
authoritativeAttempt: s.lazyStepInput !== undefined
|
|
2781
|
+
? 1
|
|
2782
|
+
: countStepStartedEvents(eventLog.events, s.correlationId, {
|
|
2783
|
+
type: 'ownedBy',
|
|
2784
|
+
messageId: metadata.messageId,
|
|
2785
|
+
}) + 1,
|
|
2786
|
+
// Lazy inline start: send the deferred step's
|
|
2787
|
+
// input on step_started so the world creates
|
|
2788
|
+
// the step on the fly. Absent for
|
|
2789
|
+
// owned-recovery steps, whose input hydrates
|
|
2790
|
+
// from the existing step entity.
|
|
2791
|
+
lazyStepInput: s.lazyStepInput,
|
|
2792
|
+
// Inline ownership: stamp (or re-stamp) this
|
|
2793
|
+
// invocation's queue message ID on the
|
|
2794
|
+
// step_started, so wake replays see the body
|
|
2795
|
+
// as in flight here and suppress the
|
|
2796
|
+
// immediate requeue (workflow#2780).
|
|
2797
|
+
ownerMessageId: metadata.messageId,
|
|
2798
|
+
// Turbo: force optimistic start and hold the
|
|
2799
|
+
// lazy step_started until the backgrounded
|
|
2800
|
+
// run_started lands (the body still runs
|
|
2801
|
+
// immediately). Both are undefined/false
|
|
2802
|
+
// outside turbo.
|
|
2803
|
+
forceOptimisticStart,
|
|
2804
|
+
// Guard-enforced batches with an open hook
|
|
2805
|
+
// await the claim before running the body, so
|
|
2806
|
+
// a 412-fenced step never executes user code —
|
|
2807
|
+
// see suppressOptimisticStart above.
|
|
2808
|
+
suppressOptimisticStart,
|
|
2809
|
+
runReadyBarrier,
|
|
2810
|
+
preconditionSnapshot: inlineClaimSnapshot,
|
|
2811
|
+
...(stepIndex === 0 &&
|
|
2812
|
+
s.lazyStepInput !== undefined &&
|
|
2813
|
+
latencyTracking
|
|
2814
|
+
? { latencyTracking }
|
|
2815
|
+
: {}),
|
|
2816
|
+
...(requestInlineDelta && eventLog.cursor
|
|
2817
|
+
? {
|
|
2818
|
+
inlineDeltaSinceCursor: eventLog.cursor,
|
|
2819
|
+
}
|
|
2820
|
+
: {}),
|
|
2821
|
+
replayRecoveryReporter,
|
|
2822
|
+
});
|
|
2823
|
+
};
|
|
2824
|
+
// Invariant bookkeeping: this invocation owns
|
|
2825
|
+
// these bodies until they settle — see
|
|
2826
|
+
// assertNoInFlightOwnedSteps.
|
|
2827
|
+
inFlightOwnedSteps.add(s.correlationId);
|
|
2828
|
+
// Lazy steps are brand-new (their create-claim
|
|
2829
|
+
// is the exactly-once gate), but an
|
|
2830
|
+
// owned-recovery step already exists and its
|
|
2831
|
+
// delayed backstop message may fire mid-body
|
|
2832
|
+
// in this same process — route those through
|
|
2833
|
+
// the in-process single-flight.
|
|
2834
|
+
const executed = s.lazyStepInput === undefined
|
|
2835
|
+
? runStepSingleFlight(runId, s.correlationId, run)
|
|
2836
|
+
: run();
|
|
2837
|
+
return executed.finally(() => inFlightOwnedSteps.delete(s.correlationId));
|
|
2838
|
+
});
|
|
2839
|
+
try {
|
|
2840
|
+
stepResults = await Promise.all(stepExecutionPromises);
|
|
2841
|
+
}
|
|
2842
|
+
catch (stepErr) {
|
|
2843
|
+
// A stale (412) rejection of an inline step_started
|
|
2844
|
+
// claim: the loaded view this batch was scheduled
|
|
2845
|
+
// from is missing an event the backend already has,
|
|
2846
|
+
// so the claim was fenced by the guard and no step
|
|
2847
|
+
// events were written. Abandon the batch — any
|
|
2848
|
+
// optimistic body result is discarded by executeStep's
|
|
2849
|
+
// reconciliation — and restart the replay so it
|
|
2850
|
+
// observes the missing event. Wait for the sibling
|
|
2851
|
+
// executions to settle first so no owned body is in
|
|
2852
|
+
// flight when the restart (or the ack path) runs.
|
|
2853
|
+
if (PreconditionFailedError.is(stepErr)) {
|
|
2854
|
+
const settled = await Promise.allSettled(stepExecutionPromises);
|
|
2855
|
+
// A sibling whose claim was accepted wrote step
|
|
2856
|
+
// events of its own, possibly after the World built
|
|
2857
|
+
// this 412's delta — so that delta can no longer be
|
|
2858
|
+
// assumed to complete the log, and the restart has
|
|
2859
|
+
// to reload it in full. `skipped` (the step already
|
|
2860
|
+
// existed), `gone` and `throttled` (claim rejected)
|
|
2861
|
+
// wrote nothing.
|
|
2862
|
+
const siblingWrote = settled.some((outcome) => outcome.status === 'fulfilled' &&
|
|
2863
|
+
(outcome.value.type === 'completed' ||
|
|
2864
|
+
outcome.value.type === 'failed' ||
|
|
2865
|
+
outcome.value.type === 'retry'));
|
|
2866
|
+
if (restartReplayInProcess('inline-claim', stepErr, {
|
|
2867
|
+
allowDelta: !siblingWrote,
|
|
2868
|
+
})) {
|
|
2869
|
+
// The finally below resumes the replay budget
|
|
2870
|
+
// before the next iteration starts.
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
// The finally below resumes the replay budget
|
|
2874
|
+
// before this return (or throw) completes.
|
|
2875
|
+
const escalation = await reinvokeAfterStaleRejection('inline-claim', stepErr);
|
|
2876
|
+
if (escalation.reinvoked)
|
|
2877
|
+
return escalation.result;
|
|
2878
|
+
throw escalation.error;
|
|
2879
|
+
}
|
|
2880
|
+
throw stepErr;
|
|
2881
|
+
}
|
|
2882
|
+
finally {
|
|
2883
|
+
replayBudget.resume();
|
|
2884
|
+
}
|
|
2885
|
+
// Aggregate the batch results. `retry` steps (which
|
|
2886
|
+
// already exist — their `step_started` succeeded) are
|
|
2887
|
+
// re-queued per-step as background steps with their own
|
|
2888
|
+
// delay; `throttled` steps (rejected on the create-claim,
|
|
2889
|
+
// so never created) instead defer redelivery of this
|
|
2890
|
+
// orchestrator message so they re-run inline with input
|
|
2891
|
+
// on replay; completed/failed steps already wrote their
|
|
2892
|
+
// terminal events. We only loop back to replay when every
|
|
2893
|
+
// inline step reached a terminal state — otherwise the
|
|
2894
|
+
// still-pending steps will be re-run by their queued retry
|
|
2895
|
+
// messages and the background-step path replays once
|
|
2896
|
+
// all steps are done.
|
|
2897
|
+
const toRetry = [];
|
|
2898
|
+
let anyPendingOps = false;
|
|
2899
|
+
// A throttled inline step delays redelivery of THIS
|
|
2900
|
+
// orchestrator message rather than being re-queued as a
|
|
2901
|
+
// background step. Crucially, a `throttled` result means
|
|
2902
|
+
// the lazy `step_started` was rejected on the atomic
|
|
2903
|
+
// create-claim — so the step was NEVER created (no
|
|
2904
|
+
// `step_created`, no step entity). Re-queuing it as a
|
|
2905
|
+
// background step would send a bare `step_started` (no
|
|
2906
|
+
// input), which the world rejects with `Step "<id>" not
|
|
2907
|
+
// found` because it cannot lazily create the step without
|
|
2908
|
+
// its input; that error isn't translatable, so the
|
|
2909
|
+
// message redelivers until MAX_QUEUE_DELIVERIES and the
|
|
2910
|
+
// step (and run) fail. Deferring redelivery of the
|
|
2911
|
+
// orchestrator instead re-attempts the throttled step
|
|
2912
|
+
// inline WITH its input on replay. We track the longest
|
|
2913
|
+
// backoff so a batch with multiple throttles waits the
|
|
2914
|
+
// max. Note: `retry` results are safe to re-queue as
|
|
2915
|
+
// background steps because a retry implies `step_started`
|
|
2916
|
+
// already succeeded and the step exists.
|
|
2917
|
+
let throttleTimeout;
|
|
2918
|
+
for (let i = 0; i < inlineExecutions.length; i++) {
|
|
2919
|
+
const r = stepResults[i];
|
|
2920
|
+
const s = inlineExecutions[i];
|
|
2921
|
+
if (r.type === 'retry') {
|
|
2922
|
+
toRetry.push({
|
|
2923
|
+
step: s,
|
|
2924
|
+
delaySeconds: r.timeoutSeconds,
|
|
2925
|
+
});
|
|
2926
|
+
}
|
|
2927
|
+
else if (r.type === 'throttled') {
|
|
2928
|
+
throttleTimeout = Math.max(throttleTimeout ?? 0, r.timeoutSeconds);
|
|
2929
|
+
}
|
|
2930
|
+
else if (r.type === 'completed' &&
|
|
2931
|
+
r.hasPendingOps) {
|
|
2932
|
+
anyPendingOps = true;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
if (throttleTimeout !== undefined) {
|
|
2936
|
+
// Defer redelivery of the orchestrator after the
|
|
2937
|
+
// throttle backoff. On replay every non-terminal step
|
|
2938
|
+
// is re-dispatched by the suspension handler: the
|
|
2939
|
+
// still-throttled steps run inline again WITH their
|
|
2940
|
+
// input (their `step_created` is deferred anew), and
|
|
2941
|
+
// any `retry` steps in this batch are queued as
|
|
2942
|
+
// background steps with their own retryAfter honored.
|
|
2943
|
+
// Terminal steps (completed/failed/skipped/gone) are
|
|
2944
|
+
// observed from their events and not re-run. Because
|
|
2945
|
+
// the replay drives all remaining work, we must NOT
|
|
2946
|
+
// also re-queue `toRetry` here — that would
|
|
2947
|
+
// double-dispatch those steps.
|
|
2948
|
+
//
|
|
2949
|
+
// This returns BEFORE the `anyPendingOps` branch
|
|
2950
|
+
// below, so a batch that mixes a throttle with a
|
|
2951
|
+
// completed step that left unflushed ops does not
|
|
2952
|
+
// queue the explicit flush continuation. That is safe
|
|
2953
|
+
// because the throttle backoff (>= 1s) always exceeds
|
|
2954
|
+
// the in-invocation flush window (<= 500ms + waitUntil),
|
|
2955
|
+
// so ops settle before the post-backoff redelivery
|
|
2956
|
+
// replays and reads them.
|
|
2957
|
+
return await reinvoke(throttleTimeout);
|
|
2958
|
+
}
|
|
2959
|
+
if (toRetry.length > 0) {
|
|
2960
|
+
const retryTraceCarrier = await nextTraceCarrier();
|
|
2961
|
+
await Promise.all(toRetry.map(({ step, delaySeconds }) => queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
2962
|
+
runId,
|
|
2963
|
+
stepId: step.correlationId,
|
|
2964
|
+
stepName: step.stepName,
|
|
2965
|
+
traceCarrier: retryTraceCarrier,
|
|
2966
|
+
requestedAt: new Date(),
|
|
2967
|
+
}, {
|
|
2968
|
+
delaySeconds,
|
|
2969
|
+
// Key the delayed retry on the step's
|
|
2970
|
+
// correlationId so it dedupes against the
|
|
2971
|
+
// keyed re-dispatch the suspension handler
|
|
2972
|
+
// performs on replay (it also uses
|
|
2973
|
+
// `idempotencyKey: step.correlationId`).
|
|
2974
|
+
//
|
|
2975
|
+
// Without this, a mixed batch where one step
|
|
2976
|
+
// `completed` with unflushed background ops
|
|
2977
|
+
// (`anyPendingOps`) and another step is
|
|
2978
|
+
// retrying would double-dispatch the retry:
|
|
2979
|
+
// the `anyPendingOps` branch below queues an
|
|
2980
|
+
// immediate plain continuation, whose replay
|
|
2981
|
+
// sees the still-`retrying` step as pending
|
|
2982
|
+
// and re-dispatches it *immediately* and
|
|
2983
|
+
// *with* a key. Since this delayed retry had
|
|
2984
|
+
// no key, the two messages wouldn't dedupe —
|
|
2985
|
+
// the step would run twice, the configured
|
|
2986
|
+
// retry backoff would be ignored (plain
|
|
2987
|
+
// `Error` retries persist no `retryAfter`, so
|
|
2988
|
+
// the world has no `TooEarly` guard), and the
|
|
2989
|
+
// retry body could run early/concurrently.
|
|
2990
|
+
// Sharing the key lets the earlier delayed
|
|
2991
|
+
// message win, honoring the backoff.
|
|
2992
|
+
idempotencyKey: step.correlationId,
|
|
2993
|
+
})));
|
|
2994
|
+
}
|
|
2995
|
+
// Let pending background operations flush before the next
|
|
2996
|
+
// replay reads their results.
|
|
2997
|
+
if (anyPendingOps) {
|
|
2998
|
+
runtimeLogger.debug('Breaking loop: inline step has pending ops', { workflowRunId: runId, loopIteration });
|
|
2999
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
3000
|
+
runId,
|
|
3001
|
+
traceCarrier: await nextTraceCarrier(),
|
|
3002
|
+
requestedAt: new Date(),
|
|
3003
|
+
});
|
|
3004
|
+
return;
|
|
3005
|
+
}
|
|
3006
|
+
if (toRetry.length > 0) {
|
|
3007
|
+
// Some inline steps will be re-run via their queued
|
|
3008
|
+
// retry messages; the background-step path replays
|
|
3009
|
+
// once all steps are terminal. Don't loop here — the
|
|
3010
|
+
// retrying steps have no terminal event to observe yet.
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
// All inline steps reached a terminal state
|
|
3014
|
+
// (completed/failed/skipped/gone) — loop back to replay
|
|
3015
|
+
// (the workflow observes the terminal events on replay).
|
|
3016
|
+
//
|
|
3017
|
+
// Reuse any inline delta. If it is partial, continue
|
|
3018
|
+
// from its cursor instead of reading the page again.
|
|
3019
|
+
if (inlineExecutions.length === 1) {
|
|
3020
|
+
const only = stepResults[0];
|
|
3021
|
+
if (only.type === 'completed' && only.inlineDelta) {
|
|
3022
|
+
appendEventLog(eventLog, only.inlineDelta);
|
|
3023
|
+
eventLog = only.inlineDelta.hasMore
|
|
3024
|
+
? nextEventLogLoad(eventLog)
|
|
3025
|
+
: { ...eventLog, type: 'ready' };
|
|
3026
|
+
continue;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
eventLog = nextEventLogLoad(eventLog);
|
|
3030
|
+
}
|
|
3031
|
+
else {
|
|
3032
|
+
// Stale-snapshot rejection of a guarded write made
|
|
3033
|
+
// directly by the replay loop — the result-bearing
|
|
3034
|
+
// `run_completed`, or the `wait_completed` of the wait
|
|
3035
|
+
// pass. Both reach this one catch and the rejection
|
|
3036
|
+
// does not say which, hence the neutral label.
|
|
3037
|
+
// Neither may be re-posted in place: the correlation id
|
|
3038
|
+
// and (for run_completed) the result itself came from
|
|
3039
|
+
// this replay, and a corrected log may produce
|
|
3040
|
+
// different ones. Don't fail the run — restart the
|
|
3041
|
+
// replay in this invocation, and only once that budget
|
|
3042
|
+
// is spent schedule an explicit re-invocation.
|
|
3043
|
+
// Rethrowing instead would rely on redelivery of the
|
|
3044
|
+
// CURRENT message, which the turbo path has already
|
|
3045
|
+
// acked — empirically the run then stalls for the
|
|
3046
|
+
// queue's ~300s default visibility timeout before
|
|
3047
|
+
// completing.
|
|
3048
|
+
let terminalError = err;
|
|
3049
|
+
if (PreconditionFailedError.is(err)) {
|
|
3050
|
+
if (restartReplayInProcess('replay-write', err)) {
|
|
3051
|
+
continue;
|
|
3052
|
+
}
|
|
3053
|
+
const escalation = await reinvokeAfterStaleRejection('replay-write', err);
|
|
3054
|
+
if (escalation.reinvoked)
|
|
3055
|
+
return escalation.result;
|
|
3056
|
+
// Per-run budget spent. Fall through to the terminal
|
|
3057
|
+
// path below instead of rethrowing: this catch owns
|
|
3058
|
+
// failing the run, and a rethrow would escape to the
|
|
3059
|
+
// queue handler and be redelivered.
|
|
3060
|
+
terminalError = escalation.error;
|
|
3061
|
+
}
|
|
3062
|
+
// Transient infrastructure failures talking to the
|
|
3063
|
+
// world (workflow-server) — an exhausted RetryAgent
|
|
3064
|
+
// (UND_ERR_REQ_RETRY from a sustained 429/503 storm),
|
|
3065
|
+
// a dropped socket, a connect/DNS failure, or a client
|
|
3066
|
+
// timeout — must NOT fail the run. Rethrow so the queue
|
|
3067
|
+
// redelivers and a fresh invocation retries the replay
|
|
3068
|
+
// once the backend recovers. The @vercel/queue handler
|
|
3069
|
+
// applies a fast (1s→60s) backoff by delivery count,
|
|
3070
|
+
// avoiding the ~5min default visibility-timeout redrive
|
|
3071
|
+
// (and never killing the process via run_failed).
|
|
3072
|
+
if (isRetryableWorldError(err)) {
|
|
3073
|
+
runLogger.warn('Transient world error during replay; redelivering via queue instead of failing the run', {
|
|
3074
|
+
errorName: err instanceof Error
|
|
3075
|
+
? err.name
|
|
3076
|
+
: 'UnknownError',
|
|
3077
|
+
errorMessage: err instanceof Error
|
|
3078
|
+
? err.message
|
|
3079
|
+
: String(err),
|
|
3080
|
+
deliveryAttempt: metadata.attempt,
|
|
3081
|
+
});
|
|
3082
|
+
throw err;
|
|
3083
|
+
}
|
|
3084
|
+
let replayDivergenceCountForFailure;
|
|
3085
|
+
if (ReplayDivergenceError.is(err)) {
|
|
3086
|
+
const divergenceCount = (replayDivergence?.count ?? 0) + 1;
|
|
3087
|
+
const maxRecoveryReplays = getReplayDivergenceMaxRetries();
|
|
3088
|
+
if (divergenceCount <= maxRecoveryReplays) {
|
|
3089
|
+
runLogger.warn('Workflow replay diverged; queueing a recovery replay before declaring the event log corrupted', {
|
|
3090
|
+
errorCode: RUN_ERROR_CODES.REPLAY_DIVERGENCE,
|
|
3091
|
+
divergenceEventId: err.eventId,
|
|
3092
|
+
priorDivergenceEventId: replayDivergence?.eventId,
|
|
3093
|
+
divergenceCount,
|
|
3094
|
+
deliveryAttempt: metadata.attempt,
|
|
3095
|
+
maxRecoveryReplays,
|
|
3096
|
+
errorMessage: err.message,
|
|
3097
|
+
});
|
|
3098
|
+
await queueMessage(world, getWorkflowQueueName(workflowName, namespace), {
|
|
3099
|
+
runId,
|
|
3100
|
+
traceCarrier: await nextTraceCarrier(),
|
|
3101
|
+
requestedAt: new Date(),
|
|
3102
|
+
replayDivergence: {
|
|
3103
|
+
eventId: err.eventId,
|
|
3104
|
+
count: divergenceCount,
|
|
3105
|
+
},
|
|
3106
|
+
});
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
replayDivergenceCountForFailure = divergenceCount;
|
|
3110
|
+
terminalError = new CorruptedEventLogError(`Workflow replay diverged ${divergenceCount} times after ${maxRecoveryReplays} recovery replays; latest divergent event was ${err.eventId}. Last divergence: ${err.message}`, { cause: err });
|
|
3111
|
+
}
|
|
3112
|
+
else if (replayStart > 0) {
|
|
3113
|
+
replayRecoveryReporter.activate();
|
|
3114
|
+
}
|
|
3115
|
+
// User code errors and terminal runtime errors fail the run.
|
|
3116
|
+
if (terminalError instanceof Error) {
|
|
3117
|
+
span?.recordException?.(terminalError);
|
|
3118
|
+
}
|
|
3119
|
+
const normalizedError = await normalizeUnknownError(terminalError);
|
|
3120
|
+
const errorName = normalizedError.name || getErrorName(terminalError);
|
|
3121
|
+
const errorMessage = normalizedError.message;
|
|
3122
|
+
let errorStack = normalizedError.stack || getErrorStack(terminalError);
|
|
3123
|
+
if (errorStack) {
|
|
3124
|
+
const parsedName = parseWorkflowName(workflowName);
|
|
3125
|
+
const filename = parsedName?.moduleSpecifier || workflowName;
|
|
3126
|
+
errorStack = remapErrorStack(errorStack, filename, workflowCode);
|
|
3127
|
+
}
|
|
3128
|
+
// Classify the error: WorkflowRuntimeError indicates
|
|
3129
|
+
// an SDK/runtime issue, and selected subclasses use
|
|
3130
|
+
// more specific codes for backend tracking.
|
|
3131
|
+
const errorCode = classifyRunError(terminalError);
|
|
3132
|
+
runtimeLogger.error('Error while running workflow', {
|
|
3133
|
+
workflowRunId: runId,
|
|
3134
|
+
errorCode,
|
|
3135
|
+
errorName,
|
|
3136
|
+
errorStack,
|
|
3137
|
+
});
|
|
3138
|
+
// Apply the source-map-remapped stack to the thrown
|
|
3139
|
+
// value so that the serialized error preserves it
|
|
3140
|
+
// for consumers. `types.isNativeError()` is used
|
|
3141
|
+
// instead of `err instanceof Error` because the
|
|
3142
|
+
// workflow runs in a separate VM realm — its Error
|
|
3143
|
+
// class is distinct from the host's, so `instanceof
|
|
3144
|
+
// Error` is `false` for VM-thrown errors. The V8
|
|
3145
|
+
// type tag works across realms.
|
|
3146
|
+
if (types.isNativeError(terminalError) && errorStack) {
|
|
3147
|
+
terminalError.stack = errorStack;
|
|
3148
|
+
}
|
|
3149
|
+
// Fail the workflow run via event (event-sourced).
|
|
3150
|
+
// Serialize the original thrown value so its full
|
|
3151
|
+
// type identity and custom properties round-trip
|
|
3152
|
+
// through the event log.
|
|
3153
|
+
//
|
|
3154
|
+
// Precondition-guard asymmetry: unlike `run_completed`,
|
|
3155
|
+
// this terminal `run_failed` sends no `stateUpdatedAt`
|
|
3156
|
+
// snapshot, so it is never 412-rejected even if a hook
|
|
3157
|
+
// landed mid-replay and could have changed the path that
|
|
3158
|
+
// threw. This is intentional and fail-open: a spurious
|
|
3159
|
+
// failure is recoverable (the run can be re-run from the
|
|
3160
|
+
// dashboard), whereas a spurious *completion* commits a
|
|
3161
|
+
// wrong result. Guarding this write symmetrically would
|
|
3162
|
+
// also need the loaded event log, which is scoped to the
|
|
3163
|
+
// replay `try` above and not available in this catch.
|
|
3164
|
+
try {
|
|
3165
|
+
// Turbo: order the terminal write after the
|
|
3166
|
+
// backgrounded run_started so the run exists.
|
|
3167
|
+
await awaitRunReady();
|
|
3168
|
+
await createEvent({
|
|
3169
|
+
eventType: 'run_failed',
|
|
3170
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
3171
|
+
eventData: {
|
|
3172
|
+
error: await dehydrateRunError(terminalError, runId, encryptionKey, globalThis, (workflowRun?.specVersion ?? 0) >=
|
|
3173
|
+
SPEC_VERSION_SUPPORTS_COMPRESSION),
|
|
3174
|
+
errorCode,
|
|
3175
|
+
},
|
|
3176
|
+
}, {
|
|
3177
|
+
requestId,
|
|
3178
|
+
...(replayDivergenceCountForFailure !== undefined
|
|
3179
|
+
? {
|
|
3180
|
+
replayDivergenceCount: replayDivergenceCountForFailure,
|
|
3181
|
+
}
|
|
3182
|
+
: {}),
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
catch (failErr) {
|
|
3186
|
+
if (EntityConflictError.is(failErr) ||
|
|
3187
|
+
RunExpiredError.is(failErr)) {
|
|
3188
|
+
runtimeLogger.info('Tried failing workflow run, but run has already finished.', {
|
|
3189
|
+
workflowRunId: runId,
|
|
3190
|
+
message: failErr.message,
|
|
3191
|
+
});
|
|
3192
|
+
return;
|
|
3193
|
+
}
|
|
3194
|
+
if (isWorldContractError(failErr)) {
|
|
3195
|
+
runtimeLogger.error('Fatal world contract error while recording workflow failure', {
|
|
3196
|
+
workflowRunId: runId,
|
|
3197
|
+
errorCode: RUN_ERROR_CODES.WORLD_CONTRACT_ERROR,
|
|
3198
|
+
error: failErr instanceof Error
|
|
3199
|
+
? failErr.message
|
|
3200
|
+
: String(failErr),
|
|
3201
|
+
});
|
|
3202
|
+
return;
|
|
3203
|
+
}
|
|
3204
|
+
throw failErr;
|
|
3205
|
+
}
|
|
384
3206
|
span?.setAttributes({
|
|
3207
|
+
...Attribute.WorkflowRunStatus('failed'),
|
|
385
3208
|
...Attribute.WorkflowErrorCode(errorCode),
|
|
386
3209
|
...Attribute.WorkflowErrorName(errorName),
|
|
387
3210
|
...Attribute.WorkflowErrorMessage(errorMessage),
|
|
@@ -389,65 +3212,49 @@ export function workflowEntrypoint(workflowCode) {
|
|
|
389
3212
|
});
|
|
390
3213
|
return;
|
|
391
3214
|
}
|
|
392
|
-
else {
|
|
393
|
-
throw failErr;
|
|
394
|
-
}
|
|
395
3215
|
}
|
|
396
|
-
span?.setAttributes({
|
|
397
|
-
...Attribute.WorkflowRunStatus('failed'),
|
|
398
|
-
...Attribute.WorkflowErrorCode(errorCode),
|
|
399
|
-
...Attribute.WorkflowErrorName(errorName),
|
|
400
|
-
...Attribute.WorkflowErrorMessage(errorMessage),
|
|
401
|
-
...Attribute.ErrorType(errorName),
|
|
402
|
-
});
|
|
403
|
-
return;
|
|
404
3216
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
try {
|
|
409
|
-
await world.events.create(runId, {
|
|
410
|
-
eventType: 'run_completed',
|
|
411
|
-
specVersion: SPEC_VERSION_CURRENT,
|
|
412
|
-
eventData: {
|
|
413
|
-
output: workflowResult,
|
|
414
|
-
},
|
|
415
|
-
}, { requestId });
|
|
416
|
-
}
|
|
417
|
-
catch (err) {
|
|
418
|
-
if (EntityConflictError.is(err) ||
|
|
419
|
-
RunExpiredError.is(err)) {
|
|
420
|
-
runtimeLogger.info('Tried completing workflow run, but run has already finished.', {
|
|
421
|
-
workflowRunId: runId,
|
|
422
|
-
message: err.message,
|
|
423
|
-
});
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
else {
|
|
427
|
-
throw err;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
span?.setAttributes({
|
|
431
|
-
...Attribute.WorkflowRunStatus('completed'),
|
|
432
|
-
...Attribute.WorkflowEventsCount(events.length),
|
|
433
|
-
});
|
|
434
|
-
}); // End trace
|
|
435
|
-
}); // End withWorkflowBaggage
|
|
436
|
-
}).finally(() => {
|
|
437
|
-
if (replayTimeout) {
|
|
438
|
-
clearTimeout(replayTimeout);
|
|
439
|
-
}
|
|
440
|
-
}); // End withTraceContext
|
|
3217
|
+
});
|
|
3218
|
+
});
|
|
3219
|
+
});
|
|
441
3220
|
});
|
|
442
3221
|
let cachedHandler;
|
|
3222
|
+
let invocationCount = 0;
|
|
3223
|
+
const entrypointCreatedAt = Date.now();
|
|
3224
|
+
const routeModuleBodyInitMs = typeof options?.routeModuleBodyStartedAt === 'number'
|
|
3225
|
+
? entrypointCreatedAt - options.routeModuleBodyStartedAt
|
|
3226
|
+
: undefined;
|
|
443
3227
|
return withHealthCheck(async (req) => {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return
|
|
3228
|
+
invocationCount += 1;
|
|
3229
|
+
const handlerCached = cachedHandler !== undefined;
|
|
3230
|
+
const spanKind = await getSpanKind('SERVER');
|
|
3231
|
+
return trace('workflow.route.flow', {
|
|
3232
|
+
kind: spanKind,
|
|
3233
|
+
attributes: {
|
|
3234
|
+
...Attribute.WorkflowRouteType('flow'),
|
|
3235
|
+
...Attribute.FaasInstance(COMPUTE_INSTANCE_ID),
|
|
3236
|
+
...Attribute.WorkflowRouteHandlerCached(handlerCached),
|
|
3237
|
+
...Attribute.WorkflowRouteInvocationCount(invocationCount),
|
|
3238
|
+
...Attribute.WorkflowRouteEntrypointAgeMs(Date.now() - entrypointCreatedAt),
|
|
3239
|
+
...(routeModuleBodyInitMs === undefined
|
|
3240
|
+
? {}
|
|
3241
|
+
: Attribute.WorkflowRouteModuleBodyInitMs(routeModuleBodyInitMs)),
|
|
3242
|
+
...Attribute.HttpRequestMethod(req.method),
|
|
3243
|
+
...Attribute.HttpRoute('/.well-known/workflow/v1/flow'),
|
|
3244
|
+
},
|
|
3245
|
+
}, async (span) => {
|
|
3246
|
+
if (!cachedHandler) {
|
|
3247
|
+
cachedHandler = await trace('workflow.route.init', async () => {
|
|
3248
|
+
const worldHandlers = await trace('workflow.route.get_world_handlers', async () => getWorldHandlers());
|
|
3249
|
+
return handler(worldHandlers);
|
|
3250
|
+
});
|
|
3251
|
+
}
|
|
3252
|
+
const response = await cachedHandler(req);
|
|
3253
|
+
if (response instanceof Response) {
|
|
3254
|
+
span?.setAttributes(Attribute.HttpResponseStatusCode(response.status));
|
|
3255
|
+
}
|
|
3256
|
+
return response;
|
|
3257
|
+
});
|
|
448
3258
|
});
|
|
449
3259
|
}
|
|
450
|
-
// this is a no-op placeholder as the client is
|
|
451
|
-
// expecting this to be present but we aren't actually using it
|
|
452
|
-
export function runStep() { }
|
|
453
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsZUFBZSxFQUNmLGVBQWUsRUFDZixvQkFBb0IsR0FDckIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBRUwsb0JBQW9CLEVBQ3BCLDJCQUEyQixHQUU1QixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM1QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDakQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM1QyxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLDBCQUEwQixFQUMxQixpQkFBaUIsR0FDbEIsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGdCQUFnQixFQUNoQix3QkFBd0IsRUFDeEIsdUJBQXVCLEVBQ3ZCLGVBQWUsR0FDaEIsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNuRSxPQUFPLEVBQ0wsUUFBUSxFQUNSLGdCQUFnQixHQUVqQixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEtBQUssU0FBUyxNQUFNLHFDQUFxQyxDQUFDO0FBQ2pFLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsS0FBSyxFQUNMLGdCQUFnQixFQUNoQixtQkFBbUIsR0FDcEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFP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Q0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUM7d0JBQzNDLEdBQUcsU0FBUyxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7cUJBQ2hELENBQUMsQ0FBQztnQkFDTCxDQUFDLENBQ0YsQ0FBQyxDQUFDLFlBQVk7WUFDakIsQ0FBQyxDQUNGLENBQUMsQ0FBQywwQkFBMEI7UUFDL0IsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNkLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQ2xCLFlBQVksQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUM5QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUMsQ0FBQyx1QkFBdUI7SUFDN0IsQ0FBQyxDQUNGLENBQUM7SUFFSixJQUFJLGFBQWdFLENBQUM7SUFDckUsT0FBTyxlQUFlLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFO1FBQ25DLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQixhQUFhLEdBQUcsT0FBTyxDQUFDLE1BQU0sZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCxPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCwrQ0FBK0M7QUFDL0MsK0RBQStEO0FBQy9ELE1BQU0sVUFBVSxPQUFPLEtBQUksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEVudGl0eUNvbmZsaWN0RXJyb3IsXG4gIFJVTl9FUlJPUl9DT0RFUyxcbiAgUnVuRXhwaXJlZEVycm9yLFxuICBXb3JrZmxvd1J1bnRpbWVFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgeyBwYXJzZVdvcmtmbG93TmFtZSB9IGZyb20gJ0B3b3JrZmxvdy91dGlscy9wYXJzZS1uYW1lJztcbmltcG9ydCB7XG4gIHR5cGUgRXZlbnQsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBXb3JrZmxvd0ludm9rZVBheWxvYWRTY2hlbWEsXG4gIHR5cGUgV29ya2Zsb3dSdW4sXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBjbGFzc2lmeVJ1bkVycm9yIH0gZnJvbSAnLi9jbGFzc2lmeS1lcnJvci5qcyc7XG5pbXBvcnQgeyBpbXBvcnRLZXkgfSBmcm9tICcuL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHsgV29ya2Zsb3dTdXNwZW5zaW9uIH0gZnJvbSAnLi9nbG9iYWwuanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7XG4gIE1BWF9RVUVVRV9ERUxJVkVSSUVTLFxuICBSRVBMQVlfVElNRU9VVF9NQVhfUkVUUklFUyxcbiAgUkVQTEFZX1RJTUVPVVRfTVMsXG59IGZyb20gJy4vcnVudGltZS9jb25zdGFudHMuanMnO1xuaW1wb3J0IHtcbiAgZ2V0QWxsV29ya2Zsb3dSdW5FdmVudHMsXG4gIGdldFF1ZXVlT3ZlcmhlYWQsXG4gIGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZSxcbiAgcGFyc2VIZWFsdGhDaGVja1BheWxvYWQsXG4gIHdpdGhIZWFsdGhDaGVjayxcbn0gZnJvbSAnLi9ydW50aW1lL2hlbHBlcnMuanMnO1xuaW1wb3J0IHsgaGFuZGxlU3VzcGVuc2lvbiB9IGZyb20gJy4vcnVudGltZS9zdXNwZW5zaW9uLWhhbmRsZXIuanMnO1xuaW1wb3J0IHtcbiAgZ2V0V29ybGQsXG4gIGdldFdvcmxkSGFuZGxlcnMsXG4gIHR5cGUgV29ybGRIYW5kbGVycyxcbn0gZnJvbSAnLi9ydW50aW1lL3dvcmxkLmpzJztcbmltcG9ydCB7IHJlbWFwRXJyb3JTdGFjayB9IGZyb20gJy4vc291cmNlLW1hcC5qcyc7XG5pbXBvcnQgKiBhcyBBdHRyaWJ1dGUgZnJvbSAnLi90ZWxlbWV0cnkvc2VtYW50aWMtY29udmVudGlvbnMuanMnO1xuaW1wb3J0IHtcbiAgbGlua1RvQ3VycmVudENvbnRleHQsXG4gIHRyYWNlLFxuICB3aXRoVHJhY2VDb250ZXh0LFxuICB3aXRoV29ya2Zsb3dCYWdnYWdlLFxufSBmcm9tICcuL3RlbGVtZXRyeS5qcyc7XG5pbXBvcnQgeyBnZXRFcnJvck5hbWUsIGdldEVycm9yU3RhY2ssIG5vcm1hbGl6ZVVua25vd25FcnJvciB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgYnVpbGRXb3JrZmxvd1N1c3BlbnNpb25NZXNzYWdlIH0gZnJvbSAnLi91dGlsLmpzJztcbmltcG9ydCB7IHJ1bldvcmtmbG93IH0gZnJvbSAnLi93b3JrZmxvdy5qcyc7XG5cbmV4cG9ydCB0eXBlIHsgRXZlbnQsIFdvcmtmbG93UnVuIH07XG5leHBvcnQgeyBXb3JrZmxvd1N1c3BlbnNpb24gfSBmcm9tICcuL2dsb2JhbC5qcyc7XG5leHBvcnQge1xuICB0eXBlIEhlYWx0aENoZWNrRW5kcG9pbnQsXG4gIHR5cGUgSGVhbHRoQ2hlY2tPcHRpb25zLFxuICB0eXBlIEhlYWx0aENoZWNrUmVzdWx0LFxuICBoZWFsdGhDaGVjayxcbn0gZnJvbSAnLi9ydW50aW1lL2hlbHBlcnMuanMnO1xuZXhwb3J0IHtcbiAgZ2V0SG9va0J5VG9rZW4sXG4gIHJlc3VtZUhvb2ssXG4gIHJlc3VtZVdlYmhvb2ssXG59IGZyb20gJy4vcnVudGltZS9yZXN1bWUtaG9vay5qcyc7XG5leHBvcnQge1xuICBnZXRSdW4sXG4gIFJ1bixcbiAgdHlwZSBXb3JrZmxvd1JlYWRhYmxlU3RyZWFtLFxuICB0eXBlIFdvcmtmbG93UmVhZGFibGVTdHJlYW1PcHRpb25zLFxufSBmcm9tICcuL3J1bnRpbWUvcnVuLmpzJztcbmV4cG9ydCB7XG4gIGNhbmNlbFJ1bixcbiAgbGlzdFN0cmVhbXMsXG4gIHR5cGUgUmVhZFN0cmVhbU9wdGlvbnMsXG4gIHR5cGUgUmVjcmVhdGVSdW5PcHRpb25zLFxuICByZWFkU3RyZWFtLFxuICByZWNyZWF0ZVJ1bkZyb21FeGlzdGluZyxcbiAgcmVlbnF1ZXVlUnVuLFxuICB0eXBlIFN0b3BTbGVlcE9wdGlvbnMsXG4gIHR5cGUgU3RvcFNsZWVwUmVzdWx0LFxuICB3YWtlVXBSdW4sXG59IGZyb20gJy4vcnVudGltZS9ydW5zLmpzJztcbmV4cG9ydCB7XG4gIHR5cGUgU3RhcnRPcHRpb25zLFxuICB0eXBlIFN0YXJ0T3B0aW9uc0Jhc2UsXG4gIHR5cGUgU3RhcnRPcHRpb25zV2l0aERlcGxveW1lbnRJZCxcbiAgdHlwZSBTdGFydE9wdGlvbnNXaXRob3V0RGVwbG95bWVudElkLFxuICBzdGFydCxcbn0gZnJvbSAnLi9ydW50aW1lL3N0YXJ0LmpzJztcbmV4cG9ydCB7IHN0ZXBFbnRyeXBvaW50IH0gZnJvbSAnLi9ydW50aW1lL3N0ZXAtaGFuZGxlci5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVXb3JsZCxcbiAgZ2V0V29ybGQsXG4gIGdldFdvcmxkSGFuZGxlcnMsXG4gIHNldFdvcmxkLFxufSBmcm9tICcuL3J1bnRpbWUvd29ybGQuanMnO1xuXG4vKipcbiAqIEZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIHNpbmdsZSByb3V0ZSB3aGljaCBoYW5kbGVzIGFueSB3b3JrZmxvdyBleGVjdXRpb25cbiAqIHJlcXVlc3QgYW5kIHJvdXRlcyB0byB0aGUgYXBwcm9wcmlhdGUgd29ya2Zsb3cgZnVuY3Rpb24uXG4gKlxuICogQHBhcmFtIHdvcmtmbG93Q29kZSAtIFRoZSB3b3JrZmxvdyBidW5kbGUgY29kZSBjb250YWluaW5nIGFsbCB0aGUgd29ya2Zsb3dcbiAqIGZ1bmN0aW9ucyBhdCB0aGUgdG9wIGxldmVsLlxuICogQHJldHVybnMgQSBmdW5jdGlvbiB0aGF0IGNhbiBiZSB1c2VkIGFzIGEgVmVyY2VsIEFQSSByb3V0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdvcmtmbG93RW50cnlwb2ludChcbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmdcbik6IChyZXE6IFJlcXVlc3QpID0+IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgY29uc3QgaGFuZGxlciA9ICh3b3JsZEhhbmRsZXJzOiBXb3JsZEhhbmRsZXJzKSA9PlxuICAgIHdvcmxkSGFuZGxlcnMuY3JlYXRlUXVldWVIYW5kbGVyKFxuICAgICAgJ19fd2tmX3dvcmtmbG93XycsXG4gICAgICBhc3luYyAobWVzc2FnZV8sIG1ldGFkYXRhKSA9PiB7XG4gICAgICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZVxuICAgICAgICAvLyBOT1RFOiBIZWFsdGggY2hlY2sgbWVzc2FnZXMgYXJlIGludGVudGlvbmFsbHkgdW5hdXRoZW50aWNhdGVkIGZvciBtb25pdG9yaW5nIHB1cnBvc2VzLlxuICAgICAgICAvLyBUaGV5IG9ubHkgd3JpdGUgYSBzaW1wbGUgc3RhdHVzIHJlc3BvbnNlIHRvIGEgc3RyZWFtIGFuZCBkbyBub3QgZXhwb3NlIHNlbnNpdGl2ZSBkYXRhLlxuICAgICAgICAvLyBUaGUgc3RyZWFtIG5hbWUgaW5jbHVkZXMgYSB1bmlxdWUgY29ycmVsYXRpb25JZCB0aGF0IG11c3QgYmUga25vd24gYnkgdGhlIGNhbGxlci5cbiAgICAgICAgY29uc3QgaGVhbHRoQ2hlY2sgPSBwYXJzZUhlYWx0aENoZWNrUGF5bG9hZChtZXNzYWdlXyk7XG4gICAgICAgIGlmIChoZWFsdGhDaGVjaykge1xuICAgICAgICAgIGF3YWl0IGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgICAgICAgICAgIGhlYWx0aENoZWNrLFxuICAgICAgICAgICAgJ3dvcmtmbG93JyxcbiAgICAgICAgICAgIHdvcmxkSGFuZGxlcnMuc3BlY1ZlcnNpb25cbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICB0cmFjZUNhcnJpZXI6IHRyYWNlQ29udGV4dCxcbiAgICAgICAgICByZXF1ZXN0ZWRBdCxcbiAgICAgICAgICBydW5JbnB1dCxcbiAgICAgICAgfSA9IFdvcmtmbG93SW52b2tlUGF5bG9hZFNjaGVtYS5wYXJzZShtZXNzYWdlXyk7XG4gICAgICAgIGNvbnN0IHsgcmVxdWVzdElkIH0gPSBtZXRhZGF0YTtcbiAgICAgICAgLy8gRXh0cmFjdCB0aGUgd29ya2Zsb3cgbmFtZSBmcm9tIHRoZSB0b3BpYyBuYW1lXG4gICAgICAgIGNvbnN0IHdvcmtmbG93TmFtZSA9IG1ldGFkYXRhLnF1ZXVlTmFtZS5zbGljZSgnX193a2Zfd29ya2Zsb3dfJy5sZW5ndGgpO1xuXG4gICAgICAgIC8vIC0tLSBNYXggZGVsaXZlcnkgY2hlY2sgLS0tXG4gICAgICAgIC8vIEVuZm9yY2UgbWF4IGRlbGl2ZXJ5IGxpbWl0IGJlZm9yZSBhbnkgaW5mcmFzdHJ1Y3R1cmUgY2FsbHMuXG4gICAgICAgIC8vIFRoaXMgcHJldmVudHMgcnVuYXdheSB3b3JrZmxvd3MgZnJvbSBjb25zdW1pbmcgaW5maW5pdGUgcXVldWUgZGVsaXZlcmllcy5cbiAgICAgICAgLy8gQXQgdGhpcyBwb2ludCwgd2Ugd2FudCB0byBkbyB0aGUgbWluaW1hbCBhbW91bnQgb2Ygd29yayAobm8gZmV0Y2hpbmdcbiAgICAgICAgLy8gb2YgdGhlIHdvcmtmbG93IGV2ZW50cywgZXRjLiBXZSBzaW1wbHkgYXR0ZW1wdCB0byBtYXJrIHRoZSBydW4gYXMgZmFpbGVkXG4gICAgICAgIC8vIGFuZCBpZiB0aGF0IGZhaWxzLCB0aGUgbWVzc2FnZSBpcyBzdGlsbCBjb25zdW1lZCBidXQgd2l0aCBhZGVxdWF0ZSBsb2dnaW5nXG4gICAgICAgIC8vIHRoYXQgYW4gZXJyb3Igb2NjdXJyZWQgcHJldmVudGluZyB1cyBmcm9tIGZhaWxpbmcgdGhlIHJ1bi5cbiAgICAgICAgaWYgKG1ldGFkYXRhLmF0dGVtcHQgPiBNQVhfUVVFVUVfREVMSVZFUklFUykge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoXG4gICAgICAgICAgICBgV29ya2Zsb3cgaGFuZGxlciBleGNlZWRlZCBtYXggZGVsaXZlcmllcyAoJHttZXRhZGF0YS5hdHRlbXB0fS8ke01BWF9RVUVVRV9ERUxJVkVSSUVTfSlgLFxuICAgICAgICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCwgd29ya2Zsb3dOYW1lLCBhdHRlbXB0OiBtZXRhZGF0YS5hdHRlbXB0IH1cbiAgICAgICAgICApO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkKCk7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3J1bl9mYWlsZWQnLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBXb3JrZmxvdyBleGNlZWRlZCBtYXhpbXVtIHF1ZXVlIGRlbGl2ZXJpZXMgKCR7bWV0YWRhdGEuYXR0ZW1wdH0vJHtNQVhfUVVFVUVfREVMSVZFUklFU30pYCxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICBlcnJvckNvZGU6IFJVTl9FUlJPUl9DT0RFUy5NQVhfREVMSVZFUklFU19FWENFRURFRCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZXJyKSB8fCBSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAvLyBSdW4gYWxyZWFkeSBmaW5pc2hlZCwgY29uc3VtZSB0aGUgbWVzc2FnZSBzaWxlbnRseVxuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBydW50aW1lTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIG1hcmsgcnVuIGFzIGZhaWxlZCBhZnRlciAke21ldGFkYXRhLmF0dGVtcHR9IGRlbGl2ZXJ5IGF0dGVtcHRzLiBgICtcbiAgICAgICAgICAgICAgICBgQSBwZXJzaXN0ZW50IGVycm9yIGlzIHByZXZlbnRpbmcgdGhlIHJ1biBmcm9tIGJlaW5nIHRlcm1pbmF0ZWQuIGAgK1xuICAgICAgICAgICAgICAgIGBUaGUgcnVuIHdpbGwgcmVtYWluIGluIGl0cyBjdXJyZW50IHN0YXRlIHVudGlsIG1hbnVhbGx5IHJlc29sdmVkLiBgICtcbiAgICAgICAgICAgICAgICBgVGhpcyBpcyBtb3N0IGxpa2VseSBkdWUgdG8gYSBwZXJzaXN0ZW50IG91dGFnZSBvZiB0aGUgd29ya2Zsb3cgYmFja2VuZCBgICtcbiAgICAgICAgICAgICAgICBgb3IgYSBidWcgaW4gdGhlIHdvcmtmbG93IHJ1bnRpbWUgYW5kIHNob3VsZCBiZSByZXBvcnRlZCB0byB0aGUgV29ya2Zsb3cgdGVhbS5gLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICAgICAgICAgICAgICBhdHRlbXB0OiBtZXRhZGF0YS5hdHRlbXB0LFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzcGFuTGlua3MgPSBhd2FpdCBsaW5rVG9DdXJyZW50Q29udGV4dCgpO1xuXG4gICAgICAgIC8vIC0tLSBSZXBsYXkgdGltZW91dCBndWFyZCAtLS1cbiAgICAgICAgLy8gSWYgdGhlIHJlcGxheSB0YWtlcyBsb25nZXIgdGhhbiB0aGUgdGltZW91dCwgZmFpbCB0aGUgcnVuIGFuZCBleGl0LlxuICAgICAgICAvLyBUaGlzIG11c3QgYmUgbG93ZXIgdGhhbiB0aGUgZnVuY3Rpb24ncyBtYXhEdXJhdGlvbiB0byBlbnN1cmVcbiAgICAgICAgLy8gdGhlIGZhaWx1cmUgaXMgcmVjb3JkZWQgYmVmb3JlIHRoZSBwbGF0Zm9ybSBraWxscyB0aGUgZnVuY3Rpb24uXG4gICAgICAgIGxldCByZXBsYXlUaW1lb3V0OiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHByb2Nlc3MuZW52LlZFUkNFTF9VUkwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlcGxheVRpbWVvdXQgPSBzZXRUaW1lb3V0KGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoJ1dvcmtmbG93IHJlcGxheSBleGNlZWRlZCB0aW1lb3V0Jywge1xuICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgdGltZW91dE1zOiBSRVBMQVlfVElNRU9VVF9NUyxcbiAgICAgICAgICAgICAgYXR0ZW1wdDogbWV0YWRhdGEuYXR0ZW1wdCxcbiAgICAgICAgICAgICAgbWF4UmV0cmllczogUkVQTEFZX1RJTUVPVVRfTUFYX1JFVFJJRVMsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gQWxsb3cgYSBmZXcgcmV0cmllcyBiZWZvcmUgcGVybWFuZW50bHkgZmFpbGluZyB0aGUgcnVuLlxuICAgICAgICAgICAgLy8gT24gZWFybHkgYXR0ZW1wdHMsIGp1c3QgZXhpdCBzbyB0aGUgcXVldWUgcmV0cmllcyB0aGUgbWVzc2FnZS5cbiAgICAgICAgICAgIGlmIChtZXRhZGF0YS5hdHRlbXB0IDw9IFJFUExBWV9USU1FT1VUX01BWF9SRVRSSUVTKSB7XG4gICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZCgpO1xuICAgICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3J1bl9mYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFdvcmtmbG93IHJlcGxheSBleGNlZWRlZCBtYXhpbXVtIGR1cmF0aW9uICgke1JFUExBWV9USU1FT1VUX01TIC8gMTAwMH1zKSBhZnRlciAke21ldGFkYXRhLmF0dGVtcHR9IGF0dGVtcHRzYCxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JDb2RlOiBSVU5fRVJST1JfQ09ERVMuUkVQTEFZX1RJTUVPVVQsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgIC8vIEJlc3QgZWZmb3J0IOKAlCBwcm9jZXNzIGV4aXRzIHJlZ2FyZGxlc3NcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIE5vdGUgdGhhdCB0aGlzIGFsc28gcHJldmVudHMgdGhlIHJ1bnRpbWUgZnJvbSBhY2tpbmcgdGhlIHF1ZXVlIG1lc3NhZ2UsXG4gICAgICAgICAgICAvLyBzbyB0aGUgcXVldWUgd2lsbCBjYWxsIGJhY2sgb25jZSwgYWZ0ZXIgd2hpY2ggYSA0MTAgd2lsbCBnZXQgaXQgdG8gZXhpdCBlYXJseS5cbiAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgICAgICB9LCBSRVBMQVlfVElNRU9VVF9NUyk7XG4gICAgICAgICAgcmVwbGF5VGltZW91dC51bnJlZigpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSW52b2tlIHVzZXIgd29ya2Zsb3cgd2l0aGluIHRoZSBwcm9wYWdhdGVkIHRyYWNlIGNvbnRleHQgYW5kIGJhZ2dhZ2VcbiAgICAgICAgcmV0dXJuIGF3YWl0IHdpdGhUcmFjZUNvbnRleHQodHJhY2VDb250ZXh0LCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgLy8gU2V0IHdvcmtmbG93IGNvbnRleHQgYXMgYmFnZ2FnZSBmb3IgYXV0b21hdGljIHByb3BhZ2F0aW9uXG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHdpdGhXb3JrZmxvd0JhZ2dhZ2UoXG4gICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCB3b3JrZmxvd05hbWUgfSxcbiAgICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZCgpO1xuICAgICAgICAgICAgICByZXR1cm4gdHJhY2UoXG4gICAgICAgICAgICAgICAgYFdPUktGTE9XICR7d29ya2Zsb3dOYW1lfWAsXG4gICAgICAgICAgICAgICAgeyBsaW5rczogc3BhbkxpbmtzIH0sXG4gICAgICAgICAgICAgICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dOYW1lKHdvcmtmbG93TmFtZSksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd09wZXJhdGlvbignZXhlY3V0ZScpLFxuICAgICAgICAgICAgICAgICAgICAvLyBTdGFuZGFyZCBPVEVMIG1lc3NhZ2luZyBjb252ZW50aW9uc1xuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nU3lzdGVtKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ0Rlc3RpbmF0aW9uTmFtZShtZXRhZGF0YS5xdWV1ZU5hbWUpLFxuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nTWVzc2FnZUlkKG1ldGFkYXRhLm1lc3NhZ2VJZCksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdPcGVyYXRpb25UeXBlKCdwcm9jZXNzJyksXG4gICAgICAgICAgICAgICAgICAgIC4uLmdldFF1ZXVlT3ZlcmhlYWQoeyByZXF1ZXN0ZWRBdCB9KSxcbiAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAvLyBUT0RPOiB2YWxpZGF0ZSBgd29ya2Zsb3dOYW1lYCBleGlzdHMgYmVmb3JlIGNvbnN1bWluZyBtZXNzYWdlP1xuXG4gICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuSWQocnVuSWQpLFxuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dUcmFjZVByb3BhZ2F0ZWQoISF0cmFjZUNvbnRleHQpLFxuICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgIGxldCB3b3JrZmxvd1N0YXJ0ZWRBdCA9IC0xO1xuICAgICAgICAgICAgICAgICAgbGV0IHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1biB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIC8vIFByZS1sb2FkZWQgZXZlbnRzIGZyb20gdGhlIHJ1bl9zdGFydGVkIHJlc3BvbnNlLlxuICAgICAgICAgICAgICAgICAgLy8gV2hlbiBwcmVzZW50LCB3ZSBza2lwIHRoZSBldmVudHMubGlzdCBjYWxsIHRvIHJlZHVjZSBUVEZCLlxuICAgICAgICAgICAgICAgICAgbGV0IHByZWxvYWRlZEV2ZW50czogRXZlbnRbXSB8IHVuZGVmaW5lZDtcblxuICAgICAgICAgICAgICAgICAgLy8gLS0tIEluZnJhc3RydWN0dXJlOiBwcmVwYXJlIHRoZSBydW4gc3RhdGUgLS0tXG4gICAgICAgICAgICAgICAgICAvLyBBbHdheXMgY2FsbCBydW5fc3RhcnRlZCBkaXJlY3RseSDigJQgdGhpcyBib3RoIHRyYW5zaXRpb25zXG4gICAgICAgICAgICAgICAgICAvLyB0aGUgcnVuIHRvICdydW5uaW5nJyBBTkQgcmV0dXJucyB0aGUgcnVuIGVudGl0eSwgc2F2aW5nXG4gICAgICAgICAgICAgICAgICAvLyBhIHNlcGFyYXRlIHJ1bnMuZ2V0IHJvdW5kLXRyaXAuXG4gICAgICAgICAgICAgICAgICAvLyBDb250cmFjdDogZXZlbnRzLmNyZWF0ZSgncnVuX3N0YXJ0ZWQnKSBtdXN0IGJlIGlkZW1wb3RlbnRcbiAgICAgICAgICAgICAgICAgIC8vIGZvciBydW5zIGFscmVhZHkgaW4gJ3J1bm5pbmcnIHN0YXR1cyAocmV0dXJuIHRoZSBydW5cbiAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgZXJyb3IpLCBub3QganVzdCBmb3IgcGVuZGluZyDihpIgcnVubmluZyB0cmFuc2l0aW9ucy5cbiAgICAgICAgICAgICAgICAgIC8vIE5ldHdvcmsvc2VydmVyIGVycm9ycyBwcm9wYWdhdGUgdG8gdGhlIHF1ZXVlIGhhbmRsZXIgZm9yIHJldHJ5LlxuICAgICAgICAgICAgICAgICAgLy8gV29ya2Zsb3dSdW50aW1lRXJyb3IgKGRhdGEgaW50ZWdyaXR5IGlzc3VlcykgYXJlIGZhdGFsIGFuZFxuICAgICAgICAgICAgICAgICAgLy8gcHJvZHVjZSBydW5fZmFpbGVkIHNpbmNlIHJldHJ5aW5nIHdvbid0IGZpeCB0aGVtLlxuICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fc3RhcnRlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIHNwZWMgdmVyc2lvbiBmcm9tIHRoZSBvcmlnaW5hbCBzdGFydCgpIGNhbGxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdoZW4gYXZhaWxhYmxlLCBzbyB0aGUgcmVzaWxpZW50IHN0YXJ0IHBhdGggY3JlYXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHJ1biB3aXRoIHRoZSBjb3JyZWN0IHZlcnNpb24gKG5vdCBhbHdheXMgY3VycmVudCkuXG4gICAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuSW5wdXQ/LnNwZWNWZXJzaW9uID8/IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGFzcyBydW4gaW5wdXQgZnJvbSBxdWV1ZSBzbyB0aGUgc2VydmVyIGNhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBydW4gaWYgcnVuX2NyZWF0ZWQgd2FzIG1pc3NlZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVpbnQ4QXJyYXkgdmFsdWVzIHN1cnZpdmUgdGhlIHF1ZXVlIG5hdGl2ZWx5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAoQ0JPUiBvbiB3b3JsZC12ZXJjZWwsIEpTT04gcmV2aXZlciBvbiB3b3JsZC1sb2NhbCkuXG4gICAgICAgICAgICAgICAgICAgICAgICAuLi4ocnVuSW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXQ6IHJ1bklucHV0LmlucHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IHJ1bklucHV0LmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lOiBydW5JbnB1dC53b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ6IHJ1bklucHV0LmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcmVzdWx0LnJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBXb3JrZmxvd1J1bnRpbWVFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBFdmVudCBjcmVhdGlvbiBmb3IgJ3J1bl9zdGFydGVkJyBkaWQgbm90IHJldHVybiB0aGUgcnVuIGVudGl0eSBmb3IgcnVuIFwiJHtydW5JZH1cImBcbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuID0gcmVzdWx0LnJ1bjtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgcmVzcG9uc2UgaW5jbHVkZXMgZXZlbnRzLCB1c2UgdGhlbSB0byBza2lwXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBpbml0aWFsIGV2ZW50cy5saXN0IGNhbGwgYW5kIHJlZHVjZSBUVEZCLlxuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmV2ZW50cyAmJiByZXN1bHQuZXZlbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICBwcmVsb2FkZWRFdmVudHMgPSByZXN1bHQuZXZlbnRzO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF3b3JrZmxvd1J1bi5zdGFydGVkQXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICBgV29ya2Zsb3cgcnVuIFwiJHtydW5JZH1cIiBoYXMgbm8gXCJzdGFydGVkQXRcIiB0aW1lc3RhbXBgXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFJ1biB3YXMgY29uY3VycmVudGx5IGNvbXBsZXRlZC9mYWlsZWQvY2FuY2VsbGVkXG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICBFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikgfHxcbiAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yOiBydW4gd2FzIGNvbmN1cnJlbnRseVxuICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbXBsZXRlZC9mYWlsZWQvY2FuY2VsbGVkIGR1cmluZyBzZXR1cC5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBSdW5FeHBpcmVkRXJyb3I6IHJ1biBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlLlxuICAgICAgICAgICAgICAgICAgICAgIC8vIEluIGJvdGggY2FzZXMsIHNraXAgcHJvY2Vzc2luZyB0aGlzIG1lc3NhZ2UuXG4gICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgJ1J1biBhbHJlYWR5IGZpbmlzaGVkIGR1cmluZyBzZXR1cCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCwgbWVzc2FnZTogZXJyLm1lc3NhZ2UgfVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIFdvcmtmbG93UnVudGltZUVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICdGYXRhbCBydW50aW1lIGVycm9yIGR1cmluZyB3b3JrZmxvdyBzZXR1cCcsXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBlcnJvcjogZXJyLm1lc3NhZ2UgfVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAncnVuX2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YWNrOiBlcnIuc3RhY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JDb2RlOiBSVU5fRVJST1JfQ09ERVMuUlVOVElNRV9FUlJPUixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgRW50aXR5Q29uZmxpY3RFcnJvci5pcyhmYWlsRXJyKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZmFpbEVycilcbiAgICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBmYWlsRXJyO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIHdvcmtmbG93U3RhcnRlZEF0ID0gK3dvcmtmbG93UnVuLnN0YXJ0ZWRBdDtcblxuICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1blN0YXR1cyh3b3JrZmxvd1J1bi5zdGF0dXMpLFxuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dTdGFydGVkQXQod29ya2Zsb3dTdGFydGVkQXQpLFxuICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgIGlmICh3b3JrZmxvd1J1bi5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBXb3JrZmxvdyBoYXMgYWxyZWFkeSBjb21wbGV0ZWQgb3IgZmFpbGVkLCBzbyB3ZSBjYW4gc2tpcCBpdFxuICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgJ1dvcmtmbG93IGFscmVhZHkgY29tcGxldGVkIG9yIGZhaWxlZCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiB3b3JrZmxvd1J1bi5zdGF0dXMsXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGZvciBgY2FuY2VsYCwgd2UgYWN0dWFsbHkgd2FudCB0byBwcm9wYWdhdGUgYSBXb3JrZmxvd0NhbmNlbGxlZCBldmVudFxuICAgICAgICAgICAgICAgICAgICAvLyBpbnNpZGUgdGhlIHdvcmtmbG93IGNvbnRleHQgc28gdGhlIHVzZXIgY2FuIGdyYWNlZnVsbHkgZXhpdC4gdGhpcyBpcyBTSUdURVJNXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGZ1cnRoZXJtb3JlLCB0aGVyZSBzaG91bGQgYmUgYSB0aW1lb3V0IG9yIGEgd2F5IHRvIGZvcmNlIGNhbmNlbCBTSUdLSUxMXG4gICAgICAgICAgICAgICAgICAgIC8vIHNvIHRoYXQgd2UgYWN0dWFsbHkgZXhpdCBoZXJlIHdpdGhvdXQgcmVwbGF5aW5nIHRoZSB3b3JrZmxvdyBhdCBhbGwsIGluIHRoZSBjYXNlXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSByZXBsYXlpbmcgdGhlIHdvcmtmbG93IGlzIGl0c2VsZiBmYWlsaW5nLlxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gTG9hZCBhbGwgZXZlbnRzIGludG8gbWVtb3J5IGJlZm9yZSBydW5uaW5nLlxuICAgICAgICAgICAgICAgICAgLy8gSWYgd2UgZ290IHByZS1sb2FkZWQgZXZlbnRzIGZyb20gdGhlIHJ1bl9zdGFydGVkIHJlc3BvbnNlLFxuICAgICAgICAgICAgICAgICAgLy8gc2tpcCB0aGUgZXZlbnRzLmxpc3Qgcm91bmQtdHJpcCB0byByZWR1Y2UgVFRGQi5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IGV2ZW50cyA9XG4gICAgICAgICAgICAgICAgICAgIHByZWxvYWRlZEV2ZW50cyA/P1xuICAgICAgICAgICAgICAgICAgICAoYXdhaXQgZ2V0QWxsV29ya2Zsb3dSdW5FdmVudHMod29ya2Zsb3dSdW4ucnVuSWQpKTtcblxuICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIGFueSBlbGFwc2VkIHdhaXRzIGFuZCBjcmVhdGUgd2FpdF9jb21wbGV0ZWQgZXZlbnRzXG4gICAgICAgICAgICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuXG4gICAgICAgICAgICAgICAgICAvLyBQcmUtY29tcHV0ZSBjb21wbGV0ZWQgY29ycmVsYXRpb24gSURzIGZvciBPKG4pIGxvb2t1cCBpbnN0ZWFkIG9mIE8obsKyKVxuICAgICAgICAgICAgICAgICAgY29uc3QgY29tcGxldGVkV2FpdElkcyA9IG5ldyBTZXQoXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50c1xuICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGUpID0+IGUuZXZlbnRUeXBlID09PSAnd2FpdF9jb21wbGV0ZWQnKVxuICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKGUpID0+IGUuY29ycmVsYXRpb25JZClcbiAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgIC8vIENvbGxlY3QgYWxsIHdhaXRzIHRoYXQgbmVlZCBjb21wbGV0aW9uXG4gICAgICAgICAgICAgICAgICBjb25zdCB3YWl0c1RvQ29tcGxldGUgPSBldmVudHNcbiAgICAgICAgICAgICAgICAgICAgLmZpbHRlcihcbiAgICAgICAgICAgICAgICAgICAgICAoZSk6IGUgaXMgdHlwZW9mIGUgJiB7IGNvcnJlbGF0aW9uSWQ6IHN0cmluZyB9ID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBlLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY3JlYXRlZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIGUuY29ycmVsYXRpb25JZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAhY29tcGxldGVkV2FpdElkcy5oYXMoZS5jb3JyZWxhdGlvbklkKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgbm93ID49IChlLmV2ZW50RGF0YS5yZXN1bWVBdCBhcyBEYXRlKS5nZXRUaW1lKClcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAubWFwKChlKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3dhaXRfY29tcGxldGVkJyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogZS5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICB9KSk7XG5cbiAgICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBhbGwgd2FpdF9jb21wbGV0ZWQgZXZlbnRzXG4gICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHdhaXRFdmVudCBvZiB3YWl0c1RvQ29tcGxldGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB3YWl0RXZlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIC8vIEFkZCB0aGUgZXZlbnQgdG8gdGhlIGV2ZW50cyBhcnJheSBzbyB0aGUgd29ya2Zsb3cgY2FuIHNlZSBpdFxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50cy5wdXNoKHJlc3VsdC5ldmVudCEpO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oJ1dhaXQgYWxyZWFkeSBjb21wbGV0ZWQsIHNraXBwaW5nJywge1xuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogd2FpdEV2ZW50LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gUmVzb2x2ZSB0aGUgZW5jcnlwdGlvbiBrZXkgZm9yIHRoaXMgcnVuJ3MgZGVwbG95bWVudFxuICAgICAgICAgICAgICAgICAgY29uc3QgcmF3S2V5ID1cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHdvcmtmbG93UnVuKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGVuY3J5cHRpb25LZXkgPSByYXdLZXlcbiAgICAgICAgICAgICAgICAgICAgPyBhd2FpdCBpbXBvcnRLZXkocmF3S2V5KVxuICAgICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZDtcblxuICAgICAgICAgICAgICAgICAgLy8gLS0tIFVzZXIgY29kZSBleGVjdXRpb24gLS0tXG4gICAgICAgICAgICAgICAgICAvLyBPbmx5IGVycm9ycyBmcm9tIHJ1bldvcmtmbG93KCkgKHVzZXIgd29ya2Zsb3cgY29kZSkgc2hvdWxkXG4gICAgICAgICAgICAgICAgICAvLyBwcm9kdWNlIHJ1bl9mYWlsZWQuIEluZnJhc3RydWN0dXJlIGVycm9ycyAobmV0d29yaywgc2VydmVyKVxuICAgICAgICAgICAgICAgICAgLy8gbXVzdCBwcm9wYWdhdGUgdG8gdGhlIHF1ZXVlIGhhbmRsZXIgZm9yIGF1dG9tYXRpYyByZXRyeS5cbiAgICAgICAgICAgICAgICAgIGxldCB3b3JrZmxvd1Jlc3VsdDogdW5rbm93bjtcbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UmVzdWx0ID0gYXdhaXQgdHJhY2UoXG4gICAgICAgICAgICAgICAgICAgICAgJ3dvcmtmbG93LnJlcGxheScsXG4gICAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgICAgYXN5bmMgKHJlcGxheVNwYW4pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheVNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFdmVudHNDb3VudChldmVudHMubGVuZ3RoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHJ1bldvcmtmbG93KFxuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd0NvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVuY3J5cHRpb25LZXlcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFdvcmtmbG93U3VzcGVuc2lvbiBpcyBub3JtYWwgY29udHJvbCBmbG93IOKAlCBub3QgYW4gZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgaWYgKFdvcmtmbG93U3VzcGVuc2lvbi5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3VzcGVuc2lvbk1lc3NhZ2UgPSBidWlsZFdvcmtmbG93U3VzcGVuc2lvbk1lc3NhZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVyci5zdGVwQ291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIuaG9va0NvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyLndhaXRDb3VudFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHN1c3BlbnNpb25NZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKHN1c3BlbnNpb25NZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVTdXNwZW5zaW9uKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb246IGVycixcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgcnVuOiB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4sXG4gICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LnRpbWVvdXRTZWNvbmRzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7IHRpbWVvdXRTZWNvbmRzOiByZXN1bHQudGltZW91dFNlY29uZHMgfTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBTdXNwZW5zaW9uIGhhbmRsZWQsIG5vIGZ1cnRoZXIgd29yayBuZWVkZWRcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgdXNlciBjb2RlIGVycm9yIG9yIGEgV29ya2Zsb3dSdW50aW1lRXJyb3JcbiAgICAgICAgICAgICAgICAgICAgLy8gKGUuZy4sIGNvcnJ1cHRlZCBldmVudCBsb2cpLiBGYWlsIHRoZSB3b3JrZmxvdyBydW4uXG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVjb3JkIGV4Y2VwdGlvbiBmb3IgT1RFTCBlcnJvciB0cmFja2luZ1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICBzcGFuPy5yZWNvcmRFeGNlcHRpb24/LihlcnIpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZEVycm9yID0gYXdhaXQgbm9ybWFsaXplVW5rbm93bkVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yTmFtZSA9IG5vcm1hbGl6ZWRFcnJvci5uYW1lIHx8IGdldEVycm9yTmFtZShlcnIpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBub3JtYWxpemVkRXJyb3IubWVzc2FnZTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yU3RhY2sgPVxuICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWRFcnJvci5zdGFjayB8fCBnZXRFcnJvclN0YWNrKGVycik7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVtYXAgZXJyb3Igc3RhY2sgdXNpbmcgc291cmNlIG1hcHMgdG8gc2hvdyBvcmlnaW5hbCBzb3VyY2UgbG9jYXRpb25zXG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvclN0YWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFyc2VkTmFtZSA9IHBhcnNlV29ya2Zsb3dOYW1lKHdvcmtmbG93TmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgZmlsZW5hbWUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2VkTmFtZT8ubW9kdWxlU3BlY2lmaWVyIHx8IHdvcmtmbG93TmFtZTtcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvclN0YWNrID0gcmVtYXBFcnJvclN0YWNrKFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JTdGFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dDb2RlXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIENsYXNzaWZ5IHRoZSBlcnJvcjogV29ya2Zsb3dSdW50aW1lRXJyb3IgaW5kaWNhdGVzIGFuXG4gICAgICAgICAgICAgICAgICAgIC8vIGludGVybmFsIGlzc3VlIChjb3JydXB0ZWQgZXZlbnQgbG9nLCBtaXNzaW5nIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICAvLyBldmVyeXRoaW5nIGVsc2UgaXMgYSB1c2VyIGNvZGUgZXJyb3IuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yQ29kZSA9IGNsYXNzaWZ5UnVuRXJyb3IoZXJyKTtcblxuICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmVycm9yKCdFcnJvciB3aGlsZSBydW5uaW5nIHdvcmtmbG93Jywge1xuICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICBlcnJvck5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgZXJyb3JTdGFjayxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gRmFpbCB0aGUgd29ya2Zsb3cgcnVuIHZpYSBldmVudCAoZXZlbnQtc291cmNlZCBhcmNoaXRlY3R1cmUpXG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcjoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyb3JNZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhY2s6IGVycm9yU3RhY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICBFbnRpdHlDb25mbGljdEVycm9yLmlzKGZhaWxFcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZmFpbEVycilcbiAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGZhaWxpbmcgd29ya2Zsb3cgcnVuLCBidXQgcnVuIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBmYWlsRXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXJyb3JDb2RlKGVycm9yQ29kZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0Vycm9yTmFtZShlcnJvck5hbWUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvck1lc3NhZ2UoZXJyb3JNZXNzYWdlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLkVycm9yVHlwZShlcnJvck5hbWUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGZhaWxFcnI7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvckNvZGUoZXJyb3JDb2RlKSxcbiAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvck5hbWUoZXJyb3JOYW1lKSxcbiAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvck1lc3NhZ2UoZXJyb3JNZXNzYWdlKSxcbiAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuRXJyb3JUeXBlKGVycm9yTmFtZSksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIC8vIC0tLSBJbmZyYXN0cnVjdHVyZTogY29tcGxldGUgdGhlIHJ1biAtLS1cbiAgICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgb3V0c2lkZSB0aGUgdXNlci1jb2RlIHRyeS9jYXRjaCBzbyB0aGF0IGZhaWx1cmVzXG4gICAgICAgICAgICAgICAgICAvLyBoZXJlIChlLmcuLCBuZXR3b3JrIGVycm9ycykgcHJvcGFnYXRlIHRvIHRoZSBxdWV1ZSBoYW5kbGVyLlxuICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdydW5fY29tcGxldGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRwdXQ6IHdvcmtmbG93UmVzdWx0LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgIHsgcmVxdWVzdElkIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgUnVuRXhwaXJlZEVycm9yLmlzKGVycilcbiAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGNvbXBsZXRpbmcgd29ya2Zsb3cgcnVuLCBidXQgcnVuIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1blN0YXR1cygnY29tcGxldGVkJyksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0V2ZW50c0NvdW50KGV2ZW50cy5sZW5ndGgpLFxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApOyAvLyBFbmQgdHJhY2VcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApOyAvLyBFbmQgd2l0aFdvcmtmbG93QmFnZ2FnZVxuICAgICAgICB9KS5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgICBpZiAocmVwbGF5VGltZW91dCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHJlcGxheVRpbWVvdXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7IC8vIEVuZCB3aXRoVHJhY2VDb250ZXh0XG4gICAgICB9XG4gICAgKTtcblxuICBsZXQgY2FjaGVkSGFuZGxlcjogKChyZXE6IFJlcXVlc3QpID0+IFByb21pc2U8UmVzcG9uc2U+KSB8IHVuZGVmaW5lZDtcbiAgcmV0dXJuIHdpdGhIZWFsdGhDaGVjayhhc3luYyAocmVxKSA9PiB7XG4gICAgaWYgKCFjYWNoZWRIYW5kbGVyKSB7XG4gICAgICBjYWNoZWRIYW5kbGVyID0gaGFuZGxlcihhd2FpdCBnZXRXb3JsZEhhbmRsZXJzKCkpO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGVkSGFuZGxlcihyZXEpO1xuICB9KTtcbn1cblxuLy8gdGhpcyBpcyBhIG5vLW9wIHBsYWNlaG9sZGVyIGFzIHRoZSBjbGllbnQgaXNcbi8vIGV4cGVjdGluZyB0aGlzIHRvIGJlIHByZXNlbnQgYnV0IHdlIGFyZW4ndCBhY3R1YWxseSB1c2luZyBpdFxuZXhwb3J0IGZ1bmN0aW9uIHJ1blN0ZXAoKSB7fVxuIl19
|
|
3260
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTSxNQUFNLG9CQUFvQixDQUFDO0FBQ3hDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixtQkFBbUIsRUFDbkIsVUFBVSxFQUNWLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsdUJBQXVCLEVBQ3ZCLHFCQUFxQixFQUNyQixlQUFlLEVBRWYsZUFBZSxFQUNmLG9CQUFvQixHQUNyQixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFBRSxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM1RCxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLG1CQUFtQixHQUNwQixNQUFNLDRCQUE0QixDQUFDO0FBQ3BDLE9BQU8sRUFLTCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLHNCQUFzQixFQUN0QixxQkFBcUIsRUFFckIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixpQ0FBaUMsRUFFakMsMkJBQTJCLEdBRzVCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BCLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDbEMsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixxQkFBcUIsRUFDckIsb0JBQW9CLEdBQ3JCLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3BELE9BQU8sRUFBZ0Msa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDL0UsT0FBTyxFQUFlLGFBQWEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQy9D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Q0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSAnbm9kZTphc3NlcnQvc3RyaWN0JztcbmltcG9ydCB7IHR5cGVzIH0gZnJvbSAnbm9kZTp1dGlsJztcbmltcG9ydCB7XG4gIENvcnJ1cHRlZEV2ZW50TG9nRXJyb3IsXG4gIEVudGl0eUNvbmZsaWN0RXJyb3IsXG4gIEZhdGFsRXJyb3IsXG4gIEhvb2tOb3RGb3VuZEVycm9yLFxuICBNYXhFdmVudHNFeGNlZWRlZEVycm9yLFxuICBQcmVjb25kaXRpb25GYWlsZWRFcnJvcixcbiAgUmVwbGF5RGl2ZXJnZW5jZUVycm9yLFxuICBSVU5fRVJST1JfQ09ERVMsXG4gIHR5cGUgUnVuRXJyb3JDb2RlLFxuICBSdW5FeHBpcmVkRXJyb3IsXG4gIFdvcmtmbG93UnVudGltZUVycm9yLFxufSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB7IG9uY2UsIHNldFdvcmtmbG93QmFzZVBhdGggfSBmcm9tICdAd29ya2Zsb3cvdXRpbHMnO1xuaW1wb3J0IHtcbiAgcGFyc2VXb3JrZmxvd05hbWUsXG4gIHdvcmtmbG93RGlzcGxheU5hbWUsXG59IGZyb20gJ0B3b3JrZmxvdy91dGlscy9wYXJzZS1uYW1lJztcbmltcG9ydCB7XG4gIHR5cGUgQ3JlYXRlRXZlbnRQYXJhbXMsXG4gIHR5cGUgQ3JlYXRlRXZlbnRSZXF1ZXN0LFxuICB0eXBlIEV2ZW50LFxuICB0eXBlIEV2ZW50UmVzdWx0LFxuICBnZXRRdWV1ZVRvcGljUHJlZml4LFxuICBpc0xlZ2FjeVNwZWNWZXJzaW9uLFxuICBpc1Rlcm1pbmFsUnVuRXZlbnRUeXBlLFxuICBST09UX1JVTl9JRF9BVFRSSUJVVEUsXG4gIHR5cGUgUnVuSW5wdXQsXG4gIHJlc29sdmVRdWV1ZU5hbWVzcGFjZSxcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTixcbiAgdHlwZSBXb3JrZmxvd0ludm9rZVBheWxvYWQsXG4gIFdvcmtmbG93SW52b2tlUGF5bG9hZFNjaGVtYSxcbiAgdHlwZSBXb3JrZmxvd1J1bixcbiAgdHlwZSBXb3JsZCxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCBtcyBmcm9tICdtcyc7XG5pbXBvcnQgeyBkZWNvZGVUaW1lIH0gZnJvbSAndWxpZCc7XG5pbXBvcnQge1xuICBjbGFzc2lmeVJ1bkVycm9yLFxuICBpc1JldHJ5YWJsZVdvcmxkRXJyb3IsXG4gIGlzV29ybGRDb250cmFjdEVycm9yLFxufSBmcm9tICcuL2NsYXNzaWZ5LWVycm9yLmpzJztcbmltcG9ydCB7IGRlc2NyaWJlRXJyb3IgfSBmcm9tICcuL2Rlc2NyaWJlLWVycm9yLmpzJztcbmltcG9ydCB7IHR5cGUgU3RlcEludm9jYXRpb25RdWV1ZUl0ZW0sIFdvcmtmbG93U3VzcGVuc2lvbiB9IGZyb20gJy4vZ2xvYmFsLmpzJztcbmltcG9ydCB7IHR5cGUgTG9nZ2VyLCBydW50aW1lTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZ2V0U3RlcEZ1bmN0aW9uIH0gZnJvbSAnLi9wcml2YXRlLmpzJztcbmltcG9ydCB7IFJlcGxheVBheWxvYWRDYWNoZSB9IGZyb20gJy4vcmVwbGF5LXBheWxvYWQtY2FjaGUuanMnO1xuaW1wb3J0IHsgQ09NUFVURV9JTlNUQU5DRV9JRCB9IGZyb20gJy4vcnVudGltZS9jb21wdXRlLWluc3RhbmNlLmpzJztcbmltcG9ydCB7XG4gIGdldE1heEV2ZW50c092ZXJyaWRlLFxuICBnZXRNYXhRdWV1ZURlbGl2ZXJpZXMsXG4gIGdldFByZWNvbmRpdGlvbk1heEluUHJvY2Vzc1Jlc3RhcnRzLFxuICBnZXRQcmVjb25kaXRpb25NYXhSZWludm9jYXRpb25zLFxuICBnZXRQcmVjb25kaXRpb25SZWludm9rZURlbGF5U2Vjb25kcyxcbiAgZ2V0UmVwbGF5RGl2ZXJnZW5jZU1heFJldHJpZXMsXG4gIGlzSW5saW5lT3duZXJzaGlwRW5hYmxlZCxcbiAgaXNUdXJib0VuYWJsZWQsXG4gIGlzVm1SZXRlbnRpb25FbmFibGVkLFxufSBmcm9tICcuL3J1bnRpbWUvY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IGNvdW50U3RlcFN0YXJ0ZWRFdmVudHMgfSBmcm9tICcuL3J1bnRpbWUvY291bnQtc3RlcC1zdGFydGVkLWV2ZW50cy5qcyc7XG5pbXBvcnQge1xuICB0eXBlIERlcGxveW1lbnRBZmZpbml0eU91dGNvbWUsXG4gIGd1YXJkRGVwbG95bWVudEFmZmluaXR5LFxuICB0eXBlIFJlZW5xdWV1ZUFyZ3MsXG59IGZyb20gJy4vcnVudGltZS9kZXBsb3ltZW50LWd1YXJkLmpzJztcbmltcG9ydCB7XG4gIGFwcGVuZFVuaXF1ZUV2ZW50cyxcbiAgZ2V0UXVldWVPdmVyaGVhZCxcbiAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUsXG4gIGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZSxcbiAgaW5zZXJ0RXZlbnRCeUV2ZW50SWQsXG4gIGlzUHJlY29uZGl0aW9uR3VhcmRFbmFibGVkLFxuICBpc1Nsb3RHYXBDaGVja0VuYWJsZWQsXG4gIHR5cGUgTG9hZGVkRXZlbnRMb2csXG4gIGxvYWRXb3JrZmxvd1J1bkV2ZW50cyxcbiAgbWVtb2l6ZUVuY3J5cHRpb25LZXksXG4gIG1lcmdlUmVwb3J0ZWRFdmVudHMsXG4gIHBhcnNlSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBwcmVjb25kaXRpb25FdmVudERlbHRhLFxuICBwcmVjb25kaXRpb25TbmFwc2hvdFBhcmFtcyxcbiAgcXVldWVNZXNzYWdlLFxuICBzZXR0bGVFdmVudFNsb3RHYXAsXG4gIHdpdGhIZWFsdGhDaGVjayxcbn0gZnJvbSAnLi9ydW50aW1lL2hlbHBlcnMuanMnO1xuaW1wb3J0IHtcbiAgaGFuZGxlUmVwbGF5QnVkZ2V0RXhoYXVzdGVkLFxuICBSZXBsYXlCdWRnZXQsXG59IGZyb20gJy4vcnVudGltZS9yZXBsYXktYnVkZ2V0LmpzJztcbmltcG9ydCB7IFJlcGxheVJlY292ZXJ5UmVwb3J0ZXIgfSBmcm9tICcuL3J1bnRpbWUvcmVwbGF5LXJlY292ZXJ5LXJlcG9ydGVyLmpzJztcbmltcG9ydCB7IHJ1bklkQ3JlYXRlZEF0IH0gZnJvbSAnLi9ydW50aW1lL3J1bi1pZC10aW1lLmpzJztcbmltcG9ydCB7XG4gIERFRkFVTFRfU1RFUF9NQVhfUkVUUklFUyxcbiAgZXhlY3V0ZVN0ZXAsXG59IGZyb20gJy4vcnVudGltZS9zdGVwLWV4ZWN1dG9yLmpzJztcbmltcG9ydCB7IGNvbXB1dGVTdGVwTGF0ZW5jeVRyYWNraW5nIH0gZnJvbSAnLi9ydW50aW1lL3N0ZXAtbGF0ZW5jeS5qcyc7XG5pbXBvcnQge1xuICBiYWNrc3RvcElkZW1wb3RlbmN5S2V5LFxuICBoYXNQZW5kaW5nU3RlcE93bmVkQnlNZXNzYWdlLFxuICBpc1N0ZXBPd25lcnNoaXBBY3RpdmUsXG4gIHN0ZXBMZWFzZVJlbWFpbmluZ1NlY29uZHMsXG59IGZyb20gJy4vcnVudGltZS9zdGVwLW93bmVyc2hpcC5qcyc7XG5pbXBvcnQgeyBydW5TdGVwU2luZ2xlRmxpZ2h0IH0gZnJvbSAnLi9ydW50aW1lL3N0ZXAtc2luZ2xlLWZsaWdodC5qcyc7XG5pbXBvcnQgeyBoYW5kbGVTdXNwZW5zaW9uIH0gZnJvbSAnLi9ydW50aW1lL3N1c3BlbnNpb24taGFuZGxlci5qcyc7XG5pbXBvcnQgeyB1c2VRdWlja0pTVm0gfSBmcm9tICcuL3J1bnRpbWUvdm0tbW9kZS5qcyc7XG5pbXBvcnQgeyBnZXRXYWl0Q29udGludWF0aW9uRGlzcGF0Y2ggfSBmcm9tICcuL3J1bnRpbWUvd2FpdC1jb250aW51YXRpb24uanMnO1xuaW1wb3J0IHtcbiAgZ2V0V29ybGQsXG4gIGdldFdvcmxkSGFuZGxlcnMsXG4gIHR5cGUgV29ybGRIYW5kbGVycyxcbn0gZnJvbSAnLi9ydW50aW1lL3dvcmxkLmpzJztcbmltcG9ydCB7IGRlaHlkcmF0ZVJ1bkVycm9yIH0gZnJvbSAnLi9zZXJpYWxpemF0aW9uLmpzJztcbmltcG9ydCB7IHJlbWFwRXJyb3JTdGFjayB9IGZyb20gJy4vc291cmNlLW1hcC5qcyc7XG5pbXBvcnQgKiBhcyBBdHRyaWJ1dGUgZnJvbSAnLi90ZWxlbWV0cnkvc2VtYW50aWMtY29udmVudGlvbnMuanMnO1xuaW1wb3J0IHtcbiAgYnVpbGRJbnZvY2F0aW9uU3BhbkxpbmtzLFxuICBnZXROZXh0VHJhY2VDYXJyaWVyLFxuICBnZXRTcGFuS2luZCxcbiAgZ2V0V29ya2Zsb3dUcmFjZU1vZGUsXG4gIGlzVXNhYmxlVHJhY2VDYXJyaWVyLFxuICB0cmFjZSxcbiAgd2l0aFRyYWNlQ29udGV4dCxcbiAgd2l0aFdvcmtmbG93QmFnZ2FnZSxcbn0gZnJvbSAnLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHsgZ2V0RXJyb3JOYW1lLCBnZXRFcnJvclN0YWNrLCBub3JtYWxpemVVbmtub3duRXJyb3IgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IGJ1aWxkV29ya2Zsb3dTdXNwZW5zaW9uTWVzc2FnZSB9IGZyb20gJy4vdXRpbC5qcyc7XG5pbXBvcnQge1xuICByZXBsYXlXb3JrZmxvdyxcbiAgcmVzdW1lV29ya2Zsb3csXG4gIHR5cGUgV29ya2Zsb3dSZXN1bWVSZXN1bHQsXG4gIHR5cGUgV29ya2Zsb3dTZXNzaW9uLFxufSBmcm9tICcuL3dvcmtmbG93LmpzJztcblxuZXhwb3J0IHR5cGUgeyBFdmVudCwgV29ya2Zsb3dSdW4gfTtcbmV4cG9ydCB7IFdvcmtmbG93U3VzcGVuc2lvbiB9IGZyb20gJy4vZ2xvYmFsLmpzJztcbmV4cG9ydCB7XG4gIHR5cGUgSGVhbHRoQ2hlY2tPcHRpb25zLFxuICB0eXBlIEhlYWx0aENoZWNrUmVzdWx0LFxuICBoZWFsdGhDaGVjayxcbn0gZnJvbSAnLi9ydW50aW1lL2hlbHBlcnMuanMnO1xuZXhwb3J0IHtcbiAgZ2V0SG9va0J5VG9rZW4sXG4gIHR5cGUgUmVzdW1lZEhvb2ssXG4gIHJlc3VtZUhvb2ssXG4gIHJlc3VtZVdlYmhvb2ssXG59IGZyb20gJy4vcnVudGltZS9yZXN1bWUtaG9vay5qcyc7XG5leHBvcnQge1xuICBnZXRSdW4sXG4gIFJ1bixcbiAgdHlwZSBXb3JrZmxvd1JlYWRhYmxlU3RyZWFtLFxuICB0eXBlIFdvcmtmbG93UmVhZGFibGVTdHJlYW1PcHRpb25zLFxufSBmcm9tICcuL3J1bnRpbWUvcnVuLmpzJztcbmV4cG9ydCB7XG4gIHR5cGUgQ2FuY2VsUnVuT3B0aW9ucyxcbiAgY2FuY2VsUnVuLFxuICBjYW5jZWxSdW5zLFxuICBsaXN0U3RyZWFtcyxcbiAgdHlwZSBSZWFkU3RyZWFtT3B0aW9ucyxcbiAgdHlwZSBSZWNyZWF0ZVJ1bk9wdGlvbnMsXG4gIHR5cGUgUmVlbnF1ZXVlUnVuT3B0aW9ucyxcbiAgcmVhZFN0cmVhbSxcbiAgcmVjcmVhdGVSdW5Gcm9tRXhpc3RpbmcsXG4gIHJlZW5xdWV1ZVJ1bixcbiAgdHlwZSBTdG9wU2xlZXBPcHRpb25zLFxuICB0eXBlIFN0b3BTbGVlcFJlc3VsdCxcbiAgd2FrZVVwUnVuLFxufSBmcm9tICcuL3J1bnRpbWUvcnVucy5qcyc7XG5leHBvcnQge1xuICB0eXBlIFN0YXJ0T3B0aW9ucyxcbiAgdHlwZSBTdGFydE9wdGlvbnNCYXNlLFxuICB0eXBlIFN0YXJ0T3B0aW9uc1dpdGhEZXBsb3ltZW50SWQsXG4gIHR5cGUgU3RhcnRPcHRpb25zV2l0aG91dERlcGxveW1lbnRJZCxcbiAgc3RhcnQsXG59IGZyb20gJy4vcnVudGltZS9zdGFydC5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVXb3JsZCxcbiAgY3JlYXRlV29ybGRGcm9tTW9kdWxlLFxuICBnZXRXb3JsZCxcbiAgZ2V0V29ybGRIYW5kbGVycyxcbiAgc2V0V29ybGQsXG4gIHR5cGUgV29ybGRGYWN0b3J5TW9kdWxlLFxufSBmcm9tICcuL3J1bnRpbWUvd29ybGQuanMnO1xuXG4vKipcbiAqIEFwcGx5IHRoZSBvcHRpb25hbCBjbGllbnQtc2lkZSBldmVudC1saW1pdCBvdmVycmlkZS5cbiAqIGBXT1JLRkxPV19NQVhfRVZFTlRTX09WRVJSSURFYCwgd2hlbiBzZXQgdG8gYSBwb3NpdGl2ZSBpbnRlZ2VyLCBjbGFtcHMgdGhlXG4gKiBzZXJ2ZXItc3VwcGxpZWQgcGVyLXJ1biBldmVudCBjZWlsaW5nIHRvIGEgc21hbGxlciB2YWx1ZSBzbyBlbmZvcmNlbWVudCBjYW5cbiAqIGJlIGV4ZXJjaXNlZCB3aXRob3V0IGEgc2VydmVyLXNpZGUgY2hhbmdlLiBDbGFtcC1kb3duIG9ubHk6IGl0IG5ldmVyIHJhaXNlc1xuICogdGhlIHNlcnZlcidzIGxpbWl0LCBhbmQgaXQgdGFrZXMgZWZmZWN0IGV2ZW4gd2hlbiB0aGUgc2VydmVyIHJldHVybnMgbm9uZS5cbiAqIFVuc2V0IOKHkiBzZXJ2ZXIgdmFsdWUgcGFzc2VzIHRocm91Z2ggdW5jaGFuZ2VkLlxuICovXG5mdW5jdGlvbiBjbGFtcE1heEV2ZW50cyhzZXJ2ZXJWYWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgb3ZlcnJpZGUgPSBnZXRNYXhFdmVudHNPdmVycmlkZSgpO1xuICBpZiAob3ZlcnJpZGUgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHNlcnZlclZhbHVlO1xuICByZXR1cm4gc2VydmVyVmFsdWUgPT09IHVuZGVmaW5lZCA/IG92ZXJyaWRlIDogTWF0aC5taW4oc2VydmVyVmFsdWUsIG92ZXJyaWRlKTtcbn1cblxuLyoqXG4gKiBSZWZ1c2UgYSBxdWV1ZSBkZWxpdmVyeSB3aG9zZSBydW4gd2FzIGNyZWF0ZWQgaW4gYSBkaWZmZXJlbnQgZW52aXJvbm1lbnQgdGhhblxuICogdGhpcyBkZXBsb3ltZW50IHJ1bnMgaW4uXG4gKlxuICogYHN0YXJ0KClgIHBlcmZvcm1zIHR3byB3cml0ZXMgdGhhdCBtdXN0IGxhbmQgaW4gdGhlIHNhbWUgdGVuYW50OiB0aGVcbiAqIGBydW5fY3JlYXRlZGAgZXZlbnQsIGF0dHJpYnV0ZWQgdG8gd2hhdGV2ZXIgZW52aXJvbm1lbnQgdGhlICpjYWxsZXIqXG4gKiBhdXRoZW50aWNhdGVzIGFzLCBhbmQgdGhlIHF1ZXVlIG1lc3NhZ2UsIHBpbm5lZCB0byBhICpkZXBsb3ltZW50Ki4gQVxuICogbWlzY29uZmlndXJlZCBjYWxsZXIgY2FuIHNwbGl0IHRoZW0g4oCUIHdyaXRpbmcgdGhlIHJ1biB0byBvbmUgZW52aXJvbm1lbnRcbiAqIHdoaWxlIGFkZHJlc3NpbmcgdGhlIG1lc3NhZ2UgdG8gYSBkZXBsb3ltZW50IGluIGFub3RoZXIuIFRoZSBjb25zdW1lciB0aGVuXG4gKiBmaW5kcyBubyBydW4gdW5kZXIgaXRzIG93biB0ZW5hbnQgYW5kIHRoZSBiYWNrZW5kJ3MgcmVzaWxpZW50IHN0YXJ0XG4gKiAoYHJ1bl9zdGFydGVkYCBjcmVhdGVzIHRoZSBydW4gd2hlbiBgcnVuX2NyZWF0ZWRgIHdhcyBuZXZlciBzZWVuKSBtaW50cyBhXG4gKiBTRUNPTkQgY29weSBvZiB0aGUgc2FtZSBydW4gaWQgaW4gdGhpcyBlbnZpcm9ubWVudC4gQm90aCBjb3BpZXMgYXJlIHJlYWw6IHRoZVxuICogY3JlYXRvcidzIHNpdHMgcGVuZGluZyBmb3JldmVyLCB0aGlzIG9uZSBleGVjdXRlcywgYW5kIGV2ZXJ5IHN1YnNlcXVlbnRcbiAqIGNyb3NzLXRlbmFudCBxdWV1ZSBhY2sgZmFpbHMgdG8gZmluZCBpdHMgbWVzc2FnZS5cbiAqXG4gKiBOb3RoaW5nIGV4dGVybmFsIGlzIG5lZWRlZCB0byBjYXRjaCB0aGlzOiB0aGUgY3JlYXRvcidzIGVudmlyb25tZW50IHJpZGVzIHRoZVxuICogbWVzc2FnZSBpbiBgcnVuSW5wdXQuZW52aXJvbm1lbnRgIGFuZCB0aGlzIHByb2Nlc3MgYWxyZWFkeSBrbm93cyBpdHMgb3duLiBTb1xuICogY29tcGFyZSB0aGVtIGFuZCBzdG9wIEJFRk9SRSBgcnVuX3N0YXJ0ZWRgIOKAlCB0aGUgd3JpdGUgdGhhdCB3b3VsZCBjcmVhdGUgdGhlXG4gKiBmb3JrLiBSZWZ1c2luZyBhZnRlciBpdCB3b3VsZCBiZSB0b28gbGF0ZS5cbiAqXG4gKiBSZXR1cm5zIGB0cnVlYCB3aGVuIHRoZSBjYWxsZXIgbXVzdCBhYmFuZG9uIHRoZSBkZWxpdmVyeS4gU2tpcHBlZCB3aGVuZXZlclxuICogZWl0aGVyIHNpZGUgaXMgdW5rbm93biwgd2hpY2gga2VlcHMgZXZlcnkgZXhpc3Rpbmcgc2V0dXAgb24gaXRzIGN1cnJlbnRcbiAqIGJlaGF2aW9yOiB3b3JsZHMgd2l0aCBubyBlbnZpcm9ubWVudCBkaW1lbnNpb24gKGB3b3JsZC1sb2NhbGAsXG4gKiBgd29ybGQtcG9zdGdyZXNgKSBkb24ndCBpbXBsZW1lbnQgYGdldEVudmlyb25tZW50YCwgYW5kIHJ1bnMgc3RhcnRlZCBieSBhblxuICogb2xkZXIgU0RLIGNhcnJ5IG5vIGBlbnZpcm9ubWVudGAgZmllbGQuXG4gKi9cbmZ1bmN0aW9uIHJlZnVzZUNyb3NzRW52aXJvbm1lbnREZWxpdmVyeSh7XG4gIHdvcmxkLFxuICBydW5JbnB1dCxcbiAgcnVuSWQsXG4gIHJ1bkxvZ2dlcixcbn06IHtcbiAgd29ybGQ6IFdvcmxkO1xuICBydW5JbnB1dDogUnVuSW5wdXQgfCB1bmRlZmluZWQ7XG4gIHJ1bklkOiBzdHJpbmc7XG4gIHJ1bkxvZ2dlcjogTG9nZ2VyO1xufSk6IGJvb2xlYW4ge1xuICBjb25zdCBjcmVhdG9yRW52aXJvbm1lbnQgPSBydW5JbnB1dD8uZW52aXJvbm1lbnQ7XG4gIGlmICghY3JlYXRvckVudmlyb25tZW50KSByZXR1cm4gZmFsc2U7XG5cbiAgY29uc3QgY3VycmVudEVudmlyb25tZW50ID0gd29ybGQuZ2V0RW52aXJvbm1lbnQ/LigpO1xuICBpZiAoIWN1cnJlbnRFbnZpcm9ubWVudCB8fCBjdXJyZW50RW52aXJvbm1lbnQgPT09IGNyZWF0b3JFbnZpcm9ubWVudCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHJ1bkxvZ2dlci5lcnJvcihcbiAgICBgUmVmdXNpbmcgdG8gcnVuIHRoaXMgd29ya2Zsb3c6IGl0IHdhcyBjcmVhdGVkIGluIHRoZSBcIiR7Y3JlYXRvckVudmlyb25tZW50fVwiIGAgK1xuICAgICAgYGVudmlyb25tZW50IGJ1dCB0aGlzIGRlcGxveW1lbnQgcnVucyBpbiBcIiR7Y3VycmVudEVudmlyb25tZW50fVwiLiBgICtcbiAgICAgICdFeGVjdXRpbmcgaXQgaGVyZSB3b3VsZCBjcmVhdGUgYSBzZWNvbmQgY29weSBvZiB0aGUgc2FtZSBydW4gaWQgaW4gJyArXG4gICAgICAnYm90aCBlbnZpcm9ubWVudHMg4oCUIG9uZSBwZW5kaW5nIGZvcmV2ZXIsIG9uZSBydW5uaW5nIOKAlCBzbyB0aGUgcXVldWUgJyArXG4gICAgICAnbWVzc2FnZSBpcyBiZWluZyBkaXNjYXJkZWQgd2l0aG91dCBleGVjdXRpbmcgYW5kIHdpdGhvdXQgcmV0cnlpbmcuICcgK1xuICAgICAgJ1RoZSBjbGllbnQgdGhhdCBjYWxsZWQgc3RhcnQoKSB3cm90ZSB0aGUgcnVuIHRvIGl0cyBvd24gZW52aXJvbm1lbnQgJyArXG4gICAgICAnYnV0IGFkZHJlc3NlZCB0aGUgcXVldWUgbWVzc2FnZSB0byBhIGRlcGxveW1lbnQgaW4gYW5vdGhlciBvbmUuIENoZWNrICcgK1xuICAgICAgJ3RoYXQgdGhlIGVudmlyb25tZW50IHRoYXQgY2xpZW50IGF1dGhlbnRpY2F0ZXMgYXMgKFdPUktGTE9XX1ZFUkNFTF9FTlYgJyArXG4gICAgICBcImZvciBDTEkgYW5kIENJIGNsaWVudHMsIG9yIHRoZSBPSURDIHRva2VuJ3MgZW52aXJvbm1lbnQgaW5zaWRlIGEgXCIgK1xuICAgICAgJ2RlcGxveW1lbnQpIG1hdGNoZXMgdGhlIGVudmlyb25tZW50IG9mIHRoZSBkZXBsb3ltZW50IGl0IHRhcmdldHMuIFRoZSAnICtcbiAgICAgIGBydW4gaXQgY3JlYXRlZCBpcyBzdGlsbCBwZW5kaW5nIGluIFwiJHtjcmVhdG9yRW52aXJvbm1lbnR9XCIgYW5kIHdpbGwgYCArXG4gICAgICAnbm90IHJ1bi4nLFxuICAgIHtcbiAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgY3JlYXRvckVudmlyb25tZW50LFxuICAgICAgY3VycmVudEVudmlyb25tZW50LFxuICAgICAgcGlubmVkRGVwbG95bWVudElkOiBydW5JbnB1dD8uZGVwbG95bWVudElkLFxuICAgIH1cbiAgKTtcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogTG9nIHdoZW4gYSBgc3RhcnQoKWAtZW5xdWV1ZWQgbWVzc2FnZSBwaW5uZWQgdG8gb25lIGRlcGxveW1lbnQgaXMgZGVsaXZlcmVkXG4gKiB0byBhIGRpZmZlcmVudCBvbmUuXG4gKlxuICogQSBmaXJzdC1kZWxpdmVyeSBtZXNzYWdlIGNhcnJpZXMgYHJ1bklucHV0LmRlcGxveW1lbnRJZGAg4oCUIHRoZSBkZXBsb3ltZW50XG4gKiBgc3RhcnQoKWAgYWRkcmVzc2VkIGl0IHRvIOKAlCBzbyBjb21wYXJpbmcgdGhhdCBhZ2FpbnN0IHRoaXMgaGFuZGxlcidzIG93blxuICogZGVwbG95bWVudCBkZXRlY3RzIG1pcy1kZWxpdmVyeSBkaXJlY3RseS4gVGhpcyBpcyBhIERJQUdOT1NUSUMsIG5vdCBhIGdhdGU6XG4gKiBpdCB3YXJucyBhbmQgbGV0cyB0aGUgaW52b2NhdGlvbiBwcm9jZWVkLCBkZWxpYmVyYXRlbHkuXG4gKlxuICogV2h5IHRoaXMgb25lIG9ubHkgd2FybnMgd2hpbGUgaXRzIGVudmlyb25tZW50IHNpYmxpbmcgYWJvdmUgcmVmdXNlczogYVxuICogZGlmZmVyaW5nIGRlcGxveW1lbnQgaWQgaXMgbm90IGJ5IGl0c2VsZiBldmlkZW5jZSBvZiB0aGUgZm9yayB3ZSBjYXJlIGFib3V0LlxuICogVGhlIGVudmlyb25tZW50IHBhaXIgaXMgZXhhY3Qg4oCUIHR3byBuYW1lZCBlbnZpcm9ubWVudHMgdGhhdCBkaXNhZ3JlZSDigJQgYW5kIGl0XG4gKiBpcyB0aGUgZGltZW5zaW9uIHRoZSBydW4ncyB0ZW5hbnQgaXMga2V5ZWQgb24uIERlcGxveW1lbnQgaWRzIGRpc2FncmVlIGZvclxuICogYmVuaWduIHJlYXNvbnMgdG9vOiBgd29ybGQtbG9jYWxgIGRlcml2ZXMgaXRzIGlkIGZyb20gdGhlIGluc3RhbGxlZCBwYWNrYWdlXG4gKiB2ZXJzaW9uIChgZHBsX2xvY2FsQDx2ZXJzaW9uPmApLCBzbyB1cGdyYWRpbmcgdGhlIFNESyBtaWQtcnVuIGNoYW5nZXMgaXQgd2l0aFxuICogbm90aGluZyB3cm9uZy4gUmVmdXNpbmcgb24gdGhhdCBzaWduYWwgd291bGQgc3RyYW5kIGNvcnJlY3QgcnVucywgYW5kXG4gKiByZWZ1c2luZyBiZWZvcmUgYHJ1bl9zdGFydGVkYCBsZWF2ZXMgbm8gc2VydmVyLXNpZGUgcmVjb3JkIHRvIGV4cGxhaW4gd2h5LlxuICogQW55b25lIHRlbXB0ZWQgdG8gcHJvbW90ZSB0aGlzIHRvIGEgaGFyZCBmYWlsdXJlIGhhcyB0byBoYW5kbGUgdGhhdCBmaXJzdC5cbiAqXG4gKiBTa2lwcGVkIHVubGVzcyBCT1RIIGlkcyBhcmUga25vd24g4oCUIGBnZXREZXBsb3ltZW50SWQoKWAgdGhyb3dzIGluIHdvcmxkcyB0aGF0XG4gKiByZXF1aXJlIGEgZGVwbG95bWVudCBhbmQgaGF2ZSBub25lLCBhbmQgYSByZS1lbnF1ZXVlZCBtZXNzYWdlIGNhcnJpZXMgbm9cbiAqIGBydW5JbnB1dGAgYXQgYWxsLlxuICovXG5hc3luYyBmdW5jdGlvbiB3YXJuT25EZXBsb3ltZW50UGlubmluZ01pc21hdGNoKHtcbiAgd29ybGQsXG4gIHJ1bklucHV0LFxuICBydW5JZCxcbiAgcnVuTG9nZ2VyLFxufToge1xuICB3b3JsZDogV29ybGQ7XG4gIHJ1bklucHV0OiBSdW5JbnB1dCB8IHVuZGVmaW5lZDtcbiAgcnVuSWQ6IHN0cmluZztcbiAgcnVuTG9nZ2VyOiBMb2dnZXI7XG59KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHBpbm5lZERlcGxveW1lbnRJZCA9IHJ1bklucHV0Py5kZXBsb3ltZW50SWQ7XG4gIGlmICghcGlubmVkRGVwbG95bWVudElkKSByZXR1cm47XG5cbiAgbGV0IGN1cnJlbnREZXBsb3ltZW50SWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjdXJyZW50RGVwbG95bWVudElkID0gYXdhaXQgd29ybGQuZ2V0RGVwbG95bWVudElkKCk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIFdvcmxkcyB0aGF0IHJlcXVpcmUgYSBkZXBsb3ltZW50IGlkIHRocm93IHdoZW4gdGhlcmUgaXNuJ3Qgb25lLiBUaGF0IGlzXG4gICAgLy8gbm90IGEgbWlzbWF0Y2gg4oCUIHRoZXJlIGlzIHNpbXBseSBub3RoaW5nIHRvIGNvbXBhcmUgYWdhaW5zdC5cbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKCFjdXJyZW50RGVwbG95bWVudElkIHx8IGN1cnJlbnREZXBsb3ltZW50SWQgPT09IHBpbm5lZERlcGxveW1lbnRJZCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHJ1bkxvZ2dlci5lcnJvcihcbiAgICAnUXVldWUgbWVzc2FnZSB3YXMgZGVsaXZlcmVkIHRvIGEgZGVwbG95bWVudCBpdCB3YXMgbm90IHBpbm5lZCB0by4gJyArXG4gICAgICAnVGhlIHJ1biB3YXMgY3JlYXRlZCB0YXJnZXRpbmcgYSBkaWZmZXJlbnQgZGVwbG95bWVudCwgc28gdGhpcyAnICtcbiAgICAgICdpbnZvY2F0aW9uIG1heSBiZSByZXBsYXlpbmcgYWdhaW5zdCBjb2RlIHRoZSBydW4gd2FzIG5vdCBzdGFydGVkIG9uLiAnICtcbiAgICAgICdDb250aW51aW5nIOKAlCB0aGlzIGlzIGV4cGVjdGVkIGlmIHRoZSBXb3JrZmxvdyBTREsgdmVyc2lvbiBjaGFuZ2VkICcgK1xuICAgICAgJ21pZC1ydW4gaW4gbG9jYWwgZGV2ZWxvcG1lbnQsIHdoZXJlIHRoZSBkZXBsb3ltZW50IGlkIGlzIGRlcml2ZWQgZnJvbSAnICtcbiAgICAgICd0aGF0IHZlcnNpb24uJyxcbiAgICB7XG4gICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgIHBpbm5lZERlcGxveW1lbnRJZCxcbiAgICAgIGN1cnJlbnREZXBsb3ltZW50SWQsXG4gICAgfVxuICApO1xufVxuXG5mdW5jdGlvbiBnZXRXb3JrZmxvd1NldHVwRXJyb3JDb2RlKGVycjogdW5rbm93bik6IFJ1bkVycm9yQ29kZSB8IG51bGwge1xuICBpZiAoV29ya2Zsb3dSdW50aW1lRXJyb3IuaXMoZXJyKSkge1xuICAgIHJldHVybiBSVU5fRVJST1JfQ09ERVMuUlVOVElNRV9FUlJPUjtcbiAgfVxuXG4gIGlmIChpc1dvcmxkQ29udHJhY3RFcnJvcihlcnIpKSB7XG4gICAgcmV0dXJuIFJVTl9FUlJPUl9DT0RFUy5XT1JMRF9DT05UUkFDVF9FUlJPUjtcbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG5hc3luYyBmdW5jdGlvbiByZWNvcmRGYXRhbFJ1bkVycm9yKHtcbiAgd29ybGQsXG4gIHdvcmtmbG93UnVuLFxuICBydW5JZCxcbiAgcmVxdWVzdElkLFxuICBlcnIsXG4gIGVycm9yQ29kZSxcbiAgbG9nTWVzc2FnZSxcbn06IHtcbiAgd29ybGQ6IFdvcmxkO1xuICB3b3JrZmxvd1J1bjogV29ya2Zsb3dSdW4gfCB1bmRlZmluZWQ7XG4gIHJ1bklkOiBzdHJpbmc7XG4gIHJlcXVlc3RJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBlcnI6IHVua25vd247XG4gIGVycm9yQ29kZTogUnVuRXJyb3JDb2RlO1xuICBsb2dNZXNzYWdlOiBzdHJpbmc7XG59KSB7XG4gIHJ1bnRpbWVMb2dnZXIuZXJyb3IobG9nTWVzc2FnZSwge1xuICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgIGVycm9yQ29kZSxcbiAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICB9KTtcblxuICB0cnkge1xuICAgIGNvbnN0IGdldEVuY3J5cHRpb25LZXkgPSBtZW1vaXplRW5jcnlwdGlvbktleSh3b3JsZCwgd29ya2Zsb3dSdW4gPz8gcnVuSWQpO1xuICAgIGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICBydW5JZCxcbiAgICAgIHtcbiAgICAgICAgZXZlbnRUeXBlOiAncnVuX2ZhaWxlZCcsXG4gICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICBhd2FpdCBnZXRFbmNyeXB0aW9uS2V5KCksXG4gICAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgICAgKHdvcmtmbG93UnVuPy5zcGVjVmVyc2lvbiA/PyAwKSA+PSBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ09NUFJFU1NJT05cbiAgICAgICAgICApLFxuICAgICAgICAgIGVycm9yQ29kZSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICB7IHJlcXVlc3RJZCB9XG4gICAgKTtcbiAgfSBjYXRjaCAoZmFpbEVycikge1xuICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGZhaWxFcnIpIHx8IFJ1bkV4cGlyZWRFcnJvci5pcyhmYWlsRXJyKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoaXNXb3JsZENvbnRyYWN0RXJyb3IoZmFpbEVycikpIHtcbiAgICAgIHJ1bnRpbWVMb2dnZXIuZXJyb3IoXG4gICAgICAgICdGYXRhbCB3b3JsZCBjb250cmFjdCBlcnJvciB3aGlsZSByZWNvcmRpbmcgd29ya2Zsb3cgZmFpbHVyZScsXG4gICAgICAgIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICBlcnJvckNvZGU6IFJVTl9FUlJPUl9DT0RFUy5XT1JMRF9DT05UUkFDVF9FUlJPUixcbiAgICAgICAgICBlcnJvcjogZmFpbEVyciBpbnN0YW5jZW9mIEVycm9yID8gZmFpbEVyci5tZXNzYWdlIDogU3RyaW5nKGZhaWxFcnIpLFxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBmYWlsRXJyO1xuICB9XG59XG5cbmZ1bmN0aW9uIGhhc1JlY29yZGVkVGVybWluYWxSdW5FdmVudChldmVudHM6IEV2ZW50W10sIHJ1bklkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gVGVybWluYWwgcnVuIGV2ZW50cyBhcmUgYWx3YXlzIGxhc3QgYnkgY29uc3RydWN0aW9uIChubyBldmVudCBjcmVhdGlvblxuICAvLyBzdWNjZWVkcyBhZ2FpbnN0IGEgdGVybWluYWwgcnVuKSwgYnV0IHNjYW4gdGhlIGZ1bGwgYXJyYXkgZm9yXG4gIC8vIGRlZmVuc2UtaW4tZGVwdGg6IGEgV29ybGQvYmFja2VuZCBvcmRlcmluZyBidWcgc2hvdWxkbid0IG1ha2UgdXMgbWlzcyBhblxuICAvLyBhY3R1YWwgdGVybWluYXRpb24gc2lnbmFsLlxuICBjb25zdCB0ZXJtaW5hbFJ1bkV2ZW50ID0gZXZlbnRzLmZpbmQoXG4gICAgKGUpID0+XG4gICAgICBlLnJ1bklkID09PSBydW5JZCAmJlxuICAgICAgKGUuZXZlbnRUeXBlID09PSAncnVuX2NvbXBsZXRlZCcgfHxcbiAgICAgICAgZS5ldmVudFR5cGUgPT09ICdydW5fZmFpbGVkJyB8fFxuICAgICAgICBlLmV2ZW50VHlwZSA9PT0gJ3J1bl9jYW5jZWxsZWQnKVxuICApO1xuXG4gIGlmICghdGVybWluYWxSdW5FdmVudCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1J1biByZWFjaGVkIHRlcm1pbmFsIGV2ZW50LCBleGl0aW5nJywge1xuICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgIGV2ZW50VHlwZTogdGVybWluYWxSdW5FdmVudC5ldmVudFR5cGUsXG4gICAgZXZlbnRJZDogdGVybWluYWxSdW5FdmVudC5ldmVudElkLFxuICB9KTtcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKiBIb3cgbWFueSBvZiBgaWRzYCBhcmUgYWJzZW50IGZyb20gYHByZXNlbnRgLiAqL1xuZnVuY3Rpb24gY291bnRNaXNzaW5nSWRzKGlkczogSXRlcmFibGU8c3RyaW5nPiwgcHJlc2VudDogU2V0PHN0cmluZz4pOiBudW1iZXIge1xuICBsZXQgbWlzc2luZyA9IDA7XG4gIGZvciAoY29uc3QgaWQgb2YgaWRzKSB7XG4gICAgaWYgKCFwcmVzZW50LmhhcyhpZCkpIG1pc3NpbmcrKztcbiAgfVxuICByZXR1cm4gbWlzc2luZztcbn1cblxuLyoqXG4gKiBUaGUgbGluZWFnZSByb290IG9mIGEgbG9hZGVkIHJ1bjogaXRzIGAkcm9vdFJ1bklkYCBhdHRyaWJ1dGUsIG9yIGl0cyBvd24gaWRcbiAqIHdoZW4gaXQgaXMgaXRzZWxmIGEgcm9vdC5cbiAqL1xuZnVuY3Rpb24gcm9vdFJ1bklkRnJvbShcbiAgYXR0cmlidXRlczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB8IHVuZGVmaW5lZCxcbiAgcnVuSWQ6IHN0cmluZ1xuKTogc3RyaW5nIHtcbiAgcmV0dXJuIGF0dHJpYnV0ZXM/LltST09UX1JVTl9JRF9BVFRSSUJVVEVdID8/IHJ1bklkO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJ1biBoYXMgYSBob29rIGFuZC9vciB3YWl0IHRoYXQgYW4gb3V0LW9mLWJhbmQgd3JpdGVyIGNvdWxkXG4gKiBhcHBlbmQgYW4gZXZlbnQgZm9yIGJldHdlZW4gYW4gaW5saW5lIHN0ZXAncyBgc3RlcF9jb21wbGV0ZWRgIHdyaXRlIGFuZFxuICogdGhlIG5leHQgcmVwbGF5IOKAlCBuYW1lbHkgYW4gb3BlbiBob29rIChhIGBob29rX2NyZWF0ZWRgIG5vdCB5ZXRcbiAqIGBob29rX2Rpc3Bvc2VkYCwgd2hpY2ggYSB3ZWJob29rIHJlY2VpdmVyIGNhbiByZXNvbHZlIHdpdGhcbiAqIGBob29rX3JlY2VpdmVkYCkgb3IgYW4gb3BlbiB3YWl0IChhIGB3YWl0X2NyZWF0ZWRgIG5vdCB5ZXRcbiAqIGB3YWl0X2NvbXBsZXRlZGAsIHdoaWNoIHRoZSB3YWl0IHRpbWVyIGNhbiByZXNvbHZlIHdpdGhcbiAqIGB3YWl0X2NvbXBsZXRlZGApLlxuICpcbiAqIFRoaXMgZ2F0ZXMgVk0gcmV0ZW50aW9uLCB0aGUgaW5saW5lLWRlbHRhIGZhc3QgcGF0aCwgYW5kIHR1cmJvJ3MgZm9yY2VkXG4gKiBvcHRpbWlzdGljIHN0YXJ0LiBBIHRlcm1pbmFsLXN0ZXAgZGVsdGEgY2FuIG9taXQgYW4gZXZlbnQgYXBwZW5kZWRcbiAqIGNvbmN1cnJlbnRseSBhZnRlciB0aGF0IHdyaXRlLiBXaXRoIG5vIG9wZW4gaG9vayBvciB3YWl0LCBvbmx5IGNhbmNlbGxhdGlvblxuICogY2FuIGRvIHNvLCBhbmQgb2JzZXJ2aW5nIGl0IG9uZSByZXBsYXkgbGF0ZSBpcyBzYWZlIGJlY2F1c2UgdGhlIG5leHQgZW50aXR5XG4gKiB3cml0ZSBpcyByZWplY3RlZC5cbiAqXG4gKiBTdGVwLWJvZHkgYGF0dHJfc2V0YCB3cml0ZXMgYXJlIE5PVCBhIGNvbmNlcm46IHRoZXkgbGFuZCBiZWZvcmUgdGhlXG4gKiBzdGVwJ3MgdGVybWluYWwgd3JpdGUgYW5kIGFyZSB0aGVyZWZvcmUgYWxyZWFkeSBpbnNpZGUgdGhlIHJldHVybmVkXG4gKiBkZWx0YS5cbiAqL1xuZnVuY3Rpb24gb3Blbkhvb2tBbmRXYWl0U3RhdGUoZXZlbnRzOiBFdmVudFtdKToge1xuICBvcGVuSG9vazogYm9vbGVhbjtcbiAgb3BlbldhaXQ6IGJvb2xlYW47XG59IHtcbiAgY29uc3QgaG9va3MgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3Qgd2FpdHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICBzd2l0Y2ggKGV2ZW50LmV2ZW50VHlwZSkge1xuICAgICAgY2FzZSAnaG9va19jcmVhdGVkJzpcbiAgICAgICAgaG9va3MuYWRkKGV2ZW50LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2hvb2tfZGlzcG9zZWQnOlxuICAgICAgICBob29rcy5kZWxldGUoZXZlbnQuY29ycmVsYXRpb25JZCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnd2FpdF9jcmVhdGVkJzpcbiAgICAgICAgd2FpdHMuYWRkKGV2ZW50LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3dhaXRfY29tcGxldGVkJzpcbiAgICAgICAgd2FpdHMuZGVsZXRlKGV2ZW50LmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHsgb3Blbkhvb2s6IGhvb2tzLnNpemUgPiAwLCBvcGVuV2FpdDogd2FpdHMuc2l6ZSA+IDAgfTtcbn1cblxudHlwZSBSZXBsYXlFdmVudExvZyA9XG4gIHwgeyB0eXBlOiAnbG9hZEFsbCcgfVxuICB8ICh7IHR5cGU6ICdyZWFkeScgfSAmIExvYWRlZEV2ZW50TG9nKVxuICB8ICh7IHR5cGU6ICdsb2FkQWZ0ZXInOyBjdXJzb3I6IHN0cmluZyB9ICYgTG9hZGVkRXZlbnRMb2cpO1xuXG5mdW5jdGlvbiBuZXh0RXZlbnRMb2dMb2FkKGxvZzogTG9hZGVkRXZlbnRMb2cpOiBSZXBsYXlFdmVudExvZyB7XG4gIGlmIChsb2cuY3Vyc29yID09PSBudWxsKSB7XG4gICAgcmV0dXJuIHsgdHlwZTogJ2xvYWRBbGwnIH07XG4gIH1cbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnbG9hZEFmdGVyJyxcbiAgICBldmVudHM6IGxvZy5ldmVudHMsXG4gICAgY3Vyc29yOiBsb2cuY3Vyc29yLFxuICB9O1xufVxuXG5mdW5jdGlvbiBhcHBlbmRFdmVudExvZyhsb2c6IExvYWRlZEV2ZW50TG9nLCBhcHBlbmRlZDogTG9hZGVkRXZlbnRMb2cpOiB2b2lkIHtcbiAgYXBwZW5kVW5pcXVlRXZlbnRzKGxvZy5ldmVudHMsIGFwcGVuZGVkLmV2ZW50cyk7XG4gIGxvZy5jdXJzb3IgPSBhcHBlbmRlZC5jdXJzb3IgPz8gbG9nLmN1cnNvcjtcbn1cblxuLyoqXG4gKiBUaGUgd2hvbGUgcmV0ZW50aW9uIHByZWRpY2F0ZToga2VlcCB0aGUgc2Vzc2lvbiBvbmx5IGZvciBhIHB1cmUgc3RlcFxuICogYm91bmRhcnkgKGV2ZXJ5IHN1c3BlbnNpb24gaXRlbSBpcyBhIHN0ZXAg4oCUIGFueSBvdGhlciBpdGVtIHR5cGUsIHByZXNlbnRcbiAqIG9yIGZ1dHVyZSwgaXMgdW5yZXRhaW5hYmxlIGJ5IGRlZmF1bHQpIHdob3NlIG5ldyBzdGVwIGlucHV0cyBzZXJpYWxpemVkXG4gKiB3aXRob3V0IGV4ZWN1dGluZyB3b3JrZmxvdyBjb2RlLCB3aXRoIG5vIG91dC1vZi1iYW5kIGNvbnRpbnVhdGlvbiBzb3VyY2U6XG4gKiBhdHRyaWJ1dGVzIHJlcXVpcmUgcmVwbGF5OyBob29rcyBhbmQgd2FpdHMgY2FuIHdha2UgYW5vdGhlciBpbnZvY2F0aW9uLlxuICogYFdPUktGTE9XX1JFVEFJTkVEX1ZNPTBgIGRpc2FibGVzIHJldGVudGlvbiBlbnRpcmVseS5cbiAqXG4gKiBUaGUgb3BlbiBob29rL3dhaXQgc2NhbiBpcyBPKGV2ZW50cyksIHNvIGl0IGlzIHRha2VuIHRocm91Z2ggYSBsYXp5IGdldHRlclxuICogYW5kIGNvbnN1bHRlZCBsYXN0LCBhZnRlciBldmVyeSBjaGVhcCBjaGVjayBoYXMgcGFzc2VkLlxuICpcbiAqIElOVkFSSUFOVCB0aGlzIHByZWRpY2F0ZSBsZWFucyBvbjogZXZlcnkgc3VzcGVuc2lvbiBzaWduYWxlciB0aGF0IGRvZXMgTk9UXG4gKiBjYXJyeSB0aGUgc3RlcC1jb25zdW1lciBnZW5lcmF0aW9uIGd1YXJkIChzbGVlcCwgaG9vaywgYXR0cmlidXRlIOKAlCBzZWVcbiAqIGBzdXNwZW5zaW9uR2VuZXJhdGlvbmAgaW4gcHJpdmF0ZS50cykgbXVzdCBiZSB1bnJldGFpbmFibGUgaGVyZSwgZWl0aGVyIHZpYVxuICogYSBub24tc3RlcCBxdWV1ZSBpdGVtIG9yIHRoZSBvcGVuIGhvb2svd2FpdCBzY2FuLiBBIG5ldyBzaWduYWxlciB0aGF0XG4gKiBzYXRpc2ZpZXMgbmVpdGhlciB3b3VsZCBsZXQgYSBzdGFsZSBzaWduYWwgYmUgYWNjZXB0ZWQgYXMgYSBmcmVzaFxuICogc3VzcGVuc2lvbiBvbiBhIHJlc3VtZWQgc2Vzc2lvbi5cbiAqXG4gKiBRdWllc2NlbmNlIGFzc3VtZXMgd29ya2Zsb3cgY29kZSBzdGF5cyBpbnNpZGUgdGhlIHNhbmRib3gncyBkZXRlcm1pbmlzbVxuICogY29udHJhY3QuIEVzY2FwaW5nIHRvIHRoZSBob3N0IHJlYWxtIChlLmcuIHJlY292ZXJpbmcgdGhlIGhvc3QgYEZ1bmN0aW9uYFxuICogY29uc3RydWN0b3IgZnJvbSBhbiBleHBvc2VkIGhvc3QgY2xhc3MgdG8gc2NoZWR1bGUgcmVhbCB0aW1lcnMpIG1ha2VzIGFcbiAqIHdvcmtmbG93IG5vbmRldGVybWluaXN0aWMgdW5kZXIgb3JkaW5hcnkgcmVwbGF5IHRvbywgYW5kIGlzIG5vdCBkZWZlbmRlZFxuICogaGVyZS5cbiAqL1xuZnVuY3Rpb24gY2FuUmV0YWluV29ya2Zsb3dTZXNzaW9uKFxuICBzdXNwZW5zaW9uOiBXb3JrZmxvd1N1c3BlbnNpb24sXG4gIHN0ZXBJbnB1dHNTYWZlOiBib29sZWFuLFxuICBvcGVuSG9va1dhaXQ6IHsgdmFsdWU6IFJldHVyblR5cGU8dHlwZW9mIG9wZW5Ib29rQW5kV2FpdFN0YXRlPiB9XG4pOiBib29sZWFuIHtcbiAgaWYgKFxuICAgICFpc1ZtUmV0ZW50aW9uRW5hYmxlZCgpIHx8XG4gICAgIXN0ZXBJbnB1dHNTYWZlIHx8XG4gICAgc3VzcGVuc2lvbi5zdGVwcy5sZW5ndGggPT09IDAgfHxcbiAgICAhc3VzcGVuc2lvbi5zdGVwcy5ldmVyeSgoaXRlbSkgPT4gaXRlbS50eXBlID09PSAnc3RlcCcpXG4gICkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCB7IG9wZW5Ib29rLCBvcGVuV2FpdCB9ID0gb3Blbkhvb2tXYWl0LnZhbHVlO1xuICByZXR1cm4gIW9wZW5Ib29rICYmICFvcGVuV2FpdDtcbn1cblxuLyoqXG4gKiBNYXhpbXVtIGlubGluZS1leGVjdXRpb24gZHVyYXRpb24gZm9yIGEgc2luZ2xlIGhhbmRsZXIgaW52b2NhdGlvbi5cbiAqXG4gKiBPcmRlciBvZiBwcmVjZWRlbmNlOlxuICogMS4gYFdPUktGTE9XX1YyX1RJTUVPVVRfTVNgIGVudiB2YXJcbiAqIDIuIFRpZXJlZCBidWRnZXQgZGVyaXZlZCBmcm9tIGB3b3JsZC5nZXRSdW50aW1lRGVhZGxpbmUoKWBcbiAqIDMuIERlZmF1bHQgb2YgMiBtaW51dGVzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldE1heElubGluZUR1cmF0aW9uTXMoXG4gIHdvcmxkOiBXb3JsZCxcbiAgaW52b2NhdGlvblN0YXJ0VGltZTogbnVtYmVyXG4pOiBQcm9taXNlPG51bWJlcj4ge1xuICBjb25zdCByYXdFbnZPdmVycmlkZSA9IHByb2Nlc3MuZW52LldPUktGTE9XX1YyX1RJTUVPVVRfTVM7XG4gIGlmIChyYXdFbnZPdmVycmlkZSAhPT0gdW5kZWZpbmVkICYmIHJhd0Vudk92ZXJyaWRlICE9PSAnJykge1xuICAgIGNvbnN0IHBhcnNlZCA9IE51bWJlcihyYXdFbnZPdmVycmlkZSk7XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZShwYXJzZWQpICYmIHBhcnNlZCA+IDApIHtcbiAgICAgIHJldHVybiBwYXJzZWQ7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcnVudGltZURlYWRsaW5lID0gYXdhaXQgd29ybGQuZ2V0UnVudGltZURlYWRsaW5lPy4oKTtcbiAgaWYgKHJ1bnRpbWVEZWFkbGluZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZGVhZGxpbmVNcyA9IHJ1bnRpbWVEZWFkbGluZS5nZXRUaW1lKCk7XG4gICAgaWYgKCFOdW1iZXIuaXNOYU4oZGVhZGxpbmVNcykpIHtcbiAgICAgIGNvbnN0IG1heER1cmF0aW9uTXMgPSBNYXRoLmZsb29yKGRlYWRsaW5lTXMgLSBpbnZvY2F0aW9uU3RhcnRUaW1lKTtcbiAgICAgIGlmIChtYXhEdXJhdGlvbk1zID49IG1zKCcyNW0nKSkge1xuICAgICAgICByZXR1cm4gbXMoJzEwbScpO1xuICAgICAgfVxuXG4gICAgICBpZiAobWF4RHVyYXRpb25NcyA+PSBtcygnMTBtJykpIHtcbiAgICAgICAgcmV0dXJuIG1zKCc1bScpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBtcygnMm0nKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgc2luZ2xlIHJvdXRlIHdoaWNoIGhhbmRsZXMgd29ya2Zsb3cgZXhlY3V0aW9uIHJlcXVlc3RzLFxuICogZXhlY3V0aW5nIHN0ZXBzIGlubGluZSB3aGVuIHBvc3NpYmxlIHRvIHJlZHVjZSBmdW5jdGlvbiBpbnZvY2F0aW9uc1xuICogYW5kIHF1ZXVlIG92ZXJoZWFkLlxuICpcbiAqIFRoZSBoYW5kbGVyIGxvb3BzOiByZXBsYXkgd29ya2Zsb3cg4oaSIGV4ZWN1dGUgc3RlcCBpbmxpbmUg4oaSIHJlcGxheSDihpIgLi4uXG4gKiB1bnRpbCB0aGUgd29ya2Zsb3cgY29tcGxldGVzLCB0aW1lcyBvdXQsIG9yIGVuY291bnRlcnMgbm9uLXN0ZXAgc3VzcGVuc2lvbnMuXG4gKlxuICogQHBhcmFtIHdvcmtmbG93Q29kZSAtIFRoZSB3b3JrZmxvdyBidW5kbGUgY29kZSBjb250YWluaW5nIGFsbCB3b3JrZmxvdyBmdW5jdGlvbnNcbiAqIEByZXR1cm5zIEEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCBhcyBhIFZlcmNlbCBBUEkgcm91dGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdvcmtmbG93RW50cnlwb2ludChcbiAgd29ya2Zsb3dDb2RlOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiB7XG4gICAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICAgIHJvdXRlTW9kdWxlQm9keVN0YXJ0ZWRBdD86IG51bWJlcjtcbiAgICBiYXNlUGF0aD86IHN0cmluZztcbiAgfVxuKTogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4ge1xuICBzZXRXb3JrZmxvd0Jhc2VQYXRoKG9wdGlvbnM/LmJhc2VQYXRoKTtcblxuICBjb25zdCBuYW1lc3BhY2UgPSByZXNvbHZlUXVldWVOYW1lc3BhY2Uob3B0aW9ucz8ubmFtZXNwYWNlKTtcbiAgY29uc3Qgd29ya2Zsb3dQcmVmaXggPSBnZXRRdWV1ZVRvcGljUHJlZml4KCd3b3JrZmxvdycsIG5hbWVzcGFjZSk7XG5cbiAgY29uc3QgaGFuZGxlciA9ICh3b3JsZEhhbmRsZXJzOiBXb3JsZEhhbmRsZXJzKSA9PlxuICAgIHdvcmxkSGFuZGxlcnMuY3JlYXRlUXVldWVIYW5kbGVyKFxuICAgICAgd29ya2Zsb3dQcmVmaXgsXG4gICAgICBhc3luYyAobWVzc2FnZV8sIG1ldGFkYXRhKSA9PiB7XG4gICAgICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZVxuICAgICAgICAvLyBOT1RFOiBIZWFsdGggY2hlY2sgbWVzc2FnZXMgYXJlIGludGVudGlvbmFsbHkgdW5hdXRoZW50aWNhdGVkIGZvciBtb25pdG9yaW5nIHB1cnBvc2VzLlxuICAgICAgICAvLyBUaGV5IG9ubHkgd3JpdGUgYSBzaW1wbGUgc3RhdHVzIHJlc3BvbnNlIHRvIGEgc3RyZWFtIGFuZCBkbyBub3QgZXhwb3NlIHNlbnNpdGl2ZSBkYXRhLlxuICAgICAgICAvLyBUaGUgc3RyZWFtIG5hbWUgaW5jbHVkZXMgYSB1bmlxdWUgY29ycmVsYXRpb25JZCB0aGF0IG11c3QgYmUga25vd24gYnkgdGhlIGNhbGxlci5cbiAgICAgICAgY29uc3QgaGVhbHRoQ2hlY2sgPSBwYXJzZUhlYWx0aENoZWNrUGF5bG9hZChtZXNzYWdlXyk7XG4gICAgICAgIGlmIChoZWFsdGhDaGVjaykge1xuICAgICAgICAgIGF3YWl0IGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgICAgICAgICAgIGhlYWx0aENoZWNrLFxuICAgICAgICAgICAgd29ybGRIYW5kbGVycy5zcGVjVmVyc2lvblxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgIHRyYWNlQ2FycmllcjogaW5jb21pbmdUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgcmVxdWVzdGVkQXQsXG4gICAgICAgICAgc3RlcElkOiBpbmNvbWluZ1N0ZXBJZCxcbiAgICAgICAgICBzdGVwTmFtZTogaW5jb21pbmdTdGVwTmFtZSxcbiAgICAgICAgICByZXBsYXlEaXZlcmdlbmNlLFxuICAgICAgICAgIHByZWNvbmRpdGlvblJlaW52b2NhdGlvbnMsXG4gICAgICAgICAgZGVwbG95bWVudE1pc21hdGNoUmV0cnlDb3VudCxcbiAgICAgICAgICBydW5JbnB1dCxcbiAgICAgICAgICBob29rSW5wdXQsXG4gICAgICAgIH0gPSBXb3JrZmxvd0ludm9rZVBheWxvYWRTY2hlbWEucGFyc2UobWVzc2FnZV8pO1xuICAgICAgICAvLyBgc3RhcnQoKWAgYWx3YXlzIGF0dGFjaGVzIGEgdHJhY2UgY2FycmllciwgYnV0XG4gICAgICAgIC8vIHNlcmlhbGl6ZVRyYWNlQ2FycmllcigpIHJldHVybnMgYHt9YCB3aGVuIG5vIE9URUwgU0RLIGlzIHJlZ2lzdGVyZWRcbiAgICAgICAgLy8gb3Igbm8gc3BhbiBpcyBhY3RpdmUg4oCUIHRyZWF0IGFuIGVtcHR5IGNhcnJpZXIgdGhlIHNhbWUgYXMgYW5cbiAgICAgICAgLy8gYWJzZW50IG9uZSBzbyBsaW5rZWQgbW9kZSBmYWxscyBiYWNrIHRvIGEgZnJlc2ggb3JpZ2luIGluc3RlYWQgb2ZcbiAgICAgICAgLy8gZm9yd2FyZGluZyBhIHVzZWxlc3MgYHt9YCBmb3JldmVyLlxuICAgICAgICBjb25zdCB0cmFjZUNvbnRleHQgPSBpc1VzYWJsZVRyYWNlQ2FycmllcihpbmNvbWluZ1RyYWNlQ2FycmllcilcbiAgICAgICAgICA/IGluY29taW5nVHJhY2VDYXJyaWVyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICAgIGNvbnN0IHsgcmVxdWVzdElkIH0gPSBtZXRhZGF0YTtcbiAgICAgICAgY29uc3Qgd29ya2Zsb3dOYW1lID0gbWV0YWRhdGEucXVldWVOYW1lLnNsaWNlKHdvcmtmbG93UHJlZml4Lmxlbmd0aCk7XG5cbiAgICAgICAgLy8gLS0tIE1heCBkZWxpdmVyeSBjaGVjayAtLS1cbiAgICAgICAgLy8gRW5mb3JjZSBtYXggZGVsaXZlcnkgbGltaXQgYmVmb3JlIGFueSBpbmZyYXN0cnVjdHVyZSBjYWxscy5cbiAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBydW5hd2F5IHdvcmtmbG93cyBmcm9tIGNvbnN1bWluZyBpbmZpbml0ZSBxdWV1ZSBkZWxpdmVyaWVzLlxuICAgICAgICAvLyBTY29wZWQgbG9nZ2VyIGZvciB0aGlzIHJ1biDigJQgYXR0YWNoZXMgcnVuSWQvd29ya2Zsb3dOYW1lIHRvIGV2ZXJ5XG4gICAgICAgIC8vIGxvZyBsaW5lIGFuZCBjaGlsZCBsb2dnZXJzIGJlbG93LCBzbyBjYWxsZXJzIGRvbid0IHJlcGVhdCBpdC5cbiAgICAgICAgY29uc3QgcnVuTG9nZ2VyID0gcnVudGltZUxvZ2dlci5mb3JSdW4ocnVuSWQsIHdvcmtmbG93TmFtZSk7XG5cbiAgICAgICAgY29uc3QgbWF4UXVldWVEZWxpdmVyaWVzID0gZ2V0TWF4UXVldWVEZWxpdmVyaWVzKCk7XG4gICAgICAgIGlmIChtZXRhZGF0YS5hdHRlbXB0ID4gbWF4UXVldWVEZWxpdmVyaWVzKSB7XG4gICAgICAgICAgY29uc3QgbWF4RGVsaXZlcmllc0Rlc2NyaXB0aW9uID0gZGVzY3JpYmVFcnJvcihcbiAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgIFJVTl9FUlJPUl9DT0RFUy5NQVhfREVMSVZFUklFU19FWENFRURFRFxuICAgICAgICAgICk7XG4gICAgICAgICAgcnVuTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgYFdvcmtmbG93IGhhbmRsZXIgZXhjZWVkZWQgbWF4IGRlbGl2ZXJpZXMgKCR7bWV0YWRhdGEuYXR0ZW1wdH0vJHttYXhRdWV1ZURlbGl2ZXJpZXN9KWAsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGF0dGVtcHQ6IG1ldGFkYXRhLmF0dGVtcHQsXG4gICAgICAgICAgICAgIGVycm9yQ29kZTogbWF4RGVsaXZlcmllc0Rlc2NyaXB0aW9uLmVycm9yQ29kZSxcbiAgICAgICAgICAgICAgZXJyb3JBdHRyaWJ1dGlvbjogbWF4RGVsaXZlcmllc0Rlc2NyaXB0aW9uLmF0dHJpYnV0aW9uLFxuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGQoKTtcbiAgICAgICAgICAgIGNvbnN0IGdldEVuY3J5cHRpb25LZXkgPSBtZW1vaXplRW5jcnlwdGlvbktleSh3b3JsZCwgcnVuSWQpO1xuICAgICAgICAgICAgY29uc3QgZXJyID0gbmV3IEZhdGFsRXJyb3IoXG4gICAgICAgICAgICAgIGBXb3JrZmxvdyBleGNlZWRlZCBtYXhpbXVtIHF1ZXVlIGRlbGl2ZXJpZXMgKCR7bWV0YWRhdGEuYXR0ZW1wdH0vJHttYXhRdWV1ZURlbGl2ZXJpZXN9KWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3J1bl9mYWlsZWQnLFxuICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgIGVycm9yOiBhd2FpdCBkZWh5ZHJhdGVSdW5FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZ2V0RW5jcnlwdGlvbktleSgpXG4gICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgZXJyb3JDb2RlOiBSVU5fRVJST1JfQ09ERVMuTUFYX0RFTElWRVJJRVNfRVhDRUVERUQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikgfHwgUnVuRXhwaXJlZEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgLy8gUnVuIGFscmVhZHkgZmluaXNoZWQsIGNvbnN1bWUgdGhlIG1lc3NhZ2Ugc2lsZW50bHlcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcnVuTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIG1hcmsgcnVuIGFzIGZhaWxlZCBhZnRlciAke21ldGFkYXRhLmF0dGVtcHR9IGRlbGl2ZXJ5IGF0dGVtcHRzLiBgICtcbiAgICAgICAgICAgICAgICBgQSBwZXJzaXN0ZW50IGVycm9yIGlzIHByZXZlbnRpbmcgdGhlIHJ1biBmcm9tIGJlaW5nIHRlcm1pbmF0ZWQuIGAgK1xuICAgICAgICAgICAgICAgIGBUaGUgcnVuIHdpbGwgcmVtYWluIGluIGl0cyBjdXJyZW50IHN0YXRlIHVudGlsIG1hbnVhbGx5IHJlc29sdmVkLiBgICtcbiAgICAgICAgICAgICAgICBgVGhpcyBpcyBtb3N0IGxpa2VseSBkdWUgdG8gYSBwZXJzaXN0ZW50IG91dGFnZSBvZiB0aGUgd29ya2Zsb3cgYmFja2VuZCBgICtcbiAgICAgICAgICAgICAgICBgb3IgYSBidWcgaW4gdGhlIHdvcmtmbG93IHJ1bnRpbWUgYW5kIHNob3VsZCBiZSByZXBvcnRlZCB0byB0aGUgV29ya2Zsb3cgdGVhbS5gLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYXR0ZW1wdDogbWV0YWRhdGEuYXR0ZW1wdCxcbiAgICAgICAgICAgICAgICBlcnJvck5hbWU6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm5hbWUgOiAnVW5rbm93bkVycm9yJyxcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICAgICAgICAgICAgICBlcnJvclN0YWNrOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5zdGFjayA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gLS0tIFRyYWNlIGNvcnJlbGF0aW9uIG1vZGUgLS0tXG4gICAgICAgIC8vICdsaW5rZWQnIChkZWZhdWx0KTogdGhlIHdvcmtmbG93LmV4ZWN1dGUgc3BhbiBiZWxvdyBzdGF5cyBhIENISUxEXG4gICAgICAgIC8vIG9mIHRoZSBsb2NhbCBkZWxpdmVyeSAoZmxvdy1yb3V0ZSkgY29udGV4dCwgc28gb25lIGludm9jYXRpb24g4oCUXG4gICAgICAgIC8vIHJvdXRlIGhhbmRsZXIsIHdvcmtmbG93IHJlcGxheSwgaW5saW5lIHN0ZXBzLCBldmVudCB3cml0ZXMg4oCUIGlzIGFcbiAgICAgICAgLy8gc2luZ2xlIGJvdW5kZWQgdHJhY2UuIFRoZSBydW4tb3JpZ2luIGNvbnRleHQgdHJhdmVscyBhcyBhIHNwYW5cbiAgICAgICAgLy8gTElOSyAobm90IGEgcGFyZW50KSwgYW5kIHJlLWVucXVldWVzIGZvcndhcmQgdGhlIG9yaWdpbmFsIGNhcnJpZXJcbiAgICAgICAgLy8gdW5jaGFuZ2VkLCBzbyBhIChwb3RlbnRpYWxseSBob3Vycy1sb25nKSBydW4gaXMgbmV2ZXIgc3RpdGNoZWRcbiAgICAgICAgLy8gaW50byBvbmUgZ2lhbnQgdHJhY2UgYWNyb3NzIGludm9jYXRpb25zLlxuICAgICAgICAvLyAnY29udGludW91cyc6IGxlZ2FjeSBiZWhhdmlvciDigJQgdGhlIHJlc3RvcmVkIHJ1bi1vcmlnaW4gY29udGV4dFxuICAgICAgICAvLyBiZWNvbWVzIHRoZSBwYXJlbnQgb2YgdGhpcyBpbnZvY2F0aW9uJ3Mgc3BhbnMuXG4gICAgICAgIGNvbnN0IHRyYWNlTW9kZSA9IGdldFdvcmtmbG93VHJhY2VNb2RlKCk7XG5cbiAgICAgICAgLy8gVHJhY2UgY2FycmllciB0byBhdHRhY2ggdG8gbWVzc2FnZXMgdGhpcyBpbnZvY2F0aW9uIGVucXVldWVzIOKAlFxuICAgICAgICAvLyBzZWUgZ2V0TmV4dFRyYWNlQ2FycmllciBmb3IgdGhlIGxpbmtlZC9jb250aW51b3VzIHNlbWFudGljcy5cbiAgICAgICAgY29uc3QgbmV4dFRyYWNlQ2FycmllciA9ICgpOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+ID0+XG4gICAgICAgICAgZ2V0TmV4dFRyYWNlQ2Fycmllcih0cmFjZU1vZGUsIHRyYWNlQ29udGV4dCk7XG5cbiAgICAgICAgLy8gU3BhbiBsaW5rcyB0byB0aGUgaW5jb21pbmcgZGVsaXZlcnkgY29udGV4dCBhbmQgKGluIGxpbmtlZCBtb2RlKVxuICAgICAgICAvLyB0aGUgcnVuLW9yaWdpbiBjb250ZXh0IGZyb20gdGhlIHRyYWNlIGNhcnJpZXIuXG4gICAgICAgIGNvbnN0IHNwYW5MaW5rcyA9IGF3YWl0IGJ1aWxkSW52b2NhdGlvblNwYW5MaW5rcyhcbiAgICAgICAgICB0cmFjZU1vZGUsXG4gICAgICAgICAgdHJhY2VDb250ZXh0XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gVGhlIHJlcGxheSBidWRnZXQgY292ZXJzIG9yY2hlc3RyYXRpb24gd29yayBiZXR3ZWVuIHN0ZXBzLCBub3QgaW5saW5lXG4gICAgICAgIC8vIHN0ZXAgYm9kaWVzLiBJdCBpcyBjaGVja2VkIGJldHdlZW4gbG9vcCBpdGVyYXRpb25zOyBzdGVwIGJvZGllcyB1c2VcbiAgICAgICAgLy8gdGhlIHBsYXRmb3JtIHRpbWVvdXQgYW5kIE5PX0lOTElORV9SRVBMQVlfQUZURVJfTVMgZ3VhcmQgaW5zdGVhZC5cbiAgICAgICAgY29uc3QgcmVwbGF5QnVkZ2V0ID0gbmV3IFJlcGxheUJ1ZGdldCgpO1xuXG4gICAgICAgIC8vIEluIGxpbmtlZCBtb2RlIHRoZSBydW4tb3JpZ2luIGNvbnRleHQgaXMgTk9UIHJlc3RvcmVkIGFzIHRoZVxuICAgICAgICAvLyBhY3RpdmUgKHBhcmVudCkgY29udGV4dCDigJQgcGFzc2luZyBgdW5kZWZpbmVkYCBtYWtlc1xuICAgICAgICAvLyB3aXRoVHJhY2VDb250ZXh0IGEgcGFzc3Rocm91Z2gsIHNvIHRoZSB3b3JrZmxvdy5leGVjdXRlIHNwYW4gYmVsb3dcbiAgICAgICAgLy8gc3RheXMgYSBjaGlsZCBvZiB0aGUgbG9jYWwgZGVsaXZlcnkgKGZsb3ctcm91dGUpIGNvbnRleHQgYW5kIHRoZVxuICAgICAgICAvLyBydW4tb3JpZ2luIHRyYXZlbHMgYXMgYSBzcGFuIGxpbmsgaW5zdGVhZC5cbiAgICAgICAgY29uc3QgcGFyZW50VHJhY2VDYXJyaWVyID1cbiAgICAgICAgICB0cmFjZU1vZGUgPT09ICdjb250aW51b3VzJyA/IHRyYWNlQ29udGV4dCA6IHVuZGVmaW5lZDtcbiAgICAgICAgLy8gUXVldWUtZGVsaXZlcmVkIGludm9jYXRpb246IENPTlNVTUVSIGtpbmQsIG1hdGNoaW5nIHRoZVxuICAgICAgICAvLyBxdWV1ZS1kZWxpdmVyZWQgc3RlcC5leGVjdXRlIHNwYW4uXG4gICAgICAgIGNvbnN0IHNwYW5LaW5kID0gYXdhaXQgZ2V0U3BhbktpbmQoJ0NPTlNVTUVSJyk7XG4gICAgICAgIHJldHVybiBhd2FpdCB3aXRoVHJhY2VDb250ZXh0KHBhcmVudFRyYWNlQ2FycmllciwgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHJldHVybiBhd2FpdCB3aXRoV29ya2Zsb3dCYWdnYWdlKFxuICAgICAgICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCwgd29ya2Zsb3dOYW1lIH0sXG4gICAgICAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgdHJhY2UoJ3dvcmtmbG93LnJvdXRlLmdldF93b3JsZCcsIGFzeW5jICgpID0+XG4gICAgICAgICAgICAgICAgZ2V0V29ybGQoKVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAvLyBCb3RoIGNoZWNrcyBiZWxvdyBsb29rIGF0IGBydW5JbnB1dGAsIHNvIGJvdGggYXJlIG5vLW9wcyBvbiBhXG4gICAgICAgICAgICAgIC8vIHJlLWVucXVldWVkIG1lc3NhZ2UgKHdoaWNoIGNhcnJpZXMgbm9uZSkg4oCUIHRoZXkgb25seSBldmVyIHJ1biBvblxuICAgICAgICAgICAgICAvLyBhIGZpcnN0IGRlbGl2ZXJ5LCB0aGUgb25lIHRoYXQgY291bGQgY3JlYXRlIHRoZSBydW4uXG4gICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgIC8vIFJldHVybmluZyBhY2tzIHRoZSBtZXNzYWdlLiBUaGF0IGlzIGRlbGliZXJhdGU6IHRoZSBtaXNtYXRjaCBpc1xuICAgICAgICAgICAgICAvLyBiYWtlZCBpbnRvIHRoaXMgbWVzc2FnZSwgc28gZXZlcnkgcmVkZWxpdmVyeSB3b3VsZCByZWFjaCB0aGVcbiAgICAgICAgICAgICAgLy8gc2FtZSB2ZXJkaWN0LCBhbmQgdGhyb3dpbmcgd291bGQganVzdCBob3QtbG9vcCB0aGUgaGFuZGxlciB1bnRpbFxuICAgICAgICAgICAgICAvLyBNQVhfUVVFVUVfREVMSVZFUklFUyB3aXRoIHRoZSBzYW1lIGVycm9yIGVhY2ggdGltZS4gSXQgbWF0Y2hlc1xuICAgICAgICAgICAgICAvLyBob3cgdGhlIHJ1bl9zdGFydGVkIHBhdGggYWxyZWFkeSBkaXNjYXJkcyBkZWxpdmVyaWVzIHdob3NlXG4gICAgICAgICAgICAgIC8vIHZlcmRpY3QgY2Fubm90IGNoYW5nZSAoRW50aXR5Q29uZmxpY3RFcnJvciwgUnVuRXhwaXJlZEVycm9yKS5cbiAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIHJlZnVzZUNyb3NzRW52aXJvbm1lbnREZWxpdmVyeSh7XG4gICAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICAgIHJ1bklucHV0LFxuICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICBydW5Mb2dnZXIsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIERpYWdub3N0aWMgb25seSDigJQgc2VlIHRoZSBoZWxwZXIgZm9yIHdoeSB0aGlzIHdhcm5zIGluc3RlYWQgb2ZcbiAgICAgICAgICAgICAgLy8gcmVmdXNpbmcgdGhlIGludm9jYXRpb24uXG4gICAgICAgICAgICAgIGF3YWl0IHdhcm5PbkRlcGxveW1lbnRQaW5uaW5nTWlzbWF0Y2goe1xuICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgIHJ1bklucHV0LFxuICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgIHJ1bkxvZ2dlcixcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybiB0cmFjZShcbiAgICAgICAgICAgICAgICBgd29ya2Zsb3cuZXhlY3V0ZSAke3dvcmtmbG93RGlzcGxheU5hbWUod29ya2Zsb3dOYW1lKX1gLFxuICAgICAgICAgICAgICAgIHsga2luZDogc3BhbktpbmQsIGxpbmtzOiBzcGFuTGlua3MgfSxcbiAgICAgICAgICAgICAgICBhc3luYyAoc3BhbikgPT4ge1xuICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd05hbWUod29ya2Zsb3dOYW1lKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93T3BlcmF0aW9uKCdleGVjdXRlX3YyJyksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdTeXN0ZW0oJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nRGVzdGluYXRpb25OYW1lKG1ldGFkYXRhLnF1ZXVlTmFtZSksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdNZXNzYWdlSWQobWV0YWRhdGEubWVzc2FnZUlkKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ09wZXJhdGlvblR5cGUoJ3Byb2Nlc3MnKSxcbiAgICAgICAgICAgICAgICAgICAgLi4uZ2V0UXVldWVPdmVyaGVhZCh7IHJlcXVlc3RlZEF0IH0pLFxuICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5JZChydW5JZCksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1RyYWNlUHJvcGFnYXRlZCghIXRyYWNlQ29udGV4dCksXG4gICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1RyYWNlTW9kZSh0cmFjZU1vZGUpLFxuICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IGludm9jYXRpb25TdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgICAgY29uc3Qgbm9JbmxpbmVSZXBsYXlBZnRlck1zID0gYXdhaXQgZ2V0TWF4SW5saW5lRHVyYXRpb25NcyhcbiAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgIGludm9jYXRpb25TdGFydFRpbWVcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICBsZXQgbG9vcEl0ZXJhdGlvbiA9IDA7XG4gICAgICAgICAgICAgICAgICBjb25zdCByZXBsYXlSZWNvdmVyeVJlcG9ydGVyID0gcmVwbGF5RGl2ZXJnZW5jZVxuICAgICAgICAgICAgICAgICAgICA/IG5ldyBSZXBsYXlSZWNvdmVyeVJlcG9ydGVyKHJlcGxheURpdmVyZ2VuY2UuY291bnQpXG4gICAgICAgICAgICAgICAgICAgIDogUmVwbGF5UmVjb3ZlcnlSZXBvcnRlci5pbmVydCgpO1xuICAgICAgICAgICAgICAgICAgLy8gRXZlcnkgd3JpdGUgdGhpcyBsb29wIG1ha2VzIGNhcnJpZXMgdGhlIGN1cnNvciBvZiB0aGUgbG9nXG4gICAgICAgICAgICAgICAgICAvLyBpdCB3YXMgY29tcHV0ZWQgYWdhaW5zdCwgYW5kIGZvbGRzIGEgY29tcGxldGUgcmV0dXJuZWRcbiAgICAgICAgICAgICAgICAgIC8vIGRlbHRhIGludG8gdGhhdCBsb2cuXG4gICAgICAgICAgICAgICAgICBjb25zdCBjcmVhdGVFdmVudCA9IGFzeW5jIDxUIGV4dGVuZHMgQ3JlYXRlRXZlbnRSZXF1ZXN0PihcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogVCxcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zPzogQ3JlYXRlRXZlbnRQYXJhbXNcbiAgICAgICAgICAgICAgICAgICkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzaW5jZUN1cnNvciA9IGRlbHRhUmVxdWVzdEN1cnNvcihkYXRhLCBwYXJhbXMpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZXBsYXlSZWNvdmVyeVJlcG9ydGVyLndpdGhFdmVudENyZWF0ZShcbiAgICAgICAgICAgICAgICAgICAgICBzaW5jZUN1cnNvciA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICA/IHBhcmFtc1xuICAgICAgICAgICAgICAgICAgICAgICAgOiB7IC4uLnBhcmFtcywgc2luY2VDdXJzb3IgfSxcbiAgICAgICAgICAgICAgICAgICAgICAocCkgPT4gd29ybGQuZXZlbnRzLmNyZWF0ZShydW5JZCwgZGF0YSwgcClcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNpbmNlQ3Vyc29yICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICBhYnNvcmJDcmVhdGVEZWx0YShzaW5jZUN1cnNvciwgcmVzdWx0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICAgKiBUaGUgY3Vyc29yIHRvIGFzayBmb3IgYW4gaW5saW5lIGRlbHRhIGFnYWluc3QsIG9yXG4gICAgICAgICAgICAgICAgICAgKiB1bmRlZmluZWQgdG8gbm90IGFzay5cbiAgICAgICAgICAgICAgICAgICAqXG4gICAgICAgICAgICAgICAgICAgKiBUdXJibyBpcyBleGNsdWRlZCBvbiBwdXJwb3NlOiBpdCBleGlzdHMgdG8gbWFrZSB0aGUgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAqIGludm9jYXRpb24ncyB3cml0ZXMgYXMgY2hlYXAgYXMgcG9zc2libGUsIGFuZCBpdCBoYXMgbm9cbiAgICAgICAgICAgICAgICAgICAqIGxvYWRlZCBsb2cgdG8gZXh0ZW5kLiBSdW4tdGVybWluYWwgd3JpdGVzIGFyZSBleGNsdWRlZFxuICAgICAgICAgICAgICAgICAgICogYmVjYXVzZSBub3RoaW5nIHJlYWRzIHRoZSBsb2cgYWZ0ZXJ3YXJkcywgc28gdGhlIGRlbHRhXG4gICAgICAgICAgICAgICAgICAgKiB3b3VsZCBiZSB3b3JrIHRoZSBXb3JsZCBkb2VzIGZvciBubyBvbmUuIEEgY2FsbGVyIHRoYXRcbiAgICAgICAgICAgICAgICAgICAqIHNldCBpdHMgb3duIGBzaW5jZUN1cnNvcmAgKG9yIGFza2VkIGZvciB0aGUgYHJ1bl9zdGFydGVkYFxuICAgICAgICAgICAgICAgICAgICogLyBgaG9va19yZWNlaXZlZGAgcHJlbG9hZCwgd2hpY2ggb3ducyB0aGUgc2FtZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICogZmllbGRzKSBrZWVwcyB3aGF0IGl0IGFza2VkIGZvci5cbiAgICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgICAgY29uc3QgZGVsdGFSZXF1ZXN0Q3Vyc29yID0gKFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiBDcmVhdGVFdmVudFJlcXVlc3QsXG4gICAgICAgICAgICAgICAgICAgIHBhcmFtczogQ3JlYXRlRXZlbnRQYXJhbXMgfCB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICk6IHN0cmluZyB8IHVuZGVmaW5lZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICB0dXJibyB8fFxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgIT09ICdyZWFkeScgfHxcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXM/LnNpbmNlQ3Vyc29yICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXM/LnByZWxvYWRFdmVudHMgPT09IHRydWUgfHxcbiAgICAgICAgICAgICAgICAgICAgICBpc1Rlcm1pbmFsUnVuRXZlbnRUeXBlKGRhdGEuZXZlbnRUeXBlKVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBldmVudExvZy5jdXJzb3IgPz8gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICAgKiBGb2xkIGFuIGlubGluZSBkZWx0YSByZXR1cm5lZCBieSBgZXZlbnRzLmNyZWF0ZWAgaW50byB0aGVcbiAgICAgICAgICAgICAgICAgICAqIGluLW1lbW9yeSBldmVudCBsb2cuXG4gICAgICAgICAgICAgICAgICAgKlxuICAgICAgICAgICAgICAgICAgICogVGhlIGRlbHRhIGlzIHdoYXQgYGV2ZW50cy5saXN0KHsgY3Vyc29yOiBzZW50Q3Vyc29yIH0pYFxuICAgICAgICAgICAgICAgICAgICogd291bGQgaGF2ZSByZXR1cm5lZCByaWdodCBhZnRlciB0aGUgd3JpdGUsIHNvIGl0IGNhcnJpZXNcbiAgICAgICAgICAgICAgICAgICAqIGJhY2sgYm90aCBvdXIgb3duIGV2ZW50IGFuZCBhbnl0aGluZyBhbm90aGVyIHdyaXRlclxuICAgICAgICAgICAgICAgICAgICogYXBwZW5kZWQgaW4gYmFuZC4gQWJzb3JiaW5nIGl0IGhlcmUgbWVhbnMgdGhlIG5leHQgcmVhZGVyXG4gICAgICAgICAgICAgICAgICAgKiBhbHJlYWR5IGhhcyB0aGUgbG9nIGFuZCB0aGUgbG9vcCdzIGluY3JlbWVudGFsXG4gICAgICAgICAgICAgICAgICAgKiBgZXZlbnRzLmxpc3RgIGZpbmRzIG5vdGhpbmcgbGVmdCB0byBmZXRjaC5cbiAgICAgICAgICAgICAgICAgICAqXG4gICAgICAgICAgICAgICAgICAgKiBEZWNsaW5pbmcgaXMgYWx3YXlzIHNhZmUg4oCUIGFuIHVuYWJzb3JiZWQgZGVsdGEgaXMgYSBkZWx0YVxuICAgICAgICAgICAgICAgICAgICogdGhlIG5leHQgYGV2ZW50cy5saXN0YCByZXR1cm5zIOKAlCBzbyB0aGUgZ3VhcmRzIGFyZSBmcmVlIHRvXG4gICAgICAgICAgICAgICAgICAgKiBiZSBzdHJpY3Q6XG4gICAgICAgICAgICAgICAgICAgKlxuICAgICAgICAgICAgICAgICAgICogLSBgaGFzTW9yZWAgbWVhbnMgdGhlIFdvcmxkIHRydW5jYXRlZCB0aGUgcGFnZS4gVGFraW5nIGl0XG4gICAgICAgICAgICAgICAgICAgKiAgIHdoaWxlIGFkdmFuY2luZyB0aGUgY3Vyc29yIHRvIHRoZSBwYWdlIGVuZCB3b3VsZCBiZVxuICAgICAgICAgICAgICAgICAgICogICBmaW5lLCBidXQgdGFraW5nIGl0IGFuZCBOT1QgYWR2YW5jaW5nIHdvdWxkIGR1cGxpY2F0ZSxcbiAgICAgICAgICAgICAgICAgICAqICAgYW5kIHRoZSB0cnVuY2F0ZWQgY2FzZSBpcyByYXJlIGVub3VnaCBub3QgdG8gc3BlY2lhbC1jYXNlLlxuICAgICAgICAgICAgICAgICAgICogLSBUaGUgY3Vyc29yIG11c3QgYmUgZXhhY3RseSB3aGVyZSBpdCB3YXMgd2hlbiB0aGUgcmVxdWVzdFxuICAgICAgICAgICAgICAgICAgICogICB3ZW50IG91dC4gQ29uY3VycmVudCB3cml0ZXMgZWFjaCBkaWZmIGFnYWluc3QgdGhlIGN1cnNvclxuICAgICAgICAgICAgICAgICAgICogICB0aGV5IHNhdywgYW5kIGBhcHBlbmRVbmlxdWVFdmVudHNgIGRlbGliZXJhdGVseSBkb2VzIG5vdFxuICAgICAgICAgICAgICAgICAgICogICByZS1zb3J0LCBzbyBhYnNvcmJpbmcgYSBzZWNvbmQgZGVsdGEgY29tcHV0ZWQgZnJvbSBhblxuICAgICAgICAgICAgICAgICAgICogICBvbGRlciBjdXJzb3IgY291bGQgYXBwZW5kIGV2ZW50cyBiZWhpbmQgb25lcyBhbHJlYWR5XG4gICAgICAgICAgICAgICAgICAgKiAgIHRha2VuLiBGaXJzdCByZXNwb25zZSBiYWNrIHdpbnM7IHRoZSByZXN0IGFyZSBkcm9wcGVkLlxuICAgICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgICBjb25zdCBhYnNvcmJDcmVhdGVEZWx0YSA9IChcbiAgICAgICAgICAgICAgICAgICAgc2VudEN1cnNvcjogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICByZXN1bHQ6IEV2ZW50UmVzdWx0XG4gICAgICAgICAgICAgICAgICApOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgIT09ICdyZWFkeScgfHxcbiAgICAgICAgICAgICAgICAgICAgICBldmVudExvZy5jdXJzb3IgIT09IHNlbnRDdXJzb3IgfHxcbiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuZXZlbnRzID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuaGFzTW9yZSA9PT0gdHJ1ZVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYXBwZW5kRXZlbnRMb2coZXZlbnRMb2csIHtcbiAgICAgICAgICAgICAgICAgICAgICBldmVudHM6IHJlc3VsdC5ldmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiByZXN1bHQuY3Vyc29yLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgIC8vIGByZWFkeWAgY2FuIHJlcGxheSBvbmNlIHdpdGhvdXQgYSByZWFkLiBUaGUgb3RoZXIgc3RhdGVzXG4gICAgICAgICAgICAgICAgICAvLyBkZXNjcmliZSB0aGUgbmV4dCBsb2FkIGV4YWN0bHkuXG4gICAgICAgICAgICAgICAgICBsZXQgZXZlbnRMb2c6IFJlcGxheUV2ZW50TG9nID0geyB0eXBlOiAnbG9hZEFsbCcgfTtcblxuICAgICAgICAgICAgICAgICAgLy8gU2hhcmVkIHN0YXRlOiBzZXQgYnkgZWl0aGVyIHRoZSBiYWNrZ3JvdW5kIHN0ZXAgcGF0aFxuICAgICAgICAgICAgICAgICAgLy8gb3IgdGhlIHJ1bl9zdGFydGVkIHNldHVwIGJlbG93LlxuICAgICAgICAgICAgICAgICAgbGV0IHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1biB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIC8vIFNlcnZlci1zdXBwbGllZCBwZXItcnVuIGV2ZW50IGNlaWxpbmcgZnJvbSB0aGUgcnVuX3N0YXJ0ZWRcbiAgICAgICAgICAgICAgICAgIC8vIHJlc3BvbnNlLiBVbmRlZmluZWQg4oeSIG5vIGVuZm9yY2VtZW50IChvbGRlciBzZXJ2ZXJzLCB0dXJibykuXG4gICAgICAgICAgICAgICAgICBsZXQgbWF4RXZlbnRzTGltaXQ6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIGxldCB3b3JrZmxvd1N0YXJ0ZWRBdCA9IC0xO1xuXG4gICAgICAgICAgICAgICAgICAvLyBMYXRlbmN5IHRlbGVtZXRyeSAoVFRGUykgc3RhdGUg4oCUIHNlZSBydW50aW1lL3N0ZXAtbGF0ZW5jeS50cy5cbiAgICAgICAgICAgICAgICAgIC8vIFdoZXRoZXIgdGhpcyBpbnZvY2F0aW9uJ3MgRklSU1QgZXZlbnQgc25hcHNob3QgY29udGFpbmVkXG4gICAgICAgICAgICAgICAgICAvLyBub3RoaW5nIGJleW9uZCBydW5fY3JlYXRlZC9ydW5fc3RhcnRlZDogYW55dGhpbmcgZWxzZSB3YXNcbiAgICAgICAgICAgICAgICAgIC8vIHdyaXR0ZW4gYnkgYW4gZWFybGllciBpbnZvY2F0aW9uLCB3aG9zZSBjb250cmlidXRpb24gdG9cbiAgICAgICAgICAgICAgICAgIC8vIHRpbWUtdG8tZmlyc3Qtc3RlcCAoaW5jbHVkaW5nIHRoZSBxdWV1ZSBob3AgYmFjayBoZXJlKVxuICAgICAgICAgICAgICAgICAgLy8gY2Fubm90IGJlIG1lYXN1cmVkIHdhbGwtY2xvY2ssIHNvIFRURlMgaXMgbm90IHJlcG9ydGVkLlxuICAgICAgICAgICAgICAgICAgLy8gU2V0IG9uY2UsIG9uIHRoZSBmaXJzdCBpdGVyYXRpb24ncyBsb2FkZWQgc25hcHNob3QuXG4gICAgICAgICAgICAgICAgICBsZXQgaW52b2NhdGlvblN0YXJ0ZWRDbGVhbjogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgIC8vIEVwb2NoIG1zIHRoZSBgcnVuX3N0YXJ0ZWRgIHJlc3BvbnNlIHdhcyByZWNlaXZlZC9wYXJzZWRcbiAgICAgICAgICAgICAgICAgIC8vIGJ5IHRoZSBTREsg4oCUIGFuY2hvcnMgUlNGUyAocnVuX3N0YXJ0ZWQg4oaSIGZpcnN0IHN0ZXAnc1xuICAgICAgICAgICAgICAgICAgLy8gc3RhcnQgUE9TVCkuIFNldCBvbmNlLCBpbiB0aGUgcnVuX3N0YXJ0ZWQgc2V0dXAgYmVsb3cuXG4gICAgICAgICAgICAgICAgICAvLyBVbmRlciB0dXJibywgcnVuX3N0YXJ0ZWQgaXMgYmFja2dyb3VuZGVkIHJhdGhlciB0aGFuXG4gICAgICAgICAgICAgICAgICAvLyBhd2FpdGVkLCBzbyB0aGlzIGlzIHN0YW1wZWQgYXQgdGhlIHBvaW50IHRoZSBydW4gaXNcbiAgICAgICAgICAgICAgICAgIC8vIHN5bnRoZXNpemVkIGxvY2FsbHkgaW5zdGVhZCBvZiB0aGUgcmVhbCByZXNwb25zZSDigJQgc2VlXG4gICAgICAgICAgICAgICAgICAvLyBTdGVwTGF0ZW5jeVRyYWNraW5nLnJzZnNBbmNob3JNcy5cbiAgICAgICAgICAgICAgICAgIGxldCBydW5TdGFydGVkUmVjZWl2ZWRBdE1zOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAvLyBXYWxsLWNsb2NrIG1zIHNwZW50IGNvbW1pdHRpbmcgaG9va19jcmVhdGVkIGV2ZW50cyBiZWZvcmVcbiAgICAgICAgICAgICAgICAgIC8vIHRoZSBmaXJzdCBzdGVwIHJhbiwgYWNjdW11bGF0ZWQgYWNyb3NzIHN1c3BlbnNpb24gcGFzc2VzXG4gICAgICAgICAgICAgICAgICAvLyBhbmQgc3VidHJhY3RlZCBmcm9tIFRURlMuIEFjY3VtdWxhdG9ycyBoZXJlIHN1cnZpdmUgYW5cbiAgICAgICAgICAgICAgICAgIC8vIGluLXByb2Nlc3MgcmVwbGF5IHJlc3RhcnQgKGEgc3RhbGUtc25hcHNob3QgcmVqZWN0aW9uLCBvclxuICAgICAgICAgICAgICAgICAgLy8gdGhlIGF0dHJpYnV0ZS1ldmVudCByZXN0YXJ0IGJlbG93KSwgc28gYSByZXN0YXJ0ZWRcbiAgICAgICAgICAgICAgICAgIC8vIGludm9jYXRpb24gb3Zlci1jb3VudHMgYnkgdGhlIGFiYW5kb25lZCBwYXNzJ3MgaG9vayB0aW1lIOKAlFxuICAgICAgICAgICAgICAgICAgLy8gdGhlIHNhbWUgc2xpZ2h0IG92ZXItY291bnQgZWl0aGVyIHJlc3RhcnQgaGFzIGFsd2F5cyBoYWQuXG4gICAgICAgICAgICAgICAgICBsZXQgcHJlU3RlcEJsb2NraW5nTXMgPSAwO1xuICAgICAgICAgICAgICAgICAgLy8gU25hcHNob3Qgb2YgdGhlIGFjY3VtdWxhdG9yIGFzIG9mIHRoZSBzdXNwZW5zaW9uIHRoYXRcbiAgICAgICAgICAgICAgICAgIC8vIHdyb3RlIHRoZSBydW4ncyBmaXJzdCBhdHRyX3NldCAod2hvc2UgaG9vayBwaGFzZSByYW5cbiAgICAgICAgICAgICAgICAgIC8vIGJlZm9yZSBpdHMgYXR0ciB3cml0ZXMpLiBXaGVuIGEgcHJlLXN0ZXAgc2V0QXR0cmlidXRlc1xuICAgICAgICAgICAgICAgICAgLy8gZW5kcyB0aGUgVFRGUyBtZWFzdXJlbWVudCBhdCB0aGUgYXR0ciB3cml0ZSwgb25seSBob29rXG4gICAgICAgICAgICAgICAgICAvLyB0aW1lIGZyb20gQkVGT1JFIHRoYXQgcG9pbnQgbWF5IGJlIHN1YnRyYWN0ZWQg4oCUIGxhdGVyXG4gICAgICAgICAgICAgICAgICAvLyBob29rIHdyaXRlcyBmYWxsIG91dHNpZGUgdGhlIG1lYXN1cmVkIHdpbmRvdy5cbiAgICAgICAgICAgICAgICAgIGxldCBwcmVTdGVwQmxvY2tpbmdCZWZvcmVBdHRyTXM6IG51bWJlciB8IHVuZGVmaW5lZDtcblxuICAgICAgICAgICAgICAgICAgLy8gVHVyYm8gbW9kZSBmYXN0LXBhdGhzIHRoZSB2ZXJ5IGZpcnN0IGRlbGl2ZXJ5IG9mIHRoZSB2ZXJ5XG4gICAgICAgICAgICAgICAgICAvLyBmaXJzdCBpbnZvY2F0aW9uLCB3aGVyZSBpdCBpcyBwcm92YWJseSBzYWZlIHRvOiBiYWNrZ3JvdW5kXG4gICAgICAgICAgICAgICAgICAvLyBgcnVuX3N0YXJ0ZWRgLCBza2lwIHRoZSBpbml0aWFsIGV2ZW50LWxvZyBsb2FkIChub3RoaW5nIGhhc1xuICAgICAgICAgICAgICAgICAgLy8gYmVlbiB3cml0dGVuIHlldCksIGFuZCBmb3JjZSBvcHRpbWlzdGljIGlubGluZSBzdGFydCAobm9cbiAgICAgICAgICAgICAgICAgIC8vIGNvbmN1cnJlbnQgcGVlciBoYW5kbGVyIGV4aXN0cyB0byByYWNlIHRoZSBjcmVhdGUtY2xhaW0pLlxuICAgICAgICAgICAgICAgICAgLy8gYHJ1bklucHV0YCBpcyBvbmx5IHByZXNlbnQgb24gdGhlIHN0YXJ0KCktZW5xdWV1ZWQgbWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgIC8vIGFuZCBgYXR0ZW1wdCA9PT0gMWAgKDEtYmFzZWQpIG1lYW5zIHRoaXMgaXMgdGhlIGZpcnN0XG4gICAgICAgICAgICAgICAgICAvLyBkZWxpdmVyeTsgYGluY29taW5nU3RlcElkYCB3b3VsZCBtYXJrIGEgYmFja2dyb3VuZC1zdGVwXG4gICAgICAgICAgICAgICAgICAvLyBpbnZvY2F0aW9uIGFuZCBgcmVwbGF5RGl2ZXJnZW5jZWAgYSByZWNvdmVyeSByZXBsYXkg4oCUIGJvdGhcbiAgICAgICAgICAgICAgICAgIC8vIGluZWxpZ2libGUuIFRoZSBzaW5nbGUtaGFuZGxlciBndWFyYW50ZWUgdGhhdCBtYWtlcyBmb3JjZWRcbiAgICAgICAgICAgICAgICAgIC8vIG9wdGltaXN0aWMgc3RhcnQgc2FmZSBlbmRzIG9uY2UgYSBob29rIG9yIHdhaXQgaXMgY3JlYXRlZFxuICAgICAgICAgICAgICAgICAgLy8gKHRoZXkgaW50cm9kdWNlIHJlc3VtZSBpbnZvY2F0aW9ucyksIHNvIHR1cmJvIGV4aXRzIGF0IHRoYXRcbiAgICAgICAgICAgICAgICAgIC8vIHBvaW50IChzZWUgYGZvcmNlT3B0aW1pc3RpY1N0YXJ0YCkuIFdvcmtmbG93IGF0dHJpYnV0ZVxuICAgICAgICAgICAgICAgICAgLy8gd3JpdGVzIGludHJvZHVjZSBubyBzdWNoIGludm9jYXRpb24gc291cmNlIOKAlCB0aGV5IHJlc29sdmVcbiAgICAgICAgICAgICAgICAgIC8vIHZpYSBhbiBpbi1wcm9jZXNzIHJlcGxheSBhbmQgZG9uJ3QgZW5kIHR1cmJvLlxuICAgICAgICAgICAgICAgICAgLy8gTk9URTogYG1ldGFkYXRhLmF0dGVtcHQgPT09IDFgIGlzIGFsc28gbG9hZC1iZWFyaW5nIGZvclxuICAgICAgICAgICAgICAgICAgLy8gaW5saW5lIHN0ZXAgb3duZXJzaGlwOiBvd25lZC1yZWNvdmVyeSBzdGVwcyAoYSBzdGVwXG4gICAgICAgICAgICAgICAgICAvLyBzdGFtcGVkIGJ5IGEgUFJFVklPVVMgZGVsaXZlcnkgb2YgdGhpcyBtZXNzYWdlKSBjYW4gb25seVxuICAgICAgICAgICAgICAgICAgLy8gZXhpc3Qgb24gYXR0ZW1wdCDiiaUgMiwgc28gdHVyYm8gYW5kIG93bmVkIHJlY292ZXJ5IGFyZVxuICAgICAgICAgICAgICAgICAgLy8gbXV0dWFsbHkgZXhjbHVzaXZlLiBUaGUgdHVyYm8gYHJlaW52b2tlKClgIHBhdGhzIChob29rXG4gICAgICAgICAgICAgICAgICAvLyBjb25mbGljdCwgdGhyb3R0bGUgYmFja29mZikgYWNrIHRoaXMgbWVzc2FnZSBhbmQgY29udGludWVcbiAgICAgICAgICAgICAgICAgIC8vIHVuZGVyIGEgTkVXIG1lc3NhZ2UgaWQg4oCUIHNhZmUgb25seSBiZWNhdXNlIG5vXG4gICAgICAgICAgICAgICAgICAvLyBub24tdGVybWluYWwgc3RlcCBjYW4gYmUgaW5saW5lLW93bmVkIGJ5IHRoZSBhY2tlZCBpZFxuICAgICAgICAgICAgICAgICAgLy8gd2hlbiB0dXJibyBpcyBvbi4gSWYgdHVyYm8gZXZlciBlbmdhZ2VzIG9uIHJlZGVsaXZlcmllcyxcbiAgICAgICAgICAgICAgICAgIC8vIHRob3NlIHBhdGhzIG11c3QgZmlyc3QgY2hlY2sgZm9yIG93bmVkIHBlbmRpbmcgc3RlcHMgYW5kXG4gICAgICAgICAgICAgICAgICAvLyBmYWxsIGJhY2sgdG8gYHsgdGltZW91dFNlY29uZHMgfWAgcmVkZWxpdmVyeS5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IHR1cmJvID1cbiAgICAgICAgICAgICAgICAgICAgaXNUdXJib0VuYWJsZWQoKSAmJlxuICAgICAgICAgICAgICAgICAgICBydW5JbnB1dCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLmF0dGVtcHQgPT09IDEgJiZcbiAgICAgICAgICAgICAgICAgICAgaW5jb21pbmdTdGVwSWQgPT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgICAgICAgICAhcmVwbGF5RGl2ZXJnZW5jZTtcbiAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoQXR0cmlidXRlLldvcmtmbG93VHVyYm8odHVyYm8pKTtcblxuICAgICAgICAgICAgICAgICAgLy8gVHVyYm8gbW9kZSBvbmx5OiByZXNvbHZlcyBvbmNlIHRoZSBiYWNrZ3JvdW5kZWRcbiAgICAgICAgICAgICAgICAgIC8vIGBydW5fc3RhcnRlZGAgaGFzIGxhbmRlZCAob3IgcmVqZWN0cyBpZiBpdCBmYWlsZWQpLiBUaHJlYWRlZFxuICAgICAgICAgICAgICAgICAgLy8gaW50byBoYW5kbGVTdXNwZW5zaW9uIGFuZCBleGVjdXRlU3RlcCBzbyBubyBzdGVwL2hvb2svd2FpdFxuICAgICAgICAgICAgICAgICAgLy8gd3JpdGUgcmFjZXMgYWhlYWQgb2YgdGhlIHJ1bidzIGNyZWF0aW9uLiBVbmRlZmluZWQgb3V0c2lkZVxuICAgICAgICAgICAgICAgICAgLy8gdHVyYm8sIHdoZXJlIGBydW5fc3RhcnRlZGAgaXMgYXdhaXRlZCB1cCBmcm9udC5cbiAgICAgICAgICAgICAgICAgIGxldCBydW5SZWFkeUJhcnJpZXI6IFByb21pc2U8dW5rbm93bj4gfCB1bmRlZmluZWQ7XG5cbiAgICAgICAgICAgICAgICAgIC8vIE9yZGVyIGEgdGVybWluYWwgcnVuIHdyaXRlIChydW5fY29tcGxldGVkIC8gcnVuX2ZhaWxlZCkgYWZ0ZXJcbiAgICAgICAgICAgICAgICAgIC8vIHRoZSBiYWNrZ3JvdW5kZWQgcnVuX3N0YXJ0ZWQgaW4gdHVyYm8gbW9kZSDigJQgYSBuby1zdGVwXG4gICAgICAgICAgICAgICAgICAvLyB3b3JrZmxvdyBjYW4gb3RoZXJ3aXNlIHJlYWNoIHJ1bl9jb21wbGV0ZWQgYmVmb3JlIHRoZSBydW5cbiAgICAgICAgICAgICAgICAgIC8vIGV4aXN0cy4gQmVzdC1lZmZvcnQ6IGEgYmFycmllciByZWplY3Rpb24gaXMgc3dhbGxvd2VkIGZvclxuICAgICAgICAgICAgICAgICAgLy8gb3JkZXJpbmcgb25seTsgaWYgcnVuX3N0YXJ0ZWQgdHJ1bHkgZmFpbGVkIHRoZSB0ZXJtaW5hbCB3cml0ZVxuICAgICAgICAgICAgICAgICAgLy8gc3VyZmFjZXMgdGhlIHJlYWwgZXJyb3IgKHJ1biBub3QgZm91bmQgLyBnb25lKSBhbmQgdGhlIG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgIC8vIHJlZGVsaXZlcnMuIE5vLW9wIG91dHNpZGUgdHVyYm8uXG4gICAgICAgICAgICAgICAgICBjb25zdCBhd2FpdFJ1blJlYWR5ID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAocnVuUmVhZHlCYXJyaWVyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHJ1blJlYWR5QmFycmllcjtcbiAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGludGVudGlvbmFsOiBvcmRlcmluZyBiYXJyaWVyIG9ubHkg4oCUIHNlZSBhYm92ZS5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgIC8vIFJlLWludm9rZSB0aGUgb3JjaGVzdHJhdG9yLiBPdXRzaWRlIHR1cmJvIHRoaXMgcmV0dXJuc1xuICAgICAgICAgICAgICAgICAgLy8gYHsgdGltZW91dFNlY29uZHMgfWAsIHdoaWNoIG1ha2VzIHRoZSBxdWV1ZSByZXNjaGVkdWxlIHRoZVxuICAgICAgICAgICAgICAgICAgLy8gQ1VSUkVOVCBkZWxpdmVyeSdzIG1lc3NhZ2UuIEluIHR1cmJvIHRoYXQgaXMgYSB0cmFwOiB0aGVcbiAgICAgICAgICAgICAgICAgIC8vIGN1cnJlbnQgbWVzc2FnZSBjYXJyaWVzIGBydW5JbnB1dGAsIGFuZCBvbiBhc3luYyBxdWV1ZXNcbiAgICAgICAgICAgICAgICAgIC8vIChlLmcuIGdyYXBoaWxlLXdvcmtlcikgYSByZXNjaGVkdWxlIGNvbWVzIGJhY2sgYXMgZGVsaXZlcnlcbiAgICAgICAgICAgICAgICAgIC8vIGF0dGVtcHQgMSDigJQgc28gdHVyYm8gcmUtZW5nYWdlcywgc2tpcHMgdGhlIGV2ZW50LWxvZyBsb2FkXG4gICAgICAgICAgICAgICAgICAvLyBhZ2FpbiwgcmVwbGF5cyBhZ2FpbnN0IGFuIGVtcHR5IGxvZywgbmV2ZXIgb2JzZXJ2ZXMgdGhlXG4gICAgICAgICAgICAgICAgICAvLyBob29rIGV2ZW50IHRoaXMgaW52b2NhdGlvbiBqdXN0IHdyb3RlLCBhbmQgcmUtc3VzcGVuZHNcbiAgICAgICAgICAgICAgICAgIC8vIGZvcmV2ZXIgKHRoZSBydW4gd2VkZ2VzKS4gVW5kZXIgdHVyYm8gd2UgaW5zdGVhZCBlbnF1ZXVlIGFuXG4gICAgICAgICAgICAgICAgICAvLyBleHBsaWNpdCBjb250aW51YXRpb24gdGhhdCBjYXJyaWVzIE5PIGBydW5JbnB1dGAsIHNvIHRoZVxuICAgICAgICAgICAgICAgICAgLy8gbmV4dCBkZWxpdmVyeSBpcyBhIG5vcm1hbCAobm9uLXR1cmJvKSBsb2FkLWFuZC1yZXBsYXkgdGhhdFxuICAgICAgICAgICAgICAgICAgLy8gb2JzZXJ2ZXMgdGhlIGNvbW1pdHRlZCBldmVudHMgYW5kIG1ha2VzIHByb2dyZXNzOyB3ZSB0aGVuXG4gICAgICAgICAgICAgICAgICAvLyByZXR1cm4gYHVuZGVmaW5lZGAgc28gdGhlIHF1ZXVlIHRyZWF0cyB0aGlzIGRlbGl2ZXJ5IGFzIGRvbmVcbiAgICAgICAgICAgICAgICAgIC8vIHJhdGhlciB0aGFuIGFsc28gcmVzY2hlZHVsaW5nIGl0LlxuICAgICAgICAgICAgICAgICAgLy8gSW5saW5lLW93bmVyc2hpcCBpbnZhcmlhbnQgZ3VhcmQ6IGNvcnJlbGF0aW9uIElEcyBvZlxuICAgICAgICAgICAgICAgICAgLy8gc3RlcHMgd2hvc2UgYm9kaWVzIHRoaXMgaW52b2NhdGlvbiBpcyBleGVjdXRpbmcgdW5kZXIgYW5cbiAgICAgICAgICAgICAgICAgIC8vIG93bmVyc2hpcCBzdGFtcCAobGF6eSBpbmxpbmUgKyBvd25lZCByZWNvdmVyeSksIHdoaWxlIHRoZVxuICAgICAgICAgICAgICAgICAgLy8gYm9keSBpcyBpbiBmbGlnaHQuIENyYXNoIHJlY292ZXJ5IGRlcGVuZHMgb24gdGhlIG93bmluZ1xuICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZSBOT1QgYmVpbmcgYWNrZWQgd2hpbGUgc3VjaCBhIHN0ZXAgaXMgbm9uLXRlcm1pbmFsXG4gICAgICAgICAgICAgICAgICAvLyAoYWNrID0gaGFuZGxlciByZXR1cm4gb3IgcmVpbnZva2UsIHdoaWNoIGFja3MgKyBlbnF1ZXVlc1xuICAgICAgICAgICAgICAgICAgLy8gdW5kZXIgYSBORVcgbWVzc2FnZSBpZCDigJQgdGhlIHJlZGVsaXZlcnkgb2YgdGhlIG9sZCBpZCBpc1xuICAgICAgICAgICAgICAgICAgLy8gd2hhdCByZS1leGVjdXRlcyBhbiBvcnBoYW5lZCBvd25lZCBzdGVwKS4gQWxsIGV4ZWN1dGVTdGVwXG4gICAgICAgICAgICAgICAgICAvLyBjYWxscyBhcmUgYXdhaXRlZCBiZWZvcmUgYW55IGFjayBwYXRoIHJ1bnMsIHNvIHRoaXMgc2V0XG4gICAgICAgICAgICAgICAgICAvLyBpcyBlbXB0eSBhdCBldmVyeSBhY2sgYnkgY29uc3RydWN0aW9uOyB0aGUgY2hlY2sgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAvLyB0byBjYXRjaCBmdXR1cmUgcmVmYWN0b3JzIHRoYXQgYnJlYWsgdGhhdCBvcmRlcmluZy5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IGluRmxpZ2h0T3duZWRTdGVwcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgYXNzZXJ0Tm9JbkZsaWdodE93bmVkU3RlcHMgPSAoXG4gICAgICAgICAgICAgICAgICAgIGFja1BhdGg6IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpbkZsaWdodE93bmVkU3RlcHMuc2l6ZSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgJ0ludmFyaWFudCB2aW9sYXRpb246IGFja2luZyB0aGUgd29ya2Zsb3cgbWVzc2FnZSB3aGlsZSBvd25lZCBpbmxpbmUgc3RlcHMgYXJlIHN0aWxsIGV4ZWN1dGluZyDigJQgY3Jhc2ggcmVjb3ZlcnkgZm9yIHRoZXNlIHN0ZXBzIGlzIGJyb2tlbicsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBhY2tQYXRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwSWRzOiBbLi4uaW5GbGlnaHRPd25lZFN0ZXBzXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICAvLyBBIHBsYWluIG9yY2hlc3RyYXRvci1yZXBsYXkgbWVzc2FnZS4gT21pdHMgYHJ1bklucHV0YCAoaXRcbiAgICAgICAgICAgICAgICAgIC8vIHJlLWVuZ2FnZXMgdHVyYm8gb24gdGhlIG5leHQgZGVsaXZlcnkgYW5kIHdlZGdlcyB0aGUgcnVuIOKAlFxuICAgICAgICAgICAgICAgICAgLy8gc2VlIGByZWludm9rZWAgYmVsb3cpIGFuZCBgcmVwbGF5RGl2ZXJnZW5jZWAgL1xuICAgICAgICAgICAgICAgICAgLy8gYHNlcnZlckVycm9yUmV0cnlDb3VudGAgKHRoaXMgZGVsaXZlcnkgY2hhaW4ncyBidWRnZXRzKS5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IHJlcGxheU1lc3NhZ2UgPVxuICAgICAgICAgICAgICAgICAgICBhc3luYyAoKTogUHJvbWlzZTxXb3JrZmxvd0ludm9rZVBheWxvYWQ+ID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICBjb25zdCByZWludm9rZSA9IGFzeW5jIChcbiAgICAgICAgICAgICAgICAgICAgZGVsYXlTZWNvbmRzOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAgICAgKiBFeHRyYSBmaWVsZHMgdG8gY2Fycnkgb24gdGhlIG5ldyBtZXNzYWdlLiBPbmx5IHJlYWNoZXMgdGhlXG4gICAgICAgICAgICAgICAgICAgICAqIG5leHQgaW52b2NhdGlvbiBvbiB0aGUgdHVyYm8gcGF0aDogd2l0aG91dCB0dXJibyBub1xuICAgICAgICAgICAgICAgICAgICAgKiBtZXNzYWdlIGlzIGVucXVldWVkIGF0IGFsbCDigJQgdGhlIGhhbmRsZXIgcmV0dXJucyBhXG4gICAgICAgICAgICAgICAgICAgICAqIHZpc2liaWxpdHkgdGltZW91dCBhbmQgdGhlIHF1ZXVlIHJlZGVsaXZlcnMgdGhlIENVUlJFTlRcbiAgICAgICAgICAgICAgICAgICAgICogbWVzc2FnZSwgd2hvc2UgYm9keSAoYW5kIHRoZXJlZm9yZSBhbnkgY291bnRlciBvbiBpdClcbiAgICAgICAgICAgICAgICAgICAgICogY2Fubm90IGJlIGNoYW5nZWQuXG4gICAgICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgICAgICBleHRyYVBheWxvYWQ/OiBQYXJ0aWFsPFdvcmtmbG93SW52b2tlUGF5bG9hZD5cbiAgICAgICAgICAgICAgICAgICk6IFByb21pc2U8eyB0aW1lb3V0U2Vjb25kczogbnVtYmVyIH0gfCB1bmRlZmluZWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgYXNzZXJ0Tm9JbkZsaWdodE93bmVkU3RlcHMoJ3JlaW52b2tlJyk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghdHVyYm8pIHJldHVybiB7IHRpbWVvdXRTZWNvbmRzOiBkZWxheVNlY29uZHMgfTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgcXVldWVNZXNzYWdlKFxuICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgICAgICAgICAgICB7IC4uLihhd2FpdCByZXBsYXlNZXNzYWdlKCkpLCAuLi5leHRyYVBheWxvYWQgfSxcbiAgICAgICAgICAgICAgICAgICAgICBkZWxheVNlY29uZHMgPiAwID8geyBkZWxheVNlY29uZHMgfSA6IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgICAgLy8gUHJlY29uZGl0aW9uICg0MTIpIHJlY292ZXJ5OiBob3cgbWFueSB0aW1lcyB0aGlzIGludm9jYXRpb25cbiAgICAgICAgICAgICAgICAgIC8vIGhhcyB0aHJvd24gYXdheSBpdHMgcmVwbGF5IGFuZCBzdGFydGVkIG92ZXIgaW4tcHJvY2Vzcy5cbiAgICAgICAgICAgICAgICAgIGxldCBwcmVjb25kaXRpb25SZXN0YXJ0cyA9IDA7XG4gICAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgICAqIEV2ZW50IGlkcyB0aGUgZGlzY2FyZGVkIHJlcGxheSBoZWxkLCBrZXB0IHVudGlsIHRoZSBuZXh0XG4gICAgICAgICAgICAgICAgICAgKiBsb2FkIHJlc29sdmVzIHNvIGEgcmVzdGFydCBjYW4gcmVwb3J0IHdoYXQgaXRzIHJlbG9hZFxuICAgICAgICAgICAgICAgICAgICogYWN0dWFsbHkgZm91bmQuIFdpdGhvdXQgdGhpcyBhIDQxMiBvbmx5IGV2ZXIgdGVsbHMgeW91IHRoYXRcbiAgICAgICAgICAgICAgICAgICAqIGEgcmVzdGFydCBoYXBwZW5lZCwgd2hpY2ggY29uZmxhdGVzIHR3byB2ZXJ5IGRpZmZlcmVudFxuICAgICAgICAgICAgICAgICAgICogc2l0dWF0aW9uczogYSBsb2cgdGhhdCBncmV3IChleHBlY3RlZCDigJQgdGhlIGZlbmNlIGRpZCBpdHNcbiAgICAgICAgICAgICAgICAgICAqIGpvYikgYW5kIGEgbG9nIHRoYXQgY2FtZSBiYWNrIGlkZW50aWNhbCwgd2hpY2ggbWVhbnMgY2xpZW50XG4gICAgICAgICAgICAgICAgICAgKiBhbmQgYmFja2VuZCBkaXNhZ3JlZSBhYm91dCB0aGUgY291bnQgZm9yIHRoZSBzYW1lIHNldCBvZlxuICAgICAgICAgICAgICAgICAgICogZXZlbnRzIGFuZCB0aGUgcmVzdGFydCB3aWxsIHJlLWRlcml2ZSB0aGUgc2FtZSBzbmFwc2hvdCBhbmRcbiAgICAgICAgICAgICAgICAgICAqIGJlIHJlamVjdGVkIGFnYWluLlxuICAgICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgICBsZXQgcHJlY29uZGl0aW9uUmVzdGFydEJhc2VsaW5lOiB7XG4gICAgICAgICAgICAgICAgICAgIGlkczogU2V0PHN0cmluZz47XG4gICAgICAgICAgICAgICAgICAgIHJlc3RhcnQ6IG51bWJlcjtcbiAgICAgICAgICAgICAgICAgICAgcmVhc29uOiBzdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZTogJ2lubGluZS1kZWx0YScgfCAnZnVsbC1yZWxvYWQnO1xuICAgICAgICAgICAgICAgICAgfSB8IG51bGwgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICAgKiBSZXBvcnQgd2hhdCBhIHN0YWxlLXNuYXBzaG90IHJlc3RhcnQncyByZWxvYWQgZm91bmQsIG9uY2VcbiAgICAgICAgICAgICAgICAgICAqIHRoZSBsb2cgdGhpcyByZXBsYXkgd2lsbCBhY3R1YWxseSBjb25zdW1lIGlzIGluIGhhbmQuXG4gICAgICAgICAgICAgICAgICAgKlxuICAgICAgICAgICAgICAgICAgICogYGdyZXdgIGlzIHRoZSBleHBlY3RlZCBjYXNlIGFuZCBnaXZlcyA0MTIgdm9sdW1lIGFcbiAgICAgICAgICAgICAgICAgICAqIGRlbm9taW5hdG9yLiBgdW5jaGFuZ2VkYCBtZWFucyB0aGUgcmVsb2FkIGRpc2FncmVlZCB3aXRoXG4gICAgICAgICAgICAgICAgICAgKiB0aGUgcmVqZWN0aW9uLCBzbyB0aGlzIHJlcGxheSByZS1kZXJpdmVzIHRoZSBzYW1lIHNuYXBzaG90XG4gICAgICAgICAgICAgICAgICAgKiBhbmQgaXMgcmVqZWN0ZWQgYWdhaW4gdW50aWwgdGhlIGJ1ZGdldCBpcyBzcGVudC4gYHNocmFua2BcbiAgICAgICAgICAgICAgICAgICAqIHNob3VsZCBiZSBpbXBvc3NpYmxlOiBldmVyeSBsb2FkIHBhdGggb25seSBhZGRzIHRvIGEgcnVuJ3NcbiAgICAgICAgICAgICAgICAgICAqIGxvZy5cbiAgICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgICAgY29uc3QgcmVwb3J0UHJlY29uZGl0aW9uUmVzdGFydFJlbG9hZCA9IChcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRzOiBFdmVudFtdXG4gICAgICAgICAgICAgICAgICApOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFzZWxpbmUgPSBwcmVjb25kaXRpb25SZXN0YXJ0QmFzZWxpbmU7XG4gICAgICAgICAgICAgICAgICAgIGlmICghYmFzZWxpbmUpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgcHJlY29uZGl0aW9uUmVzdGFydEJhc2VsaW5lID0gbnVsbDtcblxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWxvYWRlZElkcyA9IG5ldyBTZXQoXG4gICAgICAgICAgICAgICAgICAgICAgZXZlbnRzLm1hcCgoZXZlbnQpID0+IGV2ZW50LmV2ZW50SWQpXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGFkZGVkID0gY291bnRNaXNzaW5nSWRzKHJlbG9hZGVkSWRzLCBiYXNlbGluZS5pZHMpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBkcm9wcGVkID0gY291bnRNaXNzaW5nSWRzKGJhc2VsaW5lLmlkcywgcmVsb2FkZWRJZHMpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvdXRjb21lID1cbiAgICAgICAgICAgICAgICAgICAgICBkcm9wcGVkID4gMCA/ICdzaHJhbmsnIDogYWRkZWQgPiAwID8gJ2dyZXcnIDogJ3VuY2hhbmdlZCc7XG5cbiAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAgICAgICAgICAgICAgICdSZXN0YXJ0ZWQgcmVwbGF5IHJlbG9hZGVkIGl0cyBldmVudCBsb2cgYWZ0ZXIgYSBzdGFsZS1zbmFwc2hvdCByZWplY3Rpb24nLFxuICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZGVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgZHJvcHBlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50c0JlZm9yZTogYmFzZWxpbmUuaWRzLnNpemUsXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudHNBZnRlcjogcmVsb2FkZWRJZHMuc2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZWNvbmRpdGlvblJlc3RhcnRzOiBiYXNlbGluZS5yZXN0YXJ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uOiBiYXNlbGluZS5yZWFzb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2U6IGJhc2VsaW5lLnNvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BJdGVyYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAgICogUmVjb3ZlciBmcm9tIGEgc3RhbGUtc25hcHNob3QgcmVqZWN0aW9uIGJ5IHJlc3RhcnRpbmcgdGhlXG4gICAgICAgICAgICAgICAgICAgKiByZXBsYXkgaW5zaWRlIHRoaXMgaW52b2NhdGlvbiwgcmV0dXJuaW5nIGZhbHNlIHdoZW4gdGhlXG4gICAgICAgICAgICAgICAgICAgKiBwZXItaW52b2NhdGlvbiBidWRnZXQgaXMgc3BlbnQgKHRoZSBjYWxsZXIgdGhlbiBmYWxscyBiYWNrXG4gICAgICAgICAgICAgICAgICAgKiB0byBhIGZyZXNoIGludm9jYXRpb24pLlxuICAgICAgICAgICAgICAgICAgICpcbiAgICAgICAgICAgICAgICAgICAqIEEgNDEyIG1lYW5zIHRoZSBsb2cgdGhpcyByZXBsYXkgZGVyaXZlZCBpdHMgZXZlbnRzIGZyb20gd2FzXG4gICAgICAgICAgICAgICAgICAgKiBtaXNzaW5nIGFuIGV2ZW50IHRoZSBiYWNrZW5kIGhhZCBhbHJlYWR5IHJlY29yZGVkLiBUaGVcbiAgICAgICAgICAgICAgICAgICAqIHJlamVjdGVkIHdyaXRlIGNhbm5vdCBzaW1wbHkgYmUgcmV0cmllZDogY29ycmVsYXRpb24gaWRzXG4gICAgICAgICAgICAgICAgICAgKiBhcmUgcG9zaXRpb25hbCBvcmRpbmFscyBvZiBvbmUgc2VlZGVkIHNlcXVlbmNlLCBzbyBhIHJlcGxheVxuICAgICAgICAgICAgICAgICAgICogb3ZlciB0aGUgY29ycmVjdGVkIGxvZyBtaW50cyBhIGRpZmZlcmVudCBpZCBmb3IgdGhlIHNhbWVcbiAgICAgICAgICAgICAgICAgICAqIGxvZ2ljYWwgZXZlbnQsIGFuZCByZS1wb3N0aW5nIHRoaXMgb25lIHdvdWxkIHBlcnNpc3QgYW5cbiAgICAgICAgICAgICAgICAgICAqIGV2ZW50IG5vIGNvcnJlY3QgcmVwbGF5IGV2ZXIgcHJvZHVjZXMuIFRoZSB3aG9sZSByZXBsYXkgaGFzXG4gICAgICAgICAgICAgICAgICAgKiB0byBiZSByZS1kZXJpdmVkIOKAlCB3aGljaCB0aGUgbG9vcCBkb2VzIGJ5IGRpc2NhcmRpbmcgaXRzXG4gICAgICAgICAgICAgICAgICAgKiBjYWNoZWQgbG9nLCBzaW5jZSBgcnVuV29ya2Zsb3dgIHRoZW4gYnVpbGRzIGEgZnJlc2ggVk0sXG4gICAgICAgICAgICAgICAgICAgKiBzZWVkIGFuZCBjb3JyZWxhdGlvbi1pZCBzZXF1ZW5jZSBmcm9tIHRoZSByZWxvYWRlZCBldmVudHMuXG4gICAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3RhcnRSZXBsYXlJblByb2Nlc3MgPSAoXG4gICAgICAgICAgICAgICAgICAgIHJlYXNvbjogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICBlcnJvcj86IHVua25vd24sXG4gICAgICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAgICAgKiBTZXQgZmFsc2Ugd2hlbiB3cml0ZXMgdGhpcyBpbnZvY2F0aW9uIG1hZGUgY29uY3VycmVudGx5XG4gICAgICAgICAgICAgICAgICAgICAqIHdpdGggdGhlIHJlamVjdGVkIG9uZSBtYXkgYmUgbWlzc2luZyBmcm9tIHRoZSA0MTInc1xuICAgICAgICAgICAgICAgICAgICAgKiBkZWx0YTogdGhlIFdvcmxkIGNvbXB1dGVkIHRoYXQgZGVsdGEgYWdhaW5zdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICogcmVqZWN0ZWQgcmVxdWVzdCdzIHNuYXBzaG90LCBzbyBpdCBjYW5ub3QgY29udGFpbiBhblxuICAgICAgICAgICAgICAgICAgICAgKiBldmVudCBhIHNpYmxpbmcgY29tbWl0dGVkIGFmdGVyd2FyZHMsIGFuZCBtZXJnaW5nIGl0XG4gICAgICAgICAgICAgICAgICAgICAqIHdvdWxkIHJlc3RhcnQgdGhlIHJlcGxheSBvbiBhIGxvZyB0aGF0IGlzIHN0aWxsXG4gICAgICAgICAgICAgICAgICAgICAqIGluY29tcGxldGUuIE9ubHkgYSBmdWxsIHJlbG9hZCBpcyBhdXRob3JpdGF0aXZlIHRoZW4uXG4gICAgICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgICAgICB7IGFsbG93RGVsdGEgPSB0cnVlIH06IHsgYWxsb3dEZWx0YT86IGJvb2xlYW4gfSA9IHt9XG4gICAgICAgICAgICAgICAgICApOiBib29sZWFuID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgIHByZWNvbmRpdGlvblJlc3RhcnRzID49XG4gICAgICAgICAgICAgICAgICAgICAgZ2V0UHJlY29uZGl0aW9uTWF4SW5Qcm9jZXNzUmVzdGFydHMoKVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcHJlY29uZGl0aW9uUmVzdGFydHMrKztcbiAgICAgICAgICAgICAgICAgICAgLy8gRXZlcnkgc3RhbGUtc25hcHNob3QgcmVzdGFydCBpbnZhbGlkYXRlcyB0aGUgcGFya2VkIFZNOlxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgbG9nIGl0IGNvbnN1bWVkIHdhcyBtaXNzaW5nIGV2ZW50cywgc28gb25seSBhIGZyZXNoXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheSBvdmVyIHRoZSBjb3JyZWN0ZWQgbG9nIGlzIGF1dGhvcml0YXRpdmUuIFRoaXNcbiAgICAgICAgICAgICAgICAgICAgLy8gYWxzbyBjb3ZlcnMgdGhlIHN1c3BlbnNpb24tY3JlYXRlIDQxMiwgd2hpY2ggZmlyZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIHRoZSByZXRlbnRpb24gZGVjaXNpb24gKGtpbGwgc3dpdGNoICsgc3RlcC1pbnB1dFxuICAgICAgICAgICAgICAgICAgICAvLyBnYXRlKSBldmVyIHJhbiwgYW5kIHRoZSBydW5fY29tcGxldGVkIDQxMiwgd2hlcmUgYVxuICAgICAgICAgICAgICAgICAgICAvLyBjb21wbGV0ZWQgc2Vzc2lvbiBtdXN0IG5vdCBiZSByZXN1bWVkIGFnYWluLlxuICAgICAgICAgICAgICAgICAgICByZXRhaW5lZFNlc3Npb24gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAvLyBBIFdvcmxkIE1BWSByZXR1cm4gdGhlIGV2ZW50cyB3ZSB3ZXJlIG1pc3Npbmcgb24gdGhlIDQxMi5cbiAgICAgICAgICAgICAgICAgICAgLy8gVHJ1c3QgaXQgb25seSBvbiB0aGUgRklSU1QgcmVzdGFydDogaXRzIGNvbXBsZXRlbmVzcyBwcm9vZlxuICAgICAgICAgICAgICAgICAgICAvLyBsZWFucyBvbiB0aGUgYmFja2VuZCdzIG93biBib29ra2VlcGluZywgc28gaWYgdGhhdFxuICAgICAgICAgICAgICAgICAgICAvLyB1bmRlci1jb3VudHMsIGEgXCJjb21wbGV0ZVwiIGRlbHRhIGNhbiBzdGlsbCBsZWF2ZSBhIGhvbGUuXG4gICAgICAgICAgICAgICAgICAgIC8vIEJvdW5kaW5nIGl0IHRvIG9uZSBhdHRlbXB0IGNhcHMgdGhhdCBhdCBhIHNpbmdsZSB3YXN0ZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVzdGFydDsgZXZlcnkgbGF0ZXIgcmVzdGFydCBkb2VzIHRoZSBhdXRob3JpdGF0aXZlIGxvYWQuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlbHRhID1cbiAgICAgICAgICAgICAgICAgICAgICBhbGxvd0RlbHRhICYmIHByZWNvbmRpdGlvblJlc3RhcnRzID09PSAxXG4gICAgICAgICAgICAgICAgICAgICAgICA/IHByZWNvbmRpdGlvbkV2ZW50RGVsdGEoZXJyb3IsIHJ1bklkKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICAvLyBBIGRlbHRhIGlzIG9ubHkgdXNhYmxlIGlmIHRoZXJlIGlzIGEgbG9hZGVkIGxvZyB0byBtZXJnZVxuICAgICAgICAgICAgICAgICAgICAvLyBpdCBpbnRvOyB3aXRob3V0IG9uZSB0aGUgcmVzdGFydCBtdXN0IGxvYWQgZXZlcnl0aGluZy5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdXNlZERlbHRhID1cbiAgICAgICAgICAgICAgICAgICAgICBkZWx0YSAhPT0gbnVsbCAmJiBldmVudExvZy50eXBlICE9PSAnbG9hZEFsbCc7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNuYXBzaG90IHRoZSBzZXQgYmVpbmcgZGlzY2FyZGVkIHdoaWxlIGl0IGlzIHN0aWxsIGluXG4gICAgICAgICAgICAgICAgICAgIC8vIGhhbmQ7IHRoZSBjb21wYXJpc29uIGhhcHBlbnMgb25jZSB0aGUgbmV4dCBsb2FkIHJlc29sdmVzLlxuICAgICAgICAgICAgICAgICAgICBwcmVjb25kaXRpb25SZXN0YXJ0QmFzZWxpbmUgPVxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgIT09ICdsb2FkQWxsJ1xuICAgICAgICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRzOiBuZXcgU2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cuZXZlbnRzLm1hcCgoZXZlbnQpID0+IGV2ZW50LmV2ZW50SWQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN0YXJ0OiBwcmVjb25kaXRpb25SZXN0YXJ0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFzb24sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlOiB1c2VkRGVsdGEgPyAnaW5saW5lLWRlbHRhJyA6ICdmdWxsLXJlbG9hZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDogbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlbHRhICYmIGV2ZW50TG9nLnR5cGUgIT09ICdsb2FkQWxsJykge1xuICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZEV2ZW50TG9nKGV2ZW50TG9nLCBkZWx0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSB7IC4uLmV2ZW50TG9nLCB0eXBlOiAncmVhZHknIH07XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gTVVTVCBiZSBhIGZ1bGwsIGN1cnNvci1sZXNzIHJlbG9hZC4gVGhlIGN1cnNvciBmaWx0ZXJzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYnkgbGV4aWNvZ3JhcGhpYyBldmVudCBpZCB3aGlsZSBhIGhvbGUgaXMgZGVmaW5lZCBieVxuICAgICAgICAgICAgICAgICAgICAgIC8vIFVMSUQgKnRpbWUqOiBhbiBldmVudCBpbiB0aGUgc2FtZSBtaWxsaXNlY29uZCBzb3J0c1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGVpdGhlciBzaWRlIG9mIHRoZSBjdXJzb3IgZGVwZW5kaW5nIG9uIGl0cyByYW5kb21cbiAgICAgICAgICAgICAgICAgICAgICAvLyBjb21wb25lbnQsIGFuZCBhbiBldmVudCBtaW50ZWQgaW4gYW4gZWFybGllclxuICAgICAgICAgICAgICAgICAgICAgIC8vIG1pbGxpc2Vjb25kIGJ1dCBjb21taXR0ZWQgbGF0ZXIgYWx3YXlzIHNvcnRzIGJlbG93IGl0LlxuICAgICAgICAgICAgICAgICAgICAgIC8vIEFuIGluY3JlbWVudGFsIGxvYWQgdGhlcmVmb3JlIGhlYWxzIHRoZSBob2xlIG9ubHkgYnlcbiAgICAgICAgICAgICAgICAgICAgICAvLyBsdWNrLlxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nID0geyB0eXBlOiAnbG9hZEFsbCcgfTtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgY29ycmVjdGVkIGxvZyBpbnNlcnRzIHRoZSBtaXNzaW5nIGV2ZW50cyBCRUxPVyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBsZW5ndGggYWxyZWFkeSBzY2FubmVkIGZvciBwYXlsb2FkIHByZXdhcm1pbmcsIHNoaWZ0aW5nXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZXZlcnkgbGF0ZXIgcG9zaXRpb24uIE9ubHkgYSBmdWxsIHJlc2NhbiBzZWVzIHRoZW0uXG4gICAgICAgICAgICAgICAgICAgICAgcmVwbGF5UGF5bG9hZENhY2hlLnJlc2V0U2NhbigpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAnRXZlbnQgY3JlYXRpb24gcmVqZWN0ZWQgYXMgc3RhbGU7IHJlc3RhcnRpbmcgcmVwbGF5IGluLXByb2Nlc3MnLFxuICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uLFxuICAgICAgICAgICAgICAgICAgICAgICAgbG9vcEl0ZXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZWNvbmRpdGlvblJlc3RhcnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlOiB1c2VkRGVsdGEgPyAnaW5saW5lLWRlbHRhJyA6ICdmdWxsLXJlbG9hZCcsXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgICAnd29ya2Zsb3cucHJlY29uZGl0aW9uX3Jlc3RhcnRzJzogcHJlY29uZGl0aW9uUmVzdGFydHMsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAgICogRXNjYWxhdGUgYSBzdGFsZS1zbmFwc2hvdCByZWplY3Rpb24gdGhhdCBzdXJ2aXZlZCB0aGVcbiAgICAgICAgICAgICAgICAgICAqIGluLXByb2Nlc3MgcmVzdGFydCBidWRnZXQgdG8gYSBmcmVzaCBpbnZvY2F0aW9uLCBvciBnaXZlIHVwXG4gICAgICAgICAgICAgICAgICAgKiBvbiB0aGUgcnVuIHdoZW4gdGhlIHBlci1ydW4gYnVkZ2V0IGlzIGFsc28gc3BlbnQuXG4gICAgICAgICAgICAgICAgICAgKlxuICAgICAgICAgICAgICAgICAgICogVGhlIGluLXByb2Nlc3MgYnVkZ2V0IGlzIGEgY2xvc3VyZSB2YXJpYWJsZSBhbmQgdGhlIHF1ZXVlJ3NcbiAgICAgICAgICAgICAgICAgICAqIGRlbGl2ZXJ5IGNvdW50IHJlc3RhcnRzIGF0IDEgd2hlbmV2ZXIgYSBuZXcgbWVzc2FnZSBpc1xuICAgICAgICAgICAgICAgICAgICogZW5xdWV1ZWQsIHNvIGEgcnVuIHRoYXQgaXMgcGVybWFuZW50bHkgdW5hYmxlIHRvIGNhdGNoIHVwXG4gICAgICAgICAgICAgICAgICAgKiB3aXRoIGl0cyBvd24gZXZlbnQgbG9nIHdvdWxkIG90aGVyd2lzZSBjeWNsZSByZXN0YXJ0cyDihpJcbiAgICAgICAgICAgICAgICAgICAqIHJlLWludm9rZSDihpIgcmVzdGFydHMgd2l0aCBubyBydW4tbGV2ZWwgYm91bmQuIFRoZSBjaGFpbiBpc1xuICAgICAgICAgICAgICAgICAgICogdGhlcmVmb3JlIGNvdW50ZWQgb24gdGhlIG1lc3NhZ2UgaXRzZWxmLCBpbiB0aGUgc2FtZSB3YXlcbiAgICAgICAgICAgICAgICAgICAqIHJlcGxheSBkaXZlcmdlbmNlcyBhcmUsIGFuZCBmYWlscyB0aGUgcnVuIG9uY2UgZXhoYXVzdGVkLlxuICAgICAgICAgICAgICAgICAgICpcbiAgICAgICAgICAgICAgICAgICAqIFRoZSBjb3VudGVyIG9ubHkgYWR2YW5jZXMgb24gaG9wcyB0aGF0IGVucXVldWUgYSBuZXcgbWVzc2FnZVxuICAgICAgICAgICAgICAgICAgICogKHNlZSBgcmVpbnZva2VgKS4gQSByZWRlbGl2ZXJ5LWJhc2VkIGhvcCBrZWVwcyB0aGUgc2FtZSBib2R5XG4gICAgICAgICAgICAgICAgICAgKiBhbmQgc28gdGhlIHNhbWUgY291bnQsIGJ1dCBpdCBhbHNvIGtlZXBzIGFkdmFuY2luZ1xuICAgICAgICAgICAgICAgICAgICogYG1ldGFkYXRhLmF0dGVtcHRgLCB3aGljaCB0aGUgbWF4LWRlbGl2ZXJ5IGNoZWNrIGF0IHRoZSB0b3BcbiAgICAgICAgICAgICAgICAgICAqIG9mIHRoZSBoYW5kbGVyIGFscmVhZHkgYm91bmRzIOKAlCBhbmQgdGhlIGRlbGF5IGJlbG93IGlzIHdoYXRcbiAgICAgICAgICAgICAgICAgICAqIG1ha2VzIHRoYXQgYnVkZ2V0IHNwYW4gcmVhbCB0aW1lIHJhdGhlciB0aGFuIGJlaW5nIGJ1cm5lZCBpblxuICAgICAgICAgICAgICAgICAgICogYSB0aWdodCBsb29wLlxuICAgICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgICBjb25zdCByZWludm9rZUFmdGVyU3RhbGVSZWplY3Rpb24gPSBhc3luYyAoXG4gICAgICAgICAgICAgICAgICAgIHJlYXNvbjogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogdW5rbm93blxuICAgICAgICAgICAgICAgICAgKTogUHJvbWlzZTxcbiAgICAgICAgICAgICAgICAgICAgfCB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWludm9rZWQ6IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQ6IHsgdGltZW91dFNlY29uZHM6IG51bWJlciB9IHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfCB7IHJlaW52b2tlZDogZmFsc2U7IGVycm9yOiBFcnJvciB9XG4gICAgICAgICAgICAgICAgICA+ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYXR0ZW1wdCA9IChwcmVjb25kaXRpb25SZWludm9jYXRpb25zID8/IDApICsgMTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbWF4UmVpbnZvY2F0aW9ucyA9IGdldFByZWNvbmRpdGlvbk1heFJlaW52b2NhdGlvbnMoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGF0dGVtcHQgPiBtYXhSZWludm9jYXRpb25zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlaW52b2tlZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcjogbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICBgRXZlbnQgY3JlYXRpb24gd2FzIHJlamVjdGVkIGFzIHN0YWxlIGFmdGVyICR7bWF4UmVpbnZvY2F0aW9uc30gcmUtaW52b2NhdGlvbnMgb2YgJHtnZXRQcmVjb25kaXRpb25NYXhJblByb2Nlc3NSZXN0YXJ0cygpfSBpbi1wcm9jZXNzIHJlcGxheSByZXN0YXJ0cyBlYWNoOiB0aGlzIHJ1biBjYW5ub3Qgb2JzZXJ2ZSBpdHMgb3duIGV2ZW50IGxvZyBjb21wbGV0ZWx5IGVub3VnaCB0byBtYWtlIHByb2dyZXNzLiBMYXN0IHJlamVjdGlvbiAoJHtyZWFzb259KTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgeyBjYXVzZTogZXJyb3IgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAnRXZlbnQgY3JlYXRpb24gcmVqZWN0ZWQgYXMgc3RhbGUgYWZ0ZXIgaW4tcHJvY2VzcyByZXN0YXJ0czsgcmUtaW52b2tpbmcgcnVuIGZvciBhIGZyZXNoIHJlcGxheScsXG4gICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWFzb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBsb29wSXRlcmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJlY29uZGl0aW9uUmVpbnZvY2F0aW9uczogYXR0ZW1wdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFJlaW52b2NhdGlvbnMsXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgICAnd29ya2Zsb3cucHJlY29uZGl0aW9uX3JlaW52b2NhdGlvbnMnOiBhdHRlbXB0LFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRGVsYXllZCwgdW5saWtlIHRoZSBvdGhlciByZWludm9rZSgpIGNhbGxlcnM6IHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBpbi1wcm9jZXNzIHJlc3RhcnRzIGFscmVhZHkgcmVsb2FkZWQgdGhlIGxvZyBzZXZlcmFsIHRpbWVzXG4gICAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgY2F0Y2hpbmcgdXAsIHNvIHRoZSB3cml0ZXJzIHRoaXMgcmVwbGF5IGlzIHJhY2luZ1xuICAgICAgICAgICAgICAgICAgICAvLyBhcmUgc3RpbGwgYWN0aXZlLiBSZXRyeWluZyBpbnN0YW50bHkganVzdCBidXJucyB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gcGVyLXJ1biBidWRnZXQgYXQgZnVsbCBzcGVlZC5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICByZWludm9rZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgcmVzdWx0OiBhd2FpdCByZWludm9rZShcbiAgICAgICAgICAgICAgICAgICAgICAgIGdldFByZWNvbmRpdGlvblJlaW52b2tlRGVsYXlTZWNvbmRzKCksXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHByZWNvbmRpdGlvblJlaW52b2NhdGlvbnM6IGF0dGVtcHQgfVxuICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICAvLyBEZXBsb3ltZW50LWFmZmluaXR5IGd1YXJkLCBzaGFyZWQgYnkgdGhlIHR3byBwYXRocyB0aGF0XG4gICAgICAgICAgICAgICAgICAvLyBleGVjdXRlIGEgcnVuOiBxdWV1ZWQgc3RlcCBleGVjdXRpb25zIGFuZCBmbG93IHJlcGxheXMuXG4gICAgICAgICAgICAgICAgICBjb25zdCBndWFyZERlcGxveW1lbnQgPSBhc3luYyAoXG4gICAgICAgICAgICAgICAgICAgIHJ1bjogUGljazxcbiAgICAgICAgICAgICAgICAgICAgICBXb3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICAgICAgICAncnVuSWQnIHwgJ2RlcGxveW1lbnRJZCcgfCAnc3BlY1ZlcnNpb24nXG4gICAgICAgICAgICAgICAgICAgID4sXG4gICAgICAgICAgICAgICAgICAgIHJlZW5xdWV1ZVBheWxvYWQ6ICgpID0+IFByb21pc2U8V29ya2Zsb3dJbnZva2VQYXlsb2FkPixcbiAgICAgICAgICAgICAgICAgICAgYmVmb3JlU3RvcD86ICgpID0+IFByb21pc2U8dm9pZD5cbiAgICAgICAgICAgICAgICAgICk6IFByb21pc2U8RGVwbG95bWVudEFmZmluaXR5T3V0Y29tZT4gPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB7IG91dGNvbWUsIHNwYW5BdHRyaWJ1dGVzIH0gPVxuICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGd1YXJkRGVwbG95bWVudEFmZmluaXR5KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0cnlDb3VudDogZGVwbG95bWVudE1pc21hdGNoUmV0cnlDb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGJlZm9yZVN0b3AsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0RlcGxveW1lbnRVbmF2YWlsYWJsZUVycm9yOlxuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZC5pc0RlcGxveW1lbnRVbmF2YWlsYWJsZUVycm9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVlbnF1ZXVlOiBhc3luYyAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBsb3ltZW50TWlzbWF0Y2hSZXRyeUNvdW50OiByZXRyeUNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxheVNlY29uZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB9OiBSZWVucXVldWVBcmdzKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd05hbWUsIG5hbWVzcGFjZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGF3YWl0IHJlZW5xdWV1ZVBheWxvYWQoKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBsb3ltZW50TWlzbWF0Y2hSZXRyeUNvdW50OiByZXRyeUNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeyBkZXBsb3ltZW50SWQsIHNwZWNWZXJzaW9uLCBkZWxheVNlY29uZHMgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNwYW5BdHRyaWJ1dGVzKSBzcGFuPy5zZXRBdHRyaWJ1dGVzKHNwYW5BdHRyaWJ1dGVzKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG91dGNvbWU7XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICAvLyBJZiBpbmNvbWluZyBtZXNzYWdlIGhhcyBhIHN0ZXBJZCwgdGhpcyBpcyBhIGJhY2tncm91bmQgc3RlcFxuICAgICAgICAgICAgICAgICAgLy8gZXhlY3V0aW9uLiBFeGVjdXRlIHRoZSBzdGVwLCB0aGVuIGNoZWNrIGlmIGFsbCBwYXJhbGxlbCBzdGVwc1xuICAgICAgICAgICAgICAgICAgLy8gZnJvbSB0aGUgYmF0Y2ggYXJlIGRvbmUuIElmIHNvLCByZXBsYXkgaW5saW5lIChzYXZpbmcgYSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgLy8gcm91bmR0cmlwKS4gSWYgbm90LCByZXR1cm4g4oCUIHRoZSBsYXN0IGhhbmRsZXIgdG8gY29tcGxldGVcbiAgICAgICAgICAgICAgICAgIC8vIHdpbGwgcGljayB1cCB0aGUgcmVwbGF5LlxuICAgICAgICAgICAgICAgICAgaWYgKGluY29taW5nU3RlcElkICYmIGluY29taW5nU3RlcE5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBiZ1J1biA9IGF3YWl0IHdvcmxkLnJ1bnMuZ2V0KHJ1bklkLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlRGF0YTogJ25vbmUnLFxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChiZ1J1bi5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgJ1J1biBhbHJlYWR5IGZpbmlzaGVkLCBza2lwcGluZyBiYWNrZ3JvdW5kIHN0ZXAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBzdGF0dXM6IGJnUnVuLnN0YXR1cyB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAvLyBDb3ZlcnMgZXZlcnkgcXVldWVkIHN0ZXAgZXhlY3V0aW9uIOKAlCBmaXJzdCBkaXNwYXRjaCBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZWRlbGl2ZXJpZXMvcmV0cmllcyBhbGlrZS5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAoYXdhaXQgZ3VhcmREZXBsb3ltZW50KGJnUnVuLCBhc3luYyAoKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4oYXdhaXQgcmVwbGF5TWVzc2FnZSgpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcElkOiBpbmNvbWluZ1N0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IGluY29taW5nU3RlcE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KSkpICE9PSAnY29udGludWUnXG4gICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGJnU3RhcnRlZEF0ID0gYmdSdW4uc3RhcnRlZEF0XG4gICAgICAgICAgICAgICAgICAgICAgICA/ICtiZ1J1bi5zdGFydGVkQXRcbiAgICAgICAgICAgICAgICAgICAgICAgIDogRGF0ZS5ub3coKTtcblxuICAgICAgICAgICAgICAgICAgICAgIC8vIFJldHJ5IGNlaWxpbmcgZm9yIGEgYmFja2dyb3VuZGVkIHN0ZXAuIGBtZXRhZGF0YS5hdHRlbXB0YFxuICAgICAgICAgICAgICAgICAgICAgIC8vICh0aGUgcXVldWUgZGVsaXZlcnkgY291bnQpIGlzIGEgY2hlYXAgdXBwZXIgYm91bmQsIGJ1dCBpdFxuICAgICAgICAgICAgICAgICAgICAgIC8vIG92ZXItY291bnRzOiBhIFRocm90dGxlRXJyb3IgLyBUb29FYXJseUVycm9yIOKAlCBvciBhbnlcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZWRlbGl2ZXJ5IHRoYXQgbmV2ZXIgcmFuIHRoZSBib2R5IOKAlCBzdGlsbCBhZHZhbmNlcyBpdCwgc29cbiAgICAgICAgICAgICAgICAgICAgICAvLyB0cnVzdGluZyBpdCBkaXJlY3RseSBjb3VsZCBmYWlsIGEgc3RlcCBhcyBcImV4Y2VlZGVkIG1heFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHJpZXNcIiBiZWZvcmUgdGhlIGJvZHkgZXZlciByYW4gKGEgdXNlci12aXNpYmxlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmVncmVzc2lvbiB1bmRlciB0cmFuc2llbnQgYmFja2VuZCBwcmVzc3VyZSkuIFVzZSBpdCBvbmx5XG4gICAgICAgICAgICAgICAgICAgICAgLy8gYXMgYSBmYXN0IGdhdGU6IHdoaWxlIGl0IGlzIGF0IG9yIHVuZGVyIHRoZSBjZWlsaW5nIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXAgY2Fubm90IGJlIGV4aGF1c3RlZCwgc28gcHJvY2VlZCB3aXRob3V0IHRvdWNoaW5nIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIGxvZy4gT25seSBvbmNlIGl0IGNyb3NzZXMgdGhlIGNlaWxpbmcgZG8gd2UgbG9hZCB0aGUgZnVsbFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGV2ZW50IGxvZyBhbmQgZGVyaXZlIHRoZSBhdXRob3JpdGF0aXZlIGF0dGVtcHQgZnJvbSB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZWNvcmRlZCBgc3RlcF9zdGFydGVkYCBjb3VudCDigJQgc2NvcGVkIHRvIHRoZSBsaWZlY3ljbGVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBhdHRlbXB0IHRvdGFsIChiYXJlIHN0YXJ0cyBwbHVzIHRoZSBsYXJnZXN0IHNpbmdsZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIG93bmVyJ3Mgc3RhcnRzKTogdGhyb3R0bGUvdG9vLWVhcmx5IHJlZGVsaXZlcmllcyB3cml0ZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIG5vIHN0YXJ0IGF0IGFsbCwgcmFjaW5nIGludm9jYXRpb25zJyBvbmUtb2ZmIHN0YW1wZWRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBkdXBsaWNhdGVzIGRvbid0IGFjY3VtdWxhdGUgKGNvdW50aW5nIHRoZW0gZmFsc2VseVxuICAgICAgICAgICAgICAgICAgICAgIC8vIGV4aGF1c3RlZCBoZWFsdGh5IHN0ZXBzIOKAlCBzZWUgY291bnRTdGVwU3RhcnRlZEV2ZW50cyksXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIGF0dGVtcHRzIGJ1cm5lZCB1bmRlciBhIHByaW9yIGlubGluZS1vd25lcnNoaXBcbiAgICAgICAgICAgICAgICAgICAgICAvLyBwaGFzZSBzdGlsbCBjb3VudCwgc28gYSBzdGVwIHRoYXQgdGltZXMgb3V0IHVuZGVyXG4gICAgICAgICAgICAgICAgICAgICAgLy8gb3duZWQgcmVjb3ZlcnkgYW5kIHRoZW4gdHJhbnNpdGlvbnMgdG8gcXVldWVkL2JhcmVcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZXRyaWVzIHRyaXBzIHRoZSBjb21iaW5lZCBjZWlsaW5nLiBUaGlzIHN0aWxsIGJvdW5kc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHRpbWVvdXRzLCB3aGljaCB3cml0ZSBubyBlcnJvciBmb3IgdGhlIHBvc3QtYm9keSBndWFyZFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIGNhdGNoLlxuICAgICAgICAgICAgICAgICAgICAgIGxldCBiZ0F1dGhvcml0YXRpdmVBdHRlbXB0ID0gbWV0YWRhdGEuYXR0ZW1wdDtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBiZ01heFJldHJpZXMgPVxuICAgICAgICAgICAgICAgICAgICAgICAgZ2V0U3RlcEZ1bmN0aW9uKGluY29taW5nU3RlcE5hbWUpPy5tYXhSZXRyaWVzID8/XG4gICAgICAgICAgICAgICAgICAgICAgICBERUZBVUxUX1NURVBfTUFYX1JFVFJJRVM7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKG1ldGFkYXRhLmF0dGVtcHQgPiBiZ01heFJldHJpZXMgKyAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCBsb2FkV29ya2Zsb3dSdW5FdmVudHMocnVuSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYmdBdXRob3JpdGF0aXZlQXR0ZW1wdCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50U3RlcFN0YXJ0ZWRFdmVudHMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZGVkLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNvbWluZ1N0ZXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7IHR5cGU6ICd0b3RhbEF0dGVtcHRzJyB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICkgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIC8vIFBhdXNlIHRoZSByZXBsYXkgYnVkZ2V0IHdoaWxlIHRoZSBzdGVwIGJvZHkgcnVucyDigJRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBzdGVwIGR1cmF0aW9uIGlzIGJvdW5kZWQgYnkgdGhlIHBsYXRmb3JtJ3MgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAvLyBtYXhEdXJhdGlvbiwgbm90IGJ5IHRoZSByZXBsYXkgdGltZW91dC4gU2VlIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIFJlcGxheUJ1ZGdldCBkb2NzIGZvciB0aGUgY29udHJhY3QuXG4gICAgICAgICAgICAgICAgICAgICAgcmVwbGF5QnVkZ2V0LnBhdXNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgbGV0IHN0ZXBSZXN1bHQ6IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgZXhlY3V0ZVN0ZXA+PjtcbiAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2luZ2xlLWZsaWdodDogYSBkZWxheWVkIGJhY2tzdG9wIChvciByZXRyeSkgbWVzc2FnZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2FuIGFycml2ZSB3aGlsZSBhbm90aGVyIGV4ZWN1dGlvbiBvZiB0aGlzIHNhbWUgc3RlcFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgbWlkLWJvZHkgaW4gdGhpcyBwcm9jZXNzIOKAlCBtb3N0IGltcG9ydGFudGx5IG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3b3JsZHMgd2l0aCBubyBpbnZvY2F0aW9uIGtpbGwgYm91bmQgKHdvcmxkLWxvY2FsKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdoZXJlIHRoZSBvd25lcnNoaXAgbGVhc2UgaXMgbm90IGEgZGVhdGggcHJvb2YuIFRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9zZXIgYXdhaXRzIHRoZSB3aW5uZXIncyBzZXR0bGVtZW50LCB0aGVuIGFja3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgZXhlY3V0aW5nLiBObyBvd25lck1lc3NhZ2VJZCBoZXJlOiB0aGUgYmFyZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcF9zdGFydGVkIG9mIGEgcXVldWUtZHJpdmVuIGV4ZWN1dGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW50ZW50aW9uYWxseSBjbGVhcnMgaW5saW5lIG93bmVyc2hpcCAodGhlIHN0ZXAgaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHF1ZXVlLW93bmVkIGZyb20gdGhpcyBwb2ludCkuXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGVwUmVzdWx0ID0gYXdhaXQgcnVuU3RlcFNpbmdsZUZsaWdodChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGluY29taW5nU3RlcElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAoKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZWN1dGVTdGVwKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd0RlcGxveW1lbnRJZDogYmdSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dTdGFydGVkQXQ6IGJnU3RhcnRlZEF0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vdFJ1bklkOiByb290UnVuSWRGcm9tKGJnUnVuLmF0dHJpYnV0ZXMsIHJ1bklkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZDogaW5jb21pbmdTdGVwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZTogaW5jb21pbmdTdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1blNwZWNWZXJzaW9uOiBiZ1J1bi5zcGVjVmVyc2lvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJldHJ5IGNlaWxpbmc6IHRoZSBxdWV1ZSBkZWxpdmVyeSBjb3VudCBhcyBhIGZhc3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGdhdGUsIHZlcmlmaWVkIGFnYWluc3QgdGhlIHJlY29yZGVkIHN0ZXBfc3RhcnRlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY291bnQgb25jZSBpdCBjcm9zc2VzIHRoZSBjZWlsaW5nIChzZWUgYWJvdmUpLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aG9yaXRhdGl2ZUF0dGVtcHQ6IGJnQXV0aG9yaXRhdGl2ZUF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheUJ1ZGdldC5yZXN1bWUoKTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHN0ZXBSZXN1bHQudHlwZSA9PT0gJ3JldHJ5Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgdGltZW91dFNlY29uZHM6IHN0ZXBSZXN1bHQudGltZW91dFNlY29uZHMgfTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHN0ZXBSZXN1bHQudHlwZSA9PT0gJ3Rocm90dGxlZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7IHRpbWVvdXRTZWNvbmRzOiBzdGVwUmVzdWx0LnRpbWVvdXRTZWNvbmRzIH07XG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gSWYgc3RlcCBoYWQgcGVuZGluZyBvcHMgKHN0cmVhbSB3cml0ZXMpLCBicmVhayBhbmQgbGV0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gd2FpdFVudGlsIGZsdXNoIHRoZW0g4oCUIGNhbid0IGNvbnRpbnVlIGlubGluZS5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGVwUmVzdWx0LnR5cGUgPT09ICdjb21wbGV0ZWQnICYmXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGVwUmVzdWx0Lmhhc1BlbmRpbmdPcHNcbiAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlQ2FycmllcjogYXdhaXQgbmV4dFRyYWNlQ2FycmllcigpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBSZXN1bHQudHlwZSA9PT0gJ2NvbXBsZXRlZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBSZXN1bHQudHlwZSA9PT0gJ2ZhaWxlZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBSZXN1bHQudHlwZSA9PT0gJ3NraXBwZWQnXG4gICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBMb2FkIGV2ZW50cyB0byBjaGVjayBpZiBhbGwgcGFyYWxsZWwgc3RlcHMgYXJlIGRvbmUuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgY3Vyc29yLWJhc2VkIGxvYWRpbmcgc28gdGhlIG1haW4gbG9vcCBjYW4gY29udGludWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGluY3JlbWVudGFsbHkgZnJvbSBoZXJlLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbG9hZGVkID0gYXdhaXQgbG9hZFdvcmtmbG93UnVuRXZlbnRzKHJ1bklkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nID0gbmV4dEV2ZW50TG9nTG9hZChsb2FkZWQpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBmb3IgcGVuZGluZyBzdGVwczogYW55IHN0ZXBfY3JlYXRlZCB3aXRob3V0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhIG1hdGNoaW5nIHN0ZXBfY29tcGxldGVkIG9yIHN0ZXBfZmFpbGVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RlcENyZWF0ZWRJZHMgPSBuZXcgU2V0PHN0cmluZyB8IHVuZGVmaW5lZD4oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0ZXBUZXJtaW5hbElkcyA9IG5ldyBTZXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBlIG9mIGxvYWRlZC5ldmVudHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuZXZlbnRUeXBlID09PSAnc3RlcF9jcmVhdGVkJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBDcmVhdGVkSWRzLmFkZChlLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUuZXZlbnRUeXBlID09PSAnc3RlcF9jb21wbGV0ZWQnIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdzdGVwX2ZhaWxlZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcFRlcm1pbmFsSWRzLmFkZChlLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwZW5kaW5nU3RlcElkcyA9IG5ldyBTZXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBpZCBvZiBzdGVwQ3JlYXRlZElkcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXN0ZXBUZXJtaW5hbElkcy5oYXMoaWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVuZGluZ1N0ZXBJZHMuYWRkKGlkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocGVuZGluZ1N0ZXBJZHMuc2l6ZSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBwZW5kaW5nIHN0ZXAgdGhhdCBUSElTIG1lc3NhZ2UgaW5saW5lLW93bnMgKGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJldmlvdXMgZGVsaXZlcnkgb2YgdGhpcyBtZXNzYWdlIHN0YW1wZWQgaXRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXBfc3RhcnRlZCBhbmQgdGhlbiBjcmFzaGVkIG1pZC1ib2R5KSBtdXN0IGJlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlY292ZXJlZCBoZXJlOiBvbmx5IHRoZSBvd25pbmcgbWVzc2FnZSBtYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtZXhlY3V0ZSBpdCBiZWZvcmUgdGhlIG93bmVyc2hpcCBsZWFzZSBleHBpcmVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhbmQgd2FrZSByZXBsYXlzIG1lcmVseSBlbnN1cmUgYSBkZWxheWVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJhY2tzdG9wLiBGYWxsIHRocm91Z2ggdG8gdGhlIG1haW4gbG9vcCwgd2hvc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGlzcGF0Y2ggdGFibGUgcm91dGVzIGl0IHRvIG93bmVkIHJlY292ZXJ5LlxuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNJbmxpbmVPd25lcnNoaXBFbmFibGVkKCkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNQZW5kaW5nU3RlcE93bmVkQnlNZXNzYWdlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZGVkLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlbmRpbmdTdGVwSWRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEubWVzc2FnZUlkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0JhY2tncm91bmQgc3RlcCBkb25lOyBmYWxsaW5nIHRocm91Z2ggdG8gcmVjb3ZlciBhbiBpbmxpbmUgc3RlcCBvd25lZCBieSB0aGlzIG1lc3NhZ2UnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyB3b3JrZmxvd1J1bklkOiBydW5JZCB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPdGhlciBzdGVwcyBzdGlsbCBpbiBwcm9ncmVzcy4gUmV0dXJuIHdpdGhvdXRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBxdWV1aW5nIOKAlCB0aGUgbGFzdCBoYW5kbGVyIHRvIGNvbXBsZXRlIHdpbGwgc2VlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWxsIHN0ZXBzIGRvbmUgYW5kIHJlcGxheSBpbmxpbmUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCYWNrZ3JvdW5kIHN0ZXAgZG9uZSBidXQgb3RoZXIgc3RlcHMgcGVuZGluZywgcmV0dXJuaW5nJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFsbCBzdGVwcyBkb25lIOKAlCBmYWxsIHRocm91Z2ggdG8gdGhlIG1haW4gcmVwbGF5IGxvb3AuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTZXQgdXAgc2hhcmVkIHN0YXRlIHNvIHRoZSBsb29wIGNhbiBjb250aW51ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdBbGwgcGFyYWxsZWwgc3RlcHMgZG9uZSwgcmVwbGF5aW5nIGlubGluZSBhZnRlciBiYWNrZ3JvdW5kIHN0ZXAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBydW5DcmVhdGVkRXZlbnQgPSBsb2FkZWQuZXZlbnRzLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChldmVudCkgPT4gZXZlbnQuZXZlbnRUeXBlID09PSAncnVuX2NyZWF0ZWQnXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHJlcGxheUlucHV0OiB1bmtub3duO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bkNyZWF0ZWRFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYXlJbnB1dCA9IHJ1bkNyZWF0ZWRFdmVudC5ldmVudERhdGEuaW5wdXQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzTGVnYWN5U3BlY1ZlcnNpb24oYmdSdW4uc3BlY1ZlcnNpb24pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFdvcmtmbG93IHJ1biBcIiR7cnVuSWR9XCIgaGFzIG5vIFwicnVuX2NyZWF0ZWRcIiBldmVudGBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExlZ2FjeSBydW5zIHByZWRhdGUgdGhlIGV2ZW50LXNvdXJjZWQgcnVuX2NyZWF0ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW52YXJpYW50LCBzbyByZXRhaW4gdGhlIHJlc29sdmVkIEdFVCBvbmx5IGZvciB0aGVtLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsZWdhY3lSdW4gPSBhd2FpdCB3b3JsZC5ydW5zLmdldChydW5JZCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmVEYXRhOiAnYWxsJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsZWdhY3lSdW4uc3RhdHVzICE9PSAncnVubmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5SW5wdXQgPSBsZWdhY3lSdW4uaW5wdXQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1biA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uYmdSdW4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0OiByZXBsYXlJbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wbGV0ZWRBdDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93U3RhcnRlZEF0ID0gYmdTdGFydGVkQXQ7XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yQ29kZSA9IGdldFdvcmtmbG93U2V0dXBFcnJvckNvZGUoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoIWVycm9yQ29kZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBhd2FpdCByZWNvcmRGYXRhbFJ1bkVycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ01lc3NhZ2U6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICdGYXRhbCBlcnJvciB3aGlsZSBwcmVwYXJpbmcgYmFja2dyb3VuZCB3b3JrZmxvdyBzdGVwJyxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gRGVwbG95bWVudC1hZmZpbml0eSBwcmUtY2hlY2sgZm9yIHRoZSBsYXp5IGhvb2sgZmFzdFxuICAgICAgICAgICAgICAgICAgLy8gcGF0aCBiZWxvdy4gTmV3IGxhenktcmVzdW1lIG1lc3NhZ2VzIGNhcnJ5IHRoZSBydW4nc1xuICAgICAgICAgICAgICAgICAgLy8gcGlubmVkIGRlcGxveW1lbnQgKGBob29rSW5wdXQuZGVwbG95bWVudElkYCksIHNvIGFcbiAgICAgICAgICAgICAgICAgIC8vIG1pc3JvdXRlZCBkZWxpdmVyeSBpcyBkZXRlY3RhYmxlIHdpdGggYSBjaGVhcCBhbWJpZW50XG4gICAgICAgICAgICAgICAgICAvLyBkZXBsb3ltZW50LWlkIGNvbXBhcmlzb24gQkVGT1JFIHRoZSBmYXN0IHBhdGgnc1xuICAgICAgICAgICAgICAgICAgLy8gaG9va19yZWNlaXZlZCB3cml0ZSDigJQgdGhlIGNvcnJlY3RseS1yb3V0ZWQgY29tbW9uIGNhc2VcbiAgICAgICAgICAgICAgICAgIC8vIHBheXMgbm8gcnVuIGZldGNoIGFuZCBubyBsYXRlbmN5LiBPbmx5IGEgZGV0ZWN0ZWRcbiAgICAgICAgICAgICAgICAgIC8vIG1pc21hdGNoIGZldGNoZXMgdGhlIGF1dGhvcml0YXRpdmUgcnVuIGFuZCBoYW5kcyBpdCB0b1xuICAgICAgICAgICAgICAgICAgLy8gdGhlIGV4aXN0aW5nIGd1YXJkICh3aGljaCBvd25zIHJlLXJvdXRlL2ZhaWwgcG9saWN5KTtcbiAgICAgICAgICAgICAgICAgIC8vIHRoZSByZS1yb3V0ZWQgbWVzc2FnZSBrZWVwcyB0aGUgY29tcGxldGUgYGhvb2tJbnB1dGAsXG4gICAgICAgICAgICAgICAgICAvLyBzaW5jZSBpdCBtYXkgaG9sZCB0aGUgb25seSBjb3B5IG9mIHRoZSByZXN1bWUgcGF5bG9hZC5cbiAgICAgICAgICAgICAgICAgIC8vIFdoZW4gdGhlIHBpbm5lZCBvciBhbWJpZW50IGlkIGlzIHVuYXZhaWxhYmxlIChvbGRlclxuICAgICAgICAgICAgICAgICAgLy8gcHJvZHVjZXIgbWVzc2FnZSwgYSB3b3JsZCB3aXRob3V0IGRlcGxveW1lbnQgYWZmaW5pdHksXG4gICAgICAgICAgICAgICAgICAvLyBvciBhIGdldERlcGxveW1lbnRJZCBmYWlsdXJlKSwgYmVoYXZpb3IgaXMgdW5jaGFuZ2VkOlxuICAgICAgICAgICAgICAgICAgLy8gdGhlIGF1dGhvcml0YXRpdmUgZ3VhcmQgYWZ0ZXIgcnVuIHNldHVwIOKAlCB3aGljaCByZW1haW5zXG4gICAgICAgICAgICAgICAgICAvLyB0aGUgcHJvdGVjdGlvbiBiZWZvcmUgcmVwbGF5IGFuZCBzdGVwIGV4ZWN1dGlvbiDigJQgc3RpbGxcbiAgICAgICAgICAgICAgICAgIC8vIGNvdmVycyB0aGUgZGVsaXZlcnk7IHRoZSBmYXN0IHBhdGgncyB3cml0ZSBpcyBpZGVtcG90ZW50XG4gICAgICAgICAgICAgICAgICAvLyBwZXIgKHJ1bklkLCByZXN1bWVJZCksIHNvIGEgcHJlLWd1YXJkIHdyaXRlIGZyb20gYW5cbiAgICAgICAgICAgICAgICAgIC8vIG9sZGVyIG1lc3NhZ2Ugc3RheXMgY29udmVyZ2VudC5cbiAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgIXdvcmtmbG93UnVuICYmXG4gICAgICAgICAgICAgICAgICAgIGhvb2tJbnB1dD8uZGVwbG95bWVudElkICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgLy8gU2FtZSBlbGlnaWJpbGl0eSBhcyBndWFyZERlcGxveW1lbnRBZmZpbml0eTogd2l0aG91dFxuICAgICAgICAgICAgICAgICAgICAvLyBhdG9taWMsIGltbXV0YWJsZSBkZXBsb3ltZW50cyB0aGUgaWRzIGxlZ2l0aW1hdGVseVxuICAgICAgICAgICAgICAgICAgICAvLyBkaWZmZXIgKGUuZy4gZHBsX2xvY2FsQDx2ZXJzaW9uPikgYW5kIGNvbXBhcmluZyB0aGVtXG4gICAgICAgICAgICAgICAgICAgIC8vIHdvdWxkIHRyaWdnZXIgc3B1cmlvdXMgcnVuIGZldGNoZXMuXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkLmNhcGFiaWxpdGllcz8uZGVwbG95bWVudEFmZmluaXR5ID09PSB0cnVlXG4gICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGlubmVkRGVwbG95bWVudElkID0gaG9va0lucHV0LmRlcGxveW1lbnRJZDtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGN1cnJlbnREZXBsb3ltZW50SWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RGVwbG95bWVudElkID0gYXdhaXQgd29ybGQuZ2V0RGVwbG95bWVudElkKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnREZXBsb3ltZW50SWQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnREZXBsb3ltZW50SWQgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnREZXBsb3ltZW50SWQgIT09IHBpbm5lZERlcGxveW1lbnRJZFxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBydW4gPSBhd2FpdCB3b3JsZC5ydW5zLmdldChydW5JZCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZURhdGE6ICdub25lJyxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAoYXdhaXQgZ3VhcmREZXBsb3ltZW50KFxuICAgICAgICAgICAgICAgICAgICAgICAgICBydW4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGFzeW5jICgpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGF3YWl0IHJlcGxheU1lc3NhZ2UoKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaG9va0lucHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXRSdW5SZWFkeVxuICAgICAgICAgICAgICAgICAgICAgICAgKSkgIT09ICdjb250aW51ZSdcbiAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gLS0tIExhenkgaG9vayByZXN1bWUgZmFzdCBwYXRoIC0tLVxuICAgICAgICAgICAgICAgICAgLy8gQSBsYXp5IGhvb2sgZGVsaXZlcnkgKHJlc3VtZUlkICsgZGlnZXN0IG9uIHRoZSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZSkgaG9pc3RzIHRoZSBjb25zdW1lcidzIGlkZW1wb3RlbnQgaG9va19yZWNlaXZlZFxuICAgICAgICAgICAgICAgICAgLy8gcmUtZW5zdXJlIGFib3ZlIHJ1bl9zdGFydGVkIGFuZCBhc2tzIHRoZSBXb3JsZCB0byByZXR1cm5cbiAgICAgICAgICAgICAgICAgIC8vIHRoZSBjdXJyZW50IHJlcGxheSBsb2cgd2l0aCB0aGUgd3JpdGUgKHByZWxvYWRFdmVudHMpLiBBXG4gICAgICAgICAgICAgICAgICAvLyBzdXBwb3J0aW5nIFdvcmxkIGFuc3dlcnMgd2l0aCB0aGUgcmVjb25zdHJ1Y3RlZCBydW4sIHRoZVxuICAgICAgICAgICAgICAgICAgLy8gY29tcGxldGUgcmVwbGF5IGxvZywgYW5kIHRoZSBydW4ncyBldmVudCBjZWlsaW5nIOKAlFxuICAgICAgICAgICAgICAgICAgLy8gZXZlcnl0aGluZyB0aGUgZ2VuZXJpYyBzZXR1cCBiZWxvdyB3b3VsZCBzcGVuZCBhXG4gICAgICAgICAgICAgICAgICAvLyBydW5fc3RhcnRlZCBQT1NUIGFuZCBhbiBldmVudHMubGlzdCBvbi4gQW55IG90aGVyIHJlc3VsdFxuICAgICAgICAgICAgICAgICAgLy8gKG9sZGVyIHNlcnZlciwgYSBXb3JsZCB0aGF0IGlnbm9yZXMgdGhlIHBhcmFtLCBvciBhXG4gICAgICAgICAgICAgICAgICAvLyBwcmVsb2FkIHRoYXQgZmFpbHMgdmFsaWRhdGlvbiwgaW5jbHVkaW5nIGEgYm91bmRlZFxuICAgICAgICAgICAgICAgICAgLy8gaGFzTW9yZSBwYWdlKSBmYWxscyBiYWNrIHRvIHRoYXQgZ2VuZXJpYyBzZXR1cDsgdGhlXG4gICAgICAgICAgICAgICAgICAvLyBob29rX3JlY2VpdmVkIHdyaXRlIGl0c2VsZiBoYXMgc3RpbGwgc3VjY2VlZGVkIGVpdGhlclxuICAgICAgICAgICAgICAgICAgLy8gd2F5LCBzbyB0aGUgcmUtZW5zdXJlIGJsb2NrIGJlbG93IGlzIHNraXBwZWQgdmlhXG4gICAgICAgICAgICAgICAgICAvLyBgaG9va0Vuc3VyZWRgLiBOZXZlciB0YWtlbiBvbiB0dXJibyAodHVyYm8gZGVsaXZlcmllc1xuICAgICAgICAgICAgICAgICAgLy8gY2FycnkgcnVuSW5wdXQsIG5vdCBob29rSW5wdXQpIG9yIGFmdGVyIHRoZSBiYWNrZ3JvdW5kXG4gICAgICAgICAgICAgICAgICAvLyBzdGVwIHBhdGggYWxyZWFkeSBsb2FkZWQgdGhlIHJ1bi5cbiAgICAgICAgICAgICAgICAgIGxldCBob29rRW5zdXJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAhd29ya2Zsb3dSdW4gJiZcbiAgICAgICAgICAgICAgICAgICAgaG9va0lucHV0ICYmXG4gICAgICAgICAgICAgICAgICAgIGhvb2tJbnB1dC5yZXN1bWVJZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICAgICAgICAgIGhvb2tJbnB1dC5wYXlsb2FkRGlnZXN0ICE9PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBob29rUmVzdW1lSW5wdXQgPSBob29rSW5wdXQ7XG4gICAgICAgICAgICAgICAgICAgIC8vIERhdGUgdGhlIG1hdGVyaWFsaXplZCBldmVudCB0byB3aGVuIHRoZSByZXN1bWUgYWN0dWFsbHlcbiAgICAgICAgICAgICAgICAgICAgLy8gb2NjdXJyZWQg4oCUIHNhbWUgZGVyaXZhdGlvbiBhcyB0aGUgcmUtZW5zdXJlIGJlbG93ICh0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVzdW1lSWQgaXMgYSBVTElEIG1pbnRlZCBieSByZXN1bWVIb29rKCkgYXQgcmVzdW1lXG4gICAgICAgICAgICAgICAgICAgIC8vIHRpbWUpLlxuICAgICAgICAgICAgICAgICAgICBsZXQgb2NjdXJyZWRBdDogRGF0ZSB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICBvY2N1cnJlZEF0ID0gbmV3IERhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgICBkZWNvZGVUaW1lKGhvb2tSZXN1bWVJbnB1dC5yZXN1bWVJZClcbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAgICAgICBvY2N1cnJlZEF0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgc3Bhbj8uYWRkRXZlbnQoJ3dvcmtmbG93Lmhvb2tfcmVjZWl2ZWQuY3JlYXRlLnN0YXJ0Jywge1xuICAgICAgICAgICAgICAgICAgICAgICAgJ3dvcmtmbG93Lmhvb2tfcmVjZWl2ZWQucHJlbG9hZF9ldmVudHMnOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNyZWF0ZUV2ZW50KFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudFR5cGU6ICdob29rX3JlY2VpdmVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBob29rUmVzdW1lSW5wdXQuaG9va0lkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b2tlbjogaG9va1Jlc3VtZUlucHV0LnRva2VuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBheWxvYWQ6IGhvb2tSZXN1bWVJbnB1dC5wYXlsb2FkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBvY2N1cnJlZEF0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bWVJZDogaG9va1Jlc3VtZUlucHV0LnJlc3VtZUlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bWVQYXlsb2FkRGlnZXN0OiBob29rUmVzdW1lSW5wdXQucGF5bG9hZERpZ2VzdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlbG9hZEV2ZW50czogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIGhvb2tFbnN1cmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiB1bmxpa2UgdGhlIHJlLWVuc3VyZSBiZWxvdywgdGhpcyBob2lzdGVkIHdyaXRlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZG9lcyBOT1Qgc2V0IEhvb2tSZXNpbGllbnRSZXN1bWVNYXRlcmlhbGl6ZWQg4oCUIGl0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gcnVucyBvbiBldmVyeSBmYXN0LXBhdGggcmVzdW1lLCBpbmNsdWRpbmcgdGhlIGNvbW1vblxuICAgICAgICAgICAgICAgICAgICAgIC8vIGNhc2Ugd2hlcmUgdGhlIHByb2R1Y2VyJ3MgZGlyZWN0IHdyaXRlIGFscmVhZHkgbGFuZGVkXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIHRoaXMgY2FsbCBtZXJlbHkgY29udmVyZ2VkIG9uIGl0LCBzbyBpdCBjYXJyaWVzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gbm8gcmVjb3Zlcnkgc2lnbmFsLiB3b3JrZmxvdy5yZXN1bWVfc2V0dXBfc291cmNlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gKGJlbG93KSBkZXNjcmliZXMgdGhpcyBwYXRoIGluc3RlYWQuXG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcHJlbG9hZCBpcyB1c2FibGUgYXMgcmVwbGF5IGlucHV0IG9ubHkgd2hlbiBpdCBpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGRlbW9uc3RyYWJseSB0aGUgY29tcGxldGUgcGljdHVyZTogYSByZWNvbnN0cnVjdGVkXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcnVuIHdpdGggYSBzdGFydCB0aW1lLCBhIG5vbi1lbXB0eSBDT01QTEVURSBsb2dcbiAgICAgICAgICAgICAgICAgICAgICAvLyAoaGFzTW9yZSBmYWxzZSDigJQgdGhpcyBwYXRoIGhhcyBubyBjdXJzb3ItY29udGludWF0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgLy8gbWFjaGluZXJ5LCBzbyBhIGJvdW5kZWQgcGFnZSBtdXN0IG5vdCBiZSB0cnVzdGVkKSxcbiAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgc2VydmVyJ3MgZXZlbnQgY2VpbGluZyAodGhpcyByZXNwb25zZSBwbGF5c1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bl9zdGFydGVkJ3Mgcm9sZSwgc28gYSBtaXNzaW5nIGNlaWxpbmcgd291bGQgbGVhdmVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBldmVudC1saW1pdCBlbmZvcmNlbWVudCBkaXNhYmxlZCBmb3IgdGhlIHJ1biksXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYm90aCBydW4gbGlmZWN5Y2xlIGV2ZW50cywgdGhlIGNhbm9uaWNhbCBldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gd3JpdGUgY29udmVyZ2VkIG9uLCBhbmQgdGhlIGhvb2tfcmVjZWl2ZWQgbWF0Y2hpbmdcbiAgICAgICAgICAgICAgICAgICAgICAvLyBUSElTIHJlc3VtZSAoc28gd2UgbmV2ZXIgcmVwbGF5IGFnYWluc3QgYSBsb2cgdGhhdCBpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIG1pc3NpbmcgdGhlIHZlcnkgZXZlbnQgdGhhdCB0cmlnZ2VyZWQgdGhpcyBkZWxpdmVyeSkuXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgdXNhYmxlUmVwbGF5UHJlbG9hZCA9XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucnVuICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5ydW4uc3RhcnRlZEF0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5ldmVudCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuZXZlbnRzICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5ldmVudHMubGVuZ3RoID4gMCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmN1cnNvciAhPSBudWxsICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuaGFzTW9yZSA9PT0gZmFsc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiByZXN1bHQubWF4RXZlbnRzID09PSAnbnVtYmVyJyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmV2ZW50cy5zb21lKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAoZSkgPT4gZS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5ldmVudHMuc29tZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKGUpID0+IGUuZXZlbnRUeXBlID09PSAncnVuX3N0YXJ0ZWQnXG4gICAgICAgICAgICAgICAgICAgICAgICApICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuZXZlbnRzLnNvbWUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChlKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUuZXZlbnRUeXBlID09PSAnaG9va19yZWNlaXZlZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnJlc3VtZUlkID09PSBob29rUmVzdW1lSW5wdXQucmVzdW1lSWRcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICB1c2FibGVSZXBsYXlQcmVsb2FkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucnVuPy5zdGFydGVkQXQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5ldmVudHNcbiAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSByZWNvbnN0cnVjdGVkIHJ1biBhbHdheXMgcmVhZHMgJ3J1bm5pbmcnLCBidXQgYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybWluYWwgZXZlbnQgY29tbWl0dGVkIGNvbmN1cnJlbnRseSByaWRlcyBpbiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvZyBpdHNlbGYuIFRoZSBub2RlIHJlcGxheSBsb29wIHdvdWxkIGNhdGNoIGl0LCBidXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFF1aWNrSlMgZGlzcGF0Y2hlcyBiZWZvcmUgdGhhdCBjaGVjayDigJQgc28gY29uc3VtZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGRlbGl2ZXJ5IGhlcmUsIGJlZm9yZSBhbnkgZW5naW5lIHJ1bnMuIFNhbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG91dGNvbWUgYXMgdGhlIHJ1bl9zdGFydGVkIHBhdGgncyBub24tcnVubmluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RhdHVzIGNoZWNrLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGVybWluYWxFdmVudCA9IHJlc3VsdC5ldmVudHMuZmluZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKGUpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ydW5JZCA9PT0gcnVuSWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZS5ldmVudFR5cGUgPT09ICdydW5fY29tcGxldGVkJyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdydW5fZmFpbGVkJyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdydW5fY2FuY2VsbGVkJylcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGVybWluYWxFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcHJlbG9hZCBzdGlsbCBpbml0aWFsaXplZCB0aGlzIGRlbGl2ZXJ5IChpdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyBob3cgdGhlIHRlcm1pbmFsIHN0YXRlIHdhcyBvYnNlcnZlZCksIHNvIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBzZXR1cC1zb3VyY2UgYW5kIHRoZSBydW4ncyBhY3R1YWwgdGVybWluYWxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RhdHVzIGFyZSByZWNvcmRlZCBiZWZvcmUgY29uc3VtaW5nLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5TdGF0dXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtaW5hbEV2ZW50LmV2ZW50VHlwZSA9PT0gJ3J1bl9jb21wbGV0ZWQnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gJ2NvbXBsZXRlZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB0ZXJtaW5hbEV2ZW50LmV2ZW50VHlwZSA9PT0gJ3J1bl9mYWlsZWQnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAnZmFpbGVkJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogJ2NhbmNlbGxlZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Ib29rUmVzdW1lU2V0dXBTb3VyY2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaG9va19yZWNlaXZlZF9zdHJlYW0nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUnVuIGFscmVhZHkgZmluaXNoZWQgZHVyaW5nIGxhenkgaG9vayBzZXR1cCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiB0ZXJtaW5hbEV2ZW50LmV2ZW50VHlwZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuID0gcmVzdWx0LnJ1bjtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEV2ZW50c0xpbWl0ID0gY2xhbXBNYXhFdmVudHMocmVzdWx0Lm1heEV2ZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBbmNob3JzIFJTRlMg4oCUIHNlZSB0aGUgZGVjbGFyYXRpb24gYWJvdmUuIFRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlc3BvbnNlIHBsYXlzIHJ1bl9zdGFydGVkJ3Mgcm9sZSBvbiB0aGlzIHBhdGguXG4gICAgICAgICAgICAgICAgICAgICAgICBydW5TdGFydGVkUmVjZWl2ZWRBdE1zID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAncmVhZHknLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudHM6IHJlc3VsdC5ldmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnNvcjogcmVzdWx0LmN1cnNvcixcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdCA9ICtyZXN1bHQucnVuLnN0YXJ0ZWRBdDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5TdGF0dXMocmVzdWx0LnJ1bi5zdGF0dXMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dTdGFydGVkQXQod29ya2Zsb3dTdGFydGVkQXQpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuSG9va1Jlc3VtZVNldHVwU291cmNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdob29rX3JlY2VpdmVkX3N0cmVhbSdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTdWNjZXNzZnVsIHdyaXRlLCBubyB1c2FibGUgcHJlbG9hZCAoQ0JPUiByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZnJvbSBhbiBvbGRlciBzZXJ2ZXIsIGEgV29ybGQgdGhhdCBpZ25vcmVkIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3B0LWluLCBhIGJvdW5kZWQgaGFzTW9yZSBwYWdlLCBvciBhIHByZWxvYWQgdGhhdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmFpbGVkIHZhbGlkYXRpb24pOiB0YWtlIHRoZSBnZW5lcmljIHJ1bl9zdGFydGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzZXR1cCBiZWxvdy4gSXRzIHByZWxvYWQgaXMgbG9hZGVkIGFmdGVyIHRoaXMgd3JpdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbW1pdHRlZCwgc28gdGhlIGNhbm9uaWNhbCBob29rX3JlY2VpdmVkIGlzIHBhcnRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9mIHdoYXRldmVyIGxvZyB0aGF0IHNldHVwIHJlYWRzIOKAlCBubyBzcGxpY2VcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5lZWRlZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEF0dHJpYnV0ZS5Ib29rUmVzdW1lU2V0dXBTb3VyY2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2hvb2tfcmVjZWl2ZWRfZmFsbGJhY2snXG4gICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1lIGNsYXNzaWZpY2F0aW9uIGFzIHRoZSByZS1lbnN1cmUgYmVsb3c6XG4gICAgICAgICAgICAgICAgICAgICAgLy8gLSBIb29rTm90Rm91bmQgLyBSdW5FeHBpcmVkOiB0aGUgcnVuIHdlbnQgdGVybWluYWw7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gICBub3RoaW5nIGxlZnQgdG8gcmVzdW1lLCBjb25zdW1lIHRoZSBtZXNzYWdlLlxuICAgICAgICAgICAgICAgICAgICAgIC8vIC0gYW55dGhpbmcgZWxzZSAoRW50aXR5Q29uZmxpY3QsIGEgdHJ1bmNhdGVkIHByZWxvYWRcbiAgICAgICAgICAgICAgICAgICAgICAvLyAgIHN0cmVhbSwgdHJhbnNwb3J0IGZhaWx1cmVzKTogdHJhbnNpZW50IOKAlCByZXRocm93IHNvXG4gICAgICAgICAgICAgICAgICAgICAgLy8gICB0aGUgcXVldWUgcmVkZWxpdmVycyBhbmQgdGhlIGlkZW1wb3RlbnRcbiAgICAgICAgICAgICAgICAgICAgICAvLyAgIChydW5JZCwgcmVzdW1lSWQpIGNsYWltIGNvbnZlcmdlcyBvbiByZXRyeS5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICBIb29rTm90Rm91bmRFcnJvci5pcyhlcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKVxuICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAnUnVuIGFscmVhZHkgZmluaXNoZWQgZHVyaW5nIGxhenkgaG9vayBzZXR1cCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkLCBtZXNzYWdlOiBlcnIubWVzc2FnZSB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gLS0tIEluZnJhc3RydWN0dXJlOiBwcmVwYXJlIHRoZSBydW4gc3RhdGUgLS0tXG4gICAgICAgICAgICAgICAgICAvLyBTa2lwIGlmIHdvcmtmbG93UnVuIHdhcyBhbHJlYWR5IHNldCBieSB0aGUgYmFja2dyb3VuZFxuICAgICAgICAgICAgICAgICAgLy8gc3RlcCBwYXRoIChpbmxpbmUgcmVwbGF5IGFmdGVyIGFsbCBwYXJhbGxlbCBzdGVwcyBkb25lKVxuICAgICAgICAgICAgICAgICAgLy8gb3IgYnkgdGhlIGxhenkgaG9vayBmYXN0IHBhdGggYWJvdmUuXG4gICAgICAgICAgICAgICAgICBpZiAoIXdvcmtmbG93UnVuKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEFsd2F5cyBjYWxsIHJ1bl9zdGFydGVkIGRpcmVjdGx5IOKAlCB0aGlzIGJvdGggdHJhbnNpdGlvbnNcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHJ1biB0byAncnVubmluZycgQU5EIHJldHVybnMgdGhlIHJ1biBlbnRpdHksIHNhdmluZ1xuICAgICAgICAgICAgICAgICAgICAvLyBhIHNlcGFyYXRlIHJ1bnMuZ2V0IHJvdW5kLXRyaXAuXG4gICAgICAgICAgICAgICAgICAgIC8vIENvbnRyYWN0OiBldmVudHMuY3JlYXRlKCdydW5fc3RhcnRlZCcpIG11c3QgYmUgaWRlbXBvdGVudFxuICAgICAgICAgICAgICAgICAgICAvLyBmb3IgcnVucyBhbHJlYWR5IGluICdydW5uaW5nJyBzdGF0dXMgKHJldHVybiB0aGUgcnVuXG4gICAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgZXJyb3IpLCBub3QganVzdCBmb3IgcGVuZGluZyDihpIgcnVubmluZyB0cmFuc2l0aW9ucy5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcnVuU3RhcnRlZEV2ZW50ID0ge1xuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3J1bl9zdGFydGVkJyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIHNwZWMgdmVyc2lvbiBmcm9tIHRoZSBvcmlnaW5hbCBzdGFydCgpIGNhbGxcbiAgICAgICAgICAgICAgICAgICAgICAvLyB3aGVuIGF2YWlsYWJsZSwgc28gdGhlIHJlc2lsaWVudCBzdGFydCBwYXRoIGNyZWF0ZXNcbiAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcnVuIHdpdGggdGhlIGNvcnJlY3QgdmVyc2lvbiAobm90IGFsd2F5cyBjdXJyZW50KS5cbiAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjpcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklucHV0Py5zcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgICAvLyBQYXNzIHJ1biBpbnB1dCBmcm9tIHF1ZXVlIHNvIHRoZSBzZXJ2ZXIgY2FuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBydW4gaWYgcnVuX2NyZWF0ZWQgd2FzIG1pc3NlZC5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBVaW50OEFycmF5IHZhbHVlcyBzdXJ2aXZlIHRoZSBxdWV1ZSBuYXRpdmVseVxuICAgICAgICAgICAgICAgICAgICAgIC8vIChDQk9SIG9uIHdvcmxkLXZlcmNlbCwgSlNPTiByZXZpdmVyIG9uIHdvcmxkLWxvY2FsKS5cbiAgICAgICAgICAgICAgICAgICAgICAuLi4ocnVuSW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXQ6IHJ1bklucHV0LmlucHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwbG95bWVudElkOiBydW5JbnB1dC5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd05hbWU6IHJ1bklucHV0LndvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZWN1dGlvbkNvbnRleHQ6IHJ1bklucHV0LmV4ZWN1dGlvbkNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzOiBydW5JbnB1dC5hdHRyaWJ1dGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dSZXNlcnZlZEF0dHJpYnV0ZXM6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklucHV0LmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBpZiAodHVyYm8gJiYgcnVuSW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBUdXJibzogYmFja2dyb3VuZCBgcnVuX3N0YXJ0ZWRgIGFuZCBzeW50aGVzaXplIHRoZSBydW5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBlbnRpdHkgbG9jYWxseSBzbyByZXBsYXkgY2FuIGJlZ2luIHdpdGhvdXQgd2FpdGluZyBmb3JcbiAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcm91bmQtdHJpcC4gU2FmZSBoZXJlIGJlY2F1c2UgdGhpcyBpcyB0aGUgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAgICAvLyBkZWxpdmVyeSBvZiB0aGUgZmlyc3QgaW52b2NhdGlvbiDigJQgc3RhcnQoKSBjcmVhdGVkIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1biBtb21lbnRzIGFnbyBhbmQgbm8gZXZlbnRzIGhhdmUgYmVlbiB3cml0dGVuIHlldC4gVGhlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYmFycmllciBpcyBjb25zdW1lZCBieSBldmVyeSBkb3duc3RyZWFtIHdyaXRlIChzdXNwZW5zaW9uXG4gICAgICAgICAgICAgICAgICAgICAgLy8gaGFuZGxlciwgb3B0aW1pc3RpYyBzdGVwX3N0YXJ0ZWQsIHRlcm1pbmFsIHJ1biB3cml0ZXMpIHNvXG4gICAgICAgICAgICAgICAgICAgICAgLy8gbm90aGluZyBpcyB3cml0dGVuIGJlZm9yZSB0aGUgcnVuIGV4aXN0cy5cbiAgICAgICAgICAgICAgICAgICAgICBzcGFuPy5hZGRFdmVudCgnd29ya2Zsb3cucnVuX3N0YXJ0ZWQuY3JlYXRlLnN0YXJ0Jywge1xuICAgICAgICAgICAgICAgICAgICAgICAgJ3dvcmtmbG93LnJ1bl9zdGFydGVkLnNraXBfcHJlbG9hZCc6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RhcnRlZFByb21pc2UgPSBjcmVhdGVFdmVudChcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1blN0YXJ0ZWRFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdlIGJhY2tncm91bmQgdGhpcyBwdXJlbHkgYXMgYSB3cml0ZSBiYXJyaWVyIGFuZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbmV2ZXIgcmVhZCBpdHMgcHJlbG9hZGVkIGV2ZW50cywgc28gc2tpcCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bl9zdGFydGVkIGV2ZW50LWxvZyBwcmVsb2FkLiBUaGF0IHRyaW1zIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcnVuX3N0YXJ0ZWQgcmVxdWVzdCB0aGUgY2hhaW5lZCBmaXJzdCBzdGVwX3N0YXJ0ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdhaXRzIG9uIOKAlCBzaG9ydGVuaW5nIHRpbWUtdG8tc2Vjb25kLXN0ZXAg4oCUIGFuZCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdhc3RlZCBsaXN0K3Jlc29sdmUgaXQgd291bGQgb3RoZXJ3aXNlIGNvbXB1dGUuXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHJlcXVlc3RJZCwgc2tpcFByZWxvYWQ6IHRydWUgfVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgcnVuUmVhZHlCYXJyaWVyID0gc3RhcnRlZFByb21pc2U7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gVHVyYm8gYmFja2dyb3VuZHMgcnVuX3N0YXJ0ZWQsIHNvIHRoZSBub24tdHVyYm8gYXNzaWdubWVudFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGJlbG93IG5ldmVyIHJ1bnMg4oCUIHRocmVhZCB0aGUgcGVyLXJ1biBldmVudCBjZWlsaW5nIG9mZiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZ3JvdW5kZWQgcmVzcG9uc2UgaGVyZSBpbnN0ZWFkLiBUaGUgZ3VhcmQgcmUtY2hlY2tzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gbWF4RXZlbnRzTGltaXQgZXZlcnkgbG9vcCBpdGVyYXRpb24sIHNvIGEgdmFsdWUgdGhhdCBsYW5kc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHNob3J0bHkgYWZ0ZXIgc3RhcnQgc3RpbGwgZW5mb3JjZXMgd2VsbCBiZWZvcmUgYSBydW5hd2F5XG4gICAgICAgICAgICAgICAgICAgICAgLy8gbG9nIGFwcHJvYWNoZXMgdGhlIGNlaWxpbmcuXG4gICAgICAgICAgICAgICAgICAgICAgdm9pZCBzdGFydGVkUHJvbWlzZVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oKHIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbGltaXQgPSBjbGFtcE1heEV2ZW50cyhyLm1heEV2ZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsaW1pdCAhPT0gdW5kZWZpbmVkKSBtYXhFdmVudHNMaW1pdCA9IGxpbWl0O1xuICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByZXZlbnQgYW4gZWFybHkgZmFpbHVyZSBmcm9tIHN1cmZhY2luZyBhcyBhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdW5oYW5kbGVkUmVqZWN0aW9uOyBydW5SZWFkeUJhcnJpZXIgc3RpbGwgb2JzZXJ2ZXMgaXQuXG4gICAgICAgICAgICAgICAgICAgICAgICAuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFNraXAgdGhlIGluaXRpYWwgZXZlbnRzLmxpc3Q6IG5vdGhpbmcgaGFzIGJlZW4gd3JpdHRlbiB0b1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBsb2cgeWV0IG9uIGEgZmlyc3QgZGVsaXZlcnkgKHJ1bl9zdGFydGVkIGlzIHN0aWxsIGluXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZmxpZ2h0KS4gQW4gZW1wdHkgcHJlbG9hZCByb3V0ZXMgaXRlcmF0aW9uIDEgdGhyb3VnaFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBuby1sb2FkIHByZWxvYWRlZCBicmFuY2g7IGl0ZXJhdGlvbiAyIHRoZW4gdGFrZXMgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZXhpc3RpbmcgcG9zdC1wcmVsb2FkZWQgZnVsbCByZWxvYWQgdG8gcGljayB1cCBhIGN1cnNvclxuICAgICAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgYSBzcHVyaW91cyBcImN1cnNvciBtaXNzaW5nXCIgd2FybmluZy5cbiAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdyZWFkeScsXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudHM6IFtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1biA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXBsb3ltZW50SWQ6IHJ1bklucHV0LmRlcGxveW1lbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZTogcnVuSW5wdXQud29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IHJ1bklucHV0LnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXhlY3V0aW9uQ29udGV4dDogcnVuSW5wdXQuZXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0OiBydW5JbnB1dC5pbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNlZWQgYXR0cmlidXRlcyBmcm9tIHN0YXJ0KCkgcmlkZSBhbG9uZyBpbiBgcnVuSW5wdXRgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAodGhleSBsaXZlIGluIGBydW5fY3JlYXRlZGAncyBldmVudERhdGEsIG5vdCBzZXBhcmF0ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYGF0dHJfc2V0YCBldmVudHMpLCBzbyB0aGUgc3ludGhlc2l6ZWQgc25hcHNob3QgY2Fycmllc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbSBldmVuIHRob3VnaCB3ZSBza2lwIHRoZSBpbml0aWFsIGV2ZW50cy5saXN0LiBUaGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyBjb3JyZWN0IE9OTFkgd2hpbGUgYXR0cmlidXRlcyBhcmUgd3JpdGUtb25seTpcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZXJlIGlzIG5vIGluLXdvcmtmbG93IHJlYWQgQVBJIHRvZGF5IChzZWUgd29ya2Zsb3cudHNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFwic3RydWN0dXJhbCB1bnRpbCBhIHJlYWQgQVBJIGlzIGludHJvZHVjZWRcIiksIHNvIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZW1wdHkgcHJlbG9hZGVkIGxvZyBjYW4ndCBkaXZlcmdlIG9uIGEgcmVhZC4gSWYgYSByZWFkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBUEkgaXMgZXZlciBhZGRlZCBpdCBNVVNUIHJlYWQgZnJvbSB0aGlzIHNuYXBzaG90LCBub3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJ5IHJlcGxheWluZyBydW5fY3JlYXRlZC9hdHRyX3NldCBldmVudHMg4oCUIG90aGVyd2lzZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVyYm8ncyBlbXB0eSBpbml0aWFsIGxvZyB3b3VsZCBzdXJmYWNlIHNlZWQgYXR0cmlidXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXMgYHt9YCBvbiB0aGUgZmlyc3QgZGVsaXZlcnkgb25seS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM6IHJ1bklucHV0LmF0dHJpYnV0ZXMgPz8ge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGFydGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1N0YXJ0ZWRBdCA9ICtub3c7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gU2VlIHRoZSBgcnVuU3RhcnRlZFJlY2VpdmVkQXRNc2AgZGVjbGFyYXRpb24gYWJvdmU6XG4gICAgICAgICAgICAgICAgICAgICAgLy8gdHVyYm8gc3ludGhlc2l6ZXMgdGhlIHJ1biBiZWZvcmUgdGhlIHJlYWxcbiAgICAgICAgICAgICAgICAgICAgICAvLyBgcnVuX3N0YXJ0ZWRgIHJlc3BvbnNlIGxhbmRzLCBzbyBhbmNob3IgUlNGUyBoZXJlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmF0aGVyIHRoYW4gYXQgYW4gYWN0dWFsIHJlc3BvbnNlIGluc3RhbnQuXG4gICAgICAgICAgICAgICAgICAgICAgcnVuU3RhcnRlZFJlY2VpdmVkQXRNcyA9ICtub3c7XG4gICAgICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5TdGF0dXMoJ3J1bm5pbmcnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1N0YXJ0ZWRBdCh3b3JrZmxvd1N0YXJ0ZWRBdCksXG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4/LmFkZEV2ZW50KCd3b3JrZmxvdy5ydW5fc3RhcnRlZC5jcmVhdGUuc3RhcnQnLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICd3b3JrZmxvdy5ydW5fc3RhcnRlZC5za2lwX3ByZWxvYWQnOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY3JlYXRlRXZlbnQocnVuU3RhcnRlZEV2ZW50LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW4gPSByZXN1bHQucnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgbWF4RXZlbnRzTGltaXQgPSBjbGFtcE1heEV2ZW50cyhyZXN1bHQubWF4RXZlbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFuY2hvcnMgUlNGUyDigJQgc2VlIHRoZSBkZWNsYXJhdGlvbiBhYm92ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1blN0YXJ0ZWRSZWNlaXZlZEF0TXMgPSBEYXRlLm5vdygpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmV2ZW50cz8ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvYWRlZCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudHM6IFsuLi5yZXN1bHQuZXZlbnRzXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJzb3I6IHJlc3VsdC5jdXJzb3IgPz8gbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSByZXN1bHQuaGFzTW9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gbmV4dEV2ZW50TG9nTG9hZChsb2FkZWQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7IC4uLmxvYWRlZCwgdHlwZTogJ3JlYWR5JyB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dTdGFydGVkQXQgPSArcmVzdWx0LnJ1bi5zdGFydGVkQXQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKHJlc3VsdC5ydW4uc3RhdHVzKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93U3RhcnRlZEF0KHdvcmtmbG93U3RhcnRlZEF0KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LnJ1bi5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1dvcmtmbG93IGFscmVhZHkgY29tcGxldGVkIG9yIGZhaWxlZCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiByZXN1bHQucnVuLnN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogZm9yIGBjYW5jZWxgLCB3ZSBhY3R1YWxseSB3YW50IHRvIHByb3BhZ2F0ZSBhIFdvcmtmbG93Q2FuY2VsbGVkIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGluc2lkZSB0aGUgd29ya2Zsb3cgY29udGV4dCBzbyB0aGUgdXNlciBjYW4gZ3JhY2VmdWxseSBleGl0LiB0aGlzIGlzIFNJR1RFUk1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogZnVydGhlcm1vcmUsIHRoZXJlIHNob3VsZCBiZSBhIHRpbWVvdXQgb3IgYSB3YXkgdG8gZm9yY2UgY2FuY2VsIFNJR0tJTExcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gdGhhdCB3ZSBhY3R1YWxseSBleGl0IGhlcmUgd2l0aG91dCByZXBsYXlpbmcgdGhlIHdvcmtmbG93IGF0IGFsbCwgaW4gdGhlIGNhc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHJlcGxheWluZyB0aGUgd29ya2Zsb3cgaXMgaXRzZWxmIGZhaWxpbmcuXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUnVuIHdhcyBjb25jdXJyZW50bHkgY29tcGxldGVkL2ZhaWxlZC9jYW5jZWxsZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRW50aXR5Q29uZmxpY3RFcnJvcjogcnVuIHdhcyBjb25jdXJyZW50bHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29tcGxldGVkL2ZhaWxlZC9jYW5jZWxsZWQgZHVyaW5nIHNldHVwLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSdW5FeHBpcmVkRXJyb3I6IHJ1biBhbHJlYWR5IGluIHRlcm1pbmFsIHN0YXRlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJbiBib3RoIGNhc2VzLCBza2lwIHByb2Nlc3NpbmcgdGhpcyBtZXNzYWdlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1J1biBhbHJlYWR5IGZpbmlzaGVkIGR1cmluZyBzZXR1cCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQsIG1lc3NhZ2U6IGVyci5tZXNzYWdlIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JDb2RlID0gZ2V0V29ya2Zsb3dTZXR1cEVycm9yQ29kZShlcnIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWVycm9yQ29kZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCByZWNvcmRGYXRhbFJ1bkVycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dNZXNzYWdlOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0ZhdGFsIHJ1bnRpbWUgZXJyb3IgZHVyaW5nIHdvcmtmbG93IHNldHVwJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gLy8gZW5kIGVsc2UgKG5vbi10dXJibyBydW5fc3RhcnRlZClcbiAgICAgICAgICAgICAgICAgIH0gLy8gZW5kIGlmICghd29ya2Zsb3dSdW4pXG4gICAgICAgICAgICAgICAgICBhc3NlcnQoXG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgICAgICAgICAnV29ya2Zsb3cgcnVuIG11c3QgYmUgbG9hZGVkIGJlZm9yZSByZXBsYXknXG4gICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAvLyBDb3ZlcnMgZXZlcnkgZmxvdyByZXBsYXkg4oCUIGluaXRpYWwgc3RhcnQsIHN0ZXAgY29tcGxldGlvbnMsXG4gICAgICAgICAgICAgICAgICAvLyBob29rIHJlc3VtcHRpb25zLCB3YWl0IGNvbXBsZXRpb25zIOKAlCBhbmQgc3RvcHMgYmVmb3JlIGFueVxuICAgICAgICAgICAgICAgICAgLy8gd29ya2Zsb3cgY29kZSBvciBpbmxpbmUgc3RlcCBleGVjdXRlcyB3aGVuIHRoZSBydW4gaXMgbm90XG4gICAgICAgICAgICAgICAgICAvLyBwaW5uZWQgaGVyZSAoc2VlIGBndWFyZERlcGxveW1lbnRBZmZpbml0eWApLiBUaGlzIHJlbWFpbnNcbiAgICAgICAgICAgICAgICAgIC8vIHRoZSBBVVRIT1JJVEFUSVZFIHByb3RlY3Rpb24gYmVmb3JlIHJlcGxheSBhbmQgc3RlcFxuICAgICAgICAgICAgICAgICAgLy8gZXhlY3V0aW9uLiBgYXdhaXRSdW5SZWFkeWAgb3JkZXJzIHR1cmJvJ3MgYHJ1bl9zdGFydGVkYFxuICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIGVpdGhlciBzdG9wcGluZyBhY3Rpb24uXG4gICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgLy8gTGF6eSBob29rIHJlc3VtZXMgYXJlIGFkZGl0aW9uYWxseSBwcmUtY2hlY2tlZCBhYm92ZSB0aGVcbiAgICAgICAgICAgICAgICAgIC8vIGZhc3QgcGF0aDogYSBuZXcgbWVzc2FnZSdzIGBob29rSW5wdXQuZGVwbG95bWVudElkYCBpc1xuICAgICAgICAgICAgICAgICAgLy8gY29tcGFyZWQgYWdhaW5zdCB0aGUgYW1iaWVudCBkZXBsb3ltZW50IGlkIGZvciBmcmVlLCBhbmRcbiAgICAgICAgICAgICAgICAgIC8vIG9ubHkgYSBkZXRlY3RlZCBtaXNtYXRjaCBmZXRjaGVzIHRoZSBhdXRob3JpdGF0aXZlIHJ1biDigJRcbiAgICAgICAgICAgICAgICAgIC8vIHNvIGEgbWlzcm91dGVkIG1vZGVybiByZXN1bWUgcmUtcm91dGVzIHdpdGggemVybyBldmVudFxuICAgICAgICAgICAgICAgICAgLy8gd3JpdGVzLiBPbGRlciBtZXNzYWdlcyAobm8gYGhvb2tJbnB1dC5kZXBsb3ltZW50SWRgKSByZWFjaFxuICAgICAgICAgICAgICAgICAgLy8gdGhlIGZhc3QgcGF0aCdzIGlkZW1wb3RlbnQgaG9va19yZWNlaXZlZCB3cml0ZSBiZWZvcmUgdGhpc1xuICAgICAgICAgICAgICAgICAgLy8gZ3VhcmQ7IHRoYXQgd3JpdGUgY29udmVyZ2VzIHBlciAocnVuSWQsIHJlc3VtZUlkKSBvbiB0aGVcbiAgICAgICAgICAgICAgICAgIC8vIHBpbm5lZCBkZXBsb3ltZW50LCBzbyBpdCBpcyBzYWZlLCBqdXN0IG5vdCBmcmVlLiBFaXRoZXJcbiAgICAgICAgICAgICAgICAgIC8vIHdheSB0aGUgcmUtcm91dGVkIG1lc3NhZ2UgbXVzdCBjYXJyeSBgaG9va0lucHV0YCwgb3IgYVxuICAgICAgICAgICAgICAgICAgLy8gcmVzdW1lIHdob3NlIHByb2R1Y2VyIHdyaXRlIGhhZCBub3QgeWV0IGxhbmRlZCB3b3VsZCBiZVxuICAgICAgICAgICAgICAgICAgLy8gbG9zdC5cbiAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgKGF3YWl0IGd1YXJkRGVwbG95bWVudChcbiAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICAgICAgICBhc3luYyAoKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGF3YWl0IHJlcGxheU1lc3NhZ2UoKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAuLi4oaG9va0lucHV0ID8geyBob29rSW5wdXQgfSA6IHt9KSxcbiAgICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgICAgICBhd2FpdFJ1blJlYWR5XG4gICAgICAgICAgICAgICAgICAgICkpICE9PSAnY29udGludWUnXG4gICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAvLyBMYXp5IGhvb2sgcmVzdW1lOiB0aGUgcHJvZHVjZXIgKHJlc3VtZUhvb2sgZmFzdCBwYXRoKVxuICAgICAgICAgICAgICAgICAgLy8gcGFyYWxsZWxpemVkIHRoZSBgaG9va19yZWNlaXZlZGAgd3JpdGUgd2l0aCB0aGlzIHF1ZXVlXG4gICAgICAgICAgICAgICAgICAvLyBwdWJsaXNoLCBzbyB0aGUgZXZlbnQgbWF5IG5vdCBiZSBwZXJzaXN0ZWQgeWV0LiBJZGVtcG90ZW50bHlcbiAgICAgICAgICAgICAgICAgIC8vIGVuc3VyZSBpdCBiZWZvcmUgcmVwbGF5IOKAlCBrZXllZCBieSBgcmVzdW1lSWRgIHNvIGFcbiAgICAgICAgICAgICAgICAgIC8vIGNvbmN1cnJlbnQgcHJvZHVjZXIgd3JpdGUgY29udmVyZ2VzIG9uIGV4YWN0bHkgb25lIGV2ZW50XG4gICAgICAgICAgICAgICAgICAvLyAodGhlIHNlcnZlciByZXNvbHZlcyBhIG1hdGNoaW5nIGNsYWltIGFzIHN1Y2Nlc3MsIG5vdCBhblxuICAgICAgICAgICAgICAgICAgLy8gZXJyb3IpLiBgaG9va0lucHV0YCBuZXZlciByaWRlcyBhIHR1cmJvIGZpcnN0LWRlbGl2ZXJ5XG4gICAgICAgICAgICAgICAgICAvLyAodGhhdCBwYXRoIGNhcnJpZXMgYHJ1bklucHV0YCwgbm90IGBob29rSW5wdXRgKSwgc28gdGhpc1xuICAgICAgICAgICAgICAgICAgLy8gb25seSBydW5zIG9uIHRoZSBub3JtYWwgbG9hZC1hbmQtcmVwbGF5IHBhdGguIFNraXBwZWRcbiAgICAgICAgICAgICAgICAgIC8vIGVudGlyZWx5IHdoZW4gdGhlIGZhc3QgcGF0aCBhYm92ZSBhbHJlYWR5IGVuc3VyZWQgdGhlXG4gICAgICAgICAgICAgICAgICAvLyBldmVudCAoYGhvb2tFbnN1cmVkYCkg4oCUIHN1Y2Nlc3NmdWxseSBvciB2aWEgaXRzIGZhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgLy8gd2hvc2UgcnVuX3N0YXJ0ZWQgcHJlbG9hZCB3YXMgbG9hZGVkIGFmdGVyIHRoZSB3cml0ZSBhbmRcbiAgICAgICAgICAgICAgICAgIC8vIHRoZXJlZm9yZSBhbHJlYWR5IGNvbnRhaW5zIHRoZSBjYW5vbmljYWwgZXZlbnQuXG4gICAgICAgICAgICAgICAgICBpZiAoaG9va0lucHV0ICYmICFob29rRW5zdXJlZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBQZXJmIChPcHRpb24gQSk6IGlmIHRoZSBwcm9kdWNlcidzIGNvbmN1cnJlbnQgZGlyZWN0XG4gICAgICAgICAgICAgICAgICAgIC8vIHdyaXRlIGFscmVhZHkgbGFuZGVkIGluIHRoZSBydW5fc3RhcnRlZCBwcmVsb2FkLCB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gY2Fub25pY2FsIGV2ZW50IGlzIGluIHRoZSBsb2cgYW5kIHRoZSByZS1lbnN1cmUgcm91bmQgdHJpcFxuICAgICAgICAgICAgICAgICAgICAvLyBpcyBwdXJlIG92ZXJoZWFkLiBTa2lwIGl0IHdoZW4gdGhlIHByZWxvYWQgYWxyZWFkeSBjYXJyaWVzXG4gICAgICAgICAgICAgICAgICAgIC8vIGEgYGhvb2tfcmVjZWl2ZWRgIHdpdGggdGhpcyByZXN1bWUncyBwZXJzaXN0ZWQgYHJlc3VtZUlkYFxuICAgICAgICAgICAgICAgICAgICAvLyAodW5pcXVlIHBlciByZXN1bWUsIHNvIHdlIG5ldmVyIHNraXAgb24gYW4gdW5yZWxhdGVkXG4gICAgICAgICAgICAgICAgICAgIC8vIGhvb2tfcmVjZWl2ZWQpLiBCZXN0LWVmZm9ydDogdGhlIHdpbiBsYW5kcyBvbmx5IHdoZW4gdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHByb2R1Y2VyJ3Mgd3JpdGUgYmVhdCB0aGlzIGNvbnN1bWVyJ3MgbG9hZDsgb3RoZXJ3aXNlIHdlXG4gICAgICAgICAgICAgICAgICAgIC8vIGZhbGwgdGhyb3VnaCB0byB0aGUgaWRlbXBvdGVudCByZS1lbnN1cmUgYmVsb3cuXG4gICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgIC8vIEludGVudGlvbmFsbHkgdW5yZWFjaGFibGUgZm9yIGF0b21pYyBsYXp5IHJlc3VtZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gKHJlc3VtZUlkICsgZGlnZXN0KTogdGhvc2Ugc2V0IGBob29rRW5zdXJlZGAgaW4gdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIGhvaXN0ZWQgZmFzdCBwYXRoIGFib3ZlIOKAlCBvbiBzdWNjZXNzIEFORCBvbiBpdHNcbiAgICAgICAgICAgICAgICAgICAgLy8gZmFsbGJhY2sg4oCUIHNvIHRoaXMgYmxvY2sgKGFuZCB0aGUgc2tpcCBjaGVjaykgbm93IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgLy8gc2VydmVzIGhvb2tJbnB1dCBzaGFwZXMgd2l0aG91dCB0aGUgZnVsbCBpZGVtcG90ZW5jeVxuICAgICAgICAgICAgICAgICAgICAvLyBwYWlyLlxuICAgICAgICAgICAgICAgICAgICBjb25zdCBhbHJlYWR5UHJlbG9hZGVkID1cbiAgICAgICAgICAgICAgICAgICAgICBob29rSW5wdXQucmVzdW1lSWQgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgIT09ICdsb2FkQWxsJyAmJlxuICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmV2ZW50cy5zb21lKFxuICAgICAgICAgICAgICAgICAgICAgICAgKGUpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGUuZXZlbnRUeXBlID09PSAnaG9va19yZWNlaXZlZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZS5yZXN1bWVJZCA9PT0gaG9va0lucHV0LnJlc3VtZUlkXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGFscmVhZHlQcmVsb2FkZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBFdmVudCBhbHJlYWR5IHZpc2libGUgaW4gdGhlIHByZWxvYWRlZCBsb2cg4oCUIG5vdGhpbmcgdG9cbiAgICAgICAgICAgICAgICAgICAgICAvLyBlbnN1cmUgb3Igc3BsaWNlLlxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIERhdGUgdGhlIG1hdGVyaWFsaXplZCBldmVudCB0byB3aGVuIHRoZSByZXN1bWUgYWN0dWFsbHlcbiAgICAgICAgICAgICAgICAgICAgICAvLyBvY2N1cnJlZCwgbm90IHdoZW4gdGhpcyBxdWV1ZSBkZWxpdmVyeSByYW4uIGByZXN1bWVJZGBcbiAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB0aGUgVUxJRCBtaW50ZWQgYnkgYHJlc3VtZUhvb2soKWAgYXQgcmVzdW1lIHRpbWUsIHNvXG4gICAgICAgICAgICAgICAgICAgICAgLy8gaXRzIGVtYmVkZGVkIHRpbWVzdGFtcCBpcyB0aGUgaG9uZXN0IGBvY2N1cnJlZEF0YCBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBrZWVwcyBsYXRlbmN5IGF0dHJpYnV0aW9uIG9mZiB0aGUgcXVldWUgcm91bmQgdHJpcC4gQVxuICAgICAgICAgICAgICAgICAgICAgIC8vIG5vbi1VTElEIHJlc3VtZUlkIChsZWdhY3kgLyB0ZXN0KSBzaW1wbHkgbGVhdmVzIGl0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gdW5kZWZpbmVkLCBzbyB0aGUgV29ybGQgZmFsbHMgYmFjayB0byBgY3JlYXRlZEF0YC5cbiAgICAgICAgICAgICAgICAgICAgICBsZXQgb2NjdXJyZWRBdDogRGF0ZSB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2NjdXJyZWRBdCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGhvb2tJbnB1dC5yZXN1bWVJZCAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBuZXcgRGF0ZShkZWNvZGVUaW1lKGhvb2tJbnB1dC5yZXN1bWVJZCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvY2N1cnJlZEF0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBsZXQgZW5zdXJlZEV2ZW50OiBFdmVudCB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZW5zdXJlZCA9IGF3YWl0IHdvcmxkLmV2ZW50cy5jcmVhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnaG9va19yZWNlaXZlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGhvb2tJbnB1dC5ob29rSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b2tlbjogaG9va0lucHV0LnRva2VuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF5bG9hZDogaG9va0lucHV0LnBheWxvYWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvY2N1cnJlZEF0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VtZUlkOiBob29rSW5wdXQucmVzdW1lSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdW1lUGF5bG9hZERpZ2VzdDogaG9va0lucHV0LnBheWxvYWREaWdlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDb25zdW1lci1zaWRlIGNvbXBsZXRpb24gb2YgdGhlIHJlY292ZXJ5IHBhdGg6IHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheSBtYXRlcmlhbGl6ZWQgdGhlIGV2ZW50IGJlY2F1c2UgdGhlIHByb2R1Y2VyJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRpcmVjdCB3cml0ZSBoYWQgbm90IGxhbmRlZCBpbiB0aGUgcHJlbG9hZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEF0dHJpYnV0ZS5Ib29rUmVzaWxpZW50UmVzdW1lTWF0ZXJpYWxpemVkKHRydWUpXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGNhbm9uaWNhbCBldmVudCDigJQgd2hldGhlciB0aGlzIGNhbGwgY29tbWl0dGVkIGl0IG9yXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjb252ZXJnZWQgb24gdGhlIHByb2R1Y2VyJ3MgY29uY3VycmVudCB3cml0ZSDigJQgc28gd2UgY2FuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzcGxpY2UgaXQgaW50byB0aGUgcHJlbG9hZGVkIGxvZyBpbnN0ZWFkIG9mIGRpc2NhcmRpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBwcmVsb2FkIChzZWUgYmVsb3cpLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlY29uc3RydWN0IGBldmVudERhdGFgIGZyb20gYGhvb2tJbnB1dGAgcmF0aGVyIHRoYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRydXN0aW5nIHRoZSBQT1NUIHJlc3BvbnNlJ3MgcGF5bG9hZDogd29ybGQtdmVyY2VsIHBvc3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBob29rX3JlY2VpdmVkIHdpdGggYHJlbW90ZVJlZkJlaGF2aW9yOiAnbGF6eSdgLCBzbyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHVybmVkIGV2ZW50J3MgcGF5bG9hZCBpcyBhIFJlbW90ZVJlZiAqZGVzY3JpcHRvciosIG5vdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHNlcmlhbGl6ZWQgYnl0ZXMgcmVwbGF5IG5lZWRzLiBgaG9va0lucHV0YCBjYXJyaWVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcmVhbCB0b2tlbiArIHBheWxvYWQgYnl0ZXMgKHRoZXkgcm9kZSB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1lc3NhZ2UpLCBzbyBzcGxpY2UgdGhvc2Ugb250byB0aGUgcmV0dXJuZWQgZXZlbnQnc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RhYmxlIGV2ZW50SWQvbWV0YWRhdGEuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcmUtZW5zdXJlIGFsd2F5cyByZXR1cm5zIGEgYGhvb2tfcmVjZWl2ZWRgIGV2ZW50LCBzb1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHNwbGljZSBpcyBzYWZlLiBUaGUgY2FzdCBpcyBuZWVkZWQgYmVjYXVzZSBzcHJlYWRpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSByYXcgYEV2ZW50YCB1bmlvbiBhbmQgb3ZlcnJpZGluZyBgZXZlbnREYXRhYCBjb2xsYXBzZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIGEgbm9uLWBob29rX3JlY2VpdmVkYCBtZW1iZXIgKHdob3NlIGBldmVudERhdGFgIGlzIGFcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRpZmZlcmVudCBzaGFwZSk7IHRoZSBvYmplY3QgaXMgYSBnZW51aW5lIGBob29rX3JlY2VpdmVkYFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXZlbnQgYnkgY29uc3RydWN0aW9uLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFzZSA9IGVuc3VyZWQuZXZlbnQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbnN1cmVkRXZlbnQgPSBiYXNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgID8gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmJhc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW46IGhvb2tJbnB1dC50b2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF5bG9hZDogaG9va0lucHV0LnBheWxvYWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gYXMgRXZlbnQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBtYXRjaGluZyBjb25jdXJyZW50IGNsYWltIChzYW1lIHJlc3VtZUlkICsgZGlnZXN0KSBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVzb2x2ZWQgYXMgc3VjY2VzcyBzZXJ2ZXItc2lkZSBhbmQgbmV2ZXIgdGhyb3dzLCBzb1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW55dGhpbmcgY2F1Z2h0IGhlcmUgaXMgYSBnZW51aW5lIHRlcm1pbmFsIG9yIHRyYW5zaWVudFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uZGl0aW9uOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC0gSG9va05vdEZvdW5kIC8gUnVuRXhwaXJlZDogdGhlIHByb2R1Y2VyJ3MgZGlyZWN0IHdyaXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIGFscmVhZHkgZW5kZWQgdGhpcyByZXN1bWUncyBlbGlnaWJpbGl0eSAodGhlIHJ1biB3ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIHRlcm1pbmFsKS4gVGhlcmUgaXMgbm90aGluZyBsZWZ0IHRvIHJlc3VtZSwgc28gY29uc3VtZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICB0aGUgbWVzc2FnZSBhbmQgc3RvcC4gQ29udGludWluZyB0byByZXBsYXkgd291bGQgYmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgd2FzdGVkIHdvcmsg4oCUIGFuZCwgd29yc2UsIHdvdWxkIGFjayBhIGRlbGl2ZXJ5IHRoYXQgbWF5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIGNhcnJ5IHRoZSBvbmx5IGNvcHkgb2YgdGhlIHBheWxvYWQuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEhvb2tOb3RGb3VuZEVycm9yLmlzKGVycikgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgUnVuRXhwaXJlZEVycm9yLmlzKGVycilcbiAgICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAtIEVudGl0eUNvbmZsaWN0IChhbmQgYW55IG90aGVyIHVuZXhwZWN0ZWQgZXJyb3IpOiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgcmVzdW1lSWQgY29uc3RyYWludCBleGlzdHMgYnV0IHRoZSBtYXRjaGluZyBldmVudCBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICBub3QgeWV0IG9ic2VydmFibGUg4oCUIHRoZSBwcm9kdWNlcidzIHBhcmFsbGVsIHdyaXRlIGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIHN0aWxsIGluIGZsaWdodCwgb3IgYSByZWRyaXZlIHJhY2VkIHRoZSBjbGFpbS4gVGhpcyBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICB0cmFuc2llbnQ6IHJldGhyb3cgc28gdGhlIHF1ZXVlIHJlZGVsaXZlcnMgYW5kIGEgbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgYXR0ZW1wdCBjb252ZXJnZXMgb24gdGhlIGNvbW1pdHRlZCBldmVudCBpbnN0ZWFkIG9mXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIHJlcGxheWluZyAoYW5kIGFja2luZykgd2l0aG91dCB0aGUgcGF5bG9hZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHJ1bl9zdGFydGVkIHJlc3BvbnNlIHByZWxvYWRlZCB0aGUgbG9nIEJFRk9SRSB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZW5zdXJlLCBzbyBpdCBjYW5ub3QgaW5jbHVkZSB0aGUgaG9va19yZWNlaXZlZC4gUmF0aGVyXG4gICAgICAgICAgICAgICAgICAgICAgLy8gdGhhbiBkaXNjYXJkIHRoZSBwcmVsb2FkICh3aGljaCB3b3VsZCBjb3N0IGEgZnJlc2hcbiAgICAgICAgICAgICAgICAgICAgICAvLyBldmVudHMubGlzdCByb3VuZCB0cmlwIG9uIHRoZSBmaXJzdCByZXBsYXkgaXRlcmF0aW9uKSxcbiAgICAgICAgICAgICAgICAgICAgICAvLyBzcGxpY2UgaW4gdGhlIGNhbm9uaWNhbCBldmVudCByZWNvbnN0cnVjdGVkIGFib3ZlLiBJdFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGNhcnJpZXMgYSBzdGFibGUgZXZlbnRJZCwgc28gYGluc2VydEV2ZW50QnlFdmVudElkYCBrZWVwc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGl0IGluIGFzY2VuZGluZyBldmVudElkIG9yZGVyIGFuZCBpcyBpZGVtcG90ZW50IGlmIGEgbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAvLyBsaXN0IHJlLW9ic2VydmVzIGl0LiBPbmx5IHdoZW4gdGhlIFdvcmxkIHJldHVybnMgbm8gZXZlbnRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBkbyB3ZSBmYWxsIGJhY2sgdG8gcmVsb2FkaW5nIHRoZSBjb21wbGV0ZSBsb2cuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKGV2ZW50TG9nLnR5cGUgIT09ICdsb2FkQWxsJyAmJiBlbnN1cmVkRXZlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluc2VydEV2ZW50QnlFdmVudElkKGV2ZW50TG9nLmV2ZW50cywgZW5zdXJlZEV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSB7IHR5cGU6ICdsb2FkQWxsJyB9O1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSAvLyBlbmQgZWxzZSAocmUtZW5zdXJlIG5lZWRlZClcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgLy8gUmVzb2x2ZSB0aGUgZW5jcnlwdGlvbiBrZXkgZm9yIHRoaXMgcnVuJ3MgZGVwbG95bWVudC5cbiAgICAgICAgICAgICAgICAgIC8vIFVzZWQgZWFnZXJseSBoZXJlIHNpbmNlIGJvdGggd29ya2Zsb3cgZXhlY3V0aW9uIChpbnB1dFxuICAgICAgICAgICAgICAgICAgLy8gaHlkcmF0aW9uIC8gaG9vayBwYXlsb2FkIGRlY3J5cHRpb24pIGFuZCB0aGUgcnVuX2ZhaWxlZFxuICAgICAgICAgICAgICAgICAgLy8gZGVoeWRyYXRlIHBhdGggYmVsb3cgbmVlZCBpdC4gTWVtb2l6ZWQgYWNjZXNzb3I6IGZpcnN0XG4gICAgICAgICAgICAgICAgICAvLyBjYWxsIHRyaWdnZXJzIHRoZSBhY3R1YWwgZmV0Y2ggLyBIS0RGIGRlcml2YXRpb24sXG4gICAgICAgICAgICAgICAgICAvLyBzdWJzZXF1ZW50IGNhbGxzIGF3YWl0IHRoZSBjYWNoZWQgcHJvbWlzZS5cbiAgICAgICAgICAgICAgICAgIGNvbnN0IGdldEVuY3J5cHRpb25LZXkgPSBtZW1vaXplRW5jcnlwdGlvbktleShcbiAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY29uc3QgZW5jcnlwdGlvbktleSA9IGF3YWl0IGdldEVuY3J5cHRpb25LZXkoKTtcblxuICAgICAgICAgICAgICAgICAgLy8gSW52b2NhdGlvbi1zY29wZWQgY2FjaGUgb2YgVk0taW5kZXBlbmRlbnQgcHJlcGFyZWQgcGF5bG9hZHNcbiAgICAgICAgICAgICAgICAgIC8vIGFuZCBpbW11dGFibGUgZmluYWwgdmFsdWVzLiBJdCBzdXJ2aXZlcyB0aGUgZnJlc2ggd29ya2Zsb3dcbiAgICAgICAgICAgICAgICAgIC8vIFZNIGNyZWF0ZWQgYnkgZWFjaCBpbmxpbmUgcmVwbGF5LCBidXQgbmV2ZXIgY3Jvc3NlcyBydW5zIG9yXG4gICAgICAgICAgICAgICAgICAvLyBxdWV1ZSBkZWxpdmVyaWVzLlxuICAgICAgICAgICAgICAgICAgY29uc3QgcmVwbGF5UGF5bG9hZENhY2hlID0gbmV3IFJlcGxheVBheWxvYWRDYWNoZShcbiAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgLy8gVGhlIGxpdmUgVk0gcGFya2VkIGF0IHRoZSBwcmV2aW91cyBib3VuZGFyeSwgd2hlbiB0aGVcbiAgICAgICAgICAgICAgICAgIC8vIHJldGVudGlvbiBkZWNpc2lvbiBrZXB0IGl0LiBudWxsIOKGkiB0aGlzIGl0ZXJhdGlvbiBjb2xkLVxuICAgICAgICAgICAgICAgICAgLy8gcmVwbGF5cy4gSW52b2NhdGlvbi1zY29wZWQ6IGRpZXMgd2l0aCB0aGlzIGRlbGl2ZXJ5LlxuICAgICAgICAgICAgICAgICAgbGV0IHJldGFpbmVkU2Vzc2lvbjogV29ya2Zsb3dTZXNzaW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgICAgICAgICAgICAgICAgIC8vIE1haW4gcmVwbGF5IGxvb3BcbiAgICAgICAgICAgICAgICAgIC8vIGJpb21lLWlnbm9yZSBsaW50L2NvcnJlY3RuZXNzL25vQ29uc3RhbnRDb25kaXRpb246IGludGVudGlvbmFsIGxvb3BcbiAgICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvb3BJdGVyYXRpb24rKztcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZXBsYXktYnVkZ2V0IGNoZWNrOiBiYWlsIG91dCAocmV0cnkgb3IgZmFpbCkgaWZcbiAgICAgICAgICAgICAgICAgICAgLy8gbm9uLXN0ZXAgdGltZSB3aXRoaW4gdGhpcyBpbnZvY2F0aW9uIGhhcyBleGNlZWRlZFxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgY29uZmlndXJlZCBidWRnZXQuIFN0ZXAgYm9kaWVzIGFyZSBleGNsdWRlZFxuICAgICAgICAgICAgICAgICAgICAvLyBiZWNhdXNlIHJlcGxheUJ1ZGdldC5wYXVzZSgpL3Jlc3VtZSgpIGJyYWNrZXQgZXZlcnlcbiAgICAgICAgICAgICAgICAgICAgLy8gYGV4ZWN1dGVTdGVwYCBjYWxsLlxuICAgICAgICAgICAgICAgICAgICBpZiAocmVwbGF5QnVkZ2V0LmlzRXhoYXVzdGVkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBoYW5kbGVSZXBsYXlCdWRnZXRFeGhhdXN0ZWQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd05hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBhdHRlbXB0OiBtZXRhZGF0YS5hdHRlbXB0LFxuICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRNczogcmVwbGF5QnVkZ2V0LmNvbmZpZ3VyZWRMaW1pdE1zLFxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgIC8vIE9ubHkgdGhlIHRlcm1pbmFsIGF0dGVtcHQgcmV0dXJucywgYWZ0ZXIgcnVuX2ZhaWxlZCBpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGR1cmFibGUuIEVhcmxpZXIgYXR0ZW1wdHMgcmVqZWN0IGZvciBxdWV1ZSByZWRlbGl2ZXJ5LlxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIENoZWNrIHRpbWVvdXQgYmVmb3JlIHJlcGxheVxuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgRGF0ZS5ub3coKSAtIGludm9jYXRpb25TdGFydFRpbWUgPj1cbiAgICAgICAgICAgICAgICAgICAgICBub0lubGluZVJlcGxheUFmdGVyTXNcbiAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgJ1YyIHRpbWVvdXQgcmVhY2hlZCwgcmUtc2NoZWR1bGluZyB3b3JrZmxvdycsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wSXRlcmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBlbGFwc2VkTXM6IERhdGUubm93KCkgLSBpbnZvY2F0aW9uU3RhcnRUaW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgYXdhaXQgcXVldWVNZXNzYWdlKFxuICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgICAgICBnZXRXb3JrZmxvd1F1ZXVlTmFtZSh3b3JrZmxvd05hbWUsIG5hbWVzcGFjZSksXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFjZUNhcnJpZXI6IGF3YWl0IG5leHRUcmFjZUNhcnJpZXIoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBsZXQgcmVwbGF5U3RhcnQgPSAwO1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIC0tLSBRdWlja0pTIFZNIGVuZ2luZSBkaXNwYXRjaCAtLS1cbiAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgUXVpY2tKUyBlbmdpbmUgKG9wdC1pbiB2aWEgV09SS0ZMT1dfVk09cXVpY2tqc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIG9yIGV4ZWN1dGlvbkNvbnRleHQud29ya2Zsb3dWbSkgaXMgYSBzZWxmLWNvbnRhaW5lZFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFsdGVybmF0aXZlIHRvIHRoZSBub2RlOnZtIGlubGluZS1yZXBsYXkgbG9naWNcbiAgICAgICAgICAgICAgICAgICAgICAvLyBiZWxvdy4gSXQgcGVyZm9ybXMgdGhlIHNhbWUgZnVsbCBldmVudCByZXBsYXksIGJ1dFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bnMgdGhlIHdvcmtmbG93IGNvZGUgaW4gYSBRdWlja0pTIFdBU00gVk0sIHF1ZXVlc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXBzIHZpYSB0aGUgc2FtZSBjb21iaW5lZCByb3V0ZSAoc28gdGhleSBoaXRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBleGVjdXRlU3RlcCBiZWxvdyBvbiByZS1lbnRyeSksIGFuZCBtYW5hZ2VzIGl0cyBvd25cbiAgICAgICAgICAgICAgICAgICAgICAvLyBydW5fY29tcGxldGVkIC8gcnVuX2ZhaWxlZCBsaWZlY3ljbGUgZm9yIHdvcmtmbG93XG4gICAgICAgICAgICAgICAgICAgICAgLy8gb3V0Y29tZXMuIFdoZW4gdGhlIFF1aWNrSlMgZW5naW5lIGlzIGluIGVmZmVjdCxcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZXR1cm4gaW1tZWRpYXRlbHkgYWZ0ZXIgZGlzcGF0Y2guXG4gICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAvLyBEZWxpYmVyYXRlbHkgSU5TSURFIHRoaXMgdHJ5OiBlbmdpbmUgZmFpbHVyZXMgdGhhdFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGVzY2FwZSB0aGUgZW50cnlwb2ludCAoTWF4RXZlbnRzRXhjZWVkZWRFcnJvciwgYVxuICAgICAgICAgICAgICAgICAgICAgIC8vIFdBU00gT09NIGF0IHRoZSBtZW1vcnkgY2VpbGluZywgYSBidW5kbGUtZXZhbFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGZhaWx1cmUpIG11c3QgcmVhY2ggdGhpcyBsb29wJ3MgY2F0Y2ggc28gdGhleSBhcmVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBjbGFzc2lmaWVkIGFuZCByZWNvcmRlZCBhcyBydW5fZmFpbGVkIOKAlCBvdXRzaWRlIHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIHRyeSB0aGV5IHdvdWxkIG5hY2sgdGhlIG1lc3NhZ2UgYW5kIGJ1cm4gYWxsIHF1ZXVlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmVkZWxpdmVyaWVzIGJlZm9yZSBkeWluZyBhc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIE1BWF9ERUxJVkVSSUVTX0VYQ0VFREVELiBUcmFuc2llbnQgd29ybGQgZXJyb3JzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgcmV0aHJvdyBvdXQgb2YgdGhlIGNhdGNoIGZvciByZWRlbGl2ZXJ5LCBzYW1lXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYXMgbm9kZS1lbmdpbmUgcmVwbGF5IGZhaWx1cmVzLlxuICAgICAgICAgICAgICAgICAgICAgIGlmICh1c2VRdWlja0pTVm0od29ya2Zsb3dSdW4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdVc2luZyBRdWlja0pTIFZNIGVuZ2luZScsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BJdGVyYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVuZGVyIHR1cmJvLCBydW5fc3RhcnRlZCBpcyBiYWNrZ3JvdW5kZWQuIFRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUXVpY2tKUyBlbnRyeXBvaW50IGZldGNoZXMgdGhlIGV2ZW50IGxvZyBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdyaXRlcyBldmVudHMgZGlyZWN0bHksIHNvIHdhaXQgZm9yIHRoZSBydW4gdG8gYmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGR1cmFibHkgc3RhcnRlZCBmaXJzdCDigJQgaXQgZG9lcyBub3QgdGhyZWFkIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVyYm8gcnVuUmVhZHlCYXJyaWVyIHRoZSB3YXkgaGFuZGxlU3VzcGVuc2lvblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZG9lcy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGF3YWl0UnVuUmVhZHkoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChldmVudExvZy50eXBlID09PSAnbG9hZEFmdGVyJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBlbmRFdmVudExvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBsb2FkV29ya2Zsb3dSdW5FdmVudHMocnVuSWQsIGV2ZW50TG9nLmN1cnNvcilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSB7IC4uLmV2ZW50TG9nLCB0eXBlOiAncmVhZHknIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBMYXp5IGltcG9ydDogdGhlIFF1aWNrSlMgZW50cnlwb2ludCdzIGltcG9ydCBjaGFpblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZW1iZWRzIHRoZSBiYXNlNjQgV0FTTSBiaW5hcnkgKyBleHRlbnNpb25zXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAofjEuMyBNQiBkZWNvZGVkIGF0IG1vZHVsZSBzY29wZSkuIExvYWRpbmcgaXQgaGVyZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8ga2VlcHMgdGhhdCBvdXQgb2Ygbm9kZS1lbmdpbmUgZGVwbG95bWVudHMgZW50aXJlbHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIOKAlCBvbmx5IHRoZSBvcHQtaW4gcGF0aCBwYXlzLCBvbiBmaXJzdCBkaXNwYXRjaC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHsgcnVuV29ya2Zsb3dXaXRoUXVpY2tKUyB9ID0gYXdhaXQgaW1wb3J0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAnLi9ydW50aW1lL3F1aWNranMtZW50cnlwb2ludC5qcydcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBxdWlja2pzUmVzdWx0ID0gYXdhaXQgcnVuV29ya2Zsb3dXaXRoUXVpY2tKUyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93Q29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlbG9hZGVkRXZlbnRzOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgPT09ICdyZWFkeSdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gZXZlbnRMb2cuZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlbG9hZGVkRXZlbnRzQ29tcGxldGU6IGV2ZW50TG9nLnR5cGUgPT09ICdyZWFkeScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklucHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRTcGFuOiBzcGFuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhFdmVudHNMaW1pdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNwYWNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBuZXh0VHJhY2VDYXJyaWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJbmxpbmUtc3RlcCBvd25lcnNoaXAgcGx1bWJpbmc6IHJlZGVsaXZlcmllcyBvZlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIG1lc3NhZ2UgZHJpdmUgY3Jhc2ggcmVjb3ZlcnkgZm9yIHN0ZXBzIGFuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVhcmxpZXIgaW52b2NhdGlvbiBjbGFpbWVkIGlubGluZSAoc2VlIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrc3RvcCBwYXNzIGluIHRoZSBlbnRyeXBvaW50J3MgbG9vcCksIGFuZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgbWVzc2FnZSBpZCBpcyBzdGFtcGVkIGFzIGBvd25lck1lc3NhZ2VJZGBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb24gaW5saW5lIGxhenkgc3RlcCBjbGFpbXMgc28gd2FrZSByZXBsYXlzXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlZmVyIHRvIHRoZSBpbi1mbGlnaHQgYm9keSBpbnN0ZWFkIG9mXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcXVldWVpbmcgdGhlIHN0ZXAuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGl2ZXJ5QXR0ZW1wdDogbWV0YWRhdGEuYXR0ZW1wdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgb3duZXJNZXNzYWdlSWQ6IG1ldGFkYXRhLm1lc3NhZ2VJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHF1aWNranNSZXN1bHQ/LnRpbWVvdXRTZWNvbmRzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGByZWludm9rZWAgcmF0aGVyIHRoYW4gcmV0dXJuaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGB7IHRpbWVvdXRTZWNvbmRzIH1gIGRpcmVjdGx5OiB1bmRlciB0dXJibyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudCBtZXNzYWdlIGNhcnJpZXMgYHJ1bklucHV0YCBhbmQgYVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyByZXNjaGVkdWxlIHdvdWxkIHJlLWVuZ2FnZSB0dXJibyBvbiByZWRlbGl2ZXJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIChyZXBsYXlpbmcgYWdhaW5zdCBhIHN0YWxlIHByZWxvYWRlZCBsb2cgYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdlZGdpbmcgdGhlIHJ1biDigJQgc2VlIHRoZSByZWludm9rZSgpIGRvY3NcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWJvdmUpLiByZWludm9rZSBlbnF1ZXVlcyBhbiBleHBsaWNpdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjb250aW51YXRpb24gd2l0aG91dCBgcnVuSW5wdXRgIGluIHRoYXQgY2FzZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHJlaW52b2tlKHF1aWNranNSZXN1bHQudGltZW91dFNlY29uZHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIGlmIChldmVudExvZy50eXBlICE9PSAncmVhZHknKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYWdlID0gYXdhaXQgbG9hZFdvcmtmbG93UnVuRXZlbnRzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cudHlwZSA9PT0gJ2xvYWRBZnRlcidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGV2ZW50TG9nLmN1cnNvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGV2ZW50TG9nLnR5cGUgPT09ICdsb2FkQWZ0ZXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZEV2ZW50TG9nKGV2ZW50TG9nLCBwYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSB7IC4uLmV2ZW50TG9nLCB0eXBlOiAncmVhZHknIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IHsgLi4ucGFnZSwgdHlwZTogJ3JlYWR5JyB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBhc3NlcnQoZXZlbnRMb2cudHlwZSA9PT0gJ3JlYWR5Jyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICByZXBvcnRQcmVjb25kaXRpb25SZXN0YXJ0UmVsb2FkKGV2ZW50TG9nLmV2ZW50cyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBEZXRlY3QgY29uY3VycmVudCBjb21wbGV0aW9uIHZpYSB0aGUgZXZlbnQgbG9nOiBpZlxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFueSBvdGhlciBoYW5kbGVyIHdyb3RlIGEgdGVybWluYWwgcnVuIGV2ZW50LCBleGl0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIGRvaW5nIHJlcGxheSB3b3JrLiBUaGUgcnVuIGVudGl0eSdzIHN0YXR1cyBpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGRlcml2ZWQgZnJvbSB0aGVzZSBldmVudHMsIHNvIGNoZWNraW5nIHRoZSBsb2cgaGVyZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIGdpdmVzIHVzIHRoZSBzYW1lIHNpZ25hbCBhcyBhIHJ1bnMuZ2V0KCkgcm91bmQtdHJpcFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHdpdGhvdXQgdGhlIGV4dHJhIHJlcXVlc3QgcGVyIGxvb3AgaXRlcmF0aW9uLlxuICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNSZWNvcmRlZFRlcm1pbmFsUnVuRXZlbnQoZXZlbnRMb2cuZXZlbnRzLCBydW5JZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBDb21wbGV0ZSBlbGFwc2VkIHdhaXRzXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21wbGV0ZWRXYWl0SWRzID0gbmV3IFNldChcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmV2ZW50c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChlKSA9PiBlLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY29tcGxldGVkJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgoZSkgPT4gZS5jb3JyZWxhdGlvbklkKVxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qgd2FpdHNUb0NvbXBsZXRlID0gZXZlbnRMb2cuZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZVxuICAgICAgICAgICAgICAgICAgICAgICAgICApOiBlIGlzIEV4dHJhY3Q8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeyBldmVudFR5cGU6ICd3YWl0X2NyZWF0ZWQnIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPiAmIHsgY29ycmVsYXRpb25JZDogc3RyaW5nIH0gPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY3JlYXRlZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLmNvcnJlbGF0aW9uSWQgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICFjb21wbGV0ZWRXYWl0SWRzLmhhcyhlLmNvcnJlbGF0aW9uSWQpICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbm93ID49IChlLmV2ZW50RGF0YS5yZXN1bWVBdCBhcyBEYXRlKS5nZXRUaW1lKClcbiAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKGUpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogJ3dhaXRfY29tcGxldGVkJyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWxhdGlvbklkOiBlLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VtZUF0OiBlLmV2ZW50RGF0YS5yZXN1bWVBdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgd2FpdEV2ZW50IG9mIHdhaXRzVG9Db21wbGV0ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IGNyZWF0ZUV2ZW50KHdhaXRFdmVudCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5wcmVjb25kaXRpb25TbmFwc2hvdFBhcmFtcyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmN1cnNvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCdW1wLWFuZC1yZXBvcnQ6IGZvbGQgd2hhdCB0aGlzIHdyaXRlIHNraXBwZWQgb3ZlclxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnRvIHRoZSBzbmFwc2hvdCB0aGUgcmVtYWluaW5nIHdhaXRzIGFyZSBndWFyZGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnYWluc3QsIHNvIGVhY2ggYXNrcyBmb3IgYSBzbG90IGFib3ZlIGl0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGEgY29tcGxldGUgYW5zd2VyLiBgaGFzTW9yZWAgbWVhbnMgdGhlIFdvcmxkXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHVybmVkIHBhcnQgb2Ygd2hhdCBpdCB3YXMgYXNrZWQgZm9yLCBhbmQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1pc3NpbmctY29tcGxldGlvbiBjaGVjayBiZWxvdyBpcyB3aGF0IGRlY2lkZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2hldGhlciB0aGlzIGhhbmRsZXIgc3RpbGwgaGFzIHRvIGZldGNoLiBGb2xkaW5nIGluXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGEgcGFydGlhbCBwYWdlIHdvdWxkIG1ha2UgdGhlIGxvZyBsb29rIGxpa2UgaXRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaG9sZHMgdGhlIGNvbXBsZXRpb24gd2hlbiB0aGUgcmVzdCBvZiB0aGUgcGFnZSBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBzdGlsbCB1bnJlYWQsIHNvIHRoZSBmZXRjaCB3b3VsZCBiZSBza2lwcGVkIG9uIGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc25hcHNob3QgdGhhdCBpcyBzaG9ydCBvZiB0aGUgV29ybGQncy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWQuZXZlbnRzPy5sZW5ndGggJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVkLmhhc01vcmUgIT09IHRydWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVyZ2VSZXBvcnRlZEV2ZW50cyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWQuZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChFbnRpdHlDb25mbGljdEVycm9yLmlzKGVycikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnV2FpdCBhbHJlYWR5IGNvbXBsZXRlZCwgc2tpcHBpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogd2FpdEV2ZW50LmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIGFzc2VydChldmVudExvZy50eXBlID09PSAncmVhZHknKTtcblxuICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBldmVudCBsaXN0IGFib3ZlIG1heSBiZSBzdGFsZSBieSB0aGUgdGltZSBhblxuICAgICAgICAgICAgICAgICAgICAgIC8vIGVsYXBzZWQgd2FpdCBpcyBjb21taXR0ZWQsIGFuZCB0aGlzIHJlcGxheSBoYXMgdG8gc2VlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gaXRzIG93biB3YWl0X2NvbXBsZXRlZCBiZWZvcmUgaXQgY2FuIGFkdmFuY2UgcGFzdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBzbGVlcC4gRWFjaCB3cml0ZSBhc2tlZCB0aGUgV29ybGQgZm9yIHRoZSBkZWx0YSBzaW5jZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIG91ciBjdXJzb3IgYW5kIGZvbGRlZCBpdCBpbiAoc2VlIGNyZWF0ZUV2ZW50KSwgc28gYVxuICAgICAgICAgICAgICAgICAgICAgIC8vIHN1cHBvcnRpbmcgV29ybGQgaGFzIGFscmVhZHkgaGFuZGVkIHRob3NlIGV2ZW50cyBiYWNrXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIHRoZXJlIGlzIG5vdGhpbmcgbGVmdCB0byBkby4gT25seSBmZXRjaCBmb3IgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gY29tcGxldGlvbnMgc3RpbGwgbWlzc2luZyBsb2NhbGx5OiBhIFdvcmxkIHRoYXRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBpZ25vcmVzIGBzaW5jZUN1cnNvcmAsIGEgdHJ1bmNhdGVkIGRlbHRhLCBhIGNvbmN1cnJlbnRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBhYnNvcmIgdGhhdCBsb3N0IHRoZSBjdXJzb3IgcmFjZSwgb3IgYW5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBFbnRpdHlDb25mbGljdEVycm9yLCB3aG9zZSByZWplY3Rpb24gY2FycmllcyBubyBkZWx0YS5cbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21wbGV0ZWRXYWl0SWRzQWZ0ZXJXcml0ZXMgPSBuZXcgU2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cuZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGUpID0+IGUuZXZlbnRUeXBlID09PSAnd2FpdF9jb21wbGV0ZWQnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChlKSA9PiBlLmNvcnJlbGF0aW9uSWQpXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBtaXNzaW5nV2FpdENvbXBsZXRpb25zID0gd2FpdHNUb0NvbXBsZXRlLmZpbHRlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICh3YWl0RXZlbnQpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICFjb21wbGV0ZWRXYWl0SWRzQWZ0ZXJXcml0ZXMuaGFzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhaXRFdmVudC5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKG1pc3NpbmdXYWl0Q29tcGxldGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gTG9hZCBvbmx5IGV2ZW50cyBhZnRlciB0aGUgb3JpZ2luYWwgc25hcHNob3QgY3Vyc29yXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzbyBjb25jdXJyZW50IGR1cmFibGUgZXZlbnRzLCBzdWNoIGFzIGhvb2tfcmVjZWl2ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZWlyIG9yZGVyaW5nIHJlbGF0aXZlIHRvIHdhaXRfY29tcGxldGVkLiBGYWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrIHRvIGEgZnVsbCByZWxvYWQgZm9yIG9sZGVyIHdvcmxkcyB0aGF0IGNhbm5vdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZ2l2ZSB1cyBhIHN0YWJsZSBjdXJzb3IsIG9yIGlmIHRoZSBjdXJzb3IgZGVsdGEgZG9lc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm90IGluY2x1ZGUgdGhlIHdhaXQgY29tcGxldGlvbiB0aGlzIGhhbmRsZXIganVzdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXR0ZW1wdGVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGV2ZW50TG9nLmN1cnNvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYWdlID0gYXdhaXQgbG9hZFdvcmtmbG93UnVuRXZlbnRzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmN1cnNvclxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21wbGV0ZWRXYWl0SWRzQWZ0ZXJDdXJzb3IgPSBuZXcgU2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2UuZXZlbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChlKSA9PiBlLmV2ZW50VHlwZSA9PT0gJ3dhaXRfY29tcGxldGVkJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKGUpID0+IGUuY29ycmVsYXRpb25JZClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2F3QWxsV2FpdENvbXBsZXRpb25zID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaXNzaW5nV2FpdENvbXBsZXRpb25zLmV2ZXJ5KCh3YWl0RXZlbnQpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wbGV0ZWRXYWl0SWRzQWZ0ZXJDdXJzb3IuaGFzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3YWl0RXZlbnQuY29ycmVsYXRpb25JZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNhd0FsbFdhaXRDb21wbGV0aW9ucykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZEV2ZW50TG9nKGV2ZW50TG9nLCBwYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihhd2FpdCBsb2FkV29ya2Zsb3dSdW5FdmVudHMocnVuSWQpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdyZWFkeScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGF3YWl0IGxvYWRXb3JrZmxvd1J1bkV2ZW50cyhydW5JZCkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdyZWFkeScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gQSByZXBsYXkgcmVhZHMgdGhlIGxvZyBhcyB0aGUgY29tcGxldGUgcmVjb3JkIG9mIHdoYXRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBoYXMgaGFwcGVuZWQsIHNvIGEgcG9zaXRpb24gbm90aGluZyBvY2N1cGllcyBpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYW4gZXZlbnQgdGhhdCBuZXZlciBvY2N1cnJlZCBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgYnJhbmNoIGl0IHdvdWxkIGhhdmUgZGVjaWRlZCBnZXRzIGRlY2lkZWQgdGhlIG90aGVyXG4gICAgICAgICAgICAgICAgICAgICAgLy8gd2F5LiBGYWlsaW5nIGhlcmUgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhIHJ1biB0aGF0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmVwb3J0cyBpdHMgb3duIGNvcnJ1cHRpb24gYW5kIG9uZSB0aGF0IHNpbGVudGx5XG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmV0dXJucyB0aGUgd3JvbmcgYW5zd2VyLlxuICAgICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgICAgLy8gQSBob2xlIHRoYXQgaXMgbWVyZWx5IGEgd3JpdGUgbWlkLWNvbW1pdCBmaWxscyBpbiBvblxuICAgICAgICAgICAgICAgICAgICAgIC8vIGl0cyBvd24sIHNvIHNldHRsZUV2ZW50U2xvdEdhcCByZS1yZWFkcyBiZWZvcmVcbiAgICAgICAgICAgICAgICAgICAgICAvLyBjb25jbHVkaW5nLCBhbmQgYWRvcHRzIHdoaWNoZXZlciBsb2cgaXQgc2V0dGxlZCBvbi5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNTbG90R2FwQ2hlY2tFbmFibGVkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBzZXR0bGVFdmVudFNsb3RHYXAocnVuSWQsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRzOiBldmVudExvZy5ldmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnNvcjogZXZlbnRMb2cuY3Vyc29yLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IHsgLi4uc2V0dGxlZC5sb2csIHR5cGU6ICdyZWFkeScgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZXR0bGVkLmdhcCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBDb3JydXB0ZWRFdmVudExvZ0Vycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBFdmVudCBsb2cgZm9yIHJ1biAke3J1bklkfSBoYXMgYSBob2xlIGF0IHNsb3QgJHtzZXR0bGVkLmdhcC5maXJzdE1pc3NpbmdTbG90fTogJHtzZXR0bGVkLmdhcC5taXNzaW5nQ291bnR9IG9mIHRoZSAke3NldHRsZWQuZ2FwLm1heFNsb3R9IHNsb3RzIHVwIHRvIHRoZSBsb2cncyBtYXhpbXVtIGhvbGQgbm8gZXZlbnQuYFxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIC8vIENvbXBsZXRpbmcgZWxhcHNlZCB3YWl0cyByZWZyZXNoZXMgdGhlIGV2ZW50IHNuYXBzaG90LlxuICAgICAgICAgICAgICAgICAgICAgIC8vIEEgY29uY3VycmVudCBoYW5kbGVyIG1heSBoYXZlIHdyaXR0ZW4gdGhlIHRlcm1pbmFsIHJ1blxuICAgICAgICAgICAgICAgICAgICAgIC8vIGV2ZW50IGFmdGVyIHRoZSBpbml0aWFsIHNuYXBzaG90IGJ1dCBiZWZvcmUgdGhpc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheS4gT25jZSB0aGUgZXZlbnQgbG9nIHJlY29yZHMgdGhhdCBvdXRjb21lLCB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZGVsaXZlcnkgaXMgZG9uZS5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUmVjb3JkZWRUZXJtaW5hbFJ1bkV2ZW50KGV2ZW50TG9nLmV2ZW50cywgcnVuSWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gRXZlbnQtbGltaXQgZ3VhcmQ6IGZhaWwgYSBydW5hd2F5IHJ1biBvbmNlIGl0cyBsb2dcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZWFjaGVzIHRoZSBzZXJ2ZXItc3VwcGxpZWQgY2VpbGluZyAodW5kZWZpbmVkIOKHkiBub1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGVuZm9yY2VtZW50KS4gVGhlIHRocm93IGlzIGNhdWdodCBiZWxvdyBhbmQgd3JpdHRlbiBhc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bl9mYWlsZWQgLyBNQVhfRVZFTlRTX0VYQ0VFREVELlxuICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEV2ZW50c0xpbWl0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmV2ZW50cy5sZW5ndGggPj0gbWF4RXZlbnRzTGltaXRcbiAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBNYXhFdmVudHNFeGNlZWRlZEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZy5ldmVudHMubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhFdmVudHNMaW1pdFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBMYXRlbmN5IHRlbGVtZXRyeToganVkZ2UgVFRGUyBlbGlnaWJpbGl0eSBhZ2FpbnN0IHRoZVxuICAgICAgICAgICAgICAgICAgICAgIC8vIGludm9jYXRpb24ncyBmaXJzdCBzbmFwc2hvdC4gV2FpdHMgY29tcGxldGVkIGFib3ZlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gd291bGQgYWxyZWFkeSBkaXNxdWFsaWZ5IHZpYSB0aGUgZXZlbnQtdHlwZSBjaGVjaywgc29cbiAgICAgICAgICAgICAgICAgICAgICAvLyBldmFsdWF0aW5nIGFmdGVyIHRoZSB3YWl0IHBhc3MgaXMgZXF1aXZhbGVudC5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBhdHRyX3NldCBpcyBwZXJtaXR0ZWQ6IGEgcmVkZWxpdmVyeSBjYW4gbGFuZCBhZnRlciBhXG4gICAgICAgICAgICAgICAgICAgICAgLy8gY29tbWl0dGVkIHByZS1zdGVwIGF0dHJfc2V0LCBhbmQgdGhlIGRldG91ciBpdCBtYXJrc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHN1YnRyYWN0ZWQgdmlhIHByZVN0ZXBBdHRyU3RhcnRNcyByZWdhcmRsZXNzIG9mXG4gICAgICAgICAgICAgICAgICAgICAgLy8gd2hpY2ggaW52b2NhdGlvbiB3cm90ZSBpdCAoc2VlIHJ1bnRpbWUvc3RlcC1sYXRlbmN5LnRzKS5cbiAgICAgICAgICAgICAgICAgICAgICBpbnZvY2F0aW9uU3RhcnRlZENsZWFuID8/PSBldmVudExvZy5ldmVudHMuZXZlcnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAoZSkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdydW5fY3JlYXRlZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdydW5fc3RhcnRlZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZS5ldmVudFR5cGUgPT09ICdhdHRyX3NldCdcbiAgICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnU3RhcnRpbmcgd29ya2Zsb3cgZXhlY3V0aW9uJywge1xuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBsb29wSXRlcmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRDb3VudDogZXZlbnRMb2cuZXZlbnRzLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4ZWN1dGlvbk1vZGU6IHJldGFpbmVkU2Vzc2lvbiA/ICdyZXRhaW5lZCcgOiAncmVwbGF5JyxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICByZXBsYXlTdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gU3RhcnQgZXZlcnkgbWlzc2luZyBkZWNyeXB0L2RlY29tcHJlc3Mgb3BlcmF0aW9uIHVwXG4gICAgICAgICAgICAgICAgICAgICAgLy8gZnJvbnQgKGFscmVhZHktcHJlcGFyZWQgcGF5bG9hZHMgYXJlIHNraXBwZWQpLiBXZWJcbiAgICAgICAgICAgICAgICAgICAgICAvLyBDcnlwdG8gd29yayBvdmVybGFwcyBWTSBzZXR1cCBvbiB0aGUgcmVwbGF5IHBhdGggYW5kXG4gICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGFwcGVuZGVkIGV2ZW50cycgY29uc3VtcHRpb24gb24gdGhlIHJlc3VtZSBwYXRoO1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbnN1bWVycyBzdGlsbCBkZXNlcmlhbGl6ZSBhbmQgcmVzb2x2ZSBpbiBldmVudCBvcmRlci5cbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXlsb2FkUHJld2FybSA9IHJlcGxheVBheWxvYWRDYWNoZS5wcmV3YXJtKFxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZy5ldmVudHNcbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgIGxldCB3b3JrZmxvd1Jlc3VsdDogV29ya2Zsb3dSZXN1bWVSZXN1bHQgPSByZXRhaW5lZFNlc3Npb25cbiAgICAgICAgICAgICAgICAgICAgICAgID8gYXdhaXQgcmVzdW1lV29ya2Zsb3cocmV0YWluZWRTZXNzaW9uLCBldmVudExvZy5ldmVudHMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHsgdHlwZTogJ3JlcGxheScgfTtcblxuICAgICAgICAgICAgICAgICAgICAgIGlmICh3b3JrZmxvd1Jlc3VsdC50eXBlID09PSAncmVwbGF5Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0YWluZWRTZXNzaW9uID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UmVzdWx0ID0gYXdhaXQgcmVwbGF5V29ya2Zsb3coe1xuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd0NvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudHM6IGV2ZW50TG9nLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5UGF5bG9hZENhY2hlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUdXJibzogdGhlIGVuZC1vZi1ydW4gZHJhaW4gaW5zaWRlIHdvcmtmbG93XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV4ZWN1dGlvbiBjb21taXRzIGZpcmUtYW5kLWZvcmdldCBgKl9jcmVhdGVkYFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBldmVudHMgYmVmb3JlIHRoZSB0ZXJtaW5hbCBgYXdhaXRSdW5SZWFkeSgpYCBiZWxvdy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuUmVhZHlCYXJyaWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZENhcGFiaWxpdGllczogd29ybGQuY2FwYWJpbGl0aWVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHBheWxvYWRQcmV3YXJtO1xuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHdvcmtmbG93UmVzdWx0LnR5cGUgPT09ICdzdXNwZW5kZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBQYXJrIHRoZSBsaXZlIHNlc3Npb247IHRoZSBzdXNwZW5zaW9uIGNhdGNoIGJlbG93XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtYWtlcyB0aGUgb25lIHJldGVudGlvbiBkZWNpc2lvbiDigJQga2VlcCBpdCBmb3IgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBuZXh0IGl0ZXJhdGlvbiBvciBkaXNjYXJkIGl0IGZvciBhIGZyZXNoIHJlcGxheS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldGFpbmVkU2Vzc2lvbiA9IHdvcmtmbG93UmVzdWx0LnNlc3Npb247XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyB3b3JrZmxvd1Jlc3VsdC5zdXNwZW5zaW9uO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHdvcmtmbG93UmVzdWx0Lm91dHB1dDtcbiAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdXb3JrZmxvdyBleGVjdXRpb24gY29tcGxldGVkJywge1xuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBsb29wSXRlcmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5TXM6IERhdGUubm93KCkgLSByZXBsYXlTdGFydCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4ZWN1dGlvbk1vZGU6IHJldGFpbmVkU2Vzc2lvbiA/ICdyZXRhaW5lZCcgOiAncmVwbGF5JyxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICByZXBsYXlSZWNvdmVyeVJlcG9ydGVyLmFjdGl2YXRlKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBXb3JrZmxvdyBjb21wbGV0ZWQuIFNlbmQgdGhlIHNuYXBzaG90IGJ1dCBkbyBOT1RcbiAgICAgICAgICAgICAgICAgICAgICAvLyByZWxvYWQtYW5kLXJldHJ5IHRoZSBjcmVhdGUgaW4gcGxhY2U6IGByZXN1bHRgIHdhc1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbXB1dGVkIGJ5IHRoaXMgcmVwbGF5LCBzbyBhIHN0YWxlICg0MTIpIHJlamVjdGlvbiBtdXN0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gZm9yY2UgYSAqZnJlc2ggcmVwbGF5KiAod2hpY2ggbWF5IG9ic2VydmUgdGhlIG5ldyBldmVudFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFuZCBwcm9kdWNlIGEgZGlmZmVyZW50IHJlc3VsdCksIG5vdCByZS1jb21taXQgdGhlIHN0YWxlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcmVzdWx0LiBUaGUgY2F0Y2ggYmVsb3cgcmVzdGFydHMgdGhlIHJlcGxheSBpbi1wcm9jZXNzLlxuICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUdXJibzogYSB3b3JrZmxvdyB0aGF0IGZpbmlzaGVzIHdpdGggbm8gc3RlcHMgcmVhY2hlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaGVyZSBiZWZvcmUgdGhlIGJhY2tncm91bmRlZCBydW5fc3RhcnRlZDsgb3JkZXIgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0ZXJtaW5hbCB3cml0ZSBhZnRlciBpdCBzbyB0aGUgcnVuIGV4aXN0cy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGF3YWl0UnVuUmVhZHkoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGNyZWF0ZUV2ZW50KFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAncnVuX2NvbXBsZXRlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50RGF0YTogeyBvdXRwdXQ6IHJlc3VsdCB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnByZWNvbmRpdGlvblNuYXBzaG90UGFyYW1zKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cuZXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cuY3Vyc29yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgRW50aXR5Q29uZmxpY3RFcnJvci5pcyhlcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIFJ1bkV4cGlyZWRFcnJvci5pcyhlcnIpXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUcmllZCBjb21wbGV0aW5nIHdvcmtmbG93IHJ1biwgYnV0IHJ1biBoYXMgYWxyZWFkeSBmaW5pc2hlZC4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQsIG1lc3NhZ2U6IGVyci5tZXNzYWdlIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKCdjb21wbGV0ZWQnKSxcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChXb3JrZmxvd1N1c3BlbnNpb24uaXMoZXJyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5UmVjb3ZlcnlSZXBvcnRlci5hY3RpdmF0ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3luY2hyb25vdXMgd29ya2Zsb3ctZXhlY3V0aW9uIGR1cmF0aW9uIGZvciBUSElTXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzdXNwZW5zaW9uIG9ubHkg4oCUIGFuY2hvcnMgdGhlIGBmaW5hbFNjaGVkdWxpbmdSZXBsYXlgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0ZWxlbWV0cnkgZmllbGQgYmVsb3cgKHNlZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RlcExhdGVuY3lUcmFja2luZy5yZXBsYXlNcykuIFRoaXMgaXMgdGhlIEZJTkFMXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZXBsYXkgcGFzcywgdGhlIG9uZSB0aGF0IHJlYWNoZWQgYW5kIHNjaGVkdWxlZCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZpcnN0IHN0ZXA6IHZhbGlkIHJzZnMgcGF0aHMgY2FuIHJlcGxheSBtb3JlIHRoYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9uY2UgYmVmb3JlIHRoZSBmaXJzdCBzdGVwIChlLmcuIGEgd29ya2Zsb3ctYm9keVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYHNldEF0dHJpYnV0ZXMoKWAgZGV0b3VyIHJlcGxheXMgdHdpY2UpLCBhbmQgYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVkZWxpdmVyeSBvbWl0cyBlYXJsaWVyIGludm9jYXRpb25zJyByZXBsYXkgd29ya1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZW50aXJlbHkuIFRoaXMgdmFsdWUgaXMgTk9UIGFjY3VtdWxhdGVkIGFjcm9zc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhvc2UgZWFybGllciBwYXNzZXMsIHNvIGl0IG11c3Qgbm90IGJlIHJlYWQgYXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFwidGhlIHJlcGxheSBwb3J0aW9uIG9mIHJzZnNcIiDigJQgcnNmcyBjb3ZlcnMgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3aG9sZSBydW5fc3RhcnRlZC10by1maXJzdC1zdGVwIHdpbmRvdztcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZpbmFsU2NoZWR1bGluZ1JlcGxheSBjb3ZlcnMgb25seSB0aGlzIGxhc3QgcGFzcy5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENhcHR1cmVkIGhlcmUsIGJlZm9yZSBgaGFuZGxlU3VzcGVuc2lvbmAncyBhd2FpdGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJL08sIHNvIGl0IGV4Y2x1ZGVzIHRoYXQgSS9PLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgZHVwbGljYXRlcyB3aGF0IE9URUwgYWxyZWFkeSBjYXB0dXJlcyBvbiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bi9pbnZvY2F0aW9uIHNwYW4sIGJ1dCBpcyBjb2xsZWN0ZWQgYXMgY2xpZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0ZWxlbWV0cnkgc28gdGhlIHNlcnZlciBjYW4gZW1pdCBpdCBhcyBhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVU5TQU1QTEVELCBmdWxsLXBvcHVsYXRpb24gbWV0cmljOiB3b3JrZmxvdy1zZXJ2ZXInc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2VydmVyIHNwYW5zIGFyZSBoZWF2aWx5IHNhbXBsZWQgaW4gcHJvZHVjdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKH43JSksIGFuZCBjbGllbnQgc3BhbnMgY2FuJ3QgYmUgZmlsdGVyZWQgYnkgU0RLXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB2ZXJzaW9uLCBzbyBuZWl0aGVyIGNhbiBzZXJ2ZSBhcyB0aGUgZGFzaGJvYXJkJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV4YWN0IFRURlMgZGVjb21wb3NpdGlvbi4gT24gYSByZXRhaW5lZC1WTVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVzdW1lIHRoaXMgbWVhc3VyZXMgdGhlIHJlc3VtZSAodHlwaWNhbGx5IH4wbXMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm90IGEgcmVwbGF5LCBzbyB0aGUgZmllbGQncyBkaXN0cmlidXRpb24gaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJpbW9kYWwgb25jZSByZXRlbnRpb24gaXMgYWN0aXZlLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVwbGF5RHVyYXRpb25NcyA9IERhdGUubm93KCkgLSByZXBsYXlTdGFydDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1dvcmtmbG93IHN1c3BlbmRlZCcsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BJdGVyYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheU1zOiByZXBsYXlEdXJhdGlvbk1zLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwczogZXJyLnN0ZXBDb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaG9va3M6IGVyci5ob29rQ291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHdhaXRzOiBlcnIud2FpdENvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzdXNwZW5zaW9uTWVzc2FnZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGJ1aWxkV29ya2Zsb3dTdXNwZW5zaW9uTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIuc3RlcENvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVyci5ob29rQ291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyLndhaXRDb3VudFxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHN1c3BlbnNpb25NZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoc3VzcGVuc2lvbk1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBWMjogaGFuZGxlIHN1c3BlbnNpb24gd2l0aG91dCBxdWV1aW5nIHN0ZXBzLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBldmVudCBjcmVhdGlvbiBpbnNpZGUgaGFuZGxlU3VzcGVuc2lvbiBjYXJyaWVzIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJlY29uZGl0aW9uIHNuYXBzaG90IG9mIHRoZSBsb2FkZWQgZXZlbnQgbG9nLCBzbyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZW5kIGhvbGRpbmcgYW4gZXZlbnQgdGhpcyByZXBsYXkgbmV2ZXIgc2F3IHJlamVjdHNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSB3cml0ZSAoNDEyKSBpbnN0ZWFkIG9mIGFjY2VwdGluZyBhIGRpdmVyZ2VudCBvbmUuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcmVqZWN0aW9uIGlzIGhhbmRsZWQgaGVyZSwgYnkgcmVzdGFydGluZyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheSDigJQgbmV2ZXIgYnkgcmUtcG9zdGluZyB0aGUgc2FtZSBldmVudC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN1c3BlbnNpb25TdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBhc3NlcnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLnR5cGUgPT09ICdyZWFkeScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdXb3JrZmxvdyBzdXNwZW5kZWQgYmVmb3JlIGl0cyBldmVudCBsb2cgd2FzIGxvYWRlZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgc3VzcGVuc2lvblJlc3VsdDogQXdhaXRlZDxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgUmV0dXJuVHlwZTx0eXBlb2YgaGFuZGxlU3VzcGVuc2lvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgID47XG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBzdXNwZW5zaW9uUmVzdWx0ID0gYXdhaXQgaGFuZGxlU3VzcGVuc2lvbih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvbjogZXJyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bjogd29ya2Zsb3dSdW4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BhbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2csXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuUmVhZHlCYXJyaWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheVJlY292ZXJ5UmVwb3J0ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoc3VzcGVuc2lvbkVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEEgc3VzcGVuc2lvbiBjcmVhdGUgd2FzIHJlamVjdGVkIGFzIHN0YWxlOiByZS1kZXJpdmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHJlcGxheSBmcm9tIGEgY29ycmVjdGVkIGxvZyBpbiB0aGlzIGludm9jYXRpb24uXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9uY2UgdGhlIGluLXByb2Nlc3MgYnVkZ2V0IGlzIHNwZW50LCBmYWxsIGJhY2sgdG8gYW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXhwbGljaXQgaW1tZWRpYXRlIHJlLWludm9jYXRpb24gKGEgcmV0aHJvdyByZWxpZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb24gcmVkZWxpdmVyeSBvZiBhIG1lc3NhZ2UgdGhlIHR1cmJvIHBhdGggYWxyZWFkeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhY2tlZCDigJQgdGhlIHJ1biB3b3VsZCBzdGFsbCBmb3IgdGhlIHF1ZXVlJ3MgfjMwMHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVmYXVsdCB2aXNpYmlsaXR5IHRpbWVvdXQpLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoUHJlY29uZGl0aW9uRmFpbGVkRXJyb3IuaXMoc3VzcGVuc2lvbkVycm9yKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3RhcnRSZXBsYXlJblByb2Nlc3MoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzdXNwZW5zaW9uLWNyZWF0ZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25FcnJvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVzY2FsYXRpb24gPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgcmVpbnZva2VBZnRlclN0YWxlUmVqZWN0aW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc3VzcGVuc2lvbi1jcmVhdGUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdXNwZW5zaW9uRXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVzY2FsYXRpb24ucmVpbnZva2VkKSByZXR1cm4gZXNjYWxhdGlvbi5yZXN1bHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGVyLXJ1biBidWRnZXQgc3BlbnQ6IGZhaWwgdGhlIHJ1biByYXRoZXIgdGhhblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhbmQgaXQgYmFjayB0byB0aGUgcXVldWUgdG8gc3BpbiBhZ2Fpbi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlc2NhbGF0aW9uLmVycm9yO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghRmF0YWxFcnJvci5pcyhzdXNwZW5zaW9uRXJyb3IpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVHJhbnNpZW50IGZhaWx1cmVzIHByb3BhZ2F0ZSB0byB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBoYW5kbGVyIHNvIHRoZSBtZXNzYWdlIGlzIHJlZGVsaXZlcmVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IHN1c3BlbnNpb25FcnJvcjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOb24tcmV0cnlhYmxlIGZhaWx1cmUgd2hpbGUgY29tbWl0dGluZyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3VzcGVuc2lvbidzIGV2ZW50cyDigJQgZS5nLiBhbiBhdHRyaWJ1dGUgd3JpdGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIFdvcmxkIHJlamVjdGVkIGFzIGludmFsaWQgKHRoZSBjdW11bGF0aXZlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBlci1ydW4gY2FwIGNhbiBvbmx5IGJlIGNoZWNrZWQgV29ybGQtc2lkZSkuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlZGVsaXZlcnkgd291bGQgcmVwbGF5IHRoZSB3b3JrZmxvdyBpbnRvIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBzYW1lIHdyaXRlIGFuZCB0aGUgc2FtZSByZWplY3Rpb24sIHNvIGZhaWwgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1biB3aXRoIHRoZSBlcnJvciBpbnN0ZWFkIG9mIHdlZGdpbmcgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1lc3NhZ2UgaW4gcmVkZWxpdmVyeS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JDb2RlID0gY2xhc3NpZnlSdW5FcnJvcihzdXNwZW5zaW9uRXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOb24tcmV0cnlhYmxlIGVycm9yIHdoaWxlIGNvbW1pdHRpbmcgd29ya2Zsb3cgc3VzcGVuc2lvbjsgZmFpbGluZyBydW4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JDb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lOiBzdXNwZW5zaW9uRXJyb3IubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3VzcGVuc2lvbkVycm9yLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFR1cmJvOiBvcmRlciB0aGUgdGVybWluYWwgd3JpdGUgYWZ0ZXIgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmFja2dyb3VuZGVkIHJ1bl9zdGFydGVkIHNvIHRoZSBydW4gZXhpc3RzLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGF3YWl0UnVuUmVhZHkoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBjcmVhdGVFdmVudChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAncnVuX2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnREYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvbkVycm9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsVGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICh3b3JrZmxvd1J1bj8uc3BlY1ZlcnNpb24gPz8gMCkgPj1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU1BFQ19WRVJTSU9OX1NVUFBPUlRTX0NPTVBSRVNTSU9OXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyByZXF1ZXN0SWQgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbnRpdHlDb25mbGljdEVycm9yLmlzKGZhaWxFcnIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZmFpbEVycilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGZhaWxpbmcgd29ya2Zsb3cgcnVuLCBidXQgcnVuIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBmYWlsRXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGZhaWxFcnI7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuU3RhdHVzKCdmYWlsZWQnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvckNvZGUoZXJyb3JDb2RlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvck5hbWUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdXNwZW5zaW9uRXJyb3IubmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXJyb3JNZXNzYWdlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvbkVycm9yLm1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvclR5cGUoc3VzcGVuc2lvbkVycm9yLm5hbWUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHN1c3BlbnNpb25SZXN1bHQucmVwb3J0ZWRFdmVudENvdW50ID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCdW1wLWFuZC1yZXBvcnQgbWVyZ2VkIGV2ZW50cyBCRUxPVyB0aGUgdGFpbCBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtc29ydGVkIHRoZSBhcnJheSB0byBzbG90IG9yZGVyLCBzaGlmdGluZyBldmVyeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBwb3NpdGlvbiB0aGUgcHJld2FybSBzY2FuIGhhZCBhbHJlYWR5IHJlY29yZGVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgY3Vyc29yIGlzIGRlbGliZXJhdGVseSBsZWZ0IGFsb25lOiB0aGUgcmVwb3J0XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIGEgbG93ZXIgYm91bmQgb24gd2hhdCB3YXMgc2tpcHBlZCwgc28gdGhlIG5leHRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5jcmVtZW50YWwgcmVhZCBzdGlsbCBoYXMgdG8gY292ZXIgdGhlIHNhbWUgcmFuZ2UuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheVBheWxvYWRDYWNoZS5yZXNldFNjYW4oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlbiBob29rcy93YWl0cyBpbiB0aGUgbG9nIGFzIGxvYWRlZCBmb3IgdGhpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVwbGF5LiBUaGlzIHN1c3BlbnNpb24ncyBvd24gaG9vay93YWl0IHdyaXRlcyBhcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5PVCBpbiBpdCDigJQgdGhleSBuZXZlciByZWFjaCByZXRlbnRpb24gYW55d2F5LFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBhIHN1c3BlbnNpb24gY29udGFpbmluZyBhIG5vbi1zdGVwIGl0ZW1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZhaWxzIGNhblJldGFpbldvcmtmbG93U2Vzc2lvbidzIHR5cGUgY2hlY2sgYmVmb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgc2NhbiBpcyBjb25zdWx0ZWQuIENvbXB1dGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBsYXppbHksIGF0IG1vc3Qgb25jZSwgYW5kIHNoYXJlZCBiZXR3ZWVuIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0ZW50aW9uIGRlY2lzaW9uIGhlcmUgYW5kIHRoZSBkZWx0YS90dXJibyBnYXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmVsb3cg4oCUIHRoZSBhdHRyLWRldG91ciBhbmQgaG9vay1jb25mbGljdCBwYXRoc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0dXJuL2NvbnRpbnVlIGJlZm9yZSB0aGUgZ2F0ZXMgYW5kIHVzdWFsbHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNob3J0LWNpcmN1aXQgYmVmb3JlIGV2ZXIgc2Nhbm5pbmcgdGhlIGxvZy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG9wZW5Ib29rV2FpdCA9IG9uY2UoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NlcnQoZXZlbnRMb2cudHlwZSA9PT0gJ3JlYWR5Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBvcGVuSG9va0FuZFdhaXRTdGF0ZShldmVudExvZy5ldmVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBzaW5nbGUgcmV0ZW50aW9uIGRlY2lzaW9uOiBrZWVwIHRoZSBwYXJrZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNlc3Npb24gb25seSBhY3Jvc3MgYSBwdXJlIHN0ZXAgYm91bmRhcnkgd2l0aCBub1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3V0LW9mLWJhbmQgY29udGludWF0aW9uIHNvdXJjZSBhbmQgcHJvdmFibHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBhc3NpdmUgc3RlcCBpbnB1dHMuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldGFpbmVkU2Vzc2lvbiAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAhY2FuUmV0YWluV29ya2Zsb3dTZXNzaW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdXNwZW5zaW9uUmVzdWx0LnJldGFpbmVkU3RlcElucHV0c1NhZmUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Blbkhvb2tXYWl0XG4gICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXRhaW5lZFNlc3Npb24gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcHJlU3RlcEJsb2NraW5nTXMgKz0gc3VzcGVuc2lvblJlc3VsdC5ob29rQ3JlYXRpb25NcztcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvblJlc3VsdC5oYXNBdHRyaWJ1dGVFdmVudHMgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlU3RlcEJsb2NraW5nQmVmb3JlQXR0ck1zID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVTdGVwQmxvY2tpbmdCZWZvcmVBdHRyTXMgPSBwcmVTdGVwQmxvY2tpbmdNcztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ1N1c3BlbnNpb24gaGFuZGxlZCcsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25NczogRGF0ZS5ub3coKSAtIHN1c3BlbnNpb25TdGFydCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcGVuZGluZ1N0ZXBzOiBzdXNwZW5zaW9uUmVzdWx0LnBlbmRpbmdTdGVwcy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVvdXRTZWNvbmRzOiBzdXNwZW5zaW9uUmVzdWx0LndhaXRUaW1lb3V0Py5zZWNvbmRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNIb29rQ29uZmxpY3Q6IHN1c3BlbnNpb25SZXN1bHQuaGFzSG9va0NvbmZsaWN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNBd2FpdGVkSG9va0NyZWF0aW9uOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25SZXN1bHQuaGFzQXdhaXRlZEhvb2tDcmVhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzQXR0cmlidXRlRXZlbnRzOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25SZXN1bHQuaGFzQXR0cmlidXRlRXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhvb2sgY29uZmxpY3Q6IGJyZWFrIGxvb3AsIHJlLWludm9rZSB2aWEgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdXNwZW5zaW9uUmVzdWx0Lmhhc0hvb2tDb25mbGljdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgcmVpbnZva2UoMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5hdGl2ZSB3b3JrZmxvdyBhdHRyaWJ1dGUgZXZlbnRzIGFyZSByZXNvbHZlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhyb3VnaCByZXBsYXk6IHRoZSBuZXh0IGxvb3AgaXRlcmF0aW9uIHJlbG9hZHMgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2cgKG5vdyBob2xkaW5nIHRoZSBqdXN0LWNvbW1pdHRlZCBhdHRyX3NldCkgYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZXBsYXlzLCByZXNvbHZpbmcgdGhlIHNldEF0dHJpYnV0ZXMgcHJvbWlzZS4gU2tpcFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcCBwcm9jZXNzaW5nIGZvciB0aGlzIHBhc3Mgc28gdGhhdCByZXBsYXkgZGVjaWRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmFjZXMgZmlyc3Qg4oCUIGluIFByb21pc2UucmFjZShbc2V0QXR0cmlidXRlcygpLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcCgpXSksIHRoZSBkdXJhYmxlIGF0dHJpYnV0ZSBldmVudCBtdXN0IGJlIGFibGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIHdpbiB3aXRob3V0IGV4ZWN1dGluZyB0aGUgbG9zaW5nIHN0ZXAuIFRoZSByZXBsYXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhcHBlbnMgaW4tcHJvY2VzcyByYXRoZXIgdGhhbiB2aWEgYSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtaW52b2NhdGlvbjogdW5saWtlIGhvb2tzIGFuZCB3YWl0cywgYW4gYXR0cl9zZXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGludHJvZHVjZXMgbm8gb3V0LW9mLWJhbmQgaW52b2NhdGlvbiBzb3VyY2UgdGhhdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhbmRsZXIgd291bGQgbmVlZCB0byB5aWVsZCB0aGUgbWVzc2FnZSBmb3IsIHNvXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBwYXlpbmcgYSBkZWxpdmVyeSByb3VuZC10cmlwIGhlcmUgd291bGQgb25seSBhZGRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxhdGVuY3kgYmVmb3JlIHRoZSB3b3JrZmxvdydzIG5leHQgc3RlcC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdXNwZW5zaW9uUmVzdWx0Lmhhc0F0dHJpYnV0ZUV2ZW50cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IG5leHRFdmVudExvZ0xvYWQoZXZlbnRMb2cpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGVuZGluZ1N0ZXBzID0gc3VzcGVuc2lvblJlc3VsdC5wZW5kaW5nU3RlcHM7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElubGluZSBleGVjdXRpb24gaXMgZ2F0ZWQgb24gb3duZXJzaGlwLiBUaGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN1c3BlbnNpb24gaGFuZGxlciBkZWZlcnJlZCB0aGUgc3RlcF9jcmVhdGVkIHdyaXRlIGZvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXAgdG8gYGdldE1heElubGluZVN0ZXBzKClgIHN0ZXBzIChgbGF6eUlubGluZVN0ZXBzYClcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNvIHdlIGNhbiBydW4gdGhlbSBpbmxpbmUg4oCUIGluIHBhcmFsbGVsIOKAlCB2aWEgbGF6eVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYHN0ZXBfc3RhcnRlZGAgZXZlbnRzIHRoYXQgY3JlYXRlIGVhY2ggc3RlcCBvbiB0aGUgZmx5LFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2F2aW5nIG9uZSB3b3JsZCByb3VuZC10cmlwIHBlciBpbmxpbmUgc3RlcC4gT3duZXJzaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyBzdGlsbCBhdG9taWMgYW5kIGV4YWN0bHktb25lIHBlciBzdGVwOiB0aGUgd29ybGQnc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3JlYXRlLWNsYWltIGluc2lkZSBlYWNoIHN0ZXBfc3RhcnRlZCByZXR1cm5zXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBgRW50aXR5Q29uZmxpY3RFcnJvcmAgKOKGkiBleGVjdXRlU3RlcCBgc2tpcHBlZGApIHRvIGFueVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uY3VycmVudCBsb3Nlciwgc28gb25seSBvbmUgaGFuZGxlciBldmVyIHJ1bnMgYSBnaXZlblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYm9keS4gRXZlcnkgb3RoZXIgcGVuZGluZyBzdGVwIGtlZXBzIGl0cyBlYWdlclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcF9jcmVhdGVkIChpbiBgY3JlYXRlZFN0ZXBDb3JyZWxhdGlvbklkc2ApIGFuZCBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWVkIGJlbG93LlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBzdXNwZW5zaW9uIGhhbmRsZXIgb25seSBkZXNpZ25hdGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBgbGF6eUlubGluZVN0ZXBzYCB3aGVuIG5vIGBob29rLmdldENvbmZsaWN0KClgIGF3YWl0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHByZXNlbnQuIFRoYXQgYXdhaXRlciBjYXNlIG11c3QgZXhlY3V0ZSBub3RoaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbmxpbmU6IGFuIGlubGluZSBgYXdhaXQgZXhlY3V0ZVN0ZXAoLi4uKWAgYmxvY2tzIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhbmRsZXIgZm9yIHRoZSBmdWxsIHN0ZXAgZHVyYXRpb24sIHNvIHRoZSBhd2FpdGVyJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbnRpbnVhdGlvbiAod2hpY2ggb25seSBhZHZhbmNlcyBvbiB0aGUgbmV4dCByZXBsYXkpXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3b3VsZCBiZSBzZXJpYWxpemVkIGJlaGluZCB0aGUgc3RlcCDigJQgZGVmZWF0aW5nIHdvcmtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSB3b3JrZmxvdyBleHByZXNzZWQgYXMgcGFyYWxsZWwgKGUuZy5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGBob29rLmdldENvbmZsaWN0KCkudGhlbigoKSA9PiBzdGVwQigpKWAgcmFjaW5nIGBhd2FpdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcEEoKWApLiBJbiB0aGF0IGNhc2UgYGxhenlJbmxpbmVTdGVwc2AgaXMgZW1wdHkgYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBldmVyeSBzdGVwIGlzIHF1ZXVlZCBmb3IgcmUtaW52b2NhdGlvbiwgd2hpY2ggcmVwbGF5c1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3ZlciB0aGUganVzdC1jb21taXR0ZWQgaG9va19jcmVhdGVkIGFuZCByZXNvbHZlcyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGF3YWl0ZXIgd2hpbGUgcXVldWVkIHN0ZXBzIHJ1biBpbiBwYXJhbGxlbCBpbnZvY2F0aW9ucy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxhenlJbmxpbmVTdGVwcyA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25SZXN1bHQubGF6eUlubGluZVN0ZXBzO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5saW5lQ29ycmVsYXRpb25JZHMgPSBuZXcgU2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICBsYXp5SW5saW5lU3RlcHMubWFwKChzKSA9PiBzLmNvcnJlbGF0aW9uSWQpXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVbmlmaWVkIHF1ZXVlIGRpc3BhdGNoIGZvciBldmVyeXRoaW5nIHdlIGFyZSBOT1RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlubGluZS1leGVjdXRpbmcuIFN0ZXBzIGFyZSBxdWV1ZWQgd2l0aCBzdGVwSWQgc29cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSByZWNlaXZlciBydW5zIHRoZW07IHRoZSB3YWl0IHRpbWVyIGlzIHF1ZXVlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXMgYSBnZW5lcmljIGNvbnRpbnVhdGlvbiB0aGF0IGZpcmVzIGFmdGVyIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2FpdCBlbGFwc2VzIGFuZCBsZXRzIHRoZSBuZXh0IHJlcGxheSBvYnNlcnZlIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxhcHNlZCB3YWl0IHZpYSB0aGUgXCJjb21wbGV0ZSBlbGFwc2VkIHdhaXRzXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBhc3MuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RlcCBkaXNwYXRjaCBkZWNpc2lvbiB0YWJsZSAocGVyIHBlbmRpbmcgc3RlcCBub3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlc2lnbmF0ZWQgbGF6eS1pbmxpbmUpOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgLSBJbmxpbmUtb3duZWQsIG93bmVyID09PSB0aGlzIG1lc3NhZ2UgIOKGklxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIGV4ZWN1dGUgaW4gVEhJUyBpbnZvY2F0aW9uIChvd25lZCByZWNvdmVyeTogYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIHJlZGVsaXZlcnkgb2YgdGhlIG93bmluZyBtZXNzYWdlIHJlLWV4ZWN1dGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgdGhlIHN0ZXAgaXQgY3Jhc2hlZCBvbiwgdmlhIGEgcGF5bG9hZC1sZXNzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgc3RlcF9zdGFydGVkIHJlLXN0YW1wZWQgd2l0aCBpdHNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBvd25lck1lc3NhZ2VJZCDigJQgbm90IGEgYmFyZSBzdGFydCkuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIC0gSW5saW5lLW93bmVkLCBvd25lciAhPT0gdGhpcyBtZXNzYWdlICDihpJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBlbnN1cmUgYSBERUxBWUVEIGJhY2tzdG9wIHdha2UgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgKGRlbGF5U2Vjb25kcyA9IG93bmVyc2hpcCBsZWFzZSByZW1haW5pbmcpXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaW5zdGVhZCBvZiBlbnF1ZXVlaW5nIHRoZSBzdGVwLiBUaGUgb3duaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaW52b2NhdGlvbiBpcyAobGlrZWx5KSBzdGlsbCBydW5uaW5nIHRoZSBib2R5O1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIGFuIGltbWVkaWF0ZSBzdGVwIG1lc3NhZ2Ugd291bGQgYmFyZS1zdGFydCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBydW5uaW5nIHN0ZXAgYW5kIGV4ZWN1dGUgaXQgYSBzZWNvbmQgdGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICh3b3JrZmxvdyMyNzgwKS4gVGhlIGJhY2tzdG9wIGlzIGEgcGxhaW4gcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgY29udGludWF0aW9uLCBOT1QgYSBzdGVwIG1lc3NhZ2U6IHdoZW4gaXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBmaXJlcywgdGhpcyBzYW1lIGRlY2lzaW9uIHRhYmxlIGhhbmRsZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICB3aGF0ZXZlciBzdGF0ZSB0aGUgc3RlcCBpcyBpbiBieSB0aGVuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgKHRlcm1pbmFsIOKGkiBub3RoaW5nIHBlbmRpbmc7IHF1ZXVlLW93bmVkIGFmdGVyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgc3RlcF9yZXRyeWluZyDihpIgbm9ybWFsIGtleWVkIGRpc3BhdGNoOyBvd25lclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIGRlYWQgd2l0aCBsZWFzZSBleHBpcmVkIOKGkiBpbW1lZGlhdGUgZGlzcGF0Y2gsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgcHJlc2VydmluZyBzdGVwLWxldmVsIGZhaWx1cmUgc2VtYW50aWNzIGZvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIHBvaXNvbiBzdGVwczsgbGVhc2UgcmVmcmVzaGVkIGJ5IG93bmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgcmVjb3Zlcnkg4oaSIHJlLWFybSkuIFRoZSBiYWNrc3RvcCdzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaWRlbXBvdGVuY3lLZXkgaXMgc2NvcGVkIHRvIHRoZSBvd25lcnNoaXBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBFUE9DSCAobGF0ZXN0IHN0ZXBfc3RhcnRlZCB0aW1lc3RhbXApLCBOT1RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBqdXN0IHRoZSBjb3JyZWxhdGlvbiBJRCwgYW5kIG11c3QgbmV2ZXIgYmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICB0aGUgc3RlcCBtZXNzYWdlJ3Mgb3duIGtleSDigJQgc2VlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgYmFja3N0b3BJZGVtcG90ZW5jeUtleSBmb3IgYm90aCBpbnZhcmlhbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgKGZpeGVkIGtleXMgZWl0aGVyIGFic29yYiB0aGUgcmV0cnkgaGFuZG9mZlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIG9yIGRlZHVwZSB0aGUgcmVmcmVzaGVkLWxlYXNlIHJlLWFybSBhZ2FpbnN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgdGhlIGluLWZsaWdodCBiYWNrc3RvcCBpdHNlbGYpLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAtIE5vdCBvd25lZCAobmV2ZXIgc3RhbXBlZCAvIGVhZ2VyIC8gb3duZXJzaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgbGFwc2VkIGF0IHN0ZXBfcmV0cnlpbmcgLyBsZWFzZSBleHBpcmVkIC9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBraWxsLXN3aXRjaGVkKSDihpIgaW1tZWRpYXRlIGVucXVldWUsIGV4YWN0bHkgYXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBiZWZvcmUuIFRoaXMgY292ZXJzIGNyYXNoIHJlY292ZXJ5OiBpZiBhIHByaW9yXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaGFuZGxlciB3cm90ZSBzdGVwX2NyZWF0ZWQgYnV0IGNyYXNoZWQgYmVmb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgcXVldWVpbmcsIGEgbGF0ZXIgaGFuZGxlciBxdWV1ZXMgaXQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaWRlbXBvdGVuY3lLZXkgb24gY29ycmVsYXRpb25JZCBkZWR1cGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgcmVkdW5kYW50IHF1ZXVlcyBhY3Jvc3MgY29uY3VycmVudCBoYW5kbGVycy5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgd2FpdCBjb250aW51YXRpb24gaXMgd2hhdCBtYWtlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYFByb21pc2UucmFjZShzdGVwLCBzbGVlcClgIGJlaGF2ZSBjb3JyZWN0bHkgd2l0aFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5saW5lIHN0ZXAgZXhlY3V0aW9uOiBldmVuIGlmIHRoZSBpbmxpbmUgc3RlcFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmxvY2tzIHRoaXMgaGFuZGxlciBmb3IgdGhlIGZ1bGwgc3RlcCBkdXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSB3YWl0IHRpbWVyIGZpcmVzIGluIGEgc2VwYXJhdGUgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGludm9jYXRpb24uIElmIHRoZSBzbGVlcCB3aW5zLCB0aGF0IHBhcmFsbGVsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnZvY2F0aW9uIGNvbXBsZXRlcyB0aGUgcnVuOyBpZiB0aGUgc3RlcCB3aW5zLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHdhaXQgY29udGludWF0aW9uIGZpcmVzIGxhdGVyIGFuZCBuby1vcHMgb25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSB0ZXJtaW5hbCBydW4uXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGNvbnRpbnVhdGlvbidzIGRlbGF5IGlzIGNsYW1wZWQgdG8gdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtYXhpbXVtIHF1ZXVlIGRlbGF5IChsb25nIHdhaXRzIGNoYWluIGFjcm9zc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbXVsdGlwbGUgaG9wcykgYW5kIGl0cyBpZGVtcG90ZW5jeSBrZXkgZGVkdXBlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtb2JzZXJ2YXRpb25zIG9mIHRoZSBzYW1lIHBlbmRpbmcgd2FpdCBhY3Jvc3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN1c3BlbnNpb24gcGFzc2VzIOKAlCBzZWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJ1bnRpbWUvd2FpdC1jb250aW51YXRpb24udHMgZm9yIHRoZSBmdWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkZWxheS9rZXkgc2VsZWN0aW9uIHJhdGlvbmFsZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRyYWNlQ2FycmllciA9IGF3YWl0IG5leHRUcmFjZUNhcnJpZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRpc3BhdGNoZXM6IFByb21pc2U8dW5rbm93bj5bXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5saW5lT3duZXJzaGlwID0gaXNJbmxpbmVPd25lcnNoaXBFbmFibGVkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBkaXNwYXRjaE5vd01zID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG93bmVkUmVjb3ZlcnlTdGVwczogU3RlcEludm9jYXRpb25RdWV1ZUl0ZW1bXSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGJhY2tzdG9wV2FrZXNBcm1lZCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHN0ZXAgb2YgcGVuZGluZ1N0ZXBzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbmxpbmVDb3JyZWxhdGlvbklkcy5oYXMoc3RlcC5jb3JyZWxhdGlvbklkKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG93bmVyc2hpcEFjdGl2ZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5saW5lT3duZXJzaGlwICYmIGlzU3RlcE93bmVyc2hpcEFjdGl2ZShzdGVwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVyc2hpcEFjdGl2ZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAub3duZXJNZXNzYWdlSWQgPT09IG1ldGFkYXRhLm1lc3NhZ2VJZFxuICAgICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPd25lZCByZWNvdmVyeTogdGhpcyBkZWxpdmVyeSBJUyB0aGUgb3duaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZTsgcmUtZXhlY3V0ZSB0aGUgc3RlcCBpbiB0aGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW52b2NhdGlvbiBpbnN0ZWFkIG9mIHF1ZXVlaW5nIGl0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVkUmVjb3ZlcnlTdGVwcy5wdXNoKHN0ZXApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlbGF5ZWQgYmFja3N0b3Agd2FrZSB3aGlsZSBhbm90aGVyIGludm9jYXRpb24nc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvd25lcnNoaXAgbGVhc2UgaXMgbGl2ZTsgaW1tZWRpYXRlIHN0ZXAgZW5xdWV1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvdGhlcndpc2UgKGxlYXNlIGV4cGlyZWQg4oeSIHJlbWFpbmluZyAwIOKHkiBzYW1lIGFzXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvZGF5LCB3aGljaCBpcyBhbHNvIHRoZSBkZWdyYWRlZCBtb2RlIGZvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB3b3JsZHMgd2l0aCB1bnN0YWJsZSBtZXNzYWdlIElEcyDigJQgdGhlIG93bmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIGFib3ZlIG5ldmVyIG1hdGNoZXMgdGhlcmUpLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBiYWNrc3RvcERlbGF5U2Vjb25kcyA9IG93bmVyc2hpcEFjdGl2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gc3RlcExlYXNlUmVtYWluaW5nU2Vjb25kcyhzdGVwLCBkaXNwYXRjaE5vd01zKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogMDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJhY2tzdG9wRGVsYXlTZWNvbmRzID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tzdG9wV2FrZXNBcm1lZCsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUGVuZGluZyBzdGVwIGlzIGlubGluZS1vd25lZCBieSBhIGxpdmUgaW52b2NhdGlvbjsgZW5zdXJpbmcgZGVsYXllZCBiYWNrc3RvcCB3YWtlIGluc3RlYWQgb2YgaW1tZWRpYXRlIHJlcXVldWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcElkOiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVyTWVzc2FnZUlkOiBzdGVwLm93bmVyTWVzc2FnZUlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrc3RvcERlbGF5U2Vjb25kcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoZXMucHVzaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlQ2FycmllcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGF5U2Vjb25kczogYmFja3N0b3BEZWxheVNlY29uZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbXBvdGVuY3lLZXk6IGJhY2tzdG9wSWRlbXBvdGVuY3lLZXkoc3RlcCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoZXMucHVzaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZTogc3RlcC5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW1wb3RlbmN5S2V5OiBzdGVwLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHN1c3BlbnNpb25SZXN1bHQud2FpdFRpbWVvdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGF0Y2hlcy5wdXNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRXYWl0Q29udGludWF0aW9uRGlzcGF0Y2goXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25SZXN1bHQud2FpdFRpbWVvdXQuc2Vjb25kcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvblJlc3VsdC53YWl0VGltZW91dC5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoZGlzcGF0Y2hlcyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBzZXQgb2Ygc3RlcHMgVEhJUyBpbnZvY2F0aW9uIGV4ZWN1dGVzOiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlZmVycmVkIGxhenktaW5saW5lIGJhdGNoIHBsdXMgYW55IG93bmVkLXJlY292ZXJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzdGVwcyAodGhpcyBtZXNzYWdlJ3MgcmVkZWxpdmVyeSByZS1leGVjdXRpbmcgYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcCBpdCBjcmFzaGVkIG9uIOKAlCBubyBsYXp5U3RlcElucHV0OyB0aGUgaW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGh5ZHJhdGVzIGZyb20gdGhlIHN0ZXAgZW50aXR5IGxpa2UgdGhlIGJhY2tncm91bmRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBhdGgsIGFuZCB0aGUgcGF5bG9hZC1sZXNzIHN0ZXBfc3RhcnRlZCByZS1zdGFtcHNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG93bmVyc2hpcCDigJQgdW5saWtlIHRoZSBiYWNrZ3JvdW5kIHBhdGgncyBzdGFydCBpdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgTk9UIGJhcmU6IGl0IGNhcnJpZXMgdGhpcyBtZXNzYWdlJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG93bmVyTWVzc2FnZUlkLCB3aGljaCBpcyBhbHNvIHdoYXQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvd25lZC1yZWNvdmVyeSByZXRyeSBjZWlsaW5nIGNvdW50cykuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmxpbmVFeGVjdXRpb25zOiBBcnJheTx7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcE5hbWU6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbGF6eVN0ZXBJbnB1dD86ICh0eXBlb2YgbGF6eUlubGluZVN0ZXBzKVtudW1iZXJdWydkZWh5ZHJhdGVkSW5wdXQnXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0+ID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5sYXp5SW5saW5lU3RlcHMubWFwKChzKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHMuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZTogcy5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXp5U3RlcElucHV0OiBzLmRlaHlkcmF0ZWRJbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5vd25lZFJlY292ZXJ5U3RlcHMubWFwKChzKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHMuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZTogcy5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE93bmVyc2hpcCB0ZWxlbWV0cnkgKGRlc2lnbiBkb2MgUGhhc2UgNyk6IHNwYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGF0dHJpYnV0ZXMgc28gcHJvZHVjdGlvbiB0cmFjZXMgc2hvdyB3aGVuIGNyYXNoXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZWNvdmVyeSByYW4gb3IgYSB3YWtlIHdhcyBjb252ZXJ0ZWQgaW50byBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrc3RvcCwgYW5kIGEgd2FybiAoYWx3YXlzIHByaW50ZWQsIHVubGlrZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVidWcvaW5mbykgZm9yIG93bmVkIHJlY292ZXJ5IOKAlCBpdCBtZWFucyBhIHByaW9yXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkZWxpdmVyeSBvZiB0aGlzIG1lc3NhZ2UgZGllZCBtaWQtc3RlcC1ib2R5LlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrc3RvcFdha2VzQXJtZWQgPiAwIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIG93bmVkUmVjb3ZlcnlTdGVwcy5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKG93bmVkUmVjb3ZlcnlTdGVwcy5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IEF0dHJpYnV0ZS5Xb3JrZmxvd093bmVkUmVjb3ZlcnlTdGVwcyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvd25lZFJlY292ZXJ5U3RlcHMubGVuZ3RoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihiYWNrc3RvcFdha2VzQXJtZWQgPiAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IEF0dHJpYnV0ZS5Xb3JrZmxvd0JhY2tzdG9wV2FrZXNBcm1lZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrc3RvcFdha2VzQXJtZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG93bmVkUmVjb3ZlcnlTdGVwcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmUtZXhlY3V0aW5nIGlubGluZSBzdGVwcyBvd25lZCBieSB0aGlzIHF1ZXVlIG1lc3NhZ2Ug4oCUIGEgcHJldmlvdXMgZGVsaXZlcnkgY3Jhc2hlZCBtaWQtYm9keSBhbmQgdGhpcyByZWRlbGl2ZXJ5IGlzIHJlY292ZXJpbmcgdGhlbScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwSWRzOiBvd25lZFJlY292ZXJ5U3RlcHMubWFwKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocykgPT4gcy5jb3JyZWxhdGlvbklkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm90aGluZyB0byBleGVjdXRlIGlubGluZSDigJQgZXZlcnl0aGluZyBoYXMgYmVlblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWVkIChvciBubyB3b3JrIG5lZWRzIHNjaGVkdWxpbmcpLiBFeGl0IGFuZCBsZXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBxdWV1ZSBkcml2ZSBzdWJzZXF1ZW50IHJlcGxheXMuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5saW5lRXhlY3V0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBgaG9vay5nZXRDb25mbGljdCgpYCBhd2FpdGVyIG5lZWRzIGFuIGltbWVkaWF0ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyByZS1pbnZvY2F0aW9uOiB0aGUgcmVwbGF5IGNvbnN1bWVzIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBqdXN0LWNvbW1pdHRlZCBob29rX2NyZWF0ZWQgYW5kIHJlc29sdmVzIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhd2FpdGVyLiBXaXRob3V0IGl0IChubyBpbmxpbmUgc3RlcCwgYWxsIHdvcmtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWVkIG9yIG5vbmUgcGVuZGluZykgdGhlIHJ1biB3b3VsZCBzaXQgaWRsZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB1bnRpbCBzb21lIHVucmVsYXRlZCBtZXNzYWdlIHdva2UgaXQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdXNwZW5zaW9uUmVzdWx0Lmhhc0F3YWl0ZWRIb29rQ3JlYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgcmVpbnZva2UoMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVuIGhvb2tzL3dhaXRzIGFyZSBjb25zdWx0ZWQgYnkgYWxsIHRocmVlIGdhdGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiZWxvdzsgcmVzb2x2ZSB0aGUgbWVtb2l6ZWQgc2NhbiBvbmNlIGhlcmUuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvcGVuSG9va1dhaXRTdGF0ZSA9IG9wZW5Ib29rV2FpdC52YWx1ZTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW5saW5lLWRlbHRhIGZhc3QgcGF0aCBnYXRlLiBXZSByZXF1ZXN0IHRoZSBkZWx0YSDigJRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFuZCBvbiB0aGUgbmV4dCBpdGVyYXRpb24gY29uc3VtZSBpdCBpbiBwbGFjZSBvZiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV2ZW50cy5saXN0IOKAlCBvbmx5IHdoZW4gQUxMIGhvbGQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gIC0gV2UgaGF2ZSBhIHJlYWwgcHJpb3IgY3Vyc29yIHRvIGRpZmYgYWdhaW5zdCAoYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgV29ybGQgbWF5IHJldHVybiBub25lIG9uIHRoZSBpbml0aWFsIGxvYWQpLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gIC0gVGhpcyBpcyB0aGUgY2xlYW4gc2luZ2xlLXN0ZXAgc2VxdWVudGlhbCBjYXNlOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgdGhpcyBzdXNwZW5zaW9uIHByb2R1Y2VkIGV4YWN0bHkgb25lIHN0ZXAgYW5kIG5vXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICB3YWl0cyAoYGVyci57c3RlcCx3YWl0fUNvdW50YCksIHRoYXQgb25lIHN0ZXAgaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIHRoZSBsb25lIHBlbmRpbmcgc3RlcCAoYHBlbmRpbmdTdGVwcy5sZW5ndGggPT09IDFgKVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgYW5kIHRoZSBsb25lIGlubGluZSBzdGVwXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAoYGxhenlJbmxpbmVTdGVwcy5sZW5ndGggPT09IDFgIOKAlCBubyBwYXJhbGxlbFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgc2libGluZ3MgcXVldWVkIHRvIGJhY2tncm91bmQgaGFuZGxlcnMsIGFuZCBubyBvdGhlclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgaW5saW5lIHN0ZXAgd3JpdGluZyBpdHMgb3duIGV2ZW50cyBvdXQgb2YgYmFuZCkuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgLSBObyBwZW5kaW5nIHdhaXQgdGltZXIgZnJvbSBUSElTIHN1c3BlbnNpb24sIGFuZCBub1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgb3BlbiB3YWl0IGluIHRoZSBjdW11bGF0aXZlIGxvZzogYSBjb25jdXJyZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBgd2FpdF9jb21wbGV0ZWRgIGxhbmRpbmcgYWZ0ZXIgdGhlIGRlbHRhIHNuYXBzaG90XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBkb2VzIG5vdCBidW1wIHRoZSBvdXRzaWRlLWV2ZW50IG1hcmtlciwgc28gbm90aGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgZmVuY2VzIGEgcmVwbGF5IGZyb20gdGhlIHN0YWxlIGRlbHRhLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gIC0gTm8gb3BlbiAob3IgdGhpcy1zdXNwZW5zaW9uLWNyZWF0ZWQpIGhvb2sg4oCUIFVOTEVTU1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgdGhlIHByZWNvbmRpdGlvbiBndWFyZCBpcyBlbmFibGVkIEFORCB0aGUgV29ybGRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGRlY2xhcmVzIGl0IGFjdHVhbGx5IGVuZm9yY2VzIHRoZSBndWFyZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgKGBjYXBhYmlsaXRpZXMucHJlY29uZGl0aW9uR3VhcmRgOyB0aGUgZW52IGZsYWdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGFsb25lIG9ubHkgbWFrZXMgdGhlIHJ1bnRpbWUgU0VORCBzbmFwc2hvdHMsIHdoaWNoXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBhbiB1bnN1cHBvcnRpbmcgYmFja2VuZCBpZ25vcmVzIOKAlCBubyBmZW5jZSkuIFRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgZGVsdGEgc25hcHNob3RzIHRoZSBsb2cgYXQgdGhlIHN0ZXBfY29tcGxldGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICB3cml0ZSBidXQgaXMgY29uc3VtZWQgb24gdGhlIG5leHQgcmVwbGF5LCBzbyBhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgb3V0LW9mLWJhbmQgYGhvb2tfcmVjZWl2ZWRgIGxhbmRpbmcgaW4gdGhhdCB3aW5kb3dcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGlzIGFic2VudCBmcm9tIHRoZSBkZWx0YSBhbmQgb2JzZXJ2ZWQgb25lXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBpdGVyYXRpb24gbGF0ZXIgdGhhbiBhIHJlYWwgZmV0Y2ggd291bGQgb2JzZXJ2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgaXQuIFRoYXQgc3RhbGVuZXNzIGlzIHF1YWxpdGF0aXZlbHkgdGhlIHNhbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIHJlYWQtdG8td3JpdGUgcmFjZSB0aGUgZmV0Y2ggcGF0aCBhbHJlYWR5IGhhcyAoYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGV2ZW50IGNhbiBsYW5kIHJpZ2h0IGFmdGVyIGBldmVudHMubGlzdGAgcmV0dXJuc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgYW5kIGJlZm9yZSB0aGUgc3VzcGVuc2lvbidzIHdyaXRlcyk7IHdpdGggYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGVuZm9yY2VkIGd1YXJkIGl0IGlzIGFsc28gZmVuY2VkOiBgaG9va19yZWNlaXZlZGBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGJ1bXBzIHRoZSBwZXItcnVuIG91dHNpZGUtZXZlbnQgbWFya2VyLCBzbyBldmVyeVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgZHVyYWJsZSB3cml0ZSB0aGUgc3RhbGUgcmVwbGF5IGF0dGVtcHRzIGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICByZWplY3RlZCB3aXRoIDQxMiDigJQgaXRzIGd1YXJkZWQgc3VzcGVuc2lvbiBjcmVhdGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAocmV0cmllZCBvdmVyIHRoZSByZWxvYWRlZCBsb2csIG9yIGV4aGF1c3RlZCBpbnRvXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBhIHF1ZXVlIHJlLWludm9jYXRpb24pLCBBTkQgdGhlIGxhenkgc3RlcF9zdGFydGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBjbGFpbSBvZiBpdHMgbmV4dCBpbmxpbmUgc3RlcCwgd2hpY2ggY2FycmllcyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIHNuYXBzaG90IHRvbyAodGhyZWFkZWQgYmVsb3cgdmlhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBgc3RhdGVVcGRhdGVkQXRgOyBvbiByZWplY3Rpb24gdGhlIGJhdGNoIGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBhYmFuZG9uZWQgYW5kIHJlLWludm9rZWQgZm9yIGEgZnJlc2ggcmVwbGF5LCBzbyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBzdGFsZSB2aWV3IGNhbiBuZXZlciBjb21taXQgYSBzdGVwKS4gSG9va3MgY3JlYXRlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgYnkgVEhJUyBzdXNwZW5zaW9uIGFyZSBpbnNpZGUgdGhlIGRlbHRhICh0aGVpclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgYGhvb2tfY3JlYXRlZGAgbGFuZHMgYmVmb3JlIHRoZSBzdGVwLXRlcm1pbmFsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICB3cml0ZSksIHNvIG9ubHkgdGhlaXIgYGhvb2tfcmVjZWl2ZWRgIHJlc3BvbnNlc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgYXJlIHN1YmplY3QgdG8gdGhlIHNhbWUgZmVuY2VkIHdpbmRvdy4gV2l0aG91dCBhblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgZW5mb3JjZWQgZ3VhcmQgdGhlcmUgaXMgbm8gZmVuY2UsIHNvIGtlZXAgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICBjb25zZXJ2YXRpdmUgZ2F0ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAtIFdpdGggbm8gaG9vayBvciB3YWl0IG9wZW4gYXQgYWxsLCB0aGUgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgb3V0LW9mLWJhbmQgd3JpdGVyIGlzIGNhbmNlbGxhdGlvbiwgd2hpY2ggaXMgc2FmZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgdG8gb2JzZXJ2ZSBvbmUgaXRlcmF0aW9uIGxhdGUuIFNlZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgb3Blbkhvb2tBbmRXYWl0U3RhdGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2hlbiBtb3JlIHRoYW4gb25lIHN0ZXAgcnVucyBpbmxpbmUsIGVhY2ggd3JpdGVzIGl0c1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3duIGV2ZW50cyBhbmQgdGhlIHBlci13cml0ZSBkZWx0YSB3b3VsZCBiZSBwYXJ0aWFsLCBzb1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGRlbHRhIGlzIG5vdCByZXF1ZXN0ZWQgKHRoZSBnYXRlIGJlbG93IGlzIGZhbHNlIGZvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbXVsdGktc3RlcCkgYW5kIHRoZSBuZXh0IGl0ZXJhdGlvbiBkb2VzIGEgbm9ybWFsIGZldGNoLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2hldGhlciB0aGUgcHJlY29uZGl0aW9uIGd1YXJkIGlzIGFjdHVhbGx5IGluIGZvcmNlOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZW5hYmxlZCBieSBlbnYgQU5EIGVuZm9yY2VkIGJ5IHRoZSBXb3JsZC4gVGhlIGVudlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmxhZyBhbG9uZSBvbmx5IG1ha2VzIHRoZSBydW50aW1lIHNlbmQgc25hcHNob3RzLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2hpY2ggYW4gdW5zdXBwb3J0aW5nIGJhY2tlbmQgaWdub3JlcyAobm8gZmVuY2UpLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZ3VhcmRFbmZvcmNlZCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlzUHJlY29uZGl0aW9uR3VhcmRFbmFibGVkKCkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQuY2FwYWJpbGl0aWVzPy5wcmVjb25kaXRpb25HdWFyZCA9PT0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVxdWVzdElubGluZURlbHRhID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZW9mIGV2ZW50TG9nLmN1cnNvciA9PT0gJ3N0cmluZycgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnN0ZXBDb3VudCA9PT0gMSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIud2FpdENvdW50ID09PSAwICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHBlbmRpbmdTdGVwcy5sZW5ndGggPT09IDEgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbGF6eUlubGluZVN0ZXBzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICBvd25lZFJlY292ZXJ5U3RlcHMubGVuZ3RoID09PSAwICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICFzdXNwZW5zaW9uUmVzdWx0LndhaXRUaW1lb3V0ICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICFvcGVuSG9va1dhaXRTdGF0ZS5vcGVuV2FpdCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAoZ3VhcmRFbmZvcmNlZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChlcnIuaG9va0NvdW50ID09PSAwICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhb3Blbkhvb2tXYWl0U3RhdGUub3Blbkhvb2spKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RhbGUtc2Vuc2l0aXZlIGJhdGNoOiBhIGhvb2sgaXMgb3BlbiBpbiB0aGUgcnVuIChvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2FzIGNyZWF0ZWQgYnkgdGhpcyBzdXNwZW5zaW9uLCBzbyBpdHMgaG9va19yZWNlaXZlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2FuIGxhbmQgYW55IG1vbWVudCkg4oCUIGFuIG91dC1vZi1iYW5kIGV2ZW50IGNhbiBtYWtlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgdmlldyB0aGlzIGJhdGNoIHdhcyBzY2hlZHVsZWQgZnJvbSBzdGFsZS4gV2l0aFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGd1YXJkIGluIGZvcmNlLCB0aGUgZmVuY2UgcmVqZWN0cyBhIHN0YWxlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjbGFpbSdzIGR1cmFibGUgd3JpdGVzIOKAlCBidXQgaXQgY2Fubm90IHVuLXJ1biBhIHN0ZXBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJPRFkgdGhhdCBvcHRpbWlzdGljIHN0YXJ0IGJlZ2FuIGJlZm9yZSB0aGUgY2xhaW1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNldHRsZWQuIFN1cHByZXNzIG9wdGltaXN0aWMgc3RhcnQgZm9yIHRoZXNlIGJhdGNoZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICh0YWtlIGF3YWl0LXRoZW4tcnVuKSBzbyBhIDQxMi1mZW5jZWQgc3RlcCBuZXZlclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXhlY3V0ZXMgdXNlciBjb2RlIGF0IGFsbDogdGhlIGZlbmNlIHRoZW4gY292ZXJzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzaWRlIGVmZmVjdHMsIG5vdCBqdXN0IHRoZSBldmVudCBsb2cuIENvc3RzIG9uZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2xhaW0gcm91bmQtdHJpcCBwZXIgc3RlcCB3aGlsZSBhIGhvb2sgaXMgb3Blbiwgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb24gZ3VhcmQtZW5mb3JjaW5nIGRlcGxveW1lbnRzLiBXaXRob3V0IHRoZSBndWFyZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm90aGluZyA0MTJzLCBzbyBzdXBwcmVzc2lvbiB3b3VsZCBidXkgbm90aGluZyDigJRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0YWxlLXZpZXcgZXhwb3N1cmUgdGhlcmUgaXMgdGhlIHByZS1leGlzdGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3B0aW1pc3RpYy1zdGFydCBjb250cmFjdCAoaWRlbXBvdGVudCBzaWRlIGVmZmVjdHMpLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3VwcHJlc3NPcHRpbWlzdGljU3RhcnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICBndWFyZEVuZm9yY2VkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChvcGVuSG9va1dhaXRTdGF0ZS5vcGVuSG9vayB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVyci5ob29rQ291bnQgPiAwIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvblJlc3VsdC5oYXNIb29rRXZlbnRzKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVHVyYm8gbW9kZSBmb3JjZXMgb3B0aW1pc3RpYyBpbmxpbmUgc3RhcnQgZm9yIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJhdGNoIOKAlCBidXQgb25seSB3aGlsZSB0aGUgcnVuIGlzIHN0aWxsIFwiY2xlYW5cIiAoYSBwdXJlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzdGVwIHN1c3BlbnNpb24pLiBUaGUgbW9tZW50IGEgaG9vayBvciB3YWl0IGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjcmVhdGVkLCBsYXRlciByZXN1bWUvcGFyYWxsZWwgaW52b2NhdGlvbnMgYmVjb21lXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBwb3NzaWJsZSwgc28gdGhlIHNpbmdsZS1oYW5kbGVyIGd1YXJhbnRlZSB0aGF0IG1ha2VzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3JjZWQgb3B0aW1pc3RpYyBzdGFydCBzYWZlIG5vIGxvbmdlciBob2xkcyDigJQgdHVyYm9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV4aXRzIGFuZCB0aGUgc3RlcHMgdGFrZSB0aGUgbm9ybWFsIChlbnYtZ2F0ZWQpXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhd2FpdC10aGVuLXJ1biBwYXRoLiBUaGUgaG9vay1jb25mbGljdCBjYXNlIGFscmVhZHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHVybmVkIGVhcmx5IGFib3ZlLCB0aGUgYXR0ciBjYXNlIGNvbnRpbnVlZCBpbnRvIGFcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZyZXNoIHJlcGxheSAoc28gYSBiYXRjaC1zY2hlZHVsaW5nIHN1c3BlbnNpb24gbmV2ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNhcnJpZXMgYXR0ciBldmVudHMpLCBhbmQgdGhlIGF3YWl0ZWQtaG9vayBjYXNlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlbXB0aWVkIGxhenlJbmxpbmVTdGVwczsgdGhlIGNoZWNrcyBiZWxvdyBhcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlZmVuc2l2ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgYHN1c3BlbnNpb25SZXN1bHQuKmAgZmxhZ3Mgb25seSByZWZsZWN0IHdoYXQgVEhJU1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmF0Y2ggY3JlYXRlZCwgc28gdGhleSBkbyBub3QgY2F0Y2ggYSBob29rL3dhaXQgb3BlbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbiBhbiBlYXJsaWVyIGl0ZXJhdGlvbiBvZiB0aGUgc2FtZSBkZWxpdmVyeSAoZS5nLiBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmaXJlLWFuZC1mb3JnZXQgYGNyZWF0ZUhvb2soLi4uKWAgdGhhdCBkb2Vzbid0IGJsb2NrIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd29ya2Zsb3csIGxldHRpbmcgdGhlIHJlcGxheSBsb29wIGNvbnRpbnVlIHRvIGxhdGVyIHB1cmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXAgc3VzcGVuc2lvbnMpLiBPbmNlIGFueSBob29rIG9yIHdhaXQgaXMgb3BlbiBpbiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGN1bXVsYXRpdmUgbG9nLCByZXN1bWUvcGFyYWxsZWwgaW52b2NhdGlvbnMgYXJlIHBvc3NpYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3IgdGhlIHJlc3Qgb2YgdGhlIHJ1biwgc28gdHVyYm8gbXVzdCBsYXRjaCBvZmZcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBlcm1hbmVudGx5IOKAlCBjaGVja2VkIGhlcmUgdmlhIGBvcGVuSG9va0FuZFdhaXRTdGF0ZWBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG92ZXIgdGhlIGN1bXVsYXRpdmUgZXZlbnQgbG9nLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5PVEU6IGBXT1JLRkxPV19TRVFVRU5USUFMX1JFUExBWVM9MWAgKHBlci1ydW4gZmxvd1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG9waWNzIGNvbnN1bWVkIHdpdGggYG1heENvbmN1cnJlbmN5OiAxYCkgd291bGQgaW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHByaW5jaXBsZSB3YWl2ZSB0aGlzIGxhdGNoIOKAlCBzZXJpYWxpemVkIG9yY2hlc3RyYXRvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW52b2NhdGlvbnMgcmVzdG9yZSB0aGUgc2luZ2xlLWhhbmRsZXIgZ3VhcmFudGVlIGZvclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHdob2xlIGRlbGl2ZXJ5LiBUaGUgd2FpdmVyIGlzIGludGVudGlvbmFsbHkgTk9UXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0YWtlbjogdGhlIGVudiB2YXIgaXMgYSBydW50aW1lLXByb2Nlc3Mgc2V0dGluZyB0aGF0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjYW5ub3QgcHJvdmUgdGhlIEJVSUxUIGZsb3cgdHJpZ2dlciBhY3R1YWxseSBjYXJyaWVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBgbWF4Q29uY3VycmVuY3k6IDFgIChpdCBtdXN0IGJlIHNldCBhdCBidWlsZCB0aW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0b28sIGFuZCBzb21lIGludGVncmF0aW9ucyB3cml0ZSB0aGVpciBvd24gdHJpZ2dlclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uZmlnKSwgYW5kIGBjYXBhYmlsaXRpZXMubWF4Q29uY3VycmVuY3lgIG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlY2xhcmVzIHF1ZXVlIHN1cHBvcnQsIG5vdCBkZXBsb3llZCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVW50aWwgdGhlIGJ1aWxkIGVtaXRzIGEgdmVyaWZpYWJsZSBzaWduYWwgdGhhdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlcGxveWVkIHRyaWdnZXIgaXMgc2VyaWFsaXplZCwgdGhlIGNvbnNlcnZhdGl2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbGF0Y2ggc3RheXMuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmb3JjZU9wdGltaXN0aWNTdGFydCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHR1cmJvICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICFzdXNwZW5zaW9uUmVzdWx0Lmhhc0F0dHJpYnV0ZUV2ZW50cyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAhc3VzcGVuc2lvblJlc3VsdC53YWl0VGltZW91dCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAhc3VzcGVuc2lvblJlc3VsdC5oYXNIb29rRXZlbnRzICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICFzdXNwZW5zaW9uUmVzdWx0Lmhhc0F3YWl0ZWRIb29rQ3JlYXRpb24gJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIW9wZW5Ib29rV2FpdFN0YXRlLm9wZW5Ib29rICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICFvcGVuSG9va1dhaXRTdGF0ZS5vcGVuV2FpdDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRXhlY3V0ZSB0aGUgaW5saW5lIHN0ZXBzIGluIHBhcmFsbGVsLiBUaGUgcmVwbGF5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBidWRnZXQgaXMgcGF1c2VkIGZvciB0aGUgd2hvbGUgYmF0Y2gg4oCUIHN0ZXAgZHVyYXRpb24gaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJvdW5kZWQgYnkgdGhlIHBsYXRmb3JtJ3MgZnVuY3Rpb24gbWF4RHVyYXRpb24sIG5vdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheSB0aW1lb3V0IOKAlCBzbyB0aGUgYnVkZ2V0IGNoZWNrIGF0IHRoZSB0b3Agb2YgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBuZXh0IGxvb3AgaXRlcmF0aW9uIGRvZXNuJ3QgY2hhcmdlIHRoZSBzdGVwIGJvZGllcy5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIExhdGVuY3kgdGVsZW1ldHJ5OiBkZWNpZGUgd2hldGhlciB0aGlzIGJhdGNoJ3MgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXAgcXVhbGlmaWVzIGZvciBUVEZTL1NUU08gbWVhc3VyZW1lbnQuIE9ubHkgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYXRjaCdzIGZpcnN0IHN0ZXAgY2FycmllcyB0aGUgdHJhY2tpbmcgc28gYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGFyYWxsZWwgYmF0Y2ggZW1pdHMgb25lIHNhbXBsZSBwZXIgc2NoZWR1bGluZyBnYXAsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBub3Qgb25lIHBlciBzaWJsaW5nLiBUdXJibydzIHN5bnRoZXNpemVkIHJ1blxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc25hcHNob3QgaGFzIGEgbG9jYWwtY2xvY2sgY3JlYXRlZEF0LCBzbyB1bmRlclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVyYm8gb25seSB0aGUgcnVuLWlkIFVMSUQgdGltZXN0YW1wIGlzIHRydXN0ZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsYXRlbmN5VHJhY2tpbmcgPSBjb21wdXRlU3RlcExhdGVuY3lUcmFja2luZyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50czogZXZlbnRMb2cuZXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBpbnZvY2F0aW9uU3RhcnRlZENsZWFuOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludm9jYXRpb25TdGFydGVkQ2xlYW4gPT09IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bkNyZWF0ZWRBdE1zOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkQ3JlYXRlZEF0KHJ1bklkKSA/P1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh0dXJibyA/IHVuZGVmaW5lZCA6ICt3b3JrZmxvd1J1bi5jcmVhdGVkQXQpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBydW5TdGFydGVkUmVjZWl2ZWRBdE1zLFxuICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYXlNczogcmVwbGF5RHVyYXRpb25NcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlU3RlcEJsb2NraW5nTXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHByZVN0ZXBCbG9ja2luZ0JlZm9yZUF0dHJNcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBzdXNwZW5zaW9uJ3Mgb3duIGhvb2svd2FpdCB3cml0ZXMgYXJlIG5vdCBpblxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgbG9hZGVkIGV2ZW50IGxvZyB5ZXQsIHNvIHJlcG9ydCB0aGVtIGV4cGxpY2l0bHkuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25IYXNXYWl0czpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIud2FpdENvdW50ID4gMCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1c3BlbnNpb25SZXN1bHQud2FpdFRpbWVvdXQgIT09IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3VzcGVuc2lvbkNyZWF0ZWRIb29rczpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIuaG9va0NvdW50ID4gMCB8fCBzdXNwZW5zaW9uUmVzdWx0Lmhhc0hvb2tFdmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHR1cmJvLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByZWNvbmRpdGlvbi1ndWFyZCBzbmFwc2hvdCBmb3IgdGhlIGlubGluZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcF9zdGFydGVkIGNsYWltczogdGhlIGxhenkgY2xhaW0gaXMgdGhlIGZpcnN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkdXJhYmxlIHdyaXRlIG9mIGEgaG90LXBhdGggc3RlcCAoaXRzIHN0ZXBfY3JlYXRlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgZGVmZXJyZWQpLCBzbyB3aXRob3V0IGEgc25hcHNob3QgaXQgd291bGQgYnlwYXNzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgZ3VhcmQgZW50aXJlbHkgYW5kIGEgc3RhbGUgcmVwbGF5IGNvdWxkIGNsYWltIOKAlFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIGNvbW1pdCDigJQgYSBzdGVwIHNjaGVkdWxlZCBvZmYgYSB2aWV3IHRoYXQgbWlzc2VzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhbiBldmVudCBpdCBuZXZlciBsb2FkZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBgcHJlY29uZGl0aW9uU25hcHNob3RQYXJhbXNgIHJldHVybnMgYW4gZW1wdHkgb2JqZWN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3aGVuIHRoZSBndWFyZCBlbnYgZmxhZyBpcyBvZmYsIHNvIHRoaXMgaXMgYSBuby1vcFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3V0c2lkZSBndWFyZGVkIGRlcGxveW1lbnRzOyBXb3JsZHMgdGhhdCBkb24ndFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZW5mb3JjZSB0aGUgZ3VhcmQgaWdub3JlIGl0LlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5saW5lQ2xhaW1TbmFwc2hvdCA9IHByZWNvbmRpdGlvblNuYXBzaG90UGFyYW1zKFxuICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZy5ldmVudHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nLmN1cnNvclxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5QnVkZ2V0LnBhdXNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgc3RlcFJlc3VsdHM6IEF3YWl0ZWQ8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIFJldHVyblR5cGU8dHlwZW9mIGV4ZWN1dGVTdGVwPlxuICAgICAgICAgICAgICAgICAgICAgICAgPltdO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RlcEV4ZWN1dGlvblByb21pc2VzID0gaW5saW5lRXhlY3V0aW9ucy5tYXAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChzLCBzdGVwSW5kZXgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBydW4gPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NlcnQoZXZlbnRMb2cudHlwZSA9PT0gJ3JlYWR5Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXhlY3V0ZVN0ZXAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93RGVwbG95bWVudElkOiB3b3JrZmxvd1J1bi5kZXBsb3ltZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dTdGFydGVkQXQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvb3RSdW5JZDogcm9vdFJ1bklkRnJvbShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JrZmxvd1J1bi5hdHRyaWJ1dGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZDogcy5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwTmFtZTogcy5zdGVwTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuU3BlY1ZlcnNpb246IHdvcmtmbG93UnVuLnNwZWNWZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdHRlbXB0IG51bWJlciA9IHByaW9yIHN0ZXBfc3RhcnRlZCBjb3VudCArIDFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gKHRoaXMgZXhlY3V0aW9uJ3Mgc3RhcnQpLCBjb3VudGluZyBvbmx5IFRISVNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZSdzIG93biBzdGFydHM6IHRoZSBvd25lZC1yZWNvdmVyeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjZWlsaW5nIGJvdW5kcyBob3cgbWFueSB0aW1lcyB0aGlzIG93bmluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtZXNzYWdlIHJlLXJ1bnMgYSBzdGVwIGl0IGNyYXNoZWQvdGltZWQgb3V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9uLCBhbmQgZWFjaCBvZiB0aG9zZSAocmUpc3RhcnRzIHN0YW1wc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtZXRhZGF0YS5tZXNzYWdlSWQuIFN0YXJ0cyB3cml0dGVuIGJ5IHJhY2luZ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnZvY2F0aW9ucyAoc3RhbGUvd2FrZSByZXBsYXlzLCBhIHN0ZXBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZSBkaXNwYXRjaGVkIG9mZiBhIGxvc3QgY3JlYXRlLWNsYWltKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjYXJyeSBvdGhlciBJRHMg4oCUIG9yIG5vbmUg4oCUIGFuZCBtdXN0IG5vdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjb3VudCwgb3IgdGhlIGNlaWxpbmcgZmFsc2VseSBleGhhdXN0cyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhlYWx0aHkgc3RlcCAoc2VlIGNvdW50U3RlcFN0YXJ0ZWRFdmVudHMpLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBIGxhenkgc3RlcCBpcyBicmFuZC1uZXcgYnkgY29uc3RydWN0aW9uIChpdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlbnRlcnMgdGhlIGJhdGNoIG9ubHkgd2hlbiBpdCBoYXMgbm9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RlcF9jcmVhdGVkIHlldCksIHNvIGl0IGhhcyB6ZXJvIHByaW9yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0YXJ0cyBhbmQgaXMgYWx3YXlzIGF0dGVtcHQgMSDigJQgc2tpcCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9nIHNjYW4gZW50aXJlbHkuIE9ubHkgYW4gb3duZWQtcmVjb3ZlcnlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtcnVuIGNhbiBoYXZlIHByaW9yIHN0YXJ0cywgYW5kIHRoYXQgcGF0aFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB1bmNvbW1vbiwgc28gcmVzZXJ2ZSB0aGUgTyhuKSBzY2FuIGZvciBpdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyByYXRoZXIgdGhhbiB3YWxraW5nIHRoZSBncm93aW5nIGxvZyBmb3JcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXZlcnkgaW5saW5lIHN0ZXAgKHdoaWNoIHdvdWxkIGJlIE8obsKyKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhY3Jvc3MgYSBsb25nIHNlcXVlbnRpYWwgd29ya2Zsb3cpLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRob3JpdGF0aXZlQXR0ZW1wdDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzLmxhenlTdGVwSW5wdXQgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAxXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IGNvdW50U3RlcFN0YXJ0ZWRFdmVudHMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRMb2cuZXZlbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnb3duZWRCeScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlSWQ6IG1ldGFkYXRhLm1lc3NhZ2VJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKyAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMYXp5IGlubGluZSBzdGFydDogc2VuZCB0aGUgZGVmZXJyZWQgc3RlcCdzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlucHV0IG9uIHN0ZXBfc3RhcnRlZCBzbyB0aGUgd29ybGQgY3JlYXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgc3RlcCBvbiB0aGUgZmx5LiBBYnNlbnQgZm9yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG93bmVkLXJlY292ZXJ5IHN0ZXBzLCB3aG9zZSBpbnB1dCBoeWRyYXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tIHRoZSBleGlzdGluZyBzdGVwIGVudGl0eS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF6eVN0ZXBJbnB1dDogcy5sYXp5U3RlcElucHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJbmxpbmUgb3duZXJzaGlwOiBzdGFtcCAob3IgcmUtc3RhbXApIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW52b2NhdGlvbidzIHF1ZXVlIG1lc3NhZ2UgSUQgb24gdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0ZXBfc3RhcnRlZCwgc28gd2FrZSByZXBsYXlzIHNlZSB0aGUgYm9keVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBpbiBmbGlnaHQgaGVyZSBhbmQgc3VwcHJlc3MgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGltbWVkaWF0ZSByZXF1ZXVlICh3b3JrZmxvdyMyNzgwKS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3duZXJNZXNzYWdlSWQ6IG1ldGFkYXRhLm1lc3NhZ2VJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVHVyYm86IGZvcmNlIG9wdGltaXN0aWMgc3RhcnQgYW5kIGhvbGQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxhenkgc3RlcF9zdGFydGVkIHVudGlsIHRoZSBiYWNrZ3JvdW5kZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcnVuX3N0YXJ0ZWQgbGFuZHMgKHRoZSBib2R5IHN0aWxsIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW1tZWRpYXRlbHkpLiBCb3RoIGFyZSB1bmRlZmluZWQvZmFsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3V0c2lkZSB0dXJiby5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yY2VPcHRpbWlzdGljU3RhcnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEd1YXJkLWVuZm9yY2VkIGJhdGNoZXMgd2l0aCBhbiBvcGVuIGhvb2tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXdhaXQgdGhlIGNsYWltIGJlZm9yZSBydW5uaW5nIHRoZSBib2R5LCBzb1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhIDQxMi1mZW5jZWQgc3RlcCBuZXZlciBleGVjdXRlcyB1c2VyIGNvZGUg4oCUXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNlZSBzdXBwcmVzc09wdGltaXN0aWNTdGFydCBhYm92ZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VwcHJlc3NPcHRpbWlzdGljU3RhcnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1blJlYWR5QmFycmllcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlY29uZGl0aW9uU25hcHNob3Q6IGlubGluZUNsYWltU25hcHNob3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihzdGVwSW5kZXggPT09IDAgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcy5sYXp5U3RlcElucHV0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF0ZW5jeVRyYWNraW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB7IGxhdGVuY3lUcmFja2luZyB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihyZXF1ZXN0SW5saW5lRGVsdGEgJiYgZXZlbnRMb2cuY3Vyc29yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlubGluZURlbHRhU2luY2VDdXJzb3I6IGV2ZW50TG9nLmN1cnNvcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHt9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5UmVjb3ZlcnlSZXBvcnRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW52YXJpYW50IGJvb2trZWVwaW5nOiB0aGlzIGludm9jYXRpb24gb3duc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZXNlIGJvZGllcyB1bnRpbCB0aGV5IHNldHRsZSDigJQgc2VlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXNzZXJ0Tm9JbkZsaWdodE93bmVkU3RlcHMuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5GbGlnaHRPd25lZFN0ZXBzLmFkZChzLmNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExhenkgc3RlcHMgYXJlIGJyYW5kLW5ldyAodGhlaXIgY3JlYXRlLWNsYWltXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgdGhlIGV4YWN0bHktb25jZSBnYXRlKSwgYnV0IGFuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3duZWQtcmVjb3Zlcnkgc3RlcCBhbHJlYWR5IGV4aXN0cyBhbmQgaXRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVsYXllZCBiYWNrc3RvcCBtZXNzYWdlIG1heSBmaXJlIG1pZC1ib2R5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW4gdGhpcyBzYW1lIHByb2Nlc3Mg4oCUIHJvdXRlIHRob3NlIHRocm91Z2hcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgaW4tcHJvY2VzcyBzaW5nbGUtZmxpZ2h0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4ZWN1dGVkID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMubGF6eVN0ZXBJbnB1dCA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gcnVuU3RlcFNpbmdsZUZsaWdodChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcy5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHJ1bigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBleGVjdXRlZC5maW5hbGx5KCgpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbkZsaWdodE93bmVkU3RlcHMuZGVsZXRlKHMuY29ycmVsYXRpb25JZClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwRXhlY3V0aW9uUHJvbWlzZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKHN0ZXBFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBzdGFsZSAoNDEyKSByZWplY3Rpb24gb2YgYW4gaW5saW5lIHN0ZXBfc3RhcnRlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjbGFpbTogdGhlIGxvYWRlZCB2aWV3IHRoaXMgYmF0Y2ggd2FzIHNjaGVkdWxlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tIGlzIG1pc3NpbmcgYW4gZXZlbnQgdGhlIGJhY2tlbmQgYWxyZWFkeSBoYXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNvIHRoZSBjbGFpbSB3YXMgZmVuY2VkIGJ5IHRoZSBndWFyZCBhbmQgbm8gc3RlcFxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBldmVudHMgd2VyZSB3cml0dGVuLiBBYmFuZG9uIHRoZSBiYXRjaCDigJQgYW55XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9wdGltaXN0aWMgYm9keSByZXN1bHQgaXMgZGlzY2FyZGVkIGJ5IGV4ZWN1dGVTdGVwJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVjb25jaWxpYXRpb24g4oCUIGFuZCByZXN0YXJ0IHRoZSByZXBsYXkgc28gaXRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb2JzZXJ2ZXMgdGhlIG1pc3NpbmcgZXZlbnQuIFdhaXQgZm9yIHRoZSBzaWJsaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV4ZWN1dGlvbnMgdG8gc2V0dGxlIGZpcnN0IHNvIG5vIG93bmVkIGJvZHkgaXMgaW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmxpZ2h0IHdoZW4gdGhlIHJlc3RhcnQgKG9yIHRoZSBhY2sgcGF0aCkgcnVucy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFByZWNvbmRpdGlvbkZhaWxlZEVycm9yLmlzKHN0ZXBFcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2V0dGxlZCA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBFeGVjdXRpb25Qcm9taXNlc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSBzaWJsaW5nIHdob3NlIGNsYWltIHdhcyBhY2NlcHRlZCB3cm90ZSBzdGVwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXZlbnRzIG9mIGl0cyBvd24sIHBvc3NpYmx5IGFmdGVyIHRoZSBXb3JsZCBidWlsdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgNDEyJ3MgZGVsdGEg4oCUIHNvIHRoYXQgZGVsdGEgY2FuIG5vIGxvbmdlciBiZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZWQgdG8gY29tcGxldGUgdGhlIGxvZywgYW5kIHRoZSByZXN0YXJ0IGhhc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIHJlbG9hZCBpdCBpbiBmdWxsLiBgc2tpcHBlZGAgKHRoZSBzdGVwIGFscmVhZHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBleGlzdGVkKSwgYGdvbmVgIGFuZCBgdGhyb3R0bGVkYCAoY2xhaW0gcmVqZWN0ZWQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gd3JvdGUgbm90aGluZy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzaWJsaW5nV3JvdGUgPSBzZXR0bGVkLnNvbWUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAob3V0Y29tZSkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZS5zdGF0dXMgPT09ICdmdWxmaWxsZWQnICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChvdXRjb21lLnZhbHVlLnR5cGUgPT09ICdjb21wbGV0ZWQnIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZS52YWx1ZS50eXBlID09PSAnZmFpbGVkJyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGNvbWUudmFsdWUudHlwZSA9PT0gJ3JldHJ5JylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3RhcnRSZXBsYXlJblByb2Nlc3MoJ2lubGluZS1jbGFpbScsIHN0ZXBFcnIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dEZWx0YTogIXNpYmxpbmdXcm90ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZmluYWxseSBiZWxvdyByZXN1bWVzIHRoZSByZXBsYXkgYnVkZ2V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBiZWZvcmUgdGhlIG5leHQgaXRlcmF0aW9uIHN0YXJ0cy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZmluYWxseSBiZWxvdyByZXN1bWVzIHRoZSByZXBsYXkgYnVkZ2V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIHRoaXMgcmV0dXJuIChvciB0aHJvdykgY29tcGxldGVzLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVzY2FsYXRpb24gPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgcmVpbnZva2VBZnRlclN0YWxlUmVqZWN0aW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaW5saW5lLWNsYWltJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcEVyclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXNjYWxhdGlvbi5yZWludm9rZWQpIHJldHVybiBlc2NhbGF0aW9uLnJlc3VsdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlc2NhbGF0aW9uLmVycm9yO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IHN0ZXBFcnI7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYXlCdWRnZXQucmVzdW1lKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFnZ3JlZ2F0ZSB0aGUgYmF0Y2ggcmVzdWx0cy4gYHJldHJ5YCBzdGVwcyAod2hpY2hcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFscmVhZHkgZXhpc3Qg4oCUIHRoZWlyIGBzdGVwX3N0YXJ0ZWRgIHN1Y2NlZWRlZCkgYXJlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZS1xdWV1ZWQgcGVyLXN0ZXAgYXMgYmFja2dyb3VuZCBzdGVwcyB3aXRoIHRoZWlyIG93blxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVsYXk7IGB0aHJvdHRsZWRgIHN0ZXBzIChyZWplY3RlZCBvbiB0aGUgY3JlYXRlLWNsYWltLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gbmV2ZXIgY3JlYXRlZCkgaW5zdGVhZCBkZWZlciByZWRlbGl2ZXJ5IG9mIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9yY2hlc3RyYXRvciBtZXNzYWdlIHNvIHRoZXkgcmUtcnVuIGlubGluZSB3aXRoIGlucHV0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvbiByZXBsYXk7IGNvbXBsZXRlZC9mYWlsZWQgc3RlcHMgYWxyZWFkeSB3cm90ZSB0aGVpclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybWluYWwgZXZlbnRzLiBXZSBvbmx5IGxvb3AgYmFjayB0byByZXBsYXkgd2hlbiBldmVyeVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5saW5lIHN0ZXAgcmVhY2hlZCBhIHRlcm1pbmFsIHN0YXRlIOKAlCBvdGhlcndpc2UgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzdGlsbC1wZW5kaW5nIHN0ZXBzIHdpbGwgYmUgcmUtcnVuIGJ5IHRoZWlyIHF1ZXVlZCByZXRyeVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWVzc2FnZXMgYW5kIHRoZSBiYWNrZ3JvdW5kLXN0ZXAgcGF0aCByZXBsYXlzIG9uY2VcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFsbCBzdGVwcyBhcmUgZG9uZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRvUmV0cnk6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcDogKHR5cGVvZiBpbmxpbmVFeGVjdXRpb25zKVtudW1iZXJdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxheVNlY29uZHM6IG51bWJlcjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1bXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGFueVBlbmRpbmdPcHMgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEEgdGhyb3R0bGVkIGlubGluZSBzdGVwIGRlbGF5cyByZWRlbGl2ZXJ5IG9mIFRISVNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9yY2hlc3RyYXRvciBtZXNzYWdlIHJhdGhlciB0aGFuIGJlaW5nIHJlLXF1ZXVlZCBhcyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZ3JvdW5kIHN0ZXAuIENydWNpYWxseSwgYSBgdGhyb3R0bGVkYCByZXN1bHQgbWVhbnNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBsYXp5IGBzdGVwX3N0YXJ0ZWRgIHdhcyByZWplY3RlZCBvbiB0aGUgYXRvbWljXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjcmVhdGUtY2xhaW0g4oCUIHNvIHRoZSBzdGVwIHdhcyBORVZFUiBjcmVhdGVkIChub1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYHN0ZXBfY3JlYXRlZGAsIG5vIHN0ZXAgZW50aXR5KS4gUmUtcXVldWluZyBpdCBhcyBhXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZ3JvdW5kIHN0ZXAgd291bGQgc2VuZCBhIGJhcmUgYHN0ZXBfc3RhcnRlZGAgKG5vXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnB1dCksIHdoaWNoIHRoZSB3b3JsZCByZWplY3RzIHdpdGggYFN0ZXAgXCI8aWQ+XCIgbm90XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3VuZGAgYmVjYXVzZSBpdCBjYW5ub3QgbGF6aWx5IGNyZWF0ZSB0aGUgc3RlcCB3aXRob3V0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpdHMgaW5wdXQ7IHRoYXQgZXJyb3IgaXNuJ3QgdHJhbnNsYXRhYmxlLCBzbyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1lc3NhZ2UgcmVkZWxpdmVycyB1bnRpbCBNQVhfUVVFVUVfREVMSVZFUklFUyBhbmQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzdGVwIChhbmQgcnVuKSBmYWlsLiBEZWZlcnJpbmcgcmVkZWxpdmVyeSBvZiB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9yY2hlc3RyYXRvciBpbnN0ZWFkIHJlLWF0dGVtcHRzIHRoZSB0aHJvdHRsZWQgc3RlcFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5saW5lIFdJVEggaXRzIGlucHV0IG9uIHJlcGxheS4gV2UgdHJhY2sgdGhlIGxvbmdlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJhY2tvZmYgc28gYSBiYXRjaCB3aXRoIG11bHRpcGxlIHRocm90dGxlcyB3YWl0cyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1heC4gTm90ZTogYHJldHJ5YCByZXN1bHRzIGFyZSBzYWZlIHRvIHJlLXF1ZXVlIGFzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZ3JvdW5kIHN0ZXBzIGJlY2F1c2UgYSByZXRyeSBpbXBsaWVzIGBzdGVwX3N0YXJ0ZWRgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhbHJlYWR5IHN1Y2NlZWRlZCBhbmQgdGhlIHN0ZXAgZXhpc3RzLlxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHRocm90dGxlVGltZW91dDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbmxpbmVFeGVjdXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHIgPSBzdGVwUmVzdWx0c1tpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcyA9IGlubGluZUV4ZWN1dGlvbnNbaV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyLnR5cGUgPT09ICdyZXRyeScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b1JldHJ5LnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcDogcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGF5U2Vjb25kczogci50aW1lb3V0U2Vjb25kcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChyLnR5cGUgPT09ICd0aHJvdHRsZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3R0bGVUaW1lb3V0ID0gTWF0aC5tYXgoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdHRsZVRpbWVvdXQgPz8gMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHIudGltZW91dFNlY29uZHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHIudHlwZSA9PT0gJ2NvbXBsZXRlZCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByLmhhc1BlbmRpbmdPcHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYW55UGVuZGluZ09wcyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRocm90dGxlVGltZW91dCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlZmVyIHJlZGVsaXZlcnkgb2YgdGhlIG9yY2hlc3RyYXRvciBhZnRlciB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhyb3R0bGUgYmFja29mZi4gT24gcmVwbGF5IGV2ZXJ5IG5vbi10ZXJtaW5hbCBzdGVwXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHJlLWRpc3BhdGNoZWQgYnkgdGhlIHN1c3BlbnNpb24gaGFuZGxlcjogdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0aWxsLXRocm90dGxlZCBzdGVwcyBydW4gaW5saW5lIGFnYWluIFdJVEggdGhlaXJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5wdXQgKHRoZWlyIGBzdGVwX2NyZWF0ZWRgIGlzIGRlZmVycmVkIGFuZXcpLCBhbmRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW55IGByZXRyeWAgc3RlcHMgaW4gdGhpcyBiYXRjaCBhcmUgcXVldWVkIGFzXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJhY2tncm91bmQgc3RlcHMgd2l0aCB0aGVpciBvd24gcmV0cnlBZnRlciBob25vcmVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUZXJtaW5hbCBzdGVwcyAoY29tcGxldGVkL2ZhaWxlZC9za2lwcGVkL2dvbmUpIGFyZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvYnNlcnZlZCBmcm9tIHRoZWlyIGV2ZW50cyBhbmQgbm90IHJlLXJ1bi4gQmVjYXVzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcmVwbGF5IGRyaXZlcyBhbGwgcmVtYWluaW5nIHdvcmssIHdlIG11c3QgTk9UXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFsc28gcmUtcXVldWUgYHRvUmV0cnlgIGhlcmUg4oCUIHRoYXQgd291bGRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZG91YmxlLWRpc3BhdGNoIHRob3NlIHN0ZXBzLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIHJldHVybnMgQkVGT1JFIHRoZSBgYW55UGVuZGluZ09wc2AgYnJhbmNoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJlbG93LCBzbyBhIGJhdGNoIHRoYXQgbWl4ZXMgYSB0aHJvdHRsZSB3aXRoIGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29tcGxldGVkIHN0ZXAgdGhhdCBsZWZ0IHVuZmx1c2hlZCBvcHMgZG9lcyBub3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWUgdGhlIGV4cGxpY2l0IGZsdXNoIGNvbnRpbnVhdGlvbi4gVGhhdCBpcyBzYWZlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJlY2F1c2UgdGhlIHRocm90dGxlIGJhY2tvZmYgKD49IDFzKSBhbHdheXMgZXhjZWVkc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgaW4taW52b2NhdGlvbiBmbHVzaCB3aW5kb3cgKDw9IDUwMG1zICsgd2FpdFVudGlsKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gb3BzIHNldHRsZSBiZWZvcmUgdGhlIHBvc3QtYmFja29mZiByZWRlbGl2ZXJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheXMgYW5kIHJlYWRzIHRoZW0uXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCByZWludm9rZSh0aHJvdHRsZVRpbWVvdXQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodG9SZXRyeS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJldHJ5VHJhY2VDYXJyaWVyID0gYXdhaXQgbmV4dFRyYWNlQ2FycmllcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b1JldHJ5Lm1hcCgoeyBzdGVwLCBkZWxheVNlY29uZHMgfSkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZSwgbmFtZXNwYWNlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBJZDogc3RlcC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBOYW1lOiBzdGVwLnN0ZXBOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlQ2FycmllcjogcmV0cnlUcmFjZUNhcnJpZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxheVNlY29uZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS2V5IHRoZSBkZWxheWVkIHJldHJ5IG9uIHRoZSBzdGVwJ3NcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjb3JyZWxhdGlvbklkIHNvIGl0IGRlZHVwZXMgYWdhaW5zdCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBrZXllZCByZS1kaXNwYXRjaCB0aGUgc3VzcGVuc2lvbiBoYW5kbGVyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGVyZm9ybXMgb24gcmVwbGF5IChpdCBhbHNvIHVzZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBgaWRlbXBvdGVuY3lLZXk6IHN0ZXAuY29ycmVsYXRpb25JZGApLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2l0aG91dCB0aGlzLCBhIG1peGVkIGJhdGNoIHdoZXJlIG9uZSBzdGVwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYGNvbXBsZXRlZGAgd2l0aCB1bmZsdXNoZWQgYmFja2dyb3VuZCBvcHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAoYGFueVBlbmRpbmdPcHNgKSBhbmQgYW5vdGhlciBzdGVwIGlzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0cnlpbmcgd291bGQgZG91YmxlLWRpc3BhdGNoIHRoZSByZXRyeTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgYGFueVBlbmRpbmdPcHNgIGJyYW5jaCBiZWxvdyBxdWV1ZXMgYW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbW1lZGlhdGUgcGxhaW4gY29udGludWF0aW9uLCB3aG9zZSByZXBsYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBzZWVzIHRoZSBzdGlsbC1gcmV0cnlpbmdgIHN0ZXAgYXMgcGVuZGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFuZCByZS1kaXNwYXRjaGVzIGl0ICppbW1lZGlhdGVseSogYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gKndpdGgqIGEga2V5LiBTaW5jZSB0aGlzIGRlbGF5ZWQgcmV0cnkgaGFkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm8ga2V5LCB0aGUgdHdvIG1lc3NhZ2VzIHdvdWxkbid0IGRlZHVwZSDigJRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgc3RlcCB3b3VsZCBydW4gdHdpY2UsIHRoZSBjb25maWd1cmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0cnkgYmFja29mZiB3b3VsZCBiZSBpZ25vcmVkIChwbGFpblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGBFcnJvcmAgcmV0cmllcyBwZXJzaXN0IG5vIGByZXRyeUFmdGVyYCwgc29cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgd29ybGQgaGFzIG5vIGBUb29FYXJseWAgZ3VhcmQpLCBhbmQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0cnkgYm9keSBjb3VsZCBydW4gZWFybHkvY29uY3VycmVudGx5LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNoYXJpbmcgdGhlIGtleSBsZXRzIHRoZSBlYXJsaWVyIGRlbGF5ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtZXNzYWdlIHdpbiwgaG9ub3JpbmcgdGhlIGJhY2tvZmYuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbXBvdGVuY3lLZXk6IHN0ZXAuY29ycmVsYXRpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGV0IHBlbmRpbmcgYmFja2dyb3VuZCBvcGVyYXRpb25zIGZsdXNoIGJlZm9yZSB0aGUgbmV4dFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVwbGF5IHJlYWRzIHRoZWlyIHJlc3VsdHMuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoYW55UGVuZGluZ09wcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCcmVha2luZyBsb29wOiBpbmxpbmUgc3RlcCBoYXMgcGVuZGluZyBvcHMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQsIGxvb3BJdGVyYXRpb24gfVxuICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBxdWV1ZU1lc3NhZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRvUmV0cnkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb21lIGlubGluZSBzdGVwcyB3aWxsIGJlIHJlLXJ1biB2aWEgdGhlaXIgcXVldWVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHJ5IG1lc3NhZ2VzOyB0aGUgYmFja2dyb3VuZC1zdGVwIHBhdGggcmVwbGF5c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmNlIGFsbCBzdGVwcyBhcmUgdGVybWluYWwuIERvbid0IGxvb3AgaGVyZSDigJQgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJldHJ5aW5nIHN0ZXBzIGhhdmUgbm8gdGVybWluYWwgZXZlbnQgdG8gb2JzZXJ2ZSB5ZXQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWxsIGlubGluZSBzdGVwcyByZWFjaGVkIGEgdGVybWluYWwgc3RhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIChjb21wbGV0ZWQvZmFpbGVkL3NraXBwZWQvZ29uZSkg4oCUIGxvb3AgYmFjayB0byByZXBsYXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICh0aGUgd29ya2Zsb3cgb2JzZXJ2ZXMgdGhlIHRlcm1pbmFsIGV2ZW50cyBvbiByZXBsYXkpLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJldXNlIGFueSBpbmxpbmUgZGVsdGEuIElmIGl0IGlzIHBhcnRpYWwsIGNvbnRpbnVlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tIGl0cyBjdXJzb3IgaW5zdGVhZCBvZiByZWFkaW5nIHRoZSBwYWdlIGFnYWluLlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlubGluZUV4ZWN1dGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG9ubHkgPSBzdGVwUmVzdWx0c1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9ubHkudHlwZSA9PT0gJ2NvbXBsZXRlZCcgJiYgb25seS5pbmxpbmVEZWx0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZEV2ZW50TG9nKGV2ZW50TG9nLCBvbmx5LmlubGluZURlbHRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudExvZyA9IG9ubHkuaW5saW5lRGVsdGEuaGFzTW9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBuZXh0RXZlbnRMb2dMb2FkKGV2ZW50TG9nKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7IC4uLmV2ZW50TG9nLCB0eXBlOiAncmVhZHknIH07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TG9nID0gbmV4dEV2ZW50TG9nTG9hZChldmVudExvZyk7XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN0YWxlLXNuYXBzaG90IHJlamVjdGlvbiBvZiBhIGd1YXJkZWQgd3JpdGUgbWFkZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGlyZWN0bHkgYnkgdGhlIHJlcGxheSBsb29wIOKAlCB0aGUgcmVzdWx0LWJlYXJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGBydW5fY29tcGxldGVkYCwgb3IgdGhlIGB3YWl0X2NvbXBsZXRlZGAgb2YgdGhlIHdhaXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBhc3MuIEJvdGggcmVhY2ggdGhpcyBvbmUgY2F0Y2ggYW5kIHRoZSByZWplY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRvZXMgbm90IHNheSB3aGljaCwgaGVuY2UgdGhlIG5ldXRyYWwgbGFiZWwuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBOZWl0aGVyIG1heSBiZSByZS1wb3N0ZWQgaW4gcGxhY2U6IHRoZSBjb3JyZWxhdGlvbiBpZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIChmb3IgcnVuX2NvbXBsZXRlZCkgdGhlIHJlc3VsdCBpdHNlbGYgY2FtZSBmcm9tXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIHJlcGxheSwgYW5kIGEgY29ycmVjdGVkIGxvZyBtYXkgcHJvZHVjZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGlmZmVyZW50IG9uZXMuIERvbid0IGZhaWwgdGhlIHJ1biDigJQgcmVzdGFydCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlcGxheSBpbiB0aGlzIGludm9jYXRpb24sIGFuZCBvbmx5IG9uY2UgdGhhdCBidWRnZXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHNwZW50IHNjaGVkdWxlIGFuIGV4cGxpY2l0IHJlLWludm9jYXRpb24uXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXRocm93aW5nIGluc3RlYWQgd291bGQgcmVseSBvbiByZWRlbGl2ZXJ5IG9mIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ1VSUkVOVCBtZXNzYWdlLCB3aGljaCB0aGUgdHVyYm8gcGF0aCBoYXMgYWxyZWFkeVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWNrZWQg4oCUIGVtcGlyaWNhbGx5IHRoZSBydW4gdGhlbiBzdGFsbHMgZm9yIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWUncyB+MzAwcyBkZWZhdWx0IHZpc2liaWxpdHkgdGltZW91dCBiZWZvcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbXBsZXRpbmcuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgdGVybWluYWxFcnJvciA9IGVycjtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChQcmVjb25kaXRpb25GYWlsZWRFcnJvci5pcyhlcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXN0YXJ0UmVwbGF5SW5Qcm9jZXNzKCdyZXBsYXktd3JpdGUnLCBlcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXNjYWxhdGlvbiA9IGF3YWl0IHJlaW52b2tlQWZ0ZXJTdGFsZVJlamVjdGlvbihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAncmVwbGF5LXdyaXRlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVzY2FsYXRpb24ucmVpbnZva2VkKSByZXR1cm4gZXNjYWxhdGlvbi5yZXN1bHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBlci1ydW4gYnVkZ2V0IHNwZW50LiBGYWxsIHRocm91Z2ggdG8gdGhlIHRlcm1pbmFsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBhdGggYmVsb3cgaW5zdGVhZCBvZiByZXRocm93aW5nOiB0aGlzIGNhdGNoIG93bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmFpbGluZyB0aGUgcnVuLCBhbmQgYSByZXRocm93IHdvdWxkIGVzY2FwZSB0byB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVldWUgaGFuZGxlciBhbmQgYmUgcmVkZWxpdmVyZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1pbmFsRXJyb3IgPSBlc2NhbGF0aW9uLmVycm9yO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUcmFuc2llbnQgaW5mcmFzdHJ1Y3R1cmUgZmFpbHVyZXMgdGFsa2luZyB0byB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdvcmxkICh3b3JrZmxvdy1zZXJ2ZXIpIOKAlCBhbiBleGhhdXN0ZWQgUmV0cnlBZ2VudFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKFVORF9FUlJfUkVRX1JFVFJZIGZyb20gYSBzdXN0YWluZWQgNDI5LzUwMyBzdG9ybSksXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhIGRyb3BwZWQgc29ja2V0LCBhIGNvbm5lY3QvRE5TIGZhaWx1cmUsIG9yIGEgY2xpZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aW1lb3V0IOKAlCBtdXN0IE5PVCBmYWlsIHRoZSBydW4uIFJldGhyb3cgc28gdGhlIHF1ZXVlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZWRlbGl2ZXJzIGFuZCBhIGZyZXNoIGludm9jYXRpb24gcmV0cmllcyB0aGUgcmVwbGF5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmNlIHRoZSBiYWNrZW5kIHJlY292ZXJzLiBUaGUgQHZlcmNlbC9xdWV1ZSBoYW5kbGVyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhcHBsaWVzIGEgZmFzdCAoMXPihpI2MHMpIGJhY2tvZmYgYnkgZGVsaXZlcnkgY291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhdm9pZGluZyB0aGUgfjVtaW4gZGVmYXVsdCB2aXNpYmlsaXR5LXRpbWVvdXQgcmVkcml2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKGFuZCBuZXZlciBraWxsaW5nIHRoZSBwcm9jZXNzIHZpYSBydW5fZmFpbGVkKS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc1JldHJ5YWJsZVdvcmxkRXJyb3IoZXJyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBydW5Mb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVHJhbnNpZW50IHdvcmxkIGVycm9yIGR1cmluZyByZXBsYXk7IHJlZGVsaXZlcmluZyB2aWEgcXVldWUgaW5zdGVhZCBvZiBmYWlsaW5nIHRoZSBydW4nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTmFtZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGVyci5uYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnVW5rbm93bkVycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGVyci5tZXNzYWdlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBTdHJpbmcoZXJyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGl2ZXJ5QXR0ZW1wdDogbWV0YWRhdGEuYXR0ZW1wdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHJlcGxheURpdmVyZ2VuY2VDb3VudEZvckZhaWx1cmU6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChSZXBsYXlEaXZlcmdlbmNlRXJyb3IuaXMoZXJyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBkaXZlcmdlbmNlQ291bnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZXBsYXlEaXZlcmdlbmNlPy5jb3VudCA/PyAwKSArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG1heFJlY292ZXJ5UmVwbGF5cyA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0UmVwbGF5RGl2ZXJnZW5jZU1heFJldHJpZXMoKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGl2ZXJnZW5jZUNvdW50IDw9IG1heFJlY292ZXJ5UmVwbGF5cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bkxvZ2dlci53YXJuKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1dvcmtmbG93IHJlcGxheSBkaXZlcmdlZDsgcXVldWVpbmcgYSByZWNvdmVyeSByZXBsYXkgYmVmb3JlIGRlY2xhcmluZyB0aGUgZXZlbnQgbG9nIGNvcnJ1cHRlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ29kZTogUlVOX0VSUk9SX0NPREVTLlJFUExBWV9ESVZFUkdFTkNFLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXZlcmdlbmNlRXZlbnRJZDogZXJyLmV2ZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yRGl2ZXJnZW5jZUV2ZW50SWQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5RGl2ZXJnZW5jZT8uZXZlbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGl2ZXJnZW5jZUNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxpdmVyeUF0dGVtcHQ6IG1ldGFkYXRhLmF0dGVtcHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heFJlY292ZXJ5UmVwbGF5cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHF1ZXVlTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dOYW1lLCBuYW1lc3BhY2UpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW5JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2VDYXJyaWVyOiBhd2FpdCBuZXh0VHJhY2VDYXJyaWVyKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYXlEaXZlcmdlbmNlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRJZDogZXJyLmV2ZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQ6IGRpdmVyZ2VuY2VDb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheURpdmVyZ2VuY2VDb3VudEZvckZhaWx1cmUgPSBkaXZlcmdlbmNlQ291bnQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1pbmFsRXJyb3IgPSBuZXcgQ29ycnVwdGVkRXZlbnRMb2dFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgV29ya2Zsb3cgcmVwbGF5IGRpdmVyZ2VkICR7ZGl2ZXJnZW5jZUNvdW50fSB0aW1lcyBhZnRlciAke21heFJlY292ZXJ5UmVwbGF5c30gcmVjb3ZlcnkgcmVwbGF5czsgbGF0ZXN0IGRpdmVyZ2VudCBldmVudCB3YXMgJHtlcnIuZXZlbnRJZH0uIExhc3QgZGl2ZXJnZW5jZTogJHtlcnIubWVzc2FnZX1gLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgY2F1c2U6IGVyciB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHJlcGxheVN0YXJ0ID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYXlSZWNvdmVyeVJlcG9ydGVyLmFjdGl2YXRlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZXIgY29kZSBlcnJvcnMgYW5kIHRlcm1pbmFsIHJ1bnRpbWUgZXJyb3JzIGZhaWwgdGhlIHJ1bi5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0ZXJtaW5hbEVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc3Bhbj8ucmVjb3JkRXhjZXB0aW9uPy4odGVybWluYWxFcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRFcnJvciA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IG5vcm1hbGl6ZVVua25vd25FcnJvcih0ZXJtaW5hbEVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yTmFtZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWRFcnJvci5uYW1lIHx8IGdldEVycm9yTmFtZSh0ZXJtaW5hbEVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IG5vcm1hbGl6ZWRFcnJvci5tZXNzYWdlO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yU3RhY2sgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkRXJyb3Iuc3RhY2sgfHwgZ2V0RXJyb3JTdGFjayh0ZXJtaW5hbEVycm9yKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yU3RhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFyc2VkTmFtZSA9IHBhcnNlV29ya2Zsb3dOYW1lKHdvcmtmbG93TmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbGVuYW1lID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzZWROYW1lPy5tb2R1bGVTcGVjaWZpZXIgfHwgd29ya2Zsb3dOYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclN0YWNrID0gcmVtYXBFcnJvclN0YWNrKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yU3RhY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dDb2RlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENsYXNzaWZ5IHRoZSBlcnJvcjogV29ya2Zsb3dSdW50aW1lRXJyb3IgaW5kaWNhdGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhbiBTREsvcnVudGltZSBpc3N1ZSwgYW5kIHNlbGVjdGVkIHN1YmNsYXNzZXMgdXNlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtb3JlIHNwZWNpZmljIGNvZGVzIGZvciBiYWNrZW5kIHRyYWNraW5nLlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JDb2RlID0gY2xhc3NpZnlSdW5FcnJvcih0ZXJtaW5hbEVycm9yKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5lcnJvcignRXJyb3Igd2hpbGUgcnVubmluZyB3b3JrZmxvdycsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclN0YWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFwcGx5IHRoZSBzb3VyY2UtbWFwLXJlbWFwcGVkIHN0YWNrIHRvIHRoZSB0aHJvd25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHZhbHVlIHNvIHRoYXQgdGhlIHNlcmlhbGl6ZWQgZXJyb3IgcHJlc2VydmVzIGl0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmb3IgY29uc3VtZXJzLiBgdHlwZXMuaXNOYXRpdmVFcnJvcigpYCBpcyB1c2VkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnN0ZWFkIG9mIGBlcnIgaW5zdGFuY2VvZiBFcnJvcmAgYmVjYXVzZSB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdvcmtmbG93IHJ1bnMgaW4gYSBzZXBhcmF0ZSBWTSByZWFsbSDigJQgaXRzIEVycm9yXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjbGFzcyBpcyBkaXN0aW5jdCBmcm9tIHRoZSBob3N0J3MsIHNvIGBpbnN0YW5jZW9mXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFcnJvcmAgaXMgYGZhbHNlYCBmb3IgVk0tdGhyb3duIGVycm9ycy4gVGhlIFY4XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0eXBlIHRhZyB3b3JrcyBhY3Jvc3MgcmVhbG1zLlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVzLmlzTmF0aXZlRXJyb3IodGVybWluYWxFcnJvcikgJiYgZXJyb3JTdGFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAodGVybWluYWxFcnJvciBhcyBFcnJvcikuc3RhY2sgPSBlcnJvclN0YWNrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBGYWlsIHRoZSB3b3JrZmxvdyBydW4gdmlhIGV2ZW50IChldmVudC1zb3VyY2VkKS5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNlcmlhbGl6ZSB0aGUgb3JpZ2luYWwgdGhyb3duIHZhbHVlIHNvIGl0cyBmdWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0eXBlIGlkZW50aXR5IGFuZCBjdXN0b20gcHJvcGVydGllcyByb3VuZC10cmlwXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aHJvdWdoIHRoZSBldmVudCBsb2cuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJlY29uZGl0aW9uLWd1YXJkIGFzeW1tZXRyeTogdW5saWtlIGBydW5fY29tcGxldGVkYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgdGVybWluYWwgYHJ1bl9mYWlsZWRgIHNlbmRzIG5vIGBzdGF0ZVVwZGF0ZWRBdGBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNuYXBzaG90LCBzbyBpdCBpcyBuZXZlciA0MTItcmVqZWN0ZWQgZXZlbiBpZiBhIGhvb2tcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxhbmRlZCBtaWQtcmVwbGF5IGFuZCBjb3VsZCBoYXZlIGNoYW5nZWQgdGhlIHBhdGggdGhhdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhyZXcuIFRoaXMgaXMgaW50ZW50aW9uYWwgYW5kIGZhaWwtb3BlbjogYSBzcHVyaW91c1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmFpbHVyZSBpcyByZWNvdmVyYWJsZSAodGhlIHJ1biBjYW4gYmUgcmUtcnVuIGZyb20gdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBkYXNoYm9hcmQpLCB3aGVyZWFzIGEgc3B1cmlvdXMgKmNvbXBsZXRpb24qIGNvbW1pdHMgYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd3JvbmcgcmVzdWx0LiBHdWFyZGluZyB0aGlzIHdyaXRlIHN5bW1ldHJpY2FsbHkgd291bGRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFsc28gbmVlZCB0aGUgbG9hZGVkIGV2ZW50IGxvZywgd2hpY2ggaXMgc2NvcGVkIHRvIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVwbGF5IGB0cnlgIGFib3ZlIGFuZCBub3QgYXZhaWxhYmxlIGluIHRoaXMgY2F0Y2guXG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUdXJibzogb3JkZXIgdGhlIHRlcm1pbmFsIHdyaXRlIGFmdGVyIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBiYWNrZ3JvdW5kZWQgcnVuX3N0YXJ0ZWQgc28gdGhlIHJ1biBleGlzdHMuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGF3YWl0UnVuUmVhZHkoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgY3JlYXRlRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiAncnVuX2ZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGF3YWl0IGRlaHlkcmF0ZVJ1bkVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1pbmFsRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWxUaGlzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICh3b3JrZmxvd1J1bj8uc3BlY1ZlcnNpb24gPz8gMCkgPj1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKHJlcGxheURpdmVyZ2VuY2VDb3VudEZvckZhaWx1cmUgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxheURpdmVyZ2VuY2VDb3VudDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGF5RGl2ZXJnZW5jZUNvdW50Rm9yRmFpbHVyZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGZhaWxFcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudGl0eUNvbmZsaWN0RXJyb3IuaXMoZmFpbEVycikgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSdW5FeHBpcmVkRXJyb3IuaXMoZmFpbEVycilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RyaWVkIGZhaWxpbmcgd29ya2Zsb3cgcnVuLCBidXQgcnVuIGhhcyBhbHJlYWR5IGZpbmlzaGVkLicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBmYWlsRXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzV29ybGRDb250cmFjdEVycm9yKGZhaWxFcnIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVudGltZUxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdGYXRhbCB3b3JsZCBjb250cmFjdCBlcnJvciB3aGlsZSByZWNvcmRpbmcgd29ya2Zsb3cgZmFpbHVyZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckNvZGU6IFJVTl9FUlJPUl9DT0RFUy5XT1JMRF9DT05UUkFDVF9FUlJPUixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFpbEVyciBpbnN0YW5jZW9mIEVycm9yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGZhaWxFcnIubWVzc2FnZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBTdHJpbmcoZmFpbEVyciksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZmFpbEVycjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1blN0YXR1cygnZmFpbGVkJyksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0Vycm9yQ29kZShlcnJvckNvZGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFcnJvck5hbWUoZXJyb3JOYW1lKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXJyb3JNZXNzYWdlKGVycm9yTWVzc2FnZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkF0dHJpYnV0ZS5FcnJvclR5cGUoZXJyb3JOYW1lKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICApO1xuXG4gIGxldCBjYWNoZWRIYW5kbGVyOiAoKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4pIHwgdW5kZWZpbmVkO1xuICBsZXQgaW52b2NhdGlvbkNvdW50ID0gMDtcbiAgY29uc3QgZW50cnlwb2ludENyZWF0ZWRBdCA9IERhdGUubm93KCk7XG4gIGNvbnN0IHJvdXRlTW9kdWxlQm9keUluaXRNcyA9XG4gICAgdHlwZW9mIG9wdGlvbnM/LnJvdXRlTW9kdWxlQm9keVN0YXJ0ZWRBdCA9PT0gJ251bWJlcidcbiAgICAgID8gZW50cnlwb2ludENyZWF0ZWRBdCAtIG9wdGlvbnMucm91dGVNb2R1bGVCb2R5U3RhcnRlZEF0XG4gICAgICA6IHVuZGVmaW5lZDtcblxuICByZXR1cm4gd2l0aEhlYWx0aENoZWNrKGFzeW5jIChyZXEpID0+IHtcbiAgICBpbnZvY2F0aW9uQ291bnQgKz0gMTtcbiAgICBjb25zdCBoYW5kbGVyQ2FjaGVkID0gY2FjaGVkSGFuZGxlciAhPT0gdW5kZWZpbmVkO1xuICAgIGNvbnN0IHNwYW5LaW5kID0gYXdhaXQgZ2V0U3BhbktpbmQoJ1NFUlZFUicpO1xuXG4gICAgcmV0dXJuIHRyYWNlKFxuICAgICAgJ3dvcmtmbG93LnJvdXRlLmZsb3cnLFxuICAgICAge1xuICAgICAgICBraW5kOiBzcGFuS2luZCxcbiAgICAgICAgYXR0cmlidXRlczoge1xuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1JvdXRlVHlwZSgnZmxvdycpLFxuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5GYWFzSW5zdGFuY2UoQ09NUFVURV9JTlNUQU5DRV9JRCksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93Um91dGVIYW5kbGVyQ2FjaGVkKGhhbmRsZXJDYWNoZWQpLFxuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1JvdXRlSW52b2NhdGlvbkNvdW50KGludm9jYXRpb25Db3VudCksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93Um91dGVFbnRyeXBvaW50QWdlTXMoXG4gICAgICAgICAgICBEYXRlLm5vdygpIC0gZW50cnlwb2ludENyZWF0ZWRBdFxuICAgICAgICAgICksXG4gICAgICAgICAgLi4uKHJvdXRlTW9kdWxlQm9keUluaXRNcyA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICA/IHt9XG4gICAgICAgICAgICA6IEF0dHJpYnV0ZS5Xb3JrZmxvd1JvdXRlTW9kdWxlQm9keUluaXRNcyhyb3V0ZU1vZHVsZUJvZHlJbml0TXMpKSxcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuSHR0cFJlcXVlc3RNZXRob2QocmVxLm1ldGhvZCksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLkh0dHBSb3V0ZSgnLy53ZWxsLWtub3duL3dvcmtmbG93L3YxL2Zsb3cnKSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBhc3luYyAoc3BhbikgPT4ge1xuICAgICAgICBpZiAoIWNhY2hlZEhhbmRsZXIpIHtcbiAgICAgICAgICBjYWNoZWRIYW5kbGVyID0gYXdhaXQgdHJhY2UoJ3dvcmtmbG93LnJvdXRlLmluaXQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB3b3JsZEhhbmRsZXJzID0gYXdhaXQgdHJhY2UoXG4gICAgICAgICAgICAgICd3b3JrZmxvdy5yb3V0ZS5nZXRfd29ybGRfaGFuZGxlcnMnLFxuICAgICAgICAgICAgICBhc3luYyAoKSA9PiBnZXRXb3JsZEhhbmRsZXJzKClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4gaGFuZGxlcih3b3JsZEhhbmRsZXJzKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2FjaGVkSGFuZGxlcihyZXEpO1xuICAgICAgICBpZiAocmVzcG9uc2UgaW5zdGFuY2VvZiBSZXNwb25zZSkge1xuICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoXG4gICAgICAgICAgICBBdHRyaWJ1dGUuSHR0cFJlc3BvbnNlU3RhdHVzQ29kZShyZXNwb25zZS5zdGF0dXMpXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICB9XG4gICAgKTtcbiAgfSk7XG59XG4iXX0=
|