footprintjs 10.0.1 → 10.2.0

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 (368) hide show
  1. package/AGENTS.md +2 -1
  2. package/CLAUDE.md +61 -7
  3. package/README.md +136 -312
  4. package/dist/esm/index.d.ts +62 -2
  5. package/dist/esm/index.js +13 -6
  6. package/dist/esm/lib/attempt/anySignal.d.ts +19 -0
  7. package/dist/esm/lib/attempt/anySignal.js +39 -0
  8. package/dist/esm/lib/attempt/call.d.ts +88 -0
  9. package/dist/esm/lib/attempt/call.js +129 -0
  10. package/dist/esm/lib/attempt/category.d.ts +37 -0
  11. package/dist/esm/lib/attempt/category.js +131 -0
  12. package/dist/esm/lib/attempt/correlation.d.ts +95 -0
  13. package/dist/esm/lib/attempt/correlation.js +178 -0
  14. package/dist/esm/lib/attempt/deadline.d.ts +44 -0
  15. package/dist/esm/lib/attempt/deadline.js +101 -0
  16. package/dist/esm/lib/attempt/decision.d.ts +52 -0
  17. package/dist/esm/lib/attempt/decision.js +134 -0
  18. package/dist/esm/lib/attempt/effect.d.ts +76 -0
  19. package/dist/esm/lib/attempt/effect.js +160 -0
  20. package/dist/esm/lib/attempt/errors.d.ts +41 -0
  21. package/dist/esm/lib/attempt/errors.js +44 -0
  22. package/dist/esm/lib/attempt/index.d.ts +18 -0
  23. package/dist/esm/lib/attempt/index.js +15 -0
  24. package/dist/esm/lib/attempt/name.d.ts +21 -0
  25. package/dist/esm/lib/attempt/name.js +43 -0
  26. package/dist/esm/lib/attempt/observed.d.ts +66 -0
  27. package/dist/esm/lib/attempt/observed.js +171 -0
  28. package/dist/esm/lib/attempt/policy.d.ts +45 -0
  29. package/dist/esm/lib/attempt/policy.js +83 -0
  30. package/dist/esm/lib/attempt/record.d.ts +11 -0
  31. package/dist/esm/lib/attempt/record.js +24 -0
  32. package/dist/esm/lib/attempt/retryLoopContext.d.ts +18 -0
  33. package/dist/esm/lib/attempt/retryLoopContext.js +24 -0
  34. package/dist/esm/lib/attempt/retryLoopTypes.d.ts +18 -0
  35. package/dist/esm/lib/attempt/retryLoopTypes.js +2 -0
  36. package/dist/esm/lib/attempt/runner.d.ts +157 -0
  37. package/dist/esm/lib/attempt/runner.js +523 -0
  38. package/dist/esm/lib/attempt/standalone.d.ts +47 -0
  39. package/dist/esm/lib/attempt/standalone.js +126 -0
  40. package/dist/esm/lib/attempt/types.d.ts +453 -0
  41. package/dist/esm/lib/attempt/types.js +16 -0
  42. package/dist/esm/lib/budget/index.d.ts +9 -0
  43. package/dist/esm/lib/budget/index.js +9 -0
  44. package/dist/esm/lib/budget/timeBudget.d.ts +136 -0
  45. package/dist/esm/lib/budget/timeBudget.js +666 -0
  46. package/dist/esm/lib/builder/FlowChartBuilder.d.ts +88 -3
  47. package/dist/esm/lib/builder/FlowChartBuilder.js +199 -9
  48. package/dist/esm/lib/builder/retryLoop.d.ts +56 -0
  49. package/dist/esm/lib/builder/retryLoop.js +283 -0
  50. package/dist/esm/lib/builder/types.d.ts +35 -1
  51. package/dist/esm/lib/builder/types.js +1 -1
  52. package/dist/esm/lib/decide/decide.js +2 -2
  53. package/dist/esm/lib/decide/index.d.ts +1 -1
  54. package/dist/esm/lib/decide/index.js +2 -2
  55. package/dist/esm/lib/decide/types.d.ts +3 -0
  56. package/dist/esm/lib/decide/types.js +1 -8
  57. package/dist/esm/lib/engine/graph/StageNode.d.ts +11 -1
  58. package/dist/esm/lib/engine/graph/StageNode.js +1 -1
  59. package/dist/esm/lib/engine/graph/prefixNodeTree.js +5 -1
  60. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +36 -6
  61. package/dist/esm/lib/engine/handlers/DeciderHandler.js +9 -5
  62. package/dist/esm/lib/engine/handlers/ResumeEntry.js +3 -1
  63. package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -5
  64. package/dist/esm/lib/engine/handlers/StageRunner.d.ts +8 -1
  65. package/dist/esm/lib/engine/handlers/StageRunner.js +36 -9
  66. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +24 -5
  67. package/dist/esm/lib/engine/handlers/commitStage.d.ts +7 -0
  68. package/dist/esm/lib/engine/handlers/commitStage.js +22 -4
  69. package/dist/esm/lib/engine/handlers/stageError.d.ts +9 -0
  70. package/dist/esm/lib/engine/handlers/stageError.js +23 -1
  71. package/dist/esm/lib/engine/index.d.ts +2 -2
  72. package/dist/esm/lib/engine/index.js +1 -1
  73. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
  74. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +68 -40
  75. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
  76. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
  77. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
  78. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +61 -9
  79. package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
  80. package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
  81. package/dist/esm/lib/engine/narrative/formatting/sentences.d.ts +23 -0
  82. package/dist/esm/lib/engine/narrative/formatting/sentences.js +127 -1
  83. package/dist/esm/lib/engine/narrative/index.d.ts +2 -2
  84. package/dist/esm/lib/engine/narrative/index.js +1 -1
  85. package/dist/esm/lib/engine/narrative/narrativeTypes.d.ts +27 -21
  86. package/dist/esm/lib/engine/narrative/narrativeTypes.js +1 -1
  87. package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
  88. package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
  89. package/dist/esm/lib/engine/narrative/recorders/index.d.ts +1 -1
  90. package/dist/esm/lib/engine/narrative/recorders/index.js +1 -1
  91. package/dist/esm/lib/engine/narrative/types.d.ts +74 -5
  92. package/dist/esm/lib/engine/narrative/types.js +1 -1
  93. package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
  94. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +194 -118
  95. package/dist/esm/lib/engine/traversalContext.d.ts +7 -2
  96. package/dist/esm/lib/engine/traversalContext.js +6 -3
  97. package/dist/esm/lib/engine/types.d.ts +52 -57
  98. package/dist/esm/lib/engine/types.js +1 -1
  99. package/dist/esm/lib/errors/terminalFailure.d.ts +29 -0
  100. package/dist/esm/lib/errors/terminalFailure.js +60 -0
  101. package/dist/esm/lib/{decide → filter}/evaluator.d.ts +7 -2
  102. package/dist/esm/lib/filter/evaluator.js +135 -0
  103. package/dist/esm/lib/ids/idempotencyKey.d.ts +14 -0
  104. package/dist/esm/lib/ids/idempotencyKey.js +24 -0
  105. package/dist/esm/lib/memory/StageContext.d.ts +123 -3
  106. package/dist/esm/lib/memory/StageContext.js +245 -4
  107. package/dist/esm/lib/memory/attention.d.ts +26 -0
  108. package/dist/esm/lib/memory/attention.js +171 -0
  109. package/dist/esm/lib/memory/borrowedMutation.d.ts +8 -0
  110. package/dist/esm/lib/memory/borrowedMutation.js +14 -1
  111. package/dist/esm/lib/memory/frameTypes.d.ts +38 -0
  112. package/dist/esm/lib/memory/frameTypes.js +3 -1
  113. package/dist/esm/lib/memory/redaction.d.ts +12 -0
  114. package/dist/esm/lib/memory/redaction.js +54 -5
  115. package/dist/esm/lib/pause/record.js +10 -1
  116. package/dist/esm/lib/pause/types.d.ts +19 -0
  117. package/dist/esm/lib/pause/types.js +17 -1
  118. package/dist/esm/lib/reactive/createTypedScope.js +3 -1
  119. package/dist/esm/lib/reactive/types.d.ts +36 -4
  120. package/dist/esm/lib/reactive/types.js +3 -1
  121. package/dist/esm/lib/recorder/AttemptRecorder.d.ts +141 -0
  122. package/dist/esm/lib/recorder/AttemptRecorder.js +412 -0
  123. package/dist/esm/lib/recorder/ControlDepRecorder.d.ts +36 -2
  124. package/dist/esm/lib/recorder/ControlDepRecorder.js +50 -2
  125. package/dist/esm/lib/recorder/EmitRecorder.d.ts +3 -0
  126. package/dist/esm/lib/recorder/EmitRecorder.js +1 -1
  127. package/dist/esm/lib/recorder/InOutRecorder.d.ts +37 -1
  128. package/dist/esm/lib/recorder/InOutRecorder.js +75 -6
  129. package/dist/esm/lib/recorder/QualityRecorder.d.ts +32 -5
  130. package/dist/esm/lib/recorder/QualityRecorder.js +87 -29
  131. package/dist/esm/lib/recorder/TopologyRecorder.d.ts +35 -5
  132. package/dist/esm/lib/recorder/TopologyRecorder.js +76 -2
  133. package/dist/esm/lib/recorder/attemptMetricRows.d.ts +11 -0
  134. package/dist/esm/lib/recorder/attemptMetricRows.js +202 -0
  135. package/dist/esm/lib/recorder/attemptMetrics.d.ts +7 -0
  136. package/dist/esm/lib/recorder/attemptMetrics.js +165 -0
  137. package/dist/esm/lib/recorder/attemptMetricsTypes.d.ts +114 -0
  138. package/dist/esm/lib/recorder/attemptMetricsTypes.js +2 -0
  139. package/dist/esm/lib/recorder/attemptOTel.d.ts +78 -0
  140. package/dist/esm/lib/recorder/attemptOTel.js +107 -0
  141. package/dist/esm/lib/recorder/attemptSeries.d.ts +81 -0
  142. package/dist/esm/lib/recorder/attemptSeries.js +103 -0
  143. package/dist/esm/lib/recorder/hooks.d.ts +9 -0
  144. package/dist/esm/lib/recorder/hooks.js +4 -1
  145. package/dist/esm/lib/runner/DeferredObserverTier.js +13 -1
  146. package/dist/esm/lib/runner/ExecutionRuntime.d.ts +54 -6
  147. package/dist/esm/lib/runner/ExecutionRuntime.js +57 -5
  148. package/dist/esm/lib/runner/FlowChartExecutor.d.ts +46 -2
  149. package/dist/esm/lib/runner/FlowChartExecutor.js +330 -101
  150. package/dist/esm/lib/runner/RunnableChart.d.ts +6 -0
  151. package/dist/esm/lib/runner/RunnableChart.js +5 -1
  152. package/dist/esm/lib/runner/attach.d.ts +2 -1
  153. package/dist/esm/lib/runner/attach.js +8 -2
  154. package/dist/esm/lib/runner/checkpoint.js +3 -1
  155. package/dist/esm/lib/runner/deadline.d.ts +42 -0
  156. package/dist/esm/lib/runner/deadline.js +90 -0
  157. package/dist/esm/lib/runner/index.d.ts +3 -1
  158. package/dist/esm/lib/runner/index.js +2 -1
  159. package/dist/esm/lib/runner/options.d.ts +17 -0
  160. package/dist/esm/lib/runner/options.js +3 -1
  161. package/dist/esm/lib/runner/recordSink.d.ts +128 -0
  162. package/dist/esm/lib/runner/recordSink.js +296 -0
  163. package/dist/esm/lib/runner/resume.d.ts +3 -0
  164. package/dist/esm/lib/runner/resume.js +22 -2
  165. package/dist/esm/lib/runner/snapshot.d.ts +2 -2
  166. package/dist/esm/lib/runner/snapshot.js +6 -2
  167. package/dist/esm/lib/scope/ScopeFacade.d.ts +118 -4
  168. package/dist/esm/lib/scope/ScopeFacade.js +304 -7
  169. package/dist/esm/lib/scope/recorders/DebugRecorder.d.ts +17 -3
  170. package/dist/esm/lib/scope/recorders/DebugRecorder.js +79 -13
  171. package/dist/esm/lib/scope/recorders/MetricRecorder.d.ts +10 -0
  172. package/dist/esm/lib/scope/recorders/MetricRecorder.js +15 -2
  173. package/dist/esm/lib/scope/runtime.d.ts +3 -0
  174. package/dist/esm/lib/scope/runtime.js +1 -1
  175. package/dist/esm/lib/scope/types.d.ts +6 -0
  176. package/dist/esm/lib/scope/types.js +1 -1
  177. package/dist/esm/lib/sinks/fileSink.d.ts +135 -0
  178. package/dist/esm/lib/sinks/fileSink.js +387 -0
  179. package/dist/esm/recorders.d.ts +8 -2
  180. package/dist/esm/recorders.js +7 -1
  181. package/dist/esm/sinks.d.ts +23 -0
  182. package/dist/esm/sinks.js +23 -0
  183. package/dist/esm/trace.d.ts +2 -2
  184. package/dist/esm/trace.js +1 -1
  185. package/dist/index.js +77 -60
  186. package/dist/lib/attempt/anySignal.js +43 -0
  187. package/dist/lib/attempt/call.js +134 -0
  188. package/dist/lib/attempt/category.js +136 -0
  189. package/dist/lib/attempt/correlation.js +186 -0
  190. package/dist/lib/attempt/deadline.js +112 -0
  191. package/dist/lib/attempt/decision.js +139 -0
  192. package/dist/lib/attempt/effect.js +174 -0
  193. package/dist/lib/attempt/errors.js +49 -0
  194. package/dist/lib/attempt/index.js +26 -0
  195. package/dist/lib/attempt/name.js +48 -0
  196. package/dist/lib/attempt/observed.js +177 -0
  197. package/dist/lib/attempt/policy.js +92 -0
  198. package/dist/lib/attempt/record.js +29 -0
  199. package/dist/lib/attempt/retryLoopContext.js +31 -0
  200. package/dist/lib/attempt/retryLoopTypes.js +3 -0
  201. package/dist/lib/attempt/runner.js +530 -0
  202. package/dist/lib/attempt/standalone.js +130 -0
  203. package/dist/lib/attempt/types.js +17 -0
  204. package/dist/lib/budget/index.js +17 -0
  205. package/dist/lib/budget/timeBudget.js +674 -0
  206. package/dist/lib/builder/FlowChartBuilder.js +199 -9
  207. package/dist/lib/builder/retryLoop.js +287 -0
  208. package/dist/lib/builder/types.js +1 -1
  209. package/dist/lib/decide/decide.js +2 -2
  210. package/dist/lib/decide/index.js +2 -2
  211. package/dist/lib/decide/types.js +1 -8
  212. package/dist/lib/engine/graph/StageNode.js +1 -1
  213. package/dist/lib/engine/graph/prefixNodeTree.js +5 -1
  214. package/dist/lib/engine/handlers/ChildrenExecutor.js +36 -6
  215. package/dist/lib/engine/handlers/DeciderHandler.js +7 -3
  216. package/dist/lib/engine/handlers/ResumeEntry.js +3 -1
  217. package/dist/lib/engine/handlers/SelectorHandler.js +4 -3
  218. package/dist/lib/engine/handlers/StageRunner.js +36 -9
  219. package/dist/lib/engine/handlers/SubflowExecutor.js +24 -5
  220. package/dist/lib/engine/handlers/commitStage.js +24 -5
  221. package/dist/lib/engine/handlers/stageError.js +26 -2
  222. package/dist/lib/engine/index.js +1 -1
  223. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +67 -39
  224. package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
  225. package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +60 -8
  226. package/dist/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
  227. package/dist/lib/engine/narrative/formatting/sentences.js +131 -2
  228. package/dist/lib/engine/narrative/index.js +1 -1
  229. package/dist/lib/engine/narrative/narrativeTypes.js +1 -1
  230. package/dist/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
  231. package/dist/lib/engine/narrative/recorders/index.js +1 -1
  232. package/dist/lib/engine/narrative/types.js +1 -1
  233. package/dist/lib/engine/traversal/FlowchartTraverser.js +192 -116
  234. package/dist/lib/engine/traversalContext.js +6 -3
  235. package/dist/lib/engine/types.js +1 -1
  236. package/dist/lib/errors/terminalFailure.js +64 -0
  237. package/dist/lib/filter/evaluator.js +139 -0
  238. package/dist/lib/ids/idempotencyKey.js +28 -0
  239. package/dist/lib/memory/StageContext.js +246 -5
  240. package/dist/lib/memory/attention.js +175 -0
  241. package/dist/lib/memory/borrowedMutation.js +16 -2
  242. package/dist/lib/memory/frameTypes.js +3 -1
  243. package/dist/lib/memory/redaction.js +54 -5
  244. package/dist/lib/pause/record.js +10 -1
  245. package/dist/lib/pause/types.js +17 -1
  246. package/dist/lib/reactive/createTypedScope.js +3 -1
  247. package/dist/lib/reactive/types.js +3 -1
  248. package/dist/lib/recorder/AttemptRecorder.js +417 -0
  249. package/dist/lib/recorder/ControlDepRecorder.js +50 -2
  250. package/dist/lib/recorder/EmitRecorder.js +1 -1
  251. package/dist/lib/recorder/InOutRecorder.js +75 -6
  252. package/dist/lib/recorder/QualityRecorder.js +87 -29
  253. package/dist/lib/recorder/TopologyRecorder.js +76 -2
  254. package/dist/lib/recorder/attemptMetricRows.js +209 -0
  255. package/dist/lib/recorder/attemptMetrics.js +174 -0
  256. package/dist/lib/recorder/attemptMetricsTypes.js +3 -0
  257. package/dist/lib/recorder/attemptOTel.js +111 -0
  258. package/dist/lib/recorder/attemptSeries.js +113 -0
  259. package/dist/lib/recorder/hooks.js +4 -1
  260. package/dist/lib/runner/DeferredObserverTier.js +13 -1
  261. package/dist/lib/runner/ExecutionRuntime.js +57 -5
  262. package/dist/lib/runner/FlowChartExecutor.js +330 -101
  263. package/dist/lib/runner/RunnableChart.js +5 -1
  264. package/dist/lib/runner/attach.js +8 -2
  265. package/dist/lib/runner/checkpoint.js +3 -1
  266. package/dist/lib/runner/deadline.js +94 -0
  267. package/dist/lib/runner/index.js +4 -2
  268. package/dist/lib/runner/options.js +3 -1
  269. package/dist/lib/runner/recordSink.js +302 -0
  270. package/dist/lib/runner/resume.js +22 -2
  271. package/dist/lib/runner/snapshot.js +6 -2
  272. package/dist/lib/scope/ScopeFacade.js +303 -6
  273. package/dist/lib/scope/recorders/DebugRecorder.js +79 -13
  274. package/dist/lib/scope/recorders/MetricRecorder.js +15 -2
  275. package/dist/lib/scope/runtime.js +1 -1
  276. package/dist/lib/scope/types.js +1 -1
  277. package/dist/lib/sinks/fileSink.js +392 -0
  278. package/dist/recorders.js +10 -2
  279. package/dist/sinks.js +32 -0
  280. package/dist/trace.js +1 -1
  281. package/dist/types/index.d.ts +62 -2
  282. package/dist/types/lib/attempt/anySignal.d.ts +19 -0
  283. package/dist/types/lib/attempt/call.d.ts +88 -0
  284. package/dist/types/lib/attempt/category.d.ts +37 -0
  285. package/dist/types/lib/attempt/correlation.d.ts +95 -0
  286. package/dist/types/lib/attempt/deadline.d.ts +44 -0
  287. package/dist/types/lib/attempt/decision.d.ts +52 -0
  288. package/dist/types/lib/attempt/effect.d.ts +76 -0
  289. package/dist/types/lib/attempt/errors.d.ts +41 -0
  290. package/dist/types/lib/attempt/index.d.ts +18 -0
  291. package/dist/types/lib/attempt/name.d.ts +21 -0
  292. package/dist/types/lib/attempt/observed.d.ts +66 -0
  293. package/dist/types/lib/attempt/policy.d.ts +45 -0
  294. package/dist/types/lib/attempt/record.d.ts +11 -0
  295. package/dist/types/lib/attempt/retryLoopContext.d.ts +18 -0
  296. package/dist/types/lib/attempt/retryLoopTypes.d.ts +18 -0
  297. package/dist/types/lib/attempt/runner.d.ts +157 -0
  298. package/dist/types/lib/attempt/standalone.d.ts +47 -0
  299. package/dist/types/lib/attempt/types.d.ts +453 -0
  300. package/dist/types/lib/budget/index.d.ts +9 -0
  301. package/dist/types/lib/budget/timeBudget.d.ts +136 -0
  302. package/dist/types/lib/builder/FlowChartBuilder.d.ts +88 -3
  303. package/dist/types/lib/builder/retryLoop.d.ts +56 -0
  304. package/dist/types/lib/builder/types.d.ts +35 -1
  305. package/dist/types/lib/decide/index.d.ts +1 -1
  306. package/dist/types/lib/decide/types.d.ts +3 -0
  307. package/dist/types/lib/engine/graph/StageNode.d.ts +11 -1
  308. package/dist/types/lib/engine/handlers/StageRunner.d.ts +8 -1
  309. package/dist/types/lib/engine/handlers/commitStage.d.ts +7 -0
  310. package/dist/types/lib/engine/handlers/stageError.d.ts +9 -0
  311. package/dist/types/lib/engine/index.d.ts +2 -2
  312. package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
  313. package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
  314. package/dist/types/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
  315. package/dist/types/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
  316. package/dist/types/lib/engine/narrative/formatting/sentences.d.ts +23 -0
  317. package/dist/types/lib/engine/narrative/index.d.ts +2 -2
  318. package/dist/types/lib/engine/narrative/narrativeTypes.d.ts +27 -21
  319. package/dist/types/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
  320. package/dist/types/lib/engine/narrative/recorders/index.d.ts +1 -1
  321. package/dist/types/lib/engine/narrative/types.d.ts +74 -5
  322. package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
  323. package/dist/types/lib/engine/traversalContext.d.ts +7 -2
  324. package/dist/types/lib/engine/types.d.ts +52 -57
  325. package/dist/types/lib/errors/terminalFailure.d.ts +29 -0
  326. package/dist/types/lib/{decide → filter}/evaluator.d.ts +7 -2
  327. package/dist/types/lib/ids/idempotencyKey.d.ts +14 -0
  328. package/dist/types/lib/memory/StageContext.d.ts +123 -3
  329. package/dist/types/lib/memory/attention.d.ts +26 -0
  330. package/dist/types/lib/memory/borrowedMutation.d.ts +8 -0
  331. package/dist/types/lib/memory/frameTypes.d.ts +38 -0
  332. package/dist/types/lib/memory/redaction.d.ts +12 -0
  333. package/dist/types/lib/pause/types.d.ts +19 -0
  334. package/dist/types/lib/reactive/types.d.ts +36 -4
  335. package/dist/types/lib/recorder/AttemptRecorder.d.ts +141 -0
  336. package/dist/types/lib/recorder/ControlDepRecorder.d.ts +36 -2
  337. package/dist/types/lib/recorder/EmitRecorder.d.ts +3 -0
  338. package/dist/types/lib/recorder/InOutRecorder.d.ts +37 -1
  339. package/dist/types/lib/recorder/QualityRecorder.d.ts +32 -5
  340. package/dist/types/lib/recorder/TopologyRecorder.d.ts +35 -5
  341. package/dist/types/lib/recorder/attemptMetricRows.d.ts +11 -0
  342. package/dist/types/lib/recorder/attemptMetrics.d.ts +7 -0
  343. package/dist/types/lib/recorder/attemptMetricsTypes.d.ts +114 -0
  344. package/dist/types/lib/recorder/attemptOTel.d.ts +78 -0
  345. package/dist/types/lib/recorder/attemptSeries.d.ts +81 -0
  346. package/dist/types/lib/recorder/hooks.d.ts +9 -0
  347. package/dist/types/lib/runner/ExecutionRuntime.d.ts +54 -6
  348. package/dist/types/lib/runner/FlowChartExecutor.d.ts +46 -2
  349. package/dist/types/lib/runner/RunnableChart.d.ts +6 -0
  350. package/dist/types/lib/runner/attach.d.ts +2 -1
  351. package/dist/types/lib/runner/deadline.d.ts +42 -0
  352. package/dist/types/lib/runner/index.d.ts +3 -1
  353. package/dist/types/lib/runner/options.d.ts +17 -0
  354. package/dist/types/lib/runner/recordSink.d.ts +128 -0
  355. package/dist/types/lib/runner/resume.d.ts +3 -0
  356. package/dist/types/lib/runner/snapshot.d.ts +2 -2
  357. package/dist/types/lib/scope/ScopeFacade.d.ts +118 -4
  358. package/dist/types/lib/scope/recorders/DebugRecorder.d.ts +17 -3
  359. package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +10 -0
  360. package/dist/types/lib/scope/runtime.d.ts +3 -0
  361. package/dist/types/lib/scope/types.d.ts +6 -0
  362. package/dist/types/lib/sinks/fileSink.d.ts +135 -0
  363. package/dist/types/recorders.d.ts +8 -2
  364. package/dist/types/sinks.d.ts +23 -0
  365. package/dist/types/trace.d.ts +2 -2
  366. package/package.json +20 -6
  367. package/dist/esm/lib/decide/evaluator.js +0 -130
  368. package/dist/lib/decide/evaluator.js +0 -134
