@workflow/core 5.0.0-beta.4 → 5.0.0-beta.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/dist/attribute-changes.d.ts +7 -0
  2. package/dist/attribute-changes.d.ts.map +1 -0
  3. package/dist/attribute-changes.js +25 -0
  4. package/dist/capabilities.d.ts +33 -1
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +71 -4
  7. package/dist/capture-stack.d.ts +16 -0
  8. package/dist/capture-stack.d.ts.map +1 -0
  9. package/dist/capture-stack.js +21 -0
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +26 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +109 -6
  16. package/dist/context-errors.d.ts +27 -0
  17. package/dist/context-errors.d.ts.map +1 -0
  18. package/dist/context-errors.js +101 -0
  19. package/dist/context-violation-error.d.ts +97 -0
  20. package/dist/context-violation-error.d.ts.map +1 -0
  21. package/dist/context-violation-error.js +149 -0
  22. package/dist/create-hook.d.ts +62 -4
  23. package/dist/create-hook.d.ts.map +1 -1
  24. package/dist/create-hook.js +4 -3
  25. package/dist/define-hook.d.ts.map +1 -1
  26. package/dist/define-hook.js +20 -5
  27. package/dist/describe-error.d.ts +70 -0
  28. package/dist/describe-error.d.ts.map +1 -0
  29. package/dist/describe-error.js +189 -0
  30. package/dist/encryption.d.ts +37 -3
  31. package/dist/encryption.d.ts.map +1 -1
  32. package/dist/encryption.js +97 -31
  33. package/dist/events-consumer.d.ts +147 -1
  34. package/dist/events-consumer.d.ts.map +1 -1
  35. package/dist/events-consumer.js +444 -43
  36. package/dist/flushable-stream.d.ts +65 -10
  37. package/dist/flushable-stream.d.ts.map +1 -1
  38. package/dist/flushable-stream.js +131 -18
  39. package/dist/global.d.ts +37 -1
  40. package/dist/global.d.ts.map +1 -1
  41. package/dist/global.js +21 -3
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2 -1
  45. package/dist/log-format.d.ts +25 -0
  46. package/dist/log-format.d.ts.map +1 -0
  47. package/dist/log-format.js +250 -0
  48. package/dist/logger.d.ts +29 -30
  49. package/dist/logger.d.ts.map +1 -1
  50. package/dist/logger.js +82 -32
  51. package/dist/private.d.ts +246 -8
  52. package/dist/private.d.ts.map +1 -1
  53. package/dist/private.js +345 -9
  54. package/dist/replay-payload-cache.d.ts +68 -0
  55. package/dist/replay-payload-cache.d.ts.map +1 -0
  56. package/dist/replay-payload-cache.js +160 -0
  57. package/dist/runtime/compute-instance.d.ts +12 -0
  58. package/dist/runtime/compute-instance.d.ts.map +1 -0
  59. package/dist/runtime/compute-instance.js +13 -0
  60. package/dist/runtime/constants.d.ts +251 -0
  61. package/dist/runtime/constants.d.ts.map +1 -1
  62. package/dist/runtime/constants.js +425 -16
  63. package/dist/runtime/count-step-started-events.d.ts +52 -0
  64. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  65. package/dist/runtime/count-step-started-events.js +72 -0
  66. package/dist/runtime/deployment-guard.d.ts +99 -0
  67. package/dist/runtime/deployment-guard.d.ts.map +1 -0
  68. package/dist/runtime/deployment-guard.js +154 -0
  69. package/dist/runtime/get-port-lazy.d.ts +25 -0
  70. package/dist/runtime/get-port-lazy.d.ts.map +1 -0
  71. package/dist/runtime/get-port-lazy.js +92 -0
  72. package/dist/runtime/get-world-lazy.d.ts +23 -0
  73. package/dist/runtime/get-world-lazy.d.ts.map +1 -0
  74. package/dist/runtime/get-world-lazy.js +46 -0
  75. package/dist/runtime/helpers.d.ts +327 -10
  76. package/dist/runtime/helpers.d.ts.map +1 -1
  77. package/dist/runtime/helpers.js +586 -40
  78. package/dist/runtime/quickjs-assets.generated.d.ts +14 -0
  79. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -0
  80. package/dist/runtime/quickjs-assets.generated.js +30 -0
  81. package/dist/runtime/quickjs-entrypoint.d.ts +124 -0
  82. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -0
  83. package/dist/runtime/quickjs-entrypoint.js +1437 -0
  84. package/dist/runtime/quickjs-runtime.d.ts +228 -0
  85. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  86. package/dist/runtime/quickjs-runtime.js +2372 -0
  87. package/dist/runtime/quickjs-serde.d.ts +107 -0
  88. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  89. package/dist/runtime/quickjs-serde.js +2098 -0
  90. package/dist/runtime/replay-budget.d.ts +89 -0
  91. package/dist/runtime/replay-budget.d.ts.map +1 -0
  92. package/dist/runtime/replay-budget.js +139 -0
  93. package/dist/runtime/replay-recovery-reporter.d.ts +36 -0
  94. package/dist/runtime/replay-recovery-reporter.d.ts.map +1 -0
  95. package/dist/runtime/replay-recovery-reporter.js +64 -0
  96. package/dist/runtime/resume-hook.d.ts +27 -4
  97. package/dist/runtime/resume-hook.d.ts.map +1 -1
  98. package/dist/runtime/resume-hook.js +452 -76
  99. package/dist/runtime/run-id-time.d.ts +19 -0
  100. package/dist/runtime/run-id-time.d.ts.map +1 -0
  101. package/dist/runtime/run-id-time.js +42 -0
  102. package/dist/runtime/run.d.ts +8 -2
  103. package/dist/runtime/run.d.ts.map +1 -1
  104. package/dist/runtime/run.js +62 -15
  105. package/dist/runtime/runs.d.ts +54 -3
  106. package/dist/runtime/runs.d.ts.map +1 -1
  107. package/dist/runtime/runs.js +119 -13
  108. package/dist/runtime/start.d.ts +70 -1
  109. package/dist/runtime/start.d.ts.map +1 -1
  110. package/dist/runtime/start.js +313 -60
  111. package/dist/runtime/step-executor.d.ts +177 -0
  112. package/dist/runtime/step-executor.d.ts.map +1 -0
  113. package/dist/runtime/step-executor.js +946 -0
  114. package/dist/runtime/step-latency.d.ts +197 -0
  115. package/dist/runtime/step-latency.d.ts.map +1 -0
  116. package/dist/runtime/step-latency.js +207 -0
  117. package/dist/runtime/step-ownership.d.ts +72 -0
  118. package/dist/runtime/step-ownership.d.ts.map +1 -0
  119. package/dist/runtime/step-ownership.js +114 -0
  120. package/dist/runtime/step-single-flight.d.ts +12 -0
  121. package/dist/runtime/step-single-flight.d.ts.map +1 -0
  122. package/dist/runtime/step-single-flight.js +69 -0
  123. package/dist/runtime/suspension-handler.d.ts +109 -7
  124. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  125. package/dist/runtime/suspension-handler.js +486 -140
  126. package/dist/runtime/vm-mode.d.ts +44 -0
  127. package/dist/runtime/vm-mode.d.ts.map +1 -0
  128. package/dist/runtime/vm-mode.js +62 -0
  129. package/dist/runtime/vm-serde-bundle.generated.d.ts +14 -0
  130. package/dist/runtime/vm-serde-bundle.generated.d.ts.map +1 -0
  131. package/dist/runtime/vm-serde-bundle.generated.js +16 -0
  132. package/dist/runtime/wait-continuation.d.ts +84 -0
  133. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  134. package/dist/runtime/wait-continuation.js +105 -0
  135. package/dist/runtime/wait-until.d.ts +18 -0
  136. package/dist/runtime/wait-until.d.ts.map +1 -0
  137. package/dist/runtime/wait-until.js +42 -0
  138. package/dist/runtime/world-compatibility.d.ts +20 -0
  139. package/dist/runtime/world-compatibility.d.ts.map +1 -0
  140. package/dist/runtime/world-compatibility.js +32 -0
  141. package/dist/runtime/world-init.d.ts +50 -0
  142. package/dist/runtime/world-init.d.ts.map +1 -0
  143. package/dist/runtime/world-init.js +50 -0
  144. package/dist/runtime/world.d.ts +14 -2
  145. package/dist/runtime/world.d.ts.map +1 -1
  146. package/dist/runtime/world.js +101 -26
  147. package/dist/runtime.d.ts +17 -12
  148. package/dist/runtime.d.ts.map +1 -1
  149. package/dist/runtime.js +3135 -328
  150. package/dist/schemas.d.ts +1 -1
  151. package/dist/schemas.d.ts.map +1 -1
  152. package/dist/schemas.js +1 -1
  153. package/dist/sealed-box.d.ts +167 -0
  154. package/dist/sealed-box.d.ts.map +1 -0
  155. package/dist/sealed-box.js +571 -0
  156. package/dist/serialization/client.d.ts +17 -0
  157. package/dist/serialization/client.d.ts.map +1 -0
  158. package/dist/serialization/client.js +48 -0
  159. package/dist/serialization/codec-devalue-vm.d.ts +16 -0
  160. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -0
  161. package/dist/serialization/codec-devalue-vm.js +148 -0
  162. package/dist/serialization/codec-devalue.d.ts +14 -0
  163. package/dist/serialization/codec-devalue.d.ts.map +1 -0
  164. package/dist/serialization/codec-devalue.js +105 -0
  165. package/dist/serialization/codec.d.ts +125 -0
  166. package/dist/serialization/codec.d.ts.map +1 -0
  167. package/dist/serialization/codec.js +17 -0
  168. package/dist/serialization/compression.d.ts +104 -0
  169. package/dist/serialization/compression.d.ts.map +1 -0
  170. package/dist/serialization/compression.js +260 -0
  171. package/dist/serialization/encryption.d.ts +134 -0
  172. package/dist/serialization/encryption.d.ts.map +1 -0
  173. package/dist/serialization/encryption.js +186 -0
  174. package/dist/serialization/errors.d.ts +34 -0
  175. package/dist/serialization/errors.d.ts.map +1 -0
  176. package/dist/serialization/errors.js +59 -0
  177. package/dist/serialization/format.d.ts +60 -0
  178. package/dist/serialization/format.d.ts.map +1 -0
  179. package/dist/serialization/format.js +97 -0
  180. package/dist/serialization/hardened.d.ts +155 -0
  181. package/dist/serialization/hardened.d.ts.map +1 -0
  182. package/dist/serialization/hardened.js +523 -0
  183. package/dist/serialization/index.d.ts +20 -0
  184. package/dist/serialization/index.d.ts.map +1 -0
  185. package/dist/serialization/index.js +22 -0
  186. package/dist/serialization/reducers/class-vm.d.ts +20 -0
  187. package/dist/serialization/reducers/class-vm.d.ts.map +1 -0
  188. package/dist/serialization/reducers/class-vm.js +77 -0
  189. package/dist/serialization/reducers/class.d.ts +11 -0
  190. package/dist/serialization/reducers/class.d.ts.map +1 -0
  191. package/dist/serialization/reducers/class.js +73 -0
  192. package/dist/serialization/reducers/common-vm.d.ts +15 -0
  193. package/dist/serialization/reducers/common-vm.d.ts.map +1 -0
  194. package/dist/serialization/reducers/common-vm.js +579 -0
  195. package/dist/serialization/reducers/common.d.ts +16 -0
  196. package/dist/serialization/reducers/common.d.ts.map +1 -0
  197. package/dist/serialization/reducers/common.js +478 -0
  198. package/dist/serialization/reducers/step-function-vm.d.ts +44 -0
  199. package/dist/serialization/reducers/step-function-vm.d.ts.map +1 -0
  200. package/dist/serialization/reducers/step-function-vm.js +97 -0
  201. package/dist/serialization/reducers/step-function.d.ts +35 -0
  202. package/dist/serialization/reducers/step-function.d.ts.map +1 -0
  203. package/dist/serialization/reducers/step-function.js +104 -0
  204. package/dist/serialization/step.d.ts +17 -0
  205. package/dist/serialization/step.d.ts.map +1 -0
  206. package/dist/serialization/step.js +48 -0
  207. package/dist/serialization/types.d.ts +273 -0
  208. package/dist/serialization/types.d.ts.map +1 -0
  209. package/dist/serialization/types.js +35 -0
  210. package/dist/serialization/workflow-vm.d.ts +29 -0
  211. package/dist/serialization/workflow-vm.d.ts.map +1 -0
  212. package/dist/serialization/workflow-vm.js +71 -0
  213. package/dist/serialization/workflow.d.ts +29 -0
  214. package/dist/serialization/workflow.d.ts.map +1 -0
  215. package/dist/serialization/workflow.js +54 -0
  216. package/dist/serialization-format.d.ts +60 -4
  217. package/dist/serialization-format.d.ts.map +1 -1
  218. package/dist/serialization-format.js +276 -56
  219. package/dist/serialization.d.ts +374 -221
  220. package/dist/serialization.d.ts.map +1 -1
  221. package/dist/serialization.js +2300 -783
  222. package/dist/set-attributes.d.ts +13 -0
  223. package/dist/set-attributes.d.ts.map +1 -0
  224. package/dist/set-attributes.js +60 -0
  225. package/dist/sleep.d.ts.map +1 -1
  226. package/dist/sleep.js +3 -2
  227. package/dist/source-map.d.ts +25 -0
  228. package/dist/source-map.d.ts.map +1 -1
  229. package/dist/source-map.js +148 -10
  230. package/dist/step/context-storage.d.ts +61 -2
  231. package/dist/step/context-storage.d.ts.map +1 -1
  232. package/dist/step/context-storage.js +7 -5
  233. package/dist/step/get-closure-vars.d.ts.map +1 -1
  234. package/dist/step/get-closure-vars.js +3 -2
  235. package/dist/step/get-step-metadata.d.ts.map +1 -1
  236. package/dist/step/get-step-metadata.js +3 -2
  237. package/dist/step/get-workflow-metadata.d.ts.map +1 -1
  238. package/dist/step/get-workflow-metadata.js +3 -2
  239. package/dist/step/writable-stream.d.ts.map +1 -1
  240. package/dist/step/writable-stream.js +71 -7
  241. package/dist/step.d.ts.map +1 -1
  242. package/dist/step.js +225 -29
  243. package/dist/symbols.d.ts +54 -0
  244. package/dist/symbols.d.ts.map +1 -1
  245. package/dist/symbols.js +55 -1
  246. package/dist/telemetry/semantic-conventions.d.ts +265 -2
  247. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  248. package/dist/telemetry/semantic-conventions.js +190 -1
  249. package/dist/telemetry.d.ts +73 -0
  250. package/dist/telemetry.d.ts.map +1 -1
  251. package/dist/telemetry.js +153 -16
  252. package/dist/types.d.ts +6 -0
  253. package/dist/types.d.ts.map +1 -1
  254. package/dist/types.js +23 -1
  255. package/dist/util.d.ts +16 -6
  256. package/dist/util.d.ts.map +1 -1
  257. package/dist/util.js +25 -16
  258. package/dist/version.d.ts +1 -1
  259. package/dist/version.d.ts.map +1 -1
  260. package/dist/version.js +2 -2
  261. package/dist/vm/index.d.ts.map +1 -1
  262. package/dist/vm/index.js +85 -14
  263. package/dist/vm/script-cache.d.ts +28 -0
  264. package/dist/vm/script-cache.d.ts.map +1 -0
  265. package/dist/vm/script-cache.js +140 -0
  266. package/dist/workflow/abort-controller.d.ts +65 -0
  267. package/dist/workflow/abort-controller.d.ts.map +1 -0
  268. package/dist/workflow/abort-controller.js +312 -0
  269. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  270. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  271. package/dist/workflow/attribute-dispatcher.js +48 -0
  272. package/dist/workflow/create-hook.d.ts.map +1 -1
  273. package/dist/workflow/create-hook.js +25 -3
  274. package/dist/workflow/define-hook.d.ts +1 -1
  275. package/dist/workflow/define-hook.d.ts.map +1 -1
  276. package/dist/workflow/define-hook.js +8 -4
  277. package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
  278. package/dist/workflow/get-workflow-metadata.js +14 -3
  279. package/dist/workflow/hook.d.ts.map +1 -1
  280. package/dist/workflow/hook.js +302 -36
  281. package/dist/workflow/index.d.ts +1 -0
  282. package/dist/workflow/index.d.ts.map +1 -1
  283. package/dist/workflow/index.js +5 -3
  284. package/dist/workflow/set-attributes.d.ts +68 -0
  285. package/dist/workflow/set-attributes.d.ts.map +1 -0
  286. package/dist/workflow/set-attributes.js +60 -0
  287. package/dist/workflow/sleep.d.ts.map +1 -1
  288. package/dist/workflow/sleep.js +57 -8
  289. package/dist/workflow/world-init-stub.d.ts +15 -0
  290. package/dist/workflow/world-init-stub.d.ts.map +1 -0
  291. package/dist/workflow/world-init-stub.js +15 -0
  292. package/dist/workflow.d.ts +79 -3
  293. package/dist/workflow.d.ts.map +1 -1
  294. package/dist/workflow.js +831 -553
  295. package/docs/api-reference/create-hook.mdx +79 -0
  296. package/docs/api-reference/create-webhook.mdx +1 -0
  297. package/docs/api-reference/define-hook.mdx +26 -24
  298. package/docs/api-reference/fatal-error.mdx +29 -7
  299. package/docs/api-reference/fetch.mdx +8 -4
  300. package/docs/api-reference/index.mdx +3 -0
  301. package/docs/api-reference/set-attributes.mdx +61 -0
  302. package/docs/api-reference/sleep.mdx +1 -1
  303. package/docs/foundations/cancellation.mdx +459 -0
  304. package/docs/foundations/errors-and-retries.mdx +7 -3
  305. package/docs/foundations/hooks.mdx +29 -0
  306. package/docs/foundations/idempotency.mdx +243 -11
  307. package/docs/foundations/index.mdx +1 -23
  308. package/docs/foundations/meta.json +3 -1
  309. package/docs/foundations/serialization.mdx +77 -41
  310. package/docs/foundations/starting-workflows.mdx +79 -2
  311. package/docs/foundations/streaming.mdx +14 -23
  312. package/docs/foundations/versioning.mdx +263 -0
  313. package/docs/how-it-works/cancellation.mdx +287 -0
  314. package/docs/how-it-works/code-transform.mdx +21 -17
  315. package/docs/how-it-works/encryption.mdx +5 -5
  316. package/docs/how-it-works/event-sourcing.mdx +17 -9
  317. package/docs/how-it-works/framework-integrations.mdx +96 -337
  318. package/docs/how-it-works/meta.json +2 -1
  319. package/package.json +31 -13
  320. package/dist/runtime/step-handler.d.ts +0 -2
  321. package/dist/runtime/step-handler.d.ts.map +0 -1
  322. package/dist/runtime/step-handler.js +0 -678
@@ -1,10 +1,13 @@
1
- import { HealthCheckPayloadSchema, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, } from '@workflow/world';
1
+ import { PreconditionFailedError, RUN_ERROR_CODES, WorkflowWorldError, } from '@workflow/errors';
2
+ import { eventIdToSlot, FIRST_EVENT_SLOT, getQueueTopicPrefix, HealthCheckPayloadSchema, HOOK_RESUME_INPUT_VERSION, resolveQueueNamespace, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, ulidToDate, } from '@workflow/world';
2
3
  import { monotonicFactory } from 'ulid';
3
4
  import { runtimeLogger } from '../logger.js';
5
+ import { bytesToBase64, deriveRunKeyPair } from '../sealed-box.js';
6
+ import { deriveRunPayloadKeys, } from '../serialization/encryption.js';
4
7
  import * as Attribute from '../telemetry/semantic-conventions.js';
5
8
  import { getSpanKind, trace } from '../telemetry.js';
6
9
  import { version as workflowCoreVersion } from '../version.js';
7
- import { getWorld } from './world.js';
10
+ import { getWorldLazy } from './get-world-lazy.js';
8
11
  /** Default timeout for health checks in milliseconds */
9
12
  const DEFAULT_HEALTH_CHECK_TIMEOUT = 30_000;
10
13
  /**
@@ -18,11 +21,12 @@ const SAFE_WORKFLOW_NAME_PATTERN = /^[a-zA-Z0-9_\-./@]+$/;
18
21
  * Ensures the workflow name only contains safe characters before
19
22
  * interpolating it into the queue name string.
20
23
  */
