@workflow/core 5.0.0-beta.2 → 5.0.0-beta.20

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 (247) hide show
  1. package/dist/attribute-changes.d.ts +7 -0
  2. package/dist/attribute-changes.d.ts.map +1 -0
  3. package/dist/attribute-changes.js +25 -0
  4. package/dist/capabilities.d.ts +22 -1
  5. package/dist/capabilities.d.ts.map +1 -1
  6. package/dist/capabilities.js +41 -4
  7. package/dist/capture-stack.d.ts +16 -0
  8. package/dist/capture-stack.d.ts.map +1 -0
  9. package/dist/capture-stack.js +21 -0
  10. package/dist/class-serialization.d.ts +32 -0
  11. package/dist/class-serialization.d.ts.map +1 -1
  12. package/dist/class-serialization.js +37 -1
  13. package/dist/classify-error.d.ts +11 -3
  14. package/dist/classify-error.d.ts.map +1 -1
  15. package/dist/classify-error.js +59 -6
  16. package/dist/context-errors.d.ts +27 -0
  17. package/dist/context-errors.d.ts.map +1 -0
  18. package/dist/context-errors.js +101 -0
  19. package/dist/context-violation-error.d.ts +97 -0
  20. package/dist/context-violation-error.d.ts.map +1 -0
  21. package/dist/context-violation-error.js +147 -0
  22. package/dist/create-hook.d.ts +40 -1
  23. package/dist/create-hook.d.ts.map +1 -1
  24. package/dist/create-hook.js +4 -3
  25. package/dist/define-hook.d.ts.map +1 -1
  26. package/dist/define-hook.js +20 -5
  27. package/dist/describe-error.d.ts +70 -0
  28. package/dist/describe-error.d.ts.map +1 -0
  29. package/dist/describe-error.js +165 -0
  30. package/dist/encryption.d.ts +22 -1
  31. package/dist/encryption.d.ts.map +1 -1
  32. package/dist/encryption.js +72 -27
  33. package/dist/events-consumer.d.ts +24 -0
  34. package/dist/events-consumer.d.ts.map +1 -1
  35. package/dist/events-consumer.js +79 -16
  36. package/dist/flushable-stream.d.ts +10 -10
  37. package/dist/flushable-stream.d.ts.map +1 -1
  38. package/dist/flushable-stream.js +18 -13
  39. package/dist/global.d.ts +15 -1
  40. package/dist/global.d.ts.map +1 -1
  41. package/dist/global.js +21 -3
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2 -1
  45. package/dist/log-format.d.ts +25 -0
  46. package/dist/log-format.d.ts.map +1 -0
  47. package/dist/log-format.js +250 -0
  48. package/dist/logger.d.ts +28 -30
  49. package/dist/logger.d.ts.map +1 -1
  50. package/dist/logger.js +77 -31
  51. package/dist/private.d.ts +84 -0
  52. package/dist/private.d.ts.map +1 -1
  53. package/dist/private.js +80 -3
  54. package/dist/runtime/constants.d.ts +93 -0
  55. package/dist/runtime/constants.d.ts.map +1 -1
  56. package/dist/runtime/constants.js +168 -8
  57. package/dist/runtime/get-port-lazy.d.ts +25 -0
  58. package/dist/runtime/get-port-lazy.d.ts.map +1 -0
  59. package/dist/runtime/get-port-lazy.js +92 -0
  60. package/dist/runtime/get-world-lazy.d.ts +32 -0
  61. package/dist/runtime/get-world-lazy.d.ts.map +1 -0
  62. package/dist/runtime/get-world-lazy.js +56 -0
  63. package/dist/runtime/helpers.d.ts +50 -7
  64. package/dist/runtime/helpers.d.ts.map +1 -1
  65. package/dist/runtime/helpers.js +149 -31
  66. package/dist/runtime/replay-budget.d.ts +98 -0
  67. package/dist/runtime/replay-budget.d.ts.map +1 -0
  68. package/dist/runtime/replay-budget.js +191 -0
  69. package/dist/runtime/resume-hook.d.ts.map +1 -1
  70. package/dist/runtime/resume-hook.js +39 -23
  71. package/dist/runtime/run-id-time.d.ts +10 -0
  72. package/dist/runtime/run-id-time.d.ts.map +1 -0
  73. package/dist/runtime/run-id-time.js +31 -0
  74. package/dist/runtime/run.d.ts.map +1 -1
  75. package/dist/runtime/run.js +44 -9
  76. package/dist/runtime/runs.d.ts.map +1 -1
  77. package/dist/runtime/runs.js +4 -1
  78. package/dist/runtime/start.d.ts +30 -1
  79. package/dist/runtime/start.d.ts.map +1 -1
  80. package/dist/runtime/start.js +138 -20
  81. package/dist/runtime/step-executor.d.ts +91 -0
  82. package/dist/runtime/step-executor.d.ts.map +1 -0
  83. package/dist/runtime/step-executor.js +659 -0
  84. package/dist/runtime/step-handler.d.ts.map +1 -1
  85. package/dist/runtime/step-handler.js +699 -556
  86. package/dist/runtime/suspension-handler.d.ts +55 -6
  87. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  88. package/dist/runtime/suspension-handler.js +282 -115
  89. package/dist/runtime/wait-continuation.d.ts +84 -0
  90. package/dist/runtime/wait-continuation.d.ts.map +1 -0
  91. package/dist/runtime/wait-continuation.js +92 -0
  92. package/dist/runtime/wait-until.d.ts +18 -0
  93. package/dist/runtime/wait-until.d.ts.map +1 -0
  94. package/dist/runtime/wait-until.js +42 -0
  95. package/dist/runtime/world-init.d.ts +75 -0
  96. package/dist/runtime/world-init.d.ts.map +1 -0
  97. package/dist/runtime/world-init.js +75 -0
  98. package/dist/runtime/world.d.ts.map +1 -1
  99. package/dist/runtime/world.js +47 -18
  100. package/dist/runtime.d.ts +11 -8
  101. package/dist/runtime.d.ts.map +1 -1
  102. package/dist/runtime.js +1234 -334
  103. package/dist/schemas.d.ts +1 -1
  104. package/dist/schemas.d.ts.map +1 -1
  105. package/dist/schemas.js +1 -1
  106. package/dist/serialization/client.d.ts +17 -0
  107. package/dist/serialization/client.d.ts.map +1 -0
  108. package/dist/serialization/client.js +48 -0
  109. package/dist/serialization/codec-devalue.d.ts +14 -0
  110. package/dist/serialization/codec-devalue.d.ts.map +1 -0
  111. package/dist/serialization/codec-devalue.js +98 -0
  112. package/dist/serialization/codec.d.ts +106 -0
  113. package/dist/serialization/codec.d.ts.map +1 -0
  114. package/dist/serialization/codec.js +17 -0
  115. package/dist/serialization/compression.d.ts +104 -0
  116. package/dist/serialization/compression.d.ts.map +1 -0
  117. package/dist/serialization/compression.js +260 -0
  118. package/dist/serialization/encryption.d.ts +33 -0
  119. package/dist/serialization/encryption.d.ts.map +1 -0
  120. package/dist/serialization/encryption.js +70 -0
  121. package/dist/serialization/errors.d.ts +34 -0
  122. package/dist/serialization/errors.d.ts.map +1 -0
  123. package/dist/serialization/errors.js +59 -0
  124. package/dist/serialization/format.d.ts +60 -0
  125. package/dist/serialization/format.d.ts.map +1 -0
  126. package/dist/serialization/format.js +97 -0
  127. package/dist/serialization/index.d.ts +19 -0
  128. package/dist/serialization/index.d.ts.map +1 -0
  129. package/dist/serialization/index.js +22 -0
  130. package/dist/serialization/reducers/class.d.ts +11 -0
  131. package/dist/serialization/reducers/class.d.ts.map +1 -0
  132. package/dist/serialization/reducers/class.js +68 -0
  133. package/dist/serialization/reducers/common.d.ts +16 -0
  134. package/dist/serialization/reducers/common.d.ts.map +1 -0
  135. package/dist/serialization/reducers/common.js +417 -0
  136. package/dist/serialization/reducers/step-function.d.ts +35 -0
  137. package/dist/serialization/reducers/step-function.d.ts.map +1 -0
  138. package/dist/serialization/reducers/step-function.js +88 -0
  139. package/dist/serialization/step.d.ts +17 -0
  140. package/dist/serialization/step.d.ts.map +1 -0
  141. package/dist/serialization/step.js +48 -0
  142. package/dist/serialization/types.d.ts +253 -0
  143. package/dist/serialization/types.d.ts.map +1 -0
  144. package/dist/serialization/types.js +25 -0
  145. package/dist/serialization/workflow.d.ts +29 -0
  146. package/dist/serialization/workflow.d.ts.map +1 -0
  147. package/dist/serialization/workflow.js +54 -0
  148. package/dist/serialization-format.d.ts +15 -0
  149. package/dist/serialization-format.d.ts.map +1 -1
  150. package/dist/serialization-format.js +209 -11
  151. package/dist/serialization.d.ts +313 -214
  152. package/dist/serialization.d.ts.map +1 -1
  153. package/dist/serialization.js +1417 -658
  154. package/dist/set-attributes.d.ts +13 -0
  155. package/dist/set-attributes.d.ts.map +1 -0
  156. package/dist/set-attributes.js +42 -0
  157. package/dist/sleep.d.ts.map +1 -1
  158. package/dist/sleep.js +3 -2
  159. package/dist/source-map.d.ts +5 -0
  160. package/dist/source-map.d.ts.map +1 -1
  161. package/dist/source-map.js +102 -10
  162. package/dist/step/context-storage.d.ts +16 -0
  163. package/dist/step/context-storage.d.ts.map +1 -1
  164. package/dist/step/context-storage.js +1 -1
  165. package/dist/step/get-closure-vars.d.ts.map +1 -1
  166. package/dist/step/get-closure-vars.js +3 -2
  167. package/dist/step/get-step-metadata.d.ts.map +1 -1
  168. package/dist/step/get-step-metadata.js +3 -2
  169. package/dist/step/get-workflow-metadata.d.ts.map +1 -1
  170. package/dist/step/get-workflow-metadata.js +3 -2
  171. package/dist/step/writable-stream.d.ts.map +1 -1
  172. package/dist/step/writable-stream.js +49 -5
  173. package/dist/step.d.ts.map +1 -1
  174. package/dist/step.js +98 -20
  175. package/dist/symbols.d.ts +28 -0
  176. package/dist/symbols.d.ts.map +1 -1
  177. package/dist/symbols.js +29 -1
  178. package/dist/telemetry/semantic-conventions.d.ts +30 -2
  179. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  180. package/dist/telemetry/semantic-conventions.js +21 -1
  181. package/dist/telemetry.d.ts +60 -0
  182. package/dist/telemetry.d.ts.map +1 -1
  183. package/dist/telemetry.js +82 -4
  184. package/dist/types.d.ts +6 -0
  185. package/dist/types.d.ts.map +1 -1
  186. package/dist/types.js +23 -1
  187. package/dist/util.d.ts +16 -6
  188. package/dist/util.d.ts.map +1 -1
  189. package/dist/util.js +25 -16
  190. package/dist/version.d.ts +1 -1
  191. package/dist/version.d.ts.map +1 -1
  192. package/dist/version.js +2 -2
  193. package/dist/vm/index.d.ts.map +1 -1
  194. package/dist/vm/index.js +3 -2
  195. package/dist/vm/script-cache.d.ts +28 -0
  196. package/dist/vm/script-cache.d.ts.map +1 -0
  197. package/dist/vm/script-cache.js +140 -0
  198. package/dist/workflow/abort-controller.d.ts +65 -0
  199. package/dist/workflow/abort-controller.d.ts.map +1 -0
  200. package/dist/workflow/abort-controller.js +260 -0
  201. package/dist/workflow/attribute-dispatcher.d.ts +6 -0
  202. package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
  203. package/dist/workflow/attribute-dispatcher.js +48 -0
  204. package/dist/workflow/create-hook.d.ts.map +1 -1
  205. package/dist/workflow/create-hook.js +23 -2
  206. package/dist/workflow/define-hook.d.ts +1 -1
  207. package/dist/workflow/define-hook.d.ts.map +1 -1
  208. package/dist/workflow/define-hook.js +8 -4
  209. package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
  210. package/dist/workflow/get-workflow-metadata.js +14 -3
  211. package/dist/workflow/hook.d.ts.map +1 -1
  212. package/dist/workflow/hook.js +207 -33
  213. package/dist/workflow/index.d.ts +1 -0
  214. package/dist/workflow/index.d.ts.map +1 -1
  215. package/dist/workflow/index.js +5 -3
  216. package/dist/workflow/set-attributes.d.ts +73 -0
  217. package/dist/workflow/set-attributes.d.ts.map +1 -0
  218. package/dist/workflow/set-attributes.js +65 -0
  219. package/dist/workflow/sleep.d.ts.map +1 -1
  220. package/dist/workflow/sleep.js +45 -8
  221. package/dist/workflow/world-init-stub.d.ts +15 -0
  222. package/dist/workflow/world-init-stub.d.ts.map +1 -0
  223. package/dist/workflow/world-init-stub.js +15 -0
  224. package/dist/workflow.d.ts.map +1 -1
  225. package/dist/workflow.js +148 -47
  226. package/docs/api-reference/create-hook.mdx +38 -0
  227. package/docs/api-reference/create-webhook.mdx +1 -0
  228. package/docs/api-reference/experimental-set-attributes.mdx +65 -0
  229. package/docs/api-reference/fetch.mdx +5 -0
  230. package/docs/api-reference/index.mdx +3 -0
  231. package/docs/foundations/cancellation.mdx +459 -0
  232. package/docs/foundations/errors-and-retries.mdx +7 -3
  233. package/docs/foundations/hooks.mdx +29 -0
  234. package/docs/foundations/idempotency.mdx +236 -11
  235. package/docs/foundations/index.mdx +3 -3
  236. package/docs/foundations/meta.json +3 -2
  237. package/docs/foundations/serialization.mdx +78 -42
  238. package/docs/foundations/starting-workflows.mdx +6 -2
  239. package/docs/foundations/streaming.mdx +14 -23
  240. package/docs/foundations/versioning.mdx +263 -0
  241. package/docs/how-it-works/cancellation.mdx +287 -0
  242. package/docs/how-it-works/code-transform.mdx +2 -2
  243. package/docs/how-it-works/encryption.mdx +2 -2
  244. package/docs/how-it-works/event-sourcing.mdx +2 -2
  245. package/docs/how-it-works/meta.json +2 -1
  246. package/package.json +22 -10
  247. package/docs/foundations/common-patterns.mdx +0 -265