@@ -0,0 +1,135 @@
1
+ /**
2
+ * sinks/fileSink.ts — the record, one JSON line per entry, in a file (design §3.5, §4, packet P6). NODE ONLY: the
3
+ * one file in `src/` that imports a Node built-in, reachable only through the `footprintjs/sinks` door.
4
+ *
5
+ * WHY A FILE, WHY THIS SHAPE. A run's record must outlive the process that made it — a killed process, a crashed
6
+ * host, a serverless freeze. Each entry the log hands over is encoded, checked and given its own offset in the file,
7
+ * and its write is handed to the I/O pool AT ONCE (a positional write — no entry waits for the event loop to turn);
8
+ * the pool's threads perform them while the main thread runs on. A process killed after a pool thread wrote an entry
9
+ * keeps it. Until then it is not on disk: microseconds on a free pool, but the pool (4 threads by default) is shared
10
+ * with DNS lookups, zlib, crypto and other fs work, so while it is busy the window is as long as that work — and since
11
+ * writes complete out of order, a kill can lose an entry in the middle (the reader reports the hole). `flush()` waits for every write and
12
+ * `fsync`s — the step that also survives the machine losing power, and the one the executor awaits after each run's
13
+ * closing entry.
14
+ *
15
+ * THE THREAT MODEL, as code — every resource bounded, nothing that can stall the run:
16
+ * - ONLY THE PATH THE APP GIVES. Resolved once and opened once, at `fileSink(path)`; every entry goes to that open
17
+ * file. A symbolic link at the path is refused (`O_NOFOLLOW`, where the platform has it), and so is anything
18
+ * that is not a regular file, a file with another hard link, another owner, or group/world write. A file the
19
+ * sink creates is `0o600`.
20
+ * - ATOMIC PER ENTRY. A line is encoded in full first — an entry JSON cannot write (a `BigInt`, a cycle) is
21
+ * refused whole — then written at its own offset. A write that fails part-way leaves a hole up to the next
22
+ * entry's offset; the reader splits at it (NUL), so a torn line never swallows the one after it (an existing
23
+ * file with a torn tail gets a newline first).
24
+ * - BOUNDED: `maxEntryBytes` (one line, 8 MiB — refused by name, before it is encoded when its length already
25
+ * says so), `maxQueuedBytes` (accepted, not yet written, 16 MiB — past it an entry is DROPPED and counted, never
26
+ * buffered without limit), `maxBytes` (the file, 64 MiB — once full, every further entry is refused and counted;
27
+ * a closing entry may use a 64 KiB reserve so a full file can still say how the run ended), `flushTimeoutMs`
28
+ * (10 s — then `flush()` rejects). Every refusal throws from the sink method, which the log counts
29
+ * (`getSnapshot().sink`); a write that fails later rejects that entry's promise, counted the same way.
30
+ * - ASYNCHRONOUS WRITES ONLY. No method blocks on the disk; the file is released asynchronously, after every
31
+ * write and every started fsync.
32
+ * - NO SECRET ON DISK is the EXECUTOR's law, applied before any entry reaches an adapter (`runner/recordSink.ts`):
33
+ * this file writes what it is handed and reads nothing else.
34
+ * - ONE WRITER PER FILE. A second sink on a file this process has open is refused (by device and inode, across the
35
+ * CommonJS and ESM builds). ANOTHER PROCESS writing the same path is not seen at open: each writes at its own
36
+ * offsets and would overwrite the other. `flush()` checks the file's size against what this sink placed and rejects
37
+ * (a loss the run counts) when another writer's bytes reach past it — best effort: an overwrite this sink's own
38
+ * later writes cover is not seen. Give each process its own file.
39
+ *
40
+ * WHAT JSON KEEPS. A line holds what `JSON.stringify` keeps: a `Date` becomes its ISO string, a `Map` / `Set` an
41
+ * empty object, `undefined` disappears. A record of plain JSON values reads back exactly (`readRecordFile` →
42
+ * `readStoredRecord`); for richer values, bring an adapter with a richer encoding.
43
+ */
44
+ import type { RecordSink } from 'foottrace/write';
45
+ /** The default cap on a record file: 64 MiB. */
46
+ export declare const DEFAULT_FILE_SINK_MAX_BYTES: number;
47
+ /** The default cap on ONE entry's line: 8 MiB. */
48
+ export declare const DEFAULT_FILE_SINK_MAX_ENTRY_BYTES: number;
49
+ /** The default cap on bytes accepted but not yet written: 16 MiB. */
50
+ export declare const DEFAULT_FILE_SINK_MAX_QUEUED_BYTES: number;
51
+ /** The default bound on `flush()`: 10 s. */
52
+ export declare const DEFAULT_FILE_SINK_FLUSH_TIMEOUT_MS = 10000;
53
+ /** `fileSink`'s options — every resource the sink can spend, bounded. */
54
+ export interface FileSinkOptions {
55
+ /**
56
+ * The most bytes the file may hold (the bytes already in it count). Once an entry would pass it, the file is FULL:
57
+ * that entry and every later one is refused and counted by the run, never written — except a closing entry, which
58
+ * may use 64 KiB more so a full file can still say how the run ended. Default 64 MiB.
59
+ */
60
+ readonly maxBytes?: number;
61
+ /** The largest ONE entry's line may be; a larger entry is refused whole (`maxEntryBytes` named). Default 8 MiB. */
62
+ readonly maxEntryBytes?: number;
63
+ /**
64
+ * The most bytes accepted and not yet on disk. Writes are asynchronous, so a sink slower than the run queues; past
65
+ * this bound an entry is DROPPED and counted (never buffered without limit, never a stall). Default 16 MiB.
66
+ */
67
+ readonly maxQueuedBytes?: number;
68
+ /** How long `flush()` (drain the queue, then `fsync`) may take before it rejects. Default 10 s. */
69
+ readonly flushTimeoutMs?: number;
70
+ }
71
+ /** A record sink that appends to one file — `RecordSink` plus what the app needs to manage the file. */
72
+ export interface FileSink extends RecordSink {
73
+ /** The absolute path the sink writes to — resolved once, when it was made. */
74
+ readonly path: string;
75
+ /**
76
+ * Bytes this sink knows are on disk: the file's size when it opened plus every byte its writes completed — a
77
+ * running sum, not the file's end (writes complete out of order; a failed one leaves a hole).
78
+ */
79
+ readonly bytes: number;
80
+ /** Bytes accepted and not yet written. */
81
+ readonly queuedBytes: number;
82
+ /** `true` once an entry was refused for `maxBytes`: the file is full, and only a closing entry may still go. */
83
+ readonly full: boolean;
84
+ /**
85
+ * Release the file. Idempotent. Every entry after it is refused (the run counts it), and `flush()` rejects;
86
+ * entries already accepted are still written (and a flush already started finishes), then the file is closed —
87
+ * the promise settles then.
88
+ */
89
+ close(): Promise<void>;
90
+ }
91
+ /**
92
+ * A record sink that appends each entry to `path` as one JSON line — the crash-safe record on a Node host.
93
+ *
94
+ * Every method returns at once: the line is encoded, checked against every bound, given its offset and handed to
95
+ * the I/O pool. The method's promise settles when that line is written; a write that fails rejects it, and the run
96
+ * counts the loss.
97
+ *
98
+ * @throws TypeError when `path` is not a non-empty string or does not name a regular file the writer owns alone;
99
+ * RangeError for a bound that is not a whole number ≥ 1; the operating system's error when
100
+ * the file cannot be opened (a symbolic link at `path` included). Made once, at setup — never during a run.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * import { fileSink, readRecordFile } from 'footprintjs/sinks';
105
+ * import { readStoredRecord } from 'foottrace';
106
+ *
107
+ * const sink = fileSink('/var/footprint/orders.jsonl');
108
+ * const executor = new FlowChartExecutor(chart, { sink });
109
+ * await executor.run({ input });
110
+ * // …later, or after a crash:
111
+ * const record = readStoredRecord(readRecordFile('/var/footprint/orders.jsonl').entries);
112
+ * record.root(runId)?.complete; // false for a run that never ended
113
+ * ```
114
+ */
115
+ export declare function fileSink(path: string, options?: FileSinkOptions): FileSink;
116
+ /** A record file read back: every parsed line, and every line that could not be. */
117
+ export interface RecordFile {
118
+ /** The parsed entries, in file order — untrusted input for `readStoredRecord` (`foottrace`). */
119
+ readonly entries: readonly unknown[];
120
+ /** Each line that is not JSON (a torn last line, a corrupt one), by its 1-based number. Blank lines are skipped. */
121
+ readonly unreadable: readonly {
122
+ readonly line: number;
123
+ readonly reason: string;
124
+ }[];
125
+ }
126
+ /**
127
+ * Read a record file back, line by line — the entries for `readStoredRecord`, and every line that could not be
128
+ * read, by number, never a failed read. A stored key named `__proto__` stays data (`JSON.parse` makes it an own
129
+ * property). The file is untrusted: a file larger than `maxBytes` (default 256 MiB) is refused before it is read.
130
+ *
131
+ * @throws RangeError when the file is larger than `maxBytes`; the operating system's error when it cannot be read.
132
+ */
133
+ export declare function readRecordFile(path: string, options?: {
134
+ readonly maxBytes?: number;
135
+ }): RecordFile;
@@ -0,0 +1,387 @@
1
+ /**
2
+ * sinks/fileSink.ts — the record, one JSON line per entry, in a file (design §3.5, §4, packet P6). NODE ONLY: the
3
+ * one file in `src/` that imports a Node built-in, reachable only through the `footprintjs/sinks` door.
4
+ *
5
+ * WHY A FILE, WHY THIS SHAPE. A run's record must outlive the process that made it — a killed process, a crashed
6
+ * host, a serverless freeze. Each entry the log hands over is encoded, checked and given its own offset in the file,
7
+ * and its write is handed to the I/O pool AT ONCE (a positional write — no entry waits for the event loop to turn);
8
+ * the pool's threads perform them while the main thread runs on. A process killed after a pool thread wrote an entry
9
+ * keeps it. Until then it is not on disk: microseconds on a free pool, but the pool (4 threads by default) is shared
10
+ * with DNS lookups, zlib, crypto and other fs work, so while it is busy the window is as long as that work — and since
11
+ * writes complete out of order, a kill can lose an entry in the middle (the reader reports the hole). `flush()` waits for every write and
12
+ * `fsync`s — the step that also survives the machine losing power, and the one the executor awaits after each run's
13
+ * closing entry.
14
+ *
15
+ * THE THREAT MODEL, as code — every resource bounded, nothing that can stall the run:
16
+ * - ONLY THE PATH THE APP GIVES. Resolved once and opened once, at `fileSink(path)`; every entry goes to that open
17
+ * file. A symbolic link at the path is refused (`O_NOFOLLOW`, where the platform has it), and so is anything
18
+ * that is not a regular file, a file with another hard link, another owner, or group/world write. A file the
19
+ * sink creates is `0o600`.
20
+ * - ATOMIC PER ENTRY. A line is encoded in full first — an entry JSON cannot write (a `BigInt`, a cycle) is
21
+ * refused whole — then written at its own offset. A write that fails part-way leaves a hole up to the next
22
+ * entry's offset; the reader splits at it (NUL), so a torn line never swallows the one after it (an existing
23
+ * file with a torn tail gets a newline first).
24
+ * - BOUNDED: `maxEntryBytes` (one line, 8 MiB — refused by name, before it is encoded when its length already
25
+ * says so), `maxQueuedBytes` (accepted, not yet written, 16 MiB — past it an entry is DROPPED and counted, never
26
+ * buffered without limit), `maxBytes` (the file, 64 MiB — once full, every further entry is refused and counted;
27
+ * a closing entry may use a 64 KiB reserve so a full file can still say how the run ended), `flushTimeoutMs`
28
+ * (10 s — then `flush()` rejects). Every refusal throws from the sink method, which the log counts
29
+ * (`getSnapshot().sink`); a write that fails later rejects that entry's promise, counted the same way.
30
+ * - ASYNCHRONOUS WRITES ONLY. No method blocks on the disk; the file is released asynchronously, after every
31
+ * write and every started fsync.
32
+ * - NO SECRET ON DISK is the EXECUTOR's law, applied before any entry reaches an adapter (`runner/recordSink.ts`):
33
+ * this file writes what it is handed and reads nothing else.
34
+ * - ONE WRITER PER FILE. A second sink on a file this process has open is refused (by device and inode, across the
35
+ * CommonJS and ESM builds). ANOTHER PROCESS writing the same path is not seen at open: each writes at its own
36
+ * offsets and would overwrite the other. `flush()` checks the file's size against what this sink placed and rejects
37
+ * (a loss the run counts) when another writer's bytes reach past it — best effort: an overwrite this sink's own
38
+ * later writes cover is not seen. Give each process its own file.
39
+ *
40
+ * WHAT JSON KEEPS. A line holds what `JSON.stringify` keeps: a `Date` becomes its ISO string, a `Map` / `Set` an
41
+ * empty object, `undefined` disappears. A record of plain JSON values reads back exactly (`readRecordFile` →
42
+ * `readStoredRecord`); for richer values, bring an adapter with a richer encoding.
43
+ */
44
+ import { close, closeSync, constants, fstat, fstatSync, fsync, openSync, readSync, write } from 'node:fs';
45
+ import { resolve as resolvePath } from 'node:path';
46
+ import { getuid } from 'node:process';
47
+ /** The default cap on a record file: 64 MiB. */
48
+ export const DEFAULT_FILE_SINK_MAX_BYTES = 64 * 1024 * 1024;
49
+ /** The default cap on ONE entry's line: 8 MiB. */
50
+ export const DEFAULT_FILE_SINK_MAX_ENTRY_BYTES = 8 * 1024 * 1024;
51
+ /** The default cap on bytes accepted but not yet written: 16 MiB. */
52
+ export const DEFAULT_FILE_SINK_MAX_QUEUED_BYTES = 16 * 1024 * 1024;
53
+ /** The default bound on `flush()`: 10 s. */
54
+ export const DEFAULT_FILE_SINK_FLUSH_TIMEOUT_MS = 10_000;
55
+ /** How far past `maxBytes` a CLOSING entry may still go, so a full file can say how the run ended: 64 KiB. */
56
+ const CLOSE_RESERVE_BYTES = 64 * 1024;
57
+ /** The default cap `readRecordFile` reads: 256 MiB. */
58
+ const DEFAULT_READ_MAX_BYTES = 256 * 1024 * 1024;
59
+ /**
60
+ * A record sink that appends each entry to `path` as one JSON line — the crash-safe record on a Node host.
61
+ *
62
+ * Every method returns at once: the line is encoded, checked against every bound, given its offset and handed to
63
+ * the I/O pool. The method's promise settles when that line is written; a write that fails rejects it, and the run
64
+ * counts the loss.
65
+ *
66
+ * @throws TypeError when `path` is not a non-empty string or does not name a regular file the writer owns alone;
67
+ * RangeError for a bound that is not a whole number ≥ 1; the operating system's error when
68
+ * the file cannot be opened (a symbolic link at `path` included). Made once, at setup — never during a run.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * import { fileSink, readRecordFile } from 'footprintjs/sinks';
73
+ * import { readStoredRecord } from 'foottrace';
74
+ *
75
+ * const sink = fileSink('/var/footprint/orders.jsonl');
76
+ * const executor = new FlowChartExecutor(chart, { sink });
77
+ * await executor.run({ input });
78
+ * // …later, or after a crash:
79
+ * const record = readStoredRecord(readRecordFile('/var/footprint/orders.jsonl').entries);
80
+ * record.root(runId)?.complete; // false for a run that never ended
81
+ * ```
82
+ */
83
+ export function fileSink(path, options) {
84
+ if (typeof path !== 'string' || path === '')
85
+ throw new TypeError('fileSink: path must be a non-empty string');
86
+ const maxBytes = bound('maxBytes', options?.maxBytes, DEFAULT_FILE_SINK_MAX_BYTES, 1);
87
+ const maxEntryBytes = bound('maxEntryBytes', options?.maxEntryBytes, DEFAULT_FILE_SINK_MAX_ENTRY_BYTES, 1);
88
+ const maxQueuedBytes = bound('maxQueuedBytes', options?.maxQueuedBytes, DEFAULT_FILE_SINK_MAX_QUEUED_BYTES, 1);
89
+ const flushTimeoutMs = bound('flushTimeoutMs', options?.flushTimeoutMs, DEFAULT_FILE_SINK_FLUSH_TIMEOUT_MS, 1);
90
+ const absolute = resolvePath(path);
91
+ // NOT `O_APPEND`: each entry is written at the offset it was given when it was queued (a positional write), so
92
+ // every entry is handed to the I/O pool the moment it is accepted — none waits for the event loop to turn.
93
+ const fd = openSync(absolute, constants.O_RDWR | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0), 0o600);
94
+ let identity;
95
+ let size;
96
+ let needsNewline; // the file ends with a torn line: the first entry starts a new one
97
+ try {
98
+ const stat = fstatSync(fd);
99
+ if (!stat.isFile())
100
+ throw new TypeError(`fileSink: ${absolute} is not a regular file`);
101
+ refuseForeign(absolute, stat);
102
+ identity = `${stat.dev}:${stat.ino}`;
103
+ // One writer per file, in this process: a second sink would place its entries over the first's.
104
+ if (OPEN_FILES.has(identity))
105
+ throw new TypeError(`fileSink: ${absolute} already has an open sink in this process`);
106
+ size = stat.size;
107
+ needsNewline = size > 0 && !endsWithNewline(fd, size);
108
+ }
109
+ catch (error) {
110
+ closeSync(fd);
111
+ throw error;
112
+ }
113
+ OPEN_FILES.add(identity);
114
+ const encoder = new TextEncoder();
115
+ let next = size; // the offset the next accepted entry is written at — what `maxBytes` bounds
116
+ let written = size; // bytes known on disk
117
+ let queuedBytes = 0; // accepted, not yet written (in the I/O pool's hands)
118
+ let inFlight = 0;
119
+ let syncing = 0;
120
+ let full = false;
121
+ let closing = false;
122
+ let released = false;
123
+ let drained = [];
124
+ let closedSignal;
125
+ const whenReleased = new Promise((resolve) => (closedSignal = resolve));
126
+ /** Release the file once nothing is in flight and no fsync is pending — asynchronously; an error is ignored. */
127
+ const releaseIfIdle = () => {
128
+ if (!closing || released || inFlight > 0 || syncing > 0)
129
+ return;
130
+ released = true;
131
+ OPEN_FILES.delete(identity);
132
+ close(fd, () => closedSignal?.());
133
+ };
134
+ /** Everything accepted is written: start each waiting flush's fsync, then release if closing. */
135
+ const settleDrained = () => {
136
+ if (inFlight > 0)
137
+ return;
138
+ const waiting = drained;
139
+ drained = [];
140
+ for (const start of waiting)
141
+ start();
142
+ releaseIfIdle();
143
+ };
144
+ /** One entry: refused whole with a named bound (the log counts it), or submitted — never in part, never blocking. */
145
+ const enqueue = (entry) => {
146
+ if (closing)
147
+ throw new Error(`fileSink: ${absolute} is closed`);
148
+ // The cheap refusals first: a full file or a full queue costs no encoding.
149
+ if (full && entry.kind !== 'closed')
150
+ throw fileFull(absolute, maxBytes, entry.kind);
151
+ // A closing entry is exempt from the queue bound (as from `maxBytes`, within its reserve): how a log ended is
152
+ // the one entry a full queue must not drop.
153
+ const isClosingEntry = entry.kind === 'closed';
154
+ if (!isClosingEntry && queuedBytes >= maxQueuedBytes)
155
+ throw queueFull(absolute, queuedBytes, maxQueuedBytes, entry.kind);
156
+ const json = JSON.stringify(entry); // an entry JSON cannot write (a BigInt, a cycle) throws here, whole
157
+ // A string's length never exceeds its UTF-8 size: an entry already too long is refused before it is encoded.
158
+ if (json.length + 1 > maxEntryBytes)
159
+ throw tooLarge(absolute, entry.kind, maxEntryBytes);
160
+ const encoded = encoder.encode(`${needsNewline ? '\n' : ''}${json}\n`);
161
+ if (encoded.length > maxEntryBytes + 1)
162
+ throw tooLarge(absolute, entry.kind, maxEntryBytes);
163
+ const limit = entry.kind === 'closed' ? maxBytes + CLOSE_RESERVE_BYTES : maxBytes;
164
+ if (next + encoded.length > limit) {
165
+ if (entry.kind !== 'closed')
166
+ full = true;
167
+ throw fileFull(absolute, maxBytes, entry.kind);
168
+ }
169
+ if (!isClosingEntry && queuedBytes + encoded.length > maxQueuedBytes) {
170
+ throw queueFull(absolute, queuedBytes, maxQueuedBytes, entry.kind);
171
+ }
172
+ needsNewline = false;
173
+ const at = next;
174
+ next += encoded.length;
175
+ queuedBytes += encoded.length;
176
+ inFlight += 1;
177
+ return new Promise((resolve, reject) => {
178
+ writeAt(fd, encoded, at, (error, wrote) => {
179
+ inFlight -= 1;
180
+ queuedBytes -= encoded.length;
181
+ written += wrote;
182
+ // A line cut short leaves a hole up to the next entry's offset: the reader splits at it (NUL), so a torn
183
+ // line never swallows the entry after it.
184
+ if (error)
185
+ reject(error);
186
+ else
187
+ resolve();
188
+ settleDrained();
189
+ });
190
+ });
191
+ };
192
+ return {
193
+ path: absolute,
194
+ get bytes() {
195
+ return written;
196
+ },
197
+ get queuedBytes() {
198
+ return queuedBytes;
199
+ },
200
+ get full() {
201
+ return full;
202
+ },
203
+ opened: ({ address, at, initialState, meta }) => enqueue({ kind: 'opened', address, at, initialState, ...(meta === undefined ? {} : { meta }) }),
204
+ commit: ({ address, at, bundle }) => enqueue({ kind: 'commit', address, at, bundle }),
205
+ note: ({ address, at, kind, data }) => enqueue({ kind: 'note', address, at, note: kind, data }),
206
+ closed: ({ address, at, outcome, commits, meta }) => enqueue({ kind: 'closed', address, at, outcome, commits, ...(meta === undefined ? {} : { meta }) }),
207
+ flush: () => {
208
+ if (closing)
209
+ return Promise.reject(new Error(`fileSink: ${absolute} is closed`));
210
+ const work = new Promise((resolve, reject) => {
211
+ drained.push(() => {
212
+ syncing += 1;
213
+ fsync(fd, (error) => {
214
+ if (error) {
215
+ syncing -= 1;
216
+ reject(error);
217
+ releaseIfIdle();
218
+ return;
219
+ }
220
+ // Another writer (another process on the same path) grew the file past what this sink placed: its
221
+ // entries and ours overlap. Said, never silent.
222
+ fstat(fd, (statError, stat) => {
223
+ syncing -= 1;
224
+ if (statError)
225
+ reject(statError);
226
+ else if (stat.size > next) {
227
+ reject(new Error(`fileSink: ${absolute} was written by another writer (one sink per file)`));
228
+ }
229
+ else
230
+ resolve();
231
+ releaseIfIdle();
232
+ });
233
+ });
234
+ });
235
+ settleDrained();
236
+ });
237
+ return withTimeout(work, flushTimeoutMs, `fileSink: flush() of ${absolute} did not finish in ${flushTimeoutMs}ms`);
238
+ },
239
+ close: () => {
240
+ if (!closing) {
241
+ closing = true;
242
+ releaseIfIdle();
243
+ }
244
+ return whenReleased;
245
+ },
246
+ };
247
+ }
248
+ /**
249
+ * Files a sink of this process has open, by device and inode — one writer per file. Kept on the global object, so
250
+ * the package's CommonJS and ESM builds (two module instances in one process) share it.
251
+ */
252
+ const OPEN_FILES = (globalThis[Symbol.for('footprintjs.fileSink.open')] ??=
253
+ new Set());
254
+ function fileFull(path, maxBytes, kind) {
255
+ return new RangeError(`fileSink: ${path} is full (maxBytes ${maxBytes}); this ${kind} entry was not written`);
256
+ }
257
+ function queueFull(path, queued, maxQueuedBytes, kind) {
258
+ return new RangeError(`fileSink: ${path} has ${queued} bytes waiting (maxQueuedBytes ${maxQueuedBytes}); this ${kind} entry was dropped`);
259
+ }
260
+ /** A bound read off the options: absent → the default; else a whole number ≥ `min`, or a RangeError naming it. */
261
+ function bound(name, value, fallback, min) {
262
+ if (value === undefined)
263
+ return fallback;
264
+ if (!Number.isSafeInteger(value) || value < min) {
265
+ throw new RangeError(`fileSink: ${name} must be a whole number, at least ${min}`);
266
+ }
267
+ return value;
268
+ }
269
+ function tooLarge(path, kind, maxEntryBytes) {
270
+ return new RangeError(`fileSink: a ${kind} entry larger than maxEntryBytes (${maxEntryBytes}) was not written to ${path}`);
271
+ }
272
+ /** Write all of `buffer` at `position` (asynchronously, as many writes as it takes); `wrote` is how much went out. */
273
+ function writeAt(fd, buffer, position, done) {
274
+ const step = (offset) => {
275
+ write(fd, buffer, offset, buffer.length - offset, position + offset, (error, n) => {
276
+ if (error)
277
+ done(error, offset);
278
+ else if (n === 0)
279
+ done(new Error('fileSink: the disk took no bytes'), offset);
280
+ else if (offset + n < buffer.length)
281
+ step(offset + n);
282
+ else
283
+ done(null, buffer.length);
284
+ });
285
+ };
286
+ step(0);
287
+ }
288
+ /** `work`, or a rejection naming the bound once `ms` passed — the work goes on, nobody waits for it. */
289
+ function withTimeout(work, ms, message) {
290
+ return new Promise((resolve, reject) => {
291
+ const timer = setTimeout(() => reject(new Error(message)), ms);
292
+ // A timer that only bounds a wait never keeps the process alive on its own.
293
+ timer.unref?.();
294
+ Promise.prototype.then.call(work, () => {
295
+ clearTimeout(timer);
296
+ resolve();
297
+ }, (error) => {
298
+ clearTimeout(timer);
299
+ reject(error);
300
+ });
301
+ });
302
+ }
303
+ /**
304
+ * Refuse a file someone else could read or rewrite behind the sink: a hard link (another name for the same bytes —
305
+ * the sink would append into it), a file owned by another user, or one others may write. A file the sink creates is
306
+ * `0o600` and passes; a pre-existing one must already be private to the writer. (Not on Windows, whose modes and
307
+ * owners do not map: there `O_NOFOLLOW` is absent too — the guide names both.)
308
+ */
309
+ function refuseForeign(path, stat) {
310
+ if (stat.nlink > 1)
311
+ throw new TypeError(`fileSink: ${path} has other hard links — refusing to write through one`);
312
+ const uid = typeof getuid === 'function' ? getuid() : undefined;
313
+ if (uid !== undefined && stat.uid !== uid)
314
+ throw new TypeError(`fileSink: ${path} belongs to another user`);
315
+ if (uid !== undefined && (stat.mode & 0o022) !== 0) {
316
+ throw new TypeError(`fileSink: ${path} is writable by others — make it 0o600 (or remove it) first`);
317
+ }
318
+ }
319
+ /** Whether the file's last byte is a newline — read once, when the sink opens an existing file. */
320
+ function endsWithNewline(fd, size) {
321
+ const last = new Uint8Array(1);
322
+ return readSync(fd, last, 0, 1, size - 1) === 1 && last[0] === 0x0a;
323
+ }
324
+ /**
325
+ * Read a record file back, line by line — the entries for `readStoredRecord`, and every line that could not be
326
+ * read, by number, never a failed read. A stored key named `__proto__` stays data (`JSON.parse` makes it an own
327
+ * property). The file is untrusted: a file larger than `maxBytes` (default 256 MiB) is refused before it is read.
328
+ *
329
+ * @throws RangeError when the file is larger than `maxBytes`; the operating system's error when it cannot be read.
330
+ */
331
+ export function readRecordFile(path, options) {
332
+ if (typeof path !== 'string' || path === '')
333
+ throw new TypeError('readRecordFile: path must be a non-empty string');
334
+ const maxBytes = bound('maxBytes', options?.maxBytes, DEFAULT_READ_MAX_BYTES, 1);
335
+ // One descriptor for the check AND the read (a file that grows between them is still bounded); a regular file
336
+ // only (a FIFO would block, a device never end); at most `maxBytes` read.
337
+ // O_NONBLOCK: a FIFO at the path must not block the open before the regular-file check refuses it.
338
+ const fd = openSync(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
339
+ let raw;
340
+ try {
341
+ const stat = fstatSync(fd);
342
+ if (!stat.isFile())
343
+ throw new TypeError(`readRecordFile: ${path} is not a regular file`);
344
+ if (stat.size > maxBytes) {
345
+ throw new RangeError(`readRecordFile: ${path} holds ${stat.size} bytes, past the limit of ${maxBytes}`);
346
+ }
347
+ const buffer = new Uint8Array(Math.min(stat.size, maxBytes) + 1);
348
+ let read = 0;
349
+ for (;;) {
350
+ const n = readSync(fd, buffer, read, buffer.length - read, read);
351
+ if (n === 0)
352
+ break;
353
+ read += n;
354
+ if (read === buffer.length) {
355
+ throw new RangeError(`readRecordFile: ${path} grew past the limit of ${maxBytes} bytes while being read`);
356
+ }
357
+ }
358
+ raw = buffer.subarray(0, read);
359
+ }
360
+ finally {
361
+ closeSync(fd);
362
+ }
363
+ const text = new TextDecoder('utf-8').decode(raw);
364
+ const entries = [];
365
+ const unreadable = [];
366
+ const lines = text.split('\n');
367
+ for (let i = 0; i < lines.length; i++) {
368
+ // A run of NUL bytes is a hole a cut-short write left before the next entry's offset: it ends the torn part,
369
+ // so the entry after it reads on its own (the same line number names both pieces).
370
+ const line = lines[i];
371
+ // A hole is reported, never skipped: bytes that never reached the disk may be a whole entry lost mid-file.
372
+ if (line.includes('\0'))
373
+ unreadable.push({ line: i + 1, reason: 'a hole — bytes that never reached the disk' });
374
+ for (const piece of line.split(/\0+/)) {
375
+ if (piece.trim() === '')
376
+ continue;
377
+ try {
378
+ entries.push(JSON.parse(piece));
379
+ }
380
+ catch {
381
+ unreadable.push({ line: i + 1, reason: 'not JSON — a torn or corrupt line' });
382
+ }
383
+ }
384
+ }
385
+ return { entries, unreadable };
386
+ }
387
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZVNpbmsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NpbmtzL2ZpbGVTaW5rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQ0c7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDMUcsT0FBTyxFQUFFLE9BQU8sSUFBSSxXQUFXLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUl0QyxnREFBZ0Q7QUFDaEQsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDNUQsa0RBQWtEO0FBQ2xELE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ2pFLHFFQUFxRTtBQUNyRSxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUNuRSw0Q0FBNEM7QUFDNUMsTUFBTSxDQUFDLE1BQU0sa0NBQWtDLEdBQUcsTUFBTSxDQUFDO0FBQ3pELDhHQUE4RztBQUM5RyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDdEMsdURBQXVEO0FBQ3ZELE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUEwQ2pEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCRztBQUNILE1BQU0sVUFBVSxRQUFRLENBQUMsSUFBWSxFQUFFLE9BQXlCO0lBQzlELElBQUksT0FBTyxJQUFJLEtBQUssUUFB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SyxDQUFDLEVBQUUsQ0FBQztZQUN0QyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFO2dCQUFFLFNBQVM7WUFDbEMsSUFBSSxDQUFDO2dCQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxtQ0FBbUMsRUFBRSxDQUFDLENBQUM7WUFDaEYsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUNqQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBzaW5rcy9maWxlU2luay50cyDigJQgdGhlIHJlY29yZCwgb25lIEpTT04gbGluZSBwZXIgZW50cnksIGluIGEgZmlsZSAoZGVzaWduIMKnMy41LCDCpzQsIHBhY2tldCBQNikuIE5PREUgT05MWTogdGhlXG4gKiBvbmUgZmlsZSBpbiBgc3JjL2AgdGhhdCBpbXBvcnRzIGEgTm9kZSBidWlsdC1pbiwgcmVhY2hhYmxlIG9ubHkgdGhyb3VnaCB0aGUgYGZvb3RwcmludGpzL3NpbmtzYCBkb29yLlxuICpcbiAqIFdIWSBBIEZJTEUsIFdIWSBUSElTIFNIQVBFLiBBIHJ1bidzIHJlY29yZCBtdXN0IG91dGxpdmUgdGhlIHByb2Nlc3MgdGhhdCBtYWRlIGl0IOKAlCBhIGtpbGxlZCBwcm9jZXNzLCBhIGNyYXNoZWRcbiAqIGhvc3QsIGEgc2VydmVybGVzcyBmcmVlemUuIEVhY2ggZW50cnkgdGhlIGxvZyBoYW5kcyBvdmVyIGlzIGVuY29kZWQsIGNoZWNrZWQgYW5kIGdpdmVuIGl0cyBvd24gb2Zmc2V0IGluIHRoZSBmaWxlLFxuICogYW5kIGl0cyB3cml0ZSBpcyBoYW5kZWQgdG8gdGhlIEkvTyBwb29sIEFUIE9OQ0UgKGEgcG9zaXRpb25hbCB3cml0ZSDigJQgbm8gZW50cnkgd2FpdHMgZm9yIHRoZSBldmVudCBsb29wIHRvIHR1cm4pO1xuICogdGhlIHBvb2wncyB0aHJlYWRzIHBlcmZvcm0gdGhlbSB3aGlsZSB0aGUgbWFpbiB0aHJlYWQgcnVucyBvbi4gQSBwcm9jZXNzIGtpbGxlZCBhZnRlciBhIHBvb2wgdGhyZWFkIHdyb3RlIGFuIGVudHJ5XG4gKiBrZWVwcyBpdC4gVW50aWwgdGhlbiBpdCBpcyBub3Qgb24gZGlzazogbWljcm9zZWNvbmRzIG9uIGEgZnJlZSBwb29sLCBidXQgdGhlIHBvb2wgKDQgdGhyZWFkcyBieSBkZWZhdWx0KSBpcyBzaGFyZWRcbiAqIHdpdGggRE5TIGxvb2t1cHMsIHpsaWIsIGNyeXB0byBhbmQgb3RoZXIgZnMgd29yaywgc28gd2hpbGUgaXQgaXMgYnVzeSB0aGUgd2luZG93IGlzIGFzIGxvbmcgYXMgdGhhdCB3b3JrIOKAlCBhbmQgc2luY2VcbiAqIHdyaXRlcyBjb21wbGV0ZSBvdXQgb2Ygb3JkZXIsIGEga2lsbCBjYW4gbG9zZSBhbiBlbnRyeSBpbiB0aGUgbWlkZGxlICh0aGUgcmVhZGVyIHJlcG9ydHMgdGhlIGhvbGUpLiBgZmx1c2goKWAgd2FpdHMgZm9yIGV2ZXJ5IHdyaXRlIGFuZFxuICogYGZzeW5jYHMg4oCUIHRoZSBzdGVwIHRoYXQgYWxzbyBzdXJ2aXZlcyB0aGUgbWFjaGluZSBsb3NpbmcgcG93ZXIsIGFuZCB0aGUgb25lIHRoZSBleGVjdXRvciBhd2FpdHMgYWZ0ZXIgZWFjaCBydW4nc1xuICogY2xvc2luZyBlbnRyeS5cbiAqXG4gKiBUSEUgVEhSRUFUIE1PREVMLCBhcyBjb2RlIOKAlCBldmVyeSByZXNvdXJjZSBib3VuZGVkLCBub3RoaW5nIHRoYXQgY2FuIHN0YWxsIHRoZSBydW46XG4gKiAgIC0gT05MWSBUSEUgUEFUSCBUSEUgQVBQIEdJVkVTLiBSZXNvbHZlZCBvbmNlIGFuZCBvcGVuZWQgb25jZSwgYXQgYGZpbGVTaW5rKHBhdGgpYDsgZXZlcnkgZW50cnkgZ29lcyB0byB0aGF0IG9wZW5cbiAqICAgICBmaWxlLiBBIHN5bWJvbGljIGxpbmsgYXQgdGhlIHBhdGggaXMgcmVmdXNlZCAoYE9fTk9GT0xMT1dgLCB3aGVyZSB0aGUgcGxhdGZvcm0gaGFzIGl0KSwgYW5kIHNvIGlzIGFueXRoaW5nXG4gKiAgICAgdGhhdCBpcyBub3QgYSByZWd1bGFyIGZpbGUsIGEgZmlsZSB3aXRoIGFub3RoZXIgaGFyZCBsaW5rLCBhbm90aGVyIG93bmVyLCBvciBncm91cC93b3JsZCB3cml0ZS4gQSBmaWxlIHRoZVxuICogICAgIHNpbmsgY3JlYXRlcyBpcyBgMG82MDBgLlxuICogICAtIEFUT01JQyBQRVIgRU5UUlkuIEEgbGluZSBpcyBlbmNvZGVkIGluIGZ1bGwgZmlyc3Qg4oCUIGFuIGVudHJ5IEpTT04gY2Fubm90IHdyaXRlIChhIGBCaWdJbnRgLCBhIGN5Y2xlKSBpc1xuICogICAgIHJlZnVzZWQgd2hvbGUg4oCUIHRoZW4gd3JpdHRlbiBhdCBpdHMgb3duIG9mZnNldC4gQSB3cml0ZSB0aGF0IGZhaWxzIHBhcnQtd2F5IGxlYXZlcyBhIGhvbGUgdXAgdG8gdGhlIG5leHRcbiAqICAgICBlbnRyeSdzIG9mZnNldDsgdGhlIHJlYWRlciBzcGxpdHMgYXQgaXQgKE5VTCksIHNvIGEgdG9ybiBsaW5lIG5ldmVyIHN3YWxsb3dzIHRoZSBvbmUgYWZ0ZXIgaXQgKGFuIGV4aXN0aW5nXG4gKiAgICAgZmlsZSB3aXRoIGEgdG9ybiB0YWlsIGdldHMgYSBuZXdsaW5lIGZpcnN0KS5cbiAqICAgLSBCT1VOREVEOiBgbWF4RW50cnlCeXRlc2AgKG9uZSBsaW5lLCA4IE1pQiDigJQgcmVmdXNlZCBieSBuYW1lLCBiZWZvcmUgaXQgaXMgZW5jb2RlZCB3aGVuIGl0cyBsZW5ndGggYWxyZWFkeVxuICogICAgIHNheXMgc28pLCBgbWF4UXVldWVkQnl0ZXNgIChhY2NlcHRlZCwgbm90IHlldCB3cml0dGVuLCAxNiBNaUIg4oCUIHBhc3QgaXQgYW4gZW50cnkgaXMgRFJPUFBFRCBhbmQgY291bnRlZCwgbmV2ZXJcbiAqICAgICBidWZmZXJlZCB3aXRob3V0IGxpbWl0KSwgYG1heEJ5dGVzYCAodGhlIGZpbGUsIDY0IE1pQiDigJQgb25jZSBmdWxsLCBldmVyeSBmdXJ0aGVyIGVudHJ5IGlzIHJlZnVzZWQgYW5kIGNvdW50ZWQ7XG4gKiAgICAgYSBjbG9zaW5nIGVudHJ5IG1heSB1c2UgYSA2NCBLaUIgcmVzZXJ2ZSBzbyBhIGZ1bGwgZmlsZSBjYW4gc3RpbGwgc2F5IGhvdyB0aGUgcnVuIGVuZGVkKSwgYGZsdXNoVGltZW91dE1zYFxuICogICAgICgxMCBzIOKAlCB0aGVuIGBmbHVzaCgpYCByZWplY3RzKS4gRXZlcnkgcmVmdXNhbCB0aHJvd3MgZnJvbSB0aGUgc2luayBtZXRob2QsIHdoaWNoIHRoZSBsb2cgY291bnRzXG4gKiAgICAgKGBnZXRTbmFwc2hvdCgpLnNpbmtgKTsgYSB3cml0ZSB0aGF0IGZhaWxzIGxhdGVyIHJlamVjdHMgdGhhdCBlbnRyeSdzIHByb21pc2UsIGNvdW50ZWQgdGhlIHNhbWUgd2F5LlxuICogICAtIEFTWU5DSFJPTk9VUyBXUklURVMgT05MWS4gTm8gbWV0aG9kIGJsb2NrcyBvbiB0aGUgZGlzazsgdGhlIGZpbGUgaXMgcmVsZWFzZWQgYXN5bmNocm9ub3VzbHksIGFmdGVyIGV2ZXJ5XG4gKiAgICAgd3JpdGUgYW5kIGV2ZXJ5IHN0YXJ0ZWQgZnN5bmMuXG4gKiAgIC0gTk8gU0VDUkVUIE9OIERJU0sgaXMgdGhlIEVYRUNVVE9SJ3MgbGF3LCBhcHBsaWVkIGJlZm9yZSBhbnkgZW50cnkgcmVhY2hlcyBhbiBhZGFwdGVyIChgcnVubmVyL3JlY29yZFNpbmsudHNgKTpcbiAqICAgICB0aGlzIGZpbGUgd3JpdGVzIHdoYXQgaXQgaXMgaGFuZGVkIGFuZCByZWFkcyBub3RoaW5nIGVsc2UuXG4gKiAgIC0gT05FIFdSSVRFUiBQRVIgRklMRS4gQSBzZWNvbmQgc2luayBvbiBhIGZpbGUgdGhpcyBwcm9jZXNzIGhhcyBvcGVuIGlzIHJlZnVzZWQgKGJ5IGRldmljZSBhbmQgaW5vZGUsIGFjcm9zcyB0aGVcbiAqICAgICBDb21tb25KUyBhbmQgRVNNIGJ1aWxkcykuIEFOT1RIRVIgUFJPQ0VTUyB3cml0aW5nIHRoZSBzYW1lIHBhdGggaXMgbm90IHNlZW4gYXQgb3BlbjogZWFjaCB3cml0ZXMgYXQgaXRzIG93blxuICogICAgIG9mZnNldHMgYW5kIHdvdWxkIG92ZXJ3cml0ZSB0aGUgb3RoZXIuIGBmbHVzaCgpYCBjaGVja3MgdGhlIGZpbGUncyBzaXplIGFnYWluc3Qgd2hhdCB0aGlzIHNpbmsgcGxhY2VkIGFuZCByZWplY3RzXG4gKiAgICAgKGEgbG9zcyB0aGUgcnVuIGNvdW50cykgd2hlbiBhbm90aGVyIHdyaXRlcidzIGJ5dGVzIHJlYWNoIHBhc3QgaXQg4oCUIGJlc3QgZWZmb3J0OiBhbiBvdmVyd3JpdGUgdGhpcyBzaW5rJ3Mgb3duXG4gKiAgICAgbGF0ZXIgd3JpdGVzIGNvdmVyIGlzIG5vdCBzZWVuLiBHaXZlIGVhY2ggcHJvY2VzcyBpdHMgb3duIGZpbGUuXG4gKlxuICogV0hBVCBKU09OIEtFRVBTLiBBIGxpbmUgaG9sZHMgd2hhdCBgSlNPTi5zdHJpbmdpZnlgIGtlZXBzOiBhIGBEYXRlYCBiZWNvbWVzIGl0cyBJU08gc3RyaW5nLCBhIGBNYXBgIC8gYFNldGAgYW5cbiAqIGVtcHR5IG9iamVjdCwgYHVuZGVmaW5lZGAgZGlzYXBwZWFycy4gQSByZWNvcmQgb2YgcGxhaW4gSlNPTiB2YWx1ZXMgcmVhZHMgYmFjayBleGFjdGx5IChgcmVhZFJlY29yZEZpbGVgIOKGklxuICogYHJlYWRTdG9yZWRSZWNvcmRgKTsgZm9yIHJpY2hlciB2YWx1ZXMsIGJyaW5nIGFuIGFkYXB0ZXIgd2l0aCBhIHJpY2hlciBlbmNvZGluZy5cbiAqL1xuXG5pbXBvcnQgeyBjbG9zZSwgY2xvc2VTeW5jLCBjb25zdGFudHMsIGZzdGF0LCBmc3RhdFN5bmMsIGZzeW5jLCBvcGVuU3luYywgcmVhZFN5bmMsIHdyaXRlIH0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyByZXNvbHZlIGFzIHJlc29sdmVQYXRoIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGdldHVpZCB9IGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5cbmltcG9ydCB0eXBlIHsgUmVjb3JkRW50cnksIFJlY29yZFNpbmsgfSBmcm9tICdmb290dHJhY2Uvd3JpdGUnO1xuXG4vKiogVGhlIGRlZmF1bHQgY2FwIG9uIGEgcmVjb3JkIGZpbGU6IDY0IE1pQi4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0ZJTEVfU0lOS19NQVhfQllURVMgPSA2NCAqIDEwMjQgKiAxMDI0O1xuLyoqIFRoZSBkZWZhdWx0IGNhcCBvbiBPTkUgZW50cnkncyBsaW5lOiA4IE1pQi4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0ZJTEVfU0lOS19NQVhfRU5UUllfQllURVMgPSA4ICogMTAyNCAqIDEwMjQ7XG4vKiogVGhlIGRlZmF1bHQgY2FwIG9uIGJ5dGVzIGFjY2VwdGVkIGJ1dCBub3QgeWV0IHdyaXR0ZW46IDE2IE1pQi4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0ZJTEVfU0lOS19NQVhfUVVFVUVEX0JZVEVTID0gMTYgKiAxMDI0ICogMTAyNDtcbi8qKiBUaGUgZGVmYXVsdCBib3VuZCBvbiBgZmx1c2goKWA6IDEwIHMuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9GSUxFX1NJTktfRkxVU0hfVElNRU9VVF9NUyA9IDEwXzAwMDtcbi8qKiBIb3cgZmFyIHBhc3QgYG1heEJ5dGVzYCBhIENMT1NJTkcgZW50cnkgbWF5IHN0aWxsIGdvLCBzbyBhIGZ1bGwgZmlsZSBjYW4gc2F5IGhvdyB0aGUgcnVuIGVuZGVkOiA2NCBLaUIuICovXG5jb25zdCBDTE9TRV9SRVNFUlZFX0JZVEVTID0gNjQgKiAxMDI0O1xuLyoqIFRoZSBkZWZhdWx0IGNhcCBgcmVhZFJlY29yZEZpbGVgIHJlYWRzOiAyNTYgTWlCLiAqL1xuY29uc3QgREVGQVVMVF9SRUFEX01BWF9CWVRFUyA9IDI1NiAqIDEwMjQgKiAxMDI0O1xuXG4vKiogYGZpbGVTaW5rYCdzIG9wdGlvbnMg4oCUIGV2ZXJ5IHJlc291cmNlIHRoZSBzaW5rIGNhbiBzcGVuZCwgYm91bmRlZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZVNpbmtPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBtb3N0IGJ5dGVzIHRoZSBmaWxlIG1heSBob2xkICh0aGUgYnl0ZXMgYWxyZWFkeSBpbiBpdCBjb3VudCkuIE9uY2UgYW4gZW50cnkgd291bGQgcGFzcyBpdCwgdGhlIGZpbGUgaXMgRlVMTDpcbiAgICogdGhhdCBlbnRyeSBhbmQgZXZlcnkgbGF0ZXIgb25lIGlzIHJlZnVzZWQgYW5kIGNvdW50ZWQgYnkgdGhlIHJ1biwgbmV2ZXIgd3JpdHRlbiDigJQgZXhjZXB0IGEgY2xvc2luZyBlbnRyeSwgd2hpY2hcbiAgICogbWF5IHVzZSA2NCBLaUIgbW9yZSBzbyBhIGZ1bGwgZmlsZSBjYW4gc3RpbGwgc2F5IGhvdyB0aGUgcnVuIGVuZGVkLiBEZWZhdWx0IDY0IE1pQi5cbiAgICovXG4gIHJlYWRvbmx5IG1heEJ5dGVzPzogbnVtYmVyO1xuICAvKiogVGhlIGxhcmdlc3QgT05FIGVudHJ5J3MgbGluZSBtYXkgYmU7IGEgbGFyZ2VyIGVudHJ5IGlzIHJlZnVzZWQgd2hvbGUgKGBtYXhFbnRyeUJ5dGVzYCBuYW1lZCkuIERlZmF1bHQgOCBNaUIuICovXG4gIHJlYWRvbmx5IG1heEVudHJ5Qnl0ZXM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgbW9zdCBieXRlcyBhY2NlcHRlZCBhbmQgbm90IHlldCBvbiBkaXNrLiBXcml0ZXMgYXJlIGFzeW5jaHJvbm91cywgc28gYSBzaW5rIHNsb3dlciB0aGFuIHRoZSBydW4gcXVldWVzOyBwYXN0XG4gICAqIHRoaXMgYm91bmQgYW4gZW50cnkgaXMgRFJPUFBFRCBhbmQgY291bnRlZCAobmV2ZXIgYnVmZmVyZWQgd2l0aG91dCBsaW1pdCwgbmV2ZXIgYSBzdGFsbCkuIERlZmF1bHQgMTYgTWlCLlxuICAgKi9cbiAgcmVhZG9ubHkgbWF4UXVldWVkQnl0ZXM/OiBudW1iZXI7XG4gIC8qKiBIb3cgbG9uZyBgZmx1c2goKWAgKGRyYWluIHRoZSBxdWV1ZSwgdGhlbiBgZnN5bmNgKSBtYXkgdGFrZSBiZWZvcmUgaXQgcmVqZWN0cy4gRGVmYXVsdCAxMCBzLiAqL1xuICByZWFkb25seSBmbHVzaFRpbWVvdXRNcz86IG51bWJlcjtcbn1cblxuLyoqIEEgcmVjb3JkIHNpbmsgdGhhdCBhcHBlbmRzIHRvIG9uZSBmaWxlIOKAlCBgUmVjb3JkU2lua2AgcGx1cyB3aGF0IHRoZSBhcHAgbmVlZHMgdG8gbWFuYWdlIHRoZSBmaWxlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBGaWxlU2luayBleHRlbmRzIFJlY29yZFNpbmsge1xuICAvKiogVGhlIGFic29sdXRlIHBhdGggdGhlIHNpbmsgd3JpdGVzIHRvIOKAlCByZXNvbHZlZCBvbmNlLCB3aGVuIGl0IHdhcyBtYWRlLiAqL1xuICByZWFkb25seSBwYXRoOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBCeXRlcyB0aGlzIHNpbmsga25vd3MgYXJlIG9uIGRpc2s6IHRoZSBmaWxlJ3Mgc2l6ZSB3aGVuIGl0IG9wZW5lZCBwbHVzIGV2ZXJ5IGJ5dGUgaXRzIHdyaXRlcyBjb21wbGV0ZWQg4oCUIGFcbiAgICogcnVubmluZyBzdW0sIG5vdCB0aGUgZmlsZSdzIGVuZCAod3JpdGVzIGNvbXBsZXRlIG91dCBvZiBvcmRlcjsgYSBmYWlsZWQgb25lIGxlYXZlcyBhIGhvbGUpLlxuICAgKi9cbiAgcmVhZG9ubHkgYnl0ZXM6IG51bWJlcjtcbiAgLyoqIEJ5dGVzIGFjY2VwdGVkIGFuZCBub3QgeWV0IHdyaXR0ZW4uICovXG4gIHJlYWRvbmx5IHF1ZXVlZEJ5dGVzOiBudW1iZXI7XG4gIC8qKiBgdHJ1ZWAgb25jZSBhbiBlbnRyeSB3YXMgcmVmdXNlZCBmb3IgYG1heEJ5dGVzYDogdGhlIGZpbGUgaXMgZnVsbCwgYW5kIG9ubHkgYSBjbG9zaW5nIGVudHJ5IG1heSBzdGlsbCBnby4gKi9cbiAgcmVhZG9ubHkgZnVsbDogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFJlbGVhc2UgdGhlIGZpbGUuIElkZW1wb3RlbnQuIEV2ZXJ5IGVudHJ5IGFmdGVyIGl0IGlzIHJlZnVzZWQgKHRoZSBydW4gY291bnRzIGl0KSwgYW5kIGBmbHVzaCgpYCByZWplY3RzO1xuICAgKiBlbnRyaWVzIGFscmVhZHkgYWNjZXB0ZWQgYXJlIHN0aWxsIHdyaXR0ZW4gKGFuZCBhIGZsdXNoIGFscmVhZHkgc3RhcnRlZCBmaW5pc2hlcyksIHRoZW4gdGhlIGZpbGUgaXMgY2xvc2VkIOKAlFxuICAgKiB0aGUgcHJvbWlzZSBzZXR0bGVzIHRoZW4uXG4gICAqL1xuICBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKipcbiAqIEEgcmVjb3JkIHNpbmsgdGhhdCBhcHBlbmRzIGVhY2ggZW50cnkgdG8gYHBhdGhgIGFzIG9uZSBKU09OIGxpbmUg4oCUIHRoZSBjcmFzaC1zYWZlIHJlY29yZCBvbiBhIE5vZGUgaG9zdC5cbiAqXG4gKiBFdmVyeSBtZXRob2QgcmV0dXJucyBhdCBvbmNlOiB0aGUgbGluZSBpcyBlbmNvZGVkLCBjaGVja2VkIGFnYWluc3QgZXZlcnkgYm91bmQsIGdpdmVuIGl0cyBvZmZzZXQgYW5kIGhhbmRlZCB0b1xuICogdGhlIEkvTyBwb29sLiBUaGUgbWV0aG9kJ3MgcHJvbWlzZSBzZXR0bGVzIHdoZW4gdGhhdCBsaW5lIGlzIHdyaXR0ZW47IGEgd3JpdGUgdGhhdCBmYWlscyByZWplY3RzIGl0LCBhbmQgdGhlIHJ1blxuICogY291bnRzIHRoZSBsb3NzLlxuICpcbiAqIEB0aHJvd3MgVHlwZUVycm9yIHdoZW4gYHBhdGhgIGlzIG5vdCBhIG5vbi1lbXB0eSBzdHJpbmcgb3IgZG9lcyBub3QgbmFtZSBhIHJlZ3VsYXIgZmlsZSB0aGUgd3JpdGVyIG93bnMgYWxvbmU7XG4gKiAgIFJhbmdlRXJyb3IgZm9yIGEgYm91bmQgdGhhdCBpcyBub3QgYSB3aG9sZSBudW1iZXIg4omlIDE7IHRoZSBvcGVyYXRpbmcgc3lzdGVtJ3MgZXJyb3Igd2hlblxuICogICB0aGUgZmlsZSBjYW5ub3QgYmUgb3BlbmVkIChhIHN5bWJvbGljIGxpbmsgYXQgYHBhdGhgIGluY2x1ZGVkKS4gTWFkZSBvbmNlLCBhdCBzZXR1cCDigJQgbmV2ZXIgZHVyaW5nIGEgcnVuLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBmaWxlU2luaywgcmVhZFJlY29yZEZpbGUgfSBmcm9tICdmb290cHJpbnRqcy9zaW5rcyc7XG4gKiBpbXBvcnQgeyByZWFkU3RvcmVkUmVjb3JkIH0gZnJvbSAnZm9vdHRyYWNlJztcbiAqXG4gKiBjb25zdCBzaW5rID0gZmlsZVNpbmsoJy92YXIvZm9vdHByaW50L29yZGVycy5qc29ubCcpO1xuICogY29uc3QgZXhlY3V0b3IgPSBuZXcgRmxvd0NoYXJ0RXhlY3V0b3IoY2hhcnQsIHsgc2luayB9KTtcbiAqIGF3YWl0IGV4ZWN1dG9yLnJ1bih7IGlucHV0IH0pO1xuICogLy8g4oCmbGF0ZXIsIG9yIGFmdGVyIGEgY3Jhc2g6XG4gKiBjb25zdCByZWNvcmQgPSByZWFkU3RvcmVkUmVjb3JkKHJlYWRSZWNvcmRGaWxlKCcvdmFyL2Zvb3RwcmludC9vcmRlcnMuanNvbmwnKS5lbnRyaWVzKTtcbiAqIHJlY29yZC5yb290KHJ1bklkKT8uY29tcGxldGU7IC8vIGZhbHNlIGZvciBhIHJ1biB0aGF0IG5ldmVyIGVuZGVkXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbGVTaW5rKHBhdGg6IHN0cmluZywgb3B0aW9ucz86IEZpbGVTaW5rT3B0aW9ucyk6IEZpbGVTaW5rIHtcbiAgaWYgKHR5cGVvZiBwYXRoICE9PSAnc3RyaW5nJyB8fCBwYXRoID09PSAnJykgdGhyb3cgbmV3IFR5cGVFcnJvcignZmlsZVNpbms6IHBhdGggbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmcnKTtcbiAgY29uc3QgbWF4Qnl0ZXMgPSBib3VuZCgnbWF4Qnl0ZXMnLCBvcHRpb25zPy5tYXhCeXRlcywgREVGQVVMVF9GSUxFX1NJTktfTUFYX0JZVEVTLCAxKTtcbiAgY29uc3QgbWF4RW50cnlCeXRlcyA9IGJvdW5kKCdtYXhFbnRyeUJ5dGVzJywgb3B0aW9ucz8ubWF4RW50cnlCeXRlcywgREVGQVVMVF9GSUxFX1NJTktfTUFYX0VOVFJZX0JZVEVTLCAxKTtcbiAgY29uc3QgbWF4UXVldWVkQnl0ZXMgPSBib3VuZCgnbWF4UXVldWVkQnl0ZXMnLCBvcHRpb25zPy5tYXhRdWV1ZWRCeXRlcywgREVGQVVMVF9GSUxFX1NJTktfTUFYX1FVRVVFRF9CWVRFUywgMSk7XG4gIGNvbnN0IGZsdXNoVGltZW91dE1zID0gYm91bmQoJ2ZsdXNoVGltZW91dE1zJywgb3B0aW9ucz8uZmx1c2hUaW1lb3V0TXMsIERFRkFVTFRfRklMRV9TSU5LX0ZMVVNIX1RJTUVPVVRfTVMsIDEpO1xuICBjb25zdCBhYnNvbHV0ZSA9IHJlc29sdmVQYXRoKHBhdGgpO1xuICAvLyBOT1QgYE9fQVBQRU5EYDogZWFjaCBlbnRyeSBpcyB3cml0dGVuIGF0IHRoZSBvZmZzZXQgaXQgd2FzIGdpdmVuIHdoZW4gaXQgd2FzIHF1ZXVlZCAoYSBwb3NpdGlvbmFsIHdyaXRlKSwgc29cbiAgLy8gZXZlcnkgZW50cnkgaXMgaGFuZGVkIHRvIHRoZSBJL08gcG9vbCB0aGUgbW9tZW50IGl0IGlzIGFjY2VwdGVkIOKAlCBub25lIHdhaXRzIGZvciB0aGUgZXZlbnQgbG9vcCB0byB0dXJuLlxuICBjb25zdCBmZCA9IG9wZW5TeW5jKGFic29sdXRlLCBjb25zdGFudHMuT19SRFdSIHwgY29uc3RhbnRzLk9fQ1JFQVQgfCAoY29uc3RhbnRzLk9fTk9GT0xMT1cgPz8gMCksIDBvNjAwKTtcbiAgbGV0IGlkZW50aXR5OiBzdHJpbmc7XG4gIGxldCBzaXplOiBudW1iZXI7XG4gIGxldCBuZWVkc05ld2xpbmU6IGJvb2xlYW47IC8vIHRoZSBmaWxlIGVuZHMgd2l0aCBhIHRvcm4gbGluZTogdGhlIGZpcnN0IGVudHJ5IHN0YXJ0cyBhIG5ldyBvbmVcbiAgdHJ5IHtcbiAgICBjb25zdCBzdGF0ID0gZnN0YXRTeW5jKGZkKTtcbiAgICBpZiAoIXN0YXQuaXNGaWxlKCkpIHRocm93IG5ldyBUeXBlRXJyb3IoYGZpbGVTaW5rOiAke2Fic29sdXRlfSBpcyBub3QgYSByZWd1bGFyIGZpbGVgKTtcbiAgICByZWZ1c2VGb3JlaWduKGFic29sdXRlLCBzdGF0KTtcbiAgICBpZGVudGl0eSA9IGAke3N0YXQuZGV2fToke3N0YXQuaW5vfWA7XG4gICAgLy8gT25lIHdyaXRlciBwZXIgZmlsZSwgaW4gdGhpcyBwcm9jZXNzOiBhIHNlY29uZCBzaW5rIHdvdWxkIHBsYWNlIGl0cyBlbnRyaWVzIG92ZXIgdGhlIGZpcnN0J3MuXG4gICAgaWYgKE9QRU5fRklMRVMuaGFzKGlkZW50aXR5KSkgdGhyb3cgbmV3IFR5cGVFcnJvcihgZmlsZVNpbms6ICR7YWJzb2x1dGV9IGFscmVhZHkgaGFzIGFuIG9wZW4gc2luayBpbiB0aGlzIHByb2Nlc3NgKTtcbiAgICBzaXplID0gc3RhdC5zaXplO1xuICAgIG5lZWRzTmV3bGluZSA9IHNpemUgPiAwICYmICFlbmRzV2l0aE5ld2xpbmUoZmQsIHNpemUpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGNsb3NlU3luYyhmZCk7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbiAgT1BFTl9GSUxFUy5hZGQoaWRlbnRpdHkpO1xuXG4gIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgbGV0IG5leHQgPSBzaXplOyAvLyB0aGUgb2Zmc2V0IHRoZSBuZXh0IGFjY2VwdGVkIGVudHJ5IGlzIHdyaXR0ZW4gYXQg4oCUIHdoYXQgYG1heEJ5dGVzYCBib3VuZHNcbiAgbGV0IHdyaXR0ZW4gPSBzaXplOyAvLyBieXRlcyBrbm93biBvbiBkaXNrXG4gIGxldCBxdWV1ZWRCeXRlcyA9IDA7IC8vIGFjY2VwdGVkLCBub3QgeWV0IHdyaXR0ZW4gKGluIHRoZSBJL08gcG9vbCdzIGhhbmRzKVxuICBsZXQgaW5GbGlnaHQgPSAwO1xuICBsZXQgc3luY2luZyA9IDA7XG4gIGxldCBmdWxsID0gZmFsc2U7XG4gIGxldCBjbG9zaW5nID0gZmFsc2U7XG4gIGxldCByZWxlYXNlZCA9IGZhbHNlO1xuICBsZXQgZHJhaW5lZDogKCgpID0+IHZvaWQpW10gPSBbXTtcbiAgbGV0IGNsb3NlZFNpZ25hbDogKCgpID0+IHZvaWQpIHwgdW5kZWZpbmVkO1xuICBjb25zdCB3aGVuUmVsZWFzZWQgPSBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gKGNsb3NlZFNpZ25hbCA9IHJlc29sdmUpKTtcblxuICAvKiogUmVsZWFzZSB0aGUgZmlsZSBvbmNlIG5vdGhpbmcgaXMgaW4gZmxpZ2h0IGFuZCBubyBmc3luYyBpcyBwZW5kaW5nIOKAlCBhc3luY2hyb25vdXNseTsgYW4gZXJyb3IgaXMgaWdub3JlZC4gKi9cbiAgY29uc3QgcmVsZWFzZUlmSWRsZSA9ICgpOiB2b2lkID0+IHtcbiAgICBpZiAoIWNsb3NpbmcgfHwgcmVsZWFzZWQgfHwgaW5GbGlnaHQgPiAwIHx8IHN5bmNpbmcgPiAwKSByZXR1cm47XG4gICAgcmVsZWFzZWQgPSB0cnVlO1xuICAgIE9QRU5fRklMRVMuZGVsZXRlKGlkZW50aXR5KTtcbiAgICBjbG9zZShmZCwgKCkgPT4gY2xvc2VkU2lnbmFsPy4oKSk7XG4gIH07XG5cbiAgLyoqIEV2ZXJ5dGhpbmcgYWNjZXB0ZWQgaXMgd3JpdHRlbjogc3RhcnQgZWFjaCB3YWl0aW5nIGZsdXNoJ3MgZnN5bmMsIHRoZW4gcmVsZWFzZSBpZiBjbG9zaW5nLiAqL1xuICBjb25zdCBzZXR0bGVEcmFpbmVkID0gKCk6IHZvaWQgPT4ge1xuICAgIGlmIChpbkZsaWdodCA+IDApIHJldHVybjtcbiAgICBjb25zdCB3YWl0aW5nID0gZHJhaW5lZDtcbiAgICBkcmFpbmVkID0gW107XG4gICAgZm9yIChjb25zdCBzdGFydCBvZiB3YWl0aW5nKSBzdGFydCgpO1xuICAgIHJlbGVhc2VJZklkbGUoKTtcbiAgfTtcblxuICAvKiogT25lIGVudHJ5OiByZWZ1c2VkIHdob2xlIHdpdGggYSBuYW1lZCBib3VuZCAodGhlIGxvZyBjb3VudHMgaXQpLCBvciBzdWJtaXR0ZWQg4oCUIG5ldmVyIGluIHBhcnQsIG5ldmVyIGJsb2NraW5nLiAqL1xuICBjb25zdCBlbnF1ZXVlID0gKGVudHJ5OiBSZWNvcmRFbnRyeSk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIGlmIChjbG9zaW5nKSB0aHJvdyBuZXcgRXJyb3IoYGZpbGVTaW5rOiAke2Fic29sdXRlfSBpcyBjbG9zZWRgKTtcbiAgICAvLyBUaGUgY2hlYXAgcmVmdXNhbHMgZmlyc3Q6IGEgZnVsbCBmaWxlIG9yIGEgZnVsbCBxdWV1ZSBjb3N0cyBubyBlbmNvZGluZy5cbiAgICBpZiAoZnVsbCAmJiBlbnRyeS5raW5kICE9PSAnY2xvc2VkJykgdGhyb3cgZmlsZUZ1bGwoYWJzb2x1dGUsIG1heEJ5dGVzLCBlbnRyeS5raW5kKTtcbiAgICAvLyBBIGNsb3NpbmcgZW50cnkgaXMgZXhlbXB0IGZyb20gdGhlIHF1ZXVlIGJvdW5kIChhcyBmcm9tIGBtYXhCeXRlc2AsIHdpdGhpbiBpdHMgcmVzZXJ2ZSk6IGhvdyBhIGxvZyBlbmRlZCBpc1xuICAgIC8vIHRoZSBvbmUgZW50cnkgYSBmdWxsIHF1ZXVlIG11c3Qgbm90IGRyb3AuXG4gICAgY29uc3QgaXNDbG9zaW5nRW50cnkgPSBlbnRyeS5raW5kID09PSAnY2xvc2VkJztcbiAgICBpZiAoIWlzQ2xvc2luZ0VudHJ5ICYmIHF1ZXVlZEJ5dGVzID49IG1heFF1ZXVlZEJ5dGVzKVxuICAgICAgdGhyb3cgcXVldWVGdWxsKGFic29sdXRlLCBxdWV1ZWRCeXRlcywgbWF4UXVldWVkQnl0ZXMsIGVudHJ5LmtpbmQpO1xuICAgIGNvbnN0IGpzb24gPSBKU09OLnN0cmluZ2lmeShlbnRyeSk7IC8vIGFuIGVudHJ5IEpTT04gY2Fubm90IHdyaXRlIChhIEJpZ0ludCwgYSBjeWNsZSkgdGhyb3dzIGhlcmUsIHdob2xlXG4gICAgLy8gQSBzdHJpbmcncyBsZW5ndGggbmV2ZXIgZXhjZWVkcyBpdHMgVVRGLTggc2l6ZTogYW4gZW50cnkgYWxyZWFkeSB0b28gbG9uZyBpcyByZWZ1c2VkIGJlZm9yZSBpdCBpcyBlbmNvZGVkLlxuICAgIGlmIChqc29uLmxlbmd0aCArIDEgPiBtYXhFbnRyeUJ5dGVzKSB0aHJvdyB0b29MYXJnZShhYnNvbHV0ZSwgZW50cnkua2luZCwgbWF4RW50cnlCeXRlcyk7XG4gICAgY29uc3QgZW5jb2RlZCA9IGVuY29kZXIuZW5jb2RlKGAke25lZWRzTmV3bGluZSA/ICdcXG4nIDogJyd9JHtqc29ufVxcbmApO1xuICAgIGlmIChlbmNvZGVkLmxlbmd0aCA+IG1heEVudHJ5Qnl0ZXMgKyAxKSB0aHJvdyB0b29MYXJnZShhYnNvbHV0ZSwgZW50cnkua2luZCwgbWF4RW50cnlCeXRlcyk7XG4gICAgY29uc3QgbGltaXQgPSBlbnRyeS5raW5kID09PSAnY2xvc2VkJyA/IG1heEJ5dGVzICsgQ0xPU0VfUkVTRVJWRV9CWVRFUyA6IG1heEJ5dGVzO1xuICAgIGlmIChuZXh0ICsgZW5jb2RlZC5sZW5ndGggPiBsaW1pdCkge1xuICAgICAgaWYgKGVudHJ5LmtpbmQgIT09ICdjbG9zZWQnKSBmdWxsID0gdHJ1ZTtcbiAgICAgIHRocm93IGZpbGVGdWxsKGFic29sdXRlLCBtYXhCeXRlcywgZW50cnkua2luZCk7XG4gICAgfVxuICAgIGlmICghaXNDbG9zaW5nRW50cnkgJiYgcXVldWVkQnl0ZXMgKyBlbmNvZGVkLmxlbmd0aCA+IG1heFF1ZXVlZEJ5dGVzKSB7XG4gICAgICB0aHJvdyBxdWV1ZUZ1bGwoYWJzb2x1dGUsIHF1ZXVlZEJ5dGVzLCBtYXhRdWV1ZWRCeXRlcywgZW50cnkua2luZCk7XG4gICAgfVxuICAgIG5lZWRzTmV3bGluZSA9IGZhbHNlO1xuICAgIGNvbnN0IGF0ID0gbmV4dDtcbiAgICBuZXh0ICs9IGVuY29kZWQubGVuZ3RoO1xuICAgIHF1ZXVlZEJ5dGVzICs9IGVuY29kZWQubGVuZ3RoO1xuICAgIGluRmxpZ2h0ICs9IDE7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHdyaXRlQXQoZmQsIGVuY29kZWQsIGF0LCAoZXJyb3IsIHdyb3RlKSA9PiB7XG4gICAgICAgIGluRmxpZ2h0IC09IDE7XG4gICAgICAgIHF1ZXVlZEJ5dGVzIC09IGVuY29kZWQubGVuZ3RoO1xuICAgICAgICB3cml0dGVuICs9IHdyb3RlO1xuICAgICAgICAvLyBBIGxpbmUgY3V0IHNob3J0IGxlYXZlcyBhIGhvbGUgdXAgdG8gdGhlIG5leHQgZW50cnkncyBvZmZzZXQ6IHRoZSByZWFkZXIgc3BsaXRzIGF0IGl0IChOVUwpLCBzbyBhIHRvcm5cbiAgICAgICAgLy8gbGluZSBuZXZlciBzd2FsbG93cyB0aGUgZW50cnkgYWZ0ZXIgaXQuXG4gICAgICAgIGlmIChlcnJvcikgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgZWxzZSByZXNvbHZlKCk7XG4gICAgICAgIHNldHRsZURyYWluZWQoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuXG4gIHJldHVybiB7XG4gICAgcGF0aDogYWJzb2x1dGUsXG4gICAgZ2V0IGJ5dGVzKCkge1xuICAgICAgcmV0dXJuIHdyaXR0ZW47XG4gICAgfSxcbiAgICBnZXQgcXVldWVkQnl0ZXMoKSB7XG4gICAgICByZXR1cm4gcXVldWVkQnl0ZXM7XG4gICAgfSxcbiAgICBnZXQgZnVsbCgpIHtcbiAgICAgIHJldHVybiBmdWxsO1xuICAgIH0sXG4gICAgb3BlbmVkOiAoeyBhZGRyZXNzLCBhdCwgaW5pdGlhbFN0YXRlLCBtZXRhIH0pID0+XG4gICAgICBlbnF1ZXVlKHsga2luZDogJ29wZW5lZCcsIGFkZHJlc3MsIGF0LCBpbml0aWFsU3RhdGUsIC4uLihtZXRhID09PSB1bmRlZmluZWQgPyB7fSA6IHsgbWV0YSB9KSB9KSxcbiAgICBjb21taXQ6ICh7IGFkZHJlc3MsIGF0LCBidW5kbGUgfSkgPT4gZW5xdWV1ZSh7IGtpbmQ6ICdjb21taXQnLCBhZGRyZXNzLCBhdCwgYnVuZGxlIH0pLFxuICAgIG5vdGU6ICh7IGFkZHJlc3MsIGF0LCBraW5kLCBkYXRhIH0pID0+IGVucXVldWUoeyBraW5kOiAnbm90ZScsIGFkZHJlc3MsIGF0LCBub3RlOiBraW5kLCBkYXRhIH0pLFxuICAgIGNsb3NlZDogKHsgYWRkcmVzcywgYXQsIG91dGNvbWUsIGNvbW1pdHMsIG1ldGEgfSkgPT5cbiAgICAgIGVucXVldWUoeyBraW5kOiAnY2xvc2VkJywgYWRkcmVzcywgYXQsIG91dGNvbWUsIGNvbW1pdHMsIC4uLihtZXRhID09PSB1bmRlZmluZWQgPyB7fSA6IHsgbWV0YSB9KSB9KSxcbiAgICBmbHVzaDogKCkgPT4ge1xuICAgICAgaWYgKGNsb3NpbmcpIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYGZpbGVTaW5rOiAke2Fic29sdXRlfSBpcyBjbG9zZWRgKSk7XG4gICAgICBjb25zdCB3b3JrID0gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBkcmFpbmVkLnB1c2goKCkgPT4ge1xuICAgICAgICAgIHN5bmNpbmcgKz0gMTtcbiAgICAgICAgICBmc3luYyhmZCwgKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgc3luY2luZyAtPSAxO1xuICAgICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICByZWxlYXNlSWZJZGxlKCk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEFub3RoZXIgd3JpdGVyIChhbm90aGVyIHByb2Nlc3Mgb24gdGhlIHNhbWUgcGF0aCkgZ3JldyB0aGUgZmlsZSBwYXN0IHdoYXQgdGhpcyBzaW5rIHBsYWNlZDogaXRzXG4gICAgICAgICAgICAvLyBlbnRyaWVzIGFuZCBvdXJzIG92ZXJsYXAuIFNhaWQsIG5ldmVyIHNpbGVudC5cbiAgICAgICAgICAgIGZzdGF0KGZkLCAoc3RhdEVycm9yLCBzdGF0KSA9PiB7XG4gICAgICAgICAgICAgIHN5bmNpbmcgLT0gMTtcbiAgICAgICAgICAgICAgaWYgKHN0YXRFcnJvcikgcmVqZWN0KHN0YXRFcnJvcik7XG4gICAgICAgICAgICAgIGVsc2UgaWYgKHN0YXQuc2l6ZSA+IG5leHQpIHtcbiAgICAgICAgICAgICAgICByZWplY3QobmV3IEVycm9yKGBmaWxlU2luazogJHthYnNvbHV0ZX0gd2FzIHdyaXR0ZW4gYnkgYW5vdGhlciB3cml0ZXIgKG9uZSBzaW5rIHBlciBmaWxlKWApKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgcmVsZWFzZUlmSWRsZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBzZXR0bGVEcmFpbmVkKCk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB3aXRoVGltZW91dChcbiAgICAgICAgd29yayxcbiAgICAgICAgZmx1c2hUaW1lb3V0TXMsXG4gICAgICAgIGBmaWxlU2luazogZmx1c2goKSBvZiAke2Fic29sdXRlfSBkaWQgbm90IGZpbmlzaCBpbiAke2ZsdXNoVGltZW91dE1zfW1zYCxcbiAgICAgICk7XG4gICAgfSxcbiAgICBjbG9zZTogKCkgPT4ge1xuICAgICAgaWYgKCFjbG9zaW5nKSB7XG4gICAgICAgIGNsb3NpbmcgPSB0cnVlO1xuICAgICAgICByZWxlYXNlSWZJZGxlKCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gd2hlblJlbGVhc2VkO1xuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogRmlsZXMgYSBzaW5rIG9mIHRoaXMgcHJvY2VzcyBoYXMgb3BlbiwgYnkgZGV2aWNlIGFuZCBpbm9kZSDigJQgb25lIHdyaXRlciBwZXIgZmlsZS4gS2VwdCBvbiB0aGUgZ2xvYmFsIG9iamVjdCwgc29cbiAqIHRoZSBwYWNrYWdlJ3MgQ29tbW9uSlMgYW5kIEVTTSBidWlsZHMgKHR3byBtb2R1bGUgaW5zdGFuY2VzIGluIG9uZSBwcm9jZXNzKSBzaGFyZSBpdC5cbiAqL1xuY29uc3QgT1BFTl9GSUxFUzogU2V0PHN0cmluZz4gPSAoKGdsb2JhbFRoaXMgYXMgUmVjb3JkPHN5bWJvbCwgdW5rbm93bj4pW1N5bWJvbC5mb3IoJ2Zvb3RwcmludGpzLmZpbGVTaW5rLm9wZW4nKV0gPz89XG4gIG5ldyBTZXQ8c3RyaW5nPigpKSBhcyBTZXQ8c3RyaW5nPjtcblxuZnVuY3Rpb24gZmlsZUZ1bGwocGF0aDogc3RyaW5nLCBtYXhCeXRlczogbnVtYmVyLCBraW5kOiBzdHJpbmcpOiBSYW5nZUVycm9yIHtcbiAgcmV0dXJuIG5ldyBSYW5nZUVycm9yKGBmaWxlU2luazogJHtwYXRofSBpcyBmdWxsIChtYXhCeXRlcyAke21heEJ5dGVzfSk7IHRoaXMgJHtraW5kfSBlbnRyeSB3YXMgbm90IHdyaXR0ZW5gKTtcbn1cblxuZnVuY3Rpb24gcXVldWVGdWxsKHBhdGg6IHN0cmluZywgcXVldWVkOiBudW1iZXIsIG1heFF1ZXVlZEJ5dGVzOiBudW1iZXIsIGtpbmQ6IHN0cmluZyk6IFJhbmdlRXJyb3Ige1xuICByZXR1cm4gbmV3IFJhbmdlRXJyb3IoXG4gICAgYGZpbGVTaW5rOiAke3BhdGh9IGhhcyAke3F1ZXVlZH0gYnl0ZXMgd2FpdGluZyAobWF4UXVldWVkQnl0ZXMgJHttYXhRdWV1ZWRCeXRlc30pOyB0aGlzICR7a2luZH0gZW50cnkgd2FzIGRyb3BwZWRgLFxuICApO1xufVxuXG4vKiogQSBib3VuZCByZWFkIG9mZiB0aGUgb3B0aW9uczogYWJzZW50IOKGkiB0aGUgZGVmYXVsdDsgZWxzZSBhIHdob2xlIG51bWJlciDiiaUgYG1pbmAsIG9yIGEgUmFuZ2VFcnJvciBuYW1pbmcgaXQuICovXG5mdW5jdGlvbiBib3VuZChuYW1lOiBzdHJpbmcsIHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGZhbGxiYWNrOiBudW1iZXIsIG1pbjogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybiBmYWxsYmFjaztcbiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcih2YWx1ZSkgfHwgdmFsdWUgPCBtaW4pIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihgZmlsZVNpbms6ICR7bmFtZX0gbXVzdCBiZSBhIHdob2xlIG51bWJlciwgYXQgbGVhc3QgJHttaW59YCk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG5mdW5jdGlvbiB0b29MYXJnZShwYXRoOiBzdHJpbmcsIGtpbmQ6IHN0cmluZywgbWF4RW50cnlCeXRlczogbnVtYmVyKTogUmFuZ2VFcnJvciB7XG4gIHJldHVybiBuZXcgUmFuZ2VFcnJvcihcbiAgICBgZmlsZVNpbms6IGEgJHtraW5kfSBlbnRyeSBsYXJnZXIgdGhhbiBtYXhFbnRyeUJ5dGVzICgke21heEVudHJ5Qnl0ZXN9KSB3YXMgbm90IHdyaXR0ZW4gdG8gJHtwYXRofWAsXG4gICk7XG59XG5cbi8qKiBXcml0ZSBhbGwgb2YgYGJ1ZmZlcmAgYXQgYHBvc2l0aW9uYCAoYXN5bmNocm9ub3VzbHksIGFzIG1hbnkgd3JpdGVzIGFzIGl0IHRha2VzKTsgYHdyb3RlYCBpcyBob3cgbXVjaCB3ZW50IG91dC4gKi9cbmZ1bmN0aW9uIHdyaXRlQXQoXG4gIGZkOiBudW1iZXIsXG4gIGJ1ZmZlcjogVWludDhBcnJheSxcbiAgcG9zaXRpb246IG51bWJlcixcbiAgZG9uZTogKGVycm9yOiBFcnJvciB8IG51bGwsIHdyb3RlOiBudW1iZXIpID0+IHZvaWQsXG4pOiB2b2lkIHtcbiAgY29uc3Qgc3RlcCA9IChvZmZzZXQ6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgIHdyaXRlKGZkLCBidWZmZXIsIG9mZnNldCwgYnVmZmVyLmxlbmd0aCAtIG9mZnNldCwgcG9zaXRpb24gKyBvZmZzZXQsIChlcnJvciwgbikgPT4ge1xuICAgICAgaWYgKGVycm9yKSBkb25lKGVycm9yLCBvZmZzZXQpO1xuICAgICAgZWxzZSBpZiAobiA9PT0gMCkgZG9uZShuZXcgRXJyb3IoJ2ZpbGVTaW5rOiB0aGUgZGlzayB0b29rIG5vIGJ5dGVzJyksIG9mZnNldCk7XG4gICAgICBlbHNlIGlmIChvZmZzZXQgKyBuIDwgYnVmZmVyLmxlbmd0aCkgc3RlcChvZmZzZXQgKyBuKTtcbiAgICAgIGVsc2UgZG9uZShudWxsLCBidWZmZXIubGVuZ3RoKTtcbiAgICB9KTtcbiAgfTtcbiAgc3RlcCgwKTtcbn1cblxuLyoqIGB3b3JrYCwgb3IgYSByZWplY3Rpb24gbmFtaW5nIHRoZSBib3VuZCBvbmNlIGBtc2AgcGFzc2VkIOKAlCB0aGUgd29yayBnb2VzIG9uLCBub2JvZHkgd2FpdHMgZm9yIGl0LiAqL1xuZnVuY3Rpb24gd2l0aFRpbWVvdXQod29yazogUHJvbWlzZTx2b2lkPiwgbXM6IG51bWJlciwgbWVzc2FnZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHJlamVjdChuZXcgRXJyb3IobWVzc2FnZSkpLCBtcyk7XG4gICAgLy8gQSB0aW1lciB0aGF0IG9ubHkgYm91bmRzIGEgd2FpdCBuZXZlciBrZWVwcyB0aGUgcHJvY2VzcyBhbGl2ZSBvbiBpdHMgb3duLlxuICAgICh0aW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgUHJvbWlzZS5wcm90b3R5cGUudGhlbi5jYWxsKFxuICAgICAgd29yayxcbiAgICAgICgpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSxcbiAgICAgIChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSxcbiAgICApO1xuICB9KTtcbn1cblxuLyoqXG4gKiBSZWZ1c2UgYSBmaWxlIHNvbWVvbmUgZWxzZSBjb3VsZCByZWFkIG9yIHJld3JpdGUgYmVoaW5kIHRoZSBzaW5rOiBhIGhhcmQgbGluayAoYW5vdGhlciBuYW1lIGZvciB0aGUgc2FtZSBieXRlcyDigJRcbiAqIHRoZSBzaW5rIHdvdWxkIGFwcGVuZCBpbnRvIGl0KSwgYSBmaWxlIG93bmVkIGJ5IGFub3RoZXIgdXNlciwgb3Igb25lIG90aGVycyBtYXkgd3JpdGUuIEEgZmlsZSB0aGUgc2luayBjcmVhdGVzIGlzXG4gKiBgMG82MDBgIGFuZCBwYXNzZXM7IGEgcHJlLWV4aXN0aW5nIG9uZSBtdXN0IGFscmVhZHkgYmUgcHJpdmF0ZSB0byB0aGUgd3JpdGVyLiAoTm90IG9uIFdpbmRvd3MsIHdob3NlIG1vZGVzIGFuZFxuICogb3duZXJzIGRvIG5vdCBtYXA6IHRoZXJlIGBPX05PRk9MTE9XYCBpcyBhYnNlbnQgdG9vIOKAlCB0aGUgZ3VpZGUgbmFtZXMgYm90aC4pXG4gKi9cbmZ1bmN0aW9uIHJlZnVzZUZvcmVpZ24ocGF0aDogc3RyaW5nLCBzdGF0OiB7IHJlYWRvbmx5IG5saW5rOiBudW1iZXI7IHJlYWRvbmx5IHVpZDogbnVtYmVyOyByZWFkb25seSBtb2RlOiBudW1iZXIgfSkge1xuICBpZiAoc3RhdC5ubGluayA+IDEpIHRocm93IG5ldyBUeXBlRXJyb3IoYGZpbGVTaW5rOiAke3BhdGh9IGhhcyBvdGhlciBoYXJkIGxpbmtzIOKAlCByZWZ1c2luZyB0byB3cml0ZSB0aHJvdWdoIG9uZWApO1xuICBjb25zdCB1aWQgPSB0eXBlb2YgZ2V0dWlkID09PSAnZnVuY3Rpb24nID8gZ2V0dWlkKCkgOiB1bmRlZmluZWQ7XG4gIGlmICh1aWQgIT09IHVuZGVmaW5lZCAmJiBzdGF0LnVpZCAhPT0gdWlkKSB0aHJvdyBuZXcgVHlwZUVycm9yKGBmaWxlU2luazogJHtwYXRofSBiZWxvbmdzIHRvIGFub3RoZXIgdXNlcmApO1xuICBpZiAodWlkICE9PSB1bmRlZmluZWQgJiYgKHN0YXQubW9kZSAmIDBvMDIyKSAhPT0gMCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYGZpbGVTaW5rOiAke3BhdGh9IGlzIHdyaXRhYmxlIGJ5IG90aGVycyDigJQgbWFrZSBpdCAwbzYwMCAob3IgcmVtb3ZlIGl0KSBmaXJzdGApO1xuICB9XG59XG5cbi8qKiBXaGV0aGVyIHRoZSBmaWxlJ3MgbGFzdCBieXRlIGlzIGEgbmV3bGluZSDigJQgcmVhZCBvbmNlLCB3aGVuIHRoZSBzaW5rIG9wZW5zIGFuIGV4aXN0aW5nIGZpbGUuICovXG5mdW5jdGlvbiBlbmRzV2l0aE5ld2xpbmUoZmQ6IG51bWJlciwgc2l6ZTogbnVtYmVyKTogYm9vbGVhbiB7XG4gIGNvbnN0IGxhc3QgPSBuZXcgVWludDhBcnJheSgxKTtcbiAgcmV0dXJuIHJlYWRTeW5jKGZkLCBsYXN0LCAwLCAxLCBzaXplIC0gMSkgPT09IDEgJiYgbGFzdFswXSA9PT0gMHgwYTtcbn1cblxuLyoqIEEgcmVjb3JkIGZpbGUgcmVhZCBiYWNrOiBldmVyeSBwYXJzZWQgbGluZSwgYW5kIGV2ZXJ5IGxpbmUgdGhhdCBjb3VsZCBub3QgYmUuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlY29yZEZpbGUge1xuICAvKiogVGhlIHBhcnNlZCBlbnRyaWVzLCBpbiBmaWxlIG9yZGVyIOKAlCB1bnRydXN0ZWQgaW5wdXQgZm9yIGByZWFkU3RvcmVkUmVjb3JkYCAoYGZvb3R0cmFjZWApLiAqL1xuICByZWFkb25seSBlbnRyaWVzOiByZWFkb25seSB1bmtub3duW107XG4gIC8qKiBFYWNoIGxpbmUgdGhhdCBpcyBub3QgSlNPTiAoYSB0b3JuIGxhc3QgbGluZSwgYSBjb3JydXB0IG9uZSksIGJ5IGl0cyAxLWJhc2VkIG51bWJlci4gQmxhbmsgbGluZXMgYXJlIHNraXBwZWQuICovXG4gIHJlYWRvbmx5IHVucmVhZGFibGU6IHJlYWRvbmx5IHsgcmVhZG9ubHkgbGluZTogbnVtYmVyOyByZWFkb25seSByZWFzb246IHN0cmluZyB9W107XG59XG5cbi8qKlxuICogUmVhZCBhIHJlY29yZCBmaWxlIGJhY2ssIGxpbmUgYnkgbGluZSDigJQgdGhlIGVudHJpZXMgZm9yIGByZWFkU3RvcmVkUmVjb3JkYCwgYW5kIGV2ZXJ5IGxpbmUgdGhhdCBjb3VsZCBub3QgYmVcbiAqIHJlYWQsIGJ5IG51bWJlciwgbmV2ZXIgYSBmYWlsZWQgcmVhZC4gQSBzdG9yZWQga2V5IG5hbWVkIGBfX3Byb3RvX19gIHN0YXlzIGRhdGEgKGBKU09OLnBhcnNlYCBtYWtlcyBpdCBhbiBvd25cbiAqIHByb3BlcnR5KS4gVGhlIGZpbGUgaXMgdW50cnVzdGVkOiBhIGZpbGUgbGFyZ2VyIHRoYW4gYG1heEJ5dGVzYCAoZGVmYXVsdCAyNTYgTWlCKSBpcyByZWZ1c2VkIGJlZm9yZSBpdCBpcyByZWFkLlxuICpcbiAqIEB0aHJvd3MgUmFuZ2VFcnJvciB3aGVuIHRoZSBmaWxlIGlzIGxhcmdlciB0aGFuIGBtYXhCeXRlc2A7IHRoZSBvcGVyYXRpbmcgc3lzdGVtJ3MgZXJyb3Igd2hlbiBpdCBjYW5ub3QgYmUgcmVhZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRSZWNvcmRGaWxlKHBhdGg6IHN0cmluZywgb3B0aW9ucz86IHsgcmVhZG9ubHkgbWF4Qnl0ZXM/OiBudW1iZXIgfSk6IFJlY29yZEZpbGUge1xuICBpZiAodHlwZW9mIHBhdGggIT09ICdzdHJpbmcnIHx8IHBhdGggPT09ICcnKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWFkUmVjb3JkRmlsZTogcGF0aCBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZycpO1xuICBjb25zdCBtYXhCeXRlcyA9IGJvdW5kKCdtYXhCeXRlcycsIG9wdGlvbnM/Lm1heEJ5dGVzLCBERUZBVUxUX1JFQURfTUFYX0JZVEVTLCAxKTtcbiAgLy8gT25lIGRlc2NyaXB0b3IgZm9yIHRoZSBjaGVjayBBTkQgdGhlIHJlYWQgKGEgZmlsZSB0aGF0IGdyb3dzIGJldHdlZW4gdGhlbSBpcyBzdGlsbCBib3VuZGVkKTsgYSByZWd1bGFyIGZpbGVcbiAgLy8gb25seSAoYSBGSUZPIHdvdWxkIGJsb2NrLCBhIGRldmljZSBuZXZlciBlbmQpOyBhdCBtb3N0IGBtYXhCeXRlc2AgcmVhZC5cbiAgLy8gT19OT05CTE9DSzogYSBGSUZPIGF0IHRoZSBwYXRoIG11c3Qgbm90IGJsb2NrIHRoZSBvcGVuIGJlZm9yZSB0aGUgcmVndWxhci1maWxlIGNoZWNrIHJlZnVzZXMgaXQuXG4gIGNvbnN0IGZkID0gb3BlblN5bmMocGF0aCwgY29uc3RhbnRzLk9fUkRPTkxZIHwgKGNvbnN0YW50cy5PX05PRk9MTE9XID8/IDApIHwgKGNvbnN0YW50cy5PX05PTkJMT0NLID8/IDApKTtcbiAgbGV0IHJhdzogVWludDhBcnJheTtcbiAgdHJ5IHtcbiAgICBjb25zdCBzdGF0ID0gZnN0YXRTeW5jKGZkKTtcbiAgICBpZiAoIXN0YXQuaXNGaWxlKCkpIHRocm93IG5ldyBUeXBlRXJyb3IoYHJlYWRSZWNvcmRGaWxlOiAke3BhdGh9IGlzIG5vdCBhIHJlZ3VsYXIgZmlsZWApO1xuICAgIGlmIChzdGF0LnNpemUgPiBtYXhCeXRlcykge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYHJlYWRSZWNvcmRGaWxlOiAke3BhdGh9IGhvbGRzICR7c3RhdC5zaXplfSBieXRlcywgcGFzdCB0aGUgbGltaXQgb2YgJHttYXhCeXRlc31gKTtcbiAgICB9XG4gICAgY29uc3QgYnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkoTWF0aC5taW4oc3RhdC5zaXplLCBtYXhCeXRlcykgKyAxKTtcbiAgICBsZXQgcmVhZCA9IDA7XG4gICAgZm9yICg7Oykge1xuICAgICAgY29uc3QgbiA9IHJlYWRTeW5jKGZkLCBidWZmZXIsIHJlYWQsIGJ1ZmZlci5sZW5ndGggLSByZWFkLCByZWFkKTtcbiAgICAgIGlmIChuID09PSAwKSBicmVhaztcbiAgICAgIHJlYWQgKz0gbjtcbiAgICAgIGlmIChyZWFkID09PSBidWZmZXIubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKGByZWFkUmVjb3JkRmlsZTogJHtwYXRofSBncmV3IHBhc3QgdGhlIGxpbWl0IG9mICR7bWF4Qnl0ZXN9IGJ5dGVzIHdoaWxlIGJlaW5nIHJlYWRgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmF3ID0gYnVmZmVyLnN1YmFycmF5KDAsIHJlYWQpO1xuICB9IGZpbmFsbHkge1xuICAgIGNsb3NlU3luYyhmZCk7XG4gIH1cbiAgY29uc3QgdGV4dCA9IG5ldyBUZXh0RGVjb2RlcigndXRmLTgnKS5kZWNvZGUocmF3KTtcbiAgY29uc3QgZW50cmllczogdW5rbm93bltdID0gW107XG4gIGNvbnN0IHVucmVhZGFibGU6IHsgbGluZTogbnVtYmVyOyByZWFzb246IHN0cmluZyB9W10gPSBbXTtcbiAgY29uc3QgbGluZXMgPSB0ZXh0LnNwbGl0KCdcXG4nKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgIC8vIEEgcnVuIG9mIE5VTCBieXRlcyBpcyBhIGhvbGUgYSBjdXQtc2hvcnQgd3JpdGUgbGVmdCBiZWZvcmUgdGhlIG5leHQgZW50cnkncyBvZmZzZXQ6IGl0IGVuZHMgdGhlIHRvcm4gcGFydCxcbiAgICAvLyBzbyB0aGUgZW50cnkgYWZ0ZXIgaXQgcmVhZHMgb24gaXRzIG93biAodGhlIHNhbWUgbGluZSBudW1iZXIgbmFtZXMgYm90aCBwaWVjZXMpLlxuICAgIGNvbnN0IGxpbmUgPSBsaW5lc1tpXTtcbiAgICAvLyBBIGhvbGUgaXMgcmVwb3J0ZWQsIG5ldmVyIHNraXBwZWQ6IGJ5dGVzIHRoYXQgbmV2ZXIgcmVhY2hlZCB0aGUgZGlzayBtYXkgYmUgYSB3aG9sZSBlbnRyeSBsb3N0IG1pZC1maWxlLlxuICAgIGlmIChsaW5lLmluY2x1ZGVzKCdcXDAnKSkgdW5yZWFkYWJsZS5wdXNoKHsgbGluZTogaSArIDEsIHJlYXNvbjogJ2EgaG9sZSDigJQgYnl0ZXMgdGhhdCBuZXZlciByZWFjaGVkIHRoZSBkaXNrJyB9KTtcbiAgICBmb3IgKGNvbnN0IHBpZWNlIG9mIGxpbmUuc3BsaXQoL1xcMCsvKSkge1xuICAgICAgaWYgKHBpZWNlLnRyaW0oKSA9PT0gJycpIGNvbnRpbnVlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgZW50cmllcy5wdXNoKEpTT04ucGFyc2UocGllY2UpKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICB1bnJlYWRhYmxlLnB1c2goeyBsaW5lOiBpICsgMSwgcmVhc29uOiAnbm90IEpTT04g4oCUIGEgdG9ybiBvciBjb3JydXB0IGxpbmUnIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4geyBlbnRyaWVzLCB1bnJlYWRhYmxlIH07XG59XG4iXX0=