@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
|
@@ -1,40 +1,235 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ERROR_SLUGS, HookNotFoundError, RunExpiredError, WorkflowRuntimeError, } from '@workflow/errors';
|
|
2
|
+
import { HOOK_RESUME_DEDUP_VERSION, isLegacySpecVersion, isTerminalWorkflowRunStatus, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, SPEC_VERSION_SUPPORTS_COMPRESSION, } from '@workflow/world';
|
|
3
|
+
import { monotonicFactory } from 'ulid';
|
|
4
4
|
import { getRunCapabilities } from '../capabilities.js';
|
|
5
5
|
import { importKey } from '../encryption.js';
|
|
6
|
-
import {
|
|
6
|
+
import { runtimeLogger } from '../logger.js';
|
|
7
|
+
import { decodeRunPublicKey } from '../sealed-box.js';
|
|
8
|
+
import { deriveRunPayloadKeys } from '../serialization/encryption.js';
|
|
9
|
+
import { dehydrateStepReturnValue, hydrateStepArguments, SerializationFormat, sealTo, } from '../serialization.js';
|
|
7
10
|
import { WEBHOOK_RESPONSE_WRITABLE } from '../symbols.js';
|
|
8
11
|
import * as Attribute from '../telemetry/semantic-conventions.js';
|
|
9
|
-
import {
|
|
10
|
-
import { waitedUntil } from '../util.js';
|
|
12
|
+
import { linkToTraceCarrier, trace } from '../telemetry.js';
|
|
11
13
|
import { getWorldLazy } from './get-world-lazy.js';
|
|
12
14
|
import { getWorkflowQueueName } from './helpers.js';
|
|
15
|
+
import { safeWaitUntil, waitedUntil } from './wait-until.js';
|
|
16
|
+
/** Monotonic ULID factory for per-call resume idempotency keys. */
|
|
17
|
+
const generateResumeId = monotonicFactory();
|
|
13
18
|
/**
|
|
14
|
-
*
|
|
15
|
-
* and
|
|
19
|
+
* Hex SHA-256 of the serialized resume payload bytes. Computed once by the
|
|
20
|
+
* producer and sent with its durable `hook_received` write so transport and
|
|
21
|
+
* slot retries converge through the server's `(runId, resumeId)` constraint.
|
|
16
22
|
*/
|
|
17
|
-
async function
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
async function computeResumePayloadDigest(bytes) {
|
|
24
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes);
|
|
25
|
+
const view = new Uint8Array(digest);
|
|
26
|
+
let hex = '';
|
|
27
|
+
for (const b of view) {
|
|
28
|
+
hex += b.toString(16).padStart(2, '0');
|
|
29
|
+
}
|
|
30
|
+
return hex;
|
|
31
|
+
}
|
|
32
|
+
const HOOK_WAKE_RETRY_DELAYS_MS = [25, 100];
|
|
33
|
+
/**
|
|
34
|
+
* A wake failure worth retrying is transport-shaped (network error, 5xx,
|
|
35
|
+
* throttle). A definitive rejection will not change on a 25ms retry, so
|
|
36
|
+
* spending the budget on it only delays the caller's error.
|
|
37
|
+
*
|
|
38
|
+
* `@vercel/queue` errors carry no `status` field — they are bare `Error`
|
|
39
|
+
* subclasses distinguished by `name` — so classification checks the World's
|
|
40
|
+
* deployment-unavailable hook first (a deployment the queue cannot discover
|
|
41
|
+
* will not come back within this function's ~125ms budget), then a numeric
|
|
42
|
+
* status when one exists (non-Vercel queue implementations), then the queue
|
|
43
|
+
* client's definitive-4xx error names.
|
|
44
|
+
*/
|
|
45
|
+
function isRetryableWakeError(error, isDeploymentUnavailableError) {
|
|
46
|
+
if (isDeploymentUnavailableError?.(error))
|
|
47
|
+
return false;
|
|
48
|
+
const status = error ?? {};
|
|
49
|
+
const code = status.status ?? status.statusCode;
|
|
50
|
+
if (typeof code === 'number') {
|
|
51
|
+
return code >= 500 || code === 408 || code === 429;
|
|
52
|
+
}
|
|
53
|
+
const name = error?.name;
|
|
54
|
+
return (name !== 'BadRequestError' &&
|
|
55
|
+
name !== 'UnauthorizedError' &&
|
|
56
|
+
name !== 'ForbiddenError');
|
|
57
|
+
}
|
|
58
|
+
// A publish may succeed even when its response is lost, so a retry can
|
|
59
|
+
// enqueue a duplicate wake. That is harmless: the event is already durable,
|
|
60
|
+
// and deterministic replay makes a second delivery of the same run a no-op.
|
|
61
|
+
async function publishHookWakeWithRetry(publish, isDeploymentUnavailableError) {
|
|
62
|
+
let lastError;
|
|
63
|
+
for (let attempt = 0; attempt <= HOOK_WAKE_RETRY_DELAYS_MS.length; attempt++) {
|
|
64
|
+
try {
|
|
65
|
+
await publish();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
lastError = error;
|
|
70
|
+
if (!isRetryableWakeError(error, isDeploymentUnavailableError))
|
|
71
|
+
break;
|
|
72
|
+
const delayMs = HOOK_WAKE_RETRY_DELAYS_MS[attempt];
|
|
73
|
+
if (delayMs !== undefined) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// The wake only runs after the hook_received write committed, so a wake
|
|
79
|
+
// failure here is necessarily "durable but not yet dispatched": the event
|
|
80
|
+
// survives, and any later wake of the run delivers it. Do not let a queue
|
|
81
|
+
// implementation reuse HookNotFoundError and accidentally imply that no
|
|
82
|
+
// hook_received exists.
|
|
83
|
+
if (HookNotFoundError.is(lastError)) {
|
|
84
|
+
throw new WorkflowRuntimeError('The hook resume was committed, but its workflow wake could not be published', { cause: lastError });
|
|
85
|
+
}
|
|
86
|
+
throw lastError;
|
|
87
|
+
}
|
|
88
|
+
/** Derive a resume context from a full run (fallback for pre-`resumeContext` hooks). */
|
|
89
|
+
function resumeContextFromRun(run) {
|
|
90
|
+
const coreVersion = run.executionContext?.workflowCoreVersion;
|
|
91
|
+
const traceCarrier = run.executionContext?.traceCarrier;
|
|
92
|
+
const hookResumeInputVersion = run.executionContext?.hookResumeInputVersion;
|
|
93
|
+
return {
|
|
94
|
+
deploymentId: run.deploymentId,
|
|
95
|
+
workflowName: run.workflowName,
|
|
96
|
+
runSpecVersion: run.specVersion,
|
|
97
|
+
workflowCoreVersion: typeof coreVersion === 'string' ? coreVersion : undefined,
|
|
98
|
+
traceCarrier: traceCarrier && typeof traceCarrier === 'object'
|
|
99
|
+
? traceCarrier
|
|
100
|
+
: undefined,
|
|
101
|
+
encryptionPublicKey: run.encryptionPublicKey,
|
|
102
|
+
hookResumeInputVersion: typeof hookResumeInputVersion === 'number'
|
|
103
|
+
? hookResumeInputVersion
|
|
104
|
+
: undefined,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Resolve resume context for a hook. Uses the stored `resumeContext` when
|
|
109
|
+
* present (fast path, no run read); otherwise fetches the run and synthesizes
|
|
110
|
+
* it. Does NOT resolve the encryption key; callers do that separately. Only
|
|
111
|
+
* the fallback path can gate key work behind a local terminal-run check (it
|
|
112
|
+
* has the fetched run); the fast path's stored context carries no status, so
|
|
113
|
+
* seal/serialization work may run before the receiving side rejects
|
|
114
|
+
* `hook_received` for an ended run.
|
|
115
|
+
*/
|
|
116
|
+
async function resolveHookResumeInfo(hook) {
|
|
117
|
+
if (hook.resumeContext) {
|
|
118
|
+
return { resumeContext: hook.resumeContext, source: 'hook' };
|
|
25
119
|
}
|
|
26
|
-
|
|
120
|
+
const run = await (await getWorldLazy()).runs.get(hook.runId);
|
|
121
|
+
return {
|
|
122
|
+
resumeContext: resumeContextFromRun(run),
|
|
123
|
+
source: 'run_fallback',
|
|
124
|
+
run,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the run's symmetric key for a payload WRITE, as a bare `CryptoKey`
|
|
129
|
+
* (`importKey`): the `encr` write fallback used when the run published no
|
|
130
|
+
* public key to seal to. Writing needs only the AES key, not the read-side
|
|
131
|
+
* keypair. On the fast path this needs only `runId` + `deploymentId` (no run
|
|
132
|
+
* entity); on the fallback path the already fetched run is reused.
|
|
133
|
+
*/
|
|
134
|
+
async function resolveHookEncryptionKey(hook, info) {
|
|
135
|
+
const world = await getWorldLazy();
|
|
136
|
+
const rawKey = info.run
|
|
137
|
+
? await world.getEncryptionKeyForRun?.(info.run)
|
|
138
|
+
: await world.getEncryptionKeyForRun?.(hook.runId, {
|
|
139
|
+
deploymentId: info.resumeContext.deploymentId,
|
|
140
|
+
});
|
|
141
|
+
return rawKey ? await importKey(rawKey) : undefined;
|
|
142
|
+
}
|
|
143
|
+
/** Whether `metadata` on this record is already the lazy Promise accessor. */
|
|
144
|
+
function hasLazyMetadata(hook) {
|
|
145
|
+
const descriptor = Object.getOwnPropertyDescriptor(hook, 'metadata');
|
|
146
|
+
return descriptor !== undefined && typeof descriptor.get === 'function';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Wraps a raw hook record from a World in a {@link Hook},
|
|
150
|
+
* replacing its serialized `metadata` with a memoized Promise getter that
|
|
151
|
+
* hydrates on first access.
|
|
152
|
+
*
|
|
153
|
+
* Nothing here touches the network: the wrap is a property definition. All of
|
|
154
|
+
* the cost — resolving the run's payload keys and decrypting — moves inside the
|
|
155
|
+
* getter, so a lookup that never reads metadata pays for exactly one
|
|
156
|
+
* `hooks.getByToken`.
|
|
157
|
+
*
|
|
158
|
+
* The getter is defined in place on the record the World returned (the same
|
|
159
|
+
* object the eager path used to mutate), so no copy is made.
|
|
160
|
+
*/
|
|
161
|
+
function withLazyMetadata(raw) {
|
|
162
|
+
const serialized = raw.metadata;
|
|
163
|
+
let hydrated;
|
|
164
|
+
let encryptionKey;
|
|
165
|
+
// Hydrating metadata is a decrypting READ, so it derives the full
|
|
166
|
+
// RunPayloadKeys (which open sealed `encp` metadata, not just symmetric
|
|
167
|
+
// `encr`) rather than the bare write key the resume path uses.
|
|
168
|
+
const hydrate = async () => {
|
|
169
|
+
const world = await getWorldLazy();
|
|
170
|
+
const info = await resolveHookResumeInfo(raw);
|
|
171
|
+
// On the fast path this resolves the key by runId + deploymentId (no run
|
|
172
|
+
// read); on the fallback path it reuses the already-fetched run.
|
|
173
|
+
const rawKey = info.run
|
|
174
|
+
? await world.getEncryptionKeyForRun?.(info.run)
|
|
175
|
+
: await world.getEncryptionKeyForRun?.(raw.runId, {
|
|
176
|
+
deploymentId: info.resumeContext.deploymentId,
|
|
177
|
+
});
|
|
178
|
+
encryptionKey = rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
|
|
179
|
+
return await hydrateStepArguments(serialized, raw.runId, encryptionKey);
|
|
180
|
+
};
|
|
181
|
+
const hook = raw;
|
|
182
|
+
Object.defineProperty(hook, 'metadata', {
|
|
183
|
+
// A hook with no metadata resolves `undefined` without any I/O, so callers
|
|
184
|
+
// can await unconditionally. Memoized either way: metadata is fixed at
|
|
185
|
+
// hook-creation time, so hydration runs at most once per hook object.
|
|
186
|
+
get: () => (hydrated ??=
|
|
187
|
+
typeof serialized === 'undefined'
|
|
188
|
+
? Promise.resolve(undefined)
|
|
189
|
+
: hydrate()),
|
|
190
|
+
// Non-enumerable, matching `Run.returnValue` (a prototype getter, so it is
|
|
191
|
+
// absent from an instance's own keys). Spreading or `JSON.stringify`-ing a
|
|
192
|
+
// hook therefore cannot trigger hydration nobody asked for — which would
|
|
193
|
+
// otherwise leave a floating rejection when the run key is unreachable, and
|
|
194
|
+
// an unconsumed rejected Promise crashes Node as an unhandledRejection.
|
|
195
|
+
enumerable: false,
|
|
196
|
+
configurable: true,
|
|
197
|
+
});
|
|
198
|
+
return { hook, metadataEncryptionKey: () => encryptionKey };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Normalizes any hook record the resume path accepted into a
|
|
202
|
+
* {@link Hook} to return to the caller. Idempotent: a hook that
|
|
203
|
+
* already carries the lazy accessor (one that came from `getHookByToken`) is
|
|
204
|
+
* returned as-is rather than double-wrapped, which would hand
|
|
205
|
+
* `hydrateStepArguments` a Promise.
|
|
206
|
+
*/
|
|
207
|
+
function asLazyMetadataHook(hook) {
|
|
208
|
+
return hasLazyMetadata(hook)
|
|
209
|
+
? hook
|
|
210
|
+
: withLazyMetadata(hook).hook;
|
|
27
211
|
}
|
|
28
212
|
/**
|
|
29
|
-
* Get the hook by token to find the associated workflow run
|
|
30
|
-
*
|
|
31
|
-
*
|
|
213
|
+
* Get the hook by token to find the associated workflow run.
|
|
214
|
+
*
|
|
215
|
+
* This is a single read. The returned hook's `metadata` is a getter that
|
|
216
|
+
* resolves a Promise (see {@link Hook}), so the run fetch and
|
|
217
|
+
* `run-key` round trip that hydrating it can require are only paid by callers
|
|
218
|
+
* that actually await it:
|
|
219
|
+
*
|
|
220
|
+
* ```ts
|
|
221
|
+
* const hook = await getHookByToken(token);
|
|
222
|
+
* const metadata = await hook.metadata;
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* A Hook kept by minimum retention remains available here after its run ends,
|
|
226
|
+
* but cannot be resumed.
|
|
32
227
|
*
|
|
33
228
|
* @param token - The unique token identifying the hook
|
|
34
229
|
*/
|
|
35
230
|
export async function getHookByToken(token) {
|
|
36
|
-
const
|
|
37
|
-
return hook;
|
|
231
|
+
const world = await getWorldLazy();
|
|
232
|
+
return withLazyMetadata(await world.hooks.getByToken(token)).hook;
|
|
38
233
|
}
|
|
39
234
|
/**
|
|
40
235
|
* Resumes a workflow run by sending a payload to a hook identified by its token.
|
|
@@ -42,10 +237,26 @@ export async function getHookByToken(token) {
|
|
|
42
237
|
* This function is called externally (e.g., from an API route or server action)
|
|
43
238
|
* to send data to a hook and resume the associated workflow run.
|
|
44
239
|
*
|
|
240
|
+
* Resolving means BOTH that the `hook_received` event is durably recorded in
|
|
241
|
+
* the run's event log and that the workflow wake was accepted by the queue, in
|
|
242
|
+
* that order. A {@link HookNotFoundError} means this invocation committed no
|
|
243
|
+
* event. Any other error after the write is ambiguous only in dispatch, never
|
|
244
|
+
* in durability: the event may already be committed, and a later wake of the
|
|
245
|
+
* run (from any source) will deliver it.
|
|
246
|
+
*
|
|
247
|
+
* Prefer passing the token string over a cached {@link Hook} object. A token
|
|
248
|
+
* is looked up fresh, so the live backend can attest its atomic resume claim
|
|
249
|
+
* and the durable write becomes idempotent-on-retry (transport retries of the
|
|
250
|
+
* same write converge on one event). A supplied Hook object may carry a stale
|
|
251
|
+
* attestation, so it is deliberately ignored and the write is claim-less —
|
|
252
|
+
* meaning a lost response cannot be retried safely: retrying at the
|
|
253
|
+
* application level mints a fresh claim and can commit a second
|
|
254
|
+
* `hook_received`.
|
|
255
|
+
*
|
|
45
256
|
* @param tokenOrHook - The unique token identifying the hook, or the hook object itself
|
|
46
257
|
* @param payload - The data payload to send to the hook
|
|
47
|
-
* @returns Promise resolving to the
|
|
48
|
-
* @throws
|
|
258
|
+
* @returns Promise resolving to the {@link ResumedHook}
|
|
259
|
+
* @throws {HookNotFoundError} If the Hook does not exist or its run has ended
|
|
49
260
|
*
|
|
50
261
|
* @example
|
|
51
262
|
*
|
|
@@ -66,83 +277,274 @@ export async function getHookByToken(token) {
|
|
|
66
277
|
* ```
|
|
67
278
|
*/
|
|
68
279
|
export async function resumeHook(tokenOrHook, payload, encryptionKeyOverride) {
|
|
280
|
+
// Public entry point. It never attests hook freshness, so a Hook object
|
|
281
|
+
// supplied here (which may carry a `resumeCapabilities` cached before a
|
|
282
|
+
// server rollback or kill switch) is ignored by the dynamic-dedup gate and
|
|
283
|
+
// fails closed to a plain, claim-less write. Only `resumeWebhook`, which
|
|
284
|
+
// fetches the hook by token in-line during the same resume, reaches the
|
|
285
|
+
// internal implementation with the fresh attestation set. Keeping the
|
|
286
|
+
// freshness flag off the exported signature prevents a caller from passing a
|
|
287
|
+
// stale Hook plus `true` and reactivating dynamic dedup against a
|
|
288
|
+
// rolled-back backend.
|
|
289
|
+
//
|
|
290
|
+
// T0 of the hook-resume TTR window is taken HERE, at the public entry point,
|
|
291
|
+
// rather than inside the implementation; see the parameter's doc comment.
|
|
292
|
+
return resumeHookImpl(tokenOrHook, payload, encryptionKeyOverride, false, Date.now());
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Internal implementation of {@link resumeHook}. NOT exported: the
|
|
296
|
+
* `hookFreshlyLookedUp` attestation must never be reachable by public callers
|
|
297
|
+
* (see the wrapper above).
|
|
298
|
+
*
|
|
299
|
+
* @param hookFreshlyLookedUp - Attests that a supplied Hook object was fetched
|
|
300
|
+
* by token during THIS resume, so its response-only `resumeCapabilities`
|
|
301
|
+
* reflects the live backend and may be trusted for the dynamic-dedup gate.
|
|
302
|
+
* A token string is always fetched fresh here, so it is implicitly fresh.
|
|
303
|
+
* @param resumeRequestedAtMs - T0 of the hook-resume TTR window (see
|
|
304
|
+
* runtime/resume-latency.ts), stamped by the PUBLIC entry point the caller
|
|
305
|
+
* used. It is a parameter rather than a local because `resumeWebhook` does
|
|
306
|
+
* real work before it gets here (the by-token lookup, the run-key
|
|
307
|
+
* resolution that hydrates hook metadata, and the `respondWith` setup) and
|
|
308
|
+
* stamping locally would silently exclude all of it, so the two entry points
|
|
309
|
+
* would report the same metric over different windows.
|
|
310
|
+
*/
|
|
311
|
+
async function resumeHookImpl(tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs) {
|
|
69
312
|
return await waitedUntil(() => {
|
|
70
313
|
return trace('hook.resume', async (span) => {
|
|
71
314
|
const world = await getWorldLazy();
|
|
72
315
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
hook = tokenOrHook;
|
|
84
|
-
workflowRun = await world.runs.get(hook.runId);
|
|
85
|
-
if (encryptionKeyOverride) {
|
|
86
|
-
encryptionKey = encryptionKeyOverride;
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
|
|
90
|
-
encryptionKey = rawKey ? await importKey(rawKey) : undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
316
|
+
const suppliedToken = typeof tokenOrHook === 'string';
|
|
317
|
+
const hook = suppliedToken
|
|
318
|
+
? await world.hooks.getByToken(tokenOrHook)
|
|
319
|
+
: tokenOrHook;
|
|
320
|
+
// The dynamic, response-only `resumeCapabilities` may only be trusted
|
|
321
|
+
// when it came from a by-token lookup performed during this resume.
|
|
322
|
+
const hookResumeCapabilitiesAreFresh = suppliedToken || hookFreshlyLookedUp;
|
|
323
|
+
const info = await resolveHookResumeInfo(hook);
|
|
324
|
+
const { resumeContext } = info;
|
|
93
325
|
span?.setAttributes({
|
|
94
326
|
...Attribute.HookToken(hook.token),
|
|
95
327
|
...Attribute.HookId(hook.hookId),
|
|
96
328
|
...Attribute.WorkflowRunId(hook.runId),
|
|
329
|
+
'workflow.hook.resume_context_source': info.source,
|
|
97
330
|
});
|
|
331
|
+
// The stored `resumeContext` intentionally omits the run's mutable
|
|
332
|
+
// status, so this early client-side rejection only runs on the
|
|
333
|
+
// fallback path (which fetched the run). On the fast path the terminal
|
|
334
|
+
// check happens server-side: `hook_received` against an ended run is
|
|
335
|
+
// rejected, which the catch around `world.events.create` below re-keys
|
|
336
|
+
// to HookNotFoundError: same public contract, no run pre-fetch.
|
|
337
|
+
if (info.run && isTerminalWorkflowRunStatus(info.run.status)) {
|
|
338
|
+
throw new HookNotFoundError(hook.token);
|
|
339
|
+
}
|
|
98
340
|
// Check the target run's capabilities to ensure we encode the
|
|
99
341
|
// payload in a format the run's deployment can decode. For example,
|
|
100
342
|
// runs created before encryption support was added cannot decode
|
|
101
|
-
// the 'encr' serialization format
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
343
|
+
// the 'encr' serialization format, and runs created before
|
|
344
|
+
// byte-stream framing support cannot decode framed byte streams.
|
|
345
|
+
const capabilities = getRunCapabilities(resumeContext.workflowCoreVersion);
|
|
346
|
+
// Resolve how to encrypt the payload for the target run (a WRITE).
|
|
347
|
+
//
|
|
348
|
+
// Preferred path: seal to the run's published X25519 public key, which
|
|
349
|
+
// the stored `resumeContext` carries inline. On the fast path this is
|
|
350
|
+
// the whole win: no run read AND no `getEncryptionKeyForRun`, whose
|
|
351
|
+
// ~350ms `run-key` API round trip dominates cross-deployment hook
|
|
352
|
+
// resumption latency. (On the fallback path the key is synthesized
|
|
353
|
+
// from the fetched run, which also carries it.)
|
|
354
|
+
//
|
|
355
|
+
// Sealing also drops privilege: the resumer ends up able to write a
|
|
356
|
+
// payload for the run without being able to read anything of the
|
|
357
|
+
// run's, where fetching the symmetric key grants both.
|
|
358
|
+
//
|
|
359
|
+
// Deliberately NOT gated on `capabilities.supportedFormats` the way
|
|
360
|
+
// the symmetric fallback below gates `encr`: presence of the public key
|
|
361
|
+
// is itself the gate. A run only carries one if the runtime that
|
|
362
|
+
// created it could also open a sealed payload, and runs are pinned to
|
|
363
|
+
// their creating deployment, so presence is a more reliable attestation
|
|
364
|
+
// than a version compare, and it stays correct even when package
|
|
365
|
+
// versions drift.
|
|
366
|
+
let payloadKey;
|
|
367
|
+
const runPublicKey = encryptionKeyOverride
|
|
368
|
+
? // The caller already holds a key (resumeWebhook resolved one to
|
|
369
|
+
// hydrate hook metadata), so sealing would add an ECDH for no
|
|
370
|
+
// saved round trip. Reuse what it resolved.
|
|
371
|
+
undefined
|
|
372
|
+
: decodeRunPublicKey(resumeContext.encryptionPublicKey);
|
|
373
|
+
if (runPublicKey) {
|
|
374
|
+
payloadKey = sealTo(runPublicKey);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
// Symmetric `encr` write fallback: needs only the AES key
|
|
378
|
+
// (a bare CryptoKey via `resolveHookEncryptionKey`), not the
|
|
379
|
+
// read-side RunPayloadKeys.
|
|
380
|
+
let encryptionKey = encryptionKeyOverride ??
|
|
381
|
+
(await resolveHookEncryptionKey(hook, info));
|
|
382
|
+
if (!capabilities.supportedFormats.has(SerializationFormat.ENCRYPTED)) {
|
|
383
|
+
encryptionKey = undefined;
|
|
384
|
+
}
|
|
385
|
+
payloadKey = encryptionKey;
|
|
106
386
|
}
|
|
387
|
+
// Compress only when the target run and its deployment support the
|
|
388
|
+
// compression formats introduced with spec version 5.
|
|
389
|
+
const compression = (resumeContext.runSpecVersion ?? 0) >=
|
|
390
|
+
SPEC_VERSION_SUPPORTS_COMPRESSION &&
|
|
391
|
+
capabilities.supportedFormats.has(SerializationFormat.GZIP);
|
|
107
392
|
// Dehydrate the payload for storage
|
|
108
393
|
const ops = [];
|
|
394
|
+
const readbackOps = [];
|
|
109
395
|
const v1Compat = isLegacySpecVersion(hook.specVersion);
|
|
110
|
-
const dehydratedPayload = await dehydrateStepReturnValue(payload, hook.runId,
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
396
|
+
const dehydratedPayload = await dehydrateStepReturnValue(payload, hook.runId, payloadKey, ops, globalThis, v1Compat, capabilities.framedByteStreams, compression, undefined, readbackOps);
|
|
397
|
+
// A hook_received event is not durable while its payload still points
|
|
398
|
+
// at stream uploads in flight. Finish those before committing the
|
|
399
|
+
// event — but ONLY the producer-push ops in `ops`. A dehydrated
|
|
400
|
+
// WritableStream lands in `readbackOps` instead: it is a server-stream
|
|
401
|
+
// READER that resolves only once the woken workflow writes into it (a
|
|
402
|
+
// manual webhook's `responseWritable` is the canonical case), so
|
|
403
|
+
// awaiting it here would deadlock the resume against its own wake.
|
|
404
|
+
//
|
|
405
|
+
// A rejection with `undefined` is an expected artifact of the webhook
|
|
406
|
+
// bundle and was historically ignored by the background flush. Keep
|
|
407
|
+
// that tolerance now that the flush is awaited inline.
|
|
408
|
+
await Promise.all(ops.map((op) => op.catch((error) => {
|
|
409
|
+
if (error !== undefined)
|
|
410
|
+
throw error;
|
|
411
|
+
})));
|
|
412
|
+
// Readback pipes (notably a manual webhook response writable) can only
|
|
413
|
+
// finish after the workflow wakes and writes to them. Keep them alive,
|
|
414
|
+
// but never place them in the durability barrier above.
|
|
415
|
+
safeWaitUntil(Promise.all(readbackOps), (err) => {
|
|
416
|
+
if (err === undefined)
|
|
417
|
+
return;
|
|
418
|
+
runtimeLogger.warn('Background readback of hook payload failed', {
|
|
419
|
+
workflowRunId: hook.runId,
|
|
420
|
+
hookId: hook.hookId,
|
|
421
|
+
error: err instanceof Error ? err.message : String(err),
|
|
422
|
+
});
|
|
423
|
+
});
|
|
125
424
|
span?.setAttributes({
|
|
126
|
-
...Attribute.WorkflowName(
|
|
425
|
+
...Attribute.WorkflowName(resumeContext.workflowName),
|
|
127
426
|
});
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
427
|
+
// Link to the run-origin context from the stored trace carrier
|
|
428
|
+
// (skipped when absent or invalid). Resolved before dispatch so the
|
|
429
|
+
// write and the wake both sit under a span that carries it.
|
|
430
|
+
const originLink = await linkToTraceCarrier(resumeContext.traceCarrier);
|
|
431
|
+
if (originLink) {
|
|
432
|
+
span?.addLink?.(originLink);
|
|
433
|
+
}
|
|
434
|
+
const queueName = getWorkflowQueueName(resumeContext.workflowName);
|
|
435
|
+
const queueOptions = {
|
|
436
|
+
deploymentId: resumeContext.deploymentId,
|
|
437
|
+
specVersion: resumeContext.runSpecVersion ?? SPEC_VERSION_LEGACY,
|
|
438
|
+
};
|
|
439
|
+
// The dispatch is strictly serial: the hook_received event is made
|
|
440
|
+
// durable FIRST, and the workflow wake is published only after the
|
|
441
|
+
// write is acknowledged. This is what lets `resumeHook()` resolving
|
|
442
|
+
// mean "the resume survives anything that happens next" — a disposal
|
|
443
|
+
// or run completion racing the queue delivery cannot erase a committed
|
|
444
|
+
// event, and the wake itself carries no payload, so nothing rides on
|
|
445
|
+
// the message but the trigger.
|
|
446
|
+
//
|
|
447
|
+
// Backend dedup is attested when EITHER the live server attests it
|
|
448
|
+
// fresh on this by-token hook (world-vercel: response-only, recomputed
|
|
449
|
+
// every read, so rollback/kill-switch take effect immediately) OR the
|
|
450
|
+
// static world capability is set (world-local: adapter + backend ship
|
|
451
|
+
// together). When attested, the write carries a per-call resumeId +
|
|
452
|
+
// payload digest so transport-level retries of the SAME write converge
|
|
453
|
+
// on exactly one committed event via the backend's (runId, resumeId)
|
|
454
|
+
// constraint. Without it the write is a plain single-shot create,
|
|
455
|
+
// exactly as before dedup existed.
|
|
456
|
+
const backendDedupSupported = (hookResumeCapabilitiesAreFresh
|
|
457
|
+
? (hook.resumeCapabilities?.hookResumeDedupVersion ?? 0)
|
|
458
|
+
: 0) >= HOOK_RESUME_DEDUP_VERSION ||
|
|
459
|
+
world.capabilities?.hookResumeDedup === true;
|
|
460
|
+
const canClaimResume = backendDedupSupported &&
|
|
461
|
+
!v1Compat &&
|
|
462
|
+
dehydratedPayload instanceof Uint8Array;
|
|
463
|
+
span?.setAttributes({
|
|
464
|
+
'workflow.hook.resume_strategy': 'sequential',
|
|
465
|
+
});
|
|
466
|
+
const resumeId = canClaimResume ? generateResumeId() : undefined;
|
|
467
|
+
const payloadDigest = canClaimResume
|
|
468
|
+
? await computeResumePayloadDigest(dehydratedPayload)
|
|
469
|
+
: undefined;
|
|
470
|
+
if (resumeId) {
|
|
471
|
+
span?.setAttributes({ 'workflow.hook.resume_id': resumeId });
|
|
472
|
+
}
|
|
473
|
+
// Re-key any "hook can no longer be received" rejection to
|
|
474
|
+
// HookNotFoundError(hook.token) so `.token` matches the historical
|
|
475
|
+
// contract. The specific error depends on the World:
|
|
476
|
+
// - a genuinely missing hook maps to HookNotFoundError (keyed on
|
|
477
|
+
// the event correlationId / hook ID);
|
|
478
|
+
// - a terminal run on Vercel rejects hook_received with 404, which
|
|
479
|
+
// world-vercel maps to HookNotFoundError;
|
|
480
|
+
// - a terminal run on world-local / world-postgres rejects with
|
|
481
|
+
// RunExpiredError.
|
|
482
|
+
//
|
|
483
|
+
// An EntityConflictError (HTTP 409) is deliberately NOT re-keyed,
|
|
484
|
+
// breaking with the historical mapping: every 409 the backend emits
|
|
485
|
+
// on this write today is TRANSIENT — a slot conflict that escaped the
|
|
486
|
+
// server's own retry budget under contention, or a resume-claim race
|
|
487
|
+
// mid-resolution — and its transaction committed nothing. Re-keying
|
|
488
|
+
// it to HookNotFoundError told the caller (and a webhook sender, via
|
|
489
|
+
// 404) that a retryable failure was permanent, silently dropping the
|
|
490
|
+
// resume. It now surfaces as-is: retryable, with nothing committed.
|
|
491
|
+
// (A 422 resumeId-reuse error likewise passes through unmapped — it
|
|
492
|
+
// means the caller replayed a resumeId with a different payload, and
|
|
493
|
+
// hiding that behind "not found" would mask the bug.)
|
|
494
|
+
const isHookGoneError = (err) => HookNotFoundError.is(err) || RunExpiredError.is(err);
|
|
495
|
+
try {
|
|
496
|
+
await world.events.create(hook.runId, {
|
|
497
|
+
eventType: 'hook_received',
|
|
498
|
+
specVersion: SPEC_VERSION_CURRENT,
|
|
499
|
+
correlationId: hook.hookId,
|
|
500
|
+
eventData: {
|
|
501
|
+
...(v1Compat ? {} : { token: hook.token }),
|
|
502
|
+
payload: dehydratedPayload,
|
|
503
|
+
},
|
|
504
|
+
}, {
|
|
505
|
+
v1Compat,
|
|
506
|
+
...(resumeId && payloadDigest
|
|
507
|
+
? { resumeId, resumePayloadDigest: payloadDigest }
|
|
508
|
+
: {}),
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
if (isHookGoneError(err)) {
|
|
513
|
+
throw new HookNotFoundError(hook.token);
|
|
133
514
|
}
|
|
515
|
+
throw err;
|
|
134
516
|
}
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
|
|
517
|
+
// Stamped AFTER the write resolves (entry-time attributes cannot tell
|
|
518
|
+
// an attempted resume from a committed one): together with
|
|
519
|
+
// HookWakePublished below, this is what makes a stranded resume — a
|
|
520
|
+
// committed event whose wake never went out or was never delivered —
|
|
521
|
+
// queryable from traces. See the alerting note on HookWakePublished.
|
|
522
|
+
span?.setAttributes(Attribute.HookResumeCommitted(true));
|
|
523
|
+
// T1 of the TTR window. Stamped immediately before the publish so
|
|
524
|
+
// `producer_prep` covers exactly the work above it (hook lookup, key
|
|
525
|
+
// resolution, serialization, and the awaited hook_received write,
|
|
526
|
+
// which is genuinely serial here).
|
|
527
|
+
const queuePublishRequestedAtMs = Date.now();
|
|
528
|
+
await publishHookWakeWithRetry(() => world.queue(queueName, {
|
|
138
529
|
runId: hook.runId,
|
|
139
|
-
|
|
140
|
-
|
|
530
|
+
traceCarrier: resumeContext.traceCarrier ?? undefined,
|
|
531
|
+
hookResumeTiming: {
|
|
532
|
+
resumeRequestedAtMs,
|
|
533
|
+
queuePublishRequestedAtMs,
|
|
534
|
+
strategy: 'sequential',
|
|
535
|
+
},
|
|
141
536
|
}, {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
537
|
+
...queueOptions,
|
|
538
|
+
// Dedup retried publishes whose response was lost: a
|
|
539
|
+
// duplicate wake is harmless for correctness (deterministic
|
|
540
|
+
// replay) but costs a full replay of the run, and the queue
|
|
541
|
+
// accepts a repeated idempotency key by delivering only one
|
|
542
|
+
// of the messages. Claim-less writes have no resumeId and
|
|
543
|
+
// keep the previous behavior.
|
|
544
|
+
...(resumeId ? { idempotencyKey: `hook-${resumeId}` } : {}),
|
|
545
|
+
}), world.isDeploymentUnavailableError?.bind(world));
|
|
546
|
+
span?.setAttributes(Attribute.HookWakePublished(true));
|
|
547
|
+
return asLazyMetadataHook(hook);
|
|
146
548
|
}
|
|
147
549
|
catch (err) {
|
|
148
550
|
span?.setAttributes({
|
|
@@ -190,7 +592,14 @@ export async function resumeHook(tokenOrHook, payload, encryptionKeyOverride) {
|
|
|
190
592
|
* ```
|
|
191
593
|
*/
|
|
192
594
|
export async function resumeWebhook(token, request) {
|
|
193
|
-
|
|
595
|
+
// T0 of the hook-resume TTR window. Everything below (the by-token lookup,
|
|
596
|
+
// the run-key resolution it may trigger, and the `respondWith` setup) is
|
|
597
|
+
// real producer-side latency on this path, so the window has to open here
|
|
598
|
+
// and not inside `resumeHookImpl`; otherwise webhook resumes would report a
|
|
599
|
+
// systematically shorter total than `resumeHook` ones into the same metric.
|
|
600
|
+
const resumeRequestedAtMs = Date.now();
|
|
601
|
+
const world = await getWorldLazy();
|
|
602
|
+
const { hook, metadataEncryptionKey } = withLazyMetadata(await world.hooks.getByToken(token));
|
|
194
603
|
// Only webhooks can be resumed via the public endpoint.
|
|
195
604
|
// If the hook was created via createHook() (isWebhook !== true),
|
|
196
605
|
// throw the same "not found" error the world would throw for a missing
|
|
@@ -198,30 +607,44 @@ export async function resumeWebhook(token, request) {
|
|
|
198
607
|
if (hook.isWebhook === false) {
|
|
199
608
|
throw new HookNotFoundError(token);
|
|
200
609
|
}
|
|
610
|
+
// `respondWith` lives in the hook's metadata, so this is the one resume path
|
|
611
|
+
// that has to read it. Only a webhook that actually stored metadata pays for
|
|
612
|
+
// the hydration: the common default webhook — createWebhook() with no
|
|
613
|
+
// `respondWith` — stores none, so this resolves `undefined` with no ~350ms
|
|
614
|
+
// `run-key` API round trip, and hands `resumeHook` no key, leaving it free to
|
|
615
|
+
// seal the payload to the run's published public key instead.
|
|
616
|
+
const metadata = await hook.metadata;
|
|
201
617
|
let response;
|
|
202
618
|
let responseReadable;
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
'respondWith' in hook.metadata) {
|
|
206
|
-
if (hook.metadata.respondWith === 'manual') {
|
|
619
|
+
if (metadata && typeof metadata === 'object' && 'respondWith' in metadata) {
|
|
620
|
+
if (metadata.respondWith === 'manual') {
|
|
207
621
|
const { readable, writable } = new TransformStream();
|
|
208
622
|
responseReadable = readable;
|
|
209
623
|
// The request instance includes the writable stream which will be used
|
|
210
624
|
// to write the response to the client from within the workflow run
|
|
211
625
|
request[WEBHOOK_RESPONSE_WRITABLE] = writable;
|
|
212
626
|
}
|
|
213
|
-
else if (
|
|
214
|
-
response =
|
|
627
|
+
else if (metadata.respondWith instanceof Response) {
|
|
628
|
+
response = metadata.respondWith;
|
|
215
629
|
}
|
|
216
630
|
else {
|
|
217
|
-
throw new WorkflowRuntimeError(`Invalid \`respondWith\` value: ${
|
|
631
|
+
throw new WorkflowRuntimeError(`Invalid \`respondWith\` value: ${metadata.respondWith}`, { slug: ERROR_SLUGS.WEBHOOK_INVALID_RESPOND_WITH_VALUE });
|
|
218
632
|
}
|
|
219
633
|
}
|
|
220
634
|
else {
|
|
221
635
|
// No `respondWith` value implies the default behavior of returning a 202
|
|
222
636
|
response = new Response(null, { status: 202 });
|
|
223
637
|
}
|
|
224
|
-
|
|
638
|
+
// `hook` was just fetched by token above, so its response-only
|
|
639
|
+
// `resumeCapabilities` reflects the live backend. Call the internal
|
|
640
|
+
// implementation with the fresh attestation so the write's idempotency claim
|
|
641
|
+
// stays available without a second GET. (The public `resumeHook` never sets
|
|
642
|
+
// this, so a caller cannot forge it.)
|
|
643
|
+
//
|
|
644
|
+
// Reuse whatever key the metadata hydration above resolved (`undefined` when
|
|
645
|
+
// it resolved none) so a metadata-bearing webhook resolves the run key
|
|
646
|
+
// exactly once end to end.
|
|
647
|
+
await resumeHookImpl(hook, request, metadataEncryptionKey(), true, resumeRequestedAtMs);
|
|
225
648
|
if (responseReadable) {
|
|
226
649
|
// Wait for the readable stream to emit one chunk,
|
|
227
650
|
// which is the `Response` object
|
|
@@ -239,4 +662,4 @@ export async function resumeWebhook(token, request) {
|
|
|
239
662
|
}
|
|
240
663
|
return response;
|
|
241
664
|
}
|
|
242
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzdW1lLWhvb2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9yZXN1bWUtaG9vay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDOUMsT0FBTyxFQUNMLFdBQVcsRUFDWCxpQkFBaUIsRUFDakIsb0JBQW9CLEdBQ3JCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUVMLG1CQUFtQixFQUNuQixvQkFBb0IsRUFDcEIsbUJBQW1CLEdBR3BCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDeEQsT0FBTyxFQUFrQixTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM3RCxPQUFPLEVBQ0wsd0JBQXdCLEVBQ3hCLG9CQUFvQixFQUNwQixtQkFBbUIsR0FDcEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUQsT0FBTyxLQUFLLFNBQVMsTUFBTSxzQ0FBc0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbkQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXBEOzs7R0FHRztBQUNILEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxLQUFhO0lBS2hELE1BQU0sS0FBSyxHQUFHLE1BQU0sWUFBWSxFQUFFLENBQUM7SUFDbkMsTUFBTSxJQUFJLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRCxNQUFNLEdB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LElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLEVBQzdELEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQyxrQ0FBa0MsRUFBRSxDQUN6RCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04seUVBQXlFO1FBQ3pFLFFBQVEsR0FBRyxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsTUFBTSxVQUFVLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxhQUFhLENBQUMsQ0FBQztJQUUvQyxJQUFJLGdCQUFnQixFQUFFLENBQUM7UUFDckIsa0RBQWtEO1FBQ2xELGlDQUFpQztRQUNqQyxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUM1QyxNQUFNLEtBQUssR0FBRyxNQUFNLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNsQyxJQUFJLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNoQixRQUFRLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztRQUN6QixDQUFDO1FBQ0QsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxNQUFNLElBQUksb0JBQW9CLENBQUMsc0NBQXNDLEVBQUU7WUFDckUsSUFBSSxFQUFFLFdBQVcsQ0FBQyx5QkFBeUI7U0FDNUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB3YWl0VW50aWwgfSBmcm9tICdAdmVyY2VsL2Z1bmN0aW9ucyc7XG5pbXBvcnQge1xuICBFUlJPUl9TTFVHUyxcbiAgSG9va05vdEZvdW5kRXJyb3IsXG4gIFdvcmtmbG93UnVudGltZUVycm9yLFxufSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB7XG4gIHR5cGUgSG9vayxcbiAgaXNMZWdhY3lTcGVjVmVyc2lvbixcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gIHR5cGUgV29ya2Zsb3dJbnZva2VQYXlsb2FkLFxuICB0eXBlIFdvcmtmbG93UnVuLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgZ2V0UnVuQ2FwYWJpbGl0aWVzIH0gZnJvbSAnLi4vY2FwYWJpbGl0aWVzLmpzJztcbmltcG9ydCB7IHR5cGUgQ3J5cHRvS2V5LCBpbXBvcnRLZXkgfSBmcm9tICcuLi9lbmNyeXB0aW9uLmpzJztcbmltcG9ydCB7XG4gIGRlaHlkcmF0ZVN0ZXBSZXR1cm5WYWx1ZSxcbiAgaHlkcmF0ZVN0ZXBBcmd1bWVudHMsXG4gIFNlcmlhbGl6YXRpb25Gb3JtYXQsXG59IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0IHsgV0VCSE9PS19SRVNQT05TRV9XUklUQUJMRSB9IGZyb20gJy4uL3N5bWJvbHMuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBnZXRTcGFuQ29udGV4dEZvclRyYWNlQ2FycmllciwgdHJhY2UgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHsgd2FpdGVkVW50aWwgfSBmcm9tICcuLi91dGlsLmpzJztcbmltcG9ydCB7IGdldFdvcmxkTGF6eSB9IGZyb20gJy4vZ2V0LXdvcmxkLWxhenkuanMnO1xuaW1wb3J0IHsgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUgfSBmcm9tICcuL2hlbHBlcnMuanMnO1xuXG4vKipcbiAqIEludGVybmFsIGhlbHBlciB0aGF0IHJldHVybnMgdGhlIGhvb2ssIHRoZSBhc3NvY2lhdGVkIHdvcmtmbG93IHJ1bixcbiAqIGFuZCB0aGUgcmVzb2x2ZWQgZW5jcnlwdGlvbiBrZXkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldEhvb2tCeVRva2VuV2l0aEtleSh0b2tlbjogc3RyaW5nKTogUHJvbWlzZTx7XG4gIGhvb2s6IEhvb2s7XG4gIHJ1bjogV29ya2Zsb3dSdW47XG4gIGVuY3J5cHRpb25LZXk6IENyeXB0b0tleSB8IHVuZGVmaW5lZDtcbn0+IHtcbiAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZExhenkoKTtcbiAgY29uc3QgaG9vayA9IGF3YWl0IHdvcmxkLmhvb2tzLmdldEJ5VG9rZW4odG9rZW4pO1xuICBjb25zdCBydW4gPSBhd2FpdCB3b3JsZC5ydW5zLmdldChob29rLnJ1bklkKTtcbiAgY29uc3QgcmF3S2V5ID0gYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJ1bik7XG4gIGNvbnN0IGVuY3J5cHRpb25LZXkgPSByYXdLZXkgPyBhd2FpdCBpbXBvcnRLZXkocmF3S2V5KSA6IHVuZGVmaW5lZDtcbiAgaWYgKHR5cGVvZiBob29rLm1ldGFkYXRhICE9PSAndW5kZWZpbmVkJykge1xuICAgIGhvb2subWV0YWRhdGEgPSBhd2FpdCBoeWRyYXRlU3RlcEFyZ3VtZW50cyhcbiAgICAgIGhvb2subWV0YWRhdGEgYXMgYW55LFxuICAgICAgaG9vay5ydW5JZCxcbiAgICAgIGVuY3J5cHRpb25LZXlcbiAgICApO1xuICB9XG4gIHJldHVybiB7IGhvb2ssIHJ1biwgZW5jcnlwdGlvbktleSB9O1xufVxuXG4vKipcbiAqIEdldCB0aGUgaG9vayBieSB0b2tlbiB0byBmaW5kIHRoZSBhc3NvY2lhdGVkIHdvcmtmbG93IHJ1bixcbiAqIGFuZCBoeWRyYXRlIHRoZSBgbWV0YWRhdGFgIHByb3BlcnR5IGlmIGl0IHdhcyBzZXQgZnJvbSB3aXRoaW5cbiAqIHRoZSB3b3JrZmxvdyBydW4uXG4gKlxuICogQHBhcmFtIHRva2VuIC0gVGhlIHVuaXF1ZSB0b2tlbiBpZGVudGlmeWluZyB0aGUgaG9va1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0SG9va0J5VG9rZW4odG9rZW46IHN0cmluZyk6IFByb21pc2U8SG9vaz4ge1xuICBjb25zdCB7IGhvb2sgfSA9IGF3YWl0IGdldEhvb2tCeVRva2VuV2l0aEtleSh0b2tlbik7XG4gIHJldHVybiBob29rO1xufVxuXG4vKipcbiAqIFJlc3VtZXMgYSB3b3JrZmxvdyBydW4gYnkgc2VuZGluZyBhIHBheWxvYWQgdG8gYSBob29rIGlkZW50aWZpZWQgYnkgaXRzIHRva2VuLlxuICpcbiAqIFRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIGV4dGVybmFsbHkgKGUuZy4sIGZyb20gYW4gQVBJIHJvdXRlIG9yIHNlcnZlciBhY3Rpb24pXG4gKiB0byBzZW5kIGRhdGEgdG8gYSBob29rIGFuZCByZXN1bWUgdGhlIGFzc29jaWF0ZWQgd29ya2Zsb3cgcnVuLlxuICpcbiAqIEBwYXJhbSB0b2tlbk9ySG9vayAtIFRoZSB1bmlxdWUgdG9rZW4gaWRlbnRpZnlpbmcgdGhlIGhvb2ssIG9yIHRoZSBob29rIG9iamVjdCBpdHNlbGZcbiAqIEBwYXJhbSBwYXlsb2FkIC0gVGhlIGRhdGEgcGF5bG9hZCB0byBzZW5kIHRvIHRoZSBob29rXG4gKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaG9va1xuICogQHRocm93cyBFcnJvciBpZiB0aGUgaG9vayBpcyBub3QgZm91bmQgb3IgaWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIHByb2Nlc3NcbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYHRzXG4gKiAvLyBJbiBhbiBBUEkgcm91dGVcbiAqIGltcG9ydCB7IHJlc3VtZUhvb2sgfSBmcm9tICdAd29ya2Zsb3cvY29yZS9ydW50aW1lJztcbiAqXG4gKiBleHBvcnQgYXN5bmMgZnVuY3Rpb24gUE9TVChyZXF1ZXN0OiBSZXF1ZXN0KSB7XG4gKiAgIGNvbnN0IHsgdG9rZW4sIGRhdGEgfSA9IGF3YWl0IHJlcXVlc3QuanNvbigpO1xuICpcbiAqICAgdHJ5IHtcbiAqICAgICBjb25zdCBob29rID0gYXdhaXQgcmVzdW1lSG9vayh0b2tlbiwgZGF0YSk7XG4gKiAgICAgcmV0dXJuIFJlc3BvbnNlLmpzb24oeyBydW5JZDogaG9vay5ydW5JZCB9KTtcbiAqICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKCdIb29rIG5vdCBmb3VuZCcsIHsgc3RhdHVzOiA0MDQgfSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzdW1lSG9vazxUID0gYW55PihcbiAgdG9rZW5Pckhvb2s6IHN0cmluZyB8IEhvb2ssXG4gIHBheWxvYWQ6IFQsXG4gIGVuY3J5cHRpb25LZXlPdmVycmlkZT86IENyeXB0b0tleVxuKTogUHJvbWlzZTxIb29rPiB7XG4gIHJldHVybiBhd2FpdCB3YWl0ZWRVbnRpbCgoKSA9PiB7XG4gICAgcmV0dXJuIHRyYWNlKCdob29rLnJlc3VtZScsIGFzeW5jIChzcGFuKSA9PiB7XG4gICAgICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkTGF6eSgpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBsZXQgaG9vazogSG9vaztcbiAgICAgICAgbGV0IHdvcmtmbG93UnVuOiBXb3JrZmxvd1J1bjtcbiAgICAgICAgbGV0IGVuY3J5cHRpb25LZXk6IENyeXB0b0tleSB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHR5cGVvZiB0b2tlbk9ySG9vayA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBnZXRIb29rQnlUb2tlbldpdGhLZXkodG9rZW5Pckhvb2spO1xuICAgICAgICAgIGhvb2sgPSByZXN1bHQuaG9vaztcbiAgICAgICAgICB3b3JrZmxvd1J1biA9IHJlc3VsdC5ydW47XG4gICAgICAgICAgZW5jcnlwdGlvbktleSA9IGVuY3J5cHRpb25LZXlPdmVycmlkZSA/PyByZXN1bHQuZW5jcnlwdGlvbktleTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBob29rID0gdG9rZW5Pckhvb2s7XG4gICAgICAgICAgd29ya2Zsb3dSdW4gPSBhd2FpdCB3b3JsZC5ydW5zLmdldChob29rLnJ1bklkKTtcbiAgICAgICAgICBpZiAoZW5jcnlwdGlvbktleU92ZXJyaWRlKSB7XG4gICAgICAgICAgICBlbmNyeXB0aW9uS2V5ID0gZW5jcnlwdGlvbktleU92ZXJyaWRlO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCByYXdLZXkgPSBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4od29ya2Zsb3dSdW4pO1xuICAgICAgICAgICAgZW5jcnlwdGlvbktleSA9IHJhd0tleSA/IGF3YWl0IGltcG9ydEtleShyYXdLZXkpIDogdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Ib29rVG9rZW4oaG9vay50b2tlbiksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLkhvb2tJZChob29rLmhvb2tJZCksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuSWQoaG9vay5ydW5JZCksXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIENoZWNrIHRoZSB0YXJnZXQgcnVuJ3MgY2FwYWJpbGl0aWVzIHRvIGVuc3VyZSB3ZSBlbmNvZGUgdGhlXG4gICAgICAgIC8vIHBheWxvYWQgaW4gYSBmb3JtYXQgdGhlIHJ1bidzIGRlcGxveW1lbnQgY2FuIGRlY29kZS4gRm9yIGV4YW1wbGUsXG4gICAgICAgIC8vIHJ1bnMgY3JlYXRlZCBiZWZvcmUgZW5jcnlwdGlvbiBzdXBwb3J0IHdhcyBhZGRlZCBjYW5ub3QgZGVjb2RlXG4gICAgICAgIC8vIHRoZSAnZW5jcicgc2VyaWFsaXphdGlvbiBmb3JtYXQuXG4gICAgICAgIGNvbnN0IHJhd1ZlcnNpb24gPSB3b3JrZmxvd1J1bi5leGVjdXRpb25Db250ZXh0Py53b3JrZmxvd0NvcmVWZXJzaW9uO1xuICAgICAgICBjb25zdCB7IHN1cHBvcnRlZEZvcm1hdHMgfSA9IGdldFJ1bkNhcGFiaWxpdGllcyhcbiAgICAgICAgICB0eXBlb2YgcmF3VmVyc2lvbiA9PT0gJ3N0cmluZycgPyByYXdWZXJzaW9uIDogdW5kZWZpbmVkXG4gICAgICAgICk7XG4gICAgICAgIGlmICghc3VwcG9ydGVkRm9ybWF0cy5oYXMoU2VyaWFsaXphdGlvbkZvcm1hdC5FTkNSWVBURUQpKSB7XG4gICAgICAgICAgZW5jcnlwdGlvbktleSA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERlaHlkcmF0ZSB0aGUgcGF5bG9hZCBmb3Igc3RvcmFnZVxuICAgICAgICBjb25zdCBvcHM6IFByb21pc2U8YW55PltdID0gW107XG4gICAgICAgIGNvbnN0IHYxQ29tcGF0ID0gaXNMZWdhY3lTcGVjVmVyc2lvbihob29rLnNwZWNWZXJzaW9uKTtcbiAgICAgICAgY29uc3QgZGVoeWRyYXRlZFBheWxvYWQgPSBhd2FpdCBkZWh5ZHJhdGVTdGVwUmV0dXJuVmFsdWUoXG4gICAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgICBob29rLnJ1bklkLFxuICAgICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgICAgb3BzLFxuICAgICAgICAgIGdsb2JhbFRoaXMsXG4gICAgICAgICAgdjFDb21wYXRcbiAgICAgICAgKTtcbiAgICAgICAgLy8gTk9URTogV29ya2Fyb3VuZCBpbnN0ZWFkIG9mIGluamVjdGluZyBjYXRjaGluZyB1bmRlZmluZWQgdW5oYW5kbGVkIHJlamVjdGlvbnMgaW4gd2ViaG9vayBidW5kbGVcbiAgICAgICAgd2FpdFVudGlsKFxuICAgICAgICAgIFByb21pc2UuYWxsKG9wcykuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgaWYgKGVyciAhPT0gdW5kZWZpbmVkKSB0aHJvdyBlcnI7XG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBDcmVhdGUgYSBob29rX3JlY2VpdmVkIGV2ZW50IHdpdGggdGhlIHBheWxvYWRcbiAgICAgICAgYXdhaXQgd29ybGQuZXZlbnRzLmNyZWF0ZShcbiAgICAgICAgICBob29rLnJ1bklkLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogJ2hvb2tfcmVjZWl2ZWQnLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgICAgY29ycmVsYXRpb25JZDogaG9vay5ob29rSWQsXG4gICAgICAgICAgICBldmVudERhdGE6IHtcbiAgICAgICAgICAgICAgcGF5bG9hZDogZGVoeWRyYXRlZFBheWxvYWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgeyB2MUNvbXBhdCB9XG4gICAgICAgICk7XG5cbiAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93TmFtZSh3b3JrZmxvd1J1bi53b3JrZmxvd05hbWUpLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCB0cmFjZUNhcnJpZXIgPSB3b3JrZmxvd1J1bi5leGVjdXRpb25Db250ZXh0Py50cmFjZUNhcnJpZXI7XG5cbiAgICAgICAgaWYgKHRyYWNlQ2Fycmllcikge1xuICAgICAgICAgIGNvbnN0IGNvbnRleHQgPSBhd2FpdCBnZXRTcGFuQ29udGV4dEZvclRyYWNlQ2Fycmllcih0cmFjZUNhcnJpZXIpO1xuICAgICAgICAgIGlmIChjb250ZXh0KSB7XG4gICAgICAgICAgICBzcGFuPy5hZGRMaW5rPy4oeyBjb250ZXh0IH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlLXRyaWdnZXIgdGhlIHdvcmtmbG93IGFnYWluc3QgdGhlIGRlcGxveW1lbnQgSUQgYXNzb2NpYXRlZFxuICAgICAgICAvLyB3aXRoIHRoZSB3b3JrZmxvdyBydW4gdGhhdCB0aGUgaG9vayBiZWxvbmdzIHRvXG4gICAgICAgIGF3YWl0IHdvcmxkLnF1ZXVlKFxuICAgICAgICAgIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93UnVuLndvcmtmbG93TmFtZSksXG4gICAgICAgICAge1xuICAgICAgICAgICAgcnVuSWQ6IGhvb2sucnVuSWQsXG4gICAgICAgICAgICAvLyBhdHRhY2ggdGhlIHRyYWNlIGNhcnJpZXIgZnJvbSB0aGUgd29ya2Zsb3cgcnVuXG4gICAgICAgICAgICB0cmFjZUNhcnJpZXI6XG4gICAgICAgICAgICAgIHdvcmtmbG93UnVuLmV4ZWN1dGlvbkNvbnRleHQ/LnRyYWNlQ2FycmllciA/PyB1bmRlZmluZWQsXG4gICAgICAgICAgfSBzYXRpc2ZpZXMgV29ya2Zsb3dJbnZva2VQYXlsb2FkLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGRlcGxveW1lbnRJZDogd29ya2Zsb3dSdW4uZGVwbG95bWVudElkLFxuICAgICAgICAgICAgc3BlY1ZlcnNpb246IHdvcmtmbG93UnVuLnNwZWNWZXJzaW9uID8/IFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHJldHVybiBob29rO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Ib29rVG9rZW4oXG4gICAgICAgICAgICB0eXBlb2YgdG9rZW5Pckhvb2sgPT09ICdzdHJpbmcnID8gdG9rZW5Pckhvb2sgOiB0b2tlbk9ySG9vay50b2tlblxuICAgICAgICAgICksXG4gICAgICAgICAgLi4uQXR0cmlidXRlLkhvb2tGb3VuZChmYWxzZSksXG4gICAgICAgIH0pO1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFJlc3VtZXMgYSB3ZWJob29rIGJ5IHNlbmRpbmcgYSB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL1JlcXVlc3QgfCBSZXF1ZXN0fVxuICogb2JqZWN0IHRvIGEgaG9vayBpZGVudGlmaWVkIGJ5IGl0cyB0b2tlbi5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBleHRlcm5hbGx5IChlLmcuLCBmcm9tIGFuIEFQSSByb3V0ZSBvciBzZXJ2ZXIgYWN0aW9uKVxuICogdG8gc2VuZCBhIHJlcXVlc3QgdG8gYSB3ZWJob29rIGFuZCByZXN1bWUgdGhlIGFzc29jaWF0ZWQgd29ya2Zsb3cgcnVuLlxuICpcbiAqIEBwYXJhbSB0b2tlbiAtIFRoZSB1bmlxdWUgdG9rZW4gaWRlbnRpZnlpbmcgdGhlIGhvb2tcbiAqIEBwYXJhbSByZXF1ZXN0IC0gVGhlIHJlcXVlc3QgdG8gc2VuZCB0byB0aGUgaG9va1xuICogQHJldHVybnMgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHJlc3BvbnNlXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBob29rIGlzIG5vdCBmb3VuZCBvciBpZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgcHJvY2Vzc1xuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBgdHNcbiAqIC8vIEluIGFuIEFQSSByb3V0ZVxuICogaW1wb3J0IHsgcmVzdW1lV2ViaG9vayB9IGZyb20gJ0B3b3JrZmxvdy9jb3JlL3J1bnRpbWUnO1xuICpcbiAqIGV4cG9ydCBhc3luYyBmdW5jdGlvbiBQT1NUKHJlcXVlc3Q6IFJlcXVlc3QpIHtcbiAqICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXF1ZXN0LnVybCk7XG4gKiAgIGNvbnN0IHRva2VuID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoJ3Rva2VuJyk7XG4gKlxuICogICBpZiAoIXRva2VuKSB7XG4gKiAgICAgcmV0dXJuIG5ldyBSZXNwb25zZSgnTWlzc2luZyB0b2tlbicsIHsgc3RhdHVzOiA0MDAgfSk7XG4gKiAgIH1cbiAqXG4gKiAgIHRyeSB7XG4gKiAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCByZXN1bWVXZWJob29rKHRva2VuLCByZXF1ZXN0KTtcbiAqICAgICByZXR1cm4gcmVzcG9uc2U7XG4gKiAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgICAgcmV0dXJuIG5ldyBSZXNwb25zZSgnV2ViaG9vayBub3QgZm91bmQnLCB7IHN0YXR1czogNDA0IH0pO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc3VtZVdlYmhvb2soXG4gIHRva2VuOiBzdHJpbmcsXG4gIHJlcXVlc3Q6IFJlcXVlc3Rcbik6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgY29uc3QgeyBob29rLCBlbmNyeXB0aW9uS2V5IH0gPSBhd2FpdCBnZXRIb29rQnlUb2tlbldpdGhLZXkodG9rZW4pO1xuXG4gIC8vIE9ubHkgd2ViaG9va3MgY2FuIGJlIHJlc3VtZWQgdmlhIHRoZSBwdWJsaWMgZW5kcG9pbnQuXG4gIC8vIElmIHRoZSBob29rIHdhcyBjcmVhdGVkIHZpYSBjcmVhdGVIb29rKCkgKGlzV2ViaG9vayAhPT0gdHJ1ZSksXG4gIC8vIHRocm93IHRoZSBzYW1lIFwibm90IGZvdW5kXCIgZXJyb3IgdGhlIHdvcmxkIHdvdWxkIHRocm93IGZvciBhIG1pc3NpbmdcbiAgLy8gdG9rZW4uIFRoaXMgcHJldmVudHMgbGVha2luZyB0aGF0IHRoZSB0b2tlbiBpcyB2YWxpZC5cbiAgaWYgKGhvb2suaXNXZWJob29rID09PSBmYWxzZSkge1xuICAgIHRocm93IG5ldyBIb29rTm90Rm91bmRFcnJvcih0b2tlbik7XG4gIH1cblxuICBsZXQgcmVzcG9uc2U6IFJlc3BvbnNlIHwgdW5kZWZpbmVkO1xuICBsZXQgcmVzcG9uc2VSZWFkYWJsZTogUmVhZGFibGVTdHJlYW08UmVzcG9uc2U+IHwgdW5kZWZpbmVkO1xuICBpZiAoXG4gICAgaG9vay5tZXRhZGF0YSAmJlxuICAgIHR5cGVvZiBob29rLm1ldGFkYXRhID09PSAnb2JqZWN0JyAmJlxuICAgICdyZXNwb25kV2l0aCcgaW4gaG9vay5tZXRhZGF0YVxuICApIHtcbiAgICBpZiAoaG9vay5tZXRhZGF0YS5yZXNwb25kV2l0aCA9PT0gJ21hbnVhbCcpIHtcbiAgICAgIGNvbnN0IHsgcmVhZGFibGUsIHdyaXRhYmxlIH0gPSBuZXcgVHJhbnNmb3JtU3RyZWFtPFJlc3BvbnNlLCBSZXNwb25zZT4oKTtcbiAgICAgIHJlc3BvbnNlUmVhZGFibGUgPSByZWFkYWJsZTtcblxuICAgICAgLy8gVGhlIHJlcXVlc3QgaW5zdGFuY2UgaW5jbHVkZXMgdGhlIHdyaXRhYmxlIHN0cmVhbSB3aGljaCB3aWxsIGJlIHVzZWRcbiAgICAgIC8vIHRvIHdyaXRlIHRoZSByZXNwb25zZSB0byB0aGUgY2xpZW50IGZyb20gd2l0aGluIHRoZSB3b3JrZmxvdyBydW5cbiAgICAgIChyZXF1ZXN0IGFzIGFueSlbV0VCSE9PS19SRVNQT05TRV9XUklUQUJMRV0gPSB3cml0YWJsZTtcbiAgICB9IGVsc2UgaWYgKGhvb2subWV0YWRhdGEucmVzcG9uZFdpdGggaW5zdGFuY2VvZiBSZXNwb25zZSkge1xuICAgICAgcmVzcG9uc2UgPSBob29rLm1ldGFkYXRhLnJlc3BvbmRXaXRoO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIFxcYHJlc3BvbmRXaXRoXFxgIHZhbHVlOiAke2hvb2subWV0YWRhdGEucmVzcG9uZFdpdGh9YCxcbiAgICAgICAgeyBzbHVnOiBFUlJPUl9TTFVHUy5XRUJIT09LX0lOVkFMSURfUkVTUE9ORF9XSVRIX1ZBTFVFIH1cbiAgICAgICk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIE5vIGByZXNwb25kV2l0aGAgdmFsdWUgaW1wbGllcyB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZiByZXR1cm5pbmcgYSAyMDJcbiAgICByZXNwb25zZSA9IG5ldyBSZXNwb25zZShudWxsLCB7IHN0YXR1czogMjAyIH0pO1xuICB9XG5cbiAgYXdhaXQgcmVzdW1lSG9vayhob29rLCByZXF1ZXN0LCBlbmNyeXB0aW9uS2V5KTtcblxuICBpZiAocmVzcG9uc2VSZWFkYWJsZSkge1xuICAgIC8vIFdhaXQgZm9yIHRoZSByZWFkYWJsZSBzdHJlYW0gdG8gZW1pdCBvbmUgY2h1bmssXG4gICAgLy8gd2hpY2ggaXMgdGhlIGBSZXNwb25zZWAgb2JqZWN0XG4gICAgY29uc3QgcmVhZGVyID0gcmVzcG9uc2VSZWFkYWJsZS5nZXRSZWFkZXIoKTtcbiAgICBjb25zdCBjaHVuayA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgaWYgKGNodW5rLnZhbHVlKSB7XG4gICAgICByZXNwb25zZSA9IGNodW5rLnZhbHVlO1xuICAgIH1cbiAgICByZWFkZXIuY2FuY2VsKCk7XG4gIH1cblxuICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKCdXb3JrZmxvdyBydW4gZGlkIG5vdCBzZW5kIGEgcmVzcG9uc2UnLCB7XG4gICAgICBzbHVnOiBFUlJPUl9TTFVHUy5XRUJIT09LX1JFU1BPTlNFX05PVF9TRU5ULFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHJlc3BvbnNlO1xufVxuIl19
|
|
665
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzdW1lLWhvb2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVudGltZS9yZXN1bWUtaG9vay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsV0FBVyxFQUNYLGlCQUFpQixFQUNqQixlQUFlLEVBQ2Ysb0JBQW9CLEdBQ3JCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUNMLHlCQUF5QixFQUV6QixtQkFBbUIsRUFDbkIsMkJBQTJCLEVBQzNCLG9CQUFvQixFQUNwQixtQkFBbUIsRUFDbkIsaUNBQWlDLEdBSWxDLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3RFLE9BQU8sRUFDTCx3QkFBd0IsRUFDeEIsb0JBQW9CLEVBRXBCLG1CQUFtQixFQUNuQixNQUFNLEdBQ1AsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUQsT0FBTyxLQUFLLFNBQVMsTUFBTSxzQ0FBc0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNwRCxPQUFPLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRTdELG1FQUFtRTtBQUNuRSxNQUFNLGdCQUFnQixHQUFHLGdCQUFnQixFQUFFLENBQUM7QUFFNUM7Ozs7R0FJRztBQUNILEtBQUssVUFBVSwwQkFBMEIsQ0FBQyxLQUFpQjtJQUN6RCxNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUM1RCxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNwQyxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUM7SUFDYixLQUFLLE1BQU0sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3JCLEdBQUcsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFVLENBQUM7QUFFckQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFTLG9CQUFvQixDQUMzQixLQUFjLEVBQ2QsNEJBQTBEO0lBRTFELElBQUksNEJBQTRCLEVBQUUsQ0FBQyxLQUFLLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUN4RCxNQUFNLE1BQU0sR0FBSSxLQUFvRCxJQUFJLEVBQUUsQ0FBQztJQUMzRSxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUM7SUFDaEQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM3QixPQUFPLElBQUksSUFBSSxHQUFHLElBQUksSUFBSSxLQUFLLEdBQUcsSUFBSSxJQUFJLEtBQUssR0FBRyxDQUFDO0lBQ3JELENBQUM7SUFDRCxNQUFNLElBQUksR0FBSSxLQUFzQixFQUFFLElBQUksQ0FBQztJQUMzQyxPQUFPLENBQ0wsSUFBSSxLQUFLLGlCQUFpQjtRQUMxQixJQUFJLEtBQUssbUJBQW1CO1FBQzVCLElBQUksS0FBSyxnQkFBZ0IsQ0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRCx1RUFBdUU7QUFDdkUsNEVBQTRFO0FBQzVFLDRFQUE0RTtBQUM1RSxLQUFLLFVBQVUsd0JBQXdCLENBQ3JDLE9BQStCLEVBQy9CLDRCQUEwRDtJQUUxRCxJQUFJLFNBQWtCLENBQUM7SUFDdkIsS0FDRSxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQ2YsT0FBTyxJQUFJLHlCQUF5QixDQUFDLE1BQU0sRUFDM0MsT0FBTyxFQUFFLEVBQ1QsQ0FBQztRQUNELElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxFQUFFLENBQUM7WUFDaEIsT0FBTztRQUNULENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsU0FBUyxHQUFHLEtBQUssQ0FBQztZQUNsQixJQUFJLENBQUMsb0JBQW9CLENBQUMsS0FBSyxFQUFFLDRCQUE0QixDQUFDO2dCQUFFLE1BQU07WUFDdEUsTUFBTSxPQUFPLEdBQUcseUJBQXlCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbkQsSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUMvRCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCx3RUFBd0U7SUFDeEUsMEVBQTBFO0lBQzFFLDBFQUEwRTtJQUMxRSx3RUFBd0U7SUFDeEUsd0JBQXdCO0lBQ3hCLElBQUksaUJBQWlCLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDcEMsTUFBTSxJQUFJLG9CQUFvQixDQUM1Qiw2RUFBNkUsRUFDN0UsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQ3JCLENBQUM7SUFDSixDQUFDO0lBQ0QsTUFBTSxTQUFTLENBQUM7QUFDbEIsQ0FBQztBQTRFRCx3RkFBd0Y7QUFDeEYsU0FBUyxvQkFBb0IsQ0FBQyxHQUFnQjtJQUM1QyxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsbUJBQW1CLENBQUM7SUFDOUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDLGdCQUFnQixFQUFFLFlBQVksQ0FBQztJQUN4RCxNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxzQkFBc0IsQ0FBQztJQUM1RSxPQUFPO1FBQ0wsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO1FBQzlCLFlBQVksRUFBRSxHQUFHLENBQUMsWUFBWTtRQUM5QixjQUFjLEVBQUUsR0FBRyxDQUFDLFdBQVc7UUFDL0IsbUJBQW1CLEVBQ2pCLE9BQU8sV0FBVyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTO1FBQzNELFlBQVksRUFDVixZQUFZLElBQUksT0FBTyxZQUFZLEtBQUssUUFBUTtZQUM5QyxDQUFDLENBQUUsWUFBa0Q7WUFDckQsQ0FBQyxDQUFDLFNBQVM7UUFDZixtQkFBbUIsRUFBRSxHQUFHLENBQUMsbUJBQW1CO1FBQzVDLHNCQUFzQixFQUNwQixPQUFPLHNCQUFzQixLQUFLLFFBQVE7WUFDeEMsQ0FBQyxDQUFDLHNCQUFzQjtZQUN4QixDQUFDLENBQUMsU0FBUztLQUNoQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsS0FBSyxVQUFVLHFCQUFxQixDQUNsQyxJQUFtQjtJQUVuQixJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN2QixPQUFPLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQy9ELENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxZQUFZLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlELE9BQU87UUFDTCxhQUFhLEVBQUUsb0JBQW9CLENBQUMsR0FBRyxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxjQUFjO1FBQ3RCLEdBQUc7S0FDSixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILEtBQUssVUFBVSx3QkFBd0IsQ0FDckMsSUFBbUIsRUFDbkIsSUFBb0I7SUFFcEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLEVBQUUsQ0FBQztJQUNuQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRztRQUNyQixDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBQ2hELENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUU7WUFDL0MsWUFBWSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWTtTQUM5QyxDQUFDLENBQUM7SUFDUCxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUN0RCxDQUFDO0FBRUQsOEVBQThFO0FBQzlFLFNBQVMsZUFBZSxDQUFDLElBQW1CO0lBQzFDLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDckUsT0FBTyxVQUFVLEtBQUssU0FBUyxJQUFJLE9BQU8sVUFBVSxDQUFDLEdBQUcsS0FBSyxVQUFVLENBQUM7QUFDMUUsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsR0FBYztJQUN0QyxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDO0lBQ2hDLElBQUksUUFBc0MsQ0FBQztJQUMzQyxJQUFJLGFBQXFDLENBQUM7SUFFMUMsa0VBQWtFO0lBQ2xFLHdFQUF3RTtJQUN4RSwrREFBK0Q7SUFDL0QsTUFBTSxPQUFPLEdBQUcsS0FBSyxJQUFzQixFQUFFO1FBQzNDLE1BQU0sS0FBSyxHQUFHLE1BQU0sWUFBWSxFQUFFLENBQUM7UUFDbkMsTUFBTSxJQUFJLEdBQUcsTUFBTSxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5Qyx5RUFBeUU7UUFDekUsaUVBQWlFO1FBQ2pFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHO1lBQ3JCLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDaEQsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLHNCQUFzQixFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRTtnQkFDOUMsWUFBWSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWTthQUM5QyxDQUFDLENBQUM7UUFDUCxhQUFhLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDeEUsT0FBTyxNQUFNLG9CQUFvQixDQUMvQixVQUFpQixFQUNqQixHQUFHLENBQUMsS0FBSyxFQUNULGFBQWEsQ0FDZCxDQUFDO0lBQ0osQ0FBQyxDQUFDO0lBRUYsTUFBTSxJQUFJLEdBQUcsR0FBc0IsQ0FBQztJQUNwQyxNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7UUFDdEMsMkVBQTJFO1FBQzNFLHVFQUF1RTtRQUN2RSxzRUFBc0U7UUFDdEUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUNSLENBQUMsUUFBUTtZQUNQLE9BQU8sVUFBVSxLQUFLLFdBQVc7Z0JBQy9CLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztnQkFDNUIsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xCLDJFQUEyRTtRQUMzRSwyRUFBMkU7UUFDM0UseUVBQXlFO1FBQ3pFLDRFQUE0RTtRQUM1RSx3RUFBd0U7UUFDeEUsVUFBVSxFQUFFLEtBQUs7UUFDakIsWUFBWSxFQUFFLElBQUk7S0FDbkIsQ0FBQyxDQUFDO0lBRUgsT0FBTyxFQUFFLElBQUksRUFBRSxxQkFBcUIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQztBQUM5RCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBUyxrQkFBa0IsQ0FBQyxJQUFtQjtJQUM3QyxPQUFPLGVBQWUsQ0FBQyxJQUFJLENBQUM7UUFDMUIsQ0FBQyxDQUFFLElBQWE7UUFDaEIsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQWlCLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDL0MsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsY0FBYyxDQUFDLEtBQWE7SUFDaEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLEVBQUUsQ0FBQztJQUNuQyxPQUFPLGdCQUFnQixDQUFDLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDcEUsQ0FBQztBQWVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRDRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsVUFBVSxDQUM5QixXQUFtQyxFQUNuQyxPQUFVLEVBQ1YscUJBQWtDO0lBRWxDLHdFQUF3RTtJQUN4RSx3RUFBd0U7SUFDeEUsMkVBQTJFO0lBQzNFLHlFQUF5RTtJQUN6RSx3RUFBd0U7SUFDeEUsc0VBQXNFO0lBQ3RFLDZFQUE2RTtJQUM3RSxrRUFBa0U7SUFDbEUsdUJBQXVCO0lBQ3ZCLEVBQUU7SUFDRiw2RUFBNkU7SUFDN0UsMEVBQTBFO0lBQzFFLE9BQU8sY0FBYyxDQUNuQixXQUFXLEVBQ1gsT0FBTyxFQUNQLHFCQUFxQixFQUNyQixLQUFLLEVBQ0wsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUNYLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxLQUFLLFVBQVUsY0FBYyxDQUMzQixXQUFtQyxFQUNuQyxPQUFVLEVBQ1YscUJBQTZDLEVBQzdDLG1CQUE0QixFQUM1QixtQkFBMkI7SUFFM0IsT0FBTyxNQUFNLFdBQVcsQ0FBQyxHQUFHLEVBQUU7UUFDNUIsT0FBTyxLQUFLLENBQUMsYUFBYSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUN6QyxNQUFNLEtBQUssR0FBRyxNQUFNLFlBQVksRUFBRSxDQUFDO1lBRW5DLElBQUksQ0FBQztnQkFDSCxNQUFNLGFBQWEsR0FBRyxPQUFPLFdBQVcsS0FBSyxRQUFRLENBQUM7Z0JBQ3RELE1BQU0sSUFBSSxHQUFrQixhQUFhO29CQUN2QyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUM7b0JBQzNDLENBQUMsQ0FBQyxXQUFXLENBQUM7Z0JBQ2hCLHNFQUFzRTtnQkFDdEUsb0VBQW9FO2dCQUNwRSxNQUFNLDhCQUE4QixHQUNsQyxhQUFhLElBQUksbUJBQW1CLENBQUM7Z0JBRXZDLE1BQU0sSUFBSSxHQUFHLE1BQU0scUJBQXFCLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQy9DLE1BQU0sRUFBRSxhQUFhLEVBQUUsR0FBRyxJQUFJLENBQUM7Z0JBRS9CLElBQUksRUFBRSxhQUFhLENBQUM7b0JBQ2xCLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO29CQUNsQyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztvQkFDaEMsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7b0JBQ3RDLHFDQUFxQyxFQUFFLElBQUksQ0FBQyxNQUFNO2lCQUNuRCxDQUFDLENBQUM7Z0JBRUgsbUVBQW1FO2dCQUNuRSwrREFBK0Q7Z0JBQy9ELHVFQUF1RTtnQkFDdkUscUVBQXFFO2dCQUNyRSx1RUFBdUU7Z0JBQ3ZFLGdFQUFnRTtnQkFDaEUsSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLDJCQUEyQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztvQkFDN0QsTUFBTSxJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDMUMsQ0FBQztnQkFFRCw4REFBOEQ7Z0JBQzlELG9FQUFvRTtnQkFDcEUsaUVBQWlFO2dCQUNqRSwyREFBMkQ7Z0JBQzNELGlFQUFpRTtnQkFDakUsTUFBTSxZQUFZLEdBQUcsa0JBQWtCLENBQ3JDLGFBQWEsQ0FBQyxtQkFBbUIsQ0FDbEMsQ0FBQztnQkFFRixtRUFBbUU7Z0JBQ25FLEVBQUU7Z0JBQ0YsdUVBQXVFO2dCQUN2RSxzRUFBc0U7Z0JBQ3RFLG9FQUFvRTtnQkFDcEUsa0VBQWtFO2dCQUNsRSxtRUFBbUU7Z0JBQ25FLGdEQUFnRDtnQkFDaEQsRUFBRTtnQkFDRixvRUFBb0U7Z0JBQ3BFLGlFQUFpRTtnQkFDakUsdURBQXVEO2dCQUN2RCxFQUFFO2dCQUNGLG9FQUFvRTtnQkFDcEUsd0VBQXdFO2dCQUN4RSxpRUFBaUU7Z0JBQ2pFLHNFQUFzRTtnQkFDdEUsd0VBQXdFO2dCQUN4RSxpRUFBaUU7Z0JBQ2pFLGtCQUFrQjtnQkFDbEIsSUFBSSxVQUFrQyxDQUFDO2dCQUN2QyxNQUFNLFlBQVksR0FBRyxxQkFBcUI7b0JBQ3hDLENBQUMsQ0FBQyxnRUFBZ0U7d0JBQ2hFLDhEQUE4RDt3QkFDOUQsNENBQTRDO3dCQUM1QyxTQUFTO29CQUNYLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQUMsbUJBQW1CLENBQUMsQ0FBQztnQkFFMUQsSUFBSSxZQUFZLEVBQUUsQ0FBQztvQkFDakIsVUFBVSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDcEMsQ0FBQztxQkFBTSxDQUFDO29CQUNOLDBEQUEwRDtvQkFDMUQsNkRBQTZEO29CQUM3RCw0QkFBNEI7b0JBQzVCLElBQUksYUFBYSxHQUNmLHFCQUFxQjt3QkFDckIsQ0FBQyxNQUFNLHdCQUF3QixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUMvQyxJQUNFLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsRUFDakUsQ0FBQzt3QkFDRCxhQUFhLEdBQUcsU0FBUyxDQUFDO29CQUM1QixDQUFDO29CQUNELFVBQVUsR0FBRyxhQUFhLENBQUM7Z0JBQzdCLENBQUM7Z0JBRUQsbUVBQW1FO2dCQUNuRSxzREFBc0Q7Z0JBQ3RELE1BQU0sV0FBVyxHQUNmLENBQUMsYUFBYSxDQUFDLGNBQWMsSUFBSSxDQUFDLENBQUM7b0JBQ2pDLGlDQUFpQztvQkFDbkMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFFOUQsb0NBQW9DO2dCQUNwQyxNQUFNLEdBQUcsR0FBbUIsRUFBRSxDQUFDO2dCQUMvQixNQUFNLFdBQVcsR0FBbUIsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLFFBQVEsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ3ZELE1BQU0saUJBQWlCLEdBQUcsTUFBTSx3QkFBd0IsQ0FDdEQsT0FBTyxFQUNQLElBQUksQ0FBQyxLQUFLLEVBQ1YsVUFBVSxFQUNWLEdBQUcsRUFDSCxVQUFVLEVBQ1YsUUFBUSxFQUNSLFlBQVksQ0FBQyxpQkFBaUIsRUFDOUIsV0FBVyxFQUNYLFNBQVMsRUFDVCxXQUFXLENBQ1osQ0FBQztnQkFDRixzRUFBc0U7Z0JBQ3RFLGtFQUFrRTtnQkFDbEUsZ0VBQWdFO2dCQUNoRSx1RUFBdUU7Z0JBQ3ZFLHNFQUFzRTtnQkFDdEUsaUVBQWlFO2dCQUNqRSxtRUFBbUU7Z0JBQ25FLEVBQUU7Z0JBQ0Ysc0VBQXNFO2dCQUN0RSxvRUFBb0U7Z0JBQ3BFLHVEQUF1RDtnQkFDdkQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNmLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUNiLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtvQkFDakIsSUFBSSxLQUFLLEtBQUssU0FBUzt3QkFBRSxNQUFNLEtBQUssQ0FBQztnQkFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FDRixDQUFDO2dCQUNGLHVFQUF1RTtnQkFDdkUsdUVBQXVFO2dCQUN2RSx3REFBd0Q7Z0JBQ3hELGFBQWEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7b0JBQzlDLElBQUksR0FBRyxLQUFLLFNBQVM7d0JBQUUsT0FBTztvQkFDOUIsYUFBYSxDQUFDLElBQUksQ0FBQyw0Q0FBNEMsRUFBRTt3QkFDL0QsYUFBYSxFQUFFLElBQUksQ0FBQyxLQUFLO3dCQUN6QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07d0JBQ25CLEtBQUssRUFBRSxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO3FCQUN4RCxDQUFDLENBQUM7Z0JBQ0wsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsSUFBSSxFQUFFLGFBQWEsQ0FBQztvQkFDbEIsR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUM7aUJBQ3RELENBQUMsQ0FBQztnQkFFSCwrREFBK0Q7Z0JBQy9ELG9FQUFvRTtnQkFDcEUsNERBQTREO2dCQUM1RCxNQUFNLFVBQVUsR0FBRyxNQUFNLGtCQUFrQixDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDeEUsSUFBSSxVQUFVLEVBQUUsQ0FBQztvQkFDZixJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQzlCLENBQUM7Z0JBRUQsTUFBTSxTQUFTLEdBQUcsb0JBQW9CLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUNuRSxNQUFNLFlBQVksR0FBRztvQkFDbkIsWUFBWSxFQUFFLGFBQWEsQ0FBQyxZQUFZO29CQUN4QyxXQUFXLEVBQUUsYUFBYSxDQUFDLGNBQWMsSUFBSSxtQkFBbUI7aUJBQ2pFLENBQUM7Z0JBRUYsbUVBQW1FO2dCQUNuRSxtRUFBbUU7Z0JBQ25FLG9FQUFvRTtnQkFDcEUscUVBQXFFO2dCQUNyRSx1RUFBdUU7Z0JBQ3ZFLHFFQUFxRTtnQkFDckUsK0JBQStCO2dCQUMvQixFQUFFO2dCQUNGLG1FQUFtRTtnQkFDbkUsdUVBQXVFO2dCQUN2RSxzRUFBc0U7Z0JBQ3RFLHNFQUFzRTtnQkFDdEUsb0VBQW9FO2dCQUNwRSx1RUFBdUU7Z0JBQ3ZFLHFFQUFxRTtnQkFDckUsa0VBQWtFO2dCQUNsRSxtQ0FBbUM7Z0JBQ25DLE1BQU0scUJBQXFCLEdBQ3pCLENBQUMsOEJBQThCO29CQUM3QixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsc0JBQXNCLElBQUksQ0FBQyxDQUFDO29CQUN4RCxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUkseUJBQXlCO29CQUNuQyxLQUFLLENBQUMsWUFBWSxFQUFFLGVBQWUsS0FBSyxJQUFJLENBQUM7Z0JBQy9DLE1BQU0sY0FBYyxHQUNsQixxQkFBcUI7b0JBQ3JCLENBQUMsUUFBUTtvQkFDVCxpQkFBaUIsWUFBWSxVQUFVLENBQUM7Z0JBRTFDLElBQUksRUFBRSxhQUFhLENBQUM7b0JBQ2xCLCtCQUErQixFQUFFLFlBQVk7aUJBQzlDLENBQUMsQ0FBQztnQkFFSCxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztnQkFDakUsTUFBTSxhQUFhLEdBQUcsY0FBYztvQkFDbEMsQ0FBQyxDQUFDLE1BQU0sMEJBQTBCLENBQUMsaUJBQWlCLENBQUM7b0JBQ3JELENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQ2QsSUFBSSxRQUFRLEVBQUUsQ0FBQztvQkFDYixJQUFJLEVBQUUsYUFBYSxDQUFDLEVBQUUseUJBQXlCLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztnQkFDL0QsQ0FBQztnQkFFRCwyREFBMkQ7Z0JBQzNELG1FQUFtRTtnQkFDbkUscURBQXFEO2dCQUNyRCxtRUFBbUU7Z0JBQ25FLDBDQUEwQztnQkFDMUMscUVBQXFFO2dCQUNyRSw4Q0FBOEM7Z0JBQzlDLGtFQUFrRTtnQkFDbEUsdUJBQXVCO2dCQUN2QixFQUFFO2dCQUNGLGtFQUFrRTtnQkFDbEUsb0VBQW9FO2dCQUNwRSxzRUFBc0U7Z0JBQ3RFLHFFQUFxRTtnQkFDckUsb0VBQW9FO2dCQUNwRSxxRUFBcUU7Z0JBQ3JFLHFFQUFxRTtnQkFDckUsb0VBQW9FO2dCQUNwRSxvRUFBb0U7Z0JBQ3BFLHFFQUFxRTtnQkFDckUsc0RBQXNEO2dCQUN0RCxNQUFNLGVBQWUsR0FBRyxDQUFDLEdBQVksRUFBVyxFQUFFLENBQ2hELGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxlQUFlLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN2RCxJQUFJLENBQUM7b0JBQ0gsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FDdkIsSUFBSSxDQUFDLEtBQUssRUFDVjt3QkFDRSxTQUFTLEVBQUUsZUFBZTt3QkFDMUIsV0FBVyxFQUFFLG9CQUFvQjt3QkFDakMsYUFBYSxFQUFFLElBQUksQ0FBQyxNQUFNO3dCQUMxQixTQUFTLEVBQUU7NEJBQ1QsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7NEJBQzFDLE9BQU8sRUFBRSxpQkFBaUI7eUJBQzNCO3FCQUNGLEVBQ0Q7d0JBQ0UsUUFBUTt3QkFDUixHQUFHLENBQUMsUUFBUSxJQUFJLGFBQWE7NEJBQzNCLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxtQkFBbUIsRUFBRSxhQUFhLEVBQUU7NEJBQ2xELENBQUMsQ0FBQyxFQUFFLENBQUM7cUJBQ1IsQ0FDRixDQUFDO2dCQUNKLENBQUM7Z0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztvQkFDYixJQUFJLGVBQWUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO3dCQUN6QixNQUFNLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUMxQyxDQUFDO29CQUNELE1BQU0sR0FBRyxDQUFDO2dCQUNaLENBQUM7Z0JBQ0Qsc0VBQXNFO2dCQUN0RSwyREFBMkQ7Z0JBQzNELG9FQUFvRTtnQkFDcEUscUVBQXFFO2dCQUNyRSxxRUFBcUU7Z0JBQ3JFLElBQUksRUFBRSxhQUFhLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBRXpELGtFQUFrRTtnQkFDbEUscUVBQXFFO2dCQUNyRSxrRUFBa0U7Z0JBQ2xFLG1DQUFtQztnQkFDbkMsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzdDLE1BQU0sd0JBQXdCLENBQzVCLEdBQUcsRUFBRSxDQUNILEtBQUssQ0FBQyxLQUFLLENBQ1QsU0FBUyxFQUNUO29CQUNFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztvQkFDakIsWUFBWSxFQUFFLGFBQWEsQ0FBQyxZQUFZLElBQUksU0FBUztvQkFDckQsZ0JBQWdCLEVBQUU7d0JBQ2hCLG1CQUFtQjt3QkFDbkIseUJBQXlCO3dCQUN6QixRQUFRLEVBQUUsWUFBWTtxQkFDdkI7aUJBQzhCLEVBQ2pDO29CQUNFLEdBQUcsWUFBWTtvQkFDZixxREFBcUQ7b0JBQ3JELDREQUE0RDtvQkFDNUQsNERBQTREO29CQUM1RCw0REFBNEQ7b0JBQzVELDBEQUEwRDtvQkFDMUQsOEJBQThCO29CQUM5QixHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLGNBQWMsRUFBRSxRQUFRLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztpQkFDNUQsQ0FDRixFQUNILEtBQUssQ0FBQyw0QkFBNEIsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQ2hELENBQUM7Z0JBQ0YsSUFBSSxFQUFFLGFBQWEsQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFFdkQsT0FBTyxrQkFBa0IsQ0FBQyxJQUFJLENBQXVCLENBQUM7WUFDeEQsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsSUFBSSxFQUFFLGFBQWEsQ0FBQztvQkFDbEIsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUNwQixPQUFPLFdBQVcsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FDbEU7b0JBQ0QsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztpQkFDOUIsQ0FBQyxDQUFDO2dCQUNILE1BQU0sR0FBRyxDQUFDO1lBQ1osQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQ0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGFBQWEsQ0FDakMsS0FBYSxFQUNiLE9BQWdCO0lBRWhCLDJFQUEyRTtJQUMzRSx5RUFBeUU7SUFDekUsMEVBQTBFO0lBQzFFLDRFQUE0RTtJQUM1RSw0RUFBNEU7SUFDNUUsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkMsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLEVBQUUsQ0FBQztJQUNuQyxNQUFNLEVBQUUsSUFBSSxFQUFFLHFCQUFxQixFQUFFLEdBQUcsZ0JBQWdCLENBQ3RELE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQ3BDLENBQUM7SUFFRix3REFBd0Q7SUFDeEQsaUVBQWlFO0lBQ2pFLHVFQUF1RTtJQUN2RSx3REFBd0Q7SUFDeEQsSUFBSSxJQUFJLENBQUMsU0FBUyxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQzdCLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQsNkVBQTZFO0lBQzdFLDZFQUE2RTtJQUM3RSxzRUFBc0U7SUFDdEUsMkVBQTJFO0lBQzNFLDhFQUE4RTtJQUM5RSw4REFBOEQ7SUFDOUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDO0lBRXJDLElBQUksUUFBOEIsQ0FBQztJQUNuQyxJQUFJLGdCQUFzRCxDQUFDO0lBQzNELElBQUksUUFBUSxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxhQUFhLElBQUksUUFBUSxFQUFFLENBQUM7UUFDMUUsSUFBSSxRQUFRLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxlQUFlLEVBQXNCLENBQUM7WUFDekUsZ0JBQWdCLEdBQUcsUUFBUSxDQUFDO1lBRTVCLHVFQUF1RTtZQUN2RSxtRUFBbUU7WUFDbEUsT0FBZSxDQUFDLHlCQUF5QixDQUFDLEdBQUcsUUFBUSxDQUFDO1FBQ3pELENBQUM7YUFBTSxJQUFJLFFBQVEsQ0FBQyxXQUFXLFlBQVksUUFBUSxFQUFFLENBQUM7WUFDcEQsUUFBUSxHQUFHLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFDbEMsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLElBQUksb0JBQW9CLENBQzVCLGtDQUFrQyxRQUFRLENBQUMsV0FBVyxFQUFFLEVBQ3hELEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQyxrQ0FBa0MsRUFBRSxDQUN6RCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04seUVBQXlFO1FBQ3pFLFFBQVEsR0FBRyxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsK0RBQStEO0lBQy9ELG9FQUFvRTtJQUNwRSw2RUFBNkU7SUFDN0UsNEVBQTRFO0lBQzVFLHNDQUFzQztJQUN0QyxFQUFFO0lBQ0YsNkVBQTZFO0lBQzdFLHVFQUF1RTtJQUN2RSwyQkFBMkI7SUFDM0IsTUFBTSxjQUFjLENBQ2xCLElBQUksRUFDSixPQUFPLEVBQ1AscUJBQXFCLEVBQUUsRUFDdkIsSUFBSSxFQUNKLG1CQUFtQixDQUNwQixDQUFDO0lBRUYsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3JCLGtEQUFrRDtRQUNsRCxpQ0FBaUM7UUFDakMsTUFBTSxNQUFNLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDNUMsTUFBTSxLQUFLLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbEMsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDaEIsUUFBUSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7UUFDekIsQ0FBQztRQUNELE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNsQixDQUFDO0lBRUQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2QsTUFBTSxJQUFJLG9CQUFvQixDQUFDLHNDQUFzQyxFQUFFO1lBQ3JFLElBQUksRUFBRSxXQUFXLENBQUMseUJBQXlCO1NBQzVDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgRVJST1JfU0xVR1MsXG4gIEhvb2tOb3RGb3VuZEVycm9yLFxuICBSdW5FeHBpcmVkRXJyb3IsXG4gIFdvcmtmbG93UnVudGltZUVycm9yLFxufSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB7XG4gIEhPT0tfUkVTVU1FX0RFRFVQX1ZFUlNJT04sXG4gIHR5cGUgSG9va1Jlc3VtZUNvbnRleHQsXG4gIGlzTGVnYWN5U3BlY1ZlcnNpb24sXG4gIGlzVGVybWluYWxXb3JrZmxvd1J1blN0YXR1cyxcbiAgU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gIFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gIFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTixcbiAgdHlwZSBXb3JrZmxvd0ludm9rZVBheWxvYWQsXG4gIHR5cGUgV29ya2Zsb3dSdW4sXG4gIHR5cGUgSG9vayBhcyBXb3JsZEhvb2ssXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBtb25vdG9uaWNGYWN0b3J5IH0gZnJvbSAndWxpZCc7XG5pbXBvcnQgeyBnZXRSdW5DYXBhYmlsaXRpZXMgfSBmcm9tICcuLi9jYXBhYmlsaXRpZXMuanMnO1xuaW1wb3J0IHsgaW1wb3J0S2V5IH0gZnJvbSAnLi4vZW5jcnlwdGlvbi5qcyc7XG5pbXBvcnQgeyBydW50aW1lTG9nZ2VyIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGRlY29kZVJ1blB1YmxpY0tleSB9IGZyb20gJy4uL3NlYWxlZC1ib3guanMnO1xuaW1wb3J0IHsgZGVyaXZlUnVuUGF5bG9hZEtleXMgfSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHtcbiAgZGVoeWRyYXRlU3RlcFJldHVyblZhbHVlLFxuICBoeWRyYXRlU3RlcEFyZ3VtZW50cyxcbiAgdHlwZSBQYXlsb2FkS2V5LFxuICBTZXJpYWxpemF0aW9uRm9ybWF0LFxuICBzZWFsVG8sXG59IGZyb20gJy4uL3NlcmlhbGl6YXRpb24uanMnO1xuaW1wb3J0IHsgV0VCSE9PS19SRVNQT05TRV9XUklUQUJMRSB9IGZyb20gJy4uL3N5bWJvbHMuanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBsaW5rVG9UcmFjZUNhcnJpZXIsIHRyYWNlIH0gZnJvbSAnLi4vdGVsZW1ldHJ5LmpzJztcbmltcG9ydCB7IGdldFdvcmxkTGF6eSB9IGZyb20gJy4vZ2V0LXdvcmxkLWxhenkuanMnO1xuaW1wb3J0IHsgZ2V0V29ya2Zsb3dRdWV1ZU5hbWUgfSBmcm9tICcuL2hlbHBlcnMuanMnO1xuaW1wb3J0IHsgc2FmZVdhaXRVbnRpbCwgd2FpdGVkVW50aWwgfSBmcm9tICcuL3dhaXQtdW50aWwuanMnO1xuXG4vKiogTW9ub3RvbmljIFVMSUQgZmFjdG9yeSBmb3IgcGVyLWNhbGwgcmVzdW1lIGlkZW1wb3RlbmN5IGtleXMuICovXG5jb25zdCBnZW5lcmF0ZVJlc3VtZUlkID0gbW9ub3RvbmljRmFjdG9yeSgpO1xuXG4vKipcbiAqIEhleCBTSEEtMjU2IG9mIHRoZSBzZXJpYWxpemVkIHJlc3VtZSBwYXlsb2FkIGJ5dGVzLiBDb21wdXRlZCBvbmNlIGJ5IHRoZVxuICogcHJvZHVjZXIgYW5kIHNlbnQgd2l0aCBpdHMgZHVyYWJsZSBgaG9va19yZWNlaXZlZGAgd3JpdGUgc28gdHJhbnNwb3J0IGFuZFxuICogc2xvdCByZXRyaWVzIGNvbnZlcmdlIHRocm91Z2ggdGhlIHNlcnZlcidzIGAocnVuSWQsIHJlc3VtZUlkKWAgY29uc3RyYWludC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY29tcHV0ZVJlc3VtZVBheWxvYWREaWdlc3QoYnl0ZXM6IFVpbnQ4QXJyYXkpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBkaWdlc3QgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmRpZ2VzdCgnU0hBLTI1NicsIGJ5dGVzKTtcbiAgY29uc3QgdmlldyA9IG5ldyBVaW50OEFycmF5KGRpZ2VzdCk7XG4gIGxldCBoZXggPSAnJztcbiAgZm9yIChjb25zdCBiIG9mIHZpZXcpIHtcbiAgICBoZXggKz0gYi50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKTtcbiAgfVxuICByZXR1cm4gaGV4O1xufVxuXG5jb25zdCBIT09LX1dBS0VfUkVUUllfREVMQVlTX01TID0gWzI1LCAxMDBdIGFzIGNvbnN0O1xuXG4vKipcbiAqIEEgd2FrZSBmYWlsdXJlIHdvcnRoIHJldHJ5aW5nIGlzIHRyYW5zcG9ydC1zaGFwZWQgKG5ldHdvcmsgZXJyb3IsIDV4eCxcbiAqIHRocm90dGxlKS4gQSBkZWZpbml0aXZlIHJlamVjdGlvbiB3aWxsIG5vdCBjaGFuZ2Ugb24gYSAyNW1zIHJldHJ5LCBzb1xuICogc3BlbmRpbmcgdGhlIGJ1ZGdldCBvbiBpdCBvbmx5IGRlbGF5cyB0aGUgY2FsbGVyJ3MgZXJyb3IuXG4gKlxuICogYEB2ZXJjZWwvcXVldWVgIGVycm9ycyBjYXJyeSBubyBgc3RhdHVzYCBmaWVsZCDigJQgdGhleSBhcmUgYmFyZSBgRXJyb3JgXG4gKiBzdWJjbGFzc2VzIGRpc3Rpbmd1aXNoZWQgYnkgYG5hbWVgIOKAlCBzbyBjbGFzc2lmaWNhdGlvbiBjaGVja3MgdGhlIFdvcmxkJ3NcbiAqIGRlcGxveW1lbnQtdW5hdmFpbGFibGUgaG9vayBmaXJzdCAoYSBkZXBsb3ltZW50IHRoZSBxdWV1ZSBjYW5ub3QgZGlzY292ZXJcbiAqIHdpbGwgbm90IGNvbWUgYmFjayB3aXRoaW4gdGhpcyBmdW5jdGlvbidzIH4xMjVtcyBidWRnZXQpLCB0aGVuIGEgbnVtZXJpY1xuICogc3RhdHVzIHdoZW4gb25lIGV4aXN0cyAobm9uLVZlcmNlbCBxdWV1ZSBpbXBsZW1lbnRhdGlvbnMpLCB0aGVuIHRoZSBxdWV1ZVxuICogY2xpZW50J3MgZGVmaW5pdGl2ZS00eHggZXJyb3IgbmFtZXMuXG4gKi9cbmZ1bmN0aW9uIGlzUmV0cnlhYmxlV2FrZUVycm9yKFxuICBlcnJvcjogdW5rbm93bixcbiAgaXNEZXBsb3ltZW50VW5hdmFpbGFibGVFcnJvcj86IChlcnJvcjogdW5rbm93bikgPT4gYm9vbGVhblxuKTogYm9vbGVhbiB7XG4gIGlmIChpc0RlcGxveW1lbnRVbmF2YWlsYWJsZUVycm9yPy4oZXJyb3IpKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IHN0YXR1cyA9IChlcnJvciBhcyB7IHN0YXR1cz86IHVua25vd247IHN0YXR1c0NvZGU/OiB1bmtub3duIH0pID8/IHt9O1xuICBjb25zdCBjb2RlID0gc3RhdHVzLnN0YXR1cyA/PyBzdGF0dXMuc3RhdHVzQ29kZTtcbiAgaWYgKHR5cGVvZiBjb2RlID09PSAnbnVtYmVyJykge1xuICAgIHJldHVybiBjb2RlID49IDUwMCB8fCBjb2RlID09PSA0MDggfHwgY29kZSA9PT0gNDI5O1xuICB9XG4gIGNvbnN0IG5hbWUgPSAoZXJyb3IgYXMgRXJyb3IgfCBudWxsKT8ubmFtZTtcbiAgcmV0dXJuIChcbiAgICBuYW1lICE9PSAnQmFkUmVxdWVzdEVycm9yJyAmJlxuICAgIG5hbWUgIT09ICdVbmF1dGhvcml6ZWRFcnJvcicgJiZcbiAgICBuYW1lICE9PSAnRm9yYmlkZGVuRXJyb3InXG4gICk7XG59XG5cbi8vIEEgcHVibGlzaCBtYXkgc3VjY2VlZCBldmVuIHdoZW4gaXRzIHJlc3BvbnNlIGlzIGxvc3QsIHNvIGEgcmV0cnkgY2FuXG4vLyBlbnF1ZXVlIGEgZHVwbGljYXRlIHdha2UuIFRoYXQgaXMgaGFybWxlc3M6IHRoZSBldmVudCBpcyBhbHJlYWR5IGR1cmFibGUsXG4vLyBhbmQgZGV0ZXJtaW5pc3RpYyByZXBsYXkgbWFrZXMgYSBzZWNvbmQgZGVsaXZlcnkgb2YgdGhlIHNhbWUgcnVuIGEgbm8tb3AuXG5hc3luYyBmdW5jdGlvbiBwdWJsaXNoSG9va1dha2VXaXRoUmV0cnkoXG4gIHB1Ymxpc2g6ICgpID0+IFByb21pc2U8dW5rbm93bj4sXG4gIGlzRGVwbG95bWVudFVuYXZhaWxhYmxlRXJyb3I/OiAoZXJyb3I6IHVua25vd24pID0+IGJvb2xlYW5cbik6IFByb21pc2U8dm9pZD4ge1xuICBsZXQgbGFzdEVycm9yOiB1bmtub3duO1xuICBmb3IgKFxuICAgIGxldCBhdHRlbXB0ID0gMDtcbiAgICBhdHRlbXB0IDw9IEhPT0tfV0FLRV9SRVRSWV9ERUxBWVNfTVMubGVuZ3RoO1xuICAgIGF0dGVtcHQrK1xuICApIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgcHVibGlzaCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsYXN0RXJyb3IgPSBlcnJvcjtcbiAgICAgIGlmICghaXNSZXRyeWFibGVXYWtlRXJyb3IoZXJyb3IsIGlzRGVwbG95bWVudFVuYXZhaWxhYmxlRXJyb3IpKSBicmVhaztcbiAgICAgIGNvbnN0IGRlbGF5TXMgPSBIT09LX1dBS0VfUkVUUllfREVMQVlTX01TW2F0dGVtcHRdO1xuICAgICAgaWYgKGRlbGF5TXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBkZWxheU1zKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gVGhlIHdha2Ugb25seSBydW5zIGFmdGVyIHRoZSBob29rX3JlY2VpdmVkIHdyaXRlIGNvbW1pdHRlZCwgc28gYSB3YWtlXG4gIC8vIGZhaWx1cmUgaGVyZSBpcyBuZWNlc3NhcmlseSBcImR1cmFibGUgYnV0IG5vdCB5ZXQgZGlzcGF0Y2hlZFwiOiB0aGUgZXZlbnRcbiAgLy8gc3Vydml2ZXMsIGFuZCBhbnkgbGF0ZXIgd2FrZSBvZiB0aGUgcnVuIGRlbGl2ZXJzIGl0LiBEbyBub3QgbGV0IGEgcXVldWVcbiAgLy8gaW1wbGVtZW50YXRpb24gcmV1c2UgSG9va05vdEZvdW5kRXJyb3IgYW5kIGFjY2lkZW50YWxseSBpbXBseSB0aGF0IG5vXG4gIC8vIGhvb2tfcmVjZWl2ZWQgZXhpc3RzLlxuICBpZiAoSG9va05vdEZvdW5kRXJyb3IuaXMobGFzdEVycm9yKSkge1xuICAgIHRocm93IG5ldyBXb3JrZmxvd1J1bnRpbWVFcnJvcihcbiAgICAgICdUaGUgaG9vayByZXN1bWUgd2FzIGNvbW1pdHRlZCwgYnV0IGl0cyB3b3JrZmxvdyB3YWtlIGNvdWxkIG5vdCBiZSBwdWJsaXNoZWQnLFxuICAgICAgeyBjYXVzZTogbGFzdEVycm9yIH1cbiAgICApO1xuICB9XG4gIHRocm93IGxhc3RFcnJvcjtcbn1cblxuLyoqXG4gKiBBIGhvb2sgcmVjb3JkIHdpdGggaXRzIHNlcmlhbGl6ZWQgYG1ldGFkYXRhYCBvbWl0dGVkOiBldmVyeXRoaW5nIGEgcmVzdW1lXG4gKiBhY3R1YWxseSByZWFkcy4gUmVzdW1pbmcgbmV2ZXIgbG9va3MgYXQgbWV0YWRhdGEsIHNvIHRoZSByZXN1bWUgcGF0aCBhY2NlcHRzXG4gKiBib3RoIGEgcmF3IHtAbGluayBXb3JsZEhvb2t9IHN0cmFpZ2h0IG91dCBvZiBhIFdvcmxkIGFuZCBhIHtAbGluayBIb29rfVxuICogd2hvc2UgYG1ldGFkYXRhYCBpcyBhIFByb21pc2UuXG4gKi9cbnR5cGUgUmVzdW1hYmxlSG9vayA9IE9taXQ8V29ybGRIb29rLCAnbWV0YWRhdGEnPjtcblxuLyoqXG4gKiBBIGhvb2sgYXMgcmV0dXJuZWQgYnkge0BsaW5rIGdldEhvb2tCeVRva2VufSBhbmQge0BsaW5rIHJlc3VtZUhvb2t9OiB0aGVcbiAqIFdvcmxkJ3Mge0BsaW5rIFdvcmxkSG9va30gcmVjb3JkIHdpdGggaXRzIHVzZXItZGVmaW5lZCBgbWV0YWRhdGFgIGh5ZHJhdGVkXG4gKiBsYXppbHkuXG4gKlxuICogYG1ldGFkYXRhYCBpcyBhIGdldHRlciB0aGF0IHJldHVybnMgYSBQcm9taXNlIOKAlCB0aGUgc2FtZSBzaGFwZSBhc1xuICogYFJ1bi5yZXR1cm5WYWx1ZWAg4oCUIHNvIGxvb2tpbmcgYSBob29rIHVwIGJ5IHRva2VuIGNvc3RzIGV4YWN0bHkgb25lIHJlYWQuXG4gKiBIeWRyYXRpbmcgbWV0YWRhdGEgaXMgYSBkZWNyeXB0aW5nIFJFQUQgdGhhdCBuZWVkcyB0aGUgb3duaW5nIHJ1bidzIHBheWxvYWRcbiAqIGtleXMsIGFuZCByZXNvbHZpbmcgdGhvc2UgY2FuIGNvc3QgYSBydW4gZmV0Y2ggcGx1cyBhIGBydW4ta2V5YCBBUEkgcm91bmRcbiAqIHRyaXAgKH4zNTBtcykuIERlZmVycmluZyB0aGF0IHRvIGZpcnN0IGFjY2VzcyBrZWVwcyB0aGUgbG9va3VwIGZhc3QgZm9yIHRoZVxuICogbWFueSBjYWxsZXJzIHRoYXQgb25seSBuZWVkIGBydW5JZGAvYHRva2VuYCDigJQgbW9zdCBpbXBvcnRhbnRseSBob29rXG4gKiByZXN1bXB0aW9uLCB3aGljaCBuZXZlciByZWFkcyBtZXRhZGF0YSBhdCBhbGwuXG4gKlxuICogVGhlIHByb21pc2UgaXMgbWVtb2l6ZWQ6IGh5ZHJhdGlvbiAoYW5kIHRoZSBrZXkgcmVzb2x1dGlvbiBiZWhpbmQgaXQpIHJ1bnMgYXRcbiAqIG1vc3Qgb25jZSBwZXIgaG9vayBvYmplY3QuIEF3YWl0aW5nIGl0IG9uIGEgaG9vayB0aGF0IHN0b3JlZCBubyBtZXRhZGF0YVxuICogcmVzb2x2ZXMgYHVuZGVmaW5lZGAgYW5kIHBlcmZvcm1zIG5vIEkvTy5cbiAqXG4gKiBMaWtlIGBSdW4ucmV0dXJuVmFsdWVgLCB0aGUgYWNjZXNzb3IgaXMgbm9uLWVudW1lcmFibGUsIHNvIGl0IGlzIGFic2VudCBmcm9tXG4gKiBgeyAuLi5ob29rIH1gIGFuZCBgSlNPTi5zdHJpbmdpZnkoaG9vaylgIOKAlCByZWFkIGl0IGV4cGxpY2l0bHkgYW5kIGluY2x1ZGUgdGhlXG4gKiBhd2FpdGVkIHZhbHVlIGlmIHlvdSBuZWVkIHRvIGZvcndhcmQgaXQuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGB0c1xuICogY29uc3QgaG9vayA9IGF3YWl0IGdldEhvb2tCeVRva2VuKHRva2VuKTtcbiAqIGNvbnNvbGUubG9nKGhvb2sucnVuSWQpOyAvLyBubyBtZXRhZGF0YSB3b3JrXG4gKiBjb25zdCBtZXRhZGF0YSA9IChhd2FpdCBob29rLm1ldGFkYXRhKSBhcyB7IGFsbG93ZWRVc2VySWQ/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEhvb2sgZXh0ZW5kcyBSZXN1bWFibGVIb29rIHtcbiAgLyoqXG4gICAqIFRoZSBob29rJ3MgdXNlci1kZWZpbmVkIG1ldGFkYXRhLCBoeWRyYXRlZCBvbiBmaXJzdCBhY2Nlc3MgYW5kIG1lbW9pemVkLlxuICAgKiBSZXNvbHZlcyBgdW5kZWZpbmVkYCB3aGVuIHRoZSBob29rIGNhcnJpZXMgbm8gbWV0YWRhdGEuXG4gICAqL1xuICByZWFkb25seSBtZXRhZGF0YTogUHJvbWlzZTx1bmtub3duPjtcbn1cblxuLyoqXG4gKiBBIGJ5LXRva2VuIGhvb2sgbG9va3VwOiB0aGUgaG9vayBpdHNlbGYgcGx1cyBhY2Nlc3MgdG8gdGhlIHBheWxvYWQga2V5cyB0aGF0XG4gKiBoeWRyYXRpbmcgaXRzIGBtZXRhZGF0YWAgcmVzb2x2ZWQsIGlmIGFueXRoaW5nIGV2ZXIgYXdhaXRlZCBpdC5cbiAqL1xuaW50ZXJmYWNlIEhvb2tMb29rdXAge1xuICBob29rOiBIb29rO1xuICAvKipcbiAgICogVGhlIHJlYWQtc2lkZSBwYXlsb2FkIGtleXMgcmVzb2x2ZWQgd2hpbGUgaHlkcmF0aW5nIGBtZXRhZGF0YWAsIG9yXG4gICAqIGB1bmRlZmluZWRgIHdoZW4gYG1ldGFkYXRhYCB3YXMgbmV2ZXIgYXdhaXRlZCwgdGhlIGhvb2sgc3RvcmVkIG5vbmUsIG9yIHRoZVxuICAgKiBydW4gaGFzIG5vIGtleSAoZW5jcnlwdGlvbiBkaXNhYmxlZCkuIExldHMgYHJlc3VtZVdlYmhvb2tgIOKAlCB0aGUgb25lIGNhbGxlclxuICAgKiB0aGF0IG11c3QgcmVhZCBtZXRhZGF0YSDigJQgcmV1c2UgdGhhdCBrZXkgZm9yIHRoZSBwYXlsb2FkIFdSSVRFIGluc3RlYWQgb2ZcbiAgICogcGF5aW5nIGEgc2Vjb25kIGBydW4ta2V5YCByb3VuZCB0cmlwLiBPbmx5IG1lYW5pbmdmdWwgYWZ0ZXIgYXdhaXRpbmdcbiAgICogYGhvb2subWV0YWRhdGFgLlxuICAgKi9cbiAgbWV0YWRhdGFFbmNyeXB0aW9uS2V5KCk6IFBheWxvYWRLZXkgfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogVGhlIHJlc3VtZSBjb250ZXh0IGZvciBhIGhvb2sgcGx1cyB3aGVyZSBpdCBjYW1lIGZyb20uIGBydW5gIGlzIHByZXNlbnQgb25seVxuICogb24gdGhlIGZhbGxiYWNrIHBhdGggKHByZS1gcmVzdW1lQ29udGV4dGAgaG9va3MpLCB3aGVyZSBpdCBhbHNvIGNhcnJpZXMgdGhlXG4gKiBydW4ncyBtdXRhYmxlIHN0YXR1cyBmb3IgdGhlIHRlcm1pbmFsLXJ1biBjaGVjay4gS2V5IHJlc29sdXRpb24gaXMga2VwdFxuICogc2VwYXJhdGUgc28gY2FsbGVycyBjYW4gZ2F0ZSBpdCBiZWhpbmQgdGhhdCBjaGVjay5cbiAqL1xuaW50ZXJmYWNlIEhvb2tSZXN1bWVJbmZvIHtcbiAgcmVzdW1lQ29udGV4dDogSG9va1Jlc3VtZUNvbnRleHQ7XG4gIHNvdXJjZTogJ2hvb2snIHwgJ3J1bl9mYWxsYmFjayc7XG4gIHJ1bj86IFdvcmtmbG93UnVuO1xufVxuXG4vKiogRGVyaXZlIGEgcmVzdW1lIGNvbnRleHQgZnJvbSBhIGZ1bGwgcnVuIChmYWxsYmFjayBmb3IgcHJlLWByZXN1bWVDb250ZXh0YCBob29rcykuICovXG5mdW5jdGlvbiByZXN1bWVDb250ZXh0RnJvbVJ1bihydW46IFdvcmtmbG93UnVuKTogSG9va1Jlc3VtZUNvbnRleHQge1xuICBjb25zdCBjb3JlVmVyc2lvbiA9IHJ1bi5leGVjdXRpb25Db250ZXh0Py53b3JrZmxvd0NvcmVWZXJzaW9uO1xuICBjb25zdCB0cmFjZUNhcnJpZXIgPSBydW4uZXhlY3V0aW9uQ29udGV4dD8udHJhY2VDYXJyaWVyO1xuICBjb25zdCBob29rUmVzdW1lSW5wdXRWZXJzaW9uID0gcnVuLmV4ZWN1dGlvbkNvbnRleHQ/Lmhvb2tSZXN1bWVJbnB1dFZlcnNpb247XG4gIHJldHVybiB7XG4gICAgZGVwbG95bWVudElkOiBydW4uZGVwbG95bWVudElkLFxuICAgIHdvcmtmbG93TmFtZTogcnVuLndvcmtmbG93TmFtZSxcbiAgICBydW5TcGVjVmVyc2lvbjogcnVuLnNwZWNWZXJzaW9uLFxuICAgIHdvcmtmbG93Q29yZVZlcnNpb246XG4gICAgICB0eXBlb2YgY29yZVZlcnNpb24gPT09ICdzdHJpbmcnID8gY29yZVZlcnNpb24gOiB1bmRlZmluZWQsXG4gICAgdHJhY2VDYXJyaWVyOlxuICAgICAgdHJhY2VDYXJyaWVyICYmIHR5cGVvZiB0cmFjZUNhcnJpZXIgPT09ICdvYmplY3QnXG4gICAgICAgID8gKHRyYWNlQ2FycmllciBhcyBIb29rUmVzdW1lQ29udGV4dFsndHJhY2VDYXJyaWVyJ10pXG4gICAgICAgIDogdW5kZWZpbmVkLFxuICAgIGVuY3J5cHRpb25QdWJsaWNLZXk6IHJ1bi5lbmNyeXB0aW9uUHVibGljS2V5LFxuICAgIGhvb2tSZXN1bWVJbnB1dFZlcnNpb246XG4gICAgICB0eXBlb2YgaG9va1Jlc3VtZUlucHV0VmVyc2lvbiA9PT0gJ251bWJlcidcbiAgICAgICAgPyBob29rUmVzdW1lSW5wdXRWZXJzaW9uXG4gICAgICAgIDogdW5kZWZpbmVkLFxuICB9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgcmVzdW1lIGNvbnRleHQgZm9yIGEgaG9vay4gVXNlcyB0aGUgc3RvcmVkIGByZXN1bWVDb250ZXh0YCB3aGVuXG4gKiBwcmVzZW50IChmYXN0IHBhdGgsIG5vIHJ1biByZWFkKTsgb3RoZXJ3aXNlIGZldGNoZXMgdGhlIHJ1biBhbmQgc3ludGhlc2l6ZXNcbiAqIGl0LiBEb2VzIE5PVCByZXNvbHZlIHRoZSBlbmNyeXB0aW9uIGtleTsgY2FsbGVycyBkbyB0aGF0IHNlcGFyYXRlbHkuIE9ubHlcbiAqIHRoZSBmYWxsYmFjayBwYXRoIGNhbiBnYXRlIGtleSB3b3JrIGJlaGluZCBhIGxvY2FsIHRlcm1pbmFsLXJ1biBjaGVjayAoaXRcbiAqIGhhcyB0aGUgZmV0Y2hlZCBydW4pOyB0aGUgZmFzdCBwYXRoJ3Mgc3RvcmVkIGNvbnRleHQgY2FycmllcyBubyBzdGF0dXMsIHNvXG4gKiBzZWFsL3NlcmlhbGl6YXRpb24gd29yayBtYXkgcnVuIGJlZm9yZSB0aGUgcmVjZWl2aW5nIHNpZGUgcmVqZWN0c1xuICogYGhvb2tfcmVjZWl2ZWRgIGZvciBhbiBlbmRlZCBydW4uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVIb29rUmVzdW1lSW5mbyhcbiAgaG9vazogUmVzdW1hYmxlSG9va1xuKTogUHJvbWlzZTxIb29rUmVzdW1lSW5mbz4ge1xuICBpZiAoaG9vay5yZXN1bWVDb250ZXh0KSB7XG4gICAgcmV0dXJuIHsgcmVzdW1lQ29udGV4dDogaG9vay5yZXN1bWVDb250ZXh0LCBzb3VyY2U6ICdob29rJyB9O1xuICB9XG4gIGNvbnN0IHJ1biA9IGF3YWl0IChhd2FpdCBnZXRXb3JsZExhenkoKSkucnVucy5nZXQoaG9vay5ydW5JZCk7XG4gIHJldHVybiB7XG4gICAgcmVzdW1lQ29udGV4dDogcmVzdW1lQ29udGV4dEZyb21SdW4ocnVuKSxcbiAgICBzb3VyY2U6ICdydW5fZmFsbGJhY2snLFxuICAgIHJ1bixcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBydW4ncyBzeW1tZXRyaWMga2V5IGZvciBhIHBheWxvYWQgV1JJVEUsIGFzIGEgYmFyZSBgQ3J5cHRvS2V5YFxuICogKGBpbXBvcnRLZXlgKTogdGhlIGBlbmNyYCB3cml0ZSBmYWxsYmFjayB1c2VkIHdoZW4gdGhlIHJ1biBwdWJsaXNoZWQgbm9cbiAqIHB1YmxpYyBrZXkgdG8gc2VhbCB0by4gV3JpdGluZyBuZWVkcyBvbmx5IHRoZSBBRVMga2V5LCBub3QgdGhlIHJlYWQtc2lkZVxuICoga2V5cGFpci4gT24gdGhlIGZhc3QgcGF0aCB0aGlzIG5lZWRzIG9ubHkgYHJ1bklkYCArIGBkZXBsb3ltZW50SWRgIChubyBydW5cbiAqIGVudGl0eSk7IG9uIHRoZSBmYWxsYmFjayBwYXRoIHRoZSBhbHJlYWR5IGZldGNoZWQgcnVuIGlzIHJldXNlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUhvb2tFbmNyeXB0aW9uS2V5KFxuICBob29rOiBSZXN1bWFibGVIb29rLFxuICBpbmZvOiBIb29rUmVzdW1lSW5mb1xuKTogUHJvbWlzZTxBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIGltcG9ydEtleT4+IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIGNvbnN0IHJhd0tleSA9IGluZm8ucnVuXG4gICAgPyBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4oaW5mby5ydW4pXG4gICAgOiBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4oaG9vay5ydW5JZCwge1xuICAgICAgICBkZXBsb3ltZW50SWQ6IGluZm8ucmVzdW1lQ29udGV4dC5kZXBsb3ltZW50SWQsXG4gICAgICB9KTtcbiAgcmV0dXJuIHJhd0tleSA/IGF3YWl0IGltcG9ydEtleShyYXdLZXkpIDogdW5kZWZpbmVkO1xufVxuXG4vKiogV2hldGhlciBgbWV0YWRhdGFgIG9uIHRoaXMgcmVjb3JkIGlzIGFscmVhZHkgdGhlIGxhenkgUHJvbWlzZSBhY2Nlc3Nvci4gKi9cbmZ1bmN0aW9uIGhhc0xhenlNZXRhZGF0YShob29rOiBSZXN1bWFibGVIb29rKTogYm9vbGVhbiB7XG4gIGNvbnN0IGRlc2NyaXB0b3IgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGhvb2ssICdtZXRhZGF0YScpO1xuICByZXR1cm4gZGVzY3JpcHRvciAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiBkZXNjcmlwdG9yLmdldCA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuLyoqXG4gKiBXcmFwcyBhIHJhdyBob29rIHJlY29yZCBmcm9tIGEgV29ybGQgaW4gYSB7QGxpbmsgSG9va30sXG4gKiByZXBsYWNpbmcgaXRzIHNlcmlhbGl6ZWQgYG1ldGFkYXRhYCB3aXRoIGEgbWVtb2l6ZWQgUHJvbWlzZSBnZXR0ZXIgdGhhdFxuICogaHlkcmF0ZXMgb24gZmlyc3QgYWNjZXNzLlxuICpcbiAqIE5vdGhpbmcgaGVyZSB0b3VjaGVzIHRoZSBuZXR3b3JrOiB0aGUgd3JhcCBpcyBhIHByb3BlcnR5IGRlZmluaXRpb24uIEFsbCBvZlxuICogdGhlIGNvc3Qg4oCUIHJlc29sdmluZyB0aGUgcnVuJ3MgcGF5bG9hZCBrZXlzIGFuZCBkZWNyeXB0aW5nIOKAlCBtb3ZlcyBpbnNpZGUgdGhlXG4gKiBnZXR0ZXIsIHNvIGEgbG9va3VwIHRoYXQgbmV2ZXIgcmVhZHMgbWV0YWRhdGEgcGF5cyBmb3IgZXhhY3RseSBvbmVcbiAqIGBob29rcy5nZXRCeVRva2VuYC5cbiAqXG4gKiBUaGUgZ2V0dGVyIGlzIGRlZmluZWQgaW4gcGxhY2Ugb24gdGhlIHJlY29yZCB0aGUgV29ybGQgcmV0dXJuZWQgKHRoZSBzYW1lXG4gKiBvYmplY3QgdGhlIGVhZ2VyIHBhdGggdXNlZCB0byBtdXRhdGUpLCBzbyBubyBjb3B5IGlzIG1hZGUuXG4gKi9cbmZ1bmN0aW9uIHdpdGhMYXp5TWV0YWRhdGEocmF3OiBXb3JsZEhvb2spOiBIb29rTG9va3VwIHtcbiAgY29uc3Qgc2VyaWFsaXplZCA9IHJhdy5tZXRhZGF0YTtcbiAgbGV0IGh5ZHJhdGVkOiBQcm9taXNlPHVua25vd24+IHwgdW5kZWZpbmVkO1xuICBsZXQgZW5jcnlwdGlvbktleTogUGF5bG9hZEtleSB8IHVuZGVmaW5lZDtcblxuICAvLyBIeWRyYXRpbmcgbWV0YWRhdGEgaXMgYSBkZWNyeXB0aW5nIFJFQUQsIHNvIGl0IGRlcml2ZXMgdGhlIGZ1bGxcbiAgLy8gUnVuUGF5bG9hZEtleXMgKHdoaWNoIG9wZW4gc2VhbGVkIGBlbmNwYCBtZXRhZGF0YSwgbm90IGp1c3Qgc3ltbWV0cmljXG4gIC8vIGBlbmNyYCkgcmF0aGVyIHRoYW4gdGhlIGJhcmUgd3JpdGUga2V5IHRoZSByZXN1bWUgcGF0aCB1c2VzLlxuICBjb25zdCBoeWRyYXRlID0gYXN5bmMgKCk6IFByb21pc2U8dW5rbm93bj4gPT4ge1xuICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gICAgY29uc3QgaW5mbyA9IGF3YWl0IHJlc29sdmVIb29rUmVzdW1lSW5mbyhyYXcpO1xuICAgIC8vIE9uIHRoZSBmYXN0IHBhdGggdGhpcyByZXNvbHZlcyB0aGUga2V5IGJ5IHJ1bklkICsgZGVwbG95bWVudElkIChubyBydW5cbiAgICAvLyByZWFkKTsgb24gdGhlIGZhbGxiYWNrIHBhdGggaXQgcmV1c2VzIHRoZSBhbHJlYWR5LWZldGNoZWQgcnVuLlxuICAgIGNvbnN0IHJhd0tleSA9IGluZm8ucnVuXG4gICAgICA/IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihpbmZvLnJ1bilcbiAgICAgIDogYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJhdy5ydW5JZCwge1xuICAgICAgICAgIGRlcGxveW1lbnRJZDogaW5mby5yZXN1bWVDb250ZXh0LmRlcGxveW1lbnRJZCxcbiAgICAgICAgfSk7XG4gICAgZW5jcnlwdGlvbktleSA9IHJhd0tleSA/IGF3YWl0IGRlcml2ZVJ1blBheWxvYWRLZXlzKHJhd0tleSkgOiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIGF3YWl0IGh5ZHJhdGVTdGVwQXJndW1lbnRzKFxuICAgICAgc2VyaWFsaXplZCBhcyBhbnksXG4gICAgICByYXcucnVuSWQsXG4gICAgICBlbmNyeXB0aW9uS2V5XG4gICAgKTtcbiAgfTtcblxuICBjb25zdCBob29rID0gcmF3IGFzIHVua25vd24gYXMgSG9vaztcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGhvb2ssICdtZXRhZGF0YScsIHtcbiAgICAvLyBBIGhvb2sgd2l0aCBubyBtZXRhZGF0YSByZXNvbHZlcyBgdW5kZWZpbmVkYCB3aXRob3V0IGFueSBJL08sIHNvIGNhbGxlcnNcbiAgICAvLyBjYW4gYXdhaXQgdW5jb25kaXRpb25hbGx5LiBNZW1vaXplZCBlaXRoZXIgd2F5OiBtZXRhZGF0YSBpcyBmaXhlZCBhdFxuICAgIC8vIGhvb2stY3JlYXRpb24gdGltZSwgc28gaHlkcmF0aW9uIHJ1bnMgYXQgbW9zdCBvbmNlIHBlciBob29rIG9iamVjdC5cbiAgICBnZXQ6ICgpID0+XG4gICAgICAoaHlkcmF0ZWQgPz89XG4gICAgICAgIHR5cGVvZiBzZXJpYWxpemVkID09PSAndW5kZWZpbmVkJ1xuICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKHVuZGVmaW5lZClcbiAgICAgICAgICA6IGh5ZHJhdGUoKSksXG4gICAgLy8gTm9uLWVudW1lcmFibGUsIG1hdGNoaW5nIGBSdW4ucmV0dXJuVmFsdWVgIChhIHByb3RvdHlwZSBnZXR0ZXIsIHNvIGl0IGlzXG4gICAgLy8gYWJzZW50IGZyb20gYW4gaW5zdGFuY2UncyBvd24ga2V5cykuIFNwcmVhZGluZyBvciBgSlNPTi5zdHJpbmdpZnlgLWluZyBhXG4gICAgLy8gaG9vayB0aGVyZWZvcmUgY2Fubm90IHRyaWdnZXIgaHlkcmF0aW9uIG5vYm9keSBhc2tlZCBmb3Ig4oCUIHdoaWNoIHdvdWxkXG4gICAgLy8gb3RoZXJ3aXNlIGxlYXZlIGEgZmxvYXRpbmcgcmVqZWN0aW9uIHdoZW4gdGhlIHJ1biBrZXkgaXMgdW5yZWFjaGFibGUsIGFuZFxuICAgIC8vIGFuIHVuY29uc3VtZWQgcmVqZWN0ZWQgUHJvbWlzZSBjcmFzaGVzIE5vZGUgYXMgYW4gdW5oYW5kbGVkUmVqZWN0aW9uLlxuICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgfSk7XG5cbiAgcmV0dXJuIHsgaG9vaywgbWV0YWRhdGFFbmNyeXB0aW9uS2V5OiAoKSA9PiBlbmNyeXB0aW9uS2V5IH07XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhbnkgaG9vayByZWNvcmQgdGhlIHJlc3VtZSBwYXRoIGFjY2VwdGVkIGludG8gYVxuICoge0BsaW5rIEhvb2t9IHRvIHJldHVybiB0byB0aGUgY2FsbGVyLiBJZGVtcG90ZW50OiBhIGhvb2sgdGhhdFxuICogYWxyZWFkeSBjYXJyaWVzIHRoZSBsYXp5IGFjY2Vzc29yIChvbmUgdGhhdCBjYW1lIGZyb20gYGdldEhvb2tCeVRva2VuYCkgaXNcbiAqIHJldHVybmVkIGFzLWlzIHJhdGhlciB0aGFuIGRvdWJsZS13cmFwcGVkLCB3aGljaCB3b3VsZCBoYW5kXG4gKiBgaHlkcmF0ZVN0ZXBBcmd1bWVudHNgIGEgUHJvbWlzZS5cbiAqL1xuZnVuY3Rpb24gYXNMYXp5TWV0YWRhdGFIb29rKGhvb2s6IFJlc3VtYWJsZUhvb2spOiBIb29rIHtcbiAgcmV0dXJuIGhhc0xhenlNZXRhZGF0YShob29rKVxuICAgID8gKGhvb2sgYXMgSG9vaylcbiAgICA6IHdpdGhMYXp5TWV0YWRhdGEoaG9vayBhcyBXb3JsZEhvb2spLmhvb2s7XG59XG5cbi8qKlxuICogR2V0IHRoZSBob29rIGJ5IHRva2VuIHRvIGZpbmQgdGhlIGFzc29jaWF0ZWQgd29ya2Zsb3cgcnVuLlxuICpcbiAqIFRoaXMgaXMgYSBzaW5nbGUgcmVhZC4gVGhlIHJldHVybmVkIGhvb2sncyBgbWV0YWRhdGFgIGlzIGEgZ2V0dGVyIHRoYXRcbiAqIHJlc29sdmVzIGEgUHJvbWlzZSAoc2VlIHtAbGluayBIb29rfSksIHNvIHRoZSBydW4gZmV0Y2ggYW5kXG4gKiBgcnVuLWtleWAgcm91bmQgdHJpcCB0aGF0IGh5ZHJhdGluZyBpdCBjYW4gcmVxdWlyZSBhcmUgb25seSBwYWlkIGJ5IGNhbGxlcnNcbiAqIHRoYXQgYWN0dWFsbHkgYXdhaXQgaXQ6XG4gKlxuICogYGBgdHNcbiAqIGNvbnN0IGhvb2sgPSBhd2FpdCBnZXRIb29rQnlUb2tlbih0b2tlbik7XG4gKiBjb25zdCBtZXRhZGF0YSA9IGF3YWl0IGhvb2subWV0YWRhdGE7XG4gKiBgYGBcbiAqXG4gKiBBIEhvb2sga2VwdCBieSBtaW5pbXVtIHJldGVudGlvbiByZW1haW5zIGF2YWlsYWJsZSBoZXJlIGFmdGVyIGl0cyBydW4gZW5kcyxcbiAqIGJ1dCBjYW5ub3QgYmUgcmVzdW1lZC5cbiAqXG4gKiBAcGFyYW0gdG9rZW4gLSBUaGUgdW5pcXVlIHRva2VuIGlkZW50aWZ5aW5nIHRoZSBob29rXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRIb29rQnlUb2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxIb29rPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIHJldHVybiB3aXRoTGF6eU1ldGFkYXRhKGF3YWl0IHdvcmxkLmhvb2tzLmdldEJ5VG9rZW4odG9rZW4pKS5ob29rO1xufVxuXG4vKipcbiAqIFRoZSByZXN1bHQgb2Yge0BsaW5rIHJlc3VtZUhvb2t9OiBhIHtAbGluayBIb29rfSBhdWdtZW50ZWRcbiAqIHdpdGggYW4gb3B0aW9uYWwgcmVzaWxpZW5jZSBzaWduYWwuXG4gKlxuICogYHJlc2lsaWVudFJlc3VtZWAgaXMgcmV0YWluZWQgZm9yIHNvdXJjZSBjb21wYXRpYmlsaXR5IGFuZCBpcyBuZXZlciBzZXQuXG4gKiBgcmVzdW1lSG9vaygpYCBub3cgcmVxdWlyZXMgdGhlIGR1cmFibGUgYGhvb2tfcmVjZWl2ZWRgIHdyaXRlIGFuZCB3b3JrZmxvd1xuICogd2FrZSB0byBib3RoIHN1Y2NlZWQgYmVmb3JlIGl0IHJlc29sdmVzLiBUcmVhdCB0aGUgcmVzdWx0IGFzIGEgcGxhaW5cbiAqIHtAbGluayBIb29rfS5cbiAqL1xuZXhwb3J0IHR5cGUgUmVzdW1lZEhvb2sgPSBIb29rICYge1xuICByZXNpbGllbnRSZXN1bWU/OiBib29sZWFuO1xufTtcblxuLyoqXG4gKiBSZXN1bWVzIGEgd29ya2Zsb3cgcnVuIGJ5IHNlbmRpbmcgYSBwYXlsb2FkIHRvIGEgaG9vayBpZGVudGlmaWVkIGJ5IGl0cyB0b2tlbi5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBleHRlcm5hbGx5IChlLmcuLCBmcm9tIGFuIEFQSSByb3V0ZSBvciBzZXJ2ZXIgYWN0aW9uKVxuICogdG8gc2VuZCBkYXRhIHRvIGEgaG9vayBhbmQgcmVzdW1lIHRoZSBhc3NvY2lhdGVkIHdvcmtmbG93IHJ1bi5cbiAqXG4gKiBSZXNvbHZpbmcgbWVhbnMgQk9USCB0aGF0IHRoZSBgaG9va19yZWNlaXZlZGAgZXZlbnQgaXMgZHVyYWJseSByZWNvcmRlZCBpblxuICogdGhlIHJ1bidzIGV2ZW50IGxvZyBhbmQgdGhhdCB0aGUgd29ya2Zsb3cgd2FrZSB3YXMgYWNjZXB0ZWQgYnkgdGhlIHF1ZXVlLCBpblxuICogdGhhdCBvcmRlci4gQSB7QGxpbmsgSG9va05vdEZvdW5kRXJyb3J9IG1lYW5zIHRoaXMgaW52b2NhdGlvbiBjb21taXR0ZWQgbm9cbiAqIGV2ZW50LiBBbnkgb3RoZXIgZXJyb3IgYWZ0ZXIgdGhlIHdyaXRlIGlzIGFtYmlndW91cyBvbmx5IGluIGRpc3BhdGNoLCBuZXZlclxuICogaW4gZHVyYWJpbGl0eTogdGhlIGV2ZW50IG1heSBhbHJlYWR5IGJlIGNvbW1pdHRlZCwgYW5kIGEgbGF0ZXIgd2FrZSBvZiB0aGVcbiAqIHJ1biAoZnJvbSBhbnkgc291cmNlKSB3aWxsIGRlbGl2ZXIgaXQuXG4gKlxuICogUHJlZmVyIHBhc3NpbmcgdGhlIHRva2VuIHN0cmluZyBvdmVyIGEgY2FjaGVkIHtAbGluayBIb29rfSBvYmplY3QuIEEgdG9rZW5cbiAqIGlzIGxvb2tlZCB1cCBmcmVzaCwgc28gdGhlIGxpdmUgYmFja2VuZCBjYW4gYXR0ZXN0IGl0cyBhdG9taWMgcmVzdW1lIGNsYWltXG4gKiBhbmQgdGhlIGR1cmFibGUgd3JpdGUgYmVjb21lcyBpZGVtcG90ZW50LW9uLXJldHJ5ICh0cmFuc3BvcnQgcmV0cmllcyBvZiB0aGVcbiAqIHNhbWUgd3JpdGUgY29udmVyZ2Ugb24gb25lIGV2ZW50KS4gQSBzdXBwbGllZCBIb29rIG9iamVjdCBtYXkgY2FycnkgYSBzdGFsZVxuICogYXR0ZXN0YXRpb24sIHNvIGl0IGlzIGRlbGliZXJhdGVseSBpZ25vcmVkIGFuZCB0aGUgd3JpdGUgaXMgY2xhaW0tbGVzcyDigJRcbiAqIG1lYW5pbmcgYSBsb3N0IHJlc3BvbnNlIGNhbm5vdCBiZSByZXRyaWVkIHNhZmVseTogcmV0cnlpbmcgYXQgdGhlXG4gKiBhcHBsaWNhdGlvbiBsZXZlbCBtaW50cyBhIGZyZXNoIGNsYWltIGFuZCBjYW4gY29tbWl0IGEgc2Vjb25kXG4gKiBgaG9va19yZWNlaXZlZGAuXG4gKlxuICogQHBhcmFtIHRva2VuT3JIb29rIC0gVGhlIHVuaXF1ZSB0b2tlbiBpZGVudGlmeWluZyB0aGUgaG9vaywgb3IgdGhlIGhvb2sgb2JqZWN0IGl0c2VsZlxuICogQHBhcmFtIHBheWxvYWQgLSBUaGUgZGF0YSBwYXlsb2FkIHRvIHNlbmQgdG8gdGhlIGhvb2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB7QGxpbmsgUmVzdW1lZEhvb2t9XG4gKiBAdGhyb3dzIHtIb29rTm90Rm91bmRFcnJvcn0gSWYgdGhlIEhvb2sgZG9lcyBub3QgZXhpc3Qgb3IgaXRzIHJ1biBoYXMgZW5kZWRcbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYHRzXG4gKiAvLyBJbiBhbiBBUEkgcm91dGVcbiAqIGltcG9ydCB7IHJlc3VtZUhvb2sgfSBmcm9tICdAd29ya2Zsb3cvY29yZS9ydW50aW1lJztcbiAqXG4gKiBleHBvcnQgYXN5bmMgZnVuY3Rpb24gUE9TVChyZXF1ZXN0OiBSZXF1ZXN0KSB7XG4gKiAgIGNvbnN0IHsgdG9rZW4sIGRhdGEgfSA9IGF3YWl0IHJlcXVlc3QuanNvbigpO1xuICpcbiAqICAgdHJ5IHtcbiAqICAgICBjb25zdCBob29rID0gYXdhaXQgcmVzdW1lSG9vayh0b2tlbiwgZGF0YSk7XG4gKiAgICAgcmV0dXJuIFJlc3BvbnNlLmpzb24oeyBydW5JZDogaG9vay5ydW5JZCB9KTtcbiAqICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKCdIb29rIG5vdCBmb3VuZCcsIHsgc3RhdHVzOiA0MDQgfSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzdW1lSG9vazxUID0gYW55PihcbiAgdG9rZW5Pckhvb2s6IHN0cmluZyB8IFJlc3VtYWJsZUhvb2ssXG4gIHBheWxvYWQ6IFQsXG4gIGVuY3J5cHRpb25LZXlPdmVycmlkZT86IFBheWxvYWRLZXlcbik6IFByb21pc2U8UmVzdW1lZEhvb2s+IHtcbiAgLy8gUHVibGljIGVudHJ5IHBvaW50LiBJdCBuZXZlciBhdHRlc3RzIGhvb2sgZnJlc2huZXNzLCBzbyBhIEhvb2sgb2JqZWN0XG4gIC8vIHN1cHBsaWVkIGhlcmUgKHdoaWNoIG1heSBjYXJyeSBhIGByZXN1bWVDYXBhYmlsaXRpZXNgIGNhY2hlZCBiZWZvcmUgYVxuICAvLyBzZXJ2ZXIgcm9sbGJhY2sgb3Iga2lsbCBzd2l0Y2gpIGlzIGlnbm9yZWQgYnkgdGhlIGR5bmFtaWMtZGVkdXAgZ2F0ZSBhbmRcbiAgLy8gZmFpbHMgY2xvc2VkIHRvIGEgcGxhaW4sIGNsYWltLWxlc3Mgd3JpdGUuIE9ubHkgYHJlc3VtZVdlYmhvb2tgLCB3aGljaFxuICAvLyBmZXRjaGVzIHRoZSBob29rIGJ5IHRva2VuIGluLWxpbmUgZHVyaW5nIHRoZSBzYW1lIHJlc3VtZSwgcmVhY2hlcyB0aGVcbiAgLy8gaW50ZXJuYWwgaW1wbGVtZW50YXRpb24gd2l0aCB0aGUgZnJlc2ggYXR0ZXN0YXRpb24gc2V0LiBLZWVwaW5nIHRoZVxuICAvLyBmcmVzaG5lc3MgZmxhZyBvZmYgdGhlIGV4cG9ydGVkIHNpZ25hdHVyZSBwcmV2ZW50cyBhIGNhbGxlciBmcm9tIHBhc3NpbmcgYVxuICAvLyBzdGFsZSBIb29rIHBsdXMgYHRydWVgIGFuZCByZWFjdGl2YXRpbmcgZHluYW1pYyBkZWR1cCBhZ2FpbnN0IGFcbiAgLy8gcm9sbGVkLWJhY2sgYmFja2VuZC5cbiAgLy9cbiAgLy8gVDAgb2YgdGhlIGhvb2stcmVzdW1lIFRUUiB3aW5kb3cgaXMgdGFrZW4gSEVSRSwgYXQgdGhlIHB1YmxpYyBlbnRyeSBwb2ludCxcbiAgLy8gcmF0aGVyIHRoYW4gaW5zaWRlIHRoZSBpbXBsZW1lbnRhdGlvbjsgc2VlIHRoZSBwYXJhbWV0ZXIncyBkb2MgY29tbWVudC5cbiAgcmV0dXJuIHJlc3VtZUhvb2tJbXBsKFxuICAgIHRva2VuT3JIb29rLFxuICAgIHBheWxvYWQsXG4gICAgZW5jcnlwdGlvbktleU92ZXJyaWRlLFxuICAgIGZhbHNlLFxuICAgIERhdGUubm93KClcbiAgKTtcbn1cblxuLyoqXG4gKiBJbnRlcm5hbCBpbXBsZW1lbnRhdGlvbiBvZiB7QGxpbmsgcmVzdW1lSG9va30uIE5PVCBleHBvcnRlZDogdGhlXG4gKiBgaG9va0ZyZXNobHlMb29rZWRVcGAgYXR0ZXN0YXRpb24gbXVzdCBuZXZlciBiZSByZWFjaGFibGUgYnkgcHVibGljIGNhbGxlcnNcbiAqIChzZWUgdGhlIHdyYXBwZXIgYWJvdmUpLlxuICpcbiAqIEBwYXJhbSBob29rRnJlc2hseUxvb2tlZFVwIC0gQXR0ZXN0cyB0aGF0IGEgc3VwcGxpZWQgSG9vayBvYmplY3Qgd2FzIGZldGNoZWRcbiAqICAgYnkgdG9rZW4gZHVyaW5nIFRISVMgcmVzdW1lLCBzbyBpdHMgcmVzcG9uc2Utb25seSBgcmVzdW1lQ2FwYWJpbGl0aWVzYFxuICogICByZWZsZWN0cyB0aGUgbGl2ZSBiYWNrZW5kIGFuZCBtYXkgYmUgdHJ1c3RlZCBmb3IgdGhlIGR5bmFtaWMtZGVkdXAgZ2F0ZS5cbiAqICAgQSB0b2tlbiBzdHJpbmcgaXMgYWx3YXlzIGZldGNoZWQgZnJlc2ggaGVyZSwgc28gaXQgaXMgaW1wbGljaXRseSBmcmVzaC5cbiAqIEBwYXJhbSByZXN1bWVSZXF1ZXN0ZWRBdE1zIC0gVDAgb2YgdGhlIGhvb2stcmVzdW1lIFRUUiB3aW5kb3cgKHNlZVxuICogICBydW50aW1lL3Jlc3VtZS1sYXRlbmN5LnRzKSwgc3RhbXBlZCBieSB0aGUgUFVCTElDIGVudHJ5IHBvaW50IHRoZSBjYWxsZXJcbiAqICAgdXNlZC4gSXQgaXMgYSBwYXJhbWV0ZXIgcmF0aGVyIHRoYW4gYSBsb2NhbCBiZWNhdXNlIGByZXN1bWVXZWJob29rYCBkb2VzXG4gKiAgIHJlYWwgd29yayBiZWZvcmUgaXQgZ2V0cyBoZXJlICh0aGUgYnktdG9rZW4gbG9va3VwLCB0aGUgcnVuLWtleVxuICogICByZXNvbHV0aW9uIHRoYXQgaHlkcmF0ZXMgaG9vayBtZXRhZGF0YSwgYW5kIHRoZSBgcmVzcG9uZFdpdGhgIHNldHVwKSBhbmRcbiAqICAgc3RhbXBpbmcgbG9jYWxseSB3b3VsZCBzaWxlbnRseSBleGNsdWRlIGFsbCBvZiBpdCwgc28gdGhlIHR3byBlbnRyeSBwb2ludHNcbiAqICAgd291bGQgcmVwb3J0IHRoZSBzYW1lIG1ldHJpYyBvdmVyIGRpZmZlcmVudCB3aW5kb3dzLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXN1bWVIb29rSW1wbDxUID0gYW55PihcbiAgdG9rZW5Pckhvb2s6IHN0cmluZyB8IFJlc3VtYWJsZUhvb2ssXG4gIHBheWxvYWQ6IFQsXG4gIGVuY3J5cHRpb25LZXlPdmVycmlkZTogUGF5bG9hZEtleSB8IHVuZGVmaW5lZCxcbiAgaG9va0ZyZXNobHlMb29rZWRVcDogYm9vbGVhbixcbiAgcmVzdW1lUmVxdWVzdGVkQXRNczogbnVtYmVyXG4pOiBQcm9taXNlPFJlc3VtZWRIb29rPiB7XG4gIHJldHVybiBhd2FpdCB3YWl0ZWRVbnRpbCgoKSA9PiB7XG4gICAgcmV0dXJuIHRyYWNlKCdob29rLnJlc3VtZScsIGFzeW5jIChzcGFuKSA9PiB7XG4gICAgICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkTGF6eSgpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzdXBwbGllZFRva2VuID0gdHlwZW9mIHRva2VuT3JIb29rID09PSAnc3RyaW5nJztcbiAgICAgICAgY29uc3QgaG9vazogUmVzdW1hYmxlSG9vayA9IHN1cHBsaWVkVG9rZW5cbiAgICAgICAgICA/IGF3YWl0IHdvcmxkLmhvb2tzLmdldEJ5VG9rZW4odG9rZW5Pckhvb2spXG4gICAgICAgICAgOiB0b2tlbk9ySG9vaztcbiAgICAgICAgLy8gVGhlIGR5bmFtaWMsIHJlc3BvbnNlLW9ubHkgYHJlc3VtZUNhcGFiaWxpdGllc2AgbWF5IG9ubHkgYmUgdHJ1c3RlZFxuICAgICAgICAvLyB3aGVuIGl0IGNhbWUgZnJvbSBhIGJ5LXRva2VuIGxvb2t1cCBwZXJmb3JtZWQgZHVyaW5nIHRoaXMgcmVzdW1lLlxuICAgICAgICBjb25zdCBob29rUmVzdW1lQ2FwYWJpbGl0aWVzQXJlRnJlc2ggPVxuICAgICAgICAgIHN1cHBsaWVkVG9rZW4gfHwgaG9va0ZyZXNobHlMb29rZWRVcDtcblxuICAgICAgICBjb25zdCBpbmZvID0gYXdhaXQgcmVzb2x2ZUhvb2tSZXN1bWVJbmZvKGhvb2spO1xuICAgICAgICBjb25zdCB7IHJlc3VtZUNvbnRleHQgfSA9IGluZm87XG5cbiAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAgICAgLi4uQXR0cmlidXRlLkhvb2tUb2tlbihob29rLnRva2VuKSxcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuSG9va0lkKGhvb2suaG9va0lkKSxcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5JZChob29rLnJ1bklkKSxcbiAgICAgICAgICAnd29ya2Zsb3cuaG9vay5yZXN1bWVfY29udGV4dF9zb3VyY2UnOiBpbmZvLnNvdXJjZSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVGhlIHN0b3JlZCBgcmVzdW1lQ29udGV4dGAgaW50ZW50aW9uYWxseSBvbWl0cyB0aGUgcnVuJ3MgbXV0YWJsZVxuICAgICAgICAvLyBzdGF0dXMsIHNvIHRoaXMgZWFybHkgY2xpZW50LXNpZGUgcmVqZWN0aW9uIG9ubHkgcnVucyBvbiB0aGVcbiAgICAgICAgLy8gZmFsbGJhY2sgcGF0aCAod2hpY2ggZmV0Y2hlZCB0aGUgcnVuKS4gT24gdGhlIGZhc3QgcGF0aCB0aGUgdGVybWluYWxcbiAgICAgICAgLy8gY2hlY2sgaGFwcGVucyBzZXJ2ZXItc2lkZTogYGhvb2tfcmVjZWl2ZWRgIGFnYWluc3QgYW4gZW5kZWQgcnVuIGlzXG4gICAgICAgIC8vIHJlamVjdGVkLCB3aGljaCB0aGUgY2F0Y2ggYXJvdW5kIGB3b3JsZC5ldmVudHMuY3JlYXRlYCBiZWxvdyByZS1rZXlzXG4gICAgICAgIC8vIHRvIEhvb2tOb3RGb3VuZEVycm9yOiBzYW1lIHB1YmxpYyBjb250cmFjdCwgbm8gcnVuIHByZS1mZXRjaC5cbiAgICAgICAgaWYgKGluZm8ucnVuICYmIGlzVGVybWluYWxXb3JrZmxvd1J1blN0YXR1cyhpbmZvLnJ1bi5zdGF0dXMpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEhvb2tOb3RGb3VuZEVycm9yKGhvb2sudG9rZW4pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgdGhlIHRhcmdldCBydW4ncyBjYXBhYmlsaXRpZXMgdG8gZW5zdXJlIHdlIGVuY29kZSB0aGVcbiAgICAgICAgLy8gcGF5bG9hZCBpbiBhIGZvcm1hdCB0aGUgcnVuJ3MgZGVwbG95bWVudCBjYW4gZGVjb2RlLiBGb3IgZXhhbXBsZSxcbiAgICAgICAgLy8gcnVucyBjcmVhdGVkIGJlZm9yZSBlbmNyeXB0aW9uIHN1cHBvcnQgd2FzIGFkZGVkIGNhbm5vdCBkZWNvZGVcbiAgICAgICAgLy8gdGhlICdlbmNyJyBzZXJpYWxpemF0aW9uIGZvcm1hdCwgYW5kIHJ1bnMgY3JlYXRlZCBiZWZvcmVcbiAgICAgICAgLy8gYnl0ZS1zdHJlYW0gZnJhbWluZyBzdXBwb3J0IGNhbm5vdCBkZWNvZGUgZnJhbWVkIGJ5dGUgc3RyZWFtcy5cbiAgICAgICAgY29uc3QgY2FwYWJpbGl0aWVzID0gZ2V0UnVuQ2FwYWJpbGl0aWVzKFxuICAgICAgICAgIHJlc3VtZUNvbnRleHQud29ya2Zsb3dDb3JlVmVyc2lvblxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFJlc29sdmUgaG93IHRvIGVuY3J5cHQgdGhlIHBheWxvYWQgZm9yIHRoZSB0YXJnZXQgcnVuIChhIFdSSVRFKS5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gUHJlZmVycmVkIHBhdGg6IHNlYWwgdG8gdGhlIHJ1bidzIHB1Ymxpc2hlZCBYMjU1MTkgcHVibGljIGtleSwgd2hpY2hcbiAgICAgICAgLy8gdGhlIHN0b3JlZCBgcmVzdW1lQ29udGV4dGAgY2FycmllcyBpbmxpbmUuIE9uIHRoZSBmYXN0IHBhdGggdGhpcyBpc1xuICAgICAgICAvLyB0aGUgd2hvbGUgd2luOiBubyBydW4gcmVhZCBBTkQgbm8gYGdldEVuY3J5cHRpb25LZXlGb3JSdW5gLCB3aG9zZVxuICAgICAgICAvLyB+MzUwbXMgYHJ1bi1rZXlgIEFQSSByb3VuZCB0cmlwIGRvbWluYXRlcyBjcm9zcy1kZXBsb3ltZW50IGhvb2tcbiAgICAgICAgLy8gcmVzdW1wdGlvbiBsYXRlbmN5LiAoT24gdGhlIGZhbGxiYWNrIHBhdGggdGhlIGtleSBpcyBzeW50aGVzaXplZFxuICAgICAgICAvLyBmcm9tIHRoZSBmZXRjaGVkIHJ1biwgd2hpY2ggYWxzbyBjYXJyaWVzIGl0LilcbiAgICAgICAgLy9cbiAgICAgICAgLy8gU2VhbGluZyBhbHNvIGRyb3BzIHByaXZpbGVnZTogdGhlIHJlc3VtZXIgZW5kcyB1cCBhYmxlIHRvIHdyaXRlIGFcbiAgICAgICAgLy8gcGF5bG9hZCBmb3IgdGhlIHJ1biB3aXRob3V0IGJlaW5nIGFibGUgdG8gcmVhZCBhbnl0aGluZyBvZiB0aGVcbiAgICAgICAgLy8gcnVuJ3MsIHdoZXJlIGZldGNoaW5nIHRoZSBzeW1tZXRyaWMga2V5IGdyYW50cyBib3RoLlxuICAgICAgICAvL1xuICAgICAgICAvLyBEZWxpYmVyYXRlbHkgTk9UIGdhdGVkIG9uIGBjYXBhYmlsaXRpZXMuc3VwcG9ydGVkRm9ybWF0c2AgdGhlIHdheVxuICAgICAgICAvLyB0aGUgc3ltbWV0cmljIGZhbGxiYWNrIGJlbG93IGdhdGVzIGBlbmNyYDogcHJlc2VuY2Ugb2YgdGhlIHB1YmxpYyBrZXlcbiAgICAgICAgLy8gaXMgaXRzZWxmIHRoZSBnYXRlLiBBIHJ1biBvbmx5IGNhcnJpZXMgb25lIGlmIHRoZSBydW50aW1lIHRoYXRcbiAgICAgICAgLy8gY3JlYXRlZCBpdCBjb3VsZCBhbHNvIG9wZW4gYSBzZWFsZWQgcGF5bG9hZCwgYW5kIHJ1bnMgYXJlIHBpbm5lZCB0b1xuICAgICAgICAvLyB0aGVpciBjcmVhdGluZyBkZXBsb3ltZW50LCBzbyBwcmVzZW5jZSBpcyBhIG1vcmUgcmVsaWFibGUgYXR0ZXN0YXRpb25cbiAgICAgICAgLy8gdGhhbiBhIHZlcnNpb24gY29tcGFyZSwgYW5kIGl0IHN0YXlzIGNvcnJlY3QgZXZlbiB3aGVuIHBhY2thZ2VcbiAgICAgICAgLy8gdmVyc2lvbnMgZHJpZnQuXG4gICAgICAgIGxldCBwYXlsb2FkS2V5OiBQYXlsb2FkS2V5IHwgdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBydW5QdWJsaWNLZXkgPSBlbmNyeXB0aW9uS2V5T3ZlcnJpZGVcbiAgICAgICAgICA/IC8vIFRoZSBjYWxsZXIgYWxyZWFkeSBob2xkcyBhIGtleSAocmVzdW1lV2ViaG9vayByZXNvbHZlZCBvbmUgdG9cbiAgICAgICAgICAgIC8vIGh5ZHJhdGUgaG9vayBtZXRhZGF0YSksIHNvIHNlYWxpbmcgd291bGQgYWRkIGFuIEVDREggZm9yIG5vXG4gICAgICAgICAgICAvLyBzYXZlZCByb3VuZCB0cmlwLiBSZXVzZSB3aGF0IGl0IHJlc29sdmVkLlxuICAgICAgICAgICAgdW5kZWZpbmVkXG4gICAgICAgICAgOiBkZWNvZGVSdW5QdWJsaWNLZXkocmVzdW1lQ29udGV4dC5lbmNyeXB0aW9uUHVibGljS2V5KTtcblxuICAgICAgICBpZiAocnVuUHVibGljS2V5KSB7XG4gICAgICAgICAgcGF5bG9hZEtleSA9IHNlYWxUbyhydW5QdWJsaWNLZXkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFN5bW1ldHJpYyBgZW5jcmAgd3JpdGUgZmFsbGJhY2s6IG5lZWRzIG9ubHkgdGhlIEFFUyBrZXlcbiAgICAgICAgICAvLyAoYSBiYXJlIENyeXB0b0tleSB2aWEgYHJlc29sdmVIb29rRW5jcnlwdGlvbktleWApLCBub3QgdGhlXG4gICAgICAgICAgLy8gcmVhZC1zaWRlIFJ1blBheWxvYWRLZXlzLlxuICAgICAgICAgIGxldCBlbmNyeXB0aW9uS2V5ID1cbiAgICAgICAgICAgIGVuY3J5cHRpb25LZXlPdmVycmlkZSA/P1xuICAgICAgICAgICAgKGF3YWl0IHJlc29sdmVIb29rRW5jcnlwdGlvbktleShob29rLCBpbmZvKSk7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgIWNhcGFiaWxpdGllcy5zdXBwb3J0ZWRGb3JtYXRzLmhhcyhTZXJpYWxpemF0aW9uRm9ybWF0LkVOQ1JZUFRFRClcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGVuY3J5cHRpb25LZXkgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIHBheWxvYWRLZXkgPSBlbmNyeXB0aW9uS2V5O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHJlc3Mgb25seSB3aGVuIHRoZSB0YXJnZXQgcnVuIGFuZCBpdHMgZGVwbG95bWVudCBzdXBwb3J0IHRoZVxuICAgICAgICAvLyBjb21wcmVzc2lvbiBmb3JtYXRzIGludHJvZHVjZWQgd2l0aCBzcGVjIHZlcnNpb24gNS5cbiAgICAgICAgY29uc3QgY29tcHJlc3Npb24gPVxuICAgICAgICAgIChyZXN1bWVDb250ZXh0LnJ1blNwZWNWZXJzaW9uID8/IDApID49XG4gICAgICAgICAgICBTUEVDX1ZFUlNJT05fU1VQUE9SVFNfQ09NUFJFU1NJT04gJiZcbiAgICAgICAgICBjYXBhYmlsaXRpZXMuc3VwcG9ydGVkRm9ybWF0cy5oYXMoU2VyaWFsaXphdGlvbkZvcm1hdC5HWklQKTtcblxuICAgICAgICAvLyBEZWh5ZHJhdGUgdGhlIHBheWxvYWQgZm9yIHN0b3JhZ2VcbiAgICAgICAgY29uc3Qgb3BzOiBQcm9taXNlPGFueT5bXSA9IFtdO1xuICAgICAgICBjb25zdCByZWFkYmFja09wczogUHJvbWlzZTxhbnk+W10gPSBbXTtcbiAgICAgICAgY29uc3QgdjFDb21wYXQgPSBpc0xlZ2FjeVNwZWNWZXJzaW9uKGhvb2suc3BlY1ZlcnNpb24pO1xuICAgICAgICBjb25zdCBkZWh5ZHJhdGVkUGF5bG9hZCA9IGF3YWl0IGRlaHlkcmF0ZVN0ZXBSZXR1cm5WYWx1ZShcbiAgICAgICAgICBwYXlsb2FkLFxuICAgICAgICAgIGhvb2sucnVuSWQsXG4gICAgICAgICAgcGF5bG9hZEtleSxcbiAgICAgICAgICBvcHMsXG4gICAgICAgICAgZ2xvYmFsVGhpcyxcbiAgICAgICAgICB2MUNvbXBhdCxcbiAgICAgICAgICBjYXBhYmlsaXRpZXMuZnJhbWVkQnl0ZVN0cmVhbXMsXG4gICAgICAgICAgY29tcHJlc3Npb24sXG4gICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgIHJlYWRiYWNrT3BzXG4gICAgICAgICk7XG4gICAgICAgIC8vIEEgaG9va19yZWNlaXZlZCBldmVudCBpcyBub3QgZHVyYWJsZSB3aGlsZSBpdHMgcGF5bG9hZCBzdGlsbCBwb2ludHNcbiAgICAgICAgLy8gYXQgc3RyZWFtIHVwbG9hZHMgaW4gZmxpZ2h0LiBGaW5pc2ggdGhvc2UgYmVmb3JlIGNvbW1pdHRpbmcgdGhlXG4gICAgICAgIC8vIGV2ZW50IOKAlCBidXQgT05MWSB0aGUgcHJvZHVjZXItcHVzaCBvcHMgaW4gYG9wc2AuIEEgZGVoeWRyYXRlZFxuICAgICAgICAvLyBXcml0YWJsZVN0cmVhbSBsYW5kcyBpbiBgcmVhZGJhY2tPcHNgIGluc3RlYWQ6IGl0IGlzIGEgc2VydmVyLXN0cmVhbVxuICAgICAgICAvLyBSRUFERVIgdGhhdCByZXNvbHZlcyBvbmx5IG9uY2UgdGhlIHdva2VuIHdvcmtmbG93IHdyaXRlcyBpbnRvIGl0IChhXG4gICAgICAgIC8vIG1hbnVhbCB3ZWJob29rJ3MgYHJlc3BvbnNlV3JpdGFibGVgIGlzIHRoZSBjYW5vbmljYWwgY2FzZSksIHNvXG4gICAgICAgIC8vIGF3YWl0aW5nIGl0IGhlcmUgd291bGQgZGVhZGxvY2sgdGhlIHJlc3VtZSBhZ2FpbnN0IGl0cyBvd24gd2FrZS5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gQSByZWplY3Rpb24gd2l0aCBgdW5kZWZpbmVkYCBpcyBhbiBleHBlY3RlZCBhcnRpZmFjdCBvZiB0aGUgd2ViaG9va1xuICAgICAgICAvLyBidW5kbGUgYW5kIHdhcyBoaXN0b3JpY2FsbHkgaWdub3JlZCBieSB0aGUgYmFja2dyb3VuZCBmbHVzaC4gS2VlcFxuICAgICAgICAvLyB0aGF0IHRvbGVyYW5jZSBub3cgdGhhdCB0aGUgZmx1c2ggaXMgYXdhaXRlZCBpbmxpbmUuXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgIG9wcy5tYXAoKG9wKSA9PlxuICAgICAgICAgICAgb3AuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChlcnJvciAhPT0gdW5kZWZpbmVkKSB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICAvLyBSZWFkYmFjayBwaXBlcyAobm90YWJseSBhIG1hbnVhbCB3ZWJob29rIHJlc3BvbnNlIHdyaXRhYmxlKSBjYW4gb25seVxuICAgICAgICAvLyBmaW5pc2ggYWZ0ZXIgdGhlIHdvcmtmbG93IHdha2VzIGFuZCB3cml0ZXMgdG8gdGhlbS4gS2VlcCB0aGVtIGFsaXZlLFxuICAgICAgICAvLyBidXQgbmV2ZXIgcGxhY2UgdGhlbSBpbiB0aGUgZHVyYWJpbGl0eSBiYXJyaWVyIGFib3ZlLlxuICAgICAgICBzYWZlV2FpdFVudGlsKFByb21pc2UuYWxsKHJlYWRiYWNrT3BzKSwgKGVycikgPT4ge1xuICAgICAgICAgIGlmIChlcnIgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybignQmFja2dyb3VuZCByZWFkYmFjayBvZiBob29rIHBheWxvYWQgZmFpbGVkJywge1xuICAgICAgICAgICAgd29ya2Zsb3dSdW5JZDogaG9vay5ydW5JZCxcbiAgICAgICAgICAgIGhvb2tJZDogaG9vay5ob29rSWQsXG4gICAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dOYW1lKHJlc3VtZUNvbnRleHQud29ya2Zsb3dOYW1lKSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gTGluayB0byB0aGUgcnVuLW9yaWdpbiBjb250ZXh0IGZyb20gdGhlIHN0b3JlZCB0cmFjZSBjYXJyaWVyXG4gICAgICAgIC8vIChza2lwcGVkIHdoZW4gYWJzZW50IG9yIGludmFsaWQpLiBSZXNvbHZlZCBiZWZvcmUgZGlzcGF0Y2ggc28gdGhlXG4gICAgICAgIC8vIHdyaXRlIGFuZCB0aGUgd2FrZSBib3RoIHNpdCB1bmRlciBhIHNwYW4gdGhhdCBjYXJyaWVzIGl0LlxuICAgICAgICBjb25zdCBvcmlnaW5MaW5rID0gYXdhaXQgbGlua1RvVHJhY2VDYXJyaWVyKHJlc3VtZUNvbnRleHQudHJhY2VDYXJyaWVyKTtcbiAgICAgICAgaWYgKG9yaWdpbkxpbmspIHtcbiAgICAgICAgICBzcGFuPy5hZGRMaW5rPy4ob3JpZ2luTGluayk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBxdWV1ZU5hbWUgPSBnZXRXb3JrZmxvd1F1ZXVlTmFtZShyZXN1bWVDb250ZXh0LndvcmtmbG93TmFtZSk7XG4gICAgICAgIGNvbnN0IHF1ZXVlT3B0aW9ucyA9IHtcbiAgICAgICAgICBkZXBsb3ltZW50SWQ6IHJlc3VtZUNvbnRleHQuZGVwbG95bWVudElkLFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiByZXN1bWVDb250ZXh0LnJ1blNwZWNWZXJzaW9uID8/IFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gVGhlIGRpc3BhdGNoIGlzIHN0cmljdGx5IHNlcmlhbDogdGhlIGhvb2tfcmVjZWl2ZWQgZXZlbnQgaXMgbWFkZVxuICAgICAgICAvLyBkdXJhYmxlIEZJUlNULCBhbmQgdGhlIHdvcmtmbG93IHdha2UgaXMgcHVibGlzaGVkIG9ubHkgYWZ0ZXIgdGhlXG4gICAgICAgIC8vIHdyaXRlIGlzIGFja25vd2xlZGdlZC4gVGhpcyBpcyB3aGF0IGxldHMgYHJlc3VtZUhvb2soKWAgcmVzb2x2aW5nXG4gICAgICAgIC8vIG1lYW4gXCJ0aGUgcmVzdW1lIHN1cnZpdmVzIGFueXRoaW5nIHRoYXQgaGFwcGVucyBuZXh0XCIg4oCUIGEgZGlzcG9zYWxcbiAgICAgICAgLy8gb3IgcnVuIGNvbXBsZXRpb24gcmFjaW5nIHRoZSBxdWV1ZSBkZWxpdmVyeSBjYW5ub3QgZXJhc2UgYSBjb21taXR0ZWRcbiAgICAgICAgLy8gZXZlbnQsIGFuZCB0aGUgd2FrZSBpdHNlbGYgY2FycmllcyBubyBwYXlsb2FkLCBzbyBub3RoaW5nIHJpZGVzIG9uXG4gICAgICAgIC8vIHRoZSBtZXNzYWdlIGJ1dCB0aGUgdHJpZ2dlci5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gQmFja2VuZCBkZWR1cCBpcyBhdHRlc3RlZCB3aGVuIEVJVEhFUiB0aGUgbGl2ZSBzZXJ2ZXIgYXR0ZXN0cyBpdFxuICAgICAgICAvLyBmcmVzaCBvbiB0aGlzIGJ5LXRva2VuIGhvb2sgKHdvcmxkLXZlcmNlbDogcmVzcG9uc2Utb25seSwgcmVjb21wdXRlZFxuICAgICAgICAvLyBldmVyeSByZWFkLCBzbyByb2xsYmFjay9raWxsLXN3aXRjaCB0YWtlIGVmZmVjdCBpbW1lZGlhdGVseSkgT1IgdGhlXG4gICAgICAgIC8vIHN0YXRpYyB3b3JsZCBjYXBhYmlsaXR5IGlzIHNldCAod29ybGQtbG9jYWw6IGFkYXB0ZXIgKyBiYWNrZW5kIHNoaXBcbiAgICAgICAgLy8gdG9nZXRoZXIpLiBXaGVuIGF0dGVzdGVkLCB0aGUgd3JpdGUgY2FycmllcyBhIHBlci1jYWxsIHJlc3VtZUlkICtcbiAgICAgICAgLy8gcGF5bG9hZCBkaWdlc3Qgc28gdHJhbnNwb3J0LWxldmVsIHJldHJpZXMgb2YgdGhlIFNBTUUgd3JpdGUgY29udmVyZ2VcbiAgICAgICAgLy8gb24gZXhhY3RseSBvbmUgY29tbWl0dGVkIGV2ZW50IHZpYSB0aGUgYmFja2VuZCdzIChydW5JZCwgcmVzdW1lSWQpXG4gICAgICAgIC8vIGNvbnN0cmFpbnQuIFdpdGhvdXQgaXQgdGhlIHdyaXRlIGlzIGEgcGxhaW4gc2luZ2xlLXNob3QgY3JlYXRlLFxuICAgICAgICAvLyBleGFjdGx5IGFzIGJlZm9yZSBkZWR1cCBleGlzdGVkLlxuICAgICAgICBjb25zdCBiYWNrZW5kRGVkdXBTdXBwb3J0ZWQgPVxuICAgICAgICAgIChob29rUmVzdW1lQ2FwYWJpbGl0aWVzQXJlRnJlc2hcbiAgICAgICAgICAgID8gKGhvb2sucmVzdW1lQ2FwYWJpbGl0aWVzPy5ob29rUmVzdW1lRGVkdXBWZXJzaW9uID8/IDApXG4gICAgICAgICAgICA6IDApID49IEhPT0tfUkVTVU1FX0RFRFVQX1ZFUlNJT04gfHxcbiAgICAgICAgICB3b3JsZC5jYXBhYmlsaXRpZXM/Lmhvb2tSZXN1bWVEZWR1cCA9PT0gdHJ1ZTtcbiAgICAgICAgY29uc3QgY2FuQ2xhaW1SZXN1bWUgPVxuICAgICAgICAgIGJhY2tlbmREZWR1cFN1cHBvcnRlZCAmJlxuICAgICAgICAgICF2MUNvbXBhdCAmJlxuICAgICAgICAgIGRlaHlkcmF0ZWRQYXlsb2FkIGluc3RhbmNlb2YgVWludDhBcnJheTtcblxuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAnd29ya2Zsb3cuaG9vay5yZXN1bWVfc3RyYXRlZ3knOiAnc2VxdWVudGlhbCcsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IHJlc3VtZUlkID0gY2FuQ2xhaW1SZXN1bWUgPyBnZW5lcmF0ZVJlc3VtZUlkKCkgOiB1bmRlZmluZWQ7XG4gICAgICAgIGNvbnN0IHBheWxvYWREaWdlc3QgPSBjYW5DbGFpbVJlc3VtZVxuICAgICAgICAgID8gYXdhaXQgY29tcHV0ZVJlc3VtZVBheWxvYWREaWdlc3QoZGVoeWRyYXRlZFBheWxvYWQpXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChyZXN1bWVJZCkge1xuICAgICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoeyAnd29ya2Zsb3cuaG9vay5yZXN1bWVfaWQnOiByZXN1bWVJZCB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlLWtleSBhbnkgXCJob29rIGNhbiBubyBsb25nZXIgYmUgcmVjZWl2ZWRcIiByZWplY3Rpb24gdG9cbiAgICAgICAgLy8gSG9va05vdEZvdW5kRXJyb3IoaG9vay50b2tlbikgc28gYC50b2tlbmAgbWF0Y2hlcyB0aGUgaGlzdG9yaWNhbFxuICAgICAgICAvLyBjb250cmFjdC4gVGhlIHNwZWNpZmljIGVycm9yIGRlcGVuZHMgb24gdGhlIFdvcmxkOlxuICAgICAgICAvLyAgIC0gYSBnZW51aW5lbHkgbWlzc2luZyBob29rIG1hcHMgdG8gSG9va05vdEZvdW5kRXJyb3IgKGtleWVkIG9uXG4gICAgICAgIC8vICAgICB0aGUgZXZlbnQgY29ycmVsYXRpb25JZCAvIGhvb2sgSUQpO1xuICAgICAgICAvLyAgIC0gYSB0ZXJtaW5hbCBydW4gb24gVmVyY2VsIHJlamVjdHMgaG9va19yZWNlaXZlZCB3aXRoIDQwNCwgd2hpY2hcbiAgICAgICAgLy8gICAgIHdvcmxkLXZlcmNlbCBtYXBzIHRvIEhvb2tOb3RGb3VuZEVycm9yO1xuICAgICAgICAvLyAgIC0gYSB0ZXJtaW5hbCBydW4gb24gd29ybGQtbG9jYWwgLyB3b3JsZC1wb3N0Z3JlcyByZWplY3RzIHdpdGhcbiAgICAgICAgLy8gICAgIFJ1bkV4cGlyZWRFcnJvci5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gQW4gRW50aXR5Q29uZmxpY3RFcnJvciAoSFRUUCA0MDkpIGlzIGRlbGliZXJhdGVseSBOT1QgcmUta2V5ZWQsXG4gICAgICAgIC8vIGJyZWFraW5nIHdpdGggdGhlIGhpc3RvcmljYWwgbWFwcGluZzogZXZlcnkgNDA5IHRoZSBiYWNrZW5kIGVtaXRzXG4gICAgICAgIC8vIG9uIHRoaXMgd3JpdGUgdG9kYXkgaXMgVFJBTlNJRU5UIOKAlCBhIHNsb3QgY29uZmxpY3QgdGhhdCBlc2NhcGVkIHRoZVxuICAgICAgICAvLyBzZXJ2ZXIncyBvd24gcmV0cnkgYnVkZ2V0IHVuZGVyIGNvbnRlbnRpb24sIG9yIGEgcmVzdW1lLWNsYWltIHJhY2VcbiAgICAgICAgLy8gbWlkLXJlc29sdXRpb24g4oCUIGFuZCBpdHMgdHJhbnNhY3Rpb24gY29tbWl0dGVkIG5vdGhpbmcuIFJlLWtleWluZ1xuICAgICAgICAvLyBpdCB0byBIb29rTm90Rm91bmRFcnJvciB0b2xkIHRoZSBjYWxsZXIgKGFuZCBhIHdlYmhvb2sgc2VuZGVyLCB2aWFcbiAgICAgICAgLy8gNDA0KSB0aGF0IGEgcmV0cnlhYmxlIGZhaWx1cmUgd2FzIHBlcm1hbmVudCwgc2lsZW50bHkgZHJvcHBpbmcgdGhlXG4gICAgICAgIC8vIHJlc3VtZS4gSXQgbm93IHN1cmZhY2VzIGFzLWlzOiByZXRyeWFibGUsIHdpdGggbm90aGluZyBjb21taXR0ZWQuXG4gICAgICAgIC8vIChBIDQyMiByZXN1bWVJZC1yZXVzZSBlcnJvciBsaWtld2lzZSBwYXNzZXMgdGhyb3VnaCB1bm1hcHBlZCDigJQgaXRcbiAgICAgICAgLy8gbWVhbnMgdGhlIGNhbGxlciByZXBsYXllZCBhIHJlc3VtZUlkIHdpdGggYSBkaWZmZXJlbnQgcGF5bG9hZCwgYW5kXG4gICAgICAgIC8vIGhpZGluZyB0aGF0IGJlaGluZCBcIm5vdCBmb3VuZFwiIHdvdWxkIG1hc2sgdGhlIGJ1Zy4pXG4gICAgICAgIGNvbnN0IGlzSG9va0dvbmVFcnJvciA9IChlcnI6IHVua25vd24pOiBib29sZWFuID0+XG4gICAgICAgICAgSG9va05vdEZvdW5kRXJyb3IuaXMoZXJyKSB8fCBSdW5FeHBpcmVkRXJyb3IuaXMoZXJyKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCB3b3JsZC5ldmVudHMuY3JlYXRlKFxuICAgICAgICAgICAgaG9vay5ydW5JZCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiAnaG9va19yZWNlaXZlZCcsXG4gICAgICAgICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICAgICAgY29ycmVsYXRpb25JZDogaG9vay5ob29rSWQsXG4gICAgICAgICAgICAgIGV2ZW50RGF0YToge1xuICAgICAgICAgICAgICAgIC4uLih2MUNvbXBhdCA/IHt9IDogeyB0b2tlbjogaG9vay50b2tlbiB9KSxcbiAgICAgICAgICAgICAgICBwYXlsb2FkOiBkZWh5ZHJhdGVkUGF5bG9hZCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHYxQ29tcGF0LFxuICAgICAgICAgICAgICAuLi4ocmVzdW1lSWQgJiYgcGF5bG9hZERpZ2VzdFxuICAgICAgICAgICAgICAgID8geyByZXN1bWVJZCwgcmVzdW1lUGF5bG9hZERpZ2VzdDogcGF5bG9hZERpZ2VzdCB9XG4gICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgaWYgKGlzSG9va0dvbmVFcnJvcihlcnIpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgSG9va05vdEZvdW5kRXJyb3IoaG9vay50b2tlbik7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgICAvLyBTdGFtcGVkIEFGVEVSIHRoZSB3cml0ZSByZXNvbHZlcyAoZW50cnktdGltZSBhdHRyaWJ1dGVzIGNhbm5vdCB0ZWxsXG4gICAgICAgIC8vIGFuIGF0dGVtcHRlZCByZXN1bWUgZnJvbSBhIGNvbW1pdHRlZCBvbmUpOiB0b2dldGhlciB3aXRoXG4gICAgICAgIC8vIEhvb2tXYWtlUHVibGlzaGVkIGJlbG93LCB0aGlzIGlzIHdoYXQgbWFrZXMgYSBzdHJhbmRlZCByZXN1bWUg4oCUIGFcbiAgICAgICAgLy8gY29tbWl0dGVkIGV2ZW50IHdob3NlIHdha2UgbmV2ZXIgd2VudCBvdXQgb3Igd2FzIG5ldmVyIGRlbGl2ZXJlZCDigJRcbiAgICAgICAgLy8gcXVlcnlhYmxlIGZyb20gdHJhY2VzLiBTZWUgdGhlIGFsZXJ0aW5nIG5vdGUgb24gSG9va1dha2VQdWJsaXNoZWQuXG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoQXR0cmlidXRlLkhvb2tSZXN1bWVDb21taXR0ZWQodHJ1ZSkpO1xuXG4gICAgICAgIC8vIFQxIG9mIHRoZSBUVFIgd2luZG93LiBTdGFtcGVkIGltbWVkaWF0ZWx5IGJlZm9yZSB0aGUgcHVibGlzaCBzb1xuICAgICAgICAvLyBgcHJvZHVjZXJfcHJlcGAgY292ZXJzIGV4YWN0bHkgdGhlIHdvcmsgYWJvdmUgaXQgKGhvb2sgbG9va3VwLCBrZXlcbiAgICAgICAgLy8gcmVzb2x1dGlvbiwgc2VyaWFsaXphdGlvbiwgYW5kIHRoZSBhd2FpdGVkIGhvb2tfcmVjZWl2ZWQgd3JpdGUsXG4gICAgICAgIC8vIHdoaWNoIGlzIGdlbnVpbmVseSBzZXJpYWwgaGVyZSkuXG4gICAgICAgIGNvbnN0IHF1ZXVlUHVibGlzaFJlcXVlc3RlZEF0TXMgPSBEYXRlLm5vdygpO1xuICAgICAgICBhd2FpdCBwdWJsaXNoSG9va1dha2VXaXRoUmV0cnkoXG4gICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgIHdvcmxkLnF1ZXVlKFxuICAgICAgICAgICAgICBxdWV1ZU5hbWUsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBydW5JZDogaG9vay5ydW5JZCxcbiAgICAgICAgICAgICAgICB0cmFjZUNhcnJpZXI6IHJlc3VtZUNvbnRleHQudHJhY2VDYXJyaWVyID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBob29rUmVzdW1lVGltaW5nOiB7XG4gICAgICAgICAgICAgICAgICByZXN1bWVSZXF1ZXN0ZWRBdE1zLFxuICAgICAgICAgICAgICAgICAgcXVldWVQdWJsaXNoUmVxdWVzdGVkQXRNcyxcbiAgICAgICAgICAgICAgICAgIHN0cmF0ZWd5OiAnc2VxdWVudGlhbCcsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSBzYXRpc2ZpZXMgV29ya2Zsb3dJbnZva2VQYXlsb2FkLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLi4ucXVldWVPcHRpb25zLFxuICAgICAgICAgICAgICAgIC8vIERlZHVwIHJldHJpZWQgcHVibGlzaGVzIHdob3NlIHJlc3BvbnNlIHdhcyBsb3N0OiBhXG4gICAgICAgICAgICAgICAgLy8gZHVwbGljYXRlIHdha2UgaXMgaGFybWxlc3MgZm9yIGNvcnJlY3RuZXNzIChkZXRlcm1pbmlzdGljXG4gICAgICAgICAgICAgICAgLy8gcmVwbGF5KSBidXQgY29zdHMgYSBmdWxsIHJlcGxheSBvZiB0aGUgcnVuLCBhbmQgdGhlIHF1ZXVlXG4gICAgICAgICAgICAgICAgLy8gYWNjZXB0cyBhIHJlcGVhdGVkIGlkZW1wb3RlbmN5IGtleSBieSBkZWxpdmVyaW5nIG9ubHkgb25lXG4gICAgICAgICAgICAgICAgLy8gb2YgdGhlIG1lc3NhZ2VzLiBDbGFpbS1sZXNzIHdyaXRlcyBoYXZlIG5vIHJlc3VtZUlkIGFuZFxuICAgICAgICAgICAgICAgIC8vIGtlZXAgdGhlIHByZXZpb3VzIGJlaGF2aW9yLlxuICAgICAgICAgICAgICAgIC4uLihyZXN1bWVJZCA/IHsgaWRlbXBvdGVuY3lLZXk6IGBob29rLSR7cmVzdW1lSWR9YCB9IDoge30pLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApLFxuICAgICAgICAgIHdvcmxkLmlzRGVwbG95bWVudFVuYXZhaWxhYmxlRXJyb3I/LmJpbmQod29ybGQpXG4gICAgICAgICk7XG4gICAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoQXR0cmlidXRlLkhvb2tXYWtlUHVibGlzaGVkKHRydWUpKTtcblxuICAgICAgICByZXR1cm4gYXNMYXp5TWV0YWRhdGFIb29rKGhvb2spIHNhdGlzZmllcyBSZXN1bWVkSG9vaztcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgICAuLi5BdHRyaWJ1dGUuSG9va1Rva2VuKFxuICAgICAgICAgICAgdHlwZW9mIHRva2VuT3JIb29rID09PSAnc3RyaW5nJyA/IHRva2VuT3JIb29rIDogdG9rZW5Pckhvb2sudG9rZW5cbiAgICAgICAgICApLFxuICAgICAgICAgIC4uLkF0dHJpYnV0ZS5Ib29rRm91bmQoZmFsc2UpLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBSZXN1bWVzIGEgd2ViaG9vayBieSBzZW5kaW5nIGEge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9SZXF1ZXN0IHwgUmVxdWVzdH1cbiAqIG9iamVjdCB0byBhIGhvb2sgaWRlbnRpZmllZCBieSBpdHMgdG9rZW4uXG4gKlxuICogVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgZXh0ZXJuYWxseSAoZS5nLiwgZnJvbSBhbiBBUEkgcm91dGUgb3Igc2VydmVyIGFjdGlvbilcbiAqIHRvIHNlbmQgYSByZXF1ZXN0IHRvIGEgd2ViaG9vayBhbmQgcmVzdW1lIHRoZSBhc3NvY2lhdGVkIHdvcmtmbG93IHJ1bi5cbiAqXG4gKiBAcGFyYW0gdG9rZW4gLSBUaGUgdW5pcXVlIHRva2VuIGlkZW50aWZ5aW5nIHRoZSBob29rXG4gKiBAcGFyYW0gcmVxdWVzdCAtIFRoZSByZXF1ZXN0IHRvIHNlbmQgdG8gdGhlIGhvb2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXNwb25zZVxuICogQHRocm93cyBFcnJvciBpZiB0aGUgaG9vayBpcyBub3QgZm91bmQgb3IgaWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIHByb2Nlc3NcbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYHRzXG4gKiAvLyBJbiBhbiBBUEkgcm91dGVcbiAqIGltcG9ydCB7IHJlc3VtZVdlYmhvb2sgfSBmcm9tICdAd29ya2Zsb3cvY29yZS9ydW50aW1lJztcbiAqXG4gKiBleHBvcnQgYXN5bmMgZnVuY3Rpb24gUE9TVChyZXF1ZXN0OiBSZXF1ZXN0KSB7XG4gKiAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxdWVzdC51cmwpO1xuICogICBjb25zdCB0b2tlbiA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCd0b2tlbicpO1xuICpcbiAqICAgaWYgKCF0b2tlbikge1xuICogICAgIHJldHVybiBuZXcgUmVzcG9uc2UoJ01pc3NpbmcgdG9rZW4nLCB7IHN0YXR1czogNDAwIH0pO1xuICogICB9XG4gKlxuICogICB0cnkge1xuICogICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgcmVzdW1lV2ViaG9vayh0b2tlbiwgcmVxdWVzdCk7XG4gKiAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICogICB9IGNhdGNoIChlcnJvcikge1xuICogICAgIHJldHVybiBuZXcgUmVzcG9uc2UoJ1dlYmhvb2sgbm90IGZvdW5kJywgeyBzdGF0dXM6IDQwNCB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXN1bWVXZWJob29rKFxuICB0b2tlbjogc3RyaW5nLFxuICByZXF1ZXN0OiBSZXF1ZXN0XG4pOiBQcm9taXNlPFJlc3BvbnNlPiB7XG4gIC8vIFQwIG9mIHRoZSBob29rLXJlc3VtZSBUVFIgd2luZG93LiBFdmVyeXRoaW5nIGJlbG93ICh0aGUgYnktdG9rZW4gbG9va3VwLFxuICAvLyB0aGUgcnVuLWtleSByZXNvbHV0aW9uIGl0IG1heSB0cmlnZ2VyLCBhbmQgdGhlIGByZXNwb25kV2l0aGAgc2V0dXApIGlzXG4gIC8vIHJlYWwgcHJvZHVjZXItc2lkZSBsYXRlbmN5IG9uIHRoaXMgcGF0aCwgc28gdGhlIHdpbmRvdyBoYXMgdG8gb3BlbiBoZXJlXG4gIC8vIGFuZCBub3QgaW5zaWRlIGByZXN1bWVIb29rSW1wbGA7IG90aGVyd2lzZSB3ZWJob29rIHJlc3VtZXMgd291bGQgcmVwb3J0IGFcbiAgLy8gc3lzdGVtYXRpY2FsbHkgc2hvcnRlciB0b3RhbCB0aGFuIGByZXN1bWVIb29rYCBvbmVzIGludG8gdGhlIHNhbWUgbWV0cmljLlxuICBjb25zdCByZXN1bWVSZXF1ZXN0ZWRBdE1zID0gRGF0ZS5ub3coKTtcbiAgY29uc3Qgd29ybGQgPSBhd2FpdCBnZXRXb3JsZExhenkoKTtcbiAgY29uc3QgeyBob29rLCBtZXRhZGF0YUVuY3J5cHRpb25LZXkgfSA9IHdpdGhMYXp5TWV0YWRhdGEoXG4gICAgYXdhaXQgd29ybGQuaG9va3MuZ2V0QnlUb2tlbih0b2tlbilcbiAgKTtcblxuICAvLyBPbmx5IHdlYmhvb2tzIGNhbiBiZSByZXN1bWVkIHZpYSB0aGUgcHVibGljIGVuZHBvaW50LlxuICAvLyBJZiB0aGUgaG9vayB3YXMgY3JlYXRlZCB2aWEgY3JlYXRlSG9vaygpIChpc1dlYmhvb2sgIT09IHRydWUpLFxuICAvLyB0aHJvdyB0aGUgc2FtZSBcIm5vdCBmb3VuZFwiIGVycm9yIHRoZSB3b3JsZCB3b3VsZCB0aHJvdyBmb3IgYSBtaXNzaW5nXG4gIC8vIHRva2VuLiBUaGlzIHByZXZlbnRzIGxlYWtpbmcgdGhhdCB0aGUgdG9rZW4gaXMgdmFsaWQuXG4gIGlmIChob29rLmlzV2ViaG9vayA9PT0gZmFsc2UpIHtcbiAgICB0aHJvdyBuZXcgSG9va05vdEZvdW5kRXJyb3IodG9rZW4pO1xuICB9XG5cbiAgLy8gYHJlc3BvbmRXaXRoYCBsaXZlcyBpbiB0aGUgaG9vaydzIG1ldGFkYXRhLCBzbyB0aGlzIGlzIHRoZSBvbmUgcmVzdW1lIHBhdGhcbiAgLy8gdGhhdCBoYXMgdG8gcmVhZCBpdC4gT25seSBhIHdlYmhvb2sgdGhhdCBhY3R1YWxseSBzdG9yZWQgbWV0YWRhdGEgcGF5cyBmb3JcbiAgLy8gdGhlIGh5ZHJhdGlvbjogdGhlIGNvbW1vbiBkZWZhdWx0IHdlYmhvb2sg4oCUIGNyZWF0ZVdlYmhvb2soKSB3aXRoIG5vXG4gIC8vIGByZXNwb25kV2l0aGAg4oCUIHN0b3JlcyBub25lLCBzbyB0aGlzIHJlc29sdmVzIGB1bmRlZmluZWRgIHdpdGggbm8gfjM1MG1zXG4gIC8vIGBydW4ta2V5YCBBUEkgcm91bmQgdHJpcCwgYW5kIGhhbmRzIGByZXN1bWVIb29rYCBubyBrZXksIGxlYXZpbmcgaXQgZnJlZSB0b1xuICAvLyBzZWFsIHRoZSBwYXlsb2FkIHRvIHRoZSBydW4ncyBwdWJsaXNoZWQgcHVibGljIGtleSBpbnN0ZWFkLlxuICBjb25zdCBtZXRhZGF0YSA9IGF3YWl0IGhvb2subWV0YWRhdGE7XG5cbiAgbGV0IHJlc3BvbnNlOiBSZXNwb25zZSB8IHVuZGVmaW5lZDtcbiAgbGV0IHJlc3BvbnNlUmVhZGFibGU6IFJlYWRhYmxlU3RyZWFtPFJlc3BvbnNlPiB8IHVuZGVmaW5lZDtcbiAgaWYgKG1ldGFkYXRhICYmIHR5cGVvZiBtZXRhZGF0YSA9PT0gJ29iamVjdCcgJiYgJ3Jlc3BvbmRXaXRoJyBpbiBtZXRhZGF0YSkge1xuICAgIGlmIChtZXRhZGF0YS5yZXNwb25kV2l0aCA9PT0gJ21hbnVhbCcpIHtcbiAgICAgIGNvbnN0IHsgcmVhZGFibGUsIHdyaXRhYmxlIH0gPSBuZXcgVHJhbnNmb3JtU3RyZWFtPFJlc3BvbnNlLCBSZXNwb25zZT4oKTtcbiAgICAgIHJlc3BvbnNlUmVhZGFibGUgPSByZWFkYWJsZTtcblxuICAgICAgLy8gVGhlIHJlcXVlc3QgaW5zdGFuY2UgaW5jbHVkZXMgdGhlIHdyaXRhYmxlIHN0cmVhbSB3aGljaCB3aWxsIGJlIHVzZWRcbiAgICAgIC8vIHRvIHdyaXRlIHRoZSByZXNwb25zZSB0byB0aGUgY2xpZW50IGZyb20gd2l0aGluIHRoZSB3b3JrZmxvdyBydW5cbiAgICAgIChyZXF1ZXN0IGFzIGFueSlbV0VCSE9PS19SRVNQT05TRV9XUklUQUJMRV0gPSB3cml0YWJsZTtcbiAgICB9IGVsc2UgaWYgKG1ldGFkYXRhLnJlc3BvbmRXaXRoIGluc3RhbmNlb2YgUmVzcG9uc2UpIHtcbiAgICAgIHJlc3BvbnNlID0gbWV0YWRhdGEucmVzcG9uZFdpdGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBXb3JrZmxvd1J1bnRpbWVFcnJvcihcbiAgICAgICAgYEludmFsaWQgXFxgcmVzcG9uZFdpdGhcXGAgdmFsdWU6ICR7bWV0YWRhdGEucmVzcG9uZFdpdGh9YCxcbiAgICAgICAgeyBzbHVnOiBFUlJPUl9TTFVHUy5XRUJIT09LX0lOVkFMSURfUkVTUE9ORF9XSVRIX1ZBTFVFIH1cbiAgICAgICk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIE5vIGByZXNwb25kV2l0aGAgdmFsdWUgaW1wbGllcyB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZiByZXR1cm5pbmcgYSAyMDJcbiAgICByZXNwb25zZSA9IG5ldyBSZXNwb25zZShudWxsLCB7IHN0YXR1czogMjAyIH0pO1xuICB9XG5cbiAgLy8gYGhvb2tgIHdhcyBqdXN0IGZldGNoZWQgYnkgdG9rZW4gYWJvdmUsIHNvIGl0cyByZXNwb25zZS1vbmx5XG4gIC8vIGByZXN1bWVDYXBhYmlsaXRpZXNgIHJlZmxlY3RzIHRoZSBsaXZlIGJhY2tlbmQuIENhbGwgdGhlIGludGVybmFsXG4gIC8vIGltcGxlbWVudGF0aW9uIHdpdGggdGhlIGZyZXNoIGF0dGVzdGF0aW9uIHNvIHRoZSB3cml0ZSdzIGlkZW1wb3RlbmN5IGNsYWltXG4gIC8vIHN0YXlzIGF2YWlsYWJsZSB3aXRob3V0IGEgc2Vjb25kIEdFVC4gKFRoZSBwdWJsaWMgYHJlc3VtZUhvb2tgIG5ldmVyIHNldHNcbiAgLy8gdGhpcywgc28gYSBjYWxsZXIgY2Fubm90IGZvcmdlIGl0LilcbiAgLy9cbiAgLy8gUmV1c2Ugd2hhdGV2ZXIga2V5IHRoZSBtZXRhZGF0YSBoeWRyYXRpb24gYWJvdmUgcmVzb2x2ZWQgKGB1bmRlZmluZWRgIHdoZW5cbiAgLy8gaXQgcmVzb2x2ZWQgbm9uZSkgc28gYSBtZXRhZGF0YS1iZWFyaW5nIHdlYmhvb2sgcmVzb2x2ZXMgdGhlIHJ1biBrZXlcbiAgLy8gZXhhY3RseSBvbmNlIGVuZCB0byBlbmQuXG4gIGF3YWl0IHJlc3VtZUhvb2tJbXBsKFxuICAgIGhvb2ssXG4gICAgcmVxdWVzdCxcbiAgICBtZXRhZGF0YUVuY3J5cHRpb25LZXkoKSxcbiAgICB0cnVlLFxuICAgIHJlc3VtZVJlcXVlc3RlZEF0TXNcbiAgKTtcblxuICBpZiAocmVzcG9uc2VSZWFkYWJsZSkge1xuICAgIC8vIFdhaXQgZm9yIHRoZSByZWFkYWJsZSBzdHJlYW0gdG8gZW1pdCBvbmUgY2h1bmssXG4gICAgLy8gd2hpY2ggaXMgdGhlIGBSZXNwb25zZWAgb2JqZWN0XG4gICAgY29uc3QgcmVhZGVyID0gcmVzcG9uc2VSZWFkYWJsZS5nZXRSZWFkZXIoKTtcbiAgICBjb25zdCBjaHVuayA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgaWYgKGNodW5rLnZhbHVlKSB7XG4gICAgICByZXNwb25zZSA9IGNodW5rLnZhbHVlO1xuICAgIH1cbiAgICByZWFkZXIuY2FuY2VsKCk7XG4gIH1cblxuICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKCdXb3JrZmxvdyBydW4gZGlkIG5vdCBzZW5kIGEgcmVzcG9uc2UnLCB7XG4gICAgICBzbHVnOiBFUlJPUl9TTFVHUy5XRUJIT09LX1JFU1BPTlNFX05PVF9TRU5ULFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHJlc3BvbnNlO1xufVxuIl19
|