@workflow/core 5.0.0-beta.5 → 5.0.0-beta.51

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