@workflow/core 5.0.0-beta.5 → 5.0.0-beta.50
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 +5 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +35 -2
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +74 -5
- package/dist/capture-stack.d.ts +1 -1
- package/dist/capture-stack.js +2 -2
- package/dist/class-serialization.d.ts +32 -0
- package/dist/class-serialization.d.ts.map +1 -1
- package/dist/class-serialization.js +37 -1
- package/dist/classify-error.d.ts +19 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +98 -6
- package/dist/context-violation-error.d.ts +5 -5
- package/dist/context-violation-error.d.ts.map +1 -1
- package/dist/context-violation-error.js +8 -6
- package/dist/create-hook.d.ts +72 -7
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +1 -1
- package/dist/define-hook.js +2 -2
- package/dist/describe-error.d.ts +7 -7
- package/dist/describe-error.d.ts.map +1 -1
- package/dist/describe-error.js +97 -12
- package/dist/encryption.d.ts +38 -4
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +96 -14
- package/dist/events-consumer.d.ts +271 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +646 -42
- package/dist/flushable-stream.d.ts +56 -1
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +123 -11
- package/dist/global.d.ts +36 -2
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -6
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/log-format.d.ts +2 -2
- package/dist/log-format.js +7 -7
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +10 -6
- package/dist/private.d.ts +226 -9
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +626 -7
- package/dist/replay-payload-cache.d.ts +64 -0
- package/dist/replay-payload-cache.d.ts.map +1 -0
- package/dist/replay-payload-cache.js +158 -0
- package/dist/runtime/compute-instance.d.ts +13 -0
- package/dist/runtime/compute-instance.d.ts.map +1 -0
- package/dist/runtime/compute-instance.js +14 -0
- package/dist/runtime/constants.d.ts +315 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +502 -16
- package/dist/runtime/count-step-started-events.d.ts +52 -0
- package/dist/runtime/count-step-started-events.d.ts.map +1 -0
- package/dist/runtime/count-step-started-events.js +72 -0
- package/dist/runtime/deployment-guard.d.ts +99 -0
- package/dist/runtime/deployment-guard.d.ts.map +1 -0
- package/dist/runtime/deployment-guard.js +154 -0
- package/dist/runtime/get-port-lazy.d.ts +15 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -1
- package/dist/runtime/get-port-lazy.js +75 -6
- package/dist/runtime/get-world-lazy.d.ts +5 -14
- package/dist/runtime/get-world-lazy.d.ts.map +1 -1
- package/dist/runtime/get-world-lazy.js +19 -29
- package/dist/runtime/helpers.d.ts +341 -29
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +559 -57
- package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
- package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
- package/dist/runtime/quickjs-assets.generated.js +30 -0
- package/dist/runtime/quickjs-entrypoint.d.ts +136 -0
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
- package/dist/runtime/quickjs-entrypoint.js +1686 -0
- package/dist/runtime/quickjs-runtime.d.ts +244 -0
- package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
- package/dist/runtime/quickjs-runtime.js +2427 -0
- package/dist/runtime/quickjs-serde.d.ts +107 -0
- package/dist/runtime/quickjs-serde.d.ts.map +1 -0
- package/dist/runtime/quickjs-serde.js +2159 -0
- package/dist/runtime/replay-budget.d.ts +97 -0
- package/dist/runtime/replay-budget.d.ts.map +1 -0
- package/dist/runtime/replay-budget.js +139 -0
- package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
- package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
- package/dist/runtime/replay-recovery-reporter.js +64 -0
- package/dist/runtime/resume-hook.d.ts +91 -8
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +512 -89
- package/dist/runtime/resume-latency.d.ts +150 -0
- package/dist/runtime/resume-latency.d.ts.map +1 -0
- package/dist/runtime/resume-latency.js +155 -0
- package/dist/runtime/run-id-time.d.ts +19 -0
- package/dist/runtime/run-id-time.d.ts.map +1 -0
- package/dist/runtime/run-id-time.js +42 -0
- package/dist/runtime/run.d.ts +72 -7
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +280 -53
- package/dist/runtime/runs.d.ts +54 -3
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +126 -16
- package/dist/runtime/start.d.ts +101 -2
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +352 -61
- package/dist/runtime/step-executor.d.ts +205 -5
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +760 -127
- package/dist/runtime/step-latency.d.ts +220 -0
- package/dist/runtime/step-latency.d.ts.map +1 -0
- package/dist/runtime/step-latency.js +215 -0
- package/dist/runtime/step-ownership.d.ts +72 -0
- package/dist/runtime/step-ownership.d.ts.map +1 -0
- package/dist/runtime/step-ownership.js +114 -0
- package/dist/runtime/step-single-flight.d.ts +12 -0
- package/dist/runtime/step-single-flight.d.ts.map +1 -0
- package/dist/runtime/step-single-flight.js +75 -0
- package/dist/runtime/suspension-handler.d.ts +269 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +1253 -125
- package/dist/runtime/unserializable-step.d.ts +34 -0
- package/dist/runtime/unserializable-step.d.ts.map +1 -0
- package/dist/runtime/unserializable-step.js +52 -0
- package/dist/runtime/vm-mode.d.ts +44 -0
- package/dist/runtime/vm-mode.d.ts.map +1 -0
- package/dist/runtime/vm-mode.js +62 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
- package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
- package/dist/runtime/vm-serde-bundle.generated.js +16 -0
- package/dist/runtime/wait-continuation.d.ts +106 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +136 -0
- package/dist/runtime/wait-until.d.ts +18 -0
- package/dist/runtime/wait-until.d.ts.map +1 -0
- package/dist/runtime/wait-until.js +42 -0
- package/dist/runtime/world-compatibility.d.ts +32 -0
- package/dist/runtime/world-compatibility.d.ts.map +1 -0
- package/dist/runtime/world-compatibility.js +44 -0
- package/dist/runtime/world-init.d.ts +17 -42
- package/dist/runtime/world-init.d.ts.map +1 -1
- package/dist/runtime/world-init.js +18 -43
- package/dist/runtime/world.d.ts +14 -2
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +75 -19
- package/dist/runtime.d.ts +10 -6
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +3741 -490
- package/dist/sealed-box.d.ts +167 -0
- package/dist/sealed-box.d.ts.map +1 -0
- package/dist/sealed-box.js +571 -0
- package/dist/serialization/client.d.ts +3 -3
- package/dist/serialization/client.d.ts.map +1 -1
- package/dist/serialization/client.js +8 -4
- package/dist/serialization/codec-devalue-vm.d.ts +16 -0
- package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
- package/dist/serialization/codec-devalue-vm.js +148 -0
- package/dist/serialization/codec-devalue.d.ts +1 -1
- package/dist/serialization/codec-devalue.d.ts.map +1 -1
- package/dist/serialization/codec-devalue.js +24 -6
- package/dist/serialization/codec.d.ts +37 -2
- package/dist/serialization/codec.d.ts.map +1 -1
- package/dist/serialization/codec.js +2 -2
- package/dist/serialization/compression.d.ts +105 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +261 -0
- package/dist/serialization/encryption.d.ts +119 -17
- package/dist/serialization/encryption.d.ts.map +1 -1
- package/dist/serialization/encryption.js +152 -17
- package/dist/serialization/errors.d.ts +13 -0
- package/dist/serialization/errors.d.ts.map +1 -1
- package/dist/serialization/errors.js +20 -2
- package/dist/serialization/format.d.ts +6 -6
- package/dist/serialization/format.js +7 -7
- package/dist/serialization/hardened.d.ts +156 -0
- package/dist/serialization/hardened.d.ts.map +1 -0
- package/dist/serialization/hardened.js +538 -0
- package/dist/serialization/index.d.ts +10 -8
- package/dist/serialization/index.d.ts.map +1 -1
- package/dist/serialization/index.js +10 -8
- package/dist/serialization/reducers/class-vm.d.ts +20 -0
- package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/class-vm.js +77 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -1
- package/dist/serialization/reducers/class.js +11 -6
- package/dist/serialization/reducers/common-vm.d.ts +15 -0
- package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/common-vm.js +616 -0
- package/dist/serialization/reducers/common.d.ts +1 -1
- package/dist/serialization/reducers/common.d.ts.map +1 -1
- package/dist/serialization/reducers/common.js +202 -62
- package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
- package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function-vm.js +97 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -1
- package/dist/serialization/reducers/step-function.js +25 -9
- package/dist/serialization/step.d.ts +4 -4
- package/dist/serialization/step.d.ts.map +1 -1
- package/dist/serialization/step.js +9 -5
- package/dist/serialization/types.d.ts +80 -1
- package/dist/serialization/types.d.ts.map +1 -1
- package/dist/serialization/types.js +15 -1
- package/dist/serialization/workflow-vm.d.ts +29 -0
- package/dist/serialization/workflow-vm.d.ts.map +1 -0
- package/dist/serialization/workflow-vm.js +74 -0
- package/dist/serialization-format.d.ts +64 -8
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +225 -73
- package/dist/serialization.d.ts +262 -34
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1879 -274
- package/dist/set-attributes.d.ts +13 -0
- package/dist/set-attributes.d.ts.map +1 -0
- package/dist/set-attributes.js +60 -0
- package/dist/source-map.d.ts +25 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +154 -10
- package/dist/step/context-storage.d.ts +61 -2
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +7 -5
- package/dist/step/writable-stream.d.ts +3 -3
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +72 -9
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +148 -27
- package/dist/symbols.d.ts +50 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +51 -1
- package/dist/telemetry/semantic-conventions.d.ts +397 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +297 -3
- package/dist/telemetry.d.ts +91 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +244 -17
- package/dist/test-support/orchestrator-context.d.ts +25 -0
- package/dist/test-support/orchestrator-context.d.ts.map +1 -0
- package/dist/test-support/orchestrator-context.js +101 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -1
- package/dist/util.d.ts +0 -5
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +84 -14
- package/dist/vm/script-cache.d.ts +26 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +131 -0
- package/dist/vm/uint8array-base64.js +1 -1
- package/dist/workflow/abort-controller.d.ts +2 -2
- package/dist/workflow/abort-controller.d.ts.map +1 -1
- package/dist/workflow/abort-controller.js +88 -21
- package/dist/workflow/attribute-dispatcher.d.ts +6 -0
- package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
- package/dist/workflow/attribute-dispatcher.js +45 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +24 -3
- package/dist/workflow/get-workflow-metadata.js +2 -2
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +304 -47
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -1
- package/dist/workflow/set-attributes.d.ts +68 -0
- package/dist/workflow/set-attributes.d.ts.map +1 -0
- package/dist/workflow/set-attributes.js +60 -0
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +58 -12
- package/dist/workflow/world-init-stub.d.ts +3 -3
- package/dist/workflow/world-init-stub.js +4 -4
- package/dist/workflow.d.ts +95 -3
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +895 -561
- package/docs/api-reference/create-hook.mdx +89 -10
- package/docs/api-reference/create-webhook.mdx +16 -15
- package/docs/api-reference/define-hook.mdx +35 -33
- package/docs/api-reference/fatal-error.mdx +30 -8
- package/docs/api-reference/fetch.mdx +14 -10
- package/docs/api-reference/get-step-metadata.mdx +2 -2
- package/docs/api-reference/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/get-writable.mdx +7 -7
- package/docs/api-reference/index.mdx +4 -1
- package/docs/api-reference/retryable-error.mdx +1 -1
- package/docs/api-reference/set-attributes.mdx +61 -0
- package/docs/api-reference/sleep.mdx +4 -4
- package/docs/foundations/cancellation.mdx +31 -32
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +64 -35
- package/docs/foundations/idempotency.mdx +244 -12
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +2 -1
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +106 -30
- package/docs/foundations/streaming.mdx +107 -59
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/how-it-works/cancellation.mdx +63 -63
- package/docs/how-it-works/code-transform.mdx +83 -67
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +98 -34
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/understanding-directives.mdx +22 -22
- package/package.json +24 -15
- package/dist/runtime/step-handler.d.ts +0 -2
- package/dist/runtime/step-handler.d.ts.map +0 -1
- package/dist/runtime/step-handler.js +0 -776
package/dist/runtime/helpers.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PreconditionFailedError, RUN_ERROR_CODES, WorkflowWorldError, } from '@workflow/errors';
|
|
2
|
+
import { FIRST_EVENT_SLOT, getQueueTopicPrefix, HealthCheckPayloadSchema, HOOK_RESUME_INPUT_VERSION, requireEventSlot, resolveQueueNamespace, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, } from '@workflow/world';
|
|
2
3
|
import { monotonicFactory } from 'ulid';
|
|
3
|
-
import { importKey } from '../encryption.js';
|
|
4
4
|
import { runtimeLogger } from '../logger.js';
|
|
5
|
+
import { bytesToBase64, deriveRunKeyPair } from '../sealed-box.js';
|
|
6
|
+
import { deriveRunPayloadKeys, } from '../serialization/encryption.js';
|
|
5
7
|
import * as Attribute from '../telemetry/semantic-conventions.js';
|
|
6
8
|
import { getSpanKind, trace } from '../telemetry.js';
|
|
7
9
|
import { version as workflowCoreVersion } from '../version.js';
|
|
@@ -19,11 +21,12 @@ const SAFE_WORKFLOW_NAME_PATTERN = /^[a-zA-Z0-9_\-./@]+$/;
|
|
|
19
21
|
* Ensures the workflow name only contains safe characters before
|
|
20
22
|
* interpolating it into the queue name string.
|
|
21
23
|
*/
|
|
22
|
-
export function getWorkflowQueueName(workflowName) {
|
|
24
|
+
export function getWorkflowQueueName(workflowName, namespace) {
|
|
23
25
|
if (!SAFE_WORKFLOW_NAME_PATTERN.test(workflowName)) {
|
|
24
26
|
throw new Error(`Invalid workflow name "${workflowName}": must only contain alphanumeric characters, underscores, hyphens, dots, forward slashes, or at signs`);
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
const prefix = getQueueTopicPrefix('workflow', resolveQueueNamespace(namespace));
|
|
29
|
+
return `${prefix}${workflowName}`;
|
|
27
30
|
}
|
|
28
31
|
const generateId = monotonicFactory();
|
|
29
32
|
/**
|
|
@@ -57,17 +60,45 @@ function generateHealthCheckRunId(correlationId) {
|
|
|
57
60
|
* The caller can listen to this stream to get the health check response.
|
|
58
61
|
*
|
|
59
62
|
* @param healthCheck - The parsed health check payload
|
|
60
|
-
* @param endpoint - Which endpoint is responding ('workflow' or 'step')
|
|
61
63
|
*/
|
|
62
|
-
export async function handleHealthCheckMessage(healthCheck,
|
|
64
|
+
export async function handleHealthCheckMessage(healthCheck, worldSpecVersion) {
|
|
63
65
|
const world = await getWorldLazy();
|
|
64
66
|
const streamName = getHealthCheckStreamName(healthCheck.correlationId);
|
|
67
|
+
// When the probe names a run the caller is about to create, publish that
|
|
68
|
+
// run's public key. We are executing inside the target deployment, so its
|
|
69
|
+
// key material is available locally (no API call), and the caller can then
|
|
70
|
+
// seal the workflow arguments straight from this response rather than
|
|
71
|
+
// making a separate key-lookup request.
|
|
72
|
+
//
|
|
73
|
+
// Only a *public* key may travel this way: the probe response stream is
|
|
74
|
+
// deliberately unauthenticated, so anything secret would be exposed.
|
|
75
|
+
// Best-effort: a failure here must not fail the health check itself, which
|
|
76
|
+
// callers also rely on for plain capability detection.
|
|
77
|
+
let encryptionPublicKey;
|
|
78
|
+
if (healthCheck.runId) {
|
|
79
|
+
try {
|
|
80
|
+
const rawKey = await world.getEncryptionKeyForRun?.(healthCheck.runId);
|
|
81
|
+
if (rawKey) {
|
|
82
|
+
encryptionPublicKey = bytesToBase64((await deriveRunKeyPair(rawKey)).publicKey);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
runtimeLogger.warn('Health check could not derive a run public key; the caller will fall back to a key lookup', {
|
|
87
|
+
correlationId: healthCheck.correlationId,
|
|
88
|
+
error: err instanceof Error ? err.message : String(err),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
65
92
|
const response = JSON.stringify({
|
|
66
93
|
healthy: true,
|
|
67
|
-
endpoint,
|
|
68
94
|
correlationId: healthCheck.correlationId,
|
|
69
95
|
specVersion: worldSpecVersion ?? SPEC_VERSION_CURRENT,
|
|
70
96
|
workflowCoreVersion,
|
|
97
|
+
// We are executing inside the target deployment, so this constant reflects
|
|
98
|
+
// the *consumer's* hook-resume protocol version, exactly what a
|
|
99
|
+
// cross-deployment caller needs to gate its parallel resume path on.
|
|
100
|
+
hookResumeInputVersion: HOOK_RESUME_INPUT_VERSION,
|
|
101
|
+
...(encryptionPublicKey ? { encryptionPublicKey } : {}),
|
|
71
102
|
timestamp: Date.now(),
|
|
72
103
|
});
|
|
73
104
|
// Use a deterministic fake runId derived from the correlationId so that
|
|
@@ -78,13 +109,12 @@ export async function handleHealthCheckMessage(healthCheck, endpoint, worldSpecV
|
|
|
78
109
|
}
|
|
79
110
|
/**
|
|
80
111
|
* Performs a health check by sending a message through the queue pipeline
|
|
81
|
-
* and verifying it is processed by the
|
|
112
|
+
* and verifying it is processed by the combined workflow endpoint.
|
|
82
113
|
*
|
|
83
114
|
* This function bypasses Deployment Protection on Vercel because it goes
|
|
84
115
|
* through the queue infrastructure rather than direct HTTP.
|
|
85
116
|
*
|
|
86
117
|
* @param world - The World instance to use for the health check
|
|
87
|
-
* @param endpoint - Which endpoint to health check: 'workflow' or 'step'
|
|
88
118
|
* @param options - Optional configuration for the health check
|
|
89
119
|
* @returns Promise resolving to health check result
|
|
90
120
|
*/
|
|
@@ -97,6 +127,24 @@ const HEALTH_CHECK_READ_TIMEOUT = 500;
|
|
|
97
127
|
* Read chunks from a stream with a timeout per read operation.
|
|
98
128
|
* Returns { chunks, timedOut } where timedOut indicates if a read timed out.
|
|
99
129
|
*/
|
|
130
|
+
/**
|
|
131
|
+
* Race a promise against a deadline. Rejects with a timeout error when the
|
|
132
|
+
* deadline elapses first. Used to bound `world.streams.get()` inside the
|
|
133
|
+
* health-check poll loop: some worlds hold that request open until the
|
|
134
|
+
* stream has data (e.g. workflow-server holds unwritten streams open for
|
|
135
|
+
* ~2 minutes), which would otherwise blow through the configured health
|
|
136
|
+
* check timeout, since the `while` condition is only re-checked between
|
|
137
|
+
* iterations.
|
|
138
|
+
*/
|
|
139
|
+
function withDeadline(promise, ms) {
|
|
140
|
+
let timer;
|
|
141
|
+
return Promise.race([
|
|
142
|
+
promise,
|
|
143
|
+
new Promise((_, reject) => {
|
|
144
|
+
timer = setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms);
|
|
145
|
+
}),
|
|
146
|
+
]).finally(() => clearTimeout(timer));
|
|
147
|
+
}
|
|
100
148
|
async function readStreamWithTimeout(reader, readTimeout) {
|
|
101
149
|
const chunks = [];
|
|
102
150
|
let done = false;
|
|
@@ -155,18 +203,37 @@ function parseHealthCheckResponse(chunks) {
|
|
|
155
203
|
if (typeof r.specVersion === 'number') {
|
|
156
204
|
parsed.specVersion = r.specVersion;
|
|
157
205
|
}
|
|
206
|
+
if (typeof r.workflowCoreVersion === 'string') {
|
|
207
|
+
parsed.workflowCoreVersion = r.workflowCoreVersion;
|
|
208
|
+
}
|
|
209
|
+
if (typeof r.encryptionPublicKey === 'string') {
|
|
210
|
+
parsed.encryptionPublicKey = r.encryptionPublicKey;
|
|
211
|
+
}
|
|
212
|
+
if (typeof r.hookResumeInputVersion === 'number') {
|
|
213
|
+
parsed.hookResumeInputVersion = r.hookResumeInputVersion;
|
|
214
|
+
}
|
|
158
215
|
return parsed;
|
|
159
216
|
}
|
|
160
|
-
export async function healthCheck(world,
|
|
217
|
+
export async function healthCheck(world, options) {
|
|
161
218
|
const timeout = options?.timeout ?? DEFAULT_HEALTH_CHECK_TIMEOUT;
|
|
162
|
-
|
|
219
|
+
// Use the world's ID generator when available so the correlationId is a
|
|
220
|
+
// region-tagged ULID. The health-check response is delivered over a stream
|
|
221
|
+
// whose name embeds this correlationId; under platform-directed routing the
|
|
222
|
+
// reader and the responding endpoint can be served from different physical
|
|
223
|
+
// regions, so the region must be encoded in the ID itself for both sides to
|
|
224
|
+
// resolve the same (region-pinned) backend. Falls back to a plain ULID for
|
|
225
|
+
// worlds that don't tag IDs (e.g. local), which resolve to the default
|
|
226
|
+
// region on both sides.
|
|
227
|
+
const correlationId = world.createRunId?.() ?? generateId();
|
|
163
228
|
const streamName = getHealthCheckStreamName(correlationId);
|
|
164
|
-
const queueName =
|
|
165
|
-
? '__wkf_workflow_health_check'
|
|
166
|
-
: '__wkf_step_health_check';
|
|
229
|
+
const queueName = `${getQueueTopicPrefix('workflow', resolveQueueNamespace(options?.namespace))}health_check`;
|
|
167
230
|
const startTime = Date.now();
|
|
168
231
|
try {
|
|
169
|
-
await world.queue(queueName, {
|
|
232
|
+
await world.queue(queueName, {
|
|
233
|
+
__healthCheck: true,
|
|
234
|
+
correlationId,
|
|
235
|
+
...(options?.runId ? { runId: options.runId } : {}),
|
|
236
|
+
}, {
|
|
170
237
|
// Use JSON transport so the health check works against both
|
|
171
238
|
// old (JSON-only) and new (dual) deployments.
|
|
172
239
|
specVersion: SPEC_VERSION_LEGACY,
|
|
@@ -174,7 +241,8 @@ export async function healthCheck(world, endpoint, options) {
|
|
|
174
241
|
});
|
|
175
242
|
while (Date.now() - startTime < timeout) {
|
|
176
243
|
try {
|
|
177
|
-
const
|
|
244
|
+
const remainingMs = timeout - (Date.now() - startTime);
|
|
245
|
+
const stream = await withDeadline(world.streams.get(generateHealthCheckRunId(correlationId), streamName), remainingMs);
|
|
178
246
|
const reader = stream.getReader();
|
|
179
247
|
const { chunks, timedOut } = await readStreamWithTimeout(reader, HEALTH_CHECK_READ_TIMEOUT);
|
|
180
248
|
if (timedOut) {
|
|
@@ -212,6 +280,94 @@ export async function healthCheck(world, endpoint, options) {
|
|
|
212
280
|
};
|
|
213
281
|
}
|
|
214
282
|
}
|
|
283
|
+
function eventPaginationContractError(runId, message) {
|
|
284
|
+
return new WorkflowWorldError(`Event pagination ${message} for workflow run "${runId}".`, { code: RUN_ERROR_CODES.WORLD_CONTRACT_ERROR });
|
|
285
|
+
}
|
|
286
|
+
function recordRequestedEventCursor(runId, cursor, requestedCursors) {
|
|
287
|
+
if (!cursor) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (requestedCursors.has(cursor)) {
|
|
291
|
+
throw eventPaginationContractError(runId, 'did not advance');
|
|
292
|
+
}
|
|
293
|
+
requestedCursors.add(cursor);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Appends events whose IDs are not already present in `target`.
|
|
297
|
+
*
|
|
298
|
+
* Pass the IDs currently present in `target` when appending repeatedly to the
|
|
299
|
+
* same array. The set is updated alongside `target`.
|
|
300
|
+
*
|
|
301
|
+
* Events are appended in the order the World returned them, and are not
|
|
302
|
+
* re-sorted. Every append source is already in canonical order relative to the
|
|
303
|
+
* tail (a cursor-delimited page, or a write-response delta), so receipt order is
|
|
304
|
+
* the order to keep, and re-sorting here would only cost a pass over the log.
|
|
305
|
+
* Nothing downstream may assume the tail is the newest event. See
|
|
306
|
+
* {@link maxEventSlot}.
|
|
307
|
+
*/
|
|
308
|
+
export function appendUniqueEvents(target, events, targetIds) {
|
|
309
|
+
if (events.length === 0) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const ids = targetIds ?? new Set(target.map((event) => event.eventId));
|
|
313
|
+
for (const event of events) {
|
|
314
|
+
if (ids.has(event.eventId)) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
ids.add(event.eventId);
|
|
318
|
+
target.push(event);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Inserts `event` into `target` at the position that keeps `target` ordered by
|
|
323
|
+
* ascending `eventId`, or no-ops if an event with the same `eventId` is already
|
|
324
|
+
* present (idempotent).
|
|
325
|
+
*
|
|
326
|
+
* `preloadedEvents` is loaded `sortOrder: 'asc'` and is never re-sorted
|
|
327
|
+
* client-side, so a `hook_received` spliced in by the lazy-resume consumer must
|
|
328
|
+
* land in `eventId` order: a plain `push` would place a late-committing
|
|
329
|
+
* earlier event after events that sort before it, corrupting replay.
|
|
330
|
+
*
|
|
331
|
+
* Lexicographic string order is the log's order: a slot id is a fixed-width
|
|
332
|
+
* zero-padded position, so comparing the strings compares the positions. This
|
|
333
|
+
* needs no parse of its own for that reason, and the comparison is exact rather
|
|
334
|
+
* than a reconstruction.
|
|
335
|
+
*/
|
|
336
|
+
export function insertEventByEventId(target, event) {
|
|
337
|
+
// Linear scan from the end: the spliced event is almost always the newest
|
|
338
|
+
// (it sorts at or near the tail), so this finds the slot in O(1)–O(k) for the
|
|
339
|
+
// common case while still handling an out-of-order late arrival correctly.
|
|
340
|
+
let i = target.length;
|
|
341
|
+
while (i > 0) {
|
|
342
|
+
const existing = target[i - 1];
|
|
343
|
+
if (existing.eventId === event.eventId) {
|
|
344
|
+
// Already present: keep the splice idempotent.
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (existing.eventId < event.eventId) {
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
i--;
|
|
351
|
+
}
|
|
352
|
+
target.splice(i, 0, event);
|
|
353
|
+
}
|
|
354
|
+
function assertEventPaginationProgress(runId, hasMore, cursor, requestedCursors) {
|
|
355
|
+
if (!hasMore) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (cursor === null) {
|
|
359
|
+
throw eventPaginationContractError(runId, 'returned more pages without a cursor');
|
|
360
|
+
}
|
|
361
|
+
if (requestedCursors.has(cursor)) {
|
|
362
|
+
throw eventPaginationContractError(runId, 'repeated a cursor');
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function shouldRetryWithoutEventCursor(error, cursor, alreadyRetried) {
|
|
366
|
+
return (cursor !== null &&
|
|
367
|
+
!alreadyRetried &&
|
|
368
|
+
WorkflowWorldError.is(error) &&
|
|
369
|
+
error.status === 400);
|
|
370
|
+
}
|
|
215
371
|
/**
|
|
216
372
|
* Loads workflow run events by iterating through all pages of paginated
|
|
217
373
|
* results. Events are returned in chronological (ascending) order for
|
|
@@ -225,31 +381,61 @@ export async function healthCheck(world, endpoint, options) {
|
|
|
225
381
|
*/
|
|
226
382
|
export async function loadWorkflowRunEvents(runId, afterCursor) {
|
|
227
383
|
const incremental = afterCursor !== undefined;
|
|
228
|
-
return trace(
|
|
384
|
+
return trace('workflow.replay.load', async (span) => {
|
|
229
385
|
span?.setAttributes({
|
|
230
386
|
...Attribute.WorkflowRunId(runId),
|
|
387
|
+
...Attribute.WorkflowReplayLoadSource(incremental ? 'events_list_incremental' : 'events_list'),
|
|
231
388
|
});
|
|
232
389
|
const loadedEvents = [];
|
|
390
|
+
const loadedEventIds = new Set();
|
|
391
|
+
const requestedCursors = new Set();
|
|
233
392
|
let cursor = afterCursor ?? null;
|
|
234
393
|
let hasMore = true;
|
|
235
394
|
let pagesLoaded = 0;
|
|
395
|
+
let retriedWithoutCursor = false;
|
|
236
396
|
const world = await getWorldLazy();
|
|
237
397
|
const loadStart = Date.now();
|
|
238
398
|
while (hasMore) {
|
|
239
|
-
// TODO: we're currently loading all the data with resolveRef
|
|
399
|
+
// TODO: we're currently loading all the data with resolveRef behavior. We need to update this
|
|
240
400
|
// to lazyload the data from the world instead so that we can optimize and make the event log loading
|
|
241
401
|
// much faster and memory efficient
|
|
242
402
|
const pageStart = Date.now();
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
403
|
+
const requestedCursor = cursor;
|
|
404
|
+
recordRequestedEventCursor(runId, requestedCursor, requestedCursors);
|
|
405
|
+
let response;
|
|
406
|
+
try {
|
|
407
|
+
response = await world.events.list({
|
|
408
|
+
runId,
|
|
409
|
+
pagination: {
|
|
410
|
+
sortOrder: 'asc',
|
|
411
|
+
cursor: requestedCursor ?? undefined,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
if (shouldRetryWithoutEventCursor(error, requestedCursor, retriedWithoutCursor)) {
|
|
417
|
+
runtimeLogger.warn('Event cursor was rejected; retrying with a full event reload.', { workflowRunId: runId });
|
|
418
|
+
loadedEvents.length = 0;
|
|
419
|
+
loadedEventIds.clear();
|
|
420
|
+
requestedCursors.clear();
|
|
421
|
+
cursor = null;
|
|
422
|
+
retriedWithoutCursor = true;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
427
|
+
appendUniqueEvents(loadedEvents, response.data, loadedEventIds);
|
|
251
428
|
hasMore = response.hasMore;
|
|
252
|
-
|
|
429
|
+
assertEventPaginationProgress(runId, hasMore, response.cursor, requestedCursors);
|
|
430
|
+
// Preserve the last non-null cursor across pages. A World may
|
|
431
|
+
// legitimately return `{ data: [], cursor: null, hasMore: false }`
|
|
432
|
+
// on a trailing empty page, for example when the previous page's
|
|
433
|
+
// underlying DB query hit the limit exactly and returned a
|
|
434
|
+
// precautionary `LastEvaluatedKey`. Overwriting with that null
|
|
435
|
+
// would lose the position past the last real event we loaded and
|
|
436
|
+
// force the runtime into the "no cursor after initial load" full-
|
|
437
|
+
// reload fallback on every subsequent replay iteration.
|
|
438
|
+
cursor = response.cursor ?? cursor;
|
|
253
439
|
pagesLoaded++;
|
|
254
440
|
runtimeLogger.debug('Loaded event page', {
|
|
255
441
|
workflowRunId: runId,
|
|
@@ -275,6 +461,302 @@ export async function loadWorkflowRunEvents(runId, afterCursor) {
|
|
|
275
461
|
return { events: loadedEvents, cursor };
|
|
276
462
|
});
|
|
277
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Extend a loaded log with a page that continues it — a listed page, or the
|
|
466
|
+
* inline delta a write handed back — and move its read position with it.
|
|
467
|
+
*
|
|
468
|
+
* The cursor is only advanced when the page carries one, so a source with no
|
|
469
|
+
* position of its own (a skipped-slot report) cannot walk the read position
|
|
470
|
+
* past events it did not carry. Appending does not re-sort; see
|
|
471
|
+
* {@link appendUniqueEvents} for why receipt order is the order to keep.
|
|
472
|
+
*/
|
|
473
|
+
export function appendEventLog(log, appended) {
|
|
474
|
+
appendUniqueEvents(log.events, appended.events);
|
|
475
|
+
log.cursor = appended.cursor ?? log.cursor;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Whether a replay refuses to run over a log with a hole in it (see
|
|
479
|
+
* {@link findEventSlotGap}). **On by default**; set
|
|
480
|
+
* `WORKFLOW_SLOT_GAP_CHECK=0` to replay across holes instead.
|
|
481
|
+
*
|
|
482
|
+
* A World that allocates a position at the moment it commits leaves no hole
|
|
483
|
+
* behind when a write fails, so density is a property the log has by
|
|
484
|
+
* construction rather than one this check maintains. What the check is for is
|
|
485
|
+
* the reads and the Worlds where that does not hold, and by the time it runs
|
|
486
|
+
* the benign explanations are spent: a position missing because a concurrent
|
|
487
|
+
* commit is not visible yet clears on a re-read, which is what
|
|
488
|
+
* {@link settleEventSlotGap} does first.
|
|
489
|
+
*
|
|
490
|
+
* What is left is a hole that persists, and its two causes are
|
|
491
|
+
* indistinguishable from the log. Either a World allocated the position outside
|
|
492
|
+
* the commit and lost the write, in which case nothing happened there and
|
|
493
|
+
* replaying past it is correct, or an event that did happen is missing, in
|
|
494
|
+
* which case replaying past it decides a branch on absence and produces a wrong
|
|
495
|
+
* result with nothing to show for it. Failing is the recoverable side of that
|
|
496
|
+
* trade, and this is the way back out if a fleet turns out to carry holes of
|
|
497
|
+
* the first kind.
|
|
498
|
+
*/
|
|
499
|
+
export function isSlotGapCheckEnabled() {
|
|
500
|
+
return process.env.WORKFLOW_SLOT_GAP_CHECK !== '0';
|
|
501
|
+
}
|
|
502
|
+
/*
|
|
503
|
+
* Merging into a log a replay is midway through reading.
|
|
504
|
+
*
|
|
505
|
+
* Three paths add events to a loaded log after the replay has started: a
|
|
506
|
+
* bump-and-report write hands back the slots it skipped ({@link
|
|
507
|
+
* mergeReportedEvents}), an inline delta extends the tail (`absorbCreateDelta`
|
|
508
|
+
* in `runtime.ts`), and a listed page appends ({@link appendUniqueEvents}).
|
|
509
|
+
* They look alarming (the replay is reading an array while something else
|
|
510
|
+
* writes to it) and they are safe for one reason worth stating plainly, since
|
|
511
|
+
* every correctness argument in this file leans on it.
|
|
512
|
+
*
|
|
513
|
+
* **An event in the log is a fact, and a longer log cannot retract one.** The
|
|
514
|
+
* log is append-only and positions are never reused, so a replay that produced
|
|
515
|
+
* event E from the prefix it had loaded has made E true for every replay that
|
|
516
|
+
* follows. A later replay reading a fuller log does not get to decide E should
|
|
517
|
+
* not be there; it consumes E and reconciles to it, which is what the events
|
|
518
|
+
* consumer does when it walks a log holding writes from a replay that raced it.
|
|
519
|
+
*
|
|
520
|
+
* Merging is therefore monotone: it can only add facts this replay has yet to
|
|
521
|
+
* reconcile to, never remove one it already has. That is why absorbing is
|
|
522
|
+
* always optional and never wrong to decline (an unabsorbed event is one the
|
|
523
|
+
* next read returns), and why the guards below can afford to be strict.
|
|
524
|
+
*/
|
|
525
|
+
/**
|
|
526
|
+
* Merge the events a bump-and-report write handed back into the log it was
|
|
527
|
+
* derived from, and answer how many of them were new.
|
|
528
|
+
*
|
|
529
|
+
* Unlike {@link appendUniqueEvents}, this re-sorts. The reported events occupy
|
|
530
|
+
* slots *below* the write that reported them, so appending them would put them
|
|
531
|
+
* after events they precede. Sorting by id restores the World's canonical order
|
|
532
|
+
* rather than guessing at it: a slot id is that order, written down.
|
|
533
|
+
*/
|
|
534
|
+
export function mergeReportedEvents(target, events) {
|
|
535
|
+
const before = target.length;
|
|
536
|
+
appendUniqueEvents(target, events);
|
|
537
|
+
const added = target.length - before;
|
|
538
|
+
if (added > 0) {
|
|
539
|
+
target.sort((a, b) => a.eventId < b.eventId ? -1 : a.eventId > b.eventId ? 1 : 0);
|
|
540
|
+
}
|
|
541
|
+
return added;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Apply a write's skipped-slot report to the log it was derived from, deciding
|
|
545
|
+
* whether the report may be taken at all.
|
|
546
|
+
*
|
|
547
|
+
* Every replay-context write can come back carrying the events on the slots it
|
|
548
|
+
* skipped over, and every caller wants the same thing from them: fold them in
|
|
549
|
+
* so the writes that follow name a position above them, and so the replay
|
|
550
|
+
* resuming from this log sees them without a reload.
|
|
551
|
+
*
|
|
552
|
+
* The one policy is that a **truncated report is dropped whole**. It covers a
|
|
553
|
+
* span of positions but carries only some of the events on them, so merging it
|
|
554
|
+
* would raise the log's highest position past a position whose event is
|
|
555
|
+
* missing. Later writes read that maximum to say what they have seen, so each
|
|
556
|
+
* would claim a position it never saw, and the World only reports the span a
|
|
557
|
+
* write skips: it would never send the missing one. Dropping costs one more
|
|
558
|
+
* round of the same events on the next write and keeps the log a prefix of the
|
|
559
|
+
* truth, which the note above {@link mergeReportedEvents} explains is always an
|
|
560
|
+
* available answer.
|
|
561
|
+
*
|
|
562
|
+
* Callers that log do so from the returned counts; the decision is not theirs
|
|
563
|
+
* to re-derive.
|
|
564
|
+
*/
|
|
565
|
+
export function absorbSkippedSlotReport(target, result) {
|
|
566
|
+
const offered = result.events?.length ?? 0;
|
|
567
|
+
if (offered === 0) {
|
|
568
|
+
return { added: 0, offered: 0, truncated: false };
|
|
569
|
+
}
|
|
570
|
+
if (result.hasMore === true) {
|
|
571
|
+
return { added: 0, offered, truncated: true };
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
added: mergeReportedEvents(target, result.events ?? []),
|
|
575
|
+
offered,
|
|
576
|
+
truncated: false,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* The highest slot the loaded log occupies, or `undefined` for an empty log.
|
|
581
|
+
*
|
|
582
|
+
* The maximum, not the count, and the two are not interchangeable even though
|
|
583
|
+
* a healthy log makes them equal. A World hands a position to the insert that
|
|
584
|
+
* occupies it, so a write that never lands leaves no hole behind and the log
|
|
585
|
+
* stays dense. What the count cannot survive is a *partial* read: a log
|
|
586
|
+
* assembled from a truncated report, or read while a concurrent write is
|
|
587
|
+
* committing, holds fewer events than its highest position. Counting those
|
|
588
|
+
* would make the next write claim to have seen less than it has, so the World
|
|
589
|
+
* would report the same events back to it on every attempt.
|
|
590
|
+
*
|
|
591
|
+
* A hole below the maximum is therefore a property of the read, not of the log,
|
|
592
|
+
* which is what lets {@link settleEventSlotGap} re-read instead of giving up.
|
|
593
|
+
*
|
|
594
|
+
* @throws if any event id carries no slot. Every World the runtime replays
|
|
595
|
+
* against numbers events by slot, so an id that does not is a broken log rather
|
|
596
|
+
* than an older one, and a maximum derived by skipping it would understate the
|
|
597
|
+
* log to every write that reads it.
|
|
598
|
+
*/
|
|
599
|
+
export function maxEventSlot(events) {
|
|
600
|
+
let max;
|
|
601
|
+
for (const event of events) {
|
|
602
|
+
const slot = requireEventSlot(event.eventId);
|
|
603
|
+
if (max === undefined || slot > max) {
|
|
604
|
+
max = slot;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return max;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* The hole in a loaded log, or `undefined` when there is none to find.
|
|
611
|
+
*
|
|
612
|
+
* The World allocates every position, so a log that holds `n` events below slot
|
|
613
|
+
* `n` is missing one. That matters before a replay
|
|
614
|
+
* and nowhere else: the replay reads the log as the complete record of what has
|
|
615
|
+
* happened, and an absent position is indistinguishable from an event that
|
|
616
|
+
* never occurred. The branch it would have decided gets decided the other way,
|
|
617
|
+
* and the run diverges quietly rather than failing.
|
|
618
|
+
*
|
|
619
|
+
* Order-independent, unlike the equivalent audit the World runs over a page it
|
|
620
|
+
* just read. A loaded log is assembled from listed pages plus whatever a
|
|
621
|
+
* bump-and-report write handed back, and while {@link mergeReportedEvents}
|
|
622
|
+
* restores id order, a check that can fail a healthy run should not depend on
|
|
623
|
+
* that having happened.
|
|
624
|
+
*
|
|
625
|
+
* The first slot is never counted. It belongs to `run_created`, which `start()`
|
|
626
|
+
* posts concurrently with the queue send, so a log read in that window
|
|
627
|
+
* legitimately begins at the second slot and fills in on its own. Every replay
|
|
628
|
+
* that races a run's own start would otherwise report a hole.
|
|
629
|
+
*
|
|
630
|
+
* Returns `undefined` for an empty log, which has no density to check.
|
|
631
|
+
*
|
|
632
|
+
* @throws if any event id carries no slot, for the reason {@link maxEventSlot}
|
|
633
|
+
* gives.
|
|
634
|
+
*/
|
|
635
|
+
export function findEventSlotGap(events) {
|
|
636
|
+
const occupied = new Set();
|
|
637
|
+
let maxSlot = 0;
|
|
638
|
+
for (const event of events) {
|
|
639
|
+
const slot = requireEventSlot(event.eventId);
|
|
640
|
+
occupied.add(slot);
|
|
641
|
+
if (slot > maxSlot) {
|
|
642
|
+
maxSlot = slot;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (maxSlot === 0) {
|
|
646
|
+
return undefined;
|
|
647
|
+
}
|
|
648
|
+
const floor = occupied.has(FIRST_EVENT_SLOT)
|
|
649
|
+
? FIRST_EVENT_SLOT
|
|
650
|
+
: FIRST_EVENT_SLOT + 1;
|
|
651
|
+
// Every slot is at or above `floor` by construction, so the log is dense
|
|
652
|
+
// exactly when it holds one event per position in `[floor, maxSlot]`. The
|
|
653
|
+
// scan below only runs once that has already answered no.
|
|
654
|
+
if (occupied.size === maxSlot - floor + 1) {
|
|
655
|
+
return undefined;
|
|
656
|
+
}
|
|
657
|
+
let firstMissingSlot;
|
|
658
|
+
let missingCount = 0;
|
|
659
|
+
for (let slot = floor; slot <= maxSlot; slot++) {
|
|
660
|
+
if (!occupied.has(slot)) {
|
|
661
|
+
firstMissingSlot ??= slot;
|
|
662
|
+
missingCount++;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (firstMissingSlot === undefined) {
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
return { firstMissingSlot, missingCount, maxSlot };
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* How many times a detected hole is re-read before the log is taken at its
|
|
672
|
+
* word, and the backoff before each re-read (doubling per attempt).
|
|
673
|
+
*
|
|
674
|
+
* A hole can be transient. The World allocates a slot inside the insert that
|
|
675
|
+
* occupies it, so two concurrent writers can collide, one retry past the other,
|
|
676
|
+
* and the higher slot commit first, leaving a window in which the lower one is
|
|
677
|
+
* genuinely absent from a strongly-consistent read and fills in a moment later.
|
|
678
|
+
* The window is one commit wide, so a short backoff clears it; anything that
|
|
679
|
+
* survives all three re-reads is a position no write will ever occupy.
|
|
680
|
+
*/
|
|
681
|
+
export const SLOT_GAP_RECHECK_ATTEMPTS = 3;
|
|
682
|
+
const SLOT_GAP_RECHECK_BASE_DELAY_MS = 25;
|
|
683
|
+
/**
|
|
684
|
+
* Re-read a log that looks holey until the hole fills in or the re-reads run
|
|
685
|
+
* out, and return the settled log alongside the hole that survived.
|
|
686
|
+
*
|
|
687
|
+
* Reads are strongly consistent, so a hole is not an artifact of *when* the log
|
|
688
|
+
* was read, but it can be an artifact of a write that had not committed yet
|
|
689
|
+
* (see {@link SLOT_GAP_RECHECK_ATTEMPTS}). Distinguishing the two costs a
|
|
690
|
+
* re-read, which is only ever paid by a replay that already found a hole.
|
|
691
|
+
*
|
|
692
|
+
* The reload is full rather than incremental: the missing position is below the
|
|
693
|
+
* log's maximum, so a cursor-anchored read starts past it and can never see it
|
|
694
|
+
* arrive.
|
|
695
|
+
*/
|
|
696
|
+
export async function settleEventSlotGap(runId, loaded) {
|
|
697
|
+
let log = loaded;
|
|
698
|
+
let gap = findEventSlotGap(log.events);
|
|
699
|
+
for (let attempt = 0; gap !== undefined && attempt < SLOT_GAP_RECHECK_ATTEMPTS; attempt++) {
|
|
700
|
+
await new Promise((resolve) => setTimeout(resolve, SLOT_GAP_RECHECK_BASE_DELAY_MS * 2 ** attempt));
|
|
701
|
+
log = await loadWorkflowRunEvents(runId);
|
|
702
|
+
gap = findEventSlotGap(log.events);
|
|
703
|
+
}
|
|
704
|
+
return { log, gap };
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Build the slot snapshot to attach to a replay-context event creation.
|
|
708
|
+
*
|
|
709
|
+
* Empty for an empty log, which is the state a `run_created` write is issued
|
|
710
|
+
* from: there is no position held yet to name.
|
|
711
|
+
*
|
|
712
|
+
* The maximum rather than the length, for the reason {@link maxEventSlot}
|
|
713
|
+
* gives: a partially-read log holds fewer events than its highest position, and
|
|
714
|
+
* counting those would make the write claim to have seen less than it has, so
|
|
715
|
+
* the World would report the same events back on every attempt.
|
|
716
|
+
*/
|
|
717
|
+
export function slotSnapshotParams(events) {
|
|
718
|
+
const eventCount = maxEventSlot(events);
|
|
719
|
+
return eventCount === undefined ? {} : { eventCount };
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* The events a rejecting World attached to a `PreconditionFailedError`, when it
|
|
723
|
+
* returned the ones the client's snapshot was missing inline.
|
|
724
|
+
*
|
|
725
|
+
* Returns `null` for anything else: no details, a World that did not implement
|
|
726
|
+
* this, or a payload that does not narrow cleanly. Callers fall back to
|
|
727
|
+
* reloading the event log, which is always correct; this is untrusted-shaped
|
|
728
|
+
* data on a failure path, so nothing here is repaired.
|
|
729
|
+
*
|
|
730
|
+
* `runId` is the caller's run. Every event must belong to it: the delta is
|
|
731
|
+
* merged straight into the replay's log, and one foreign event there is a
|
|
732
|
+
* corrupt log rather than a corrected one: the replay would consume a
|
|
733
|
+
* correlation id for an event that does not exist on this run.
|
|
734
|
+
*/
|
|
735
|
+
export function preconditionEventDelta(error, runId) {
|
|
736
|
+
if (!PreconditionFailedError.is(error)) {
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
const details = error.details;
|
|
740
|
+
if (typeof details !== 'object' || details === null) {
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
const { events, cursor } = details;
|
|
744
|
+
if (!Array.isArray(events) || events.length === 0) {
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
747
|
+
for (const event of events) {
|
|
748
|
+
if (typeof event !== 'object' ||
|
|
749
|
+
event === null ||
|
|
750
|
+
typeof event.eventId !== 'string' ||
|
|
751
|
+
event.runId !== runId) {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
events: events,
|
|
757
|
+
cursor: typeof cursor === 'string' ? cursor : null,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
278
760
|
/**
|
|
279
761
|
* CORS headers for health check responses.
|
|
280
762
|
* Allows the observability UI to check endpoint health from a different origin.
|
|
@@ -316,6 +798,40 @@ export function withHealthCheck(handler, worldSpecVersion) {
|
|
|
316
798
|
return await handler(req);
|
|
317
799
|
};
|
|
318
800
|
}
|
|
801
|
+
/** FNV-1a 32-bit hash of a string, as 8 hex chars. Tiny, deterministic, and
|
|
802
|
+
* dependency-free. Used only to scope idempotency keys, not for security. */
|
|
803
|
+
function fnv1a32Hex(value) {
|
|
804
|
+
let hash = 0x811c9dc5;
|
|
805
|
+
for (let i = 0; i < value.length; i++) {
|
|
806
|
+
hash ^= value.charCodeAt(i);
|
|
807
|
+
hash = Math.imul(hash, 0x01000193);
|
|
808
|
+
}
|
|
809
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Idempotency key for a step's background-dispatch queue message, scoped to
|
|
813
|
+
* the step's IDENTITY, correlation id plus (hashed) step name, rather than
|
|
814
|
+
* the bare correlation id.
|
|
815
|
+
*
|
|
816
|
+
* The scoping matters for resilient step dispatch under the precondition
|
|
817
|
+
* guard: a guard-rejected `step_created` leaves its (revoked) step message in
|
|
818
|
+
* flight, and the corrected replay may re-derive the same correlation id for
|
|
819
|
+
* a DIFFERENT step. Under a bare-correlationId key the corrected replay's
|
|
820
|
+
* dispatch would silently dedupe against the revoked in-flight message,
|
|
821
|
+
* which then resolves `skipped` against the re-created entity (the server's
|
|
822
|
+
* stepName fence rejects its bare start), and the legitimate step would
|
|
823
|
+
* never be executed. Scoping by step name keeps every dedup property that
|
|
824
|
+
* matters (crash recovery re-dispatch, concurrent handlers, the delayed
|
|
825
|
+
* retry sharing the suspension re-dispatch's key: all name the same step)
|
|
826
|
+
* while letting the corrected schedule's dispatch through.
|
|
827
|
+
*
|
|
828
|
+
* Every producer of a step-dispatch (or step-retry) message must use this
|
|
829
|
+
* key. Cross-version mixing is not a concern: queue messages are pinned to
|
|
830
|
+
* the deployment that produced them, so one run never sees two key schemes.
|
|
831
|
+
*/
|
|
832
|
+
export function stepDispatchIdempotencyKey(correlationId, stepName) {
|
|
833
|
+
return `${correlationId}:${fnv1a32Hex(stepName)}`;
|
|
834
|
+
}
|
|
319
835
|
/**
|
|
320
836
|
* Queues a message to the specified queue with tracing.
|
|
321
837
|
*/
|
|
@@ -355,42 +871,28 @@ export function getQueueOverhead(message) {
|
|
|
355
871
|
}
|
|
356
872
|
}
|
|
357
873
|
/**
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* Errors thrown by `getEncryptionKeyForRun` propagate to every caller
|
|
373
|
-
* (the cached promise rejects). This is intentional: when encryption is
|
|
374
|
-
* configured, we never want to silently fall back to plaintext
|
|
375
|
-
* serialization. A propagated error in an event-emission path leaves the
|
|
376
|
-
* outer try/catch to log and surface the issue; the queue's redelivery
|
|
377
|
-
* semantics will retry the key fetch on the next attempt.
|
|
874
|
+
* Resolve the run's full payload-encryption capability. This includes the
|
|
875
|
+
* symmetric key and X25519 keypair needed to open cross-run sealed payloads.
|
|
876
|
+
* Missing world support or key material resolves to `undefined`; lookup and
|
|
877
|
+
* derivation failures propagate rather than silently falling back to plaintext.
|
|
878
|
+
*/
|
|
879
|
+
export async function resolveRunEncryptionKey(world, runOrId, context) {
|
|
880
|
+
const rawKey = typeof runOrId === 'string'
|
|
881
|
+
? await world.getEncryptionKeyForRun?.(runOrId, context)
|
|
882
|
+
: await world.getEncryptionKeyForRun?.(runOrId);
|
|
883
|
+
return rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Return a lazy, memoized accessor around {@link resolveRunEncryptionKey}.
|
|
887
|
+
* Concurrent callers share the same promise, including its rejection.
|
|
378
888
|
*/
|
|
379
889
|
export function memoizeEncryptionKey(world, runOrId) {
|
|
380
890
|
let cached;
|
|
381
891
|
return () => {
|
|
382
892
|
if (!cached) {
|
|
383
|
-
cached = (
|
|
384
|
-
// The `getEncryptionKeyForRun` overload set takes either a
|
|
385
|
-
// `WorkflowRun` or a `runId: string` (with optional context). Branch
|
|
386
|
-
// here so TypeScript picks the right overload for each shape.
|
|
387
|
-
const rawKey = typeof runOrId === 'string'
|
|
388
|
-
? await world.getEncryptionKeyForRun?.(runOrId)
|
|
389
|
-
: await world.getEncryptionKeyForRun?.(runOrId);
|
|
390
|
-
return rawKey ? await importKey(rawKey) : undefined;
|
|
391
|
-
})();
|
|
893
|
+
cached = resolveRunEncryptionKey(world, runOrId);
|
|
392
894
|
}
|
|
393
895
|
return cached;
|
|
394
896
|
};
|
|
395
897
|
}
|
|
396
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUNMLHdCQUF3QixFQUN4QixvQkFBb0IsRUFDcEIsbUJBQW1CLEdBQ3BCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXhDLE9BQU8sRUFBa0IsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbkQsd0RBQXdEO0FBQ3hELE1BQU0sNEJBQTRCLEdBQUcsTUFBTSxDQUFDO0FBRTVDOzs7O0dBSUc7QUFDSCxNQUFNLDBCQUEwQixHQUFHLHNCQUFzQixDQUFDO0FBRTFEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQUMsWUFBb0I7SUFDdkQsSUFBSSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1FBQ25ELE1BQU0sSUFBSSxLQUFLLENBQ2IsMEJBQTBCLFlBQVksd0dBQXdHLENBQy9JLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxrQkFBa0IsWUFBWSxFQUFvQixDQUFDO0FBQzVELENBQUM7QUFFRCxNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsRUFBRSxDQUFDO0FBRXRDOztHQUVHO0FBQ0gsU0FBUyx3QkFBd0IsQ0FBQyxhQUFxQjtJQUNyRCxPQUFPLG1C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VyxDQUFDLE9BQU8sRUFBRSxDQUMzQyxDQUFDO0lBQ0osQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU87SUFDVCxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLEtBQVksRUFDWixPQUE2QjtJQUU3QixJQUFJLE1BQWtELENBQUM7SUFDdkQsT0FBTyxHQUFHLEVBQUU7UUFDVixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDbkIsMkRBQTJEO2dCQUMzRCxxRUFBcUU7Z0JBQ3JFLDhEQUE4RDtnQkFDOUQsTUFBTSxNQUFNLEdBQ1YsT0FBTyxPQUFPLEtBQUssUUFBUTtvQkFDekIsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLHNCQUFzQixFQUFFLENBQUMsT0FBTyxDQUFDO29CQUMvQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDcEQsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDdEQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNQLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUge1xuICBFdmVudCxcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBWYWxpZFF1ZXVlTmFtZSxcbiAgV29ya2Zsb3dSdW4sXG4gIFdvcmxkLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHtcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkU2NoZW1hLFxuICBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgU1BFQ19WRVJTSU9OX0xFR0FDWSxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7IG1vbm90b25pY0ZhY3RvcnkgfSBmcm9tICd1bGlkJztcblxuaW1wb3J0IHsgdHlwZSBDcnlwdG9LZXksIGltcG9ydEtleSB9IGZyb20gJy4uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgKiBhcyBBdHRyaWJ1dGUgZnJvbSAnLi4vdGVsZW1ldHJ5L3NlbWFudGljLWNvbnZlbnRpb25zLmpzJztcbmltcG9ydCB7IGdldFNwYW5LaW5kLCB0cmFjZSB9IGZyb20gJy4uL3RlbGVtZXRyeS5qcyc7XG5pbXBvcnQgeyB2ZXJzaW9uIGFzIHdvcmtmbG93Q29yZVZlcnNpb24gfSBmcm9tICcuLi92ZXJzaW9uLmpzJztcbmltcG9ydCB7IGdldFdvcmxkTGF6eSB9IGZyb20gJy4vZ2V0LXdvcmxkLWxhenkuanMnO1xuXG4vKiogRGVmYXVsdCB0aW1lb3V0IGZvciBoZWFsdGggY2hlY2tzIGluIG1pbGxpc2Vjb25kcyAqL1xuY29uc3QgREVGQVVMVF9IRUFMVEhfQ0hFQ0tfVElNRU9VVCA9IDMwXzAwMDtcblxuLyoqXG4gKiBQYXR0ZXJuIGZvciBzYWZlIHdvcmtmbG93IG5hbWVzLiBPbmx5IGFsbG93cyBhbHBoYW51bWVyaWMgY2hhcmFjdGVycyxcbiAqIHVuZGVyc2NvcmVzLCBoeXBoZW5zLCBkb3RzLCBmb3J3YXJkIHNsYXNoZXMgKGZvciBuYW1lc3BhY2VkIHdvcmtmbG93cyksXG4gKiBhbmQgYXQgc2lnbnMgKGZvciBzY29wZWQgcGFja2FnZXMpLlxuICovXG5jb25zdCBTQUZFX1dPUktGTE9XX05BTUVfUEFUVEVSTiA9IC9eW2EtekEtWjAtOV9cXC0uL0BdKyQvO1xuXG4vKipcbiAqIFZhbGlkYXRlcyBhIHdvcmtmbG93IG5hbWUgYW5kIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgcXVldWUgbmFtZS5cbiAqIEVuc3VyZXMgdGhlIHdvcmtmbG93IG5hbWUgb25seSBjb250YWlucyBzYWZlIGNoYXJhY3RlcnMgYmVmb3JlXG4gKiBpbnRlcnBvbGF0aW5nIGl0IGludG8gdGhlIHF1ZXVlIG5hbWUgc3RyaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dOYW1lOiBzdHJpbmcpOiBWYWxpZFF1ZXVlTmFtZSB7XG4gIGlmICghU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4udGVzdCh3b3JrZmxvd05hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEludmFsaWQgd29ya2Zsb3cgbmFtZSBcIiR7d29ya2Zsb3dOYW1lfVwiOiBtdXN0IG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgdW5kZXJzY29yZXMsIGh5cGhlbnMsIGRvdHMsIGZvcndhcmQgc2xhc2hlcywgb3IgYXQgc2lnbnNgXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYF9fd2tmX3dvcmtmbG93XyR7d29ya2Zsb3dOYW1lfWAgYXMgVmFsaWRRdWV1ZU5hbWU7XG59XG5cbmNvbnN0IGdlbmVyYXRlSWQgPSBtb25vdG9uaWNGYWN0b3J5KCk7XG5cbi8qKlxuICogUmV0dXJucyB0aGUgc3RyZWFtIG5hbWUgZm9yIGEgaGVhbHRoIGNoZWNrIHdpdGggdGhlIGdpdmVuIGNvcnJlbGF0aW9uIElELlxuICovXG5mdW5jdGlvbiBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBfX2hlYWx0aF9jaGVja19fJHtjb3JyZWxhdGlvbklkfWA7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGEgaGVhbHRoIGNoZWNrIG9wZXJhdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhDaGVja1Jlc3VsdCB7XG4gIGhlYWx0aHk6IGJvb2xlYW47XG4gIC8qKiBFcnJvciBtZXNzYWdlIGlmIGhlYWx0aCBjaGVjayBmYWlsZWQgKi9cbiAgZXJyb3I/OiBzdHJpbmc7XG4gIC8qKiBMYXRlbmN5IGlmIHRoZSBoZWFsdGggY2hlY2sgd2FzIHN1Y2Nlc3NmdWwgKi9cbiAgbGF0ZW5jeU1zPzogbnVtYmVyO1xuICAvKiogU3BlYyB2ZXJzaW9uIG9mIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQgKi9cbiAgc3BlY1ZlcnNpb24/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBtZXNzYWdlIGlzIGEgaGVhbHRoIGNoZWNrIHBheWxvYWQuXG4gKiBJZiBzbywgcmV0dXJucyB0aGUgcGFyc2VkIHBheWxvYWQuIE90aGVyd2lzZSByZXR1cm5zIHVuZGVmaW5lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tQYXlsb2FkKFxuICBtZXNzYWdlOiB1bmtub3duXG4pOiBIZWFsdGhDaGVja1BheWxvYWQgfCB1bmRlZmluZWQge1xuICBjb25zdCByZXN1bHQgPSBIZWFsdGhDaGVja1BheWxvYWRTY2hlbWEuc2FmZVBhcnNlKG1lc3NhZ2UpO1xuICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4gcmVzdWx0LmRhdGE7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBkZXRlcm1pbmlzdGljIGZha2UgcnVuSWQgZm9yIGhlYWx0aCBjaGVjayBzdHJlYW1zLlxuICogQm90aCB0aGUgd3JpdGVyIChoYW5kbGVIZWFsdGhDaGVja01lc3NhZ2UpIGFuZCByZWFkZXIgKGhlYWx0aENoZWNrKSBkZXJpdmVcbiAqIHRoZSBzYW1lIHJ1bklkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdCBpbXBsZW1lbnRhdGlvbnMgdGhhdCBzY29wZVxuICogc3RyZWFtIHJlYWRzIGJ5IHJ1bklkIHN0aWxsIHdvcmsgY29ycmVjdGx5LlxuICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhlYWx0aENoZWNrUnVuSWQoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGB3cnVuX2hjXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIEhhbmRsZXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZSBieSB3cml0aW5nIHRoZSByZXN1bHQgdG8gdGhlIHdvcmxkJ3Mgc3RyZWFtLlxuICogVGhlIGNhbGxlciBjYW4gbGlzdGVuIHRvIHRoaXMgc3RyZWFtIHRvIGdldCB0aGUgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSBoZWFsdGhDaGVjayAtIFRoZSBwYXJzZWQgaGVhbHRoIGNoZWNrIHBheWxvYWRcbiAqIEBwYXJhbSBlbmRwb2ludCAtIFdoaWNoIGVuZHBvaW50IGlzIHJlc3BvbmRpbmcgKCd3b3JrZmxvdycgb3IgJ3N0ZXAnKVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlSGVhbHRoQ2hlY2tNZXNzYWdlKFxuICBoZWFsdGhDaGVjazogSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBlbmRwb2ludDogJ3dvcmtmbG93JyB8ICdzdGVwJyxcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCk7XG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIGhlYWx0aHk6IHRydWUsXG4gICAgZW5kcG9pbnQsXG4gICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgfSk7XG4gIC8vIFVzZSBhIGRldGVybWluaXN0aWMgZmFrZSBydW5JZCBkZXJpdmVkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdFxuICAvLyB0aGUgcmVhZGVyIHNpZGUgcHJvZHVjZXMgdGhlIHNhbWUgdmFsdWUuXG4gIGNvbnN0IGZha2VSdW5JZCA9IGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChoZWFsdGhDaGVjay5jb3JyZWxhdGlvbklkKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUsIHJlc3BvbnNlKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUpO1xufVxuXG5leHBvcnQgdHlwZSBIZWFsdGhDaGVja0VuZHBvaW50ID0gJ3dvcmtmbG93JyB8ICdzdGVwJztcblxuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhDaGVja09wdGlvbnMge1xuICAvKiogVGltZW91dCBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLiBEZWZhdWx0OiAzMDAwMCAoMzBzKSAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xuICAvKiogRGVwbG95bWVudCBJRCB0byBzZW5kIHRoZSBoZWFsdGggY2hlY2sgdG8uIEZhbGxzIGJhY2sgdG8gcHJvY2Vzcy5lbnYuVkVSQ0VMX0RFUExPWU1FTlRfSUQuICovXG4gIGRlcGxveW1lbnRJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQZXJmb3JtcyBhIGhlYWx0aCBjaGVjayBieSBzZW5kaW5nIGEgbWVzc2FnZSB0aHJvdWdoIHRoZSBxdWV1ZSBwaXBlbGluZVxuICogYW5kIHZlcmlmeWluZyBpdCBpcyBwcm9jZXNzZWQgYnkgdGhlIHNwZWNpZmllZCBlbmRwb2ludC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGJ5cGFzc2VzIERlcGxveW1lbnQgUHJvdGVjdGlvbiBvbiBWZXJjZWwgYmVjYXVzZSBpdCBnb2VzXG4gKiB0aHJvdWdoIHRoZSBxdWV1ZSBpbmZyYXN0cnVjdHVyZSByYXRoZXIgdGhhbiBkaXJlY3QgSFRUUC5cbiAqXG4gKiBAcGFyYW0gd29ybGQgLSBUaGUgV29ybGQgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcGFyYW0gZW5kcG9pbnQgLSBXaGljaCBlbmRwb2ludCB0byBoZWFsdGggY2hlY2s6ICd3b3JrZmxvdycgb3IgJ3N0ZXAnXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBoZWFsdGggY2hlY2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIGhlYWx0aCBjaGVjayByZXN1bHRcbiAqL1xuLy8gUG9sbCBpbnRlcnZhbCBmb3IgaGVhbHRoIGNoZWNrIHJldHJpZXMgKG1zKVxuY29uc3QgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwgPSAxMDA7XG4vLyBQZXItcmVhZCB0aW1lb3V0IHRvIHByZXZlbnQgYmxvY2tpbmcgZm9yZXZlciBvbiBsb2NhbCB3b3JsZCdzIEV2ZW50RW1pdHRlclxuLy8gKHdoaWNoIGRvZXNuJ3Qgd29yayBhY3Jvc3MgcHJvY2Vzc2VzKVxuY29uc3QgSEVBTFRIX0NIRUNLX1JFQURfVElNRU9VVCA9IDUwMDtcblxuLyoqXG4gKiBSZWFkIGNodW5rcyBmcm9tIGEgc3RyZWFtIHdpdGggYSB0aW1lb3V0IHBlciByZWFkIG9wZXJhdGlvbi5cbiAqIFJldHVybnMgeyBjaHVua3MsIHRpbWVkT3V0IH0gd2hlcmUgdGltZWRPdXQgaW5kaWNhdGVzIGlmIGEgcmVhZCB0aW1lZCBvdXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlYWRTdHJlYW1XaXRoVGltZW91dChcbiAgcmVhZGVyOiBSZWFkYWJsZVN0cmVhbURlZmF1bHRSZWFkZXI8VWludDhBcnJheT4sXG4gIHJlYWRUaW1lb3V0OiBudW1iZXJcbik6IFByb21pc2U8eyBjaHVua3M6IFVpbnQ4QXJyYXlbXTsgdGltZWRPdXQ6IGJvb2xlYW4gfT4ge1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICBsZXQgZG9uZSA9IGZhbHNlO1xuICBsZXQgdGltZWRPdXQgPSBmYWxzZTtcblxuICB3aGlsZSAoIWRvbmUgJiYgIXRpbWVkT3V0KSB7XG4gICAgY29uc3QgcmVhZFByb21pc2UgPSByZWFkZXIucmVhZCgpO1xuICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2U8eyBkb25lOiB0cnVlOyB2YWx1ZTogdW5kZWZpbmVkIH0+KFxuICAgICAgKHJlc29sdmUpID0+XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHRpbWVkT3V0ID0gdHJ1ZTtcbiAgICAgICAgICByZXNvbHZlKHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgfSwgcmVhZFRpbWVvdXQpXG4gICAgKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UucmFjZShbcmVhZFByb21pc2UsIHRpbWVvdXRQcm9taXNlXSk7XG4gICAgZG9uZSA9IHJlc3VsdC5kb25lO1xuICAgIGlmIChyZXN1bHQudmFsdWUpIGNodW5rcy5wdXNoKHJlc3VsdC52YWx1ZSk7XG4gIH1cblxuICByZXR1cm4geyBjaHVua3MsIHRpbWVkT3V0IH07XG59XG5cbi8qKlxuICogUGFyc2UgYW5kIHZhbGlkYXRlIGEgaGVhbHRoIGNoZWNrIHJlc3BvbnNlIGZyb20gc3RyZWFtIGNodW5rcy5cbiAqIFJldHVybnMgdGhlIHBhcnNlZCByZXNwb25zZSBvciBudWxsIGlmIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShcbiAgY2h1bmtzOiBVaW50OEFycmF5W11cbik6IHsgaGVhbHRoeTogYm9vbGVhbiB9IHwgbnVsbCB7XG4gIGlmIChjaHVua3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcblxuICBjb25zdCB0b3RhbExlbmd0aCA9IGNodW5rcy5yZWR1Y2UoKHN1bSwgY2h1bmspID0+IHN1bSArIGNodW5rLmxlbmd0aCwgMCk7XG4gIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkodG90YWxMZW5ndGgpO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3MpIHtcbiAgICBjb21iaW5lZC5zZXQoY2h1bmssIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IGNodW5rLmxlbmd0aDtcbiAgfVxuICBjb25zdCByZXNwb25zZVRleHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoY29tYmluZWQpO1xuXG4gIGxldCByZXNwb25zZTogdW5rbm93bjtcbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IEpTT04ucGFyc2UocmVzcG9uc2VUZXh0KTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gT2xkIGRlcGxveW1lbnRzIChzcGVjVmVyc2lvbiA8IDMpIHJldHVybiBwbGFpbiB0ZXh0IGxpa2VcbiAgICAvLyAnV29ya2Zsb3cgU0RLIFwiLi4uXCIgZW5kcG9pbnQgaXMgaGVhbHRoeScuIFRyZWF0IGFueSBub24tZW1wdHlcbiAgICAvLyB0ZXh0IHJlc3BvbnNlIGFzIGEgaGVhbHRoeSBkZXBsb3ltZW50IHdpdGggdW5rbm93biBzcGVjVmVyc2lvbi5cbiAgICBpZiAocmVzcG9uc2VUZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoXG4gICAgdHlwZW9mIHJlc3BvbnNlICE9PSAnb2JqZWN0JyB8fFxuICAgIHJlc3BvbnNlID09PSBudWxsIHx8XG4gICAgISgnaGVhbHRoeScgaW4gcmVzcG9uc2UpIHx8XG4gICAgdHlwZW9mIChyZXNwb25zZSBhcyB7IGhlYWx0aHk6IHVua25vd24gfSkuaGVhbHRoeSAhPT0gJ2Jvb2xlYW4nXG4gICkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgciA9IHJlc3BvbnNlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBwYXJzZWQ6IHsgaGVhbHRoeTogYm9vbGVhbjsgc3BlY1ZlcnNpb24/OiBudW1iZXIgfSA9IHtcbiAgICBoZWFsdGh5OiByLmhlYWx0aHkgYXMgYm9vbGVhbixcbiAgfTtcbiAgaWYgKHR5cGVvZiByLnNwZWNWZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgIHBhcnNlZC5zcGVjVmVyc2lvbiA9IHIuc3BlY1ZlcnNpb247XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhlYWx0aENoZWNrKFxuICB3b3JsZDogV29ybGQsXG4gIGVuZHBvaW50OiBIZWFsdGhDaGVja0VuZHBvaW50LFxuICBvcHRpb25zPzogSGVhbHRoQ2hlY2tPcHRpb25zXG4pOiBQcm9taXNlPEhlYWx0aENoZWNrUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zPy50aW1lb3V0ID8/IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQ7XG4gIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBnZW5lcmF0ZUlkKCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoY29ycmVsYXRpb25JZCk7XG5cbiAgY29uc3QgcXVldWVOYW1lOiBWYWxpZFF1ZXVlTmFtZSA9XG4gICAgZW5kcG9pbnQgPT09ICd3b3JrZmxvdydcbiAgICAgID8gJ19fd2tmX3dvcmtmbG93X2hlYWx0aF9jaGVjaydcbiAgICAgIDogJ19fd2tmX3N0ZXBfaGVhbHRoX2NoZWNrJztcblxuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd29ybGQucXVldWUoXG4gICAgICBxdWV1ZU5hbWUsXG4gICAgICB7IF9faGVhbHRoQ2hlY2s6IHRydWUsIGNvcnJlbGF0aW9uSWQgfSxcbiAgICAgIHtcbiAgICAgICAgLy8gVXNlIEpTT04gdHJhbnNwb3J0IHNvIHRoZSBoZWFsdGggY2hlY2sgd29ya3MgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9sZCAoSlNPTi1vbmx5KSBhbmQgbmV3IChkdWFsKSBkZXBsb3ltZW50cy5cbiAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gICAgICAgIGRlcGxveW1lbnRJZDogb3B0aW9ucz8uZGVwbG95bWVudElkLFxuICAgICAgfVxuICAgICk7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA8IHRpbWVvdXQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IHdvcmxkLnN0cmVhbXMuZ2V0KFxuICAgICAgICAgIGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChjb3JyZWxhdGlvbklkKSxcbiAgICAgICAgICBzdHJlYW1OYW1lXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHN0cmVhbS5nZXRSZWFkZXIoKTtcbiAgICAgICAgY29uc3QgeyBjaHVua3MsIHRpbWVkT3V0IH0gPSBhd2FpdCByZWFkU3RyZWFtV2l0aFRpbWVvdXQoXG4gICAgICAgICAgcmVhZGVyLFxuICAgICAgICAgIEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVRcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGltZWRPdXQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVhZGVyLmNhbmNlbCgpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSWdub3JlIGNhbmNlbCBlcnJvcnNcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3MpO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4ucmVzcG9uc2UsXG4gICAgICAgICAgICBsYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydFRpbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBIZWFsdGggY2hlY2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tc2AsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhbHRoeTogZmFsc2UsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBMb2FkcyB3b3JrZmxvdyBydW4gZXZlbnRzIGJ5IGl0ZXJhdGluZyB0aHJvdWdoIGFsbCBwYWdlcyBvZiBwYWdpbmF0ZWRcbiAqIHJlc3VsdHMuIEV2ZW50cyBhcmUgcmV0dXJuZWQgaW4gY2hyb25vbG9naWNhbCAoYXNjZW5kaW5nKSBvcmRlciBmb3JcbiAqIGRldGVybWluaXN0aWMgd29ya2Zsb3cgcmVwbGF5LlxuICpcbiAqIEBwYXJhbSBydW5JZCAtIFRoZSB3b3JrZmxvdyBydW4gSUQuXG4gKiBAcGFyYW0gYWZ0ZXJDdXJzb3IgLSBJZiBwcm92aWRlZCwgb25seSBldmVudHMgYWZ0ZXIgdGhpcyBjdXJzb3IgYXJlXG4gKiAgIHJldHVybmVkIChpbmNyZW1lbnRhbCBsb2FkKS4gSWYgb21pdHRlZCwgYWxsIGV2ZW50cyBhcmUgcmV0dXJuZWQuXG4gKiAgIFRoZSByZXR1cm5lZCBjdXJzb3IgY2FuIGJlIHBhc3NlZCBiYWNrIGluIG9uIGEgc3Vic2VxdWVudCBjYWxsIGZvclxuICogICBpbmNyZW1lbnRhbCBsb2FkaW5nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZFdvcmtmbG93UnVuRXZlbnRzKFxuICBydW5JZDogc3RyaW5nLFxuICBhZnRlckN1cnNvcj86IHN0cmluZ1xuKTogUHJvbWlzZTx7IGV2ZW50czogRXZlbnRbXTsgY3Vyc29yOiBzdHJpbmcgfCBudWxsIH0+IHtcbiAgY29uc3QgaW5jcmVtZW50YWwgPSBhZnRlckN1cnNvciAhPT0gdW5kZWZpbmVkO1xuICByZXR1cm4gdHJhY2UoXG4gICAgaW5jcmVtZW50YWwgPyAnd29ya2Zsb3cubG9hZE5ld0V2ZW50cycgOiAnd29ya2Zsb3cubG9hZEV2ZW50cycsXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5JZChydW5JZCksXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbG9hZGVkRXZlbnRzOiBFdmVudFtdID0gW107XG4gICAgICBsZXQgY3Vyc29yOiBzdHJpbmcgfCBudWxsID0gYWZ0ZXJDdXJzb3IgPz8gbnVsbDtcbiAgICAgIGxldCBoYXNNb3JlID0gdHJ1ZTtcbiAgICAgIGxldCBwYWdlc0xvYWRlZCA9IDA7XG5cbiAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gICAgICBjb25zdCBsb2FkU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgd2hpbGUgKGhhc01vcmUpIHtcbiAgICAgICAgLy8gVE9ETzogd2UncmUgY3VycmVudGx5IGxvYWRpbmcgYWxsIHRoZSBkYXRhIHdpdGggcmVzb2x2ZVJlZiBiZWhhdmlvdXIuIFdlIG5lZWQgdG8gdXBkYXRlIHRoaXNcbiAgICAgICAgLy8gdG8gbGF6eWxvYWQgdGhlIGRhdGEgZnJvbSB0aGUgd29ybGQgaW5zdGVhZCBzbyB0aGF0IHdlIGNhbiBvcHRpbWl6ZSBhbmQgbWFrZSB0aGUgZXZlbnQgbG9nIGxvYWRpbmdcbiAgICAgICAgLy8gbXVjaCBmYXN0ZXIgYW5kIG1lbW9yeSBlZmZpY2llbnRcbiAgICAgICAgY29uc3QgcGFnZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB3b3JsZC5ldmVudHMubGlzdCh7XG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgICAgc29ydE9yZGVyOiAnYXNjJyxcbiAgICAgICAgICAgIGN1cnNvcjogY3Vyc29yID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBsb2FkZWRFdmVudHMucHVzaCguLi5yZXNwb25zZS5kYXRhKTtcbiAgICAgICAgaGFzTW9yZSA9IHJlc3BvbnNlLmhhc01vcmU7XG4gICAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvcjtcbiAgICAgICAgcGFnZXNMb2FkZWQrKztcblxuICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdMb2FkZWQgZXZlbnQgcGFnZScsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICBpbmNyZW1lbnRhbCxcbiAgICAgICAgICBwYWdlOiBwYWdlc0xvYWRlZCxcbiAgICAgICAgICBwYWdlRXZlbnRzOiByZXNwb25zZS5kYXRhLmxlbmd0aCxcbiAgICAgICAgICB0b3RhbEV2ZW50czogbG9hZGVkRXZlbnRzLmxlbmd0aCxcbiAgICAgICAgICBoYXNNb3JlLFxuICAgICAgICAgIHBhZ2VNczogRGF0ZS5ub3coKSAtIHBhZ2VTdGFydCxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ0V2ZW50IGxvYWQgY29tcGxldGUnLCB7XG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICBpbmNyZW1lbnRhbCxcbiAgICAgICAgdG90YWxFdmVudHM6IGxvYWRlZEV2ZW50cy5sZW5ndGgsXG4gICAgICAgIHBhZ2VzTG9hZGVkLFxuICAgICAgICB0b3RhbE1zOiBEYXRlLm5vdygpIC0gbG9hZFN0YXJ0LFxuICAgICAgfSk7XG5cbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFdmVudHNDb3VudChsb2FkZWRFdmVudHMubGVuZ3RoKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXZlbnRzUGFnZXNMb2FkZWQocGFnZXNMb2FkZWQpLFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB7IGV2ZW50czogbG9hZGVkRXZlbnRzLCBjdXJzb3IgfTtcbiAgICB9XG4gICk7XG59XG5cbi8qKlxuICogQ09SUyBoZWFkZXJzIGZvciBoZWFsdGggY2hlY2sgcmVzcG9uc2VzLlxuICogQWxsb3dzIHRoZSBvYnNlcnZhYmlsaXR5IFVJIHRvIGNoZWNrIGVuZHBvaW50IGhlYWx0aCBmcm9tIGEgZGlmZmVyZW50IG9yaWdpbi5cbiAqL1xuY29uc3QgSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyA9IHtcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnOiAnUE9TVCwgT1BUSU9OUywgR0VULCBIRUFEJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOiAnQ29udGVudC1UeXBlJyxcbn07XG5cbi8qKlxuICogV3JhcHMgYSByZXF1ZXN0L3Jlc3BvbnNlIGhhbmRsZXIgYW5kIGFkZHMgYSBoZWFsdGggY2hlY2sgXCJtb2RlXCJcbiAqIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhIGBfX2hlYWx0aGAgcXVlcnkgcGFyYW1ldGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEhlYWx0aENoZWNrKFxuICBoYW5kbGVyOiAocmVxOiBSZXF1ZXN0KSA9PiBQcm9taXNlPFJlc3BvbnNlPixcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4ge1xuICByZXR1cm4gYXN5bmMgKHJlcTogUmVxdWVzdCkgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCk7XG4gICAgY29uc3QgaXNIZWFsdGhDaGVjayA9IHVybC5zZWFyY2hQYXJhbXMuaGFzKCdfX2hlYWx0aCcpO1xuICAgIGlmIChpc0hlYWx0aENoZWNrKSB7XG4gICAgICAvLyBIYW5kbGUgQ09SUyBwcmVmbGlnaHQgZm9yIGhlYWx0aCBjaGVja1xuICAgICAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKG51bGwsIHtcbiAgICAgICAgICBzdGF0dXM6IDIwNCxcbiAgICAgICAgICBoZWFkZXJzOiBIRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBoZWFsdGh5OiB0cnVlLFxuICAgICAgICAgIGVuZHBvaW50OiB1cmwucGF0aG5hbWUsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IHdvcmxkU3BlY1ZlcnNpb24gPz8gU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgd29ya2Zsb3dDb3JlVmVyc2lvbixcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBzdGF0dXM6IDIwMCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgLi4uSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyxcbiAgICAgICAgICB9LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgaGFuZGxlcihyZXEpO1xuICB9O1xufVxuXG4vKipcbiAqIFF1ZXVlcyBhIG1lc3NhZ2UgdG8gdGhlIHNwZWNpZmllZCBxdWV1ZSB3aXRoIHRyYWNpbmcuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBxdWV1ZU1lc3NhZ2UoXG4gIHdvcmxkOiBXb3JsZCxcbiAgLi4uYXJnczogUGFyYW1ldGVyczx0eXBlb2Ygd29ybGQucXVldWU+XG4pIHtcbiAgY29uc3QgcXVldWVOYW1lID0gYXJnc1swXTtcbiAgYXdhaXQgdHJhY2UoXG4gICAgJ3F1ZXVlLnB1Ymxpc2gnLFxuICAgIHtcbiAgICAgIC8vIFN0YW5kYXJkIE9URUwgbWVzc2FnaW5nIGNvbnZlbnRpb25zXG4gICAgICBhdHRyaWJ1dGVzOiB7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdTeXN0ZW0oJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nRGVzdGluYXRpb25OYW1lKHF1ZXVlTmFtZSksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdPcGVyYXRpb25UeXBlKCdwdWJsaXNoJyksXG4gICAgICAgIC8vIFBlZXIgc2VydmljZSBmb3IgRGF0YWRvZyBzZXJ2aWNlIG1hcHNcbiAgICAgICAgLi4uQXR0cmlidXRlLlBlZXJTZXJ2aWNlKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5ScGNTZXJ2aWNlKCd2cXMnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY01ldGhvZCgncHVibGlzaCcpLFxuICAgICAgfSxcbiAgICAgIGtpbmQ6IGF3YWl0IGdldFNwYW5LaW5kKCdQUk9EVUNFUicpLFxuICAgIH0sXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIGNvbnN0IHsgbWVzc2FnZUlkIH0gPSBhd2FpdCB3b3JsZC5xdWV1ZSguLi5hcmdzKTtcbiAgICAgIGlmIChtZXNzYWdlSWQpIHtcbiAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyhBdHRyaWJ1dGUuTWVzc2FnaW5nTWVzc2FnZUlkKG1lc3NhZ2VJZCkpO1xuICAgICAgfVxuICAgIH1cbiAgKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBxdWV1ZSBvdmVyaGVhZCB0aW1lIGluIG1pbGxpc2Vjb25kcyBmb3IgYSBnaXZlbiBtZXNzYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVldWVPdmVyaGVhZChtZXNzYWdlOiB7IHJlcXVlc3RlZEF0PzogRGF0ZSB9KSB7XG4gIGlmICghbWVzc2FnZS5yZXF1ZXN0ZWRBdCkgcmV0dXJuO1xuICB0cnkge1xuICAgIHJldHVybiBBdHRyaWJ1dGUuUXVldWVPdmVyaGVhZE1zKFxuICAgICAgRGF0ZS5ub3coKSAtIG1lc3NhZ2UucmVxdWVzdGVkQXQuZ2V0VGltZSgpXG4gICAgKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyBhIG1lbW9pemVkIGFjY2Vzc29yIGZvciB0aGUgcGVyLXJ1biBBRVMtMjU2IGVuY3J5cHRpb24ga2V5LlxuICpcbiAqIFRoZSBmaXJzdCBjYWxsIHJlc29sdmVzIHRoZSBrZXkgdmlhIGB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuYCAod2hpY2hcbiAqIG1heSBkbyBIS0RGIGRlcml2YXRpb24gbG9jYWxseSBvbiBWZXJjZWwsIG9yIGEgbmV0d29yayBmZXRjaCBmcm9tXG4gKiBleHRlcm5hbCBjb250ZXh0cykgYW5kIGltcG9ydHMgaXQgYXMgYSBgQ3J5cHRvS2V5YDsgc3Vic2VxdWVudCBjYWxsc1xuICogYXdhaXQgdGhlIHNhbWUgY2FjaGVkIHByb21pc2UuIElmIHRoZSB3b3JsZCBkb2Vzbid0IHN1cHBvcnQgZW5jcnlwdGlvblxuICogb3IgdGhlIHJ1biBoYXMgbm8ga2V5IGNvbmZpZ3VyZWQsIHRoZSBjYWNoZWQgdmFsdWUgaXMgYHVuZGVmaW5lZGAuXG4gKlxuICogVXNlZCBieSBzdGVwIC8gd29ya2Zsb3cgaGFuZGxlcnMgdG8gZGVmZXIgdGhlIChwb3RlbnRpYWxseSBleHBlbnNpdmUpXG4gKiBrZXkgZmV0Y2ggdW50aWwgdGhlIGZpcnN0IGNvZGUgcGF0aCB0aGF0IGFjdHVhbGx5IG5lZWRzIGl0IOKAlCB0eXBpY2FsbHlcbiAqIGlucHV0IGh5ZHJhdGlvbiBvbiB0aGUgc3VjY2VzcyBwYXRoLCBvciBlcnJvciBkZWh5ZHJhdGlvbiBvbiBhIGZhaWx1cmVcbiAqIHBhdGguIEJvdGggcGF0aHMgY2FuIHJhY2UtY2FsbCB0aGUgYWNjZXNzb3Igd2l0aG91dCB0cmlnZ2VyaW5nIGR1cGxpY2F0ZVxuICogZmV0Y2hlcy5cbiAqXG4gKiBFcnJvcnMgdGhyb3duIGJ5IGBnZXRFbmNyeXB0aW9uS2V5Rm9yUnVuYCBwcm9wYWdhdGUgdG8gZXZlcnkgY2FsbGVyXG4gKiAodGhlIGNhY2hlZCBwcm9taXNlIHJlamVjdHMpLiBUaGlzIGlzIGludGVudGlvbmFsOiB3aGVuIGVuY3J5cHRpb24gaXNcbiAqIGNvbmZpZ3VyZWQsIHdlIG5ldmVyIHdhbnQgdG8gc2lsZW50bHkgZmFsbCBiYWNrIHRvIHBsYWludGV4dFxuICogc2VyaWFsaXphdGlvbi4gQSBwcm9wYWdhdGVkIGVycm9yIGluIGFuIGV2ZW50LWVtaXNzaW9uIHBhdGggbGVhdmVzIHRoZVxuICogb3V0ZXIgdHJ5L2NhdGNoIHRvIGxvZyBhbmQgc3VyZmFjZSB0aGUgaXNzdWU7IHRoZSBxdWV1ZSdzIHJlZGVsaXZlcnlcbiAqIHNlbWFudGljcyB3aWxsIHJldHJ5IHRoZSBrZXkgZmV0Y2ggb24gdGhlIG5leHQgYXR0ZW1wdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lbW9pemVFbmNyeXB0aW9uS2V5KFxuICB3b3JsZDogV29ybGQsXG4gIHJ1bk9ySWQ6IFdvcmtmbG93UnVuIHwgc3RyaW5nXG4pOiAoKSA9PiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4ge1xuICBsZXQgY2FjaGVkOiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgaWYgKCFjYWNoZWQpIHtcbiAgICAgIGNhY2hlZCA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIC8vIFRoZSBgZ2V0RW5jcnlwdGlvbktleUZvclJ1bmAgb3ZlcmxvYWQgc2V0IHRha2VzIGVpdGhlciBhXG4gICAgICAgIC8vIGBXb3JrZmxvd1J1bmAgb3IgYSBgcnVuSWQ6IHN0cmluZ2AgKHdpdGggb3B0aW9uYWwgY29udGV4dCkuIEJyYW5jaFxuICAgICAgICAvLyBoZXJlIHNvIFR5cGVTY3JpcHQgcGlja3MgdGhlIHJpZ2h0IG92ZXJsb2FkIGZvciBlYWNoIHNoYXBlLlxuICAgICAgICBjb25zdCByYXdLZXkgPVxuICAgICAgICAgIHR5cGVvZiBydW5PcklkID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4ocnVuT3JJZClcbiAgICAgICAgICAgIDogYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJ1bk9ySWQpO1xuICAgICAgICByZXR1cm4gcmF3S2V5ID8gYXdhaXQgaW1wb3J0S2V5KHJhd0tleSkgOiB1bmRlZmluZWQ7XG4gICAgICB9KSgpO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGVkO1xuICB9O1xufVxuIl19
|
|
898
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixlQUFlLEVBQ2Ysa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFXMUIsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixtQkFBbUIsRUFDbkIsd0JBQXdCLEVBQ3hCLHlCQUF5QixFQUN6QixnQkFBZ0IsRUFDaEIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixtQkFBbUIsR0FDcEIsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbkUsT0FBTyxFQUNMLG9CQUFvQixHQUVyQixNQUFNLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxTQUFTLE1BQU0sc0NBQXNDLENBQUM7QUFDbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsT0FBTyxJQUFJLG1CQUFtQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVuRCx3REFBd0Q7QUFDeEQsTUFBTSw0QkFBNEIsR0FBRyxNQUFNLENBQUM7QUFFNUM7Ozs7R0FJRztBQUNILE1BQU0sMEJBQTBCLEdBQUcsc0JBQXNCLENBQUM7QUFFMUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FDbEMsWUFBb0IsRUFDcEIsU0FBa0I7SUFFbEIsSUFBSSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxD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RUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLHVCQUF1QixDQUMzQyxLQUFZLEVBQ1osT0FBNkIsRUFDN0IsT0FBaUM7SUFFakMsTUFBTSxNQUFNLEdBQ1YsT0FBTyxPQUFPLEtBQUssUUFBUTtRQUN6QixDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDO1FBQ3hELENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3BELE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDakUsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FDbEMsS0FBWSxFQUNaLE9BQTZCO0lBRTdCLElBQUksTUFBbUQsQ0FBQztJQUN4RCxPQUFPLEdBQUcsRUFBRTtRQUNWLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sR0FBRyx1QkFBdUIsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBQcmVjb25kaXRpb25GYWlsZWRFcnJvcixcbiAgUlVOX0VSUk9SX0NPREVTLFxuICBXb3JrZmxvd1dvcmxkRXJyb3IsXG59IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHR5cGUge1xuICBDcmVhdGVFdmVudFBhcmFtcyxcbiAgQ3JlYXRlRXZlbnRSZXF1ZXN0LFxuICBFdmVudCxcbiAgRXZlbnRSZXN1bHQsXG4gIEhlYWx0aENoZWNrUGF5bG9hZCxcbiAgVmFsaWRRdWV1ZU5hbWUsXG4gIFdvcmtmbG93UnVuLFxuICBXb3JsZCxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7XG4gIEZJUlNUX0VWRU5UX1NMT1QsXG4gIGdldFF1ZXVlVG9waWNQcmVmaXgsXG4gIEhlYWx0aENoZWNrUGF5bG9hZFNjaGVtYSxcbiAgSE9PS19SRVNVTUVfSU5QVVRfVkVSU0lPTixcbiAgcmVxdWlyZUV2ZW50U2xvdCxcbiAgcmVzb2x2ZVF1ZXVlTmFtZXNwYWNlLFxuICBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgU1BFQ19WRVJTSU9OX0xFR0FDWSxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7IG1vbm90b25pY0ZhY3RvcnkgfSBmcm9tICd1bGlkJztcbmltcG9ydCB7IHJ1bnRpbWVMb2dnZXIgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgYnl0ZXNUb0Jhc2U2NCwgZGVyaXZlUnVuS2V5UGFpciB9IGZyb20gJy4uL3NlYWxlZC1ib3guanMnO1xuaW1wb3J0IHtcbiAgZGVyaXZlUnVuUGF5bG9hZEtleXMsXG4gIHR5cGUgUGF5bG9hZEtleSxcbn0gZnJvbSAnLi4vc2VyaWFsaXphdGlvbi9lbmNyeXB0aW9uLmpzJztcbmltcG9ydCAqIGFzIEF0dHJpYnV0ZSBmcm9tICcuLi90ZWxlbWV0cnkvc2VtYW50aWMtY29udmVudGlvbnMuanMnO1xuaW1wb3J0IHsgZ2V0U3BhbktpbmQsIHRyYWNlIH0gZnJvbSAnLi4vdGVsZW1ldHJ5LmpzJztcbmltcG9ydCB7IHZlcnNpb24gYXMgd29ya2Zsb3dDb3JlVmVyc2lvbiB9IGZyb20gJy4uL3ZlcnNpb24uanMnO1xuaW1wb3J0IHsgZ2V0V29ybGRMYXp5IH0gZnJvbSAnLi9nZXQtd29ybGQtbGF6eS5qcyc7XG5cbi8qKiBEZWZhdWx0IHRpbWVvdXQgZm9yIGhlYWx0aCBjaGVja3MgaW4gbWlsbGlzZWNvbmRzICovXG5jb25zdCBERUZBVUxUX0hFQUxUSF9DSEVDS19USU1FT1VUID0gMzBfMDAwO1xuXG4vKipcbiAqIFBhdHRlcm4gZm9yIHNhZmUgd29ya2Zsb3cgbmFtZXMuIE9ubHkgYWxsb3dzIGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzLFxuICogdW5kZXJzY29yZXMsIGh5cGhlbnMsIGRvdHMsIGZvcndhcmQgc2xhc2hlcyAoZm9yIG5hbWVzcGFjZWQgd29ya2Zsb3dzKSxcbiAqIGFuZCBhdCBzaWducyAoZm9yIHNjb3BlZCBwYWNrYWdlcykuXG4gKi9cbmNvbnN0IFNBRkVfV09SS0ZMT1dfTkFNRV9QQVRURVJOID0gL15bYS16QS1aMC05X1xcLS4vQF0rJC87XG5cbi8qKlxuICogVmFsaWRhdGVzIGEgd29ya2Zsb3cgbmFtZSBhbmQgcmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyBxdWV1ZSBuYW1lLlxuICogRW5zdXJlcyB0aGUgd29ya2Zsb3cgbmFtZSBvbmx5IGNvbnRhaW5zIHNhZmUgY2hhcmFjdGVycyBiZWZvcmVcbiAqIGludGVycG9sYXRpbmcgaXQgaW50byB0aGUgcXVldWUgbmFtZSBzdHJpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRXb3JrZmxvd1F1ZXVlTmFtZShcbiAgd29ya2Zsb3dOYW1lOiBzdHJpbmcsXG4gIG5hbWVzcGFjZT86IHN0cmluZ1xuKTogVmFsaWRRdWV1ZU5hbWUge1xuICBpZiAoIVNBRkVfV09SS0ZMT1dfTkFNRV9QQVRURVJOLnRlc3Qod29ya2Zsb3dOYW1lKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBJbnZhbGlkIHdvcmtmbG93IG5hbWUgXCIke3dvcmtmbG93TmFtZX1cIjogbXVzdCBvbmx5IGNvbnRhaW4gYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIHVuZGVyc2NvcmVzLCBoeXBoZW5zLCBkb3RzLCBmb3J3YXJkIHNsYXNoZXMsIG9yIGF0IHNpZ25zYFxuICAgICk7XG4gIH1cbiAgY29uc3QgcHJlZml4ID0gZ2V0UXVldWVUb3BpY1ByZWZpeChcbiAgICAnd29ya2Zsb3cnLFxuICAgIHJlc29sdmVRdWV1ZU5hbWVzcGFjZShuYW1lc3BhY2UpXG4gICk7XG4gIHJldHVybiBgJHtwcmVmaXh9JHt3b3JrZmxvd05hbWV9YCBhcyBWYWxpZFF1ZXVlTmFtZTtcbn1cblxuY29uc3QgZ2VuZXJhdGVJZCA9IG1vbm90b25pY0ZhY3RvcnkoKTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBzdHJlYW0gbmFtZSBmb3IgYSBoZWFsdGggY2hlY2sgd2l0aCB0aGUgZ2l2ZW4gY29ycmVsYXRpb24gSUQuXG4gKi9cbmZ1bmN0aW9uIGdldEhlYWx0aENoZWNrU3RyZWFtTmFtZShjb3JyZWxhdGlvbklkOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYF9faGVhbHRoX2NoZWNrX18ke2NvcnJlbGF0aW9uSWR9YDtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgYSBoZWFsdGggY2hlY2sgb3BlcmF0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEhlYWx0aENoZWNrUmVzdWx0IHtcbiAgaGVhbHRoeTogYm9vbGVhbjtcbiAgLyoqIEVycm9yIG1lc3NhZ2UgaWYgaGVhbHRoIGNoZWNrIGZhaWxlZCAqL1xuICBlcnJvcj86IHN0cmluZztcbiAgLyoqIExhdGVuY3kgaWYgdGhlIGhlYWx0aCBjaGVjayB3YXMgc3VjY2Vzc2Z1bCAqL1xuICBsYXRlbmN5TXM/OiBudW1iZXI7XG4gIC8qKiBTcGVjIHZlcnNpb24gb2YgdGhlIHJlc3BvbmRpbmcgZGVwbG95bWVudCAqL1xuICBzcGVjVmVyc2lvbj86IG51bWJlcjtcbiAgLyoqXG4gICAqIGBAd29ya2Zsb3cvY29yZWAgdmVyc2lvbiBvZiB0aGUgcmVzcG9uZGluZyBkZXBsb3ltZW50LCB1c2VkIGZvclxuICAgKiBjYXBhYmlsaXR5IGRldGVjdGlvbiAoc2VlIGBnZXRSdW5DYXBhYmlsaXRpZXNgKS4gT21pdHRlZCB3aGVuIHRoZVxuICAgKiByZXNwb25kaW5nIGRlcGxveW1lbnQgZGlkIG5vdCBwcm92aWRlIHRoZSBmaWVsZCBhcyBhIHN0cmluZzpcbiAgICogZm9yIGV4YW1wbGUsIGFuIG9sZGVyIGBAd29ya2Zsb3cvY29yZWAgdGhhdCBwcmVkYXRlcyB0aGlzIGZpZWxkLFxuICAgKiBvciBhIG5vbi1KU09OIHBsYWluLXRleHQgaGVhbHRoIHJlc3BvbnNlLlxuICAgKi9cbiAgd29ya2Zsb3dDb3JlVmVyc2lvbj86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSB0YXJnZXQgcnVuJ3MgWDI1NTE5IHB1YmxpYyBrZXkgKGJhc2U2NCksIHJldHVybmVkIG9ubHkgd2hlbiB0aGUgcHJvYmVcbiAgICogY2FycmllZCBhIGBydW5JZGAgYW5kIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQgaGFzIGVuY3J5cHRpb24gZW5hYmxlZC5cbiAgICpcbiAgICogTGV0cyBhIGNyb3NzLWRlcGxveW1lbnQgYHN0YXJ0KClgIHNlYWwgdGhlIHdvcmtmbG93IGFyZ3VtZW50cyB1c2luZyBhXG4gICAqIHJlc3BvbnNlIGl0IHdhcyBhbHJlYWR5IHdhaXRpbmcgb24sIGluc3RlYWQgb2YgbWFraW5nIGEgc2VwYXJhdGVcbiAgICoga2V5LWxvb2t1cCByZXF1ZXN0LlxuICAgKi9cbiAgZW5jcnlwdGlvblB1YmxpY0tleT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQncyBgSE9PS19SRVNVTUVfSU5QVVRfVkVSU0lPTmA6IHRoZSBwcm90b2NvbFxuICAgKiB2ZXJzaW9uIGF0IHdoaWNoIHRoZSAqY29uc3VtZXIqIChxdWV1ZS1tZXNzYWdlIHRhcmdldCkgbWF0ZXJpYWxpemVzIHRoZVxuICAgKiBgaG9va19yZWNlaXZlZGAgZXZlbnQgZnJvbSBgaG9va0lucHV0YCBvbiByZXBsYXkuIEEgY3Jvc3MtZGVwbG95bWVudFxuICAgKiBgc3RhcnQoKWAgc3RhbXBzIHRoZSAqdGFyZ2V0J3MqIHZhbHVlIChub3QgdGhlIGNhbGxlcidzKSBpbnRvIHRoZSBuZXdcbiAgICogcnVuJ3MgYGV4ZWN1dGlvbkNvbnRleHQuaG9va1Jlc3VtZUlucHV0VmVyc2lvbmAuIEN1cnJlbnQgcHJvZHVjZXJzIHdyaXRlXG4gICAqIHRoZSBldmVudCBkdXJhYmx5IGJlZm9yZSBwdWJsaXNoaW5nIHRoZSB3YWtlIGFuZCBkbyBub3QgcmVhZCB0aGUgbWFya2VyO1xuICAgKiBPTERFUiBwcm9kdWNlcnMgc3RpbGwgZ2F0ZSB0aGVpciBsYXp5IHBhdGggb24gaXQsIHNvIGl0IGtlZXBzIGJlaW5nXG4gICAqIHN0YW1wZWQuIE9taXR0ZWQgd2hlbiB0aGUgcmVzcG9uZGluZyBkZXBsb3ltZW50IHByZWRhdGVzIHRoaXMgZmllbGQsXG4gICAqIHdoaWNoIGZhaWxzIHRoYXQgZ2F0ZSBjbG9zZWQuXG4gICAqL1xuICBob29rUmVzdW1lSW5wdXRWZXJzaW9uPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbWVzc2FnZSBpcyBhIGhlYWx0aCBjaGVjayBwYXlsb2FkLlxuICogSWYgc28sIHJldHVybnMgdGhlIHBhcnNlZCBwYXlsb2FkLiBPdGhlcndpc2UgcmV0dXJucyB1bmRlZmluZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUhlYWx0aENoZWNrUGF5bG9hZChcbiAgbWVzc2FnZTogdW5rbm93blxuKTogSGVhbHRoQ2hlY2tQYXlsb2FkIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmVzdWx0ID0gSGVhbHRoQ2hlY2tQYXlsb2FkU2NoZW1hLnNhZmVQYXJzZShtZXNzYWdlKTtcbiAgaWYgKHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgcmV0dXJuIHJlc3VsdC5kYXRhO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgZGV0ZXJtaW5pc3RpYyBmYWtlIHJ1bklkIGZvciBoZWFsdGggY2hlY2sgc3RyZWFtcy5cbiAqIEJvdGggdGhlIHdyaXRlciAoaGFuZGxlSGVhbHRoQ2hlY2tNZXNzYWdlKSBhbmQgcmVhZGVyIChoZWFsdGhDaGVjaykgZGVyaXZlXG4gKiB0aGUgc2FtZSBydW5JZCBmcm9tIHRoZSBjb3JyZWxhdGlvbklkIHNvIHRoYXQgaW1wbGVtZW50YXRpb25zIHRoYXQgc2NvcGVcbiAqIHN0cmVhbSByZWFkcyBieSBydW5JZCBzdGlsbCB3b3JrIGNvcnJlY3RseS5cbiAqL1xuZnVuY3Rpb24gZ2VuZXJhdGVIZWFsdGhDaGVja1J1bklkKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgd3J1bl9oY18ke2NvcnJlbGF0aW9uSWR9YDtcbn1cblxuLyoqXG4gKiBIYW5kbGVzIGEgaGVhbHRoIGNoZWNrIG1lc3NhZ2UgYnkgd3JpdGluZyB0aGUgcmVzdWx0IHRvIHRoZSB3b3JsZCdzIHN0cmVhbS5cbiAqIFRoZSBjYWxsZXIgY2FuIGxpc3RlbiB0byB0aGlzIHN0cmVhbSB0byBnZXQgdGhlIGhlYWx0aCBjaGVjayByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0gaGVhbHRoQ2hlY2sgLSBUaGUgcGFyc2VkIGhlYWx0aCBjaGVjayBwYXlsb2FkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVIZWFsdGhDaGVja01lc3NhZ2UoXG4gIGhlYWx0aENoZWNrOiBIZWFsdGhDaGVja1BheWxvYWQsXG4gIHdvcmxkU3BlY1ZlcnNpb24/OiBudW1iZXJcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkTGF6eSgpO1xuICBjb25zdCBzdHJlYW1OYW1lID0gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGhlYWx0aENoZWNrLmNvcnJlbGF0aW9uSWQpO1xuXG4gIC8vIFdoZW4gdGhlIHByb2JlIG5hbWVzIGEgcnVuIHRoZSBjYWxsZXIgaXMgYWJvdXQgdG8gY3JlYXRlLCBwdWJsaXNoIHRoYXRcbiAgLy8gcnVuJ3MgcHVibGljIGtleS4gV2UgYXJlIGV4ZWN1dGluZyBpbnNpZGUgdGhlIHRhcmdldCBkZXBsb3ltZW50LCBzbyBpdHNcbiAgLy8ga2V5IG1hdGVyaWFsIGlzIGF2YWlsYWJsZSBsb2NhbGx5IChubyBBUEkgY2FsbCksIGFuZCB0aGUgY2FsbGVyIGNhbiB0aGVuXG4gIC8vIHNlYWwgdGhlIHdvcmtmbG93IGFyZ3VtZW50cyBzdHJhaWdodCBmcm9tIHRoaXMgcmVzcG9uc2UgcmF0aGVyIHRoYW5cbiAgLy8gbWFraW5nIGEgc2VwYXJhdGUga2V5LWxvb2t1cCByZXF1ZXN0LlxuICAvL1xuICAvLyBPbmx5IGEgKnB1YmxpYyoga2V5IG1heSB0cmF2ZWwgdGhpcyB3YXk6IHRoZSBwcm9iZSByZXNwb25zZSBzdHJlYW0gaXNcbiAgLy8gZGVsaWJlcmF0ZWx5IHVuYXV0aGVudGljYXRlZCwgc28gYW55dGhpbmcgc2VjcmV0IHdvdWxkIGJlIGV4cG9zZWQuXG4gIC8vIEJlc3QtZWZmb3J0OiBhIGZhaWx1cmUgaGVyZSBtdXN0IG5vdCBmYWlsIHRoZSBoZWFsdGggY2hlY2sgaXRzZWxmLCB3aGljaFxuICAvLyBjYWxsZXJzIGFsc28gcmVseSBvbiBmb3IgcGxhaW4gY2FwYWJpbGl0eSBkZXRlY3Rpb24uXG4gIGxldCBlbmNyeXB0aW9uUHVibGljS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGlmIChoZWFsdGhDaGVjay5ydW5JZCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByYXdLZXkgPSBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4oaGVhbHRoQ2hlY2sucnVuSWQpO1xuICAgICAgaWYgKHJhd0tleSkge1xuICAgICAgICBlbmNyeXB0aW9uUHVibGljS2V5ID0gYnl0ZXNUb0Jhc2U2NChcbiAgICAgICAgICAoYXdhaXQgZGVyaXZlUnVuS2V5UGFpcihyYXdLZXkpKS5wdWJsaWNLZXlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgJ0hlYWx0aCBjaGVjayBjb3VsZCBub3QgZGVyaXZlIGEgcnVuIHB1YmxpYyBrZXk7IHRoZSBjYWxsZXIgd2lsbCBmYWxsIGJhY2sgdG8gYSBrZXkgbG9va3VwJyxcbiAgICAgICAge1xuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IGhlYWx0aENoZWNrLmNvcnJlbGF0aW9uSWQsXG4gICAgICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCByZXNwb25zZSA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICBoZWFsdGh5OiB0cnVlLFxuICAgIGNvcnJlbGF0aW9uSWQ6IGhlYWx0aENoZWNrLmNvcnJlbGF0aW9uSWQsXG4gICAgc3BlY1ZlcnNpb246IHdvcmxkU3BlY1ZlcnNpb24gPz8gU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgd29ya2Zsb3dDb3JlVmVyc2lvbixcbiAgICAvLyBXZSBhcmUgZXhlY3V0aW5nIGluc2lkZSB0aGUgdGFyZ2V0IGRlcGxveW1lbnQsIHNvIHRoaXMgY29uc3RhbnQgcmVmbGVjdHNcbiAgICAvLyB0aGUgKmNvbnN1bWVyJ3MqIGhvb2stcmVzdW1lIHByb3RvY29sIHZlcnNpb24sIGV4YWN0bHkgd2hhdCBhXG4gICAgLy8gY3Jvc3MtZGVwbG95bWVudCBjYWxsZXIgbmVlZHMgdG8gZ2F0ZSBpdHMgcGFyYWxsZWwgcmVzdW1lIHBhdGggb24uXG4gICAgaG9va1Jlc3VtZUlucHV0VmVyc2lvbjogSE9PS19SRVNVTUVfSU5QVVRfVkVSU0lPTixcbiAgICAuLi4oZW5jcnlwdGlvblB1YmxpY0tleSA/IHsgZW5jcnlwdGlvblB1YmxpY0tleSB9IDoge30pLFxuICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgfSk7XG4gIC8vIFVzZSBhIGRldGVybWluaXN0aWMgZmFrZSBydW5JZCBkZXJpdmVkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdFxuICAvLyB0aGUgcmVhZGVyIHNpZGUgcHJvZHVjZXMgdGhlIHNhbWUgdmFsdWUuXG4gIGNvbnN0IGZha2VSdW5JZCA9IGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChoZWFsdGhDaGVjay5jb3JyZWxhdGlvbklkKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUsIHJlc3BvbnNlKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEhlYWx0aENoZWNrT3B0aW9ucyB7XG4gIC8qKiBUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBoZWFsdGggY2hlY2sgcmVzcG9uc2UuIERlZmF1bHQ6IDMwMDAwICgzMHMpICovXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG4gIC8qKiBEZXBsb3ltZW50IElEIHRvIHNlbmQgdGhlIGhlYWx0aCBjaGVjayB0by4gRmFsbHMgYmFjayB0byBwcm9jZXNzLmVudi5WRVJDRUxfREVQTE9ZTUVOVF9JRC4gKi9cbiAgZGVwbG95bWVudElkPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHJ1biBpZCB0aGUgY2FsbGVyIGlzIGFib3V0IHRvIGNyZWF0ZS4gV2hlbiBzZXQsIHRoZSByZXNwb25kaW5nXG4gICAqIGRlcGxveW1lbnQgZGVyaXZlcyB0aGF0IHJ1bidzIHB1YmxpYyBrZXkgbG9jYWxseSBhbmQgcmV0dXJucyBpdCBhc1xuICAgKiBgZW5jcnlwdGlvblB1YmxpY0tleWAsIGxldHRpbmcgYSBjcm9zcy1kZXBsb3ltZW50IGBzdGFydCgpYCBzZWFsIHRoZVxuICAgKiB3b3JrZmxvdyBhcmd1bWVudHMgd2l0aG91dCBhIHNlcGFyYXRlIGtleSBsb29rdXAuXG4gICAqL1xuICBydW5JZD86IHN0cmluZztcbiAgLyoqXG4gICAqIFF1ZXVlIG5hbWVzcGFjZSBvZiB0aGUgdGFyZ2V0IGRlcGxveW1lbnQgKGUuZy4gYCdldmUnYCBmb3IgdG9waWNzIGxpa2VcbiAgICogYF9fZXZlX3drZl93b3JrZmxvd18qYCkuIEZhbGxzIGJhY2sgdG8gYFdPUktGTE9XX1FVRVVFX05BTUVTUEFDRWAgaW4gdGhlXG4gICAqIGNhbGxpbmcgcHJvY2Vzcy4gQ3Jvc3MtY29udGV4dCBjYWxsZXJzIChlLmcuIHRoZSBvYnNlcnZhYmlsaXR5XG4gICAqIGRhc2hib2FyZCkgbXVzdCBwYXNzIHRoZSB0YXJnZXQgZGVwbG95bWVudCdzIG5hbWVzcGFjZSBleHBsaWNpdGx5OlxuICAgKiB0aGUgZW52IGZhbGxiYWNrIHJlc29sdmVzIGluIHRoZSBjYWxsZXIncyBwcm9jZXNzLCBhbmQgYSBtZXNzYWdlXG4gICAqIHB1Ymxpc2hlZCB0byBhIG1pc21hdGNoZWQgdG9waWMgaGFzIG5vIGNvbnN1bWVyLCBzbyB0aGUgY2hlY2sgd291bGRcbiAgICogYWx3YXlzIHRpbWUgb3V0LlxuICAgKi9cbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBlcmZvcm1zIGEgaGVhbHRoIGNoZWNrIGJ5IHNlbmRpbmcgYSBtZXNzYWdlIHRocm91Z2ggdGhlIHF1ZXVlIHBpcGVsaW5lXG4gKiBhbmQgdmVyaWZ5aW5nIGl0IGlzIHByb2Nlc3NlZCBieSB0aGUgY29tYmluZWQgd29ya2Zsb3cgZW5kcG9pbnQuXG4gKlxuICogVGhpcyBmdW5jdGlvbiBieXBhc3NlcyBEZXBsb3ltZW50IFByb3RlY3Rpb24gb24gVmVyY2VsIGJlY2F1c2UgaXQgZ29lc1xuICogdGhyb3VnaCB0aGUgcXVldWUgaW5mcmFzdHJ1Y3R1cmUgcmF0aGVyIHRoYW4gZGlyZWN0IEhUVFAuXG4gKlxuICogQHBhcmFtIHdvcmxkIC0gVGhlIFdvcmxkIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIGhlYWx0aCBjaGVja1xuICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBoZWFsdGggY2hlY2sgcmVzdWx0XG4gKi9cbi8vIFBvbGwgaW50ZXJ2YWwgZm9yIGhlYWx0aCBjaGVjayByZXRyaWVzIChtcylcbmNvbnN0IEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMID0gMTAwO1xuLy8gUGVyLXJlYWQgdGltZW91dCB0byBwcmV2ZW50IGJsb2NraW5nIGZvcmV2ZXIgb24gbG9jYWwgd29ybGQncyBFdmVudEVtaXR0ZXJcbi8vICh3aGljaCBkb2Vzbid0IHdvcmsgYWNyb3NzIHByb2Nlc3NlcylcbmNvbnN0IEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVQgPSA1MDA7XG5cbi8qKlxuICogUmVhZCBjaHVua3MgZnJvbSBhIHN0cmVhbSB3aXRoIGEgdGltZW91dCBwZXIgcmVhZCBvcGVyYXRpb24uXG4gKiBSZXR1cm5zIHsgY2h1bmtzLCB0aW1lZE91dCB9IHdoZXJlIHRpbWVkT3V0IGluZGljYXRlcyBpZiBhIHJlYWQgdGltZWQgb3V0LlxuICovXG4vKipcbiAqIFJhY2UgYSBwcm9taXNlIGFnYWluc3QgYSBkZWFkbGluZS4gUmVqZWN0cyB3aXRoIGEgdGltZW91dCBlcnJvciB3aGVuIHRoZVxuICogZGVhZGxpbmUgZWxhcHNlcyBmaXJzdC4gVXNlZCB0byBib3VuZCBgd29ybGQuc3RyZWFtcy5nZXQoKWAgaW5zaWRlIHRoZVxuICogaGVhbHRoLWNoZWNrIHBvbGwgbG9vcDogc29tZSB3b3JsZHMgaG9sZCB0aGF0IHJlcXVlc3Qgb3BlbiB1bnRpbCB0aGVcbiAqIHN0cmVhbSBoYXMgZGF0YSAoZS5nLiB3b3JrZmxvdy1zZXJ2ZXIgaG9sZHMgdW53cml0dGVuIHN0cmVhbXMgb3BlbiBmb3JcbiAqIH4yIG1pbnV0ZXMpLCB3aGljaCB3b3VsZCBvdGhlcndpc2UgYmxvdyB0aHJvdWdoIHRoZSBjb25maWd1cmVkIGhlYWx0aFxuICogY2hlY2sgdGltZW91dCwgc2luY2UgdGhlIGB3aGlsZWAgY29uZGl0aW9uIGlzIG9ubHkgcmUtY2hlY2tlZCBiZXR3ZWVuXG4gKiBpdGVyYXRpb25zLlxuICovXG5mdW5jdGlvbiB3aXRoRGVhZGxpbmU8VD4ocHJvbWlzZTogUHJvbWlzZTxUPiwgbXM6IG51bWJlcik6IFByb21pc2U8VD4ge1xuICBsZXQgdGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcbiAgICBwcm9taXNlLFxuICAgIG5ldyBQcm9taXNlPG5ldmVyPigoXywgcmVqZWN0KSA9PiB7XG4gICAgICB0aW1lciA9IHNldFRpbWVvdXQoXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXJyb3IoYE9wZXJhdGlvbiB0aW1lZCBvdXQgYWZ0ZXIgJHttc31tc2ApKSxcbiAgICAgICAgbXNcbiAgICAgICk7XG4gICAgfSksXG4gIF0pLmZpbmFsbHkoKCkgPT4gY2xlYXJUaW1lb3V0KHRpbWVyKSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRTdHJlYW1XaXRoVGltZW91dChcbiAgcmVhZGVyOiBSZWFkYWJsZVN0cmVhbURlZmF1bHRSZWFkZXI8VWludDhBcnJheT4sXG4gIHJlYWRUaW1lb3V0OiBudW1iZXJcbik6IFByb21pc2U8eyBjaHVua3M6IFVpbnQ4QXJyYXlbXTsgdGltZWRPdXQ6IGJvb2xlYW4gfT4ge1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICBsZXQgZG9uZSA9IGZhbHNlO1xuICBsZXQgdGltZWRPdXQgPSBmYWxzZTtcblxuICB3aGlsZSAoIWRvbmUgJiYgIXRpbWVkT3V0KSB7XG4gICAgY29uc3QgcmVhZFByb21pc2UgPSByZWFkZXIucmVhZCgpO1xuICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2U8eyBkb25lOiB0cnVlOyB2YWx1ZTogdW5kZWZpbmVkIH0+KFxuICAgICAgKHJlc29sdmUpID0+XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHRpbWVkT3V0ID0gdHJ1ZTtcbiAgICAgICAgICByZXNvbHZlKHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgfSwgcmVhZFRpbWVvdXQpXG4gICAgKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UucmFjZShbcmVhZFByb21pc2UsIHRpbWVvdXRQcm9taXNlXSk7XG4gICAgZG9uZSA9IHJlc3VsdC5kb25lO1xuICAgIGlmIChyZXN1bHQudmFsdWUpIGNodW5rcy5wdXNoKHJlc3VsdC52YWx1ZSk7XG4gIH1cblxuICByZXR1cm4geyBjaHVua3MsIHRpbWVkT3V0IH07XG59XG5cbi8qKlxuICogUGFyc2UgYW5kIHZhbGlkYXRlIGEgaGVhbHRoIGNoZWNrIHJlc3BvbnNlIGZyb20gc3RyZWFtIGNodW5rcy5cbiAqIFJldHVybnMgdGhlIHBhcnNlZCByZXNwb25zZSBvciBudWxsIGlmIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3M6IFVpbnQ4QXJyYXlbXSk6IHtcbiAgaGVhbHRoeTogYm9vbGVhbjtcbiAgc3BlY1ZlcnNpb24/OiBudW1iZXI7XG4gIHdvcmtmbG93Q29yZVZlcnNpb24/OiBzdHJpbmc7XG4gIGVuY3J5cHRpb25QdWJsaWNLZXk/OiBzdHJpbmc7XG59IHwgbnVsbCB7XG4gIGlmIChjaHVua3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcblxuICBjb25zdCB0b3RhbExlbmd0aCA9IGNodW5rcy5yZWR1Y2UoKHN1bSwgY2h1bmspID0+IHN1bSArIGNodW5rLmxlbmd0aCwgMCk7XG4gIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkodG90YWxMZW5ndGgpO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3MpIHtcbiAgICBjb21iaW5lZC5zZXQoY2h1bmssIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IGNodW5rLmxlbmd0aDtcbiAgfVxuICBjb25zdCByZXNwb25zZVRleHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoY29tYmluZWQpO1xuXG4gIGxldCByZXNwb25zZTogdW5rbm93bjtcbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IEpTT04ucGFyc2UocmVzcG9uc2VUZXh0KTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gT2xkIGRlcGxveW1lbnRzIChzcGVjVmVyc2lvbiA8IDMpIHJldHVybiBwbGFpbiB0ZXh0IGxpa2VcbiAgICAvLyAnV29ya2Zsb3cgU0RLIFwiLi4uXCIgZW5kcG9pbnQgaXMgaGVhbHRoeScuIFRyZWF0IGFueSBub24tZW1wdHlcbiAgICAvLyB0ZXh0IHJlc3BvbnNlIGFzIGEgaGVhbHRoeSBkZXBsb3ltZW50IHdpdGggdW5rbm93biBzcGVjVmVyc2lvbi5cbiAgICBpZiAocmVzcG9uc2VUZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoXG4gICAgdHlwZW9mIHJlc3BvbnNlICE9PSAnb2JqZWN0JyB8fFxuICAgIHJlc3BvbnNlID09PSBudWxsIHx8XG4gICAgISgnaGVhbHRoeScgaW4gcmVzcG9uc2UpIHx8XG4gICAgdHlwZW9mIChyZXNwb25zZSBhcyB7IGhlYWx0aHk6IHVua25vd24gfSkuaGVhbHRoeSAhPT0gJ2Jvb2xlYW4nXG4gICkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgciA9IHJlc3BvbnNlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBwYXJzZWQ6IHtcbiAgICBoZWFsdGh5OiBib29sZWFuO1xuICAgIHNwZWNWZXJzaW9uPzogbnVtYmVyO1xuICAgIHdvcmtmbG93Q29yZVZlcnNpb24/OiBzdHJpbmc7XG4gICAgZW5jcnlwdGlvblB1YmxpY0tleT86IHN0cmluZztcbiAgICBob29rUmVzdW1lSW5wdXRWZXJzaW9uPzogbnVtYmVyO1xuICB9ID0ge1xuICAgIGhlYWx0aHk6IHIuaGVhbHRoeSBhcyBib29sZWFuLFxuICB9O1xuICBpZiAodHlwZW9mIHIuc3BlY1ZlcnNpb24gPT09ICdudW1iZXInKSB7XG4gICAgcGFyc2VkLnNwZWNWZXJzaW9uID0gci5zcGVjVmVyc2lvbjtcbiAgfVxuICBpZiAodHlwZW9mIHIud29ya2Zsb3dDb3JlVmVyc2lvbiA9PT0gJ3N0cmluZycpIHtcbiAgICBwYXJzZWQud29ya2Zsb3dDb3JlVmVyc2lvbiA9IHIud29ya2Zsb3dDb3JlVmVyc2lvbjtcbiAgfVxuICBpZiAodHlwZW9mIHIuZW5jcnlwdGlvblB1YmxpY0tleSA9PT0gJ3N0cmluZycpIHtcbiAgICBwYXJzZWQuZW5jcnlwdGlvblB1YmxpY0tleSA9IHIuZW5jcnlwdGlvblB1YmxpY0tleTtcbiAgfVxuICBpZiAodHlwZW9mIHIuaG9va1Jlc3VtZUlucHV0VmVyc2lvbiA9PT0gJ251bWJlcicpIHtcbiAgICBwYXJzZWQuaG9va1Jlc3VtZUlucHV0VmVyc2lvbiA9IHIuaG9va1Jlc3VtZUlucHV0VmVyc2lvbjtcbiAgfVxuICByZXR1cm4gcGFyc2VkO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGVhbHRoQ2hlY2soXG4gIHdvcmxkOiBXb3JsZCxcbiAgb3B0aW9ucz86IEhlYWx0aENoZWNrT3B0aW9uc1xuKTogUHJvbWlzZTxIZWFsdGhDaGVja1Jlc3VsdD4ge1xuICBjb25zdCB0aW1lb3V0ID0gb3B0aW9ucz8udGltZW91dCA/PyBERUZBVUxUX0hFQUxUSF9DSEVDS19USU1FT1VUO1xuICAvLyBVc2UgdGhlIHdvcmxkJ3MgSUQgZ2VuZXJhdG9yIHdoZW4gYXZhaWxhYmxlIHNvIHRoZSBjb3JyZWxhdGlvbklkIGlzIGFcbiAgLy8gcmVnaW9uLXRhZ2dlZCBVTElELiBUaGUgaGVhbHRoLWNoZWNrIHJlc3BvbnNlIGlzIGRlbGl2ZXJlZCBvdmVyIGEgc3RyZWFtXG4gIC8vIHdob3NlIG5hbWUgZW1iZWRzIHRoaXMgY29ycmVsYXRpb25JZDsgdW5kZXIgcGxhdGZvcm0tZGlyZWN0ZWQgcm91dGluZyB0aGVcbiAgLy8gcmVhZGVyIGFuZCB0aGUgcmVzcG9uZGluZyBlbmRwb2ludCBjYW4gYmUgc2VydmVkIGZyb20gZGlmZmVyZW50IHBoeXNpY2FsXG4gIC8vIHJlZ2lvbnMsIHNvIHRoZSByZWdpb24gbXVzdCBiZSBlbmNvZGVkIGluIHRoZSBJRCBpdHNlbGYgZm9yIGJvdGggc2lkZXMgdG9cbiAgLy8gcmVzb2x2ZSB0aGUgc2FtZSAocmVnaW9uLXBpbm5lZCkgYmFja2VuZC4gRmFsbHMgYmFjayB0byBhIHBsYWluIFVMSUQgZm9yXG4gIC8vIHdvcmxkcyB0aGF0IGRvbid0IHRhZyBJRHMgKGUuZy4gbG9jYWwpLCB3aGljaCByZXNvbHZlIHRvIHRoZSBkZWZhdWx0XG4gIC8vIHJlZ2lvbiBvbiBib3RoIHNpZGVzLlxuICBjb25zdCBjb3JyZWxhdGlvbklkID0gd29ybGQuY3JlYXRlUnVuSWQ/LigpID8/IGdlbmVyYXRlSWQoKTtcbiAgY29uc3Qgc3RyZWFtTmFtZSA9IGdldEhlYWx0aENoZWNrU3RyZWFtTmFtZShjb3JyZWxhdGlvbklkKTtcblxuICBjb25zdCBxdWV1ZU5hbWUgPVxuICAgIGAke2dldFF1ZXVlVG9waWNQcmVmaXgoJ3dvcmtmbG93JywgcmVzb2x2ZVF1ZXVlTmFtZXNwYWNlKG9wdGlvbnM/Lm5hbWVzcGFjZSkpfWhlYWx0aF9jaGVja2AgYXMgVmFsaWRRdWV1ZU5hbWU7XG5cbiAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcblxuICB0cnkge1xuICAgIGF3YWl0IHdvcmxkLnF1ZXVlKFxuICAgICAgcXVldWVOYW1lLFxuICAgICAge1xuICAgICAgICBfX2hlYWx0aENoZWNrOiB0cnVlLFxuICAgICAgICBjb3JyZWxhdGlvbklkLFxuICAgICAgICAuLi4ob3B0aW9ucz8ucnVuSWQgPyB7IHJ1bklkOiBvcHRpb25zLnJ1bklkIH0gOiB7fSksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICAvLyBVc2UgSlNPTiB0cmFuc3BvcnQgc28gdGhlIGhlYWx0aCBjaGVjayB3b3JrcyBhZ2FpbnN0IGJvdGhcbiAgICAgICAgLy8gb2xkIChKU09OLW9ubHkpIGFuZCBuZXcgKGR1YWwpIGRlcGxveW1lbnRzLlxuICAgICAgICBzcGVjVmVyc2lvbjogU1BFQ19WRVJTSU9OX0xFR0FDWSxcbiAgICAgICAgZGVwbG95bWVudElkOiBvcHRpb25zPy5kZXBsb3ltZW50SWQsXG4gICAgICB9XG4gICAgKTtcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIC0gc3RhcnRUaW1lIDwgdGltZW91dCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVtYWluaW5nTXMgPSB0aW1lb3V0IC0gKERhdGUubm93KCkgLSBzdGFydFRpbWUpO1xuICAgICAgICBjb25zdCBzdHJlYW0gPSBhd2FpdCB3aXRoRGVhZGxpbmUoXG4gICAgICAgICAgd29ybGQuc3RyZWFtcy5nZXQoXG4gICAgICAgICAgICBnZW5lcmF0ZUhlYWx0aENoZWNrUnVuSWQoY29ycmVsYXRpb25JZCksXG4gICAgICAgICAgICBzdHJlYW1OYW1lXG4gICAgICAgICAgKSxcbiAgICAgICAgICByZW1haW5pbmdNc1xuICAgICAgICApO1xuICAgICAgICBjb25zdCByZWFkZXIgPSBzdHJlYW0uZ2V0UmVhZGVyKCk7XG4gICAgICAgIGNvbnN0IHsgY2h1bmtzLCB0aW1lZE91dCB9ID0gYXdhaXQgcmVhZFN0cmVhbVdpdGhUaW1lb3V0KFxuICAgICAgICAgIHJlYWRlcixcbiAgICAgICAgICBIRUFMVEhfQ0hFQ0tfUkVBRF9USU1FT1VUXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKHRpbWVkT3V0KSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJlYWRlci5jYW5jZWwoKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8vIElnbm9yZSBjYW5jZWwgZXJyb3JzXG4gICAgICAgICAgfVxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBwYXJzZUhlYWx0aENoZWNrUmVzcG9uc2UoY2h1bmtzKTtcbiAgICAgICAgaWYgKHJlc3BvbnNlKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLnJlc3BvbnNlLFxuICAgICAgICAgICAgbGF0ZW5jeU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT5cbiAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBoZWFsdGh5OiBmYWxzZSxcbiAgICAgIGVycm9yOiBgSGVhbHRoIGNoZWNrIHRpbWVkIG91dCBhZnRlciAke3RpbWVvdXR9bXNgLFxuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSxcbiAgICB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IoXG4gIHJ1bklkOiBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZ1xuKTogV29ya2Zsb3dXb3JsZEVycm9yIHtcbiAgcmV0dXJuIG5ldyBXb3JrZmxvd1dvcmxkRXJyb3IoXG4gICAgYEV2ZW50IHBhZ2luYXRpb24gJHttZXNzYWdlfSBmb3Igd29ya2Zsb3cgcnVuIFwiJHtydW5JZH1cIi5gLFxuICAgIHsgY29kZTogUlVOX0VSUk9SX0NPREVTLldPUkxEX0NPTlRSQUNUX0VSUk9SIH1cbiAgKTtcbn1cblxuZnVuY3Rpb24gcmVjb3JkUmVxdWVzdGVkRXZlbnRDdXJzb3IoXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGN1cnNvcjogc3RyaW5nIHwgbnVsbCxcbiAgcmVxdWVzdGVkQ3Vyc29yczogU2V0PHN0cmluZz5cbik6IHZvaWQge1xuICBpZiAoIWN1cnNvcikge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAocmVxdWVzdGVkQ3Vyc29ycy5oYXMoY3Vyc29yKSkge1xuICAgIHRocm93IGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IocnVuSWQsICdkaWQgbm90IGFkdmFuY2UnKTtcbiAgfVxuICByZXF1ZXN0ZWRDdXJzb3JzLmFkZChjdXJzb3IpO1xufVxuXG4vKipcbiAqIEFwcGVuZHMgZXZlbnRzIHdob3NlIElEcyBhcmUgbm90IGFscmVhZHkgcHJlc2VudCBpbiBgdGFyZ2V0YC5cbiAqXG4gKiBQYXNzIHRoZSBJRHMgY3VycmVudGx5IHByZXNlbnQgaW4gYHRhcmdldGAgd2hlbiBhcHBlbmRpbmcgcmVwZWF0ZWRseSB0byB0aGVcbiAqIHNhbWUgYXJyYXkuIFRoZSBzZXQgaXMgdXBkYXRlZCBhbG9uZ3NpZGUgYHRhcmdldGAuXG4gKlxuICogRXZlbnRzIGFyZSBhcHBlbmRlZCBpbiB0aGUgb3JkZXIgdGhlIFdvcmxkIHJldHVybmVkIHRoZW0sIGFuZCBhcmUgbm90XG4gKiByZS1zb3J0ZWQuIEV2ZXJ5IGFwcGVuZCBzb3VyY2UgaXMgYWxyZWFkeSBpbiBjYW5vbmljYWwgb3JkZXIgcmVsYXRpdmUgdG8gdGhlXG4gKiB0YWlsIChhIGN1cnNvci1kZWxpbWl0ZWQgcGFnZSwgb3IgYSB3cml0ZS1yZXNwb25zZSBkZWx0YSksIHNvIHJlY2VpcHQgb3JkZXIgaXNcbiAqIHRoZSBvcmRlciB0byBrZWVwLCBhbmQgcmUtc29ydGluZyBoZXJlIHdvdWxkIG9ubHkgY29zdCBhIHBhc3Mgb3ZlciB0aGUgbG9nLlxuICogTm90aGluZyBkb3duc3RyZWFtIG1heSBhc3N1bWUgdGhlIHRhaWwgaXMgdGhlIG5ld2VzdCBldmVudC4gU2VlXG4gKiB7QGxpbmsgbWF4RXZlbnRTbG90fS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGVuZFVuaXF1ZUV2ZW50cyhcbiAgdGFyZ2V0OiBFdmVudFtdLFxuICBldmVudHM6IHJlYWRvbmx5IEV2ZW50W10sXG4gIHRhcmdldElkcz86IFNldDxzdHJpbmc+XG4pOiB2b2lkIHtcbiAgaWYgKGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBpZHMgPSB0YXJnZXRJZHMgPz8gbmV3IFNldCh0YXJnZXQubWFwKChldmVudCkgPT4gZXZlbnQuZXZlbnRJZCkpO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGlmIChpZHMuaGFzKGV2ZW50LmV2ZW50SWQpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWRzLmFkZChldmVudC5ldmVudElkKTtcbiAgICB0YXJnZXQucHVzaChldmVudCk7XG4gIH1cbn1cblxuLyoqXG4gKiBJbnNlcnRzIGBldmVudGAgaW50byBgdGFyZ2V0YCBhdCB0aGUgcG9zaXRpb24gdGhhdCBrZWVwcyBgdGFyZ2V0YCBvcmRlcmVkIGJ5XG4gKiBhc2NlbmRpbmcgYGV2ZW50SWRgLCBvciBuby1vcHMgaWYgYW4gZXZlbnQgd2l0aCB0aGUgc2FtZSBgZXZlbnRJZGAgaXMgYWxyZWFkeVxuICogcHJlc2VudCAoaWRlbXBvdGVudCkuXG4gKlxuICogYHByZWxvYWRlZEV2ZW50c2AgaXMgbG9hZGVkIGBzb3J0T3JkZXI6ICdhc2MnYCBhbmQgaXMgbmV2ZXIgcmUtc29ydGVkXG4gKiBjbGllbnQtc2lkZSwgc28gYSBgaG9va19yZWNlaXZlZGAgc3BsaWNlZCBpbiBieSB0aGUgbGF6eS1yZXN1bWUgY29uc3VtZXIgbXVzdFxuICogbGFuZCBpbiBgZXZlbnRJZGAgb3JkZXI6IGEgcGxhaW4gYHB1c2hgIHdvdWxkIHBsYWNlIGEgbGF0ZS1jb21taXR0aW5nXG4gKiBlYXJsaWVyIGV2ZW50IGFmdGVyIGV2ZW50cyB0aGF0IHNvcnQgYmVmb3JlIGl0LCBjb3JydXB0aW5nIHJlcGxheS5cbiAqXG4gKiBMZXhpY29ncmFwaGljIHN0cmluZyBvcmRlciBpcyB0aGUgbG9nJ3Mgb3JkZXI6IGEgc2xvdCBpZCBpcyBhIGZpeGVkLXdpZHRoXG4gKiB6ZXJvLXBhZGRlZCBwb3NpdGlvbiwgc28gY29tcGFyaW5nIHRoZSBzdHJpbmdzIGNvbXBhcmVzIHRoZSBwb3NpdGlvbnMuIFRoaXNcbiAqIG5lZWRzIG5vIHBhcnNlIG9mIGl0cyBvd24gZm9yIHRoYXQgcmVhc29uLCBhbmQgdGhlIGNvbXBhcmlzb24gaXMgZXhhY3QgcmF0aGVyXG4gKiB0aGFuIGEgcmVjb25zdHJ1Y3Rpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnNlcnRFdmVudEJ5RXZlbnRJZCh0YXJnZXQ6IEV2ZW50W10sIGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAvLyBMaW5lYXIgc2NhbiBmcm9tIHRoZSBlbmQ6IHRoZSBzcGxpY2VkIGV2ZW50IGlzIGFsbW9zdCBhbHdheXMgdGhlIG5ld2VzdFxuICAvLyAoaXQgc29ydHMgYXQgb3IgbmVhciB0aGUgdGFpbCksIHNvIHRoaXMgZmluZHMgdGhlIHNsb3QgaW4gTygxKeKAk08oaykgZm9yIHRoZVxuICAvLyBjb21tb24gY2FzZSB3aGlsZSBzdGlsbCBoYW5kbGluZyBhbiBvdXQtb2Ytb3JkZXIgbGF0ZSBhcnJpdmFsIGNvcnJlY3RseS5cbiAgbGV0IGkgPSB0YXJnZXQubGVuZ3RoO1xuICB3aGlsZSAoaSA+IDApIHtcbiAgICBjb25zdCBleGlzdGluZyA9IHRhcmdldFtpIC0gMV07XG4gICAgaWYgKGV4aXN0aW5nLmV2ZW50SWQgPT09IGV2ZW50LmV2ZW50SWQpIHtcbiAgICAgIC8vIEFscmVhZHkgcHJlc2VudDoga2VlcCB0aGUgc3BsaWNlIGlkZW1wb3RlbnQuXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChleGlzdGluZy5ldmVudElkIDwgZXZlbnQuZXZlbnRJZCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIGktLTtcbiAgfVxuICB0YXJnZXQuc3BsaWNlKGksIDAsIGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gYXNzZXJ0RXZlbnRQYWdpbmF0aW9uUHJvZ3Jlc3MoXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhhc01vcmU6IGJvb2xlYW4sXG4gIGN1cnNvcjogc3RyaW5nIHwgbnVsbCxcbiAgcmVxdWVzdGVkQ3Vyc29yczogU2V0PHN0cmluZz5cbik6IHZvaWQge1xuICBpZiAoIWhhc01vcmUpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGN1cnNvciA9PT0gbnVsbCkge1xuICAgIHRocm93IGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IoXG4gICAgICBydW5JZCxcbiAgICAgICdyZXR1cm5lZCBtb3JlIHBhZ2VzIHdpdGhvdXQgYSBjdXJzb3InXG4gICAgKTtcbiAgfVxuICBpZiAocmVxdWVzdGVkQ3Vyc29ycy5oYXMoY3Vyc29yKSkge1xuICAgIHRocm93IGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IocnVuSWQsICdyZXBlYXRlZCBhIGN1cnNvcicpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHNob3VsZFJldHJ5V2l0aG91dEV2ZW50Q3Vyc29yKFxuICBlcnJvcjogdW5rbm93bixcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsLFxuICBhbHJlYWR5UmV0cmllZDogYm9vbGVhblxuKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgY3Vyc29yICE9PSBudWxsICYmXG4gICAgIWFscmVhZHlSZXRyaWVkICYmXG4gICAgV29ya2Zsb3dXb3JsZEVycm9yLmlzKGVycm9yKSAmJlxuICAgIGVycm9yLnN0YXR1cyA9PT0gNDAwXG4gICk7XG59XG5cbi8qKlxuICogTG9hZHMgd29ya2Zsb3cgcnVuIGV2ZW50cyBieSBpdGVyYXRpbmcgdGhyb3VnaCBhbGwgcGFnZXMgb2YgcGFnaW5hdGVkXG4gKiByZXN1bHRzLiBFdmVudHMgYXJlIHJldHVybmVkIGluIGNocm9ub2xvZ2ljYWwgKGFzY2VuZGluZykgb3JkZXIgZm9yXG4gKiBkZXRlcm1pbmlzdGljIHdvcmtmbG93IHJlcGxheS5cbiAqXG4gKiBAcGFyYW0gcnVuSWQgLSBUaGUgd29ya2Zsb3cgcnVuIElELlxuICogQHBhcmFtIGFmdGVyQ3Vyc29yIC0gSWYgcHJvdmlkZWQsIG9ubHkgZXZlbnRzIGFmdGVyIHRoaXMgY3Vyc29yIGFyZVxuICogICByZXR1cm5lZCAoaW5jcmVtZW50YWwgbG9hZCkuIElmIG9taXR0ZWQsIGFsbCBldmVudHMgYXJlIHJldHVybmVkLlxuICogICBUaGUgcmV0dXJuZWQgY3Vyc29yIGNhbiBiZSBwYXNzZWQgYmFjayBpbiBvbiBhIHN1YnNlcXVlbnQgY2FsbCBmb3JcbiAqICAgaW5jcmVtZW50YWwgbG9hZGluZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRXb3JrZmxvd1J1bkV2ZW50cyhcbiAgcnVuSWQ6IHN0cmluZyxcbiAgYWZ0ZXJDdXJzb3I/OiBzdHJpbmdcbik6IFByb21pc2U8TG9hZGVkRXZlbnRMb2c+IHtcbiAgY29uc3QgaW5jcmVtZW50YWwgPSBhZnRlckN1cnNvciAhPT0gdW5kZWZpbmVkO1xuICByZXR1cm4gdHJhY2UoJ3dvcmtmbG93LnJlcGxheS5sb2FkJywgYXN5bmMgKHNwYW4pID0+IHtcbiAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1J1bklkKHJ1bklkKSxcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd1JlcGxheUxvYWRTb3VyY2UoXG4gICAgICAgIGluY3JlbWVudGFsID8gJ2V2ZW50c19saXN0X2luY3JlbWVudGFsJyA6ICdldmVudHNfbGlzdCdcbiAgICAgICksXG4gICAgfSk7XG5cbiAgICBjb25zdCBsb2FkZWRFdmVudHM6IEV2ZW50W10gPSBbXTtcbiAgICBjb25zdCBsb2FkZWRFdmVudElkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IHJlcXVlc3RlZEN1cnNvcnMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBsZXQgY3Vyc29yOiBzdHJpbmcgfCBudWxsID0gYWZ0ZXJDdXJzb3IgPz8gbnVsbDtcbiAgICBsZXQgaGFzTW9yZSA9IHRydWU7XG4gICAgbGV0IHBhZ2VzTG9hZGVkID0gMDtcbiAgICBsZXQgcmV0cmllZFdpdGhvdXRDdXJzb3IgPSBmYWxzZTtcbiAgICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkTGF6eSgpO1xuICAgIGNvbnN0IGxvYWRTdGFydCA9IERhdGUubm93KCk7XG4gICAgd2hpbGUgKGhhc01vcmUpIHtcbiAgICAgIC8vIFRPRE86IHdlJ3JlIGN1cnJlbnRseSBsb2FkaW5nIGFsbCB0aGUgZGF0YSB3aXRoIHJlc29sdmVSZWYgYmVoYXZpb3IuIFdlIG5lZWQgdG8gdXBkYXRlIHRoaXNcbiAgICAgIC8vIHRvIGxhenlsb2FkIHRoZSBkYXRhIGZyb20gdGhlIHdvcmxkIGluc3RlYWQgc28gdGhhdCB3ZSBjYW4gb3B0aW1pemUgYW5kIG1ha2UgdGhlIGV2ZW50IGxvZyBsb2FkaW5nXG4gICAgICAvLyBtdWNoIGZhc3RlciBhbmQgbWVtb3J5IGVmZmljaWVudFxuICAgICAgY29uc3QgcGFnZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHJlcXVlc3RlZEN1cnNvciA9IGN1cnNvcjtcbiAgICAgIHJlY29yZFJlcXVlc3RlZEV2ZW50Q3Vyc29yKHJ1bklkLCByZXF1ZXN0ZWRDdXJzb3IsIHJlcXVlc3RlZEN1cnNvcnMpO1xuXG4gICAgICBsZXQgcmVzcG9uc2U6IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2Ygd29ybGQuZXZlbnRzLmxpc3Q+PjtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3BvbnNlID0gYXdhaXQgd29ybGQuZXZlbnRzLmxpc3Qoe1xuICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgIHBhZ2luYXRpb246IHtcbiAgICAgICAgICAgIHNvcnRPcmRlcjogJ2FzYycsXG4gICAgICAgICAgICBjdXJzb3I6IHJlcXVlc3RlZEN1cnNvciA/PyB1bmRlZmluZWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgc2hvdWxkUmV0cnlXaXRob3V0RXZlbnRDdXJzb3IoXG4gICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgIHJlcXVlc3RlZEN1cnNvcixcbiAgICAgICAgICAgIHJldHJpZWRXaXRob3V0Q3Vyc29yXG4gICAgICAgICAgKVxuICAgICAgICApIHtcbiAgICAgICAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAnRXZlbnQgY3Vyc29yIHdhcyByZWplY3RlZDsgcmV0cnlpbmcgd2l0aCBhIGZ1bGwgZXZlbnQgcmVsb2FkLicsXG4gICAgICAgICAgICB7IHdvcmtmbG93UnVuSWQ6IHJ1bklkIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIGxvYWRlZEV2ZW50cy5sZW5ndGggPSAwO1xuICAgICAgICAgIGxvYWRlZEV2ZW50SWRzLmNsZWFyKCk7XG4gICAgICAgICAgcmVxdWVzdGVkQ3Vyc29ycy5jbGVhcigpO1xuICAgICAgICAgIGN1cnNvciA9IG51bGw7XG4gICAgICAgICAgcmV0cmllZFdpdGhvdXRDdXJzb3IgPSB0cnVlO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuXG4gICAgICBhcHBlbmRVbmlxdWVFdmVudHMobG9hZGVkRXZlbnRzLCByZXNwb25zZS5kYXRhLCBsb2FkZWRFdmVudElkcyk7XG4gICAgICBoYXNNb3JlID0gcmVzcG9uc2UuaGFzTW9yZTtcbiAgICAgIGFzc2VydEV2ZW50UGFnaW5hdGlvblByb2dyZXNzKFxuICAgICAgICBydW5JZCxcbiAgICAgICAgaGFzTW9yZSxcbiAgICAgICAgcmVzcG9uc2UuY3Vyc29yLFxuICAgICAgICByZXF1ZXN0ZWRDdXJzb3JzXG4gICAgICApO1xuICAgICAgLy8gUHJlc2VydmUgdGhlIGxhc3Qgbm9uLW51bGwgY3Vyc29yIGFjcm9zcyBwYWdlcy4gQSBXb3JsZCBtYXlcbiAgICAgIC8vIGxlZ2l0aW1hdGVseSByZXR1cm4gYHsgZGF0YTogW10sIGN1cnNvcjogbnVsbCwgaGFzTW9yZTogZmFsc2UgfWBcbiAgICAgIC8vIG9uIGEgdHJhaWxpbmcgZW1wdHkgcGFnZSwgZm9yIGV4YW1wbGUgd2hlbiB0aGUgcHJldmlvdXMgcGFnZSdzXG4gICAgICAvLyB1bmRlcmx5aW5nIERCIHF1ZXJ5IGhpdCB0aGUgbGltaXQgZXhhY3RseSBhbmQgcmV0dXJuZWQgYVxuICAgICAgLy8gcHJlY2F1dGlvbmFyeSBgTGFzdEV2YWx1YXRlZEtleWAuIE92ZXJ3cml0aW5nIHdpdGggdGhhdCBudWxsXG4gICAgICAvLyB3b3VsZCBsb3NlIHRoZSBwb3NpdGlvbiBwYXN0IHRoZSBsYXN0IHJlYWwgZXZlbnQgd2UgbG9hZGVkIGFuZFxuICAgICAgLy8gZm9yY2UgdGhlIHJ1bnRpbWUgaW50byB0aGUgXCJubyBjdXJzb3IgYWZ0ZXIgaW5pdGlhbCBsb2FkXCIgZnVsbC1cbiAgICAgIC8vIHJlbG9hZCBmYWxsYmFjayBvbiBldmVyeSBzdWJzZXF1ZW50IHJlcGxheSBpdGVyYXRpb24uXG4gICAgICBjdXJzb3IgPSByZXNwb25zZS5jdXJzb3IgPz8gY3Vyc29yO1xuICAgICAgcGFnZXNMb2FkZWQrKztcblxuICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnTG9hZGVkIGV2ZW50IHBhZ2UnLCB7XG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICBpbmNyZW1lbnRhbCxcbiAgICAgICAgcGFnZTogcGFnZXNMb2FkZWQsXG4gICAgICAgIHBhZ2VFdmVudHM6IHJlc3BvbnNlLmRhdGEubGVuZ3RoLFxuICAgICAgICB0b3RhbEV2ZW50czogbG9hZGVkRXZlbnRzLmxlbmd0aCxcbiAgICAgICAgaGFzTW9yZSxcbiAgICAgICAgcGFnZU1zOiBEYXRlLm5vdygpIC0gcGFnZVN0YXJ0LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnRXZlbnQgbG9hZCBjb21wbGV0ZScsIHtcbiAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgaW5jcmVtZW50YWwsXG4gICAgICB0b3RhbEV2ZW50czogbG9hZGVkRXZlbnRzLmxlbmd0aCxcbiAgICAgIHBhZ2VzTG9hZGVkLFxuICAgICAgdG90YWxNczogRGF0ZS5ub3coKSAtIGxvYWRTdGFydCxcbiAgICB9KTtcblxuICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXZlbnRzQ291bnQobG9hZGVkRXZlbnRzLmxlbmd0aCksXG4gICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFdmVudHNQYWdlc0xvYWRlZChwYWdlc0xvYWRlZCksXG4gICAgfSk7XG5cbiAgICByZXR1cm4geyBldmVudHM6IGxvYWRlZEV2ZW50cywgY3Vyc29yIH07XG4gIH0pO1xufVxuXG4vKipcbiAqIFRoZSBydW50aW1lJ3MgbG9hZGVkIGV2ZW50LWxvZyBzbmFwc2hvdDogdGhlIGV2ZW50cyByZXBsYXllZCBzbyBmYXIgYW5kIHRoZVxuICogY3Vyc29yIHBvc2l0aW9uZWQgYWZ0ZXIgdGhlbS4gSGFuZGVkIHRvIGhlbHBlcnMgdGhhdCBkZXJpdmUgdGhlIHByZWNvbmRpdGlvblxuICogc25hcHNob3QgZnJvbSBpdDsgdGhleSBkbyBub3QgbXV0YXRlIGl0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExvYWRlZEV2ZW50TG9nIHtcbiAgZXZlbnRzOiBFdmVudFtdO1xuICBjdXJzb3I6IHN0cmluZyB8IG51bGw7XG59XG5cbi8qKlxuICogRXh0ZW5kIGEgbG9hZGVkIGxvZyB3aXRoIGEgcGFnZSB0aGF0IGNvbnRpbnVlcyBpdCDigJQgYSBsaXN0ZWQgcGFnZSwgb3IgdGhlXG4gKiBpbmxpbmUgZGVsdGEgYSB3cml0ZSBoYW5kZWQgYmFjayDigJQgYW5kIG1vdmUgaXRzIHJlYWQgcG9zaXRpb24gd2l0aCBpdC5cbiAqXG4gKiBUaGUgY3Vyc29yIGlzIG9ubHkgYWR2YW5jZWQgd2hlbiB0aGUgcGFnZSBjYXJyaWVzIG9uZSwgc28gYSBzb3VyY2Ugd2l0aCBub1xuICogcG9zaXRpb24gb2YgaXRzIG93biAoYSBza2lwcGVkLXNsb3QgcmVwb3J0KSBjYW5ub3Qgd2FsayB0aGUgcmVhZCBwb3NpdGlvblxuICogcGFzdCBldmVudHMgaXQgZGlkIG5vdCBjYXJyeS4gQXBwZW5kaW5nIGRvZXMgbm90IHJlLXNvcnQ7IHNlZVxuICoge0BsaW5rIGFwcGVuZFVuaXF1ZUV2ZW50c30gZm9yIHdoeSByZWNlaXB0IG9yZGVyIGlzIHRoZSBvcmRlciB0byBrZWVwLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwZW5kRXZlbnRMb2coXG4gIGxvZzogTG9hZGVkRXZlbnRMb2csXG4gIGFwcGVuZGVkOiB7IGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXTsgY3Vyc29yPzogc3RyaW5nIHwgbnVsbCB9XG4pOiB2b2lkIHtcbiAgYXBwZW5kVW5pcXVlRXZlbnRzKGxvZy5ldmVudHMsIGFwcGVuZGVkLmV2ZW50cyk7XG4gIGxvZy5jdXJzb3IgPSBhcHBlbmRlZC5jdXJzb3IgPz8gbG9nLmN1cnNvcjtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGEgcmVwbGF5IHJlZnVzZXMgdG8gcnVuIG92ZXIgYSBsb2cgd2l0aCBhIGhvbGUgaW4gaXQgKHNlZVxuICoge0BsaW5rIGZpbmRFdmVudFNsb3RHYXB9KS4gKipPbiBieSBkZWZhdWx0Kio7IHNldFxuICogYFdPUktGTE9XX1NMT1RfR0FQX0NIRUNLPTBgIHRvIHJlcGxheSBhY3Jvc3MgaG9sZXMgaW5zdGVhZC5cbiAqXG4gKiBBIFdvcmxkIHRoYXQgYWxsb2NhdGVzIGEgcG9zaXRpb24gYXQgdGhlIG1vbWVudCBpdCBjb21taXRzIGxlYXZlcyBubyBob2xlXG4gKiBiZWhpbmQgd2hlbiBhIHdyaXRlIGZhaWxzLCBzbyBkZW5zaXR5IGlzIGEgcHJvcGVydHkgdGhlIGxvZyBoYXMgYnlcbiAqIGNvbnN0cnVjdGlvbiByYXRoZXIgdGhhbiBvbmUgdGhpcyBjaGVjayBtYWludGFpbnMuIFdoYXQgdGhlIGNoZWNrIGlzIGZvciBpc1xuICogdGhlIHJlYWRzIGFuZCB0aGUgV29ybGRzIHdoZXJlIHRoYXQgZG9lcyBub3QgaG9sZCwgYW5kIGJ5IHRoZSB0aW1lIGl0IHJ1bnNcbiAqIHRoZSBiZW5pZ24gZXhwbGFuYXRpb25zIGFyZSBzcGVudDogYSBwb3NpdGlvbiBtaXNzaW5nIGJlY2F1c2UgYSBjb25jdXJyZW50XG4gKiBjb21taXQgaXMgbm90IHZpc2libGUgeWV0IGNsZWFycyBvbiBhIHJlLXJlYWQsIHdoaWNoIGlzIHdoYXRcbiAqIHtAbGluayBzZXR0bGVFdmVudFNsb3RHYXB9IGRvZXMgZmlyc3QuXG4gKlxuICogV2hhdCBpcyBsZWZ0IGlzIGEgaG9sZSB0aGF0IHBlcnNpc3RzLCBhbmQgaXRzIHR3byBjYXVzZXMgYXJlXG4gKiBpbmRpc3Rpbmd1aXNoYWJsZSBmcm9tIHRoZSBsb2cuIEVpdGhlciBhIFdvcmxkIGFsbG9jYXRlZCB0aGUgcG9zaXRpb24gb3V0c2lkZVxuICogdGhlIGNvbW1pdCBhbmQgbG9zdCB0aGUgd3JpdGUsIGluIHdoaWNoIGNhc2Ugbm90aGluZyBoYXBwZW5lZCB0aGVyZSBhbmRcbiAqIHJlcGxheWluZyBwYXN0IGl0IGlzIGNvcnJlY3QsIG9yIGFuIGV2ZW50IHRoYXQgZGlkIGhhcHBlbiBpcyBtaXNzaW5nLCBpblxuICogd2hpY2ggY2FzZSByZXBsYXlpbmcgcGFzdCBpdCBkZWNpZGVzIGEgYnJhbmNoIG9uIGFic2VuY2UgYW5kIHByb2R1Y2VzIGEgd3JvbmdcbiAqIHJlc3VsdCB3aXRoIG5vdGhpbmcgdG8gc2hvdyBmb3IgaXQuIEZhaWxpbmcgaXMgdGhlIHJlY292ZXJhYmxlIHNpZGUgb2YgdGhhdFxuICogdHJhZGUsIGFuZCB0aGlzIGlzIHRoZSB3YXkgYmFjayBvdXQgaWYgYSBmbGVldCB0dXJucyBvdXQgdG8gY2FycnkgaG9sZXMgb2ZcbiAqIHRoZSBmaXJzdCBraW5kLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTbG90R2FwQ2hlY2tFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfU0xPVF9HQVBfQ0hFQ0sgIT09ICcwJztcbn1cblxuLypcbiAqIE1lcmdpbmcgaW50byBhIGxvZyBhIHJlcGxheSBpcyBtaWR3YXkgdGhyb3VnaCByZWFkaW5nLlxuICpcbiAqIFRocmVlIHBhdGhzIGFkZCBldmVudHMgdG8gYSBsb2FkZWQgbG9nIGFmdGVyIHRoZSByZXBsYXkgaGFzIHN0YXJ0ZWQ6IGFcbiAqIGJ1bXAtYW5kLXJlcG9ydCB3cml0ZSBoYW5kcyBiYWNrIHRoZSBzbG90cyBpdCBza2lwcGVkICh7QGxpbmtcbiAqIG1lcmdlUmVwb3J0ZWRFdmVudHN9KSwgYW4gaW5saW5lIGRlbHRhIGV4dGVuZHMgdGhlIHRhaWwgKGBhYnNvcmJDcmVhdGVEZWx0YWBcbiAqIGluIGBydW50aW1lLnRzYCksIGFuZCBhIGxpc3RlZCBwYWdlIGFwcGVuZHMgKHtAbGluayBhcHBlbmRVbmlxdWVFdmVudHN9KS5cbiAqIFRoZXkgbG9vayBhbGFybWluZyAodGhlIHJlcGxheSBpcyByZWFkaW5nIGFuIGFycmF5IHdoaWxlIHNvbWV0aGluZyBlbHNlXG4gKiB3cml0ZXMgdG8gaXQpIGFuZCB0aGV5IGFyZSBzYWZlIGZvciBvbmUgcmVhc29uIHdvcnRoIHN0YXRpbmcgcGxhaW5seSwgc2luY2VcbiAqIGV2ZXJ5IGNvcnJlY3RuZXNzIGFyZ3VtZW50IGluIHRoaXMgZmlsZSBsZWFucyBvbiBpdC5cbiAqXG4gKiAqKkFuIGV2ZW50IGluIHRoZSBsb2cgaXMgYSBmYWN0LCBhbmQgYSBsb25nZXIgbG9nIGNhbm5vdCByZXRyYWN0IG9uZS4qKiBUaGVcbiAqIGxvZyBpcyBhcHBlbmQtb25seSBhbmQgcG9zaXRpb25zIGFyZSBuZXZlciByZXVzZWQsIHNvIGEgcmVwbGF5IHRoYXQgcHJvZHVjZWRcbiAqIGV2ZW50IEUgZnJvbSB0aGUgcHJlZml4IGl0IGhhZCBsb2FkZWQgaGFzIG1hZGUgRSB0cnVlIGZvciBldmVyeSByZXBsYXkgdGhhdFxuICogZm9sbG93cy4gQSBsYXRlciByZXBsYXkgcmVhZGluZyBhIGZ1bGxlciBsb2cgZG9lcyBub3QgZ2V0IHRvIGRlY2lkZSBFIHNob3VsZFxuICogbm90IGJlIHRoZXJlOyBpdCBjb25zdW1lcyBFIGFuZCByZWNvbmNpbGVzIHRvIGl0LCB3aGljaCBpcyB3aGF0IHRoZSBldmVudHNcbiAqIGNvbnN1bWVyIGRvZXMgd2hlbiBpdCB3YWxrcyBhIGxvZyBob2xkaW5nIHdyaXRlcyBmcm9tIGEgcmVwbGF5IHRoYXQgcmFjZWQgaXQuXG4gKlxuICogTWVyZ2luZyBpcyB0aGVyZWZvcmUgbW9ub3RvbmU6IGl0IGNhbiBvbmx5IGFkZCBmYWN0cyB0aGlzIHJlcGxheSBoYXMgeWV0IHRvXG4gKiByZWNvbmNpbGUgdG8sIG5ldmVyIHJlbW92ZSBvbmUgaXQgYWxyZWFkeSBoYXMuIFRoYXQgaXMgd2h5IGFic29yYmluZyBpc1xuICogYWx3YXlzIG9wdGlvbmFsIGFuZCBuZXZlciB3cm9uZyB0byBkZWNsaW5lIChhbiB1bmFic29yYmVkIGV2ZW50IGlzIG9uZSB0aGVcbiAqIG5leHQgcmVhZCByZXR1cm5zKSwgYW5kIHdoeSB0aGUgZ3VhcmRzIGJlbG93IGNhbiBhZmZvcmQgdG8gYmUgc3RyaWN0LlxuICovXG5cbi8qKlxuICogTWVyZ2UgdGhlIGV2ZW50cyBhIGJ1bXAtYW5kLXJlcG9ydCB3cml0ZSBoYW5kZWQgYmFjayBpbnRvIHRoZSBsb2cgaXQgd2FzXG4gKiBkZXJpdmVkIGZyb20sIGFuZCBhbnN3ZXIgaG93IG1hbnkgb2YgdGhlbSB3ZXJlIG5ldy5cbiAqXG4gKiBVbmxpa2Uge0BsaW5rIGFwcGVuZFVuaXF1ZUV2ZW50c30sIHRoaXMgcmUtc29ydHMuIFRoZSByZXBvcnRlZCBldmVudHMgb2NjdXB5XG4gKiBzbG90cyAqYmVsb3cqIHRoZSB3cml0ZSB0aGF0IHJlcG9ydGVkIHRoZW0sIHNvIGFwcGVuZGluZyB0aGVtIHdvdWxkIHB1dCB0aGVtXG4gKiBhZnRlciBldmVudHMgdGhleSBwcmVjZWRlLiBTb3J0aW5nIGJ5IGlkIHJlc3RvcmVzIHRoZSBXb3JsZCdzIGNhbm9uaWNhbCBvcmRlclxuICogcmF0aGVyIHRoYW4gZ3Vlc3NpbmcgYXQgaXQ6IGEgc2xvdCBpZCBpcyB0aGF0IG9yZGVyLCB3cml0dGVuIGRvd24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVJlcG9ydGVkRXZlbnRzKFxuICB0YXJnZXQ6IEV2ZW50W10sXG4gIGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXVxuKTogbnVtYmVyIHtcbiAgY29uc3QgYmVmb3JlID0gdGFyZ2V0Lmxlbmd0aDtcbiAgYXBwZW5kVW5pcXVlRXZlbnRzKHRhcmdldCwgZXZlbnRzKTtcbiAgY29uc3QgYWRkZWQgPSB0YXJnZXQubGVuZ3RoIC0gYmVmb3JlO1xuICBpZiAoYWRkZWQgPiAwKSB7XG4gICAgdGFyZ2V0LnNvcnQoKGEsIGIpID0+XG4gICAgICBhLmV2ZW50SWQgPCBiLmV2ZW50SWQgPyAtMSA6IGEuZXZlbnRJZCA+IGIuZXZlbnRJZCA/IDEgOiAwXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYWRkZWQ7XG59XG5cbi8qKiBXaGF0IHtAbGluayBhYnNvcmJTa2lwcGVkU2xvdFJlcG9ydH0gZGlkIHdpdGggYSB3cml0ZSdzIHJlcG9ydC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2tpcHBlZFNsb3RSZXBvcnQge1xuICAvKiogSG93IG1hbnkgb2YgdGhlIHJlcG9ydGVkIGV2ZW50cyB3ZXJlIG5ldyB0byB0aGUgbG9nLiBaZXJvIGlmIGRyb3BwZWQuICovXG4gIGFkZGVkOiBudW1iZXI7XG4gIC8qKiBIb3cgbWFueSBldmVudHMgdGhlIHJlcG9ydCBvZmZlcmVkLCB3aGV0aGVyIG9yIG5vdCB0aGV5IHdlcmUgdGFrZW4uICovXG4gIG9mZmVyZWQ6IG51bWJlcjtcbiAgLyoqIFRoZSByZXBvcnQgd2FzIHRydW5jYXRlZCwgc28gaXQgd2FzIGRyb3BwZWQgd2hvbGUgaW5zdGVhZCBvZiBtZXJnZWQuICovXG4gIHRydW5jYXRlZDogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBBcHBseSBhIHdyaXRlJ3Mgc2tpcHBlZC1zbG90IHJlcG9ydCB0byB0aGUgbG9nIGl0IHdhcyBkZXJpdmVkIGZyb20sIGRlY2lkaW5nXG4gKiB3aGV0aGVyIHRoZSByZXBvcnQgbWF5IGJlIHRha2VuIGF0IGFsbC5cbiAqXG4gKiBFdmVyeSByZXBsYXktY29udGV4dCB3cml0ZSBjYW4gY29tZSBiYWNrIGNhcnJ5aW5nIHRoZSBldmVudHMgb24gdGhlIHNsb3RzIGl0XG4gKiBza2lwcGVkIG92ZXIsIGFuZCBldmVyeSBjYWxsZXIgd2FudHMgdGhlIHNhbWUgdGhpbmcgZnJvbSB0aGVtOiBmb2xkIHRoZW0gaW5cbiAqIHNvIHRoZSB3cml0ZXMgdGhhdCBmb2xsb3cgbmFtZSBhIHBvc2l0aW9uIGFib3ZlIHRoZW0sIGFuZCBzbyB0aGUgcmVwbGF5XG4gKiByZXN1bWluZyBmcm9tIHRoaXMgbG9nIHNlZXMgdGhlbSB3aXRob3V0IGEgcmVsb2FkLlxuICpcbiAqIFRoZSBvbmUgcG9saWN5IGlzIHRoYXQgYSAqKnRydW5jYXRlZCByZXBvcnQgaXMgZHJvcHBlZCB3aG9sZSoqLiBJdCBjb3ZlcnMgYVxuICogc3BhbiBvZiBwb3NpdGlvbnMgYnV0IGNhcnJpZXMgb25seSBzb21lIG9mIHRoZSBldmVudHMgb24gdGhlbSwgc28gbWVyZ2luZyBpdFxuICogd291bGQgcmFpc2UgdGhlIGxvZydzIGhpZ2hlc3QgcG9zaXRpb24gcGFzdCBhIHBvc2l0aW9uIHdob3NlIGV2ZW50IGlzXG4gKiBtaXNzaW5nLiBMYXRlciB3cml0ZXMgcmVhZCB0aGF0IG1heGltdW0gdG8gc2F5IHdoYXQgdGhleSBoYXZlIHNlZW4sIHNvIGVhY2hcbiAqIHdvdWxkIGNsYWltIGEgcG9zaXRpb24gaXQgbmV2ZXIgc2F3LCBhbmQgdGhlIFdvcmxkIG9ubHkgcmVwb3J0cyB0aGUgc3BhbiBhXG4gKiB3cml0ZSBza2lwczogaXQgd291bGQgbmV2ZXIgc2VuZCB0aGUgbWlzc2luZyBvbmUuIERyb3BwaW5nIGNvc3RzIG9uZSBtb3JlXG4gKiByb3VuZCBvZiB0aGUgc2FtZSBldmVudHMgb24gdGhlIG5leHQgd3JpdGUgYW5kIGtlZXBzIHRoZSBsb2cgYSBwcmVmaXggb2YgdGhlXG4gKiB0cnV0aCwgd2hpY2ggdGhlIG5vdGUgYWJvdmUge0BsaW5rIG1lcmdlUmVwb3J0ZWRFdmVudHN9IGV4cGxhaW5zIGlzIGFsd2F5cyBhblxuICogYXZhaWxhYmxlIGFuc3dlci5cbiAqXG4gKiBDYWxsZXJzIHRoYXQgbG9nIGRvIHNvIGZyb20gdGhlIHJldHVybmVkIGNvdW50czsgdGhlIGRlY2lzaW9uIGlzIG5vdCB0aGVpcnNcbiAqIHRvIHJlLWRlcml2ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFic29yYlNraXBwZWRTbG90UmVwb3J0KFxuICB0YXJnZXQ6IEV2ZW50W10sXG4gIHJlc3VsdDogeyBldmVudHM/OiByZWFkb25seSBFdmVudFtdOyBoYXNNb3JlPzogYm9vbGVhbiB9XG4pOiBTa2lwcGVkU2xvdFJlcG9ydCB7XG4gIGNvbnN0IG9mZmVyZWQgPSByZXN1bHQuZXZlbnRzPy5sZW5ndGggPz8gMDtcbiAgaWYgKG9mZmVyZWQgPT09IDApIHtcbiAgICByZXR1cm4geyBhZGRlZDogMCwgb2ZmZXJlZDogMCwgdHJ1bmNhdGVkOiBmYWxzZSB9O1xuICB9XG4gIGlmIChyZXN1bHQuaGFzTW9yZSA9PT0gdHJ1ZSkge1xuICAgIHJldHVybiB7IGFkZGVkOiAwLCBvZmZlcmVkLCB0cnVuY2F0ZWQ6IHRydWUgfTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGFkZGVkOiBtZXJnZVJlcG9ydGVkRXZlbnRzKHRhcmdldCwgcmVzdWx0LmV2ZW50cyA/PyBbXSksXG4gICAgb2ZmZXJlZCxcbiAgICB0cnVuY2F0ZWQ6IGZhbHNlLFxuICB9O1xufVxuXG4vKipcbiAqIFRoZSBoaWdoZXN0IHNsb3QgdGhlIGxvYWRlZCBsb2cgb2NjdXBpZXMsIG9yIGB1bmRlZmluZWRgIGZvciBhbiBlbXB0eSBsb2cuXG4gKlxuICogVGhlIG1heGltdW0sIG5vdCB0aGUgY291bnQsIGFuZCB0aGUgdHdvIGFyZSBub3QgaW50ZXJjaGFuZ2VhYmxlIGV2ZW4gdGhvdWdoXG4gKiBhIGhlYWx0aHkgbG9nIG1ha2VzIHRoZW0gZXF1YWwuIEEgV29ybGQgaGFuZHMgYSBwb3NpdGlvbiB0byB0aGUgaW5zZXJ0IHRoYXRcbiAqIG9jY3VwaWVzIGl0LCBzbyBhIHdyaXRlIHRoYXQgbmV2ZXIgbGFuZHMgbGVhdmVzIG5vIGhvbGUgYmVoaW5kIGFuZCB0aGUgbG9nXG4gKiBzdGF5cyBkZW5zZS4gV2hhdCB0aGUgY291bnQgY2Fubm90IHN1cnZpdmUgaXMgYSAqcGFydGlhbCogcmVhZDogYSBsb2dcbiAqIGFzc2VtYmxlZCBmcm9tIGEgdHJ1bmNhdGVkIHJlcG9ydCwgb3IgcmVhZCB3aGlsZSBhIGNvbmN1cnJlbnQgd3JpdGUgaXNcbiAqIGNvbW1pdHRpbmcsIGhvbGRzIGZld2VyIGV2ZW50cyB0aGFuIGl0cyBoaWdoZXN0IHBvc2l0aW9uLiBDb3VudGluZyB0aG9zZVxuICogd291bGQgbWFrZSB0aGUgbmV4dCB3cml0ZSBjbGFpbSB0byBoYXZlIHNlZW4gbGVzcyB0aGFuIGl0IGhhcywgc28gdGhlIFdvcmxkXG4gKiB3b3VsZCByZXBvcnQgdGhlIHNhbWUgZXZlbnRzIGJhY2sgdG8gaXQgb24gZXZlcnkgYXR0ZW1wdC5cbiAqXG4gKiBBIGhvbGUgYmVsb3cgdGhlIG1heGltdW0gaXMgdGhlcmVmb3JlIGEgcHJvcGVydHkgb2YgdGhlIHJlYWQsIG5vdCBvZiB0aGUgbG9nLFxuICogd2hpY2ggaXMgd2hhdCBsZXRzIHtAbGluayBzZXR0bGVFdmVudFNsb3RHYXB9IHJlLXJlYWQgaW5zdGVhZCBvZiBnaXZpbmcgdXAuXG4gKlxuICogQHRocm93cyBpZiBhbnkgZXZlbnQgaWQgY2FycmllcyBubyBzbG90LiBFdmVyeSBXb3JsZCB0aGUgcnVudGltZSByZXBsYXlzXG4gKiBhZ2FpbnN0IG51bWJlcnMgZXZlbnRzIGJ5IHNsb3QsIHNvIGFuIGlkIHRoYXQgZG9lcyBub3QgaXMgYSBicm9rZW4gbG9nIHJhdGhlclxuICogdGhhbiBhbiBvbGRlciBvbmUsIGFuZCBhIG1heGltdW0gZGVyaXZlZCBieSBza2lwcGluZyBpdCB3b3VsZCB1bmRlcnN0YXRlIHRoZVxuICogbG9nIHRvIGV2ZXJ5IHdyaXRlIHRoYXQgcmVhZHMgaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXhFdmVudFNsb3QoZXZlbnRzOiByZWFkb25seSBFdmVudFtdKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgbGV0IG1heDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGNvbnN0IHNsb3QgPSByZXF1aXJlRXZlbnRTbG90KGV2ZW50LmV2ZW50SWQpO1xuICAgIGlmIChtYXggPT09IHVuZGVmaW5lZCB8fCBzbG90ID4gbWF4KSB7XG4gICAgICBtYXggPSBzbG90O1xuICAgIH1cbiAgfVxuICByZXR1cm4gbWF4O1xufVxuXG4vKiogQSBwb3NpdGlvbiB0aGUgbG9nIHNraXBzIG92ZXIsIGRlc2NyaWJlZCB3ZWxsIGVub3VnaCB0byBuYW1lIGluIGFuIGVycm9yLiAqL1xuZXhwb3J0IGludGVyZmFjZSBFdmVudFNsb3RHYXAge1xuICAvKiogVGhlIGxvd2VzdCBzbG90IGJlbG93IHRoZSBsb2cncyBtYXhpbXVtIHRoYXQgbm8gZXZlbnQgb2NjdXBpZXMuICovXG4gIGZpcnN0TWlzc2luZ1Nsb3Q6IG51bWJlcjtcbiAgLyoqIEhvdyBtYW55IHNsb3RzIGJlbG93IHRoZSBtYXhpbXVtIG5vIGV2ZW50IG9jY3VwaWVzLiAqL1xuICBtaXNzaW5nQ291bnQ6IG51bWJlcjtcbiAgLyoqIFRoZSBoaWdoZXN0IHNsb3QgdGhlIGxvZyBvY2N1cGllcy4gKi9cbiAgbWF4U2xvdDogbnVtYmVyO1xufVxuXG4vKipcbiAqIFRoZSBob2xlIGluIGEgbG9hZGVkIGxvZywgb3IgYHVuZGVmaW5lZGAgd2hlbiB0aGVyZSBpcyBub25lIHRvIGZpbmQuXG4gKlxuICogVGhlIFdvcmxkIGFsbG9jYXRlcyBldmVyeSBwb3NpdGlvbiwgc28gYSBsb2cgdGhhdCBob2xkcyBgbmAgZXZlbnRzIGJlbG93IHNsb3RcbiAqIGBuYCBpcyBtaXNzaW5nIG9uZS4gVGhhdCBtYXR0ZXJzIGJlZm9yZSBhIHJlcGxheVxuICogYW5kIG5vd2hlcmUgZWxzZTogdGhlIHJlcGxheSByZWFkcyB0aGUgbG9nIGFzIHRoZSBjb21wbGV0ZSByZWNvcmQgb2Ygd2hhdCBoYXNcbiAqIGhhcHBlbmVkLCBhbmQgYW4gYWJzZW50IHBvc2l0aW9uIGlzIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYW4gZXZlbnQgdGhhdFxuICogbmV2ZXIgb2NjdXJyZWQuIFRoZSBicmFuY2ggaXQgd291bGQgaGF2ZSBkZWNpZGVkIGdldHMgZGVjaWRlZCB0aGUgb3RoZXIgd2F5LFxuICogYW5kIHRoZSBydW4gZGl2ZXJnZXMgcXVpZXRseSByYXRoZXIgdGhhbiBmYWlsaW5nLlxuICpcbiAqIE9yZGVyLWluZGVwZW5kZW50LCB1bmxpa2UgdGhlIGVxdWl2YWxlbnQgYXVkaXQgdGhlIFdvcmxkIHJ1bnMgb3ZlciBhIHBhZ2UgaXRcbiAqIGp1c3QgcmVhZC4gQSBsb2FkZWQgbG9nIGlzIGFzc2VtYmxlZCBmcm9tIGxpc3RlZCBwYWdlcyBwbHVzIHdoYXRldmVyIGFcbiAqIGJ1bXAtYW5kLXJlcG9ydCB3cml0ZSBoYW5kZWQgYmFjaywgYW5kIHdoaWxlIHtAbGluayBtZXJnZVJlcG9ydGVkRXZlbnRzfVxuICogcmVzdG9yZXMgaWQgb3JkZXIsIGEgY2hlY2sgdGhhdCBjYW4gZmFpbCBhIGhlYWx0aHkgcnVuIHNob3VsZCBub3QgZGVwZW5kIG9uXG4gKiB0aGF0IGhhdmluZyBoYXBwZW5lZC5cbiAqXG4gKiBUaGUgZmlyc3Qgc2xvdCBpcyBuZXZlciBjb3VudGVkLiBJdCBiZWxvbmdzIHRvIGBydW5fY3JlYXRlZGAsIHdoaWNoIGBzdGFydCgpYFxuICogcG9zdHMgY29uY3VycmVudGx5IHdpdGggdGhlIHF1ZXVlIHNlbmQsIHNvIGEgbG9nIHJlYWQgaW4gdGhhdCB3aW5kb3dcbiAqIGxlZ2l0aW1hdGVseSBiZWdpbnMgYXQgdGhlIHNlY29uZCBzbG90IGFuZCBmaWxscyBpbiBvbiBpdHMgb3duLiBFdmVyeSByZXBsYXlcbiAqIHRoYXQgcmFjZXMgYSBydW4ncyBvd24gc3RhcnQgd291bGQgb3RoZXJ3aXNlIHJlcG9ydCBhIGhvbGUuXG4gKlxuICogUmV0dXJucyBgdW5kZWZpbmVkYCBmb3IgYW4gZW1wdHkgbG9nLCB3aGljaCBoYXMgbm8gZGVuc2l0eSB0byBjaGVjay5cbiAqXG4gKiBAdGhyb3dzIGlmIGFueSBldmVudCBpZCBjYXJyaWVzIG5vIHNsb3QsIGZvciB0aGUgcmVhc29uIHtAbGluayBtYXhFdmVudFNsb3R9XG4gKiBnaXZlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRFdmVudFNsb3RHYXAoXG4gIGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXVxuKTogRXZlbnRTbG90R2FwIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgb2NjdXBpZWQgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgbGV0IG1heFNsb3QgPSAwO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGNvbnN0IHNsb3QgPSByZXF1aXJlRXZlbnRTbG90KGV2ZW50LmV2ZW50SWQpO1xuICAgIG9jY3VwaWVkLmFkZChzbG90KTtcbiAgICBpZiAoc2xvdCA+IG1heFNsb3QpIHtcbiAgICAgIG1heFNsb3QgPSBzbG90O1xuICAgIH1cbiAgfVxuICBpZiAobWF4U2xvdCA9PT0gMCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgZmxvb3IgPSBvY2N1cGllZC5oYXMoRklSU1RfRVZFTlRfU0xPVClcbiAgICA/IEZJUlNUX0VWRU5UX1NMT1RcbiAgICA6IEZJUlNUX0VWRU5UX1NMT1QgKyAxO1xuICAvLyBFdmVyeSBzbG90IGlzIGF0IG9yIGFib3ZlIGBmbG9vcmAgYnkgY29uc3RydWN0aW9uLCBzbyB0aGUgbG9nIGlzIGRlbnNlXG4gIC8vIGV4YWN0bHkgd2hlbiBpdCBob2xkcyBvbmUgZXZlbnQgcGVyIHBvc2l0aW9uIGluIGBbZmxvb3IsIG1heFNsb3RdYC4gVGhlXG4gIC8vIHNjYW4gYmVsb3cgb25seSBydW5zIG9uY2UgdGhhdCBoYXMgYWxyZWFkeSBhbnN3ZXJlZCBuby5cbiAgaWYgKG9jY3VwaWVkLnNpemUgPT09IG1heFNsb3QgLSBmbG9vciArIDEpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGxldCBmaXJzdE1pc3NpbmdTbG90OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGxldCBtaXNzaW5nQ291bnQgPSAwO1xuICBmb3IgKGxldCBzbG90ID0gZmxvb3I7IHNsb3QgPD0gbWF4U2xvdDsgc2xvdCsrKSB7XG4gICAgaWYgKCFvY2N1cGllZC5oYXMoc2xvdCkpIHtcbiAgICAgIGZpcnN0TWlzc2luZ1Nsb3QgPz89IHNsb3Q7XG4gICAgICBtaXNzaW5nQ291bnQrKztcbiAgICB9XG4gIH1cbiAgaWYgKGZpcnN0TWlzc2luZ1Nsb3QgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHsgZmlyc3RNaXNzaW5nU2xvdCwgbWlzc2luZ0NvdW50LCBtYXhTbG90IH07XG59XG5cbi8qKlxuICogSG93IG1hbnkgdGltZXMgYSBkZXRlY3RlZCBob2xlIGlzIHJlLXJlYWQgYmVmb3JlIHRoZSBsb2cgaXMgdGFrZW4gYXQgaXRzXG4gKiB3b3JkLCBhbmQgdGhlIGJhY2tvZmYgYmVmb3JlIGVhY2ggcmUtcmVhZCAoZG91YmxpbmcgcGVyIGF0dGVtcHQpLlxuICpcbiAqIEEgaG9sZSBjYW4gYmUgdHJhbnNpZW50LiBUaGUgV29ybGQgYWxsb2NhdGVzIGEgc2xvdCBpbnNpZGUgdGhlIGluc2VydCB0aGF0XG4gKiBvY2N1cGllcyBpdCwgc28gdHdvIGNvbmN1cnJlbnQgd3JpdGVycyBjYW4gY29sbGlkZSwgb25lIHJldHJ5IHBhc3QgdGhlIG90aGVyLFxuICogYW5kIHRoZSBoaWdoZXIgc2xvdCBjb21taXQgZmlyc3QsIGxlYXZpbmcgYSB3aW5kb3cgaW4gd2hpY2ggdGhlIGxvd2VyIG9uZSBpc1xuICogZ2VudWluZWx5IGFic2VudCBmcm9tIGEgc3Ryb25nbHktY29uc2lzdGVudCByZWFkIGFuZCBmaWxscyBpbiBhIG1vbWVudCBsYXRlci5cbiAqIFRoZSB3aW5kb3cgaXMgb25lIGNvbW1pdCB3aWRlLCBzbyBhIHNob3J0IGJhY2tvZmYgY2xlYXJzIGl0OyBhbnl0aGluZyB0aGF0XG4gKiBzdXJ2aXZlcyBhbGwgdGhyZWUgcmUtcmVhZHMgaXMgYSBwb3NpdGlvbiBubyB3cml0ZSB3aWxsIGV2ZXIgb2NjdXB5LlxuICovXG5leHBvcnQgY29uc3QgU0xPVF9HQVBfUkVDSEVDS19BVFRFTVBUUyA9IDM7XG5jb25zdCBTTE9UX0dBUF9SRUNIRUNLX0JBU0VfREVMQVlfTVMgPSAyNTtcblxuLyoqXG4gKiBSZS1yZWFkIGEgbG9nIHRoYXQgbG9va3MgaG9sZXkgdW50aWwgdGhlIGhvbGUgZmlsbHMgaW4gb3IgdGhlIHJlLXJlYWRzIHJ1blxuICogb3V0LCBhbmQgcmV0dXJuIHRoZSBzZXR0bGVkIGxvZyBhbG9uZ3NpZGUgdGhlIGhvbGUgdGhhdCBzdXJ2aXZlZC5cbiAqXG4gKiBSZWFkcyBhcmUgc3Ryb25nbHkgY29uc2lzdGVudCwgc28gYSBob2xlIGlzIG5vdCBhbiBhcnRpZmFjdCBvZiAqd2hlbiogdGhlIGxvZ1xuICogd2FzIHJlYWQsIGJ1dCBpdCBjYW4gYmUgYW4gYXJ0aWZhY3Qgb2YgYSB3cml0ZSB0aGF0IGhhZCBub3QgY29tbWl0dGVkIHlldFxuICogKHNlZSB7QGxpbmsgU0xPVF9HQVBfUkVDSEVDS19BVFRFTVBUU30pLiBEaXN0aW5ndWlzaGluZyB0aGUgdHdvIGNvc3RzIGFcbiAqIHJlLXJlYWQsIHdoaWNoIGlzIG9ubHkgZXZlciBwYWlkIGJ5IGEgcmVwbGF5IHRoYXQgYWxyZWFkeSBmb3VuZCBhIGhvbGUuXG4gKlxuICogVGhlIHJlbG9hZCBpcyBmdWxsIHJhdGhlciB0aGFuIGluY3JlbWVudGFsOiB0aGUgbWlzc2luZyBwb3NpdGlvbiBpcyBiZWxvdyB0aGVcbiAqIGxvZydzIG1heGltdW0sIHNvIGEgY3Vyc29yLWFuY2hvcmVkIHJlYWQgc3RhcnRzIHBhc3QgaXQgYW5kIGNhbiBuZXZlciBzZWUgaXRcbiAqIGFycml2ZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldHRsZUV2ZW50U2xvdEdhcChcbiAgcnVuSWQ6IHN0cmluZyxcbiAgbG9hZGVkOiBMb2FkZWRFdmVudExvZ1xuKTogUHJvbWlzZTx7IGxvZzogTG9hZGVkRXZlbnRMb2c7IGdhcDogRXZlbnRTbG90R2FwIHwgdW5kZWZpbmVkIH0+IHtcbiAgbGV0IGxvZyA9IGxvYWRlZDtcbiAgbGV0IGdhcCA9IGZpbmRFdmVudFNsb3RHYXAobG9nLmV2ZW50cyk7XG4gIGZvciAoXG4gICAgbGV0IGF0dGVtcHQgPSAwO1xuICAgIGdhcCAhPT0gdW5kZWZpbmVkICYmIGF0dGVtcHQgPCBTTE9UX0dBUF9SRUNIRUNLX0FUVEVNUFRTO1xuICAgIGF0dGVtcHQrK1xuICApIHtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT5cbiAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgU0xPVF9HQVBfUkVDSEVDS19CQVNFX0RFTEFZX01TICogMiAqKiBhdHRlbXB0KVxuICAgICk7XG4gICAgbG9nID0gYXdhaXQgbG9hZFdvcmtmbG93UnVuRXZlbnRzKHJ1bklkKTtcbiAgICBnYXAgPSBmaW5kRXZlbnRTbG90R2FwKGxvZy5ldmVudHMpO1xuICB9XG4gIHJldHVybiB7IGxvZywgZ2FwIH07XG59XG5cbi8qKlxuICogSG93IG11Y2ggb2YgaXRzIHJ1bidzIGxvZyBhIHJlcGxheS1jb250ZXh0IGV2ZW50IGNyZWF0aW9uIGhhZCBsb2FkZWQgd2hlbiBpdFxuICogZGVjaWRlZCB0byB3cml0ZSwgYXMgdGhlIGhpZ2hlc3Qgc2xvdCB0aGF0IGxvZyBvY2N1cGllcy5cbiAqXG4gKiBPbmUgaW50ZWdlciBzYXlzIGl0IGJlY2F1c2UgdGhlIFdvcmxkIGtlZXBzIGl0cyBwb3NpdGlvbnMgZGVuc2U6IGEgd3JpdGVyXG4gKiB0aGF0IG5hbWVzIHNsb3QgTiBpcyBjbGFpbWluZyB0byBob2xkIGV2ZXJ5IGV2ZW50IGZyb20gMSB0byBOIGFuZCBub3RoaW5nXG4gKiBhYm92ZS4gVGhlIFdvcmxkIGFuc3dlcnMgYnkgbnVtYmVyaW5nIHRoZSB3cml0ZSBhYm92ZSB3aGF0ZXZlciB0aGUgbG9nIGhhc1xuICogYWN0dWFsbHkgcmVhY2hlZCBhbmQgaGFuZGluZyBiYWNrIHRoZSBldmVudHMgb24gdGhlIHNsb3RzIGluIGJldHdlZW46IHRoZVxuICogb25lcyB0aGlzIHdyaXRlciBkZWNpZGVkIHdpdGhvdXQuXG4gKlxuICogRGVuc2l0eSBpcyB0aGUgV29ybGQncyBpbnZhcmlhbnQsIG5vdCBhIGNsYWltIGFib3V0IHRoaXMgcGFydGljdWxhciByZWFkLiBBXG4gKiByZWFkZXIgdGhhdCBpcyBzaG9ydCBvZiBhIHBvc2l0aW9uIGl0IGhvbGRzIG5vIGV2ZW50IGZvciBuYW1lcyBhIGxvd2VyIE4sXG4gKiB3aGljaCB1bmRlcnN0YXRlcyB3aGF0IGl0IGhhcyBzZWVuIGFuZCBvbmx5IGNvc3RzIGl0IGEgd2lkZXIgcmVwb3J0LiBOYW1pbmdcbiAqIGEgcG9zaXRpb24gaXQgY2Fubm90IGFjY291bnQgZm9yIGlzIHRoZSBkaXJlY3Rpb24gdGhhdCBpcyB1bnNhZmUsIHdoaWNoIGlzXG4gKiB3aHkge0BsaW5rIHNsb3RTbmFwc2hvdFBhcmFtc30gdGFrZXMgdGhlIG1heGltdW0gcmF0aGVyIHRoYW4gdGhlIGNvdW50LlxuICpcbiAqIEl0cyBvd24gb2JqZWN0IHJhdGhlciB0aGFuIGEgYmFyZSBudW1iZXIgc28gYSBjYWxsIHNpdGUgY2Fubm90IGhhbGYtc2VuZCBpdCxcbiAqIGFuZCBzbyB0aGUgZW1wdHkgY2FzZSBzcHJlYWRzIHRvIG5vdGhpbmcuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2xvdFNuYXBzaG90UGFyYW1zIHtcbiAgZXZlbnRDb3VudD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgc2xvdCBzbmFwc2hvdCB0byBhdHRhY2ggdG8gYSByZXBsYXktY29udGV4dCBldmVudCBjcmVhdGlvbi5cbiAqXG4gKiBFbXB0eSBmb3IgYW4gZW1wdHkgbG9nLCB3aGljaCBpcyB0aGUgc3RhdGUgYSBgcnVuX2NyZWF0ZWRgIHdyaXRlIGlzIGlzc3VlZFxuICogZnJvbTogdGhlcmUgaXMgbm8gcG9zaXRpb24gaGVsZCB5ZXQgdG8gbmFtZS5cbiAqXG4gKiBUaGUgbWF4aW11bSByYXRoZXIgdGhhbiB0aGUgbGVuZ3RoLCBmb3IgdGhlIHJlYXNvbiB7QGxpbmsgbWF4RXZlbnRTbG90fVxuICogZ2l2ZXM6IGEgcGFydGlhbGx5LXJlYWQgbG9nIGhvbGRzIGZld2VyIGV2ZW50cyB0aGFuIGl0cyBoaWdoZXN0IHBvc2l0aW9uLCBhbmRcbiAqIGNvdW50aW5nIHRob3NlIHdvdWxkIG1ha2UgdGhlIHdyaXRlIGNsYWltIHRvIGhhdmUgc2VlbiBsZXNzIHRoYW4gaXQgaGFzLCBzb1xuICogdGhlIFdvcmxkIHdvdWxkIHJlcG9ydCB0aGUgc2FtZSBldmVudHMgYmFjayBvbiBldmVyeSBhdHRlbXB0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2xvdFNuYXBzaG90UGFyYW1zKFxuICBldmVudHM6IHJlYWRvbmx5IEV2ZW50W11cbik6IFNsb3RTbmFwc2hvdFBhcmFtcyB7XG4gIGNvbnN0IGV2ZW50Q291bnQgPSBtYXhFdmVudFNsb3QoZXZlbnRzKTtcbiAgcmV0dXJuIGV2ZW50Q291bnQgPT09IHVuZGVmaW5lZCA/IHt9IDogeyBldmVudENvdW50IH07XG59XG5cbi8qKlxuICogVGhlIGV2ZW50cyBhIHJlamVjdGluZyBXb3JsZCBhdHRhY2hlZCB0byBhIGBQcmVjb25kaXRpb25GYWlsZWRFcnJvcmAsIHdoZW4gaXRcbiAqIHJldHVybmVkIHRoZSBvbmVzIHRoZSBjbGllbnQncyBzbmFwc2hvdCB3YXMgbWlzc2luZyBpbmxpbmUuXG4gKlxuICogUmV0dXJucyBgbnVsbGAgZm9yIGFueXRoaW5nIGVsc2U6IG5vIGRldGFpbHMsIGEgV29ybGQgdGhhdCBkaWQgbm90IGltcGxlbWVudFxuICogdGhpcywgb3IgYSBwYXlsb2FkIHRoYXQgZG9lcyBub3QgbmFycm93IGNsZWFubHkuIENhbGxlcnMgZmFsbCBiYWNrIHRvXG4gKiByZWxvYWRpbmcgdGhlIGV2ZW50IGxvZywgd2hpY2ggaXMgYWx3YXlzIGNvcnJlY3Q7IHRoaXMgaXMgdW50cnVzdGVkLXNoYXBlZFxuICogZGF0YSBvbiBhIGZhaWx1cmUgcGF0aCwgc28gbm90aGluZyBoZXJlIGlzIHJlcGFpcmVkLlxuICpcbiAqIGBydW5JZGAgaXMgdGhlIGNhbGxlcidzIHJ1bi4gRXZlcnkgZXZlbnQgbXVzdCBiZWxvbmcgdG8gaXQ6IHRoZSBkZWx0YSBpc1xuICogbWVyZ2VkIHN0cmFpZ2h0IGludG8gdGhlIHJlcGxheSdzIGxvZywgYW5kIG9uZSBmb3JlaWduIGV2ZW50IHRoZXJlIGlzIGFcbiAqIGNvcnJ1cHQgbG9nIHJhdGhlciB0aGFuIGEgY29ycmVjdGVkIG9uZTogdGhlIHJlcGxheSB3b3VsZCBjb25zdW1lIGFcbiAqIGNvcnJlbGF0aW9uIGlkIGZvciBhbiBldmVudCB0aGF0IGRvZXMgbm90IGV4aXN0IG9uIHRoaXMgcnVuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlY29uZGl0aW9uRXZlbnREZWx0YShcbiAgZXJyb3I6IHVua25vd24sXG4gIHJ1bklkOiBzdHJpbmdcbik6IHsgZXZlbnRzOiBFdmVudFtdOyBjdXJzb3I6IHN0cmluZyB8IG51bGwgfSB8IG51bGwge1xuICBpZiAoIVByZWNvbmRpdGlvbkZhaWxlZEVycm9yLmlzKGVycm9yKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGNvbnN0IGRldGFpbHMgPSBlcnJvci5kZXRhaWxzO1xuICBpZiAodHlwZW9mIGRldGFpbHMgIT09ICdvYmplY3QnIHx8IGRldGFpbHMgPT09IG51bGwpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCB7IGV2ZW50cywgY3Vyc29yIH0gPSBkZXRhaWxzIGFzIHsgZXZlbnRzPzogdW5rbm93bjsgY3Vyc29yPzogdW5rbm93biB9O1xuICBpZiAoIUFycmF5LmlzQXJyYXkoZXZlbnRzKSB8fCBldmVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICBpZiAoXG4gICAgICB0eXBlb2YgZXZlbnQgIT09ICdvYmplY3QnIHx8XG4gICAgICBldmVudCA9PT0gbnVsbCB8fFxuICAgICAgdHlwZW9mIChldmVudCBhcyB7IGV2ZW50SWQ/OiB1bmtub3duIH0pLmV2ZW50SWQgIT09ICdzdHJpbmcnIHx8XG4gICAgICAoZXZlbnQgYXMgeyBydW5JZD86IHVua25vd24gfSkucnVuSWQgIT09IHJ1bklkXG4gICAgKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBldmVudHM6IGV2ZW50cyBhcyBFdmVudFtdLFxuICAgIGN1cnNvcjogdHlwZW9mIGN1cnNvciA9PT0gJ3N0cmluZycgPyBjdXJzb3IgOiBudWxsLFxuICB9O1xufVxuXG4vKiogQ3JlYXRlcyBvbmUgZXZlbnQgb24gYSBib3VuZCBydW4sIGNhcnJ5aW5nIHJlcGxheS1yZWNvdmVyeSB0ZWxlbWV0cnkuICovXG5leHBvcnQgdHlwZSBFdmVudENyZWF0b3IgPSAoXG4gIGRhdGE6IENyZWF0ZUV2ZW50UmVxdWVzdCxcbiAgcGFyYW1zPzogQ3JlYXRlRXZlbnRQYXJhbXNcbikgPT4gUHJvbWlzZTxFdmVudFJlc3VsdD47XG5cbi8qKlxuICogQ09SUyBoZWFkZXJzIGZvciBoZWFsdGggY2hlY2sgcmVzcG9uc2VzLlxuICogQWxsb3dzIHRoZSBvYnNlcnZhYmlsaXR5IFVJIHRvIGNoZWNrIGVuZHBvaW50IGhlYWx0aCBmcm9tIGEgZGlmZmVyZW50IG9yaWdpbi5cbiAqL1xuY29uc3QgSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyA9IHtcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnOiAnUE9TVCwgT1BUSU9OUywgR0VULCBIRUFEJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOiAnQ29udGVudC1UeXBlJyxcbn07XG5cbi8qKlxuICogV3JhcHMgYSByZXF1ZXN0L3Jlc3BvbnNlIGhhbmRsZXIgYW5kIGFkZHMgYSBoZWFsdGggY2hlY2sgXCJtb2RlXCJcbiAqIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhIGBfX2hlYWx0aGAgcXVlcnkgcGFyYW1ldGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEhlYWx0aENoZWNrKFxuICBoYW5kbGVyOiAocmVxOiBSZXF1ZXN0KSA9PiBQcm9taXNlPFJlc3BvbnNlPixcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4ge1xuICByZXR1cm4gYXN5bmMgKHJlcTogUmVxdWVzdCkgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCk7XG4gICAgY29uc3QgaXNIZWFsdGhDaGVjayA9IHVybC5zZWFyY2hQYXJhbXMuaGFzKCdfX2hlYWx0aCcpO1xuICAgIGlmIChpc0hlYWx0aENoZWNrKSB7XG4gICAgICAvLyBIYW5kbGUgQ09SUyBwcmVmbGlnaHQgZm9yIGhlYWx0aCBjaGVja1xuICAgICAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKG51bGwsIHtcbiAgICAgICAgICBzdGF0dXM6IDIwNCxcbiAgICAgICAgICBoZWFkZXJzOiBIRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBoZWFsdGh5OiB0cnVlLFxuICAgICAgICAgIGVuZHBvaW50OiB1cmwucGF0aG5hbWUsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IHdvcmxkU3BlY1ZlcnNpb24gPz8gU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgd29ya2Zsb3dDb3JlVmVyc2lvbixcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBzdGF0dXM6IDIwMCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgLi4uSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyxcbiAgICAgICAgICB9LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgaGFuZGxlcihyZXEpO1xuICB9O1xufVxuXG4vKiogRk5WLTFhIDMyLWJpdCBoYXNoIG9mIGEgc3RyaW5nLCBhcyA4IGhleCBjaGFycy4gVGlueSwgZGV0ZXJtaW5pc3RpYywgYW5kXG4gKiAgZGVwZW5kZW5jeS1mcmVlLiBVc2VkIG9ubHkgdG8gc2NvcGUgaWRlbXBvdGVuY3kga2V5cywgbm90IGZvciBzZWN1cml0eS4gKi9cbmZ1bmN0aW9uIGZudjFhMzJIZXgodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGxldCBoYXNoID0gMHg4MTFjOWRjNTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZS5sZW5ndGg7IGkrKykge1xuICAgIGhhc2ggXj0gdmFsdWUuY2hhckNvZGVBdChpKTtcbiAgICBoYXNoID0gTWF0aC5pbXVsKGhhc2gsIDB4MDEwMDAxOTMpO1xuICB9XG4gIHJldHVybiAoaGFzaCA+Pj4gMCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDgsICcwJyk7XG59XG5cbi8qKlxuICogSWRlbXBvdGVuY3kga2V5IGZvciBhIHN0ZXAncyBiYWNrZ3JvdW5kLWRpc3BhdGNoIHF1ZXVlIG1lc3NhZ2UsIHNjb3BlZCB0b1xuICogdGhlIHN0ZXAncyBJREVOVElUWSwgY29ycmVsYXRpb24gaWQgcGx1cyAoaGFzaGVkKSBzdGVwIG5hbWUsIHJhdGhlciB0aGFuXG4gKiB0aGUgYmFyZSBjb3JyZWxhdGlvbiBpZC5cbiAqXG4gKiBUaGUgc2NvcGluZyBtYXR0ZXJzIGZvciByZXNpbGllbnQgc3RlcCBkaXNwYXRjaCB1bmRlciB0aGUgcHJlY29uZGl0aW9uXG4gKiBndWFyZDogYSBndWFyZC1yZWplY3RlZCBgc3RlcF9jcmVhdGVkYCBsZWF2ZXMgaXRzIChyZXZva2VkKSBzdGVwIG1lc3NhZ2UgaW5cbiAqIGZsaWdodCwgYW5kIHRoZSBjb3JyZWN0ZWQgcmVwbGF5IG1heSByZS1kZXJpdmUgdGhlIHNhbWUgY29ycmVsYXRpb24gaWQgZm9yXG4gKiBhIERJRkZFUkVOVCBzdGVwLiBVbmRlciBhIGJhcmUtY29ycmVsYXRpb25JZCBrZXkgdGhlIGNvcnJlY3RlZCByZXBsYXknc1xuICogZGlzcGF0Y2ggd291bGQgc2lsZW50bHkgZGVkdXBlIGFnYWluc3QgdGhlIHJldm9rZWQgaW4tZmxpZ2h0IG1lc3NhZ2UsXG4gKiB3aGljaCB0aGVuIHJlc29sdmVzIGBza2lwcGVkYCBhZ2FpbnN0IHRoZSByZS1jcmVhdGVkIGVudGl0eSAodGhlIHNlcnZlcidzXG4gKiBzdGVwTmFtZSBmZW5jZSByZWplY3RzIGl0cyBiYXJlIHN0YXJ0KSwgYW5kIHRoZSBsZWdpdGltYXRlIHN0ZXAgd291bGRcbiAqIG5ldmVyIGJlIGV4ZWN1dGVkLiBTY29waW5nIGJ5IHN0ZXAgbmFtZSBrZWVwcyBldmVyeSBkZWR1cCBwcm9wZXJ0eSB0aGF0XG4gKiBtYXR0ZXJzIChjcmFzaCByZWNvdmVyeSByZS1kaXNwYXRjaCwgY29uY3VycmVudCBoYW5kbGVycywgdGhlIGRlbGF5ZWRcbiAqIHJldHJ5IHNoYXJpbmcgdGhlIHN1c3BlbnNpb24gcmUtZGlzcGF0Y2gncyBrZXk6IGFsbCBuYW1lIHRoZSBzYW1lIHN0ZXApXG4gKiB3aGlsZSBsZXR0aW5nIHRoZSBjb3JyZWN0ZWQgc2NoZWR1bGUncyBkaXNwYXRjaCB0aHJvdWdoLlxuICpcbiAqIEV2ZXJ5IHByb2R1Y2VyIG9mIGEgc3RlcC1kaXNwYXRjaCAob3Igc3RlcC1yZXRyeSkgbWVzc2FnZSBtdXN0IHVzZSB0aGlzXG4gKiBrZXkuIENyb3NzLXZlcnNpb24gbWl4aW5nIGlzIG5vdCBhIGNvbmNlcm46IHF1ZXVlIG1lc3NhZ2VzIGFyZSBwaW5uZWQgdG9cbiAqIHRoZSBkZXBsb3ltZW50IHRoYXQgcHJvZHVjZWQgdGhlbSwgc28gb25lIHJ1biBuZXZlciBzZWVzIHR3byBrZXkgc2NoZW1lcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0ZXBEaXNwYXRjaElkZW1wb3RlbmN5S2V5KFxuICBjb3JyZWxhdGlvbklkOiBzdHJpbmcsXG4gIHN0ZXBOYW1lOiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIHJldHVybiBgJHtjb3JyZWxhdGlvbklkfToke2ZudjFhMzJIZXgoc3RlcE5hbWUpfWA7XG59XG5cbi8qKlxuICogUXVldWVzIGEgbWVzc2FnZSB0byB0aGUgc3BlY2lmaWVkIHF1ZXVlIHdpdGggdHJhY2luZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHF1ZXVlTWVzc2FnZShcbiAgd29ybGQ6IFdvcmxkLFxuICAuLi5hcmdzOiBQYXJhbWV0ZXJzPHR5cGVvZiB3b3JsZC5xdWV1ZT5cbikge1xuICBjb25zdCBxdWV1ZU5hbWUgPSBhcmdzWzBdO1xuICBhd2FpdCB0cmFjZShcbiAgICAncXVldWUucHVibGlzaCcsXG4gICAge1xuICAgICAgLy8gU3RhbmRhcmQgT1RFTCBtZXNzYWdpbmcgY29udmVudGlvbnNcbiAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdEZXN0aW5hdGlvbk5hbWUocXVldWVOYW1lKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ09wZXJhdGlvblR5cGUoJ3B1Ymxpc2gnKSxcbiAgICAgICAgLy8gUGVlciBzZXJ2aWNlIGZvciBEYXRhZG9nIHNlcnZpY2UgbWFwc1xuICAgICAgICAuLi5BdHRyaWJ1dGUuUGVlclNlcnZpY2UoJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjU3lzdGVtKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1NlcnZpY2UoJ3ZxcycpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjTWV0aG9kKCdwdWJsaXNoJyksXG4gICAgICB9LFxuICAgICAga2luZDogYXdhaXQgZ2V0U3BhbktpbmQoJ1BST0RVQ0VSJyksXG4gICAgfSxcbiAgICBhc3luYyAoc3BhbikgPT4ge1xuICAgICAgY29uc3QgeyBtZXNzYWdlSWQgfSA9IGF3YWl0IHdvcmxkLnF1ZXVlKC4uLmFyZ3MpO1xuICAgICAgaWYgKG1lc3NhZ2VJZCkge1xuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKEF0dHJpYnV0ZS5NZXNzYWdpbmdNZXNzYWdlSWQobWVzc2FnZUlkKSk7XG4gICAgICB9XG4gICAgfVxuICApO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHF1ZXVlIG92ZXJoZWFkIHRpbWUgaW4gbWlsbGlzZWNvbmRzIGZvciBhIGdpdmVuIG1lc3NhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWV1ZU92ZXJoZWFkKG1lc3NhZ2U6IHsgcmVxdWVzdGVkQXQ/OiBEYXRlIH0pIHtcbiAgaWYgKCFtZXNzYWdlLnJlcXVlc3RlZEF0KSByZXR1cm47XG4gIHRyeSB7XG4gICAgcmV0dXJuIEF0dHJpYnV0ZS5RdWV1ZU92ZXJoZWFkTXMoXG4gICAgICBEYXRlLm5vdygpIC0gbWVzc2FnZS5yZXF1ZXN0ZWRBdC5nZXRUaW1lKClcbiAgICApO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm47XG4gIH1cbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBydW4ncyBmdWxsIHBheWxvYWQtZW5jcnlwdGlvbiBjYXBhYmlsaXR5LiBUaGlzIGluY2x1ZGVzIHRoZVxuICogc3ltbWV0cmljIGtleSBhbmQgWDI1NTE5IGtleXBhaXIgbmVlZGVkIHRvIG9wZW4gY3Jvc3MtcnVuIHNlYWxlZCBwYXlsb2Fkcy5cbiAqIE1pc3Npbmcgd29ybGQgc3VwcG9ydCBvciBrZXkgbWF0ZXJpYWwgcmVzb2x2ZXMgdG8gYHVuZGVmaW5lZGA7IGxvb2t1cCBhbmRcbiAqIGRlcml2YXRpb24gZmFpbHVyZXMgcHJvcGFnYXRlIHJhdGhlciB0aGFuIHNpbGVudGx5IGZhbGxpbmcgYmFjayB0byBwbGFpbnRleHQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXNvbHZlUnVuRW5jcnlwdGlvbktleShcbiAgd29ybGQ6IFdvcmxkLFxuICBydW5PcklkOiBXb3JrZmxvd1J1biB8IHN0cmluZyxcbiAgY29udGV4dD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4pOiBQcm9taXNlPFBheWxvYWRLZXkgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgcmF3S2V5ID1cbiAgICB0eXBlb2YgcnVuT3JJZCA9PT0gJ3N0cmluZydcbiAgICAgID8gYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJ1bk9ySWQsIGNvbnRleHQpXG4gICAgICA6IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihydW5PcklkKTtcbiAgcmV0dXJuIHJhd0tleSA/IGF3YWl0IGRlcml2ZVJ1blBheWxvYWRLZXlzKHJhd0tleSkgOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUmV0dXJuIGEgbGF6eSwgbWVtb2l6ZWQgYWNjZXNzb3IgYXJvdW5kIHtAbGluayByZXNvbHZlUnVuRW5jcnlwdGlvbktleX0uXG4gKiBDb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgdGhlIHNhbWUgcHJvbWlzZSwgaW5jbHVkaW5nIGl0cyByZWplY3Rpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplRW5jcnlwdGlvbktleShcbiAgd29ybGQ6IFdvcmxkLFxuICBydW5PcklkOiBXb3JrZmxvd1J1biB8IHN0cmluZ1xuKTogKCkgPT4gUHJvbWlzZTxQYXlsb2FkS2V5IHwgdW5kZWZpbmVkPiB7XG4gIGxldCBjYWNoZWQ6IFByb21pc2U8UGF5bG9hZEtleSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgaWYgKCFjYWNoZWQpIHtcbiAgICAgIGNhY2hlZCA9IHJlc29sdmVSdW5FbmNyeXB0aW9uS2V5KHdvcmxkLCBydW5PcklkKTtcbiAgICB9XG4gICAgcmV0dXJuIGNhY2hlZDtcbiAgfTtcbn1cbiJdfQ==
|