@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,7 +1,9 @@
1
- import { HealthCheckPayloadSchema, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, } from '@workflow/world';
1
+ import { PreconditionFailedError, RUN_ERROR_CODES, WorkflowWorldError, } from '@workflow/errors';
2
+ import { FIRST_EVENT_SLOT, getQueueTopicPrefix, HealthCheckPayloadSchema, HOOK_RESUME_INPUT_VERSION, ROOT_RUN_ID_ATTRIBUTE, requireEventSlot, resolveQueueNamespace, SPEC_VERSION_CURRENT, SPEC_VERSION_LEGACY, } from '@workflow/world';
2
3
  import { monotonicFactory } from 'ulid';
3
- import { importKey } from '../encryption.js';
4
4
  import { runtimeLogger } from '../logger.js';
5
+ import { bytesToBase64, deriveRunKeyPair } from '../sealed-box.js';
6
+ import { deriveRunPayloadKeys, } from '../serialization/encryption.js';
5
7
  import * as Attribute from '../telemetry/semantic-conventions.js';
6
8
  import { getSpanKind, trace } from '../telemetry.js';
7
9
  import { version as workflowCoreVersion } from '../version.js';
@@ -19,11 +21,12 @@ const SAFE_WORKFLOW_NAME_PATTERN = /^[a-zA-Z0-9_\-./@]+$/;
19
21
  * Ensures the workflow name only contains safe characters before
20
22
  * interpolating it into the queue name string.
21
23
  */