@@ -0,0 +1,28 @@
1
+ import { type Context, Script } from 'node:vm';
2
+ /**
3
+ * Returns a compiled `vm.Script` for the given workflow bundle code and
4
+ * filename, compiling and caching it on first use. Subsequent calls with the
5
+ * same `(code, filename)` return the cached `Script`.
6
+ *
7
+ * The returned `Script` is not yet bound to any context; the caller runs it
8
+ * against a specific VM context via `script.runInContext(context)`. This is
9
+ * equivalent to `vm.runInContext(code, context, { filename })` but skips the
10
+ * recompile.
11
+ */
12
+ export declare function getCachedWorkflowScript(code: string, filename: string): Script;
13
+ /**
14
+ * Runs the cached workflow-bundle `Script` against `context`. Compiles and
15
+ * caches the `Script` on first use for the given `(code, filename)`.
16
+ */
17
+ export declare function runCachedWorkflowScript(code: string, filename: string, context: Context): unknown;
18
+ /**
19
+ * Clears the compiled-script cache. Intended for tests that want to assert
20
+ * compile-vs-cache behaviour in isolation; not used on the hot path.
21
+ */
22
+ export declare function clearWorkflowScriptCache(): void;
23
+ /**
24
+ * Number of distinct bundle (`code`) versions currently retained. Exposed for
25
+ * tests asserting the LRU bound; not used on the hot path.
26
+ */
27
+ export declare function workflowScriptCacheSize(): number;
28
+ //# sourceMappingURL=script-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-cache.d.ts","sourceRoot":"","sources":["../../src/vm/script-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AA0F/C;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,MAAM,CAqBR;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAET;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD"}
@@ -0,0 +1,140 @@
1
+ import { Script } from 'node:vm';
2
+ /**
3
+ * Module-level cache of compiled workflow-bundle `vm.Script` objects.
4
+ *
5
+ * Why this exists
6
+ * ---------------
7
+ * Replaying a workflow re-evaluates the workflow bundle against a fresh VM
8
+ * context on every iteration of the inline replay loop (see
9
+ * `runWorkflow` in `../workflow.ts`). The bundle is a single string that
10
+ * contains every workflow function in the app and registers them on
11
+ * `globalThis.__private_workflows`. Previously each replay called
12
+ * `vm.runInContext(workflowCode, context, { filename })`, which RE-PARSES and
13
+ * RE-COMPILES the entire bundle every time — O(N) full re-parses for a
14
+ * sequential workflow of N steps, plus the same parse cost repeated across
15
+ * every invocation in the process.
16
+ *
17
+ * Compilation is a pure function of `(code, filename)`: a `vm.Script` carries
18
+ * no realm/context state — it is only bound to a context at `runInContext`
19
+ * time. So a single compiled `Script` can be reused across replays AND across
20
+ * workflow invocations in the same process without affecting determinism: the
21
+ * produced workflow function is identical to the previous re-parse-every-time
22
+ * behaviour, with identical `filename` source attribution (see the precise
23
+ * claim — and its one caveat — in `runWorkflow`).
24
+ *
25
+ * Keying
26
+ * ------
27
+ * Keyed by `code` then `filename`. The `filename` is part of the key on
28
+ * purpose, NOT as a dedupe key: it is baked into the compiled script's source
29
+ * attribution and surfaces in stack traces, where `remapErrorStack` keys on it
30
+ * to map frames back to the user's source. Two workflows in the same bundle
31
+ * share the same `code` but have different `filename`s, so they intentionally
32
+ * compile to distinct `Script`s — collapsing them onto a single shared `Script`
33
+ * would misattribute one workflow's stack frames to another file. The cost of
34
+ * keeping them distinct is that the whole bundle is compiled once per distinct
35
+ * `filename` (not once per bundle); in practice that is bounded by the number
36
+ * of source files that define a workflow, and because V8 lazily compiles
37
+ * function bodies the duplicated work is the (cheap) top-level parse, not full
38
+ * per-workflow codegen.
39
+ *
40
+ * We use a nested Map (code -> filename -> Script) so that evicting a bundle
41
+ * (e.g. a new deployment/hot-reload producing a different `code`) drops the old
42
+ * code string and all of its per-filename scripts together.
43
+ *
44
+ * Bounding
45
+ * --------
46
+ * The top-level (`code`-keyed) map is an insertion-ordered LRU capped at
47
+ * `MAX_BUNDLES` entries. In production this bound is never reached: a
48
+ * deployment is its own process serving exactly one build-time bundle literal
49
+ * (skew protection runs old versions as separate processes), so there is a
50
+ * single `code` key for the process lifetime. The bound exists for dev/watch
51
+ * mode, where the dev route re-reads `workflowCode` from disk and re-invokes
52
+ * the entrypoint on every edit — each edit produces a NEW bundle string, which
53
+ * without a bound would pin every historical version forever (~0.8MB per edit,
54
+ * growing monotonically with edit count). The dev path only ever needs the
55
+ * latest bundle, so an LRU that keeps the few most-recent bundles and evicts
56
+ * the rest preserves the pre-cache GC behaviour while still serving the
57
+ * steady-state single-bundle case for free. The per-`filename` inner map is not
58
+ * separately bounded: it is naturally bounded by the (small) number of workflow
59
+ * source files in a bundle and is dropped wholesale when its parent `code`
60
+ * entry is evicted.
61
+ */
62
+ const scriptCache = new Map();
63
+ /**
64
+ * Max number of distinct bundle (`code`) versions to retain. One is enough for
65
+ * production; a handful covers pathological dev hot-reload / repeated-rebuild
66
+ * churn within a single long-lived process (e.g. a watch session or a test
67
+ * file) without unbounded growth. Kept deliberately small — there is no value
68
+ * in retaining stale bundles, only a memory cost.
69
+ */
70
+ const MAX_BUNDLES = 8;
71
+ /**
72
+ * Looks up the per-filename map for `code`, marking it most-recently-used.
73
+ * Relies on `Map` preserving insertion order: deleting and re-inserting an
74
+ * existing key moves it to the end (newest), so the first key is always the
75
+ * least-recently-used eviction candidate.
76
+ */
77
+ function touchBundle(code) {
78
+ const byFilename = scriptCache.get(code);
79
+ if (byFilename === undefined) {
80
+ return undefined;
81
+ }
82
+ // Move to the most-recently-used position (end of insertion order).
83
+ scriptCache.delete(code);
84
+ scriptCache.set(code, byFilename);
85
+ return byFilename;
86
+ }
87
+ /**
88
+ * Returns a compiled `vm.Script` for the given workflow bundle code and
89
+ * filename, compiling and caching it on first use. Subsequent calls with the
90
+ * same `(code, filename)` return the cached `Script`.
91
+ *
92
+ * The returned `Script` is not yet bound to any context; the caller runs it
93
+ * against a specific VM context via `script.runInContext(context)`. This is
94
+ * equivalent to `vm.runInContext(code, context, { filename })` but skips the
95
+ * recompile.
96
+ */
97
+ export function getCachedWorkflowScript(code, filename) {
98
+ let byFilename = touchBundle(code);
99
+ if (byFilename === undefined) {
100
+ byFilename = new Map();
101
+ scriptCache.set(code, byFilename);
102
+ // Evict the least-recently-used bundle(s) when over the cap. New bundles
103
+ // are appended at the end, so the oldest live at the front.
104
+ while (scriptCache.size > MAX_BUNDLES) {
105
+ const oldest = scriptCache.keys().next().value;
106
+ if (oldest === undefined) {
107
+ break;
108
+ }
109
+ scriptCache.delete(oldest);
110
+ }
111
+ }
112
+ let script = byFilename.get(filename);
113
+ if (script === undefined) {
114
+ script = new Script(code, { filename });
115
+ byFilename.set(filename, script);
116
+ }
117
+ return script;
118
+ }
119
+ /**
120
+ * Runs the cached workflow-bundle `Script` against `context`. Compiles and
121
+ * caches the `Script` on first use for the given `(code, filename)`.
122
+ */
123
+ export function runCachedWorkflowScript(code, filename, context) {
124
+ return getCachedWorkflowScript(code, filename).runInContext(context);
125
+ }
126
+ /**
127
+ * Clears the compiled-script cache. Intended for tests that want to assert
128
+ * compile-vs-cache behaviour in isolation; not used on the hot path.
129
+ */
130
+ export function clearWorkflowScriptCache() {
131
+ scriptCache.clear();
132
+ }
133
+ /**
134
+ * Number of distinct bundle (`code`) versions currently retained. Exposed for
135
+ * tests asserting the LRU bound; not used on the hot path.
136
+ */
137
+ export function workflowScriptCacheSize() {
138
+ return scriptCache.size;
139
+ }
140
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0LWNhY2hlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3ZtL3NjcmlwdC1jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWdCLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUUvQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyREc7QUFDSCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsRUFBK0IsQ0FBQztBQUUzRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFFdEI7Ozs7O0dBS0c7QUFDSCxTQUFTLFdBQVcsQ0FBQyxJQUFZO0lBQy9CLE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekMsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDN0IsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELG9FQUFvRTtJQUNwRSxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3pCLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ2xDLE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQ3JDLElBQVksRUFDWixRQUFnQjtJQUVoQixJQUFJLFVBQVUsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkMsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDN0IsVUFBVSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBQ3ZDLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2xDLHlFQUF5RTtRQUN6RSw0REFBNEQ7UUFDNUQsT0FBTyxXQUFXLENBQUMsSUFBSSxHQUFHLFdBQVcsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUM7WUFDL0MsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3pCLE1BQU07WUFDUixDQUFDO1lBQ0QsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM3QixDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksTUFBTSxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdEMsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDekIsTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDeEMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQ3JDLElBQVksRUFDWixRQUFnQixFQUNoQixPQUFnQjtJQUVoQixPQUFPLHVCQUF1QixDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSx3QkFBd0I7SUFDdEMsV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQ3RCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsdUJBQXVCO0lBQ3JDLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQztBQUMxQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdHlwZSBDb250ZXh0LCBTY3JpcHQgfSBmcm9tICdub2RlOnZtJztcblxuLyoqXG4gKiBNb2R1bGUtbGV2ZWwgY2FjaGUgb2YgY29tcGlsZWQgd29ya2Zsb3ctYnVuZGxlIGB2bS5TY3JpcHRgIG9iamVjdHMuXG4gKlxuICogV2h5IHRoaXMgZXhpc3RzXG4gKiAtLS0tLS0tLS0tLS0tLS1cbiAqIFJlcGxheWluZyBhIHdvcmtmbG93IHJlLWV2YWx1YXRlcyB0aGUgd29ya2Zsb3cgYnVuZGxlIGFnYWluc3QgYSBmcmVzaCBWTVxuICogY29udGV4dCBvbiBldmVyeSBpdGVyYXRpb24gb2YgdGhlIGlubGluZSByZXBsYXkgbG9vcCAoc2VlXG4gKiBgcnVuV29ya2Zsb3dgIGluIGAuLi93b3JrZmxvdy50c2ApLiBUaGUgYnVuZGxlIGlzIGEgc2luZ2xlIHN0cmluZyB0aGF0XG4gKiBjb250YWlucyBldmVyeSB3b3JrZmxvdyBmdW5jdGlvbiBpbiB0aGUgYXBwIGFuZCByZWdpc3RlcnMgdGhlbSBvblxuICogYGdsb2JhbFRoaXMuX19wcml2YXRlX3dvcmtmbG93c2AuIFByZXZpb3VzbHkgZWFjaCByZXBsYXkgY2FsbGVkXG4gKiBgdm0ucnVuSW5Db250ZXh0KHdvcmtmbG93Q29kZSwgY29udGV4dCwgeyBmaWxlbmFtZSB9KWAsIHdoaWNoIFJFLVBBUlNFUyBhbmRcbiAqIFJFLUNPTVBJTEVTIHRoZSBlbnRpcmUgYnVuZGxlIGV2ZXJ5IHRpbWUg4oCUIE8oTikgZnVsbCByZS1wYXJzZXMgZm9yIGFcbiAqIHNlcXVlbnRpYWwgd29ya2Zsb3cgb2YgTiBzdGVwcywgcGx1cyB0aGUgc2FtZSBwYXJzZSBjb3N0IHJlcGVhdGVkIGFjcm9zc1xuICogZXZlcnkgaW52b2NhdGlvbiBpbiB0aGUgcHJvY2Vzcy5cbiAqXG4gKiBDb21waWxhdGlvbiBpcyBhIHB1cmUgZnVuY3Rpb24gb2YgYChjb2RlLCBmaWxlbmFtZSlgOiBhIGB2bS5TY3JpcHRgIGNhcnJpZXNcbiAqIG5vIHJlYWxtL2NvbnRleHQgc3RhdGUg4oCUIGl0IGlzIG9ubHkgYm91bmQgdG8gYSBjb250ZXh0IGF0IGBydW5JbkNvbnRleHRgXG4gKiB0aW1lLiBTbyBhIHNpbmdsZSBjb21waWxlZCBgU2NyaXB0YCBjYW4gYmUgcmV1c2VkIGFjcm9zcyByZXBsYXlzIEFORCBhY3Jvc3NcbiAqIHdvcmtmbG93IGludm9jYXRpb25zIGluIHRoZSBzYW1lIHByb2Nlc3Mgd2l0aG91dCBhZmZlY3RpbmcgZGV0ZXJtaW5pc206IHRoZVxuICogcHJvZHVjZWQgd29ya2Zsb3cgZnVuY3Rpb24gaXMgaWRlbnRpY2FsIHRvIHRoZSBwcmV2aW91cyByZS1wYXJzZS1ldmVyeS10aW1lXG4gKiBiZWhhdmlvdXIsIHdpdGggaWRlbnRpY2FsIGBmaWxlbmFtZWAgc291cmNlIGF0dHJpYnV0aW9uIChzZWUgdGhlIHByZWNpc2VcbiAqIGNsYWltIOKAlCBhbmQgaXRzIG9uZSBjYXZlYXQg4oCUIGluIGBydW5Xb3JrZmxvd2ApLlxuICpcbiAqIEtleWluZ1xuICogLS0tLS0tXG4gKiBLZXllZCBieSBgY29kZWAgdGhlbiBgZmlsZW5hbWVgLiBUaGUgYGZpbGVuYW1lYCBpcyBwYXJ0IG9mIHRoZSBrZXkgb25cbiAqIHB1cnBvc2UsIE5PVCBhcyBhIGRlZHVwZSBrZXk6IGl0IGlzIGJha2VkIGludG8gdGhlIGNvbXBpbGVkIHNjcmlwdCdzIHNvdXJjZVxuICogYXR0cmlidXRpb24gYW5kIHN1cmZhY2VzIGluIHN0YWNrIHRyYWNlcywgd2hlcmUgYHJlbWFwRXJyb3JTdGFja2Aga2V5cyBvbiBpdFxuICogdG8gbWFwIGZyYW1lcyBiYWNrIHRvIHRoZSB1c2VyJ3Mgc291cmNlLiBUd28gd29ya2Zsb3dzIGluIHRoZSBzYW1lIGJ1bmRsZVxuICogc2hhcmUgdGhlIHNhbWUgYGNvZGVgIGJ1dCBoYXZlIGRpZmZlcmVudCBgZmlsZW5hbWVgcywgc28gdGhleSBpbnRlbnRpb25hbGx5XG4gKiBjb21waWxlIHRvIGRpc3RpbmN0IGBTY3JpcHRgcyDigJQgY29sbGFwc2luZyB0aGVtIG9udG8gYSBzaW5nbGUgc2hhcmVkIGBTY3JpcHRgXG4gKiB3b3VsZCBtaXNhdHRyaWJ1dGUgb25lIHdvcmtmbG93J3Mgc3RhY2sgZnJhbWVzIHRvIGFub3RoZXIgZmlsZS4gVGhlIGNvc3Qgb2ZcbiAqIGtlZXBpbmcgdGhlbSBkaXN0aW5jdCBpcyB0aGF0IHRoZSB3aG9sZSBidW5kbGUgaXMgY29tcGlsZWQgb25jZSBwZXIgZGlzdGluY3RcbiAqIGBmaWxlbmFtZWAgKG5vdCBvbmNlIHBlciBidW5kbGUpOyBpbiBwcmFjdGljZSB0aGF0IGlzIGJvdW5kZWQgYnkgdGhlIG51bWJlclxuICogb2Ygc291cmNlIGZpbGVzIHRoYXQgZGVmaW5lIGEgd29ya2Zsb3csIGFuZCBiZWNhdXNlIFY4IGxhemlseSBjb21waWxlc1xuICogZnVuY3Rpb24gYm9kaWVzIHRoZSBkdXBsaWNhdGVkIHdvcmsgaXMgdGhlIChjaGVhcCkgdG9wLWxldmVsIHBhcnNlLCBub3QgZnVsbFxuICogcGVyLXdvcmtmbG93IGNvZGVnZW4uXG4gKlxuICogV2UgdXNlIGEgbmVzdGVkIE1hcCAoY29kZSAtPiBmaWxlbmFtZSAtPiBTY3JpcHQpIHNvIHRoYXQgZXZpY3RpbmcgYSBidW5kbGVcbiAqIChlLmcuIGEgbmV3IGRlcGxveW1lbnQvaG90LXJlbG9hZCBwcm9kdWNpbmcgYSBkaWZmZXJlbnQgYGNvZGVgKSBkcm9wcyB0aGUgb2xkXG4gKiBjb2RlIHN0cmluZyBhbmQgYWxsIG9mIGl0cyBwZXItZmlsZW5hbWUgc2NyaXB0cyB0b2dldGhlci5cbiAqXG4gKiBCb3VuZGluZ1xuICogLS0tLS0tLS1cbiAqIFRoZSB0b3AtbGV2ZWwgKGBjb2RlYC1rZXllZCkgbWFwIGlzIGFuIGluc2VydGlvbi1vcmRlcmVkIExSVSBjYXBwZWQgYXRcbiAqIGBNQVhfQlVORExFU2AgZW50cmllcy4gSW4gcHJvZHVjdGlvbiB0aGlzIGJvdW5kIGlzIG5ldmVyIHJlYWNoZWQ6IGFcbiAqIGRlcGxveW1lbnQgaXMgaXRzIG93biBwcm9jZXNzIHNlcnZpbmcgZXhhY3RseSBvbmUgYnVpbGQtdGltZSBidW5kbGUgbGl0ZXJhbFxuICogKHNrZXcgcHJvdGVjdGlvbiBydW5zIG9sZCB2ZXJzaW9ucyBhcyBzZXBhcmF0ZSBwcm9jZXNzZXMpLCBzbyB0aGVyZSBpcyBhXG4gKiBzaW5nbGUgYGNvZGVgIGtleSBmb3IgdGhlIHByb2Nlc3MgbGlmZXRpbWUuIFRoZSBib3VuZCBleGlzdHMgZm9yIGRldi93YXRjaFxuICogbW9kZSwgd2hlcmUgdGhlIGRldiByb3V0ZSByZS1yZWFkcyBgd29ya2Zsb3dDb2RlYCBmcm9tIGRpc2sgYW5kIHJlLWludm9rZXNcbiAqIHRoZSBlbnRyeXBvaW50IG9uIGV2ZXJ5IGVkaXQg4oCUIGVhY2ggZWRpdCBwcm9kdWNlcyBhIE5FVyBidW5kbGUgc3RyaW5nLCB3aGljaFxuICogd2l0aG91dCBhIGJvdW5kIHdvdWxkIHBpbiBldmVyeSBoaXN0b3JpY2FsIHZlcnNpb24gZm9yZXZlciAofjAuOE1CIHBlciBlZGl0LFxuICogZ3Jvd2luZyBtb25vdG9uaWNhbGx5IHdpdGggZWRpdCBjb3VudCkuIFRoZSBkZXYgcGF0aCBvbmx5IGV2ZXIgbmVlZHMgdGhlXG4gKiBsYXRlc3QgYnVuZGxlLCBzbyBhbiBMUlUgdGhhdCBrZWVwcyB0aGUgZmV3IG1vc3QtcmVjZW50IGJ1bmRsZXMgYW5kIGV2aWN0c1xuICogdGhlIHJlc3QgcHJlc2VydmVzIHRoZSBwcmUtY2FjaGUgR0MgYmVoYXZpb3VyIHdoaWxlIHN0aWxsIHNlcnZpbmcgdGhlXG4gKiBzdGVhZHktc3RhdGUgc2luZ2xlLWJ1bmRsZSBjYXNlIGZvciBmcmVlLiBUaGUgcGVyLWBmaWxlbmFtZWAgaW5uZXIgbWFwIGlzIG5vdFxuICogc2VwYXJhdGVseSBib3VuZGVkOiBpdCBpcyBuYXR1cmFsbHkgYm91bmRlZCBieSB0aGUgKHNtYWxsKSBudW1iZXIgb2Ygd29ya2Zsb3dcbiAqIHNvdXJjZSBmaWxlcyBpbiBhIGJ1bmRsZSBhbmQgaXMgZHJvcHBlZCB3aG9sZXNhbGUgd2hlbiBpdHMgcGFyZW50IGBjb2RlYFxuICogZW50cnkgaXMgZXZpY3RlZC5cbiAqL1xuY29uc3Qgc2NyaXB0Q2FjaGUgPSBuZXcgTWFwPHN0cmluZywgTWFwPHN0cmluZywgU2NyaXB0Pj4oKTtcblxuLyoqXG4gKiBNYXggbnVtYmVyIG9mIGRpc3RpbmN0IGJ1bmRsZSAoYGNvZGVgKSB2ZXJzaW9ucyB0byByZXRhaW4uIE9uZSBpcyBlbm91Z2ggZm9yXG4gKiBwcm9kdWN0aW9uOyBhIGhhbmRmdWwgY292ZXJzIHBhdGhvbG9naWNhbCBkZXYgaG90LXJlbG9hZCAvIHJlcGVhdGVkLXJlYnVpbGRcbiAqIGNodXJuIHdpdGhpbiBhIHNpbmdsZSBsb25nLWxpdmVkIHByb2Nlc3MgKGUuZy4gYSB3YXRjaCBzZXNzaW9uIG9yIGEgdGVzdFxuICogZmlsZSkgd2l0aG91dCB1bmJvdW5kZWQgZ3Jvd3RoLiBLZXB0IGRlbGliZXJhdGVseSBzbWFsbCDigJQgdGhlcmUgaXMgbm8gdmFsdWVcbiAqIGluIHJldGFpbmluZyBzdGFsZSBidW5kbGVzLCBvbmx5IGEgbWVtb3J5IGNvc3QuXG4gKi9cbmNvbnN0IE1BWF9CVU5ETEVTID0gODtcblxuLyoqXG4gKiBMb29rcyB1cCB0aGUgcGVyLWZpbGVuYW1lIG1hcCBmb3IgYGNvZGVgLCBtYXJraW5nIGl0IG1vc3QtcmVjZW50bHktdXNlZC5cbiAqIFJlbGllcyBvbiBgTWFwYCBwcmVzZXJ2aW5nIGluc2VydGlvbiBvcmRlcjogZGVsZXRpbmcgYW5kIHJlLWluc2VydGluZyBhblxuICogZXhpc3Rpbmcga2V5IG1vdmVzIGl0IHRvIHRoZSBlbmQgKG5ld2VzdCksIHNvIHRoZSBmaXJzdCBrZXkgaXMgYWx3YXlzIHRoZVxuICogbGVhc3QtcmVjZW50bHktdXNlZCBldmljdGlvbiBjYW5kaWRhdGUuXG4gKi9cbmZ1bmN0aW9uIHRvdWNoQnVuZGxlKGNvZGU6IHN0cmluZyk6IE1hcDxzdHJpbmcsIFNjcmlwdD4gfCB1bmRlZmluZWQge1xuICBjb25zdCBieUZpbGVuYW1lID0gc2NyaXB0Q2FjaGUuZ2V0KGNvZGUpO1xuICBpZiAoYnlGaWxlbmFtZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICAvLyBNb3ZlIHRvIHRoZSBtb3N0LXJlY2VudGx5LXVzZWQgcG9zaXRpb24gKGVuZCBvZiBpbnNlcnRpb24gb3JkZXIpLlxuICBzY3JpcHRDYWNoZS5kZWxldGUoY29kZSk7XG4gIHNjcmlwdENhY2hlLnNldChjb2RlLCBieUZpbGVuYW1lKTtcbiAgcmV0dXJuIGJ5RmlsZW5hbWU7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGNvbXBpbGVkIGB2bS5TY3JpcHRgIGZvciB0aGUgZ2l2ZW4gd29ya2Zsb3cgYnVuZGxlIGNvZGUgYW5kXG4gKiBmaWxlbmFtZSwgY29tcGlsaW5nIGFuZCBjYWNoaW5nIGl0IG9uIGZpcnN0IHVzZS4gU3Vic2VxdWVudCBjYWxscyB3aXRoIHRoZVxuICogc2FtZSBgKGNvZGUsIGZpbGVuYW1lKWAgcmV0dXJuIHRoZSBjYWNoZWQgYFNjcmlwdGAuXG4gKlxuICogVGhlIHJldHVybmVkIGBTY3JpcHRgIGlzIG5vdCB5ZXQgYm91bmQgdG8gYW55IGNvbnRleHQ7IHRoZSBjYWxsZXIgcnVucyBpdFxuICogYWdhaW5zdCBhIHNwZWNpZmljIFZNIGNvbnRleHQgdmlhIGBzY3JpcHQucnVuSW5Db250ZXh0KGNvbnRleHQpYC4gVGhpcyBpc1xuICogZXF1aXZhbGVudCB0byBgdm0ucnVuSW5Db250ZXh0KGNvZGUsIGNvbnRleHQsIHsgZmlsZW5hbWUgfSlgIGJ1dCBza2lwcyB0aGVcbiAqIHJlY29tcGlsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlZFdvcmtmbG93U2NyaXB0KFxuICBjb2RlOiBzdHJpbmcsXG4gIGZpbGVuYW1lOiBzdHJpbmdcbik6IFNjcmlwdCB7XG4gIGxldCBieUZpbGVuYW1lID0gdG91Y2hCdW5kbGUoY29kZSk7XG4gIGlmIChieUZpbGVuYW1lID09PSB1bmRlZmluZWQpIHtcbiAgICBieUZpbGVuYW1lID0gbmV3IE1hcDxzdHJpbmcsIFNjcmlwdD4oKTtcbiAgICBzY3JpcHRDYWNoZS5zZXQoY29kZSwgYnlGaWxlbmFtZSk7XG4gICAgLy8gRXZpY3QgdGhlIGxlYXN0LXJlY2VudGx5LXVzZWQgYnVuZGxlKHMpIHdoZW4gb3ZlciB0aGUgY2FwLiBOZXcgYnVuZGxlc1xuICAgIC8vIGFyZSBhcHBlbmRlZCBhdCB0aGUgZW5kLCBzbyB0aGUgb2xkZXN0IGxpdmUgYXQgdGhlIGZyb250LlxuICAgIHdoaWxlIChzY3JpcHRDYWNoZS5zaXplID4gTUFYX0JVTkRMRVMpIHtcbiAgICAgIGNvbnN0IG9sZGVzdCA9IHNjcmlwdENhY2hlLmtleXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICBpZiAob2xkZXN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzY3JpcHRDYWNoZS5kZWxldGUob2xkZXN0KTtcbiAgICB9XG4gIH1cbiAgbGV0IHNjcmlwdCA9IGJ5RmlsZW5hbWUuZ2V0KGZpbGVuYW1lKTtcbiAgaWYgKHNjcmlwdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc2NyaXB0ID0gbmV3IFNjcmlwdChjb2RlLCB7IGZpbGVuYW1lIH0pO1xuICAgIGJ5RmlsZW5hbWUuc2V0KGZpbGVuYW1lLCBzY3JpcHQpO1xuICB9XG4gIHJldHVybiBzY3JpcHQ7XG59XG5cbi8qKlxuICogUnVucyB0aGUgY2FjaGVkIHdvcmtmbG93LWJ1bmRsZSBgU2NyaXB0YCBhZ2FpbnN0IGBjb250ZXh0YC4gQ29tcGlsZXMgYW5kXG4gKiBjYWNoZXMgdGhlIGBTY3JpcHRgIG9uIGZpcnN0IHVzZSBmb3IgdGhlIGdpdmVuIGAoY29kZSwgZmlsZW5hbWUpYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1bkNhY2hlZFdvcmtmbG93U2NyaXB0KFxuICBjb2RlOiBzdHJpbmcsXG4gIGZpbGVuYW1lOiBzdHJpbmcsXG4gIGNvbnRleHQ6IENvbnRleHRcbik6IHVua25vd24ge1xuICByZXR1cm4gZ2V0Q2FjaGVkV29ya2Zsb3dTY3JpcHQoY29kZSwgZmlsZW5hbWUpLnJ1bkluQ29udGV4dChjb250ZXh0KTtcbn1cblxuLyoqXG4gKiBDbGVhcnMgdGhlIGNvbXBpbGVkLXNjcmlwdCBjYWNoZS4gSW50ZW5kZWQgZm9yIHRlc3RzIHRoYXQgd2FudCB0byBhc3NlcnRcbiAqIGNvbXBpbGUtdnMtY2FjaGUgYmVoYXZpb3VyIGluIGlzb2xhdGlvbjsgbm90IHVzZWQgb24gdGhlIGhvdCBwYXRoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJXb3JrZmxvd1NjcmlwdENhY2hlKCk6IHZvaWQge1xuICBzY3JpcHRDYWNoZS5jbGVhcigpO1xufVxuXG4vKipcbiAqIE51bWJlciBvZiBkaXN0aW5jdCBidW5kbGUgKGBjb2RlYCkgdmVyc2lvbnMgY3VycmVudGx5IHJldGFpbmVkLiBFeHBvc2VkIGZvclxuICogdGVzdHMgYXNzZXJ0aW5nIHRoZSBMUlUgYm91bmQ7IG5vdCB1c2VkIG9uIHRoZSBob3QgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdvcmtmbG93U2NyaXB0Q2FjaGVTaXplKCk6IG51bWJlciB7XG4gIHJldHVybiBzY3JpcHRDYWNoZS5zaXplO1xufVxuIl19
@@ -0,0 +1,65 @@
1
+ import type { WorkflowOrchestratorContext } from '../private.js';
2
+ import { ABORT_HOOK_TOKEN, ABORT_STREAM_NAME } from '../symbols.js';
3
+ /**
4
+ * A lightweight AbortSignal implementation for the workflow VM context.
5
+ *
6
+ * `signal.aborted` and listeners are updated in two scenarios:
7
+ * 1. On first-run: when `abort()` is called in the workflow code
8
+ * 2. On replay: when the events consumer processes the `hook_received`
9
+ * event (chained through promiseQueue for deterministic ordering)
10
+ *
11
+ * On replay, `abort()` in the workflow code becomes a no-op since
12
+ * `_setAborted` was already called by the events consumer.
13
+ */
14
+ export declare class WorkflowAbortSignal {
15
+ #private;
16
+ aborted: boolean;
17
+ reason: unknown;
18
+ readonly [ABORT_STREAM_NAME]: string;
19
+ readonly [ABORT_HOOK_TOKEN]: string;
20
+ get onabort(): ((this: WorkflowAbortSignal) => void) | null;
21
+ set onabort(handler: ((this: WorkflowAbortSignal) => void) | null);
22
+ constructor(streamName: string, hookToken: string);
23
+ /**
24
+ * @internal Sets aborted state and fires listeners.
25
+ * Called by abort() on first-run, or by the events consumer on replay.
26
+ * Idempotent — second call is a no-op.
27
+ */
28
+ _setAborted(reason?: unknown): void;
29
+ addEventListener(type: string, listener: () => void): void;
30
+ removeEventListener(type: string, listener: () => void): void;
31
+ throwIfAborted(): void;
32
+ }
33
+ /**
34
+ * Creates a workflow-context `AbortController` class that uses hooks for
35
+ * durable state and streams for real-time step propagation.
36
+ *
37
+ * Follows the same pattern as `createCreateHook()` in `workflow/hook.ts`:
38
+ * - Registers a hook in the invocations queue on construction
39
+ * - Subscribes to the events consumer for hook_created/hook_received events
40
+ * - `abort()` calls `_setAborted` + marks the hook for resumption
41
+ * - The suspension handler processes the abort (creates event + writes stream)
42
+ * - On replay, the events consumer calls `_setAborted` when hook_received
43
+ * is processed, and `abort()` in the workflow code becomes a no-op
44
+ */
45
+ export declare function createCreateAbortController(ctx: WorkflowOrchestratorContext): {
46
+ new (): {
47
+ readonly signal: WorkflowAbortSignal;
48
+ abort(reason?: unknown): void;
49
+ readonly [ABORT_STREAM_NAME]: string;
50
+ readonly [ABORT_HOOK_TOKEN]: string;
51
+ };
52
+ };
53
+ /**
54
+ * Creates a workflow-context `AbortSignal` object with static methods.
55
+ */
56
+ export declare function createAbortSignalStatics(): {
57
+ abort: (reason?: unknown) => WorkflowAbortSignal;
58
+ any: (signals: Iterable<{
59
+ aborted: boolean;
60
+ reason?: unknown;
61
+ addEventListener?: Function;
62
+ }>) => WorkflowAbortSignal;
63
+ timeout: () => never;
64
+ };
65
+ //# sourceMappingURL=abort-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort-controller.d.ts","sourceRoot":"","sources":["../../src/workflow/abort-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGpE;;;;;;;;;;GAUG;AACH,qBAAa,mBAAmB;;IAC9B,OAAO,UAAS;IAChB,MAAM,EAAE,OAAO,CAAa;IAE5B,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAKpC,IAAI,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,IAAI,CAE1D;IAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,IAAI,EAKhE;gBAEW,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKjD;;;;OAIG;IACH,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAanC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAa1D,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAK7D,cAAc,IAAI,IAAI;CAQvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,2BAA2B;;yBAEvD,mBAAmB;uBAwHrB,OAAO,GAAG,IAAI;sCAvHC,MAAM;qCACP,MAAM;;EAuItC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI;IAC1C,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,mBAAmB,CAAC;IACjD,GAAG,EAAE,CACH,OAAO,EAAE,QAAQ,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,gBAAgB,CAAC,EAAE,QAAQ,CAAC;KAC7B,CAAC,KACC,mBAAmB,CAAC;IACzB,OAAO,EAAE,MAAM,KAAK,CAAC;CACtB,CAwEA"}
@@ -0,0 +1,260 @@
1
+ import { ReplayDivergenceError } from '@workflow/errors';
2
+ import { EventConsumerResult } from '../events-consumer.js';
3
+ import { hydrateStepReturnValue } from '../serialization.js';
4
+ import { ABORT_HOOK_TOKEN, ABORT_STREAM_NAME } from '../symbols.js';
5
+ import { getAbortStreamId } from '../util.js';
6
+ /**
7
+ * A lightweight AbortSignal implementation for the workflow VM context.
8
+ *
9
+ * `signal.aborted` and listeners are updated in two scenarios:
10
+ * 1. On first-run: when `abort()` is called in the workflow code
11
+ * 2. On replay: when the events consumer processes the `hook_received`
12
+ * event (chained through promiseQueue for deterministic ordering)
13
+ *
14
+ * On replay, `abort()` in the workflow code becomes a no-op since
15
+ * `_setAborted` was already called by the events consumer.
16
+ */
17
+ export class WorkflowAbortSignal {
18
+ aborted = false;
19
+ reason = undefined;
20
+ [ABORT_STREAM_NAME];
21
+ [ABORT_HOOK_TOKEN];
22
+ #listeners = [];
23
+ #onabort = null;
24
+ get onabort() {
25
+ return this.#onabort;
26
+ }
27
+ set onabort(handler) {
28
+ this.#onabort = handler;
29
+ if (handler && this.aborted) {
30
+ handler.call(this);
31
+ }
32
+ }
33
+ constructor(streamName, hookToken) {
34
+ this[ABORT_STREAM_NAME] = streamName;
35
+ this[ABORT_HOOK_TOKEN] = hookToken;
36
+ }
37
+ /**
38
+ * @internal Sets aborted state and fires listeners.
39
+ * Called by abort() on first-run, or by the events consumer on replay.
40
+ * Idempotent — second call is a no-op.
41
+ */
42
+ _setAborted(reason) {
43
+ if (this.aborted)
44
+ return;
45
+ this.aborted = true;
46
+ this.reason = reason;
47
+ if (this.#onabort) {
48
+ this.#onabort.call(this);
49
+ }
50
+ for (const listener of this.#listeners) {
51
+ listener();
52
+ }
53
+ this.#listeners = [];
54
+ }
55
+ addEventListener(type, listener) {
56
+ if (type !== 'abort')
57
+ return;
58
+ if (this.aborted) {
59
+ // Fire synchronously, not on a microtask. Native AbortSignal fires on a
60
+ // microtask per spec, but inside the workflow VM we deliberately diverge
61
+ // for deterministic replay: listener ordering must be tied to the
62
+ // orchestrator's sync execution path, not to microtask scheduling.
63
+ listener();
64
+ return;
65
+ }
66
+ this.#listeners.push(listener);
67
+ }
68
+ removeEventListener(type, listener) {
69
+ if (type !== 'abort')
70
+ return;
71
+ this.#listeners = this.#listeners.filter((l) => l !== listener);
72
+ }
73
+ throwIfAborted() {
74
+ if (this.aborted) {
75
+ throw (this.reason ??
76
+ new DOMException('The operation was aborted.', 'AbortError'));
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * Creates a workflow-context `AbortController` class that uses hooks for
82
+ * durable state and streams for real-time step propagation.
83
+ *
84
+ * Follows the same pattern as `createCreateHook()` in `workflow/hook.ts`:
85
+ * - Registers a hook in the invocations queue on construction
86
+ * - Subscribes to the events consumer for hook_created/hook_received events
87
+ * - `abort()` calls `_setAborted` + marks the hook for resumption
88
+ * - The suspension handler processes the abort (creates event + writes stream)
89
+ * - On replay, the events consumer calls `_setAborted` when hook_received
90
+ * is processed, and `abort()` in the workflow code becomes a no-op
91
+ */
92
+ export function createCreateAbortController(ctx) {
93
+ return class WorkflowAbortController {
94
+ signal;
95
+ [ABORT_STREAM_NAME];
96
+ [ABORT_HOOK_TOKEN];
97
+ constructor() {
98
+ const id = ctx.generateUlid();
99
+ const streamName = getAbortStreamId(id);
100
+ const hookToken = `abrt_${id}`;
101
+ this[ABORT_STREAM_NAME] = streamName;
102
+ this[ABORT_HOOK_TOKEN] = hookToken;
103
+ this.signal = new WorkflowAbortSignal(streamName, hookToken);
104
+ // Register an internal system hook in the invocations queue.
105
+ // isSystem prevents token namespace conflicts with user hooks.
106
+ const correlationId = `hook_${ctx.generateUlid()}`;
107
+ ctx.invocationsQueue.set(correlationId, {
108
+ type: 'hook',
109
+ correlationId,
110
+ token: hookToken,
111
+ isWebhook: false,
112
+ isSystem: true,
113
+ });
114
+ // Subscribe to events for this hook's lifecycle
115
+ ctx.eventsConsumer.subscribe((event) => {
116
+ if (!event) {
117
+ return EventConsumerResult.NotConsumed;
118
+ }
119
+ if (event.correlationId !== correlationId) {
120
+ return EventConsumerResult.NotConsumed;
121
+ }
122
+ const eventToken = 'eventData' in event && event.eventData && 'token' in event.eventData
123
+ ? event.eventData.token
124
+ : undefined;
125
+ if (typeof eventToken === 'string' &&
126
+ eventToken !== this[ABORT_HOOK_TOKEN]) {
127
+ ctx.promiseQueue = ctx.promiseQueue.then(() => {
128
+ ctx.onWorkflowError(new ReplayDivergenceError(`Replay divergence: abort hook event ${event.eventType} for ${correlationId} belongs to token "${eventToken}", but the current abort hook expects "${this[ABORT_HOOK_TOKEN]}"`, { eventId: event.eventId }));
129
+ });
130
+ return EventConsumerResult.Finished;
131
+ }
132
+ if (event.eventType === 'hook_created') {
133
+ const queueItem = ctx.invocationsQueue.get(correlationId);
134
+ if (queueItem && queueItem.type === 'hook') {
135
+ queueItem.hasCreatedEvent = true;
136
+ }
137
+ return EventConsumerResult.Consumed;
138
+ }
139
+ if (event.eventType === 'hook_received') {
140
+ // The abort was recorded in the event log (from a previous run's
141
+ // abort() call, or from a step/external abort). Update signal
142
+ // state and fire listeners at this deterministic point in the
143
+ // promiseQueue — same ordering as hook payload delivery.
144
+ //
145
+ // The payload is the dehydrated form written by the suspension
146
+ // handler (a Uint8Array, possibly encrypted). Hydrate it via the
147
+ // same machinery as regular hook payloads (workflow/hook.ts:117)
148
+ // so the reason round-trips with full type fidelity. Reading the
149
+ // raw payload here is a bug — it's not a plain object after
150
+ // dehydration, so `'reason' in payload` is false and reason
151
+ // ends up undefined on replay.
152
+ const rawPayload = event.eventData?.payload;
153
+ ctx.promiseQueue = ctx.promiseQueue.then(async () => {
154
+ let reason;
155
+ if (rawPayload !== undefined) {
156
+ try {
157
+ const hydrated = (await hydrateStepReturnValue(rawPayload, ctx.runId, ctx.encryptionKey, ctx.globalThis));
158
+ if (hydrated &&
159
+ typeof hydrated === 'object' &&
160
+ 'reason' in hydrated) {
161
+ reason = hydrated.reason;
162
+ }
163
+ }
164
+ catch {
165
+ // Best-effort: if hydration fails, fall back to undefined
166
+ // reason. The signal still aborts; the user just won't see
167
+ // the original reason. Matches WorkflowAbortSignal's spec
168
+ // fallback (DOMException AbortError).
169
+ }
170
+ }
171
+ this.signal._setAborted(reason);
172
+ });
173
+ ctx.invocationsQueue.delete(correlationId);
174
+ // Multiple handlers can observe the same pending abort request and
175
+ // durably record it before replay removes the queue item. Abort is
176
+ // idempotent, so consume later matching receipts as no-ops instead
177
+ // of surfacing a corrupted event log after the first receipt.
178
+ return EventConsumerResult.Consumed;
179
+ }
180
+ if (event.eventType === 'hook_disposed') {
181
+ ctx.invocationsQueue.delete(correlationId);
182
+ return EventConsumerResult.Finished;
183
+ }
184
+ return EventConsumerResult.NotConsumed;
185
+ });
186
+ }
187
+ abort(reason) {
188
+ if (this.signal.aborted)
189
+ return; // no-op (already aborted, e.g. from replay)
190
+ // Update signal state and fire listeners synchronously
191
+ this.signal._setAborted(reason);
192
+ // Mark the hook for resumption so the suspension handler records
193
+ // the abort in the event log and writes the stream packet.
194
+ for (const [, item] of ctx.invocationsQueue) {
195
+ if (item.type === 'hook' && item.token === this[ABORT_HOOK_TOKEN]) {
196
+ item.abortRequested = true;
197
+ item.abortReason = reason;
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ };
203
+ }
204
+ /**
205
+ * Creates a workflow-context `AbortSignal` object with static methods.
206
+ */
207
+ export function createAbortSignalStatics() {
208
+ return {
209
+ abort(reason) {
210
+ const signal = new WorkflowAbortSignal('', '');
211
+ signal._setAborted(reason ?? new DOMException('The operation was aborted.', 'AbortError'));
212
+ return signal;
213
+ },
214
+ any(signals) {
215
+ const composite = new WorkflowAbortSignal('', '');
216
+ // Materialize the iterable once. Native AbortSignal.any does the same:
217
+ // single-shot iterables (e.g. generators) would otherwise produce zero
218
+ // entries on the second pass below.
219
+ const arr = Array.from(signals);
220
+ for (const signal of arr) {
221
+ if (signal.aborted) {
222
+ composite._setAborted(signal.reason);
223
+ return composite;
224
+ }
225
+ }
226
+ // Listen to each signal — first one to abort wins. Track listeners so
227
+ // we can remove them after the composite aborts; otherwise the closures
228
+ // (capturing `composite`) prevent GC for any input signal that outlives
229
+ // the composite (e.g. a long-lived external controller).
230
+ const listeners = [];
231
+ const cleanup = () => {
232
+ for (const { signal, listener } of listeners) {
233
+ if (signal.removeEventListener) {
234
+ signal.removeEventListener('abort', listener);
235
+ }
236
+ }
237
+ listeners.length = 0;
238
+ };
239
+ for (const signal of arr) {
240
+ if (!signal.addEventListener)
241
+ continue;
242
+ const listener = () => {
243
+ if (!composite.aborted) {
244
+ composite._setAborted(signal.reason);
245
+ cleanup();
246
+ }
247
+ };
248
+ listeners.push({ signal, listener });
249
+ signal.addEventListener('abort', listener);
250
+ }
251
+ return composite;
252
+ },
253
+ timeout() {
254
+ throw new Error('AbortSignal.timeout() is not supported in workflow functions. ' +
255
+ 'Use sleep() with an AbortController instead. ' +
256
+ 'See: /docs/errors/abort-signal-timeout-in-workflow');
257
+ },
258
+ };
259
+ }
260
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJvcnQtY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JrZmxvdy9hYm9ydC1jb250cm9sbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRTVELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFOUM7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sT0FBTyxtQkFBbUI7SUFDOUIsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNoQixNQUFNLEdBQVksU0FBUyxDQUFDO0lBRW5CLENBQUMsaUJBQWlCLENBQUMsQ0FBUztJQUM1QixDQUFDLGdCQUFnQixDQUFDLENBQVM7SUFFcEMsVUFBVSxHQUFzQixFQUFFLENBQUM7SUFDbkMsUUFBUSxHQUFpRCxJQUFJLENBQUM7SUFFOUQsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxJQUFJLE9BQU8sQ0FBQyxPQUFxRDtRQUMvRCxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUN4QixJQUFJLE9BQU8sSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNyQixDQUFDO0lBQ0gsQ0FBQztJQUVELFlBQVksVUFBa0IsRUFBRSxTQUFpQjtRQUMvQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxVQUFVLENBQUM7UUFDckMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsU0FBUyxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsV0FBVyxDQUFDLE1BQWdCO1FBQzFCLElBQUksSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFPO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNCLENBQUM7UUFDRCxLQUFLLE1BQU0sUUFBUSxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUN2QyxRQUFRLEVBQUUsQ0FBQztRQUNiLENBQUM7UUFDRCxJQUFJLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsZ0JBQWdCLENBQUMsSUFBWSxFQUFFLFFBQW9CO1FBQ2pELElBQUksSUFBSSxLQUFLLE9BQU87WUFBRSxPQUFPO1FBQzdCLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2pCLHdFQUF3RTtZQUN4RSx5RUFBeUU7WUFDekUsa0VBQWtFO1lBQ2xFLG1FQUFtRTtZQUNuRSxRQUFRLEVBQUUsQ0FBQztZQUNYLE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELG1CQUFtQixDQUFDLElBQVksRUFBRSxRQUFvQjtRQUNwRCxJQUFJLElBQUksS0FBSyxPQUFPO1lBQUUsT0FBTztRQUM3QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssUUFBUSxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVELGNBQWM7UUFDWixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixNQUFNLENBQ0osSUFBSSxDQUFDLE1BQU07Z0JBQ1gsSUFBSSxZQUFZLENBQUMsNEJBQTRCLEVBQUUsWUFBWSxDQUFDLENBQzdELENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsMkJBQTJCLENBQUMsR0FBZ0M7SUFDMUUsT0FBTyxNQUFNLHVCQUF1QjtRQUN6QixNQUFNLENBQXNCO1FBQzVCLENBQUMsaUJBQWlCLENBQUMsQ0FBUztRQUM1QixDQUFDLGdCQUFnQixDQUFDLENBQVM7UUFFcEM7WUFDRSxNQUFNLEVBQUUsR0FBRyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDOUIsTUFBTSxVQUFVLEdBQUcsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDeEMsTUFBTSxTQUFTLEdBQUcsUUFBUSxFQUFFLEVBQUUsQ0FBQztZQUUvQixJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxVQUFVLENBQUM7WUFDckMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsU0FBUyxDQUFDO1lBQ25DLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFN0QsNkRBQTZEO1lBQzdELCtEQUErRDtZQUMvRCxNQUFNLGFBQWEsR0FBRyxRQUFRLEdBQUcsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO1lBQ25ELEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFO2dCQUN0QyxJQUFJLEVBQUUsTUFBTTtnQkFDWixhQUFhO2dCQUNiLEtBQUssRUFBRSxTQUFTO2dCQUNoQixTQUFTLEVBQUUsS0FBSztnQkFDaEIsUUFBUSxFQUFFLElBQUk7YUFDZixDQUFDLENBQUM7WUFFSCxnREFBZ0Q7WUFDaEQsR0FBRyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtnQkFDckMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNYLE9BQU8sbUJBQW1CLENBQUMsV0FBVyxDQUFDO2dCQUN6QyxDQUFDO2dCQUVELElBQUksS0FBSyxDQUFDLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztvQkFDMUMsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7Z0JBQ3pDLENBQUM7Z0JBRUQsTUFBTSxVQUFVLEdBQ2QsV0FBVyxJQUFJLEtBQUssSUFBSSxLQUFLLENBQUMsU0FBUyxJQUFJLE9BQU8sSUFBSSxLQUFLLENBQUMsU0FBUztvQkFDbkUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSztvQkFDdkIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztnQkFFaEIsSUFDRSxPQUFPLFVBQVUsS0FBSyxRQUFRO29CQUM5QixVQUFVLEtBQUssSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQ3JDLENBQUM7b0JBQ0QsR0FBRyxDQUFDLFlBQVksR0FBRyxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7d0JBQzVDLEdBQUcsQ0FBQyxlQUFlLENBQ2pCLElBQUkscUJBQXFCLENBQ3ZCLHVDQUF1QyxLQUFLLENBQUMsU0FBUyxRQUFRLGFBQWEsc0JBQXNCLFVBQVUsMENBQTBDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQzlLLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FDM0IsQ0FDRixDQUFDO29CQUNKLENBQUMsQ0FBQyxDQUFDO29CQUNILE9BQU8sbUJBQW1CLENBQUMsUUFBUSxDQUFDO2dCQUN0QyxDQUFDO2dCQUVELElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxjQUFjLEVBQUUsQ0FBQztvQkFDdkMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDMUQsSUFBSSxTQUFTLElBQUksU0FBUyxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQzt3QkFDM0MsU0FBUyxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7b0JBQ25DLENBQUM7b0JBQ0QsT0FBTyxtQkFBbUIsQ0FBQyxRQUFRLENBQUM7Z0JBQ3RDLENBQUM7Z0JBRUQsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLGVBQWUsRUFBRSxDQUFDO29CQUN4QyxpRUFBaUU7b0JBQ2pFLDhEQUE4RDtvQkFDOUQsOERBQThEO29CQUM5RCx5REFBeUQ7b0JBQ3pELEVBQUU7b0JBQ0YsK0RBQStEO29CQUMvRCxpRUFBaUU7b0JBQ2pFLGlFQUFpRTtvQkFDakUsaUVBQWlFO29CQUNqRSw0REFBNEQ7b0JBQzVELDREQUE0RDtvQkFDNUQsK0JBQStCO29CQUMvQixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQztvQkFDNUMsR0FBRyxDQUFDLFlBQVksR0FBRyxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTt3QkFDbEQsSUFBSSxNQUFlLENBQUM7d0JBQ3BCLElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDOzRCQUM3QixJQUFJLENBQUM7Z0NBQ0gsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFNLHNCQUFzQixDQUM1QyxVQUFVLEVBQ1YsR0FBRyxDQUFDLEtBQUssRUFDVCxHQUFHLENBQUMsYUFBYSxFQUNqQixHQUFHLENBQUMsVUFBVSxDQUNmLENBQXFDLENBQUM7Z0NBQ3ZDLElBQ0UsUUFBUTtvQ0FDUixPQUFPLFFBQVEsS0FBSyxRQUFRO29DQUM1QixRQUFRLElBQUksUUFBUSxFQUNwQixDQUFDO29DQUNELE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO2dDQUMzQixDQUFDOzRCQUNILENBQUM7NEJBQUMsTUFBTSxDQUFDO2dDQUNQLDBEQUEwRDtnQ0FDMUQsMkRBQTJEO2dDQUMzRCwwREFBMEQ7Z0NBQzFELHNDQUFzQzs0QkFDeEMsQ0FBQzt3QkFDSCxDQUFDO3dCQUNELElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUNsQyxDQUFDLENBQUMsQ0FBQztvQkFFSCxHQUFHLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO29CQUMzQyxtRUFBbUU7b0JBQ25FLG1FQUFtRTtvQkFDbkUsbUVBQW1FO29CQUNuRSw4REFBOEQ7b0JBQzlELE9BQU8sbUJBQW1CLENBQUMsUUFBUSxDQUFDO2dCQUN0QyxDQUFDO2dCQUVELElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxlQUFlLEVBQUUsQ0FBQztvQkFDeEMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDM0MsT0FBTyxtQkFBbUIsQ0FBQyxRQUFRLENBQUM7Z0JBQ3RDLENBQUM7Z0JBRUQsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7WUFDekMsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsS0FBSyxDQUFDLE1BQWdCO1lBQ3BCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLE9BQU8sQ0FBQyw0Q0FBNEM7WUFFN0UsdURBQXVEO1lBQ3ZELElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBRWhDLGlFQUFpRTtZQUNqRSwyREFBMkQ7WUFDM0QsS0FBSyxNQUFNLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztnQkFDNUMsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUM7b0JBQ2xFLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO29CQUMzQixJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQztvQkFDMUIsTUFBTTtnQkFDUixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QjtJQVd0QyxPQUFPO1FBQ0wsS0FBSyxDQUFDLE1BQWdCO1lBQ3BCLE1BQU0sTUFBTSxHQUFHLElBQUksbUJBQW1CLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQy9DLE1BQU0sQ0FBQyxXQUFXLENBQ2hCLE1BQU0sSUFBSSxJQUFJLFlBQVksQ0FBQyw0QkFBNEIsRUFBRSxZQUFZLENBQUMsQ0FDdkUsQ0FBQztZQUNGLE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7UUFFRCxHQUFHLENBQ0QsT0FLRTtZQUVGLE1BQU0sU0FBUyxHQUFHLElBQUksbUJBQW1CLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBRWxELHVFQUF1RTtZQUN2RSx1RUFBdUU7WUFDdkUsb0NBQW9DO1lBQ3BDLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFaEMsS0FBSyxNQUFNLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ25CLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUNyQyxPQUFPLFNBQVMsQ0FBQztnQkFDbkIsQ0FBQztZQUNILENBQUM7WUFFRCxzRUFBc0U7WUFDdEUsd0VBQXdFO1lBQ3hFLHdFQUF3RTtZQUN4RSx5REFBeUQ7WUFDekQsTUFBTSxTQUFTLEdBR1YsRUFBRSxDQUFDO1lBQ1IsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFO2dCQUNuQixLQUFLLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLElBQUksU0FBUyxFQUFFLENBQUM7b0JBQzdDLElBQUksTUFBTSxDQUFDLG1CQUFtQixFQUFFLENBQUM7d0JBQy9CLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQ2hELENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUN2QixDQUFDLENBQUM7WUFFRixLQUFLLE1BQU0sTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDO2dCQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLGdCQUFnQjtvQkFBRSxTQUFTO2dCQUN2QyxNQUFNLFFBQVEsR0FBRyxHQUFHLEVBQUU7b0JBQ3BCLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7d0JBQ3ZCLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO3dCQUNyQyxPQUFPLEVBQUUsQ0FBQztvQkFDWixDQUFDO2dCQUNILENBQUMsQ0FBQztnQkFDRixTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQ3JDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDN0MsQ0FBQztZQUVELE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFFRCxPQUFPO1lBQ0wsTUFBTSxJQUFJLEtBQUssQ0FDYixnRUFBZ0U7Z0JBQzlELCtDQUErQztnQkFDL0Msb0RBQW9ELENBQ3ZELENBQUM7UUFDSixDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXBsYXlEaXZlcmdlbmNlRXJyb3IgfSBmcm9tICdAd29ya2Zsb3cvZXJyb3JzJztcbmltcG9ydCB7IEV2ZW50Q29uc3VtZXJSZXN1bHQgfSBmcm9tICcuLi9ldmVudHMtY29uc3VtZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBXb3JrZmxvd09yY2hlc3RyYXRvckNvbnRleHQgfSBmcm9tICcuLi9wcml2YXRlLmpzJztcbmltcG9ydCB7IGh5ZHJhdGVTdGVwUmV0dXJuVmFsdWUgfSBmcm9tICcuLi9zZXJpYWxpemF0aW9uLmpzJztcbmltcG9ydCB7IEFCT1JUX0hPT0tfVE9LRU4sIEFCT1JUX1NUUkVBTV9OQU1FIH0gZnJvbSAnLi4vc3ltYm9scy5qcyc7XG5pbXBvcnQgeyBnZXRBYm9ydFN0cmVhbUlkIH0gZnJvbSAnLi4vdXRpbC5qcyc7XG5cbi8qKlxuICogQSBsaWdodHdlaWdodCBBYm9ydFNpZ25hbCBpbXBsZW1lbnRhdGlvbiBmb3IgdGhlIHdvcmtmbG93IFZNIGNvbnRleHQuXG4gKlxuICogYHNpZ25hbC5hYm9ydGVkYCBhbmQgbGlzdGVuZXJzIGFyZSB1cGRhdGVkIGluIHR3byBzY2VuYXJpb3M6XG4gKiAxLiBPbiBmaXJzdC1ydW46IHdoZW4gYGFib3J0KClgIGlzIGNhbGxlZCBpbiB0aGUgd29ya2Zsb3cgY29kZVxuICogMi4gT24gcmVwbGF5OiB3aGVuIHRoZSBldmVudHMgY29uc3VtZXIgcHJvY2Vzc2VzIHRoZSBgaG9va19yZWNlaXZlZGBcbiAqICAgIGV2ZW50IChjaGFpbmVkIHRocm91Z2ggcHJvbWlzZVF1ZXVlIGZvciBkZXRlcm1pbmlzdGljIG9yZGVyaW5nKVxuICpcbiAqIE9uIHJlcGxheSwgYGFib3J0KClgIGluIHRoZSB3b3JrZmxvdyBjb2RlIGJlY29tZXMgYSBuby1vcCBzaW5jZVxuICogYF9zZXRBYm9ydGVkYCB3YXMgYWxyZWFkeSBjYWxsZWQgYnkgdGhlIGV2ZW50cyBjb25zdW1lci5cbiAqL1xuZXhwb3J0IGNsYXNzIFdvcmtmbG93QWJvcnRTaWduYWwge1xuICBhYm9ydGVkID0gZmFsc2U7XG4gIHJlYXNvbjogdW5rbm93biA9IHVuZGVmaW5lZDtcblxuICByZWFkb25seSBbQUJPUlRfU1RSRUFNX05BTUVdOiBzdHJpbmc7XG4gIHJlYWRvbmx5IFtBQk9SVF9IT09LX1RPS0VOXTogc3RyaW5nO1xuXG4gICNsaXN0ZW5lcnM6IEFycmF5PCgpID0+IHZvaWQ+ID0gW107XG4gICNvbmFib3J0OiAoKHRoaXM6IFdvcmtmbG93QWJvcnRTaWduYWwpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG5cbiAgZ2V0IG9uYWJvcnQoKTogKCh0aGlzOiBXb3JrZmxvd0Fib3J0U2lnbmFsKSA9PiB2b2lkKSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLiNvbmFib3J0O1xuICB9XG5cbiAgc2V0IG9uYWJvcnQoaGFuZGxlcjogKCh0aGlzOiBXb3JrZmxvd0Fib3J0U2lnbmFsKSA9PiB2b2lkKSB8IG51bGwpIHtcbiAgICB0aGlzLiNvbmFib3J0ID0gaGFuZGxlcjtcbiAgICBpZiAoaGFuZGxlciAmJiB0aGlzLmFib3J0ZWQpIHtcbiAgICAgIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICB9XG4gIH1cblxuICBjb25zdHJ1Y3RvcihzdHJlYW1OYW1lOiBzdHJpbmcsIGhvb2tUb2tlbjogc3RyaW5nKSB7XG4gICAgdGhpc1tBQk9SVF9TVFJFQU1fTkFNRV0gPSBzdHJlYW1OYW1lO1xuICAgIHRoaXNbQUJPUlRfSE9PS19UT0tFTl0gPSBob29rVG9rZW47XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsIFNldHMgYWJvcnRlZCBzdGF0ZSBhbmQgZmlyZXMgbGlzdGVuZXJzLlxuICAgKiBDYWxsZWQgYnkgYWJvcnQoKSBvbiBmaXJzdC1ydW4sIG9yIGJ5IHRoZSBldmVudHMgY29uc3VtZXIgb24gcmVwbGF5LlxuICAgKiBJZGVtcG90ZW50IOKAlCBzZWNvbmQgY2FsbCBpcyBhIG5vLW9wLlxuICAgKi9cbiAgX3NldEFib3J0ZWQocmVhc29uPzogdW5rbm93bik6IHZvaWQge1xuICAgIGlmICh0aGlzLmFib3J0ZWQpIHJldHVybjtcbiAgICB0aGlzLmFib3J0ZWQgPSB0cnVlO1xuICAgIHRoaXMucmVhc29uID0gcmVhc29uO1xuICAgIGlmICh0aGlzLiNvbmFib3J0KSB7XG4gICAgICB0aGlzLiNvbmFib3J0LmNhbGwodGhpcyk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgbGlzdGVuZXIgb2YgdGhpcy4jbGlzdGVuZXJzKSB7XG4gICAgICBsaXN0ZW5lcigpO1xuICAgIH1cbiAgICB0aGlzLiNsaXN0ZW5lcnMgPSBbXTtcbiAgfVxuXG4gIGFkZEV2ZW50TGlzdGVuZXIodHlwZTogc3RyaW5nLCBsaXN0ZW5lcjogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIGlmICh0eXBlICE9PSAnYWJvcnQnKSByZXR1cm47XG4gICAgaWYgKHRoaXMuYWJvcnRlZCkge1xuICAgICAgLy8gRmlyZSBzeW5jaHJvbm91c2x5LCBub3Qgb24gYSBtaWNyb3Rhc2suIE5hdGl2ZSBBYm9ydFNpZ25hbCBmaXJlcyBvbiBhXG4gICAgICAvLyBtaWNyb3Rhc2sgcGVyIHNwZWMsIGJ1dCBpbnNpZGUgdGhlIHdvcmtmbG93IFZNIHdlIGRlbGliZXJhdGVseSBkaXZlcmdlXG4gICAgICAvLyBmb3IgZGV0ZXJtaW5pc3RpYyByZXBsYXk6IGxpc3RlbmVyIG9yZGVyaW5nIG11c3QgYmUgdGllZCB0byB0aGVcbiAgICAgIC8vIG9yY2hlc3RyYXRvcidzIHN5bmMgZXhlY3V0aW9uIHBhdGgsIG5vdCB0byBtaWNyb3Rhc2sgc2NoZWR1bGluZy5cbiAgICAgIGxpc3RlbmVyKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuI2xpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXIodHlwZTogc3RyaW5nLCBsaXN0ZW5lcjogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIGlmICh0eXBlICE9PSAnYWJvcnQnKSByZXR1cm47XG4gICAgdGhpcy4jbGlzdGVuZXJzID0gdGhpcy4jbGlzdGVuZXJzLmZpbHRlcigobCkgPT4gbCAhPT0gbGlzdGVuZXIpO1xuICB9XG5cbiAgdGhyb3dJZkFib3J0ZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYWJvcnRlZCkge1xuICAgICAgdGhyb3cgKFxuICAgICAgICB0aGlzLnJlYXNvbiA/P1xuICAgICAgICBuZXcgRE9NRXhjZXB0aW9uKCdUaGUgb3BlcmF0aW9uIHdhcyBhYm9ydGVkLicsICdBYm9ydEVycm9yJylcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHdvcmtmbG93LWNvbnRleHQgYEFib3J0Q29udHJvbGxlcmAgY2xhc3MgdGhhdCB1c2VzIGhvb2tzIGZvclxuICogZHVyYWJsZSBzdGF0ZSBhbmQgc3RyZWFtcyBmb3IgcmVhbC10aW1lIHN0ZXAgcHJvcGFnYXRpb24uXG4gKlxuICogRm9sbG93cyB0aGUgc2FtZSBwYXR0ZXJuIGFzIGBjcmVhdGVDcmVhdGVIb29rKClgIGluIGB3b3JrZmxvdy9ob29rLnRzYDpcbiAqIC0gUmVnaXN0ZXJzIGEgaG9vayBpbiB0aGUgaW52b2NhdGlvbnMgcXVldWUgb24gY29uc3RydWN0aW9uXG4gKiAtIFN1YnNjcmliZXMgdG8gdGhlIGV2ZW50cyBjb25zdW1lciBmb3IgaG9va19jcmVhdGVkL2hvb2tfcmVjZWl2ZWQgZXZlbnRzXG4gKiAtIGBhYm9ydCgpYCBjYWxscyBgX3NldEFib3J0ZWRgICsgbWFya3MgdGhlIGhvb2sgZm9yIHJlc3VtcHRpb25cbiAqIC0gVGhlIHN1c3BlbnNpb24gaGFuZGxlciBwcm9jZXNzZXMgdGhlIGFib3J0IChjcmVhdGVzIGV2ZW50ICsgd3JpdGVzIHN0cmVhbSlcbiAqIC0gT24gcmVwbGF5LCB0aGUgZXZlbnRzIGNvbnN1bWVyIGNhbGxzIGBfc2V0QWJvcnRlZGAgd2hlbiBob29rX3JlY2VpdmVkXG4gKiAgIGlzIHByb2Nlc3NlZCwgYW5kIGBhYm9ydCgpYCBpbiB0aGUgd29ya2Zsb3cgY29kZSBiZWNvbWVzIGEgbm8tb3BcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNyZWF0ZUFib3J0Q29udHJvbGxlcihjdHg6IFdvcmtmbG93T3JjaGVzdHJhdG9yQ29udGV4dCkge1xuICByZXR1cm4gY2xhc3MgV29ya2Zsb3dBYm9ydENvbnRyb2xsZXIge1xuICAgIHJlYWRvbmx5IHNpZ25hbDogV29ya2Zsb3dBYm9ydFNpZ25hbDtcbiAgICByZWFkb25seSBbQUJPUlRfU1RSRUFNX05BTUVdOiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgW0FCT1JUX0hPT0tfVE9LRU5dOiBzdHJpbmc7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgIGNvbnN0IGlkID0gY3R4LmdlbmVyYXRlVWxpZCgpO1xuICAgICAgY29uc3Qgc3RyZWFtTmFtZSA9IGdldEFib3J0U3RyZWFtSWQoaWQpO1xuICAgICAgY29uc3QgaG9va1Rva2VuID0gYGFicnRfJHtpZH1gO1xuXG4gICAgICB0aGlzW0FCT1JUX1NUUkVBTV9OQU1FXSA9IHN0cmVhbU5hbWU7XG4gICAgICB0aGlzW0FCT1JUX0hPT0tfVE9LRU5dID0gaG9va1Rva2VuO1xuICAgICAgdGhpcy5zaWduYWwgPSBuZXcgV29ya2Zsb3dBYm9ydFNpZ25hbChzdHJlYW1OYW1lLCBob29rVG9rZW4pO1xuXG4gICAgICAvLyBSZWdpc3RlciBhbiBpbnRlcm5hbCBzeXN0ZW0gaG9vayBpbiB0aGUgaW52b2NhdGlvbnMgcXVldWUuXG4gICAgICAvLyBpc1N5c3RlbSBwcmV2ZW50cyB0b2tlbiBuYW1lc3BhY2UgY29uZmxpY3RzIHdpdGggdXNlciBob29rcy5cbiAgICAgIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBgaG9va18ke2N0eC5nZW5lcmF0ZVVsaWQoKX1gO1xuICAgICAgY3R4Lmludm9jYXRpb25zUXVldWUuc2V0KGNvcnJlbGF0aW9uSWQsIHtcbiAgICAgICAgdHlwZTogJ2hvb2snLFxuICAgICAgICBjb3JyZWxhdGlvbklkLFxuICAgICAgICB0b2tlbjogaG9va1Rva2VuLFxuICAgICAgICBpc1dlYmhvb2s6IGZhbHNlLFxuICAgICAgICBpc1N5c3RlbTogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBTdWJzY3JpYmUgdG8gZXZlbnRzIGZvciB0aGlzIGhvb2sncyBsaWZlY3ljbGVcbiAgICAgIGN0eC5ldmVudHNDb25zdW1lci5zdWJzY3JpYmUoKGV2ZW50KSA9PiB7XG4gICAgICAgIGlmICghZXZlbnQpIHtcbiAgICAgICAgICByZXR1cm4gRXZlbnRDb25zdW1lclJlc3VsdC5Ob3RDb25zdW1lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5jb3JyZWxhdGlvbklkICE9PSBjb3JyZWxhdGlvbklkKSB7XG4gICAgICAgICAgcmV0dXJuIEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBldmVudFRva2VuID1cbiAgICAgICAgICAnZXZlbnREYXRhJyBpbiBldmVudCAmJiBldmVudC5ldmVudERhdGEgJiYgJ3Rva2VuJyBpbiBldmVudC5ldmVudERhdGFcbiAgICAgICAgICAgID8gZXZlbnQuZXZlbnREYXRhLnRva2VuXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgdHlwZW9mIGV2ZW50VG9rZW4gPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgZXZlbnRUb2tlbiAhPT0gdGhpc1tBQk9SVF9IT09LX1RPS0VOXVxuICAgICAgICApIHtcbiAgICAgICAgICBjdHgucHJvbWlzZVF1ZXVlID0gY3R4LnByb21pc2VRdWV1ZS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIGN0eC5vbldvcmtmbG93RXJyb3IoXG4gICAgICAgICAgICAgIG5ldyBSZXBsYXlEaXZlcmdlbmNlRXJyb3IoXG4gICAgICAgICAgICAgICAgYFJlcGxheSBkaXZlcmdlbmNlOiBhYm9ydCBob29rIGV2ZW50ICR7ZXZlbnQuZXZlbnRUeXBlfSBmb3IgJHtjb3JyZWxhdGlvbklkfSBiZWxvbmdzIHRvIHRva2VuIFwiJHtldmVudFRva2VufVwiLCBidXQgdGhlIGN1cnJlbnQgYWJvcnQgaG9vayBleHBlY3RzIFwiJHt0aGlzW0FCT1JUX0hPT0tfVE9LRU5dfVwiYCxcbiAgICAgICAgICAgICAgICB7IGV2ZW50SWQ6IGV2ZW50LmV2ZW50SWQgfVxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiBFdmVudENvbnN1bWVyUmVzdWx0LkZpbmlzaGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmV2ZW50VHlwZSA9PT0gJ2hvb2tfY3JlYXRlZCcpIHtcbiAgICAgICAgICBjb25zdCBxdWV1ZUl0ZW0gPSBjdHguaW52b2NhdGlvbnNRdWV1ZS5nZXQoY29ycmVsYXRpb25JZCk7XG4gICAgICAgICAgaWYgKHF1ZXVlSXRlbSAmJiBxdWV1ZUl0ZW0udHlwZSA9PT0gJ2hvb2snKSB7XG4gICAgICAgICAgICBxdWV1ZUl0ZW0uaGFzQ3JlYXRlZEV2ZW50ID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIEV2ZW50Q29uc3VtZXJSZXN1bHQuQ29uc3VtZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQuZXZlbnRUeXBlID09PSAnaG9va19yZWNlaXZlZCcpIHtcbiAgICAgICAgICAvLyBUaGUgYWJvcnQgd2FzIHJlY29yZGVkIGluIHRoZSBldmVudCBsb2cgKGZyb20gYSBwcmV2aW91cyBydW4nc1xuICAgICAgICAgIC8vIGFib3J0KCkgY2FsbCwgb3IgZnJvbSBhIHN0ZXAvZXh0ZXJuYWwgYWJvcnQpLiBVcGRhdGUgc2lnbmFsXG4gICAgICAgICAgLy8gc3RhdGUgYW5kIGZpcmUgbGlzdGVuZXJzIGF0IHRoaXMgZGV0ZXJtaW5pc3RpYyBwb2ludCBpbiB0aGVcbiAgICAgICAgICAvLyBwcm9taXNlUXVldWUg4oCUIHNhbWUgb3JkZXJpbmcgYXMgaG9vayBwYXlsb2FkIGRlbGl2ZXJ5LlxuICAgICAgICAgIC8vXG4gICAgICAgICAgLy8gVGhlIHBheWxvYWQgaXMgdGhlIGRlaHlkcmF0ZWQgZm9ybSB3cml0dGVuIGJ5IHRoZSBzdXNwZW5zaW9uXG4gICAgICAgICAgLy8gaGFuZGxlciAoYSBVaW50OEFycmF5LCBwb3NzaWJseSBlbmNyeXB0ZWQpLiBIeWRyYXRlIGl0IHZpYSB0aGVcbiAgICAgICAgICAvLyBzYW1lIG1hY2hpbmVyeSBhcyByZWd1bGFyIGhvb2sgcGF5bG9hZHMgKHdvcmtmbG93L2hvb2sudHM6MTE3KVxuICAgICAgICAgIC8vIHNvIHRoZSByZWFzb24gcm91bmQtdHJpcHMgd2l0aCBmdWxsIHR5cGUgZmlkZWxpdHkuIFJlYWRpbmcgdGhlXG4gICAgICAgICAgLy8gcmF3IHBheWxvYWQgaGVyZSBpcyBhIGJ1ZyDigJQgaXQncyBub3QgYSBwbGFpbiBvYmplY3QgYWZ0ZXJcbiAgICAgICAgICAvLyBkZWh5ZHJhdGlvbiwgc28gYCdyZWFzb24nIGluIHBheWxvYWRgIGlzIGZhbHNlIGFuZCByZWFzb25cbiAgICAgICAgICAvLyBlbmRzIHVwIHVuZGVmaW5lZCBvbiByZXBsYXkuXG4gICAgICAgICAgY29uc3QgcmF3UGF5bG9hZCA9IGV2ZW50LmV2ZW50RGF0YT8ucGF5bG9hZDtcbiAgICAgICAgICBjdHgucHJvbWlzZVF1ZXVlID0gY3R4LnByb21pc2VRdWV1ZS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGxldCByZWFzb246IHVua25vd247XG4gICAgICAgICAgICBpZiAocmF3UGF5bG9hZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaHlkcmF0ZWQgPSAoYXdhaXQgaHlkcmF0ZVN0ZXBSZXR1cm5WYWx1ZShcbiAgICAgICAgICAgICAgICAgIHJhd1BheWxvYWQsXG4gICAgICAgICAgICAgICAgICBjdHgucnVuSWQsXG4gICAgICAgICAgICAgICAgICBjdHguZW5jcnlwdGlvbktleSxcbiAgICAgICAgICAgICAgICAgIGN0eC5nbG9iYWxUaGlzXG4gICAgICAgICAgICAgICAgKSkgYXMgeyByZWFzb24/OiB1bmtub3duIH0gfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgaHlkcmF0ZWQgJiZcbiAgICAgICAgICAgICAgICAgIHR5cGVvZiBoeWRyYXRlZCA9PT0gJ29iamVjdCcgJiZcbiAgICAgICAgICAgICAgICAgICdyZWFzb24nIGluIGh5ZHJhdGVkXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICByZWFzb24gPSBoeWRyYXRlZC5yZWFzb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAvLyBCZXN0LWVmZm9ydDogaWYgaHlkcmF0aW9uIGZhaWxzLCBmYWxsIGJhY2sgdG8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgLy8gcmVhc29uLiBUaGUgc2lnbmFsIHN0aWxsIGFib3J0czsgdGhlIHVzZXIganVzdCB3b24ndCBzZWVcbiAgICAgICAgICAgICAgICAvLyB0aGUgb3JpZ2luYWwgcmVhc29uLiBNYXRjaGVzIFdvcmtmbG93QWJvcnRTaWduYWwncyBzcGVjXG4gICAgICAgICAgICAgICAgLy8gZmFsbGJhY2sgKERPTUV4Y2VwdGlvbiBBYm9ydEVycm9yKS5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zaWduYWwuX3NldEFib3J0ZWQocmVhc29uKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGN0eC5pbnZvY2F0aW9uc1F1ZXVlLmRlbGV0ZShjb3JyZWxhdGlvbklkKTtcbiAgICAgICAgICAvLyBNdWx0aXBsZSBoYW5kbGVycyBjYW4gb2JzZXJ2ZSB0aGUgc2FtZSBwZW5kaW5nIGFib3J0IHJlcXVlc3QgYW5kXG4gICAgICAgICAgLy8gZHVyYWJseSByZWNvcmQgaXQgYmVmb3JlIHJlcGxheSByZW1vdmVzIHRoZSBxdWV1ZSBpdGVtLiBBYm9ydCBpc1xuICAgICAgICAgIC8vIGlkZW1wb3RlbnQsIHNvIGNvbnN1bWUgbGF0ZXIgbWF0Y2hpbmcgcmVjZWlwdHMgYXMgbm8tb3BzIGluc3RlYWRcbiAgICAgICAgICAvLyBvZiBzdXJmYWNpbmcgYSBjb3JydXB0ZWQgZXZlbnQgbG9nIGFmdGVyIHRoZSBmaXJzdCByZWNlaXB0LlxuICAgICAgICAgIHJldHVybiBFdmVudENvbnN1bWVyUmVzdWx0LkNvbnN1bWVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmV2ZW50VHlwZSA9PT0gJ2hvb2tfZGlzcG9zZWQnKSB7XG4gICAgICAgICAgY3R4Lmludm9jYXRpb25zUXVldWUuZGVsZXRlKGNvcnJlbGF0aW9uSWQpO1xuICAgICAgICAgIHJldHVybiBFdmVudENvbnN1bWVyUmVzdWx0LkZpbmlzaGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWQ7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBhYm9ydChyZWFzb24/OiB1bmtub3duKTogdm9pZCB7XG4gICAgICBpZiAodGhpcy5zaWduYWwuYWJvcnRlZCkgcmV0dXJuOyAvLyBuby1vcCAoYWxyZWFkeSBhYm9ydGVkLCBlLmcuIGZyb20gcmVwbGF5KVxuXG4gICAgICAvLyBVcGRhdGUgc2lnbmFsIHN0YXRlIGFuZCBmaXJlIGxpc3RlbmVycyBzeW5jaHJvbm91c2x5XG4gICAgICB0aGlzLnNpZ25hbC5fc2V0QWJvcnRlZChyZWFzb24pO1xuXG4gICAgICAvLyBNYXJrIHRoZSBob29rIGZvciByZXN1bXB0aW9uIHNvIHRoZSBzdXNwZW5zaW9uIGhhbmRsZXIgcmVjb3Jkc1xuICAgICAgLy8gdGhlIGFib3J0IGluIHRoZSBldmVudCBsb2cgYW5kIHdyaXRlcyB0aGUgc3RyZWFtIHBhY2tldC5cbiAgICAgIGZvciAoY29uc3QgWywgaXRlbV0gb2YgY3R4Lmludm9jYXRpb25zUXVldWUpIHtcbiAgICAgICAgaWYgKGl0ZW0udHlwZSA9PT0gJ2hvb2snICYmIGl0ZW0udG9rZW4gPT09IHRoaXNbQUJPUlRfSE9PS19UT0tFTl0pIHtcbiAgICAgICAgICBpdGVtLmFib3J0UmVxdWVzdGVkID0gdHJ1ZTtcbiAgICAgICAgICBpdGVtLmFib3J0UmVhc29uID0gcmVhc29uO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB3b3JrZmxvdy1jb250ZXh0IGBBYm9ydFNpZ25hbGAgb2JqZWN0IHdpdGggc3RhdGljIG1ldGhvZHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBYm9ydFNpZ25hbFN0YXRpY3MoKToge1xuICBhYm9ydDogKHJlYXNvbj86IHVua25vd24pID0+IFdvcmtmbG93QWJvcnRTaWduYWw7XG4gIGFueTogKFxuICAgIHNpZ25hbHM6IEl0ZXJhYmxlPHtcbiAgICAgIGFib3J0ZWQ6IGJvb2xlYW47XG4gICAgICByZWFzb24/OiB1bmtub3duO1xuICAgICAgYWRkRXZlbnRMaXN0ZW5lcj86IEZ1bmN0aW9uO1xuICAgIH0+XG4gICkgPT4gV29ya2Zsb3dBYm9ydFNpZ25hbDtcbiAgdGltZW91dDogKCkgPT4gbmV2ZXI7XG59IHtcbiAgcmV0dXJuIHtcbiAgICBhYm9ydChyZWFzb24/OiB1bmtub3duKTogV29ya2Zsb3dBYm9ydFNpZ25hbCB7XG4gICAgICBjb25zdCBzaWduYWwgPSBuZXcgV29ya2Zsb3dBYm9ydFNpZ25hbCgnJywgJycpO1xuICAgICAgc2lnbmFsLl9zZXRBYm9ydGVkKFxuICAgICAgICByZWFzb24gPz8gbmV3IERPTUV4Y2VwdGlvbignVGhlIG9wZXJhdGlvbiB3YXMgYWJvcnRlZC4nLCAnQWJvcnRFcnJvcicpXG4gICAgICApO1xuICAgICAgcmV0dXJuIHNpZ25hbDtcbiAgICB9LFxuXG4gICAgYW55KFxuICAgICAgc2lnbmFsczogSXRlcmFibGU8e1xuICAgICAgICBhYm9ydGVkOiBib29sZWFuO1xuICAgICAgICByZWFzb24/OiB1bmtub3duO1xuICAgICAgICBhZGRFdmVudExpc3RlbmVyPzogRnVuY3Rpb247XG4gICAgICAgIHJlbW92ZUV2ZW50TGlzdGVuZXI/OiBGdW5jdGlvbjtcbiAgICAgIH0+XG4gICAgKTogV29ya2Zsb3dBYm9ydFNpZ25hbCB7XG4gICAgICBjb25zdCBjb21wb3NpdGUgPSBuZXcgV29ya2Zsb3dBYm9ydFNpZ25hbCgnJywgJycpO1xuXG4gICAgICAvLyBNYXRlcmlhbGl6ZSB0aGUgaXRlcmFibGUgb25jZS4gTmF0aXZlIEFib3J0U2lnbmFsLmFueSBkb2VzIHRoZSBzYW1lOlxuICAgICAgLy8gc2luZ2xlLXNob3QgaXRlcmFibGVzIChlLmcuIGdlbmVyYXRvcnMpIHdvdWxkIG90aGVyd2lzZSBwcm9kdWNlIHplcm9cbiAgICAgIC8vIGVudHJpZXMgb24gdGhlIHNlY29uZCBwYXNzIGJlbG93LlxuICAgICAgY29uc3QgYXJyID0gQXJyYXkuZnJvbShzaWduYWxzKTtcblxuICAgICAgZm9yIChjb25zdCBzaWduYWwgb2YgYXJyKSB7XG4gICAgICAgIGlmIChzaWduYWwuYWJvcnRlZCkge1xuICAgICAgICAgIGNvbXBvc2l0ZS5fc2V0QWJvcnRlZChzaWduYWwucmVhc29uKTtcbiAgICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIExpc3RlbiB0byBlYWNoIHNpZ25hbCDigJQgZmlyc3Qgb25lIHRvIGFib3J0IHdpbnMuIFRyYWNrIGxpc3RlbmVycyBzb1xuICAgICAgLy8gd2UgY2FuIHJlbW92ZSB0aGVtIGFmdGVyIHRoZSBjb21wb3NpdGUgYWJvcnRzOyBvdGhlcndpc2UgdGhlIGNsb3N1cmVzXG4gICAgICAvLyAoY2FwdHVyaW5nIGBjb21wb3NpdGVgKSBwcmV2ZW50IEdDIGZvciBhbnkgaW5wdXQgc2lnbmFsIHRoYXQgb3V0bGl2ZXNcbiAgICAgIC8vIHRoZSBjb21wb3NpdGUgKGUuZy4gYSBsb25nLWxpdmVkIGV4dGVybmFsIGNvbnRyb2xsZXIpLlxuICAgICAgY29uc3QgbGlzdGVuZXJzOiBBcnJheTx7XG4gICAgICAgIHNpZ25hbDogKHR5cGVvZiBhcnIpW251bWJlcl07XG4gICAgICAgIGxpc3RlbmVyOiAoKSA9PiB2b2lkO1xuICAgICAgfT4gPSBbXTtcbiAgICAgIGNvbnN0IGNsZWFudXAgPSAoKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgeyBzaWduYWwsIGxpc3RlbmVyIH0gb2YgbGlzdGVuZXJzKSB7XG4gICAgICAgICAgaWYgKHNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgICBzaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignYWJvcnQnLCBsaXN0ZW5lcik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxpc3RlbmVycy5sZW5ndGggPSAwO1xuICAgICAgfTtcblxuICAgICAgZm9yIChjb25zdCBzaWduYWwgb2YgYXJyKSB7XG4gICAgICAgIGlmICghc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBsaXN0ZW5lciA9ICgpID0+IHtcbiAgICAgICAgICBpZiAoIWNvbXBvc2l0ZS5hYm9ydGVkKSB7XG4gICAgICAgICAgICBjb21wb3NpdGUuX3NldEFib3J0ZWQoc2lnbmFsLnJlYXNvbik7XG4gICAgICAgICAgICBjbGVhbnVwKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBsaXN0ZW5lcnMucHVzaCh7IHNpZ25hbCwgbGlzdGVuZXIgfSk7XG4gICAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCdhYm9ydCcsIGxpc3RlbmVyKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNvbXBvc2l0ZTtcbiAgICB9LFxuXG4gICAgdGltZW91dCgpOiBuZXZlciB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdBYm9ydFNpZ25hbC50aW1lb3V0KCkgaXMgbm90IHN1cHBvcnRlZCBpbiB3b3JrZmxvdyBmdW5jdGlvbnMuICcgK1xuICAgICAgICAgICdVc2Ugc2xlZXAoKSB3aXRoIGFuIEFib3J0Q29udHJvbGxlciBpbnN0ZWFkLiAnICtcbiAgICAgICAgICAnU2VlOiAvZG9jcy9lcnJvcnMvYWJvcnQtc2lnbmFsLXRpbWVvdXQtaW4td29ya2Zsb3cnXG4gICAgICApO1xuICAgIH0sXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,6 @@
1
+ import type { AttributeChange } from '@workflow/world';
2
+ import { type WorkflowOrchestratorContext } from '../private.js';
3
+ export declare function createSetAttributes(ctx: WorkflowOrchestratorContext): (changes: AttributeChange[], options?: {
4
+ allowReservedAttributes?: boolean;
5
+ }) => Promise<void>;
6
+ //# sourceMappingURL=attribute-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-dispatcher.d.ts","sourceRoot":"","sources":["../../src/workflow/attribute-dispatcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvD,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,eAAe,CAAC;AAEvB,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,2BAA2B,IAEhE,SAAS,eAAe,EAAE,EAC1B,UAAS;IAAE,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAAO,KAClD,OAAO,CAAC,IAAI,CAAC,CAsDjB"}
@@ -0,0 +1,48 @@
1
+ import { ReplayDivergenceError } from '@workflow/errors';
2
+ import { withResolvers } from '@workflow/utils';
3
+ import { EventConsumerResult } from '../events-consumer.js';
4
+ import { WorkflowSuspension, } from '../global.js';
5
+ import { scheduleWhenIdle, } from '../private.js';
6
+ export function createSetAttributes(ctx) {
7
+ return async function setAttributes(changes, options = {}) {
8
+ const { promise, resolve } = withResolvers();
9
+ const correlationId = `attr_${ctx.generateUlid()}`;
10
+ const queueItem = {
11
+ type: 'attribute',
12
+ correlationId,
13
+ changes,
14
+ ...(options.allowReservedAttributes === true
15
+ ? { allowReservedAttributes: true }
16
+ : {}),
17
+ };
18
+ ctx.invocationsQueue.set(correlationId, queueItem);
19
+ ctx.eventsConsumer.subscribe((event) => {
20
+ if (!event) {
21
+ scheduleWhenIdle(ctx, () => {
22
+ ctx.onWorkflowError(new WorkflowSuspension(ctx.invocationsQueue, ctx.globalThis));
23
+ });
24
+ return EventConsumerResult.NotConsumed;
25
+ }
26
+ if (event.correlationId !== correlationId) {
27
+ return EventConsumerResult.NotConsumed;
28
+ }
29
+ if (event.eventType !== 'attr_set' ||
30
+ event.eventData.writer.type !== 'workflow' ||
31
+ JSON.stringify(event.eventData.changes) !== JSON.stringify(changes) ||
32
+ (event.eventData.allowReservedAttributes === true) !==
33
+ (options.allowReservedAttributes === true)) {
34
+ ctx.promiseQueue = ctx.promiseQueue.then(() => {
35
+ ctx.onWorkflowError(new ReplayDivergenceError(`Replay divergence: Unexpected attribute event for ${correlationId}`, { eventId: event.eventId }));
36
+ });
37
+ return EventConsumerResult.Finished;
38
+ }
39
+ ctx.invocationsQueue.delete(correlationId);
40
+ ctx.promiseQueue = ctx.promiseQueue.then(() => {
41
+ resolve();
42
+ });
43
+ return EventConsumerResult.Finished;
44
+ });
45
+ return promise;
46
+ };
47
+ }
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0cmlidXRlLWRpc3BhdGNoZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2Zsb3cvYXR0cmlidXRlLWRpc3BhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWhELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFFTCxrQkFBa0IsR0FDbkIsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUNMLGdCQUFnQixHQUVqQixNQUFNLGVBQWUsQ0FBQztBQUV2QixNQUFNLFVBQVUsbUJBQW1CLENBQUMsR0FBZ0M7SUFDbEUsT0FBTyxLQUFLLFVBQVUsYUFBYSxDQUNqQyxPQUEwQixFQUMxQixVQUFpRCxFQUFFO1FBRW5ELE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLEdBQUcsYUFBYSxFQUFRLENBQUM7UUFDbkQsTUFBTSxhQUFhLEdBQUcsUUFBUSxHQUFHLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQztRQUNuRCxNQUFNLFNBQVMsR0FBaUM7WUFDOUMsSUFBSSxFQUFFLFdBQVc7WUFDakIsYUFBYTtZQUNiLE9BQU87WUFDUCxHQUFHLENBQUMsT0FBTyxDQUFDLHVCQUF1QixLQUFLLElBQUk7Z0JBQzFDLENBQUMsQ0FBQyxFQUFFLHVCQUF1QixFQUFFLElBQUksRUFBRTtnQkFDbkMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztTQUNSLENBQUM7UUFDRixHQUFHLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUVuRCxHQUFHLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ3JDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDWCxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO29CQUN6QixHQUFHLENBQUMsZUFBZSxDQUNqQixJQUFJLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsVUFBVSxDQUFDLENBQzdELENBQUM7Z0JBQ0osQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7WUFDekMsQ0FBQztZQUVELElBQUksS0FBSyxDQUFDLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztnQkFDMUMsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7WUFDekMsQ0FBQztZQUVELElBQ0UsS0FBSyxDQUFDLFNBQVMsS0FBSyxVQUFVO2dCQUM5QixLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssVUFBVTtnQkFDMUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDO2dCQUNuRSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsdUJBQXVCLEtBQUssSUFBSSxDQUFDO29CQUNoRCxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsS0FBSyxJQUFJLENBQUMsRUFDNUMsQ0FBQztnQkFDRCxHQUFHLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtvQkFDNUMsR0FBRyxDQUFDLGVBQWUsQ0FDakIsSUFBSSxxQkFBcUIsQ0FDdkIscURBQXFELGFBQWEsRUFBRSxFQUNwRSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQzNCLENBQ0YsQ0FBQztnQkFDSixDQUFDLENBQUMsQ0FBQztnQkFDSCxPQUFPLG1CQUFtQixDQUFDLFFBQVEsQ0FBQztZQUN0QyxDQUFDO1lBRUQsR0FBRyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUMzQyxHQUFHLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDNUMsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDLENBQUMsQ0FBQztZQUNILE9BQU8sbUJBQW1CLENBQUMsUUFBUSxDQUFDO1FBQ3RDLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlcGxheURpdmVyZ2VuY2VFcnJvciB9IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHsgd2l0aFJlc29sdmVycyB9IGZyb20gJ0B3b3JrZmxvdy91dGlscyc7XG5pbXBvcnQgdHlwZSB7IEF0dHJpYnV0ZUNoYW5nZSB9IGZyb20gJ0B3b3JrZmxvdy93b3JsZCc7XG5pbXBvcnQgeyBFdmVudENvbnN1bWVyUmVzdWx0IH0gZnJvbSAnLi4vZXZlbnRzLWNvbnN1bWVyLmpzJztcbmltcG9ydCB7XG4gIHR5cGUgQXR0cmlidXRlSW52b2NhdGlvblF1ZXVlSXRlbSxcbiAgV29ya2Zsb3dTdXNwZW5zaW9uLFxufSBmcm9tICcuLi9nbG9iYWwuanMnO1xuaW1wb3J0IHtcbiAgc2NoZWR1bGVXaGVuSWRsZSxcbiAgdHlwZSBXb3JrZmxvd09yY2hlc3RyYXRvckNvbnRleHQsXG59IGZyb20gJy4uL3ByaXZhdGUuanMnO1xuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2V0QXR0cmlidXRlcyhjdHg6IFdvcmtmbG93T3JjaGVzdHJhdG9yQ29udGV4dCkge1xuICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gc2V0QXR0cmlidXRlcyhcbiAgICBjaGFuZ2VzOiBBdHRyaWJ1dGVDaGFuZ2VbXSxcbiAgICBvcHRpb25zOiB7IGFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzPzogYm9vbGVhbiB9ID0ge31cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBwcm9taXNlLCByZXNvbHZlIH0gPSB3aXRoUmVzb2x2ZXJzPHZvaWQ+KCk7XG4gICAgY29uc3QgY29ycmVsYXRpb25JZCA9IGBhdHRyXyR7Y3R4LmdlbmVyYXRlVWxpZCgpfWA7XG4gICAgY29uc3QgcXVldWVJdGVtOiBBdHRyaWJ1dGVJbnZvY2F0aW9uUXVldWVJdGVtID0ge1xuICAgICAgdHlwZTogJ2F0dHJpYnV0ZScsXG4gICAgICBjb3JyZWxhdGlvbklkLFxuICAgICAgY2hhbmdlcyxcbiAgICAgIC4uLihvcHRpb25zLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzID09PSB0cnVlXG4gICAgICAgID8geyBhbGxvd1Jlc2VydmVkQXR0cmlidXRlczogdHJ1ZSB9XG4gICAgICAgIDoge30pLFxuICAgIH07XG4gICAgY3R4Lmludm9jYXRpb25zUXVldWUuc2V0KGNvcnJlbGF0aW9uSWQsIHF1ZXVlSXRlbSk7XG5cbiAgICBjdHguZXZlbnRzQ29uc3VtZXIuc3Vic2NyaWJlKChldmVudCkgPT4ge1xuICAgICAgaWYgKCFldmVudCkge1xuICAgICAgICBzY2hlZHVsZVdoZW5JZGxlKGN0eCwgKCkgPT4ge1xuICAgICAgICAgIGN0eC5vbldvcmtmbG93RXJyb3IoXG4gICAgICAgICAgICBuZXcgV29ya2Zsb3dTdXNwZW5zaW9uKGN0eC5pbnZvY2F0aW9uc1F1ZXVlLCBjdHguZ2xvYmFsVGhpcylcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIEV2ZW50Q29uc3VtZXJSZXN1bHQuTm90Q29uc3VtZWQ7XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC5jb3JyZWxhdGlvbklkICE9PSBjb3JyZWxhdGlvbklkKSB7XG4gICAgICAgIHJldHVybiBFdmVudENvbnN1bWVyUmVzdWx0Lk5vdENvbnN1bWVkO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIGV2ZW50LmV2ZW50VHlwZSAhPT0gJ2F0dHJfc2V0JyB8fFxuICAgICAgICBldmVudC5ldmVudERhdGEud3JpdGVyLnR5cGUgIT09ICd3b3JrZmxvdycgfHxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoZXZlbnQuZXZlbnREYXRhLmNoYW5nZXMpICE9PSBKU09OLnN0cmluZ2lmeShjaGFuZ2VzKSB8fFxuICAgICAgICAoZXZlbnQuZXZlbnREYXRhLmFsbG93UmVzZXJ2ZWRBdHRyaWJ1dGVzID09PSB0cnVlKSAhPT1cbiAgICAgICAgICAob3B0aW9ucy5hbGxvd1Jlc2VydmVkQXR0cmlidXRlcyA9PT0gdHJ1ZSlcbiAgICAgICkge1xuICAgICAgICBjdHgucHJvbWlzZVF1ZXVlID0gY3R4LnByb21pc2VRdWV1ZS50aGVuKCgpID0+IHtcbiAgICAgICAgICBjdHgub25Xb3JrZmxvd0Vycm9yKFxuICAgICAgICAgICAgbmV3IFJlcGxheURpdmVyZ2VuY2VFcnJvcihcbiAgICAgICAgICAgICAgYFJlcGxheSBkaXZlcmdlbmNlOiBVbmV4cGVjdGVkIGF0dHJpYnV0ZSBldmVudCBmb3IgJHtjb3JyZWxhdGlvbklkfWAsXG4gICAgICAgICAgICAgIHsgZXZlbnRJZDogZXZlbnQuZXZlbnRJZCB9XG4gICAgICAgICAgICApXG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBFdmVudENvbnN1bWVyUmVzdWx0LkZpbmlzaGVkO1xuICAgICAgfVxuXG4gICAgICBjdHguaW52b2NhdGlvbnNRdWV1ZS5kZWxldGUoY29ycmVsYXRpb25JZCk7XG4gICAgICBjdHgucHJvbWlzZVF1ZXVlID0gY3R4LnByb21pc2VRdWV1ZS50aGVuKCgpID0+IHtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gRXZlbnRDb25zdW1lclJlc3VsdC5GaW5pc2hlZDtcbiAgICB9KTtcblxuICAgIHJldHVybiBwcm9taXNlO1xuICB9O1xufVxuIl19