@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,68 @@
1
+ import { MultiPolygon, Polygon, Rectangle } from '../models/region';
2
+ /**
3
+ * Choose the physical pixel size for area display from the image meta. The
4
+ * calibration may sit on any channel entry, not necessarily [0], so take the
5
+ * first entry with a positive mppX (as PlotlyService.currentMpp does). With
6
+ * only one axis reported, pixels are square (mppY = mppX), so a scaled image
7
+ * shows µm²/mm² rather than px².
8
+ */
9
+ export function pickMpp(meta) {
10
+ const m = Array.isArray(meta) ? (meta.find((e) => e && (e.mppX ?? 0) > 0) ?? meta[0]) : undefined;
11
+ const mx = m && (m.mppX ?? 0) > 0 ? m.mppX : undefined;
12
+ const my = m && (m.mppY ?? 0) > 0 ? m.mppY : undefined;
13
+ return { mppX: mx, mppY: my ?? mx };
14
+ }
15
+ /**
16
+ * A region's area in px²: width·height for a rectangle, shoelace for a polygon
17
+ * with each interior ring (hole) subtracted (a donut reports the annulus), and
18
+ * the sum of the parts for a multi-polygon (jit-ui#85). 0 for anything else.
19
+ */
20
+ export function regionAreaPx(region) {
21
+ const b = region.bounds;
22
+ if (b instanceof Rectangle)
23
+ return Math.abs(b.width * b.height);
24
+ if (b instanceof Polygon)
25
+ return polygonArea(b);
26
+ if (b instanceof MultiPolygon)
27
+ return b.polygons.reduce((sum, p) => sum + polygonArea(p), 0);
28
+ return 0;
29
+ }
30
+ /**
31
+ * An area for display: µm² (mm² from 1e6 µm²) when the pixel size is known,
32
+ * otherwise px². Empty for a degenerate (non-positive) area.
33
+ */
34
+ export function formatArea(px, mpp = {}) {
35
+ if (!(px > 0))
36
+ return '';
37
+ const { mppX, mppY } = mpp;
38
+ if (mppX && mppY && mppX > 0 && mppY > 0) {
39
+ const um2 = px * mppX * mppY;
40
+ return um2 >= 1e6 ? `${fmt(um2 / 1e6)} mm²` : `${fmt(um2)} µm²`;
41
+ }
42
+ return `${fmt(px)} px²`;
43
+ }
44
+ /** Exterior shoelace minus each hole, never negative. */
45
+ function polygonArea(p) {
46
+ if ((p.xpoints?.length ?? 0) < 3)
47
+ return 0;
48
+ let a = ringArea(p.xpoints, p.ypoints);
49
+ if (p.holes) {
50
+ for (const ring of p.holes)
51
+ a -= ringArea(ring.map((pt) => pt[0]), ring.map((pt) => pt[1]));
52
+ }
53
+ return Math.max(0, a);
54
+ }
55
+ /** Absolute shoelace area of one ring. */
56
+ function ringArea(xs, ys) {
57
+ const n = xs?.length ?? 0;
58
+ if (n < 3)
59
+ return 0;
60
+ let a = 0;
61
+ for (let i = 0, j = n - 1; i < n; j = i++)
62
+ a += (xs[j] + xs[i]) * (ys[j] - ys[i]);
63
+ return Math.abs(a / 2);
64
+ }
65
+ function fmt(n) {
66
+ return (n >= 1000 ? Math.round(n) : Math.round(n * 100) / 100).toLocaleString();
67
+ }
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLW1ldHJpY3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3JlZ2lvbi1lZGl0b3IvcmVnaW9uLW1ldHJpY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFVLE1BQU0sa0JBQWtCLENBQUM7QUFTNUU7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FBQyxJQUFrQztJQUN4RCxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUNsRyxNQUFNLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFDLElBQWUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ25FLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsSUFBZSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDbkUsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQztBQUN0QyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsTUFBOEI7SUFDekQsTUFBTSxDQUFDLEdBQUcsTUFBTSxD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QUFDO0lBQ2xGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDekIsQ0FBQztBQUVELFNBQVMsR0FBRyxDQUFDLENBQVM7SUFDcEIsT0FBTyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO0FBQ2xGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNdWx0aVBvbHlnb24sIFBvbHlnb24sIFJlY3RhbmdsZSwgUmVnaW9uIH0gZnJvbSAnLi4vbW9kZWxzL3JlZ2lvbic7XG5pbXBvcnQgeyBJSW1hZ2VNZXRhZGF0YSB9IGZyb20gJy4uL2NvbnRyYWN0cy9pbWFnZS5jb250cmFjdCc7XG5cbi8qKiBQaHlzaWNhbCBwaXhlbCBzaXplICjCtW0vcGl4ZWwpOyBib3RoIHVuZGVmaW5lZCB3aGVuIHRoZSBpbWFnZSBpcyB1bnNjYWxlZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGl4ZWxTaXplIHtcbiAgbXBwWD86IG51bWJlcjtcbiAgbXBwWT86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBDaG9vc2UgdGhlIHBoeXNpY2FsIHBpeGVsIHNpemUgZm9yIGFyZWEgZGlzcGxheSBmcm9tIHRoZSBpbWFnZSBtZXRhLiBUaGVcbiAqIGNhbGlicmF0aW9uIG1heSBzaXQgb24gYW55IGNoYW5uZWwgZW50cnksIG5vdCBuZWNlc3NhcmlseSBbMF0sIHNvIHRha2UgdGhlXG4gKiBmaXJzdCBlbnRyeSB3aXRoIGEgcG9zaXRpdmUgbXBwWCAoYXMgUGxvdGx5U2VydmljZS5jdXJyZW50TXBwIGRvZXMpLiBXaXRoXG4gKiBvbmx5IG9uZSBheGlzIHJlcG9ydGVkLCBwaXhlbHMgYXJlIHNxdWFyZSAobXBwWSA9IG1wcFgpLCBzbyBhIHNjYWxlZCBpbWFnZVxuICogc2hvd3MgwrVtwrIvbW3CsiByYXRoZXIgdGhhbiBweMKyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGlja01wcChtZXRhOiBJSW1hZ2VNZXRhZGF0YVtdIHwgdW5kZWZpbmVkKTogUGl4ZWxTaXplIHtcbiAgY29uc3QgbSA9IEFycmF5LmlzQXJyYXkobWV0YSkgPyAobWV0YS5maW5kKChlKSA9PiBlICYmIChlLm1wcFggPz8gMCkgPiAwKSA/PyBtZXRhWzBdKSA6IHVuZGVmaW5lZDtcbiAgY29uc3QgbXggPSBtICYmIChtLm1wcFggPz8gMCkgPiAwID8gKG0ubXBwWCBhcyBudW1iZXIpIDogdW5kZWZpbmVkO1xuICBjb25zdCBteSA9IG0gJiYgKG0ubXBwWSA/PyAwKSA+IDAgPyAobS5tcHBZIGFzIG51bWJlcikgOiB1bmRlZmluZWQ7XG4gIHJldHVybiB7IG1wcFg6IG14LCBtcHBZOiBteSA/PyBteCB9O1xufVxuXG4vKipcbiAqIEEgcmVnaW9uJ3MgYXJlYSBpbiBweMKyOiB3aWR0aMK3aGVpZ2h0IGZvciBhIHJlY3RhbmdsZSwgc2hvZWxhY2UgZm9yIGEgcG9seWdvblxuICogd2l0aCBlYWNoIGludGVyaW9yIHJpbmcgKGhvbGUpIHN1YnRyYWN0ZWQgKGEgZG9udXQgcmVwb3J0cyB0aGUgYW5udWx1cyksIGFuZFxuICogdGhlIHN1bSBvZiB0aGUgcGFydHMgZm9yIGEgbXVsdGktcG9seWdvbiAoaml0LXVpIzg1KS4gMCBmb3IgYW55dGhpbmcgZWxzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lvbkFyZWFQeChyZWdpb246IFBpY2s8UmVnaW9uLCAnYm91bmRzJz4pOiBudW1iZXIge1xuICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgaWYgKGIgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHJldHVybiBNYXRoLmFicyhiLndpZHRoICogYi5oZWlnaHQpO1xuICBpZiAoYiBpbnN0YW5jZW9mIFBvbHlnb24pIHJldHVybiBwb2x5Z29uQXJlYShiKTtcbiAgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHJldHVybiBiLnBvbHlnb25zLnJlZHVjZSgoc3VtLCBwKSA9PiBzdW0gKyBwb2x5Z29uQXJlYShwKSwgMCk7XG4gIHJldHVybiAwO1xufVxuXG4vKipcbiAqIEFuIGFyZWEgZm9yIGRpc3BsYXk6IMK1bcKyIChtbcKyIGZyb20gMWU2IMK1bcKyKSB3aGVuIHRoZSBwaXhlbCBzaXplIGlzIGtub3duLFxuICogb3RoZXJ3aXNlIHB4wrIuIEVtcHR5IGZvciBhIGRlZ2VuZXJhdGUgKG5vbi1wb3NpdGl2ZSkgYXJlYS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEFyZWEocHg6IG51bWJlciwgbXBwOiBQaXhlbFNpemUgPSB7fSk6IHN0cmluZyB7XG4gIGlmICghKHB4ID4gMCkpIHJldHVybiAnJztcbiAgY29uc3QgeyBtcHBYLCBtcHBZIH0gPSBtcHA7XG4gIGlmIChtcHBYICYmIG1wcFkgJiYgbXBwWCA+IDAgJiYgbXBwWSA+IDApIHtcbiAgICBjb25zdCB1bTIgPSBweCAqIG1wcFggKiBtcHBZO1xuICAgIHJldHVybiB1bTIgPj0gMWU2ID8gYCR7Zm10KHVtMiAvIDFlNil9IG1twrJgIDogYCR7Zm10KHVtMil9IMK1bcKyYDtcbiAgfVxuICByZXR1cm4gYCR7Zm10KHB4KX0gcHjCsmA7XG59XG5cbi8qKiBFeHRlcmlvciBzaG9lbGFjZSBtaW51cyBlYWNoIGhvbGUsIG5ldmVyIG5lZ2F0aXZlLiAqL1xuZnVuY3Rpb24gcG9seWdvbkFyZWEocDogUG9seWdvbik6IG51bWJlciB7XG4gIGlmICgocC54cG9pbnRzPy5sZW5ndGggPz8gMCkgPCAzKSByZXR1cm4gMDtcbiAgbGV0IGEgPSByaW5nQXJlYShwLnhwb2ludHMsIHAueXBvaW50cyk7XG4gIGlmIChwLmhvbGVzKSB7XG4gICAgZm9yIChjb25zdCByaW5nIG9mIHAuaG9sZXMpXG4gICAgICBhIC09IHJpbmdBcmVhKFxuICAgICAgICByaW5nLm1hcCgocHQpID0+IHB0WzBdKSxcbiAgICAgICAgcmluZy5tYXAoKHB0KSA9PiBwdFsxXSksXG4gICAgICApO1xuICB9XG4gIHJldHVybiBNYXRoLm1heCgwLCBhKTtcbn1cblxuLyoqIEFic29sdXRlIHNob2VsYWNlIGFyZWEgb2Ygb25lIHJpbmcuICovXG5mdW5jdGlvbiByaW5nQXJlYSh4czogbnVtYmVyW10sIHlzOiBudW1iZXJbXSk6IG51bWJlciB7XG4gIGNvbnN0IG4gPSB4cz8ubGVuZ3RoID8/IDA7XG4gIGlmIChuIDwgMykgcmV0dXJuIDA7XG4gIGxldCBhID0gMDtcbiAgZm9yIChsZXQgaSA9IDAsIGogPSBuIC0gMTsgaSA8IG47IGogPSBpKyspIGEgKz0gKHhzW2pdICsgeHNbaV0pICogKHlzW2pdIC0geXNbaV0pO1xuICByZXR1cm4gTWF0aC5hYnMoYSAvIDIpO1xufVxuXG5mdW5jdGlvbiBmbXQobjogbnVtYmVyKTogc3RyaW5nIHtcbiAgcmV0dXJuIChuID49IDEwMDAgPyBNYXRoLnJvdW5kKG4pIDogTWF0aC5yb3VuZChuICogMTAwKSAvIDEwMCkudG9Mb2NhbGVTdHJpbmcoKTtcbn1cbiJdfQ==
@@ -0,0 +1,134 @@
1
+ import { Inject, Injectable } from '@angular/core';
2
+ import { saveAs } from 'file-saver';
3
+ import { Observable, of } from 'rxjs';
4
+ import { catchError, debounceTime, switchMap } from 'rxjs/operators';
5
+ import { withRegionZ } from '../models/region-clone';
6
+ import { REGION_EDITOR_API } from '../contracts/region-editor-api.contract';
7
+ import { REGION_IO_PORT } from '../contracts/ports/region-io.port';
8
+ import { fileStem } from './file-stem';
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * Region file I/O for the Region Editor: default file names, GeoJSON download
12
+ * (export), save to the host through {@link RegionIoPort} (with a debounced
13
+ * "file exists" check), per-slice saves for folder stacks, and reading an
14
+ * imported file. Provided by the editor; it holds no state — the editor owns
15
+ * the dialogs, the toasts and the running jobs.
16
+ */
17
+ export class RegionPersistenceService {
18
+ constructor(api, io) {
19
+ this.api = api;
20
+ this.io = io;
21
+ }
22
+ /** The selected image's file name, if any. */
23
+ selectedFileName() {
24
+ return this.io.getSelectedFileName();
25
+ }
26
+ /** `<image-stem>.geojson` for a server save; undefined with no image selected. */
27
+ defaultSaveName() {
28
+ const name = this.io.getSelectedFileName();
29
+ return name ? `${fileStem(name, name)}.geojson` : undefined;
30
+ }
31
+ /** `<image-stem>.geojson` (or `rois.geojson`) for a download. */
32
+ defaultExportName() {
33
+ return `${fileStem(this.io.getSelectedFileName(), 'rois')}.geojson`;
34
+ }
35
+ /** `<image-stem>_mask.png` (or `regions_mask.png`) for a mask download. */
36
+ defaultMaskName() {
37
+ return `${fileStem(this.io.getSelectedFileName(), 'regions')}_mask.png`;
38
+ }
39
+ /** True when a save writes one geojson per slice-file (folder stack, jit-ui#93). */
40
+ savesPerSlice() {
41
+ return this.api.isStackMode() && this.api.getStackSaveLayout() === 'per-slice-file';
42
+ }
43
+ /**
44
+ * Regions to serialize on save/export. For a single-file z-stack the store
45
+ * keeps only the current slice live, so take EVERY slice's annotations (each
46
+ * tagged with its zero-based Region.z) for one combined z-indexed geojson
47
+ * (jit-ui#93); otherwise `live` (single plane, or a folder stack whose slices
48
+ * save to their own files).
49
+ */
50
+ regionsForSave(live) {
51
+ if (this.api.isStackMode() && this.api.getStackSaveLayout() === 'combined') {
52
+ return this.api.getSliceAnnotationRegions();
53
+ }
54
+ return live;
55
+ }
56
+ /**
57
+ * Whether each file name in `names` already exists on the host, debounced
58
+ * 400 ms; a newer name supersedes an in-flight check. A failed check reads as
59
+ * "does not exist" and later checks keep working.
60
+ */
61
+ fileExists(names) {
62
+ return names.pipe(debounceTime(400), switchMap((name) => this.io.roiFileExists(name).pipe(catchError(() => of(false)))));
63
+ }
64
+ /** Download `regions` as a GeoJSON file named `filename`. */
65
+ download(regions, filename) {
66
+ const blob = new Blob([this.api.getGeoJsonString(regions)], { type: 'application/json' });
67
+ saveAs(blob, filename);
68
+ }
69
+ /**
70
+ * Save `regions()` to the host as `filename`. Serializing is deferred one
71
+ * tick (so a progress indicator paints before a large synchronous
72
+ * serialize); unsubscribing before then cancels the save entirely, and after
73
+ * it cancels the upload. A serialize failure is an error, like an upload one.
74
+ */
75
+ save(regions, filename) {
76
+ return new Observable((subscriber) => {
77
+ let upload;
78
+ const timer = setTimeout(() => {
79
+ let geoJsonStr;
80
+ try {
81
+ geoJsonStr = this.api.getGeoJsonString(regions());
82
+ }
83
+ catch (err) {
84
+ subscriber.error(err);
85
+ return;
86
+ }
87
+ upload = this.io.saveGeoJson(geoJsonStr, filename).subscribe(subscriber);
88
+ });
89
+ return () => {
90
+ clearTimeout(timer);
91
+ upload?.unsubscribe();
92
+ };
93
+ });
94
+ }
95
+ /**
96
+ * A folder stack's regions as one geojson per slice-file (jit-ui#93), each
97
+ * serialized on the default plane (z=0): every slice-file is one plane, and
98
+ * the loader re-derives the slice index from the file's position. Slices
99
+ * cleared since load are included (empty) so their file is overwritten.
100
+ */
101
+ sliceGeoJsons() {
102
+ const out = [];
103
+ for (const [z, regs] of this.api.getStackSaveAnnotationSlices()) {
104
+ out.push({ z, geoJsonStr: this.api.getGeoJsonString(regs.map((r) => withRegionZ(r, 0))) });
105
+ }
106
+ return out;
107
+ }
108
+ /** Write per-slice geojsons through the host port. */
109
+ saveSlices(slices) {
110
+ return this.io.saveSliceGeoJsons(slices);
111
+ }
112
+ /** Read the file chosen in a file input's change event as text, then call
113
+ * `onText`. No-op when no file was chosen. */
114
+ readChosenFile(event, onText) {
115
+ const file = event.target.files?.[0];
116
+ if (!file)
117
+ return;
118
+ const reader = new FileReader();
119
+ reader.onload = () => onText(reader.result);
120
+ reader.readAsText(file);
121
+ }
122
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionPersistenceService, deps: [{ token: REGION_EDITOR_API }, { token: REGION_IO_PORT }], target: i0.ɵɵFactoryTarget.Injectable }); }
123
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionPersistenceService }); }
124
+ }
125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionPersistenceService, decorators: [{
126
+ type: Injectable
127
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
128
+ type: Inject,
129
+ args: [REGION_EDITOR_API]
130
+ }] }, { type: undefined, decorators: [{
131
+ type: Inject,
132
+ args: [REGION_IO_PORT]
133
+ }] }] });
134
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXBlcnNpc3RlbmNlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3JlZ2lvbi1lZGl0b3IvcmVnaW9uLXBlcnNpc3RlbmNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFnQixFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDcEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHckUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBb0IsaUJBQWlCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUM5RixPQUFPLEVBQUUsY0FBYyxFQUFnQixNQUFNLG1DQUFtQyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxhQUFhLENBQUM7O0FBUXZDOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyx3QkFBd0I7SUFDbkMsWUFDOEMsR0FBcUIsRUFDeEIsRUFBZ0I7UUFEYixRQUFHLEdBQUgsR0FBRyxDQUFrQjtRQUN4QixPQUFFLEdBQUYsRUFBRSxDQUFjO0lBQ3hELENBQUM7SUFFSiw4Q0FBOEM7SUFDOUMsZ0JBQWdCO1FBQ2QsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDdkMsQ0FBQztJQUVELGtGQUFrRjtJQUNsRixlQUFlO1FBQ2IsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLEVBQUUs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ZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBzYXZlQXMgfSBmcm9tICdmaWxlLXNhdmVyJztcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIGRlYm91bmNlVGltZSwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZWdpb24gfSBmcm9tICcuLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IHdpdGhSZWdpb25aIH0gZnJvbSAnLi4vbW9kZWxzL3JlZ2lvbi1jbG9uZSc7XG5pbXBvcnQgeyBJUmVnaW9uRWRpdG9yQXBpLCBSRUdJT05fRURJVE9SX0FQSSB9IGZyb20gJy4uL2NvbnRyYWN0cy9yZWdpb24tZWRpdG9yLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBSRUdJT05fSU9fUE9SVCwgUmVnaW9uSW9Qb3J0IH0gZnJvbSAnLi4vY29udHJhY3RzL3BvcnRzL3JlZ2lvbi1pby5wb3J0JztcbmltcG9ydCB7IGZpbGVTdGVtIH0gZnJvbSAnLi9maWxlLXN0ZW0nO1xuXG4vKiogT25lIHNsaWNlLWZpbGUncyBzZXJpYWxpemVkIHJlZ2lvbnMgKGZvbGRlciBzdGFjaywgaml0LXVpIzkzKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2xpY2VHZW9Kc29uIHtcbiAgejogbnVtYmVyO1xuICBnZW9Kc29uU3RyOiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVnaW9uIGZpbGUgSS9PIGZvciB0aGUgUmVnaW9uIEVkaXRvcjogZGVmYXVsdCBmaWxlIG5hbWVzLCBHZW9KU09OIGRvd25sb2FkXG4gKiAoZXhwb3J0KSwgc2F2ZSB0byB0aGUgaG9zdCB0aHJvdWdoIHtAbGluayBSZWdpb25Jb1BvcnR9ICh3aXRoIGEgZGVib3VuY2VkXG4gKiBcImZpbGUgZXhpc3RzXCIgY2hlY2spLCBwZXItc2xpY2Ugc2F2ZXMgZm9yIGZvbGRlciBzdGFja3MsIGFuZCByZWFkaW5nIGFuXG4gKiBpbXBvcnRlZCBmaWxlLiBQcm92aWRlZCBieSB0aGUgZWRpdG9yOyBpdCBob2xkcyBubyBzdGF0ZSDigJQgdGhlIGVkaXRvciBvd25zXG4gKiB0aGUgZGlhbG9ncywgdGhlIHRvYXN0cyBhbmQgdGhlIHJ1bm5pbmcgam9icy5cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFJlZ2lvblBlcnNpc3RlbmNlU2VydmljZSB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoUkVHSU9OX0VESVRPUl9BUEkpIHByaXZhdGUgcmVhZG9ubHkgYXBpOiBJUmVnaW9uRWRpdG9yQXBpLFxuICAgIEBJbmplY3QoUkVHSU9OX0lPX1BPUlQpIHByaXZhdGUgcmVhZG9ubHkgaW86IFJlZ2lvbklvUG9ydCxcbiAgKSB7fVxuXG4gIC8qKiBUaGUgc2VsZWN0ZWQgaW1hZ2UncyBmaWxlIG5hbWUsIGlmIGFueS4gKi9cbiAgc2VsZWN0ZWRGaWxlTmFtZSgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmlvLmdldFNlbGVjdGVkRmlsZU5hbWUoKTtcbiAgfVxuXG4gIC8qKiBgPGltYWdlLXN0ZW0+Lmdlb2pzb25gIGZvciBhIHNlcnZlciBzYXZlOyB1bmRlZmluZWQgd2l0aCBubyBpbWFnZSBzZWxlY3RlZC4gKi9cbiAgZGVmYXVsdFNhdmVOYW1lKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgbmFtZSA9IHRoaXMuaW8uZ2V0U2VsZWN0ZWRGaWxlTmFtZSgpO1xuICAgIHJldHVybiBuYW1lID8gYCR7ZmlsZVN0ZW0obmFtZSwgbmFtZSl9Lmdlb2pzb25gIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqIGA8aW1hZ2Utc3RlbT4uZ2VvanNvbmAgKG9yIGByb2lzLmdlb2pzb25gKSBmb3IgYSBkb3dubG9hZC4gKi9cbiAgZGVmYXVsdEV4cG9ydE5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCR7ZmlsZVN0ZW0odGhpcy5pby5nZXRTZWxlY3RlZEZpbGVOYW1lKCksICdyb2lzJyl9Lmdlb2pzb25gO1xuICB9XG5cbiAgLyoqIGA8aW1hZ2Utc3RlbT5fbWFzay5wbmdgIChvciBgcmVnaW9uc19tYXNrLnBuZ2ApIGZvciBhIG1hc2sgZG93bmxvYWQuICovXG4gIGRlZmF1bHRNYXNrTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHtmaWxlU3RlbSh0aGlzLmlvLmdldFNlbGVjdGVkRmlsZU5hbWUoKSwgJ3JlZ2lvbnMnKX1fbWFzay5wbmdgO1xuICB9XG5cbiAgLyoqIFRydWUgd2hlbiBhIHNhdmUgd3JpdGVzIG9uZSBnZW9qc29uIHBlciBzbGljZS1maWxlIChmb2xkZXIgc3RhY2ssIGppdC11aSM5MykuICovXG4gIHNhdmVzUGVyU2xpY2UoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYXBpLmlzU3RhY2tNb2RlKCkgJiYgdGhpcy5hcGkuZ2V0U3RhY2tTYXZlTGF5b3V0KCkgPT09ICdwZXItc2xpY2UtZmlsZSc7XG4gIH1cblxuICAvKipcbiAgICogUmVnaW9ucyB0byBzZXJpYWxpemUgb24gc2F2ZS9leHBvcnQuIEZvciBhIHNpbmdsZS1maWxlIHotc3RhY2sgdGhlIHN0b3JlXG4gICAqIGtlZXBzIG9ubHkgdGhlIGN1cnJlbnQgc2xpY2UgbGl2ZSwgc28gdGFrZSBFVkVSWSBzbGljZSdzIGFubm90YXRpb25zIChlYWNoXG4gICAqIHRhZ2dlZCB3aXRoIGl0cyB6ZXJvLWJhc2VkIFJlZ2lvbi56KSBmb3Igb25lIGNvbWJpbmVkIHotaW5kZXhlZCBnZW9qc29uXG4gICAqIChqaXQtdWkjOTMpOyBvdGhlcndpc2UgYGxpdmVgIChzaW5nbGUgcGxhbmUsIG9yIGEgZm9sZGVyIHN0YWNrIHdob3NlIHNsaWNlc1xuICAgKiBzYXZlIHRvIHRoZWlyIG93biBmaWxlcykuXG4gICAqL1xuICByZWdpb25zRm9yU2F2ZShsaXZlOiBSZWdpb25bXSk6IFJlZ2lvbltdIHtcbiAgICBpZiAodGhpcy5hcGkuaXNTdGFja01vZGUoKSAmJiB0aGlzLmFwaS5nZXRTdGFja1NhdmVMYXlvdXQoKSA9PT0gJ2NvbWJpbmVkJykge1xuICAgICAgcmV0dXJuIHRoaXMuYXBpLmdldFNsaWNlQW5ub3RhdGlvblJlZ2lvbnMoKTtcbiAgICB9XG4gICAgcmV0dXJuIGxpdmU7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciBlYWNoIGZpbGUgbmFtZSBpbiBgbmFtZXNgIGFscmVhZHkgZXhpc3RzIG9uIHRoZSBob3N0LCBkZWJvdW5jZWRcbiAgICogNDAwIG1zOyBhIG5ld2VyIG5hbWUgc3VwZXJzZWRlcyBhbiBpbi1mbGlnaHQgY2hlY2suIEEgZmFpbGVkIGNoZWNrIHJlYWRzIGFzXG4gICAqIFwiZG9lcyBub3QgZXhpc3RcIiBhbmQgbGF0ZXIgY2hlY2tzIGtlZXAgd29ya2luZy5cbiAgICovXG4gIGZpbGVFeGlzdHMobmFtZXM6IE9ic2VydmFibGU8c3RyaW5nPik6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBuYW1lcy5waXBlKFxuICAgICAgZGVib3VuY2VUaW1lKDQwMCksXG4gICAgICBzd2l0Y2hNYXAoKG5hbWUpID0+IHRoaXMuaW8ucm9pRmlsZUV4aXN0cyhuYW1lKS5waXBlKGNhdGNoRXJyb3IoKCkgPT4gb2YoZmFsc2UpKSkpLFxuICAgICk7XG4gIH1cblxuICAvKiogRG93bmxvYWQgYHJlZ2lvbnNgIGFzIGEgR2VvSlNPTiBmaWxlIG5hbWVkIGBmaWxlbmFtZWAuICovXG4gIGRvd25sb2FkKHJlZ2lvbnM6IFJlZ2lvbltdLCBmaWxlbmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgYmxvYiA9IG5ldyBCbG9iKFt0aGlzLmFwaS5nZXRHZW9Kc29uU3RyaW5nKHJlZ2lvbnMpXSwgeyB0eXBlOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgc2F2ZUFzKGJsb2IsIGZpbGVuYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlIGByZWdpb25zKClgIHRvIHRoZSBob3N0IGFzIGBmaWxlbmFtZWAuIFNlcmlhbGl6aW5nIGlzIGRlZmVycmVkIG9uZVxuICAgKiB0aWNrIChzbyBhIHByb2dyZXNzIGluZGljYXRvciBwYWludHMgYmVmb3JlIGEgbGFyZ2Ugc3luY2hyb25vdXNcbiAgICogc2VyaWFsaXplKTsgdW5zdWJzY3JpYmluZyBiZWZvcmUgdGhlbiBjYW5jZWxzIHRoZSBzYXZlIGVudGlyZWx5LCBhbmQgYWZ0ZXJcbiAgICogaXQgY2FuY2VscyB0aGUgdXBsb2FkLiBBIHNlcmlhbGl6ZSBmYWlsdXJlIGlzIGFuIGVycm9yLCBsaWtlIGFuIHVwbG9hZCBvbmUuXG4gICAqL1xuICBzYXZlKHJlZ2lvbnM6ICgpID0+IFJlZ2lvbltdLCBmaWxlbmFtZTogc3RyaW5nKTogT2JzZXJ2YWJsZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlPHZvaWQ+KChzdWJzY3JpYmVyKSA9PiB7XG4gICAgICBsZXQgdXBsb2FkOiBTdWJzY3JpcHRpb24gfCB1bmRlZmluZWQ7XG4gICAgICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBsZXQgZ2VvSnNvblN0cjogc3RyaW5nO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGdlb0pzb25TdHIgPSB0aGlzLmFwaS5nZXRHZW9Kc29uU3RyaW5nKHJlZ2lvbnMoKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIHN1YnNjcmliZXIuZXJyb3IoZXJyKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdXBsb2FkID0gdGhpcy5pby5zYXZlR2VvSnNvbihnZW9Kc29uU3RyLCBmaWxlbmFtZSkuc3Vic2NyaWJlKHN1YnNjcmliZXIpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICB1cGxvYWQ/LnVuc3Vic2NyaWJlKCk7XG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgZm9sZGVyIHN0YWNrJ3MgcmVnaW9ucyBhcyBvbmUgZ2VvanNvbiBwZXIgc2xpY2UtZmlsZSAoaml0LXVpIzkzKSwgZWFjaFxuICAgKiBzZXJpYWxpemVkIG9uIHRoZSBkZWZhdWx0IHBsYW5lICh6PTApOiBldmVyeSBzbGljZS1maWxlIGlzIG9uZSBwbGFuZSwgYW5kXG4gICAqIHRoZSBsb2FkZXIgcmUtZGVyaXZlcyB0aGUgc2xpY2UgaW5kZXggZnJvbSB0aGUgZmlsZSdzIHBvc2l0aW9uLiBTbGljZXNcbiAgICogY2xlYXJlZCBzaW5jZSBsb2FkIGFyZSBpbmNsdWRlZCAoZW1wdHkpIHNvIHRoZWlyIGZpbGUgaXMgb3ZlcndyaXR0ZW4uXG4gICAqL1xuICBzbGljZUdlb0pzb25zKCk6IFNsaWNlR2VvSnNvbltdIHtcbiAgICBjb25zdCBvdXQ6IFNsaWNlR2VvSnNvbltdID0gW107XG4gICAgZm9yIChjb25zdCBbeiwgcmVnc10gb2YgdGhpcy5hcGkuZ2V0U3RhY2tTYXZlQW5ub3RhdGlvblNsaWNlcygpKSB7XG4gICAgICBvdXQucHVzaCh7IHosIGdlb0pzb25TdHI6IHRoaXMuYXBpLmdldEdlb0pzb25TdHJpbmcocmVncy5tYXAoKHIpID0+IHdpdGhSZWdpb25aKHIsIDApKSkgfSk7XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKiogV3JpdGUgcGVyLXNsaWNlIGdlb2pzb25zIHRocm91Z2ggdGhlIGhvc3QgcG9ydC4gKi9cbiAgc2F2ZVNsaWNlcyhzbGljZXM6IFNsaWNlR2VvSnNvbltdKTogT2JzZXJ2YWJsZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuaW8uc2F2ZVNsaWNlR2VvSnNvbnMoc2xpY2VzKTtcbiAgfVxuXG4gIC8qKiBSZWFkIHRoZSBmaWxlIGNob3NlbiBpbiBhIGZpbGUgaW5wdXQncyBjaGFuZ2UgZXZlbnQgYXMgdGV4dCwgdGhlbiBjYWxsXG4gICAqICBgb25UZXh0YC4gTm8tb3Agd2hlbiBubyBmaWxlIHdhcyBjaG9zZW4uICovXG4gIHJlYWRDaG9zZW5GaWxlKGV2ZW50OiBFdmVudCwgb25UZXh0OiAodGV4dDogc3RyaW5nKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgY29uc3QgZmlsZSA9IChldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkuZmlsZXM/LlswXTtcbiAgICBpZiAoIWZpbGUpIHJldHVybjtcbiAgICBjb25zdCByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpO1xuICAgIHJlYWRlci5vbmxvYWQgPSAoKSA9PiBvblRleHQocmVhZGVyLnJlc3VsdCBhcyBzdHJpbmcpO1xuICAgIHJlYWRlci5yZWFkQXNUZXh0KGZpbGUpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,153 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { SharedModule } from 'primeng/api';
5
+ import { ButtonModule } from 'primeng/button';
6
+ import { DropdownModule } from 'primeng/dropdown';
7
+ import { InputTextModule } from 'primeng/inputtext';
8
+ import { PaginatorModule } from 'primeng/paginator';
9
+ import { RippleModule } from 'primeng/ripple';
10
+ import { TableModule } from 'primeng/table';
11
+ import { TooltipModule } from 'primeng/tooltip';
12
+ import { defaultPresetSet } from '../../models/class-preset';
13
+ import { colorForLabel } from '../../store/class-color.util';
14
+ import { formatArea, regionAreaPx } from '../region-metrics';
15
+ import * as i0 from "@angular/core";
16
+ import * as i1 from "@angular/common";
17
+ import * as i2 from "@angular/forms";
18
+ import * as i3 from "primeng/api";
19
+ import * as i4 from "primeng/button";
20
+ import * as i5 from "primeng/dropdown";
21
+ import * as i6 from "primeng/inputtext";
22
+ import * as i7 from "primeng/paginator";
23
+ import * as i8 from "primeng/ripple";
24
+ import * as i9 from "primeng/table";
25
+ import * as i10 from "primeng/tooltip";
26
+ /**
27
+ * The Region Editor's regions table and paginator: one page of rows with a
28
+ * class dropdown (or an inline label editor), the area, and a delete button.
29
+ * Presentational and OnPush: the editor owns the rows, the selection, the
30
+ * paging and the label drafts, and applies every edit through its one
31
+ * copy-on-write commit path — the table never changes a {@link Region}.
32
+ */
33
+ export class RegionTableComponent {
34
+ constructor() {
35
+ /** The rows on the current page. */
36
+ this.page = [];
37
+ /** Total number of rows (all pages). */
38
+ this.total = 0;
39
+ /** Index of the page's first row across all pages. */
40
+ this.first = 0;
41
+ /** Rows per page. */
42
+ this.rows = 10;
43
+ /** The paginator's rows-per-page choices. */
44
+ this.rowsPerPageOptions = [10, 25, 50];
45
+ /** Ctrl/Cmd-click toggles a row (PrimeNG metaKeySelection). */
46
+ this.metaKey = true;
47
+ /** The selected rows. */
48
+ this.selection = [];
49
+ /** The table's selection changed (any row click). */
50
+ this.selectionChange = new EventEmitter();
51
+ /** A row was selected or unselected (after {@link selectionChange}). */
52
+ this.rowSelect = new EventEmitter();
53
+ /** Classes for the per-row dropdown, and their colours. */
54
+ this.presetSet = defaultPresetSet();
55
+ /** Swatch colour of an unlabelled row. */
56
+ this.defaultColor = '#00FFFF';
57
+ /** Pixel size for the area column. */
58
+ this.mpp = {};
59
+ /** Rows whose label is being edited → the typed draft. A new map per start/stop. */
60
+ this.labelDrafts = new Map();
61
+ /** A row's pencil: start editing its label. */
62
+ this.labelEditStart = new EventEmitter();
63
+ /** The inline label editor's text changed. */
64
+ this.labelDraftChange = new EventEmitter();
65
+ /** The inline label editor closed: Enter commits, Escape / close cancels. */
66
+ this.labelEditStop = new EventEmitter();
67
+ /** A class was picked in a row's dropdown. */
68
+ this.classPick = new EventEmitter();
69
+ /** A row's trash button: the row's index across all pages. */
70
+ this.deleteRow = new EventEmitter();
71
+ /** The paginator moved or changed its page size. */
72
+ this.pageChange = new EventEmitter();
73
+ /** Per row of {@link page}: its class swatch colour and formatted area, derived when
74
+ * an input changes instead of per check (the area walks the region's geometry). */
75
+ this.rowView = new Map();
76
+ }
77
+ ngOnChanges() {
78
+ this.rowView = new Map(this.page.map((r) => [r, { color: this.classColor(r.label), area: this.area(r) }]));
79
+ }
80
+ classColor(name) {
81
+ return name ? colorForLabel(name, this.presetSet) : this.defaultColor;
82
+ }
83
+ area(region) {
84
+ return formatArea(regionAreaPx(region), this.mpp);
85
+ }
86
+ startEdit(region, event) {
87
+ event.stopPropagation(); // don't toggle row selection
88
+ this.labelEditStart.emit(region);
89
+ }
90
+ stopEdit(region, commit, event) {
91
+ event.stopPropagation();
92
+ this.labelEditStop.emit({ region, commit });
93
+ }
94
+ onPage(event) {
95
+ this.pageChange.emit({ first: event.first ?? 0, rows: event.rows ?? this.rows });
96
+ }
97
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
98
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: RegionTableComponent, isStandalone: true, selector: "region-table", inputs: { page: "page", total: "total", first: "first", rows: "rows", rowsPerPageOptions: "rowsPerPageOptions", metaKey: "metaKey", selection: "selection", presetSet: "presetSet", defaultColor: "defaultColor", mpp: "mpp", labelDrafts: "labelDrafts" }, outputs: { selectionChange: "selectionChange", rowSelect: "rowSelect", labelEditStart: "labelEditStart", labelDraftChange: "labelDraftChange", labelEditStop: "labelEditStop", classPick: "classPick", deleteRow: "deleteRow", pageChange: "pageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"region-editor-content\">\n <p-table\n [value]=\"page\"\n [tableStyle]=\"{ width: '100%' }\"\n [selection]=\"selection\"\n (selectionChange)=\"selectionChange.emit($event)\"\n selectionMode=\"multiple\"\n [metaKeySelection]=\"metaKey\"\n (onRowSelect)=\"rowSelect.emit()\"\n (onRowUnselect)=\"rowSelect.emit()\"\n [resizableColumns]=\"true\"\n [rowHover]=\"true\"\n dataKey=\"id\"\n styleClass=\"p-datatable-sm region-editor-table\"\n [scrollable]=\"true\"\n scrollHeight=\"100%\"\n >\n <ng-template pTemplate=\"header\">\n <!-- Hide the column header when there are no regions to show. -->\n <tr *ngIf=\"total > 0\">\n <!-- Class column: shrinks to fit \"Region\" by default, grows with longer labels. -->\n <th class=\"class-col-header\" pResizableColumn>Class <p-sortIcon field=\"label\"></p-sortIcon></th>\n <th class=\"surface-col-header\" pResizableColumn>Surface</th>\n <!-- Trash column: just enough for the icon. -->\n <th style=\"width: 2rem\"></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-region let-rowIdx=\"rowIndex\">\n <tr [pSelectableRow]=\"region\" [pSelectableRowIndex]=\"rowIdx\">\n <td class=\"class-cell\">\n <ng-container *ngIf=\"!labelDrafts.has(region); else editLabelTpl\">\n <span class=\"class-cell-display\">\n <!-- Quick-pick a preset class (its colour follows); the pencil is for\n a free-form name / rename (jit-ui#70). -->\n <p-dropdown\n class=\"class-dropdown\"\n appendTo=\"body\"\n [options]=\"presetSet.classes\"\n optionLabel=\"name\"\n optionValue=\"name\"\n [ngModel]=\"region.label\"\n [autoDisplayFirst]=\"false\"\n ariaLabel=\"Class\"\n (onChange)=\"classPick.emit({ region: region, name: $event.value })\"\n >\n <ng-template pTemplate=\"selectedItem\">\n <span class=\"dd-value\">\n <span class=\"chip-swatch\" [style.background]=\"rowView.get(region)?.color\"></span>\n <span class=\"class-name\" [pTooltip]=\"region.label\" tooltipPosition=\"bottom\">{{\n region.label || '\u2014'\n }}</span>\n </span>\n </ng-template>\n <ng-template let-c pTemplate=\"item\">\n <span class=\"dd-value\">\n <span class=\"chip-swatch\" [style.background]=\"c.color\"></span>\n <span>{{ c.name }}</span>\n </span>\n </ng-template>\n </p-dropdown>\n <i\n class=\"pi pi-pencil icon-hover ml-2\"\n pTooltip=\"Rename / free-form label\"\n tooltipPosition=\"bottom\"\n role=\"button\"\n aria-label=\"Rename\"\n (click)=\"startEdit(region, $event)\"\n ></i>\n </span>\n </ng-container>\n <ng-template #editLabelTpl>\n <span class=\"p-input-icon-right class-cell-edit\">\n <i\n class=\"pi pi-times icon-hover\"\n pTooltip=\"Close\"\n tooltipPosition=\"bottom\"\n role=\"button\"\n aria-label=\"Cancel rename\"\n (click)=\"stopEdit(region, false, $event)\"\n ></i>\n <input\n type=\"text\"\n pInputText\n class=\"p-inputtext-sm w-full\"\n aria-label=\"Class label\"\n [ngModel]=\"labelDrafts.get(region)\"\n (ngModelChange)=\"labelDraftChange.emit({ region: region, value: $event })\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"stopEdit(region, true, $event)\"\n (keydown.escape)=\"stopEdit(region, false, $event)\"\n />\n </span>\n </ng-template>\n </td>\n <!-- Surface area (\u00B5m\u00B2/mm\u00B2 when the image is scaled, else px\u00B2). -->\n <td class=\"surface-cell\">{{ rowView.get(region)?.area || '\u2014' }}</td>\n <td>\n <button\n pButton\n pRipple\n icon=\"pi pi-trash\"\n aria-label=\"Delete region\"\n class=\"p-button-sm p-button-rounded p-button-text p-button-warning\"\n (click)=\"deleteRow.emit(first + rowIdx)\"\n ></button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n</div>\n\n<p-paginator\n *ngIf=\"total > 0\"\n [rows]=\"rows\"\n [totalRecords]=\"total\"\n [first]=\"first\"\n [rowsPerPageOptions]=\"rowsPerPageOptions\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} to {last} of {totalRecords}\"\n (onPageChange)=\"onPage($event)\"\n styleClass=\"region-editor-paginator\"\n>\n</p-paginator>\n", styles: ["@charset \"UTF-8\";.chip-swatch{display:inline-block;width:.75rem;height:.75rem;border-radius:50%;border:1px solid rgba(0,0,0,.2);flex:0 0 auto}.dd-value{display:inline-flex;align-items:center;gap:.4rem;min-width:0}.dd-value .class-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}.region-editor-content{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-3{padding:0!important}::ng-deep .region-editor-content>p-table{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-datatable.region-editor-table{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-header{flex:0 0 auto}::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-wrapper,::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-table-container,::ng-deep .region-editor-content .p-datatable.region-editor-table .p-scroller-viewport{flex:1 1 0;min-height:0;height:100%;max-height:100%;overflow:auto}:host>p-paginator{display:block;flex:0 0 auto;border-top:1px solid var(--surface-border);padding:.25rem 0}.class-col-header,.class-cell{white-space:nowrap;max-width:16rem}.class-cell .class-cell-display{display:flex;align-items:center;min-width:0}.class-cell .class-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.class-cell .icon-hover{flex:0 0 auto}.class-cell .icon-hover{cursor:pointer;color:var(--text-color-secondary);transition:color .15s ease}.class-cell .icon-hover:hover{color:var(--primary-color)}.class-cell .class-cell-edit{display:inline-block;width:100%}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-rounded,::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-icon-only{width:1.5rem;height:1.5rem;padding:0}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-rounded .p-button-icon,::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-icon-only .p-button-icon{font-size:.75rem}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-inputtext{padding:.25rem .5rem;font-size:.875rem}::ng-deep .p-datatable-sm .p-paginator{padding:.15rem .25rem!important;min-height:unset!important}::ng-deep .p-datatable-sm .p-paginator,::ng-deep .p-datatable-sm .p-paginator *{font-size:.75rem!important}::ng-deep .p-datatable-sm .p-paginator .p-paginator-element{min-width:1.5rem!important;height:1.5rem!important}::ng-deep .p-datatable-sm .p-paginator .p-paginator-current{font-size:.75rem!important;height:1.5rem!important;min-width:unset!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown{height:1.5rem!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown .p-dropdown-label{padding:.1rem .25rem!important;line-height:1.2!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown .p-dropdown-trigger{width:1.25rem!important}::ng-deep .p-paginator-rpp-options .p-dropdown-panel .p-dropdown-items .p-dropdown-item{padding:.25rem .5rem!important;font-size:.75rem!important}.class-cell .class-dropdown{min-width:0;flex:1 1 auto}::ng-deep .class-cell .class-dropdown.p-dropdown{width:100%}::ng-deep .class-cell .class-dropdown .p-dropdown-label{padding:.15rem .5rem;display:flex;align-items:center}\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.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: SharedModule }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i5.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i6.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i7.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i8.Ripple, selector: "[pRipple]" }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i9.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll", "virtualRowHeight"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i9.SelectableRow, selector: "[pSelectableRow]", inputs: ["pSelectableRow", "pSelectableRowIndex", "pSelectableRowDisabled"] }, { kind: "directive", type: i9.ResizableColumn, selector: "[pResizableColumn]", inputs: ["pResizableColumnDisabled"] }, { kind: "component", type: i9.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i10.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 }); }
99
+ }
100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionTableComponent, decorators: [{
101
+ type: Component,
102
+ args: [{ selector: 'region-table', standalone: true, imports: [
103
+ CommonModule,
104
+ FormsModule,
105
+ SharedModule,
106
+ ButtonModule,
107
+ DropdownModule,
108
+ InputTextModule,
109
+ PaginatorModule,
110
+ RippleModule,
111
+ TableModule,
112
+ TooltipModule,
113
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"region-editor-content\">\n <p-table\n [value]=\"page\"\n [tableStyle]=\"{ width: '100%' }\"\n [selection]=\"selection\"\n (selectionChange)=\"selectionChange.emit($event)\"\n selectionMode=\"multiple\"\n [metaKeySelection]=\"metaKey\"\n (onRowSelect)=\"rowSelect.emit()\"\n (onRowUnselect)=\"rowSelect.emit()\"\n [resizableColumns]=\"true\"\n [rowHover]=\"true\"\n dataKey=\"id\"\n styleClass=\"p-datatable-sm region-editor-table\"\n [scrollable]=\"true\"\n scrollHeight=\"100%\"\n >\n <ng-template pTemplate=\"header\">\n <!-- Hide the column header when there are no regions to show. -->\n <tr *ngIf=\"total > 0\">\n <!-- Class column: shrinks to fit \"Region\" by default, grows with longer labels. -->\n <th class=\"class-col-header\" pResizableColumn>Class <p-sortIcon field=\"label\"></p-sortIcon></th>\n <th class=\"surface-col-header\" pResizableColumn>Surface</th>\n <!-- Trash column: just enough for the icon. -->\n <th style=\"width: 2rem\"></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-region let-rowIdx=\"rowIndex\">\n <tr [pSelectableRow]=\"region\" [pSelectableRowIndex]=\"rowIdx\">\n <td class=\"class-cell\">\n <ng-container *ngIf=\"!labelDrafts.has(region); else editLabelTpl\">\n <span class=\"class-cell-display\">\n <!-- Quick-pick a preset class (its colour follows); the pencil is for\n a free-form name / rename (jit-ui#70). -->\n <p-dropdown\n class=\"class-dropdown\"\n appendTo=\"body\"\n [options]=\"presetSet.classes\"\n optionLabel=\"name\"\n optionValue=\"name\"\n [ngModel]=\"region.label\"\n [autoDisplayFirst]=\"false\"\n ariaLabel=\"Class\"\n (onChange)=\"classPick.emit({ region: region, name: $event.value })\"\n >\n <ng-template pTemplate=\"selectedItem\">\n <span class=\"dd-value\">\n <span class=\"chip-swatch\" [style.background]=\"rowView.get(region)?.color\"></span>\n <span class=\"class-name\" [pTooltip]=\"region.label\" tooltipPosition=\"bottom\">{{\n region.label || '\u2014'\n }}</span>\n </span>\n </ng-template>\n <ng-template let-c pTemplate=\"item\">\n <span class=\"dd-value\">\n <span class=\"chip-swatch\" [style.background]=\"c.color\"></span>\n <span>{{ c.name }}</span>\n </span>\n </ng-template>\n </p-dropdown>\n <i\n class=\"pi pi-pencil icon-hover ml-2\"\n pTooltip=\"Rename / free-form label\"\n tooltipPosition=\"bottom\"\n role=\"button\"\n aria-label=\"Rename\"\n (click)=\"startEdit(region, $event)\"\n ></i>\n </span>\n </ng-container>\n <ng-template #editLabelTpl>\n <span class=\"p-input-icon-right class-cell-edit\">\n <i\n class=\"pi pi-times icon-hover\"\n pTooltip=\"Close\"\n tooltipPosition=\"bottom\"\n role=\"button\"\n aria-label=\"Cancel rename\"\n (click)=\"stopEdit(region, false, $event)\"\n ></i>\n <input\n type=\"text\"\n pInputText\n class=\"p-inputtext-sm w-full\"\n aria-label=\"Class label\"\n [ngModel]=\"labelDrafts.get(region)\"\n (ngModelChange)=\"labelDraftChange.emit({ region: region, value: $event })\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"stopEdit(region, true, $event)\"\n (keydown.escape)=\"stopEdit(region, false, $event)\"\n />\n </span>\n </ng-template>\n </td>\n <!-- Surface area (\u00B5m\u00B2/mm\u00B2 when the image is scaled, else px\u00B2). -->\n <td class=\"surface-cell\">{{ rowView.get(region)?.area || '\u2014' }}</td>\n <td>\n <button\n pButton\n pRipple\n icon=\"pi pi-trash\"\n aria-label=\"Delete region\"\n class=\"p-button-sm p-button-rounded p-button-text p-button-warning\"\n (click)=\"deleteRow.emit(first + rowIdx)\"\n ></button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n</div>\n\n<p-paginator\n *ngIf=\"total > 0\"\n [rows]=\"rows\"\n [totalRecords]=\"total\"\n [first]=\"first\"\n [rowsPerPageOptions]=\"rowsPerPageOptions\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} to {last} of {totalRecords}\"\n (onPageChange)=\"onPage($event)\"\n styleClass=\"region-editor-paginator\"\n>\n</p-paginator>\n", styles: ["@charset \"UTF-8\";.chip-swatch{display:inline-block;width:.75rem;height:.75rem;border-radius:50%;border:1px solid rgba(0,0,0,.2);flex:0 0 auto}.dd-value{display:inline-flex;align-items:center;gap:.4rem;min-width:0}.dd-value .class-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}.region-editor-content{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-3{padding:0!important}::ng-deep .region-editor-content>p-table{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-datatable.region-editor-table{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-header{flex:0 0 auto}::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-wrapper,::ng-deep .region-editor-content .p-datatable.region-editor-table>.p-datatable-table-container,::ng-deep .region-editor-content .p-datatable.region-editor-table .p-scroller-viewport{flex:1 1 0;min-height:0;height:100%;max-height:100%;overflow:auto}:host>p-paginator{display:block;flex:0 0 auto;border-top:1px solid var(--surface-border);padding:.25rem 0}.class-col-header,.class-cell{white-space:nowrap;max-width:16rem}.class-cell .class-cell-display{display:flex;align-items:center;min-width:0}.class-cell .class-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.class-cell .icon-hover{flex:0 0 auto}.class-cell .icon-hover{cursor:pointer;color:var(--text-color-secondary);transition:color .15s ease}.class-cell .icon-hover:hover{color:var(--primary-color)}.class-cell .class-cell-edit{display:inline-block;width:100%}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-rounded,::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-icon-only{width:1.5rem;height:1.5rem;padding:0}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-rounded .p-button-icon,::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-button.p-button-icon-only .p-button-icon{font-size:.75rem}::ng-deep .p-datatable-sm .p-datatable-tbody>tr>td .p-inputtext{padding:.25rem .5rem;font-size:.875rem}::ng-deep .p-datatable-sm .p-paginator{padding:.15rem .25rem!important;min-height:unset!important}::ng-deep .p-datatable-sm .p-paginator,::ng-deep .p-datatable-sm .p-paginator *{font-size:.75rem!important}::ng-deep .p-datatable-sm .p-paginator .p-paginator-element{min-width:1.5rem!important;height:1.5rem!important}::ng-deep .p-datatable-sm .p-paginator .p-paginator-current{font-size:.75rem!important;height:1.5rem!important;min-width:unset!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown{height:1.5rem!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown .p-dropdown-label{padding:.1rem .25rem!important;line-height:1.2!important}::ng-deep .p-datatable-sm .p-paginator .p-dropdown .p-dropdown-trigger{width:1.25rem!important}::ng-deep .p-paginator-rpp-options .p-dropdown-panel .p-dropdown-items .p-dropdown-item{padding:.25rem .5rem!important;font-size:.75rem!important}.class-cell .class-dropdown{min-width:0;flex:1 1 auto}::ng-deep .class-cell .class-dropdown.p-dropdown{width:100%}::ng-deep .class-cell .class-dropdown .p-dropdown-label{padding:.15rem .5rem;display:flex;align-items:center}\n"] }]
114
+ }], propDecorators: { page: [{
115
+ type: Input
116
+ }], total: [{
117
+ type: Input
118
+ }], first: [{
119
+ type: Input
120
+ }], rows: [{
121
+ type: Input
122
+ }], rowsPerPageOptions: [{
123
+ type: Input
124
+ }], metaKey: [{
125
+ type: Input
126
+ }], selection: [{
127
+ type: Input
128
+ }], selectionChange: [{
129
+ type: Output
130
+ }], rowSelect: [{
131
+ type: Output
132
+ }], presetSet: [{
133
+ type: Input
134
+ }], defaultColor: [{
135
+ type: Input
136
+ }], mpp: [{
137
+ type: Input
138
+ }], labelDrafts: [{
139
+ type: Input
140
+ }], labelEditStart: [{
141
+ type: Output
142
+ }], labelDraftChange: [{
143
+ type: Output
144
+ }], labelEditStop: [{
145
+ type: Output
146
+ }], classPick: [{
147
+ type: Output
148
+ }], deleteRow: [{
149
+ type: Output
150
+ }], pageChange: [{
151
+ type: Output
152
+ }] } });
153
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXRhYmxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWVkaXRvci9yZWdpb24tdGFibGUvcmVnaW9uLXRhYmxlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWVkaXRvci9yZWdpb24tdGFibGUvcmVnaW9uLXRhYmxlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBYSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0csT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM1QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHaEQsT0FBTyxFQUFhLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzdELE9BQU8sRUFBYSxVQUFVLEVBQUUsWUFBWSxFQUFFLE1BQU0sbUJBQW1C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O2dCQUVHLFNBQVM7c0JBQWxCLE1BQU07Z0JBRUcsVUFBVTtzQkFBbkIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uQ2hhbmdlcywgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTaGFyZWRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2FwaSc7XG5pbXBvcnQgeyBCdXR0b25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2J1dHRvbic7XG5pbXBvcnQgeyBEcm9wZG93bk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvZHJvcGRvd24nO1xuaW1wb3J0IHsgSW5wdXRUZXh0TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dHRleHQnO1xuaW1wb3J0IHsgUGFnaW5hdG9yTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9wYWdpbmF0b3InO1xuaW1wb3J0IHsgUmlwcGxlTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9yaXBwbGUnO1xuaW1wb3J0IHsgVGFibGVNb2R1bGUgfSBmcm9tICdwcmltZW5nL3RhYmxlJztcbmltcG9ydCB7IFRvb2x0aXBNb2R1bGUgfSBmcm9tICdwcmltZW5nL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBSZWdpb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFByZXNldFNldCwgZGVmYXVsdFByZXNldFNldCB9IGZyb20gJy4uLy4uL21vZGVscy9jbGFzcy1wcmVzZXQnO1xuaW1wb3J0IHsgY29sb3JGb3JMYWJlbCB9IGZyb20gJy4uLy4uL3N0b3JlL2NsYXNzLWNvbG9yLnV0aWwnO1xuaW1wb3J0IHsgUGl4ZWxTaXplLCBmb3JtYXRBcmVhLCByZWdpb25BcmVhUHggfSBmcm9tICcuLi9yZWdpb24tbWV0cmljcyc7XG5cbi8qKiBBIHBhZ2UgY2hhbmdlIGZyb20gdGhlIHBhZ2luYXRvci4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVnaW9uUGFnZSB7XG4gIGZpcnN0OiBudW1iZXI7XG4gIHJvd3M6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgUmVnaW9uIEVkaXRvcidzIHJlZ2lvbnMgdGFibGUgYW5kIHBhZ2luYXRvcjogb25lIHBhZ2Ugb2Ygcm93cyB3aXRoIGFcbiAqIGNsYXNzIGRyb3Bkb3duIChvciBhbiBpbmxpbmUgbGFiZWwgZWRpdG9yKSwgdGhlIGFyZWEsIGFuZCBhIGRlbGV0ZSBidXR0b24uXG4gKiBQcmVzZW50YXRpb25hbCBhbmQgT25QdXNoOiB0aGUgZWRpdG9yIG93bnMgdGhlIHJvd3MsIHRoZSBzZWxlY3Rpb24sIHRoZVxuICogcGFnaW5nIGFuZCB0aGUgbGFiZWwgZHJhZnRzLCBhbmQgYXBwbGllcyBldmVyeSBlZGl0IHRocm91Z2ggaXRzIG9uZVxuICogY29weS1vbi13cml0ZSBjb21taXQgcGF0aCDigJQgdGhlIHRhYmxlIG5ldmVyIGNoYW5nZXMgYSB7QGxpbmsgUmVnaW9ufS5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAncmVnaW9uLXRhYmxlJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIENvbW1vbk1vZHVsZSxcbiAgICBGb3Jtc01vZHVsZSxcbiAgICBTaGFyZWRNb2R1bGUsXG4gICAgQnV0dG9uTW9kdWxlLFxuICAgIERyb3Bkb3duTW9kdWxlLFxuICAgIElucHV0VGV4dE1vZHVsZSxcbiAgICBQYWdpbmF0b3JNb2R1bGUsXG4gICAgUmlwcGxlTW9kdWxlLFxuICAgIFRhYmxlTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9yZWdpb24tdGFibGUuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9yZWdpb24tdGFibGUuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFJlZ2lvblRhYmxlQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLyoqIFRoZSByb3dzIG9uIHRoZSBjdXJyZW50IHBhZ2UuICovXG4gIEBJbnB1dCgpIHBhZ2U6IFJlZ2lvbltdID0gW107XG4gIC8qKiBUb3RhbCBudW1iZXIgb2Ygcm93cyAoYWxsIHBhZ2VzKS4gKi9cbiAgQElucHV0KCkgdG90YWwgPSAwO1xuICAvKiogSW5kZXggb2YgdGhlIHBhZ2UncyBmaXJzdCByb3cgYWNyb3NzIGFsbCBwYWdlcy4gKi9cbiAgQElucHV0KCkgZmlyc3QgPSAwO1xuICAvKiogUm93cyBwZXIgcGFnZS4gKi9cbiAgQElucHV0KCkgcm93cyA9IDEwO1xuICAvKiogVGhlIHBhZ2luYXRvcidzIHJvd3MtcGVyLXBhZ2UgY2hvaWNlcy4gKi9cbiAgQElucHV0KCkgcm93c1BlclBhZ2VPcHRpb25zID0gWzEwLCAyNSwgNTBdO1xuICAvKiogQ3RybC9DbWQtY2xpY2sgdG9nZ2xlcyBhIHJvdyAoUHJpbWVORyBtZXRhS2V5U2VsZWN0aW9uKS4gKi9cbiAgQElucHV0KCkgbWV0YUtleSA9IHRydWU7XG5cbiAgLyoqIFRoZSBzZWxlY3RlZCByb3dzLiAqL1xuICBASW5wdXQoKSBzZWxlY3Rpb246IFJlZ2lvbltdID0gW107XG4gIC8qKiBUaGUgdGFibGUncyBzZWxlY3Rpb24gY2hhbmdlZCAoYW55IHJvdyBjbGljaykuICovXG4gIEBPdXRwdXQoKSBzZWxlY3Rpb25DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPFJlZ2lvbltdPigpO1xuICAvKiogQSByb3cgd2FzIHNlbGVjdGVkIG9yIHVuc2VsZWN0ZWQgKGFmdGVyIHtAbGluayBzZWxlY3Rpb25DaGFuZ2V9KS4gKi9cbiAgQE91dHB1dCgpIHJvd1NlbGVjdCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICAvKiogQ2xhc3NlcyBmb3IgdGhlIHBlci1yb3cgZHJvcGRvd24sIGFuZCB0aGVpciBjb2xvdXJzLiAqL1xuICBASW5wdXQoKSBwcmVzZXRTZXQ6IFByZXNldFNldCA9IGRlZmF1bHRQcmVzZXRTZXQoKTtcbiAgLyoqIFN3YXRjaCBjb2xvdXIgb2YgYW4gdW5sYWJlbGxlZCByb3cuICovXG4gIEBJbnB1dCgpIGRlZmF1bHRDb2xvciA9ICcjMDBGRkZGJztcbiAgLyoqIFBpeGVsIHNpemUgZm9yIHRoZSBhcmVhIGNvbHVtbi4gKi9cbiAgQElucHV0KCkgbXBwOiBQaXhlbFNpemUgPSB7fTtcblxuICAvKiogUm93cyB3aG9zZSBsYWJlbCBpcyBiZWluZyBlZGl0ZWQg4oaSIHRoZSB0eXBlZCBkcmFmdC4gQSBuZXcgbWFwIHBlciBzdGFydC9zdG9wLiAqL1xuICBASW5wdXQoKSBsYWJlbERyYWZ0cyA9IG5ldyBNYXA8UmVnaW9uLCBzdHJpbmc+KCk7XG4gIC8qKiBBIHJvdydzIHBlbmNpbDogc3RhcnQgZWRpdGluZyBpdHMgbGFiZWwuICovXG4gIEBPdXRwdXQoKSBsYWJlbEVkaXRTdGFydCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVnaW9uPigpO1xuICAvKiogVGhlIGlubGluZSBsYWJlbCBlZGl0b3IncyB0ZXh0IGNoYW5nZWQuICovXG4gIEBPdXRwdXQoKSBsYWJlbERyYWZ0Q2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjx7IHJlZ2lvbjogUmVnaW9uOyB2YWx1ZTogc3RyaW5nIH0+KCk7XG4gIC8qKiBUaGUgaW5saW5lIGxhYmVsIGVkaXRvciBjbG9zZWQ6IEVudGVyIGNvbW1pdHMsIEVzY2FwZSAvIGNsb3NlIGNhbmNlbHMuICovXG4gIEBPdXRwdXQoKSBsYWJlbEVkaXRTdG9wID0gbmV3IEV2ZW50RW1pdHRlcjx7IHJlZ2lvbjogUmVnaW9uOyBjb21taXQ6IGJvb2xlYW4gfT4oKTtcblxuICAvKiogQSBjbGFzcyB3YXMgcGlja2VkIGluIGEgcm93J3MgZHJvcGRvd24uICovXG4gIEBPdXRwdXQoKSBjbGFzc1BpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPHsgcmVnaW9uOiBSZWdpb247IG5hbWU6IHN0cmluZyB9PigpO1xuICAvKiogQSByb3cncyB0cmFzaCBidXR0b246IHRoZSByb3cncyBpbmRleCBhY3Jvc3MgYWxsIHBhZ2VzLiAqL1xuICBAT3V0cHV0KCkgZGVsZXRlUm93ID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG4gIC8qKiBUaGUgcGFnaW5hdG9yIG1vdmVkIG9yIGNoYW5nZWQgaXRzIHBhZ2Ugc2l6ZS4gKi9cbiAgQE91dHB1dCgpIHBhZ2VDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPFJlZ2lvblBhZ2U+KCk7XG5cbiAgLyoqIFBlciByb3cgb2Yge0BsaW5rIHBhZ2V9OiBpdHMgY2xhc3Mgc3dhdGNoIGNvbG91ciBhbmQgZm9ybWF0dGVkIGFyZWEsIGRlcml2ZWQgd2hlblxuICAgKiAgYW4gaW5wdXQgY2hhbmdlcyBpbnN0ZWFkIG9mIHBlciBjaGVjayAodGhlIGFyZWEgd2Fsa3MgdGhlIHJlZ2lvbidzIGdlb21ldHJ5KS4gKi9cbiAgcHJvdGVjdGVkIHJvd1ZpZXcgPSBuZXcgTWFwPFJlZ2lvbiwgeyBjb2xvcjogc3RyaW5nOyBhcmVhOiBzdHJpbmcgfT4oKTtcblxuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLnJvd1ZpZXcgPSBuZXcgTWFwKHRoaXMucGFnZS5tYXAoKHIpID0+IFtyLCB7IGNvbG9yOiB0aGlzLmNsYXNzQ29sb3Ioci5sYWJlbCksIGFyZWE6IHRoaXMuYXJlYShyKSB9XSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBjbGFzc0NvbG9yKG5hbWU/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBuYW1lID8gY29sb3JGb3JMYWJlbChuYW1lLCB0aGlzLnByZXNldFNldCkgOiB0aGlzLmRlZmF1bHRDb2xvcjtcbiAgfVxuXG4gIHByaXZhdGUgYXJlYShyZWdpb246IFJlZ2lvbik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGZvcm1hdEFyZWEocmVnaW9uQXJlYVB4KHJlZ2lvbiksIHRoaXMubXBwKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGFydEVkaXQocmVnaW9uOiBSZWdpb24sIGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpOyAvLyBkb24ndCB0b2dnbGUgcm93IHNlbGVjdGlvblxuICAgIHRoaXMubGFiZWxFZGl0U3RhcnQuZW1pdChyZWdpb24pO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0b3BFZGl0KHJlZ2lvbjogUmVnaW9uLCBjb21taXQ6IGJvb2xlYW4sIGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHRoaXMubGFiZWxFZGl0U3RvcC5lbWl0KHsgcmVnaW9uLCBjb21taXQgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25QYWdlKGV2ZW50OiB7IGZpcnN0PzogbnVtYmVyOyByb3dzPzogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICB0aGlzLnBhZ2VDaGFuZ2UuZW1pdCh7IGZpcnN0OiBldmVudC5maXJzdCA/PyAwLCByb3dzOiBldmVudC5yb3dzID8/IHRoaXMucm93cyB9KTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInJlZ2lvbi1lZGl0b3ItY29udGVudFwiPlxuICA8cC10YWJsZVxuICAgIFt2YWx1ZV09XCJwYWdlXCJcbiAgICBbdGFibGVTdHlsZV09XCJ7IHdpZHRoOiAnMTAwJScgfVwiXG4gICAgW3NlbGVjdGlvbl09XCJzZWxlY3Rpb25cIlxuICAgIChzZWxlY3Rpb25DaGFuZ2UpPVwic2VsZWN0aW9uQ2hhbmdlLmVtaXQoJGV2ZW50KVwiXG4gICAgc2VsZWN0aW9uTW9kZT1cIm11bHRpcGxlXCJcbiAgICBbbWV0YUtleVNlbGVjdGlvbl09XCJtZXRhS2V5XCJcbiAgICAob25Sb3dTZWxlY3QpPVwicm93U2VsZWN0LmVtaXQoKVwiXG4gICAgKG9uUm93VW5zZWxlY3QpPVwicm93U2VsZWN0LmVtaXQoKVwiXG4gICAgW3Jlc2l6YWJsZUNvbHVtbnNdPVwidHJ1ZVwiXG4gICAgW3Jvd0hvdmVyXT1cInRydWVcIlxuICAgIGRhdGFLZXk9XCJpZFwiXG4gICAgc3R5bGVDbGFzcz1cInAtZGF0YXRhYmxlLXNtIHJlZ2lvbi1lZGl0b3ItdGFibGVcIlxuICAgIFtzY3JvbGxhYmxlXT1cInRydWVcIlxuICAgIHNjcm9sbEhlaWdodD1cIjEwMCVcIlxuICA+XG4gICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImhlYWRlclwiPlxuICAgICAgPCEtLSBIaWRlIHRoZSBjb2x1bW4gaGVhZGVyIHdoZW4gdGhlcmUgYXJlIG5vIHJlZ2lvbnMgdG8gc2hvdy4gLS0+XG4gICAgICA8dHIgKm5nSWY9XCJ0b3RhbCA+IDBcIj5cbiAgICAgICAgPCEtLSBDbGFzcyBjb2x1bW46IHNocmlua3MgdG8gZml0IFwiUmVnaW9uXCIgYnkgZGVmYXVsdCwgZ3Jvd3Mgd2l0aCBsb25nZXIgbGFiZWxzLiAtLT5cbiAgICAgICAgPHRoIGNsYXNzPVwiY2xhc3MtY29sLWhlYWRlclwiIHBSZXNpemFibGVDb2x1bW4+Q2xhc3MgPHAtc29ydEljb24gZmllbGQ9XCJsYWJlbFwiPjwvcC1zb3J0SWNvbj48L3RoPlxuICAgICAgICA8dGggY2xhc3M9XCJzdXJmYWNlLWNvbC1oZWFkZXJcIiBwUmVzaXphYmxlQ29sdW1uPlN1cmZhY2U8L3RoPlxuICAgICAgICA8IS0tIFRyYXNoIGNvbHVtbjoganVzdCBlbm91Z2ggZm9yIHRoZSBpY29uLiAtLT5cbiAgICAgICAgPHRoIHN0eWxlPVwid2lkdGg6IDJyZW1cIj48L3RoPlxuICAgICAgPC90cj5cbiAgICA8L25nLXRlbXBsYXRlPlxuICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJib2R5XCIgbGV0LXJlZ2lvbiBsZXQtcm93SWR4PVwicm93SW5kZXhcIj5cbiAgICAgIDx0ciBbcFNlbGVjdGFibGVSb3ddPVwicmVnaW9uXCIgW3BTZWxlY3RhYmxlUm93SW5kZXhdPVwicm93SWR4XCI+XG4gICAgICAgIDx0ZCBjbGFzcz1cImNsYXNzLWNlbGxcIj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWxhYmVsRHJhZnRzLmhhcyhyZWdpb24pOyBlbHNlIGVkaXRMYWJlbFRwbFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjbGFzcy1jZWxsLWRpc3BsYXlcIj5cbiAgICAgICAgICAgICAgPCEtLSBRdWljay1waWNrIGEgcHJlc2V0IGNsYXNzIChpdHMgY29sb3VyIGZvbGxvd3MpOyB0aGUgcGVuY2lsIGlzIGZvclxuICAgICAgICAgICAgICAgICAgICAgYSBmcmVlLWZvcm0gbmFtZSAvIHJlbmFtZSAoaml0LXVpIzcwKS4gLS0+XG4gICAgICAgICAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjbGFzcy1kcm9wZG93blwiXG4gICAgICAgICAgICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgICAgICAgICBbb3B0aW9uc109XCJwcmVzZXRTZXQuY2xhc3Nlc1wiXG4gICAgICAgICAgICAgICAgb3B0aW9uTGFiZWw9XCJuYW1lXCJcbiAgICAgICAgICAgICAgICBvcHRpb25WYWx1ZT1cIm5hbWVcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJlZ2lvbi5sYWJlbFwiXG4gICAgICAgICAgICAgICAgW2F1dG9EaXNwbGF5Rmlyc3RdPVwiZmFsc2VcIlxuICAgICAgICAgICAgICAgIGFyaWFMYWJlbD1cIkNsYXNzXCJcbiAgICAgICAgICAgICAgICAob25DaGFuZ2UpPVwiY2xhc3NQaWNrLmVtaXQoeyByZWdpb246IHJlZ2lvbiwgbmFtZTogJGV2ZW50LnZhbHVlIH0pXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJzZWxlY3RlZEl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZGQtdmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjaGlwLXN3YXRjaFwiIFtzdHlsZS5iYWNrZ3JvdW5kXT1cInJvd1ZpZXcuZ2V0KHJlZ2lvbik/LmNvbG9yXCI+PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNsYXNzLW5hbWVcIiBbcFRvb2x0aXBdPVwicmVnaW9uLmxhYmVsXCIgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCI+e3tcbiAgICAgICAgICAgICAgICAgICAgICByZWdpb24ubGFiZWwgfHwgJ+KAlCdcbiAgICAgICAgICAgICAgICAgICAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgbGV0LWMgcFRlbXBsYXRlPVwiaXRlbVwiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJkZC12YWx1ZVwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNoaXAtc3dhdGNoXCIgW3N0eWxlLmJhY2tncm91bmRdPVwiYy5jb2xvclwiPjwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgYy5uYW1lIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICAgIDwvcC1kcm9wZG93bj5cbiAgICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgICBjbGFzcz1cInBpIHBpLXBlbmNpbCBpY29uLWhvdmVyIG1sLTJcIlxuICAgICAgICAgICAgICAgIHBUb29sdGlwPVwiUmVuYW1lIC8gZnJlZS1mb3JtIGxhYmVsXCJcbiAgICAgICAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJib3R0b21cIlxuICAgICAgICAgICAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgIGFyaWEtbGFiZWw9XCJSZW5hbWVcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJzdGFydEVkaXQocmVnaW9uLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI2VkaXRMYWJlbFRwbD5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicC1pbnB1dC1pY29uLXJpZ2h0IGNsYXNzLWNlbGwtZWRpdFwiPlxuICAgICAgICAgICAgICA8aVxuICAgICAgICAgICAgICAgIGNsYXNzPVwicGkgcGktdGltZXMgaWNvbi1ob3ZlclwiXG4gICAgICAgICAgICAgICAgcFRvb2x0aXA9XCJDbG9zZVwiXG4gICAgICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAgICAgICAgICAgICByb2xlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBhcmlhLWxhYmVsPVwiQ2FuY2VsIHJlbmFtZVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInN0b3BFZGl0KHJlZ2lvbiwgZmFsc2UsICRldmVudClcIlxuICAgICAgICAgICAgICA+PC9pPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgcElucHV0VGV4dFxuICAgICAgICAgICAgICAgIGNsYXNzPVwicC1pbnB1dHRleHQtc20gdy1mdWxsXCJcbiAgICAgICAgICAgICAgICBhcmlhLWxhYmVsPVwiQ2xhc3MgbGFiZWxcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImxhYmVsRHJhZnRzLmdldChyZWdpb24pXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJsYWJlbERyYWZ0Q2hhbmdlLmVtaXQoeyByZWdpb246IHJlZ2lvbiwgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwic3RvcEVkaXQocmVnaW9uLCB0cnVlLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAoa2V5ZG93bi5lc2NhcGUpPVwic3RvcEVkaXQocmVnaW9uLCBmYWxzZSwgJGV2ZW50KVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC90ZD5cbiAgICAgICAgPCEtLSBTdXJmYWNlIGFyZWEgKMK1bcKyL21twrIgd2hlbiB0aGUgaW1hZ2UgaXMgc2NhbGVkLCBlbHNlIHB4wrIpLiAtLT5cbiAgICAgICAgPHRkIGNsYXNzPVwic3VyZmFjZS1jZWxsXCI+e3sgcm93Vmlldy5nZXQocmVnaW9uKT8uYXJlYSB8fCAn4oCUJyB9fTwvdGQ+XG4gICAgICAgIDx0ZD5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBwQnV0dG9uXG4gICAgICAgICAgICBwUmlwcGxlXG4gICAgICAgICAgICBpY29uPVwicGkgcGktdHJhc2hcIlxuICAgICAgICAgICAgYXJpYS1sYWJlbD1cIkRlbGV0ZSByZWdpb25cIlxuICAgICAgICAgICAgY2xhc3M9XCJwLWJ1dHRvbi1zbSBwLWJ1dHRvbi1yb3VuZGVkIHAtYnV0dG9uLXRleHQgcC1idXR0b24td2FybmluZ1wiXG4gICAgICAgICAgICAoY2xpY2spPVwiZGVsZXRlUm93LmVtaXQoZmlyc3QgKyByb3dJZHgpXCJcbiAgICAgICAgICA+PC9idXR0b24+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L3RyPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcC10YWJsZT5cbjwvZGl2PlxuXG48cC1wYWdpbmF0b3JcbiAgKm5nSWY9XCJ0b3RhbCA+IDBcIlxuICBbcm93c109XCJyb3dzXCJcbiAgW3RvdGFsUmVjb3Jkc109XCJ0b3RhbFwiXG4gIFtmaXJzdF09XCJmaXJzdFwiXG4gIFtyb3dzUGVyUGFnZU9wdGlvbnNdPVwicm93c1BlclBhZ2VPcHRpb25zXCJcbiAgW3Nob3dDdXJyZW50UGFnZVJlcG9ydF09XCJ0cnVlXCJcbiAgY3VycmVudFBhZ2VSZXBvcnRUZW1wbGF0ZT1cIntmaXJzdH0gdG8ge2xhc3R9IG9mIHt0b3RhbFJlY29yZHN9XCJcbiAgKG9uUGFnZUNoYW5nZSk9XCJvblBhZ2UoJGV2ZW50KVwiXG4gIHN0eWxlQ2xhc3M9XCJyZWdpb24tZWRpdG9yLXBhZ2luYXRvclwiXG4+XG48L3AtcGFnaW5hdG9yPlxuIl19
@@ -0,0 +1,91 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { SharedModule } from 'primeng/api';
5
+ import { ButtonModule } from 'primeng/button';
6
+ import { DialogModule } from 'primeng/dialog';
7
+ import { InputTextModule } from 'primeng/inputtext';
8
+ import { ProgressBarModule } from 'primeng/progressbar';
9
+ import { RadioButtonModule } from 'primeng/radiobutton';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "@angular/common";
12
+ import * as i2 from "@angular/forms";
13
+ import * as i3 from "primeng/api";
14
+ import * as i4 from "primeng/button";
15
+ import * as i5 from "primeng/dialog";
16
+ import * as i6 from "primeng/inputtext";
17
+ import * as i7 from "primeng/progressbar";
18
+ import * as i8 from "primeng/radiobutton";
19
+ /**
20
+ * The Region Editor's "Save mask" dialog: filename + mask type while idle, a
21
+ * progress bar (rasterize, then encode) with a Cancel button while the export
22
+ * runs. Presentational — the editor owns the state and the export
23
+ * ({@link MaskExportService}); the dialog only reports edits and clicks.
24
+ */
25
+ export class SaveMaskDialogComponent {
26
+ constructor() {
27
+ /** The dialog is open. */
28
+ this.visible = false;
29
+ /** The dialog was closed (`false`); two-way with {@link visible}. */
30
+ this.visibleChange = new EventEmitter();
31
+ /** The PNG filename. */
32
+ this.filename = '';
33
+ /** The filename was edited; two-way with {@link filename}. */
34
+ this.filenameChange = new EventEmitter();
35
+ /** The mask type: binary, or one label value per class. */
36
+ this.mode = 'binary';
37
+ /** The mask type was changed; two-way with {@link mode}. */
38
+ this.modeChange = new EventEmitter();
39
+ /** True while the export runs (the form is replaced by progress). */
40
+ this.busy = false;
41
+ /** 0–100 rasterization progress. */
42
+ this.progress = 0;
43
+ /** True once rasterizing is done and the PNG is being encoded. */
44
+ this.encoding = false;
45
+ /** Download clicked with a non-blank filename. */
46
+ this.confirm = new EventEmitter();
47
+ /** Cancel clicked while the export runs. */
48
+ this.cancelExport = new EventEmitter();
49
+ }
50
+ close() {
51
+ this.visibleChange.emit(false);
52
+ }
53
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SaveMaskDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
54
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SaveMaskDialogComponent, isStandalone: true, selector: "region-save-mask-dialog", inputs: { visible: "visible", filename: "filename", mode: "mode", busy: "busy", progress: "progress", encoding: "encoding" }, outputs: { visibleChange: "visibleChange", filenameChange: "filenameChange", modeChange: "modeChange", confirm: "confirm", cancelExport: "cancelExport" }, ngImport: i0, template: "<p-dialog\n header=\"Save Mask\"\n [visible]=\"visible\"\n (visibleChange)=\"visibleChange.emit($event)\"\n [modal]=\"true\"\n appendTo=\"body\"\n [style]=\"{ width: '30rem' }\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [closable]=\"!busy\"\n [closeOnEscape]=\"!busy\"\n>\n <!-- Idle: filename + mask-type form. -->\n <div *ngIf=\"!busy\" class=\"flex flex-column gap-3 pt-2\">\n <label for=\"mask-filename\" class=\"font-medium\">Mask filename</label>\n <input\n id=\"mask-filename\"\n type=\"text\"\n pInputText\n [ngModel]=\"filename\"\n (ngModelChange)=\"filenameChange.emit($event)\"\n class=\"w-full\"\n />\n <span class=\"font-medium\">Mask type</span>\n <div class=\"flex align-items-center gap-2\">\n <p-radioButton\n inputId=\"mask-binary\"\n name=\"maskMode\"\n value=\"binary\"\n [ngModel]=\"mode\"\n (ngModelChange)=\"modeChange.emit($event)\"\n ></p-radioButton>\n <label for=\"mask-binary\">Binary <span class=\"text-color-secondary\">(regions 1, background 0)</span></label>\n </div>\n <div class=\"flex align-items-center gap-2\">\n <p-radioButton\n inputId=\"mask-multiclass\"\n name=\"maskMode\"\n value=\"multiclass\"\n [ngModel]=\"mode\"\n (ngModelChange)=\"modeChange.emit($event)\"\n ></p-radioButton>\n <label for=\"mask-multiclass\"\n >Multi-class <span class=\"text-color-secondary\">(unique id per region, background 0)</span></label\n >\n </div>\n </div>\n\n <!-- Busy: progress while the worker rasterizes + encodes the PNG. -->\n <div *ngIf=\"busy\" class=\"flex flex-column gap-3 pt-2\">\n <span>{{ encoding ? 'Encoding PNG\u2026' : 'Rasterizing regions\u2026' }}</span>\n <p-progressBar\n [mode]=\"encoding ? 'indeterminate' : 'determinate'\"\n [value]=\"progress\"\n [style]=\"{ height: '0.75rem' }\"\n ></p-progressBar>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <p-button *ngIf=\"!busy\" label=\"Cancel\" icon=\"pi pi-times\" [text]=\"true\" (onClick)=\"close()\"></p-button>\n <p-button\n *ngIf=\"!busy\"\n label=\"Download\"\n icon=\"pi pi-download\"\n [disabled]=\"!filename || !filename.trim()\"\n (onClick)=\"confirm.emit()\"\n ></p-button>\n <p-button\n *ngIf=\"busy\"\n label=\"Cancel\"\n icon=\"pi pi-times\"\n [text]=\"true\"\n (onClick)=\"cancelExport.emit()\"\n ></p-button>\n </ng-template>\n</p-dialog>\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.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: SharedModule }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.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: DialogModule }, { kind: "component", type: i5.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "visible", "style", "position"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i6.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i7.ProgressBar, selector: "p-progressBar", inputs: ["value", "showValue", "styleClass", "style", "unit", "mode", "color"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i8.RadioButton, selector: "p-radioButton", inputs: ["value", "formControlName", "name", "disabled", "label", "variant", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "labelStyleClass", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
55
+ }
56
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SaveMaskDialogComponent, decorators: [{
57
+ type: Component,
58
+ args: [{ selector: 'region-save-mask-dialog', standalone: true, imports: [
59
+ CommonModule,
60
+ FormsModule,
61
+ SharedModule,
62
+ ButtonModule,
63
+ DialogModule,
64
+ InputTextModule,
65
+ ProgressBarModule,
66
+ RadioButtonModule,
67
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-dialog\n header=\"Save Mask\"\n [visible]=\"visible\"\n (visibleChange)=\"visibleChange.emit($event)\"\n [modal]=\"true\"\n appendTo=\"body\"\n [style]=\"{ width: '30rem' }\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [closable]=\"!busy\"\n [closeOnEscape]=\"!busy\"\n>\n <!-- Idle: filename + mask-type form. -->\n <div *ngIf=\"!busy\" class=\"flex flex-column gap-3 pt-2\">\n <label for=\"mask-filename\" class=\"font-medium\">Mask filename</label>\n <input\n id=\"mask-filename\"\n type=\"text\"\n pInputText\n [ngModel]=\"filename\"\n (ngModelChange)=\"filenameChange.emit($event)\"\n class=\"w-full\"\n />\n <span class=\"font-medium\">Mask type</span>\n <div class=\"flex align-items-center gap-2\">\n <p-radioButton\n inputId=\"mask-binary\"\n name=\"maskMode\"\n value=\"binary\"\n [ngModel]=\"mode\"\n (ngModelChange)=\"modeChange.emit($event)\"\n ></p-radioButton>\n <label for=\"mask-binary\">Binary <span class=\"text-color-secondary\">(regions 1, background 0)</span></label>\n </div>\n <div class=\"flex align-items-center gap-2\">\n <p-radioButton\n inputId=\"mask-multiclass\"\n name=\"maskMode\"\n value=\"multiclass\"\n [ngModel]=\"mode\"\n (ngModelChange)=\"modeChange.emit($event)\"\n ></p-radioButton>\n <label for=\"mask-multiclass\"\n >Multi-class <span class=\"text-color-secondary\">(unique id per region, background 0)</span></label\n >\n </div>\n </div>\n\n <!-- Busy: progress while the worker rasterizes + encodes the PNG. -->\n <div *ngIf=\"busy\" class=\"flex flex-column gap-3 pt-2\">\n <span>{{ encoding ? 'Encoding PNG\u2026' : 'Rasterizing regions\u2026' }}</span>\n <p-progressBar\n [mode]=\"encoding ? 'indeterminate' : 'determinate'\"\n [value]=\"progress\"\n [style]=\"{ height: '0.75rem' }\"\n ></p-progressBar>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <p-button *ngIf=\"!busy\" label=\"Cancel\" icon=\"pi pi-times\" [text]=\"true\" (onClick)=\"close()\"></p-button>\n <p-button\n *ngIf=\"!busy\"\n label=\"Download\"\n icon=\"pi pi-download\"\n [disabled]=\"!filename || !filename.trim()\"\n (onClick)=\"confirm.emit()\"\n ></p-button>\n <p-button\n *ngIf=\"busy\"\n label=\"Cancel\"\n icon=\"pi pi-times\"\n [text]=\"true\"\n (onClick)=\"cancelExport.emit()\"\n ></p-button>\n </ng-template>\n</p-dialog>\n" }]
68
+ }], propDecorators: { visible: [{
69
+ type: Input
70
+ }], visibleChange: [{
71
+ type: Output
72
+ }], filename: [{
73
+ type: Input
74
+ }], filenameChange: [{
75
+ type: Output
76
+ }], mode: [{
77
+ type: Input
78
+ }], modeChange: [{
79
+ type: Output
80
+ }], busy: [{
81
+ type: Input
82
+ }], progress: [{
83
+ type: Input
84
+ }], encoding: [{
85
+ type: Input
86
+ }], confirm: [{
87
+ type: Output
88
+ }], cancelExport: [{
89
+ type: Output
90
+ }] } });
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS1tYXNrLWRpYWxvZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3JlZ2lvbi1lZGl0b3Ivc2F2ZS1tYXNrLWRpYWxvZy9zYXZlLW1hc2stZGlhbG9nLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWVkaXRvci9zYXZlLW1hc2stZGlhbG9nL3NhdmUtbWFzay1kaWFsb2cuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7Ozs7Ozs7Ozs7QUFJeEQ7Ozs7O0dBS0c7QUFpQkgsTUFBTSxPQUFPLHVCQUF1QjtJQWhCcEM7UUFpQkUsMEJBQTBCO1FBQ2pCLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFDekIscUVBQXFFO1FBQzNELGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQVcsQ0FBQztRQUV0RCx3QkFBd0I7UUFDZixhQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLDhEQUE4RDtRQUNwRCxtQkFBYyxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFFdEQsMkRBQTJEO1FBQ2xELFNBQUksR0FBYSxRQUFRLENBQUM7UUFDbkMsNERBQTREO1FBQ2xELGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBWSxDQUFDO1FBRXBELHFFQUFxRTtRQUM1RCxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLG9DQUFvQztRQUMzQixhQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ3RCLGtFQUFrRTtRQUN6RCxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBRTFCLGtEQUFrRDtRQUN4QyxZQUFPLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUM3Qyw0Q0FBNEM7UUFDbEMsaUJBQVksR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0tBS25EO0lBSFcsS0FBSztRQUNiLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7OEdBOUJVLHVCQUF1QjtrR0FBdkIsdUJBQXVCLDRXQ2xDcEMsOCtFQTRFQSwyQ0R0REksWUFBWSxrSUFDWixXQUFXLDhtQkFDWCxZQUFZLHFJQUNaLFlBQVksNlhBQ1osWUFBWSx1dUJBQ1osZUFBZSx3SEFDZixpQkFBaUIsc0xBQ2pCLGlCQUFpQjs7MkZBS1IsdUJBQXVCO2tCQWhCbkMsU0FBUzsrQkFDRSx5QkFBeUIsY0FDdkIsSUFBSSxXQUNQO3dCQUNQLFlBQVk7d0JBQ1osV0FBVzt3QkFDWCxZQUFZO3dCQUNaLFlBQVk7d0JBQ1osWUFBWTt3QkFDWixlQUFlO3dCQUNmLGlCQUFpQjt3QkFDakIsaUJBQWlCO3FCQUNsQixtQkFFZ0IsdUJBQXVCLENBQUMsTUFBTTs4QkFJdEMsT0FBTztzQkFBZixLQUFLO2dCQUVJLGFBQWE7c0JBQXRCLE1BQU07Z0JBR0UsUUFBUTtzQkFBaEIsS0FBSztnQkFFSSxjQUFjO3NCQUF2QixNQUFNO2dCQUdFLElBQUk7c0JBQVosS0FBSztnQkFFSSxVQUFVO3NCQUFuQixNQUFNO2dCQUdFLElBQUk7c0JBQVosS0FBSztnQkFFRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBR0ksT0FBTztzQkFBaEIsTUFBTTtnQkFFRyxZQUFZO3NCQUFyQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTaGFyZWRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2FwaSc7XG5pbXBvcnQgeyBCdXR0b25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2J1dHRvbic7XG5pbXBvcnQgeyBEaWFsb2dNb2R1bGUgfSBmcm9tICdwcmltZW5nL2RpYWxvZyc7XG5pbXBvcnQgeyBJbnB1dFRleHRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2lucHV0dGV4dCc7XG5pbXBvcnQgeyBQcm9ncmVzc0Jhck1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvcHJvZ3Jlc3NiYXInO1xuaW1wb3J0IHsgUmFkaW9CdXR0b25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL3JhZGlvYnV0dG9uJztcblxuaW1wb3J0IHsgTWFza01vZGUgfSBmcm9tICcuLi9tYXNrLWV4cG9ydC5zZXJ2aWNlJztcblxuLyoqXG4gKiBUaGUgUmVnaW9uIEVkaXRvcidzIFwiU2F2ZSBtYXNrXCIgZGlhbG9nOiBmaWxlbmFtZSArIG1hc2sgdHlwZSB3aGlsZSBpZGxlLCBhXG4gKiBwcm9ncmVzcyBiYXIgKHJhc3Rlcml6ZSwgdGhlbiBlbmNvZGUpIHdpdGggYSBDYW5jZWwgYnV0dG9uIHdoaWxlIHRoZSBleHBvcnRcbiAqIHJ1bnMuIFByZXNlbnRhdGlvbmFsIOKAlCB0aGUgZWRpdG9yIG93bnMgdGhlIHN0YXRlIGFuZCB0aGUgZXhwb3J0XG4gKiAoe0BsaW5rIE1hc2tFeHBvcnRTZXJ2aWNlfSk7IHRoZSBkaWFsb2cgb25seSByZXBvcnRzIGVkaXRzIGFuZCBjbGlja3MuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3JlZ2lvbi1zYXZlLW1hc2stZGlhbG9nJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIENvbW1vbk1vZHVsZSxcbiAgICBGb3Jtc01vZHVsZSxcbiAgICBTaGFyZWRNb2R1bGUsXG4gICAgQnV0dG9uTW9kdWxlLFxuICAgIERpYWxvZ01vZHVsZSxcbiAgICBJbnB1dFRleHRNb2R1bGUsXG4gICAgUHJvZ3Jlc3NCYXJNb2R1bGUsXG4gICAgUmFkaW9CdXR0b25Nb2R1bGUsXG4gIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9zYXZlLW1hc2stZGlhbG9nLmNvbXBvbmVudC5odG1sJyxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNhdmVNYXNrRGlhbG9nQ29tcG9uZW50IHtcbiAgLyoqIFRoZSBkaWFsb2cgaXMgb3Blbi4gKi9cbiAgQElucHV0KCkgdmlzaWJsZSA9IGZhbHNlO1xuICAvKiogVGhlIGRpYWxvZyB3YXMgY2xvc2VkIChgZmFsc2VgKTsgdHdvLXdheSB3aXRoIHtAbGluayB2aXNpYmxlfS4gKi9cbiAgQE91dHB1dCgpIHZpc2libGVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgLyoqIFRoZSBQTkcgZmlsZW5hbWUuICovXG4gIEBJbnB1dCgpIGZpbGVuYW1lID0gJyc7XG4gIC8qKiBUaGUgZmlsZW5hbWUgd2FzIGVkaXRlZDsgdHdvLXdheSB3aXRoIHtAbGluayBmaWxlbmFtZX0uICovXG4gIEBPdXRwdXQoKSBmaWxlbmFtZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIC8qKiBUaGUgbWFzayB0eXBlOiBiaW5hcnksIG9yIG9uZSBsYWJlbCB2YWx1ZSBwZXIgY2xhc3MuICovXG4gIEBJbnB1dCgpIG1vZGU6IE1hc2tNb2RlID0gJ2JpbmFyeSc7XG4gIC8qKiBUaGUgbWFzayB0eXBlIHdhcyBjaGFuZ2VkOyB0d28td2F5IHdpdGgge0BsaW5rIG1vZGV9LiAqL1xuICBAT3V0cHV0KCkgbW9kZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8TWFza01vZGU+KCk7XG5cbiAgLyoqIFRydWUgd2hpbGUgdGhlIGV4cG9ydCBydW5zICh0aGUgZm9ybSBpcyByZXBsYWNlZCBieSBwcm9ncmVzcykuICovXG4gIEBJbnB1dCgpIGJ1c3kgPSBmYWxzZTtcbiAgLyoqIDDigJMxMDAgcmFzdGVyaXphdGlvbiBwcm9ncmVzcy4gKi9cbiAgQElucHV0KCkgcHJvZ3Jlc3MgPSAwO1xuICAvKiogVHJ1ZSBvbmNlIHJhc3Rlcml6aW5nIGlzIGRvbmUgYW5kIHRoZSBQTkcgaXMgYmVpbmcgZW5jb2RlZC4gKi9cbiAgQElucHV0KCkgZW5jb2RpbmcgPSBmYWxzZTtcblxuICAvKiogRG93bmxvYWQgY2xpY2tlZCB3aXRoIGEgbm9uLWJsYW5rIGZpbGVuYW1lLiAqL1xuICBAT3V0cHV0KCkgY29uZmlybSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIENhbmNlbCBjbGlja2VkIHdoaWxlIHRoZSBleHBvcnQgcnVucy4gKi9cbiAgQE91dHB1dCgpIGNhbmNlbEV4cG9ydCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBwcm90ZWN0ZWQgY2xvc2UoKTogdm9pZCB7XG4gICAgdGhpcy52aXNpYmxlQ2hhbmdlLmVtaXQoZmFsc2UpO1xuICB9XG59XG4iLCI8cC1kaWFsb2dcbiAgaGVhZGVyPVwiU2F2ZSBNYXNrXCJcbiAgW3Zpc2libGVdPVwidmlzaWJsZVwiXG4gICh2aXNpYmxlQ2hhbmdlKT1cInZpc2libGVDaGFuZ2UuZW1pdCgkZXZlbnQpXCJcbiAgW21vZGFsXT1cInRydWVcIlxuICBhcHBlbmRUbz1cImJvZHlcIlxuICBbc3R5bGVdPVwieyB3aWR0aDogJzMwcmVtJyB9XCJcbiAgW2RyYWdnYWJsZV09XCJmYWxzZVwiXG4gIFtyZXNpemFibGVdPVwiZmFsc2VcIlxuICBbY2xvc2FibGVdPVwiIWJ1c3lcIlxuICBbY2xvc2VPbkVzY2FwZV09XCIhYnVzeVwiXG4+XG4gIDwhLS0gSWRsZTogZmlsZW5hbWUgKyBtYXNrLXR5cGUgZm9ybS4gLS0+XG4gIDxkaXYgKm5nSWY9XCIhYnVzeVwiIGNsYXNzPVwiZmxleCBmbGV4LWNvbHVtbiBnYXAtMyBwdC0yXCI+XG4gICAgPGxhYmVsIGZvcj1cIm1hc2stZmlsZW5hbWVcIiBjbGFzcz1cImZvbnQtbWVkaXVtXCI+TWFzayBmaWxlbmFtZTwvbGFiZWw+XG4gICAgPGlucHV0XG4gICAgICBpZD1cIm1hc2stZmlsZW5hbWVcIlxuICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgcElucHV0VGV4dFxuICAgICAgW25nTW9kZWxdPVwiZmlsZW5hbWVcIlxuICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwiZmlsZW5hbWVDaGFuZ2UuZW1pdCgkZXZlbnQpXCJcbiAgICAgIGNsYXNzPVwidy1mdWxsXCJcbiAgICAvPlxuICAgIDxzcGFuIGNsYXNzPVwiZm9udC1tZWRpdW1cIj5NYXNrIHR5cGU8L3NwYW4+XG4gICAgPGRpdiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIGdhcC0yXCI+XG4gICAgICA8cC1yYWRpb0J1dHRvblxuICAgICAgICBpbnB1dElkPVwibWFzay1iaW5hcnlcIlxuICAgICAgICBuYW1lPVwibWFza01vZGVcIlxuICAgICAgICB2YWx1ZT1cImJpbmFyeVwiXG4gICAgICAgIFtuZ01vZGVsXT1cIm1vZGVcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJtb2RlQ2hhbmdlLmVtaXQoJGV2ZW50KVwiXG4gICAgICA+PC9wLXJhZGlvQnV0dG9uPlxuICAgICAgPGxhYmVsIGZvcj1cIm1hc2stYmluYXJ5XCI+QmluYXJ5IDxzcGFuIGNsYXNzPVwidGV4dC1jb2xvci1zZWNvbmRhcnlcIj4ocmVnaW9ucyAxLCBiYWNrZ3JvdW5kIDApPC9zcGFuPjwvbGFiZWw+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIGdhcC0yXCI+XG4gICAgICA8cC1yYWRpb0J1dHRvblxuICAgICAgICBpbnB1dElkPVwibWFzay1tdWx0aWNsYXNzXCJcbiAgICAgICAgbmFtZT1cIm1hc2tNb2RlXCJcbiAgICAgICAgdmFsdWU9XCJtdWx0aWNsYXNzXCJcbiAgICAgICAgW25nTW9kZWxdPVwibW9kZVwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm1vZGVDaGFuZ2UuZW1pdCgkZXZlbnQpXCJcbiAgICAgID48L3AtcmFkaW9CdXR0b24+XG4gICAgICA8bGFiZWwgZm9yPVwibWFzay1tdWx0aWNsYXNzXCJcbiAgICAgICAgPk11bHRpLWNsYXNzIDxzcGFuIGNsYXNzPVwidGV4dC1jb2xvci1zZWNvbmRhcnlcIj4odW5pcXVlIGlkIHBlciByZWdpb24sIGJhY2tncm91bmQgMCk8L3NwYW4+PC9sYWJlbFxuICAgICAgPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIEJ1c3k6IHByb2dyZXNzIHdoaWxlIHRoZSB3b3JrZXIgcmFzdGVyaXplcyArIGVuY29kZXMgdGhlIFBORy4gLS0+XG4gIDxkaXYgKm5nSWY9XCJidXN5XCIgY2xhc3M9XCJmbGV4IGZsZXgtY29sdW1uIGdhcC0zIHB0LTJcIj5cbiAgICA8c3Bhbj57eyBlbmNvZGluZyA/ICdFbmNvZGluZyBQTkfigKYnIDogJ1Jhc3Rlcml6aW5nIHJlZ2lvbnPigKYnIH19PC9zcGFuPlxuICAgIDxwLXByb2dyZXNzQmFyXG4gICAgICBbbW9kZV09XCJlbmNvZGluZyA/ICdpbmRldGVybWluYXRlJyA6ICdkZXRlcm1pbmF0ZSdcIlxuICAgICAgW3ZhbHVlXT1cInByb2dyZXNzXCJcbiAgICAgIFtzdHlsZV09XCJ7IGhlaWdodDogJzAuNzVyZW0nIH1cIlxuICAgID48L3AtcHJvZ3Jlc3NCYXI+XG4gIDwvZGl2PlxuXG4gIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJmb290ZXJcIj5cbiAgICA8cC1idXR0b24gKm5nSWY9XCIhYnVzeVwiIGxhYmVsPVwiQ2FuY2VsXCIgaWNvbj1cInBpIHBpLXRpbWVzXCIgW3RleHRdPVwidHJ1ZVwiIChvbkNsaWNrKT1cImNsb3NlKClcIj48L3AtYnV0dG9uPlxuICAgIDxwLWJ1dHRvblxuICAgICAgKm5nSWY9XCIhYnVzeVwiXG4gICAgICBsYWJlbD1cIkRvd25sb2FkXCJcbiAgICAgIGljb249XCJwaSBwaS1kb3dubG9hZFwiXG4gICAgICBbZGlzYWJsZWRdPVwiIWZpbGVuYW1lIHx8ICFmaWxlbmFtZS50cmltKClcIlxuICAgICAgKG9uQ2xpY2spPVwiY29uZmlybS5lbWl0KClcIlxuICAgID48L3AtYnV0dG9uPlxuICAgIDxwLWJ1dHRvblxuICAgICAgKm5nSWY9XCJidXN5XCJcbiAgICAgIGxhYmVsPVwiQ2FuY2VsXCJcbiAgICAgIGljb249XCJwaSBwaS10aW1lc1wiXG4gICAgICBbdGV4dF09XCJ0cnVlXCJcbiAgICAgIChvbkNsaWNrKT1cImNhbmNlbEV4cG9ydC5lbWl0KClcIlxuICAgID48L3AtYnV0dG9uPlxuICA8L25nLXRlbXBsYXRlPlxuPC9wLWRpYWxvZz5cbiJdfQ==