@workflow/web-shared 5.0.0-beta.3 → 5.0.0-beta.30

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 (402) hide show
  1. package/README.md +2 -10
  2. package/dist/components/error-boundary.js +1 -1
  3. package/dist/components/event-list-view.d.ts +46 -1
  4. package/dist/components/event-list-view.d.ts.map +1 -1
  5. package/dist/components/event-list-view.js +228 -90
  6. package/dist/components/hook-actions.js +1 -1
  7. package/dist/components/index.d.ts +6 -2
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/components/index.js +5 -2
  10. package/dist/components/new-trace-viewer/components/copy-button.js +3 -3
  11. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts +34 -0
  12. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts.map +1 -0
  13. package/dist/components/new-trace-viewer/components/detail-panel-width.js +67 -0
  14. package/dist/components/new-trace-viewer/components/detail-panel.d.ts +14 -0
  15. package/dist/components/new-trace-viewer/components/detail-panel.d.ts.map +1 -0
  16. package/dist/components/new-trace-viewer/components/detail-panel.js +122 -0
  17. package/dist/components/new-trace-viewer/components/draggable-border.d.ts +31 -0
  18. package/dist/components/new-trace-viewer/components/draggable-border.d.ts.map +1 -0
  19. package/dist/components/new-trace-viewer/components/draggable-border.js +140 -0
  20. package/dist/components/new-trace-viewer/components/event-list.d.ts +4 -2
  21. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
  22. package/dist/components/new-trace-viewer/components/event-list.js +22 -13
  23. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
  24. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
  25. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
  26. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
  27. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
  28. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
  29. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
  30. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
  31. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
  32. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
  33. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
  34. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
  35. package/dist/components/new-trace-viewer/components/minimap.d.ts +14 -0
  36. package/dist/components/new-trace-viewer/components/minimap.d.ts.map +1 -0
  37. package/dist/components/new-trace-viewer/components/minimap.js +337 -0
  38. package/dist/components/new-trace-viewer/components/pane-constants.d.ts +14 -0
  39. package/dist/components/new-trace-viewer/components/pane-constants.d.ts.map +1 -0
  40. package/dist/components/new-trace-viewer/components/pane-constants.js +16 -0
  41. package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
  42. package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
  43. package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
  44. package/dist/components/new-trace-viewer/components/split-pane.d.ts +3 -7
  45. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -1
  46. package/dist/components/new-trace-viewer/components/split-pane.js +25 -84
  47. package/dist/components/new-trace-viewer/components/timeline.d.ts +19 -15
  48. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
  49. package/dist/components/new-trace-viewer/components/timeline.js +229 -111
  50. package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
  51. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts +5 -0
  52. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts.map +1 -0
  53. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.js +55 -0
  54. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  55. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
  56. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
  57. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +26 -0
  58. package/dist/components/new-trace-viewer/components/use-element-width.d.ts +8 -0
  59. package/dist/components/new-trace-viewer/components/use-element-width.d.ts.map +1 -0
  60. package/dist/components/new-trace-viewer/components/use-element-width.js +25 -0
  61. package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
  62. package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
  63. package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
  64. package/dist/components/new-trace-viewer/context.d.ts +3 -1
  65. package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
  66. package/dist/components/new-trace-viewer/context.js +9 -10
  67. package/dist/components/new-trace-viewer/icons.js +3 -3
  68. package/dist/components/new-trace-viewer/search.d.ts +19 -0
  69. package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
  70. package/dist/components/new-trace-viewer/search.js +134 -0
  71. package/dist/components/new-trace-viewer/trace-viewer.d.ts +6 -3
  72. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
  73. package/dist/components/new-trace-viewer/trace-viewer.js +167 -162
  74. package/dist/components/new-trace-viewer/types.d.ts +2 -0
  75. package/dist/components/new-trace-viewer/types.d.ts.map +1 -1
  76. package/dist/components/new-trace-viewer/types.js +2 -2
  77. package/dist/components/new-trace-viewer/utils.d.ts +48 -13
  78. package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
  79. package/dist/components/new-trace-viewer/utils.js +135 -107
  80. package/dist/components/run-trace-view.d.ts +5 -7
  81. package/dist/components/run-trace-view.d.ts.map +1 -1
  82. package/dist/components/run-trace-view.js +3 -3
  83. package/dist/components/sidebar/attribute-panel.d.ts +4 -1
  84. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  85. package/dist/components/sidebar/attribute-panel.js +133 -113
  86. package/dist/components/sidebar/attributes-block.d.ts +40 -0
  87. package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
  88. package/dist/components/sidebar/attributes-block.js +140 -0
  89. package/dist/components/sidebar/conversation-view.js +1 -1
  90. package/dist/components/sidebar/copyable-data-block.d.ts +2 -0
  91. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  92. package/dist/components/sidebar/copyable-data-block.js +17 -16
  93. package/dist/components/sidebar/entity-detail-panel.d.ts +11 -11
  94. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  95. package/dist/components/sidebar/entity-detail-panel.js +35 -69
  96. package/dist/components/sidebar/events-list.d.ts +6 -2
  97. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  98. package/dist/components/sidebar/events-list.js +76 -62
  99. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  100. package/dist/components/sidebar/sidebar-data-context.d.ts +10 -7
  101. package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -1
  102. package/dist/components/sidebar/sidebar-data-context.js +1 -1
  103. package/dist/components/sidebar/span-detail-merge.d.ts +31 -0
  104. package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
  105. package/dist/components/sidebar/span-detail-merge.js +92 -0
  106. package/dist/components/sidebar/use-selected-span-detail.d.ts +16 -0
  107. package/dist/components/sidebar/use-selected-span-detail.d.ts.map +1 -0
  108. package/dist/components/sidebar/use-selected-span-detail.js +93 -0
  109. package/dist/components/stream-viewer.js +1 -1
  110. package/dist/components/trace-viewer/components/map.d.ts +2 -2
  111. package/dist/components/trace-viewer/components/map.d.ts.map +1 -1
  112. package/dist/components/trace-viewer/components/map.js +1 -1
  113. package/dist/components/trace-viewer/components/markers.js +1 -1
  114. package/dist/components/trace-viewer/components/node.d.ts +7 -7
  115. package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
  116. package/dist/components/trace-viewer/components/node.js +2 -1
  117. package/dist/components/trace-viewer/components/search-input.js +1 -1
  118. package/dist/components/trace-viewer/components/search.js +1 -1
  119. package/dist/components/trace-viewer/components/span-content.js +1 -1
  120. package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
  121. package/dist/components/trace-viewer/components/span-segments.js +1 -1
  122. package/dist/components/trace-viewer/components/span-strategies.js +1 -1
  123. package/dist/components/trace-viewer/components/ui.js +1 -1
  124. package/dist/components/trace-viewer/components/zoom-button.js +1 -1
  125. package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
  126. package/dist/components/trace-viewer/context.js +1 -1
  127. package/dist/components/trace-viewer/index.js +1 -1
  128. package/dist/components/trace-viewer/trace-viewer.js +1 -1
  129. package/dist/components/trace-viewer/trace-viewer.module.css +4 -4
  130. package/dist/components/trace-viewer/types.js +1 -1
  131. package/dist/components/trace-viewer/util/constants.js +1 -1
  132. package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
  133. package/dist/components/trace-viewer/util/timing.d.ts +3 -3
  134. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
  135. package/dist/components/trace-viewer/util/timing.js +8 -11
  136. package/dist/components/trace-viewer/util/tree.js +1 -1
  137. package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
  138. package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
  139. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
  140. package/dist/components/trace-viewer/worker.js +1 -1
  141. package/dist/components/trace-viewer-new.d.ts +5 -1
  142. package/dist/components/trace-viewer-new.d.ts.map +1 -1
  143. package/dist/components/trace-viewer-new.js +8 -10
  144. package/dist/components/ui/alert.js +2 -2
  145. package/dist/components/ui/button.d.ts +10 -0
  146. package/dist/components/ui/button.d.ts.map +1 -0
  147. package/dist/components/ui/button.js +46 -0
  148. package/dist/components/ui/card.js +2 -2
  149. package/dist/components/ui/collapsible.d.ts +46 -0
  150. package/dist/components/ui/collapsible.d.ts.map +1 -0
  151. package/dist/components/ui/collapsible.js +66 -0
  152. package/dist/components/ui/context-card.d.ts +47 -0
  153. package/dist/components/ui/context-card.d.ts.map +1 -0
  154. package/dist/components/ui/context-card.js +471 -0
  155. package/dist/components/ui/data-inspector.d.ts +7 -6
  156. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  157. package/dist/components/ui/data-inspector.js +232 -99
  158. package/dist/components/ui/data-inspector.styles.d.ts +29 -0
  159. package/dist/components/ui/data-inspector.styles.d.ts.map +1 -0
  160. package/dist/components/ui/data-inspector.styles.js +95 -0
  161. package/dist/components/ui/decrypt-button.js +1 -1
  162. package/dist/components/ui/error-card.js +2 -2
  163. package/dist/components/ui/error-stack-block.d.ts +17 -10
  164. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  165. package/dist/components/ui/error-stack-block.js +49 -30
  166. package/dist/components/ui/icon-button.d.ts +19 -0
  167. package/dist/components/ui/icon-button.d.ts.map +1 -0
  168. package/dist/components/ui/icon-button.js +29 -0
  169. package/dist/components/ui/kbd.d.ts +10 -0
  170. package/dist/components/ui/kbd.d.ts.map +1 -0
  171. package/dist/components/ui/kbd.js +25 -0
  172. package/dist/components/ui/load-more-button.js +1 -1
  173. package/dist/components/ui/menu-dropdown.js +1 -1
  174. package/dist/components/ui/skeleton.js +2 -2
  175. package/dist/components/ui/spinner.js +1 -1
  176. package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
  177. package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
  178. package/dist/components/ui/timestamp-tooltip.js +80 -132
  179. package/dist/components/ui/tooltip.d.ts +10 -0
  180. package/dist/components/ui/tooltip.d.ts.map +1 -0
  181. package/dist/components/ui/tooltip.js +12 -0
  182. package/dist/components/workflow-trace-view.d.ts +7 -8
  183. package/dist/components/workflow-trace-view.d.ts.map +1 -1
  184. package/dist/components/workflow-trace-view.js +11 -16
  185. package/dist/components/workflow-traces/event-colors.d.ts +2 -1
  186. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
  187. package/dist/components/workflow-traces/event-colors.js +15 -7
  188. package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -1
  189. package/dist/components/workflow-traces/trace-colors.js +3 -4
  190. package/dist/components/workflow-traces/trace-span-construction.d.ts +7 -4
  191. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
  192. package/dist/components/workflow-traces/trace-span-construction.js +87 -33
  193. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  194. package/dist/hooks/use-dark-mode.js +1 -1
  195. package/dist/hooks/use-intersection-observer.d.ts +17 -0
  196. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  197. package/dist/hooks/use-intersection-observer.js +29 -0
  198. package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
  199. package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
  200. package/dist/hooks/use-load-more-on-scroll.js +28 -0
  201. package/dist/hooks/use-reduced-motion.d.ts +10 -0
  202. package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
  203. package/dist/hooks/use-reduced-motion.js +29 -0
  204. package/dist/index.d.ts +3 -2
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +4 -3
  207. package/dist/lib/cn.d.ts +10 -0
  208. package/dist/lib/cn.d.ts.map +1 -0
  209. package/dist/lib/cn.js +83 -0
  210. package/dist/lib/event-analysis.d.ts +1 -1
  211. package/dist/lib/event-analysis.d.ts.map +1 -1
  212. package/dist/lib/event-analysis.js +3 -2
  213. package/dist/lib/event-materialization.d.ts +1 -1
  214. package/dist/lib/event-materialization.d.ts.map +1 -1
  215. package/dist/lib/event-materialization.js +29 -21
  216. package/dist/lib/exact-event-search-id.d.ts +25 -0
  217. package/dist/lib/exact-event-search-id.d.ts.map +1 -0
  218. package/dist/lib/exact-event-search-id.js +39 -0
  219. package/dist/lib/hydration.d.ts +17 -2
  220. package/dist/lib/hydration.d.ts.map +1 -1
  221. package/dist/lib/hydration.js +185 -22
  222. package/dist/lib/stream-display.js +1 -1
  223. package/dist/lib/toast.js +1 -1
  224. package/dist/lib/trace-builder.d.ts +16 -4
  225. package/dist/lib/trace-builder.d.ts.map +1 -1
  226. package/dist/lib/trace-builder.js +34 -15
  227. package/dist/lib/utils.d.ts +23 -9
  228. package/dist/lib/utils.d.ts.map +1 -1
  229. package/dist/lib/utils.js +73 -33
  230. package/dist/lib/zstd-browser-decoder.d.ts +7 -0
  231. package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
  232. package/dist/lib/zstd-browser-decoder.js +41 -0
  233. package/dist/styles.css +14 -0
  234. package/package.json +10 -7
  235. package/src/components/event-list-view.tsx +375 -116
  236. package/src/components/index.ts +12 -5
  237. package/src/components/new-trace-viewer/components/copy-button.tsx +2 -2
  238. package/src/components/new-trace-viewer/components/detail-panel-width.test.ts +123 -0
  239. package/src/components/new-trace-viewer/components/detail-panel-width.ts +76 -0
  240. package/src/components/new-trace-viewer/components/detail-panel.tsx +273 -0
  241. package/src/components/new-trace-viewer/components/draggable-border.tsx +216 -0
  242. package/src/components/new-trace-viewer/components/event-list.tsx +57 -32
  243. package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
  244. package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
  245. package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
  246. package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
  247. package/src/components/new-trace-viewer/components/minimap.tsx +559 -0
  248. package/src/components/new-trace-viewer/components/pane-constants.ts +19 -0
  249. package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
  250. package/src/components/new-trace-viewer/components/split-pane.tsx +80 -135
  251. package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
  252. package/src/components/new-trace-viewer/components/timeline.tsx +603 -239
  253. package/src/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  254. package/src/components/new-trace-viewer/components/trace-shortcut-helper.tsx +116 -0
  255. package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +114 -0
  256. package/src/components/new-trace-viewer/components/use-element-width.ts +29 -0
  257. package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
  258. package/src/components/new-trace-viewer/context.tsx +13 -14
  259. package/src/components/new-trace-viewer/icons.tsx +2 -2
  260. package/src/components/new-trace-viewer/search.ts +178 -0
  261. package/src/components/new-trace-viewer/trace-viewer.tsx +336 -293
  262. package/src/components/new-trace-viewer/types.ts +2 -0
  263. package/src/components/new-trace-viewer/utils.test.ts +247 -0
  264. package/src/components/new-trace-viewer/utils.ts +203 -134
  265. package/src/components/run-trace-view.tsx +10 -14
  266. package/src/components/sidebar/attribute-panel.tsx +276 -275
  267. package/src/components/sidebar/attributes-block.tsx +326 -0
  268. package/src/components/sidebar/copyable-data-block.tsx +50 -28
  269. package/src/components/sidebar/entity-detail-panel.tsx +89 -123
  270. package/src/components/sidebar/events-list.tsx +196 -178
  271. package/src/components/sidebar/sidebar-data-context.tsx +11 -11
  272. package/src/components/sidebar/span-detail-merge.ts +134 -0
  273. package/src/components/sidebar/use-selected-span-detail.ts +146 -0
  274. package/src/components/trace-viewer/components/node.tsx +3 -2
  275. package/src/components/trace-viewer/trace-viewer.module.css +4 -4
  276. package/src/components/trace-viewer/util/timing.ts +7 -11
  277. package/src/components/trace-viewer-new.tsx +21 -15
  278. package/src/components/ui/alert.tsx +1 -1
  279. package/src/components/ui/button.tsx +68 -0
  280. package/src/components/ui/card.tsx +1 -1
  281. package/src/components/ui/collapsible.tsx +219 -0
  282. package/src/components/ui/context-card.tsx +784 -0
  283. package/src/components/ui/data-inspector.styles.ts +96 -0
  284. package/src/components/ui/data-inspector.tsx +501 -204
  285. package/src/components/ui/error-card.tsx +1 -1
  286. package/src/components/ui/error-stack-block.tsx +84 -55
  287. package/src/components/ui/icon-button.tsx +53 -0
  288. package/src/components/ui/kbd.tsx +43 -0
  289. package/src/components/ui/skeleton.tsx +1 -1
  290. package/src/components/ui/timestamp-tooltip.tsx +132 -194
  291. package/src/components/ui/tooltip.tsx +47 -0
  292. package/src/components/workflow-trace-view.tsx +31 -36
  293. package/src/components/workflow-traces/event-colors.ts +15 -11
  294. package/src/components/workflow-traces/trace-colors.ts +6 -6
  295. package/src/components/workflow-traces/trace-span-construction.test.ts +85 -0
  296. package/src/components/workflow-traces/trace-span-construction.ts +118 -35
  297. package/src/hooks/use-intersection-observer.ts +57 -0
  298. package/src/hooks/use-load-more-on-scroll.ts +49 -0
  299. package/src/hooks/use-reduced-motion.ts +34 -0
  300. package/src/index.ts +9 -0
  301. package/src/lib/cn.ts +93 -0
  302. package/src/lib/event-analysis.ts +6 -4
  303. package/src/lib/event-materialization.ts +35 -21
  304. package/src/lib/exact-event-search-id.ts +67 -0
  305. package/src/lib/hydration.ts +203 -29
  306. package/src/lib/trace-builder.ts +44 -19
  307. package/src/lib/utils.test.ts +33 -0
  308. package/src/lib/utils.ts +82 -35
  309. package/src/lib/zstd-browser-decoder.ts +42 -0
  310. package/src/styles.css +14 -0
  311. package/dist/components/error-boundary.js.map +0 -1
  312. package/dist/components/event-list-view.js.map +0 -1
  313. package/dist/components/hook-actions.js.map +0 -1
  314. package/dist/components/index.js.map +0 -1
  315. package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
  316. package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
  317. package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
  318. package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
  319. package/dist/components/new-trace-viewer/context.js.map +0 -1
  320. package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
  321. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
  322. package/dist/components/new-trace-viewer/detail-panel.js +0 -11
  323. package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
  324. package/dist/components/new-trace-viewer/icons.js.map +0 -1
  325. package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
  326. package/dist/components/new-trace-viewer/types.js.map +0 -1
  327. package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
  328. package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
  329. package/dist/components/new-trace-viewer/util/constants.js +0 -2
  330. package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
  331. package/dist/components/new-trace-viewer/utils.js.map +0 -1
  332. package/dist/components/run-trace-view.js.map +0 -1
  333. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  334. package/dist/components/sidebar/conversation-view.js.map +0 -1
  335. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  336. package/dist/components/sidebar/detail-card.d.ts +0 -14
  337. package/dist/components/sidebar/detail-card.d.ts.map +0 -1
  338. package/dist/components/sidebar/detail-card.js +0 -20
  339. package/dist/components/sidebar/detail-card.js.map +0 -1
  340. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  341. package/dist/components/sidebar/events-list.js.map +0 -1
  342. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  343. package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
  344. package/dist/components/stream-viewer.js.map +0 -1
  345. package/dist/components/trace-viewer/components/map.js.map +0 -1
  346. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  347. package/dist/components/trace-viewer/components/node.js.map +0 -1
  348. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  349. package/dist/components/trace-viewer/components/search.js.map +0 -1
  350. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  351. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  352. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  353. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  354. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  355. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  356. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  357. package/dist/components/trace-viewer/context.js.map +0 -1
  358. package/dist/components/trace-viewer/index.js.map +0 -1
  359. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  360. package/dist/components/trace-viewer/types.js.map +0 -1
  361. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  362. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  363. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  364. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  365. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  366. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  367. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  368. package/dist/components/trace-viewer/worker.js.map +0 -1
  369. package/dist/components/trace-viewer-new.js.map +0 -1
  370. package/dist/components/ui/alert.js.map +0 -1
  371. package/dist/components/ui/card.js.map +0 -1
  372. package/dist/components/ui/data-inspector.js.map +0 -1
  373. package/dist/components/ui/decrypt-button.js.map +0 -1
  374. package/dist/components/ui/error-card.js.map +0 -1
  375. package/dist/components/ui/error-stack-block.js.map +0 -1
  376. package/dist/components/ui/inspector-theme.d.ts +0 -95
  377. package/dist/components/ui/inspector-theme.d.ts.map +0 -1
  378. package/dist/components/ui/inspector-theme.js +0 -82
  379. package/dist/components/ui/inspector-theme.js.map +0 -1
  380. package/dist/components/ui/load-more-button.js.map +0 -1
  381. package/dist/components/ui/menu-dropdown.js.map +0 -1
  382. package/dist/components/ui/skeleton.js.map +0 -1
  383. package/dist/components/ui/spinner.js.map +0 -1
  384. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  385. package/dist/components/workflow-trace-view.js.map +0 -1
  386. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  387. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  388. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  389. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  390. package/dist/hooks/use-dark-mode.js.map +0 -1
  391. package/dist/index.js.map +0 -1
  392. package/dist/lib/event-analysis.js.map +0 -1
  393. package/dist/lib/event-materialization.js.map +0 -1
  394. package/dist/lib/hydration.js.map +0 -1
  395. package/dist/lib/stream-display.js.map +0 -1
  396. package/dist/lib/toast.js.map +0 -1
  397. package/dist/lib/trace-builder.js.map +0 -1
  398. package/dist/lib/utils.js.map +0 -1
  399. package/src/components/new-trace-viewer/detail-panel.tsx +0 -57
  400. package/src/components/new-trace-viewer/util/constants.ts +0 -0
  401. package/src/components/sidebar/detail-card.tsx +0 -65
  402. package/src/components/ui/inspector-theme.ts +0 -110
