@jax-data-science/sci-image-visualizer 0.8.2 → 0.9.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 (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,108 @@
1
+ import { Subscription } from 'rxjs';
2
+ import { takeUntil } from 'rxjs/operators';
3
+ /**
4
+ * One viewer's segmentation runs and their sticky progress toast (jit-ui#90): the
5
+ * box-prompt SAM and Cellpose tools, contributed whole-view tools, and the
6
+ * interactive SAM point tool whose feeds it bridges.
7
+ *
8
+ * The toast is keyed per viewer (`toastKey`), so a run in a pipeline preview does not
9
+ * show in the main view; results and failures go to the viewer's `resultKey` outlet,
10
+ * which the sticky toast's teardown does not clear. The toast template binds
11
+ * {@link status}, {@link progress}, {@link downloading} and {@link busy}.
12
+ */
13
+ export class SegmentationRunner {
14
+ constructor(messages, toastKey, resultKey,
15
+ /** Re-render the toast (its feeds may fire outside the zone). */
16
+ changed) {
17
+ this.messages = messages;
18
+ this.toastKey = toastKey;
19
+ this.resultKey = resultKey;
20
+ this.changed = changed;
21
+ this.status = '';
22
+ /** Encoder download, 0..100. */
23
+ this.progress = 0;
24
+ this.downloading = false;
25
+ /** Any segmentation work in flight (the indeterminate spinner). */
26
+ this.busy = false;
27
+ /** Whether the sticky toast is up — re-adding it would stack one per point click. */
28
+ this.shown = false;
29
+ }
30
+ /** Surface the interactive SAM point tool's status and download progress, which runs
31
+ * inside the renderer on each click (the first click pulls the encoder). */
32
+ bindPointTool(tool, until$) {
33
+ tool.progress$.pipe(takeUntil(until$)).subscribe((f) => this.onProgress(f));
34
+ tool.status$.pipe(takeUntil(until$)).subscribe((m) => {
35
+ this.status = m;
36
+ this.changed();
37
+ });
38
+ tool.busy$.pipe(takeUntil(until$)).subscribe((busy) => {
39
+ this.busy = busy;
40
+ if (busy)
41
+ this.show('SAM point segmentation');
42
+ this.changed();
43
+ });
44
+ }
45
+ /**
46
+ * Run `op` with the tool's status and download progress in the sticky toast, then
47
+ * report the outcome: the region count (or the tool's last status line) on success,
48
+ * the error on failure. The toast stays until the run settles.
49
+ */
50
+ async run(label, tool, op) {
51
+ this.status = 'Starting…';
52
+ this.progress = 0;
53
+ this.downloading = false;
54
+ this.busy = true;
55
+ // The last non-empty status is what the result reports: `tool` is only an
56
+ // Observable pair, so there is no `.value` to sample once the run settles.
57
+ let lastStatus = '';
58
+ const subs = new Subscription();
59
+ subs.add(tool.progress$.subscribe((f) => this.onProgress(f)));
60
+ subs.add(tool.status$.subscribe((m) => {
61
+ if (!m)
62
+ return;
63
+ lastStatus = m;
64
+ this.status = m;
65
+ this.changed();
66
+ }));
67
+ this.show(label);
68
+ try {
69
+ const n = await op();
70
+ this.messages.add({
71
+ key: this.resultKey,
72
+ severity: n > 0 ? 'success' : 'warn',
73
+ summary: label,
74
+ detail: lastStatus || (n > 0 ? `Added ${n} region(s).` : 'No regions added.'),
75
+ });
76
+ }
77
+ catch (e) {
78
+ this.messages.add({ key: this.resultKey, severity: 'error', summary: `${label} failed`, detail: String(e) });
79
+ }
80
+ finally {
81
+ subs.unsubscribe();
82
+ this.hide();
83
+ }
84
+ }
85
+ /** Show the sticky toast once (idempotent). */
86
+ show(summary) {
87
+ if (this.shown)
88
+ return;
89
+ this.shown = true;
90
+ this.messages.add({ key: this.toastKey, sticky: true, severity: 'info', summary });
91
+ }
92
+ /** Dismiss the sticky toast and reset its progress/spinner state. */
93
+ hide() {
94
+ this.shown = false;
95
+ this.busy = false;
96
+ this.downloading = false;
97
+ this.progress = 0;
98
+ this.messages.clear(this.toastKey);
99
+ this.changed();
100
+ }
101
+ onProgress(f) {
102
+ this.downloading = f >= 0 && f < 1;
103
+ if (f >= 0)
104
+ this.progress = Math.min(100, Math.round(f * 100));
105
+ this.changed();
106
+ }
107
+ }
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudGF0aW9uLXJ1bm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2VnbWVudGF0aW9uLXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWMsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVUzQzs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBVTdCLFlBQ21CLFFBQStDLEVBQ3ZELFFBQWdCLEVBQ2hCLFNBQWlCO0lBQzFCLGlFQUFpRTtJQUNoRCxPQUFtQjtRQUpuQixhQUFRLEdBQVIsUUFBUSxDQUF1QztRQUN2RCxhQUFRLEdBQVIsUUFBUSxDQUFRO1FBQ2hCLGNBQVMsR0FBVCxTQUFTLENBQVE7UUFFVCxZQUFPLEdBQVAsT0FBTyxDQUFZO1FBZHRDLFdBQU0sR0FBRyxFQUFFLENBQUM7UUFDWixnQ0FBZ0M7UUFDaEMsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLG1FQUFtRTtRQUNuRSxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBQ2IscUZBQXFGO1FBQzdFLFVBQUssR0FBRyxLQUFLLENBQUM7SUFRbkIsQ0FBQztJQUVKO2lGQUM2RTtJQUM3RSxhQUFhLENBQUMsSUFBMkQsRUFBRSxNQUEyQjtRQUNwRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM1RSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMs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QUM7UUFDbEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBRUQscUVBQXFFO0lBQ3JFLElBQUk7UUFDRixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQztRQUNsQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztRQUN6QixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFTyxVQUFVLENBQUMsQ0FBUztRQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQUUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNqQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IE1lc3NhZ2VTZXJ2aWNlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuXG4vKiogQSBzZWdtZW50YXRpb24gdG9vbCdzIGxpdmUgZmVlZHM6IHN0YXR1cyBsaW5lIGFuZCBlbmNvZGVyLWRvd25sb2FkIHByb2dyZXNzICgwLi4xLCA8MCA9IG5vbmUpLlxuICogIE9ic2VydmFibGVzLCBub3Qgc3ViamVjdHMsIHNvIGEgY29udHJpYnV0ZWQgdG9vbCBuZWVkIG5vdCBleHBvc2UgaXRzIGludGVybmFscy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VnbWVudGF0aW9uUHJvZ3Jlc3Mge1xuICBzdGF0dXMkOiBPYnNlcnZhYmxlPHN0cmluZz47XG4gIHByb2dyZXNzJDogT2JzZXJ2YWJsZTxudW1iZXI+O1xufVxuXG4vKipcbiAqIE9uZSB2aWV3ZXIncyBzZWdtZW50YXRpb24gcnVucyBhbmQgdGhlaXIgc3RpY2t5IHByb2dyZXNzIHRvYXN0IChqaXQtdWkjOTApOiB0aGVcbiAqIGJveC1wcm9tcHQgU0FNIGFuZCBDZWxscG9zZSB0b29scywgY29udHJpYnV0ZWQgd2hvbGUtdmlldyB0b29scywgYW5kIHRoZVxuICogaW50ZXJhY3RpdmUgU0FNIHBvaW50IHRvb2wgd2hvc2UgZmVlZHMgaXQgYnJpZGdlcy5cbiAqXG4gKiBUaGUgdG9hc3QgaXMga2V5ZWQgcGVyIHZpZXdlciAoYHRvYXN0S2V5YCksIHNvIGEgcnVuIGluIGEgcGlwZWxpbmUgcHJldmlldyBkb2VzIG5vdFxuICogc2hvdyBpbiB0aGUgbWFpbiB2aWV3OyByZXN1bHRzIGFuZCBmYWlsdXJlcyBnbyB0byB0aGUgdmlld2VyJ3MgYHJlc3VsdEtleWAgb3V0bGV0LFxuICogd2hpY2ggdGhlIHN0aWNreSB0b2FzdCdzIHRlYXJkb3duIGRvZXMgbm90IGNsZWFyLiBUaGUgdG9hc3QgdGVtcGxhdGUgYmluZHNcbiAqIHtAbGluayBzdGF0dXN9LCB7QGxpbmsgcHJvZ3Jlc3N9LCB7QGxpbmsgZG93bmxvYWRpbmd9IGFuZCB7QGxpbmsgYnVzeX0uXG4gKi9cbmV4cG9ydCBjbGFzcyBTZWdtZW50YXRpb25SdW5uZXIge1xuICBzdGF0dXMgPSAnJztcbiAgLyoqIEVuY29kZXIgZG93bmxvYWQsIDAuLjEwMC4gKi9cbiAgcHJvZ3Jlc3MgPSAwO1xuICBkb3dubG9hZGluZyA9IGZhbHNlO1xuICAvKiogQW55IHNlZ21lbnRhdGlvbiB3b3JrIGluIGZsaWdodCAodGhlIGluZGV0ZXJtaW5hdGUgc3Bpbm5lcikuICovXG4gIGJ1c3kgPSBmYWxzZTtcbiAgLyoqIFdoZXRoZXIgdGhlIHN0aWNreSB0b2FzdCBpcyB1cCDigJQgcmUtYWRkaW5nIGl0IHdvdWxkIHN0YWNrIG9uZSBwZXIgcG9pbnQgY2xpY2suICovXG4gIHByaXZhdGUgc2hvd24gPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1lc3NhZ2VzOiBQaWNrPE1lc3NhZ2VTZXJ2aWNlLCAnYWRkJyB8ICdjbGVhcic+LFxuICAgIHJlYWRvbmx5IHRvYXN0S2V5OiBzdHJpbmcsXG4gICAgcmVhZG9ubHkgcmVzdWx0S2V5OiBzdHJpbmcsXG4gICAgLyoqIFJlLXJlbmRlciB0aGUgdG9hc3QgKGl0cyBmZWVkcyBtYXkgZmlyZSBvdXRzaWRlIHRoZSB6b25lKS4gKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGNoYW5nZWQ6ICgpID0+IHZvaWQsXG4gICkge31cblxuICAvKiogU3VyZmFjZSB0aGUgaW50ZXJhY3RpdmUgU0FNIHBvaW50IHRvb2wncyBzdGF0dXMgYW5kIGRvd25sb2FkIHByb2dyZXNzLCB3aGljaCBydW5zXG4gICAqICBpbnNpZGUgdGhlIHJlbmRlcmVyIG9uIGVhY2ggY2xpY2sgKHRoZSBmaXJzdCBjbGljayBwdWxscyB0aGUgZW5jb2RlcikuICovXG4gIGJpbmRQb2ludFRvb2wodG9vbDogU2VnbWVudGF0aW9uUHJvZ3Jlc3MgJiB7IGJ1c3kkOiBPYnNlcnZhYmxlPGJvb2xlYW4+IH0sIHVudGlsJDogT2JzZXJ2YWJsZTx1bmtub3duPik6IHZvaWQge1xuICAgIHRvb2wucHJvZ3Jlc3MkLnBpcGUodGFrZVVudGlsKHVudGlsJCkpLnN1YnNjcmliZSgoZikgPT4gdGhpcy5vblByb2dyZXNzKGYpKTtcbiAgICB0b29sLnN0YXR1cyQucGlwZSh0YWtlVW50aWwodW50aWwkKSkuc3Vic2NyaWJlKChtKSA9PiB7XG4gICAgICB0aGlzLnN0YXR1cyA9IG07XG4gICAgICB0aGlzLmNoYW5nZWQoKTtcbiAgICB9KTtcbiAgICB0b29sLmJ1c3kkLnBpcGUodGFrZVVudGlsKHVudGlsJCkpLnN1YnNjcmliZSgoYnVzeSkgPT4ge1xuICAgICAgdGhpcy5idXN5ID0gYnVzeTtcbiAgICAgIGlmIChidXN5KSB0aGlzLnNob3coJ1NBTSBwb2ludCBzZWdtZW50YXRpb24nKTtcbiAgICAgIHRoaXMuY2hhbmdlZCgpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBgb3BgIHdpdGggdGhlIHRvb2wncyBzdGF0dXMgYW5kIGRvd25sb2FkIHByb2dyZXNzIGluIHRoZSBzdGlja3kgdG9hc3QsIHRoZW5cbiAgICogcmVwb3J0IHRoZSBvdXRjb21lOiB0aGUgcmVnaW9uIGNvdW50IChvciB0aGUgdG9vbCdzIGxhc3Qgc3RhdHVzIGxpbmUpIG9uIHN1Y2Nlc3MsXG4gICAqIHRoZSBlcnJvciBvbiBmYWlsdXJlLiBUaGUgdG9hc3Qgc3RheXMgdW50aWwgdGhlIHJ1biBzZXR0bGVzLlxuICAgKi9cbiAgYXN5bmMgcnVuKGxhYmVsOiBzdHJpbmcsIHRvb2w6IFNlZ21lbnRhdGlvblByb2dyZXNzLCBvcDogKCkgPT4gUHJvbWlzZTxudW1iZXI+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5zdGF0dXMgPSAnU3RhcnRpbmfigKYnO1xuICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgIHRoaXMuZG93bmxvYWRpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmJ1c3kgPSB0cnVlO1xuICAgIC8vIFRoZSBsYXN0IG5vbi1lbXB0eSBzdGF0dXMgaXMgd2hhdCB0aGUgcmVzdWx0IHJlcG9ydHM6IGB0b29sYCBpcyBvbmx5IGFuXG4gICAgLy8gT2JzZXJ2YWJsZSBwYWlyLCBzbyB0aGVyZSBpcyBubyBgLnZhbHVlYCB0byBzYW1wbGUgb25jZSB0aGUgcnVuIHNldHRsZXMuXG4gICAgbGV0IGxhc3RTdGF0dXMgPSAnJztcbiAgICBjb25zdCBzdWJzID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuICAgIHN1YnMuYWRkKHRvb2wucHJvZ3Jlc3MkLnN1YnNjcmliZSgoZikgPT4gdGhpcy5vblByb2dyZXNzKGYpKSk7XG4gICAgc3Vicy5hZGQoXG4gICAgICB0b29sLnN0YXR1cyQuc3Vic2NyaWJlKChtKSA9PiB7XG4gICAgICAgIGlmICghbSkgcmV0dXJuO1xuICAgICAgICBsYXN0U3RhdHVzID0gbTtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSBtO1xuICAgICAgICB0aGlzLmNoYW5nZWQoKTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5zaG93KGxhYmVsKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbiA9IGF3YWl0IG9wKCk7XG4gICAgICB0aGlzLm1lc3NhZ2VzLmFkZCh7XG4gICAgICAgIGtleTogdGhpcy5yZXN1bHRLZXksXG4gICAgICAgIHNldmVyaXR5OiBuID4gMCA/ICdzdWNjZXNzJyA6ICd3YXJuJyxcbiAgICAgICAgc3VtbWFyeTogbGFiZWwsXG4gICAgICAgIGRldGFpbDogbGFzdFN0YXR1cyB8fCAobiA+IDAgPyBgQWRkZWQgJHtufSByZWdpb24ocykuYCA6ICdObyByZWdpb25zIGFkZGVkLicpLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5tZXNzYWdlcy5hZGQoeyBrZXk6IHRoaXMucmVzdWx0S2V5LCBzZXZlcml0eTogJ2Vycm9yJywgc3VtbWFyeTogYCR7bGFiZWx9IGZhaWxlZGAsIGRldGFpbDogU3RyaW5nKGUpIH0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzdWJzLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLmhpZGUoKTtcbiAgICB9XG4gIH1cblxuICAvKiogU2hvdyB0aGUgc3RpY2t5IHRvYXN0IG9uY2UgKGlkZW1wb3RlbnQpLiAqL1xuICBzaG93KHN1bW1hcnk6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLnNob3duKSByZXR1cm47XG4gICAgdGhpcy5zaG93biA9IHRydWU7XG4gICAgdGhpcy5tZXNzYWdlcy5hZGQoeyBrZXk6IHRoaXMudG9hc3RLZXksIHN0aWNreTogdHJ1ZSwgc2V2ZXJpdHk6ICdpbmZvJywgc3VtbWFyeSB9KTtcbiAgfVxuXG4gIC8qKiBEaXNtaXNzIHRoZSBzdGlja3kgdG9hc3QgYW5kIHJlc2V0IGl0cyBwcm9ncmVzcy9zcGlubmVyIHN0YXRlLiAqL1xuICBoaWRlKCk6IHZvaWQge1xuICAgIHRoaXMuc2hvd24gPSBmYWxzZTtcbiAgICB0aGlzLmJ1c3kgPSBmYWxzZTtcbiAgICB0aGlzLmRvd25sb2FkaW5nID0gZmFsc2U7XG4gICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gICAgdGhpcy5tZXNzYWdlcy5jbGVhcih0aGlzLnRvYXN0S2V5KTtcbiAgICB0aGlzLmNoYW5nZWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgb25Qcm9ncmVzcyhmOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmRvd25sb2FkaW5nID0gZiA+PSAwICYmIGYgPCAxO1xuICAgIGlmIChmID49IDApIHRoaXMucHJvZ3Jlc3MgPSBNYXRoLm1pbigxMDAsIE1hdGgucm91bmQoZiAqIDEwMCkpO1xuICAgIHRoaXMuY2hhbmdlZCgpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,155 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { SharedModule } from 'primeng/api';
4
+ import { ButtonModule } from 'primeng/button';
5
+ import { MenuModule } from 'primeng/menu';
6
+ import { TooltipModule } from 'primeng/tooltip';
7
+ import { MODEL_INFO } from '../model-info';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ import * as i2 from "primeng/api";
11
+ import * as i3 from "primeng/button";
12
+ import * as i4 from "primeng/menu";
13
+ import * as i5 from "primeng/tooltip";
14
+ /**
15
+ * The toolbar's segmentation group: SAM box prompt, SAM point prompts and the
16
+ * shared SAM model picker, cellpose, and the contributed no-prompt tools (run,
17
+ * pick checkpoint, parameters). Presentational: the host runs every action.
18
+ */
19
+ export class SegmentationToolsComponent {
20
+ constructor() {
21
+ /** The armed tool's mode (`samPoint` highlights the point-prompt button), or null. */
22
+ this.activeDragMode = null;
23
+ /** SAM model picker options + current selection (jit-ui#90 P1). */
24
+ this.samModels = [];
25
+ /** The selected SAM model id. */
26
+ this.samModelId = '';
27
+ /** Contributed no-prompt tools, already filtered and sorted by the host. */
28
+ this.contributedTools = [];
29
+ /** Active checkpoint per contributed tool, keyed by tool id. */
30
+ this.toolModelIds = {};
31
+ /** Run box-prompted SAM segmentation on the drawn rectangles (jit-ui#90). */
32
+ this.segmentRegions = new EventEmitter();
33
+ /** Run cellpose-SAM (auto) inside each drawn rectangle's crop (jit-ui#90). */
34
+ this.segmentCellpose = new EventEmitter();
35
+ /** The SAM point tool's toggle ('samPoint'). */
36
+ this.toggleDragMode = new EventEmitter();
37
+ /** A SAM model was picked from the model menu (its id). */
38
+ this.samModelChange = new EventEmitter();
39
+ /** Run a contributed tool over the current view (its id). */
40
+ this.runTool = new EventEmitter();
41
+ /** A contributed tool's checkpoint was picked. */
42
+ this.toolModelChange = new EventEmitter();
43
+ /** Open a contributed tool's parameter dialog (its id). */
44
+ this.openToolParams = new EventEmitter();
45
+ /** Model picker for the Segment button's dropdown menu. The active model
46
+ * (`samModelId`) is marked with a check; selecting an item emits
47
+ * `samModelChange` (jit-ui#90 P1).
48
+ *
49
+ * Held as a stable array (rebuilt only when `samModels`/`samModelId` change),
50
+ * NOT a getter: a getter returns a fresh array with new `command` closures on
51
+ * every change-detection tick, which makes the bound `p-menu` overlay rebuild
52
+ * its DOM mid-interaction and swallow the click on a menu item.
53
+ *
54
+ * `tooltip` carries the model's description from {@link MODEL_INFO}; the
55
+ * menus' shared item template turns it into the hover info icon. p-menu's own
56
+ * rendering ignores the field (it reads `item.title`), so it is free to use. */
57
+ this.samMenuItems = [];
58
+ /**
59
+ * Model menus for the contributed tools, keyed by tool id. Same stable-array
60
+ * reasoning as {@link samMenuItems} — and it is why this is a map rebuilt in
61
+ * `ngOnChanges` rather than a method called from the template, which would
62
+ * hand `p-menu` a new array every tick.
63
+ *
64
+ * A contributed tool supplies its own per-model description, so unlike the
65
+ * SAM menu these do not consult {@link MODEL_INFO}: this library has no
66
+ * copy for checkpoints it does not know about.
67
+ */
68
+ this.toolMenuItems = {};
69
+ }
70
+ ngOnChanges(changes) {
71
+ if (changes['samModels'] || changes['samModelId']) {
72
+ this.samMenuItems = this.samModels.map((m) => ({
73
+ label: m.label,
74
+ icon: m.id === this.samModelId ? 'pi pi-check' : 'pi pi-fw',
75
+ tooltip: MODEL_INFO[m.id],
76
+ infoLabel: this.infoLabel(m.label, MODEL_INFO[m.id]),
77
+ command: () => this.samModelChange.emit(m.id),
78
+ }));
79
+ }
80
+ if (changes['contributedTools'] || changes['toolModelIds']) {
81
+ this.toolMenuItems = {};
82
+ for (const tool of this.contributedTools) {
83
+ const active = this.toolModelIds[tool.id] ?? tool.defaultModelId();
84
+ this.toolMenuItems[tool.id] = tool.models().map((m) => ({
85
+ label: m.label,
86
+ icon: m.id === active ? 'pi pi-check' : 'pi pi-fw',
87
+ tooltip: m.info,
88
+ infoLabel: this.infoLabel(m.label, m.info),
89
+ command: () => this.toolModelChange.emit({ toolId: tool.id, modelId: m.id }),
90
+ }));
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Strip markup from a model description so it can be read aloud.
96
+ *
97
+ * The copy in MODEL_INFO and in a contribution's `ToolModelOption.info` is
98
+ * written for a visual tooltip rendered with `[escape]="false"`, so it carries
99
+ * `<b>` and `<br>`. Passed to `aria-label` verbatim a screen reader announces
100
+ * the tags, so they are removed and `<br>` becomes a sentence break. Entities
101
+ * used in that copy (`&nbsp;`, `&times;`, `&amp;`) are decoded for the same
102
+ * reason.
103
+ */
104
+ plainText(html) {
105
+ return (html ?? '')
106
+ .replace(/<br\s*\/?>/gi, '. ')
107
+ .replace(/<[^>]+>/g, '')
108
+ .replace(/&nbsp;/g, ' ')
109
+ .replace(/&times;/g, 'x')
110
+ .replace(/&amp;/g, '&')
111
+ .replace(/\s+/g, ' ')
112
+ .trim();
113
+ }
114
+ /** The info button's `aria-label` (`infoLabel` on a menu item), built once with the
115
+ * menu rather than by a template call on every check; none without a description. */
116
+ infoLabel(label, info) {
117
+ return info ? `About ${label}: ${this.plainText(info)}` : undefined;
118
+ }
119
+ /** Keeps each contributed tool's `p-menu` overlay alive across CD ticks —
120
+ * re-creating it mid-interaction swallows the click on a menu item. */
121
+ trackToolById(_index, tool) {
122
+ return tool.id;
123
+ }
124
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SegmentationToolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
125
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SegmentationToolsComponent, isStandalone: true, selector: "toolbar-segmentation-tools", inputs: { activeDragMode: "activeDragMode", samModels: "samModels", samModelId: "samModelId", contributedTools: "contributedTools", toolModelIds: "toolModelIds" }, outputs: { segmentRegions: "segmentRegions", segmentCellpose: "segmentCellpose", toggleDragMode: "toggleDragMode", samModelChange: "samModelChange", runTool: "runTool", toolModelChange: "toolModelChange", openToolParams: "openToolParams" }, usesOnChanges: true, ngImport: i0, template: "<!-- SAM (jit-ui#90): box-prompt segment, interactive point prompts, and a\n model picker. -->\n<span class=\"toolbar-separator\"></span>\n<!-- SAM controls grouped: box-prompt Segment, then the point-prompt tool,\n then the model-picker dropdown (the chevron) which governs BOTH tools.\n Falls back to Segment + point with no model picker when none are set. -->\n<span *ngIf=\"samModels.length; else segmentPlain\" class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Pick the SAM model\"\n pTooltip=\"Pick the SAM model (used by both segment tools)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"samModelMenu.toggle($event)\"\n >\n </p-button>\n</span>\n<ng-template #segmentPlain>\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n </span>\n</ng-template>\n<!-- Point-prompt tool \u2014 shared between the models / no-models layouts so it\n always sits just left of the model dropdown. -->\n<ng-template #samPointBtn>\n <p-button\n size=\"small\"\n ariaLabel=\"SAM point prompts\"\n [text]=\"activeDragMode !== 'samPoint'\"\n pTooltip=\"SAM point prompts: click a fiber to segment it as a new region;\n Shift/Alt-click to refine (exclude) the current one.<br>Esc undoes it.\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toggleDragMode.emit('samPoint')\"\n >\n <img\n src=\"assets/plotting/sam-point-prompt.svg\"\n [class]=\"activeDragMode === 'samPoint' ? 'toolbar-icon-active' : 'toolbar-icon-dark'\"\n style=\"width: 1rem\"\n />\n </p-button>\n</ng-template>\n<p-menu #samModelMenu styleClass=\"model-menu\" [model]=\"samMenuItems\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n</p-menu>\n\n<!-- Shared item body for all three model pickers (SAM / YOLO / retinal):\n the standard check-or-blank icon and label, plus an info icon carrying\n the model's description as a hover tooltip. This replaced a single\n \"About the SAM models\" overlay panel \u2014 per-model text sits next to the\n model it describes, and YOLO/retinal get the same affordance.\n\n p-menu puts its click handler on the wrapping `.p-menuitem-content`,\n outside this template, so `command` still fires and the whole row stays\n clickable \u2014 which is also why the info icon has to stop propagation, or\n reading about a model would switch to it. -->\n<ng-template #modelMenuItem let-item>\n <a class=\"p-menuitem-link model-menu-item\">\n <span class=\"p-menuitem-icon\" [ngClass]=\"item.icon\"></span>\n <span class=\"p-menuitem-text\">{{ item.label }}</span>\n <!-- `bottom` like every other tooltip in this toolbar, and for room:\n these menus open under buttons that can sit near the right edge,\n where a `right` tooltip has a few hundred px and squeezes its text\n into a narrow column instead of using its max-width. -->\n <!-- A focusable <button>, not a bare <i>. As an <i> the description\n was reachable only by hovering a mouse: not tabbable, no\n accessible name, nothing for a screen reader to announce \u2014 so\n keyboard and AT users could pick a checkpoint but never read what\n it was. PrimeNG's tooltip shows on focus as well as hover, so\n making it a button restores it for free.\n\n `aria-describedby` is deliberately not used: the tooltip is\n rendered into `body` on demand and has no stable id to point at.\n The description is carried on `aria-label` instead, which is\n announced whether or not the tooltip is showing. It is stripped of\n markup first, since the copy contains `<b>`/`<br>` for the visual\n tooltip and those would otherwise be read out literally. -->\n <button\n *ngIf=\"item.tooltip\"\n type=\"button\"\n class=\"pi pi-info-circle model-info-icon\"\n [attr.aria-label]=\"item.infoLabel\"\n [pTooltip]=\"item.tooltip\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n appendTo=\"body\"\n tooltipStyleClass=\"model-info-tooltip\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n ></button>\n </a>\n</ng-template>\n<p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment cells (cellpose-SAM)\"\n pTooltip=\"Auto-segment cells inside each drawn rectangle (cellpose-SAM)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentCellpose.emit()\"\n>\n <img src=\"assets/plotting/cells.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n</p-button>\n\n<!-- Contributed no-prompt tools (TOOLBAR_TOOLS). Unlike the SAM and\n cellpose tools these take no prompt \u2014 they sweep the whole current\n view rather than being pointed at something \u2014 so there is nothing to\n draw first. Each renders the same split button: run, pick checkpoint,\n open parameters.\n\n Nothing here names a specific tool. The library ships none; a host\n registers them, which is what lets this package be published without\n the closed model dependencies. -->\n<ng-container *ngFor=\"let tool of contributedTools; trackBy: trackToolById\">\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"tool.label\"\n [pTooltip]=\"tool.runTooltip\"\n tooltipPosition=\"bottom\"\n (onClick)=\"runTool.emit(tool.id)\"\n >\n <!-- `toolbar-icon-dark` is hardcoded rather than bound, unlike the\n toggle tools: these fire a run and have no active state. -->\n <img\n *ngIf=\"tool.icon.src\"\n [src]=\"tool.icon.src\"\n class=\"toolbar-icon-dark\"\n style=\"width: 1rem\"\n [alt]=\"tool.label\"\n />\n <i *ngIf=\"tool.icon.pi\" class=\"pi {{ tool.icon.pi }}\"></i>\n </p-button>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Pick the model for ' + tool.label\"\n [pTooltip]=\"tool.modelTooltip || 'Pick the model'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toolMenu.toggle($event)\"\n >\n </p-button>\n <p-button\n *ngIf=\"tool.params.length\"\n icon=\"pi pi-sliders-h\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Parameters for ' + tool.label\"\n [pTooltip]=\"tool.paramsTooltip || 'Parameters'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"openToolParams.emit(tool.id)\"\n >\n </p-button>\n </span>\n <p-menu #toolMenu styleClass=\"model-menu\" [model]=\"toolMenuItems[tool.id] || []\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n </p-menu>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SharedModule }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i4.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: TooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
126
+ }
127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SegmentationToolsComponent, decorators: [{
128
+ type: Component,
129
+ args: [{ selector: 'toolbar-segmentation-tools', standalone: true, imports: [CommonModule, SharedModule, ButtonModule, MenuModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- SAM (jit-ui#90): box-prompt segment, interactive point prompts, and a\n model picker. -->\n<span class=\"toolbar-separator\"></span>\n<!-- SAM controls grouped: box-prompt Segment, then the point-prompt tool,\n then the model-picker dropdown (the chevron) which governs BOTH tools.\n Falls back to Segment + point with no model picker when none are set. -->\n<span *ngIf=\"samModels.length; else segmentPlain\" class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Pick the SAM model\"\n pTooltip=\"Pick the SAM model (used by both segment tools)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"samModelMenu.toggle($event)\"\n >\n </p-button>\n</span>\n<ng-template #segmentPlain>\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n </span>\n</ng-template>\n<!-- Point-prompt tool \u2014 shared between the models / no-models layouts so it\n always sits just left of the model dropdown. -->\n<ng-template #samPointBtn>\n <p-button\n size=\"small\"\n ariaLabel=\"SAM point prompts\"\n [text]=\"activeDragMode !== 'samPoint'\"\n pTooltip=\"SAM point prompts: click a fiber to segment it as a new region;\n Shift/Alt-click to refine (exclude) the current one.<br>Esc undoes it.\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toggleDragMode.emit('samPoint')\"\n >\n <img\n src=\"assets/plotting/sam-point-prompt.svg\"\n [class]=\"activeDragMode === 'samPoint' ? 'toolbar-icon-active' : 'toolbar-icon-dark'\"\n style=\"width: 1rem\"\n />\n </p-button>\n</ng-template>\n<p-menu #samModelMenu styleClass=\"model-menu\" [model]=\"samMenuItems\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n</p-menu>\n\n<!-- Shared item body for all three model pickers (SAM / YOLO / retinal):\n the standard check-or-blank icon and label, plus an info icon carrying\n the model's description as a hover tooltip. This replaced a single\n \"About the SAM models\" overlay panel \u2014 per-model text sits next to the\n model it describes, and YOLO/retinal get the same affordance.\n\n p-menu puts its click handler on the wrapping `.p-menuitem-content`,\n outside this template, so `command` still fires and the whole row stays\n clickable \u2014 which is also why the info icon has to stop propagation, or\n reading about a model would switch to it. -->\n<ng-template #modelMenuItem let-item>\n <a class=\"p-menuitem-link model-menu-item\">\n <span class=\"p-menuitem-icon\" [ngClass]=\"item.icon\"></span>\n <span class=\"p-menuitem-text\">{{ item.label }}</span>\n <!-- `bottom` like every other tooltip in this toolbar, and for room:\n these menus open under buttons that can sit near the right edge,\n where a `right` tooltip has a few hundred px and squeezes its text\n into a narrow column instead of using its max-width. -->\n <!-- A focusable <button>, not a bare <i>. As an <i> the description\n was reachable only by hovering a mouse: not tabbable, no\n accessible name, nothing for a screen reader to announce \u2014 so\n keyboard and AT users could pick a checkpoint but never read what\n it was. PrimeNG's tooltip shows on focus as well as hover, so\n making it a button restores it for free.\n\n `aria-describedby` is deliberately not used: the tooltip is\n rendered into `body` on demand and has no stable id to point at.\n The description is carried on `aria-label` instead, which is\n announced whether or not the tooltip is showing. It is stripped of\n markup first, since the copy contains `<b>`/`<br>` for the visual\n tooltip and those would otherwise be read out literally. -->\n <button\n *ngIf=\"item.tooltip\"\n type=\"button\"\n class=\"pi pi-info-circle model-info-icon\"\n [attr.aria-label]=\"item.infoLabel\"\n [pTooltip]=\"item.tooltip\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n appendTo=\"body\"\n tooltipStyleClass=\"model-info-tooltip\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n ></button>\n </a>\n</ng-template>\n<p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment cells (cellpose-SAM)\"\n pTooltip=\"Auto-segment cells inside each drawn rectangle (cellpose-SAM)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentCellpose.emit()\"\n>\n <img src=\"assets/plotting/cells.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n</p-button>\n\n<!-- Contributed no-prompt tools (TOOLBAR_TOOLS). Unlike the SAM and\n cellpose tools these take no prompt \u2014 they sweep the whole current\n view rather than being pointed at something \u2014 so there is nothing to\n draw first. Each renders the same split button: run, pick checkpoint,\n open parameters.\n\n Nothing here names a specific tool. The library ships none; a host\n registers them, which is what lets this package be published without\n the closed model dependencies. -->\n<ng-container *ngFor=\"let tool of contributedTools; trackBy: trackToolById\">\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"tool.label\"\n [pTooltip]=\"tool.runTooltip\"\n tooltipPosition=\"bottom\"\n (onClick)=\"runTool.emit(tool.id)\"\n >\n <!-- `toolbar-icon-dark` is hardcoded rather than bound, unlike the\n toggle tools: these fire a run and have no active state. -->\n <img\n *ngIf=\"tool.icon.src\"\n [src]=\"tool.icon.src\"\n class=\"toolbar-icon-dark\"\n style=\"width: 1rem\"\n [alt]=\"tool.label\"\n />\n <i *ngIf=\"tool.icon.pi\" class=\"pi {{ tool.icon.pi }}\"></i>\n </p-button>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Pick the model for ' + tool.label\"\n [pTooltip]=\"tool.modelTooltip || 'Pick the model'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toolMenu.toggle($event)\"\n >\n </p-button>\n <p-button\n *ngIf=\"tool.params.length\"\n icon=\"pi pi-sliders-h\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Parameters for ' + tool.label\"\n [pTooltip]=\"tool.paramsTooltip || 'Parameters'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"openToolParams.emit(tool.id)\"\n >\n </p-button>\n </span>\n <p-menu #toolMenu styleClass=\"model-menu\" [model]=\"toolMenuItems[tool.id] || []\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n </p-menu>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"] }]
130
+ }], propDecorators: { activeDragMode: [{
131
+ type: Input
132
+ }], samModels: [{
133
+ type: Input
134
+ }], samModelId: [{
135
+ type: Input
136
+ }], contributedTools: [{
137
+ type: Input
138
+ }], toolModelIds: [{
139
+ type: Input
140
+ }], segmentRegions: [{
141
+ type: Output
142
+ }], segmentCellpose: [{
143
+ type: Output
144
+ }], toggleDragMode: [{
145
+ type: Output
146
+ }], samModelChange: [{
147
+ type: Output
148
+ }], runTool: [{
149
+ type: Output
150
+ }], toolModelChange: [{
151
+ type: Output
152
+ }], openToolParams: [{
153
+ type: Output
154
+ }] } });
155
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24tdG9vbHMvc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24tdG9vbHMvc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQVksWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUdoRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7Ozs7O0FBRTNDOzs7O0dBSUc7QUFTSCxNQUFNLE9BQU8sMEJBQTBCO0lBUnZDO1FBU0Usc0ZBQXNGO1FBQzdFLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUM5QyxtRUFBbUU7UUFDMUQsY0FBUyxHQUFvQyxFQUFFLENBQUM7UUFDekQsaUNBQWlDO1FBQ3hCLGVBQVUsR0FBRyxFQUFFLENBQUM7UUFDekIsNEVBQTRFO1FBQ25FLHFCQUFnQixHQUE4QixFQUFFLENBQUM7UUFDMUQsZ0VBQWdFO1FBQ3ZELGlCQUFZLEdBQTJCLEVBQUUsQ0FBQztRQUVuRCw2RUFBNkU7UUFDbkUsbUJBQWMsR0FBRyxJQUFJLFlBQVks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TTtnQkFFRyxjQUFjO3NCQUF2QixNQUFNO2dCQUVHLGNBQWM7c0JBQXZCLE1BQU07Z0JBRUcsT0FBTztzQkFBaEIsTUFBTTtnQkFFRyxlQUFlO3NCQUF4QixNQUFNO2dCQUVHLGNBQWM7c0JBQXZCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTWVudUl0ZW0sIFNoYXJlZE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYXBpJztcbmltcG9ydCB7IEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYnV0dG9uJztcbmltcG9ydCB7IE1lbnVNb2R1bGUgfSBmcm9tICdwcmltZW5nL21lbnUnO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB7IFRvb2xiYXJUb29sQ29udHJpYnV0aW9uIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Rvb2xiYXItdG9vbC5jb250cmFjdCc7XG5pbXBvcnQgeyBNT0RFTF9JTkZPIH0gZnJvbSAnLi4vbW9kZWwtaW5mbyc7XG5cbi8qKlxuICogVGhlIHRvb2xiYXIncyBzZWdtZW50YXRpb24gZ3JvdXA6IFNBTSBib3ggcHJvbXB0LCBTQU0gcG9pbnQgcHJvbXB0cyBhbmQgdGhlXG4gKiBzaGFyZWQgU0FNIG1vZGVsIHBpY2tlciwgY2VsbHBvc2UsIGFuZCB0aGUgY29udHJpYnV0ZWQgbm8tcHJvbXB0IHRvb2xzIChydW4sXG4gKiBwaWNrIGNoZWNrcG9pbnQsIHBhcmFtZXRlcnMpLiBQcmVzZW50YXRpb25hbDogdGhlIGhvc3QgcnVucyBldmVyeSBhY3Rpb24uXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3Rvb2xiYXItc2VnbWVudGF0aW9uLXRvb2xzJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgU2hhcmVkTW9kdWxlLCBCdXR0b25Nb2R1bGUsIE1lbnVNb2R1bGUsIFRvb2x0aXBNb2R1bGVdLFxuICB0ZW1wbGF0ZVVybDogJy4vc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBTZWdtZW50YXRpb25Ub29sc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8qKiBUaGUgYXJtZWQgdG9vbCdzIG1vZGUgKGBzYW1Qb2ludGAgaGlnaGxpZ2h0cyB0aGUgcG9pbnQtcHJvbXB0IGJ1dHRvbiksIG9yIG51bGwuICovXG4gIEBJbnB1dCgpIGFjdGl2ZURyYWdNb2RlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFNBTSBtb2RlbCBwaWNrZXIgb3B0aW9ucyArIGN1cnJlbnQgc2VsZWN0aW9uIChqaXQtdWkjOTAgUDEpLiAqL1xuICBASW5wdXQoKSBzYW1Nb2RlbHM6IHsgaWQ6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9W10gPSBbXTtcbiAgLyoqIFRoZSBzZWxlY3RlZCBTQU0gbW9kZWwgaWQuICovXG4gIEBJbnB1dCgpIHNhbU1vZGVsSWQgPSAnJztcbiAgLyoqIENvbnRyaWJ1dGVkIG5vLXByb21wdCB0b29scywgYWxyZWFkeSBmaWx0ZXJlZCBhbmQgc29ydGVkIGJ5IHRoZSBob3N0LiAqL1xuICBASW5wdXQoKSBjb250cmlidXRlZFRvb2xzOiBUb29sYmFyVG9vbENvbnRyaWJ1dGlvbltdID0gW107XG4gIC8qKiBBY3RpdmUgY2hlY2twb2ludCBwZXIgY29udHJpYnV0ZWQgdG9vbCwga2V5ZWQgYnkgdG9vbCBpZC4gKi9cbiAgQElucHV0KCkgdG9vbE1vZGVsSWRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cbiAgLyoqIFJ1biBib3gtcHJvbXB0ZWQgU0FNIHNlZ21lbnRhdGlvbiBvbiB0aGUgZHJhd24gcmVjdGFuZ2xlcyAoaml0LXVpIzkwKS4gKi9cbiAgQE91dHB1dCgpIHNlZ21lbnRSZWdpb25zID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuICAvKiogUnVuIGNlbGxwb3NlLVNBTSAoYXV0bykgaW5zaWRlIGVhY2ggZHJhd24gcmVjdGFuZ2xlJ3MgY3JvcCAoaml0LXVpIzkwKS4gKi9cbiAgQE91dHB1dCgpIHNlZ21lbnRDZWxscG9zZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIFRoZSBTQU0gcG9pbnQgdG9vbCdzIHRvZ2dsZSAoJ3NhbVBvaW50JykuICovXG4gIEBPdXRwdXQoKSB0b2dnbGVEcmFnTW9kZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAvKiogQSBTQU0gbW9kZWwgd2FzIHBpY2tlZCBmcm9tIHRoZSBtb2RlbCBtZW51IChpdHMgaWQpLiAqL1xuICBAT3V0cHV0KCkgc2FtTW9kZWxDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgLyoqIFJ1biBhIGNvbnRyaWJ1dGVkIHRvb2wgb3ZlciB0aGUgY3VycmVudCB2aWV3IChpdHMgaWQpLiAqL1xuICBAT3V0cHV0KCkgcnVuVG9vbCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAvKiogQSBjb250cmlidXRlZCB0b29sJ3MgY2hlY2twb2ludCB3YXMgcGlja2VkLiAqL1xuICBAT3V0cHV0KCkgdG9vbE1vZGVsQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjx7IHRvb2xJZDogc3RyaW5nOyBtb2RlbElkOiBzdHJpbmcgfT4oKTtcbiAgLyoqIE9wZW4gYSBjb250cmlidXRlZCB0b29sJ3MgcGFyYW1ldGVyIGRpYWxvZyAoaXRzIGlkKS4gKi9cbiAgQE91dHB1dCgpIG9wZW5Ub29sUGFyYW1zID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgLyoqIE1vZGVsIHBpY2tlciBmb3IgdGhlIFNlZ21lbnQgYnV0dG9uJ3MgZHJvcGRvd24gbWVudS4gVGhlIGFjdGl2ZSBtb2RlbFxuICAgKiAgKGBzYW1Nb2RlbElkYCkgaXMgbWFya2VkIHdpdGggYSBjaGVjazsgc2VsZWN0aW5nIGFuIGl0ZW0gZW1pdHNcbiAgICogIGBzYW1Nb2RlbENoYW5nZWAgKGppdC11aSM5MCBQMSkuXG4gICAqXG4gICAqICBIZWxkIGFzIGEgc3RhYmxlIGFycmF5IChyZWJ1aWx0IG9ubHkgd2hlbiBgc2FtTW9kZWxzYC9gc2FtTW9kZWxJZGAgY2hhbmdlKSxcbiAgICogIE5PVCBhIGdldHRlcjogYSBnZXR0ZXIgcmV0dXJucyBhIGZyZXNoIGFycmF5IHdpdGggbmV3IGBjb21tYW5kYCBjbG9zdXJlcyBvblxuICAgKiAgZXZlcnkgY2hhbmdlLWRldGVjdGlvbiB0aWNrLCB3aGljaCBtYWtlcyB0aGUgYm91bmQgYHAtbWVudWAgb3ZlcmxheSByZWJ1aWxkXG4gICAqICBpdHMgRE9NIG1pZC1pbnRlcmFjdGlvbiBhbmQgc3dhbGxvdyB0aGUgY2xpY2sgb24gYSBtZW51IGl0ZW0uXG4gICAqXG4gICAqICBgdG9vbHRpcGAgY2FycmllcyB0aGUgbW9kZWwncyBkZXNjcmlwdGlvbiBmcm9tIHtAbGluayBNT0RFTF9JTkZPfTsgdGhlXG4gICAqICBtZW51cycgc2hhcmVkIGl0ZW0gdGVtcGxhdGUgdHVybnMgaXQgaW50byB0aGUgaG92ZXIgaW5mbyBpY29uLiBwLW1lbnUncyBvd25cbiAgICogIHJlbmRlcmluZyBpZ25vcmVzIHRoZSBmaWVsZCAoaXQgcmVhZHMgYGl0ZW0udGl0bGVgKSwgc28gaXQgaXMgZnJlZSB0byB1c2UuICovXG4gIHByb3RlY3RlZCBzYW1NZW51SXRlbXM6IE1lbnVJdGVtW10gPSBbXTtcbiAgLyoqXG4gICAqIE1vZGVsIG1lbnVzIGZvciB0aGUgY29udHJpYnV0ZWQgdG9vbHMsIGtleWVkIGJ5IHRvb2wgaWQuIFNhbWUgc3RhYmxlLWFycmF5XG4gICAqIHJlYXNvbmluZyBhcyB7QGxpbmsgc2FtTWVudUl0ZW1zfSDigJQgYW5kIGl0IGlzIHdoeSB0aGlzIGlzIGEgbWFwIHJlYnVpbHQgaW5cbiAgICogYG5nT25DaGFuZ2VzYCByYXRoZXIgdGhhbiBhIG1ldGhvZCBjYWxsZWQgZnJvbSB0aGUgdGVtcGxhdGUsIHdoaWNoIHdvdWxkXG4gICAqIGhhbmQgYHAtbWVudWAgYSBuZXcgYXJyYXkgZXZlcnkgdGljay5cbiAgICpcbiAgICogQSBjb250cmlidXRlZCB0b29sIHN1cHBsaWVzIGl0cyBvd24gcGVyLW1vZGVsIGRlc2NyaXB0aW9uLCBzbyB1bmxpa2UgdGhlXG4gICAqIFNBTSBtZW51IHRoZXNlIGRvIG5vdCBjb25zdWx0IHtAbGluayBNT0RFTF9JTkZPfTogdGhpcyBsaWJyYXJ5IGhhcyBub1xuICAgKiBjb3B5IGZvciBjaGVja3BvaW50cyBpdCBkb2VzIG5vdCBrbm93IGFib3V0LlxuICAgKi9cbiAgcHJvdGVjdGVkIHRvb2xNZW51SXRlbXM6IFJlY29yZDxzdHJpbmcsIE1lbnVJdGVtW10+ID0ge307XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydzYW1Nb2RlbHMnXSB8fCBjaGFuZ2VzWydzYW1Nb2RlbElkJ10pIHtcbiAgICAgIHRoaXMuc2FtTWVudUl0ZW1zID0gdGhpcy5zYW1Nb2RlbHMubWFwKChtKSA9PiAoe1xuICAgICAgICBsYWJlbDogbS5sYWJlbCxcbiAgICAgICAgaWNvbjogbS5pZCA9PT0gdGhpcy5zYW1Nb2RlbElkID8gJ3BpIHBpLWNoZWNrJyA6ICdwaSBwaS1mdycsXG4gICAgICAgIHRvb2x0aXA6IE1PREVMX0lORk9bbS5pZF0sXG4gICAgICAgIGluZm9MYWJlbDogdGhpcy5pbmZvTGFiZWwobS5sYWJlbCwgTU9ERUxfSU5GT1ttLmlkXSksXG4gICAgICAgIGNvbW1hbmQ6ICgpID0+IHRoaXMuc2FtTW9kZWxDaGFuZ2UuZW1pdChtLmlkKSxcbiAgICAgIH0pKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ2NvbnRyaWJ1dGVkVG9vbHMnXSB8fCBjaGFuZ2VzWyd0b29sTW9kZWxJZHMnXSkge1xuICAgICAgdGhpcy50b29sTWVudUl0ZW1zID0ge307XG4gICAgICBmb3IgKGNvbnN0IHRvb2wgb2YgdGhpcy5jb250cmlidXRlZFRvb2xzKSB7XG4gICAgICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMudG9vbE1vZGVsSWRzW3Rvb2wuaWRdID8/IHRvb2wuZGVmYXVsdE1vZGVsSWQoKTtcbiAgICAgICAgdGhpcy50b29sTWVudUl0ZW1zW3Rvb2wuaWRdID0gdG9vbC5tb2RlbHMoKS5tYXAoKG0pID0+ICh7XG4gICAgICAgICAgbGFiZWw6IG0ubGFiZWwsXG4gICAgICAgICAgaWNvbjogbS5pZCA9PT0gYWN0aXZlID8gJ3BpIHBpLWNoZWNrJyA6ICdwaSBwaS1mdycsXG4gICAgICAgICAgdG9vbHRpcDogbS5pbmZvLFxuICAgICAgICAgIGluZm9MYWJlbDogdGhpcy5pbmZvTGFiZWwobS5sYWJlbCwgbS5pbmZvKSxcbiAgICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLnRvb2xNb2RlbENoYW5nZS5lbWl0KHsgdG9vbElkOiB0b29sLmlkLCBtb2RlbElkOiBtLmlkIH0pLFxuICAgICAgICB9KSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0cmlwIG1hcmt1cCBmcm9tIGEgbW9kZWwgZGVzY3JpcHRpb24gc28gaXQgY2FuIGJlIHJlYWQgYWxvdWQuXG4gICAqXG4gICAqIFRoZSBjb3B5IGluIE1PREVMX0lORk8gYW5kIGluIGEgY29udHJpYnV0aW9uJ3MgYFRvb2xNb2RlbE9wdGlvbi5pbmZvYCBpc1xuICAgKiB3cml0dGVuIGZvciBhIHZpc3VhbCB0b29sdGlwIHJlbmRlcmVkIHdpdGggYFtlc2NhcGVdPVwiZmFsc2VcImAsIHNvIGl0IGNhcnJpZXNcbiAgICogYDxiPmAgYW5kIGA8YnI+YC4gUGFzc2VkIHRvIGBhcmlhLWxhYmVsYCB2ZXJiYXRpbSBhIHNjcmVlbiByZWFkZXIgYW5ub3VuY2VzXG4gICAqIHRoZSB0YWdzLCBzbyB0aGV5IGFyZSByZW1vdmVkIGFuZCBgPGJyPmAgYmVjb21lcyBhIHNlbnRlbmNlIGJyZWFrLiBFbnRpdGllc1xuICAgKiB1c2VkIGluIHRoYXQgY29weSAoYCZuYnNwO2AsIGAmdGltZXM7YCwgYCZhbXA7YCkgYXJlIGRlY29kZWQgZm9yIHRoZSBzYW1lXG4gICAqIHJlYXNvbi5cbiAgICovXG4gIHByb3RlY3RlZCBwbGFpblRleHQoaHRtbDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gKGh0bWwgPz8gJycpXG4gICAgICAucmVwbGFjZSgvPGJyXFxzKlxcLz8+L2dpLCAnLiAnKVxuICAgICAgLnJlcGxhY2UoLzxbXj5dKz4vZywgJycpXG4gICAgICAucmVwbGFjZSgvJm5ic3A7L2csICcgJylcbiAgICAgIC5yZXBsYWNlKC8mdGltZXM7L2csICd4JylcbiAgICAgIC5yZXBsYWNlKC8mYW1wOy9nLCAnJicpXG4gICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpXG4gICAgICAudHJpbSgpO1xuICB9XG5cbiAgLyoqIFRoZSBpbmZvIGJ1dHRvbidzIGBhcmlhLWxhYmVsYCAoYGluZm9MYWJlbGAgb24gYSBtZW51IGl0ZW0pLCBidWlsdCBvbmNlIHdpdGggdGhlXG4gICAqICBtZW51IHJhdGhlciB0aGFuIGJ5IGEgdGVtcGxhdGUgY2FsbCBvbiBldmVyeSBjaGVjazsgbm9uZSB3aXRob3V0IGEgZGVzY3JpcHRpb24uICovXG4gIHByaXZhdGUgaW5mb0xhYmVsKGxhYmVsOiBzdHJpbmcsIGluZm86IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIGluZm8gPyBgQWJvdXQgJHtsYWJlbH06ICR7dGhpcy5wbGFpblRleHQoaW5mbyl9YCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKiBLZWVwcyBlYWNoIGNvbnRyaWJ1dGVkIHRvb2wncyBgcC1tZW51YCBvdmVybGF5IGFsaXZlIGFjcm9zcyBDRCB0aWNrcyDigJRcbiAgICogIHJlLWNyZWF0aW5nIGl0IG1pZC1pbnRlcmFjdGlvbiBzd2FsbG93cyB0aGUgY2xpY2sgb24gYSBtZW51IGl0ZW0uICovXG4gIHByb3RlY3RlZCB0cmFja1Rvb2xCeUlkKF9pbmRleDogbnVtYmVyLCB0b29sOiB7IGlkOiBzdHJpbmcgfSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRvb2wuaWQ7XG4gIH1cbn1cbiIsIjwhLS0gU0FNIChqaXQtdWkjOTApOiBib3gtcHJvbXB0IHNlZ21lbnQsIGludGVyYWN0aXZlIHBvaW50IHByb21wdHMsIGFuZCBhXG4gICAgIG1vZGVsIHBpY2tlci4gLS0+XG48c3BhbiBjbGFzcz1cInRvb2xiYXItc2VwYXJhdG9yXCI+PC9zcGFuPlxuPCEtLSBTQU0gY29udHJvbHMgZ3JvdXBlZDogYm94LXByb21wdCBTZWdtZW50LCB0aGVuIHRoZSBwb2ludC1wcm9tcHQgdG9vbCxcbiAgICAgdGhlbiB0aGUgbW9kZWwtcGlja2VyIGRyb3Bkb3duICh0aGUgY2hldnJvbikgd2hpY2ggZ292ZXJucyBCT1RIIHRvb2xzLlxuICAgICBGYWxscyBiYWNrIHRvIFNlZ21lbnQgKyBwb2ludCB3aXRoIG5vIG1vZGVsIHBpY2tlciB3aGVuIG5vbmUgYXJlIHNldC4gLS0+XG48c3BhbiAqbmdJZj1cInNhbU1vZGVscy5sZW5ndGg7IGVsc2Ugc2VnbWVudFBsYWluXCIgY2xhc3M9XCJwLWJ1dHRvbnNldCBzZWdtZW50LXNwbGl0XCI+XG4gIDxwLWJ1dHRvblxuICAgIHNpemU9XCJzbWFsbFwiXG4gICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgYXJpYUxhYmVsPVwiU2VnbWVudCB3aXRoIFNBTSAoYm94IHByb21wdClcIlxuICAgIHBUb29sdGlwPVwiU2VnbWVudCB0aGUgZHJhd24gcmVjdGFuZ2xlcyB3aXRoIFNBTSAoYm94IHByb21wdClcIlxuICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgKG9uQ2xpY2spPVwic2VnbWVudFJlZ2lvbnMuZW1pdCgpXCJcbiAgPlxuICAgIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL3NhbS1ib3gtcHJvbXB0LnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbiAgPC9wLWJ1dHRvbj5cbiAgPG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJzYW1Qb2ludEJ0blwiPjwvbmctY29udGFpbmVyPlxuICA8cC1idXR0b25cbiAgICBpY29uPVwicGkgcGktY2hldnJvbi1kb3duXCJcbiAgICBzaXplPVwic21hbGxcIlxuICAgIFt0ZXh0XT1cInRydWVcIlxuICAgIGFyaWFMYWJlbD1cIlBpY2sgdGhlIFNBTSBtb2RlbFwiXG4gICAgcFRvb2x0aXA9XCJQaWNrIHRoZSBTQU0gbW9kZWwgKHVzZWQgYnkgYm90aCBzZWdtZW50IHRvb2xzKVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAob25DbGljayk9XCJzYW1Nb2RlbE1lbnUudG9nZ2xlKCRldmVudClcIlxuICA+XG4gIDwvcC1idXR0b24+XG48L3NwYW4+XG48bmctdGVtcGxhdGUgI3NlZ21lbnRQbGFpbj5cbiAgPHNwYW4gY2xhc3M9XCJwLWJ1dHRvbnNldCBzZWdtZW50LXNwbGl0XCI+XG4gICAgPHAtYnV0dG9uXG4gICAgICBzaXplPVwic21hbGxcIlxuICAgICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgICBhcmlhTGFiZWw9XCJTZWdtZW50IHdpdGggU0FNIChib3ggcHJvbXB0KVwiXG4gICAgICBwVG9vbHRpcD1cIlNlZ21lbnQgdGhlIGRyYXduIHJlY3RhbmdsZXMgd2l0aCBTQU0gKGJveCBwcm9tcHQpXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJzZWdtZW50UmVnaW9ucy5lbWl0KClcIlxuICAgID5cbiAgICAgIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL3NhbS1ib3gtcHJvbXB0LnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbiAgICA8L3AtYnV0dG9uPlxuICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwic2FtUG9pbnRCdG5cIj48L25nLWNvbnRhaW5lcj5cbiAgPC9zcGFuPlxuPC9uZy10ZW1wbGF0ZT5cbjwhLS0gUG9pbnQtcHJvbXB0IHRvb2wg4oCUIHNoYXJlZCBiZXR3ZWVuIHRoZSBtb2RlbHMgLyBuby1tb2RlbHMgbGF5b3V0cyBzbyBpdFxuICAgICBhbHdheXMgc2l0cyBqdXN0IGxlZnQgb2YgdGhlIG1vZGVsIGRyb3Bkb3duLiAtLT5cbjxuZy10ZW1wbGF0ZSAjc2FtUG9pbnRCdG4+XG4gIDxwLWJ1dHRvblxuICAgIHNpemU9XCJzbWFsbFwiXG4gICAgYXJpYUxhYmVsPVwiU0FNIHBvaW50IHByb21wdHNcIlxuICAgIFt0ZXh0XT1cImFjdGl2ZURyYWdNb2RlICE9PSAnc2FtUG9pbnQnXCJcbiAgICBwVG9vbHRpcD1cIlNBTSBwb2ludCBwcm9tcHRzOiBjbGljayBhIGZpYmVyIHRvIHNlZ21lbnQgaXQgYXMgYSBuZXcgcmVnaW9uO1xuICAgICAgICAgICAgU2hpZnQvQWx0LWNsaWNrIHRvIHJlZmluZSAoZXhjbHVkZSkgdGhlIGN1cnJlbnQgb25lLjxicj5Fc2MgdW5kb2VzIGl0LlwiXG4gICAgW2VzY2FwZV09XCJmYWxzZVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAob25DbGljayk9XCJ0b2dnbGVEcmFnTW9kZS5lbWl0KCdzYW1Qb2ludCcpXCJcbiAgPlxuICAgIDxpbWdcbiAgICAgIHNyYz1cImFzc2V0cy9wbG90dGluZy9zYW0tcG9pbnQtcHJvbXB0LnN2Z1wiXG4gICAgICBbY2xhc3NdPVwiYWN0aXZlRHJhZ01vZGUgPT09ICdzYW1Qb2ludCcgPyAndG9vbGJhci1pY29uLWFjdGl2ZScgOiAndG9vbGJhci1pY29uLWRhcmsnXCJcbiAgICAgIHN0eWxlPVwid2lkdGg6IDFyZW1cIlxuICAgIC8+XG4gIDwvcC1idXR0b24+XG48L25nLXRlbXBsYXRlPlxuPHAtbWVudSAjc2FtTW9kZWxNZW51IHN0eWxlQ2xhc3M9XCJtb2RlbC1tZW51XCIgW21vZGVsXT1cInNhbU1lbnVJdGVtc1wiIFtwb3B1cF09XCJ0cnVlXCIgYXBwZW5kVG89XCJib2R5XCI+XG4gIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJpdGVtXCIgbGV0LWl0ZW0+XG4gICAgPG5nLWNvbnRhaW5lclxuICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwibW9kZWxNZW51SXRlbVwiXG4gICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGl0ZW0gfVwiXG4gICAgPjwvbmctY29udGFpbmVyPlxuICA8L25nLXRlbXBsYXRlPlxuPC9wLW1lbnU+XG5cbjwhLS0gU2hhcmVkIGl0ZW0gYm9keSBmb3IgYWxsIHRocmVlIG1vZGVsIHBpY2tlcnMgKFNBTSAvIFlPTE8gLyByZXRpbmFsKTpcbiAgICAgdGhlIHN0YW5kYXJkIGNoZWNrLW9yLWJsYW5rIGljb24gYW5kIGxhYmVsLCBwbHVzIGFuIGluZm8gaWNvbiBjYXJyeWluZ1xuICAgICB0aGUgbW9kZWwncyBkZXNjcmlwdGlvbiBhcyBhIGhvdmVyIHRvb2x0aXAuIFRoaXMgcmVwbGFjZWQgYSBzaW5nbGVcbiAgICAgXCJBYm91dCB0aGUgU0FNIG1vZGVsc1wiIG92ZXJsYXkgcGFuZWwg4oCUIHBlci1tb2RlbCB0ZXh0IHNpdHMgbmV4dCB0byB0aGVcbiAgICAgbW9kZWwgaXQgZGVzY3JpYmVzLCBhbmQgWU9MTy9yZXRpbmFsIGdldCB0aGUgc2FtZSBhZmZvcmRhbmNlLlxuXG4gICAgIHAtbWVudSBwdXRzIGl0cyBjbGljayBoYW5kbGVyIG9uIHRoZSB3cmFwcGluZyBgLnAtbWVudWl0ZW0tY29udGVudGAsXG4gICAgIG91dHNpZGUgdGhpcyB0ZW1wbGF0ZSwgc28gYGNvbW1hbmRgIHN0aWxsIGZpcmVzIGFuZCB0aGUgd2hvbGUgcm93IHN0YXlzXG4gICAgIGNsaWNrYWJsZSDigJQgd2hpY2ggaXMgYWxzbyB3aHkgdGhlIGluZm8gaWNvbiBoYXMgdG8gc3RvcCBwcm9wYWdhdGlvbiwgb3JcbiAgICAgcmVhZGluZyBhYm91dCBhIG1vZGVsIHdvdWxkIHN3aXRjaCB0byBpdC4gLS0+XG48bmctdGVtcGxhdGUgI21vZGVsTWVudUl0ZW0gbGV0LWl0ZW0+XG4gIDxhIGNsYXNzPVwicC1tZW51aXRlbS1saW5rIG1vZGVsLW1lbnUtaXRlbVwiPlxuICAgIDxzcGFuIGNsYXNzPVwicC1tZW51aXRlbS1pY29uXCIgW25nQ2xhc3NdPVwiaXRlbS5pY29uXCI+PC9zcGFuPlxuICAgIDxzcGFuIGNsYXNzPVwicC1tZW51aXRlbS10ZXh0XCI+e3sgaXRlbS5sYWJlbCB9fTwvc3Bhbj5cbiAgICA8IS0tIGBib3R0b21gIGxpa2UgZXZlcnkgb3RoZXIgdG9vbHRpcCBpbiB0aGlzIHRvb2xiYXIsIGFuZCBmb3Igcm9vbTpcbiAgICAgICAgIHRoZXNlIG1lbnVzIG9wZW4gdW5kZXIgYnV0dG9ucyB0aGF0IGNhbiBzaXQgbmVhciB0aGUgcmlnaHQgZWRnZSxcbiAgICAgICAgIHdoZXJlIGEgYHJpZ2h0YCB0b29sdGlwIGhhcyBhIGZldyBodW5kcmVkIHB4IGFuZCBzcXVlZXplcyBpdHMgdGV4dFxuICAgICAgICAgaW50byBhIG5hcnJvdyBjb2x1bW4gaW5zdGVhZCBvZiB1c2luZyBpdHMgbWF4LXdpZHRoLiAtLT5cbiAgICA8IS0tIEEgZm9jdXNhYmxlIDxidXR0b24+LCBub3QgYSBiYXJlIDxpPi4gQXMgYW4gPGk+IHRoZSBkZXNjcmlwdGlvblxuICAgICAgICAgd2FzIHJlYWNoYWJsZSBvbmx5IGJ5IGhvdmVyaW5nIGEgbW91c2U6IG5vdCB0YWJiYWJsZSwgbm9cbiAgICAgICAgIGFjY2Vzc2libGUgbmFtZSwgbm90aGluZyBmb3IgYSBzY3JlZW4gcmVhZGVyIHRvIGFubm91bmNlIOKAlCBzb1xuICAgICAgICAga2V5Ym9hcmQgYW5kIEFUIHVzZXJzIGNvdWxkIHBpY2sgYSBjaGVja3BvaW50IGJ1dCBuZXZlciByZWFkIHdoYXRcbiAgICAgICAgIGl0IHdhcy4gUHJpbWVORydzIHRvb2x0aXAgc2hvd3Mgb24gZm9jdXMgYXMgd2VsbCBhcyBob3Zlciwgc29cbiAgICAgICAgIG1ha2luZyBpdCBhIGJ1dHRvbiByZXN0b3JlcyBpdCBmb3IgZnJlZS5cblxuICAgICAgICAgYGFyaWEtZGVzY3JpYmVkYnlgIGlzIGRlbGliZXJhdGVseSBub3QgdXNlZDogdGhlIHRvb2x0aXAgaXNcbiAgICAgICAgIHJlbmRlcmVkIGludG8gYGJvZHlgIG9uIGRlbWFuZCBhbmQgaGFzIG5vIHN0YWJsZSBpZCB0byBwb2ludCBhdC5cbiAgICAgICAgIFRoZSBkZXNjcmlwdGlvbiBpcyBjYXJyaWVkIG9uIGBhcmlhLWxhYmVsYCBpbnN0ZWFkLCB3aGljaCBpc1xuICAgICAgICAgYW5ub3VuY2VkIHdoZXRoZXIgb3Igbm90IHRoZSB0b29sdGlwIGlzIHNob3dpbmcuIEl0IGlzIHN0cmlwcGVkIG9mXG4gICAgICAgICBtYXJrdXAgZmlyc3QsIHNpbmNlIHRoZSBjb3B5IGNvbnRhaW5zIGA8Yj5gL2A8YnI+YCBmb3IgdGhlIHZpc3VhbFxuICAgICAgICAgdG9vbHRpcCBhbmQgdGhvc2Ugd291bGQgb3RoZXJ3aXNlIGJlIHJlYWQgb3V0IGxpdGVyYWxseS4gLS0+XG4gICAgPGJ1dHRvblxuICAgICAgKm5nSWY9XCJpdGVtLnRvb2x0aXBcIlxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInBpIHBpLWluZm8tY2lyY2xlIG1vZGVsLWluZm8taWNvblwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIml0ZW0uaW5mb0xhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJpdGVtLnRvb2x0aXBcIlxuICAgICAgW2VzY2FwZV09XCJmYWxzZVwiXG4gICAgICB0b29sdGlwUG9zaXRpb249XCJib3R0b21cIlxuICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgIHRvb2x0aXBTdHlsZUNsYXNzPVwibW9kZWwtaW5mby10b29sdGlwXCJcbiAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKGtleWRvd24uZW50ZXIpPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgIChrZXlkb3duLnNwYWNlKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgPjwvYnV0dG9uPlxuICA8L2E+XG48L25nLXRlbXBsYXRlPlxuPHAtYnV0dG9uXG4gIHNpemU9XCJzbWFsbFwiXG4gIFt0ZXh0XT1cInRydWVcIlxuICBhcmlhTGFiZWw9XCJTZWdtZW50IGNlbGxzIChjZWxscG9zZS1TQU0pXCJcbiAgcFRvb2x0aXA9XCJBdXRvLXNlZ21lbnQgY2VsbHMgaW5zaWRlIGVhY2ggZHJhd24gcmVjdGFuZ2xlIChjZWxscG9zZS1TQU0pXCJcbiAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgKG9uQ2xpY2spPVwic2VnbWVudENlbGxwb3NlLmVtaXQoKVwiXG4+XG4gIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL2NlbGxzLnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbjwvcC1idXR0b24+XG5cbjwhLS0gQ29udHJpYnV0ZWQgbm8tcHJvbXB0IHRvb2xzIChUT09MQkFSX1RPT0xTKS4gVW5saWtlIHRoZSBTQU0gYW5kXG4gICAgIGNlbGxwb3NlIHRvb2xzIHRoZXNlIHRha2Ugbm8gcHJvbXB0IOKAlCB0aGV5IHN3ZWVwIHRoZSB3aG9sZSBjdXJyZW50XG4gICAgIHZpZXcgcmF0aGVyIHRoYW4gYmVpbmcgcG9pbnRlZCBhdCBzb21ldGhpbmcg4oCUIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG9cbiAgICAgZHJhdyBmaXJzdC4gRWFjaCByZW5kZXJzIHRoZSBzYW1lIHNwbGl0IGJ1dHRvbjogcnVuLCBwaWNrIGNoZWNrcG9pbnQsXG4gICAgIG9wZW4gcGFyYW1ldGVycy5cblxuICAgICBOb3RoaW5nIGhlcmUgbmFtZXMgYSBzcGVjaWZpYyB0b29sLiBUaGUgbGlicmFyeSBzaGlwcyBub25lOyBhIGhvc3RcbiAgICAgcmVnaXN0ZXJzIHRoZW0sIHdoaWNoIGlzIHdoYXQgbGV0cyB0aGlzIHBhY2thZ2UgYmUgcHVibGlzaGVkIHdpdGhvdXRcbiAgICAgdGhlIGNsb3NlZCBtb2RlbCBkZXBlbmRlbmNpZXMuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgdG9vbCBvZiBjb250cmlidXRlZFRvb2xzOyB0cmFja0J5OiB0cmFja1Rvb2xCeUlkXCI+XG4gIDxzcGFuIGNsYXNzPVwicC1idXR0b25zZXQgc2VnbWVudC1zcGxpdFwiPlxuICAgIDxwLWJ1dHRvblxuICAgICAgc2l6ZT1cInNtYWxsXCJcbiAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgW2FyaWFMYWJlbF09XCJ0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLnJ1blRvb2x0aXBcIlxuICAgICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAgIChvbkNsaWNrKT1cInJ1blRvb2wuZW1pdCh0b29sLmlkKVwiXG4gICAgPlxuICAgICAgPCEtLSBgdG9vbGJhci1pY29uLWRhcmtgIGlzIGhhcmRjb2RlZCByYXRoZXIgdGhhbiBib3VuZCwgdW5saWtlIHRoZVxuICAgICAgICAgICB0b2dnbGUgdG9vbHM6IHRoZXNlIGZpcmUgYSBydW4gYW5kIGhhdmUgbm8gYWN0aXZlIHN0YXRlLiAtLT5cbiAgICAgIDxpbWdcbiAgICAgICAgKm5nSWY9XCJ0b29sLmljb24uc3JjXCJcbiAgICAgICAgW3NyY109XCJ0b29sLmljb24uc3JjXCJcbiAgICAgICAgY2xhc3M9XCJ0b29sYmFyLWljb24tZGFya1wiXG4gICAgICAgIHN0eWxlPVwid2lkdGg6IDFyZW1cIlxuICAgICAgICBbYWx0XT1cInRvb2wubGFiZWxcIlxuICAgICAgLz5cbiAgICAgIDxpICpuZ0lmPVwidG9vbC5pY29uLnBpXCIgY2xhc3M9XCJwaSB7eyB0b29sLmljb24ucGkgfX1cIj48L2k+XG4gICAgPC9wLWJ1dHRvbj5cbiAgICA8cC1idXR0b25cbiAgICAgIGljb249XCJwaSBwaS1jaGV2cm9uLWRvd25cIlxuICAgICAgc2l6ZT1cInNtYWxsXCJcbiAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgW2FyaWFMYWJlbF09XCInUGljayB0aGUgbW9kZWwgZm9yICcgKyB0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLm1vZGVsVG9vbHRpcCB8fCAnUGljayB0aGUgbW9kZWwnXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJ0b29sTWVudS50b2dnbGUoJGV2ZW50KVwiXG4gICAgPlxuICAgIDwvcC1idXR0b24+XG4gICAgPHAtYnV0dG9uXG4gICAgICAqbmdJZj1cInRvb2wucGFyYW1zLmxlbmd0aFwiXG4gICAgICBpY29uPVwicGkgcGktc2xpZGVycy1oXCJcbiAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICBbdGV4dF09XCJ0cnVlXCJcbiAgICAgIFthcmlhTGFiZWxdPVwiJ1BhcmFtZXRlcnMgZm9yICcgKyB0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLnBhcmFtc1Rvb2x0aXAgfHwgJ1BhcmFtZXRlcnMnXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJvcGVuVG9vbFBhcmFtcy5lbWl0KHRvb2wuaWQpXCJcbiAgICA+XG4gICAgPC9wLWJ1dHRvbj5cbiAgPC9zcGFuPlxuICA8cC1tZW51ICN0b29sTWVudSBzdHlsZUNsYXNzPVwibW9kZWwtbWVudVwiIFttb2RlbF09XCJ0b29sTWVudUl0ZW1zW3Rvb2wuaWRdIHx8IFtdXCIgW3BvcHVwXT1cInRydWVcIiBhcHBlbmRUbz1cImJvZHlcIj5cbiAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaXRlbVwiIGxldC1pdGVtPlxuICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJtb2RlbE1lbnVJdGVtXCJcbiAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgJGltcGxpY2l0OiBpdGVtIH1cIlxuICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcC1tZW51PlxuPC9uZy1jb250YWluZXI+XG4iXX0=
@@ -0,0 +1,81 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { ButtonModule } from 'primeng/button';
5
+ import { InputNumberModule } from 'primeng/inputnumber';
6
+ import { SliderModule } from 'primeng/slider';
7
+ import { TooltipModule } from 'primeng/tooltip';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ import * as i2 from "@angular/forms";
11
+ import * as i3 from "primeng/button";
12
+ import * as i4 from "primeng/inputnumber";
13
+ import * as i5 from "primeng/slider";
14
+ import * as i6 from "primeng/tooltip";
15
+ /**
16
+ * The toolbar's z-stack group: a live slice scrubber for the views that swap
17
+ * slices in place, or (Plotly heatmap) the single-image / stack toggle with a
18
+ * slice-number field. Presentational: the host owns `zIndex`.
19
+ */
20
+ export class StackControlsComponent {
21
+ constructor() {
22
+ /** Show the live slice scrubber. */
23
+ this.liveScrubber = false;
24
+ /** Show the single-image / stack toggle (Plotly heatmap). */
25
+ this.stackToggle = false;
26
+ /** Stack mode is on (the toggle's state). */
27
+ this.showStack = false;
28
+ /** The two stack-mode choices of the toggle. */
29
+ this.stackOptions = [
30
+ { name: 'Single image', val: 'false' },
31
+ { name: 'Stack', val: 'true' },
32
+ ];
33
+ /** The current slice (0-based). */
34
+ this.zIndex = 0;
35
+ /** The last slice index. */
36
+ this.maxIndex = 0;
37
+ /** The live scrubber moved (fires while dragging). */
38
+ this.zScrub = new EventEmitter();
39
+ /** The live scrubber was released on a slice. */
40
+ this.zSlide = new EventEmitter();
41
+ /** A stack-mode choice was picked. */
42
+ this.selectStackOption = new EventEmitter();
43
+ /** A slice number was typed (blank reports the current slice). */
44
+ this.zIndexInput = new EventEmitter();
45
+ /** Enter in the slice field / the reload button: re-plot at the typed slice. */
46
+ this.reloadAndPlot = new EventEmitter();
47
+ }
48
+ /** The slice field reports what was typed (blank keeps the current slice). */
49
+ onSliceInput(value) {
50
+ this.zIndexInput.emit(value == null || value === '' ? this.zIndex : Number(value));
51
+ }
52
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: StackControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
53
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: StackControlsComponent, isStandalone: true, selector: "toolbar-stack-controls", inputs: { liveScrubber: "liveScrubber", stackToggle: "stackToggle", showStack: "showStack", stackOptions: "stackOptions", zIndex: "zIndex", maxIndex: "maxIndex" }, outputs: { zScrub: "zScrub", zSlide: "zSlide", selectStackOption: "selectStackOption", zIndexInput: "zIndexInput", reloadAndPlot: "reloadAndPlot" }, ngImport: i0, template: "<span class=\"toolbar-separator\"></span>\n<!-- Live views: scrub z-slices (the renderer swaps slices in place). -->\n<ng-container *ngIf=\"liveScrubber\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <p-slider\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n ariaLabel=\"Slice\"\n (onChange)=\"zScrub.emit($event.value)\"\n (onSlideEnd)=\"zSlide.emit($event.value)\"\n pTooltip=\"Slice through the stack (\u2190 / \u2192 keys)\"\n tooltipPosition=\"bottom\"\n [style]=\"{ width: '16rem' }\"\n styleClass=\"wand-sensitivity-slider\"\n ></p-slider>\n <span class=\"flex align-items-center mx-1 toolbar-text\">{{ zIndex }} of {{ maxIndex }}</span>\n</ng-container>\n<!-- Heatmap view: single-image (high-def zoom) vs stack (frame slider). Plotly-only \u2014\n hidden for napari, which has no single/stack toggle or per-frame fetch, and for the\n spatial-omics modes: a 3D omics dataset publishes its reference volume as a z-stack\n image, and these modes draw observations, not one of its slices. -->\n<ng-container *ngIf=\"stackToggle\">\n <p-button\n icon=\"pi pi-image\"\n size=\"small\"\n ariaLabel=\"Single image mode\"\n [text]=\"showStack\"\n pTooltip=\"Single image mode: enables high-def zoom\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[0])\"\n >\n </p-button>\n <p-button\n icon=\"pi pi-images\"\n size=\"small\"\n ariaLabel=\"Stack mode\"\n [text]=\"!showStack\"\n pTooltip=\"Stack mode, enables slicing through image frames\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[1])\"\n >\n </p-button>\n <ng-container *ngIf=\"!showStack\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <div class=\"p-inputgroup\" style=\"width: auto\">\n <p-inputNumber\n styleClass=\"w-3rem toolbar-input\"\n ariaLabel=\"Slice number\"\n pTooltip=\"View image in stack (&#x23CE;)\"\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n (onInput)=\"onSliceInput($event.value)\"\n (keydown.enter)=\"reloadAndPlot.emit()\"\n />\n <p-button\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Plot this slice\"\n (onClick)=\"reloadAndPlot.emit()\"\n pTooltip=\"Plot this slice\"\n tooltipPosition=\"bottom\"\n >\n </p-button>\n </div>\n <span class=\"flex align-items-center mx-1 toolbar-text\">of {{ maxIndex }}</span>\n </ng-container>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i4.InputNumber, selector: "p-inputNumber", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i5.Slider, selector: "p-slider", inputs: ["animate", "disabled", "min", "max", "orientation", "step", "range", "style", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
54
+ }
55
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: StackControlsComponent, decorators: [{
56
+ type: Component,
57
+ args: [{ selector: 'toolbar-stack-controls', standalone: true, imports: [CommonModule, FormsModule, ButtonModule, InputNumberModule, SliderModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"toolbar-separator\"></span>\n<!-- Live views: scrub z-slices (the renderer swaps slices in place). -->\n<ng-container *ngIf=\"liveScrubber\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <p-slider\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n ariaLabel=\"Slice\"\n (onChange)=\"zScrub.emit($event.value)\"\n (onSlideEnd)=\"zSlide.emit($event.value)\"\n pTooltip=\"Slice through the stack (\u2190 / \u2192 keys)\"\n tooltipPosition=\"bottom\"\n [style]=\"{ width: '16rem' }\"\n styleClass=\"wand-sensitivity-slider\"\n ></p-slider>\n <span class=\"flex align-items-center mx-1 toolbar-text\">{{ zIndex }} of {{ maxIndex }}</span>\n</ng-container>\n<!-- Heatmap view: single-image (high-def zoom) vs stack (frame slider). Plotly-only \u2014\n hidden for napari, which has no single/stack toggle or per-frame fetch, and for the\n spatial-omics modes: a 3D omics dataset publishes its reference volume as a z-stack\n image, and these modes draw observations, not one of its slices. -->\n<ng-container *ngIf=\"stackToggle\">\n <p-button\n icon=\"pi pi-image\"\n size=\"small\"\n ariaLabel=\"Single image mode\"\n [text]=\"showStack\"\n pTooltip=\"Single image mode: enables high-def zoom\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[0])\"\n >\n </p-button>\n <p-button\n icon=\"pi pi-images\"\n size=\"small\"\n ariaLabel=\"Stack mode\"\n [text]=\"!showStack\"\n pTooltip=\"Stack mode, enables slicing through image frames\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[1])\"\n >\n </p-button>\n <ng-container *ngIf=\"!showStack\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <div class=\"p-inputgroup\" style=\"width: auto\">\n <p-inputNumber\n styleClass=\"w-3rem toolbar-input\"\n ariaLabel=\"Slice number\"\n pTooltip=\"View image in stack (&#x23CE;)\"\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n (onInput)=\"onSliceInput($event.value)\"\n (keydown.enter)=\"reloadAndPlot.emit()\"\n />\n <p-button\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Plot this slice\"\n (onClick)=\"reloadAndPlot.emit()\"\n pTooltip=\"Plot this slice\"\n tooltipPosition=\"bottom\"\n >\n </p-button>\n </div>\n <span class=\"flex align-items-center mx-1 toolbar-text\">of {{ maxIndex }}</span>\n </ng-container>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"] }]
58
+ }], propDecorators: { liveScrubber: [{
59
+ type: Input
60
+ }], stackToggle: [{
61
+ type: Input
62
+ }], showStack: [{
63
+ type: Input
64
+ }], stackOptions: [{
65
+ type: Input
66
+ }], zIndex: [{
67
+ type: Input
68
+ }], maxIndex: [{
69
+ type: Input
70
+ }], zScrub: [{
71
+ type: Output
72
+ }], zSlide: [{
73
+ type: Output
74
+ }], selectStackOption: [{
75
+ type: Output
76
+ }], zIndexInput: [{
77
+ type: Output
78
+ }], reloadAndPlot: [{
79
+ type: Output
80
+ }] } });
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2stY29udHJvbHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90b29sYmFyL3N0YWNrLWNvbnRyb2xzL3N0YWNrLWNvbnRyb2xzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zdGFjay1jb250cm9scy9zdGFjay1jb250cm9scy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7O0FBUWhEOzs7O0dBSUc7QUFTSCxNQUFNLE9BQU8sc0JBQXNCO0lBUm5DO1FBU0Usb0NBQW9DO1FBQzNCLGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBQzlCLDZEQUE2RDtRQUNwRCxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUM3Qiw2Q0FBNkM7UUFDcEMsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUMzQixnREFBZ0Q7UUFDdkMsaUJBQVksR0FBa0I7WUFDckMsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUU7WUFDdEMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUU7U0FDL0IsQ0FBQztRQUNGLG1DQUFtQztRQUMxQixXQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ3BCLDRCQUE0QjtRQUNuQixhQUFRLEdBQUcsQ0FBQyxDQUFDO1FBRXRCLHNEQUFzRDtRQUM1QyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQXNCLENBQUM7UUFDMUQsaURBQWlEO1FBQ3ZDLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBc0IsQ0FBQztRQUMxRCxzQ0FBc0M7UUFDNUIsc0JBQWlCLEdBQUcsSUFBSSxZQUFZLEVBQWUsQ0FBQztRQUM5RCxrRUFBa0U7UUFDeEQsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBQ25ELGdGQUFnRjtRQUN0RSxrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7S0FNcEQ7SUFKQyw4RUFBOEU7SUFDcEUsWUFBWSxDQUFDLEtBQTZCO1FBQ2xELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDckYsQ0FBQzs4R0EvQlUsc0JBQXNCO2tHQUF0QixzQkFBc0IsMllDM0JuQyx5bEZBc0VBLHdlRGhEWSxZQUFZLGtJQUFFLFdBQVcsOFZBQUUsWUFBWSw2WEFBRSxpQkFBaUIseXZCQUFFLFlBQVksK1JBQUUsYUFBYTs7MkZBS3RGLHNCQUFzQjtrQkFSbEMsU0FBUzsrQkFDRSx3QkFBd0IsY0FDdEIsSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLGFBQWEsQ0FBQyxtQkFHakYsdUJBQXVCLENBQUMsTUFBTTs4QkFJdEMsWUFBWTtzQkFBcEIsS0FBSztnQkFFRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsWUFBWTtzQkFBcEIsS0FBSztnQkFLRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFHSSxNQUFNO3NCQUFmLE1BQU07Z0JBRUcsTUFBTTtzQkFBZixNQUFNO2dCQUVHLGlCQUFpQjtzQkFBMUIsTUFBTTtnQkFFRyxXQUFXO3NCQUFwQixNQUFNO2dCQUVHLGFBQWE7c0JBQXRCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYnV0dG9uJztcbmltcG9ydCB7IElucHV0TnVtYmVyTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dG51bWJlcic7XG5pbXBvcnQgeyBTbGlkZXJNb2R1bGUgfSBmcm9tICdwcmltZW5nL3NsaWRlcic7XG5pbXBvcnQgeyBUb29sdGlwTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90b29sdGlwJztcblxuLyoqIEEgc3RhY2stbW9kZSBjaG9pY2UgKGB2YWxgICdmYWxzZScgPSBzaW5nbGUgaW1hZ2UsICd0cnVlJyA9IHN0YWNrKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhY2tPcHRpb24ge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZhbDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSB0b29sYmFyJ3Mgei1zdGFjayBncm91cDogYSBsaXZlIHNsaWNlIHNjcnViYmVyIGZvciB0aGUgdmlld3MgdGhhdCBzd2FwXG4gKiBzbGljZXMgaW4gcGxhY2UsIG9yIChQbG90bHkgaGVhdG1hcCkgdGhlIHNpbmdsZS1pbWFnZSAvIHN0YWNrIHRvZ2dsZSB3aXRoIGFcbiAqIHNsaWNlLW51bWJlciBmaWVsZC4gUHJlc2VudGF0aW9uYWw6IHRoZSBob3N0IG93bnMgYHpJbmRleGAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3Rvb2xiYXItc3RhY2stY29udHJvbHMnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBGb3Jtc01vZHVsZSwgQnV0dG9uTW9kdWxlLCBJbnB1dE51bWJlck1vZHVsZSwgU2xpZGVyTW9kdWxlLCBUb29sdGlwTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3N0YWNrLWNvbnRyb2xzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3RhY2stY29udHJvbHMuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFN0YWNrQ29udHJvbHNDb21wb25lbnQge1xuICAvKiogU2hvdyB0aGUgbGl2ZSBzbGljZSBzY3J1YmJlci4gKi9cbiAgQElucHV0KCkgbGl2ZVNjcnViYmVyID0gZmFsc2U7XG4gIC8qKiBTaG93IHRoZSBzaW5nbGUtaW1hZ2UgLyBzdGFjayB0b2dnbGUgKFBsb3RseSBoZWF0bWFwKS4gKi9cbiAgQElucHV0KCkgc3RhY2tUb2dnbGUgPSBmYWxzZTtcbiAgLyoqIFN0YWNrIG1vZGUgaXMgb24gKHRoZSB0b2dnbGUncyBzdGF0ZSkuICovXG4gIEBJbnB1dCgpIHNob3dTdGFjayA9IGZhbHNlO1xuICAvKiogVGhlIHR3byBzdGFjay1tb2RlIGNob2ljZXMgb2YgdGhlIHRvZ2dsZS4gKi9cbiAgQElucHV0KCkgc3RhY2tPcHRpb25zOiBTdGFja09wdGlvbltdID0gW1xuICAgIHsgbmFtZTogJ1NpbmdsZSBpbWFnZScsIHZhbDogJ2ZhbHNlJyB9LFxuICAgIHsgbmFtZTogJ1N0YWNrJywgdmFsOiAndHJ1ZScgfSxcbiAgXTtcbiAgLyoqIFRoZSBjdXJyZW50IHNsaWNlICgwLWJhc2VkKS4gKi9cbiAgQElucHV0KCkgekluZGV4ID0gMDtcbiAgLyoqIFRoZSBsYXN0IHNsaWNlIGluZGV4LiAqL1xuICBASW5wdXQoKSBtYXhJbmRleCA9IDA7XG5cbiAgLyoqIFRoZSBsaXZlIHNjcnViYmVyIG1vdmVkIChmaXJlcyB3aGlsZSBkcmFnZ2luZykuICovXG4gIEBPdXRwdXQoKSB6U2NydWIgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlciB8IHVuZGVmaW5lZD4oKTtcbiAgLyoqIFRoZSBsaXZlIHNjcnViYmVyIHdhcyByZWxlYXNlZCBvbiBhIHNsaWNlLiAqL1xuICBAT3V0cHV0KCkgelNsaWRlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXIgfCB1bmRlZmluZWQ+KCk7XG4gIC8qKiBBIHN0YWNrLW1vZGUgY2hvaWNlIHdhcyBwaWNrZWQuICovXG4gIEBPdXRwdXQoKSBzZWxlY3RTdGFja09wdGlvbiA9IG5ldyBFdmVudEVtaXR0ZXI8U3RhY2tPcHRpb24+KCk7XG4gIC8qKiBBIHNsaWNlIG51bWJlciB3YXMgdHlwZWQgKGJsYW5rIHJlcG9ydHMgdGhlIGN1cnJlbnQgc2xpY2UpLiAqL1xuICBAT3V0cHV0KCkgekluZGV4SW5wdXQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcbiAgLyoqIEVudGVyIGluIHRoZSBzbGljZSBmaWVsZCAvIHRoZSByZWxvYWQgYnV0dG9uOiByZS1wbG90IGF0IHRoZSB0eXBlZCBzbGljZS4gKi9cbiAgQE91dHB1dCgpIHJlbG9hZEFuZFBsb3QgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgLyoqIFRoZSBzbGljZSBmaWVsZCByZXBvcnRzIHdoYXQgd2FzIHR5cGVkIChibGFuayBrZWVwcyB0aGUgY3VycmVudCBzbGljZSkuICovXG4gIHByb3RlY3RlZCBvblNsaWNlSW5wdXQodmFsdWU6IHN0cmluZyB8IG51bWJlciB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnpJbmRleElucHV0LmVtaXQodmFsdWUgPT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycgPyB0aGlzLnpJbmRleCA6IE51bWJlcih2YWx1ZSkpO1xuICB9XG59XG4iLCI8c3BhbiBjbGFzcz1cInRvb2xiYXItc2VwYXJhdG9yXCI+PC9zcGFuPlxuPCEtLSBMaXZlIHZpZXdzOiBzY3J1YiB6LXNsaWNlcyAodGhlIHJlbmRlcmVyIHN3YXBzIHNsaWNlcyBpbiBwbGFjZSkuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpdmVTY3J1YmJlclwiPlxuICA8c3BhbiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIG14LTEgdG9vbGJhci10ZXh0XCI+U2xpY2U8L3NwYW4+XG4gIDxwLXNsaWRlclxuICAgIFtuZ01vZGVsXT1cInpJbmRleFwiXG4gICAgW21pbl09XCIwXCJcbiAgICBbbWF4XT1cIm1heEluZGV4XCJcbiAgICBhcmlhTGFiZWw9XCJTbGljZVwiXG4gICAgKG9uQ2hhbmdlKT1cInpTY3J1Yi5lbWl0KCRldmVudC52YWx1ZSlcIlxuICAgIChvblNsaWRlRW5kKT1cInpTbGlkZS5lbWl0KCRldmVudC52YWx1ZSlcIlxuICAgIHBUb29sdGlwPVwiU2xpY2UgdGhyb3VnaCB0aGUgc3RhY2sgKOKGkCAvIOKGkiBrZXlzKVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICBbc3R5bGVdPVwieyB3aWR0aDogJzE2cmVtJyB9XCJcbiAgICBzdHlsZUNsYXNzPVwid2FuZC1zZW5zaXRpdml0eS1zbGlkZXJcIlxuICA+PC9wLXNsaWRlcj5cbiAgPHNwYW4gY2xhc3M9XCJmbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBteC0xIHRvb2xiYXItdGV4dFwiPnt7IHpJbmRleCB9fSBvZiB7eyBtYXhJbmRleCB9fTwvc3Bhbj5cbjwvbmctY29udGFpbmVyPlxuPCEtLSBIZWF0bWFwIHZpZXc6IHNpbmdsZS1pbWFnZSAoaGlnaC1kZWYgem9vbSkgdnMgc3RhY2sgKGZyYW1lIHNsaWRlcikuIFBsb3RseS1vbmx5IOKAlFxuICAgICBoaWRkZW4gZm9yIG5hcGFyaSwgd2hpY2ggaGFzIG5vIHNpbmdsZS9zdGFjayB0b2dnbGUgb3IgcGVyLWZyYW1lIGZldGNoLCBhbmQgZm9yIHRoZVxuICAgICBzcGF0aWFsLW9taWNzIG1vZGVzOiBhIDNEIG9taWNzIGRhdGFzZXQgcHVibGlzaGVzIGl0cyByZWZlcmVuY2Ugdm9sdW1lIGFzIGEgei1zdGFja1xuICAgICBpbWFnZSwgYW5kIHRoZXNlIG1vZGVzIGRyYXcgb2JzZXJ2YXRpb25zLCBub3Qgb25lIG9mIGl0cyBzbGljZXMuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdJZj1cInN0YWNrVG9nZ2xlXCI+XG4gIDxwLWJ1dHRvblxuICAgIGljb249XCJwaSBwaS1pbWFnZVwiXG4gICAgc2l6ZT1cInNtYWxsXCJcbiAgICBhcmlhTGFiZWw9XCJTaW5nbGUgaW1hZ2UgbW9kZVwiXG4gICAgW3RleHRdPVwic2hvd1N0YWNrXCJcbiAgICBwVG9vbHRpcD1cIlNpbmdsZSBpbWFnZSBtb2RlOiBlbmFibGVzIGhpZ2gtZGVmIHpvb21cIlxuICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgKG9uQ2xpY2spPVwic2VsZWN0U3RhY2tPcHRpb24uZW1pdChzdGFja09wdGlvbnNbMF0pXCJcbiAgPlxuICA8L3AtYnV0dG9uPlxuICA8cC1idXR0b25cbiAgICBpY29uPVwicGkgcGktaW1hZ2VzXCJcbiAgICBzaXplPVwic21hbGxcIlxuICAgIGFyaWFMYWJlbD1cIlN0YWNrIG1vZGVcIlxuICAgIFt0ZXh0XT1cIiFzaG93U3RhY2tcIlxuICAgIHBUb29sdGlwPVwiU3RhY2sgbW9kZSwgZW5hYmxlcyBzbGljaW5nIHRocm91Z2ggaW1hZ2UgZnJhbWVzXCJcbiAgICB0b29sdGlwUG9zaXRpb249XCJib3R0b21cIlxuICAgIChvbkNsaWNrKT1cInNlbGVjdFN0YWNrT3B0aW9uLmVtaXQoc3RhY2tPcHRpb25zWzFdKVwiXG4gID5cbiAgPC9wLWJ1dHRvbj5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzaG93U3RhY2tcIj5cbiAgICA8c3BhbiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIG14LTEgdG9vbGJhci10ZXh0XCI+U2xpY2U8L3NwYW4+XG4gICAgPGRpdiBjbGFzcz1cInAtaW5wdXRncm91cFwiIHN0eWxlPVwid2lkdGg6IGF1dG9cIj5cbiAgICAgIDxwLWlucHV0TnVtYmVyXG4gICAgICAgIHN0eWxlQ2xhc3M9XCJ3LTNyZW0gdG9vbGJhci1pbnB1dFwiXG4gICAgICAgIGFyaWFMYWJlbD1cIlNsaWNlIG51bWJlclwiXG4gICAgICAgIHBUb29sdGlwPVwiVmlldyBpbWFnZSBpbiBzdGFjayAoJiN4MjNDRTspXCJcbiAgICAgICAgW25nTW9kZWxdPVwiekluZGV4XCJcbiAgICAgICAgW21pbl09XCIwXCJcbiAgICAgICAgW21heF09XCJtYXhJbmRleFwiXG4gICAgICAgIChvbklucHV0KT1cIm9uU2xpY2VJbnB1dCgkZXZlbnQudmFsdWUpXCJcbiAgICAgICAgKGtleWRvd24uZW50ZXIpPVwicmVsb2FkQW5kUGxvdC5lbWl0KClcIlxuICAgICAgLz5cbiAgICAgIDxwLWJ1dHRvblxuICAgICAgICBpY29uPVwicGkgcGktcmVmcmVzaFwiXG4gICAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgICBhcmlhTGFiZWw9XCJQbG90IHRoaXMgc2xpY2VcIlxuICAgICAgICAob25DbGljayk9XCJyZWxvYWRBbmRQbG90LmVtaXQoKVwiXG4gICAgICAgIHBUb29sdGlwPVwiUGxvdCB0aGlzIHNsaWNlXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAgID5cbiAgICAgIDwvcC1idXR0b24+XG4gICAgPC9kaXY+XG4gICAgPHNwYW4gY2xhc3M9XCJmbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBteC0xIHRvb2xiYXItdGV4dFwiPm9mIHt7IG1heEluZGV4IH19PC9zcGFuPlxuICA8L25nLWNvbnRhaW5lcj5cbjwvbmctY29udGFpbmVyPlxuIl19
@@ -0,0 +1,37 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ /**
3
+ * Status, busy flag and progress of a long-running (download / inference) tool,
4
+ * plus the re-entrancy guard that goes with them.
5
+ */
6
+ export class AsyncToolStatus {
7
+ constructor() {
8
+ /** Status text for a toast / spinner label. */
9
+ this.status$ = new BehaviorSubject('');
10
+ /** True from the start of a run until it settles. */
11
+ this.busy$ = new BehaviorSubject(false);
12
+ /** Download progress: -1 = not downloading, 0..1 = downloading. */
13
+ this.progress$ = new BehaviorSubject(-1);
14
+ }
15
+ get busy() {
16
+ return this.busy$.value;
17
+ }
18
+ /**
19
+ * Run `job` unless a run is already in flight (then resolve `undefined` at
20
+ * once). Busy is set *before* the first await — a model download is exactly
21
+ * the window a second press must not start another run in — and busy and
22
+ * progress are reset however the job ends.
23
+ */
24
+ async run(job) {
25
+ if (this.busy$.value)
26
+ return undefined;
27
+ this.busy$.next(true);
28
+ try {
29
+ return await job();
30
+ }
31
+ finally {
32
+ this.busy$.next(false);
33
+ this.progress$.next(-1);
34
+ }
35
+ }
36
+ }
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmMtdG9vbC1zdGF0dXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvdG9vbC1raXQvYXN5bmMtdG9vbC1zdGF0dXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUV2Qzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUE1QjtRQUNFLCtDQUErQztRQUN0QyxZQUFPLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUM7UUFDbkQscURBQXFEO1FBQzVDLFVBQUssR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUNyRCxtRUFBbUU7UUFDMUQsY0FBUyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFzQnZELENBQUM7SUFwQkMsSUFBSSxJQUFJO1FBQ04sT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUMxQixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFJLEdBQXFCO1FBQ2hDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDdkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdEIsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIFN0YXR1cywgYnVzeSBmbGFnIGFuZCBwcm9ncmVzcyBvZiBhIGxvbmctcnVubmluZyAoZG93bmxvYWQgLyBpbmZlcmVuY2UpIHRvb2wsXG4gKiBwbHVzIHRoZSByZS1lbnRyYW5jeSBndWFyZCB0aGF0IGdvZXMgd2l0aCB0aGVtLlxuICovXG5leHBvcnQgY2xhc3MgQXN5bmNUb29sU3RhdHVzIHtcbiAgLyoqIFN0YXR1cyB0ZXh0IGZvciBhIHRvYXN0IC8gc3Bpbm5lciBsYWJlbC4gKi9cbiAgcmVhZG9ubHkgc3RhdHVzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIC8qKiBUcnVlIGZyb20gdGhlIHN0YXJ0IG9mIGEgcnVuIHVudGlsIGl0IHNldHRsZXMuICovXG4gIHJlYWRvbmx5IGJ1c3kkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIC8qKiBEb3dubG9hZCBwcm9ncmVzczogLTEgPSBub3QgZG93bmxvYWRpbmcsIDAuLjEgPSBkb3dubG9hZGluZy4gKi9cbiAgcmVhZG9ubHkgcHJvZ3Jlc3MkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KC0xKTtcblxuICBnZXQgYnVzeSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5idXN5JC52YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gYGpvYmAgdW5sZXNzIGEgcnVuIGlzIGFscmVhZHkgaW4gZmxpZ2h0ICh0aGVuIHJlc29sdmUgYHVuZGVmaW5lZGAgYXRcbiAgICogb25jZSkuIEJ1c3kgaXMgc2V0ICpiZWZvcmUqIHRoZSBmaXJzdCBhd2FpdCDigJQgYSBtb2RlbCBkb3dubG9hZCBpcyBleGFjdGx5XG4gICAqIHRoZSB3aW5kb3cgYSBzZWNvbmQgcHJlc3MgbXVzdCBub3Qgc3RhcnQgYW5vdGhlciBydW4gaW4g4oCUIGFuZCBidXN5IGFuZFxuICAgKiBwcm9ncmVzcyBhcmUgcmVzZXQgaG93ZXZlciB0aGUgam9iIGVuZHMuXG4gICAqL1xuICBhc3luYyBydW48VD4oam9iOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUIHwgdW5kZWZpbmVkPiB7XG4gICAgaWYgKHRoaXMuYnVzeSQudmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgdGhpcy5idXN5JC5uZXh0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgam9iKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuYnVzeSQubmV4dChmYWxzZSk7XG4gICAgICB0aGlzLnByb2dyZXNzJC5uZXh0KC0xKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,63 @@
1
+ /**
2
+ * One backend's canvas tools. Each backend (Plotly, OpenSeadragon, napari-js)
3
+ * creates its own manager with its own {@link CanvasToolHost} and its own tool
4
+ * instances, so arming a tool never re-binds a tool another backend is using,
5
+ * and a backend switch never carries a stroke or SAM points across (RT-21).
6
+ * At most one tool is armed at a time.
7
+ */
8
+ export class CanvasToolManager {
9
+ constructor(host, tools) {
10
+ this.host = host;
11
+ this.tools = new Map();
12
+ this.active = null;
13
+ for (const tool of tools)
14
+ this.tools.set(tool.id, tool);
15
+ }
16
+ /** The armed tool's id, or null. */
17
+ get activeId() {
18
+ return this.active?.id ?? null;
19
+ }
20
+ /** Whether this manager has a tool for `id`. */
21
+ has(id) {
22
+ return id != null && this.tools.has(id);
23
+ }
24
+ /** The tool with this id, typed by the caller. */
25
+ get(id) {
26
+ return this.tools.get(id);
27
+ }
28
+ /**
29
+ * Arm `id` with `options`, disarming the armed tool first. null — or an id
30
+ * this manager has no tool for, such as a region draw mode — disarms only.
31
+ * Arming the armed tool again forwards `options` and keeps its work in progress.
32
+ */
33
+ activate(id, options) {
34
+ const next = this.has(id) ? this.tools.get(id) : null;
35
+ if (this.active && this.active !== next)
36
+ this.deactivate();
37
+ if (!next)
38
+ return;
39
+ this.active = next;
40
+ next.activate(this.host, options);
41
+ }
42
+ /** Disarm the armed tool, if any. */
43
+ deactivate() {
44
+ const tool = this.active;
45
+ this.active = null;
46
+ tool?.deactivate();
47
+ }
48
+ /** Forward live options to a tool, armed or not. */
49
+ setOptions(id, options) {
50
+ this.tools.get(id)?.setOptions?.(options);
51
+ }
52
+ /** Drop one tool's work in progress (it stays armed). */
53
+ reset(id) {
54
+ this.tools.get(id)?.reset?.();
55
+ }
56
+ /** Drop every tool's work in progress — after undo/redo or an image switch,
57
+ * where a stroke or prompt no longer matches the regions on screen. */
58
+ resetAll() {
59
+ for (const tool of this.tools.values())
60
+ tool.reset?.();
61
+ }
62
+ }
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudmFzLXRvb2wtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci90b29sLWtpdC9jYW52YXMtdG9vbC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7R0FNRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFJNUIsWUFDbUIsSUFBb0IsRUFDckMsS0FBd0M7UUFEdkIsU0FBSSxHQUFKLElBQUksQ0FBZ0I7UUFKdEIsVUFBSyxHQUFHLElBQUksR0FBRyxFQUFzQyxDQUFDO1FBQy9ELFdBQU0sR0FBZ0MsSUFBSSxDQUFDO1FBTWpELEtBQUssTUFBTSxJQUFJLElBQUksS0FBSztZQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBNEIsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxvQ0FBb0M7SUFDcEMsSUFBSSxRQUFRO1FBQ1YsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsSUFBSSxJQUFJLENBQUM7SUFDakMsQ0FBQztJQUVELGdEQUFnRDtJQUNoRCxHQUFHLENBQUMsRUFBNkI7UUFDL0IsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQWtCLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRUQsa0RBQWtEO0lBQ2xELEdBQUcsQ0FBK0IsRUFBZ0I7UUFDaEQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQWtCLENBQUM7SUFDN0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxRQUFRLENBQUMsRUFBaUIsRUFBRSxPQUFpQjtRQUMzQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3ZELElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLElBQUk7WUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDM0QsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ2xCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQscUNBQXFDO0lBQ3JDLFVBQVU7UUFDUixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQsb0RBQW9EO0lBQ3BELFVBQVUsQ0FBQyxFQUFnQixFQUFFLE9BQWdCO1FBQzNDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRCx5REFBeUQ7SUFDekQsS0FBSyxDQUFDLEVBQWdCO1FBQ3BCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVEOzRFQUN3RTtJQUN4RSxRQUFRO1FBQ04sS0FBSyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRTtZQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQ3pELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgQ2FudmFzVG9vbElkIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgQ2FudmFzVG9vbEhvc3QsIElDYW52YXNUb29sIH0gZnJvbSAnLi9jYW52YXMtdG9vbCc7XG5cbi8qKlxuICogT25lIGJhY2tlbmQncyBjYW52YXMgdG9vbHMuIEVhY2ggYmFja2VuZCAoUGxvdGx5LCBPcGVuU2VhZHJhZ29uLCBuYXBhcmktanMpXG4gKiBjcmVhdGVzIGl0cyBvd24gbWFuYWdlciB3aXRoIGl0cyBvd24ge0BsaW5rIENhbnZhc1Rvb2xIb3N0fSBhbmQgaXRzIG93biB0b29sXG4gKiBpbnN0YW5jZXMsIHNvIGFybWluZyBhIHRvb2wgbmV2ZXIgcmUtYmluZHMgYSB0b29sIGFub3RoZXIgYmFja2VuZCBpcyB1c2luZyxcbiAqIGFuZCBhIGJhY2tlbmQgc3dpdGNoIG5ldmVyIGNhcnJpZXMgYSBzdHJva2Ugb3IgU0FNIHBvaW50cyBhY3Jvc3MgKFJULTIxKS5cbiAqIEF0IG1vc3Qgb25lIHRvb2wgaXMgYXJtZWQgYXQgYSB0aW1lLlxuICovXG5leHBvcnQgY2xhc3MgQ2FudmFzVG9vbE1hbmFnZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHRvb2xzID0gbmV3IE1hcDxDYW52YXNUb29sSWQsIElDYW52YXNUb29sPHVua25vd24+PigpO1xuICBwcml2YXRlIGFjdGl2ZTogSUNhbnZhc1Rvb2w8dW5rbm93bj4gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IENhbnZhc1Rvb2xIb3N0LFxuICAgIHRvb2xzOiBSZWFkb25seUFycmF5PElDYW52YXNUb29sPG5ldmVyPj4sXG4gICkge1xuICAgIGZvciAoY29uc3QgdG9vbCBvZiB0b29scykgdGhpcy50b29scy5zZXQodG9vbC5pZCwgdG9vbCBhcyBJQ2FudmFzVG9vbDx1bmtub3duPik7XG4gIH1cblxuICAvKiogVGhlIGFybWVkIHRvb2wncyBpZCwgb3IgbnVsbC4gKi9cbiAgZ2V0IGFjdGl2ZUlkKCk6IENhbnZhc1Rvb2xJZCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZT8uaWQgPz8gbnVsbDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoaXMgbWFuYWdlciBoYXMgYSB0b29sIGZvciBgaWRgLiAqL1xuICBoYXMoaWQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBpZCBpcyBDYW52YXNUb29sSWQge1xuICAgIHJldHVybiBpZCAhPSBudWxsICYmIHRoaXMudG9vbHMuaGFzKGlkIGFzIENhbnZhc1Rvb2xJZCk7XG4gIH1cblxuICAvKiogVGhlIHRvb2wgd2l0aCB0aGlzIGlkLCB0eXBlZCBieSB0aGUgY2FsbGVyLiAqL1xuICBnZXQ8VCBleHRlbmRzIElDYW52YXNUb29sPG5ldmVyPj4oaWQ6IENhbnZhc1Rvb2xJZCk6IFQgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnRvb2xzLmdldChpZCkgYXMgVCB8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcm0gYGlkYCB3aXRoIGBvcHRpb25zYCwgZGlzYXJtaW5nIHRoZSBhcm1lZCB0b29sIGZpcnN0LiBudWxsIOKAlCBvciBhbiBpZFxuICAgKiB0aGlzIG1hbmFnZXIgaGFzIG5vIHRvb2wgZm9yLCBzdWNoIGFzIGEgcmVnaW9uIGRyYXcgbW9kZSDigJQgZGlzYXJtcyBvbmx5LlxuICAgKiBBcm1pbmcgdGhlIGFybWVkIHRvb2wgYWdhaW4gZm9yd2FyZHMgYG9wdGlvbnNgIGFuZCBrZWVwcyBpdHMgd29yayBpbiBwcm9ncmVzcy5cbiAgICovXG4gIGFjdGl2YXRlKGlkOiBzdHJpbmcgfCBudWxsLCBvcHRpb25zPzogdW5rbm93bik6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB0aGlzLmhhcyhpZCkgPyB0aGlzLnRvb2xzLmdldChpZCkhIDogbnVsbDtcbiAgICBpZiAodGhpcy5hY3RpdmUgJiYgdGhpcy5hY3RpdmUgIT09IG5leHQpIHRoaXMuZGVhY3RpdmF0ZSgpO1xuICAgIGlmICghbmV4dCkgcmV0dXJuO1xuICAgIHRoaXMuYWN0aXZlID0gbmV4dDtcbiAgICBuZXh0LmFjdGl2YXRlKHRoaXMuaG9zdCwgb3B0aW9ucyk7XG4gIH1cblxuICAvKiogRGlzYXJtIHRoZSBhcm1lZCB0b29sLCBpZiBhbnkuICovXG4gIGRlYWN0aXZhdGUoKTogdm9pZCB7XG4gICAgY29uc3QgdG9vbCA9IHRoaXMuYWN0aXZlO1xuICAgIHRoaXMuYWN0aXZlID0gbnVsbDtcbiAgICB0b29sPy5kZWFjdGl2YXRlKCk7XG4gIH1cblxuICAvKiogRm9yd2FyZCBsaXZlIG9wdGlvbnMgdG8gYSB0b29sLCBhcm1lZCBvciBub3QuICovXG4gIHNldE9wdGlvbnMoaWQ6IENhbnZhc1Rvb2xJZCwgb3B0aW9uczogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMudG9vbHMuZ2V0KGlkKT8uc2V0T3B0aW9ucz8uKG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqIERyb3Agb25lIHRvb2wncyB3b3JrIGluIHByb2dyZXNzIChpdCBzdGF5cyBhcm1lZCkuICovXG4gIHJlc2V0KGlkOiBDYW52YXNUb29sSWQpOiB2b2lkIHtcbiAgICB0aGlzLnRvb2xzLmdldChpZCk/LnJlc2V0Py4oKTtcbiAgfVxuXG4gIC8qKiBEcm9wIGV2ZXJ5IHRvb2wncyB3b3JrIGluIHByb2dyZXNzIOKAlCBhZnRlciB1bmRvL3JlZG8gb3IgYW4gaW1hZ2Ugc3dpdGNoLFxuICAgKiAgd2hlcmUgYSBzdHJva2Ugb3IgcHJvbXB0IG5vIGxvbmdlciBtYXRjaGVzIHRoZSByZWdpb25zIG9uIHNjcmVlbi4gKi9cbiAgcmVzZXRBbGwoKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCB0b29sIG9mIHRoaXMudG9vbHMudmFsdWVzKCkpIHRvb2wucmVzZXQ/LigpO1xuICB9XG59XG4iXX0=