@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,126 @@
1
+ /**
2
+ * Draggable Z-height handle for the napari-js WebGPU volume (jit-ui#102). A small DOM grip is drawn
3
+ * over the 3D canvas at the projected top-face centre of the volume box (reusing the axes-label
4
+ * {@link projectPoint} projection, so it tracks the box as the volume orbits). Dragging it up makes
5
+ * the volume taller, down makes it flatter — the host maps the drag to a Z-scale factor and
6
+ * restretches the volume + axes live (only the model matrix changes; the voxel texture is untouched).
7
+ *
8
+ * Direct-manipulation counterpart of {@link NapariAxesLabels}: both are absolute-positioned overlays
9
+ * updated on every `camera3d.changed`, but this one accepts pointer input.
10
+ */
11
+ import { projectPoint } from './napari-axes-labels';
12
+ const DEFAULTS = { pixelsPerDouble: 180, minScale: 0.1, maxScale: 10 };
13
+ export class NapariVolumeZHandle {
14
+ constructor(host, camera3d, opts) {
15
+ this.host = host;
16
+ this.camera3d = camera3d;
17
+ this.visible = true;
18
+ this.dragging = false;
19
+ this.startY = 0;
20
+ this.startScale = 1;
21
+ this.onPointerDown = (e) => {
22
+ e.preventDefault();
23
+ e.stopPropagation();
24
+ this.dragging = true;
25
+ this.startY = e.clientY;
26
+ this.startScale = this.opts.getScale();
27
+ this.el.setPointerCapture?.(e.pointerId);
28
+ };
29
+ this.onPointerMove = (e) => {
30
+ if (!this.dragging)
31
+ return;
32
+ e.preventDefault();
33
+ e.stopPropagation();
34
+ // Up (negative dy) → taller. Exponential so each `pixelsPerDouble` px doubles/halves the height.
35
+ const dy = e.clientY - this.startY;
36
+ const factor = Math.pow(2, -dy / this.opts.pixelsPerDouble);
37
+ const next = Math.min(this.opts.maxScale, Math.max(this.opts.minScale, this.startScale * factor));
38
+ this.opts.setScale(next);
39
+ this.reposition();
40
+ };
41
+ this.onPointerUp = (e) => {
42
+ if (!this.dragging)
43
+ return;
44
+ this.dragging = false;
45
+ if (this.el.hasPointerCapture?.(e.pointerId))
46
+ this.el.releasePointerCapture?.(e.pointerId);
47
+ };
48
+ this.onDoubleClick = (e) => {
49
+ e.preventDefault();
50
+ e.stopPropagation();
51
+ this.opts.setScale(1);
52
+ this.reposition();
53
+ };
54
+ this.opts = { ...DEFAULTS, ...opts };
55
+ if (getComputedStyle(host).position === 'static')
56
+ host.style.position = 'relative';
57
+ this.el = document.createElement('div');
58
+ Object.assign(this.el.style, {
59
+ position: 'absolute',
60
+ zIndex: '31',
61
+ width: '22px',
62
+ height: '22px',
63
+ marginLeft: '-11px',
64
+ marginTop: '-11px',
65
+ borderRadius: '50%',
66
+ background: 'rgba(102,140,255,0.85)', // matches the Z axis colour (#668cff)
67
+ border: '1.5px solid #fff',
68
+ boxShadow: '0 0 4px rgba(0,0,0,0.6)',
69
+ color: '#fff',
70
+ font: '13px sans-serif',
71
+ lineHeight: '20px',
72
+ textAlign: 'center',
73
+ cursor: 'ns-resize',
74
+ touchAction: 'none',
75
+ userSelect: 'none',
76
+ });
77
+ this.el.textContent = '↕';
78
+ this.el.title = 'Drag to change the volume height (Z). Double-click to reset.';
79
+ this.host.appendChild(this.el);
80
+ this.el.addEventListener('pointerdown', this.onPointerDown);
81
+ this.el.addEventListener('pointermove', this.onPointerMove);
82
+ this.el.addEventListener('pointerup', this.onPointerUp);
83
+ this.el.addEventListener('pointercancel', this.onPointerUp);
84
+ this.el.addEventListener('dblclick', this.onDoubleClick);
85
+ this.disconnectCamera = this.camera3d.changed.connect(() => this.reposition());
86
+ if (typeof ResizeObserver !== 'undefined') {
87
+ this.resizeObserver = new ResizeObserver(() => this.reposition());
88
+ this.resizeObserver.observe(this.host);
89
+ }
90
+ this.reposition();
91
+ }
92
+ setVisible(visible) {
93
+ this.visible = visible;
94
+ this.reposition();
95
+ }
96
+ /** Reproject the handle to the current top-face anchor. Called on camera move, resize, and after
97
+ * the host applies a new scale (so the grip follows the growing/shrinking box). */
98
+ reposition() {
99
+ const vw = this.host.clientWidth;
100
+ const vh = this.host.clientHeight;
101
+ if (!this.visible || vw <= 0 || vh <= 0) {
102
+ this.el.style.display = 'none';
103
+ return;
104
+ }
105
+ const mvp = this.camera3d.viewProjection(vw, vh);
106
+ const s = projectPoint(mvp, this.opts.topAnchor(), vw, vh);
107
+ if (!s.visible) {
108
+ this.el.style.display = 'none';
109
+ return;
110
+ }
111
+ this.el.style.display = '';
112
+ this.el.style.left = `${s.x}px`;
113
+ this.el.style.top = `${s.y}px`;
114
+ }
115
+ destroy() {
116
+ this.disconnectCamera();
117
+ this.resizeObserver?.disconnect();
118
+ this.el.removeEventListener('pointerdown', this.onPointerDown);
119
+ this.el.removeEventListener('pointermove', this.onPointerMove);
120
+ this.el.removeEventListener('pointerup', this.onPointerUp);
121
+ this.el.removeEventListener('pointercancel', this.onPointerUp);
122
+ this.el.removeEventListener('dblclick', this.onDoubleClick);
123
+ this.el.parentNode?.removeChild(this.el);
124
+ }
125
+ }
126
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXZvbHVtZS16LWhhbmRsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvaW1wbGVtZW50YXRpb25zL25hcGFyaS1qcy9uYXBhcmktdm9sdW1lLXotaGFuZGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUNILE9BQU8sRUFBcUIsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFnQnZFLE1BQU0sUUFBUSxHQUFHLEVBQUUsZUFBZSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsQ0FBQztBQUV2RSxNQUFNLE9BQU8sbUJBQW1CO0lBVTlCLFlBQ21CLElBQWlCLEVBQ2pCLFFBQTJCLEVBQzVDLElBQTBCO1FBRlQsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixhQUFRLEdBQVIsUUFBUSxDQUFtQjtRQVB0QyxZQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ2YsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixXQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ1gsZUFBVSxHQUFHLENBQUMsQ0FBQztRQXlFTixrQkFBYSxHQUFHLENBQUMsQ0FBZSxFQUFRLEVBQUU7WUFDekQsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ25CLENBQUMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztZQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDeEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxFQUFFLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDM0MsQ0FBQyxDQUFDO1FBRWUsa0JBQWEsR0FBRyxDQUFDLENBQWUs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QUM7UUFDL0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzVELElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEcmFnZ2FibGUgWi1oZWlnaHQgaGFuZGxlIGZvciB0aGUgbmFwYXJpLWpzIFdlYkdQVSB2b2x1bWUgKGppdC11aSMxMDIpLiBBIHNtYWxsIERPTSBncmlwIGlzIGRyYXduXG4gKiBvdmVyIHRoZSAzRCBjYW52YXMgYXQgdGhlIHByb2plY3RlZCB0b3AtZmFjZSBjZW50cmUgb2YgdGhlIHZvbHVtZSBib3ggKHJldXNpbmcgdGhlIGF4ZXMtbGFiZWxcbiAqIHtAbGluayBwcm9qZWN0UG9pbnR9IHByb2plY3Rpb24sIHNvIGl0IHRyYWNrcyB0aGUgYm94IGFzIHRoZSB2b2x1bWUgb3JiaXRzKS4gRHJhZ2dpbmcgaXQgdXAgbWFrZXNcbiAqIHRoZSB2b2x1bWUgdGFsbGVyLCBkb3duIG1ha2VzIGl0IGZsYXR0ZXIg4oCUIHRoZSBob3N0IG1hcHMgdGhlIGRyYWcgdG8gYSBaLXNjYWxlIGZhY3RvciBhbmRcbiAqIHJlc3RyZXRjaGVzIHRoZSB2b2x1bWUgKyBheGVzIGxpdmUgKG9ubHkgdGhlIG1vZGVsIG1hdHJpeCBjaGFuZ2VzOyB0aGUgdm94ZWwgdGV4dHVyZSBpcyB1bnRvdWNoZWQpLlxuICpcbiAqIERpcmVjdC1tYW5pcHVsYXRpb24gY291bnRlcnBhcnQgb2Yge0BsaW5rIE5hcGFyaUF4ZXNMYWJlbHN9OiBib3RoIGFyZSBhYnNvbHV0ZS1wb3NpdGlvbmVkIG92ZXJsYXlzXG4gKiB1cGRhdGVkIG9uIGV2ZXJ5IGBjYW1lcmEzZC5jaGFuZ2VkYCwgYnV0IHRoaXMgb25lIGFjY2VwdHMgcG9pbnRlciBpbnB1dC5cbiAqL1xuaW1wb3J0IHsgQXhlc0xhYmVsQ2FtZXJhM0QsIHByb2plY3RQb2ludCB9IGZyb20gJy4vbmFwYXJpLWF4ZXMtbGFiZWxzJztcblxuZXhwb3J0IGludGVyZmFjZSBWb2x1bWVaSGFuZGxlT3B0aW9ucyB7XG4gIC8qKiBDdXJyZW50IHRvcC1mYWNlLWNlbnRyZSB3b3JsZCBwb2ludCAodGhlIGJveCBpcyBjZW50cmVkIGF0IHRoZSBvcmlnaW4sIHNvIGBbMCwgMCwgK2hhbGZaXWApLiAqL1xuICB0b3BBbmNob3I6ICgpID0+IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcbiAgLyoqIFRoZSBjdXJyZW50IFotc2NhbGUgZmFjdG9yICgxID0gdGhlIHZvbHVtZSdzIGRlZmF1bHQgcHJvcG9ydGlvbnMpLiAqL1xuICBnZXRTY2FsZTogKCkgPT4gbnVtYmVyO1xuICAvKiogQXBwbHkgYSBuZXcgWi1zY2FsZSBmYWN0b3Ig4oCUIHRoZSBob3N0IHJlc3RyZXRjaGVzIHRoZSB2b2x1bWUgKyBheGVzIGFuZCByZXBvc2l0aW9ucyBvdmVybGF5cy4gKi9cbiAgc2V0U2NhbGU6IChzY2FsZTogbnVtYmVyKSA9PiB2b2lkO1xuICAvKiogVmVydGljYWwgZHJhZyAocHgpIGZvciBvbmUgZG91YmxpbmcvaGFsdmluZyBvZiB0aGUgWiBoZWlnaHQuIExhcmdlciA9IGxlc3Mgc2Vuc2l0aXZlLiAqL1xuICBwaXhlbHNQZXJEb3VibGU/OiBudW1iZXI7XG4gIC8qKiBDbGFtcCBmb3IgdGhlIFotc2NhbGUgZmFjdG9yLiAqL1xuICBtaW5TY2FsZT86IG51bWJlcjtcbiAgbWF4U2NhbGU/OiBudW1iZXI7XG59XG5cbmNvbnN0IERFRkFVTFRTID0geyBwaXhlbHNQZXJEb3VibGU6IDE4MCwgbWluU2NhbGU6IDAuMSwgbWF4U2NhbGU6IDEwIH07XG5cbmV4cG9ydCBjbGFzcyBOYXBhcmlWb2x1bWVaSGFuZGxlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBlbDogSFRNTERpdkVsZW1lbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGlzY29ubmVjdENhbWVyYTogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSByZXNpemVPYnNlcnZlcj86IFJlc2l6ZU9ic2VydmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IG9wdHM6IFJlcXVpcmVkPFZvbHVtZVpIYW5kbGVPcHRpb25zPjtcbiAgcHJpdmF0ZSB2aXNpYmxlID0gdHJ1ZTtcbiAgcHJpdmF0ZSBkcmFnZ2luZyA9IGZhbHNlO1xuICBwcml2YXRlIHN0YXJ0WSA9IDA7XG4gIHByaXZhdGUgc3RhcnRTY2FsZSA9IDE7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBob3N0OiBIVE1MRWxlbWVudCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNhbWVyYTNkOiBBeGVzTGFiZWxDYW1lcmEzRCxcbiAgICBvcHRzOiBWb2x1bWVaSGFuZGxlT3B0aW9ucyxcbiAgKSB7XG4gICAgdGhpcy5vcHRzID0geyAuLi5ERUZBVUxUUywgLi4ub3B0cyB9O1xuICAgIGlmIChnZXRDb21wdXRlZFN0eWxlKGhvc3QpLnBvc2l0aW9uID09PSAnc3RhdGljJykgaG9zdC5zdHlsZS5wb3NpdGlvbiA9ICdyZWxhdGl2ZSc7XG5cbiAgICB0aGlzLmVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLmVsLnN0eWxlLCB7XG4gICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgIHpJbmRleDogJzMxJyxcbiAgICAgIHdpZHRoOiAnMjJweCcsXG4gICAgICBoZWlnaHQ6ICcyMnB4JyxcbiAgICAgIG1hcmdpbkxlZnQ6ICctMTFweCcsXG4gICAgICBtYXJnaW5Ub3A6ICctMTFweCcsXG4gICAgICBib3JkZXJSYWRpdXM6ICc1MCUnLFxuICAgICAgYmFja2dyb3VuZDogJ3JnYmEoMTAyLDE0MCwyNTUsMC44NSknLCAvLyBtYXRjaGVzIHRoZSBaIGF4aXMgY29sb3VyICgjNjY4Y2ZmKVxuICAgICAgYm9yZGVyOiAnMS41cHggc29saWQgI2ZmZicsXG4gICAgICBib3hTaGFkb3c6ICcwIDAgNHB4IHJnYmEoMCwwLDAsMC42KScsXG4gICAgICBjb2xvcjogJyNmZmYnLFxuICAgICAgZm9udDogJzEzcHggc2Fucy1zZXJpZicsXG4gICAgICBsaW5lSGVpZ2h0OiAnMjBweCcsXG4gICAgICB0ZXh0QWxpZ246ICdjZW50ZXInLFxuICAgICAgY3Vyc29yOiAnbnMtcmVzaXplJyxcbiAgICAgIHRvdWNoQWN0aW9uOiAnbm9uZScsXG4gICAgICB1c2VyU2VsZWN0OiAnbm9uZScsXG4gICAgfSBhcyBQYXJ0aWFsPENTU1N0eWxlRGVjbGFyYXRpb24+KTtcbiAgICB0aGlzLmVsLnRleHRDb250ZW50ID0gJ+KGlSc7XG4gICAgdGhpcy5lbC50aXRsZSA9ICdEcmFnIHRvIGNoYW5nZSB0aGUgdm9sdW1lIGhlaWdodCAoWikuIERvdWJsZS1jbGljayB0byByZXNldC4nO1xuICAgIHRoaXMuaG9zdC5hcHBlbmRDaGlsZCh0aGlzLmVsKTtcblxuICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcmRvd24nLCB0aGlzLm9uUG9pbnRlckRvd24pO1xuICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCB0aGlzLm9uUG9pbnRlck1vdmUpO1xuICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywgdGhpcy5vblBvaW50ZXJVcCk7XG4gICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyY2FuY2VsJywgdGhpcy5vblBvaW50ZXJVcCk7XG4gICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIHRoaXMub25Eb3VibGVDbGljayk7XG5cbiAgICB0aGlzLmRpc2Nvbm5lY3RDYW1lcmEgPSB0aGlzLmNhbWVyYTNkLmNoYW5nZWQuY29ubmVjdCgoKSA9PiB0aGlzLnJlcG9zaXRpb24oKSk7XG4gICAgaWYgKHR5cGVvZiBSZXNpemVPYnNlcnZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHRoaXMucmVzaXplT2JzZXJ2ZXIgPSBuZXcgUmVzaXplT2JzZXJ2ZXIoKCkgPT4gdGhpcy5yZXBvc2l0aW9uKCkpO1xuICAgICAgdGhpcy5yZXNpemVPYnNlcnZlci5vYnNlcnZlKHRoaXMuaG9zdCk7XG4gICAgfVxuICAgIHRoaXMucmVwb3NpdGlvbigpO1xuICB9XG5cbiAgc2V0VmlzaWJsZSh2aXNpYmxlOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy52aXNpYmxlID0gdmlzaWJsZTtcbiAgICB0aGlzLnJlcG9zaXRpb24oKTtcbiAgfVxuXG4gIC8qKiBSZXByb2plY3QgdGhlIGhhbmRsZSB0byB0aGUgY3VycmVudCB0b3AtZmFjZSBhbmNob3IuIENhbGxlZCBvbiBjYW1lcmEgbW92ZSwgcmVzaXplLCBhbmQgYWZ0ZXJcbiAgICogIHRoZSBob3N0IGFwcGxpZXMgYSBuZXcgc2NhbGUgKHNvIHRoZSBncmlwIGZvbGxvd3MgdGhlIGdyb3dpbmcvc2hyaW5raW5nIGJveCkuICovXG4gIHJlcG9zaXRpb24oKTogdm9pZCB7XG4gICAgY29uc3QgdncgPSB0aGlzLmhvc3QuY2xpZW50V2lkdGg7XG4gICAgY29uc3QgdmggPSB0aGlzLmhvc3QuY2xpZW50SGVpZ2h0O1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHZ3IDw9IDAgfHwgdmggPD0gMCkge1xuICAgICAgdGhpcy5lbC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBtdnAgPSB0aGlzLmNhbWVyYTNkLnZpZXdQcm9qZWN0aW9uKHZ3LCB2aCk7XG4gICAgY29uc3QgcyA9IHByb2plY3RQb2ludChtdnAsIHRoaXMub3B0cy50b3BBbmNob3IoKSwgdncsIHZoKTtcbiAgICBpZiAoIXMudmlzaWJsZSkge1xuICAgICAgdGhpcy5lbC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmVsLnN0eWxlLmRpc3BsYXkgPSAnJztcbiAgICB0aGlzLmVsLnN0eWxlLmxlZnQgPSBgJHtzLnh9cHhgO1xuICAgIHRoaXMuZWwuc3R5bGUudG9wID0gYCR7cy55fXB4YDtcbiAgfVxuXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyRG93biA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB0aGlzLmRyYWdnaW5nID0gdHJ1ZTtcbiAgICB0aGlzLnN0YXJ0WSA9IGUuY2xpZW50WTtcbiAgICB0aGlzLnN0YXJ0U2NhbGUgPSB0aGlzLm9wdHMuZ2V0U2NhbGUoKTtcbiAgICB0aGlzLmVsLnNldFBvaW50ZXJDYXB0dXJlPy4oZS5wb2ludGVySWQpO1xuICB9O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyTW92ZSA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBpZiAoIXRoaXMuZHJhZ2dpbmcpIHJldHVybjtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAvLyBVcCAobmVnYXRpdmUgZHkpIOKGkiB0YWxsZXIuIEV4cG9uZW50aWFsIHNvIGVhY2ggYHBpeGVsc1BlckRvdWJsZWAgcHggZG91Ymxlcy9oYWx2ZXMgdGhlIGhlaWdodC5cbiAgICBjb25zdCBkeSA9IGUuY2xpZW50WSAtIHRoaXMuc3RhcnRZO1xuICAgIGNvbnN0IGZhY3RvciA9IE1hdGgucG93KDIsIC1keSAvIHRoaXMub3B0cy5waXhlbHNQZXJEb3VibGUpO1xuICAgIGNvbnN0IG5leHQgPSBNYXRoLm1pbihcbiAgICAgIHRoaXMub3B0cy5tYXhTY2FsZSxcbiAgICAgIE1hdGgubWF4KHRoaXMub3B0cy5taW5TY2FsZSwgdGhpcy5zdGFydFNjYWxlICogZmFjdG9yKSxcbiAgICApO1xuICAgIHRoaXMub3B0cy5zZXRTY2FsZShuZXh0KTtcbiAgICB0aGlzLnJlcG9zaXRpb24oKTtcbiAgfTtcblxuICBwcml2YXRlIHJlYWRvbmx5IG9uUG9pbnRlclVwID0gKGU6IFBvaW50ZXJFdmVudCk6IHZvaWQgPT4ge1xuICAgIGlmICghdGhpcy5kcmFnZ2luZykgcmV0dXJuO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgICBpZiAodGhpcy5lbC5oYXNQb2ludGVyQ2FwdHVyZT8uKGUucG9pbnRlcklkKSkgdGhpcy5lbC5yZWxlYXNlUG9pbnRlckNhcHR1cmU/LihlLnBvaW50ZXJJZCk7XG4gIH07XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvbkRvdWJsZUNsaWNrID0gKGU6IE1vdXNlRXZlbnQpOiB2b2lkID0+IHtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB0aGlzLm9wdHMuc2V0U2NhbGUoMSk7XG4gICAgdGhpcy5yZXBvc2l0aW9uKCk7XG4gIH07XG5cbiAgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRpc2Nvbm5lY3RDYW1lcmEoKTtcbiAgICB0aGlzLnJlc2l6ZU9ic2VydmVyPy5kaXNjb25uZWN0KCk7XG4gICAgdGhpcy5lbC5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsIHRoaXMub25Qb2ludGVyRG93bik7XG4gICAgdGhpcy5lbC5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIHRoaXMub25Qb2ludGVyTW92ZSk7XG4gICAgdGhpcy5lbC5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVydXAnLCB0aGlzLm9uUG9pbnRlclVwKTtcbiAgICB0aGlzLmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJjYW5jZWwnLCB0aGlzLm9uUG9pbnRlclVwKTtcbiAgICB0aGlzLmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgdGhpcy5vbkRvdWJsZUNsaWNrKTtcbiAgICB0aGlzLmVsLnBhcmVudE5vZGU/LnJlbW92ZUNoaWxkKHRoaXMuZWwpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,143 @@
1
+ export class DisplayPipeline {
2
+ constructor(host) {
3
+ this.host = host;
4
+ }
5
+ /**
6
+ * Apply the current display pipeline to an RGBA buffer in place; returns
7
+ * whether any opaque pixel was written.
8
+ * - Grayscale: intensity → window + gamma + invert → colormap LUT.
9
+ * - RGB/multichannel: additive pseudo-colour merge — each visible channel's
10
+ * windowed intensity is tinted by its assigned colour and summed (Fiji
11
+ * "Merge Channels"). Defaults (R=red, G=green, B=blue) are the identity.
12
+ */
13
+ applyToRgba(d) {
14
+ let changed = false;
15
+ const channelStates = this.host.channelStates();
16
+ const invertBg = this.host.invertBg();
17
+ if (this.host.isGrayscale()) {
18
+ const lut = this.host.colorLut();
19
+ if (!lut)
20
+ return false;
21
+ const ch = channelStates[0];
22
+ const wMin = ch ? ch.min : 0;
23
+ const wSpan = ch && ch.max > ch.min ? ch.max - ch.min : 255;
24
+ const invGamma = ch && ch.gamma > 0 ? 1 / ch.gamma : 1;
25
+ // Precompute raw(0..255) -> final RGB once (256 window+gamma+invert+colormap
26
+ // evaluations) and map each pixel by table lookup — a Math.pow per pixel
27
+ // (~262k/tile) made the window/gamma sliders crawl on large stacks.
28
+ const rL = new Uint8ClampedArray(256);
29
+ const gL = new Uint8ClampedArray(256);
30
+ const bL = new Uint8ClampedArray(256);
31
+ for (let raw = 0; raw < 256; raw++) {
32
+ let t = (raw - wMin) / wSpan;
33
+ t = t < 0 ? 0 : t > 1 ? 1 : t;
34
+ if (invGamma !== 1)
35
+ t = Math.pow(t, invGamma);
36
+ let v = Math.round(t * 255);
37
+ if (invertBg)
38
+ v = 255 - v;
39
+ const c = lut[v];
40
+ rL[raw] = c[0];
41
+ gL[raw] = c[1];
42
+ bL[raw] = c[2];
43
+ }
44
+ for (let i = 0; i < d.length; i += 4) {
45
+ if (d[i + 3] === 0)
46
+ continue;
47
+ // maxRgb (contracts/intensity) inlined on purpose: this loop runs
48
+ // ~262k times per tile on every recolor.
49
+ const raw = d[i] >= d[i + 1] ? (d[i] >= d[i + 2] ? d[i] : d[i + 2]) : d[i + 1] >= d[i + 2] ? d[i + 1] : d[i + 2];
50
+ d[i] = rL[raw];
51
+ d[i + 1] = gL[raw];
52
+ d[i + 2] = bL[raw];
53
+ changed = true;
54
+ }
55
+ }
56
+ else {
57
+ const chans = [channelStates[0], channelStates[1], channelStates[2]];
58
+ const tints = chans.map((c) => this.tint01(c));
59
+ for (let i = 0; i < d.length; i += 4) {
60
+ if (d[i + 3] === 0)
61
+ continue;
62
+ let oR = 0, oG = 0, oB = 0;
63
+ for (let k = 0; k < 3; k++) {
64
+ const c = chans[k];
65
+ if (c && !c.visible)
66
+ continue;
67
+ const v = this.channelIntensity(d[i + k], c);
68
+ const tint = tints[k];
69
+ oR += v * tint[0];
70
+ oG += v * tint[1];
71
+ oB += v * tint[2];
72
+ }
73
+ if (oR > 255)
74
+ oR = 255;
75
+ if (oG > 255)
76
+ oG = 255;
77
+ if (oB > 255)
78
+ oB = 255;
79
+ if (invertBg) {
80
+ oR = 255 - oR;
81
+ oG = 255 - oG;
82
+ oB = 255 - oB;
83
+ }
84
+ d[i] = oR;
85
+ d[i + 1] = oG;
86
+ d[i + 2] = oB;
87
+ changed = true;
88
+ }
89
+ }
90
+ return changed;
91
+ }
92
+ /** Precomputed lum(0..255) → tinted-RGB lookup for a channel's window/gamma/
93
+ * colour. Building it costs 256 channelIntensity() calls; using it makes a
94
+ * full-tile recolor ~262k array lookups instead of ~262k Math.pow() calls. */
95
+ channelRgbLut(st) {
96
+ const r = new Uint8ClampedArray(256);
97
+ const g = new Uint8ClampedArray(256);
98
+ const b = new Uint8ClampedArray(256);
99
+ const [tr, tg, tb] = this.tint01(st);
100
+ for (let lum = 0; lum < 256; lum++) {
101
+ const v = this.channelIntensity(lum, st);
102
+ r[lum] = v * tr;
103
+ g[lum] = v * tg;
104
+ b[lum] = v * tb;
105
+ }
106
+ return { r, g, b };
107
+ }
108
+ /** Windowed + gamma intensity (0..255) for a channel, ignoring tint/invert. */
109
+ channelIntensity(val, c) {
110
+ if (!c)
111
+ return val;
112
+ const span = c.max > c.min ? c.max - c.min : 0;
113
+ if (!span)
114
+ return 0;
115
+ let t = (val - c.min) / span;
116
+ t = t < 0 ? 0 : t > 1 ? 1 : t;
117
+ if (c.gamma > 0 && c.gamma !== 1)
118
+ t = Math.pow(t, 1 / c.gamma);
119
+ return t * 255;
120
+ }
121
+ /** A channel's pseudo-colour tint as [r,g,b] in 0..1 (default white). */
122
+ tint01(c) {
123
+ const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c?.color ?? '');
124
+ return m ? [parseInt(m[1], 16) / 255, parseInt(m[2], 16) / 255, parseInt(m[3], 16) / 255] : [1, 1, 1];
125
+ }
126
+ /** True when any RGB channel is windowed/hidden/gamma'd/re-tinted or the
127
+ * background is inverted — otherwise the tile passes through unchanged. */
128
+ rgbNeedsRecolor() {
129
+ if (this.host.invertBg())
130
+ return true;
131
+ const defaults = ['#ff0000', '#00ff00', '#0000ff'];
132
+ const channelStates = this.host.channelStates();
133
+ for (let k = 0; k < 3; k++) {
134
+ const c = channelStates[k];
135
+ if (c && (!c.visible || c.min !== 0 || c.max !== 255 || c.gamma !== 1 ||
136
+ (c.color || '').toLowerCase() !== defaults[k])) {
137
+ return true;
138
+ }
139
+ }
140
+ return false;
141
+ }
142
+ }
143
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzcGxheS1waXBlbGluZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvaW1wbGVtZW50YXRpb25zL29zZC9kaXNwbGF5LXBpcGVsaW5lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXFCQSxNQUFNLE9BQU8sZUFBZTtJQUMxQixZQUFvQixJQUF5QjtRQUF6QixTQUFJLEdBQUosSUFBSSxDQUFxQjtJQUFHLENBQUM7SUFFakQ7Ozs7Ozs7T0FPRztJQUNILFdBQVcsQ0FBQyxDQUFvQjtRQUM5QixJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7UUFDcEIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNoRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3RDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDakMsSUFBSSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxLQUFLLENBQUM7WUFDdkIsTUFBTSxFQUFFLEdBQUcsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzdCLE1BQU0sS0FBSyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQzVELE1BQU0sUUFBUSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENB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QUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsV0FBVyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQ2hELENBQUM7Z0JBQ0QsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSUNoYW5uZWxTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jaGFubmVsLWhpc3RvZ3JhbS1hcGkuY29udHJhY3QnO1xuaW1wb3J0IHsgUmdiIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NvbG9ybWFwLWx1dCc7XG5cbi8qKlxuICogVGhlIE9TRCBwaXhlbCBkaXNwbGF5IHBpcGVsaW5lIChyZWZhY3RvcmluZyBwbGFuLCBTdGVwIDQg4oCUIGEgcHVyZSBtb3ZlIG9mXG4gKiB0aGUgcmVjb2xvciBtYXRoIG91dCBvZiB0aGUgdmlzdWFsaXplciBzZXJ2aWNlKS4gU3RhdGVsZXNzOiBldmVyeSBjYWxsIHJlYWRzXG4gKiB0aGUgY3VycmVudCBkaXNwbGF5IHN0YXRlIHRocm91Z2ggdGhlIGhvc3QgY2xvc3VyZXMsIGV4YWN0bHkgbGlrZSB0aGUgbW92ZWRcbiAqIGNvZGUgcmVhZCB0aGUgc2VydmljZSdzIGZpZWxkcy4gU2hhcmVkIGJ5IHRpbGUgcmVjb2xvcmluZyBhbmQgdGhlIGNvbXBvc2l0ZVxuICogZXhwb3J0IHNvIHRoZXkgc3RheSBpZGVudGljYWwuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGlzcGxheVBpcGVsaW5lSG9zdCB7XG4gIC8qKiBHcmF5c2NhbGUgaW1hZ2UgKGNvbG9ybWFwIExVVCBwYXRoKSB2cyBSR0IvbXVsdGljaGFubmVsIChhZGRpdGl2ZSB0aW50KS4gKi9cbiAgaXNHcmF5c2NhbGUoKTogYm9vbGVhbjtcbiAgLyoqIDI1Ni1lbnRyeSBjb2xvcm1hcCBMVVQgKGdyYXlzY2FsZSBwYXRoKTsgbnVsbCB3aGlsZSBvcHRpb25zIHJlc29sdmUuICovXG4gIGNvbG9yTHV0KCk6IFJnYltdIHwgbnVsbDtcbiAgLyoqIExhdGVzdCBwZXItY2hhbm5lbCBkaXNwbGF5IHN0YXRlIGZyb20gdGhlIHN0b3JlLiAqL1xuICBjaGFubmVsU3RhdGVzKCk6IElDaGFubmVsU3RhdGVbXTtcbiAgLyoqIEludmVydGVkIGJhY2tncm91bmQgKHdoaXRlID0gemVybykuICovXG4gIGludmVydEJnKCk6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBEaXNwbGF5UGlwZWxpbmUge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGhvc3Q6IERpc3BsYXlQaXBlbGluZUhvc3QpIHt9XG5cbiAgLyoqXG4gICAqIEFwcGx5IHRoZSBjdXJyZW50IGRpc3BsYXkgcGlwZWxpbmUgdG8gYW4gUkdCQSBidWZmZXIgaW4gcGxhY2U7IHJldHVybnNcbiAgICogd2hldGhlciBhbnkgb3BhcXVlIHBpeGVsIHdhcyB3cml0dGVuLlxuICAgKiAgLSBHcmF5c2NhbGU6IGludGVuc2l0eSDihpIgd2luZG93ICsgZ2FtbWEgKyBpbnZlcnQg4oaSIGNvbG9ybWFwIExVVC5cbiAgICogIC0gUkdCL211bHRpY2hhbm5lbDogYWRkaXRpdmUgcHNldWRvLWNvbG91ciBtZXJnZSDigJQgZWFjaCB2aXNpYmxlIGNoYW5uZWwnc1xuICAgKiAgICB3aW5kb3dlZCBpbnRlbnNpdHkgaXMgdGludGVkIGJ5IGl0cyBhc3NpZ25lZCBjb2xvdXIgYW5kIHN1bW1lZCAoRmlqaVxuICAgKiAgICBcIk1lcmdlIENoYW5uZWxzXCIpLiBEZWZhdWx0cyAoUj1yZWQsIEc9Z3JlZW4sIEI9Ymx1ZSkgYXJlIHRoZSBpZGVudGl0eS5cbiAgICovXG4gIGFwcGx5VG9SZ2JhKGQ6IFVpbnQ4Q2xhbXBlZEFycmF5KTogYm9vbGVhbiB7XG4gICAgbGV0IGNoYW5nZWQgPSBmYWxzZTtcbiAgICBjb25zdCBjaGFubmVsU3RhdGVzID0gdGhpcy5ob3N0LmNoYW5uZWxTdGF0ZXMoKTtcbiAgICBjb25zdCBpbnZlcnRCZyA9IHRoaXMuaG9zdC5pbnZlcnRCZygpO1xuICAgIGlmICh0aGlzLmhvc3QuaXNHcmF5c2NhbGUoKSkge1xuICAgICAgY29uc3QgbHV0ID0gdGhpcy5ob3N0LmNvbG9yTHV0KCk7XG4gICAgICBpZiAoIWx1dCkgcmV0dXJuIGZhbHNlO1xuICAgICAgY29uc3QgY2ggPSBjaGFubmVsU3RhdGVzWzBdO1xuICAgICAgY29uc3Qgd01pbiA9IGNoID8gY2gubWluIDogMDtcbiAgICAgIGNvbnN0IHdTcGFuID0gY2ggJiYgY2gubWF4ID4gY2gubWluID8gY2gubWF4IC0gY2gubWluIDogMjU1O1xuICAgICAgY29uc3QgaW52R2FtbWEgPSBjaCAmJiBjaC5nYW1tYSA+IDAgPyAxIC8gY2guZ2FtbWEgOiAxO1xuICAgICAgLy8gUHJlY29tcHV0ZSByYXcoMC4uMjU1KSAtPiBmaW5hbCBSR0Igb25jZSAoMjU2IHdpbmRvdytnYW1tYStpbnZlcnQrY29sb3JtYXBcbiAgICAgIC8vIGV2YWx1YXRpb25zKSBhbmQgbWFwIGVhY2ggcGl4ZWwgYnkgdGFibGUgbG9va3VwIOKAlCBhIE1hdGgucG93IHBlciBwaXhlbFxuICAgICAgLy8gKH4yNjJrL3RpbGUpIG1hZGUgdGhlIHdpbmRvdy9nYW1tYSBzbGlkZXJzIGNyYXdsIG9uIGxhcmdlIHN0YWNrcy5cbiAgICAgIGNvbnN0IHJMID0gbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KDI1Nik7XG4gICAgICBjb25zdCBnTCA9IG5ldyBVaW50OENsYW1wZWRBcnJheSgyNTYpO1xuICAgICAgY29uc3QgYkwgPSBuZXcgVWludDhDbGFtcGVkQXJyYXkoMjU2KTtcbiAgICAgIGZvciAobGV0IHJhdyA9IDA7IHJhdyA8IDI1NjsgcmF3KyspIHtcbiAgICAgICAgbGV0IHQgPSAocmF3IC0gd01pbikgLyB3U3BhbjtcbiAgICAgICAgdCA9IHQgPCAwID8gMCA6IHQgPiAxID8gMSA6IHQ7XG4gICAgICAgIGlmIChpbnZHYW1tYSAhPT0gMSkgdCA9IE1hdGgucG93KHQsIGludkdhbW1hKTtcbiAgICAgICAgbGV0IHYgPSBNYXRoLnJvdW5kKHQgKiAyNTUpO1xuICAgICAgICBpZiAoaW52ZXJ0QmcpIHYgPSAyNTUgLSB2O1xuICAgICAgICBjb25zdCBjID0gbHV0W3ZdO1xuICAgICAgICByTFtyYXddID0gY1swXTtcbiAgICAgICAgZ0xbcmF3XSA9IGNbMV07XG4gICAgICAgIGJMW3Jhd10gPSBjWzJdO1xuICAgICAgfVxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgIGlmIChkW2kgKyAzXSA9PT0gMCkgY29udGludWU7XG4gICAgICAgIC8vIG1heFJnYiAoY29udHJhY3RzL2ludGVuc2l0eSkgaW5saW5lZCBvbiBwdXJwb3NlOiB0aGlzIGxvb3AgcnVuc1xuICAgICAgICAvLyB+MjYyayB0aW1lcyBwZXIgdGlsZSBvbiBldmVyeSByZWNvbG9yLlxuICAgICAgICBjb25zdCByYXcgPVxuICAgICAgICAgIGRbaV0gPj0gZFtpICsgMV0gPyAoZFtpXSA+PSBkW2kgKyAyXSA/IGRbaV0gOiBkW2kgKyAyXSkgOiBkW2kgKyAxXSA+PSBkW2kgKyAyXSA/IGRbaSArIDFdIDogZFtpICsgMl07XG4gICAgICAgIGRbaV0gPSByTFtyYXddO1xuICAgICAgICBkW2kgKyAxXSA9IGdMW3Jhd107XG4gICAgICAgIGRbaSArIDJdID0gYkxbcmF3XTtcbiAgICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGNoYW5zID0gW2NoYW5uZWxTdGF0ZXNbMF0sIGNoYW5uZWxTdGF0ZXNbMV0sIGNoYW5uZWxTdGF0ZXNbMl1dO1xuICAgICAgY29uc3QgdGludHMgPSBjaGFucy5tYXAoKGMpID0+IHRoaXMudGludDAxKGMpKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZC5sZW5ndGg7IGkgKz0gNCkge1xuICAgICAgICBpZiAoZFtpICsgM10gPT09IDApIGNvbnRpbnVlO1xuICAgICAgICBsZXQgb1IgPSAwLCBvRyA9IDAsIG9CID0gMDtcbiAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCAzOyBrKyspIHtcbiAgICAgICAgICBjb25zdCBjID0gY2hhbnNba107XG4gICAgICAgICAgaWYgKGMgJiYgIWMudmlzaWJsZSkgY29udGludWU7XG4gICAgICAgICAgY29uc3QgdiA9IHRoaXMuY2hhbm5lbEludGVuc2l0eShkW2kgKyBrXSwgYyk7XG4gICAgICAgICAgY29uc3QgdGludCA9IHRpbnRzW2tdO1xuICAgICAgICAgIG9SICs9IHYgKiB0aW50WzBdO1xuICAgICAgICAgIG9HICs9IHYgKiB0aW50WzFdO1xuICAgICAgICAgIG9CICs9IHYgKiB0aW50WzJdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvUiA+IDI1NSkgb1IgPSAyNTU7XG4gICAgICAgIGlmIChvRyA+IDI1NSkgb0cgPSAyNTU7XG4gICAgICAgIGlmIChvQiA+IDI1NSkgb0IgPSAyNTU7XG4gICAgICAgIGlmIChpbnZlcnRCZykgeyBvUiA9IDI1NSAtIG9SOyBvRyA9IDI1NSAtIG9HOyBvQiA9IDI1NSAtIG9COyB9XG4gICAgICAgIGRbaV0gPSBvUjtcbiAgICAgICAgZFtpICsgMV0gPSBvRztcbiAgICAgICAgZFtpICsgMl0gPSBvQjtcbiAgICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjaGFuZ2VkO1xuICB9XG5cbiAgLyoqIFByZWNvbXB1dGVkIGx1bSgwLi4yNTUpIOKGkiB0aW50ZWQtUkdCIGxvb2t1cCBmb3IgYSBjaGFubmVsJ3Mgd2luZG93L2dhbW1hL1xuICAgKiAgY29sb3VyLiBCdWlsZGluZyBpdCBjb3N0cyAyNTYgY2hhbm5lbEludGVuc2l0eSgpIGNhbGxzOyB1c2luZyBpdCBtYWtlcyBhXG4gICAqICBmdWxsLXRpbGUgcmVjb2xvciB+MjYyayBhcnJheSBsb29rdXBzIGluc3RlYWQgb2YgfjI2MmsgTWF0aC5wb3coKSBjYWxscy4gKi9cbiAgY2hhbm5lbFJnYkx1dChzdD86IElDaGFubmVsU3RhdGUpOiB7IHI6IFVpbnQ4Q2xhbXBlZEFycmF5OyBnOiBVaW50OENsYW1wZWRBcnJheTsgYjogVWludDhDbGFtcGVkQXJyYXkgfSB7XG4gICAgY29uc3QgciA9IG5ldyBVaW50OENsYW1wZWRBcnJheSgyNTYpO1xuICAgIGNvbnN0IGcgPSBuZXcgVWludDhDbGFtcGVkQXJyYXkoMjU2KTtcbiAgICBjb25zdCBiID0gbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KDI1Nik7XG4gICAgY29uc3QgW3RyLCB0ZywgdGJdID0gdGhpcy50aW50MDEoc3QpO1xuICAgIGZvciAobGV0IGx1bSA9IDA7IGx1bSA8IDI1NjsgbHVtKyspIHtcbiAgICAgIGNvbnN0IHYgPSB0aGlzLmNoYW5uZWxJbnRlbnNpdHkobHVtLCBzdCk7XG4gICAgICByW2x1bV0gPSB2ICogdHI7XG4gICAgICBnW2x1bV0gPSB2ICogdGc7XG4gICAgICBiW2x1bV0gPSB2ICogdGI7XG4gICAgfVxuICAgIHJldHVybiB7IHIsIGcsIGIgfTtcbiAgfVxuXG4gIC8qKiBXaW5kb3dlZCArIGdhbW1hIGludGVuc2l0eSAoMC4uMjU1KSBmb3IgYSBjaGFubmVsLCBpZ25vcmluZyB0aW50L2ludmVydC4gKi9cbiAgY2hhbm5lbEludGVuc2l0eSh2YWw6IG51bWJlciwgYz86IElDaGFubmVsU3RhdGUpOiBudW1iZXIge1xuICAgIGlmICghYykgcmV0dXJuIHZhbDtcbiAgICBjb25zdCBzcGFuID0gYy5tYXggPiBjLm1pbiA/IGMubWF4IC0gYy5taW4gOiAwO1xuICAgIGlmICghc3BhbikgcmV0dXJuIDA7XG4gICAgbGV0IHQgPSAodmFsIC0gYy5taW4pIC8gc3BhbjtcbiAgICB0ID0gdCA8IDAgPyAwIDogdCA+IDEgPyAxIDogdDtcbiAgICBpZiAoYy5nYW1tYSA+IDAgJiYgYy5nYW1tYSAhPT0gMSkgdCA9IE1hdGgucG93KHQsIDEgLyBjLmdhbW1hKTtcbiAgICByZXR1cm4gdCAqIDI1NTtcbiAgfVxuXG4gIC8qKiBBIGNoYW5uZWwncyBwc2V1ZG8tY29sb3VyIHRpbnQgYXMgW3IsZyxiXSBpbiAwLi4xIChkZWZhdWx0IHdoaXRlKS4gKi9cbiAgdGludDAxKGM/OiBJQ2hhbm5lbFN0YXRlKTogW251bWJlciwgbnVtYmVyLCBudW1iZXJdIHtcbiAgICBjb25zdCBtID0gL14jPyhbYS1mXFxkXXsyfSkoW2EtZlxcZF17Mn0pKFthLWZcXGRdezJ9KSQvaS5leGVjKGM/LmNvbG9yID8/ICcnKTtcbiAgICByZXR1cm4gbSA/IFtwYXJzZUludChtWzFdLCAxNikgLyAyNTUsIHBhcnNlSW50KG1bMl0sIDE2KSAvIDI1NSwgcGFyc2VJbnQobVszXSwgMTYpIC8gMjU1XSA6IFsxLCAxLCAxXTtcbiAgfVxuXG4gIC8qKiBUcnVlIHdoZW4gYW55IFJHQiBjaGFubmVsIGlzIHdpbmRvd2VkL2hpZGRlbi9nYW1tYSdkL3JlLXRpbnRlZCBvciB0aGVcbiAgICogIGJhY2tncm91bmQgaXMgaW52ZXJ0ZWQg4oCUIG90aGVyd2lzZSB0aGUgdGlsZSBwYXNzZXMgdGhyb3VnaCB1bmNoYW5nZWQuICovXG4gIHJnYk5lZWRzUmVjb2xvcigpOiBib29sZWFuIHtcbiAgICBpZiAodGhpcy5ob3N0LmludmVydEJnKCkpIHJldHVybiB0cnVlO1xuICAgIGNvbnN0IGRlZmF1bHRzID0gWycjZmYwMDAwJywgJyMwMGZmMDAnLCAnIzAwMDBmZiddO1xuICAgIGNvbnN0IGNoYW5uZWxTdGF0ZXMgPSB0aGlzLmhvc3QuY2hhbm5lbFN0YXRlcygpO1xuICAgIGZvciAobGV0IGsgPSAwOyBrIDwgMzsgaysrKSB7XG4gICAgICBjb25zdCBjID0gY2hhbm5lbFN0YXRlc1trXTtcbiAgICAgIGlmIChcbiAgICAgICAgYyAmJiAoIWMudmlzaWJsZSB8fCBjLm1pbiAhPT0gMCB8fCBjLm1heCAhPT0gMjU1IHx8IGMuZ2FtbWEgIT09IDEgfHxcbiAgICAgICAgICAoYy5jb2xvciB8fCAnJykudG9Mb3dlckNhc2UoKSAhPT0gZGVmYXVsdHNba10pXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19
@@ -0,0 +1,217 @@
1
+ import { firstValueFrom, from, of } from 'rxjs';
2
+ import { timeout } from 'rxjs/operators';
3
+ import { buildTileUrl, fetchTileRgba } from './tile-client';
4
+ import { histogram256, maxRgb } from '../../contracts/intensity';
5
+ export class HistogramSampler {
6
+ constructor(http, api, host) {
7
+ this.http = http;
8
+ this.api = api;
9
+ this.host = host;
10
+ /** 256-bin intensity histogram per z-slice, from sampled tiles. */
11
+ this.sliceHistograms = new Map();
12
+ /** Native-bit-depth histograms from `/histogram`, keyed `${z}|${channel}`. */
13
+ this.nativeHistograms = new Map();
14
+ /** Per-app-load cache-buster for `/histogram` — the server marks the
15
+ * response cacheable for 24h, and a hard refresh can't bust a post-load
16
+ * XHR. A token stable within a session but new on each full load keeps the
17
+ * in-session dedup (via `nativeHistograms`) while always reflecting the
18
+ * live backend after a reload. */
19
+ this.histCacheBuster = Date.now();
20
+ }
21
+ /** The sampled histogram for one channel of slice z, or null until the
22
+ * async sampling resolves (or if it was skipped). */
23
+ get(z, channelIndex) {
24
+ return this.sliceHistograms.get(z)?.[channelIndex] ?? null;
25
+ }
26
+ /** Drop everything (teardown / image switch). */
27
+ clear() {
28
+ this.sliceHistograms.clear();
29
+ this.nativeHistograms.clear();
30
+ }
31
+ /**
32
+ * Per-channel intensity histograms for multichannel images: sample each
33
+ * channel's single-band tiles at the coarsest real level and bin the
34
+ * luminance. Fire-and-forget.
35
+ */
36
+ async computeMultiChannelHistograms(d, infoB64, z) {
37
+ try {
38
+ const t = d.tileSize;
39
+ // Sample the COARSEST real level (per-channel tiles exist only at real
40
+ // resolutions; the coarsest is small enough to bin even for whole-slides).
41
+ const res = Math.max(0, this.host.realLevels() - 1);
42
+ const lvl = d.levels?.[res];
43
+ const lw = lvl?.width ?? d.width;
44
+ const lh = lvl?.height ?? d.height;
45
+ const cols = Math.max(1, Math.ceil(lw / t));
46
+ const rows = Math.max(1, Math.ceil(lh / t));
47
+ if (cols * rows > 64)
48
+ return; // even the coarsest real level is too big
49
+ const nCh = this.host.channelCount(d);
50
+ if (nCh < 1)
51
+ return;
52
+ const counts = Array.from({ length: nCh }, () => new Array(256).fill(0));
53
+ const jobs = [];
54
+ for (let row = 0; row < rows; row++) {
55
+ for (let col = 0; col < cols; col++) {
56
+ for (let c = 0; c < nCh; c++) {
57
+ const url = buildTileUrl(this.api, infoB64, { res, col, row, z, tileSize: t, channel: c });
58
+ jobs.push((async () => {
59
+ try {
60
+ const img = await fetchTileRgba(this.http, url, 20000);
61
+ if (!img)
62
+ return;
63
+ const data = img.data;
64
+ const cc = counts[c];
65
+ for (let i = 0; i < data.length; i += 4) {
66
+ if (data[i + 3] === 0)
67
+ continue;
68
+ cc[maxRgb(data[i], data[i + 1], data[i + 2])]++;
69
+ }
70
+ }
71
+ catch (err) {
72
+ // Skip this tile — the histogram is just missing its counts.
73
+ console.warn('[viz:histogram] channel tile sample failed, skipping', url, err);
74
+ }
75
+ })());
76
+ }
77
+ }
78
+ }
79
+ await Promise.all(jobs);
80
+ this.sliceHistograms.set(z, counts.map((c) => histogram256(c)));
81
+ this.host.onChannelHistogramsSampled();
82
+ }
83
+ catch (err) {
84
+ // Leave histograms unset (the pane shows empty) — but say why.
85
+ console.warn('[viz:histogram] multichannel histogram sampling failed', err);
86
+ }
87
+ }
88
+ /**
89
+ * Compute a per-image intensity window [min,max] for grayscale auto-ranging,
90
+ * mirroring the heatmap's auto-stretch. Two constraints force the sampling
91
+ * strategy:
92
+ * - The window MUST be in the same value space as the displayed tiles: the
93
+ * `/preview` endpoint is server-normalized while `/tile` serves raw
94
+ * un-normalized 8-bit — a window from the preview wouldn't match.
95
+ * - It must read FULL-RESOLUTION tiles, not a downsampled overview:
96
+ * averaging sparse low values (label masks) toward 0 wipes the signal.
97
+ * So we sample the full-res level across the whole image — bounded to 64
98
+ * tiles (a huge grayscale image samples the coarsest overview for histograms
99
+ * only). Fire-and-forget; failures leave the window unset (identity 0..255).
100
+ */
101
+ async computeImageWindow(d, infoB64, z) {
102
+ const gray = this.host.isGrayscale();
103
+ try {
104
+ const t = d.tileSize;
105
+ // Sample full-resolution when the grid is small (accurate for the grayscale
106
+ // auto-window); otherwise sample the coarsest overview just for histograms
107
+ // (whole-slide images). RGB only needs the histograms, not an auto-window.
108
+ let res = 0;
109
+ let cols = Math.max(1, Math.ceil(d.width / t));
110
+ let rows = Math.max(1, Math.ceil(d.height / t));
111
+ let fullRes = true;
112
+ if (cols * rows > 64) {
113
+ res = Math.max(0, (d.levels?.length ?? 1) - 1);
114
+ const lvl = d.levels?.[res];
115
+ cols = Math.max(1, Math.ceil((lvl?.width ?? d.width) / t));
116
+ rows = Math.max(1, Math.ceil((lvl?.height ?? d.height) / t));
117
+ fullRes = false;
118
+ if (cols * rows > 36)
119
+ return; // even the coarsest is too big — give up
120
+ }
121
+ const coords = [];
122
+ for (let row = 0; row < rows; row++) {
123
+ for (let col = 0; col < cols; col++)
124
+ coords.push([col, row]);
125
+ }
126
+ let min = 255;
127
+ let max = 0;
128
+ const cR = new Array(256).fill(0);
129
+ const cG = gray ? null : new Array(256).fill(0);
130
+ const cB = gray ? null : new Array(256).fill(0);
131
+ await Promise.all(coords.map(async ([col, row]) => {
132
+ const url = buildTileUrl(this.api, infoB64, { res, col, row, z, tileSize: t });
133
+ try {
134
+ const img = await fetchTileRgba(this.http, url, 20000);
135
+ if (!img)
136
+ return;
137
+ const data = img.data;
138
+ for (let i = 0; i < data.length; i += 4) {
139
+ if (data[i + 3] === 0)
140
+ continue; // skip transparent padding
141
+ if (gray) {
142
+ const v = maxRgb(data[i], data[i + 1], data[i + 2]);
143
+ if (v < min)
144
+ min = v;
145
+ if (v > max)
146
+ max = v;
147
+ cR[v]++;
148
+ }
149
+ else {
150
+ cR[data[i]]++;
151
+ cG[data[i + 1]]++;
152
+ cB[data[i + 2]]++;
153
+ }
154
+ }
155
+ }
156
+ catch (err) {
157
+ // Skip this tile — window/histogram just lose its samples.
158
+ console.warn('[viz:window] tile sample failed, skipping', url, err);
159
+ }
160
+ }));
161
+ // Cache per-channel histograms: grayscale → [intensity]; RGB → [R, G, B].
162
+ this.sliceHistograms.set(z, gray ? [histogram256(cR)] : [histogram256(cR), histogram256(cG), histogram256(cB)]);
163
+ // Grayscale auto-window — only from full-res samples (coarsest averaging
164
+ // is inaccurate); the host seeds the channel or re-invalidates.
165
+ if (gray && fullRes && max > min && (min > 0 || max < 255)) {
166
+ this.host.onGrayWindowSampled(min, max);
167
+ }
168
+ }
169
+ catch (err) {
170
+ console.warn('[viz:window] per-image window compute failed — using identity 0..255', err);
171
+ }
172
+ }
173
+ /**
174
+ * Native-bit-depth histogram for >8-bit images, from the server `/histogram`
175
+ * endpoint (the 8-bit canvas tiles can't carry 16-bit values). Cached per
176
+ * slice+channel for the session.
177
+ */
178
+ native$(infoB64, z, channel, bins) {
179
+ const key = `${z}|${channel}`;
180
+ const cached = this.nativeHistograms.get(key);
181
+ if (cached)
182
+ return of(cached);
183
+ return from(this.fetchNative(infoB64, z, channel, bins, key));
184
+ }
185
+ /** Fetch + cache one channel's native histogram from `GET /histogram`. */
186
+ async fetchNative(infoB64, z, channel, bins, key) {
187
+ const url = `${this.api}histogram?info=${infoB64}&channel=${channel}&z=${z}&bins=${bins}&_=${this.histCacheBuster}`;
188
+ try {
189
+ // HttpClient calls get auth via the Angular interceptor (unlike OSD's own
190
+ // ajax tile loader, which needs authHeaders) — mirror the other fetches.
191
+ const hi = await firstValueFrom(this.http
192
+ .get(url)
193
+ .pipe(timeout(45000)));
194
+ if (!hi || !hi.counts)
195
+ return null;
196
+ const out = {
197
+ // Native bin left-edges: rangeMin + i*binWidth.
198
+ bins: hi.counts.map((_, i) => hi.rangeMin + i * hi.binWidth),
199
+ counts: hi.counts,
200
+ max: hi.counts.reduce((m, c) => (c > m ? c : m), 0),
201
+ bitDepth: hi.bitDepth,
202
+ rangeMin: hi.rangeMin,
203
+ rangeMax: hi.rangeMax,
204
+ observedMin: hi.observedMin,
205
+ observedMax: hi.observedMax,
206
+ };
207
+ this.nativeHistograms.set(key, out);
208
+ return out;
209
+ }
210
+ catch (err) {
211
+ // 202 (still caching) or a transient error → null; the pane retries.
212
+ console.warn('[viz:histogram] native histogram fetch failed', err);
213
+ return null;
214
+ }
215
+ }
216
+ }
217
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGlzdG9ncmFtLXNhbXBsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9vc2QvaGlzdG9ncmFtLXNhbXBsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFjLGNBQWMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUd6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM1RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBbUNqRSxNQUFNLE9BQU8sZ0JBQWdCO0lBWTNCLFlBQ1UsSUFBZ0IsRUFDaEIsR0FBVyxFQUNYLElBQTBCO1FBRjFCLFNBQUksR0FBSixJQUFJLENBQVk7UUFDaEIsUUFBRyxHQUFILEdBQUcsQ0FBUTtRQUNYLFNBQUksR0FBSixJQUFJLENBQXNCO1FBZHBDLG1FQUFtRTtRQUMzRCxvQkFBZSxHQUFHLElBQUksR0FBRyxFQUF3QixDQUFDO1FBQzFELDhFQUE4RTtRQUN0RSxxQkFBZ0IsR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztRQUN6RDs7OzsyQ0FJbUM7UUFDbEIsb0JBQWUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFNM0MsQ0FBQztJQUVKOzBEQUNzRDtJQUN0RCxHQUFHLENBQUMsQ0FBUyxFQUFFLFlBQW9CO1FBQ2pDLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUM7SUFDN0QsQ0FBQztJQUVELGlEQUFpRDtJQUNqRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMs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LEVBQUUsQ0FBQyxRQUFRO2dCQUNyQixXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVc7Z0JBQzNCLFdBQVcsRUFBRSxFQUFFLENBQUMsV0FBVzthQUM1QixDQUFDO1lBQ0YsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDcEMsT0FBTyxHQUFHLENBQUM7UUFDYixDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLHFFQUFxRTtZQUNyRSxPQUFPLENBQUMsSUFBSSxDQUFDLCtDQUErQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ25FLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmaXJzdFZhbHVlRnJvbSwgZnJvbSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRpbWVvdXQgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IElIaXN0b2dyYW0gfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2hhbm5lbC1oaXN0b2dyYW0tYXBpLmNvbnRyYWN0JztcbmltcG9ydCB7IGJ1aWxkVGlsZVVybCwgZmV0Y2hUaWxlUmdiYSB9IGZyb20gJy4vdGlsZS1jbGllbnQnO1xuaW1wb3J0IHsgaGlzdG9ncmFtMjU2LCBtYXhSZ2IgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvaW50ZW5zaXR5JztcblxuLyoqXG4gKiBIaXN0b2dyYW0gKyBhdXRvLXdpbmRvdyBzYW1wbGluZyBmb3IgdGhlIE9TRCBiYWNrZW5kIChyZWZhY3RvcmluZyBwbGFuLFxuICogU3RlcCA0IOKAlCBhIHB1cmUgbW92ZSBvdXQgb2YgdGhlIHZpc3VhbGl6ZXIgc2VydmljZSkuIE93bnMgdGhlIHBlci1zbGljZVxuICogOC1iaXQgaGlzdG9ncmFtcyAoc2FtcGxlZCBmcm9tIGRpc3BsYXllZCB0aWxlcykgYW5kIHRoZSBuYXRpdmUtYml0LWRlcHRoXG4gKiBoaXN0b2dyYW1zIChmZXRjaGVkIGZyb20gdGhlIHNlcnZlciBgL2hpc3RvZ3JhbWAgZW5kcG9pbnQpLiBSZWFkLW9ubHkgd2l0aFxuICogcmVzcGVjdCB0byB0aGUgdGlsZS9kaXNwbGF5IHBpcGVsaW5lLlxuICovXG5cbi8qKiBUaGUgZGVzY3JpcHRvciBmaWVsZHMgdGhlIHNhbXBsZXJzIHJlYWQgKHN0cnVjdHVyYWxseSBzYXRpc2ZpZWQgYnkgdGhlXG4gKiAgc2VydmljZSdzIFRpbGVEZXNjcmlwdG9yKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2FtcGxlZERlc2NyaXB0b3Ige1xuICB3aWR0aDogbnVtYmVyO1xuICBoZWlnaHQ6IG51bWJlcjtcbiAgdGlsZVNpemU6IG51bWJlcjtcbiAgY2hhbm5lbHM/OiBudW1iZXI7XG4gIGxldmVscz86IEFycmF5PHsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXIgfT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGlzdG9ncmFtU2FtcGxlckhvc3Qge1xuICAvKiogUmVhbCBCaW8tRm9ybWF0cyBsZXZlbHMgKHBlci1jaGFubmVsIHRpbGVzIGV4aXN0IG9ubHkgdGhlcmUpLiAqL1xuICByZWFsTGV2ZWxzKCk6IG51bWJlcjtcbiAgLyoqIENoYW5uZWwgY291bnQgZm9yIHRoZSBtdWx0aWNoYW5uZWwgc2FtcGxlci4gKi9cbiAgY2hhbm5lbENvdW50KGQ6IFNhbXBsZWREZXNjcmlwdG9yKTogbnVtYmVyO1xuICAvKiogR3JheXNjYWxlIChpbnRlbnNpdHkgaGlzdG9ncmFtICsgYXV0by13aW5kb3cpIHZzIFJHQiAoUi9HL0IgaGlzdG9ncmFtcykuICovXG4gIGlzR3JheXNjYWxlKCk6IGJvb2xlYW47XG4gIC8qKiBIaXN0b2dyYW1zIGxhbmRlZCDigJQgbnVkZ2UgdGhlIHBhbmUgdG8gcmUtcmVhZCAoaXRzIHJldHJ5IHdpbmRvdyBtYXkgaGF2ZVxuICAgKiAgbGFwc2VkKS4gKi9cbiAgb25DaGFubmVsSGlzdG9ncmFtc1NhbXBsZWQoKTogdm9pZDtcbiAgLyoqIEEgZ3JheXNjYWxlIGF1dG8td2luZG93IHdhcyBtZWFzdXJlZCBmcm9tIGZ1bGwtcmVzIHRpbGVzIOKAlCBzZWVkIHRoZVxuICAgKiAgSW50ZW5zaXR5IGNoYW5uZWwgKG9yIHJlLWludmFsaWRhdGUgaWYgdGhlIHVzZXIgYWxyZWFkeSB3aW5kb3dlZCkuICovXG4gIG9uR3JheVdpbmRvd1NhbXBsZWQobWluOiBudW1iZXIsIG1heDogbnVtYmVyKTogdm9pZDtcbn1cblxuZXhwb3J0IGNsYXNzIEhpc3RvZ3JhbVNhbXBsZXIge1xuICAvKiogMjU2LWJpbiBpbnRlbnNpdHkgaGlzdG9ncmFtIHBlciB6LXNsaWNlLCBmcm9tIHNhbXBsZWQgdGlsZXMuICovXG4gIHByaXZhdGUgc2xpY2VIaXN0b2dyYW1zID0gbmV3IE1hcDxudW1iZXIsIElIaXN0b2dyYW1bXT4oKTtcbiAgLyoqIE5hdGl2ZS1iaXQtZGVwdGggaGlzdG9ncmFtcyBmcm9tIGAvaGlzdG9ncmFtYCwga2V5ZWQgYCR7en18JHtjaGFubmVsfWAuICovXG4gIHByaXZhdGUgbmF0aXZlSGlzdG9ncmFtcyA9IG5ldyBNYXA8c3RyaW5nLCBJSGlzdG9ncmFtPigpO1xuICAvKiogUGVyLWFwcC1sb2FkIGNhY2hlLWJ1c3RlciBmb3IgYC9oaXN0b2dyYW1gIOKAlCB0aGUgc2VydmVyIG1hcmtzIHRoZVxuICAgKiAgcmVzcG9uc2UgY2FjaGVhYmxlIGZvciAyNGgsIGFuZCBhIGhhcmQgcmVmcmVzaCBjYW4ndCBidXN0IGEgcG9zdC1sb2FkXG4gICAqICBYSFIuIEEgdG9rZW4gc3RhYmxlIHdpdGhpbiBhIHNlc3Npb24gYnV0IG5ldyBvbiBlYWNoIGZ1bGwgbG9hZCBrZWVwcyB0aGVcbiAgICogIGluLXNlc3Npb24gZGVkdXAgKHZpYSBgbmF0aXZlSGlzdG9ncmFtc2ApIHdoaWxlIGFsd2F5cyByZWZsZWN0aW5nIHRoZVxuICAgKiAgbGl2ZSBiYWNrZW5kIGFmdGVyIGEgcmVsb2FkLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhpc3RDYWNoZUJ1c3RlciA9IERhdGUubm93KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgIHByaXZhdGUgYXBpOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSBob3N0OiBIaXN0b2dyYW1TYW1wbGVySG9zdCxcbiAgKSB7fVxuXG4gIC8qKiBUaGUgc2FtcGxlZCBoaXN0b2dyYW0gZm9yIG9uZSBjaGFubmVsIG9mIHNsaWNlIHosIG9yIG51bGwgdW50aWwgdGhlXG4gICAqICBhc3luYyBzYW1wbGluZyByZXNvbHZlcyAob3IgaWYgaXQgd2FzIHNraXBwZWQpLiAqL1xuICBnZXQoejogbnVtYmVyLCBjaGFubmVsSW5kZXg6IG51bWJlcik6IElIaXN0b2dyYW0gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5zbGljZUhpc3RvZ3JhbXMuZ2V0KHopPy5bY2hhbm5lbEluZGV4XSA/PyBudWxsO1xuICB9XG5cbiAgLyoqIERyb3AgZXZlcnl0aGluZyAodGVhcmRvd24gLyBpbWFnZSBzd2l0Y2gpLiAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLnNsaWNlSGlzdG9ncmFtcy5jbGVhcigpO1xuICAgIHRoaXMubmF0aXZlSGlzdG9ncmFtcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlci1jaGFubmVsIGludGVuc2l0eSBoaXN0b2dyYW1zIGZvciBtdWx0aWNoYW5uZWwgaW1hZ2VzOiBzYW1wbGUgZWFjaFxuICAgKiBjaGFubmVsJ3Mgc2luZ2xlLWJhbmQgdGlsZXMgYXQgdGhlIGNvYXJzZXN0IHJlYWwgbGV2ZWwgYW5kIGJpbiB0aGVcbiAgICogbHVtaW5hbmNlLiBGaXJlLWFuZC1mb3JnZXQuXG4gICAqL1xuICBhc3luYyBjb21wdXRlTXVsdGlDaGFubmVsSGlzdG9ncmFtcyhkOiBTYW1wbGVkRGVzY3JpcHRvciwgaW5mb0I2NDogc3RyaW5nLCB6OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdCA9IGQudGlsZVNpemU7XG4gICAgICAvLyBTYW1wbGUgdGhlIENPQVJTRVNUIHJlYWwgbGV2ZWwgKHBlci1jaGFubmVsIHRpbGVzIGV4aXN0IG9ubHkgYXQgcmVhbFxuICAgICAgLy8gcmVzb2x1dGlvbnM7IHRoZSBjb2Fyc2VzdCBpcyBzbWFsbCBlbm91Z2ggdG8gYmluIGV2ZW4gZm9yIHdob2xlLXNsaWRlcykuXG4gICAgICBjb25zdCByZXMgPSBNYXRoLm1heCgwLCB0aGlzLmhvc3QucmVhbExldmVscygpIC0gMSk7XG4gICAgICBjb25zdCBsdmwgPSBkLmxldmVscz8uW3Jlc107XG4gICAgICBjb25zdCBsdyA9IGx2bD8ud2lkdGggPz8gZC53aWR0aDtcbiAgICAgIGNvbnN0IGxoID0gbHZsPy5oZWlnaHQgPz8gZC5oZWlnaHQ7XG4gICAgICBjb25zdCBjb2xzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKGx3IC8gdCkpO1xuICAgICAgY29uc3Qgcm93cyA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChsaCAvIHQpKTtcbiAgICAgIGlmIChjb2xzICogcm93cyA+IDY0KSByZXR1cm47IC8vIGV2ZW4gdGhlIGNvYXJzZXN0IHJlYWwgbGV2ZWwgaXMgdG9vIGJpZ1xuICAgICAgY29uc3QgbkNoID0gdGhpcy5ob3N0LmNoYW5uZWxDb3VudChkKTtcbiAgICAgIGlmIChuQ2ggPCAxKSByZXR1cm47XG4gICAgICBjb25zdCBjb3VudHM6IG51bWJlcltdW10gPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiBuQ2ggfSwgKCkgPT4gbmV3IEFycmF5KDI1NikuZmlsbCgwKSk7XG4gICAgICBjb25zdCBqb2JzOiBBcnJheTxQcm9taXNlPHZvaWQ+PiA9IFtdO1xuICAgICAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgcm93czsgcm93KyspIHtcbiAgICAgICAgZm9yIChsZXQgY29sID0gMDsgY29sIDwgY29sczsgY29sKyspIHtcbiAgICAgICAgICBmb3IgKGxldCBjID0gMDsgYyA8IG5DaDsgYysrKSB7XG4gICAgICAgICAgICBjb25zdCB1cmwgPSBidWlsZFRpbGVVcmwodGhpcy5hcGksIGluZm9CNjQsIHsgcmVzLCBjb2wsIHJvdywgeiwgdGlsZVNpemU6IHQsIGNoYW5uZWw6IGMgfSk7XG4gICAgICAgICAgICBqb2JzLnB1c2goXG4gICAgICAgICAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGltZyA9IGF3YWl0IGZldGNoVGlsZVJnYmEodGhpcy5odHRwLCB1cmwsIDIwMDAwKTtcbiAgICAgICAgICAgICAgICAgIGlmICghaW1nKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICBjb25zdCBkYXRhID0gaW1nLmRhdGE7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjYyA9IGNvdW50c1tjXTtcbiAgICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZGF0YS5sZW5ndGg7IGkgKz0gNCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZGF0YVtpICsgM10gPT09IDApIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICBjY1ttYXhSZ2IoZGF0YVtpXSwgZGF0YVtpICsgMV0sIGRhdGFbaSArIDJdKV0rKztcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgIC8vIFNraXAgdGhpcyB0aWxlIOKAlCB0aGUgaGlzdG9ncmFtIGlzIGp1c3QgbWlzc2luZyBpdHMgY291bnRzLlxuICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbdml6Omhpc3RvZ3JhbV0gY2hhbm5lbCB0aWxlIHNhbXBsZSBmYWlsZWQsIHNraXBwaW5nJywgdXJsLCBlcnIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSkoKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChqb2JzKTtcbiAgICAgIHRoaXMuc2xpY2VIaXN0b2dyYW1zLnNldCh6LCBjb3VudHMubWFwKChjKSA9PiBoaXN0b2dyYW0yNTYoYykpKTtcbiAgICAgIHRoaXMuaG9zdC5vbkNoYW5uZWxIaXN0b2dyYW1zU2FtcGxlZCgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gTGVhdmUgaGlzdG9ncmFtcyB1bnNldCAodGhlIHBhbmUgc2hvd3MgZW1wdHkpIOKAlCBidXQgc2F5IHdoeS5cbiAgICAgIGNvbnNvbGUud2FybignW3ZpejpoaXN0b2dyYW1dIG11bHRpY2hhbm5lbCBoaXN0b2dyYW0gc2FtcGxpbmcgZmFpbGVkJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29tcHV0ZSBhIHBlci1pbWFnZSBpbnRlbnNpdHkgd2luZG93IFttaW4sbWF4XSBmb3IgZ3JheXNjYWxlIGF1dG8tcmFuZ2luZyxcbiAgICogbWlycm9yaW5nIHRoZSBoZWF0bWFwJ3MgYXV0by1zdHJldGNoLiBUd28gY29uc3RyYWludHMgZm9yY2UgdGhlIHNhbXBsaW5nXG4gICAqIHN0cmF0ZWd5OlxuICAgKiAgLSBUaGUgd2luZG93IE1VU1QgYmUgaW4gdGhlIHNhbWUgdmFsdWUgc3BhY2UgYXMgdGhlIGRpc3BsYXllZCB0aWxlczogdGhlXG4gICAqICAgIGAvcHJldmlld2AgZW5kcG9pbnQgaXMgc2VydmVyLW5vcm1hbGl6ZWQgd2hpbGUgYC90aWxlYCBzZXJ2ZXMgcmF3XG4gICAqICAgIHVuLW5vcm1hbGl6ZWQgOC1iaXQg4oCUIGEgd2luZG93IGZyb20gdGhlIHByZXZpZXcgd291bGRuJ3QgbWF0Y2guXG4gICAqICAtIEl0IG11c3QgcmVhZCBGVUxMLVJFU09MVVRJT04gdGlsZXMsIG5vdCBhIGRvd25zYW1wbGVkIG92ZXJ2aWV3OlxuICAgKiAgICBhdmVyYWdpbmcgc3BhcnNlIGxvdyB2YWx1ZXMgKGxhYmVsIG1hc2tzKSB0b3dhcmQgMCB3aXBlcyB0aGUgc2lnbmFsLlxuICAgKiBTbyB3ZSBzYW1wbGUgdGhlIGZ1bGwtcmVzIGxldmVsIGFjcm9zcyB0aGUgd2hvbGUgaW1hZ2Ug4oCUIGJvdW5kZWQgdG8gNjRcbiAgICogdGlsZXMgKGEgaHVnZSBncmF5c2NhbGUgaW1hZ2Ugc2FtcGxlcyB0aGUgY29hcnNlc3Qgb3ZlcnZpZXcgZm9yIGhpc3RvZ3JhbXNcbiAgICogb25seSkuIEZpcmUtYW5kLWZvcmdldDsgZmFpbHVyZXMgbGVhdmUgdGhlIHdpbmRvdyB1bnNldCAoaWRlbnRpdHkgMC4uMjU1KS5cbiAgICovXG4gIGFzeW5jIGNvbXB1dGVJbWFnZVdpbmRvdyhkOiBTYW1wbGVkRGVzY3JpcHRvciwgaW5mb0I2NDogc3RyaW5nLCB6OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBncmF5ID0gdGhpcy5ob3N0LmlzR3JheXNjYWxlKCk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHQgPSBkLnRpbGVTaXplO1xuICAgICAgLy8gU2FtcGxlIGZ1bGwtcmVzb2x1dGlvbiB3aGVuIHRoZSBncmlkIGlzIHNtYWxsIChhY2N1cmF0ZSBmb3IgdGhlIGdyYXlzY2FsZVxuICAgICAgLy8gYXV0by13aW5kb3cpOyBvdGhlcndpc2Ugc2FtcGxlIHRoZSBjb2Fyc2VzdCBvdmVydmlldyBqdXN0IGZvciBoaXN0b2dyYW1zXG4gICAgICAvLyAod2hvbGUtc2xpZGUgaW1hZ2VzKS4gUkdCIG9ubHkgbmVlZHMgdGhlIGhpc3RvZ3JhbXMsIG5vdCBhbiBhdXRvLXdpbmRvdy5cbiAgICAgIGxldCByZXMgPSAwO1xuICAgICAgbGV0IGNvbHMgPSBNYXRoLm1heCgxLCBNYXRoLmNlaWwoZC53aWR0aCAvIHQpKTtcbiAgICAgIGxldCByb3dzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKGQuaGVpZ2h0IC8gdCkpO1xuICAgICAgbGV0IGZ1bGxSZXMgPSB0cnVlO1xuICAgICAgaWYgKGNvbHMgKiByb3dzID4gNjQpIHtcbiAgICAgICAgcmVzID0gTWF0aC5tYXgoMCwgKGQubGV2ZWxzPy5sZW5ndGggPz8gMSkgLSAxKTtcbiAgICAgICAgY29uc3QgbHZsID0gZC5sZXZlbHM/LltyZXNdO1xuICAgICAgICBjb2xzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKChsdmw/LndpZHRoID8/IGQud2lkdGgpIC8gdCkpO1xuICAgICAgICByb3dzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKChsdmw/LmhlaWdodCA/PyBkLmhlaWdodCkgLyB0KSk7XG4gICAgICAgIGZ1bGxSZXMgPSBmYWxzZTtcbiAgICAgICAgaWYgKGNvbHMgKiByb3dzID4gMzYpIHJldHVybjsgLy8gZXZlbiB0aGUgY29hcnNlc3QgaXMgdG9vIGJpZyDigJQgZ2l2ZSB1cFxuICAgICAgfVxuICAgICAgY29uc3QgY29vcmRzOiBBcnJheTxbbnVtYmVyLCBudW1iZXJdPiA9IFtdO1xuICAgICAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgcm93czsgcm93KyspIHtcbiAgICAgICAgZm9yIChsZXQgY29sID0gMDsgY29sIDwgY29sczsgY29sKyspIGNvb3Jkcy5wdXNoKFtjb2wsIHJvd10pO1xuICAgICAgfVxuICAgICAgbGV0IG1pbiA9IDI1NTtcbiAgICAgIGxldCBtYXggPSAwO1xuICAgICAgY29uc3QgY1IgPSBuZXcgQXJyYXkoMjU2KS5maWxsKDApO1xuICAgICAgY29uc3QgY0cgPSBncmF5ID8gbnVsbCA6IG5ldyBBcnJheSgyNTYpLmZpbGwoMCk7XG4gICAgICBjb25zdCBjQiA9IGdyYXkgPyBudWxsIDogbmV3IEFycmF5KDI1NikuZmlsbCgwKTtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb29yZHMubWFwKGFzeW5jIChbY29sLCByb3ddKSA9PiB7XG4gICAgICAgICAgY29uc3QgdXJsID0gYnVpbGRUaWxlVXJsKHRoaXMuYXBpLCBpbmZvQjY0LCB7IHJlcywgY29sLCByb3csIHosIHRpbGVTaXplOiB0IH0pO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBhd2FpdCBmZXRjaFRpbGVSZ2JhKHRoaXMuaHR0cCwgdXJsLCAyMDAwMCk7XG4gICAgICAgICAgICBpZiAoIWltZykgcmV0dXJuO1xuICAgICAgICAgICAgY29uc3QgZGF0YSA9IGltZy5kYXRhO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgICAgICAgIGlmIChkYXRhW2kgKyAzXSA9PT0gMCkgY29udGludWU7IC8vIHNraXAgdHJhbnNwYXJlbnQgcGFkZGluZ1xuICAgICAgICAgICAgICBpZiAoZ3JheSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHYgPSBtYXhSZ2IoZGF0YVtpXSwgZGF0YVtpICsgMV0sIGRhdGFbaSArIDJdKTtcbiAgICAgICAgICAgICAgICBpZiAodiA8IG1pbikgbWluID0gdjtcbiAgICAgICAgICAgICAgICBpZiAodiA+IG1heCkgbWF4ID0gdjtcbiAgICAgICAgICAgICAgICBjUlt2XSsrO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNSW2RhdGFbaV1dKys7XG4gICAgICAgICAgICAgICAgY0chW2RhdGFbaSArIDFdXSsrO1xuICAgICAgICAgICAgICAgIGNCIVtkYXRhW2kgKyAyXV0rKztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgLy8gU2tpcCB0aGlzIHRpbGUg4oCUIHdpbmRvdy9oaXN0b2dyYW0ganVzdCBsb3NlIGl0cyBzYW1wbGVzLlxuICAgICAgICAgICAgY29uc29sZS53YXJuKCdbdml6OndpbmRvd10gdGlsZSBzYW1wbGUgZmFpbGVkLCBza2lwcGluZycsIHVybCwgZXJyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICAgIC8vIENhY2hlIHBlci1jaGFubmVsIGhpc3RvZ3JhbXM6IGdyYXlzY2FsZSDihpIgW2ludGVuc2l0eV07IFJHQiDihpIgW1IsIEcsIEJdLlxuICAgICAgdGhpcy5zbGljZUhpc3RvZ3JhbXMuc2V0KFxuICAgICAgICB6LCBncmF5ID8gW2hpc3RvZ3JhbTI1NihjUildIDogW2hpc3RvZ3JhbTI1NihjUiksIGhpc3RvZ3JhbTI1NihjRyEpLCBoaXN0b2dyYW0yNTYoY0IhKV0sXG4gICAgICApO1xuICAgICAgLy8gR3JheXNjYWxlIGF1dG8td2luZG93IOKAlCBvbmx5IGZyb20gZnVsbC1yZXMgc2FtcGxlcyAoY29hcnNlc3QgYXZlcmFnaW5nXG4gICAgICAvLyBpcyBpbmFjY3VyYXRlKTsgdGhlIGhvc3Qgc2VlZHMgdGhlIGNoYW5uZWwgb3IgcmUtaW52YWxpZGF0ZXMuXG4gICAgICBpZiAoZ3JheSAmJiBmdWxsUmVzICYmIG1heCA+IG1pbiAmJiAobWluID4gMCB8fCBtYXggPCAyNTUpKSB7XG4gICAgICAgIHRoaXMuaG9zdC5vbkdyYXlXaW5kb3dTYW1wbGVkKG1pbiwgbWF4KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUud2FybignW3Zpejp3aW5kb3ddIHBlci1pbWFnZSB3aW5kb3cgY29tcHV0ZSBmYWlsZWQg4oCUIHVzaW5nIGlkZW50aXR5IDAuLjI1NScsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE5hdGl2ZS1iaXQtZGVwdGggaGlzdG9ncmFtIGZvciA+OC1iaXQgaW1hZ2VzLCBmcm9tIHRoZSBzZXJ2ZXIgYC9oaXN0b2dyYW1gXG4gICAqIGVuZHBvaW50ICh0aGUgOC1iaXQgY2FudmFzIHRpbGVzIGNhbid0IGNhcnJ5IDE2LWJpdCB2YWx1ZXMpLiBDYWNoZWQgcGVyXG4gICAqIHNsaWNlK2NoYW5uZWwgZm9yIHRoZSBzZXNzaW9uLlxuICAgKi9cbiAgbmF0aXZlJChpbmZvQjY0OiBzdHJpbmcsIHo6IG51bWJlciwgY2hhbm5lbDogbnVtYmVyLCBiaW5zOiBudW1iZXIpOiBPYnNlcnZhYmxlPElIaXN0b2dyYW0gfCBudWxsPiB7XG4gICAgY29uc3Qga2V5ID0gYCR7en18JHtjaGFubmVsfWA7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5uYXRpdmVIaXN0b2dyYW1zLmdldChrZXkpO1xuICAgIGlmIChjYWNoZWQpIHJldHVybiBvZihjYWNoZWQpO1xuICAgIHJldHVybiBmcm9tKHRoaXMuZmV0Y2hOYXRpdmUoaW5mb0I2NCwgeiwgY2hhbm5lbCwgYmlucywga2V5KSk7XG4gIH1cblxuICAvKiogRmV0Y2ggKyBjYWNoZSBvbmUgY2hhbm5lbCdzIG5hdGl2ZSBoaXN0b2dyYW0gZnJvbSBgR0VUIC9oaXN0b2dyYW1gLiAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoTmF0aXZlKFxuICAgIGluZm9CNjQ6IHN0cmluZywgejogbnVtYmVyLCBjaGFubmVsOiBudW1iZXIsIGJpbnM6IG51bWJlciwga2V5OiBzdHJpbmcsXG4gICk6IFByb21pc2U8SUhpc3RvZ3JhbSB8IG51bGw+IHtcbiAgICBjb25zdCB1cmwgPSBgJHt0aGlzLmFwaX1oaXN0b2dyYW0/aW5mbz0ke2luZm9CNjR9JmNoYW5uZWw9JHtjaGFubmVsfSZ6PSR7en0mYmlucz0ke2JpbnN9Jl89JHt0aGlzLmhpc3RDYWNoZUJ1c3Rlcn1gO1xuICAgIHRyeSB7XG4gICAgICAvLyBIdHRwQ2xpZW50IGNhbGxzIGdldCBhdXRoIHZpYSB0aGUgQW5ndWxhciBpbnRlcmNlcHRvciAodW5saWtlIE9TRCdzIG93blxuICAgICAgLy8gYWpheCB0aWxlIGxvYWRlciwgd2hpY2ggbmVlZHMgYXV0aEhlYWRlcnMpIOKAlCBtaXJyb3IgdGhlIG90aGVyIGZldGNoZXMuXG4gICAgICBjb25zdCBoaSA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKFxuICAgICAgICB0aGlzLmh0dHBcbiAgICAgICAgICAuZ2V0PHtcbiAgICAgICAgICAgIGJpdERlcHRoOiBudW1iZXI7IHJhbmdlTWluOiBudW1iZXI7IHJhbmdlTWF4OiBudW1iZXI7XG4gICAgICAgICAgICBvYnNlcnZlZE1pbjogbnVtYmVyOyBvYnNlcnZlZE1heDogbnVtYmVyOyBiaW5XaWR0aDogbnVtYmVyOyBjb3VudHM6IG51bWJlcltdO1xuICAgICAgICAgIH0+KHVybClcbiAgICAgICAgICAucGlwZSh0aW1lb3V0KDQ1MDAwKSksXG4gICAgICApO1xuICAgICAgaWYgKCFoaSB8fCAhaGkuY291bnRzKSByZXR1cm4gbnVsbDtcbiAgICAgIGNvbnN0IG91dDogSUhpc3RvZ3JhbSA9IHtcbiAgICAgICAgLy8gTmF0aXZlIGJpbiBsZWZ0LWVkZ2VzOiByYW5nZU1pbiArIGkqYmluV2lkdGguXG4gICAgICAgIGJpbnM6IGhpLmNvdW50cy5tYXAoKF8sIGkpID0+IGhpLnJhbmdlTWluICsgaSAqIGhpLmJpbldpZHRoKSxcbiAgICAgICAgY291bnRzOiBoaS5jb3VudHMsXG4gICAgICAgIG1heDogaGkuY291bnRzLnJlZHVjZSgobSwgYykgPT4gKGMgPiBtID8gYyA6IG0pLCAwKSxcbiAgICAgICAgYml0RGVwdGg6IGhpLmJpdERlcHRoLFxuICAgICAgICByYW5nZU1pbjogaGkucmFuZ2VNaW4sXG4gICAgICAgIHJhbmdlTWF4OiBoaS5yYW5nZU1heCxcbiAgICAgICAgb2JzZXJ2ZWRNaW46IGhpLm9ic2VydmVkTWluLFxuICAgICAgICBvYnNlcnZlZE1heDogaGkub2JzZXJ2ZWRNYXgsXG4gICAgICB9O1xuICAgICAgdGhpcy5uYXRpdmVIaXN0b2dyYW1zLnNldChrZXksIG91dCk7XG4gICAgICByZXR1cm4gb3V0O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gMjAyIChzdGlsbCBjYWNoaW5nKSBvciBhIHRyYW5zaWVudCBlcnJvciDihpIgbnVsbDsgdGhlIHBhbmUgcmV0cmllcy5cbiAgICAgIGNvbnNvbGUud2FybignW3ZpejpoaXN0b2dyYW1dIG5hdGl2ZSBoaXN0b2dyYW0gZmV0Y2ggZmFpbGVkJywgZXJyKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxufVxuIl19