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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,614 @@
1
+ import { NO_CATEGORY, isCategoricalColumn, } from '../../contracts/spatial-dataset.contract';
2
+ import { encodeCategorical, markerDiameters, resolveCategoryColors } from '../../spatial/spatial-encoding';
3
+ import { emptySelection, maskToIndices, mutedFromSelection, } from '../../spatial/spatial-selection';
4
+ import { framePositions } from '../../spatial/spatial-framing';
5
+ import { PIXEL_WORLD_QUANTUM, worldQuantumForExtent } from '../../spatial/world-grid';
6
+ import { observationsInSlice, volumeImageRef } from '../../spatial/spatial-volume-image';
7
+ import { cellTypeColumnFor } from '../../spatial/spatial-tiles';
8
+ import { colorExpressionField, fieldContrastWindow } from '../../spatial/spatial-expression';
9
+ import { computeExpressionFieldAsync } from '../../workers/spatial-math';
10
+ import { Supersede } from '../../util/supersede';
11
+ import { isAbortError } from '../tile-server';
12
+ import { Image2dScene } from './napari-image-2d-scene';
13
+ import { GENE_MAP_MAX_SIDE, GENE_MAP_SIGMA, SPATIAL_FALLBACK_RADIUS, SPATIAL_NEUTRAL_COLOR, SPATIAL_NEUTRAL_HEX, SPATIAL_SLICE_MIN_DIAMETER_PX, encodeSpatialContinuous, gatherColors, } from './napari-spatial-encoding';
14
+ import { SpatialSceneBase } from './napari-spatial-scene';
15
+ /**
16
+ * SPATIAL_OMICS (review Appendix B, cluster J): the tissue image (an {@link Image2dScene}) with one
17
+ * marker per observation, coloured by an annotation column or a gene, the gene map under the
18
+ * cells, and the level-of-detail tile layers (outlines, transcripts, density) over them. The
19
+ * markers rebuild whenever the dataset or the view state changes, so switching the colour-by
20
+ * column does not remount the scene.
21
+ *
22
+ * Sets up the full 2D interaction stack — region overlay, pixel tools, readback currency — exactly
23
+ * as the plain image view does. That is NOT optional here: this mode's selection is driven by
24
+ * drawn ROIs, so without the overlay there is no way to make a selection at all.
25
+ */
26
+ export class Spatial2dScene extends SpatialSceneBase {
27
+ /** `noImage`: an image-less dataset opened before any image — the observations alone. */
28
+ constructor(ctx, session, noImage = false) {
29
+ super(ctx, session, false);
30
+ /** The observation markers, and which dataset/plane they were built for — so a display-only
31
+ * change (size, colour, opacity, selection) can update them in place. */
32
+ this.points = null;
33
+ this.layerKey = null;
34
+ /** The observation each marker is, in draw order; null when every observation is drawn. */
35
+ this.drawn = null;
36
+ /** The gene map's layer and the inputs it was coloured for (its field is cached in the session,
37
+ * on a clock of its own). */
38
+ this.geneMapLayer = null;
39
+ this.geneMapKey = null;
40
+ /** The dataset the camera has been framed on — see {@link frameOnce}. */
41
+ this.framed = null;
42
+ /** The gene-map estimate in flight (off the main thread past the worker threshold,
43
+ * SPATIAL-19): a new field key supersedes — and aborts — it; a rebuild that leaves the key
44
+ * alone lets it finish. */
45
+ this.geneMapLoads = new Supersede();
46
+ this.image = new Image2dScene(ctx, {
47
+ image: !noImage,
48
+ // Only fit to the image when this dataset actually has one. Otherwise there is nothing to
49
+ // fit, the image size still holds the LAST image's dimensions, and this fits to those — and
50
+ // because it defers to a frame, it lands AFTER the points are added and overwrites the
51
+ // framing they set. That is what left an image-less dataset as a ten-pixel speck.
52
+ fit: () => !!session.latest?.[0]?.imageRef,
53
+ onSlice: (rerendered) => {
54
+ this.redrawMarkers();
55
+ // The stitched re-render cleared the cells, transcripts and density too: re-plan them now
56
+ // rather than at the next camera move (each group redraws only what left the scene).
57
+ if (rerendered)
58
+ this.session.tiles?.refresh();
59
+ },
60
+ onNavigatorInteract: () => this.hover.hide(),
61
+ });
62
+ }
63
+ async mount() {
64
+ const { ctx } = this;
65
+ await this.image.mount();
66
+ // Disposed while the image loaded: claiming the tiles now would take them from the next scene,
67
+ // and the spatial subscription would outlive this one.
68
+ if (ctx.signal.aborted)
69
+ return;
70
+ this.hover.install(ctx.host);
71
+ this.session.claimTiles(this)?.attach(ctx.viewer);
72
+ this.subscribeSpatial();
73
+ ctx.tools.scheduleReadback();
74
+ }
75
+ setZ(z) {
76
+ this.image.setZ(z);
77
+ }
78
+ histogram(channel, bins) {
79
+ return this.image.histogram(channel, bins);
80
+ }
81
+ setImageSmoothing(enabled) {
82
+ this.image.setImageSmoothing(enabled);
83
+ }
84
+ setNavigatorVisible(visible) {
85
+ this.image.setNavigatorVisible(visible);
86
+ }
87
+ dispose() {
88
+ this.disposeSpatial();
89
+ this.geneMapLoads.cancel();
90
+ this.session.releaseTiles(this);
91
+ this.image.dispose();
92
+ }
93
+ canvasSize() {
94
+ return [this.ctx.canvas.clientWidth ?? 0, this.ctx.canvas.clientHeight ?? 0];
95
+ }
96
+ polygonsShownChanged() {
97
+ if (this.points)
98
+ this.points.visible = this.pointsVisible();
99
+ this.ctx.viewer.requestRender();
100
+ }
101
+ afterChange() {
102
+ this.session.tiles?.refresh();
103
+ }
104
+ hoverTiles() {
105
+ return this.session.tiles;
106
+ }
107
+ /**
108
+ * The observation under a client position: napari-js's pick on the marker layer itself (a grid
109
+ * over its positions, rebuilt only when they change), so the tooltip cannot name a cell that is
110
+ * not drawn, then the drawn index mapped back to the observation.
111
+ *
112
+ * A marker is hit anywhere on its drawn disc, or within `slackPx` screen pixels of its centre
113
+ * when it is smaller than that (a 1.5 px dot still has to be hoverable), and of several hits the
114
+ * NEAREST centre wins (an exact tie goes to the one drawn on top). Not napari's `'topmost'`: the
115
+ * slack is wider than most markers, and over a dense field of small ones "the last drawn within
116
+ * 10 px" names a neighbour rather than the cell under the cursor.
117
+ */
118
+ pickObservation(clientX, clientY, slackPx) {
119
+ const points = this.points;
120
+ if (!points)
121
+ return -1;
122
+ const viewer = this.ctx.viewer;
123
+ const [wx, wy] = viewer.canvasToWorld(clientX, clientY);
124
+ const zoom = viewer.camera.zoom;
125
+ const k = points.pick(wx, wy, { tolerance: slackPx / (zoom > 0 ? zoom : 1), tieBreak: 'nearest' });
126
+ if (k < 0)
127
+ return -1;
128
+ return this.drawn ? this.drawn[k] : k;
129
+ }
130
+ /**
131
+ * Whether the markers are drawn: when the user wants them, and not while cell outlines are on
132
+ * screen — then a cell IS its outline, and a circle on top of it is noise. Zoomed out past the
133
+ * outline threshold, the circles stand in for the cells.
134
+ */
135
+ pointsVisible() {
136
+ const view = this.session.latest?.[1];
137
+ return (view?.showPoints ?? true) && !this.session.tiles?.outlinesShown;
138
+ }
139
+ /**
140
+ * Redraw the markers over a freshly rendered image. Two reasons, both invisible from the
141
+ * spatial store — which is why a scrub or a re-render never reached the markers on its own:
142
+ * - the image render CLEARS the layer list, taking the markers with it;
143
+ * - over a volume-backed dataset the displayed plane decides which observations belong on
144
+ * screen at all, so the cells have to move with the section rather than hang over another.
145
+ */
146
+ redrawMarkers() {
147
+ const latest = this.session.latest;
148
+ if (!latest?.[0])
149
+ return;
150
+ void this.rebuild(...latest);
151
+ }
152
+ /** (Re)build the observation marker layer for the current dataset + view state. */
153
+ async rebuild(dataset, view, selection = emptySelection()) {
154
+ const viewer = this.ctx.viewer;
155
+ const task = this.rebuilds.next();
156
+ // Resolve colours BEFORE touching the scene: a gene fetch can fail or be
157
+ // superseded, and dropping the existing layer first would blank the view.
158
+ let faceColor;
159
+ const endLoading = this.ctx.badge.begin('Observations');
160
+ try {
161
+ faceColor = dataset ? await this.faceColors(dataset, view, selection) : SPATIAL_NEUTRAL_COLOR;
162
+ }
163
+ catch (err) {
164
+ console.warn('[napari-js] spatial colouring failed — falling back to a flat colour', err);
165
+ faceColor = SPATIAL_NEUTRAL_COLOR;
166
+ }
167
+ finally {
168
+ endLoading();
169
+ }
170
+ // A newer rebuild (or a teardown) started while the vector was in flight.
171
+ if (!task())
172
+ return;
173
+ if (!dataset || dataset.observations.count === 0) {
174
+ this.removeLayers(viewer);
175
+ return;
176
+ }
177
+ // A dataset whose image IS its volume shows ONE PLANE at a time, so the
178
+ // markers are the observations in the displayed plane, drawn in that plane's
179
+ // pixel grid. Without the filter the specimen's whole depth piles onto one
180
+ // section and reads as a smear; without the affine the coordinates are read
181
+ // as pixels and land off the slice entirely.
182
+ const slab = slabAt(dataset, this.ctx.z());
183
+ // The gene map goes UNDER the cells, so it is settled before they are added.
184
+ await this.ensureGeneMap(viewer, dataset, view, selection, slab);
185
+ if (!task())
186
+ return;
187
+ this.drawMarkers(viewer, dataset, view, faceColor, slab);
188
+ }
189
+ /** Nothing to draw: drop the markers and the gene map. */
190
+ removeLayers(viewer) {
191
+ if (this.points) {
192
+ viewer.layers.remove(this.points);
193
+ this.points = null;
194
+ this.layerKey = null;
195
+ this.drawn = null;
196
+ }
197
+ if (this.geneMapLayer) {
198
+ viewer.layers.remove(this.geneMapLayer);
199
+ this.geneMapLayer = null;
200
+ this.geneMapKey = null;
201
+ }
202
+ }
203
+ /**
204
+ * Draw the observation markers over the image (and the gene map): restyled in place for a
205
+ * display-only change, else a new layer.
206
+ */
207
+ drawMarkers(viewer, dataset, view, faceColor, slab) {
208
+ const obs = dataset.observations;
209
+ const ref = slab?.ref ?? dataset.imageRef;
210
+ const size = markerSizes(obs, view, slab);
211
+ // napari's image view CLEARS the whole layer list on every render, so the
212
+ // markers go with it whenever the image is re-rendered — a scrub, a contrast
213
+ // change. The cached handle is then detached, and mutating it draws nothing:
214
+ // treat a layer that is no longer in the scene as absent so it gets re-added.
215
+ if (this.points && !viewer.layers.items.includes(this.points)) {
216
+ this.points = null;
217
+ this.layerKey = null;
218
+ }
219
+ const showImage = (!!ref || !!dataset.volume) && view.showImage !== false;
220
+ // A size/colour/opacity/selection change is DISPLAY-only: mutate the layer
221
+ // rather than dropping and re-adding it. Both setters bump the layer's
222
+ // dataVersion, which is what makes napari-js rebuild the instance buffer and
223
+ // redraw — and it avoids rebuilding 84k positions to change one number.
224
+ // The slice is part of the key: a scrub changes WHICH observations are drawn,
225
+ // which is geometry, not display.
226
+ const key = `${dataset.id}:${obs.count}:${slab?.slice ?? ''}`;
227
+ if (this.points && key === this.layerKey) {
228
+ this.points.size = size;
229
+ this.points.visible = this.pointsVisible();
230
+ this.points.faceColor = gatherColors(faceColor, slab?.indices);
231
+ this.hideForeignImage(viewer, showImage);
232
+ this.ctx.tools.regionOverlay?.setRegionsVisible(view.showAnnotations !== false);
233
+ viewer.requestRender();
234
+ return;
235
+ }
236
+ if (this.points) {
237
+ viewer.layers.remove(this.points);
238
+ this.points = null;
239
+ }
240
+ const drawn = slab?.indices;
241
+ const positions = observationPositions(obs, drawn);
242
+ this.layerKey = key;
243
+ this.drawn = drawn ?? null;
244
+ this.points = viewer.addPoints(positions, {
245
+ name: 'observations',
246
+ size,
247
+ faceColor: gatherColors(faceColor, drawn),
248
+ // No border: at Visium spot density an outline per marker reads as noise,
249
+ // and it costs a second colour array.
250
+ borderWidth: 0,
251
+ // The dataset's data->world affine. SpatialData records one per coordinate
252
+ // system (Visium spot coords are in the FULL-resolution frame while the
253
+ // served image may be the hires downscale), so without this the markers
254
+ // land in the right shape at the wrong scale. Defaults to identity when
255
+ // the coordinates are already in the image's pixel space.
256
+ scale: ref?.scale ?? [1, 1],
257
+ translate: ref?.translate ?? [0, 0],
258
+ visible: this.pointsVisible(),
259
+ });
260
+ // Outlines, density and transcripts go back over the markers just added.
261
+ this.session.tiles?.afterObservations();
262
+ this.frameOnce(viewer, dataset.id, positions, !!ref);
263
+ this.hideForeignImage(viewer, showImage);
264
+ this.ctx.tools.regionOverlay?.setRegionsVisible(view.showAnnotations !== false);
265
+ this.setRegionGridFor(dataset, positions);
266
+ }
267
+ /**
268
+ * Tell the region overlay how finely a drawn vertex may be placed.
269
+ *
270
+ * Region geometry is stored in whole world units, which is right when the world IS
271
+ * pixels — a region should align to them. It is wrong for a dataset that registers onto
272
+ * no image: seqFISH's observations span about 5 x 7 units in total, so whole-unit
273
+ * vertices leave roughly six by eight placeable positions across the entire sample and
274
+ * an ROI cannot be drawn at any zoom. Nothing errors; the tool just cannot express the
275
+ * shape.
276
+ *
277
+ * Keyed on whether the dataset brings PIXELS rather than on the extent, because the
278
+ * extent cannot tell the two apart — 2,000 units is a small slide or a large section
279
+ * depending only on what the units are, and only the dataset knows.
280
+ */
281
+ setRegionGridFor(dataset, positions) {
282
+ const overlay = this.ctx.tools.regionOverlay;
283
+ if (!overlay?.setWorldQuantum)
284
+ return;
285
+ if (dataset.imageRef || dataset.volume) {
286
+ overlay.setWorldQuantum(PIXEL_WORLD_QUANTUM);
287
+ return;
288
+ }
289
+ let minX = Infinity;
290
+ let maxX = -Infinity;
291
+ let minY = Infinity;
292
+ let maxY = -Infinity;
293
+ for (let i = 0; i < positions.length; i += 2) {
294
+ const x = positions[i];
295
+ const y = positions[i + 1];
296
+ if (!Number.isFinite(x) || !Number.isFinite(y))
297
+ continue;
298
+ if (x < minX)
299
+ minX = x;
300
+ if (x > maxX)
301
+ maxX = x;
302
+ if (y < minY)
303
+ minY = y;
304
+ if (y > maxY)
305
+ maxY = y;
306
+ }
307
+ overlay.setWorldQuantum(worldQuantumForExtent(maxX - minX, maxY - minY));
308
+ }
309
+ /**
310
+ * Hide the image layer for a dataset that brings no image of its own.
311
+ *
312
+ * The host's viewer keeps whatever image was last loaded, and for a dataset that
313
+ * registers onto none that picture belongs to something else entirely — the example's
314
+ * default slide, say. It is not merely irrelevant: the two live in different coordinate
315
+ * spaces (image pixels against the embedding's own units), so the leftover is magnified
316
+ * roughly a hundredfold. At the fitted zoom the camera sits inside its corner, where it
317
+ * reads as blank background, and it appears only once you zoom out far enough to find
318
+ * it — which is exactly how it gets noticed.
319
+ *
320
+ * Hidden rather than removed, and hidden HERE rather than by clearing the host's image
321
+ * state: that state drives the whole render pipeline, including a Plotly backend whose
322
+ * fields are declared with definite-assignment assertions, so emptying it throws from
323
+ * whichever field the next path happens to read. This touches one layer's visibility
324
+ * and nothing else.
325
+ */
326
+ hideForeignImage(viewer, datasetHasPixels) {
327
+ // No image of its own → nothing for an overview to show either.
328
+ this.image.showNavigatorFor(datasetHasPixels);
329
+ const tiles = this.session.tiles;
330
+ for (const layer of viewer.layers.items) {
331
+ if (layer.kind !== 'image')
332
+ continue;
333
+ // The transcript-density raster and the gene map are image layers too, but they are
334
+ // data, not the tissue: the Images toggle must not take them down with the slide.
335
+ if (tiles?.owns(layer) || layer === this.geneMapLayer)
336
+ continue;
337
+ // Re-shown when a dataset that owns an image comes back, so switching between
338
+ // datasets does not leave the tissue permanently hidden.
339
+ layer.visible = datasetHasPixels;
340
+ }
341
+ viewer.requestRender();
342
+ }
343
+ /**
344
+ * Frame the camera on the observations, for a dataset that brings no image.
345
+ *
346
+ * The 2D camera is normally fitted to the IMAGE, because the observations are in that
347
+ * image's pixel space and framing the image frames them too. A dataset with no
348
+ * reference image has coordinates in its own units instead — seqFISH's span about
349
+ * 5x7 — so the image framing left over from whatever was on screen before puts the
350
+ * whole cloud offscreen: measured at 9.7 x 13.4 PIXELS, centred 256px from where the
351
+ * camera was looking. The points are all there and drawn; they are a speck. Which
352
+ * looks exactly like the dataset having failed to load.
353
+ *
354
+ * Once per dataset, as napari-js's `fit3d: 'once'` does for the cloud: re-colouring,
355
+ * slicing or picking a gene re-adds this layer, and re-framing on those would move
356
+ * the camera under the user — the camera tools and the canvas drag are meant to be
357
+ * the only things that do.
358
+ */
359
+ frameOnce(viewer, datasetId, positions, registered) {
360
+ // Gated on whether THIS dataset registers onto an image, not on the image size: that keeps
361
+ // the last plotted image's dimensions after the host clears it, so a stale 512x383 read as
362
+ // "there is an image" and skipped the framing entirely.
363
+ if (registered)
364
+ return;
365
+ // Once per dataset (see above).
366
+ if (this.framed === datasetId)
367
+ return;
368
+ const { canvas } = this.ctx;
369
+ const fit = framePositions(positions, canvas.clientWidth ?? 0, canvas.clientHeight ?? 0);
370
+ // Null means there is nothing to frame on; leave the camera where it is rather
371
+ // than moving the view for a dataset we cannot fit.
372
+ if (!fit)
373
+ return;
374
+ viewer.camera.set(fit.center, fit.zoom ?? viewer.camera.zoom);
375
+ this.framed = datasetId;
376
+ }
377
+ /**
378
+ * The **gene map**: the active gene's expression as a continuous field drawn under
379
+ * the cells.
380
+ *
381
+ * A scatter coloured by a gene says which cells express it; it cannot say where,
382
+ * because the eye will not integrate thousands of dots into a territory. The field
383
+ * is a kernel-weighted MEAN per cell (see `spatial-expression.ts`), so a dense
384
+ * region does not glow merely for being dense, and it is transparent wherever no
385
+ * cell was measured — an unsampled gap must not read as "not expressed".
386
+ *
387
+ * It shares the points' LUT, percentile window and log flag, so the layer under
388
+ * the cells and the cells themselves cannot disagree about what a colour means.
389
+ *
390
+ * Estimated on the DISPLAYED image's pixel grid, coarsened so the long side is at
391
+ * most `GENE_MAP_MAX_SIDE`: a smooth field gains nothing from a slide's full
392
+ * resolution. For a volume-backed dataset that grid is the current slice, and only
393
+ * that plane's observations are included — the same rule the markers follow.
394
+ */
395
+ async ensureGeneMap(viewer, dataset, view, selection, slab) {
396
+ const gene = view.geneMap && view.colorBy?.kind === 'feature' ? view.colorBy.name : null;
397
+ const port = this.session.port;
398
+ const cache = this.session.geneMap;
399
+ const smoothing = view.geneMapSmoothing > 0 ? view.geneMapSmoothing : 1;
400
+ const clip = view.percentileClip ?? [0.01, 0.99];
401
+ // Two clocks: the FIELD depends on the gene, the plane and the bandwidth, while
402
+ // the colours depend on the window, the log flag and the opacity. Recolouring a
403
+ // cached field is a fraction of estimating one.
404
+ const fieldKey = gene
405
+ ? [dataset.id, gene, slab?.slice ?? '', smoothing, this.session.selectionRev(selection)].join('|')
406
+ : null;
407
+ const key = fieldKey
408
+ ? [
409
+ fieldKey,
410
+ clip.join(','),
411
+ view.logScale ? 'log' : 'lin',
412
+ view.geneMapOpacity,
413
+ this.ctx.display.continuousColormapKey(view),
414
+ ].join('|')
415
+ : null;
416
+ // A stitched slice re-render clears the whole layer list, the map with it, and the key of a
417
+ // registered image's map does not name the slice: a map no longer in the scene is absent,
418
+ // as the markers' is (see `rebuild`), so it is drawn again from the cached field.
419
+ if (this.geneMapLayer && !viewer.layers.items.includes(this.geneMapLayer)) {
420
+ this.geneMapLayer = null;
421
+ this.geneMapKey = null;
422
+ }
423
+ if (key === this.geneMapKey)
424
+ return;
425
+ if (this.geneMapLayer) {
426
+ viewer.layers.remove(this.geneMapLayer);
427
+ this.geneMapLayer = null;
428
+ }
429
+ this.geneMapKey = key;
430
+ if (!key || !gene || !port) {
431
+ cache.field = null;
432
+ cache.key = null;
433
+ return;
434
+ }
435
+ // The raster covers the displayed image; without one there is nothing to
436
+ // overlay and the cloud is the 3D mode's business, not this one's. Gated on the
437
+ // DATASET bringing pixels, not on the image size: that keeps the last plotted image's
438
+ // size after the host clears it, which would size the map over the wrong extent.
439
+ if (!slab && !dataset.imageRef)
440
+ return;
441
+ const size = this.ctx.imageSize();
442
+ const imageW = slab ? dataset.volume.width : size.width;
443
+ const imageH = slab ? dataset.volume.height : size.height;
444
+ if (!imageW || !imageH)
445
+ return;
446
+ const step = Math.max(1, Math.ceil(Math.max(imageW, imageH) / GENE_MAP_MAX_SIDE));
447
+ if (fieldKey !== cache.key) {
448
+ const load = this.geneMapLoads.next();
449
+ let values;
450
+ try {
451
+ values = await port.getFeatureVector(gene);
452
+ }
453
+ catch (err) {
454
+ console.warn(`[napari-js] gene map: "${gene}" unavailable`, err);
455
+ this.geneMapKey = null;
456
+ return;
457
+ }
458
+ if (!load() || this.geneMapKey !== key)
459
+ return;
460
+ const inSelection = selection.count > 0 ? maskToIndices(selection.mask) : undefined;
461
+ let estimated;
462
+ try {
463
+ estimated = await computeExpressionFieldAsync(dataset.observations, {
464
+ ref: slab?.ref ?? dataset.imageRef,
465
+ width: Math.ceil(imageW / step),
466
+ height: Math.ceil(imageH / step),
467
+ step,
468
+ sigma: GENE_MAP_SIGMA * smoothing,
469
+ values,
470
+ // A plane wins over a selection: the 2D view is showing one section, so a
471
+ // field spanning the specimen's depth would not be the thing on screen.
472
+ indices: slab?.indices ?? inSelection,
473
+ }, { signal: load.signal });
474
+ }
475
+ catch (err) {
476
+ if (isAbortError(err))
477
+ return; // superseded by a newer map, or the scene went away
478
+ throw err;
479
+ }
480
+ if (!load() || this.geneMapKey !== key)
481
+ return;
482
+ cache.field = estimated;
483
+ cache.key = fieldKey;
484
+ }
485
+ const field = cache.field;
486
+ if (!field)
487
+ return;
488
+ const lut = this.ctx.display.spatialLut(view);
489
+ // Over the measured pixels only: unmeasured ones are 0 and would drag the low end down.
490
+ const [lo, hi] = fieldContrastWindow(field, clip[0], clip[1]);
491
+ const rgba = colorExpressionField(field, lut, [lo, hi], {
492
+ log: view.logScale,
493
+ // The MAP's own opacity: reading a field under the cells means turning the
494
+ // cells down, which must not take the field with them.
495
+ opacity: view.geneMapOpacity,
496
+ });
497
+ this.geneMapLayer = viewer.addImage({ kind: 'typed', width: field.width, height: field.height, channels: 4, dtype: 'uint8', data: rgba }, {
498
+ name: `gene map · ${gene}`,
499
+ scale: [step, step],
500
+ translate: [0, 0],
501
+ blending: 'translucent',
502
+ });
503
+ // `addImage` appends, so the map just landed over the cells (drawn by this rebuild's
504
+ // previous pass, or by a newer rebuild while the field was computing): move it to just under
505
+ // them. A move keeps the markers' GPU buffers, where dropping and re-adding the markers
506
+ // re-uploaded every one of them (NAPARI-BOUNDARY-11). Without markers on screen there is
507
+ // nothing to go under; the rebuild adds them over the map.
508
+ const under = this.points ? viewer.layers.items.indexOf(this.points) : -1;
509
+ if (under >= 0)
510
+ viewer.layers.move(this.geneMapLayer, under);
511
+ viewer.requestRender();
512
+ }
513
+ /**
514
+ * Per-observation colours for the current view state, or a single flat colour when nothing is
515
+ * selected to colour by. Categorical columns use the column's own palette; continuous columns
516
+ * and gene vectors go through the active colormap with a percentile-clipped window.
517
+ */
518
+ async faceColors(dataset, view, selection) {
519
+ const port = this.session.port;
520
+ const colorBy = view.colorBy;
521
+ // Everything NOT selected is muted; with nothing selected, nothing is muted
522
+ // and the whole tissue reads normally (the CosMx highlight-vs-mute rule).
523
+ const muted = mutedFromSelection(selection);
524
+ if (!port || !colorBy) {
525
+ // Genuinely uniform: one broadcast tuple, so a flat 84k-observation view
526
+ // does not allocate a colour per point.
527
+ if (!muted && view.opacity >= 1)
528
+ return SPATIAL_NEUTRAL_COLOR;
529
+ // Not uniform — the opacity control or a selection varies the alpha, so it
530
+ // has to be per-point. Returning the constant tuple here is what made the
531
+ // Opacity slider do nothing in the default state, which is the state anyone
532
+ // lands in before picking a colour source.
533
+ return encodeCategorical(new Uint16Array(dataset.observations.count), {
534
+ colors: [SPATIAL_NEUTRAL_HEX],
535
+ opacity: view.opacity,
536
+ muted,
537
+ });
538
+ }
539
+ if (colorBy.kind === 'column') {
540
+ const column = await port.getColumn(colorBy.name);
541
+ if (isCategoricalColumn(column)) {
542
+ const rgba = encodeCategorical(column.codes, {
543
+ colors: resolveCategoryColors(column.meta),
544
+ opacity: view.opacity,
545
+ muted,
546
+ });
547
+ // Groups switched off in the Cells panel hide their dots too, when the dots are
548
+ // coloured by that same grouping.
549
+ const groupColumn = cellTypeColumnFor(dataset, view);
550
+ if (view.hiddenGroups?.length && groupColumn === colorBy.name) {
551
+ const off = new Set(view.hiddenGroups);
552
+ const hide = column.meta.categories.map((c) => off.has(c));
553
+ for (let i = 0; i < column.codes.length; i++) {
554
+ const c = column.codes[i];
555
+ if (c !== NO_CATEGORY && hide[c])
556
+ rgba[4 * i + 3] = 0;
557
+ }
558
+ }
559
+ return rgba;
560
+ }
561
+ // A continuous column may carry its own log hint (counts); the view's
562
+ // toggle wins once the user has set it.
563
+ return this.encodeContinuous(column.values, view, muted);
564
+ }
565
+ const values = await port.getFeatureVector(colorBy.name);
566
+ return this.encodeContinuous(values, view, muted);
567
+ }
568
+ /** Continuous values → RGBA through the active colormap and a clipped window. */
569
+ encodeContinuous(values, view, muted = null) {
570
+ return encodeSpatialContinuous(values, view, this.ctx.display.spatialLut(view), this.session.contrastWindows, muted);
571
+ }
572
+ }
573
+ /** The markers' diameters: each observation's own (or the fallback), at least the slab's floor,
574
+ * times the view's point scale; one number when every marker is drawn at the same size. */
575
+ function markerSizes(obs, view, slab) {
576
+ const base = markerDiameters(obs, SPATIAL_FALLBACK_RADIUS);
577
+ const scale = view.pointScale > 0 ? view.pointScale : 1;
578
+ const floor = slab?.minDiameter ?? 0;
579
+ if (typeof base === 'number' && !slab)
580
+ return Math.max(base, floor) * scale;
581
+ const sizeOf = (i) => Math.max(typeof base === 'number' ? base : base[i], floor) * scale;
582
+ return Float32Array.from(slab?.indices ?? { length: obs.count }, (_v, i) => sizeOf(slab ? slab.indices[i] : i));
583
+ }
584
+ /** Interleaved x,y of the `drawn` observations (undefined: all of them). */
585
+ function observationPositions(obs, drawn) {
586
+ const count = drawn ? drawn.length : obs.count;
587
+ const positions = new Float32Array(count * 2);
588
+ for (let i = 0; i < count; i++) {
589
+ const o = drawn ? drawn[i] : i;
590
+ positions[i * 2] = obs.x[o];
591
+ positions[i * 2 + 1] = obs.y[o];
592
+ }
593
+ return positions;
594
+ }
595
+ /**
596
+ * The plane `slice` of a volume-backed dataset: its pixel affine, the observations that fall in
597
+ * it, and the marker floor that grid needs.
598
+ *
599
+ * Null for a dataset with a real `imageRef` (its coordinates are already the image's pixels and
600
+ * every observation belongs to the one section) and for one with no volume at all — both of
601
+ * which draw exactly as before.
602
+ */
603
+ function slabAt(dataset, slice) {
604
+ const volume = dataset.volume;
605
+ if (dataset.imageRef || !volume)
606
+ return null;
607
+ return {
608
+ ref: volumeImageRef(volume, dataset.micronsPerUnit),
609
+ indices: observationsInSlice(dataset.observations, volume, slice),
610
+ slice,
611
+ minDiameter: SPATIAL_SLICE_MIN_DIAMETER_PX * volume.voxelSize[0],
612
+ };
613
+ }
614
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtMmQtc2NlbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtMmQtc2NlbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0EsT0FBTyxFQUNMLFdBQVcsRUFLWCxtQkFBbUIsR0FDcEIsTUFBTSwwQ0FBMEMsQ0FBQztBQUVsRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsZUFBZSxFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDM0csT0FBTyxFQUVMLGNBQWMsRUFDZCxhQUFhLEVBQ2Isa0JBQWtCLEdBQ25CLE1BQU0saUNBQWlDLENBQUM7QUFDekMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3RGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN6RixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEVBQW1CLG9CQUFvQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDOUcsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDekUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixjQUFjLEVBQ2QsdUJBQXVCLEVBQ3ZCLHFCQUFxQixFQUNyQixtQkFBbUIsRUFDbkIsNkJBQTZCLEVBRTdCLHVCQUF1QixFQUN2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ZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHsgSUhpc3RvZ3JhbSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jaGFubmVsLWhpc3RvZ3JhbS1hcGkuY29udHJhY3QnO1xuaW1wb3J0IHtcbiAgTk9fQ0FURUdPUlksXG4gIFNwYXRpYWxDb2x1bW4sXG4gIFNwYXRpYWxEYXRhc2V0LFxuICBTcGF0aWFsSW1hZ2VSZWYsXG4gIFNwYXRpYWxPYnNlcnZhdGlvbnMsXG4gIGlzQ2F0ZWdvcmljYWxDb2x1bW4sXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IGVuY29kZUNhdGVnb3JpY2FsLCBtYXJrZXJEaWFtZXRlcnMsIHJlc29sdmVDYXRlZ29yeUNvbG9ycyB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1lbmNvZGluZyc7XG5pbXBvcnQge1xuICBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgZW1wdHlTZWxlY3Rpb24sXG4gIG1hc2tUb0luZGljZXMsXG4gIG11dGVkRnJvbVNlbGVjdGlvbixcbn0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXNlbGVjdGlvbic7XG5pbXBvcnQgeyBmcmFtZVBvc2l0aW9ucyB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1mcmFtaW5nJztcbmltcG9ydCB7IFBJWEVMX1dPUkxEX1FVQU5UVU0sIHdvcmxkUXVhbnR1bUZvckV4dGVudCB9IGZyb20gJy4uLy4uL3NwYXRpYWwvd29ybGQtZ3JpZCc7XG5pbXBvcnQgeyBvYnNlcnZhdGlvbnNJblNsaWNlLCB2b2x1bWVJbWFnZVJlZiB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC12b2x1bWUtaW1hZ2UnO1xuaW1wb3J0IHsgY2VsbFR5cGVDb2x1bW5Gb3IgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtdGlsZXMnO1xuaW1wb3J0IHsgRXhwcmVzc2lvbkZpZWxkLCBjb2xvckV4cHJlc3Npb25GaWVsZCwgZmllbGRDb250cmFzdFdpbmRvdyB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1leHByZXNzaW9uJztcbmltcG9ydCB7IGNvbXB1dGVFeHByZXNzaW9uRmllbGRBc3luYyB9IGZyb20gJy4uLy4uL3dvcmtlcnMvc3BhdGlhbC1tYXRoJztcbmltcG9ydCB7IFN1cGVyc2VkZSB9IGZyb20gJy4uLy4uL3V0aWwvc3VwZXJzZWRlJztcbmltcG9ydCB7IGlzQWJvcnRFcnJvciB9IGZyb20gJy4uL3RpbGUtc2VydmVyJztcbmltcG9ydCB7IE5hcGFyaVNwYXRpYWxUaWxlTGF5ZXJzIH0gZnJvbSAnLi9uYXBhcmktc3BhdGlhbC10aWxlcyc7XG5pbXBvcnQgeyBJbWFnZTJkU2NlbmUgfSBmcm9tICcuL25hcGFyaS1pbWFnZS0yZC1zY2VuZSc7XG5pbXBvcnQge1xuICBHRU5FX01BUF9NQVhfU0lERSxcbiAgR0VORV9NQVBfU0lHTUEsXG4gIFNQQVRJQUxfRkFMTEJBQ0tfUkFESVVTLFxuICBTUEFUSUFMX05FVVRSQUxfQ09MT1IsXG4gIFNQQVRJQUxfTkVVVFJBTF9IRVgsXG4gIFNQQVRJQUxfU0xJQ0VfTUlOX0RJQU1FVEVSX1BYLFxuICBQb2ludENvbG9ycyxcbiAgZW5jb2RlU3BhdGlhbENvbnRpbnVvdXMsXG4gIGdhdGhlckNvbG9ycyxcbn0gZnJvbSAnLi9uYXBhcmktc3BhdGlhbC1lbmNvZGluZyc7XG5pbXBvcnQgeyBTcGF0aWFsU2NlbmVCYXNlLCBTcGF0aWFsU2Vzc2lvbiwgU3BhdGlhbFRpbGVPd25lciB9IGZyb20gJy4vbmFwYXJpLXNwYXRpYWwtc2NlbmUnO1xuaW1wb3J0IHR5cGUgeyBOYXBhcmlTY2VuZSwgU2NlbmVDb250ZXh0IH0gZnJvbSAnLi9uYXBhcmktc2NlbmUnO1xuXG4vKiogVGhlIHBsYW5lIGEgdm9sdW1lLWJhY2tlZCBkYXRhc2V0IGlzIHNob3dpbmcgKHNlZSB7QGxpbmsgU3BhdGlhbDJkU2NlbmUuc2xhYn0pLiAqL1xuaW50ZXJmYWNlIFNsYWIge1xuICByZWY6IFNwYXRpYWxJbWFnZVJlZjtcbiAgaW5kaWNlczogVWludDMyQXJyYXk7XG4gIHNsaWNlOiBudW1iZXI7XG4gIG1pbkRpYW1ldGVyOiBudW1iZXI7XG59XG5cbi8qKlxuICogU1BBVElBTF9PTUlDUyAocmV2aWV3IEFwcGVuZGl4IEIsIGNsdXN0ZXIgSik6IHRoZSB0aXNzdWUgaW1hZ2UgKGFuIHtAbGluayBJbWFnZTJkU2NlbmV9KSB3aXRoIG9uZVxuICogbWFya2VyIHBlciBvYnNlcnZhdGlvbiwgY29sb3VyZWQgYnkgYW4gYW5ub3RhdGlvbiBjb2x1bW4gb3IgYSBnZW5lLCB0aGUgZ2VuZSBtYXAgdW5kZXIgdGhlXG4gKiBjZWxscywgYW5kIHRoZSBsZXZlbC1vZi1kZXRhaWwgdGlsZSBsYXllcnMgKG91dGxpbmVzLCB0cmFuc2NyaXB0cywgZGVuc2l0eSkgb3ZlciB0aGVtLiBUaGVcbiAqIG1hcmtlcnMgcmVidWlsZCB3aGVuZXZlciB0aGUgZGF0YXNldCBvciB0aGUgdmlldyBzdGF0ZSBjaGFuZ2VzLCBzbyBzd2l0Y2hpbmcgdGhlIGNvbG91ci1ieVxuICogY29sdW1uIGRvZXMgbm90IHJlbW91bnQgdGhlIHNjZW5lLlxuICpcbiAqIFNldHMgdXAgdGhlIGZ1bGwgMkQgaW50ZXJhY3Rpb24gc3RhY2sg4oCUIHJlZ2lvbiBvdmVybGF5LCBwaXhlbCB0b29scywgcmVhZGJhY2sgY3VycmVuY3kg4oCUIGV4YWN0bHlcbiAqIGFzIHRoZSBwbGFpbiBpbWFnZSB2aWV3IGRvZXMuIFRoYXQgaXMgTk9UIG9wdGlvbmFsIGhlcmU6IHRoaXMgbW9kZSdzIHNlbGVjdGlvbiBpcyBkcml2ZW4gYnlcbiAqIGRyYXduIFJPSXMsIHNvIHdpdGhvdXQgdGhlIG92ZXJsYXkgdGhlcmUgaXMgbm8gd2F5IHRvIG1ha2UgYSBzZWxlY3Rpb24gYXQgYWxsLlxuICovXG5leHBvcnQgY2xhc3MgU3BhdGlhbDJkU2NlbmUgZXh0ZW5kcyBTcGF0aWFsU2NlbmVCYXNlIGltcGxlbWVudHMgTmFwYXJpU2NlbmUsIFNwYXRpYWxUaWxlT3duZXIge1xuICByZWFkb25seSBpbWFnZTogSW1hZ2UyZFNjZW5lO1xuICAvKiogVGhlIG9ic2VydmF0aW9uIG1hcmtlcnMsIGFuZCB3aGljaCBkYXRhc2V0L3BsYW5lIHRoZXkgd2VyZSBidWlsdCBmb3Ig4oCUIHNvIGEgZGlzcGxheS1vbmx5XG4gICAqICBjaGFuZ2UgKHNpemUsIGNvbG91ciwgb3BhY2l0eSwgc2VsZWN0aW9uKSBjYW4gdXBkYXRlIHRoZW0gaW4gcGxhY2UuICovXG4gIHByaXZhdGUgcG9pbnRzOiBQb2ludHNMYXllciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGxheWVyS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBvYnNlcnZhdGlvbiBlYWNoIG1hcmtlciBpcywgaW4gZHJhdyBvcmRlcjsgbnVsbCB3aGVuIGV2ZXJ5IG9ic2VydmF0aW9uIGlzIGRyYXduLiAqL1xuICBwcml2YXRlIGRyYXduOiBVaW50MzJBcnJheSB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGdlbmUgbWFwJ3MgbGF5ZXIgYW5kIHRoZSBpbnB1dHMgaXQgd2FzIGNvbG91cmVkIGZvciAoaXRzIGZpZWxkIGlzIGNhY2hlZCBpbiB0aGUgc2Vzc2lvbixcbiAgICogIG9uIGEgY2xvY2sgb2YgaXRzIG93bikuICovXG4gIGdlbmVNYXBMYXllcjogSW1hZ2VMYXllciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGdlbmVNYXBLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGRhdGFzZXQgdGhlIGNhbWVyYSBoYXMgYmVlbiBmcmFtZWQgb24g4oCUIHNlZSB7QGxpbmsgZnJhbWVPbmNlfS4gKi9cbiAgcHJpdmF0ZSBmcmFtZWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGdlbmUtbWFwIGVzdGltYXRlIGluIGZsaWdodCAob2ZmIHRoZSBtYWluIHRocmVhZCBwYXN0IHRoZSB3b3JrZXIgdGhyZXNob2xkLFxuICAgKiAgU1BBVElBTC0xOSk6IGEgbmV3IGZpZWxkIGtleSBzdXBlcnNlZGVzIOKAlCBhbmQgYWJvcnRzIOKAlCBpdDsgYSByZWJ1aWxkIHRoYXQgbGVhdmVzIHRoZSBrZXlcbiAgICogIGFsb25lIGxldHMgaXQgZmluaXNoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGdlbmVNYXBMb2FkcyA9IG5ldyBTdXBlcnNlZGUoKTtcblxuICAvKiogYG5vSW1hZ2VgOiBhbiBpbWFnZS1sZXNzIGRhdGFzZXQgb3BlbmVkIGJlZm9yZSBhbnkgaW1hZ2Ug4oCUIHRoZSBvYnNlcnZhdGlvbnMgYWxvbmUuICovXG4gIGNvbnN0cnVjdG9yKGN0eDogU2NlbmVDb250ZXh0LCBzZXNzaW9uOiBTcGF0aWFsU2Vzc2lvbiwgbm9JbWFnZSA9IGZhbHNlKSB7XG4gICAgc3VwZXIoY3R4LCBzZXNzaW9uLCBmYWxzZSk7XG4gICAgdGhpcy5pbWFnZSA9IG5ldyBJbWFnZTJkU2NlbmUoY3R4LCB7XG4gICAgICBpbWFnZTogIW5vSW1hZ2UsXG4gICAgICAvLyBPbmx5IGZpdCB0byB0aGUgaW1hZ2Ugd2hlbiB0aGlzIGRhdGFzZXQgYWN0dWFsbHkgaGFzIG9uZS4gT3RoZXJ3aXNlIHRoZXJlIGlzIG5vdGhpbmcgdG9cbiAgICAgIC8vIGZpdCwgdGhlIGltYWdlIHNpemUgc3RpbGwgaG9sZHMgdGhlIExBU1QgaW1hZ2UncyBkaW1lbnNpb25zLCBhbmQgdGhpcyBmaXRzIHRvIHRob3NlIOKAlCBhbmRcbiAgICAgIC8vIGJlY2F1c2UgaXQgZGVmZXJzIHRvIGEgZnJhbWUsIGl0IGxhbmRzIEFGVEVSIHRoZSBwb2ludHMgYXJlIGFkZGVkIGFuZCBvdmVyd3JpdGVzIHRoZVxuICAgICAgLy8gZnJhbWluZyB0aGV5IHNldC4gVGhhdCBpcyB3aGF0IGxlZnQgYW4gaW1hZ2UtbGVzcyBkYXRhc2V0IGFzIGEgdGVuLXBpeGVsIHNwZWNrLlxuICAgICAgZml0OiAoKSA9PiAhIXNlc3Npb24ubGF0ZXN0Py5bMF0/LmltYWdlUmVmLFxuICAgICAgb25TbGljZTogKHJlcmVuZGVyZWQpID0+IHtcbiAgICAgICAgdGhpcy5yZWRyYXdNYXJrZXJzKCk7XG4gICAgICAgIC8vIFRoZSBzdGl0Y2hlZCByZS1yZW5kZXIgY2xlYXJlZCB0aGUgY2VsbHMsIHRyYW5zY3JpcHRzIGFuZCBkZW5zaXR5IHRvbzogcmUtcGxhbiB0aGVtIG5vd1xuICAgICAgICAvLyByYXRoZXIgdGhhbiBhdCB0aGUgbmV4dCBjYW1lcmEgbW92ZSAoZWFjaCBncm91cCByZWRyYXdzIG9ubHkgd2hhdCBsZWZ0IHRoZSBzY2VuZSkuXG4gICAgICAgIGlmIChyZXJlbmRlcmVkKSB0aGlzLnNlc3Npb24udGlsZXM/LnJlZnJlc2goKTtcbiAgICAgIH0sXG4gICAgICBvbk5hdmlnYXRvckludGVyYWN0OiAoKSA9PiB0aGlzLmhvdmVyLmhpZGUoKSxcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIG1vdW50KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzO1xuICAgIGF3YWl0IHRoaXMuaW1hZ2UubW91bnQoKTtcbiAgICAvLyBEaXNwb3NlZCB3aGlsZSB0aGUgaW1hZ2UgbG9hZGVkOiBjbGFpbWluZyB0aGUgdGlsZXMgbm93IHdvdWxkIHRha2UgdGhlbSBmcm9tIHRoZSBuZXh0IHNjZW5lLFxuICAgIC8vIGFuZCB0aGUgc3BhdGlhbCBzdWJzY3JpcHRpb24gd291bGQgb3V0bGl2ZSB0aGlzIG9uZS5cbiAgICBpZiAoY3R4LnNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgdGhpcy5ob3Zlci5pbnN0YWxsKGN0eC5ob3N0KTtcbiAgICB0aGlzLnNlc3Npb24uY2xhaW1UaWxlcyh0aGlzKT8uYXR0YWNoKGN0eC52aWV3ZXIpO1xuICAgIHRoaXMuc3Vic2NyaWJlU3BhdGlhbCgpO1xuICAgIGN0eC50b29scy5zY2hlZHVsZVJlYWRiYWNrKCk7XG4gIH1cblxuICBzZXRaKHo6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaW1hZ2Uuc2V0Wih6KTtcbiAgfVxuXG4gIGhpc3RvZ3JhbShjaGFubmVsOiBudW1iZXIsIGJpbnM6IG51bWJlcik6IElIaXN0b2dyYW0gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5pbWFnZS5oaXN0b2dyYW0oY2hhbm5lbCwgYmlucyk7XG4gIH1cblxuICBzZXRJbWFnZVNtb290aGluZyhlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5pbWFnZS5zZXRJbWFnZVNtb290aGluZyhlbmFibGVkKTtcbiAgfVxuXG4gIHNldE5hdmlnYXRvclZpc2libGUodmlzaWJsZTogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuaW1hZ2Uuc2V0TmF2aWdhdG9yVmlzaWJsZSh2aXNpYmxlKTtcbiAgfVxuXG4gIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwb3NlU3BhdGlhbCgpO1xuICAgIHRoaXMuZ2VuZU1hcExvYWRzLmNhbmNlbCgpO1xuICAgIHRoaXMuc2Vzc2lvbi5yZWxlYXNlVGlsZXModGhpcyk7XG4gICAgdGhpcy5pbWFnZS5kaXNwb3NlKCk7XG4gIH1cblxuICBjYW52YXNTaXplKCk6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgIHJldHVybiBbdGhpcy5jdHguY2FudmFzLmNsaWVudFdpZHRoID8/IDAsIHRoaXMuY3R4LmNhbnZhcy5jbGllbnRIZWlnaHQgPz8gMF07XG4gIH1cblxuICBwb2x5Z29uc1Nob3duQ2hhbmdlZCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5wb2ludHMpIHRoaXMucG9pbnRzLnZpc2libGUgPSB0aGlzLnBvaW50c1Zpc2libGUoKTtcbiAgICB0aGlzLmN0eC52aWV3ZXIucmVxdWVzdFJlbmRlcigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFmdGVyQ2hhbmdlKCk6IHZvaWQge1xuICAgIHRoaXMuc2Vzc2lvbi50aWxlcz8ucmVmcmVzaCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGhvdmVyVGlsZXMoKTogTmFwYXJpU3BhdGlhbFRpbGVMYXllcnMgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uLnRpbGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBvYnNlcnZhdGlvbiB1bmRlciBhIGNsaWVudCBwb3NpdGlvbjogbmFwYXJpLWpzJ3MgcGljayBvbiB0aGUgbWFya2VyIGxheWVyIGl0c2VsZiAoYSBncmlkXG4gICAqIG92ZXIgaXRzIHBvc2l0aW9ucywgcmVidWlsdCBvbmx5IHdoZW4gdGhleSBjaGFuZ2UpLCBzbyB0aGUgdG9vbHRpcCBjYW5ub3QgbmFtZSBhIGNlbGwgdGhhdCBpc1xuICAgKiBub3QgZHJhd24sIHRoZW4gdGhlIGRyYXduIGluZGV4IG1hcHBlZCBiYWNrIHRvIHRoZSBvYnNlcnZhdGlvbi5cbiAgICpcbiAgICogQSBtYXJrZXIgaXMgaGl0IGFueXdoZXJlIG9uIGl0cyBkcmF3biBkaXNjLCBvciB3aXRoaW4gYHNsYWNrUHhgIHNjcmVlbiBwaXhlbHMgb2YgaXRzIGNlbnRyZVxuICAgKiB3aGVuIGl0IGlzIHNtYWxsZXIgdGhhbiB0aGF0IChhIDEuNSBweCBkb3Qgc3RpbGwgaGFzIHRvIGJlIGhvdmVyYWJsZSksIGFuZCBvZiBzZXZlcmFsIGhpdHMgdGhlXG4gICAqIE5FQVJFU1QgY2VudHJlIHdpbnMgKGFuIGV4YWN0IHRpZSBnb2VzIHRvIHRoZSBvbmUgZHJhd24gb24gdG9wKS4gTm90IG5hcGFyaSdzIGAndG9wbW9zdCdgOiB0aGVcbiAgICogc2xhY2sgaXMgd2lkZXIgdGhhbiBtb3N0IG1hcmtlcnMsIGFuZCBvdmVyIGEgZGVuc2UgZmllbGQgb2Ygc21hbGwgb25lcyBcInRoZSBsYXN0IGRyYXduIHdpdGhpblxuICAgKiAxMCBweFwiIG5hbWVzIGEgbmVpZ2hib3VyIHJhdGhlciB0aGFuIHRoZSBjZWxsIHVuZGVyIHRoZSBjdXJzb3IuXG4gICAqL1xuICBwcm90ZWN0ZWQgcGlja09ic2VydmF0aW9uKGNsaWVudFg6IG51bWJlciwgY2xpZW50WTogbnVtYmVyLCBzbGFja1B4OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IHBvaW50cyA9IHRoaXMucG9pbnRzO1xuICAgIGlmICghcG9pbnRzKSByZXR1cm4gLTE7XG4gICAgY29uc3Qgdmlld2VyID0gdGhpcy5jdHgudmlld2VyO1xuICAgIGNvbnN0IFt3eCwgd3ldID0gdmlld2VyLmNhbnZhc1RvV29ybGQoY2xpZW50WCwgY2xpZW50WSk7XG4gICAgY29uc3Qgem9vbSA9IHZpZXdlci5jYW1lcmEuem9vbTtcbiAgICBjb25zdCBrID0gcG9pbnRzLnBpY2sod3gsIHd5LCB7IHRvbGVyYW5jZTogc2xhY2tQeCAvICh6b29tID4gMCA/IHpvb20gOiAxKSwgdGllQnJlYWs6ICduZWFyZXN0JyB9KTtcbiAgICBpZiAoayA8IDApIHJldHVybiAtMTtcbiAgICByZXR1cm4gdGhpcy5kcmF3biA/IHRoaXMuZHJhd25ba10gOiBrO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIG1hcmtlcnMgYXJlIGRyYXduOiB3aGVuIHRoZSB1c2VyIHdhbnRzIHRoZW0sIGFuZCBub3Qgd2hpbGUgY2VsbCBvdXRsaW5lcyBhcmUgb25cbiAgICogc2NyZWVuIOKAlCB0aGVuIGEgY2VsbCBJUyBpdHMgb3V0bGluZSwgYW5kIGEgY2lyY2xlIG9uIHRvcCBvZiBpdCBpcyBub2lzZS4gWm9vbWVkIG91dCBwYXN0IHRoZVxuICAgKiBvdXRsaW5lIHRocmVzaG9sZCwgdGhlIGNpcmNsZXMgc3RhbmQgaW4gZm9yIHRoZSBjZWxscy5cbiAgICovXG4gIHByaXZhdGUgcG9pbnRzVmlzaWJsZSgpOiBib29sZWFuIHtcbiAgICBjb25zdCB2aWV3ID0gdGhpcy5zZXNzaW9uLmxhdGVzdD8uWzFdO1xuICAgIHJldHVybiAodmlldz8uc2hvd1BvaW50cyA/PyB0cnVlKSAmJiAhdGhpcy5zZXNzaW9uLnRpbGVzPy5vdXRsaW5lc1Nob3duO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZHJhdyB0aGUgbWFya2VycyBvdmVyIGEgZnJlc2hseSByZW5kZXJlZCBpbWFnZS4gVHdvIHJlYXNvbnMsIGJvdGggaW52aXNpYmxlIGZyb20gdGhlXG4gICAqIHNwYXRpYWwgc3RvcmUg4oCUIHdoaWNoIGlzIHdoeSBhIHNjcnViIG9yIGEgcmUtcmVuZGVyIG5ldmVyIHJlYWNoZWQgdGhlIG1hcmtlcnMgb24gaXRzIG93bjpcbiAgICogIC0gdGhlIGltYWdlIHJlbmRlciBDTEVBUlMgdGhlIGxheWVyIGxpc3QsIHRha2luZyB0aGUgbWFya2VycyB3aXRoIGl0O1xuICAgKiAgLSBvdmVyIGEgdm9sdW1lLWJhY2tlZCBkYXRhc2V0IHRoZSBkaXNwbGF5ZWQgcGxhbmUgZGVjaWRlcyB3aGljaCBvYnNlcnZhdGlvbnMgYmVsb25nIG9uXG4gICAqICAgIHNjcmVlbiBhdCBhbGwsIHNvIHRoZSBjZWxscyBoYXZlIHRvIG1vdmUgd2l0aCB0aGUgc2VjdGlvbiByYXRoZXIgdGhhbiBoYW5nIG92ZXIgYW5vdGhlci5cbiAgICovXG4gIHByaXZhdGUgcmVkcmF3TWFya2VycygpOiB2b2lkIHtcbiAgICBjb25zdCBsYXRlc3QgPSB0aGlzLnNlc3Npb24ubGF0ZXN0O1xuICAgIGlmICghbGF0ZXN0Py5bMF0pIHJldHVybjtcbiAgICB2b2lkIHRoaXMucmVidWlsZCguLi5sYXRlc3QpO1xuICB9XG5cbiAgLyoqIChSZSlidWlsZCB0aGUgb2JzZXJ2YXRpb24gbWFya2VyIGxheWVyIGZvciB0aGUgY3VycmVudCBkYXRhc2V0ICsgdmlldyBzdGF0ZS4gKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlYnVpbGQoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQgfCBudWxsLFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayA9IGVtcHR5U2VsZWN0aW9uKCksXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHZpZXdlciA9IHRoaXMuY3R4LnZpZXdlcjtcbiAgICBjb25zdCB0YXNrID0gdGhpcy5yZWJ1aWxkcy5uZXh0KCk7XG5cbiAgICAvLyBSZXNvbHZlIGNvbG91cnMgQkVGT1JFIHRvdWNoaW5nIHRoZSBzY2VuZTogYSBnZW5lIGZldGNoIGNhbiBmYWlsIG9yIGJlXG4gICAgLy8gc3VwZXJzZWRlZCwgYW5kIGRyb3BwaW5nIHRoZSBleGlzdGluZyBsYXllciBmaXJzdCB3b3VsZCBibGFuayB0aGUgdmlldy5cbiAgICBsZXQgZmFjZUNvbG9yOiBQb2ludENvbG9ycztcbiAgICBjb25zdCBlbmRMb2FkaW5nID0gdGhpcy5jdHguYmFkZ2UuYmVnaW4oJ09ic2VydmF0aW9ucycpO1xuICAgIHRyeSB7XG4gICAgICBmYWNlQ29sb3IgPSBkYXRhc2V0ID8gYXdhaXQgdGhpcy5mYWNlQ29sb3JzKGRhdGFzZXQsIHZpZXcsIHNlbGVjdGlvbikgOiBTUEFUSUFMX05FVVRSQUxfQ09MT1I7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHNwYXRpYWwgY29sb3VyaW5nIGZhaWxlZCDigJQgZmFsbGluZyBiYWNrIHRvIGEgZmxhdCBjb2xvdXInLCBlcnIpO1xuICAgICAgZmFjZUNvbG9yID0gU1BBVElBTF9ORVVUUkFMX0NPTE9SO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBlbmRMb2FkaW5nKCk7XG4gICAgfVxuICAgIC8vIEEgbmV3ZXIgcmVidWlsZCAob3IgYSB0ZWFyZG93bikgc3RhcnRlZCB3aGlsZSB0aGUgdmVjdG9yIHdhcyBpbiBmbGlnaHQuXG4gICAgaWYgKCF0YXNrKCkpIHJldHVybjtcblxuICAgIGlmICghZGF0YXNldCB8fCBkYXRhc2V0Lm9ic2VydmF0aW9ucy5jb3VudCA9PT0gMCkge1xuICAgICAgdGhpcy5yZW1vdmVMYXllcnModmlld2VyKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBIGRhdGFzZXQgd2hvc2UgaW1hZ2UgSVMgaXRzIHZvbHVtZSBzaG93cyBPTkUgUExBTkUgYXQgYSB0aW1lLCBzbyB0aGVcbiAgICAvLyBtYXJrZXJzIGFyZSB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBkaXNwbGF5ZWQgcGxhbmUsIGRyYXduIGluIHRoYXQgcGxhbmUnc1xuICAgIC8vIHBpeGVsIGdyaWQuIFdpdGhvdXQgdGhlIGZpbHRlciB0aGUgc3BlY2ltZW4ncyB3aG9sZSBkZXB0aCBwaWxlcyBvbnRvIG9uZVxuICAgIC8vIHNlY3Rpb24gYW5kIHJlYWRzIGFzIGEgc21lYXI7IHdpdGhvdXQgdGhlIGFmZmluZSB0aGUgY29vcmRpbmF0ZXMgYXJlIHJlYWRcbiAgICAvLyBhcyBwaXhlbHMgYW5kIGxhbmQgb2ZmIHRoZSBzbGljZSBlbnRpcmVseS5cbiAgICBjb25zdCBzbGFiID0gc2xhYkF0KGRhdGFzZXQsIHRoaXMuY3R4LnooKSk7XG4gICAgLy8gVGhlIGdlbmUgbWFwIGdvZXMgVU5ERVIgdGhlIGNlbGxzLCBzbyBpdCBpcyBzZXR0bGVkIGJlZm9yZSB0aGV5IGFyZSBhZGRlZC5cbiAgICBhd2FpdCB0aGlzLmVuc3VyZUdlbmVNYXAodmlld2VyLCBkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb24sIHNsYWIpO1xuICAgIGlmICghdGFzaygpKSByZXR1cm47XG4gICAgdGhpcy5kcmF3TWFya2Vycyh2aWV3ZXIsIGRhdGFzZXQsIHZpZXcsIGZhY2VDb2xvciwgc2xhYik7XG4gIH1cblxuICAvKiogTm90aGluZyB0byBkcmF3OiBkcm9wIHRoZSBtYXJrZXJzIGFuZCB0aGUgZ2VuZSBtYXAuICovXG4gIHByaXZhdGUgcmVtb3ZlTGF5ZXJzKHZpZXdlcjogVmlld2VyKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucG9pbnRzKSB7XG4gICAgICB2aWV3ZXIubGF5ZXJzLnJlbW92ZSh0aGlzLnBvaW50cyk7XG4gICAgICB0aGlzLnBvaW50cyA9IG51bGw7XG4gICAgICB0aGlzLmxheWVyS2V5ID0gbnVsbDtcbiAgICAgIHRoaXMuZHJhd24gPSBudWxsO1xuICAgIH1cbiAgICBpZiAodGhpcy5nZW5lTWFwTGF5ZXIpIHtcbiAgICAgIHZpZXdlci5sYXllcnMucmVtb3ZlKHRoaXMuZ2VuZU1hcExheWVyKTtcbiAgICAgIHRoaXMuZ2VuZU1hcExheWVyID0gbnVsbDtcbiAgICAgIHRoaXMuZ2VuZU1hcEtleSA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERyYXcgdGhlIG9ic2VydmF0aW9uIG1hcmtlcnMgb3ZlciB0aGUgaW1hZ2UgKGFuZCB0aGUgZ2VuZSBtYXApOiByZXN0eWxlZCBpbiBwbGFjZSBmb3IgYVxuICAgKiBkaXNwbGF5LW9ubHkgY2hhbmdlLCBlbHNlIGEgbmV3IGxheWVyLlxuICAgKi9cbiAgcHJpdmF0ZSBkcmF3TWFya2VycyhcbiAgICB2aWV3ZXI6IFZpZXdlcixcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICAgIGZhY2VDb2xvcjogUG9pbnRDb2xvcnMsXG4gICAgc2xhYjogU2xhYiB8IG51bGwsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IG9icyA9IGRhdGFzZXQub2JzZXJ2YXRpb25zO1xuICAgIGNvbnN0IHJlZiA9IHNsYWI/LnJlZiA/PyBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHNpemUgPSBtYXJrZXJTaXplcyhvYnMsIHZpZXcsIHNsYWIpO1xuXG4gICAgLy8gbmFwYXJpJ3MgaW1hZ2UgdmlldyBDTEVBUlMgdGhlIHdob2xlIGxheWVyIGxpc3Qgb24gZXZlcnkgcmVuZGVyLCBzbyB0aGVcbiAgICAvLyBtYXJrZXJzIGdvIHdpdGggaXQgd2hlbmV2ZXIgdGhlIGltYWdlIGlzIHJlLXJlbmRlcmVkIOKAlCBhIHNjcnViLCBhIGNvbnRyYXN0XG4gICAgLy8gY2hhbmdlLiBUaGUgY2FjaGVkIGhhbmRsZSBpcyB0aGVuIGRldGFjaGVkLCBhbmQgbXV0YXRpbmcgaXQgZHJhd3Mgbm90aGluZzpcbiAgICAvLyB0cmVhdCBhIGxheWVyIHRoYXQgaXMgbm8gbG9uZ2VyIGluIHRoZSBzY2VuZSBhcyBhYnNlbnQgc28gaXQgZ2V0cyByZS1hZGRlZC5cbiAgICBpZiAodGhpcy5wb2ludHMgJiYgIXZpZXdlci5sYXllcnMuaXRlbXMuaW5jbHVkZXModGhpcy5wb2ludHMpKSB7XG4gICAgICB0aGlzLnBvaW50cyA9IG51bGw7XG4gICAgICB0aGlzLmxheWVyS2V5ID0gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBzaG93SW1hZ2UgPSAoISFyZWYgfHwgISFkYXRhc2V0LnZvbHVtZSkgJiYgdmlldy5zaG93SW1hZ2UgIT09IGZhbHNlO1xuICAgIC8vIEEgc2l6ZS9jb2xvdXIvb3BhY2l0eS9zZWxlY3Rpb24gY2hhbmdlIGlzIERJU1BMQVktb25seTogbXV0YXRlIHRoZSBsYXllclxuICAgIC8vIHJhdGhlciB0aGFuIGRyb3BwaW5nIGFuZCByZS1hZGRpbmcgaXQuIEJvdGggc2V0dGVycyBidW1wIHRoZSBsYXllcidzXG4gICAgLy8gZGF0YVZlcnNpb24sIHdoaWNoIGlzIHdoYXQgbWFrZXMgbmFwYXJpLWpzIHJlYnVpbGQgdGhlIGluc3RhbmNlIGJ1ZmZlciBhbmRcbiAgICAvLyByZWRyYXcg4oCUIGFuZCBpdCBhdm9pZHMgcmVidWlsZGluZyA4NGsgcG9zaXRpb25zIHRvIGNoYW5nZSBvbmUgbnVtYmVyLlxuICAgIC8vIFRoZSBzbGljZSBpcyBwYXJ0IG9mIHRoZSBrZXk6IGEgc2NydWIgY2hhbmdlcyBXSElDSCBvYnNlcnZhdGlvbnMgYXJlIGRyYXduLFxuICAgIC8vIHdoaWNoIGlzIGdlb21ldHJ5LCBub3QgZGlzcGxheS5cbiAgICBjb25zdCBrZXkgPSBgJHtkYXRhc2V0LmlkfToke29icy5jb3VudH06JHtzbGFiPy5zbGljZSA/PyAnJ31gO1xuICAgIGlmICh0aGlzLnBvaW50cyAmJiBrZXkgPT09IHRoaXMubGF5ZXJLZXkpIHtcbiAgICAgIHRoaXMucG9pbnRzLnNpemUgPSBzaXplO1xuICAgICAgdGhpcy5wb2ludHMudmlzaWJsZSA9IHRoaXMucG9pbnRzVmlzaWJsZSgpO1xuICAgICAgdGhpcy5wb2ludHMuZmFjZUNvbG9yID0gZ2F0aGVyQ29sb3JzKGZhY2VDb2xvciwgc2xhYj8uaW5kaWNlcyk7XG4gICAgICB0aGlzLmhpZGVGb3JlaWduSW1hZ2Uodmlld2VyLCBzaG93SW1hZ2UpO1xuICAgICAgdGhpcy5jdHgudG9vbHMucmVnaW9uT3ZlcmxheT8uc2V0UmVnaW9uc1Zpc2libGUodmlldy5zaG93QW5ub3RhdGlvbnMgIT09IGZhbHNlKTtcbiAgICAgIHZpZXdlci5yZXF1ZXN0UmVuZGVyKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucG9pbnRzKSB7XG4gICAgICB2aWV3ZXIubGF5ZXJzLnJlbW92ZSh0aGlzLnBvaW50cyk7XG4gICAgICB0aGlzLnBvaW50cyA9IG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgZHJhd24gPSBzbGFiPy5pbmRpY2VzO1xuICAgIGNvbnN0IHBvc2l0aW9ucyA9IG9ic2VydmF0aW9uUG9zaXRpb25zKG9icywgZHJhd24pO1xuICAgIHRoaXMubGF5ZXJLZXkgPSBrZXk7XG4gICAgdGhpcy5kcmF3biA9IGRyYXduID8/IG51bGw7XG4gICAgdGhpcy5wb2ludHMgPSB2aWV3ZXIuYWRkUG9pbnRzKHBvc2l0aW9ucywge1xuICAgICAgbmFtZTogJ29ic2VydmF0aW9ucycsXG4gICAgICBzaXplLFxuICAgICAgZmFjZUNvbG9yOiBnYXRoZXJDb2xvcnMoZmFjZUNvbG9yLCBkcmF3biksXG4gICAgICAvLyBObyBib3JkZXI6IGF0IFZpc2l1bSBzcG90IGRlbnNpdHkgYW4gb3V0bGluZSBwZXIgbWFya2VyIHJlYWRzIGFzIG5vaXNlLFxuICAgICAgLy8gYW5kIGl0IGNvc3RzIGEgc2Vjb25kIGNvbG91ciBhcnJheS5cbiAgICAgIGJvcmRlcldpZHRoOiAwLFxuICAgICAgLy8gVGhlIGRhdGFzZXQncyBkYXRhLT53b3JsZCBhZmZpbmUuIFNwYXRpYWxEYXRhIHJlY29yZHMgb25lIHBlciBjb29yZGluYXRlXG4gICAgICAvLyBzeXN0ZW0gKFZpc2l1bSBzcG90IGNvb3JkcyBhcmUgaW4gdGhlIEZVTEwtcmVzb2x1dGlvbiBmcmFtZSB3aGlsZSB0aGVcbiAgICAgIC8vIHNlcnZlZCBpbWFnZSBtYXkgYmUgdGhlIGhpcmVzIGRvd25zY2FsZSksIHNvIHdpdGhvdXQgdGhpcyB0aGUgbWFya2Vyc1xuICAgICAgLy8gbGFuZCBpbiB0aGUgcmlnaHQgc2hhcGUgYXQgdGhlIHdyb25nIHNjYWxlLiBEZWZhdWx0cyB0byBpZGVudGl0eSB3aGVuXG4gICAgICAvLyB0aGUgY29vcmRpbmF0ZXMgYXJlIGFscmVhZHkgaW4gdGhlIGltYWdlJ3MgcGl4ZWwgc3BhY2UuXG4gICAgICBzY2FsZTogcmVmPy5zY2FsZSA/PyBbMSwgMV0sXG4gICAgICB0cmFuc2xhdGU6IHJlZj8udHJhbnNsYXRlID8/IFswLCAwXSxcbiAgICAgIHZpc2libGU6IHRoaXMucG9pbnRzVmlzaWJsZSgpLFxuICAgIH0pO1xuICAgIC8vIE91dGxpbmVzLCBkZW5zaXR5IGFuZCB0cmFuc2NyaXB0cyBnbyBiYWNrIG92ZXIgdGhlIG1hcmtlcnMganVzdCBhZGRlZC5cbiAgICB0aGlzLnNlc3Npb24udGlsZXM/LmFmdGVyT2JzZXJ2YXRpb25zKCk7XG4gICAgdGhpcy5mcmFtZU9uY2Uodmlld2VyLCBkYXRhc2V0LmlkLCBwb3NpdGlvbnMsICEhcmVmKTtcbiAgICB0aGlzLmhpZGVGb3JlaWduSW1hZ2Uodmlld2VyLCBzaG93SW1hZ2UpO1xuICAgIHRoaXMuY3R4LnRvb2xzLnJlZ2lvbk92ZXJsYXk/LnNldFJlZ2lvbnNWaXNpYmxlKHZpZXcuc2hvd0Fubm90YXRpb25zICE9PSBmYWxzZSk7XG4gICAgdGhpcy5zZXRSZWdpb25HcmlkRm9yKGRhdGFzZXQsIHBvc2l0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogVGVsbCB0aGUgcmVnaW9uIG92ZXJsYXkgaG93IGZpbmVseSBhIGRyYXduIHZlcnRleCBtYXkgYmUgcGxhY2VkLlxuICAgKlxuICAgKiBSZWdpb24gZ2VvbWV0cnkgaXMgc3RvcmVkIGluIHdob2xlIHdvcmxkIHVuaXRzLCB3aGljaCBpcyByaWdodCB3aGVuIHRoZSB3b3JsZCBJU1xuICAgKiBwaXhlbHMg4oCUIGEgcmVnaW9uIHNob3VsZCBhbGlnbiB0byB0aGVtLiBJdCBpcyB3cm9uZyBmb3IgYSBkYXRhc2V0IHRoYXQgcmVnaXN0ZXJzIG9udG9cbiAgICogbm8gaW1hZ2U6IHNlcUZJU0gncyBvYnNlcnZhdGlvbnMgc3BhbiBhYm91dCA1IHggNyB1bml0cyBpbiB0b3RhbCwgc28gd2hvbGUtdW5pdFxuICAgKiB2ZXJ0aWNlcyBsZWF2ZSByb3VnaGx5IHNpeCBieSBlaWdodCBwbGFjZWFibGUgcG9zaXRpb25zIGFjcm9zcyB0aGUgZW50aXJlIHNhbXBsZSBhbmRcbiAgICogYW4gUk9JIGNhbm5vdCBiZSBkcmF3biBhdCBhbnkgem9vbS4gTm90aGluZyBlcnJvcnM7IHRoZSB0b29sIGp1c3QgY2Fubm90IGV4cHJlc3MgdGhlXG4gICAqIHNoYXBlLlxuICAgKlxuICAgKiBLZXllZCBvbiB3aGV0aGVyIHRoZSBkYXRhc2V0IGJyaW5ncyBQSVhFTFMgcmF0aGVyIHRoYW4gb24gdGhlIGV4dGVudCwgYmVjYXVzZSB0aGVcbiAgICogZXh0ZW50IGNhbm5vdCB0ZWxsIHRoZSB0d28gYXBhcnQg4oCUIDIsMDAwIHVuaXRzIGlzIGEgc21hbGwgc2xpZGUgb3IgYSBsYXJnZSBzZWN0aW9uXG4gICAqIGRlcGVuZGluZyBvbmx5IG9uIHdoYXQgdGhlIHVuaXRzIGFyZSwgYW5kIG9ubHkgdGhlIGRhdGFzZXQga25vd3MuXG4gICAqL1xuICBwcml2YXRlIHNldFJlZ2lvbkdyaWRGb3IoZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHBvc2l0aW9uczogRmxvYXQzMkFycmF5KTogdm9pZCB7XG4gICAgY29uc3Qgb3ZlcmxheSA9IHRoaXMuY3R4LnRvb2xzLnJlZ2lvbk92ZXJsYXk7XG4gICAgaWYgKCFvdmVybGF5Py5zZXRXb3JsZFF1YW50dW0pIHJldHVybjtcbiAgICBpZiAoZGF0YXNldC5pbWFnZVJlZiB8fCBkYXRhc2V0LnZvbHVtZSkge1xuICAgICAgb3ZlcmxheS5zZXRXb3JsZFF1YW50dW0oUElYRUxfV09STERfUVVBTlRVTSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBtaW5YID0gSW5maW5pdHk7XG4gICAgbGV0IG1heFggPSAtSW5maW5pdHk7XG4gICAgbGV0IG1pblkgPSBJbmZpbml0eTtcbiAgICBsZXQgbWF4WSA9IC1JbmZpbml0eTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvc2l0aW9ucy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgY29uc3QgeCA9IHBvc2l0aW9uc1tpXTtcbiAgICAgIGNvbnN0IHkgPSBwb3NpdGlvbnNbaSArIDFdO1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoeCkgfHwgIU51bWJlci5pc0Zpbml0ZSh5KSkgY29udGludWU7XG4gICAgICBpZiAoeCA8IG1pblgpIG1pblggPSB4O1xuICAgICAgaWYgKHggPiBtYXhYKSBtYXhYID0geDtcbiAgICAgIGlmICh5IDwgbWluWSkgbWluWSA9IHk7XG4gICAgICBpZiAoeSA+IG1heFkpIG1heFkgPSB5O1xuICAgIH1cbiAgICBvdmVybGF5LnNldFdvcmxkUXVhbnR1bSh3b3JsZFF1YW50dW1Gb3JFeHRlbnQobWF4WCAtIG1pblgsIG1heFkgLSBtaW5ZKSk7XG4gIH1cblxuICAvKipcbiAgICogSGlkZSB0aGUgaW1hZ2UgbGF5ZXIgZm9yIGEgZGF0YXNldCB0aGF0IGJyaW5ncyBubyBpbWFnZSBvZiBpdHMgb3duLlxuICAgKlxuICAgKiBUaGUgaG9zdCdzIHZpZXdlciBrZWVwcyB3aGF0ZXZlciBpbWFnZSB3YXMgbGFzdCBsb2FkZWQsIGFuZCBmb3IgYSBkYXRhc2V0IHRoYXRcbiAgICogcmVnaXN0ZXJzIG9udG8gbm9uZSB0aGF0IHBpY3R1cmUgYmVsb25ncyB0byBzb21ldGhpbmcgZWxzZSBlbnRpcmVseSDigJQgdGhlIGV4YW1wbGUnc1xuICAgKiBkZWZhdWx0IHNsaWRlLCBzYXkuIEl0IGlzIG5vdCBtZXJlbHkgaXJyZWxldmFudDogdGhlIHR3byBsaXZlIGluIGRpZmZlcmVudCBjb29yZGluYXRlXG4gICAqIHNwYWNlcyAoaW1hZ2UgcGl4ZWxzIGFnYWluc3QgdGhlIGVtYmVkZGluZydzIG93biB1bml0cyksIHNvIHRoZSBsZWZ0b3ZlciBpcyBtYWduaWZpZWRcbiAgICogcm91Z2hseSBhIGh1bmRyZWRmb2xkLiBBdCB0aGUgZml0dGVkIHpvb20gdGhlIGNhbWVyYSBzaXRzIGluc2lkZSBpdHMgY29ybmVyLCB3aGVyZSBpdFxuICAgKiByZWFkcyBhcyBibGFuayBiYWNrZ3JvdW5kLCBhbmQgaXQgYXBwZWFycyBvbmx5IG9uY2UgeW91IHpvb20gb3V0IGZhciBlbm91Z2ggdG8gZmluZFxuICAgKiBpdCDigJQgd2hpY2ggaXMgZXhhY3RseSBob3cgaXQgZ2V0cyBub3RpY2VkLlxuICAgKlxuICAgKiBIaWRkZW4gcmF0aGVyIHRoYW4gcmVtb3ZlZCwgYW5kIGhpZGRlbiBIRVJFIHJhdGhlciB0aGFuIGJ5IGNsZWFyaW5nIHRoZSBob3N0J3MgaW1hZ2VcbiAgICogc3RhdGU6IHRoYXQgc3RhdGUgZHJpdmVzIHRoZSB3aG9sZSByZW5kZXIgcGlwZWxpbmUsIGluY2x1ZGluZyBhIFBsb3RseSBiYWNrZW5kIHdob3NlXG4gICAqIGZpZWxkcyBhcmUgZGVjbGFyZWQgd2l0aCBkZWZpbml0ZS1hc3NpZ25tZW50IGFzc2VydGlvbnMsIHNvIGVtcHR5aW5nIGl0IHRocm93cyBmcm9tXG4gICAqIHdoaWNoZXZlciBmaWVsZCB0aGUgbmV4dCBwYXRoIGhhcHBlbnMgdG8gcmVhZC4gVGhpcyB0b3VjaGVzIG9uZSBsYXllcidzIHZpc2liaWxpdHlcbiAgICogYW5kIG5vdGhpbmcgZWxzZS5cbiAgICovXG4gIGhpZGVGb3JlaWduSW1hZ2Uodmlld2VyOiBQaWNrPFZpZXdlciwgJ2xheWVycycgfCAncmVxdWVzdFJlbmRlcic+LCBkYXRhc2V0SGFzUGl4ZWxzOiBib29sZWFuKTogdm9pZCB7XG4gICAgLy8gTm8gaW1hZ2Ugb2YgaXRzIG93biDihpIgbm90aGluZyBmb3IgYW4gb3ZlcnZpZXcgdG8gc2hvdyBlaXRoZXIuXG4gICAgdGhpcy5pbWFnZS5zaG93TmF2aWdhdG9yRm9yKGRhdGFzZXRIYXNQaXhlbHMpO1xuICAgIGNvbnN0IHRpbGVzID0gdGhpcy5zZXNzaW9uLnRpbGVzO1xuICAgIGZvciAoY29uc3QgbGF5ZXIgb2Ygdmlld2VyLmxheWVycy5pdGVtcykge1xuICAgICAgaWYgKGxheWVyLmtpbmQgIT09ICdpbWFnZScpIGNvbnRpbnVlO1xuICAgICAgLy8gVGhlIHRyYW5zY3JpcHQtZGVuc2l0eSByYXN0ZXIgYW5kIHRoZSBnZW5lIG1hcCBhcmUgaW1hZ2UgbGF5ZXJzIHRvbywgYnV0IHRoZXkgYXJlXG4gICAgICAvLyBkYXRhLCBub3QgdGhlIHRpc3N1ZTogdGhlIEltYWdlcyB0b2dnbGUgbXVzdCBub3QgdGFrZSB0aGVtIGRvd24gd2l0aCB0aGUgc2xpZGUuXG4gICAgICBpZiAodGlsZXM/Lm93bnMobGF5ZXIpIHx8IGxheWVyID09PSB0aGlzLmdlbmVNYXBMYXllcikgY29udGludWU7XG4gICAgICAvLyBSZS1zaG93biB3aGVuIGEgZGF0YXNldCB0aGF0IG93bnMgYW4gaW1hZ2UgY29tZXMgYmFjaywgc28gc3dpdGNoaW5nIGJldHdlZW5cbiAgICAgIC8vIGRhdGFzZXRzIGRvZXMgbm90IGxlYXZlIHRoZSB0aXNzdWUgcGVybWFuZW50bHkgaGlkZGVuLlxuICAgICAgbGF5ZXIudmlzaWJsZSA9IGRhdGFzZXRIYXNQaXhlbHM7XG4gICAgfVxuICAgIHZpZXdlci5yZXF1ZXN0UmVuZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogRnJhbWUgdGhlIGNhbWVyYSBvbiB0aGUgb2JzZXJ2YXRpb25zLCBmb3IgYSBkYXRhc2V0IHRoYXQgYnJpbmdzIG5vIGltYWdlLlxuICAgKlxuICAgKiBUaGUgMkQgY2FtZXJhIGlzIG5vcm1hbGx5IGZpdHRlZCB0byB0aGUgSU1BR0UsIGJlY2F1c2UgdGhlIG9ic2VydmF0aW9ucyBhcmUgaW4gdGhhdFxuICAgKiBpbWFnZSdzIHBpeGVsIHNwYWNlIGFuZCBmcmFtaW5nIHRoZSBpbWFnZSBmcmFtZXMgdGhlbSB0b28uIEEgZGF0YXNldCB3aXRoIG5vXG4gICAqIHJlZmVyZW5jZSBpbWFnZSBoYXMgY29vcmRpbmF0ZXMgaW4gaXRzIG93biB1bml0cyBpbnN0ZWFkIOKAlCBzZXFGSVNIJ3Mgc3BhbiBhYm91dFxuICAgKiA1eDcg4oCUIHNvIHRoZSBpbWFnZSBmcmFtaW5nIGxlZnQgb3ZlciBmcm9tIHdoYXRldmVyIHdhcyBvbiBzY3JlZW4gYmVmb3JlIHB1dHMgdGhlXG4gICAqIHdob2xlIGNsb3VkIG9mZnNjcmVlbjogbWVhc3VyZWQgYXQgOS43IHggMTMuNCBQSVhFTFMsIGNlbnRyZWQgMjU2cHggZnJvbSB3aGVyZSB0aGVcbiAgICogY2FtZXJhIHdhcyBsb29raW5nLiBUaGUgcG9pbnRzIGFyZSBhbGwgdGhlcmUgYW5kIGRyYXduOyB0aGV5IGFyZSBhIHNwZWNrLiBXaGljaFxuICAgKiBsb29rcyBleGFjdGx5IGxpa2UgdGhlIGRhdGFzZXQgaGF2aW5nIGZhaWxlZCB0byBsb2FkLlxuICAgKlxuICAgKiBPbmNlIHBlciBkYXRhc2V0LCBhcyBuYXBhcmktanMncyBgZml0M2Q6ICdvbmNlJ2AgZG9lcyBmb3IgdGhlIGNsb3VkOiByZS1jb2xvdXJpbmcsXG4gICAqIHNsaWNpbmcgb3IgcGlja2luZyBhIGdlbmUgcmUtYWRkcyB0aGlzIGxheWVyLCBhbmQgcmUtZnJhbWluZyBvbiB0aG9zZSB3b3VsZCBtb3ZlXG4gICAqIHRoZSBjYW1lcmEgdW5kZXIgdGhlIHVzZXIg4oCUIHRoZSBjYW1lcmEgdG9vbHMgYW5kIHRoZSBjYW52YXMgZHJhZyBhcmUgbWVhbnQgdG8gYmVcbiAgICogdGhlIG9ubHkgdGhpbmdzIHRoYXQgZG8uXG4gICAqL1xuICBwcml2YXRlIGZyYW1lT25jZSh2aWV3ZXI6IFZpZXdlciwgZGF0YXNldElkOiBzdHJpbmcsIHBvc2l0aW9uczogRmxvYXQzMkFycmF5LCByZWdpc3RlcmVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgLy8gR2F0ZWQgb24gd2hldGhlciBUSElTIGRhdGFzZXQgcmVnaXN0ZXJzIG9udG8gYW4gaW1hZ2UsIG5vdCBvbiB0aGUgaW1hZ2Ugc2l6ZTogdGhhdCBrZWVwc1xuICAgIC8vIHRoZSBsYXN0IHBsb3R0ZWQgaW1hZ2UncyBkaW1lbnNpb25zIGFmdGVyIHRoZSBob3N0IGNsZWFycyBpdCwgc28gYSBzdGFsZSA1MTJ4MzgzIHJlYWQgYXNcbiAgICAvLyBcInRoZXJlIGlzIGFuIGltYWdlXCIgYW5kIHNraXBwZWQgdGhlIGZyYW1pbmcgZW50aXJlbHkuXG4gICAgaWYgKHJlZ2lzdGVyZWQpIHJldHVybjtcbiAgICAvLyBPbmNlIHBlciBkYXRhc2V0IChzZWUgYWJvdmUpLlxuICAgIGlmICh0aGlzLmZyYW1lZCA9PT0gZGF0YXNldElkKSByZXR1cm47XG5cbiAgICBjb25zdCB7IGNhbnZhcyB9ID0gdGhpcy5jdHg7XG4gICAgY29uc3QgZml0ID0gZnJhbWVQb3NpdGlvbnMocG9zaXRpb25zLCBjYW52YXMuY2xpZW50V2lkdGggPz8gMCwgY2FudmFzLmNsaWVudEhlaWdodCA/PyAwKTtcbiAgICAvLyBOdWxsIG1lYW5zIHRoZXJlIGlzIG5vdGhpbmcgdG8gZnJhbWUgb247IGxlYXZlIHRoZSBjYW1lcmEgd2hlcmUgaXQgaXMgcmF0aGVyXG4gICAgLy8gdGhhbiBtb3ZpbmcgdGhlIHZpZXcgZm9yIGEgZGF0YXNldCB3ZSBjYW5ub3QgZml0LlxuICAgIGlmICghZml0KSByZXR1cm47XG4gICAgdmlld2VyLmNhbWVyYS5zZXQoZml0LmNlbnRlciwgZml0Lnpvb20gPz8gdmlld2VyLmNhbWVyYS56b29tKTtcbiAgICB0aGlzLmZyYW1lZCA9IGRhdGFzZXRJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgKipnZW5lIG1hcCoqOiB0aGUgYWN0aXZlIGdlbmUncyBleHByZXNzaW9uIGFzIGEgY29udGludW91cyBmaWVsZCBkcmF3biB1bmRlclxuICAgKiB0aGUgY2VsbHMuXG4gICAqXG4gICAqIEEgc2NhdHRlciBjb2xvdXJlZCBieSBhIGdlbmUgc2F5cyB3aGljaCBjZWxscyBleHByZXNzIGl0OyBpdCBjYW5ub3Qgc2F5IHdoZXJlLFxuICAgKiBiZWNhdXNlIHRoZSBleWUgd2lsbCBub3QgaW50ZWdyYXRlIHRob3VzYW5kcyBvZiBkb3RzIGludG8gYSB0ZXJyaXRvcnkuIFRoZSBmaWVsZFxuICAgKiBpcyBhIGtlcm5lbC13ZWlnaHRlZCBNRUFOIHBlciBjZWxsIChzZWUgYHNwYXRpYWwtZXhwcmVzc2lvbi50c2ApLCBzbyBhIGRlbnNlXG4gICAqIHJlZ2lvbiBkb2VzIG5vdCBnbG93IG1lcmVseSBmb3IgYmVpbmcgZGVuc2UsIGFuZCBpdCBpcyB0cmFuc3BhcmVudCB3aGVyZXZlciBub1xuICAgKiBjZWxsIHdhcyBtZWFzdXJlZCDigJQgYW4gdW5zYW1wbGVkIGdhcCBtdXN0IG5vdCByZWFkIGFzIFwibm90IGV4cHJlc3NlZFwiLlxuICAgKlxuICAgKiBJdCBzaGFyZXMgdGhlIHBvaW50cycgTFVULCBwZXJjZW50aWxlIHdpbmRvdyBhbmQgbG9nIGZsYWcsIHNvIHRoZSBsYXllciB1bmRlclxuICAgKiB0aGUgY2VsbHMgYW5kIHRoZSBjZWxscyB0aGVtc2VsdmVzIGNhbm5vdCBkaXNhZ3JlZSBhYm91dCB3aGF0IGEgY29sb3VyIG1lYW5zLlxuICAgKlxuICAgKiBFc3RpbWF0ZWQgb24gdGhlIERJU1BMQVlFRCBpbWFnZSdzIHBpeGVsIGdyaWQsIGNvYXJzZW5lZCBzbyB0aGUgbG9uZyBzaWRlIGlzIGF0XG4gICAqIG1vc3QgYEdFTkVfTUFQX01BWF9TSURFYDogYSBzbW9vdGggZmllbGQgZ2FpbnMgbm90aGluZyBmcm9tIGEgc2xpZGUncyBmdWxsXG4gICAqIHJlc29sdXRpb24uIEZvciBhIHZvbHVtZS1iYWNrZWQgZGF0YXNldCB0aGF0IGdyaWQgaXMgdGhlIGN1cnJlbnQgc2xpY2UsIGFuZCBvbmx5XG4gICAqIHRoYXQgcGxhbmUncyBvYnNlcnZhdGlvbnMgYXJlIGluY2x1ZGVkIOKAlCB0aGUgc2FtZSBydWxlIHRoZSBtYXJrZXJzIGZvbGxvdy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlR2VuZU1hcChcbiAgICB2aWV3ZXI6IFZpZXdlcixcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICAgIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2ssXG4gICAgc2xhYjogU2xhYiB8IG51bGwsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGdlbmUgPSB2aWV3LmdlbmVNYXAgJiYgdmlldy5jb2xvckJ5Py5raW5kID09PSAnZmVhdHVyZScgPyB2aWV3LmNvbG9yQnkubmFtZSA6IG51bGw7XG4gICAgY29uc3QgcG9ydCA9IHRoaXMuc2Vzc2lvbi5wb3J0O1xuICAgIGNvbnN0IGNhY2hlID0gdGhpcy5zZXNzaW9uLmdlbmVNYXA7XG4gICAgY29uc3Qgc21vb3RoaW5nID0gdmlldy5nZW5lTWFwU21vb3RoaW5nID4gMCA/IHZpZXcuZ2VuZU1hcFNtb290aGluZyA6IDE7XG4gICAgY29uc3QgY2xpcCA9IHZpZXcucGVyY2VudGlsZUNsaXAgPz8gWzAuMDEsIDAuOTldO1xuXG4gICAgLy8gVHdvIGNsb2NrczogdGhlIEZJRUxEIGRlcGVuZHMgb24gdGhlIGdlbmUsIHRoZSBwbGFuZSBhbmQgdGhlIGJhbmR3aWR0aCwgd2hpbGVcbiAgICAvLyB0aGUgY29sb3VycyBkZXBlbmQgb24gdGhlIHdpbmRvdywgdGhlIGxvZyBmbGFnIGFuZCB0aGUgb3BhY2l0eS4gUmVjb2xvdXJpbmcgYVxuICAgIC8vIGNhY2hlZCBmaWVsZCBpcyBhIGZyYWN0aW9uIG9mIGVzdGltYXRpbmcgb25lLlxuICAgIGNvbnN0IGZpZWxkS2V5ID0gZ2VuZVxuICAgICAgPyBbZGF0YXNldC5pZCwgZ2VuZSwgc2xhYj8uc2xpY2UgPz8gJycsIHNtb290aGluZywgdGhpcy5zZXNzaW9uLnNlbGVjdGlvblJldihzZWxlY3Rpb24pXS5qb2luKCd8JylcbiAgICAgIDogbnVsbDtcbiAgICBjb25zdCBrZXkgPSBmaWVsZEtleVxuICAgICAgPyBbXG4gICAgICAgICAgZmllbGRLZXksXG4gICAgICAgICAgY2xpcC5qb2luKCcsJyksXG4gICAgICAgICAgdmlldy5sb2dTY2FsZSA/ICdsb2cnIDogJ2xpbicsXG4gICAgICAgICAgdmlldy5nZW5lTWFwT3BhY2l0eSxcbiAgICAgICAgICB0aGlzLmN0eC5kaXNwbGF5LmNvbnRpbnVvdXNDb2xvcm1hcEtleSh2aWV3KSxcbiAgICAgICAgXS5qb2luKCd8JylcbiAgICAgIDogbnVsbDtcbiAgICAvLyBBIHN0aXRjaGVkIHNsaWNlIHJlLXJlbmRlciBjbGVhcnMgdGhlIHdob2xlIGxheWVyIGxpc3QsIHRoZSBtYXAgd2l0aCBpdCwgYW5kIHRoZSBrZXkgb2YgYVxuICAgIC8vIHJlZ2lzdGVyZWQgaW1hZ2UncyBtYXAgZG9lcyBub3QgbmFtZSB0aGUgc2xpY2U6IGEgbWFwIG5vIGxvbmdlciBpbiB0aGUgc2NlbmUgaXMgYWJzZW50LFxuICAgIC8vIGFzIHRoZSBtYXJrZXJzJyBpcyAoc2VlIGByZWJ1aWxkYCksIHNvIGl0IGlzIGRyYXduIGFnYWluIGZyb20gdGhlIGNhY2hlZCBmaWVsZC5cbiAgICBpZiAodGhpcy5nZW5lTWFwTGF5ZXIgJiYgIXZpZXdlci5sYXllcnMuaXRlbXMuaW5jbHVkZXModGhpcy5nZW5lTWFwTGF5ZXIpKSB7XG4gICAgICB0aGlzLmdlbmVNYXBMYXllciA9IG51bGw7XG4gICAgICB0aGlzLmdlbmVNYXBLZXkgPSBudWxsO1xuICAgIH1cbiAgICBpZiAoa2V5ID09PSB0aGlzLmdlbmVNYXBLZXkpIHJldHVybjtcblxuICAgIGlmICh0aGlzLmdlbmVNYXBMYXllcikge1xuICAgICAgdmlld2VyLmxheWVycy5yZW1vdmUodGhpcy5nZW5lTWFwTGF5ZXIpO1xuICAgICAgdGhpcy5nZW5lTWFwTGF5ZXIgPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmdlbmVNYXBLZXkgPSBrZXk7XG4gICAgaWYgKCFrZXkgfHwgIWdlbmUgfHwgIXBvcnQpIHtcbiAgICAgIGNhY2hlLmZpZWxkID0gbnVsbDtcbiAgICAgIGNhY2hlLmtleSA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVGhlIHJhc3RlciBjb3ZlcnMgdGhlIGRpc3BsYXllZCBpbWFnZTsgd2l0aG91dCBvbmUgdGhlcmUgaXMgbm90aGluZyB0b1xuICAgIC8vIG92ZXJsYXkgYW5kIHRoZSBjbG91ZCBpcyB0aGUgM0QgbW9kZSdzIGJ1c2luZXNzLCBub3QgdGhpcyBvbmUncy4gR2F0ZWQgb24gdGhlXG4gICAgLy8gREFUQVNFVCBicmluZ2luZyBwaXhlbHMsIG5vdCBvbiB0aGUgaW1hZ2Ugc2l6ZTogdGhhdCBrZWVwcyB0aGUgbGFzdCBwbG90dGVkIGltYWdlJ3NcbiAgICAvLyBzaXplIGFmdGVyIHRoZSBob3N0IGNsZWFycyBpdCwgd2hpY2ggd291bGQgc2l6ZSB0aGUgbWFwIG92ZXIgdGhlIHdyb25nIGV4dGVudC5cbiAgICBpZiAoIXNsYWIgJiYgIWRhdGFzZXQuaW1hZ2VSZWYpIHJldHVybjtcbiAgICBjb25zdCBzaXplID0gdGhpcy5jdHguaW1hZ2VTaXplKCk7XG4gICAgY29uc3QgaW1hZ2VXID0gc2xhYiA/IGRhdGFzZXQudm9sdW1lIS53aWR0aCA6IHNpemUud2lkdGg7XG4gICAgY29uc3QgaW1hZ2VIID0gc2xhYiA/IGRhdGFzZXQudm9sdW1lIS5oZWlnaHQgOiBzaXplLmhlaWdodDtcbiAgICBpZiAoIWltYWdlVyB8fCAhaW1hZ2VIKSByZXR1cm47XG4gICAgY29uc3Qgc3RlcCA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChNYXRoLm1heChpbWFnZVcsIGltYWdlSCkgLyBHRU5FX01BUF9NQVhfU0lERSkpO1xuXG4gICAgaWYgKGZpZWxkS2V5ICE9PSBjYWNoZS5rZXkpIHtcbiAgICAgIGNvbnN0IGxvYWQgPSB0aGlzLmdlbmVNYXBMb2Fkcy5uZXh0KCk7XG4gICAgICBsZXQgdmFsdWVzOiBGbG9hdDMyQXJyYXk7XG4gICAgICB0cnkge1xuICAgICAgICB2YWx1ZXMgPSBhd2FpdCBwb3J0LmdldEZlYXR1cmVWZWN0b3IoZ2VuZSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbbmFwYXJpLWpzXSBnZW5lIG1hcDogXCIke2dlbmV9XCIgdW5hdmFpbGFibGVgLCBlcnIpO1xuICAgICAgICB0aGlzLmdlbmVNYXBLZXkgPSBudWxsO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAoIWxvYWQoKSB8fCB0aGlzLmdlbmVNYXBLZXkgIT09IGtleSkgcmV0dXJuO1xuICAgICAgY29uc3QgaW5TZWxlY3Rpb24gPSBzZWxlY3Rpb24uY291bnQgPiAwID8gbWFza1RvSW5kaWNlcyhzZWxlY3Rpb24ubWFzaykgOiB1bmRlZmluZWQ7XG4gICAgICBsZXQgZXN0aW1hdGVkOiBFeHByZXNzaW9uRmllbGQgfCBudWxsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgZXN0aW1hdGVkID0gYXdhaXQgY29tcHV0ZUV4cHJlc3Npb25GaWVsZEFzeW5jKFxuICAgICAgICAgIGRhdGFzZXQub2JzZXJ2YXRpb25zLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHJlZjogc2xhYj8ucmVmID8/IGRhdGFzZXQuaW1hZ2VSZWYsXG4gICAgICAgICAgICB3aWR0aDogTWF0aC5jZWlsKGltYWdlVyAvIHN0ZXApLFxuICAgICAgICAgICAgaGVpZ2h0OiBNYXRoLmNlaWwoaW1hZ2VIIC8gc3RlcCksXG4gICAgICAgICAgICBzdGVwLFxuICAgICAgICAgICAgc2lnbWE6IEdFTkVfTUFQX1NJR01BICogc21vb3RoaW5nLFxuICAgICAgICAgICAgdmFsdWVzLFxuICAgICAgICAgICAgLy8gQSBwbGFuZSB3aW5zIG92ZXIgYSBzZWxlY3Rpb246IHRoZSAyRCB2aWV3IGlzIHNob3dpbmcgb25lIHNlY3Rpb24sIHNvIGFcbiAgICAgICAgICAgIC8vIGZpZWxkIHNwYW5uaW5nIHRoZSBzcGVjaW1lbidzIGRlcHRoIHdvdWxkIG5vdCBiZSB0aGUgdGhpbmcgb24gc2NyZWVuLlxuICAgICAgICAgICAgaW5kaWNlczogc2xhYj8uaW5kaWNlcyA/PyBpblNlbGVjdGlvbixcbiAgICAgICAgICB9LFxuICAgICAgICAgIHsgc2lnbmFsOiBsb2FkLnNpZ25hbCB9LFxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmIChpc0Fib3J0RXJyb3IoZXJyKSkgcmV0dXJuOyAvLyBzdXBlcnNlZGVkIGJ5IGEgbmV3ZXIgbWFwLCBvciB0aGUgc2NlbmUgd2VudCBhd2F5XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICAgIGlmICghbG9hZCgpIHx8IHRoaXMuZ2VuZU1hcEtleSAhPT0ga2V5KSByZXR1cm47XG4gICAgICBjYWNoZS5maWVsZCA9IGVzdGltYXRlZDtcbiAgICAgIGNhY2hlLmtleSA9IGZpZWxkS2V5O1xuICAgIH1cbiAgICBjb25zdCBmaWVsZCA9IGNhY2hlLmZpZWxkO1xuICAgIGlmICghZmllbGQpIHJldHVybjtcblxuICAgIGNvbnN0IGx1dCA9IHRoaXMuY3R4LmRpc3BsYXkuc3BhdGlhbEx1dCh2aWV3KTtcbiAgICAvLyBPdmVyIHRoZSBtZWFzdXJlZCBwaXhlbHMgb25seTogdW5tZWFzdXJlZCBvbmVzIGFyZSAwIGFuZCB3b3VsZCBkcmFnIHRoZSBsb3cgZW5kIGRvd24uXG4gICAgY29uc3QgW2xvLCBoaV0gPSBmaWVsZENvbnRyYXN0V2luZG93KGZpZWxkLCBjbGlwWzBdLCBjbGlwWzFdKTtcbiAgICBjb25zdCByZ2JhID0gY29sb3JFeHByZXNzaW9uRmllbGQoZmllbGQsIGx1dCwgW2xvLCBoaV0sIHtcbiAgICAgIGxvZzogdmlldy5sb2dTY2FsZSxcbiAgICAgIC8vIFRoZSBNQVAncyBvd24gb3BhY2l0eTogcmVhZGluZyBhIGZpZWxkIHVuZGVyIHRoZSBjZWxscyBtZWFucyB0dXJuaW5nIHRoZVxuICAgICAgLy8gY2VsbHMgZG93biwgd2hpY2ggbXVzdCBub3QgdGFrZSB0aGUgZmllbGQgd2l0aCB0aGVtLlxuICAgICAgb3BhY2l0eTogdmlldy5nZW5lTWFwT3BhY2l0eSxcbiAgICB9KTtcbiAgICB0aGlzLmdlbmVNYXBMYXllciA9IHZpZXdlci5hZGRJbWFnZShcbiAgICAgIHsga2luZDogJ3R5cGVkJywgd2lkdGg6IGZpZWxkLndpZHRoLCBoZWlnaHQ6IGZpZWxkLmhlaWdodCwgY2hhbm5lbHM6IDQsIGR0eXBlOiAndWludDgnLCBkYXRhOiByZ2JhIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6IGBnZW5lIG1hcCDCtyAke2dlbmV9YCxcbiAgICAgICAgc2NhbGU6IFtzdGVwLCBzdGVwXSxcbiAgICAgICAgdHJhbnNsYXRlOiBbMCwgMF0sXG4gICAgICAgIGJsZW5kaW5nOiAndHJhbnNsdWNlbnQnLFxuICAgICAgfSxcbiAgICApO1xuICAgIC8vIGBhZGRJbWFnZWAgYXBwZW5kcywgc28gdGhlIG1hcCBqdXN0IGxhbmRlZCBvdmVyIHRoZSBjZWxscyAoZHJhd24gYnkgdGhpcyByZWJ1aWxkJ3NcbiAgICAvLyBwcmV2aW91cyBwYXNzLCBvciBieSBhIG5ld2VyIHJlYnVpbGQgd2hpbGUgdGhlIGZpZWxkIHdhcyBjb21wdXRpbmcpOiBtb3ZlIGl0IHRvIGp1c3QgdW5kZXJcbiAgICAvLyB0aGVtLiBBIG1vdmUga2VlcHMgdGhlIG1hcmtlcnMnIEdQVSBidWZmZXJzLCB3aGVyZSBkcm9wcGluZyBhbmQgcmUtYWRkaW5nIHRoZSBtYXJrZXJzXG4gICAgLy8gcmUtdXBsb2FkZWQgZXZlcnkgb25lIG9mIHRoZW0gKE5BUEFSSS1CT1VOREFSWS0xMSkuIFdpdGhvdXQgbWFya2VycyBvbiBzY3JlZW4gdGhlcmUgaXNcbiAgICAvLyBub3RoaW5nIHRvIGdvIHVuZGVyOyB0aGUgcmVidWlsZCBhZGRzIHRoZW0gb3ZlciB0aGUgbWFwLlxuICAgIGNvbnN0IHVuZGVyID0gdGhpcy5wb2ludHMgPyB2aWV3ZXIubGF5ZXJzLml0ZW1zLmluZGV4T2YodGhpcy5wb2ludHMpIDogLTE7XG4gICAgaWYgKHVuZGVyID49IDApIHZpZXdlci5sYXllcnMubW92ZSh0aGlzLmdlbmVNYXBMYXllciwgdW5kZXIpO1xuICAgIHZpZXdlci5yZXF1ZXN0UmVuZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogUGVyLW9ic2VydmF0aW9uIGNvbG91cnMgZm9yIHRoZSBjdXJyZW50IHZpZXcgc3RhdGUsIG9yIGEgc2luZ2xlIGZsYXQgY29sb3VyIHdoZW4gbm90aGluZyBpc1xuICAgKiBzZWxlY3RlZCB0byBjb2xvdXIgYnkuIENhdGVnb3JpY2FsIGNvbHVtbnMgdXNlIHRoZSBjb2x1bW4ncyBvd24gcGFsZXR0ZTsgY29udGludW91cyBjb2x1bW5zXG4gICAqIGFuZCBnZW5lIHZlY3RvcnMgZ28gdGhyb3VnaCB0aGUgYWN0aXZlIGNvbG9ybWFwIHdpdGggYSBwZXJjZW50aWxlLWNsaXBwZWQgd2luZG93LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmYWNlQ29sb3JzKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgKTogUHJvbWlzZTxQb2ludENvbG9ycz4ge1xuICAgIGNvbnN0IHBvcnQgPSB0aGlzLnNlc3Npb24ucG9ydDtcbiAgICBjb25zdCBjb2xvckJ5ID0gdmlldy5jb2xvckJ5O1xuICAgIC8vIEV2ZXJ5dGhpbmcgTk9UIHNlbGVjdGVkIGlzIG11dGVkOyB3aXRoIG5vdGhpbmcgc2VsZWN0ZWQsIG5vdGhpbmcgaXMgbXV0ZWRcbiAgICAvLyBhbmQgdGhlIHdob2xlIHRpc3N1ZSByZWFkcyBub3JtYWxseSAodGhlIENvc014IGhpZ2hsaWdodC12cy1tdXRlIHJ1bGUpLlxuICAgIGNvbnN0IG11dGVkID0gbXV0ZWRGcm9tU2VsZWN0aW9uKHNlbGVjdGlvbik7XG5cbiAgICBpZiAoIXBvcnQgfHwgIWNvbG9yQnkpIHtcbiAgICAgIC8vIEdlbnVpbmVseSB1bmlmb3JtOiBvbmUgYnJvYWRjYXN0IHR1cGxlLCBzbyBhIGZsYXQgODRrLW9ic2VydmF0aW9uIHZpZXdcbiAgICAgIC8vIGRvZXMgbm90IGFsbG9jYXRlIGEgY29sb3VyIHBlciBwb2ludC5cbiAgICAgIGlmICghbXV0ZWQgJiYgdmlldy5vcGFjaXR5ID49IDEpIHJldHVybiBTUEFUSUFMX05FVVRSQUxfQ09MT1I7XG4gICAgICAvLyBOb3QgdW5pZm9ybSDigJQgdGhlIG9wYWNpdHkgY29udHJvbCBvciBhIHNlbGVjdGlvbiB2YXJpZXMgdGhlIGFscGhhLCBzbyBpdFxuICAgICAgLy8gaGFzIHRvIGJlIHBlci1wb2ludC4gUmV0dXJuaW5nIHRoZSBjb25zdGFudCB0dXBsZSBoZXJlIGlzIHdoYXQgbWFkZSB0aGVcbiAgICAgIC8vIE9wYWNpdHkgc2xpZGVyIGRvIG5vdGhpbmcgaW4gdGhlIGRlZmF1bHQgc3RhdGUsIHdoaWNoIGlzIHRoZSBzdGF0ZSBhbnlvbmVcbiAgICAgIC8vIGxhbmRzIGluIGJlZm9yZSBwaWNraW5nIGEgY29sb3VyIHNvdXJjZS5cbiAgICAgIHJldHVybiBlbmNvZGVDYXRlZ29yaWNhbChuZXcgVWludDE2QXJyYXkoZGF0YXNldC5vYnNlcnZhdGlvbnMuY291bnQpLCB7XG4gICAgICAgIGNvbG9yczogW1NQQVRJQUxfTkVVVFJBTF9IRVhdLFxuICAgICAgICBvcGFjaXR5OiB2aWV3Lm9wYWNpdHksXG4gICAgICAgIG11dGVkLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGNvbG9yQnkua2luZCA9PT0gJ2NvbHVtbicpIHtcbiAgICAgIGNvbnN0IGNvbHVtbjogU3BhdGlhbENvbHVtbiA9IGF3YWl0IHBvcnQuZ2V0Q29sdW1uKGNvbG9yQnkubmFtZSk7XG4gICAgICBpZiAoaXNDYXRlZ29yaWNhbENvbHVtbihjb2x1bW4pKSB7XG4gICAgICAgIGNvbnN0IHJnYmEgPSBlbmNvZGVDYXRlZ29yaWNhbChjb2x1bW4uY29kZXMsIHtcbiAgICAgICAgICBjb2xvcnM6IHJlc29sdmVDYXRlZ29yeUNvbG9ycyhjb2x1bW4ubWV0YSksXG4gICAgICAgICAgb3BhY2l0eTogdmlldy5vcGFjaXR5LFxuICAgICAgICAgIG11dGVkLFxuICAgICAgICB9KTtcbiAgICAgICAgLy8gR3JvdXBzIHN3aXRjaGVkIG9mZiBpbiB0aGUgQ2VsbHMgcGFuZWwgaGlkZSB0aGVpciBkb3RzIHRvbywgd2hlbiB0aGUgZG90cyBhcmVcbiAgICAgICAgLy8gY29sb3VyZWQgYnkgdGhhdCBzYW1lIGdyb3VwaW5nLlxuICAgICAgICBjb25zdCBncm91cENvbHVtbiA9IGNlbGxUeXBlQ29sdW1uRm9yKGRhdGFzZXQsIHZpZXcpO1xuICAgICAgICBpZiAodmlldy5oaWRkZW5Hcm91cHM/Lmxlbmd0aCAmJiBncm91cENvbHVtbiA9PT0gY29sb3JCeS5uYW1lKSB7XG4gICAgICAgICAgY29uc3Qgb2ZmID0gbmV3IFNldCh2aWV3LmhpZGRlbkdyb3Vwcyk7XG4gICAgICAgICAgY29uc3QgaGlkZSA9IGNvbHVtbi5tZXRhLmNhdGVnb3JpZXMubWFwKChjKSA9PiBvZmYuaGFzKGMpKTtcbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbHVtbi5jb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgYyA9IGNvbHVtbi5jb2Rlc1tpXTtcbiAgICAgICAgICAgIGlmIChjICE9PSBOT19DQVRFR09SWSAmJiBoaWRlW2NdKSByZ2JhWzQgKiBpICsgM10gPSAwO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmdiYTtcbiAgICAgIH1cbiAgICAgIC8vIEEgY29udGludW91cyBjb2x1bW4gbWF5IGNhcnJ5IGl0cyBvd24gbG9nIGhpbnQgKGNvdW50cyk7IHRoZSB2aWV3J3NcbiAgICAgIC8vIHRvZ2dsZSB3aW5zIG9uY2UgdGhlIHVzZXIgaGFzIHNldCBpdC5cbiAgICAgIHJldHVybiB0aGlzLmVuY29kZUNvbnRpbnVvdXMoY29sdW1uLnZhbHVlcywgdmlldywgbXV0ZWQpO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlcyA9IGF3YWl0IHBvcnQuZ2V0RmVhdHVyZVZlY3Rvcihjb2xvckJ5Lm5hbWUpO1xuICAgIHJldHVybiB0aGlzLmVuY29kZUNvbnRpbnVvdXModmFsdWVzLCB2aWV3LCBtdXRlZCk7XG4gIH1cblxuICAvKiogQ29udGludW91cyB2YWx1ZXMg4oaSIFJHQkEgdGhyb3VnaCB0aGUgYWN0aXZlIGNvbG9ybWFwIGFuZCBhIGNsaXBwZWQgd2luZG93LiAqL1xuICBlbmNvZGVDb250aW51b3VzKHZhbHVlczogRmxvYXQzMkFycmF5LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBtdXRlZDogVWludDhBcnJheSB8IG51bGwgPSBudWxsKTogRmxvYXQzMkFycmF5IHtcbiAgICByZXR1cm4gZW5jb2RlU3BhdGlhbENvbnRpbnVvdXMoXG4gICAgICB2YWx1ZXMsXG4gICAgICB2aWV3LFxuICAgICAgdGhpcy5jdHguZGlzcGxheS5zcGF0aWFsTHV0KHZpZXcpLFxuICAgICAgdGhpcy5zZXNzaW9uLmNvbnRyYXN0V2luZG93cyxcbiAgICAgIG11dGVkLFxuICAgICk7XG4gIH1cbn1cblxuLyoqIFRoZSBtYXJrZXJzJyBkaWFtZXRlcnM6IGVhY2ggb2JzZXJ2YXRpb24ncyBvd24gKG9yIHRoZSBmYWxsYmFjayksIGF0IGxlYXN0IHRoZSBzbGFiJ3MgZmxvb3IsXG4gKiAgdGltZXMgdGhlIHZpZXcncyBwb2ludCBzY2FsZTsgb25lIG51bWJlciB3aGVuIGV2ZXJ5IG1hcmtlciBpcyBkcmF3biBhdCB0aGUgc2FtZSBzaXplLiAqL1xuZnVuY3Rpb24gbWFya2VyU2l6ZXMob2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zLCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBzbGFiOiBTbGFiIHwgbnVsbCk6IG51bWJlciB8IEZsb2F0MzJBcnJheSB7XG4gIGNvbnN0IGJhc2UgPSBtYXJrZXJEaWFtZXRlcnMob2JzLCBTUEFUSUFMX0ZBTExCQUNLX1JBRElVUyk7XG4gIGNvbnN0IHNjYWxlID0gdmlldy5wb2ludFNjYWxlID4gMCA/IHZpZXcucG9pbnRTY2FsZSA6IDE7XG4gIGNvbnN0IGZsb29yID0gc2xhYj8ubWluRGlhbWV0ZXIgPz8gMDtcbiAgaWYgKHR5cGVvZiBiYXNlID09PSAnbnVtYmVyJyAmJiAhc2xhYikgcmV0dXJuIE1hdGgubWF4KGJhc2UsIGZsb29yKSAqIHNjYWxlO1xuICBjb25zdCBzaXplT2YgPSAoaTogbnVtYmVyKSA9PiBNYXRoLm1heCh0eXBlb2YgYmFzZSA9PT0gJ251bWJlcicgPyBiYXNlIDogYmFzZVtpXSwgZmxvb3IpICogc2NhbGU7XG4gIHJldHVybiBGbG9hdDMyQXJyYXkuZnJvbShzbGFiPy5pbmRpY2VzID8/IHsgbGVuZ3RoOiBvYnMuY291bnQgfSwgKF92LCBpKSA9PiBzaXplT2Yoc2xhYiA/IHNsYWIuaW5kaWNlc1tpXSA6IGkpKTtcbn1cblxuLyoqIEludGVybGVhdmVkIHgseSBvZiB0aGUgYGRyYXduYCBvYnNlcnZhdGlvbnMgKHVuZGVmaW5lZDogYWxsIG9mIHRoZW0pLiAqL1xuZnVuY3Rpb24gb2JzZXJ2YXRpb25Qb3NpdGlvbnMob2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zLCBkcmF3bjogVWludDMyQXJyYXkgfCB1bmRlZmluZWQpOiBGbG9hdDMyQXJyYXkge1xuICBjb25zdCBjb3VudCA9IGRyYXduID8gZHJhd24ubGVuZ3RoIDogb2JzLmNvdW50O1xuICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KGNvdW50ICogMik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY291bnQ7IGkrKykge1xuICAgIGNvbnN0IG8gPSBkcmF3biA/IGRyYXduW2ldIDogaTtcbiAgICBwb3NpdGlvbnNbaSAqIDJdID0gb2JzLnhbb107XG4gICAgcG9zaXRpb25zW2kgKiAyICsgMV0gPSBvYnMueVtvXTtcbiAgfVxuICByZXR1cm4gcG9zaXRpb25zO1xufVxuXG4vKipcbiAqIFRoZSBwbGFuZSBgc2xpY2VgIG9mIGEgdm9sdW1lLWJhY2tlZCBkYXRhc2V0OiBpdHMgcGl4ZWwgYWZmaW5lLCB0aGUgb2JzZXJ2YXRpb25zIHRoYXQgZmFsbCBpblxuICogaXQsIGFuZCB0aGUgbWFya2VyIGZsb29yIHRoYXQgZ3JpZCBuZWVkcy5cbiAqXG4gKiBOdWxsIGZvciBhIGRhdGFzZXQgd2l0aCBhIHJlYWwgYGltYWdlUmVmYCAoaXRzIGNvb3JkaW5hdGVzIGFyZSBhbHJlYWR5IHRoZSBpbWFnZSdzIHBpeGVscyBhbmRcbiAqIGV2ZXJ5IG9ic2VydmF0aW9uIGJlbG9uZ3MgdG8gdGhlIG9uZSBzZWN0aW9uKSBhbmQgZm9yIG9uZSB3aXRoIG5vIHZvbHVtZSBhdCBhbGwg4oCUIGJvdGggb2ZcbiAqIHdoaWNoIGRyYXcgZXhhY3RseSBhcyBiZWZvcmUuXG4gKi9cbmZ1bmN0aW9uIHNsYWJBdChkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgc2xpY2U6IG51bWJlcik6IFNsYWIgfCBudWxsIHtcbiAgY29uc3Qgdm9sdW1lID0gZGF0YXNldC52b2x1bWU7XG4gIGlmIChkYXRhc2V0LmltYWdlUmVmIHx8ICF2b2x1bWUpIHJldHVybiBudWxsO1xuICByZXR1cm4ge1xuICAgIHJlZjogdm9sdW1lSW1hZ2VSZWYodm9sdW1lLCBkYXRhc2V0Lm1pY3JvbnNQZXJVbml0KSxcbiAgICBpbmRpY2VzOiBvYnNlcnZhdGlvbnNJblNsaWNlKGRhdGFzZXQub2JzZXJ2YXRpb25zLCB2b2x1bWUsIHNsaWNlKSxcbiAgICBzbGljZSxcbiAgICBtaW5EaWFtZXRlcjogU1BBVElBTF9TTElDRV9NSU5fRElBTUVURVJfUFggKiB2b2x1bWUudm94ZWxTaXplWzBdLFxuICB9O1xufVxuIl19