@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,27 +1,513 @@
|
|
|
1
|
+
import { globalSingleton } from '@workflow/utils';
|
|
2
|
+
import { envNumber } from '@workflow/world';
|
|
3
|
+
import { runtimeLogger } from '../logger.js';
|
|
1
4
|
// Maximum number of queue delivery attempts before the handler gives up and
|
|
2
5
|
// gracefully fails the run/step. This must be bounded under the VQS message
|
|
3
6
|
// max visibility window (24 hours) so that our handler-side failure path
|
|
4
7
|
// reliably executes before VQS expires the message.
|
|
5
8
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// The effective wall-clock survival depends on the per-redelivery backoff: the
|
|
10
|
+
// `retry-after` the handler returns (see world-vercel
|
|
11
|
+
// `getHandlerErrorRetryAfterSeconds`) fed through VQS `calculateBackoffDelay`.
|
|
12
|
+
// VQS uses our value for the first 32 attempts (clamped to [5s, 900s]) then
|
|
13
|
+
// applies its own exponential growth, every hop hard-capped at the SQS limit
|
|
14
|
+
// of 900s. With the backoff ramping toward that 900s ceiling (reached by
|
|
15
|
+
// ~delivery 11), 48 attempts span roughly 9–10 hours of wall-clock (~35,000s),
|
|
16
|
+
// comfortably under the 24-hour message-visibility limit so the failure path
|
|
17
|
+
// runs before the message expires. (A flatter, low-capped backoff exhausts the
|
|
18
|
+
// budget in only a few hours, failing otherwise-healthy runs during a transient
|
|
19
|
+
// backend outage; conversely, spanning the full 24h window would require a
|
|
20
|
+
// substantially higher cap here, not a higher per-hop ceiling, since VQS
|
|
21
|
+
// clamps every hop at 900s.)
|
|
13
22
|
export const MAX_QUEUE_DELIVERIES = 48;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
23
|
+
/**
|
|
24
|
+
* Effective max queue deliveries. Override via `WORKFLOW_MAX_QUEUE_DELIVERIES`.
|
|
25
|
+
*/
|
|
26
|
+
export function getMaxQueueDeliveries() {
|
|
27
|
+
// Only ever lower the delivery budget. The default is calibrated so the
|
|
28
|
+
// handler-side failure path runs before VQS message-retention expiry (see
|
|
29
|
+
// MAX_QUEUE_DELIVERIES above); a higher value would bypass that invariant and
|
|
30
|
+
// let a bad deployment redeliver until queue expiry instead of recording
|
|
31
|
+
// run_fail. `max` clamps a too-high override back down to the safe default.
|
|
32
|
+
return envNumber('WORKFLOW_MAX_QUEUE_DELIVERIES', MAX_QUEUE_DELIVERIES, {
|
|
33
|
+
integer: true,
|
|
34
|
+
min: 1,
|
|
35
|
+
max: MAX_QUEUE_DELIVERIES,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Default maximum time allowed for the *replay* portion of a single workflow
|
|
40
|
+
* handler invocation (in ms). This budget only covers deterministic-replay
|
|
41
|
+
* and workflow-VM execution between step boundaries. Inline step bodies
|
|
42
|
+
* (`"use step"` functions invoked via `executeStep`) do NOT count against
|
|
43
|
+
* it. Step bodies are bounded separately by the platform's function
|
|
44
|
+
* `maxDuration` (e.g. 800s on Vercel Pro Fluid) and `NO_INLINE_REPLAY_AFTER_MS`.
|
|
45
|
+
*
|
|
46
|
+
* If the non-step ("replay") time within a single invocation exceeds this
|
|
47
|
+
* budget, the handler rejects so the queue can retry. After
|
|
48
|
+
* `REPLAY_TIMEOUT_MAX_RETRIES` exhausted attempts the run is failed with
|
|
49
|
+
* `RUN_ERROR_CODES.REPLAY_TIMEOUT`.
|
|
50
|
+
*
|
|
51
|
+
* Note that on Vercel Hobby (standard functions), the platform `maxDuration`
|
|
52
|
+
* is 60s, well below this budget, so the platform SIGTERM will fire first
|
|
53
|
+
* and the queue will re-deliver until the visibility window expires. With
|
|
54
|
+
* Fluid Compute on Hobby the per-function ceiling rises to 300s, still
|
|
55
|
+
* under the default budget.
|
|
56
|
+
*
|
|
57
|
+
* Override via the `WORKFLOW_REPLAY_TIMEOUT_MS` env var (clamped to
|
|
58
|
+
* `MIN_REPLAY_TIMEOUT_MS`..`MAX_REPLAY_TIMEOUT_MS`).
|
|
59
|
+
*/
|
|
21
60
|
export const REPLAY_TIMEOUT_MS = 240_000;
|
|
61
|
+
/** Lower bound for the replay-timeout env var override. */
|
|
62
|
+
export const MIN_REPLAY_TIMEOUT_MS = 30_000;
|
|
63
|
+
/**
|
|
64
|
+
* Upper bound for the replay-timeout env var override. 780s leaves ≥20s of
|
|
65
|
+
* headroom under Vercel Pro Fluid's 800s function ceiling so the handler
|
|
66
|
+
* can write `run_failed` before SIGTERM.
|
|
67
|
+
*/
|
|
68
|
+
export const MAX_REPLAY_TIMEOUT_MS = 780_000;
|
|
69
|
+
// Track which raw env var values we've already warned about so the warning
|
|
70
|
+
// log only fires once per process (the function may be called many times).
|
|
71
|
+
//
|
|
72
|
+
// On `globalThis` rather than at module scope so "once per process" survives
|
|
73
|
+
// bundling: this package is compiled into the host application's server build
|
|
74
|
+
// once per bundler layer, and per-copy sets warn once per layer instead.
|
|
75
|
+
const warned = globalSingleton('@workflow/core//envWarnings', 1, () => ({
|
|
76
|
+
replayTimeoutValues: new Set(),
|
|
77
|
+
maxInlineStepsValues: new Set(),
|
|
78
|
+
maxEventsValues: new Set(),
|
|
79
|
+
}));
|
|
80
|
+
function warnOnce(raw, message, data) {
|
|
81
|
+
if (warned.replayTimeoutValues.has(raw))
|
|
82
|
+
return;
|
|
83
|
+
warned.replayTimeoutValues.add(raw);
|
|
84
|
+
runtimeLogger.warn(message, data);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Resolve the effective replay-timeout budget for the current process.
|
|
88
|
+
*
|
|
89
|
+
* Reads `process.env.WORKFLOW_REPLAY_TIMEOUT_MS` lazily so tests and
|
|
90
|
+
* deployments can override per invocation. Invalid / out-of-range values
|
|
91
|
+
* fall back to a safe value (no throw: the env var is an escape hatch,
|
|
92
|
+
* not a hard requirement) and emit a one-time warning so misconfiguration
|
|
93
|
+
* is observable.
|
|
94
|
+
*/
|
|
95
|
+
export function getReplayTimeoutMs() {
|
|
96
|
+
const raw = process.env.WORKFLOW_REPLAY_TIMEOUT_MS;
|
|
97
|
+
if (!raw)
|
|
98
|
+
return REPLAY_TIMEOUT_MS;
|
|
99
|
+
const parsed = Number(raw);
|
|
100
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
101
|
+
warnOnce(raw, 'Ignoring WORKFLOW_REPLAY_TIMEOUT_MS: not a positive finite number; using default', { raw, defaultMs: REPLAY_TIMEOUT_MS });
|
|
102
|
+
return REPLAY_TIMEOUT_MS;
|
|
103
|
+
}
|
|
104
|
+
if (parsed < MIN_REPLAY_TIMEOUT_MS) {
|
|
105
|
+
warnOnce(raw, 'WORKFLOW_REPLAY_TIMEOUT_MS below minimum; clamped', {
|
|
106
|
+
raw,
|
|
107
|
+
clampedMs: MIN_REPLAY_TIMEOUT_MS,
|
|
108
|
+
minMs: MIN_REPLAY_TIMEOUT_MS,
|
|
109
|
+
});
|
|
110
|
+
return MIN_REPLAY_TIMEOUT_MS;
|
|
111
|
+
}
|
|
112
|
+
if (parsed > MAX_REPLAY_TIMEOUT_MS) {
|
|
113
|
+
warnOnce(raw, 'WORKFLOW_REPLAY_TIMEOUT_MS above maximum; clamped', {
|
|
114
|
+
raw,
|
|
115
|
+
clampedMs: MAX_REPLAY_TIMEOUT_MS,
|
|
116
|
+
maxMs: MAX_REPLAY_TIMEOUT_MS,
|
|
117
|
+
});
|
|
118
|
+
return MAX_REPLAY_TIMEOUT_MS;
|
|
119
|
+
}
|
|
120
|
+
return parsed;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Reset the warn-once cache. Test-only: exported so unit tests can
|
|
124
|
+
* exercise the warn path repeatedly without sharing state.
|
|
125
|
+
*
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
export function _resetReplayTimeoutWarnCacheForTests() {
|
|
129
|
+
warned.replayTimeoutValues.clear();
|
|
130
|
+
}
|
|
22
131
|
// Number of queue delivery attempts to allow before permanently failing a run
|
|
23
132
|
// due to a replay timeout. On attempts 1 through this value, the timeout
|
|
24
|
-
// handler
|
|
133
|
+
// handler rejects without writing run_failed so the queue retries the message.
|
|
25
134
|
// On the next attempt the run is marked as failed.
|
|
26
135
|
export const REPLAY_TIMEOUT_MAX_RETRIES = 3;
|
|
27
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Effective replay-timeout retry budget. Override via
|
|
138
|
+
* `WORKFLOW_REPLAY_TIMEOUT_MAX_RETRIES`.
|
|
139
|
+
*/
|
|
140
|
+
export function getReplayTimeoutMaxRetries() {
|
|
141
|
+
return envNumber('WORKFLOW_REPLAY_TIMEOUT_MAX_RETRIES', REPLAY_TIMEOUT_MAX_RETRIES, { integer: true });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Default maximum number of steps the owned-inline path runs inline (in
|
|
145
|
+
* parallel) per suspension. The rest are queued to background handlers. Each
|
|
146
|
+
* inline step is created lazily (its `step_created` is folded into the
|
|
147
|
+
* `step_started` that `executeStep` sends), so inlining N steps saves N queue
|
|
148
|
+
* round-trips for a `Promise.all`-style fan-out. `1` reproduces the
|
|
149
|
+
* single-inline-step behavior exactly (useful kill-switch).
|
|
150
|
+
*
|
|
151
|
+
* Override via `WORKFLOW_MAX_INLINE_STEPS` (clamped to
|
|
152
|
+
* `MIN_MAX_INLINE_STEPS`..`MAX_MAX_INLINE_STEPS`).
|
|
153
|
+
*/
|
|
154
|
+
export const MAX_INLINE_STEPS = 3;
|
|
155
|
+
/** Lower bound for the inline-steps env override (1 = single inline step). */
|
|
156
|
+
export const MIN_MAX_INLINE_STEPS = 1;
|
|
157
|
+
/**
|
|
158
|
+
* Upper bound for the inline-steps env override. Inline bodies run in parallel
|
|
159
|
+
* within one function invocation, so this caps memory/CPU fan-out per handler.
|
|
160
|
+
*/
|
|
161
|
+
export const MAX_MAX_INLINE_STEPS = 16;
|
|
162
|
+
/**
|
|
163
|
+
* Resolve the effective max number of inline steps for the current process.
|
|
164
|
+
*
|
|
165
|
+
* Reads `process.env.WORKFLOW_MAX_INLINE_STEPS` lazily so tests and
|
|
166
|
+
* deployments can override per invocation. Invalid / out-of-range values fall
|
|
167
|
+
* back to a safe value (no throw: the env var is an escape hatch) and emit a
|
|
168
|
+
* one-time warning so misconfiguration is observable.
|
|
169
|
+
*/
|
|
170
|
+
export function getMaxInlineSteps() {
|
|
171
|
+
const raw = process.env.WORKFLOW_MAX_INLINE_STEPS;
|
|
172
|
+
if (!raw)
|
|
173
|
+
return MAX_INLINE_STEPS;
|
|
174
|
+
const parsed = Number(raw);
|
|
175
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
176
|
+
if (!warned.maxInlineStepsValues.has(raw)) {
|
|
177
|
+
warned.maxInlineStepsValues.add(raw);
|
|
178
|
+
runtimeLogger.warn('Ignoring WORKFLOW_MAX_INLINE_STEPS: not a positive integer; using default', { raw, defaultValue: MAX_INLINE_STEPS });
|
|
179
|
+
}
|
|
180
|
+
return MAX_INLINE_STEPS;
|
|
181
|
+
}
|
|
182
|
+
if (parsed < MIN_MAX_INLINE_STEPS)
|
|
183
|
+
return MIN_MAX_INLINE_STEPS;
|
|
184
|
+
if (parsed > MAX_MAX_INLINE_STEPS) {
|
|
185
|
+
if (!warned.maxInlineStepsValues.has(raw)) {
|
|
186
|
+
warned.maxInlineStepsValues.add(raw);
|
|
187
|
+
runtimeLogger.warn('WORKFLOW_MAX_INLINE_STEPS above maximum; clamped', {
|
|
188
|
+
raw,
|
|
189
|
+
clampedValue: MAX_MAX_INLINE_STEPS,
|
|
190
|
+
maxValue: MAX_MAX_INLINE_STEPS,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return MAX_MAX_INLINE_STEPS;
|
|
194
|
+
}
|
|
195
|
+
return parsed;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Upper bound on the serialized step input that resilient step dispatch will
|
|
199
|
+
* inline into the queue message's `stepInput`.
|
|
200
|
+
*
|
|
201
|
+
* Vercel Queues has no hard message-size cap (bodies above its ~256 KB
|
|
202
|
+
* inline threshold transparently spill to S3-backed storage), so this bound
|
|
203
|
+
* is a cost/latency choice, not a rejection guard: the message also carries
|
|
204
|
+
* the runId, stepId, stepName, and trace carrier alongside CBOR framing
|
|
205
|
+
* overhead, and staying under the queue's inline threshold keeps step
|
|
206
|
+
* messages on its fast inline path instead of paying an S3 store+fetch
|
|
207
|
+
* double-hop for bytes that already live in the event log. Above this size
|
|
208
|
+
* the dispatch falls back to the sequential path (`step_created` write, then
|
|
209
|
+
* a payload-less queue message).
|
|
210
|
+
*/
|
|
211
|
+
export const MAX_RESILIENT_STEP_INPUT_BYTES = 128 * 1024;
|
|
212
|
+
/**
|
|
213
|
+
* Whether resilient step dispatch is enabled: the suspension handler
|
|
214
|
+
* parallelizes each newly created step's `step_created` event write with its
|
|
215
|
+
* step-execution queue publish, carrying the serialized step input in the
|
|
216
|
+
* queue message (`stepInput`) so the consumer can idempotently re-ensure the
|
|
217
|
+
* event if the direct write failed transiently. Mirrors the resilient start
|
|
218
|
+
* (`runInput`) pattern (and the legacy lazy hook resume's `hookInput`, which
|
|
219
|
+
* current producers no longer send).
|
|
220
|
+
*
|
|
221
|
+
* **Off by default.** Enable via `WORKFLOW_RESILIENT_STEP_DISPATCH=1`.
|
|
222
|
+
*
|
|
223
|
+
* The queue publish races the create's verdict, and a create can come back
|
|
224
|
+
* refused: as a duplicate this replay should stop pursuing, or as a stale
|
|
225
|
+
* write on a World that refuses rather than reports. Either way the message
|
|
226
|
+
* carrying the payload is already out, so the consumer can materialize a step
|
|
227
|
+
* whose create was refused, and nothing orders the verdict before the
|
|
228
|
+
* consumer's redelivery re-ensure. Enabling this trades that window for the
|
|
229
|
+
* latency the parallel publish saves.
|
|
230
|
+
*/
|
|
231
|
+
export function isResilientStepDispatchEnabled() {
|
|
232
|
+
return process.env.WORKFLOW_RESILIENT_STEP_DISPATCH === '1';
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Whether batched event transitions are enabled: the suspension handler folds
|
|
236
|
+
* a clean fan-out's `step_created` + `wait_created` writes into one
|
|
237
|
+
* `world.events.createBatch` call (one durable write, per-event outcomes)
|
|
238
|
+
* instead of one write per event. Only engages when the World implements the
|
|
239
|
+
* optional `events.createBatch` AND the run is on slot identity
|
|
240
|
+
* (specVersion >= 6) AND the suspension carries no attribute/hook writes and
|
|
241
|
+
* no resilient step dispatch. Everything else keeps the single-event path
|
|
242
|
+
* byte-for-byte.
|
|
243
|
+
*
|
|
244
|
+
* Reads `process.env.WORKFLOW_BATCH_TRANSITIONS` lazily. Default **ON**;
|
|
245
|
+
* disabled only by an explicit `'0'` / `'false'` (case-insensitive), the
|
|
246
|
+
* operator escape hatch that restores the exact prior one-write-per-event
|
|
247
|
+
* path, mirroring `WORKFLOW_TURBO`'s kill-switch shape.
|
|
248
|
+
*/
|
|
249
|
+
export function isBatchTransitionsEnabled() {
|
|
250
|
+
const raw = process.env.WORKFLOW_BATCH_TRANSITIONS;
|
|
251
|
+
if (raw === undefined || raw === '')
|
|
252
|
+
return true;
|
|
253
|
+
return !(raw === '0' || raw.toLowerCase() === 'false');
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Ceiling on events per `createBatch` call from the batched fan-out fold.
|
|
257
|
+
* Mirrors the server's transaction budgets with a comfortable margin: each
|
|
258
|
+
* fan-out event costs 2 transaction items server-side (entity + event row)
|
|
259
|
+
* against the 100-item DynamoDB cap, and inline payloads count against a
|
|
260
|
+
* 768 KB byte budget, so 32 events stays well under both, and a fan-out larger
|
|
261
|
+
* than this commits in successive batches (split batches lose
|
|
262
|
+
* cross-batch atomicity, which is exactly today's per-event-write crash
|
|
263
|
+
* surface, and every batch still converges on retry via per-event 409s).
|
|
264
|
+
*/
|
|
265
|
+
export const MAX_BATCH_FANOUT_EVENTS = 32;
|
|
266
|
+
/**
|
|
267
|
+
* Optional client-side override for the server-supplied per-run event ceiling.
|
|
268
|
+
* When set to a positive integer, the runtime clamps the server's limit *down*
|
|
269
|
+
* to this value (never raises it) so enforcement can be exercised without a
|
|
270
|
+
* server-side change. `undefined` (unset) ⇒ use the server value as-is.
|
|
271
|
+
*
|
|
272
|
+
* Reads `process.env.WORKFLOW_MAX_EVENTS_OVERRIDE` lazily so tests and
|
|
273
|
+
* deployments can override per invocation. Invalid values fall back to unset
|
|
274
|
+
* (no throw: the env var is an escape hatch) and emit a one-time warning.
|
|
275
|
+
*/
|
|
276
|
+
export function getMaxEventsOverride() {
|
|
277
|
+
const raw = process.env.WORKFLOW_MAX_EVENTS_OVERRIDE;
|
|
278
|
+
if (!raw)
|
|
279
|
+
return undefined;
|
|
280
|
+
const parsed = Number(raw);
|
|
281
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
282
|
+
if (!warned.maxEventsValues.has(raw)) {
|
|
283
|
+
warned.maxEventsValues.add(raw);
|
|
284
|
+
runtimeLogger.warn('Ignoring WORKFLOW_MAX_EVENTS_OVERRIDE: not a positive integer; using server limit', { raw });
|
|
285
|
+
}
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
return parsed;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Whether optimistic inline step start is enabled. When on, the owned-inline
|
|
292
|
+
* path begins running a brand-new step's body *before* its lazy `step_started`
|
|
293
|
+
* network call resolves (the input is already known locally), awaiting the
|
|
294
|
+
* `step_started` only before the terminal write.
|
|
295
|
+
*
|
|
296
|
+
* This can run a step body more than once when handlers race for the same
|
|
297
|
+
* step's create-claim: both run the body before one wins. That is unsafe for
|
|
298
|
+
* steps with non-idempotent side effects; in particular, two concurrent runs
|
|
299
|
+
* of a step that writes to the workflow stream (e.g. an AI agent streaming
|
|
300
|
+
* tokens) can interleave and corrupt the stream data. So the optimization is
|
|
301
|
+
* **off by default** and must be explicitly opted into per deployment.
|
|
302
|
+
*
|
|
303
|
+
* Reads `process.env.WORKFLOW_OPTIMISTIC_INLINE_START` lazily. Default OFF;
|
|
304
|
+
* enabled only by an explicit `'1'` / `'true'`.
|
|
305
|
+
*/
|
|
306
|
+
export function isOptimisticInlineStartEnabled() {
|
|
307
|
+
const raw = process.env.WORKFLOW_OPTIMISTIC_INLINE_START;
|
|
308
|
+
if (raw === undefined || raw === '')
|
|
309
|
+
return false;
|
|
310
|
+
return raw === '1' || raw.toLowerCase() === 'true';
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Whether an operator has **explicitly disabled** optimistic inline start via
|
|
314
|
+
* `WORKFLOW_OPTIMISTIC_INLINE_START=0` / `=false`. Distinct from "unset": unset
|
|
315
|
+
* leaves the optimization off by default but lets turbo force it on; an explicit
|
|
316
|
+
* `0`/`false` is an operator opt-out that turbo must honor (turbo's forced
|
|
317
|
+
* optimistic start still runs a step body before `step_started`/`run_started` is
|
|
318
|
+
* confirmed, the property such an operator is opting out of), so
|
|
319
|
+
* `forceOptimisticStart` defers to this. Reads the env var lazily.
|
|
320
|
+
*/
|
|
321
|
+
export function isOptimisticInlineStartExplicitlyDisabled() {
|
|
322
|
+
const raw = process.env.WORKFLOW_OPTIMISTIC_INLINE_START;
|
|
323
|
+
if (raw === undefined || raw === '')
|
|
324
|
+
return false;
|
|
325
|
+
return raw === '0' || raw.toLowerCase() === 'false';
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Whether "turbo mode" is enabled. Turbo mode fast-paths the *first delivery of
|
|
329
|
+
* the first invocation* of a run (detected by the entrypoint via `runInput`
|
|
330
|
+
* presence + `metadata.attempt === 1`): it backgrounds the `run_started` event
|
|
331
|
+
* creation, skips the initial event-log load (nothing has been written yet),
|
|
332
|
+
* and forces optimistic inline step start for that invocation, independent of
|
|
333
|
+
* `WORKFLOW_OPTIMISTIC_INLINE_START`.
|
|
334
|
+
*
|
|
335
|
+
* Forcing optimistic start is safe here because the first delivery has no
|
|
336
|
+
* concurrent peer handler to race the step create-claim, so a step body runs
|
|
337
|
+
* exactly once. That single-handler guarantee ends as soon as the run creates a
|
|
338
|
+
* hook or wait (which introduce resume/parallel invocations), so the runtime
|
|
339
|
+
* exits turbo at that point.
|
|
340
|
+
*
|
|
341
|
+
* Reads `process.env.WORKFLOW_TURBO` lazily. Default **ON**; disabled only by an
|
|
342
|
+
* explicit `'0'` / `'false'` (case-insensitive).
|
|
343
|
+
*/
|
|
344
|
+
export function isTurboEnabled() {
|
|
345
|
+
const raw = process.env.WORKFLOW_TURBO;
|
|
346
|
+
if (raw === undefined || raw === '')
|
|
347
|
+
return true;
|
|
348
|
+
return !(raw === '0' || raw.toLowerCase() === 'false');
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Whether the QuickJS engine's baseline-snapshot startup optimization is
|
|
352
|
+
* enabled (default ON). When on, the engine hydrates a VM with the
|
|
353
|
+
* workflow bundle once per function instance, snapshots it, and starts
|
|
354
|
+
* every invocation by restoring the snapshot instead of re-evaluating
|
|
355
|
+
* the bundle, skipping the dominant share of VM startup (measured
|
|
356
|
+
* ~77ms → ~3ms to first suspension for a 1.3MB bundle). Bundles whose
|
|
357
|
+
* module scope consumes randomness, reads the clock, or replaces a
|
|
358
|
+
* serialization intrinsic are detected at hydrate time and
|
|
359
|
+
* automatically fall back to per-invocation fresh evaluation (see
|
|
360
|
+
* prepareBaselineSnapshot). Set WORKFLOW_QUICKJS_BASELINE_SNAPSHOT=0 to
|
|
361
|
+
* disable.
|
|
362
|
+
*/
|
|
363
|
+
export function isQuickJSBaselineSnapshotEnabled() {
|
|
364
|
+
const raw = process.env.WORKFLOW_QUICKJS_BASELINE_SNAPSHOT;
|
|
365
|
+
if (raw === undefined || raw === '')
|
|
366
|
+
return true;
|
|
367
|
+
return !(raw === '0' || raw.toLowerCase() === 'false');
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Whether the Node.js inline loop retains a suspended workflow VM within one
|
|
371
|
+
* invocation (default ON). When on, a step- or attribute-driven suspension can
|
|
372
|
+
* keep the live VM, event consumer, and hydrated state even with open hooks or
|
|
373
|
+
* waits. The next loop iteration appends newly durable events instead of
|
|
374
|
+
* rebuilding the `vm.Context` and replaying the whole event log. Hook- or
|
|
375
|
+
* wait-only suspensions park the invocation, while replay divergence falls back
|
|
376
|
+
* to the ordinary durable replay path. QuickJS manages its own retained loop.
|
|
377
|
+
*
|
|
378
|
+
* `WORKFLOW_RETAINED_VM=0` (or `false`) is the kill switch: every iteration
|
|
379
|
+
* replays the Node.js engine from scratch in a fresh VM, matching the
|
|
380
|
+
* pre-retention behavior.
|
|
381
|
+
*/
|
|
382
|
+
export function isVmRetentionEnabled() {
|
|
383
|
+
const raw = process.env.WORKFLOW_RETAINED_VM;
|
|
384
|
+
if (raw === undefined || raw === '')
|
|
385
|
+
return true;
|
|
386
|
+
return !(raw === '0' || raw.toLowerCase() === 'false');
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Whether inline step ownership is enabled (default ON). When on, the lazy
|
|
390
|
+
* `step_started` that creates an inline step records the owning queue
|
|
391
|
+
* message ID, and wake replays that observe an actively-owned step enqueue a
|
|
392
|
+
* *delayed backstop* message instead of immediately requeueing it, fixing
|
|
393
|
+
* duplicate inline step execution when a hook/wait wakes a run mid-step
|
|
394
|
+
* (vercel/workflow#2780).
|
|
395
|
+
*
|
|
396
|
+
* `WORKFLOW_INLINE_OWNERSHIP=0` (or `false`) is the kill switch: dispatch
|
|
397
|
+
* reverts to the unconditional immediate requeue. Stamping is unaffected:
|
|
398
|
+
* the recorded ownerMessageId is inert data when the switch is off.
|
|
399
|
+
*/
|
|
400
|
+
export function isInlineOwnershipEnabled() {
|
|
401
|
+
const raw = process.env.WORKFLOW_INLINE_OWNERSHIP;
|
|
402
|
+
if (raw === undefined || raw === '')
|
|
403
|
+
return true;
|
|
404
|
+
return !(raw === '0' || raw.toLowerCase() === 'false');
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Default inline-ownership lease, in seconds: how long after a step's latest
|
|
408
|
+
* (stamped) `step_started` a non-owner invocation assumes the owning
|
|
409
|
+
* invocation may still be alive. Within the lease, wake replays enqueue the
|
|
410
|
+
* step's backstop message with `delaySeconds = lease remaining` instead of
|
|
411
|
+
* immediately; past it, they enqueue immediately (today's behavior).
|
|
412
|
+
*
|
|
413
|
+
* Why a fixed 860 and not a value derived from the function's `maxDuration`:
|
|
414
|
+
* neither runtime nor build time can see the resolved value: builders emit
|
|
415
|
+
* `maxDuration: 'max'`, which the platform resolves per-plan at deploy, and
|
|
416
|
+
* no env var or request-context deadline API exposes the result. The bound
|
|
417
|
+
* comes from a platform rule instead: durations above 800s require explicit
|
|
418
|
+
* per-function numeric config, so a builder-emitted `'max'` resolves to at
|
|
419
|
+
* most 800s, and 860s therefore dominates any workflow route's invocation
|
|
420
|
+
* lifetime plus scheduling slack. Revisit when that ceiling moves (the
|
|
421
|
+
* 30-minute duration beta becoming reachable via `'max'` would invalidate
|
|
422
|
+
* the bound). Worlds without an invocation kill bound (world-local,
|
|
423
|
+
* self-hosted) get no death proof from any constant. There the in-process
|
|
424
|
+
* single-flight layer (step-single-flight.ts) is what makes a backstop
|
|
425
|
+
* firing mid-step harmless.
|
|
426
|
+
*
|
|
427
|
+
* 860 also stays under the queue's 900s maximum delay (SQS cap), so a
|
|
428
|
+
* backstop's full lease remainder always fits in a single delayed message.
|
|
429
|
+
*
|
|
430
|
+
* Override via `WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS` (clamped to
|
|
431
|
+
* 1..`MAX_INLINE_OWNERSHIP_LEASE_SECONDS`).
|
|
432
|
+
*/
|
|
433
|
+
export const INLINE_OWNERSHIP_LEASE_SECONDS = 860;
|
|
434
|
+
/**
|
|
435
|
+
* Upper bound for the lease env override. 900s is the queue's maximum
|
|
436
|
+
* per-message delay (SQS cap). A longer lease would need delay chaining
|
|
437
|
+
* like long waits use; clamp instead so one delayed message always suffices.
|
|
438
|
+
*/
|
|
439
|
+
export const MAX_INLINE_OWNERSHIP_LEASE_SECONDS = 900;
|
|
440
|
+
/**
|
|
441
|
+
* Effective inline-ownership lease. Override via
|
|
442
|
+
* `WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS`, e.g. raise it on self-hosted
|
|
443
|
+
* multi-instance worlds with long-running steps to widen the window in which
|
|
444
|
+
* a live owner is protected from a concurrent backstop execution.
|
|
445
|
+
*/
|
|
446
|
+
export function getInlineOwnershipLeaseSeconds() {
|
|
447
|
+
return envNumber('WORKFLOW_INLINE_OWNERSHIP_LEASE_SECONDS', INLINE_OWNERSHIP_LEASE_SECONDS, { integer: true, min: 1, max: MAX_INLINE_OWNERSHIP_LEASE_SECONDS });
|
|
448
|
+
}
|
|
449
|
+
// A replay-consumer mismatch can be caused by a transient divergent replay
|
|
450
|
+
// rather than an invalid persisted history. Queue bounded recovery replays
|
|
451
|
+
// before recording terminal corruption for a run that cannot replay.
|
|
452
|
+
export const REPLAY_DIVERGENCE_MAX_RETRIES = 3;
|
|
453
|
+
/**
|
|
454
|
+
* Effective replay-divergence recovery budget. Override via
|
|
455
|
+
* `WORKFLOW_REPLAY_DIVERGENCE_MAX_RETRIES`.
|
|
456
|
+
*/
|
|
457
|
+
export function getReplayDivergenceMaxRetries() {
|
|
458
|
+
return envNumber('WORKFLOW_REPLAY_DIVERGENCE_MAX_RETRIES', REPLAY_DIVERGENCE_MAX_RETRIES, { integer: true });
|
|
459
|
+
}
|
|
460
|
+
// A stale-snapshot rejection (412) means the replay's event log was missing an
|
|
461
|
+
// event the World had already recorded, so the replay is re-derived from a
|
|
462
|
+
// corrected log inside the same invocation. Bounded because a persistently
|
|
463
|
+
// rejected write should escalate rather than spin: after this many restarts the
|
|
464
|
+
// run is re-invoked (a new invocation, possibly in a different region), and the
|
|
465
|
+
// run-level budget below then applies.
|
|
466
|
+
export const PRECONDITION_MAX_INPROCESS_RESTARTS = 3;
|
|
467
|
+
/**
|
|
468
|
+
* Effective in-process replay-restart budget for stale-snapshot rejections.
|
|
469
|
+
* Override via `WORKFLOW_PRECONDITION_MAX_INPROCESS_RESTARTS`.
|
|
470
|
+
*/
|
|
471
|
+
export function getPreconditionMaxInProcessRestarts() {
|
|
472
|
+
return envNumber('WORKFLOW_PRECONDITION_MAX_INPROCESS_RESTARTS', PRECONDITION_MAX_INPROCESS_RESTARTS, { integer: true });
|
|
473
|
+
}
|
|
474
|
+
// The in-process budget above is per-invocation, and a re-invocation that
|
|
475
|
+
// enqueues a fresh message also restarts the queue's delivery count, so without
|
|
476
|
+
// a counter carried on the message a permanently fenced run has no run-level
|
|
477
|
+
// bound at all. It can stay fenced without any permanent fault (a full reload
|
|
478
|
+
// is not atomic across pages, so a busy run can acquire a new hole on every
|
|
479
|
+
// reload), so the chain is counted and the run fails once this many
|
|
480
|
+
// re-invocations have been spent on stale-snapshot rejections.
|
|
481
|
+
export const PRECONDITION_MAX_REINVOCATIONS = 5;
|
|
482
|
+
/**
|
|
483
|
+
* Effective per-run budget for re-invocations caused by stale-snapshot
|
|
484
|
+
* rejections. Override via `WORKFLOW_PRECONDITION_MAX_REINVOCATIONS`.
|
|
485
|
+
*/
|
|
486
|
+
export function getPreconditionMaxReinvocations() {
|
|
487
|
+
return envNumber('WORKFLOW_PRECONDITION_MAX_REINVOCATIONS', PRECONDITION_MAX_REINVOCATIONS, { integer: true });
|
|
488
|
+
}
|
|
489
|
+
// Backoff before a precondition re-invocation. Unlike the in-process restart
|
|
490
|
+
// (where the point is to re-read immediately), a re-invocation only happens
|
|
491
|
+
// after the in-process budget failed to catch up, so the log is being extended
|
|
492
|
+
// faster than this replay can follow it. Waiting lets the writers quiesce.
|
|
493
|
+
export const PRECONDITION_REINVOKE_DELAY_SECONDS = 2;
|
|
494
|
+
/**
|
|
495
|
+
* Effective delay before a precondition re-invocation. Override via
|
|
496
|
+
* `WORKFLOW_PRECONDITION_REINVOKE_DELAY_SECONDS`.
|
|
497
|
+
*/
|
|
498
|
+
export function getPreconditionReinvokeDelaySeconds() {
|
|
499
|
+
return envNumber('WORKFLOW_PRECONDITION_REINVOKE_DELAY_SECONDS', PRECONDITION_REINVOKE_DELAY_SECONDS, { integer: true });
|
|
500
|
+
}
|
|
501
|
+
// A delivery reaching a deployment the run is not pinned to is not treated as
|
|
502
|
+
// permanent. Re-route the message at the run's own deployment a bounded number
|
|
503
|
+
// of times before failing the run with DEPLOYMENT_MISMATCH.
|
|
504
|
+
export const DEPLOYMENT_MISMATCH_MAX_RETRIES = 3;
|
|
505
|
+
/**
|
|
506
|
+
* Effective deployment-mismatch re-route budget. Override via
|
|
507
|
+
* `WORKFLOW_DEPLOYMENT_MISMATCH_MAX_RETRIES`; `0` fails the run on the first
|
|
508
|
+
* misrouted delivery instead of attempting recovery.
|
|
509
|
+
*/
|
|
510
|
+
export function getDeploymentMismatchMaxRetries() {
|
|
511
|
+
return envNumber('WORKFLOW_DEPLOYMENT_MISMATCH_MAX_RETRIES', DEPLOYMENT_MISMATCH_MAX_RETRIES, { integer: true, min: 0 });
|
|
512
|
+
}
|
|
513
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bnRpbWUvY29uc3RhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDNUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU3Qyw0RUFBNEU7QUFDNUUsNEVBQTRFO0FBQzVFLHlFQUF5RTtBQUN6RSxvREFBb0Q7QUFDcEQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSxzREFBc0Q7QUFDdEQsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw2RUFBNkU7QUFDN0UseUVBQXlFO0FBQ3pFLCtFQUErRTtBQUMvRSw2RUFBNkU7QUFDN0UsK0VBQStFO0FBQy9FLGdGQUFnRjtBQUNoRiwyRUFBMkU7QUFDM0UseUVBQXlFO0FBQ3pFLDZCQUE2QjtBQUM3QixNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxFQUFFLENBQUM7QUFFdkM7O0dBRUc7QUFDSCxNQUFNLFVBQVUscUJBQXFCO0lBQ25DLHdFQUF3RTtJQUN4RSwwRUFBMEU7SUFDMUUsOEVBQThFO0lBQzlFLHlFQUF5RTtJQUN6RSw0RUFBNEU7SUFDNUUsT0FBTyxTQUFTLENBQUMsK0JBQStCLEVBQUUsb0JBQW9CLEVBQUU7UUFDdEUsT0FBTyxFQUFFLElBQUk7UUFDYixHQUFHLEVBQUUsQ0FBQztRQUNOLEdBQUcsRUFBRSxvQkFBb0I7S0FDMUIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUM7QUFFekMsMkRBQTJEO0FBQzNELE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLE1BQU0sQ0FBQztBQUU1Qzs7OztHQUlHO0FBQ0gs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Q0FBQyxDQUFDO0FBRXJEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxtQ0FBbUM7SUFDakQsT0FBTyxTQUFTLENBQ2QsOENBQThDLEVBQzlDLG1DQUFtQyxFQUNuQyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FDbEIsQ0FBQztBQUNKLENBQUM7QUFFRCw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDREQUE0RDtBQUM1RCxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxDQUFDLENBQUM7QUFFakQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSwrQkFBK0I7SUFDN0MsT0FBTyxTQUFTLENBQ2QsMENBQTBDLEVBQzFDLCtCQUErQixFQUMvQixFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUMxQixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdsb2JhbFNpbmdsZXRvbiB9IGZyb20gJ0B3b3JrZmxvdy91dGlscyc7XG5pbXBvcnQgeyBlbnZOdW1iZXIgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8vIE1heGltdW0gbnVtYmVyIG9mIHF1ZXVlIGRlbGl2ZXJ5IGF0dGVtcHRzIGJlZm9yZSB0aGUgaGFuZGxlciBnaXZlcyB1cCBhbmRcbi8vIGdyYWNlZnVsbHkgZmFpbHMgdGhlIHJ1bi9zdGVwLiBUaGlzIG11c3QgYmUgYm91bmRlZCB1bmRlciB0aGUgVlFTIG1lc3NhZ2Vcbi8vIG1heCB2aXNpYmlsaXR5IHdpbmRvdyAoMjQgaG91cnMpIHNvIHRoYXQgb3VyIGhhbmRsZXItc2lkZSBmYWlsdXJlIHBhdGhcbi8vIHJlbGlhYmx5IGV4ZWN1dGVzIGJlZm9yZSBWUVMgZXhwaXJlcyB0aGUgbWVzc2FnZS5cbi8vXG4vLyBUaGUgZWZmZWN0aXZlIHdhbGwtY2xvY2sgc3Vydml2YWwgZGVwZW5kcyBvbiB0aGUgcGVyLXJlZGVsaXZlcnkgYmFja29mZjogdGhlXG4vLyBgcmV0cnktYWZ0ZXJgIHRoZSBoYW5kbGVyIHJldHVybnMgKHNlZSB3b3JsZC12ZXJjZWxcbi8vIGBnZXRIYW5kbGVyRXJyb3JSZXRyeUFmdGVyU2Vjb25kc2ApIGZlZCB0aHJvdWdoIFZRUyBgY2FsY3VsYXRlQmFja29mZkRlbGF5YC5cbi8vIFZRUyB1c2VzIG91ciB2YWx1ZSBmb3IgdGhlIGZpcnN0IDMyIGF0dGVtcHRzIChjbGFtcGVkIHRvIFs1cywgOTAwc10pIHRoZW5cbi8vIGFwcGxpZXMgaXRzIG93biBleHBvbmVudGlhbCBncm93dGgsIGV2ZXJ5IGhvcCBoYXJkLWNhcHBlZCBhdCB0aGUgU1FTIGxpbWl0XG4vLyBvZiA5MDBzLiBXaXRoIHRoZSBiYWNrb2ZmIHJhbXBpbmcgdG93YXJkIHRoYXQgOTAwcyBjZWlsaW5nIChyZWFjaGVkIGJ5XG4vLyB+ZGVsaXZlcnkgMTEpLCA0OCBhdHRlbXB0cyBzcGFuIHJvdWdobHkgOeKAkzEwIGhvdXJzIG9mIHdhbGwtY2xvY2sgKH4zNSwwMDBzKSxcbi8vIGNvbWZvcnRhYmx5IHVuZGVyIHRoZSAyNC1ob3VyIG1lc3NhZ2UtdmlzaWJpbGl0eSBsaW1pdCBzbyB0aGUgZmFpbHVyZSBwYXRoXG4vLyBydW5zIGJlZm9yZSB0aGUgbWVzc2FnZSBleHBpcmVzLiAoQSBmbGF0dGVyLCBsb3ctY2FwcGVkIGJhY2tvZmYgZXhoYXVzdHMgdGhlXG4vLyBidWRnZXQgaW4gb25seSBhIGZldyBob3VycywgZmFpbGluZyBvdGhlcndpc2UtaGVhbHRoeSBydW5zIGR1cmluZyBhIHRyYW5zaWVudFxuLy8gYmFja2VuZCBvdXRhZ2U7IGNvbnZlcnNlbHksIHNwYW5uaW5nIHRoZSBmdWxsIDI0aCB3aW5kb3cgd291bGQgcmVxdWlyZSBhXG4vLyBzdWJzdGFudGlhbGx5IGhpZ2hlciBjYXAgaGVyZSwgbm90IGEgaGlnaGVyIHBlci1ob3AgY2VpbGluZywgc2luY2UgVlFTXG4vLyBjbGFtcHMgZXZlcnkgaG9wIGF0IDkwMHMuKVxuZXhwb3J0IGNvbnN0IE1BWF9RVUVVRV9ERUxJVkVSSUVTID0gNDg7XG5cbi8qKlxuICogRWZmZWN0aXZlIG1heCBxdWV1ZSBkZWxpdmVyaWVzLiBPdmVycmlkZSB2aWEgYFdPUktGTE9XX01BWF9RVUVVRV9ERUxJVkVSSUVTYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1heFF1ZXVlRGVsaXZlcmllcygpOiBudW1iZXIge1xuICAvLyBPbmx5IGV2ZXIgbG93ZXIgdGhlIGRlbGl2ZXJ5IGJ1ZGdldC4gVGhlIGRlZmF1bHQgaXMgY2FsaWJyYXRlZCBzbyB0aGVcbiAgLy8gaGFuZGxlci1zaWRlIGZhaWx1cmUgcGF0aCBydW5zIGJlZm9yZSBWUVMgbWVzc2FnZS1yZXRlbnRpb24gZXhwaXJ5IChzZWVcbiAgLy8gTUFYX1FVRVVFX0RFTElWRVJJRVMgYWJvdmUpOyBhIGhpZ2hlciB2YWx1ZSB3b3VsZCBieXBhc3MgdGhhdCBpbnZhcmlhbnQgYW5kXG4gIC8vIGxldCBhIGJhZCBkZXBsb3ltZW50IHJlZGVsaXZlciB1bnRpbCBxdWV1ZSBleHBpcnkgaW5zdGVhZCBvZiByZWNvcmRpbmdcbiAgLy8gcnVuX2ZhaWwuIGBtYXhgIGNsYW1wcyBhIHRvby1oaWdoIG92ZXJyaWRlIGJhY2sgZG93biB0byB0aGUgc2FmZSBkZWZhdWx0LlxuICByZXR1cm4gZW52TnVtYmVyKCdXT1JLRkxPV19NQVhfUVVFVUVfREVMSVZFUklFUycsIE1BWF9RVUVVRV9ERUxJVkVSSUVTLCB7XG4gICAgaW50ZWdlcjogdHJ1ZSxcbiAgICBtaW46IDEsXG4gICAgbWF4OiBNQVhfUVVFVUVfREVMSVZFUklFUyxcbiAgfSk7XG59XG5cbi8qKlxuICogRGVmYXVsdCBtYXhpbXVtIHRpbWUgYWxsb3dlZCBmb3IgdGhlICpyZXBsYXkqIHBvcnRpb24gb2YgYSBzaW5nbGUgd29ya2Zsb3dcbiAqIGhhbmRsZXIgaW52b2NhdGlvbiAoaW4gbXMpLiBUaGlzIGJ1ZGdldCBvbmx5IGNvdmVycyBkZXRlcm1pbmlzdGljLXJlcGxheVxuICogYW5kIHdvcmtmbG93LVZNIGV4ZWN1dGlvbiBiZXR3ZWVuIHN0ZXAgYm91bmRhcmllcy4gSW5saW5lIHN0ZXAgYm9kaWVzXG4gKiAoYFwidXNlIHN0ZXBcImAgZnVuY3Rpb25zIGludm9rZWQgdmlhIGBleGVjdXRlU3RlcGApIGRvIE5PVCBjb3VudCBhZ2FpbnN0XG4gKiBpdC4gU3RlcCBib2RpZXMgYXJlIGJvdW5kZWQgc2VwYXJhdGVseSBieSB0aGUgcGxhdGZvcm0ncyBmdW5jdGlvblxuICogYG1heER1cmF0aW9uYCAoZS5nLiA4MDBzIG9uIFZlcmNlbCBQcm8gRmx1aWQpIGFuZCBgTk9fSU5MSU5FX1JFUExBWV9BRlRFUl9NU2AuXG4gKlxuICogSWYgdGhlIG5vbi1zdGVwIChcInJlcGxheVwiKSB0aW1lIHdpdGhpbiBhIHNpbmdsZSBpbnZvY2F0aW9uIGV4Y2VlZHMgdGhpc1xuICogYnVkZ2V0LCB0aGUgaGFuZGxlciByZWplY3RzIHNvIHRoZSBxdWV1ZSBjYW4gcmV0cnkuIEFmdGVyXG4gKiBgUkVQTEFZX1RJTUVPVVRfTUFYX1JFVFJJRVNgIGV4aGF1c3RlZCBhdHRlbXB0cyB0aGUgcnVuIGlzIGZhaWxlZCB3aXRoXG4gKiBgUlVOX0VSUk9SX0NPREVTLlJFUExBWV9USU1FT1VUYC5cbiAqXG4gKiBOb3RlIHRoYXQgb24gVmVyY2VsIEhvYmJ5IChzdGFuZGFyZCBmdW5jdGlvbnMpLCB0aGUgcGxhdGZvcm0gYG1heER1cmF0aW9uYFxuICogaXMgNjBzLCB3ZWxsIGJlbG93IHRoaXMgYnVkZ2V0LCBzbyB0aGUgcGxhdGZvcm0gU0lHVEVSTSB3aWxsIGZpcmUgZmlyc3RcbiAqIGFuZCB0aGUgcXVldWUgd2lsbCByZS1kZWxpdmVyIHVudGlsIHRoZSB2aXNpYmlsaXR5IHdpbmRvdyBleHBpcmVzLiBXaXRoXG4gKiBGbHVpZCBDb21wdXRlIG9uIEhvYmJ5IHRoZSBwZXItZnVuY3Rpb24gY2VpbGluZyByaXNlcyB0byAzMDBzLCBzdGlsbFxuICogdW5kZXIgdGhlIGRlZmF1bHQgYnVkZ2V0LlxuICpcbiAqIE92ZXJyaWRlIHZpYSB0aGUgYFdPUktGTE9XX1JFUExBWV9USU1FT1VUX01TYCBlbnYgdmFyIChjbGFtcGVkIHRvXG4gKiBgTUlOX1JFUExBWV9USU1FT1VUX01TYC4uYE1BWF9SRVBMQVlfVElNRU9VVF9NU2ApLlxuICovXG5leHBvcnQgY29uc3QgUkVQTEFZX1RJTUVPVVRfTVMgPSAyNDBfMDAwO1xuXG4vKiogTG93ZXIgYm91bmQgZm9yIHRoZSByZXBsYXktdGltZW91dCBlbnYgdmFyIG92ZXJyaWRlLiAqL1xuZXhwb3J0IGNvbnN0IE1JTl9SRVBMQVlfVElNRU9VVF9NUyA9IDMwXzAwMDtcblxuLyoqXG4gKiBVcHBlciBib3VuZCBmb3IgdGhlIHJlcGxheS10aW1lb3V0IGVudiB2YXIgb3ZlcnJpZGUuIDc4MHMgbGVhdmVzIOKJpTIwcyBvZlxuICogaGVhZHJvb20gdW5kZXIgVmVyY2VsIFBybyBGbHVpZCdzIDgwMHMgZnVuY3Rpb24gY2VpbGluZyBzbyB0aGUgaGFuZGxlclxuICogY2FuIHdyaXRlIGBydW5fZmFpbGVkYCBiZWZvcmUgU0lHVEVSTS5cbiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9SRVBMQVlfVElNRU9VVF9NUyA9IDc4MF8wMDA7XG5cbi8vIFRyYWNrIHdoaWNoIHJhdyBlbnYgdmFyIHZhbHVlcyB3ZSd2ZSBhbHJlYWR5IHdhcm5lZCBhYm91dCBzbyB0aGUgd2FybmluZ1xuLy8gbG9nIG9ubHkgZmlyZXMgb25jZSBwZXIgcHJvY2VzcyAodGhlIGZ1bmN0aW9uIG1heSBiZSBjYWxsZWQgbWFueSB0aW1lcykuXG4vL1xuLy8gT24gYGdsb2JhbFRoaXNgIHJhdGhlciB0aGFuIGF0IG1vZHVsZSBzY29wZSBzbyBcIm9uY2UgcGVyIHByb2Nlc3NcIiBzdXJ2aXZlc1xuLy8gYnVuZGxpbmc6IHRoaXMgcGFja2FnZSBpcyBjb21waWxlZCBpbnRvIHRoZSBob3N0IGFwcGxpY2F0aW9uJ3Mgc2VydmVyIGJ1aWxkXG4vLyBvbmNlIHBlciBidW5kbGVyIGxheWVyLCBhbmQgcGVyLWNvcHkgc2V0cyB3YXJuIG9uY2UgcGVyIGxheWVyIGluc3RlYWQuXG5jb25zdCB3YXJuZWQgPSBnbG9iYWxTaW5nbGV0b24oJ0B3b3JrZmxvdy9jb3JlLy9lbnZXYXJuaW5ncycsIDEsICgpID0+ICh7XG4gIHJlcGxheVRpbWVvdXRWYWx1ZXM6IG5ldyBTZXQ8c3RyaW5nPigpLFxuICBtYXhJbmxpbmVTdGVwc1ZhbHVlczogbmV3IFNldDxzdHJpbmc+KCksXG4gIG1heEV2ZW50c1ZhbHVlczogbmV3IFNldDxzdHJpbmc+KCksXG59KSk7XG5cbmZ1bmN0aW9uIHdhcm5PbmNlKFxuICByYXc6IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuKTogdm9pZCB7XG4gIGlmICh3YXJuZWQucmVwbGF5VGltZW91dFZhbHVlcy5oYXMocmF3KSkgcmV0dXJuO1xuICB3YXJuZWQucmVwbGF5VGltZW91dFZhbHVlcy5hZGQocmF3KTtcbiAgcnVudGltZUxvZ2dlci53YXJuKG1lc3NhZ2UsIGRhdGEpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGVmZmVjdGl2ZSByZXBsYXktdGltZW91dCBidWRnZXQgZm9yIHRoZSBjdXJyZW50IHByb2Nlc3MuXG4gKlxuICogUmVhZHMgYHByb2Nlc3MuZW52LldPUktGTE9XX1JFUExBWV9USU1FT1VUX01TYCBsYXppbHkgc28gdGVzdHMgYW5kXG4gKiBkZXBsb3ltZW50cyBjYW4gb3ZlcnJpZGUgcGVyIGludm9jYXRpb24uIEludmFsaWQgLyBvdXQtb2YtcmFuZ2UgdmFsdWVzXG4gKiBmYWxsIGJhY2sgdG8gYSBzYWZlIHZhbHVlIChubyB0aHJvdzogdGhlIGVudiB2YXIgaXMgYW4gZXNjYXBlIGhhdGNoLFxuICogbm90IGEgaGFyZCByZXF1aXJlbWVudCkgYW5kIGVtaXQgYSBvbmUtdGltZSB3YXJuaW5nIHNvIG1pc2NvbmZpZ3VyYXRpb25cbiAqIGlzIG9ic2VydmFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRSZXBsYXlUaW1lb3V0TXMoKTogbnVtYmVyIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfUkVQTEFZX1RJTUVPVVRfTVM7XG4gIGlmICghcmF3KSByZXR1cm4gUkVQTEFZX1RJTUVPVVRfTVM7XG4gIGNvbnN0IHBhcnNlZCA9IE51bWJlcihyYXcpO1xuICBpZiAoIU51bWJlci5pc0Zpbml0ZShwYXJzZWQpIHx8IHBhcnNlZCA8PSAwKSB7XG4gICAgd2Fybk9uY2UoXG4gICAgICByYXcsXG4gICAgICAnSWdub3JpbmcgV09SS0ZMT1dfUkVQTEFZX1RJTUVPVVRfTVM6IG5vdCBhIHBvc2l0aXZlIGZpbml0ZSBudW1iZXI7IHVzaW5nIGRlZmF1bHQnLFxuICAgICAgeyByYXcsIGRlZmF1bHRNczogUkVQTEFZX1RJTUVPVVRfTVMgfVxuICAgICk7XG4gICAgcmV0dXJuIFJFUExBWV9USU1FT1VUX01TO1xuICB9XG4gIGlmIChwYXJzZWQgPCBNSU5fUkVQTEFZX1RJTUVPVVRfTVMpIHtcbiAgICB3YXJuT25jZShyYXcsICdXT1JLRkxPV19SRVBMQVlfVElNRU9VVF9NUyBiZWxvdyBtaW5pbXVtOyBjbGFtcGVkJywge1xuICAgICAgcmF3LFxuICAgICAgY2xhbXBlZE1zOiBNSU5fUkVQTEFZX1RJTUVPVVRfTVMsXG4gICAgICBtaW5NczogTUlOX1JFUExBWV9USU1FT1VUX01TLFxuICAgIH0pO1xuICAgIHJldHVybiBNSU5fUkVQTEFZX1RJTUVPVVRfTVM7XG4gIH1cbiAgaWYgKHBhcnNlZCA+IE1BWF9SRVBMQVlfVElNRU9VVF9NUykge1xuICAgIHdhcm5PbmNlKHJhdywgJ1dPUktGTE9XX1JFUExBWV9USU1FT1VUX01TIGFib3ZlIG1heGltdW07IGNsYW1wZWQnLCB7XG4gICAgICByYXcsXG4gICAgICBjbGFtcGVkTXM6IE1BWF9SRVBMQVlfVElNRU9VVF9NUyxcbiAgICAgIG1heE1zOiBNQVhfUkVQTEFZX1RJTUVPVVRfTVMsXG4gICAgfSk7XG4gICAgcmV0dXJuIE1BWF9SRVBMQVlfVElNRU9VVF9NUztcbiAgfVxuICByZXR1cm4gcGFyc2VkO1xufVxuXG4vKipcbiAqIFJlc2V0IHRoZSB3YXJuLW9uY2UgY2FjaGUuIFRlc3Qtb25seTogZXhwb3J0ZWQgc28gdW5pdCB0ZXN0cyBjYW5cbiAqIGV4ZXJjaXNlIHRoZSB3YXJuIHBhdGggcmVwZWF0ZWRseSB3aXRob3V0IHNoYXJpbmcgc3RhdGUuXG4gKlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfcmVzZXRSZXBsYXlUaW1lb3V0V2FybkNhY2hlRm9yVGVzdHMoKTogdm9pZCB7XG4gIHdhcm5lZC5yZXBsYXlUaW1lb3V0VmFsdWVzLmNsZWFyKCk7XG59XG5cbi8vIE51bWJlciBvZiBxdWV1ZSBkZWxpdmVyeSBhdHRlbXB0cyB0byBhbGxvdyBiZWZvcmUgcGVybWFuZW50bHkgZmFpbGluZyBhIHJ1blxuLy8gZHVlIHRvIGEgcmVwbGF5IHRpbWVvdXQuIE9uIGF0dGVtcHRzIDEgdGhyb3VnaCB0aGlzIHZhbHVlLCB0aGUgdGltZW91dFxuLy8gaGFuZGxlciByZWplY3RzIHdpdGhvdXQgd3JpdGluZyBydW5fZmFpbGVkIHNvIHRoZSBxdWV1ZSByZXRyaWVzIHRoZSBtZXNzYWdlLlxuLy8gT24gdGhlIG5leHQgYXR0ZW1wdCB0aGUgcnVuIGlzIG1hcmtlZCBhcyBmYWlsZWQuXG5leHBvcnQgY29uc3QgUkVQTEFZX1RJTUVPVVRfTUFYX1JFVFJJRVMgPSAzO1xuXG4vKipcbiAqIEVmZmVjdGl2ZSByZXBsYXktdGltZW91dCByZXRyeSBidWRnZXQuIE92ZXJyaWRlIHZpYVxuICogYFdPUktGTE9XX1JFUExBWV9USU1FT1VUX01BWF9SRVRSSUVTYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFJlcGxheVRpbWVvdXRNYXhSZXRyaWVzKCk6IG51bWJlciB7XG4gIHJldHVybiBlbnZOdW1iZXIoXG4gICAgJ1dPUktGTE9XX1JFUExBWV9USU1FT1VUX01BWF9SRVRSSUVTJyxcbiAgICBSRVBMQVlfVElNRU9VVF9NQVhfUkVUUklFUyxcbiAgICB7IGludGVnZXI6IHRydWUgfVxuICApO1xufVxuXG4vKipcbiAqIERlZmF1bHQgbWF4aW11bSBudW1iZXIgb2Ygc3RlcHMgdGhlIG93bmVkLWlubGluZSBwYXRoIHJ1bnMgaW5saW5lIChpblxuICogcGFyYWxsZWwpIHBlciBzdXNwZW5zaW9uLiBUaGUgcmVzdCBhcmUgcXVldWVkIHRvIGJhY2tncm91bmQgaGFuZGxlcnMuIEVhY2hcbiAqIGlubGluZSBzdGVwIGlzIGNyZWF0ZWQgbGF6aWx5IChpdHMgYHN0ZXBfY3JlYXRlZGAgaXMgZm9sZGVkIGludG8gdGhlXG4gKiBgc3RlcF9zdGFydGVkYCB0aGF0IGBleGVjdXRlU3RlcGAgc2VuZHMpLCBzbyBpbmxpbmluZyBOIHN0ZXBzIHNhdmVzIE4gcXVldWVcbiAqIHJvdW5kLXRyaXBzIGZvciBhIGBQcm9taXNlLmFsbGAtc3R5bGUgZmFuLW91dC4gYDFgIHJlcHJvZHVjZXMgdGhlXG4gKiBzaW5nbGUtaW5saW5lLXN0ZXAgYmVoYXZpb3IgZXhhY3RseSAodXNlZnVsIGtpbGwtc3dpdGNoKS5cbiAqXG4gKiBPdmVycmlkZSB2aWEgYFdPUktGTE9XX01BWF9JTkxJTkVfU1RFUFNgIChjbGFtcGVkIHRvXG4gKiBgTUlOX01BWF9JTkxJTkVfU1RFUFNgLi5gTUFYX01BWF9JTkxJTkVfU1RFUFNgKS5cbiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9JTkxJTkVfU1RFUFMgPSAzO1xuXG4vKiogTG93ZXIgYm91bmQgZm9yIHRoZSBpbmxpbmUtc3RlcHMgZW52IG92ZXJyaWRlICgxID0gc2luZ2xlIGlubGluZSBzdGVwKS4gKi9cbmV4cG9ydCBjb25zdCBNSU5fTUFYX0lOTElORV9TVEVQUyA9IDE7XG5cbi8qKlxuICogVXBwZXIgYm91bmQgZm9yIHRoZSBpbmxpbmUtc3RlcHMgZW52IG92ZXJyaWRlLiBJbmxpbmUgYm9kaWVzIHJ1biBpbiBwYXJhbGxlbFxuICogd2l0aGluIG9uZSBmdW5jdGlvbiBpbnZvY2F0aW9uLCBzbyB0aGlzIGNhcHMgbWVtb3J5L0NQVSBmYW4tb3V0IHBlciBoYW5kbGVyLlxuICovXG5leHBvcnQgY29uc3QgTUFYX01BWF9JTkxJTkVfU1RFUFMgPSAxNjtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBlZmZlY3RpdmUgbWF4IG51bWJlciBvZiBpbmxpbmUgc3RlcHMgZm9yIHRoZSBjdXJyZW50IHByb2Nlc3MuXG4gKlxuICogUmVhZHMgYHByb2Nlc3MuZW52LldPUktGTE9XX01BWF9JTkxJTkVfU1RFUFNgIGxhemlseSBzbyB0ZXN0cyBhbmRcbiAqIGRlcGxveW1lbnRzIGNhbiBvdmVycmlkZSBwZXIgaW52b2NhdGlvbi4gSW52YWxpZCAvIG91dC1vZi1yYW5nZSB2YWx1ZXMgZmFsbFxuICogYmFjayB0byBhIHNhZmUgdmFsdWUgKG5vIHRocm93OiB0aGUgZW52IHZhciBpcyBhbiBlc2NhcGUgaGF0Y2gpIGFuZCBlbWl0IGFcbiAqIG9uZS10aW1lIHdhcm5pbmcgc28gbWlzY29uZmlndXJhdGlvbiBpcyBvYnNlcnZhYmxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWF4SW5saW5lU3RlcHMoKTogbnVtYmVyIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfTUFYX0lOTElORV9TVEVQUztcbiAgaWYgKCFyYXcpIHJldHVybiBNQVhfSU5MSU5FX1NURVBTO1xuICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmF3KTtcbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHBhcnNlZCkgfHwgcGFyc2VkIDw9IDApIHtcbiAgICBpZiAoIXdhcm5lZC5tYXhJbmxpbmVTdGVwc1ZhbHVlcy5oYXMocmF3KSkge1xuICAgICAgd2FybmVkLm1heElubGluZVN0ZXBzVmFsdWVzLmFkZChyYXcpO1xuICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAnSWdub3JpbmcgV09SS0ZMT1dfTUFYX0lOTElORV9TVEVQUzogbm90IGEgcG9zaXRpdmUgaW50ZWdlcjsgdXNpbmcgZGVmYXVsdCcsXG4gICAgICAgIHsgcmF3LCBkZWZhdWx0VmFsdWU6IE1BWF9JTkxJTkVfU1RFUFMgfVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIE1BWF9JTkxJTkVfU1RFUFM7XG4gIH1cbiAgaWYgKHBhcnNlZCA8IE1JTl9NQVhfSU5MSU5FX1NURVBTKSByZXR1cm4gTUlOX01BWF9JTkxJTkVfU1RFUFM7XG4gIGlmIChwYXJzZWQgPiBNQVhfTUFYX0lOTElORV9TVEVQUykge1xuICAgIGlmICghd2FybmVkLm1heElubGluZVN0ZXBzVmFsdWVzLmhhcyhyYXcpKSB7XG4gICAgICB3YXJuZWQubWF4SW5saW5lU3RlcHNWYWx1ZXMuYWRkKHJhdyk7XG4gICAgICBydW50aW1lTG9nZ2VyLndhcm4oJ1dPUktGTE9XX01BWF9JTkxJTkVfU1RFUFMgYWJvdmUgbWF4aW11bTsgY2xhbXBlZCcsIHtcbiAgICAgICAgcmF3LFxuICAgICAgICBjbGFtcGVkVmFsdWU6IE1BWF9NQVhfSU5MSU5FX1NURVBTLFxuICAgICAgICBtYXhWYWx1ZTogTUFYX01BWF9JTkxJTkVfU1RFUFMsXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIE1BWF9NQVhfSU5MSU5FX1NURVBTO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbi8qKlxuICogVXBwZXIgYm91bmQgb24gdGhlIHNlcmlhbGl6ZWQgc3RlcCBpbnB1dCB0aGF0IHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoIHdpbGxcbiAqIGlubGluZSBpbnRvIHRoZSBxdWV1ZSBtZXNzYWdlJ3MgYHN0ZXBJbnB1dGAuXG4gKlxuICogVmVyY2VsIFF1ZXVlcyBoYXMgbm8gaGFyZCBtZXNzYWdlLXNpemUgY2FwIChib2RpZXMgYWJvdmUgaXRzIH4yNTYgS0JcbiAqIGlubGluZSB0aHJlc2hvbGQgdHJhbnNwYXJlbnRseSBzcGlsbCB0byBTMy1iYWNrZWQgc3RvcmFnZSksIHNvIHRoaXMgYm91bmRcbiAqIGlzIGEgY29zdC9sYXRlbmN5IGNob2ljZSwgbm90IGEgcmVqZWN0aW9uIGd1YXJkOiB0aGUgbWVzc2FnZSBhbHNvIGNhcnJpZXNcbiAqIHRoZSBydW5JZCwgc3RlcElkLCBzdGVwTmFtZSwgYW5kIHRyYWNlIGNhcnJpZXIgYWxvbmdzaWRlIENCT1IgZnJhbWluZ1xuICogb3ZlcmhlYWQsIGFuZCBzdGF5aW5nIHVuZGVyIHRoZSBxdWV1ZSdzIGlubGluZSB0aHJlc2hvbGQga2VlcHMgc3RlcFxuICogbWVzc2FnZXMgb24gaXRzIGZhc3QgaW5saW5lIHBhdGggaW5zdGVhZCBvZiBwYXlpbmcgYW4gUzMgc3RvcmUrZmV0Y2hcbiAqIGRvdWJsZS1ob3AgZm9yIGJ5dGVzIHRoYXQgYWxyZWFkeSBsaXZlIGluIHRoZSBldmVudCBsb2cuIEFib3ZlIHRoaXMgc2l6ZVxuICogdGhlIGRpc3BhdGNoIGZhbGxzIGJhY2sgdG8gdGhlIHNlcXVlbnRpYWwgcGF0aCAoYHN0ZXBfY3JlYXRlZGAgd3JpdGUsIHRoZW5cbiAqIGEgcGF5bG9hZC1sZXNzIHF1ZXVlIG1lc3NhZ2UpLlxuICovXG5leHBvcnQgY29uc3QgTUFYX1JFU0lMSUVOVF9TVEVQX0lOUFVUX0JZVEVTID0gMTI4ICogMTAyNDtcblxuLyoqXG4gKiBXaGV0aGVyIHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoIGlzIGVuYWJsZWQ6IHRoZSBzdXNwZW5zaW9uIGhhbmRsZXJcbiAqIHBhcmFsbGVsaXplcyBlYWNoIG5ld2x5IGNyZWF0ZWQgc3RlcCdzIGBzdGVwX2NyZWF0ZWRgIGV2ZW50IHdyaXRlIHdpdGggaXRzXG4gKiBzdGVwLWV4ZWN1dGlvbiBxdWV1ZSBwdWJsaXNoLCBjYXJyeWluZyB0aGUgc2VyaWFsaXplZCBzdGVwIGlucHV0IGluIHRoZVxuICogcXVldWUgbWVzc2FnZSAoYHN0ZXBJbnB1dGApIHNvIHRoZSBjb25zdW1lciBjYW4gaWRlbXBvdGVudGx5IHJlLWVuc3VyZSB0aGVcbiAqIGV2ZW50IGlmIHRoZSBkaXJlY3Qgd3JpdGUgZmFpbGVkIHRyYW5zaWVudGx5LiBNaXJyb3JzIHRoZSByZXNpbGllbnQgc3RhcnRcbiAqIChgcnVuSW5wdXRgKSBwYXR0ZXJuIChhbmQgdGhlIGxlZ2FjeSBsYXp5IGhvb2sgcmVzdW1lJ3MgYGhvb2tJbnB1dGAsIHdoaWNoXG4gKiBjdXJyZW50IHByb2R1Y2VycyBubyBsb25nZXIgc2VuZCkuXG4gKlxuICogKipPZmYgYnkgZGVmYXVsdC4qKiBFbmFibGUgdmlhIGBXT1JLRkxPV19SRVNJTElFTlRfU1RFUF9ESVNQQVRDSD0xYC5cbiAqXG4gKiBUaGUgcXVldWUgcHVibGlzaCByYWNlcyB0aGUgY3JlYXRlJ3MgdmVyZGljdCwgYW5kIGEgY3JlYXRlIGNhbiBjb21lIGJhY2tcbiAqIHJlZnVzZWQ6IGFzIGEgZHVwbGljYXRlIHRoaXMgcmVwbGF5IHNob3VsZCBzdG9wIHB1cnN1aW5nLCBvciBhcyBhIHN0YWxlXG4gKiB3cml0ZSBvbiBhIFdvcmxkIHRoYXQgcmVmdXNlcyByYXRoZXIgdGhhbiByZXBvcnRzLiBFaXRoZXIgd2F5IHRoZSBtZXNzYWdlXG4gKiBjYXJyeWluZyB0aGUgcGF5bG9hZCBpcyBhbHJlYWR5IG91dCwgc28gdGhlIGNvbnN1bWVyIGNhbiBtYXRlcmlhbGl6ZSBhIHN0ZXBcbiAqIHdob3NlIGNyZWF0ZSB3YXMgcmVmdXNlZCwgYW5kIG5vdGhpbmcgb3JkZXJzIHRoZSB2ZXJkaWN0IGJlZm9yZSB0aGVcbiAqIGNvbnN1bWVyJ3MgcmVkZWxpdmVyeSByZS1lbnN1cmUuIEVuYWJsaW5nIHRoaXMgdHJhZGVzIHRoYXQgd2luZG93IGZvciB0aGVcbiAqIGxhdGVuY3kgdGhlIHBhcmFsbGVsIHB1Ymxpc2ggc2F2ZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1Jlc2lsaWVudFN0ZXBEaXNwYXRjaEVuYWJsZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiBwcm9jZXNzLmVudi5XT1JLRkxPV19SRVNJTElFTlRfU1RFUF9ESVNQQVRDSCA9PT0gJzEnO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYmF0Y2hlZCBldmVudCB0cmFuc2l0aW9ucyBhcmUgZW5hYmxlZDogdGhlIHN1c3BlbnNpb24gaGFuZGxlciBmb2xkc1xuICogYSBjbGVhbiBmYW4tb3V0J3MgYHN0ZXBfY3JlYXRlZGAgKyBgd2FpdF9jcmVhdGVkYCB3cml0ZXMgaW50byBvbmVcbiAqIGB3b3JsZC5ldmVudHMuY3JlYXRlQmF0Y2hgIGNhbGwgKG9uZSBkdXJhYmxlIHdyaXRlLCBwZXItZXZlbnQgb3V0Y29tZXMpXG4gKiBpbnN0ZWFkIG9mIG9uZSB3cml0ZSBwZXIgZXZlbnQuIE9ubHkgZW5nYWdlcyB3aGVuIHRoZSBXb3JsZCBpbXBsZW1lbnRzIHRoZVxuICogb3B0aW9uYWwgYGV2ZW50cy5jcmVhdGVCYXRjaGAgQU5EIHRoZSBydW4gaXMgb24gc2xvdCBpZGVudGl0eVxuICogKHNwZWNWZXJzaW9uID49IDYpIEFORCB0aGUgc3VzcGVuc2lvbiBjYXJyaWVzIG5vIGF0dHJpYnV0ZS9ob29rIHdyaXRlcyBhbmRcbiAqIG5vIHJlc2lsaWVudCBzdGVwIGRpc3BhdGNoLiBFdmVyeXRoaW5nIGVsc2Uga2VlcHMgdGhlIHNpbmdsZS1ldmVudCBwYXRoXG4gKiBieXRlLWZvci1ieXRlLlxuICpcbiAqIFJlYWRzIGBwcm9jZXNzLmVudi5XT1JLRkxPV19CQVRDSF9UUkFOU0lUSU9OU2AgbGF6aWx5LiBEZWZhdWx0ICoqT04qKjtcbiAqIGRpc2FibGVkIG9ubHkgYnkgYW4gZXhwbGljaXQgYCcwJ2AgLyBgJ2ZhbHNlJ2AgKGNhc2UtaW5zZW5zaXRpdmUpLCB0aGVcbiAqIG9wZXJhdG9yIGVzY2FwZSBoYXRjaCB0aGF0IHJlc3RvcmVzIHRoZSBleGFjdCBwcmlvciBvbmUtd3JpdGUtcGVyLWV2ZW50XG4gKiBwYXRoLCBtaXJyb3JpbmcgYFdPUktGTE9XX1RVUkJPYCdzIGtpbGwtc3dpdGNoIHNoYXBlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNCYXRjaFRyYW5zaXRpb25zRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfQkFUQ0hfVFJBTlNJVElPTlM7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09ICcnKSByZXR1cm4gdHJ1ZTtcbiAgcmV0dXJuICEocmF3ID09PSAnMCcgfHwgcmF3LnRvTG93ZXJDYXNlKCkgPT09ICdmYWxzZScpO1xufVxuXG4vKipcbiAqIENlaWxpbmcgb24gZXZlbnRzIHBlciBgY3JlYXRlQmF0Y2hgIGNhbGwgZnJvbSB0aGUgYmF0Y2hlZCBmYW4tb3V0IGZvbGQuXG4gKiBNaXJyb3JzIHRoZSBzZXJ2ZXIncyB0cmFuc2FjdGlvbiBidWRnZXRzIHdpdGggYSBjb21mb3J0YWJsZSBtYXJnaW46IGVhY2hcbiAqIGZhbi1vdXQgZXZlbnQgY29zdHMgMiB0cmFuc2FjdGlvbiBpdGVtcyBzZXJ2ZXItc2lkZSAoZW50aXR5ICsgZXZlbnQgcm93KVxuICogYWdhaW5zdCB0aGUgMTAwLWl0ZW0gRHluYW1vREIgY2FwLCBhbmQgaW5saW5lIHBheWxvYWRzIGNvdW50IGFnYWluc3QgYVxuICogNzY4IEtCIGJ5dGUgYnVkZ2V0LCBzbyAzMiBldmVudHMgc3RheXMgd2VsbCB1bmRlciBib3RoLCBhbmQgYSBmYW4tb3V0IGxhcmdlclxuICogdGhhbiB0aGlzIGNvbW1pdHMgaW4gc3VjY2Vzc2l2ZSBiYXRjaGVzIChzcGxpdCBiYXRjaGVzIGxvc2VcbiAqIGNyb3NzLWJhdGNoIGF0b21pY2l0eSwgd2hpY2ggaXMgZXhhY3RseSB0b2RheSdzIHBlci1ldmVudC13cml0ZSBjcmFzaFxuICogc3VyZmFjZSwgYW5kIGV2ZXJ5IGJhdGNoIHN0aWxsIGNvbnZlcmdlcyBvbiByZXRyeSB2aWEgcGVyLWV2ZW50IDQwOXMpLlxuICovXG5leHBvcnQgY29uc3QgTUFYX0JBVENIX0ZBTk9VVF9FVkVOVFMgPSAzMjtcblxuLyoqXG4gKiBPcHRpb25hbCBjbGllbnQtc2lkZSBvdmVycmlkZSBmb3IgdGhlIHNlcnZlci1zdXBwbGllZCBwZXItcnVuIGV2ZW50IGNlaWxpbmcuXG4gKiBXaGVuIHNldCB0byBhIHBvc2l0aXZlIGludGVnZXIsIHRoZSBydW50aW1lIGNsYW1wcyB0aGUgc2VydmVyJ3MgbGltaXQgKmRvd24qXG4gKiB0byB0aGlzIHZhbHVlIChuZXZlciByYWlzZXMgaXQpIHNvIGVuZm9yY2VtZW50IGNhbiBiZSBleGVyY2lzZWQgd2l0aG91dCBhXG4gKiBzZXJ2ZXItc2lkZSBjaGFuZ2UuIGB1bmRlZmluZWRgICh1bnNldCkg4oeSIHVzZSB0aGUgc2VydmVyIHZhbHVlIGFzLWlzLlxuICpcbiAqIFJlYWRzIGBwcm9jZXNzLmVudi5XT1JLRkxPV19NQVhfRVZFTlRTX09WRVJSSURFYCBsYXppbHkgc28gdGVzdHMgYW5kXG4gKiBkZXBsb3ltZW50cyBjYW4gb3ZlcnJpZGUgcGVyIGludm9jYXRpb24uIEludmFsaWQgdmFsdWVzIGZhbGwgYmFjayB0byB1bnNldFxuICogKG5vIHRocm93OiB0aGUgZW52IHZhciBpcyBhbiBlc2NhcGUgaGF0Y2gpIGFuZCBlbWl0IGEgb25lLXRpbWUgd2FybmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1heEV2ZW50c092ZXJyaWRlKCk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LldPUktGTE9XX01BWF9FVkVOVFNfT1ZFUlJJREU7XG4gIGlmICghcmF3KSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmF3KTtcbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHBhcnNlZCkgfHwgcGFyc2VkIDw9IDApIHtcbiAgICBpZiAoIXdhcm5lZC5tYXhFdmVudHNWYWx1ZXMuaGFzKHJhdykpIHtcbiAgICAgIHdhcm5lZC5tYXhFdmVudHNWYWx1ZXMuYWRkKHJhdyk7XG4gICAgICBydW50aW1lTG9nZ2VyLndhcm4oXG4gICAgICAgICdJZ25vcmluZyBXT1JLRkxPV19NQVhfRVZFTlRTX09WRVJSSURFOiBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyOyB1c2luZyBzZXJ2ZXIgbGltaXQnLFxuICAgICAgICB7IHJhdyB9XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbi8qKlxuICogV2hldGhlciBvcHRpbWlzdGljIGlubGluZSBzdGVwIHN0YXJ0IGlzIGVuYWJsZWQuIFdoZW4gb24sIHRoZSBvd25lZC1pbmxpbmVcbiAqIHBhdGggYmVnaW5zIHJ1bm5pbmcgYSBicmFuZC1uZXcgc3RlcCdzIGJvZHkgKmJlZm9yZSogaXRzIGxhenkgYHN0ZXBfc3RhcnRlZGBcbiAqIG5ldHdvcmsgY2FsbCByZXNvbHZlcyAodGhlIGlucHV0IGlzIGFscmVhZHkga25vd24gbG9jYWxseSksIGF3YWl0aW5nIHRoZVxuICogYHN0ZXBfc3RhcnRlZGAgb25seSBiZWZvcmUgdGhlIHRlcm1pbmFsIHdyaXRlLlxuICpcbiAqIFRoaXMgY2FuIHJ1biBhIHN0ZXAgYm9keSBtb3JlIHRoYW4gb25jZSB3aGVuIGhhbmRsZXJzIHJhY2UgZm9yIHRoZSBzYW1lXG4gKiBzdGVwJ3MgY3JlYXRlLWNsYWltOiBib3RoIHJ1biB0aGUgYm9keSBiZWZvcmUgb25lIHdpbnMuIFRoYXQgaXMgdW5zYWZlIGZvclxuICogc3RlcHMgd2l0aCBub24taWRlbXBvdGVudCBzaWRlIGVmZmVjdHM7IGluIHBhcnRpY3VsYXIsIHR3byBjb25jdXJyZW50IHJ1bnNcbiAqIG9mIGEgc3RlcCB0aGF0IHdyaXRlcyB0byB0aGUgd29ya2Zsb3cgc3RyZWFtIChlLmcuIGFuIEFJIGFnZW50IHN0cmVhbWluZ1xuICogdG9rZW5zKSBjYW4gaW50ZXJsZWF2ZSBhbmQgY29ycnVwdCB0aGUgc3RyZWFtIGRhdGEuIFNvIHRoZSBvcHRpbWl6YXRpb24gaXNcbiAqICoqb2ZmIGJ5IGRlZmF1bHQqKiBhbmQgbXVzdCBiZSBleHBsaWNpdGx5IG9wdGVkIGludG8gcGVyIGRlcGxveW1lbnQuXG4gKlxuICogUmVhZHMgYHByb2Nlc3MuZW52LldPUktGTE9XX09QVElNSVNUSUNfSU5MSU5FX1NUQVJUYCBsYXppbHkuIERlZmF1bHQgT0ZGO1xuICogZW5hYmxlZCBvbmx5IGJ5IGFuIGV4cGxpY2l0IGAnMSdgIC8gYCd0cnVlJ2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc09wdGltaXN0aWNJbmxpbmVTdGFydEVuYWJsZWQoKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LldPUktGTE9XX09QVElNSVNUSUNfSU5MSU5FX1NUQVJUO1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQgfHwgcmF3ID09PSAnJykgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gcmF3ID09PSAnMScgfHwgcmF3LnRvTG93ZXJDYXNlKCkgPT09ICd0cnVlJztcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGFuIG9wZXJhdG9yIGhhcyAqKmV4cGxpY2l0bHkgZGlzYWJsZWQqKiBvcHRpbWlzdGljIGlubGluZSBzdGFydCB2aWFcbiAqIGBXT1JLRkxPV19PUFRJTUlTVElDX0lOTElORV9TVEFSVD0wYCAvIGA9ZmFsc2VgLiBEaXN0aW5jdCBmcm9tIFwidW5zZXRcIjogdW5zZXRcbiAqIGxlYXZlcyB0aGUgb3B0aW1pemF0aW9uIG9mZiBieSBkZWZhdWx0IGJ1dCBsZXRzIHR1cmJvIGZvcmNlIGl0IG9uOyBhbiBleHBsaWNpdFxuICogYDBgL2BmYWxzZWAgaXMgYW4gb3BlcmF0b3Igb3B0LW91dCB0aGF0IHR1cmJvIG11c3QgaG9ub3IgKHR1cmJvJ3MgZm9yY2VkXG4gKiBvcHRpbWlzdGljIHN0YXJ0IHN0aWxsIHJ1bnMgYSBzdGVwIGJvZHkgYmVmb3JlIGBzdGVwX3N0YXJ0ZWRgL2BydW5fc3RhcnRlZGAgaXNcbiAqIGNvbmZpcm1lZCwgdGhlIHByb3BlcnR5IHN1Y2ggYW4gb3BlcmF0b3IgaXMgb3B0aW5nIG91dCBvZiksIHNvXG4gKiBgZm9yY2VPcHRpbWlzdGljU3RhcnRgIGRlZmVycyB0byB0aGlzLiBSZWFkcyB0aGUgZW52IHZhciBsYXppbHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc09wdGltaXN0aWNJbmxpbmVTdGFydEV4cGxpY2l0bHlEaXNhYmxlZCgpOiBib29sZWFuIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfT1BUSU1JU1RJQ19JTkxJTkVfU1RBUlQ7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09ICcnKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiByYXcgPT09ICcwJyB8fCByYXcudG9Mb3dlckNhc2UoKSA9PT0gJ2ZhbHNlJztcbn1cblxuLyoqXG4gKiBXaGV0aGVyIFwidHVyYm8gbW9kZVwiIGlzIGVuYWJsZWQuIFR1cmJvIG1vZGUgZmFzdC1wYXRocyB0aGUgKmZpcnN0IGRlbGl2ZXJ5IG9mXG4gKiB0aGUgZmlyc3QgaW52b2NhdGlvbiogb2YgYSBydW4gKGRldGVjdGVkIGJ5IHRoZSBlbnRyeXBvaW50IHZpYSBgcnVuSW5wdXRgXG4gKiBwcmVzZW5jZSArIGBtZXRhZGF0YS5hdHRlbXB0ID09PSAxYCk6IGl0IGJhY2tncm91bmRzIHRoZSBgcnVuX3N0YXJ0ZWRgIGV2ZW50XG4gKiBjcmVhdGlvbiwgc2tpcHMgdGhlIGluaXRpYWwgZXZlbnQtbG9nIGxvYWQgKG5vdGhpbmcgaGFzIGJlZW4gd3JpdHRlbiB5ZXQpLFxuICogYW5kIGZvcmNlcyBvcHRpbWlzdGljIGlubGluZSBzdGVwIHN0YXJ0IGZvciB0aGF0IGludm9jYXRpb24sIGluZGVwZW5kZW50IG9mXG4gKiBgV09SS0ZMT1dfT1BUSU1JU1RJQ19JTkxJTkVfU1RBUlRgLlxuICpcbiAqIEZvcmNpbmcgb3B0aW1pc3RpYyBzdGFydCBpcyBzYWZlIGhlcmUgYmVjYXVzZSB0aGUgZmlyc3QgZGVsaXZlcnkgaGFzIG5vXG4gKiBjb25jdXJyZW50IHBlZXIgaGFuZGxlciB0byByYWNlIHRoZSBzdGVwIGNyZWF0ZS1jbGFpbSwgc28gYSBzdGVwIGJvZHkgcnVuc1xuICogZXhhY3RseSBvbmNlLiBUaGF0IHNpbmdsZS1oYW5kbGVyIGd1YXJhbnRlZSBlbmRzIGFzIHNvb24gYXMgdGhlIHJ1biBjcmVhdGVzIGFcbiAqIGhvb2sgb3Igd2FpdCAod2hpY2ggaW50cm9kdWNlIHJlc3VtZS9wYXJhbGxlbCBpbnZvY2F0aW9ucyksIHNvIHRoZSBydW50aW1lXG4gKiBleGl0cyB0dXJibyBhdCB0aGF0IHBvaW50LlxuICpcbiAqIFJlYWRzIGBwcm9jZXNzLmVudi5XT1JLRkxPV19UVVJCT2AgbGF6aWx5LiBEZWZhdWx0ICoqT04qKjsgZGlzYWJsZWQgb25seSBieSBhblxuICogZXhwbGljaXQgYCcwJ2AgLyBgJ2ZhbHNlJ2AgKGNhc2UtaW5zZW5zaXRpdmUpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNUdXJib0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LldPUktGTE9XX1RVUkJPO1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQgfHwgcmF3ID09PSAnJykgcmV0dXJuIHRydWU7XG4gIHJldHVybiAhKHJhdyA9PT0gJzAnIHx8IHJhdy50b0xvd2VyQ2FzZSgpID09PSAnZmFsc2UnKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHRoZSBRdWlja0pTIGVuZ2luZSdzIGJhc2VsaW5lLXNuYXBzaG90IHN0YXJ0dXAgb3B0aW1pemF0aW9uIGlzXG4gKiBlbmFibGVkIChkZWZhdWx0IE9OKS4gV2hlbiBvbiwgdGhlIGVuZ2luZSBoeWRyYXRlcyBhIFZNIHdpdGggdGhlXG4gKiB3b3JrZmxvdyBidW5kbGUgb25jZSBwZXIgZnVuY3Rpb24gaW5zdGFuY2UsIHNuYXBzaG90cyBpdCwgYW5kIHN0YXJ0c1xuICogZXZlcnkgaW52b2NhdGlvbiBieSByZXN0b3JpbmcgdGhlIHNuYXBzaG90IGluc3RlYWQgb2YgcmUtZXZhbHVhdGluZ1xuICogdGhlIGJ1bmRsZSwgc2tpcHBpbmcgdGhlIGRvbWluYW50IHNoYXJlIG9mIFZNIHN0YXJ0dXAgKG1lYXN1cmVkXG4gKiB+NzdtcyDihpIgfjNtcyB0byBmaXJzdCBzdXNwZW5zaW9uIGZvciBhIDEuM01CIGJ1bmRsZSkuIEJ1bmRsZXMgd2hvc2VcbiAqIG1vZHVsZSBzY29wZSBjb25zdW1lcyByYW5kb21uZXNzLCByZWFkcyB0aGUgY2xvY2ssIG9yIHJlcGxhY2VzIGFcbiAqIHNlcmlhbGl6YXRpb24gaW50cmluc2ljIGFyZSBkZXRlY3RlZCBhdCBoeWRyYXRlIHRpbWUgYW5kXG4gKiBhdXRvbWF0aWNhbGx5IGZhbGwgYmFjayB0byBwZXItaW52b2NhdGlvbiBmcmVzaCBldmFsdWF0aW9uIChzZWVcbiAqIHByZXBhcmVCYXNlbGluZVNuYXBzaG90KS4gU2V0IFdPUktGTE9XX1FVSUNLSlNfQkFTRUxJTkVfU05BUFNIT1Q9MCB0b1xuICogZGlzYWJsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUXVpY2tKU0Jhc2VsaW5lU25hcHNob3RFbmFibGVkKCk6IGJvb2xlYW4ge1xuICBjb25zdCByYXcgPSBwcm9jZXNzLmVudi5XT1JLRkxPV19RVUlDS0pTX0JBU0VMSU5FX1NOQVBTSE9UO1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQgfHwgcmF3ID09PSAnJykgcmV0dXJuIHRydWU7XG4gIHJldHVybiAhKHJhdyA9PT0gJzAnIHx8IHJhdy50b0xvd2VyQ2FzZSgpID09PSAnZmFsc2UnKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHRoZSBOb2RlLmpzIGlubGluZSBsb29wIHJldGFpbnMgYSBzdXNwZW5kZWQgd29ya2Zsb3cgVk0gd2l0aGluIG9uZVxuICogaW52b2NhdGlvbiAoZGVmYXVsdCBPTikuIFdoZW4gb24sIGEgc3RlcC0gb3IgYXR0cmlidXRlLWRyaXZlbiBzdXNwZW5zaW9uIGNhblxuICoga2VlcCB0aGUgbGl2ZSBWTSwgZXZlbnQgY29uc3VtZXIsIGFuZCBoeWRyYXRlZCBzdGF0ZSBldmVuIHdpdGggb3BlbiBob29rcyBvclxuICogd2FpdHMuIFRoZSBuZXh0IGxvb3AgaXRlcmF0aW9uIGFwcGVuZHMgbmV3bHkgZHVyYWJsZSBldmVudHMgaW5zdGVhZCBvZlxuICogcmVidWlsZGluZyB0aGUgYHZtLkNvbnRleHRgIGFuZCByZXBsYXlpbmcgdGhlIHdob2xlIGV2ZW50IGxvZy4gSG9vay0gb3JcbiAqIHdhaXQtb25seSBzdXNwZW5zaW9ucyBwYXJrIHRoZSBpbnZvY2F0aW9uLCB3aGlsZSByZXBsYXkgZGl2ZXJnZW5jZSBmYWxscyBiYWNrXG4gKiB0byB0aGUgb3JkaW5hcnkgZHVyYWJsZSByZXBsYXkgcGF0aC4gUXVpY2tKUyBtYW5hZ2VzIGl0cyBvd24gcmV0YWluZWQgbG9vcC5cbiAqXG4gKiBgV09SS0ZMT1dfUkVUQUlORURfVk09MGAgKG9yIGBmYWxzZWApIGlzIHRoZSBraWxsIHN3aXRjaDogZXZlcnkgaXRlcmF0aW9uXG4gKiByZXBsYXlzIHRoZSBOb2RlLmpzIGVuZ2luZSBmcm9tIHNjcmF0Y2ggaW4gYSBmcmVzaCBWTSwgbWF0Y2hpbmcgdGhlXG4gKiBwcmUtcmV0ZW50aW9uIGJlaGF2aW9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNWbVJldGVudGlvbkVuYWJsZWQoKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LldPUktGTE9XX1JFVEFJTkVEX1ZNO1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQgfHwgcmF3ID09PSAnJykgcmV0dXJuIHRydWU7XG4gIHJldHVybiAhKHJhdyA9PT0gJzAnIHx8IHJhdy50b0xvd2VyQ2FzZSgpID09PSAnZmFsc2UnKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGlubGluZSBzdGVwIG93bmVyc2hpcCBpcyBlbmFibGVkIChkZWZhdWx0IE9OKS4gV2hlbiBvbiwgdGhlIGxhenlcbiAqIGBzdGVwX3N0YXJ0ZWRgIHRoYXQgY3JlYXRlcyBhbiBpbmxpbmUgc3RlcCByZWNvcmRzIHRoZSBvd25pbmcgcXVldWVcbiAqIG1lc3NhZ2UgSUQsIGFuZCB3YWtlIHJlcGxheXMgdGhhdCBvYnNlcnZlIGFuIGFjdGl2ZWx5LW93bmVkIHN0ZXAgZW5xdWV1ZSBhXG4gKiAqZGVsYXllZCBiYWNrc3RvcCogbWVzc2FnZSBpbnN0ZWFkIG9mIGltbWVkaWF0ZWx5IHJlcXVldWVpbmcgaXQsIGZpeGluZ1xuICogZHVwbGljYXRlIGlubGluZSBzdGVwIGV4ZWN1dGlvbiB3aGVuIGEgaG9vay93YWl0IHdha2VzIGEgcnVuIG1pZC1zdGVwXG4gKiAodmVyY2VsL3dvcmtmbG93IzI3ODApLlxuICpcbiAqIGBXT1JLRkxPV19JTkxJTkVfT1dORVJTSElQPTBgIChvciBgZmFsc2VgKSBpcyB0aGUga2lsbCBzd2l0Y2g6IGRpc3BhdGNoXG4gKiByZXZlcnRzIHRvIHRoZSB1bmNvbmRpdGlvbmFsIGltbWVkaWF0ZSByZXF1ZXVlLiBTdGFtcGluZyBpcyB1bmFmZmVjdGVkOlxuICogdGhlIHJlY29yZGVkIG93bmVyTWVzc2FnZUlkIGlzIGluZXJ0IGRhdGEgd2hlbiB0aGUgc3dpdGNoIGlzIG9mZi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSW5saW5lT3duZXJzaGlwRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnYuV09SS0ZMT1dfSU5MSU5FX09XTkVSU0hJUDtcbiAgaWYgKHJhdyA9PT0gdW5kZWZpbmVkIHx8IHJhdyA9PT0gJycpIHJldHVybiB0cnVlO1xuICByZXR1cm4gIShyYXcgPT09ICcwJyB8fCByYXcudG9Mb3dlckNhc2UoKSA9PT0gJ2ZhbHNlJyk7XG59XG5cbi8qKlxuICogRGVmYXVsdCBpbmxpbmUtb3duZXJzaGlwIGxlYXNlLCBpbiBzZWNvbmRzOiBob3cgbG9uZyBhZnRlciBhIHN0ZXAncyBsYXRlc3RcbiAqIChzdGFtcGVkKSBgc3RlcF9zdGFydGVkYCBhIG5vbi1vd25lciBpbnZvY2F0aW9uIGFzc3VtZXMgdGhlIG93bmluZ1xuICogaW52b2NhdGlvbiBtYXkgc3RpbGwgYmUgYWxpdmUuIFdpdGhpbiB0aGUgbGVhc2UsIHdha2UgcmVwbGF5cyBlbnF1ZXVlIHRoZVxuICogc3RlcCdzIGJhY2tzdG9wIG1lc3NhZ2Ugd2l0aCBgZGVsYXlTZWNvbmRzID0gbGVhc2UgcmVtYWluaW5nYCBpbnN0ZWFkIG9mXG4gKiBpbW1lZGlhdGVseTsgcGFzdCBpdCwgdGhleSBlbnF1ZXVlIGltbWVkaWF0ZWx5ICh0b2RheSdzIGJlaGF2aW9yKS5cbiAqXG4gKiBXaHkgYSBmaXhlZCA4NjAgYW5kIG5vdCBhIHZhbHVlIGRlcml2ZWQgZnJvbSB0aGUgZnVuY3Rpb24ncyBgbWF4RHVyYXRpb25gOlxuICogbmVpdGhlciBydW50aW1lIG5vciBidWlsZCB0aW1lIGNhbiBzZWUgdGhlIHJlc29sdmVkIHZhbHVlOiBidWlsZGVycyBlbWl0XG4gKiBgbWF4RHVyYXRpb246ICdtYXgnYCwgd2hpY2ggdGhlIHBsYXRmb3JtIHJlc29sdmVzIHBlci1wbGFuIGF0IGRlcGxveSwgYW5kXG4gKiBubyBlbnYgdmFyIG9yIHJlcXVlc3QtY29udGV4dCBkZWFkbGluZSBBUEkgZXhwb3NlcyB0aGUgcmVzdWx0LiBUaGUgYm91bmRcbiAqIGNvbWVzIGZyb20gYSBwbGF0Zm9ybSBydWxlIGluc3RlYWQ6IGR1cmF0aW9ucyBhYm92ZSA4MDBzIHJlcXVpcmUgZXhwbGljaXRcbiAqIHBlci1mdW5jdGlvbiBudW1lcmljIGNvbmZpZywgc28gYSBidWlsZGVyLWVtaXR0ZWQgYCdtYXgnYCByZXNvbHZlcyB0byBhdFxuICogbW9zdCA4MDBzLCBhbmQgODYwcyB0aGVyZWZvcmUgZG9taW5hdGVzIGFueSB3b3JrZmxvdyByb3V0ZSdzIGludm9jYXRpb25cbiAqIGxpZmV0aW1lIHBsdXMgc2NoZWR1bGluZyBzbGFjay4gUmV2aXNpdCB3aGVuIHRoYXQgY2VpbGluZyBtb3ZlcyAodGhlXG4gKiAzMC1taW51dGUgZHVyYXRpb24gYmV0YSBiZWNvbWluZyByZWFjaGFibGUgdmlhIGAnbWF4J2Agd291bGQgaW52YWxpZGF0ZVxuICogdGhlIGJvdW5kKS4gV29ybGRzIHdpdGhvdXQgYW4gaW52b2NhdGlvbiBraWxsIGJvdW5kICh3b3JsZC1sb2NhbCxcbiAqIHNlbGYtaG9zdGVkKSBnZXQgbm8gZGVhdGggcHJvb2YgZnJvbSBhbnkgY29uc3RhbnQuIFRoZXJlIHRoZSBpbi1wcm9jZXNzXG4gKiBzaW5nbGUtZmxpZ2h0IGxheWVyIChzdGVwLXNpbmdsZS1mbGlnaHQudHMpIGlzIHdoYXQgbWFrZXMgYSBiYWNrc3RvcFxuICogZmlyaW5nIG1pZC1zdGVwIGhhcm1sZXNzLlxuICpcbiAqIDg2MCBhbHNvIHN0YXlzIHVuZGVyIHRoZSBxdWV1ZSdzIDkwMHMgbWF4aW11bSBkZWxheSAoU1FTIGNhcCksIHNvIGFcbiAqIGJhY2tzdG9wJ3MgZnVsbCBsZWFzZSByZW1haW5kZXIgYWx3YXlzIGZpdHMgaW4gYSBzaW5nbGUgZGVsYXllZCBtZXNzYWdlLlxuICpcbiAqIE92ZXJyaWRlIHZpYSBgV09SS0ZMT1dfSU5MSU5FX09XTkVSU0hJUF9MRUFTRV9TRUNPTkRTYCAoY2xhbXBlZCB0b1xuICogMS4uYE1BWF9JTkxJTkVfT1dORVJTSElQX0xFQVNFX1NFQ09ORFNgKS5cbiAqL1xuZXhwb3J0IGNvbnN0IElOTElORV9PV05FUlNISVBfTEVBU0VfU0VDT05EUyA9IDg2MDtcblxuLyoqXG4gKiBVcHBlciBib3VuZCBmb3IgdGhlIGxlYXNlIGVudiBvdmVycmlkZS4gOTAwcyBpcyB0aGUgcXVldWUncyBtYXhpbXVtXG4gKiBwZXItbWVzc2FnZSBkZWxheSAoU1FTIGNhcCkuIEEgbG9uZ2VyIGxlYXNlIHdvdWxkIG5lZWQgZGVsYXkgY2hhaW5pbmdcbiAqIGxpa2UgbG9uZyB3YWl0cyB1c2U7IGNsYW1wIGluc3RlYWQgc28gb25lIGRlbGF5ZWQgbWVzc2FnZSBhbHdheXMgc3VmZmljZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBNQVhfSU5MSU5FX09XTkVSU0hJUF9MRUFTRV9TRUNPTkRTID0gOTAwO1xuXG4vKipcbiAqIEVmZmVjdGl2ZSBpbmxpbmUtb3duZXJzaGlwIGxlYXNlLiBPdmVycmlkZSB2aWFcbiAqIGBXT1JLRkxPV19JTkxJTkVfT1dORVJTSElQX0xFQVNFX1NFQ09ORFNgLCBlLmcuIHJhaXNlIGl0IG9uIHNlbGYtaG9zdGVkXG4gKiBtdWx0aS1pbnN0YW5jZSB3b3JsZHMgd2l0aCBsb25nLXJ1bm5pbmcgc3RlcHMgdG8gd2lkZW4gdGhlIHdpbmRvdyBpbiB3aGljaFxuICogYSBsaXZlIG93bmVyIGlzIHByb3RlY3RlZCBmcm9tIGEgY29uY3VycmVudCBiYWNrc3RvcCBleGVjdXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRJbmxpbmVPd25lcnNoaXBMZWFzZVNlY29uZHMoKTogbnVtYmVyIHtcbiAgcmV0dXJuIGVudk51bWJlcihcbiAgICAnV09SS0ZMT1dfSU5MSU5FX09XTkVSU0hJUF9MRUFTRV9TRUNPTkRTJyxcbiAgICBJTkxJTkVfT1dORVJTSElQX0xFQVNFX1NFQ09ORFMsXG4gICAgeyBpbnRlZ2VyOiB0cnVlLCBtaW46IDEsIG1heDogTUFYX0lOTElORV9PV05FUlNISVBfTEVBU0VfU0VDT05EUyB9XG4gICk7XG59XG5cbi8vIEEgcmVwbGF5LWNvbnN1bWVyIG1pc21hdGNoIGNhbiBiZSBjYXVzZWQgYnkgYSB0cmFuc2llbnQgZGl2ZXJnZW50IHJlcGxheVxuLy8gcmF0aGVyIHRoYW4gYW4gaW52YWxpZCBwZXJzaXN0ZWQgaGlzdG9yeS4gUXVldWUgYm91bmRlZCByZWNvdmVyeSByZXBsYXlzXG4vLyBiZWZvcmUgcmVjb3JkaW5nIHRlcm1pbmFsIGNvcnJ1cHRpb24gZm9yIGEgcnVuIHRoYXQgY2Fubm90IHJlcGxheS5cbmV4cG9ydCBjb25zdCBSRVBMQVlfRElWRVJHRU5DRV9NQVhfUkVUUklFUyA9IDM7XG5cbi8qKlxuICogRWZmZWN0aXZlIHJlcGxheS1kaXZlcmdlbmNlIHJlY292ZXJ5IGJ1ZGdldC4gT3ZlcnJpZGUgdmlhXG4gKiBgV09SS0ZMT1dfUkVQTEFZX0RJVkVSR0VOQ0VfTUFYX1JFVFJJRVNgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVwbGF5RGl2ZXJnZW5jZU1heFJldHJpZXMoKTogbnVtYmVyIHtcbiAgcmV0dXJuIGVudk51bWJlcihcbiAgICAnV09SS0ZMT1dfUkVQTEFZX0RJVkVSR0VOQ0VfTUFYX1JFVFJJRVMnLFxuICAgIFJFUExBWV9ESVZFUkdFTkNFX01BWF9SRVRSSUVTLFxuICAgIHsgaW50ZWdlcjogdHJ1ZSB9XG4gICk7XG59XG5cbi8vIEEgc3RhbGUtc25hcHNob3QgcmVqZWN0aW9uICg0MTIpIG1lYW5zIHRoZSByZXBsYXkncyBldmVudCBsb2cgd2FzIG1pc3NpbmcgYW5cbi8vIGV2ZW50IHRoZSBXb3JsZCBoYWQgYWxyZWFkeSByZWNvcmRlZCwgc28gdGhlIHJlcGxheSBpcyByZS1kZXJpdmVkIGZyb20gYVxuLy8gY29ycmVjdGVkIGxvZyBpbnNpZGUgdGhlIHNhbWUgaW52b2NhdGlvbi4gQm91bmRlZCBiZWNhdXNlIGEgcGVyc2lzdGVudGx5XG4vLyByZWplY3RlZCB3cml0ZSBzaG91bGQgZXNjYWxhdGUgcmF0aGVyIHRoYW4gc3BpbjogYWZ0ZXIgdGhpcyBtYW55IHJlc3RhcnRzIHRoZVxuLy8gcnVuIGlzIHJlLWludm9rZWQgKGEgbmV3IGludm9jYXRpb24sIHBvc3NpYmx5IGluIGEgZGlmZmVyZW50IHJlZ2lvbiksIGFuZCB0aGVcbi8vIHJ1bi1sZXZlbCBidWRnZXQgYmVsb3cgdGhlbiBhcHBsaWVzLlxuZXhwb3J0IGNvbnN0IFBSRUNPTkRJVElPTl9NQVhfSU5QUk9DRVNTX1JFU1RBUlRTID0gMztcblxuLyoqXG4gKiBFZmZlY3RpdmUgaW4tcHJvY2VzcyByZXBsYXktcmVzdGFydCBidWRnZXQgZm9yIHN0YWxlLXNuYXBzaG90IHJlamVjdGlvbnMuXG4gKiBPdmVycmlkZSB2aWEgYFdPUktGTE9XX1BSRUNPTkRJVElPTl9NQVhfSU5QUk9DRVNTX1JFU1RBUlRTYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFByZWNvbmRpdGlvbk1heEluUHJvY2Vzc1Jlc3RhcnRzKCk6IG51bWJlciB7XG4gIHJldHVybiBlbnZOdW1iZXIoXG4gICAgJ1dPUktGTE9XX1BSRUNPTkRJVElPTl9NQVhfSU5QUk9DRVNTX1JFU1RBUlRTJyxcbiAgICBQUkVDT05ESVRJT05fTUFYX0lOUFJPQ0VTU19SRVNUQVJUUyxcbiAgICB7IGludGVnZXI6IHRydWUgfVxuICApO1xufVxuXG4vLyBUaGUgaW4tcHJvY2VzcyBidWRnZXQgYWJvdmUgaXMgcGVyLWludm9jYXRpb24sIGFuZCBhIHJlLWludm9jYXRpb24gdGhhdFxuLy8gZW5xdWV1ZXMgYSBmcmVzaCBtZXNzYWdlIGFsc28gcmVzdGFydHMgdGhlIHF1ZXVlJ3MgZGVsaXZlcnkgY291bnQsIHNvIHdpdGhvdXRcbi8vIGEgY291bnRlciBjYXJyaWVkIG9uIHRoZSBtZXNzYWdlIGEgcGVybWFuZW50bHkgZmVuY2VkIHJ1biBoYXMgbm8gcnVuLWxldmVsXG4vLyBib3VuZCBhdCBhbGwuIEl0IGNhbiBzdGF5IGZlbmNlZCB3aXRob3V0IGFueSBwZXJtYW5lbnQgZmF1bHQgKGEgZnVsbCByZWxvYWRcbi8vIGlzIG5vdCBhdG9taWMgYWNyb3NzIHBhZ2VzLCBzbyBhIGJ1c3kgcnVuIGNhbiBhY3F1aXJlIGEgbmV3IGhvbGUgb24gZXZlcnlcbi8vIHJlbG9hZCksIHNvIHRoZSBjaGFpbiBpcyBjb3VudGVkIGFuZCB0aGUgcnVuIGZhaWxzIG9uY2UgdGhpcyBtYW55XG4vLyByZS1pbnZvY2F0aW9ucyBoYXZlIGJlZW4gc3BlbnQgb24gc3RhbGUtc25hcHNob3QgcmVqZWN0aW9ucy5cbmV4cG9ydCBjb25zdCBQUkVDT05ESVRJT05fTUFYX1JFSU5WT0NBVElPTlMgPSA1O1xuXG4vKipcbiAqIEVmZmVjdGl2ZSBwZXItcnVuIGJ1ZGdldCBmb3IgcmUtaW52b2NhdGlvbnMgY2F1c2VkIGJ5IHN0YWxlLXNuYXBzaG90XG4gKiByZWplY3Rpb25zLiBPdmVycmlkZSB2aWEgYFdPUktGTE9XX1BSRUNPTkRJVElPTl9NQVhfUkVJTlZPQ0FUSU9OU2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQcmVjb25kaXRpb25NYXhSZWludm9jYXRpb25zKCk6IG51bWJlciB7XG4gIHJldHVybiBlbnZOdW1iZXIoXG4gICAgJ1dPUktGTE9XX1BSRUNPTkRJVElPTl9NQVhfUkVJTlZPQ0FUSU9OUycsXG4gICAgUFJFQ09ORElUSU9OX01BWF9SRUlOVk9DQVRJT05TLFxuICAgIHsgaW50ZWdlcjogdHJ1ZSB9XG4gICk7XG59XG5cbi8vIEJhY2tvZmYgYmVmb3JlIGEgcHJlY29uZGl0aW9uIHJlLWludm9jYXRpb24uIFVubGlrZSB0aGUgaW4tcHJvY2VzcyByZXN0YXJ0XG4vLyAod2hlcmUgdGhlIHBvaW50IGlzIHRvIHJlLXJlYWQgaW1tZWRpYXRlbHkpLCBhIHJlLWludm9jYXRpb24gb25seSBoYXBwZW5zXG4vLyBhZnRlciB0aGUgaW4tcHJvY2VzcyBidWRnZXQgZmFpbGVkIHRvIGNhdGNoIHVwLCBzbyB0aGUgbG9nIGlzIGJlaW5nIGV4dGVuZGVkXG4vLyBmYXN0ZXIgdGhhbiB0aGlzIHJlcGxheSBjYW4gZm9sbG93IGl0LiBXYWl0aW5nIGxldHMgdGhlIHdyaXRlcnMgcXVpZXNjZS5cbmV4cG9ydCBjb25zdCBQUkVDT05ESVRJT05fUkVJTlZPS0VfREVMQVlfU0VDT05EUyA9IDI7XG5cbi8qKlxuICogRWZmZWN0aXZlIGRlbGF5IGJlZm9yZSBhIHByZWNvbmRpdGlvbiByZS1pbnZvY2F0aW9uLiBPdmVycmlkZSB2aWFcbiAqIGBXT1JLRkxPV19QUkVDT05ESVRJT05fUkVJTlZPS0VfREVMQVlfU0VDT05EU2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQcmVjb25kaXRpb25SZWludm9rZURlbGF5U2Vjb25kcygpOiBudW1iZXIge1xuICByZXR1cm4gZW52TnVtYmVyKFxuICAgICdXT1JLRkxPV19QUkVDT05ESVRJT05fUkVJTlZPS0VfREVMQVlfU0VDT05EUycsXG4gICAgUFJFQ09ORElUSU9OX1JFSU5WT0tFX0RFTEFZX1NFQ09ORFMsXG4gICAgeyBpbnRlZ2VyOiB0cnVlIH1cbiAgKTtcbn1cblxuLy8gQSBkZWxpdmVyeSByZWFjaGluZyBhIGRlcGxveW1lbnQgdGhlIHJ1biBpcyBub3QgcGlubmVkIHRvIGlzIG5vdCB0cmVhdGVkIGFzXG4vLyBwZXJtYW5lbnQuIFJlLXJvdXRlIHRoZSBtZXNzYWdlIGF0IHRoZSBydW4ncyBvd24gZGVwbG95bWVudCBhIGJvdW5kZWQgbnVtYmVyXG4vLyBvZiB0aW1lcyBiZWZvcmUgZmFpbGluZyB0aGUgcnVuIHdpdGggREVQTE9ZTUVOVF9NSVNNQVRDSC5cbmV4cG9ydCBjb25zdCBERVBMT1lNRU5UX01JU01BVENIX01BWF9SRVRSSUVTID0gMztcblxuLyoqXG4gKiBFZmZlY3RpdmUgZGVwbG95bWVudC1taXNtYXRjaCByZS1yb3V0ZSBidWRnZXQuIE92ZXJyaWRlIHZpYVxuICogYFdPUktGTE9XX0RFUExPWU1FTlRfTUlTTUFUQ0hfTUFYX1JFVFJJRVNgOyBgMGAgZmFpbHMgdGhlIHJ1biBvbiB0aGUgZmlyc3RcbiAqIG1pc3JvdXRlZCBkZWxpdmVyeSBpbnN0ZWFkIG9mIGF0dGVtcHRpbmcgcmVjb3ZlcnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXREZXBsb3ltZW50TWlzbWF0Y2hNYXhSZXRyaWVzKCk6IG51bWJlciB7XG4gIHJldHVybiBlbnZOdW1iZXIoXG4gICAgJ1dPUktGTE9XX0RFUExPWU1FTlRfTUlTTUFUQ0hfTUFYX1JFVFJJRVMnLFxuICAgIERFUExPWU1FTlRfTUlTTUFUQ0hfTUFYX1JFVFJJRVMsXG4gICAgeyBpbnRlZ2VyOiB0cnVlLCBtaW46IDAgfVxuICApO1xufVxuIl19
|