@jax-data-science/sci-image-visualizer 0.8.3 → 0.10.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 (579) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +34 -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/image.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  13. package/esm2022/lib/contracts/intensity.mjs +48 -5
  14. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  15. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  16. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  17. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  18. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  19. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  20. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  21. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  25. package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
  26. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  28. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  29. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  30. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  31. package/esm2022/lib/geometry/contour.mjs +63 -0
  32. package/esm2022/lib/geometry/loft.mjs +128 -0
  33. package/esm2022/lib/geometry/polylabel.mjs +156 -0
  34. package/esm2022/lib/geometry/raster.mjs +98 -0
  35. package/esm2022/lib/geometry/reconstruct.mjs +315 -0
  36. package/esm2022/lib/geometry/reslice-image.mjs +57 -0
  37. package/esm2022/lib/geometry/ring.mjs +201 -0
  38. package/esm2022/lib/geometry/section.mjs +215 -0
  39. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  40. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  41. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  42. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  43. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  45. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +12 -9
  46. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +83 -0
  47. package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
  48. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +180 -591
  49. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  50. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  51. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  52. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  53. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +270 -0
  54. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  55. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  56. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  57. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  58. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  59. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +347 -0
  60. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +427 -4207
  61. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
  62. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +550 -0
  63. package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
  64. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  65. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  66. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  67. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +194 -0
  68. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  69. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  70. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  71. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  72. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  73. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  74. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  75. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  76. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  77. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  78. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  79. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  80. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  81. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  82. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  83. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  84. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  85. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  86. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +164 -0
  87. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +213 -716
  88. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  89. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  90. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  91. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  92. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  93. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  94. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  95. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  96. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  97. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  98. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  99. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  100. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  101. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  102. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  103. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  104. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  105. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  106. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  107. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  108. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  109. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  110. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  111. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  112. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  113. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  114. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  115. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  116. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  117. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  118. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  119. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  120. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  121. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  122. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  123. package/esm2022/lib/models/bezier.mjs +1 -11
  124. package/esm2022/lib/models/class-preset.mjs +41 -3
  125. package/esm2022/lib/models/geometry.mjs +27 -164
  126. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  127. package/esm2022/lib/models/polygon-factory.mjs +134 -0
  128. package/esm2022/lib/models/region-clone.mjs +68 -0
  129. package/esm2022/lib/models/region-geojson.mjs +411 -0
  130. package/esm2022/lib/models/region.mjs +34 -33
  131. package/esm2022/lib/models/shape.mjs +18 -16
  132. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  133. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  134. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  135. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  136. package/esm2022/lib/plot.utilities.mjs +296 -473
  137. package/esm2022/lib/processing/image-crop.mjs +1 -1
  138. package/esm2022/lib/processing/processing-image.mjs +28 -15
  139. package/esm2022/lib/provide-visualization.mjs +40 -14
  140. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
  141. package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
  142. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +163 -0
  143. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  144. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  145. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  146. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  147. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  148. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  149. package/esm2022/lib/region-editor/region-editor.component.mjs +896 -660
  150. package/esm2022/lib/region-editor/region-metrics.mjs +86 -0
  151. package/esm2022/lib/region-editor/region-persistence.service.mjs +160 -0
  152. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +169 -0
  153. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  154. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  155. package/esm2022/lib/region-ops.service.mjs +28 -70
  156. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  157. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  158. package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
  159. package/esm2022/lib/region-overlay/region-style.mjs +97 -0
  160. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  161. package/esm2022/lib/region-source/http-region-source.mjs +104 -0
  162. package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
  163. package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
  164. package/esm2022/lib/region-source/region-source.mjs +67 -0
  165. package/esm2022/lib/region-source/region-tiles.mjs +708 -0
  166. package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
  167. package/esm2022/lib/render-orchestrator.mjs +14 -11
  168. package/esm2022/lib/render-session.mjs +207 -0
  169. package/esm2022/lib/routing-visualizer.service.mjs +858 -414
  170. package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
  171. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  172. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  173. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  174. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  175. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  176. package/esm2022/lib/spatial/lod.mjs +187 -0
  177. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  178. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  179. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  180. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  181. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  182. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  183. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  184. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  185. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  186. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  187. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  188. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  189. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  190. package/esm2022/lib/spatial/stats.mjs +71 -0
  191. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  192. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  193. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  194. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  195. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  196. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  197. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  198. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  199. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  200. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  201. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  202. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  203. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  204. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  205. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  206. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  207. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  208. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  209. package/esm2022/lib/store/class-color.util.mjs +53 -5
  210. package/esm2022/lib/store/class-signatures.mjs +63 -0
  211. package/esm2022/lib/store/region-history.mjs +146 -0
  212. package/esm2022/lib/store/region-scope-cache.mjs +144 -0
  213. package/esm2022/lib/store/region-selection.mjs +82 -0
  214. package/esm2022/lib/store/region-source-scope.mjs +171 -0
  215. package/esm2022/lib/store/region-store.service.mjs +986 -670
  216. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  217. package/esm2022/lib/store/visualizer-store.service.mjs +81 -76
  218. package/esm2022/lib/toast-outlets.mjs +5 -4
  219. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  220. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  221. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  222. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  223. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  224. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +120 -0
  225. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  226. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  227. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  228. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  229. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  230. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  231. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  232. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  233. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  234. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  235. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  236. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  237. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  238. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +121 -0
  239. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  240. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  241. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  242. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  243. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  244. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  245. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  246. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  247. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  248. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  249. package/esm2022/lib/toolbar/toolbar.component.mjs +84 -119
  250. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  251. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  252. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  253. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  254. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  255. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  256. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  257. package/esm2022/lib/util/supersede.mjs +56 -0
  258. package/esm2022/lib/visualization.module.mjs +39 -141
  259. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  260. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  261. package/esm2022/lib/visualizer/region-load.mjs +123 -0
  262. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  263. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  264. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  265. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  266. package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
  267. package/esm2022/lib/visualizer.component.mjs +602 -1902
  268. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  269. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  270. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  271. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs +47169 -0
  272. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +1 -0
  273. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs +238 -0
  274. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map +1 -0
  275. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
  276. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
  277. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  278. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  279. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
  280. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  281. package/fesm2022/mask.worker.js +36 -917
  282. package/fesm2022/onnx-sam.worker.js +52 -16
  283. package/fesm2022/region-source.worker.js +1067 -0
  284. package/fesm2022/spatial-math.worker.js +471 -0
  285. package/fesm2022/tsne.worker.js +32 -15
  286. package/index.d.ts +19 -10
  287. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  288. package/lib/contracts/capabilities.contract.d.ts +4 -2
  289. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  290. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  291. package/lib/contracts/color.d.ts +27 -0
  292. package/lib/contracts/colormap-lut.d.ts +19 -4
  293. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  294. package/lib/contracts/display-types.d.ts +21 -0
  295. package/lib/contracts/image.contract.d.ts +4 -0
  296. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  297. package/lib/contracts/intensity.d.ts +13 -2
  298. package/lib/contracts/plot-type.d.ts +3 -1
  299. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  300. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  301. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  302. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  303. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  304. package/lib/contracts/region-editor-api.contract.d.ts +85 -1
  305. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  306. package/lib/contracts/region-store.contract.d.ts +22 -0
  307. package/lib/contracts/sam.contract.d.ts +7 -0
  308. package/lib/contracts/section-view.contract.d.ts +44 -0
  309. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  310. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  311. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  312. package/lib/contracts/visualizer.contract.d.ts +231 -54
  313. package/lib/contracts/viz-config.d.ts +9 -0
  314. package/lib/geometry/contour.d.ts +24 -0
  315. package/lib/geometry/loft.d.ts +22 -0
  316. package/lib/geometry/polylabel.d.ts +23 -0
  317. package/lib/geometry/raster.d.ts +42 -0
  318. package/lib/geometry/reconstruct.d.ts +54 -0
  319. package/lib/geometry/reslice-image.d.ts +33 -0
  320. package/lib/geometry/ring.d.ts +67 -0
  321. package/lib/geometry/section.d.ts +52 -0
  322. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  323. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  324. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  325. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  326. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  327. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  328. package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -3
  329. package/lib/implementations/napari-js/napari-loading-state.d.ts +37 -0
  330. package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
  331. package/lib/implementations/napari-js/napari-region-overlay.d.ts +68 -71
  332. package/lib/implementations/napari-js/napari-scene.d.ts +126 -0
  333. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  334. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  335. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  336. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +91 -0
  337. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  338. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  339. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  340. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  341. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  342. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  343. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +169 -883
  344. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
  345. package/lib/implementations/napari-js/napari-volume-scene.d.ts +148 -0
  346. package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
  347. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  348. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  349. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  350. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  351. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  352. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  353. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  354. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  355. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  356. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  357. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  358. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  359. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  360. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  361. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  362. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  363. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  364. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  365. package/lib/implementations/osd/osd-export.d.ts +36 -0
  366. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  367. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  368. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  369. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +38 -0
  370. package/lib/implementations/osd/osd-region-overlay.d.ts +46 -51
  371. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  372. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  373. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  374. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  375. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  376. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  377. package/lib/implementations/osd/simple-source.d.ts +161 -0
  378. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  379. package/lib/implementations/osd/tile-client.d.ts +11 -14
  380. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  381. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  382. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  383. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  384. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  385. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  386. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  387. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  388. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  389. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  390. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  391. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  392. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  393. package/lib/implementations/region-centroids.d.ts +14 -0
  394. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  395. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  396. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  397. package/lib/implementations/tile-server/index.d.ts +5 -0
  398. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  399. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  400. package/lib/implementations/tile-server/tile-protocol.d.ts +83 -0
  401. package/lib/implementations/tile-server/transport.d.ts +62 -0
  402. package/lib/intensity/intensity-profile.d.ts +66 -0
  403. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  404. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  405. package/lib/models/bezier.d.ts +0 -5
  406. package/lib/models/class-preset.d.ts +25 -0
  407. package/lib/models/geometry.d.ts +14 -48
  408. package/lib/models/polygon-edit.d.ts +72 -0
  409. package/lib/models/polygon-factory.d.ts +45 -0
  410. package/lib/models/region-clone.d.ts +20 -0
  411. package/lib/models/region-geojson.d.ts +57 -0
  412. package/lib/models/region.d.ts +59 -4
  413. package/lib/models/shape.d.ts +8 -0
  414. package/lib/plot-mode/contribution-host.d.ts +125 -0
  415. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  416. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  417. package/lib/plot.utilities.d.ts +19 -30
  418. package/lib/processing/processing-image.d.ts +5 -2
  419. package/lib/provide-visualization.d.ts +19 -2
  420. package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
  421. package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
  422. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +86 -0
  423. package/lib/region-editor/file-stem.d.ts +7 -0
  424. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  425. package/lib/region-editor/mask-export.service.d.ts +54 -0
  426. package/lib/region-editor/mask-raster.d.ts +2 -8
  427. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  428. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  429. package/lib/region-editor/region-editor.component.d.ts +283 -200
  430. package/lib/region-editor/region-metrics.d.ts +34 -0
  431. package/lib/region-editor/region-persistence.service.d.ts +77 -0
  432. package/lib/region-editor/region-table/region-table.component.d.ts +89 -0
  433. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  434. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  435. package/lib/region-ops.service.d.ts +1 -7
  436. package/lib/region-overlay/region-geometry.d.ts +158 -0
  437. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  438. package/lib/region-overlay/region-source-layer.d.ts +96 -0
  439. package/lib/region-overlay/region-style.d.ts +52 -0
  440. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  441. package/lib/region-source/http-region-source.d.ts +45 -0
  442. package/lib/region-source/region-source-ops.d.ts +89 -0
  443. package/lib/region-source/region-source-worker.d.ts +7 -0
  444. package/lib/region-source/region-source.d.ts +82 -0
  445. package/lib/region-source/region-tiles.d.ts +289 -0
  446. package/lib/region-source/worker-region-source.d.ts +65 -0
  447. package/lib/render-orchestrator.d.ts +6 -2
  448. package/lib/render-session.d.ts +75 -0
  449. package/lib/routing-visualizer.service.d.ts +248 -59
  450. package/lib/section-pane/section-pane.component.d.ts +47 -0
  451. package/lib/spatial/density-raster.d.ts +6 -0
  452. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  453. package/lib/spatial/embedding-compute.d.ts +21 -2
  454. package/lib/spatial/glyphs.d.ts +16 -0
  455. package/lib/spatial/lod.d.ts +94 -0
  456. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  457. package/lib/spatial/spatial-density.d.ts +15 -5
  458. package/lib/spatial/spatial-encoding.d.ts +11 -44
  459. package/lib/spatial/spatial-expression.d.ts +40 -22
  460. package/lib/spatial/spatial-framing.d.ts +1 -0
  461. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  462. package/lib/spatial/spatial-hover.d.ts +4 -16
  463. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  464. package/lib/spatial/spatial-selection.d.ts +21 -26
  465. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  466. package/lib/spatial/spatial-tiles.d.ts +9 -256
  467. package/lib/spatial/stats.d.ts +38 -0
  468. package/lib/spatial/transcript-grouping.d.ts +119 -0
  469. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  470. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  471. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  472. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  473. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  474. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  475. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  476. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  477. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  478. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  479. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  480. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  481. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  482. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  483. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  484. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  485. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  486. package/lib/store/class-color.util.d.ts +39 -2
  487. package/lib/store/class-signatures.d.ts +11 -0
  488. package/lib/store/region-history.d.ts +66 -0
  489. package/lib/store/region-scope-cache.d.ts +65 -0
  490. package/lib/store/region-selection.d.ts +36 -0
  491. package/lib/store/region-source-scope.d.ts +68 -0
  492. package/lib/store/region-store.service.d.ts +312 -116
  493. package/lib/store/visualizer-store.service.d.ts +32 -33
  494. package/lib/toast-outlets.d.ts +4 -3
  495. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  496. package/lib/toolbar/canvas-tools.d.ts +20 -0
  497. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  498. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  499. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  500. package/lib/toolbar/region-tools/region-tools.component.d.ts +62 -0
  501. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  502. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  503. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  504. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  505. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  506. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  507. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  508. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  509. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  510. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  511. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  512. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  513. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  514. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +51 -0
  515. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  516. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  517. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  518. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  519. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  520. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  521. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  522. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  523. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  524. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  525. package/lib/toolbar/toolbar.component.d.ts +55 -84
  526. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  527. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  528. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  529. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  530. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  531. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  532. package/lib/util/mark-for-check.d.ts +11 -0
  533. package/lib/util/supersede.d.ts +53 -0
  534. package/lib/visualization.module.d.ts +18 -39
  535. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  536. package/lib/visualizer/region-actions.d.ts +54 -0
  537. package/lib/visualizer/region-load.d.ts +46 -0
  538. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  539. package/lib/visualizer/tool-modes.d.ts +49 -0
  540. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  541. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  542. package/lib/visualizer/volume-sections.d.ts +64 -0
  543. package/lib/visualizer.component.d.ts +232 -447
  544. package/lib/workers/spatial-math-ops.d.ts +65 -0
  545. package/lib/workers/spatial-math-worker.d.ts +7 -0
  546. package/lib/workers/spatial-math.d.ts +74 -0
  547. package/package.json +12 -3
  548. package/src/lib/assets/slice.svg +23 -0
  549. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  550. package/src/lib/styles/viz-icons.scss +14 -0
  551. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  552. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  553. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  554. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  555. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  556. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  557. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  558. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  559. package/src/lib/assets/cell-detection.svg +0 -37
  560. package/src/lib/assets/click.svg +0 -1
  561. package/src/lib/assets/colormap-luts.json +0 -1
  562. package/src/lib/assets/edit-selection-white.svg +0 -47
  563. package/src/lib/assets/icons/colormap-earth.png +0 -0
  564. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  565. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  566. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  567. package/src/lib/assets/picture-segmentation.svg +0 -43
  568. package/src/lib/assets/test/download-379.svg +0 -1
  569. package/src/lib/assets/test/download-98.svg +0 -1
  570. package/src/lib/assets/test/json-1.svg +0 -1
  571. package/src/lib/assets/test/load-53.svg +0 -1
  572. package/src/lib/assets/test/mask-44.svg +0 -1
  573. package/src/lib/assets/test/mask-download-44.svg +0 -15
  574. package/src/lib/assets/test/mask-save-44.svg +0 -11
  575. package/src/lib/assets/test/overlay-1.svg +0 -1
  576. package/src/lib/assets/test/overlay-4.svg +0 -1
  577. package/src/lib/assets/test/region-26.svg +0 -1
  578. package/src/lib/assets/test/save-56.svg +0 -1
  579. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,300 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { CheckboxModule } from 'primeng/checkbox';
