nastech-tui 0.0.1

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 (424) hide show
  1. package/.prettierrc +11 -0
  2. package/README.md +346 -0
  3. package/eslint.config.mjs +111 -0
  4. package/package.json +51 -0
  5. package/packages/nastech-ink/ambient.d.ts +83 -0
  6. package/packages/nastech-ink/index.d.ts +40 -0
  7. package/packages/nastech-ink/index.js +1 -0
  8. package/packages/nastech-ink/nastech-ink/ambient.d.ts +83 -0
  9. package/packages/nastech-ink/nastech-ink/index.d.ts +40 -0
  10. package/packages/nastech-ink/nastech-ink/index.js +1 -0
  11. package/packages/nastech-ink/nastech-ink/package.json +54 -0
  12. package/packages/nastech-ink/nastech-ink/src/bootstrap/state.ts +9 -0
  13. package/packages/nastech-ink/nastech-ink/src/entry-exports.ts +32 -0
  14. package/packages/nastech-ink/nastech-ink/src/hooks/use-stderr.ts +15 -0
  15. package/packages/nastech-ink/nastech-ink/src/hooks/use-stdout.ts +15 -0
  16. package/packages/nastech-ink/nastech-ink/src/ink/Ansi.tsx +435 -0
  17. package/packages/nastech-ink/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  18. package/packages/nastech-ink/nastech-ink/src/ink/bidi.ts +145 -0
  19. package/packages/nastech-ink/nastech-ink/src/ink/cache-eviction.ts +45 -0
  20. package/packages/nastech-ink/nastech-ink/src/ink/clearTerminal.ts +68 -0
  21. package/packages/nastech-ink/nastech-ink/src/ink/colorize.test.ts +60 -0
  22. package/packages/nastech-ink/nastech-ink/src/ink/colorize.ts +277 -0
  23. package/packages/nastech-ink/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  24. package/packages/nastech-ink/nastech-ink/src/ink/components/App.tsx +830 -0
  25. package/packages/nastech-ink/nastech-ink/src/ink/components/AppContext.ts +20 -0
  26. package/packages/nastech-ink/nastech-ink/src/ink/components/Box.tsx +294 -0
  27. package/packages/nastech-ink/nastech-ink/src/ink/components/Button.tsx +236 -0
  28. package/packages/nastech-ink/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  29. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  30. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  31. package/packages/nastech-ink/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  32. package/packages/nastech-ink/nastech-ink/src/ink/components/Link.tsx +38 -0
  33. package/packages/nastech-ink/nastech-ink/src/ink/components/Newline.tsx +43 -0
  34. package/packages/nastech-ink/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  35. package/packages/nastech-ink/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  36. package/packages/nastech-ink/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  37. package/packages/nastech-ink/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  38. package/packages/nastech-ink/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  39. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  40. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  41. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.test.ts +38 -0
  42. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.tsx +336 -0
  43. package/packages/nastech-ink/nastech-ink/src/ink/constants.ts +6 -0
  44. package/packages/nastech-ink/nastech-ink/src/ink/cursor.ts +5 -0
  45. package/packages/nastech-ink/nastech-ink/src/ink/devtools.ts +2 -0
  46. package/packages/nastech-ink/nastech-ink/src/ink/dom.ts +495 -0
  47. package/packages/nastech-ink/nastech-ink/src/ink/events/click-event.ts +38 -0
  48. package/packages/nastech-ink/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  49. package/packages/nastech-ink/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  50. package/packages/nastech-ink/nastech-ink/src/ink/events/emitter.ts +40 -0
  51. package/packages/nastech-ink/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  52. package/packages/nastech-ink/nastech-ink/src/ink/events/event.ts +11 -0
  53. package/packages/nastech-ink/nastech-ink/src/ink/events/focus-event.ts +18 -0
  54. package/packages/nastech-ink/nastech-ink/src/ink/events/input-event.ts +176 -0
  55. package/packages/nastech-ink/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  56. package/packages/nastech-ink/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  57. package/packages/nastech-ink/nastech-ink/src/ink/events/paste-event.ts +10 -0
  58. package/packages/nastech-ink/nastech-ink/src/ink/events/resize-event.ts +12 -0
  59. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  60. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  61. package/packages/nastech-ink/nastech-ink/src/ink/focus.ts +219 -0
  62. package/packages/nastech-ink/nastech-ink/src/ink/frame.ts +124 -0
  63. package/packages/nastech-ink/nastech-ink/src/ink/get-max-width.ts +27 -0
  64. package/packages/nastech-ink/nastech-ink/src/ink/global.d.ts +1 -0
  65. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.test.ts +38 -0
  66. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.ts +224 -0
  67. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  68. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  69. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  70. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  71. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  72. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  73. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  74. package/packages/nastech-ink/package.json +57 -0
  75. package/packages/nastech-ink/src/bootstrap/state.ts +9 -0
  76. package/packages/nastech-ink/src/entry-exports.ts +32 -0
  77. package/packages/nastech-ink/src/hooks/use-stderr.ts +15 -0
  78. package/packages/nastech-ink/src/hooks/use-stdout.ts +15 -0
  79. package/packages/nastech-ink/src/ink/Ansi.tsx +435 -0
  80. package/packages/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  81. package/packages/nastech-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
  82. package/packages/nastech-ink/src/ink/bidi.ts +145 -0
  83. package/packages/nastech-ink/src/ink/cache-eviction.ts +45 -0
  84. package/packages/nastech-ink/src/ink/clearTerminal.ts +68 -0
  85. package/packages/nastech-ink/src/ink/colorize.test.ts +60 -0
  86. package/packages/nastech-ink/src/ink/colorize.ts +277 -0
  87. package/packages/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  88. package/packages/nastech-ink/src/ink/components/App.tsx +855 -0
  89. package/packages/nastech-ink/src/ink/components/AppContext.ts +20 -0
  90. package/packages/nastech-ink/src/ink/components/Box.tsx +294 -0
  91. package/packages/nastech-ink/src/ink/components/Button.tsx +236 -0
  92. package/packages/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  93. package/packages/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  94. package/packages/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  95. package/packages/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  96. package/packages/nastech-ink/src/ink/components/Link.tsx +38 -0
  97. package/packages/nastech-ink/src/ink/components/Newline.tsx +43 -0
  98. package/packages/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  99. package/packages/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  100. package/packages/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  101. package/packages/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  102. package/packages/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  103. package/packages/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  104. package/packages/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  105. package/packages/nastech-ink/src/ink/components/Text.test.ts +38 -0
  106. package/packages/nastech-ink/src/ink/components/Text.tsx +336 -0
  107. package/packages/nastech-ink/src/ink/constants.ts +6 -0
  108. package/packages/nastech-ink/src/ink/cursor.ts +5 -0
  109. package/packages/nastech-ink/src/ink/devtools.ts +2 -0
  110. package/packages/nastech-ink/src/ink/dom.ts +495 -0
  111. package/packages/nastech-ink/src/ink/events/click-event.ts +38 -0
  112. package/packages/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  113. package/packages/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  114. package/packages/nastech-ink/src/ink/events/emitter.ts +40 -0
  115. package/packages/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  116. package/packages/nastech-ink/src/ink/events/event.ts +11 -0
  117. package/packages/nastech-ink/src/ink/events/focus-event.ts +18 -0
  118. package/packages/nastech-ink/src/ink/events/input-event.ts +176 -0
  119. package/packages/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  120. package/packages/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  121. package/packages/nastech-ink/src/ink/events/paste-event.ts +10 -0
  122. package/packages/nastech-ink/src/ink/events/resize-event.ts +12 -0
  123. package/packages/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  124. package/packages/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  125. package/packages/nastech-ink/src/ink/focus.ts +219 -0
  126. package/packages/nastech-ink/src/ink/frame.ts +124 -0
  127. package/packages/nastech-ink/src/ink/get-max-width.ts +27 -0
  128. package/packages/nastech-ink/src/ink/global.d.ts +1 -0
  129. package/packages/nastech-ink/src/ink/hit-test.test.ts +38 -0
  130. package/packages/nastech-ink/src/ink/hit-test.ts +224 -0
  131. package/packages/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  132. package/packages/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  133. package/packages/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  134. package/packages/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  135. package/packages/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  136. package/packages/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  137. package/packages/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  138. package/packages/nastech-ink/src/ink/hooks/use-search-highlight.ts +56 -0
  139. package/packages/nastech-ink/src/ink/hooks/use-selection.ts +101 -0
  140. package/packages/nastech-ink/src/ink/hooks/use-stdin.ts +9 -0
  141. package/packages/nastech-ink/src/ink/hooks/use-tab-status.ts +71 -0
  142. package/packages/nastech-ink/src/ink/hooks/use-terminal-focus.ts +18 -0
  143. package/packages/nastech-ink/src/ink/hooks/use-terminal-title.ts +34 -0
  144. package/packages/nastech-ink/src/ink/hooks/use-terminal-viewport.ts +100 -0
  145. package/packages/nastech-ink/src/ink/hyperlinkHover.ts +52 -0
  146. package/packages/nastech-ink/src/ink/ink-cursor-advance.test.ts +234 -0
  147. package/packages/nastech-ink/src/ink/ink-resize.test.ts +50 -0
  148. package/packages/nastech-ink/src/ink/ink.tsx +2705 -0
  149. package/packages/nastech-ink/src/ink/instances.ts +10 -0
  150. package/packages/nastech-ink/src/ink/layout/engine.ts +6 -0
  151. package/packages/nastech-ink/src/ink/layout/geometry.ts +98 -0
  152. package/packages/nastech-ink/src/ink/layout/node.ts +145 -0
  153. package/packages/nastech-ink/src/ink/layout/yoga.ts +313 -0
  154. package/packages/nastech-ink/src/ink/line-width-cache.ts +38 -0
  155. package/packages/nastech-ink/src/ink/log-update.test.ts +223 -0
  156. package/packages/nastech-ink/src/ink/log-update.ts +752 -0
  157. package/packages/nastech-ink/src/ink/lru.ts +14 -0
  158. package/packages/nastech-ink/src/ink/measure-element.ts +23 -0
  159. package/packages/nastech-ink/src/ink/measure-text.ts +50 -0
  160. package/packages/nastech-ink/src/ink/node-cache.ts +53 -0
  161. package/packages/nastech-ink/src/ink/optimizer.ts +99 -0
  162. package/packages/nastech-ink/src/ink/output.ts +845 -0
  163. package/packages/nastech-ink/src/ink/parse-keypress.test.ts +133 -0
  164. package/packages/nastech-ink/src/ink/parse-keypress.ts +848 -0
  165. package/packages/nastech-ink/src/ink/reconciler.ts +382 -0
  166. package/packages/nastech-ink/src/ink/render-border.ts +206 -0
  167. package/packages/nastech-ink/src/ink/render-node-to-output.ts +1582 -0
  168. package/packages/nastech-ink/src/ink/render-to-screen.ts +236 -0
  169. package/packages/nastech-ink/src/ink/renderer.ts +169 -0
  170. package/packages/nastech-ink/src/ink/root.ts +204 -0
  171. package/packages/nastech-ink/src/ink/screen.ts +1590 -0
  172. package/packages/nastech-ink/src/ink/searchHighlight.ts +91 -0
  173. package/packages/nastech-ink/src/ink/selection.test.ts +82 -0
  174. package/packages/nastech-ink/src/ink/selection.ts +1143 -0
  175. package/packages/nastech-ink/src/ink/squash-text-nodes.ts +74 -0
  176. package/packages/nastech-ink/src/ink/stringWidth.ts +341 -0
  177. package/packages/nastech-ink/src/ink/styles.ts +750 -0
  178. package/packages/nastech-ink/src/ink/supports-hyperlinks.ts +51 -0
  179. package/packages/nastech-ink/src/ink/tabstops.ts +44 -0
  180. package/packages/nastech-ink/src/ink/terminal-focus-state.ts +52 -0
  181. package/packages/nastech-ink/src/ink/terminal-querier.ts +222 -0
  182. package/packages/nastech-ink/src/ink/terminal.test.ts +15 -0
  183. package/packages/nastech-ink/src/ink/terminal.ts +299 -0
  184. package/packages/nastech-ink/src/ink/termio/ansi.ts +75 -0
  185. package/packages/nastech-ink/src/ink/termio/csi.ts +334 -0
  186. package/packages/nastech-ink/src/ink/termio/dec.ts +99 -0
  187. package/packages/nastech-ink/src/ink/termio/esc.ts +69 -0
  188. package/packages/nastech-ink/src/ink/termio/osc.test.ts +191 -0
  189. package/packages/nastech-ink/src/ink/termio/osc.ts +724 -0
  190. package/packages/nastech-ink/src/ink/termio/parser.ts +467 -0
  191. package/packages/nastech-ink/src/ink/termio/sgr.ts +362 -0
  192. package/packages/nastech-ink/src/ink/termio/tokenize.test.ts +185 -0
  193. package/packages/nastech-ink/src/ink/termio/tokenize.ts +350 -0
  194. package/packages/nastech-ink/src/ink/termio/types.ts +230 -0
  195. package/packages/nastech-ink/src/ink/termio.ts +42 -0
  196. package/packages/nastech-ink/src/ink/useTerminalNotification.ts +110 -0
  197. package/packages/nastech-ink/src/ink/warn.ts +15 -0
  198. package/packages/nastech-ink/src/ink/widest-line.ts +22 -0
  199. package/packages/nastech-ink/src/ink/wrap-text.test.ts +17 -0
  200. package/packages/nastech-ink/src/ink/wrap-text.ts +144 -0
  201. package/packages/nastech-ink/src/ink/wrapAnsi.ts +13 -0
  202. package/packages/nastech-ink/src/native-ts/yoga-layout/enums.ts +112 -0
  203. package/packages/nastech-ink/src/native-ts/yoga-layout/index.ts +2326 -0
  204. package/packages/nastech-ink/src/utils/debug.ts +6 -0
  205. package/packages/nastech-ink/src/utils/earlyInput.ts +131 -0
  206. package/packages/nastech-ink/src/utils/env.ts +66 -0
  207. package/packages/nastech-ink/src/utils/envUtils.ts +13 -0
  208. package/packages/nastech-ink/src/utils/execFileNoThrow.test.ts +146 -0
  209. package/packages/nastech-ink/src/utils/execFileNoThrow.ts +115 -0
  210. package/packages/nastech-ink/src/utils/fullscreen.ts +3 -0
  211. package/packages/nastech-ink/src/utils/intl.ts +87 -0
  212. package/packages/nastech-ink/src/utils/log.ts +7 -0
  213. package/packages/nastech-ink/src/utils/semver.ts +57 -0
  214. package/packages/nastech-ink/src/utils/sliceAnsi.ts +106 -0
  215. package/packages/nastech-ink/text-input.d.ts +2 -0
  216. package/packages/nastech-ink/text-input.js +1 -0
  217. package/scripts/build.mjs +61 -0
  218. package/scripts/profile-tui.mjs +121 -0
  219. package/src/__tests__/activeSessionSwitcher.test.ts +157 -0
  220. package/src/__tests__/appChromeStatusRule.test.tsx +84 -0
  221. package/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
  222. package/src/__tests__/approvalAction.test.ts +50 -0
  223. package/src/__tests__/asCommandDispatch.test.ts +27 -0
  224. package/src/__tests__/blockLayout.test.ts +122 -0
  225. package/src/__tests__/clipboard.test.ts +369 -0
  226. package/src/__tests__/constants.test.ts +53 -0
  227. package/src/__tests__/createGatewayEventHandler.test.ts +1091 -0
  228. package/src/__tests__/createSlashHandler.test.ts +822 -0
  229. package/src/__tests__/creditsCommand.test.ts +144 -0
  230. package/src/__tests__/cursorDriftRegression.test.ts +114 -0
  231. package/src/__tests__/details.test.ts +115 -0
  232. package/src/__tests__/emoji.test.ts +64 -0
  233. package/src/__tests__/externalLink.test.ts +144 -0
  234. package/src/__tests__/forceTruecolor.test.ts +191 -0
  235. package/src/__tests__/gatewayClient.test.ts +394 -0
  236. package/src/__tests__/gatewayRecovery.test.ts +47 -0
  237. package/src/__tests__/markdown.test.ts +331 -0
  238. package/src/__tests__/mathUnicode.test.ts +293 -0
  239. package/src/__tests__/memoryMonitor.test.ts +102 -0
  240. package/src/__tests__/messageLine.test.ts +19 -0
  241. package/src/__tests__/messages.test.ts +92 -0
  242. package/src/__tests__/orchestratorPromptSession.test.ts +64 -0
  243. package/src/__tests__/osc52.test.ts +67 -0
  244. package/src/__tests__/parentLog.test.ts +75 -0
  245. package/src/__tests__/paths.test.ts +70 -0
  246. package/src/__tests__/platform.test.ts +556 -0
  247. package/src/__tests__/precisionWheel.test.ts +44 -0
  248. package/src/__tests__/prompt.test.ts +31 -0
  249. package/src/__tests__/providers.test.ts +65 -0
  250. package/src/__tests__/reasoning.test.ts +76 -0
  251. package/src/__tests__/rpc.test.ts +27 -0
  252. package/src/__tests__/scroll.test.ts +99 -0
  253. package/src/__tests__/slashParity.test.ts +123 -0
  254. package/src/__tests__/spawnHistoryStore.test.ts +46 -0
  255. package/src/__tests__/stateIsolation.test.ts +46 -0
  256. package/src/__tests__/statusBarTicker.test.ts +18 -0
  257. package/src/__tests__/statusRule.test.ts +32 -0
  258. package/src/__tests__/streamingMarkdown.test.ts +121 -0
  259. package/src/__tests__/subagentTree.test.ts +407 -0
  260. package/src/__tests__/syntax.test.ts +45 -0
  261. package/src/__tests__/terminalModes.test.ts +39 -0
  262. package/src/__tests__/terminalParity.test.ts +77 -0
  263. package/src/__tests__/terminalSetup.test.ts +386 -0
  264. package/src/__tests__/termux.test.ts +35 -0
  265. package/src/__tests__/termuxComposerLayout.test.ts +40 -0
  266. package/src/__tests__/text.test.ts +233 -0
  267. package/src/__tests__/textInputBurstInput.test.ts +40 -0
  268. package/src/__tests__/textInputCursorSourceOfTruth.test.ts +50 -0
  269. package/src/__tests__/textInputFastEcho.test.ts +200 -0
  270. package/src/__tests__/textInputLineNav.test.ts +55 -0
  271. package/src/__tests__/textInputPassThrough.test.ts +59 -0
  272. package/src/__tests__/textInputRightClick.test.ts +48 -0
  273. package/src/__tests__/textInputWrap.test.ts +151 -0
  274. package/src/__tests__/theme.test.ts +311 -0
  275. package/src/__tests__/turnControllerNotice.test.ts +43 -0
  276. package/src/__tests__/turnStore.test.ts +66 -0
  277. package/src/__tests__/useCompletion.test.ts +35 -0
  278. package/src/__tests__/useComposerState.test.ts +59 -0
  279. package/src/__tests__/useConfigSync.test.ts +460 -0
  280. package/src/__tests__/useInputHandlers.test.ts +77 -0
  281. package/src/__tests__/useQueue.test.ts +28 -0
  282. package/src/__tests__/useSessionLifecycle.test.ts +60 -0
  283. package/src/__tests__/useVirtualHistoryHeights.test.ts +39 -0
  284. package/src/__tests__/viewport.test.ts +58 -0
  285. package/src/__tests__/viewportStore.test.ts +85 -0
  286. package/src/__tests__/virtualHeights.test.ts +96 -0
  287. package/src/__tests__/virtualHistoryClamp.test.ts +19 -0
  288. package/src/__tests__/virtualHistoryOffsetCache.test.ts +282 -0
  289. package/src/__tests__/wheelAccel.test.ts +138 -0
  290. package/src/app/createGatewayEventHandler.ts +833 -0
  291. package/src/app/createSlashHandler.ts +130 -0
  292. package/src/app/delegationStore.ts +77 -0
  293. package/src/app/gatewayContext.tsx +19 -0
  294. package/src/app/gatewayRecovery.ts +35 -0
  295. package/src/app/inputSelectionStore.ts +15 -0
  296. package/src/app/interfaces.ts +394 -0
  297. package/src/app/overlayStore.ts +53 -0
  298. package/src/app/scroll.ts +71 -0
  299. package/src/app/setupHandoff.ts +54 -0
  300. package/src/app/slash/commands/core.ts +648 -0
  301. package/src/app/slash/commands/credits.ts +57 -0
  302. package/src/app/slash/commands/debug.ts +48 -0
  303. package/src/app/slash/commands/ops.ts +717 -0
  304. package/src/app/slash/commands/session.ts +554 -0
  305. package/src/app/slash/commands/setup.ts +20 -0
  306. package/src/app/slash/registry.ts +20 -0
  307. package/src/app/slash/types.ts +21 -0
  308. package/src/app/spawnHistoryStore.ts +159 -0
  309. package/src/app/turnController.ts +866 -0
  310. package/src/app/turnStore.ts +85 -0
  311. package/src/app/uiStore.ts +44 -0
  312. package/src/app/useComposerState.ts +367 -0
  313. package/src/app/useConfigSync.ts +288 -0
  314. package/src/app/useInputHandlers.ts +576 -0
  315. package/src/app/useLongRunToolCharms.ts +69 -0
  316. package/src/app/useMainApp.ts +1039 -0
  317. package/src/app/useSessionLifecycle.ts +366 -0
  318. package/src/app/useSubmission.ts +429 -0
  319. package/src/app.tsx +25 -0
  320. package/src/banner.ts +93 -0
  321. package/src/components/activeSessionSwitcher.tsx +635 -0
  322. package/src/components/agentsOverlay.tsx +1073 -0
  323. package/src/components/appChrome.tsx +554 -0
  324. package/src/components/appLayout.tsx +444 -0
  325. package/src/components/appOverlays.tsx +254 -0
  326. package/src/components/branding.tsx +466 -0
  327. package/src/components/fpsOverlay.tsx +30 -0
  328. package/src/components/helpHint.tsx +73 -0
  329. package/src/components/markdown.tsx +1119 -0
  330. package/src/components/maskedPrompt.tsx +34 -0
  331. package/src/components/messageLine.tsx +237 -0
  332. package/src/components/modelPicker.tsx +527 -0
  333. package/src/components/overlayControls.tsx +50 -0
  334. package/src/components/pluginsHub.tsx +238 -0
  335. package/src/components/prompts.tsx +276 -0
  336. package/src/components/queuedMessages.tsx +64 -0
  337. package/src/components/sessionPicker.tsx +227 -0
  338. package/src/components/skillsHub.tsx +308 -0
  339. package/src/components/streamingAssistant.tsx +110 -0
  340. package/src/components/streamingMarkdown.tsx +174 -0
  341. package/src/components/textInput.tsx +1340 -0
  342. package/src/components/themed.tsx +30 -0
  343. package/src/components/thinking.tsx +1224 -0
  344. package/src/components/todoPanel.tsx +93 -0
  345. package/src/config/env.ts +64 -0
  346. package/src/config/limits.ts +13 -0
  347. package/src/config/timing.ts +6 -0
  348. package/src/content/charms.ts +1 -0
  349. package/src/content/faces.ts +17 -0
  350. package/src/content/fortunes.ts +30 -0
  351. package/src/content/hotkeys.ts +37 -0
  352. package/src/content/placeholders.ts +13 -0
  353. package/src/content/setup.ts +17 -0
  354. package/src/content/verbs.ts +38 -0
  355. package/src/domain/blockLayout.ts +146 -0
  356. package/src/domain/details.ts +76 -0
  357. package/src/domain/messages.ts +91 -0
  358. package/src/domain/paths.ts +16 -0
  359. package/src/domain/providers.ts +11 -0
  360. package/src/domain/roles.ts +9 -0
  361. package/src/domain/slash.ts +10 -0
  362. package/src/domain/usage.ts +3 -0
  363. package/src/domain/viewport.ts +51 -0
  364. package/src/entry.tsx +104 -0
  365. package/src/gatewayClient.ts +730 -0
  366. package/src/gatewayTypes.ts +568 -0
  367. package/src/hooks/useCompletion.ts +112 -0
  368. package/src/hooks/useGitBranch.ts +72 -0
  369. package/src/hooks/useInputHistory.ts +11 -0
  370. package/src/hooks/useQueue.ts +76 -0
  371. package/src/hooks/useVirtualHistory.ts +554 -0
  372. package/src/lib/circularBuffer.ts +48 -0
  373. package/src/lib/clipboard.ts +182 -0
  374. package/src/lib/editor.test.ts +74 -0
  375. package/src/lib/editor.ts +47 -0
  376. package/src/lib/emoji.ts +55 -0
  377. package/src/lib/externalCli.ts +16 -0
  378. package/src/lib/externalLink.ts +435 -0
  379. package/src/lib/forceTruecolor.ts +60 -0
  380. package/src/lib/fpsStore.ts +51 -0
  381. package/src/lib/fuzzy.test.ts +109 -0
  382. package/src/lib/fuzzy.ts +177 -0
  383. package/src/lib/gracefulExit.ts +47 -0
  384. package/src/lib/history.ts +82 -0
  385. package/src/lib/inputMetrics.ts +203 -0
  386. package/src/lib/liveProgress.test.ts +116 -0
  387. package/src/lib/liveProgress.ts +79 -0
  388. package/src/lib/mathUnicode.ts +770 -0
  389. package/src/lib/memory.test.ts +155 -0
  390. package/src/lib/memory.ts +188 -0
  391. package/src/lib/memoryMonitor.ts +109 -0
  392. package/src/lib/messages.test.ts +29 -0
  393. package/src/lib/messages.ts +8 -0
  394. package/src/lib/openExternalUrl.test.ts +217 -0
  395. package/src/lib/openExternalUrl.ts +158 -0
  396. package/src/lib/osc52.ts +73 -0
  397. package/src/lib/parentLog.ts +57 -0
  398. package/src/lib/perfPane.tsx +107 -0
  399. package/src/lib/platform.ts +409 -0
  400. package/src/lib/precisionWheel.ts +48 -0
  401. package/src/lib/prompt.ts +35 -0
  402. package/src/lib/reasoning.ts +55 -0
  403. package/src/lib/rpc.ts +41 -0
  404. package/src/lib/subagentTree.ts +355 -0
  405. package/src/lib/syntax.ts +117 -0
  406. package/src/lib/terminalModes.ts +51 -0
  407. package/src/lib/terminalParity.ts +78 -0
  408. package/src/lib/terminalSetup.ts +444 -0
  409. package/src/lib/termux.ts +29 -0
  410. package/src/lib/text.test.ts +18 -0
  411. package/src/lib/text.ts +339 -0
  412. package/src/lib/todo.test.ts +21 -0
  413. package/src/lib/todo.ts +9 -0
  414. package/src/lib/viewportStore.ts +124 -0
  415. package/src/lib/virtualHeights.ts +145 -0
  416. package/src/lib/wheelAccel.ts +190 -0
  417. package/src/protocol/interpolation.ts +3 -0
  418. package/src/protocol/paste.ts +1 -0
  419. package/src/theme.ts +589 -0
  420. package/src/types/nastech-ink.d.ts +176 -0
  421. package/src/types.ts +212 -0
  422. package/tsconfig.build.json +9 -0
  423. package/tsconfig.json +19 -0
  424. package/vitest.config.ts +7 -0
