@jax-data-science/sci-image-visualizer 0.1.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.
- package/LICENSE +21 -0
- package/README.md +404 -0
- package/esm2022/index.mjs +52 -0
- package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
- package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
- package/esm2022/lib/contracts/display-types.mjs +8 -0
- package/esm2022/lib/contracts/image.contract.mjs +11 -0
- package/esm2022/lib/contracts/intensity.mjs +28 -0
- package/esm2022/lib/contracts/plot-type.mjs +112 -0
- package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
- package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
- package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
- package/esm2022/lib/contracts/sam.contract.mjs +12 -0
- package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
- package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
- package/esm2022/lib/contracts/viz-config.mjs +3 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
- package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
- package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
- package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
- package/esm2022/lib/models/bezier.mjs +120 -0
- package/esm2022/lib/models/class-preset.mjs +46 -0
- package/esm2022/lib/models/geometry.mjs +198 -0
- package/esm2022/lib/models/region.mjs +166 -0
- package/esm2022/lib/models/shape.mjs +53 -0
- package/esm2022/lib/plot.utilities.mjs +693 -0
- package/esm2022/lib/processing/image-converter.service.mjs +90 -0
- package/esm2022/lib/processing/image-crop.mjs +62 -0
- package/esm2022/lib/processing/processing-image.mjs +50 -0
- package/esm2022/lib/provide-visualization.mjs +63 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
- package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
- package/esm2022/lib/region-ops.service.mjs +301 -0
- package/esm2022/lib/render-orchestrator.mjs +87 -0
- package/esm2022/lib/routing-visualizer.service.mjs +533 -0
- package/esm2022/lib/store/class-color.util.mjs +52 -0
- package/esm2022/lib/store/region-store.service.mjs +1029 -0
- package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
- package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
- package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
- package/esm2022/lib/visualization.module.mjs +162 -0
- package/esm2022/lib/visualizer.component.mjs +1597 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
- package/fesm2022/mask.worker.js +989 -0
- package/fesm2022/onnx-sam.worker.js +202 -0
- package/index.d.ts +39 -0
- package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
- package/lib/contracts/capabilities.contract.d.ts +30 -0
- package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
- package/lib/contracts/colormap-lut.d.ts +21 -0
- package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
- package/lib/contracts/display-types.d.ts +41 -0
- package/lib/contracts/image.contract.d.ts +72 -0
- package/lib/contracts/intensity.d.ts +18 -0
- package/lib/contracts/plot-type.d.ts +108 -0
- package/lib/contracts/ports/image-state.port.d.ts +29 -0
- package/lib/contracts/ports/preferences.port.d.ts +19 -0
- package/lib/contracts/ports/region-io.port.d.ts +29 -0
- package/lib/contracts/ports/tile-access.port.d.ts +27 -0
- package/lib/contracts/region-editor-api.contract.d.ts +83 -0
- package/lib/contracts/region-overlay.contract.d.ts +47 -0
- package/lib/contracts/region-store.contract.d.ts +74 -0
- package/lib/contracts/sam.contract.d.ts +98 -0
- package/lib/contracts/toolbar-config.d.ts +24 -0
- package/lib/contracts/visualizer.contract.d.ts +346 -0
- package/lib/contracts/viz-config.d.ts +25 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
- package/lib/implementations/base-store-visualizer.d.ts +71 -0
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
- package/lib/implementations/osd/display-pipeline.d.ts +47 -0
- package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
- package/lib/implementations/osd/osd-coords.d.ts +16 -0
- package/lib/implementations/osd/osd-lib.d.ts +19 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
- package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
- package/lib/implementations/osd/slice-cache.d.ts +161 -0
- package/lib/implementations/osd/tile-client.d.ts +32 -0
- package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
- package/lib/implementations/plotly/plotly.service.d.ts +594 -0
- package/lib/implementations/simple-slice-access.service.d.ts +64 -0
- package/lib/models/bezier.d.ts +59 -0
- package/lib/models/class-preset.d.ts +39 -0
- package/lib/models/geometry.d.ts +66 -0
- package/lib/models/region.d.ts +132 -0
- package/lib/models/shape.d.ts +44 -0
- package/lib/plot.utilities.d.ts +107 -0
- package/lib/processing/image-converter.service.d.ts +28 -0
- package/lib/processing/image-crop.d.ts +18 -0
- package/lib/processing/processing-image.d.ts +17 -0
- package/lib/provide-visualization.d.ts +34 -0
- package/lib/region-editor/mask-raster.d.ts +61 -0
- package/lib/region-editor/mask-worker.d.ts +7 -0
- package/lib/region-editor/region-editor.component.d.ts +305 -0
- package/lib/region-ops.service.d.ts +92 -0
- package/lib/render-orchestrator.d.ts +59 -0
- package/lib/routing-visualizer.service.d.ts +227 -0
- package/lib/store/class-color.util.d.ts +26 -0
- package/lib/store/region-store.service.d.ts +315 -0
- package/lib/store/visualizer-store.service.d.ts +123 -0
- package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
- package/lib/toolbar/crop/slide-crop.d.ts +30 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
- package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
- package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
- package/lib/toolbar/toolbar.component.d.ts +167 -0
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
- package/lib/toolbar/wand/wand.service.d.ts +133 -0
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
- package/lib/visualization.module.d.ts +45 -0
- package/lib/visualizer.component.d.ts +378 -0
- package/package.json +73 -0
- package/src/lib/assets/3d-coordinates.svg +49 -0
- package/src/lib/assets/cells.svg +1 -0
- package/src/lib/assets/click.svg +1 -0
- package/src/lib/assets/colormap-luts.json +1 -0
- package/src/lib/assets/contour.svg +48 -0
- package/src/lib/assets/cube-3d.svg +1 -0
- package/src/lib/assets/edit-selection-white.svg +47 -0
- package/src/lib/assets/heatmap.svg +1 -0
- package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
- package/src/lib/assets/icons/colormap-accent.png +0 -0
- package/src/lib/assets/icons/colormap-afmhot.png +0 -0
- package/src/lib/assets/icons/colormap-autumn.png +0 -0
- package/src/lib/assets/icons/colormap-berlin.png +0 -0
- package/src/lib/assets/icons/colormap-binary.png +0 -0
- package/src/lib/assets/icons/colormap-blackbody.png +0 -0
- package/src/lib/assets/icons/colormap-bluered.png +0 -0
- package/src/lib/assets/icons/colormap-blues.png +0 -0
- package/src/lib/assets/icons/colormap-bone.png +0 -0
- package/src/lib/assets/icons/colormap-brbg.png +0 -0
- package/src/lib/assets/icons/colormap-brg.png +0 -0
- package/src/lib/assets/icons/colormap-bugn.png +0 -0
- package/src/lib/assets/icons/colormap-bupu.png +0 -0
- package/src/lib/assets/icons/colormap-bwr.png +0 -0
- package/src/lib/assets/icons/colormap-cividis.png +0 -0
- package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
- package/src/lib/assets/icons/colormap-cool.png +0 -0
- package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
- package/src/lib/assets/icons/colormap-copper.png +0 -0
- package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
- package/src/lib/assets/icons/colormap-dark2.png +0 -0
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-electric.png +0 -0
- package/src/lib/assets/icons/colormap-flag.png +0 -0
- package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
- package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
- package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
- package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
- package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
- package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
- package/src/lib/assets/icons/colormap-gnbu.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
- package/src/lib/assets/icons/colormap-gray.png +0 -0
- package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greens.png +0 -0
- package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greys.png +0 -0
- package/src/lib/assets/icons/colormap-hot.png +0 -0
- package/src/lib/assets/icons/colormap-hsv.png +0 -0
- package/src/lib/assets/icons/colormap-inferno.png +0 -0
- package/src/lib/assets/icons/colormap-jet.png +0 -0
- package/src/lib/assets/icons/colormap-magma.png +0 -0
- package/src/lib/assets/icons/colormap-managua.png +0 -0
- package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
- package/src/lib/assets/icons/colormap-ocean.png +0 -0
- package/src/lib/assets/icons/colormap-oranges.png +0 -0
- package/src/lib/assets/icons/colormap-orrd.png +0 -0
- package/src/lib/assets/icons/colormap-pastel2.png +0 -0
- package/src/lib/assets/icons/colormap-picnic.png +0 -0
- package/src/lib/assets/icons/colormap-pink.png +0 -0
- package/src/lib/assets/icons/colormap-piyg.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-plasma.png +0 -0
- package/src/lib/assets/icons/colormap-portland.png +0 -0
- package/src/lib/assets/icons/colormap-prgn.png +0 -0
- package/src/lib/assets/icons/colormap-prism.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/icons/colormap-pubugn.png +0 -0
- package/src/lib/assets/icons/colormap-puor.png +0 -0
- package/src/lib/assets/icons/colormap-purd.png +0 -0
- package/src/lib/assets/icons/colormap-purples.png +0 -0
- package/src/lib/assets/icons/colormap-rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-rdbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdgy.png +0 -0
- package/src/lib/assets/icons/colormap-rdpu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
- package/src/lib/assets/icons/colormap-reds.png +0 -0
- package/src/lib/assets/icons/colormap-seismic.png +0 -0
- package/src/lib/assets/icons/colormap-set1.png +0 -0
- package/src/lib/assets/icons/colormap-set2.png +0 -0
- package/src/lib/assets/icons/colormap-set3.png +0 -0
- package/src/lib/assets/icons/colormap-spectral.png +0 -0
- package/src/lib/assets/icons/colormap-spring.png +0 -0
- package/src/lib/assets/icons/colormap-summer.png +0 -0
- package/src/lib/assets/icons/colormap-tab10.png +0 -0
- package/src/lib/assets/icons/colormap-tab20.png +0 -0
- package/src/lib/assets/icons/colormap-tab20b.png +0 -0
- package/src/lib/assets/icons/colormap-tab20c.png +0 -0
- package/src/lib/assets/icons/colormap-terrain.png +0 -0
- package/src/lib/assets/icons/colormap-turbo.png +0 -0
- package/src/lib/assets/icons/colormap-twilight.png +0 -0
- package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
- package/src/lib/assets/icons/colormap-vanimo.png +0 -0
- package/src/lib/assets/icons/colormap-viridis.png +0 -0
- package/src/lib/assets/icons/colormap-winter.png +0 -0
- package/src/lib/assets/icons/colormap-wistia.png +0 -0
- package/src/lib/assets/icons/colormap-ylgn.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
- package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
- package/src/lib/assets/invert.svg +1 -0
- package/src/lib/assets/isosurface.svg +7 -0
- package/src/lib/assets/mask.svg +1 -0
- package/src/lib/assets/paintbrush.svg +1 -0
- package/src/lib/assets/picture-segmentation.svg +43 -0
- package/src/lib/assets/polygon-vertices.svg +13 -0
- package/src/lib/assets/polyline.svg +3 -0
- package/src/lib/assets/redo.svg +39 -0
- package/src/lib/assets/region-editor.svg +37 -0
- package/src/lib/assets/region-move.svg +7 -0
- package/src/lib/assets/smooth.svg +56 -0
- package/src/lib/assets/spline-chart.svg +7 -0
- package/src/lib/assets/surface.svg +37 -0
- package/src/lib/assets/test/download-379.svg +1 -0
- package/src/lib/assets/test/download-98.svg +1 -0
- package/src/lib/assets/test/json-1.svg +1 -0
- package/src/lib/assets/test/load-53.svg +1 -0
- package/src/lib/assets/test/mask-44.svg +1 -0
- package/src/lib/assets/test/mask-download-44.svg +15 -0
- package/src/lib/assets/test/mask-save-44.svg +11 -0
- package/src/lib/assets/test/overlay-1.svg +1 -0
- package/src/lib/assets/test/overlay-4.svg +1 -0
- package/src/lib/assets/test/region-26.svg +1 -0
- package/src/lib/assets/test/save-56.svg +1 -0
- package/src/lib/assets/test/upload-43.svg +1 -0
- package/src/lib/assets/to-bezier.svg +15 -0
- package/src/lib/assets/to-polygon.svg +11 -0
- package/src/lib/assets/undo.svg +38 -0
- package/src/lib/assets/vertex-add.svg +12 -0
- package/src/lib/assets/vertex-delete.svg +12 -0
- package/src/lib/assets/wand.svg +54 -0
- package/src/lib/assets/zoom-box.svg +10 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import { OSD } from './osd-lib';
|
|
2
|
+
export class SliceCache {
|
|
3
|
+
constructor(host) {
|
|
4
|
+
this.host = host;
|
|
5
|
+
/** z-slice → its TiledImage in the viewer world (composite path). */
|
|
6
|
+
this.sliceItems = new Map();
|
|
7
|
+
/** Multichannel per-slice cache: z → the N channel TiledImages for that slice
|
|
8
|
+
* (additively composited by OSD; index = channel). Only the active slice's
|
|
9
|
+
* visible channels have opacity > 0. */
|
|
10
|
+
this.channelSliceItems = new Map();
|
|
11
|
+
/** Cached multichannel slices whose tiles were tinted before the latest
|
|
12
|
+
* display change; re-tinted lazily when next revealed by z-scrub. */
|
|
13
|
+
this.staleSlices = new Set();
|
|
14
|
+
/** Most-recently-shown z last; drives LRU eviction. */
|
|
15
|
+
this.sliceLru = [];
|
|
16
|
+
/** z-slices whose tiled image is being added (dedupe rapid scrubbing). */
|
|
17
|
+
this.slicesLoading = new Set();
|
|
18
|
+
/** Bumped whenever the loaded image changes; in-flight background slice adds
|
|
19
|
+
* captured under an older token are dropped (cancelled image switch). */
|
|
20
|
+
this.sliceLoadToken = 0;
|
|
21
|
+
/** The slice the background loader is currently waiting on (its tiles are
|
|
22
|
+
* still streaming): addTiledImage 'success' fires on add, not on tile load,
|
|
23
|
+
* so we gate the next slice on getFullyLoaded(). */
|
|
24
|
+
this.bgLoadingZ = null;
|
|
25
|
+
/** When bgLoadingZ started loading — a fallback so a slow/stuck slice can't
|
|
26
|
+
* stall the whole background pass forever. */
|
|
27
|
+
this.bgLoadingSince = 0;
|
|
28
|
+
/** Slices the background loader has already attempted (no tight retry loop). */
|
|
29
|
+
this.bgAttempted = new Set();
|
|
30
|
+
/** Max cached slice tiled images kept resident before LRU eviction. */
|
|
31
|
+
this.maxCachedSlices = 8;
|
|
32
|
+
/** Upper bound on resident slices, regardless of stack depth (memory guard). */
|
|
33
|
+
this.MAX_CACHED_SLICES_CAP = 64;
|
|
34
|
+
/** Fit-view tile budget above which background preloading is skipped: a huge
|
|
35
|
+
* no-pyramid stack would preload every slice at full resolution and
|
|
36
|
+
* flood/timeout. Normal stacks stay below it and KEEP the flicker-free
|
|
37
|
+
* pre-cache. */
|
|
38
|
+
this.MAX_PREFETCH_FIT_TILES = 256;
|
|
39
|
+
/** True only for stacks too large to background-preload. */
|
|
40
|
+
this.skipSlicePrefetch = false;
|
|
41
|
+
this.prefetchTimer = null;
|
|
42
|
+
}
|
|
43
|
+
// ── configuration (per image, from plot()) ────────────────────────────
|
|
44
|
+
/** Size the cache for the loaded image: keep the whole stack resident
|
|
45
|
+
* (capped) so the background loader fills every slice without evicting
|
|
46
|
+
* itself; skip preloading entirely when even the coarsest level's tile
|
|
47
|
+
* grid is too large (its slices only exist at full resolution). */
|
|
48
|
+
configure(stackDepth, coarseFitTiles) {
|
|
49
|
+
this.skipSlicePrefetch = coarseFitTiles > this.MAX_PREFETCH_FIT_TILES;
|
|
50
|
+
this.maxCachedSlices =
|
|
51
|
+
stackDepth > 1 ? Math.min(this.MAX_CACHED_SLICES_CAP, stackDepth) : 1;
|
|
52
|
+
}
|
|
53
|
+
/** Current LRU cap (the viewer sizes its tile cache from it). */
|
|
54
|
+
maxSlices() {
|
|
55
|
+
return this.maxCachedSlices;
|
|
56
|
+
}
|
|
57
|
+
/** Drop the per-channel groups (on a fresh plot). */
|
|
58
|
+
clearChannelGroups() {
|
|
59
|
+
this.channelSliceItems.clear();
|
|
60
|
+
}
|
|
61
|
+
/** Seed the cache with the just-opened composite slice (world item 0), so
|
|
62
|
+
* scrubbing back to it later is an instant opacity toggle, not a re-open. */
|
|
63
|
+
seedComposite(z, item) {
|
|
64
|
+
this.sliceItems.set(z, item);
|
|
65
|
+
this.touchSliceLru(z);
|
|
66
|
+
}
|
|
67
|
+
// ── slice display (setZIndex's cache work) ────────────────────────────
|
|
68
|
+
/** Show slice z: reveal it instantly when cached (re-tinting a stale
|
|
69
|
+
* multichannel group), otherwise add it once. The current slice stays
|
|
70
|
+
* visible until the new one is in — no white-flicker. */
|
|
71
|
+
showSlice(z) {
|
|
72
|
+
if (this.host.isMultiChannel()) {
|
|
73
|
+
const group = this.channelSliceItems.get(z);
|
|
74
|
+
if (group && group.length && group.some((it) => it && this.sliceInWorld(it))) {
|
|
75
|
+
this.revealChannelSlice(z);
|
|
76
|
+
// If a display change happened while this slice was cached, its tiles
|
|
77
|
+
// hold a stale tint — re-apply now (it's the visible slice, so the
|
|
78
|
+
// brief restore flash is acceptable, like a fresh load).
|
|
79
|
+
if (this.staleSlices.delete(z))
|
|
80
|
+
this.invalidateSlice(z);
|
|
81
|
+
this.touchSliceLru(z);
|
|
82
|
+
this.schedulePrefetch();
|
|
83
|
+
}
|
|
84
|
+
else if (!this.slicesLoading.has(z)) {
|
|
85
|
+
this.addChannelSlice(z);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const cached = this.sliceItems.get(z);
|
|
90
|
+
if (cached && this.sliceInWorld(cached)) {
|
|
91
|
+
// Instant: reveal the cached slice, hide the others — no fetch/decode.
|
|
92
|
+
this.showOnlySlice(z);
|
|
93
|
+
this.touchSliceLru(z);
|
|
94
|
+
this.schedulePrefetch();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (this.slicesLoading.has(z))
|
|
98
|
+
return; // already being added; success reveals it
|
|
99
|
+
this.addSlice(z);
|
|
100
|
+
}
|
|
101
|
+
/** Add a never-seen slice as a hidden tiled image, then reveal it once loaded
|
|
102
|
+
* (composite path; multichannel routes to addChannelSlice). */
|
|
103
|
+
addSlice(z) {
|
|
104
|
+
if (!this.host.hasImage())
|
|
105
|
+
return;
|
|
106
|
+
if (this.host.isMultiChannel()) {
|
|
107
|
+
this.addChannelSlice(z);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.slicesLoading.add(z);
|
|
111
|
+
// Tag this add to the current image; if the user switches images before it
|
|
112
|
+
// resolves, the stale callback is dropped (the add belongs to the old stack).
|
|
113
|
+
const token = this.sliceLoadToken;
|
|
114
|
+
const ts = this.host.buildTileSource(z);
|
|
115
|
+
try {
|
|
116
|
+
// addTiledImage lives on the Viewer (it queues the add into the world).
|
|
117
|
+
this.host.viewer().addTiledImage({
|
|
118
|
+
tileSource: ts,
|
|
119
|
+
x: 0,
|
|
120
|
+
y: 0,
|
|
121
|
+
width: 1, // match the primary image's normalized placement
|
|
122
|
+
opacity: 0,
|
|
123
|
+
// Load tiles even though it's hidden — this is what lets the background
|
|
124
|
+
// loader fill every slice's cache so scrubbing gets progressively smoother.
|
|
125
|
+
preload: true,
|
|
126
|
+
success: (e) => {
|
|
127
|
+
const item = e?.item;
|
|
128
|
+
if (token !== this.sliceLoadToken) {
|
|
129
|
+
// Image switched while this was adding — drop the orphan so it stops
|
|
130
|
+
// loading instead of streaming tiles for the abandoned stack.
|
|
131
|
+
if (item) {
|
|
132
|
+
try {
|
|
133
|
+
this.host.viewer()?.world?.removeItem(item);
|
|
134
|
+
}
|
|
135
|
+
catch { /* gone */ }
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.slicesLoading.delete(z);
|
|
140
|
+
if (!item)
|
|
141
|
+
return;
|
|
142
|
+
this.sliceItems.set(z, item);
|
|
143
|
+
this.touchSliceLru(z);
|
|
144
|
+
this.host.onCompositeSliceAdded(z);
|
|
145
|
+
// Only reveal if the user is still on this slice (fast scrubbing may
|
|
146
|
+
// have moved on — leave it cached/hidden for a later revisit).
|
|
147
|
+
if (z === this.host.currentZ()) {
|
|
148
|
+
this.showOnlySlice(z);
|
|
149
|
+
this.schedulePrefetch();
|
|
150
|
+
}
|
|
151
|
+
this.evictSliceLru();
|
|
152
|
+
},
|
|
153
|
+
error: () => {
|
|
154
|
+
if (token === this.sliceLoadToken)
|
|
155
|
+
this.slicesLoading.delete(z);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
this.slicesLoading.delete(z);
|
|
161
|
+
console.warn('[OSD] failed to add z-slice', err);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Add slice z's channel group: one additively-composited ('lighter' = Fiji
|
|
166
|
+
* "Composite") TiledImage per channel, hidden (opacity 0) until revealed.
|
|
167
|
+
* Each is preloaded so the background loader can pre-fill every slice.
|
|
168
|
+
* Cached so a revisit is an instant opacity toggle — no re-fetch, no
|
|
169
|
+
* white-flicker. Mirrors addSlice for the composite path.
|
|
170
|
+
*/
|
|
171
|
+
addChannelSlice(z) {
|
|
172
|
+
if (!this.host.hasImage())
|
|
173
|
+
return;
|
|
174
|
+
if (this.channelSliceItems.has(z) || this.slicesLoading.has(z))
|
|
175
|
+
return;
|
|
176
|
+
this.slicesLoading.add(z);
|
|
177
|
+
const token = this.sliceLoadToken;
|
|
178
|
+
const n = this.host.channelCount();
|
|
179
|
+
const group = new Array(n);
|
|
180
|
+
let settled = 0;
|
|
181
|
+
const onSettled = () => {
|
|
182
|
+
if (++settled < n)
|
|
183
|
+
return;
|
|
184
|
+
if (token !== this.sliceLoadToken)
|
|
185
|
+
return; // image switched mid-add
|
|
186
|
+
this.slicesLoading.delete(z);
|
|
187
|
+
this.channelSliceItems.set(z, group);
|
|
188
|
+
this.staleSlices.delete(z); // freshly tinted at the current display state
|
|
189
|
+
this.touchSliceLru(z);
|
|
190
|
+
if (z === this.host.currentZ()) {
|
|
191
|
+
this.revealChannelSlice(z); // tiles may still be decoding; opacity is set now
|
|
192
|
+
this.schedulePrefetch();
|
|
193
|
+
}
|
|
194
|
+
this.evictSliceLru();
|
|
195
|
+
};
|
|
196
|
+
for (let c = 0; c < n; c++) {
|
|
197
|
+
try {
|
|
198
|
+
this.host.viewer().addTiledImage({
|
|
199
|
+
tileSource: this.host.buildTileSource(z, c),
|
|
200
|
+
x: 0, y: 0, width: 1,
|
|
201
|
+
opacity: 0, // revealed by revealChannelSlice once the group is in
|
|
202
|
+
compositeOperation: 'lighter',
|
|
203
|
+
preload: true,
|
|
204
|
+
success: (e) => {
|
|
205
|
+
const item = e?.item;
|
|
206
|
+
if (token !== this.sliceLoadToken) {
|
|
207
|
+
if (item) {
|
|
208
|
+
try {
|
|
209
|
+
this.host.viewer()?.world?.removeItem(item);
|
|
210
|
+
}
|
|
211
|
+
catch { /* gone */ }
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (item)
|
|
216
|
+
group[c] = item;
|
|
217
|
+
onSettled();
|
|
218
|
+
},
|
|
219
|
+
error: () => onSettled(),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
console.warn('[OSD] failed to add channel slice image', z, c, err);
|
|
224
|
+
onSettled();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/** Reveal slice z's channel group (each visible channel → opacity 1) and
|
|
229
|
+
* hide every other cached slice's group. Instant; no fetch/decode. */
|
|
230
|
+
revealChannelSlice(z) {
|
|
231
|
+
for (const [zz, group] of this.channelSliceItems) {
|
|
232
|
+
const active = zz === z;
|
|
233
|
+
group.forEach((it, c) => {
|
|
234
|
+
if (!it)
|
|
235
|
+
return;
|
|
236
|
+
const visible = this.host.channelVisible(c);
|
|
237
|
+
try {
|
|
238
|
+
it.setOpacity(active && visible ? 1 : 0);
|
|
239
|
+
}
|
|
240
|
+
catch { /* gone */ }
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Show the given composite slice (opacity 1) and hide all other cached slices. */
|
|
245
|
+
showOnlySlice(z) {
|
|
246
|
+
for (const [zz, item] of this.sliceItems) {
|
|
247
|
+
try {
|
|
248
|
+
item.setOpacity(zz === z ? 1 : 0);
|
|
249
|
+
}
|
|
250
|
+
catch { /* item gone */ }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// ── display invalidation (multichannel) ───────────────────────────────
|
|
254
|
+
/** Re-tint after a display change: invalidate ONLY the visible slice's
|
|
255
|
+
* channel images — invalidating the whole world would re-process every
|
|
256
|
+
* hidden/preloaded slice's tiles (hundreds), flooding OSD and wasting work
|
|
257
|
+
* on tiles that aren't on screen. The other cached slices are marked stale
|
|
258
|
+
* and re-tinted lazily when revealed. */
|
|
259
|
+
invalidateChannelDisplay(z) {
|
|
260
|
+
this.invalidateSlice(z);
|
|
261
|
+
this.staleSlices.clear();
|
|
262
|
+
for (const zz of this.channelSliceItems.keys()) {
|
|
263
|
+
if (zz !== z)
|
|
264
|
+
this.staleSlices.add(zz);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Invalidate (restore + re-recolor) just the channel images of one cached
|
|
268
|
+
* slice. A shared timestamp batches the per-image invalidations into one
|
|
269
|
+
* processing pass (OSD dedupes tiles already stamped at >= tStamp). */
|
|
270
|
+
invalidateSlice(z) {
|
|
271
|
+
const group = this.channelSliceItems.get(z) ?? [];
|
|
272
|
+
if (!group.length)
|
|
273
|
+
return;
|
|
274
|
+
const osd = OSD;
|
|
275
|
+
const tStamp = typeof osd.now === 'function' ? osd.now() : Date.now();
|
|
276
|
+
for (const it of group) {
|
|
277
|
+
if (it && typeof it.requestInvalidate === 'function') {
|
|
278
|
+
try {
|
|
279
|
+
it.requestInvalidate(true, false, tStamp);
|
|
280
|
+
}
|
|
281
|
+
catch { /* gone */ }
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// ── background stack preloading ───────────────────────────────────────
|
|
286
|
+
/** Debounce so a burst of viewport/slice events coalesces, then advance the
|
|
287
|
+
* background stack loader by one slice. */
|
|
288
|
+
schedulePrefetch() {
|
|
289
|
+
if (this.skipSlicePrefetch)
|
|
290
|
+
return;
|
|
291
|
+
if (this.prefetchTimer)
|
|
292
|
+
clearTimeout(this.prefetchTimer);
|
|
293
|
+
this.prefetchTimer = setTimeout(() => this.loadNextBackgroundSlice(), 200);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Background-load the whole stack: add each not-yet-cached slice as a
|
|
297
|
+
* hidden, preloaded tiled image, one at a time, working outward from the
|
|
298
|
+
* current slice — and never blocking the visible slice (it yields while the
|
|
299
|
+
* current view is still streaming tiles; only one slice is in flight at a
|
|
300
|
+
* time so the on-screen tiles always win the connection).
|
|
301
|
+
*/
|
|
302
|
+
loadNextBackgroundSlice() {
|
|
303
|
+
this.prefetchTimer = null;
|
|
304
|
+
if (!this.host.hasImage())
|
|
305
|
+
return;
|
|
306
|
+
const sliceCount = this.host.sliceCount();
|
|
307
|
+
if (sliceCount <= 1)
|
|
308
|
+
return; // not a stack — nothing to preload
|
|
309
|
+
// Yield to the visible slice while it's still streaming tiles.
|
|
310
|
+
if (this.sliceTilesLoading(this.host.currentZ())) {
|
|
311
|
+
this.schedulePrefetch();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// Gate on the in-flight slice's TILES finishing — addTiledImage's success
|
|
315
|
+
// fires on add, not on tile load, so without this we'd add the whole stack
|
|
316
|
+
// at once and flood the connection. A time fallback prevents a stuck slice
|
|
317
|
+
// from stalling the pass.
|
|
318
|
+
if (this.bgLoadingZ != null) {
|
|
319
|
+
const adding = this.slicesLoading.has(this.bgLoadingZ);
|
|
320
|
+
const tilesLoading = this.sliceTilesLoading(this.bgLoadingZ);
|
|
321
|
+
const timedOut = Date.now() - this.bgLoadingSince > 8000;
|
|
322
|
+
if ((adding || tilesLoading) && !timedOut) {
|
|
323
|
+
this.schedulePrefetch();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
this.bgLoadingZ = null; // that slice's tiles are in (or gave up) — advance
|
|
327
|
+
}
|
|
328
|
+
const next = this.nearestUncachedSlice(sliceCount);
|
|
329
|
+
if (next == null)
|
|
330
|
+
return; // whole stack cached — done
|
|
331
|
+
this.bgLoadingZ = next;
|
|
332
|
+
this.bgLoadingSince = Date.now();
|
|
333
|
+
this.bgAttempted.add(next);
|
|
334
|
+
this.addSlice(next); // hidden + preload (added with opacity 0; not revealed)
|
|
335
|
+
this.schedulePrefetch(); // poll until its tiles load, then advance
|
|
336
|
+
}
|
|
337
|
+
/** The not-yet-cached slice closest to the current one (load nearest first),
|
|
338
|
+
* skipping any already attempted so a failed/slow one isn't retried in a loop. */
|
|
339
|
+
nearestUncachedSlice(sliceCount) {
|
|
340
|
+
const cur = this.host.currentZ();
|
|
341
|
+
for (let d = 0; d < sliceCount; d++) {
|
|
342
|
+
const candidates = d === 0 ? [cur] : [cur - d, cur + d];
|
|
343
|
+
for (const z of candidates) {
|
|
344
|
+
if (z >= 0 && z < sliceCount &&
|
|
345
|
+
!this.sliceCacheHas(z) && !this.slicesLoading.has(z) && !this.bgAttempted.has(z)) {
|
|
346
|
+
return z;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Stop background stack preloading and invalidate any in-flight slice add.
|
|
354
|
+
* Called when a different image is selected so the previous stack stops
|
|
355
|
+
* loading immediately instead of finishing in the background.
|
|
356
|
+
*/
|
|
357
|
+
cancelBackgroundLoad() {
|
|
358
|
+
if (this.prefetchTimer) {
|
|
359
|
+
clearTimeout(this.prefetchTimer);
|
|
360
|
+
this.prefetchTimer = null;
|
|
361
|
+
}
|
|
362
|
+
this.slicesLoading.clear();
|
|
363
|
+
this.bgLoadingZ = null;
|
|
364
|
+
this.bgAttempted.clear();
|
|
365
|
+
this.sliceLoadToken++; // drop pending addTiledImage callbacks from the old image
|
|
366
|
+
// Abort in-flight background tiles immediately by dropping the hidden
|
|
367
|
+
// preloaded slices (removeItem cancels their pending tile loads). Keep the
|
|
368
|
+
// visible slice so the current view doesn't blank before the next plot.
|
|
369
|
+
this.dropHiddenSlices();
|
|
370
|
+
}
|
|
371
|
+
/** Remove every cached slice except the currently displayed one, aborting
|
|
372
|
+
* their in-flight tile requests. */
|
|
373
|
+
dropHiddenSlices() {
|
|
374
|
+
const v = this.host.viewer();
|
|
375
|
+
if (!v)
|
|
376
|
+
return;
|
|
377
|
+
const cur = this.host.currentZ();
|
|
378
|
+
for (const [z, item] of [...this.sliceItems]) {
|
|
379
|
+
if (z === cur)
|
|
380
|
+
continue;
|
|
381
|
+
this.sliceItems.delete(z);
|
|
382
|
+
try {
|
|
383
|
+
v.world.removeItem(item);
|
|
384
|
+
}
|
|
385
|
+
catch { /* already gone */ }
|
|
386
|
+
}
|
|
387
|
+
for (const [z, group] of [...this.channelSliceItems]) {
|
|
388
|
+
if (z === cur)
|
|
389
|
+
continue;
|
|
390
|
+
this.channelSliceItems.delete(z);
|
|
391
|
+
for (const it of group) {
|
|
392
|
+
if (it) {
|
|
393
|
+
try {
|
|
394
|
+
v.world.removeItem(it);
|
|
395
|
+
}
|
|
396
|
+
catch { /* gone */ }
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
this.sliceLru = this.sliceCacheHas(cur) ? [cur] : [];
|
|
401
|
+
}
|
|
402
|
+
// ── cache bookkeeping ─────────────────────────────────────────────────
|
|
403
|
+
/** Whether slice z is in the active cache (composite single image, or the
|
|
404
|
+
* multichannel per-channel group). */
|
|
405
|
+
sliceCacheHas(z) {
|
|
406
|
+
return this.host.isMultiChannel() ? this.channelSliceItems.has(z) : this.sliceItems.has(z);
|
|
407
|
+
}
|
|
408
|
+
/** The cached TiledImage(s) for slice z (0–1 for composite, N for multichannel). */
|
|
409
|
+
sliceGroup(z) {
|
|
410
|
+
if (this.host.isMultiChannel())
|
|
411
|
+
return this.channelSliceItems.get(z) ?? [];
|
|
412
|
+
const it = this.sliceItems.get(z);
|
|
413
|
+
return it ? [it] : [];
|
|
414
|
+
}
|
|
415
|
+
/** Whether slice z's tiles are still streaming (any cached image not fully loaded). */
|
|
416
|
+
sliceTilesLoading(z) {
|
|
417
|
+
const g = this.sliceGroup(z);
|
|
418
|
+
if (!g.length)
|
|
419
|
+
return false;
|
|
420
|
+
return g.some((it) => it && typeof it.getFullyLoaded === 'function' && !it.getFullyLoaded());
|
|
421
|
+
}
|
|
422
|
+
/** Remove slice z's cached image(s) from the world and the active cache. */
|
|
423
|
+
removeCachedSlice(z) {
|
|
424
|
+
const v = this.host.viewer();
|
|
425
|
+
if (this.host.isMultiChannel()) {
|
|
426
|
+
const group = this.channelSliceItems.get(z);
|
|
427
|
+
this.channelSliceItems.delete(z);
|
|
428
|
+
if (group && v)
|
|
429
|
+
for (const it of group) {
|
|
430
|
+
if (it) {
|
|
431
|
+
try {
|
|
432
|
+
v.world.removeItem(it);
|
|
433
|
+
}
|
|
434
|
+
catch { /* gone */ }
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
const item = this.sliceItems.get(z);
|
|
440
|
+
this.sliceItems.delete(z);
|
|
441
|
+
if (item && v) {
|
|
442
|
+
try {
|
|
443
|
+
v.world.removeItem(item);
|
|
444
|
+
}
|
|
445
|
+
catch { /* gone */ }
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/** Is the tiled image still in the world (not evicted)? */
|
|
450
|
+
sliceInWorld(item) {
|
|
451
|
+
try {
|
|
452
|
+
return this.host.viewer().world.getIndexOfItem(item) >= 0;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/** Mark z as most-recently-used. */
|
|
459
|
+
touchSliceLru(z) {
|
|
460
|
+
const i = this.sliceLru.indexOf(z);
|
|
461
|
+
if (i >= 0)
|
|
462
|
+
this.sliceLru.splice(i, 1);
|
|
463
|
+
this.sliceLru.push(z);
|
|
464
|
+
}
|
|
465
|
+
/** Drop the least-recently-used cached slices beyond the cap (never the
|
|
466
|
+
* current one), removing their tiled images so memory stays bounded. */
|
|
467
|
+
evictSliceLru() {
|
|
468
|
+
while (this.sliceLru.length > this.maxCachedSlices) {
|
|
469
|
+
const cur = this.host.currentZ();
|
|
470
|
+
const idx = this.sliceLru.findIndex((z) => z !== cur);
|
|
471
|
+
if (idx < 0)
|
|
472
|
+
break;
|
|
473
|
+
const z = this.sliceLru.splice(idx, 1)[0];
|
|
474
|
+
this.removeCachedSlice(z);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/** Clear the cache (on teardown / image switch). */
|
|
478
|
+
reset() {
|
|
479
|
+
this.sliceItems.clear();
|
|
480
|
+
this.channelSliceItems.clear();
|
|
481
|
+
this.staleSlices.clear();
|
|
482
|
+
this.sliceLru = [];
|
|
483
|
+
this.slicesLoading.clear();
|
|
484
|
+
this.bgLoadingZ = null;
|
|
485
|
+
this.bgAttempted.clear();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xpY2UtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9vc2Qvc2xpY2UtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQXlDaEMsTUFBTSxPQUFPLFVBQVU7SUF1Q3JCLFlBQW9CLElBQW9CO1FBQXBCLFNBQUksR0FBSixJQUFJLENBQWdCO1FBdEN4QyxxRUFBcUU7UUFDN0QsZUFBVSxHQUFHLElBQUksR0FBRyxFQUFlLENBQUM7UUFDNUM7O2lEQUV5QztRQUNqQyxzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBaUIsQ0FBQztRQUNyRDs4RUFDc0U7UUFDOUQsZ0JBQVcsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ3hDLHVEQUF1RDtRQUMvQyxhQUFRLEdBQWEsRUFBRSxDQUFDO1FBQ2hDLDBFQUEwRTtRQUNsRSxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDMUM7a0ZBQzBFO1FBQ2xFLG1CQUFjLEdBQUcsQ0FBQyxDQUFDO1FBQzNCOzs2REFFcUQ7UUFDN0MsZUFBVSxHQUFrQixJQUFJLENBQUM7UUFDekM7dURBQytDO1FBQ3ZDLG1CQUFjLEdBQUcsQ0FBQyxDQUFDO1FBQzNCLGdGQUFnRjtRQUN4RSxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDeEMsdUVBQXVFO1FBQy9ELG9CQUFlLEdBQUcsQ0FBQyxDQUFDO1FBQzVCLGdGQUFnRjtRQUMvRCwwQkFBcUIsR0FBRyxFQUFFLENBQUM7UUFDNUM7Ozt5QkFHaUI7UUFDQSwyQkFBc0IsR0FBRyxHQUFHLENBQUM7UUFDOUMsNERBQTREO1FBQ3BELHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQUMxQixrQkFBYSxHQUFRLElBQUksQ0FBQztJQUVTLENBQUM7SUFFNUMseUVBQXlFO0lBRXpFOzs7d0VBR29FO0lB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Q0FBQztZQUNuRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7WUFDdEQsSUFBSSxHQUFHLEdBQUcsQ0FBQztnQkFBRSxNQUFNO1lBQ25CLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUM7SUFFRCxvREFBb0Q7SUFDcEQsS0FBSztRQUNILElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQy9CLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxFQUFFLENBQUM7UUFDbkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztRQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzNCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE9TRCB9IGZyb20gJy4vb3NkLWxpYic7XG5cbi8qKlxuICogU3RhY2stc2xpY2UgY2FjaGUgZm9yIHRoZSBPcGVuU2VhZHJhZ29uIGJhY2tlbmQgKHJlZmFjdG9yaW5nIHBsYW4sIFN0ZXAgMyDigJRcbiAqIGEgcHVyZSBtb3ZlIG9mIHRoZSBjYWNoZSBjbHVzdGVyIG91dCBvZiB0aGUgdmlzdWFsaXplciBzZXJ2aWNlKS5cbiAqXG4gKiBTY3J1YmJpbmcgdGhlIHotc2xpZGVyIHVzZWQgdG8gdmlld2VyLm9wZW4oKSBhIGZyZXNoIHRpbGUgc291cmNlIHBlciBzbGljZSxcbiAqIHdoaWNoIGRlc3Ryb3lzIHRoZSBjdXJyZW50IHRpbGVkIGltYWdlIChhbmQgaXRzIGRlY29kZWQrcmVjb2xvcmVkIHRpbGVzKSwgc29cbiAqIHJldmlzaXRpbmcgYSBzbGljZSByZS1mZXRjaGVkIGV2ZXJ5dGhpbmcuIEluc3RlYWQgd2Uga2VlcCBlYWNoIHZpc2l0ZWQgc2xpY2VcbiAqIGFzIGl0cyBvd24gdGlsZWQgaW1hZ2UgaW4gdGhlIHdvcmxkIGFuZCBqdXN0IHRvZ2dsZSBvcGFjaXR5IOKAlCBhIHJldmlzaXRlZFxuICogc2xpY2UgaXMgaW5zdGFudCAobm8gbmV0d29yaywgbm8gcmUtZGVjb2RlLCBubyByZS1yZWNvbG9yKS4gQm91bmRlZCBieSBhblxuICogTFJVIHNvIGRlZXAgc3RhY2tzIGRvbid0IGdyb3cgd2l0aG91dCBsaW1pdC4gTXVsdGljaGFubmVsIHNsaWNlcyBjYWNoZSBvbmVcbiAqIFRpbGVkSW1hZ2UgcGVyIGNoYW5uZWwgKGFkZGl0aXZlbHkgY29tcG9zaXRlZCk7IGNvbXBvc2l0ZSBzbGljZXMgY2FjaGUgb25lLlxuICogQSBiYWNrZ3JvdW5kIGxvYWRlciBwcmUtZmlsbHMgdGhlIHJlc3Qgb2YgdGhlIHN0YWNrLCBvbmUgc2xpY2UgYXQgYSB0aW1lLFxuICogeWllbGRpbmcgdG8gdGhlIHZpc2libGUgc2xpY2Ugc28gb24tc2NyZWVuIHRpbGVzIGFsd2F5cyB3aW4gdGhlIGNvbm5lY3Rpb24uXG4gKi9cblxuLyoqIFdoYXQgdGhlIGNhY2hlIG5lZWRzIGZyb20gdGhlIHZpc3VhbGl6ZXIgc2VydmljZS4gQWxsIGFjY2Vzc29ycyBhcmUgbGl2ZVxuICogIChjYWxsZWQgYXQgdXNlIHRpbWUsIG5ldmVyIGNhcHR1cmVkKSBzbyB0aGUgY2FjaGUgYWx3YXlzIHNlZXMgdGhlIGN1cnJlbnRcbiAqICB2aWV3ZXIvZGVzY3JpcHRvci96IOKAlCBtYXRjaGluZyB0aGUgZmllbGQgcmVhZHMgaXQgcmVwbGFjZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIFNsaWNlQ2FjaGVIb3N0IHtcbiAgLyoqIFRoZSBtb3VudGVkIHZpZXdlciwgb3IgbnVsbC4gKi9cbiAgdmlld2VyKCk6IGFueSB8IG51bGw7XG4gIC8qKiBUcnVlIHdoZW4gYSB2aWV3ZXIsIGRlc2NyaXB0b3IgYW5kIGluZm9CNjQgYXJlIGFsbCBwcmVzZW50LiAqL1xuICBoYXNJbWFnZSgpOiBib29sZWFuO1xuICAvKiogU3RhY2sgZGVwdGggKGRlc2NyaXB0b3IueiwgMSBmb3Igc2luZ2xlIGltYWdlcykuICovXG4gIHNsaWNlQ291bnQoKTogbnVtYmVyO1xuICAvKiogVGhlIGN1cnJlbnRseSBkaXNwbGF5ZWQgei1zbGljZS4gKi9cbiAgY3VycmVudFooKTogbnVtYmVyO1xuICAvKiogUGVyLWNoYW5uZWwgcmVuZGVyaW5nIChtdWx0aWNoYW5uZWwgZmx1b3Jlc2NlbmNlKSB2cyBjb21wb3NpdGUuICovXG4gIGlzTXVsdGlDaGFubmVsKCk6IGJvb2xlYW47XG4gIC8qKiBDaGFubmVsIGNvdW50IGZvciBhIG11bHRpY2hhbm5lbCBncm91cCBhZGQuICovXG4gIGNoYW5uZWxDb3VudCgpOiBudW1iZXI7XG4gIC8qKiBDaGFubmVsIHZpc2liaWxpdHkgKGRyaXZlcyBncm91cCByZXZlYWwgb3BhY2l0eSkuICovXG4gIGNoYW5uZWxWaXNpYmxlKGM6IG51bWJlcik6IGJvb2xlYW47XG4gIC8qKiBUaWxlIHNvdXJjZSBmb3Igc2xpY2UgeiAob3B0aW9uYWxseSBvbmUgY2hhbm5lbCkuICovXG4gIGJ1aWxkVGlsZVNvdXJjZSh6OiBudW1iZXIsIGNoYW5uZWw/OiBudW1iZXIpOiBhbnk7XG4gIC8qKiBBIGNvbXBvc2l0ZSBzbGljZSBsYW5kZWQgaW4gdGhlIHdvcmxkIOKAlCB0aGUgc2VydmljZSBzYW1wbGVzIGl0cyB3aW5kb3cuICovXG4gIG9uQ29tcG9zaXRlU2xpY2VBZGRlZCh6OiBudW1iZXIpOiB2b2lkO1xufVxuXG5leHBvcnQgY2xhc3MgU2xpY2VDYWNoZSB7XG4gIC8qKiB6LXNsaWNlIOKGkiBpdHMgVGlsZWRJbWFnZSBpbiB0aGUgdmlld2VyIHdvcmxkIChjb21wb3NpdGUgcGF0aCkuICovXG4gIHByaXZhdGUgc2xpY2VJdGVtcyA9IG5ldyBNYXA8bnVtYmVyLCBhbnk+KCk7XG4gIC8qKiBNdWx0aWNoYW5uZWwgcGVyLXNsaWNlIGNhY2hlOiB6IOKGkiB0aGUgTiBjaGFubmVsIFRpbGVkSW1hZ2VzIGZvciB0aGF0IHNsaWNlXG4gICAqICAoYWRkaXRpdmVseSBjb21wb3NpdGVkIGJ5IE9TRDsgaW5kZXggPSBjaGFubmVsKS4gT25seSB0aGUgYWN0aXZlIHNsaWNlJ3NcbiAgICogIHZpc2libGUgY2hhbm5lbHMgaGF2ZSBvcGFjaXR5ID4gMC4gKi9cbiAgcHJpdmF0ZSBjaGFubmVsU2xpY2VJdGVtcyA9IG5ldyBNYXA8bnVtYmVyLCBhbnlbXT4oKTtcbiAgLyoqIENhY2hlZCBtdWx0aWNoYW5uZWwgc2xpY2VzIHdob3NlIHRpbGVzIHdlcmUgdGludGVkIGJlZm9yZSB0aGUgbGF0ZXN0XG4gICAqICBkaXNwbGF5IGNoYW5nZTsgcmUtdGludGVkIGxhemlseSB3aGVuIG5leHQgcmV2ZWFsZWQgYnkgei1zY3J1Yi4gKi9cbiAgcHJpdmF0ZSBzdGFsZVNsaWNlcyA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAvKiogTW9zdC1yZWNlbnRseS1zaG93biB6IGxhc3Q7IGRyaXZlcyBMUlUgZXZpY3Rpb24uICovXG4gIHByaXZhdGUgc2xpY2VMcnU6IG51bWJlcltdID0gW107XG4gIC8qKiB6LXNsaWNlcyB3aG9zZSB0aWxlZCBpbWFnZSBpcyBiZWluZyBhZGRlZCAoZGVkdXBlIHJhcGlkIHNjcnViYmluZykuICovXG4gIHByaXZhdGUgc2xpY2VzTG9hZGluZyA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAvKiogQnVtcGVkIHdoZW5ldmVyIHRoZSBsb2FkZWQgaW1hZ2UgY2hhbmdlczsgaW4tZmxpZ2h0IGJhY2tncm91bmQgc2xpY2UgYWRkc1xuICAgKiAgY2FwdHVyZWQgdW5kZXIgYW4gb2xkZXIgdG9rZW4gYXJlIGRyb3BwZWQgKGNhbmNlbGxlZCBpbWFnZSBzd2l0Y2gpLiAqL1xuICBwcml2YXRlIHNsaWNlTG9hZFRva2VuID0gMDtcbiAgLyoqIFRoZSBzbGljZSB0aGUgYmFja2dyb3VuZCBsb2FkZXIgaXMgY3VycmVudGx5IHdhaXRpbmcgb24gKGl0cyB0aWxlcyBhcmVcbiAgICogIHN0aWxsIHN0cmVhbWluZyk6IGFkZFRpbGVkSW1hZ2UgJ3N1Y2Nlc3MnIGZpcmVzIG9uIGFkZCwgbm90IG9uIHRpbGUgbG9hZCxcbiAgICogIHNvIHdlIGdhdGUgdGhlIG5leHQgc2xpY2Ugb24gZ2V0RnVsbHlMb2FkZWQoKS4gKi9cbiAgcHJpdmF0ZSBiZ0xvYWRpbmdaOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIFdoZW4gYmdMb2FkaW5nWiBzdGFydGVkIGxvYWRpbmcg4oCUIGEgZmFsbGJhY2sgc28gYSBzbG93L3N0dWNrIHNsaWNlIGNhbid0XG4gICAqICBzdGFsbCB0aGUgd2hvbGUgYmFja2dyb3VuZCBwYXNzIGZvcmV2ZXIuICovXG4gIHByaXZhdGUgYmdMb2FkaW5nU2luY2UgPSAwO1xuICAvKiogU2xpY2VzIHRoZSBiYWNrZ3JvdW5kIGxvYWRlciBoYXMgYWxyZWFkeSBhdHRlbXB0ZWQgKG5vIHRpZ2h0IHJldHJ5IGxvb3ApLiAqL1xuICBwcml2YXRlIGJnQXR0ZW1wdGVkID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIC8qKiBNYXggY2FjaGVkIHNsaWNlIHRpbGVkIGltYWdlcyBrZXB0IHJlc2lkZW50IGJlZm9yZSBMUlUgZXZpY3Rpb24uICovXG4gIHByaXZhdGUgbWF4Q2FjaGVkU2xpY2VzID0gODtcbiAgLyoqIFVwcGVyIGJvdW5kIG9uIHJlc2lkZW50IHNsaWNlcywgcmVnYXJkbGVzcyBvZiBzdGFjayBkZXB0aCAobWVtb3J5IGd1YXJkKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfQ0FDSEVEX1NMSUNFU19DQVAgPSA2NDtcbiAgLyoqIEZpdC12aWV3IHRpbGUgYnVkZ2V0IGFib3ZlIHdoaWNoIGJhY2tncm91bmQgcHJlbG9hZGluZyBpcyBza2lwcGVkOiBhIGh1Z2VcbiAgICogIG5vLXB5cmFtaWQgc3RhY2sgd291bGQgcHJlbG9hZCBldmVyeSBzbGljZSBhdCBmdWxsIHJlc29sdXRpb24gYW5kXG4gICAqICBmbG9vZC90aW1lb3V0LiBOb3JtYWwgc3RhY2tzIHN0YXkgYmVsb3cgaXQgYW5kIEtFRVAgdGhlIGZsaWNrZXItZnJlZVxuICAgKiAgcHJlLWNhY2hlLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9QUkVGRVRDSF9GSVRfVElMRVMgPSAyNTY7XG4gIC8qKiBUcnVlIG9ubHkgZm9yIHN0YWNrcyB0b28gbGFyZ2UgdG8gYmFja2dyb3VuZC1wcmVsb2FkLiAqL1xuICBwcml2YXRlIHNraXBTbGljZVByZWZldGNoID0gZmFsc2U7XG4gIHByaXZhdGUgcHJlZmV0Y2hUaW1lcjogYW55ID0gbnVsbDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGhvc3Q6IFNsaWNlQ2FjaGVIb3N0KSB7fVxuXG4gIC8vIOKUgOKUgCBjb25maWd1cmF0aW9uIChwZXIgaW1hZ2UsIGZyb20gcGxvdCgpKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogU2l6ZSB0aGUgY2FjaGUgZm9yIHRoZSBsb2FkZWQgaW1hZ2U6IGtlZXAgdGhlIHdob2xlIHN0YWNrIHJlc2lkZW50XG4gICAqICAoY2FwcGVkKSBzbyB0aGUgYmFja2dyb3VuZCBsb2FkZXIgZmlsbHMgZXZlcnkgc2xpY2Ugd2l0aG91dCBldmljdGluZ1xuICAgKiAgaXRzZWxmOyBza2lwIHByZWxvYWRpbmcgZW50aXJlbHkgd2hlbiBldmVuIHRoZSBjb2Fyc2VzdCBsZXZlbCdzIHRpbGVcbiAgICogIGdyaWQgaXMgdG9vIGxhcmdlIChpdHMgc2xpY2VzIG9ubHkgZXhpc3QgYXQgZnVsbCByZXNvbHV0aW9uKS4gKi9cbiAgY29uZmlndXJlKHN0YWNrRGVwdGg6IG51bWJlciwgY29hcnNlRml0VGlsZXM6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuc2tpcFNsaWNlUHJlZmV0Y2ggPSBjb2Fyc2VGaXRUaWxlcyA+IHRoaXMuTUFYX1BSRUZFVENIX0ZJVF9USUxFUztcbiAgICB0aGlzLm1heENhY2hlZFNsaWNlcyA9XG4gICAgICBzdGFja0RlcHRoID4gMSA/IE1hdGgubWluKHRoaXMuTUFYX0NBQ0hFRF9TTElDRVNfQ0FQLCBzdGFja0RlcHRoKSA6IDE7XG4gIH1cblxuICAvKiogQ3VycmVudCBMUlUgY2FwICh0aGUgdmlld2VyIHNpemVzIGl0cyB0aWxlIGNhY2hlIGZyb20gaXQpLiAqL1xuICBtYXhTbGljZXMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5tYXhDYWNoZWRTbGljZXM7XG4gIH1cblxuICAvKiogRHJvcCB0aGUgcGVyLWNoYW5uZWwgZ3JvdXBzIChvbiBhIGZyZXNoIHBsb3QpLiAqL1xuICBjbGVhckNoYW5uZWxHcm91cHMoKTogdm9pZCB7XG4gICAgdGhpcy5jaGFubmVsU2xpY2VJdGVtcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqIFNlZWQgdGhlIGNhY2hlIHdpdGggdGhlIGp1c3Qtb3BlbmVkIGNvbXBvc2l0ZSBzbGljZSAod29ybGQgaXRlbSAwKSwgc29cbiAgICogIHNjcnViYmluZyBiYWNrIHRvIGl0IGxhdGVyIGlzIGFuIGluc3RhbnQgb3BhY2l0eSB0b2dnbGUsIG5vdCBhIHJlLW9wZW4uICovXG4gIHNlZWRDb21wb3NpdGUoejogbnVtYmVyLCBpdGVtOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLnNsaWNlSXRlbXMuc2V0KHosIGl0ZW0pO1xuICAgIHRoaXMudG91Y2hTbGljZUxydSh6KTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBzbGljZSBkaXNwbGF5IChzZXRaSW5kZXgncyBjYWNoZSB3b3JrKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogU2hvdyBzbGljZSB6OiByZXZlYWwgaXQgaW5zdGFudGx5IHdoZW4gY2FjaGVkIChyZS10aW50aW5nIGEgc3RhbGVcbiAgICogIG11bHRpY2hhbm5lbCBncm91cCksIG90aGVyd2lzZSBhZGQgaXQgb25jZS4gVGhlIGN1cnJlbnQgc2xpY2Ugc3RheXNcbiAgICogIHZpc2libGUgdW50aWwgdGhlIG5ldyBvbmUgaXMgaW4g4oCUIG5vIHdoaXRlLWZsaWNrZXIuICovXG4gIHNob3dTbGljZSh6OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5ob3N0LmlzTXVsdGlDaGFubmVsKCkpIHtcbiAgICAgIGNvbnN0IGdyb3VwID0gdGhpcy5jaGFubmVsU2xpY2VJdGVtcy5nZXQoeik7XG4gICAgICBpZiAoZ3JvdXAgJiYgZ3JvdXAubGVuZ3RoICYmIGdyb3VwLnNvbWUoKGl0KSA9PiBpdCAmJiB0aGlzLnNsaWNlSW5Xb3JsZChpdCkpKSB7XG4gICAgICAgIHRoaXMucmV2ZWFsQ2hhbm5lbFNsaWNlKHopO1xuICAgICAgICAvLyBJZiBhIGRpc3BsYXkgY2hhbmdlIGhhcHBlbmVkIHdoaWxlIHRoaXMgc2xpY2Ugd2FzIGNhY2hlZCwgaXRzIHRpbGVzXG4gICAgICAgIC8vIGhvbGQgYSBzdGFsZSB0aW50IOKAlCByZS1hcHBseSBub3cgKGl0J3MgdGhlIHZpc2libGUgc2xpY2UsIHNvIHRoZVxuICAgICAgICAvLyBicmllZiByZXN0b3JlIGZsYXNoIGlzIGFjY2VwdGFibGUsIGxpa2UgYSBmcmVzaCBsb2FkKS5cbiAgICAgICAgaWYgKHRoaXMuc3RhbGVTbGljZXMuZGVsZXRlKHopKSB0aGlzLmludmFsaWRhdGVTbGljZSh6KTtcbiAgICAgICAgdGhpcy50b3VjaFNsaWNlTHJ1KHopO1xuICAgICAgICB0aGlzLnNjaGVkdWxlUHJlZmV0Y2goKTtcbiAgICAgIH0gZWxzZSBpZiAoIXRoaXMuc2xpY2VzTG9hZGluZy5oYXMoeikpIHtcbiAgICAgICAgdGhpcy5hZGRDaGFubmVsU2xpY2Uoeik7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuc2xpY2VJdGVtcy5nZXQoeik7XG4gICAgaWYgKGNhY2hlZCAmJiB0aGlzLnNsaWNlSW5Xb3JsZChjYWNoZWQpKSB7XG4gICAgICAvLyBJbnN0YW50OiByZXZlYWwgdGhlIGNhY2hlZCBzbGljZSwgaGlkZSB0aGUgb3RoZXJzIOKAlCBubyBmZXRjaC9kZWNvZGUuXG4gICAgICB0aGlzLnNob3dPbmx5U2xpY2Uoeik7XG4gICAgICB0aGlzLnRvdWNoU2xpY2VMcnUoeik7XG4gICAgICB0aGlzLnNjaGVkdWxlUHJlZmV0Y2goKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRoaXMuc2xpY2VzTG9hZGluZy5oYXMoeikpIHJldHVybjsgLy8gYWxyZWFkeSBiZWluZyBhZGRlZDsgc3VjY2VzcyByZXZlYWxzIGl0XG4gICAgdGhpcy5hZGRTbGljZSh6KTtcbiAgfVxuXG4gIC8qKiBBZGQgYSBuZXZlci1zZWVuIHNsaWNlIGFzIGEgaGlkZGVuIHRpbGVkIGltYWdlLCB0aGVuIHJldmVhbCBpdCBvbmNlIGxvYWRlZFxuICAgKiAgKGNvbXBvc2l0ZSBwYXRoOyBtdWx0aWNoYW5uZWwgcm91dGVzIHRvIGFkZENoYW5uZWxTbGljZSkuICovXG4gIHByaXZhdGUgYWRkU2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhvc3QuaGFzSW1hZ2UoKSkgcmV0dXJuO1xuICAgIGlmICh0aGlzLmhvc3QuaXNNdWx0aUNoYW5uZWwoKSkge1xuICAgICAgdGhpcy5hZGRDaGFubmVsU2xpY2Uoeik7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuc2xpY2VzTG9hZGluZy5hZGQoeik7XG4gICAgLy8gVGFnIHRoaXMgYWRkIHRvIHRoZSBjdXJyZW50IGltYWdlOyBpZiB0aGUgdXNlciBzd2l0Y2hlcyBpbWFnZXMgYmVmb3JlIGl0XG4gICAgLy8gcmVzb2x2ZXMsIHRoZSBzdGFsZSBjYWxsYmFjayBpcyBkcm9wcGVkICh0aGUgYWRkIGJlbG9uZ3MgdG8gdGhlIG9sZCBzdGFjaykuXG4gICAgY29uc3QgdG9rZW4gPSB0aGlzLnNsaWNlTG9hZFRva2VuO1xuICAgIGNvbnN0IHRzID0gdGhpcy5ob3N0LmJ1aWxkVGlsZVNvdXJjZSh6KTtcbiAgICB0cnkge1xuICAgICAgLy8gYWRkVGlsZWRJbWFnZSBsaXZlcyBvbiB0aGUgVmlld2VyIChpdCBxdWV1ZXMgdGhlIGFkZCBpbnRvIHRoZSB3b3JsZCkuXG4gICAgICB0aGlzLmhvc3Qudmlld2VyKCkuYWRkVGlsZWRJbWFnZSh7XG4gICAgICAgIHRpbGVTb3VyY2U6IHRzLFxuICAgICAgICB4OiAwLFxuICAgICAgICB5OiAwLFxuICAgICAgICB3aWR0aDogMSwgLy8gbWF0Y2ggdGhlIHByaW1hcnkgaW1hZ2UncyBub3JtYWxpemVkIHBsYWNlbWVudFxuICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAvLyBMb2FkIHRpbGVzIGV2ZW4gdGhvdWdoIGl0J3MgaGlkZGVuIOKAlCB0aGlzIGlzIHdoYXQgbGV0cyB0aGUgYmFja2dyb3VuZFxuICAgICAgICAvLyBsb2FkZXIgZmlsbCBldmVyeSBzbGljZSdzIGNhY2hlIHNvIHNjcnViYmluZyBnZXRzIHByb2dyZXNzaXZlbHkgc21vb3RoZXIuXG4gICAgICAgIHByZWxvYWQ6IHRydWUsXG4gICAgICAgIHN1Y2Nlc3M6IChlOiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBpdGVtID0gZT8uaXRlbTtcbiAgICAgICAgICBpZiAodG9rZW4gIT09IHRoaXMuc2xpY2VMb2FkVG9rZW4pIHtcbiAgICAgICAgICAgIC8vIEltYWdlIHN3aXRjaGVkIHdoaWxlIHRoaXMgd2FzIGFkZGluZyDigJQgZHJvcCB0aGUgb3JwaGFuIHNvIGl0IHN0b3BzXG4gICAgICAgICAgICAvLyBsb2FkaW5nIGluc3RlYWQgb2Ygc3RyZWFtaW5nIHRpbGVzIGZvciB0aGUgYWJhbmRvbmVkIHN0YWNrLlxuICAgICAgICAgICAgaWYgKGl0ZW0pIHtcbiAgICAgICAgICAgICAgdHJ5IHsgdGhpcy5ob3N0LnZpZXdlcigpPy53b3JsZD8ucmVtb3ZlSXRlbShpdGVtKTsgfSBjYXRjaCB7IC8qIGdvbmUgKi8gfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLnNsaWNlc0xvYWRpbmcuZGVsZXRlKHopO1xuICAgICAgICAgIGlmICghaXRlbSkgcmV0dXJuO1xuICAgICAgICAgIHRoaXMuc2xpY2VJdGVtcy5zZXQoeiwgaXRlbSk7XG4gICAgICAgICAgdGhpcy50b3VjaFNsaWNlTHJ1KHopO1xuICAgICAgICAgIHRoaXMuaG9zdC5vbkNvbXBvc2l0ZVNsaWNlQWRkZWQoeik7XG4gICAgICAgICAgLy8gT25seSByZXZlYWwgaWYgdGhlIHVzZXIgaXMgc3RpbGwgb24gdGhpcyBzbGljZSAoZmFzdCBzY3J1YmJpbmcgbWF5XG4gICAgICAgICAgLy8gaGF2ZSBtb3ZlZCBvbiDigJQgbGVhdmUgaXQgY2FjaGVkL2hpZGRlbiBmb3IgYSBsYXRlciByZXZpc2l0KS5cbiAgICAgICAgICBpZiAoeiA9PT0gdGhpcy5ob3N0LmN1cnJlbnRaKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd09ubHlTbGljZSh6KTtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVQcmVmZXRjaCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmV2aWN0U2xpY2VMcnUoKTtcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3I6ICgpID0+IHtcbiAgICAgICAgICBpZiAodG9rZW4gPT09IHRoaXMuc2xpY2VMb2FkVG9rZW4pIHRoaXMuc2xpY2VzTG9hZGluZy5kZWxldGUoeik7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuc2xpY2VzTG9hZGluZy5kZWxldGUoeik7XG4gICAgICBjb25zb2xlLndhcm4oJ1tPU0RdIGZhaWxlZCB0byBhZGQgei1zbGljZScsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBzbGljZSB6J3MgY2hhbm5lbCBncm91cDogb25lIGFkZGl0aXZlbHktY29tcG9zaXRlZCAoJ2xpZ2h0ZXInID0gRmlqaVxuICAgKiBcIkNvbXBvc2l0ZVwiKSBUaWxlZEltYWdlIHBlciBjaGFubmVsLCBoaWRkZW4gKG9wYWNpdHkgMCkgdW50aWwgcmV2ZWFsZWQuXG4gICAqIEVhY2ggaXMgcHJlbG9hZGVkIHNvIHRoZSBiYWNrZ3JvdW5kIGxvYWRlciBjYW4gcHJlLWZpbGwgZXZlcnkgc2xpY2UuXG4gICAqIENhY2hlZCBzbyBhIHJldmlzaXQgaXMgYW4gaW5zdGFudCBvcGFjaXR5IHRvZ2dsZSDigJQgbm8gcmUtZmV0Y2gsIG5vXG4gICAqIHdoaXRlLWZsaWNrZXIuIE1pcnJvcnMgYWRkU2xpY2UgZm9yIHRoZSBjb21wb3NpdGUgcGF0aC5cbiAgICovXG4gIGFkZENoYW5uZWxTbGljZSh6OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaG9zdC5oYXNJbWFnZSgpKSByZXR1cm47XG4gICAgaWYgKHRoaXMuY2hhbm5lbFNsaWNlSXRlbXMuaGFzKHopIHx8IHRoaXMuc2xpY2VzTG9hZGluZy5oYXMoeikpIHJldHVybjtcbiAgICB0aGlzLnNsaWNlc0xvYWRpbmcuYWRkKHopO1xuICAgIGNvbnN0IHRva2VuID0gdGhpcy5zbGljZUxvYWRUb2tlbjtcbiAgICBjb25zdCBuID0gdGhpcy5ob3N0LmNoYW5uZWxDb3VudCgpO1xuICAgIGNvbnN0IGdyb3VwOiBhbnlbXSA9IG5ldyBBcnJheShuKTtcbiAgICBsZXQgc2V0dGxlZCA9IDA7XG4gICAgY29uc3Qgb25TZXR0bGVkID0gKCkgPT4ge1xuICAgICAgaWYgKCsrc2V0dGxlZCA8IG4pIHJldHVybjtcbiAgICAgIGlmICh0b2tlbiAhPT0gdGhpcy5zbGljZUxvYWRUb2tlbikgcmV0dXJuOyAvLyBpbWFnZSBzd2l0Y2hlZCBtaWQtYWRkXG4gICAgICB0aGlzLnNsaWNlc0xvYWRpbmcuZGVsZXRlKHopO1xuICAgICAgdGhpcy5jaGFubmVsU2xpY2VJdGVtcy5zZXQoeiwgZ3JvdXApO1xuICAgICAgdGhpcy5zdGFsZVNsaWNlcy5kZWxldGUoeik7IC8vIGZyZXNobHkgdGludGVkIGF0IHRoZSBjdXJyZW50IGRpc3BsYXkgc3RhdGVcbiAgICAgIHRoaXMudG91Y2hTbGljZUxydSh6KTtcbiAgICAgIGlmICh6ID09PSB0aGlzLmhvc3QuY3VycmVudFooKSkge1xuICAgICAgICB0aGlzLnJldmVhbENoYW5uZWxTbGljZSh6KTsgLy8gdGlsZXMgbWF5IHN0aWxsIGJlIGRlY29kaW5nOyBvcGFjaXR5IGlzIHNldCBub3dcbiAgICAgICAgdGhpcy5zY2hlZHVsZVByZWZldGNoKCk7XG4gICAgICB9XG4gICAgICB0aGlzLmV2aWN0U2xpY2VMcnUoKTtcbiAgICB9O1xuICAgIGZvciAobGV0IGMgPSAwOyBjIDwgbjsgYysrKSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLmhvc3Qudmlld2VyKCkuYWRkVGlsZWRJbWFnZSh7XG4gICAgICAgICAgdGlsZVNvdXJjZTogdGhpcy5ob3N0LmJ1aWxkVGlsZVNvdXJjZSh6LCBjKSxcbiAgICAgICAgICB4OiAwLCB5OiAwLCB3aWR0aDogMSxcbiAgICAgICAgICBvcGFjaXR5OiAwLCAvLyByZXZlYWxlZCBieSByZXZlYWxDaGFubmVsU2xpY2Ugb25jZSB0aGUgZ3JvdXAgaXMgaW5cbiAgICAgICAgICBjb21wb3NpdGVPcGVyYXRpb246ICdsaWdodGVyJyxcbiAgICAgICAgICBwcmVsb2FkOiB0cnVlLFxuICAgICAgICAgIHN1Y2Nlc3M6IChlOiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGl0ZW0gPSBlPy5pdGVtO1xuICAgICAgICAgICAgaWYgKHRva2VuICE9PSB0aGlzLnNsaWNlTG9hZFRva2VuKSB7XG4gICAgICAgICAgICAgIGlmIChpdGVtKSB7IHRyeSB7IHRoaXMuaG9zdC52aWV3ZXIoKT8ud29ybGQ/LnJlbW92ZUl0ZW0oaXRlbSk7IH0gY2F0Y2ggeyAvKiBnb25lICovIH0gfVxuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXRlbSkgZ3JvdXBbY10gPSBpdGVtO1xuICAgICAgICAgICAgb25TZXR0bGVkKCk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBlcnJvcjogKCkgPT4gb25TZXR0bGVkKCksXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW09TRF0gZmFpbGVkIHRvIGFkZCBjaGFubmVsIHNsaWNlIGltYWdlJywgeiwgYywgZXJyKTtcbiAgICAgICAgb25TZXR0bGVkKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqIFJldmVhbCBzbGljZSB6J3MgY2hhbm5lbCBncm91cCAoZWFjaCB2aXNpYmxlIGNoYW5uZWwg4oaSIG9wYWNpdHkgMSkgYW5kXG4gICAqICBoaWRlIGV2ZXJ5IG90aGVyIGNhY2hlZCBzbGljZSdzIGdyb3VwLiBJbnN0YW50OyBubyBmZXRjaC9kZWNvZGUuICovXG4gIHJldmVhbENoYW5uZWxTbGljZSh6OiBudW1iZXIpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IFt6eiwgZ3JvdXBdIG9mIHRoaXMuY2hhbm5lbFNsaWNlSXRlbXMpIHtcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IHp6ID09PSB6O1xuICAgICAgZ3JvdXAuZm9yRWFjaCgoaXQsIGMpID0+IHtcbiAgICAgICAgaWYgKCFpdCkgcmV0dXJuO1xuICAgICAgICBjb25zdCB2aXNpYmxlID0gdGhpcy5ob3N0LmNoYW5uZWxWaXNpYmxlKGMpO1xuICAgICAgICB0cnkgeyBpdC5zZXRPcGFjaXR5KGFjdGl2ZSAmJiB2aXNpYmxlID8gMSA6IDApOyB9IGNhdGNoIHsgLyogZ29uZSAqLyB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvKiogU2hvdyB0aGUgZ2l2ZW4gY29tcG9zaXRlIHNsaWNlIChvcGFjaXR5IDEpIGFuZCBoaWRlIGFsbCBvdGhlciBjYWNoZWQgc2xpY2VzLiAqL1xuICBwcml2YXRlIHNob3dPbmx5U2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBbenosIGl0ZW1dIG9mIHRoaXMuc2xpY2VJdGVtcykge1xuICAgICAgdHJ5IHsgaXRlbS5zZXRPcGFjaXR5KHp6ID09PSB6ID8gMSA6IDApOyB9IGNhdGNoIHsgLyogaXRlbSBnb25lICovIH1cbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgZGlzcGxheSBpbnZhbGlkYXRpb24gKG11bHRpY2hhbm5lbCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFJlLXRpbnQgYWZ0ZXIgYSBkaXNwbGF5IGNoYW5nZTogaW52YWxpZGF0ZSBPTkxZIHRoZSB2aXNpYmxlIHNsaWNlJ3NcbiAgICogIGNoYW5uZWwgaW1hZ2VzIOKAlCBpbnZhbGlkYXRpbmcgdGhlIHdob2xlIHdvcmxkIHdvdWxkIHJlLXByb2Nlc3MgZXZlcnlcbiAgICogIGhpZGRlbi9wcmVsb2FkZWQgc2xpY2UncyB0aWxlcyAoaHVuZHJlZHMpLCBmbG9vZGluZyBPU0QgYW5kIHdhc3Rpbmcgd29ya1xuICAgKiAgb24gdGlsZXMgdGhhdCBhcmVuJ3Qgb24gc2NyZWVuLiBUaGUgb3RoZXIgY2FjaGVkIHNsaWNlcyBhcmUgbWFya2VkIHN0YWxlXG4gICAqICBhbmQgcmUtdGludGVkIGxhemlseSB3aGVuIHJldmVhbGVkLiAqL1xuICBpbnZhbGlkYXRlQ2hhbm5lbERpc3BsYXkoejogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5pbnZhbGlkYXRlU2xpY2Uoeik7XG4gICAgdGhpcy5zdGFsZVNsaWNlcy5jbGVhcigpO1xuICAgIGZvciAoY29uc3Qgenogb2YgdGhpcy5jaGFubmVsU2xpY2VJdGVtcy5rZXlzKCkpIHtcbiAgICAgIGlmICh6eiAhPT0geikgdGhpcy5zdGFsZVNsaWNlcy5hZGQoenopO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBJbnZhbGlkYXRlIChyZXN0b3JlICsgcmUtcmVjb2xvcikganVzdCB0aGUgY2hhbm5lbCBpbWFnZXMgb2Ygb25lIGNhY2hlZFxuICAgKiAgc2xpY2UuIEEgc2hhcmVkIHRpbWVzdGFtcCBiYXRjaGVzIHRoZSBwZXItaW1hZ2UgaW52YWxpZGF0aW9ucyBpbnRvIG9uZVxuICAgKiAgcHJvY2Vzc2luZyBwYXNzIChPU0QgZGVkdXBlcyB0aWxlcyBhbHJlYWR5IHN0YW1wZWQgYXQgPj0gdFN0YW1wKS4gKi9cbiAgcHJpdmF0ZSBpbnZhbGlkYXRlU2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgZ3JvdXAgPSB0aGlzLmNoYW5uZWxTbGljZUl0ZW1zLmdldCh6KSA/PyBbXTtcbiAgICBpZiAoIWdyb3VwLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IG9zZDogYW55ID0gT1NEO1xuICAgIGNvbnN0IHRTdGFtcCA9IHR5cGVvZiBvc2Qubm93ID09PSAnZnVuY3Rpb24nID8gb3NkLm5vdygpIDogRGF0ZS5ub3coKTtcbiAgICBmb3IgKGNvbnN0IGl0IG9mIGdyb3VwKSB7XG4gICAgICBpZiAoaXQgJiYgdHlwZW9mIGl0LnJlcXVlc3RJbnZhbGlkYXRlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRyeSB7IGl0LnJlcXVlc3RJbnZhbGlkYXRlKHRydWUsIGZhbHNlLCB0U3RhbXApOyB9IGNhdGNoIHsgLyogZ29uZSAqLyB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIGJhY2tncm91bmQgc3RhY2sgcHJlbG9hZGluZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogRGVib3VuY2Ugc28gYSBidXJzdCBvZiB2aWV3cG9ydC9zbGljZSBldmVudHMgY29hbGVzY2VzLCB0aGVuIGFkdmFuY2UgdGhlXG4gICAqICBiYWNrZ3JvdW5kIHN0YWNrIGxvYWRlciBieSBvbmUgc2xpY2UuICovXG4gIHNjaGVkdWxlUHJlZmV0Y2goKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2tpcFNsaWNlUHJlZmV0Y2gpIHJldHVybjtcbiAgICBpZiAodGhpcy5wcmVmZXRjaFRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy5wcmVmZXRjaFRpbWVyKTtcbiAgICB0aGlzLnByZWZldGNoVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHRoaXMubG9hZE5leHRCYWNrZ3JvdW5kU2xpY2UoKSwgMjAwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCYWNrZ3JvdW5kLWxvYWQgdGhlIHdob2xlIHN0YWNrOiBhZGQgZWFjaCBub3QteWV0LWNhY2hlZCBzbGljZSBhcyBhXG4gICAqIGhpZGRlbiwgcHJlbG9hZGVkIHRpbGVkIGltYWdlLCBvbmUgYXQgYSB0aW1lLCB3b3JraW5nIG91dHdhcmQgZnJvbSB0aGVcbiAgICogY3VycmVudCBzbGljZSDigJQgYW5kIG5ldmVyIGJsb2NraW5nIHRoZSB2aXNpYmxlIHNsaWNlIChpdCB5aWVsZHMgd2hpbGUgdGhlXG4gICAqIGN1cnJlbnQgdmlldyBpcyBzdGlsbCBzdHJlYW1pbmcgdGlsZXM7IG9ubHkgb25lIHNsaWNlIGlzIGluIGZsaWdodCBhdCBhXG4gICAqIHRpbWUgc28gdGhlIG9uLXNjcmVlbiB0aWxlcyBhbHdheXMgd2luIHRoZSBjb25uZWN0aW9uKS5cbiAgICovXG4gIHByaXZhdGUgbG9hZE5leHRCYWNrZ3JvdW5kU2xpY2UoKTogdm9pZCB7XG4gICAgdGhpcy5wcmVmZXRjaFRpbWVyID0gbnVsbDtcbiAgICBpZiAoIXRoaXMuaG9zdC5oYXNJbWFnZSgpKSByZXR1cm47XG4gICAgY29uc3Qgc2xpY2VDb3VudCA9IHRoaXMuaG9zdC5zbGljZUNvdW50KCk7XG4gICAgaWYgKHNsaWNlQ291bnQgPD0gMSkgcmV0dXJuOyAvLyBub3QgYSBzdGFjayDigJQgbm90aGluZyB0byBwcmVsb2FkXG4gICAgLy8gWWllbGQgdG8gdGhlIHZpc2libGUgc2xpY2Ugd2hpbGUgaXQncyBzdGlsbCBzdHJlYW1pbmcgdGlsZXMuXG4gICAgaWYgKHRoaXMuc2xpY2VUaWxlc0xvYWRpbmcodGhpcy5ob3N0LmN1cnJlbnRaKCkpKSB7XG4gICAgICB0aGlzLnNjaGVkdWxlUHJlZmV0Y2goKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gR2F0ZSBvbiB0aGUgaW4tZmxpZ2h0IHNsaWNlJ3MgVElMRVMgZmluaXNoaW5nIOKAlCBhZGRUaWxlZEltYWdlJ3Mgc3VjY2Vzc1xuICAgIC8vIGZpcmVzIG9uIGFkZCwgbm90IG9uIHRpbGUgbG9hZCwgc28gd2l0aG91dCB0aGlzIHdlJ2QgYWRkIHRoZSB3aG9sZSBzdGFja1xuICAgIC8vIGF0IG9uY2UgYW5kIGZsb29kIHRoZSBjb25uZWN0aW9uLiBBIHRpbWUgZmFsbGJhY2sgcHJldmVudHMgYSBzdHVjayBzbGljZVxuICAgIC8vIGZyb20gc3RhbGxpbmcgdGhlIHBhc3MuXG4gICAgaWYgKHRoaXMuYmdMb2FkaW5nWiAhPSBudWxsKSB7XG4gICAgICBjb25zdCBhZGRpbmcgPSB0aGlzLnNsaWNlc0xvYWRpbmcuaGFzKHRoaXMuYmdMb2FkaW5nWik7XG4gICAgICBjb25zdCB0aWxlc0xvYWRpbmcgPSB0aGlzLnNsaWNlVGlsZXNMb2FkaW5nKHRoaXMuYmdMb2FkaW5nWik7XG4gICAgICBjb25zdCB0aW1lZE91dCA9IERhdGUubm93KCkgLSB0aGlzLmJnTG9hZGluZ1NpbmNlID4gODAwMDtcbiAgICAgIGlmICgoYWRkaW5nIHx8IHRpbGVzTG9hZGluZykgJiYgIXRpbWVkT3V0KSB7XG4gICAgICAgIHRoaXMuc2NoZWR1bGVQcmVmZXRjaCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLmJnTG9hZGluZ1ogPSBudWxsOyAvLyB0aGF0IHNsaWNlJ3MgdGlsZXMgYXJlIGluIChvciBnYXZlIHVwKSDigJQgYWR2YW5jZVxuICAgIH1cbiAgICBjb25zdCBuZXh0ID0gdGhpcy5uZWFyZXN0VW5jYWNoZWRTbGljZShzbGljZUNvdW50KTtcbiAgICBpZiAobmV4dCA9PSBudWxsKSByZXR1cm47IC8vIHdob2xlIHN0YWNrIGNhY2hlZCDigJQgZG9uZVxuICAgIHRoaXMuYmdMb2FkaW5nWiA9IG5leHQ7XG4gICAgdGhpcy5iZ0xvYWRpbmdTaW5jZSA9IERhdGUubm93KCk7XG4gICAgdGhpcy5iZ0F0dGVtcHRlZC5hZGQobmV4dCk7XG4gICAgdGhpcy5hZGRTbGljZShuZXh0KTsgLy8gaGlkZGVuICsgcHJlbG9hZCAoYWRkZWQgd2l0aCBvcGFjaXR5IDA7IG5vdCByZXZlYWxlZClcbiAgICB0aGlzLnNjaGVkdWxlUHJlZmV0Y2goKTsgLy8gcG9sbCB1bnRpbCBpdHMgdGlsZXMgbG9hZCwgdGhlbiBhZHZhbmNlXG4gIH1cblxuICAvKiogVGhlIG5vdC15ZXQtY2FjaGVkIHNsaWNlIGNsb3Nlc3QgdG8gdGhlIGN1cnJlbnQgb25lIChsb2FkIG5lYXJlc3QgZmlyc3QpLFxuICAgKiAgc2tpcHBpbmcgYW55IGFscmVhZHkgYXR0ZW1wdGVkIHNvIGEgZmFpbGVkL3Nsb3cgb25lIGlzbid0IHJldHJpZWQgaW4gYSBsb29wLiAqL1xuICBwcml2YXRlIG5lYXJlc3RVbmNhY2hlZFNsaWNlKHNsaWNlQ291bnQ6IG51bWJlcik6IG51bWJlciB8IG51bGwge1xuICAgIGNvbnN0IGN1ciA9IHRoaXMuaG9zdC5jdXJyZW50WigpO1xuICAgIGZvciAobGV0IGQgPSAwOyBkIDwgc2xpY2VDb3VudDsgZCsrKSB7XG4gICAgICBjb25zdCBjYW5kaWRhdGVzID0gZCA9PT0gMCA/IFtjdXJdIDogW2N1ciAtIGQsIGN1ciArIGRdO1xuICAgICAgZm9yIChjb25zdCB6IG9mIGNhbmRpZGF0ZXMpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHogPj0gMCAmJiB6IDwgc2xpY2VDb3VudCAmJlxuICAgICAgICAgICF0aGlzLnNsaWNlQ2FjaGVIYXMoeikgJiYgIXRoaXMuc2xpY2VzTG9hZGluZy5oYXMoeikgJiYgIXRoaXMuYmdBdHRlbXB0ZWQuaGFzKHopXG4gICAgICAgICkge1xuICAgICAgICAgIHJldHVybiB6O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0b3AgYmFja2dyb3VuZCBzdGFjayBwcmVsb2FkaW5nIGFuZCBpbnZhbGlkYXRlIGFueSBpbi1mbGlnaHQgc2xpY2UgYWRkLlxuICAgKiBDYWxsZWQgd2hlbiBhIGRpZmZlcmVudCBpbWFnZSBpcyBzZWxlY3RlZCBzbyB0aGUgcHJldmlvdXMgc3RhY2sgc3RvcHNcbiAgICogbG9hZGluZyBpbW1lZGlhdGVseSBpbnN0ZWFkIG9mIGZpbmlzaGluZyBpbiB0aGUgYmFja2dyb3VuZC5cbiAgICovXG4gIGNhbmNlbEJhY2tncm91bmRMb2FkKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnByZWZldGNoVGltZXIpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLnByZWZldGNoVGltZXIpO1xuICAgICAgdGhpcy5wcmVmZXRjaFRpbWVyID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5zbGljZXNMb2FkaW5nLmNsZWFyKCk7XG4gICAgdGhpcy5iZ0xvYWRpbmdaID0gbnVsbDtcbiAgICB0aGlzLmJnQXR0ZW1wdGVkLmNsZWFyKCk7XG4gICAgdGhpcy5zbGljZUxvYWRUb2tlbisrOyAvLyBkcm9wIHBlbmRpbmcgYWRkVGlsZWRJbWFnZSBjYWxsYmFja3MgZnJvbSB0aGUgb2xkIGltYWdlXG4gICAgLy8gQWJvcnQgaW4tZmxpZ2h0IGJhY2tncm91bmQgdGlsZXMgaW1tZWRpYXRlbHkgYnkgZHJvcHBpbmcgdGhlIGhpZGRlblxuICAgIC8vIHByZWxvYWRlZCBzbGljZXMgKHJlbW92ZUl0ZW0gY2FuY2VscyB0aGVpciBwZW5kaW5nIHRpbGUgbG9hZHMpLiBLZWVwIHRoZVxuICAgIC8vIHZpc2libGUgc2xpY2Ugc28gdGhlIGN1cnJlbnQgdmlldyBkb2Vzbid0IGJsYW5rIGJlZm9yZSB0aGUgbmV4dCBwbG90LlxuICAgIHRoaXMuZHJvcEhpZGRlblNsaWNlcygpO1xuICB9XG5cbiAgLyoqIFJlbW92ZSBldmVyeSBjYWNoZWQgc2xpY2UgZXhjZXB0IHRoZSBjdXJyZW50bHkgZGlzcGxheWVkIG9uZSwgYWJvcnRpbmdcbiAgICogIHRoZWlyIGluLWZsaWdodCB0aWxlIHJlcXVlc3RzLiAqL1xuICBwcml2YXRlIGRyb3BIaWRkZW5TbGljZXMoKTogdm9pZCB7XG4gICAgY29uc3QgdiA9IHRoaXMuaG9zdC52aWV3ZXIoKTtcbiAgICBpZiAoIXYpIHJldHVybjtcbiAgICBjb25zdCBjdXIgPSB0aGlzLmhvc3QuY3VycmVudFooKTtcbiAgICBmb3IgKGNvbnN0IFt6LCBpdGVtXSBvZiBbLi4udGhpcy5zbGljZUl0ZW1zXSkge1xuICAgICAgaWYgKHogPT09IGN1cikgY29udGludWU7XG4gICAgICB0aGlzLnNsaWNlSXRlbXMuZGVsZXRlKHopO1xuICAgICAgdHJ5IHsgdi53b3JsZC5yZW1vdmVJdGVtKGl0ZW0pOyB9IGNhdGNoIHsgLyogYWxyZWFkeSBnb25lICovIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBbeiwgZ3JvdXBdIG9mIFsuLi50aGlzLmNoYW5uZWxTbGljZUl0ZW1zXSkge1xuICAgICAgaWYgKHogPT09IGN1cikgY29udGludWU7XG4gICAgICB0aGlzLmNoYW5uZWxTbGljZUl0ZW1zLmRlbGV0ZSh6KTtcbiAgICAgIGZvciAoY29uc3QgaXQgb2YgZ3JvdXApIHsgaWYgKGl0KSB7IHRyeSB7IHYud29ybGQucmVtb3ZlSXRlbShpdCk7IH0gY2F0Y2ggeyAvKiBnb25lICovIH0gfSB9XG4gICAgfVxuICAgIHRoaXMuc2xpY2VMcnUgPSB0aGlzLnNsaWNlQ2FjaGVIYXMoY3VyKSA/IFtjdXJdIDogW107XG4gIH1cblxuICAvLyDilIDilIAgY2FjaGUgYm9va2tlZXBpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFdoZXRoZXIgc2xpY2UgeiBpcyBpbiB0aGUgYWN0aXZlIGNhY2hlIChjb21wb3NpdGUgc2luZ2xlIGltYWdlLCBvciB0aGVcbiAgICogIG11bHRpY2hhbm5lbCBwZXItY2hhbm5lbCBncm91cCkuICovXG4gIHByaXZhdGUgc2xpY2VDYWNoZUhhcyh6OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5ob3N0LmlzTXVsdGlDaGFubmVsKCkgPyB0aGlzLmNoYW5uZWxTbGljZUl0ZW1zLmhhcyh6KSA6IHRoaXMuc2xpY2VJdGVtcy5oYXMoeik7XG4gIH1cblxuICAvKiogVGhlIGNhY2hlZCBUaWxlZEltYWdlKHMpIGZvciBzbGljZSB6ICgw4oCTMSBmb3IgY29tcG9zaXRlLCBOIGZvciBtdWx0aWNoYW5uZWwpLiAqL1xuICBwcml2YXRlIHNsaWNlR3JvdXAoejogbnVtYmVyKTogYW55W10ge1xuICAgIGlmICh0aGlzLmhvc3QuaXNNdWx0aUNoYW5uZWwoKSkgcmV0dXJuIHRoaXMuY2hhbm5lbFNsaWNlSXRlbXMuZ2V0KHopID8/IFtdO1xuICAgIGNvbnN0IGl0ID0gdGhpcy5zbGljZUl0ZW1zLmdldCh6KTtcbiAgICByZXR1cm4gaXQgPyBbaXRdIDogW107XG4gIH1cblxuICAvKiogV2hldGhlciBzbGljZSB6J3MgdGlsZXMgYXJlIHN0aWxsIHN0cmVhbWluZyAoYW55IGNhY2hlZCBpbWFnZSBub3QgZnVsbHkgbG9hZGVkKS4gKi9cbiAgcHJpdmF0ZSBzbGljZVRpbGVzTG9hZGluZyh6OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBjb25zdCBnID0gdGhpcy5zbGljZUdyb3VwKHopO1xuICAgIGlmICghZy5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gZy5zb21lKChpdCkgPT4gaXQgJiYgdHlwZW9mIGl0LmdldEZ1bGx5TG9hZGVkID09PSAnZnVuY3Rpb24nICYmICFpdC5nZXRGdWxseUxvYWRlZCgpKTtcbiAgfVxuXG4gIC8qKiBSZW1vdmUgc2xpY2UgeidzIGNhY2hlZCBpbWFnZShzKSBmcm9tIHRoZSB3b3JsZCBhbmQgdGhlIGFjdGl2ZSBjYWNoZS4gKi9cbiAgcHJpdmF0ZSByZW1vdmVDYWNoZWRTbGljZSh6OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCB2ID0gdGhpcy5ob3N0LnZpZXdlcigpO1xuICAgIGlmICh0aGlzLmhvc3QuaXNNdWx0aUNoYW5uZWwoKSkge1xuICAgICAgY29uc3QgZ3JvdXAgPSB0aGlzLmNoYW5uZWxTbGljZUl0ZW1zLmdldCh6KTtcbiAgICAgIHRoaXMuY2hhbm5lbFNsaWNlSXRlbXMuZGVsZXRlKHopO1xuICAgICAgaWYgKGdyb3VwICYmIHYpIGZvciAoY29uc3QgaXQgb2YgZ3JvdXApIHsgaWYgKGl0KSB7IHRyeSB7IHYud29ybGQucmVtb3ZlSXRlbShpdCk7IH0gY2F0Y2ggeyAvKiBnb25lICovIH0gfSB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLnNsaWNlSXRlbXMuZ2V0KHopO1xuICAgICAgdGhpcy5zbGljZUl0ZW1zLmRlbGV0ZSh6KTtcbiAgICAgIGlmIChpdGVtICYmIHYpIHsgdHJ5IHsgdi53b3JsZC5yZW1vdmVJdGVtKGl0ZW0pOyB9IGNhdGNoIHsgLyogZ29uZSAqLyB9IH1cbiAgICB9XG4gIH1cblxuICAvKiogSXMgdGhlIHRpbGVkIGltYWdlIHN0aWxsIGluIHRoZSB3b3JsZCAobm90IGV2aWN0ZWQpPyAqL1xuICBwcml2YXRlIHNsaWNlSW5Xb3JsZChpdGVtOiBhbnkpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRoaXMuaG9zdC52aWV3ZXIoKS53b3JsZC5nZXRJbmRleE9mSXRlbShpdGVtKSA+PSAwO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBNYXJrIHogYXMgbW9zdC1yZWNlbnRseS11c2VkLiAqL1xuICBwcml2YXRlIHRvdWNoU2xpY2VMcnUoejogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgaSA9IHRoaXMuc2xpY2VMcnUuaW5kZXhPZih6KTtcbiAgICBpZiAoaSA+PSAwKSB0aGlzLnNsaWNlTHJ1LnNwbGljZShpLCAxKTtcbiAgICB0aGlzLnNsaWNlTHJ1LnB1c2goeik7XG4gIH1cblxuICAvKiogRHJvcCB0aGUgbGVhc3QtcmVjZW50bHktdXNlZCBjYWNoZWQgc2xpY2VzIGJleW9uZCB0aGUgY2FwIChuZXZlciB0aGVcbiAgICogIGN1cnJlbnQgb25lKSwgcmVtb3ZpbmcgdGhlaXIgdGlsZWQgaW1hZ2VzIHNvIG1lbW9yeSBzdGF5cyBib3VuZGVkLiAqL1xuICBwcml2YXRlIGV2aWN0U2xpY2VMcnUoKTogdm9pZCB7XG4gICAgd2hpbGUgKHRoaXMuc2xpY2VMcnUubGVuZ3RoID4gdGhpcy5tYXhDYWNoZWRTbGljZXMpIHtcbiAgICAgIGNvbnN0IGN1ciA9IHRoaXMuaG9zdC5jdXJyZW50WigpO1xuICAgICAgY29uc3QgaWR4ID0gdGhpcy5zbGljZUxydS5maW5kSW5kZXgoKHopID0+IHogIT09IGN1cik7XG4gICAgICBpZiAoaWR4IDwgMCkgYnJlYWs7XG4gICAgICBjb25zdCB6ID0gdGhpcy5zbGljZUxydS5zcGxpY2UoaWR4LCAxKVswXTtcbiAgICAgIHRoaXMucmVtb3ZlQ2FjaGVkU2xpY2Uoeik7XG4gICAgfVxuICB9XG5cbiAgLyoqIENsZWFyIHRoZSBjYWNoZSAob24gdGVhcmRvd24gLyBpbWFnZSBzd2l0Y2gpLiAqL1xuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLnNsaWNlSXRlbXMuY2xlYXIoKTtcbiAgICB0aGlzLmNoYW5uZWxTbGljZUl0ZW1zLmNsZWFyKCk7XG4gICAgdGhpcy5zdGFsZVNsaWNlcy5jbGVhcigpO1xuICAgIHRoaXMuc2xpY2VMcnUgPSBbXTtcbiAgICB0aGlzLnNsaWNlc0xvYWRpbmcuY2xlYXIoKTtcbiAgICB0aGlzLmJnTG9hZGluZ1ogPSBudWxsO1xuICAgIHRoaXMuYmdBdHRlbXB0ZWQuY2xlYXIoKTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { firstValueFrom } from 'rxjs';
|
|
2
|
+
import { timeout } from 'rxjs/operators';
|
|
3
|
+
/** Build the `/tile` request URL — the one place its query shape lives. */
|
|
4
|
+
export function buildTileUrl(api, infoB64, c) {
|
|
5
|
+
const ch = c.channel == null ? '' : `&channel=${c.channel}`;
|
|
6
|
+
return `${api}tile?info=${infoB64}&res=${c.res}&col=${c.col}&row=${c.row}&z=${c.z}&tileSize=${c.tileSize}${ch}`;
|
|
7
|
+
}
|
|
8
|
+
/** Fetch a tile PNG and decode it to an ImageBitmap. The caller owns the
|
|
9
|
+
* bitmap (call `close()` when done). Throws on network/decode failure. */
|
|
10
|
+
export async function fetchTileBitmap(http, url, timeoutMs) {
|
|
11
|
+
const blob = await firstValueFrom(http.get(url, { responseType: 'blob' }).pipe(timeout(timeoutMs)));
|
|
12
|
+
return createImageBitmap(blob);
|
|
13
|
+
}
|
|
14
|
+
/** Fetch a tile and read its pixels back as RGBA ImageData (via an offscreen
|
|
15
|
+
* canvas). Returns null only when a 2d context can't be created; throws on
|
|
16
|
+
* network/decode failure (the caller's tagged catch handles it). */
|
|
17
|
+
export async function fetchTileRgba(http, url, timeoutMs) {
|
|
18
|
+
const bmp = await fetchTileBitmap(http, url, timeoutMs);
|
|
19
|
+
const cv = document.createElement('canvas');
|
|
20
|
+
cv.width = bmp.width;
|
|
21
|
+
cv.height = bmp.height;
|
|
22
|
+
const ctx = cv.getContext('2d', { willReadFrequently: true });
|
|
23
|
+
if (!ctx)
|
|
24
|
+
return null;
|
|
25
|
+
ctx.drawImage(bmp, 0, 0);
|
|
26
|
+
bmp.close?.();
|
|
27
|
+
return ctx.getImageData(0, 0, cv.width, cv.height);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGlsZS1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9vc2QvdGlsZS1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUEwQnpDLDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsWUFBWSxDQUFDLEdBQVcsRUFBRSxPQUFlLEVBQUUsQ0FBYTtJQUN0RSxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1RCxPQUFPLEdBQUcsR0FBRyxhQUFhLE9BQU8sUUFBUSxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxRQUFRLEdBQUcsRUFBRSxFQUFFLENBQUM7QUFDbEgsQ0FBQztBQUVEOzJFQUMyRTtBQUMzRSxNQUFNLENBQUMsS0FBSyxVQUFVLGVBQWUsQ0FBQyxJQUFnQixFQUFFLEdBQVcsRUFBRSxTQUFpQjtJQUNwRixNQUFNLElBQUksR0FBRyxNQUFNLGNBQWMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BHLE9BQU8saUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUVEOztxRUFFcUU7QUFDckUsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQ2pDLElBQWdCLEVBQUUsR0FBVyxFQUFFLFNBQWlCO0lBRWhELE1BQU0sR0FBRyxHQUFHLE1BQU0sZUFBZSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDeEQsTUFBTSxFQUFFLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1QyxFQUFFLENBQUMsS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUM7SUFDckIsRUFBRSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDO0lBQ3ZCLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM5RCxJQUFJLENBQUMsR0FBRztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3RCLEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN6QixHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztJQUNkLE9BQU8sR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3JELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRpbWVvdXQgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbi8qKlxuICogU2luZ2xlIHNvdXJjZSBvZiB0cnV0aCBmb3Igaml0LXNlcnZpY2UgYC90aWxlYCBhY2Nlc3MgZnJvbSB0aGUgT1NEIGJhY2tlbmRcbiAqIChyZWZhY3RvcmluZyBwbGFuLCBTdGVwIDIpLiBCZWZvcmUgdGhpcyBtb2R1bGUgdGhlIHRpbGUgVVJMIHdhcyBzdHJpbmctYnVpbHRcbiAqIGluIGZvdXIgcGxhY2VzIGFuZCB0aGUgZmV0Y2jihpJkZWNvZGUgcGlwZWxpbmUgY29weS1wYXN0ZWQgaW4gdGhyZWUg4oCUIGV2ZXJ5XG4gKiBxdWVyeS1wYXJhbSBjaGFuZ2UgaGFkIHRvIGJlIHJlcGVhdGVkIHBlciBzaXRlLlxuICpcbiAqIEVycm9yIGhhbmRsaW5nIGlzIGRlbGliZXJhdGVseSBsZWZ0IHRvIHRoZSBDQUxMIFNJVEVTOiB0aGVzZSBoZWxwZXJzXG4gKiBwcm9wYWdhdGUgZmFpbHVyZXMgc28gZWFjaCBjYWxsZXIga2VlcHMgaXRzIG93biB0YWdnZWQgY2F0Y2hcbiAqIChgW3ZpejpoaXN0b2dyYW1dYCwgYFt2aXo6d2luZG93XWAsIGBbdml6OmV4cG9ydF1gKSBhbmQgaXRzIG93blxuICogc2tpcC9mYWxsYmFjayBzZW1hbnRpY3MuXG4gKi9cblxuLyoqIFRpbGUgY29vcmRpbmF0ZXMgZm9yIG9uZSBgL3RpbGVgIHJlcXVlc3QuIGBjaGFubmVsID09IG51bGxgIChvciBvbWl0dGVkKVxuICogIHJlcXVlc3RzIHRoZSBzZXJ2ZXItY29tcG9zaXRlZCB0aWxlOyBhbiBpbmRleCAoaW5jbHVkaW5nIDApIHJlcXVlc3RzIHRoYXRcbiAqICBzaW5nbGUgY2hhbm5lbCBhcyBncmF5c2NhbGUuICovXG5leHBvcnQgaW50ZXJmYWNlIFRpbGVDb29yZHMge1xuICByZXM6IG51bWJlcjtcbiAgY29sOiBudW1iZXI7XG4gIHJvdzogbnVtYmVyO1xuICB6OiBudW1iZXI7XG4gIHRpbGVTaXplOiBudW1iZXI7XG4gIGNoYW5uZWw/OiBudW1iZXIgfCBudWxsO1xufVxuXG4vKiogQnVpbGQgdGhlIGAvdGlsZWAgcmVxdWVzdCBVUkwg4oCUIHRoZSBvbmUgcGxhY2UgaXRzIHF1ZXJ5IHNoYXBlIGxpdmVzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkVGlsZVVybChhcGk6IHN0cmluZywgaW5mb0I2NDogc3RyaW5nLCBjOiBUaWxlQ29vcmRzKTogc3RyaW5nIHtcbiAgY29uc3QgY2ggPSBjLmNoYW5uZWwgPT0gbnVsbCA/ICcnIDogYCZjaGFubmVsPSR7Yy5jaGFubmVsfWA7XG4gIHJldHVybiBgJHthcGl9dGlsZT9pbmZvPSR7aW5mb0I2NH0mcmVzPSR7Yy5yZXN9JmNvbD0ke2MuY29sfSZyb3c9JHtjLnJvd30mej0ke2Muen0mdGlsZVNpemU9JHtjLnRpbGVTaXplfSR7Y2h9YDtcbn1cblxuLyoqIEZldGNoIGEgdGlsZSBQTkcgYW5kIGRlY29kZSBpdCB0byBhbiBJbWFnZUJpdG1hcC4gVGhlIGNhbGxlciBvd25zIHRoZVxuICogIGJpdG1hcCAoY2FsbCBgY2xvc2UoKWAgd2hlbiBkb25lKS4gVGhyb3dzIG9uIG5ldHdvcmsvZGVjb2RlIGZhaWx1cmUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hUaWxlQml0bWFwKGh0dHA6IEh0dHBDbGllbnQsIHVybDogc3RyaW5nLCB0aW1lb3V0TXM6IG51bWJlcik6IFByb21pc2U8SW1hZ2VCaXRtYXA+IHtcbiAgY29uc3QgYmxvYiA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKGh0dHAuZ2V0KHVybCwgeyByZXNwb25zZVR5cGU6ICdibG9iJyB9KS5waXBlKHRpbWVvdXQodGltZW91dE1zKSkpO1xuICByZXR1cm4gY3JlYXRlSW1hZ2VCaXRtYXAoYmxvYik7XG59XG5cbi8qKiBGZXRjaCBhIHRpbGUgYW5kIHJlYWQgaXRzIHBpeGVscyBiYWNrIGFzIFJHQkEgSW1hZ2VEYXRhICh2aWEgYW4gb2Zmc2NyZWVuXG4gKiAgY2FudmFzKS4gUmV0dXJucyBudWxsIG9ubHkgd2hlbiBhIDJkIGNvbnRleHQgY2FuJ3QgYmUgY3JlYXRlZDsgdGhyb3dzIG9uXG4gKiAgbmV0d29yay9kZWNvZGUgZmFpbHVyZSAodGhlIGNhbGxlcidzIHRhZ2dlZCBjYXRjaCBoYW5kbGVzIGl0KS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaFRpbGVSZ2JhKFxuICBodHRwOiBIdHRwQ2xpZW50LCB1cmw6IHN0cmluZywgdGltZW91dE1zOiBudW1iZXIsXG4pOiBQcm9taXNlPEltYWdlRGF0YSB8IG51bGw+IHtcbiAgY29uc3QgYm1wID0gYXdhaXQgZmV0Y2hUaWxlQml0bWFwKGh0dHAsIHVybCwgdGltZW91dE1zKTtcbiAgY29uc3QgY3YgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgY3Yud2lkdGggPSBibXAud2lkdGg7XG4gIGN2LmhlaWdodCA9IGJtcC5oZWlnaHQ7XG4gIGNvbnN0IGN0eCA9IGN2LmdldENvbnRleHQoJzJkJywgeyB3aWxsUmVhZEZyZXF1ZW50bHk6IHRydWUgfSk7XG4gIGlmICghY3R4KSByZXR1cm4gbnVsbDtcbiAgY3R4LmRyYXdJbWFnZShibXAsIDAsIDApO1xuICBibXAuY2xvc2U/LigpO1xuICByZXR1cm4gY3R4LmdldEltYWdlRGF0YSgwLCAwLCBjdi53aWR0aCwgY3YuaGVpZ2h0KTtcbn1cbiJdfQ==
|