@jax-data-science/sci-image-visualizer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +404 -0
  3. package/esm2022/index.mjs +52 -0
  4. package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
  5. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
  6. package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
  7. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
  8. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
  9. package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
  10. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
  11. package/esm2022/lib/contracts/display-types.mjs +8 -0
  12. package/esm2022/lib/contracts/image.contract.mjs +11 -0
  13. package/esm2022/lib/contracts/intensity.mjs +28 -0
  14. package/esm2022/lib/contracts/plot-type.mjs +112 -0
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
  18. package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
  19. package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
  20. package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
  21. package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
  22. package/esm2022/lib/contracts/sam.contract.mjs +12 -0
  23. package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
  24. package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
  25. package/esm2022/lib/contracts/viz-config.mjs +3 -0
  26. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
  27. package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
  28. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
  29. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
  30. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
  31. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
  32. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
  33. package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
  34. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
  35. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
  36. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
  37. package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
  38. package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
  39. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
  40. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
  41. package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
  42. package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
  43. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
  44. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
  45. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
  46. package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
  47. package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
  48. package/esm2022/lib/models/bezier.mjs +120 -0
  49. package/esm2022/lib/models/class-preset.mjs +46 -0
  50. package/esm2022/lib/models/geometry.mjs +198 -0
  51. package/esm2022/lib/models/region.mjs +166 -0
  52. package/esm2022/lib/models/shape.mjs +53 -0
  53. package/esm2022/lib/plot.utilities.mjs +693 -0
  54. package/esm2022/lib/processing/image-converter.service.mjs +90 -0
  55. package/esm2022/lib/processing/image-crop.mjs +62 -0
  56. package/esm2022/lib/processing/processing-image.mjs +50 -0
  57. package/esm2022/lib/provide-visualization.mjs +63 -0
  58. package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
  59. package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
  60. package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
  61. package/esm2022/lib/region-ops.service.mjs +301 -0
  62. package/esm2022/lib/render-orchestrator.mjs +87 -0
  63. package/esm2022/lib/routing-visualizer.service.mjs +533 -0
  64. package/esm2022/lib/store/class-color.util.mjs +52 -0
  65. package/esm2022/lib/store/region-store.service.mjs +1029 -0
  66. package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
  67. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
  68. package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
  69. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
  70. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
  71. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
  72. package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
  73. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
  74. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
  75. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
  76. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
  77. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
  78. package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
  79. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
  80. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
  81. package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
  82. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
  83. package/esm2022/lib/visualization.module.mjs +162 -0
  84. package/esm2022/lib/visualizer.component.mjs +1597 -0
  85. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
  86. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
  87. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
  88. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
  89. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
  90. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
  91. package/fesm2022/mask.worker.js +989 -0
  92. package/fesm2022/onnx-sam.worker.js +202 -0
  93. package/index.d.ts +39 -0
  94. package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
  95. package/lib/contracts/capabilities.contract.d.ts +30 -0
  96. package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
  97. package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
  98. package/lib/contracts/colormap-lut.d.ts +21 -0
  99. package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
  100. package/lib/contracts/display-types.d.ts +41 -0
  101. package/lib/contracts/image.contract.d.ts +72 -0
  102. package/lib/contracts/intensity.d.ts +18 -0
  103. package/lib/contracts/plot-type.d.ts +108 -0
  104. package/lib/contracts/ports/image-state.port.d.ts +29 -0
  105. package/lib/contracts/ports/preferences.port.d.ts +19 -0
  106. package/lib/contracts/ports/region-io.port.d.ts +29 -0
  107. package/lib/contracts/ports/tile-access.port.d.ts +27 -0
  108. package/lib/contracts/region-editor-api.contract.d.ts +83 -0
  109. package/lib/contracts/region-overlay.contract.d.ts +47 -0
  110. package/lib/contracts/region-store.contract.d.ts +74 -0
  111. package/lib/contracts/sam.contract.d.ts +98 -0
  112. package/lib/contracts/toolbar-config.d.ts +24 -0
  113. package/lib/contracts/visualizer.contract.d.ts +346 -0
  114. package/lib/contracts/viz-config.d.ts +25 -0
  115. package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
  116. package/lib/implementations/base-store-visualizer.d.ts +71 -0
  117. package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
  118. package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
  119. package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
  120. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
  121. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
  122. package/lib/implementations/osd/display-pipeline.d.ts +47 -0
  123. package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
  124. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
  125. package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
  126. package/lib/implementations/osd/osd-coords.d.ts +16 -0
  127. package/lib/implementations/osd/osd-lib.d.ts +19 -0
  128. package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
  129. package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
  130. package/lib/implementations/osd/slice-cache.d.ts +161 -0
  131. package/lib/implementations/osd/tile-client.d.ts +32 -0
  132. package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
  133. package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
  134. package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
  135. package/lib/implementations/plotly/plotly.service.d.ts +594 -0
  136. package/lib/implementations/simple-slice-access.service.d.ts +64 -0
  137. package/lib/models/bezier.d.ts +59 -0
  138. package/lib/models/class-preset.d.ts +39 -0
  139. package/lib/models/geometry.d.ts +66 -0
  140. package/lib/models/region.d.ts +132 -0
  141. package/lib/models/shape.d.ts +44 -0
  142. package/lib/plot.utilities.d.ts +107 -0
  143. package/lib/processing/image-converter.service.d.ts +28 -0
  144. package/lib/processing/image-crop.d.ts +18 -0
  145. package/lib/processing/processing-image.d.ts +17 -0
  146. package/lib/provide-visualization.d.ts +34 -0
  147. package/lib/region-editor/mask-raster.d.ts +61 -0
  148. package/lib/region-editor/mask-worker.d.ts +7 -0
  149. package/lib/region-editor/region-editor.component.d.ts +305 -0
  150. package/lib/region-ops.service.d.ts +92 -0
  151. package/lib/render-orchestrator.d.ts +59 -0
  152. package/lib/routing-visualizer.service.d.ts +227 -0
  153. package/lib/store/class-color.util.d.ts +26 -0
  154. package/lib/store/region-store.service.d.ts +315 -0
  155. package/lib/store/visualizer-store.service.d.ts +123 -0
  156. package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
  157. package/lib/toolbar/crop/slide-crop.d.ts +30 -0
  158. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
  159. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
  160. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
  161. package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
  162. package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
  163. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
  164. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
  165. package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
  166. package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
  167. package/lib/toolbar/toolbar.component.d.ts +167 -0
  168. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
  169. package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
  170. package/lib/toolbar/wand/wand.service.d.ts +133 -0
  171. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
  172. package/lib/visualization.module.d.ts +45 -0
  173. package/lib/visualizer.component.d.ts +378 -0
  174. package/package.json +73 -0
  175. package/src/lib/assets/3d-coordinates.svg +49 -0
  176. package/src/lib/assets/cells.svg +1 -0
  177. package/src/lib/assets/click.svg +1 -0
  178. package/src/lib/assets/colormap-luts.json +1 -0
  179. package/src/lib/assets/contour.svg +48 -0
  180. package/src/lib/assets/cube-3d.svg +1 -0
  181. package/src/lib/assets/edit-selection-white.svg +47 -0
  182. package/src/lib/assets/heatmap.svg +1 -0
  183. package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
  184. package/src/lib/assets/icons/colormap-accent.png +0 -0
  185. package/src/lib/assets/icons/colormap-afmhot.png +0 -0
  186. package/src/lib/assets/icons/colormap-autumn.png +0 -0
  187. package/src/lib/assets/icons/colormap-berlin.png +0 -0
  188. package/src/lib/assets/icons/colormap-binary.png +0 -0
  189. package/src/lib/assets/icons/colormap-blackbody.png +0 -0
  190. package/src/lib/assets/icons/colormap-bluered.png +0 -0
  191. package/src/lib/assets/icons/colormap-blues.png +0 -0
  192. package/src/lib/assets/icons/colormap-bone.png +0 -0
  193. package/src/lib/assets/icons/colormap-brbg.png +0 -0
  194. package/src/lib/assets/icons/colormap-brg.png +0 -0
  195. package/src/lib/assets/icons/colormap-bugn.png +0 -0
  196. package/src/lib/assets/icons/colormap-bupu.png +0 -0
  197. package/src/lib/assets/icons/colormap-bwr.png +0 -0
  198. package/src/lib/assets/icons/colormap-cividis.png +0 -0
  199. package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
  200. package/src/lib/assets/icons/colormap-cool.png +0 -0
  201. package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
  202. package/src/lib/assets/icons/colormap-copper.png +0 -0
  203. package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
  204. package/src/lib/assets/icons/colormap-dark2.png +0 -0
  205. package/src/lib/assets/icons/colormap-earth.png +0 -0
  206. package/src/lib/assets/icons/colormap-electric.png +0 -0
  207. package/src/lib/assets/icons/colormap-flag.png +0 -0
  208. package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
  209. package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
  210. package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
  211. package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
  212. package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
  213. package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
  214. package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
  215. package/src/lib/assets/icons/colormap-gnbu.png +0 -0
  216. package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
  217. package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
  218. package/src/lib/assets/icons/colormap-gray.png +0 -0
  219. package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
  220. package/src/lib/assets/icons/colormap-greens.png +0 -0
  221. package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
  222. package/src/lib/assets/icons/colormap-greys.png +0 -0
  223. package/src/lib/assets/icons/colormap-hot.png +0 -0
  224. package/src/lib/assets/icons/colormap-hsv.png +0 -0
  225. package/src/lib/assets/icons/colormap-inferno.png +0 -0
  226. package/src/lib/assets/icons/colormap-jet.png +0 -0
  227. package/src/lib/assets/icons/colormap-magma.png +0 -0
  228. package/src/lib/assets/icons/colormap-managua.png +0 -0
  229. package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
  230. package/src/lib/assets/icons/colormap-ocean.png +0 -0
  231. package/src/lib/assets/icons/colormap-oranges.png +0 -0
  232. package/src/lib/assets/icons/colormap-orrd.png +0 -0
  233. package/src/lib/assets/icons/colormap-pastel2.png +0 -0
  234. package/src/lib/assets/icons/colormap-picnic.png +0 -0
  235. package/src/lib/assets/icons/colormap-pink.png +0 -0
  236. package/src/lib/assets/icons/colormap-piyg.png +0 -0
  237. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  238. package/src/lib/assets/icons/colormap-plasma.png +0 -0
  239. package/src/lib/assets/icons/colormap-portland.png +0 -0
  240. package/src/lib/assets/icons/colormap-prgn.png +0 -0
  241. package/src/lib/assets/icons/colormap-prism.png +0 -0
  242. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  243. package/src/lib/assets/icons/colormap-pubugn.png +0 -0
  244. package/src/lib/assets/icons/colormap-puor.png +0 -0
  245. package/src/lib/assets/icons/colormap-purd.png +0 -0
  246. package/src/lib/assets/icons/colormap-purples.png +0 -0
  247. package/src/lib/assets/icons/colormap-rainbow.png +0 -0
  248. package/src/lib/assets/icons/colormap-rdbu.png +0 -0
  249. package/src/lib/assets/icons/colormap-rdgy.png +0 -0
  250. package/src/lib/assets/icons/colormap-rdpu.png +0 -0
  251. package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
  252. package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
  253. package/src/lib/assets/icons/colormap-reds.png +0 -0
  254. package/src/lib/assets/icons/colormap-seismic.png +0 -0
  255. package/src/lib/assets/icons/colormap-set1.png +0 -0
  256. package/src/lib/assets/icons/colormap-set2.png +0 -0
  257. package/src/lib/assets/icons/colormap-set3.png +0 -0
  258. package/src/lib/assets/icons/colormap-spectral.png +0 -0
  259. package/src/lib/assets/icons/colormap-spring.png +0 -0
  260. package/src/lib/assets/icons/colormap-summer.png +0 -0
  261. package/src/lib/assets/icons/colormap-tab10.png +0 -0
  262. package/src/lib/assets/icons/colormap-tab20.png +0 -0
  263. package/src/lib/assets/icons/colormap-tab20b.png +0 -0
  264. package/src/lib/assets/icons/colormap-tab20c.png +0 -0
  265. package/src/lib/assets/icons/colormap-terrain.png +0 -0
  266. package/src/lib/assets/icons/colormap-turbo.png +0 -0
  267. package/src/lib/assets/icons/colormap-twilight.png +0 -0
  268. package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
  269. package/src/lib/assets/icons/colormap-vanimo.png +0 -0
  270. package/src/lib/assets/icons/colormap-viridis.png +0 -0
  271. package/src/lib/assets/icons/colormap-winter.png +0 -0
  272. package/src/lib/assets/icons/colormap-wistia.png +0 -0
  273. package/src/lib/assets/icons/colormap-ylgn.png +0 -0
  274. package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
  275. package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
  276. package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
  277. package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
  278. package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
  279. package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
  280. package/src/lib/assets/invert.svg +1 -0
  281. package/src/lib/assets/isosurface.svg +7 -0
  282. package/src/lib/assets/mask.svg +1 -0
  283. package/src/lib/assets/paintbrush.svg +1 -0
  284. package/src/lib/assets/picture-segmentation.svg +43 -0
  285. package/src/lib/assets/polygon-vertices.svg +13 -0
  286. package/src/lib/assets/polyline.svg +3 -0
  287. package/src/lib/assets/redo.svg +39 -0
  288. package/src/lib/assets/region-editor.svg +37 -0
  289. package/src/lib/assets/region-move.svg +7 -0
  290. package/src/lib/assets/smooth.svg +56 -0
  291. package/src/lib/assets/spline-chart.svg +7 -0
  292. package/src/lib/assets/surface.svg +37 -0
  293. package/src/lib/assets/test/download-379.svg +1 -0
  294. package/src/lib/assets/test/download-98.svg +1 -0
  295. package/src/lib/assets/test/json-1.svg +1 -0
  296. package/src/lib/assets/test/load-53.svg +1 -0
  297. package/src/lib/assets/test/mask-44.svg +1 -0
  298. package/src/lib/assets/test/mask-download-44.svg +15 -0
  299. package/src/lib/assets/test/mask-save-44.svg +11 -0
  300. package/src/lib/assets/test/overlay-1.svg +1 -0
  301. package/src/lib/assets/test/overlay-4.svg +1 -0
  302. package/src/lib/assets/test/region-26.svg +1 -0
  303. package/src/lib/assets/test/save-56.svg +1 -0
  304. package/src/lib/assets/test/upload-43.svg +1 -0
  305. package/src/lib/assets/to-bezier.svg +15 -0
  306. package/src/lib/assets/to-polygon.svg +11 -0
  307. package/src/lib/assets/undo.svg +38 -0
  308. package/src/lib/assets/vertex-add.svg +12 -0
  309. package/src/lib/assets/vertex-delete.svg +12 -0
  310. package/src/lib/assets/wand.svg +54 -0
  311. package/src/lib/assets/zoom-box.svg +10 -0