@@ -0,0 +1,830 @@
1
+ import { PureComponent, type ReactNode } from 'react'
2
+
3
+ import { updateLastInteractionTime } from '../../bootstrap/state.js'
4
+ import { logForDebugging } from '../../utils/debug.js'
5
+ import { stopCapturingEarlyInput } from '../../utils/earlyInput.js'
6
+ import { isMouseClicksDisabled } from '../../utils/fullscreen.js'
7
+ import { logError } from '../../utils/log.js'
8
+ import type { DOMElement } from '../dom.js'
9
+ import { EventEmitter } from '../events/emitter.js'
10
+ import { InputEvent } from '../events/input-event.js'
11
+ import { TerminalFocusEvent } from '../events/terminal-focus-event.js'
12
+ import {
13
+ INITIAL_STATE,
14
+ type ParsedInput,
15
+ type ParsedKey,
16
+ type ParsedMouse,
17
+ parseMultipleKeypresses
18
+ } from '../parse-keypress.js'
19
+ import reconciler from '../reconciler.js'
20
+ import { clearSelection, finishSelection, hasSelection, type SelectionState, startSelection } from '../selection.js'
21
+ import { getTerminalFocused, setTerminalFocused } from '../terminal-focus-state.js'
22
+ import { TerminalQuerier, xtversion } from '../terminal-querier.js'
23
+ import { isXtermJs, setXtversionName, supportsExtendedKeys } from '../terminal.js'
24
+ import {
25
+ DISABLE_KITTY_KEYBOARD,
26
+ DISABLE_MODIFY_OTHER_KEYS,
27
+ ENABLE_KITTY_KEYBOARD,
28
+ ENABLE_MODIFY_OTHER_KEYS,
29
+ FOCUS_IN,
30
+ FOCUS_OUT
31
+ } from '../termio/csi.js'
32
+ import { DBP, DFE, DISABLE_MOUSE_TRACKING, EBP, EFE, SHOW_CURSOR } from '../termio/dec.js'
33
+
34
+ import AppContext from './AppContext.js'
35
+ import { ClockProvider } from './ClockContext.js'
36
+ import CursorAdvanceContext, { type CursorAdvanceNotifier } from './CursorAdvanceContext.js'
37
+ import CursorDeclarationContext, { type CursorDeclarationSetter } from './CursorDeclarationContext.js'
38
+ import ErrorOverview from './ErrorOverview.js'
39
+ import StdinContext from './StdinContext.js'
40
+ import { TerminalFocusProvider } from './TerminalFocusContext.js'
41
+ import { TerminalSizeContext } from './TerminalSizeContext.js'
42
+
43
+ // Platforms that support Unix-style process suspension (SIGSTOP/SIGCONT)
44
+ const SUPPORTS_SUSPEND = false
45
+
46
+ // After this many milliseconds of stdin silence, the next chunk triggers
47
+ // a terminal mode re-assert (mouse tracking). Catches tmux detach→attach,
48
+ // ssh reconnect, and laptop wake — the terminal resets DEC private modes
49
+ // but no signal reaches us. 5s is well above normal inter-keystroke gaps
50
+ // but short enough that the first scroll after reattach works.
51
+ const STDIN_RESUME_GAP_MS = 5000
52
+ type Props = {
53
+ readonly children: ReactNode
54
+ readonly stdin: NodeJS.ReadStream
55
+ readonly stdout: NodeJS.WriteStream
56
+ readonly stderr: NodeJS.WriteStream
57
+ readonly exitOnCtrlC: boolean
58
+ readonly onExit: (error?: Error) => void
59
+ readonly terminalColumns: number
60
+ readonly terminalRows: number
61
+ // Text selection state. App mutates this directly from mouse events
62
+ // and calls onSelectionChange to trigger a repaint. Mouse events only
63
+ // arrive when <AlternateScreen> (or similar) enables mouse tracking,
64
+ // so the handler is always wired but dormant until tracking is on.
65
+ readonly selection: SelectionState
66
+ readonly onSelectionChange: () => void
67
+ // Dispatch a click at (col, row) — hit-tests the DOM tree and bubbles
68
+ // onClick handlers. Returns true if a DOM handler consumed the click.
69
+ // No-op (returns false) outside fullscreen mode (Ink.dispatchClick
70
+ // gates on altScreenActive).
71
+ readonly onClickAt: (col: number, row: number) => boolean
72
+ readonly onMouseDownAt: (col: number, row: number, button: number) => DOMElement | undefined
73
+ readonly onMouseUpAt: (target: DOMElement, col: number, row: number, button: number) => void
74
+ readonly onMouseDragAt: (target: DOMElement, col: number, row: number, button: number) => void
75
+ // Dispatch hover (onMouseEnter/onMouseLeave) as the pointer moves over
76
+ // DOM elements. Called for mode-1003 motion events with no button held.
77
+ // No-op outside fullscreen (Ink.dispatchHover gates on altScreenActive).
78
+ readonly onHoverAt: (col: number, row: number) => void
79
+ // Copy the active fullscreen text selection without clearing the highlight.
80
+ // Used for terminal-native right-click-copy behaviour.
81
+ readonly onCopySelectionNoClear: () => Promise<string>
82
+ readonly getSelectedText: () => string
83
+ // Look up the OSC 8 hyperlink at (col, row) synchronously at click
84
+ // time. Returns the URL or undefined. The browser-open is deferred by
85
+ // MULTI_CLICK_TIMEOUT_MS so double-click can cancel it.
86
+ readonly getHyperlinkAt: (col: number, row: number) => string | undefined
87
+ // Open a hyperlink URL in the browser. Called after the timer fires.
88
+ readonly onOpenHyperlink: (url: string) => void
89
+ // Called on double/triple-click PRESS at (col, row). count=2 selects
90
+ // the word under the cursor; count=3 selects the line. Ink reads the
91
+ // screen buffer to find word/line boundaries and mutates selection,
92
+ // setting isDragging=true so a subsequent drag extends by word/line.
93
+ readonly onMultiClick: (col: number, row: number, count: 2 | 3) => void
94
+ // Called on drag-motion. Mode-aware: char mode updates focus to the
95
+ // exact cell; word/line mode snaps to word/line boundaries. Needs
96
+ // screen-buffer access (word boundaries) so lives on Ink, not here.
97
+ readonly onSelectionDrag: (col: number, row: number) => void
98
+ // Called when stdin data arrives after a >STDIN_RESUME_GAP_MS gap.
99
+ // Ink re-asserts terminal modes: extended key reporting, and (when in
100
+ // fullscreen) re-enters alt-screen + mouse tracking. Idempotent on the
101
+ // terminal side. Optional so testing.tsx doesn't need to stub it.
102
+ readonly onStdinResume?: () => void
103
+ // Receives the declared native-cursor position from useDeclaredCursor
104
+ // so ink.tsx can park the terminal cursor there after each frame.
105
+ // Enables IME composition at the input caret and lets screen readers /
106
+ // magnifiers track the input. Optional so testing.tsx doesn't stub it.
107
+ readonly onCursorDeclaration?: CursorDeclarationSetter
108
+ // Receives notifications that the physical cursor was advanced out-of-band
109
+ // (e.g. TextInput's fast-echo bypass writing directly to stdout). The
110
+ // handler in ink.tsx updates two pieces of state from a single call:
111
+ // - `displayCursor` (the relative-move basis log-update uses on the
112
+ // next frame; skipped on alt-screen where CSI H resets it every
113
+ // frame anyway), and
114
+ // - the active `cursorDeclaration.relativeX/Y` (the target the cursor
115
+ // parks at after every frame; bumped on BOTH screens because
116
+ // onRender's alt-screen branch emits an absolute CUP from it and
117
+ // a stale declaration there is still visibly wrong).
118
+ // Optional so testing.tsx doesn't need to stub it.
119
+ readonly onCursorAdvance?: CursorAdvanceNotifier
120
+ // Dispatch a keyboard event through the DOM tree. Called for each
121
+ // parsed key alongside the legacy EventEmitter path.
122
+ readonly dispatchKeyboardEvent: (parsedKey: ParsedKey) => void
123
+ }
124
+
125
+ // Multi-click detection thresholds. 500ms is the macOS default; a small
126
+ // position tolerance allows for trackpad jitter between clicks.
127
+ const MULTI_CLICK_TIMEOUT_MS = 500
128
+ const MULTI_CLICK_DISTANCE = 1
129
+ type State = {
130
+ readonly error?: Error
131
+ }
132
+
133
+ // Root component for all Ink apps
134
+ // It renders stdin and stdout contexts, so that children can access them if needed
135
+ // It also handles Ctrl+C exiting and cursor visibility
136
+ export default class App extends PureComponent<Props, State> {
137
+ static displayName = 'InternalApp'
138
+ static getDerivedStateFromError(error: Error) {
139
+ return {
140
+ error
141
+ }
142
+ }
143
+ override state = {
144
+ error: undefined
145
+ }
146
+
147
+ // Count how many components enabled raw mode to avoid disabling
148
+ // raw mode until all components don't need it anymore
149
+ rawModeEnabledCount = 0
150
+ inputEmitter = new EventEmitter()
151
+ keyParseState = INITIAL_STATE
152
+ // Timer for flushing incomplete escape sequences
153
+ incompleteEscapeTimer: NodeJS.Timeout | null = null
154
+ // Timeout durations for incomplete sequences (ms)
155
+ readonly NORMAL_TIMEOUT = 50 // Short timeout for regular esc sequences
156
+ readonly PASTE_TIMEOUT = 500 // Longer timeout for paste operations
157
+
158
+ // Terminal query/response dispatch. Responses arrive on stdin (parsed
159
+ // out by parse-keypress) and are routed to pending promise resolvers.
160
+ querier = new TerminalQuerier(this.props.stdout)
161
+
162
+ // Multi-click tracking for double/triple-click text selection. A click
163
+ // within MULTI_CLICK_TIMEOUT_MS and MULTI_CLICK_DISTANCE of the previous
164
+ // click increments clickCount; otherwise it resets to 1.
165
+ lastClickTime = 0
166
+ lastClickCol = -1
167
+ lastClickRow = -1
168
+ clickCount = 0
169
+ // Deferred hyperlink-open timer — cancelled if a second click arrives
170
+ // within MULTI_CLICK_TIMEOUT_MS (so double-clicking a hyperlink selects
171
+ // the word without also opening the browser). DOM onClick dispatch is
172
+ // NOT deferred — it returns true from onClickAt and skips this timer.
173
+ pendingHyperlinkTimer: ReturnType<typeof setTimeout> | null = null
174
+ // Last mode-1003 motion position. Terminals already dedupe to cell
175
+ // granularity but this also lets us skip dispatchHover entirely on
176
+ // repeat events (drag-then-release at same cell, etc.).
177
+ lastHoverCol = -1
178
+ lastHoverRow = -1
179
+ mouseCaptureTarget: DOMElement | undefined
180
+
181
+ // Timestamp of last stdin chunk. Used to detect long gaps (tmux attach,
182
+ // ssh reconnect, laptop wake) and trigger terminal mode re-assert.
183
+ // Initialized to now so startup doesn't false-trigger.
184
+ lastStdinTime = Date.now()
185
+
186
+ // Determines if TTY is supported on the provided stdin
187
+ isRawModeSupported(): boolean {
188
+ return this.props.stdin.isTTY
189
+ }
190
+ override render() {
191
+ return (
192
+ <TerminalSizeContext.Provider
193
+ value={{
194
+ columns: this.props.terminalColumns,
195
+ rows: this.props.terminalRows
196
+ }}
197
+ >
198
+ <AppContext.Provider
199
+ value={{
200
+ exit: this.handleExit
201
+ }}
202
+ >
203
+ <StdinContext.Provider
204
+ value={{
205
+ stdin: this.props.stdin,
206
+ setRawMode: this.handleSetRawMode,
207
+ isRawModeSupported: this.isRawModeSupported(),
208
+ exitOnCtrlC: this.props.exitOnCtrlC,
209
+ inputEmitter: this.inputEmitter,
210
+ querier: this.querier
211
+ }}
212
+ >
213
+ <TerminalFocusProvider>
214
+ <ClockProvider>
215
+ <CursorDeclarationContext.Provider value={this.props.onCursorDeclaration ?? (() => {})}>
216
+ <CursorAdvanceContext.Provider value={this.props.onCursorAdvance ?? (() => {})}>
217
+ {this.state.error ? <ErrorOverview error={this.state.error as Error} /> : this.props.children}
218
+ </CursorAdvanceContext.Provider>
219
+ </CursorDeclarationContext.Provider>
220
+ </ClockProvider>
221
+ </TerminalFocusProvider>
222
+ </StdinContext.Provider>
223
+ </AppContext.Provider>
224
+ </TerminalSizeContext.Provider>
225
+ )
226
+ }
227
+ override componentWillUnmount() {
228
+ if (this.props.stdout.isTTY) {
229
+ this.props.stdout.write(SHOW_CURSOR)
230
+ }
231
+
232
+ // Clear any pending timers
233
+ if (this.incompleteEscapeTimer) {
234
+ clearTimeout(this.incompleteEscapeTimer)
235
+ this.incompleteEscapeTimer = null
236
+ }
237
+
238
+ if (this.pendingHyperlinkTimer) {
239
+ clearTimeout(this.pendingHyperlinkTimer)
240
+ this.pendingHyperlinkTimer = null
241
+ }
242
+
243
+ // ignore calling setRawMode on an handle stdin it cannot be called
244
+ if (this.isRawModeSupported()) {
245
+ this.handleSetRawMode(false)
246
+ }
247
+ }
248
+ override componentDidCatch(error: Error) {
249
+ this.handleExit(error)
250
+ }
251
+ handleSetRawMode = (isEnabled: boolean): void => {
252
+ const { stdin } = this.props
253
+
254
+ if (!this.isRawModeSupported()) {
255
+ if (stdin === process.stdin) {
256
+ throw new Error(
257
+ 'Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported'
258
+ )
259
+ } else {
260
+ throw new Error(
261
+ 'Raw mode is not supported on the stdin provided to Ink.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported'
262
+ )
263
+ }
264
+ }
265
+
266
+ stdin.setEncoding('utf8')
267
+
268
+ if (isEnabled) {
269
+ // Ensure raw mode is enabled only once
270
+ if (this.rawModeEnabledCount === 0) {
271
+ // Stop early input capture right before we add our own readable handler.
272
+ // Both use the same stdin 'readable' + read() pattern, so they can't
273
+ // coexist -- our handler would drain stdin before Ink's can see it.
274
+ // The buffered text is preserved for REPL.tsx via consumeEarlyInput().
275
+ stopCapturingEarlyInput()
276
+ stdin.ref()
277
+ stdin.setRawMode(true)
278
+ stdin.addListener('readable', this.handleReadable)
279
+ // Enable bracketed paste mode
280
+ this.props.stdout.write(EBP)
281
+ // Enable terminal focus reporting (DECSET 1004)
282
+ this.props.stdout.write(EFE)
283
+
284
+ // Enable extended key reporting so ctrl+shift+<letter> is
285
+ // distinguishable from ctrl+<letter>. We write both the kitty stack
286
+ // push (CSI >1u) and xterm modifyOtherKeys level 2 (CSI >4;2m) —
287
+ // terminals honor whichever they implement (tmux only accepts the
288
+ // latter).
289
+ if (supportsExtendedKeys()) {
290
+ this.props.stdout.write(ENABLE_KITTY_KEYBOARD)
291
+ this.props.stdout.write(ENABLE_MODIFY_OTHER_KEYS)
292
+ }
293
+
294
+ // Probe terminal identity. XTVERSION survives SSH (query/reply goes
295
+ // through the pty), unlike TERM_PROGRAM. Used for wheel-scroll base
296
+ // detection when env vars are absent. Fire-and-forget: the DA1
297
+ // sentinel bounds the round-trip, and if the terminal ignores the
298
+ // query, flush() still resolves and name stays undefined.
299
+ // Deferred to next tick so it fires AFTER the current synchronous
300
+ // init sequence completes — avoids interleaving with alt-screen/mouse
301
+ // tracking enable writes that may happen in the same render cycle.
302
+ setImmediate(() => {
303
+ void Promise.all([this.querier.send(xtversion()), this.querier.flush()]).then(([r]) => {
304
+ if (r) {
305
+ setXtversionName(r.name)
306
+ logForDebugging(`XTVERSION: terminal identified as "${r.name}"`)
307
+ } else {
308
+ logForDebugging('XTVERSION: no reply (terminal ignored query)')
309
+ }
310
+ })
311
+ })
312
+ }
313
+
314
+ this.rawModeEnabledCount++
315
+
316
+ return
317
+ }
318
+
319
+ // Disable raw mode only when no components left that are using it
320
+ if (--this.rawModeEnabledCount === 0) {
321
+ this.props.stdout.write(DISABLE_MODIFY_OTHER_KEYS)
322
+ this.props.stdout.write(DISABLE_KITTY_KEYBOARD)
323
+ // Disable terminal focus reporting (DECSET 1004)
324
+ this.props.stdout.write(DFE)
325
+ // Disable bracketed paste mode
326
+ this.props.stdout.write(DBP)
327
+ stdin.setRawMode(false)
328
+ stdin.removeListener('readable', this.handleReadable)
329
+ stdin.unref()
330
+ }
331
+ }
332
+
333
+ // Helper to flush incomplete escape sequences
334
+ flushIncomplete = (): void => {
335
+ // Clear the timer reference
336
+ this.incompleteEscapeTimer = null
337
+
338
+ // Only proceed if we have an incomplete escape sequence or an unterminated
339
+ // bracketed paste. Missing paste-end markers otherwise leave every later
340
+ // keystroke trapped in the paste buffer.
341
+ if (!this.keyParseState.incomplete && this.keyParseState.mode !== 'IN_PASTE') {
342
+ return
343
+ }
344
+
345
+ // Fullscreen: if stdin has data waiting, it's almost certainly the
346
+ // continuation of the buffered sequence (e.g. `[<64;74;16M` after a
347
+ // lone ESC). Node's event loop runs the timers phase before the poll
348
+ // phase, so when a heavy render blocks the loop past 50ms, this timer
349
+ // fires before the queued readable event even though the bytes are
350
+ // already buffered. Re-arm instead of flushing: handleReadable will
351
+ // drain stdin next and clear this timer. Prevents both the spurious
352
+ // Escape key and the lost scroll event.
353
+ if (this.props.stdin.readableLength > 0) {
354
+ this.incompleteEscapeTimer = setTimeout(
355
+ this.flushIncomplete,
356
+ this.keyParseState.mode === 'IN_PASTE' ? this.PASTE_TIMEOUT : this.NORMAL_TIMEOUT
357
+ )
358
+
359
+ return
360
+ }
361
+
362
+ // Process incomplete/paste state as a flush operation (input=null).
363
+ // This reuses all existing parsing logic.
364
+ this.processInput(null)
365
+ }
366
+
367
+ // Process input through the parser and handle the results
368
+ processInput = (input: string | Buffer | null): void => {
369
+ // Parse input using our state machine
370
+ const [keys, newState] = parseMultipleKeypresses(this.keyParseState, input)
371
+ this.keyParseState = newState
372
+
373
+ // Process ALL keys in a SINGLE discreteUpdates call to prevent
374
+ // "Maximum update depth exceeded" error when many keys arrive at once
375
+ // (e.g., from paste operations or holding keys rapidly).
376
+ // This batches all state updates from handleInput and all useInput
377
+ // listeners together within one high-priority update context.
378
+ if (keys.length > 0) {
379
+ reconciler.discreteUpdates(processKeysInBatch, this, keys, undefined, undefined)
380
+ }
381
+
382
+ // If we have incomplete escape sequences or an unterminated paste, set a
383
+ // timer to flush/reset them. Paste starts are complete CSI sequences, so
384
+ // checking only `incomplete` would never arm the watchdog.
385
+ if (this.keyParseState.incomplete || this.keyParseState.mode === 'IN_PASTE') {
386
+ // Cancel any existing timer first
387
+ if (this.incompleteEscapeTimer) {
388
+ clearTimeout(this.incompleteEscapeTimer)
389
+ }
390
+
391
+ this.incompleteEscapeTimer = setTimeout(
392
+ this.flushIncomplete,
393
+ this.keyParseState.mode === 'IN_PASTE' ? this.PASTE_TIMEOUT : this.NORMAL_TIMEOUT
394
+ )
395
+ }
396
+ }
397
+ handleReadable = (): void => {
398
+ // Detect long stdin gaps (tmux attach, ssh reconnect, laptop wake).
399
+ // The terminal may have reset DEC private modes; re-assert mouse
400
+ // tracking. Checked before the read loop so one Date.now() covers
401
+ // all chunks in this readable event.
402
+ const now = Date.now()
403
+
404
+ if (now - this.lastStdinTime > STDIN_RESUME_GAP_MS) {
405
+ this.props.onStdinResume?.()
406
+ }
407
+
408
+ this.lastStdinTime = now
409
+
410
+ try {
411
+ let chunk
412
+
413
+ while ((chunk = this.props.stdin.read() as string | null) !== null) {
414
+ // Process the input chunk
415
+ this.processInput(chunk)
416
+ }
417
+ } catch (error) {
418
+ // In Bun, an uncaught throw inside a stream 'readable' handler can
419
+ // permanently wedge the stream: data stays buffered and 'readable'
420
+ // never re-emits. Catching here ensures the stream stays healthy so
421
+ // subsequent keystrokes are still delivered.
422
+ logError(error)
423
+
424
+ // Re-attach the listener in case the exception detached it.
425
+ // Bun may remove the listener after an error; without this,
426
+ // the session freezes permanently (stdin reader dead, event loop alive).
427
+ const { stdin } = this.props
428
+
429
+ if (this.rawModeEnabledCount > 0 && !stdin.listeners('readable').includes(this.handleReadable)) {
430
+ logForDebugging('handleReadable: re-attaching stdin readable listener after error recovery', {
431
+ level: 'warn'
432
+ })
433
+ stdin.addListener('readable', this.handleReadable)
434
+ }
435
+ }
436
+ }
437
+ handleInput = (input: string | undefined): void => {
438
+ // Exit on Ctrl+C
439
+ if (input === '\x03' && this.props.exitOnCtrlC) {
440
+ this.handleExit()
441
+ }
442
+
443
+ // Note: Ctrl+Z (suspend) is now handled in processKeysInBatch using the
444
+ // parsed key to support both raw (\x1a) and CSI u format from Kitty
445
+ // keyboard protocol terminals (Ghostty, iTerm2, kitty, WezTerm)
446
+ }
447
+ handleExit = (error?: Error): void => {
448
+ if (this.isRawModeSupported()) {
449
+ this.handleSetRawMode(false)
450
+ }
451
+
452
+ this.props.onExit(error)
453
+ }
454
+ handleTerminalFocus = (isFocused: boolean): void => {
455
+ // setTerminalFocused notifies subscribers: TerminalFocusProvider (context)
456
+ // and Clock (interval speed) — no App setState needed.
457
+ setTerminalFocused(isFocused)
458
+ }
459
+ handleSuspend = (): void => {
460
+ if (!this.isRawModeSupported()) {
461
+ return
462
+ }
463
+
464
+ // Store the exact raw mode count to restore it properly
465
+ const rawModeCountBeforeSuspend = this.rawModeEnabledCount
466
+
467
+ // Completely disable raw mode before suspending
468
+ while (this.rawModeEnabledCount > 0) {
469
+ this.handleSetRawMode(false)
470
+ }
471
+
472
+ // Show cursor, disable focus reporting, and disable mouse tracking
473
+ // before suspending. DISABLE_MOUSE_TRACKING is a no-op if tracking
474
+ // wasn't enabled, so it's safe to emit unconditionally — without
475
+ // it, SGR mouse sequences would appear as garbled text at the
476
+ // shell prompt while suspended.
477
+ if (this.props.stdout.isTTY) {
478
+ this.props.stdout.write(SHOW_CURSOR + DFE + DISABLE_MOUSE_TRACKING)
479
+ }
480
+
481
+ this.inputEmitter.emit('suspend')
482
+
483
+ // Set up resume handler
484
+ const resumeHandler = () => {
485
+ // Restore raw mode to exact previous state
486
+ for (let i = 0; i < rawModeCountBeforeSuspend; i++) {
487
+ if (this.isRawModeSupported()) {
488
+ this.handleSetRawMode(true)
489
+ }
490
+ }
491
+
492
+ if (this.props.stdout.isTTY) {
493
+ this.props.stdout.write(EFE)
494
+ }
495
+
496
+ this.inputEmitter.emit('resume')
497
+ process.removeListener('SIGCONT', resumeHandler)
498
+ }
499
+
500
+ process.on('SIGCONT', resumeHandler)
501
+ process.kill(process.pid, 'SIGSTOP')
502
+ }
503
+ }
504
+
505
+ // Helper to process all keys within a single discrete update context.
506
+ // discreteUpdates expects (fn, a, b, c, d) -> fn(a, b, c, d)
507
+ function processKeysInBatch(app: App, items: ParsedInput[], _unused1: undefined, _unused2: undefined): void {
508
+ // Update interaction time for notification timeout tracking.
509
+ // This is called from the central input handler to avoid having multiple
510
+ // stdin listeners that can cause race conditions and dropped input.
511
+ // Terminal responses (kind: 'response') are automated, not user input.
512
+ // Mode-1003 no-button motion is also excluded — passive cursor drift is
513
+ // not engagement (would suppress idle notifications + defer housekeeping).
514
+ if (
515
+ items.some(i => i.kind === 'key' || (i.kind === 'mouse' && !((i.button & 0x20) !== 0 && (i.button & 0x03) === 3)))
516
+ ) {
517
+ updateLastInteractionTime()
518
+ }
519
+
520
+ for (const item of items) {
521
+ // Terminal responses (DECRPM, DA1, OSC replies, etc.) are not user
522
+ // input — route them to the querier to resolve pending promises.
523
+ if (item.kind === 'response') {
524
+ app.querier.onResponse(item.response)
525
+
526
+ continue
527
+ }
528
+
529
+ // Mouse click/drag events update selection state (fullscreen only).
530
+ // Terminal sends 1-indexed col/row; convert to 0-indexed for the
531
+ // screen buffer. Button bit 0x20 = drag (motion while button held).
532
+ if (item.kind === 'mouse') {
533
+ handleMouseEvent(app, item)
534
+
535
+ continue
536
+ }
537
+
538
+ const sequence = item.sequence
539
+
540
+ // Handle terminal focus events (DECSET 1004)
541
+ if (sequence === FOCUS_IN) {
542
+ app.handleTerminalFocus(true)
543
+ const event = new TerminalFocusEvent('terminalfocus')
544
+ app.inputEmitter.emit('terminalfocus', event)
545
+
546
+ continue
547
+ }
548
+
549
+ if (sequence === FOCUS_OUT) {
550
+ app.handleTerminalFocus(false)
551
+
552
+ // Defensive: if we lost the release event (mouse released outside
553
+ // terminal window — some emulators drop it rather than capturing the
554
+ // pointer), focus-out is the next observable signal that the drag is
555
+ // over. Without this, drag-to-scroll's timer runs until the scroll
556
+ // boundary is hit.
557
+ if (app.props.selection.isDragging) {
558
+ finishSelection(app.props.selection)
559
+ app.props.onSelectionChange()
560
+ }
561
+
562
+ const event = new TerminalFocusEvent('terminalblur')
563
+ app.inputEmitter.emit('terminalblur', event)
564
+
565
+ continue
566
+ }
567
+
568
+ // Failsafe: if we receive input, the terminal must be focused
569
+ if (!getTerminalFocused()) {
570
+ setTerminalFocused(true)
571
+ }
572
+
573
+ // Handle Ctrl+Z (suspend) using parsed key to support both raw (\x1a) and
574
+ // CSI u format (\x1b[122;5u) from Kitty keyboard protocol terminals
575
+ if (item.name === 'z' && item.ctrl && SUPPORTS_SUSPEND) {
576
+ app.handleSuspend()
577
+
578
+ continue
579
+ }
580
+
581
+ app.handleInput(sequence)
582
+ const event = new InputEvent(item)
583
+ app.inputEmitter.emit('input', event)
584
+
585
+ // Also dispatch through the DOM tree so onKeyDown handlers fire.
586
+ app.props.dispatchKeyboardEvent(item)
587
+ }
588
+ }
589
+
590
+ /** Exported for testing. Mutates app.props.selection and click/hover state. */
591
+ export function handleMouseEvent(app: App, m: ParsedMouse): void {
592
+ const sel = app.props.selection
593
+ // Terminal coords are 1-indexed; screen buffer is 0-indexed
594
+ const col = m.col - 1
595
+ const row = m.row - 1
596
+ const baseButton = m.button & 0x03
597
+
598
+ // Disable app click handling without blocking wheel/right-click dispatch.
599
+ if (isMouseClicksDisabled() && baseButton === 0) {
600
+ return
601
+ }
602
+
603
+ if (m.action === 'press') {
604
+ if ((m.button & 0x20) !== 0 && baseButton === 3) {
605
+ if (app.mouseCaptureTarget) {
606
+ app.props.onMouseUpAt(app.mouseCaptureTarget, col, row, baseButton)
607
+ app.mouseCaptureTarget = undefined
608
+ }
609
+
610
+ // Mode-1003 motion with no button held. Dispatch hover; skip the
611
+ // rest of this handler (no selection, no click-count side effects).
612
+ // Lost-release recovery: no-button motion while isDragging=true means
613
+ // the release happened outside the terminal window (iTerm2 doesn't
614
+ // capture the pointer past window bounds, so the SGR 'm' never
615
+ // arrives). Finish the selection here so copy-on-select fires. The
616
+ // FOCUS_OUT handler covers the "switched apps" case but not "released
617
+ // past the edge, came back" — and tmux drops focus events unless
618
+ // `focus-events on` is set, so this is the more reliable signal.
619
+ if (sel.isDragging) {
620
+ finishSelection(sel)
621
+ app.props.onSelectionChange()
622
+ }
623
+
624
+ if (col === app.lastHoverCol && row === app.lastHoverRow) {
625
+ return
626
+ }
627
+
628
+ app.lastHoverCol = col
629
+ app.lastHoverRow = row
630
+ app.props.onHoverAt(col, row)
631
+
632
+ return
633
+ }
634
+
635
+ if (baseButton !== 0) {
636
+ // Non-left press breaks the multi-click chain.
637
+ app.clickCount = 0
638
+
639
+ if (baseButton === 2 && hasSelection(sel)) {
640
+ if ((m.button & 0x20) !== 0) {
641
+ return
642
+ }
643
+
644
+ if (!app.props.getSelectedText()) {
645
+ return
646
+ }
647
+
648
+ void app.props
649
+ .onCopySelectionNoClear()
650
+ .then(text => {
651
+ if (text) {
652
+ // Right-click copy is a deliberate action (unlike copy-on-select
653
+ // during a drag, which keeps the highlight so the drag can
654
+ // continue). Clear the highlight so the user gets visual
655
+ // confirmation the copy landed and a follow-up right-click on
656
+ // empty space pastes instead of re-copying the stale range.
657
+ clearSelection(sel)
658
+ app.props.onSelectionChange()
659
+ } else {
660
+ app.props.onMouseDownAt(col, row, baseButton)
661
+ }
662
+ })
663
+ .catch(() => app.props.onMouseDownAt(col, row, baseButton))
664
+
665
+ return
666
+ }
667
+
668
+ app.props.onMouseDownAt(col, row, baseButton)
669
+
670
+ return
671
+ }
672
+
673
+ if ((m.button & 0x20) !== 0) {
674
+ if (app.mouseCaptureTarget) {
675
+ app.props.onMouseDragAt(app.mouseCaptureTarget, col, row, baseButton)
676
+
677
+ return
678
+ }
679
+
680
+ // Drag motion: mode-aware extension (char/word/line). onSelectionDrag
681
+ // calls notifySelectionChange internally — no extra onSelectionChange.
682
+ app.props.onSelectionDrag(col, row)
683
+
684
+ return
685
+ }
686
+
687
+ // Lost-release fallback for mode-1002-only terminals: a fresh press
688
+ // while isDragging=true means the previous release was dropped (cursor
689
+ // left the window). Finish that selection so copy-on-select fires
690
+ // before startSelection/onMultiClick clobbers it. Mode-1003 terminals
691
+ // hit the no-button-motion recovery above instead, so this is rare.
692
+ if (sel.isDragging) {
693
+ finishSelection(sel)
694
+ app.props.onSelectionChange()
695
+ }
696
+
697
+ const capture = app.props.onMouseDownAt(col, row, baseButton)
698
+
699
+ if (capture) {
700
+ app.mouseCaptureTarget = capture
701
+ app.clickCount = 0
702
+
703
+ return
704
+ }
705
+
706
+ // Fresh left press. Detect multi-click HERE (not on release) so the
707
+ // word/line highlight appears immediately and a subsequent drag can
708
+ // extend by word/line like native macOS. Previously detected on
709
+ // release, which meant (a) visible latency before the word highlights
710
+ // and (b) double-click+drag fell through to char-mode selection.
711
+ const now = Date.now()
712
+
713
+ const nearLast =
714
+ now - app.lastClickTime < MULTI_CLICK_TIMEOUT_MS &&
715
+ Math.abs(col - app.lastClickCol) <= MULTI_CLICK_DISTANCE &&
716
+ Math.abs(row - app.lastClickRow) <= MULTI_CLICK_DISTANCE
717
+
718
+ app.clickCount = nearLast ? app.clickCount + 1 : 1
719
+ app.lastClickTime = now
720
+ app.lastClickCol = col
721
+ app.lastClickRow = row
722
+
723
+ if (app.clickCount >= 2) {
724
+ // Cancel any pending hyperlink-open from the first click — this is
725
+ // a double-click, not a single-click on a link.
726
+ if (app.pendingHyperlinkTimer) {
727
+ clearTimeout(app.pendingHyperlinkTimer)
728
+ app.pendingHyperlinkTimer = null
729
+ }
730
+
731
+ // Cap at 3 (line select) for quadruple+ clicks.
732
+ const count = app.clickCount === 2 ? 2 : 3
733
+ app.props.onMultiClick(col, row, count)
734
+
735
+ return
736
+ }
737
+
738
+ startSelection(sel, col, row)
739
+ // SGR bit 0x08 = alt (xterm.js wires altKey here, not metaKey — see
740
+ // comment at the hyperlink-open guard below). On macOS xterm.js,
741
+ // receiving alt means macOptionClickForcesSelection is OFF (otherwise
742
+ // xterm.js would have consumed the event for native selection).
743
+ sel.lastPressHadAlt = (m.button & 0x08) !== 0
744
+ app.props.onSelectionChange()
745
+
746
+ return
747
+ }
748
+
749
+ // Release: end the drag even for non-zero button codes. Some terminals
750
+ // encode release with the motion bit or button=3 "no button" (carried
751
+ // over from pre-SGR X10 encoding) — filtering those would orphan
752
+ // isDragging=true and leave drag-to-scroll's timer running until the
753
+ // scroll boundary. Only act on non-left releases when we ARE dragging
754
+ // (so an unrelated middle/right click-release doesn't touch selection).
755
+ if (app.mouseCaptureTarget) {
756
+ app.props.onMouseUpAt(app.mouseCaptureTarget, col, row, baseButton)
757
+ app.mouseCaptureTarget = undefined
758
+
759
+ return
760
+ }
761
+
762
+ if (baseButton !== 0) {
763
+ if (!sel.isDragging) {
764
+ return
765
+ }
766
+
767
+ finishSelection(sel)
768
+ app.props.onSelectionChange()
769
+
770
+ return
771
+ }
772
+
773
+ finishSelection(sel)
774
+
775
+ // NOTE: unlike the old release-based detection we do NOT reset clickCount
776
+ // on release-after-drag. This aligns with NSEvent.clickCount semantics:
777
+ // an intervening drag doesn't break the click chain. Practical upside:
778
+ // trackpad jitter during an intended double-click (press→wobble→release
779
+ // →press) now correctly resolves to word-select instead of breaking to a
780
+ // fresh single click. The nearLast window (500ms, 1 cell) bounds the
781
+ // effect — a deliberate drag past that just starts a fresh chain.
782
+ // A press+release with no drag in char mode is a click: anchor set,
783
+ // focus null → hasSelection false. In word/line mode the press already
784
+ // set anchor+focus (hasSelection true), so release just keeps the
785
+ // highlight. The anchor check guards against an orphaned release (no
786
+ // prior press — e.g. button was held when mouse tracking was enabled).
787
+ if (!hasSelection(sel) && sel.anchor) {
788
+ // Single click: dispatch DOM click immediately (cursor repositioning
789
+ // etc. are latency-sensitive). If no DOM handler consumed it, defer
790
+ // the hyperlink check so a second click can cancel it.
791
+ if (!app.props.onClickAt(col, row)) {
792
+ // Resolve the hyperlink URL synchronously while the screen buffer
793
+ // still reflects what the user clicked — deferring only the
794
+ // browser-open so double-click can cancel it.
795
+ const url = app.props.getHyperlinkAt(col, row)
796
+
797
+ // xterm.js (VS Code, Cursor, Windsurf, etc.) has its own OSC 8 link
798
+ // handler that fires on Cmd+click *without consuming the mouse event*
799
+ // (Linkifier._handleMouseUp calls link.activate() but never
800
+ // preventDefault/stopPropagation). The click is also forwarded to the
801
+ // pty as SGR, so both VS Code's terminalLinkManager AND our handler
802
+ // here would open the URL — twice. We can't filter on Cmd: xterm.js
803
+ // drops metaKey before SGR encoding (ICoreMouseEvent has no meta
804
+ // field; the SGR bit we call 'meta' is wired to alt). Let xterm.js
805
+ // own link-opening; Cmd+click is the native UX there anyway.
806
+ // TERM_PROGRAM is the sync fast-path; isXtermJs() is the XTVERSION
807
+ // probe result (catches SSH + non-VS Code embedders like Hyper).
808
+ if (url && process.env.TERM_PROGRAM !== 'vscode' && !isXtermJs()) {
809
+ // Clear any prior pending timer — clicking a second link
810
+ // supersedes the first (only the latest click opens).
811
+ if (app.pendingHyperlinkTimer) {
812
+ clearTimeout(app.pendingHyperlinkTimer)
813
+ }
814
+
815
+ app.pendingHyperlinkTimer = setTimeout(
816
+ (app, url) => {
817
+ app.pendingHyperlinkTimer = null
818
+ app.props.onOpenHyperlink(url)
819
+ },
820
+ MULTI_CLICK_TIMEOUT_MS,
821
+ app,
822
+ url
823
+ )
824
+ }
825
+ }
826
+ }
827
+
828
+ app.props.onSelectionChange()
829
+ }
830
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlB1cmVDb21wb25lbnQiLCJSZWFjdE5vZGUiLCJ1cGRhdGVMYXN0SW50ZXJhY3Rpb25UaW1lIiwibG9nRm9yRGVidWdnaW5nIiwic3RvcENhcHR1cmluZ0Vhcmx5SW5wdXQiLCJpc0VudlRydXRoeSIsImlzTW91c2VDbGlja3NEaXNhYmxlZCIsImxvZ0Vycm9yIiwiRXZlbnRFbWl0dGVyIiwiSW5wdXRFdmVudCIsIlRlcm1pbmFsRm9jdXNFdmVudCIsIklOSVRJQUxfU1RBVEUiLCJQYXJzZWRJbnB1dCIsIlBhcnNlZEtleSIsIlBhcnNlZE1vdXNlIiwicGFyc2VNdWx0aXBsZUtleXByZXNzZXMiLCJyZWNvbmNpbGVyIiwiZmluaXNoU2VsZWN0aW9uIiwiaGFzU2VsZWN0aW9uIiwiU2VsZWN0aW9uU3RhdGUiLCJzdGFydFNlbGVjdGlvbiIsImlzWHRlcm1KcyIsInNldFh0dmVyc2lvbk5hbWUiLCJzdXBwb3J0c0V4dGVuZGVkS2V5cyIsImdldFRlcm1pbmFsRm9jdXNlZCIsInNldFRlcm1pbmFsRm9jdXNlZCIsIlRlcm1pbmFsUXVlcmllciIsInh0dmVyc2lvbiIsIkRJU0FCTEVfS0lUVFlfS0VZQk9BUkQiLCJESVNBQkxFX01PRElGWV9PVEhFUl9LRVlTIiwiRU5BQkxFX0tJVFRZX0tFWUJPQVJEIiwiRU5BQkxFX01PRElGWV9PVEhFUl9LRVlTIiwiRk9DVVNfSU4iLCJGT0NVU19PVVQiLCJEQlAiLCJERkUiLCJESVNBQkxFX01PVVNFX1RSQUNLSU5HIiwiRUJQIiwiRUZFIiwiSElERV9DVVJTT1IiLCJTSE9XX0NVUlNPUiIsIkFwcENvbnRleHQiLCJDbG9ja1Byb3ZpZGVyIiwiQ3Vyc29yRGVjbGFyYXRpb25Db250ZXh0IiwiQ3Vyc29yRGVjbGFyYXRpb25TZXR0ZXIiLCJFcnJvck92ZXJ2aWV3IiwiU3RkaW5Db250ZXh0IiwiVGVybWluYWxGb2N1c1Byb3ZpZGVyIiwiVGVybWluYWxTaXplQ29udGV4dCIsIlNVUFBPUlRTX1NVU1BFTkQiLCJwcm9jZXNzIiwicGxhdGZvcm0iLCJTVERJTl9SRVNVTUVfR0FQX01TIiwiUHJvcHMiLCJjaGlsZHJlbiIsInN0ZGluIiwiTm9kZUpTIiwiUmVhZFN0cmVhbSIsInN0ZG91dCIsIldyaXRlU3RyZWFtIiwic3RkZXJyIiwiZXhpdE9uQ3RybEMiLCJvbkV4aXQiLCJlcnJvciIsIkVycm9yIiwidGVybWluYWxDb2x1bW5zIiwidGVybWluYWxSb3dzIiwic2VsZWN0aW9uIiwib25TZWxlY3Rpb25DaGFuZ2UiLCJvbkNsaWNrQXQiLCJjb2wiLCJyb3ciLCJvbkhvdmVyQXQiLCJnZXRIeXBlcmxpbmtBdCIsIm9uT3Blbkh5cGVybGluayIsInVybCIsIm9uTXVsdGlDbGljayIsImNvdW50Iiwib25TZWxlY3Rpb25EcmFnIiwib25TdGRpblJlc3VtZSIsIm9uQ3Vyc29yRGVjbGFyYXRpb24iLCJkaXNwYXRjaEtleWJvYXJkRXZlbnQiLCJwYXJzZWRLZXkiLCJNVUxUSV9DTElDS19USU1FT1VUX01TIiwiTVVMVElfQ0xJQ0tfRElTVEFOQ0UiLCJTdGF0ZSIsIkFwcCIsImRpc3BsYXlOYW1lIiwiZ2V0RGVyaXZlZFN0YXRlRnJvbUVycm9yIiwic3RhdGUiLCJ1bmRlZmluZWQiLCJyYXdNb2RlRW5hYmxlZENvdW50IiwiaW50ZXJuYWxfZXZlbnRFbWl0dGVyIiwia2V5UGFyc2VTdGF0ZSIsImluY29tcGxldGVFc2NhcGVUaW1lciIsIlRpbWVvdXQiLCJOT1JNQUxfVElNRU9VVCIsIlBBU1RFX1RJTUVPVVQiLCJxdWVyaWVyIiwicHJvcHMiLCJsYXN0Q2xpY2tUaW1lIiwibGFzdENsaWNrQ29sIiwibGFzdENsaWNrUm93IiwiY2xpY2tDb3VudCIsInBlbmRpbmdIeXBlcmxpbmtUaW1lciIsIlJldHVyblR5cGUiLCJzZXRUaW1lb3V0IiwibGFzdEhvdmVyQ29sIiwibGFzdEhvdmVyUm93IiwibGFzdFN0ZGluVGltZSIsIkRhdGUiLCJub3ciLCJpc1Jhd01vZGVTdXBwb3J0ZWQiLCJpc1RUWSIsInJlbmRlciIsImNvbHVtbnMiLCJyb3dzIiwiZXhpdCIsImhhbmRsZUV4aXQiLCJzZXRSYXdNb2RlIiwiaGFuZGxlU2V0UmF3TW9kZSIsImludGVybmFsX2V4aXRPbkN0cmxDIiwiaW50ZXJuYWxfcXVlcmllciIsImNvbXBvbmVudERpZE1vdW50IiwiZW52IiwiQ0xBVURFX0NPREVfQUNDRVNTSUJJTElUWSIsIndyaXRlIiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJjbGVhclRpbWVvdXQiLCJjb21wb25lbnREaWRDYXRjaCIsImlzRW5hYmxlZCIsInNldEVuY29kaW5nIiwicmVmIiwiYWRkTGlzdGVuZXIiLCJoYW5kbGVSZWFkYWJsZSIsInNldEltbWVkaWF0ZSIsIlByb21pc2UiLCJhbGwiLCJzZW5kIiwiZmx1c2giLCJ0aGVuIiwiciIsIm5hbWUiLCJyZW1vdmVMaXN0ZW5lciIsInVucmVmIiwiZmx1c2hJbmNvbXBsZXRlIiwiaW5jb21wbGV0ZSIsInJlYWRhYmxlTGVuZ3RoIiwicHJvY2Vzc0lucHV0IiwiaW5wdXQiLCJCdWZmZXIiLCJrZXlzIiwibmV3U3RhdGUiLCJsZW5ndGgiLCJkaXNjcmV0ZVVwZGF0ZXMiLCJwcm9jZXNzS2V5c0luQmF0Y2giLCJtb2RlIiwiY2h1bmsiLCJyZWFkIiwibGlzdGVuZXJzIiwiaW5jbHVkZXMiLCJsZXZlbCIsImhhbmRsZUlucHV0IiwiaGFuZGxlVGVybWluYWxGb2N1cyIsImlzRm9jdXNlZCIsImhhbmRsZVN1c3BlbmQiLCJyYXdNb2RlQ291bnRCZWZvcmVTdXNwZW5kIiwiZW1pdCIsInJlc3VtZUhhbmRsZXIiLCJpIiwib24iLCJraWxsIiwicGlkIiwiYXBwIiwiaXRlbXMiLCJfdW51c2VkMSIsIl91bnVzZWQyIiwic29tZSIsImtpbmQiLCJidXR0b24iLCJpdGVtIiwib25SZXNwb25zZSIsInJlc3BvbnNlIiwiaGFuZGxlTW91c2VFdmVudCIsInNlcXVlbmNlIiwiZXZlbnQiLCJpc0RyYWdnaW5nIiwiY3RybCIsIm0iLCJzZWwiLCJiYXNlQnV0dG9uIiwiYWN0aW9uIiwibmVhckxhc3QiLCJNYXRoIiwiYWJzIiwibGFzdFByZXNzSGFkQWx0IiwiYW5jaG9yIiwiVEVSTV9QUk9HUkFNIl0sInNvdXJjZXMiOlsiQXBwLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHsgUHVyZUNvbXBvbmVudCwgdHlwZSBSZWFjdE5vZGUgfSBmcm9tICdyZWFjdCdcbmltcG9ydCB7IHVwZGF0ZUxhc3RJbnRlcmFjdGlvblRpbWUgfSBmcm9tICcuLi8uLi9ib290c3RyYXAvc3RhdGUuanMnXG5pbXBvcnQgeyBsb2dGb3JEZWJ1Z2dpbmcgfSBmcm9tICcuLi8uLi91dGlscy9kZWJ1Zy5qcydcbmltcG9ydCB7IHN0b3BDYXB0dXJpbmdFYXJseUlucHV0IH0gZnJvbSAnLi4vLi4vdXRpbHMvZWFybHlJbnB1dC5qcydcbmltcG9ydCB7IGlzRW52VHJ1dGh5IH0gZnJvbSAnLi4vLi4vdXRpbHMvZW52VXRpbHMuanMnXG5pbXBvcnQgeyBpc01vdXNlQ2xpY2tzRGlzYWJsZWQgfSBmcm9tICcuLi8uLi91dGlscy9mdWxsc2NyZWVuLmpzJ1xuaW1wb3J0IHsgbG9nRXJyb3IgfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICcuLi9ldmVudHMvZW1pdHRlci5qcydcbmltcG9ydCB7IElucHV0RXZlbnQgfSBmcm9tICcuLi9ldmVudHMvaW5wdXQtZXZlbnQuanMnXG5pbXBvcnQgeyBUZXJtaW5hbEZvY3VzRXZlbnQgfSBmcm9tICcuLi9ldmVudHMvdGVybWluYWwtZm9jdXMtZXZlbnQuanMnXG5pbXBvcnQge1xuICBJTklUSUFMX1NUQVRFLFxuICB0eXBlIFBhcnNlZElucHV0LFxuICB0eXBlIFBhcnNlZEtleSxcbiAgdHlwZSBQYXJzZWRNb3VzZSxcbiAgcGFyc2VNdWx0aXBsZUtleXByZXNzZXMsXG59IGZyb20gJy4uL3BhcnNlLWtleXByZXNzLmpzJ1xuaW1wb3J0IHJlY29uY2lsZXIgZnJvbSAnLi4vcmVjb25jaWxlci5qcydcbmltcG9ydCB7XG4gIGZpbmlzaFNlbGVjdGlvbixcbiAgaGFzU2VsZWN0aW9uLFxuICB0eXBlIFNlbGVjdGlvblN0YXRlLFxuICBzdGFydFNlbGVjdGlvbixcbn0gZnJvbSAnLi4vc2VsZWN0aW9uLmpzJ1xuaW1wb3J0IHtcbiAgaXNYdGVybUpzLFxuICBzZXRYdHZlcnNpb25OYW1lLFxuICBzdXBwb3J0c0V4dGVuZGVkS2V5cyxcbn0gZnJvbSAnLi4vdGVybWluYWwuanMnXG5pbXBvcnQge1xuICBnZXRUZXJtaW5hbEZvY3VzZWQsXG4gIHNldFRlcm1pbmFsRm9jdXNlZCxcbn0gZnJvbSAnLi4vdGVybWluYWwtZm9jdXMtc3RhdGUuanMnXG5pbXBvcnQgeyBUZXJtaW5hbFF1ZXJpZXIsIHh0dmVyc2lvbiB9IGZyb20gJy4uL3Rlcm1pbmFsLXF1ZXJpZXIuanMnXG5pbXBvcnQge1xuICBESVNBQkxFX0tJVFRZX0tFWUJPQVJELFxuICBESVNBQkxFX01PRElGWV9PVEhFUl9LRVlTLFxuICBFTkFCTEVfS0lUVFlfS0VZQk9BUkQsXG4gIEVOQUJMRV9NT0RJRllfT1RIRVJfS0VZUyxcbiAgRk9DVVNfSU4sXG4gIEZPQ1VTX09VVCxcbn0gZnJvbSAnLi4vdGVybWlvL2NzaS5qcydcbmltcG9ydCB7XG4gIERCUCxcbiAgREZFLFxuICBESVNBQkxFX01PVVNFX1RSQUNLSU5HLFxuICBFQlAsXG4gIEVGRSxcbiAgSElERV9DVVJTT1IsXG4gIFNIT1dfQ1VSU09SLFxufSBmcm9tICcuLi90ZXJtaW8vZGVjLmpzJ1xuaW1wb3J0IEFwcENvbnRleHQgZnJvbSAnLi9BcHBDb250ZXh0LmpzJ1xuaW1wb3J0IHsgQ2xvY2tQcm92aWRlciB9IGZyb20gJy4vQ2xvY2tDb250ZXh0LmpzJ1xuaW1wb3J0IEN1cnNvckRlY2xhcmF0aW9uQ29udGV4dCwge1xuICB0eXBlIEN1cnNvckRlY2xhcmF0aW9uU2V0dGVyLFxufSBmcm9tICcuL0N1cnNvckRlY2xhcmF0aW9uQ29udGV4dC5qcydcbmltcG9ydCBFcnJvck92ZXJ2aWV3IGZyb20gJy4vRXJyb3JPdmVydmlldy5qcydcbmltcG9ydCBTdGRpbkNvbnRleHQgZnJvbSAnLi9TdGRpbkNvbnRleHQuanMnXG5pbXBvcnQgeyBUZXJtaW5hbEZvY3VzUHJvdmlkZXIgfSBmcm9tICcuL1Rlcm1pbmFsRm9jdXNDb250ZXh0LmpzJ1xuaW1wb3J0IHsgVGVybWluYWxTaXplQ29udGV4dCB9IGZyb20gJy4vVGVybWluYWxTaXplQ29udGV4dC5qcydcblxuLy8gUGxhdGZvcm1zIHRoYXQgc3VwcG9ydCBVbml4LXN0eWxlIHByb2Nlc3Mgc3VzcGVuc2lvbiAoU0lHU1RPUC9TSUdDT05UKVxuY29uc3QgU1VQUE9SVFNfU1VTUEVORCA9IHByb2Nlc3MucGxhdGZvcm0gIT09ICd3aW4zMidcblxuLy8gQWZ0ZXIgdGhpcyBtYW55IG1pbGxpc2Vjb25kcyBvZiBzdGRpbiBzaWxlbmNlLCB0aGUgbmV4dCBjaHVuayB0cmlnZ2Vyc1xuLy8gYSB0ZXJtaW5hbCBtb2RlIHJlLWFzc2VydCAobW91c2UgdHJhY2tpbmcpLiBDYXRjaGVzIHRtdXggZGV0YWNo4oaSYXR0YWNoLFxuLy8gc3NoIHJlY29ubmVjdCwgYW5kIGxhcHRvcCB3YWtlIOKAlCB0aGUgdGVybWluYWwgcmVzZXRzIERFQyBwcml2YXRlIG1vZGVzXG4vLyBidXQgbm8gc2lnbmFsIHJlYWNoZXMgdXMuIDVzIGlzIHdlbGwgYWJvdmUgbm9ybWFsIGludGVyLWtleXN0cm9rZSBnYXBzXG4vLyBidXQgc2hvcnQgZW5vdWdoIHRoYXQgdGhlIGZpcnN0IHNjcm9sbCBhZnRlciByZWF0dGFjaCB3b3Jrcy5cbmNvbnN0IFNURElOX1JFU1VNRV9HQVBfTVMgPSA1MDAwXG5cbnR5cGUgUHJvcHMgPSB7XG4gIHJlYWRvbmx5IGNoaWxkcmVuOiBSZWFjdE5vZGVcbiAgcmVhZG9ubHkgc3RkaW46IE5vZGVKUy5SZWFkU3RyZWFtXG4gIHJlYWRvbmx5IHN0ZG91dDogTm9kZUpTLldyaXRlU3RyZWFtXG4gIHJlYWRvbmx5IHN0ZGVycjogTm9kZUpTLldyaXRlU3RyZWFtXG4gIHJlYWRvbmx5IGV4aXRPbkN0cmxDOiBib29sZWFuXG4gIHJlYWRvbmx5IG9uRXhpdDogKGVycm9yPzogRXJyb3IpID0+IHZvaWRcbiAgcmVhZG9ubHkgdGVybWluYWxDb2x1bW5zOiBudW1iZXJcbiAgcmVhZG9ubHkgdGVybWluYWxSb3dzOiBudW1iZXJcbiAgLy8gVGV4dCBzZWxlY3Rpb24gc3RhdGUuIEFwcCBtdXRhdGVzIHRoaXMgZGlyZWN0bHkgZnJvbSBtb3VzZSBldmVudHNcbiAgLy8gYW5kIGNhbGxzIG9uU2VsZWN0aW9uQ2hhbmdlIHRvIHRyaWdnZXIgYSByZXBhaW50LiBNb3VzZSBldmVudHMgb25seVxuICAvLyBhcnJpdmUgd2hlbiA8QWx0ZXJuYXRlU2NyZWVuPiAob3Igc2ltaWxhcikgZW5hYmxlcyBtb3VzZSB0cmFja2luZyxcbiAgLy8gc28gdGhlIGhhbmRsZXIgaXMgYWx3YXlzIHdpcmVkIGJ1dCBkb3JtYW50IHVudGlsIHRyYWNraW5nIGlzIG9uLlxuICByZWFkb25seSBzZWxlY3Rpb246IFNlbGVjdGlvblN0YXRlXG4gIHJlYWRvbmx5IG9uU2VsZWN0aW9uQ2hhbmdlOiAoKSA9PiB2b2lkXG4gIC8vIERpc3BhdGNoIGEgY2xpY2sgYXQgKGNvbCwgcm93KSDigJQgaGl0LXRlc3RzIHRoZSBET00gdHJlZSBhbmQgYnViYmxlc1xuICAvLyBvbkNsaWNrIGhhbmRsZXJzLiBSZXR1cm5zIHRydWUgaWYgYSBET00gaGFuZGxlciBjb25zdW1lZCB0aGUgY2xpY2suXG4gIC8vIE5vLW9wIChyZXR1cm5zIGZhbHNlKSBvdXRzaWRlIGZ1bGxzY3JlZW4gbW9kZSAoSW5rLmRpc3BhdGNoQ2xpY2tcbiAgLy8gZ2F0ZXMgb24gYWx0U2NyZWVuQWN0aXZlKS5cbiAgcmVhZG9ubHkgb25DbGlja0F0OiAoY29sOiBudW1iZXIsIHJvdzogbnVtYmVyKSA9PiBib29sZWFuXG4gIC8vIERpc3BhdGNoIGhvdmVyIChvbk1vdXNlRW50ZXIvb25Nb3VzZUxlYXZlKSBhcyB0aGUgcG9pbnRlciBtb3ZlcyBvdmVyXG4gIC8vIERPTSBlbGVtZW50cy4gQ2FsbGVkIGZvciBtb2RlLTEwMDMgbW90aW9uIGV2ZW50cyB3aXRoIG5vIGJ1dHRvbiBoZWxkLlxuICAvLyBOby1vcCBvdXRzaWRlIGZ1bGxzY3JlZW4gKEluay5kaXNwYXRjaEhvdmVyIGdhdGVzIG9uIGFsdFNjcmVlbkFjdGl2ZSkuXG4gIHJlYWRvbmx5IG9uSG92ZXJBdDogKGNvbDogbnVtYmVyLCByb3c6IG51bWJlcikgPT4gdm9pZFxuICAvLyBMb29rIHVwIHRoZSBPU0MgOCBoeXBlcmxpbmsgYXQgKGNvbCwgcm93KSBzeW5jaHJvbm91c2x5IGF0IGNsaWNrXG4gIC8vIHRpbWUuIFJldHVybnMgdGhlIFVSTCBvciB1bmRlZmluZWQuIFRoZSBicm93c2VyLW9wZW4gaXMgZGVmZXJyZWQgYnlcbiAgLy8gTVVMVElfQ0xJQ0tfVElNRU9VVF9NUyBzbyBkb3VibGUtY2xpY2sgY2FuIGNhbmNlbCBpdC5cbiAgcmVhZG9ubHkgZ2V0SHlwZXJsaW5rQXQ6IChjb2w6IG51bWJlciwgcm93OiBudW1iZXIpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAvLyBPcGVuIGEgaHlwZXJsaW5rIFVSTCBpbiB0aGUgYnJvd3Nlci4gQ2FsbGVkIGFmdGVyIHRoZSB0aW1lciBmaXJlcy5cbiAgcmVhZG9ubHkgb25PcGVuSHlwZXJsaW5rOiAodXJsOiBzdHJpbmcpID0+IHZvaWRcbiAgLy8gQ2FsbGVkIG9uIGRvdWJsZS90cmlwbGUtY2xpY2sgUFJFU1MgYXQgKGNvbCwgcm93KS4gY291bnQ9MiBzZWxlY3RzXG4gIC8vIHRoZSB3b3JkIHVuZGVyIHRoZSBjdXJzb3I7IGNvdW50PTMgc2VsZWN0cyB0aGUgbGluZS4gSW5rIHJlYWRzIHRoZVxuICAvLyBzY3JlZW4gYnVmZmVyIHRvIGZpbmQgd29yZC9saW5lIGJvdW5kYXJpZXMgYW5kIG11dGF0ZXMgc2VsZWN0aW9uLFxuICAvLyBzZXR0aW5nIGlzRHJhZ2dpbmc9dHJ1ZSBzbyBhIHN1YnNlcXVlbnQgZHJhZyBleHRlbmRzIGJ5IHdvcmQvbGluZS5cbiAgcmVhZG9ubHkgb25NdWx0aUNsaWNrOiAoY29sOiBudW1iZXIsIHJvdzogbnVtYmVyLCBjb3VudDogMiB8IDMpID0+IHZvaWRcbiAgLy8gQ2FsbGVkIG9uIGRyYWctbW90aW9uLiBNb2RlLWF3YXJlOiBjaGFyIG1vZGUgdXBkYXRlcyBmb2N1cyB0byB0aGVcbiAgLy8gZXhhY3QgY2VsbDsgd29yZC9saW5lIG1vZGUgc25hcHMgdG8gd29yZC9saW5lIGJvdW5kYXJpZXMuIE5lZWRzXG4gIC8vIHNjcmVlbi1idWZmZXIgYWNjZXNzICh3b3JkIGJvdW5kYXJpZXMpIHNvIGxpdmVzIG9uIEluaywgbm90IGhlcmUuXG4gIHJlYWRvbmx5IG9uU2VsZWN0aW9uRHJhZzogKGNvbDogbnVtYmVyLCByb3c6IG51bWJlcikgPT4gdm9pZFxuICAvLyBDYWxsZWQgd2hlbiBzdGRpbiBkYXRhIGFycml2ZXMgYWZ0ZXIgYSA+U1RESU5fUkVTVU1FX0dBUF9NUyBnYXAuXG4gIC8vIEluayByZS1hc3NlcnRzIHRlcm1pbmFsIG1vZGVzOiBleHRlbmRlZCBrZXkgcmVwb3J0aW5nLCBhbmQgKHdoZW4gaW5cbiAgLy8gZnVsbHNjcmVlbikgcmUtZW50ZXJzIGFsdC1zY3JlZW4gKyBtb3VzZSB0cmFja2luZy4gSWRlbXBvdGVudCBvbiB0aGVcbiAgLy8gdGVybWluYWwgc2lkZS4gT3B0aW9uYWwgc28gdGVzdGluZy50c3ggZG9lc24ndCBuZWVkIHRvIHN0dWIgaXQuXG4gIHJlYWRvbmx5IG9uU3RkaW5SZXN1bWU/OiAoKSA9PiB2b2lkXG4gIC8vIFJlY2VpdmVzIHRoZSBkZWNsYXJlZCBuYXRpdmUtY3Vyc29yIHBvc2l0aW9uIGZyb20gdXNlRGVjbGFyZWRDdXJzb3JcbiAgLy8gc28gaW5rLnRzeCBjYW4gcGFyayB0aGUgdGVybWluYWwgY3Vyc29yIHRoZXJlIGFmdGVyIGVhY2ggZnJhbWUuXG4gIC8vIEVuYWJsZXMgSU1FIGNvbXBvc2l0aW9uIGF0IHRoZSBpbnB1dCBjYXJldCBhbmQgbGV0cyBzY3JlZW4gcmVhZGVycyAvXG4gIC8vIG1hZ25pZmllcnMgdHJhY2sgdGhlIGlucHV0LiBPcHRpb25hbCBzbyB0ZXN0aW5nLnRzeCBkb2Vzbid0IHN0dWIgaXQuXG4gIHJlYWRvbmx5IG9uQ3Vyc29yRGVjbGFyYXRpb24/OiBDdXJzb3JEZWNsYXJhdGlvblNldHRlclxuICAvLyBEaXNwYXRjaCBhIGtleWJvYXJkIGV2ZW50IHRocm91Z2ggdGhlIERPTSB0cmVlLiBDYWxsZWQgZm9yIGVhY2hcbiAgLy8gcGFyc2VkIGtleSBhbG9uZ3NpZGUgdGhlIGxlZ2FjeSBFdmVudEVtaXR0ZXIgcGF0aC5cbiAgcmVhZG9ubHkgZGlzcGF0Y2hLZXlib2FyZEV2ZW50OiAocGFyc2VkS2V5OiBQYXJzZWRLZXkpID0+IHZvaWRcbn1cblxuLy8gTXVsdGktY2xpY2sgZGV0ZWN0aW9uIHRocmVzaG9sZHMuIDUwMG1zIGlzIHRoZSBtYWNPUyBkZWZhdWx0OyBhIHNtYWxsXG4vLyBwb3NpdGlvbiB0b2xlcmFuY2UgYWxsb3dzIGZvciB0cmFja3BhZCBqaXR0ZXIgYmV0d2VlbiBjbGlja3MuXG5jb25zdCBNVUxUSV9DTElDS19USU1FT1VUX01TID0gNTAwXG5jb25zdCBNVUxUSV9DTElDS19ESVNUQU5DRSA9IDFcblxudHlwZSBTdGF0ZSA9IHtcbiAgcmVhZG9ubHkgZXJyb3I/OiBFcnJvclxufVxuXG4vLyBSb290IGNvbXBvbmVudCBmb3IgYWxsIEluayBhcHBzXG4vLyBJdCByZW5kZXJzIHN0ZGluIGFuZCBzdGRvdXQgY29udGV4dHMsIHNvIHRoYXQgY2hpbGRyZW4gY2FuIGFjY2VzcyB0aGVtIGlmIG5lZWRlZFxuLy8gSXQgYWxzbyBoYW5kbGVzIEN0cmwrQyBleGl0aW5nIGFuZCBjdXJzb3IgdmlzaWJpbGl0eVxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXBwIGV4dGVuZHMgUHVyZUNvbXBvbmVudDxQcm9wcywgU3RhdGU+IHtcbiAgc3RhdGljIGRpc3BsYXlOYW1lID0gJ0ludGVybmFsQXBwJ1xuXG4gIHN0YXRpYyBnZXREZXJpdmVkU3RhdGVGcm9tRXJyb3IoZXJyb3I6IEVycm9yKSB7XG4gICAgcmV0dXJuIHsgZXJyb3IgfVxuICB9XG5cbiAgb3ZlcnJpZGUgc3RhdGUgPSB7XG4gICAgZXJyb3I6IHVuZGVmaW5lZCxcbiAgfVxuXG4gIC8vIENvdW50IGhvdyBtYW55IGNvbXBvbmVudHMgZW5hYmxlZCByYXcgbW9kZSB0byBhdm9pZCBkaXNhYmxpbmdcbiAgLy8gcmF3IG1vZGUgdW50aWwgYWxsIGNvbXBvbmVudHMgZG9uJ3QgbmVlZCBpdCBhbnltb3JlXG4gIHJhd01vZGVFbmFibGVkQ291bnQgPSAwXG5cbiAgaW50ZXJuYWxfZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpXG4gIGtleVBhcnNlU3RhdGUgPSBJTklUSUFMX1NUQVRFXG4gIC8vIFRpbWVyIGZvciBmbHVzaGluZyBpbmNvbXBsZXRlIGVzY2FwZSBzZXF1ZW5jZXNcbiAgaW5jb21wbGV0ZUVzY2FwZVRpbWVyOiBOb2RlSlMuVGltZW91dCB8IG51bGwgPSBudWxsXG4gIC8vIFRpbWVvdXQgZHVyYXRpb25zIGZvciBpbmNvbXBsZXRlIHNlcXVlbmNlcyAobXMpXG4gIHJlYWRvbmx5IE5PUk1BTF9USU1FT1VUID0gNTAgLy8gU2hvcnQgdGltZW91dCBmb3IgcmVndWxhciBlc2Mgc2VxdWVuY2VzXG4gIHJlYWRvbmx5IFBBU1RFX1RJTUVPVVQgPSA1MDAgLy8gTG9uZ2VyIHRpbWVvdXQgZm9yIHBhc3RlIG9wZXJhdGlvbnNcblxuICAvLyBUZXJtaW5hbCBxdWVyeS9yZXNwb25zZSBkaXNwYXRjaC4gUmVzcG9uc2VzIGFycml2ZSBvbiBzdGRpbiAocGFyc2VkXG4gIC8vIG91dCBieSBwYXJzZS1rZXlwcmVzcykgYW5kIGFyZSByb3V0ZWQgdG8gcGVuZGluZyBwcm9taXNlIHJlc29sdmVycy5cbiAgcXVlcmllciA9IG5ldyBUZXJtaW5hbFF1ZXJpZXIodGhpcy5wcm9wcy5zdGRvdXQpXG5cbiAgLy8gTXVsdGktY2xpY2sgdHJhY2tpbmcgZm9yIGRvdWJsZS90cmlwbGUtY2xpY2sgdGV4dCBzZWxlY3Rpb24uIEEgY2xpY2tcbiAgLy8gd2l0aGluIE1VTFRJX0NMSUNLX1RJTUVPVVRfTVMgYW5kIE1VTFRJX0NMSUNLX0RJU1RBTkNFIG9mIHRoZSBwcmV2aW91c1xuICAvLyBjbGljayBpbmNyZW1lbnRzIGNsaWNrQ291bnQ7IG90aGVyd2lzZSBpdCByZXNldHMgdG8gMS5cbiAgbGFzdENsaWNrVGltZSA9IDBcbiAgbGFzdENsaWNrQ29sID0gLTFcbiAgbGFzdENsaWNrUm93ID0gLTFcbiAgY2xpY2tDb3VudCA9IDBcbiAgLy8gRGVmZXJyZWQgaHlwZXJsaW5rLW9wZW4gdGltZXIg4oCUIGNhbmNlbGxlZCBpZiBhIHNlY29uZCBjbGljayBhcnJpdmVzXG4gIC8vIHdpdGhpbiBNVUxUSV9DTElDS19USU1FT1VUX01TIChzbyBkb3VibGUtY2xpY2tpbmcgYSBoeXBlcmxpbmsgc2VsZWN0c1xuICAvLyB0aGUgd29yZCB3aXRob3V0IGFsc28gb3BlbmluZyB0aGUgYnJvd3NlcikuIERPTSBvbkNsaWNrIGRpc3BhdGNoIGlzXG4gIC8vIE5PVCBkZWZlcnJlZCDigJQgaXQgcmV0dXJucyB0cnVlIGZyb20gb25DbGlja0F0IGFuZCBza2lwcyB0aGlzIHRpbWVyLlxuICBwZW5kaW5nSHlwZXJsaW5rVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGxcbiAgLy8gTGFzdCBtb2RlLTEwMDMgbW90aW9uIHBvc2l0aW9uLiBUZXJtaW5hbHMgYWxyZWFkeSBkZWR1cGUgdG8gY2VsbFxuICAvLyBncmFudWxhcml0eSBidXQgdGhpcyBhbHNvIGxldHMgdXMgc2tpcCBkaXNwYXRjaEhvdmVyIGVudGlyZWx5IG9uXG4gIC8vIHJlcGVhdCBldmVudHMgKGRyYWctdGhlbi1yZWxlYXNlIGF0IHNhbWUgY2VsbCwgZXRjLikuXG4gIGxhc3RIb3ZlckNvbCA9IC0xXG4gIGxhc3RIb3ZlclJvdyA9IC0xXG5cbiAgLy8gVGltZXN0YW1wIG9mIGxhc3Qgc3RkaW4gY2h1bmsuIFVzZWQgdG8gZGV0ZWN0IGxvbmcgZ2FwcyAodG11eCBhdHRhY2gsXG4gIC8vIHNzaCByZWNvbm5lY3QsIGxhcHRvcCB3YWtlKSBhbmQgdHJpZ2dlciB0ZXJtaW5hbCBtb2RlIHJlLWFzc2VydC5cbiAgLy8gSW5pdGlhbGl6ZWQgdG8gbm93IHNvIHN0YXJ0dXAgZG9lc24ndCBmYWxzZS10cmlnZ2VyLlxuICBsYXN0U3RkaW5UaW1lID0gRGF0ZS5ub3coKVxuXG4gIC8vIERldGVybWluZXMgaWYgVFRZIGlzIHN1cHBvcnRlZCBvbiB0aGUgcHJvdmlkZWQgc3RkaW5cbiAgaXNSYXdNb2RlU3VwcG9ydGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnByb3BzLnN0ZGluLmlzVFRZXG4gIH1cblxuICBvdmVycmlkZSByZW5kZXIoKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxUZXJtaW5hbFNpemVDb250ZXh0LlByb3ZpZGVyXG4gICAgICAgIHZhbHVlPXt7XG4gICAgICAgICAgY29sdW1uczogdGhpcy5wcm9wcy50ZXJtaW5hbENvbHVtbnMsXG4gICAgICAgICAgcm93czogdGhpcy5wcm9wcy50ZXJtaW5hbFJvd3MsXG4gICAgICAgIH19XG4gICAgICA+XG4gICAgICAgIDxBcHBDb250ZXh0LlByb3ZpZGVyXG4gICAgICAgICAgdmFsdWU9e3tcbiAgICAgICAgICAgIGV4aXQ6IHRoaXMuaGFuZGxlRXhpdCxcbiAgICAgICAgICB9fVxuICAgICAgICA+XG4gICAgICAgICAgPFN0ZGluQ29udGV4dC5Qcm92aWRlclxuICAgICAgICAgICAgdmFsdWU9e3tcbiAgICAgICAgICAgICAgc3RkaW46IHRoaXMucHJvcHMuc3RkaW4sXG4gICAgICAgICAgICAgIHNldFJhd01vZGU6IHRoaXMuaGFuZGxlU2V0UmF3TW9kZSxcbiAgICAgICAgICAgICAgaXNSYXdNb2RlU3VwcG9ydGVkOiB0aGlzLmlzUmF3TW9kZVN1cHBvcnRlZCgpLFxuXG4gICAgICAgICAgICAgIGludGVybmFsX2V4aXRPbkN0cmxDOiB0aGlzLnByb3BzLmV4aXRPbkN0cmxDLFxuXG4gICAgICAgICAgICAgIGludGVybmFsX2V2ZW50RW1pdHRlcjogdGhpcy5pbnRlcm5hbF9ldmVudEVtaXR0ZXIsXG4gICAgICAgICAgICAgIGludGVybmFsX3F1ZXJpZXI6IHRoaXMucXVlcmllcixcbiAgICAgICAgICAgIH19XG4gICAgICAgICAgPlxuICAgICAgICAgICAgPFRlcm1pbmFsRm9jdXNQcm92aWRlcj5cbiAgICAgICAgICAgICAgPENsb2NrUHJvdmlkZXI+XG4gICAgICAgICAgICAgICAgPEN1cnNvckRlY2xhcmF0aW9uQ29udGV4dC5Qcm92aWRlclxuICAgICAgICAgICAgICAgICAgdmFsdWU9e3RoaXMucHJvcHMub25DdXJzb3JEZWNsYXJhdGlvbiA/PyAoKCkgPT4ge30pfVxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIHt0aGlzLnN0YXRlLmVycm9yID8gKFxuICAgICAgICAgICAgICAgICAgICA8RXJyb3JPdmVydmlldyBlcnJvcj17dGhpcy5zdGF0ZS5lcnJvciBhcyBFcnJvcn0gLz5cbiAgICAgICAgICAgICAgICAgICkgOiAoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucHJvcHMuY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAgICl9XG4gICAgICAgICAgICAgICAgPC9DdXJzb3JEZWNsYXJhdGlvbkNvbnRleHQuUHJvdmlkZXI+XG4gICAgICAgICAgICAgIDwvQ2xvY2tQcm92aWRlcj5cbiAgICAgICAgICAgIDwvVGVybWluYWxGb2N1c1Byb3ZpZGVyPlxuICAgICAgICAgIDwvU3RkaW5Db250ZXh0LlByb3ZpZGVyPlxuICAgICAgICA8L0FwcENvbnRleHQuUHJvdmlkZXI+XG4gICAgICA8L1Rlcm1pbmFsU2l6ZUNvbnRleHQuUHJvdmlkZXI+XG4gICAgKVxuICB9XG5cbiAgb3ZlcnJpZGUgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgLy8gSW4gYWNjZXNzaWJpbGl0eSBtb2RlLCBrZWVwIHRoZSBuYXRpdmUgY3Vyc29yIHZpc2libGUgZm9yIHNjcmVlbiBtYWduaWZpZXJzIGFuZCBvdGhlciB0b29sc1xuICAgIGlmIChcbiAgICAgIHRoaXMucHJvcHMuc3Rkb3V0LmlzVFRZICYmXG4gICAgICAhaXNFbnZUcnV0aHkocHJvY2Vzcy5lbnYuQ0xBVURFX0NPREVfQUNDRVNTSUJJTElUWSlcbiAgICApIHtcbiAgICAgIHRoaXMucHJvcHMuc3Rkb3V0LndyaXRlKEhJREVfQ1VSU09SKVxuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgIGlmICh0aGlzLnByb3BzLnN0ZG91dC5pc1RUWSkge1xuICAgICAgdGhpcy5wcm9wcy5zdGRvdXQud3JpdGUoU0hPV19DVVJTT1IpXG4gICAgfVxuXG4gICAgLy8gQ2xlYXIgYW55IHBlbmRpbmcgdGltZXJzXG4gICAgaWYgKHRoaXMuaW5jb21wbGV0ZUVzY2FwZVRpbWVyKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5pbmNvbXBsZXRlRXNjYXBlVGltZXIpXG4gICAgICB0aGlzLmluY29tcGxldGVFc2NhcGVUaW1lciA9IG51bGxcbiAgICB9XG4gICAgaWYgKHRoaXMucGVuZGluZ0h5cGVybGlua1RpbWVyKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5wZW5kaW5nSHlwZXJsaW5rVGltZXIpXG4gICAgICB0aGlzLnBlbmRpbmdIeXBlcmxpbmtUaW1lciA9IG51bGxcbiAgICB9XG4gICAgLy8gaWdub3JlIGNhbGxpbmcgc2V0UmF3TW9kZSBvbiBhbiBoYW5kbGUgc3RkaW4gaXQgY2Fubm90IGJlIGNhbGxlZFxuICAgIGlmICh0aGlzLmlzUmF3TW9kZVN1cHBvcnRlZCgpKSB7XG4gICAgICB0aGlzLmhhbmRsZVNldFJhd01vZGUoZmFsc2UpXG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgY29tcG9uZW50RGlkQ2F0Y2goZXJyb3I6IEVycm9yKSB7XG4gICAgdGhpcy5oYW5kbGVFeGl0KGVycm9yKVxuICB9XG5cbiAgaGFuZGxlU2V0UmF3TW9kZSA9IChpc0VuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkID0+IHtcbiAgICBjb25zdCB7IHN0ZGluIH0gPSB0aGlzLnByb3BzXG5cbiAgICBpZiAoIXRoaXMuaXNSYXdNb2RlU3VwcG9ydGVkKCkpIHtcbiAgICAgIGlmIChzdGRpbiA9PT0gcHJvY2Vzcy5zdGRpbikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ1JhdyBtb2RlIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIGN1cnJlbnQgcHJvY2Vzcy5zdGRpbiwgd2hpY2ggSW5rIHVzZXMgYXMgaW5wdXQgc3RyZWFtIGJ5IGRlZmF1bHQuXFxuUmVhZCBhYm91dCBob3cgdG8gcHJldmVudCB0aGlzIGVycm9yIG9uIGh0dHBzOi8vZ2l0aHViLmNvbS92YWRpbWRlbWVkZXMvaW5rLyNpc3Jhd21vZGVzdXBwb3J0ZWQnLFxuICAgICAgICApXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ1JhdyBtb2RlIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIHN0ZGluIHByb3ZpZGVkIHRvIEluay5cXG5SZWFkIGFib3V0IGhvdyB0byBwcmV2ZW50IHRoaXMgZXJyb3Igb24gaHR0cHM6Ly9naXRodWIuY29tL3ZhZGltZGVtZWRlcy9pbmsvI2lzcmF3bW9kZXN1cHBvcnRlZCcsXG4gICAgICAgIClcbiAgICAgIH1cbiAgICB9XG5cbiAgICBzdGRpbi5zZXRFbmNvZGluZygndXRmOCcpXG5cbiAgICBpZiAoaXNFbmFibGVkKSB7XG4gICAgICAvLyBFbnN1cmUgcmF3IG1vZGUgaXMgZW5hYmxlZCBvbmx5IG9uY2VcbiAgICAgIGlmICh0aGlzLnJhd01vZGVFbmFibGVkQ291bnQgPT09IDApIHtcbiAgICAgICAgLy8gU3RvcCBlYXJseSBpbnB1dCBjYXB0dXJlIHJpZ2h0IGJlZm9yZSB3ZSBhZGQgb3VyIG93biByZWFkYWJsZSBoYW5kbGVyLlxuICAgICAgICAvLyBCb3RoIHVzZSB0aGUgc2FtZSBzdGRpbiAncmVhZGFibGUnICsgcmVhZCgpIHBhdHRlcm4sIHNvIHRoZXkgY2FuJ3RcbiAgICAgICAgLy8gY29leGlzdCAtLSBvdXIgaGFuZGxlciB3b3VsZCBkcmFpbiBzdGRpbiBiZWZvcmUgSW5rJ3MgY2FuIHNlZSBpdC5cbiAgICAgICAgLy8gVGhlIGJ1ZmZlcmVkIHRleHQgaXMgcHJlc2VydmVkIGZvciBSRVBMLnRzeCB2aWEgY29uc3VtZUVhcmx5SW5wdXQoKS5cbiAgICAgICAgc3RvcENhcHR1cmluZ0Vhcmx5SW5wdXQoKVxuICAgICAgICBzdGRpbi5yZWYoKVxuICAgICAgICBzdGRpbi5zZXRSYXdNb2RlKHRydWUpXG4gICAgICAgIHN0ZGluLmFkZExpc3RlbmVyKCdyZWFkYWJsZScsIHRoaXMuaGFuZGxlUmVhZGFibGUpXG4gICAgICAgIC8vIEVuYWJsZSBicmFja2V0ZWQgcGFzdGUgbW9kZVxuICAgICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShFQlApXG4gICAgICAgIC8vIEVuYWJsZSB0ZXJtaW5hbCBmb2N1cyByZXBvcnRpbmcgKERFQ1NFVCAxMDA0KVxuICAgICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShFRkUpXG4gICAgICAgIC8vIEVuYWJsZSBleHRlbmRlZCBrZXkgcmVwb3J0aW5nIHNvIGN0cmwrc2hpZnQrPGxldHRlcj4gaXNcbiAgICAgICAgLy8gZGlzdGluZ3Vpc2hhYmxlIGZyb20gY3RybCs8bGV0dGVyPi4gV2Ugd3JpdGUgYm90aCB0aGUga2l0dHkgc3RhY2tcbiAgICAgICAgLy8gcHVzaCAoQ1NJID4xdSkgYW5kIHh0ZXJtIG1vZGlmeU90aGVyS2V5cyBsZXZlbCAyIChDU0kgPjQ7Mm0pIOKAlFxuICAgICAgICAvLyB0ZXJtaW5hbHMgaG9ub3Igd2hpY2hldmVyIHRoZXkgaW1wbGVtZW50ICh0bXV4IG9ubHkgYWNjZXB0cyB0aGVcbiAgICAgICAgLy8gbGF0dGVyKS5cbiAgICAgICAgaWYgKHN1cHBvcnRzRXh0ZW5kZWRLZXlzKCkpIHtcbiAgICAgICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShFTkFCTEVfS0lUVFlfS0VZQk9BUkQpXG4gICAgICAgICAgdGhpcy5wcm9wcy5zdGRvdXQud3JpdGUoRU5BQkxFX01PRElGWV9PVEhFUl9LRVlTKVxuICAgICAgICB9XG4gICAgICAgIC8vIFByb2JlIHRlcm1pbmFsIGlkZW50aXR5LiBYVFZFUlNJT04gc3Vydml2ZXMgU1NIIChxdWVyeS9yZXBseSBnb2VzXG4gICAgICAgIC8vIHRocm91Z2ggdGhlIHB0eSksIHVubGlrZSBURVJNX1BST0dSQU0uIFVzZWQgZm9yIHdoZWVsLXNjcm9sbCBiYXNlXG4gICAgICAgIC8vIGRldGVjdGlvbiB3aGVuIGVudiB2YXJzIGFyZSBhYnNlbnQuIEZpcmUtYW5kLWZvcmdldDogdGhlIERBMVxuICAgICAgICAvLyBzZW50aW5lbCBib3VuZHMgdGhlIHJvdW5kLXRyaXAsIGFuZCBpZiB0aGUgdGVybWluYWwgaWdub3JlcyB0aGVcbiAgICAgICAgLy8gcXVlcnksIGZsdXNoKCkgc3RpbGwgcmVzb2x2ZXMgYW5kIG5hbWUgc3RheXMgdW5kZWZpbmVkLlxuICAgICAgICAvLyBEZWZlcnJlZCB0byBuZXh0IHRpY2sgc28gaXQgZmlyZXMgQUZURVIgdGhlIGN1cnJlbnQgc3luY2hyb25vdXNcbiAgICAgICAgLy8gaW5pdCBzZXF1ZW5jZSBjb21wbGV0ZXMg4oCUIGF2b2lkcyBpbnRlcmxlYXZpbmcgd2l0aCBhbHQtc2NyZWVuL21vdXNlXG4gICAgICAgIC8vIHRyYWNraW5nIGVuYWJsZSB3cml0ZXMgdGhhdCBtYXkgaGFwcGVuIGluIHRoZSBzYW1lIHJlbmRlciBjeWNsZS5cbiAgICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHtcbiAgICAgICAgICB2b2lkIFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIHRoaXMucXVlcmllci5zZW5kKHh0dmVyc2lvbigpKSxcbiAgICAgICAgICAgIHRoaXMucXVlcmllci5mbHVzaCgpLFxuICAgICAgICAgIF0pLnRoZW4oKFtyXSkgPT4ge1xuICAgICAgICAgICAgaWYgKHIpIHtcbiAgICAgICAgICAgICAgc2V0WHR2ZXJzaW9uTmFtZShyLm5hbWUpXG4gICAgICAgICAgICAgIGxvZ0ZvckRlYnVnZ2luZyhgWFRWRVJTSU9OOiB0ZXJtaW5hbCBpZGVudGlmaWVkIGFzIFwiJHtyLm5hbWV9XCJgKVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgbG9nRm9yRGVidWdnaW5nKCdYVFZFUlNJT046IG5vIHJlcGx5ICh0ZXJtaW5hbCBpZ25vcmVkIHF1ZXJ5KScpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgfSlcbiAgICAgIH1cblxuICAgICAgdGhpcy5yYXdNb2RlRW5hYmxlZENvdW50KytcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIERpc2FibGUgcmF3IG1vZGUgb25seSB3aGVuIG5vIGNvbXBvbmVudHMgbGVmdCB0aGF0IGFyZSB1c2luZyBpdFxuICAgIGlmICgtLXRoaXMucmF3TW9kZUVuYWJsZWRDb3VudCA9PT0gMCkge1xuICAgICAgdGhpcy5wcm9wcy5zdGRvdXQud3JpdGUoRElTQUJMRV9NT0RJRllfT1RIRVJfS0VZUylcbiAgICAgIHRoaXMucHJvcHMuc3Rkb3V0LndyaXRlKERJU0FCTEVfS0lUVFlfS0VZQk9BUkQpXG4gICAgICAvLyBEaXNhYmxlIHRlcm1pbmFsIGZvY3VzIHJlcG9ydGluZyAoREVDU0VUIDEwMDQpXG4gICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShERkUpXG4gICAgICAvLyBEaXNhYmxlIGJyYWNrZXRlZCBwYXN0ZSBtb2RlXG4gICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShEQlApXG4gICAgICBzdGRpbi5zZXRSYXdNb2RlKGZhbHNlKVxuICAgICAgc3RkaW4ucmVtb3ZlTGlzdGVuZXIoJ3JlYWRhYmxlJywgdGhpcy5oYW5kbGVSZWFkYWJsZSlcbiAgICAgIHN0ZGluLnVucmVmKClcbiAgICB9XG4gIH1cblxuICAvLyBIZWxwZXIgdG8gZmx1c2ggaW5jb21wbGV0ZSBlc2NhcGUgc2VxdWVuY2VzXG4gIGZsdXNoSW5jb21wbGV0ZSA9ICgpOiB2b2lkID0+IHtcbiAgICAvLyBDbGVhciB0aGUgdGltZXIgcmVmZXJlbmNlXG4gICAgdGhpcy5pbmNvbXBsZXRlRXNjYXBlVGltZXIgPSBudWxsXG5cbiAgICAvLyBPbmx5IHByb2NlZWQgaWYgd2UgaGF2ZSBpbmNvbXBsZXRlIHNlcXVlbmNlc1xuICAgIGlmICghdGhpcy5rZXlQYXJzZVN0YXRlLmluY29tcGxldGUpIHJldHVyblxuXG4gICAgLy8gRnVsbHNjcmVlbjogaWYgc3RkaW4gaGFzIGRhdGEgd2FpdGluZywgaXQncyBhbG1vc3QgY2VydGFpbmx5IHRoZVxuICAgIC8vIGNvbnRpbnVhdGlvbiBvZiB0aGUgYnVmZmVyZWQgc2VxdWVuY2UgKGUuZy4gYFs8NjQ7NzQ7MTZNYCBhZnRlciBhXG4gICAgLy8gbG9uZSBFU0MpLiBOb2RlJ3MgZXZlbnQgbG9vcCBydW5zIHRoZSB0aW1lcnMgcGhhc2UgYmVmb3JlIHRoZSBwb2xsXG4gICAgLy8gcGhhc2UsIHNvIHdoZW4gYSBoZWF2eSByZW5kZXIgYmxvY2tzIHRoZSBsb29wIHBhc3QgNTBtcywgdGhpcyB0aW1lclxuICAgIC8vIGZpcmVzIGJlZm9yZSB0aGUgcXVldWVkIHJlYWRhYmxlIGV2ZW50IGV2ZW4gdGhvdWdoIHRoZSBieXRlcyBhcmVcbiAgICAvLyBhbHJlYWR5IGJ1ZmZlcmVkLiBSZS1hcm0gaW5zdGVhZCBvZiBmbHVzaGluZzogaGFuZGxlUmVhZGFibGUgd2lsbFxuICAgIC8vIGRyYWluIHN0ZGluIG5leHQgYW5kIGNsZWFyIHRoaXMgdGltZXIuIFByZXZlbnRzIGJvdGggdGhlIHNwdXJpb3VzXG4gICAgLy8gRXNjYXBlIGtleSBhbmQgdGhlIGxvc3Qgc2Nyb2xsIGV2ZW50LlxuICAgIGlmICh0aGlzLnByb3BzLnN0ZGluLnJlYWRhYmxlTGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5pbmNvbXBsZXRlRXNjYXBlVGltZXIgPSBzZXRUaW1lb3V0KFxuICAgICAgICB0aGlzLmZsdXNoSW5jb21wbGV0ZSxcbiAgICAgICAgdGhpcy5OT1JNQUxfVElNRU9VVCxcbiAgICAgIClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIFByb2Nlc3MgaW5jb21wbGV0ZSBhcyBhIGZsdXNoIG9wZXJhdGlvbiAoaW5wdXQ9bnVsbClcbiAgICAvLyBUaGlzIHJldXNlcyBhbGwgZXhpc3RpbmcgcGFyc2luZyBsb2dpY1xuICAgIHRoaXMucHJvY2Vzc0lucHV0KG51bGwpXG4gIH1cblxuICAvLyBQcm9jZXNzIGlucHV0IHRocm91Z2ggdGhlIHBhcnNlciBhbmQgaGFuZGxlIHRoZSByZXN1bHRzXG4gIHByb2Nlc3NJbnB1dCA9IChpbnB1dDogc3RyaW5nIHwgQnVmZmVyIHwgbnVsbCk6IHZvaWQgPT4ge1xuICAgIC8vIFBhcnNlIGlucHV0IHVzaW5nIG91ciBzdGF0ZSBtYWNoaW5lXG4gICAgY29uc3QgW2tleXMsIG5ld1N0YXRlXSA9IHBhcnNlTXVsdGlwbGVLZXlwcmVzc2VzKHRoaXMua2V5UGFyc2VTdGF0ZSwgaW5wdXQpXG4gICAgdGhpcy5rZXlQYXJzZVN0YXRlID0gbmV3U3RhdGVcblxuICAgIC8vIFByb2Nlc3MgQUxMIGtleXMgaW4gYSBTSU5HTEUgZGlzY3JldGVVcGRhdGVzIGNhbGwgdG8gcHJldmVudFxuICAgIC8vIFwiTWF4aW11bSB1cGRhdGUgZGVwdGggZXhjZWVkZWRcIiBlcnJvciB3aGVuIG1hbnkga2V5cyBhcnJpdmUgYXQgb25jZVxuICAgIC8vIChlLmcuLCBmcm9tIHBhc3RlIG9wZXJhdGlvbnMgb3IgaG9sZGluZyBrZXlzIHJhcGlkbHkpLlxuICAgIC8vIFRoaXMgYmF0Y2hlcyBhbGwgc3RhdGUgdXBkYXRlcyBmcm9tIGhhbmRsZUlucHV0IGFuZCBhbGwgdXNlSW5wdXRcbiAgICAvLyBsaXN0ZW5lcnMgdG9nZXRoZXIgd2l0aGluIG9uZSBoaWdoLXByaW9yaXR5IHVwZGF0ZSBjb250ZXh0LlxuICAgIGlmIChrZXlzLmxlbmd0aCA+IDApIHtcbiAgICAgIHJlY29uY2lsZXIuZGlzY3JldGVVcGRhdGVzKFxuICAgICAgICBwcm9jZXNzS2V5c0luQmF0Y2gsXG4gICAgICAgIHRoaXMsXG4gICAgICAgIGtleXMsXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgKVxuICAgIH1cblxuICAgIC8vIElmIHdlIGhhdmUgaW5jb21wbGV0ZSBlc2NhcGUgc2VxdWVuY2VzLCBzZXQgYSB0aW1lciB0byBmbHVzaCB0aGVtXG4gICAgaWYgKHRoaXMua2V5UGFyc2VTdGF0ZS5pbmNvbXBsZXRlKSB7XG4gICAgICAvLyBDYW5jZWwgYW55IGV4aXN0aW5nIHRpbWVyIGZpcnN0XG4gICAgICBpZiAodGhpcy5pbmNvbXBsZXRlRXNjYXBlVGltZXIpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuaW5jb21wbGV0ZUVzY2FwZVRpbWVyKVxuICAgICAgfVxuICAgICAgdGhpcy5pbmNvbXBsZXRlRXNjYXBlVGltZXIgPSBzZXRUaW1lb3V0KFxuICAgICAgICB0aGlzLmZsdXNoSW5jb21wbGV0ZSxcbiAgICAgICAgdGhpcy5rZXlQYXJzZVN0YXRlLm1vZGUgPT09ICdJTl9QQVNURSdcbiAgICAgICAgICA/IHRoaXMuUEFTVEVfVElNRU9VVFxuICAgICAgICAgIDogdGhpcy5OT1JNQUxfVElNRU9VVCxcbiAgICAgIClcbiAgICB9XG4gIH1cblxuICBoYW5kbGVSZWFkYWJsZSA9ICgpOiB2b2lkID0+IHtcbiAgICAvLyBEZXRlY3QgbG9uZyBzdGRpbiBnYXBzICh0bXV4IGF0dGFjaCwgc3NoIHJlY29ubmVjdCwgbGFwdG9wIHdha2UpLlxuICAgIC8vIFRoZSB0ZXJtaW5hbCBtYXkgaGF2ZSByZXNldCBERUMgcHJpdmF0ZSBtb2RlczsgcmUtYXNzZXJ0IG1vdXNlXG4gICAgLy8gdHJhY2tpbmcuIENoZWNrZWQgYmVmb3JlIHRoZSByZWFkIGxvb3Agc28gb25lIERhdGUubm93KCkgY292ZXJzXG4gICAgLy8gYWxsIGNodW5rcyBpbiB0aGlzIHJlYWRhYmxlIGV2ZW50LlxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KClcbiAgICBpZiAobm93IC0gdGhpcy5sYXN0U3RkaW5UaW1lID4gU1RESU5fUkVTVU1FX0dBUF9NUykge1xuICAgICAgdGhpcy5wcm9wcy5vblN0ZGluUmVzdW1lPy4oKVxuICAgIH1cbiAgICB0aGlzLmxhc3RTdGRpblRpbWUgPSBub3dcbiAgICB0cnkge1xuICAgICAgbGV0IGNodW5rXG4gICAgICB3aGlsZSAoKGNodW5rID0gdGhpcy5wcm9wcy5zdGRpbi5yZWFkKCkgYXMgc3RyaW5nIHwgbnVsbCkgIT09IG51bGwpIHtcbiAgICAgICAgLy8gUHJvY2VzcyB0aGUgaW5wdXQgY2h1bmtcbiAgICAgICAgdGhpcy5wcm9jZXNzSW5wdXQoY2h1bmspXG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIEluIEJ1biwgYW4gdW5jYXVnaHQgdGhyb3cgaW5zaWRlIGEgc3RyZWFtICdyZWFkYWJsZScgaGFuZGxlciBjYW5cbiAgICAgIC8vIHBlcm1hbmVudGx5IHdlZGdlIHRoZSBzdHJlYW06IGRhdGEgc3RheXMgYnVmZmVyZWQgYW5kICdyZWFkYWJsZSdcbiAgICAgIC8vIG5ldmVyIHJlLWVtaXRzLiBDYXRjaGluZyBoZXJlIGVuc3VyZXMgdGhlIHN0cmVhbSBzdGF5cyBoZWFsdGh5IHNvXG4gICAgICAvLyBzdWJzZXF1ZW50IGtleXN0cm9rZXMgYXJlIHN0aWxsIGRlbGl2ZXJlZC5cbiAgICAgIGxvZ0Vycm9yKGVycm9yKVxuXG4gICAgICAvLyBSZS1hdHRhY2ggdGhlIGxpc3RlbmVyIGluIGNhc2UgdGhlIGV4Y2VwdGlvbiBkZXRhY2hlZCBpdC5cbiAgICAgIC8vIEJ1biBtYXkgcmVtb3ZlIHRoZSBsaXN0ZW5lciBhZnRlciBhbiBlcnJvcjsgd2l0aG91dCB0aGlzLFxuICAgICAgLy8gdGhlIHNlc3Npb24gZnJlZXplcyBwZXJtYW5lbnRseSAoc3RkaW4gcmVhZGVyIGRlYWQsIGV2ZW50IGxvb3AgYWxpdmUpLlxuICAgICAgY29uc3QgeyBzdGRpbiB9ID0gdGhpcy5wcm9wc1xuICAgICAgaWYgKFxuICAgICAgICB0aGlzLnJhd01vZGVFbmFibGVkQ291bnQgPiAwICYmXG4gICAgICAgICFzdGRpbi5saXN0ZW5lcnMoJ3JlYWRhYmxlJykuaW5jbHVkZXModGhpcy5oYW5kbGVSZWFkYWJsZSlcbiAgICAgICkge1xuICAgICAgICBsb2dGb3JEZWJ1Z2dpbmcoXG4gICAgICAgICAgJ2hhbmRsZVJlYWRhYmxlOiByZS1hdHRhY2hpbmcgc3RkaW4gcmVhZGFibGUgbGlzdGVuZXIgYWZ0ZXIgZXJyb3IgcmVjb3ZlcnknLFxuICAgICAgICAgIHsgbGV2ZWw6ICd3YXJuJyB9LFxuICAgICAgICApXG4gICAgICAgIHN0ZGluLmFkZExpc3RlbmVyKCdyZWFkYWJsZScsIHRoaXMuaGFuZGxlUmVhZGFibGUpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlSW5wdXQgPSAoaW5wdXQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHZvaWQgPT4ge1xuICAgIC8vIEV4aXQgb24gQ3RybCtDXG4gICAgaWYgKGlucHV0ID09PSAnXFx4MDMnICYmIHRoaXMucHJvcHMuZXhpdE9uQ3RybEMpIHtcbiAgICAgIHRoaXMuaGFuZGxlRXhpdCgpXG4gICAgfVxuXG4gICAgLy8gTm90ZTogQ3RybCtaIChzdXNwZW5kKSBpcyBub3cgaGFuZGxlZCBpbiBwcm9jZXNzS2V5c0luQmF0Y2ggdXNpbmcgdGhlXG4gICAgLy8gcGFyc2VkIGtleSB0byBzdXBwb3J0IGJvdGggcmF3IChcXHgxYSkgYW5kIENTSSB1IGZvcm1hdCBmcm9tIEtpdHR5XG4gICAgLy8ga2V5Ym9hcmQgcHJvdG9jb2wgdGVybWluYWxzIChHaG9zdHR5LCBpVGVybTIsIGtpdHR5LCBXZXpUZXJtKVxuICB9XG5cbiAgaGFuZGxlRXhpdCA9IChlcnJvcj86IEVycm9yKTogdm9pZCA9PiB7XG4gICAgaWYgKHRoaXMuaXNSYXdNb2RlU3VwcG9ydGVkKCkpIHtcbiAgICAgIHRoaXMuaGFuZGxlU2V0UmF3TW9kZShmYWxzZSlcbiAgICB9XG5cbiAgICB0aGlzLnByb3BzLm9uRXhpdChlcnJvcilcbiAgfVxuXG4gIGhhbmRsZVRlcm1pbmFsRm9jdXMgPSAoaXNGb2N1c2VkOiBib29sZWFuKTogdm9pZCA9PiB7XG4gICAgLy8gc2V0VGVybWluYWxGb2N1c2VkIG5vdGlmaWVzIHN1YnNjcmliZXJzOiBUZXJtaW5hbEZvY3VzUHJvdmlkZXIgKGNvbnRleHQpXG4gICAgLy8gYW5kIENsb2NrIChpbnRlcnZhbCBzcGVlZCkg4oCUIG5vIEFwcCBzZXRTdGF0ZSBuZWVkZWQuXG4gICAgc2V0VGVybWluYWxGb2N1c2VkKGlzRm9jdXNlZClcbiAgfVxuXG4gIGhhbmRsZVN1c3BlbmQgPSAoKTogdm9pZCA9PiB7XG4gICAgaWYgKCF0aGlzLmlzUmF3TW9kZVN1cHBvcnRlZCgpKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBTdG9yZSB0aGUgZXhhY3QgcmF3IG1vZGUgY291bnQgdG8gcmVzdG9yZSBpdCBwcm9wZXJseVxuICAgIGNvbnN0IHJhd01vZGVDb3VudEJlZm9yZVN1c3BlbmQgPSB0aGlzLnJhd01vZGVFbmFibGVkQ291bnRcblxuICAgIC8vIENvbXBsZXRlbHkgZGlzYWJsZSByYXcgbW9kZSBiZWZvcmUgc3VzcGVuZGluZ1xuICAgIHdoaWxlICh0aGlzLnJhd01vZGVFbmFibGVkQ291bnQgPiAwKSB7XG4gICAgICB0aGlzLmhhbmRsZVNldFJhd01vZGUoZmFsc2UpXG4gICAgfVxuXG4gICAgLy8gU2hvdyBjdXJzb3IsIGRpc2FibGUgZm9jdXMgcmVwb3J0aW5nLCBhbmQgZGlzYWJsZSBtb3VzZSB0cmFja2luZ1xuICAgIC8vIGJlZm9yZSBzdXNwZW5kaW5nLiBESVNBQkxFX01PVVNFX1RSQUNLSU5HIGlzIGEgbm8tb3AgaWYgdHJhY2tpbmdcbiAgICAvLyB3YXNuJ3QgZW5hYmxlZCwgc28gaXQncyBzYWZlIHRvIGVtaXQgdW5jb25kaXRpb25hbGx5IOKAlCB3aXRob3V0XG4gICAgLy8gaXQsIFNHUiBtb3VzZSBzZXF1ZW5jZXMgd291bGQgYXBwZWFyIGFzIGdhcmJsZWQgdGV4dCBhdCB0aGVcbiAgICAvLyBzaGVsbCBwcm9tcHQgd2hpbGUgc3VzcGVuZGVkLlxuICAgIGlmICh0aGlzLnByb3BzLnN0ZG91dC5pc1RUWSkge1xuICAgICAgdGhpcy5wcm9wcy5zdGRvdXQud3JpdGUoU0hPV19DVVJTT1IgKyBERkUgKyBESVNBQkxFX01PVVNFX1RSQUNLSU5HKVxuICAgIH1cblxuICAgIC8vIEVtaXQgc3VzcGVuZCBldmVudCBmb3IgQ2xhdWRlIENvZGUgdG8gaGFuZGxlLiBNb3N0bHkganVzdCBoYXMgYSBub3RpZmljYXRpb25cbiAgICB0aGlzLmludGVybmFsX2V2ZW50RW1pdHRlci5lbWl0KCdzdXNwZW5kJylcblxuICAgIC8vIFNldCB1cCByZXN1bWUgaGFuZGxlclxuICAgIGNvbnN0IHJlc3VtZUhhbmRsZXIgPSAoKSA9PiB7XG4gICAgICAvLyBSZXN0b3JlIHJhdyBtb2RlIHRvIGV4YWN0IHByZXZpb3VzIHN0YXRlXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJhd01vZGVDb3VudEJlZm9yZVN1c3BlbmQ7IGkrKykge1xuICAgICAgICBpZiAodGhpcy5pc1Jhd01vZGVTdXBwb3J0ZWQoKSkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlU2V0UmF3TW9kZSh0cnVlKVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEhpZGUgY3Vyc29yICh1bmxlc3MgaW4gYWNjZXNzaWJpbGl0eSBtb2RlKSBhbmQgcmUtZW5hYmxlIGZvY3VzIHJlcG9ydGluZyBhZnRlciByZXN1bWluZ1xuICAgICAgaWYgKHRoaXMucHJvcHMuc3Rkb3V0LmlzVFRZKSB7XG4gICAgICAgIGlmICghaXNFbnZUcnV0aHkocHJvY2Vzcy5lbnYuQ0xBVURFX0NPREVfQUNDRVNTSUJJTElUWSkpIHtcbiAgICAgICAgICB0aGlzLnByb3BzLnN0ZG91dC53cml0ZShISURFX0NVUlNPUilcbiAgICAgICAgfVxuICAgICAgICAvLyBSZS1lbmFibGUgZm9jdXMgcmVwb3J0aW5nIHRvIHJlc3RvcmUgdGVybWluYWwgc3RhdGVcbiAgICAgICAgdGhpcy5wcm9wcy5zdGRvdXQud3JpdGUoRUZFKVxuICAgICAgfVxuXG4gICAgICAvLyBFbWl0IHJlc3VtZSBldmVudCBmb3IgQ2xhdWRlIENvZGUgdG8gaGFuZGxlXG4gICAgICB0aGlzLmludGVybmFsX2V2ZW50RW1pdHRlci5lbWl0KCdyZXN1bWUnKVxuXG4gICAgICBwcm9jZXNzLnJlbW92ZUxpc3RlbmVyKCdTSUdDT05UJywgcmVzdW1lSGFuZGxlcilcbiAgICB9XG5cbiAgICBwcm9jZXNzLm9uKCdTSUdDT05UJywgcmVzdW1lSGFuZGxlcilcbiAgICBwcm9jZXNzLmtpbGwocHJvY2Vzcy5waWQsICdTSUdTVE9QJylcbiAgfVxufVxuXG4vLyBIZWxwZXIgdG8gcHJvY2VzcyBhbGwga2V5cyB3aXRoaW4gYSBzaW5nbGUgZGlzY3JldGUgdXBkYXRlIGNvbnRleHQuXG4vLyBkaXNjcmV0ZVVwZGF0ZXMgZXhwZWN0cyAoZm4sIGEsIGIsIGMsIGQpIC0+IGZuKGEsIGIsIGMsIGQpXG5mdW5jdGlvbiBwcm9jZXNzS2V5c0luQmF0Y2goXG4gIGFwcDogQXBwLFxuICBpdGVtczogUGFyc2VkSW5wdXRbXSxcbiAgX3VudXNlZDE6IHVuZGVmaW5lZCxcbiAgX3VudXNlZDI6IHVuZGVmaW5lZCxcbik6IHZvaWQge1xuICAvLyBVcGRhdGUgaW50ZXJhY3Rpb24gdGltZSBmb3Igbm90aWZpY2F0aW9uIHRpbWVvdXQgdHJhY2tpbmcuXG4gIC8vIFRoaXMgaXMgY2FsbGVkIGZyb20gdGhlIGNlbnRyYWwgaW5wdXQgaGFuZGxlciB0byBhdm9pZCBoYXZpbmcgbXVsdGlwbGVcbiAgLy8gc3RkaW4gbGlzdGVuZXJzIHRoYXQgY2FuIGNhdXNlIHJhY2UgY29uZGl0aW9ucyBhbmQgZHJvcHBlZCBpbnB1dC5cbiAgLy8gVGVybWluYWwgcmVzcG9uc2VzIChraW5kOiAncmVzcG9uc2UnKSBhcmUgYXV0b21hdGVkLCBub3QgdXNlciBpbnB1dC5cbiAgLy8gTW9kZS0xMDAzIG5vLWJ1dHRvbiBtb3Rpb24gaXMgYWxzbyBleGNsdWRlZCDigJQgcGFzc2l2ZSBjdXJzb3IgZHJpZnQgaXNcbiAgLy8gbm90IGVuZ2FnZW1lbnQgKHdvdWxkIHN1cHByZXNzIGlkbGUgbm90aWZpY2F0aW9ucyArIGRlZmVyIGhvdXNla2VlcGluZykuXG4gIGlmIChcbiAgICBpdGVtcy5zb21lKFxuICAgICAgaSA9PlxuICAgICAgICBpLmtpbmQgPT09ICdrZXknIHx8XG4gICAgICAgIChpLmtpbmQgPT09ICdtb3VzZScgJiZcbiAgICAgICAgICAhKChpLmJ1dHRvbiAmIDB4MjApICE9PSAwICYmIChpLmJ1dHRvbiAmIDB4MDMpID09PSAzKSksXG4gICAgKVxuICApIHtcbiAgICB1cGRhdGVMYXN0SW50ZXJhY3Rpb25UaW1lKClcbiAgfVxuXG4gIGZvciAoY29uc3QgaXRlbSBvZiBpdGVtcykge1xuICAgIC8vIFRlcm1pbmFsIHJlc3BvbnNlcyAoREVDUlBNLCBEQTEsIE9TQyByZXBsaWVzLCBldGMuKSBhcmUgbm90IHVzZXJcbiAgICAvLyBpbnB1dCDigJQgcm91dGUgdGhlbSB0byB0aGUgcXVlcmllciB0byByZXNvbHZlIHBlbmRpbmcgcHJvbWlzZXMuXG4gICAgaWYgKGl0ZW0ua2luZCA9PT0gJ3Jlc3BvbnNlJykge1xuICAgICAgYXBwLnF1ZXJpZXIub25SZXNwb25zZShpdGVtLnJlc3BvbnNlKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICAvLyBNb3VzZSBjbGljay9kcmFnIGV2ZW50cyB1cGRhdGUgc2VsZWN0aW9uIHN0YXRlIChmdWxsc2NyZWVuIG9ubHkpLlxuICAgIC8vIFRlcm1pbmFsIHNlbmRzIDEtaW5kZXhlZCBjb2wvcm93OyBjb252ZXJ0IHRvIDAtaW5kZXhlZCBmb3IgdGhlXG4gICAgLy8gc2NyZWVuIGJ1ZmZlci4gQnV0dG9uIGJpdCAweDIwID0gZHJhZyAobW90aW9uIHdoaWxlIGJ1dHRvbiBoZWxkKS5cbiAgICBpZiAoaXRlbS5raW5kID09PSAnbW91c2UnKSB7XG4gICAgICBoYW5kbGVNb3VzZUV2ZW50KGFwcCwgaXRlbSlcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgY29uc3Qgc2VxdWVuY2UgPSBpdGVtLnNlcXVlbmNlXG5cbiAgICAvLyBIYW5kbGUgdGVybWluYWwgZm9jdXMgZXZlbnRzIChERUNTRVQgMTAwNClcbiAgICBpZiAoc2VxdWVuY2UgPT09IEZPQ1VTX0lOKSB7XG4gICAgICBhcHAuaGFuZGxlVGVybWluYWxGb2N1cyh0cnVlKVxuICAgICAgY29uc3QgZXZlbnQgPSBuZXcgVGVybWluYWxGb2N1c0V2ZW50KCd0ZXJtaW5hbGZvY3VzJylcbiAgICAgIGFwcC5pbnRlcm5hbF9ldmVudEVtaXR0ZXIuZW1pdCgndGVybWluYWxmb2N1cycsIGV2ZW50KVxuICAgICAgY29udGludWVcbiAgICB9XG4gICAgaWYgKHNlcXVlbmNlID09PSBGT0NVU19PVVQpIHtcbiAgICAgIGFwcC5oYW5kbGVUZXJtaW5hbEZvY3VzKGZhbHNlKVxuICAgICAgLy8gRGVmZW5zaXZlOiBpZiB3ZSBsb3N0IHRoZSByZWxlYXNlIGV2ZW50IChtb3VzZSByZWxlYXNlZCBvdXRzaWRlXG4gICAgICAvLyB0ZXJtaW5hbCB3aW5kb3cg4oCUIHNvbWUgZW11bGF0b3JzIGRyb3AgaXQgcmF0aGVyIHRoYW4gY2FwdHVyaW5nIHRoZVxuICAgICAgLy8gcG9pbnRlciksIGZvY3VzLW91dCBpcyB0aGUgbmV4dCBvYnNlcnZhYmxlIHNpZ25hbCB0aGF0IHRoZSBkcmFnIGlzXG4gICAgICAvLyBvdmVyLiBXaXRob3V0IHRoaXMsIGRyYWctdG8tc2Nyb2xsJ3MgdGltZXIgcnVucyB1bnRpbCB0aGUgc2Nyb2xsXG4gICAgICAvLyBib3VuZGFyeSBpcyBoaXQuXG4gICAgICBpZiAoYXBwLnByb3BzLnNlbGVjdGlvbi5pc0RyYWdnaW5nKSB7XG4gICAgICAgIGZpbmlzaFNlbGVjdGlvbihhcHAucHJvcHMuc2VsZWN0aW9uKVxuICAgICAgICBhcHAucHJvcHMub25TZWxlY3Rpb25DaGFuZ2UoKVxuICAgICAgfVxuICAgICAgY29uc3QgZXZlbnQgPSBuZXcgVGVybWluYWxGb2N1c0V2ZW50KCd0ZXJtaW5hbGJsdXInKVxuICAgICAgYXBwLmludGVybmFsX2V2ZW50RW1pdHRlci5lbWl0KCd0ZXJtaW5hbGJsdXInLCBldmVudClcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgLy8gRmFpbHNhZmU6IGlmIHdlIHJlY2VpdmUgaW5wdXQsIHRoZSB0ZXJtaW5hbCBtdXN0IGJlIGZvY3VzZWRcbiAgICBpZiAoIWdldFRlcm1pbmFsRm9jdXNlZCgpKSB7XG4gICAgICBzZXRUZXJtaW5hbEZvY3VzZWQodHJ1ZSlcbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgQ3RybCtaIChzdXNwZW5kKSB1c2luZyBwYXJzZWQga2V5IHRvIHN1cHBvcnQgYm90aCByYXcgKFxceDFhKSBhbmRcbiAgICAvLyBDU0kgdSBmb3JtYXQgKFxceDFiWzEyMjs1dSkgZnJvbSBLaXR0eSBrZXlib2FyZCBwcm90b2NvbCB0ZXJtaW5hbHNcbiAgICBpZiAoaXRlbS5uYW1lID09PSAneicgJiYgaXRlbS5jdHJsICYmIFNVUFBPUlRTX1NVU1BFTkQpIHtcbiAgICAgIGFwcC5oYW5kbGVTdXNwZW5kKClcbiAgICAgIGNvbnRpbnVlXG4gICAgfVxuXG4gICAgYXBwLmhhbmRsZUlucHV0KHNlcXVlbmNlKVxuICAgIGNvbnN0IGV2ZW50ID0gbmV3IElucHV0RXZlbnQoaXRlbSlcbiAgICBhcHAuaW50ZXJuYWxfZXZlbnRFbWl0dGVyLmVtaXQoJ2lucHV0JywgZXZlbnQpXG5cbiAgICAvLyBBbHNvIGRpc3BhdGNoIHRocm91Z2ggdGhlIERPTSB0cmVlIHNvIG9uS2V5RG93biBoYW5kbGVycyBmaXJlLlxuICAgIGFwcC5wcm9wcy5kaXNwYXRjaEtleWJvYXJkRXZlbnQoaXRlbSlcbiAgfVxufVxuXG4vKiogRXhwb3J0ZWQgZm9yIHRlc3RpbmcuIE11dGF0ZXMgYXBwLnByb3BzLnNlbGVjdGlvbiBhbmQgY2xpY2svaG92ZXIgc3RhdGUuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlTW91c2VFdmVudChhcHA6IEFwcCwgbTogUGFyc2VkTW91c2UpOiB2b2lkIHtcbiAgLy8gQWxsb3cgZGlzYWJsaW5nIGNsaWNrIGhhbmRsaW5nIHdoaWxlIGtlZXBpbmcgd2hlZWwgc2Nyb2xsICh3aGljaCBnb2VzXG4gIC8vIHRocm91Z2ggdGhlIGtleWJpbmRpbmcgc3lzdGVtIGFzICd3aGVlbHVwJy8nd2hlZWxkb3duJywgbm90IGhlcmUpLlxuICBpZiAoaXNNb3VzZUNsaWNrc0Rpc2FibGVkKCkpIHJldHVyblxuXG4gIGNvbnN0IHNlbCA9IGFwcC5wcm9wcy5zZWxlY3Rpb25cbiAgLy8gVGVybWluYWwgY29vcmRzIGFyZSAxLWluZGV4ZWQ7IHNjcmVlbiBidWZmZXIgaXMgMC1pbmRleGVkXG4gIGNvbnN0IGNvbCA9IG0uY29sIC0gMVxuICBjb25zdCByb3cgPSBtLnJvdyAtIDFcbiAgY29uc3QgYmFzZUJ1dHRvbiA9IG0uYnV0dG9uICYgMHgwM1xuXG4gIGlmIChtLmFjdGlvbiA9PT0gJ3ByZXNzJykge1xuICAgIGlmICgobS5idXR0b24gJiAweDIwKSAhPT0gMCAmJiBiYXNlQnV0dG9uID09PSAzKSB7XG4gICAgICAvLyBNb2RlLTEwMDMgbW90aW9uIHdpdGggbm8gYnV0dG9uIGhlbGQuIERpc3BhdGNoIGhvdmVyOyBza2lwIHRoZVxuICAgICAgLy8gcmVzdCBvZiB0aGlzIGhhbmRsZXIgKG5vIHNlbGVjdGlvbiwgbm8gY2xpY2stY291bnQgc2lkZSBlZmZlY3RzKS5cbiAgICAgIC8vIExvc3QtcmVsZWFzZSByZWNvdmVyeTogbm8tYnV0dG9uIG1vdGlvbiB3aGlsZSBpc0RyYWdnaW5nPXRydWUgbWVhbnNcbiAgICAgIC8vIHRoZSByZWxlYXNlIGhhcHBlbmVkIG91dHNpZGUgdGhlIHRlcm1pbmFsIHdpbmRvdyAoaVRlcm0yIGRvZXNuJ3RcbiAgICAgIC8vIGNhcHR1cmUgdGhlIHBvaW50ZXIgcGFzdCB3aW5kb3cgYm91bmRzLCBzbyB0aGUgU0dSICdtJyBuZXZlclxuICAgICAgLy8gYXJyaXZlcykuIEZpbmlzaCB0aGUgc2VsZWN0aW9uIGhlcmUgc28gY29weS1vbi1zZWxlY3QgZmlyZXMuIFRoZVxuICAgICAgLy8gRk9DVVNfT1VUIGhhbmRsZXIgY292ZXJzIHRoZSBcInN3aXRjaGVkIGFwcHNcIiBjYXNlIGJ1dCBub3QgXCJyZWxlYXNlZFxuICAgICAgLy8gcGFzdCB0aGUgZWRnZSwgY2FtZSBiYWNrXCIg4oCUIGFuZCB0bXV4IGRyb3BzIGZvY3VzIGV2ZW50cyB1bmxlc3NcbiAgICAgIC8vIGBmb2N1cy1ldmVudHMgb25gIGlzIHNldCwgc28gdGhpcyBpcyB0aGUgbW9yZSByZWxpYWJsZSBzaWduYWwuXG4gICAgICBpZiAoc2VsLmlzRHJhZ2dpbmcpIHtcbiAgICAgICAgZmluaXNoU2VsZWN0aW9uKHNlbClcbiAgICAgICAgYXBwLnByb3BzLm9uU2VsZWN0aW9uQ2hhbmdlKClcbiAgICAgIH1cbiAgICAgIGlmIChjb2wgPT09IGFwcC5sYXN0SG92ZXJDb2wgJiYgcm93ID09PSBhcHAubGFzdEhvdmVyUm93KSByZXR1cm5cbiAgICAgIGFwcC5sYXN0SG92ZXJDb2wgPSBjb2xcbiAgICAgIGFwcC5sYXN0SG92ZXJSb3cgPSByb3dcbiAgICAgIGFwcC5wcm9wcy5vbkhvdmVyQXQoY29sLCByb3cpXG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgaWYgKGJhc2VCdXR0b24gIT09IDApIHtcbiAgICAgIC8vIE5vbi1sZWZ0IHByZXNzIGJyZWFrcyB0aGUgbXVsdGktY2xpY2sgY2hhaW4uXG4gICAgICBhcHAuY2xpY2tDb3VudCA9IDBcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICBpZiAoKG0uYnV0dG9uICYgMHgyMCkgIT09IDApIHtcbiAgICAgIC8vIERyYWcgbW90aW9uOiBtb2RlLWF3YXJlIGV4dGVuc2lvbiAoY2hhci93b3JkL2xpbmUpLiBvblNlbGVjdGlvbkRyYWdcbiAgICAgIC8vIGNhbGxzIG5vdGlmeVNlbGVjdGlvbkNoYW5nZSBpbnRlcm5hbGx5IOKAlCBubyBleHRyYSBvblNlbGVjdGlvbkNoYW5nZS5cbiAgICAgIGFwcC5wcm9wcy5vblNlbGVjdGlvbkRyYWcoY29sLCByb3cpXG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgLy8gTG9zdC1yZWxlYXNlIGZhbGxiYWNrIGZvciBtb2RlLTEwMDItb25seSB0ZXJtaW5hbHM6IGEgZnJlc2ggcHJlc3NcbiAgICAvLyB3aGlsZSBpc0RyYWdnaW5nPXRydWUgbWVhbnMgdGhlIHByZXZpb3VzIHJlbGVhc2Ugd2FzIGRyb3BwZWQgKGN1cnNvclxuICAgIC8vIGxlZnQgdGhlIHdpbmRvdykuIEZpbmlzaCB0aGF0IHNlbGVjdGlvbiBzbyBjb3B5LW9uLXNlbGVjdCBmaXJlc1xuICAgIC8vIGJlZm9yZSBzdGFydFNlbGVjdGlvbi9vbk11bHRpQ2xpY2sgY2xvYmJlcnMgaXQuIE1vZGUtMTAwMyB0ZXJtaW5hbHNcbiAgICAvLyBoaXQgdGhlIG5vLWJ1dHRvbi1tb3Rpb24gcmVjb3ZlcnkgYWJvdmUgaW5zdGVhZCwgc28gdGhpcyBpcyByYXJlLlxuICAgIGlmIChzZWwuaXNEcmFnZ2luZykge1xuICAgICAgZmluaXNoU2VsZWN0aW9uKHNlbClcbiAgICAgIGFwcC5wcm9wcy5vblNlbGVjdGlvbkNoYW5nZSgpXG4gICAgfVxuICAgIC8vIEZyZXNoIGxlZnQgcHJlc3MuIERldGVjdCBtdWx0aS1jbGljayBIRVJFIChub3Qgb24gcmVsZWFzZSkgc28gdGhlXG4gICAgLy8gd29yZC9saW5lIGhpZ2hsaWdodCBhcHBlYXJzIGltbWVkaWF0ZWx5IGFuZCBhIHN1YnNlcXVlbnQgZHJhZyBjYW5cbiAgICAvLyBleHRlbmQgYnkgd29yZC9saW5lIGxpa2UgbmF0aXZlIG1hY09TLiBQcmV2aW91c2x5IGRldGVjdGVkIG9uXG4gICAgLy8gcmVsZWFzZSwgd2hpY2ggbWVhbnQgKGEpIHZpc2libGUgbGF0ZW5jeSBiZWZvcmUgdGhlIHdvcmQgaGlnaGxpZ2h0c1xuICAgIC8vIGFuZCAoYikgZG91YmxlLWNsaWNrK2RyYWcgZmVsbCB0aHJvdWdoIHRvIGNoYXItbW9kZSBzZWxlY3Rpb24uXG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgIGNvbnN0IG5lYXJMYXN0ID1cbiAgICAgIG5vdyAtIGFwcC5sYXN0Q2xpY2tUaW1lIDwgTVVMVElfQ0xJQ0tfVElNRU9VVF9NUyAmJlxuICAgICAgTWF0aC5hYnMoY29sIC0gYXBwLmxhc3RDbGlja0NvbCkgPD0gTVVMVElfQ0xJQ0tfRElTVEFOQ0UgJiZcbiAgICAgIE1hdGguYWJzKHJvdyAtIGFwcC5sYXN0Q2xpY2tSb3cpIDw9IE1VTFRJX0NMSUNLX0RJU1RBTkNFXG4gICAgYXBwLmNsaWNrQ291bnQgPSBuZWFyTGFzdCA/IGFwcC5jbGlja0NvdW50ICsgMSA6IDFcbiAgICBhcHAubGFzdENsaWNrVGltZSA9IG5vd1xuICAgIGFwcC5sYXN0Q2xpY2tDb2wgPSBjb2xcbiAgICBhcHAubGFzdENsaWNrUm93ID0gcm93XG4gICAgaWYgKGFwcC5jbGlja0NvdW50ID49IDIpIHtcbiAgICAgIC8vIENhbmNlbCBhbnkgcGVuZGluZyBoeXBlcmxpbmstb3BlbiBmcm9tIHRoZSBmaXJzdCBjbGljayDigJQgdGhpcyBpc1xuICAgICAgLy8gYSBkb3VibGUtY2xpY2ssIG5vdCBhIHNpbmdsZS1jbGljayBvbiBhIGxpbmsuXG4gICAgICBpZiAoYXBwLnBlbmRpbmdIeXBlcmxpbmtUaW1lcikge1xuICAgICAgICBjbGVhclRpbWVvdXQoYXBwLnBlbmRpbmdIeXBlcmxpbmtUaW1lcilcbiAgICAgICAgYXBwLnBlbmRpbmdIeXBlcmxpbmtUaW1lciA9IG51bGxcbiAgICAgIH1cbiAgICAgIC8vIENhcCBhdCAzIChsaW5lIHNlbGVjdCkgZm9yIHF1YWRydXBsZSsgY2xpY2tzLlxuICAgICAgY29uc3QgY291bnQgPSBhcHAuY2xpY2tDb3VudCA9PT0gMiA/IDIgOiAzXG4gICAgICBhcHAucHJvcHMub25NdWx0aUNsaWNrKGNvbCwgcm93LCBjb3VudClcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICBzdGFydFNlbGVjdGlvbihzZWwsIGNvbCwgcm93KVxuICAgIC8vIFNHUiBiaXQgMHgwOCA9IGFsdCAoeHRlcm0uanMgd2lyZXMgYWx0S2V5IGhlcmUsIG5vdCBtZXRhS2V5IOKAlCBzZWVcbiAgICAvLyBjb21tZW50IGF0IHRoZSBoeXBlcmxpbmstb3BlbiBndWFyZCBiZWxvdykuIE9uIG1hY09TIHh0ZXJtLmpzLFxuICAgIC8vIHJlY2VpdmluZyBhbHQgbWVhbnMgbWFjT3B0aW9uQ2xpY2tGb3JjZXNTZWxlY3Rpb24gaXMgT0ZGIChvdGhlcndpc2VcbiAgICAvLyB4dGVybS5qcyB3b3VsZCBoYXZlIGNvbnN1bWVkIHRoZSBldmVudCBmb3IgbmF0aXZlIHNlbGVjdGlvbikuXG4gICAgc2VsLmxhc3RQcmVzc0hhZEFsdCA9IChtLmJ1dHRvbiAmIDB4MDgpICE9PSAwXG4gICAgYXBwLnByb3BzLm9uU2VsZWN0aW9uQ2hhbmdlKClcbiAgICByZXR1cm5cbiAgfVxuXG4gIC8vIFJlbGVhc2U6IGVuZCB0aGUgZHJhZyBldmVuIGZvciBub24temVybyBidXR0b24gY29kZXMuIFNvbWUgdGVybWluYWxzXG4gIC8vIGVuY29kZSByZWxlYXNlIHdpdGggdGhlIG1vdGlvbiBiaXQgb3IgYnV0dG9uPTMgXCJubyBidXR0b25cIiAoY2FycmllZFxuICAvLyBvdmVyIGZyb20gcHJlLVNHUiBYMTAgZW5jb2RpbmcpIOKAlCBmaWx0ZXJpbmcgdGhvc2Ugd291bGQgb3JwaGFuXG4gIC8vIGlzRHJhZ2dpbmc9dHJ1ZSBhbmQgbGVhdmUgZHJhZy10by1zY3JvbGwncyB0aW1lciBydW5uaW5nIHVudGlsIHRoZVxuICAvLyBzY3JvbGwgYm91bmRhcnkuIE9ubHkgYWN0IG9uIG5vbi1sZWZ0IHJlbGVhc2VzIHdoZW4gd2UgQVJFIGRyYWdnaW5nXG4gIC8vIChzbyBhbiB1bnJlbGF0ZWQgbWlkZGxlL3JpZ2h0IGNsaWNrLXJlbGVhc2UgZG9lc24ndCB0b3VjaCBzZWxlY3Rpb24pLlxuICBpZiAoYmFzZUJ1dHRvbiAhPT0gMCkge1xuICAgIGlmICghc2VsLmlzRHJhZ2dpbmcpIHJldHVyblxuICAgIGZpbmlzaFNlbGVjdGlvbihzZWwpXG4gICAgYXBwLnByb3BzLm9uU2VsZWN0aW9uQ2hhbmdlKClcbiAgICByZXR1cm5cbiAgfVxuICBmaW5pc2hTZWxlY3Rpb24oc2VsKVxuICAvLyBOT1RFOiB1bmxpa2UgdGhlIG9sZCByZWxlYXNlLWJhc2VkIGRldGVjdGlvbiB3ZSBkbyBOT1QgcmVzZXQgY2xpY2tDb3VudFxuICAvLyBvbiByZWxlYXNlLWFmdGVyLWRyYWcuIFRoaXMgYWxpZ25zIHdpdGggTlNFdmVudC5jbGlja0NvdW50IHNlbWFudGljczpcbiAgLy8gYW4gaW50ZXJ2ZW5pbmcgZHJhZyBkb2Vzbid0IGJyZWFrIHRoZSBjbGljayBjaGFpbi4gUHJhY3RpY2FsIHVwc2lkZTpcbiAgLy8gdHJhY2twYWQgaml0dGVyIGR1cmluZyBhbiBpbnRlbmRlZCBkb3VibGUtY2xpY2sgKHByZXNz4oaSd29iYmxl4oaScmVsZWFzZVxuICAvLyDihpJwcmVzcykgbm93IGNvcnJlY3RseSByZXNvbHZlcyB0byB3b3JkLXNlbGVjdCBpbnN0ZWFkIG9mIGJyZWFraW5nIHRvIGFcbiAgLy8gZnJlc2ggc2luZ2xlIGNsaWNrLiBUaGUgbmVhckxhc3Qgd2luZG93ICg1MDBtcywgMSBjZWxsKSBib3VuZHMgdGhlXG4gIC8vIGVmZmVjdCDigJQgYSBkZWxpYmVyYXRlIGRyYWcgcGFzdCB0aGF0IGp1c3Qgc3RhcnRzIGEgZnJlc2ggY2hhaW4uXG4gIC8vIEEgcHJlc3MrcmVsZWFzZSB3aXRoIG5vIGRyYWcgaW4gY2hhciBtb2RlIGlzIGEgY2xpY2s6IGFuY2hvciBzZXQsXG4gIC8vIGZvY3VzIG51bGwg4oaSIGhhc1NlbGVjdGlvbiBmYWxzZS4gSW4gd29yZC9saW5lIG1vZGUgdGhlIHByZXNzIGFscmVhZHlcbiAgLy8gc2V0IGFuY2hvcitmb2N1cyAoaGFzU2VsZWN0aW9uIHRydWUpLCBzbyByZWxlYXNlIGp1c3Qga2VlcHMgdGhlXG4gIC8vIGhpZ2hsaWdodC4gVGhlIGFuY2hvciBjaGVjayBndWFyZHMgYWdhaW5zdCBhbiBvcnBoYW5lZCByZWxlYXNlIChub1xuICAvLyBwcmlvciBwcmVzcyDigJQgZS5nLiBidXR0b24gd2FzIGhlbGQgd2hlbiBtb3VzZSB0cmFja2luZyB3YXMgZW5hYmxlZCkuXG4gIGlmICghaGFzU2VsZWN0aW9uKHNlbCkgJiYgc2VsLmFuY2hvcikge1xuICAgIC8vIFNpbmdsZSBjbGljazogZGlzcGF0Y2ggRE9NIGNsaWNrIGltbWVkaWF0ZWx5IChjdXJzb3IgcmVwb3NpdGlvbmluZ1xuICAgIC8vIGV0Yy4gYXJlIGxhdGVuY3ktc2Vuc2l0aXZlKS4gSWYgbm8gRE9NIGhhbmRsZXIgY29uc3VtZWQgaXQsIGRlZmVyXG4gICAgLy8gdGhlIGh5cGVybGluayBjaGVjayBzbyBhIHNlY29uZCBjbGljayBjYW4gY2FuY2VsIGl0LlxuICAgIGlmICghYXBwLnByb3BzLm9uQ2xpY2tBdChjb2wsIHJvdykpIHtcbiAgICAgIC8vIFJlc29sdmUgdGhlIGh5cGVybGluayBVUkwgc3luY2hyb25vdXNseSB3aGlsZSB0aGUgc2NyZWVuIGJ1ZmZlclxuICAgICAgLy8gc3RpbGwgcmVmbGVjdHMgd2hhdCB0aGUgdXNlciBjbGlja2VkIOKAlCBkZWZlcnJpbmcgb25seSB0aGVcbiAgICAgIC8vIGJyb3dzZXItb3BlbiBzbyBkb3VibGUtY2xpY2sgY2FuIGNhbmNlbCBpdC5cbiAgICAgIGNvbnN0IHVybCA9IGFwcC5wcm9wcy5nZXRIeXBlcmxpbmtBdChjb2wsIHJvdylcbiAgICAgIC8vIHh0ZXJtLmpzIChWUyBDb2RlLCBDdXJzb3IsIFdpbmRzdXJmLCBldGMuKSBoYXMgaXRzIG93biBPU0MgOCBsaW5rXG4gICAgICAvLyBoYW5kbGVyIHRoYXQgZmlyZXMgb24gQ21kK2NsaWNrICp3aXRob3V0IGNvbnN1bWluZyB0aGUgbW91c2UgZXZlbnQqXG4gICAgICAvLyAoTGlua2lmaWVyLl9oYW5kbGVNb3VzZVVwIGNhbGxzIGxpbmsuYWN0aXZhdGUoKSBidXQgbmV2ZXJcbiAgICAgIC8vIHByZXZlbnREZWZhdWx0L3N0b3BQcm9wYWdhdGlvbikuIFRoZSBjbGljayBpcyBhbHNvIGZvcndhcmRlZCB0byB0aGVcbiAgICAgIC8vIHB0eSBhcyBTR1IsIHNvIGJvdGggVlMgQ29kZSdzIHRlcm1pbmFsTGlua01hbmFnZXIgQU5EIG91ciBoYW5kbGVyXG4gICAgICAvLyBoZXJlIHdvdWxkIG9wZW4gdGhlIFVSTCDigJQgdHdpY2UuIFdlIGNhbid0IGZpbHRlciBvbiBDbWQ6IHh0ZXJtLmpzXG4gICAgICAvLyBkcm9wcyBtZXRhS2V5IGJlZm9yZSBTR1IgZW5jb2RpbmcgKElDb3JlTW91c2VFdmVudCBoYXMgbm8gbWV0YVxuICAgICAgLy8gZmllbGQ7IHRoZSBTR1IgYml0IHdlIGNhbGwgJ21ldGEnIGlzIHdpcmVkIHRvIGFsdCkuIExldCB4dGVybS5qc1xuICAgICAgLy8gb3duIGxpbmstb3BlbmluZzsgQ21kK2NsaWNrIGlzIHRoZSBuYXRpdmUgVVggdGhlcmUgYW55d2F5LlxuICAgICAgLy8gVEVSTV9QUk9HUkFNIGlzIHRoZSBzeW5jIGZhc3QtcGF0aDsgaXNYdGVybUpzKCkgaXMgdGhlIFhUVkVSU0lPTlxuICAgICAgLy8gcHJvYmUgcmVzdWx0IChjYXRjaGVzIFNTSCArIG5vbi1WUyBDb2RlIGVtYmVkZGVycyBsaWtlIEh5cGVyKS5cbiAgICAgIGlmICh1cmwgJiYgcHJvY2Vzcy5lbnYuVEVSTV9QUk9HUkFNICE9PSAndnNjb2RlJyAmJiAhaXNYdGVybUpzKCkpIHtcbiAgICAgICAgLy8gQ2xlYXIgYW55IHByaW9yIHBlbmRpbmcgdGltZXIg4oCUIGNsaWNraW5nIGEgc2Vjb25kIGxpbmtcbiAgICAgICAgLy8gc3VwZXJzZWRlcyB0aGUgZmlyc3QgKG9ubHkgdGhlIGxhdGVzdCBjbGljayBvcGVucykuXG4gICAgICAgIGlmIChhcHAucGVuZGluZ0h5cGVybGlua1RpbWVyKSB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KGFwcC5wZW5kaW5nSHlwZXJsaW5rVGltZXIpXG4gICAgICAgIH1cbiAgICAgICAgYXBwLnBlbmRpbmdIeXBlcmxpbmtUaW1lciA9IHNldFRpbWVvdXQoXG4gICAgICAgICAgKGFwcCwgdXJsKSA9PiB7XG4gICAgICAgICAgICBhcHAucGVuZGluZ0h5cGVybGlua1RpbWVyID0gbnVsbFxuICAgICAgICAgICAgYXBwLnByb3BzLm9uT3Blbkh5cGVybGluayh1cmwpXG4gICAgICAgICAgfSxcbiAgICAgICAgICBNVUxUSV9DTElDS19USU1FT1VUX01TLFxuICAgICAgICAgIGFwcCxcbiAgICAgICAgICB1cmwsXG4gICAgICAgIClcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgYXBwLnByb3BzLm9uU2VsZWN0aW9uQ2hhbmdlKClcbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsS0FBSyxJQUFJQyxhQUFhLEVBQUUsS0FBS0MsU0FBUyxRQUFRLE9BQU87QUFDNUQsU0FBU0MseUJBQXlCLFFBQVEsMEJBQTBCO0FBQ3BFLFNBQVNDLGVBQWUsUUFBUSxzQkFBc0I7QUFDdEQsU0FBU0MsdUJBQXVCLFFBQVEsMkJBQTJCO0FBQ25FLFNBQVNDLFdBQVcsUUFBUSx5QkFBeUI7QUFDckQsU0FBU0MscUJBQXFCLFFBQVEsMkJBQTJCO0FBQ2pFLFNBQVNDLFFBQVEsUUFBUSxvQkFBb0I7QUFDN0MsU0FBU0MsWUFBWSxRQUFRLHNCQUFzQjtBQUNuRCxTQUFTQyxVQUFVLFFBQVEsMEJBQTBCO0FBQ3JELFNBQVNDLGtCQUFrQixRQUFRLG1DQUFtQztBQUN0RSxTQUNFQyxhQUFhLEVBQ2IsS0FBS0MsV0FBVyxFQUNoQixLQUFLQyxTQUFTLEVBQ2QsS0FBS0MsV0FBVyxFQUNoQkMsdUJBQXVCLFFBQ2xCLHNCQUFzQjtBQUM3QixPQUFPQyxVQUFVLE1BQU0sa0JBQWtCO0FBQ3pDLFNBQ0VDLGVBQWUsRUFDZkMsWUFBWSxF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