5
+ import { DropdownModule } from 'primeng/dropdown';
6
+ import { SliderModule } from 'primeng/slider';
7
+ import { TooltipModule } from 'primeng/tooltip';
8
+ import { DEFAULT_SPATIAL_VIEW } from '../../contracts/display-types';
9
+ import { emptySelection } from '../../spatial/spatial-selection';
10
+ import { CLIP_OPTIONS, columnOptions, middleSection, sectionLabel, } from '../../spatial/spatial-panel-model';
11
+ import { SpatialKeyComponent } from '../spatial-key/spatial-key.component';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@angular/common";
14
+ import * as i2 from "@angular/forms";
15
+ import * as i3 from "primeng/checkbox";
16
+ import * as i4 from "primeng/dropdown";
17
+ import * as i5 from "primeng/slider";
18
+ import * as i6 from "primeng/tooltip";
19
+ /**
20
+ * The Observations section — one marker per observation (cell centroid, Visium spot) — and
21
+ * what else draws them: what colours them (a column or a gene, mutually exclusive, with
22
+ * the {@link SpatialKeyComponent key}), point size and opacity, the gene map, the 3D scene
23
+ * (volume, cloud, sections, density volumes) and the continuous-only knobs.
24
+ *
25
+ * Renders the section and the sections after it as siblings in the dialog body
26
+ * (`display: contents`). Writes only through the port: `setViewState`, and the colour
27
+ * source's own `colorByColumn` / `colorByFeature` / `clearColorBy`.
28
+ */
29
+ export class SpatialObservationsPanelComponent {
30
+ constructor() {
31
+ /** The spatial controls this panel reads and writes through; null without a `SPATIAL_DATA_PORT`. */
32
+ this.controls = null;
33
+ /** The dataset on offer, or null. */
34
+ this.dataset = null;
35
+ /** The current spatial view state: what is drawn, and how. */
36
+ this.view = DEFAULT_SPATIAL_VIEW;
37
+ /** The gene list "Colour by gene" picks from, shared with the other gene dropdowns. */
38
+ this.genes = null;
39
+ /** The key's categorical legend, or null — which also decides the continuous knobs. */
40
+ this.legend = null;
41
+ /** The key's continuous colour bar (a CSS gradient), or null when categorical. */
42
+ this.colorBarCss = null;
43
+ /** The current selection (its count, and what is muted). */
44
+ this.selection = emptySelection();
45
+ /** The legend row whose category is selected, for highlighting. */
46
+ this.selectedCategory = null;
47
+ /** Colormap tree for the continuous colour scale. */
48
+ this.colormapOptions = [];
49
+ /** Set while the 3D cloud is the active mode. */
50
+ this.is3d = false;
51
+ /** Whether the Observations section is expanded. */
52
+ this.open = false;
53
+ /** Asks to open or close it; two-way with `open`. */
54
+ this.openChange = new EventEmitter();
55
+ /** A legend row was clicked (see the key). */
56
+ this.categoryClicked = new EventEmitter();
57
+ this.clipOptions = CLIP_OPTIONS;
58
+ /** Virtual-scrolled only past this many options (see the cells panel's gene dropdown). */
59
+ this.geneVirtualScrollFrom = 200;
60
+ /** Colour-by column choices — "None" plus every column the dataset declares. */
61
+ this.columnOptions = [];
62
+ this.selectedColumn = null;
63
+ this.selectedGene = null;
64
+ /**
65
+ * The dataset's imaged section positions, or null when its z is continuous rather than
66
+ * sectioned. Read once per dataset — the scan walks the z of every observation, so it
67
+ * must not sit in a template getter.
68
+ */
69
+ this.sections = null;
70
+ }
71
+ ngOnChanges(changes) {
72
+ if (changes['dataset'] || changes['controls']) {
73
+ this.columnOptions = columnOptions(this.dataset);
74
+ // A new dataset almost certainly has different columns; drop stale UI state.
75
+ this.selectedGene = null;
76
+ this.sections = this.controls?.sampledSections() ?? null;
77
+ }
78
+ if (changes['view']) {
79
+ this.selectedColumn = this.view.colorBy?.kind === 'column' ? this.view.colorBy.name : null;
80
+ this.selectedGene = this.view.colorBy?.kind === 'feature' ? this.view.colorBy.name : null;
81
+ }
82
+ }
83
+ // ── colour source ───────────────────────────────────────────────────────
84
+ /** Column dropdown. Choosing a column supersedes any gene selection. */
85
+ onColumn(name) {
86
+ this.selectedColumn = name;
87
+ this.selectedGene = null;
88
+ if (!name) {
89
+ this.controls?.clearColorBy();
90
+ return;
91
+ }
92
+ this.controls?.colorByColumn(name);
93
+ }
94
+ /** A gene was picked; it supersedes any column selection. */
95
+ onGene(name) {
96
+ this.selectedGene = name;
97
+ if (!name) {
98
+ this.controls?.clearColorBy();
99
+ return;
100
+ }
101
+ this.selectedColumn = null;
102
+ this.controls?.colorByFeature(name);
103
+ }
104
+ /** Cell outlines on offer, which changes what the circles mean. */
105
+ get hasCells() {
106
+ return !!(this.dataset?.polygonTiles || this.dataset?.polygons);
107
+ }
108
+ /** True while a selection is active — everything else renders muted. */
109
+ get hasSelection() {
110
+ return this.selection.count > 0;
111
+ }
112
+ /** Whether log/clip apply — they are continuous-only knobs. */
113
+ get isContinuous() {
114
+ return !!this.view.colorBy && this.legend === null;
115
+ }
116
+ // ── display ─────────────────────────────────────────────────────────────
117
+ // PrimeNG's slider reports `number | undefined`; ignore the empty case rather
118
+ // than writing `undefined` into the store and rendering NaN-sized markers.
119
+ onPointScale(value) {
120
+ if (value === undefined)
121
+ return;
122
+ this.controls?.setViewState({ pointScale: value });
123
+ }
124
+ onOpacity(value) {
125
+ if (value === undefined)
126
+ return;
127
+ this.controls?.setViewState({ opacity: value });
128
+ }
129
+ onLogScale(on) {
130
+ this.controls?.setViewState({ logScale: on });
131
+ }
132
+ onGeneMap(on) {
133
+ this.controls?.setViewState({ geneMap: on });
134
+ }
135
+ /** 3D: smooth the per-section sheets along z into a continuous volume. */
136
+ onGeneMapVolume(on) {
137
+ this.controls?.setViewState({ geneMapVolume: on });
138
+ }
139
+ /** 3D: restrict the sheets to one imaged section. */
140
+ onGeneMapOneSection(on) {
141
+ if (!on) {
142
+ this.controls?.setViewState({ geneMapSection: null });
143
+ return;
144
+ }
145
+ this.controls?.setViewState({ geneMapSection: middleSection(this.sections) });
146
+ }
147
+ onGeneMapSection(value) {
148
+ if (value === undefined)
149
+ return;
150
+ this.controls?.setViewState({ geneMapSection: value });
151
+ }
152
+ get geneMapOneSection() {
153
+ return this.view.geneMapSection != null;
154
+ }
155
+ /** "12 of 53" for the gene map's own section, 1-based like the cloud's. */
156
+ get geneMapSectionLabel() {
157
+ return sectionLabel(this.sections, this.view.geneMapSection);
158
+ }
159
+ onGeneMapSmoothing(value) {
160
+ if (value === undefined)
161
+ return;
162
+ this.controls?.setViewState({ geneMapSmoothing: value });
163
+ }
164
+ onGeneMapOpacity(value) {
165
+ if (value === undefined)
166
+ return;
167
+ this.controls?.setViewState({ geneMapOpacity: value });
168
+ }
169
+ /**
170
+ * What the 3D gene map is currently showing, said plainly — the sheets are a
171
+ * measurement and the volume is an estimate, and the panel has to be the place
172
+ * that says which one is on screen.
173
+ */
174
+ get geneMapVolumeNote() {
175
+ const total = this.sections?.length ?? 0;
176
+ if (this.view.geneMapVolume) {
177
+ return ('Interpolated along z: the planes between the imaged sections carry an ' +
178
+ "ESTIMATE, smoothed from their neighbours' mean. Nothing is drawn beyond the " +
179
+ 'outermost section.');
180
+ }
181
+ if (this.geneMapOneSection) {
182
+ return ("One imaged section's field — measured, not interpolated. Hide the " +
183
+ 'observations to read it, or leave them on to check the field against them.');
184
+ }
185
+ return (`One field per imaged section${total ? ` (${total})` : ''}, at its own depth, ` +
186
+ 'with the gaps between sections empty. Kernel-weighted mean per cell, not a sum.');
187
+ }
188
+ /** True while a gene is the colour source — the only thing a gene map can map. */
189
+ get canMapGene() {
190
+ return this.view.colorBy?.kind === 'feature';
191
+ }
192
+ // ── what the 3D scene draws ─────────────────────────────────────────────
193
+ // The volume, the cloud and the density volumes share one space, so each one
194
+ // hides the others to some degree. Independent toggles because the useful views
195
+ // are the combinations, not a single "3D mode".
196
+ onShowVolume(on) {
197
+ this.controls?.setViewState({ showVolume: on });
198
+ }
199
+ onVolumeOpacity(value) {
200
+ if (value === undefined)
201
+ return;
202
+ this.controls?.setViewState({ volumeOpacity: value });
203
+ }
204
+ onShowPoints(on) {
205
+ this.controls?.setViewState({ showPoints: on });
206
+ }
207
+ /** The "one section at a time" switch: null restores the whole stack. */
208
+ onOneSection(on) {
209
+ if (!on) {
210
+ this.controls?.setViewState({ pointSection: null });
211
+ return;
212
+ }
213
+ // Open in the middle of the stack rather than on the first section, which for
214
+ // a brain is a nearly empty olfactory-bulb slide.
215
+ this.controls?.setViewState({ pointSection: middleSection(this.sections) });
216
+ }
217
+ onPointSection(value) {
218
+ if (value === undefined)
219
+ return;
220
+ this.controls?.setViewState({ pointSection: value });
221
+ }
222
+ /** True while the cloud is restricted to a single section. */
223
+ get oneSection() {
224
+ return this.view.pointSection != null;
225
+ }
226
+ /** Highest section index the slider can reach. */
227
+ get lastSection() {
228
+ return Math.max(0, (this.sections?.length ?? 1) - 1);
229
+ }
230
+ /** "12 of 53" — 1-based, because the sections are slides, not array slots. */
231
+ get sectionLabel() {
232
+ return sectionLabel(this.sections, this.view.pointSection);
233
+ }
234
+ /** Whether this dataset has sections to pick from at all. */
235
+ get isSectioned() {
236
+ return (this.sections?.length ?? 0) > 1;
237
+ }
238
+ onDensityVolume(on) {
239
+ this.controls?.setViewState({ densityVolume: on });
240
+ }
241
+ onDensitySmoothing(value) {
242
+ if (value === undefined)
243
+ return;
244
+ this.controls?.setViewState({ densitySmoothing: value });
245
+ }
246
+ /** What the density volumes are actually showing, said plainly — an estimate is
247
+ * only honest if the reader knows it is one, and which clusters are in view. */
248
+ get densityNote() {
249
+ const capped = `the ${SpatialObservationsPanelComponent.DENSITY_MAX_CLUSTERS} largest clusters`;
250
+ const what = this.legend ? capped : this.hasSelection ? 'the selected cells' : 'all cells';
251
+ return (`Density estimate over ${what} — smoothed between the imaged sections, ` +
252
+ 'not measured cells. Lower Opacity to read the fields under the cloud.');
253
+ }
254
+ /** Mirrors the renderer's cap, for the note only. */
255
+ static { this.DENSITY_MAX_CLUSTERS = 6; }
256
+ onClip(value) {
257
+ this.controls?.setViewState({ percentileClip: value });
258
+ }
259
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialObservationsPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
260
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialObservationsPanelComponent, isStandalone: true, selector: "spatial-observations-panel", inputs: { controls: "controls", dataset: "dataset", view: "view", genes: "genes", legend: "legend", colorBarCss: "colorBarCss", selection: "selection", selectedCategory: "selectedCategory", colormapOptions: "colormapOptions", is3d: "is3d", open: "open" }, outputs: { openChange: "openChange", categoryClicked: "categoryClicked" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowPoints($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <small class=\"sc-hint\" *ngIf=\"hasCells && !is3d\">\n One circle per cell. With cell outlines on, circles are only drawn where cells are too small on screen to\n outline.\n </small>\n <!-- Colour source. Column and gene are mutually exclusive: picking one\n clears the other, so what drives the colours is never ambiguous. -->\n <div class=\"sc-section\">\n <label class=\"sc-lbl\" for=\"sc-column\">Colour by column</label>\n <p-dropdown\n inputId=\"sc-column\"\n [options]=\"columnOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedColumn\"\n (ngModelChange)=\"onColumn($event)\"\n placeholder=\"None (flat colour)\"\n appendTo=\"body\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n </div>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-gene\">Colour by gene</label>\n <!-- A filterable dropdown, not a free-text box: the genes are visible before\n anything is typed, and each keystroke narrows a list the user can see.\n Virtual-scrolled because a targeted panel runs to a few thousand names. -->\n <p-dropdown\n inputId=\"sc-gene\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedGene\"\n (ngModelChange)=\"onGene($event)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onShow)=\"genes?.ensureList()\"\n [showClear]=\"true\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Search {{ ds.features.count | number }} genes\u2026\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n <small class=\"sc-hint\" *ngIf=\"gene.failed\">Gene lookup failed.</small>\n </div>\n </ng-container>\n\n <spatial-key\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-key>\n\n <!-- Display -->\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <div class=\"sc-row\" *ngIf=\"ds.volume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showVolume\"\n (onChange)=\"onShowVolume($event.checked)\"\n label=\"Reference volume\"\n pTooltip=\"The registered anatomy the observations sit in\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- The backdrop's own opacity: reading the cloud or a density field\n through the anatomy means turning the anatomy down, not the data. -->\n <div class=\"sc-row\" *ngIf=\"ds.volume && view.showVolume\">\n <span class=\"sc-lbl\">Volume opacity</span>\n <p-slider\n [ngModel]=\"view.volumeOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onVolumeOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.volumeOpacity }}</span>\n </div>\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (onChange)=\"onShowPoints($event.checked)\"\n label=\"Observations\"\n pTooltip=\"The measured cells. Hide them to read the density volumes underneath\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i3.Checkbox, selector: "p-checkbox", inputs: ["value", "name", "disabled", "binary", "label", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "styleClass", "labelStyleClass", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i4.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: SliderModule }, { kind: "component", type: i5.Slider, selector: "p-slider", inputs: ["animate", "disabled", "min", "max", "orientation", "step", "range", "style", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: SpatialKeyComponent, selector: "spatial-key", inputs: ["controls", "dataset", "view", "legend", "colorBarCss", "selectedCategory", "colormapOptions"], outputs: ["categoryClicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
261
+ }
262
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialObservationsPanelComponent, decorators: [{
263
+ type: Component,
264
+ args: [{ selector: 'spatial-observations-panel', standalone: true, imports: [
265
+ CommonModule,
266
+ FormsModule,
267
+ CheckboxModule,
268
+ DropdownModule,
269
+ SliderModule,
270
+ TooltipModule,
271
+ SpatialKeyComponent,
272
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowPoints($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <small class=\"sc-hint\" *ngIf=\"hasCells && !is3d\">\n One circle per cell. With cell outlines on, circles are only drawn where cells are too small on screen to\n outline.\n </small>\n <!-- Colour source. Column and gene are mutually exclusive: picking one\n clears the other, so what drives the colours is never ambiguous. -->\n <div class=\"sc-section\">\n <label class=\"sc-lbl\" for=\"sc-column\">Colour by column</label>\n <p-dropdown\n inputId=\"sc-column\"\n [options]=\"columnOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedColumn\"\n (ngModelChange)=\"onColumn($event)\"\n placeholder=\"None (flat colour)\"\n appendTo=\"body\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n </div>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-gene\">Colour by gene</label>\n <!-- A filterable dropdown, not a free-text box: the genes are visible before\n anything is typed, and each keystroke narrows a list the user can see.\n Virtual-scrolled because a targeted panel runs to a few thousand names. -->\n <p-dropdown\n inputId=\"sc-gene\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedGene\"\n (ngModelChange)=\"onGene($event)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onShow)=\"genes?.ensureList()\"\n [showClear]=\"true\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Search {{ ds.features.count | number }} genes\u2026\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n <small class=\"sc-hint\" *ngIf=\"gene.failed\">Gene lookup failed.</small>\n </div>\n </ng-container>\n\n <spatial-key\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-key>\n\n <!-- Display -->\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <div class=\"sc-row\" *ngIf=\"ds.volume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showVolume\"\n (onChange)=\"onShowVolume($event.checked)\"\n label=\"Reference volume\"\n pTooltip=\"The registered anatomy the observations sit in\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- The backdrop's own opacity: reading the cloud or a density field\n through the anatomy means turning the anatomy down, not the data. -->\n <div class=\"sc-row\" *ngIf=\"ds.volume && view.showVolume\">\n <span class=\"sc-lbl\">Volume opacity</span>\n <p-slider\n [ngModel]=\"view.volumeOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onVolumeOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.volumeOpacity }}</span>\n </div>\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (onChange)=\"onShowPoints($event.checked)\"\n label=\"Observations\"\n pTooltip=\"The measured cells. Hide them to read the density volumes underneath\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}:host{display:contents}\n"] }]
273
+ }], propDecorators: { controls: [{
274
+ type: Input
275
+ }], dataset: [{
276
+ type: Input
277
+ }], view: [{
278
+ type: Input
279
+ }], genes: [{
280
+ type: Input
281
+ }], legend: [{
282
+ type: Input
283
+ }], colorBarCss: [{
284
+ type: Input
285
+ }], selection: [{
286
+ type: Input
287
+ }], selectedCategory: [{
288
+ type: Input
289
+ }], colormapOptions: [{
290
+ type: Input
291
+ }], is3d: [{
292
+ type: Input
293
+ }], open: [{
294
+ type: Input
295
+ }], openChange: [{
296
+ type: Output
297
+ }], categoryClicked: [{
298
+ type: Output
299
+ }] } });
300
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUVMLE1BQU0sR0FFUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUloRCxPQUFPLEVBQWdCLG9CQUFvQixFQUFvQixNQUFNLCtCQUErQixDQUFDO0FBQ3JHLE9BQU8sRUFBd0IsY0FBYyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdkYsT0FBTyxFQUNMLFlBQVksRUFFWixhQUFhLEVBQ2IsYUFBYSxFQUNiLFlBQVksR0FDYixNQUFNLG1DQUFtQyxDQUFDO0FBRzNDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDOzs7Ozs7OztBQUUzRTs7Ozs7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LENBQUM7OEdBcFBVLGlDQUFpQztrR0FBakMsaUNBQWlDLHNiQ3pEOUMscTlZQXFUQSwrOUlEeFFJLFlBQVksK09BQ1osV0FBVyw4VkFDWCxjQUFjLGdaQUNkLGNBQWMsdXRDQUNkLFlBQVksK1JBQ1osYUFBYSxzWEFDYixtQkFBbUI7OzJGQU1WLGlDQUFpQztrQkFoQjdDLFNBQVM7K0JBQ0UsNEJBQTRCLGNBQzFCLElBQUksV0FDUDt3QkFDUCxZQUFZO3dCQUNaLFdBQVc7d0JBQ1gsY0FBYzt3QkFDZCxjQUFjO3dCQUNkLFlBQVk7d0JBQ1osYUFBYTt3QkFDYixtQkFBbUI7cUJBQ3BCLG1CQUdnQix1QkFBdUIsQ0FBQyxNQUFNOzhCQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLE1BQU07c0JBQWQsS0FBSztnQkFFRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUVHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsSUFBSTtzQkFBWixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFYSxVQUFVO3NCQUE1QixNQUFNO2dCQUVZLGVBQWU7c0JBQWpDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBDaGVja2JveE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvY2hlY2tib3gnO1xuaW1wb3J0IHsgRHJvcGRvd25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2Ryb3Bkb3duJztcbmltcG9ydCB7IFNsaWRlck1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvc2xpZGVyJztcbmltcG9ydCB7IFRvb2x0aXBNb2R1bGUgfSBmcm9tICdwcmltZW5nL3Rvb2x0aXAnO1xuXG5pbXBvcnQgdHlwZSB7IElTcGF0aWFsQ29udHJvbHMgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvdmlzdWFsaXplci5jb250cmFjdCc7XG5pbXBvcnQgdHlwZSB7IFNwYXRpYWxEYXRhc2V0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBDb2xvcm1hcE5vZGUsIERFRkFVTFRfU1BBVElBTF9WSUVXLCBTcGF0aWFsVmlld1N0YXRlIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgU3BhdGlhbFNlbGVjdGlvbk1hc2ssIGVtcHR5U2VsZWN0aW9uIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXNlbGVjdGlvbic7XG5pbXBvcnQge1xuICBDTElQX09QVElPTlMsXG4gIFBhbmVsT3B0aW9uLFxuICBjb2x1bW5PcHRpb25zLFxuICBtaWRkbGVTZWN0aW9uLFxuICBzZWN0aW9uTGFiZWwsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgdHlwZSB7IEdlbmVQaWNrZXJNb2RlbCB9IGZyb20gJy4uL3NwYXRpYWwtZ2VuZS1waWNrZXInO1xuaW1wb3J0IHR5cGUgeyBTcGF0aWFsTGVnZW5kRW50cnkgfSBmcm9tICcuLi9zcGF0aWFsLWtleS9zcGF0aWFsLWtleS5tb2RlbCc7XG5pbXBvcnQgeyBTcGF0aWFsS2V5Q29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1rZXkvc3BhdGlhbC1rZXkuY29tcG9uZW50JztcblxuLyoqXG4gKiBUaGUgT2JzZXJ2YXRpb25zIHNlY3Rpb24g4oCUIG9uZSBtYXJrZXIgcGVyIG9ic2VydmF0aW9uIChjZWxsIGNlbnRyb2lkLCBWaXNpdW0gc3BvdCkg4oCUIGFuZFxuICogd2hhdCBlbHNlIGRyYXdzIHRoZW06IHdoYXQgY29sb3VycyB0aGVtIChhIGNvbHVtbiBvciBhIGdlbmUsIG11dHVhbGx5IGV4Y2x1c2l2ZSwgd2l0aFxuICogdGhlIHtAbGluayBTcGF0aWFsS2V5Q29tcG9uZW50IGtleX0pLCBwb2ludCBzaXplIGFuZCBvcGFjaXR5LCB0aGUgZ2VuZSBtYXAsIHRoZSAzRCBzY2VuZVxuICogKHZvbHVtZSwgY2xvdWQsIHNlY3Rpb25zLCBkZW5zaXR5IHZvbHVtZXMpIGFuZCB0aGUgY29udGludW91cy1vbmx5IGtub2JzLlxuICpcbiAqIFJlbmRlcnMgdGhlIHNlY3Rpb24gYW5kIHRoZSBzZWN0aW9ucyBhZnRlciBpdCBhcyBzaWJsaW5ncyBpbiB0aGUgZGlhbG9nIGJvZHlcbiAqIChgZGlzcGxheTogY29udGVudHNgKS4gV3JpdGVzIG9ubHkgdGhyb3VnaCB0aGUgcG9ydDogYHNldFZpZXdTdGF0ZWAsIGFuZCB0aGUgY29sb3VyXG4gKiBzb3VyY2UncyBvd24gYGNvbG9yQnlDb2x1bW5gIC8gYGNvbG9yQnlGZWF0dXJlYCAvIGBjbGVhckNvbG9yQnlgLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgQ2hlY2tib3hNb2R1bGUsXG4gICAgRHJvcGRvd25Nb2R1bGUsXG4gICAgU2xpZGVyTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gICAgU3BhdGlhbEtleUNvbXBvbmVudCxcbiAgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNwYXRpYWxPYnNlcnZhdGlvbnNQYW5lbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8qKiBUaGUgc3BhdGlhbCBjb250cm9scyB0aGlzIHBhbmVsIHJlYWRzIGFuZCB3cml0ZXMgdGhyb3VnaDsgbnVsbCB3aXRob3V0IGEgYFNQQVRJQUxfREFUQV9QT1JUYC4gKi9cbiAgQElucHV0KCkgY29udHJvbHM6IElTcGF0aWFsQ29udHJvbHMgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBkYXRhc2V0IG9uIG9mZmVyLCBvciBudWxsLiAqL1xuICBASW5wdXQoKSBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGN1cnJlbnQgc3BhdGlhbCB2aWV3IHN0YXRlOiB3aGF0IGlzIGRyYXduLCBhbmQgaG93LiAqL1xuICBASW5wdXQoKSB2aWV3OiBTcGF0aWFsVmlld1N0YXRlID0gREVGQVVMVF9TUEFUSUFMX1ZJRVc7XG4gIC8qKiBUaGUgZ2VuZSBsaXN0IFwiQ29sb3VyIGJ5IGdlbmVcIiBwaWNrcyBmcm9tLCBzaGFyZWQgd2l0aCB0aGUgb3RoZXIgZ2VuZSBkcm9wZG93bnMuICovXG4gIEBJbnB1dCgpIGdlbmVzOiBHZW5lUGlja2VyTW9kZWwgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBrZXkncyBjYXRlZ29yaWNhbCBsZWdlbmQsIG9yIG51bGwg4oCUIHdoaWNoIGFsc28gZGVjaWRlcyB0aGUgY29udGludW91cyBrbm9icy4gKi9cbiAgQElucHV0KCkgbGVnZW5kOiBTcGF0aWFsTGVnZW5kRW50cnlbXSB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGtleSdzIGNvbnRpbnVvdXMgY29sb3VyIGJhciAoYSBDU1MgZ3JhZGllbnQpLCBvciBudWxsIHdoZW4gY2F0ZWdvcmljYWwuICovXG4gIEBJbnB1dCgpIGNvbG9yQmFyQ3NzOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBjdXJyZW50IHNlbGVjdGlvbiAoaXRzIGNvdW50LCBhbmQgd2hhdCBpcyBtdXRlZCkuICovXG4gIEBJbnB1dCgpIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2sgPSBlbXB0eVNlbGVjdGlvbigpO1xuICAvKiogVGhlIGxlZ2VuZCByb3cgd2hvc2UgY2F0ZWdvcnkgaXMgc2VsZWN0ZWQsIGZvciBoaWdobGlnaHRpbmcuICovXG4gIEBJbnB1dCgpIHNlbGVjdGVkQ2F0ZWdvcnk6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICAvKiogQ29sb3JtYXAgdHJlZSBmb3IgdGhlIGNvbnRpbnVvdXMgY29sb3VyIHNjYWxlLiAqL1xuICBASW5wdXQoKSBjb2xvcm1hcE9wdGlvbnM6IENvbG9ybWFwTm9kZVtdID0gW107XG4gIC8qKiBTZXQgd2hpbGUgdGhlIDNEIGNsb3VkIGlzIHRoZSBhY3RpdmUgbW9kZS4gKi9cbiAgQElucHV0KCkgaXMzZCA9IGZhbHNlO1xuICAvKiogV2hldGhlciB0aGUgT2JzZXJ2YXRpb25zIHNlY3Rpb24gaXMgZXhwYW5kZWQuICovXG4gIEBJbnB1dCgpIG9wZW4gPSBmYWxzZTtcbiAgLyoqIEFza3MgdG8gb3BlbiBvciBjbG9zZSBpdDsgdHdvLXdheSB3aXRoIGBvcGVuYC4gKi9cbiAgQE91dHB1dCgpIHJlYWRvbmx5IG9wZW5DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gIC8qKiBBIGxlZ2VuZCByb3cgd2FzIGNsaWNrZWQgKHNlZSB0aGUga2V5KS4gKi9cbiAgQE91dHB1dCgpIHJlYWRvbmx5IGNhdGVnb3J5Q2xpY2tlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBjbGlwT3B0aW9ucyA9IENMSVBfT1BUSU9OUztcbiAgLyoqIFZpcnR1YWwtc2Nyb2xsZWQgb25seSBwYXN0IHRoaXMgbWFueSBvcHRpb25zIChzZWUgdGhlIGNlbGxzIHBhbmVsJ3MgZ2VuZSBkcm9wZG93bikuICovXG4gIHByb3RlY3RlZCByZWFkb25seSBnZW5lVmlydHVhbFNjcm9sbEZyb20gPSAyMDA7XG5cbiAgLyoqIENvbG91ci1ieSBjb2x1bW4gY2hvaWNlcyDigJQgXCJOb25lXCIgcGx1cyBldmVyeSBjb2x1bW4gdGhlIGRhdGFzZXQgZGVjbGFyZXMuICovXG4gIHByb3RlY3RlZCBjb2x1bW5PcHRpb25zOiBQYW5lbE9wdGlvbjxzdHJpbmcgfCBudWxsPltdID0gW107XG4gIHByb3RlY3RlZCBzZWxlY3RlZENvbHVtbjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByb3RlY3RlZCBzZWxlY3RlZEdlbmU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKipcbiAgICogVGhlIGRhdGFzZXQncyBpbWFnZWQgc2VjdGlvbiBwb3NpdGlvbnMsIG9yIG51bGwgd2hlbiBpdHMgeiBpcyBjb250aW51b3VzIHJhdGhlciB0aGFuXG4gICAqIHNlY3Rpb25lZC4gUmVhZCBvbmNlIHBlciBkYXRhc2V0IOKAlCB0aGUgc2NhbiB3YWxrcyB0aGUgeiBvZiBldmVyeSBvYnNlcnZhdGlvbiwgc28gaXRcbiAgICogbXVzdCBub3Qgc2l0IGluIGEgdGVtcGxhdGUgZ2V0dGVyLlxuICAgKi9cbiAgcHJvdGVjdGVkIHNlY3Rpb25zOiBGbG9hdDMyQXJyYXkgfCBudWxsID0gbnVsbDtcblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2RhdGFzZXQnXSB8fCBjaGFuZ2VzWydjb250cm9scyddKSB7XG4gICAgICB0aGlzLmNvbHVtbk9wdGlvbnMgPSBjb2x1bW5PcHRpb25zKHRoaXMuZGF0YXNldCk7XG4gICAgICAvLyBBIG5ldyBkYXRhc2V0IGFsbW9zdCBjZXJ0YWlubHkgaGFzIGRpZmZlcmVudCBjb2x1bW5zOyBkcm9wIHN0YWxlIFVJIHN0YXRlLlxuICAgICAgdGhpcy5zZWxlY3RlZEdlbmUgPSBudWxsO1xuICAgICAgdGhpcy5zZWN0aW9ucyA9IHRoaXMuY29udHJvbHM/LnNhbXBsZWRTZWN0aW9ucygpID8/IG51bGw7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWyd2aWV3J10pIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRDb2x1bW4gPSB0aGlzLnZpZXcuY29sb3JCeT8ua2luZCA9PT0gJ2NvbHVtbicgPyB0aGlzLnZpZXcuY29sb3JCeS5uYW1lIDogbnVsbDtcbiAgICAgIHRoaXMuc2VsZWN0ZWRHZW5lID0gdGhpcy52aWV3LmNvbG9yQnk/LmtpbmQgPT09ICdmZWF0dXJlJyA/IHRoaXMudmlldy5jb2xvckJ5Lm5hbWUgOiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBjb2xvdXIgc291cmNlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBDb2x1bW4gZHJvcGRvd24uIENob29zaW5nIGEgY29sdW1uIHN1cGVyc2VkZXMgYW55IGdlbmUgc2VsZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25Db2x1bW4obmFtZTogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgIHRoaXMuc2VsZWN0ZWRDb2x1bW4gPSBuYW1lO1xuICAgIHRoaXMuc2VsZWN0ZWRHZW5lID0gbnVsbDtcbiAgICBpZiAoIW5hbWUpIHtcbiAgICAgIHRoaXMuY29udHJvbHM/LmNsZWFyQ29sb3JCeSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNvbnRyb2xzPy5jb2xvckJ5Q29sdW1uKG5hbWUpO1xuICB9XG5cbiAgLyoqIEEgZ2VuZSB3YXMgcGlja2VkOyBpdCBzdXBlcnNlZGVzIGFueSBjb2x1bW4gc2VsZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25HZW5lKG5hbWU6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGVkR2VuZSA9IG5hbWU7XG4gICAgaWYgKCFuYW1lKSB7XG4gICAgICB0aGlzLmNvbnRyb2xzPy5jbGVhckNvbG9yQnkoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zZWxlY3RlZENvbHVtbiA9IG51bGw7XG4gICAgdGhpcy5jb250cm9scz8uY29sb3JCeUZlYXR1cmUobmFtZSk7XG4gIH1cblxuICAvKiogQ2VsbCBvdXRsaW5lcyBvbiBvZmZlciwgd2hpY2ggY2hhbmdlcyB3aGF0IHRoZSBjaXJjbGVzIG1lYW4uICovXG4gIHByb3RlY3RlZCBnZXQgaGFzQ2VsbHMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhKHRoaXMuZGF0YXNldD8ucG9seWdvblRpbGVzIHx8IHRoaXMuZGF0YXNldD8ucG9seWdvbnMpO1xuICB9XG5cbiAgLyoqIFRydWUgd2hpbGUgYSBzZWxlY3Rpb24gaXMgYWN0aXZlIOKAlCBldmVyeXRoaW5nIGVsc2UgcmVuZGVycyBtdXRlZC4gKi9cbiAgZ2V0IGhhc1NlbGVjdGlvbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3Rpb24uY291bnQgPiAwO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgbG9nL2NsaXAgYXBwbHkg4oCUIHRoZXkgYXJlIGNvbnRpbnVvdXMtb25seSBrbm9icy4gKi9cbiAgcHJvdGVjdGVkIGdldCBpc0NvbnRpbnVvdXMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhdGhpcy52aWV3LmNvbG9yQnkgJiYgdGhpcy5sZWdlbmQgPT09IG51bGw7XG4gIH1cblxuICAvLyDilIDilIAgZGlzcGxheSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvLyBQcmltZU5HJ3Mgc2xpZGVyIHJlcG9ydHMgYG51bWJlciB8IHVuZGVmaW5lZGA7IGlnbm9yZSB0aGUgZW1wdHkgY2FzZSByYXRoZXJcbiAgLy8gdGhhbiB3cml0aW5nIGB1bmRlZmluZWRgIGludG8gdGhlIHN0b3JlIGFuZCByZW5kZXJpbmcgTmFOLXNpemVkIG1hcmtlcnMuXG4gIHByb3RlY3RlZCBvblBvaW50U2NhbGUodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgcG9pbnRTY2FsZTogdmFsdWUgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uT3BhY2l0eSh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvcGFjaXR5OiB2YWx1ZSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25Mb2dTY2FsZShvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGxvZ1NjYWxlOiBvbiB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25HZW5lTWFwKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcDogb24gfSk7XG4gIH1cbiAgLyoqIDNEOiBzbW9vdGggdGhlIHBlci1zZWN0aW9uIHNoZWV0cyBhbG9uZyB6IGludG8gYSBjb250aW51b3VzIHZvbHVtZS4gKi9cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcFZvbHVtZShvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBWb2x1bWU6IG9uIH0pO1xuICB9XG4gIC8qKiAzRDogcmVzdHJpY3QgdGhlIHNoZWV0cyB0byBvbmUgaW1hZ2VkIHNlY3Rpb24uICovXG4gIHByb3RlY3RlZCBvbkdlbmVNYXBPbmVTZWN0aW9uKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKCFvbikge1xuICAgICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcFNlY3Rpb246IG51bGwgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBTZWN0aW9uOiBtaWRkbGVTZWN0aW9uKHRoaXMuc2VjdGlvbnMpIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbkdlbmVNYXBTZWN0aW9uKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBTZWN0aW9uOiB2YWx1ZSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgZ2V0IGdlbmVNYXBPbmVTZWN0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcuZ2VuZU1hcFNlY3Rpb24gIT0gbnVsbDtcbiAgfVxuICAvKiogXCIxMiBvZiA1M1wiIGZvciB0aGUgZ2VuZSBtYXAncyBvd24gc2VjdGlvbiwgMS1iYXNlZCBsaWtlIHRoZSBjbG91ZCdzLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGdlbmVNYXBTZWN0aW9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gc2VjdGlvbkxhYmVsKHRoaXMuc2VjdGlvbnMsIHRoaXMudmlldy5nZW5lTWFwU2VjdGlvbik7XG4gIH1cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcFNtb290aGluZyh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwU21vb3RoaW5nOiB2YWx1ZSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25HZW5lTWFwT3BhY2l0eSh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwT3BhY2l0eTogdmFsdWUgfSk7XG4gIH1cbiAgLyoqXG4gICAqIFdoYXQgdGhlIDNEIGdlbmUgbWFwIGlzIGN1cnJlbnRseSBzaG93aW5nLCBzYWlkIHBsYWlubHkg4oCUIHRoZSBzaGVldHMgYXJlIGFcbiAgICogbWVhc3VyZW1lbnQgYW5kIHRoZSB2b2x1bWUgaXMgYW4gZXN0aW1hdGUsIGFuZCB0aGUgcGFuZWwgaGFzIHRvIGJlIHRoZSBwbGFjZVxuICAgKiB0aGF0IHNheXMgd2hpY2ggb25lIGlzIG9uIHNjcmVlbi5cbiAgICovXG4gIHByb3RlY3RlZCBnZXQgZ2VuZU1hcFZvbHVtZU5vdGUoKTogc3RyaW5nIHtcbiAgICBjb25zdCB0b3RhbCA9IHRoaXMuc2VjdGlvbnM/Lmxlbmd0aCA/PyAwO1xuICAgIGlmICh0aGlzLnZpZXcuZ2VuZU1hcFZvbHVtZSkge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgJ0ludGVycG9sYXRlZCBhbG9uZyB6OiB0aGUgcGxhbmVzIGJldHdlZW4gdGhlIGltYWdlZCBzZWN0aW9ucyBjYXJyeSBhbiAnICtcbiAgICAgICAgXCJFU1RJTUFURSwgc21vb3RoZWQgZnJvbSB0aGVpciBuZWlnaGJvdXJzJyBtZWFuLiBOb3RoaW5nIGlzIGRyYXduIGJleW9uZCB0aGUgXCIgK1xuICAgICAgICAnb3V0ZXJtb3N0IHNlY3Rpb24uJ1xuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZ2VuZU1hcE9uZVNlY3Rpb24pIHtcbiAgICAgIHJldHVybiAoXG4gICAgICAgIFwiT25lIGltYWdlZCBzZWN0aW9uJ3MgZmllbGQg4oCUIG1lYXN1cmVkLCBub3QgaW50ZXJwb2xhdGVkLiBIaWRlIHRoZSBcIiArXG4gICAgICAgICdvYnNlcnZhdGlvbnMgdG8gcmVhZCBpdCwgb3IgbGVhdmUgdGhlbSBvbiB0byBjaGVjayB0aGUgZmllbGQgYWdhaW5zdCB0aGVtLidcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiAoXG4gICAgICBgT25lIGZpZWxkIHBlciBpbWFnZWQgc2VjdGlvbiR7dG90YWwgPyBgICgke3RvdGFsfSlgIDogJyd9LCBhdCBpdHMgb3duIGRlcHRoLCBgICtcbiAgICAgICd3aXRoIHRoZSBnYXBzIGJldHdlZW4gc2VjdGlvbnMgZW1wdHkuIEtlcm5lbC13ZWlnaHRlZCBtZWFuIHBlciBjZWxsLCBub3QgYSBzdW0uJ1xuICAgICk7XG4gIH1cblxuICAvKiogVHJ1ZSB3aGlsZSBhIGdlbmUgaXMgdGhlIGNvbG91ciBzb3VyY2Ug4oCUIHRoZSBvbmx5IHRoaW5nIGEgZ2VuZSBtYXAgY2FuIG1hcC4gKi9cbiAgcHJvdGVjdGVkIGdldCBjYW5NYXBHZW5lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcuY29sb3JCeT8ua2luZCA9PT0gJ2ZlYXR1cmUnO1xuICB9XG5cbiAgLy8g4pSA4pSAIHdoYXQgdGhlIDNEIHNjZW5lIGRyYXdzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBUaGUgdm9sdW1lLCB0aGUgY2xvdWQgYW5kIHRoZSBkZW5zaXR5IHZvbHVtZXMgc2hhcmUgb25lIHNwYWNlLCBzbyBlYWNoIG9uZVxuICAvLyBoaWRlcyB0aGUgb3RoZXJzIHRvIHNvbWUgZGVncmVlLiBJbmRlcGVuZGVudCB0b2dnbGVzIGJlY2F1c2UgdGhlIHVzZWZ1bCB2aWV3c1xuICAvLyBhcmUgdGhlIGNvbWJpbmF0aW9ucywgbm90IGEgc2luZ2xlIFwiM0QgbW9kZVwiLlxuXG4gIHByb3RlY3RlZCBvblNob3dWb2x1bWUob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBzaG93Vm9sdW1lOiBvbiB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25Wb2x1bWVPcGFjaXR5KHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHZvbHVtZU9wYWNpdHk6IHZhbHVlIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvblNob3dQb2ludHMob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBzaG93UG9pbnRzOiBvbiB9KTtcbiAgfVxuICAvKiogVGhlIFwib25lIHNlY3Rpb24gYXQgYSB0aW1lXCIgc3dpdGNoOiBudWxsIHJlc3RvcmVzIHRoZSB3aG9sZSBzdGFjay4gKi9cbiAgcHJvdGVjdGVkIG9uT25lU2VjdGlvbihvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICghb24pIHtcbiAgICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHBvaW50U2VjdGlvbjogbnVsbCB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gT3BlbiBpbiB0aGUgbWlkZGxlIG9mIHRoZSBzdGFjayByYXRoZXIgdGhhbiBvbiB0aGUgZmlyc3Qgc2VjdGlvbiwgd2hpY2ggZm9yXG4gICAgLy8gYSBicmFpbiBpcyBhIG5lYXJseSBlbXB0eSBvbGZhY3RvcnktYnVsYiBzbGlkZS5cbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBwb2ludFNlY3Rpb246IG1pZGRsZVNlY3Rpb24odGhpcy5zZWN0aW9ucykgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uUG9pbnRTZWN0aW9uKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHBvaW50U2VjdGlvbjogdmFsdWUgfSk7XG4gIH1cbiAgLyoqIFRydWUgd2hpbGUgdGhlIGNsb3VkIGlzIHJlc3RyaWN0ZWQgdG8gYSBzaW5nbGUgc2VjdGlvbi4gKi9cbiAgcHJvdGVjdGVkIGdldCBvbmVTZWN0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcucG9pbnRTZWN0aW9uICE9IG51bGw7XG4gIH1cbiAgLyoqIEhpZ2hlc3Qgc2VjdGlvbiBpbmRleCB0aGUgc2xpZGVyIGNhbiByZWFjaC4gKi9cbiAgcHJvdGVjdGVkIGdldCBsYXN0U2VjdGlvbigpOiBudW1iZXIge1xuICAgIHJldHVybiBNYXRoLm1heCgwLCAodGhpcy5zZWN0aW9ucz8ubGVuZ3RoID8/IDEpIC0gMSk7XG4gIH1cbiAgLyoqIFwiMTIgb2YgNTNcIiDigJQgMS1iYXNlZCwgYmVjYXVzZSB0aGUgc2VjdGlvbnMgYXJlIHNsaWRlcywgbm90IGFycmF5IHNsb3RzLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IHNlY3Rpb25MYWJlbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBzZWN0aW9uTGFiZWwodGhpcy5zZWN0aW9ucywgdGhpcy52aWV3LnBvaW50U2VjdGlvbik7XG4gIH1cbiAgLyoqIFdoZXRoZXIgdGhpcyBkYXRhc2V0IGhhcyBzZWN0aW9ucyB0byBwaWNrIGZyb20gYXQgYWxsLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGlzU2VjdGlvbmVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAodGhpcy5zZWN0aW9ucz8ubGVuZ3RoID8/IDApID4gMTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkRlbnNpdHlWb2x1bWUob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBkZW5zaXR5Vm9sdW1lOiBvbiB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25EZW5zaXR5U21vb3RoaW5nKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGRlbnNpdHlTbW9vdGhpbmc6IHZhbHVlIH0pO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGRlbnNpdHkgdm9sdW1lcyBhcmUgYWN0dWFsbHkgc2hvd2luZywgc2FpZCBwbGFpbmx5IOKAlCBhbiBlc3RpbWF0ZSBpc1xuICAgKiAgb25seSBob25lc3QgaWYgdGhlIHJlYWRlciBrbm93cyBpdCBpcyBvbmUsIGFuZCB3aGljaCBjbHVzdGVycyBhcmUgaW4gdmlldy4gKi9cbiAgcHJvdGVjdGVkIGdldCBkZW5zaXR5Tm90ZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNhcHBlZCA9IGB0aGUgJHtTcGF0aWFsT2JzZXJ2YXRpb25zUGFuZWxDb21wb25lbnQuREVOU0lUWV9NQVhfQ0xVU1RFUlN9IGxhcmdlc3QgY2x1c3RlcnNgO1xuICAgIGNvbnN0IHdoYXQgPSB0aGlzLmxlZ2VuZCA/IGNhcHBlZCA6IHRoaXMuaGFzU2VsZWN0aW9uID8gJ3RoZSBzZWxlY3RlZCBjZWxscycgOiAnYWxsIGNlbGxzJztcbiAgICByZXR1cm4gKFxuICAgICAgYERlbnNpdHkgZXN0aW1hdGUgb3ZlciAke3doYXR9IOKAlCBzbW9vdGhlZCBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMsIGAgK1xuICAgICAgJ25vdCBtZWFzdXJlZCBjZWxscy4gTG93ZXIgT3BhY2l0eSB0byByZWFkIHRoZSBmaWVsZHMgdW5kZXIgdGhlIGNsb3VkLidcbiAgICApO1xuICB9XG5cbiAgLyoqIE1pcnJvcnMgdGhlIHJlbmRlcmVyJ3MgY2FwLCBmb3IgdGhlIG5vdGUgb25seS4gKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgREVOU0lUWV9NQVhfQ0xVU1RFUlMgPSA2O1xuICBwcm90ZWN0ZWQgb25DbGlwKHZhbHVlOiBbbnVtYmVyLCBudW1iZXJdKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgcGVyY2VudGlsZUNsaXA6IHZhbHVlIH0pO1xuICB9XG59XG4iLCI8bmctY29udGFpbmVyICpuZ0lmPVwiZGF0YXNldCBhcyBkc1wiPlxuICA8IS0tIE9ic2VydmF0aW9uczogb25lIG1hcmtlciBwZXIgb2JzZXJ2YXRpb24gKGNlbGwgY2VudHJvaWQsIFZpc2l1bSBzcG90KSwgYW5kIHdoYXRcbiAgICAgY29sb3VycyB0aGVtLiBUaGUgbGVhZCBzZWN0aW9uIGZvciBkYXRhc2V0cyB3aXRob3V0IGNlbGwgb3V0bGluZXMuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2MtcGFuZWxcIiBbY2xhc3Mub3Blbl09XCJvcGVuXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXBhbmVsLWhlYWRcIiAoY2xpY2spPVwib3BlbkNoYW5nZS5lbWl0KCFvcGVuKVwiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5zaG93UG9pbnRzXCJcbiAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvblNob3dQb2ludHMoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXBhbmVsLXRpdGxlXCI+T2JzZXJ2YXRpb25zPC9zcGFuPlxuICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1jaGV2cm9uLWRvd25dPVwib3BlblwiIFtjbGFzcy5waS1jaGV2cm9uLXJpZ2h0XT1cIiFvcGVuXCI+PC9pPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1wYW5lbC1ib2R5XCIgKm5nSWY9XCJvcGVuXCI+XG4gICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJoYXNDZWxscyAmJiAhaXMzZFwiPlxuICAgICAgICBPbmUgY2lyY2xlIHBlciBjZWxsLiBXaXRoIGNlbGwgb3V0bGluZXMgb24sIGNpcmNsZXMgYXJlIG9ubHkgZHJhd24gd2hlcmUgY2VsbHMgYXJlIHRvbyBzbWFsbCBvbiBzY3JlZW4gdG9cbiAgICAgICAgb3V0bGluZS5cbiAgICAgIDwvc21hbGw+XG4gICAgICA8IS0tIENvbG91ciBzb3VyY2UuIENvbHVtbiBhbmQgZ2VuZSBhcmUgbXV0dWFsbHkgZXhjbHVzaXZlOiBwaWNraW5nIG9uZVxuICAgICBjbGVhcnMgdGhlIG90aGVyLCBzbyB3aGF0IGRyaXZlcyB0aGUgY29sb3VycyBpcyBuZXZlciBhbWJpZ3VvdXMuIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2MtY29sdW1uXCI+Q29sb3VyIGJ5IGNvbHVtbjwvbGFiZWw+XG4gICAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgICAgaW5wdXRJZD1cInNjLWNvbHVtblwiXG4gICAgICAgICAgW29wdGlvbnNdPVwiY29sdW1uT3B0aW9uc1wiXG4gICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgW25nTW9kZWxdPVwic2VsZWN0ZWRDb2x1bW5cIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ29sdW1uKCRldmVudClcIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwiTm9uZSAoZmxhdCBjb2xvdXIpXCJcbiAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1mdWxsXCJcbiAgICAgICAgPjwvcC1kcm9wZG93bj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZ2VuZXM/LnN0YXRlJCB8IGFzeW5jIGFzIGdlbmVcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImRzLmZlYXR1cmVzXCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2MtZ2VuZVwiPkNvbG91ciBieSBnZW5lPC9sYWJlbD5cbiAgICAgICAgICA8IS0tIEEgZmlsdGVyYWJsZSBkcm9wZG93biwgbm90IGEgZnJlZS10ZXh0IGJveDogdGhlIGdlbmVzIGFyZSB2aXNpYmxlIGJlZm9yZVxuICAgICAgIGFueXRoaW5nIGlzIHR5cGVkLCBhbmQgZWFjaCBrZXlzdHJva2UgbmFycm93cyBhIGxpc3QgdGhlIHVzZXIgY2FuIHNlZS5cbiAgICAgICBWaXJ0dWFsLXNjcm9sbGVkIGJlY2F1c2UgYSB0YXJnZXRlZCBwYW5lbCBydW5zIHRvIGEgZmV3IHRob3VzYW5kIG5hbWVzLiAtLT5cbiAgICAgICAgICA8cC1kcm9wZG93blxuICAgICAgICAgICAgaW5wdXRJZD1cInNjLWdlbmVcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwiZ2VuZS5vcHRpb25zXCJcbiAgICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJzZWxlY3RlZEdlbmVcIlxuICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25HZW5lKCRldmVudClcIlxuICAgICAgICAgICAgW2ZpbHRlcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIGZpbHRlckJ5PVwibGFiZWxcIlxuICAgICAgICAgICAgW3Jlc2V0RmlsdGVyT25IaWRlXT1cInRydWVcIlxuICAgICAgICAgICAgKG9uRmlsdGVyKT1cImdlbmVzPy5vbkZpbHRlcigkZXZlbnQuZmlsdGVyKVwiXG4gICAgICAgICAgICAob25TaG93KT1cImdlbmVzPy5lbnN1cmVMaXN0KClcIlxuICAgICAgICAgICAgW3Nob3dDbGVhcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIFt2aXJ0dWFsU2Nyb2xsXT1cImdlbmUub3B0aW9ucy5sZW5ndGggPiBnZW5lVmlydHVhbFNjcm9sbEZyb21cIlxuICAgICAgICAgICAgW3ZpcnR1YWxTY3JvbGxJdGVtU2l6ZV09XCIzMFwiXG4gICAgICAgICAgICBbZW1wdHlGaWx0ZXJNZXNzYWdlXT1cImdlbmUucmVtb3RlID8gJ05vIG1hdGNoIOKAlCBrZWVwIHR5cGluZycgOiAnTm8gbWF0Y2gnXCJcbiAgICAgICAgICAgIFtlbXB0eU1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnVHlwZSB0byBzZWFyY2ggZ2VuZXMnIDogJ05vIGdlbmVzJ1wiXG4gICAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJTZWFyY2gge3sgZHMuZmVhdHVyZXMuY291bnQgfCBudW1iZXIgfX0gZ2VuZXPigKZcIlxuICAgICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWZ1bGxcIlxuICAgICAgICAgID48L3AtZHJvcGRvd24+XG4gICAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiZ2VuZS5mYWlsZWRcIj5HZW5lIGxvb2t1cCBmYWlsZWQuPC9zbWFsbD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPHNwYXRpYWwta2V5XG4gICAgICAgIFtjb250cm9sc109XCJjb250cm9sc1wiXG4gICAgICAgIFtkYXRhc2V0XT1cImRzXCJcbiAgICAgICAgW3ZpZXddPVwidmlld1wiXG4gICAgICAgIFtsZWdlbmRdPVwibGVnZW5kXCJcbiAgICAgICAgW2NvbG9yQmFyQ3NzXT1cImNvbG9yQmFyQ3NzXCJcbiAgICAgICAgW3NlbGVjdGVkQ2F0ZWdvcnldPVwic2VsZWN0ZWRDYXRlZ29yeVwiXG4gICAgICAgIFtjb2xvcm1hcE9wdGlvbnNdPVwiY29sb3JtYXBPcHRpb25zXCJcbiAgICAgICAgKGNhdGVnb3J5Q2xpY2tlZCk9XCJjYXRlZ29yeUNsaWNrZWQuZW1pdCgkZXZlbnQpXCJcbiAgICAgID48L3NwYXRpYWwta2V5PlxuXG4gICAgICA8IS0tIERpc3BsYXkgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5Qb2ludCBzaXplPC9zcGFuPlxuICAgICAgICAgIDxwLXNsaWRlclxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5wb2ludFNjYWxlXCJcbiAgICAgICAgICAgIFttaW5dPVwiMC4yNVwiXG4gICAgICAgICAgICBbbWF4XT1cIjVcIlxuICAgICAgICAgICAgW3N0ZXBdPVwiMC4yNVwiXG4gICAgICAgICAgICAob25DaGFuZ2UpPVwib25Qb2ludFNjYWxlKCRldmVudC52YWx1ZSlcIlxuICAgICAgICAgID48L3Atc2xpZGVyPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5wb2ludFNjYWxlIH19w5c8L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5PcGFjaXR5PC9zcGFuPlxuICAgICAgICAgIDxwLXNsaWRlclxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5vcGFjaXR5XCJcbiAgICAgICAgICAgIFttaW5dPVwiMC4xXCJcbiAgICAgICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgICAgICBbc3RlcF09XCIwLjA1XCJcbiAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvbk9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3Lm9wYWNpdHkgfX08L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gT25seSBmb3IgYSBnZW5lOiB0aGUgbWFwIGRyYXdzIHRoYXQgZ2VuZSdzIGV4cHJlc3Npb24gYXMgYSBmaWVsZC4gSW4gMkRcbiAgICAgaXQgZ29lcyB1bmRlciB0aGUgY2VsbHMgb2YgdGhlIGRpc3BsYXllZCBwbGFuZTsgaW4gM0QgaXQgaXMgb25lIHNoZWV0IHBlclxuICAgICBpbWFnZWQgc2VjdGlvbiwgb3B0aW9uYWxseSBzbW9vdGhlZCBhbG9uZyB6IGludG8gYSB2b2x1bWUuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiY2FuTWFwR2VuZVwiPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXAoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJHZW5lIG1hcCAoZXhwcmVzc2lvbiBmaWVsZClcIlxuICAgICAgICBbcFRvb2x0aXBdPVwiXG4gICAgICAgICAgaXMzZFxuICAgICAgICAgICAgPyAnRHJhdyB0aGlzIGdlbmVcXCdzIGV4cHJlc3Npb24gYXMgb25lIGZpZWxkIHBlciBpbWFnZWQgc2VjdGlvbiDigJQgYW4gZXN0aW1hdGUgYmV0d2VlbiB0aGUgY2VsbHMsIGVtcHR5IHdoZXJlIG5vdGhpbmcgd2FzIG1lYXN1cmVkJ1xuICAgICAgICAgICAgOiAnRHJhdyB0aGlzIGdlbmVcXCdzIGV4cHJlc3Npb24gYXMgYSBzbW9vdGggZmllbGQgVU5ERVIgdGhlIGNlbGxzIOKAlCBhbiBlc3RpbWF0ZSBiZXR3ZWVuIHRoZW0sIHRyYW5zcGFyZW50IHdoZXJlIG5vdGhpbmcgd2FzIG1lYXN1cmVkJ1xuICAgICAgICBcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIDNEIG9ubHk6IGludGVycG9sYXRpbmcgYWxvbmcgeiB0dXJucyB0aGUgbWVhc3VyZWQgc2hlZXRzIGludG8gYW5cbiAgICAgICBlc3RpbWF0ZSwgc28gaXQgaXMgaXRzIG93biBkZWNpc2lvbiBhbmQgaXRzIG93biBsYWJlbC4gLS0+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2RcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFZvbHVtZVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBWb2x1bWUoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJWb2x1bWUgcmVuZGVyaW5nIChpbnRlcnBvbGF0ZSBhbG9uZyB6KVwiXG4gICAgICAgIHBUb29sdGlwPVwiU21vb3RoIHRoZSBwZXItc2VjdGlvbiBmaWVsZHMgaW50byBhIGNvbnRpbnVvdXMgdm9sdW1lIOKAlCBhbiBFU1RJTUFURSBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMsIG5vdCBtZWFzdXJlZCB0aXNzdWVcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIE1lYW5pbmdsZXNzIHdoaWxlIGludGVycG9sYXRpbmc6IGEgdm9sdW1lIGJ1aWx0IGZyb20gb25lIHNlY3Rpb24gd291bGRcbiAgICAgICBzbWVhciB0aGF0IHNsaWRlIHRocm91Z2ggdGhlIHNwZWNpbWVuJ3Mgd2hvbGUgZGVwdGguIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiBpczNkICYmIGlzU2VjdGlvbmVkICYmICF2aWV3LmdlbmVNYXBWb2x1bWVcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cImdlbmVNYXBPbmVTZWN0aW9uXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcE9uZVNlY3Rpb24oJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJPbmUgbWFwIHNlY3Rpb24gYXQgYSB0aW1lXCJcbiAgICAgICAgcFRvb2x0aXA9XCJEcmF3IGEgc2luZ2xlIGltYWdlZCBzZWN0aW9uJ3MgZmllbGQgaW5zdGVhZCBvZiB0aGUgd2hvbGUgc3RhY2sgb2Ygc2hlZXRzXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2QgJiYgaXNTZWN0aW9uZWQgJiYgIXZpZXcuZ2VuZU1hcFZvbHVtZSAmJiBnZW5lTWFwT25lU2VjdGlvblwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5NYXAgc2VjdGlvbjwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBTZWN0aW9uXCJcbiAgICAgICAgW21pbl09XCIwXCJcbiAgICAgICAgW21heF09XCJsYXN0U2VjdGlvblwiXG4gICAgICAgIFtzdGVwXT1cIjFcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwU2VjdGlvbigkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyBnZW5lTWFwU2VjdGlvbkxhYmVsIH19PC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcFwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TbW9vdGhpbmc8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwU21vb3RoaW5nXCJcbiAgICAgICAgW21pbl09XCIwLjVcIlxuICAgICAgICBbbWF4XT1cIjRcIlxuICAgICAgICBbc3RlcF09XCIwLjVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwU21vb3RoaW5nKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcuZ2VuZU1hcFNtb290aGluZyB9fcOXPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcFwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5NYXAgb3BhY2l0eTwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBPcGFjaXR5XCJcbiAgICAgICAgW21pbl09XCIwLjFcIlxuICAgICAgICBbbWF4XT1cIjFcIlxuICAgICAgICBbc3RlcF09XCIwLjA1XCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcE9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5nZW5lTWFwT3BhY2l0eSB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmICFpczNkXCI+XG4gICAgICBLZXJuZWwtd2VpZ2h0ZWQgbWVhbiBwZXIgY2VsbCwgbm90IGEgc3VtIOKAlCBzbyBhIGNyb3dkZWQgcmVnaW9uIGRvZXMgbm90IGdsb3cgZm9yIGJlaW5nIGNyb3dkZWQuIFRyYW5zcGFyZW50XG4gICAgICB3aGVyZSBubyBjZWxsIHdhcyBtZWFzdXJlZC4gVHVybiB0aGUgY2VsbHMnIG93biBPcGFjaXR5IGRvd24gdG8gcmVhZCB0aGUgZmllbGQgdW5kZXIgdGhlbS5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2RcIj5cbiAgICAgIHt7IGdlbmVNYXBWb2x1bWVOb3RlIH19XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gM0Qgb25seTogdGhlIHZvbHVtZSwgdGhlIGNsb3VkIGFuZCB0aGUgZGVuc2l0eSB2b2x1bWVzIG9jY3VweSB0aGUgc2FtZVxuICAgICBzcGFjZSwgc28gZWFjaCBoaWRlcyB0aGUgb3RoZXJzLiBJbmRlcGVuZGVudCB0b2dnbGVzLCBiZWNhdXNlIHRoZSB1c2VmdWxcbiAgICAgdmlld3MgYXJlIHRoZSBjb21iaW5hdGlvbnMg4oCUIHRoZSBmaWVsZCBhbG9uZSwgb25lIHNlY3Rpb24ncyBjZWxscyBvdmVyIGl0LFxuICAgICB0aGUgYW5hdG9teSBhbG9uZS4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpczNkXCI+XG4gICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TaG93PC9zcGFuPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cImRzLnZvbHVtZVwiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5zaG93Vm9sdW1lXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uU2hvd1ZvbHVtZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIlJlZmVyZW5jZSB2b2x1bWVcIlxuICAgICAgICBwVG9vbHRpcD1cIlRoZSByZWdpc3RlcmVkIGFuYXRvbXkgdGhlIG9ic2VydmF0aW9ucyBzaXQgaW5cIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIFRoZSBiYWNrZHJvcCdzIG93biBvcGFjaXR5OiByZWFkaW5nIHRoZSBjbG91ZCBvciBhIGRlbnNpdHkgZmllbGRcbiAgICAgICB0aHJvdWdoIHRoZSBhbmF0b215IG1lYW5zIHR1cm5pbmcgdGhlIGFuYXRvbXkgZG93biwgbm90IHRoZSBkYXRhLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJkcy52b2x1bWUgJiYgdmlldy5zaG93Vm9sdW1lXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlZvbHVtZSBvcGFjaXR5PC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcudm9sdW1lT3BhY2l0eVwiXG4gICAgICAgIFttaW5dPVwiMC4wNVwiXG4gICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgIFtzdGVwXT1cIjAuMDVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25Wb2x1bWVPcGFjaXR5KCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcudm9sdW1lT3BhY2l0eSB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnNob3dQb2ludHNcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25TaG93UG9pbnRzKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiT2JzZXJ2YXRpb25zXCJcbiAgICAgICAgcFRvb2x0aXA9XCJUaGUgbWVhc3VyZWQgY2VsbHMuIEhpZGUgdGhlbSB0byByZWFkIHRoZSBkZW5zaXR5IHZvbHVtZXMgdW5kZXJuZWF0aFwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDwhLS0gT25seSBmb3IgZGF0YSB0aGF0IHJlYWxseSBpcyBzZWN0aW9uZWQ7IGEgY29udGludW91cyB6IGhhcyBubyBzZWN0aW9uc1xuICAgICAgIHRvIHN0ZXAgdGhyb3VnaC4gLS0+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5zaG93UG9pbnRzICYmIGlzU2VjdGlvbmVkXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJvbmVTZWN0aW9uXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uT25lU2VjdGlvbigkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIk9uZSBzZWN0aW9uIGF0IGEgdGltZVwiXG4gICAgICAgIHBUb29sdGlwPVwiRHJhdyBhIHNpbmdsZSBpbWFnZWQgc2VjdGlvbidzIGNlbGxzLCBzbyB0aGUgZGVuc2l0eSB2b2x1bWVzIGJldHdlZW4gdGhlIHNlY3Rpb25zIHN0YXkgdmlzaWJsZVwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuc2hvd1BvaW50cyAmJiBpc1NlY3Rpb25lZCAmJiBvbmVTZWN0aW9uXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlNlY3Rpb248L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5wb2ludFNlY3Rpb25cIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cImxhc3RTZWN0aW9uXCJcbiAgICAgICAgW3N0ZXBdPVwiMVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvblBvaW50U2VjdGlvbigkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyBzZWN0aW9uTGFiZWwgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpczNkXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5kZW5zaXR5Vm9sdW1lXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eVZvbHVtZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIkNsdXN0ZXIgZGVuc2l0eSB2b2x1bWVzXCJcbiAgICAgICAgcFRvb2x0aXA9XCJSYXltYXJjaCBlYWNoIGNsdXN0ZXIgYXMgYSBzbW9vdGggZGVuc2l0eSBmaWVsZCDigJQgYW4gRVNUSU1BVEUgYmV0d2VlbiB0aGUgaW1hZ2VkIHNlY3Rpb25zLCBub3QgbWVhc3VyZWQgY2VsbHNcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U21vb3RoaW5nPC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZGVuc2l0eVNtb290aGluZ1wiXG4gICAgICAgIFttaW5dPVwiMC41XCJcbiAgICAgICAgW21heF09XCI0XCJcbiAgICAgICAgW3N0ZXBdPVwiMC41XCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eVNtb290aGluZygkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LmRlbnNpdHlTbW9vdGhpbmcgfX3Dlzwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5kZW5zaXR5Vm9sdW1lXCI+e3sgZGVuc2l0eU5vdGUgfX08L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBDb250aW51b3VzLW9ubHkga25vYnM6IG1lYW5pbmdsZXNzIGZvciBhIGNhdGVnb3JpY2FsIHBhbGV0dGUuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiaXNDb250aW51b3VzXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5sb2dTY2FsZVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkxvZ1NjYWxlKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiTG9nIHNjYWxlXCJcbiAgICAgICAgcFRvb2x0aXA9XCJDb3VudHMgY29sbGFwc2UgYWdhaW5zdCB0aGVpciBvdXRsaWVycyBvbiBhIGxpbmVhciByYW1wXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5DbGlwIG91dGxpZXJzPC9zcGFuPlxuICAgICAgPHAtZHJvcGRvd25cbiAgICAgICAgW29wdGlvbnNdPVwiY2xpcE9wdGlvbnNcIlxuICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcucGVyY2VudGlsZUNsaXBcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkNsaXAoJGV2ZW50KVwiXG4gICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgIHBUb29sdGlwPVwiUGVyY2VudGlsZSB0aGUgY29udHJhc3Qgd2luZG93IGlzIHRha2VuIGF0XCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtZHJvcGRvd24+XG4gICAgICA8IS0tIFJlc2VydmVzIHRoZSByZWFkb3V0IGNvbHVtbiB0aGlzIHJvdyBoYXMgbm8gcmVhZG91dCBmb3IsIHNvIHRoZVxuICAgICAgICAgY29udHJvbCdzIHJpZ2h0IGVkZ2UgbGluZXMgdXAgd2l0aCBldmVyeSBzbGlkZXIncy4gLS0+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPjwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==