@@ -0,0 +1,301 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Region, Rectangle, Polygon, MultiPolygon } from './models/region';
3
+ import { unionMasks, simplifyRing } from './models/geometry';
4
+ import { WandService } from './toolbar/wand/wand.service';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./toolbar/wand/wand.service";
7
+ /**
8
+ * Pure (DOM-free) region set-operations — merge / inverse / ungroup (jit-ui#85).
9
+ *
10
+ * Raster-based, reusing the wand/brush mask pipeline
11
+ * ({@link WandService.rasterizePolygon} → {@link WandService.maskToPolygons}),
12
+ * so "select + merge" yields the same geometry as brushing regions together:
13
+ * one engine, one set of behaviours, holes + multi-part results for free.
14
+ *
15
+ * Every method takes the current regions plus the image dimensions and returns
16
+ * new {@link Region}(s); it never mutates the store. Callers commit the result
17
+ * through the normal region-write path (so undo/redo applies). Coordinates are
18
+ * image pixels throughout.
19
+ */
20
+ export class RegionOpsService {
21
+ /**
22
+ * Largest raster (in pixels) a region set-op will allocate on the main thread.
23
+ * Selections whose clipped bbox exceeds this are rasterized at a proportional
24
+ * downscale (then the traced geometry is scaled back), so merge/inverse stay
25
+ * responsive on gigapixel slides. ~16 MP keeps the synchronous contour trace
26
+ * well under a second; the downscale only affects boundary fidelity of very
27
+ * large-extent selections (small selections keep full resolution).
28
+ */
29
+ static { this.MAX_OP_PIXELS = 16_000_000; }
30
+ constructor(wand) {
31
+ this.wand = wand;
32
+ }
33
+ /**
34
+ * Geometric union of `regions` into a single region: a {@link Polygon} when
35
+ * the union is one connected piece, a {@link MultiPolygon} when it stays
36
+ * disjoint, with holes preserved. Returns null when nothing rasterises (e.g.
37
+ * only open polylines were selected).
38
+ */
39
+ merge(regions, imageWidth, imageHeight) {
40
+ // The raster is bounded by the selection's bbox, not the image — but on a
41
+ // whole-slide image a large-extent selection still spans billions of pixels,
42
+ // which freezes (or overflows the typed-array limit) on the main thread.
43
+ // Rasterize at a capped resolution and scale the traced polygons back up.
44
+ const scale = this.opRasterScale(regions, imageWidth, imageHeight);
45
+ const mask = this.unionMask(regions, imageWidth, imageHeight, scale);
46
+ if (!mask)
47
+ return null;
48
+ const sw = Math.max(1, Math.round(imageWidth * scale));
49
+ const sh = Math.max(1, Math.round(imageHeight * scale));
50
+ let polys = this.wand.maskToPolygons(mask.mask, mask.bw, mask.bh, sw, sh, mask.bx, mask.by, 1, 1);
51
+ if (scale !== 1)
52
+ polys = polys.map((p) => this.scalePolygon(p, 1 / scale));
53
+ return this.regionFromParts(polys, regions[0]);
54
+ }
55
+ /** Downscale factor (≤ 1) keeping the selection's clipped bbox within
56
+ * {@link MAX_OP_PIXELS}; 1 when it already fits. */
57
+ opRasterScale(regions, W, H) {
58
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
59
+ const scan = (xs, ys) => {
60
+ for (const x of xs) {
61
+ if (x < minX)
62
+ minX = x;
63
+ if (x > maxX)
64
+ maxX = x;
65
+ }
66
+ for (const y of ys) {
67
+ if (y < minY)
68
+ minY = y;
69
+ if (y > maxY)
70
+ maxY = y;
71
+ }
72
+ };
73
+ for (const r of regions || []) {
74
+ const b = r?.bounds;
75
+ if (b instanceof Rectangle)
76
+ scan([b.x, b.x + b.width], [b.y, b.y + b.height]);
77
+ else if (b instanceof Polygon)
78
+ scan(b.xpoints, b.ypoints);
79
+ else if (b instanceof MultiPolygon)
80
+ for (const p of b.polygons)
81
+ scan(p.xpoints, p.ypoints);
82
+ }
83
+ if (!Number.isFinite(minX))
84
+ return 1;
85
+ const bw = Math.min(W, maxX) - Math.max(0, minX);
86
+ const bh = Math.min(H, maxY) - Math.max(0, minY);
87
+ const area = bw * bh;
88
+ if (!(area > RegionOpsService.MAX_OP_PIXELS))
89
+ return 1;
90
+ return Math.sqrt(RegionOpsService.MAX_OP_PIXELS / area);
91
+ }
92
+ /** A copy of `p` with every coordinate (and hole coordinate) multiplied by `s`. */
93
+ scalePolygon(p, s) {
94
+ const poly = new Polygon();
95
+ poly.xpoints = p.xpoints.map((x) => x * s);
96
+ poly.ypoints = p.ypoints.map((y) => y * s);
97
+ poly.npoints = poly.xpoints.length;
98
+ poly.closed = p.closed;
99
+ poly.coordinates = poly.xpoints.map((x, i) => [x, poly.ypoints[i]]);
100
+ if (p.holes)
101
+ poly.holes = p.holes.map((ring) => ring.map(([x, y]) => [x * s, y * s]));
102
+ return poly;
103
+ }
104
+ /**
105
+ * Replace `regions` with their inverse inside the image rectangle: the image
106
+ * minus the selection's union (the former regions become holes). Returns null
107
+ * for a degenerate image or an empty selection.
108
+ *
109
+ * Done *vectorially* so it scales to gigapixel images: the selection is
110
+ * unioned first (raster, bounded by the ROIs' extent — never the whole image),
111
+ * then the result is the image rectangle as the exterior with each union
112
+ * component's outline punched out as a hole. A component's own hole (a donut)
113
+ * becomes a solid island part. Only the image's corner coordinates are used —
114
+ * no full-image buffer is ever allocated.
115
+ */
116
+ inverse(regions, imageWidth, imageHeight) {
117
+ if (imageWidth <= 0 || imageHeight <= 0)
118
+ return null;
119
+ const merged = this.merge(regions, imageWidth, imageHeight);
120
+ if (!merged)
121
+ return null;
122
+ const comps = merged.bounds instanceof MultiPolygon
123
+ ? merged.bounds.polygons
124
+ : merged.bounds instanceof Polygon ? [merged.bounds] : [];
125
+ if (comps.length === 0)
126
+ return null;
127
+ // Image rectangle exterior with every component outline as a hole.
128
+ const rect = this.ringPolygon([0, imageWidth, imageWidth, 0], [0, 0, imageHeight, imageHeight]);
129
+ rect.holes = comps.map((c) => c.xpoints.map((x, i) => [x, c.ypoints[i]]));
130
+ // Each component's own hole (donut interior) is *outside* the region, so it
131
+ // stays solid in the inverse — emit it as its own island part.
132
+ const parts = [rect];
133
+ for (const c of comps) {
134
+ if (c.holes) {
135
+ for (const ring of c.holes) {
136
+ parts.push(this.ringPolygon(ring.map((p) => p[0]), ring.map((p) => p[1])));
137
+ }
138
+ }
139
+ }
140
+ const bounds = parts.length === 1 ? parts[0] : Object.assign(new MultiPolygon(), { polygons: parts });
141
+ return this.makeRegion(bounds, regions[0]);
142
+ }
143
+ /** A closed straight-edged Polygon from parallel coord arrays. */
144
+ ringPolygon(xs, ys) {
145
+ const p = new Polygon();
146
+ p.xpoints = xs.slice();
147
+ p.ypoints = ys.slice();
148
+ p.npoints = xs.length;
149
+ p.coordinates = xs.map((x, i) => [x, ys[i]]);
150
+ p.closed = true;
151
+ return p;
152
+ }
153
+ /**
154
+ * Split a region into its disjoint parts — one region per {@link MultiPolygon}
155
+ * part. A single connected {@link Polygon}/{@link Rectangle} has nothing to
156
+ * split and is returned unchanged (as a one-element list).
157
+ */
158
+ ungroup(region) {
159
+ const b = region.bounds;
160
+ if (b instanceof MultiPolygon) {
161
+ return b.polygons
162
+ .filter((p) => p.xpoints.length >= 3)
163
+ .map((p) => this.makeRegion(this.clonePolygon(p), region));
164
+ }
165
+ return [region];
166
+ }
167
+ /** True when ungrouping `region` would actually split it (≥2 parts). */
168
+ canUngroup(region) {
169
+ return region.bounds instanceof MultiPolygon && region.bounds.polygons.length > 1;
170
+ }
171
+ /**
172
+ * Simplify a region's outline(s) with Douglas–Peucker — drop vertices within
173
+ * `altitudePx` pixels of the line between their kept neighbours. Applies to
174
+ * the exterior and every hole, of a polygon or each part of a MultiPolygon; a
175
+ * ring that would degenerate below a triangle is left at its previous detail
176
+ * (the part/hole is kept, not dropped). Rectangles and open polylines are
177
+ * returned unchanged. Result is always a straight-edged polygon (any Bézier
178
+ * smoothing is dropped, since the anchor set changes).
179
+ */
180
+ simplify(region, altitudePx) {
181
+ const b = region.bounds;
182
+ if (!(altitudePx > 0))
183
+ return region;
184
+ if (b instanceof Polygon && b.closed !== false) {
185
+ return this.makeRegion(this.simplifyPolygon(b, altitudePx), region);
186
+ }
187
+ if (b instanceof MultiPolygon) {
188
+ const mp = new MultiPolygon();
189
+ mp.polygons = b.polygons.map((p) => this.simplifyPolygon(p, altitudePx));
190
+ return this.makeRegion(mp, region);
191
+ }
192
+ return region;
193
+ }
194
+ /** Douglas–Peucker the exterior + each hole of one polygon. A ring that
195
+ * collapses below 3 vertices keeps its original points (never degenerates). */
196
+ simplifyPolygon(p, eps) {
197
+ const keepOrSrc = (xs, ys) => {
198
+ const s = simplifyRing(xs, ys, eps);
199
+ return s.xs.length >= 3 ? s : { xs: xs.slice(), ys: ys.slice() };
200
+ };
201
+ const ext = keepOrSrc(p.xpoints, p.ypoints);
202
+ const poly = new Polygon();
203
+ poly.npoints = ext.xs.length;
204
+ poly.xpoints = ext.xs;
205
+ poly.ypoints = ext.ys;
206
+ poly.coordinates = ext.xs.map((x, i) => [x, ext.ys[i]]);
207
+ poly.closed = true;
208
+ if (p.holes) {
209
+ const holes = p.holes.map((ring) => {
210
+ const s = keepOrSrc(ring.map((q) => q[0]), ring.map((q) => q[1]));
211
+ return s.xs.map((x, i) => [x, s.ys[i]]);
212
+ });
213
+ if (holes.length)
214
+ poly.holes = holes;
215
+ }
216
+ return poly;
217
+ }
218
+ // ── internals ──────────────────────────────────────────────────────────
219
+ /** Union of every region's filled mask (exterior minus holes), or null.
220
+ * `scale` (≤ 1) downscales the raster for large selections; coordinates and
221
+ * the clip bounds are scaled to match. */
222
+ unionMask(regions, W, H, scale = 1) {
223
+ let acc = null;
224
+ for (const region of regions || []) {
225
+ const m = this.rasterizeRegion(region, W, H, scale);
226
+ if (!m)
227
+ continue;
228
+ acc = acc ? unionMasks(acc, m) : m;
229
+ }
230
+ return acc;
231
+ }
232
+ /** Rasterise any region (rect / closed polygon / multi-polygon, holes punched
233
+ * out) into a bbox mask. Null for open polylines or degenerate geometry.
234
+ * `scale` (≤ 1) shrinks the coordinates and clip bounds for a downscaled raster. */
235
+ rasterizeRegion(region, W, H, scale = 1) {
236
+ const sw = scale === 1 ? W : Math.max(1, Math.round(W * scale));
237
+ const sh = scale === 1 ? H : Math.max(1, Math.round(H * scale));
238
+ const sc = (arr) => (scale === 1 ? arr : arr.map((v) => v * scale));
239
+ const scHoles = (holes) => !holes || scale === 1 ? holes : holes.map((ring) => ring.map(([x, y]) => [x * scale, y * scale]));
240
+ const b = region?.bounds;
241
+ if (b instanceof Rectangle) {
242
+ const xs = [b.x, b.x + b.width, b.x + b.width, b.x];
243
+ const ys = [b.y, b.y, b.y + b.height, b.y + b.height];
244
+ return this.wand.rasterizePolygon(sc(xs), sc(ys), sw, sh);
245
+ }
246
+ if (b instanceof Polygon) {
247
+ if (b.closed === false || b.xpoints.length < 3)
248
+ return null;
249
+ return this.wand.rasterizePolygon(sc(b.xpoints), sc(b.ypoints), sw, sh, scHoles(b.holes));
250
+ }
251
+ if (b instanceof MultiPolygon) {
252
+ let acc = null;
253
+ for (const part of b.polygons) {
254
+ if (part.xpoints.length < 3)
255
+ continue;
256
+ const m = this.wand.rasterizePolygon(sc(part.xpoints), sc(part.ypoints), sw, sh, scHoles(part.holes));
257
+ if (m)
258
+ acc = acc ? unionMasks(acc, m) : m;
259
+ }
260
+ return acc;
261
+ }
262
+ return null;
263
+ }
264
+ /** Wrap traced parts as one region (Polygon if single, else MultiPolygon),
265
+ * inheriting colour/label from `proto`. Null when there are no parts. */
266
+ regionFromParts(polys, proto) {
267
+ if (!polys || polys.length === 0)
268
+ return null;
269
+ if (polys.length === 1)
270
+ return this.makeRegion(polys[0], proto);
271
+ const mp = new MultiPolygon();
272
+ mp.polygons = polys;
273
+ return this.makeRegion(mp, proto);
274
+ }
275
+ makeRegion(bounds, proto) {
276
+ const r = new Region();
277
+ r.bounds = bounds;
278
+ r.color = proto?.color;
279
+ r.label = proto?.label ?? 'Region';
280
+ return r;
281
+ }
282
+ clonePolygon(p) {
283
+ const poly = new Polygon();
284
+ poly.npoints = p.npoints;
285
+ poly.xpoints = p.xpoints.slice();
286
+ poly.ypoints = p.ypoints.slice();
287
+ poly.coordinates = p.coordinates.map((c) => c.slice());
288
+ poly.closed = p.closed;
289
+ poly.bezier = p.bezier;
290
+ if (p.holes)
291
+ poly.holes = p.holes.map((ring) => ring.map((pt) => pt.slice()));
292
+ return poly;
293
+ }
294
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionOpsService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
295
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionOpsService, providedIn: 'root' }); }
296
+ }
297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionOpsService, decorators: [{
298
+ type: Injectable,
299
+ args: [{ providedIn: 'root' }]
300
+ }], ctorParameters: () => [{ type: i1.WandService }] });
301
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLW9wcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9yZWdpb24tb3BzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0UsT0FBTyxFQUFZLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN2RSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7OztBQUUxRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxNQUFNLE9BQU8sZ0JBQWdCO0lBQzNCOzs7Ozs7O09BT0c7YUFDcUIsa0JBQWEsR0FBRyxVQUFVLEFBQWIsQ0FBYztJQUVuRCxZQUFvQixJQUFpQjtRQUFqQixTQUFJLEdBQUosSUFBSSxDQUFhO0lBQUcsQ0FBQztJQUV6Qzs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxPQUFpQixFQUFFLFVBQWtCLEVBQUUsV0FBbUI7UUFDOUQsMEVBQTBFO1FBQzFFLDZFQUE2RTtRQUM3RSx5RUFBeUU7UUFDekUsMEVBQTBFO1FBQzFFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUNuRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3JFLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDdkIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLENB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RyxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUN2QixJQUFJLENBQUMsQ0FBQyxLQUFLO1lBQUUsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUM5RSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7OEdBcFFVLGdCQUFnQjtrSEFBaEIsZ0JBQWdCLGNBREgsTUFBTTs7MkZBQ25CLGdCQUFnQjtrQkFENUIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IFJlZ2lvbiwgUmVjdGFuZ2xlLCBQb2x5Z29uLCBNdWx0aVBvbHlnb24gfSBmcm9tICcuL21vZGVscy9yZWdpb24nO1xuaW1wb3J0IHsgQkJveE1hc2ssIHVuaW9uTWFza3MsIHNpbXBsaWZ5UmluZyB9IGZyb20gJy4vbW9kZWxzL2dlb21ldHJ5JztcbmltcG9ydCB7IFdhbmRTZXJ2aWNlIH0gZnJvbSAnLi90b29sYmFyL3dhbmQvd2FuZC5zZXJ2aWNlJztcblxuLyoqXG4gKiBQdXJlIChET00tZnJlZSkgcmVnaW9uIHNldC1vcGVyYXRpb25zIOKAlCBtZXJnZSAvIGludmVyc2UgLyB1bmdyb3VwIChqaXQtdWkjODUpLlxuICpcbiAqIFJhc3Rlci1iYXNlZCwgcmV1c2luZyB0aGUgd2FuZC9icnVzaCBtYXNrIHBpcGVsaW5lXG4gKiAoe0BsaW5rIFdhbmRTZXJ2aWNlLnJhc3Rlcml6ZVBvbHlnb259IOKGkiB7QGxpbmsgV2FuZFNlcnZpY2UubWFza1RvUG9seWdvbnN9KSxcbiAqIHNvIFwic2VsZWN0ICsgbWVyZ2VcIiB5aWVsZHMgdGhlIHNhbWUgZ2VvbWV0cnkgYXMgYnJ1c2hpbmcgcmVnaW9ucyB0b2dldGhlcjpcbiAqIG9uZSBlbmdpbmUsIG9uZSBzZXQgb2YgYmVoYXZpb3VycywgaG9sZXMgKyBtdWx0aS1wYXJ0IHJlc3VsdHMgZm9yIGZyZWUuXG4gKlxuICogRXZlcnkgbWV0aG9kIHRha2VzIHRoZSBjdXJyZW50IHJlZ2lvbnMgcGx1cyB0aGUgaW1hZ2UgZGltZW5zaW9ucyBhbmQgcmV0dXJuc1xuICogbmV3IHtAbGluayBSZWdpb259KHMpOyBpdCBuZXZlciBtdXRhdGVzIHRoZSBzdG9yZS4gQ2FsbGVycyBjb21taXQgdGhlIHJlc3VsdFxuICogdGhyb3VnaCB0aGUgbm9ybWFsIHJlZ2lvbi13cml0ZSBwYXRoIChzbyB1bmRvL3JlZG8gYXBwbGllcykuIENvb3JkaW5hdGVzIGFyZVxuICogaW1hZ2UgcGl4ZWxzIHRocm91Z2hvdXQuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUmVnaW9uT3BzU2VydmljZSB7XG4gIC8qKlxuICAgKiBMYXJnZXN0IHJhc3RlciAoaW4gcGl4ZWxzKSBhIHJlZ2lvbiBzZXQtb3Agd2lsbCBhbGxvY2F0ZSBvbiB0aGUgbWFpbiB0aHJlYWQuXG4gICAqIFNlbGVjdGlvbnMgd2hvc2UgY2xpcHBlZCBiYm94IGV4Y2VlZHMgdGhpcyBhcmUgcmFzdGVyaXplZCBhdCBhIHByb3BvcnRpb25hbFxuICAgKiBkb3duc2NhbGUgKHRoZW4gdGhlIHRyYWNlZCBnZW9tZXRyeSBpcyBzY2FsZWQgYmFjayksIHNvIG1lcmdlL2ludmVyc2Ugc3RheVxuICAgKiByZXNwb25zaXZlIG9uIGdpZ2FwaXhlbCBzbGlkZXMuIH4xNiBNUCBrZWVwcyB0aGUgc3luY2hyb25vdXMgY29udG91ciB0cmFjZVxuICAgKiB3ZWxsIHVuZGVyIGEgc2Vjb25kOyB0aGUgZG93bnNjYWxlIG9ubHkgYWZmZWN0cyBib3VuZGFyeSBmaWRlbGl0eSBvZiB2ZXJ5XG4gICAqIGxhcmdlLWV4dGVudCBzZWxlY3Rpb25zIChzbWFsbCBzZWxlY3Rpb25zIGtlZXAgZnVsbCByZXNvbHV0aW9uKS5cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IE1BWF9PUF9QSVhFTFMgPSAxNl8wMDBfMDAwO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgd2FuZDogV2FuZFNlcnZpY2UpIHt9XG5cbiAgLyoqXG4gICAqIEdlb21ldHJpYyB1bmlvbiBvZiBgcmVnaW9uc2AgaW50byBhIHNpbmdsZSByZWdpb246IGEge0BsaW5rIFBvbHlnb259IHdoZW5cbiAgICogdGhlIHVuaW9uIGlzIG9uZSBjb25uZWN0ZWQgcGllY2UsIGEge0BsaW5rIE11bHRpUG9seWdvbn0gd2hlbiBpdCBzdGF5c1xuICAgKiBkaXNqb2ludCwgd2l0aCBob2xlcyBwcmVzZXJ2ZWQuIFJldHVybnMgbnVsbCB3aGVuIG5vdGhpbmcgcmFzdGVyaXNlcyAoZS5nLlxuICAgKiBvbmx5IG9wZW4gcG9seWxpbmVzIHdlcmUgc2VsZWN0ZWQpLlxuICAgKi9cbiAgbWVyZ2UocmVnaW9uczogUmVnaW9uW10sIGltYWdlV2lkdGg6IG51bWJlciwgaW1hZ2VIZWlnaHQ6IG51bWJlcik6IFJlZ2lvbiB8IG51bGwge1xuICAgIC8vIFRoZSByYXN0ZXIgaXMgYm91bmRlZCBieSB0aGUgc2VsZWN0aW9uJ3MgYmJveCwgbm90IHRoZSBpbWFnZSDigJQgYnV0IG9uIGFcbiAgICAvLyB3aG9sZS1zbGlkZSBpbWFnZSBhIGxhcmdlLWV4dGVudCBzZWxlY3Rpb24gc3RpbGwgc3BhbnMgYmlsbGlvbnMgb2YgcGl4ZWxzLFxuICAgIC8vIHdoaWNoIGZyZWV6ZXMgKG9yIG92ZXJmbG93cyB0aGUgdHlwZWQtYXJyYXkgbGltaXQpIG9uIHRoZSBtYWluIHRocmVhZC5cbiAgICAvLyBSYXN0ZXJpemUgYXQgYSBjYXBwZWQgcmVzb2x1dGlvbiBhbmQgc2NhbGUgdGhlIHRyYWNlZCBwb2x5Z29ucyBiYWNrIHVwLlxuICAgIGNvbnN0IHNjYWxlID0gdGhpcy5vcFJhc3RlclNjYWxlKHJlZ2lvbnMsIGltYWdlV2lkdGgsIGltYWdlSGVpZ2h0KTtcbiAgICBjb25zdCBtYXNrID0gdGhpcy51bmlvbk1hc2socmVnaW9ucywgaW1hZ2VXaWR0aCwgaW1hZ2VIZWlnaHQsIHNjYWxlKTtcbiAgICBpZiAoIW1hc2spIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHN3ID0gTWF0aC5tYXgoMSwgTWF0aC5yb3VuZChpbWFnZVdpZHRoICogc2NhbGUpKTtcbiAgICBjb25zdCBzaCA9IE1hdGgubWF4KDEsIE1hdGgucm91bmQoaW1hZ2VIZWlnaHQgKiBzY2FsZSkpO1xuICAgIGxldCBwb2x5cyA9IHRoaXMud2FuZC5tYXNrVG9Qb2x5Z29ucyhtYXNrLm1hc2ssIG1hc2suYncsIG1hc2suYmgsIHN3LCBzaCwgbWFzay5ieCwgbWFzay5ieSwgMSwgMSk7XG4gICAgaWYgKHNjYWxlICE9PSAxKSBwb2x5cyA9IHBvbHlzLm1hcCgocCkgPT4gdGhpcy5zY2FsZVBvbHlnb24ocCwgMSAvIHNjYWxlKSk7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9uRnJvbVBhcnRzKHBvbHlzLCByZWdpb25zWzBdKTtcbiAgfVxuXG4gIC8qKiBEb3duc2NhbGUgZmFjdG9yICjiiaQgMSkga2VlcGluZyB0aGUgc2VsZWN0aW9uJ3MgY2xpcHBlZCBiYm94IHdpdGhpblxuICAgKiAge0BsaW5rIE1BWF9PUF9QSVhFTFN9OyAxIHdoZW4gaXQgYWxyZWFkeSBmaXRzLiAqL1xuICBwcml2YXRlIG9wUmFzdGVyU2NhbGUocmVnaW9uczogUmVnaW9uW10sIFc6IG51bWJlciwgSDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBsZXQgbWluWCA9IEluZmluaXR5LCBtaW5ZID0gSW5maW5pdHksIG1heFggPSAtSW5maW5pdHksIG1heFkgPSAtSW5maW5pdHk7XG4gICAgY29uc3Qgc2NhbiA9ICh4czogbnVtYmVyW10sIHlzOiBudW1iZXJbXSkgPT4ge1xuICAgICAgZm9yIChjb25zdCB4IG9mIHhzKSB7IGlmICh4IDwgbWluWCkgbWluWCA9IHg7IGlmICh4ID4gbWF4WCkgbWF4WCA9IHg7IH1cbiAgICAgIGZvciAoY29uc3QgeSBvZiB5cykgeyBpZiAoeSA8IG1pblkpIG1pblkgPSB5OyBpZiAoeSA+IG1heFkpIG1heFkgPSB5OyB9XG4gICAgfTtcbiAgICBmb3IgKGNvbnN0IHIgb2YgcmVnaW9ucyB8fCBbXSkge1xuICAgICAgY29uc3QgYiA9IHI/LmJvdW5kcztcbiAgICAgIGlmIChiIGluc3RhbmNlb2YgUmVjdGFuZ2xlKSBzY2FuKFtiLngsIGIueCArIGIud2lkdGhdLCBbYi55LCBiLnkgKyBiLmhlaWdodF0pO1xuICAgICAgZWxzZSBpZiAoYiBpbnN0YW5jZW9mIFBvbHlnb24pIHNjYW4oYi54cG9pbnRzLCBiLnlwb2ludHMpO1xuICAgICAgZWxzZSBpZiAoYiBpbnN0YW5jZW9mIE11bHRpUG9seWdvbikgZm9yIChjb25zdCBwIG9mIGIucG9seWdvbnMpIHNjYW4ocC54cG9pbnRzLCBwLnlwb2ludHMpO1xuICAgIH1cbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShtaW5YKSkgcmV0dXJuIDE7XG4gICAgY29uc3QgYncgPSBNYXRoLm1pbihXLCBtYXhYKSAtIE1hdGgubWF4KDAsIG1pblgpO1xuICAgIGNvbnN0IGJoID0gTWF0aC5taW4oSCwgbWF4WSkgLSBNYXRoLm1heCgwLCBtaW5ZKTtcbiAgICBjb25zdCBhcmVhID0gYncgKiBiaDtcbiAgICBpZiAoIShhcmVhID4gUmVnaW9uT3BzU2VydmljZS5NQVhfT1BfUElYRUxTKSkgcmV0dXJuIDE7XG4gICAgcmV0dXJuIE1hdGguc3FydChSZWdpb25PcHNTZXJ2aWNlLk1BWF9PUF9QSVhFTFMgLyBhcmVhKTtcbiAgfVxuXG4gIC8qKiBBIGNvcHkgb2YgYHBgIHdpdGggZXZlcnkgY29vcmRpbmF0ZSAoYW5kIGhvbGUgY29vcmRpbmF0ZSkgbXVsdGlwbGllZCBieSBgc2AuICovXG4gIHByaXZhdGUgc2NhbGVQb2x5Z29uKHA6IFBvbHlnb24sIHM6IG51bWJlcik6IFBvbHlnb24ge1xuICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgIHBvbHkueHBvaW50cyA9IHAueHBvaW50cy5tYXAoKHgpID0+IHggKiBzKTtcbiAgICBwb2x5Lnlwb2ludHMgPSBwLnlwb2ludHMubWFwKCh5KSA9PiB5ICogcyk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICBwb2x5LmNsb3NlZCA9IHAuY2xvc2VkO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBwb2x5Lnhwb2ludHMubWFwKCh4LCBpKSA9PiBbeCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgaWYgKHAuaG9sZXMpIHBvbHkuaG9sZXMgPSBwLmhvbGVzLm1hcCgocmluZykgPT4gcmluZy5tYXAoKFt4LCB5XSkgPT4gW3ggKiBzLCB5ICogc10pKTtcbiAgICByZXR1cm4gcG9seTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXBsYWNlIGByZWdpb25zYCB3aXRoIHRoZWlyIGludmVyc2UgaW5zaWRlIHRoZSBpbWFnZSByZWN0YW5nbGU6IHRoZSBpbWFnZVxuICAgKiBtaW51cyB0aGUgc2VsZWN0aW9uJ3MgdW5pb24gKHRoZSBmb3JtZXIgcmVnaW9ucyBiZWNvbWUgaG9sZXMpLiBSZXR1cm5zIG51bGxcbiAgICogZm9yIGEgZGVnZW5lcmF0ZSBpbWFnZSBvciBhbiBlbXB0eSBzZWxlY3Rpb24uXG4gICAqXG4gICAqIERvbmUgKnZlY3RvcmlhbGx5KiBzbyBpdCBzY2FsZXMgdG8gZ2lnYXBpeGVsIGltYWdlczogdGhlIHNlbGVjdGlvbiBpc1xuICAgKiB1bmlvbmVkIGZpcnN0IChyYXN0ZXIsIGJvdW5kZWQgYnkgdGhlIFJPSXMnIGV4dGVudCDigJQgbmV2ZXIgdGhlIHdob2xlIGltYWdlKSxcbiAgICogdGhlbiB0aGUgcmVzdWx0IGlzIHRoZSBpbWFnZSByZWN0YW5nbGUgYXMgdGhlIGV4dGVyaW9yIHdpdGggZWFjaCB1bmlvblxuICAgKiBjb21wb25lbnQncyBvdXRsaW5lIHB1bmNoZWQgb3V0IGFzIGEgaG9sZS4gQSBjb21wb25lbnQncyBvd24gaG9sZSAoYSBkb251dClcbiAgICogYmVjb21lcyBhIHNvbGlkIGlzbGFuZCBwYXJ0LiBPbmx5IHRoZSBpbWFnZSdzIGNvcm5lciBjb29yZGluYXRlcyBhcmUgdXNlZCDigJRcbiAgICogbm8gZnVsbC1pbWFnZSBidWZmZXIgaXMgZXZlciBhbGxvY2F0ZWQuXG4gICAqL1xuICBpbnZlcnNlKHJlZ2lvbnM6IFJlZ2lvbltdLCBpbWFnZVdpZHRoOiBudW1iZXIsIGltYWdlSGVpZ2h0OiBudW1iZXIpOiBSZWdpb24gfCBudWxsIHtcbiAgICBpZiAoaW1hZ2VXaWR0aCA8PSAwIHx8IGltYWdlSGVpZ2h0IDw9IDApIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG1lcmdlZCA9IHRoaXMubWVyZ2UocmVnaW9ucywgaW1hZ2VXaWR0aCwgaW1hZ2VIZWlnaHQpO1xuICAgIGlmICghbWVyZ2VkKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBjb21wczogUG9seWdvbltdID0gbWVyZ2VkLmJvdW5kcyBpbnN0YW5jZW9mIE11bHRpUG9seWdvblxuICAgICAgPyBtZXJnZWQuYm91bmRzLnBvbHlnb25zXG4gICAgICA6IG1lcmdlZC5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uID8gW21lcmdlZC5ib3VuZHNdIDogW107XG4gICAgaWYgKGNvbXBzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG5cbiAgICAvLyBJbWFnZSByZWN0YW5nbGUgZXh0ZXJpb3Igd2l0aCBldmVyeSBjb21wb25lbnQgb3V0bGluZSBhcyBhIGhvbGUuXG4gICAgY29uc3QgcmVjdCA9IHRoaXMucmluZ1BvbHlnb24oXG4gICAgICBbMCwgaW1hZ2VXaWR0aCwgaW1hZ2VXaWR0aCwgMF0sIFswLCAwLCBpbWFnZUhlaWdodCwgaW1hZ2VIZWlnaHRdKTtcbiAgICByZWN0LmhvbGVzID0gY29tcHMubWFwKChjKSA9PiBjLnhwb2ludHMubWFwKCh4LCBpKSA9PiBbeCwgYy55cG9pbnRzW2ldXSkpO1xuXG4gICAgLy8gRWFjaCBjb21wb25lbnQncyBvd24gaG9sZSAoZG9udXQgaW50ZXJpb3IpIGlzICpvdXRzaWRlKiB0aGUgcmVnaW9uLCBzbyBpdFxuICAgIC8vIHN0YXlzIHNvbGlkIGluIHRoZSBpbnZlcnNlIOKAlCBlbWl0IGl0IGFzIGl0cyBvd24gaXNsYW5kIHBhcnQuXG4gICAgY29uc3QgcGFydHM6IFBvbHlnb25bXSA9IFtyZWN0XTtcbiAgICBmb3IgKGNvbnN0IGMgb2YgY29tcHMpIHtcbiAgICAgIGlmIChjLmhvbGVzKSB7XG4gICAgICAgIGZvciAoY29uc3QgcmluZyBvZiBjLmhvbGVzKSB7XG4gICAgICAgICAgcGFydHMucHVzaCh0aGlzLnJpbmdQb2x5Z29uKHJpbmcubWFwKChwKSA9PiBwWzBdKSwgcmluZy5tYXAoKHApID0+IHBbMV0pKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgYm91bmRzID0gcGFydHMubGVuZ3RoID09PSAxID8gcGFydHNbMF0gOiBPYmplY3QuYXNzaWduKG5ldyBNdWx0aVBvbHlnb24oKSwgeyBwb2x5Z29uczogcGFydHMgfSk7XG4gICAgcmV0dXJuIHRoaXMubWFrZVJlZ2lvbihib3VuZHMsIHJlZ2lvbnNbMF0pO1xuICB9XG5cbiAgLyoqIEEgY2xvc2VkIHN0cmFpZ2h0LWVkZ2VkIFBvbHlnb24gZnJvbSBwYXJhbGxlbCBjb29yZCBhcnJheXMuICovXG4gIHByaXZhdGUgcmluZ1BvbHlnb24oeHM6IG51bWJlcltdLCB5czogbnVtYmVyW10pOiBQb2x5Z29uIHtcbiAgICBjb25zdCBwID0gbmV3IFBvbHlnb24oKTtcbiAgICBwLnhwb2ludHMgPSB4cy5zbGljZSgpO1xuICAgIHAueXBvaW50cyA9IHlzLnNsaWNlKCk7XG4gICAgcC5ucG9pbnRzID0geHMubGVuZ3RoO1xuICAgIHAuY29vcmRpbmF0ZXMgPSB4cy5tYXAoKHgsIGkpID0+IFt4LCB5c1tpXV0pO1xuICAgIHAuY2xvc2VkID0gdHJ1ZTtcbiAgICByZXR1cm4gcDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTcGxpdCBhIHJlZ2lvbiBpbnRvIGl0cyBkaXNqb2ludCBwYXJ0cyDigJQgb25lIHJlZ2lvbiBwZXIge0BsaW5rIE11bHRpUG9seWdvbn1cbiAgICogcGFydC4gQSBzaW5nbGUgY29ubmVjdGVkIHtAbGluayBQb2x5Z29ufS97QGxpbmsgUmVjdGFuZ2xlfSBoYXMgbm90aGluZyB0b1xuICAgKiBzcGxpdCBhbmQgaXMgcmV0dXJuZWQgdW5jaGFuZ2VkIChhcyBhIG9uZS1lbGVtZW50IGxpc3QpLlxuICAgKi9cbiAgdW5ncm91cChyZWdpb246IFJlZ2lvbik6IFJlZ2lvbltdIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoYiBpbnN0YW5jZW9mIE11bHRpUG9seWdvbikge1xuICAgICAgcmV0dXJuIGIucG9seWdvbnNcbiAgICAgICAgLmZpbHRlcigocCkgPT4gcC54cG9pbnRzLmxlbmd0aCA+PSAzKVxuICAgICAgICAubWFwKChwKSA9PiB0aGlzLm1ha2VSZWdpb24odGhpcy5jbG9uZVBvbHlnb24ocCksIHJlZ2lvbikpO1xuICAgIH1cbiAgICByZXR1cm4gW3JlZ2lvbl07XG4gIH1cblxuICAvKiogVHJ1ZSB3aGVuIHVuZ3JvdXBpbmcgYHJlZ2lvbmAgd291bGQgYWN0dWFsbHkgc3BsaXQgaXQgKOKJpTIgcGFydHMpLiAqL1xuICBjYW5Vbmdyb3VwKHJlZ2lvbjogUmVnaW9uKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlZ2lvbi5ib3VuZHMgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24gJiYgcmVnaW9uLmJvdW5kcy5wb2x5Z29ucy5sZW5ndGggPiAxO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpbXBsaWZ5IGEgcmVnaW9uJ3Mgb3V0bGluZShzKSB3aXRoIERvdWdsYXPigJNQZXVja2VyIOKAlCBkcm9wIHZlcnRpY2VzIHdpdGhpblxuICAgKiBgYWx0aXR1ZGVQeGAgcGl4ZWxzIG9mIHRoZSBsaW5lIGJldHdlZW4gdGhlaXIga2VwdCBuZWlnaGJvdXJzLiBBcHBsaWVzIHRvXG4gICAqIHRoZSBleHRlcmlvciBhbmQgZXZlcnkgaG9sZSwgb2YgYSBwb2x5Z29uIG9yIGVhY2ggcGFydCBvZiBhIE11bHRpUG9seWdvbjsgYVxuICAgKiByaW5nIHRoYXQgd291bGQgZGVnZW5lcmF0ZSBiZWxvdyBhIHRyaWFuZ2xlIGlzIGxlZnQgYXQgaXRzIHByZXZpb3VzIGRldGFpbFxuICAgKiAodGhlIHBhcnQvaG9sZSBpcyBrZXB0LCBub3QgZHJvcHBlZCkuIFJlY3RhbmdsZXMgYW5kIG9wZW4gcG9seWxpbmVzIGFyZVxuICAgKiByZXR1cm5lZCB1bmNoYW5nZWQuIFJlc3VsdCBpcyBhbHdheXMgYSBzdHJhaWdodC1lZGdlZCBwb2x5Z29uIChhbnkgQsOpemllclxuICAgKiBzbW9vdGhpbmcgaXMgZHJvcHBlZCwgc2luY2UgdGhlIGFuY2hvciBzZXQgY2hhbmdlcykuXG4gICAqL1xuICBzaW1wbGlmeShyZWdpb246IFJlZ2lvbiwgYWx0aXR1ZGVQeDogbnVtYmVyKTogUmVnaW9uIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoIShhbHRpdHVkZVB4ID4gMCkpIHJldHVybiByZWdpb247XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBQb2x5Z29uICYmIGIuY2xvc2VkICE9PSBmYWxzZSkge1xuICAgICAgcmV0dXJuIHRoaXMubWFrZVJlZ2lvbih0aGlzLnNpbXBsaWZ5UG9seWdvbihiLCBhbHRpdHVkZVB4KSwgcmVnaW9uKTtcbiAgICB9XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHtcbiAgICAgIGNvbnN0IG1wID0gbmV3IE11bHRpUG9seWdvbigpO1xuICAgICAgbXAucG9seWdvbnMgPSBiLnBvbHlnb25zLm1hcCgocCkgPT4gdGhpcy5zaW1wbGlmeVBvbHlnb24ocCwgYWx0aXR1ZGVQeCkpO1xuICAgICAgcmV0dXJuIHRoaXMubWFrZVJlZ2lvbihtcCwgcmVnaW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlZ2lvbjtcbiAgfVxuXG4gIC8qKiBEb3VnbGFz4oCTUGV1Y2tlciB0aGUgZXh0ZXJpb3IgKyBlYWNoIGhvbGUgb2Ygb25lIHBvbHlnb24uIEEgcmluZyB0aGF0XG4gICAqICBjb2xsYXBzZXMgYmVsb3cgMyB2ZXJ0aWNlcyBrZWVwcyBpdHMgb3JpZ2luYWwgcG9pbnRzIChuZXZlciBkZWdlbmVyYXRlcykuICovXG4gIHByaXZhdGUgc2ltcGxpZnlQb2x5Z29uKHA6IFBvbHlnb24sIGVwczogbnVtYmVyKTogUG9seWdvbiB7XG4gICAgY29uc3Qga2VlcE9yU3JjID0gKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdKTogeyB4czogbnVtYmVyW107IHlzOiBudW1iZXJbXSB9ID0+IHtcbiAgICAgIGNvbnN0IHMgPSBzaW1wbGlmeVJpbmcoeHMsIHlzLCBlcHMpO1xuICAgICAgcmV0dXJuIHMueHMubGVuZ3RoID49IDMgPyBzIDogeyB4czogeHMuc2xpY2UoKSwgeXM6IHlzLnNsaWNlKCkgfTtcbiAgICB9O1xuICAgIGNvbnN0IGV4dCA9IGtlZXBPclNyYyhwLnhwb2ludHMsIHAueXBvaW50cyk7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gZXh0LnhzLmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSBleHQueHM7XG4gICAgcG9seS55cG9pbnRzID0gZXh0LnlzO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBleHQueHMubWFwKCh4LCBpKSA9PiBbeCwgZXh0LnlzW2ldXSk7XG4gICAgcG9seS5jbG9zZWQgPSB0cnVlO1xuICAgIGlmIChwLmhvbGVzKSB7XG4gICAgICBjb25zdCBob2xlcyA9IHAuaG9sZXMubWFwKChyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IHMgPSBrZWVwT3JTcmMocmluZy5tYXAoKHEpID0+IHFbMF0pLCByaW5nLm1hcCgocSkgPT4gcVsxXSkpO1xuICAgICAgICByZXR1cm4gcy54cy5tYXAoKHgsIGkpID0+IFt4LCBzLnlzW2ldXSk7XG4gICAgICB9KTtcbiAgICAgIGlmIChob2xlcy5sZW5ndGgpIHBvbHkuaG9sZXMgPSBob2xlcztcbiAgICB9XG4gICAgcmV0dXJuIHBvbHk7XG4gIH1cblxuICAvLyDilIDilIAgaW50ZXJuYWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBVbmlvbiBvZiBldmVyeSByZWdpb24ncyBmaWxsZWQgbWFzayAoZXh0ZXJpb3IgbWludXMgaG9sZXMpLCBvciBudWxsLlxuICAgKiAgYHNjYWxlYCAo4omkIDEpIGRvd25zY2FsZXMgdGhlIHJhc3RlciBmb3IgbGFyZ2Ugc2VsZWN0aW9uczsgY29vcmRpbmF0ZXMgYW5kXG4gICAqICB0aGUgY2xpcCBib3VuZHMgYXJlIHNjYWxlZCB0byBtYXRjaC4gKi9cbiAgcHJpdmF0ZSB1bmlvbk1hc2socmVnaW9uczogUmVnaW9uW10sIFc6IG51bWJlciwgSDogbnVtYmVyLCBzY2FsZSA9IDEpOiBCQm94TWFzayB8IG51bGwge1xuICAgIGxldCBhY2M6IEJCb3hNYXNrIHwgbnVsbCA9IG51bGw7XG4gICAgZm9yIChjb25zdCByZWdpb24gb2YgcmVnaW9ucyB8fCBbXSkge1xuICAgICAgY29uc3QgbSA9IHRoaXMucmFzdGVyaXplUmVnaW9uKHJlZ2lvbiwgVywgSCwgc2NhbGUpO1xuICAgICAgaWYgKCFtKSBjb250aW51ZTtcbiAgICAgIGFjYyA9IGFjYyA/IHVuaW9uTWFza3MoYWNjLCBtKSA6IG07XG4gICAgfVxuICAgIHJldHVybiBhY2M7XG4gIH1cblxuICAvKiogUmFzdGVyaXNlIGFueSByZWdpb24gKHJlY3QgLyBjbG9zZWQgcG9seWdvbiAvIG11bHRpLXBvbHlnb24sIGhvbGVzIHB1bmNoZWRcbiAgICogIG91dCkgaW50byBhIGJib3ggbWFzay4gTnVsbCBmb3Igb3BlbiBwb2x5bGluZXMgb3IgZGVnZW5lcmF0ZSBnZW9tZXRyeS5cbiAgICogIGBzY2FsZWAgKOKJpCAxKSBzaHJpbmtzIHRoZSBjb29yZGluYXRlcyBhbmQgY2xpcCBib3VuZHMgZm9yIGEgZG93bnNjYWxlZCByYXN0ZXIuICovXG4gIHByaXZhdGUgcmFzdGVyaXplUmVnaW9uKHJlZ2lvbjogUmVnaW9uLCBXOiBudW1iZXIsIEg6IG51bWJlciwgc2NhbGUgPSAxKTogQkJveE1hc2sgfCBudWxsIHtcbiAgICBjb25zdCBzdyA9IHNjYWxlID09PSAxID8gVyA6IE1hdGgubWF4KDEsIE1hdGgucm91bmQoVyAqIHNjYWxlKSk7XG4gICAgY29uc3Qgc2ggPSBzY2FsZSA9PT0gMSA/IEggOiBNYXRoLm1heCgxLCBNYXRoLnJvdW5kKEggKiBzY2FsZSkpO1xuICAgIGNvbnN0IHNjID0gKGFycjogbnVtYmVyW10pID0+IChzY2FsZSA9PT0gMSA/IGFyciA6IGFyci5tYXAoKHYpID0+IHYgKiBzY2FsZSkpO1xuICAgIGNvbnN0IHNjSG9sZXMgPSAoaG9sZXM/OiBudW1iZXJbXVtdW10pID0+XG4gICAgICAhaG9sZXMgfHwgc2NhbGUgPT09IDEgPyBob2xlcyA6IGhvbGVzLm1hcCgocmluZykgPT4gcmluZy5tYXAoKFt4LCB5XSkgPT4gW3ggKiBzY2FsZSwgeSAqIHNjYWxlXSkpO1xuICAgIGNvbnN0IGIgPSByZWdpb24/LmJvdW5kcztcbiAgICBpZiAoYiBpbnN0YW5jZW9mIFJlY3RhbmdsZSkge1xuICAgICAgY29uc3QgeHMgPSBbYi54LCBiLnggKyBiLndpZHRoLCBiLnggKyBiLndpZHRoLCBiLnhdO1xuICAgICAgY29uc3QgeXMgPSBbYi55LCBiLnksIGIueSArIGIuaGVpZ2h0LCBiLnkgKyBiLmhlaWdodF07XG4gICAgICByZXR1cm4gdGhpcy53YW5kLnJhc3Rlcml6ZVBvbHlnb24oc2MoeHMpLCBzYyh5cyksIHN3LCBzaCk7XG4gICAgfVxuICAgIGlmIChiIGluc3RhbmNlb2YgUG9seWdvbikge1xuICAgICAgaWYgKGIuY2xvc2VkID09PSBmYWxzZSB8fCBiLnhwb2ludHMubGVuZ3RoIDwgMykgcmV0dXJuIG51bGw7XG4gICAgICByZXR1cm4gdGhpcy53YW5kLnJhc3Rlcml6ZVBvbHlnb24oc2MoYi54cG9pbnRzKSwgc2MoYi55cG9pbnRzKSwgc3csIHNoLCBzY0hvbGVzKGIuaG9sZXMpKTtcbiAgICB9XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHtcbiAgICAgIGxldCBhY2M6IEJCb3hNYXNrIHwgbnVsbCA9IG51bGw7XG4gICAgICBmb3IgKGNvbnN0IHBhcnQgb2YgYi5wb2x5Z29ucykge1xuICAgICAgICBpZiAocGFydC54cG9pbnRzLmxlbmd0aCA8IDMpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBtID0gdGhpcy53YW5kLnJhc3Rlcml6ZVBvbHlnb24oc2MocGFydC54cG9pbnRzKSwgc2MocGFydC55cG9pbnRzKSwgc3csIHNoLCBzY0hvbGVzKHBhcnQuaG9sZXMpKTtcbiAgICAgICAgaWYgKG0pIGFjYyA9IGFjYyA/IHVuaW9uTWFza3MoYWNjLCBtKSA6IG07XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBXcmFwIHRyYWNlZCBwYXJ0cyBhcyBvbmUgcmVnaW9uIChQb2x5Z29uIGlmIHNpbmdsZSwgZWxzZSBNdWx0aVBvbHlnb24pLFxuICAgKiAgaW5oZXJpdGluZyBjb2xvdXIvbGFiZWwgZnJvbSBgcHJvdG9gLiBOdWxsIHdoZW4gdGhlcmUgYXJlIG5vIHBhcnRzLiAqL1xuICBwcml2YXRlIHJlZ2lvbkZyb21QYXJ0cyhwb2x5czogUG9seWdvbltdLCBwcm90bzogUmVnaW9uIHwgdW5kZWZpbmVkKTogUmVnaW9uIHwgbnVsbCB7XG4gICAgaWYgKCFwb2x5cyB8fCBwb2x5cy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuICAgIGlmIChwb2x5cy5sZW5ndGggPT09IDEpIHJldHVybiB0aGlzLm1ha2VSZWdpb24ocG9seXNbMF0sIHByb3RvKTtcbiAgICBjb25zdCBtcCA9IG5ldyBNdWx0aVBvbHlnb24oKTtcbiAgICBtcC5wb2x5Z29ucyA9IHBvbHlzO1xuICAgIHJldHVybiB0aGlzLm1ha2VSZWdpb24obXAsIHByb3RvKTtcbiAgfVxuXG4gIHByaXZhdGUgbWFrZVJlZ2lvbihib3VuZHM6IFBvbHlnb24gfCBNdWx0aVBvbHlnb24sIHByb3RvOiBSZWdpb24gfCB1bmRlZmluZWQpOiBSZWdpb24ge1xuICAgIGNvbnN0IHIgPSBuZXcgUmVnaW9uKCk7XG4gICAgci5ib3VuZHMgPSBib3VuZHM7XG4gICAgci5jb2xvciA9IHByb3RvPy5jb2xvcjtcbiAgICByLmxhYmVsID0gcHJvdG8/LmxhYmVsID8/ICdSZWdpb24nO1xuICAgIHJldHVybiByO1xuICB9XG5cbiAgcHJpdmF0ZSBjbG9uZVBvbHlnb24ocDogUG9seWdvbik6IFBvbHlnb24ge1xuICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgIHBvbHkubnBvaW50cyA9IHAubnBvaW50cztcbiAgICBwb2x5Lnhwb2ludHMgPSBwLnhwb2ludHMuc2xpY2UoKTtcbiAgICBwb2x5Lnlwb2ludHMgPSBwLnlwb2ludHMuc2xpY2UoKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcC5jb29yZGluYXRlcy5tYXAoKGMpID0+IGMuc2xpY2UoKSk7XG4gICAgcG9seS5jbG9zZWQgPSBwLmNsb3NlZDtcbiAgICBwb2x5LmJlemllciA9IHAuYmV6aWVyO1xuICAgIGlmIChwLmhvbGVzKSBwb2x5LmhvbGVzID0gcC5ob2xlcy5tYXAoKHJpbmcpID0+IHJpbmcubWFwKChwdCkgPT4gcHQuc2xpY2UoKSkpO1xuICAgIHJldHVybiBwb2x5O1xuICB9XG59XG4iXX0=
@@ -0,0 +1,87 @@
1
+ export class RenderOrchestrator {
2
+ constructor(host, retryDelayMs = 1000) {
3
+ this.host = host;
4
+ this.retryDelayMs = retryDelayMs;
5
+ }
6
+ /** Run the render: single-pass when `smallInfo` is null, two-pass otherwise. */
7
+ async render(info, smallInfo) {
8
+ if (!smallInfo) {
9
+ try {
10
+ await this.host.renderPhase(info, false);
11
+ this.host.finished(false, 'finished plotting');
12
+ }
13
+ catch (err) {
14
+ console.error('Preview failed', err);
15
+ this.host.finished(false, 'plotting aborted');
16
+ }
17
+ return;
18
+ }
19
+ let smallReleasedOverlay = false;
20
+ try {
21
+ await this.host.renderPhase(smallInfo, false);
22
+ this.host.smallShown();
23
+ smallReleasedOverlay = true;
24
+ console.log('multi-tier: small tier rendered, starting large');
25
+ }
26
+ catch (err) {
27
+ // Small-tier render failed (older backend without tier support, transient
28
+ // error, …). Continue with large only; the overlay stays up until it lands.
29
+ console.warn('Small-tier preview failed, falling back to large', err);
30
+ }
31
+ try {
32
+ await this.renderLargeWithRetry(info);
33
+ this.host.sharpenSettled();
34
+ if (smallReleasedOverlay) {
35
+ this.host.finished(true, 'multi-tier: large tier rendered, sharpening complete');
36
+ }
37
+ else {
38
+ this.host.finished(false, 'finished plotting (large only after small fallback)');
39
+ }
40
+ }
41
+ catch (err) {
42
+ this.host.sharpenSettled();
43
+ console.error('Large-tier preview failed after retry', err);
44
+ this.host.sharpenFailed(err);
45
+ }
46
+ }
47
+ /** One retry after a brief delay before giving up on the large tier. */
48
+ renderLargeWithRetry(info) {
49
+ return this.host.renderPhase(info, true).catch((err) => {
50
+ console.warn('Large-tier preview failed on first try, retrying in 1s', err);
51
+ return new Promise((resolve) => setTimeout(resolve, this.retryDelayMs)).then(() => this.host.renderPhase(info, true));
52
+ });
53
+ }
54
+ }
55
+ /**
56
+ * Debounced z-slice scrubbing (extracted with the orchestrator): coalesce the
57
+ * rapid changes a slider drag fires so a slice swap doesn't run on every
58
+ * pixel; the final value lands immediately via {@link commit} (onSlideEnd).
59
+ */
60
+ export class SliceScrubber {
61
+ constructor(apply, delayMs = 120) {
62
+ this.apply = apply;
63
+ this.delayMs = delayMs;
64
+ this.timer = null;
65
+ }
66
+ /** Debounced application of z while dragging. */
67
+ scrub(z) {
68
+ this.cancel();
69
+ this.timer = setTimeout(() => {
70
+ this.timer = null;
71
+ this.apply(z);
72
+ }, this.delayMs);
73
+ }
74
+ /** Apply z immediately (slide end / keyboard step), dropping any pending scrub. */
75
+ commit(z) {
76
+ this.cancel();
77
+ this.apply(z);
78
+ }
79
+ /** Drop a pending scrub without applying (teardown). */
80
+ cancel() {
81
+ if (this.timer) {
82
+ clearTimeout(this.timer);
83
+ this.timer = null;
84
+ }
85
+ }
86
+ }
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyLW9yY2hlc3RyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvcmVuZGVyLW9yY2hlc3RyYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFtQ0EsTUFBTSxPQUFPLGtCQUFrQjtJQUM3QixZQUNVLElBQXVCLEVBQ3ZCLGVBQWUsSUFBSTtRQURuQixTQUFJLEdBQUosSUFBSSxDQUFtQjtRQUN2QixpQkFBWSxHQUFaLFlBQVksQ0FBTztJQUMxQixDQUFDO0lBRUosZ0ZBQWdGO0lBQ2hGLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBZ0IsRUFBRSxTQUE0QjtRQUN6RCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ3pDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1lBQ2pELENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1lBQ2hELENBQUM7WUFDRCxPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksb0JBQW9CLEdBQUcsS0FBSyxDQUFDO1FBQ2pDLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDdkIsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaURBQWlELENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLDBFQUEwRTtZQUMxRSw0RUFBNEU7WUFDNUUsT0FBTyxDQUFDLElBQUksQ0FBQyxrREFBa0QsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN4RSxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUMzQixJQUFJLG9CQUFvQixFQUFFLENBQUM7Z0JBQ3pCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxzREFBc0QsQ0FBQyxDQUFDO1lBQ25GLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUscURBQXFELENBQUMsQ0FBQztZQUNuRixDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYixJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzNCLE9BQU8sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDNUQsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDL0IsQ0FBQztJQUNILENBQUM7SUFFRCx3RUFBd0U7SUFDaEUsb0JBQW9CLENBQUMsSUFBZ0I7UUFDM0MsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7WUFDckQsT0FBTyxDQUFDLElBQUksQ0FBQyx3REFBd0QsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUM1RSxPQUFPLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FDdEYsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUNsQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFHeEIsWUFDVSxLQUEwQixFQUMxQixVQUFVLEdBQUc7UUFEYixVQUFLLEdBQUwsS0FBSyxDQUFxQjtRQUMxQixZQUFPLEdBQVAsT0FBTyxDQUFNO1FBSmYsVUFBSyxHQUF5QyxJQUFJLENBQUM7SUFLeEQsQ0FBQztJQUVKLGlEQUFpRDtJQUNqRCxLQUFLLENBQUMsQ0FBUztRQUNiLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNkLElBQUksQ0FBQyxLQUFLLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUMzQixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztZQUNsQixJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hCLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUVELG1GQUFtRjtJQUNuRixNQUFNLENBQUMsQ0FBUztRQUNkLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNkLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEIsQ0FBQztJQUVELHdEQUF3RDtJQUN4RCxNQUFNO1FBQ0osSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDZixZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi9jb250cmFjdHMvaW1hZ2UuY29udHJhY3QnO1xuXG4vKipcbiAqIFR3by1wYXNzIChzbWFsbOKGkmxhcmdlKSByZW5kZXIgc2VxdWVuY2luZywgZXh0cmFjdGVkIGZyb21cbiAqIFZpc3VhbGl6ZXJDb21wb25lbnQgKHJlZmFjdG9yaW5nIHBsYW4sIFN0ZXAgNyDigJQgYSBwdXJlIG1vdmUgb2YgdGhlXG4gKiBvcmNoZXN0cmF0aW9uOyB0aGUgY29tcG9uZW50IGtlZXBzIHRoZSBVSSBmbGFncyBhbmQgc3VwcGxpZXMgdGhlbSB0aHJvdWdoXG4gKiB0aGUgaG9zdCBjYWxsYmFja3MpLlxuICpcbiAqIFdoZW4gdGhlIGZpbGUgaGFzIHNtYWxsLXRpZXIgVVJMcyB3ZSByZW5kZXIgdGhlIHNtYWxsIHRpZXIgZmlyc3QgZm9yIGEgZmFzdFxuICogYmx1cnJ5IHByZXZpZXcsIHJlbGVhc2UgdGhlIGxvYWRpbmcgb3ZlcmxheSAoa2VlcGluZyBhIHRyYW5zbHVjZW50XG4gKiBcInNoYXJwZW5pbmdcIiBzcGlubmVyKSwgdGhlbiBzaGFycGVuIGJ5IHJlLXJlbmRlcmluZyB0aGUgY2Fub25pY2FsIGxhcmdlIHRpZXJcbiAqIGluIHBsYWNlLiBXaXRob3V0IGEgc21hbGwgdGllciBpdCdzIHRoZSBvcmlnaW5hbCBzaW5nbGUgcGFzcy4gVGhlIGxhcmdlIHBhc3NcbiAqIHJldHJpZXMgb25jZSBhZnRlciBhIHNob3J0IGRlbGF5IOKAlCB0aGUgcHJldmlldyBlbmRwb2ludCBjYW4gaGl0IGEgdHJhbnNpZW50XG4gKiA1MDMgb3IgYSBsb2NrLWNvbnRlbnRpb24gd2luZG93LCBhbmQgdGhlIHNlY29uZCBhdHRlbXB0IHVzdWFsbHkgbGFuZHMgb25cbiAqIGZyZXNoIHByZS1nZW4tY2FjaGVkIFBOR3MuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHdvUGFzc1JlbmRlckhvc3Qge1xuICAvKiogTG9hZCArIHBsb3Qgb25lIHBoYXNlICh0aGUgY29tcG9uZW50IG93bnMgZGl2L3NjcmVlbi9wbG90LXR5cGUveiBhbmQgdGhlXG4gICAqICBuZXdlci1jbGljayBmaWxlbmFtZSBndWFyZCkuIGBpblBsYWNlYCB1cGRhdGVzIHRoZSBleGlzdGluZyByZW5kZXIgc28gdGhlXG4gICAqICBjYW52YXMgZG9lc24ndCBibGFuayBkdXJpbmcgdGhlIHNtYWxs4oaSbGFyZ2Ugc3dhcC4gKi9cbiAgcmVuZGVyUGhhc2UoaW5mbzogSUltYWdlSW5mbywgaW5QbGFjZTogYm9vbGVhbik6IFByb21pc2U8dW5rbm93bj47XG4gIC8qKiBUaGUgc21hbGwgdGllciBpcyBvbiBzY3JlZW4g4oCUIGRyb3AgdGhlIGZ1bGwgbG9hZGluZyBvdmVybGF5IHNvIHRoZSB1c2VyXG4gICAqICBzZWVzIHRoZSBibHVycnkgcHJldmlldywgYW5kIHNob3cgdGhlIHNoYXJwZW5pbmcgc3Bpbm5lci4gKi9cbiAgc21hbGxTaG93bigpOiB2b2lkO1xuICAvKiogVGhlIGxhcmdlIHJlbmRlciBzZXR0bGVkIChlaXRoZXIgd2F5KSDigJQgc2hhcnBlbmluZyBzcGlubmVyIG9mZi4gKi9cbiAgc2hhcnBlblNldHRsZWQoKTogdm9pZDtcbiAgLyoqIFJlbmRlcmluZyBmaW5pc2hlZC4gYHZpYVNtYWxsYCA9IHRoZSBvdmVybGF5IHdhcyBhbHJlYWR5IHJlbGVhc2VkIGJ5IHRoZVxuICAgKiAgc21hbGwgdGllciAoc28gb25seSByZWxlYXNlIHRoZSBydW5uaW5nIGd1YXJkICsgYXBwbHkgdGhlIFJPSSk7IG90aGVyd2lzZVxuICAgKiAgZG8gdGhlIGZ1bGwgZmluYWxpemUgKG92ZXJsYXkgKyBydW5uaW5nICsgUk9JKS4gKi9cbiAgZmluaXNoZWQodmlhU21hbGw6IGJvb2xlYW4sIGxvZ1RhZzogc3RyaW5nKTogdm9pZDtcbiAgLyoqIEJvdGggbGFyZ2UtdGllciBhdHRlbXB0cyBmYWlsZWQ7IHRoZSBzbWFsbCB0aWVyIHN0YXlzIG9uIHNjcmVlbiBhcyB0aGVcbiAgICogIGZhbGxiYWNrLiBTdXJmYWNlIGl0IHRvIHRoZSB1c2VyIGFuZCByZWxlYXNlIHRoZSBydW5uaW5nIGd1YXJkICsgUk9JLiAqL1xuICBzaGFycGVuRmFpbGVkKGVycjogdW5rbm93bik6IHZvaWQ7XG59XG5cbmV4cG9ydCBjbGFzcyBSZW5kZXJPcmNoZXN0cmF0b3Ige1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGhvc3Q6IFR3b1Bhc3NSZW5kZXJIb3N0LFxuICAgIHByaXZhdGUgcmV0cnlEZWxheU1zID0gMTAwMCxcbiAgKSB7fVxuXG4gIC8qKiBSdW4gdGhlIHJlbmRlcjogc2luZ2xlLXBhc3Mgd2hlbiBgc21hbGxJbmZvYCBpcyBudWxsLCB0d28tcGFzcyBvdGhlcndpc2UuICovXG4gIGFzeW5jIHJlbmRlcihpbmZvOiBJSW1hZ2VJbmZvLCBzbWFsbEluZm86IElJbWFnZUluZm8gfCBudWxsKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCFzbWFsbEluZm8pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaG9zdC5yZW5kZXJQaGFzZShpbmZvLCBmYWxzZSk7XG4gICAgICAgIHRoaXMuaG9zdC5maW5pc2hlZChmYWxzZSwgJ2ZpbmlzaGVkIHBsb3R0aW5nJyk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignUHJldmlldyBmYWlsZWQnLCBlcnIpO1xuICAgICAgICB0aGlzLmhvc3QuZmluaXNoZWQoZmFsc2UsICdwbG90dGluZyBhYm9ydGVkJyk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IHNtYWxsUmVsZWFzZWRPdmVybGF5ID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuaG9zdC5yZW5kZXJQaGFzZShzbWFsbEluZm8sIGZhbHNlKTtcbiAgICAgIHRoaXMuaG9zdC5zbWFsbFNob3duKCk7XG4gICAgICBzbWFsbFJlbGVhc2VkT3ZlcmxheSA9IHRydWU7XG4gICAgICBjb25zb2xlLmxvZygnbXVsdGktdGllcjogc21hbGwgdGllciByZW5kZXJlZCwgc3RhcnRpbmcgbGFyZ2UnKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIFNtYWxsLXRpZXIgcmVuZGVyIGZhaWxlZCAob2xkZXIgYmFja2VuZCB3aXRob3V0IHRpZXIgc3VwcG9ydCwgdHJhbnNpZW50XG4gICAgICAvLyBlcnJvciwg4oCmKS4gQ29udGludWUgd2l0aCBsYXJnZSBvbmx5OyB0aGUgb3ZlcmxheSBzdGF5cyB1cCB1bnRpbCBpdCBsYW5kcy5cbiAgICAgIGNvbnNvbGUud2FybignU21hbGwtdGllciBwcmV2aWV3IGZhaWxlZCwgZmFsbGluZyBiYWNrIHRvIGxhcmdlJywgZXJyKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXJMYXJnZVdpdGhSZXRyeShpbmZvKTtcbiAgICAgIHRoaXMuaG9zdC5zaGFycGVuU2V0dGxlZCgpO1xuICAgICAgaWYgKHNtYWxsUmVsZWFzZWRPdmVybGF5KSB7XG4gICAgICAgIHRoaXMuaG9zdC5maW5pc2hlZCh0cnVlLCAnbXVsdGktdGllcjogbGFyZ2UgdGllciByZW5kZXJlZCwgc2hhcnBlbmluZyBjb21wbGV0ZScpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ob3N0LmZpbmlzaGVkKGZhbHNlLCAnZmluaXNoZWQgcGxvdHRpbmcgKGxhcmdlIG9ubHkgYWZ0ZXIgc21hbGwgZmFsbGJhY2spJyk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmhvc3Quc2hhcnBlblNldHRsZWQoKTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0xhcmdlLXRpZXIgcHJldmlldyBmYWlsZWQgYWZ0ZXIgcmV0cnknLCBlcnIpO1xuICAgICAgdGhpcy5ob3N0LnNoYXJwZW5GYWlsZWQoZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKiogT25lIHJldHJ5IGFmdGVyIGEgYnJpZWYgZGVsYXkgYmVmb3JlIGdpdmluZyB1cCBvbiB0aGUgbGFyZ2UgdGllci4gKi9cbiAgcHJpdmF0ZSByZW5kZXJMYXJnZVdpdGhSZXRyeShpbmZvOiBJSW1hZ2VJbmZvKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgcmV0dXJuIHRoaXMuaG9zdC5yZW5kZXJQaGFzZShpbmZvLCB0cnVlKS5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICBjb25zb2xlLndhcm4oJ0xhcmdlLXRpZXIgcHJldmlldyBmYWlsZWQgb24gZmlyc3QgdHJ5LCByZXRyeWluZyBpbiAxcycsIGVycik7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGhpcy5yZXRyeURlbGF5TXMpKS50aGVuKCgpID0+XG4gICAgICAgIHRoaXMuaG9zdC5yZW5kZXJQaGFzZShpbmZvLCB0cnVlKSxcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZWJvdW5jZWQgei1zbGljZSBzY3J1YmJpbmcgKGV4dHJhY3RlZCB3aXRoIHRoZSBvcmNoZXN0cmF0b3IpOiBjb2FsZXNjZSB0aGVcbiAqIHJhcGlkIGNoYW5nZXMgYSBzbGlkZXIgZHJhZyBmaXJlcyBzbyBhIHNsaWNlIHN3YXAgZG9lc24ndCBydW4gb24gZXZlcnlcbiAqIHBpeGVsOyB0aGUgZmluYWwgdmFsdWUgbGFuZHMgaW1tZWRpYXRlbHkgdmlhIHtAbGluayBjb21taXR9IChvblNsaWRlRW5kKS5cbiAqL1xuZXhwb3J0IGNsYXNzIFNsaWNlU2NydWJiZXIge1xuICBwcml2YXRlIHRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXBwbHk6ICh6OiBudW1iZXIpID0+IHZvaWQsXG4gICAgcHJpdmF0ZSBkZWxheU1zID0gMTIwLFxuICApIHt9XG5cbiAgLyoqIERlYm91bmNlZCBhcHBsaWNhdGlvbiBvZiB6IHdoaWxlIGRyYWdnaW5nLiAqL1xuICBzY3J1Yih6OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmNhbmNlbCgpO1xuICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudGltZXIgPSBudWxsO1xuICAgICAgdGhpcy5hcHBseSh6KTtcbiAgICB9LCB0aGlzLmRlbGF5TXMpO1xuICB9XG5cbiAgLyoqIEFwcGx5IHogaW1tZWRpYXRlbHkgKHNsaWRlIGVuZCAvIGtleWJvYXJkIHN0ZXApLCBkcm9wcGluZyBhbnkgcGVuZGluZyBzY3J1Yi4gKi9cbiAgY29tbWl0KHo6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuY2FuY2VsKCk7XG4gICAgdGhpcy5hcHBseSh6KTtcbiAgfVxuXG4gIC8qKiBEcm9wIGEgcGVuZGluZyBzY3J1YiB3aXRob3V0IGFwcGx5aW5nICh0ZWFyZG93bikuICovXG4gIGNhbmNlbCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50aW1lcikge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZXIpO1xuICAgICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgfVxuICB9XG59XG4iXX0=