22
- export function getWorkflowQueueName(workflowName) {
24
+ export function getWorkflowQueueName(workflowName, namespace) {
23
25
  if (!SAFE_WORKFLOW_NAME_PATTERN.test(workflowName)) {
24
26
  throw new Error(`Invalid workflow name "${workflowName}": must only contain alphanumeric characters, underscores, hyphens, dots, forward slashes, or at signs`);
25
27
  }
26
- return `__wkf_workflow_${workflowName}`;
28
+ const prefix = getQueueTopicPrefix('workflow', resolveQueueNamespace(namespace));
29
+ return `${prefix}${workflowName}`;
27
30
  }
28
31
  const generateId = monotonicFactory();
29
32
  /**
@@ -57,17 +60,45 @@ function generateHealthCheckRunId(correlationId) {
57
60
  * The caller can listen to this stream to get the health check response.
58
61
  *
59
62
  * @param healthCheck - The parsed health check payload
60
- * @param endpoint - Which endpoint is responding ('workflow' or 'step')
61
63
  */
62
- export async function handleHealthCheckMessage(healthCheck, endpoint, worldSpecVersion) {
64
+ export async function handleHealthCheckMessage(healthCheck, worldSpecVersion) {
63
65
  const world = await getWorldLazy();
64
66
  const streamName = getHealthCheckStreamName(healthCheck.correlationId);
67
+ // When the probe names a run the caller is about to create, publish that
68
+ // run's public key. We are executing inside the target deployment, so its
69
+ // key material is available locally (no API call), and the caller can then
70
+ // seal the workflow arguments straight from this response rather than
71
+ // making a separate key-lookup request.
72
+ //
73
+ // Only a *public* key may travel this way: the probe response stream is
74
+ // deliberately unauthenticated, so anything secret would be exposed.
75
+ // Best-effort: a failure here must not fail the health check itself, which
76
+ // callers also rely on for plain capability detection.
77
+ let encryptionPublicKey;
78
+ if (healthCheck.runId) {
79
+ try {
80
+ const rawKey = await world.getEncryptionKeyForRun?.(healthCheck.runId);
81
+ if (rawKey) {
82
+ encryptionPublicKey = bytesToBase64((await deriveRunKeyPair(rawKey)).publicKey);
83
+ }
84
+ }
85
+ catch (err) {
86
+ runtimeLogger.warn('Health check could not derive a run public key; the caller will fall back to a key lookup', {
87
+ correlationId: healthCheck.correlationId,
88
+ error: err instanceof Error ? err.message : String(err),
89
+ });
90
+ }
91
+ }
65
92
  const response = JSON.stringify({
66
93
  healthy: true,
67
- endpoint,
68
94
  correlationId: healthCheck.correlationId,
69
95
  specVersion: worldSpecVersion ?? SPEC_VERSION_CURRENT,
70
96
  workflowCoreVersion,
97
+ // We are executing inside the target deployment, so this constant reflects
98
+ // the *consumer's* hook-resume protocol version, exactly what a
99
+ // cross-deployment caller needs to gate its parallel resume path on.
100
+ hookResumeInputVersion: HOOK_RESUME_INPUT_VERSION,
101
+ ...(encryptionPublicKey ? { encryptionPublicKey } : {}),
71
102
  timestamp: Date.now(),
72
103
  });
73
104
  // Use a deterministic fake runId derived from the correlationId so that
@@ -78,13 +109,12 @@ export async function handleHealthCheckMessage(healthCheck, endpoint, worldSpecV
78
109
  }
79
110
  /**
80
111
  * Performs a health check by sending a message through the queue pipeline
81
- * and verifying it is processed by the specified endpoint.
112
+ * and verifying it is processed by the combined workflow endpoint.
82
113
  *
83
114
  * This function bypasses Deployment Protection on Vercel because it goes
84
115
  * through the queue infrastructure rather than direct HTTP.
85
116
  *
86
117
  * @param world - The World instance to use for the health check
87
- * @param endpoint - Which endpoint to health check: 'workflow' or 'step'
88
118
  * @param options - Optional configuration for the health check
89
119
  * @returns Promise resolving to health check result
90
120
  */
@@ -97,6 +127,24 @@ const HEALTH_CHECK_READ_TIMEOUT = 500;
97
127
  * Read chunks from a stream with a timeout per read operation.
98
128
  * Returns { chunks, timedOut } where timedOut indicates if a read timed out.
99
129
  */
130
+ /**
131
+ * Race a promise against a deadline. Rejects with a timeout error when the
132
+ * deadline elapses first. Used to bound `world.streams.get()` inside the
133
+ * health-check poll loop: some worlds hold that request open until the
134
+ * stream has data (e.g. workflow-server holds unwritten streams open for
135
+ * ~2 minutes), which would otherwise blow through the configured health
136
+ * check timeout, since the `while` condition is only re-checked between
137
+ * iterations.
138
+ */
139
+ function withDeadline(promise, ms) {
140
+ let timer;
141
+ return Promise.race([
142
+ promise,
143
+ new Promise((_, reject) => {
144
+ timer = setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms);
145
+ }),
146
+ ]).finally(() => clearTimeout(timer));
147
+ }
100
148
  async function readStreamWithTimeout(reader, readTimeout) {
101
149
  const chunks = [];
102
150
  let done = false;
@@ -155,18 +203,37 @@ function parseHealthCheckResponse(chunks) {
155
203
  if (typeof r.specVersion === 'number') {
156
204
  parsed.specVersion = r.specVersion;
157
205
  }
206
+ if (typeof r.workflowCoreVersion === 'string') {
207
+ parsed.workflowCoreVersion = r.workflowCoreVersion;
208
+ }
209
+ if (typeof r.encryptionPublicKey === 'string') {
210
+ parsed.encryptionPublicKey = r.encryptionPublicKey;
211
+ }
212
+ if (typeof r.hookResumeInputVersion === 'number') {
213
+ parsed.hookResumeInputVersion = r.hookResumeInputVersion;
214
+ }
158
215
  return parsed;
159
216
  }
160
- export async function healthCheck(world, endpoint, options) {
217
+ export async function healthCheck(world, options) {
161
218
  const timeout = options?.timeout ?? DEFAULT_HEALTH_CHECK_TIMEOUT;
162
- const correlationId = generateId();
219
+ // Use the world's ID generator when available so the correlationId is a
220
+ // region-tagged ULID. The health-check response is delivered over a stream
221
+ // whose name embeds this correlationId; under platform-directed routing the
222
+ // reader and the responding endpoint can be served from different physical
223
+ // regions, so the region must be encoded in the ID itself for both sides to
224
+ // resolve the same (region-pinned) backend. Falls back to a plain ULID for
225
+ // worlds that don't tag IDs (e.g. local), which resolve to the default
226
+ // region on both sides.
227
+ const correlationId = world.createRunId?.() ?? generateId();
163
228
  const streamName = getHealthCheckStreamName(correlationId);
164
- const queueName = endpoint === 'workflow'
165
- ? '__wkf_workflow_health_check'
166
- : '__wkf_step_health_check';
229
+ const queueName = `${getQueueTopicPrefix('workflow', resolveQueueNamespace(options?.namespace))}health_check`;
167
230
  const startTime = Date.now();
168
231
  try {
169
- await world.queue(queueName, { __healthCheck: true, correlationId }, {
232
+ await world.queue(queueName, {
233
+ __healthCheck: true,
234
+ correlationId,
235
+ ...(options?.runId ? { runId: options.runId } : {}),
236
+ }, {
170
237
  // Use JSON transport so the health check works against both
171
238
  // old (JSON-only) and new (dual) deployments.
172
239
  specVersion: SPEC_VERSION_LEGACY,
@@ -174,7 +241,8 @@ export async function healthCheck(world, endpoint, options) {
174
241
  });
175
242
  while (Date.now() - startTime < timeout) {
176
243
  try {
177
- const stream = await world.streams.get(generateHealthCheckRunId(correlationId), streamName);
244
+ const remainingMs = timeout - (Date.now() - startTime);
245
+ const stream = await withDeadline(world.streams.get(generateHealthCheckRunId(correlationId), streamName), remainingMs);
178
246
  const reader = stream.getReader();
179
247
  const { chunks, timedOut } = await readStreamWithTimeout(reader, HEALTH_CHECK_READ_TIMEOUT);
180
248
  if (timedOut) {
@@ -212,6 +280,94 @@ export async function healthCheck(world, endpoint, options) {
212
280
  };
213
281
  }
214
282
  }
283
+ function eventPaginationContractError(runId, message) {
284
+ return new WorkflowWorldError(`Event pagination ${message} for workflow run "${runId}".`, { code: RUN_ERROR_CODES.WORLD_CONTRACT_ERROR });
285
+ }
286
+ function recordRequestedEventCursor(runId, cursor, requestedCursors) {
287
+ if (!cursor) {
288
+ return;
289
+ }
290
+ if (requestedCursors.has(cursor)) {
291
+ throw eventPaginationContractError(runId, 'did not advance');
292
+ }
293
+ requestedCursors.add(cursor);
294
+ }
295
+ /**
296
+ * Appends events whose IDs are not already present in `target`.
297
+ *
298
+ * Pass the IDs currently present in `target` when appending repeatedly to the
299
+ * same array. The set is updated alongside `target`.
300
+ *
301
+ * Events are appended in the order the World returned them, and are not
302
+ * re-sorted. Every append source is already in canonical order relative to the
303
+ * tail (a cursor-delimited page, or a write-response delta), so receipt order is
304
+ * the order to keep, and re-sorting here would only cost a pass over the log.
305
+ * Nothing downstream may assume the tail is the newest event. See
306
+ * {@link maxEventSlot}.
307
+ */
308
+ export function appendUniqueEvents(target, events, targetIds) {
309
+ if (events.length === 0) {
310
+ return;
311
+ }
312
+ const ids = targetIds ?? new Set(target.map((event) => event.eventId));
313
+ for (const event of events) {
314
+ if (ids.has(event.eventId)) {
315
+ continue;
316
+ }
317
+ ids.add(event.eventId);
318
+ target.push(event);
319
+ }
320
+ }
321
+ /**
322
+ * Inserts `event` into `target` at the position that keeps `target` ordered by
323
+ * ascending `eventId`, or no-ops if an event with the same `eventId` is already
324
+ * present (idempotent).
325
+ *
326
+ * `preloadedEvents` is loaded `sortOrder: 'asc'` and is never re-sorted
327
+ * client-side, so a `hook_received` spliced in by the lazy-resume consumer must
328
+ * land in `eventId` order: a plain `push` would place a late-committing
329
+ * earlier event after events that sort before it, corrupting replay.
330
+ *
331
+ * Lexicographic string order is the log's order: a slot id is a fixed-width
332
+ * zero-padded position, so comparing the strings compares the positions. This
333
+ * needs no parse of its own for that reason, and the comparison is exact rather
334
+ * than a reconstruction.
335
+ */
336
+ export function insertEventByEventId(target, event) {
337
+ // Linear scan from the end: the spliced event is almost always the newest
338
+ // (it sorts at or near the tail), so this finds the slot in O(1)–O(k) for the
339
+ // common case while still handling an out-of-order late arrival correctly.
340
+ let i = target.length;
341
+ while (i > 0) {
342
+ const existing = target[i - 1];
343
+ if (existing.eventId === event.eventId) {
344
+ // Already present: keep the splice idempotent.
345
+ return;
346
+ }
347
+ if (existing.eventId < event.eventId) {
348
+ break;
349
+ }
350
+ i--;
351
+ }
352
+ target.splice(i, 0, event);
353
+ }
354
+ function assertEventPaginationProgress(runId, hasMore, cursor, requestedCursors) {
355
+ if (!hasMore) {
356
+ return;
357
+ }
358
+ if (cursor === null) {
359
+ throw eventPaginationContractError(runId, 'returned more pages without a cursor');
360
+ }
361
+ if (requestedCursors.has(cursor)) {
362
+ throw eventPaginationContractError(runId, 'repeated a cursor');
363
+ }
364
+ }
365
+ function shouldRetryWithoutEventCursor(error, cursor, alreadyRetried) {
366
+ return (cursor !== null &&
367
+ !alreadyRetried &&
368
+ WorkflowWorldError.is(error) &&
369
+ error.status === 400);
370
+ }
215
371
  /**
216
372
  * Loads workflow run events by iterating through all pages of paginated
217
373
  * results. Events are returned in chronological (ascending) order for
@@ -225,31 +381,61 @@ export async function healthCheck(world, endpoint, options) {
225
381
  */
226
382
  export async function loadWorkflowRunEvents(runId, afterCursor) {
227
383
  const incremental = afterCursor !== undefined;
228
- return trace(incremental ? 'workflow.loadNewEvents' : 'workflow.loadEvents', async (span) => {
384
+ return trace('workflow.replay.load', async (span) => {
229
385
  span?.setAttributes({
230
386
  ...Attribute.WorkflowRunId(runId),
387
+ ...Attribute.WorkflowReplayLoadSource(incremental ? 'events_list_incremental' : 'events_list'),
231
388
  });
232
389
  const loadedEvents = [];
390
+ const loadedEventIds = new Set();
391
+ const requestedCursors = new Set();
233
392
  let cursor = afterCursor ?? null;
234
393
  let hasMore = true;
235
394
  let pagesLoaded = 0;
395
+ let retriedWithoutCursor = false;
236
396
  const world = await getWorldLazy();
237
397
  const loadStart = Date.now();
238
398
  while (hasMore) {
239
- // TODO: we're currently loading all the data with resolveRef behaviour. We need to update this
399
+ // TODO: we're currently loading all the data with resolveRef behavior. We need to update this
240
400
  // to lazyload the data from the world instead so that we can optimize and make the event log loading
241
401
  // much faster and memory efficient
242
402
  const pageStart = Date.now();
243
- const response = await world.events.list({
244
- runId,
245
- pagination: {
246
- sortOrder: 'asc',
247
- cursor: cursor ?? undefined,
248
- },
249
- });
250
- loadedEvents.push(...response.data);
403
+ const requestedCursor = cursor;
404
+ recordRequestedEventCursor(runId, requestedCursor, requestedCursors);
405
+ let response;
406
+ try {
407
+ response = await world.events.list({
408
+ runId,
409
+ pagination: {
410
+ sortOrder: 'asc',
411
+ cursor: requestedCursor ?? undefined,
412
+ },
413
+ });
414
+ }
415
+ catch (error) {
416
+ if (shouldRetryWithoutEventCursor(error, requestedCursor, retriedWithoutCursor)) {
417
+ runtimeLogger.warn('Event cursor was rejected; retrying with a full event reload.', { workflowRunId: runId });
418
+ loadedEvents.length = 0;
419
+ loadedEventIds.clear();
420
+ requestedCursors.clear();
421
+ cursor = null;
422
+ retriedWithoutCursor = true;
423
+ continue;
424
+ }
425
+ throw error;
426
+ }
427
+ appendUniqueEvents(loadedEvents, response.data, loadedEventIds);
251
428
  hasMore = response.hasMore;
252
- cursor = response.cursor;
429
+ assertEventPaginationProgress(runId, hasMore, response.cursor, requestedCursors);
430
+ // Preserve the last non-null cursor across pages. A World may
431
+ // legitimately return `{ data: [], cursor: null, hasMore: false }`
432
+ // on a trailing empty page, for example when the previous page's
433
+ // underlying DB query hit the limit exactly and returned a
434
+ // precautionary `LastEvaluatedKey`. Overwriting with that null
435
+ // would lose the position past the last real event we loaded and
436
+ // force the runtime into the "no cursor after initial load" full-
437
+ // reload fallback on every subsequent replay iteration.
438
+ cursor = response.cursor ?? cursor;
253
439
  pagesLoaded++;
254
440
  runtimeLogger.debug('Loaded event page', {
255
441
  workflowRunId: runId,
@@ -275,6 +461,349 @@ export async function loadWorkflowRunEvents(runId, afterCursor) {
275
461
  return { events: loadedEvents, cursor };
276
462
  });
277
463
  }
464
+ /**
465
+ * Extend a loaded log with a page that continues it — a listed page, or the
466
+ * inline delta a write handed back — and move its read position with it.
467
+ *
468
+ * The cursor is only advanced when the page carries one, so a source with no
469
+ * position of its own (a skipped-slot report) cannot walk the read position
470
+ * past events it did not carry. Appending does not re-sort; see
471
+ * {@link appendUniqueEvents} for why receipt order is the order to keep.
472
+ */
473
+ export function appendEventLog(log, appended) {
474
+ appendUniqueEvents(log.events, appended.events);
475
+ log.cursor = appended.cursor ?? log.cursor;
476
+ }
477
+ /**
478
+ * Whether a replay refuses to run over a log with a hole in it (see
479
+ * {@link findEventSlotGap}). **On by default**; set
480
+ * `WORKFLOW_SLOT_GAP_CHECK=0` to replay across holes instead.
481
+ *
482
+ * A World that allocates a position at the moment it commits leaves no hole
483
+ * behind when a write fails, so density is a property the log has by
484
+ * construction rather than one this check maintains. What the check is for is
485
+ * the reads and the Worlds where that does not hold, and by the time it runs
486
+ * the benign explanations are spent: a position missing because a concurrent
487
+ * commit is not visible yet clears on a re-read, which is what
488
+ * {@link settleEventSlotGap} does first.
489
+ *
490
+ * What is left is a hole that persists, and its two causes are
491
+ * indistinguishable from the log. Either a World allocated the position outside
492
+ * the commit and lost the write, in which case nothing happened there and
493
+ * replaying past it is correct, or an event that did happen is missing, in
494
+ * which case replaying past it decides a branch on absence and produces a wrong
495
+ * result with nothing to show for it. Failing is the recoverable side of that
496
+ * trade, and this is the way back out if a fleet turns out to carry holes of
497
+ * the first kind.
498
+ */
499
+ export function isSlotGapCheckEnabled() {
500
+ return process.env.WORKFLOW_SLOT_GAP_CHECK !== '0';
501
+ }
502
+ /*
503
+ * Merging into a log a replay is midway through reading.
504
+ *
505
+ * Three paths add events to a loaded log after the replay has started: a
506
+ * bump-and-report write hands back the slots it skipped ({@link
507
+ * mergeReportedEvents}), an inline delta extends the tail (`absorbCreateDelta`
508
+ * in `runtime.ts`), and a listed page appends ({@link appendUniqueEvents}).
509
+ * They look alarming (the replay is reading an array while something else
510
+ * writes to it) and they are safe for one reason worth stating plainly, since
511
+ * every correctness argument in this file leans on it.
512
+ *
513
+ * **An event in the log is a fact, and a longer log cannot retract one.** The
514
+ * log is append-only and positions are never reused, so a replay that produced
515
+ * event E from the prefix it had loaded has made E true for every replay that
516
+ * follows. A later replay reading a fuller log does not get to decide E should
517
+ * not be there; it consumes E and reconciles to it, which is what the events
518
+ * consumer does when it walks a log holding writes from a replay that raced it.
519
+ *
520
+ * Merging is therefore monotone: it can only add facts this replay has yet to
521
+ * reconcile to, never remove one it already has. That is why absorbing is
522
+ * always optional and never wrong to decline (an unabsorbed event is one the
523
+ * next read returns), and why the guards below can afford to be strict.
524
+ */
525
+ /**
526
+ * Merge the events a bump-and-report write handed back into the log it was
527
+ * derived from, and answer how many of them were new.
528
+ *
529
+ * Unlike {@link appendUniqueEvents}, this re-sorts. The reported events occupy
530
+ * slots *below* the write that reported them, so appending them would put them
531
+ * after events they precede. Sorting by id restores the World's canonical order
532
+ * rather than guessing at it: a slot id is that order, written down.
533
+ */
534
+ export function mergeReportedEvents(target, events) {
535
+ const before = target.length;
536
+ appendUniqueEvents(target, events);
537
+ const added = target.length - before;
538
+ if (added > 0) {
539
+ target.sort((a, b) => a.eventId < b.eventId ? -1 : a.eventId > b.eventId ? 1 : 0);
540
+ }
541
+ return added;
542
+ }
543
+ /**
544
+ * Apply a write's skipped-slot report to the log it was derived from, deciding
545
+ * whether the report may be taken at all.
546
+ *
547
+ * Every replay-context write can come back carrying the events on the slots it
548
+ * skipped over, and every caller wants the same thing from them: fold them in
549
+ * so the writes that follow name a position above them, and so the replay
550
+ * resuming from this log sees them without a reload.
551
+ *
552
+ * The one policy is that a **truncated report is dropped whole**. It covers a
553
+ * span of positions but carries only some of the events on them, so merging it
554
+ * would raise the log's highest position past a position whose event is
555
+ * missing. Later writes read that maximum to say what they have seen, so each
556
+ * would claim a position it never saw, and the World only reports the span a
557
+ * write skips: it would never send the missing one. Dropping costs one more
558
+ * round of the same events on the next write and keeps the log a prefix of the
559
+ * truth, which the note above {@link mergeReportedEvents} explains is always an
560
+ * available answer.
561
+ *
562
+ * Callers that log do so from the returned counts; the decision is not theirs
563
+ * to re-derive.
564
+ */
565
+ export function absorbSkippedSlotReport(target, result) {
566
+ const offered = result.events?.length ?? 0;
567
+ if (offered === 0) {
568
+ return { added: 0, offered: 0, truncated: false };
569
+ }
570
+ if (result.hasMore === true) {
571
+ return { added: 0, offered, truncated: true };
572
+ }
573
+ return {
574
+ added: mergeReportedEvents(target, result.events ?? []),
575
+ offered,
576
+ truncated: false,
577
+ };
578
+ }
579
+ /**
580
+ * The highest slot the loaded log occupies, or `undefined` for an empty log.
581
+ *
582
+ * The maximum, not the count, and the two are not interchangeable even though
583
+ * a healthy log makes them equal. A World hands a position to the insert that
584
+ * occupies it, so a write that never lands leaves no hole behind and the log
585
+ * stays dense. What the count cannot survive is a *partial* read: a log
586
+ * assembled from a truncated report, or read while a concurrent write is
587
+ * committing, holds fewer events than its highest position. Counting those
588
+ * would make the next write claim to have seen less than it has, so the World
589
+ * would report the same events back to it on every attempt.
590
+ *
591
+ * A hole below the maximum is therefore a property of the read, not of the log,
592
+ * which is what lets {@link settleEventSlotGap} re-read instead of giving up.
593
+ *
594
+ * @throws if any event id carries no slot. Every World the runtime replays
595
+ * against numbers events by slot, so an id that does not is a broken log rather
596
+ * than an older one, and a maximum derived by skipping it would understate the
597
+ * log to every write that reads it.
598
+ */
599
+ export function maxEventSlot(events) {
600
+ let max;
601
+ for (const event of events) {
602
+ const slot = requireEventSlot(event.eventId);
603
+ if (max === undefined || slot > max) {
604
+ max = slot;
605
+ }
606
+ }
607
+ return max;
608
+ }
609
+ /**
610
+ * The hole in a loaded log, or `undefined` when there is none to find.
611
+ *
612
+ * The World allocates every position, so a log that holds `n` events below slot
613
+ * `n` is missing one. That matters before a replay
614
+ * and nowhere else: the replay reads the log as the complete record of what has
615
+ * happened, and an absent position is indistinguishable from an event that
616
+ * never occurred. The branch it would have decided gets decided the other way,
617
+ * and the run diverges quietly rather than failing.
618
+ *
619
+ * Order-independent, unlike the equivalent audit the World runs over a page it
620
+ * just read. A loaded log is assembled from listed pages plus whatever a
621
+ * bump-and-report write handed back, and while {@link mergeReportedEvents}
622
+ * restores id order, a check that can fail a healthy run should not depend on
623
+ * that having happened.
624
+ *
625
+ * The first slot is never counted. It belongs to `run_created`, which `start()`
626
+ * posts concurrently with the queue send, so a log read in that window
627
+ * legitimately begins at the second slot and fills in on its own. Every replay
628
+ * that races a run's own start would otherwise report a hole.
629
+ *
630
+ * Returns `undefined` for an empty log, which has no density to check.
631
+ *
632
+ * @throws if any event id carries no slot, for the reason {@link maxEventSlot}
633
+ * gives.
634
+ */
635
+ export function findEventSlotGap(events) {
636
+ const occupied = new Set();
637
+ let maxSlot = 0;
638
+ for (const event of events) {
639
+ const slot = requireEventSlot(event.eventId);
640
+ occupied.add(slot);
641
+ if (slot > maxSlot) {
642
+ maxSlot = slot;
643
+ }
644
+ }
645
+ if (maxSlot === 0) {
646
+ return undefined;
647
+ }
648
+ const floor = occupied.has(FIRST_EVENT_SLOT)
649
+ ? FIRST_EVENT_SLOT
650
+ : FIRST_EVENT_SLOT + 1;
651
+ // Every slot is at or above `floor` by construction, so the log is dense
652
+ // exactly when it holds one event per position in `[floor, maxSlot]`. The
653
+ // scan below only runs once that has already answered no.
654
+ if (occupied.size === maxSlot - floor + 1) {
655
+ return undefined;
656
+ }
657
+ let firstMissingSlot;
658
+ let missingCount = 0;
659
+ for (let slot = floor; slot <= maxSlot; slot++) {
660
+ if (!occupied.has(slot)) {
661
+ firstMissingSlot ??= slot;
662
+ missingCount++;
663
+ }
664
+ }
665
+ if (firstMissingSlot === undefined) {
666
+ return undefined;
667
+ }
668
+ return { firstMissingSlot, missingCount, maxSlot };
669
+ }
670
+ /**
671
+ * How many times a detected hole is re-read before the log is taken at its
672
+ * word, and the backoff before each re-read (doubling per attempt).
673
+ *
674
+ * A hole can be transient. The World allocates a slot inside the insert that
675
+ * occupies it, so two concurrent writers can collide, one retry past the other,
676
+ * and the higher slot commit first, leaving a window in which the lower one is
677
+ * genuinely absent from a strongly-consistent read and fills in a moment later.
678
+ * The window is one commit wide, so a short backoff clears it; anything that
679
+ * survives all three re-reads is a position no write will ever occupy.
680
+ */
681
+ export const SLOT_GAP_RECHECK_ATTEMPTS = 3;
682
+ const SLOT_GAP_RECHECK_BASE_DELAY_MS = 25;
683
+ /**
684
+ * Re-read a log that looks holey until the hole fills in or the re-reads run
685
+ * out, and return the settled log alongside the hole that survived.
686
+ *
687
+ * Reads are strongly consistent, so a hole is not an artifact of *when* the log
688
+ * was read, but it can be an artifact of a write that had not committed yet
689
+ * (see {@link SLOT_GAP_RECHECK_ATTEMPTS}). Distinguishing the two costs a
690
+ * re-read, which is only ever paid by a replay that already found a hole.
691
+ *
692
+ * The reload is full rather than incremental: the missing position is below the
693
+ * log's maximum, so a cursor-anchored read starts past it and can never see it
694
+ * arrive.
695
+ */
696
+ export async function settleEventSlotGap(runId, loaded) {
697
+ let log = loaded;
698
+ let gap = findEventSlotGap(log.events);
699
+ for (let attempt = 0; gap !== undefined && attempt < SLOT_GAP_RECHECK_ATTEMPTS; attempt++) {
700
+ await new Promise((resolve) => setTimeout(resolve, SLOT_GAP_RECHECK_BASE_DELAY_MS * 2 ** attempt));
701
+ log = await loadWorkflowRunEvents(runId);
702
+ gap = findEventSlotGap(log.events);
703
+ }
704
+ return { log, gap };
705
+ }
706
+ /**
707
+ * Build the slot snapshot to attach to a replay-context event creation.
708
+ *
709
+ * Empty for an empty log, which is the state a `run_created` write is issued
710
+ * from: there is no position held yet to name.
711
+ *
712
+ * ## Who names a position
713
+ *
714
+ * A World can hand events back on a write's success response through two
715
+ * params (`CreateEventParams` in `@workflow/world`): `eventCount`, which is
716
+ * answered with the events on the positions the write skipped over (the
717
+ * skipped-slot report), and `sinceCursor`, which is answered with everything
718
+ * after that cursor (the inline delta). Both exist to save the writer a
719
+ * reload. So the rule for which writes send them is not about the event type;
720
+ * it is about whether **the process that writes holds a loaded log it will
721
+ * keep deciding from**, its own next writes or the replay it resumes. A writer
722
+ * with no log has nothing to merge a page into, and whoever decides next is a
723
+ * fresh replay that loads the log anyway.
724
+ *
725
+ * Three gates, all of which must pass for a page to come back:
726
+ *
727
+ * 1. The writer names a position. Only the replay loop's `createEvent` seam
728
+ * (runtime.ts) and the suspension handler's `createGuarded` do; the QuickJS
729
+ * engine's `createEvent` (quickjs-entrypoint.ts) follows the same rule. Raw
730
+ * `world.events.create` calls send nothing.
731
+ * 2. The World reads a page for that event type. A World may decline for types
732
+ * whose writer never holds a log (step executor writes, run-terminal
733
+ * writes), whatever the client sent.
734
+ * 3. There is something to hand back: the report only when the write landed
735
+ * more than one position above `eventCount`; the delta always.
736
+ *
737
+ * | Event | Writer | Sends | Why |
738
+ * |---|---|---|---|
739
+ * | `run_created` | `start()` | nothing | no log exists yet |
740
+ * | `run_started` | replay loop, first write of a delivery | `eventCount` when a log is loaded; no cursor, the `run_started` preload owns the response fields | the preload already returns the full log |
741
+ * | `step_created`, `wait_created`, `hook_disposed`, `attr_set` | suspension handler (`createGuarded`) | `eventCount` | the handler keeps writing from, and resumes replay from, this log |
742
+ * | `step_created` | queue-consumer re-ensure (raw) | nothing | runs from a queue message, no log |
743
+ * | `hook_created` | suspension handler (node), `dispatchPendingOps` (QuickJS) | `eventCount` + `sinceCursor` (only when the suspension creates exactly one hook) | the delta is how an already-received hook resolves without a re-invocation; two creates against one cursor would give two deltas of which only the first could be taken |
744
+ * | `hook_received` | replay loop lazy resume; handler in-suspension resume | `eventCount` (preload owns the cursor fields) | both replay from the log right after |
745
+ * | `hook_received` | webhook / `resumeHook` (raw) | nothing | out-of-band, enqueues a delivery that loads the log |
746
+ * | `wait_completed` | replay loop timer path | `eventCount` | the loop keeps replaying from the log |
747
+ * | `wait_completed` | `runs.*` out-of-band (raw) | nothing | no log |
748
+ * | `step_started`, `step_retrying` | step executor | nothing | no log; the next decision is a replay that reloads or receives the delta below |
749
+ * | `step_completed`, `step_failed` | step executor | `sinceCursor` only, outside turbo, single inline step | this is where the inline execution loop gets its log back; in turbo or from a queued delivery a fresh replay loads it anyway |
750
+ * | `step_failed` | suspension handler, unserializable input | `eventCount` | the handler holds a log; rare, and follows a `step_created` that drew the page |
751
+ * | `attr_set` | `setAttributes()` API (raw) | nothing | out-of-band |
752
+ * | `run_completed`, `run_failed`, `run_cancelled` | replay loop, replay budget, `runs.cancel` | `eventCount` where the node loop's seam stamps it (the QuickJS engine sends nothing); never `sinceCursor` (`deltaRequestCursor` excludes terminal types) | terminal: nothing replays the log afterwards, so a World reads no page for them |
753
+ *
754
+ * Batched writes (`events.createBatch`) are outside all of this: a batch carries
755
+ * no per-event position and gets no page. The user-facing version of this table
756
+ * is in `docs/content/docs/v5/how-it-works/event-sourcing.mdx`; keep the two in
757
+ * step.
758
+ *
759
+ * The maximum rather than the length, for the reason {@link maxEventSlot}
760
+ * gives: a partially-read log holds fewer events than its highest position, and
761
+ * counting those would make the write claim to have seen less than it has, so
762
+ * the World would report the same events back on every attempt.
763
+ */
764
+ export function slotSnapshotParams(events) {
765
+ const eventCount = maxEventSlot(events);
766
+ return eventCount === undefined ? {} : { eventCount };
767
+ }
768
+ /**
769
+ * The events a rejecting World attached to a `PreconditionFailedError`, when it
770
+ * returned the ones the client's snapshot was missing inline.
771
+ *
772
+ * Returns `null` for anything else: no details, a World that did not implement
773
+ * this, or a payload that does not narrow cleanly. Callers fall back to
774
+ * reloading the event log, which is always correct; this is untrusted-shaped
775
+ * data on a failure path, so nothing here is repaired.
776
+ *
777
+ * `runId` is the caller's run. Every event must belong to it: the delta is
778
+ * merged straight into the replay's log, and one foreign event there is a
779
+ * corrupt log rather than a corrected one: the replay would consume a
780
+ * correlation id for an event that does not exist on this run.
781
+ */
782
+ export function preconditionEventDelta(error, runId) {
783
+ if (!PreconditionFailedError.is(error)) {
784
+ return null;
785
+ }
786
+ const details = error.details;
787
+ if (typeof details !== 'object' || details === null) {
788
+ return null;
789
+ }
790
+ const { events, cursor } = details;
791
+ if (!Array.isArray(events) || events.length === 0) {
792
+ return null;
793
+ }
794
+ for (const event of events) {
795
+ if (typeof event !== 'object' ||
796
+ event === null ||
797
+ typeof event.eventId !== 'string' ||
798
+ event.runId !== runId) {
799
+ return null;
800
+ }
801
+ }
802
+ return {
803
+ events: events,
804
+ cursor: typeof cursor === 'string' ? cursor : null,
805
+ };
806
+ }
278
807
  /**
279
808
  * CORS headers for health check responses.
280
809
  * Allows the observability UI to check endpoint health from a different origin.
@@ -316,6 +845,61 @@ export function withHealthCheck(handler, worldSpecVersion) {
316
845
  return await handler(req);
317
846
  };
318
847
  }
848
+ /**
849
+ * The lineage root of a loaded run: its `$rootRunId` attribute, or its own id
850
+ * when it is itself a root.
851
+ */
852
+ export function rootRunIdFrom(attributes, runId) {
853
+ return attributes?.[ROOT_RUN_ID_ATTRIBUTE] ?? runId;
854
+ }
855
+ /**
856
+ * The immutable run identity a step-execution message carries so its consumer
857
+ * can start the step without a blocking `runs.get` — see
858
+ * `RunDispatchContextSchema` in @workflow/world. Built at dispatch time from
859
+ * the run row the producer already holds.
860
+ */
861
+ export function runDispatchContext(run) {
862
+ return {
863
+ deploymentId: run.deploymentId,
864
+ specVersion: run.specVersion ?? 0,
865
+ ...(run.startedAt ? { startedAt: +run.startedAt } : {}),
866
+ rootRunId: rootRunIdFrom(run.attributes, run.runId),
867
+ };
868
+ }
869
+ /** FNV-1a 32-bit hash of a string, as 8 hex chars. Tiny, deterministic, and
870
+ * dependency-free. Used only to scope idempotency keys, not for security. */
871
+ function fnv1a32Hex(value) {
872
+ let hash = 0x811c9dc5;
873
+ for (let i = 0; i < value.length; i++) {
874
+ hash ^= value.charCodeAt(i);
875
+ hash = Math.imul(hash, 0x01000193);
876
+ }
877
+ return (hash >>> 0).toString(16).padStart(8, '0');
878
+ }
879
+ /**
880
+ * Idempotency key for a step's background-dispatch queue message, scoped to
881
+ * the step's IDENTITY, correlation id plus (hashed) step name, rather than
882
+ * the bare correlation id.
883
+ *
884
+ * The scoping matters for resilient step dispatch under the precondition
885
+ * guard: a guard-rejected `step_created` leaves its (revoked) step message in
886
+ * flight, and the corrected replay may re-derive the same correlation id for
887
+ * a DIFFERENT step. Under a bare-correlationId key the corrected replay's
888
+ * dispatch would silently dedupe against the revoked in-flight message,
889
+ * which then resolves `skipped` against the re-created entity (the server's
890
+ * stepName fence rejects its bare start), and the legitimate step would
891
+ * never be executed. Scoping by step name keeps every dedup property that
892
+ * matters (crash recovery re-dispatch, concurrent handlers, the delayed
893
+ * retry sharing the suspension re-dispatch's key: all name the same step)
894
+ * while letting the corrected schedule's dispatch through.
895
+ *
896
+ * Every producer of a step-dispatch (or step-retry) message must use this
897
+ * key. Cross-version mixing is not a concern: queue messages are pinned to
898
+ * the deployment that produced them, so one run never sees two key schemes.
899
+ */
900
+ export function stepDispatchIdempotencyKey(correlationId, stepName) {
901
+ return `${correlationId}:${fnv1a32Hex(stepName)}`;
902
+ }
319
903
  /**
320
904
  * Queues a message to the specified queue with tracing.
321
905
  */
@@ -341,6 +925,65 @@ export async function queueMessage(world, ...args) {
341
925
  }
342
926
  });
343
927
  }
928
+ /**
929
+ * Publishes several messages to one logical queue, using the World's batch
930
+ * send when it has one and falling back to concurrent single sends when it
931
+ * does not.
932
+ *
933
+ * Rejects if ANY message failed to publish, because every caller so far wants
934
+ * all-or-nothing: the recovery is to fail the delivery and let redelivery
935
+ * republish the whole set, deduped by the per-message `idempotencyKey`. That
936
+ * means a partial batch can leave some messages already out — which is
937
+ * exactly why the keys are required rather than advisory.
938
+ */
939
+ export async function queueMessages(world, queueName, messages) {
940
+ if (messages.length === 0)
941
+ return;
942
+ const batch = world.queueBatch?.bind(world);
943
+ if (!batch) {
944
+ await Promise.all(messages.map((entry) => queueMessage(world, queueName, entry.message, entry.opts)));
945
+ return;
946
+ }
947
+ await trace('queue.publish', {
948
+ attributes: {
949
+ ...Attribute.MessagingSystem('vercel-queue'),
950
+ ...Attribute.MessagingDestinationName(queueName),
951
+ ...Attribute.MessagingOperationType('publish'),
952
+ ...Attribute.MessagingBatchMessageCount(messages.length),
953
+ ...Attribute.PeerService('vercel-queue'),
954
+ ...Attribute.RpcSystem('vercel-queue'),
955
+ ...Attribute.RpcService('vqs'),
956
+ ...Attribute.RpcMethod('publishBatch'),
957
+ },
958
+ kind: await getSpanKind('PRODUCER'),
959
+ }, async () => {
960
+ const results = await batch(queueName, messages);
961
+ // A World that answers with the wrong number of results has told us
962
+ // nothing about the messages it left out. Treated as a failure of the
963
+ // whole batch rather than read as success for the entries that ARE
964
+ // present: republishing under the same idempotency keys is safe,
965
+ // silently never dispatching a step is not (the run makes no progress
966
+ // and nothing surfaces an error).
967
+ if (results.length !== messages.length) {
968
+ throw Object.assign(new Error(`Queue batch for ${queueName} returned ${results.length} ` +
969
+ `result(s) for ${messages.length} message(s)`), { retryable: true });
970
+ }
971
+ const failures = results.filter((result) => result.error !== undefined);
972
+ if (failures.length === 0)
973
+ return;
974
+ const retryable = failures.some((failure) => failure.error !== undefined && failure.retryable);
975
+ const error = new Error(`Failed to publish ${failures.length} of ${messages.length} queue ` +
976
+ `message(s) to ${queueName}: ${failures[0]?.error}`);
977
+ // Carried on the error so a caller CAN tell a transient partial batch
978
+ // from a permanent rejection. Nothing reads it yet: today every caller
979
+ // rejects the delivery either way, so a permanently rejected entry
980
+ // still costs the full redelivery budget. Left in place because the
981
+ // information is only available here, and a fast-fail on
982
+ // `retryable: false` needs it.
983
+ Object.assign(error, { retryable });
984
+ throw error;
985
+ });
986
+ }
344
987
  /**
345
988
  * Calculates the queue overhead time in milliseconds for a given message.
346
989
  */
@@ -355,42 +998,28 @@ export function getQueueOverhead(message) {
355
998
  }
356
999
  }
357
1000
  /**
358
- * Returns a memoized accessor for the per-run AES-256 encryption key.
359
- *
360
- * The first call resolves the key via `world.getEncryptionKeyForRun` (which
361
- * may do HKDF derivation locally on Vercel, or a network fetch from
362
- * external contexts) and imports it as a `CryptoKey`; subsequent calls
363
- * await the same cached promise. If the world doesn't support encryption
364
- * or the run has no key configured, the cached value is `undefined`.
365
- *
366
- * Used by step / workflow handlers to defer the (potentially expensive)
367
- * key fetch until the first code path that actually needs it — typically
368
- * input hydration on the success path, or error dehydration on a failure
369
- * path. Both paths can race-call the accessor without triggering duplicate
370
- * fetches.
371
- *
372
- * Errors thrown by `getEncryptionKeyForRun` propagate to every caller
373
- * (the cached promise rejects). This is intentional: when encryption is
374
- * configured, we never want to silently fall back to plaintext
375
- * serialization. A propagated error in an event-emission path leaves the
376
- * outer try/catch to log and surface the issue; the queue's redelivery
377
- * semantics will retry the key fetch on the next attempt.
1001
+ * Resolve the run's full payload-encryption capability. This includes the
1002
+ * symmetric key and X25519 keypair needed to open cross-run sealed payloads.
1003
+ * Missing world support or key material resolves to `undefined`; lookup and
1004
+ * derivation failures propagate rather than silently falling back to plaintext.
1005
+ */
1006
+ export async function resolveRunEncryptionKey(world, runOrId, context) {
1007
+ const rawKey = typeof runOrId === 'string'
1008
+ ? await world.getEncryptionKeyForRun?.(runOrId, context)
1009
+ : await world.getEncryptionKeyForRun?.(runOrId);
1010
+ return rawKey ? await deriveRunPayloadKeys(rawKey) : undefined;
1011
+ }
1012
+ /**
1013
+ * Return a lazy, memoized accessor around {@link resolveRunEncryptionKey}.
1014
+ * Concurrent callers share the same promise, including its rejection.
378
1015
  */
379
1016
  export function memoizeEncryptionKey(world, runOrId) {
380
1017
  let cached;
381
1018
  return () => {
382
1019
  if (!cached) {
383
- cached = (async () => {
384
- // The `getEncryptionKeyForRun` overload set takes either a
385
- // `WorkflowRun` or a `runId: string` (with optional context). Branch
386
- // here so TypeScript picks the right overload for each shape.
387
- const rawKey = typeof runOrId === 'string'
388
- ? await world.getEncryptionKeyForRun?.(runOrId)
389
- : await world.getEncryptionKeyForRun?.(runOrId);
390
- return rawKey ? await importKey(rawKey) : undefined;
391
- })();
1020
+ cached = resolveRunEncryptionKey(world, runOrId);
392
1021
  }
393
1022
  return cached;
394
1023
  };
395
1024
  }
396
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUNMLHdCQUF3QixFQUN4QixvQkFBb0IsRUFDcEIsbUJBQW1CLEdBQ3BCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXhDLE9BQU8sRUFBa0IsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM3QyxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbkQsd0RBQXdEO0FBQ3hELE1BQU0sNEJBQTRCLEdBQUcsTUFBTSxDQUFDO0FBRTVDOzs7O0dBSUc7QUFDSCxNQUFNLDBCQUEwQixHQUFHLHNCQUFzQixDQUFDO0FBRTFEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQUMsWUFBb0I7SUFDdkQsSUFBSSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1FBQ25ELE1BQU0sSUFBSSxLQUFLLENBQ2IsMEJBQTBCLFlBQVksd0dBQXdHLENBQy9JLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxrQkFBa0IsWUFBWSxFQUFvQixDQUFDO0FBQzVELENBQUM7QUFFRCxNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsRUFBRSxDQUFDO0FBRXRDOztHQUVHO0FBQ0gsU0FBUyx3QkFBd0IsQ0FBQyxhQUFxQjtJQUNyRCxPQUFPLG1C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VyxDQUFDLE9BQU8sRUFBRSxDQUMzQyxDQUFDO0lBQ0osQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU87SUFDVCxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLEtBQVksRUFDWixPQUE2QjtJQUU3QixJQUFJLE1BQWtELENBQUM7SUFDdkQsT0FBTyxHQUFHLEVBQUU7UUFDVixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDbkIsMkRBQTJEO2dCQUMzRCxxRUFBcUU7Z0JBQ3JFLDhEQUE4RDtnQkFDOUQsTUFBTSxNQUFNLEdBQ1YsT0FBTyxPQUFPLEtBQUssUUFBUTtvQkFDekIsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLHNCQUFzQixFQUFFLENBQUMsT0FBTyxDQUFDO29CQUMvQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDcEQsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDdEQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNQLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUge1xuICBFdmVudCxcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBWYWxpZFF1ZXVlTmFtZSxcbiAgV29ya2Zsb3dSdW4sXG4gIFdvcmxkLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHtcbiAgSGVhbHRoQ2hlY2tQYXlsb2FkU2NoZW1hLFxuICBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgU1BFQ19WRVJTSU9OX0xFR0FDWSxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7IG1vbm90b25pY0ZhY3RvcnkgfSBmcm9tICd1bGlkJztcblxuaW1wb3J0IHsgdHlwZSBDcnlwdG9LZXksIGltcG9ydEtleSB9IGZyb20gJy4uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgKiBhcyBBdHRyaWJ1dGUgZnJvbSAnLi4vdGVsZW1ldHJ5L3NlbWFudGljLWNvbnZlbnRpb25zLmpzJztcbmltcG9ydCB7IGdldFNwYW5LaW5kLCB0cmFjZSB9IGZyb20gJy4uL3RlbGVtZXRyeS5qcyc7XG5pbXBvcnQgeyB2ZXJzaW9uIGFzIHdvcmtmbG93Q29yZVZlcnNpb24gfSBmcm9tICcuLi92ZXJzaW9uLmpzJztcbmltcG9ydCB7IGdldFdvcmxkTGF6eSB9IGZyb20gJy4vZ2V0LXdvcmxkLWxhenkuanMnO1xuXG4vKiogRGVmYXVsdCB0aW1lb3V0IGZvciBoZWFsdGggY2hlY2tzIGluIG1pbGxpc2Vjb25kcyAqL1xuY29uc3QgREVGQVVMVF9IRUFMVEhfQ0hFQ0tfVElNRU9VVCA9IDMwXzAwMDtcblxuLyoqXG4gKiBQYXR0ZXJuIGZvciBzYWZlIHdvcmtmbG93IG5hbWVzLiBPbmx5IGFsbG93cyBhbHBoYW51bWVyaWMgY2hhcmFjdGVycyxcbiAqIHVuZGVyc2NvcmVzLCBoeXBoZW5zLCBkb3RzLCBmb3J3YXJkIHNsYXNoZXMgKGZvciBuYW1lc3BhY2VkIHdvcmtmbG93cyksXG4gKiBhbmQgYXQgc2lnbnMgKGZvciBzY29wZWQgcGFja2FnZXMpLlxuICovXG5jb25zdCBTQUZFX1dPUktGTE9XX05BTUVfUEFUVEVSTiA9IC9eW2EtekEtWjAtOV9cXC0uL0BdKyQvO1xuXG4vKipcbiAqIFZhbGlkYXRlcyBhIHdvcmtmbG93IG5hbWUgYW5kIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgcXVldWUgbmFtZS5cbiAqIEVuc3VyZXMgdGhlIHdvcmtmbG93IG5hbWUgb25seSBjb250YWlucyBzYWZlIGNoYXJhY3RlcnMgYmVmb3JlXG4gKiBpbnRlcnBvbGF0aW5nIGl0IGludG8gdGhlIHF1ZXVlIG5hbWUgc3RyaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0V29ya2Zsb3dRdWV1ZU5hbWUod29ya2Zsb3dOYW1lOiBzdHJpbmcpOiBWYWxpZFF1ZXVlTmFtZSB7XG4gIGlmICghU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4udGVzdCh3b3JrZmxvd05hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEludmFsaWQgd29ya2Zsb3cgbmFtZSBcIiR7d29ya2Zsb3dOYW1lfVwiOiBtdXN0IG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgdW5kZXJzY29yZXMsIGh5cGhlbnMsIGRvdHMsIGZvcndhcmQgc2xhc2hlcywgb3IgYXQgc2lnbnNgXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYF9fd2tmX3dvcmtmbG93XyR7d29ya2Zsb3dOYW1lfWAgYXMgVmFsaWRRdWV1ZU5hbWU7XG59XG5cbmNvbnN0IGdlbmVyYXRlSWQgPSBtb25vdG9uaWNGYWN0b3J5KCk7XG5cbi8qKlxuICogUmV0dXJucyB0aGUgc3RyZWFtIG5hbWUgZm9yIGEgaGVhbHRoIGNoZWNrIHdpdGggdGhlIGdpdmVuIGNvcnJlbGF0aW9uIElELlxuICovXG5mdW5jdGlvbiBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBfX2hlYWx0aF9jaGVja19fJHtjb3JyZWxhdGlvbklkfWA7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGEgaGVhbHRoIGNoZWNrIG9wZXJhdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhDaGVja1Jlc3VsdCB7XG4gIGhlYWx0aHk6IGJvb2xlYW47XG4gIC8qKiBFcnJvciBtZXNzYWdlIGlmIGhlYWx0aCBjaGVjayBmYWlsZWQgKi9cbiAgZXJyb3I/OiBzdHJpbmc7XG4gIC8qKiBMYXRlbmN5IGlmIHRoZSBoZWFsdGggY2hlY2sgd2FzIHN1Y2Nlc3NmdWwgKi9cbiAgbGF0ZW5jeU1zPzogbnVtYmVyO1xuICAvKiogU3BlYyB2ZXJzaW9uIG9mIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQgKi9cbiAgc3BlY1ZlcnNpb24/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBtZXNzYWdlIGlzIGEgaGVhbHRoIGNoZWNrIHBheWxvYWQuXG4gKiBJZiBzbywgcmV0dXJucyB0aGUgcGFyc2VkIHBheWxvYWQuIE90aGVyd2lzZSByZXR1cm5zIHVuZGVmaW5lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tQYXlsb2FkKFxuICBtZXNzYWdlOiB1bmtub3duXG4pOiBIZWFsdGhDaGVja1BheWxvYWQgfCB1bmRlZmluZWQge1xuICBjb25zdCByZXN1bHQgPSBIZWFsdGhDaGVja1BheWxvYWRTY2hlbWEuc2FmZVBhcnNlKG1lc3NhZ2UpO1xuICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4gcmVzdWx0LmRhdGE7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBkZXRlcm1pbmlzdGljIGZha2UgcnVuSWQgZm9yIGhlYWx0aCBjaGVjayBzdHJlYW1zLlxuICogQm90aCB0aGUgd3JpdGVyIChoYW5kbGVIZWFsdGhDaGVja01lc3NhZ2UpIGFuZCByZWFkZXIgKGhlYWx0aENoZWNrKSBkZXJpdmVcbiAqIHRoZSBzYW1lIHJ1bklkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdCBpbXBsZW1lbnRhdGlvbnMgdGhhdCBzY29wZVxuICogc3RyZWFtIHJlYWRzIGJ5IHJ1bklkIHN0aWxsIHdvcmsgY29ycmVjdGx5LlxuICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhlYWx0aENoZWNrUnVuSWQoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGB3cnVuX2hjXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIEhhbmRsZXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZSBieSB3cml0aW5nIHRoZSByZXN1bHQgdG8gdGhlIHdvcmxkJ3Mgc3RyZWFtLlxuICogVGhlIGNhbGxlciBjYW4gbGlzdGVuIHRvIHRoaXMgc3RyZWFtIHRvIGdldCB0aGUgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSBoZWFsdGhDaGVjayAtIFRoZSBwYXJzZWQgaGVhbHRoIGNoZWNrIHBheWxvYWRcbiAqIEBwYXJhbSBlbmRwb2ludCAtIFdoaWNoIGVuZHBvaW50IGlzIHJlc3BvbmRpbmcgKCd3b3JrZmxvdycgb3IgJ3N0ZXAnKVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlSGVhbHRoQ2hlY2tNZXNzYWdlKFxuICBoZWFsdGhDaGVjazogSGVhbHRoQ2hlY2tQYXlsb2FkLFxuICBlbmRwb2ludDogJ3dvcmtmbG93JyB8ICdzdGVwJyxcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCk7XG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIGhlYWx0aHk6IHRydWUsXG4gICAgZW5kcG9pbnQsXG4gICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgfSk7XG4gIC8vIFVzZSBhIGRldGVybWluaXN0aWMgZmFrZSBydW5JZCBkZXJpdmVkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdFxuICAvLyB0aGUgcmVhZGVyIHNpZGUgcHJvZHVjZXMgdGhlIHNhbWUgdmFsdWUuXG4gIGNvbnN0IGZha2VSdW5JZCA9IGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChoZWFsdGhDaGVjay5jb3JyZWxhdGlvbklkKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy53cml0ZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUsIHJlc3BvbnNlKTtcbiAgYXdhaXQgd29ybGQuc3RyZWFtcy5jbG9zZShmYWtlUnVuSWQsIHN0cmVhbU5hbWUpO1xufVxuXG5leHBvcnQgdHlwZSBIZWFsdGhDaGVja0VuZHBvaW50ID0gJ3dvcmtmbG93JyB8ICdzdGVwJztcblxuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhDaGVja09wdGlvbnMge1xuICAvKiogVGltZW91dCBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLiBEZWZhdWx0OiAzMDAwMCAoMzBzKSAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xuICAvKiogRGVwbG95bWVudCBJRCB0byBzZW5kIHRoZSBoZWFsdGggY2hlY2sgdG8uIEZhbGxzIGJhY2sgdG8gcHJvY2Vzcy5lbnYuVkVSQ0VMX0RFUExPWU1FTlRfSUQuICovXG4gIGRlcGxveW1lbnRJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQZXJmb3JtcyBhIGhlYWx0aCBjaGVjayBieSBzZW5kaW5nIGEgbWVzc2FnZSB0aHJvdWdoIHRoZSBxdWV1ZSBwaXBlbGluZVxuICogYW5kIHZlcmlmeWluZyBpdCBpcyBwcm9jZXNzZWQgYnkgdGhlIHNwZWNpZmllZCBlbmRwb2ludC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGJ5cGFzc2VzIERlcGxveW1lbnQgUHJvdGVjdGlvbiBvbiBWZXJjZWwgYmVjYXVzZSBpdCBnb2VzXG4gKiB0aHJvdWdoIHRoZSBxdWV1ZSBpbmZyYXN0cnVjdHVyZSByYXRoZXIgdGhhbiBkaXJlY3QgSFRUUC5cbiAqXG4gKiBAcGFyYW0gd29ybGQgLSBUaGUgV29ybGQgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcGFyYW0gZW5kcG9pbnQgLSBXaGljaCBlbmRwb2ludCB0byBoZWFsdGggY2hlY2s6ICd3b3JrZmxvdycgb3IgJ3N0ZXAnXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBoZWFsdGggY2hlY2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIGhlYWx0aCBjaGVjayByZXN1bHRcbiAqL1xuLy8gUG9sbCBpbnRlcnZhbCBmb3IgaGVhbHRoIGNoZWNrIHJldHJpZXMgKG1zKVxuY29uc3QgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwgPSAxMDA7XG4vLyBQZXItcmVhZCB0aW1lb3V0IHRvIHByZXZlbnQgYmxvY2tpbmcgZm9yZXZlciBvbiBsb2NhbCB3b3JsZCdzIEV2ZW50RW1pdHRlclxuLy8gKHdoaWNoIGRvZXNuJ3Qgd29yayBhY3Jvc3MgcHJvY2Vzc2VzKVxuY29uc3QgSEVBTFRIX0NIRUNLX1JFQURfVElNRU9VVCA9IDUwMDtcblxuLyoqXG4gKiBSZWFkIGNodW5rcyBmcm9tIGEgc3RyZWFtIHdpdGggYSB0aW1lb3V0IHBlciByZWFkIG9wZXJhdGlvbi5cbiAqIFJldHVybnMgeyBjaHVua3MsIHRpbWVkT3V0IH0gd2hlcmUgdGltZWRPdXQgaW5kaWNhdGVzIGlmIGEgcmVhZCB0aW1lZCBvdXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlYWRTdHJlYW1XaXRoVGltZW91dChcbiAgcmVhZGVyOiBSZWFkYWJsZVN0cmVhbURlZmF1bHRSZWFkZXI8VWludDhBcnJheT4sXG4gIHJlYWRUaW1lb3V0OiBudW1iZXJcbik6IFByb21pc2U8eyBjaHVua3M6IFVpbnQ4QXJyYXlbXTsgdGltZWRPdXQ6IGJvb2xlYW4gfT4ge1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICBsZXQgZG9uZSA9IGZhbHNlO1xuICBsZXQgdGltZWRPdXQgPSBmYWxzZTtcblxuICB3aGlsZSAoIWRvbmUgJiYgIXRpbWVkT3V0KSB7XG4gICAgY29uc3QgcmVhZFByb21pc2UgPSByZWFkZXIucmVhZCgpO1xuICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2U8eyBkb25lOiB0cnVlOyB2YWx1ZTogdW5kZWZpbmVkIH0+KFxuICAgICAgKHJlc29sdmUpID0+XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHRpbWVkT3V0ID0gdHJ1ZTtcbiAgICAgICAgICByZXNvbHZlKHsgZG9uZTogdHJ1ZSwgdmFsdWU6IHVuZGVmaW5lZCB9KTtcbiAgICAgICAgfSwgcmVhZFRpbWVvdXQpXG4gICAgKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UucmFjZShbcmVhZFByb21pc2UsIHRpbWVvdXRQcm9taXNlXSk7XG4gICAgZG9uZSA9IHJlc3VsdC5kb25lO1xuICAgIGlmIChyZXN1bHQudmFsdWUpIGNodW5rcy5wdXNoKHJlc3VsdC52YWx1ZSk7XG4gIH1cblxuICByZXR1cm4geyBjaHVua3MsIHRpbWVkT3V0IH07XG59XG5cbi8qKlxuICogUGFyc2UgYW5kIHZhbGlkYXRlIGEgaGVhbHRoIGNoZWNrIHJlc3BvbnNlIGZyb20gc3RyZWFtIGNodW5rcy5cbiAqIFJldHVybnMgdGhlIHBhcnNlZCByZXNwb25zZSBvciBudWxsIGlmIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShcbiAgY2h1bmtzOiBVaW50OEFycmF5W11cbik6IHsgaGVhbHRoeTogYm9vbGVhbiB9IHwgbnVsbCB7XG4gIGlmIChjaHVua3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcblxuICBjb25zdCB0b3RhbExlbmd0aCA9IGNodW5rcy5yZWR1Y2UoKHN1bSwgY2h1bmspID0+IHN1bSArIGNodW5rLmxlbmd0aCwgMCk7XG4gIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkodG90YWxMZW5ndGgpO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3MpIHtcbiAgICBjb21iaW5lZC5zZXQoY2h1bmssIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IGNodW5rLmxlbmd0aDtcbiAgfVxuICBjb25zdCByZXNwb25zZVRleHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoY29tYmluZWQpO1xuXG4gIGxldCByZXNwb25zZTogdW5rbm93bjtcbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IEpTT04ucGFyc2UocmVzcG9uc2VUZXh0KTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gT2xkIGRlcGxveW1lbnRzIChzcGVjVmVyc2lvbiA8IDMpIHJldHVybiBwbGFpbiB0ZXh0IGxpa2VcbiAgICAvLyAnV29ya2Zsb3cgU0RLIFwiLi4uXCIgZW5kcG9pbnQgaXMgaGVhbHRoeScuIFRyZWF0IGFueSBub24tZW1wdHlcbiAgICAvLyB0ZXh0IHJlc3BvbnNlIGFzIGEgaGVhbHRoeSBkZXBsb3ltZW50IHdpdGggdW5rbm93biBzcGVjVmVyc2lvbi5cbiAgICBpZiAocmVzcG9uc2VUZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoXG4gICAgdHlwZW9mIHJlc3BvbnNlICE9PSAnb2JqZWN0JyB8fFxuICAgIHJlc3BvbnNlID09PSBudWxsIHx8XG4gICAgISgnaGVhbHRoeScgaW4gcmVzcG9uc2UpIHx8XG4gICAgdHlwZW9mIChyZXNwb25zZSBhcyB7IGhlYWx0aHk6IHVua25vd24gfSkuaGVhbHRoeSAhPT0gJ2Jvb2xlYW4nXG4gICkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgciA9IHJlc3BvbnNlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBwYXJzZWQ6IHsgaGVhbHRoeTogYm9vbGVhbjsgc3BlY1ZlcnNpb24/OiBudW1iZXIgfSA9IHtcbiAgICBoZWFsdGh5OiByLmhlYWx0aHkgYXMgYm9vbGVhbixcbiAgfTtcbiAgaWYgKHR5cGVvZiByLnNwZWNWZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgIHBhcnNlZC5zcGVjVmVyc2lvbiA9IHIuc3BlY1ZlcnNpb247XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhlYWx0aENoZWNrKFxuICB3b3JsZDogV29ybGQsXG4gIGVuZHBvaW50OiBIZWFsdGhDaGVja0VuZHBvaW50LFxuICBvcHRpb25zPzogSGVhbHRoQ2hlY2tPcHRpb25zXG4pOiBQcm9taXNlPEhlYWx0aENoZWNrUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zPy50aW1lb3V0ID8/IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQ7XG4gIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBnZW5lcmF0ZUlkKCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoY29ycmVsYXRpb25JZCk7XG5cbiAgY29uc3QgcXVldWVOYW1lOiBWYWxpZFF1ZXVlTmFtZSA9XG4gICAgZW5kcG9pbnQgPT09ICd3b3JrZmxvdydcbiAgICAgID8gJ19fd2tmX3dvcmtmbG93X2hlYWx0aF9jaGVjaydcbiAgICAgIDogJ19fd2tmX3N0ZXBfaGVhbHRoX2NoZWNrJztcblxuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd29ybGQucXVldWUoXG4gICAgICBxdWV1ZU5hbWUsXG4gICAgICB7IF9faGVhbHRoQ2hlY2s6IHRydWUsIGNvcnJlbGF0aW9uSWQgfSxcbiAgICAgIHtcbiAgICAgICAgLy8gVXNlIEpTT04gdHJhbnNwb3J0IHNvIHRoZSBoZWFsdGggY2hlY2sgd29ya3MgYWdhaW5zdCBib3RoXG4gICAgICAgIC8vIG9sZCAoSlNPTi1vbmx5KSBhbmQgbmV3IChkdWFsKSBkZXBsb3ltZW50cy5cbiAgICAgICAgc3BlY1ZlcnNpb246IFNQRUNfVkVSU0lPTl9MRUdBQ1ksXG4gICAgICAgIGRlcGxveW1lbnRJZDogb3B0aW9ucz8uZGVwbG95bWVudElkLFxuICAgICAgfVxuICAgICk7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA8IHRpbWVvdXQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IHdvcmxkLnN0cmVhbXMuZ2V0KFxuICAgICAgICAgIGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChjb3JyZWxhdGlvbklkKSxcbiAgICAgICAgICBzdHJlYW1OYW1lXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHN0cmVhbS5nZXRSZWFkZXIoKTtcbiAgICAgICAgY29uc3QgeyBjaHVua3MsIHRpbWVkT3V0IH0gPSBhd2FpdCByZWFkU3RyZWFtV2l0aFRpbWVvdXQoXG4gICAgICAgICAgcmVhZGVyLFxuICAgICAgICAgIEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVRcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGltZWRPdXQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVhZGVyLmNhbmNlbCgpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSWdub3JlIGNhbmNlbCBlcnJvcnNcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3MpO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4ucmVzcG9uc2UsXG4gICAgICAgICAgICBsYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydFRpbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBIZWFsdGggY2hlY2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tc2AsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhbHRoeTogZmFsc2UsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBMb2FkcyB3b3JrZmxvdyBydW4gZXZlbnRzIGJ5IGl0ZXJhdGluZyB0aHJvdWdoIGFsbCBwYWdlcyBvZiBwYWdpbmF0ZWRcbiAqIHJlc3VsdHMuIEV2ZW50cyBhcmUgcmV0dXJuZWQgaW4gY2hyb25vbG9naWNhbCAoYXNjZW5kaW5nKSBvcmRlciBmb3JcbiAqIGRldGVybWluaXN0aWMgd29ya2Zsb3cgcmVwbGF5LlxuICpcbiAqIEBwYXJhbSBydW5JZCAtIFRoZSB3b3JrZmxvdyBydW4gSUQuXG4gKiBAcGFyYW0gYWZ0ZXJDdXJzb3IgLSBJZiBwcm92aWRlZCwgb25seSBldmVudHMgYWZ0ZXIgdGhpcyBjdXJzb3IgYXJlXG4gKiAgIHJldHVybmVkIChpbmNyZW1lbnRhbCBsb2FkKS4gSWYgb21pdHRlZCwgYWxsIGV2ZW50cyBhcmUgcmV0dXJuZWQuXG4gKiAgIFRoZSByZXR1cm5lZCBjdXJzb3IgY2FuIGJlIHBhc3NlZCBiYWNrIGluIG9uIGEgc3Vic2VxdWVudCBjYWxsIGZvclxuICogICBpbmNyZW1lbnRhbCBsb2FkaW5nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZFdvcmtmbG93UnVuRXZlbnRzKFxuICBydW5JZDogc3RyaW5nLFxuICBhZnRlckN1cnNvcj86IHN0cmluZ1xuKTogUHJvbWlzZTx7IGV2ZW50czogRXZlbnRbXTsgY3Vyc29yOiBzdHJpbmcgfCBudWxsIH0+IHtcbiAgY29uc3QgaW5jcmVtZW50YWwgPSBhZnRlckN1cnNvciAhPT0gdW5kZWZpbmVkO1xuICByZXR1cm4gdHJhY2UoXG4gICAgaW5jcmVtZW50YWwgPyAnd29ya2Zsb3cubG9hZE5ld0V2ZW50cycgOiAnd29ya2Zsb3cubG9hZEV2ZW50cycsXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dSdW5JZChydW5JZCksXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbG9hZGVkRXZlbnRzOiBFdmVudFtdID0gW107XG4gICAgICBsZXQgY3Vyc29yOiBzdHJpbmcgfCBudWxsID0gYWZ0ZXJDdXJzb3IgPz8gbnVsbDtcbiAgICAgIGxldCBoYXNNb3JlID0gdHJ1ZTtcbiAgICAgIGxldCBwYWdlc0xvYWRlZCA9IDA7XG5cbiAgICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gICAgICBjb25zdCBsb2FkU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgd2hpbGUgKGhhc01vcmUpIHtcbiAgICAgICAgLy8gVE9ETzogd2UncmUgY3VycmVudGx5IGxvYWRpbmcgYWxsIHRoZSBkYXRhIHdpdGggcmVzb2x2ZVJlZiBiZWhhdmlvdXIuIFdlIG5lZWQgdG8gdXBkYXRlIHRoaXNcbiAgICAgICAgLy8gdG8gbGF6eWxvYWQgdGhlIGRhdGEgZnJvbSB0aGUgd29ybGQgaW5zdGVhZCBzbyB0aGF0IHdlIGNhbiBvcHRpbWl6ZSBhbmQgbWFrZSB0aGUgZXZlbnQgbG9nIGxvYWRpbmdcbiAgICAgICAgLy8gbXVjaCBmYXN0ZXIgYW5kIG1lbW9yeSBlZmZpY2llbnRcbiAgICAgICAgY29uc3QgcGFnZVN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB3b3JsZC5ldmVudHMubGlzdCh7XG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgICAgc29ydE9yZGVyOiAnYXNjJyxcbiAgICAgICAgICAgIGN1cnNvcjogY3Vyc29yID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBsb2FkZWRFdmVudHMucHVzaCguLi5yZXNwb25zZS5kYXRhKTtcbiAgICAgICAgaGFzTW9yZSA9IHJlc3BvbnNlLmhhc01vcmU7XG4gICAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvcjtcbiAgICAgICAgcGFnZXNMb2FkZWQrKztcblxuICAgICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdMb2FkZWQgZXZlbnQgcGFnZScsIHtcbiAgICAgICAgICB3b3JrZmxvd1J1bklkOiBydW5JZCxcbiAgICAgICAgICBpbmNyZW1lbnRhbCxcbiAgICAgICAgICBwYWdlOiBwYWdlc0xvYWRlZCxcbiAgICAgICAgICBwYWdlRXZlbnRzOiByZXNwb25zZS5kYXRhLmxlbmd0aCxcbiAgICAgICAgICB0b3RhbEV2ZW50czogbG9hZGVkRXZlbnRzLmxlbmd0aCxcbiAgICAgICAgICBoYXNNb3JlLFxuICAgICAgICAgIHBhZ2VNczogRGF0ZS5ub3coKSAtIHBhZ2VTdGFydCxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJ1bnRpbWVMb2dnZXIuZGVidWcoJ0V2ZW50IGxvYWQgY29tcGxldGUnLCB7XG4gICAgICAgIHdvcmtmbG93UnVuSWQ6IHJ1bklkLFxuICAgICAgICBpbmNyZW1lbnRhbCxcbiAgICAgICAgdG90YWxFdmVudHM6IGxvYWRlZEV2ZW50cy5sZW5ndGgsXG4gICAgICAgIHBhZ2VzTG9hZGVkLFxuICAgICAgICB0b3RhbE1zOiBEYXRlLm5vdygpIC0gbG9hZFN0YXJ0LFxuICAgICAgfSk7XG5cbiAgICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFdmVudHNDb3VudChsb2FkZWRFdmVudHMubGVuZ3RoKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93RXZlbnRzUGFnZXNMb2FkZWQocGFnZXNMb2FkZWQpLFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB7IGV2ZW50czogbG9hZGVkRXZlbnRzLCBjdXJzb3IgfTtcbiAgICB9XG4gICk7XG59XG5cbi8qKlxuICogQ09SUyBoZWFkZXJzIGZvciBoZWFsdGggY2hlY2sgcmVzcG9uc2VzLlxuICogQWxsb3dzIHRoZSBvYnNlcnZhYmlsaXR5IFVJIHRvIGNoZWNrIGVuZHBvaW50IGhlYWx0aCBmcm9tIGEgZGlmZmVyZW50IG9yaWdpbi5cbiAqL1xuY29uc3QgSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyA9IHtcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnOiAnUE9TVCwgT1BUSU9OUywgR0VULCBIRUFEJyxcbiAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOiAnQ29udGVudC1UeXBlJyxcbn07XG5cbi8qKlxuICogV3JhcHMgYSByZXF1ZXN0L3Jlc3BvbnNlIGhhbmRsZXIgYW5kIGFkZHMgYSBoZWFsdGggY2hlY2sgXCJtb2RlXCJcbiAqIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhIGBfX2hlYWx0aGAgcXVlcnkgcGFyYW1ldGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEhlYWx0aENoZWNrKFxuICBoYW5kbGVyOiAocmVxOiBSZXF1ZXN0KSA9PiBQcm9taXNlPFJlc3BvbnNlPixcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4ge1xuICByZXR1cm4gYXN5bmMgKHJlcTogUmVxdWVzdCkgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCk7XG4gICAgY29uc3QgaXNIZWFsdGhDaGVjayA9IHVybC5zZWFyY2hQYXJhbXMuaGFzKCdfX2hlYWx0aCcpO1xuICAgIGlmIChpc0hlYWx0aENoZWNrKSB7XG4gICAgICAvLyBIYW5kbGUgQ09SUyBwcmVmbGlnaHQgZm9yIGhlYWx0aCBjaGVja1xuICAgICAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKG51bGwsIHtcbiAgICAgICAgICBzdGF0dXM6IDIwNCxcbiAgICAgICAgICBoZWFkZXJzOiBIRUFMVEhfQ0hFQ0tfQ09SU19IRUFERVJTLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBoZWFsdGh5OiB0cnVlLFxuICAgICAgICAgIGVuZHBvaW50OiB1cmwucGF0aG5hbWUsXG4gICAgICAgICAgc3BlY1ZlcnNpb246IHdvcmxkU3BlY1ZlcnNpb24gPz8gU1BFQ19WRVJTSU9OX0NVUlJFTlQsXG4gICAgICAgICAgd29ya2Zsb3dDb3JlVmVyc2lvbixcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBzdGF0dXM6IDIwMCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgLi4uSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyxcbiAgICAgICAgICB9LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgaGFuZGxlcihyZXEpO1xuICB9O1xufVxuXG4vKipcbiAqIFF1ZXVlcyBhIG1lc3NhZ2UgdG8gdGhlIHNwZWNpZmllZCBxdWV1ZSB3aXRoIHRyYWNpbmcuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBxdWV1ZU1lc3NhZ2UoXG4gIHdvcmxkOiBXb3JsZCxcbiAgLi4uYXJnczogUGFyYW1ldGVyczx0eXBlb2Ygd29ybGQucXVldWU+XG4pIHtcbiAgY29uc3QgcXVldWVOYW1lID0gYXJnc1swXTtcbiAgYXdhaXQgdHJhY2UoXG4gICAgJ3F1ZXVlLnB1Ymxpc2gnLFxuICAgIHtcbiAgICAgIC8vIFN0YW5kYXJkIE9URUwgbWVzc2FnaW5nIGNvbnZlbnRpb25zXG4gICAgICBhdHRyaWJ1dGVzOiB7XG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdTeXN0ZW0oJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nRGVzdGluYXRpb25OYW1lKHF1ZXVlTmFtZSksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdPcGVyYXRpb25UeXBlKCdwdWJsaXNoJyksXG4gICAgICAgIC8vIFBlZXIgc2VydmljZSBmb3IgRGF0YWRvZyBzZXJ2aWNlIG1hcHNcbiAgICAgICAgLi4uQXR0cmlidXRlLlBlZXJTZXJ2aWNlKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5ScGNTZXJ2aWNlKCd2cXMnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY01ldGhvZCgncHVibGlzaCcpLFxuICAgICAgfSxcbiAgICAgIGtpbmQ6IGF3YWl0IGdldFNwYW5LaW5kKCdQUk9EVUNFUicpLFxuICAgIH0sXG4gICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgIGNvbnN0IHsgbWVzc2FnZUlkIH0gPSBhd2FpdCB3b3JsZC5xdWV1ZSguLi5hcmdzKTtcbiAgICAgIGlmIChtZXNzYWdlSWQpIHtcbiAgICAgICAgc3Bhbj8uc2V0QXR0cmlidXRlcyhBdHRyaWJ1dGUuTWVzc2FnaW5nTWVzc2FnZUlkKG1lc3NhZ2VJZCkpO1xuICAgICAgfVxuICAgIH1cbiAgKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBxdWV1ZSBvdmVyaGVhZCB0aW1lIGluIG1pbGxpc2Vjb25kcyBmb3IgYSBnaXZlbiBtZXNzYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVldWVPdmVyaGVhZChtZXNzYWdlOiB7IHJlcXVlc3RlZEF0PzogRGF0ZSB9KSB7XG4gIGlmICghbWVzc2FnZS5yZXF1ZXN0ZWRBdCkgcmV0dXJuO1xuICB0cnkge1xuICAgIHJldHVybiBBdHRyaWJ1dGUuUXVldWVPdmVyaGVhZE1zKFxuICAgICAgRGF0ZS5ub3coKSAtIG1lc3NhZ2UucmVxdWVzdGVkQXQuZ2V0VGltZSgpXG4gICAgKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyBhIG1lbW9pemVkIGFjY2Vzc29yIGZvciB0aGUgcGVyLXJ1biBBRVMtMjU2IGVuY3J5cHRpb24ga2V5LlxuICpcbiAqIFRoZSBmaXJzdCBjYWxsIHJlc29sdmVzIHRoZSBrZXkgdmlhIGB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuYCAod2hpY2hcbiAqIG1heSBkbyBIS0RGIGRlcml2YXRpb24gbG9jYWxseSBvbiBWZXJjZWwsIG9yIGEgbmV0d29yayBmZXRjaCBmcm9tXG4gKiBleHRlcm5hbCBjb250ZXh0cykgYW5kIGltcG9ydHMgaXQgYXMgYSBgQ3J5cHRvS2V5YDsgc3Vic2VxdWVudCBjYWxsc1xuICogYXdhaXQgdGhlIHNhbWUgY2FjaGVkIHByb21pc2UuIElmIHRoZSB3b3JsZCBkb2Vzbid0IHN1cHBvcnQgZW5jcnlwdGlvblxuICogb3IgdGhlIHJ1biBoYXMgbm8ga2V5IGNvbmZpZ3VyZWQsIHRoZSBjYWNoZWQgdmFsdWUgaXMgYHVuZGVmaW5lZGAuXG4gKlxuICogVXNlZCBieSBzdGVwIC8gd29ya2Zsb3cgaGFuZGxlcnMgdG8gZGVmZXIgdGhlIChwb3RlbnRpYWxseSBleHBlbnNpdmUpXG4gKiBrZXkgZmV0Y2ggdW50aWwgdGhlIGZpcnN0IGNvZGUgcGF0aCB0aGF0IGFjdHVhbGx5IG5lZWRzIGl0IOKAlCB0eXBpY2FsbHlcbiAqIGlucHV0IGh5ZHJhdGlvbiBvbiB0aGUgc3VjY2VzcyBwYXRoLCBvciBlcnJvciBkZWh5ZHJhdGlvbiBvbiBhIGZhaWx1cmVcbiAqIHBhdGguIEJvdGggcGF0aHMgY2FuIHJhY2UtY2FsbCB0aGUgYWNjZXNzb3Igd2l0aG91dCB0cmlnZ2VyaW5nIGR1cGxpY2F0ZVxuICogZmV0Y2hlcy5cbiAqXG4gKiBFcnJvcnMgdGhyb3duIGJ5IGBnZXRFbmNyeXB0aW9uS2V5Rm9yUnVuYCBwcm9wYWdhdGUgdG8gZXZlcnkgY2FsbGVyXG4gKiAodGhlIGNhY2hlZCBwcm9taXNlIHJlamVjdHMpLiBUaGlzIGlzIGludGVudGlvbmFsOiB3aGVuIGVuY3J5cHRpb24gaXNcbiAqIGNvbmZpZ3VyZWQsIHdlIG5ldmVyIHdhbnQgdG8gc2lsZW50bHkgZmFsbCBiYWNrIHRvIHBsYWludGV4dFxuICogc2VyaWFsaXphdGlvbi4gQSBwcm9wYWdhdGVkIGVycm9yIGluIGFuIGV2ZW50LWVtaXNzaW9uIHBhdGggbGVhdmVzIHRoZVxuICogb3V0ZXIgdHJ5L2NhdGNoIHRvIGxvZyBhbmQgc3VyZmFjZSB0aGUgaXNzdWU7IHRoZSBxdWV1ZSdzIHJlZGVsaXZlcnlcbiAqIHNlbWFudGljcyB3aWxsIHJldHJ5IHRoZSBrZXkgZmV0Y2ggb24gdGhlIG5leHQgYXR0ZW1wdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lbW9pemVFbmNyeXB0aW9uS2V5KFxuICB3b3JsZDogV29ybGQsXG4gIHJ1bk9ySWQ6IFdvcmtmbG93UnVuIHwgc3RyaW5nXG4pOiAoKSA9PiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4ge1xuICBsZXQgY2FjaGVkOiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgaWYgKCFjYWNoZWQpIHtcbiAgICAgIGNhY2hlZCA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIC8vIFRoZSBgZ2V0RW5jcnlwdGlvbktleUZvclJ1bmAgb3ZlcmxvYWQgc2V0IHRha2VzIGVpdGhlciBhXG4gICAgICAgIC8vIGBXb3JrZmxvd1J1bmAgb3IgYSBgcnVuSWQ6IHN0cmluZ2AgKHdpdGggb3B0aW9uYWwgY29udGV4dCkuIEJyYW5jaFxuICAgICAgICAvLyBoZXJlIHNvIFR5cGVTY3JpcHQgcGlja3MgdGhlIHJpZ2h0IG92ZXJsb2FkIGZvciBlYWNoIHNoYXBlLlxuICAgICAgICBjb25zdCByYXdLZXkgPVxuICAgICAgICAgIHR5cGVvZiBydW5PcklkID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4ocnVuT3JJZClcbiAgICAgICAgICAgIDogYXdhaXQgd29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bj8uKHJ1bk9ySWQpO1xuICAgICAgICByZXR1cm4gcmF3S2V5ID8gYXdhaXQgaW1wb3J0S2V5KHJhd0tleSkgOiB1bmRlZmluZWQ7XG4gICAgICB9KSgpO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGVkO1xuICB9O1xufVxuIl19
1025
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixlQUFlLEVBQ2Ysa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFZMUIsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixtQkFBbUIsRUFDbkIsd0JBQXdCLEVBQ3hCLHlCQUF5QixFQUN6QixxQkFBcUIsRUFDckIsZ0JBQWdCLEVBQ2hCLHFCQUFxQixFQUNyQixvQkFBb0IsRUFDcEIsbUJBQW1CLEdBQ3BCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ25FLE9BQU8sRUFDTCxvQkFBb0IsR0FFckIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLHNDQUFzQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbkQsd0RBQXdEO0FBQ3hELE1BQU0sNEJBQTRCLEdBQUcsTUFBTSxDQUFDO0FBRTVDOzs7O0dBSUc7QUFDSCxNQUFNLDBCQUEwQixHQUFHLHNCQUFzQixDQUFDO0FBRTFEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLFlBQW9CLEVBQ3BCLFNBQWtCO0lBRWxCLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsWUFB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O0dBR0c7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLEtBQVksRUFDWixPQUE2QjtJQUU3QixJQUFJLE1BQW1ELENBQUM7SUFDeEQsT0FBTyxHQUFHLEVBQUU7UUFDVixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLEdBQUcsdUJBQXVCLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ25ELENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgUHJlY29uZGl0aW9uRmFpbGVkRXJyb3IsXG4gIFJVTl9FUlJPUl9DT0RFUyxcbiAgV29ya2Zsb3dXb3JsZEVycm9yLFxufSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB0eXBlIHtcbiAgQ3JlYXRlRXZlbnRQYXJhbXMsXG4gIENyZWF0ZUV2ZW50UmVxdWVzdCxcbiAgRXZlbnQsXG4gIEV2ZW50UmVzdWx0LFxuICBIZWFsdGhDaGVja1BheWxvYWQsXG4gIFJ1bkRpc3BhdGNoQ29udGV4dCxcbiAgVmFsaWRRdWV1ZU5hbWUsXG4gIFdvcmtmbG93UnVuLFxuICBXb3JsZCxcbn0gZnJvbSAnQHdvcmtmbG93L3dvcmxkJztcbmltcG9ydCB7XG4gIEZJUlNUX0VWRU5UX1NMT1QsXG4gIGdldFF1ZXVlVG9waWNQcmVmaXgsXG4gIEhlYWx0aENoZWNrUGF5bG9hZFNjaGVtYSxcbiAgSE9PS19SRVNVTUVfSU5QVVRfVkVSU0lPTixcbiAgUk9PVF9SVU5fSURfQVRUUklCVVRFLFxuICByZXF1aXJlRXZlbnRTbG90LFxuICByZXNvbHZlUXVldWVOYW1lc3BhY2UsXG4gIFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICBTUEVDX1ZFUlNJT05fTEVHQUNZLFxufSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgbW9ub3RvbmljRmFjdG9yeSB9IGZyb20gJ3VsaWQnO1xuaW1wb3J0IHsgcnVudGltZUxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBieXRlc1RvQmFzZTY0LCBkZXJpdmVSdW5LZXlQYWlyIH0gZnJvbSAnLi4vc2VhbGVkLWJveC5qcyc7XG5pbXBvcnQge1xuICBkZXJpdmVSdW5QYXlsb2FkS2V5cyxcbiAgdHlwZSBQYXlsb2FkS2V5LFxufSBmcm9tICcuLi9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0ICogYXMgQXR0cmlidXRlIGZyb20gJy4uL3RlbGVtZXRyeS9zZW1hbnRpYy1jb252ZW50aW9ucy5qcyc7XG5pbXBvcnQgeyBnZXRTcGFuS2luZCwgdHJhY2UgfSBmcm9tICcuLi90ZWxlbWV0cnkuanMnO1xuaW1wb3J0IHsgdmVyc2lvbiBhcyB3b3JrZmxvd0NvcmVWZXJzaW9uIH0gZnJvbSAnLi4vdmVyc2lvbi5qcyc7XG5pbXBvcnQgeyBnZXRXb3JsZExhenkgfSBmcm9tICcuL2dldC13b3JsZC1sYXp5LmpzJztcblxuLyoqIERlZmF1bHQgdGltZW91dCBmb3IgaGVhbHRoIGNoZWNrcyBpbiBtaWxsaXNlY29uZHMgKi9cbmNvbnN0IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQgPSAzMF8wMDA7XG5cbi8qKlxuICogUGF0dGVybiBmb3Igc2FmZSB3b3JrZmxvdyBuYW1lcy4gT25seSBhbGxvd3MgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsXG4gKiB1bmRlcnNjb3JlcywgaHlwaGVucywgZG90cywgZm9yd2FyZCBzbGFzaGVzIChmb3IgbmFtZXNwYWNlZCB3b3JrZmxvd3MpLFxuICogYW5kIGF0IHNpZ25zIChmb3Igc2NvcGVkIHBhY2thZ2VzKS5cbiAqL1xuY29uc3QgU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4gPSAvXlthLXpBLVowLTlfXFwtLi9AXSskLztcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYSB3b3JrZmxvdyBuYW1lIGFuZCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHF1ZXVlIG5hbWUuXG4gKiBFbnN1cmVzIHRoZSB3b3JrZmxvdyBuYW1lIG9ubHkgY29udGFpbnMgc2FmZSBjaGFyYWN0ZXJzIGJlZm9yZVxuICogaW50ZXJwb2xhdGluZyBpdCBpbnRvIHRoZSBxdWV1ZSBuYW1lIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFdvcmtmbG93UXVldWVOYW1lKFxuICB3b3JrZmxvd05hbWU6IHN0cmluZyxcbiAgbmFtZXNwYWNlPzogc3RyaW5nXG4pOiBWYWxpZFF1ZXVlTmFtZSB7XG4gIGlmICghU0FGRV9XT1JLRkxPV19OQU1FX1BBVFRFUk4udGVzdCh3b3JrZmxvd05hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEludmFsaWQgd29ya2Zsb3cgbmFtZSBcIiR7d29ya2Zsb3dOYW1lfVwiOiBtdXN0IG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgdW5kZXJzY29yZXMsIGh5cGhlbnMsIGRvdHMsIGZvcndhcmQgc2xhc2hlcywgb3IgYXQgc2lnbnNgXG4gICAgKTtcbiAgfVxuICBjb25zdCBwcmVmaXggPSBnZXRRdWV1ZVRvcGljUHJlZml4KFxuICAgICd3b3JrZmxvdycsXG4gICAgcmVzb2x2ZVF1ZXVlTmFtZXNwYWNlKG5hbWVzcGFjZSlcbiAgKTtcbiAgcmV0dXJuIGAke3ByZWZpeH0ke3dvcmtmbG93TmFtZX1gIGFzIFZhbGlkUXVldWVOYW1lO1xufVxuXG5jb25zdCBnZW5lcmF0ZUlkID0gbW9ub3RvbmljRmFjdG9yeSgpO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIHN0cmVhbSBuYW1lIGZvciBhIGhlYWx0aCBjaGVjayB3aXRoIHRoZSBnaXZlbiBjb3JyZWxhdGlvbiBJRC5cbiAqL1xuZnVuY3Rpb24gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGNvcnJlbGF0aW9uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgX19oZWFsdGhfY2hlY2tfXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBhIGhlYWx0aCBjaGVjayBvcGVyYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tSZXN1bHQge1xuICBoZWFsdGh5OiBib29sZWFuO1xuICAvKiogRXJyb3IgbWVzc2FnZSBpZiBoZWFsdGggY2hlY2sgZmFpbGVkICovXG4gIGVycm9yPzogc3RyaW5nO1xuICAvKiogTGF0ZW5jeSBpZiB0aGUgaGVhbHRoIGNoZWNrIHdhcyBzdWNjZXNzZnVsICovXG4gIGxhdGVuY3lNcz86IG51bWJlcjtcbiAgLyoqIFNwZWMgdmVyc2lvbiBvZiB0aGUgcmVzcG9uZGluZyBkZXBsb3ltZW50ICovXG4gIHNwZWNWZXJzaW9uPzogbnVtYmVyO1xuICAvKipcbiAgICogYEB3b3JrZmxvdy9jb3JlYCB2ZXJzaW9uIG9mIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQsIHVzZWQgZm9yXG4gICAqIGNhcGFiaWxpdHkgZGV0ZWN0aW9uIChzZWUgYGdldFJ1bkNhcGFiaWxpdGllc2ApLiBPbWl0dGVkIHdoZW4gdGhlXG4gICAqIHJlc3BvbmRpbmcgZGVwbG95bWVudCBkaWQgbm90IHByb3ZpZGUgdGhlIGZpZWxkIGFzIGEgc3RyaW5nOlxuICAgKiBmb3IgZXhhbXBsZSwgYW4gb2xkZXIgYEB3b3JrZmxvdy9jb3JlYCB0aGF0IHByZWRhdGVzIHRoaXMgZmllbGQsXG4gICAqIG9yIGEgbm9uLUpTT04gcGxhaW4tdGV4dCBoZWFsdGggcmVzcG9uc2UuXG4gICAqL1xuICB3b3JrZmxvd0NvcmVWZXJzaW9uPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHRhcmdldCBydW4ncyBYMjU1MTkgcHVibGljIGtleSAoYmFzZTY0KSwgcmV0dXJuZWQgb25seSB3aGVuIHRoZSBwcm9iZVxuICAgKiBjYXJyaWVkIGEgYHJ1bklkYCBhbmQgdGhlIHJlc3BvbmRpbmcgZGVwbG95bWVudCBoYXMgZW5jcnlwdGlvbiBlbmFibGVkLlxuICAgKlxuICAgKiBMZXRzIGEgY3Jvc3MtZGVwbG95bWVudCBgc3RhcnQoKWAgc2VhbCB0aGUgd29ya2Zsb3cgYXJndW1lbnRzIHVzaW5nIGFcbiAgICogcmVzcG9uc2UgaXQgd2FzIGFscmVhZHkgd2FpdGluZyBvbiwgaW5zdGVhZCBvZiBtYWtpbmcgYSBzZXBhcmF0ZVxuICAgKiBrZXktbG9va3VwIHJlcXVlc3QuXG4gICAqL1xuICBlbmNyeXB0aW9uUHVibGljS2V5Pzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHJlc3BvbmRpbmcgZGVwbG95bWVudCdzIGBIT09LX1JFU1VNRV9JTlBVVF9WRVJTSU9OYDogdGhlIHByb3RvY29sXG4gICAqIHZlcnNpb24gYXQgd2hpY2ggdGhlICpjb25zdW1lciogKHF1ZXVlLW1lc3NhZ2UgdGFyZ2V0KSBtYXRlcmlhbGl6ZXMgdGhlXG4gICAqIGBob29rX3JlY2VpdmVkYCBldmVudCBmcm9tIGBob29rSW5wdXRgIG9uIHJlcGxheS4gQSBjcm9zcy1kZXBsb3ltZW50XG4gICAqIGBzdGFydCgpYCBzdGFtcHMgdGhlICp0YXJnZXQncyogdmFsdWUgKG5vdCB0aGUgY2FsbGVyJ3MpIGludG8gdGhlIG5ld1xuICAgKiBydW4ncyBgZXhlY3V0aW9uQ29udGV4dC5ob29rUmVzdW1lSW5wdXRWZXJzaW9uYC4gQ3VycmVudCBwcm9kdWNlcnMgd3JpdGVcbiAgICogdGhlIGV2ZW50IGR1cmFibHkgYmVmb3JlIHB1Ymxpc2hpbmcgdGhlIHdha2UgYW5kIGRvIG5vdCByZWFkIHRoZSBtYXJrZXI7XG4gICAqIE9MREVSIHByb2R1Y2VycyBzdGlsbCBnYXRlIHRoZWlyIGxhenkgcGF0aCBvbiBpdCwgc28gaXQga2VlcHMgYmVpbmdcbiAgICogc3RhbXBlZC4gT21pdHRlZCB3aGVuIHRoZSByZXNwb25kaW5nIGRlcGxveW1lbnQgcHJlZGF0ZXMgdGhpcyBmaWVsZCxcbiAgICogd2hpY2ggZmFpbHMgdGhhdCBnYXRlIGNsb3NlZC5cbiAgICovXG4gIGhvb2tSZXN1bWVJbnB1dFZlcnNpb24/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBtZXNzYWdlIGlzIGEgaGVhbHRoIGNoZWNrIHBheWxvYWQuXG4gKiBJZiBzbywgcmV0dXJucyB0aGUgcGFyc2VkIHBheWxvYWQuIE90aGVyd2lzZSByZXR1cm5zIHVuZGVmaW5lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlSGVhbHRoQ2hlY2tQYXlsb2FkKFxuICBtZXNzYWdlOiB1bmtub3duXG4pOiBIZWFsdGhDaGVja1BheWxvYWQgfCB1bmRlZmluZWQge1xuICBjb25zdCByZXN1bHQgPSBIZWFsdGhDaGVja1BheWxvYWRTY2hlbWEuc2FmZVBhcnNlKG1lc3NhZ2UpO1xuICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4gcmVzdWx0LmRhdGE7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBkZXRlcm1pbmlzdGljIGZha2UgcnVuSWQgZm9yIGhlYWx0aCBjaGVjayBzdHJlYW1zLlxuICogQm90aCB0aGUgd3JpdGVyIChoYW5kbGVIZWFsdGhDaGVja01lc3NhZ2UpIGFuZCByZWFkZXIgKGhlYWx0aENoZWNrKSBkZXJpdmVcbiAqIHRoZSBzYW1lIHJ1bklkIGZyb20gdGhlIGNvcnJlbGF0aW9uSWQgc28gdGhhdCBpbXBsZW1lbnRhdGlvbnMgdGhhdCBzY29wZVxuICogc3RyZWFtIHJlYWRzIGJ5IHJ1bklkIHN0aWxsIHdvcmsgY29ycmVjdGx5LlxuICovXG5mdW5jdGlvbiBnZW5lcmF0ZUhlYWx0aENoZWNrUnVuSWQoY29ycmVsYXRpb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGB3cnVuX2hjXyR7Y29ycmVsYXRpb25JZH1gO1xufVxuXG4vKipcbiAqIEhhbmRsZXMgYSBoZWFsdGggY2hlY2sgbWVzc2FnZSBieSB3cml0aW5nIHRoZSByZXN1bHQgdG8gdGhlIHdvcmxkJ3Mgc3RyZWFtLlxuICogVGhlIGNhbGxlciBjYW4gbGlzdGVuIHRvIHRoaXMgc3RyZWFtIHRvIGdldCB0aGUgaGVhbHRoIGNoZWNrIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSBoZWFsdGhDaGVjayAtIFRoZSBwYXJzZWQgaGVhbHRoIGNoZWNrIHBheWxvYWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZUhlYWx0aENoZWNrTWVzc2FnZShcbiAgaGVhbHRoQ2hlY2s6IEhlYWx0aENoZWNrUGF5bG9hZCxcbiAgd29ybGRTcGVjVmVyc2lvbj86IG51bWJlclxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gIGNvbnN0IHN0cmVhbU5hbWUgPSBnZXRIZWFsdGhDaGVja1N0cmVhbU5hbWUoaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCk7XG5cbiAgLy8gV2hlbiB0aGUgcHJvYmUgbmFtZXMgYSBydW4gdGhlIGNhbGxlciBpcyBhYm91dCB0byBjcmVhdGUsIHB1Ymxpc2ggdGhhdFxuICAvLyBydW4ncyBwdWJsaWMga2V5LiBXZSBhcmUgZXhlY3V0aW5nIGluc2lkZSB0aGUgdGFyZ2V0IGRlcGxveW1lbnQsIHNvIGl0c1xuICAvLyBrZXkgbWF0ZXJpYWwgaXMgYXZhaWxhYmxlIGxvY2FsbHkgKG5vIEFQSSBjYWxsKSwgYW5kIHRoZSBjYWxsZXIgY2FuIHRoZW5cbiAgLy8gc2VhbCB0aGUgd29ya2Zsb3cgYXJndW1lbnRzIHN0cmFpZ2h0IGZyb20gdGhpcyByZXNwb25zZSByYXRoZXIgdGhhblxuICAvLyBtYWtpbmcgYSBzZXBhcmF0ZSBrZXktbG9va3VwIHJlcXVlc3QuXG4gIC8vXG4gIC8vIE9ubHkgYSAqcHVibGljKiBrZXkgbWF5IHRyYXZlbCB0aGlzIHdheTogdGhlIHByb2JlIHJlc3BvbnNlIHN0cmVhbSBpc1xuICAvLyBkZWxpYmVyYXRlbHkgdW5hdXRoZW50aWNhdGVkLCBzbyBhbnl0aGluZyBzZWNyZXQgd291bGQgYmUgZXhwb3NlZC5cbiAgLy8gQmVzdC1lZmZvcnQ6IGEgZmFpbHVyZSBoZXJlIG11c3Qgbm90IGZhaWwgdGhlIGhlYWx0aCBjaGVjayBpdHNlbGYsIHdoaWNoXG4gIC8vIGNhbGxlcnMgYWxzbyByZWx5IG9uIGZvciBwbGFpbiBjYXBhYmlsaXR5IGRldGVjdGlvbi5cbiAgbGV0IGVuY3J5cHRpb25QdWJsaWNLZXk6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaWYgKGhlYWx0aENoZWNrLnJ1bklkKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJhd0tleSA9IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihoZWFsdGhDaGVjay5ydW5JZCk7XG4gICAgICBpZiAocmF3S2V5KSB7XG4gICAgICAgIGVuY3J5cHRpb25QdWJsaWNLZXkgPSBieXRlc1RvQmFzZTY0KFxuICAgICAgICAgIChhd2FpdCBkZXJpdmVSdW5LZXlQYWlyKHJhd0tleSkpLnB1YmxpY0tleVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcnVudGltZUxvZ2dlci53YXJuKFxuICAgICAgICAnSGVhbHRoIGNoZWNrIGNvdWxkIG5vdCBkZXJpdmUgYSBydW4gcHVibGljIGtleTsgdGhlIGNhbGxlciB3aWxsIGZhbGwgYmFjayB0byBhIGtleSBsb29rdXAnLFxuICAgICAgICB7XG4gICAgICAgICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIGhlYWx0aHk6IHRydWUsXG4gICAgY29ycmVsYXRpb25JZDogaGVhbHRoQ2hlY2suY29ycmVsYXRpb25JZCxcbiAgICBzcGVjVmVyc2lvbjogd29ybGRTcGVjVmVyc2lvbiA/PyBTUEVDX1ZFUlNJT05fQ1VSUkVOVCxcbiAgICB3b3JrZmxvd0NvcmVWZXJzaW9uLFxuICAgIC8vIFdlIGFyZSBleGVjdXRpbmcgaW5zaWRlIHRoZSB0YXJnZXQgZGVwbG95bWVudCwgc28gdGhpcyBjb25zdGFudCByZWZsZWN0c1xuICAgIC8vIHRoZSAqY29uc3VtZXIncyogaG9vay1yZXN1bWUgcHJvdG9jb2wgdmVyc2lvbiwgZXhhY3RseSB3aGF0IGFcbiAgICAvLyBjcm9zcy1kZXBsb3ltZW50IGNhbGxlciBuZWVkcyB0byBnYXRlIGl0cyBwYXJhbGxlbCByZXN1bWUgcGF0aCBvbi5cbiAgICBob29rUmVzdW1lSW5wdXRWZXJzaW9uOiBIT09LX1JFU1VNRV9JTlBVVF9WRVJTSU9OLFxuICAgIC4uLihlbmNyeXB0aW9uUHVibGljS2V5ID8geyBlbmNyeXB0aW9uUHVibGljS2V5IH0gOiB7fSksXG4gICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICB9KTtcbiAgLy8gVXNlIGEgZGV0ZXJtaW5pc3RpYyBmYWtlIHJ1bklkIGRlcml2ZWQgZnJvbSB0aGUgY29ycmVsYXRpb25JZCBzbyB0aGF0XG4gIC8vIHRoZSByZWFkZXIgc2lkZSBwcm9kdWNlcyB0aGUgc2FtZSB2YWx1ZS5cbiAgY29uc3QgZmFrZVJ1bklkID0gZ2VuZXJhdGVIZWFsdGhDaGVja1J1bklkKGhlYWx0aENoZWNrLmNvcnJlbGF0aW9uSWQpO1xuICBhd2FpdCB3b3JsZC5zdHJlYW1zLndyaXRlKGZha2VSdW5JZCwgc3RyZWFtTmFtZSwgcmVzcG9uc2UpO1xuICBhd2FpdCB3b3JsZC5zdHJlYW1zLmNsb3NlKGZha2VSdW5JZCwgc3RyZWFtTmFtZSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tPcHRpb25zIHtcbiAgLyoqIFRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGhlYWx0aCBjaGVjayByZXNwb25zZS4gRGVmYXVsdDogMzAwMDAgKDMwcykgKi9cbiAgdGltZW91dD86IG51bWJlcjtcbiAgLyoqIERlcGxveW1lbnQgSUQgdG8gc2VuZCB0aGUgaGVhbHRoIGNoZWNrIHRvLiBGYWxscyBiYWNrIHRvIHByb2Nlc3MuZW52LlZFUkNFTF9ERVBMT1lNRU5UX0lELiAqL1xuICBkZXBsb3ltZW50SWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgcnVuIGlkIHRoZSBjYWxsZXIgaXMgYWJvdXQgdG8gY3JlYXRlLiBXaGVuIHNldCwgdGhlIHJlc3BvbmRpbmdcbiAgICogZGVwbG95bWVudCBkZXJpdmVzIHRoYXQgcnVuJ3MgcHVibGljIGtleSBsb2NhbGx5IGFuZCByZXR1cm5zIGl0IGFzXG4gICAqIGBlbmNyeXB0aW9uUHVibGljS2V5YCwgbGV0dGluZyBhIGNyb3NzLWRlcGxveW1lbnQgYHN0YXJ0KClgIHNlYWwgdGhlXG4gICAqIHdvcmtmbG93IGFyZ3VtZW50cyB3aXRob3V0IGEgc2VwYXJhdGUga2V5IGxvb2t1cC5cbiAgICovXG4gIHJ1bklkPzogc3RyaW5nO1xuICAvKipcbiAgICogUXVldWUgbmFtZXNwYWNlIG9mIHRoZSB0YXJnZXQgZGVwbG95bWVudCAoZS5nLiBgJ2V2ZSdgIGZvciB0b3BpY3MgbGlrZVxuICAgKiBgX19ldmVfd2tmX3dvcmtmbG93XypgKS4gRmFsbHMgYmFjayB0byBgV09SS0ZMT1dfUVVFVUVfTkFNRVNQQUNFYCBpbiB0aGVcbiAgICogY2FsbGluZyBwcm9jZXNzLiBDcm9zcy1jb250ZXh0IGNhbGxlcnMgKGUuZy4gdGhlIG9ic2VydmFiaWxpdHlcbiAgICogZGFzaGJvYXJkKSBtdXN0IHBhc3MgdGhlIHRhcmdldCBkZXBsb3ltZW50J3MgbmFtZXNwYWNlIGV4cGxpY2l0bHk6XG4gICAqIHRoZSBlbnYgZmFsbGJhY2sgcmVzb2x2ZXMgaW4gdGhlIGNhbGxlcidzIHByb2Nlc3MsIGFuZCBhIG1lc3NhZ2VcbiAgICogcHVibGlzaGVkIHRvIGEgbWlzbWF0Y2hlZCB0b3BpYyBoYXMgbm8gY29uc3VtZXIsIHNvIHRoZSBjaGVjayB3b3VsZFxuICAgKiBhbHdheXMgdGltZSBvdXQuXG4gICAqL1xuICBuYW1lc3BhY2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUGVyZm9ybXMgYSBoZWFsdGggY2hlY2sgYnkgc2VuZGluZyBhIG1lc3NhZ2UgdGhyb3VnaCB0aGUgcXVldWUgcGlwZWxpbmVcbiAqIGFuZCB2ZXJpZnlpbmcgaXQgaXMgcHJvY2Vzc2VkIGJ5IHRoZSBjb21iaW5lZCB3b3JrZmxvdyBlbmRwb2ludC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGJ5cGFzc2VzIERlcGxveW1lbnQgUHJvdGVjdGlvbiBvbiBWZXJjZWwgYmVjYXVzZSBpdCBnb2VzXG4gKiB0aHJvdWdoIHRoZSBxdWV1ZSBpbmZyYXN0cnVjdHVyZSByYXRoZXIgdGhhbiBkaXJlY3QgSFRUUC5cbiAqXG4gKiBAcGFyYW0gd29ybGQgLSBUaGUgV29ybGQgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgaGVhbHRoIGNoZWNrXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBoZWFsdGggY2hlY2tcbiAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIGhlYWx0aCBjaGVjayByZXN1bHRcbiAqL1xuLy8gUG9sbCBpbnRlcnZhbCBmb3IgaGVhbHRoIGNoZWNrIHJldHJpZXMgKG1zKVxuY29uc3QgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwgPSAxMDA7XG4vLyBQZXItcmVhZCB0aW1lb3V0IHRvIHByZXZlbnQgYmxvY2tpbmcgZm9yZXZlciBvbiBsb2NhbCB3b3JsZCdzIEV2ZW50RW1pdHRlclxuLy8gKHdoaWNoIGRvZXNuJ3Qgd29yayBhY3Jvc3MgcHJvY2Vzc2VzKVxuY29uc3QgSEVBTFRIX0NIRUNLX1JFQURfVElNRU9VVCA9IDUwMDtcblxuLyoqXG4gKiBSZWFkIGNodW5rcyBmcm9tIGEgc3RyZWFtIHdpdGggYSB0aW1lb3V0IHBlciByZWFkIG9wZXJhdGlvbi5cbiAqIFJldHVybnMgeyBjaHVua3MsIHRpbWVkT3V0IH0gd2hlcmUgdGltZWRPdXQgaW5kaWNhdGVzIGlmIGEgcmVhZCB0aW1lZCBvdXQuXG4gKi9cbi8qKlxuICogUmFjZSBhIHByb21pc2UgYWdhaW5zdCBhIGRlYWRsaW5lLiBSZWplY3RzIHdpdGggYSB0aW1lb3V0IGVycm9yIHdoZW4gdGhlXG4gKiBkZWFkbGluZSBlbGFwc2VzIGZpcnN0LiBVc2VkIHRvIGJvdW5kIGB3b3JsZC5zdHJlYW1zLmdldCgpYCBpbnNpZGUgdGhlXG4gKiBoZWFsdGgtY2hlY2sgcG9sbCBsb29wOiBzb21lIHdvcmxkcyBob2xkIHRoYXQgcmVxdWVzdCBvcGVuIHVudGlsIHRoZVxuICogc3RyZWFtIGhhcyBkYXRhIChlLmcuIHdvcmtmbG93LXNlcnZlciBob2xkcyB1bndyaXR0ZW4gc3RyZWFtcyBvcGVuIGZvclxuICogfjIgbWludXRlcyksIHdoaWNoIHdvdWxkIG90aGVyd2lzZSBibG93IHRocm91Z2ggdGhlIGNvbmZpZ3VyZWQgaGVhbHRoXG4gKiBjaGVjayB0aW1lb3V0LCBzaW5jZSB0aGUgYHdoaWxlYCBjb25kaXRpb24gaXMgb25seSByZS1jaGVja2VkIGJldHdlZW5cbiAqIGl0ZXJhdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIHdpdGhEZWFkbGluZTxUPihwcm9taXNlOiBQcm9taXNlPFQ+LCBtczogbnVtYmVyKTogUHJvbWlzZTxUPiB7XG4gIGxldCB0aW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xuICAgIHByb21pc2UsXG4gICAgbmV3IFByb21pc2U8bmV2ZXI+KChfLCByZWplY3QpID0+IHtcbiAgICAgIHRpbWVyID0gc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihgT3BlcmF0aW9uIHRpbWVkIG91dCBhZnRlciAke21zfW1zYCkpLFxuICAgICAgICBtc1xuICAgICAgKTtcbiAgICB9KSxcbiAgXSkuZmluYWxseSgoKSA9PiBjbGVhclRpbWVvdXQodGltZXIpKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZFN0cmVhbVdpdGhUaW1lb3V0KFxuICByZWFkZXI6IFJlYWRhYmxlU3RyZWFtRGVmYXVsdFJlYWRlcjxVaW50OEFycmF5PixcbiAgcmVhZFRpbWVvdXQ6IG51bWJlclxuKTogUHJvbWlzZTx7IGNodW5rczogVWludDhBcnJheVtdOyB0aW1lZE91dDogYm9vbGVhbiB9PiB7XG4gIGNvbnN0IGNodW5rczogVWludDhBcnJheVtdID0gW107XG4gIGxldCBkb25lID0gZmFsc2U7XG4gIGxldCB0aW1lZE91dCA9IGZhbHNlO1xuXG4gIHdoaWxlICghZG9uZSAmJiAhdGltZWRPdXQpIHtcbiAgICBjb25zdCByZWFkUHJvbWlzZSA9IHJlYWRlci5yZWFkKCk7XG4gICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZTx7IGRvbmU6IHRydWU7IHZhbHVlOiB1bmRlZmluZWQgfT4oXG4gICAgICAocmVzb2x2ZSkgPT5cbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgdGltZWRPdXQgPSB0cnVlO1xuICAgICAgICAgIHJlc29sdmUoeyBkb25lOiB0cnVlLCB2YWx1ZTogdW5kZWZpbmVkIH0pO1xuICAgICAgICB9LCByZWFkVGltZW91dClcbiAgICApO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtyZWFkUHJvbWlzZSwgdGltZW91dFByb21pc2VdKTtcbiAgICBkb25lID0gcmVzdWx0LmRvbmU7XG4gICAgaWYgKHJlc3VsdC52YWx1ZSkgY2h1bmtzLnB1c2gocmVzdWx0LnZhbHVlKTtcbiAgfVxuXG4gIHJldHVybiB7IGNodW5rcywgdGltZWRPdXQgfTtcbn1cblxuLyoqXG4gKiBQYXJzZSBhbmQgdmFsaWRhdGUgYSBoZWFsdGggY2hlY2sgcmVzcG9uc2UgZnJvbSBzdHJlYW0gY2h1bmtzLlxuICogUmV0dXJucyB0aGUgcGFyc2VkIHJlc3BvbnNlIG9yIG51bGwgaWYgaW52YWxpZC5cbiAqL1xuZnVuY3Rpb24gcGFyc2VIZWFsdGhDaGVja1Jlc3BvbnNlKGNodW5rczogVWludDhBcnJheVtdKToge1xuICBoZWFsdGh5OiBib29sZWFuO1xuICBzcGVjVmVyc2lvbj86IG51bWJlcjtcbiAgd29ya2Zsb3dDb3JlVmVyc2lvbj86IHN0cmluZztcbiAgZW5jcnlwdGlvblB1YmxpY0tleT86IHN0cmluZztcbn0gfCBudWxsIHtcbiAgaWYgKGNodW5rcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IHRvdGFsTGVuZ3RoID0gY2h1bmtzLnJlZHVjZSgoc3VtLCBjaHVuaykgPT4gc3VtICsgY2h1bmsubGVuZ3RoLCAwKTtcbiAgY29uc3QgY29tYmluZWQgPSBuZXcgVWludDhBcnJheSh0b3RhbExlbmd0aCk7XG4gIGxldCBvZmZzZXQgPSAwO1xuICBmb3IgKGNvbnN0IGNodW5rIG9mIGNodW5rcykge1xuICAgIGNvbWJpbmVkLnNldChjaHVuaywgb2Zmc2V0KTtcbiAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICB9XG4gIGNvbnN0IHJlc3BvbnNlVGV4dCA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShjb21iaW5lZCk7XG5cbiAgbGV0IHJlc3BvbnNlOiB1bmtub3duO1xuICB0cnkge1xuICAgIHJlc3BvbnNlID0gSlNPTi5wYXJzZShyZXNwb25zZVRleHQpO1xuICB9IGNhdGNoIHtcbiAgICAvLyBPbGQgZGVwbG95bWVudHMgKHNwZWNWZXJzaW9uIDwgMykgcmV0dXJuIHBsYWluIHRleHQgbGlrZVxuICAgIC8vICdXb3JrZmxvdyBTREsgXCIuLi5cIiBlbmRwb2ludCBpcyBoZWFsdGh5Jy4gVHJlYXQgYW55IG5vbi1lbXB0eVxuICAgIC8vIHRleHQgcmVzcG9uc2UgYXMgYSBoZWFsdGh5IGRlcGxveW1lbnQgd2l0aCB1bmtub3duIHNwZWNWZXJzaW9uLlxuICAgIGlmIChyZXNwb25zZVRleHQubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHsgaGVhbHRoeTogdHJ1ZSB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmIChcbiAgICB0eXBlb2YgcmVzcG9uc2UgIT09ICdvYmplY3QnIHx8XG4gICAgcmVzcG9uc2UgPT09IG51bGwgfHxcbiAgICAhKCdoZWFsdGh5JyBpbiByZXNwb25zZSkgfHxcbiAgICB0eXBlb2YgKHJlc3BvbnNlIGFzIHsgaGVhbHRoeTogdW5rbm93biB9KS5oZWFsdGh5ICE9PSAnYm9vbGVhbidcbiAgKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCByID0gcmVzcG9uc2UgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHBhcnNlZDoge1xuICAgIGhlYWx0aHk6IGJvb2xlYW47XG4gICAgc3BlY1ZlcnNpb24/OiBudW1iZXI7XG4gICAgd29ya2Zsb3dDb3JlVmVyc2lvbj86IHN0cmluZztcbiAgICBlbmNyeXB0aW9uUHVibGljS2V5Pzogc3RyaW5nO1xuICAgIGhvb2tSZXN1bWVJbnB1dFZlcnNpb24/OiBudW1iZXI7XG4gIH0gPSB7XG4gICAgaGVhbHRoeTogci5oZWFsdGh5IGFzIGJvb2xlYW4sXG4gIH07XG4gIGlmICh0eXBlb2Ygci5zcGVjVmVyc2lvbiA9PT0gJ251bWJlcicpIHtcbiAgICBwYXJzZWQuc3BlY1ZlcnNpb24gPSByLnNwZWNWZXJzaW9uO1xuICB9XG4gIGlmICh0eXBlb2Ygci53b3JrZmxvd0NvcmVWZXJzaW9uID09PSAnc3RyaW5nJykge1xuICAgIHBhcnNlZC53b3JrZmxvd0NvcmVWZXJzaW9uID0gci53b3JrZmxvd0NvcmVWZXJzaW9uO1xuICB9XG4gIGlmICh0eXBlb2Ygci5lbmNyeXB0aW9uUHVibGljS2V5ID09PSAnc3RyaW5nJykge1xuICAgIHBhcnNlZC5lbmNyeXB0aW9uUHVibGljS2V5ID0gci5lbmNyeXB0aW9uUHVibGljS2V5O1xuICB9XG4gIGlmICh0eXBlb2Ygci5ob29rUmVzdW1lSW5wdXRWZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgIHBhcnNlZC5ob29rUmVzdW1lSW5wdXRWZXJzaW9uID0gci5ob29rUmVzdW1lSW5wdXRWZXJzaW9uO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoZWFsdGhDaGVjayhcbiAgd29ybGQ6IFdvcmxkLFxuICBvcHRpb25zPzogSGVhbHRoQ2hlY2tPcHRpb25zXG4pOiBQcm9taXNlPEhlYWx0aENoZWNrUmVzdWx0PiB7XG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zPy50aW1lb3V0ID8/IERFRkFVTFRfSEVBTFRIX0NIRUNLX1RJTUVPVVQ7XG4gIC8vIFVzZSB0aGUgd29ybGQncyBJRCBnZW5lcmF0b3Igd2hlbiBhdmFpbGFibGUgc28gdGhlIGNvcnJlbGF0aW9uSWQgaXMgYVxuICAvLyByZWdpb24tdGFnZ2VkIFVMSUQuIFRoZSBoZWFsdGgtY2hlY2sgcmVzcG9uc2UgaXMgZGVsaXZlcmVkIG92ZXIgYSBzdHJlYW1cbiAgLy8gd2hvc2UgbmFtZSBlbWJlZHMgdGhpcyBjb3JyZWxhdGlvbklkOyB1bmRlciBwbGF0Zm9ybS1kaXJlY3RlZCByb3V0aW5nIHRoZVxuICAvLyByZWFkZXIgYW5kIHRoZSByZXNwb25kaW5nIGVuZHBvaW50IGNhbiBiZSBzZXJ2ZWQgZnJvbSBkaWZmZXJlbnQgcGh5c2ljYWxcbiAgLy8gcmVnaW9ucywgc28gdGhlIHJlZ2lvbiBtdXN0IGJlIGVuY29kZWQgaW4gdGhlIElEIGl0c2VsZiBmb3IgYm90aCBzaWRlcyB0b1xuICAvLyByZXNvbHZlIHRoZSBzYW1lIChyZWdpb24tcGlubmVkKSBiYWNrZW5kLiBGYWxscyBiYWNrIHRvIGEgcGxhaW4gVUxJRCBmb3JcbiAgLy8gd29ybGRzIHRoYXQgZG9uJ3QgdGFnIElEcyAoZS5nLiBsb2NhbCksIHdoaWNoIHJlc29sdmUgdG8gdGhlIGRlZmF1bHRcbiAgLy8gcmVnaW9uIG9uIGJvdGggc2lkZXMuXG4gIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSB3b3JsZC5jcmVhdGVSdW5JZD8uKCkgPz8gZ2VuZXJhdGVJZCgpO1xuICBjb25zdCBzdHJlYW1OYW1lID0gZ2V0SGVhbHRoQ2hlY2tTdHJlYW1OYW1lKGNvcnJlbGF0aW9uSWQpO1xuXG4gIGNvbnN0IHF1ZXVlTmFtZSA9XG4gICAgYCR7Z2V0UXVldWVUb3BpY1ByZWZpeCgnd29ya2Zsb3cnLCByZXNvbHZlUXVldWVOYW1lc3BhY2Uob3B0aW9ucz8ubmFtZXNwYWNlKSl9aGVhbHRoX2NoZWNrYCBhcyBWYWxpZFF1ZXVlTmFtZTtcblxuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd29ybGQucXVldWUoXG4gICAgICBxdWV1ZU5hbWUsXG4gICAgICB7XG4gICAgICAgIF9faGVhbHRoQ2hlY2s6IHRydWUsXG4gICAgICAgIGNvcnJlbGF0aW9uSWQsXG4gICAgICAgIC4uLihvcHRpb25zPy5ydW5JZCA/IHsgcnVuSWQ6IG9wdGlvbnMucnVuSWQgfSA6IHt9KSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIC8vIFVzZSBKU09OIHRyYW5zcG9ydCBzbyB0aGUgaGVhbHRoIGNoZWNrIHdvcmtzIGFnYWluc3QgYm90aFxuICAgICAgICAvLyBvbGQgKEpTT04tb25seSkgYW5kIG5ldyAoZHVhbCkgZGVwbG95bWVudHMuXG4gICAgICAgIHNwZWNWZXJzaW9uOiBTUEVDX1ZFUlNJT05fTEVHQUNZLFxuICAgICAgICBkZXBsb3ltZW50SWQ6IG9wdGlvbnM/LmRlcGxveW1lbnRJZCxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgd2hpbGUgKERhdGUubm93KCkgLSBzdGFydFRpbWUgPCB0aW1lb3V0KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZW1haW5pbmdNcyA9IHRpbWVvdXQgLSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSk7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IHdpdGhEZWFkbGluZShcbiAgICAgICAgICB3b3JsZC5zdHJlYW1zLmdldChcbiAgICAgICAgICAgIGdlbmVyYXRlSGVhbHRoQ2hlY2tSdW5JZChjb3JyZWxhdGlvbklkKSxcbiAgICAgICAgICAgIHN0cmVhbU5hbWVcbiAgICAgICAgICApLFxuICAgICAgICAgIHJlbWFpbmluZ01zXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHN0cmVhbS5nZXRSZWFkZXIoKTtcbiAgICAgICAgY29uc3QgeyBjaHVua3MsIHRpbWVkT3V0IH0gPSBhd2FpdCByZWFkU3RyZWFtV2l0aFRpbWVvdXQoXG4gICAgICAgICAgcmVhZGVyLFxuICAgICAgICAgIEhFQUxUSF9DSEVDS19SRUFEX1RJTUVPVVRcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGltZWRPdXQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVhZGVyLmNhbmNlbCgpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSWdub3JlIGNhbmNlbCBlcnJvcnNcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEhFQUxUSF9DSEVDS19QT0xMX0lOVEVSVkFMKVxuICAgICAgICAgICk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IHBhcnNlSGVhbHRoQ2hlY2tSZXNwb25zZShjaHVua3MpO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4ucmVzcG9uc2UsXG4gICAgICAgICAgICBsYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydFRpbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgSEVBTFRIX0NIRUNLX1BPTExfSU5URVJWQUwpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBIRUFMVEhfQ0hFQ0tfUE9MTF9JTlRFUlZBTClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWx0aHk6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBIZWFsdGggY2hlY2sgdGltZWQgb3V0IGFmdGVyICR7dGltZW91dH1tc2AsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhbHRoeTogZmFsc2UsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH07XG4gIH1cbn1cblxuZnVuY3Rpb24gZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihcbiAgcnVuSWQ6IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nXG4pOiBXb3JrZmxvd1dvcmxkRXJyb3Ige1xuICByZXR1cm4gbmV3IFdvcmtmbG93V29ybGRFcnJvcihcbiAgICBgRXZlbnQgcGFnaW5hdGlvbiAke21lc3NhZ2V9IGZvciB3b3JrZmxvdyBydW4gXCIke3J1bklkfVwiLmAsXG4gICAgeyBjb2RlOiBSVU5fRVJST1JfQ09ERVMuV09STERfQ09OVFJBQ1RfRVJST1IgfVxuICApO1xufVxuXG5mdW5jdGlvbiByZWNvcmRSZXF1ZXN0ZWRFdmVudEN1cnNvcihcbiAgcnVuSWQ6IHN0cmluZyxcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsLFxuICByZXF1ZXN0ZWRDdXJzb3JzOiBTZXQ8c3RyaW5nPlxuKTogdm9pZCB7XG4gIGlmICghY3Vyc29yKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChyZXF1ZXN0ZWRDdXJzb3JzLmhhcyhjdXJzb3IpKSB7XG4gICAgdGhyb3cgZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihydW5JZCwgJ2RpZCBub3QgYWR2YW5jZScpO1xuICB9XG4gIHJlcXVlc3RlZEN1cnNvcnMuYWRkKGN1cnNvcik7XG59XG5cbi8qKlxuICogQXBwZW5kcyBldmVudHMgd2hvc2UgSURzIGFyZSBub3QgYWxyZWFkeSBwcmVzZW50IGluIGB0YXJnZXRgLlxuICpcbiAqIFBhc3MgdGhlIElEcyBjdXJyZW50bHkgcHJlc2VudCBpbiBgdGFyZ2V0YCB3aGVuIGFwcGVuZGluZyByZXBlYXRlZGx5IHRvIHRoZVxuICogc2FtZSBhcnJheS4gVGhlIHNldCBpcyB1cGRhdGVkIGFsb25nc2lkZSBgdGFyZ2V0YC5cbiAqXG4gKiBFdmVudHMgYXJlIGFwcGVuZGVkIGluIHRoZSBvcmRlciB0aGUgV29ybGQgcmV0dXJuZWQgdGhlbSwgYW5kIGFyZSBub3RcbiAqIHJlLXNvcnRlZC4gRXZlcnkgYXBwZW5kIHNvdXJjZSBpcyBhbHJlYWR5IGluIGNhbm9uaWNhbCBvcmRlciByZWxhdGl2ZSB0byB0aGVcbiAqIHRhaWwgKGEgY3Vyc29yLWRlbGltaXRlZCBwYWdlLCBvciBhIHdyaXRlLXJlc3BvbnNlIGRlbHRhKSwgc28gcmVjZWlwdCBvcmRlciBpc1xuICogdGhlIG9yZGVyIHRvIGtlZXAsIGFuZCByZS1zb3J0aW5nIGhlcmUgd291bGQgb25seSBjb3N0IGEgcGFzcyBvdmVyIHRoZSBsb2cuXG4gKiBOb3RoaW5nIGRvd25zdHJlYW0gbWF5IGFzc3VtZSB0aGUgdGFpbCBpcyB0aGUgbmV3ZXN0IGV2ZW50LiBTZWVcbiAqIHtAbGluayBtYXhFdmVudFNsb3R9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwZW5kVW5pcXVlRXZlbnRzKFxuICB0YXJnZXQ6IEV2ZW50W10sXG4gIGV2ZW50czogcmVhZG9ubHkgRXZlbnRbXSxcbiAgdGFyZ2V0SWRzPzogU2V0PHN0cmluZz5cbik6IHZvaWQge1xuICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGlkcyA9IHRhcmdldElkcyA/PyBuZXcgU2V0KHRhcmdldC5tYXAoKGV2ZW50KSA9PiBldmVudC5ldmVudElkKSk7XG4gIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgaWYgKGlkcy5oYXMoZXZlbnQuZXZlbnRJZCkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZHMuYWRkKGV2ZW50LmV2ZW50SWQpO1xuICAgIHRhcmdldC5wdXNoKGV2ZW50KTtcbiAgfVxufVxuXG4vKipcbiAqIEluc2VydHMgYGV2ZW50YCBpbnRvIGB0YXJnZXRgIGF0IHRoZSBwb3NpdGlvbiB0aGF0IGtlZXBzIGB0YXJnZXRgIG9yZGVyZWQgYnlcbiAqIGFzY2VuZGluZyBgZXZlbnRJZGAsIG9yIG5vLW9wcyBpZiBhbiBldmVudCB3aXRoIHRoZSBzYW1lIGBldmVudElkYCBpcyBhbHJlYWR5XG4gKiBwcmVzZW50IChpZGVtcG90ZW50KS5cbiAqXG4gKiBgcHJlbG9hZGVkRXZlbnRzYCBpcyBsb2FkZWQgYHNvcnRPcmRlcjogJ2FzYydgIGFuZCBpcyBuZXZlciByZS1zb3J0ZWRcbiAqIGNsaWVudC1zaWRlLCBzbyBhIGBob29rX3JlY2VpdmVkYCBzcGxpY2VkIGluIGJ5IHRoZSBsYXp5LXJlc3VtZSBjb25zdW1lciBtdXN0XG4gKiBsYW5kIGluIGBldmVudElkYCBvcmRlcjogYSBwbGFpbiBgcHVzaGAgd291bGQgcGxhY2UgYSBsYXRlLWNvbW1pdHRpbmdcbiAqIGVhcmxpZXIgZXZlbnQgYWZ0ZXIgZXZlbnRzIHRoYXQgc29ydCBiZWZvcmUgaXQsIGNvcnJ1cHRpbmcgcmVwbGF5LlxuICpcbiAqIExleGljb2dyYXBoaWMgc3RyaW5nIG9yZGVyIGlzIHRoZSBsb2cncyBvcmRlcjogYSBzbG90IGlkIGlzIGEgZml4ZWQtd2lkdGhcbiAqIHplcm8tcGFkZGVkIHBvc2l0aW9uLCBzbyBjb21wYXJpbmcgdGhlIHN0cmluZ3MgY29tcGFyZXMgdGhlIHBvc2l0aW9ucy4gVGhpc1xuICogbmVlZHMgbm8gcGFyc2Ugb2YgaXRzIG93biBmb3IgdGhhdCByZWFzb24sIGFuZCB0aGUgY29tcGFyaXNvbiBpcyBleGFjdCByYXRoZXJcbiAqIHRoYW4gYSByZWNvbnN0cnVjdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluc2VydEV2ZW50QnlFdmVudElkKHRhcmdldDogRXZlbnRbXSwgZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gIC8vIExpbmVhciBzY2FuIGZyb20gdGhlIGVuZDogdGhlIHNwbGljZWQgZXZlbnQgaXMgYWxtb3N0IGFsd2F5cyB0aGUgbmV3ZXN0XG4gIC8vIChpdCBzb3J0cyBhdCBvciBuZWFyIHRoZSB0YWlsKSwgc28gdGhpcyBmaW5kcyB0aGUgc2xvdCBpbiBPKDEp4oCTTyhrKSBmb3IgdGhlXG4gIC8vIGNvbW1vbiBjYXNlIHdoaWxlIHN0aWxsIGhhbmRsaW5nIGFuIG91dC1vZi1vcmRlciBsYXRlIGFycml2YWwgY29ycmVjdGx5LlxuICBsZXQgaSA9IHRhcmdldC5sZW5ndGg7XG4gIHdoaWxlIChpID4gMCkge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGFyZ2V0W2kgLSAxXTtcbiAgICBpZiAoZXhpc3RpbmcuZXZlbnRJZCA9PT0gZXZlbnQuZXZlbnRJZCkge1xuICAgICAgLy8gQWxyZWFkeSBwcmVzZW50OiBrZWVwIHRoZSBzcGxpY2UgaWRlbXBvdGVudC5cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGV4aXN0aW5nLmV2ZW50SWQgPCBldmVudC5ldmVudElkKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgaS0tO1xuICB9XG4gIHRhcmdldC5zcGxpY2UoaSwgMCwgZXZlbnQpO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRFdmVudFBhZ2luYXRpb25Qcm9ncmVzcyhcbiAgcnVuSWQ6IHN0cmluZyxcbiAgaGFzTW9yZTogYm9vbGVhbixcbiAgY3Vyc29yOiBzdHJpbmcgfCBudWxsLFxuICByZXF1ZXN0ZWRDdXJzb3JzOiBTZXQ8c3RyaW5nPlxuKTogdm9pZCB7XG4gIGlmICghaGFzTW9yZSkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY3Vyc29yID09PSBudWxsKSB7XG4gICAgdGhyb3cgZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihcbiAgICAgIHJ1bklkLFxuICAgICAgJ3JldHVybmVkIG1vcmUgcGFnZXMgd2l0aG91dCBhIGN1cnNvcidcbiAgICApO1xuICB9XG4gIGlmIChyZXF1ZXN0ZWRDdXJzb3JzLmhhcyhjdXJzb3IpKSB7XG4gICAgdGhyb3cgZXZlbnRQYWdpbmF0aW9uQ29udHJhY3RFcnJvcihydW5JZCwgJ3JlcGVhdGVkIGEgY3Vyc29yJyk7XG4gIH1cbn1cblxuZnVuY3Rpb24gc2hvdWxkUmV0cnlXaXRob3V0RXZlbnRDdXJzb3IoXG4gIGVycm9yOiB1bmtub3duLFxuICBjdXJzb3I6IHN0cmluZyB8IG51bGwsXG4gIGFscmVhZHlSZXRyaWVkOiBib29sZWFuXG4pOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBjdXJzb3IgIT09IG51bGwgJiZcbiAgICAhYWxyZWFkeVJldHJpZWQgJiZcbiAgICBXb3JrZmxvd1dvcmxkRXJyb3IuaXMoZXJyb3IpICYmXG4gICAgZXJyb3Iuc3RhdHVzID09PSA0MDBcbiAgKTtcbn1cblxuLyoqXG4gKiBMb2FkcyB3b3JrZmxvdyBydW4gZXZlbnRzIGJ5IGl0ZXJhdGluZyB0aHJvdWdoIGFsbCBwYWdlcyBvZiBwYWdpbmF0ZWRcbiAqIHJlc3VsdHMuIEV2ZW50cyBhcmUgcmV0dXJuZWQgaW4gY2hyb25vbG9naWNhbCAoYXNjZW5kaW5nKSBvcmRlciBmb3JcbiAqIGRldGVybWluaXN0aWMgd29ya2Zsb3cgcmVwbGF5LlxuICpcbiAqIEBwYXJhbSBydW5JZCAtIFRoZSB3b3JrZmxvdyBydW4gSUQuXG4gKiBAcGFyYW0gYWZ0ZXJDdXJzb3IgLSBJZiBwcm92aWRlZCwgb25seSBldmVudHMgYWZ0ZXIgdGhpcyBjdXJzb3IgYXJlXG4gKiAgIHJldHVybmVkIChpbmNyZW1lbnRhbCBsb2FkKS4gSWYgb21pdHRlZCwgYWxsIGV2ZW50cyBhcmUgcmV0dXJuZWQuXG4gKiAgIFRoZSByZXR1cm5lZCBjdXJzb3IgY2FuIGJlIHBhc3NlZCBiYWNrIGluIG9uIGEgc3Vic2VxdWVudCBjYWxsIGZvclxuICogICBpbmNyZW1lbnRhbCBsb2FkaW5nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZFdvcmtmbG93UnVuRXZlbnRzKFxuICBydW5JZDogc3RyaW5nLFxuICBhZnRlckN1cnNvcj86IHN0cmluZ1xuKTogUHJvbWlzZTxMb2FkZWRFdmVudExvZz4ge1xuICBjb25zdCBpbmNyZW1lbnRhbCA9IGFmdGVyQ3Vyc29yICE9PSB1bmRlZmluZWQ7XG4gIHJldHVybiB0cmFjZSgnd29ya2Zsb3cucmVwbGF5LmxvYWQnLCBhc3luYyAoc3BhbikgPT4ge1xuICAgIHNwYW4/LnNldEF0dHJpYnV0ZXMoe1xuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UnVuSWQocnVuSWQpLFxuICAgICAgLi4uQXR0cmlidXRlLldvcmtmbG93UmVwbGF5TG9hZFNvdXJjZShcbiAgICAgICAgaW5jcmVtZW50YWwgPyAnZXZlbnRzX2xpc3RfaW5jcmVtZW50YWwnIDogJ2V2ZW50c19saXN0J1xuICAgICAgKSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGxvYWRlZEV2ZW50czogRXZlbnRbXSA9IFtdO1xuICAgIGNvbnN0IGxvYWRlZEV2ZW50SWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3QgcmVxdWVzdGVkQ3Vyc29ycyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGxldCBjdXJzb3I6IHN0cmluZyB8IG51bGwgPSBhZnRlckN1cnNvciA/PyBudWxsO1xuICAgIGxldCBoYXNNb3JlID0gdHJ1ZTtcbiAgICBsZXQgcGFnZXNMb2FkZWQgPSAwO1xuICAgIGxldCByZXRyaWVkV2l0aG91dEN1cnNvciA9IGZhbHNlO1xuICAgIGNvbnN0IHdvcmxkID0gYXdhaXQgZ2V0V29ybGRMYXp5KCk7XG4gICAgY29uc3QgbG9hZFN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICB3aGlsZSAoaGFzTW9yZSkge1xuICAgICAgLy8gVE9ETzogd2UncmUgY3VycmVudGx5IGxvYWRpbmcgYWxsIHRoZSBkYXRhIHdpdGggcmVzb2x2ZVJlZiBiZWhhdmlvci4gV2UgbmVlZCB0byB1cGRhdGUgdGhpc1xuICAgICAgLy8gdG8gbGF6eWxvYWQgdGhlIGRhdGEgZnJvbSB0aGUgd29ybGQgaW5zdGVhZCBzbyB0aGF0IHdlIGNhbiBvcHRpbWl6ZSBhbmQgbWFrZSB0aGUgZXZlbnQgbG9nIGxvYWRpbmdcbiAgICAgIC8vIG11Y2ggZmFzdGVyIGFuZCBtZW1vcnkgZWZmaWNpZW50XG4gICAgICBjb25zdCBwYWdlU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3QgcmVxdWVzdGVkQ3Vyc29yID0gY3Vyc29yO1xuICAgICAgcmVjb3JkUmVxdWVzdGVkRXZlbnRDdXJzb3IocnVuSWQsIHJlcXVlc3RlZEN1cnNvciwgcmVxdWVzdGVkQ3Vyc29ycyk7XG5cbiAgICAgIGxldCByZXNwb25zZTogQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiB3b3JsZC5ldmVudHMubGlzdD4+O1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmVzcG9uc2UgPSBhd2FpdCB3b3JsZC5ldmVudHMubGlzdCh7XG4gICAgICAgICAgcnVuSWQsXG4gICAgICAgICAgcGFnaW5hdGlvbjoge1xuICAgICAgICAgICAgc29ydE9yZGVyOiAnYXNjJyxcbiAgICAgICAgICAgIGN1cnNvcjogcmVxdWVzdGVkQ3Vyc29yID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBzaG91bGRSZXRyeVdpdGhvdXRFdmVudEN1cnNvcihcbiAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgcmVxdWVzdGVkQ3Vyc29yLFxuICAgICAgICAgICAgcmV0cmllZFdpdGhvdXRDdXJzb3JcbiAgICAgICAgICApXG4gICAgICAgICkge1xuICAgICAgICAgIHJ1bnRpbWVMb2dnZXIud2FybihcbiAgICAgICAgICAgICdFdmVudCBjdXJzb3Igd2FzIHJlamVjdGVkOyByZXRyeWluZyB3aXRoIGEgZnVsbCBldmVudCByZWxvYWQuJyxcbiAgICAgICAgICAgIHsgd29ya2Zsb3dSdW5JZDogcnVuSWQgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgbG9hZGVkRXZlbnRzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgbG9hZGVkRXZlbnRJZHMuY2xlYXIoKTtcbiAgICAgICAgICByZXF1ZXN0ZWRDdXJzb3JzLmNsZWFyKCk7XG4gICAgICAgICAgY3Vyc29yID0gbnVsbDtcbiAgICAgICAgICByZXRyaWVkV2l0aG91dEN1cnNvciA9IHRydWU7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIGFwcGVuZFVuaXF1ZUV2ZW50cyhsb2FkZWRFdmVudHMsIHJlc3BvbnNlLmRhdGEsIGxvYWRlZEV2ZW50SWRzKTtcbiAgICAgIGhhc01vcmUgPSByZXNwb25zZS5oYXNNb3JlO1xuICAgICAgYXNzZXJ0RXZlbnRQYWdpbmF0aW9uUHJvZ3Jlc3MoXG4gICAgICAgIHJ1bklkLFxuICAgICAgICBoYXNNb3JlLFxuICAgICAgICByZXNwb25zZS5jdXJzb3IsXG4gICAgICAgIHJlcXVlc3RlZEN1cnNvcnNcbiAgICAgICk7XG4gICAgICAvLyBQcmVzZXJ2ZSB0aGUgbGFzdCBub24tbnVsbCBjdXJzb3IgYWNyb3NzIHBhZ2VzLiBBIFdvcmxkIG1heVxuICAgICAgLy8gbGVnaXRpbWF0ZWx5IHJldHVybiBgeyBkYXRhOiBbXSwgY3Vyc29yOiBudWxsLCBoYXNNb3JlOiBmYWxzZSB9YFxuICAgICAgLy8gb24gYSB0cmFpbGluZyBlbXB0eSBwYWdlLCBmb3IgZXhhbXBsZSB3aGVuIHRoZSBwcmV2aW91cyBwYWdlJ3NcbiAgICAgIC8vIHVuZGVybHlpbmcgREIgcXVlcnkgaGl0IHRoZSBsaW1pdCBleGFjdGx5IGFuZCByZXR1cm5lZCBhXG4gICAgICAvLyBwcmVjYXV0aW9uYXJ5IGBMYXN0RXZhbHVhdGVkS2V5YC4gT3ZlcndyaXRpbmcgd2l0aCB0aGF0IG51bGxcbiAgICAgIC8vIHdvdWxkIGxvc2UgdGhlIHBvc2l0aW9uIHBhc3QgdGhlIGxhc3QgcmVhbCBldmVudCB3ZSBsb2FkZWQgYW5kXG4gICAgICAvLyBmb3JjZSB0aGUgcnVudGltZSBpbnRvIHRoZSBcIm5vIGN1cnNvciBhZnRlciBpbml0aWFsIGxvYWRcIiBmdWxsLVxuICAgICAgLy8gcmVsb2FkIGZhbGxiYWNrIG9uIGV2ZXJ5IHN1YnNlcXVlbnQgcmVwbGF5IGl0ZXJhdGlvbi5cbiAgICAgIGN1cnNvciA9IHJlc3BvbnNlLmN1cnNvciA/PyBjdXJzb3I7XG4gICAgICBwYWdlc0xvYWRlZCsrO1xuXG4gICAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdMb2FkZWQgZXZlbnQgcGFnZScsIHtcbiAgICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICAgIGluY3JlbWVudGFsLFxuICAgICAgICBwYWdlOiBwYWdlc0xvYWRlZCxcbiAgICAgICAgcGFnZUV2ZW50czogcmVzcG9uc2UuZGF0YS5sZW5ndGgsXG4gICAgICAgIHRvdGFsRXZlbnRzOiBsb2FkZWRFdmVudHMubGVuZ3RoLFxuICAgICAgICBoYXNNb3JlLFxuICAgICAgICBwYWdlTXM6IERhdGUubm93KCkgLSBwYWdlU3RhcnQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBydW50aW1lTG9nZ2VyLmRlYnVnKCdFdmVudCBsb2FkIGNvbXBsZXRlJywge1xuICAgICAgd29ya2Zsb3dSdW5JZDogcnVuSWQsXG4gICAgICBpbmNyZW1lbnRhbCxcbiAgICAgIHRvdGFsRXZlbnRzOiBsb2FkZWRFdmVudHMubGVuZ3RoLFxuICAgICAgcGFnZXNMb2FkZWQsXG4gICAgICB0b3RhbE1zOiBEYXRlLm5vdygpIC0gbG9hZFN0YXJ0LFxuICAgIH0pO1xuXG4gICAgc3Bhbj8uc2V0QXR0cmlidXRlcyh7XG4gICAgICAuLi5BdHRyaWJ1dGUuV29ya2Zsb3dFdmVudHNDb3VudChsb2FkZWRFdmVudHMubGVuZ3RoKSxcbiAgICAgIC4uLkF0dHJpYnV0ZS5Xb3JrZmxvd0V2ZW50c1BhZ2VzTG9hZGVkKHBhZ2VzTG9hZGVkKSxcbiAgICB9KTtcblxuICAgIHJldHVybiB7IGV2ZW50czogbG9hZGVkRXZlbnRzLCBjdXJzb3IgfTtcbiAgfSk7XG59XG5cbi8qKlxuICogVGhlIHJ1bnRpbWUncyBsb2FkZWQgZXZlbnQtbG9nIHNuYXBzaG90OiB0aGUgZXZlbnRzIHJlcGxheWVkIHNvIGZhciBhbmQgdGhlXG4gKiBjdXJzb3IgcG9zaXRpb25lZCBhZnRlciB0aGVtLiBIYW5kZWQgdG8gaGVscGVycyB0aGF0IGRlcml2ZSB0aGUgcHJlY29uZGl0aW9uXG4gKiBzbmFwc2hvdCBmcm9tIGl0OyB0aGV5IGRvIG5vdCBtdXRhdGUgaXQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9hZGVkRXZlbnRMb2cge1xuICBldmVudHM6IEV2ZW50W107XG4gIGN1cnNvcjogc3RyaW5nIHwgbnVsbDtcbn1cblxuLyoqXG4gKiBFeHRlbmQgYSBsb2FkZWQgbG9nIHdpdGggYSBwYWdlIHRoYXQgY29udGludWVzIGl0IOKAlCBhIGxpc3RlZCBwYWdlLCBvciB0aGVcbiAqIGlubGluZSBkZWx0YSBhIHdyaXRlIGhhbmRlZCBiYWNrIOKAlCBhbmQgbW92ZSBpdHMgcmVhZCBwb3NpdGlvbiB3aXRoIGl0LlxuICpcbiAqIFRoZSBjdXJzb3IgaXMgb25seSBhZHZhbmNlZCB3aGVuIHRoZSBwYWdlIGNhcnJpZXMgb25lLCBzbyBhIHNvdXJjZSB3aXRoIG5vXG4gKiBwb3NpdGlvbiBvZiBpdHMgb3duIChhIHNraXBwZWQtc2xvdCByZXBvcnQpIGNhbm5vdCB3YWxrIHRoZSByZWFkIHBvc2l0aW9uXG4gKiBwYXN0IGV2ZW50cyBpdCBkaWQgbm90IGNhcnJ5LiBBcHBlbmRpbmcgZG9lcyBub3QgcmUtc29ydDsgc2VlXG4gKiB7QGxpbmsgYXBwZW5kVW5pcXVlRXZlbnRzfSBmb3Igd2h5IHJlY2VpcHQgb3JkZXIgaXMgdGhlIG9yZGVyIHRvIGtlZXAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBlbmRFdmVudExvZyhcbiAgbG9nOiBMb2FkZWRFdmVudExvZyxcbiAgYXBwZW5kZWQ6IHsgZXZlbnRzOiByZWFkb25seSBFdmVudFtdOyBjdXJzb3I/OiBzdHJpbmcgfCBudWxsIH1cbik6IHZvaWQge1xuICBhcHBlbmRVbmlxdWVFdmVudHMobG9nLmV2ZW50cywgYXBwZW5kZWQuZXZlbnRzKTtcbiAgbG9nLmN1cnNvciA9IGFwcGVuZGVkLmN1cnNvciA/PyBsb2cuY3Vyc29yO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYSByZXBsYXkgcmVmdXNlcyB0byBydW4gb3ZlciBhIGxvZyB3aXRoIGEgaG9sZSBpbiBpdCAoc2VlXG4gKiB7QGxpbmsgZmluZEV2ZW50U2xvdEdhcH0pLiAqKk9uIGJ5IGRlZmF1bHQqKjsgc2V0XG4gKiBgV09SS0ZMT1dfU0xPVF9HQVBfQ0hFQ0s9MGAgdG8gcmVwbGF5IGFjcm9zcyBob2xlcyBpbnN0ZWFkLlxuICpcbiAqIEEgV29ybGQgdGhhdCBhbGxvY2F0ZXMgYSBwb3NpdGlvbiBhdCB0aGUgbW9tZW50IGl0IGNvbW1pdHMgbGVhdmVzIG5vIGhvbGVcbiAqIGJlaGluZCB3aGVuIGEgd3JpdGUgZmFpbHMsIHNvIGRlbnNpdHkgaXMgYSBwcm9wZXJ0eSB0aGUgbG9nIGhhcyBieVxuICogY29uc3RydWN0aW9uIHJhdGhlciB0aGFuIG9uZSB0aGlzIGNoZWNrIG1haW50YWlucy4gV2hhdCB0aGUgY2hlY2sgaXMgZm9yIGlzXG4gKiB0aGUgcmVhZHMgYW5kIHRoZSBXb3JsZHMgd2hlcmUgdGhhdCBkb2VzIG5vdCBob2xkLCBhbmQgYnkgdGhlIHRpbWUgaXQgcnVuc1xuICogdGhlIGJlbmlnbiBleHBsYW5hdGlvbnMgYXJlIHNwZW50OiBhIHBvc2l0aW9uIG1pc3NpbmcgYmVjYXVzZSBhIGNvbmN1cnJlbnRcbiAqIGNvbW1pdCBpcyBub3QgdmlzaWJsZSB5ZXQgY2xlYXJzIG9uIGEgcmUtcmVhZCwgd2hpY2ggaXMgd2hhdFxuICoge0BsaW5rIHNldHRsZUV2ZW50U2xvdEdhcH0gZG9lcyBmaXJzdC5cbiAqXG4gKiBXaGF0IGlzIGxlZnQgaXMgYSBob2xlIHRoYXQgcGVyc2lzdHMsIGFuZCBpdHMgdHdvIGNhdXNlcyBhcmVcbiAqIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gdGhlIGxvZy4gRWl0aGVyIGEgV29ybGQgYWxsb2NhdGVkIHRoZSBwb3NpdGlvbiBvdXRzaWRlXG4gKiB0aGUgY29tbWl0IGFuZCBsb3N0IHRoZSB3cml0ZSwgaW4gd2hpY2ggY2FzZSBub3RoaW5nIGhhcHBlbmVkIHRoZXJlIGFuZFxuICogcmVwbGF5aW5nIHBhc3QgaXQgaXMgY29ycmVjdCwgb3IgYW4gZXZlbnQgdGhhdCBkaWQgaGFwcGVuIGlzIG1pc3NpbmcsIGluXG4gKiB3aGljaCBjYXNlIHJlcGxheWluZyBwYXN0IGl0IGRlY2lkZXMgYSBicmFuY2ggb24gYWJzZW5jZSBhbmQgcHJvZHVjZXMgYSB3cm9uZ1xuICogcmVzdWx0IHdpdGggbm90aGluZyB0byBzaG93IGZvciBpdC4gRmFpbGluZyBpcyB0aGUgcmVjb3ZlcmFibGUgc2lkZSBvZiB0aGF0XG4gKiB0cmFkZSwgYW5kIHRoaXMgaXMgdGhlIHdheSBiYWNrIG91dCBpZiBhIGZsZWV0IHR1cm5zIG91dCB0byBjYXJyeSBob2xlcyBvZlxuICogdGhlIGZpcnN0IGtpbmQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1Nsb3RHYXBDaGVja0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiBwcm9jZXNzLmVudi5XT1JLRkxPV19TTE9UX0dBUF9DSEVDSyAhPT0gJzAnO1xufVxuXG4vKlxuICogTWVyZ2luZyBpbnRvIGEgbG9nIGEgcmVwbGF5IGlzIG1pZHdheSB0aHJvdWdoIHJlYWRpbmcuXG4gKlxuICogVGhyZWUgcGF0aHMgYWRkIGV2ZW50cyB0byBhIGxvYWRlZCBsb2cgYWZ0ZXIgdGhlIHJlcGxheSBoYXMgc3RhcnRlZDogYVxuICogYnVtcC1hbmQtcmVwb3J0IHdyaXRlIGhhbmRzIGJhY2sgdGhlIHNsb3RzIGl0IHNraXBwZWQgKHtAbGlua1xuICogbWVyZ2VSZXBvcnRlZEV2ZW50c30pLCBhbiBpbmxpbmUgZGVsdGEgZXh0ZW5kcyB0aGUgdGFpbCAoYGFic29yYkNyZWF0ZURlbHRhYFxuICogaW4gYHJ1bnRpbWUudHNgKSwgYW5kIGEgbGlzdGVkIHBhZ2UgYXBwZW5kcyAoe0BsaW5rIGFwcGVuZFVuaXF1ZUV2ZW50c30pLlxuICogVGhleSBsb29rIGFsYXJtaW5nICh0aGUgcmVwbGF5IGlzIHJlYWRpbmcgYW4gYXJyYXkgd2hpbGUgc29tZXRoaW5nIGVsc2VcbiAqIHdyaXRlcyB0byBpdCkgYW5kIHRoZXkgYXJlIHNhZmUgZm9yIG9uZSByZWFzb24gd29ydGggc3RhdGluZyBwbGFpbmx5LCBzaW5jZVxuICogZXZlcnkgY29ycmVjdG5lc3MgYXJndW1lbnQgaW4gdGhpcyBmaWxlIGxlYW5zIG9uIGl0LlxuICpcbiAqICoqQW4gZXZlbnQgaW4gdGhlIGxvZyBpcyBhIGZhY3QsIGFuZCBhIGxvbmdlciBsb2cgY2Fubm90IHJldHJhY3Qgb25lLioqIFRoZVxuICogbG9nIGlzIGFwcGVuZC1vbmx5IGFuZCBwb3NpdGlvbnMgYXJlIG5ldmVyIHJldXNlZCwgc28gYSByZXBsYXkgdGhhdCBwcm9kdWNlZFxuICogZXZlbnQgRSBmcm9tIHRoZSBwcmVmaXggaXQgaGFkIGxvYWRlZCBoYXMgbWFkZSBFIHRydWUgZm9yIGV2ZXJ5IHJlcGxheSB0aGF0XG4gKiBmb2xsb3dzLiBBIGxhdGVyIHJlcGxheSByZWFkaW5nIGEgZnVsbGVyIGxvZyBkb2VzIG5vdCBnZXQgdG8gZGVjaWRlIEUgc2hvdWxkXG4gKiBub3QgYmUgdGhlcmU7IGl0IGNvbnN1bWVzIEUgYW5kIHJlY29uY2lsZXMgdG8gaXQsIHdoaWNoIGlzIHdoYXQgdGhlIGV2ZW50c1xuICogY29uc3VtZXIgZG9lcyB3aGVuIGl0IHdhbGtzIGEgbG9nIGhvbGRpbmcgd3JpdGVzIGZyb20gYSByZXBsYXkgdGhhdCByYWNlZCBpdC5cbiAqXG4gKiBNZXJnaW5nIGlzIHRoZXJlZm9yZSBtb25vdG9uZTogaXQgY2FuIG9ubHkgYWRkIGZhY3RzIHRoaXMgcmVwbGF5IGhhcyB5ZXQgdG9cbiAqIHJlY29uY2lsZSB0bywgbmV2ZXIgcmVtb3ZlIG9uZSBpdCBhbHJlYWR5IGhhcy4gVGhhdCBpcyB3aHkgYWJzb3JiaW5nIGlzXG4gKiBhbHdheXMgb3B0aW9uYWwgYW5kIG5ldmVyIHdyb25nIHRvIGRlY2xpbmUgKGFuIHVuYWJzb3JiZWQgZXZlbnQgaXMgb25lIHRoZVxuICogbmV4dCByZWFkIHJldHVybnMpLCBhbmQgd2h5IHRoZSBndWFyZHMgYmVsb3cgY2FuIGFmZm9yZCB0byBiZSBzdHJpY3QuXG4gKi9cblxuLyoqXG4gKiBNZXJnZSB0aGUgZXZlbnRzIGEgYnVtcC1hbmQtcmVwb3J0IHdyaXRlIGhhbmRlZCBiYWNrIGludG8gdGhlIGxvZyBpdCB3YXNcbiAqIGRlcml2ZWQgZnJvbSwgYW5kIGFuc3dlciBob3cgbWFueSBvZiB0aGVtIHdlcmUgbmV3LlxuICpcbiAqIFVubGlrZSB7QGxpbmsgYXBwZW5kVW5pcXVlRXZlbnRzfSwgdGhpcyByZS1zb3J0cy4gVGhlIHJlcG9ydGVkIGV2ZW50cyBvY2N1cHlcbiAqIHNsb3RzICpiZWxvdyogdGhlIHdyaXRlIHRoYXQgcmVwb3J0ZWQgdGhlbSwgc28gYXBwZW5kaW5nIHRoZW0gd291bGQgcHV0IHRoZW1cbiAqIGFmdGVyIGV2ZW50cyB0aGV5IHByZWNlZGUuIFNvcnRpbmcgYnkgaWQgcmVzdG9yZXMgdGhlIFdvcmxkJ3MgY2Fub25pY2FsIG9yZGVyXG4gKiByYXRoZXIgdGhhbiBndWVzc2luZyBhdCBpdDogYSBzbG90IGlkIGlzIHRoYXQgb3JkZXIsIHdyaXR0ZW4gZG93bi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlUmVwb3J0ZWRFdmVudHMoXG4gIHRhcmdldDogRXZlbnRbXSxcbiAgZXZlbnRzOiByZWFkb25seSBFdmVudFtdXG4pOiBudW1iZXIge1xuICBjb25zdCBiZWZvcmUgPSB0YXJnZXQubGVuZ3RoO1xuICBhcHBlbmRVbmlxdWVFdmVudHModGFyZ2V0LCBldmVudHMpO1xuICBjb25zdCBhZGRlZCA9IHRhcmdldC5sZW5ndGggLSBiZWZvcmU7XG4gIGlmIChhZGRlZCA+IDApIHtcbiAgICB0YXJnZXQuc29ydCgoYSwgYikgPT5cbiAgICAgIGEuZXZlbnRJZCA8IGIuZXZlbnRJZCA/IC0xIDogYS5ldmVudElkID4gYi5ldmVudElkID8gMSA6IDBcbiAgICApO1xuICB9XG4gIHJldHVybiBhZGRlZDtcbn1cblxuLyoqIFdoYXQge0BsaW5rIGFic29yYlNraXBwZWRTbG90UmVwb3J0fSBkaWQgd2l0aCBhIHdyaXRlJ3MgcmVwb3J0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTa2lwcGVkU2xvdFJlcG9ydCB7XG4gIC8qKiBIb3cgbWFueSBvZiB0aGUgcmVwb3J0ZWQgZXZlbnRzIHdlcmUgbmV3IHRvIHRoZSBsb2cuIFplcm8gaWYgZHJvcHBlZC4gKi9cbiAgYWRkZWQ6IG51bWJlcjtcbiAgLyoqIEhvdyBtYW55IGV2ZW50cyB0aGUgcmVwb3J0IG9mZmVyZWQsIHdoZXRoZXIgb3Igbm90IHRoZXkgd2VyZSB0YWtlbi4gKi9cbiAgb2ZmZXJlZDogbnVtYmVyO1xuICAvKiogVGhlIHJlcG9ydCB3YXMgdHJ1bmNhdGVkLCBzbyBpdCB3YXMgZHJvcHBlZCB3aG9sZSBpbnN0ZWFkIG9mIG1lcmdlZC4gKi9cbiAgdHJ1bmNhdGVkOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEFwcGx5IGEgd3JpdGUncyBza2lwcGVkLXNsb3QgcmVwb3J0IHRvIHRoZSBsb2cgaXQgd2FzIGRlcml2ZWQgZnJvbSwgZGVjaWRpbmdcbiAqIHdoZXRoZXIgdGhlIHJlcG9ydCBtYXkgYmUgdGFrZW4gYXQgYWxsLlxuICpcbiAqIEV2ZXJ5IHJlcGxheS1jb250ZXh0IHdyaXRlIGNhbiBjb21lIGJhY2sgY2FycnlpbmcgdGhlIGV2ZW50cyBvbiB0aGUgc2xvdHMgaXRcbiAqIHNraXBwZWQgb3ZlciwgYW5kIGV2ZXJ5IGNhbGxlciB3YW50cyB0aGUgc2FtZSB0aGluZyBmcm9tIHRoZW06IGZvbGQgdGhlbSBpblxuICogc28gdGhlIHdyaXRlcyB0aGF0IGZvbGxvdyBuYW1lIGEgcG9zaXRpb24gYWJvdmUgdGhlbSwgYW5kIHNvIHRoZSByZXBsYXlcbiAqIHJlc3VtaW5nIGZyb20gdGhpcyBsb2cgc2VlcyB0aGVtIHdpdGhvdXQgYSByZWxvYWQuXG4gKlxuICogVGhlIG9uZSBwb2xpY3kgaXMgdGhhdCBhICoqdHJ1bmNhdGVkIHJlcG9ydCBpcyBkcm9wcGVkIHdob2xlKiouIEl0IGNvdmVycyBhXG4gKiBzcGFuIG9mIHBvc2l0aW9ucyBidXQgY2FycmllcyBvbmx5IHNvbWUgb2YgdGhlIGV2ZW50cyBvbiB0aGVtLCBzbyBtZXJnaW5nIGl0XG4gKiB3b3VsZCByYWlzZSB0aGUgbG9nJ3MgaGlnaGVzdCBwb3NpdGlvbiBwYXN0IGEgcG9zaXRpb24gd2hvc2UgZXZlbnQgaXNcbiAqIG1pc3NpbmcuIExhdGVyIHdyaXRlcyByZWFkIHRoYXQgbWF4aW11bSB0byBzYXkgd2hhdCB0aGV5IGhhdmUgc2Vlbiwgc28gZWFjaFxuICogd291bGQgY2xhaW0gYSBwb3NpdGlvbiBpdCBuZXZlciBzYXcsIGFuZCB0aGUgV29ybGQgb25seSByZXBvcnRzIHRoZSBzcGFuIGFcbiAqIHdyaXRlIHNraXBzOiBpdCB3b3VsZCBuZXZlciBzZW5kIHRoZSBtaXNzaW5nIG9uZS4gRHJvcHBpbmcgY29zdHMgb25lIG1vcmVcbiAqIHJvdW5kIG9mIHRoZSBzYW1lIGV2ZW50cyBvbiB0aGUgbmV4dCB3cml0ZSBhbmQga2VlcHMgdGhlIGxvZyBhIHByZWZpeCBvZiB0aGVcbiAqIHRydXRoLCB3aGljaCB0aGUgbm90ZSBhYm92ZSB7QGxpbmsgbWVyZ2VSZXBvcnRlZEV2ZW50c30gZXhwbGFpbnMgaXMgYWx3YXlzIGFuXG4gKiBhdmFpbGFibGUgYW5zd2VyLlxuICpcbiAqIENhbGxlcnMgdGhhdCBsb2cgZG8gc28gZnJvbSB0aGUgcmV0dXJuZWQgY291bnRzOyB0aGUgZGVjaXNpb24gaXMgbm90IHRoZWlyc1xuICogdG8gcmUtZGVyaXZlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWJzb3JiU2tpcHBlZFNsb3RSZXBvcnQoXG4gIHRhcmdldDogRXZlbnRbXSxcbiAgcmVzdWx0OiB7IGV2ZW50cz86IHJlYWRvbmx5IEV2ZW50W107IGhhc01vcmU/OiBib29sZWFuIH1cbik6IFNraXBwZWRTbG90UmVwb3J0IHtcbiAgY29uc3Qgb2ZmZXJlZCA9IHJlc3VsdC5ldmVudHM/Lmxlbmd0aCA/PyAwO1xuICBpZiAob2ZmZXJlZCA9PT0gMCkge1xuICAgIHJldHVybiB7IGFkZGVkOiAwLCBvZmZlcmVkOiAwLCB0cnVuY2F0ZWQ6IGZhbHNlIH07XG4gIH1cbiAgaWYgKHJlc3VsdC5oYXNNb3JlID09PSB0cnVlKSB7XG4gICAgcmV0dXJuIHsgYWRkZWQ6IDAsIG9mZmVyZWQsIHRydW5jYXRlZDogdHJ1ZSB9O1xuICB9XG4gIHJldHVybiB7XG4gICAgYWRkZWQ6IG1lcmdlUmVwb3J0ZWRFdmVudHModGFyZ2V0LCByZXN1bHQuZXZlbnRzID8/IFtdKSxcbiAgICBvZmZlcmVkLFxuICAgIHRydW5jYXRlZDogZmFsc2UsXG4gIH07XG59XG5cbi8qKlxuICogVGhlIGhpZ2hlc3Qgc2xvdCB0aGUgbG9hZGVkIGxvZyBvY2N1cGllcywgb3IgYHVuZGVmaW5lZGAgZm9yIGFuIGVtcHR5IGxvZy5cbiAqXG4gKiBUaGUgbWF4aW11bSwgbm90IHRoZSBjb3VudCwgYW5kIHRoZSB0d28gYXJlIG5vdCBpbnRlcmNoYW5nZWFibGUgZXZlbiB0aG91Z2hcbiAqIGEgaGVhbHRoeSBsb2cgbWFrZXMgdGhlbSBlcXVhbC4gQSBXb3JsZCBoYW5kcyBhIHBvc2l0aW9uIHRvIHRoZSBpbnNlcnQgdGhhdFxuICogb2NjdXBpZXMgaXQsIHNvIGEgd3JpdGUgdGhhdCBuZXZlciBsYW5kcyBsZWF2ZXMgbm8gaG9sZSBiZWhpbmQgYW5kIHRoZSBsb2dcbiAqIHN0YXlzIGRlbnNlLiBXaGF0IHRoZSBjb3VudCBjYW5ub3Qgc3Vydml2ZSBpcyBhICpwYXJ0aWFsKiByZWFkOiBhIGxvZ1xuICogYXNzZW1ibGVkIGZyb20gYSB0cnVuY2F0ZWQgcmVwb3J0LCBvciByZWFkIHdoaWxlIGEgY29uY3VycmVudCB3cml0ZSBpc1xuICogY29tbWl0dGluZywgaG9sZHMgZmV3ZXIgZXZlbnRzIHRoYW4gaXRzIGhpZ2hlc3QgcG9zaXRpb24uIENvdW50aW5nIHRob3NlXG4gKiB3b3VsZCBtYWtlIHRoZSBuZXh0IHdyaXRlIGNsYWltIHRvIGhhdmUgc2VlbiBsZXNzIHRoYW4gaXQgaGFzLCBzbyB0aGUgV29ybGRcbiAqIHdvdWxkIHJlcG9ydCB0aGUgc2FtZSBldmVudHMgYmFjayB0byBpdCBvbiBldmVyeSBhdHRlbXB0LlxuICpcbiAqIEEgaG9sZSBiZWxvdyB0aGUgbWF4aW11bSBpcyB0aGVyZWZvcmUgYSBwcm9wZXJ0eSBvZiB0aGUgcmVhZCwgbm90IG9mIHRoZSBsb2csXG4gKiB3aGljaCBpcyB3aGF0IGxldHMge0BsaW5rIHNldHRsZUV2ZW50U2xvdEdhcH0gcmUtcmVhZCBpbnN0ZWFkIG9mIGdpdmluZyB1cC5cbiAqXG4gKiBAdGhyb3dzIGlmIGFueSBldmVudCBpZCBjYXJyaWVzIG5vIHNsb3QuIEV2ZXJ5IFdvcmxkIHRoZSBydW50aW1lIHJlcGxheXNcbiAqIGFnYWluc3QgbnVtYmVycyBldmVudHMgYnkgc2xvdCwgc28gYW4gaWQgdGhhdCBkb2VzIG5vdCBpcyBhIGJyb2tlbiBsb2cgcmF0aGVyXG4gKiB0aGFuIGFuIG9sZGVyIG9uZSwgYW5kIGEgbWF4aW11bSBkZXJpdmVkIGJ5IHNraXBwaW5nIGl0IHdvdWxkIHVuZGVyc3RhdGUgdGhlXG4gKiBsb2cgdG8gZXZlcnkgd3JpdGUgdGhhdCByZWFkcyBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1heEV2ZW50U2xvdChldmVudHM6IHJlYWRvbmx5IEV2ZW50W10pOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICBsZXQgbWF4OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgY29uc3Qgc2xvdCA9IHJlcXVpcmVFdmVudFNsb3QoZXZlbnQuZXZlbnRJZCk7XG4gICAgaWYgKG1heCA9PT0gdW5kZWZpbmVkIHx8IHNsb3QgPiBtYXgpIHtcbiAgICAgIG1heCA9IHNsb3Q7XG4gICAgfVxuICB9XG4gIHJldHVybiBtYXg7XG59XG5cbi8qKiBBIHBvc2l0aW9uIHRoZSBsb2cgc2tpcHMgb3ZlciwgZGVzY3JpYmVkIHdlbGwgZW5vdWdoIHRvIG5hbWUgaW4gYW4gZXJyb3IuICovXG5leHBvcnQgaW50ZXJmYWNlIEV2ZW50U2xvdEdhcCB7XG4gIC8qKiBUaGUgbG93ZXN0IHNsb3QgYmVsb3cgdGhlIGxvZydzIG1heGltdW0gdGhhdCBubyBldmVudCBvY2N1cGllcy4gKi9cbiAgZmlyc3RNaXNzaW5nU2xvdDogbnVtYmVyO1xuICAvKiogSG93IG1hbnkgc2xvdHMgYmVsb3cgdGhlIG1heGltdW0gbm8gZXZlbnQgb2NjdXBpZXMuICovXG4gIG1pc3NpbmdDb3VudDogbnVtYmVyO1xuICAvKiogVGhlIGhpZ2hlc3Qgc2xvdCB0aGUgbG9nIG9jY3VwaWVzLiAqL1xuICBtYXhTbG90OiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIGhvbGUgaW4gYSBsb2FkZWQgbG9nLCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vbmUgdG8gZmluZC5cbiAqXG4gKiBUaGUgV29ybGQgYWxsb2NhdGVzIGV2ZXJ5IHBvc2l0aW9uLCBzbyBhIGxvZyB0aGF0IGhvbGRzIGBuYCBldmVudHMgYmVsb3cgc2xvdFxuICogYG5gIGlzIG1pc3Npbmcgb25lLiBUaGF0IG1hdHRlcnMgYmVmb3JlIGEgcmVwbGF5XG4gKiBhbmQgbm93aGVyZSBlbHNlOiB0aGUgcmVwbGF5IHJlYWRzIHRoZSBsb2cgYXMgdGhlIGNvbXBsZXRlIHJlY29yZCBvZiB3aGF0IGhhc1xuICogaGFwcGVuZWQsIGFuZCBhbiBhYnNlbnQgcG9zaXRpb24gaXMgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSBhbiBldmVudCB0aGF0XG4gKiBuZXZlciBvY2N1cnJlZC4gVGhlIGJyYW5jaCBpdCB3b3VsZCBoYXZlIGRlY2lkZWQgZ2V0cyBkZWNpZGVkIHRoZSBvdGhlciB3YXksXG4gKiBhbmQgdGhlIHJ1biBkaXZlcmdlcyBxdWlldGx5IHJhdGhlciB0aGFuIGZhaWxpbmcuXG4gKlxuICogT3JkZXItaW5kZXBlbmRlbnQsIHVubGlrZSB0aGUgZXF1aXZhbGVudCBhdWRpdCB0aGUgV29ybGQgcnVucyBvdmVyIGEgcGFnZSBpdFxuICoganVzdCByZWFkLiBBIGxvYWRlZCBsb2cgaXMgYXNzZW1ibGVkIGZyb20gbGlzdGVkIHBhZ2VzIHBsdXMgd2hhdGV2ZXIgYVxuICogYnVtcC1hbmQtcmVwb3J0IHdyaXRlIGhhbmRlZCBiYWNrLCBhbmQgd2hpbGUge0BsaW5rIG1lcmdlUmVwb3J0ZWRFdmVudHN9XG4gKiByZXN0b3JlcyBpZCBvcmRlciwgYSBjaGVjayB0aGF0IGNhbiBmYWlsIGEgaGVhbHRoeSBydW4gc2hvdWxkIG5vdCBkZXBlbmQgb25cbiAqIHRoYXQgaGF2aW5nIGhhcHBlbmVkLlxuICpcbiAqIFRoZSBmaXJzdCBzbG90IGlzIG5ldmVyIGNvdW50ZWQuIEl0IGJlbG9uZ3MgdG8gYHJ1bl9jcmVhdGVkYCwgd2hpY2ggYHN0YXJ0KClgXG4gKiBwb3N0cyBjb25jdXJyZW50bHkgd2l0aCB0aGUgcXVldWUgc2VuZCwgc28gYSBsb2cgcmVhZCBpbiB0aGF0IHdpbmRvd1xuICogbGVnaXRpbWF0ZWx5IGJlZ2lucyBhdCB0aGUgc2Vjb25kIHNsb3QgYW5kIGZpbGxzIGluIG9uIGl0cyBvd24uIEV2ZXJ5IHJlcGxheVxuICogdGhhdCByYWNlcyBhIHJ1bidzIG93biBzdGFydCB3b3VsZCBvdGhlcndpc2UgcmVwb3J0IGEgaG9sZS5cbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIGZvciBhbiBlbXB0eSBsb2csIHdoaWNoIGhhcyBubyBkZW5zaXR5IHRvIGNoZWNrLlxuICpcbiAqIEB0aHJvd3MgaWYgYW55IGV2ZW50IGlkIGNhcnJpZXMgbm8gc2xvdCwgZm9yIHRoZSByZWFzb24ge0BsaW5rIG1heEV2ZW50U2xvdH1cbiAqIGdpdmVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZmluZEV2ZW50U2xvdEdhcChcbiAgZXZlbnRzOiByZWFkb25seSBFdmVudFtdXG4pOiBFdmVudFNsb3RHYXAgfCB1bmRlZmluZWQge1xuICBjb25zdCBvY2N1cGllZCA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICBsZXQgbWF4U2xvdCA9IDA7XG4gIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgY29uc3Qgc2xvdCA9IHJlcXVpcmVFdmVudFNsb3QoZXZlbnQuZXZlbnRJZCk7XG4gICAgb2NjdXBpZWQuYWRkKHNsb3QpO1xuICAgIGlmIChzbG90ID4gbWF4U2xvdCkge1xuICAgICAgbWF4U2xvdCA9IHNsb3Q7XG4gICAgfVxuICB9XG4gIGlmIChtYXhTbG90ID09PSAwKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBjb25zdCBmbG9vciA9IG9jY3VwaWVkLmhhcyhGSVJTVF9FVkVOVF9TTE9UKVxuICAgID8gRklSU1RfRVZFTlRfU0xPVFxuICAgIDogRklSU1RfRVZFTlRfU0xPVCArIDE7XG4gIC8vIEV2ZXJ5IHNsb3QgaXMgYXQgb3IgYWJvdmUgYGZsb29yYCBieSBjb25zdHJ1Y3Rpb24sIHNvIHRoZSBsb2cgaXMgZGVuc2VcbiAgLy8gZXhhY3RseSB3aGVuIGl0IGhvbGRzIG9uZSBldmVudCBwZXIgcG9zaXRpb24gaW4gYFtmbG9vciwgbWF4U2xvdF1gLiBUaGVcbiAgLy8gc2NhbiBiZWxvdyBvbmx5IHJ1bnMgb25jZSB0aGF0IGhhcyBhbHJlYWR5IGFuc3dlcmVkIG5vLlxuICBpZiAob2NjdXBpZWQuc2l6ZSA9PT0gbWF4U2xvdCAtIGZsb29yICsgMSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgbGV0IGZpcnN0TWlzc2luZ1Nsb3Q6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgbGV0IG1pc3NpbmdDb3VudCA9IDA7XG4gIGZvciAobGV0IHNsb3QgPSBmbG9vcjsgc2xvdCA8PSBtYXhTbG90OyBzbG90KyspIHtcbiAgICBpZiAoIW9jY3VwaWVkLmhhcyhzbG90KSkge1xuICAgICAgZmlyc3RNaXNzaW5nU2xvdCA/Pz0gc2xvdDtcbiAgICAgIG1pc3NpbmdDb3VudCsrO1xuICAgIH1cbiAgfVxuICBpZiAoZmlyc3RNaXNzaW5nU2xvdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4geyBmaXJzdE1pc3NpbmdTbG90LCBtaXNzaW5nQ291bnQsIG1heFNsb3QgfTtcbn1cblxuLyoqXG4gKiBIb3cgbWFueSB0aW1lcyBhIGRldGVjdGVkIGhvbGUgaXMgcmUtcmVhZCBiZWZvcmUgdGhlIGxvZyBpcyB0YWtlbiBhdCBpdHNcbiAqIHdvcmQsIGFuZCB0aGUgYmFja29mZiBiZWZvcmUgZWFjaCByZS1yZWFkIChkb3VibGluZyBwZXIgYXR0ZW1wdCkuXG4gKlxuICogQSBob2xlIGNhbiBiZSB0cmFuc2llbnQuIFRoZSBXb3JsZCBhbGxvY2F0ZXMgYSBzbG90IGluc2lkZSB0aGUgaW5zZXJ0IHRoYXRcbiAqIG9jY3VwaWVzIGl0LCBzbyB0d28gY29uY3VycmVudCB3cml0ZXJzIGNhbiBjb2xsaWRlLCBvbmUgcmV0cnkgcGFzdCB0aGUgb3RoZXIsXG4gKiBhbmQgdGhlIGhpZ2hlciBzbG90IGNvbW1pdCBmaXJzdCwgbGVhdmluZyBhIHdpbmRvdyBpbiB3aGljaCB0aGUgbG93ZXIgb25lIGlzXG4gKiBnZW51aW5lbHkgYWJzZW50IGZyb20gYSBzdHJvbmdseS1jb25zaXN0ZW50IHJlYWQgYW5kIGZpbGxzIGluIGEgbW9tZW50IGxhdGVyLlxuICogVGhlIHdpbmRvdyBpcyBvbmUgY29tbWl0IHdpZGUsIHNvIGEgc2hvcnQgYmFja29mZiBjbGVhcnMgaXQ7IGFueXRoaW5nIHRoYXRcbiAqIHN1cnZpdmVzIGFsbCB0aHJlZSByZS1yZWFkcyBpcyBhIHBvc2l0aW9uIG5vIHdyaXRlIHdpbGwgZXZlciBvY2N1cHkuXG4gKi9cbmV4cG9ydCBjb25zdCBTTE9UX0dBUF9SRUNIRUNLX0FUVEVNUFRTID0gMztcbmNvbnN0IFNMT1RfR0FQX1JFQ0hFQ0tfQkFTRV9ERUxBWV9NUyA9IDI1O1xuXG4vKipcbiAqIFJlLXJlYWQgYSBsb2cgdGhhdCBsb29rcyBob2xleSB1bnRpbCB0aGUgaG9sZSBmaWxscyBpbiBvciB0aGUgcmUtcmVhZHMgcnVuXG4gKiBvdXQsIGFuZCByZXR1cm4gdGhlIHNldHRsZWQgbG9nIGFsb25nc2lkZSB0aGUgaG9sZSB0aGF0IHN1cnZpdmVkLlxuICpcbiAqIFJlYWRzIGFyZSBzdHJvbmdseSBjb25zaXN0ZW50LCBzbyBhIGhvbGUgaXMgbm90IGFuIGFydGlmYWN0IG9mICp3aGVuKiB0aGUgbG9nXG4gKiB3YXMgcmVhZCwgYnV0IGl0IGNhbiBiZSBhbiBhcnRpZmFjdCBvZiBhIHdyaXRlIHRoYXQgaGFkIG5vdCBjb21taXR0ZWQgeWV0XG4gKiAoc2VlIHtAbGluayBTTE9UX0dBUF9SRUNIRUNLX0FUVEVNUFRTfSkuIERpc3Rpbmd1aXNoaW5nIHRoZSB0d28gY29zdHMgYVxuICogcmUtcmVhZCwgd2hpY2ggaXMgb25seSBldmVyIHBhaWQgYnkgYSByZXBsYXkgdGhhdCBhbHJlYWR5IGZvdW5kIGEgaG9sZS5cbiAqXG4gKiBUaGUgcmVsb2FkIGlzIGZ1bGwgcmF0aGVyIHRoYW4gaW5jcmVtZW50YWw6IHRoZSBtaXNzaW5nIHBvc2l0aW9uIGlzIGJlbG93IHRoZVxuICogbG9nJ3MgbWF4aW11bSwgc28gYSBjdXJzb3ItYW5jaG9yZWQgcmVhZCBzdGFydHMgcGFzdCBpdCBhbmQgY2FuIG5ldmVyIHNlZSBpdFxuICogYXJyaXZlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2V0dGxlRXZlbnRTbG90R2FwKFxuICBydW5JZDogc3RyaW5nLFxuICBsb2FkZWQ6IExvYWRlZEV2ZW50TG9nXG4pOiBQcm9taXNlPHsgbG9nOiBMb2FkZWRFdmVudExvZzsgZ2FwOiBFdmVudFNsb3RHYXAgfCB1bmRlZmluZWQgfT4ge1xuICBsZXQgbG9nID0gbG9hZGVkO1xuICBsZXQgZ2FwID0gZmluZEV2ZW50U2xvdEdhcChsb2cuZXZlbnRzKTtcbiAgZm9yIChcbiAgICBsZXQgYXR0ZW1wdCA9IDA7XG4gICAgZ2FwICE9PSB1bmRlZmluZWQgJiYgYXR0ZW1wdCA8IFNMT1RfR0FQX1JFQ0hFQ0tfQVRURU1QVFM7XG4gICAgYXR0ZW1wdCsrXG4gICkge1xuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBTTE9UX0dBUF9SRUNIRUNLX0JBU0VfREVMQVlfTVMgKiAyICoqIGF0dGVtcHQpXG4gICAgKTtcbiAgICBsb2cgPSBhd2FpdCBsb2FkV29ya2Zsb3dSdW5FdmVudHMocnVuSWQpO1xuICAgIGdhcCA9IGZpbmRFdmVudFNsb3RHYXAobG9nLmV2ZW50cyk7XG4gIH1cbiAgcmV0dXJuIHsgbG9nLCBnYXAgfTtcbn1cblxuLyoqXG4gKiBIb3cgbXVjaCBvZiBpdHMgcnVuJ3MgbG9nIGEgcmVwbGF5LWNvbnRleHQgZXZlbnQgY3JlYXRpb24gaGFkIGxvYWRlZCB3aGVuIGl0XG4gKiBkZWNpZGVkIHRvIHdyaXRlLCBhcyB0aGUgaGlnaGVzdCBzbG90IHRoYXQgbG9nIG9jY3VwaWVzLlxuICpcbiAqIE9uZSBpbnRlZ2VyIHNheXMgaXQgYmVjYXVzZSB0aGUgV29ybGQga2VlcHMgaXRzIHBvc2l0aW9ucyBkZW5zZTogYSB3cml0ZXJcbiAqIHRoYXQgbmFtZXMgc2xvdCBOIGlzIGNsYWltaW5nIHRvIGhvbGQgZXZlcnkgZXZlbnQgZnJvbSAxIHRvIE4gYW5kIG5vdGhpbmdcbiAqIGFib3ZlLiBUaGUgV29ybGQgYW5zd2VycyBieSBudW1iZXJpbmcgdGhlIHdyaXRlIGFib3ZlIHdoYXRldmVyIHRoZSBsb2cgaGFzXG4gKiBhY3R1YWxseSByZWFjaGVkIGFuZCBoYW5kaW5nIGJhY2sgdGhlIGV2ZW50cyBvbiB0aGUgc2xvdHMgaW4gYmV0d2VlbjogdGhlXG4gKiBvbmVzIHRoaXMgd3JpdGVyIGRlY2lkZWQgd2l0aG91dC5cbiAqXG4gKiBEZW5zaXR5IGlzIHRoZSBXb3JsZCdzIGludmFyaWFudCwgbm90IGEgY2xhaW0gYWJvdXQgdGhpcyBwYXJ0aWN1bGFyIHJlYWQuIEFcbiAqIHJlYWRlciB0aGF0IGlzIHNob3J0IG9mIGEgcG9zaXRpb24gaXQgaG9sZHMgbm8gZXZlbnQgZm9yIG5hbWVzIGEgbG93ZXIgTixcbiAqIHdoaWNoIHVuZGVyc3RhdGVzIHdoYXQgaXQgaGFzIHNlZW4gYW5kIG9ubHkgY29zdHMgaXQgYSB3aWRlciByZXBvcnQuIE5hbWluZ1xuICogYSBwb3NpdGlvbiBpdCBjYW5ub3QgYWNjb3VudCBmb3IgaXMgdGhlIGRpcmVjdGlvbiB0aGF0IGlzIHVuc2FmZSwgd2hpY2ggaXNcbiAqIHdoeSB7QGxpbmsgc2xvdFNuYXBzaG90UGFyYW1zfSB0YWtlcyB0aGUgbWF4aW11bSByYXRoZXIgdGhhbiB0aGUgY291bnQuXG4gKlxuICogSXRzIG93biBvYmplY3QgcmF0aGVyIHRoYW4gYSBiYXJlIG51bWJlciBzbyBhIGNhbGwgc2l0ZSBjYW5ub3QgaGFsZi1zZW5kIGl0LFxuICogYW5kIHNvIHRoZSBlbXB0eSBjYXNlIHNwcmVhZHMgdG8gbm90aGluZy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTbG90U25hcHNob3RQYXJhbXMge1xuICBldmVudENvdW50PzogbnVtYmVyO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBzbG90IHNuYXBzaG90IHRvIGF0dGFjaCB0byBhIHJlcGxheS1jb250ZXh0IGV2ZW50IGNyZWF0aW9uLlxuICpcbiAqIEVtcHR5IGZvciBhbiBlbXB0eSBsb2csIHdoaWNoIGlzIHRoZSBzdGF0ZSBhIGBydW5fY3JlYXRlZGAgd3JpdGUgaXMgaXNzdWVkXG4gKiBmcm9tOiB0aGVyZSBpcyBubyBwb3NpdGlvbiBoZWxkIHlldCB0byBuYW1lLlxuICpcbiAqICMjIFdobyBuYW1lcyBhIHBvc2l0aW9uXG4gKlxuICogQSBXb3JsZCBjYW4gaGFuZCBldmVudHMgYmFjayBvbiBhIHdyaXRlJ3Mgc3VjY2VzcyByZXNwb25zZSB0aHJvdWdoIHR3b1xuICogcGFyYW1zIChgQ3JlYXRlRXZlbnRQYXJhbXNgIGluIGBAd29ya2Zsb3cvd29ybGRgKTogYGV2ZW50Q291bnRgLCB3aGljaCBpc1xuICogYW5zd2VyZWQgd2l0aCB0aGUgZXZlbnRzIG9uIHRoZSBwb3NpdGlvbnMgdGhlIHdyaXRlIHNraXBwZWQgb3ZlciAodGhlXG4gKiBza2lwcGVkLXNsb3QgcmVwb3J0KSwgYW5kIGBzaW5jZUN1cnNvcmAsIHdoaWNoIGlzIGFuc3dlcmVkIHdpdGggZXZlcnl0aGluZ1xuICogYWZ0ZXIgdGhhdCBjdXJzb3IgKHRoZSBpbmxpbmUgZGVsdGEpLiBCb3RoIGV4aXN0IHRvIHNhdmUgdGhlIHdyaXRlciBhXG4gKiByZWxvYWQuIFNvIHRoZSBydWxlIGZvciB3aGljaCB3cml0ZXMgc2VuZCB0aGVtIGlzIG5vdCBhYm91dCB0aGUgZXZlbnQgdHlwZTtcbiAqIGl0IGlzIGFib3V0IHdoZXRoZXIgKip0aGUgcHJvY2VzcyB0aGF0IHdyaXRlcyBob2xkcyBhIGxvYWRlZCBsb2cgaXQgd2lsbFxuICoga2VlcCBkZWNpZGluZyBmcm9tKiosIGl0cyBvd24gbmV4dCB3cml0ZXMgb3IgdGhlIHJlcGxheSBpdCByZXN1bWVzLiBBIHdyaXRlclxuICogd2l0aCBubyBsb2cgaGFzIG5vdGhpbmcgdG8gbWVyZ2UgYSBwYWdlIGludG8sIGFuZCB3aG9ldmVyIGRlY2lkZXMgbmV4dCBpcyBhXG4gKiBmcmVzaCByZXBsYXkgdGhhdCBsb2FkcyB0aGUgbG9nIGFueXdheS5cbiAqXG4gKiBUaHJlZSBnYXRlcywgYWxsIG9mIHdoaWNoIG11c3QgcGFzcyBmb3IgYSBwYWdlIHRvIGNvbWUgYmFjazpcbiAqXG4gKiAxLiBUaGUgd3JpdGVyIG5hbWVzIGEgcG9zaXRpb24uIE9ubHkgdGhlIHJlcGxheSBsb29wJ3MgYGNyZWF0ZUV2ZW50YCBzZWFtXG4gKiAgICAocnVudGltZS50cykgYW5kIHRoZSBzdXNwZW5zaW9uIGhhbmRsZXIncyBgY3JlYXRlR3VhcmRlZGAgZG87IHRoZSBRdWlja0pTXG4gKiAgICBlbmdpbmUncyBgY3JlYXRlRXZlbnRgIChxdWlja2pzLWVudHJ5cG9pbnQudHMpIGZvbGxvd3MgdGhlIHNhbWUgcnVsZS4gUmF3XG4gKiAgICBgd29ybGQuZXZlbnRzLmNyZWF0ZWAgY2FsbHMgc2VuZCBub3RoaW5nLlxuICogMi4gVGhlIFdvcmxkIHJlYWRzIGEgcGFnZSBmb3IgdGhhdCBldmVudCB0eXBlLiBBIFdvcmxkIG1heSBkZWNsaW5lIGZvciB0eXBlc1xuICogICAgd2hvc2Ugd3JpdGVyIG5ldmVyIGhvbGRzIGEgbG9nIChzdGVwIGV4ZWN1dG9yIHdyaXRlcywgcnVuLXRlcm1pbmFsXG4gKiAgICB3cml0ZXMpLCB3aGF0ZXZlciB0aGUgY2xpZW50IHNlbnQuXG4gKiAzLiBUaGVyZSBpcyBzb21ldGhpbmcgdG8gaGFuZCBiYWNrOiB0aGUgcmVwb3J0IG9ubHkgd2hlbiB0aGUgd3JpdGUgbGFuZGVkXG4gKiAgICBtb3JlIHRoYW4gb25lIHBvc2l0aW9uIGFib3ZlIGBldmVudENvdW50YDsgdGhlIGRlbHRhIGFsd2F5cy5cbiAqXG4gKiB8IEV2ZW50IHwgV3JpdGVyIHwgU2VuZHMgfCBXaHkgfFxuICogfC0tLXwtLS18LS0tfC0tLXxcbiAqIHwgYHJ1bl9jcmVhdGVkYCB8IGBzdGFydCgpYCB8IG5vdGhpbmcgfCBubyBsb2cgZXhpc3RzIHlldCB8XG4gKiB8IGBydW5fc3RhcnRlZGAgfCByZXBsYXkgbG9vcCwgZmlyc3Qgd3JpdGUgb2YgYSBkZWxpdmVyeSB8IGBldmVudENvdW50YCB3aGVuIGEgbG9nIGlzIGxvYWRlZDsgbm8gY3Vyc29yLCB0aGUgYHJ1bl9zdGFydGVkYCBwcmVsb2FkIG93bnMgdGhlIHJlc3BvbnNlIGZpZWxkcyB8IHRoZSBwcmVsb2FkIGFscmVhZHkgcmV0dXJucyB0aGUgZnVsbCBsb2cgfFxuICogfCBgc3RlcF9jcmVhdGVkYCwgYHdhaXRfY3JlYXRlZGAsIGBob29rX2Rpc3Bvc2VkYCwgYGF0dHJfc2V0YCB8IHN1c3BlbnNpb24gaGFuZGxlciAoYGNyZWF0ZUd1YXJkZWRgKSB8IGBldmVudENvdW50YCB8IHRoZSBoYW5kbGVyIGtlZXBzIHdyaXRpbmcgZnJvbSwgYW5kIHJlc3VtZXMgcmVwbGF5IGZyb20sIHRoaXMgbG9nIHxcbiAqIHwgYHN0ZXBfY3JlYXRlZGAgfCBxdWV1ZS1jb25zdW1lciByZS1lbnN1cmUgKHJhdykgfCBub3RoaW5nIHwgcnVucyBmcm9tIGEgcXVldWUgbWVzc2FnZSwgbm8gbG9nIHxcbiAqIHwgYGhvb2tfY3JlYXRlZGAgfCBzdXNwZW5zaW9uIGhhbmRsZXIgKG5vZGUpLCBgZGlzcGF0Y2hQZW5kaW5nT3BzYCAoUXVpY2tKUykgfCBgZXZlbnRDb3VudGAgKyBgc2luY2VDdXJzb3JgIChvbmx5IHdoZW4gdGhlIHN1c3BlbnNpb24gY3JlYXRlcyBleGFjdGx5IG9uZSBob29rKSB8IHRoZSBkZWx0YSBpcyBob3cgYW4gYWxyZWFkeS1yZWNlaXZlZCBob29rIHJlc29sdmVzIHdpdGhvdXQgYSByZS1pbnZvY2F0aW9uOyB0d28gY3JlYXRlcyBhZ2FpbnN0IG9uZSBjdXJzb3Igd291bGQgZ2l2ZSB0d28gZGVsdGFzIG9mIHdoaWNoIG9ubHkgdGhlIGZpcnN0IGNvdWxkIGJlIHRha2VuIHxcbiAqIHwgYGhvb2tfcmVjZWl2ZWRgIHwgcmVwbGF5IGxvb3AgbGF6eSByZXN1bWU7IGhhbmRsZXIgaW4tc3VzcGVuc2lvbiByZXN1bWUgfCBgZXZlbnRDb3VudGAgKHByZWxvYWQgb3ducyB0aGUgY3Vyc29yIGZpZWxkcykgfCBib3RoIHJlcGxheSBmcm9tIHRoZSBsb2cgcmlnaHQgYWZ0ZXIgfFxuICogfCBgaG9va19yZWNlaXZlZGAgfCB3ZWJob29rIC8gYHJlc3VtZUhvb2tgIChyYXcpIHwgbm90aGluZyB8IG91dC1vZi1iYW5kLCBlbnF1ZXVlcyBhIGRlbGl2ZXJ5IHRoYXQgbG9hZHMgdGhlIGxvZyB8XG4gKiB8IGB3YWl0X2NvbXBsZXRlZGAgfCByZXBsYXkgbG9vcCB0aW1lciBwYXRoIHwgYGV2ZW50Q291bnRgIHwgdGhlIGxvb3Aga2VlcHMgcmVwbGF5aW5nIGZyb20gdGhlIGxvZyB8XG4gKiB8IGB3YWl0X2NvbXBsZXRlZGAgfCBgcnVucy4qYCBvdXQtb2YtYmFuZCAocmF3KSB8IG5vdGhpbmcgfCBubyBsb2cgfFxuICogfCBgc3RlcF9zdGFydGVkYCwgYHN0ZXBfcmV0cnlpbmdgIHwgc3RlcCBleGVjdXRvciB8IG5vdGhpbmcgfCBubyBsb2c7IHRoZSBuZXh0IGRlY2lzaW9uIGlzIGEgcmVwbGF5IHRoYXQgcmVsb2FkcyBvciByZWNlaXZlcyB0aGUgZGVsdGEgYmVsb3cgfFxuICogfCBgc3RlcF9jb21wbGV0ZWRgLCBgc3RlcF9mYWlsZWRgIHwgc3RlcCBleGVjdXRvciB8IGBzaW5jZUN1cnNvcmAgb25seSwgb3V0c2lkZSB0dXJibywgc2luZ2xlIGlubGluZSBzdGVwIHwgdGhpcyBpcyB3aGVyZSB0aGUgaW5saW5lIGV4ZWN1dGlvbiBsb29wIGdldHMgaXRzIGxvZyBiYWNrOyBpbiB0dXJibyBvciBmcm9tIGEgcXVldWVkIGRlbGl2ZXJ5IGEgZnJlc2ggcmVwbGF5IGxvYWRzIGl0IGFueXdheSB8XG4gKiB8IGBzdGVwX2ZhaWxlZGAgfCBzdXNwZW5zaW9uIGhhbmRsZXIsIHVuc2VyaWFsaXphYmxlIGlucHV0IHwgYGV2ZW50Q291bnRgIHwgdGhlIGhhbmRsZXIgaG9sZHMgYSBsb2c7IHJhcmUsIGFuZCBmb2xsb3dzIGEgYHN0ZXBfY3JlYXRlZGAgdGhhdCBkcmV3IHRoZSBwYWdlIHxcbiAqIHwgYGF0dHJfc2V0YCB8IGBzZXRBdHRyaWJ1dGVzKClgIEFQSSAocmF3KSB8IG5vdGhpbmcgfCBvdXQtb2YtYmFuZCB8XG4gKiB8IGBydW5fY29tcGxldGVkYCwgYHJ1bl9mYWlsZWRgLCBgcnVuX2NhbmNlbGxlZGAgfCByZXBsYXkgbG9vcCwgcmVwbGF5IGJ1ZGdldCwgYHJ1bnMuY2FuY2VsYCB8IGBldmVudENvdW50YCB3aGVyZSB0aGUgbm9kZSBsb29wJ3Mgc2VhbSBzdGFtcHMgaXQgKHRoZSBRdWlja0pTIGVuZ2luZSBzZW5kcyBub3RoaW5nKTsgbmV2ZXIgYHNpbmNlQ3Vyc29yYCAoYGRlbHRhUmVxdWVzdEN1cnNvcmAgZXhjbHVkZXMgdGVybWluYWwgdHlwZXMpIHwgdGVybWluYWw6IG5vdGhpbmcgcmVwbGF5cyB0aGUgbG9nIGFmdGVyd2FyZHMsIHNvIGEgV29ybGQgcmVhZHMgbm8gcGFnZSBmb3IgdGhlbSB8XG4gKlxuICogQmF0Y2hlZCB3cml0ZXMgKGBldmVudHMuY3JlYXRlQmF0Y2hgKSBhcmUgb3V0c2lkZSBhbGwgb2YgdGhpczogYSBiYXRjaCBjYXJyaWVzXG4gKiBubyBwZXItZXZlbnQgcG9zaXRpb24gYW5kIGdldHMgbm8gcGFnZS4gVGhlIHVzZXItZmFjaW5nIHZlcnNpb24gb2YgdGhpcyB0YWJsZVxuICogaXMgaW4gYGRvY3MvY29udGVudC9kb2NzL3Y1L2hvdy1pdC13b3Jrcy9ldmVudC1zb3VyY2luZy5tZHhgOyBrZWVwIHRoZSB0d28gaW5cbiAqIHN0ZXAuXG4gKlxuICogVGhlIG1heGltdW0gcmF0aGVyIHRoYW4gdGhlIGxlbmd0aCwgZm9yIHRoZSByZWFzb24ge0BsaW5rIG1heEV2ZW50U2xvdH1cbiAqIGdpdmVzOiBhIHBhcnRpYWxseS1yZWFkIGxvZyBob2xkcyBmZXdlciBldmVudHMgdGhhbiBpdHMgaGlnaGVzdCBwb3NpdGlvbiwgYW5kXG4gKiBjb3VudGluZyB0aG9zZSB3b3VsZCBtYWtlIHRoZSB3cml0ZSBjbGFpbSB0byBoYXZlIHNlZW4gbGVzcyB0aGFuIGl0IGhhcywgc29cbiAqIHRoZSBXb3JsZCB3b3VsZCByZXBvcnQgdGhlIHNhbWUgZXZlbnRzIGJhY2sgb24gZXZlcnkgYXR0ZW1wdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNsb3RTbmFwc2hvdFBhcmFtcyhcbiAgZXZlbnRzOiByZWFkb25seSBFdmVudFtdXG4pOiBTbG90U25hcHNob3RQYXJhbXMge1xuICBjb25zdCBldmVudENvdW50ID0gbWF4RXZlbnRTbG90KGV2ZW50cyk7XG4gIHJldHVybiBldmVudENvdW50ID09PSB1bmRlZmluZWQgPyB7fSA6IHsgZXZlbnRDb3VudCB9O1xufVxuXG4vKipcbiAqIFRoZSBldmVudHMgYSByZWplY3RpbmcgV29ybGQgYXR0YWNoZWQgdG8gYSBgUHJlY29uZGl0aW9uRmFpbGVkRXJyb3JgLCB3aGVuIGl0XG4gKiByZXR1cm5lZCB0aGUgb25lcyB0aGUgY2xpZW50J3Mgc25hcHNob3Qgd2FzIG1pc3NpbmcgaW5saW5lLlxuICpcbiAqIFJldHVybnMgYG51bGxgIGZvciBhbnl0aGluZyBlbHNlOiBubyBkZXRhaWxzLCBhIFdvcmxkIHRoYXQgZGlkIG5vdCBpbXBsZW1lbnRcbiAqIHRoaXMsIG9yIGEgcGF5bG9hZCB0aGF0IGRvZXMgbm90IG5hcnJvdyBjbGVhbmx5LiBDYWxsZXJzIGZhbGwgYmFjayB0b1xuICogcmVsb2FkaW5nIHRoZSBldmVudCBsb2csIHdoaWNoIGlzIGFsd2F5cyBjb3JyZWN0OyB0aGlzIGlzIHVudHJ1c3RlZC1zaGFwZWRcbiAqIGRhdGEgb24gYSBmYWlsdXJlIHBhdGgsIHNvIG5vdGhpbmcgaGVyZSBpcyByZXBhaXJlZC5cbiAqXG4gKiBgcnVuSWRgIGlzIHRoZSBjYWxsZXIncyBydW4uIEV2ZXJ5IGV2ZW50IG11c3QgYmVsb25nIHRvIGl0OiB0aGUgZGVsdGEgaXNcbiAqIG1lcmdlZCBzdHJhaWdodCBpbnRvIHRoZSByZXBsYXkncyBsb2csIGFuZCBvbmUgZm9yZWlnbiBldmVudCB0aGVyZSBpcyBhXG4gKiBjb3JydXB0IGxvZyByYXRoZXIgdGhhbiBhIGNvcnJlY3RlZCBvbmU6IHRoZSByZXBsYXkgd291bGQgY29uc3VtZSBhXG4gKiBjb3JyZWxhdGlvbiBpZCBmb3IgYW4gZXZlbnQgdGhhdCBkb2VzIG5vdCBleGlzdCBvbiB0aGlzIHJ1bi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZWNvbmRpdGlvbkV2ZW50RGVsdGEoXG4gIGVycm9yOiB1bmtub3duLFxuICBydW5JZDogc3RyaW5nXG4pOiB7IGV2ZW50czogRXZlbnRbXTsgY3Vyc29yOiBzdHJpbmcgfCBudWxsIH0gfCBudWxsIHtcbiAgaWYgKCFQcmVjb25kaXRpb25GYWlsZWRFcnJvci5pcyhlcnJvcikpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCBkZXRhaWxzID0gZXJyb3IuZGV0YWlscztcbiAgaWYgKHR5cGVvZiBkZXRhaWxzICE9PSAnb2JqZWN0JyB8fCBkZXRhaWxzID09PSBudWxsKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3QgeyBldmVudHMsIGN1cnNvciB9ID0gZGV0YWlscyBhcyB7IGV2ZW50cz86IHVua25vd247IGN1cnNvcj86IHVua25vd24gfTtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGV2ZW50cykgfHwgZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIGV2ZW50ICE9PSAnb2JqZWN0JyB8fFxuICAgICAgZXZlbnQgPT09IG51bGwgfHxcbiAgICAgIHR5cGVvZiAoZXZlbnQgYXMgeyBldmVudElkPzogdW5rbm93biB9KS5ldmVudElkICE9PSAnc3RyaW5nJyB8fFxuICAgICAgKGV2ZW50IGFzIHsgcnVuSWQ/OiB1bmtub3duIH0pLnJ1bklkICE9PSBydW5JZFxuICAgICkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG4gIHJldHVybiB7XG4gICAgZXZlbnRzOiBldmVudHMgYXMgRXZlbnRbXSxcbiAgICBjdXJzb3I6IHR5cGVvZiBjdXJzb3IgPT09ICdzdHJpbmcnID8gY3Vyc29yIDogbnVsbCxcbiAgfTtcbn1cblxuLyoqIENyZWF0ZXMgb25lIGV2ZW50IG9uIGEgYm91bmQgcnVuLCBjYXJyeWluZyByZXBsYXktcmVjb3ZlcnkgdGVsZW1ldHJ5LiAqL1xuZXhwb3J0IHR5cGUgRXZlbnRDcmVhdG9yID0gKFxuICBkYXRhOiBDcmVhdGVFdmVudFJlcXVlc3QsXG4gIHBhcmFtcz86IENyZWF0ZUV2ZW50UGFyYW1zXG4pID0+IFByb21pc2U8RXZlbnRSZXN1bHQ+O1xuXG4vKipcbiAqIENPUlMgaGVhZGVycyBmb3IgaGVhbHRoIGNoZWNrIHJlc3BvbnNlcy5cbiAqIEFsbG93cyB0aGUgb2JzZXJ2YWJpbGl0eSBVSSB0byBjaGVjayBlbmRwb2ludCBoZWFsdGggZnJvbSBhIGRpZmZlcmVudCBvcmlnaW4uXG4gKi9cbmNvbnN0IEhFQUxUSF9DSEVDS19DT1JTX0hFQURFUlMgPSB7XG4gICdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nOiAnKicsXG4gICdBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzJzogJ1BPU1QsIE9QVElPTlMsIEdFVCwgSEVBRCcsXG4gICdBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJzogJ0NvbnRlbnQtVHlwZScsXG59O1xuXG4vKipcbiAqIFdyYXBzIGEgcmVxdWVzdC9yZXNwb25zZSBoYW5kbGVyIGFuZCBhZGRzIGEgaGVhbHRoIGNoZWNrIFwibW9kZVwiXG4gKiBiYXNlZCBvbiB0aGUgcHJlc2VuY2Ugb2YgYSBgX19oZWFsdGhgIHF1ZXJ5IHBhcmFtZXRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdpdGhIZWFsdGhDaGVjayhcbiAgaGFuZGxlcjogKHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTxSZXNwb25zZT4sXG4gIHdvcmxkU3BlY1ZlcnNpb24/OiBudW1iZXJcbik6IChyZXE6IFJlcXVlc3QpID0+IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgcmV0dXJuIGFzeW5jIChyZXE6IFJlcXVlc3QpID0+IHtcbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHJlcS51cmwpO1xuICAgIGNvbnN0IGlzSGVhbHRoQ2hlY2sgPSB1cmwuc2VhcmNoUGFyYW1zLmhhcygnX19oZWFsdGgnKTtcbiAgICBpZiAoaXNIZWFsdGhDaGVjaykge1xuICAgICAgLy8gSGFuZGxlIENPUlMgcHJlZmxpZ2h0IGZvciBoZWFsdGggY2hlY2tcbiAgICAgIGlmIChyZXEubWV0aG9kID09PSAnT1BUSU9OUycpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBSZXNwb25zZShudWxsLCB7XG4gICAgICAgICAgc3RhdHVzOiAyMDQsXG4gICAgICAgICAgaGVhZGVyczogSEVBTFRIX0NIRUNLX0NPUlNfSEVBREVSUyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgaGVhbHRoeTogdHJ1ZSxcbiAgICAgICAgICBlbmRwb2ludDogdXJsLnBhdGhuYW1lLFxuICAgICAgICAgIHNwZWNWZXJzaW9uOiB3b3JsZFNwZWNWZXJzaW9uID8/IFNQRUNfVkVSU0lPTl9DVVJSRU5ULFxuICAgICAgICAgIHdvcmtmbG93Q29yZVZlcnNpb24sXG4gICAgICAgIH0pLFxuICAgICAgICB7XG4gICAgICAgICAgc3RhdHVzOiAyMDAsXG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAgIC4uLkhFQUxUSF9DSEVDS19DT1JTX0hFQURFUlMsXG4gICAgICAgICAgfSxcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGF3YWl0IGhhbmRsZXIocmVxKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgbGluZWFnZSByb290IG9mIGEgbG9hZGVkIHJ1bjogaXRzIGAkcm9vdFJ1bklkYCBhdHRyaWJ1dGUsIG9yIGl0cyBvd24gaWRcbiAqIHdoZW4gaXQgaXMgaXRzZWxmIGEgcm9vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvb3RSdW5JZEZyb20oXG4gIGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQsXG4gIHJ1bklkOiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIHJldHVybiBhdHRyaWJ1dGVzPy5bUk9PVF9SVU5fSURfQVRUUklCVVRFXSA/PyBydW5JZDtcbn1cblxuLyoqXG4gKiBUaGUgaW1tdXRhYmxlIHJ1biBpZGVudGl0eSBhIHN0ZXAtZXhlY3V0aW9uIG1lc3NhZ2UgY2FycmllcyBzbyBpdHMgY29uc3VtZXJcbiAqIGNhbiBzdGFydCB0aGUgc3RlcCB3aXRob3V0IGEgYmxvY2tpbmcgYHJ1bnMuZ2V0YCDigJQgc2VlXG4gKiBgUnVuRGlzcGF0Y2hDb250ZXh0U2NoZW1hYCBpbiBAd29ya2Zsb3cvd29ybGQuIEJ1aWx0IGF0IGRpc3BhdGNoIHRpbWUgZnJvbVxuICogdGhlIHJ1biByb3cgdGhlIHByb2R1Y2VyIGFscmVhZHkgaG9sZHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5EaXNwYXRjaENvbnRleHQoXG4gIHJ1bjogUGljazxcbiAgICBXb3JrZmxvd1J1bixcbiAgICAncnVuSWQnIHwgJ2RlcGxveW1lbnRJZCcgfCAnc3BlY1ZlcnNpb24nIHwgJ3N0YXJ0ZWRBdCcgfCAnYXR0cmlidXRlcydcbiAgPlxuKTogUnVuRGlzcGF0Y2hDb250ZXh0IHtcbiAgcmV0dXJuIHtcbiAgICBkZXBsb3ltZW50SWQ6IHJ1bi5kZXBsb3ltZW50SWQsXG4gICAgc3BlY1ZlcnNpb246IHJ1bi5zcGVjVmVyc2lvbiA/PyAwLFxuICAgIC4uLihydW4uc3RhcnRlZEF0ID8geyBzdGFydGVkQXQ6ICtydW4uc3RhcnRlZEF0IH0gOiB7fSksXG4gICAgcm9vdFJ1bklkOiByb290UnVuSWRGcm9tKHJ1bi5hdHRyaWJ1dGVzLCBydW4ucnVuSWQpLFxuICB9O1xufVxuXG4vKiogRk5WLTFhIDMyLWJpdCBoYXNoIG9mIGEgc3RyaW5nLCBhcyA4IGhleCBjaGFycy4gVGlueSwgZGV0ZXJtaW5pc3RpYywgYW5kXG4gKiAgZGVwZW5kZW5jeS1mcmVlLiBVc2VkIG9ubHkgdG8gc2NvcGUgaWRlbXBvdGVuY3kga2V5cywgbm90IGZvciBzZWN1cml0eS4gKi9cbmZ1bmN0aW9uIGZudjFhMzJIZXgodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGxldCBoYXNoID0gMHg4MTFjOWRjNTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZS5sZW5ndGg7IGkrKykge1xuICAgIGhhc2ggXj0gdmFsdWUuY2hhckNvZGVBdChpKTtcbiAgICBoYXNoID0gTWF0aC5pbXVsKGhhc2gsIDB4MDEwMDAxOTMpO1xuICB9XG4gIHJldHVybiAoaGFzaCA+Pj4gMCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDgsICcwJyk7XG59XG5cbi8qKlxuICogSWRlbXBvdGVuY3kga2V5IGZvciBhIHN0ZXAncyBiYWNrZ3JvdW5kLWRpc3BhdGNoIHF1ZXVlIG1lc3NhZ2UsIHNjb3BlZCB0b1xuICogdGhlIHN0ZXAncyBJREVOVElUWSwgY29ycmVsYXRpb24gaWQgcGx1cyAoaGFzaGVkKSBzdGVwIG5hbWUsIHJhdGhlciB0aGFuXG4gKiB0aGUgYmFyZSBjb3JyZWxhdGlvbiBpZC5cbiAqXG4gKiBUaGUgc2NvcGluZyBtYXR0ZXJzIGZvciByZXNpbGllbnQgc3RlcCBkaXNwYXRjaCB1bmRlciB0aGUgcHJlY29uZGl0aW9uXG4gKiBndWFyZDogYSBndWFyZC1yZWplY3RlZCBgc3RlcF9jcmVhdGVkYCBsZWF2ZXMgaXRzIChyZXZva2VkKSBzdGVwIG1lc3NhZ2UgaW5cbiAqIGZsaWdodCwgYW5kIHRoZSBjb3JyZWN0ZWQgcmVwbGF5IG1heSByZS1kZXJpdmUgdGhlIHNhbWUgY29ycmVsYXRpb24gaWQgZm9yXG4gKiBhIERJRkZFUkVOVCBzdGVwLiBVbmRlciBhIGJhcmUtY29ycmVsYXRpb25JZCBrZXkgdGhlIGNvcnJlY3RlZCByZXBsYXknc1xuICogZGlzcGF0Y2ggd291bGQgc2lsZW50bHkgZGVkdXBlIGFnYWluc3QgdGhlIHJldm9rZWQgaW4tZmxpZ2h0IG1lc3NhZ2UsXG4gKiB3aGljaCB0aGVuIHJlc29sdmVzIGBza2lwcGVkYCBhZ2FpbnN0IHRoZSByZS1jcmVhdGVkIGVudGl0eSAodGhlIHNlcnZlcidzXG4gKiBzdGVwTmFtZSBmZW5jZSByZWplY3RzIGl0cyBiYXJlIHN0YXJ0KSwgYW5kIHRoZSBsZWdpdGltYXRlIHN0ZXAgd291bGRcbiAqIG5ldmVyIGJlIGV4ZWN1dGVkLiBTY29waW5nIGJ5IHN0ZXAgbmFtZSBrZWVwcyBldmVyeSBkZWR1cCBwcm9wZXJ0eSB0aGF0XG4gKiBtYXR0ZXJzIChjcmFzaCByZWNvdmVyeSByZS1kaXNwYXRjaCwgY29uY3VycmVudCBoYW5kbGVycywgdGhlIGRlbGF5ZWRcbiAqIHJldHJ5IHNoYXJpbmcgdGhlIHN1c3BlbnNpb24gcmUtZGlzcGF0Y2gncyBrZXk6IGFsbCBuYW1lIHRoZSBzYW1lIHN0ZXApXG4gKiB3aGlsZSBsZXR0aW5nIHRoZSBjb3JyZWN0ZWQgc2NoZWR1bGUncyBkaXNwYXRjaCB0aHJvdWdoLlxuICpcbiAqIEV2ZXJ5IHByb2R1Y2VyIG9mIGEgc3RlcC1kaXNwYXRjaCAob3Igc3RlcC1yZXRyeSkgbWVzc2FnZSBtdXN0IHVzZSB0aGlzXG4gKiBrZXkuIENyb3NzLXZlcnNpb24gbWl4aW5nIGlzIG5vdCBhIGNvbmNlcm46IHF1ZXVlIG1lc3NhZ2VzIGFyZSBwaW5uZWQgdG9cbiAqIHRoZSBkZXBsb3ltZW50IHRoYXQgcHJvZHVjZWQgdGhlbSwgc28gb25lIHJ1biBuZXZlciBzZWVzIHR3byBrZXkgc2NoZW1lcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0ZXBEaXNwYXRjaElkZW1wb3RlbmN5S2V5KFxuICBjb3JyZWxhdGlvbklkOiBzdHJpbmcsXG4gIHN0ZXBOYW1lOiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIHJldHVybiBgJHtjb3JyZWxhdGlvbklkfToke2ZudjFhMzJIZXgoc3RlcE5hbWUpfWA7XG59XG5cbi8qKlxuICogUXVldWVzIGEgbWVzc2FnZSB0byB0aGUgc3BlY2lmaWVkIHF1ZXVlIHdpdGggdHJhY2luZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHF1ZXVlTWVzc2FnZShcbiAgd29ybGQ6IFdvcmxkLFxuICAuLi5hcmdzOiBQYXJhbWV0ZXJzPHR5cGVvZiB3b3JsZC5xdWV1ZT5cbikge1xuICBjb25zdCBxdWV1ZU5hbWUgPSBhcmdzWzBdO1xuICBhd2FpdCB0cmFjZShcbiAgICAncXVldWUucHVibGlzaCcsXG4gICAge1xuICAgICAgLy8gU3RhbmRhcmQgT1RFTCBtZXNzYWdpbmcgY29udmVudGlvbnNcbiAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5NZXNzYWdpbmdEZXN0aW5hdGlvbk5hbWUocXVldWVOYW1lKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ09wZXJhdGlvblR5cGUoJ3B1Ymxpc2gnKSxcbiAgICAgICAgLy8gUGVlciBzZXJ2aWNlIGZvciBEYXRhZG9nIHNlcnZpY2UgbWFwc1xuICAgICAgICAuLi5BdHRyaWJ1dGUuUGVlclNlcnZpY2UoJ3ZlcmNlbC1xdWV1ZScpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjU3lzdGVtKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1NlcnZpY2UoJ3ZxcycpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuUnBjTWV0aG9kKCdwdWJsaXNoJyksXG4gICAgICB9LFxuICAgICAga2luZDogYXdhaXQgZ2V0U3BhbktpbmQoJ1BST0RVQ0VSJyksXG4gICAgfSxcbiAgICBhc3luYyAoc3BhbikgPT4ge1xuICAgICAgY29uc3QgeyBtZXNzYWdlSWQgfSA9IGF3YWl0IHdvcmxkLnF1ZXVlKC4uLmFyZ3MpO1xuICAgICAgaWYgKG1lc3NhZ2VJZCkge1xuICAgICAgICBzcGFuPy5zZXRBdHRyaWJ1dGVzKEF0dHJpYnV0ZS5NZXNzYWdpbmdNZXNzYWdlSWQobWVzc2FnZUlkKSk7XG4gICAgICB9XG4gICAgfVxuICApO1xufVxuXG4vKipcbiAqIFB1Ymxpc2hlcyBzZXZlcmFsIG1lc3NhZ2VzIHRvIG9uZSBsb2dpY2FsIHF1ZXVlLCB1c2luZyB0aGUgV29ybGQncyBiYXRjaFxuICogc2VuZCB3aGVuIGl0IGhhcyBvbmUgYW5kIGZhbGxpbmcgYmFjayB0byBjb25jdXJyZW50IHNpbmdsZSBzZW5kcyB3aGVuIGl0XG4gKiBkb2VzIG5vdC5cbiAqXG4gKiBSZWplY3RzIGlmIEFOWSBtZXNzYWdlIGZhaWxlZCB0byBwdWJsaXNoLCBiZWNhdXNlIGV2ZXJ5IGNhbGxlciBzbyBmYXIgd2FudHNcbiAqIGFsbC1vci1ub3RoaW5nOiB0aGUgcmVjb3ZlcnkgaXMgdG8gZmFpbCB0aGUgZGVsaXZlcnkgYW5kIGxldCByZWRlbGl2ZXJ5XG4gKiByZXB1Ymxpc2ggdGhlIHdob2xlIHNldCwgZGVkdXBlZCBieSB0aGUgcGVyLW1lc3NhZ2UgYGlkZW1wb3RlbmN5S2V5YC4gVGhhdFxuICogbWVhbnMgYSBwYXJ0aWFsIGJhdGNoIGNhbiBsZWF2ZSBzb21lIG1lc3NhZ2VzIGFscmVhZHkgb3V0IOKAlCB3aGljaCBpc1xuICogZXhhY3RseSB3aHkgdGhlIGtleXMgYXJlIHJlcXVpcmVkIHJhdGhlciB0aGFuIGFkdmlzb3J5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcXVldWVNZXNzYWdlcyhcbiAgd29ybGQ6IFdvcmxkLFxuICBxdWV1ZU5hbWU6IFBhcmFtZXRlcnM8dHlwZW9mIHdvcmxkLnF1ZXVlPlswXSxcbiAgbWVzc2FnZXM6IHJlYWRvbmx5IHtcbiAgICBtZXNzYWdlOiBQYXJhbWV0ZXJzPHR5cGVvZiB3b3JsZC5xdWV1ZT5bMV07XG4gICAgb3B0cz86IFBhcmFtZXRlcnM8dHlwZW9mIHdvcmxkLnF1ZXVlPlsyXTtcbiAgfVtdXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICBjb25zdCBiYXRjaCA9IHdvcmxkLnF1ZXVlQmF0Y2g/LmJpbmQod29ybGQpO1xuICBpZiAoIWJhdGNoKSB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtZXNzYWdlcy5tYXAoKGVudHJ5KSA9PlxuICAgICAgICBxdWV1ZU1lc3NhZ2Uod29ybGQsIHF1ZXVlTmFtZSwgZW50cnkubWVzc2FnZSwgZW50cnkub3B0cylcbiAgICAgIClcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuICBhd2FpdCB0cmFjZShcbiAgICAncXVldWUucHVibGlzaCcsXG4gICAge1xuICAgICAgYXR0cmlidXRlczoge1xuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nU3lzdGVtKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLk1lc3NhZ2luZ0Rlc3RpbmF0aW9uTmFtZShxdWV1ZU5hbWUpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nT3BlcmF0aW9uVHlwZSgncHVibGlzaCcpLFxuICAgICAgICAuLi5BdHRyaWJ1dGUuTWVzc2FnaW5nQmF0Y2hNZXNzYWdlQ291bnQobWVzc2FnZXMubGVuZ3RoKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlBlZXJTZXJ2aWNlKCd2ZXJjZWwtcXVldWUnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY1N5c3RlbSgndmVyY2VsLXF1ZXVlJyksXG4gICAgICAgIC4uLkF0dHJpYnV0ZS5ScGNTZXJ2aWNlKCd2cXMnKSxcbiAgICAgICAgLi4uQXR0cmlidXRlLlJwY01ldGhvZCgncHVibGlzaEJhdGNoJyksXG4gICAgICB9LFxuICAgICAga2luZDogYXdhaXQgZ2V0U3BhbktpbmQoJ1BST0RVQ0VSJyksXG4gICAgfSxcbiAgICBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgYmF0Y2gocXVldWVOYW1lLCBtZXNzYWdlcyk7XG4gICAgICAvLyBBIFdvcmxkIHRoYXQgYW5zd2VycyB3aXRoIHRoZSB3cm9uZyBudW1iZXIgb2YgcmVzdWx0cyBoYXMgdG9sZCB1c1xuICAgICAgLy8gbm90aGluZyBhYm91dCB0aGUgbWVzc2FnZXMgaXQgbGVmdCBvdXQuIFRyZWF0ZWQgYXMgYSBmYWlsdXJlIG9mIHRoZVxuICAgICAgLy8gd2hvbGUgYmF0Y2ggcmF0aGVyIHRoYW4gcmVhZCBhcyBzdWNjZXNzIGZvciB0aGUgZW50cmllcyB0aGF0IEFSRVxuICAgICAgLy8gcHJlc2VudDogcmVwdWJsaXNoaW5nIHVuZGVyIHRoZSBzYW1lIGlkZW1wb3RlbmN5IGtleXMgaXMgc2FmZSxcbiAgICAgIC8vIHNpbGVudGx5IG5ldmVyIGRpc3BhdGNoaW5nIGEgc3RlcCBpcyBub3QgKHRoZSBydW4gbWFrZXMgbm8gcHJvZ3Jlc3NcbiAgICAgIC8vIGFuZCBub3RoaW5nIHN1cmZhY2VzIGFuIGVycm9yKS5cbiAgICAgIGlmIChyZXN1bHRzLmxlbmd0aCAhPT0gbWVzc2FnZXMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFF1ZXVlIGJhdGNoIGZvciAke3F1ZXVlTmFtZX0gcmV0dXJuZWQgJHtyZXN1bHRzLmxlbmd0aH0gYCArXG4gICAgICAgICAgICAgIGByZXN1bHQocykgZm9yICR7bWVzc2FnZXMubGVuZ3RofSBtZXNzYWdlKHMpYFxuICAgICAgICAgICksXG4gICAgICAgICAgeyByZXRyeWFibGU6IHRydWUgfVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgZmFpbHVyZXMgPSByZXN1bHRzLmZpbHRlcigocmVzdWx0KSA9PiByZXN1bHQuZXJyb3IgIT09IHVuZGVmaW5lZCk7XG4gICAgICBpZiAoZmFpbHVyZXMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgICBjb25zdCByZXRyeWFibGUgPSBmYWlsdXJlcy5zb21lKFxuICAgICAgICAoZmFpbHVyZSkgPT4gZmFpbHVyZS5lcnJvciAhPT0gdW5kZWZpbmVkICYmIGZhaWx1cmUucmV0cnlhYmxlXG4gICAgICApO1xuICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gcHVibGlzaCAke2ZhaWx1cmVzLmxlbmd0aH0gb2YgJHttZXNzYWdlcy5sZW5ndGh9IHF1ZXVlIGAgK1xuICAgICAgICAgIGBtZXNzYWdlKHMpIHRvICR7cXVldWVOYW1lfTogJHtmYWlsdXJlc1swXT8uZXJyb3J9YFxuICAgICAgKTtcbiAgICAgIC8vIENhcnJpZWQgb24gdGhlIGVycm9yIHNvIGEgY2FsbGVyIENBTiB0ZWxsIGEgdHJhbnNpZW50IHBhcnRpYWwgYmF0Y2hcbiAgICAgIC8vIGZyb20gYSBwZXJtYW5lbnQgcmVqZWN0aW9uLiBOb3RoaW5nIHJlYWRzIGl0IHlldDogdG9kYXkgZXZlcnkgY2FsbGVyXG4gICAgICAvLyByZWplY3RzIHRoZSBkZWxpdmVyeSBlaXRoZXIgd2F5LCBzbyBhIHBlcm1hbmVudGx5IHJlamVjdGVkIGVudHJ5XG4gICAgICAvLyBzdGlsbCBjb3N0cyB0aGUgZnVsbCByZWRlbGl2ZXJ5IGJ1ZGdldC4gTGVmdCBpbiBwbGFjZSBiZWNhdXNlIHRoZVxuICAgICAgLy8gaW5mb3JtYXRpb24gaXMgb25seSBhdmFpbGFibGUgaGVyZSwgYW5kIGEgZmFzdC1mYWlsIG9uXG4gICAgICAvLyBgcmV0cnlhYmxlOiBmYWxzZWAgbmVlZHMgaXQuXG4gICAgICBPYmplY3QuYXNzaWduKGVycm9yLCB7IHJldHJ5YWJsZSB9KTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBxdWV1ZSBvdmVyaGVhZCB0aW1lIGluIG1pbGxpc2Vjb25kcyBmb3IgYSBnaXZlbiBtZXNzYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVldWVPdmVyaGVhZChtZXNzYWdlOiB7IHJlcXVlc3RlZEF0PzogRGF0ZSB9KSB7XG4gIGlmICghbWVzc2FnZS5yZXF1ZXN0ZWRBdCkgcmV0dXJuO1xuICB0cnkge1xuICAgIHJldHVybiBBdHRyaWJ1dGUuUXVldWVPdmVyaGVhZE1zKFxuICAgICAgRGF0ZS5ub3coKSAtIG1lc3NhZ2UucmVxdWVzdGVkQXQuZ2V0VGltZSgpXG4gICAgKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuO1xuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgcnVuJ3MgZnVsbCBwYXlsb2FkLWVuY3J5cHRpb24gY2FwYWJpbGl0eS4gVGhpcyBpbmNsdWRlcyB0aGVcbiAqIHN5bW1ldHJpYyBrZXkgYW5kIFgyNTUxOSBrZXlwYWlyIG5lZWRlZCB0byBvcGVuIGNyb3NzLXJ1biBzZWFsZWQgcGF5bG9hZHMuXG4gKiBNaXNzaW5nIHdvcmxkIHN1cHBvcnQgb3Iga2V5IG1hdGVyaWFsIHJlc29sdmVzIHRvIGB1bmRlZmluZWRgOyBsb29rdXAgYW5kXG4gKiBkZXJpdmF0aW9uIGZhaWx1cmVzIHByb3BhZ2F0ZSByYXRoZXIgdGhhbiBzaWxlbnRseSBmYWxsaW5nIGJhY2sgdG8gcGxhaW50ZXh0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZVJ1bkVuY3J5cHRpb25LZXkoXG4gIHdvcmxkOiBXb3JsZCxcbiAgcnVuT3JJZDogV29ya2Zsb3dSdW4gfCBzdHJpbmcsXG4gIGNvbnRleHQ/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuKTogUHJvbWlzZTxQYXlsb2FkS2V5IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHJhd0tleSA9XG4gICAgdHlwZW9mIHJ1bk9ySWQgPT09ICdzdHJpbmcnXG4gICAgICA/IGF3YWl0IHdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4/LihydW5PcklkLCBjb250ZXh0KVxuICAgICAgOiBhd2FpdCB3b3JsZC5nZXRFbmNyeXB0aW9uS2V5Rm9yUnVuPy4ocnVuT3JJZCk7XG4gIHJldHVybiByYXdLZXkgPyBhd2FpdCBkZXJpdmVSdW5QYXlsb2FkS2V5cyhyYXdLZXkpIDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJldHVybiBhIGxhenksIG1lbW9pemVkIGFjY2Vzc29yIGFyb3VuZCB7QGxpbmsgcmVzb2x2ZVJ1bkVuY3J5cHRpb25LZXl9LlxuICogQ29uY3VycmVudCBjYWxsZXJzIHNoYXJlIHRoZSBzYW1lIHByb21pc2UsIGluY2x1ZGluZyBpdHMgcmVqZWN0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWVtb2l6ZUVuY3J5cHRpb25LZXkoXG4gIHdvcmxkOiBXb3JsZCxcbiAgcnVuT3JJZDogV29ya2Zsb3dSdW4gfCBzdHJpbmdcbik6ICgpID0+IFByb21pc2U8UGF5bG9hZEtleSB8IHVuZGVmaW5lZD4ge1xuICBsZXQgY2FjaGVkOiBQcm9taXNlPFBheWxvYWRLZXkgfCB1bmRlZmluZWQ+IHwgdW5kZWZpbmVkO1xuICByZXR1cm4gKCkgPT4ge1xuICAgIGlmICghY2FjaGVkKSB7XG4gICAgICBjYWNoZWQgPSByZXNvbHZlUnVuRW5jcnlwdGlvbktleSh3b3JsZCwgcnVuT3JJZCk7XG4gICAgfVxuICAgIHJldHVybiBjYWNoZWQ7XG4gIH07XG59XG4iXX0=