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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +358 -4218
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -883
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,769 @@
1
+ import { PointPicker, colormapFromLut } from 'napari-js';
2
+ import { ScaleBarOverlay } from 'napari-js/overlays';
3
+ import { findColumnMeta, isCategoricalColumn, } from '../../contracts/spatial-dataset.contract';
4
+ import { DEFAULT_MUTED_OPACITY, resolveCategoryColors } from '../../spatial/spatial-encoding';
5
+ import { emptySelection, maskToIndices } from '../../spatial/spatial-selection';
6
+ import { defaultSigma, densityGrid } from '../../spatial/spatial-density';
7
+ import { observationsInSection, sectionsOf } from '../../spatial/spatial-sections';
8
+ import { encodeExpressionVolume, fieldContrastWindow, } from '../../spatial/spatial-expression';
9
+ import { computeExpressionVolumeAsync, rasterizeDensityAsync } from '../../workers/spatial-math';
10
+ import { Supersede } from '../../util/supersede';
11
+ import { isAbortError } from '../tile-server';
12
+ import { GENE_MAP_SIGMA, GENE_MAP_VOLUME_STRIDE, SPATIAL_3D_BASE_SIZE, SPATIAL_SELECTED_SIZE_SCALE, encodeSpatial3dCategorical, encodeSpatial3dContinuous, gatherColors, rankDensityGroups, spatialFlatColormap, totalDensityGroup, } from './napari-spatial-encoding';
13
+ import { HOVER_RADIUS_PX } from './napari-spatial-hover';
14
+ import { SpatialSceneBase } from './napari-spatial-scene';
15
+ /**
16
+ * SPATIAL_OMICS_3D (review Appendix B, cluster K): observations as a 3D point cloud under the
17
+ * orbit camera, with the dataset's reference volume around it, per-cluster density volumes and the
18
+ * 3D gene map.
19
+ *
20
+ * Thinner than the 2D scene: there is no tissue image to render (a registered volume like the
21
+ * Allen CCF has no single reference plane), so no readback and no navigator; the 3D scale bar
22
+ * follows the dataset (see {@link installScaleBar}). The region tools work in SCREEN space through
23
+ * the tool bridge's 3D interaction — a lasso selects the cells under it, and an orbit clears the
24
+ * shape while keeping the selection. The first 3D layer added frames the camera (`fit3d: 'once'`).
25
+ */
26
+ export class Spatial3dScene extends SpatialSceneBase {
27
+ constructor(ctx, session) {
28
+ super(ctx, session, true);
29
+ /** The 3D point cloud. One layer: selection is a per-point alpha on it, not a second. */
30
+ this.points = null;
31
+ this.layerKey = null;
32
+ /** Interleaved x,y,z, cached so a colour change does not re-walk 3.7M observations. */
33
+ this.positions = null;
34
+ /** Identity of the scalars currently uploaded — see {@link rebuild}. */
35
+ this.scalarKey = null;
36
+ /** Observation indices the cached positions belong to, in the same order; null when every
37
+ * observation is drawn. Without it a projection built from the positions is indexed by DRAWN
38
+ * order and silently attributes each point to the wrong observation as soon as a section is
39
+ * isolated. */
40
+ this.drawn = null;
41
+ /** The anatomical volume the cloud sits inside, when the dataset has one. */
42
+ this.volume = null;
43
+ this.volumeKey = null;
44
+ /** Per-cluster density volumes drawn alongside the cloud, and what they were
45
+ * built from — rasterising is seconds of work, so it must not repeat for a
46
+ * change that cannot affect the field. */
47
+ this.densityLayers = [];
48
+ this.densityKey = null;
49
+ /** The 3D gene map's volume layer and the inputs it was coloured for (its field is cached in
50
+ * the session, on a clock of its own). */
51
+ this.geneMapLayer = null;
52
+ this.geneMapKey = null;
53
+ /** Offset applied to observation coordinates to sit them in the volume's box. */
54
+ this.origin = [0, 0, 0];
55
+ /**
56
+ * napari-js's depth-aware pick over the cloud, and the projection the ROI selection reads. It
57
+ * owns the caching policy: re-project lazily, on the first pick after the camera, the canvas or
58
+ * the cloud's data moved (never on the camera event, so an orbit drag pays nothing), into
59
+ * reused buffers, with a screen index once the cloud is large enough.
60
+ */
61
+ this.picker = null;
62
+ this.scaleBar = null;
63
+ /** Dataset the scale bar was built for. */
64
+ this.scaleBarKey = null;
65
+ /** The density rasterisation and the 3D gene-map estimate in flight (off the main thread
66
+ * past the worker threshold, SPATIAL-19): a new key supersedes — and aborts — the previous
67
+ * one; a rebuild that leaves the key alone lets it finish. */
68
+ this.densityLoads = new Supersede();
69
+ this.geneMapLoads = new Supersede();
70
+ /** The store's invert setting, which the density volumes follow (no other subscription of
71
+ * this scene carries it). */
72
+ this.invertSub = null;
73
+ }
74
+ async mount() {
75
+ // Before the spatial subscription, so the first build already reads the current value.
76
+ this.invertSub = this.ctx.display.watchInvert((invert) => {
77
+ // A live setter: the volumes restyle, nothing is rasterised again.
78
+ for (const layer of this.densityLayers)
79
+ layer.invert = invert;
80
+ this.ctx.viewer.requestRender();
81
+ });
82
+ this.ctx.tools.install3dInteraction(this.ctx.viewer, this.ctx.host);
83
+ this.hover.install(this.ctx.host);
84
+ this.subscribeSpatial();
85
+ }
86
+ /** The observations' own z is on screen: there is no plane to step. */
87
+ setZ() {
88
+ /* nothing to step */
89
+ }
90
+ /** A cloud has no intensity distribution for the histogram pane. */
91
+ histogram() {
92
+ return null;
93
+ }
94
+ /**
95
+ * Every observation's position on the canvas under the current 3D camera (for the ROI
96
+ * selection), indexed by observation with NaN for anything not drawn. Null before the cloud
97
+ * is built.
98
+ *
99
+ * The projection is the picker's (see {@link picker}); what is left is the part that is
100
+ * genuinely this adapter's: SCATTERING the drawn subset back into observation order. The cloud
101
+ * holds only the points of the displayed section, in its own packing; every consumer indexes by
102
+ * observation. NaN stands for "not on screen", which is also the right answer for an
103
+ * observation whose section is hidden.
104
+ */
105
+ screenProjection(obs) {
106
+ const projected = this.picker?.projected();
107
+ if (!projected)
108
+ return null;
109
+ const drawn = this.drawn;
110
+ const { screen } = projected;
111
+ const count = screen.length >> 1;
112
+ const out = new Float32Array(obs.count * 2).fill(NaN);
113
+ for (let k = 0; k < count; k++) {
114
+ const i = drawn ? drawn[k] : k;
115
+ if (i >= obs.count)
116
+ continue;
117
+ out[i * 2] = screen[k * 2];
118
+ out[i * 2 + 1] = screen[k * 2 + 1];
119
+ }
120
+ return out;
121
+ }
122
+ dispose() {
123
+ this.disposeSpatial();
124
+ this.invertSub?.unsubscribe();
125
+ this.invertSub = null;
126
+ this.densityLoads.cancel();
127
+ this.geneMapLoads.cancel();
128
+ this.scaleBar?.dispose();
129
+ this.scaleBar = null;
130
+ // Drop the cached interleaved coordinates too: holding 3.7M x 3 floats after
131
+ // a teardown is ~45MB of retained heap for a scene that no longer exists.
132
+ this.positions = null;
133
+ this.setPicker(null);
134
+ }
135
+ /**
136
+ * The observation under a client position: the FRONT-most marker within `slackPx` of the
137
+ * pointer (ties by distance), as napari-js's {@link PointPicker} picks it. That matters more
138
+ * than it sounds: the renderer depth-tests the billboards, and in a 3.7M-point cloud the cursor
139
+ * covers many of them — picking the one nearest the cursor's centre regularly names a cell that
140
+ * something else is drawn over. The picker also takes each point's radius from the layer's
141
+ * per-point `sizes`, so a selected marker, drawn larger, is as large to the pointer.
142
+ */
143
+ pickObservation(clientX, clientY, slackPx) {
144
+ const picker = this.picker;
145
+ if (!picker)
146
+ return -1;
147
+ const rect = this.ctx.canvas.getBoundingClientRect();
148
+ const k = picker.pick(clientX - rect.left, clientY - rect.top, slackPx);
149
+ if (k < 0)
150
+ return -1;
151
+ return this.drawn ? this.drawn[k] : k;
152
+ }
153
+ /** Replace the cloud's picker (null: no cloud), releasing the old one's camera listener. */
154
+ setPicker(points) {
155
+ this.picker?.dispose();
156
+ this.picker = points
157
+ ? new PointPicker(this.ctx.viewer, points, {
158
+ // The largest radius a pick here can claim: the hover slack times the scale a SELECTED
159
+ // marker is drawn at. It decides whether a marker straddling the canvas edge is found.
160
+ maxReach: HOVER_RADIUS_PX * SPATIAL_SELECTED_SIZE_SCALE,
161
+ })
162
+ : null;
163
+ }
164
+ /**
165
+ * Scale bar for the cloud, measured at the ORBIT PIVOT.
166
+ *
167
+ * A perspective camera has no single scale — things farther away are smaller — so a bar can
168
+ * only be true at one depth. The pivot is the honest choice: it is what the camera is framing,
169
+ * what a zoom moves towards, and where the eye is anyway. napari's own 3D scale bar works the
170
+ * same way.
171
+ *
172
+ * napari-js's `ScaleBarOverlay` in `'3d'` mode measures there: CSS px per world unit is the
173
+ * reciprocal of `Camera3D.worldPerPixel` — the scale `Camera3D.pan` uses to track the cursor.
174
+ * The bar then converts through `micronsPerUnit`, and draws nothing at all when the dataset does
175
+ * not declare one, because a bar labelled in microns over unknown units would read as a
176
+ * measurement.
177
+ */
178
+ installScaleBar(dataset) {
179
+ this.scaleBar?.dispose();
180
+ this.scaleBar = null;
181
+ const micronsPerUnit = dataset?.micronsPerUnit;
182
+ if (!micronsPerUnit || micronsPerUnit <= 0)
183
+ return;
184
+ this.scaleBar = new ScaleBarOverlay(this.ctx.host, this.ctx.viewer, {
185
+ unitPerWorld: micronsPerUnit,
186
+ mode: '3d',
187
+ });
188
+ }
189
+ /** (Re)build the 3D point cloud for the current dataset + view state. */
190
+ async rebuild(dataset, view, selection = emptySelection()) {
191
+ const viewer = this.ctx.viewer;
192
+ const task = this.rebuilds.next();
193
+ // Resolve the scalar encoding BEFORE touching the scene, for the same reason
194
+ // the 2D path does: a gene fetch can fail or be superseded, and dropping the
195
+ // layer first would blank the view.
196
+ let enc = null;
197
+ if (dataset) {
198
+ const endLoading = this.ctx.badge.begin('Observations');
199
+ try {
200
+ enc = await this.scalarEncoding(view);
201
+ }
202
+ catch (err) {
203
+ console.warn('[napari-js] spatial 3D colouring failed — falling back to a flat colour', err);
204
+ enc = null;
205
+ }
206
+ finally {
207
+ endLoading();
208
+ }
209
+ }
210
+ if (!task())
211
+ return;
212
+ const obs = dataset?.observations;
213
+ // No z means nothing to draw in 3D. The plot type is gated on `requiresSpatial3d`
214
+ // so this should be unreachable from the UI, but a host can set the type directly.
215
+ if (!dataset || !obs || obs.count === 0 || !obs.z) {
216
+ this.removeLayers(viewer);
217
+ return;
218
+ }
219
+ // Anatomy first: on a scene's FIRST layer napari frames the orbit camera, and
220
+ // the reference volume is the framing we want — the brain, not the outermost
221
+ // stray segmentation. Every later add keeps the pose instead (napari-js `fit3d: 'once'`).
222
+ await this.ensureVolume(viewer, dataset, view);
223
+ if (!task())
224
+ return;
225
+ // Then the cluster density volumes, which can set the centring offset when
226
+ // there is no reference volume — so before any position is computed from it.
227
+ await this.ensureDensityVolumes(viewer, dataset, view, selection);
228
+ if (!task())
229
+ return;
230
+ // Then the gene map, which shares the reference volume's lattice — so it goes
231
+ // after anything that can still move the centring offset.
232
+ await this.ensureGeneMap(viewer, dataset, view, selection);
233
+ if (!task())
234
+ return;
235
+ // Scale depends on the dataset's declared unit, so it waits for the dataset
236
+ // rather than being set up at mount time.
237
+ if (dataset.id !== this.scaleBarKey) {
238
+ this.scaleBarKey = dataset.id;
239
+ this.installScaleBar(dataset);
240
+ }
241
+ // The reference volume is hidden, not removed: it also fixes the centring
242
+ // offset every position is computed from, and re-fetching a 100 MB template
243
+ // to un-hide it would make a checkbox feel like a load.
244
+ if (this.volume) {
245
+ this.volume.visible = view.showVolume;
246
+ this.volume.opacity = view.volumeOpacity;
247
+ }
248
+ this.drawCloud(viewer, dataset, view, selection, enc);
249
+ }
250
+ /**
251
+ * Draw the point cloud: a new layer for new geometry (a dataset or a section), the colour
252
+ * source swapped in place otherwise; then the selection and the visibility.
253
+ */
254
+ drawCloud(viewer, dataset, view, selection, enc) {
255
+ const obs = dataset.observations;
256
+ const scale = view.pointScale > 0 ? view.pointScale : 1;
257
+ const size = SPATIAL_3D_BASE_SIZE * scale;
258
+ // A categorical colouring is per-point RGBA, which wins over the scalars; the flat colormap
259
+ // and zero scalars stand behind it, as they do for "nothing to colour by".
260
+ const scalar = enc?.kind === 'scalars' ? enc : null;
261
+ const colors = enc?.kind === 'colors' ? enc.colors : null;
262
+ const scalars = scalar?.values ?? new Float32Array(obs.count);
263
+ const colormap = scalar?.colormap ?? spatialFlatColormap();
264
+ const contrastLimits = scalar?.contrastLimits ?? [0, 1];
265
+ const { shown, key, scalarKey } = cloudSubset(dataset, view);
266
+ if (key !== this.layerKey) {
267
+ // New geometry: interleave x,y,z (the layer's documented layout, x-fastest)
268
+ // and cache it, so later colour changes rebuild the layer without walking
269
+ // the observations again.
270
+ this.positions = this.cloudPositions(obs, shown);
271
+ this.drawn = shown;
272
+ }
273
+ // The scalars have to follow the geometry: a per-observation vector against one
274
+ // section's positions would colour each cell by a stranger's value. So do the colours.
275
+ const valuesFor = () => (shown ? Float32Array.from(shown, (i) => scalars[i]) : scalars);
276
+ const colorsFor = () => (colors ? gatherColors(colors, shown ?? undefined) : null);
277
+ if (!this.points || key !== this.layerKey) {
278
+ // New GEOMETRY — a different dataset, or a different section — so a new layer.
279
+ if (this.points)
280
+ viewer.layers.remove(this.points);
281
+ this.layerKey = key;
282
+ this.scalarKey = scalarKey;
283
+ this.points = viewer.addPoints3D(this.positions, valuesFor(), {
284
+ name: 'observations',
285
+ colormap,
286
+ contrastLimits,
287
+ size,
288
+ colors: colorsFor() ?? undefined,
289
+ });
290
+ this.setPicker(this.points);
291
+ }
292
+ else {
293
+ if (scalarKey !== this.scalarKey) {
294
+ // A change of colour SOURCE, which used to mean discarding the layer and building
295
+ // another — and, because adding a 3D layer reframes, a camera jump to undo as well.
296
+ // napari-js ≥ 0.14 lets the scalars be replaced in place — the setter bumps the
297
+ // layer's dataVersion so the visual re-uploads — and the positions have not moved,
298
+ // so there is nothing for the camera to reframe.
299
+ this.scalarKey = scalarKey;
300
+ this.points.values = valuesFor();
301
+ this.points.colors = colorsFor();
302
+ }
303
+ this.points.colormap = colormap;
304
+ this.points.contrastLimits = contrastLimits;
305
+ this.points.size = size;
306
+ }
307
+ const cloud = this.points;
308
+ if (cloud) {
309
+ cloud.opacity = view.opacity;
310
+ this.applySelection(cloud, selection, shown, obs.count);
311
+ }
312
+ // Last, so it also covers a layer this pass just created.
313
+ if (this.points)
314
+ this.points.visible = view.showPoints;
315
+ viewer.requestRender();
316
+ }
317
+ /** Interleaved x,y,z of the `shown` observations (null: all of them), offset by {@link origin}. */
318
+ cloudPositions(obs, shown) {
319
+ // rebuild() draws only a dataset whose observations have a z.
320
+ const z = obs.z;
321
+ const [ox, oy, oz] = this.origin;
322
+ const count = shown ? shown.length : obs.count;
323
+ const positions = new Float32Array(count * 3);
324
+ for (let k = 0; k < count; k++) {
325
+ const i = shown ? shown[k] : k;
326
+ positions[k * 3] = obs.x[i] + ox;
327
+ positions[k * 3 + 1] = obs.y[i] + oy;
328
+ positions[k * 3 + 2] = z[i] + oz;
329
+ }
330
+ return positions;
331
+ }
332
+ /**
333
+ * Selection is a PER-POINT alpha, in the one layer.
334
+ *
335
+ * It used to be a second layer: with a single opacity for the whole cloud, the only way
336
+ * to highlight a subset was to draw it again on top at full opacity while the parent
337
+ * dropped to the muted level. That second layer had to be kept in step through every
338
+ * colormap, window and size change, and the two then depth-sorted against each other as
339
+ * separate draws. Per-point alphas and sizes give the same reading — muted cloud, bright
340
+ * selection, slightly larger so a small one is findable inside 3.7M points — in one.
341
+ *
342
+ * `shown` is the drawn subset (null: every one of the `total` observations), so the alphas
343
+ * follow the drawn order.
344
+ */
345
+ applySelection(cloud, selection, shown, total) {
346
+ if (selection.count === 0 || selection.mask.length !== total) {
347
+ cloud.alphas = null;
348
+ cloud.sizes = null;
349
+ return;
350
+ }
351
+ const shownCount = shown ? shown.length : total;
352
+ const alphas = new Float32Array(shownCount);
353
+ const sizes = new Float32Array(shownCount);
354
+ for (let k = 0; k < shownCount; k++) {
355
+ const i = shown ? shown[k] : k;
356
+ const picked = !!selection.mask[i];
357
+ alphas[k] = picked ? 1 : DEFAULT_MUTED_OPACITY;
358
+ sizes[k] = picked ? SPATIAL_SELECTED_SIZE_SCALE : 1;
359
+ }
360
+ cloud.alphas = alphas;
361
+ cloud.sizes = sizes;
362
+ }
363
+ /**
364
+ * The **3D gene map**: the active gene's expression over the whole sectioned
365
+ * specimen, as one raymarched volume.
366
+ *
367
+ * Two things it can be, and the panel's `Volume rendering` toggle picks which:
368
+ *
369
+ * - **sheets** — exactly the planes that were imaged, each carrying that
370
+ * slide's own 2D gene map, with the gaps between sections empty. A stack of
371
+ * measured fields, at their true z.
372
+ * - **volume** — the same fields smoothed along z, so the planes between the
373
+ * sections carry an interpolated value. An estimate, and drawn as a
374
+ * translucent cloud for the same reason the density volumes are.
375
+ *
376
+ * One `VolumeLayer` rather than a textured quad per section: an `ImageLayer`
377
+ * renders only at `ndisplay === 2`, so 53 sheets in the orbit view would need a
378
+ * new layer type upstream — while a scalar volume whose z sampling already IS
379
+ * the section spacing expresses the sheets exactly, and the same lattice then
380
+ * gives the interpolated version for free.
381
+ *
382
+ * Estimated on the reference volume's own lattice (`densityGrid` at stride 1),
383
+ * so the field lands voxel-for-voxel on the anatomy and needs no offset — a
384
+ * `VolumeLayer` has no translate, and napari centres both boxes on the world
385
+ * origin.
386
+ */
387
+ async ensureGeneMap(viewer, dataset, view, selection) {
388
+ const gene = view.geneMap && view.colorBy?.kind === 'feature' ? view.colorBy.name : null;
389
+ const port = this.session.port;
390
+ const cache = this.session.geneMapVolume;
391
+ const smoothing = view.geneMapSmoothing > 0 ? view.geneMapSmoothing : 1;
392
+ const clip = view.percentileClip ?? [0.01, 0.99];
393
+ const obs = dataset.observations;
394
+ // A volume built from ONE section would smear that slide through the whole
395
+ // depth, so the section restriction only applies to the sheets.
396
+ const interpolate = !!view.geneMapVolume;
397
+ const sections = sectionsOf(obs);
398
+ const section = !interpolate && view.geneMapSection != null && sections && sections.length > 0
399
+ ? sections[Math.max(0, Math.min(sections.length - 1, view.geneMapSection))]
400
+ : null;
401
+ const fieldKey = gene
402
+ ? [
403
+ dataset.id,
404
+ gene,
405
+ smoothing,
406
+ section ?? 'all',
407
+ interpolate ? 'vol' : 'sheets',
408
+ this.session.selectionRev(selection),
409
+ ].join('|')
410
+ : null;
411
+ const key = fieldKey
412
+ ? [
413
+ fieldKey,
414
+ clip.join(','),
415
+ view.logScale ? 'log' : 'lin',
416
+ view.geneMapOpacity,
417
+ this.ctx.display.continuousColormapKey(view),
418
+ ].join('|')
419
+ : null;
420
+ if (key === this.geneMapKey)
421
+ return;
422
+ if (this.geneMapLayer) {
423
+ viewer.layers.remove(this.geneMapLayer);
424
+ this.geneMapLayer = null;
425
+ }
426
+ this.geneMapKey = key;
427
+ if (!key || !gene || !port) {
428
+ cache.field = null;
429
+ cache.key = null;
430
+ return;
431
+ }
432
+ // Coarsened in-plane but NOT along z: the sheets need one plane per imaged
433
+ // section, while the field they carry is smooth by construction and gains
434
+ // nothing from the template's 40 µm detail. At full resolution the estimate is
435
+ // a 5.7M-voxel pair of blurs — seconds of work for a checkbox; an eighth of the
436
+ // voxels is an eighth of the work.
437
+ const grid = densityGrid(dataset, GENE_MAP_VOLUME_STRIDE, 128, 1);
438
+ if (!grid)
439
+ return;
440
+ if (fieldKey !== cache.key) {
441
+ const load = this.geneMapLoads.next();
442
+ let values;
443
+ try {
444
+ values = await port.getFeatureVector(gene);
445
+ }
446
+ catch (err) {
447
+ console.warn(`[napari-js] 3D gene map: "${gene}" unavailable`, err);
448
+ this.geneMapKey = null;
449
+ return;
450
+ }
451
+ if (!load() || this.geneMapKey !== key)
452
+ return;
453
+ const inSelection = selection.count > 0 ? maskToIndices(selection.mask) : undefined;
454
+ // In-plane σ is a PHYSICAL bandwidth, anchored to the reference volume's own
455
+ // voxel — the resolution the 2D map estimates at — so a sheet and the 2D
456
+ // view of the same section are the same field whatever lattice this is
457
+ // rasterised on. Along z it is the density path's 1.5 voxels: the smallest σ
458
+ // that bridges one section gap.
459
+ const inPlane = dataset.volume?.voxelSize ?? grid.voxelSize;
460
+ let field;
461
+ try {
462
+ field = await computeExpressionVolumeAsync(obs, grid, {
463
+ sigma: [
464
+ inPlane[0] * GENE_MAP_SIGMA * smoothing,
465
+ inPlane[1] * GENE_MAP_SIGMA * smoothing,
466
+ grid.voxelSize[2] * 1.5 * smoothing,
467
+ ],
468
+ values,
469
+ indices: section != null ? observationsInSection(obs, section) : inSelection,
470
+ interpolate,
471
+ }, { signal: load.signal });
472
+ }
473
+ catch (err) {
474
+ if (isAbortError(err))
475
+ return; // superseded by a newer map, or the scene went away
476
+ throw err;
477
+ }
478
+ if (!load() || this.geneMapKey !== key)
479
+ return;
480
+ cache.field = field;
481
+ cache.key = fieldKey;
482
+ }
483
+ const field = cache.field;
484
+ if (!field)
485
+ return;
486
+ // The high end over the MEASURED voxels only (the unmeasured zeros would pull it down and
487
+ // saturate the map), but the low end stays 0: in a volume the value is also the opacity and
488
+ // 0 reads as "nothing here", so starting at the lowest measured value would erase it.
489
+ const [, hi] = fieldContrastWindow(field, clip[0], clip[1]);
490
+ const lo = 0;
491
+ const data = encodeExpressionVolume(field, [lo, hi], { log: view.logScale });
492
+ const lut = this.ctx.display.spatialLut(view);
493
+ this.geneMapLayer = viewer.addVolume(data, field.width, field.height, field.depth, {
494
+ name: `gene map · ${gene}${interpolate ? ' · volume' : ''}`,
495
+ colormap: colormapFromLut(`gene-map-${gene}`, lut),
496
+ // The encoding already applied the window, so the layer must not apply a
497
+ // second one: 0..255 is the whole of what it was given.
498
+ contrastLimits: [0, 255],
499
+ rendering: 'translucent',
500
+ // Additive like the density volumes, and for the same reason: the sheets
501
+ // have to read THROUGH each other and through the anatomy, which a
502
+ // translucent blend would occlude one sheet at a time.
503
+ blending: 'additive',
504
+ opacity: view.geneMapOpacity,
505
+ voxelSize: grid.voxelSize,
506
+ });
507
+ viewer.requestRender();
508
+ }
509
+ /**
510
+ * Cluster density volumes: each cluster rasterised into a smooth scalar field and
511
+ * raymarched alongside the cloud, tinted with the cluster's own legend colour.
512
+ *
513
+ * This is what makes a serially sectioned dataset readable as an anatomical
514
+ * distribution. The cloud shows measured cells and nothing else — but at 200 µm
515
+ * section spacing the eye cannot integrate a stack of discs into a shape, and
516
+ * every gap reads as absence. A density field is a different object from a cell:
517
+ * an estimate, defined between the imaged planes, drawn as a translucent cloud so
518
+ * it cannot be mistaken for measurement. Individual cells are never interpolated —
519
+ * consecutive sections sample different cells, so there is nothing to interpolate
520
+ * along.
521
+ *
522
+ * One volume per cluster rather than one for everything: additive blending is what
523
+ * makes two clusters' territories comparable, and a single blended field would
524
+ * answer no question anyone asks of a taxonomy. Capped at `DENSITY_MAX_CLUSTERS` by cell
525
+ * count.
526
+ *
527
+ * Keyed so it rebuilds only when the field would actually differ — the dataset,
528
+ * the colour column, the bandwidth, or the selection.
529
+ */
530
+ async ensureDensityVolumes(viewer, dataset, view, selection) {
531
+ const on = !!view.densityVolume && !!dataset.observations.z;
532
+ const smoothing = view.densitySmoothing > 0 ? view.densitySmoothing : 1;
533
+ const column = view.colorBy?.kind === 'column' ? view.colorBy.name : null;
534
+ // The selection enters the key by IDENTITY, not by count: two different ROIs
535
+ // holding the same number of cells would otherwise look like the same key and
536
+ // leave the previous ROI's fields on screen.
537
+ const key = on
538
+ ? [dataset.id, column ?? 'all', smoothing, this.session.selectionRev(selection)].join('|')
539
+ : null;
540
+ if (key === this.densityKey)
541
+ return;
542
+ for (const layer of this.densityLayers)
543
+ viewer.layers.remove(layer);
544
+ this.densityLayers = [];
545
+ this.densityKey = key;
546
+ const load = this.densityLoads.next();
547
+ if (!key)
548
+ return;
549
+ const grid = densityGrid(dataset);
550
+ if (!grid)
551
+ return;
552
+ // With no reference volume there is no offset yet, and a VolumeLayer has no
553
+ // translate — napari centres its box on the world origin. So the POINTS move by
554
+ // half the density box, exactly as they do for a reference volume, and the
555
+ // cached geometry is invalidated because that offset just changed.
556
+ if (!this.volume) {
557
+ this.origin = [
558
+ -(grid.width * grid.voxelSize[0]) / 2,
559
+ -(grid.height * grid.voxelSize[1]) / 2,
560
+ -(grid.depth * grid.voxelSize[2]) / 2,
561
+ ];
562
+ this.layerKey = null;
563
+ }
564
+ let groups;
565
+ try {
566
+ groups = await this.densityGroups(dataset, column, selection);
567
+ }
568
+ catch (err) {
569
+ console.warn('[napari-js] density volumes: column unavailable', err);
570
+ this.densityKey = null;
571
+ return;
572
+ }
573
+ if (!load() || this.densityKey !== key)
574
+ return;
575
+ const sigma = defaultSigma(grid, smoothing);
576
+ // Additive blending SUMS, so a fixed per-layer opacity blows out to white as
577
+ // soon as several broad clusters overlap — six subclasses at 0.55 each turned
578
+ // the brain into one cyan mass. Splitting the budget keeps n fully overlapping
579
+ // peaks inside the display's range, so overlap reads as overlap; a single
580
+ // cluster still gets the full 0.55. It only mitigates: a translucent raymarch
581
+ // integrates along the ray, so clusters that are ubiquitous rather than
582
+ // regional (the largest subclasses are glia, which are everywhere) still pile
583
+ // up, and one cluster at a time is the readable way to look at those.
584
+ const opacity = Math.min(0.55, 0.9 / Math.max(1, groups.length));
585
+ let fields;
586
+ try {
587
+ // Off the main thread past the worker threshold; the clusters queue on one worker.
588
+ fields = await Promise.all(groups.map((group) => rasterizeDensityAsync(dataset.observations, grid, { sigma, indices: group.indices }, { signal: load.signal })));
589
+ }
590
+ catch (err) {
591
+ if (isAbortError(err))
592
+ return; // superseded by a newer key, or the scene went away
593
+ throw err;
594
+ }
595
+ if (!load() || this.densityKey !== key)
596
+ return;
597
+ groups.forEach((group, i) => {
598
+ const data = fields[i];
599
+ // A cluster with nothing on the grid draws no layer, rather than an empty box.
600
+ if (!data)
601
+ return;
602
+ this.densityLayers.push(viewer.addVolume(data, grid.width, grid.height, grid.depth, {
603
+ name: `density · ${group.name}`,
604
+ colormap: this.ctx.display.channelTintColormap(group.color),
605
+ invert: this.ctx.display.invert,
606
+ // Translucent, not MIP: a cluster's interior is the readable part, and MIP
607
+ // would flatten every cloud to its brightest shell.
608
+ rendering: 'translucent',
609
+ opacity,
610
+ // Additive, so two clusters overlapping read as both being there instead
611
+ // of the nearer one hiding the other.
612
+ blending: 'additive',
613
+ voxelSize: grid.voxelSize,
614
+ }));
615
+ });
616
+ viewer.requestRender();
617
+ }
618
+ /**
619
+ * The clusters to rasterise: the categories of the active categorical colouring,
620
+ * biggest first and capped, each with its legend colour, restricted to the current selection
621
+ * when there is one. With no categorical colouring there is one group — total cell density,
622
+ * which is a real question on its own ("where is the tissue dense?") and the honest thing to
623
+ * show when the view is not encoding a taxonomy.
624
+ */
625
+ async densityGroups(dataset, column, selection) {
626
+ const port = this.session.port;
627
+ const meta = column ? findColumnMeta(dataset, column) : undefined;
628
+ if (!port || !column || !meta || meta.kind !== 'categorical')
629
+ return [totalDensityGroup(selection)];
630
+ const loaded = await port.getColumn(column);
631
+ if (!isCategoricalColumn(loaded))
632
+ return [];
633
+ return rankDensityGroups(column, loaded, dataset.observations.count, selection);
634
+ }
635
+ /**
636
+ * Add (or keep) the dataset's reference volume, and derive the offset that sits the
637
+ * observations inside it.
638
+ *
639
+ * `VolumeLayer` has no translate: napari-js maps the volume's unit cube to a world box
640
+ * **centred on the origin**, sized `dims x voxelSize`. The observations, by contract, are in
641
+ * the volume's own frame with its near corner at the coordinate origin. So the two only line
642
+ * up if the POINTS move — by half the box — which is what {@link origin} is.
643
+ *
644
+ * A failed or absent volume is not fatal: the cloud renders on its own, at its own
645
+ * coordinates, and the camera frames the points instead.
646
+ */
647
+ async ensureVolume(viewer, dataset, view) {
648
+ const meta = dataset.volume;
649
+ const port = this.session.port;
650
+ const key = meta ? `${dataset.id}:${meta.width}x${meta.height}x${meta.depth}` : null;
651
+ if (key && key === this.volumeKey)
652
+ return;
653
+ if (this.volume) {
654
+ viewer.layers.remove(this.volume);
655
+ this.volume = null;
656
+ this.volumeKey = null;
657
+ }
658
+ this.origin = [0, 0, 0];
659
+ if (!meta || !port?.getVolume)
660
+ return;
661
+ let voxels;
662
+ try {
663
+ voxels = await port.getVolume();
664
+ }
665
+ catch (err) {
666
+ console.warn('[napari-js] reference volume unavailable — drawing the cloud alone', err);
667
+ return;
668
+ }
669
+ if (this.ctx.signal.aborted)
670
+ return;
671
+ const [vx, vy, vz] = meta.voxelSize;
672
+ this.volumeKey = key;
673
+ this.volume = viewer.addVolume(voxels, meta.width, meta.height, meta.depth, {
674
+ name: 'reference volume',
675
+ colormap: 'gray',
676
+ // MIP would draw the brightest voxel along each ray, which for an averaged
677
+ // template means a flat white shell that hides the cloud. Translucent lets
678
+ // the points read through the tissue, which is the entire point of drawing
679
+ // them together.
680
+ rendering: 'translucent',
681
+ opacity: view.volumeOpacity,
682
+ voxelSize: [vx, vy, vz],
683
+ });
684
+ // Half the box, negated: the observations' origin is the box's near corner,
685
+ // and the box is centred on the world origin.
686
+ this.origin = [-(meta.width * vx) / 2, -(meta.height * vy) / 2, -(meta.depth * vz) / 2];
687
+ // Force a geometry rebuild: the offset changed, so cached positions are stale.
688
+ this.layerKey = null;
689
+ }
690
+ /** Drop every layer of the cloud (the dataset went away, or has no z). */
691
+ removeLayers(viewer) {
692
+ for (const layer of [this.points, this.volume, this.geneMapLayer, ...this.densityLayers]) {
693
+ if (layer)
694
+ viewer.layers.remove(layer);
695
+ }
696
+ this.geneMapLayer = null;
697
+ this.geneMapKey = null;
698
+ this.session.geneMapVolume.field = null;
699
+ this.session.geneMapVolume.key = null;
700
+ this.densityLayers = [];
701
+ this.densityKey = null;
702
+ // The scene is gone, so the next 3D layer should frame itself again. That used to be
703
+ // `spatialFramed = null` next to a hand-rolled save/restore; the renderer owns the
704
+ // policy now, and this is the same statement addressed to it.
705
+ viewer.resetFit3D();
706
+ this.volume = null;
707
+ this.volumeKey = null;
708
+ this.origin = [0, 0, 0];
709
+ this.points = null;
710
+ this.setPicker(null);
711
+ this.layerKey = null;
712
+ this.scalarKey = null;
713
+ this.positions = null;
714
+ this.drawn = null;
715
+ }
716
+ /**
717
+ * What colours the cloud.
718
+ *
719
+ * Continuous data goes through the active colormap with the same percentile window the 2D path
720
+ * uses. Categorical data is one RGBA per point from the column's palette, so any number of
721
+ * categories keeps its own colour — see `encodeSpatial3dCategorical`.
722
+ */
723
+ async scalarEncoding(view) {
724
+ const port = this.session.port;
725
+ const colorBy = view.colorBy;
726
+ if (!port || !colorBy)
727
+ return null;
728
+ if (colorBy.kind === 'column') {
729
+ const column = await port.getColumn(colorBy.name);
730
+ if (isCategoricalColumn(column)) {
731
+ return encodeSpatial3dCategorical(column.codes, resolveCategoryColors(column.meta));
732
+ }
733
+ return this.encodeContinuous(column.values, view);
734
+ }
735
+ return this.encodeContinuous(await port.getFeatureVector(colorBy.name), view);
736
+ }
737
+ /** Continuous values → the active colormap over a percentile-clipped window. */
738
+ encodeContinuous(source, view) {
739
+ return encodeSpatial3dContinuous(source, view, this.ctx.display.spatialLut(view), this.session.contrastWindows);
740
+ }
741
+ }
742
+ /**
743
+ * The observations the cloud draws, and the keys of its geometry and of its colour source.
744
+ *
745
+ * One imaged section, or the whole stack (`shown` null). The subset IS the geometry, so it
746
+ * belongs in the geometry key rather than being re-derived per frame — and an out-of-range
747
+ * index is clamped rather than dropping the cloud, because the section count changes with the
748
+ * dataset while the view state persists. The scalars' identity is tracked separately from the
749
+ * geometry's (`colorBy` plus the transforms feeding the encoding): a new colour source swaps
750
+ * `values` in place (napari-js ≥ 0.14), while a new geometry needs a new layer.
751
+ */
752
+ function cloudSubset(dataset, view) {
753
+ const obs = dataset.observations;
754
+ const sections = sectionsOf(obs);
755
+ const section = view.pointSection != null && sections && sections.length > 0
756
+ ? sections[Math.max(0, Math.min(sections.length - 1, view.pointSection))]
757
+ : null;
758
+ const shown = section != null ? observationsInSection(obs, section) : null;
759
+ const key = `${dataset.id}:${obs.count}:${section ?? 'all'}`;
760
+ const clip = view.percentileClip ?? [0.01, 0.99];
761
+ const scalarKey = [
762
+ key,
763
+ view.colorBy ? `${view.colorBy.kind}:${view.colorBy.name}` : 'flat',
764
+ view.logScale ? 'log' : 'lin',
765
+ clip.join(','),
766
+ ].join('|');
767
+ return { shown, key, scalarKey };
768
+ }
769
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtM2Qtc2NlbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtM2Qtc2NlbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFekQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBR3JELE9BQU8sRUFJTCxjQUFjLEVBQ2QsbUJBQW1CLEdBQ3BCLE1BQU0sMENBQTBDLENBQUM7QUFFbEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDOUYsT0FBTyxFQUF3QixjQUFjLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdEcsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbkYsT0FBTyxFQUVMLHNCQUFzQixFQUN0QixtQkFBbUIsR0FDcEIsTUFBTSxrQ0FBa0MsQ0FBQztBQUMxQyxPQUFPLEVBQUUsNEJBQTRCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNqRyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFFTCxjQUFjLEVBQ2Qsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQiwyQkFBMkIsRUFHM0IsMEJBQTBCLEVBQzFCLHlCQUF5QixFQUN6QixZQUFZLEVBQ1osaUJBQWlCLEVBQ2pCLG1CQUFtQixFQUNuQixpQkFBaUIsR0FDbEIsTUFBTSwyQkFBMkIs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OlsiaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBQb2ludFBpY2tlciwgY29sb3JtYXBGcm9tTHV0IH0gZnJvbSAnbmFwYXJpLWpzJztcbmltcG9ydCB0eXBlIHsgUG9pbnRzM0RMYXllciwgVmlld2VyLCBWb2x1bWVMYXllciB9IGZyb20gJ25hcGFyaS1qcyc7XG5pbXBvcnQgeyBTY2FsZUJhck92ZXJsYXkgfSBmcm9tICduYXBhcmktanMvb3ZlcmxheXMnO1xuXG5pbXBvcnQgeyBJSGlzdG9ncmFtIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NoYW5uZWwtaGlzdG9ncmFtLWFwaS5jb250cmFjdCc7XG5pbXBvcnQge1xuICBTcGF0aWFsQ29sdW1uLFxuICBTcGF0aWFsRGF0YXNldCxcbiAgU3BhdGlhbE9ic2VydmF0aW9ucyxcbiAgZmluZENvbHVtbk1ldGEsXG4gIGlzQ2F0ZWdvcmljYWxDb2x1bW4sXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IERFRkFVTFRfTVVURURfT1BBQ0lUWSwgcmVzb2x2ZUNhdGVnb3J5Q29sb3JzIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nJztcbmltcG9ydCB7IFNwYXRpYWxTZWxlY3Rpb25NYXNrLCBlbXB0eVNlbGVjdGlvbiwgbWFza1RvSW5kaWNlcyB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1zZWxlY3Rpb24nO1xuaW1wb3J0IHsgZGVmYXVsdFNpZ21hLCBkZW5zaXR5R3JpZCB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1kZW5zaXR5JztcbmltcG9ydCB7IG9ic2VydmF0aW9uc0luU2VjdGlvbiwgc2VjdGlvbnNPZiB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1zZWN0aW9ucyc7XG5pbXBvcnQge1xuICBFeHByZXNzaW9uVm9sdW1lRmllbGQsXG4gIGVuY29kZUV4cHJlc3Npb25Wb2x1bWUsXG4gIGZpZWxkQ29udHJhc3RXaW5kb3csXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1leHByZXNzaW9uJztcbmltcG9ydCB7IGNvbXB1dGVFeHByZXNzaW9uVm9sdW1lQXN5bmMsIHJhc3Rlcml6ZURlbnNpdHlBc3luYyB9IGZyb20gJy4uLy4uL3dvcmtlcnMvc3BhdGlhbC1tYXRoJztcbmltcG9ydCB7IFN1cGVyc2VkZSB9IGZyb20gJy4uLy4uL3V0aWwvc3VwZXJzZWRlJztcbmltcG9ydCB7IGlzQWJvcnRFcnJvciB9IGZyb20gJy4uL3RpbGUtc2VydmVyJztcbmltcG9ydCB7XG4gIERlbnNpdHlHcm91cCxcbiAgR0VORV9NQVBfU0lHTUEsXG4gIEdFTkVfTUFQX1ZPTFVNRV9TVFJJREUsXG4gIFNQQVRJQUxfM0RfQkFTRV9TSVpFLFxuICBTUEFUSUFMX1NFTEVDVEVEX1NJWkVfU0NBTEUsXG4gIFNwYXRpYWwzZEVuY29kaW5nLFxuICBTcGF0aWFsM2RTY2FsYXJzLFxuICBlbmNvZGVTcGF0aWFsM2RDYXRlZ29yaWNhbCxcbiAgZW5jb2RlU3BhdGlhbDNkQ29udGludW91cyxcbiAgZ2F0aGVyQ29sb3JzLFxuICByYW5rRGVuc2l0eUdyb3VwcyxcbiAgc3BhdGlhbEZsYXRDb2xvcm1hcCxcbiAgdG90YWxEZW5zaXR5R3JvdXAsXG59IGZyb20gJy4vbmFwYXJpLXNwYXRpYWwtZW5jb2RpbmcnO1xuaW1wb3J0IHsgSE9WRVJfUkFESVVTX1BYIH0gZnJvbSAnLi9uYXBhcmktc3BhdGlhbC1ob3Zlcic7XG5pbXBvcnQgeyBTcGF0aWFsU2NlbmVCYXNlLCBTcGF0aWFsU2Vzc2lvbiB9IGZyb20gJy4vbmFwYXJpLXNwYXRpYWwtc2NlbmUnO1xuaW1wb3J0IHR5cGUgeyBOYXBhcmlTY2VuZSwgU2NlbmVDb250ZXh0IH0gZnJvbSAnLi9uYXBhcmktc2NlbmUnO1xuXG4vKipcbiAqIFNQQVRJQUxfT01JQ1NfM0QgKHJldmlldyBBcHBlbmRpeCBCLCBjbHVzdGVyIEspOiBvYnNlcnZhdGlvbnMgYXMgYSAzRCBwb2ludCBjbG91ZCB1bmRlciB0aGVcbiAqIG9yYml0IGNhbWVyYSwgd2l0aCB0aGUgZGF0YXNldCdzIHJlZmVyZW5jZSB2b2x1bWUgYXJvdW5kIGl0LCBwZXItY2x1c3RlciBkZW5zaXR5IHZvbHVtZXMgYW5kIHRoZVxuICogM0QgZ2VuZSBtYXAuXG4gKlxuICogVGhpbm5lciB0aGFuIHRoZSAyRCBzY2VuZTogdGhlcmUgaXMgbm8gdGlzc3VlIGltYWdlIHRvIHJlbmRlciAoYSByZWdpc3RlcmVkIHZvbHVtZSBsaWtlIHRoZVxuICogQWxsZW4gQ0NGIGhhcyBubyBzaW5nbGUgcmVmZXJlbmNlIHBsYW5lKSwgc28gbm8gcmVhZGJhY2sgYW5kIG5vIG5hdmlnYXRvcjsgdGhlIDNEIHNjYWxlIGJhclxuICogZm9sbG93cyB0aGUgZGF0YXNldCAoc2VlIHtAbGluayBpbnN0YWxsU2NhbGVCYXJ9KS4gVGhlIHJlZ2lvbiB0b29scyB3b3JrIGluIFNDUkVFTiBzcGFjZSB0aHJvdWdoXG4gKiB0aGUgdG9vbCBicmlkZ2UncyAzRCBpbnRlcmFjdGlvbiDigJQgYSBsYXNzbyBzZWxlY3RzIHRoZSBjZWxscyB1bmRlciBpdCwgYW5kIGFuIG9yYml0IGNsZWFycyB0aGVcbiAqIHNoYXBlIHdoaWxlIGtlZXBpbmcgdGhlIHNlbGVjdGlvbi4gVGhlIGZpcnN0IDNEIGxheWVyIGFkZGVkIGZyYW1lcyB0aGUgY2FtZXJhIChgZml0M2Q6ICdvbmNlJ2ApLlxuICovXG5leHBvcnQgY2xhc3MgU3BhdGlhbDNkU2NlbmUgZXh0ZW5kcyBTcGF0aWFsU2NlbmVCYXNlIGltcGxlbWVudHMgTmFwYXJpU2NlbmUge1xuICAvKiogVGhlIDNEIHBvaW50IGNsb3VkLiBPbmUgbGF5ZXI6IHNlbGVjdGlvbiBpcyBhIHBlci1wb2ludCBhbHBoYSBvbiBpdCwgbm90IGEgc2Vjb25kLiAqL1xuICBwcml2YXRlIHBvaW50czogUG9pbnRzM0RMYXllciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGxheWVyS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIEludGVybGVhdmVkIHgseSx6LCBjYWNoZWQgc28gYSBjb2xvdXIgY2hhbmdlIGRvZXMgbm90IHJlLXdhbGsgMy43TSBvYnNlcnZhdGlvbnMuICovXG4gIHByaXZhdGUgcG9zaXRpb25zOiBGbG9hdDMyQXJyYXkgfCBudWxsID0gbnVsbDtcbiAgLyoqIElkZW50aXR5IG9mIHRoZSBzY2FsYXJzIGN1cnJlbnRseSB1cGxvYWRlZCDigJQgc2VlIHtAbGluayByZWJ1aWxkfS4gKi9cbiAgcHJpdmF0ZSBzY2FsYXJLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogT2JzZXJ2YXRpb24gaW5kaWNlcyB0aGUgY2FjaGVkIHBvc2l0aW9ucyBiZWxvbmcgdG8sIGluIHRoZSBzYW1lIG9yZGVyOyBudWxsIHdoZW4gZXZlcnlcbiAgICogIG9ic2VydmF0aW9uIGlzIGRyYXduLiBXaXRob3V0IGl0IGEgcHJvamVjdGlvbiBidWlsdCBmcm9tIHRoZSBwb3NpdGlvbnMgaXMgaW5kZXhlZCBieSBEUkFXTlxuICAgKiAgb3JkZXIgYW5kIHNpbGVudGx5IGF0dHJpYnV0ZXMgZWFjaCBwb2ludCB0byB0aGUgd3Jvbmcgb2JzZXJ2YXRpb24gYXMgc29vbiBhcyBhIHNlY3Rpb24gaXNcbiAgICogIGlzb2xhdGVkLiAqL1xuICBwcml2YXRlIGRyYXduOiBVaW50MzJBcnJheSB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGFuYXRvbWljYWwgdm9sdW1lIHRoZSBjbG91ZCBzaXRzIGluc2lkZSwgd2hlbiB0aGUgZGF0YXNldCBoYXMgb25lLiAqL1xuICBwcml2YXRlIHZvbHVtZTogVm9sdW1lTGF5ZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB2b2x1bWVLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogUGVyLWNsdXN0ZXIgZGVuc2l0eSB2b2x1bWVzIGRyYXduIGFsb25nc2lkZSB0aGUgY2xvdWQsIGFuZCB3aGF0IHRoZXkgd2VyZVxuICAgKiAgYnVpbHQgZnJvbSDigJQgcmFzdGVyaXNpbmcgaXMgc2Vjb25kcyBvZiB3b3JrLCBzbyBpdCBtdXN0IG5vdCByZXBlYXQgZm9yIGFcbiAgICogIGNoYW5nZSB0aGF0IGNhbm5vdCBhZmZlY3QgdGhlIGZpZWxkLiAqL1xuICBwcml2YXRlIGRlbnNpdHlMYXllcnM6IFZvbHVtZUxheWVyW10gPSBbXTtcbiAgcHJpdmF0ZSBkZW5zaXR5S2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSAzRCBnZW5lIG1hcCdzIHZvbHVtZSBsYXllciBhbmQgdGhlIGlucHV0cyBpdCB3YXMgY29sb3VyZWQgZm9yIChpdHMgZmllbGQgaXMgY2FjaGVkIGluXG4gICAqICB0aGUgc2Vzc2lvbiwgb24gYSBjbG9jayBvZiBpdHMgb3duKS4gKi9cbiAgcHJpdmF0ZSBnZW5lTWFwTGF5ZXI6IFZvbHVtZUxheWVyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZ2VuZU1hcEtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBPZmZzZXQgYXBwbGllZCB0byBvYnNlcnZhdGlvbiBjb29yZGluYXRlcyB0byBzaXQgdGhlbSBpbiB0aGUgdm9sdW1lJ3MgYm94LiAqL1xuICBwcml2YXRlIG9yaWdpbjogW251bWJlciwgbnVtYmVyLCBudW1iZXJdID0gWzAsIDAsIDBdO1xuICAvKipcbiAgICogbmFwYXJpLWpzJ3MgZGVwdGgtYXdhcmUgcGljayBvdmVyIHRoZSBjbG91ZCwgYW5kIHRoZSBwcm9qZWN0aW9uIHRoZSBST0kgc2VsZWN0aW9uIHJlYWRzLiBJdFxuICAgKiBvd25zIHRoZSBjYWNoaW5nIHBvbGljeTogcmUtcHJvamVjdCBsYXppbHksIG9uIHRoZSBmaXJzdCBwaWNrIGFmdGVyIHRoZSBjYW1lcmEsIHRoZSBjYW52YXMgb3JcbiAgICogdGhlIGNsb3VkJ3MgZGF0YSBtb3ZlZCAobmV2ZXIgb24gdGhlIGNhbWVyYSBldmVudCwgc28gYW4gb3JiaXQgZHJhZyBwYXlzIG5vdGhpbmcpLCBpbnRvXG4gICAqIHJldXNlZCBidWZmZXJzLCB3aXRoIGEgc2NyZWVuIGluZGV4IG9uY2UgdGhlIGNsb3VkIGlzIGxhcmdlIGVub3VnaC5cbiAgICovXG4gIHByaXZhdGUgcGlja2VyOiBQb2ludFBpY2tlciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHNjYWxlQmFyOiBTY2FsZUJhck92ZXJsYXkgfCBudWxsID0gbnVsbDtcbiAgLyoqIERhdGFzZXQgdGhlIHNjYWxlIGJhciB3YXMgYnVpbHQgZm9yLiAqL1xuICBwcml2YXRlIHNjYWxlQmFyS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBkZW5zaXR5IHJhc3RlcmlzYXRpb24gYW5kIHRoZSAzRCBnZW5lLW1hcCBlc3RpbWF0ZSBpbiBmbGlnaHQgKG9mZiB0aGUgbWFpbiB0aHJlYWRcbiAgICogIHBhc3QgdGhlIHdvcmtlciB0aHJlc2hvbGQsIFNQQVRJQUwtMTkpOiBhIG5ldyBrZXkgc3VwZXJzZWRlcyDigJQgYW5kIGFib3J0cyDigJQgdGhlIHByZXZpb3VzXG4gICAqICBvbmU7IGEgcmVidWlsZCB0aGF0IGxlYXZlcyB0aGUga2V5IGFsb25lIGxldHMgaXQgZmluaXNoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRlbnNpdHlMb2FkcyA9IG5ldyBTdXBlcnNlZGUoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBnZW5lTWFwTG9hZHMgPSBuZXcgU3VwZXJzZWRlKCk7XG4gIC8qKiBUaGUgc3RvcmUncyBpbnZlcnQgc2V0dGluZywgd2hpY2ggdGhlIGRlbnNpdHkgdm9sdW1lcyBmb2xsb3cgKG5vIG90aGVyIHN1YnNjcmlwdGlvbiBvZlxuICAgKiAgdGhpcyBzY2VuZSBjYXJyaWVzIGl0KS4gKi9cbiAgcHJpdmF0ZSBpbnZlcnRTdWI6IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKGN0eDogU2NlbmVDb250ZXh0LCBzZXNzaW9uOiBTcGF0aWFsU2Vzc2lvbikge1xuICAgIHN1cGVyKGN0eCwgc2Vzc2lvbiwgdHJ1ZSk7XG4gIH1cblxuICBhc3luYyBtb3VudCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBCZWZvcmUgdGhlIHNwYXRpYWwgc3Vic2NyaXB0aW9uLCBzbyB0aGUgZmlyc3QgYnVpbGQgYWxyZWFkeSByZWFkcyB0aGUgY3VycmVudCB2YWx1ZS5cbiAgICB0aGlzLmludmVydFN1YiA9IHRoaXMuY3R4LmRpc3BsYXkud2F0Y2hJbnZlcnQoKGludmVydCkgPT4ge1xuICAgICAgLy8gQSBsaXZlIHNldHRlcjogdGhlIHZvbHVtZXMgcmVzdHlsZSwgbm90aGluZyBpcyByYXN0ZXJpc2VkIGFnYWluLlxuICAgICAgZm9yIChjb25zdCBsYXllciBvZiB0aGlzLmRlbnNpdHlMYXllcnMpIGxheWVyLmludmVydCA9IGludmVydDtcbiAgICAgIHRoaXMuY3R4LnZpZXdlci5yZXF1ZXN0UmVuZGVyKCk7XG4gICAgfSk7XG4gICAgdGhpcy5jdHgudG9vbHMuaW5zdGFsbDNkSW50ZXJhY3Rpb24odGhpcy5jdHgudmlld2VyLCB0aGlzLmN0eC5ob3N0KTtcbiAgICB0aGlzLmhvdmVyLmluc3RhbGwodGhpcy5jdHguaG9zdCk7XG4gICAgdGhpcy5zdWJzY3JpYmVTcGF0aWFsKCk7XG4gIH1cblxuICAvKiogVGhlIG9ic2VydmF0aW9ucycgb3duIHogaXMgb24gc2NyZWVuOiB0aGVyZSBpcyBubyBwbGFuZSB0byBzdGVwLiAqL1xuICBzZXRaKCk6IHZvaWQge1xuICAgIC8qIG5vdGhpbmcgdG8gc3RlcCAqL1xuICB9XG5cbiAgLyoqIEEgY2xvdWQgaGFzIG5vIGludGVuc2l0eSBkaXN0cmlidXRpb24gZm9yIHRoZSBoaXN0b2dyYW0gcGFuZS4gKi9cbiAgaGlzdG9ncmFtKCk6IElIaXN0b2dyYW0gfCBudWxsIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmVyeSBvYnNlcnZhdGlvbidzIHBvc2l0aW9uIG9uIHRoZSBjYW52YXMgdW5kZXIgdGhlIGN1cnJlbnQgM0QgY2FtZXJhIChmb3IgdGhlIFJPSVxuICAgKiBzZWxlY3Rpb24pLCBpbmRleGVkIGJ5IG9ic2VydmF0aW9uIHdpdGggTmFOIGZvciBhbnl0aGluZyBub3QgZHJhd24uIE51bGwgYmVmb3JlIHRoZSBjbG91ZFxuICAgKiBpcyBidWlsdC5cbiAgICpcbiAgICogVGhlIHByb2plY3Rpb24gaXMgdGhlIHBpY2tlcidzIChzZWUge0BsaW5rIHBpY2tlcn0pOyB3aGF0IGlzIGxlZnQgaXMgdGhlIHBhcnQgdGhhdCBpc1xuICAgKiBnZW51aW5lbHkgdGhpcyBhZGFwdGVyJ3M6IFNDQVRURVJJTkcgdGhlIGRyYXduIHN1YnNldCBiYWNrIGludG8gb2JzZXJ2YXRpb24gb3JkZXIuIFRoZSBjbG91ZFxuICAgKiBob2xkcyBvbmx5IHRoZSBwb2ludHMgb2YgdGhlIGRpc3BsYXllZCBzZWN0aW9uLCBpbiBpdHMgb3duIHBhY2tpbmc7IGV2ZXJ5IGNvbnN1bWVyIGluZGV4ZXMgYnlcbiAgICogb2JzZXJ2YXRpb24uIE5hTiBzdGFuZHMgZm9yIFwibm90IG9uIHNjcmVlblwiLCB3aGljaCBpcyBhbHNvIHRoZSByaWdodCBhbnN3ZXIgZm9yIGFuXG4gICAqIG9ic2VydmF0aW9uIHdob3NlIHNlY3Rpb24gaXMgaGlkZGVuLlxuICAgKi9cbiAgc2NyZWVuUHJvamVjdGlvbihvYnM6IFNwYXRpYWxPYnNlcnZhdGlvbnMpOiBGbG9hdDMyQXJyYXkgfCBudWxsIHtcbiAgICBjb25zdCBwcm9qZWN0ZWQgPSB0aGlzLnBpY2tlcj8ucHJvamVjdGVkKCk7XG4gICAgaWYgKCFwcm9qZWN0ZWQpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IGRyYXduID0gdGhpcy5kcmF3bjtcbiAgICBjb25zdCB7IHNjcmVlbiB9ID0gcHJvamVjdGVkO1xuICAgIGNvbnN0IGNvdW50ID0gc2NyZWVuLmxlbmd0aCA+PiAxO1xuICAgIGNvbnN0IG91dCA9IG5ldyBGbG9hdDMyQXJyYXkob2JzLmNvdW50ICogMikuZmlsbChOYU4pO1xuICAgIGZvciAobGV0IGsgPSAwOyBrIDwgY291bnQ7IGsrKykge1xuICAgICAgY29uc3QgaSA9IGRyYXduID8gZHJhd25ba10gOiBrO1xuICAgICAgaWYgKGkgPj0gb2JzLmNvdW50KSBjb250aW51ZTtcbiAgICAgIG91dFtpICogMl0gPSBzY3JlZW5bayAqIDJdO1xuICAgICAgb3V0W2kgKiAyICsgMV0gPSBzY3JlZW5bayAqIDIgKyAxXTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwb3NlU3BhdGlhbCgpO1xuICAgIHRoaXMuaW52ZXJ0U3ViPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuaW52ZXJ0U3ViID0gbnVsbDtcbiAgICB0aGlzLmRlbnNpdHlMb2Fkcy5jYW5jZWwoKTtcbiAgICB0aGlzLmdlbmVNYXBMb2Fkcy5jYW5jZWwoKTtcbiAgICB0aGlzLnNjYWxlQmFyPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5zY2FsZUJhciA9IG51bGw7XG4gICAgLy8gRHJvcCB0aGUgY2FjaGVkIGludGVybGVhdmVkIGNvb3JkaW5hdGVzIHRvbzogaG9sZGluZyAzLjdNIHggMyBmbG9hdHMgYWZ0ZXJcbiAgICAvLyBhIHRlYXJkb3duIGlzIH40NU1CIG9mIHJldGFpbmVkIGhlYXAgZm9yIGEgc2NlbmUgdGhhdCBubyBsb25nZXIgZXhpc3RzLlxuICAgIHRoaXMucG9zaXRpb25zID0gbnVsbDtcbiAgICB0aGlzLnNldFBpY2tlcihudWxsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgb2JzZXJ2YXRpb24gdW5kZXIgYSBjbGllbnQgcG9zaXRpb246IHRoZSBGUk9OVC1tb3N0IG1hcmtlciB3aXRoaW4gYHNsYWNrUHhgIG9mIHRoZVxuICAgKiBwb2ludGVyICh0aWVzIGJ5IGRpc3RhbmNlKSwgYXMgbmFwYXJpLWpzJ3Mge0BsaW5rIFBvaW50UGlja2VyfSBwaWNrcyBpdC4gVGhhdCBtYXR0ZXJzIG1vcmVcbiAgICogdGhhbiBpdCBzb3VuZHM6IHRoZSByZW5kZXJlciBkZXB0aC10ZXN0cyB0aGUgYmlsbGJvYXJkcywgYW5kIGluIGEgMy43TS1wb2ludCBjbG91ZCB0aGUgY3Vyc29yXG4gICAqIGNvdmVycyBtYW55IG9mIHRoZW0g4oCUIHBpY2tpbmcgdGhlIG9uZSBuZWFyZXN0IHRoZSBjdXJzb3IncyBjZW50cmUgcmVndWxhcmx5IG5hbWVzIGEgY2VsbCB0aGF0XG4gICAqIHNvbWV0aGluZyBlbHNlIGlzIGRyYXduIG92ZXIuIFRoZSBwaWNrZXIgYWxzbyB0YWtlcyBlYWNoIHBvaW50J3MgcmFkaXVzIGZyb20gdGhlIGxheWVyJ3NcbiAgICogcGVyLXBvaW50IGBzaXplc2AsIHNvIGEgc2VsZWN0ZWQgbWFya2VyLCBkcmF3biBsYXJnZXIsIGlzIGFzIGxhcmdlIHRvIHRoZSBwb2ludGVyLlxuICAgKi9cbiAgcHJvdGVjdGVkIHBpY2tPYnNlcnZhdGlvbihjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlciwgc2xhY2tQeDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBjb25zdCBwaWNrZXIgPSB0aGlzLnBpY2tlcjtcbiAgICBpZiAoIXBpY2tlcikgcmV0dXJuIC0xO1xuICAgIGNvbnN0IHJlY3QgPSB0aGlzLmN0eC5jYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgayA9IHBpY2tlci5waWNrKGNsaWVudFggLSByZWN0LmxlZnQsIGNsaWVudFkgLSByZWN0LnRvcCwgc2xhY2tQeCk7XG4gICAgaWYgKGsgPCAwKSByZXR1cm4gLTE7XG4gICAgcmV0dXJuIHRoaXMuZHJhd24gPyB0aGlzLmRyYXduW2tdIDogaztcbiAgfVxuXG4gIC8qKiBSZXBsYWNlIHRoZSBjbG91ZCdzIHBpY2tlciAobnVsbDogbm8gY2xvdWQpLCByZWxlYXNpbmcgdGhlIG9sZCBvbmUncyBjYW1lcmEgbGlzdGVuZXIuICovXG4gIHByaXZhdGUgc2V0UGlja2VyKHBvaW50czogUG9pbnRzM0RMYXllciB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnBpY2tlcj8uZGlzcG9zZSgpO1xuICAgIHRoaXMucGlja2VyID0gcG9pbnRzXG4gICAgICA/IG5ldyBQb2ludFBpY2tlcih0aGlzLmN0eC52aWV3ZXIsIHBvaW50cywge1xuICAgICAgICAgIC8vIFRoZSBsYXJnZXN0IHJhZGl1cyBhIHBpY2sgaGVyZSBjYW4gY2xhaW06IHRoZSBob3ZlciBzbGFjayB0aW1lcyB0aGUgc2NhbGUgYSBTRUxFQ1RFRFxuICAgICAgICAgIC8vIG1hcmtlciBpcyBkcmF3biBhdC4gSXQgZGVjaWRlcyB3aGV0aGVyIGEgbWFya2VyIHN0cmFkZGxpbmcgdGhlIGNhbnZhcyBlZGdlIGlzIGZvdW5kLlxuICAgICAgICAgIG1heFJlYWNoOiBIT1ZFUl9SQURJVVNfUFggKiBTUEFUSUFMX1NFTEVDVEVEX1NJWkVfU0NBTEUsXG4gICAgICAgIH0pXG4gICAgICA6IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogU2NhbGUgYmFyIGZvciB0aGUgY2xvdWQsIG1lYXN1cmVkIGF0IHRoZSBPUkJJVCBQSVZPVC5cbiAgICpcbiAgICogQSBwZXJzcGVjdGl2ZSBjYW1lcmEgaGFzIG5vIHNpbmdsZSBzY2FsZSDigJQgdGhpbmdzIGZhcnRoZXIgYXdheSBhcmUgc21hbGxlciDigJQgc28gYSBiYXIgY2FuXG4gICAqIG9ubHkgYmUgdHJ1ZSBhdCBvbmUgZGVwdGguIFRoZSBwaXZvdCBpcyB0aGUgaG9uZXN0IGNob2ljZTogaXQgaXMgd2hhdCB0aGUgY2FtZXJhIGlzIGZyYW1pbmcsXG4gICAqIHdoYXQgYSB6b29tIG1vdmVzIHRvd2FyZHMsIGFuZCB3aGVyZSB0aGUgZXllIGlzIGFueXdheS4gbmFwYXJpJ3Mgb3duIDNEIHNjYWxlIGJhciB3b3JrcyB0aGVcbiAgICogc2FtZSB3YXkuXG4gICAqXG4gICAqIG5hcGFyaS1qcydzIGBTY2FsZUJhck92ZXJsYXlgIGluIGAnM2QnYCBtb2RlIG1lYXN1cmVzIHRoZXJlOiBDU1MgcHggcGVyIHdvcmxkIHVuaXQgaXMgdGhlXG4gICAqIHJlY2lwcm9jYWwgb2YgYENhbWVyYTNELndvcmxkUGVyUGl4ZWxgIOKAlCB0aGUgc2NhbGUgYENhbWVyYTNELnBhbmAgdXNlcyB0byB0cmFjayB0aGUgY3Vyc29yLlxuICAgKiBUaGUgYmFyIHRoZW4gY29udmVydHMgdGhyb3VnaCBgbWljcm9uc1BlclVuaXRgLCBhbmQgZHJhd3Mgbm90aGluZyBhdCBhbGwgd2hlbiB0aGUgZGF0YXNldCBkb2VzXG4gICAqIG5vdCBkZWNsYXJlIG9uZSwgYmVjYXVzZSBhIGJhciBsYWJlbGxlZCBpbiBtaWNyb25zIG92ZXIgdW5rbm93biB1bml0cyB3b3VsZCByZWFkIGFzIGFcbiAgICogbWVhc3VyZW1lbnQuXG4gICAqL1xuICBwcml2YXRlIGluc3RhbGxTY2FsZUJhcihkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnNjYWxlQmFyPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5zY2FsZUJhciA9IG51bGw7XG4gICAgY29uc3QgbWljcm9uc1BlclVuaXQgPSBkYXRhc2V0Py5taWNyb25zUGVyVW5pdDtcbiAgICBpZiAoIW1pY3JvbnNQZXJVbml0IHx8IG1pY3JvbnNQZXJVbml0IDw9IDApIHJldHVybjtcbiAgICB0aGlzLnNjYWxlQmFyID0gbmV3IFNjYWxlQmFyT3ZlcmxheSh0aGlzLmN0eC5ob3N0LCB0aGlzLmN0eC52aWV3ZXIsIHtcbiAgICAgIHVuaXRQZXJXb3JsZDogbWljcm9uc1BlclVuaXQsXG4gICAgICBtb2RlOiAnM2QnLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIChSZSlidWlsZCB0aGUgM0QgcG9pbnQgY2xvdWQgZm9yIHRoZSBjdXJyZW50IGRhdGFzZXQgKyB2aWV3IHN0YXRlLiAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcmVidWlsZChcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCB8IG51bGwsXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrID0gZW1wdHlTZWxlY3Rpb24oKSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgdmlld2VyID0gdGhpcy5jdHgudmlld2VyO1xuICAgIGNvbnN0IHRhc2sgPSB0aGlzLnJlYnVpbGRzLm5leHQoKTtcblxuICAgIC8vIFJlc29sdmUgdGhlIHNjYWxhciBlbmNvZGluZyBCRUZPUkUgdG91Y2hpbmcgdGhlIHNjZW5lLCBmb3IgdGhlIHNhbWUgcmVhc29uXG4gICAgLy8gdGhlIDJEIHBhdGggZG9lczogYSBnZW5lIGZldGNoIGNhbiBmYWlsIG9yIGJlIHN1cGVyc2VkZWQsIGFuZCBkcm9wcGluZyB0aGVcbiAgICAvLyBsYXllciBmaXJzdCB3b3VsZCBibGFuayB0aGUgdmlldy5cbiAgICBsZXQgZW5jOiBTcGF0aWFsM2RFbmNvZGluZyB8IG51bGwgPSBudWxsO1xuICAgIGlmIChkYXRhc2V0KSB7XG4gICAgICBjb25zdCBlbmRMb2FkaW5nID0gdGhpcy5jdHguYmFkZ2UuYmVnaW4oJ09ic2VydmF0aW9ucycpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgZW5jID0gYXdhaXQgdGhpcy5zY2FsYXJFbmNvZGluZyh2aWV3KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHNwYXRpYWwgM0QgY29sb3VyaW5nIGZhaWxlZCDigJQgZmFsbGluZyBiYWNrIHRvIGEgZmxhdCBjb2xvdXInLCBlcnIpO1xuICAgICAgICBlbmMgPSBudWxsO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgZW5kTG9hZGluZygpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIXRhc2soKSkgcmV0dXJuO1xuXG4gICAgY29uc3Qgb2JzID0gZGF0YXNldD8ub2JzZXJ2YXRpb25zO1xuICAgIC8vIE5vIHogbWVhbnMgbm90aGluZyB0byBkcmF3IGluIDNELiBUaGUgcGxvdCB0eXBlIGlzIGdhdGVkIG9uIGByZXF1aXJlc1NwYXRpYWwzZGBcbiAgICAvLyBzbyB0aGlzIHNob3VsZCBiZSB1bnJlYWNoYWJsZSBmcm9tIHRoZSBVSSwgYnV0IGEgaG9zdCBjYW4gc2V0IHRoZSB0eXBlIGRpcmVjdGx5LlxuICAgIGlmICghZGF0YXNldCB8fCAhb2JzIHx8IG9icy5jb3VudCA9PT0gMCB8fCAhb2JzLnopIHtcbiAgICAgIHRoaXMucmVtb3ZlTGF5ZXJzKHZpZXdlcik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQW5hdG9teSBmaXJzdDogb24gYSBzY2VuZSdzIEZJUlNUIGxheWVyIG5hcGFyaSBmcmFtZXMgdGhlIG9yYml0IGNhbWVyYSwgYW5kXG4gICAgLy8gdGhlIHJlZmVyZW5jZSB2b2x1bWUgaXMgdGhlIGZyYW1pbmcgd2Ugd2FudCDigJQgdGhlIGJyYWluLCBub3QgdGhlIG91dGVybW9zdFxuICAgIC8vIHN0cmF5IHNlZ21lbnRhdGlvbi4gRXZlcnkgbGF0ZXIgYWRkIGtlZXBzIHRoZSBwb3NlIGluc3RlYWQgKG5hcGFyaS1qcyBgZml0M2Q6ICdvbmNlJ2ApLlxuICAgIGF3YWl0IHRoaXMuZW5zdXJlVm9sdW1lKHZpZXdlciwgZGF0YXNldCwgdmlldyk7XG4gICAgaWYgKCF0YXNrKCkpIHJldHVybjtcbiAgICAvLyBUaGVuIHRoZSBjbHVzdGVyIGRlbnNpdHkgdm9sdW1lcywgd2hpY2ggY2FuIHNldCB0aGUgY2VudHJpbmcgb2Zmc2V0IHdoZW5cbiAgICAvLyB0aGVyZSBpcyBubyByZWZlcmVuY2Ugdm9sdW1lIOKAlCBzbyBiZWZvcmUgYW55IHBvc2l0aW9uIGlzIGNvbXB1dGVkIGZyb20gaXQuXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVEZW5zaXR5Vm9sdW1lcyh2aWV3ZXIsIGRhdGFzZXQsIHZpZXcsIHNlbGVjdGlvbik7XG4gICAgaWYgKCF0YXNrKCkpIHJldHVybjtcbiAgICAvLyBUaGVuIHRoZSBnZW5lIG1hcCwgd2hpY2ggc2hhcmVzIHRoZSByZWZlcmVuY2Ugdm9sdW1lJ3MgbGF0dGljZSDigJQgc28gaXQgZ29lc1xuICAgIC8vIGFmdGVyIGFueXRoaW5nIHRoYXQgY2FuIHN0aWxsIG1vdmUgdGhlIGNlbnRyaW5nIG9mZnNldC5cbiAgICBhd2FpdCB0aGlzLmVuc3VyZUdlbmVNYXAodmlld2VyLCBkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb24pO1xuICAgIGlmICghdGFzaygpKSByZXR1cm47XG4gICAgLy8gU2NhbGUgZGVwZW5kcyBvbiB0aGUgZGF0YXNldCdzIGRlY2xhcmVkIHVuaXQsIHNvIGl0IHdhaXRzIGZvciB0aGUgZGF0YXNldFxuICAgIC8vIHJhdGhlciB0aGFuIGJlaW5nIHNldCB1cCBhdCBtb3VudCB0aW1lLlxuICAgIGlmIChkYXRhc2V0LmlkICE9PSB0aGlzLnNjYWxlQmFyS2V5KSB7XG4gICAgICB0aGlzLnNjYWxlQmFyS2V5ID0gZGF0YXNldC5pZDtcbiAgICAgIHRoaXMuaW5zdGFsbFNjYWxlQmFyKGRhdGFzZXQpO1xuICAgIH1cblxuICAgIC8vIFRoZSByZWZlcmVuY2Ugdm9sdW1lIGlzIGhpZGRlbiwgbm90IHJlbW92ZWQ6IGl0IGFsc28gZml4ZXMgdGhlIGNlbnRyaW5nXG4gICAgLy8gb2Zmc2V0IGV2ZXJ5IHBvc2l0aW9uIGlzIGNvbXB1dGVkIGZyb20sIGFuZCByZS1mZXRjaGluZyBhIDEwMCBNQiB0ZW1wbGF0ZVxuICAgIC8vIHRvIHVuLWhpZGUgaXQgd291bGQgbWFrZSBhIGNoZWNrYm94IGZlZWwgbGlrZSBhIGxvYWQuXG4gICAgaWYgKHRoaXMudm9sdW1lKSB7XG4gICAgICB0aGlzLnZvbHVtZS52aXNpYmxlID0gdmlldy5zaG93Vm9sdW1lO1xuICAgICAgdGhpcy52b2x1bWUub3BhY2l0eSA9IHZpZXcudm9sdW1lT3BhY2l0eTtcbiAgICB9XG4gICAgdGhpcy5kcmF3Q2xvdWQodmlld2VyLCBkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb24sIGVuYyk7XG4gIH1cblxuICAvKipcbiAgICogRHJhdyB0aGUgcG9pbnQgY2xvdWQ6IGEgbmV3IGxheWVyIGZvciBuZXcgZ2VvbWV0cnkgKGEgZGF0YXNldCBvciBhIHNlY3Rpb24pLCB0aGUgY29sb3VyXG4gICAqIHNvdXJjZSBzd2FwcGVkIGluIHBsYWNlIG90aGVyd2lzZTsgdGhlbiB0aGUgc2VsZWN0aW9uIGFuZCB0aGUgdmlzaWJpbGl0eS5cbiAgICovXG4gIHByaXZhdGUgZHJhd0Nsb3VkKFxuICAgIHZpZXdlcjogVmlld2VyLFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgICBlbmM6IFNwYXRpYWwzZEVuY29kaW5nIHwgbnVsbCxcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgb2JzID0gZGF0YXNldC5vYnNlcnZhdGlvbnM7XG4gICAgY29uc3Qgc2NhbGUgPSB2aWV3LnBvaW50U2NhbGUgPiAwID8gdmlldy5wb2ludFNjYWxlIDogMTtcbiAgICBjb25zdCBzaXplID0gU1BBVElBTF8zRF9CQVNFX1NJWkUgKiBzY2FsZTtcbiAgICAvLyBBIGNhdGVnb3JpY2FsIGNvbG91cmluZyBpcyBwZXItcG9pbnQgUkdCQSwgd2hpY2ggd2lucyBvdmVyIHRoZSBzY2FsYXJzOyB0aGUgZmxhdCBjb2xvcm1hcFxuICAgIC8vIGFuZCB6ZXJvIHNjYWxhcnMgc3RhbmQgYmVoaW5kIGl0LCBhcyB0aGV5IGRvIGZvciBcIm5vdGhpbmcgdG8gY29sb3VyIGJ5XCIuXG4gICAgY29uc3Qgc2NhbGFyID0gZW5jPy5raW5kID09PSAnc2NhbGFycycgPyBlbmMgOiBudWxsO1xuICAgIGNvbnN0IGNvbG9ycyA9IGVuYz8ua2luZCA9PT0gJ2NvbG9ycycgPyBlbmMuY29sb3JzIDogbnVsbDtcbiAgICBjb25zdCBzY2FsYXJzID0gc2NhbGFyPy52YWx1ZXMgPz8gbmV3IEZsb2F0MzJBcnJheShvYnMuY291bnQpO1xuICAgIGNvbnN0IGNvbG9ybWFwID0gc2NhbGFyPy5jb2xvcm1hcCA/PyBzcGF0aWFsRmxhdENvbG9ybWFwKCk7XG4gICAgY29uc3QgY29udHJhc3RMaW1pdHM6IFtudW1iZXIsIG51bWJlcl0gPSBzY2FsYXI/LmNvbnRyYXN0TGltaXRzID8/IFswLCAxXTtcbiAgICBjb25zdCB7IHNob3duLCBrZXksIHNjYWxhcktleSB9ID0gY2xvdWRTdWJzZXQoZGF0YXNldCwgdmlldyk7XG5cbiAgICBpZiAoa2V5ICE9PSB0aGlzLmxheWVyS2V5KSB7XG4gICAgICAvLyBOZXcgZ2VvbWV0cnk6IGludGVybGVhdmUgeCx5LHogKHRoZSBsYXllcidzIGRvY3VtZW50ZWQgbGF5b3V0LCB4LWZhc3Rlc3QpXG4gICAgICAvLyBhbmQgY2FjaGUgaXQsIHNvIGxhdGVyIGNvbG91ciBjaGFuZ2VzIHJlYnVpbGQgdGhlIGxheWVyIHdpdGhvdXQgd2Fsa2luZ1xuICAgICAgLy8gdGhlIG9ic2VydmF0aW9ucyBhZ2Fpbi5cbiAgICAgIHRoaXMucG9zaXRpb25zID0gdGhpcy5jbG91ZFBvc2l0aW9ucyhvYnMsIHNob3duKTtcbiAgICAgIHRoaXMuZHJhd24gPSBzaG93bjtcbiAgICB9XG5cbiAgICAvLyBUaGUgc2NhbGFycyBoYXZlIHRvIGZvbGxvdyB0aGUgZ2VvbWV0cnk6IGEgcGVyLW9ic2VydmF0aW9uIHZlY3RvciBhZ2FpbnN0IG9uZVxuICAgIC8vIHNlY3Rpb24ncyBwb3NpdGlvbnMgd291bGQgY29sb3VyIGVhY2ggY2VsbCBieSBhIHN0cmFuZ2VyJ3MgdmFsdWUuIFNvIGRvIHRoZSBjb2xvdXJzLlxuICAgIGNvbnN0IHZhbHVlc0ZvciA9ICgpID0+IChzaG93biA/IEZsb2F0MzJBcnJheS5mcm9tKHNob3duLCAoaSkgPT4gc2NhbGFyc1tpXSkgOiBzY2FsYXJzKTtcbiAgICBjb25zdCBjb2xvcnNGb3IgPSAoKSA9PiAoY29sb3JzID8gKGdhdGhlckNvbG9ycyhjb2xvcnMsIHNob3duID8/IHVuZGVmaW5lZCkgYXMgRmxvYXQzMkFycmF5KSA6IG51bGwpO1xuXG4gICAgaWYgKCF0aGlzLnBvaW50cyB8fCBrZXkgIT09IHRoaXMubGF5ZXJLZXkpIHtcbiAgICAgIC8vIE5ldyBHRU9NRVRSWSDigJQgYSBkaWZmZXJlbnQgZGF0YXNldCwgb3IgYSBkaWZmZXJlbnQgc2VjdGlvbiDigJQgc28gYSBuZXcgbGF5ZXIuXG4gICAgICBpZiAodGhpcy5wb2ludHMpIHZpZXdlci5sYXllcnMucmVtb3ZlKHRoaXMucG9pbnRzKTtcbiAgICAgIHRoaXMubGF5ZXJLZXkgPSBrZXk7XG4gICAgICB0aGlzLnNjYWxhcktleSA9IHNjYWxhcktleTtcbiAgICAgIHRoaXMucG9pbnRzID0gdmlld2VyLmFkZFBvaW50czNEKHRoaXMucG9zaXRpb25zISwgdmFsdWVzRm9yKCksIHtcbiAgICAgICAgbmFtZTogJ29ic2VydmF0aW9ucycsXG4gICAgICAgIGNvbG9ybWFwLFxuICAgICAgICBjb250cmFzdExpbWl0cyxcbiAgICAgICAgc2l6ZSxcbiAgICAgICAgY29sb3JzOiBjb2xvcnNGb3IoKSA/PyB1bmRlZmluZWQsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuc2V0UGlja2VyKHRoaXMucG9pbnRzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHNjYWxhcktleSAhPT0gdGhpcy5zY2FsYXJLZXkpIHtcbiAgICAgICAgLy8gQSBjaGFuZ2Ugb2YgY29sb3VyIFNPVVJDRSwgd2hpY2ggdXNlZCB0byBtZWFuIGRpc2NhcmRpbmcgdGhlIGxheWVyIGFuZCBidWlsZGluZ1xuICAgICAgICAvLyBhbm90aGVyIOKAlCBhbmQsIGJlY2F1c2UgYWRkaW5nIGEgM0QgbGF5ZXIgcmVmcmFtZXMsIGEgY2FtZXJhIGp1bXAgdG8gdW5kbyBhcyB3ZWxsLlxuICAgICAgICAvLyBuYXBhcmktanMg4omlIDAuMTQgbGV0cyB0aGUgc2NhbGFycyBiZSByZXBsYWNlZCBpbiBwbGFjZSDigJQgdGhlIHNldHRlciBidW1wcyB0aGVcbiAgICAgICAgLy8gbGF5ZXIncyBkYXRhVmVyc2lvbiBzbyB0aGUgdmlzdWFsIHJlLXVwbG9hZHMg4oCUIGFuZCB0aGUgcG9zaXRpb25zIGhhdmUgbm90IG1vdmVkLFxuICAgICAgICAvLyBzbyB0aGVyZSBpcyBub3RoaW5nIGZvciB0aGUgY2FtZXJhIHRvIHJlZnJhbWUuXG4gICAgICAgIHRoaXMuc2NhbGFyS2V5ID0gc2NhbGFyS2V5O1xuICAgICAgICB0aGlzLnBvaW50cy52YWx1ZXMgPSB2YWx1ZXNGb3IoKTtcbiAgICAgICAgdGhpcy5wb2ludHMuY29sb3JzID0gY29sb3JzRm9yKCk7XG4gICAgICB9XG4gICAgICB0aGlzLnBvaW50cy5jb2xvcm1hcCA9IGNvbG9ybWFwO1xuICAgICAgdGhpcy5wb2ludHMuY29udHJhc3RMaW1pdHMgPSBjb250cmFzdExpbWl0cztcbiAgICAgIHRoaXMucG9pbnRzLnNpemUgPSBzaXplO1xuICAgIH1cblxuICAgIGNvbnN0IGNsb3VkID0gdGhpcy5wb2ludHM7XG4gICAgaWYgKGNsb3VkKSB7XG4gICAgICBjbG91ZC5vcGFjaXR5ID0gdmlldy5vcGFjaXR5O1xuICAgICAgdGhpcy5hcHBseVNlbGVjdGlvbihjbG91ZCwgc2VsZWN0aW9uLCBzaG93biwgb2JzLmNvdW50KTtcbiAgICB9XG4gICAgLy8gTGFzdCwgc28gaXQgYWxzbyBjb3ZlcnMgYSBsYXllciB0aGlzIHBhc3MganVzdCBjcmVhdGVkLlxuICAgIGlmICh0aGlzLnBvaW50cykgdGhpcy5wb2ludHMudmlzaWJsZSA9IHZpZXcuc2hvd1BvaW50cztcbiAgICB2aWV3ZXIucmVxdWVzdFJlbmRlcigpO1xuICB9XG5cbiAgLyoqIEludGVybGVhdmVkIHgseSx6IG9mIHRoZSBgc2hvd25gIG9ic2VydmF0aW9ucyAobnVsbDogYWxsIG9mIHRoZW0pLCBvZmZzZXQgYnkge0BsaW5rIG9yaWdpbn0uICovXG4gIHByaXZhdGUgY2xvdWRQb3NpdGlvbnMob2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zLCBzaG93bjogVWludDMyQXJyYXkgfCBudWxsKTogRmxvYXQzMkFycmF5IHtcbiAgICAvLyByZWJ1aWxkKCkgZHJhd3Mgb25seSBhIGRhdGFzZXQgd2hvc2Ugb2JzZXJ2YXRpb25zIGhhdmUgYSB6LlxuICAgIGNvbnN0IHogPSBvYnMueiE7XG4gICAgY29uc3QgW294LCBveSwgb3pdID0gdGhpcy5vcmlnaW47XG4gICAgY29uc3QgY291bnQgPSBzaG93biA/IHNob3duLmxlbmd0aCA6IG9icy5jb3VudDtcbiAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KGNvdW50ICogMyk7XG4gICAgZm9yIChsZXQgayA9IDA7IGsgPCBjb3VudDsgaysrKSB7XG4gICAgICBjb25zdCBpID0gc2hvd24gPyBzaG93bltrXSA6IGs7XG4gICAgICBwb3NpdGlvbnNbayAqIDNdID0gb2JzLnhbaV0gKyBveDtcbiAgICAgIHBvc2l0aW9uc1trICogMyArIDFdID0gb2JzLnlbaV0gKyBveTtcbiAgICAgIHBvc2l0aW9uc1trICogMyArIDJdID0geltpXSArIG96O1xuICAgIH1cbiAgICByZXR1cm4gcG9zaXRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbGVjdGlvbiBpcyBhIFBFUi1QT0lOVCBhbHBoYSwgaW4gdGhlIG9uZSBsYXllci5cbiAgICpcbiAgICogSXQgdXNlZCB0byBiZSBhIHNlY29uZCBsYXllcjogd2l0aCBhIHNpbmdsZSBvcGFjaXR5IGZvciB0aGUgd2hvbGUgY2xvdWQsIHRoZSBvbmx5IHdheVxuICAgKiB0byBoaWdobGlnaHQgYSBzdWJzZXQgd2FzIHRvIGRyYXcgaXQgYWdhaW4gb24gdG9wIGF0IGZ1bGwgb3BhY2l0eSB3aGlsZSB0aGUgcGFyZW50XG4gICAqIGRyb3BwZWQgdG8gdGhlIG11dGVkIGxldmVsLiBUaGF0IHNlY29uZCBsYXllciBoYWQgdG8gYmUga2VwdCBpbiBzdGVwIHRocm91Z2ggZXZlcnlcbiAgICogY29sb3JtYXAsIHdpbmRvdyBhbmQgc2l6ZSBjaGFuZ2UsIGFuZCB0aGUgdHdvIHRoZW4gZGVwdGgtc29ydGVkIGFnYWluc3QgZWFjaCBvdGhlciBhc1xuICAgKiBzZXBhcmF0ZSBkcmF3cy4gUGVyLXBvaW50IGFscGhhcyBhbmQgc2l6ZXMgZ2l2ZSB0aGUgc2FtZSByZWFkaW5nIOKAlCBtdXRlZCBjbG91ZCwgYnJpZ2h0XG4gICAqIHNlbGVjdGlvbiwgc2xpZ2h0bHkgbGFyZ2VyIHNvIGEgc21hbGwgb25lIGlzIGZpbmRhYmxlIGluc2lkZSAzLjdNIHBvaW50cyDigJQgaW4gb25lLlxuICAgKlxuICAgKiBgc2hvd25gIGlzIHRoZSBkcmF3biBzdWJzZXQgKG51bGw6IGV2ZXJ5IG9uZSBvZiB0aGUgYHRvdGFsYCBvYnNlcnZhdGlvbnMpLCBzbyB0aGUgYWxwaGFzXG4gICAqIGZvbGxvdyB0aGUgZHJhd24gb3JkZXIuXG4gICAqL1xuICBwcml2YXRlIGFwcGx5U2VsZWN0aW9uKFxuICAgIGNsb3VkOiBQb2ludHMzRExheWVyLFxuICAgIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2ssXG4gICAgc2hvd246IFVpbnQzMkFycmF5IHwgbnVsbCxcbiAgICB0b3RhbDogbnVtYmVyLFxuICApOiB2b2lkIHtcbiAgICBpZiAoc2VsZWN0aW9uLmNvdW50ID09PSAwIHx8IHNlbGVjdGlvbi5tYXNrLmxlbmd0aCAhPT0gdG90YWwpIHtcbiAgICAgIGNsb3VkLmFscGhhcyA9IG51bGw7XG4gICAgICBjbG91ZC5zaXplcyA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHNob3duQ291bnQgPSBzaG93biA/IHNob3duLmxlbmd0aCA6IHRvdGFsO1xuICAgIGNvbnN0IGFscGhhcyA9IG5ldyBGbG9hdDMyQXJyYXkoc2hvd25Db3VudCk7XG4gICAgY29uc3Qgc2l6ZXMgPSBuZXcgRmxvYXQzMkFycmF5KHNob3duQ291bnQpO1xuICAgIGZvciAobGV0IGsgPSAwOyBrIDwgc2hvd25Db3VudDsgaysrKSB7XG4gICAgICBjb25zdCBpID0gc2hvd24gPyBzaG93bltrXSA6IGs7XG4gICAgICBjb25zdCBwaWNrZWQgPSAhIXNlbGVjdGlvbi5tYXNrW2ldO1xuICAgICAgYWxwaGFzW2tdID0gcGlja2VkID8gMSA6IERFRkFVTFRfTVVURURfT1BBQ0lUWTtcbiAgICAgIHNpemVzW2tdID0gcGlja2VkID8gU1BBVElBTF9TRUxFQ1RFRF9TSVpFX1NDQUxFIDogMTtcbiAgICB9XG4gICAgY2xvdWQuYWxwaGFzID0gYWxwaGFzO1xuICAgIGNsb3VkLnNpemVzID0gc2l6ZXM7XG4gIH1cblxuICAvKipcbiAgICogVGhlICoqM0QgZ2VuZSBtYXAqKjogdGhlIGFjdGl2ZSBnZW5lJ3MgZXhwcmVzc2lvbiBvdmVyIHRoZSB3aG9sZSBzZWN0aW9uZWRcbiAgICogc3BlY2ltZW4sIGFzIG9uZSByYXltYXJjaGVkIHZvbHVtZS5cbiAgICpcbiAgICogVHdvIHRoaW5ncyBpdCBjYW4gYmUsIGFuZCB0aGUgcGFuZWwncyBgVm9sdW1lIHJlbmRlcmluZ2AgdG9nZ2xlIHBpY2tzIHdoaWNoOlxuICAgKlxuICAgKiAgLSAqKnNoZWV0cyoqIOKAlCBleGFjdGx5IHRoZSBwbGFuZXMgdGhhdCB3ZXJlIGltYWdlZCwgZWFjaCBjYXJyeWluZyB0aGF0XG4gICAqICAgIHNsaWRlJ3Mgb3duIDJEIGdlbmUgbWFwLCB3aXRoIHRoZSBnYXBzIGJldHdlZW4gc2VjdGlvbnMgZW1wdHkuIEEgc3RhY2sgb2ZcbiAgICogICAgbWVhc3VyZWQgZmllbGRzLCBhdCB0aGVpciB0cnVlIHouXG4gICAqICAtICoqdm9sdW1lKiog4oCUIHRoZSBzYW1lIGZpZWxkcyBzbW9vdGhlZCBhbG9uZyB6LCBzbyB0aGUgcGxhbmVzIGJldHdlZW4gdGhlXG4gICAqICAgIHNlY3Rpb25zIGNhcnJ5IGFuIGludGVycG9sYXRlZCB2YWx1ZS4gQW4gZXN0aW1hdGUsIGFuZCBkcmF3biBhcyBhXG4gICAqICAgIHRyYW5zbHVjZW50IGNsb3VkIGZvciB0aGUgc2FtZSByZWFzb24gdGhlIGRlbnNpdHkgdm9sdW1lcyBhcmUuXG4gICAqXG4gICAqIE9uZSBgVm9sdW1lTGF5ZXJgIHJhdGhlciB0aGFuIGEgdGV4dHVyZWQgcXVhZCBwZXIgc2VjdGlvbjogYW4gYEltYWdlTGF5ZXJgXG4gICAqIHJlbmRlcnMgb25seSBhdCBgbmRpc3BsYXkgPT09IDJgLCBzbyA1MyBzaGVldHMgaW4gdGhlIG9yYml0IHZpZXcgd291bGQgbmVlZCBhXG4gICAqIG5ldyBsYXllciB0eXBlIHVwc3RyZWFtIOKAlCB3aGlsZSBhIHNjYWxhciB2b2x1bWUgd2hvc2UgeiBzYW1wbGluZyBhbHJlYWR5IElTXG4gICAqIHRoZSBzZWN0aW9uIHNwYWNpbmcgZXhwcmVzc2VzIHRoZSBzaGVldHMgZXhhY3RseSwgYW5kIHRoZSBzYW1lIGxhdHRpY2UgdGhlblxuICAgKiBnaXZlcyB0aGUgaW50ZXJwb2xhdGVkIHZlcnNpb24gZm9yIGZyZWUuXG4gICAqXG4gICAqIEVzdGltYXRlZCBvbiB0aGUgcmVmZXJlbmNlIHZvbHVtZSdzIG93biBsYXR0aWNlIChgZGVuc2l0eUdyaWRgIGF0IHN0cmlkZSAxKSxcbiAgICogc28gdGhlIGZpZWxkIGxhbmRzIHZveGVsLWZvci12b3hlbCBvbiB0aGUgYW5hdG9teSBhbmQgbmVlZHMgbm8gb2Zmc2V0IOKAlCBhXG4gICAqIGBWb2x1bWVMYXllcmAgaGFzIG5vIHRyYW5zbGF0ZSwgYW5kIG5hcGFyaSBjZW50cmVzIGJvdGggYm94ZXMgb24gdGhlIHdvcmxkXG4gICAqIG9yaWdpbi5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlR2VuZU1hcChcbiAgICB2aWV3ZXI6IFZpZXdlcixcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICAgIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2ssXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGdlbmUgPSB2aWV3LmdlbmVNYXAgJiYgdmlldy5jb2xvckJ5Py5raW5kID09PSAnZmVhdHVyZScgPyB2aWV3LmNvbG9yQnkubmFtZSA6IG51bGw7XG4gICAgY29uc3QgcG9ydCA9IHRoaXMuc2Vzc2lvbi5wb3J0O1xuICAgIGNvbnN0IGNhY2hlID0gdGhpcy5zZXNzaW9uLmdlbmVNYXBWb2x1bWU7XG4gICAgY29uc3Qgc21vb3RoaW5nID0gdmlldy5nZW5lTWFwU21vb3RoaW5nID4gMCA/IHZpZXcuZ2VuZU1hcFNtb290aGluZyA6IDE7XG4gICAgY29uc3QgY2xpcCA9IHZpZXcucGVyY2VudGlsZUNsaXAgPz8gWzAuMDEsIDAuOTldO1xuICAgIGNvbnN0IG9icyA9IGRhdGFzZXQub2JzZXJ2YXRpb25zO1xuICAgIC8vIEEgdm9sdW1lIGJ1aWx0IGZyb20gT05FIHNlY3Rpb24gd291bGQgc21lYXIgdGhhdCBzbGlkZSB0aHJvdWdoIHRoZSB3aG9sZVxuICAgIC8vIGRlcHRoLCBzbyB0aGUgc2VjdGlvbiByZXN0cmljdGlvbiBvbmx5IGFwcGxpZXMgdG8gdGhlIHNoZWV0cy5cbiAgICBjb25zdCBpbnRlcnBvbGF0ZSA9ICEhdmlldy5nZW5lTWFwVm9sdW1lO1xuICAgIGNvbnN0IHNlY3Rpb25zID0gc2VjdGlvbnNPZihvYnMpO1xuICAgIGNvbnN0IHNlY3Rpb24gPVxuICAgICAgIWludGVycG9sYXRlICYmIHZpZXcuZ2VuZU1hcFNlY3Rpb24gIT0gbnVsbCAmJiBzZWN0aW9ucyAmJiBzZWN0aW9ucy5sZW5ndGggPiAwXG4gICAgICAgID8gc2VjdGlvbnNbTWF0aC5tYXgoMCwgTWF0aC5taW4oc2VjdGlvbnMubGVuZ3RoIC0gMSwgdmlldy5nZW5lTWFwU2VjdGlvbikpXVxuICAgICAgICA6IG51bGw7XG5cbiAgICBjb25zdCBmaWVsZEtleSA9IGdlbmVcbiAgICAgID8gW1xuICAgICAgICAgIGRhdGFzZXQuaWQsXG4gICAgICAgICAgZ2VuZSxcbiAgICAgICAgICBzbW9vdGhpbmcsXG4gICAgICAgICAgc2VjdGlvbiA/PyAnYWxsJyxcbiAgICAgICAgICBpbnRlcnBvbGF0ZSA/ICd2b2wnIDogJ3NoZWV0cycsXG4gICAgICAgICAgdGhpcy5zZXNzaW9uLnNlbGVjdGlvblJldihzZWxlY3Rpb24pLFxuICAgICAgICBdLmpvaW4oJ3wnKVxuICAgICAgOiBudWxsO1xuICAgIGNvbnN0IGtleSA9IGZpZWxkS2V5XG4gICAgICA/IFtcbiAgICAgICAgICBmaWVsZEtleSxcbiAgICAgICAgICBjbGlwLmpvaW4oJywnKSxcbiAgICAgICAgICB2aWV3LmxvZ1NjYWxlID8gJ2xvZycgOiAnbGluJyxcbiAgICAgICAgICB2aWV3LmdlbmVNYXBPcGFjaXR5LFxuICAgICAgICAgIHRoaXMuY3R4LmRpc3BsYXkuY29udGludW91c0NvbG9ybWFwS2V5KHZpZXcpLFxuICAgICAgICBdLmpvaW4oJ3wnKVxuICAgICAgOiBudWxsO1xuICAgIGlmIChrZXkgPT09IHRoaXMuZ2VuZU1hcEtleSkgcmV0dXJuO1xuXG4gICAgaWYgKHRoaXMuZ2VuZU1hcExheWVyKSB7XG4gICAgICB2aWV3ZXIubGF5ZXJzLnJlbW92ZSh0aGlzLmdlbmVNYXBMYXllcik7XG4gICAgICB0aGlzLmdlbmVNYXBMYXllciA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuZ2VuZU1hcEtleSA9IGtleTtcbiAgICBpZiAoIWtleSB8fCAhZ2VuZSB8fCAhcG9ydCkge1xuICAgICAgY2FjaGUuZmllbGQgPSBudWxsO1xuICAgICAgY2FjaGUua2V5ID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDb2Fyc2VuZWQgaW4tcGxhbmUgYnV0IE5PVCBhbG9uZyB6OiB0aGUgc2hlZXRzIG5lZWQgb25lIHBsYW5lIHBlciBpbWFnZWRcbiAgICAvLyBzZWN0aW9uLCB3aGlsZSB0aGUgZmllbGQgdGhleSBjYXJyeSBpcyBzbW9vdGggYnkgY29uc3RydWN0aW9uIGFuZCBnYWluc1xuICAgIC8vIG5vdGhpbmcgZnJvbSB0aGUgdGVtcGxhdGUncyA0MCDCtW0gZGV0YWlsLiBBdCBmdWxsIHJlc29sdXRpb24gdGhlIGVzdGltYXRlIGlzXG4gICAgLy8gYSA1LjdNLXZveGVsIHBhaXIgb2YgYmx1cnMg4oCUIHNlY29uZHMgb2Ygd29yayBmb3IgYSBjaGVja2JveDsgYW4gZWlnaHRoIG9mIHRoZVxuICAgIC8vIHZveGVscyBpcyBhbiBlaWdodGggb2YgdGhlIHdvcmsuXG4gICAgY29uc3QgZ3JpZCA9IGRlbnNpdHlHcmlkKGRhdGFzZXQsIEdFTkVfTUFQX1ZPTFVNRV9TVFJJREUsIDEyOCwgMSk7XG4gICAgaWYgKCFncmlkKSByZXR1cm47XG5cbiAgICBpZiAoZmllbGRLZXkgIT09IGNhY2hlLmtleSkge1xuICAgICAgY29uc3QgbG9hZCA9IHRoaXMuZ2VuZU1hcExvYWRzLm5leHQoKTtcbiAgICAgIGxldCB2YWx1ZXM6IEZsb2F0MzJBcnJheTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHZhbHVlcyA9IGF3YWl0IHBvcnQuZ2V0RmVhdHVyZVZlY3RvcihnZW5lKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oYFtuYXBhcmktanNdIDNEIGdlbmUgbWFwOiBcIiR7Z2VuZX1cIiB1bmF2YWlsYWJsZWAsIGVycik7XG4gICAgICAgIHRoaXMuZ2VuZU1hcEtleSA9IG51bGw7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICghbG9hZCgpIHx8IHRoaXMuZ2VuZU1hcEtleSAhPT0ga2V5KSByZXR1cm47XG4gICAgICBjb25zdCBpblNlbGVjdGlvbiA9IHNlbGVjdGlvbi5jb3VudCA+IDAgPyBtYXNrVG9JbmRpY2VzKHNlbGVjdGlvbi5tYXNrKSA6IHVuZGVmaW5lZDtcbiAgICAgIC8vIEluLXBsYW5lIM+DIGlzIGEgUEhZU0lDQUwgYmFuZHdpZHRoLCBhbmNob3JlZCB0byB0aGUgcmVmZXJlbmNlIHZvbHVtZSdzIG93blxuICAgICAgLy8gdm94ZWwg4oCUIHRoZSByZXNvbHV0aW9uIHRoZSAyRCBtYXAgZXN0aW1hdGVzIGF0IOKAlCBzbyBhIHNoZWV0IGFuZCB0aGUgMkRcbiAgICAgIC8vIHZpZXcgb2YgdGhlIHNhbWUgc2VjdGlvbiBhcmUgdGhlIHNhbWUgZmllbGQgd2hhdGV2ZXIgbGF0dGljZSB0aGlzIGlzXG4gICAgICAvLyByYXN0ZXJpc2VkIG9uLiBBbG9uZyB6IGl0IGlzIHRoZSBkZW5zaXR5IHBhdGgncyAxLjUgdm94ZWxzOiB0aGUgc21hbGxlc3Qgz4NcbiAgICAgIC8vIHRoYXQgYnJpZGdlcyBvbmUgc2VjdGlvbiBnYXAuXG4gICAgICBjb25zdCBpblBsYW5lID0gZGF0YXNldC52b2x1bWU/LnZveGVsU2l6ZSA/PyBncmlkLnZveGVsU2l6ZTtcbiAgICAgIGxldCBmaWVsZDogRXhwcmVzc2lvblZvbHVtZUZpZWxkIHwgbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGZpZWxkID0gYXdhaXQgY29tcHV0ZUV4cHJlc3Npb25Wb2x1bWVBc3luYyhcbiAgICAgICAgICBvYnMsXG4gICAgICAgICAgZ3JpZCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzaWdtYTogW1xuICAgICAgICAgICAgICBpblBsYW5lWzBdICogR0VORV9NQVBfU0lHTUEgKiBzbW9vdGhpbmcsXG4gICAgICAgICAgICAgIGluUGxhbmVbMV0gKiBHRU5FX01BUF9TSUdNQSAqIHNtb290aGluZyxcbiAgICAgICAgICAgICAgZ3JpZC52b3hlbFNpemVbMl0gKiAxLjUgKiBzbW9vdGhpbmcsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgdmFsdWVzLFxuICAgICAgICAgICAgaW5kaWNlczogc2VjdGlvbiAhPSBudWxsID8gb2JzZXJ2YXRpb25zSW5TZWN0aW9uKG9icywgc2VjdGlvbikgOiBpblNlbGVjdGlvbixcbiAgICAgICAgICAgIGludGVycG9sYXRlLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBzaWduYWw6IGxvYWQuc2lnbmFsIH0sXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKGlzQWJvcnRFcnJvcihlcnIpKSByZXR1cm47IC8vIHN1cGVyc2VkZWQgYnkgYSBuZXdlciBtYXAsIG9yIHRoZSBzY2VuZSB3ZW50IGF3YXlcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgICAgaWYgKCFsb2FkKCkgfHwgdGhpcy5nZW5lTWFwS2V5ICE9PSBrZXkpIHJldHVybjtcbiAgICAgIGNhY2hlLmZpZWxkID0gZmllbGQ7XG4gICAgICBjYWNoZS5rZXkgPSBmaWVsZEtleTtcbiAgICB9XG4gICAgY29uc3QgZmllbGQgPSBjYWNoZS5maWVsZDtcbiAgICBpZiAoIWZpZWxkKSByZXR1cm47XG5cbiAgICAvLyBUaGUgaGlnaCBlbmQgb3ZlciB0aGUgTUVBU1VSRUQgdm94ZWxzIG9ubHkgKHRoZSB1bm1lYXN1cmVkIHplcm9zIHdvdWxkIHB1bGwgaXQgZG93biBhbmRcbiAgICAvLyBzYXR1cmF0ZSB0aGUgbWFwKSwgYnV0IHRoZSBsb3cgZW5kIHN0YXlzIDA6IGluIGEgdm9sdW1lIHRoZSB2YWx1ZSBpcyBhbHNvIHRoZSBvcGFjaXR5IGFuZFxuICAgIC8vIDAgcmVhZHMgYXMgXCJub3RoaW5nIGhlcmVcIiwgc28gc3RhcnRpbmcgYXQgdGhlIGxvd2VzdCBtZWFzdXJlZCB2YWx1ZSB3b3VsZCBlcmFzZSBpdC5cbiAgICBjb25zdCBbLCBoaV0gPSBmaWVsZENvbnRyYXN0V2luZG93KGZpZWxkLCBjbGlwWzBdLCBjbGlwWzFdKTtcbiAgICBjb25zdCBsbyA9IDA7XG4gICAgY29uc3QgZGF0YSA9IGVuY29kZUV4cHJlc3Npb25Wb2x1bWUoZmllbGQsIFtsbywgaGldLCB7IGxvZzogdmlldy5sb2dTY2FsZSB9KTtcbiAgICBjb25zdCBsdXQgPSB0aGlzLmN0eC5kaXNwbGF5LnNwYXRpYWxMdXQodmlldyk7XG4gICAgdGhpcy5nZW5lTWFwTGF5ZXIgPSB2aWV3ZXIuYWRkVm9sdW1lKGRhdGEsIGZpZWxkLndpZHRoLCBmaWVsZC5oZWlnaHQsIGZpZWxkLmRlcHRoLCB7XG4gICAgICBuYW1lOiBgZ2VuZSBtYXAgwrcgJHtnZW5lfSR7aW50ZXJwb2xhdGUgPyAnIMK3IHZvbHVtZScgOiAnJ31gLFxuICAgICAgY29sb3JtYXA6IGNvbG9ybWFwRnJvbUx1dChgZ2VuZS1tYXAtJHtnZW5lfWAsIGx1dCksXG4gICAgICAvLyBUaGUgZW5jb2RpbmcgYWxyZWFkeSBhcHBsaWVkIHRoZSB3aW5kb3csIHNvIHRoZSBsYXllciBtdXN0IG5vdCBhcHBseSBhXG4gICAgICAvLyBzZWNvbmQgb25lOiAwLi4yNTUgaXMgdGhlIHdob2xlIG9mIHdoYXQgaXQgd2FzIGdpdmVuLlxuICAgICAgY29udHJhc3RMaW1pdHM6IFswLCAyNTVdLFxuICAgICAgcmVuZGVyaW5nOiAndHJhbnNsdWNlbnQnLFxuICAgICAgLy8gQWRkaXRpdmUgbGlrZSB0aGUgZGVuc2l0eSB2b2x1bWVzLCBhbmQgZm9yIHRoZSBzYW1lIHJlYXNvbjogdGhlIHNoZWV0c1xuICAgICAgLy8gaGF2ZSB0byByZWFkIFRIUk9VR0ggZWFjaCBvdGhlciBhbmQgdGhyb3VnaCB0aGUgYW5hdG9teSwgd2hpY2ggYVxuICAgICAgLy8gdHJhbnNsdWNlbnQgYmxlbmQgd291bGQgb2NjbHVkZSBvbmUgc2hlZXQgYXQgYSB0aW1lLlxuICAgICAgYmxlbmRpbmc6ICdhZGRpdGl2ZScsXG4gICAgICBvcGFjaXR5OiB2aWV3LmdlbmVNYXBPcGFjaXR5LFxuICAgICAgdm94ZWxTaXplOiBncmlkLnZveGVsU2l6ZSxcbiAgICB9KTtcbiAgICB2aWV3ZXIucmVxdWVzdFJlbmRlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsdXN0ZXIgZGVuc2l0eSB2b2x1bWVzOiBlYWNoIGNsdXN0ZXIgcmFzdGVyaXNlZCBpbnRvIGEgc21vb3RoIHNjYWxhciBmaWVsZCBhbmRcbiAgICogcmF5bWFyY2hlZCBhbG9uZ3NpZGUgdGhlIGNsb3VkLCB0aW50ZWQgd2l0aCB0aGUgY2x1c3RlcidzIG93biBsZWdlbmQgY29sb3VyLlxuICAgKlxuICAgKiBUaGlzIGlzIHdoYXQgbWFrZXMgYSBzZXJpYWxseSBzZWN0aW9uZWQgZGF0YXNldCByZWFkYWJsZSBhcyBhbiBhbmF0b21pY2FsXG4gICAqIGRpc3RyaWJ1dGlvbi4gVGhlIGNsb3VkIHNob3dzIG1lYXN1cmVkIGNlbGxzIGFuZCBub3RoaW5nIGVsc2Ug4oCUIGJ1dCBhdCAyMDAgwrVtXG4gICAqIHNlY3Rpb24gc3BhY2luZyB0aGUgZXllIGNhbm5vdCBpbnRlZ3JhdGUgYSBzdGFjayBvZiBkaXNjcyBpbnRvIGEgc2hhcGUsIGFuZFxuICAgKiBldmVyeSBnYXAgcmVhZHMgYXMgYWJzZW5jZS4gQSBkZW5zaXR5IGZpZWxkIGlzIGEgZGlmZmVyZW50IG9iamVjdCBmcm9tIGEgY2VsbDpcbiAgICogYW4gZXN0aW1hdGUsIGRlZmluZWQgYmV0d2VlbiB0aGUgaW1hZ2VkIHBsYW5lcywgZHJhd24gYXMgYSB0cmFuc2x1Y2VudCBjbG91ZCBzb1xuICAgKiBpdCBjYW5ub3QgYmUgbWlzdGFrZW4gZm9yIG1lYXN1cmVtZW50LiBJbmRpdmlkdWFsIGNlbGxzIGFyZSBuZXZlciBpbnRlcnBvbGF0ZWQg4oCUXG4gICAqIGNvbnNlY3V0aXZlIHNlY3Rpb25zIHNhbXBsZSBkaWZmZXJlbnQgY2VsbHMsIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG8gaW50ZXJwb2xhdGVcbiAgICogYWxvbmcuXG4gICAqXG4gICAqIE9uZSB2b2x1bWUgcGVyIGNsdXN0ZXIgcmF0aGVyIHRoYW4gb25lIGZvciBldmVyeXRoaW5nOiBhZGRpdGl2ZSBibGVuZGluZyBpcyB3aGF0XG4gICAqIG1ha2VzIHR3byBjbHVzdGVycycgdGVycml0b3JpZXMgY29tcGFyYWJsZSwgYW5kIGEgc2luZ2xlIGJsZW5kZWQgZmllbGQgd291bGRcbiAgICogYW5zd2VyIG5vIHF1ZXN0aW9uIGFueW9uZSBhc2tzIG9mIGEgdGF4b25vbXkuIENhcHBlZCBhdCBgREVOU0lUWV9NQVhfQ0xVU1RFUlNgIGJ5IGNlbGxcbiAgICogY291bnQuXG4gICAqXG4gICAqIEtleWVkIHNvIGl0IHJlYnVpbGRzIG9ubHkgd2hlbiB0aGUgZmllbGQgd291bGQgYWN0dWFsbHkgZGlmZmVyIOKAlCB0aGUgZGF0YXNldCxcbiAgICogdGhlIGNvbG91ciBjb2x1bW4sIHRoZSBiYW5kd2lkdGgsIG9yIHRoZSBzZWxlY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGVuc3VyZURlbnNpdHlWb2x1bWVzKFxuICAgIHZpZXdlcjogVmlld2VyLFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgb24gPSAhIXZpZXcuZGVuc2l0eVZvbHVtZSAmJiAhIWRhdGFzZXQub2JzZXJ2YXRpb25zLno7XG4gICAgY29uc3Qgc21vb3RoaW5nID0gdmlldy5kZW5zaXR5U21vb3RoaW5nID4gMCA/IHZpZXcuZGVuc2l0eVNtb290aGluZyA6IDE7XG4gICAgY29uc3QgY29sdW1uID0gdmlldy5jb2xvckJ5Py5raW5kID09PSAnY29sdW1uJyA/IHZpZXcuY29sb3JCeS5uYW1lIDogbnVsbDtcbiAgICAvLyBUaGUgc2VsZWN0aW9uIGVudGVycyB0aGUga2V5IGJ5IElERU5USVRZLCBub3QgYnkgY291bnQ6IHR3byBkaWZmZXJlbnQgUk9Jc1xuICAgIC8vIGhvbGRpbmcgdGhlIHNhbWUgbnVtYmVyIG9mIGNlbGxzIHdvdWxkIG90aGVyd2lzZSBsb29rIGxpa2UgdGhlIHNhbWUga2V5IGFuZFxuICAgIC8vIGxlYXZlIHRoZSBwcmV2aW91cyBST0kncyBmaWVsZHMgb24gc2NyZWVuLlxuICAgIGNvbnN0IGtleSA9IG9uXG4gICAgICA/IFtkYXRhc2V0LmlkLCBjb2x1bW4gPz8gJ2FsbCcsIHNtb290aGluZywgdGhpcy5zZXNzaW9uLnNlbGVjdGlvblJldihzZWxlY3Rpb24pXS5qb2luKCd8JylcbiAgICAgIDogbnVsbDtcbiAgICBpZiAoa2V5ID09PSB0aGlzLmRlbnNpdHlLZXkpIHJldHVybjtcblxuICAgIGZvciAoY29uc3QgbGF5ZXIgb2YgdGhpcy5kZW5zaXR5TGF5ZXJzKSB2aWV3ZXIubGF5ZXJzLnJlbW92ZShsYXllcik7XG4gICAgdGhpcy5kZW5zaXR5TGF5ZXJzID0gW107XG4gICAgdGhpcy5kZW5zaXR5S2V5ID0ga2V5O1xuICAgIGNvbnN0IGxvYWQgPSB0aGlzLmRlbnNpdHlMb2Fkcy5uZXh0KCk7XG4gICAgaWYgKCFrZXkpIHJldHVybjtcblxuICAgIGNvbnN0IGdyaWQgPSBkZW5zaXR5R3JpZChkYXRhc2V0KTtcbiAgICBpZiAoIWdyaWQpIHJldHVybjtcbiAgICAvLyBXaXRoIG5vIHJlZmVyZW5jZSB2b2x1bWUgdGhlcmUgaXMgbm8gb2Zmc2V0IHlldCwgYW5kIGEgVm9sdW1lTGF5ZXIgaGFzIG5vXG4gICAgLy8gdHJhbnNsYXRlIOKAlCBuYXBhcmkgY2VudHJlcyBpdHMgYm94IG9uIHRoZSB3b3JsZCBvcmlnaW4uIFNvIHRoZSBQT0lOVFMgbW92ZSBieVxuICAgIC8vIGhhbGYgdGhlIGRlbnNpdHkgYm94LCBleGFjdGx5IGFzIHRoZXkgZG8gZm9yIGEgcmVmZXJlbmNlIHZvbHVtZSwgYW5kIHRoZVxuICAgIC8vIGNhY2hlZCBnZW9tZXRyeSBpcyBpbnZhbGlkYXRlZCBiZWNhdXNlIHRoYXQgb2Zmc2V0IGp1c3QgY2hhbmdlZC5cbiAgICBpZiAoIXRoaXMudm9sdW1lKSB7XG4gICAgICB0aGlzLm9yaWdpbiA9IFtcbiAgICAgICAgLShncmlkLndpZHRoICogZ3JpZC52b3hlbFNpemVbMF0pIC8gMixcbiAgICAgICAgLShncmlkLmhlaWdodCAqIGdyaWQudm94ZWxTaXplWzFdKSAvIDIsXG4gICAgICAgIC0oZ3JpZC5kZXB0aCAqIGdyaWQudm94ZWxTaXplWzJdKSAvIDIsXG4gICAgICBdO1xuICAgICAgdGhpcy5sYXllcktleSA9IG51bGw7XG4gICAgfVxuXG4gICAgbGV0IGdyb3VwczogRGVuc2l0eUdyb3VwW107XG4gICAgdHJ5IHtcbiAgICAgIGdyb3VwcyA9IGF3YWl0IHRoaXMuZGVuc2l0eUdyb3VwcyhkYXRhc2V0LCBjb2x1bW4sIHNlbGVjdGlvbik7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIGRlbnNpdHkgdm9sdW1lczogY29sdW1uIHVuYXZhaWxhYmxlJywgZXJyKTtcbiAgICAgIHRoaXMuZGVuc2l0eUtleSA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghbG9hZCgpIHx8IHRoaXMuZGVuc2l0eUtleSAhPT0ga2V5KSByZXR1cm47XG5cbiAgICBjb25zdCBzaWdtYSA9IGRlZmF1bHRTaWdtYShncmlkLCBzbW9vdGhpbmcpO1xuICAgIC8vIEFkZGl0aXZlIGJsZW5kaW5nIFNVTVMsIHNvIGEgZml4ZWQgcGVyLWxheWVyIG9wYWNpdHkgYmxvd3Mgb3V0IHRvIHdoaXRlIGFzXG4gICAgLy8gc29vbiBhcyBzZXZlcmFsIGJyb2FkIGNsdXN0ZXJzIG92ZXJsYXAg4oCUIHNpeCBzdWJjbGFzc2VzIGF0IDAuNTUgZWFjaCB0dXJuZWRcbiAgICAvLyB0aGUgYnJhaW4gaW50byBvbmUgY3lhbiBtYXNzLiBTcGxpdHRpbmcgdGhlIGJ1ZGdldCBrZWVwcyBuIGZ1bGx5IG92ZXJsYXBwaW5nXG4gICAgLy8gcGVha3MgaW5zaWRlIHRoZSBkaXNwbGF5J3MgcmFuZ2UsIHNvIG92ZXJsYXAgcmVhZHMgYXMgb3ZlcmxhcDsgYSBzaW5nbGVcbiAgICAvLyBjbHVzdGVyIHN0aWxsIGdldHMgdGhlIGZ1bGwgMC41NS4gSXQgb25seSBtaXRpZ2F0ZXM6IGEgdHJhbnNsdWNlbnQgcmF5bWFyY2hcbiAgICAvLyBpbnRlZ3JhdGVzIGFsb25nIHRoZSByYXksIHNvIGNsdXN0ZXJzIHRoYXQgYXJlIHViaXF1aXRvdXMgcmF0aGVyIHRoYW5cbiAgICAvLyByZWdpb25hbCAodGhlIGxhcmdlc3Qgc3ViY2xhc3NlcyBhcmUgZ2xpYSwgd2hpY2ggYXJlIGV2ZXJ5d2hlcmUpIHN0aWxsIHBpbGVcbiAgICAvLyB1cCwgYW5kIG9uZSBjbHVzdGVyIGF0IGEgdGltZSBpcyB0aGUgcmVhZGFibGUgd2F5IHRvIGxvb2sgYXQgdGhvc2UuXG4gICAgY29uc3Qgb3BhY2l0eSA9IE1hdGgubWluKDAuNTUsIDAuOSAvIE1hdGgubWF4KDEsIGdyb3Vwcy5sZW5ndGgpKTtcbiAgICBsZXQgZmllbGRzOiAoVWludDhBcnJheSB8IG51bGwpW107XG4gICAgdHJ5IHtcbiAgICAgIC8vIE9mZiB0aGUgbWFpbiB0aHJlYWQgcGFzdCB0aGUgd29ya2VyIHRocmVzaG9sZDsgdGhlIGNsdXN0ZXJzIHF1ZXVlIG9uIG9uZSB3b3JrZXIuXG4gICAgICBmaWVsZHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZ3JvdXBzLm1hcCgoZ3JvdXApID0+XG4gICAgICAgICAgcmFzdGVyaXplRGVuc2l0eUFzeW5jKFxuICAgICAgICAgICAgZGF0YXNldC5vYnNlcnZhdGlvbnMsXG4gICAgICAgICAgICBncmlkLFxuICAgICAgICAgICAgeyBzaWdtYSwgaW5kaWNlczogZ3JvdXAuaW5kaWNlcyB9LFxuICAgICAgICAgICAgeyBzaWduYWw6IGxvYWQuc2lnbmFsIH0sXG4gICAgICAgICAgKSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoaXNBYm9ydEVycm9yKGVycikpIHJldHVybjsgLy8gc3VwZXJzZWRlZCBieSBhIG5ld2VyIGtleSwgb3IgdGhlIHNjZW5lIHdlbnQgYXdheVxuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgICBpZiAoIWxvYWQoKSB8fCB0aGlzLmRlbnNpdHlLZXkgIT09IGtleSkgcmV0dXJuO1xuICAgIGdyb3Vwcy5mb3JFYWNoKChncm91cCwgaSkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGZpZWxkc1tpXTtcbiAgICAgIC8vIEEgY2x1c3RlciB3aXRoIG5vdGhpbmcgb24gdGhlIGdyaWQgZHJhd3Mgbm8gbGF5ZXIsIHJhdGhlciB0aGFuIGFuIGVtcHR5IGJveC5cbiAgICAgIGlmICghZGF0YSkgcmV0dXJuO1xuICAgICAgdGhpcy5kZW5zaXR5TGF5ZXJzLnB1c2goXG4gICAgICAgIHZpZXdlci5hZGRWb2x1bWUoZGF0YSwgZ3JpZC53aWR0aCwgZ3JpZC5oZWlnaHQsIGdyaWQuZGVwdGgsIHtcbiAgICAgICAgICBuYW1lOiBgZGVuc2l0eSDCtyAke2dyb3VwLm5hbWV9YCxcbiAgICAgICAgICBjb2xvcm1hcDogdGhpcy5jdHguZGlzcGxheS5jaGFubmVsVGludENvbG9ybWFwKGdyb3VwLmNvbG9yKSxcbiAgICAgICAgICBpbnZlcnQ6IHRoaXMuY3R4LmRpc3BsYXkuaW52ZXJ0LFxuICAgICAgICAgIC8vIFRyYW5zbHVjZW50LCBub3QgTUlQOiBhIGNsdXN0ZXIncyBpbnRlcmlvciBpcyB0aGUgcmVhZGFibGUgcGFydCwgYW5kIE1JUFxuICAgICAgICAgIC8vIHdvdWxkIGZsYXR0ZW4gZXZlcnkgY2xvdWQgdG8gaXRzIGJyaWdodGVzdCBzaGVsbC5cbiAgICAgICAgICByZW5kZXJpbmc6ICd0cmFuc2x1Y2VudCcsXG4gICAgICAgICAgb3BhY2l0eSxcbiAgICAgICAgICAvLyBBZGRpdGl2ZSwgc28gdHdvIGNsdXN0ZXJzIG92ZXJsYXBwaW5nIHJlYWQgYXMgYm90aCBiZWluZyB0aGVyZSBpbnN0ZWFkXG4gICAgICAgICAgLy8gb2YgdGhlIG5lYXJlciBvbmUgaGlkaW5nIHRoZSBvdGhlci5cbiAgICAgICAgICBibGVuZGluZzogJ2FkZGl0aXZlJyxcbiAgICAgICAgICB2b3hlbFNpemU6IGdyaWQudm94ZWxTaXplLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfSk7XG4gICAgdmlld2VyLnJlcXVlc3RSZW5kZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY2x1c3RlcnMgdG8gcmFzdGVyaXNlOiB0aGUgY2F0ZWdvcmllcyBvZiB0aGUgYWN0aXZlIGNhdGVnb3JpY2FsIGNvbG91cmluZyxcbiAgICogYmlnZ2VzdCBmaXJzdCBhbmQgY2FwcGVkLCBlYWNoIHdpdGggaXRzIGxlZ2VuZCBjb2xvdXIsIHJlc3RyaWN0ZWQgdG8gdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG4gICAqIHdoZW4gdGhlcmUgaXMgb25lLiBXaXRoIG5vIGNhdGVnb3JpY2FsIGNvbG91cmluZyB0aGVyZSBpcyBvbmUgZ3JvdXAg4oCUIHRvdGFsIGNlbGwgZGVuc2l0eSxcbiAgICogd2hpY2ggaXMgYSByZWFsIHF1ZXN0aW9uIG9uIGl0cyBvd24gKFwid2hlcmUgaXMgdGhlIHRpc3N1ZSBkZW5zZT9cIikgYW5kIHRoZSBob25lc3QgdGhpbmcgdG9cbiAgICogc2hvdyB3aGVuIHRoZSB2aWV3IGlzIG5vdCBlbmNvZGluZyBhIHRheG9ub215LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkZW5zaXR5R3JvdXBzKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIGNvbHVtbjogc3RyaW5nIHwgbnVsbCxcbiAgICBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrLFxuICApOiBQcm9taXNlPERlbnNpdHlHcm91cFtdPiB7XG4gICAgY29uc3QgcG9ydCA9IHRoaXMuc2Vzc2lvbi5wb3J0O1xuICAgIGNvbnN0IG1ldGEgPSBjb2x1bW4gPyBmaW5kQ29sdW1uTWV0YShkYXRhc2V0LCBjb2x1bW4pIDogdW5kZWZpbmVkO1xuICAgIGlmICghcG9ydCB8fCAhY29sdW1uIHx8ICFtZXRhIHx8IG1ldGEua2luZCAhPT0gJ2NhdGVnb3JpY2FsJykgcmV0dXJuIFt0b3RhbERlbnNpdHlHcm91cChzZWxlY3Rpb24pXTtcbiAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCBwb3J0LmdldENvbHVtbihjb2x1bW4pO1xuICAgIGlmICghaXNDYXRlZ29yaWNhbENvbHVtbihsb2FkZWQpKSByZXR1cm4gW107XG4gICAgcmV0dXJuIHJhbmtEZW5zaXR5R3JvdXBzKGNvbHVtbiwgbG9hZGVkLCBkYXRhc2V0Lm9ic2VydmF0aW9ucy5jb3VudCwgc2VsZWN0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgKG9yIGtlZXApIHRoZSBkYXRhc2V0J3MgcmVmZXJlbmNlIHZvbHVtZSwgYW5kIGRlcml2ZSB0aGUgb2Zmc2V0IHRoYXQgc2l0cyB0aGVcbiAgICogb2JzZXJ2YXRpb25zIGluc2lkZSBpdC5cbiAgICpcbiAgICogYFZvbHVtZUxheWVyYCBoYXMgbm8gdHJhbnNsYXRlOiBuYXBhcmktanMgbWFwcyB0aGUgdm9sdW1lJ3MgdW5pdCBjdWJlIHRvIGEgd29ybGQgYm94XG4gICAqICoqY2VudHJlZCBvbiB0aGUgb3JpZ2luKiosIHNpemVkIGBkaW1zIHggdm94ZWxTaXplYC4gVGhlIG9ic2VydmF0aW9ucywgYnkgY29udHJhY3QsIGFyZSBpblxuICAgKiB0aGUgdm9sdW1lJ3Mgb3duIGZyYW1lIHdpdGggaXRzIG5lYXIgY29ybmVyIGF0IHRoZSBjb29yZGluYXRlIG9yaWdpbi4gU28gdGhlIHR3byBvbmx5IGxpbmVcbiAgICogdXAgaWYgdGhlIFBPSU5UUyBtb3ZlIOKAlCBieSBoYWxmIHRoZSBib3gg4oCUIHdoaWNoIGlzIHdoYXQge0BsaW5rIG9yaWdpbn0gaXMuXG4gICAqXG4gICAqIEEgZmFpbGVkIG9yIGFic2VudCB2b2x1bWUgaXMgbm90IGZhdGFsOiB0aGUgY2xvdWQgcmVuZGVycyBvbiBpdHMgb3duLCBhdCBpdHMgb3duXG4gICAqIGNvb3JkaW5hdGVzLCBhbmQgdGhlIGNhbWVyYSBmcmFtZXMgdGhlIHBvaW50cyBpbnN0ZWFkLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVWb2x1bWUodmlld2VyOiBWaWV3ZXIsIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbWV0YSA9IGRhdGFzZXQudm9sdW1lO1xuICAgIGNvbnN0IHBvcnQgPSB0aGlzLnNlc3Npb24ucG9ydDtcbiAgICBjb25zdCBrZXkgPSBtZXRhID8gYCR7ZGF0YXNldC5pZH06JHttZXRhLndpZHRofXgke21ldGEuaGVpZ2h0fXgke21ldGEuZGVwdGh9YCA6IG51bGw7XG4gICAgaWYgKGtleSAmJiBrZXkgPT09IHRoaXMudm9sdW1lS2V5KSByZXR1cm47XG5cbiAgICBpZiAodGhpcy52b2x1bWUpIHtcbiAgICAgIHZpZXdlci5sYXllcnMucmVtb3ZlKHRoaXMudm9sdW1lKTtcbiAgICAgIHRoaXMudm9sdW1lID0gbnVsbDtcbiAgICAgIHRoaXMudm9sdW1lS2V5ID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5vcmlnaW4gPSBbMCwgMCwgMF07XG4gICAgaWYgKCFtZXRhIHx8ICFwb3J0Py5nZXRWb2x1bWUpIHJldHVybjtcblxuICAgIGxldCB2b3hlbHM6IFVpbnQ4QXJyYXk7XG4gICAgdHJ5IHtcbiAgICAgIHZveGVscyA9IGF3YWl0IHBvcnQuZ2V0Vm9sdW1lKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHJlZmVyZW5jZSB2b2x1bWUgdW5hdmFpbGFibGUg4oCUIGRyYXdpbmcgdGhlIGNsb3VkIGFsb25lJywgZXJyKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRoaXMuY3R4LnNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG5cbiAgICBjb25zdCBbdngsIHZ5LCB2el0gPSBtZXRhLnZveGVsU2l6ZTtcbiAgICB0aGlzLnZvbHVtZUtleSA9IGtleTtcbiAgICB0aGlzLnZvbHVtZSA9IHZpZXdlci5hZGRWb2x1bWUodm94ZWxzLCBtZXRhLndpZHRoLCBtZXRhLmhlaWdodCwgbWV0YS5kZXB0aCwge1xuICAgICAgbmFtZTogJ3JlZmVyZW5jZSB2b2x1bWUnLFxuICAgICAgY29sb3JtYXA6ICdncmF5JyxcbiAgICAgIC8vIE1JUCB3b3VsZCBkcmF3IHRoZSBicmlnaHRlc3Qgdm94ZWwgYWxvbmcgZWFjaCByYXksIHdoaWNoIGZvciBhbiBhdmVyYWdlZFxuICAgICAgLy8gdGVtcGxhdGUgbWVhbnMgYSBmbGF0IHdoaXRlIHNoZWxsIHRoYXQgaGlkZXMgdGhlIGNsb3VkLiBUcmFuc2x1Y2VudCBsZXRzXG4gICAgICAvLyB0aGUgcG9pbnRzIHJlYWQgdGhyb3VnaCB0aGUgdGlzc3VlLCB3aGljaCBpcyB0aGUgZW50aXJlIHBvaW50IG9mIGRyYXdpbmdcbiAgICAgIC8vIHRoZW0gdG9nZXRoZXIuXG4gICAgICByZW5kZXJpbmc6ICd0cmFuc2x1Y2VudCcsXG4gICAgICBvcGFjaXR5OiB2aWV3LnZvbHVtZU9wYWNpdHksXG4gICAgICB2b3hlbFNpemU6IFt2eCwgdnksIHZ6XSxcbiAgICB9KTtcbiAgICAvLyBIYWxmIHRoZSBib3gsIG5lZ2F0ZWQ6IHRoZSBvYnNlcnZhdGlvbnMnIG9yaWdpbiBpcyB0aGUgYm94J3MgbmVhciBjb3JuZXIsXG4gICAgLy8gYW5kIHRoZSBib3ggaXMgY2VudHJlZCBvbiB0aGUgd29ybGQgb3JpZ2luLlxuICAgIHRoaXMub3JpZ2luID0gWy0obWV0YS53aWR0aCAqIHZ4KSAvIDIsIC0obWV0YS5oZWlnaHQgKiB2eSkgLyAyLCAtKG1ldGEuZGVwdGggKiB2eikgLyAyXTtcbiAgICAvLyBGb3JjZSBhIGdlb21ldHJ5IHJlYnVpbGQ6IHRoZSBvZmZzZXQgY2hhbmdlZCwgc28gY2FjaGVkIHBvc2l0aW9ucyBhcmUgc3RhbGUuXG4gICAgdGhpcy5sYXllcktleSA9IG51bGw7XG4gIH1cblxuICAvKiogRHJvcCBldmVyeSBsYXllciBvZiB0aGUgY2xvdWQgKHRoZSBkYXRhc2V0IHdlbnQgYXdheSwgb3IgaGFzIG5vIHopLiAqL1xuICBwcml2YXRlIHJlbW92ZUxheWVycyh2aWV3ZXI6IFZpZXdlcik6IHZvaWQge1xuICAgIGZvciAoY29uc3QgbGF5ZXIgb2YgW3RoaXMucG9pbnRzLCB0aGlzLnZvbHVtZSwgdGhpcy5nZW5lTWFwTGF5ZXIsIC4uLnRoaXMuZGVuc2l0eUxheWVyc10pIHtcbiAgICAgIGlmIChsYXllcikgdmlld2VyLmxheWVycy5yZW1vdmUobGF5ZXIpO1xuICAgIH1cbiAgICB0aGlzLmdlbmVNYXBMYXllciA9IG51bGw7XG4gICAgdGhpcy5nZW5lTWFwS2V5ID0gbnVsbDtcbiAgICB0aGlzLnNlc3Npb24uZ2VuZU1hcFZvbHVtZS5maWVsZCA9IG51bGw7XG4gICAgdGhpcy5zZXNzaW9uLmdlbmVNYXBWb2x1bWUua2V5ID0gbnVsbDtcbiAgICB0aGlzLmRlbnNpdHlMYXllcnMgPSBbXTtcbiAgICB0aGlzLmRlbnNpdHlLZXkgPSBudWxsO1xuICAgIC8vIFRoZSBzY2VuZSBpcyBnb25lLCBzbyB0aGUgbmV4dCAzRCBsYXllciBzaG91bGQgZnJhbWUgaXRzZWxmIGFnYWluLiBUaGF0IHVzZWQgdG8gYmVcbiAgICAvLyBgc3BhdGlhbEZyYW1lZCA9IG51bGxgIG5leHQgdG8gYSBoYW5kLXJvbGxlZCBzYXZlL3Jlc3RvcmU7IHRoZSByZW5kZXJlciBvd25zIHRoZVxuICAgIC8vIHBvbGljeSBub3csIGFuZCB0aGlzIGlzIHRoZSBzYW1lIHN0YXRlbWVudCBhZGRyZXNzZWQgdG8gaXQuXG4gICAgdmlld2VyLnJlc2V0Rml0M0QoKTtcbiAgICB0aGlzLnZvbHVtZSA9IG51bGw7XG4gICAgdGhpcy52b2x1bWVLZXkgPSBudWxsO1xuICAgIHRoaXMub3JpZ2luID0gWzAsIDAsIDBdO1xuICAgIHRoaXMucG9pbnRzID0gbnVsbDtcbiAgICB0aGlzLnNldFBpY2tlcihudWxsKTtcbiAgICB0aGlzLmxheWVyS2V5ID0gbnVsbDtcbiAgICB0aGlzLnNjYWxhcktleSA9IG51bGw7XG4gICAgdGhpcy5wb3NpdGlvbnMgPSBudWxsO1xuICAgIHRoaXMuZHJhd24gPSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoYXQgY29sb3VycyB0aGUgY2xvdWQuXG4gICAqXG4gICAqIENvbnRpbnVvdXMgZGF0YSBnb2VzIHRocm91Z2ggdGhlIGFjdGl2ZSBjb2xvcm1hcCB3aXRoIHRoZSBzYW1lIHBlcmNlbnRpbGUgd2luZG93IHRoZSAyRCBwYXRoXG4gICAqIHVzZXMuIENhdGVnb3JpY2FsIGRhdGEgaXMgb25lIFJHQkEgcGVyIHBvaW50IGZyb20gdGhlIGNvbHVtbidzIHBhbGV0dGUsIHNvIGFueSBudW1iZXIgb2ZcbiAgICogY2F0ZWdvcmllcyBrZWVwcyBpdHMgb3duIGNvbG91ciDigJQgc2VlIGBlbmNvZGVTcGF0aWFsM2RDYXRlZ29yaWNhbGAuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNjYWxhckVuY29kaW5nKHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiBQcm9taXNlPFNwYXRpYWwzZEVuY29kaW5nIHwgbnVsbD4ge1xuICAgIGNvbnN0IHBvcnQgPSB0aGlzLnNlc3Npb24ucG9ydDtcbiAgICBjb25zdCBjb2xvckJ5ID0gdmlldy5jb2xvckJ5O1xuICAgIGlmICghcG9ydCB8fCAhY29sb3JCeSkgcmV0dXJuIG51bGw7XG5cbiAgICBpZiAoY29sb3JCeS5raW5kID09PSAnY29sdW1uJykge1xuICAgICAgY29uc3QgY29sdW1uOiBTcGF0aWFsQ29sdW1uID0gYXdhaXQgcG9ydC5nZXRDb2x1bW4oY29sb3JCeS5uYW1lKTtcbiAgICAgIGlmIChpc0NhdGVnb3JpY2FsQ29sdW1uKGNvbHVtbikpIHtcbiAgICAgICAgcmV0dXJuIGVuY29kZVNwYXRpYWwzZENhdGVnb3JpY2FsKGNvbHVtbi5jb2RlcywgcmVzb2x2ZUNhdGVnb3J5Q29sb3JzKGNvbHVtbi5tZXRhKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5lbmNvZGVDb250aW51b3VzKGNvbHVtbi52YWx1ZXMsIHZpZXcpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5lbmNvZGVDb250aW51b3VzKGF3YWl0IHBvcnQuZ2V0RmVhdHVyZVZlY3Rvcihjb2xvckJ5Lm5hbWUpLCB2aWV3KTtcbiAgfVxuXG4gIC8qKiBDb250aW51b3VzIHZhbHVlcyDihpIgdGhlIGFjdGl2ZSBjb2xvcm1hcCBvdmVyIGEgcGVyY2VudGlsZS1jbGlwcGVkIHdpbmRvdy4gKi9cbiAgZW5jb2RlQ29udGludW91cyhzb3VyY2U6IEZsb2F0MzJBcnJheSwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSk6IFNwYXRpYWwzZFNjYWxhcnMge1xuICAgIHJldHVybiBlbmNvZGVTcGF0aWFsM2RDb250aW51b3VzKFxuICAgICAgc291cmNlLFxuICAgICAgdmlldyxcbiAgICAgIHRoaXMuY3R4LmRpc3BsYXkuc3BhdGlhbEx1dCh2aWV3KSxcbiAgICAgIHRoaXMuc2Vzc2lvbi5jb250cmFzdFdpbmRvd3MsXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBvYnNlcnZhdGlvbnMgdGhlIGNsb3VkIGRyYXdzLCBhbmQgdGhlIGtleXMgb2YgaXRzIGdlb21ldHJ5IGFuZCBvZiBpdHMgY29sb3VyIHNvdXJjZS5cbiAqXG4gKiBPbmUgaW1hZ2VkIHNlY3Rpb24sIG9yIHRoZSB3aG9sZSBzdGFjayAoYHNob3duYCBudWxsKS4gVGhlIHN1YnNldCBJUyB0aGUgZ2VvbWV0cnksIHNvIGl0XG4gKiBiZWxvbmdzIGluIHRoZSBnZW9tZXRyeSBrZXkgcmF0aGVyIHRoYW4gYmVpbmcgcmUtZGVyaXZlZCBwZXIgZnJhbWUg4oCUIGFuZCBhbiBvdXQtb2YtcmFuZ2VcbiAqIGluZGV4IGlzIGNsYW1wZWQgcmF0aGVyIHRoYW4gZHJvcHBpbmcgdGhlIGNsb3VkLCBiZWNhdXNlIHRoZSBzZWN0aW9uIGNvdW50IGNoYW5nZXMgd2l0aCB0aGVcbiAqIGRhdGFzZXQgd2hpbGUgdGhlIHZpZXcgc3RhdGUgcGVyc2lzdHMuIFRoZSBzY2FsYXJzJyBpZGVudGl0eSBpcyB0cmFja2VkIHNlcGFyYXRlbHkgZnJvbSB0aGVcbiAqIGdlb21ldHJ5J3MgKGBjb2xvckJ5YCBwbHVzIHRoZSB0cmFuc2Zvcm1zIGZlZWRpbmcgdGhlIGVuY29kaW5nKTogYSBuZXcgY29sb3VyIHNvdXJjZSBzd2Fwc1xuICogYHZhbHVlc2AgaW4gcGxhY2UgKG5hcGFyaS1qcyDiiaUgMC4xNCksIHdoaWxlIGEgbmV3IGdlb21ldHJ5IG5lZWRzIGEgbmV3IGxheWVyLlxuICovXG5mdW5jdGlvbiBjbG91ZFN1YnNldChcbiAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4pOiB7IHNob3duOiBVaW50MzJBcnJheSB8IG51bGw7IGtleTogc3RyaW5nOyBzY2FsYXJLZXk6IHN0cmluZyB9IHtcbiAgY29uc3Qgb2JzID0gZGF0YXNldC5vYnNlcnZhdGlvbnM7XG4gIGNvbnN0IHNlY3Rpb25zID0gc2VjdGlvbnNPZihvYnMpO1xuICBjb25zdCBzZWN0aW9uID1cbiAgICB2aWV3LnBvaW50U2VjdGlvbiAhPSBudWxsICYmIHNlY3Rpb25zICYmIHNlY3Rpb25zLmxlbmd0aCA+IDBcbiAgICAgID8gc2VjdGlvbnNbTWF0aC5tYXgoMCwgTWF0aC5taW4oc2VjdGlvbnMubGVuZ3RoIC0gMSwgdmlldy5wb2ludFNlY3Rpb24pKV1cbiAgICAgIDogbnVsbDtcbiAgY29uc3Qgc2hvd24gPSBzZWN0aW9uICE9IG51bGwgPyBvYnNlcnZhdGlvbnNJblNlY3Rpb24ob2JzLCBzZWN0aW9uKSA6IG51bGw7XG4gIGNvbnN0IGtleSA9IGAke2RhdGFzZXQuaWR9OiR7b2JzLmNvdW50fToke3NlY3Rpb24gPz8gJ2FsbCd9YDtcbiAgY29uc3QgY2xpcCA9IHZpZXcucGVyY2VudGlsZUNsaXAgPz8gWzAuMDEsIDAuOTldO1xuICBjb25zdCBzY2FsYXJLZXkgPSBbXG4gICAga2V5LFxuICAgIHZpZXcuY29sb3JCeSA/IGAke3ZpZXcuY29sb3JCeS5raW5kfToke3ZpZXcuY29sb3JCeS5uYW1lfWAgOiAnZmxhdCcsXG4gICAgdmlldy5sb2dTY2FsZSA/ICdsb2cnIDogJ2xpbicsXG4gICAgY2xpcC5qb2luKCcsJyksXG4gIF0uam9pbignfCcpO1xuICByZXR1cm4geyBzaG93biwga2V5LCBzY2FsYXJLZXkgfTtcbn1cbiJdfQ==