21
- export function getWorkflowQueueName(workflowName) {
24
+ export function getWorkflowQueueName(workflowName, namespace) {
22
25
  if (!SAFE_WORKFLOW_NAME_PATTERN.test(workflowName)) {
23
26
  throw new Error(`Invalid workflow name "${workflowName}": must only contain alphanumeric characters, underscores, hyphens, dots, forward slashes, or at signs`);
24
27
  }
25
- return `__wkf_workflow_${workflowName}`;
28
+ const prefix = getQueueTopicPrefix('workflow', resolveQueueNamespace(namespace));
29
+ return `${prefix}${workflowName}`;
26
30
  }
27
31
  const generateId = monotonicFactory();
28
32
  /**
@@ -56,17 +60,45 @@ function generateHealthCheckRunId(correlationId) {
56
60
  * The caller can listen to this stream to get the health check response.
57
61
  *
58
62
  * @param healthCheck - The parsed health check payload
59
- * @param endpoint - Which endpoint is responding ('workflow' or 'step')
60
63
  */
61
- export async function handleHealthCheckMessage(healthCheck, endpoint, worldSpecVersion) {
62
- const world = await getWorld();
64
+ export async function handleHealthCheckMessage(healthCheck, worldSpecVersion) {
65
+ const world = await getWorldLazy();
63
66
  const streamName = getHealthCheckStreamName(healthCheck.correlationId);
67
+ // When the probe names a run the caller is about to create, publish that
68
+ // run's public key. We are executing inside the target deployment, so its
69
+ // key material is available locally (no API call), and the caller can then
70
+ // seal the workflow arguments straight from this response rather than
71
+ // making a separate key-lookup request.
72
+ //
73
+ // Only a *public* key may travel this way: the probe response stream is
74
+ // deliberately unauthenticated, so anything secret would be exposed.
75
+ // Best-effort — a failure here must not fail the health check itself, which
76
+ // callers also rely on for plain capability detection.
77
+ let encryptionPublicKey;
78
+ if (healthCheck.runId) {
79
+ try {
80
+ const rawKey = await world.getEncryptionKeyForRun?.(healthCheck.runId);
81
+ if (rawKey) {
82
+ encryptionPublicKey = bytesToBase64((await deriveRunKeyPair(rawKey)).publicKey);
83
+ }
84
+ }
85
+ catch (err) {
86
+ runtimeLogger.warn('Health check could not derive a run public key; the caller will fall back to a key lookup', {
87
+ correlationId: healthCheck.correlationId,
88
+ error: err instanceof Error ? err.message : String(err),
89
+ });
90
+ }
91
+ }
64
92
  const response = JSON.stringify({
65
93
  healthy: true,
66
- endpoint,
67
94
  correlationId: healthCheck.correlationId,
68
95
  specVersion: worldSpecVersion ?? SPEC_VERSION_CURRENT,
69
96
  workflowCoreVersion,
97
+ // We are executing inside the target deployment, so this constant reflects
98
+ // the *consumer's* hook-resume protocol version — exactly what a
99
+ // cross-deployment caller needs to gate its parallel resume path on.
100
+ hookResumeInputVersion: HOOK_RESUME_INPUT_VERSION,
101
+ ...(encryptionPublicKey ? { encryptionPublicKey } : {}),
70
102
  timestamp: Date.now(),
71
103
  });
72
104
  // Use a deterministic fake runId derived from the correlationId so that
@@ -77,13 +109,12 @@ export async function handleHealthCheckMessage(healthCheck, endpoint, worldSpecV
77
109
  }
78
110
  /**
79
111
  * Performs a health check by sending a message through the queue pipeline
80
- * and verifying it is processed by the specified endpoint.
112
+ * and verifying it is processed by the combined workflow endpoint.
81
113
  *
82
114
  * This function bypasses Deployment Protection on Vercel because it goes
83
115
  * through the queue infrastructure rather than direct HTTP.
84
116
  *
85
117
  * @param world - The World instance to use for the health check
86
- * @param endpoint - Which endpoint to health check: 'workflow' or 'step'
87
118
  * @param options - Optional configuration for the health check
88
119
  * @returns Promise resolving to health check result
89
120
  */
@@ -96,6 +127,24 @@ const HEALTH_CHECK_READ_TIMEOUT = 500;
96
127
  * Read chunks from a stream with a timeout per read operation.
97
128
  * Returns { chunks, timedOut } where timedOut indicates if a read timed out.
98
129
  */
130
+ /**
131
+ * Race a promise against a deadline. Rejects with a timeout error when the
132
+ * deadline elapses first. Used to bound `world.streams.get()` inside the
133
+ * health-check poll loop: some worlds hold that request open until the
134
+ * stream has data (e.g. workflow-server holds unwritten streams open for
135
+ * ~2 minutes), which would otherwise blow through the configured health
136
+ * check timeout — the `while` condition is only re-checked between
137
+ * iterations.
138
+ */
139
+ function withDeadline(promise, ms) {
140
+ let timer;
141
+ return Promise.race([
142
+ promise,
143
+ new Promise((_, reject) => {
144
+ timer = setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms);
145
+ }),
146
+ ]).finally(() => clearTimeout(timer));
147
+ }
99
148
  async function readStreamWithTimeout(reader, readTimeout) {
100
149
  const chunks = [];
101
150
  let done = false;
@@ -154,18 +203,37 @@ function parseHealthCheckResponse(chunks) {
154
203
  if (typeof r.specVersion === 'number') {
155
204
  parsed.specVersion = r.specVersion;
156
205
  }
206
+ if (typeof r.workflowCoreVersion === 'string') {
207
+ parsed.workflowCoreVersion = r.workflowCoreVersion;
208
+ }
209
+ if (typeof r.encryptionPublicKey === 'string') {
210
+ parsed.encryptionPublicKey = r.encryptionPublicKey;
211
+ }
212
+ if (typeof r.hookResumeInputVersion === 'number') {
213
+ parsed.hookResumeInputVersion = r.hookResumeInputVersion;
214
+ }
157
215
  return parsed;
158
216
  }
159
- export async function healthCheck(world, endpoint, options) {
217
+ export async function healthCheck(world, options) {
160
218
  const timeout = options?.timeout ?? DEFAULT_HEALTH_CHECK_TIMEOUT;
161
- const correlationId = generateId();
219
+ // Use the world's ID generator when available so the correlationId is a
220
+ // region-tagged ULID. The health-check response is delivered over a stream
221
+ // whose name embeds this correlationId; under platform-directed routing the
222
+ // reader and the responding endpoint can be served from different physical
223
+ // regions, so the region must be encoded in the ID itself for both sides to
224
+ // resolve the same (region-pinned) backend. Falls back to a plain ULID for
225
+ // worlds that don't tag IDs (e.g. local), which resolve to the default
226
+ // region on both sides.
227
+ const correlationId = world.createRunId?.() ?? generateId();
162
228
  const streamName = getHealthCheckStreamName(correlationId);
163
- const queueName = endpoint === 'workflow'
164
- ? '__wkf_workflow_health_check'
165
- : '__wkf_step_health_check';
229
+ const queueName = `${getQueueTopicPrefix('workflow', resolveQueueNamespace(options?.namespace))}health_check`;
166
230
  const startTime = Date.now();
167
231
  try {
168
- await world.queue(queueName, { __healthCheck: true, correlationId }, {
232
+ await world.queue(queueName, {
233
+ __healthCheck: true,
234
+ correlationId,
235
+ ...(options?.runId ? { runId: options.runId } : {}),
236
+ }, {
169
237
  // Use JSON transport so the health check works against both
170
238
  // old (JSON-only) and new (dual) deployments.
171
239
  specVersion: SPEC_VERSION_LEGACY,
@@ -173,7 +241,8 @@ export async function healthCheck(world, endpoint, options) {
173
241
  });
174
242
  while (Date.now() - startTime < timeout) {
175
243
  try {
176
- const stream = await world.streams.get(generateHealthCheckRunId(correlationId), streamName);
244
+ const remainingMs = timeout - (Date.now() - startTime);
245
+ const stream = await withDeadline(world.streams.get(generateHealthCheckRunId(correlationId), streamName), remainingMs);
177
246
  const reader = stream.getReader();
178
247
  const { chunks, timedOut } = await readStreamWithTimeout(reader, HEALTH_CHECK_READ_TIMEOUT);
179
248
  if (timedOut) {
@@ -211,60 +280,486 @@ export async function healthCheck(world, endpoint, options) {
211
280
  };
212
281
  }
213
282
  }
283
+ function eventPaginationContractError(runId, message) {
284
+ return new WorkflowWorldError(`Event pagination ${message} for workflow run "${runId}".`, { code: RUN_ERROR_CODES.WORLD_CONTRACT_ERROR });
285
+ }
286
+ function recordRequestedEventCursor(runId, cursor, requestedCursors) {
287
+ if (!cursor) {
288
+ return;
289
+ }
290
+ if (requestedCursors.has(cursor)) {
291
+ throw eventPaginationContractError(runId, 'did not advance');
292
+ }
293
+ requestedCursors.add(cursor);
294
+ }
295
+ /**
296
+ * Appends events whose IDs are not already present in `target`.
297
+ *
298
+ * Pass the IDs currently present in `target` when appending repeatedly to the
299
+ * same array. The set is updated alongside `target`.
300
+ *
301
+ * Events are appended in the order the World returned them, and are not
302
+ * re-sorted: a World's canonical order is its own, and the runtime cannot
303
+ * reproduce it from event ids alone. `world-vercel` orders by event id, while
304
+ * `world-local` orders by `(createdAt, eventId)` and deliberately re-mints keys
305
+ * so that the two diverge. Every append source is already in canonical order
306
+ * relative to the tail (a cursor-delimited page, or a write-response delta), so
307
+ * receipt order is the order to keep. Nothing downstream may assume the tail is
308
+ * the newest event — see {@link latestEventStateUpdatedAt}.
309
+ */
310
+ export function appendUniqueEvents(target, events, targetIds) {
311
+ if (events.length === 0) {
312
+ return;
313
+ }
314
+ const ids = targetIds ?? new Set(target.map((event) => event.eventId));
315
+ for (const event of events) {
316
+ if (ids.has(event.eventId)) {
317
+ continue;
318
+ }
319
+ ids.add(event.eventId);
320
+ target.push(event);
321
+ }
322
+ }
214
323
  /**
215
- * Loads all workflow run events by iterating through all pages of paginated results.
216
- * This ensures that *all* events are loaded into memory before running the workflow.
217
- * Events must be in chronological order (ascending) for proper workflow replay.
324
+ * Inserts `event` into `target` at the position that keeps `target` ordered by
325
+ * ascending `eventId`, or no-ops if an event with the same `eventId` is already
326
+ * present (idempotent).
327
+ *
328
+ * `preloadedEvents` is loaded `sortOrder: 'asc'` and is never re-sorted
329
+ * client-side, so a `hook_received` spliced in by the lazy-resume consumer must
330
+ * land in `eventId` order — a plain `push` would place a late-committing
331
+ * earlier event after events that sort before it, corrupting replay. Event IDs
332
+ * are ULIDs, so lexicographic string order matches commit order.
218
333
  */
219
- export async function getAllWorkflowRunEvents(runId) {
220
- return trace('workflow.loadEvents', async (span) => {
334
+ export function insertEventByEventId(target, event) {
335
+ // Linear scan from the end: the spliced event is almost always the newest
336
+ // (it sorts at or near the tail), so this finds the slot in O(1)–O(k) for the
337
+ // common case while still handling an out-of-order late arrival correctly.
338
+ let i = target.length;
339
+ while (i > 0) {
340
+ const existing = target[i - 1];
341
+ if (existing.eventId === event.eventId) {
342
+ // Already present — keep the splice idempotent.
343
+ return;
344
+ }
345
+ if (existing.eventId < event.eventId) {
346
+ break;
347
+ }
348
+ i--;
349
+ }
350
+ target.splice(i, 0, event);
351
+ }
352
+ function assertEventPaginationProgress(runId, hasMore, cursor, requestedCursors) {
353
+ if (!hasMore) {
354
+ return;
355
+ }
356
+ if (cursor === null) {
357
+ throw eventPaginationContractError(runId, 'returned more pages without a cursor');
358
+ }
359
+ if (requestedCursors.has(cursor)) {
360
+ throw eventPaginationContractError(runId, 'repeated a cursor');
361
+ }
362
+ }
363
+ function shouldRetryWithoutEventCursor(error, cursor, alreadyRetried) {
364
+ return (cursor !== null &&
365
+ !alreadyRetried &&
366
+ WorkflowWorldError.is(error) &&
367
+ error.status === 400);
368
+ }
369
+ /**
370
+ * Loads workflow run events by iterating through all pages of paginated
371
+ * results. Events are returned in chronological (ascending) order for
372
+ * deterministic workflow replay.
373
+ *
374
+ * @param runId - The workflow run ID.
375
+ * @param afterCursor - If provided, only events after this cursor are
376
+ * returned (incremental load). If omitted, all events are returned.
377
+ * The returned cursor can be passed back in on a subsequent call for
378
+ * incremental loading.
379
+ */
380
+ export async function loadWorkflowRunEvents(runId, afterCursor) {
381
+ const incremental = afterCursor !== undefined;
382
+ return trace(incremental ? 'workflow.loadNewEvents' : 'workflow.loadEvents', async (span) => {
221
383
  span?.setAttributes({
222
384
  ...Attribute.WorkflowRunId(runId),
223
385
  });
224
- const allEvents = [];
225
- let cursor = null;
386
+ const loadedEvents = [];
387
+ const loadedEventIds = new Set();
388
+ const requestedCursors = new Set();
389
+ let cursor = afterCursor ?? null;
226
390
  let hasMore = true;
227
391
  let pagesLoaded = 0;
228
- const world = await getWorld();
392
+ let retriedWithoutCursor = false;
393
+ const world = await getWorldLazy();
229
394
  const loadStart = Date.now();
230
395
  while (hasMore) {
231
396
  // TODO: we're currently loading all the data with resolveRef behaviour. We need to update this
232
397
  // to lazyload the data from the world instead so that we can optimize and make the event log loading
233
398
  // much faster and memory efficient
234
399
  const pageStart = Date.now();
235
- const response = await world.events.list({
236
- runId,
237
- pagination: {
238
- sortOrder: 'asc', // Required: events must be in chronological order for replay
239
- cursor: cursor ?? undefined,
240
- },
241
- });
242
- allEvents.push(...response.data);
400
+ const requestedCursor = cursor;
401
+ recordRequestedEventCursor(runId, requestedCursor, requestedCursors);
402
+ let response;
403
+ try {
404
+ response = await world.events.list({
405
+ runId,
406
+ pagination: {
407
+ sortOrder: 'asc',
408
+ cursor: requestedCursor ?? undefined,
409
+ },
410
+ });
411
+ }
412
+ catch (error) {
413
+ if (shouldRetryWithoutEventCursor(error, requestedCursor, retriedWithoutCursor)) {
414
+ runtimeLogger.warn('Event cursor was rejected; retrying with a full event reload.', { workflowRunId: runId });
415
+ loadedEvents.length = 0;
416
+ loadedEventIds.clear();
417
+ requestedCursors.clear();
418
+ cursor = null;
419
+ retriedWithoutCursor = true;
420
+ continue;
421
+ }
422
+ throw error;
423
+ }
424
+ appendUniqueEvents(loadedEvents, response.data, loadedEventIds);
243
425
  hasMore = response.hasMore;
244
- cursor = response.cursor;
426
+ assertEventPaginationProgress(runId, hasMore, response.cursor, requestedCursors);
427
+ // Preserve the last non-null cursor across pages. A World may
428
+ // legitimately return `{ data: [], cursor: null, hasMore: false }`
429
+ // on a trailing empty page — for example when the previous page's
430
+ // underlying DB query hit the limit exactly and returned a
431
+ // `LastEvaluatedKey` "just in case". Overwriting with that null
432
+ // would lose the position past the last real event we loaded and
433
+ // force the runtime into the "no cursor after initial load" full-
434
+ // reload fallback on every subsequent replay iteration.
435
+ cursor = response.cursor ?? cursor;
245
436
  pagesLoaded++;
246
437
  runtimeLogger.debug('Loaded event page', {
247
438
  workflowRunId: runId,
439
+ incremental,
248
440
  page: pagesLoaded,
249
441
  pageEvents: response.data.length,
250
- totalEvents: allEvents.length,
442
+ totalEvents: loadedEvents.length,
251
443
  hasMore,
252
444
  pageMs: Date.now() - pageStart,
253
445
  });
254
446
  }
255
- runtimeLogger.debug('Event loading complete', {
447
+ runtimeLogger.debug('Event load complete', {
256
448
  workflowRunId: runId,
257
- totalEvents: allEvents.length,
449
+ incremental,
450
+ totalEvents: loadedEvents.length,
258
451
  pagesLoaded,
259
452
  totalMs: Date.now() - loadStart,
260
453
  });
261
454
  span?.setAttributes({
262
- ...Attribute.WorkflowEventsCount(allEvents.length),
455
+ ...Attribute.WorkflowEventsCount(loadedEvents.length),
263
456
  ...Attribute.WorkflowEventsPagesLoaded(pagesLoaded),
264
457
  });
265
- return allEvents;
458
+ return { events: loadedEvents, cursor };
266
459
  });
267
460
  }
461
+ /**
462
+ * Whether the optimistic-concurrency guard for event creation is enabled.
463
+ * **On by default** where the runtime executes: replay-context creates send a
464
+ * `stateUpdatedAt` snapshot (and can be rejected with 412 by a supporting
465
+ * backend) unless `WORKFLOW_PRECONDITION_GUARD` is set to `0`. Backends without
466
+ * guard support ignore the snapshot, so enabling by default is
467
+ * backward-compatible.
468
+ */
469
+ export function isPreconditionGuardEnabled() {
470
+ return process.env.WORKFLOW_PRECONDITION_GUARD !== '0';
471
+ }
472
+ /**
473
+ * Whether a replay refuses to run over a log with a hole in it (see
474
+ * {@link findEventSlotGap}). **On by default**; set
475
+ * `WORKFLOW_SLOT_GAP_CHECK=0` to replay across holes instead.
476
+ *
477
+ * The switch exists because the check trades one failure for another. A hole is
478
+ * a position claimed by a write that then failed, so most of them stand for an
479
+ * event that never happened and replaying past one is correct. But a hole
480
+ * standing for an event that *did* happen is indistinguishable from that, and
481
+ * replaying past that one produces a run whose result is wrong with nothing to
482
+ * show for it. Failing loudly is the recoverable side of the trade, and this is
483
+ * the way back out if a fleet turns out to carry benign holes.
484
+ */
485
+ export function isSlotGapCheckEnabled() {
486
+ return process.env.WORKFLOW_SLOT_GAP_CHECK !== '0';
487
+ }
488
+ /**
489
+ * The `stateUpdatedAt` value to send with a replay-context event creation: the
490
+ * *maximum* ULID time (epoch ms) over the events the runtime has loaded. Returns
491
+ * `undefined` when there are no events or that id is not a decodable ULID.
492
+ *
493
+ * It is the maximum rather than the tail's because the loaded log is in the
494
+ * World's canonical order, which is not necessarily event-id order (see
495
+ * {@link appendUniqueEvents}). The maximum is what lets the count sent alongside
496
+ * it be read as "events at or below this watermark": every loaded event is at or
497
+ * below it, so the count is exactly `events.length`. Reading the tail instead
498
+ * would understate the watermark on a World whose order is not id-ordered, which
499
+ * is safe (it can only weaken detection) but needlessly imprecise.
500
+ *
501
+ * The maximum is found by lexicographic id comparison, decoding only once: the
502
+ * 26-character Crockford ULID encodes its timestamp in the leading 10
503
+ * characters, so the greatest id also carries the greatest time.
504
+ *
505
+ * Granularity: snapshots are epoch-milliseconds, and the backend allows an
506
+ * equal-timestamp snapshot (an up-to-date client must not be rejected). Two
507
+ * out-of-band events landing in the same millisecond where only the first was
508
+ * loaded therefore pass this half of the guard undetected — that is exactly
509
+ * the hole `stateEventCount` closes, since the count of events at or below the
510
+ * watermark differs even when the watermarks are equal.
511
+ */
512
+ export function latestEventStateUpdatedAt(events) {
513
+ let latest;
514
+ for (const event of events) {
515
+ if (latest === undefined || event.eventId > latest) {
516
+ latest = event.eventId;
517
+ }
518
+ }
519
+ if (latest === undefined) {
520
+ return undefined;
521
+ }
522
+ // Event IDs are prefixed ULIDs (e.g. `evnt_01ARYZ...`); ulidToDate only
523
+ // decodes the bare 26-char ULID, so strip the prefix first.
524
+ const eventId = latest;
525
+ const underscore = eventId.lastIndexOf('_');
526
+ const rawUlid = underscore === -1 ? eventId : eventId.slice(underscore + 1);
527
+ const time = ulidToDate(rawUlid)?.getTime();
528
+ if (time === undefined) {
529
+ // Fail open: a non-decodable id disarms the guard for this create (no
530
+ // snapshot sent). Log so a fleet-wide silent disarm is diagnosable.
531
+ runtimeLogger.debug('Precondition guard: latest event id is not a decodable ULID; sending no snapshot', { eventId });
532
+ return undefined;
533
+ }
534
+ return time;
535
+ }
536
+ /**
537
+ * Merge the events a bump-and-report write handed back into the log it was
538
+ * derived from, and answer how many of them were new.
539
+ *
540
+ * Unlike {@link appendUniqueEvents}, this re-sorts. The reported events occupy
541
+ * slots *below* the write that reported them, so appending them would put them
542
+ * after events they precede — and on a slot-numbered run the id order is the
543
+ * World's canonical order, so restoring it is well defined rather than a guess.
544
+ * A run that is not slot-numbered cannot produce this report in the first
545
+ * place; the sort is skipped rather than applied to ids it cannot order.
546
+ */
547
+ export function mergeReportedEvents(target, events) {
548
+ const before = target.length;
549
+ appendUniqueEvents(target, events);
550
+ const added = target.length - before;
551
+ if (added > 0 && maxEventSlot(target) !== undefined) {
552
+ target.sort((a, b) => a.eventId < b.eventId ? -1 : a.eventId > b.eventId ? 1 : 0);
553
+ }
554
+ return added;
555
+ }
556
+ /**
557
+ * The highest slot the loaded log occupies, or `undefined` when the run is not
558
+ * slot-numbered. A run keeps the id scheme it was created under, so one event
559
+ * settles it for the whole log.
560
+ *
561
+ * The maximum, not the count, and the two are not interchangeable even though
562
+ * a healthy log makes them equal. A World hands a position to the insert that
563
+ * occupies it, so a write that never lands leaves no hole behind and the log
564
+ * stays dense. What the count cannot survive is a *partial* read: a log
565
+ * assembled from a truncated report, or read while a concurrent write is
566
+ * committing, holds fewer events than its highest position. Counting those
567
+ * would make the next write claim to have seen less than it has, so the World
568
+ * would report the same events back to it on every attempt.
569
+ *
570
+ * A hole below the maximum is therefore a property of the read, not of the log,
571
+ * which is what lets {@link settleEventSlotGap} re-read instead of giving up.
572
+ */
573
+ export function maxEventSlot(events) {
574
+ let max;
575
+ for (const event of events) {
576
+ const slot = eventIdToSlot(event.eventId);
577
+ if (slot === null) {
578
+ return undefined;
579
+ }
580
+ if (max === undefined || slot > max) {
581
+ max = slot;
582
+ }
583
+ }
584
+ return max;
585
+ }
586
+ /**
587
+ * The hole in a loaded log, or `undefined` when there is none to find.
588
+ *
589
+ * On a slot-numbered run the World allocates every position, so a log that
590
+ * holds `n` events below slot `n` is missing one. That matters before a replay
591
+ * and nowhere else: the replay reads the log as the complete record of what has
592
+ * happened, and an absent position is indistinguishable from an event that
593
+ * never occurred. The branch it would have decided gets decided the other way,
594
+ * and the run diverges quietly rather than failing.
595
+ *
596
+ * Order-independent, unlike the equivalent audit the World runs over a page it
597
+ * just read. A loaded log is assembled from listed pages plus whatever a
598
+ * bump-and-report write handed back, and while {@link mergeReportedEvents}
599
+ * restores id order, a check that can fail a healthy run should not depend on
600
+ * that having happened.
601
+ *
602
+ * The first slot is never counted. It belongs to `run_created`, which `start()`
603
+ * posts concurrently with the queue send, so a log read in that window
604
+ * legitimately begins at the second slot and fills in on its own. Every replay
605
+ * that races a run's own start would otherwise report a hole.
606
+ *
607
+ * Returns `undefined` for a log this cannot read as slots at all: an empty one,
608
+ * or a run numbered by ULID, where positions carry no density to check.
609
+ */
610
+ export function findEventSlotGap(events) {
611
+ const occupied = new Set();
612
+ let maxSlot = 0;
613
+ for (const event of events) {
614
+ const slot = eventIdToSlot(event.eventId);
615
+ if (slot === null) {
616
+ return undefined;
617
+ }
618
+ occupied.add(slot);
619
+ if (slot > maxSlot) {
620
+ maxSlot = slot;
621
+ }
622
+ }
623
+ if (maxSlot === 0) {
624
+ return undefined;
625
+ }
626
+ const floor = occupied.has(FIRST_EVENT_SLOT)
627
+ ? FIRST_EVENT_SLOT
628
+ : FIRST_EVENT_SLOT + 1;
629
+ // Every slot is at or above `floor` by construction, so the log is dense
630
+ // exactly when it holds one event per position in `[floor, maxSlot]`. The
631
+ // scan below only runs once that has already answered no.
632
+ if (occupied.size === maxSlot - floor + 1) {
633
+ return undefined;
634
+ }
635
+ let firstMissingSlot;
636
+ let missingCount = 0;
637
+ for (let slot = floor; slot <= maxSlot; slot++) {
638
+ if (!occupied.has(slot)) {
639
+ firstMissingSlot ??= slot;
640
+ missingCount++;
641
+ }
642
+ }
643
+ if (firstMissingSlot === undefined) {
644
+ return undefined;
645
+ }
646
+ return { firstMissingSlot, missingCount, maxSlot };
647
+ }
648
+ /**
649
+ * How many times a detected hole is re-read before the log is taken at its
650
+ * word, and the backoff before each re-read (doubling per attempt).
651
+ *
652
+ * A hole can be transient. The World allocates a slot inside the insert that
653
+ * occupies it, so two concurrent writers can collide, one retry past the other,
654
+ * and the higher slot commit first — leaving a window in which the lower one is
655
+ * genuinely absent from a strongly-consistent read and fills in a moment later.
656
+ * The window is one commit wide, so a short backoff clears it; anything that
657
+ * survives all three re-reads is a position no write will ever occupy.
658
+ */
659
+ export const SLOT_GAP_RECHECK_ATTEMPTS = 3;
660
+ const SLOT_GAP_RECHECK_BASE_DELAY_MS = 25;
661
+ /**
662
+ * Re-read a log that looks holey until the hole fills in or the re-reads run
663
+ * out, and return the settled log alongside the hole that survived.
664
+ *
665
+ * Reads are strongly consistent, so a hole is not an artifact of *when* the log
666
+ * was read — but it can be an artifact of a write that had not committed yet
667
+ * (see {@link SLOT_GAP_RECHECK_ATTEMPTS}). Distinguishing the two costs a
668
+ * re-read, which is only ever paid by a replay that already found a hole.
669
+ *
670
+ * The reload is full rather than incremental: the missing position is below the
671
+ * log's maximum, so a cursor-anchored read starts past it and can never see it
672
+ * arrive.
673
+ */
674
+ export async function settleEventSlotGap(runId, loaded) {
675
+ let log = loaded;
676
+ let gap = findEventSlotGap(log.events);
677
+ for (let attempt = 0; gap !== undefined && attempt < SLOT_GAP_RECHECK_ATTEMPTS; attempt++) {
678
+ await new Promise((resolve) => setTimeout(resolve, SLOT_GAP_RECHECK_BASE_DELAY_MS * 2 ** attempt));
679
+ log = await loadWorkflowRunEvents(runId);
680
+ gap = findEventSlotGap(log.events);
681
+ }
682
+ return { log, gap };
683
+ }
684
+ /**
685
+ * Build the precondition snapshot to attach to a replay-context event creation.
686
+ *
687
+ * Returns an empty object — no guard, backend behaves as before — when the
688
+ * guard is disabled or the watermark is not derivable. All three fields fail
689
+ * open together: a count without a watermark is meaningless to the backend, and
690
+ * a cursor without either would invite a delta nobody asked for.
691
+ *
692
+ * `stateEventCount` is `events.length` because the watermark is the log's
693
+ * *maximum* ULID time, so every loaded event is at or below it regardless of the
694
+ * order the World returned them in.
695
+ *
696
+ * Both fields are therefore invariant under permutation of the log: a maximum is
697
+ * order-independent, and the length is set cardinality once `appendUniqueEvents`
698
+ * has deduped by event id. Two replays that consume the same events in different
699
+ * orders send an identical snapshot, so this guard detects that a log is missing
700
+ * an event and can never detect that a replay consumed one in a different order.
701
+ */
702
+ export function preconditionSnapshotParams(events, cursor) {
703
+ if (!isPreconditionGuardEnabled()) {
704
+ return {};
705
+ }
706
+ // A slot-numbered run says with one integer everything the triple was
707
+ // approximating, so the two are alternatives rather than a pair. Sending the
708
+ // triple here would also be futile: a slot id carries no time, so
709
+ // `latestEventStateUpdatedAt` would fail open on every single write.
710
+ const eventCount = maxEventSlot(events);
711
+ if (eventCount !== undefined) {
712
+ return { eventCount };
713
+ }
714
+ const stateUpdatedAt = latestEventStateUpdatedAt(events);
715
+ if (stateUpdatedAt === undefined) {
716
+ return {};
717
+ }
718
+ return {
719
+ stateUpdatedAt,
720
+ stateEventCount: events.length,
721
+ ...(cursor ? { stateCursor: cursor } : {}),
722
+ };
723
+ }
724
+ /**
725
+ * The events a rejecting World attached to a `PreconditionFailedError`, when it
726
+ * returned the ones the client's snapshot was missing inline.
727
+ *
728
+ * Returns `null` for anything else — no details, a World that did not implement
729
+ * this, or a payload that does not narrow cleanly. Callers fall back to
730
+ * reloading the event log, which is always correct; this is untrusted-shaped
731
+ * data on a failure path, so nothing here is repaired.
732
+ *
733
+ * `runId` is the caller's run. Every event must belong to it: the delta is
734
+ * merged straight into the replay's log, and one foreign event there is a
735
+ * corrupt log rather than a corrected one — the replay would consume a
736
+ * correlation id for an event that does not exist on this run.
737
+ */
738
+ export function preconditionEventDelta(error, runId) {
739
+ if (!PreconditionFailedError.is(error)) {
740
+ return null;
741
+ }
742
+ const details = error.details;
743
+ if (typeof details !== 'object' || details === null) {
744
+ return null;
745
+ }
746
+ const { events, cursor } = details;
747
+ if (!Array.isArray(events) || events.length === 0) {
748
+ return null;
749
+ }
750
+ for (const event of events) {
751
+ if (typeof event !== 'object' ||
752
+ event === null ||
753
+ typeof event.eventId !== 'string' ||
754
+ event.runId !== runId) {
755
+ return null;
756
+ }
757
+ }
758
+ return {
759
+ events: events,
760
+ cursor: typeof cursor === 'string' ? cursor : null,
761
+ };
762
+ }
268
763
  /**
269
764
  * CORS headers for health check responses.
270
765
  * Allows the observability UI to check endpoint health from a different origin.
@@ -344,4 +839,55 @@ export function getQueueOverhead(message) {
344
839
  return;
345
840
  }
346
841
  }
347
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBTUEsT0FBTyxFQUNMLHdCQUF3QixFQUN4QixvQkFBb0IsRUFDcEIsbUJBQW1CLEdBQ3BCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXhDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxLQUFLLFNBQVMsTUFBTSxzQ0FBc0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxPQUFPLElBQUksbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUV0Qyx3REFBd0Q7QUFDeEQsTUFBTSw0QkFBNEIsR0FBRyxNQUFNLENBQUM7QUFFNUM7Ozs7R0FJRztBQUNILE1BQU0sMEJBQTBCLEdBQUcsc0JBQXNCLENBQUM7QUFFMUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxZQUFvQjtJQUN2RCxJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7UUFDbkQsTUFBTSxJQUFJLEtBQUssQ0FDYiwwQkFBMEIsWUFBWSx3R0FBd0csQ0FDL0ksQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLGtCQUFrQixZQUFZLEVBQW9CLENBQUM7QUFDNUQsQ0FBQztBQUVELE1BQU0sVUFBVSxHQUFHLGdCQUFnQixFQUFFLENBQUM7QUFFdEM7O0dBRUc7QUFDSCxTQUFTLHdCQUF3QixDQUFDLGFBQXFCO0lBQ3JELE9BQU8sbUJBQW1CLGFBQWEsRUFBRSxDQUFDO0FBQzVDLENBQUM7QUFlRDs7O0dBR0c7QUFD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LHdCQUF3QixDQUFDLFNBQVMsQ0FBQztZQUNoRCxHQUFHLFNBQVMsQ0FBQyxzQkFBc0IsQ0FBQyxTQUFTLENBQUM7WUFDOUMsd0NBQXdDO1lBQ3hDLEdBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUM7WUFDeEMsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQztZQUN0QyxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDO1lBQzlCLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUM7U0FDbEM7UUFDRCxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUMsVUFBVSxDQUFDO0tBQ3BDLEVBQ0QsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQ2IsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQ2pELElBQUksU0FBUyxFQUFFLENBQUM7WUFDZCxJQUFJLEVBQUUsYUFBYSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQy9ELENBQUM7SUFDSCxDQUFDLENBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUErQjtJQUM5RCxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVc7UUFBRSxPQUFPO0lBQ2pDLElBQUksQ0FBQztRQUNILE9BQU8sU0FBUyxDQUFDLGVBQWUsQ0FDOUIsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQzNDLENBQUM7SUFDSixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTztJQUNULENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUge1xuICBFdmVudCxcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBWYWxpZFF1ZXVlTmFtZSxcbiAgV29ybGQsXG59IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQge1xuICBIZWFsdGhDaGVja1BheWxvYWRTY2hlbWEsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTUEVDX1ZFUlNJT05fTEVHQUNZLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgbW9ub3RvbmljRmFjdG9yeSB9IGZyb20gJ3VsaWQnO1xuXG5pbXBvcnQgeyBydW50aW1lTG9nZ2VyIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCAqIGFzIEF0dHJpYnV0ZSBmcm9tICcuLi90ZWxlbWV0cnkvc2VtYW50aWMtY29udmVudGlvbnMuanMnO1xuaW1wb3J0IHsgZ2V0U3BhbktpbmQsIHRyYWNlIH0gZnJvbSAnLi4vdGVsZW1ldHJ5LmpzJztcbmltcG9ydCB7IHZlcnNpb24gYXMgd29ya2Zsb3dDb3JlVmVyc2lvbiB9IGZyb20gJy4uL3ZlcnNpb24uanMnO1xuaW1wb3J0IHsgZ2V0V29ybGQgfSBmcm9tICcuL3dvcmxkLmpzJztcblxuLyoqIERlZmF1bHQgdGltZW91dCBmb3IgaGVhbHRoIGNoZWNrcyBpbiBtaWxsaXNlY29uZHMgKi9cbmNvbnN0IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQgPSAzMF8wMDA7XG5cbi8qKlxuICogUGF0dGVybiBmb3Igc2FmZSB3b3JrZmxvdyBuYW1lcy4gT25seSBhbGxvd3MgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsXG4gKiB1bmRlcnNjb3JlcywgaHlwaGVucywgZG90cywgZm9yd2FyZCBzbGFzaGVzIChmb3IgbmFtZXNwYWNlZCB3b3JrZmxvd3MpLFxuICogYW5kIGF0IHNpZ25zIChmb3Igc2NvcGVkIHBhY2thZ2VzKS5cbiAqL1xuY29uc3QgU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4gPSAvXlthLXpBLVowLTlfXFwtLi9AXSskLztcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYSB3b3JrZmxvdyBuYW1lIGFuZCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHF1ZXVlIG5hbWUuXG4gKiBFbnN1cmVzIHRoZSB3b3JrZmxvdyBuYW1lIG9ubHkgY29udGFpbnMgc2FmZSBjaGFyYWN0ZXJzIGJlZm9yZVxuICogaW50ZXJwb2xhdGluZyBpdCBpbnRvIHRoZSBxdWV1ZSBuYW1lIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFdvcmtmbG93UXVldWVOYW1lKHdvcmtmbG93TmFtZTogc3RyaW5nKTogVmFsaWRRdWV1ZU5hbWUge1xuICBpZiAoIVNBRkVfV09SS0ZMT1dfTkFNRV9QQVRURVJOLnRlc3Qod29ya2Zsb3dOYW1lKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBJbnZhbGlkIHdvcmtmbG93IG5hbWUgXCIke3dvcmtmbG93TmFtZX1cIjogbXVzdCBvbmx5IGNvbnRhaW4gYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIHVuZGVyc2NvcmVzLCBoeXBoZW5zLCBkb3RzLCBmb3J3YXJkIHNsYXNoZXMsIG9yIGF0IHNpZ25zYFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGBfX3drZl93b3JrZmxvd18ke3dvcmtmbG93TmFtZX1gIGFzIFZhbGlkUXVldWVOYW1lO1xufVxuXG5jb25zdCBnZW5lcmF0ZUlkID0gbW9ub3RvbmljRmFjdG9yeSgpO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIHN0cmVhbSBuYW1lIGZvciBhIGhlYWx0aCBjaGVjayB3aXRoIHRoZSBnaXZlbiBjb3JyZWxhdGlvbiBJRC5cbiAqL1xuZnVuY3Rpb24gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgX19oZWFsdGhfY2hlY2tfXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBhIGhlYWx0aCBjaGVjayBvcGVyYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tSZXN1bHQge1xuICBoZWFsdGh5OiBib29sZWFuO1xuICAvKiogRXJyb3IgbWVzc2FnZSBpZiBoZWFsdGggY2hlY2sgZmFpbGVkICovXG4gIGVycm9yPzogc3RyaW5nO1xuICAvKiogTGF0ZW5jeSBpZiB0aGUgaGVhbHRoIGNoZWNrIHdhcyBzdWNjZXNzZnVsICovXG4gIGxhdGVuY3lNcz86IG51bWJlcjtcbiAgLyoqIFNwZWMgdmVyc2lvbiBvZiB0aGUgcmVzcG9uZGluZyBkZXBsb3ltZW50ICovXG4gIHNwZWNWZXJzaW9uPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gbWVzc2FnZSBpcyBhIGhlYWx0aCBjaGVjayBwYXlsb2FkLlxuICogSWYgc28sIHJldHVybnMgdGhlIHBhcnNlZCBwYXlsb2FkLiBPdGhlcndpc2UgcmV0dXJucyB1bmRlZmluZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUhlYWx0aENoZWNrUGF5bG9hZChcbiAgbWVzc2FnZTogdW5rbm93blxuKTogSGVhbHRoQ2hlY2tQYXlsb2FkIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmVzdWx0ID0gSGVhbHRoQ2hlY2tQYXlsb2FkU2NoZW1hLnNhZmVQYXJzZShtZXNzYWdlKTtcbiAgaWYgKHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgcmV0dXJuIHJlc3VsdC5kYXRhO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgZGV0ZXJtaW5pc3RpYyBmYWtlIHJ1bklkIGZvciBoZWFsdGggY2hlY2sgc3RyZWFtcy5cbiAqIEJvdGggdGhlIHdyaXRlciAoaGFuZGxlSGVhbHRoQ2hlY2tNZXNzYWdlKSBhbmQgcmVhZGVyIChoZWFsdGhDaGVjaykgZGVyaXZlXG4gKiB0aGUgc2FtZSBydW5JZCBmcm9tIHRoZSBjb3JyZWxhdGlvbklkIHNvIHRoYXQgaW1wbGVtZW50YXRpb25zIHRoYXQgc2NvcGVcbiAqIHN0cmVhbSByZWFkcyBieSBydW5JZCBzdGlsbCB3b3JrIGNvcnJlY3RseS5cbiAqL1xuZnVuY3Rpb24gZ2VuZXJhdGVIZWFsdGhDaGVja1J1bklkKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgd3J1bl9oY18ke2NvcnJlbGF0aW9uSWR9YDtcbn1cblxuLyoqXG4gKiBIYW5kbGVzIGEgaGVhbHRoIGNoZWNrIG1lc3NhZ2UgYnkgd3JpdGluZyB0aGUgcmVzdWx0IHRvIHRoZSB3b3JsZCdzIHN0cmVhbS5cbiAqIFRoZSBjYWxsZXIgY2FuIGxpc3RlbiB0byB0aGlzIHN0cmVhbSB0byBnZXQgdGhlIGhlYWx0aCBjaGVjayByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0gaGVhbHRoQ2hlY2sgLSBUaGUgcGFyc2VkIGhlYWx0aCBjaGVjayBwYXlsb2FkXG4gKiBAcGFyYW0gZW5kcG9pbnQgLSBXaGljaCBlbmRwb2ludCBpcyByZXNwb25kaW5nICgnd29ya2Zsb3cnIG9yICdzdGVwJylcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgaGVhbHRoQ2hlY2s6IEhlYWx0aENoZWNrUGF5bG9hZCxcbiAgZW5kcG9pbnQ6ICd3b3JrZmxvdycgfCAnc3RlcCcsXG4gIHdvcmxkU3BlY1ZlcnNpb24/OiBudW1iZXJcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkKCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCk7XG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIGhlYWx0aHk6IHRydWUsXG4gICAgZW5kcG9pbnQsXG4gICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgfSk7XG4gIC8vIFVzZSBhIGRldGVybWluaXN0aWMgZmFrZSBydW5JZCBkZXJpdmVkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdFxuICAvLyB0aGUgcmVhZGVyIHNpZGUgcHJvZHVjZXMgdGhlIHNhbWUgdmFsdWUuXG4gIGNvbnN0IGZha2VSdW5JZCA9IGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChoZWFsdGhDaGVjay5jb3JyZWxhdGlvbklkKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUsIHJlc3BvbnNlKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUpO1xufVxuXG5leHBvcnQgdHlwZSBIZWFsdGhDaGVja0VuZHBvaW50ID0gJ3dvcmtmbG93JyB8ICdzdGVwJztcblxuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhDaGVja09wdGlvbnMge1xuICAvKiogVGltZW91dCBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLiBEZWZhdWx0OiAzMDAwMCAoMzBzKSAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xuICAvKiogRGVwbG95bWVudCBJRCB0byBzZW5kIHRoZSBoZWFsdGggY2hlY2sgdG8uIEZhbGxzIGJhY2sgdG8gcHJvY2Vzcy5lbnYuVkVSQ0VMX0RFUExPWU1FTlRfSUQuICovXG4gIGRlcGxveW1lbnRJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQZXJmb3JtcyBhIGhlYWx0aCBjaGVjayBieSBzZW5kaW5nIGEgbWVzc2FnZSB0aHJvdWdoIHRoZSBxdWV1ZSBwaXBlbGluZVxuICogYW5kIHZlcmlmeWluZyBpdCBpcyBwcm9jZXNzZWQgYnkgdGhlIHNwZWNpZmllZCBlbmRwb2ludC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGJ5cGFzc2VzIERlcGxveW1lbnQgUHJvdGVjdGlvbiBvbiBWZXJjZWwgYmVjYXVzZSBpdCBnb2VzXG4gKiB0aHJvdWdoIHRoZSBxdWV1ZSBpbmZyYXN0cnVjdHVyZSByYXRoZXIgdGhhbiBkaXJlY3QgSFRUUC5cbiAqXG4gKiBAcGFyYW0gd29ybGQgLSBUaGUgV29ybGQgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcGFyYW0gZW5kcG9pbnQgLSBXaGljaCBlbmRwb2ludCB0byBoZWFsdGggY2hlY2s6ICd3b3JrZmxvdycgb3IgJ3N0ZXAnXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBoZWFsdGggY2hlY2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIGhlYWx0aCBjaGVjayByZXN1bHRcbiAqL1xuLy8gUG9sbCBpbnRlcnZhbCBmb3IgaGVhbHRoIGNoZWNrIHJldHJpZXMgKG1zKVxuY29uc3QgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwgPSAxMDA7XG4vLyBQZXItcmVhZCB0aW1lb3V0IHRvIHByZXZlbnQgYmxvY2tpbmcgZm9yZXZlciBvbiBsb2NhbCB3b3JsZCdzIEV2ZW50RW1pdHRlclxuLy8gKHdoaWNoIGRvZXNuJ3Qgd29yayBhY3Jvc3MgcHJvY2Vzc2VzKVxuY29uc3QgSEVBTFRIX0NIRUNLX1JFQURfVElNRU9VVCA9IDUwMDtcblxuLyoqXG4gKiBSZWFkIGNodW5rcyBmcm9tIGEgc3RyZWFtIHdpdGggYSB0aW1lb3V0IHBlciByZWFkIG9wZXJhdGlvbi5cbiAqIFJldHVybnMgeyBjaHVua3MsIHRpbWVkT3V0IH0gd2hlcmUgdGltZWRPdXQgaW5kaWNhdGVzIGlmIGEgcmVhZCB0aW1lZCBvdXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlYWRTdHJlYW1XaXRoVGltZW91dChcbiAgcmVhZGVyOiBSZWFkYWJsZVN0cmVhbURlZmF1bHRSZWFkZXI8VWludDhBcnJheT4sXG4gIHJlYWRUaW1lb3V0OiBudW1iZXJcbik6IFByb21pc2U8eyBjaHVua3M6IFVpbnQ4QXJyYXlbXTsgdGltZWRPdXQ6IGJvb2xlYW4gfT4ge1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICBsZXQgZG9uZSA9IGZhbHNlO1xuICBsZXQgdGltZWRPdXQgPSBmYWxzZTtcblxuICB3aGlsZSAoIWRvbmUgJiYgIXRpbWVkT3V0KSB7XG4gICAgY29uc3QgcmVhZFByb21pc2UgPSByZWFkZXIucmVhZCgpO1xuICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2U8eyBkb25lOiB0cnVlOyB2YWx1ZTogdW5kZWZpbmVkIH0+KFxuICAgICAgKHJlc29sdmUpID0+XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHRpbWVkT3V0ID0gdHJ1ZTtcbiAgICAgICAgICByZXNvbHZlKHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgfSwgcmVhZFRpbWVvdXQpXG4gICAgKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UucmFjZShbcmVhZFByb21pc2UsIHRpbWVvdXRQcm9taXNlXSk7XG4gICAgZG9uZSA9IHJlc3VsdC5kb25lO1xuICAgIGlmIChyZXN1bHQudmFsdWUpIGNodW5rcy5wdXNoKHJlc3VsdC52YWx1ZSk7XG4gIH1cblxuICByZXR1cm4geyBjaHVua3MsIHRpbWVkT3V0IH07XG59XG5cbi8qKlxuICogUGFyc2UgYW5kIHZhbGlkYXRlIGEgaGVhbHRoIGNoZWNrIHJlc3BvbnNlIGZyb20gc3RyZWFtIGNodW5rcy5cbiAqIFJldHVybnMgdGhlIHBhcnNlZCByZXNwb25zZSBvciBudWxsIGlmIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShcbiAgY2h1bmtzOiBVaW50OEFycmF5W11cbik6IHsgaGVhbHRoeTogYm9vbGVhbiB9IHwgbnVsbCB7XG4gIGlmIChjaHVua3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcblxuICBjb25zdCB0b3RhbExlbmd0aCA9IGNodW5rcy5yZWR1Y2UoKHN1bSwgY2h1bmspID0+IHN1bSArIGNodW5rLmxlbmd0aCwgMCk7XG4gIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkodG90YWxMZW5ndGgpO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3MpIHtcbiAgICBjb21iaW5lZC5zZXQoY2h1bmssIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IGNodW5rLmxlbmd0aDtcbiAgfVxuICBjb25zdCByZXNwb25zZVRleHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoY29tYmluZWQpO1xuXG4gIGxldCByZXNwb25zZTogdW5rbm93bjtcbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IEpTT04ucGFyc2UocmVzcG9uc2VUZXh0KTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gT2xkIGRlcGxveW1lbnRzIChzcGVjVmVyc2lvbiA8IDMpIHJldHVybiBwbGFpbiB0ZXh0IGxpa2VcbiAgICAvLyAnV29ya2Zsb3cgU0RLIFwiLi4uXCIgZW5kcG9pbnQgaXMgaGVhbHRoeScuIFRyZWF0IGFueSBub24tZW1wdHlcbiAgICAvLyB0ZXh0IHJlc3BvbnNlIGFzIGEgaGVhbHRoeSBkZXBsb3ltZW50IHdpdGggdW5rbm93biBzcGVjVmVyc2lvbi5cbiAgICBpZiAocmVzcG9uc2VUZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoXG4gICAgdHlwZW9mIHJlc3BvbnNlICE9PSAnb2JqZWN0JyB8fFxuICAgIHJlc3BvbnNlID09PSBudWxsIHx8XG4gICAgISgnaGVhbHRoeScgaW4gcmVzcG9uc2UpIHx8XG4gICAgdHlwZW9mIChyZXNwb25zZSBhcyB7IGhlYWx0aHk6IHVua25vd24gfSkuaGVhbHRoeSAhPT0gJ2Jvb2xlYW4nXG4gICkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgciA9IHJlc3BvbnNlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBwYXJzZWQ6IHsgaGVhbHRoeTogYm9vbGVhbjsgc3BlY1ZlcnNpb24/OiBudW1iZXIgfSA9IHtcbiAgICBoZWFsdGh5OiByLmhlYWx0aHkgYXMgYm9vbGVhbixcbiAgfTtcbiAgaWYgKHR5cGVvZiByLnNwZWNWZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgIHBhcnNlZC5zcGVjVmVyc2lvbiA9IHIuc3BlY1ZlcnNpb247XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhlYWx0aENoZWNrKFxuICB3b3JsZDogV29ybGQsXG4gIGVuZHBvaW50OiBIZWFsdGhDaGVja0VuZHBvaW50LFxuICBvcHRpb25zPzogSGVhbHRoQ2hlY2tPcHRpb25zXG4pOiBQcm9taXNlPEhlYWx0aENoZWNrUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zPy50aW1lb3V0ID8/IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQ7XG4gIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBnZW5lcmF0ZUlkKCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoY29ycmVsYXRpb25JZCk7XG5cbiAgY29uc3QgcXVldWVOYW1lOiBWYWxpZFF1ZXVlTmFtZSA9XG4gICAgZW5kcG9pbnQgPT09ICd3b3JrZmxvdydcbiAgICAgID8gJ19fd2tmX3dvcmtmbG93X2hlYWx0aF9jaGVjaydcbiAgICAgIDogJ19fd2tmX3N0ZXBfaGVhbHRoX2NoZWNrJztcblxuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd29ybGQucXVldWUoXG4gICAgICBxdWV1ZU5hbWUsXG4gICAgICB7IF9faGVhbHRoQ2hlY2s6IHRydWUsIGNvcnJlbGF0aW9uSWQgfSxcbiAgICAgIHtcbiAgICAgICAgLy8gVXNlIEpTT04gdHJhbnNwb3J0IHNvIHRoZSBoZWFsdGggY2hlY2sgd29ya3MgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9sZCAoSlNPTi1vbmx5KSBhbmQgbmV3IChkdWFsKSBkZXBsb3ltZW50cy5cbiAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gICAgICAgIGRlcGxveW1lbnRJZDogb3B0aW9ucz8uZGVwbG95bWVudElkLFxuICAgICAgfVxuICAgICk7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA8IHRpbWVvdXQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IHdvcmxkLnN0cmVhbXMuZ2V0KFxuICAgICAgICAgIGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChjb3JyZWxhdGlvbklkKSxcbiAgICAgICAgICBzdHJlYW1OYW1lXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHN0cmVhbS5nZXRSZWFkZXIoKTtcbiAgICAgICAgY29uc3QgeyBjaHVua3MsIHRpbWVkT3V0IH0gPSBhd2FpdCByZWFkU3RyZWFtV2l0aFRpbWVvdXQoXG4gICAgICAgICAgcmVhZGVyLFxuICAgICAgICAgIEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVRcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGltZWRPdXQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVhZGVyLmNhbmNlbCgpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSWdub3JlIGNhbmNlbCBlcnJvcnNcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3MpO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4ucmVzcG9uc2UsXG4gICAgICAgICAgICBsYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydFRpbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBIZWFsdGggY2hlY2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tc2AsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhbHRoeTogZmFsc2UsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBMb2FkcyBhbGwgd29ya2Zsb3cgcnVuIGV2ZW50cyBieSBpdGVyYXRpbmcgdGhyb3VnaCBhbGwgcGFnZXMgb2YgcGFnaW5hdGVkIHJlc3VsdHMuXG4gKiBUaGlzIGVuc3VyZXMgdGhhdCAqYWxsKiBldmVudHMgYXJlIGxvYWRlZCBpbnRvIG1lbW9yeSBiZWZvcmUgcnVubmluZyB0aGUgd29ya2Zsb3cuXG4gKiBFdmVudHMgbXVzdCBiZSBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIChhc2NlbmRpbmcpIGZvciBwcm9wZXIgd29ya2Zsb3cgcmVwbGF5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0QWxsV29ya2Zsb3dSdW5FdmVudHMocnVuSWQ6IHN0cmluZyk6IFByb21pc2U8RXZlbnRbXT4ge1xuICByZXR1cm4gdHJhY2UoJ3dvcmtmbG93LmxvYWRFdmVudHMnLCBhc3luYyAoc3BhbikgPT4ge1xuICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuSWQocnVuSWQpLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYWxsRXZlbnRzOiBFdmVudFtdID0gW107XG4gICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gICAgbGV0IGhhc01vcmUgPSB0cnVlO1xuICAgIGxldCBwYWdlc0xvYWRlZCA9IDA7XG5cbiAgICBjb25zdCB3b3JsZCA9IGF3YWl0IGdldFdvcmxkKCk7XG4gICAgY29uc3QgbG9hZFN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICB3aGlsZSAoaGFzTW9yZSkge1xuICAgICAgLy8gVE9ETzogd2UncmUgY3VycmVudGx5IGxvYWRpbmcgYWxsIHRoZSBkYXRhIHdpdGggcmVzb2x2ZVJlZiBiZWhhdmlvdXIuIFdlIG5lZWQgdG8gdXBkYXRlIHRoaXNcbiAgICAgIC8vIHRvIGxhenlsb2FkIHRoZSBkYXRhIGZyb20gdGhlIHdvcmxkIGluc3RlYWQgc28gdGhhdCB3ZSBjYW4gb3B0aW1pemUgYW5kIG1ha2UgdGhlIGV2ZW50IGxvZyBsb2FkaW5nXG4gICAgICAvLyBtdWNoIGZhc3RlciBhbmQgbWVtb3J5IGVmZmljaWVudFxuICAgICAgY29uc3QgcGFnZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgd29ybGQuZXZlbnRzLmxpc3Qoe1xuICAgICAgICBydW5JZCxcbiAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgIHNvcnRPcmRlcjogJ2FzYycsIC8vIFJlcXVpcmVkOiBldmVudHMgbXVzdCBiZSBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyIGZvciByZXBsYXlcbiAgICAgICAgICBjdXJzb3I6IGN1cnNvciA/PyB1bmRlZmluZWQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgYWxsRXZlbnRzLnB1c2goLi4ucmVzcG9uc2UuZGF0YSk7XG4gICAgICBoYXNNb3JlID0gcmVzcG9uc2UuaGFzTW9yZTtcbiAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvcjtcbiAgICAgIHBhZ2VzTG9hZGVkKys7XG5cbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ0xvYWRlZCBldmVudCBwYWdlJywge1xuICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgcGFnZTogcGFnZXNMb2FkZWQsXG4gICAgICAgIHBhZ2VFdmVudHM6IHJlc3BvbnNlLmRhdGEubGVuZ3RoLFxuICAgICAgICB0b3RhbEV2ZW50czogYWxsRXZlbnRzLmxlbmd0aCxcbiAgICAgICAgaGFzTW9yZSxcbiAgICAgICAgcGFnZU1zOiBEYXRlLm5vdygpIC0gcGFnZVN0YXJ0LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnRXZlbnQgbG9hZGluZyBjb21wbGV0ZScsIHtcbiAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgdG90YWxFdmVudHM6IGFsbEV2ZW50cy5sZW5ndGgsXG4gICAgICBwYWdlc0xvYWRlZCxcbiAgICAgIHRvdGFsTXM6IERhdGUubm93KCkgLSBsb2FkU3RhcnQsXG4gICAgfSk7XG5cbiAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0V2ZW50c0NvdW50KGFsbEV2ZW50cy5sZW5ndGgpLFxuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXZlbnRzUGFnZXNMb2FkZWQocGFnZXNMb2FkZWQpLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGFsbEV2ZW50cztcbiAgfSk7XG59XG5cbi8qKlxuICogQ09SUyBoZWFkZXJzIGZvciBoZWFsdGggY2hlY2sgcmVzcG9uc2VzLlxuICogQWxsb3dzIHRoZSBvYnNlcnZhYmlsaXR5IFVJIHRvIGNoZWNrIGVuZHBvaW50IGhlYWx0aCBmcm9tIGEgZGlmZmVyZW50IG9yaWdpbi5cbiAqL1xuY29uc3QgSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyA9IHtcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnOiAnUE9TVCwgT1BUSU9OUywgR0VULCBIRUFEJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOiAnQ29udGVudC1UeXBlJyxcbn07XG5cbi8qKlxuICogV3JhcHMgYSByZXF1ZXN0L3Jlc3BvbnNlIGhhbmRsZXIgYW5kIGFkZHMgYSBoZWFsdGggY2hlY2sgXCJtb2RlXCJcbiAqIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhIGBfX2hlYWx0aGAgcXVlcnkgcGFyYW1ldGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEhlYWx0aENoZWNrKFxuICBoYW5kbGVyOiAocmVxOiBSZXF1ZXN0KSA9PiBQcm9taXNlPFJlc3BvbnNlPixcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4ge1xuICByZXR1cm4gYXN5bmMgKHJlcTogUmVxdWVzdCkgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCk7XG4gICAgY29uc3QgaXNIZWFsdGhDaGVjayA9IHVybC5zZWFyY2hQYXJhbXMuaGFzKCdfX2hlYWx0aCcpO1xuICAgIGlmIChpc0hlYWx0aENoZWNrKSB7XG4gICAgICAvLyBIYW5kbGUgQ09SUyBwcmVmbGlnaHQgZm9yIGhlYWx0aCBjaGVja1xuICAgICAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKG51bGwsIHtcbiAgICAgICAgICBzdGF0dXM6IDIwNCxcbiAgICAgICAgICBoZWFkZXJzOiBIRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBoZWFsdGh5OiB0cnVlLFxuICAgICAgICAgIGVuZHBvaW50OiB1cmwucGF0aG5hbWUsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IHdvcmxkU3BlY1ZlcnNpb24gPz8gU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgd29ya2Zsb3dDb3JlVmVyc2lvbixcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBzdGF0dXM6IDIwMCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgLi4uSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyxcbiAgICAgICAgICB9LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgaGFuZGxlcihyZXEpO1xuICB9O1xufVxuXG4vKipcbiAqIFF1ZXVlcyBhIG1lc3NhZ2UgdG8gdGhlIHNwZWNpZmllZCBxdWV1ZSB3aXRoIHRyYWNpbmcuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBxdWV1ZU1lc3NhZ2UoXG4gIHdvcmxkOiBXb3JsZCxcbiAgLi4uYXJnczogUGFyYW1ldGVyczx0eXBlb2Ygd29ybGQucXVldWU+XG4pIHtcbiAgY29uc3QgcXVldWVOYW1lID0gYXJnc1swXTtcbiAgYXdhaXQgdHJhY2UoXG4gICAgJ3F1ZXVlLnB1Ymxpc2gnLFxuICAgIHtcbiAgICAgIC8vIFN0YW5kYXJkIE9URUwgbWVzc2FnaW5nIGNvbnZlbnRpb25zXG4gICAgICBhdHRyaWJ1dGVzOiB7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdTeXN0ZW0oJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nRGVzdGluYXRpb25OYW1lKHF1ZXVlTmFtZSksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdPcGVyYXRpb25UeXBlKCdwdWJsaXNoJyksXG4gICAgICAgIC8vIFBlZXIgc2VydmljZSBmb3IgRGF0YWRvZyBzZXJ2aWNlIG1hcHNcbiAgICAgICAgLi4uQXR0cmlidXRlLlBlZXJTZXJ2aWNlKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5ScGNTZXJ2aWNlKCd2cXMnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY01ldGhvZCgncHVibGlzaCcpLFxuICAgICAgfSxcbiAgICAgIGtpbmQ6IGF3YWl0IGdldFNwYW5LaW5kKCdQUk9EVUNFUicpLFxuICAgIH0sXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIGNvbnN0IHsgbWVzc2FnZUlkIH0gPSBhd2FpdCB3b3JsZC5xdWV1ZSguLi5hcmdzKTtcbiAgICAgIGlmIChtZXNzYWdlSWQpIHtcbiAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyhBdHRyaWJ1dGUuTWVzc2FnaW5nTWVzc2FnZUlkKG1lc3NhZ2VJZCkpO1xuICAgICAgfVxuICAgIH1cbiAgKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBxdWV1ZSBvdmVyaGVhZCB0aW1lIGluIG1pbGxpc2Vjb25kcyBmb3IgYSBnaXZlbiBtZXNzYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVldWVPdmVyaGVhZChtZXNzYWdlOiB7IHJlcXVlc3RlZEF0PzogRGF0ZSB9KSB7XG4gIGlmICghbWVzc2FnZS5yZXF1ZXN0ZWRBdCkgcmV0dXJuO1xuICB0cnkge1xuICAgIHJldHVybiBBdHRyaWJ1dGUuUXVldWVPdmVyaGVhZE1zKFxuICAgICAgRGF0ZS5ub3coKSAtIG1lc3NhZ2UucmVxdWVzdGVkQXQuZ2V0VGltZSgpXG4gICAgKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuO1xuICB9XG59XG4iXX0=
842
+ /**
843
+ * Returns a memoized accessor for a run's full encryption capability.
844
+ *
845
+ * The first call resolves the run's key material via
846
+ * `world.getEncryptionKeyForRun` (which may do HKDF derivation locally on
847
+ * Vercel, or a network fetch from external contexts) and derives a
848
+ * {@link PayloadKey} from it; subsequent calls await the same cached promise.
849
+ * If the world doesn't support encryption or the run has no key configured,
850
+ * the cached value is `undefined`.
851
+ *
852
+ * The resolved value is deliberately the *full* capability — the symmetric AES
853
+ * key plus the run's X25519 keypair — not just a `CryptoKey`. A run reading
854
+ * its own event log can encounter sealed (`encp`) payloads that another run
855
+ * wrote to it (a cross-deployment hook resumption, say), and opening those
856
+ * needs the keypair. Resolving only the symmetric key would leave those
857
+ * payloads unopenable and wedge the run.
858
+ *
859
+ * Used by step / workflow handlers to defer the (potentially expensive)
860
+ * key fetch until the first code path that actually needs it — typically
861
+ * input hydration on the success path, or error dehydration on a failure
862
+ * path. Both paths can race-call the accessor without triggering duplicate
863
+ * fetches.
864
+ *
865
+ * Errors thrown by `getEncryptionKeyForRun` propagate to every caller
866
+ * (the cached promise rejects). This is intentional: when encryption is
867
+ * configured, we never want to silently fall back to plaintext
868
+ * serialization. A propagated error in an event-emission path leaves the
869
+ * outer try/catch to log and surface the issue; the queue's redelivery
870
+ * semantics will retry the key fetch on the next attempt.
871
+ */
872
+ export function memoizeEncryptionKey(world, runOrId) {
873
+ let cached;
874
+ return () => {
875
+ if (!cached) {
876
+ cached = (async () => {
877
+ // The `getEncryptionKeyForRun` overload set takes either a
878
+ // `WorkflowRun` or a `runId: string` (with optional context). Branch
879
+ // here so TypeScript picks the right overload for each shape.
880
+ const rawKey = typeof runOrId === 'string'
881
+ ? await world.getEncryptionKeyForRun?.(runOrId)
882
+ : await world.getEncryptionKeyForRun?.(runOrId);
883
+ // Resolve the *full* capability, not just the symmetric key: a run
884
+ // reading its own event log may encounter sealed (`encp`) payloads
885
+ // that another run wrote to it, and opening those needs the run's
886
+ // X25519 scalar as well.
887
+ return rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
888
+ })();
889
+ }
890
+ return cached;
891
+ };
892
+ }
893
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixlQUFlLEVBQ2Ysa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFXMUIsT0FBTyxFQUNMLGFBQWEsRUFDYixnQkFBZ0IsRUFDaEIsbUJBQW1CLEVBQ25CLHdCQUF3QixFQUN4Qix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixtQkFBbUIsRUFDbkIsVUFBVSxHQUNYLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ25FLE9BQU8sRUFDTCxvQkFBb0IsR0FFckIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbkQsd0RBQXdEO0FBQ3hELE1BQU0sNEJBQTRCLEdBQUcsTUFBTSxDQUFDO0FBRTVDOzs7O0dBSUc7QUFDSCxNQUFNLDBCQUEwQixHQUFHLHNCQUFzQixDQUFDO0FBRTFEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLFlBQW9CLEVBQ3BCLFNBQWtCO0lBRWxCLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFD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QixJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FDM0MsQ0FBQztJQUNKLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPO0lBQ1QsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLEtBQVksRUFDWixPQUE2QjtJQUU3QixJQUFJLE1BQW1ELENBQUM7SUFDeEQsT0FBTyxHQUFHLEVBQUU7UUFDVixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDbkIsMkRBQTJEO2dCQUMzRCxxRUFBcUU7Z0JBQ3JFLDhEQUE4RDtnQkFDOUQsTUFBTSxNQUFNLEdBQ1YsT0FBTyxPQUFPLEtBQUssUUFBUTtvQkFDekIsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLHNCQUFzQixFQUFFLENBQUMsT0FBTyxDQUFDO29CQUMvQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDcEQsbUVBQW1FO2dCQUNuRSxtRUFBbUU7Z0JBQ25FLGtFQUFrRTtnQkFDbEUseUJBQXlCO2dCQUN6QixPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBQ2pFLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDUCxDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIFByZWNvbmRpdGlvbkZhaWxlZEVycm9yLFxuICBSVU5fRVJST1JfQ09ERVMsXG4gIFdvcmtmbG93V29ybGRFcnJvcixcbn0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQgdHlwZSB7XG4gIENyZWF0ZUV2ZW50UGFyYW1zLFxuICBDcmVhdGVFdmVudFJlcXVlc3QsXG4gIEV2ZW50LFxuICBFdmVudFJlc3VsdCxcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBWYWxpZFF1ZXVlTmFtZSxcbiAgV29ya2Zsb3dSdW4sXG4gIFdvcmxkLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHtcbiAgZXZlbnRJZFRvU2xvdCxcbiAgRklSU1RfRVZFTlRfU0xPVCxcbiAgZ2V0UXVldWVUb3BpY1ByZWZpeCxcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkU2NoZW1hLFxuICBIT09LX1JFU1VNRV9JTlBVVF9WRVJTSU9OLFxuICByZXNvbHZlUXVldWVOYW1lc3BhY2UsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTUEVDX1ZFUlNJT05fTEVHQUNZLFxuICB1bGlkVG9EYXRlLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgbW9ub3RvbmljRmFjdG9yeSB9IGZyb20gJ3VsaWQnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBieXRlc1RvQmFzZTY0LCBkZXJpdmVSdW5LZXlQYWlyIH0gZnJvbSAnLi4vc2VhbGVkLWJveC5qcyc7XG5pbXBvcnQge1xuICBkZXJpdmVSdW5QYXlsb2FkS2V5cyxcbiAgdHlwZSBQYXlsb2FkS2V5LFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBnZXRTcGFuS2luZCwgdHJhY2UgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHsgdmVyc2lvbiBhcyB3b3JrZmxvd0NvcmVWZXJzaW9uIH0gZnJvbSAnLi4vdmVyc2lvbi5qcyc7XG5pbXBvcnQgeyBnZXRXb3JsZExhenkgfSBmcm9tICcuL2dldC13b3JsZC1sYXp5LmpzJztcblxuLyoqIERlZmF1bHQgdGltZW91dCBmb3IgaGVhbHRoIGNoZWNrcyBpbiBtaWxsaXNlY29uZHMgKi9cbmNvbnN0IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQgPSAzMF8wMDA7XG5cbi8qKlxuICogUGF0dGVybiBmb3Igc2FmZSB3b3JrZmxvdyBuYW1lcy4gT25seSBhbGxvd3MgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsXG4gKiB1bmRlcnNjb3JlcywgaHlwaGVucywgZG90cywgZm9yd2FyZCBzbGFzaGVzIChmb3IgbmFtZXNwYWNlZCB3b3JrZmxvd3MpLFxuICogYW5kIGF0IHNpZ25zIChmb3Igc2NvcGVkIHBhY2thZ2VzKS5cbiAqL1xuY29uc3QgU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4gPSAvXlthLXpBLVowLTlfXFwtLi9AXSskLztcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYSB3b3JrZmxvdyBuYW1lIGFuZCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHF1ZXVlIG5hbWUuXG4gKiBFbnN1cmVzIHRoZSB3b3JrZmxvdyBuYW1lIG9ubHkgY29udGFpbnMgc2FmZSBjaGFyYWN0ZXJzIGJlZm9yZVxuICogaW50ZXJwb2xhdGluZyBpdCBpbnRvIHRoZSBxdWV1ZSBuYW1lIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFdvcmtmbG93UXVldWVOYW1lKFxuICB3b3JrZmxvd05hbWU6IHN0cmluZyxcbiAgbmFtZXNwYWNlPzogc3RyaW5nXG4pOiBWYWxpZFF1ZXVlTmFtZSB7XG4gIGlmICghU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4udGVzdCh3b3JrZmxvd05hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEludmFsaWQgd29ya2Zsb3cgbmFtZSBcIiR7d29ya2Zsb3dOYW1lfVwiOiBtdXN0IG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgdW5kZXJzY29yZXMsIGh5cGhlbnMsIGRvdHMsIGZvcndhcmQgc2xhc2hlcywgb3IgYXQgc2lnbnNgXG4gICAgKTtcbiAgfVxuICBjb25zdCBwcmVmaXggPSBnZXRRdWV1ZVRvcGljUHJlZml4KFxuICAgICd3b3JrZmxvdycsXG4gICAgcmVzb2x2ZVF1ZXVlTmFtZXNwYWNlKG5hbWVzcGFjZSlcbiAgKTtcbiAgcmV0dXJuIGAke3ByZWZpeH0ke3dvcmtmbG93TmFtZX1gIGFzIFZhbGlkUXVldWVOYW1lO1xufVxuXG5jb25zdCBnZW5lcmF0ZUlkID0gbW9ub3RvbmljRmFjdG9yeSgpO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIHN0cmVhbSBuYW1lIGZvciBhIGhlYWx0aCBjaGVjayB3aXRoIHRoZSBnaXZlbiBjb3JyZWxhdGlvbiBJRC5cbiAqL1xuZnVuY3Rpb24gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgX19oZWFsdGhfY2hlY2tfXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBhIGhlYWx0aCBjaGVjayBvcGVyYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tSZXN1bHQge1xuICBoZWFsdGh5OiBib29sZWFuO1xuICAvKiogRXJyb3IgbWVzc2FnZSBpZiBoZWFsdGggY2hlY2sgZmFpbGVkICovXG4gIGVycm9yPzogc3RyaW5nO1xuICAvKiogTGF0ZW5jeSBpZiB0aGUgaGVhbHRoIGNoZWNrIHdhcyBzdWNjZXNzZnVsICovXG4gIGxhdGVuY3lNcz86IG51bWJlcjtcbiAgLyoqIFNwZWMgdmVyc2lvbiBvZiB0aGUgcmVzcG9uZGluZyBkZXBsb3ltZW50ICovXG4gIHNwZWNWZXJzaW9uPzogbnVtYmVyO1xuICAvKipcbiAgICogYEB3b3JrZmxvdy9jb3JlYCB2ZXJzaW9uIG9mIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQsIHVzZWQgZm9yXG4gICAqIGNhcGFiaWxpdHkgZGV0ZWN0aW9uIChzZWUgYGdldFJ1bkNhcGFiaWxpdGllc2ApLiBPbWl0dGVkIHdoZW4gdGhlXG4gICAqIHJlc3BvbmRpbmcgZGVwbG95bWVudCBkaWQgbm90IHByb3ZpZGUgdGhlIGZpZWxkIGFzIGEgc3RyaW5nIOKAlFxuICAgKiBmb3IgZXhhbXBsZSwgYW4gb2xkZXIgYEB3b3JrZmxvdy9jb3JlYCB0aGF0IHByZWRhdGVzIHRoaXMgZmllbGQsXG4gICAqIG9yIGEgbm9uLUpTT04gcGxhaW4tdGV4dCBoZWFsdGggcmVzcG9uc2UuXG4gICAqL1xuICB3b3JrZmxvd0NvcmVWZXJzaW9uPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHRhcmdldCBydW4ncyBYMjU1MTkgcHVibGljIGtleSAoYmFzZTY0KSwgcmV0dXJuZWQgb25seSB3aGVuIHRoZSBwcm9iZVxuICAgKiBjYXJyaWVkIGEgYHJ1bklkYCBhbmQgdGhlIHJlc3BvbmRpbmcgZGVwbG95bWVudCBoYXMgZW5jcnlwdGlvbiBlbmFibGVkLlxuICAgKlxuICAgKiBMZXRzIGEgY3Jvc3MtZGVwbG95bWVudCBgc3RhcnQoKWAgc2VhbCB0aGUgd29ya2Zsb3cgYXJndW1lbnRzIHVzaW5nIGFcbiAgICogcmVzcG9uc2UgaXQgd2FzIGFscmVhZHkgd2FpdGluZyBvbiwgaW5zdGVhZCBvZiBtYWtpbmcgYSBzZXBhcmF0ZVxuICAgKiBrZXktbG9va3VwIHJlcXVlc3QuXG4gICAqL1xuICBlbmNyeXB0aW9uUHVibGljS2V5Pzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHJlc3BvbmRpbmcgZGVwbG95bWVudCdzIGBIT09LX1JFU1VNRV9JTlBVVF9WRVJTSU9OYCDigJQgdGhlIHByb3RvY29sXG4gICAqIHZlcnNpb24gYXQgd2hpY2ggdGhlICpjb25zdW1lciogKHF1ZXVlLW1lc3NhZ2UgdGFyZ2V0KSByZS1lbnN1cmVzIHRoZVxuICAgKiBgaG9va19yZWNlaXZlZGAgZXZlbnQgZnJvbSBgaG9va0lucHV0YCBvbiByZXBsYXkuIEEgY3Jvc3MtZGVwbG95bWVudFxuICAgKiBgc3RhcnQoKWAgc3RhbXBzIHRoZSAqdGFyZ2V0J3MqIHZhbHVlIChub3QgdGhlIGNhbGxlcidzKSBpbnRvIHRoZSBuZXdcbiAgICogcnVuJ3MgYGV4ZWN1dGlvbkNvbnRleHQuaG9va1Jlc3VtZUlucHV0VmVyc2lvbmAgc28gdGhhdCBgcmVzdW1lSG9vaygpYFxuICAgKiBvbmx5IHRha2VzIHRoZSBwYXJhbGxlbCBwYXRoIHdoZW4gdGhlIGRlcGxveW1lbnQgdGhhdCB3aWxsIGFjdHVhbGx5XG4gICAqIGNvbnN1bWUgdGhlIHF1ZXVlIG1lc3NhZ2UgaXMga25vd24gdG8gaG9ub3IgYGhvb2tJbnB1dGAuIE9taXR0ZWQgd2hlbiB0aGVcbiAgICogcmVzcG9uZGluZyBkZXBsb3ltZW50IHByZWRhdGVzIHRoaXMgZmllbGQgKGFuIG9sZGVyIGNvbnN1bWVyIHRoYXQgaWdub3Jlc1xuICAgKiBgaG9va0lucHV0YCksIHdoaWNoIGZhaWxzIHRoZSBnYXRlIGNsb3NlZC5cbiAgICovXG4gIGhvb2tSZXN1bWVJbnB1dFZlcnNpb24/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBtZXNzYWdlIGlzIGEgaGVhbHRoIGNoZWNrIHBheWxvYWQuXG4gKiBJZiBzbywgcmV0dXJucyB0aGUgcGFyc2VkIHBheWxvYWQuIE90aGVyd2lzZSByZXR1cm5zIHVuZGVmaW5lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tQYXlsb2FkKFxuICBtZXNzYWdlOiB1bmtub3duXG4pOiBIZWFsdGhDaGVja1BheWxvYWQgfCB1bmRlZmluZWQge1xuICBjb25zdCByZXN1bHQgPSBIZWFsdGhDaGVja1BheWxvYWRTY2hlbWEuc2FmZVBhcnNlKG1lc3NhZ2UpO1xuICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4gcmVzdWx0LmRhdGE7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBkZXRlcm1pbmlzdGljIGZha2UgcnVuSWQgZm9yIGhlYWx0aCBjaGVjayBzdHJlYW1zLlxuICogQm90aCB0aGUgd3JpdGVyIChoYW5kbGVIZWFsdGhDaGVja01lc3NhZ2UpIGFuZCByZWFkZXIgKGhlYWx0aENoZWNrKSBkZXJpdmVcbiAqIHRoZSBzYW1lIHJ1bklkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdCBpbXBsZW1lbnRhdGlvbnMgdGhhdCBzY29wZVxuICogc3RyZWFtIHJlYWRzIGJ5IHJ1bklkIHN0aWxsIHdvcmsgY29ycmVjdGx5LlxuICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhlYWx0aENoZWNrUnVuSWQoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGB3cnVuX2hjXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIEhhbmRsZXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZSBieSB3cml0aW5nIHRoZSByZXN1bHQgdG8gdGhlIHdvcmxkJ3Mgc3RyZWFtLlxuICogVGhlIGNhbGxlciBjYW4gbGlzdGVuIHRvIHRoaXMgc3RyZWFtIHRvIGdldCB0aGUgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSBoZWFsdGhDaGVjayAtIFRoZSBwYXJzZWQgaGVhbHRoIGNoZWNrIHBheWxvYWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgaGVhbHRoQ2hlY2s6IEhlYWx0aENoZWNrUGF5bG9hZCxcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCk7XG5cbiAgLy8gV2hlbiB0aGUgcHJvYmUgbmFtZXMgYSBydW4gdGhlIGNhbGxlciBpcyBhYm91dCB0byBjcmVhdGUsIHB1Ymxpc2ggdGhhdFxuICAvLyBydW4ncyBwdWJsaWMga2V5LiBXZSBhcmUgZXhlY3V0aW5nIGluc2lkZSB0aGUgdGFyZ2V0IGRlcGxveW1lbnQsIHNvIGl0c1xuICAvLyBrZXkgbWF0ZXJpYWwgaXMgYXZhaWxhYmxlIGxvY2FsbHkgKG5vIEFQSSBjYWxsKSwgYW5kIHRoZSBjYWxsZXIgY2FuIHRoZW5cbiAgLy8gc2VhbCB0aGUgd29ya2Zsb3cgYXJndW1lbnRzIHN0cmFpZ2h0IGZyb20gdGhpcyByZXNwb25zZSByYXRoZXIgdGhhblxuICAvLyBtYWtpbmcgYSBzZXBhcmF0ZSBrZXktbG9va3VwIHJlcXVlc3QuXG4gIC8vXG4gIC8vIE9ubHkgYSAqcHVibGljKiBrZXkgbWF5IHRyYXZlbCB0aGlzIHdheTogdGhlIHByb2JlIHJlc3BvbnNlIHN0cmVhbSBpc1xuICAvLyBkZWxpYmVyYXRlbHkgdW5hdXRoZW50aWNhdGVkLCBzbyBhbnl0aGluZyBzZWNyZXQgd291bGQgYmUgZXhwb3NlZC5cbiAgLy8gQmVzdC1lZmZvcnQg4oCUIGEgZmFpbHVyZSBoZXJlIG11c3Qgbm90IGZhaWwgdGhlIGhlYWx0aCBjaGVjayBpdHNlbGYsIHdoaWNoXG4gIC8vIGNhbGxlcnMgYWxzbyByZWx5IG9uIGZvciBwbGFpbiBjYXBhYmlsaXR5IGRldGVjdGlvbi5cbiAgbGV0IGVuY3J5cHRpb25QdWJsaWNLZXk6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaWYgKGhlYWx0aENoZWNrLnJ1bklkKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJhd0tleSA9IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihoZWFsdGhDaGVjay5ydW5JZCk7XG4gICAgICBpZiAocmF3S2V5KSB7XG4gICAgICAgIGVuY3J5cHRpb25QdWJsaWNLZXkgPSBieXRlc1RvQmFzZTY0KFxuICAgICAgICAgIChhd2FpdCBkZXJpdmVSdW5LZXlQYWlyKHJhd0tleSkpLnB1YmxpY0tleVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAnSGVhbHRoIGNoZWNrIGNvdWxkIG5vdCBkZXJpdmUgYSBydW4gcHVibGljIGtleTsgdGhlIGNhbGxlciB3aWxsIGZhbGwgYmFjayB0byBhIGtleSBsb29rdXAnLFxuICAgICAgICB7XG4gICAgICAgICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIGhlYWx0aHk6IHRydWUsXG4gICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgIC8vIFdlIGFyZSBleGVjdXRpbmcgaW5zaWRlIHRoZSB0YXJnZXQgZGVwbG95bWVudCwgc28gdGhpcyBjb25zdGFudCByZWZsZWN0c1xuICAgIC8vIHRoZSAqY29uc3VtZXIncyogaG9vay1yZXN1bWUgcHJvdG9jb2wgdmVyc2lvbiDigJQgZXhhY3RseSB3aGF0IGFcbiAgICAvLyBjcm9zcy1kZXBsb3ltZW50IGNhbGxlciBuZWVkcyB0byBnYXRlIGl0cyBwYXJhbGxlbCByZXN1bWUgcGF0aCBvbi5cbiAgICBob29rUmVzdW1lSW5wdXRWZXJzaW9uOiBIT09LX1JFU1VNRV9JTlBVVF9WRVJTSU9OLFxuICAgIC4uLihlbmNyeXB0aW9uUHVibGljS2V5ID8geyBlbmNyeXB0aW9uUHVibGljS2V5IH0gOiB7fSksXG4gICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICB9KTtcbiAgLy8gVXNlIGEgZGV0ZXJtaW5pc3RpYyBmYWtlIHJ1bklkIGRlcml2ZWQgZnJvbSB0aGUgY29ycmVsYXRpb25JZCBzbyB0aGF0XG4gIC8vIHRoZSByZWFkZXIgc2lkZSBwcm9kdWNlcyB0aGUgc2FtZSB2YWx1ZS5cbiAgY29uc3QgZmFrZVJ1bklkID0gZ2VuZXJhdGVIZWFsdGhDaGVja1J1bklkKGhlYWx0aENoZWNrLmNvcnJlbGF0aW9uSWQpO1xuICBhd2FpdCB3b3JsZC5zdHJlYW1zLndyaXRlKGZha2VSdW5JZCwgc3RyZWFtTmFtZSwgcmVzcG9uc2UpO1xuICBhd2FpdCB3b3JsZC5zdHJlYW1zLmNsb3NlKGZha2VSdW5JZCwgc3RyZWFtTmFtZSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tPcHRpb25zIHtcbiAgLyoqIFRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGhlYWx0aCBjaGVjayByZXNwb25zZS4gRGVmYXVsdDogMzAwMDAgKDMwcykgKi9cbiAgdGltZW91dD86IG51bWJlcjtcbiAgLyoqIERlcGxveW1lbnQgSUQgdG8gc2VuZCB0aGUgaGVhbHRoIGNoZWNrIHRvLiBGYWxscyBiYWNrIHRvIHByb2Nlc3MuZW52LlZFUkNFTF9ERVBMT1lNRU5UX0lELiAqL1xuICBkZXBsb3ltZW50SWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgcnVuIGlkIHRoZSBjYWxsZXIgaXMgYWJvdXQgdG8gY3JlYXRlLiBXaGVuIHNldCwgdGhlIHJlc3BvbmRpbmdcbiAgICogZGVwbG95bWVudCBkZXJpdmVzIHRoYXQgcnVuJ3MgcHVibGljIGtleSBsb2NhbGx5IGFuZCByZXR1cm5zIGl0IGFzXG4gICAqIGBlbmNyeXB0aW9uUHVibGljS2V5YCwgbGV0dGluZyBhIGNyb3NzLWRlcGxveW1lbnQgYHN0YXJ0KClgIHNlYWwgdGhlXG4gICAqIHdvcmtmbG93IGFyZ3VtZW50cyB3aXRob3V0IGEgc2VwYXJhdGUga2V5IGxvb2t1cC5cbiAgICovXG4gIHJ1bklkPzogc3RyaW5nO1xuICAvKipcbiAgICogUXVldWUgbmFtZXNwYWNlIG9mIHRoZSB0YXJnZXQgZGVwbG95bWVudCAoZS5nLiBgJ2V2ZSdgIGZvciB0b3BpY3MgbGlrZVxuICAgKiBgX19ldmVfd2tmX3dvcmtmbG93XypgKS4gRmFsbHMgYmFjayB0byBgV09SS0ZMT1dfUVVFVUVfTkFNRVNQQUNFYCBpbiB0aGVcbiAgICogY2FsbGluZyBwcm9jZXNzLiBDcm9zcy1jb250ZXh0IGNhbGxlcnMgKGUuZy4gdGhlIG9ic2VydmFiaWxpdHlcbiAgICogZGFzaGJvYXJkKSBtdXN0IHBhc3MgdGhlIHRhcmdldCBkZXBsb3ltZW50J3MgbmFtZXNwYWNlIGV4cGxpY2l0bHkg4oCUXG4gICAqIHRoZSBlbnYgZmFsbGJhY2sgcmVzb2x2ZXMgaW4gdGhlIGNhbGxlcidzIHByb2Nlc3MsIGFuZCBhIG1lc3NhZ2VcbiAgICogcHVibGlzaGVkIHRvIGEgbWlzbWF0Y2hlZCB0b3BpYyBoYXMgbm8gY29uc3VtZXIsIHNvIHRoZSBjaGVjayB3b3VsZFxuICAgKiBhbHdheXMgdGltZSBvdXQuXG4gICAqL1xuICBuYW1lc3BhY2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUGVyZm9ybXMgYSBoZWFsdGggY2hlY2sgYnkgc2VuZGluZyBhIG1lc3NhZ2UgdGhyb3VnaCB0aGUgcXVldWUgcGlwZWxpbmVcbiAqIGFuZCB2ZXJpZnlpbmcgaXQgaXMgcHJvY2Vzc2VkIGJ5IHRoZSBjb21iaW5lZCB3b3JrZmxvdyBlbmRwb2ludC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGJ5cGFzc2VzIERlcGxveW1lbnQgUHJvdGVjdGlvbiBvbiBWZXJjZWwgYmVjYXVzZSBpdCBnb2VzXG4gKiB0aHJvdWdoIHRoZSBxdWV1ZSBpbmZyYXN0cnVjdHVyZSByYXRoZXIgdGhhbiBkaXJlY3QgSFRUUC5cbiAqXG4gKiBAcGFyYW0gd29ybGQgLSBUaGUgV29ybGQgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBoZWFsdGggY2hlY2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIGhlYWx0aCBjaGVjayByZXN1bHRcbiAqL1xuLy8gUG9sbCBpbnRlcnZhbCBmb3IgaGVhbHRoIGNoZWNrIHJldHJpZXMgKG1zKVxuY29uc3QgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwgPSAxMDA7XG4vLyBQZXItcmVhZCB0aW1lb3V0IHRvIHByZXZlbnQgYmxvY2tpbmcgZm9yZXZlciBvbiBsb2NhbCB3b3JsZCdzIEV2ZW50RW1pdHRlclxuLy8gKHdoaWNoIGRvZXNuJ3Qgd29yayBhY3Jvc3MgcHJvY2Vzc2VzKVxuY29uc3QgSEVBTFRIX0NIRUNLX1JFQURfVElNRU9VVCA9IDUwMDtcblxuLyoqXG4gKiBSZWFkIGNodW5rcyBmcm9tIGEgc3RyZWFtIHdpdGggYSB0aW1lb3V0IHBlciByZWFkIG9wZXJhdGlvbi5cbiAqIFJldHVybnMgeyBjaHVua3MsIHRpbWVkT3V0IH0gd2hlcmUgdGltZWRPdXQgaW5kaWNhdGVzIGlmIGEgcmVhZCB0aW1lZCBvdXQuXG4gKi9cbi8qKlxuICogUmFjZSBhIHByb21pc2UgYWdhaW5zdCBhIGRlYWRsaW5lLiBSZWplY3RzIHdpdGggYSB0aW1lb3V0IGVycm9yIHdoZW4gdGhlXG4gKiBkZWFkbGluZSBlbGFwc2VzIGZpcnN0LiBVc2VkIHRvIGJvdW5kIGB3b3JsZC5zdHJlYW1zLmdldCgpYCBpbnNpZGUgdGhlXG4gKiBoZWFsdGgtY2hlY2sgcG9sbCBsb29wOiBzb21lIHdvcmxkcyBob2xkIHRoYXQgcmVxdWVzdCBvcGVuIHVudGlsIHRoZVxuICogc3RyZWFtIGhhcyBkYXRhIChlLmcuIHdvcmtmbG93LXNlcnZlciBob2xkcyB1bndyaXR0ZW4gc3RyZWFtcyBvcGVuIGZvclxuICogfjIgbWludXRlcyksIHdoaWNoIHdvdWxkIG90aGVyd2lzZSBibG93IHRocm91Z2ggdGhlIGNvbmZpZ3VyZWQgaGVhbHRoXG4gKiBjaGVjayB0aW1lb3V0IOKAlCB0aGUgYHdoaWxlYCBjb25kaXRpb24gaXMgb25seSByZS1jaGVja2VkIGJldHdlZW5cbiAqIGl0ZXJhdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIHdpdGhEZWFkbGluZTxUPihwcm9taXNlOiBQcm9taXNlPFQ+LCBtczogbnVtYmVyKTogUHJvbWlzZTxUPiB7XG4gIGxldCB0aW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xuICAgIHByb21pc2UsXG4gICAgbmV3IFByb21pc2U8bmV2ZXI+KChfLCByZWplY3QpID0+IHtcbiAgICAgIHRpbWVyID0gc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihgT3BlcmF0aW9uIHRpbWVkIG91dCBhZnRlciAke21zfW1zYCkpLFxuICAgICAgICBtc1xuICAgICAgKTtcbiAgICB9KSxcbiAgXSkuZmluYWxseSgoKSA9PiBjbGVhclRpbWVvdXQodGltZXIpKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZFN0cmVhbVdpdGhUaW1lb3V0KFxuICByZWFkZXI6IFJlYWRhYmxlU3RyZWFtRGVmYXVsdFJlYWRlcjxVaW50OEFycmF5PixcbiAgcmVhZFRpbWVvdXQ6IG51bWJlclxuKTogUHJvbWlzZTx7IGNodW5rczogVWludDhBcnJheVtdOyB0aW1lZE91dDogYm9vbGVhbiB9PiB7XG4gIGNvbnN0IGNodW5rczogVWludDhBcnJheVtdID0gW107XG4gIGxldCBkb25lID0gZmFsc2U7XG4gIGxldCB0aW1lZE91dCA9IGZhbHNlO1xuXG4gIHdoaWxlICghZG9uZSAmJiAhdGltZWRPdXQpIHtcbiAgICBjb25zdCByZWFkUHJvbWlzZSA9IHJlYWRlci5yZWFkKCk7XG4gICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZTx7IGRvbmU6IHRydWU7IHZhbHVlOiB1bmRlZmluZWQgfT4oXG4gICAgICAocmVzb2x2ZSkgPT5cbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgdGltZWRPdXQgPSB0cnVlO1xuICAgICAgICAgIHJlc29sdmUoeyBkb25lOiB0cnVlLCB2YWx1ZTogdW5kZWZpbmVkIH0pO1xuICAgICAgICB9LCByZWFkVGltZW91dClcbiAgICApO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtyZWFkUHJvbWlzZSwgdGltZW91dFByb21pc2VdKTtcbiAgICBkb25lID0gcmVzdWx0LmRvbmU7XG4gICAgaWYgKHJlc3VsdC52YWx1ZSkgY2h1bmtzLnB1c2gocmVzdWx0LnZhbHVlKTtcbiAgfVxuXG4gIHJldHVybiB7IGNodW5rcywgdGltZWRPdXQgfTtcbn1cblxuLyoqXG4gKiBQYXJzZSBhbmQgdmFsaWRhdGUgYSBoZWFsdGggY2hlY2sgcmVzcG9uc2UgZnJvbSBzdHJlYW0gY2h1bmtzLlxuICogUmV0dXJucyB0aGUgcGFyc2VkIHJlc3BvbnNlIG9yIG51bGwgaWYgaW52YWxpZC5cbiAqL1xuZnVuY3Rpb24gcGFyc2VIZWFsdGhDaGVja1Jlc3BvbnNlKGNodW5rczogVWludDhBcnJheVtdKToge1xuICBoZWFsdGh5OiBib29sZWFuO1xuICBzcGVjVmVyc2lvbj86IG51bWJlcjtcbiAgd29ya2Zsb3dDb3JlVmVyc2lvbj86IHN0cmluZztcbiAgZW5jcnlwdGlvblB1YmxpY0tleT86IHN0cmluZztcbn0gfCBudWxsIHtcbiAgaWYgKGNodW5rcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IHRvdGFsTGVuZ3RoID0gY2h1bmtzLnJlZHVjZSgoc3VtLCBjaHVuaykgPT4gc3VtICsgY2h1bmsubGVuZ3RoLCAwKTtcbiAgY29uc3QgY29tYmluZWQgPSBuZXcgVWludDhBcnJheSh0b3RhbExlbmd0aCk7XG4gIGxldCBvZmZzZXQgPSAwO1xuICBmb3IgKGNvbnN0IGNodW5rIG9mIGNodW5rcykge1xuICAgIGNvbWJpbmVkLnNldChjaHVuaywgb2Zmc2V0KTtcbiAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICB9XG4gIGNvbnN0IHJlc3BvbnNlVGV4dCA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShjb21iaW5lZCk7XG5cbiAgbGV0IHJlc3BvbnNlOiB1bmtub3duO1xuICB0cnkge1xuICAgIHJlc3BvbnNlID0gSlNPTi5wYXJzZShyZXNwb25zZVRleHQpO1xuICB9IGNhdGNoIHtcbiAgICAvLyBPbGQgZGVwbG95bWVudHMgKHNwZWNWZXJzaW9uIDwgMykgcmV0dXJuIHBsYWluIHRleHQgbGlrZVxuICAgIC8vICdXb3JrZmxvdyBTREsgXCIuLi5cIiBlbmRwb2ludCBpcyBoZWFsdGh5Jy4gVHJlYXQgYW55IG5vbi1lbXB0eVxuICAgIC8vIHRleHQgcmVzcG9uc2UgYXMgYSBoZWFsdGh5IGRlcGxveW1lbnQgd2l0aCB1bmtub3duIHNwZWNWZXJzaW9uLlxuICAgIGlmIChyZXNwb25zZVRleHQubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHsgaGVhbHRoeTogdHJ1ZSB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmIChcbiAgICB0eXBlb2YgcmVzcG9uc2UgIT09ICdvYmplY3QnIHx8XG4gICAgcmVzcG9uc2UgPT09IG51bGwgfHxcbiAgICAhKCdoZWFsdGh5JyBpbiByZXNwb25zZSkgfHxcbiAgICB0eXBlb2YgKHJlc3BvbnNlIGFzIHsgaGVhbHRoeTogdW5rbm93biB9KS5oZWFsdGh5ICE9PSAnYm9vbGVhbidcbiAgKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCByID0gcmVzcG9uc2UgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHBhcnNlZDoge1xuICAgIGhlYWx0aHk6IGJvb2xlYW47XG4gICAgc3BlY1ZlcnNpb24/OiBudW1iZXI7XG4gICAgd29ya2Zsb3dDb3JlVmVyc2lvbj86IHN0cmluZztcbiAgICBlbmNyeXB0aW9uUHVibGljS2V5Pzogc3RyaW5nO1xuICAgIGhvb2tSZXN1bWVJbnB1dFZlcnNpb24/OiBudW1iZXI7XG4gIH0gPSB7XG4gICAgaGVhbHRoeTogci5oZWFsdGh5IGFzIGJvb2xlYW4sXG4gIH07XG4gIGlmICh0eXBlb2Ygci5zcGVjVmVyc2lvbiA9PT0gJ251bWJlcicpIHtcbiAgICBwYXJzZWQuc3BlY1ZlcnNpb24gPSByLnNwZWNWZXJzaW9uO1xuICB9XG4gIGlmICh0eXBlb2Ygci53b3JrZmxvd0NvcmVWZXJzaW9uID09PSAnc3RyaW5nJykge1xuICAgIHBhcnNlZC53b3JrZmxvd0NvcmVWZXJzaW9uID0gci53b3JrZmxvd0NvcmVWZXJzaW9uO1xuICB9XG4gIGlmICh0eXBlb2Ygci5lbmNyeXB0aW9uUHVibGljS2V5ID09PSAnc3RyaW5nJykge1xuICAgIHBhcnNlZC5lbmNyeXB0aW9uUHVibGljS2V5ID0gci5lbmNyeXB0aW9uUHVibGljS2V5O1xuICB9XG4gIGlmICh0eXBlb2Ygci5ob29rUmVzdW1lSW5wdXRWZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgIHBhcnNlZC5ob29rUmVzdW1lSW5wdXRWZXJzaW9uID0gci5ob29rUmVzdW1lSW5wdXRWZXJzaW9uO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoZWFsdGhDaGVjayhcbiAgd29ybGQ6IFdvcmxkLFxuICBvcHRpb25zPzogSGVhbHRoQ2hlY2tPcHRpb25zXG4pOiBQcm9taXNlPEhlYWx0aENoZWNrUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zPy50aW1lb3V0ID8/IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQ7XG4gIC8vIFVzZSB0aGUgd29ybGQncyBJRCBnZW5lcmF0b3Igd2hlbiBhdmFpbGFibGUgc28gdGhlIGNvcnJlbGF0aW9uSWQgaXMgYVxuICAvLyByZWdpb24tdGFnZ2VkIFVMSUQuIFRoZSBoZWFsdGgtY2hlY2sgcmVzcG9uc2UgaXMgZGVsaXZlcmVkIG92ZXIgYSBzdHJlYW1cbiAgLy8gd2hvc2UgbmFtZSBlbWJlZHMgdGhpcyBjb3JyZWxhdGlvbklkOyB1bmRlciBwbGF0Zm9ybS1kaXJlY3RlZCByb3V0aW5nIHRoZVxuICAvLyByZWFkZXIgYW5kIHRoZSByZXNwb25kaW5nIGVuZHBvaW50IGNhbiBiZSBzZXJ2ZWQgZnJvbSBkaWZmZXJlbnQgcGh5c2ljYWxcbiAgLy8gcmVnaW9ucywgc28gdGhlIHJlZ2lvbiBtdXN0IGJlIGVuY29kZWQgaW4gdGhlIElEIGl0c2VsZiBmb3IgYm90aCBzaWRlcyB0b1xuICAvLyByZXNvbHZlIHRoZSBzYW1lIChyZWdpb24tcGlubmVkKSBiYWNrZW5kLiBGYWxscyBiYWNrIHRvIGEgcGxhaW4gVUxJRCBmb3JcbiAgLy8gd29ybGRzIHRoYXQgZG9uJ3QgdGFnIElEcyAoZS5nLiBsb2NhbCksIHdoaWNoIHJlc29sdmUgdG8gdGhlIGRlZmF1bHRcbiAgLy8gcmVnaW9uIG9uIGJvdGggc2lkZXMuXG4gIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSB3b3JsZC5jcmVhdGVSdW5JZD8uKCkgPz8gZ2VuZXJhdGVJZCgpO1xuICBjb25zdCBzdHJlYW1OYW1lID0gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGNvcnJlbGF0aW9uSWQpO1xuXG4gIGNvbnN0IHF1ZXVlTmFtZSA9XG4gICAgYCR7Z2V0UXVldWVUb3BpY1ByZWZpeCgnd29ya2Zsb3cnLCByZXNvbHZlUXVldWVOYW1lc3BhY2Uob3B0aW9ucz8ubmFtZXNwYWNlKSl9aGVhbHRoX2NoZWNrYCBhcyBWYWxpZFF1ZXVlTmFtZTtcblxuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd29ybGQucXVldWUoXG4gICAgICBxdWV1ZU5hbWUsXG4gICAgICB7XG4gICAgICAgIF9faGVhbHRoQ2hlY2s6IHRydWUsXG4gICAgICAgIGNvcnJlbGF0aW9uSWQsXG4gICAgICAgIC4uLihvcHRpb25zPy5ydW5JZCA/IHsgcnVuSWQ6IG9wdGlvbnMucnVuSWQgfSA6IHt9KSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIC8vIFVzZSBKU09OIHRyYW5zcG9ydCBzbyB0aGUgaGVhbHRoIGNoZWNrIHdvcmtzIGFnYWluc3QgYm90aFxuICAgICAgICAvLyBvbGQgKEpTT04tb25seSkgYW5kIG5ldyAoZHVhbCkgZGVwbG95bWVudHMuXG4gICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fTEVHQUNZLFxuICAgICAgICBkZXBsb3ltZW50SWQ6IG9wdGlvbnM/LmRlcGxveW1lbnRJZCxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgd2hpbGUgKERhdGUubm93KCkgLSBzdGFydFRpbWUgPCB0aW1lb3V0KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZW1haW5pbmdNcyA9IHRpbWVvdXQgLSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSk7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IHdpdGhEZWFkbGluZShcbiAgICAgICAgICB3b3JsZC5zdHJlYW1zLmdldChcbiAgICAgICAgICAgIGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChjb3JyZWxhdGlvbklkKSxcbiAgICAgICAgICAgIHN0cmVhbU5hbWVcbiAgICAgICAgICApLFxuICAgICAgICAgIHJlbWFpbmluZ01zXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHN0cmVhbS5nZXRSZWFkZXIoKTtcbiAgICAgICAgY29uc3QgeyBjaHVua3MsIHRpbWVkT3V0IH0gPSBhd2FpdCByZWFkU3RyZWFtV2l0aFRpbWVvdXQoXG4gICAgICAgICAgcmVhZGVyLFxuICAgICAgICAgIEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVRcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGltZWRPdXQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVhZGVyLmNhbmNlbCgpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSWdub3JlIGNhbmNlbCBlcnJvcnNcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3MpO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4ucmVzcG9uc2UsXG4gICAgICAgICAgICBsYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydFRpbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBIZWFsdGggY2hlY2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tc2AsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhbHRoeTogZmFsc2UsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH07XG4gIH1cbn1cblxuZnVuY3Rpb24gZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihcbiAgcnVuSWQ6IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nXG4pOiBXb3JrZmxvd1dvcmxkRXJyb3Ige1xuICByZXR1cm4gbmV3IFdvcmtmbG93V29ybGRFcnJvcihcbiAgICBgRXZlbnQgcGFnaW5hdGlvbiAke21lc3NhZ2V9IGZvciB3b3JrZmxvdyBydW4gXCIke3J1bklkfVwiLmAsXG4gICAgeyBjb2RlOiBSVU5fRVJST1JfQ09ERVMuV09STERfQ09OVFJBQ1RfRVJST1IgfVxuICApO1xufVxuXG5mdW5jdGlvbiByZWNvcmRSZXF1ZXN0ZWRFdmVudEN1cnNvcihcbiAgcnVuSWQ6IHN0cmluZyxcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsLFxuICByZXF1ZXN0ZWRDdXJzb3JzOiBTZXQ8c3RyaW5nPlxuKTogdm9pZCB7XG4gIGlmICghY3Vyc29yKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChyZXF1ZXN0ZWRDdXJzb3JzLmhhcyhjdXJzb3IpKSB7XG4gICAgdGhyb3cgZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihydW5JZCwgJ2RpZCBub3QgYWR2YW5jZScpO1xuICB9XG4gIHJlcXVlc3RlZEN1cnNvcnMuYWRkKGN1cnNvcik7XG59XG5cbi8qKlxuICogQXBwZW5kcyBldmVudHMgd2hvc2UgSURzIGFyZSBub3QgYWxyZWFkeSBwcmVzZW50IGluIGB0YXJnZXRgLlxuICpcbiAqIFBhc3MgdGhlIElEcyBjdXJyZW50bHkgcHJlc2VudCBpbiBgdGFyZ2V0YCB3aGVuIGFwcGVuZGluZyByZXBlYXRlZGx5IHRvIHRoZVxuICogc2FtZSBhcnJheS4gVGhlIHNldCBpcyB1cGRhdGVkIGFsb25nc2lkZSBgdGFyZ2V0YC5cbiAqXG4gKiBFdmVudHMgYXJlIGFwcGVuZGVkIGluIHRoZSBvcmRlciB0aGUgV29ybGQgcmV0dXJuZWQgdGhlbSwgYW5kIGFyZSBub3RcbiAqIHJlLXNvcnRlZDogYSBXb3JsZCdzIGNhbm9uaWNhbCBvcmRlciBpcyBpdHMgb3duLCBhbmQgdGhlIHJ1bnRpbWUgY2Fubm90XG4gKiByZXByb2R1Y2UgaXQgZnJvbSBldmVudCBpZHMgYWxvbmUuIGB3b3JsZC12ZXJjZWxgIG9yZGVycyBieSBldmVudCBpZCwgd2hpbGVcbiAqIGB3b3JsZC1sb2NhbGAgb3JkZXJzIGJ5IGAoY3JlYXRlZEF0LCBldmVudElkKWAgYW5kIGRlbGliZXJhdGVseSByZS1taW50cyBrZXlzXG4gKiBzbyB0aGF0IHRoZSB0d28gZGl2ZXJnZS4gRXZlcnkgYXBwZW5kIHNvdXJjZSBpcyBhbHJlYWR5IGluIGNhbm9uaWNhbCBvcmRlclxuICogcmVsYXRpdmUgdG8gdGhlIHRhaWwgKGEgY3Vyc29yLWRlbGltaXRlZCBwYWdlLCBvciBhIHdyaXRlLXJlc3BvbnNlIGRlbHRhKSwgc29cbiAqIHJlY2VpcHQgb3JkZXIgaXMgdGhlIG9yZGVyIHRvIGtlZXAuIE5vdGhpbmcgZG93bnN0cmVhbSBtYXkgYXNzdW1lIHRoZSB0YWlsIGlzXG4gKiB0aGUgbmV3ZXN0IGV2ZW50IOKAlCBzZWUge0BsaW5rIGxhdGVzdEV2ZW50U3RhdGVVcGRhdGVkQXR9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwZW5kVW5pcXVlRXZlbnRzKFxuICB0YXJnZXQ6IEV2ZW50W10sXG4gIGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXSxcbiAgdGFyZ2V0SWRzPzogU2V0PHN0cmluZz5cbik6IHZvaWQge1xuICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGlkcyA9IHRhcmdldElkcyA/PyBuZXcgU2V0KHRhcmdldC5tYXAoKGV2ZW50KSA9PiBldmVudC5ldmVudElkKSk7XG4gIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgaWYgKGlkcy5oYXMoZXZlbnQuZXZlbnRJZCkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZHMuYWRkKGV2ZW50LmV2ZW50SWQpO1xuICAgIHRhcmdldC5wdXNoKGV2ZW50KTtcbiAgfVxufVxuXG4vKipcbiAqIEluc2VydHMgYGV2ZW50YCBpbnRvIGB0YXJnZXRgIGF0IHRoZSBwb3NpdGlvbiB0aGF0IGtlZXBzIGB0YXJnZXRgIG9yZGVyZWQgYnlcbiAqIGFzY2VuZGluZyBgZXZlbnRJZGAsIG9yIG5vLW9wcyBpZiBhbiBldmVudCB3aXRoIHRoZSBzYW1lIGBldmVudElkYCBpcyBhbHJlYWR5XG4gKiBwcmVzZW50IChpZGVtcG90ZW50KS5cbiAqXG4gKiBgcHJlbG9hZGVkRXZlbnRzYCBpcyBsb2FkZWQgYHNvcnRPcmRlcjogJ2FzYydgIGFuZCBpcyBuZXZlciByZS1zb3J0ZWRcbiAqIGNsaWVudC1zaWRlLCBzbyBhIGBob29rX3JlY2VpdmVkYCBzcGxpY2VkIGluIGJ5IHRoZSBsYXp5LXJlc3VtZSBjb25zdW1lciBtdXN0XG4gKiBsYW5kIGluIGBldmVudElkYCBvcmRlciDigJQgYSBwbGFpbiBgcHVzaGAgd291bGQgcGxhY2UgYSBsYXRlLWNvbW1pdHRpbmdcbiAqIGVhcmxpZXIgZXZlbnQgYWZ0ZXIgZXZlbnRzIHRoYXQgc29ydCBiZWZvcmUgaXQsIGNvcnJ1cHRpbmcgcmVwbGF5LiBFdmVudCBJRHNcbiAqIGFyZSBVTElEcywgc28gbGV4aWNvZ3JhcGhpYyBzdHJpbmcgb3JkZXIgbWF0Y2hlcyBjb21taXQgb3JkZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnNlcnRFdmVudEJ5RXZlbnRJZCh0YXJnZXQ6IEV2ZW50W10sIGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAvLyBMaW5lYXIgc2NhbiBmcm9tIHRoZSBlbmQ6IHRoZSBzcGxpY2VkIGV2ZW50IGlzIGFsbW9zdCBhbHdheXMgdGhlIG5ld2VzdFxuICAvLyAoaXQgc29ydHMgYXQgb3IgbmVhciB0aGUgdGFpbCksIHNvIHRoaXMgZmluZHMgdGhlIHNsb3QgaW4gTygxKeKAk08oaykgZm9yIHRoZVxuICAvLyBjb21tb24gY2FzZSB3aGlsZSBzdGlsbCBoYW5kbGluZyBhbiBvdXQtb2Ytb3JkZXIgbGF0ZSBhcnJpdmFsIGNvcnJlY3RseS5cbiAgbGV0IGkgPSB0YXJnZXQubGVuZ3RoO1xuICB3aGlsZSAoaSA+IDApIHtcbiAgICBjb25zdCBleGlzdGluZyA9IHRhcmdldFtpIC0gMV07XG4gICAgaWYgKGV4aXN0aW5nLmV2ZW50SWQgPT09IGV2ZW50LmV2ZW50SWQpIHtcbiAgICAgIC8vIEFscmVhZHkgcHJlc2VudCDigJQga2VlcCB0aGUgc3BsaWNlIGlkZW1wb3RlbnQuXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChleGlzdGluZy5ldmVudElkIDwgZXZlbnQuZXZlbnRJZCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIGktLTtcbiAgfVxuICB0YXJnZXQuc3BsaWNlKGksIDAsIGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gYXNzZXJ0RXZlbnRQYWdpbmF0aW9uUHJvZ3Jlc3MoXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhhc01vcmU6IGJvb2xlYW4sXG4gIGN1cnNvcjogc3RyaW5nIHwgbnVsbCxcbiAgcmVxdWVzdGVkQ3Vyc29yczogU2V0PHN0cmluZz5cbik6IHZvaWQge1xuICBpZiAoIWhhc01vcmUpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGN1cnNvciA9PT0gbnVsbCkge1xuICAgIHRocm93IGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IoXG4gICAgICBydW5JZCxcbiAgICAgICdyZXR1cm5lZCBtb3JlIHBhZ2VzIHdpdGhvdXQgYSBjdXJzb3InXG4gICAgKTtcbiAgfVxuICBpZiAocmVxdWVzdGVkQ3Vyc29ycy5oYXMoY3Vyc29yKSkge1xuICAgIHRocm93IGV2ZW50UGFnaW5hdGlvbkNvbnRyYWN0RXJyb3IocnVuSWQsICdyZXBlYXRlZCBhIGN1cnNvcicpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHNob3VsZFJldHJ5V2l0aG91dEV2ZW50Q3Vyc29yKFxuICBlcnJvcjogdW5rbm93bixcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsLFxuICBhbHJlYWR5UmV0cmllZDogYm9vbGVhblxuKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgY3Vyc29yICE9PSBudWxsICYmXG4gICAgIWFscmVhZHlSZXRyaWVkICYmXG4gICAgV29ya2Zsb3dXb3JsZEVycm9yLmlzKGVycm9yKSAmJlxuICAgIGVycm9yLnN0YXR1cyA9PT0gNDAwXG4gICk7XG59XG5cbi8qKlxuICogTG9hZHMgd29ya2Zsb3cgcnVuIGV2ZW50cyBieSBpdGVyYXRpbmcgdGhyb3VnaCBhbGwgcGFnZXMgb2YgcGFnaW5hdGVkXG4gKiByZXN1bHRzLiBFdmVudHMgYXJlIHJldHVybmVkIGluIGNocm9ub2xvZ2ljYWwgKGFzY2VuZGluZykgb3JkZXIgZm9yXG4gKiBkZXRlcm1pbmlzdGljIHdvcmtmbG93IHJlcGxheS5cbiAqXG4gKiBAcGFyYW0gcnVuSWQgLSBUaGUgd29ya2Zsb3cgcnVuIElELlxuICogQHBhcmFtIGFmdGVyQ3Vyc29yIC0gSWYgcHJvdmlkZWQsIG9ubHkgZXZlbnRzIGFmdGVyIHRoaXMgY3Vyc29yIGFyZVxuICogICByZXR1cm5lZCAoaW5jcmVtZW50YWwgbG9hZCkuIElmIG9taXR0ZWQsIGFsbCBldmVudHMgYXJlIHJldHVybmVkLlxuICogICBUaGUgcmV0dXJuZWQgY3Vyc29yIGNhbiBiZSBwYXNzZWQgYmFjayBpbiBvbiBhIHN1YnNlcXVlbnQgY2FsbCBmb3JcbiAqICAgaW5jcmVtZW50YWwgbG9hZGluZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRXb3JrZmxvd1J1bkV2ZW50cyhcbiAgcnVuSWQ6IHN0cmluZyxcbiAgYWZ0ZXJDdXJzb3I/OiBzdHJpbmdcbik6IFByb21pc2U8TG9hZGVkRXZlbnRMb2c+IHtcbiAgY29uc3QgaW5jcmVtZW50YWwgPSBhZnRlckN1cnNvciAhPT0gdW5kZWZpbmVkO1xuICByZXR1cm4gdHJhY2UoXG4gICAgaW5jcmVtZW50YWwgPyAnd29ya2Zsb3cubG9hZE5ld0V2ZW50cycgOiAnd29ya2Zsb3cubG9hZEV2ZW50cycsXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5JZChydW5JZCksXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbG9hZGVkRXZlbnRzOiBFdmVudFtdID0gW107XG4gICAgICBjb25zdCBsb2FkZWRFdmVudElkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgY29uc3QgcmVxdWVzdGVkQ3Vyc29ycyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgbnVsbCA9IGFmdGVyQ3Vyc29yID8/IG51bGw7XG4gICAgICBsZXQgaGFzTW9yZSA9IHRydWU7XG4gICAgICBsZXQgcGFnZXNMb2FkZWQgPSAwO1xuICAgICAgbGV0IHJldHJpZWRXaXRob3V0Q3Vyc29yID0gZmFsc2U7XG5cbiAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gICAgICBjb25zdCBsb2FkU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgd2hpbGUgKGhhc01vcmUpIHtcbiAgICAgICAgLy8gVE9ETzogd2UncmUgY3VycmVudGx5IGxvYWRpbmcgYWxsIHRoZSBkYXRhIHdpdGggcmVzb2x2ZVJlZiBiZWhhdmlvdXIuIFdlIG5lZWQgdG8gdXBkYXRlIHRoaXNcbiAgICAgICAgLy8gdG8gbGF6eWxvYWQgdGhlIGRhdGEgZnJvbSB0aGUgd29ybGQgaW5zdGVhZCBzbyB0aGF0IHdlIGNhbiBvcHRpbWl6ZSBhbmQgbWFrZSB0aGUgZXZlbnQgbG9nIGxvYWRpbmdcbiAgICAgICAgLy8gbXVjaCBmYXN0ZXIgYW5kIG1lbW9yeSBlZmZpY2llbnRcbiAgICAgICAgY29uc3QgcGFnZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgcmVxdWVzdGVkQ3Vyc29yID0gY3Vyc29yO1xuICAgICAgICByZWNvcmRSZXF1ZXN0ZWRFdmVudEN1cnNvcihydW5JZCwgcmVxdWVzdGVkQ3Vyc29yLCByZXF1ZXN0ZWRDdXJzb3JzKTtcblxuICAgICAgICBsZXQgcmVzcG9uc2U6IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2Ygd29ybGQuZXZlbnRzLmxpc3Q+PjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXNwb25zZSA9IGF3YWl0IHdvcmxkLmV2ZW50cy5saXN0KHtcbiAgICAgICAgICAgIHJ1bklkLFxuICAgICAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgICAgICBzb3J0T3JkZXI6ICdhc2MnLFxuICAgICAgICAgICAgICBjdXJzb3I6IHJlcXVlc3RlZEN1cnNvciA/PyB1bmRlZmluZWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHNob3VsZFJldHJ5V2l0aG91dEV2ZW50Q3Vyc29yKFxuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgcmVxdWVzdGVkQ3Vyc29yLFxuICAgICAgICAgICAgICByZXRyaWVkV2l0aG91dEN1cnNvclxuICAgICAgICAgICAgKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAgICAgICAnRXZlbnQgY3Vyc29yIHdhcyByZWplY3RlZDsgcmV0cnlpbmcgd2l0aCBhIGZ1bGwgZXZlbnQgcmVsb2FkLicsXG4gICAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGxvYWRlZEV2ZW50cy5sZW5ndGggPSAwO1xuICAgICAgICAgICAgbG9hZGVkRXZlbnRJZHMuY2xlYXIoKTtcbiAgICAgICAgICAgIHJlcXVlc3RlZEN1cnNvcnMuY2xlYXIoKTtcbiAgICAgICAgICAgIGN1cnNvciA9IG51bGw7XG4gICAgICAgICAgICByZXRyaWVkV2l0aG91dEN1cnNvciA9IHRydWU7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICBhcHBlbmRVbmlxdWVFdmVudHMobG9hZGVkRXZlbnRzLCByZXNwb25zZS5kYXRhLCBsb2FkZWRFdmVudElkcyk7XG4gICAgICAgIGhhc01vcmUgPSByZXNwb25zZS5oYXNNb3JlO1xuICAgICAgICBhc3NlcnRFdmVudFBhZ2luYXRpb25Qcm9ncmVzcyhcbiAgICAgICAgICBydW5JZCxcbiAgICAgICAgICBoYXNNb3JlLFxuICAgICAgICAgIHJlc3BvbnNlLmN1cnNvcixcbiAgICAgICAgICByZXF1ZXN0ZWRDdXJzb3JzXG4gICAgICAgICk7XG4gICAgICAgIC8vIFByZXNlcnZlIHRoZSBsYXN0IG5vbi1udWxsIGN1cnNvciBhY3Jvc3MgcGFnZXMuIEEgV29ybGQgbWF5XG4gICAgICAgIC8vIGxlZ2l0aW1hdGVseSByZXR1cm4gYHsgZGF0YTogW10sIGN1cnNvcjogbnVsbCwgaGFzTW9yZTogZmFsc2UgfWBcbiAgICAgICAgLy8gb24gYSB0cmFpbGluZyBlbXB0eSBwYWdlIOKAlCBmb3IgZXhhbXBsZSB3aGVuIHRoZSBwcmV2aW91cyBwYWdlJ3NcbiAgICAgICAgLy8gdW5kZXJseWluZyBEQiBxdWVyeSBoaXQgdGhlIGxpbWl0IGV4YWN0bHkgYW5kIHJldHVybmVkIGFcbiAgICAgICAgLy8gYExhc3RFdmFsdWF0ZWRLZXlgIFwianVzdCBpbiBjYXNlXCIuIE92ZXJ3cml0aW5nIHdpdGggdGhhdCBudWxsXG4gICAgICAgIC8vIHdvdWxkIGxvc2UgdGhlIHBvc2l0aW9uIHBhc3QgdGhlIGxhc3QgcmVhbCBldmVudCB3ZSBsb2FkZWQgYW5kXG4gICAgICAgIC8vIGZvcmNlIHRoZSBydW50aW1lIGludG8gdGhlIFwibm8gY3Vyc29yIGFmdGVyIGluaXRpYWwgbG9hZFwiIGZ1bGwtXG4gICAgICAgIC8vIHJlbG9hZCBmYWxsYmFjayBvbiBldmVyeSBzdWJzZXF1ZW50IHJlcGxheSBpdGVyYXRpb24uXG4gICAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvciA/PyBjdXJzb3I7XG4gICAgICAgIHBhZ2VzTG9hZGVkKys7XG5cbiAgICAgICAgcnVudGltZUxvZ2dlci5kZWJ1ZygnTG9hZGVkIGV2ZW50IHBhZ2UnLCB7XG4gICAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgICAgaW5jcmVtZW50YWwsXG4gICAgICAgICAgcGFnZTogcGFnZXNMb2FkZWQsXG4gICAgICAgICAgcGFnZUV2ZW50czogcmVzcG9uc2UuZGF0YS5sZW5ndGgsXG4gICAgICAgICAgdG90YWxFdmVudHM6IGxvYWRlZEV2ZW50cy5sZW5ndGgsXG4gICAgICAgICAgaGFzTW9yZSxcbiAgICAgICAgICBwYWdlTXM6IERhdGUubm93KCkgLSBwYWdlU3RhcnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdFdmVudCBsb2FkIGNvbXBsZXRlJywge1xuICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgaW5jcmVtZW50YWwsXG4gICAgICAgIHRvdGFsRXZlbnRzOiBsb2FkZWRFdmVudHMubGVuZ3RoLFxuICAgICAgICBwYWdlc0xvYWRlZCxcbiAgICAgICAgdG90YWxNczogRGF0ZS5ub3coKSAtIGxvYWRTdGFydCxcbiAgICAgIH0pO1xuXG4gICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKHtcbiAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXZlbnRzQ291bnQobG9hZGVkRXZlbnRzLmxlbmd0aCksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0V2ZW50c1BhZ2VzTG9hZGVkKHBhZ2VzTG9hZGVkKSxcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4geyBldmVudHM6IGxvYWRlZEV2ZW50cywgY3Vyc29yIH07XG4gICAgfVxuICApO1xufVxuXG4vKipcbiAqIFRoZSBydW50aW1lJ3MgbG9hZGVkIGV2ZW50LWxvZyBzbmFwc2hvdDogdGhlIGV2ZW50cyByZXBsYXllZCBzbyBmYXIgYW5kIHRoZVxuICogY3Vyc29yIHBvc2l0aW9uZWQgYWZ0ZXIgdGhlbS4gSGFuZGVkIHRvIGhlbHBlcnMgdGhhdCBkZXJpdmUgdGhlIHByZWNvbmRpdGlvblxuICogc25hcHNob3QgZnJvbSBpdDsgdGhleSBkbyBub3QgbXV0YXRlIGl0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExvYWRlZEV2ZW50TG9nIHtcbiAgZXZlbnRzOiBFdmVudFtdO1xuICBjdXJzb3I6IHN0cmluZyB8IG51bGw7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgb3B0aW1pc3RpYy1jb25jdXJyZW5jeSBndWFyZCBmb3IgZXZlbnQgY3JlYXRpb24gaXMgZW5hYmxlZC5cbiAqICoqT24gYnkgZGVmYXVsdCoqIHdoZXJlIHRoZSBydW50aW1lIGV4ZWN1dGVzOiByZXBsYXktY29udGV4dCBjcmVhdGVzIHNlbmQgYVxuICogYHN0YXRlVXBkYXRlZEF0YCBzbmFwc2hvdCAoYW5kIGNhbiBiZSByZWplY3RlZCB3aXRoIDQxMiBieSBhIHN1cHBvcnRpbmdcbiAqIGJhY2tlbmQpIHVubGVzcyBgV09SS0ZMT1dfUFJFQ09ORElUSU9OX0dVQVJEYCBpcyBzZXQgdG8gYDBgLiBCYWNrZW5kcyB3aXRob3V0XG4gKiBndWFyZCBzdXBwb3J0IGlnbm9yZSB0aGUgc25hcHNob3QsIHNvIGVuYWJsaW5nIGJ5IGRlZmF1bHQgaXNcbiAqIGJhY2t3YXJkLWNvbXBhdGlibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ByZWNvbmRpdGlvbkd1YXJkRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgcmV0dXJuIHByb2Nlc3MuZW52LldPUktGTE9XX1BSRUNPTkRJVElPTl9HVUFSRCAhPT0gJzAnO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYSByZXBsYXkgcmVmdXNlcyB0byBydW4gb3ZlciBhIGxvZyB3aXRoIGEgaG9sZSBpbiBpdCAoc2VlXG4gKiB7QGxpbmsgZmluZEV2ZW50U2xvdEdhcH0pLiAqKk9uIGJ5IGRlZmF1bHQqKjsgc2V0XG4gKiBgV09SS0ZMT1dfU0xPVF9HQVBfQ0hFQ0s9MGAgdG8gcmVwbGF5IGFjcm9zcyBob2xlcyBpbnN0ZWFkLlxuICpcbiAqIFRoZSBzd2l0Y2ggZXhpc3RzIGJlY2F1c2UgdGhlIGNoZWNrIHRyYWRlcyBvbmUgZmFpbHVyZSBmb3IgYW5vdGhlci4gQSBob2xlIGlzXG4gKiBhIHBvc2l0aW9uIGNsYWltZWQgYnkgYSB3cml0ZSB0aGF0IHRoZW4gZmFpbGVkLCBzbyBtb3N0IG9mIHRoZW0gc3RhbmQgZm9yIGFuXG4gKiBldmVudCB0aGF0IG5ldmVyIGhhcHBlbmVkIGFuZCByZXBsYXlpbmcgcGFzdCBvbmUgaXMgY29ycmVjdC4gQnV0IGEgaG9sZVxuICogc3RhbmRpbmcgZm9yIGFuIGV2ZW50IHRoYXQgKmRpZCogaGFwcGVuIGlzIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gdGhhdCwgYW5kXG4gKiByZXBsYXlpbmcgcGFzdCB0aGF0IG9uZSBwcm9kdWNlcyBhIHJ1biB3aG9zZSByZXN1bHQgaXMgd3Jvbmcgd2l0aCBub3RoaW5nIHRvXG4gKiBzaG93IGZvciBpdC4gRmFpbGluZyBsb3VkbHkgaXMgdGhlIHJlY292ZXJhYmxlIHNpZGUgb2YgdGhlIHRyYWRlLCBhbmQgdGhpcyBpc1xuICogdGhlIHdheSBiYWNrIG91dCBpZiBhIGZsZWV0IHR1cm5zIG91dCB0byBjYXJyeSBiZW5pZ24gaG9sZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1Nsb3RHYXBDaGVja0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiBwcm9jZXNzLmVudi5XT1JLRkxPV19TTE9UX0dBUF9DSEVDSyAhPT0gJzAnO1xufVxuXG4vKipcbiAqIFRoZSBgc3RhdGVVcGRhdGVkQXRgIHZhbHVlIHRvIHNlbmQgd2l0aCBhIHJlcGxheS1jb250ZXh0IGV2ZW50IGNyZWF0aW9uOiB0aGVcbiAqICptYXhpbXVtKiBVTElEIHRpbWUgKGVwb2NoIG1zKSBvdmVyIHRoZSBldmVudHMgdGhlIHJ1bnRpbWUgaGFzIGxvYWRlZC4gUmV0dXJuc1xuICogYHVuZGVmaW5lZGAgd2hlbiB0aGVyZSBhcmUgbm8gZXZlbnRzIG9yIHRoYXQgaWQgaXMgbm90IGEgZGVjb2RhYmxlIFVMSUQuXG4gKlxuICogSXQgaXMgdGhlIG1heGltdW0gcmF0aGVyIHRoYW4gdGhlIHRhaWwncyBiZWNhdXNlIHRoZSBsb2FkZWQgbG9nIGlzIGluIHRoZVxuICogV29ybGQncyBjYW5vbmljYWwgb3JkZXIsIHdoaWNoIGlzIG5vdCBuZWNlc3NhcmlseSBldmVudC1pZCBvcmRlciAoc2VlXG4gKiB7QGxpbmsgYXBwZW5kVW5pcXVlRXZlbnRzfSkuIFRoZSBtYXhpbXVtIGlzIHdoYXQgbGV0cyB0aGUgY291bnQgc2VudCBhbG9uZ3NpZGVcbiAqIGl0IGJlIHJlYWQgYXMgXCJldmVudHMgYXQgb3IgYmVsb3cgdGhpcyB3YXRlcm1hcmtcIjogZXZlcnkgbG9hZGVkIGV2ZW50IGlzIGF0IG9yXG4gKiBiZWxvdyBpdCwgc28gdGhlIGNvdW50IGlzIGV4YWN0bHkgYGV2ZW50cy5sZW5ndGhgLiBSZWFkaW5nIHRoZSB0YWlsIGluc3RlYWRcbiAqIHdvdWxkIHVuZGVyc3RhdGUgdGhlIHdhdGVybWFyayBvbiBhIFdvcmxkIHdob3NlIG9yZGVyIGlzIG5vdCBpZC1vcmRlcmVkLCB3aGljaFxuICogaXMgc2FmZSAoaXQgY2FuIG9ubHkgd2Vha2VuIGRldGVjdGlvbikgYnV0IG5lZWRsZXNzbHkgaW1wcmVjaXNlLlxuICpcbiAqIFRoZSBtYXhpbXVtIGlzIGZvdW5kIGJ5IGxleGljb2dyYXBoaWMgaWQgY29tcGFyaXNvbiwgZGVjb2Rpbmcgb25seSBvbmNlOiB0aGVcbiAqIDI2LWNoYXJhY3RlciBDcm9ja2ZvcmQgVUxJRCBlbmNvZGVzIGl0cyB0aW1lc3RhbXAgaW4gdGhlIGxlYWRpbmcgMTBcbiAqIGNoYXJhY3RlcnMsIHNvIHRoZSBncmVhdGVzdCBpZCBhbHNvIGNhcnJpZXMgdGhlIGdyZWF0ZXN0IHRpbWUuXG4gKlxuICogR3JhbnVsYXJpdHk6IHNuYXBzaG90cyBhcmUgZXBvY2gtbWlsbGlzZWNvbmRzLCBhbmQgdGhlIGJhY2tlbmQgYWxsb3dzIGFuXG4gKiBlcXVhbC10aW1lc3RhbXAgc25hcHNob3QgKGFuIHVwLXRvLWRhdGUgY2xpZW50IG11c3Qgbm90IGJlIHJlamVjdGVkKS4gVHdvXG4gKiBvdXQtb2YtYmFuZCBldmVudHMgbGFuZGluZyBpbiB0aGUgc2FtZSBtaWxsaXNlY29uZCB3aGVyZSBvbmx5IHRoZSBmaXJzdCB3YXNcbiAqIGxvYWRlZCB0aGVyZWZvcmUgcGFzcyB0aGlzIGhhbGYgb2YgdGhlIGd1YXJkIHVuZGV0ZWN0ZWQg4oCUIHRoYXQgaXMgZXhhY3RseVxuICogdGhlIGhvbGUgYHN0YXRlRXZlbnRDb3VudGAgY2xvc2VzLCBzaW5jZSB0aGUgY291bnQgb2YgZXZlbnRzIGF0IG9yIGJlbG93IHRoZVxuICogd2F0ZXJtYXJrIGRpZmZlcnMgZXZlbiB3aGVuIHRoZSB3YXRlcm1hcmtzIGFyZSBlcXVhbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxhdGVzdEV2ZW50U3RhdGVVcGRhdGVkQXQoZXZlbnRzOiBFdmVudFtdKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgbGV0IGxhdGVzdDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGlmIChsYXRlc3QgPT09IHVuZGVmaW5lZCB8fCBldmVudC5ldmVudElkID4gbGF0ZXN0KSB7XG4gICAgICBsYXRlc3QgPSBldmVudC5ldmVudElkO1xuICAgIH1cbiAgfVxuICBpZiAobGF0ZXN0ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIC8vIEV2ZW50IElEcyBhcmUgcHJlZml4ZWQgVUxJRHMgKGUuZy4gYGV2bnRfMDFBUllaLi4uYCk7IHVsaWRUb0RhdGUgb25seVxuICAvLyBkZWNvZGVzIHRoZSBiYXJlIDI2LWNoYXIgVUxJRCwgc28gc3RyaXAgdGhlIHByZWZpeCBmaXJzdC5cbiAgY29uc3QgZXZlbnRJZCA9IGxhdGVzdDtcbiAgY29uc3QgdW5kZXJzY29yZSA9IGV2ZW50SWQubGFzdEluZGV4T2YoJ18nKTtcbiAgY29uc3QgcmF3VWxpZCA9IHVuZGVyc2NvcmUgPT09IC0xID8gZXZlbnRJZCA6IGV2ZW50SWQuc2xpY2UodW5kZXJzY29yZSArIDEpO1xuICBjb25zdCB0aW1lID0gdWxpZFRvRGF0ZShyYXdVbGlkKT8uZ2V0VGltZSgpO1xuICBpZiAodGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgLy8gRmFpbCBvcGVuOiBhIG5vbi1kZWNvZGFibGUgaWQgZGlzYXJtcyB0aGUgZ3VhcmQgZm9yIHRoaXMgY3JlYXRlIChub1xuICAgIC8vIHNuYXBzaG90IHNlbnQpLiBMb2cgc28gYSBmbGVldC13aWRlIHNpbGVudCBkaXNhcm0gaXMgZGlhZ25vc2FibGUuXG4gICAgcnVudGltZUxvZ2dlci5kZWJ1ZyhcbiAgICAgICdQcmVjb25kaXRpb24gZ3VhcmQ6IGxhdGVzdCBldmVudCBpZCBpcyBub3QgYSBkZWNvZGFibGUgVUxJRDsgc2VuZGluZyBubyBzbmFwc2hvdCcsXG4gICAgICB7IGV2ZW50SWQgfVxuICAgICk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4gdGltZTtcbn1cblxuLyoqXG4gKiBNZXJnZSB0aGUgZXZlbnRzIGEgYnVtcC1hbmQtcmVwb3J0IHdyaXRlIGhhbmRlZCBiYWNrIGludG8gdGhlIGxvZyBpdCB3YXNcbiAqIGRlcml2ZWQgZnJvbSwgYW5kIGFuc3dlciBob3cgbWFueSBvZiB0aGVtIHdlcmUgbmV3LlxuICpcbiAqIFVubGlrZSB7QGxpbmsgYXBwZW5kVW5pcXVlRXZlbnRzfSwgdGhpcyByZS1zb3J0cy4gVGhlIHJlcG9ydGVkIGV2ZW50cyBvY2N1cHlcbiAqIHNsb3RzICpiZWxvdyogdGhlIHdyaXRlIHRoYXQgcmVwb3J0ZWQgdGhlbSwgc28gYXBwZW5kaW5nIHRoZW0gd291bGQgcHV0IHRoZW1cbiAqIGFmdGVyIGV2ZW50cyB0aGV5IHByZWNlZGUg4oCUIGFuZCBvbiBhIHNsb3QtbnVtYmVyZWQgcnVuIHRoZSBpZCBvcmRlciBpcyB0aGVcbiAqIFdvcmxkJ3MgY2Fub25pY2FsIG9yZGVyLCBzbyByZXN0b3JpbmcgaXQgaXMgd2VsbCBkZWZpbmVkIHJhdGhlciB0aGFuIGEgZ3Vlc3MuXG4gKiBBIHJ1biB0aGF0IGlzIG5vdCBzbG90LW51bWJlcmVkIGNhbm5vdCBwcm9kdWNlIHRoaXMgcmVwb3J0IGluIHRoZSBmaXJzdFxuICogcGxhY2U7IHRoZSBzb3J0IGlzIHNraXBwZWQgcmF0aGVyIHRoYW4gYXBwbGllZCB0byBpZHMgaXQgY2Fubm90IG9yZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VSZXBvcnRlZEV2ZW50cyhcbiAgdGFyZ2V0OiBFdmVudFtdLFxuICBldmVudHM6IHJlYWRvbmx5IEV2ZW50W11cbik6IG51bWJlciB7XG4gIGNvbnN0IGJlZm9yZSA9IHRhcmdldC5sZW5ndGg7XG4gIGFwcGVuZFVuaXF1ZUV2ZW50cyh0YXJnZXQsIGV2ZW50cyk7XG4gIGNvbnN0IGFkZGVkID0gdGFyZ2V0Lmxlbmd0aCAtIGJlZm9yZTtcbiAgaWYgKGFkZGVkID4gMCAmJiBtYXhFdmVudFNsb3QodGFyZ2V0KSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdGFyZ2V0LnNvcnQoKGEsIGIpID0+XG4gICAgICBhLmV2ZW50SWQgPCBiLmV2ZW50SWQgPyAtMSA6IGEuZXZlbnRJZCA+IGIuZXZlbnRJZCA/IDEgOiAwXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYWRkZWQ7XG59XG5cbi8qKlxuICogVGhlIGhpZ2hlc3Qgc2xvdCB0aGUgbG9hZGVkIGxvZyBvY2N1cGllcywgb3IgYHVuZGVmaW5lZGAgd2hlbiB0aGUgcnVuIGlzIG5vdFxuICogc2xvdC1udW1iZXJlZC4gQSBydW4ga2VlcHMgdGhlIGlkIHNjaGVtZSBpdCB3YXMgY3JlYXRlZCB1bmRlciwgc28gb25lIGV2ZW50XG4gKiBzZXR0bGVzIGl0IGZvciB0aGUgd2hvbGUgbG9nLlxuICpcbiAqIFRoZSBtYXhpbXVtLCBub3QgdGhlIGNvdW50LCBhbmQgdGhlIHR3byBhcmUgbm90IGludGVyY2hhbmdlYWJsZSBldmVuIHRob3VnaFxuICogYSBoZWFsdGh5IGxvZyBtYWtlcyB0aGVtIGVxdWFsLiBBIFdvcmxkIGhhbmRzIGEgcG9zaXRpb24gdG8gdGhlIGluc2VydCB0aGF0XG4gKiBvY2N1cGllcyBpdCwgc28gYSB3cml0ZSB0aGF0IG5ldmVyIGxhbmRzIGxlYXZlcyBubyBob2xlIGJlaGluZCBhbmQgdGhlIGxvZ1xuICogc3RheXMgZGVuc2UuIFdoYXQgdGhlIGNvdW50IGNhbm5vdCBzdXJ2aXZlIGlzIGEgKnBhcnRpYWwqIHJlYWQ6IGEgbG9nXG4gKiBhc3NlbWJsZWQgZnJvbSBhIHRydW5jYXRlZCByZXBvcnQsIG9yIHJlYWQgd2hpbGUgYSBjb25jdXJyZW50IHdyaXRlIGlzXG4gKiBjb21taXR0aW5nLCBob2xkcyBmZXdlciBldmVudHMgdGhhbiBpdHMgaGlnaGVzdCBwb3NpdGlvbi4gQ291bnRpbmcgdGhvc2VcbiAqIHdvdWxkIG1ha2UgdGhlIG5leHQgd3JpdGUgY2xhaW0gdG8gaGF2ZSBzZWVuIGxlc3MgdGhhbiBpdCBoYXMsIHNvIHRoZSBXb3JsZFxuICogd291bGQgcmVwb3J0IHRoZSBzYW1lIGV2ZW50cyBiYWNrIHRvIGl0IG9uIGV2ZXJ5IGF0dGVtcHQuXG4gKlxuICogQSBob2xlIGJlbG93IHRoZSBtYXhpbXVtIGlzIHRoZXJlZm9yZSBhIHByb3BlcnR5IG9mIHRoZSByZWFkLCBub3Qgb2YgdGhlIGxvZyxcbiAqIHdoaWNoIGlzIHdoYXQgbGV0cyB7QGxpbmsgc2V0dGxlRXZlbnRTbG90R2FwfSByZS1yZWFkIGluc3RlYWQgb2YgZ2l2aW5nIHVwLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWF4RXZlbnRTbG90KGV2ZW50czogRXZlbnRbXSk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gIGxldCBtYXg6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgZm9yIChjb25zdCBldmVudCBvZiBldmVudHMpIHtcbiAgICBjb25zdCBzbG90ID0gZXZlbnRJZFRvU2xvdChldmVudC5ldmVudElkKTtcbiAgICBpZiAoc2xvdCA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKG1heCA9PT0gdW5kZWZpbmVkIHx8IHNsb3QgPiBtYXgpIHtcbiAgICAgIG1heCA9IHNsb3Q7XG4gICAgfVxuICB9XG4gIHJldHVybiBtYXg7XG59XG5cbi8qKiBBIHBvc2l0aW9uIHRoZSBsb2cgc2tpcHMgb3ZlciwgZGVzY3JpYmVkIHdlbGwgZW5vdWdoIHRvIG5hbWUgaW4gYW4gZXJyb3IuICovXG5leHBvcnQgaW50ZXJmYWNlIEV2ZW50U2xvdEdhcCB7XG4gIC8qKiBUaGUgbG93ZXN0IHNsb3QgYmVsb3cgdGhlIGxvZydzIG1heGltdW0gdGhhdCBubyBldmVudCBvY2N1cGllcy4gKi9cbiAgZmlyc3RNaXNzaW5nU2xvdDogbnVtYmVyO1xuICAvKiogSG93IG1hbnkgc2xvdHMgYmVsb3cgdGhlIG1heGltdW0gbm8gZXZlbnQgb2NjdXBpZXMuICovXG4gIG1pc3NpbmdDb3VudDogbnVtYmVyO1xuICAvKiogVGhlIGhpZ2hlc3Qgc2xvdCB0aGUgbG9nIG9jY3VwaWVzLiAqL1xuICBtYXhTbG90OiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIGhvbGUgaW4gYSBsb2FkZWQgbG9nLCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vbmUgdG8gZmluZC5cbiAqXG4gKiBPbiBhIHNsb3QtbnVtYmVyZWQgcnVuIHRoZSBXb3JsZCBhbGxvY2F0ZXMgZXZlcnkgcG9zaXRpb24sIHNvIGEgbG9nIHRoYXRcbiAqIGhvbGRzIGBuYCBldmVudHMgYmVsb3cgc2xvdCBgbmAgaXMgbWlzc2luZyBvbmUuIFRoYXQgbWF0dGVycyBiZWZvcmUgYSByZXBsYXlcbiAqIGFuZCBub3doZXJlIGVsc2U6IHRoZSByZXBsYXkgcmVhZHMgdGhlIGxvZyBhcyB0aGUgY29tcGxldGUgcmVjb3JkIG9mIHdoYXQgaGFzXG4gKiBoYXBwZW5lZCwgYW5kIGFuIGFic2VudCBwb3NpdGlvbiBpcyBpbmRpc3Rpbmd1aXNoYWJsZSBmcm9tIGFuIGV2ZW50IHRoYXRcbiAqIG5ldmVyIG9jY3VycmVkLiBUaGUgYnJhbmNoIGl0IHdvdWxkIGhhdmUgZGVjaWRlZCBnZXRzIGRlY2lkZWQgdGhlIG90aGVyIHdheSxcbiAqIGFuZCB0aGUgcnVuIGRpdmVyZ2VzIHF1aWV0bHkgcmF0aGVyIHRoYW4gZmFpbGluZy5cbiAqXG4gKiBPcmRlci1pbmRlcGVuZGVudCwgdW5saWtlIHRoZSBlcXVpdmFsZW50IGF1ZGl0IHRoZSBXb3JsZCBydW5zIG92ZXIgYSBwYWdlIGl0XG4gKiBqdXN0IHJlYWQuIEEgbG9hZGVkIGxvZyBpcyBhc3NlbWJsZWQgZnJvbSBsaXN0ZWQgcGFnZXMgcGx1cyB3aGF0ZXZlciBhXG4gKiBidW1wLWFuZC1yZXBvcnQgd3JpdGUgaGFuZGVkIGJhY2ssIGFuZCB3aGlsZSB7QGxpbmsgbWVyZ2VSZXBvcnRlZEV2ZW50c31cbiAqIHJlc3RvcmVzIGlkIG9yZGVyLCBhIGNoZWNrIHRoYXQgY2FuIGZhaWwgYSBoZWFsdGh5IHJ1biBzaG91bGQgbm90IGRlcGVuZCBvblxuICogdGhhdCBoYXZpbmcgaGFwcGVuZWQuXG4gKlxuICogVGhlIGZpcnN0IHNsb3QgaXMgbmV2ZXIgY291bnRlZC4gSXQgYmVsb25ncyB0byBgcnVuX2NyZWF0ZWRgLCB3aGljaCBgc3RhcnQoKWBcbiAqIHBvc3RzIGNvbmN1cnJlbnRseSB3aXRoIHRoZSBxdWV1ZSBzZW5kLCBzbyBhIGxvZyByZWFkIGluIHRoYXQgd2luZG93XG4gKiBsZWdpdGltYXRlbHkgYmVnaW5zIGF0IHRoZSBzZWNvbmQgc2xvdCBhbmQgZmlsbHMgaW4gb24gaXRzIG93bi4gRXZlcnkgcmVwbGF5XG4gKiB0aGF0IHJhY2VzIGEgcnVuJ3Mgb3duIHN0YXJ0IHdvdWxkIG90aGVyd2lzZSByZXBvcnQgYSBob2xlLlxuICpcbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgZm9yIGEgbG9nIHRoaXMgY2Fubm90IHJlYWQgYXMgc2xvdHMgYXQgYWxsOiBhbiBlbXB0eSBvbmUsXG4gKiBvciBhIHJ1biBudW1iZXJlZCBieSBVTElELCB3aGVyZSBwb3NpdGlvbnMgY2Fycnkgbm8gZGVuc2l0eSB0byBjaGVjay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRFdmVudFNsb3RHYXAoXG4gIGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXVxuKTogRXZlbnRTbG90R2FwIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgb2NjdXBpZWQgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgbGV0IG1heFNsb3QgPSAwO1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGNvbnN0IHNsb3QgPSBldmVudElkVG9TbG90KGV2ZW50LmV2ZW50SWQpO1xuICAgIGlmIChzbG90ID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBvY2N1cGllZC5hZGQoc2xvdCk7XG4gICAgaWYgKHNsb3QgPiBtYXhTbG90KSB7XG4gICAgICBtYXhTbG90ID0gc2xvdDtcbiAgICB9XG4gIH1cbiAgaWYgKG1heFNsb3QgPT09IDApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IGZsb29yID0gb2NjdXBpZWQuaGFzKEZJUlNUX0VWRU5UX1NMT1QpXG4gICAgPyBGSVJTVF9FVkVOVF9TTE9UXG4gICAgOiBGSVJTVF9FVkVOVF9TTE9UICsgMTtcbiAgLy8gRXZlcnkgc2xvdCBpcyBhdCBvciBhYm92ZSBgZmxvb3JgIGJ5IGNvbnN0cnVjdGlvbiwgc28gdGhlIGxvZyBpcyBkZW5zZVxuICAvLyBleGFjdGx5IHdoZW4gaXQgaG9sZHMgb25lIGV2ZW50IHBlciBwb3NpdGlvbiBpbiBgW2Zsb29yLCBtYXhTbG90XWAuIFRoZVxuICAvLyBzY2FuIGJlbG93IG9ubHkgcnVucyBvbmNlIHRoYXQgaGFzIGFscmVhZHkgYW5zd2VyZWQgbm8uXG4gIGlmIChvY2N1cGllZC5zaXplID09PSBtYXhTbG90IC0gZmxvb3IgKyAxKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBsZXQgZmlyc3RNaXNzaW5nU2xvdDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBsZXQgbWlzc2luZ0NvdW50ID0gMDtcbiAgZm9yIChsZXQgc2xvdCA9IGZsb29yOyBzbG90IDw9IG1heFNsb3Q7IHNsb3QrKykge1xuICAgIGlmICghb2NjdXBpZWQuaGFzKHNsb3QpKSB7XG4gICAgICBmaXJzdE1pc3NpbmdTbG90ID8/PSBzbG90O1xuICAgICAgbWlzc2luZ0NvdW50Kys7XG4gICAgfVxuICB9XG4gIGlmIChmaXJzdE1pc3NpbmdTbG90ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiB7IGZpcnN0TWlzc2luZ1Nsb3QsIG1pc3NpbmdDb3VudCwgbWF4U2xvdCB9O1xufVxuXG4vKipcbiAqIEhvdyBtYW55IHRpbWVzIGEgZGV0ZWN0ZWQgaG9sZSBpcyByZS1yZWFkIGJlZm9yZSB0aGUgbG9nIGlzIHRha2VuIGF0IGl0c1xuICogd29yZCwgYW5kIHRoZSBiYWNrb2ZmIGJlZm9yZSBlYWNoIHJlLXJlYWQgKGRvdWJsaW5nIHBlciBhdHRlbXB0KS5cbiAqXG4gKiBBIGhvbGUgY2FuIGJlIHRyYW5zaWVudC4gVGhlIFdvcmxkIGFsbG9jYXRlcyBhIHNsb3QgaW5zaWRlIHRoZSBpbnNlcnQgdGhhdFxuICogb2NjdXBpZXMgaXQsIHNvIHR3byBjb25jdXJyZW50IHdyaXRlcnMgY2FuIGNvbGxpZGUsIG9uZSByZXRyeSBwYXN0IHRoZSBvdGhlcixcbiAqIGFuZCB0aGUgaGlnaGVyIHNsb3QgY29tbWl0IGZpcnN0IOKAlCBsZWF2aW5nIGEgd2luZG93IGluIHdoaWNoIHRoZSBsb3dlciBvbmUgaXNcbiAqIGdlbnVpbmVseSBhYnNlbnQgZnJvbSBhIHN0cm9uZ2x5LWNvbnNpc3RlbnQgcmVhZCBhbmQgZmlsbHMgaW4gYSBtb21lbnQgbGF0ZXIuXG4gKiBUaGUgd2luZG93IGlzIG9uZSBjb21taXQgd2lkZSwgc28gYSBzaG9ydCBiYWNrb2ZmIGNsZWFycyBpdDsgYW55dGhpbmcgdGhhdFxuICogc3Vydml2ZXMgYWxsIHRocmVlIHJlLXJlYWRzIGlzIGEgcG9zaXRpb24gbm8gd3JpdGUgd2lsbCBldmVyIG9jY3VweS5cbiAqL1xuZXhwb3J0IGNvbnN0IFNMT1RfR0FQX1JFQ0hFQ0tfQVRURU1QVFMgPSAzO1xuY29uc3QgU0xPVF9HQVBfUkVDSEVDS19CQVNFX0RFTEFZX01TID0gMjU7XG5cbi8qKlxuICogUmUtcmVhZCBhIGxvZyB0aGF0IGxvb2tzIGhvbGV5IHVudGlsIHRoZSBob2xlIGZpbGxzIGluIG9yIHRoZSByZS1yZWFkcyBydW5cbiAqIG91dCwgYW5kIHJldHVybiB0aGUgc2V0dGxlZCBsb2cgYWxvbmdzaWRlIHRoZSBob2xlIHRoYXQgc3Vydml2ZWQuXG4gKlxuICogUmVhZHMgYXJlIHN0cm9uZ2x5IGNvbnNpc3RlbnQsIHNvIGEgaG9sZSBpcyBub3QgYW4gYXJ0aWZhY3Qgb2YgKndoZW4qIHRoZSBsb2dcbiAqIHdhcyByZWFkIOKAlCBidXQgaXQgY2FuIGJlIGFuIGFydGlmYWN0IG9mIGEgd3JpdGUgdGhhdCBoYWQgbm90IGNvbW1pdHRlZCB5ZXRcbiAqIChzZWUge0BsaW5rIFNMT1RfR0FQX1JFQ0hFQ0tfQVRURU1QVFN9KS4gRGlzdGluZ3Vpc2hpbmcgdGhlIHR3byBjb3N0cyBhXG4gKiByZS1yZWFkLCB3aGljaCBpcyBvbmx5IGV2ZXIgcGFpZCBieSBhIHJlcGxheSB0aGF0IGFscmVhZHkgZm91bmQgYSBob2xlLlxuICpcbiAqIFRoZSByZWxvYWQgaXMgZnVsbCByYXRoZXIgdGhhbiBpbmNyZW1lbnRhbDogdGhlIG1pc3NpbmcgcG9zaXRpb24gaXMgYmVsb3cgdGhlXG4gKiBsb2cncyBtYXhpbXVtLCBzbyBhIGN1cnNvci1hbmNob3JlZCByZWFkIHN0YXJ0cyBwYXN0IGl0IGFuZCBjYW4gbmV2ZXIgc2VlIGl0XG4gKiBhcnJpdmUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXR0bGVFdmVudFNsb3RHYXAoXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGxvYWRlZDogTG9hZGVkRXZlbnRMb2dcbik6IFByb21pc2U8eyBsb2c6IExvYWRlZEV2ZW50TG9nOyBnYXA6IEV2ZW50U2xvdEdhcCB8IHVuZGVmaW5lZCB9PiB7XG4gIGxldCBsb2cgPSBsb2FkZWQ7XG4gIGxldCBnYXAgPSBmaW5kRXZlbnRTbG90R2FwKGxvZy5ldmVudHMpO1xuICBmb3IgKFxuICAgIGxldCBhdHRlbXB0ID0gMDtcbiAgICBnYXAgIT09IHVuZGVmaW5lZCAmJiBhdHRlbXB0IDwgU0xPVF9HQVBfUkVDSEVDS19BVFRFTVBUUztcbiAgICBhdHRlbXB0KytcbiAgKSB7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIFNMT1RfR0FQX1JFQ0hFQ0tfQkFTRV9ERUxBWV9NUyAqIDIgKiogYXR0ZW1wdClcbiAgICApO1xuICAgIGxvZyA9IGF3YWl0IGxvYWRXb3JrZmxvd1J1bkV2ZW50cyhydW5JZCk7XG4gICAgZ2FwID0gZmluZEV2ZW50U2xvdEdhcChsb2cuZXZlbnRzKTtcbiAgfVxuICByZXR1cm4geyBsb2csIGdhcCB9O1xufVxuXG4vKipcbiAqIFRoZSBwcmVjb25kaXRpb24gc25hcHNob3QgYSByZXBsYXktY29udGV4dCBldmVudCBjcmVhdGlvbiBzZW5kcywgZGVzY3JpYmluZ1xuICogdGhlIGV2ZW50IGxvZyB0aGUgcmVwbGF5IGRlcml2ZWQgdGhlIGV2ZW50IGZyb20uXG4gKlxuICogT24gYSBzbG90LW51bWJlcmVkIHJ1biB0aGlzIGlzIGBldmVudENvdW50YCwgb3B0aW9uYWxseSB3aXRoIHRoZSBzZXQgb2ZcbiAqIGNvcnJlbGF0aW9uIGlkcyB0aGUgd3JpdGVyIGlzIGJsb2NrZWQgb24uIE9uIGEgVUxJRC1udW1iZXJlZCBydW4gaXQgaXMgdGhlXG4gKiBgc3RhdGVVcGRhdGVkQXRgIC8gYHN0YXRlRXZlbnRDb3VudGAgLyBgc3RhdGVDdXJzb3JgIHRyaXBsZSwgd2hvc2UgdGhyZWVcbiAqIGZpZWxkcyBhcmUgb25lIGluZGl2aXNpYmxlIHVuaXQ6IHRoZSBiYWNrZW5kIHJlYWRzIHRoZSBjb3VudCBvbmx5IHJlbGF0aXZlIHRvXG4gKiB0aGUgd2F0ZXJtYXJrLCBhbmQgcmV0dXJucyBpdHMgaW5saW5lIGRlbHRhIG9ubHkgcmVsYXRpdmUgdG8gdGhlIGN1cnNvci5cbiAqIFBhc3NpbmcgdGhlbSBhcyBhIHNpbmdsZSBvYmplY3QgaXMgd2hhdCBrZWVwcyB0aGVtIGZyb20gZHJpZnRpbmcgYXBhcnQgYXQgYVxuICogY2FsbCBzaXRlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByZWNvbmRpdGlvblNuYXBzaG90UGFyYW1zIHtcbiAgc3RhdGVVcGRhdGVkQXQ/OiBudW1iZXI7XG4gIHN0YXRlRXZlbnRDb3VudD86IG51bWJlcjtcbiAgc3RhdGVDdXJzb3I/OiBzdHJpbmc7XG4gIGV2ZW50Q291bnQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIHByZWNvbmRpdGlvbiBzbmFwc2hvdCB0byBhdHRhY2ggdG8gYSByZXBsYXktY29udGV4dCBldmVudCBjcmVhdGlvbi5cbiAqXG4gKiBSZXR1cm5zIGFuIGVtcHR5IG9iamVjdCDigJQgbm8gZ3VhcmQsIGJhY2tlbmQgYmVoYXZlcyBhcyBiZWZvcmUg4oCUIHdoZW4gdGhlXG4gKiBndWFyZCBpcyBkaXNhYmxlZCBvciB0aGUgd2F0ZXJtYXJrIGlzIG5vdCBkZXJpdmFibGUuIEFsbCB0aHJlZSBmaWVsZHMgZmFpbFxuICogb3BlbiB0b2dldGhlcjogYSBjb3VudCB3aXRob3V0IGEgd2F0ZXJtYXJrIGlzIG1lYW5pbmdsZXNzIHRvIHRoZSBiYWNrZW5kLCBhbmRcbiAqIGEgY3Vyc29yIHdpdGhvdXQgZWl0aGVyIHdvdWxkIGludml0ZSBhIGRlbHRhIG5vYm9keSBhc2tlZCBmb3IuXG4gKlxuICogYHN0YXRlRXZlbnRDb3VudGAgaXMgYGV2ZW50cy5sZW5ndGhgIGJlY2F1c2UgdGhlIHdhdGVybWFyayBpcyB0aGUgbG9nJ3NcbiAqICptYXhpbXVtKiBVTElEIHRpbWUsIHNvIGV2ZXJ5IGxvYWRlZCBldmVudCBpcyBhdCBvciBiZWxvdyBpdCByZWdhcmRsZXNzIG9mIHRoZVxuICogb3JkZXIgdGhlIFdvcmxkIHJldHVybmVkIHRoZW0gaW4uXG4gKlxuICogQm90aCBmaWVsZHMgYXJlIHRoZXJlZm9yZSBpbnZhcmlhbnQgdW5kZXIgcGVybXV0YXRpb24gb2YgdGhlIGxvZzogYSBtYXhpbXVtIGlzXG4gKiBvcmRlci1pbmRlcGVuZGVudCwgYW5kIHRoZSBsZW5ndGggaXMgc2V0IGNhcmRpbmFsaXR5IG9uY2UgYGFwcGVuZFVuaXF1ZUV2ZW50c2BcbiAqIGhhcyBkZWR1cGVkIGJ5IGV2ZW50IGlkLiBUd28gcmVwbGF5cyB0aGF0IGNvbnN1bWUgdGhlIHNhbWUgZXZlbnRzIGluIGRpZmZlcmVudFxuICogb3JkZXJzIHNlbmQgYW4gaWRlbnRpY2FsIHNuYXBzaG90LCBzbyB0aGlzIGd1YXJkIGRldGVjdHMgdGhhdCBhIGxvZyBpcyBtaXNzaW5nXG4gKiBhbiBldmVudCBhbmQgY2FuIG5ldmVyIGRldGVjdCB0aGF0IGEgcmVwbGF5IGNvbnN1bWVkIG9uZSBpbiBhIGRpZmZlcmVudCBvcmRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZWNvbmRpdGlvblNuYXBzaG90UGFyYW1zKFxuICBldmVudHM6IEV2ZW50W10sXG4gIGN1cnNvcj86IHN0cmluZyB8IG51bGxcbik6IFByZWNvbmRpdGlvblNuYXBzaG90UGFyYW1zIHtcbiAgaWYgKCFpc1ByZWNvbmRpdGlvbkd1YXJkRW5hYmxlZCgpKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG4gIC8vIEEgc2xvdC1udW1iZXJlZCBydW4gc2F5cyB3aXRoIG9uZSBpbnRlZ2VyIGV2ZXJ5dGhpbmcgdGhlIHRyaXBsZSB3YXNcbiAgLy8gYXBwcm94aW1hdGluZywgc28gdGhlIHR3byBhcmUgYWx0ZXJuYXRpdmVzIHJhdGhlciB0aGFuIGEgcGFpci4gU2VuZGluZyB0aGVcbiAgLy8gdHJpcGxlIGhlcmUgd291bGQgYWxzbyBiZSBmdXRpbGU6IGEgc2xvdCBpZCBjYXJyaWVzIG5vIHRpbWUsIHNvXG4gIC8vIGBsYXRlc3RFdmVudFN0YXRlVXBkYXRlZEF0YCB3b3VsZCBmYWlsIG9wZW4gb24gZXZlcnkgc2luZ2xlIHdyaXRlLlxuICBjb25zdCBldmVudENvdW50ID0gbWF4RXZlbnRTbG90KGV2ZW50cyk7XG4gIGlmIChldmVudENvdW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4geyBldmVudENvdW50IH07XG4gIH1cbiAgY29uc3Qgc3RhdGVVcGRhdGVkQXQgPSBsYXRlc3RFdmVudFN0YXRlVXBkYXRlZEF0KGV2ZW50cyk7XG4gIGlmIChzdGF0ZVVwZGF0ZWRBdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG4gIHJldHVybiB7XG4gICAgc3RhdGVVcGRhdGVkQXQsXG4gICAgc3RhdGVFdmVudENvdW50OiBldmVudHMubGVuZ3RoLFxuICAgIC4uLihjdXJzb3IgPyB7IHN0YXRlQ3Vyc29yOiBjdXJzb3IgfSA6IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgZXZlbnRzIGEgcmVqZWN0aW5nIFdvcmxkIGF0dGFjaGVkIHRvIGEgYFByZWNvbmRpdGlvbkZhaWxlZEVycm9yYCwgd2hlbiBpdFxuICogcmV0dXJuZWQgdGhlIG9uZXMgdGhlIGNsaWVudCdzIHNuYXBzaG90IHdhcyBtaXNzaW5nIGlubGluZS5cbiAqXG4gKiBSZXR1cm5zIGBudWxsYCBmb3IgYW55dGhpbmcgZWxzZSDigJQgbm8gZGV0YWlscywgYSBXb3JsZCB0aGF0IGRpZCBub3QgaW1wbGVtZW50XG4gKiB0aGlzLCBvciBhIHBheWxvYWQgdGhhdCBkb2VzIG5vdCBuYXJyb3cgY2xlYW5seS4gQ2FsbGVycyBmYWxsIGJhY2sgdG9cbiAqIHJlbG9hZGluZyB0aGUgZXZlbnQgbG9nLCB3aGljaCBpcyBhbHdheXMgY29ycmVjdDsgdGhpcyBpcyB1bnRydXN0ZWQtc2hhcGVkXG4gKiBkYXRhIG9uIGEgZmFpbHVyZSBwYXRoLCBzbyBub3RoaW5nIGhlcmUgaXMgcmVwYWlyZWQuXG4gKlxuICogYHJ1bklkYCBpcyB0aGUgY2FsbGVyJ3MgcnVuLiBFdmVyeSBldmVudCBtdXN0IGJlbG9uZyB0byBpdDogdGhlIGRlbHRhIGlzXG4gKiBtZXJnZWQgc3RyYWlnaHQgaW50byB0aGUgcmVwbGF5J3MgbG9nLCBhbmQgb25lIGZvcmVpZ24gZXZlbnQgdGhlcmUgaXMgYVxuICogY29ycnVwdCBsb2cgcmF0aGVyIHRoYW4gYSBjb3JyZWN0ZWQgb25lIOKAlCB0aGUgcmVwbGF5IHdvdWxkIGNvbnN1bWUgYVxuICogY29ycmVsYXRpb24gaWQgZm9yIGFuIGV2ZW50IHRoYXQgZG9lcyBub3QgZXhpc3Qgb24gdGhpcyBydW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmVjb25kaXRpb25FdmVudERlbHRhKFxuICBlcnJvcjogdW5rbm93bixcbiAgcnVuSWQ6IHN0cmluZ1xuKTogeyBldmVudHM6IEV2ZW50W107IGN1cnNvcjogc3RyaW5nIHwgbnVsbCB9IHwgbnVsbCB7XG4gIGlmICghUHJlY29uZGl0aW9uRmFpbGVkRXJyb3IuaXMoZXJyb3IpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3QgZGV0YWlscyA9IGVycm9yLmRldGFpbHM7XG4gIGlmICh0eXBlb2YgZGV0YWlscyAhPT0gJ29iamVjdCcgfHwgZGV0YWlscyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGNvbnN0IHsgZXZlbnRzLCBjdXJzb3IgfSA9IGRldGFpbHMgYXMgeyBldmVudHM/OiB1bmtub3duOyBjdXJzb3I/OiB1bmtub3duIH07XG4gIGlmICghQXJyYXkuaXNBcnJheShldmVudHMpIHx8IGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGV2ZW50cykge1xuICAgIGlmIChcbiAgICAgIHR5cGVvZiBldmVudCAhPT0gJ29iamVjdCcgfHxcbiAgICAgIGV2ZW50ID09PSBudWxsIHx8XG4gICAgICB0eXBlb2YgKGV2ZW50IGFzIHsgZXZlbnRJZD86IHVua25vd24gfSkuZXZlbnRJZCAhPT0gJ3N0cmluZycgfHxcbiAgICAgIChldmVudCBhcyB7IHJ1bklkPzogdW5rbm93biB9KS5ydW5JZCAhPT0gcnVuSWRcbiAgICApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuICByZXR1cm4ge1xuICAgIGV2ZW50czogZXZlbnRzIGFzIEV2ZW50W10sXG4gICAgY3Vyc29yOiB0eXBlb2YgY3Vyc29yID09PSAnc3RyaW5nJyA/IGN1cnNvciA6IG51bGwsXG4gIH07XG59XG5cbi8qKiBDcmVhdGVzIG9uZSBldmVudCBvbiBhIGJvdW5kIHJ1biwgY2FycnlpbmcgcmVwbGF5LXJlY292ZXJ5IHRlbGVtZXRyeS4gKi9cbmV4cG9ydCB0eXBlIEV2ZW50Q3JlYXRvciA9IChcbiAgZGF0YTogQ3JlYXRlRXZlbnRSZXF1ZXN0LFxuICBwYXJhbXM/OiBDcmVhdGVFdmVudFBhcmFtc1xuKSA9PiBQcm9taXNlPEV2ZW50UmVzdWx0PjtcblxuLyoqXG4gKiBDT1JTIGhlYWRlcnMgZm9yIGhlYWx0aCBjaGVjayByZXNwb25zZXMuXG4gKiBBbGxvd3MgdGhlIG9ic2VydmFiaWxpdHkgVUkgdG8gY2hlY2sgZW5kcG9pbnQgaGVhbHRoIGZyb20gYSBkaWZmZXJlbnQgb3JpZ2luLlxuICovXG5jb25zdCBIRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTID0ge1xuICAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJzogJyonLFxuICAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcyc6ICdQT1NULCBPUFRJT05TLCBHRVQsIEhFQUQnLFxuICAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyc6ICdDb250ZW50LVR5cGUnLFxufTtcblxuLyoqXG4gKiBXcmFwcyBhIHJlcXVlc3QvcmVzcG9uc2UgaGFuZGxlciBhbmQgYWRkcyBhIGhlYWx0aCBjaGVjayBcIm1vZGVcIlxuICogYmFzZWQgb24gdGhlIHByZXNlbmNlIG9mIGEgYF9faGVhbHRoYCBxdWVyeSBwYXJhbWV0ZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRoSGVhbHRoQ2hlY2soXG4gIGhhbmRsZXI6IChyZXE6IFJlcXVlc3QpID0+IFByb21pc2U8UmVzcG9uc2U+LFxuICB3b3JsZFNwZWNWZXJzaW9uPzogbnVtYmVyXG4pOiAocmVxOiBSZXF1ZXN0KSA9PiBQcm9taXNlPFJlc3BvbnNlPiB7XG4gIHJldHVybiBhc3luYyAocmVxOiBSZXF1ZXN0KSA9PiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsKTtcbiAgICBjb25zdCBpc0hlYWx0aENoZWNrID0gdXJsLnNlYXJjaFBhcmFtcy5oYXMoJ19faGVhbHRoJyk7XG4gICAgaWYgKGlzSGVhbHRoQ2hlY2spIHtcbiAgICAgIC8vIEhhbmRsZSBDT1JTIHByZWZsaWdodCBmb3IgaGVhbHRoIGNoZWNrXG4gICAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ09QVElPTlMnKSB7XG4gICAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UobnVsbCwge1xuICAgICAgICAgIHN0YXR1czogMjA0LFxuICAgICAgICAgIGhlYWRlcnM6IEhFQUxUSF9DSEVDS19DT1JTX0hFQURFUlMsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5ldyBSZXNwb25zZShcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGhlYWx0aHk6IHRydWUsXG4gICAgICAgICAgZW5kcG9pbnQ6IHVybC5wYXRobmFtZSxcbiAgICAgICAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICAgICAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgICAgICB9KSxcbiAgICAgICAge1xuICAgICAgICAgIHN0YXR1czogMjAwLFxuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICAgICAuLi5IRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTLFxuICAgICAgICAgIH0sXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCBoYW5kbGVyKHJlcSk7XG4gIH07XG59XG5cbi8qKlxuICogUXVldWVzIGEgbWVzc2FnZSB0byB0aGUgc3BlY2lmaWVkIHF1ZXVlIHdpdGggdHJhY2luZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHF1ZXVlTWVzc2FnZShcbiAgd29ybGQ6IFdvcmxkLFxuICAuLi5hcmdzOiBQYXJhbWV0ZXJzPHR5cGVvZiB3b3JsZC5xdWV1ZT5cbikge1xuICBjb25zdCBxdWV1ZU5hbWUgPSBhcmdzWzBdO1xuICBhd2FpdCB0cmFjZShcbiAgICAncXVldWUucHVibGlzaCcsXG4gICAge1xuICAgICAgLy8gU3RhbmRhcmQgT1RFTCBtZXNzYWdpbmcgY29udmVudGlvbnNcbiAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdEZXN0aW5hdGlvbk5hbWUocXVldWVOYW1lKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ09wZXJhdGlvblR5cGUoJ3B1Ymxpc2gnKSxcbiAgICAgICAgLy8gUGVlciBzZXJ2aWNlIGZvciBEYXRhZG9nIHNlcnZpY2UgbWFwc1xuICAgICAgICAuLi5BdHRyaWJ1dGUuUGVlclNlcnZpY2UoJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjU3lzdGVtKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1NlcnZpY2UoJ3ZxcycpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjTWV0aG9kKCdwdWJsaXNoJyksXG4gICAgICB9LFxuICAgICAga2luZDogYXdhaXQgZ2V0U3BhbktpbmQoJ1BST0RVQ0VSJyksXG4gICAgfSxcbiAgICBhc3luYyAoc3BhbikgPT4ge1xuICAgICAgY29uc3QgeyBtZXNzYWdlSWQgfSA9IGF3YWl0IHdvcmxkLnF1ZXVlKC4uLmFyZ3MpO1xuICAgICAgaWYgKG1lc3NhZ2VJZCkge1xuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKEF0dHJpYnV0ZS5NZXNzYWdpbmdNZXNzYWdlSWQobWVzc2FnZUlkKSk7XG4gICAgICB9XG4gICAgfVxuICApO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHF1ZXVlIG92ZXJoZWFkIHRpbWUgaW4gbWlsbGlzZWNvbmRzIGZvciBhIGdpdmVuIG1lc3NhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWV1ZU92ZXJoZWFkKG1lc3NhZ2U6IHsgcmVxdWVzdGVkQXQ/OiBEYXRlIH0pIHtcbiAgaWYgKCFtZXNzYWdlLnJlcXVlc3RlZEF0KSByZXR1cm47XG4gIHRyeSB7XG4gICAgcmV0dXJuIEF0dHJpYnV0ZS5RdWV1ZU92ZXJoZWFkTXMoXG4gICAgICBEYXRlLm5vdygpIC0gbWVzc2FnZS5yZXF1ZXN0ZWRBdC5nZXRUaW1lKClcbiAgICApO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm47XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgbWVtb2l6ZWQgYWNjZXNzb3IgZm9yIGEgcnVuJ3MgZnVsbCBlbmNyeXB0aW9uIGNhcGFiaWxpdHkuXG4gKlxuICogVGhlIGZpcnN0IGNhbGwgcmVzb2x2ZXMgdGhlIHJ1bidzIGtleSBtYXRlcmlhbCB2aWFcbiAqIGB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuYCAod2hpY2ggbWF5IGRvIEhLREYgZGVyaXZhdGlvbiBsb2NhbGx5IG9uXG4gKiBWZXJjZWwsIG9yIGEgbmV0d29yayBmZXRjaCBmcm9tIGV4dGVybmFsIGNvbnRleHRzKSBhbmQgZGVyaXZlcyBhXG4gKiB7QGxpbmsgUGF5bG9hZEtleX0gZnJvbSBpdDsgc3Vic2VxdWVudCBjYWxscyBhd2FpdCB0aGUgc2FtZSBjYWNoZWQgcHJvbWlzZS5cbiAqIElmIHRoZSB3b3JsZCBkb2Vzbid0IHN1cHBvcnQgZW5jcnlwdGlvbiBvciB0aGUgcnVuIGhhcyBubyBrZXkgY29uZmlndXJlZCxcbiAqIHRoZSBjYWNoZWQgdmFsdWUgaXMgYHVuZGVmaW5lZGAuXG4gKlxuICogVGhlIHJlc29sdmVkIHZhbHVlIGlzIGRlbGliZXJhdGVseSB0aGUgKmZ1bGwqIGNhcGFiaWxpdHkg4oCUIHRoZSBzeW1tZXRyaWMgQUVTXG4gKiBrZXkgcGx1cyB0aGUgcnVuJ3MgWDI1NTE5IGtleXBhaXIg4oCUIG5vdCBqdXN0IGEgYENyeXB0b0tleWAuIEEgcnVuIHJlYWRpbmdcbiAqIGl0cyBvd24gZXZlbnQgbG9nIGNhbiBlbmNvdW50ZXIgc2VhbGVkIChgZW5jcGApIHBheWxvYWRzIHRoYXQgYW5vdGhlciBydW5cbiAqIHdyb3RlIHRvIGl0IChhIGNyb3NzLWRlcGxveW1lbnQgaG9vayByZXN1bXB0aW9uLCBzYXkpLCBhbmQgb3BlbmluZyB0aG9zZVxuICogbmVlZHMgdGhlIGtleXBhaXIuIFJlc29sdmluZyBvbmx5IHRoZSBzeW1tZXRyaWMga2V5IHdvdWxkIGxlYXZlIHRob3NlXG4gKiBwYXlsb2FkcyB1bm9wZW5hYmxlIGFuZCB3ZWRnZSB0aGUgcnVuLlxuICpcbiAqIFVzZWQgYnkgc3RlcCAvIHdvcmtmbG93IGhhbmRsZXJzIHRvIGRlZmVyIHRoZSAocG90ZW50aWFsbHkgZXhwZW5zaXZlKVxuICoga2V5IGZldGNoIHVudGlsIHRoZSBmaXJzdCBjb2RlIHBhdGggdGhhdCBhY3R1YWxseSBuZWVkcyBpdCDigJQgdHlwaWNhbGx5XG4gKiBpbnB1dCBoeWRyYXRpb24gb24gdGhlIHN1Y2Nlc3MgcGF0aCwgb3IgZXJyb3IgZGVoeWRyYXRpb24gb24gYSBmYWlsdXJlXG4gKiBwYXRoLiBCb3RoIHBhdGhzIGNhbiByYWNlLWNhbGwgdGhlIGFjY2Vzc29yIHdpdGhvdXQgdHJpZ2dlcmluZyBkdXBsaWNhdGVcbiAqIGZldGNoZXMuXG4gKlxuICogRXJyb3JzIHRocm93biBieSBgZ2V0RW5jcnlwdGlvbktleUZvclJ1bmAgcHJvcGFnYXRlIHRvIGV2ZXJ5IGNhbGxlclxuICogKHRoZSBjYWNoZWQgcHJvbWlzZSByZWplY3RzKS4gVGhpcyBpcyBpbnRlbnRpb25hbDogd2hlbiBlbmNyeXB0aW9uIGlzXG4gKiBjb25maWd1cmVkLCB3ZSBuZXZlciB3YW50IHRvIHNpbGVudGx5IGZhbGwgYmFjayB0byBwbGFpbnRleHRcbiAqIHNlcmlhbGl6YXRpb24uIEEgcHJvcGFnYXRlZCBlcnJvciBpbiBhbiBldmVudC1lbWlzc2lvbiBwYXRoIGxlYXZlcyB0aGVcbiAqIG91dGVyIHRyeS9jYXRjaCB0byBsb2cgYW5kIHN1cmZhY2UgdGhlIGlzc3VlOyB0aGUgcXVldWUncyByZWRlbGl2ZXJ5XG4gKiBzZW1hbnRpY3Mgd2lsbCByZXRyeSB0aGUga2V5IGZldGNoIG9uIHRoZSBuZXh0IGF0dGVtcHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplRW5jcnlwdGlvbktleShcbiAgd29ybGQ6IFdvcmxkLFxuICBydW5PcklkOiBXb3JrZmxvd1J1biB8IHN0cmluZ1xuKTogKCkgPT4gUHJvbWlzZTxQYXlsb2FkS2V5IHwgdW5kZWZpbmVkPiB7XG4gIGxldCBjYWNoZWQ6IFByb21pc2U8UGF5bG9hZEtleSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgaWYgKCFjYWNoZWQpIHtcbiAgICAgIGNhY2hlZCA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIC8vIFRoZSBgZ2V0RW5jcnlwdGlvbktleUZvclJ1bmAgb3ZlcmxvYWQgc2V0IHRha2VzIGVpdGhlciBhXG4gICAgICAgIC8vIGBXb3JrZmxvd1J1bmAgb3IgYSBgcnVuSWQ6IHN0cmluZ2AgKHdpdGggb3B0aW9uYWwgY29udGV4dCkuIEJyYW5jaFxuICAgICAgICAvLyBoZXJlIHNvIFR5cGVTY3JpcHQgcGlja3MgdGhlIHJpZ2h0IG92ZXJsb2FkIGZvciBlYWNoIHNoYXBlLlxuICAgICAgICBjb25zdCByYXdLZXkgPVxuICAgICAgICAgIHR5cGVvZiBydW5PcklkID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4ocnVuT3JJZClcbiAgICAgICAgICAgIDogYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJ1bk9ySWQpO1xuICAgICAgICAvLyBSZXNvbHZlIHRoZSAqZnVsbCogY2FwYWJpbGl0eSwgbm90IGp1c3QgdGhlIHN5bW1ldHJpYyBrZXk6IGEgcnVuXG4gICAgICAgIC8vIHJlYWRpbmcgaXRzIG93biBldmVudCBsb2cgbWF5IGVuY291bnRlciBzZWFsZWQgKGBlbmNwYCkgcGF5bG9hZHNcbiAgICAgICAgLy8gdGhhdCBhbm90aGVyIHJ1biB3cm90ZSB0byBpdCwgYW5kIG9wZW5pbmcgdGhvc2UgbmVlZHMgdGhlIHJ1bidzXG4gICAgICAgIC8vIFgyNTUxOSBzY2FsYXIgYXMgd2VsbC5cbiAgICAgICAgcmV0dXJuIHJhd0tleSA/IGF3YWl0IGRlcml2ZVJ1blBheWxvYWRLZXlzKHJhd0tleSkgOiB1bmRlZmluZWQ7XG4gICAgICB9KSgpO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGVkO1xuICB9O1xufVxuIl19