@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,99 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { HttpClient } from '@angular/common/http';
3
+ import { firstValueFrom } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/common/http";
6
+ /**
7
+ * Shared access to a "simple" (`IImageInfo.tiled === false`) stack — a
8
+ * self-contained per-slice-URL image, as opposed to one server-tiled file
9
+ * with an internal z dimension (the tile-pyramid case each backend already
10
+ * handles on its own, since the tiling protocol itself IS backend-specific).
11
+ * A numbered image series assembled client-side from separate files (the
12
+ * jit-ui folder-stack feature) is the current producer of this shape.
13
+ *
14
+ * Every backend that can render a 2D image (OSD, napari-js) needs the exact
15
+ * same three things for this case — detect it, resolve `urls[z]`, and fetch
16
+ * that URL with the app's auth applied — so they live here once instead of
17
+ * being reimplemented per backend. Plotly needs no equivalent: its `load()`
18
+ * already fetches `urls[i]` generically for every plot type, with no
19
+ * tile-server concept to route around.
20
+ *
21
+ * Fetches go through Angular's `HttpClient` so the app's auth interceptor
22
+ * (Bearer token) applies — a raw `fetch()`/`<img src>` bypasses it and, behind
23
+ * an OAuth2-proxied deployment, gets redirected to the login page and then
24
+ * CORS-fails. Mirrors `PlotlyService.loadImage`, the reference
25
+ * implementation this generalizes for the other backends.
26
+ */
27
+ export class SimpleSliceAccessService {
28
+ constructor(http) {
29
+ this.http = http;
30
+ /** raw slice URL → already-fetched blob: URL, so a backend that opens a
31
+ * URL (OSD) doesn't repeat the auth round-trip revisiting a slice (scrub
32
+ * back, the small→large tier re-fetch). Shared across backends: switching
33
+ * plot types on the same file (e.g. Image → Volume) reuses entries. */
34
+ this.blobUrls = new Map();
35
+ }
36
+ /** True when `imageInfo` is a self-contained per-slice-URL stack with no
37
+ * server tile pyramid to route to. */
38
+ isSimple(imageInfo) {
39
+ return imageInfo?.tiled === false;
40
+ }
41
+ /** The URL for slice `z` of a simple stack (falls back to slice 0 if `z`
42
+ * is out of range or unset). */
43
+ urlFor(imageInfo, z) {
44
+ return imageInfo.urls?.[z] ?? imageInfo.urls?.[0];
45
+ }
46
+ /** Call once per backend `load()` so the blob cache is evicted when a
47
+ * genuinely different file is selected — not on every phase/z-scrub of
48
+ * the SAME file, and not wrongly evicted by a second backend loading the
49
+ * same file for a different plot type. */
50
+ noteActiveFile(fileName) {
51
+ if (fileName && this.currentFileName && fileName !== this.currentFileName) {
52
+ this.revokeAll();
53
+ }
54
+ this.currentFileName = fileName;
55
+ }
56
+ /** Fetch a slice's own URL and hand back a blob: URL — for backends (OSD)
57
+ * that open a URL rather than decode bytes directly. A true in-memory
58
+ * blob:/data: URL (the processing-pipeline's original tiled:false use
59
+ * case) is already self-contained and returned as-is, no fetch/cache. */
60
+ async fetchAsBlobUrl(rawUrl) {
61
+ if (rawUrl.startsWith('blob:') || rawUrl.startsWith('data:'))
62
+ return rawUrl;
63
+ const cached = this.blobUrls.get(rawUrl);
64
+ if (cached)
65
+ return cached;
66
+ const blob = await firstValueFrom(this.http.get(rawUrl, { responseType: 'blob' }));
67
+ const blobUrl = URL.createObjectURL(blob);
68
+ this.blobUrls.set(rawUrl, blobUrl);
69
+ return blobUrl;
70
+ }
71
+ /** Fetch a slice's own URL and decode it as an `ImageBitmap` — for
72
+ * backends (napari-js) that upload pixels directly rather than opening a
73
+ * URL. Not cached (ImageBitmaps are consumed once and closed by the
74
+ * caller); the underlying HTTP response may still hit the browser cache.
75
+ *
76
+ * A self-contained blob:/data: URL (e.g. the processing-pipeline's
77
+ * in-memory preview, which also emits `tiled:false`) needs no auth and
78
+ * isn't a server URL to route through the interceptor — read it directly
79
+ * via the browser. Only real server URLs go through HttpClient so the auth
80
+ * interceptor applies. Mirrors {@link fetchAsBlobUrl}'s blob:/data: branch. */
81
+ async fetchAsBitmap(rawUrl) {
82
+ const blob = rawUrl.startsWith('blob:') || rawUrl.startsWith('data:')
83
+ ? await (await fetch(rawUrl)).blob()
84
+ : await firstValueFrom(this.http.get(rawUrl, { responseType: 'blob' }));
85
+ return createImageBitmap(blob);
86
+ }
87
+ revokeAll() {
88
+ for (const url of this.blobUrls.values())
89
+ URL.revokeObjectURL(url);
90
+ this.blobUrls.clear();
91
+ }
92
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SimpleSliceAccessService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
93
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SimpleSliceAccessService, providedIn: 'root' }); }
94
+ }
95
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SimpleSliceAccessService, decorators: [{
96
+ type: Injectable,
97
+ args: [{ providedIn: 'root' }]
98
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
99
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltcGxlLXNsaWNlLWFjY2Vzcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvc2ltcGxlLXNsaWNlLWFjY2Vzcy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxNQUFNLENBQUM7OztBQUl0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFFSCxNQUFNLE9BQU8sd0JBQXdCO0lBUW5DLFlBQW9CLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7UUFQcEM7OztnRkFHd0U7UUFDdkQsYUFBUSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBR2YsQ0FBQztJQUV4QzsyQ0FDdUM7SUFDdkMsUUFBUSxDQUFDLFNBQXdDO1FBQy9DLE9BQU8sU0FBUyxFQUFFLEtBQUssS0FBSyxLQUFLLENBQUM7SUFDcEMsQ0FBQztJQUVEO3FDQUNpQztJQUNqQyxNQUFNLENBQUMsU0FBcUIsRUFBRSxDQUFTO1FBQ3JDLE9BQU8sU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7OzsrQ0FHMkM7SUFDM0MsY0FBYyxDQUFDLFFBQTRCO1FBQ3pDLElBQUksUUFBUSxJQUFJLElBQUksQ0FBQyxlQUFlLElBQUksUUFBUSxLQUFLLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMxRSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsQ0FBQztRQUNELElBQUksQ0FBQyxlQUFlLEdBQUcsUUFBUSxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7OzhFQUcwRTtJQUMxRSxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQWM7UUFDakMsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFDNUUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDekMsSUFBSSxNQUFNO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFDMUIsTUFBTSxJQUFJLEdBQUcsTUFBTSxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNuRixNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNuQyxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQ7Ozs7Ozs7OztvRkFTZ0Y7SUFDaEYsS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFjO1FBQ2hDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7WUFDbkUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRTtZQUNwQyxDQUFDLENBQUMsTUFBTSxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMxRSxPQUFPLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFTyxTQUFTO1FBQ2YsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRTtZQUFFLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixDQUFDOzhHQW5FVSx3QkFBd0I7a0hBQXhCLHdCQUF3QixjQURYLE1BQU07OzJGQUNuQix3QkFBd0I7a0JBRHBDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IGZpcnN0VmFsdWVGcm9tIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IElJbWFnZUluZm8gfSBmcm9tICcuLi9jb250cmFjdHMvaW1hZ2UuY29udHJhY3QnO1xuXG4vKipcbiAqIFNoYXJlZCBhY2Nlc3MgdG8gYSBcInNpbXBsZVwiIChgSUltYWdlSW5mby50aWxlZCA9PT0gZmFsc2VgKSBzdGFjayDigJQgYVxuICogc2VsZi1jb250YWluZWQgcGVyLXNsaWNlLVVSTCBpbWFnZSwgYXMgb3Bwb3NlZCB0byBvbmUgc2VydmVyLXRpbGVkIGZpbGVcbiAqIHdpdGggYW4gaW50ZXJuYWwgeiBkaW1lbnNpb24gKHRoZSB0aWxlLXB5cmFtaWQgY2FzZSBlYWNoIGJhY2tlbmQgYWxyZWFkeVxuICogaGFuZGxlcyBvbiBpdHMgb3duLCBzaW5jZSB0aGUgdGlsaW5nIHByb3RvY29sIGl0c2VsZiBJUyBiYWNrZW5kLXNwZWNpZmljKS5cbiAqIEEgbnVtYmVyZWQgaW1hZ2Ugc2VyaWVzIGFzc2VtYmxlZCBjbGllbnQtc2lkZSBmcm9tIHNlcGFyYXRlIGZpbGVzICh0aGVcbiAqIGppdC11aSBmb2xkZXItc3RhY2sgZmVhdHVyZSkgaXMgdGhlIGN1cnJlbnQgcHJvZHVjZXIgb2YgdGhpcyBzaGFwZS5cbiAqXG4gKiBFdmVyeSBiYWNrZW5kIHRoYXQgY2FuIHJlbmRlciBhIDJEIGltYWdlIChPU0QsIG5hcGFyaS1qcykgbmVlZHMgdGhlIGV4YWN0XG4gKiBzYW1lIHRocmVlIHRoaW5ncyBmb3IgdGhpcyBjYXNlIOKAlCBkZXRlY3QgaXQsIHJlc29sdmUgYHVybHNbel1gLCBhbmQgZmV0Y2hcbiAqIHRoYXQgVVJMIHdpdGggdGhlIGFwcCdzIGF1dGggYXBwbGllZCDigJQgc28gdGhleSBsaXZlIGhlcmUgb25jZSBpbnN0ZWFkIG9mXG4gKiBiZWluZyByZWltcGxlbWVudGVkIHBlciBiYWNrZW5kLiBQbG90bHkgbmVlZHMgbm8gZXF1aXZhbGVudDogaXRzIGBsb2FkKClgXG4gKiBhbHJlYWR5IGZldGNoZXMgYHVybHNbaV1gIGdlbmVyaWNhbGx5IGZvciBldmVyeSBwbG90IHR5cGUsIHdpdGggbm9cbiAqIHRpbGUtc2VydmVyIGNvbmNlcHQgdG8gcm91dGUgYXJvdW5kLlxuICpcbiAqIEZldGNoZXMgZ28gdGhyb3VnaCBBbmd1bGFyJ3MgYEh0dHBDbGllbnRgIHNvIHRoZSBhcHAncyBhdXRoIGludGVyY2VwdG9yXG4gKiAoQmVhcmVyIHRva2VuKSBhcHBsaWVzIOKAlCBhIHJhdyBgZmV0Y2goKWAvYDxpbWcgc3JjPmAgYnlwYXNzZXMgaXQgYW5kLCBiZWhpbmRcbiAqIGFuIE9BdXRoMi1wcm94aWVkIGRlcGxveW1lbnQsIGdldHMgcmVkaXJlY3RlZCB0byB0aGUgbG9naW4gcGFnZSBhbmQgdGhlblxuICogQ09SUy1mYWlscy4gTWlycm9ycyBgUGxvdGx5U2VydmljZS5sb2FkSW1hZ2VgLCB0aGUgcmVmZXJlbmNlXG4gKiBpbXBsZW1lbnRhdGlvbiB0aGlzIGdlbmVyYWxpemVzIGZvciB0aGUgb3RoZXIgYmFja2VuZHMuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgU2ltcGxlU2xpY2VBY2Nlc3NTZXJ2aWNlIHtcbiAgLyoqIHJhdyBzbGljZSBVUkwg4oaSIGFscmVhZHktZmV0Y2hlZCBibG9iOiBVUkwsIHNvIGEgYmFja2VuZCB0aGF0IG9wZW5zIGFcbiAgICogIFVSTCAoT1NEKSBkb2Vzbid0IHJlcGVhdCB0aGUgYXV0aCByb3VuZC10cmlwIHJldmlzaXRpbmcgYSBzbGljZSAoc2NydWJcbiAgICogIGJhY2ssIHRoZSBzbWFsbOKGkmxhcmdlIHRpZXIgcmUtZmV0Y2gpLiBTaGFyZWQgYWNyb3NzIGJhY2tlbmRzOiBzd2l0Y2hpbmdcbiAgICogIHBsb3QgdHlwZXMgb24gdGhlIHNhbWUgZmlsZSAoZS5nLiBJbWFnZSDihpIgVm9sdW1lKSByZXVzZXMgZW50cmllcy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBibG9iVXJscyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gIHByaXZhdGUgY3VycmVudEZpbGVOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50KSB7fVxuXG4gIC8qKiBUcnVlIHdoZW4gYGltYWdlSW5mb2AgaXMgYSBzZWxmLWNvbnRhaW5lZCBwZXItc2xpY2UtVVJMIHN0YWNrIHdpdGggbm9cbiAgICogIHNlcnZlciB0aWxlIHB5cmFtaWQgdG8gcm91dGUgdG8uICovXG4gIGlzU2ltcGxlKGltYWdlSW5mbzogSUltYWdlSW5mbyB8IG51bGwgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaW1hZ2VJbmZvPy50aWxlZCA9PT0gZmFsc2U7XG4gIH1cblxuICAvKiogVGhlIFVSTCBmb3Igc2xpY2UgYHpgIG9mIGEgc2ltcGxlIHN0YWNrIChmYWxscyBiYWNrIHRvIHNsaWNlIDAgaWYgYHpgXG4gICAqICBpcyBvdXQgb2YgcmFuZ2Ugb3IgdW5zZXQpLiAqL1xuICB1cmxGb3IoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6OiBudW1iZXIpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBpbWFnZUluZm8udXJscz8uW3pdID8/IGltYWdlSW5mby51cmxzPy5bMF07XG4gIH1cblxuICAvKiogQ2FsbCBvbmNlIHBlciBiYWNrZW5kIGBsb2FkKClgIHNvIHRoZSBibG9iIGNhY2hlIGlzIGV2aWN0ZWQgd2hlbiBhXG4gICAqICBnZW51aW5lbHkgZGlmZmVyZW50IGZpbGUgaXMgc2VsZWN0ZWQg4oCUIG5vdCBvbiBldmVyeSBwaGFzZS96LXNjcnViIG9mXG4gICAqICB0aGUgU0FNRSBmaWxlLCBhbmQgbm90IHdyb25nbHkgZXZpY3RlZCBieSBhIHNlY29uZCBiYWNrZW5kIGxvYWRpbmcgdGhlXG4gICAqICBzYW1lIGZpbGUgZm9yIGEgZGlmZmVyZW50IHBsb3QgdHlwZS4gKi9cbiAgbm90ZUFjdGl2ZUZpbGUoZmlsZU5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmIChmaWxlTmFtZSAmJiB0aGlzLmN1cnJlbnRGaWxlTmFtZSAmJiBmaWxlTmFtZSAhPT0gdGhpcy5jdXJyZW50RmlsZU5hbWUpIHtcbiAgICAgIHRoaXMucmV2b2tlQWxsKCk7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudEZpbGVOYW1lID0gZmlsZU5hbWU7XG4gIH1cblxuICAvKiogRmV0Y2ggYSBzbGljZSdzIG93biBVUkwgYW5kIGhhbmQgYmFjayBhIGJsb2I6IFVSTCDigJQgZm9yIGJhY2tlbmRzIChPU0QpXG4gICAqICB0aGF0IG9wZW4gYSBVUkwgcmF0aGVyIHRoYW4gZGVjb2RlIGJ5dGVzIGRpcmVjdGx5LiBBIHRydWUgaW4tbWVtb3J5XG4gICAqICBibG9iOi9kYXRhOiBVUkwgKHRoZSBwcm9jZXNzaW5nLXBpcGVsaW5lJ3Mgb3JpZ2luYWwgdGlsZWQ6ZmFsc2UgdXNlXG4gICAqICBjYXNlKSBpcyBhbHJlYWR5IHNlbGYtY29udGFpbmVkIGFuZCByZXR1cm5lZCBhcy1pcywgbm8gZmV0Y2gvY2FjaGUuICovXG4gIGFzeW5jIGZldGNoQXNCbG9iVXJsKHJhd1VybDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAocmF3VXJsLnN0YXJ0c1dpdGgoJ2Jsb2I6JykgfHwgcmF3VXJsLnN0YXJ0c1dpdGgoJ2RhdGE6JykpIHJldHVybiByYXdVcmw7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5ibG9iVXJscy5nZXQocmF3VXJsKTtcbiAgICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuICAgIGNvbnN0IGJsb2IgPSBhd2FpdCBmaXJzdFZhbHVlRnJvbSh0aGlzLmh0dHAuZ2V0KHJhd1VybCwgeyByZXNwb25zZVR5cGU6ICdibG9iJyB9KSk7XG4gICAgY29uc3QgYmxvYlVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYik7XG4gICAgdGhpcy5ibG9iVXJscy5zZXQocmF3VXJsLCBibG9iVXJsKTtcbiAgICByZXR1cm4gYmxvYlVybDtcbiAgfVxuXG4gIC8qKiBGZXRjaCBhIHNsaWNlJ3Mgb3duIFVSTCBhbmQgZGVjb2RlIGl0IGFzIGFuIGBJbWFnZUJpdG1hcGAg4oCUIGZvclxuICAgKiAgYmFja2VuZHMgKG5hcGFyaS1qcykgdGhhdCB1cGxvYWQgcGl4ZWxzIGRpcmVjdGx5IHJhdGhlciB0aGFuIG9wZW5pbmcgYVxuICAgKiAgVVJMLiBOb3QgY2FjaGVkIChJbWFnZUJpdG1hcHMgYXJlIGNvbnN1bWVkIG9uY2UgYW5kIGNsb3NlZCBieSB0aGVcbiAgICogIGNhbGxlcik7IHRoZSB1bmRlcmx5aW5nIEhUVFAgcmVzcG9uc2UgbWF5IHN0aWxsIGhpdCB0aGUgYnJvd3NlciBjYWNoZS5cbiAgICpcbiAgICogIEEgc2VsZi1jb250YWluZWQgYmxvYjovZGF0YTogVVJMIChlLmcuIHRoZSBwcm9jZXNzaW5nLXBpcGVsaW5lJ3NcbiAgICogIGluLW1lbW9yeSBwcmV2aWV3LCB3aGljaCBhbHNvIGVtaXRzIGB0aWxlZDpmYWxzZWApIG5lZWRzIG5vIGF1dGggYW5kXG4gICAqICBpc24ndCBhIHNlcnZlciBVUkwgdG8gcm91dGUgdGhyb3VnaCB0aGUgaW50ZXJjZXB0b3Ig4oCUIHJlYWQgaXQgZGlyZWN0bHlcbiAgICogIHZpYSB0aGUgYnJvd3Nlci4gT25seSByZWFsIHNlcnZlciBVUkxzIGdvIHRocm91Z2ggSHR0cENsaWVudCBzbyB0aGUgYXV0aFxuICAgKiAgaW50ZXJjZXB0b3IgYXBwbGllcy4gTWlycm9ycyB7QGxpbmsgZmV0Y2hBc0Jsb2JVcmx9J3MgYmxvYjovZGF0YTogYnJhbmNoLiAqL1xuICBhc3luYyBmZXRjaEFzQml0bWFwKHJhd1VybDogc3RyaW5nKTogUHJvbWlzZTxJbWFnZUJpdG1hcD4ge1xuICAgIGNvbnN0IGJsb2IgPSByYXdVcmwuc3RhcnRzV2l0aCgnYmxvYjonKSB8fCByYXdVcmwuc3RhcnRzV2l0aCgnZGF0YTonKVxuICAgICAgPyBhd2FpdCAoYXdhaXQgZmV0Y2gocmF3VXJsKSkuYmxvYigpXG4gICAgICA6IGF3YWl0IGZpcnN0VmFsdWVGcm9tKHRoaXMuaHR0cC5nZXQocmF3VXJsLCB7IHJlc3BvbnNlVHlwZTogJ2Jsb2InIH0pKTtcbiAgICByZXR1cm4gY3JlYXRlSW1hZ2VCaXRtYXAoYmxvYik7XG4gIH1cblxuICBwcml2YXRlIHJldm9rZUFsbCgpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IHVybCBvZiB0aGlzLmJsb2JVcmxzLnZhbHVlcygpKSBVUkwucmV2b2tlT2JqZWN0VVJMKHVybCk7XG4gICAgdGhpcy5ibG9iVXJscy5jbGVhcigpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Bezier-curve helpers (no external dependency).
3
+ *
4
+ * JIT supports true bezier regions: a polygon's vertices are the editable
5
+ * *anchors*, and the smooth curve through them is derived here with the
6
+ * Catmull-Rom construction — the same algorithm paper.js uses in
7
+ * `path.smooth()`. The curve interpolates every anchor and
8
+ * each anchor's two handles are colinear (a smooth tangent).
9
+ *
10
+ * The OSD overlay renders the curve as a true cubic SVG path + draggable handles
11
+ * (see {@link bezierAnchorHandles}); GeoJSON export flattens the *same* cubics
12
+ * into a dense point list (see {@link bezierCurve}) so a viewer without bezier
13
+ * support (e.g. QuPath, which just draws the coordinate list) still shows the
14
+ * smooth shape. Using one algorithm for both keeps what JIT draws identical to
15
+ * what it exports.
16
+ *
17
+ * Pure functions: no DOM, no service state. Coordinates are image pixels.
18
+ */
19
+ /** How many points to sample per cubic segment when flattening for export. */
20
+ const SAMPLES_PER_SEGMENT = 16;
21
+ /**
22
+ * Per-anchor cubic-bezier control points using the Catmull-Rom construction
23
+ * (tension 1: control = anchor ± (next − prev) / 6). Matches paper.js
24
+ * `path.smooth()`: the resulting cubic interpolates every anchor and the two
25
+ * handles of each anchor are colinear. Coordinates are in the input space.
26
+ */
27
+ export function bezierAnchorHandles(xs, ys, closed) {
28
+ const n = Math.min(xs.length, ys.length);
29
+ const out = [];
30
+ for (let i = 0; i < n; i++) {
31
+ const prev = closed ? (i - 1 + n) % n : Math.max(0, i - 1);
32
+ const next = closed ? (i + 1) % n : Math.min(n - 1, i + 1);
33
+ const tx = (xs[next] - xs[prev]) / 6;
34
+ const ty = (ys[next] - ys[prev]) / 6;
35
+ out.push({
36
+ out: [xs[i] + tx, ys[i] + ty],
37
+ in: [xs[i] - tx, ys[i] - ty],
38
+ hasOut: closed || i < n - 1,
39
+ hasIn: closed || i > 0,
40
+ });
41
+ }
42
+ return out;
43
+ }
44
+ /** The Catmull-Rom handles as **relative** offsets `[dx, dy]` per anchor — used
45
+ * to initialise a region's editable handles when bezier is turned on. */
46
+ export function defaultHandleOffsets(xs, ys, closed) {
47
+ const h = bezierAnchorHandles(xs, ys, closed);
48
+ return {
49
+ in: h.map((a, i) => [a.in[0] - xs[i], a.in[1] - ys[i]]),
50
+ out: h.map((a, i) => [a.out[0] - xs[i], a.out[1] - ys[i]]),
51
+ };
52
+ }
53
+ /** Absolute handles from stored relative offsets (anchor + offset). */
54
+ export function handlesFromOffsets(xs, ys, inOff, outOff, closed) {
55
+ const n = Math.min(xs.length, ys.length);
56
+ const out = [];
57
+ for (let i = 0; i < n; i++) {
58
+ out.push({
59
+ in: [xs[i] + (inOff[i]?.[0] ?? 0), ys[i] + (inOff[i]?.[1] ?? 0)],
60
+ out: [xs[i] + (outOff[i]?.[0] ?? 0), ys[i] + (outOff[i]?.[1] ?? 0)],
61
+ hasOut: closed || i < n - 1,
62
+ hasIn: closed || i > 0,
63
+ });
64
+ }
65
+ return out;
66
+ }
67
+ /** A region's handles: from its stored (editable) offsets when present, else the
68
+ * Catmull-Rom default. The single source of truth for both rendering and export. */
69
+ export function resolveHandles(xs, ys, closed, inOff, outOff) {
70
+ if (inOff && outOff && inOff.length === xs.length && outOff.length === xs.length) {
71
+ return handlesFromOffsets(xs, ys, inOff, outOff, closed);
72
+ }
73
+ return bezierAnchorHandles(xs, ys, closed);
74
+ }
75
+ /**
76
+ * Flatten a cubic bezier (defined by explicit per-anchor handles) into a dense
77
+ * point list by sampling each segment. The curve passes through every anchor; a
78
+ * closed ring returns to its first point.
79
+ */
80
+ export function bezierCurveFromHandles(xs, ys, handles, closed) {
81
+ const n = Math.min(xs.length, ys.length);
82
+ if (n < 3)
83
+ return { xs: xs.slice(), ys: ys.slice() };
84
+ const outX = [];
85
+ const outY = [];
86
+ const segs = closed ? n : n - 1;
87
+ for (let i = 0; i < segs; i++) {
88
+ const j = (i + 1) % n;
89
+ const p0x = xs[i], p0y = ys[i];
90
+ const c1 = handles[i].out, c2 = handles[j].in;
91
+ const p3x = xs[j], p3y = ys[j];
92
+ for (let s = 0; s < SAMPLES_PER_SEGMENT; s++) {
93
+ const t = s / SAMPLES_PER_SEGMENT;
94
+ const u = 1 - t;
95
+ const w0 = u * u * u, w1 = 3 * u * u * t, w2 = 3 * u * t * t, w3 = t * t * t;
96
+ outX.push(w0 * p0x + w1 * c1[0] + w2 * c2[0] + w3 * p3x);
97
+ outY.push(w0 * p0y + w1 * c1[1] + w2 * c2[1] + w3 * p3y);
98
+ }
99
+ }
100
+ if (closed) {
101
+ outX.push(xs[0]);
102
+ outY.push(ys[0]);
103
+ }
104
+ else {
105
+ outX.push(xs[n - 1]);
106
+ outY.push(ys[n - 1]);
107
+ }
108
+ return { xs: outX, ys: outY };
109
+ }
110
+ /**
111
+ * Flatten the smooth Catmull-Rom bezier through the anchors (no custom handles).
112
+ * Falls back to the anchors when there are too few to form a curve.
113
+ */
114
+ export function bezierCurve(xs, ys, closed) {
115
+ const n = Math.min(xs.length, ys.length);
116
+ if (n < 3)
117
+ return { xs: xs.slice(), ys: ys.slice() };
118
+ return bezierCurveFromHandles(xs, ys, bezierAnchorHandles(xs, ys, closed), closed);
119
+ }
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmV6aWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tb2RlbHMvYmV6aWVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQWdCSCw4RUFBOEU7QUFDOUUsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7QUFFL0I7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQUMsRUFBWSxFQUFFLEVBQVksRUFBRSxNQUFlO0lBQzdFLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDekMsTUFBTSxHQUFHLEdBQW1CLEVBQUUsQ0FBQztJQUMvQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDM0IsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0QsTUFBTSxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUks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LEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3RCLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9CLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDOUMsTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDL0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLG1CQUFtQixFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDN0MsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLG1CQUFtQixDQUFDO1lBQ2xDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDaEIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3RSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxHQUFHLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUMsQ0FBQztZQUN6RCxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxHQUFHLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUMsQ0FBQztRQUMzRCxDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksTUFBTSxFQUFFLENBQUM7UUFDWCxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyQyxDQUFDO1NBQU0sQ0FBQztRQUNOLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUNELE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQztBQUNoQyxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FBQyxFQUFZLEVBQUUsRUFBWSxFQUFFLE1BQWU7SUFDckUsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6QyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQ3JELE9BQU8sc0JBQXNCLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxtQkFBbUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ3JGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJlemllci1jdXJ2ZSBoZWxwZXJzIChubyBleHRlcm5hbCBkZXBlbmRlbmN5KS5cbiAqXG4gKiBKSVQgc3VwcG9ydHMgdHJ1ZSBiZXppZXIgcmVnaW9uczogYSBwb2x5Z29uJ3MgdmVydGljZXMgYXJlIHRoZSBlZGl0YWJsZVxuICogKmFuY2hvcnMqLCBhbmQgdGhlIHNtb290aCBjdXJ2ZSB0aHJvdWdoIHRoZW0gaXMgZGVyaXZlZCBoZXJlIHdpdGggdGhlXG4gKiBDYXRtdWxsLVJvbSBjb25zdHJ1Y3Rpb24g4oCUIHRoZSBzYW1lIGFsZ29yaXRobSBwYXBlci5qcyB1c2VzIGluXG4gKiBgcGF0aC5zbW9vdGgoKWAuIFRoZSBjdXJ2ZSBpbnRlcnBvbGF0ZXMgZXZlcnkgYW5jaG9yIGFuZFxuICogZWFjaCBhbmNob3IncyB0d28gaGFuZGxlcyBhcmUgY29saW5lYXIgKGEgc21vb3RoIHRhbmdlbnQpLlxuICpcbiAqIFRoZSBPU0Qgb3ZlcmxheSByZW5kZXJzIHRoZSBjdXJ2ZSBhcyBhIHRydWUgY3ViaWMgU1ZHIHBhdGggKyBkcmFnZ2FibGUgaGFuZGxlc1xuICogKHNlZSB7QGxpbmsgYmV6aWVyQW5jaG9ySGFuZGxlc30pOyBHZW9KU09OIGV4cG9ydCBmbGF0dGVucyB0aGUgKnNhbWUqIGN1Ymljc1xuICogaW50byBhIGRlbnNlIHBvaW50IGxpc3QgKHNlZSB7QGxpbmsgYmV6aWVyQ3VydmV9KSBzbyBhIHZpZXdlciB3aXRob3V0IGJlemllclxuICogc3VwcG9ydCAoZS5nLiBRdVBhdGgsIHdoaWNoIGp1c3QgZHJhd3MgdGhlIGNvb3JkaW5hdGUgbGlzdCkgc3RpbGwgc2hvd3MgdGhlXG4gKiBzbW9vdGggc2hhcGUuIFVzaW5nIG9uZSBhbGdvcml0aG0gZm9yIGJvdGgga2VlcHMgd2hhdCBKSVQgZHJhd3MgaWRlbnRpY2FsIHRvXG4gKiB3aGF0IGl0IGV4cG9ydHMuXG4gKlxuICogUHVyZSBmdW5jdGlvbnM6IG5vIERPTSwgbm8gc2VydmljZSBzdGF0ZS4gQ29vcmRpbmF0ZXMgYXJlIGltYWdlIHBpeGVscy5cbiAqL1xuXG5leHBvcnQgaW50ZXJmYWNlIEN1cnZlUG9pbnRzIHtcbiAgeHM6IG51bWJlcltdO1xuICB5czogbnVtYmVyW107XG59XG5cbi8qKiBBIHZlcnRleCdzIHR3byBjdWJpYy1iZXppZXIgY29udHJvbCBwb2ludHMgKGFic29sdXRlIGNvb3JkcykgcGx1cyB3aGV0aGVyXG4gKiAgZWFjaCBzaWRlIGhhcyBhIGhhbmRsZSAob3Blbi1wYXRoIGVuZHBvaW50cyBoYXZlIG9ubHkgb25lKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQW5jaG9ySGFuZGxlIHtcbiAgaW46IFtudW1iZXIsIG51bWJlcl07XG4gIG91dDogW251bWJlciwgbnVtYmVyXTtcbiAgaGFzSW46IGJvb2xlYW47XG4gIGhhc091dDogYm9vbGVhbjtcbn1cblxuLyoqIEhvdyBtYW55IHBvaW50cyB0byBzYW1wbGUgcGVyIGN1YmljIHNlZ21lbnQgd2hlbiBmbGF0dGVuaW5nIGZvciBleHBvcnQuICovXG5jb25zdCBTQU1QTEVTX1BFUl9TRUdNRU5UID0gMTY7XG5cbi8qKlxuICogUGVyLWFuY2hvciBjdWJpYy1iZXppZXIgY29udHJvbCBwb2ludHMgdXNpbmcgdGhlIENhdG11bGwtUm9tIGNvbnN0cnVjdGlvblxuICogKHRlbnNpb24gMTogY29udHJvbCA9IGFuY2hvciDCsSAobmV4dCDiiJIgcHJldikgLyA2KS4gTWF0Y2hlcyBwYXBlci5qc1xuICogYHBhdGguc21vb3RoKClgOiB0aGUgcmVzdWx0aW5nIGN1YmljIGludGVycG9sYXRlcyBldmVyeSBhbmNob3IgYW5kIHRoZSB0d29cbiAqIGhhbmRsZXMgb2YgZWFjaCBhbmNob3IgYXJlIGNvbGluZWFyLiBDb29yZGluYXRlcyBhcmUgaW4gdGhlIGlucHV0IHNwYWNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYmV6aWVyQW5jaG9ySGFuZGxlcyh4czogbnVtYmVyW10sIHlzOiBudW1iZXJbXSwgY2xvc2VkOiBib29sZWFuKTogQW5jaG9ySGFuZGxlW10ge1xuICBjb25zdCBuID0gTWF0aC5taW4oeHMubGVuZ3RoLCB5cy5sZW5ndGgpO1xuICBjb25zdCBvdXQ6IEFuY2hvckhhbmRsZVtdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgY29uc3QgcHJldiA9IGNsb3NlZCA/IChpIC0gMSArIG4pICUgbiA6IE1hdGgubWF4KDAsIGkgLSAxKTtcbiAgICBjb25zdCBuZXh0ID0gY2xvc2VkID8gKGkgKyAxKSAlIG4gOiBNYXRoLm1pbihuIC0gMSwgaSArIDEpO1xuICAgIGNvbnN0IHR4ID0gKHhzW25leHRdIC0geHNbcHJldl0pIC8gNjtcbiAgICBjb25zdCB0eSA9ICh5c1tuZXh0XSAtIHlzW3ByZXZdKSAvIDY7XG4gICAgb3V0LnB1c2goe1xuICAgICAgb3V0OiBbeHNbaV0gKyB0eCwgeXNbaV0gKyB0eV0sXG4gICAgICBpbjogW3hzW2ldIC0gdHgsIHlzW2ldIC0gdHldLFxuICAgICAgaGFzT3V0OiBjbG9zZWQgfHwgaSA8IG4gLSAxLFxuICAgICAgaGFzSW46IGNsb3NlZCB8fCBpID4gMCxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKiogVGhlIENhdG11bGwtUm9tIGhhbmRsZXMgYXMgKipyZWxhdGl2ZSoqIG9mZnNldHMgYFtkeCwgZHldYCBwZXIgYW5jaG9yIOKAlCB1c2VkXG4gKiAgdG8gaW5pdGlhbGlzZSBhIHJlZ2lvbidzIGVkaXRhYmxlIGhhbmRsZXMgd2hlbiBiZXppZXIgaXMgdHVybmVkIG9uLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlZmF1bHRIYW5kbGVPZmZzZXRzKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLCBjbG9zZWQ6IGJvb2xlYW4pOlxuICB7IGluOiBudW1iZXJbXVtdOyBvdXQ6IG51bWJlcltdW10gfSB7XG4gIGNvbnN0IGggPSBiZXppZXJBbmNob3JIYW5kbGVzKHhzLCB5cywgY2xvc2VkKTtcbiAgcmV0dXJuIHtcbiAgICBpbjogaC5tYXAoKGEsIGkpID0+IFthLmluWzBdIC0geHNbaV0sIGEuaW5bMV0gLSB5c1tpXV0pLFxuICAgIG91dDogaC5tYXAoKGEsIGkpID0+IFthLm91dFswXSAtIHhzW2ldLCBhLm91dFsxXSAtIHlzW2ldXSksXG4gIH07XG59XG5cbi8qKiBBYnNvbHV0ZSBoYW5kbGVzIGZyb20gc3RvcmVkIHJlbGF0aXZlIG9mZnNldHMgKGFuY2hvciArIG9mZnNldCkuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlc0Zyb21PZmZzZXRzKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbk9mZjogbnVtYmVyW11bXSwgb3V0T2ZmOiBudW1iZXJbXVtdLCBjbG9zZWQ6IGJvb2xlYW4pOiBBbmNob3JIYW5kbGVbXSB7XG4gIGNvbnN0IG4gPSBNYXRoLm1pbih4cy5sZW5ndGgsIHlzLmxlbmd0aCk7XG4gIGNvbnN0IG91dDogQW5jaG9ySGFuZGxlW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICBvdXQucHVzaCh7XG4gICAgICBpbjogW3hzW2ldICsgKGluT2ZmW2ldPy5bMF0gPz8gMCksIHlzW2ldICsgKGluT2ZmW2ldPy5bMV0gPz8gMCldLFxuICAgICAgb3V0OiBbeHNbaV0gKyAob3V0T2ZmW2ldPy5bMF0gPz8gMCksIHlzW2ldICsgKG91dE9mZltpXT8uWzFdID8/IDApXSxcbiAgICAgIGhhc091dDogY2xvc2VkIHx8IGkgPCBuIC0gMSxcbiAgICAgIGhhc0luOiBjbG9zZWQgfHwgaSA+IDAsXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIEEgcmVnaW9uJ3MgaGFuZGxlczogZnJvbSBpdHMgc3RvcmVkIChlZGl0YWJsZSkgb2Zmc2V0cyB3aGVuIHByZXNlbnQsIGVsc2UgdGhlXG4gKiAgQ2F0bXVsbC1Sb20gZGVmYXVsdC4gVGhlIHNpbmdsZSBzb3VyY2Ugb2YgdHJ1dGggZm9yIGJvdGggcmVuZGVyaW5nIGFuZCBleHBvcnQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUhhbmRsZXMoeHM6IG51bWJlcltdLCB5czogbnVtYmVyW10sIGNsb3NlZDogYm9vbGVhbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbk9mZj86IG51bWJlcltdW10sIG91dE9mZj86IG51bWJlcltdW10pOiBBbmNob3JIYW5kbGVbXSB7XG4gIGlmIChpbk9mZiAmJiBvdXRPZmYgJiYgaW5PZmYubGVuZ3RoID09PSB4cy5sZW5ndGggJiYgb3V0T2ZmLmxlbmd0aCA9PT0geHMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGhhbmRsZXNGcm9tT2Zmc2V0cyh4cywgeXMsIGluT2ZmLCBvdXRPZmYsIGNsb3NlZCk7XG4gIH1cbiAgcmV0dXJuIGJlemllckFuY2hvckhhbmRsZXMoeHMsIHlzLCBjbG9zZWQpO1xufVxuXG4vKipcbiAqIEZsYXR0ZW4gYSBjdWJpYyBiZXppZXIgKGRlZmluZWQgYnkgZXhwbGljaXQgcGVyLWFuY2hvciBoYW5kbGVzKSBpbnRvIGEgZGVuc2VcbiAqIHBvaW50IGxpc3QgYnkgc2FtcGxpbmcgZWFjaCBzZWdtZW50LiBUaGUgY3VydmUgcGFzc2VzIHRocm91Z2ggZXZlcnkgYW5jaG9yOyBhXG4gKiBjbG9zZWQgcmluZyByZXR1cm5zIHRvIGl0cyBmaXJzdCBwb2ludC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlemllckN1cnZlRnJvbUhhbmRsZXMoeHM6IG51bWJlcltdLCB5czogbnVtYmVyW10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVzOiBBbmNob3JIYW5kbGVbXSwgY2xvc2VkOiBib29sZWFuKTogQ3VydmVQb2ludHMge1xuICBjb25zdCBuID0gTWF0aC5taW4oeHMubGVuZ3RoLCB5cy5sZW5ndGgpO1xuICBpZiAobiA8IDMpIHJldHVybiB7IHhzOiB4cy5zbGljZSgpLCB5czogeXMuc2xpY2UoKSB9O1xuXG4gIGNvbnN0IG91dFg6IG51bWJlcltdID0gW107XG4gIGNvbnN0IG91dFk6IG51bWJlcltdID0gW107XG4gIGNvbnN0IHNlZ3MgPSBjbG9zZWQgPyBuIDogbiAtIDE7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2VnczsgaSsrKSB7XG4gICAgY29uc3QgaiA9IChpICsgMSkgJSBuO1xuICAgIGNvbnN0IHAweCA9IHhzW2ldLCBwMHkgPSB5c1tpXTtcbiAgICBjb25zdCBjMSA9IGhhbmRsZXNbaV0ub3V0LCBjMiA9IGhhbmRsZXNbal0uaW47XG4gICAgY29uc3QgcDN4ID0geHNbal0sIHAzeSA9IHlzW2pdO1xuICAgIGZvciAobGV0IHMgPSAwOyBzIDwgU0FNUExFU19QRVJfU0VHTUVOVDsgcysrKSB7XG4gICAgICBjb25zdCB0ID0gcyAvIFNBTVBMRVNfUEVSX1NFR01FTlQ7XG4gICAgICBjb25zdCB1ID0gMSAtIHQ7XG4gICAgICBjb25zdCB3MCA9IHUgKiB1ICogdSwgdzEgPSAzICogdSAqIHUgKiB0LCB3MiA9IDMgKiB1ICogdCAqIHQsIHczID0gdCAqIHQgKiB0O1xuICAgICAgb3V0WC5wdXNoKHcwICogcDB4ICsgdzEgKiBjMVswXSArIHcyICogYzJbMF0gKyB3MyAqIHAzeCk7XG4gICAgICBvdXRZLnB1c2godzAgKiBwMHkgKyB3MSAqIGMxWzFdICsgdzIgKiBjMlsxXSArIHczICogcDN5KTtcbiAgICB9XG4gIH1cbiAgaWYgKGNsb3NlZCkge1xuICAgIG91dFgucHVzaCh4c1swXSk7IG91dFkucHVzaCh5c1swXSk7XG4gIH0gZWxzZSB7XG4gICAgb3V0WC5wdXNoKHhzW24gLSAxXSk7IG91dFkucHVzaCh5c1tuIC0gMV0pO1xuICB9XG4gIHJldHVybiB7IHhzOiBvdXRYLCB5czogb3V0WSB9O1xufVxuXG4vKipcbiAqIEZsYXR0ZW4gdGhlIHNtb290aCBDYXRtdWxsLVJvbSBiZXppZXIgdGhyb3VnaCB0aGUgYW5jaG9ycyAobm8gY3VzdG9tIGhhbmRsZXMpLlxuICogRmFsbHMgYmFjayB0byB0aGUgYW5jaG9ycyB3aGVuIHRoZXJlIGFyZSB0b28gZmV3IHRvIGZvcm0gYSBjdXJ2ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlemllckN1cnZlKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLCBjbG9zZWQ6IGJvb2xlYW4pOiBDdXJ2ZVBvaW50cyB7XG4gIGNvbnN0IG4gPSBNYXRoLm1pbih4cy5sZW5ndGgsIHlzLmxlbmd0aCk7XG4gIGlmIChuIDwgMykgcmV0dXJuIHsgeHM6IHhzLnNsaWNlKCksIHlzOiB5cy5zbGljZSgpIH07XG4gIHJldHVybiBiZXppZXJDdXJ2ZUZyb21IYW5kbGVzKHhzLCB5cywgYmV6aWVyQW5jaG9ySGFuZGxlcyh4cywgeXMsIGNsb3NlZCksIGNsb3NlZCk7XG59XG4iXX0=
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Preset annotation classes (jit-ui#70).
3
+ *
4
+ * A class is a flat `{ name, color }` pair (v1: no hierarchy, no special-class semantics).
5
+ * The `PresetSet` is the per-user, server-persisted source of truth for region colours;
6
+ * see `class-color.util.ts` for the deterministic colour-resolution engine.
7
+ */
8
+ /**
9
+ * Fallback palette for classes not present in the preset set — reasonably distinct hues.
10
+ * Colours are assigned by a stable hash of the class name, so the same unknown class always
11
+ * gets the same colour with no stored state.
12
+ */
13
+ export const DEFAULT_FALLBACK_PALETTE = [
14
+ '#6C8EBF', '#82B366', '#B85450', '#9673A6', '#D79B00',
15
+ '#3C948B', '#A64CA6', '#CC6677', '#4477AA', '#228833',
16
+ ];
17
+ /** Seed classes — mirrors the historical hard-coded `classificationColors` map. */
18
+ const DEFAULT_CLASSES = [
19
+ { name: 'Fragmented-embryo', color: '#FF8C00', source: 'default' },
20
+ { name: 'Dying-embryo', color: '#FF3333', source: 'default' },
21
+ { name: 'Two-cell-embryo', color: '#33CC66', source: 'default' },
22
+ { name: 'One-cell-embryo', color: '#3399FF', source: 'default' },
23
+ { name: 'Unknown', color: '#888888', source: 'default' },
24
+ { name: 'Tumor', color: '#FF4444', source: 'default' },
25
+ { name: 'Stroma', color: '#44AAFF', source: 'default' },
26
+ { name: 'Immune cells', color: '#FFDD00', source: 'default' },
27
+ { name: 'Necrosis', color: '#AA6633', source: 'default' },
28
+ { name: 'Region', color: '#00FFFF', source: 'default' },
29
+ { name: 'Ignore', color: '#AAAAAA', source: 'default' },
30
+ { name: 'Positive', color: '#00CC44', source: 'default' },
31
+ { name: 'Negative', color: '#CC0000', source: 'default' },
32
+ ];
33
+ /** A fresh default preset set (deep-copied so callers can mutate safely). */
34
+ export function defaultPresetSet() {
35
+ return {
36
+ classes: DEFAULT_CLASSES.map((c) => ({ ...c })),
37
+ fallbackPalette: [...DEFAULT_FALLBACK_PALETTE],
38
+ autoPromote: false,
39
+ matchMode: 'exact',
40
+ };
41
+ }
42
+ /** True when the set has no usable classes (e.g. the server returned an empty/blank record). */
43
+ export function isEmptyPresetSet(set) {
44
+ return !set || !Array.isArray(set.classes) || set.classes.length === 0;
45
+ }
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3MtcHJlc2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tb2RlbHMvY2xhc3MtcHJlc2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQTRCSDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQWE7SUFDaEQsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVM7SUFDckQsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVM7Q0FDdEQsQ0FBQztBQUVGLG1GQUFtRjtBQUNuRixNQUFNLGVBQWUsR0FBa0I7SUFDckMsRUFBRSxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFO0lBQ2xFLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7SUFDN0QsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFO0lBQ2hFLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRTtJQUNoRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFO0lBQ3hELEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7SUFDdEQsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRTtJQUN2RCxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFO0lBQzdELEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7SUFDekQsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRTtJQUN2RCxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFO0lBQ3ZELEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7SUFDekQsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRTtDQUMxRCxDQUFDO0FBRUYsNkVBQTZFO0FBQzdFLE1BQU0sVUFBVSxnQkFBZ0I7SUFDOUIsT0FBTztRQUNMLE9BQU8sRUFBRSxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLGVBQWUsRUFBRSxDQUFDLEdBQUcsd0JBQXdCLENBQUM7UUFDOUMsV0FBVyxFQUFFLEtBQUs7UUFDbEIsU0FBUyxFQUFFLE9BQU87S0FDbkIsQ0FBQztBQUNKLENBQUM7QUFFRCxnR0FBZ0c7QUFDaEcsTUFBTSxVQUFVLGdCQUFnQixDQUFDLEdBQWlDO0lBQ2hFLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUM7QUFDekUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHJlc2V0IGFubm90YXRpb24gY2xhc3NlcyAoaml0LXVpIzcwKS5cbiAqXG4gKiBBIGNsYXNzIGlzIGEgZmxhdCBgeyBuYW1lLCBjb2xvciB9YCBwYWlyICh2MTogbm8gaGllcmFyY2h5LCBubyBzcGVjaWFsLWNsYXNzIHNlbWFudGljcykuXG4gKiBUaGUgYFByZXNldFNldGAgaXMgdGhlIHBlci11c2VyLCBzZXJ2ZXItcGVyc2lzdGVkIHNvdXJjZSBvZiB0cnV0aCBmb3IgcmVnaW9uIGNvbG91cnM7XG4gKiBzZWUgYGNsYXNzLWNvbG9yLnV0aWwudHNgIGZvciB0aGUgZGV0ZXJtaW5pc3RpYyBjb2xvdXItcmVzb2x1dGlvbiBlbmdpbmUuXG4gKi9cblxuZXhwb3J0IHR5cGUgUHJlc2V0U291cmNlID0gJ3VzZXInIHwgJ2RlZmF1bHQnIHwgJ2F1dG8nO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsYXNzUHJlc2V0IHtcbiAgLyoqIFRoZSBjbGFzcyBuYW1lIOKAlCBtYXRjaGVkIGFnYWluc3QgYFJlZ2lvbi5sYWJlbGAuICovXG4gIG5hbWU6IHN0cmluZztcbiAgLyoqIEhleCBjb2xvdXIsIGAjUlJHR0JCYC4gKi9cbiAgY29sb3I6IHN0cmluZztcbiAgLyoqIFJlc2VydmVkIGZvciBhIGZ1dHVyZSBwZXItY2xhc3Mgb3ZlcmxheS12aXNpYmlsaXR5IHRvZ2dsZS4gKi9cbiAgdmlzaWJsZT86IGJvb2xlYW47XG4gIC8qKiBQcm92ZW5hbmNlOyBgJ2F1dG8nYCA9IGFkZGVkIGJ5IG9wdC1pbiBmYWxsYmFjayBwcm9tb3Rpb24uICovXG4gIHNvdXJjZT86IFByZXNldFNvdXJjZTtcbn1cblxuZXhwb3J0IHR5cGUgTWF0Y2hNb2RlID0gJ2V4YWN0JyB8ICdub3JtYWxpemVkJztcblxuZXhwb3J0IGludGVyZmFjZSBQcmVzZXRTZXQge1xuICAvKiogT3JkZXJlZCBsaXN0IG9mIHByZXNldCBjbGFzc2VzLiAqL1xuICBjbGFzc2VzOiBDbGFzc1ByZXNldFtdO1xuICAvKiogQ29sb3VycyB1c2VkIGZvciBjbGFzc2VzIG5vdCBpbiBgY2xhc3Nlc2AgKGFzc2lnbmVkIGRldGVybWluaXN0aWNhbGx5KS4gKi9cbiAgZmFsbGJhY2tQYWxldHRlOiBzdHJpbmdbXTtcbiAgLyoqIE9wdC1pbiAoZGVmYXVsdCBmYWxzZSk6IGFkZCBhbiB1bmtub3duIGNsYXNzIHRvIGBjbGFzc2VzYCB0aGUgZmlyc3QgdGltZSBpdCBpcyBzZWVuLiAqL1xuICBhdXRvUHJvbW90ZTogYm9vbGVhbjtcbiAgLyoqIExhYmVsIG1hdGNoaW5nIGFnYWluc3QgYFJlZ2lvbi5sYWJlbGAgKGRlZmF1bHQgYCdleGFjdCdgKS4gKi9cbiAgbWF0Y2hNb2RlOiBNYXRjaE1vZGU7XG59XG5cbi8qKlxuICogRmFsbGJhY2sgcGFsZXR0ZSBmb3IgY2xhc3NlcyBub3QgcHJlc2VudCBpbiB0aGUgcHJlc2V0IHNldCDigJQgcmVhc29uYWJseSBkaXN0aW5jdCBodWVzLlxuICogQ29sb3VycyBhcmUgYXNzaWduZWQgYnkgYSBzdGFibGUgaGFzaCBvZiB0aGUgY2xhc3MgbmFtZSwgc28gdGhlIHNhbWUgdW5rbm93biBjbGFzcyBhbHdheXNcbiAqIGdldHMgdGhlIHNhbWUgY29sb3VyIHdpdGggbm8gc3RvcmVkIHN0YXRlLlxuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9GQUxMQkFDS19QQUxFVFRFOiBzdHJpbmdbXSA9IFtcbiAgJyM2QzhFQkYnLCAnIzgyQjM2NicsICcjQjg1NDUwJywgJyM5NjczQTYnLCAnI0Q3OUIwMCcsXG4gICcjM0M5NDhCJywgJyNBNjRDQTYnLCAnI0NDNjY3NycsICcjNDQ3N0FBJywgJyMyMjg4MzMnLFxuXTtcblxuLyoqIFNlZWQgY2xhc3NlcyDigJQgbWlycm9ycyB0aGUgaGlzdG9yaWNhbCBoYXJkLWNvZGVkIGBjbGFzc2lmaWNhdGlvbkNvbG9yc2AgbWFwLiAqL1xuY29uc3QgREVGQVVMVF9DTEFTU0VTOiBDbGFzc1ByZXNldFtdID0gW1xuICB7IG5hbWU6ICdGcmFnbWVudGVkLWVtYnJ5bycsIGNvbG9yOiAnI0ZGOEMwMCcsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ0R5aW5nLWVtYnJ5bycsIGNvbG9yOiAnI0ZGMzMzMycsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ1R3by1jZWxsLWVtYnJ5bycsIGNvbG9yOiAnIzMzQ0M2NicsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ09uZS1jZWxsLWVtYnJ5bycsIGNvbG9yOiAnIzMzOTlGRicsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ1Vua25vd24nLCBjb2xvcjogJyM4ODg4ODgnLCBzb3VyY2U6ICdkZWZhdWx0JyB9LFxuICB7IG5hbWU6ICdUdW1vcicsIGNvbG9yOiAnI0ZGNDQ0NCcsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ1N0cm9tYScsIGNvbG9yOiAnIzQ0QUFGRicsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ0ltbXVuZSBjZWxscycsIGNvbG9yOiAnI0ZGREQwMCcsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG4gIHsgbmFtZTogJ05lY3Jvc2lzJywgY29sb3I6ICcjQUE2NjMzJywgc291cmNlOiAnZGVmYXVsdCcgfSxcbiAgeyBuYW1lOiAnUmVnaW9uJywgY29sb3I6ICcjMDBGRkZGJywgc291cmNlOiAnZGVmYXVsdCcgfSxcbiAgeyBuYW1lOiAnSWdub3JlJywgY29sb3I6ICcjQUFBQUFBJywgc291cmNlOiAnZGVmYXVsdCcgfSxcbiAgeyBuYW1lOiAnUG9zaXRpdmUnLCBjb2xvcjogJyMwMENDNDQnLCBzb3VyY2U6ICdkZWZhdWx0JyB9LFxuICB7IG5hbWU6ICdOZWdhdGl2ZScsIGNvbG9yOiAnI0NDMDAwMCcsIHNvdXJjZTogJ2RlZmF1bHQnIH0sXG5dO1xuXG4vKiogQSBmcmVzaCBkZWZhdWx0IHByZXNldCBzZXQgKGRlZXAtY29waWVkIHNvIGNhbGxlcnMgY2FuIG11dGF0ZSBzYWZlbHkpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlZmF1bHRQcmVzZXRTZXQoKTogUHJlc2V0U2V0IHtcbiAgcmV0dXJuIHtcbiAgICBjbGFzc2VzOiBERUZBVUxUX0NMQVNTRVMubWFwKChjKSA9PiAoeyAuLi5jIH0pKSxcbiAgICBmYWxsYmFja1BhbGV0dGU6IFsuLi5ERUZBVUxUX0ZBTExCQUNLX1BBTEVUVEVdLFxuICAgIGF1dG9Qcm9tb3RlOiBmYWxzZSxcbiAgICBtYXRjaE1vZGU6ICdleGFjdCcsXG4gIH07XG59XG5cbi8qKiBUcnVlIHdoZW4gdGhlIHNldCBoYXMgbm8gdXNhYmxlIGNsYXNzZXMgKGUuZy4gdGhlIHNlcnZlciByZXR1cm5lZCBhbiBlbXB0eS9ibGFuayByZWNvcmQpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRW1wdHlQcmVzZXRTZXQoc2V0OiBQcmVzZXRTZXQgfCBudWxsIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gIHJldHVybiAhc2V0IHx8ICFBcnJheS5pc0FycmF5KHNldC5jbGFzc2VzKSB8fCBzZXQuY2xhc3Nlcy5sZW5ndGggPT09IDA7XG59XG4iXX0=
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Pure geometry helpers extracted from PlotlyService.
3
+ *
4
+ * No DOM access, no service state, no `this` — every function is testable
5
+ * in isolation. Keep it that way: this module is the dumping ground for
6
+ * shape/mask/SVG-path utilities the wand, vertex eraser, and region editor
7
+ * share. If a helper grows a `this.shapes` reference, it doesn't belong here.
8
+ */
9
+ // ── SVG path parsing / building ──────────────────────────────────────
10
+ /**
11
+ * Parse a single-subpath `M x,y L x,y ... Z` path into vertex arrays.
12
+ *
13
+ * Returns null for paths we can't safely round-trip (multi-subpath, curves,
14
+ * fewer than three vertices). The wand only adopts shapes it produced or
15
+ * that Plotly's drawclosedpath produces, both of which are single-subpath
16
+ * polygons.
17
+ */
18
+ export function parseSvgPathPolygon(path) {
19
+ if (!path || path[0] !== 'M')
20
+ return null;
21
+ if (path.indexOf('M', 1) !== -1)
22
+ return null; // multi-subpath
23
+ const trimmed = path.endsWith('Z') ? path.slice(1, -1) : path.slice(1);
24
+ const segs = trimmed.split('L');
25
+ const xpoints = [];
26
+ const ypoints = [];
27
+ for (const seg of segs) {
28
+ const [sx, sy] = seg.split(',');
29
+ const x = parseFloat(sx);
30
+ const y = parseFloat(sy);
31
+ if (!Number.isFinite(x) || !Number.isFinite(y))
32
+ return null;
33
+ xpoints.push(x);
34
+ ypoints.push(y);
35
+ }
36
+ if (xpoints.length < 3)
37
+ return null;
38
+ return { xpoints, ypoints };
39
+ }
40
+ /**
41
+ * Build a closed SVG path string `M x,y L x,y L ... Z` from vertex arrays.
42
+ * Returns '' for fewer than three vertices (degenerate).
43
+ */
44
+ export function polygonToSvgPath(xpoints, ypoints) {
45
+ if (xpoints.length < 3)
46
+ return '';
47
+ let path = 'M';
48
+ for (let i = 0; i < xpoints.length; i++) {
49
+ path += `${xpoints[i]},${ypoints[i]}`;
50
+ path += i < xpoints.length - 1 ? 'L' : 'Z';
51
+ }
52
+ return path;
53
+ }
54
+ /**
55
+ * Build an SVG path string from vertex arrays. Closed polygons end with `Z`,
56
+ * open polylines do not. Returns '' for fewer than two vertices (degenerate).
57
+ */
58
+ export function verticesToSvgPath(xs, ys, closed) {
59
+ if (xs.length < 2)
60
+ return '';
61
+ let path = 'M';
62
+ for (let i = 0; i < xs.length; i++) {
63
+ path += `${xs[i]},${ys[i]}`;
64
+ if (i < xs.length - 1)
65
+ path += 'L';
66
+ }
67
+ if (closed)
68
+ path += 'Z';
69
+ return path;
70
+ }
71
+ // ── Region equality ──────────────────────────────────────────────────
72
+ /**
73
+ * Compare two Plotly shape objects for "same region" — used by the wand to
74
+ * avoid appending duplicates when the user pushes the same find result more
75
+ * than once. Polygons compare by SVG path string, rectangles compare by
76
+ * (x0, y0, x1, y1).
77
+ */
78
+ export function shapesEqual(a, b) {
79
+ if (a.path && b.path) {
80
+ return a.path === b.path;
81
+ }
82
+ if (a.x0 !== undefined && a.y0 !== undefined &&
83
+ a.x1 !== undefined && a.y1 !== undefined &&
84
+ b.x0 !== undefined && b.y0 !== undefined &&
85
+ b.x1 !== undefined && b.y1 !== undefined) {
86
+ return a.x0 === b.x0 &&
87
+ a.y0 === b.y0 &&
88
+ a.x1 === b.x1 &&
89
+ a.y1 === b.y1;
90
+ }
91
+ return false;
92
+ }
93
+ // ── BBox-mask operations (used by the wand stroke accumulator) ───────
94
+ /** Returns true if the two bbox-relative masks share at least one set pixel. */
95
+ export function masksOverlap(a, b) {
96
+ const ix0 = Math.max(a.bx, b.bx);
97
+ const iy0 = Math.max(a.by, b.by);
98
+ const ix1 = Math.min(a.bx + a.bw, b.bx + b.bw);
99
+ const iy1 = Math.min(a.by + a.bh, b.by + b.bh);
100
+ if (ix0 >= ix1 || iy0 >= iy1)
101
+ return false;
102
+ for (let y = iy0; y < iy1; y++) {
103
+ const ar = (y - a.by) * a.bw;
104
+ const br = (y - b.by) * b.bw;
105
+ for (let x = ix0; x < ix1; x++) {
106
+ if (a.mask[ar + (x - a.bx)] && b.mask[br + (x - b.bx)])
107
+ return true;
108
+ }
109
+ }
110
+ return false;
111
+ }
112
+ /**
113
+ * Allocate a fresh accumulator covering both masks and OR them in. The
114
+ * resulting mask's bbox is the smallest rectangle containing both inputs.
115
+ */
116
+ export function unionMasks(a, b) {
117
+ const ux0 = Math.min(a.bx, b.bx);
118
+ const uy0 = Math.min(a.by, b.by);
119
+ const ux1 = Math.max(a.bx + a.bw, b.bx + b.bw);
120
+ const uy1 = Math.max(a.by + a.bh, b.by + b.bh);
121
+ const ubw = ux1 - ux0;
122
+ const ubh = uy1 - uy0;
123
+ const umask = new Uint8Array(ubw * ubh);
124
+ const dax = a.bx - ux0;
125
+ const day = a.by - uy0;
126
+ for (let row = 0; row < a.bh; row++) {
127
+ const src = row * a.bw;
128
+ const dst = (row + day) * ubw + dax;
129
+ umask.set(a.mask.subarray(src, src + a.bw), dst);
130
+ }
131
+ const dbx = b.bx - ux0;
132
+ const dby = b.by - uy0;
133
+ for (let row = 0; row < b.bh; row++) {
134
+ const srcRow = row * b.bw;
135
+ const dstRow = (row + dby) * ubw;
136
+ for (let col = 0; col < b.bw; col++) {
137
+ if (b.mask[srcRow + col])
138
+ umask[dstRow + (dbx + col)] = 1;
139
+ }
140
+ }
141
+ return { bx: ux0, by: uy0, bw: ubw, bh: ubh, mask: umask };
142
+ }
143
+ // ── Ring simplification (Douglas–Peucker) ───────────────────────────────
144
+ /** Perpendicular distance from (px,py) to the segment (ax,ay)–(bx,by). */
145
+ function perpDistance(px, py, ax, ay, bx, by) {
146
+ const dx = bx - ax, dy = by - ay;
147
+ const len2 = dx * dx + dy * dy;
148
+ if (len2 === 0)
149
+ return Math.hypot(px - ax, py - ay);
150
+ let t = ((px - ax) * dx + (py - ay) * dy) / len2;
151
+ t = Math.max(0, Math.min(1, t));
152
+ return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
153
+ }
154
+ /**
155
+ * Simplify a closed ring with the Douglas–Peucker algorithm (jit-ui#85):
156
+ * drop every vertex that lies within `epsilon` pixels (the "altitude
157
+ * threshold") of the line between its kept neighbours. Anchored at vertex 0
158
+ * (the ring is closed by appending it). Rings of ≤ 3 vertices, or a
159
+ * non-positive epsilon, are returned unchanged. Output keeps the closed-ring
160
+ * convention (no repeated closing point).
161
+ */
162
+ export function simplifyRing(xs, ys, epsilon) {
163
+ const n = xs.length;
164
+ if (n <= 3 || !(epsilon > 0))
165
+ return { xs: xs.slice(), ys: ys.slice() };
166
+ // Close the ring so both endpoints of the DP run are vertex 0.
167
+ const px = [...xs, xs[0]];
168
+ const py = [...ys, ys[0]];
169
+ const m = px.length;
170
+ const keep = new Array(m).fill(false);
171
+ keep[0] = true;
172
+ keep[m - 1] = true;
173
+ const stack = [[0, m - 1]];
174
+ while (stack.length) {
175
+ const [a, b] = stack.pop();
176
+ let maxD = -1, idx = -1;
177
+ for (let i = a + 1; i < b; i++) {
178
+ const d = perpDistance(px[i], py[i], px[a], py[a], px[b], py[b]);
179
+ if (d > maxD) {
180
+ maxD = d;
181
+ idx = i;
182
+ }
183
+ }
184
+ if (maxD > epsilon && idx > a) {
185
+ keep[idx] = true;
186
+ stack.push([a, idx], [idx, b]);
187
+ }
188
+ }
189
+ const outX = [], outY = [];
190
+ for (let i = 0; i < m - 1; i++) { // drop the duplicated closing vertex
191
+ if (keep[i]) {
192
+ outX.push(px[i]);
193
+ outY.push(py[i]);
194
+ }
195
+ }
196
+ return { xs: outX, ys: outY };
197
+ }
198
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VvbWV0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL21vZGVscy9nZW9tZXRyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBaUJILHdFQUF3RTtBQUV4RTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLElBQVk7SUFDOUMsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzFDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQyxnQkFBZ0I7SUFDOUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RSxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sT0FBTyxHQUFhLEVBQUUsQ0FBQztJQUM3QixNQUFNLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDN0IsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDaEMsTUFBTSxDQUFDLEdBQUcsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3pCLE1BQU0sQ0FBQyxHQUFHLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDNUQsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUM7SUFDRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3BDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDOUIsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUFpQixFQUFFLE9BQWlCO0lBQ25FLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQUUsT0FBTyxFQUFFLENBQUM7SUFDbEMsSUFBSSxJQUFJLEdBQUcsR0FBRyxDQUFDO0lBQ2YsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUN4QyxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdEMsSUFBSSxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDN0MsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxFQUFZLEVBQUUsRUFBWSxFQUFFLE1BQWU7SUFDM0UsSUFBSSxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUM7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUM3QixJQUFJLElBQUksR0FBRyxHQUFHLENBQUM7SUFDZixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ25DLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUM7WUFBRSxJQUFJLElBQUksR0FBRyxDQUFDO0lBQ3JDLENBQUM7SUFDRCxJQUFJLE1BQU07UUFBRSxJQUFJLElBQUksR0FBRyxDQUFDO0lBQ3hCLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVELHdFQUF3RTtBQUV4RTs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsQ0FBTSxFQUFFLENBQU07SUFDeEMsSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNyQixPQUFPLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQztJQUMzQixDQUFDO0lBQ0QsSUFDRSxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsSUFBSSxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVM7UUFDeEMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxTQUFTLElBQUksQ0FBQyxDQUFDLEVBQUUsS0FBSyxTQUFTO1FBQ3hDLENBQUMsQ0FBQyxFQUFFLEtBQUssU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssU0FBUztRQUN4QyxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsSUFBSSxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsRUFDeEMsQ0FBQztRQUNELE9BQU8sQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNiLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLEVBQUU7WUFDYixDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQ2IsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCx3RUFBd0U7QUFFeEUsZ0ZBQWdGO0FBQ2hGLE1BQU0sVUFBVSxZQUFZLENBQUMsQ0FBVyxFQUFFLENBQVc7SUFDbkQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNqQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLElBQUksR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzNDLEtBQUssSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUMvQixNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM3QixNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM3QixLQUFLLElBQUksQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDL0IsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQUUsT0FBTyxJQUFJLENBQUM7UUFDdEUsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsVUFBVSxDQUFDLENBQVcsRUFBRSxDQUFXO0lBQ2pELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDakMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNqQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQyxNQUFNLEdBQUcsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQ3RCLE1BQU0sR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDdEIsTUFBTSxLQUFLLEdBQUcsSUFBSSxVQUFVLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBRXhDLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxDQUFDO0lBQ3ZCLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxDQUFDO0lBQ3ZCLEtBQUssSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUM7UUFDcEMsTUFBTSxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdkIsTUFBTSxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNwQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQztJQUN2QixNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQztJQUN2QixLQUFLLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzFCLE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztRQUNqQyxLQUFLLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQ3BDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO2dCQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDNUQs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WyIvKipcbiAqIFB1cmUgZ2VvbWV0cnkgaGVscGVycyBleHRyYWN0ZWQgZnJvbSBQbG90bHlTZXJ2aWNlLlxuICpcbiAqIE5vIERPTSBhY2Nlc3MsIG5vIHNlcnZpY2Ugc3RhdGUsIG5vIGB0aGlzYCDigJQgZXZlcnkgZnVuY3Rpb24gaXMgdGVzdGFibGVcbiAqIGluIGlzb2xhdGlvbi4gS2VlcCBpdCB0aGF0IHdheTogdGhpcyBtb2R1bGUgaXMgdGhlIGR1bXBpbmcgZ3JvdW5kIGZvclxuICogc2hhcGUvbWFzay9TVkctcGF0aCB1dGlsaXRpZXMgdGhlIHdhbmQsIHZlcnRleCBlcmFzZXIsIGFuZCByZWdpb24gZWRpdG9yXG4gKiBzaGFyZS4gSWYgYSBoZWxwZXIgZ3Jvd3MgYSBgdGhpcy5zaGFwZXNgIHJlZmVyZW5jZSwgaXQgZG9lc24ndCBiZWxvbmcgaGVyZS5cbiAqL1xuXG4vKiogQSBiYm94LXJlbGF0aXZlIGJpbmFyeSBtYXNrICgxID0gZmlsbGVkLCAwID0gZW1wdHkpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBCQm94TWFzayB7XG4gIGJ4OiBudW1iZXI7XG4gIGJ5OiBudW1iZXI7XG4gIGJ3OiBudW1iZXI7XG4gIGJoOiBudW1iZXI7XG4gIG1hc2s6IFVpbnQ4QXJyYXk7XG59XG5cbi8qKiBQYXJzZWQgc2luZ2xlLXN1YnBhdGggcG9seWdvbiB2ZXJ0aWNlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUG9seWdvblZlcnRpY2VzIHtcbiAgeHBvaW50czogbnVtYmVyW107XG4gIHlwb2ludHM6IG51bWJlcltdO1xufVxuXG4vLyDilIDilIAgU1ZHIHBhdGggcGFyc2luZyAvIGJ1aWxkaW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFBhcnNlIGEgc2luZ2xlLXN1YnBhdGggYE0geCx5IEwgeCx5IC4uLiBaYCBwYXRoIGludG8gdmVydGV4IGFycmF5cy5cbiAqXG4gKiBSZXR1cm5zIG51bGwgZm9yIHBhdGhzIHdlIGNhbid0IHNhZmVseSByb3VuZC10cmlwIChtdWx0aS1zdWJwYXRoLCBjdXJ2ZXMsXG4gKiBmZXdlciB0aGFuIHRocmVlIHZlcnRpY2VzKS4gVGhlIHdhbmQgb25seSBhZG9wdHMgc2hhcGVzIGl0IHByb2R1Y2VkIG9yXG4gKiB0aGF0IFBsb3RseSdzIGRyYXdjbG9zZWRwYXRoIHByb2R1Y2VzLCBib3RoIG9mIHdoaWNoIGFyZSBzaW5nbGUtc3VicGF0aFxuICogcG9seWdvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVN2Z1BhdGhQb2x5Z29uKHBhdGg6IHN0cmluZyk6IFBvbHlnb25WZXJ0aWNlcyB8IG51bGwge1xuICBpZiAoIXBhdGggfHwgcGF0aFswXSAhPT0gJ00nKSByZXR1cm4gbnVsbDtcbiAgaWYgKHBhdGguaW5kZXhPZignTScsIDEpICE9PSAtMSkgcmV0dXJuIG51bGw7IC8vIG11bHRpLXN1YnBhdGhcbiAgY29uc3QgdHJpbW1lZCA9IHBhdGguZW5kc1dpdGgoJ1onKSA/IHBhdGguc2xpY2UoMSwgLTEpIDogcGF0aC5zbGljZSgxKTtcbiAgY29uc3Qgc2VncyA9IHRyaW1tZWQuc3BsaXQoJ0wnKTtcbiAgY29uc3QgeHBvaW50czogbnVtYmVyW10gPSBbXTtcbiAgY29uc3QgeXBvaW50czogbnVtYmVyW10gPSBbXTtcbiAgZm9yIChjb25zdCBzZWcgb2Ygc2Vncykge1xuICAgIGNvbnN0IFtzeCwgc3ldID0gc2VnLnNwbGl0KCcsJyk7XG4gICAgY29uc3QgeCA9IHBhcnNlRmxvYXQoc3gpO1xuICAgIGNvbnN0IHkgPSBwYXJzZUZsb2F0KHN5KTtcbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZSh4KSB8fCAhTnVtYmVyLmlzRmluaXRlKHkpKSByZXR1cm4gbnVsbDtcbiAgICB4cG9pbnRzLnB1c2goeCk7XG4gICAgeXBvaW50cy5wdXNoKHkpO1xuICB9XG4gIGlmICh4cG9pbnRzLmxlbmd0aCA8IDMpIHJldHVybiBudWxsO1xuICByZXR1cm4geyB4cG9pbnRzLCB5cG9pbnRzIH07XG59XG5cbi8qKlxuICogQnVpbGQgYSBjbG9zZWQgU1ZHIHBhdGggc3RyaW5nIGBNIHgseSBMIHgseSBMIC4uLiBaYCBmcm9tIHZlcnRleCBhcnJheXMuXG4gKiBSZXR1cm5zICcnIGZvciBmZXdlciB0aGFuIHRocmVlIHZlcnRpY2VzIChkZWdlbmVyYXRlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBvbHlnb25Ub1N2Z1BhdGgoeHBvaW50czogbnVtYmVyW10sIHlwb2ludHM6IG51bWJlcltdKTogc3RyaW5nIHtcbiAgaWYgKHhwb2ludHMubGVuZ3RoIDwgMykgcmV0dXJuICcnO1xuICBsZXQgcGF0aCA9ICdNJztcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB4cG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgcGF0aCArPSBgJHt4cG9pbnRzW2ldfSwke3lwb2ludHNbaV19YDtcbiAgICBwYXRoICs9IGkgPCB4cG9pbnRzLmxlbmd0aCAtIDEgPyAnTCcgOiAnWic7XG4gIH1cbiAgcmV0dXJuIHBhdGg7XG59XG5cbi8qKlxuICogQnVpbGQgYW4gU1ZHIHBhdGggc3RyaW5nIGZyb20gdmVydGV4IGFycmF5cy4gQ2xvc2VkIHBvbHlnb25zIGVuZCB3aXRoIGBaYCxcbiAqIG9wZW4gcG9seWxpbmVzIGRvIG5vdC4gUmV0dXJucyAnJyBmb3IgZmV3ZXIgdGhhbiB0d28gdmVydGljZXMgKGRlZ2VuZXJhdGUpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVydGljZXNUb1N2Z1BhdGgoeHM6IG51bWJlcltdLCB5czogbnVtYmVyW10sIGNsb3NlZDogYm9vbGVhbik6IHN0cmluZyB7XG4gIGlmICh4cy5sZW5ndGggPCAyKSByZXR1cm4gJyc7XG4gIGxldCBwYXRoID0gJ00nO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgcGF0aCArPSBgJHt4c1tpXX0sJHt5c1tpXX1gO1xuICAgIGlmIChpIDwgeHMubGVuZ3RoIC0gMSkgcGF0aCArPSAnTCc7XG4gIH1cbiAgaWYgKGNsb3NlZCkgcGF0aCArPSAnWic7XG4gIHJldHVybiBwYXRoO1xufVxuXG4vLyDilIDilIAgUmVnaW9uIGVxdWFsaXR5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIENvbXBhcmUgdHdvIFBsb3RseSBzaGFwZSBvYmplY3RzIGZvciBcInNhbWUgcmVnaW9uXCIg4oCUIHVzZWQgYnkgdGhlIHdhbmQgdG9cbiAqIGF2b2lkIGFwcGVuZGluZyBkdXBsaWNhdGVzIHdoZW4gdGhlIHVzZXIgcHVzaGVzIHRoZSBzYW1lIGZpbmQgcmVzdWx0IG1vcmVcbiAqIHRoYW4gb25jZS4gUG9seWdvbnMgY29tcGFyZSBieSBTVkcgcGF0aCBzdHJpbmcsIHJlY3RhbmdsZXMgY29tcGFyZSBieVxuICogKHgwLCB5MCwgeDEsIHkxKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoYXBlc0VxdWFsKGE6IGFueSwgYjogYW55KTogYm9vbGVhbiB7XG4gIGlmIChhLnBhdGggJiYgYi5wYXRoKSB7XG4gICAgcmV0dXJuIGEucGF0aCA9PT0gYi5wYXRoO1xuICB9XG4gIGlmIChcbiAgICBhLngwICE9PSB1bmRlZmluZWQgJiYgYS55MCAhPT0gdW5kZWZpbmVkICYmXG4gICAgYS54MSAhPT0gdW5kZWZpbmVkICYmIGEueTEgIT09IHVuZGVmaW5lZCAmJlxuICAgIGIueDAgIT09IHVuZGVmaW5lZCAmJiBiLnkwICE9PSB1bmRlZmluZWQgJiZcbiAgICBiLngxICE9PSB1bmRlZmluZWQgJiYgYi55MSAhPT0gdW5kZWZpbmVkXG4gICkge1xuICAgIHJldHVybiBhLngwID09PSBiLngwICYmXG4gICAgICAgICAgIGEueTAgPT09IGIueTAgJiZcbiAgICAgICAgICAgYS54MSA9PT0gYi54MSAmJlxuICAgICAgICAgICBhLnkxID09PSBiLnkxO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLy8g4pSA4pSAIEJCb3gtbWFzayBvcGVyYXRpb25zICh1c2VkIGJ5IHRoZSB3YW5kIHN0cm9rZSBhY2N1bXVsYXRvcikg4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIHR3byBiYm94LXJlbGF0aXZlIG1hc2tzIHNoYXJlIGF0IGxlYXN0IG9uZSBzZXQgcGl4ZWwuICovXG5leHBvcnQgZnVuY3Rpb24gbWFza3NPdmVybGFwKGE6IEJCb3hNYXNrLCBiOiBCQm94TWFzayk6IGJvb2xlYW4ge1xuICBjb25zdCBpeDAgPSBNYXRoLm1heChhLmJ4LCBiLmJ4KTtcbiAgY29uc3QgaXkwID0gTWF0aC5tYXgoYS5ieSwgYi5ieSk7XG4gIGNvbnN0IGl4MSA9IE1hdGgubWluKGEuYnggKyBhLmJ3LCBiLmJ4ICsgYi5idyk7XG4gIGNvbnN0IGl5MSA9IE1hdGgubWluKGEuYnkgKyBhLmJoLCBiLmJ5ICsgYi5iaCk7XG4gIGlmIChpeDAgPj0gaXgxIHx8IGl5MCA+PSBpeTEpIHJldHVybiBmYWxzZTtcbiAgZm9yIChsZXQgeSA9IGl5MDsgeSA8IGl5MTsgeSsrKSB7XG4gICAgY29uc3QgYXIgPSAoeSAtIGEuYnkpICogYS5idztcbiAgICBjb25zdCBiciA9ICh5IC0gYi5ieSkgKiBiLmJ3O1xuICAgIGZvciAobGV0IHggPSBpeDA7IHggPCBpeDE7IHgrKykge1xuICAgICAgaWYgKGEubWFza1thciArICh4IC0gYS5ieCldICYmIGIubWFza1ticiArICh4IC0gYi5ieCldKSByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIEFsbG9jYXRlIGEgZnJlc2ggYWNjdW11bGF0b3IgY292ZXJpbmcgYm90aCBtYXNrcyBhbmQgT1IgdGhlbSBpbi4gVGhlXG4gKiByZXN1bHRpbmcgbWFzaydzIGJib3ggaXMgdGhlIHNtYWxsZXN0IHJlY3RhbmdsZSBjb250YWluaW5nIGJvdGggaW5wdXRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb25NYXNrcyhhOiBCQm94TWFzaywgYjogQkJveE1hc2spOiBCQm94TWFzayB7XG4gIGNvbnN0IHV4MCA9IE1hdGgubWluKGEuYngsIGIuYngpO1xuICBjb25zdCB1eTAgPSBNYXRoLm1pbihhLmJ5LCBiLmJ5KTtcbiAgY29uc3QgdXgxID0gTWF0aC5tYXgoYS5ieCArIGEuYncsIGIuYnggKyBiLmJ3KTtcbiAgY29uc3QgdXkxID0gTWF0aC5tYXgoYS5ieSArIGEuYmgsIGIuYnkgKyBiLmJoKTtcbiAgY29uc3QgdWJ3ID0gdXgxIC0gdXgwO1xuICBjb25zdCB1YmggPSB1eTEgLSB1eTA7XG4gIGNvbnN0IHVtYXNrID0gbmV3IFVpbnQ4QXJyYXkodWJ3ICogdWJoKTtcblxuICBjb25zdCBkYXggPSBhLmJ4IC0gdXgwO1xuICBjb25zdCBkYXkgPSBhLmJ5IC0gdXkwO1xuICBmb3IgKGxldCByb3cgPSAwOyByb3cgPCBhLmJoOyByb3crKykge1xuICAgIGNvbnN0IHNyYyA9IHJvdyAqIGEuYnc7XG4gICAgY29uc3QgZHN0ID0gKHJvdyArIGRheSkgKiB1YncgKyBkYXg7XG4gICAgdW1hc2suc2V0KGEubWFzay5zdWJhcnJheShzcmMsIHNyYyArIGEuYncpLCBkc3QpO1xuICB9XG4gIGNvbnN0IGRieCA9IGIuYnggLSB1eDA7XG4gIGNvbnN0IGRieSA9IGIuYnkgLSB1eTA7XG4gIGZvciAobGV0IHJvdyA9IDA7IHJvdyA8IGIuYmg7IHJvdysrKSB7XG4gICAgY29uc3Qgc3JjUm93ID0gcm93ICogYi5idztcbiAgICBjb25zdCBkc3RSb3cgPSAocm93ICsgZGJ5KSAqIHVidztcbiAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCBiLmJ3OyBjb2wrKykge1xuICAgICAgaWYgKGIubWFza1tzcmNSb3cgKyBjb2xdKSB1bWFza1tkc3RSb3cgKyAoZGJ4ICsgY29sKV0gPSAxO1xuICAgIH1cbiAgfVxuICByZXR1cm4geyBieDogdXgwLCBieTogdXkwLCBidzogdWJ3LCBiaDogdWJoLCBtYXNrOiB1bWFzayB9O1xufVxuXG4vLyDilIDilIAgUmluZyBzaW1wbGlmaWNhdGlvbiAoRG91Z2xhc+KAk1BldWNrZXIpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogUGVycGVuZGljdWxhciBkaXN0YW5jZSBmcm9tIChweCxweSkgdG8gdGhlIHNlZ21lbnQgKGF4LGF5KeKAkyhieCxieSkuICovXG5mdW5jdGlvbiBwZXJwRGlzdGFuY2UocHg6IG51bWJlciwgcHk6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgICBheDogbnVtYmVyLCBheTogbnVtYmVyLCBieDogbnVtYmVyLCBieTogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgZHggPSBieCAtIGF4LCBkeSA9IGJ5IC0gYXk7XG4gIGNvbnN0IGxlbjIgPSBkeCAqIGR4ICsgZHkgKiBkeTtcbiAgaWYgKGxlbjIgPT09IDApIHJldHVybiBNYXRoLmh5cG90KHB4IC0gYXgsIHB5IC0gYXkpO1xuICBsZXQgdCA9ICgocHggLSBheCkgKiBkeCArIChweSAtIGF5KSAqIGR5KSAvIGxlbjI7XG4gIHQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB0KSk7XG4gIHJldHVybiBNYXRoLmh5cG90KHB4IC0gKGF4ICsgdCAqIGR4KSwgcHkgLSAoYXkgKyB0ICogZHkpKTtcbn1cblxuLyoqXG4gKiBTaW1wbGlmeSBhIGNsb3NlZCByaW5nIHdpdGggdGhlIERvdWdsYXPigJNQZXVja2VyIGFsZ29yaXRobSAoaml0LXVpIzg1KTpcbiAqIGRyb3AgZXZlcnkgdmVydGV4IHRoYXQgbGllcyB3aXRoaW4gYGVwc2lsb25gIHBpeGVscyAodGhlIFwiYWx0aXR1ZGVcbiAqIHRocmVzaG9sZFwiKSBvZiB0aGUgbGluZSBiZXR3ZWVuIGl0cyBrZXB0IG5laWdoYm91cnMuIEFuY2hvcmVkIGF0IHZlcnRleCAwXG4gKiAodGhlIHJpbmcgaXMgY2xvc2VkIGJ5IGFwcGVuZGluZyBpdCkuIFJpbmdzIG9mIOKJpCAzIHZlcnRpY2VzLCBvciBhXG4gKiBub24tcG9zaXRpdmUgZXBzaWxvbiwgYXJlIHJldHVybmVkIHVuY2hhbmdlZC4gT3V0cHV0IGtlZXBzIHRoZSBjbG9zZWQtcmluZ1xuICogY29udmVudGlvbiAobm8gcmVwZWF0ZWQgY2xvc2luZyBwb2ludCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaW1wbGlmeVJpbmcoeHM6IG51bWJlcltdLCB5czogbnVtYmVyW10sIGVwc2lsb246IG51bWJlcilcbiAgOiB7IHhzOiBudW1iZXJbXTsgeXM6IG51bWJlcltdIH0ge1xuICBjb25zdCBuID0geHMubGVuZ3RoO1xuICBpZiAobiA8PSAzIHx8ICEoZXBzaWxvbiA+IDApKSByZXR1cm4geyB4czogeHMuc2xpY2UoKSwgeXM6IHlzLnNsaWNlKCkgfTtcblxuICAvLyBDbG9zZSB0aGUgcmluZyBzbyBib3RoIGVuZHBvaW50cyBvZiB0aGUgRFAgcnVuIGFyZSB2ZXJ0ZXggMC5cbiAgY29uc3QgcHggPSBbLi4ueHMsIHhzWzBdXTtcbiAgY29uc3QgcHkgPSBbLi4ueXMsIHlzWzBdXTtcbiAgY29uc3QgbSA9IHB4Lmxlbmd0aDtcbiAgY29uc3Qga2VlcCA9IG5ldyBBcnJheTxib29sZWFuPihtKS5maWxsKGZhbHNlKTtcbiAga2VlcFswXSA9IHRydWU7XG4gIGtlZXBbbSAtIDFdID0gdHJ1ZTtcblxuICBjb25zdCBzdGFjazogQXJyYXk8W251bWJlciwgbnVtYmVyXT4gPSBbWzAsIG0gLSAxXV07XG4gIHdoaWxlIChzdGFjay5sZW5ndGgpIHtcbiAgICBjb25zdCBbYSwgYl0gPSBzdGFjay5wb3AoKSBhcyBbbnVtYmVyLCBudW1iZXJdO1xuICAgIGxldCBtYXhEID0gLTEsIGlkeCA9IC0xO1xuICAgIGZvciAobGV0IGkgPSBhICsgMTsgaSA8IGI7IGkrKykge1xuICAgICAgY29uc3QgZCA9IHBlcnBEaXN0YW5jZShweFtpXSwgcHlbaV0sIHB4W2FdLCBweVthXSwgcHhbYl0sIHB5W2JdKTtcbiAgICAgIGlmIChkID4gbWF4RCkgeyBtYXhEID0gZDsgaWR4ID0gaTsgfVxuICAgIH1cbiAgICBpZiAobWF4RCA+IGVwc2lsb24gJiYgaWR4ID4gYSkge1xuICAgICAga2VlcFtpZHhdID0gdHJ1ZTtcbiAgICAgIHN0YWNrLnB1c2goW2EsIGlkeF0sIFtpZHgsIGJdKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBvdXRYOiBudW1iZXJbXSA9IFtdLCBvdXRZOiBudW1iZXJbXSA9IFtdO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG0gLSAxOyBpKyspIHsgICAgICAvLyBkcm9wIHRoZSBkdXBsaWNhdGVkIGNsb3NpbmcgdmVydGV4XG4gICAgaWYgKGtlZXBbaV0pIHsgb3V0WC5wdXNoKHB4W2ldKTsgb3V0WS5wdXNoKHB5W2ldKTsgfVxuICB9XG4gIHJldHVybiB7IHhzOiBvdXRYLCB5czogb3V0WSB9O1xufVxuIl19