@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,94 @@
1
+ /**
2
+ * Pure helpers for SAM inference — no DOM, no ORT, no `this` — so they're unit
3
+ * testable. The session uses these to assemble decoder inputs and to convert
4
+ * the cached image frame into the RGBA buffer the encoder preprocesses.
5
+ */
6
+ /**
7
+ * Build an RGBA buffer (the encoder's input image) from a cached image frame.
8
+ * Grayscale frames are replicated across R/G/B; RGB tuples are copied through.
9
+ * Out-of-range/missing pixels become opaque black.
10
+ */
11
+ export function frameToRgba(cached, frameIndex) {
12
+ const { width, height } = cached;
13
+ const frame = cached.frames[frameIndex] ?? cached.frames[0];
14
+ const rgba = new Uint8ClampedArray(width * height * 4);
15
+ for (let y = 0; y < height; y++) {
16
+ const row = frame?.[y];
17
+ for (let x = 0; x < width; x++) {
18
+ const o = (y * width + x) * 4;
19
+ const px = row?.[x];
20
+ if (px == null) {
21
+ rgba[o + 3] = 255;
22
+ continue;
23
+ }
24
+ if (cached.isGrayscale) {
25
+ const v = px;
26
+ rgba[o] = v;
27
+ rgba[o + 1] = v;
28
+ rgba[o + 2] = v;
29
+ }
30
+ else {
31
+ const t = px;
32
+ rgba[o] = t[0];
33
+ rgba[o + 1] = t[1];
34
+ rgba[o + 2] = t[2];
35
+ }
36
+ rgba[o + 3] = 255;
37
+ }
38
+ }
39
+ return rgba;
40
+ }
41
+ /**
42
+ * Assemble the SAM decoder's `point_coords` / `point_labels` from a prompt.
43
+ *
44
+ * Coordinates are scaled into the encoder's resized space (`scale =
45
+ * inputSize / max(imageW, imageH)`). A box is encoded as two points labelled
46
+ * `2` (top-left) and `3` (bottom-right); positive/negative points use `1`/`0`.
47
+ * When there are points but no box, a padding point `[0,0]` labelled `-1` is
48
+ * appended (the decoder expects the box slots padded when absent).
49
+ */
50
+ export function buildDecoderPrompt(prompt, scale) {
51
+ const coords = [];
52
+ const labels = [];
53
+ for (const p of prompt.points ?? []) {
54
+ coords.push(p.x * scale, p.y * scale);
55
+ labels.push(p.label);
56
+ }
57
+ if (prompt.box) {
58
+ const b = prompt.box;
59
+ coords.push(b.x0 * scale, b.y0 * scale);
60
+ labels.push(2);
61
+ coords.push(b.x1 * scale, b.y1 * scale);
62
+ labels.push(3);
63
+ }
64
+ else if (labels.length > 0) {
65
+ // Points-only: pad the (absent) box slot.
66
+ coords.push(0, 0);
67
+ labels.push(-1);
68
+ }
69
+ return {
70
+ pointCoords: Float32Array.from(coords),
71
+ pointLabels: Float32Array.from(labels),
72
+ numPoints: labels.length,
73
+ };
74
+ }
75
+ /**
76
+ * Binarize SAM mask logits (`> threshold`, default 0 per SAM's mask_threshold)
77
+ * into a 0/1 mask the contour tracer (WandService.maskToPolygons) consumes.
78
+ */
79
+ export function binarizeMask(logits, threshold = 0) {
80
+ const out = new Uint8Array(logits.length);
81
+ for (let i = 0; i < logits.length; i++)
82
+ out[i] = logits[i] > threshold ? 1 : 0;
83
+ return out;
84
+ }
85
+ /** Index of the highest-scoring mask in a multimask decoder output. */
86
+ export function bestMaskIndex(iouPredictions) {
87
+ let best = 0;
88
+ for (let i = 1; i < iouPredictions.length; i++) {
89
+ if (iouPredictions[i] > iouPredictions[best])
90
+ best = i;
91
+ }
92
+ return best;
93
+ }
94
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLXByb21wdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXByb21wdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQTs7OztHQUlHO0FBRUg7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsTUFBdUIsRUFBRSxVQUFrQjtJQUNyRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUNqQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxLQUFLLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNoQyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDL0IsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM5QixNQUFNLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNwQixJQUFJLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDZixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztnQkFDbEIsU0FBUztZQUNYLENBQUM7WUFDRCxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztn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QUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0UsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQsdUVBQXVFO0FBQ3ZFLE1BQU0sVUFBVSxhQUFhLENBQUMsY0FBdUM7SUFDbkUsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUMvQyxJQUFJLGNBQWMsQ0FBQyxDQUFDLENBQUMsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDO1lBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2FjaGVkSW1hZ2VEYXRhIH0gZnJvbSAnLi4vd2FuZC93YW5kLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBTYW1Qcm9tcHQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc2FtLmNvbnRyYWN0JztcblxuLyoqXG4gKiBQdXJlIGhlbHBlcnMgZm9yIFNBTSBpbmZlcmVuY2Ug4oCUIG5vIERPTSwgbm8gT1JULCBubyBgdGhpc2Ag4oCUIHNvIHRoZXkncmUgdW5pdFxuICogdGVzdGFibGUuIFRoZSBzZXNzaW9uIHVzZXMgdGhlc2UgdG8gYXNzZW1ibGUgZGVjb2RlciBpbnB1dHMgYW5kIHRvIGNvbnZlcnRcbiAqIHRoZSBjYWNoZWQgaW1hZ2UgZnJhbWUgaW50byB0aGUgUkdCQSBidWZmZXIgdGhlIGVuY29kZXIgcHJlcHJvY2Vzc2VzLlxuICovXG5cbi8qKlxuICogQnVpbGQgYW4gUkdCQSBidWZmZXIgKHRoZSBlbmNvZGVyJ3MgaW5wdXQgaW1hZ2UpIGZyb20gYSBjYWNoZWQgaW1hZ2UgZnJhbWUuXG4gKiBHcmF5c2NhbGUgZnJhbWVzIGFyZSByZXBsaWNhdGVkIGFjcm9zcyBSL0cvQjsgUkdCIHR1cGxlcyBhcmUgY29waWVkIHRocm91Z2guXG4gKiBPdXQtb2YtcmFuZ2UvbWlzc2luZyBwaXhlbHMgYmVjb21lIG9wYXF1ZSBibGFjay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZyYW1lVG9SZ2JhKGNhY2hlZDogQ2FjaGVkSW1hZ2VEYXRhLCBmcmFtZUluZGV4OiBudW1iZXIpOiBVaW50OENsYW1wZWRBcnJheSB7XG4gIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gY2FjaGVkO1xuICBjb25zdCBmcmFtZSA9IGNhY2hlZC5mcmFtZXNbZnJhbWVJbmRleF0gPz8gY2FjaGVkLmZyYW1lc1swXTtcbiAgY29uc3QgcmdiYSA9IG5ldyBVaW50OENsYW1wZWRBcnJheSh3aWR0aCAqIGhlaWdodCAqIDQpO1xuICBmb3IgKGxldCB5ID0gMDsgeSA8IGhlaWdodDsgeSsrKSB7XG4gICAgY29uc3Qgcm93ID0gZnJhbWU/Llt5XTtcbiAgICBmb3IgKGxldCB4ID0gMDsgeCA8IHdpZHRoOyB4KyspIHtcbiAgICAgIGNvbnN0IG8gPSAoeSAqIHdpZHRoICsgeCkgKiA0O1xuICAgICAgY29uc3QgcHggPSByb3c/Llt4XTtcbiAgICAgIGlmIChweCA9PSBudWxsKSB7XG4gICAgICAgIHJnYmFbbyArIDNdID0gMjU1O1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmIChjYWNoZWQuaXNHcmF5c2NhbGUpIHtcbiAgICAgICAgY29uc3QgdiA9IHB4IGFzIG51bWJlcjtcbiAgICAgICAgcmdiYVtvXSA9IHY7IHJnYmFbbyArIDFdID0gdjsgcmdiYVtvICsgMl0gPSB2O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgdCA9IHB4IGFzIG51bWJlcltdO1xuICAgICAgICByZ2JhW29dID0gdFswXTsgcmdiYVtvICsgMV0gPSB0WzFdOyByZ2JhW28gKyAyXSA9IHRbMl07XG4gICAgICB9XG4gICAgICByZ2JhW28gKyAzXSA9IDI1NTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJnYmE7XG59XG5cbi8qKlxuICogQXNzZW1ibGUgdGhlIFNBTSBkZWNvZGVyJ3MgYHBvaW50X2Nvb3Jkc2AgLyBgcG9pbnRfbGFiZWxzYCBmcm9tIGEgcHJvbXB0LlxuICpcbiAqIENvb3JkaW5hdGVzIGFyZSBzY2FsZWQgaW50byB0aGUgZW5jb2RlcidzIHJlc2l6ZWQgc3BhY2UgKGBzY2FsZSA9XG4gKiBpbnB1dFNpemUgLyBtYXgoaW1hZ2VXLCBpbWFnZUgpYCkuIEEgYm94IGlzIGVuY29kZWQgYXMgdHdvIHBvaW50cyBsYWJlbGxlZFxuICogYDJgICh0b3AtbGVmdCkgYW5kIGAzYCAoYm90dG9tLXJpZ2h0KTsgcG9zaXRpdmUvbmVnYXRpdmUgcG9pbnRzIHVzZSBgMWAvYDBgLlxuICogV2hlbiB0aGVyZSBhcmUgcG9pbnRzIGJ1dCBubyBib3gsIGEgcGFkZGluZyBwb2ludCBgWzAsMF1gIGxhYmVsbGVkIGAtMWAgaXNcbiAqIGFwcGVuZGVkICh0aGUgZGVjb2RlciBleHBlY3RzIHRoZSBib3ggc2xvdHMgcGFkZGVkIHdoZW4gYWJzZW50KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRGVjb2RlclByb21wdChcbiAgcHJvbXB0OiBTYW1Qcm9tcHQsXG4gIHNjYWxlOiBudW1iZXIsXG4pOiB7IHBvaW50Q29vcmRzOiBGbG9hdDMyQXJyYXk7IHBvaW50TGFiZWxzOiBGbG9hdDMyQXJyYXk7IG51bVBvaW50czogbnVtYmVyIH0ge1xuICBjb25zdCBjb29yZHM6IG51bWJlcltdID0gW107XG4gIGNvbnN0IGxhYmVsczogbnVtYmVyW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IHAgb2YgcHJvbXB0LnBvaW50cyA/PyBbXSkge1xuICAgIGNvb3Jkcy5wdXNoKHAueCAqIHNjYWxlLCBwLnkgKiBzY2FsZSk7XG4gICAgbGFiZWxzLnB1c2gocC5sYWJlbCk7XG4gIH1cblxuICBpZiAocHJvbXB0LmJveCkge1xuICAgIGNvbnN0IGIgPSBwcm9tcHQuYm94O1xuICAgIGNvb3Jkcy5wdXNoKGIueDAgKiBzY2FsZSwgYi55MCAqIHNjYWxlKTtcbiAgICBsYWJlbHMucHVzaCgyKTtcbiAgICBjb29yZHMucHVzaChiLngxICogc2NhbGUsIGIueTEgKiBzY2FsZSk7XG4gICAgbGFiZWxzLnB1c2goMyk7XG4gIH0gZWxzZSBpZiAobGFiZWxzLmxlbmd0aCA+IDApIHtcbiAgICAvLyBQb2ludHMtb25seTogcGFkIHRoZSAoYWJzZW50KSBib3ggc2xvdC5cbiAgICBjb29yZHMucHVzaCgwLCAwKTtcbiAgICBsYWJlbHMucHVzaCgtMSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHBvaW50Q29vcmRzOiBGbG9hdDMyQXJyYXkuZnJvbShjb29yZHMpLFxuICAgIHBvaW50TGFiZWxzOiBGbG9hdDMyQXJyYXkuZnJvbShsYWJlbHMpLFxuICAgIG51bVBvaW50czogbGFiZWxzLmxlbmd0aCxcbiAgfTtcbn1cblxuLyoqXG4gKiBCaW5hcml6ZSBTQU0gbWFzayBsb2dpdHMgKGA+IHRocmVzaG9sZGAsIGRlZmF1bHQgMCBwZXIgU0FNJ3MgbWFza190aHJlc2hvbGQpXG4gKiBpbnRvIGEgMC8xIG1hc2sgdGhlIGNvbnRvdXIgdHJhY2VyIChXYW5kU2VydmljZS5tYXNrVG9Qb2x5Z29ucykgY29uc3VtZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcml6ZU1hc2sobG9naXRzOiBGbG9hdDMyQXJyYXkgfCBudW1iZXJbXSwgdGhyZXNob2xkID0gMCk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShsb2dpdHMubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsb2dpdHMubGVuZ3RoOyBpKyspIG91dFtpXSA9IGxvZ2l0c1tpXSA+IHRocmVzaG9sZCA/IDEgOiAwO1xuICByZXR1cm4gb3V0O1xufVxuXG4vKiogSW5kZXggb2YgdGhlIGhpZ2hlc3Qtc2NvcmluZyBtYXNrIGluIGEgbXVsdGltYXNrIGRlY29kZXIgb3V0cHV0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlc3RNYXNrSW5kZXgoaW91UHJlZGljdGlvbnM6IEZsb2F0MzJBcnJheSB8IG51bWJlcltdKTogbnVtYmVyIHtcbiAgbGV0IGJlc3QgPSAwO1xuICBmb3IgKGxldCBpID0gMTsgaSA8IGlvdVByZWRpY3Rpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGlvdVByZWRpY3Rpb25zW2ldID4gaW91UHJlZGljdGlvbnNbYmVzdF0pIGJlc3QgPSBpO1xuICB9XG4gIHJldHVybiBiZXN0O1xufVxuIl19
@@ -0,0 +1,188 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import { WandService } from '../wand/wand.service';
4
+ import { frameToRgba } from './sam-prompt';
5
+ import { getSamModel, isSamModelReady } from './sam-model-registry';
6
+ import { Region, Polygon, Rectangle } from '../../models/region';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "../wand/wand.service";
9
+ /**
10
+ * Box-prompted SAM segmentation tool (jit-ui#90, P0). On `segmentBoxes()` it
11
+ * reads every rectangle region, runs the (cached) encoder once for the image,
12
+ * then runs the decoder per box, traces each mask to a polygon (reusing
13
+ * WandService.maskToPolygons) and commits them as regions.
14
+ *
15
+ * Inference is abstracted behind {@link ISamSession}: production uses the
16
+ * onnxruntime-web session (lazy-imported so ORT never loads in unit tests);
17
+ * tests inject a fake via {@link useSession}.
18
+ */
19
+ export class SamToolService {
20
+ constructor(wandService) {
21
+ this.wandService = wandService;
22
+ this.session = null;
23
+ this.model = getSamModel();
24
+ /** Cached encoder embedding + the key (image identity) it was computed for. */
25
+ this.embedding = null;
26
+ this.embeddingKey = null;
27
+ /** Status text + busy flag for a spinner / toast in the host. */
28
+ this.status$ = new BehaviorSubject('');
29
+ this.busy$ = new BehaviorSubject(false);
30
+ /** Encoder-download progress: -1 = not downloading, 0..1 = downloading. */
31
+ this.progress$ = new BehaviorSubject(-1);
32
+ }
33
+ /** Bind to the active backend's host (called by the backend, like the wand). */
34
+ bindHost(host) {
35
+ this.host = host;
36
+ }
37
+ /** Choose the registered model to use; invalidates any cached embedding. */
38
+ setModel(id) {
39
+ const next = getSamModel(id);
40
+ if (next.id === this.model.id)
41
+ return;
42
+ this.model = next;
43
+ this.invalidateEmbedding();
44
+ // Drop the loaded session so the next run reloads the newly-picked model's
45
+ // ONNX pair — ensureSession() returns the cached session as-is, so without
46
+ // this a model switch would keep running the previous model.
47
+ this.session?.dispose();
48
+ this.session = null;
49
+ }
50
+ /** Drop the cached embedding (e.g. after the image/slice changes). */
51
+ invalidateEmbedding() {
52
+ this.embedding = null;
53
+ this.embeddingKey = null;
54
+ }
55
+ /** Test seam: inject a fake/alternate inference session. */
56
+ useSession(session) {
57
+ this.session = session;
58
+ }
59
+ /**
60
+ * Segment every rectangle region with a box prompt and append the resulting
61
+ * masks as new polygon regions. Returns how many regions were added.
62
+ */
63
+ async segmentBoxes() {
64
+ if (!this.host)
65
+ return 0;
66
+ // Re-entrancy guard: a second Segment press while the first run is still
67
+ // downloading/encoding would launch a concurrent model download + GPU
68
+ // encode (and can freeze the tab on a heavy WebGPU ViT-B). Ignore it.
69
+ if (this.busy$.value)
70
+ return 0;
71
+ const cached = this.host.getCachedImageData();
72
+ if (!cached || cached.frames.length === 0) {
73
+ this.status$.next('No image loaded.');
74
+ return 0;
75
+ }
76
+ const regions = this.host.getRegions();
77
+ const rects = regions.filter((r) => r.bounds instanceof Rectangle);
78
+ if (rects.length === 0) {
79
+ this.status$.next('Draw one or more rectangles, then press Segment.');
80
+ return 0;
81
+ }
82
+ const rx = cached.ratios[0] || 1;
83
+ const ry = cached.ratios[0] || 1;
84
+ const ox = cached.originX ?? 0;
85
+ const oy = cached.originY ?? 0;
86
+ let session;
87
+ try {
88
+ session = await this.ensureSession();
89
+ }
90
+ catch (err) {
91
+ this.busy$.next(false);
92
+ this.status$.next(err instanceof Error ? err.message : 'SAM model unavailable.');
93
+ return 0;
94
+ }
95
+ this.busy$.next(true);
96
+ try {
97
+ // Encode once per image; reuse the embedding across all boxes.
98
+ const key = [
99
+ this.host.getFileName() ?? '',
100
+ this.host.getActiveFrameIndex(),
101
+ `${cached.width}x${cached.height}`,
102
+ `${ox},${oy},${rx}`,
103
+ this.model.id,
104
+ ].join('|');
105
+ if (!this.embedding || this.embeddingKey !== key) {
106
+ this.status$.next('Encoding image…');
107
+ const rgba = frameToRgba(cached, this.host.getActiveFrameIndex());
108
+ this.embedding = await session.embed({ data: rgba, width: cached.width, height: cached.height });
109
+ this.embeddingKey = key;
110
+ }
111
+ const masks = [];
112
+ const consumed = new Set(); // prompt rectangles that produced a mask
113
+ let added = 0;
114
+ for (let i = 0; i < rects.length; i++) {
115
+ this.status$.next(`Segmenting ${i + 1}/${rects.length}…`);
116
+ const b = rects[i].bounds;
117
+ // Rectangle is in data coords → convert to image (matrix) coords.
118
+ const box = {
119
+ x0: (b.x - ox) / rx,
120
+ y0: (b.y - oy) / ry,
121
+ x1: (b.x + b.width - ox) / rx,
122
+ y1: (b.y + b.height - oy) / ry,
123
+ };
124
+ const res = await session.decode(this.embedding, { box });
125
+ const polys = this.wandService.maskToPolygons(res.mask, res.width, res.height, cached.width, cached.height, 0, 0);
126
+ if (polys.length === 0)
127
+ continue;
128
+ // Keep the largest connected piece (maskToPolygons returns largest-first).
129
+ const poly = polys[0];
130
+ masks.push(this.makeRegion(poly.xpoints.map((x) => ox + x * rx), poly.ypoints.map((y) => oy + y * ry), rects[i].color));
131
+ consumed.add(rects[i]); // this rectangle is now represented by its mask
132
+ added++;
133
+ }
134
+ // Replace each segmented prompt rectangle with its mask region; keep any
135
+ // rectangle that produced no mask (so it can be retried) + other regions.
136
+ const out = regions.filter((r) => !consumed.has(r)).concat(masks);
137
+ this.host.setRegions(out);
138
+ this.status$.next(added > 0 ? `Added ${added} region(s).` : 'No masks found.');
139
+ return added;
140
+ }
141
+ catch (err) {
142
+ this.status$.next(err instanceof Error ? err.message : 'Segmentation failed.');
143
+ return 0;
144
+ }
145
+ finally {
146
+ this.busy$.next(false);
147
+ this.progress$.next(-1);
148
+ }
149
+ }
150
+ makeRegion(xData, yData, color) {
151
+ const poly = new Polygon();
152
+ poly.npoints = xData.length;
153
+ poly.xpoints = xData;
154
+ poly.ypoints = yData;
155
+ poly.coordinates = xData.map((x, i) => [x, yData[i]]);
156
+ poly.closed = true;
157
+ const region = new Region();
158
+ region.bounds = poly;
159
+ // Inherit the source prompt rectangle's color; fall back to the host default.
160
+ region.color = color || this.host.getShapeColor();
161
+ // Default class/annotation name, matching the wand/brush + overlay-drawn regions.
162
+ region.label = 'sam';
163
+ return region;
164
+ }
165
+ async ensureSession() {
166
+ if (this.session)
167
+ return this.session;
168
+ if (!isSamModelReady(this.model)) {
169
+ throw new Error(`SAM model "${this.model.id}" is not configured yet (no ONNX URLs). ` +
170
+ 'Host it and call setSamModelUrls(), then retry.');
171
+ }
172
+ // Lazy-import so onnxruntime-web is never pulled into unit tests / the
173
+ // initial bundle — only when segmentation actually runs.
174
+ const { OnnxSamSession } = await import('./onnx-sam-session');
175
+ const session = new OnnxSamSession();
176
+ this.progress$.next(0);
177
+ await session.loadModel(this.model, (f) => this.progress$.next(f));
178
+ this.session = session;
179
+ return session;
180
+ }
181
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
182
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, providedIn: 'root' }); }
183
+ }
184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SamToolService, decorators: [{
185
+ type: Injectable,
186
+ args: [{ providedIn: 'root' }]
187
+ }], ctorParameters: () => [{ type: i1.WandService }] });
188
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FtLXRvb2wuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFdkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRW5ELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVwRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBTWpFOzs7Ozs7Ozs7R0FTRztBQUVILE1BQU0sT0FBTyxjQUFjO0lBZXpCLFlBQW9CLFdBQXdCO1FBQXhCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBYnBDLFlBQU8sR0FBdUIsSUFBSSxDQUFDO1FBQ25DLFVBQUssR0FBZ0IsV0FBVyxFQUFFLENBQUM7UUFFM0MsK0VBQStFO1FBQ3ZFLGNBQVMsR0FBd0IsSUFBSSxDQUFDO1FBQ3RDLGlCQUFZLEdBQWtCLElBQUksQ0FBQztRQUUzQyxpRUFBaUU7UUFDeEQsWUFBTyxHQUFHLElBQUksZUFBZSxDQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLFVBQUssR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUNyRCwyRUFBMkU7UUFDbEUsY0FBUyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFTixDQUFDO0lBRWhELGdGQUFnRjtJQUNoRixRQUFRLENBQUMsSUFBaUI7UUFDeEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENB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Q0FBQyxFQUFFLDBDQUEwQztnQkFDckUsaURBQWlELENBQ2xELENBQUM7UUFDSixDQUFDO1FBQ0QsdUVBQXVFO1FBQ3ZFLHlEQUF5RDtRQUN6RCxNQUFNLEVBQUUsY0FBYyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUM5RCxNQUFNLE9BQU8sR0FBRyxJQUFJLGNBQWMsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZCLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25FLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7OEdBakxVLGNBQWM7a0hBQWQsY0FBYyxjQURELE1BQU07OzJGQUNuQixjQUFjO2tCQUQxQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBXYW5kU2VydmljZSB9IGZyb20gJy4uL3dhbmQvd2FuZC5zZXJ2aWNlJztcbmltcG9ydCB7IFdhbmRUb29sSG9zdCB9IGZyb20gJy4uL3dhbmQvd2FuZC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgZnJhbWVUb1JnYmEgfSBmcm9tICcuL3NhbS1wcm9tcHQnO1xuaW1wb3J0IHsgZ2V0U2FtTW9kZWwsIGlzU2FtTW9kZWxSZWFkeSB9IGZyb20gJy4vc2FtLW1vZGVsLXJlZ2lzdHJ5JztcbmltcG9ydCB7IElTYW1TZXNzaW9uLCBTYW1FbWJlZGRpbmcsIFNhbU1vZGVsRGVmIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NhbS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb24sIFBvbHlnb24sIFJlY3RhbmdsZSB9IGZyb20gJy4uLy4uL21vZGVscy9yZWdpb24nO1xuXG4vKiogVGhlIFNBTSB0b29sIGJpbmRzIHRvIHRoZSBzYW1lIGhvc3QgdGhlIHdhbmQvYnJ1c2ggdXNlLCBzbyBlYWNoIGJhY2tlbmRcbiAqICByZXVzZXMgaXRzIGV4aXN0aW5nIHBpeGVsIHJlYWRiYWNrICsgY29vcmRpbmF0ZSB0cmFuc2Zvcm0gKyByZWdpb24gc3RvcmUuICovXG5leHBvcnQgdHlwZSBTYW1Ub29sSG9zdCA9IFdhbmRUb29sSG9zdDtcblxuLyoqXG4gKiBCb3gtcHJvbXB0ZWQgU0FNIHNlZ21lbnRhdGlvbiB0b29sIChqaXQtdWkjOTAsIFAwKS4gT24gYHNlZ21lbnRCb3hlcygpYCBpdFxuICogcmVhZHMgZXZlcnkgcmVjdGFuZ2xlIHJlZ2lvbiwgcnVucyB0aGUgKGNhY2hlZCkgZW5jb2RlciBvbmNlIGZvciB0aGUgaW1hZ2UsXG4gKiB0aGVuIHJ1bnMgdGhlIGRlY29kZXIgcGVyIGJveCwgdHJhY2VzIGVhY2ggbWFzayB0byBhIHBvbHlnb24gKHJldXNpbmdcbiAqIFdhbmRTZXJ2aWNlLm1hc2tUb1BvbHlnb25zKSBhbmQgY29tbWl0cyB0aGVtIGFzIHJlZ2lvbnMuXG4gKlxuICogSW5mZXJlbmNlIGlzIGFic3RyYWN0ZWQgYmVoaW5kIHtAbGluayBJU2FtU2Vzc2lvbn06IHByb2R1Y3Rpb24gdXNlcyB0aGVcbiAqIG9ubnhydW50aW1lLXdlYiBzZXNzaW9uIChsYXp5LWltcG9ydGVkIHNvIE9SVCBuZXZlciBsb2FkcyBpbiB1bml0IHRlc3RzKTtcbiAqIHRlc3RzIGluamVjdCBhIGZha2UgdmlhIHtAbGluayB1c2VTZXNzaW9ufS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBTYW1Ub29sU2VydmljZSB7XG4gIHByaXZhdGUgaG9zdCE6IFNhbVRvb2xIb3N0O1xuICBwcml2YXRlIHNlc3Npb246IElTYW1TZXNzaW9uIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbW9kZWw6IFNhbU1vZGVsRGVmID0gZ2V0U2FtTW9kZWwoKTtcblxuICAvKiogQ2FjaGVkIGVuY29kZXIgZW1iZWRkaW5nICsgdGhlIGtleSAoaW1hZ2UgaWRlbnRpdHkpIGl0IHdhcyBjb21wdXRlZCBmb3IuICovXG4gIHByaXZhdGUgZW1iZWRkaW5nOiBTYW1FbWJlZGRpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBlbWJlZGRpbmdLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBTdGF0dXMgdGV4dCArIGJ1c3kgZmxhZyBmb3IgYSBzcGlubmVyIC8gdG9hc3QgaW4gdGhlIGhvc3QuICovXG4gIHJlYWRvbmx5IHN0YXR1cyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuICByZWFkb25seSBidXN5JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW5jb2Rlci1kb3dubG9hZCBwcm9ncmVzczogLTEgPSBub3QgZG93bmxvYWRpbmcsIDAuLjEgPSBkb3dubG9hZGluZy4gKi9cbiAgcmVhZG9ubHkgcHJvZ3Jlc3MkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KC0xKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSkge31cblxuICAvKiogQmluZCB0byB0aGUgYWN0aXZlIGJhY2tlbmQncyBob3N0IChjYWxsZWQgYnkgdGhlIGJhY2tlbmQsIGxpa2UgdGhlIHdhbmQpLiAqL1xuICBiaW5kSG9zdChob3N0OiBTYW1Ub29sSG9zdCk6IHZvaWQge1xuICAgIHRoaXMuaG9zdCA9IGhvc3Q7XG4gIH1cblxuICAvKiogQ2hvb3NlIHRoZSByZWdpc3RlcmVkIG1vZGVsIHRvIHVzZTsgaW52YWxpZGF0ZXMgYW55IGNhY2hlZCBlbWJlZGRpbmcuICovXG4gIHNldE1vZGVsKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gZ2V0U2FtTW9kZWwoaWQpO1xuICAgIGlmIChuZXh0LmlkID09PSB0aGlzLm1vZGVsLmlkKSByZXR1cm47XG4gICAgdGhpcy5tb2RlbCA9IG5leHQ7XG4gICAgdGhpcy5pbnZhbGlkYXRlRW1iZWRkaW5nKCk7XG4gICAgLy8gRHJvcCB0aGUgbG9hZGVkIHNlc3Npb24gc28gdGhlIG5leHQgcnVuIHJlbG9hZHMgdGhlIG5ld2x5LXBpY2tlZCBtb2RlbCdzXG4gICAgLy8gT05OWCBwYWlyIOKAlCBlbnN1cmVTZXNzaW9uKCkgcmV0dXJucyB0aGUgY2FjaGVkIHNlc3Npb24gYXMtaXMsIHNvIHdpdGhvdXRcbiAgICAvLyB0aGlzIGEgbW9kZWwgc3dpdGNoIHdvdWxkIGtlZXAgcnVubmluZyB0aGUgcHJldmlvdXMgbW9kZWwuXG4gICAgdGhpcy5zZXNzaW9uPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5zZXNzaW9uID0gbnVsbDtcbiAgfVxuXG4gIC8qKiBEcm9wIHRoZSBjYWNoZWQgZW1iZWRkaW5nIChlLmcuIGFmdGVyIHRoZSBpbWFnZS9zbGljZSBjaGFuZ2VzKS4gKi9cbiAgaW52YWxpZGF0ZUVtYmVkZGluZygpOiB2b2lkIHtcbiAgICB0aGlzLmVtYmVkZGluZyA9IG51bGw7XG4gICAgdGhpcy5lbWJlZGRpbmdLZXkgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRlc3Qgc2VhbTogaW5qZWN0IGEgZmFrZS9hbHRlcm5hdGUgaW5mZXJlbmNlIHNlc3Npb24uICovXG4gIHVzZVNlc3Npb24oc2Vzc2lvbjogSVNhbVNlc3Npb24pOiB2b2lkIHtcbiAgICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlZ21lbnQgZXZlcnkgcmVjdGFuZ2xlIHJlZ2lvbiB3aXRoIGEgYm94IHByb21wdCBhbmQgYXBwZW5kIHRoZSByZXN1bHRpbmdcbiAgICogbWFza3MgYXMgbmV3IHBvbHlnb24gcmVnaW9ucy4gUmV0dXJucyBob3cgbWFueSByZWdpb25zIHdlcmUgYWRkZWQuXG4gICAqL1xuICBhc3luYyBzZWdtZW50Qm94ZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAoIXRoaXMuaG9zdCkgcmV0dXJuIDA7XG4gICAgLy8gUmUtZW50cmFuY3kgZ3VhcmQ6IGEgc2Vjb25kIFNlZ21lbnQgcHJlc3Mgd2hpbGUgdGhlIGZpcnN0IHJ1biBpcyBzdGlsbFxuICAgIC8vIGRvd25sb2FkaW5nL2VuY29kaW5nIHdvdWxkIGxhdW5jaCBhIGNvbmN1cnJlbnQgbW9kZWwgZG93bmxvYWQgKyBHUFVcbiAgICAvLyBlbmNvZGUgKGFuZCBjYW4gZnJlZXplIHRoZSB0YWIgb24gYSBoZWF2eSBXZWJHUFUgVmlULUIpLiBJZ25vcmUgaXQuXG4gICAgaWYgKHRoaXMuYnVzeSQudmFsdWUpIHJldHVybiAwO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKTtcbiAgICBpZiAoIWNhY2hlZCB8fCBjYWNoZWQuZnJhbWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5zdGF0dXMkLm5leHQoJ05vIGltYWdlIGxvYWRlZC4nKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLmhvc3QuZ2V0UmVnaW9ucygpO1xuICAgIGNvbnN0IHJlY3RzID0gcmVnaW9ucy5maWx0ZXIoKHIpID0+IHIuYm91bmRzIGluc3RhbmNlb2YgUmVjdGFuZ2xlKTtcbiAgICBpZiAocmVjdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLnN0YXR1cyQubmV4dCgnRHJhdyBvbmUgb3IgbW9yZSByZWN0YW5nbGVzLCB0aGVuIHByZXNzIFNlZ21lbnQuJyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBjb25zdCByeCA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCByeSA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCBveCA9IGNhY2hlZC5vcmlnaW5YID8/IDA7XG4gICAgY29uc3Qgb3kgPSBjYWNoZWQub3JpZ2luWSA/PyAwO1xuXG4gICAgbGV0IHNlc3Npb246IElTYW1TZXNzaW9uO1xuICAgIHRyeSB7XG4gICAgICBzZXNzaW9uID0gYXdhaXQgdGhpcy5lbnN1cmVTZXNzaW9uKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmJ1c3kkLm5leHQoZmFsc2UpO1xuICAgICAgdGhpcy5zdGF0dXMkLm5leHQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6ICdTQU0gbW9kZWwgdW5hdmFpbGFibGUuJyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICB0aGlzLmJ1c3kkLm5leHQodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEVuY29kZSBvbmNlIHBlciBpbWFnZTsgcmV1c2UgdGhlIGVtYmVkZGluZyBhY3Jvc3MgYWxsIGJveGVzLlxuICAgICAgY29uc3Qga2V5ID0gW1xuICAgICAgICB0aGlzLmhvc3QuZ2V0RmlsZU5hbWUoKSA/PyAnJyxcbiAgICAgICAgdGhpcy5ob3N0LmdldEFjdGl2ZUZyYW1lSW5kZXgoKSxcbiAgICAgICAgYCR7Y2FjaGVkLndpZHRofXgke2NhY2hlZC5oZWlnaHR9YCxcbiAgICAgICAgYCR7b3h9LCR7b3l9LCR7cnh9YCxcbiAgICAgICAgdGhpcy5tb2RlbC5pZCxcbiAgICAgIF0uam9pbignfCcpO1xuICAgICAgaWYgKCF0aGlzLmVtYmVkZGluZyB8fCB0aGlzLmVtYmVkZGluZ0tleSAhPT0ga2V5KSB7XG4gICAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KCdFbmNvZGluZyBpbWFnZeKApicpO1xuICAgICAgICBjb25zdCByZ2JhID0gZnJhbWVUb1JnYmEoY2FjaGVkLCB0aGlzLmhvc3QuZ2V0QWN0aXZlRnJhbWVJbmRleCgpKTtcbiAgICAgICAgdGhpcy5lbWJlZGRpbmcgPSBhd2FpdCBzZXNzaW9uLmVtYmVkKHsgZGF0YTogcmdiYSwgd2lkdGg6IGNhY2hlZC53aWR0aCwgaGVpZ2h0OiBjYWNoZWQuaGVpZ2h0IH0pO1xuICAgICAgICB0aGlzLmVtYmVkZGluZ0tleSA9IGtleTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWFza3M6IFJlZ2lvbltdID0gW107XG4gICAgICBjb25zdCBjb25zdW1lZCA9IG5ldyBTZXQ8UmVnaW9uPigpOyAvLyBwcm9tcHQgcmVjdGFuZ2xlcyB0aGF0IHByb2R1Y2VkIGEgbWFza1xuICAgICAgbGV0IGFkZGVkID0gMDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVjdHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5zdGF0dXMkLm5leHQoYFNlZ21lbnRpbmcgJHtpICsgMX0vJHtyZWN0cy5sZW5ndGh94oCmYCk7XG4gICAgICAgIGNvbnN0IGIgPSByZWN0c1tpXS5ib3VuZHMgYXMgUmVjdGFuZ2xlO1xuICAgICAgICAvLyBSZWN0YW5nbGUgaXMgaW4gZGF0YSBjb29yZHMg4oaSIGNvbnZlcnQgdG8gaW1hZ2UgKG1hdHJpeCkgY29vcmRzLlxuICAgICAgICBjb25zdCBib3ggPSB7XG4gICAgICAgICAgeDA6IChiLnggLSBveCkgLyByeCxcbiAgICAgICAgICB5MDogKGIueSAtIG95KSAvIHJ5LFxuICAgICAgICAgIHgxOiAoYi54ICsgYi53aWR0aCAtIG94KSAvIHJ4LFxuICAgICAgICAgIHkxOiAoYi55ICsgYi5oZWlnaHQgLSBveSkgLyByeSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgc2Vzc2lvbi5kZWNvZGUodGhpcy5lbWJlZGRpbmcsIHsgYm94IH0pO1xuICAgICAgICBjb25zdCBwb2x5cyA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbnMoXG4gICAgICAgICAgcmVzLm1hc2ssIHJlcy53aWR0aCwgcmVzLmhlaWdodCwgY2FjaGVkLndpZHRoLCBjYWNoZWQuaGVpZ2h0LCAwLCAwLFxuICAgICAgICApO1xuICAgICAgICBpZiAocG9seXMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcbiAgICAgICAgLy8gS2VlcCB0aGUgbGFyZ2VzdCBjb25uZWN0ZWQgcGllY2UgKG1hc2tUb1BvbHlnb25zIHJldHVybnMgbGFyZ2VzdC1maXJzdCkuXG4gICAgICAgIGNvbnN0IHBvbHkgPSBwb2x5c1swXTtcbiAgICAgICAgbWFza3MucHVzaCh0aGlzLm1ha2VSZWdpb24oXG4gICAgICAgICAgcG9seS54cG9pbnRzLm1hcCgoeCkgPT4gb3ggKyB4ICogcngpLFxuICAgICAgICAgIHBvbHkueXBvaW50cy5tYXAoKHkpID0+IG95ICsgeSAqIHJ5KSxcbiAgICAgICAgICByZWN0c1tpXS5jb2xvciwgLy8gaW5oZXJpdCB0aGUgcHJvbXB0IHJlY3RhbmdsZSdzIGNvbG9yXG4gICAgICAgICkpO1xuICAgICAgICBjb25zdW1lZC5hZGQocmVjdHNbaV0pOyAvLyB0aGlzIHJlY3RhbmdsZSBpcyBub3cgcmVwcmVzZW50ZWQgYnkgaXRzIG1hc2tcbiAgICAgICAgYWRkZWQrKztcbiAgICAgIH1cblxuICAgICAgLy8gUmVwbGFjZSBlYWNoIHNlZ21lbnRlZCBwcm9tcHQgcmVjdGFuZ2xlIHdpdGggaXRzIG1hc2sgcmVnaW9uOyBrZWVwIGFueVxuICAgICAgLy8gcmVjdGFuZ2xlIHRoYXQgcHJvZHVjZWQgbm8gbWFzayAoc28gaXQgY2FuIGJlIHJldHJpZWQpICsgb3RoZXIgcmVnaW9ucy5cbiAgICAgIGNvbnN0IG91dCA9IHJlZ2lvbnMuZmlsdGVyKChyKSA9PiAhY29uc3VtZWQuaGFzKHIpKS5jb25jYXQobWFza3MpO1xuICAgICAgdGhpcy5ob3N0LnNldFJlZ2lvbnMob3V0KTtcbiAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KGFkZGVkID4gMCA/IGBBZGRlZCAke2FkZGVkfSByZWdpb24ocykuYCA6ICdObyBtYXNrcyBmb3VuZC4nKTtcbiAgICAgIHJldHVybiBhZGRlZDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuc3RhdHVzJC5uZXh0KGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAnU2VnbWVudGF0aW9uIGZhaWxlZC4nKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmJ1c3kkLm5leHQoZmFsc2UpO1xuICAgICAgdGhpcy5wcm9ncmVzcyQubmV4dCgtMSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtYWtlUmVnaW9uKHhEYXRhOiBudW1iZXJbXSwgeURhdGE6IG51bWJlcltdLCBjb2xvcj86IHN0cmluZyk6IFJlZ2lvbiB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0geERhdGEubGVuZ3RoO1xuICAgIHBvbHkueHBvaW50cyA9IHhEYXRhO1xuICAgIHBvbHkueXBvaW50cyA9IHlEYXRhO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSB4RGF0YS5tYXAoKHgsIGkpID0+IFt4LCB5RGF0YVtpXV0pO1xuICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcblxuICAgIGNvbnN0IHJlZ2lvbiA9IG5ldyBSZWdpb24oKTtcbiAgICByZWdpb24uYm91bmRzID0gcG9seTtcbiAgICAvLyBJbmhlcml0IHRoZSBzb3VyY2UgcHJvbXB0IHJlY3RhbmdsZSdzIGNvbG9yOyBmYWxsIGJhY2sgdG8gdGhlIGhvc3QgZGVmYXVsdC5cbiAgICByZWdpb24uY29sb3IgPSBjb2xvciB8fCB0aGlzLmhvc3QuZ2V0U2hhcGVDb2xvcigpO1xuICAgIC8vIERlZmF1bHQgY2xhc3MvYW5ub3RhdGlvbiBuYW1lLCBtYXRjaGluZyB0aGUgd2FuZC9icnVzaCArIG92ZXJsYXktZHJhd24gcmVnaW9ucy5cbiAgICByZWdpb24ubGFiZWwgPSAnc2FtJztcbiAgICByZXR1cm4gcmVnaW9uO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVTZXNzaW9uKCk6IFByb21pc2U8SVNhbVNlc3Npb24+IHtcbiAgICBpZiAodGhpcy5zZXNzaW9uKSByZXR1cm4gdGhpcy5zZXNzaW9uO1xuICAgIGlmICghaXNTYW1Nb2RlbFJlYWR5KHRoaXMubW9kZWwpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBTQU0gbW9kZWwgXCIke3RoaXMubW9kZWwuaWR9XCIgaXMgbm90IGNvbmZpZ3VyZWQgeWV0IChubyBPTk5YIFVSTHMpLiBgICtcbiAgICAgICAgJ0hvc3QgaXQgYW5kIGNhbGwgc2V0U2FtTW9kZWxVcmxzKCksIHRoZW4gcmV0cnkuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIExhenktaW1wb3J0IHNvIG9ubnhydW50aW1lLXdlYiBpcyBuZXZlciBwdWxsZWQgaW50byB1bml0IHRlc3RzIC8gdGhlXG4gICAgLy8gaW5pdGlhbCBidW5kbGUg4oCUIG9ubHkgd2hlbiBzZWdtZW50YXRpb24gYWN0dWFsbHkgcnVucy5cbiAgICBjb25zdCB7IE9ubnhTYW1TZXNzaW9uIH0gPSBhd2FpdCBpbXBvcnQoJy4vb25ueC1zYW0tc2Vzc2lvbicpO1xuICAgIGNvbnN0IHNlc3Npb24gPSBuZXcgT25ueFNhbVNlc3Npb24oKTtcbiAgICB0aGlzLnByb2dyZXNzJC5uZXh0KDApO1xuICAgIGF3YWl0IHNlc3Npb24ubG9hZE1vZGVsKHRoaXMubW9kZWwsIChmKSA9PiB0aGlzLnByb2dyZXNzJC5uZXh0KGYpKTtcbiAgICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICAgIHJldHVybiBzZXNzaW9uO1xuICB9XG59XG4iXX0=