@jax-data-science/sci-image-visualizer 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +358 -4218
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -883
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,370 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewChild, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { SharedModule } from 'primeng/api';
5
+ import { CheckboxModule } from 'primeng/checkbox';
6
+ import { DropdownModule } from 'primeng/dropdown';
7
+ import { InputNumberModule } from 'primeng/inputnumber';
8
+ import { MenuModule } from 'primeng/menu';
9
+ import { MultiSelectModule } from 'primeng/multiselect';
10
+ import { SelectButtonModule } from 'primeng/selectbutton';
11
+ import { SliderModule } from 'primeng/slider';
12
+ import { TooltipModule } from 'primeng/tooltip';
13
+ import { TreeSelectModule } from 'primeng/treeselect';
14
+ import { DEFAULT_SPATIAL_VIEW, } from '../../contracts/display-types';
15
+ import { defaultGlyphFor } from '../../spatial/spatial-tiles';
16
+ import { GLYPH_OPTIONS, allGenesPreparingNote, densityColorBarCss, importGeneGroupsPatch, markerColumnOptions, parseGeneGroups, tileOptions, } from '../../spatial/spatial-panel-model';
17
+ import { colormapNodeFor } from '../spatial-key/spatial-key.component';
18
+ import { SpatialGeneTreeComponent } from '../spatial-gene-tree/spatial-gene-tree.component';
19
+ import { SpatialMarkerGenesFormComponent } from '../spatial-marker-genes-form/spatial-marker-genes-form.component';
20
+ import * as i0 from "@angular/core";
21
+ import * as i1 from "@angular/common";
22
+ import * as i2 from "@angular/forms";
23
+ import * as i3 from "primeng/api";
24
+ import * as i4 from "primeng/checkbox";
25
+ import * as i5 from "primeng/dropdown";
26
+ import * as i6 from "primeng/inputnumber";
27
+ import * as i7 from "primeng/menu";
28
+ import * as i8 from "primeng/tooltip";
29
+ import * as i9 from "primeng/multiselect";
30
+ import * as i10 from "primeng/selectbutton";
31
+ import * as i11 from "primeng/slider";
32
+ import * as i12 from "primeng/treeselect";
33
+ /**
34
+ * The Transcripts section, as Xenium Explorer's: the on/off switch, the transcript genes
35
+ * (with "All genes", the '⋮' menu and gene-group import), the
36
+ * {@link SpatialMarkerGenesFormComponent marker-genes form}, the
37
+ * {@link SpatialGeneTreeComponent gene tree}, how transcripts are drawn — the points
38
+ * estimate against its budget, colouring, icon, size, opacity and quality — and the
39
+ * density map's opacity, bin size, threshold window and colormap.
40
+ *
41
+ * Writes only through `controls.setViewState`.
42
+ */
43
+ export class SpatialTranscriptsPanelComponent {
44
+ constructor(zone, cdr) {
45
+ this.zone = zone;
46
+ this.cdr = cdr;
47
+ /** The spatial controls this panel reads and writes through; null without a `SPATIAL_DATA_PORT`. */
48
+ this.controls = null;
49
+ /** The dataset on offer, or null. */
50
+ this.dataset = null;
51
+ /** The current spatial view state: what is drawn, and how. */
52
+ this.view = DEFAULT_SPATIAL_VIEW;
53
+ /** The gene list the transcript genes are picked from, shared with the other gene dropdowns. */
54
+ this.genes = null;
55
+ /** Estimated transcripts in view, against the budget — Explorer's points bar. */
56
+ this.estimate = null;
57
+ /** The density window in use and its densest bin, for the threshold control. */
58
+ this.densityStats = null;
59
+ /** Transcripts of each selected gene in the current view, from the renderer. */
60
+ this.geneCounts = null;
61
+ /** Colormap tree for the density map's colouring. */
62
+ this.colormapOptions = [];
63
+ /** Whether the section is expanded. */
64
+ this.open = false;
65
+ /** Asks to open or close it; two-way with `open`. */
66
+ this.openChange = new EventEmitter();
67
+ /** Virtual-scrolled only past this many options (see the cells panel's gene dropdown). */
68
+ this.geneVirtualScrollFrom = 200;
69
+ this.transcriptColorOptions = [
70
+ { label: 'Cluster', value: 'cluster' },
71
+ { label: 'Cell type', value: 'cellType' },
72
+ { label: 'Gene', value: 'gene' },
73
+ ];
74
+ this.glyphOptions = GLYPH_OPTIONS;
75
+ this.budgetOptions = [25_000, 50_000, 100_000, 200_000, 400_000].map((n) => ({
76
+ label: n.toLocaleString(),
77
+ value: n,
78
+ }));
79
+ this.densityBins = [10, 20, 40, 80];
80
+ /**
81
+ * Transcript modes on offer. Built once per dataset rather than in a getter: a getter
82
+ * returns a fresh array on every change-detection pass, and PrimeNG re-renders its
83
+ * buttons whenever the array identity changes — which made them impossible to click.
84
+ */
85
+ this.transcriptModeOptions = [];
86
+ /** The '⋮' menu, rebuilt when what enables its items changes. */
87
+ this.geneMenu = [];
88
+ this.editingMax = false;
89
+ /** Whether the marker-genes form is shown. */
90
+ this.markersOpen = false;
91
+ this.geneGroupError = null;
92
+ /**
93
+ * The threshold window shown: the one set, else the one derived. A stored array, not a
94
+ * getter: a range slider's `ngModel` given a fresh array every change-detection pass
95
+ * schedules another pass, forever — which hung the page the moment the density
96
+ * controls appeared.
97
+ */
98
+ this.densityWindow = [0, 1];
99
+ this.densitySliderMax = 1;
100
+ this.densityStep = 0.005;
101
+ this.selectedDensityColormapNode = null;
102
+ /** Built once per density colormap: a 256-entry LUT per change-detection pass is waste. */
103
+ this.densityColorBarCss = '';
104
+ this.densityBarFor = undefined;
105
+ /** The mode the section header's switch turns back on. */
106
+ this.lastTranscriptMode = 'circles';
107
+ /** Whether any column can supply marker genes' clusters. */
108
+ this.hasMarkerColumns = false;
109
+ }
110
+ ngOnChanges(changes) {
111
+ if (changes['dataset']) {
112
+ this.transcriptModeOptions = tileOptions(this.dataset).transcriptModeOptions;
113
+ this.hasMarkerColumns = markerColumnOptions(this.dataset?.columns).length > 0;
114
+ }
115
+ if (changes['view'] || changes['dataset'] || changes['controls'])
116
+ this.geneMenu = this.buildGeneMenu();
117
+ if (changes['view'] || changes['colormapOptions']) {
118
+ this.selectedDensityColormapNode = colormapNodeFor(this.colormapOptions, this.view.densityColormap);
119
+ }
120
+ if (this.densityBarFor !== this.view.densityColormap || !this.densityColorBarCss) {
121
+ this.densityBarFor = this.view.densityColormap;
122
+ this.densityColorBarCss = densityColorBarCss(this.view.densityColormap);
123
+ }
124
+ this.refreshDensityWindow();
125
+ }
126
+ // ── the section switch and the genes ────────────────────────────────────
127
+ onTranscriptsOn(on) {
128
+ if (!on) {
129
+ if (this.view.transcriptMode !== 'off')
130
+ this.lastTranscriptMode = this.view.transcriptMode;
131
+ this.controls?.setViewState({ transcriptMode: 'off' });
132
+ return;
133
+ }
134
+ const mode = this.dataset?.transcriptTiles ? this.lastTranscriptMode : 'density';
135
+ this.onTranscriptMode(mode);
136
+ this.openChange.emit(true);
137
+ }
138
+ onTranscriptMode(mode) {
139
+ // Seed the gene list from the gene being coloured by, so switching transcripts on
140
+ // shows something straight away.
141
+ const seed = !this.view.transcriptGenes.length && this.view.colorBy?.kind === 'feature' ? [this.view.colorBy.name] : null;
142
+ this.controls?.setViewState({ transcriptMode: mode, ...(seed ? { transcriptGenes: seed } : {}) });
143
+ }
144
+ onTranscriptGenes(genes) {
145
+ this.controls?.setViewState({ transcriptGenes: [...(genes ?? [])] });
146
+ }
147
+ /** Real genes in the panel — the tree's denominator. */
148
+ get geneTotal() {
149
+ return (this.dataset?.transcriptTiles?.geneCount ?? this.dataset?.features?.count ?? this.genes?.residentCount ?? 0);
150
+ }
151
+ /** "All genes" needs the grouping pyramid, or at least tiles to draw individually. */
152
+ get canShowAllGenes() {
153
+ return !!this.dataset?.transcriptBins;
154
+ }
155
+ /** Why "All genes" is not offered yet, while the server builds its pyramid. */
156
+ get allGenesPreparing() {
157
+ return allGenesPreparingNote(this.dataset);
158
+ }
159
+ get showingAllGenes() {
160
+ return this.canShowAllGenes && this.view.transcriptAllGenes && this.view.transcriptMode !== 'density';
161
+ }
162
+ onTranscriptAllGenes(on) {
163
+ this.controls?.setViewState({ transcriptAllGenes: on });
164
+ }
165
+ /** '±': every gene, or back to the chosen list. */
166
+ onToggleAllGenes() {
167
+ if (!this.canShowAllGenes)
168
+ return;
169
+ this.onTranscriptAllGenes(!this.view.transcriptAllGenes);
170
+ }
171
+ get canAddMarkers() {
172
+ return !!this.controls?.markerGenes && this.hasMarkerColumns;
173
+ }
174
+ /** Open the marker-genes form (from the '⋮' menu). */
175
+ openMarkers() {
176
+ this.markersOpen = true;
177
+ this.openChange.emit(true);
178
+ this.cdr.markForCheck();
179
+ }
180
+ onNewGeneGroup() {
181
+ const name = (globalThis.prompt?.('Name for this gene group', 'Gene group') ?? '').trim();
182
+ if (!name)
183
+ return;
184
+ const groups = this.view.transcriptGeneGroups.filter((g) => g.name !== name);
185
+ this.controls?.setViewState({
186
+ transcriptGeneGroups: [...groups, { name, genes: [...this.view.transcriptGenes] }],
187
+ });
188
+ }
189
+ /**
190
+ * Import gene groups: CSV/TSV with a group and a gene column (header optional), e.g.
191
+ * marker genes per cell type. The genes are added to the selection.
192
+ */
193
+ async onImportGeneGroups(input) {
194
+ const file = input.files?.[0];
195
+ input.value = '';
196
+ if (!file)
197
+ return;
198
+ this.geneGroupError = null;
199
+ const groups = parseGeneGroups(await file.text());
200
+ this.zone.run(() => {
201
+ if (!groups.length)
202
+ this.geneGroupError = 'No "group,gene" rows found in that file.';
203
+ else
204
+ this.controls?.setViewState(importGeneGroupsPatch(this.view, groups));
205
+ this.cdr.markForCheck();
206
+ });
207
+ }
208
+ // ── how transcripts are drawn ───────────────────────────────────────────
209
+ get estimatePercent() {
210
+ const e = this.estimate;
211
+ return e && e.max > 0 ? Math.min(100, (100 * e.points) / e.max) : 0;
212
+ }
213
+ get estimateOverMax() {
214
+ return !!this.estimate && this.estimate.points > this.estimate.max;
215
+ }
216
+ onTranscriptBudget(n) {
217
+ this.controls?.setViewState({ transcriptBudget: n });
218
+ }
219
+ onTranscriptColorBy(by) {
220
+ this.controls?.setViewState({ transcriptColorBy: by });
221
+ }
222
+ // PrimeNG's slider reports `number | undefined`; ignore the empty case rather than
223
+ // writing `undefined` into the store.
224
+ onTranscriptScale(value) {
225
+ if (value === undefined)
226
+ return;
227
+ this.controls?.setViewState({ transcriptScale: value });
228
+ }
229
+ onTranscriptOpacity(value) {
230
+ if (value === undefined)
231
+ return;
232
+ this.controls?.setViewState({ transcriptOpacity: value });
233
+ }
234
+ onTranscriptQuality(includeLow) {
235
+ this.controls?.setViewState({ transcriptQuality: includeLow ? 'all' : 'high' });
236
+ }
237
+ glyphOf(gene, slot) {
238
+ return this.view.transcriptGlyphs[gene] ?? defaultGlyphFor(slot);
239
+ }
240
+ onGlyph(gene, glyph) {
241
+ this.controls?.setViewState({ transcriptGlyphs: { ...this.view.transcriptGlyphs, [gene]: glyph } });
242
+ }
243
+ // ── density map ─────────────────────────────────────────────────────────
244
+ get densityOpacityPercent() {
245
+ return Math.round(this.view.densityOpacity * 100);
246
+ }
247
+ onDensityOpacity(value) {
248
+ if (value === undefined)
249
+ return;
250
+ this.controls?.setViewState({ densityOpacity: value });
251
+ }
252
+ onDensityOpacityPercent(v) {
253
+ if (v === null || !Number.isFinite(v))
254
+ return;
255
+ this.controls?.setViewState({ densityOpacity: Math.min(1, Math.max(0.05, v / 100)) });
256
+ }
257
+ get densityBinIndex() {
258
+ return Math.max(0, this.densityBins.indexOf(this.view.densityBin));
259
+ }
260
+ onDensityBinIndex(i) {
261
+ if (i === undefined)
262
+ return;
263
+ this.controls?.setViewState({ densityBin: this.densityBins[i] ?? 10 });
264
+ }
265
+ onDensityRange(range) {
266
+ if (!range || range.length !== 2)
267
+ return;
268
+ this.controls?.setViewState({ densityRange: [Math.min(range[0], range[1]), Math.max(range[0], range[1])] });
269
+ }
270
+ onDensityRangeEnd(which, v) {
271
+ if (v === null || !Number.isFinite(v))
272
+ return;
273
+ const next = [...this.densityWindow];
274
+ next[which] = v;
275
+ this.onDensityRange(next);
276
+ }
277
+ onDensityAuto() {
278
+ this.controls?.setViewState({ densityRange: null });
279
+ }
280
+ onDensityColormap(node) {
281
+ this.selectedDensityColormapNode = node;
282
+ this.controls?.setViewState({ densityColormap: node?.data?.value ?? null });
283
+ }
284
+ refreshDensityWindow() {
285
+ const next = this.view.densityRange ?? (this.densityStats ? [this.densityStats.lo, this.densityStats.hi] : [0, 1]);
286
+ if (next[0] !== this.densityWindow[0] || next[1] !== this.densityWindow[1])
287
+ this.densityWindow = next;
288
+ this.densitySliderMax = Math.max(this.densityStats?.max ?? 1, this.densityWindow[1]);
289
+ this.densityStep = this.densitySliderMax / 200;
290
+ }
291
+ /** '⋮' menu. */
292
+ buildGeneMenu() {
293
+ return [
294
+ {
295
+ label: 'Add marker genes of clusters…',
296
+ icon: 'pi pi-sitemap',
297
+ disabled: !this.canAddMarkers,
298
+ command: () => this.openMarkers(),
299
+ },
300
+ {
301
+ label: 'New group from selected genes',
302
+ icon: 'pi pi-folder-plus',
303
+ disabled: !this.view.transcriptGenes.length,
304
+ command: () => this.onNewGeneGroup(),
305
+ },
306
+ {
307
+ label: 'Import gene groups (CSV)…',
308
+ icon: 'pi pi-upload',
309
+ command: () => this.geneGroupFileRef?.nativeElement.click(),
310
+ },
311
+ {
312
+ label: 'Remove gene groups',
313
+ icon: 'pi pi-times',
314
+ disabled: !this.view.transcriptGeneGroups.length,
315
+ command: () => this.controls?.setViewState({ transcriptGeneGroups: [] }),
316
+ },
317
+ {
318
+ label: 'Clear selection',
319
+ icon: 'pi pi-ban',
320
+ disabled: !this.view.transcriptGenes.length,
321
+ command: () => this.controls?.setViewState({ transcriptGenes: [], transcriptHiddenGenes: [] }),
322
+ },
323
+ ];
324
+ }
325
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialTranscriptsPanelComponent, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
326
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialTranscriptsPanelComponent, isStandalone: true, selector: "spatial-transcripts-panel", inputs: { controls: "controls", dataset: "dataset", view: "view", genes: "genes", estimate: "estimate", densityStats: "densityStats", geneCounts: "geneCounts", colormapOptions: "colormapOptions", open: "open" }, outputs: { openChange: "openChange" }, viewQueries: [{ propertyName: "geneGroupFileRef", first: true, predicate: ["geneGroupFile"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<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.transcriptMode !== 'off'\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onTranscriptsOn($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Transcripts</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 <div class=\"sc-row sc-row-picker\">\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <p-multiSelect\n inputId=\"sc-tx-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptGenes\"\n (onChange)=\"onTranscriptGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\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 for genes to visualize\u2026\"\n [selectedItemsLabel]=\"'{0} genes selected'\"\n [maxSelectedLabels]=\"0\"\n styleClass=\"sc-full\"\n ></p-multiSelect>\n </ng-container>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n *ngIf=\"canShowAllGenes\"\n (click)=\"onToggleAllGenes()\"\n [class.active]=\"view.transcriptAllGenes\"\n [title]=\"view.transcriptAllGenes ? 'Back to the selected genes' : 'Select all genes'\"\n >\n \u00B1\n </button>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"geneMenuRef.toggle($event)\" title=\"More\">\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n <p-menu #geneMenuRef [model]=\"geneMenu\" [popup]=\"true\" appendTo=\"body\"></p-menu>\n <input\n #geneGroupFile\n type=\"file\"\n accept=\".csv,.tsv,.txt\"\n hidden\n (change)=\"onImportGeneGroups(geneGroupFile)\"\n />\n </div>\n <small class=\"sc-hint sc-error\" *ngIf=\"geneGroupError\">{{ geneGroupError }}</small>\n <small class=\"sc-hint\" *ngIf=\"allGenesPreparing\">{{ allGenesPreparing }}</small>\n\n <spatial-marker-genes-form\n [controls]=\"controls\"\n [dataset]=\"dataset\"\n [view]=\"view\"\n [open]=\"markersOpen\"\n (openChange)=\"markersOpen = $event\"\n ></spatial-marker-genes-form>\n\n <spatial-gene-tree\n [controls]=\"controls\"\n [dataset]=\"dataset\"\n [view]=\"view\"\n [geneCounts]=\"geneCounts\"\n [geneTotal]=\"geneTotal\"\n ></spatial-gene-tree>\n\n <div class=\"sc-subhead\">Transcript controls</div>\n <span class=\"sc-lbl\">View transcripts as</span>\n <p-selectButton\n [options]=\"transcriptModeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptMode === 'off' ? null : view.transcriptMode\"\n (ngModelChange)=\"onTranscriptMode($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n\n <ng-container *ngIf=\"estimate\">\n <div class=\"sc-row\">\n <span\n class=\"sc-lbl\"\n pTooltip=\"Transcripts of the visible genes estimated to be in view, against the most markers drawn at once\"\n tooltipPosition=\"top\"\n >Estimated Transcript Points</span\n >\n <button type=\"button\" class=\"sc-small-btn\" (click)=\"editingMax = !editingMax\">Edit Max</button>\n </div>\n <div class=\"sc-meter\">\n <div class=\"sc-meter-fill\" [class.over]=\"estimateOverMax\" [style.width.%]=\"estimatePercent\"></div>\n </div>\n <div class=\"sc-meter-ends\">\n <span>{{ estimate.points | number }} points</span>\n <span>{{ estimate.max | number }} max{{ estimateOverMax ? ' reached' : '' }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"editingMax\">\n <span class=\"sc-lbl\">Max markers</span>\n <p-dropdown\n [options]=\"budgetOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptBudget\"\n (ngModelChange)=\"onTranscriptBudget($event)\"\n appendTo=\"body\"\n ></p-dropdown>\n </div>\n <small class=\"sc-hint\" *ngIf=\"estimateOverMax && view.transcriptMode !== 'density'\">\n Max points reached: transcripts are grouped by area, circles sized by how many they hold. Zoom in or select\n fewer genes to see individual points.\n </small>\n </ng-container>\n\n <ng-container *ngIf=\"view.transcriptMode === 'circles' || view.transcriptMode === 'glyphs'\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Colour by</span>\n <p-selectButton\n [options]=\"transcriptColorOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptColorBy\"\n (ngModelChange)=\"onTranscriptColorBy($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n </div>\n <small\n class=\"sc-hint\"\n *ngIf=\"view.transcriptAllGenes && view.transcriptColorBy === 'gene' && estimateOverMax\"\n >\n Grouped markers mix genes, so they are coloured by cell type until you zoom in to individual transcripts.\n </small>\n <div class=\"sc-row\" *ngIf=\"view.transcriptAllGenes && view.transcriptMode === 'glyphs'\">\n <span class=\"sc-lbl\">Icon</span>\n <p-dropdown\n [options]=\"glyphOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"glyphOf('*', 0)\"\n (ngModelChange)=\"onGlyph('*', $event)\"\n appendTo=\"body\"\n styleClass=\"sc-glyph-pick\"\n >\n <ng-template let-opt pTemplate=\"item\">\n <span class=\"sc-glyph-option\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt.points\"></polygon>\n </svg>\n {{ opt.label }}\n </span>\n </ng-template>\n <ng-template let-opt pTemplate=\"selectedItem\">\n <span class=\"sc-glyph-option\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt?.points\"></polygon>\n </svg>\n </span>\n </ng-template>\n </p-dropdown>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Size</span>\n <p-slider\n [ngModel]=\"view.transcriptScale\"\n [min]=\"0.5\"\n [max]=\"3\"\n [step]=\"0.25\"\n (onChange)=\"onTranscriptScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.transcriptScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.transcriptOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onTranscriptOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.transcriptOpacity }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"!showingAllGenes\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.transcriptQuality === 'all'\"\n inputId=\"sc-tx-lowq\"\n (onChange)=\"onTranscriptQuality($event.checked)\"\n ></p-checkbox>\n <label class=\"sc-lbl\" for=\"sc-tx-lowq\">Include low-quality calls</label>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"view.transcriptMode === 'density'\">\n <span class=\"sc-lbl\">Density map opacity</span>\n <div class=\"sc-row sc-row-number\">\n <p-slider\n [ngModel]=\"view.densityOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onDensityOpacity($event.value)\"\n ></p-slider>\n <p-inputNumber\n [ngModel]=\"densityOpacityPercent\"\n (ngModelChange)=\"onDensityOpacityPercent($event)\"\n [min]=\"5\"\n [max]=\"100\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n </div>\n <span class=\"sc-lbl\" pTooltip=\"Edge of each density bin\" tooltipPosition=\"top\">Density map bin size</span>\n <p-slider\n [ngModel]=\"densityBinIndex\"\n [min]=\"0\"\n [max]=\"3\"\n [step]=\"1\"\n (onChange)=\"onDensityBinIndex($event.value)\"\n styleClass=\"sc-bin-slider\"\n ></p-slider>\n <div class=\"sc-ticks\">\n <span *ngFor=\"let b of densityBins\">{{ b }}\u00D7{{ b }}\u00B5m</span>\n </div>\n <span\n class=\"sc-lbl\"\n pTooltip=\"Transcripts per \u00B5m\u00B2 at which the colour scale starts and saturates\"\n tooltipPosition=\"top\"\n >Density map scale threshold</span\n >\n <div class=\"sc-row sc-row-range\">\n <p-inputNumber\n [ngModel]=\"densityWindow[0]\"\n (ngModelChange)=\"onDensityRangeEnd(0, $event)\"\n mode=\"decimal\"\n [minFractionDigits]=\"3\"\n [maxFractionDigits]=\"3\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n <p-slider\n [ngModel]=\"densityWindow\"\n [range]=\"true\"\n [min]=\"0\"\n [max]=\"densitySliderMax\"\n [step]=\"densityStep\"\n (onChange)=\"onDensityRange($event.values)\"\n ></p-slider>\n <p-inputNumber\n [ngModel]=\"densityWindow[1]\"\n (ngModelChange)=\"onDensityRangeEnd(1, $event)\"\n mode=\"decimal\"\n [minFractionDigits]=\"3\"\n [maxFractionDigits]=\"3\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n </div>\n <div class=\"sc-row\">\n <small class=\"sc-hint\">{{ view.densityRange ? 'Set by hand.' : 'Derived from the data.' }}</small>\n <button type=\"button\" class=\"sc-small-btn\" *ngIf=\"view.densityRange\" (click)=\"onDensityAuto()\">\n Auto\n </button>\n </div>\n <span class=\"sc-lbl\">Density map bin coloring</span>\n <div class=\"sc-row sc-row-picker\">\n <div class=\"sc-colorbar sc-full\" [style.background]=\"densityColorBarCss\"></div>\n <p-treeSelect\n [options]=\"colormapOptions\"\n [ngModel]=\"selectedDensityColormapNode\"\n selectionMode=\"single\"\n [showClear]=\"true\"\n placeholder=\"Inferno\"\n [scrollHeight]=\"'260px'\"\n appendTo=\"body\"\n styleClass=\"sc-palette\"\n (onNodeSelect)=\"onDensityColormap($event.node)\"\n (onClear)=\"onDensityColormap(null)\"\n >\n <ng-template let-node pTemplate=\"default\">\n <span class=\"sc-cmap-option\">\n <img *ngIf=\"!node.children && node.data?.src\" [src]=\"node.data.src\" class=\"sc-cmap-swatch\" alt=\"\" />\n <span>{{ node.label }}</span>\n </span>\n </ng-template>\n </p-treeSelect>\n </div>\n <div class=\"sc-colorbar-ends\">\n <span>{{ densityWindow[0] | number: '1.0-3' }}</span\n ><span>{{ densityWindow[1] | number: '1.0-3' }}</span>\n </div>\n </ng-container>\n </div>\n</div>\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}.sc-meter{height:.45rem;border-radius:3px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-meter-fill{height:100%;background:var(--primary-color, #2196f3)}.sc-meter-fill.over{background:var(--orange-500, #f59e0b)}.sc-meter-ends,.sc-ticks{display:flex;justify-content:space-between;font-size:.72rem;font-weight:600;color:var(--text-color-secondary, #6c757d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { 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: SharedModule }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4.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: i5.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i6.InputNumber, selector: "p-inputNumber", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i7.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "directive", type: i8.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i9.MultiSelect, selector: "p-multiSelect", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i10.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey", "autofocus"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i11.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: "ngmodule", type: TreeSelectModule }, { kind: "component", type: i12.TreeSelect, selector: "p-treeSelect", inputs: ["inputId", "scrollHeight", "disabled", "metaKeySelection", "variant", "display", "selectionMode", "tabindex", "ariaLabel", "ariaLabelledBy", "placeholder", "panelClass", "panelStyle", "panelStyleClass", "containerStyle", "containerStyleClass", "labelStyle", "labelStyleClass", "overlayOptions", "emptyMessage", "appendTo", "filter", "filterBy", "filterMode", "filterPlaceholder", "filterLocale", "filterInputAutoFocus", "propagateSelectionDown", "propagateSelectionUp", "showClear", "resetFilterOnHide", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autofocus", "options", "showTransitionOptions", "hideTransitionOptions", "loading"], outputs: ["onNodeExpand", "onNodeCollapse", "onShow", "onHide", "onClear", "onFilter", "onFocus", "onBlur", "onNodeUnselect", "onNodeSelect"] }, { kind: "component", type: SpatialGeneTreeComponent, selector: "spatial-gene-tree", inputs: ["controls", "dataset", "view", "geneCounts", "geneTotal"] }, { kind: "component", type: SpatialMarkerGenesFormComponent, selector: "spatial-marker-genes-form", inputs: ["controls", "dataset", "view", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
327
+ }
328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialTranscriptsPanelComponent, decorators: [{
329
+ type: Component,
330
+ args: [{ selector: 'spatial-transcripts-panel', standalone: true, imports: [
331
+ CommonModule,
332
+ FormsModule,
333
+ SharedModule,
334
+ CheckboxModule,
335
+ DropdownModule,
336
+ InputNumberModule,
337
+ MenuModule,
338
+ MultiSelectModule,
339
+ SelectButtonModule,
340
+ SliderModule,
341
+ TooltipModule,
342
+ TreeSelectModule,
343
+ SpatialGeneTreeComponent,
344
+ SpatialMarkerGenesFormComponent,
345
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<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.transcriptMode !== 'off'\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onTranscriptsOn($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Transcripts</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 <div class=\"sc-row sc-row-picker\">\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <p-multiSelect\n inputId=\"sc-tx-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptGenes\"\n (onChange)=\"onTranscriptGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\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 for genes to visualize\u2026\"\n [selectedItemsLabel]=\"'{0} genes selected'\"\n [maxSelectedLabels]=\"0\"\n styleClass=\"sc-full\"\n ></p-multiSelect>\n </ng-container>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n *ngIf=\"canShowAllGenes\"\n (click)=\"onToggleAllGenes()\"\n [class.active]=\"view.transcriptAllGenes\"\n [title]=\"view.transcriptAllGenes ? 'Back to the selected genes' : 'Select all genes'\"\n >\n \u00B1\n </button>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"geneMenuRef.toggle($event)\" title=\"More\">\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n <p-menu #geneMenuRef [model]=\"geneMenu\" [popup]=\"true\" appendTo=\"body\"></p-menu>\n <input\n #geneGroupFile\n type=\"file\"\n accept=\".csv,.tsv,.txt\"\n hidden\n (change)=\"onImportGeneGroups(geneGroupFile)\"\n />\n </div>\n <small class=\"sc-hint sc-error\" *ngIf=\"geneGroupError\">{{ geneGroupError }}</small>\n <small class=\"sc-hint\" *ngIf=\"allGenesPreparing\">{{ allGenesPreparing }}</small>\n\n <spatial-marker-genes-form\n [controls]=\"controls\"\n [dataset]=\"dataset\"\n [view]=\"view\"\n [open]=\"markersOpen\"\n (openChange)=\"markersOpen = $event\"\n ></spatial-marker-genes-form>\n\n <spatial-gene-tree\n [controls]=\"controls\"\n [dataset]=\"dataset\"\n [view]=\"view\"\n [geneCounts]=\"geneCounts\"\n [geneTotal]=\"geneTotal\"\n ></spatial-gene-tree>\n\n <div class=\"sc-subhead\">Transcript controls</div>\n <span class=\"sc-lbl\">View transcripts as</span>\n <p-selectButton\n [options]=\"transcriptModeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptMode === 'off' ? null : view.transcriptMode\"\n (ngModelChange)=\"onTranscriptMode($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n\n <ng-container *ngIf=\"estimate\">\n <div class=\"sc-row\">\n <span\n class=\"sc-lbl\"\n pTooltip=\"Transcripts of the visible genes estimated to be in view, against the most markers drawn at once\"\n tooltipPosition=\"top\"\n >Estimated Transcript Points</span\n >\n <button type=\"button\" class=\"sc-small-btn\" (click)=\"editingMax = !editingMax\">Edit Max</button>\n </div>\n <div class=\"sc-meter\">\n <div class=\"sc-meter-fill\" [class.over]=\"estimateOverMax\" [style.width.%]=\"estimatePercent\"></div>\n </div>\n <div class=\"sc-meter-ends\">\n <span>{{ estimate.points | number }} points</span>\n <span>{{ estimate.max | number }} max{{ estimateOverMax ? ' reached' : '' }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"editingMax\">\n <span class=\"sc-lbl\">Max markers</span>\n <p-dropdown\n [options]=\"budgetOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptBudget\"\n (ngModelChange)=\"onTranscriptBudget($event)\"\n appendTo=\"body\"\n ></p-dropdown>\n </div>\n <small class=\"sc-hint\" *ngIf=\"estimateOverMax && view.transcriptMode !== 'density'\">\n Max points reached: transcripts are grouped by area, circles sized by how many they hold. Zoom in or select\n fewer genes to see individual points.\n </small>\n </ng-container>\n\n <ng-container *ngIf=\"view.transcriptMode === 'circles' || view.transcriptMode === 'glyphs'\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Colour by</span>\n <p-selectButton\n [options]=\"transcriptColorOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.transcriptColorBy\"\n (ngModelChange)=\"onTranscriptColorBy($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n </div>\n <small\n class=\"sc-hint\"\n *ngIf=\"view.transcriptAllGenes && view.transcriptColorBy === 'gene' && estimateOverMax\"\n >\n Grouped markers mix genes, so they are coloured by cell type until you zoom in to individual transcripts.\n </small>\n <div class=\"sc-row\" *ngIf=\"view.transcriptAllGenes && view.transcriptMode === 'glyphs'\">\n <span class=\"sc-lbl\">Icon</span>\n <p-dropdown\n [options]=\"glyphOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"glyphOf('*', 0)\"\n (ngModelChange)=\"onGlyph('*', $event)\"\n appendTo=\"body\"\n styleClass=\"sc-glyph-pick\"\n >\n <ng-template let-opt pTemplate=\"item\">\n <span class=\"sc-glyph-option\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt.points\"></polygon>\n </svg>\n {{ opt.label }}\n </span>\n </ng-template>\n <ng-template let-opt pTemplate=\"selectedItem\">\n <span class=\"sc-glyph-option\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt?.points\"></polygon>\n </svg>\n </span>\n </ng-template>\n </p-dropdown>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Size</span>\n <p-slider\n [ngModel]=\"view.transcriptScale\"\n [min]=\"0.5\"\n [max]=\"3\"\n [step]=\"0.25\"\n (onChange)=\"onTranscriptScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.transcriptScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.transcriptOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onTranscriptOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.transcriptOpacity }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"!showingAllGenes\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.transcriptQuality === 'all'\"\n inputId=\"sc-tx-lowq\"\n (onChange)=\"onTranscriptQuality($event.checked)\"\n ></p-checkbox>\n <label class=\"sc-lbl\" for=\"sc-tx-lowq\">Include low-quality calls</label>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"view.transcriptMode === 'density'\">\n <span class=\"sc-lbl\">Density map opacity</span>\n <div class=\"sc-row sc-row-number\">\n <p-slider\n [ngModel]=\"view.densityOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onDensityOpacity($event.value)\"\n ></p-slider>\n <p-inputNumber\n [ngModel]=\"densityOpacityPercent\"\n (ngModelChange)=\"onDensityOpacityPercent($event)\"\n [min]=\"5\"\n [max]=\"100\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n </div>\n <span class=\"sc-lbl\" pTooltip=\"Edge of each density bin\" tooltipPosition=\"top\">Density map bin size</span>\n <p-slider\n [ngModel]=\"densityBinIndex\"\n [min]=\"0\"\n [max]=\"3\"\n [step]=\"1\"\n (onChange)=\"onDensityBinIndex($event.value)\"\n styleClass=\"sc-bin-slider\"\n ></p-slider>\n <div class=\"sc-ticks\">\n <span *ngFor=\"let b of densityBins\">{{ b }}\u00D7{{ b }}\u00B5m</span>\n </div>\n <span\n class=\"sc-lbl\"\n pTooltip=\"Transcripts per \u00B5m\u00B2 at which the colour scale starts and saturates\"\n tooltipPosition=\"top\"\n >Density map scale threshold</span\n >\n <div class=\"sc-row sc-row-range\">\n <p-inputNumber\n [ngModel]=\"densityWindow[0]\"\n (ngModelChange)=\"onDensityRangeEnd(0, $event)\"\n mode=\"decimal\"\n [minFractionDigits]=\"3\"\n [maxFractionDigits]=\"3\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n <p-slider\n [ngModel]=\"densityWindow\"\n [range]=\"true\"\n [min]=\"0\"\n [max]=\"densitySliderMax\"\n [step]=\"densityStep\"\n (onChange)=\"onDensityRange($event.values)\"\n ></p-slider>\n <p-inputNumber\n [ngModel]=\"densityWindow[1]\"\n (ngModelChange)=\"onDensityRangeEnd(1, $event)\"\n mode=\"decimal\"\n [minFractionDigits]=\"3\"\n [maxFractionDigits]=\"3\"\n inputStyleClass=\"sc-num\"\n ></p-inputNumber>\n </div>\n <div class=\"sc-row\">\n <small class=\"sc-hint\">{{ view.densityRange ? 'Set by hand.' : 'Derived from the data.' }}</small>\n <button type=\"button\" class=\"sc-small-btn\" *ngIf=\"view.densityRange\" (click)=\"onDensityAuto()\">\n Auto\n </button>\n </div>\n <span class=\"sc-lbl\">Density map bin coloring</span>\n <div class=\"sc-row sc-row-picker\">\n <div class=\"sc-colorbar sc-full\" [style.background]=\"densityColorBarCss\"></div>\n <p-treeSelect\n [options]=\"colormapOptions\"\n [ngModel]=\"selectedDensityColormapNode\"\n selectionMode=\"single\"\n [showClear]=\"true\"\n placeholder=\"Inferno\"\n [scrollHeight]=\"'260px'\"\n appendTo=\"body\"\n styleClass=\"sc-palette\"\n (onNodeSelect)=\"onDensityColormap($event.node)\"\n (onClear)=\"onDensityColormap(null)\"\n >\n <ng-template let-node pTemplate=\"default\">\n <span class=\"sc-cmap-option\">\n <img *ngIf=\"!node.children && node.data?.src\" [src]=\"node.data.src\" class=\"sc-cmap-swatch\" alt=\"\" />\n <span>{{ node.label }}</span>\n </span>\n </ng-template>\n </p-treeSelect>\n </div>\n <div class=\"sc-colorbar-ends\">\n <span>{{ densityWindow[0] | number: '1.0-3' }}</span\n ><span>{{ densityWindow[1] | number: '1.0-3' }}</span>\n </div>\n </ng-container>\n </div>\n</div>\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}.sc-meter{height:.45rem;border-radius:3px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-meter-fill{height:100%;background:var(--primary-color, #2196f3)}.sc-meter-fill.over{background:var(--orange-500, #f59e0b)}.sc-meter-ends,.sc-ticks{display:flex;justify-content:space-between;font-size:.72rem;font-weight:600;color:var(--text-color-secondary, #6c757d)}\n"] }]
346
+ }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { controls: [{
347
+ type: Input
348
+ }], dataset: [{
349
+ type: Input
350
+ }], view: [{
351
+ type: Input
352
+ }], genes: [{
353
+ type: Input
354
+ }], estimate: [{
355
+ type: Input
356
+ }], densityStats: [{
357
+ type: Input
358
+ }], geneCounts: [{
359
+ type: Input
360
+ }], colormapOptions: [{
361
+ type: Input
362
+ }], open: [{
363
+ type: Input
364
+ }], openChange: [{
365
+ type: Output
366
+ }], geneGroupFileRef: [{
367
+ type: ViewChild,
368
+ args: ['geneGroupFile']
369
+ }] } });
370
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC10cmFuc2NyaXB0cy1wYW5lbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NwYXRpYWwtY29udHJvbHMvc3BhdGlhbC10cmFuc2NyaXB0cy1wYW5lbC9zcGF0aWFsLXRyYW5zY3JpcHRzLXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLXRyYW5zY3JpcHRzLXBhbmVsL3NwYXRpYWwtdHJhbnNjcmlwdHMtcGFuZWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFFTixNQUFNLEVBRU4sU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDMUMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFB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LE1BQU07MkdBSXRDLFFBQVE7c0JBQWhCLEtBQUs7Z0JBRUcsT0FBTztzQkFBZixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFRyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFFRyxZQUFZO3NCQUFwQixLQUFLO2dCQUVHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBRUcsZUFBZTtzQkFBdkIsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRWEsVUFBVTtzQkFBNUIsTUFBTTtnQkFpRDZCLGdCQUFnQjtzQkFBbkQsU0FBUzt1QkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE5nWm9uZSxcbiAgT25DaGFuZ2VzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTaGFyZWRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2FwaSc7XG5pbXBvcnQgeyBDaGVja2JveE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvY2hlY2tib3gnO1xuaW1wb3J0IHsgRHJvcGRvd25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2Ryb3Bkb3duJztcbmltcG9ydCB7IElucHV0TnVtYmVyTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dG51bWJlcic7XG5pbXBvcnQgeyBNZW51TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9tZW51JztcbmltcG9ydCB7IE11bHRpU2VsZWN0TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9tdWx0aXNlbGVjdCc7XG5pbXBvcnQgeyBTZWxlY3RCdXR0b25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL3NlbGVjdGJ1dHRvbic7XG5pbXBvcnQgeyBTbGlkZXJNb2R1bGUgfSBmcm9tICdwcmltZW5nL3NsaWRlcic7XG5pbXBvcnQgeyBUb29sdGlwTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90b29sdGlwJztcbmltcG9ydCB7IFRyZWVTZWxlY3RNb2R1bGUgfSBmcm9tICdwcmltZW5nL3RyZWVzZWxlY3QnO1xuXG5pbXBvcnQgdHlwZSB7IElTcGF0aWFsQ29udHJvbHMgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvdmlzdWFsaXplci5jb250cmFjdCc7XG5pbXBvcnQgdHlwZSB7IFNwYXRpYWxEYXRhc2V0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQge1xuICBDb2xvcm1hcE5vZGUsXG4gIERFRkFVTFRfU1BBVElBTF9WSUVXLFxuICBTcGF0aWFsVmlld1N0YXRlLFxuICBUcmFuc2NyaXB0R2x5cGhOYW1lLFxufSBmcm9tICcuLi8uLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQgeyBkZWZhdWx0R2x5cGhGb3IgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtdGlsZXMnO1xuaW1wb3J0IHtcbiAgR0xZUEhfT1BUSU9OUyxcbiAgUGFuZWxPcHRpb24sXG4gIGFsbEdlbmVzUHJlcGFyaW5nTm90ZSxcbiAgZGVuc2l0eUNvbG9yQmFyQ3NzLFxuICBpbXBvcnRHZW5lR3JvdXBzUGF0Y2gsXG4gIG1hcmtlckNvbHVtbk9wdGlvbnMsXG4gIHBhcnNlR2VuZUdyb3VwcyxcbiAgdGlsZU9wdGlvbnMsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgdHlwZSB7IEdlbmVQaWNrZXJNb2RlbCB9IGZyb20gJy4uL3NwYXRpYWwtZ2VuZS1waWNrZXInO1xuaW1wb3J0IHsgY29sb3JtYXBOb2RlRm9yIH0gZnJvbSAnLi4vc3BhdGlhbC1rZXkvc3BhdGlhbC1rZXkuY29tcG9uZW50JztcbmltcG9ydCB7IFNwYXRpYWxHZW5lVHJlZUNvbXBvbmVudCB9IGZyb20gJy4uL3NwYXRpYWwtZ2VuZS10cmVlL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTcGF0aWFsTWFya2VyR2VuZXNGb3JtQ29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1tYXJrZXItZ2VuZXMtZm9ybS9zcGF0aWFsLW1hcmtlci1nZW5lcy1mb3JtLmNvbXBvbmVudCc7XG5cbi8qKiBPbmUgaXRlbSBvZiB0aGUgZ2VuZSBsaXN0J3MgJ+KLricgbWVudS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2VuZU1lbnVJdGVtIHtcbiAgbGFiZWw6IHN0cmluZztcbiAgaWNvbjogc3RyaW5nO1xuICBjb21tYW5kOiAoKSA9PiB2b2lkO1xuICBkaXNhYmxlZD86IGJvb2xlYW47XG59XG5cbi8qKlxuICogVGhlIFRyYW5zY3JpcHRzIHNlY3Rpb24sIGFzIFhlbml1bSBFeHBsb3JlcidzOiB0aGUgb24vb2ZmIHN3aXRjaCwgdGhlIHRyYW5zY3JpcHQgZ2VuZXNcbiAqICh3aXRoIFwiQWxsIGdlbmVzXCIsIHRoZSAn4ouuJyBtZW51IGFuZCBnZW5lLWdyb3VwIGltcG9ydCksIHRoZVxuICoge0BsaW5rIFNwYXRpYWxNYXJrZXJHZW5lc0Zvcm1Db21wb25lbnQgbWFya2VyLWdlbmVzIGZvcm19LCB0aGVcbiAqIHtAbGluayBTcGF0aWFsR2VuZVRyZWVDb21wb25lbnQgZ2VuZSB0cmVlfSwgaG93IHRyYW5zY3JpcHRzIGFyZSBkcmF3biDigJQgdGhlIHBvaW50c1xuICogZXN0aW1hdGUgYWdhaW5zdCBpdHMgYnVkZ2V0LCBjb2xvdXJpbmcsIGljb24sIHNpemUsIG9wYWNpdHkgYW5kIHF1YWxpdHkg4oCUIGFuZCB0aGVcbiAqIGRlbnNpdHkgbWFwJ3Mgb3BhY2l0eSwgYmluIHNpemUsIHRocmVzaG9sZCB3aW5kb3cgYW5kIGNvbG9ybWFwLlxuICpcbiAqIFdyaXRlcyBvbmx5IHRocm91Z2ggYGNvbnRyb2xzLnNldFZpZXdTdGF0ZWAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NwYXRpYWwtdHJhbnNjcmlwdHMtcGFuZWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIFNoYXJlZE1vZHVsZSxcbiAgICBDaGVja2JveE1vZHVsZSxcbiAgICBEcm9wZG93bk1vZHVsZSxcbiAgICBJbnB1dE51bWJlck1vZHVsZSxcbiAgICBNZW51TW9kdWxlLFxuICAgIE11bHRpU2VsZWN0TW9kdWxlLFxuICAgIFNlbGVjdEJ1dHRvbk1vZHVsZSxcbiAgICBTbGlkZXJNb2R1bGUsXG4gICAgVG9vbHRpcE1vZHVsZSxcbiAgICBUcmVlU2VsZWN0TW9kdWxlLFxuICAgIFNwYXRpYWxHZW5lVHJlZUNvbXBvbmVudCxcbiAgICBTcGF0aWFsTWFya2VyR2VuZXNGb3JtQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vc3BhdGlhbC10cmFuc2NyaXB0cy1wYW5lbC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NwYXRpYWwtdHJhbnNjcmlwdHMtcGFuZWwuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNwYXRpYWxUcmFuc2NyaXB0c1BhbmVsQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLyoqIFRoZSBzcGF0aWFsIGNvbnRyb2xzIHRoaXMgcGFuZWwgcmVhZHMgYW5kIHdyaXRlcyB0aHJvdWdoOyBudWxsIHdpdGhvdXQgYSBgU1BBVElBTF9EQVRBX1BPUlRgLiAqL1xuICBASW5wdXQoKSBjb250cm9sczogSVNwYXRpYWxDb250cm9scyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGRhdGFzZXQgb24gb2ZmZXIsIG9yIG51bGwuICovXG4gIEBJbnB1dCgpIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgY3VycmVudCBzcGF0aWFsIHZpZXcgc3RhdGU6IHdoYXQgaXMgZHJhd24sIGFuZCBob3cuICovXG4gIEBJbnB1dCgpIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUgPSBERUZBVUxUX1NQQVRJQUxfVklFVztcbiAgLyoqIFRoZSBnZW5lIGxpc3QgdGhlIHRyYW5zY3JpcHQgZ2VuZXMgYXJlIHBpY2tlZCBmcm9tLCBzaGFyZWQgd2l0aCB0aGUgb3RoZXIgZ2VuZSBkcm9wZG93bnMuICovXG4gIEBJbnB1dCgpIGdlbmVzOiBHZW5lUGlja2VyTW9kZWwgfCBudWxsID0gbnVsbDtcbiAgLyoqIEVzdGltYXRlZCB0cmFuc2NyaXB0cyBpbiB2aWV3LCBhZ2FpbnN0IHRoZSBidWRnZXQg4oCUIEV4cGxvcmVyJ3MgcG9pbnRzIGJhci4gKi9cbiAgQElucHV0KCkgZXN0aW1hdGU6IHsgcG9pbnRzOiBudW1iZXI7IG1heDogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBkZW5zaXR5IHdpbmRvdyBpbiB1c2UgYW5kIGl0cyBkZW5zZXN0IGJpbiwgZm9yIHRoZSB0aHJlc2hvbGQgY29udHJvbC4gKi9cbiAgQElucHV0KCkgZGVuc2l0eVN0YXRzOiB7IGxvOiBudW1iZXI7IGhpOiBudW1iZXI7IG1heDogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIGVhY2ggc2VsZWN0ZWQgZ2VuZSBpbiB0aGUgY3VycmVudCB2aWV3LCBmcm9tIHRoZSByZW5kZXJlci4gKi9cbiAgQElucHV0KCkgZ2VuZUNvdW50czogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB8IG51bGwgPSBudWxsO1xuICAvKiogQ29sb3JtYXAgdHJlZSBmb3IgdGhlIGRlbnNpdHkgbWFwJ3MgY29sb3VyaW5nLiAqL1xuICBASW5wdXQoKSBjb2xvcm1hcE9wdGlvbnM6IENvbG9ybWFwTm9kZVtdID0gW107XG4gIC8qKiBXaGV0aGVyIHRoZSBzZWN0aW9uIGlzIGV4cGFuZGVkLiAqL1xuICBASW5wdXQoKSBvcGVuID0gZmFsc2U7XG4gIC8qKiBBc2tzIHRvIG9wZW4gb3IgY2xvc2UgaXQ7IHR3by13YXkgd2l0aCBgb3BlbmAuICovXG4gIEBPdXRwdXQoKSByZWFkb25seSBvcGVuQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gIC8qKiBWaXJ0dWFsLXNjcm9sbGVkIG9ubHkgcGFzdCB0aGlzIG1hbnkgb3B0aW9ucyAoc2VlIHRoZSBjZWxscyBwYW5lbCdzIGdlbmUgZHJvcGRvd24pLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZ2VuZVZpcnR1YWxTY3JvbGxGcm9tID0gMjAwO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdHJhbnNjcmlwdENvbG9yT3B0aW9uczogUGFuZWxPcHRpb248U3BhdGlhbFZpZXdTdGF0ZVsndHJhbnNjcmlwdENvbG9yQnknXT5bXSA9IFtcbiAgICB7IGxhYmVsOiAnQ2x1c3RlcicsIHZhbHVlOiAnY2x1c3RlcicgfSxcbiAgICB7IGxhYmVsOiAnQ2VsbCB0eXBlJywgdmFsdWU6ICdjZWxsVHlwZScgfSxcbiAgICB7IGxhYmVsOiAnR2VuZScsIHZhbHVlOiAnZ2VuZScgfSxcbiAgXTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGdseXBoT3B0aW9ucyA9IEdMWVBIX09QVElPTlM7XG4gIHByb3RlY3RlZCByZWFkb25seSBidWRnZXRPcHRpb25zID0gWzI1XzAwMCwgNTBfMDAwLCAxMDBfMDAwLCAyMDBfMDAwLCA0MDBfMDAwXS5tYXAoKG4pID0+ICh7XG4gICAgbGFiZWw6IG4udG9Mb2NhbGVTdHJpbmcoKSxcbiAgICB2YWx1ZTogbixcbiAgfSkpO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVuc2l0eUJpbnMgPSBbMTAsIDIwLCA0MCwgODBdO1xuXG4gIC8qKlxuICAgKiBUcmFuc2NyaXB0IG1vZGVzIG9uIG9mZmVyLiBCdWlsdCBvbmNlIHBlciBkYXRhc2V0IHJhdGhlciB0aGFuIGluIGEgZ2V0dGVyOiBhIGdldHRlclxuICAgKiByZXR1cm5zIGEgZnJlc2ggYXJyYXkgb24gZXZlcnkgY2hhbmdlLWRldGVjdGlvbiBwYXNzLCBhbmQgUHJpbWVORyByZS1yZW5kZXJzIGl0c1xuICAgKiBidXR0b25zIHdoZW5ldmVyIHRoZSBhcnJheSBpZGVudGl0eSBjaGFuZ2VzIOKAlCB3aGljaCBtYWRlIHRoZW0gaW1wb3NzaWJsZSB0byBjbGljay5cbiAgICovXG4gIHByb3RlY3RlZCB0cmFuc2NyaXB0TW9kZU9wdGlvbnM6IFBhbmVsT3B0aW9uPFNwYXRpYWxWaWV3U3RhdGVbJ3RyYW5zY3JpcHRNb2RlJ10+W10gPSBbXTtcbiAgLyoqIFRoZSAn4ouuJyBtZW51LCByZWJ1aWx0IHdoZW4gd2hhdCBlbmFibGVzIGl0cyBpdGVtcyBjaGFuZ2VzLiAqL1xuICBwcm90ZWN0ZWQgZ2VuZU1lbnU6IEdlbmVNZW51SXRlbVtdID0gW107XG4gIHByb3RlY3RlZCBlZGl0aW5nTWF4ID0gZmFsc2U7XG4gIC8qKiBXaGV0aGVyIHRoZSBtYXJrZXItZ2VuZXMgZm9ybSBpcyBzaG93bi4gKi9cbiAgcHJvdGVjdGVkIG1hcmtlcnNPcGVuID0gZmFsc2U7XG4gIHByb3RlY3RlZCBnZW5lR3JvdXBFcnJvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFRoZSB0aHJlc2hvbGQgd2luZG93IHNob3duOiB0aGUgb25lIHNldCwgZWxzZSB0aGUgb25lIGRlcml2ZWQuIEEgc3RvcmVkIGFycmF5LCBub3QgYVxuICAgKiBnZXR0ZXI6IGEgcmFuZ2Ugc2xpZGVyJ3MgYG5nTW9kZWxgIGdpdmVuIGEgZnJlc2ggYXJyYXkgZXZlcnkgY2hhbmdlLWRldGVjdGlvbiBwYXNzXG4gICAqIHNjaGVkdWxlcyBhbm90aGVyIHBhc3MsIGZvcmV2ZXIg4oCUIHdoaWNoIGh1bmcgdGhlIHBhZ2UgdGhlIG1vbWVudCB0aGUgZGVuc2l0eVxuICAgKiBjb250cm9scyBhcHBlYXJlZC5cbiAgICovXG4gIHByb3RlY3RlZCBkZW5zaXR5V2luZG93OiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDFdO1xuICBwcm90ZWN0ZWQgZGVuc2l0eVNsaWRlck1heCA9IDE7XG4gIHByb3RlY3RlZCBkZW5zaXR5U3RlcCA9IDAuMDA1O1xuICBwcm90ZWN0ZWQgc2VsZWN0ZWREZW5zaXR5Q29sb3JtYXBOb2RlOiBDb2xvcm1hcE5vZGUgfCBudWxsID0gbnVsbDtcbiAgLyoqIEJ1aWx0IG9uY2UgcGVyIGRlbnNpdHkgY29sb3JtYXA6IGEgMjU2LWVudHJ5IExVVCBwZXIgY2hhbmdlLWRldGVjdGlvbiBwYXNzIGlzIHdhc3RlLiAqL1xuICBwcm90ZWN0ZWQgZGVuc2l0eUNvbG9yQmFyQ3NzID0gJyc7XG4gIHByaXZhdGUgZGVuc2l0eUJhckZvcjogU3BhdGlhbFZpZXdTdGF0ZVsnZGVuc2l0eUNvbG9ybWFwJ10gfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbiAgLyoqIFRoZSBtb2RlIHRoZSBzZWN0aW9uIGhlYWRlcidzIHN3aXRjaCB0dXJucyBiYWNrIG9uLiAqL1xuICBwcml2YXRlIGxhc3RUcmFuc2NyaXB0TW9kZTogRXhjbHVkZTxTcGF0aWFsVmlld1N0YXRlWyd0cmFuc2NyaXB0TW9kZSddLCAnb2ZmJz4gPSAnY2lyY2xlcyc7XG4gIC8qKiBXaGV0aGVyIGFueSBjb2x1bW4gY2FuIHN1cHBseSBtYXJrZXIgZ2VuZXMnIGNsdXN0ZXJzLiAqL1xuICBwcml2YXRlIGhhc01hcmtlckNvbHVtbnMgPSBmYWxzZTtcblxuICAvKiogVGhlIGhpZGRlbiBmaWxlIGlucHV0IHRoZSBtZW51J3MgaW1wb3J0IG9wZW5zLiAqL1xuICBAVmlld0NoaWxkKCdnZW5lR3JvdXBGaWxlJykgcHJpdmF0ZSBnZW5lR3JvdXBGaWxlUmVmPzogRWxlbWVudFJlZjxIVE1MSW5wdXRFbGVtZW50PjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHpvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICkge31cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2RhdGFzZXQnXSkge1xuICAgICAgdGhpcy50cmFuc2NyaXB0TW9kZU9wdGlvbnMgPSB0aWxlT3B0aW9ucyh0aGlzLmRhdGFzZXQpLnRyYW5zY3JpcHRNb2RlT3B0aW9ucztcbiAgICAgIHRoaXMuaGFzTWFya2VyQ29sdW1ucyA9IG1hcmtlckNvbHVtbk9wdGlvbnModGhpcy5kYXRhc2V0Py5jb2x1bW5zKS5sZW5ndGggPiAwO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1sndmlldyddIHx8IGNoYW5nZXNbJ2RhdGFzZXQnXSB8fCBjaGFuZ2VzWydjb250cm9scyddKSB0aGlzLmdlbmVNZW51ID0gdGhpcy5idWlsZEdlbmVNZW51KCk7XG4gICAgaWYgKGNoYW5nZXNbJ3ZpZXcnXSB8fCBjaGFuZ2VzWydjb2xvcm1hcE9wdGlvbnMnXSkge1xuICAgICAgdGhpcy5zZWxlY3RlZERlbnNpdHlDb2xvcm1hcE5vZGUgPSBjb2xvcm1hcE5vZGVGb3IodGhpcy5jb2xvcm1hcE9wdGlvbnMsIHRoaXMudmlldy5kZW5zaXR5Q29sb3JtYXApO1xuICAgIH1cbiAgICBpZiAodGhpcy5kZW5zaXR5QmFyRm9yICE9PSB0aGlzLnZpZXcuZGVuc2l0eUNvbG9ybWFwIHx8ICF0aGlzLmRlbnNpdHlDb2xvckJhckNzcykge1xuICAgICAgdGhpcy5kZW5zaXR5QmFyRm9yID0gdGhpcy52aWV3LmRlbnNpdHlDb2xvcm1hcDtcbiAgICAgIHRoaXMuZGVuc2l0eUNvbG9yQmFyQ3NzID0gZGVuc2l0eUNvbG9yQmFyQ3NzKHRoaXMudmlldy5kZW5zaXR5Q29sb3JtYXApO1xuICAgIH1cbiAgICB0aGlzLnJlZnJlc2hEZW5zaXR5V2luZG93KCk7XG4gIH1cblxuICAvLyDilIDilIAgdGhlIHNlY3Rpb24gc3dpdGNoIGFuZCB0aGUgZ2VuZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJvdGVjdGVkIG9uVHJhbnNjcmlwdHNPbihvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICghb24pIHtcbiAgICAgIGlmICh0aGlzLnZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdvZmYnKSB0aGlzLmxhc3RUcmFuc2NyaXB0TW9kZSA9IHRoaXMudmlldy50cmFuc2NyaXB0TW9kZTtcbiAgICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRNb2RlOiAnb2ZmJyB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbW9kZSA9IHRoaXMuZGF0YXNldD8udHJhbnNjcmlwdFRpbGVzID8gdGhpcy5sYXN0VHJhbnNjcmlwdE1vZGUgOiAnZGVuc2l0eSc7XG4gICAgdGhpcy5vblRyYW5zY3JpcHRNb2RlKG1vZGUpO1xuICAgIHRoaXMub3BlbkNoYW5nZS5lbWl0KHRydWUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uVHJhbnNjcmlwdE1vZGUobW9kZTogU3BhdGlhbFZpZXdTdGF0ZVsndHJhbnNjcmlwdE1vZGUnXSk6IHZvaWQge1xuICAgIC8vIFNlZWQgdGhlIGdlbmUgbGlzdCBmcm9tIHRoZSBnZW5lIGJlaW5nIGNvbG91cmVkIGJ5LCBzbyBzd2l0Y2hpbmcgdHJhbnNjcmlwdHMgb25cbiAgICAvLyBzaG93cyBzb21ldGhpbmcgc3RyYWlnaHQgYXdheS5cbiAgICBjb25zdCBzZWVkID1cbiAgICAgICF0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVzLmxlbmd0aCAmJiB0aGlzLnZpZXcuY29sb3JCeT8ua2luZCA9PT0gJ2ZlYXR1cmUnID8gW3RoaXMudmlldy5jb2xvckJ5Lm5hbWVdIDogbnVsbDtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0TW9kZTogbW9kZSwgLi4uKHNlZWQgPyB7IHRyYW5zY3JpcHRHZW5lczogc2VlZCB9IDoge30pIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uVHJhbnNjcmlwdEdlbmVzKGdlbmVzOiBzdHJpbmdbXSB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2VuZXM6IFsuLi4oZ2VuZXMgPz8gW10pXSB9KTtcbiAgfVxuXG4gIC8qKiBSZWFsIGdlbmVzIGluIHRoZSBwYW5lbCDigJQgdGhlIHRyZWUncyBkZW5vbWluYXRvci4gKi9cbiAgcHJvdGVjdGVkIGdldCBnZW5lVG90YWwoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5kYXRhc2V0Py50cmFuc2NyaXB0VGlsZXM/LmdlbmVDb3VudCA/PyB0aGlzLmRhdGFzZXQ/LmZlYXR1cmVzPy5jb3VudCA/PyB0aGlzLmdlbmVzPy5yZXNpZGVudENvdW50ID8/IDBcbiAgICApO1xuICB9XG5cbiAgLyoqIFwiQWxsIGdlbmVzXCIgbmVlZHMgdGhlIGdyb3VwaW5nIHB5cmFtaWQsIG9yIGF0IGxlYXN0IHRpbGVzIHRvIGRyYXcgaW5kaXZpZHVhbGx5LiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGNhblNob3dBbGxHZW5lcygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmRhdGFzZXQ/LnRyYW5zY3JpcHRCaW5zO1xuICB9XG5cbiAgLyoqIFdoeSBcIkFsbCBnZW5lc1wiIGlzIG5vdCBvZmZlcmVkIHlldCwgd2hpbGUgdGhlIHNlcnZlciBidWlsZHMgaXRzIHB5cmFtaWQuICovXG4gIHByb3RlY3RlZCBnZXQgYWxsR2VuZXNQcmVwYXJpbmcoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIGFsbEdlbmVzUHJlcGFyaW5nTm90ZSh0aGlzLmRhdGFzZXQpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCBzaG93aW5nQWxsR2VuZXMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY2FuU2hvd0FsbEdlbmVzICYmIHRoaXMudmlldy50cmFuc2NyaXB0QWxsR2VuZXMgJiYgdGhpcy52aWV3LnRyYW5zY3JpcHRNb2RlICE9PSAnZGVuc2l0eSc7XG4gIH1cblxuICBvblRyYW5zY3JpcHRBbGxHZW5lcyhvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRBbGxHZW5lczogb24gfSk7XG4gIH1cblxuICAvKiogJ8KxJzogZXZlcnkgZ2VuZSwgb3IgYmFjayB0byB0aGUgY2hvc2VuIGxpc3QuICovXG4gIHByb3RlY3RlZCBvblRvZ2dsZUFsbEdlbmVzKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jYW5TaG93QWxsR2VuZXMpIHJldHVybjtcbiAgICB0aGlzLm9uVHJhbnNjcmlwdEFsbEdlbmVzKCF0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzKTtcbiAgfVxuXG4gIGdldCBjYW5BZGRNYXJrZXJzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMuY29udHJvbHM/Lm1hcmtlckdlbmVzICYmIHRoaXMuaGFzTWFya2VyQ29sdW1ucztcbiAgfVxuXG4gIC8qKiBPcGVuIHRoZSBtYXJrZXItZ2VuZXMgZm9ybSAoZnJvbSB0aGUgJ+KLricgbWVudSkuICovXG4gIG9wZW5NYXJrZXJzKCk6IHZvaWQge1xuICAgIHRoaXMubWFya2Vyc09wZW4gPSB0cnVlO1xuICAgIHRoaXMub3BlbkNoYW5nZS5lbWl0KHRydWUpO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgb25OZXdHZW5lR3JvdXAoKTogdm9pZCB7XG4gICAgY29uc3QgbmFtZSA9IChnbG9iYWxUaGlzLnByb21wdD8uKCdOYW1lIGZvciB0aGlzIGdlbmUgZ3JvdXAnLCAnR2VuZSBncm91cCcpID8/ICcnKS50cmltKCk7XG4gICAgaWYgKCFuYW1lKSByZXR1cm47XG4gICAgY29uc3QgZ3JvdXBzID0gdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzLmZpbHRlcigoZykgPT4gZy5uYW1lICE9PSBuYW1lKTtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoe1xuICAgICAgdHJhbnNjcmlwdEdlbmVHcm91cHM6IFsuLi5ncm91cHMsIHsgbmFtZSwgZ2VuZXM6IFsuLi50aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVzXSB9XSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgZ2VuZSBncm91cHM6IENTVi9UU1Ygd2l0aCBhIGdyb3VwIGFuZCBhIGdlbmUgY29sdW1uIChoZWFkZXIgb3B0aW9uYWwpLCBlLmcuXG4gICAqIG1hcmtlciBnZW5lcyBwZXIgY2VsbCB0eXBlLiBUaGUgZ2VuZXMgYXJlIGFkZGVkIHRvIHRoZSBzZWxlY3Rpb24uXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgb25JbXBvcnRHZW5lR3JvdXBzKGlucHV0OiBIVE1MSW5wdXRFbGVtZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZmlsZSA9IGlucHV0LmZpbGVzPy5bMF07XG4gICAgaW5wdXQudmFsdWUgPSAnJztcbiAgICBpZiAoIWZpbGUpIHJldHVybjtcbiAgICB0aGlzLmdlbmVHcm91cEVycm9yID0gbnVsbDtcbiAgICBjb25zdCBncm91cHMgPSBwYXJzZUdlbmVHcm91cHMoYXdhaXQgZmlsZS50ZXh0KCkpO1xuICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xuICAgICAgaWYgKCFncm91cHMubGVuZ3RoKSB0aGlzLmdlbmVHcm91cEVycm9yID0gJ05vIFwiZ3JvdXAsZ2VuZVwiIHJvd3MgZm91bmQgaW4gdGhhdCBmaWxlLic7XG4gICAgICBlbHNlIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZShpbXBvcnRHZW5lR3JvdXBzUGF0Y2godGhpcy52aWV3LCBncm91cHMpKTtcbiAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIGhvdyB0cmFuc2NyaXB0cyBhcmUgZHJhd24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJvdGVjdGVkIGdldCBlc3RpbWF0ZVBlcmNlbnQoKTogbnVtYmVyIHtcbiAgICBjb25zdCBlID0gdGhpcy5lc3RpbWF0ZTtcbiAgICByZXR1cm4gZSAmJiBlLm1heCA+IDAgPyBNYXRoLm1pbigxMDAsICgxMDAgKiBlLnBvaW50cykgLyBlLm1heCkgOiAwO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCBlc3RpbWF0ZU92ZXJNYXgoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhdGhpcy5lc3RpbWF0ZSAmJiB0aGlzLmVzdGltYXRlLnBvaW50cyA+IHRoaXMuZXN0aW1hdGUubWF4O1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uVHJhbnNjcmlwdEJ1ZGdldChuOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0QnVkZ2V0OiBuIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uVHJhbnNjcmlwdENvbG9yQnkoYnk6IFNwYXRpYWxWaWV3U3RhdGVbJ3RyYW5zY3JpcHRDb2xvckJ5J10pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0Q29sb3JCeTogYnkgfSk7XG4gIH1cblxuICAvLyBQcmltZU5HJ3Mgc2xpZGVyIHJlcG9ydHMgYG51bWJlciB8IHVuZGVmaW5lZGA7IGlnbm9yZSB0aGUgZW1wdHkgY2FzZSByYXRoZXIgdGhhblxuICAvLyB3cml0aW5nIGB1bmRlZmluZWRgIGludG8gdGhlIHN0b3JlLlxuICBwcm90ZWN0ZWQgb25UcmFuc2NyaXB0U2NhbGUodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdHJhbnNjcmlwdFNjYWxlOiB2YWx1ZSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvblRyYW5zY3JpcHRPcGFjaXR5KHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRPcGFjaXR5OiB2YWx1ZSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvblRyYW5zY3JpcHRRdWFsaXR5KGluY2x1ZGVMb3c6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0UXVhbGl0eTogaW5jbHVkZUxvdyA/ICdhbGwnIDogJ2hpZ2gnIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdseXBoT2YoZ2VuZTogc3RyaW5nLCBzbG90OiBudW1iZXIpOiBUcmFuc2NyaXB0R2x5cGhOYW1lIHtcbiAgICByZXR1cm4gdGhpcy52aWV3LnRyYW5zY3JpcHRHbHlwaHNbZ2VuZV0gPz8gZGVmYXVsdEdseXBoRm9yKHNsb3QpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uR2x5cGgoZ2VuZTogc3RyaW5nLCBnbHlwaDogVHJhbnNjcmlwdEdseXBoTmFtZSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRHbHlwaHM6IHsgLi4udGhpcy52aWV3LnRyYW5zY3JpcHRHbHlwaHMsIFtnZW5lXTogZ2x5cGggfSB9KTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBkZW5zaXR5IG1hcCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcm90ZWN0ZWQgZ2V0IGRlbnNpdHlPcGFjaXR5UGVyY2VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKHRoaXMudmlldy5kZW5zaXR5T3BhY2l0eSAqIDEwMCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5T3BhY2l0eSh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBkZW5zaXR5T3BhY2l0eTogdmFsdWUgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5T3BhY2l0eVBlcmNlbnQodjogbnVtYmVyIHwgbnVsbCk6IHZvaWQge1xuICAgIGlmICh2ID09PSBudWxsIHx8ICFOdW1iZXIuaXNGaW5pdGUodikpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBkZW5zaXR5T3BhY2l0eTogTWF0aC5taW4oMSwgTWF0aC5tYXgoMC4wNSwgdiAvIDEwMCkpIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCBkZW5zaXR5QmluSW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5tYXgoMCwgdGhpcy5kZW5zaXR5Qmlucy5pbmRleE9mKHRoaXMudmlldy5kZW5zaXR5QmluKSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5QmluSW5kZXgoaTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKGkgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGRlbnNpdHlCaW46IHRoaXMuZGVuc2l0eUJpbnNbaV0gPz8gMTAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5UmFuZ2UocmFuZ2U6IFtudW1iZXIsIG51bWJlcl0gfCBudW1iZXJbXSB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICghcmFuZ2UgfHwgcmFuZ2UubGVuZ3RoICE9PSAyKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZGVuc2l0eVJhbmdlOiBbTWF0aC5taW4ocmFuZ2VbMF0sIHJhbmdlWzFdKSwgTWF0aC5tYXgocmFuZ2VbMF0sIHJhbmdlWzFdKV0gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5UmFuZ2VFbmQod2hpY2g6IDAgfCAxLCB2OiBudW1iZXIgfCBudWxsKTogdm9pZCB7XG4gICAgaWYgKHYgPT09IG51bGwgfHwgIU51bWJlci5pc0Zpbml0ZSh2KSkgcmV0dXJuO1xuICAgIGNvbnN0IG5leHQ6IFtudW1iZXIsIG51bWJlcl0gPSBbLi4udGhpcy5kZW5zaXR5V2luZG93XTtcbiAgICBuZXh0W3doaWNoXSA9IHY7XG4gICAgdGhpcy5vbkRlbnNpdHlSYW5nZShuZXh0KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkRlbnNpdHlBdXRvKCk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGRlbnNpdHlSYW5nZTogbnVsbCB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkRlbnNpdHlDb2xvcm1hcChub2RlOiBDb2xvcm1hcE5vZGUgfCBudWxsKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZERlbnNpdHlDb2xvcm1hcE5vZGUgPSBub2RlO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGRlbnNpdHlDb2xvcm1hcDogbm9kZT8uZGF0YT8udmFsdWUgPz8gbnVsbCB9KTtcbiAgfVxuXG4gIHByaXZhdGUgcmVmcmVzaERlbnNpdHlXaW5kb3coKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dDogW251bWJlciwgbnVtYmVyXSA9XG4gICAgICB0aGlzLnZpZXcuZGVuc2l0eVJhbmdlID8/ICh0aGlzLmRlbnNpdHlTdGF0cyA/IFt0aGlzLmRlbnNpdHlTdGF0cy5sbywgdGhpcy5kZW5zaXR5U3RhdHMuaGldIDogWzAsIDFdKTtcbiAgICBpZiAobmV4dFswXSAhPT0gdGhpcy5kZW5zaXR5V2luZG93WzBdIHx8IG5leHRbMV0gIT09IHRoaXMuZGVuc2l0eVdpbmRvd1sxXSkgdGhpcy5kZW5zaXR5V2luZG93ID0gbmV4dDtcbiAgICB0aGlzLmRlbnNpdHlTbGlkZXJNYXggPSBNYXRoLm1heCh0aGlzLmRlbnNpdHlTdGF0cz8ubWF4ID8/IDEsIHRoaXMuZGVuc2l0eVdpbmRvd1sxXSk7XG4gICAgdGhpcy5kZW5zaXR5U3RlcCA9IHRoaXMuZGVuc2l0eVNsaWRlck1heCAvIDIwMDtcbiAgfVxuXG4gIC8qKiAn4ouuJyBtZW51LiAqL1xuICBwcml2YXRlIGJ1aWxkR2VuZU1lbnUoKTogR2VuZU1lbnVJdGVtW10ge1xuICAgIHJldHVybiBbXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiAnQWRkIG1hcmtlciBnZW5lcyBvZiBjbHVzdGVyc+KApicsXG4gICAgICAgIGljb246ICdwaSBwaS1zaXRlbWFwJyxcbiAgICAgICAgZGlzYWJsZWQ6ICF0aGlzLmNhbkFkZE1hcmtlcnMsXG4gICAgICAgIGNvbW1hbmQ6ICgpID0+IHRoaXMub3Blbk1hcmtlcnMoKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiAnTmV3IGdyb3VwIGZyb20gc2VsZWN0ZWQgZ2VuZXMnLFxuICAgICAgICBpY29uOiAncGkgcGktZm9sZGVyLXBsdXMnLFxuICAgICAgICBkaXNhYmxlZDogIXRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoLFxuICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLm9uTmV3R2VuZUdyb3VwKCksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBsYWJlbDogJ0ltcG9ydCBnZW5lIGdyb3VwcyAoQ1NWKeKApicsXG4gICAgICAgIGljb246ICdwaSBwaS11cGxvYWQnLFxuICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLmdlbmVHcm91cEZpbGVSZWY/Lm5hdGl2ZUVsZW1lbnQuY2xpY2soKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGxhYmVsOiAnUmVtb3ZlIGdlbmUgZ3JvdXBzJyxcbiAgICAgICAgaWNvbjogJ3BpIHBpLXRpbWVzJyxcbiAgICAgICAgZGlzYWJsZWQ6ICF0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHMubGVuZ3RoLFxuICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2VuZUdyb3VwczogW10gfSksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBsYWJlbDogJ0NsZWFyIHNlbGVjdGlvbicsXG4gICAgICAgIGljb246ICdwaSBwaS1iYW4nLFxuICAgICAgICBkaXNhYmxlZDogIXRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoLFxuICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2VuZXM6IFtdLCB0cmFuc2NyaXB0SGlkZGVuR2VuZXM6IFtdIH0pLFxuICAgICAgfSxcbiAgICBdO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwic2MtcGFuZWxcIiBbY2xhc3Mub3Blbl09XCJvcGVuXCI+XG4gIDxkaXYgY2xhc3M9XCJzYy1wYW5lbC1oZWFkXCIgKGNsaWNrKT1cIm9wZW5DaGFuZ2UuZW1pdCghb3BlbilcIj5cbiAgICA8cC1jaGVja2JveFxuICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgIFtuZ01vZGVsXT1cInZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdvZmYnXCJcbiAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKG9uQ2hhbmdlKT1cIm9uVHJhbnNjcmlwdHNPbigkZXZlbnQuY2hlY2tlZClcIlxuICAgID48L3AtY2hlY2tib3g+XG4gICAgPHNwYW4gY2xhc3M9XCJzYy1wYW5lbC10aXRsZVwiPlRyYW5zY3JpcHRzPC9zcGFuPlxuICAgIDxpIGNsYXNzPVwicGlcIiBbY2xhc3MucGktY2hldnJvbi1kb3duXT1cIm9wZW5cIiBbY2xhc3MucGktY2hldnJvbi1yaWdodF09XCIhb3BlblwiPjwvaT5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJzYy1wYW5lbC1ib2R5XCIgKm5nSWY9XCJvcGVuXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvdyBzYy1yb3ctcGlja2VyXCI+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZ2VuZXM/LnN0YXRlJCB8IGFzeW5jIGFzIGdlbmVcIj5cbiAgICAgICAgPHAtbXVsdGlTZWxlY3RcbiAgICAgICAgICBpbnB1dElkPVwic2MtdHgtZ2VuZXNcIlxuICAgICAgICAgIFtvcHRpb25zXT1cImdlbmUub3B0aW9uc1wiXG4gICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgW25nTW9kZWxdPVwidmlldy50cmFuc2NyaXB0R2VuZXNcIlxuICAgICAgICAgIChvbkNoYW5nZSk9XCJvblRyYW5zY3JpcHRHZW5lcygkZXZlbnQudmFsdWUpXCJcbiAgICAgICAgICBbZmlsdGVyXT1cInRydWVcIlxuICAgICAgICAgIGZpbHRlckJ5PVwibGFiZWxcIlxuICAgICAgICAgIFtyZXNldEZpbHRlck9uSGlkZV09XCJ0cnVlXCJcbiAgICAgICAgICAob25GaWx0ZXIpPVwiZ2VuZXM/Lm9uRmlsdGVyKCRldmVudC5maWx0ZXIpXCJcbiAgICAgICAgICAob25QYW5lbFNob3cpPVwiZ2VuZXM/LmVuc3VyZUxpc3QoKVwiXG4gICAgICAgICAgW3ZpcnR1YWxTY3JvbGxdPVwiZ2VuZS5vcHRpb25zLmxlbmd0aCA+IGdlbmVWaXJ0dWFsU2Nyb2xsRnJvbVwiXG4gICAgICAgICAgW3ZpcnR1YWxTY3JvbGxJdGVtU2l6ZV09XCIzMFwiXG4gICAgICAgICAgW3Nob3dUb2dnbGVBbGxdPVwiZmFsc2VcIlxuICAgICAgICAgIFtlbXB0eUZpbHRlck1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnTm8gbWF0Y2gg4oCUIGtlZXAgdHlwaW5nJyA6ICdObyBtYXRjaCdcIlxuICAgICAgICAgIFtlbXB0eU1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnVHlwZSB0byBzZWFyY2ggZ2VuZXMnIDogJ05vIGdlbmVzJ1wiXG4gICAgICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgICBwbGFjZWhvbGRlcj1cIlNlYXJjaCBmb3IgZ2VuZXMgdG8gdmlzdWFsaXpl4oCmXCJcbiAgICAgICAgICBbc2VsZWN0ZWRJdGVtc0xhYmVsXT1cIid7MH0gZ2VuZXMgc2VsZWN0ZWQnXCJcbiAgICAgICAgICBbbWF4U2VsZWN0ZWRMYWJlbHNdPVwiMFwiXG4gICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWZ1bGxcIlxuICAgICAgICA+PC9wLW11bHRpU2VsZWN0PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cInNjLWljb24tYnRuXCJcbiAgICAgICAgKm5nSWY9XCJjYW5TaG93QWxsR2VuZXNcIlxuICAgICAgICAoY2xpY2spPVwib25Ub2dnbGVBbGxHZW5lcygpXCJcbiAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJ2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1wiXG4gICAgICAgIFt0aXRsZV09XCJ2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/ICdCYWNrIHRvIHRoZSBzZWxlY3RlZCBnZW5lcycgOiAnU2VsZWN0IGFsbCBnZW5lcydcIlxuICAgICAgPlxuICAgICAgICDCsVxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLWljb24tYnRuXCIgKGNsaWNrKT1cImdlbmVNZW51UmVmLnRvZ2dsZSgkZXZlbnQpXCIgdGl0bGU9XCJNb3JlXCI+XG4gICAgICAgIDxpIGNsYXNzPVwicGkgcGktZWxsaXBzaXMtdlwiPjwvaT5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPHAtbWVudSAjZ2VuZU1lbnVSZWYgW21vZGVsXT1cImdlbmVNZW51XCIgW3BvcHVwXT1cInRydWVcIiBhcHBlbmRUbz1cImJvZHlcIj48L3AtbWVudT5cbiAgICAgIDxpbnB1dFxuICAgICAgICAjZ2VuZUdyb3VwRmlsZVxuICAgICAgICB0eXBlPVwiZmlsZVwiXG4gICAgICAgIGFjY2VwdD1cIi5jc3YsLnRzdiwudHh0XCJcbiAgICAgICAgaGlkZGVuXG4gICAgICAgIChjaGFuZ2UpPVwib25JbXBvcnRHZW5lR3JvdXBzKGdlbmVHcm91cEZpbGUpXCJcbiAgICAgIC8+XG4gICAgPC9kaXY+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludCBzYy1lcnJvclwiICpuZ0lmPVwiZ2VuZUdyb3VwRXJyb3JcIj57eyBnZW5lR3JvdXBFcnJvciB9fTwvc21hbGw+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiYWxsR2VuZXNQcmVwYXJpbmdcIj57eyBhbGxHZW5lc1ByZXBhcmluZyB9fTwvc21hbGw+XG5cbiAgICA8c3BhdGlhbC1tYXJrZXItZ2VuZXMtZm9ybVxuICAgICAgW2NvbnRyb2xzXT1cImNvbnRyb2xzXCJcbiAgICAgIFtkYXRhc2V0XT1cImRhdGFzZXRcIlxuICAgICAgW3ZpZXddPVwidmlld1wiXG4gICAgICBbb3Blbl09XCJtYXJrZXJzT3BlblwiXG4gICAgICAob3BlbkNoYW5nZSk9XCJtYXJrZXJzT3BlbiA9ICRldmVudFwiXG4gICAgPjwvc3BhdGlhbC1tYXJrZXItZ2VuZXMtZm9ybT5cblxuICAgIDxzcGF0aWFsLWdlbmUtdHJlZVxuICAgICAgW2NvbnRyb2xzXT1cImNvbnRyb2xzXCJcbiAgICAgIFtkYXRhc2V0XT1cImRhdGFzZXRcIlxuICAgICAgW3ZpZXddPVwidmlld1wiXG4gICAgICBbZ2VuZUNvdW50c109XCJnZW5lQ291bnRzXCJcbiAgICAgIFtnZW5lVG90YWxdPVwiZ2VuZVRvdGFsXCJcbiAgICA+PC9zcGF0aWFsLWdlbmUtdHJlZT5cblxuICAgIDxkaXYgY2xhc3M9XCJzYy1zdWJoZWFkXCI+VHJhbnNjcmlwdCBjb250cm9sczwvZGl2PlxuICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+VmlldyB0cmFuc2NyaXB0cyBhczwvc3Bhbj5cbiAgICA8cC1zZWxlY3RCdXR0b25cbiAgICAgIFtvcHRpb25zXT1cInRyYW5zY3JpcHRNb2RlT3B0aW9uc1wiXG4gICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgW25nTW9kZWxdPVwidmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ29mZicgPyBudWxsIDogdmlldy50cmFuc2NyaXB0TW9kZVwiXG4gICAgICAobmdNb2RlbENoYW5nZSk9XCJvblRyYW5zY3JpcHRNb2RlKCRldmVudClcIlxuICAgICAgW2FsbG93RW1wdHldPVwiZmFsc2VcIlxuICAgICAgc3R5bGVDbGFzcz1cInNjLWJ1dHRvbnNcIlxuICAgID48L3Atc2VsZWN0QnV0dG9uPlxuXG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImVzdGltYXRlXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgIDxzcGFuXG4gICAgICAgICAgY2xhc3M9XCJzYy1sYmxcIlxuICAgICAgICAgIHBUb29sdGlwPVwiVHJhbnNjcmlwdHMgb2YgdGhlIHZpc2libGUgZ2VuZXMgZXN0aW1hdGVkIHRvIGJlIGluIHZpZXcsIGFnYWluc3QgdGhlIG1vc3QgbWFya2VycyBkcmF3biBhdCBvbmNlXCJcbiAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgICAgID5Fc3RpbWF0ZWQgVHJhbnNjcmlwdCBQb2ludHM8L3NwYW5cbiAgICAgICAgPlxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLXNtYWxsLWJ0blwiIChjbGljayk9XCJlZGl0aW5nTWF4ID0gIWVkaXRpbmdNYXhcIj5FZGl0IE1heDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwic2MtbWV0ZXJcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLW1ldGVyLWZpbGxcIiBbY2xhc3Mub3Zlcl09XCJlc3RpbWF0ZU92ZXJNYXhcIiBbc3R5bGUud2lkdGguJV09XCJlc3RpbWF0ZVBlcmNlbnRcIj48L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInNjLW1ldGVyLWVuZHNcIj5cbiAgICAgICAgPHNwYW4+e3sgZXN0aW1hdGUucG9pbnRzIHwgbnVtYmVyIH19IHBvaW50czwvc3Bhbj5cbiAgICAgICAgPHNwYW4+e3sgZXN0aW1hdGUubWF4IHwgbnVtYmVyIH19IG1heHt7IGVzdGltYXRlT3Zlck1heCA/ICcgcmVhY2hlZCcgOiAnJyB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwiZWRpdGluZ01heFwiPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPk1heCBtYXJrZXJzPC9zcGFuPlxuICAgICAgICA8cC1kcm9wZG93blxuICAgICAgICAgIFtvcHRpb25zXT1cImJ1ZGdldE9wdGlvbnNcIlxuICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcudHJhbnNjcmlwdEJ1ZGdldFwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25UcmFuc2NyaXB0QnVkZ2V0KCRldmVudClcIlxuICAgICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgID48L3AtZHJvcGRvd24+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cImVzdGltYXRlT3Zlck1heCAmJiB2aWV3LnRyYW5zY3JpcHRNb2RlICE9PSAnZGVuc2l0eSdcIj5cbiAgICAgICAgTWF4IHBvaW50cyByZWFjaGVkOiB0cmFuc2NyaXB0cyBhcmUgZ3JvdXBlZCBieSBhcmVhLCBjaXJjbGVzIHNpemVkIGJ5IGhvdyBtYW55IHRoZXkgaG9sZC4gWm9vbSBpbiBvciBzZWxlY3RcbiAgICAgICAgZmV3ZXIgZ2VuZXMgdG8gc2VlIGluZGl2aWR1YWwgcG9pbnRzLlxuICAgICAgPC9zbWFsbD5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJ2aWV3LnRyYW5zY3JpcHRNb2RlID09PSAnY2lyY2xlcycgfHwgdmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ2dseXBocydcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5Db2xvdXIgYnk8L3NwYW4+XG4gICAgICAgIDxwLXNlbGVjdEJ1dHRvblxuICAgICAgICAgIFtvcHRpb25zXT1cInRyYW5zY3JpcHRDb2xvck9wdGlvbnNcIlxuICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcudHJhbnNjcmlwdENvbG9yQnlcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVHJhbnNjcmlwdENvbG9yQnkoJGV2ZW50KVwiXG4gICAgICAgICAgW2FsbG93RW1wdHldPVwiZmFsc2VcIlxuICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1idXR0b25zXCJcbiAgICAgICAgPjwvcC1zZWxlY3RCdXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxzbWFsbFxuICAgICAgICBjbGFzcz1cInNjLWhpbnRcIlxuICAgICAgICAqbmdJZj1cInZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIHZpZXcudHJhbnNjcmlwdENvbG9yQnkgPT09ICdnZW5lJyAmJiBlc3RpbWF0ZU92ZXJNYXhcIlxuICAgICAgPlxuICAgICAgICBHcm91cGVkIG1hcmtlcnMgbWl4IGdlbmVzLCBzbyB0aGV5IGFyZSBjb2xvdXJlZCBieSBjZWxsIHR5cGUgdW50aWwgeW91IHpvb20gaW4gdG8gaW5kaXZpZHVhbCB0cmFuc2NyaXB0cy5cbiAgICAgIDwvc21hbGw+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyAmJiB2aWV3LnRyYW5zY3JpcHRNb2RlID09PSAnZ2x5cGhzJ1wiPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPkljb248L3NwYW4+XG4gICAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgICAgW29wdGlvbnNdPVwiZ2x5cGhPcHRpb25zXCJcbiAgICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICBbbmdNb2RlbF09XCJnbHlwaE9mKCcqJywgMClcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uR2x5cGgoJyonLCAkZXZlbnQpXCJcbiAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1nbHlwaC1waWNrXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBsZXQtb3B0IHBUZW1wbGF0ZT1cIml0ZW1cIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ2x5cGgtb3B0aW9uXCI+XG4gICAgICAgICAgICAgIDxzdmcgdmlld0JveD1cIi0xLjIgLTEuMiAyLjQgMi40XCIgY2xhc3M9XCJzYy1nbHlwaC1zdmdcIj5cbiAgICAgICAgICAgICAgICA8cG9seWdvbiBbYXR0ci5wb2ludHNdPVwib3B0LnBvaW50c1wiPjwvcG9seWdvbj5cbiAgICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgICAgIHt7IG9wdC5sYWJlbCB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIGxldC1vcHQgcFRlbXBsYXRlPVwic2VsZWN0ZWRJdGVtXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWdseXBoLW9wdGlvblwiPlxuICAgICAgICAgICAgICA8c3ZnIHZpZXdCb3g9XCItMS4yIC0xLjIgMi40IDIuNFwiIGNsYXNzPVwic2MtZ2x5cGgtc3ZnXCI+XG4gICAgICAgICAgICAgICAgPHBvbHlnb24gW2F0dHIucG9pbnRzXT1cIm9wdD8ucG9pbnRzXCI+PC9wb2x5Z29uPlxuICAgICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3AtZHJvcGRvd24+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TaXplPC9zcGFuPlxuICAgICAgICA8cC1zbGlkZXJcbiAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnRyYW5zY3JpcHRTY2FsZVwiXG4gICAgICAgICAgW21pbl09XCIwLjVcIlxuICAgICAgICAgIFttYXhdPVwiM1wiXG4gICAgICAgICAgW3N0ZXBdPVwiMC4yNVwiXG4gICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uVHJhbnNjcmlwdFNjYWxlKCRldmVudC52YWx1ZSlcIlxuICAgICAgICA+PC9wLXNsaWRlcj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LnRyYW5zY3JpcHRTY2FsZSB9fcOXPC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+T3BhY2l0eTwvc3Bhbj5cbiAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgW25nTW9kZWxdPVwidmlldy50cmFuc2NyaXB0T3BhY2l0eVwiXG4gICAgICAgICAgW21pbl09XCIwLjFcIlxuICAgICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgICAgW3N0ZXBdPVwiMC4wNVwiXG4gICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uVHJhbnNjcmlwdE9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgID48L3Atc2xpZGVyPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcudHJhbnNjcmlwdE9wYWNpdHkgfX08L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cIiFzaG93aW5nQWxsR2VuZXNcIj5cbiAgICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcudHJhbnNjcmlwdFF1YWxpdHkgPT09ICdhbGwnXCJcbiAgICAgICAgICBpbnB1dElkPVwic2MtdHgtbG93cVwiXG4gICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uVHJhbnNjcmlwdFF1YWxpdHkoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgPjwvcC1jaGVja2JveD5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2MtdHgtbG93cVwiPkluY2x1ZGUgbG93LXF1YWxpdHkgY2FsbHM8L2xhYmVsPlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwidmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ2RlbnNpdHknXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPkRlbnNpdHkgbWFwIG9wYWNpdHk8L3NwYW4+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93IHNjLXJvdy1udW1iZXJcIj5cbiAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgW25nTW9kZWxdPVwidmlldy5kZW5zaXR5T3BhY2l0eVwiXG4gICAgICAgICAgW21pbl09XCIwLjA1XCJcbiAgICAgICAgICBbbWF4XT1cIjFcIlxuICAgICAgICAgIFtzdGVwXT1cIjAuMDVcIlxuICAgICAgICAgIChvbkNoYW5nZSk9XCJvbkRlbnNpdHlPcGFjaXR5KCRldmVudC52YWx1ZSlcIlxuICAgICAgICA+PC9wLXNsaWRlcj5cbiAgICAgICAgPHAtaW5wdXROdW1iZXJcbiAgICAgICAgICBbbmdNb2RlbF09XCJkZW5zaXR5T3BhY2l0eVBlcmNlbnRcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uRGVuc2l0eU9wYWNpdHlQZXJjZW50KCRldmVudClcIlxuICAgICAgICAgIFttaW5dPVwiNVwiXG4gICAgICAgICAgW21heF09XCIxMDBcIlxuICAgICAgICAgIGlucHV0U3R5bGVDbGFzcz1cInNjLW51bVwiXG4gICAgICAgID48L3AtaW5wdXROdW1iZXI+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCIgcFRvb2x0aXA9XCJFZGdlIG9mIGVhY2ggZGVuc2l0eSBiaW5cIiB0b29sdGlwUG9zaXRpb249XCJ0b3BcIj5EZW5zaXR5IG1hcCBiaW4gc2l6ZTwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJkZW5zaXR5QmluSW5kZXhcIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cIjNcIlxuICAgICAgICBbc3RlcF09XCIxXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eUJpbkluZGV4KCRldmVudC52YWx1ZSlcIlxuICAgICAgICBzdHlsZUNsYXNzPVwic2MtYmluLXNsaWRlclwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy10aWNrc1wiPlxuICAgICAgICA8c3BhbiAqbmdGb3I9XCJsZXQgYiBvZiBkZW5zaXR5Qmluc1wiPnt7IGIgfX3Dl3t7IGIgfX3CtW08L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwic2MtbGJsXCJcbiAgICAgICAgcFRvb2x0aXA9XCJUcmFuc2NyaXB0cyBwZXIgwrVtwrIgYXQgd2hpY2ggdGhlIGNvbG91ciBzY2FsZSBzdGFydHMgYW5kIHNhdHVyYXRlc1wiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgID5EZW5zaXR5IG1hcCBzY2FsZSB0aHJlc2hvbGQ8L3NwYW5cbiAgICAgID5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3cgc2Mtcm93LXJhbmdlXCI+XG4gICAgICAgIDxwLWlucHV0TnVtYmVyXG4gICAgICAgICAgW25nTW9kZWxdPVwiZGVuc2l0eVdpbmRvd1swXVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25EZW5zaXR5UmFuZ2VFbmQoMCwgJGV2ZW50KVwiXG4gICAgICAgICAgbW9kZT1cImRlY2ltYWxcIlxuICAgICAgICAgIFttaW5GcmFjdGlvbkRpZ2l0c109XCIzXCJcbiAgICAgICAgICBbbWF4RnJhY3Rpb25EaWdpdHNdPVwiM1wiXG4gICAgICAgICAgaW5wdXRTdHlsZUNsYXNzPVwic2MtbnVtXCJcbiAgICAgICAgPjwvcC1pbnB1dE51bWJlcj5cbiAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgW25nTW9kZWxdPVwiZGVuc2l0eVdpbmRvd1wiXG4gICAgICAgICAgW3JhbmdlXT1cInRydWVcIlxuICAgICAgICAgIFttaW5dPVwiMFwiXG4gICAgICAgICAgW21heF09XCJkZW5zaXR5U2xpZGVyTWF4XCJcbiAgICAgICAgICBbc3RlcF09XCJkZW5zaXR5U3RlcFwiXG4gICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eVJhbmdlKCRldmVudC52YWx1ZXMpXCJcbiAgICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICAgIDxwLWlucHV0TnVtYmVyXG4gICAgICAgICAgW25nTW9kZWxdPVwiZGVuc2l0eVdpbmRvd1sxXVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25EZW5zaXR5UmFuZ2VFbmQoMSwgJGV2ZW50KVwiXG4gICAgICAgICAgbW9kZT1cImRlY2ltYWxcIlxuICAgICAgICAgIFttaW5GcmFjdGlvbkRpZ2l0c109XCIzXCJcbiAgICAgICAgICBbbWF4RnJhY3Rpb25EaWdpdHNdPVwiM1wiXG4gICAgICAgICAgaW5wdXRTdHlsZUNsYXNzPVwic2MtbnVtXCJcbiAgICAgICAgPjwvcC1pbnB1dE51bWJlcj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCI+e3sgdmlldy5kZW5zaXR5UmFuZ2UgPyAnU2V0IGJ5IGhhbmQuJyA6ICdEZXJpdmVkIGZyb20gdGhlIGRhdGEuJyB9fTwvc21hbGw+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwic2Mtc21hbGwtYnRuXCIgKm5nSWY9XCJ2aWV3LmRlbnNpdHlSYW5nZVwiIChjbGljayk9XCJvbkRlbnNpdHlBdXRvKClcIj5cbiAgICAgICAgICBBdXRvXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPkRlbnNpdHkgbWFwIGJpbiBjb2xvcmluZzwvc3Bhbj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3cgc2Mtcm93LXBpY2tlclwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2MtY29sb3JiYXIgc2MtZnVsbFwiIFtzdHlsZS5iYWNrZ3JvdW5kXT1cImRlbnNpdHlDb2xvckJhckNzc1wiPjwvZGl2PlxuICAgICAgICA8cC10cmVlU2VsZWN0XG4gICAgICAgICAgW29wdGlvbnNdPVwiY29sb3JtYXBPcHRpb25zXCJcbiAgICAgICAgICBbbmdNb2RlbF09XCJzZWxlY3RlZERlbnNpdHlDb2xvcm1hcE5vZGVcIlxuICAgICAgICAgIHNlbGVjdGlvbk1vZGU9XCJzaW5nbGVcIlxuICAgICAgICAgIFtzaG93Q2xlYXJdPVwidHJ1ZVwiXG4gICAgICAgICAgcGxhY2Vob2xkZXI9XCJJbmZlcm5vXCJcbiAgICAgICAgICBbc2Nyb2xsSGVpZ2h0XT1cIicyNjBweCdcIlxuICAgICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgc3R5bGVDbGFzcz1cInNjLXBhbGV0dGVcIlxuICAgICAgICAgIChvbk5vZGVTZWxlY3QpPVwib25EZW5zaXR5Q29sb3JtYXAoJGV2ZW50Lm5vZGUpXCJcbiAgICAgICAgICAob25DbGVhcik9XCJvbkRlbnNpdHlDb2xvcm1hcChudWxsKVwiXG4gICAgICAgID5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgbGV0LW5vZGUgcFRlbXBsYXRlPVwiZGVmYXVsdFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1jbWFwLW9wdGlvblwiPlxuICAgICAgICAgICAgICA8aW1nICpuZ0lmPVwiIW5vZGUuY2hpbGRyZW4gJiYgbm9kZS5kYXRhPy5zcmNcIiBbc3JjXT1cIm5vZGUuZGF0YS5zcmNcIiBjbGFzcz1cInNjLWNtYXAtc3dhdGNoXCIgYWx0PVwiXCIgLz5cbiAgICAgICAgICAgICAgPHNwYW4+e3sgbm9kZS5sYWJlbCB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3AtdHJlZVNlbGVjdD5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInNjLWNvbG9yYmFyLWVuZHNcIj5cbiAgICAgICAgPHNwYW4+e3sgZGVuc2l0eVdpbmRvd1swXSB8IG51bWJlcjogJzEuMC0zJyB9fTwvc3BhblxuICAgICAgICA+PHNwYW4+e3sgZGVuc2l0eVdpbmRvd1sxXSB8IG51bWJlcjogJzEuMC0zJyB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19