@@ -1,123 +1,239 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { memo, useEffect, useMemo, useRef, useState } from 'react';
4
- import { cn } from '../../../lib/utils';
5
- import { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';
6
- import { computeCompressedTimeMarkers, computeSpanGaps, computeSpanSegments, computeTimeMarkers, getResourceColor, } from '../utils';
7
- const QUEUED_BACKGROUND = 'radial-gradient(circle, var(--ds-gray-400) 2px, transparent 2px) center / 20px 20px space no-repeat, var(--ds-gray-500)';
8
- const HATCHED_BACKGROUND = 'repeating-linear-gradient(-45deg, var(--ds-gray-400) 0px, var(--ds-gray-400) 3px, var(--ds-gray-500) 3px, var(--ds-gray-500) 6px)';
9
- const SEGMENT_CONFIG = {
10
- queued: { style: { background: QUEUED_BACKGROUND } },
11
- retrying: {
12
- className: 'box-border bg-gray-500',
13
- },
14
- waiting: { style: { background: HATCHED_BACKGROUND } },
15
- running: { className: 'bg-blue-700' },
16
- failed: { className: 'bg-red-700' },
17
- succeeded: { className: 'bg-green-700' },
18
- sleeping: { className: 'bg-amber-700' },
19
- received: { className: 'bg-blue-700' },
3
+ import { ArrowLeft, ArrowRight } from 'lucide-react';
4
+ import { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
5
+ import { cn } from '../../../lib/cn';
6
+ import { formatDurationPrecise, getHighResInMs, } from '../../trace-viewer/util/timing';
7
+ import { isSpanDimmedBySearch } from '../search';
8
+ import { computeOffscreenMarkers, computeSpanGaps, computeSpanMarkers, computeSpanSegments, getResourceColor, getSpanDurationMs, isSpanErrored, } from '../utils';
9
+ import { cullCollidingMarkers, MarkerLayer, OffscreenMarkerIndicator, projectMarkers, } from './span-markers';
10
+ import styles from './timeline.module.css';
11
+ import { ROW_HEIGHT_PX, useRowWindow } from './use-row-window';
12
+ // ---------------------------------------------------------------------------
13
+ // Constants
14
+ // ---------------------------------------------------------------------------
15
+ const TINY_BAR_BOX_SIZE_PX = 24;
16
+ const TINY_BAR_WIDTH_PX = 4;
17
+ export const TIMELINE_PADDING_PX = 16;
18
+ const SEGMENT_CLASSES = {
19
+ queued: 'bg-gray-400 border border-gray-500',
20
+ pending: 'bg-gray-200 border border-gray-500',
21
+ retrying: 'bg-gray-400 border border-gray-500',
22
+ waiting: 'bg-gray-200 border border-gray-500',
23
+ running: 'bg-blue-200 border border-blue-500',
24
+ completed: 'bg-blue-200 border border-blue-500',
25
+ failed: 'bg-red-200 border border-red-500',
26
+ succeeded: 'bg-green-200 border border-green-500',
27
+ sleeping: 'bg-gray-400 border border-gray-500',
28
+ received: 'bg-blue-200 border border-blue-500',
20
29
  };
21
- const FIXED_BAR_WIDTH_PX = 4;
22
- const SEGMENT_GAP_PX = 1;
23
- // Keep this in sync with the rendered row height in the timeline/event list.
24
- const ROW_HEIGHT = 34;
25
- const CONTAINER_PAD_Y = 8;
26
- const END_CAP_HEIGHT = 8;
30
+ const TIMELINE_INSET_STYLE = {
31
+ left: TIMELINE_PADDING_PX,
32
+ right: TIMELINE_PADDING_PX,
33
+ };
34
+ const STRIPED_SEGMENT_STATUSES = new Set([
35
+ 'pending',
36
+ 'running',
37
+ 'received',
38
+ ]);
39
+ function AnimatedStripes({ status }) {
40
+ return (_jsx("div", { "aria-hidden": true, className: status === 'pending' ? styles.pendingStripes : styles.runningStripes }));
41
+ }
42
+ /**
43
+ * Compute the bar's geometry inside the timeline viewport. Percentages are
44
+ * always in [0, 100] so we never emit CSS values that exceed browser layout
45
+ * limits at extreme zoom.
46
+ */
47
+ function computeBarGeometry(startMs, endMs, viewStart, viewEnd, containerWidth) {
48
+ const viewDuration = viewEnd - viewStart;
49
+ const visibleStartMs = Math.max(startMs, viewStart);
50
+ const visibleEndMs = Math.min(endMs, viewEnd);
51
+ const visibleDurationMs = Math.max(0, visibleEndMs - visibleStartMs);
52
+ const widthFrac = viewDuration > 0 ? visibleDurationMs / viewDuration : 0;
53
+ const visiblePixelWidth = widthFrac * containerWidth;
54
+ const isTiny = containerWidth > 0 && visiblePixelWidth < TINY_BAR_BOX_SIZE_PX;
55
+ const extendsOffLeft = startMs < viewStart;
56
+ const extendsOffRight = endMs > viewEnd;
57
+ const mode = isTiny && (extendsOffLeft || extendsOffRight)
58
+ ? { kind: 'arrow', direction: extendsOffRight ? 'right' : 'left' }
59
+ : isTiny
60
+ ? { kind: 'tiny' }
61
+ : { kind: 'full' };
62
+ return {
63
+ mode,
64
+ leftPct: viewDuration > 0
65
+ ? ((visibleStartMs - viewStart) / viewDuration) * 100
66
+ : 0,
67
+ widthPct: widthFrac * 100,
68
+ visibleStartMs,
69
+ visibleEndMs,
70
+ visiblePixelWidth,
71
+ };
72
+ }
73
+ function getBarPositionStyle(geometry) {
74
+ switch (geometry.mode.kind) {
75
+ case 'arrow':
76
+ return {
77
+ left: geometry.mode.direction === 'right'
78
+ ? `calc(100% - ${TINY_BAR_BOX_SIZE_PX}px)`
79
+ : '0px',
80
+ width: `${TINY_BAR_BOX_SIZE_PX}px`,
81
+ };
82
+ case 'tiny':
83
+ return {
84
+ left: `min(${geometry.leftPct}%, calc(100% - ${TINY_BAR_WIDTH_PX}px))`,
85
+ width: `${TINY_BAR_WIDTH_PX}px`,
86
+ };
87
+ case 'full':
88
+ return {
89
+ left: `${geometry.leftPct}%`,
90
+ width: `max(${geometry.widthPct}%, 4px)`,
91
+ };
92
+ }
93
+ }
94
+ /**
95
+ * Project status segments onto the visible portion of a bar. Segments fully
96
+ * outside the visible window are dropped; segments crossing the edge are
97
+ * clipped to [0%, 100%] of the visible bar.
98
+ */
99
+ function projectSegments(segments, spanStartMs, spanDurationMs, geometry) {
100
+ const visibleDurationMs = geometry.visibleEndMs - geometry.visibleStartMs;
101
+ if (visibleDurationMs <= 0)
102
+ return [];
103
+ return segments.flatMap((seg) => {
104
+ const segStartMs = spanStartMs + seg.startFraction * spanDurationMs;
105
+ const segEndMs = spanStartMs + seg.endFraction * spanDurationMs;
106
+ const startMs = Math.max(segStartMs, geometry.visibleStartMs);
107
+ const endMs = Math.min(segEndMs, geometry.visibleEndMs);
108
+ if (endMs <= startMs)
109
+ return [];
110
+ const widthFrac = (endMs - startMs) / visibleDurationMs;
111
+ return [
112
+ {
113
+ status: seg.status,
114
+ leftPct: ((startMs - geometry.visibleStartMs) / visibleDurationMs) * 100,
115
+ widthPct: widthFrac * 100,
116
+ pixelWidth: widthFrac * geometry.visiblePixelWidth,
117
+ fullDurationMs: (seg.endFraction - seg.startFraction) * spanDurationMs,
118
+ },
119
+ ];
120
+ });
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // Small render helpers
124
+ // ---------------------------------------------------------------------------
125
+ function DurationLabel({ label, className, }) {
126
+ return (_jsx("span", { className: cn('pointer-events-none absolute inset-0 flex items-center justify-start overflow-hidden px-1 text-[10px] font-mono font-medium leading-none whitespace-nowrap text-left text-gray-1000 tabular-nums opacity-0 group-hover/timeline-row:opacity-100', className), children: label }));
127
+ }
128
+ function BoundaryArrow({ direction, }) {
129
+ const Icon = direction === 'right' ? ArrowRight : ArrowLeft;
130
+ return (_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-[0.25rem]", children: _jsx(Icon, { className: "size-3 text-gray-900" }) }));
131
+ }
132
+ function PlainBar({ bg, border, label, }) {
133
+ return (_jsx("div", { className: "relative h-6 w-full min-w-1 rounded-[0.25rem] border", style: { background: bg, borderColor: border }, children: label ? _jsx(DurationLabel, { label: label }) : null }));
134
+ }
135
+ function LeadInConnector({ leftPct, widthPct, label, }) {
136
+ return (_jsxs("div", { className: "absolute top-1/2 h-6 -translate-y-1/2", style: {
137
+ left: `calc(${leftPct}% + 0.5px)`,
138
+ width: `calc(${widthPct}% - 1px)`,
139
+ }, children: [_jsx("div", { className: "absolute left-0 top-1/2 h-4 w-px -translate-y-1/2 bg-gray-500" }), _jsx("div", { className: "absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-gray-500" }), label ? _jsx(DurationLabel, { label: label }) : null] }));
140
+ }
141
+ function SegmentBar({ segments, showLabels = true, }) {
142
+ return (_jsx("div", { className: "relative h-6 w-full", children: segments.map((seg, i) => {
143
+ if (seg.status === 'queued') {
144
+ const leadInLabel = formatDurationPrecise(seg.fullDurationMs);
145
+ const showLeadInLabel = showLabels &&
146
+ seg.pixelWidth >= Math.max(40, leadInLabel.length * 6 + 12);
147
+ const isFullWidthQueued = segments.length === 1;
148
+ return (_jsxs(Fragment, { children: [_jsx(LeadInConnector, { leftPct: seg.leftPct, widthPct: seg.widthPct, label: showLeadInLabel ? leadInLabel : null }), isFullWidthQueued ? (_jsx("div", { className: "absolute top-1/2 h-4 w-px -translate-y-1/2 bg-gray-500", style: {
149
+ left: `calc(${seg.leftPct + seg.widthPct}% - 1.5px)`,
150
+ } })) : null] }, i));
151
+ }
152
+ const label = formatDurationPrecise(seg.fullDurationMs);
153
+ // Only render the label when there's enough room for it without clipping.
154
+ const showLabel = showLabels && seg.pixelWidth >= Math.max(40, label.length * 6 + 12);
155
+ return (_jsxs("div", { className: cn('absolute h-full overflow-hidden rounded-[0.25rem]', SEGMENT_CLASSES[seg.status]), style: {
156
+ // 1px gap between adjacent segments, distributed equally.
157
+ left: `calc(${seg.leftPct}% + 0.5px)`,
158
+ width: `calc(${seg.widthPct}% - 1px)`,
159
+ minWidth: 1,
160
+ }, children: [STRIPED_SEGMENT_STATUSES.has(seg.status) ? (_jsx(AnimatedStripes, { status: seg.status })) : null, showLabel ? _jsx(DurationLabel, { label: label }) : null] }, i));
161
+ }) }));
162
+ }
163
+ // ---------------------------------------------------------------------------
164
+ // TimelineBar
165
+ // ---------------------------------------------------------------------------
166
+ const TimelineBar = memo(function TimelineBar({ span, viewStart, viewDuration, containerWidth, isSelected, isDimmed, onSelect, onRevealTime, }) {
167
+ const startMs = getHighResInMs(span.startTime);
168
+ const endMs = getHighResInMs(span.endTime);
169
+ const totalDurationMs = getSpanDurationMs(span);
170
+ const geometry = useMemo(() => computeBarGeometry(startMs, endMs, viewStart, viewStart + viewDuration, containerWidth), [startMs, endMs, viewStart, viewDuration, containerWidth]);
171
+ const baseSegments = useMemo(() => computeSpanSegments(span), [span]);
172
+ const segments = useMemo(() => geometry.mode.kind === 'full'
173
+ ? projectSegments(baseSegments, startMs, totalDurationMs, geometry)
174
+ : [], [geometry, baseSegments, startMs, totalDurationMs]);
175
+ const baseMarkers = useMemo(() => computeSpanMarkers(span), [span]);
176
+ const markers = useMemo(() => geometry.mode.kind === 'full'
177
+ ? cullCollidingMarkers(projectMarkers(baseMarkers, geometry.visibleStartMs, geometry.visibleEndMs), geometry.visiblePixelWidth)
178
+ : [], [geometry, baseMarkers]);
179
+ // Markers that fall outside the visible window (scrolled off while zoomed in)
180
+ // — surfaced as edge indicators so they aren't silently lost.
181
+ const offscreen = useMemo(() => geometry.mode.kind === 'full'
182
+ ? computeOffscreenMarkers(baseMarkers, geometry.visibleStartMs, geometry.visibleEndMs)
183
+ : { left: null, right: null }, [geometry, baseMarkers]);
184
+ // Markers (visible or off-screen) move the duration label into the overlay,
185
+ // so the in-bar segment label is suppressed.
186
+ const hasMarkers = markers.length > 0 || offscreen.left !== null || offscreen.right !== null;
187
+ const isErrored = isSpanErrored(span);
188
+ const colors = getResourceColor(span.resource);
189
+ const fallbackBg = isErrored
190
+ ? (colors.errorBg ?? 'var(--ds-red-200)')
191
+ : colors.bg;
192
+ const fallbackBorder = isErrored
193
+ ? (colors.errorBorder ?? 'var(--ds-red-500)')
194
+ : colors.border;
195
+ const totalLabel = formatDurationPrecise(totalDurationMs);
196
+ const showTotalLabel = geometry.visiblePixelWidth >= Math.max(40, totalLabel.length * 6 + 12);
197
+ const handleClick = useCallback(() => {
198
+ onSelect(span.spanId);
199
+ }, [onSelect, span.spanId]);
200
+ return (_jsx("div", { role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, className: cn('group/timeline-row h-10 relative flex items-center hover:bg-gray-100 aria-selected:bg-gray-100 aria-selected:hover:bg-gray-200 transition-opacity', isDimmed && 'opacity-35'), onClick: handleClick, children: _jsxs("div", { className: "absolute inset-y-0", style: TIMELINE_INSET_STYLE, children: [_jsx("div", { className: "absolute top-1/2 h-6 -translate-y-1/2 overflow-hidden rounded-[0.25rem]", style: getBarPositionStyle(geometry), children: geometry.mode.kind === 'arrow' ? (_jsx(BoundaryArrow, { direction: geometry.mode.direction })) : geometry.mode.kind === 'tiny' ? (_jsx("div", { className: "h-6 rounded-[0.25rem] border", style: { background: fallbackBg, borderColor: fallbackBorder } })) : segments.length > 0 ? (_jsx(SegmentBar, { segments: segments, showLabels: !hasMarkers })) : (_jsx(PlainBar, { bg: fallbackBg, border: fallbackBorder, label: showTotalLabel ? totalLabel : null })) }), hasMarkers ? (_jsxs("div", { className: "pointer-events-none absolute top-1/2 h-6 -translate-y-1/2", style: getBarPositionStyle(geometry), children: [markers.length > 0 ? _jsx(MarkerLayer, { markers: markers }) : null, offscreen.left ? (_jsx(OffscreenMarkerIndicator, { direction: "left", count: offscreen.left.count, targetMs: offscreen.left.nearestMs, onReveal: onRevealTime })) : null, offscreen.right ? (_jsx(OffscreenMarkerIndicator, { direction: "right", count: offscreen.right.count, targetMs: offscreen.right.nearestMs, onReveal: onRevealTime })) : null, showTotalLabel ? (_jsx(DurationLabel, { label: totalLabel,
201
+ // Shift clear of the left edge indicator so it isn't covered.
202
+ className: offscreen.left ? 'pl-10' : undefined })) : null] })) : null] }) }));
203
+ });
204
+ export { TimelineBar };
205
+ // ---------------------------------------------------------------------------
206
+ // DeltaIndicator (Alt-key gap overlay)
207
+ // ---------------------------------------------------------------------------
208
+ const DELTA_CAP_HEIGHT_PX = 8;
209
+ // Vertical offset to sit the indicator inside the gap between row N and N+1,
210
+ // aligned with where the bar starts in the next row (rows center a 24px bar
211
+ // inside 40px, so bars start ~8px from the top of the row).
212
+ const DELTA_ROW_OFFSET_PX = 8;
27
213
  const DeltaIndicator = memo(function DeltaIndicator({ leftFrac, rightFrac, label, rowIndex, }) {
28
- const centerY = CONTAINER_PAD_Y + (rowIndex + 1) * ROW_HEIGHT;
214
+ const centerY = DELTA_ROW_OFFSET_PX + (rowIndex + 1) * ROW_HEIGHT_PX;
29
215
  return (_jsxs("div", { className: "absolute pointer-events-none", style: {
30
216
  left: `${leftFrac * 100}%`,
31
217
  width: `${(rightFrac - leftFrac) * 100}%`,
32
- top: centerY - END_CAP_HEIGHT / 2,
33
- height: END_CAP_HEIGHT,
218
+ top: centerY - DELTA_CAP_HEIGHT_PX / 2,
219
+ height: DELTA_CAP_HEIGHT_PX,
34
220
  }, children: [_jsx("div", { className: "absolute left-0 top-0 w-px h-full bg-amber-800" }), _jsx("div", { className: "absolute left-0 right-0 top-1/2 h-px bg-amber-800" }), _jsx("div", { className: "absolute right-0 top-0 w-px h-full bg-amber-800" }), _jsx("span", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-label-12 leading-none whitespace-nowrap rounded-xs px-1 py-0.5 text-gray-100 bg-amber-800", children: label })] }));
35
221
  });
36
- const TimelineBar = memo(function TimelineBar({ span, compression, containerWidth, isSelected, onClick, }) {
37
- const startTime = getHighResInMs(span.startTime);
38
- const endTime = getHighResInMs(span.endTime);
39
- const totalDurationMs = endTime - startTime;
40
- const leftFrac = compression.toVisual(startTime);
41
- const rightFrac = compression.toVisual(endTime);
42
- const widthFrac = rightFrac - leftFrac;
43
- const leftPct = leftFrac * 100;
44
- const widthPct = widthFrac * 100;
45
- const pixelWidth = widthFrac * containerWidth;
46
- const isCompressed = containerWidth > 0 && pixelWidth < FIXED_BAR_WIDTH_PX;
47
- const [isRowHovered, setIsRowHovered] = useState(false);
48
- const segments = useMemo(() => computeSpanSegments(span), [span]);
49
- const finalSegment = segments[segments.length - 1];
50
- const workflowStatus = span.attributes.data
51
- ?.status;
52
- const isErrored = span.status.code === 2 || workflowStatus === 'failed';
53
- const colors = getResourceColor(span.resource);
54
- const fallbackColor = isErrored
55
- ? (colors.errorBar ?? 'var(--ds-red-700)')
56
- : colors.bar;
57
- const compressedSegmentStatus = isErrored
58
- ? 'failed'
59
- : span.resource === 'hook'
60
- ? 'received'
61
- : finalSegment?.status;
62
- const compressedSegmentStyle = compressedSegmentStatus === 'queued'
63
- ? { background: 'var(--ds-gray-500)' }
64
- : compressedSegmentStatus
65
- ? SEGMENT_CONFIG[compressedSegmentStatus].style
66
- : undefined;
67
- const compressedSegmentClassName = compressedSegmentStatus
68
- ? SEGMENT_CONFIG[compressedSegmentStatus].className
69
- : undefined;
70
- const hasCompressedStatus = Boolean(compressedSegmentClassName || compressedSegmentStyle);
71
- const renderDurationLabel = (label) => (_jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-start overflow-hidden px-1 text-[10px] font-mono font-medium leading-none whitespace-nowrap text-left text-white tabular-nums", style: { textShadow: '0 1px 1px rgba(0, 0, 0, 0.45)' }, children: label }));
72
- const getMinDurationLabelWidthPx = (label) => Math.max(40, label.length * 6 + 12);
73
- const totalDurationLabel = formatDuration(totalDurationMs);
74
- const showBarDurationLabel = isRowHovered &&
75
- pixelWidth >= getMinDurationLabelWidthPx(totalDurationLabel);
76
- const barContent = isCompressed ? (_jsx("div", { className: cn('relative h-4 rounded-[0.25rem] top-[3px]', compressedSegmentClassName), style: {
77
- width: '100%',
78
- background: hasCompressedStatus ? undefined : fallbackColor,
79
- ...compressedSegmentStyle,
80
- }, children: showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null })) : segments.length > 0 ? (_jsx("div", { className: "relative w-full h-4 top-[3px]", children: segments.map((seg, i) => {
81
- const segPixelWidth = (seg.endFraction - seg.startFraction) * pixelWidth;
82
- const segDurationLabel = formatDuration((seg.endFraction - seg.startFraction) * totalDurationMs);
83
- const showSegmentDurationLabel = isRowHovered &&
84
- segPixelWidth >= getMinDurationLabelWidthPx(segDurationLabel);
85
- const segStyle = seg.status === 'queued' && segPixelWidth < 20
86
- ? { background: 'var(--ds-gray-500)' }
87
- : SEGMENT_CONFIG[seg.status].style;
88
- return (_jsx("div", { className: cn('absolute h-full rounded-[0.25rem]', SEGMENT_CONFIG[seg.status].className), style: {
89
- left: `calc(${seg.startFraction * 100}% + ${SEGMENT_GAP_PX / 2}px)`,
90
- width: `calc(${(seg.endFraction - seg.startFraction) * 100}% - ${SEGMENT_GAP_PX}px)`,
91
- minWidth: 1,
92
- ...segStyle,
93
- }, children: showSegmentDurationLabel
94
- ? renderDurationLabel(segDurationLabel)
95
- : null }, `${seg.status}-${i}`));
96
- }) })) : (_jsx("div", { className: "relative h-4 rounded-[0.25rem] top-[3px]", style: {
97
- width: '100%',
98
- minWidth: 4,
99
- background: fallbackColor,
100
- }, children: showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null }));
101
- return (_jsx("div", { role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, className: cn('h-[34px] relative flex items-center hover:bg-gray-100 aria-selected:bg-gray-100 rounded-sm aria-selected:hover:bg-gray-200'), onMouseEnter: () => setIsRowHovered(true), onMouseLeave: () => setIsRowHovered(false), onClick: onClick, children: _jsx("div", { className: "absolute top-1.5 h-[22px] rounded-sm", style: {
102
- left: isCompressed
103
- ? `min(${leftPct}%, calc(100% - ${FIXED_BAR_WIDTH_PX}px))`
104
- : `${leftPct}%`,
105
- width: isCompressed
106
- ? `${FIXED_BAR_WIDTH_PX}px`
107
- : `max(${widthPct}%, 4px)`,
108
- }, children: barContent }) }));
109
- });
110
- export { TimelineBar };
111
- export function TimelineHeader({ viewStart, viewDuration, rootStart, compression, isZoomed, onResetZoom, hoverInfo, }) {
112
- const viewEnd = viewStart + viewDuration;
113
- const markers = useMemo(() => compression.isCompressed
114
- ? computeCompressedTimeMarkers(compression, viewStart, viewEnd, rootStart)
115
- : computeTimeMarkers(viewDuration, viewStart - rootStart), [compression, viewStart, viewEnd, viewDuration, rootStart]);
116
- return (_jsxs("div", { className: "relative bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-end px-2 pb-1", children: [_jsxs("div", { className: "relative h-full flex-1", children: [markers.map((m, i) => (_jsx("span", { className: "absolute bottom-1 font-mono text-xs font-normal leading-4 text-gray-900 whitespace-nowrap", style: { left: `${m.position * 100}%` }, children: m.label }, i))), hoverInfo && (_jsx("span", { className: "absolute top-1 pointer-events-none z-10 font-mono text-[11px] leading-4 text-gray-1000 whitespace-nowrap bg-background-100 border border-gray-alpha-400 rounded px-1 -translate-x-1/2", style: { left: `${hoverInfo.fraction * 100}%` }, children: hoverInfo.label }))] }), isZoomed && (_jsx("button", { type: "button", className: "absolute right-2 top-1/2 -translate-y-1/2 z-[5] flex items-center py-0.5 px-2 border border-gray-alpha-400 rounded-md bg-background-100 font-sans text-[11px] font-medium text-gray-900 cursor-pointer whitespace-nowrap transition-[color,border-color] duration-[120ms] ease-in-out hover:text-gray-1000 hover:border-gray-600", onClick: onResetZoom, children: "Reset zoom" }))] }));
222
+ // ---------------------------------------------------------------------------
223
+ // TimelineHeader
224
+ // ---------------------------------------------------------------------------
225
+ export function TimelineHeader({ markers, hoverInfo, }) {
226
+ return (_jsx("div", { className: "relative bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-end px-4 pb-1", children: _jsxs("div", { className: "relative h-full flex-1", children: [markers.map((m) => (_jsx("span", { className: "absolute bottom-1 font-mono text-xs font-normal leading-4 text-gray-900 whitespace-nowrap", style: { left: `${m.position * 100}%` }, children: m.label }, String(m.value)))), hoverInfo && (_jsx("span", { className: "absolute top-1 pointer-events-none z-10 font-mono text-[11px] leading-4 text-gray-1000 whitespace-nowrap bg-background-100 border border-gray-alpha-400 rounded px-1 -translate-x-1/2", style: { left: `${hoverInfo.fraction * 100}%` }, children: hoverInfo.label }))] }) }));
117
227
  }
118
- export function Timeline({ spans, compression, selectedId, onSelect, hoverFraction, altHeld = false, }) {
228
+ // ---------------------------------------------------------------------------
229
+ // Timeline
230
+ // ---------------------------------------------------------------------------
231
+ export function Timeline({ spans, viewStart, viewEnd, markers, selectedId, searchResult, onSelect, onRevealTime, hoverFraction, altHeld = false, }) {
119
232
  const containerRef = useRef(null);
120
233
  const [containerWidth, setContainerWidth] = useState(0);
234
+ const viewDuration = viewEnd - viewStart;
235
+ const timelineWidth = Math.max(0, containerWidth - TIMELINE_PADDING_PX * 2);
236
+ const { start, end } = useRowWindow(containerRef, spans.length, ROW_HEIGHT_PX);
121
237
  useEffect(() => {
122
238
  const el = containerRef.current;
123
239
  if (!el)
@@ -128,7 +244,9 @@ export function Timeline({ spans, compression, selectedId, onSelect, hoverFracti
128
244
  ro.observe(el);
129
245
  return () => ro.disconnect();
130
246
  }, []);
131
- const gaps = useMemo(() => computeSpanGaps(spans, compression), [spans, compression]);
132
- return (_jsxs("div", { ref: containerRef, className: "relative py-2", children: [hoverFraction != null && (_jsx("div", { className: "absolute top-0 bottom-0 w-px bg-gray-alpha-400 pointer-events-none z-10", style: { left: `${hoverFraction * 100}%` } })), spans.map((span) => (_jsx(TimelineBar, { span: span, compression: compression, containerWidth: containerWidth, isSelected: selectedId === span.spanId, onClick: () => onSelect(span.spanId) }, span.spanId))), altHeld && (_jsx("div", { "aria-hidden": true, className: "absolute inset-0 pointer-events-none", children: gaps.map((gap) => (_jsx(DeltaIndicator, { leftFrac: gap.leftFrac, rightFrac: gap.rightFrac, label: formatDuration(gap.gapMs, true), rowIndex: gap.rowIndex }, gap.rowIndex))) }))] }));
247
+ const gaps = useMemo(() => computeSpanGaps(spans, viewStart, viewEnd), [spans, viewStart, viewEnd]);
248
+ return (_jsxs("div", { ref: containerRef, className: "relative h-full overflow-hidden", style: { minHeight: spans.length * ROW_HEIGHT_PX }, children: [_jsx("div", { "aria-hidden": true, className: "absolute inset-y-0 pointer-events-none", style: TIMELINE_INSET_STYLE, children: markers.map((marker) =>
249
+ // Skip the "0s" origin marker since the left edge already implies it.
250
+ Math.abs(marker.value) > 0.000001 ? (_jsx("div", { className: "absolute top-0 bottom-0 w-px bg-gray-alpha-300", style: { left: `${marker.position * 100}%` } }, String(marker.value))) : null) }), hoverFraction != null && (_jsx("div", { className: "absolute inset-y-0 pointer-events-none z-10", style: TIMELINE_INSET_STYLE, children: _jsx("div", { className: "absolute top-0 bottom-0 w-px bg-gray-alpha-500", style: { left: `${hoverFraction * 100}%` } }) })), _jsx("div", { style: { transform: `translateY(${start * ROW_HEIGHT_PX}px)` }, children: spans.slice(start, end).map((span) => (_jsx(TimelineBar, { span: span, viewStart: viewStart, viewDuration: viewDuration, containerWidth: timelineWidth, isSelected: selectedId === span.spanId, isDimmed: isSpanDimmedBySearch(span.spanId, searchResult), onSelect: onSelect, onRevealTime: onRevealTime }, span.spanId))) }), altHeld && (_jsx("div", { "aria-hidden": true, className: "absolute inset-y-0 pointer-events-none", style: TIMELINE_INSET_STYLE, children: gaps.map((gap) => (_jsx(DeltaIndicator, { leftFrac: gap.leftFrac, rightFrac: gap.rightFrac, label: formatDurationPrecise(gap.gapMs), rowIndex: gap.rowIndex }, gap.rowIndex))) }))] }));
133
251
  }
134
- //# sourceMappingURL=timeline.js.map
252
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZWxpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9uZXctdHJhY2Utdmlld2VyL2NvbXBvbmVudHMvdGltZWxpbmUudHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVksQ0FBQzs7QUFFYixPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsUUFBUSxFQUNSLElBQUksRUFDSixXQUFXLEVBQ1gsU0FBUyxFQUNULE9BQU8sRUFDUCxNQUFNLEVBQ04sUUFBUSxHQUNULE1BQU0sT0FBTyxDQUFDO0FBQ2YsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3JDLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsY0FBYyxHQUNmLE1BQU0sZ0NBQWdDLENBQUM7QUFDeEMsT0FBTyxFQUFFLG9CQUFvQixFQUF5QixNQUFNLFdBQVcsQ0FBQztBQVF4RSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGVBQWUsRUFDZixrQkFBa0IsRUFDbEIsbUJBQW1CLEVBQ25CLGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIsYUFBYSxHQUNkLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsV0FBVyxFQUNYLHdCQUF3QixFQUN4QixjQUFjLEdBQ2YsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLE1BQU0sTUFBTSx1QkFBdUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsYUFBYSxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRS9ELDhFQUE4RTtBQUM5RSxZQUFZO0FBQ1osOEVBQThFO0FBRTlFLE1BQU0sb0JBQW9CLEdBQUcsRUFBRSxDQUFDO0FBQ2hDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0FBQzVCLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsQ0FBQztBQUV0QyxNQUFN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QUMxQyxHQUNFLENBQ1AsRUFDRCxjQUFLLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxjQUFjLEtBQUssR0FBRyxhQUFhLEtBQUssRUFBRSxZQUNoRSxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQ3JDLEtBQUMsV0FBVyxJQUVWLElBQUksRUFBRSxJQUFJLEVBQ1YsU0FBUyxFQUFFLFNBQVMsRUFDcEIsWUFBWSxFQUFFLFlBQVksRUFDMUIsY0FBYyxFQUFFLGFBQWEsRUFDN0IsVUFBVSxFQUFFLFVBQVUsS0FBSyxJQUFJLENBQUMsTUFBTSxFQUN0QyxRQUFRLEVBQUUsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsRUFDekQsUUFBUSxFQUFFLFFBQVEsRUFDbEIsWUFBWSxFQUFFLFlBQVksSUFSckIsSUFBSSxDQUFDLE1BQU0sQ0FTaEIsQ0FDSCxDQUFDLEdBQ0UsRUFDTCxPQUFPLElBQUksQ0FDVixtQ0FFRSxTQUFTLEVBQUMsd0NBQXdDLEVBQ2xELEtBQUssRUFBRSxvQkFBb0IsWUFFMUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FDakIsS0FBQyxjQUFjLElBRWIsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQ3RCLFNBQVMsRUFBRSxHQUFHLENBQUMsU0FBUyxFQUN4QixLQUFLLEVBQUUscUJBQXFCLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUN2QyxRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVEsSUFKakIsR0FBRyxDQUFDLFFBQVEsQ0FLakIsQ0FDSCxDQUFDLEdBQ0UsQ0FDUCxJQUNHLENBQ1AsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIGNsaWVudCc7XG5cbmltcG9ydCB7IEFycm93TGVmdCwgQXJyb3dSaWdodCB9IGZyb20gJ2x1Y2lkZS1yZWFjdCc7XG5pbXBvcnQgdHlwZSB7IENTU1Byb3BlcnRpZXMsIFJlYWN0Tm9kZSB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7XG4gIEZyYWdtZW50LFxuICBtZW1vLFxuICB1c2VDYWxsYmFjayxcbiAgdXNlRWZmZWN0LFxuICB1c2VNZW1vLFxuICB1c2VSZWYsXG4gIHVzZVN0YXRlLFxufSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBjbiB9IGZyb20gJy4uLy4uLy4uL2xpYi9jbic7XG5pbXBvcnQge1xuICBmb3JtYXREdXJhdGlvblByZWNpc2UsXG4gIGdldEhpZ2hSZXNJbk1zLFxufSBmcm9tICcuLi8uLi90cmFjZS12aWV3ZXIvdXRpbC90aW1pbmcnO1xuaW1wb3J0IHsgaXNTcGFuRGltbWVkQnlTZWFyY2gsIHR5cGUgU3BhblNlYXJjaFJlc3VsdCB9IGZyb20gJy4uL3NlYXJjaCc7XG5pbXBvcnQgdHlwZSB7IFNwYW4gfSBmcm9tICcuLi90eXBlcyc7XG5pbXBvcnQgdHlwZSB7XG4gIE9mZnNjcmVlbk1hcmtlcnMsXG4gIFNlZ21lbnQsXG4gIFNlZ21lbnRTdGF0dXMsXG4gIFRpbWVNYXJrZXIsXG59IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7XG4gIGNvbXB1dGVPZmZzY3JlZW5NYXJrZXJzLFxuICBjb21wdXRlU3BhbkdhcHMsXG4gIGNvbXB1dGVTcGFuTWFya2VycyxcbiAgY29tcHV0ZVNwYW5TZWdtZW50cyxcbiAgZ2V0UmVzb3VyY2VDb2xvcixcbiAgZ2V0U3BhbkR1cmF0aW9uTXMsXG4gIGlzU3BhbkVycm9yZWQsXG59IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7XG4gIGN1bGxDb2xsaWRpbmdNYXJrZXJzLFxuICBNYXJrZXJMYXllcixcbiAgT2Zmc2NyZWVuTWFya2VySW5kaWNhdG9yLFxuICBwcm9qZWN0TWFya2Vycyxcbn0gZnJvbSAnLi9zcGFuLW1hcmtlcnMnO1xuaW1wb3J0IHN0eWxlcyBmcm9tICcuL3RpbWVsaW5lLm1vZHVsZS5jc3MnO1xuaW1wb3J0IHsgUk9XX0hFSUdIVF9QWCwgdXNlUm93V2luZG93IH0gZnJvbSAnLi91c2Utcm93LXdpbmRvdyc7XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ29uc3RhbnRzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuY29uc3QgVElOWV9CQVJfQk9YX1NJWkVfUFggPSAyNDtcbmNvbnN0IFRJTllfQkFSX1dJRFRIX1BYID0gNDtcbmV4cG9ydCBjb25zdCBUSU1FTElORV9QQURESU5HX1BYID0gMTY7XG5cbmNvbnN0IFNFR01FTlRfQ0xBU1NFUzogUmVjb3JkPFNlZ21lbnRTdGF0dXMsIHN0cmluZz4gPSB7XG4gIHF1ZXVlZDogJ2JnLWdyYXktNDAwIGJvcmRlciBib3JkZXItZ3JheS01MDAnLFxuICBwZW5kaW5nOiAnYmctZ3JheS0yMDAgYm9yZGVyIGJvcmRlci1ncmF5LTUwMCcsXG4gIHJldHJ5aW5nOiAnYmctZ3JheS00MDAgYm9yZGVyIGJvcmRlci1ncmF5LTUwMCcsXG4gIHdhaXRpbmc6ICdiZy1ncmF5LTIwMCBib3JkZXIgYm9yZGVyLWdyYXktNTAwJyxcbiAgcnVubmluZzogJ2JnLWJsdWUtMjAwIGJvcmRlciBib3JkZXItYmx1ZS01MDAnLFxuICBjb21wbGV0ZWQ6ICdiZy1ibHVlLTIwMCBib3JkZXIgYm9yZGVyLWJsdWUtNTAwJyxcbiAgZmFpbGVkOiAnYmctcmVkLTIwMCBib3JkZXIgYm9yZGVyLXJlZC01MDAnLFxuICBzdWNjZWVkZWQ6ICdiZy1ncmVlbi0yMDAgYm9yZGVyIGJvcmRlci1ncmVlbi01MDAnLFxuICBzbGVlcGluZzogJ2JnLWdyYXktNDAwIGJvcmRlciBib3JkZXItZ3JheS01MDAnLFxuICByZWNlaXZlZDogJ2JnLWJsdWUtMjAwIGJvcmRlciBib3JkZXItYmx1ZS01MDAnLFxufTtcblxuY29uc3QgVElNRUxJTkVfSU5TRVRfU1RZTEU6IENTU1Byb3BlcnRpZXMgPSB7XG4gIGxlZnQ6IFRJTUVMSU5FX1BBRERJTkdfUFgsXG4gIHJpZ2h0OiBUSU1FTElORV9QQURESU5HX1BYLFxufTtcblxuY29uc3QgU1RSSVBFRF9TRUdNRU5UX1NUQVRVU0VTOiBSZWFkb25seVNldDxTZWdtZW50U3RhdHVzPiA9IG5ldyBTZXQoW1xuICAncGVuZGluZycsXG4gICdydW5uaW5nJyxcbiAgJ3JlY2VpdmVkJyxcbl0pO1xuXG5mdW5jdGlvbiBBbmltYXRlZFN0cmlwZXMoeyBzdGF0dXMgfTogeyBzdGF0dXM6IFNlZ21lbnRTdGF0dXMgfSk6IFJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPGRpdlxuICAgICAgYXJpYS1oaWRkZW5cbiAgICAgIGNsYXNzTmFtZT17XG4gICAgICAgIHN0YXR1cyA9PT0gJ3BlbmRpbmcnID8gc3R5bGVzLnBlbmRpbmdTdHJpcGVzIDogc3R5bGVzLnJ1bm5pbmdTdHJpcGVzXG4gICAgICB9XG4gICAgLz5cbiAgKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBCYXIgZ2VvbWV0cnlcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50eXBlIEJhck1vZGUgPVxuICB8IHsga2luZDogJ2Fycm93JzsgZGlyZWN0aW9uOiAnbGVmdCcgfCAncmlnaHQnIH1cbiAgfCB7IGtpbmQ6ICd0aW55JyB9XG4gIHwgeyBraW5kOiAnZnVsbCcgfTtcblxuaW50ZXJmYWNlIEJhckdlb21ldHJ5IHtcbiAgbW9kZTogQmFyTW9kZTtcbiAgbGVmdFBjdDogbnVtYmVyO1xuICB3aWR0aFBjdDogbnVtYmVyO1xuICB2aXNpYmxlU3RhcnRNczogbnVtYmVyO1xuICB2aXNpYmxlRW5kTXM6IG51bWJlcjtcbiAgdmlzaWJsZVBpeGVsV2lkdGg6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBDb21wdXRlIHRoZSBiYXIncyBnZW9tZXRyeSBpbnNpZGUgdGhlIHRpbWVsaW5lIHZpZXdwb3J0LiBQZXJjZW50YWdlcyBhcmVcbiAqIGFsd2F5cyBpbiBbMCwgMTAwXSBzbyB3ZSBuZXZlciBlbWl0IENTUyB2YWx1ZXMgdGhhdCBleGNlZWQgYnJvd3NlciBsYXlvdXRcbiAqIGxpbWl0cyBhdCBleHRyZW1lIHpvb20uXG4gKi9cbmZ1bmN0aW9uIGNvbXB1dGVCYXJHZW9tZXRyeShcbiAgc3RhcnRNczogbnVtYmVyLFxuICBlbmRNczogbnVtYmVyLFxuICB2aWV3U3RhcnQ6IG51bWJlcixcbiAgdmlld0VuZDogbnVtYmVyLFxuICBjb250YWluZXJXaWR0aDogbnVtYmVyXG4pOiBCYXJHZW9tZXRyeSB7XG4gIGNvbnN0IHZpZXdEdXJhdGlvbiA9IHZpZXdFbmQgLSB2aWV3U3RhcnQ7XG4gIGNvbnN0IHZpc2libGVTdGFydE1zID0gTWF0aC5tYXgoc3RhcnRNcywgdmlld1N0YXJ0KTtcbiAgY29uc3QgdmlzaWJsZUVuZE1zID0gTWF0aC5taW4oZW5kTXMsIHZpZXdFbmQpO1xuICBjb25zdCB2aXNpYmxlRHVyYXRpb25NcyA9IE1hdGgubWF4KDAsIHZpc2libGVFbmRNcyAtIHZpc2libGVTdGFydE1zKTtcbiAgY29uc3Qgd2lkdGhGcmFjID0gdmlld0R1cmF0aW9uID4gMCA/IHZpc2libGVEdXJhdGlvbk1zIC8gdmlld0R1cmF0aW9uIDogMDtcbiAgY29uc3QgdmlzaWJsZVBpeGVsV2lkdGggPSB3aWR0aEZyYWMgKiBjb250YWluZXJXaWR0aDtcblxuICBjb25zdCBpc1RpbnkgPSBjb250YWluZXJXaWR0aCA+IDAgJiYgdmlzaWJsZVBpeGVsV2lkdGggPCBUSU5ZX0JBUl9CT1hfU0laRV9QWDtcbiAgY29uc3QgZXh0ZW5kc09mZkxlZnQgPSBzdGFydE1zIDwgdmlld1N0YXJ0O1xuICBjb25zdCBleHRlbmRzT2ZmUmlnaHQgPSBlbmRNcyA+IHZpZXdFbmQ7XG5cbiAgY29uc3QgbW9kZTogQmFyTW9kZSA9XG4gICAgaXNUaW55ICYmIChleHRlbmRzT2ZmTGVmdCB8fCBleHRlbmRzT2ZmUmlnaHQpXG4gICAgICA/IHsga2luZDogJ2Fycm93JywgZGlyZWN0aW9uOiBleHRlbmRzT2ZmUmlnaHQgPyAncmlnaHQnIDogJ2xlZnQnIH1cbiAgICAgIDogaXNUaW55XG4gICAgICAgID8geyBraW5kOiAndGlueScgfVxuICAgICAgICA6IHsga2luZDogJ2Z1bGwnIH07XG5cbiAgcmV0dXJuIHtcbiAgICBtb2RlLFxuICAgIGxlZnRQY3Q6XG4gICAgICB2aWV3RHVyYXRpb24gPiAwXG4gICAgICAgID8gKCh2aXNpYmxlU3RhcnRNcyAtIHZpZXdTdGFydCkgLyB2aWV3RHVyYXRpb24pICogMTAwXG4gICAgICAgIDogMCxcbiAgICB3aWR0aFBjdDogd2lkdGhGcmFjICogMTAwLFxuICAgIHZpc2libGVTdGFydE1zLFxuICAgIHZpc2libGVFbmRNcyxcbiAgICB2aXNpYmxlUGl4ZWxXaWR0aCxcbiAgfTtcbn1cblxuZnVuY3Rpb24gZ2V0QmFyUG9zaXRpb25TdHlsZShnZW9tZXRyeTogQmFyR2VvbWV0cnkpOiB7XG4gIGxlZnQ6IHN0cmluZztcbiAgd2lkdGg6IHN0cmluZztcbn0ge1xuICBzd2l0Y2ggKGdlb21ldHJ5Lm1vZGUua2luZCkge1xuICAgIGNhc2UgJ2Fycm93JzpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6XG4gICAgICAgICAgZ2VvbWV0cnkubW9kZS5kaXJlY3Rpb24gPT09ICdyaWdodCdcbiAgICAgICAgICAgID8gYGNhbGMoMTAwJSAtICR7VElOWV9CQVJfQk9YX1NJWkVfUFh9cHgpYFxuICAgICAgICAgICAgOiAnMHB4JyxcbiAgICAgICAgd2lkdGg6IGAke1RJTllfQkFSX0JPWF9TSVpFX1BYfXB4YCxcbiAgICAgIH07XG4gICAgY2FzZSAndGlueSc6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBsZWZ0OiBgbWluKCR7Z2VvbWV0cnkubGVmdFBjdH0lLCBjYWxjKDEwMCUgLSAke1RJTllfQkFSX1dJRFRIX1BYfXB4KSlgLFxuICAgICAgICB3aWR0aDogYCR7VElOWV9CQVJfV0lEVEhfUFh9cHhgLFxuICAgICAgfTtcbiAgICBjYXNlICdmdWxsJzpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IGAke2dlb21ldHJ5LmxlZnRQY3R9JWAsXG4gICAgICAgIHdpZHRoOiBgbWF4KCR7Z2VvbWV0cnkud2lkdGhQY3R9JSwgNHB4KWAsXG4gICAgICB9O1xuICB9XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2VnbWVudCBwcm9qZWN0aW9uXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuaW50ZXJmYWNlIFZpc2libGVTZWdtZW50IHtcbiAgc3RhdHVzOiBTZWdtZW50U3RhdHVzO1xuICBsZWZ0UGN0OiBudW1iZXI7XG4gIHdpZHRoUGN0OiBudW1iZXI7XG4gIHBpeGVsV2lkdGg6IG51bWJlcjtcbiAgZnVsbER1cmF0aW9uTXM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBQcm9qZWN0IHN0YXR1cyBzZWdtZW50cyBvbnRvIHRoZSB2aXNpYmxlIHBvcnRpb24gb2YgYSBiYXIuIFNlZ21lbnRzIGZ1bGx5XG4gKiBvdXRzaWRlIHRoZSB2aXNpYmxlIHdpbmRvdyBhcmUgZHJvcHBlZDsgc2VnbWVudHMgY3Jvc3NpbmcgdGhlIGVkZ2UgYXJlXG4gKiBjbGlwcGVkIHRvIFswJSwgMTAwJV0gb2YgdGhlIHZpc2libGUgYmFyLlxuICovXG5mdW5jdGlvbiBwcm9qZWN0U2VnbWVudHMoXG4gIHNlZ21lbnRzOiBTZWdtZW50W10sXG4gIHNwYW5TdGFydE1zOiBudW1iZXIsXG4gIHNwYW5EdXJhdGlvbk1zOiBudW1iZXIsXG4gIGdlb21ldHJ5OiBCYXJHZW9tZXRyeVxuKTogVmlzaWJsZVNlZ21lbnRbXSB7XG4gIGNvbnN0IHZpc2libGVEdXJhdGlvbk1zID0gZ2VvbWV0cnkudmlzaWJsZUVuZE1zIC0gZ2VvbWV0cnkudmlzaWJsZVN0YXJ0TXM7XG4gIGlmICh2aXNpYmxlRHVyYXRpb25NcyA8PSAwKSByZXR1cm4gW107XG5cbiAgcmV0dXJuIHNlZ21lbnRzLmZsYXRNYXAoKHNlZykgPT4ge1xuICAgIGNvbnN0IHNlZ1N0YXJ0TXMgPSBzcGFuU3RhcnRNcyArIHNlZy5zdGFydEZyYWN0aW9uICogc3BhbkR1cmF0aW9uTXM7XG4gICAgY29uc3Qgc2VnRW5kTXMgPSBzcGFuU3RhcnRNcyArIHNlZy5lbmRGcmFjdGlvbiAqIHNwYW5EdXJhdGlvbk1zO1xuICAgIGNvbnN0IHN0YXJ0TXMgPSBNYXRoLm1heChzZWdTdGFydE1zLCBnZW9tZXRyeS52aXNpYmxlU3RhcnRNcyk7XG4gICAgY29uc3QgZW5kTXMgPSBNYXRoLm1pbihzZWdFbmRNcywgZ2VvbWV0cnkudmlzaWJsZUVuZE1zKTtcbiAgICBpZiAoZW5kTXMgPD0gc3RhcnRNcykgcmV0dXJuIFtdO1xuXG4gICAgY29uc3Qgd2lkdGhGcmFjID0gKGVuZE1zIC0gc3RhcnRNcykgLyB2aXNpYmxlRHVyYXRpb25NcztcbiAgICByZXR1cm4gW1xuICAgICAge1xuICAgICAgICBzdGF0dXM6IHNlZy5zdGF0dXMsXG4gICAgICAgIGxlZnRQY3Q6XG4gICAgICAgICAgKChzdGFydE1zIC0gZ2VvbWV0cnkudmlzaWJsZVN0YXJ0TXMpIC8gdmlzaWJsZUR1cmF0aW9uTXMpICogMTAwLFxuICAgICAgICB3aWR0aFBjdDogd2lkdGhGcmFjICogMTAwLFxuICAgICAgICBwaXhlbFdpZHRoOiB3aWR0aEZyYWMgKiBnZW9tZXRyeS52aXNpYmxlUGl4ZWxXaWR0aCxcbiAgICAgICAgZnVsbER1cmF0aW9uTXM6IChzZWcuZW5kRnJhY3Rpb24gLSBzZWcuc3RhcnRGcmFjdGlvbikgKiBzcGFuRHVyYXRpb25NcyxcbiAgICAgIH0sXG4gICAgXTtcbiAgfSk7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU21hbGwgcmVuZGVyIGhlbHBlcnNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5mdW5jdGlvbiBEdXJhdGlvbkxhYmVsKHtcbiAgbGFiZWwsXG4gIGNsYXNzTmFtZSxcbn06IHtcbiAgbGFiZWw6IHN0cmluZztcbiAgY2xhc3NOYW1lPzogc3RyaW5nO1xufSk6IFJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPHNwYW5cbiAgICAgIGNsYXNzTmFtZT17Y24oXG4gICAgICAgICdwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIGluc2V0LTAgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1zdGFydCBvdmVyZmxvdy1oaWRkZW4gcHgtMSB0ZXh0LVsxMHB4XSBmb250LW1vbm8gZm9udC1tZWRpdW0gbGVhZGluZy1ub25lIHdoaXRlc3BhY2Utbm93cmFwIHRleHQtbGVmdCB0ZXh0LWdyYXktMTAwMCB0YWJ1bGFyLW51bXMgb3BhY2l0eS0wIGdyb3VwLWhvdmVyL3RpbWVsaW5lLXJvdzpvcGFjaXR5LTEwMCcsXG4gICAgICAgIGNsYXNzTmFtZVxuICAgICAgKX1cbiAgICA+XG4gICAgICB7bGFiZWx9XG4gICAgPC9zcGFuPlxuICApO1xufVxuXG5mdW5jdGlvbiBCb3VuZGFyeUFycm93KHtcbiAgZGlyZWN0aW9uLFxufToge1xuICBkaXJlY3Rpb246ICdsZWZ0JyB8ICdyaWdodCc7XG59KTogUmVhY3ROb2RlIHtcbiAgY29uc3QgSWNvbiA9IGRpcmVjdGlvbiA9PT0gJ3JpZ2h0JyA/IEFycm93UmlnaHQgOiBBcnJvd0xlZnQ7XG4gIHJldHVybiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4IGgtNiB3LTYgaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHJvdW5kZWQtWzAuMjVyZW1dXCI+XG4gICAgICA8SWNvbiBjbGFzc05hbWU9XCJzaXplLTMgdGV4dC1ncmF5LTkwMFwiIC8+XG4gICAgPC9kaXY+XG4gICk7XG59XG5cbmZ1bmN0aW9uIFBsYWluQmFyKHtcbiAgYmcsXG4gIGJvcmRlcixcbiAgbGFiZWwsXG59OiB7XG4gIGJnOiBzdHJpbmc7XG4gIGJvcmRlcjogc3RyaW5nO1xuICBsYWJlbDogc3RyaW5nIHwgbnVsbDtcbn0pOiBSZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxkaXZcbiAgICAgIGNsYXNzTmFtZT1cInJlbGF0aXZlIGgtNiB3LWZ1bGwgbWluLXctMSByb3VuZGVkLVswLjI1cmVtXSBib3JkZXJcIlxuICAgICAgc3R5bGU9e3sgYmFja2dyb3VuZDogYmcsIGJvcmRlckNvbG9yOiBib3JkZXIgfX1cbiAgICA+XG4gICAgICB7bGFiZWwgPyA8RHVyYXRpb25MYWJlbCBsYWJlbD17bGFiZWx9IC8+IDogbnVsbH1cbiAgICA8L2Rpdj5cbiAgKTtcbn1cblxuZnVuY3Rpb24gTGVhZEluQ29ubmVjdG9yKHtcbiAgbGVmdFBjdCxcbiAgd2lkdGhQY3QsXG4gIGxhYmVsLFxufToge1xuICBsZWZ0UGN0OiBudW1iZXI7XG4gIHdpZHRoUGN0OiBudW1iZXI7XG4gIGxhYmVsOiBzdHJpbmcgfCBudWxsO1xufSk6IFJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPGRpdlxuICAgICAgY2xhc3NOYW1lPVwiYWJzb2x1dGUgdG9wLTEvMiBoLTYgLXRyYW5zbGF0ZS15LTEvMlwiXG4gICAgICBzdHlsZT17e1xuICAgICAgICBsZWZ0OiBgY2FsYygke2xlZnRQY3R9JSArIDAuNXB4KWAsXG4gICAgICAgIHdpZHRoOiBgY2FsYygke3dpZHRoUGN0fSUgLSAxcHgpYCxcbiAgICAgIH19XG4gICAgPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJhYnNvbHV0ZSBsZWZ0LTAgdG9wLTEvMiBoLTQgdy1weCAtdHJhbnNsYXRlLXktMS8yIGJnLWdyYXktNTAwXCIgLz5cbiAgICAgIDxkaXYgY2xhc3NOYW1lPVwiYWJzb2x1dGUgaW5zZXQteC0wIHRvcC0xLzIgaC1weCAtdHJhbnNsYXRlLXktMS8yIGJnLWdyYXktNTAwXCIgLz5cbiAgICAgIHtsYWJlbCA/IDxEdXJhdGlvbkxhYmVsIGxhYmVsPXtsYWJlbH0gLz4gOiBudWxsfVxuICAgIDwvZGl2PlxuICApO1xufVxuXG5mdW5jdGlvbiBTZWdtZW50QmFyKHtcbiAgc2VnbWVudHMsXG4gIHNob3dMYWJlbHMgPSB0cnVlLFxufToge1xuICBzZWdtZW50czogVmlzaWJsZVNlZ21lbnRbXTtcbiAgLyoqXG4gICAqIFdoZW4gZmFsc2UsIHNlZ21lbnQgZHVyYXRpb24gbGFiZWxzIGFyZSBzdXBwcmVzc2VkLiBVc2VkIHdoZW4gYSBzZXBhcmF0ZVxuICAgKiB0b3AgbGF5ZXIgKGUuZy4gdGhlIHJlc3VtcHRpb24tbWFya2VyIGR1cmF0aW9uIG92ZXJsYXkpIHJlbmRlcnMgdGhlIGxhYmVsXG4gICAqIGFib3ZlIHRoZSBtYXJrZXJzIGluc3RlYWQsIHNvIHdlIGRvbid0IGRyYXcgaXQgdHdpY2UuXG4gICAqL1xuICBzaG93TGFiZWxzPzogYm9vbGVhbjtcbn0pOiBSZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwicmVsYXRpdmUgaC02IHctZnVsbFwiPlxuICAgICAge3NlZ21lbnRzLm1hcCgoc2VnLCBpKSA9PiB7XG4gICAgICAgIGlmIChzZWcuc3RhdHVzID09PSAncXVldWVkJykge1xuICAgICAgICAgIGNvbnN0IGxlYWRJbkxhYmVsID0gZm9ybWF0RHVyYXRpb25QcmVjaXNlKHNlZy5mdWxsRHVyYXRpb25Ncyk7XG4gICAgICAgICAgY29uc3Qgc2hvd0xlYWRJbkxhYmVsID1cbiAgICAgICAgICAgIHNob3dMYWJlbHMgJiZcbiAgICAgICAgICAgIHNlZy5waXhlbFdpZHRoID49IE1hdGgubWF4KDQwLCBsZWFkSW5MYWJlbC5sZW5ndGggKiA2ICsgMTIpO1xuICAgICAgICAgIGNvbnN0IGlzRnVsbFdpZHRoUXVldWVkID0gc2VnbWVudHMubGVuZ3RoID09PSAxO1xuICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8RnJhZ21lbnQga2V5PXtpfT5cbiAgICAgICAgICAgICAgPExlYWRJbkNvbm5lY3RvclxuICAgICAgICAgICAgICAgIGxlZnRQY3Q9e3NlZy5sZWZ0UGN0fVxuICAgICAgICAgICAgICAgIHdpZHRoUGN0PXtzZWcud2lkdGhQY3R9XG4gICAgICAgICAgICAgICAgbGFiZWw9e3Nob3dMZWFkSW5MYWJlbCA/IGxlYWRJbkxhYmVsIDogbnVsbH1cbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAge2lzRnVsbFdpZHRoUXVldWVkID8gKFxuICAgICAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cImFic29sdXRlIHRvcC0xLzIgaC00IHctcHggLXRyYW5zbGF0ZS15LTEvMiBiZy1ncmF5LTUwMFwiXG4gICAgICAgICAgICAgICAgICBzdHlsZT17e1xuICAgICAgICAgICAgICAgICAgICBsZWZ0OiBgY2FsYygke3NlZy5sZWZ0UGN0ICsgc2VnLndpZHRoUGN0fSUgLSAxLjVweClgLFxuICAgICAgICAgICAgICAgICAgfX1cbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICApIDogbnVsbH1cbiAgICAgICAgICAgIDwvRnJhZ21lbnQ+XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxhYmVsID0gZm9ybWF0RHVyYXRpb25QcmVjaXNlKHNlZy5mdWxsRHVyYXRpb25Ncyk7XG4gICAgICAgIC8vIE9ubHkgcmVuZGVyIHRoZSBsYWJlbCB3aGVuIHRoZXJlJ3MgZW5vdWdoIHJvb20gZm9yIGl0IHdpdGhvdXQgY2xpcHBpbmcuXG4gICAgICAgIGNvbnN0IHNob3dMYWJlbCA9XG4gICAgICAgICAgc2hvd0xhYmVscyAmJiBzZWcucGl4ZWxXaWR0aCA+PSBNYXRoLm1heCg0MCwgbGFiZWwubGVuZ3RoICogNiArIDEyKTtcblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgIGtleT17aX1cbiAgICAgICAgICAgIGNsYXNzTmFtZT17Y24oXG4gICAgICAgICAgICAgICdhYnNvbHV0ZSBoLWZ1bGwgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtWzAuMjVyZW1dJyxcbiAgICAgICAgICAgICAgU0VHTUVOVF9DTEFTU0VTW3NlZy5zdGF0dXNdXG4gICAgICAgICAgICApfVxuICAgICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgICAgLy8gMXB4IGdhcCBiZXR3ZWVuIGFkamFjZW50IHNlZ21lbnRzLCBkaXN0cmlidXRlZCBlcXVhbGx5LlxuICAgICAgICAgICAgICBsZWZ0OiBgY2FsYygke3NlZy5sZWZ0UGN0fSUgKyAwLjVweClgLFxuICAgICAgICAgICAgICB3aWR0aDogYGNhbGMoJHtzZWcud2lkdGhQY3R9JSAtIDFweClgLFxuICAgICAgICAgICAgICBtaW5XaWR0aDogMSxcbiAgICAgICAgICAgIH19XG4gICAgICAgICAgPlxuICAgICAgICAgICAge1NUUklQRURfU0VHTUVOVF9TVEFUVVNFUy5oYXMoc2VnLnN0YXR1cykgPyAoXG4gICAgICAgICAgICAgIDxBbmltYXRlZFN0cmlwZXMgc3RhdHVzPXtzZWcuc3RhdHVzfSAvPlxuICAgICAgICAgICAgKSA6IG51bGx9XG4gICAgICAgICAgICB7c2hvd0xhYmVsID8gPER1cmF0aW9uTGFiZWwgbGFiZWw9e2xhYmVsfSAvPiA6IG51bGx9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICk7XG4gICAgICB9KX1cbiAgICA8L2Rpdj5cbiAgKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUaW1lbGluZUJhclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmNvbnN0IFRpbWVsaW5lQmFyID0gbWVtbyhmdW5jdGlvbiBUaW1lbGluZUJhcih7XG4gIHNwYW4sXG4gIHZpZXdTdGFydCxcbiAgdmlld0R1cmF0aW9uLFxuICBjb250YWluZXJXaWR0aCxcbiAgaXNTZWxlY3RlZCxcbiAgaXNEaW1tZWQsXG4gIG9uU2VsZWN0LFxuICBvblJldmVhbFRpbWUsXG59OiB7XG4gIHNwYW46IFNwYW47XG4gIHZpZXdTdGFydDogbnVtYmVyO1xuICB2aWV3RHVyYXRpb246IG51bWJlcjtcbiAgY29udGFpbmVyV2lkdGg6IG51bWJlcjtcbiAgaXNTZWxlY3RlZDogYm9vbGVhbjtcbiAgaXNEaW1tZWQ/OiBib29sZWFuO1xuICBvblNlbGVjdDogKHNwYW5JZDogc3RyaW5nKSA9PiB2b2lkO1xuICBvblJldmVhbFRpbWU/OiAodGltZU1zOiBudW1iZXIpID0+IHZvaWQ7XG59KTogUmVhY3ROb2RlIHtcbiAgY29uc3Qgc3RhcnRNcyA9IGdldEhpZ2hSZXNJbk1zKHNwYW4uc3RhcnRUaW1lKTtcbiAgY29uc3QgZW5kTXMgPSBnZXRIaWdoUmVzSW5NcyhzcGFuLmVuZFRpbWUpO1xuICBjb25zdCB0b3RhbER1cmF0aW9uTXMgPSBnZXRTcGFuRHVyYXRpb25NcyhzcGFuKTtcblxuICBjb25zdCBnZW9tZXRyeSA9IHVzZU1lbW8oXG4gICAgKCkgPT5cbiAgICAgIGNvbXB1dGVCYXJHZW9tZXRyeShcbiAgICAgICAgc3RhcnRNcyxcbiAgICAgICAgZW5kTXMsXG4gICAgICAgIHZpZXdTdGFydCxcbiAgICAgICAgdmlld1N0YXJ0ICsgdmlld0R1cmF0aW9uLFxuICAgICAgICBjb250YWluZXJXaWR0aFxuICAgICAgKSxcbiAgICBbc3RhcnRNcywgZW5kTXMsIHZpZXdTdGFydCwgdmlld0R1cmF0aW9uLCBjb250YWluZXJXaWR0aF1cbiAgKTtcblxuICBjb25zdCBiYXNlU2VnbWVudHMgPSB1c2VNZW1vKCgpID0+IGNvbXB1dGVTcGFuU2VnbWVudHMoc3BhbiksIFtzcGFuXSk7XG4gIGNvbnN0IHNlZ21lbnRzID0gdXNlTWVtbyhcbiAgICAoKSA9PlxuICAgICAgZ2VvbWV0cnkubW9kZS5raW5kID09PSAnZnVsbCdcbiAgICAgICAgPyBwcm9qZWN0U2VnbWVudHMoYmFzZVNlZ21lbnRzLCBzdGFydE1zLCB0b3RhbER1cmF0aW9uTXMsIGdlb21ldHJ5KVxuICAgICAgICA6IFtdLFxuICAgIFtnZW9tZXRyeSwgYmFzZVNlZ21lbnRzLCBzdGFydE1zLCB0b3RhbER1cmF0aW9uTXNdXG4gICk7XG5cbiAgY29uc3QgYmFzZU1hcmtlcnMgPSB1c2VNZW1vKCgpID0+IGNvbXB1dGVTcGFuTWFya2VycyhzcGFuKSwgW3NwYW5dKTtcbiAgY29uc3QgbWFya2VycyA9IHVzZU1lbW8oXG4gICAgKCkgPT5cbiAgICAgIGdlb21ldHJ5Lm1vZGUua2luZCA9PT0gJ2Z1bGwnXG4gICAgICAgID8gY3VsbENvbGxpZGluZ01hcmtlcnMoXG4gICAgICAgICAgICBwcm9qZWN0TWFya2VycyhcbiAgICAgICAgICAgICAgYmFzZU1hcmtlcnMsXG4gICAgICAgICAgICAgIGdlb21ldHJ5LnZpc2libGVTdGFydE1zLFxuICAgICAgICAgICAgICBnZW9tZXRyeS52aXNpYmxlRW5kTXNcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBnZW9tZXRyeS52aXNpYmxlUGl4ZWxXaWR0aFxuICAgICAgICAgIClcbiAgICAgICAgOiBbXSxcbiAgICBbZ2VvbWV0cnksIGJhc2VNYXJrZXJzXVxuICApO1xuXG4gIC8vIE1hcmtlcnMgdGhhdCBmYWxsIG91dHNpZGUgdGhlIHZpc2libGUgd2luZG93IChzY3JvbGxlZCBvZmYgd2hpbGUgem9vbWVkIGluKVxuICAvLyDigJQgc3VyZmFjZWQgYXMgZWRnZSBpbmRpY2F0b3JzIHNvIHRoZXkgYXJlbid0IHNpbGVudGx5IGxvc3QuXG4gIGNvbnN0IG9mZnNjcmVlbiA9IHVzZU1lbW88T2Zmc2NyZWVuTWFya2Vycz4oXG4gICAgKCkgPT5cbiAgICAgIGdlb21ldHJ5Lm1vZGUua2luZCA9PT0gJ2Z1bGwnXG4gICAgICAgID8gY29tcHV0ZU9mZnNjcmVlbk1hcmtlcnMoXG4gICAgICAgICAgICBiYXNlTWFya2VycyxcbiAgICAgICAgICAgIGdlb21ldHJ5LnZpc2libGVTdGFydE1zLFxuICAgICAgICAgICAgZ2VvbWV0cnkudmlzaWJsZUVuZE1zXG4gICAgICAgICAgKVxuICAgICAgICA6IHsgbGVmdDogbnVsbCwgcmlnaHQ6IG51bGwgfSxcbiAgICBbZ2VvbWV0cnksIGJhc2VNYXJrZXJzXVxuICApO1xuXG4gIC8vIE1hcmtlcnMgKHZpc2libGUgb3Igb2ZmLXNjcmVlbikgbW92ZSB0aGUgZHVyYXRpb24gbGFiZWwgaW50byB0aGUgb3ZlcmxheSxcbiAgLy8gc28gdGhlIGluLWJhciBzZWdtZW50IGxhYmVsIGlzIHN1cHByZXNzZWQuXG4gIGNvbnN0IGhhc01hcmtlcnMgPVxuICAgIG1hcmtlcnMubGVuZ3RoID4gMCB8fCBvZmZzY3JlZW4ubGVmdCAhPT0gbnVsbCB8fCBvZmZzY3JlZW4ucmlnaHQgIT09IG51bGw7XG5cbiAgY29uc3QgaXNFcnJvcmVkID0gaXNTcGFuRXJyb3JlZChzcGFuKTtcbiAgY29uc3QgY29sb3JzID0gZ2V0UmVzb3VyY2VDb2xvcihzcGFuLnJlc291cmNlKTtcbiAgY29uc3QgZmFsbGJhY2tCZyA9IGlzRXJyb3JlZFxuICAgID8gKGNvbG9ycy5lcnJvckJnID8/ICd2YXIoLS1kcy1yZWQtMjAwKScpXG4gICAgOiBjb2xvcnMuYmc7XG4gIGNvbnN0IGZhbGxiYWNrQm9yZGVyID0gaXNFcnJvcmVkXG4gICAgPyAoY29sb3JzLmVycm9yQm9yZGVyID8/ICd2YXIoLS1kcy1yZWQtNTAwKScpXG4gICAgOiBjb2xvcnMuYm9yZGVyO1xuXG4gIGNvbnN0IHRvdGFsTGFiZWwgPSBmb3JtYXREdXJhdGlvblByZWNpc2UodG90YWxEdXJhdGlvbk1zKTtcbiAgY29uc3Qgc2hvd1RvdGFsTGFiZWwgPVxuICAgIGdlb21ldHJ5LnZpc2libGVQaXhlbFdpZHRoID49IE1hdGgubWF4KDQwLCB0b3RhbExhYmVsLmxlbmd0aCAqIDYgKyAxMik7XG5cbiAgY29uc3QgaGFuZGxlQ2xpY2sgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgb25TZWxlY3Qoc3Bhbi5zcGFuSWQpO1xuICB9LCBbb25TZWxlY3QsIHNwYW4uc3BhbklkXSk7XG5cbiAgcmV0dXJuIChcbiAgICA8ZGl2XG4gICAgICByb2xlPVwidHJlZWl0ZW1cIlxuICAgICAgYXJpYS1zZWxlY3RlZD17aXNTZWxlY3RlZH1cbiAgICAgIGFyaWEtZXhwYW5kZWQ9e2lzU2VsZWN0ZWR9XG4gICAgICBhcmlhLWxldmVsPXsxfVxuICAgICAgY2xhc3NOYW1lPXtjbihcbiAgICAgICAgJ2dyb3VwL3RpbWVsaW5lLXJvdyBoLTEwIHJlbGF0aXZlIGZsZXggaXRlbXMtY2VudGVyIGhvdmVyOmJnLWdyYXktMTAwIGFyaWEtc2VsZWN0ZWQ6YmctZ3JheS0xMDAgYXJpYS1zZWxlY3RlZDpob3ZlcjpiZy1ncmF5LTIwMCB0cmFuc2l0aW9uLW9wYWNpdHknLFxuICAgICAgICBpc0RpbW1lZCAmJiAnb3BhY2l0eS0zNSdcbiAgICAgICl9XG4gICAgICBvbkNsaWNrPXtoYW5kbGVDbGlja31cbiAgICA+XG4gICAgICA8ZGl2IGNsYXNzTmFtZT1cImFic29sdXRlIGluc2V0LXktMFwiIHN0eWxlPXtUSU1FTElORV9JTlNFVF9TVFlMRX0+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSB0b3AtMS8yIGgtNiAtdHJhbnNsYXRlLXktMS8yIG92ZXJmbG93LWhpZGRlbiByb3VuZGVkLVswLjI1cmVtXVwiXG4gICAgICAgICAgc3R5bGU9e2dldEJhclBvc2l0aW9uU3R5bGUoZ2VvbWV0cnkpfVxuICAgICAgICA+XG4gICAgICAgICAge2dlb21ldHJ5Lm1vZGUua2luZCA9PT0gJ2Fycm93JyA/IChcbiAgICAgICAgICAgIDxCb3VuZGFyeUFycm93IGRpcmVjdGlvbj17Z2VvbWV0cnkubW9kZS5kaXJlY3Rpb259IC8+XG4gICAgICAgICAgKSA6IGdlb21ldHJ5Lm1vZGUua2luZCA9PT0gJ3RpbnknID8gKFxuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBjbGFzc05hbWU9XCJoLTYgcm91bmRlZC1bMC4yNXJlbV0gYm9yZGVyXCJcbiAgICAgICAgICAgICAgc3R5bGU9e3sgYmFja2dyb3VuZDogZmFsbGJhY2tCZywgYm9yZGVyQ29sb3I6IGZhbGxiYWNrQm9yZGVyIH19XG4gICAgICAgICAgICAvPlxuICAgICAgICAgICkgOiBzZWdtZW50cy5sZW5ndGggPiAwID8gKFxuICAgICAgICAgICAgPFNlZ21lbnRCYXIgc2VnbWVudHM9e3NlZ21lbnRzfSBzaG93TGFiZWxzPXshaGFzTWFya2Vyc30gLz5cbiAgICAgICAgICApIDogKFxuICAgICAgICAgICAgPFBsYWluQmFyXG4gICAgICAgICAgICAgIGJnPXtmYWxsYmFja0JnfVxuICAgICAgICAgICAgICBib3JkZXI9e2ZhbGxiYWNrQm9yZGVyfVxuICAgICAgICAgICAgICBsYWJlbD17c2hvd1RvdGFsTGFiZWwgPyB0b3RhbExhYmVsIDogbnVsbH1cbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgKX1cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIHsvKiBPdmVybGF5IChub3QgY2xpcHBlZCk6IHRpY2tzLCBvZmYtc2NyZWVuIGluZGljYXRvcnMsIHRoZW4gdGhlIGR1cmF0aW9uIGxhYmVsIG9uIHRvcC4gKi99XG4gICAgICAgIHtoYXNNYXJrZXJzID8gKFxuICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgIGNsYXNzTmFtZT1cInBvaW50ZXItZXZlbnRzLW5vbmUgYWJzb2x1dGUgdG9wLTEvMiBoLTYgLXRyYW5zbGF0ZS15LTEvMlwiXG4gICAgICAgICAgICBzdHlsZT17Z2V0QmFyUG9zaXRpb25TdHlsZShnZW9tZXRyeSl9XG4gICAgICAgICAgPlxuICAgICAgICAgICAge21hcmtlcnMubGVuZ3RoID4gMCA/IDxNYXJrZXJMYXllciBtYXJrZXJzPXttYXJrZXJzfSAvPiA6IG51bGx9XG4gICAgICAgICAgICB7b2Zmc2NyZWVuLmxlZnQgPyAoXG4gICAgICAgICAgICAgIDxPZmZzY3JlZW5NYXJrZXJJbmRpY2F0b3JcbiAgICAgICAgICAgICAgICBkaXJlY3Rpb249XCJsZWZ0XCJcbiAgICAgICAgICAgICAgICBjb3VudD17b2Zmc2NyZWVuLmxlZnQuY291bnR9XG4gICAgICAgICAgICAgICAgdGFyZ2V0TXM9e29mZnNjcmVlbi5sZWZ0Lm5lYXJlc3RNc31cbiAgICAgICAgICAgICAgICBvblJldmVhbD17b25SZXZlYWxUaW1lfVxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgKSA6IG51bGx9XG4gICAgICAgICAgICB7b2Zmc2NyZWVuLnJpZ2h0ID8gKFxuICAgICAgICAgICAgICA8T2Zmc2NyZWVuTWFya2VySW5kaWNhdG9yXG4gICAgICAgICAgICAgICAgZGlyZWN0aW9uPVwicmlnaHRcIlxuICAgICAgICAgICAgICAgIGNvdW50PXtvZmZzY3JlZW4ucmlnaHQuY291bnR9XG4gICAgICAgICAgICAgICAgdGFyZ2V0TXM9e29mZnNjcmVlbi5yaWdodC5uZWFyZXN0TXN9XG4gICAgICAgICAgICAgICAgb25SZXZlYWw9e29uUmV2ZWFsVGltZX1cbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICkgOiBudWxsfVxuICAgICAgICAgICAge3Nob3dUb3RhbExhYmVsID8gKFxuICAgICAgICAgICAgICA8RHVyYXRpb25MYWJlbFxuICAgICAgICAgICAgICAgIGxhYmVsPXt0b3RhbExhYmVsfVxuICAgICAgICAgICAgICAgIC8vIFNoaWZ0IGNsZWFyIG9mIHRoZSBsZWZ0IGVkZ2UgaW5kaWNhdG9yIHNvIGl0IGlzbid0IGNvdmVyZWQuXG4gICAgICAgICAgICAgICAgY2xhc3NOYW1lPXtvZmZzY3JlZW4ubGVmdCA/ICdwbC0xMCcgOiB1bmRlZmluZWR9XG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICApIDogbnVsbH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKSA6IG51bGx9XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgKTtcbn0pO1xuXG5leHBvcnQgeyBUaW1lbGluZUJhciB9O1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERlbHRhSW5kaWNhdG9yIChBbHQta2V5IGdhcCBvdmVybGF5KVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmNvbnN0IERFTFRBX0NBUF9IRUlHSFRfUFggPSA4O1xuLy8gVmVydGljYWwgb2Zmc2V0IHRvIHNpdCB0aGUgaW5kaWNhdG9yIGluc2lkZSB0aGUgZ2FwIGJldHdlZW4gcm93IE4gYW5kIE4rMSxcbi8vIGFsaWduZWQgd2l0aCB3aGVyZSB0aGUgYmFyIHN0YXJ0cyBpbiB0aGUgbmV4dCByb3cgKHJvd3MgY2VudGVyIGEgMjRweCBiYXJcbi8vIGluc2lkZSA0MHB4LCBzbyBiYXJzIHN0YXJ0IH44cHggZnJvbSB0aGUgdG9wIG9mIHRoZSByb3cpLlxuY29uc3QgREVMVEFfUk9XX09GRlNFVF9QWCA9IDg7XG5cbmNvbnN0IERlbHRhSW5kaWNhdG9yID0gbWVtbyhmdW5jdGlvbiBEZWx0YUluZGljYXRvcih7XG4gIGxlZnRGcmFjLFxuICByaWdodEZyYWMsXG4gIGxhYmVsLFxuICByb3dJbmRleCxcbn06IHtcbiAgbGVmdEZyYWM6IG51bWJlcjtcbiAgcmlnaHRGcmFjOiBudW1iZXI7XG4gIGxhYmVsOiBzdHJpbmc7XG4gIHJvd0luZGV4OiBudW1iZXI7XG59KSB7XG4gIGNvbnN0IGNlbnRlclkgPSBERUxUQV9ST1dfT0ZGU0VUX1BYICsgKHJvd0luZGV4ICsgMSkgKiBST1dfSEVJR0hUX1BYO1xuXG4gIHJldHVybiAoXG4gICAgPGRpdlxuICAgICAgY2xhc3NOYW1lPVwiYWJzb2x1dGUgcG9pbnRlci1ldmVudHMtbm9uZVwiXG4gICAgICBzdHlsZT17e1xuICAgICAgICBsZWZ0OiBgJHtsZWZ0RnJhYyAqIDEwMH0lYCxcbiAgICAgICAgd2lkdGg6IGAkeyhyaWdodEZyYWMgLSBsZWZ0RnJhYykgKiAxMDB9JWAsXG4gICAgICAgIHRvcDogY2VudGVyWSAtIERFTFRBX0NBUF9IRUlHSFRfUFggLyAyLFxuICAgICAgICBoZWlnaHQ6IERFTFRBX0NBUF9IRUlHSFRfUFgsXG4gICAgICB9fVxuICAgID5cbiAgICAgIDxkaXYgY2xhc3NOYW1lPVwiYWJzb2x1dGUgbGVmdC0wIHRvcC0wIHctcHggaC1mdWxsIGJnLWFtYmVyLTgwMFwiIC8+XG4gICAgICA8ZGl2IGNsYXNzTmFtZT1cImFic29sdXRlIGxlZnQtMCByaWdodC0wIHRvcC0xLzIgaC1weCBiZy1hbWJlci04MDBcIiAvPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJhYnNvbHV0ZSByaWdodC0wIHRvcC0wIHctcHggaC1mdWxsIGJnLWFtYmVyLTgwMFwiIC8+XG4gICAgICA8c3BhbiBjbGFzc05hbWU9XCJhYnNvbHV0ZSBsZWZ0LTEvMiB0b3AtMS8yIC10cmFuc2xhdGUteC0xLzIgLXRyYW5zbGF0ZS15LTEvMiB0ZXh0LWxhYmVsLTEyIGxlYWRpbmctbm9uZSB3aGl0ZXNwYWNlLW5vd3JhcCByb3VuZGVkLXhzIHB4LTEgcHktMC41IHRleHQtZ3JheS0xMDAgYmctYW1iZXItODAwXCI+XG4gICAgICAgIHtsYWJlbH1cbiAgICAgIDwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgKTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFRpbWVsaW5lSGVhZGVyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZXhwb3J0IGZ1bmN0aW9uIFRpbWVsaW5lSGVhZGVyKHtcbiAgbWFya2VycyxcbiAgaG92ZXJJbmZvLFxufToge1xuICBtYXJrZXJzOiBUaW1lTWFya2VyW107XG4gIGhvdmVySW5mbz86IHsgZnJhY3Rpb246IG51bWJlcjsgbGFiZWw6IHN0cmluZyB9IHwgbnVsbDtcbn0pOiBSZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwicmVsYXRpdmUgYmctYmFja2dyb3VuZC0xMDAgYm9yZGVyLWIgYm9yZGVyLWdyYXktYWxwaGEtNDAwIGgtMTAgbWluLWgtMTAgZmxleCBpdGVtcy1lbmQgcHgtNCBwYi0xXCI+XG4gICAgICA8ZGl2IGNsYXNzTmFtZT1cInJlbGF0aXZlIGgtZnVsbCBmbGV4LTFcIj5cbiAgICAgICAge21hcmtlcnMubWFwKChtKSA9PiAoXG4gICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgIGtleT17U3RyaW5nKG0udmFsdWUpfVxuICAgICAgICAgICAgY2xhc3NOYW1lPVwiYWJzb2x1dGUgYm90dG9tLTEgZm9udC1tb25vIHRleHQteHMgZm9udC1ub3JtYWwgbGVhZGluZy00IHRleHQtZ3JheS05MDAgd2hpdGVzcGFjZS1ub3dyYXBcIlxuICAgICAgICAgICAgc3R5bGU9e3sgbGVmdDogYCR7bS5wb3NpdGlvbiAqIDEwMH0lYCB9fVxuICAgICAgICAgID5cbiAgICAgICAgICAgIHttLmxhYmVsfVxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgKSl9XG4gICAgICAgIHtob3ZlckluZm8gJiYgKFxuICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSB0b3AtMSBwb2ludGVyLWV2ZW50cy1ub25lIHotMTAgZm9udC1tb25vIHRleHQtWzExcHhdIGxlYWRpbmctNCB0ZXh0LWdyYXktMTAwMCB3aGl0ZXNwYWNlLW5vd3JhcCBiZy1iYWNrZ3JvdW5kLTEwMCBib3JkZXIgYm9yZGVyLWdyYXktYWxwaGEtNDAwIHJvdW5kZWQgcHgtMSAtdHJhbnNsYXRlLXgtMS8yXCJcbiAgICAgICAgICAgIHN0eWxlPXt7IGxlZnQ6IGAke2hvdmVySW5mby5mcmFjdGlvbiAqIDEwMH0lYCB9fVxuICAgICAgICAgID5cbiAgICAgICAgICAgIHtob3ZlckluZm8ubGFiZWx9XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICApfVxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gICk7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gVGltZWxpbmVcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5leHBvcnQgZnVuY3Rpb24gVGltZWxpbmUoe1xuICBzcGFucyxcbiAgdmlld1N0YXJ0LFxuICB2aWV3RW5kLFxuICBtYXJrZXJzLFxuICBzZWxlY3RlZElkLFxuICBzZWFyY2hSZXN1bHQsXG4gIG9uU2VsZWN0LFxuICBvblJldmVhbFRpbWUsXG4gIGhvdmVyRnJhY3Rpb24sXG4gIGFsdEhlbGQgPSBmYWxzZSxcbn06IHtcbiAgc3BhbnM6IFNwYW5bXTtcbiAgdmlld1N0YXJ0OiBudW1iZXI7XG4gIHZpZXdFbmQ6IG51bWJlcjtcbiAgbWFya2VyczogVGltZU1hcmtlcltdO1xuICBzZWxlY3RlZElkOiBzdHJpbmcgfCBudWxsO1xuICBzZWFyY2hSZXN1bHQ6IFNwYW5TZWFyY2hSZXN1bHQ7XG4gIG9uU2VsZWN0OiAoc3BhbklkOiBzdHJpbmcpID0+IHZvaWQ7XG4gIG9uUmV2ZWFsVGltZT86ICh0aW1lTXM6IG51bWJlcikgPT4gdm9pZDtcbiAgaG92ZXJGcmFjdGlvbj86IG51bWJlciB8IG51bGw7XG4gIGFsdEhlbGQ/OiBib29sZWFuO1xufSk6IFJlYWN0Tm9kZSB7XG4gIGNvbnN0IGNvbnRhaW5lclJlZiA9IHVzZVJlZjxIVE1MRGl2RWxlbWVudD4obnVsbCk7XG4gIGNvbnN0IFtjb250YWluZXJXaWR0aCwgc2V0Q29udGFpbmVyV2lkdGhdID0gdXNlU3RhdGUoMCk7XG4gIGNvbnN0IHZpZXdEdXJhdGlvbiA9IHZpZXdFbmQgLSB2aWV3U3RhcnQ7XG4gIGNvbnN0IHRpbWVsaW5lV2lkdGggPSBNYXRoLm1heCgwLCBjb250YWluZXJXaWR0aCAtIFRJTUVMSU5FX1BBRERJTkdfUFggKiAyKTtcbiAgY29uc3QgeyBzdGFydCwgZW5kIH0gPSB1c2VSb3dXaW5kb3coXG4gICAgY29udGFpbmVyUmVmLFxuICAgIHNwYW5zLmxlbmd0aCxcbiAgICBST1dfSEVJR0hUX1BYXG4gICk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBjb25zdCBlbCA9IGNvbnRhaW5lclJlZi5jdXJyZW50O1xuICAgIGlmICghZWwpIHJldHVybjtcbiAgICBjb25zdCBybyA9IG5ldyBSZXNpemVPYnNlcnZlcigoW2VudHJ5XSkgPT4ge1xuICAgICAgc2V0Q29udGFpbmVyV2lkdGgoZW50cnkuY29udGVudFJlY3Qud2lkdGgpO1xuICAgIH0pO1xuICAgIHJvLm9ic2VydmUoZWwpO1xuICAgIHJldHVybiAoKSA9PiByby5kaXNjb25uZWN0KCk7XG4gIH0sIFtdKTtcblxuICBjb25zdCBnYXBzID0gdXNlTWVtbyhcbiAgICAoKSA9PiBjb21wdXRlU3BhbkdhcHMoc3BhbnMsIHZpZXdTdGFydCwgdmlld0VuZCksXG4gICAgW3NwYW5zLCB2aWV3U3RhcnQsIHZpZXdFbmRdXG4gICk7XG5cbiAgcmV0dXJuIChcbiAgICA8ZGl2XG4gICAgICByZWY9e2NvbnRhaW5lclJlZn1cbiAgICAgIGNsYXNzTmFtZT1cInJlbGF0aXZlIGgtZnVsbCBvdmVyZmxvdy1oaWRkZW5cIlxuICAgICAgc3R5bGU9e3sgbWluSGVpZ2h0OiBzcGFucy5sZW5ndGggKiBST1dfSEVJR0hUX1BYIH19XG4gICAgPlxuICAgICAgPGRpdlxuICAgICAgICBhcmlhLWhpZGRlblxuICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSBpbnNldC15LTAgcG9pbnRlci1ldmVudHMtbm9uZVwiXG4gICAgICAgIHN0eWxlPXtUSU1FTElORV9JTlNFVF9TVFlMRX1cbiAgICAgID5cbiAgICAgICAge21hcmtlcnMubWFwKChtYXJrZXIpID0+XG4gICAgICAgICAgLy8gU2tpcCB0aGUgXCIwc1wiIG9yaWdpbiBtYXJrZXIgc2luY2UgdGhlIGxlZnQgZWRnZSBhbHJlYWR5IGltcGxpZXMgaXQuXG4gICAgICAgICAgTWF0aC5hYnMobWFya2VyLnZhbHVlKSA+IDAuMDAwMDAxID8gKFxuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBrZXk9e1N0cmluZyhtYXJrZXIudmFsdWUpfVxuICAgICAgICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSB0b3AtMCBib3R0b20tMCB3LXB4IGJnLWdyYXktYWxwaGEtMzAwXCJcbiAgICAgICAgICAgICAgc3R5bGU9e3sgbGVmdDogYCR7bWFya2VyLnBvc2l0aW9uICogMTAwfSVgIH19XG4gICAgICAgICAgICAvPlxuICAgICAgICAgICkgOiBudWxsXG4gICAgICAgICl9XG4gICAgICA8L2Rpdj5cbiAgICAgIHtob3ZlckZyYWN0aW9uICE9IG51bGwgJiYgKFxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3NOYW1lPVwiYWJzb2x1dGUgaW5zZXQteS0wIHBvaW50ZXItZXZlbnRzLW5vbmUgei0xMFwiXG4gICAgICAgICAgc3R5bGU9e1RJTUVMSU5FX0lOU0VUX1NUWUxFfVxuICAgICAgICA+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3NOYW1lPVwiYWJzb2x1dGUgdG9wLTAgYm90dG9tLTAgdy1weCBiZy1ncmF5LWFscGhhLTUwMFwiXG4gICAgICAgICAgICBzdHlsZT17eyBsZWZ0OiBgJHtob3ZlckZyYWN0aW9uICogMTAwfSVgIH19XG4gICAgICAgICAgLz5cbiAgICAgICAgPC9kaXY+XG4gICAgICApfVxuICAgICAgPGRpdiBzdHlsZT17eyB0cmFuc2Zvcm06IGB0cmFuc2xhdGVZKCR7c3RhcnQgKiBST1dfSEVJR0hUX1BYfXB4KWAgfX0+XG4gICAgICAgIHtzcGFucy5zbGljZShzdGFydCwgZW5kKS5tYXAoKHNwYW4pID0+IChcbiAgICAgICAgICA8VGltZWxpbmVCYXJcbiAgICAgICAgICAgIGtleT17c3Bhbi5zcGFuSWR9XG4gICAgICAgICAgICBzcGFuPXtzcGFufVxuICAgICAgICAgICAgdmlld1N0YXJ0PXt2aWV3U3RhcnR9XG4gICAgICAgICAgICB2aWV3RHVyYXRpb249e3ZpZXdEdXJhdGlvbn1cbiAgICAgICAgICAgIGNvbnRhaW5lcldpZHRoPXt0aW1lbGluZVdpZHRofVxuICAgICAgICAgICAgaXNTZWxlY3RlZD17c2VsZWN0ZWRJZCA9PT0gc3Bhbi5zcGFuSWR9XG4gICAgICAgICAgICBpc0RpbW1lZD17aXNTcGFuRGltbWVkQnlTZWFyY2goc3Bhbi5zcGFuSWQsIHNlYXJjaFJlc3VsdCl9XG4gICAgICAgICAgICBvblNlbGVjdD17b25TZWxlY3R9XG4gICAgICAgICAgICBvblJldmVhbFRpbWU9e29uUmV2ZWFsVGltZX1cbiAgICAgICAgICAvPlxuICAgICAgICApKX1cbiAgICAgIDwvZGl2PlxuICAgICAge2FsdEhlbGQgJiYgKFxuICAgICAgICA8ZGl2XG4gICAgICAgICAgYXJpYS1oaWRkZW5cbiAgICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSBpbnNldC15LTAgcG9pbnRlci1ldmVudHMtbm9uZVwiXG4gICAgICAgICAgc3R5bGU9e1RJTUVMSU5FX0lOU0VUX1NUWUxFfVxuICAgICAgICA+XG4gICAgICAgICAge2dhcHMubWFwKChnYXApID0+IChcbiAgICAgICAgICAgIDxEZWx0YUluZGljYXRvclxuICAgICAgICAgICAgICBrZXk9e2dhcC5yb3dJbmRleH1cbiAgICAgICAgICAgICAgbGVmdEZyYWM9e2dhcC5sZWZ0RnJhY31cbiAgICAgICAgICAgICAgcmlnaHRGcmFjPXtnYXAucmlnaHRGcmFjfVxuICAgICAgICAgICAgICBsYWJlbD17Zm9ybWF0RHVyYXRpb25QcmVjaXNlKGdhcC5nYXBNcyl9XG4gICAgICAgICAgICAgIHJvd0luZGV4PXtnYXAucm93SW5kZXh9XG4gICAgICAgICAgICAvPlxuICAgICAgICAgICkpfVxuICAgICAgICA8L2Rpdj5cbiAgICAgICl9XG4gICAgPC9kaXY+XG4gICk7XG59XG4iXX0=
@@ -0,0 +1,46 @@
1
+ .runningStripes,
2
+ .pendingStripes {
3
+ position: absolute;
4
+ inset: 0;
5
+ pointer-events: none;
6
+ border-radius: 0.25rem;
7
+ opacity: 0.5;
8
+ background-size: 11.314px 11.314px;
9
+ animation: running-stripes 0.6s linear infinite;
10
+ }
11
+
12
+ .runningStripes {
13
+ background-image: repeating-linear-gradient(
14
+ 45deg,
15
+ var(--ds-blue-500) 0,
16
+ var(--ds-blue-500) 1.5px,
17
+ transparent 1.5px,
18
+ transparent 8px
19
+ );
20
+ }
21
+
22
+ .pendingStripes {
23
+ background-image: repeating-linear-gradient(
24
+ 45deg,
25
+ var(--ds-gray-500) 0,
26
+ var(--ds-gray-500) 1.5px,
27
+ transparent 1.5px,
28
+ transparent 8px
29
+ );
30
+ }
31
+
32
+ @keyframes running-stripes {
33
+ from {
34
+ background-position: 0 0;
35
+ }
36
+ to {
37
+ background-position: 11.314px 0;
38
+ }
39
+ }
40
+
41
+ @media (prefers-reduced-motion: reduce) {
42
+ .runningStripes,
43
+ .pendingStripes {
44
+ animation: none;
45
+ }
46
+ }
@@ -0,0 +1,5 @@
1
+ export declare function TraceShortcutHelper({ hasMultipleSpans, reducedMotion, }: {
2
+ hasMultipleSpans: boolean;
3
+ reducedMotion: boolean;
4
+ }): import("react/jsx-runtime").JSX.Element | null;
5
+ //# sourceMappingURL=trace-shortcut-helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-shortcut-helper.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/trace-shortcut-helper.tsx"],"names":[],"mappings":"AAwDA,wBAAgB,mBAAmB,CAAC,EAClC,gBAAgB,EAChB,aAAa,GACd,EAAE;IACD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;CACxB,kDAqDA"}
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { X } from 'lucide-react';
4
+ import { useEffect, useState } from 'react';
5
+ import { Kbd } from '../../ui/kbd';
6
+ import styles from './trace-shortcut-helper.module.css';
7
+ const DISMISSALS_KEY = 'workflow-step-shortcut-helper-dismissals';
8
+ const DISMISSAL_LIMIT = 3;
9
+ const HINT_ROTATION_MS = 8000;
10
+ function getAltKeyLabel() {
11
+ if (typeof navigator === 'undefined')
12
+ return 'Alt';
13
+ return navigator.platform.toLowerCase().includes('mac') ? 'Option' : 'Alt';
14
+ }
15
+ function readDismissals() {
16
+ try {
17
+ const dismissals = Number.parseInt(window.localStorage.getItem(DISMISSALS_KEY) ?? '0', 10);
18
+ return Number.isNaN(dismissals) ? 0 : dismissals;
19
+ }
20
+ catch {
21
+ return 0;
22
+ }
23
+ }
24
+ function AltHint() {
25
+ return (_jsxs(_Fragment, { children: ["Hold", _jsx(Kbd, { variant: "outline", size: "compact", className: "mx-1", children: getAltKeyLabel() }), "to see delta between spans"] }));
26
+ }
27
+ function NavHint() {
28
+ return (_jsxs(_Fragment, { children: ["Use", _jsx(Kbd, { variant: "outline", size: "compact", className: "ml-1", children: "J" }), _jsx("span", { className: "mx-1", children: "/" }), _jsx(Kbd, { variant: "outline", size: "compact", className: "mr-1", children: "K" }), "to move between spans"] }));
29
+ }
30
+ export function TraceShortcutHelper({ hasMultipleSpans, reducedMotion, }) {
31
+ const [visible, setVisible] = useState(false);
32
+ const [index, setIndex] = useState(0);
33
+ useEffect(() => {
34
+ setVisible(readDismissals() < DISMISSAL_LIMIT);
35
+ }, []);
36
+ useEffect(() => {
37
+ if (reducedMotion)
38
+ return;
39
+ const id = setInterval(() => {
40
+ setIndex((i) => (i === 0 ? 1 : 0));
41
+ }, HINT_ROTATION_MS);
42
+ return () => clearInterval(id);
43
+ }, [reducedMotion]);
44
+ if (!visible || !hasMultipleSpans)
45
+ return null;
46
+ const dismiss = () => {
47
+ try {
48
+ window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
49
+ }
50
+ catch { }
51
+ setVisible(false);
52
+ };
53
+ return (_jsxs("div", { className: "group sticky bottom-3 z-10 ml-4 mb-3 hidden h-8 w-fit items-center gap-1 text-xs leading-none text-gray-900 @min-[480px]:flex", children: [_jsx("span", { "aria-live": "polite", "aria-atomic": "true", className: "inline-flex items-center whitespace-nowrap", children: reducedMotion ? (_jsx(AltHint, {})) : (_jsx("span", { className: `inline-flex items-center ${styles.hint}`, children: index === 0 ? _jsx(AltHint, {}) : _jsx(NavHint, {}) }, index)) }), _jsx("button", { type: "button", className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none", onClick: dismiss, "aria-label": "Dismiss trace shortcuts helper", children: _jsx(X, { className: "h-3 w-3" }) })] }));
54
+ }
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2Utc2hvcnRjdXQtaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvbmV3LXRyYWNlLXZpZXdlci9jb21wb25lbnRzL3RyYWNlLXNob3J0Y3V0LWhlbHBlci50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOztBQUViLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDakMsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxPQUFPLENBQUM7QUFDNUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNuQyxPQUFPLE1BQU0sTUFBTSxvQ0FBb0MsQ0FBQztBQUV4RCxNQUFNLGNBQWMsR0FBRywwQ0FBMEMsQ0FBQztBQUNsRSxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7QUFDMUIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7QUFFOUIsU0FBUyxjQUFjO0lBQ3JCLElBQUksT0FBTyxTQUFTLEtBQUssV0FBVztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ25ELE9BQU8sU0FBUyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0FBQzdFLENBQUM7QUFFRCxTQUFTLGNBQWM7SUFDckIsSUFBSSxDQUFDO1FBQ0gsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FDaEMsTUFBTSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksR0FBRyxFQUNsRCxFQUFFLENBQ0gsQ0FBQztRQUNGLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDbkQsQ0FBQztJQUFDLE1BQU0sQ0FB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Q0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIid1c2UgY2xpZW50JztcblxuaW1wb3J0IHsgWCB9IGZyb20gJ2x1Y2lkZS1yZWFjdCc7XG5pbXBvcnQgeyB1c2VFZmZlY3QsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgS2JkIH0gZnJvbSAnLi4vLi4vdWkva2JkJztcbmltcG9ydCBzdHlsZXMgZnJvbSAnLi90cmFjZS1zaG9ydGN1dC1oZWxwZXIubW9kdWxlLmNzcyc7XG5cbmNvbnN0IERJU01JU1NBTFNfS0VZID0gJ3dvcmtmbG93LXN0ZXAtc2hvcnRjdXQtaGVscGVyLWRpc21pc3NhbHMnO1xuY29uc3QgRElTTUlTU0FMX0xJTUlUID0gMztcbmNvbnN0IEhJTlRfUk9UQVRJT05fTVMgPSA4MDAwO1xuXG5mdW5jdGlvbiBnZXRBbHRLZXlMYWJlbCgpOiAnQWx0JyB8ICdPcHRpb24nIHtcbiAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gJ0FsdCc7XG4gIHJldHVybiBuYXZpZ2F0b3IucGxhdGZvcm0udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnbWFjJykgPyAnT3B0aW9uJyA6ICdBbHQnO1xufVxuXG5mdW5jdGlvbiByZWFkRGlzbWlzc2FscygpOiBudW1iZXIge1xuICB0cnkge1xuICAgIGNvbnN0IGRpc21pc3NhbHMgPSBOdW1iZXIucGFyc2VJbnQoXG4gICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oRElTTUlTU0FMU19LRVkpID8/ICcwJyxcbiAgICAgIDEwXG4gICAgKTtcbiAgICByZXR1cm4gTnVtYmVyLmlzTmFOKGRpc21pc3NhbHMpID8gMCA6IGRpc21pc3NhbHM7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiAwO1xuICB9XG59XG5cbmZ1bmN0aW9uIEFsdEhpbnQoKSB7XG4gIHJldHVybiAoXG4gICAgPD5cbiAgICAgIEhvbGRcbiAgICAgIDxLYmQgdmFyaWFudD1cIm91dGxpbmVcIiBzaXplPVwiY29tcGFjdFwiIGNsYXNzTmFtZT1cIm14LTFcIj5cbiAgICAgICAge2dldEFsdEtleUxhYmVsKCl9XG4gICAgICA8L0tiZD5cbiAgICAgIHRvIHNlZSBkZWx0YSBiZXR3ZWVuIHNwYW5zXG4gICAgPC8+XG4gICk7XG59XG5cbmZ1bmN0aW9uIE5hdkhpbnQoKSB7XG4gIHJldHVybiAoXG4gICAgPD5cbiAgICAgIFVzZVxuICAgICAgPEtiZCB2YXJpYW50PVwib3V0bGluZVwiIHNpemU9XCJjb21wYWN0XCIgY2xhc3NOYW1lPVwibWwtMVwiPlxuICAgICAgICBKXG4gICAgICA8L0tiZD5cbiAgICAgIDxzcGFuIGNsYXNzTmFtZT1cIm14LTFcIj4vPC9zcGFuPlxuICAgICAgPEtiZCB2YXJpYW50PVwib3V0bGluZVwiIHNpemU9XCJjb21wYWN0XCIgY2xhc3NOYW1lPVwibXItMVwiPlxuICAgICAgICBLXG4gICAgICA8L0tiZD5cbiAgICAgIHRvIG1vdmUgYmV0d2VlbiBzcGFuc1xuICAgIDwvPlxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gVHJhY2VTaG9ydGN1dEhlbHBlcih7XG4gIGhhc011bHRpcGxlU3BhbnMsXG4gIHJlZHVjZWRNb3Rpb24sXG59OiB7XG4gIGhhc011bHRpcGxlU3BhbnM6IGJvb2xlYW47XG4gIHJlZHVjZWRNb3Rpb246IGJvb2xlYW47XG59KSB7XG4gIGNvbnN0IFt2aXNpYmxlLCBzZXRWaXNpYmxlXSA9IHVzZVN0YXRlKGZhbHNlKTtcbiAgY29uc3QgW2luZGV4LCBzZXRJbmRleF0gPSB1c2VTdGF0ZSgwKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIHNldFZpc2libGUocmVhZERpc21pc3NhbHMoKSA8IERJU01JU1NBTF9MSU1JVCk7XG4gIH0sIFtdKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGlmIChyZWR1Y2VkTW90aW9uKSByZXR1cm47XG4gICAgY29uc3QgaWQgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICBzZXRJbmRleCgoaSkgPT4gKGkgPT09IDAgPyAxIDogMCkpO1xuICAgIH0sIEhJTlRfUk9UQVRJT05fTVMpO1xuICAgIHJldHVybiAoKSA9PiBjbGVhckludGVydmFsKGlkKTtcbiAgfSwgW3JlZHVjZWRNb3Rpb25dKTtcblxuICBpZiAoIXZpc2libGUgfHwgIWhhc011bHRpcGxlU3BhbnMpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IGRpc21pc3MgPSAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShESVNNSVNTQUxTX0tFWSwgU3RyaW5nKHJlYWREaXNtaXNzYWxzKCkgKyAxKSk7XG4gICAgfSBjYXRjaCB7fVxuICAgIHNldFZpc2libGUoZmFsc2UpO1xuICB9O1xuXG4gIHJldHVybiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJncm91cCBzdGlja3kgYm90dG9tLTMgei0xMCBtbC00IG1iLTMgaGlkZGVuIGgtOCB3LWZpdCBpdGVtcy1jZW50ZXIgZ2FwLTEgdGV4dC14cyBsZWFkaW5nLW5vbmUgdGV4dC1ncmF5LTkwMCBAbWluLVs0ODBweF06ZmxleFwiPlxuICAgICAgPHNwYW5cbiAgICAgICAgYXJpYS1saXZlPVwicG9saXRlXCJcbiAgICAgICAgYXJpYS1hdG9taWM9XCJ0cnVlXCJcbiAgICAgICAgY2xhc3NOYW1lPVwiaW5saW5lLWZsZXggaXRlbXMtY2VudGVyIHdoaXRlc3BhY2Utbm93cmFwXCJcbiAgICAgID5cbiAgICAgICAge3JlZHVjZWRNb3Rpb24gPyAoXG4gICAgICAgICAgPEFsdEhpbnQgLz5cbiAgICAgICAgKSA6IChcbiAgICAgICAgICA8c3BhblxuICAgICAgICAgICAga2V5PXtpbmRleH1cbiAgICAgICAgICAgIGNsYXNzTmFtZT17YGlubGluZS1mbGV4IGl0ZW1zLWNlbnRlciAke3N0eWxlcy5oaW50fWB9XG4gICAgICAgICAgPlxuICAgICAgICAgICAge2luZGV4ID09PSAwID8gPEFsdEhpbnQgLz4gOiA8TmF2SGludCAvPn1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICl9XG4gICAgICA8L3NwYW4+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzc05hbWU9XCJpbmxpbmUtZmxleCBoLTUgdy01IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkIHRleHQtbXV0ZWQtZm9yZWdyb3VuZCBvcGFjaXR5LTAgdHJhbnNpdGlvbi1vcGFjaXR5IGhvdmVyOmJnLWFjY2VudCBob3Zlcjp0ZXh0LWZvcmVncm91bmQgZ3JvdXAtaG92ZXI6b3BhY2l0eS0xMDAgZm9jdXMtdmlzaWJsZTpvcGFjaXR5LTEwMCBtb3Rpb24tcmVkdWNlOnRyYW5zaXRpb24tbm9uZVwiXG4gICAgICAgIG9uQ2xpY2s9e2Rpc21pc3N9XG4gICAgICAgIGFyaWEtbGFiZWw9XCJEaXNtaXNzIHRyYWNlIHNob3J0Y3V0cyBoZWxwZXJcIlxuICAgICAgPlxuICAgICAgICA8WCBjbGFzc05hbWU9XCJoLTMgdy0zXCIgLz5cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICApO1xufVxuIl19