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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,562 @@
1
+ import { from, of } from 'rxjs';
2
+ import { saveAs } from 'file-saver';
3
+ import { LruCache, assembleVolume, bitmapToScalar, chooseStitchLevel, decodeImageRGBA, readLevel, } from 'napari-js';
4
+ import { buildTileUrl, exportTiffFilename, exportTiffUrl, fetchJsonWithAuth, fetchWithAuth, isAbortError, nativeHistogram, pollDescriptor, tilesInfoUrl, } from '../tile-server';
5
+ import { DESCRIPTOR_POLL_INTERVAL_MS, DESCRIPTOR_TIMEOUT_MS, MAX_STITCH_TILES, MAX_TEXTURE_DIM, RGB_BAND_CACHE_TILES, STITCH_BUDGET_COEFF, TILE_FETCH_CONCURRENCY, TILE_SIZE, VOLUME_FETCH_CONCURRENCY, VOLUME_MAX_SLICE, create2dCanvas, splitRgbBands, stackDepth, } from './napari-helpers';
6
+ /** Decode an `ImageBitmap` to a single-channel uint8 luminance plane with napari-js's
7
+ * `bitmapToScalar` (server bands are grey, R=G=B, and decode exactly; a colour composite
8
+ * becomes its BT.601 luminance). `maxSide` caps the longest side (downscaling on the canvas
9
+ * draw) — used to keep pre-loaded surface slice planes small. Closes the bitmap. */
10
+ export function bitmapToLuminance(bmp, maxSide) {
11
+ const plane = bitmapToScalar(bmp, { maxSide, weights: 'bt601' });
12
+ bmp.close?.();
13
+ return plane;
14
+ }
15
+ /** A colour tile's R, G and B bands (closes a bitmap tile). */
16
+ function chunkToBands(chunk) {
17
+ if (typeof ImageBitmap !== 'undefined' && chunk.data instanceof ImageBitmap) {
18
+ const bmp = chunk.data;
19
+ try {
20
+ return splitRgbBands(decodeImageRGBA(bmp));
21
+ }
22
+ finally {
23
+ bmp.close?.();
24
+ }
25
+ }
26
+ return splitRgbBands({ data: chunk.data, width: chunk.width, height: chunk.height });
27
+ }
28
+ /**
29
+ * The napari-js backend's client of the jit-service tile server (review Appendix B, step 2), on
30
+ * the shared `tile-server/` protocol: the `/tiles/info` descriptor (polled, cached per source,
31
+ * shared between concurrent callers), whole-slice reads from the pyramid (napari-js `readLevel`), the pyramidal
32
+ * {@link TiledSource}s the 2D image draws, volume assembly, surface planes, the native `/histogram`
33
+ * and the `/export/tiff` download.
34
+ *
35
+ * The image is always passed in — the client never reads which image the service has loaded —
36
+ * so a descriptor can only ever describe the image a caller asked about (NAPARI-SVC-2).
37
+ *
38
+ * Scene-scoped state (the poll in flight, the sources that answered "no", the native histograms)
39
+ * lives until {@link startScene}; the descriptor cache itself survives scenes, keyed by source.
40
+ */
41
+ export class NapariTileClient {
42
+ constructor(tiles, simpleStack, api) {
43
+ this.tiles = tiles;
44
+ this.simpleStack = simpleStack;
45
+ this.api = api;
46
+ /** Cached `/tiles/info` pyramid descriptor + the infoB64 it was fetched for. */
47
+ this.descriptor = null;
48
+ this.descriptorKey = null;
49
+ /** The poll in flight, shared by every caller asking for the same `infoB64`. */
50
+ this.descriptorPoll = null;
51
+ /** `infoB64`s this scene's poll got no descriptor for (non-202 status, empty body, timeout).
52
+ * Scene-scoped, so a re-plot retries a slow or flaky server once. */
53
+ this.descriptorMisses = new Set();
54
+ /** Native-bit-depth histograms from `/histogram`, keyed `${z}|${channel}` (>8-bit images). */
55
+ this.nativeHistograms = new Map();
56
+ /** The current scene's lifetime: a poll started under it ends when it is aborted. */
57
+ this.scene = new AbortController().signal;
58
+ }
59
+ /** Whether `info` is a self-contained stack (`tiled:false`: each slice its own file, no
60
+ * server pyramid). */
61
+ isSimple(info) {
62
+ return this.simpleStack.isSimple(info);
63
+ }
64
+ /** A new scene: forget the scene-scoped state and poll under `signal` from now on. */
65
+ startScene(signal) {
66
+ this.scene = signal;
67
+ this.descriptorPoll = null;
68
+ this.descriptorMisses.clear();
69
+ this.nativeHistograms.clear();
70
+ }
71
+ /**
72
+ * Fetch + cache the server pyramid descriptor (`GET /tiles/info`): the REAL per-level tile grid,
73
+ * tile size, channel metadata and physical pixel size. The backend returns 202 while the source
74
+ * is still caching, so we poll ({@link pollDescriptor}). Cached per `infoB64`; returns null if it
75
+ * never becomes ready, or the server will not describe the source (callers fall back to a
76
+ * single-tile fetch). Read it back through {@link currentDescriptor}. This is the authoritative
77
+ * grid — guessing level dims from `trueImageSize` overshoots the real grid and the server 400s
78
+ * out-of-range tiles.
79
+ */
80
+ ensureDescriptor(info) {
81
+ // Self-contained multi-slice stack (no tile server — e.g. a numbered image
82
+ // series assembled client-side, each slice a different file): there is no
83
+ // single server-tiled pyramid to describe. Returning null routes every
84
+ // caller (2D image, volume, surface) to their stitched/single-fetch
85
+ // fallback, which — via fetchImage's own SimpleSliceAccessService branch —
86
+ // correctly fetches each slice's own URL instead of one fixed file's tile
87
+ // pyramid.
88
+ if (this.simpleStack.isSimple(info))
89
+ return Promise.resolve(null);
90
+ const infoB64 = this.tiles.getSelectedInfoB64();
91
+ if (!infoB64)
92
+ return Promise.resolve(null);
93
+ if (this.descriptor && this.descriptorKey === infoB64)
94
+ return Promise.resolve(this.descriptor);
95
+ // A source that answered "no" (or never answered) this scene is not asked again: the render,
96
+ // the stitch fallback and every slice would otherwise each wait out their own poll.
97
+ if (this.descriptorMisses.has(infoB64))
98
+ return Promise.resolve(null);
99
+ // Concurrent callers (render, navigator, histogram) share one poll.
100
+ if (this.descriptorPoll?.key === infoB64)
101
+ return this.descriptorPoll.promise;
102
+ const scene = this.scene;
103
+ const promise = this.pollDescriptor(infoB64, scene).then((desc) => {
104
+ if (this.descriptorPoll?.promise === promise)
105
+ this.descriptorPoll = null;
106
+ if (desc) {
107
+ this.descriptor = desc;
108
+ this.descriptorKey = infoB64;
109
+ }
110
+ else if (!scene.aborted) {
111
+ this.descriptorMisses.add(infoB64);
112
+ }
113
+ return desc;
114
+ });
115
+ this.descriptorPoll = { key: infoB64, promise };
116
+ return promise;
117
+ }
118
+ /**
119
+ * The `/tiles/info` loop behind {@link ensureDescriptor}: the shared jit-service poll
120
+ * (`tile-server/pollDescriptor`). Re-polls only on 202 (the server is still caching the source);
121
+ * any other status means this server will not describe it, so the answer is null at once. Each
122
+ * request gives up after its own timeout — a hung request would otherwise never reach the
123
+ * deadline check — and the whole poll ends (null) as soon as `scene` is aborted.
124
+ */
125
+ async pollDescriptor(infoB64, scene) {
126
+ try {
127
+ return await pollDescriptor(fetchJsonWithAuth(this.tiles), tilesInfoUrl(this.api, infoB64), {
128
+ deadlineMs: DESCRIPTOR_TIMEOUT_MS,
129
+ intervalMs: DESCRIPTOR_POLL_INTERVAL_MS,
130
+ signal: scene,
131
+ tag: '[napari-js]',
132
+ });
133
+ }
134
+ catch (err) {
135
+ if (isAbortError(err))
136
+ return null; // the scene was reset
137
+ throw err;
138
+ }
139
+ }
140
+ /**
141
+ * The pyramid descriptor of `info`, or null when it has none.
142
+ *
143
+ * The cache is keyed by `infoB64` and survives image switches and failed polls, so reading it
144
+ * directly would hand a `tiled:false` stack (or an image whose poll never answered) the
145
+ * PREVIOUS image's size, µm/pixel, tile size and bit depth. Every read site goes through here.
146
+ */
147
+ currentDescriptor(info) {
148
+ if (!this.descriptor || this.simpleStack.isSimple(info))
149
+ return null;
150
+ return this.descriptorKey === this.tiles.getSelectedInfoB64() ? this.descriptor : null;
151
+ }
152
+ /** µm per pixel along x for `info`: the descriptor's, else the image metadata's; 0 when
153
+ * neither declares it. */
154
+ mppX(info) {
155
+ return this.currentDescriptor(info)?.mppX || info?.imageMeta?.[0]?.mppX || 0;
156
+ }
157
+ /**
158
+ * Slice `z` as ONE image, for a source with no pyramid to read: a `tiled:false` stack's own
159
+ * file for `z`, else (no descriptor) the server's single top-left tile — correct for
160
+ * small/simple images.
161
+ *
162
+ * A self-contained multi-slice stack's `z` indexes a completely different file's own preview
163
+ * URL, not an internal slice of one server-tiled file, so it is resolved and fetched via
164
+ * SimpleSliceAccessService (shared with OSD; see its docs for why this can't be a bare fetch())
165
+ * rather than as a /tile?info=...&z= request against whichever single file
166
+ * getSelectedInfoB64() points at (which would 400/mismatch for any z beyond that one file's own
167
+ * extent). `channel` selects a band: a serverless multichannel stack's own plane
168
+ * (`channelUrls[z][channel]`, the client-side analog of the server's per-channel
169
+ * `/tile?channel=c`), else the server's.
170
+ */
171
+ async fetchImage(info, z, channel) {
172
+ if (this.simpleStack.isSimple(info)) {
173
+ const chUrls = info.channelUrls;
174
+ const url = channel != null && chUrls?.[z]?.[channel] != null
175
+ ? chUrls[z][channel]
176
+ : this.simpleStack.urlFor(info, z);
177
+ if (!url)
178
+ throw new Error(`[napari-js] no URL for slice ${z}`);
179
+ return this.simpleStack.fetchAsBitmap(url);
180
+ }
181
+ const infoB64 = this.tiles.getSelectedInfoB64();
182
+ if (!infoB64)
183
+ throw new Error('[napari-js] no selected image info (getSelectedInfoB64 null)');
184
+ const url = buildTileUrl(this.api, infoB64, { res: 0, col: 0, row: 0, z, tileSize: TILE_SIZE, channel });
185
+ const resp = await fetchWithAuth(this.tiles, url);
186
+ if (!resp.ok)
187
+ throw new Error(`[napari-js] slice fetch failed: ${resp.status} (0/0 res 0)`);
188
+ return createImageBitmap(await resp.blob());
189
+ }
190
+ /**
191
+ * Slice `z` as a single-channel uint8 luminance plane. With a pyramid, napari-js's `readLevel`
192
+ * reads it from the same {@link tiledSource} the 2D view draws: the finest level whose tile grid
193
+ * fits `maxTiles` and whose longest side fits the GPU texture limit (no finer than `maxSide`
194
+ * needs, when given), stitched with bounded concurrency and area-averaged down to `maxSide`.
195
+ * Without one, the single image of {@link fetchImage}. `channel` selects a band (real levels
196
+ * only); omit it for the composite, whose overview levels let a large image read a small level.
197
+ * `compositeFallback`: see {@link planeSource}. `signal` cancels the read (it rejects).
198
+ */
199
+ async readPlane(info, z, channel, opts) {
200
+ // A tiled:false stack has no pyramid: fetch its slice in this tick, as the 2D render does.
201
+ const desc = this.simpleStack.isSimple(info) ? null : await this.ensureDescriptor(info);
202
+ if (!desc?.levels?.length)
203
+ return bitmapToLuminance(await this.fetchImage(info, z, channel), opts.maxSide);
204
+ const budget = {
205
+ maxTiles: opts.maxTiles,
206
+ maxSide: opts.maxSide,
207
+ maxTextureDim: MAX_TEXTURE_DIM,
208
+ };
209
+ const source = opts.compositeFallback
210
+ ? this.planeSource(desc, channel, budget)
211
+ : this.tiledSource(desc, channel, 1);
212
+ const img = await readLevel(source, z, {
213
+ ...budget,
214
+ concurrency: TILE_FETCH_CONCURRENCY,
215
+ signal: opts.signal,
216
+ });
217
+ if (!img.fits && opts.maxTiles >= MAX_STITCH_TILES) {
218
+ console.warn(`[napari-js] no level of slice ${z} fits the ${opts.maxTiles}-tile/${MAX_TEXTURE_DIM}px budget; ` +
219
+ `read the coarsest (level ${img.level}) and downscaled it to ${img.width}×${img.height}.`);
220
+ }
221
+ return { data: img.data, width: img.width, height: img.height };
222
+ }
223
+ /**
224
+ * The scalar source for one decimated plane of band `channel`. A band has tiles only at the
225
+ * (few, large) real Bio-Formats levels; when none of them fits the budget — e.g. the coarsest
226
+ * real level is still 14982×18670, ~1100 full-res tiles — stitching it per slice floods the
227
+ * server (504s) and stalls the load. The composite pyramid has small overview levels, so the
228
+ * plane is read from the composite instead (its luminance). Only for a caller that wants one
229
+ * decimated plane (the surface height): for a multichannel VOLUME every channel would then read
230
+ * the same composite and the channels would collapse into one, so volumes keep each band.
231
+ */
232
+ planeSource(desc, channel, budget) {
233
+ const band = this.tiledSource(desc, channel, 1);
234
+ if (channel == null || desc.levels.length <= (desc.realLevels ?? desc.levels.length))
235
+ return band;
236
+ const own = chooseStitchLevel(band, budget);
237
+ if (own.fits)
238
+ return band;
239
+ const composite = this.tiledSource(desc, undefined, 1);
240
+ const alt = chooseStitchLevel(composite, budget);
241
+ if (!alt.fits && alt.cols * alt.rows >= own.cols * own.rows)
242
+ return band;
243
+ console.warn(`[napari-js] channel ${channel} has no pyramid level within the ${budget.maxTiles}-tile ` +
244
+ `budget; using the composite overview (${alt.width}×${alt.height}) for this plane.`);
245
+ return composite;
246
+ }
247
+ /**
248
+ * A small picture of the whole slice for the navigator: the composite (or band `channel`) at the
249
+ * finest level a single tile holds, else the coarsest level, as an RGBA canvas. Without a
250
+ * pyramid, the single image of {@link fetchImage}.
251
+ */
252
+ async overviewImage(info, z, channel) {
253
+ const desc = this.simpleStack.isSimple(info) ? null : await this.ensureDescriptor(info);
254
+ if (!desc?.levels?.length)
255
+ return this.fetchImage(info, z, channel);
256
+ const img = await readLevel(this.tiledSource(desc, channel, 4), z, {
257
+ maxTiles: 1,
258
+ maxTextureDim: MAX_TEXTURE_DIM,
259
+ concurrency: TILE_FETCH_CONCURRENCY,
260
+ });
261
+ const { canvas, ctx } = create2dCanvas(img.width, img.height, 'overview');
262
+ const pixels = ctx.createImageData(img.width, img.height);
263
+ pixels.data.set(img.data);
264
+ ctx.putImageData(pixels, 0, 0);
265
+ return canvas;
266
+ }
267
+ /**
268
+ * Slice `z`'s R, G and B bands, as three uint8 planes: the composite read as RGBA at the
269
+ * finest level within `maxTiles` (as {@link readPlane} picks it; 1 for a cheap overview
270
+ * sample), else the single image of {@link fetchImage}. The raw bands of an RGB image, for the
271
+ * per-band layers and their histograms.
272
+ */
273
+ async readRgbBands(info, z, maxTiles = MAX_STITCH_TILES) {
274
+ const desc = this.simpleStack.isSimple(info) ? null : await this.ensureDescriptor(info);
275
+ if (!desc?.levels?.length) {
276
+ const bmp = await this.fetchImage(info, z);
277
+ return chunkToBands({ width: bmp.width, height: bmp.height, data: bmp });
278
+ }
279
+ const img = await readLevel(this.tiledSource(desc, undefined, 4), z, {
280
+ maxTiles,
281
+ maxTextureDim: MAX_TEXTURE_DIM,
282
+ concurrency: TILE_FETCH_CONCURRENCY,
283
+ });
284
+ return splitRgbBands({ data: img.data, width: img.width, height: img.height });
285
+ }
286
+ /** Fetch slice `z` and read it back as a single-channel uint8 plane (see {@link readPlane}),
287
+ * within `budgetTiles`: the 2D stitch fallback reads at the full budget, the histogram samples
288
+ * at 1 for a cheap overview tile. */
289
+ async fetchChannelData(info, z, channel, budgetTiles = MAX_STITCH_TILES) {
290
+ return this.readPlane(info, z, channel, { maxTiles: budgetTiles });
291
+ }
292
+ /** Tile budget to stitch a whole slice at ~`targetPx` resolution from the pyramid. Shared by the
293
+ * surface plane fetch and the volume assembly, so both cap their reads by the decimate factor. */
294
+ tileBudgetFor(info, targetPx) {
295
+ const tileSize = this.currentDescriptor(info)?.tileSize || TILE_SIZE;
296
+ return Math.min(MAX_STITCH_TILES, Math.max(1, Math.round((targetPx / tileSize) ** 2 * STITCH_BUDGET_COEFF)));
297
+ }
298
+ /**
299
+ * Build a pyramidal TiledSource backed by the server `/tile` endpoint. `channel` selects a band
300
+ * (grayscale luminance, real levels only); omit it for the composite (RGBA, all levels).
301
+ *
302
+ * For the 2D view, `scene` is the signal of the render that asked for it, taken before that
303
+ * render's awaits, and `onTile` is told of each tile request and handed back the tile's end. A
304
+ * request issued once `scene` is aborted (a disposed source still fetching after a reset) is not
305
+ * reported, and one that settles after it does not end, so it can never count toward the next
306
+ * scene. A tile request's own `signal` (napari-js aborts a read it no longer needs) aborts the
307
+ * HTTP request.
308
+ */
309
+ tiledSource(desc, channel, channels, scene, onTile) {
310
+ const infoB64 = this.tiles.getSelectedInfoB64() ?? '';
311
+ // Per-channel tiles exist only at REAL Bio-Formats levels; the composite exists at all levels.
312
+ const usable = channel == null ? desc.levels : desc.levels.slice(0, Math.max(1, desc.realLevels ?? desc.levels.length));
313
+ const levelScales = usable.map((l) => desc.width / Math.max(1, l.width)); // level-0 px per level px
314
+ const tileSize = desc.tileSize || TILE_SIZE;
315
+ const api = this.api;
316
+ return {
317
+ kind: 'tiled',
318
+ width: desc.width,
319
+ height: desc.height,
320
+ tileSize,
321
+ levels: usable.length,
322
+ levelScales,
323
+ depth: Math.max(1, desc.z || 1),
324
+ channels,
325
+ dtype: 'uint8',
326
+ fetchTile: async (key, signal) => {
327
+ const res = usable[key.level]?.res ?? key.level;
328
+ const url = buildTileUrl(api, infoB64, {
329
+ res,
330
+ col: key.col,
331
+ row: key.row,
332
+ z: key.z,
333
+ tileSize,
334
+ channel,
335
+ });
336
+ const end = !onTile || scene?.aborted ? null : onTile();
337
+ try {
338
+ const resp = await fetchWithAuth(this.tiles, url, signal ? { signal } : {});
339
+ if (!resp.ok) {
340
+ throw new Error(`[napari-js] tile ${key.level}/${key.col}/${key.row} → ${resp.status}`);
341
+ }
342
+ const bmp = await createImageBitmap(await resp.blob());
343
+ if (channels === 4)
344
+ return { width: bmp.width, height: bmp.height, data: bmp };
345
+ return bitmapToLuminance(bmp);
346
+ }
347
+ finally {
348
+ if (!scene?.aborted)
349
+ end?.();
350
+ }
351
+ },
352
+ };
353
+ }
354
+ /**
355
+ * The composite pyramid's R, G and B bands as three scalar {@link TiledSource}s — one per
356
+ * additive layer, so each band takes its own window, gamma, invert, tint and visibility — that
357
+ * share ONE `/tile` request per tile. The three layers ask for a tile in the same frame: the
358
+ * first fetches the RGBA tile and splits it, the other two take their band from the same
359
+ * promise, and the split tile is dropped once all three have it. A band that asks later (one
360
+ * shown again after being hidden) finds it in a small LRU, else fetches it again. `scene` and
361
+ * `onTile` as {@link tiledSource}: the loading badge counts the one request.
362
+ */
363
+ rgbBandSources(desc, scene, onTile) {
364
+ const composite = this.tiledSource(desc, undefined, 4, scene, onTile);
365
+ const split = new LruCache(RGB_BAND_CACHE_TILES);
366
+ const band = (key, b) => {
367
+ const id = `${key.z}/${key.level}/${key.col}/${key.row}`;
368
+ let entry = split.get(id);
369
+ if (!entry) {
370
+ const bands = composite.fetchTile(key).then(chunkToBands);
371
+ const fresh = { bands, taken: new Set() };
372
+ // A failed tile is not remembered: the next ask fetches it again.
373
+ bands.catch(() => split.get(id) === fresh && split.delete(id));
374
+ split.set(id, (entry = fresh));
375
+ }
376
+ entry.taken.add(b);
377
+ if (entry.taken.size === 3)
378
+ split.delete(id);
379
+ return entry.bands.then((planes) => planes[b]);
380
+ };
381
+ return [0, 1, 2].map((b) => ({
382
+ ...composite,
383
+ channels: 1,
384
+ fetchTile: (key) => band(key, b),
385
+ }));
386
+ }
387
+ /**
388
+ * Assemble a downsampled uint8 volume (luminance) of `info`'s stack with napari-js's
389
+ * `assembleVolume`: every `sliceStep`th slice, read from the band's (or composite's) pyramid at
390
+ * the level that `maxSlice` needs, within its tile budget, and area-averaged to `maxSlice` on
391
+ * the longest side. Slices are read with bounded concurrency (the connection pool stays full
392
+ * without flooding it on a deep stack), each reporting `progress` (0–100) as it lands so the host
393
+ * shows a determinate progress bar. Null when `signal` aborts (a Cancel or a new plot), which
394
+ * also aborts the tile requests in flight — a partial volume is never returned.
395
+ */
396
+ async assembleVolume(info, opts, channel, hooks) {
397
+ const { signal } = hooks;
398
+ const fullDepth = stackDepth(info) || 1;
399
+ const step = Math.max(1, Math.floor(opts.sliceStep ?? 1));
400
+ const maxSlice = opts.maxSlice ?? VOLUME_MAX_SLICE;
401
+ // Source-slice indices sampled into the volume (every `step`th plane → low-res is faster).
402
+ const zIndices = [];
403
+ for (let z = 0; z < fullDepth; z += step)
404
+ zIndices.push(z);
405
+ hooks.progress(0);
406
+ try {
407
+ // `channel` selects a band (multichannel volume); omit for the grayscale composite. The
408
+ // caller owns the stackLoading flag (multichannel assembles channels in turn).
409
+ const source = await this.volumeSource(info, channel, zIndices[0]);
410
+ return await assembleVolume(source, zIndices, {
411
+ maxSide: maxSlice,
412
+ maxTiles: this.tileBudgetFor(info, maxSlice),
413
+ maxTextureDim: MAX_TEXTURE_DIM,
414
+ concurrency: VOLUME_FETCH_CONCURRENCY,
415
+ tileConcurrency: TILE_FETCH_CONCURRENCY,
416
+ onProgress: (done, total) => hooks.progress(Math.round((done / total) * 100)),
417
+ signal,
418
+ });
419
+ }
420
+ catch (err) {
421
+ if (signal.aborted)
422
+ return null; // cancelled → don't render a partial volume
423
+ throw err;
424
+ }
425
+ finally {
426
+ hooks.progress(0);
427
+ }
428
+ }
429
+ /**
430
+ * The scalar source a volume reads: the band's (or composite's) pyramid; without one, one whole
431
+ * image per slice ({@link fetchImage}) as a single-tile level sized by the first slice, which is
432
+ * fetched here and served again as that slice's tile.
433
+ */
434
+ async volumeSource(info, channel, firstZ) {
435
+ const desc = this.simpleStack.isSimple(info) ? null : await this.ensureDescriptor(info);
436
+ if (desc?.levels?.length)
437
+ return this.tiledSource(desc, channel, 1);
438
+ let first = await this.fetchImage(info, firstZ, channel);
439
+ const source = {
440
+ kind: 'tiled',
441
+ width: first.width,
442
+ height: first.height,
443
+ tileSize: Math.max(1, first.width, first.height),
444
+ levels: 1,
445
+ depth: stackDepth(info) || 1,
446
+ channels: 1,
447
+ dtype: 'uint8',
448
+ fetchTile: async (key) => {
449
+ let bmp;
450
+ if (first && key.z === firstZ) {
451
+ bmp = first;
452
+ first = null;
453
+ }
454
+ else {
455
+ bmp = await this.fetchImage(info, key.z, channel);
456
+ }
457
+ return { width: bmp.width, height: bmp.height, data: bmp };
458
+ },
459
+ };
460
+ return source;
461
+ }
462
+ /**
463
+ * Slice `z` as a single WHOLE-image luminance plane (decimated to `maxGrid`), for the surface.
464
+ * Prefers the server pyramid, read at the level the grid needs ({@link readPlane}, which may
465
+ * drop a band to the composite overview); without a descriptor, the app's complete per-slice
466
+ * image (`urls`/`smallUrls`, as the Plotly surface) — never a lone top-left tile, which would be
467
+ * a corner of the slice — and only as a last resort the single-tile fetch.
468
+ */
469
+ async fetchPlane(info, z, channel, maxGrid) {
470
+ const desc = await this.ensureDescriptor(info);
471
+ // Preferred: the WHOLE slice from the server pyramid at a resolution driven by the decimate
472
+ // factor — a higher target grid reads a FINER pyramid level (more real detail). This is what
473
+ // makes "Full" actually higher-res than "½", not just a fixed preview. The surface is a single
474
+ // decimated plane, so the composite fallback is acceptable when the band has no small level.
475
+ if (desc?.levels?.length) {
476
+ return this.readPlane(info, z, channel, {
477
+ maxTiles: this.tileBudgetFor(info, maxGrid),
478
+ maxSide: maxGrid,
479
+ compositeFallback: true,
480
+ });
481
+ }
482
+ // Fallback (no pyramid): the app's COMPLETE per-slice image (urls[z], not the small blurry
483
+ // thumbnail) — whole slice, avoids a corner tile. Capped at the image's own resolution.
484
+ const url = info?.urls?.[z] ?? info?.smallUrls?.[z];
485
+ if (url) {
486
+ try {
487
+ const resp = await fetchWithAuth(this.tiles, url);
488
+ if (resp.ok)
489
+ return bitmapToLuminance(await createImageBitmap(await resp.blob()), maxGrid);
490
+ }
491
+ catch (err) {
492
+ console.warn(`[napari-js] surface url fetch failed for z=${z}`, err);
493
+ }
494
+ }
495
+ // Last resort (no pyramid and no complete image): the single image.
496
+ return bitmapToLuminance(await this.fetchImage(info, z, channel), maxGrid);
497
+ }
498
+ /**
499
+ * Channel `channel`'s native-bit-depth histogram at slice `z` when `info` is a >8-bit image —
500
+ * the displayed pixels are 8-bit, so a client histogram would be clipped — cached per
501
+ * `(z, channel)`; null for an 8-bit channel, which the caller bins from the client data.
502
+ */
503
+ nativeHistogram$(info, z, channel, bins) {
504
+ const bitDepth = this.currentDescriptor(info)?.channelInfo?.[channel]?.bitDepth ?? 8;
505
+ if (bitDepth <= 8)
506
+ return null;
507
+ const key = `${z}|${channel}`;
508
+ const cached = this.nativeHistograms.get(key);
509
+ if (cached)
510
+ return of(cached);
511
+ return from(this.fetchNativeHistogram(channel, bins, z, key));
512
+ }
513
+ /** Fetch + cache one channel's native-bit-depth histogram from `GET /histogram` (>8-bit),
514
+ * through the shared jit-service client — whose URL carries the per-app-load cache-buster
515
+ * this backend used to omit, so a reload showed the server's 24 h-cached histogram. */
516
+ async fetchNativeHistogram(channel, bins, z, key) {
517
+ const infoB64 = this.tiles.getSelectedInfoB64();
518
+ if (!infoB64)
519
+ return null;
520
+ try {
521
+ const out = await nativeHistogram(fetchJsonWithAuth(this.tiles), this.api, infoB64, {
522
+ z,
523
+ channel,
524
+ bins,
525
+ });
526
+ if (!out)
527
+ return null; // 202 (still caching) or transient → null; the pane retries
528
+ this.nativeHistograms.set(key, out);
529
+ return out;
530
+ }
531
+ catch (err) {
532
+ console.warn('[napari-js] native histogram fetch failed', err);
533
+ return null;
534
+ }
535
+ }
536
+ /** Native-bit-depth (16/32-bit) multi-band TIFF export of slice `z` via the server
537
+ * `/export/tiff` endpoint — the displayed PNG is an 8-bit figure, this preserves the true pixel
538
+ * values. Visible channels only (omitted when all are visible → server default). Mirrors the
539
+ * OSD backend. */
540
+ async exportTiff(z, states, fileName) {
541
+ const infoB64 = this.tiles.getSelectedInfoB64();
542
+ if (!infoB64)
543
+ return;
544
+ const visible = states.filter((c) => c.visible).map((c) => c.index);
545
+ const url = exportTiffUrl(this.api, infoB64, z, visible, states.length);
546
+ const saveName = exportTiffFilename(fileName);
547
+ try {
548
+ const resp = await fetchWithAuth(this.tiles, url);
549
+ if (resp.status === 202) {
550
+ console.warn('[napari-js] 16-bit export: file still caching — try again shortly.');
551
+ return;
552
+ }
553
+ if (!resp.ok)
554
+ throw new Error(`status ${resp.status}`);
555
+ saveAs(await resp.blob(), saveName);
556
+ }
557
+ catch (err) {
558
+ console.warn('[napari-js] 16-bit TIFF export failed', err);
559
+ }
560
+ }
561
+ }
562
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXRpbGUtY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvbmFwYXJpLWpzL25hcGFyaS10aWxlLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWMsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFDTCxRQUFRLEVBQ1IsY0FBYyxFQUNkLGNBQWMsRUFDZCxpQkFBaUIsRUFDakIsZUFBZSxFQUNmLFNBQVMsR0FDVixNQUFNLFdBQVcsQ0FBQztBQU9uQixPQUFPLEVBRUwsWUFBWSxFQUNaLGtCQUFrQixFQUNsQixhQUFhLEVBQ2IsaUJBQWlCLEVBQ2pCLGFBQWEsRUFDYixZQUFZLEVBQ1osZUFBZSxFQUNmLGNBQWMsRUFDZCxZQUFZLEdBQ2IsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQ0wsMkJBQTJCLEVBQzNCLHFCQUFxQixFQUVyQixnQkFBZ0IsRUFDaEIsZUFBZSxFQUNmLG9CQUFvQixFQUNwQixtQkFBbUIsRUFDbkIsc0JBQXNCLEVBQ3RCLFNBQVMsRUFDVCx3QkFBd0IsRUFDeEIsZ0JBQWdCLEVBQ2hCLGNBQWMsRUFDZCxhQUFhLEVBQ2IsVUFBVSxHQUNYLE1BQU0sa0JBQWtCLENBQUM7QUFhMUI7OztxRkFHcUY7QUFDckYsTUFBTSxVQUFVLGlCQUFpQixDQUFDLEdBQWdCLEVBQUUsT0FBZ0I7SUFDbEUsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNqRSxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztJQUNkLE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVELCtEQUErRDtBQUMvRCxT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QUFHLENBQUMsQ0FBQztRQUM3RCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT2JzZXJ2YWJsZSwgZnJvbSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHNhdmVBcyB9IGZyb20gJ2ZpbGUtc2F2ZXInO1xuaW1wb3J0IHtcbiAgTHJ1Q2FjaGUsXG4gIGFzc2VtYmxlVm9sdW1lLFxuICBiaXRtYXBUb1NjYWxhcixcbiAgY2hvb3NlU3RpdGNoTGV2ZWwsXG4gIGRlY29kZUltYWdlUkdCQSxcbiAgcmVhZExldmVsLFxufSBmcm9tICduYXBhcmktanMnO1xuaW1wb3J0IHR5cGUgeyBQaXhlbENodW5rLCBTdGl0Y2hCdWRnZXQsIFRpbGVLZXksIFRpbGVkU291cmNlIH0gZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHsgSUltYWdlSW5mbyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9pbWFnZS5jb250cmFjdCc7XG5pbXBvcnQgeyBJQ2hhbm5lbFN0YXRlLCBJSGlzdG9ncmFtIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NoYW5uZWwtaGlzdG9ncmFtLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBUaWxlQWNjZXNzUG9ydCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9wb3J0cy90aWxlLWFjY2Vzcy5wb3J0JztcbmltcG9ydCB7IFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZSB9IGZyb20gJy4uL3NpbXBsZS1zbGljZS1hY2Nlc3Muc2VydmljZSc7XG5pbXBvcnQge1xuICBUaWxlRGVzY3JpcHRvcixcbiAgYnVpbGRUaWxlVXJsLFxuICBleHBvcnRUaWZmRmlsZW5hbWUsXG4gIGV4cG9ydFRpZmZVcmwsXG4gIGZldGNoSnNvbldpdGhBdXRoLFxuICBmZXRjaFdpdGhBdXRoLFxuICBpc0Fib3J0RXJyb3IsXG4gIG5hdGl2ZUhpc3RvZ3JhbSxcbiAgcG9sbERlc2NyaXB0b3IsXG4gIHRpbGVzSW5mb1VybCxcbn0gZnJvbSAnLi4vdGlsZS1zZXJ2ZXInO1xuaW1wb3J0IHtcbiAgREVTQ1JJUFRPUl9QT0xMX0lOVEVSVkFMX01TLFxuICBERVNDUklQVE9SX1RJTUVPVVRfTVMsXG4gIEx1bWFQbGFuZSxcbiAgTUFYX1NUSVRDSF9USUxFUyxcbiAgTUFYX1RFWFRVUkVfRElNLFxuICBSR0JfQkFORF9DQUNIRV9USUxFUyxcbiAgU1RJVENIX0JVREdFVF9DT0VGRixcbiAgVElMRV9GRVRDSF9DT05DVVJSRU5DWSxcbiAgVElMRV9TSVpFLFxuICBWT0xVTUVfRkVUQ0hfQ09OQ1VSUkVOQ1ksXG4gIFZPTFVNRV9NQVhfU0xJQ0UsXG4gIGNyZWF0ZTJkQ2FudmFzLFxuICBzcGxpdFJnYkJhbmRzLFxuICBzdGFja0RlcHRoLFxufSBmcm9tICcuL25hcGFyaS1oZWxwZXJzJztcblxuLyoqIFdoYXQgdGhlIG5hdmlnYXRvciBkcmF3czogYSB3aG9sZS1zbGljZSBwaWN0dXJlIChhIGNhbnZhcyByZWFkIGZyb20gdGhlIHB5cmFtaWQsIG9yIGEgYml0bWFwKS4gKi9cbmV4cG9ydCB0eXBlIE92ZXJ2aWV3SW1hZ2UgPSBJbWFnZUJpdG1hcCB8IEhUTUxDYW52YXNFbGVtZW50IHwgT2Zmc2NyZWVuQ2FudmFzO1xuXG4vKiogQW4gYXNzZW1ibGVkIHVpbnQ4IChsdW1pbmFuY2UpIHZvbHVtZSwgeC1mYXN0ZXN0IHRoZW4geSB0aGVuIHouICovXG5leHBvcnQgaW50ZXJmYWNlIEFzc2VtYmxlZFZvbHVtZSB7XG4gIGRhdGE6IFVpbnQ4QXJyYXk7XG4gIHdpZHRoOiBudW1iZXI7XG4gIGhlaWdodDogbnVtYmVyO1xuICBkZXB0aDogbnVtYmVyO1xufVxuXG4vKiogRGVjb2RlIGFuIGBJbWFnZUJpdG1hcGAgdG8gYSBzaW5nbGUtY2hhbm5lbCB1aW50OCBsdW1pbmFuY2UgcGxhbmUgd2l0aCBuYXBhcmktanMnc1xuICogIGBiaXRtYXBUb1NjYWxhcmAgKHNlcnZlciBiYW5kcyBhcmUgZ3JleSwgUj1HPUIsIGFuZCBkZWNvZGUgZXhhY3RseTsgYSBjb2xvdXIgY29tcG9zaXRlXG4gKiAgYmVjb21lcyBpdHMgQlQuNjAxIGx1bWluYW5jZSkuIGBtYXhTaWRlYCBjYXBzIHRoZSBsb25nZXN0IHNpZGUgKGRvd25zY2FsaW5nIG9uIHRoZSBjYW52YXNcbiAqICBkcmF3KSDigJQgdXNlZCB0byBrZWVwIHByZS1sb2FkZWQgc3VyZmFjZSBzbGljZSBwbGFuZXMgc21hbGwuIENsb3NlcyB0aGUgYml0bWFwLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJpdG1hcFRvTHVtaW5hbmNlKGJtcDogSW1hZ2VCaXRtYXAsIG1heFNpZGU/OiBudW1iZXIpOiBMdW1hUGxhbmUge1xuICBjb25zdCBwbGFuZSA9IGJpdG1hcFRvU2NhbGFyKGJtcCwgeyBtYXhTaWRlLCB3ZWlnaHRzOiAnYnQ2MDEnIH0pO1xuICBibXAuY2xvc2U/LigpO1xuICByZXR1cm4gcGxhbmU7XG59XG5cbi8qKiBBIGNvbG91ciB0aWxlJ3MgUiwgRyBhbmQgQiBiYW5kcyAoY2xvc2VzIGEgYml0bWFwIHRpbGUpLiAqL1xuZnVuY3Rpb24gY2h1bmtUb0JhbmRzKGNodW5rOiBQaXhlbENodW5rKTogTHVtYVBsYW5lW10ge1xuICBpZiAodHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBjaHVuay5kYXRhIGluc3RhbmNlb2YgSW1hZ2VCaXRtYXApIHtcbiAgICBjb25zdCBibXAgPSBjaHVuay5kYXRhO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gc3BsaXRSZ2JCYW5kcyhkZWNvZGVJbWFnZVJHQkEoYm1wKSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGJtcC5jbG9zZT8uKCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBzcGxpdFJnYkJhbmRzKHsgZGF0YTogY2h1bmsuZGF0YSBhcyBVaW50OEFycmF5LCB3aWR0aDogY2h1bmsud2lkdGgsIGhlaWdodDogY2h1bmsuaGVpZ2h0IH0pO1xufVxuXG4vKipcbiAqIFRoZSBuYXBhcmktanMgYmFja2VuZCdzIGNsaWVudCBvZiB0aGUgaml0LXNlcnZpY2UgdGlsZSBzZXJ2ZXIgKHJldmlldyBBcHBlbmRpeCBCLCBzdGVwIDIpLCBvblxuICogdGhlIHNoYXJlZCBgdGlsZS1zZXJ2ZXIvYCBwcm90b2NvbDogdGhlIGAvdGlsZXMvaW5mb2AgZGVzY3JpcHRvciAocG9sbGVkLCBjYWNoZWQgcGVyIHNvdXJjZSxcbiAqIHNoYXJlZCBiZXR3ZWVuIGNvbmN1cnJlbnQgY2FsbGVycyksIHdob2xlLXNsaWNlIHJlYWRzIGZyb20gdGhlIHB5cmFtaWQgKG5hcGFyaS1qcyBgcmVhZExldmVsYCksIHRoZSBweXJhbWlkYWxcbiAqIHtAbGluayBUaWxlZFNvdXJjZX1zIHRoZSAyRCBpbWFnZSBkcmF3cywgdm9sdW1lIGFzc2VtYmx5LCBzdXJmYWNlIHBsYW5lcywgdGhlIG5hdGl2ZSBgL2hpc3RvZ3JhbWBcbiAqIGFuZCB0aGUgYC9leHBvcnQvdGlmZmAgZG93bmxvYWQuXG4gKlxuICogVGhlIGltYWdlIGlzIGFsd2F5cyBwYXNzZWQgaW4g4oCUIHRoZSBjbGllbnQgbmV2ZXIgcmVhZHMgd2hpY2ggaW1hZ2UgdGhlIHNlcnZpY2UgaGFzIGxvYWRlZCDigJRcbiAqIHNvIGEgZGVzY3JpcHRvciBjYW4gb25seSBldmVyIGRlc2NyaWJlIHRoZSBpbWFnZSBhIGNhbGxlciBhc2tlZCBhYm91dCAoTkFQQVJJLVNWQy0yKS5cbiAqXG4gKiBTY2VuZS1zY29wZWQgc3RhdGUgKHRoZSBwb2xsIGluIGZsaWdodCwgdGhlIHNvdXJjZXMgdGhhdCBhbnN3ZXJlZCBcIm5vXCIsIHRoZSBuYXRpdmUgaGlzdG9ncmFtcylcbiAqIGxpdmVzIHVudGlsIHtAbGluayBzdGFydFNjZW5lfTsgdGhlIGRlc2NyaXB0b3IgY2FjaGUgaXRzZWxmIHN1cnZpdmVzIHNjZW5lcywga2V5ZWQgYnkgc291cmNlLlxuICovXG5leHBvcnQgY2xhc3MgTmFwYXJpVGlsZUNsaWVudCB7XG4gIC8qKiBDYWNoZWQgYC90aWxlcy9pbmZvYCBweXJhbWlkIGRlc2NyaXB0b3IgKyB0aGUgaW5mb0I2NCBpdCB3YXMgZmV0Y2hlZCBmb3IuICovXG4gIHByaXZhdGUgZGVzY3JpcHRvcjogVGlsZURlc2NyaXB0b3IgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBkZXNjcmlwdG9yS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBwb2xsIGluIGZsaWdodCwgc2hhcmVkIGJ5IGV2ZXJ5IGNhbGxlciBhc2tpbmcgZm9yIHRoZSBzYW1lIGBpbmZvQjY0YC4gKi9cbiAgcHJpdmF0ZSBkZXNjcmlwdG9yUG9sbDogeyBrZXk6IHN0cmluZzsgcHJvbWlzZTogUHJvbWlzZTxUaWxlRGVzY3JpcHRvciB8IG51bGw+IH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIGBpbmZvQjY0YHMgdGhpcyBzY2VuZSdzIHBvbGwgZ290IG5vIGRlc2NyaXB0b3IgZm9yIChub24tMjAyIHN0YXR1cywgZW1wdHkgYm9keSwgdGltZW91dCkuXG4gICAqICBTY2VuZS1zY29wZWQsIHNvIGEgcmUtcGxvdCByZXRyaWVzIGEgc2xvdyBvciBmbGFreSBzZXJ2ZXIgb25jZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBkZXNjcmlwdG9yTWlzc2VzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIC8qKiBOYXRpdmUtYml0LWRlcHRoIGhpc3RvZ3JhbXMgZnJvbSBgL2hpc3RvZ3JhbWAsIGtleWVkIGAke3p9fCR7Y2hhbm5lbH1gICg+OC1iaXQgaW1hZ2VzKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBuYXRpdmVIaXN0b2dyYW1zID0gbmV3IE1hcDxzdHJpbmcsIElIaXN0b2dyYW0+KCk7XG4gIC8qKiBUaGUgY3VycmVudCBzY2VuZSdzIGxpZmV0aW1lOiBhIHBvbGwgc3RhcnRlZCB1bmRlciBpdCBlbmRzIHdoZW4gaXQgaXMgYWJvcnRlZC4gKi9cbiAgcHJpdmF0ZSBzY2VuZTogQWJvcnRTaWduYWwgPSBuZXcgQWJvcnRDb250cm9sbGVyKCkuc2lnbmFsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdGlsZXM6IFRpbGVBY2Nlc3NQb3J0LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc2ltcGxlU3RhY2s6IFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFwaTogc3RyaW5nLFxuICApIHt9XG5cbiAgLyoqIFdoZXRoZXIgYGluZm9gIGlzIGEgc2VsZi1jb250YWluZWQgc3RhY2sgKGB0aWxlZDpmYWxzZWA6IGVhY2ggc2xpY2UgaXRzIG93biBmaWxlLCBub1xuICAgKiAgc2VydmVyIHB5cmFtaWQpLiAqL1xuICBpc1NpbXBsZShpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2ltcGxlU3RhY2suaXNTaW1wbGUoaW5mbyk7XG4gIH1cblxuICAvKiogQSBuZXcgc2NlbmU6IGZvcmdldCB0aGUgc2NlbmUtc2NvcGVkIHN0YXRlIGFuZCBwb2xsIHVuZGVyIGBzaWduYWxgIGZyb20gbm93IG9uLiAqL1xuICBzdGFydFNjZW5lKHNpZ25hbDogQWJvcnRTaWduYWwpOiB2b2lkIHtcbiAgICB0aGlzLnNjZW5lID0gc2lnbmFsO1xuICAgIHRoaXMuZGVzY3JpcHRvclBvbGwgPSBudWxsO1xuICAgIHRoaXMuZGVzY3JpcHRvck1pc3Nlcy5jbGVhcigpO1xuICAgIHRoaXMubmF0aXZlSGlzdG9ncmFtcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoICsgY2FjaGUgdGhlIHNlcnZlciBweXJhbWlkIGRlc2NyaXB0b3IgKGBHRVQgL3RpbGVzL2luZm9gKTogdGhlIFJFQUwgcGVyLWxldmVsIHRpbGUgZ3JpZCxcbiAgICogdGlsZSBzaXplLCBjaGFubmVsIG1ldGFkYXRhIGFuZCBwaHlzaWNhbCBwaXhlbCBzaXplLiBUaGUgYmFja2VuZCByZXR1cm5zIDIwMiB3aGlsZSB0aGUgc291cmNlXG4gICAqIGlzIHN0aWxsIGNhY2hpbmcsIHNvIHdlIHBvbGwgKHtAbGluayBwb2xsRGVzY3JpcHRvcn0pLiBDYWNoZWQgcGVyIGBpbmZvQjY0YDsgcmV0dXJucyBudWxsIGlmIGl0XG4gICAqIG5ldmVyIGJlY29tZXMgcmVhZHksIG9yIHRoZSBzZXJ2ZXIgd2lsbCBub3QgZGVzY3JpYmUgdGhlIHNvdXJjZSAoY2FsbGVycyBmYWxsIGJhY2sgdG8gYVxuICAgKiBzaW5nbGUtdGlsZSBmZXRjaCkuIFJlYWQgaXQgYmFjayB0aHJvdWdoIHtAbGluayBjdXJyZW50RGVzY3JpcHRvcn0uIFRoaXMgaXMgdGhlIGF1dGhvcml0YXRpdmVcbiAgICogZ3JpZCDigJQgZ3Vlc3NpbmcgbGV2ZWwgZGltcyBmcm9tIGB0cnVlSW1hZ2VTaXplYCBvdmVyc2hvb3RzIHRoZSByZWFsIGdyaWQgYW5kIHRoZSBzZXJ2ZXIgNDAwc1xuICAgKiBvdXQtb2YtcmFuZ2UgdGlsZXMuXG4gICAqL1xuICBlbnN1cmVEZXNjcmlwdG9yKGluZm86IElJbWFnZUluZm8gfCB1bmRlZmluZWQpOiBQcm9taXNlPFRpbGVEZXNjcmlwdG9yIHwgbnVsbD4ge1xuICAgIC8vIFNlbGYtY29udGFpbmVkIG11bHRpLXNsaWNlIHN0YWNrIChubyB0aWxlIHNlcnZlciDigJQgZS5nLiBhIG51bWJlcmVkIGltYWdlXG4gICAgLy8gc2VyaWVzIGFzc2VtYmxlZCBjbGllbnQtc2lkZSwgZWFjaCBzbGljZSBhIGRpZmZlcmVudCBmaWxlKTogdGhlcmUgaXMgbm9cbiAgICAvLyBzaW5nbGUgc2VydmVyLXRpbGVkIHB5cmFtaWQgdG8gZGVzY3JpYmUuIFJldHVybmluZyBudWxsIHJvdXRlcyBldmVyeVxuICAgIC8vIGNhbGxlciAoMkQgaW1hZ2UsIHZvbHVtZSwgc3VyZmFjZSkgdG8gdGhlaXIgc3RpdGNoZWQvc2luZ2xlLWZldGNoXG4gICAgLy8gZmFsbGJhY2ssIHdoaWNoIOKAlCB2aWEgZmV0Y2hJbWFnZSdzIG93biBTaW1wbGVTbGljZUFjY2Vzc1NlcnZpY2UgYnJhbmNoIOKAlFxuICAgIC8vIGNvcnJlY3RseSBmZXRjaGVzIGVhY2ggc2xpY2UncyBvd24gVVJMIGluc3RlYWQgb2Ygb25lIGZpeGVkIGZpbGUncyB0aWxlXG4gICAgLy8gcHlyYW1pZC5cbiAgICBpZiAodGhpcy5zaW1wbGVTdGFjay5pc1NpbXBsZShpbmZvKSkgcmV0dXJuIFByb21pc2UucmVzb2x2ZShudWxsKTtcbiAgICBjb25zdCBpbmZvQjY0ID0gdGhpcy50aWxlcy5nZXRTZWxlY3RlZEluZm9CNjQoKTtcbiAgICBpZiAoIWluZm9CNjQpIHJldHVybiBQcm9taXNlLnJlc29sdmUobnVsbCk7XG4gICAgaWYgKHRoaXMuZGVzY3JpcHRvciAmJiB0aGlzLmRlc2NyaXB0b3JLZXkgPT09IGluZm9CNjQpIHJldHVybiBQcm9taXNlLnJlc29sdmUodGhpcy5kZXNjcmlwdG9yKTtcbiAgICAvLyBBIHNvdXJjZSB0aGF0IGFuc3dlcmVkIFwibm9cIiAob3IgbmV2ZXIgYW5zd2VyZWQpIHRoaXMgc2NlbmUgaXMgbm90IGFza2VkIGFnYWluOiB0aGUgcmVuZGVyLFxuICAgIC8vIHRoZSBzdGl0Y2ggZmFsbGJhY2sgYW5kIGV2ZXJ5IHNsaWNlIHdvdWxkIG90aGVyd2lzZSBlYWNoIHdhaXQgb3V0IHRoZWlyIG93biBwb2xsLlxuICAgIGlmICh0aGlzLmRlc2NyaXB0b3JNaXNzZXMuaGFzKGluZm9CNjQpKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG51bGwpO1xuICAgIC8vIENvbmN1cnJlbnQgY2FsbGVycyAocmVuZGVyLCBuYXZpZ2F0b3IsIGhpc3RvZ3JhbSkgc2hhcmUgb25lIHBvbGwuXG4gICAgaWYgKHRoaXMuZGVzY3JpcHRvclBvbGw/LmtleSA9PT0gaW5mb0I2NCkgcmV0dXJuIHRoaXMuZGVzY3JpcHRvclBvbGwucHJvbWlzZTtcbiAgICBjb25zdCBzY2VuZSA9IHRoaXMuc2NlbmU7XG4gICAgY29uc3QgcHJvbWlzZSA9IHRoaXMucG9sbERlc2NyaXB0b3IoaW5mb0I2NCwgc2NlbmUpLnRoZW4oKGRlc2MpID0+IHtcbiAgICAgIGlmICh0aGlzLmRlc2NyaXB0b3JQb2xsPy5wcm9taXNlID09PSBwcm9taXNlKSB0aGlzLmRlc2NyaXB0b3JQb2xsID0gbnVsbDtcbiAgICAgIGlmIChkZXNjKSB7XG4gICAgICAgIHRoaXMuZGVzY3JpcHRvciA9IGRlc2M7XG4gICAgICAgIHRoaXMuZGVzY3JpcHRvcktleSA9IGluZm9CNjQ7XG4gICAgICB9IGVsc2UgaWYgKCFzY2VuZS5hYm9ydGVkKSB7XG4gICAgICAgIHRoaXMuZGVzY3JpcHRvck1pc3Nlcy5hZGQoaW5mb0I2NCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGVzYztcbiAgICB9KTtcbiAgICB0aGlzLmRlc2NyaXB0b3JQb2xsID0geyBrZXk6IGluZm9CNjQsIHByb21pc2UgfTtcbiAgICByZXR1cm4gcHJvbWlzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgYC90aWxlcy9pbmZvYCBsb29wIGJlaGluZCB7QGxpbmsgZW5zdXJlRGVzY3JpcHRvcn06IHRoZSBzaGFyZWQgaml0LXNlcnZpY2UgcG9sbFxuICAgKiAoYHRpbGUtc2VydmVyL3BvbGxEZXNjcmlwdG9yYCkuIFJlLXBvbGxzIG9ubHkgb24gMjAyICh0aGUgc2VydmVyIGlzIHN0aWxsIGNhY2hpbmcgdGhlIHNvdXJjZSk7XG4gICAqIGFueSBvdGhlciBzdGF0dXMgbWVhbnMgdGhpcyBzZXJ2ZXIgd2lsbCBub3QgZGVzY3JpYmUgaXQsIHNvIHRoZSBhbnN3ZXIgaXMgbnVsbCBhdCBvbmNlLiBFYWNoXG4gICAqIHJlcXVlc3QgZ2l2ZXMgdXAgYWZ0ZXIgaXRzIG93biB0aW1lb3V0IOKAlCBhIGh1bmcgcmVxdWVzdCB3b3VsZCBvdGhlcndpc2UgbmV2ZXIgcmVhY2ggdGhlXG4gICAqIGRlYWRsaW5lIGNoZWNrIOKAlCBhbmQgdGhlIHdob2xlIHBvbGwgZW5kcyAobnVsbCkgYXMgc29vbiBhcyBgc2NlbmVgIGlzIGFib3J0ZWQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBvbGxEZXNjcmlwdG9yKGluZm9CNjQ6IHN0cmluZywgc2NlbmU6IEFib3J0U2lnbmFsKTogUHJvbWlzZTxUaWxlRGVzY3JpcHRvciB8IG51bGw+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHBvbGxEZXNjcmlwdG9yKGZldGNoSnNvbldpdGhBdXRoKHRoaXMudGlsZXMpLCB0aWxlc0luZm9VcmwodGhpcy5hcGksIGluZm9CNjQpLCB7XG4gICAgICAgIGRlYWRsaW5lTXM6IERFU0NSSVBUT1JfVElNRU9VVF9NUyxcbiAgICAgICAgaW50ZXJ2YWxNczogREVTQ1JJUFRPUl9QT0xMX0lOVEVSVkFMX01TLFxuICAgICAgICBzaWduYWw6IHNjZW5lLFxuICAgICAgICB0YWc6ICdbbmFwYXJpLWpzXScsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChpc0Fib3J0RXJyb3IoZXJyKSkgcmV0dXJuIG51bGw7IC8vIHRoZSBzY2VuZSB3YXMgcmVzZXRcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhlIHB5cmFtaWQgZGVzY3JpcHRvciBvZiBgaW5mb2AsIG9yIG51bGwgd2hlbiBpdCBoYXMgbm9uZS5cbiAgICpcbiAgICogVGhlIGNhY2hlIGlzIGtleWVkIGJ5IGBpbmZvQjY0YCBhbmQgc3Vydml2ZXMgaW1hZ2Ugc3dpdGNoZXMgYW5kIGZhaWxlZCBwb2xscywgc28gcmVhZGluZyBpdFxuICAgKiBkaXJlY3RseSB3b3VsZCBoYW5kIGEgYHRpbGVkOmZhbHNlYCBzdGFjayAob3IgYW4gaW1hZ2Ugd2hvc2UgcG9sbCBuZXZlciBhbnN3ZXJlZCkgdGhlXG4gICAqIFBSRVZJT1VTIGltYWdlJ3Mgc2l6ZSwgwrVtL3BpeGVsLCB0aWxlIHNpemUgYW5kIGJpdCBkZXB0aC4gRXZlcnkgcmVhZCBzaXRlIGdvZXMgdGhyb3VnaCBoZXJlLlxuICAgKi9cbiAgY3VycmVudERlc2NyaXB0b3IoaW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCk6IFRpbGVEZXNjcmlwdG9yIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmRlc2NyaXB0b3IgfHwgdGhpcy5zaW1wbGVTdGFjay5pc1NpbXBsZShpbmZvKSkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIHRoaXMuZGVzY3JpcHRvcktleSA9PT0gdGhpcy50aWxlcy5nZXRTZWxlY3RlZEluZm9CNjQoKSA/IHRoaXMuZGVzY3JpcHRvciA6IG51bGw7XG4gIH1cblxuICAvKiogwrVtIHBlciBwaXhlbCBhbG9uZyB4IGZvciBgaW5mb2A6IHRoZSBkZXNjcmlwdG9yJ3MsIGVsc2UgdGhlIGltYWdlIG1ldGFkYXRhJ3M7IDAgd2hlblxuICAgKiAgbmVpdGhlciBkZWNsYXJlcyBpdC4gKi9cbiAgbXBwWChpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50RGVzY3JpcHRvcihpbmZvKT8ubXBwWCB8fCBpbmZvPy5pbWFnZU1ldGE/LlswXT8ubXBwWCB8fCAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFNsaWNlIGB6YCBhcyBPTkUgaW1hZ2UsIGZvciBhIHNvdXJjZSB3aXRoIG5vIHB5cmFtaWQgdG8gcmVhZDogYSBgdGlsZWQ6ZmFsc2VgIHN0YWNrJ3Mgb3duXG4gICAqIGZpbGUgZm9yIGB6YCwgZWxzZSAobm8gZGVzY3JpcHRvcikgdGhlIHNlcnZlcidzIHNpbmdsZSB0b3AtbGVmdCB0aWxlIOKAlCBjb3JyZWN0IGZvclxuICAgKiBzbWFsbC9zaW1wbGUgaW1hZ2VzLlxuICAgKlxuICAgKiBBIHNlbGYtY29udGFpbmVkIG11bHRpLXNsaWNlIHN0YWNrJ3MgYHpgIGluZGV4ZXMgYSBjb21wbGV0ZWx5IGRpZmZlcmVudCBmaWxlJ3Mgb3duIHByZXZpZXdcbiAgICogVVJMLCBub3QgYW4gaW50ZXJuYWwgc2xpY2Ugb2Ygb25lIHNlcnZlci10aWxlZCBmaWxlLCBzbyBpdCBpcyByZXNvbHZlZCBhbmQgZmV0Y2hlZCB2aWFcbiAgICogU2ltcGxlU2xpY2VBY2Nlc3NTZXJ2aWNlIChzaGFyZWQgd2l0aCBPU0Q7IHNlZSBpdHMgZG9jcyBmb3Igd2h5IHRoaXMgY2FuJ3QgYmUgYSBiYXJlIGZldGNoKCkpXG4gICAqIHJhdGhlciB0aGFuIGFzIGEgL3RpbGU/aW5mbz0uLi4mej0gcmVxdWVzdCBhZ2FpbnN0IHdoaWNoZXZlciBzaW5nbGUgZmlsZVxuICAgKiBnZXRTZWxlY3RlZEluZm9CNjQoKSBwb2ludHMgYXQgKHdoaWNoIHdvdWxkIDQwMC9taXNtYXRjaCBmb3IgYW55IHogYmV5b25kIHRoYXQgb25lIGZpbGUncyBvd25cbiAgICogZXh0ZW50KS4gYGNoYW5uZWxgIHNlbGVjdHMgYSBiYW5kOiBhIHNlcnZlcmxlc3MgbXVsdGljaGFubmVsIHN0YWNrJ3Mgb3duIHBsYW5lXG4gICAqIChgY2hhbm5lbFVybHNbel1bY2hhbm5lbF1gLCB0aGUgY2xpZW50LXNpZGUgYW5hbG9nIG9mIHRoZSBzZXJ2ZXIncyBwZXItY2hhbm5lbFxuICAgKiBgL3RpbGU/Y2hhbm5lbD1jYCksIGVsc2UgdGhlIHNlcnZlcidzLlxuICAgKi9cbiAgYXN5bmMgZmV0Y2hJbWFnZShpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkLCB6OiBudW1iZXIsIGNoYW5uZWw/OiBudW1iZXIpOiBQcm9taXNlPEltYWdlQml0bWFwPiB7XG4gICAgaWYgKHRoaXMuc2ltcGxlU3RhY2suaXNTaW1wbGUoaW5mbykpIHtcbiAgICAgIGNvbnN0IGNoVXJscyA9IChpbmZvIGFzIElJbWFnZUluZm8pLmNoYW5uZWxVcmxzO1xuICAgICAgY29uc3QgdXJsID1cbiAgICAgICAgY2hhbm5lbCAhPSBudWxsICYmIGNoVXJscz8uW3pdPy5bY2hhbm5lbF0gIT0gbnVsbFxuICAgICAgICAgID8gY2hVcmxzW3pdW2NoYW5uZWxdXG4gICAgICAgICAgOiB0aGlzLnNpbXBsZVN0YWNrLnVybEZvcihpbmZvIGFzIElJbWFnZUluZm8sIHopO1xuICAgICAgaWYgKCF1cmwpIHRocm93IG5ldyBFcnJvcihgW25hcGFyaS1qc10gbm8gVVJMIGZvciBzbGljZSAke3p9YCk7XG4gICAgICByZXR1cm4gdGhpcy5zaW1wbGVTdGFjay5mZXRjaEFzQml0bWFwKHVybCk7XG4gICAgfVxuICAgIGNvbnN0IGluZm9CNjQgPSB0aGlzLnRpbGVzLmdldFNlbGVjdGVkSW5mb0I2NCgpO1xuICAgIGlmICghaW5mb0I2NCkgdGhyb3cgbmV3IEVycm9yKCdbbmFwYXJpLWpzXSBubyBzZWxlY3RlZCBpbWFnZSBpbmZvIChnZXRTZWxlY3RlZEluZm9CNjQgbnVsbCknKTtcbiAgICBjb25zdCB1cmwgPSBidWlsZFRpbGVVcmwodGhpcy5hcGksIGluZm9CNjQsIHsgcmVzOiAwLCBjb2w6IDAsIHJvdzogMCwgeiwgdGlsZVNpemU6IFRJTEVfU0laRSwgY2hhbm5lbCB9KTtcbiAgICBjb25zdCByZXNwID0gYXdhaXQgZmV0Y2hXaXRoQXV0aCh0aGlzLnRpbGVzLCB1cmwpO1xuICAgIGlmICghcmVzcC5vaykgdGhyb3cgbmV3IEVycm9yKGBbbmFwYXJpLWpzXSBzbGljZSBmZXRjaCBmYWlsZWQ6ICR7cmVzcC5zdGF0dXN9ICgwLzAgcmVzIDApYCk7XG4gICAgcmV0dXJuIGNyZWF0ZUltYWdlQml0bWFwKGF3YWl0IHJlc3AuYmxvYigpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbGljZSBgemAgYXMgYSBzaW5nbGUtY2hhbm5lbCB1aW50OCBsdW1pbmFuY2UgcGxhbmUuIFdpdGggYSBweXJhbWlkLCBuYXBhcmktanMncyBgcmVhZExldmVsYFxuICAgKiByZWFkcyBpdCBmcm9tIHRoZSBzYW1lIHtAbGluayB0aWxlZFNvdXJjZX0gdGhlIDJEIHZpZXcgZHJhd3M6IHRoZSBmaW5lc3QgbGV2ZWwgd2hvc2UgdGlsZSBncmlkXG4gICAqIGZpdHMgYG1heFRpbGVzYCBhbmQgd2hvc2UgbG9uZ2VzdCBzaWRlIGZpdHMgdGhlIEdQVSB0ZXh0dXJlIGxpbWl0IChubyBmaW5lciB0aGFuIGBtYXhTaWRlYFxuICAgKiBuZWVkcywgd2hlbiBnaXZlbiksIHN0aXRjaGVkIHdpdGggYm91bmRlZCBjb25jdXJyZW5jeSBhbmQgYXJlYS1hdmVyYWdlZCBkb3duIHRvIGBtYXhTaWRlYC5cbiAgICogV2l0aG91dCBvbmUsIHRoZSBzaW5nbGUgaW1hZ2Ugb2Yge0BsaW5rIGZldGNoSW1hZ2V9LiBgY2hhbm5lbGAgc2VsZWN0cyBhIGJhbmQgKHJlYWwgbGV2ZWxzXG4gICAqIG9ubHkpOyBvbWl0IGl0IGZvciB0aGUgY29tcG9zaXRlLCB3aG9zZSBvdmVydmlldyBsZXZlbHMgbGV0IGEgbGFyZ2UgaW1hZ2UgcmVhZCBhIHNtYWxsIGxldmVsLlxuICAgKiBgY29tcG9zaXRlRmFsbGJhY2tgOiBzZWUge0BsaW5rIHBsYW5lU291cmNlfS4gYHNpZ25hbGAgY2FuY2VscyB0aGUgcmVhZCAoaXQgcmVqZWN0cykuXG4gICAqL1xuICBhc3luYyByZWFkUGxhbmUoXG4gICAgaW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCxcbiAgICB6OiBudW1iZXIsXG4gICAgY2hhbm5lbDogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICAgIG9wdHM6IHsgbWF4VGlsZXM6IG51bWJlcjsgbWF4U2lkZT86IG51bWJlcjsgY29tcG9zaXRlRmFsbGJhY2s/OiBib29sZWFuOyBzaWduYWw/OiBBYm9ydFNpZ25hbCB9LFxuICApOiBQcm9taXNlPEx1bWFQbGFuZT4ge1xuICAgIC8vIEEgdGlsZWQ6ZmFsc2Ugc3RhY2sgaGFzIG5vIHB5cmFtaWQ6IGZldGNoIGl0cyBzbGljZSBpbiB0aGlzIHRpY2ssIGFzIHRoZSAyRCByZW5kZXIgZG9lcy5cbiAgICBjb25zdCBkZXNjID0gdGhpcy5zaW1wbGVTdGFjay5pc1NpbXBsZShpbmZvKSA/IG51bGwgOiBhd2FpdCB0aGlzLmVuc3VyZURlc2NyaXB0b3IoaW5mbyk7XG4gICAgaWYgKCFkZXNjPy5sZXZlbHM/Lmxlbmd0aCkgcmV0dXJuIGJpdG1hcFRvTHVtaW5hbmNlKGF3YWl0IHRoaXMuZmV0Y2hJbWFnZShpbmZvLCB6LCBjaGFubmVsKSwgb3B0cy5tYXhTaWRlKTtcbiAgICBjb25zdCBidWRnZXQ6IFN0aXRjaEJ1ZGdldCA9IHtcbiAgICAgIG1heFRpbGVzOiBvcHRzLm1heFRpbGVzLFxuICAgICAgbWF4U2lkZTogb3B0cy5tYXhTaWRlLFxuICAgICAgbWF4VGV4dHVyZURpbTogTUFYX1RFWFRVUkVfRElNLFxuICAgIH07XG4gICAgY29uc3Qgc291cmNlID0gb3B0cy5jb21wb3NpdGVGYWxsYmFja1xuICAgICAgPyB0aGlzLnBsYW5lU291cmNlKGRlc2MsIGNoYW5uZWwsIGJ1ZGdldClcbiAgICAgIDogdGhpcy50aWxlZFNvdXJjZShkZXNjLCBjaGFubmVsLCAxKTtcbiAgICBjb25zdCBpbWcgPSBhd2FpdCByZWFkTGV2ZWwoc291cmNlLCB6LCB7XG4gICAgICAuLi5idWRnZXQsXG4gICAgICBjb25jdXJyZW5jeTogVElMRV9GRVRDSF9DT05DVVJSRU5DWSxcbiAgICAgIHNpZ25hbDogb3B0cy5zaWduYWwsXG4gICAgfSk7XG4gICAgaWYgKCFpbWcuZml0cyAmJiBvcHRzLm1heFRpbGVzID49IE1BWF9TVElUQ0hfVElMRVMpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFtuYXBhcmktanNdIG5vIGxldmVsIG9mIHNsaWNlICR7en0gZml0cyB0aGUgJHtvcHRzLm1heFRpbGVzfS10aWxlLyR7TUFYX1RFWFRVUkVfRElNfXB4IGJ1ZGdldDsgYCArXG4gICAgICAgICAgYHJlYWQgdGhlIGNvYXJzZXN0IChsZXZlbCAke2ltZy5sZXZlbH0pIGFuZCBkb3duc2NhbGVkIGl0IHRvICR7aW1nLndpZHRofcOXJHtpbWcuaGVpZ2h0fS5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgZGF0YTogaW1nLmRhdGEgYXMgVWludDhBcnJheSwgd2lkdGg6IGltZy53aWR0aCwgaGVpZ2h0OiBpbWcuaGVpZ2h0IH07XG4gIH1cblxuICAvKipcbiAgICogVGhlIHNjYWxhciBzb3VyY2UgZm9yIG9uZSBkZWNpbWF0ZWQgcGxhbmUgb2YgYmFuZCBgY2hhbm5lbGAuIEEgYmFuZCBoYXMgdGlsZXMgb25seSBhdCB0aGVcbiAgICogKGZldywgbGFyZ2UpIHJlYWwgQmlvLUZvcm1hdHMgbGV2ZWxzOyB3aGVuIG5vbmUgb2YgdGhlbSBmaXRzIHRoZSBidWRnZXQg4oCUIGUuZy4gdGhlIGNvYXJzZXN0XG4gICAqIHJlYWwgbGV2ZWwgaXMgc3RpbGwgMTQ5ODLDlzE4NjcwLCB+MTEwMCBmdWxsLXJlcyB0aWxlcyDigJQgc3RpdGNoaW5nIGl0IHBlciBzbGljZSBmbG9vZHMgdGhlXG4gICAqIHNlcnZlciAoNTA0cykgYW5kIHN0YWxscyB0aGUgbG9hZC4gVGhlIGNvbXBvc2l0ZSBweXJhbWlkIGhhcyBzbWFsbCBvdmVydmlldyBsZXZlbHMsIHNvIHRoZVxuICAgKiBwbGFuZSBpcyByZWFkIGZyb20gdGhlIGNvbXBvc2l0ZSBpbnN0ZWFkIChpdHMgbHVtaW5hbmNlKS4gT25seSBmb3IgYSBjYWxsZXIgdGhhdCB3YW50cyBvbmVcbiAgICogZGVjaW1hdGVkIHBsYW5lICh0aGUgc3VyZmFjZSBoZWlnaHQpOiBmb3IgYSBtdWx0aWNoYW5uZWwgVk9MVU1FIGV2ZXJ5IGNoYW5uZWwgd291bGQgdGhlbiByZWFkXG4gICAqIHRoZSBzYW1lIGNvbXBvc2l0ZSBhbmQgdGhlIGNoYW5uZWxzIHdvdWxkIGNvbGxhcHNlIGludG8gb25lLCBzbyB2b2x1bWVzIGtlZXAgZWFjaCBiYW5kLlxuICAgKi9cbiAgcHJpdmF0ZSBwbGFuZVNvdXJjZShkZXNjOiBUaWxlRGVzY3JpcHRvciwgY2hhbm5lbDogbnVtYmVyIHwgdW5kZWZpbmVkLCBidWRnZXQ6IFN0aXRjaEJ1ZGdldCk6IFRpbGVkU291cmNlIHtcbiAgICBjb25zdCBiYW5kID0gdGhpcy50aWxlZFNvdXJjZShkZXNjLCBjaGFubmVsLCAxKTtcbiAgICBpZiAoY2hhbm5lbCA9PSBudWxsIHx8IGRlc2MubGV2ZWxzLmxlbmd0aCA8PSAoZGVzYy5yZWFsTGV2ZWxzID8/IGRlc2MubGV2ZWxzLmxlbmd0aCkpIHJldHVybiBiYW5kO1xuICAgIGNvbnN0IG93biA9IGNob29zZVN0aXRjaExldmVsKGJhbmQsIGJ1ZGdldCk7XG4gICAgaWYgKG93bi5maXRzKSByZXR1cm4gYmFuZDtcbiAgICBjb25zdCBjb21wb3NpdGUgPSB0aGlzLnRpbGVkU291cmNlKGRlc2MsIHVuZGVmaW5lZCwgMSk7XG4gICAgY29uc3QgYWx0ID0gY2hvb3NlU3RpdGNoTGV2ZWwoY29tcG9zaXRlLCBidWRnZXQpO1xuICAgIGlmICghYWx0LmZpdHMgJiYgYWx0LmNvbHMgKiBhbHQucm93cyA+PSBvd24uY29scyAqIG93bi5yb3dzKSByZXR1cm4gYmFuZDtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBgW25hcGFyaS1qc10gY2hhbm5lbCAke2NoYW5uZWx9IGhhcyBubyBweXJhbWlkIGxldmVsIHdpdGhpbiB0aGUgJHtidWRnZXQubWF4VGlsZXN9LXRpbGUgYCArXG4gICAgICAgIGBidWRnZXQ7IHVzaW5nIHRoZSBjb21wb3NpdGUgb3ZlcnZpZXcgKCR7YWx0LndpZHRofcOXJHthbHQuaGVpZ2h0fSkgZm9yIHRoaXMgcGxhbmUuYCxcbiAgICApO1xuICAgIHJldHVybiBjb21wb3NpdGU7XG4gIH1cblxuICAvKipcbiAgICogQSBzbWFsbCBwaWN0dXJlIG9mIHRoZSB3aG9sZSBzbGljZSBmb3IgdGhlIG5hdmlnYXRvcjogdGhlIGNvbXBvc2l0ZSAob3IgYmFuZCBgY2hhbm5lbGApIGF0IHRoZVxuICAgKiBmaW5lc3QgbGV2ZWwgYSBzaW5nbGUgdGlsZSBob2xkcywgZWxzZSB0aGUgY29hcnNlc3QgbGV2ZWwsIGFzIGFuIFJHQkEgY2FudmFzLiBXaXRob3V0IGFcbiAgICogcHlyYW1pZCwgdGhlIHNpbmdsZSBpbWFnZSBvZiB7QGxpbmsgZmV0Y2hJbWFnZX0uXG4gICAqL1xuICBhc3luYyBvdmVydmlld0ltYWdlKGluZm86IElJbWFnZUluZm8gfCB1bmRlZmluZWQsIHo6IG51bWJlciwgY2hhbm5lbD86IG51bWJlcik6IFByb21pc2U8T3ZlcnZpZXdJbWFnZT4ge1xuICAgIGNvbnN0IGRlc2MgPSB0aGlzLnNpbXBsZVN0YWNrLmlzU2ltcGxlKGluZm8pID8gbnVsbCA6IGF3YWl0IHRoaXMuZW5zdXJlRGVzY3JpcHRvcihpbmZvKTtcbiAgICBpZiAoIWRlc2M/LmxldmVscz8ubGVuZ3RoKSByZXR1cm4gdGhpcy5mZXRjaEltYWdlKGluZm8sIHosIGNoYW5uZWwpO1xuICAgIGNvbnN0IGltZyA9IGF3YWl0IHJlYWRMZXZlbCh0aGlzLnRpbGVkU291cmNlKGRlc2MsIGNoYW5uZWwsIDQpLCB6LCB7XG4gICAgICBtYXhUaWxlczogMSxcbiAgICAgIG1heFRleHR1cmVEaW06IE1BWF9URVhUVVJFX0RJTSxcbiAgICAgIGNvbmN1cnJlbmN5OiBUSUxFX0ZFVENIX0NPTkNVUlJFTkNZLFxuICAgIH0pO1xuICAgIGNvbnN0IHsgY2FudmFzLCBjdHggfSA9IGNyZWF0ZTJkQ2FudmFzKGltZy53aWR0aCwgaW1nLmhlaWdodCwgJ292ZXJ2aWV3Jyk7XG4gICAgY29uc3QgcGl4ZWxzID0gY3R4LmNyZWF0ZUltYWdlRGF0YShpbWcud2lkdGgsIGltZy5oZWlnaHQpO1xuICAgIHBpeGVscy5kYXRhLnNldChpbWcuZGF0YSBhcyBVaW50OEFycmF5KTtcbiAgICBjdHgucHV0SW1hZ2VEYXRhKHBpeGVscywgMCwgMCk7XG4gICAgcmV0dXJuIGNhbnZhcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTbGljZSBgemAncyBSLCBHIGFuZCBCIGJhbmRzLCBhcyB0aHJlZSB1aW50OCBwbGFuZXM6IHRoZSBjb21wb3NpdGUgcmVhZCBhcyBSR0JBIGF0IHRoZVxuICAgKiBmaW5lc3QgbGV2ZWwgd2l0aGluIGBtYXhUaWxlc2AgKGFzIHtAbGluayByZWFkUGxhbmV9IHBpY2tzIGl0OyAxIGZvciBhIGNoZWFwIG92ZXJ2aWV3XG4gICAqIHNhbXBsZSksIGVsc2UgdGhlIHNpbmdsZSBpbWFnZSBvZiB7QGxpbmsgZmV0Y2hJbWFnZX0uIFRoZSByYXcgYmFuZHMgb2YgYW4gUkdCIGltYWdlLCBmb3IgdGhlXG4gICAqIHBlci1iYW5kIGxheWVycyBhbmQgdGhlaXIgaGlzdG9ncmFtcy5cbiAgICovXG4gIGFzeW5jIHJlYWRSZ2JCYW5kcyhcbiAgICBpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkLFxuICAgIHo6IG51bWJlcixcbiAgICBtYXhUaWxlczogbnVtYmVyID0gTUFYX1NUSVRDSF9USUxFUyxcbiAgKTogUHJvbWlzZTxMdW1hUGxhbmVbXT4ge1xuICAgIGNvbnN0IGRlc2MgPSB0aGlzLnNpbXBsZVN0YWNrLmlzU2ltcGxlKGluZm8pID8gbnVsbCA6IGF3YWl0IHRoaXMuZW5zdXJlRGVzY3JpcHRvcihpbmZvKTtcbiAgICBpZiAoIWRlc2M/LmxldmVscz8ubGVuZ3RoKSB7XG4gICAgICBjb25zdCBibXAgPSBhd2FpdCB0aGlzLmZldGNoSW1hZ2UoaW5mbywgeik7XG4gICAgICByZXR1cm4gY2h1bmtUb0JhbmRzKHsgd2lkdGg6IGJtcC53aWR0aCwgaGVpZ2h0OiBibXAuaGVpZ2h0LCBkYXRhOiBibXAgfSk7XG4gICAgfVxuICAgIGNvbnN0IGltZyA9IGF3YWl0IHJlYWRMZXZlbCh0aGlzLnRpbGVkU291cmNlKGRlc2MsIHVuZGVmaW5lZCwgNCksIHosIHtcbiAgICAgIG1heFRpbGVzLFxuICAgICAgbWF4VGV4dHVyZURpbTogTUFYX1RFWFRVUkVfRElNLFxuICAgICAgY29uY3VycmVuY3k6IFRJTEVfRkVUQ0hfQ09OQ1VSUkVOQ1ksXG4gICAgfSk7XG4gICAgcmV0dXJuIHNwbGl0UmdiQmFuZHMoeyBkYXRhOiBpbWcuZGF0YSBhcyBVaW50OEFycmF5LCB3aWR0aDogaW1nLndpZHRoLCBoZWlnaHQ6IGltZy5oZWlnaHQgfSk7XG4gIH1cblxuICAvKiogRmV0Y2ggc2xpY2UgYHpgIGFuZCByZWFkIGl0IGJhY2sgYXMgYSBzaW5nbGUtY2hhbm5lbCB1aW50OCBwbGFuZSAoc2VlIHtAbGluayByZWFkUGxhbmV9KSxcbiAgICogIHdpdGhpbiBgYnVkZ2V0VGlsZXNgOiB0aGUgMkQgc3RpdGNoIGZhbGxiYWNrIHJlYWRzIGF0IHRoZSBmdWxsIGJ1ZGdldCwgdGhlIGhpc3RvZ3JhbSBzYW1wbGVzXG4gICAqICBhdCAxIGZvciBhIGNoZWFwIG92ZXJ2aWV3IHRpbGUuICovXG4gIGFzeW5jIGZldGNoQ2hhbm5lbERhdGEoXG4gICAgaW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCxcbiAgICB6OiBudW1iZXIsXG4gICAgY2hhbm5lbD86IG51bWJlcixcbiAgICBidWRnZXRUaWxlczogbnVtYmVyID0gTUFYX1NUSVRDSF9USUxFUyxcbiAgKTogUHJvbWlzZTxMdW1hUGxhbmU+IHtcbiAgICByZXR1cm4gdGhpcy5yZWFkUGxhbmUoaW5mbywgeiwgY2hhbm5lbCwgeyBtYXhUaWxlczogYnVkZ2V0VGlsZXMgfSk7XG4gIH1cblxuICAvKiogVGlsZSBidWRnZXQgdG8gc3RpdGNoIGEgd2hvbGUgc2xpY2UgYXQgfmB0YXJnZXRQeGAgcmVzb2x1dGlvbiBmcm9tIHRoZSBweXJhbWlkLiBTaGFyZWQgYnkgdGhlXG4gICAqICBzdXJmYWNlIHBsYW5lIGZldGNoIGFuZCB0aGUgdm9sdW1lIGFzc2VtYmx5LCBzbyBib3RoIGNhcCB0aGVpciByZWFkcyBieSB0aGUgZGVjaW1hdGUgZmFjdG9yLiAqL1xuICB0aWxlQnVkZ2V0Rm9yKGluZm86IElJbWFnZUluZm8gfCB1bmRlZmluZWQsIHRhcmdldFB4OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IHRpbGVTaXplID0gdGhpcy5jdXJyZW50RGVzY3JpcHRvcihpbmZvKT8udGlsZVNpemUgfHwgVElMRV9TSVpFO1xuICAgIHJldHVybiBNYXRoLm1pbihNQVhfU1RJVENIX1RJTEVTLCBNYXRoLm1heCgxLCBNYXRoLnJvdW5kKCh0YXJnZXRQeCAvIHRpbGVTaXplKSAqKiAyICogU1RJVENIX0JVREdFVF9DT0VGRikpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIHB5cmFtaWRhbCBUaWxlZFNvdXJjZSBiYWNrZWQgYnkgdGhlIHNlcnZlciBgL3RpbGVgIGVuZHBvaW50LiBgY2hhbm5lbGAgc2VsZWN0cyBhIGJhbmRcbiAgICogKGdyYXlzY2FsZSBsdW1pbmFuY2UsIHJlYWwgbGV2ZWxzIG9ubHkpOyBvbWl0IGl0IGZvciB0aGUgY29tcG9zaXRlIChSR0JBLCBhbGwgbGV2ZWxzKS5cbiAgICpcbiAgICogRm9yIHRoZSAyRCB2aWV3LCBgc2NlbmVgIGlzIHRoZSBzaWduYWwgb2YgdGhlIHJlbmRlciB0aGF0IGFza2VkIGZvciBpdCwgdGFrZW4gYmVmb3JlIHRoYXRcbiAgICogcmVuZGVyJ3MgYXdhaXRzLCBhbmQgYG9uVGlsZWAgaXMgdG9sZCBvZiBlYWNoIHRpbGUgcmVxdWVzdCBhbmQgaGFuZGVkIGJhY2sgdGhlIHRpbGUncyBlbmQuIEFcbiAgICogcmVxdWVzdCBpc3N1ZWQgb25jZSBgc2NlbmVgIGlzIGFib3J0ZWQgKGEgZGlzcG9zZWQgc291cmNlIHN0aWxsIGZldGNoaW5nIGFmdGVyIGEgcmVzZXQpIGlzIG5vdFxuICAgKiByZXBvcnRlZCwgYW5kIG9uZSB0aGF0IHNldHRsZXMgYWZ0ZXIgaXQgZG9lcyBub3QgZW5kLCBzbyBpdCBjYW4gbmV2ZXIgY291bnQgdG93YXJkIHRoZSBuZXh0XG4gICAqIHNjZW5lLiBBIHRpbGUgcmVxdWVzdCdzIG93biBgc2lnbmFsYCAobmFwYXJpLWpzIGFib3J0cyBhIHJlYWQgaXQgbm8gbG9uZ2VyIG5lZWRzKSBhYm9ydHMgdGhlXG4gICAqIEhUVFAgcmVxdWVzdC5cbiAgICovXG4gIHRpbGVkU291cmNlKFxuICAgIGRlc2M6IFRpbGVEZXNjcmlwdG9yLFxuICAgIGNoYW5uZWw6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgICBjaGFubmVsczogMSB8IDQsXG4gICAgc2NlbmU/OiBBYm9ydFNpZ25hbCxcbiAgICBvblRpbGU/OiAoKSA9PiAoKSA9PiB2b2lkLFxuICApOiBUaWxlZFNvdXJjZSB7XG4gICAgY29uc3QgaW5mb0I2NCA9IHRoaXMudGlsZXMuZ2V0U2VsZWN0ZWRJbmZvQjY0KCkgPz8gJyc7XG4gICAgLy8gUGVyLWNoYW5uZWwgdGlsZXMgZXhpc3Qgb25seSBhdCBSRUFMIEJpby1Gb3JtYXRzIGxldmVsczsgdGhlIGNvbXBvc2l0ZSBleGlzdHMgYXQgYWxsIGxldmVscy5cbiAgICBjb25zdCB1c2FibGUgPVxuICAgICAgY2hhbm5lbCA9PSBudWxsID8gZGVzYy5sZXZlbHMgOiBkZXNjLmxldmVscy5zbGljZSgwLCBNYXRoLm1heCgxLCBkZXNjLnJlYWxMZXZlbHMgPz8gZGVzYy5sZXZlbHMubGVuZ3RoKSk7XG4gICAgY29uc3QgbGV2ZWxTY2FsZXMgPSB1c2FibGUubWFwKChsKSA9PiBkZXNjLndpZHRoIC8gTWF0aC5tYXgoMSwgbC53aWR0aCkpOyAvLyBsZXZlbC0wIHB4IHBlciBsZXZlbCBweFxuICAgIGNvbnN0IHRpbGVTaXplID0gZGVzYy50aWxlU2l6ZSB8fCBUSUxFX1NJWkU7XG4gICAgY29uc3QgYXBpID0gdGhpcy5hcGk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtpbmQ6ICd0aWxlZCcsXG4gICAgICB3aWR0aDogZGVzYy53aWR0aCxcbiAgICAgIGhlaWdodDogZGVzYy5oZWlnaHQsXG4gICAgICB0aWxlU2l6ZSxcbiAgICAgIGxldmVsczogdXNhYmxlLmxlbmd0aCxcbiAgICAgIGxldmVsU2NhbGVzLFxuICAgICAgZGVwdGg6IE1hdGgubWF4KDEsIGRlc2MueiB8fCAxKSxcbiAgICAgIGNoYW5uZWxzLFxuICAgICAgZHR5cGU6ICd1aW50OCcsXG4gICAgICBmZXRjaFRpbGU6IGFzeW5jIChrZXk6IFRpbGVLZXksIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxQaXhlbENodW5rPiA9PiB7XG4gICAgICAgIGNvbnN0IHJlcyA9IHVzYWJsZVtrZXkubGV2ZWxdPy5yZXMgPz8ga2V5LmxldmVsO1xuICAgICAgICBjb25zdCB1cmwgPSBidWlsZFRpbGVVcmwoYXBpLCBpbmZvQjY0LCB7XG4gICAgICAgICAgcmVzLFxuICAgICAgICAgIGNvbDoga2V5LmNvbCxcbiAgICAgICAgICByb3c6IGtleS5yb3csXG4gICAgICAgICAgejoga2V5LnosXG4gICAgICAgICAgdGlsZVNpemUsXG4gICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGVuZCA9ICFvblRpbGUgfHwgc2NlbmU/LmFib3J0ZWQgPyBudWxsIDogb25UaWxlKCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IGZldGNoV2l0aEF1dGgodGhpcy50aWxlcywgdXJsLCBzaWduYWwgPyB7IHNpZ25hbCB9IDoge30pO1xuICAgICAgICAgIGlmICghcmVzcC5vaykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbbmFwYXJpLWpzXSB0aWxlICR7a2V5LmxldmVsfS8ke2tleS5jb2x9LyR7a2V5LnJvd30g4oaSICR7cmVzcC5zdGF0dXN9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGJtcCA9IGF3YWl0IGNyZWF0ZUltYWdlQml0bWFwKGF3YWl0IHJlc3AuYmxvYigpKTtcbiAgICAgICAgICBpZiAoY2hhbm5lbHMgPT09IDQpIHJldHVybiB7IHdpZHRoOiBibXAud2lkdGgsIGhlaWdodDogYm1wLmhlaWdodCwgZGF0YTogYm1wIH07XG4gICAgICAgICAgcmV0dXJuIGJpdG1hcFRvTHVtaW5hbmNlKGJtcCk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgaWYgKCFzY2VuZT8uYWJvcnRlZCkgZW5kPy4oKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjb21wb3NpdGUgcHlyYW1pZCdzIFIsIEcgYW5kIEIgYmFuZHMgYXMgdGhyZWUgc2NhbGFyIHtAbGluayBUaWxlZFNvdXJjZX1zIOKAlCBvbmUgcGVyXG4gICAqIGFkZGl0aXZlIGxheWVyLCBzbyBlYWNoIGJhbmQgdGFrZXMgaXRzIG93biB3aW5kb3csIGdhbW1hLCBpbnZlcnQsIHRpbnQgYW5kIHZpc2liaWxpdHkg4oCUIHRoYXRcbiAgICogc2hhcmUgT05FIGAvdGlsZWAgcmVxdWVzdCBwZXIgdGlsZS4gVGhlIHRocmVlIGxheWVycyBhc2sgZm9yIGEgdGlsZSBpbiB0aGUgc2FtZSBmcmFtZTogdGhlXG4gICAqIGZpcnN0IGZldGNoZXMgdGhlIFJHQkEgdGlsZSBhbmQgc3BsaXRzIGl0LCB0aGUgb3RoZXIgdHdvIHRha2UgdGhlaXIgYmFuZCBmcm9tIHRoZSBzYW1lXG4gICAqIHByb21pc2UsIGFuZCB0aGUgc3BsaXQgdGlsZSBpcyBkcm9wcGVkIG9uY2UgYWxsIHRocmVlIGhhdmUgaXQuIEEgYmFuZCB0aGF0IGFza3MgbGF0ZXIgKG9uZVxuICAgKiBzaG93biBhZ2FpbiBhZnRlciBiZWluZyBoaWRkZW4pIGZpbmRzIGl0IGluIGEgc21hbGwgTFJVLCBlbHNlIGZldGNoZXMgaXQgYWdhaW4uIGBzY2VuZWAgYW5kXG4gICAqIGBvblRpbGVgIGFzIHtAbGluayB0aWxlZFNvdXJjZX06IHRoZSBsb2FkaW5nIGJhZGdlIGNvdW50cyB0aGUgb25lIHJlcXVlc3QuXG4gICAqL1xuICByZ2JCYW5kU291cmNlcyhkZXNjOiBUaWxlRGVzY3JpcHRvciwgc2NlbmU/OiBBYm9ydFNpZ25hbCwgb25UaWxlPzogKCkgPT4gKCkgPT4gdm9pZCk6IFRpbGVkU291cmNlW10ge1xuICAgIGNvbnN0IGNvbXBvc2l0ZSA9IHRoaXMudGlsZWRTb3VyY2UoZGVzYywgdW5kZWZpbmVkLCA0LCBzY2VuZSwgb25UaWxlKTtcbiAgICBjb25zdCBzcGxpdCA9IG5ldyBMcnVDYWNoZTx7IGJhbmRzOiBQcm9taXNlPEx1bWFQbGFuZVtdPjsgdGFrZW46IFNldDxudW1iZXI+IH0+KFJHQl9CQU5EX0NBQ0hFX1RJTEVTKTtcbiAgICBjb25zdCBiYW5kID0gKGtleTogVGlsZUtleSwgYjogbnVtYmVyKTogUHJvbWlzZTxQaXhlbENodW5rPiA9PiB7XG4gICAgICBjb25zdCBpZCA9IGAke2tleS56fS8ke2tleS5sZXZlbH0vJHtrZXkuY29sfS8ke2tleS5yb3d9YDtcbiAgICAgIGxldCBlbnRyeSA9IHNwbGl0LmdldChpZCk7XG4gICAgICBpZiAoIWVudHJ5KSB7XG4gICAgICAgIGNvbnN0IGJhbmRzID0gY29tcG9zaXRlLmZldGNoVGlsZShrZXkpLnRoZW4oY2h1bmtUb0JhbmRzKTtcbiAgICAgICAgY29uc3QgZnJlc2ggPSB7IGJhbmRzLCB0YWtlbjogbmV3IFNldDxudW1iZXI+KCkgfTtcbiAgICAgICAgLy8gQSBmYWlsZWQgdGlsZSBpcyBub3QgcmVtZW1iZXJlZDogdGhlIG5leHQgYXNrIGZldGNoZXMgaXQgYWdhaW4uXG4gICAgICAgIGJhbmRzLmNhdGNoKCgpID0+IHNwbGl0LmdldChpZCkgPT09IGZyZXNoICYmIHNwbGl0LmRlbGV0ZShpZCkpO1xuICAgICAgICBzcGxpdC5zZXQoaWQsIChlbnRyeSA9IGZyZXNoKSk7XG4gICAgICB9XG4gICAgICBlbnRyeS50YWtlbi5hZGQoYik7XG4gICAgICBpZiAoZW50cnkudGFrZW4uc2l6ZSA9PT0gMykgc3BsaXQuZGVsZXRlKGlkKTtcbiAgICAgIHJldHVybiBlbnRyeS5iYW5kcy50aGVuKChwbGFuZXMpID0+IHBsYW5lc1tiXSk7XG4gICAgfTtcbiAgICByZXR1cm4gWzAsIDEsIDJdLm1hcCgoYik6IFRpbGVkU291cmNlID0+ICh7XG4gICAgICAuLi5jb21wb3NpdGUsXG4gICAgICBjaGFubmVsczogMSxcbiAgICAgIGZldGNoVGlsZTogKGtleTogVGlsZUtleSkgPT4gYmFuZChrZXksIGIpLFxuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlbWJsZSBhIGRvd25zYW1wbGVkIHVpbnQ4IHZvbHVtZSAobHVtaW5hbmNlKSBvZiBgaW5mb2AncyBzdGFjayB3aXRoIG5hcGFyaS1qcydzXG4gICAqIGBhc3NlbWJsZVZvbHVtZWA6IGV2ZXJ5IGBzbGljZVN0ZXBgdGggc2xpY2UsIHJlYWQgZnJvbSB0aGUgYmFuZCdzIChvciBjb21wb3NpdGUncykgcHlyYW1pZCBhdFxuICAgKiB0aGUgbGV2ZWwgdGhhdCBgbWF4U2xpY2VgIG5lZWRzLCB3aXRoaW4gaXRzIHRpbGUgYnVkZ2V0LCBhbmQgYXJlYS1hdmVyYWdlZCB0byBgbWF4U2xpY2VgIG9uXG4gICAqIHRoZSBsb25nZXN0IHNpZGUuIFNsaWNlcyBhcmUgcmVhZCB3aXRoIGJvdW5kZWQgY29uY3VycmVuY3kgKHRoZSBjb25uZWN0aW9uIHBvb2wgc3RheXMgZnVsbFxuICAgKiB3aXRob3V0IGZsb29kaW5nIGl0IG9uIGEgZGVlcCBzdGFjayksIGVhY2ggcmVwb3J0aW5nIGBwcm9ncmVzc2AgKDDigJMxMDApIGFzIGl0IGxhbmRzIHNvIHRoZSBob3N0XG4gICAqIHNob3dzIGEgZGV0ZXJtaW5hdGUgcHJvZ3Jlc3MgYmFyLiBOdWxsIHdoZW4gYHNpZ25hbGAgYWJvcnRzIChhIENhbmNlbCBvciBhIG5ldyBwbG90KSwgd2hpY2hcbiAgICogYWxzbyBhYm9ydHMgdGhlIHRpbGUgcmVxdWVzdHMgaW4gZmxpZ2h0IOKAlCBhIHBhcnRpYWwgdm9sdW1lIGlzIG5ldmVyIHJldHVybmVkLlxuICAgKi9cbiAgYXN5bmMgYXNzZW1ibGVWb2x1bWUoXG4gICAgaW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCxcbiAgICBvcHRzOiB7IG1heFNsaWNlPzogbnVtYmVyOyBzbGljZVN0ZXA/OiBudW1iZXIgfSxcbiAgICBjaGFubmVsOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gICAgaG9va3M6IHsgc2lnbmFsOiBBYm9ydFNpZ25hbDsgcHJvZ3Jlc3MocGVyY2VudDogbnVtYmVyKTogdm9pZCB9LFxuICApOiBQcm9taXNlPEFzc2VtYmxlZFZvbHVtZSB8IG51bGw+IHtcbiAgICBjb25zdCB7IHNpZ25hbCB9ID0gaG9va3M7XG4gICAgY29uc3QgZnVsbERlcHRoID0gc3RhY2tEZXB0aChpbmZvKSB8fCAxO1xuICAgIGNvbnN0IHN0ZXAgPSBNYXRoLm1heCgxLCBNYXRoLmZsb29yKG9wdHMuc2xpY2VTdGVwID8/IDEpKTtcbiAgICBjb25zdCBtYXhTbGljZSA9IG9wdHMubWF4U2xpY2UgPz8gVk9MVU1FX01BWF9TTElDRTtcbiAgICAvLyBTb3VyY2Utc2xpY2UgaW5kaWNlcyBzYW1wbGVkIGludG8gdGhlIHZvbHVtZSAoZXZlcnkgYHN0ZXBgdGggcGxhbmUg4oaSIGxvdy1yZXMgaXMgZmFzdGVyKS5cbiAgICBjb25zdCB6SW5kaWNlczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCB6ID0gMDsgeiA8IGZ1bGxEZXB0aDsgeiArPSBzdGVwKSB6SW5kaWNlcy5wdXNoKHopO1xuXG4gICAgaG9va3MucHJvZ3Jlc3MoMCk7XG4gICAgdHJ5IHtcbiAgICAgIC8vIGBjaGFubmVsYCBzZWxlY3RzIGEgYmFuZCAobXVsdGljaGFubmVsIHZvbHVtZSk7IG9taXQgZm9yIHRoZSBncmF5c2NhbGUgY29tcG9zaXRlLiBUaGVcbiAgICAgIC8vIGNhbGxlciBvd25zIHRoZSBzdGFja0xvYWRpbmcgZmxhZyAobXVsdGljaGFubmVsIGFzc2VtYmxlcyBjaGFubmVscyBpbiB0dXJuKS5cbiAgICAgIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHRoaXMudm9sdW1lU291cmNlKGluZm8sIGNoYW5uZWwsIHpJbmRpY2VzWzBdKTtcbiAgICAgIHJldHVybiBhd2FpdCBhc3NlbWJsZVZvbHVtZShzb3VyY2UsIHpJbmRpY2VzLCB7XG4gICAgICAgIG1heFNpZGU6IG1heFNsaWNlLFxuICAgICAgICBtYXhUaWxlczogdGhpcy50aWxlQnVkZ2V0Rm9yKGluZm8sIG1heFNsaWNlKSxcbiAgICAgICAgbWF4VGV4dHVyZURpbTogTUFYX1RFWFRVUkVfRElNLFxuICAgICAgICBjb25jdXJyZW5jeTogVk9MVU1FX0ZFVENIX0NPTkNVUlJFTkNZLFxuICAgICAgICB0aWxlQ29uY3VycmVuY3k6IFRJTEVfRkVUQ0hfQ09OQ1VSUkVOQ1ksXG4gICAgICAgIG9uUHJvZ3Jlc3M6IChkb25lLCB0b3RhbCkgPT4gaG9va3MucHJvZ3Jlc3MoTWF0aC5yb3VuZCgoZG9uZSAvIHRvdGFsKSAqIDEwMCkpLFxuICAgICAgICBzaWduYWwsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChzaWduYWwuYWJvcnRlZCkgcmV0dXJuIG51bGw7IC8vIGNhbmNlbGxlZCDihpIgZG9uJ3QgcmVuZGVyIGEgcGFydGlhbCB2b2x1bWVcbiAgICAgIHRocm93IGVycjtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgaG9va3MucHJvZ3Jlc3MoMCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBzY2FsYXIgc291cmNlIGEgdm9sdW1lIHJlYWRzOiB0aGUgYmFuZCdzIChvciBjb21wb3NpdGUncykgcHlyYW1pZDsgd2l0aG91dCBvbmUsIG9uZSB3aG9sZVxuICAgKiBpbWFnZSBwZXIgc2xpY2UgKHtAbGluayBmZXRjaEltYWdlfSkgYXMgYSBzaW5nbGUtdGlsZSBsZXZlbCBzaXplZCBieSB0aGUgZmlyc3Qgc2xpY2UsIHdoaWNoIGlzXG4gICAqIGZldGNoZWQgaGVyZSBhbmQgc2VydmVkIGFnYWluIGFzIHRoYXQgc2xpY2UncyB0aWxlLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2b2x1bWVTb3VyY2UoaW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCwgY2hhbm5lbDogbnVtYmVyIHwgdW5kZWZpbmVkLCBmaXJzdFo6IG51bWJlcikge1xuICAgIGNvbnN0IGRlc2MgPSB0aGlzLnNpbXBsZVN0YWNrLmlzU2ltcGxlKGluZm8pID8gbnVsbCA6IGF3YWl0IHRoaXMuZW5zdXJlRGVzY3JpcHRvcihpbmZvKTtcbiAgICBpZiAoZGVzYz8ubGV2ZWxzPy5sZW5ndGgpIHJldHVybiB0aGlzLnRpbGVkU291cmNlKGRlc2MsIGNoYW5uZWwsIDEpO1xuICAgIGxldCBmaXJzdDogSW1hZ2VCaXRtYXAgfCBudWxsID0gYXdhaXQgdGhpcy5mZXRjaEltYWdlKGluZm8sIGZpcnN0WiwgY2hhbm5lbCk7XG4gICAgY29uc3Qgc291cmNlOiBUaWxlZFNvdXJjZSA9IHtcbiAgICAgIGtpbmQ6ICd0aWxlZCcsXG4gICAgICB3aWR0aDogZmlyc3Qud2lkdGgsXG4gICAgICBoZWlnaHQ6IGZpcnN0LmhlaWdodCxcbiAgICAgIHRpbGVTaXplOiBNYXRoLm1heCgxLCBmaXJzdC53aWR0aCwgZmlyc3QuaGVpZ2h0KSxcbiAgICAgIGxldmVsczogMSxcbiAgICAgIGRlcHRoOiBzdGFja0RlcHRoKGluZm8pIHx8IDEsXG4gICAgICBjaGFubmVsczogMSxcbiAgICAgIGR0eXBlOiAndWludDgnLFxuICAgICAgZmV0Y2hUaWxlOiBhc3luYyAoa2V5OiBUaWxlS2V5KTogUHJvbWlzZTxQaXhlbENodW5rPiA9PiB7XG4gICAgICAgIGxldCBibXA6IEltYWdlQml0bWFwO1xuICAgICAgICBpZiAoZmlyc3QgJiYga2V5LnogPT09IGZpcnN0Wikge1xuICAgICAgICAgIGJtcCA9IGZpcnN0O1xuICAgICAgICAgIGZpcnN0ID0gbnVsbDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBibXAgPSBhd2FpdCB0aGlzLmZldGNoSW1hZ2UoaW5mbywga2V5LnosIGNoYW5uZWwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IHdpZHRoOiBibXAud2lkdGgsIGhlaWdodDogYm1wLmhlaWdodCwgZGF0YTogYm1wIH07XG4gICAgICB9LFxuICAgIH07XG4gICAgcmV0dXJuIHNvdXJjZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbGljZSBgemAgYXMgYSBzaW5nbGUgV0hPTEUtaW1hZ2UgbHVtaW5hbmNlIHBsYW5lIChkZWNpbWF0ZWQgdG8gYG1heEdyaWRgKSwgZm9yIHRoZSBzdXJmYWNlLlxuICAgKiBQcmVmZXJzIHRoZSBzZXJ2ZXIgcHlyYW1pZCwgcmVhZCBhdCB0aGUgbGV2ZWwgdGhlIGdyaWQgbmVlZHMgKHtAbGluayByZWFkUGxhbmV9LCB3aGljaCBtYXlcbiAgICogZHJvcCBhIGJhbmQgdG8gdGhlIGNvbXBvc2l0ZSBvdmVydmlldyk7IHdpdGhvdXQgYSBkZXNjcmlwdG9yLCB0aGUgYXBwJ3MgY29tcGxldGUgcGVyLXNsaWNlXG4gICAqIGltYWdlIChgdXJsc2AvYHNtYWxsVXJsc2AsIGFzIHRoZSBQbG90bHkgc3VyZmFjZSkg4oCUIG5ldmVyIGEgbG9uZSB0b3AtbGVmdCB0aWxlLCB3aGljaCB3b3VsZCBiZVxuICAgKiBhIGNvcm5lciBvZiB0aGUgc2xpY2Ug4oCUIGFuZCBvbmx5IGFzIGEgbGFzdCByZXNvcnQgdGhlIHNpbmdsZS10aWxlIGZldGNoLlxuICAgKi9cbiAgYXN5bmMgZmV0Y2hQbGFuZShcbiAgICBpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkLFxuICAgIHo6IG51bWJlcixcbiAgICBjaGFubmVsOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gICAgbWF4R3JpZDogbnVtYmVyLFxuICApOiBQcm9taXNlPEx1bWFQbGFuZT4ge1xuICAgIGNvbnN0IGRlc2MgPSBhd2FpdCB0aGlzLmVuc3VyZURlc2NyaXB0b3IoaW5mbyk7XG4gICAgLy8gUHJlZmVycmVkOiB0aGUgV0hPTEUgc2xpY2UgZnJvbSB0aGUgc2VydmVyIHB5cmFtaWQgYXQgYSByZXNvbHV0aW9uIGRyaXZlbiBieSB0aGUgZGVjaW1hdGVcbiAgICAvLyBmYWN0b3Ig4oCUIGEgaGlnaGVyIHRhcmdldCBncmlkIHJlYWRzIGEgRklORVIgcHlyYW1pZCBsZXZlbCAobW9yZSByZWFsIGRldGFpbCkuIFRoaXMgaXMgd2hhdFxuICAgIC8vIG1ha2VzIFwiRnVsbFwiIGFjdHVhbGx5IGhpZ2hlci1yZXMgdGhhbiBcIsK9XCIsIG5vdCBqdXN0IGEgZml4ZWQgcHJldmlldy4gVGhlIHN1cmZhY2UgaXMgYSBzaW5nbGVcbiAgICAvLyBkZWNpbWF0ZWQgcGxhbmUsIHNvIHRoZSBjb21wb3NpdGUgZmFsbGJhY2sgaXMgYWNjZXB0YWJsZSB3aGVuIHRoZSBiYW5kIGhhcyBubyBzbWFsbCBsZXZlbC5cbiAgICBpZiAoZGVzYz8ubGV2ZWxzPy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0aGlzLnJlYWRQbGFuZShpbmZvLCB6LCBjaGFubmVsLCB7XG4gICAgICAgIG1heFRpbGVzOiB0aGlzLnRpbGVCdWRnZXRGb3IoaW5mbywgbWF4R3JpZCksXG4gICAgICAgIG1heFNpZGU6IG1heEdyaWQsXG4gICAgICAgIGNvbXBvc2l0ZUZhbGxiYWNrOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgKG5vIHB5cmFtaWQpOiB0aGUgYXBwJ3MgQ09NUExFVEUgcGVyLXNsaWNlIGltYWdlICh1cmxzW3pdLCBub3QgdGhlIHNtYWxsIGJsdXJyeVxuICAgIC8vIHRodW1ibmFpbCkg4oCUIHdob2xlIHNsaWNlLCBhdm9pZHMgYSBjb3JuZXIgdGlsZS4gQ2FwcGVkIGF0IHRoZSBpbWFnZSdzIG93biByZXNvbHV0aW9uLlxuICAgIGNvbnN0IHVybCA9IGluZm8/LnVybHM/Llt6XSA/PyBpbmZvPy5zbWFsbFVybHM/Llt6XTtcbiAgICBpZiAodXJsKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwID0gYXdhaXQgZmV0Y2hXaXRoQXV0aCh0aGlzLnRpbGVzLCB1cmwpO1xuICAgICAgICBpZiAocmVzcC5vaykgcmV0dXJuIGJpdG1hcFRvTHVtaW5hbmNlKGF3YWl0IGNyZWF0ZUltYWdlQml0bWFwKGF3YWl0IHJlc3AuYmxvYigpKSwgbWF4R3JpZCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbbmFwYXJpLWpzXSBzdXJmYWNlIHVybCBmZXRjaCBmYWlsZWQgZm9yIHo9JHt6fWAsIGVycik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gTGFzdCByZXNvcnQgKG5vIHB5cmFtaWQgYW5kIG5vIGNvbXBsZXRlIGltYWdlKTogdGhlIHNpbmdsZSBpbWFnZS5cbiAgICByZXR1cm4gYml0bWFwVG9MdW1pbmFuY2UoYXdhaXQgdGhpcy5mZXRjaEltYWdlKGluZm8sIHosIGNoYW5uZWwpLCBtYXhHcmlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGFubmVsIGBjaGFubmVsYCdzIG5hdGl2ZS1iaXQtZGVwdGggaGlzdG9ncmFtIGF0IHNsaWNlIGB6YCB3aGVuIGBpbmZvYCBpcyBhID44LWJpdCBpbWFnZSDigJRcbiAgICogdGhlIGRpc3BsYXllZCBwaXhlbHMgYXJlIDgtYml0LCBzbyBhIGNsaWVudCBoaXN0b2dyYW0gd291bGQgYmUgY2xpcHBlZCDigJQgY2FjaGVkIHBlclxuICAgKiBgKHosIGNoYW5uZWwpYDsgbnVsbCBmb3IgYW4gOC1iaXQgY2hhbm5lbCwgd2hpY2ggdGhlIGNhbGxlciBiaW5zIGZyb20gdGhlIGNsaWVudCBkYXRhLlxuICAgKi9cbiAgbmF0aXZlSGlzdG9ncmFtJChcbiAgICBpbmZvOiBJSW1hZ2VJbmZvIHwgdW5kZWZpbmVkLFxuICAgIHo6IG51bWJlcixcbiAgICBjaGFubmVsOiBudW1iZXIsXG4gICAgYmluczogbnVtYmVyLFxuICApOiBPYnNlcnZhYmxlPElIaXN0b2dyYW0gfCBudWxsPiB8IG51bGwge1xuICAgIGNvbnN0IGJpdERlcHRoID0gdGhpcy5jdXJyZW50RGVzY3JpcHRvcihpbmZvKT8uY2hhbm5lbEluZm8/LltjaGFubmVsXT8uYml0RGVwdGggPz8gODtcbiAgICBpZiAoYml0RGVwdGggPD0gOCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3Qga2V5ID0gYCR7en18JHtjaGFubmVsfWA7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5uYXRpdmVIaXN0b2dyYW1zLmdldChrZXkpO1xuICAgIGlmIChjYWNoZWQpIHJldHVybiBvZihjYWNoZWQpO1xuICAgIHJldHVybiBmcm9tKHRoaXMuZmV0Y2hOYXRpdmVIaXN0b2dyYW0oY2hhbm5lbCwgYmlucywgeiwga2V5KSk7XG4gIH1cblxuICAvKiogRmV0Y2ggKyBjYWNoZSBvbmUgY2hhbm5lbCdzIG5hdGl2ZS1iaXQtZGVwdGggaGlzdG9ncmFtIGZyb20gYEdFVCAvaGlzdG9ncmFtYCAoPjgtYml0KSxcbiAgICogIHRocm91Z2ggdGhlIHNoYXJlZCBqaXQtc2VydmljZSBjbGllbnQg4oCUIHdob3NlIFVSTCBjYXJyaWVzIHRoZSBwZXItYXBwLWxvYWQgY2FjaGUtYnVzdGVyXG4gICAqICB0aGlzIGJhY2tlbmQgdXNlZCB0byBvbWl0LCBzbyBhIHJlbG9hZCBzaG93ZWQgdGhlIHNlcnZlcidzIDI0IGgtY2FjaGVkIGhpc3RvZ3JhbS4gKi9cbiAgYXN5bmMgZmV0Y2hOYXRpdmVIaXN0b2dyYW0oY2hhbm5lbDogbnVtYmVyLCBiaW5zOiBudW1iZXIsIHo6IG51bWJlciwga2V5OiBzdHJpbmcpOiBQcm9taXNlPElIaXN0b2dyYW0gfCBudWxsPiB7XG4gICAgY29uc3QgaW5mb0I2NCA9IHRoaXMudGlsZXMuZ2V0U2VsZWN0ZWRJbmZvQjY0KCk7XG4gICAgaWYgKCFpbmZvQjY0KSByZXR1cm4gbnVsbDtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3V0ID0gYXdhaXQgbmF0aXZlSGlzdG9ncmFtKGZldGNoSnNvbldpdGhBdXRoKHRoaXMudGlsZXMpLCB0aGlzLmFwaSwgaW5mb0I2NCwge1xuICAgICAgICB6LFxuICAgICAgICBjaGFubmVsLFxuICAgICAgICBiaW5zLFxuICAgICAgfSk7XG4gICAgICBpZiAoIW91dCkgcmV0dXJuIG51bGw7IC8vIDIwMiAoc3RpbGwgY2FjaGluZykgb3IgdHJhbnNpZW50IOKGkiBudWxsOyB0aGUgcGFuZSByZXRyaWVzXG4gICAgICB0aGlzLm5hdGl2ZUhpc3RvZ3JhbXMuc2V0KGtleSwgb3V0KTtcbiAgICAgIHJldHVybiBvdXQ7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIG5hdGl2ZSBoaXN0b2dyYW0gZmV0Y2ggZmFpbGVkJywgZXJyKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBOYXRpdmUtYml0LWRlcHRoICgxNi8zMi1iaXQpIG11bHRpLWJhbmQgVElGRiBleHBvcnQgb2Ygc2xpY2UgYHpgIHZpYSB0aGUgc2VydmVyXG4gICAqICBgL2V4cG9ydC90aWZmYCBlbmRwb2ludCDigJQgdGhlIGRpc3BsYXllZCBQTkcgaXMgYW4gOC1iaXQgZmlndXJlLCB0aGlzIHByZXNlcnZlcyB0aGUgdHJ1ZSBwaXhlbFxuICAgKiAgdmFsdWVzLiBWaXNpYmxlIGNoYW5uZWxzIG9ubHkgKG9taXR0ZWQgd2hlbiBhbGwgYXJlIHZpc2libGUg4oaSIHNlcnZlciBkZWZhdWx0KS4gTWlycm9ycyB0aGVcbiAgICogIE9TRCBiYWNrZW5kLiAqL1xuICBhc3luYyBleHBvcnRUaWZmKHo6IG51bWJlciwgc3RhdGVzOiBJQ2hhbm5lbFN0YXRlW10sIGZpbGVOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBpbmZvQjY0ID0gdGhpcy50aWxlcy5nZXRTZWxlY3RlZEluZm9CNjQoKTtcbiAgICBpZiAoIWluZm9CNjQpIHJldHVybjtcbiAgICBjb25zdCB2aXNpYmxlID0gc3RhdGVzLmZpbHRlcigoYykgPT4gYy52aXNpYmxlKS5tYXAoKGMpID0+IGMuaW5kZXgpO1xuICAgIGNvbnN0IHVybCA9IGV4cG9ydFRpZmZVcmwodGhpcy5hcGksIGluZm9CNjQsIHosIHZpc2libGUsIHN0YXRlcy5sZW5ndGgpO1xuICAgIGNvbnN0IHNhdmVOYW1lID0gZXhwb3J0VGlmZkZpbGVuYW1lKGZpbGVOYW1lKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IGZldGNoV2l0aEF1dGgodGhpcy50aWxlcywgdXJsKTtcbiAgICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAyKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW25hcGFyaS1qc10gMTYtYml0IGV4cG9ydDogZmlsZSBzdGlsbCBjYWNoaW5nIOKAlCB0cnkgYWdhaW4gc2hvcnRseS4nKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKCFyZXNwLm9rKSB0aHJvdyBuZXcgRXJyb3IoYHN0YXR1cyAke3Jlc3Auc3RhdHVzfWApO1xuICAgICAgc2F2ZUFzKGF3YWl0IHJlc3AuYmxvYigpLCBzYXZlTmFtZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIDE2LWJpdCBUSUZGIGV4cG9ydCBmYWlsZWQnLCBlcnIpO1xuICAgIH1cbiAgfVxufVxuIl19