@jax-data-science/sci-image-visualizer 0.8.3 → 0.10.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/README.md +201 -460
- package/esm2022/index.mjs +34 -15
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
- package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
- package/esm2022/lib/contracts/color.mjs +60 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
- package/esm2022/lib/contracts/display-types.mjs +11 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/intensity.mjs +48 -5
- package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
- package/esm2022/lib/contracts/plot-type.mjs +134 -17
- package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
- package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
- package/esm2022/lib/contracts/sam.contract.mjs +1 -1
- package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
- package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/contracts/viz-config.mjs +2 -1
- package/esm2022/lib/geometry/contour.mjs +63 -0
- package/esm2022/lib/geometry/loft.mjs +128 -0
- package/esm2022/lib/geometry/polylabel.mjs +156 -0
- package/esm2022/lib/geometry/raster.mjs +98 -0
- package/esm2022/lib/geometry/reconstruct.mjs +315 -0
- package/esm2022/lib/geometry/reslice-image.mjs +57 -0
- package/esm2022/lib/geometry/ring.mjs +201 -0
- package/esm2022/lib/geometry/section.mjs +215 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
- package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
- package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
- package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
- package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +12 -9
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +83 -0
- package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +180 -591
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +270 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
- package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +347 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +427 -4207
- package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +550 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
- package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +194 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
- package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
- package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
- package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
- package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +164 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +213 -716
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
- package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
- package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
- package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
- package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
- package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
- package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
- package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
- package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
- package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
- package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
- package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
- package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
- package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
- package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
- package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
- package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
- package/esm2022/lib/implementations/region-centroids.mjs +47 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
- package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
- package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
- package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
- package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
- package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
- package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
- package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
- package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
- package/esm2022/lib/models/bezier.mjs +1 -11
- package/esm2022/lib/models/class-preset.mjs +41 -3
- package/esm2022/lib/models/geometry.mjs +27 -164
- package/esm2022/lib/models/polygon-edit.mjs +254 -0
- package/esm2022/lib/models/polygon-factory.mjs +134 -0
- package/esm2022/lib/models/region-clone.mjs +68 -0
- package/esm2022/lib/models/region-geojson.mjs +411 -0
- package/esm2022/lib/models/region.mjs +34 -33
- package/esm2022/lib/models/shape.mjs +18 -16
- package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
- package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
- package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
- package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
- package/esm2022/lib/plot.utilities.mjs +296 -473
- package/esm2022/lib/processing/image-crop.mjs +1 -1
- package/esm2022/lib/processing/processing-image.mjs +28 -15
- package/esm2022/lib/provide-visualization.mjs +40 -14
- package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
- package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +163 -0
- package/esm2022/lib/region-editor/file-stem.mjs +13 -0
- package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
- package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
- package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
- package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +896 -660
- package/esm2022/lib/region-editor/region-metrics.mjs +86 -0
- package/esm2022/lib/region-editor/region-persistence.service.mjs +160 -0
- package/esm2022/lib/region-editor/region-table/region-table.component.mjs +169 -0
- package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
- package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
- package/esm2022/lib/region-ops.service.mjs +28 -70
- package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
- package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
- package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
- package/esm2022/lib/region-overlay/region-style.mjs +97 -0
- package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
- package/esm2022/lib/region-source/http-region-source.mjs +104 -0
- package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
- package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
- package/esm2022/lib/region-source/region-source.mjs +67 -0
- package/esm2022/lib/region-source/region-tiles.mjs +708 -0
- package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
- package/esm2022/lib/render-orchestrator.mjs +14 -11
- package/esm2022/lib/render-session.mjs +207 -0
- package/esm2022/lib/routing-visualizer.service.mjs +858 -414
- package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
- package/esm2022/lib/spatial/density-raster.mjs +14 -0
- package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
- package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
- package/esm2022/lib/spatial/gene-search.mjs +1 -1
- package/esm2022/lib/spatial/glyphs.mjs +97 -0
- package/esm2022/lib/spatial/lod.mjs +187 -0
- package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
- package/esm2022/lib/spatial/spatial-density.mjs +25 -16
- package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
- package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
- package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
- package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
- package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
- package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
- package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
- package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
- package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
- package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
- package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
- package/esm2022/lib/spatial/stats.mjs +71 -0
- package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
- package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
- package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
- package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
- package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
- package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
- package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
- package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
- package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
- package/esm2022/lib/store/class-color.util.mjs +53 -5
- package/esm2022/lib/store/class-signatures.mjs +63 -0
- package/esm2022/lib/store/region-history.mjs +146 -0
- package/esm2022/lib/store/region-scope-cache.mjs +144 -0
- package/esm2022/lib/store/region-selection.mjs +82 -0
- package/esm2022/lib/store/region-source-scope.mjs +171 -0
- package/esm2022/lib/store/region-store.service.mjs +986 -670
- package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
- package/esm2022/lib/store/visualizer-store.service.mjs +81 -76
- package/esm2022/lib/toast-outlets.mjs +5 -4
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
- package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
- package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
- package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
- package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +120 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
- package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
- package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
- package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
- package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
- package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +121 -0
- package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
- package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
- package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
- package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
- package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
- package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
- package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
- package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +84 -119
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
- package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
- package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
- package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
- package/esm2022/lib/util/mark-for-check.mjs +17 -0
- package/esm2022/lib/util/supersede.mjs +56 -0
- package/esm2022/lib/visualization.module.mjs +39 -141
- package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
- package/esm2022/lib/visualizer/region-actions.mjs +149 -0
- package/esm2022/lib/visualizer/region-load.mjs +123 -0
- package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
- package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
- package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
- package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
- package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
- package/esm2022/lib/visualizer.component.mjs +602 -1902
- package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
- package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
- package/esm2022/lib/workers/spatial-math.mjs +190 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs +47169 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs +238 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/fesm2022/mask.worker.js +36 -917
- package/fesm2022/onnx-sam.worker.js +52 -16
- package/fesm2022/region-source.worker.js +1067 -0
- package/fesm2022/spatial-math.worker.js +471 -0
- package/fesm2022/tsne.worker.js +32 -15
- package/index.d.ts +19 -10
- package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
- package/lib/contracts/capabilities.contract.d.ts +4 -2
- package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
- package/lib/contracts/color.d.ts +27 -0
- package/lib/contracts/colormap-lut.d.ts +19 -4
- package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
- package/lib/contracts/display-types.d.ts +21 -0
- package/lib/contracts/image.contract.d.ts +4 -0
- package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
- package/lib/contracts/intensity.d.ts +13 -2
- package/lib/contracts/plot-type.d.ts +3 -1
- package/lib/contracts/ports/image-state.port.d.ts +6 -2
- package/lib/contracts/ports/preferences.port.d.ts +4 -0
- package/lib/contracts/ports/region-io.port.d.ts +1 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
- package/lib/contracts/ports/tile-access.port.d.ts +1 -0
- package/lib/contracts/region-editor-api.contract.d.ts +85 -1
- package/lib/contracts/region-overlay.contract.d.ts +5 -0
- package/lib/contracts/region-store.contract.d.ts +22 -0
- package/lib/contracts/sam.contract.d.ts +7 -0
- package/lib/contracts/section-view.contract.d.ts +44 -0
- package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
- package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
- package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
- package/lib/contracts/visualizer.contract.d.ts +231 -54
- package/lib/contracts/viz-config.d.ts +9 -0
- package/lib/geometry/contour.d.ts +24 -0
- package/lib/geometry/loft.d.ts +22 -0
- package/lib/geometry/polylabel.d.ts +23 -0
- package/lib/geometry/raster.d.ts +42 -0
- package/lib/geometry/reconstruct.d.ts +54 -0
- package/lib/geometry/reslice-image.d.ts +33 -0
- package/lib/geometry/ring.d.ts +67 -0
- package/lib/geometry/section.d.ts +52 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
- package/lib/implementations/base-store-visualizer.d.ts +61 -15
- package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
- package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
- package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
- package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -3
- package/lib/implementations/napari-js/napari-loading-state.d.ts +37 -0
- package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +68 -71
- package/lib/implementations/napari-js/napari-scene.d.ts +126 -0
- package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
- package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +91 -0
- package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
- package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
- package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
- package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
- package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +169 -883
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +148 -0
- package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
- package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
- package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
- package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
- package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
- package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
- package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
- package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
- package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
- package/lib/implementations/osd/display-pipeline.d.ts +38 -9
- package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
- package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
- package/lib/implementations/osd/osd-coords.d.ts +6 -4
- package/lib/implementations/osd/osd-export.d.ts +36 -0
- package/lib/implementations/osd/osd-lib.d.ts +7 -0
- package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
- package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
- package/lib/implementations/osd/osd-region-overlay-draw.d.ts +38 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +46 -51
- package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
- package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
- package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
- package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
- package/lib/implementations/osd/osd-viewport.d.ts +77 -0
- package/lib/implementations/osd/osd-zoom.d.ts +6 -0
- package/lib/implementations/osd/simple-source.d.ts +161 -0
- package/lib/implementations/osd/slice-cache.d.ts +12 -3
- package/lib/implementations/osd/tile-client.d.ts +11 -14
- package/lib/implementations/osd/tile-recolor.d.ts +141 -0
- package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
- package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
- package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
- package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
- package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
- package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
- package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
- package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
- package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
- package/lib/implementations/plotly/plotly.service.d.ts +136 -401
- package/lib/implementations/region-centroids.d.ts +14 -0
- package/lib/implementations/simple-slice-access.service.d.ts +7 -4
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
- package/lib/implementations/tile-server/index.d.ts +5 -0
- package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
- package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
- package/lib/implementations/tile-server/tile-protocol.d.ts +83 -0
- package/lib/implementations/tile-server/transport.d.ts +62 -0
- package/lib/intensity/intensity-profile.d.ts +66 -0
- package/lib/intensity/intensity-profile.service.d.ts +108 -0
- package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
- package/lib/models/bezier.d.ts +0 -5
- package/lib/models/class-preset.d.ts +25 -0
- package/lib/models/geometry.d.ts +14 -48
- package/lib/models/polygon-edit.d.ts +72 -0
- package/lib/models/polygon-factory.d.ts +45 -0
- package/lib/models/region-clone.d.ts +20 -0
- package/lib/models/region-geojson.d.ts +57 -0
- package/lib/models/region.d.ts +59 -4
- package/lib/models/shape.d.ts +8 -0
- package/lib/plot-mode/contribution-host.d.ts +125 -0
- package/lib/plot-mode/plot-type-menu.d.ts +60 -0
- package/lib/plot-mode/tool-params-model.d.ts +49 -0
- package/lib/plot.utilities.d.ts +19 -30
- package/lib/processing/processing-image.d.ts +5 -2
- package/lib/provide-visualization.d.ts +19 -2
- package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
- package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +86 -0
- package/lib/region-editor/file-stem.d.ts +7 -0
- package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
- package/lib/region-editor/mask-export.service.d.ts +54 -0
- package/lib/region-editor/mask-raster.d.ts +2 -8
- package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
- package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
- package/lib/region-editor/region-editor.component.d.ts +283 -200
- package/lib/region-editor/region-metrics.d.ts +34 -0
- package/lib/region-editor/region-persistence.service.d.ts +77 -0
- package/lib/region-editor/region-table/region-table.component.d.ts +89 -0
- package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
- package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
- package/lib/region-ops.service.d.ts +1 -7
- package/lib/region-overlay/region-geometry.d.ts +158 -0
- package/lib/region-overlay/region-hit-test.d.ts +38 -0
- package/lib/region-overlay/region-source-layer.d.ts +96 -0
- package/lib/region-overlay/region-style.d.ts +52 -0
- package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
- package/lib/region-source/http-region-source.d.ts +45 -0
- package/lib/region-source/region-source-ops.d.ts +89 -0
- package/lib/region-source/region-source-worker.d.ts +7 -0
- package/lib/region-source/region-source.d.ts +82 -0
- package/lib/region-source/region-tiles.d.ts +289 -0
- package/lib/region-source/worker-region-source.d.ts +65 -0
- package/lib/render-orchestrator.d.ts +6 -2
- package/lib/render-session.d.ts +75 -0
- package/lib/routing-visualizer.service.d.ts +248 -59
- package/lib/section-pane/section-pane.component.d.ts +47 -0
- package/lib/spatial/density-raster.d.ts +6 -0
- package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
- package/lib/spatial/embedding-compute.d.ts +21 -2
- package/lib/spatial/glyphs.d.ts +16 -0
- package/lib/spatial/lod.d.ts +94 -0
- package/lib/spatial/spatial-controls.facade.d.ts +64 -0
- package/lib/spatial/spatial-density.d.ts +15 -5
- package/lib/spatial/spatial-encoding.d.ts +11 -44
- package/lib/spatial/spatial-expression.d.ts +40 -22
- package/lib/spatial/spatial-framing.d.ts +1 -0
- package/lib/spatial/spatial-heatmap.d.ts +2 -0
- package/lib/spatial/spatial-hover.d.ts +4 -16
- package/lib/spatial/spatial-panel-model.d.ts +135 -0
- package/lib/spatial/spatial-selection.d.ts +21 -26
- package/lib/spatial/spatial-tile-merge.d.ts +41 -0
- package/lib/spatial/spatial-tiles.d.ts +9 -256
- package/lib/spatial/stats.d.ts +38 -0
- package/lib/spatial/transcript-grouping.d.ts +119 -0
- package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
- package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
- package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
- package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
- package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
- package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
- package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
- package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
- package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
- package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
- package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
- package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
- package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
- package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
- package/lib/store/class-color.util.d.ts +39 -2
- package/lib/store/class-signatures.d.ts +11 -0
- package/lib/store/region-history.d.ts +66 -0
- package/lib/store/region-scope-cache.d.ts +65 -0
- package/lib/store/region-selection.d.ts +36 -0
- package/lib/store/region-source-scope.d.ts +68 -0
- package/lib/store/region-store.service.d.ts +312 -116
- package/lib/store/visualizer-store.service.d.ts +32 -33
- package/lib/toast-outlets.d.ts +4 -3
- package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
- package/lib/toolbar/canvas-tools.d.ts +20 -0
- package/lib/toolbar/crop/slide-crop.d.ts +10 -4
- package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
- package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
- package/lib/toolbar/region-tools/region-tools.component.d.ts +62 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
- package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
- package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
- package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
- package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
- package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
- package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
- package/lib/toolbar/stack-controls/stack-controls.component.d.ts +51 -0
- package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
- package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
- package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
- package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
- package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
- package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
- package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
- package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
- package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
- package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
- package/lib/toolbar/toolbar.component.d.ts +55 -84
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
- package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
- package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
- package/lib/toolbar/wand/wand.service.d.ts +22 -116
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
- package/lib/util/mark-for-check.d.ts +11 -0
- package/lib/util/supersede.d.ts +53 -0
- package/lib/visualization.module.d.ts +18 -39
- package/lib/visualizer/floating-drag.directive.d.ts +30 -0
- package/lib/visualizer/region-actions.d.ts +54 -0
- package/lib/visualizer/region-load.d.ts +46 -0
- package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
- package/lib/visualizer/tool-modes.d.ts +49 -0
- package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
- package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
- package/lib/visualizer/volume-sections.d.ts +64 -0
- package/lib/visualizer.component.d.ts +232 -447
- package/lib/workers/spatial-math-ops.d.ts +65 -0
- package/lib/workers/spatial-math-worker.d.ts +7 -0
- package/lib/workers/spatial-math.d.ts +74 -0
- package/package.json +12 -3
- package/src/lib/assets/slice.svg +23 -0
- package/src/lib/styles/_viz-icons-rules.scss +73 -0
- package/src/lib/styles/viz-icons.scss +14 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
- package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
- package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
- package/src/lib/assets/cell-detection.svg +0 -37
- package/src/lib/assets/click.svg +0 -1
- package/src/lib/assets/colormap-luts.json +0 -1
- package/src/lib/assets/edit-selection-white.svg +0 -47
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
- package/src/lib/assets/picture-segmentation.svg +0 -43
- package/src/lib/assets/test/download-379.svg +0 -1
- package/src/lib/assets/test/download-98.svg +0 -1
- package/src/lib/assets/test/json-1.svg +0 -1
- package/src/lib/assets/test/load-53.svg +0 -1
- package/src/lib/assets/test/mask-44.svg +0 -1
- package/src/lib/assets/test/mask-download-44.svg +0 -15
- package/src/lib/assets/test/mask-save-44.svg +0 -11
- package/src/lib/assets/test/overlay-1.svg +0 -1
- package/src/lib/assets/test/overlay-4.svg +0 -1
- package/src/lib/assets/test/region-26.svg +0 -1
- package/src/lib/assets/test/save-56.svg +0 -1
- package/src/lib/assets/test/upload-43.svg +0 -1
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
import { MultiChannelImageView, decodeImageRGBA, histogramScalar, tintColormap } from 'napari-js';
|
|
2
|
+
import { NavigatorOverlay, ScaleBarOverlay } from 'napari-js/overlays';
|
|
3
|
+
import { rgbNeedsRecolor } from '../osd/display-pipeline';
|
|
4
|
+
import { regionCentroids } from '../region-centroids';
|
|
5
|
+
import { isServerlessMultichannel, splitRgbBands, tintFor, tintedComposite, toIHistogram, toNapariGamma, typedPlane, } from './napari-helpers';
|
|
6
|
+
/**
|
|
7
|
+
* Composite additive channel layers onto black, as OSD and Plotly merge them: the bottom-most
|
|
8
|
+
* SHOWN layer replaces what is under it, the others add onto it. All-additive layers added onto
|
|
9
|
+
* the viewer's dark-grey background instead, lifting every black pixel to that grey.
|
|
10
|
+
*/
|
|
11
|
+
function mergeOntoBlack(layers) {
|
|
12
|
+
const base = layers.find((layer) => layer.visible);
|
|
13
|
+
for (const layer of layers)
|
|
14
|
+
layer.blending = layer === base ? 'translucent' : 'additive';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The 2D image (review Appendix B, cluster E): pyramidal `TiledSource`s against the `/tile`
|
|
18
|
+
* endpoint when `/tiles/info` describes the image, else a single stitched level (`tiled:false`
|
|
19
|
+
* stacks fetch each slice's own URL, a serverless multichannel stack each channel's own plane);
|
|
20
|
+
* multichannel additive tints, grayscale colormap or RGB (recoloured per band, see
|
|
21
|
+
* {@link syncRgbBands}); the coarse histogram samples of the tiled path, the scale bar, the
|
|
22
|
+
* overview navigator and the 2D interaction stack (region overlay + pixel tools). The
|
|
23
|
+
* region-centroid scatter and the spatial 2D scene are built over it.
|
|
24
|
+
*/
|
|
25
|
+
export class Image2dScene {
|
|
26
|
+
constructor(ctx, opts = {}) {
|
|
27
|
+
this.ctx = ctx;
|
|
28
|
+
this.opts = opts;
|
|
29
|
+
/** How the image is composited (drives the histogram and the display-state updates). */
|
|
30
|
+
this.imageMode = 'rgb';
|
|
31
|
+
/** True when the image is rendered via pyramidal TiledSources (descriptor available). */
|
|
32
|
+
this.tiled = false;
|
|
33
|
+
/** napari-js high-level view owning the per-channel layer set for {@link imageMode}. */
|
|
34
|
+
this.channelView = null;
|
|
35
|
+
/** Latest wins for a stitched slice: a slow older slice can't clobber a newer one. */
|
|
36
|
+
this.sliceReq = 0;
|
|
37
|
+
/** RGB: the R, G and B bands as layer sources (typed planes, or band `TiledSource`s that share
|
|
38
|
+
* one request per tile) and the stitched level's scale — what {@link syncRgbBands} draws. */
|
|
39
|
+
this.rgbBands = null;
|
|
40
|
+
/** RGB: the three additive band layers while the channel states recolour the image; null while
|
|
41
|
+
* the RGB layer draws it as it is. */
|
|
42
|
+
this.bandLayers = null;
|
|
43
|
+
/** Coarse per-channel luminance sample (keyed by channel index) for the histogram in tiled mode,
|
|
44
|
+
* where the layers have no full in-memory pixels — and an RGB image's raw bands in either mode.
|
|
45
|
+
* Refreshed on mount + slice change. */
|
|
46
|
+
this.histSamples = new Map();
|
|
47
|
+
/** Latest-wins token for {@link refreshHistogramSamples}. */
|
|
48
|
+
this.histGen = 0;
|
|
49
|
+
/** Physical scale bar overlay (null when the image has no µm/pixel). */
|
|
50
|
+
this.scaleBar = null;
|
|
51
|
+
/** Overview minimap (bottom-right), as OSD's navigator. */
|
|
52
|
+
this.navigator = null;
|
|
53
|
+
/** Bumped per thumbnail request, so a slow one cannot overwrite a newer slice's. */
|
|
54
|
+
this.navigatorToken = 0;
|
|
55
|
+
/** The current slice's per-channel thumbnail bitmaps (multichannel only), kept so a tint or
|
|
56
|
+
* visibility change recolours the thumbnail without re-fetching it. */
|
|
57
|
+
this.navigatorChannels = null;
|
|
58
|
+
/** The tints/visibility the thumbnail was last composited with — see {@link recolorNavigator}. */
|
|
59
|
+
this.navigatorTintKey = '';
|
|
60
|
+
this.displaySub = null;
|
|
61
|
+
}
|
|
62
|
+
get hasImage() {
|
|
63
|
+
return this.opts.image !== false;
|
|
64
|
+
}
|
|
65
|
+
async mount() {
|
|
66
|
+
const { ctx } = this;
|
|
67
|
+
const z = ctx.z();
|
|
68
|
+
if (this.hasImage)
|
|
69
|
+
await this.render(z);
|
|
70
|
+
// Reset into a newer scene while the image loaded: this scene is already disposed, and the
|
|
71
|
+
// tool bridge is the next scene's — install nothing more.
|
|
72
|
+
if (ctx.signal.aborted)
|
|
73
|
+
return;
|
|
74
|
+
if (this.opts.fit ? this.opts.fit() : this.hasImage)
|
|
75
|
+
ctx.fitCameraSoon();
|
|
76
|
+
this.followDisplayState();
|
|
77
|
+
// The scale bar and navigator describe an image; with none loaded, whatever they would
|
|
78
|
+
// read is left over from the last one.
|
|
79
|
+
if (this.hasImage) {
|
|
80
|
+
this.installScaleBar();
|
|
81
|
+
this.installNavigator(z);
|
|
82
|
+
}
|
|
83
|
+
ctx.tools.install2dInteraction(ctx.viewer, ctx.host);
|
|
84
|
+
}
|
|
85
|
+
setZ(z) {
|
|
86
|
+
const { ctx } = this;
|
|
87
|
+
if (this.navigator)
|
|
88
|
+
void this.refreshNavigatorImage(z);
|
|
89
|
+
// Tiled: just move the dims plane — the tiled visual fetches the new slice's tiles (cached per
|
|
90
|
+
// z), no layer rebuild. Refresh the coarse histogram sample for the new slice.
|
|
91
|
+
if (this.tiled) {
|
|
92
|
+
ctx.viewer.dims.z = z;
|
|
93
|
+
const desc = ctx.tiles.currentDescriptor(ctx.info());
|
|
94
|
+
if (desc)
|
|
95
|
+
void this.refreshHistogramSamples(z, desc);
|
|
96
|
+
this.opts.onSlice?.(false);
|
|
97
|
+
ctx.tools.scheduleReadback();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Stitch fallback: re-render the slice (re-fetches per-channel / composite). The token lets
|
|
101
|
+
// render drop a superseded scrub so a slow older slice can't clobber a newer one.
|
|
102
|
+
const req = ++this.sliceReq;
|
|
103
|
+
void this.render(z, req)
|
|
104
|
+
.then(() => {
|
|
105
|
+
if (req !== this.sliceReq || ctx.signal.aborted)
|
|
106
|
+
return;
|
|
107
|
+
// AFTER the image, never before: the render clears the layer list, so whatever sits over
|
|
108
|
+
// the image is wiped by the very image meant to sit under it.
|
|
109
|
+
this.opts.onSlice?.(true);
|
|
110
|
+
ctx.tools.scheduleReadback();
|
|
111
|
+
})
|
|
112
|
+
.catch((err) => console.error('[napari-js] setZIndex slice failed:', err));
|
|
113
|
+
}
|
|
114
|
+
histogram(channel, bins) {
|
|
115
|
+
// Tiled mode has no full in-memory pixels → the coarse per-channel sample. RGB: its raw band
|
|
116
|
+
// (either mode) — never the displayed pixels, which the channel states have recoloured.
|
|
117
|
+
if (this.tiled || this.imageMode === 'rgb') {
|
|
118
|
+
const sample = this.histSamples.get(this.imageMode === 'grayscale' ? 0 : channel);
|
|
119
|
+
return sample ? toIHistogram(histogramScalar(sample, bins, 0, 255)) : null;
|
|
120
|
+
}
|
|
121
|
+
// Grayscale/multichannel (stitch): native per-channel histogram straight from the in-memory
|
|
122
|
+
// scalar layer (no GPU readback).
|
|
123
|
+
const layer = this.channelView?.layers[this.imageMode === 'grayscale' ? 0 : channel];
|
|
124
|
+
const h = layer ? this.ctx.viewer.layerHistogram(layer, bins) : null;
|
|
125
|
+
return h ? toIHistogram(h) : null;
|
|
126
|
+
}
|
|
127
|
+
setImageSmoothing(enabled) {
|
|
128
|
+
// Apply live to the rendered image layers; baked into the next render too.
|
|
129
|
+
const interpolation = enabled ? 'linear' : 'nearest';
|
|
130
|
+
this.channelView?.setInterpolation(interpolation);
|
|
131
|
+
this.bandLayers?.forEach((layer) => (layer.interpolation = interpolation));
|
|
132
|
+
}
|
|
133
|
+
setNavigatorVisible(visible) {
|
|
134
|
+
this.navigator?.setVisible(visible);
|
|
135
|
+
}
|
|
136
|
+
/** Show the navigator only for a dataset that brings pixels of its own (and when the user
|
|
137
|
+
* wants it): with no image of its own there is nothing for an overview to show. */
|
|
138
|
+
showNavigatorFor(datasetHasPixels) {
|
|
139
|
+
this.navigator?.setVisible(datasetHasPixels && this.ctx.settings.navigatorVisible);
|
|
140
|
+
}
|
|
141
|
+
dispose() {
|
|
142
|
+
this.displaySub?.unsubscribe();
|
|
143
|
+
this.displaySub = null;
|
|
144
|
+
this.scaleBar?.dispose();
|
|
145
|
+
this.scaleBar = null;
|
|
146
|
+
this.navigator?.dispose();
|
|
147
|
+
this.navigator = null;
|
|
148
|
+
this.setNavigatorChannels(null);
|
|
149
|
+
this.histGen++;
|
|
150
|
+
this.histSamples.clear();
|
|
151
|
+
this.channelView = null;
|
|
152
|
+
this.rgbBands = null;
|
|
153
|
+
this.bandLayers = null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Render slice `z`. With a server pyramid descriptor each layer is a pyramidal
|
|
157
|
+
* {@link TiledSource}, so the view refines to higher resolution on zoom (like OSD) and sits
|
|
158
|
+
* naturally in full-resolution coordinates; without one, the single-level stitch. Three display
|
|
159
|
+
* modes either way: multichannel additive tint, grayscale colormap, RGB.
|
|
160
|
+
*/
|
|
161
|
+
async render(z, token) {
|
|
162
|
+
const { ctx } = this;
|
|
163
|
+
const scene = ctx.signal;
|
|
164
|
+
const desc = await ctx.tiles.ensureDescriptor(ctx.info());
|
|
165
|
+
// Reset into a newer scene while the descriptor was in flight: this render is superseded.
|
|
166
|
+
if (scene.aborted)
|
|
167
|
+
return;
|
|
168
|
+
if (desc && desc.levels?.length) {
|
|
169
|
+
if (token != null && token !== this.sliceReq)
|
|
170
|
+
return;
|
|
171
|
+
await this.renderTiled(z, desc, scene);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
return this.renderStitched(z, token);
|
|
175
|
+
}
|
|
176
|
+
/** Single-level stitch fallback (no descriptor): the pre-tiling path. */
|
|
177
|
+
async renderStitched(z, token) {
|
|
178
|
+
const { ctx } = this;
|
|
179
|
+
const info = ctx.info();
|
|
180
|
+
const desc = await ctx.tiles.ensureDescriptor(info);
|
|
181
|
+
const states = ctx.store.currentChannelStates();
|
|
182
|
+
// A serverless multichannel stack has no descriptor: its channels are its own plane URLs
|
|
183
|
+
// (`channelUrls[z][c]`, which fetchChannelData reads), and `urls[z]` only a composite.
|
|
184
|
+
const serverlessMc = isServerlessMultichannel(ctx.tiles.isSimple(info), info);
|
|
185
|
+
const channelCount = desc?.channels ?? (serverlessMc ? (info?.imageMeta?.[0]?.channelCount ?? 1) : states.length || 1);
|
|
186
|
+
const multichannel = (!!desc?.multichannel || serverlessMc) && channelCount > 1;
|
|
187
|
+
// 1) Fetch all pixel data BEFORE touching the viewer, so a superseded scrub can bail without
|
|
188
|
+
// having torn down the visible layers (avoids flicker / out-of-order layer state).
|
|
189
|
+
let mode;
|
|
190
|
+
let planes = [];
|
|
191
|
+
let bitmap = null;
|
|
192
|
+
if (multichannel) {
|
|
193
|
+
mode = 'multichannel';
|
|
194
|
+
planes = await Promise.all(Array.from({ length: channelCount }, (_, c) => ctx.tiles.fetchChannelData(info, z, c)));
|
|
195
|
+
}
|
|
196
|
+
else if (channelCount === 1) {
|
|
197
|
+
mode = 'grayscale';
|
|
198
|
+
// Composite fetch (no channel) → all overview levels usable, so a large grayscale image
|
|
199
|
+
// selects a fitting downscaled level instead of the full-res real level (texture limit).
|
|
200
|
+
planes = [await ctx.tiles.fetchChannelData(info, z)];
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
mode = 'rgb';
|
|
204
|
+
// The bitmap draws the image as it is; its raw bands, the per-band layers and histograms.
|
|
205
|
+
bitmap = await ctx.tiles.fetchImage(info, z);
|
|
206
|
+
planes = splitRgbBands(decodeImageRGBA(bitmap));
|
|
207
|
+
}
|
|
208
|
+
// 2) Commit — unless a newer scrub superseded us or the scene was torn down.
|
|
209
|
+
if ((token != null && token !== this.sliceReq) || ctx.signal.aborted) {
|
|
210
|
+
bitmap?.close?.();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// The displayed texture may be a downscaled pyramid level; scale the layer into FULL-RESOLUTION
|
|
214
|
+
// world coordinates (level-0 pixels) so the camera, readback and — critically — pre-saved
|
|
215
|
+
// regions (stored in full-res coords, e.g. ndpi) all line up regardless of which level is shown.
|
|
216
|
+
// This mirrors OSD, whose coordinate system is always level 0.
|
|
217
|
+
const texW = planes[0]?.width ?? 0;
|
|
218
|
+
const texH = planes[0]?.height ?? 0;
|
|
219
|
+
const fullW = desc?.width || texW || 1;
|
|
220
|
+
const fullH = desc?.height || texH || 1;
|
|
221
|
+
const scale = [texW ? fullW / texW : 1, texH ? fullH / texH : 1];
|
|
222
|
+
this.imageMode = mode;
|
|
223
|
+
const interpolation = ctx.settings.imageSmoothing ? 'linear' : 'nearest';
|
|
224
|
+
this.channelView = new MultiChannelImageView(ctx.viewer);
|
|
225
|
+
this.bandLayers = null; // the render clears the layer list, band layers included
|
|
226
|
+
if (mode === 'multichannel') {
|
|
227
|
+
const views = planes.map((d, c) => this.tintedChannelView(c, states, desc, typedPlane(d), scale));
|
|
228
|
+
this.channelView.render('multichannel', views, { interpolation });
|
|
229
|
+
mergeOntoBlack(this.channelView.layers);
|
|
230
|
+
}
|
|
231
|
+
else if (mode === 'grayscale') {
|
|
232
|
+
const view = this.grayscaleChannelView(states[0], typedPlane(planes[0]), scale);
|
|
233
|
+
this.channelView.render('grayscale', [view], { interpolation });
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
this.channelView.render('rgb', [{ source: bitmap, scale }], { interpolation });
|
|
237
|
+
this.rgbBands = { sources: planes.map(typedPlane), scale };
|
|
238
|
+
this.histSamples.clear();
|
|
239
|
+
planes.forEach((band, c) => this.histSamples.set(c, band.data));
|
|
240
|
+
this.syncRgbBands(states);
|
|
241
|
+
}
|
|
242
|
+
ctx.setImageSize(fullW, fullH);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Render with pyramidal {@link TiledSource}s — the view refines to higher resolution as you
|
|
246
|
+
* zoom in (the visual fetches the level whose texels ≈ screen pixels) and sits in full-res
|
|
247
|
+
* coordinates so regions align. Same three modes as the stitch path. Per-channel layers use the
|
|
248
|
+
* REAL pyramid levels (per-channel tiles only exist there); the composite uses all levels.
|
|
249
|
+
*/
|
|
250
|
+
async renderTiled(z, desc, scene) {
|
|
251
|
+
const { ctx } = this;
|
|
252
|
+
const states = ctx.store.currentChannelStates();
|
|
253
|
+
const channelCount = desc.channels ?? (states.length || 1);
|
|
254
|
+
const multichannel = !!desc.multichannel && channelCount > 1;
|
|
255
|
+
const interpolation = ctx.settings.imageSmoothing ? 'linear' : 'nearest';
|
|
256
|
+
this.tiled = true;
|
|
257
|
+
this.channelView = new MultiChannelImageView(ctx.viewer);
|
|
258
|
+
if (multichannel) {
|
|
259
|
+
this.imageMode = 'multichannel';
|
|
260
|
+
const views = Array.from({ length: channelCount }, (_, c) => this.tintedChannelView(c, states, desc, this.tiledSource(desc, c, 1, scene)));
|
|
261
|
+
this.channelView.render('multichannel', views, { interpolation });
|
|
262
|
+
mergeOntoBlack(this.channelView.layers);
|
|
263
|
+
}
|
|
264
|
+
else if (channelCount === 1) {
|
|
265
|
+
this.imageMode = 'grayscale';
|
|
266
|
+
const view = this.grayscaleChannelView(states[0], this.tiledSource(desc, undefined, 1, scene));
|
|
267
|
+
this.channelView.render('grayscale', [view], { interpolation });
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.imageMode = 'rgb';
|
|
271
|
+
this.channelView.render('rgb', [{ source: this.tiledSource(desc, undefined, 4, scene) }], {
|
|
272
|
+
interpolation,
|
|
273
|
+
});
|
|
274
|
+
this.rgbBands = {
|
|
275
|
+
sources: ctx.tiles.rgbBandSources(desc, scene, () => this.ctx.badge.begin('Image')),
|
|
276
|
+
};
|
|
277
|
+
this.syncRgbBands(states);
|
|
278
|
+
}
|
|
279
|
+
ctx.setImageSize(desc.width, desc.height);
|
|
280
|
+
// Await on the initial render so getHistogram/autoContrast have data immediately; slice changes
|
|
281
|
+
// refresh fire-and-forget (the histogram pane retries).
|
|
282
|
+
await this.refreshHistogramSamples(z, desc);
|
|
283
|
+
}
|
|
284
|
+
/** A pyramidal TiledSource whose tiles count on the loading badge while `scene` (the render that
|
|
285
|
+
* asked for it, taken before its awaits) is current. */
|
|
286
|
+
tiledSource(desc, channel, channels, scene) {
|
|
287
|
+
return this.ctx.tiles.tiledSource(desc, channel, channels, scene, () => this.ctx.badge.begin('Image'));
|
|
288
|
+
}
|
|
289
|
+
/** Channel `c`'s layer in the additive multichannel composite: tinted by its display colour
|
|
290
|
+
* (store, else descriptor, else the Fiji palette), with its window, gamma and visibility. */
|
|
291
|
+
tintedChannelView(c, states, desc, source, scale) {
|
|
292
|
+
const st = states.find((s) => s.index === c);
|
|
293
|
+
return {
|
|
294
|
+
source,
|
|
295
|
+
tint: st?.color ?? desc?.channelInfo?.[c]?.color ?? tintFor(c),
|
|
296
|
+
name: st?.name ?? `ch${c}`,
|
|
297
|
+
contrastLimits: [st?.min ?? 0, st?.max ?? 255],
|
|
298
|
+
gamma: toNapariGamma(st?.gamma), // ImageJ γ → napari-js γ
|
|
299
|
+
visible: st?.visible ?? true,
|
|
300
|
+
invert: this.ctx.display.invert,
|
|
301
|
+
...(scale ? { scale } : {}),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/** The single grayscale layer: the selected colormap, with the channel's window and gamma. */
|
|
305
|
+
grayscaleChannelView(st, source, scale) {
|
|
306
|
+
return {
|
|
307
|
+
source,
|
|
308
|
+
colormap: this.ctx.display.grayscaleColormap(),
|
|
309
|
+
contrastLimits: [st?.min ?? 0, st?.max ?? 255],
|
|
310
|
+
gamma: toNapariGamma(st?.gamma), // ImageJ γ → napari-js γ
|
|
311
|
+
invert: this.ctx.display.invert,
|
|
312
|
+
...(scale ? { scale } : {}),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/** (Re)fetch a coarse per-channel luminance sample for the histogram (tiled mode has no full
|
|
316
|
+
* in-memory pixels). One cheap overview tile per channel, fetched together; cached by channel
|
|
317
|
+
* index. Latest wins: a scrub fires one refresh per slice, and an older slice's samples that
|
|
318
|
+
* land after a newer one's are dropped rather than shown as the current distribution. */
|
|
319
|
+
async refreshHistogramSamples(z, desc) {
|
|
320
|
+
const gen = ++this.histGen;
|
|
321
|
+
this.histSamples.clear();
|
|
322
|
+
const info = this.ctx.info();
|
|
323
|
+
if (this.imageMode === 'rgb') {
|
|
324
|
+
// One coarse composite tile, split into its raw R, G and B bands.
|
|
325
|
+
const bands = await this.ctx.tiles.readRgbBands(info, z, 1).catch(() => null);
|
|
326
|
+
if (gen !== this.histGen || !bands)
|
|
327
|
+
return;
|
|
328
|
+
bands.forEach((band, c) => this.histSamples.set(c, band.data));
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const multichannel = this.imageMode === 'multichannel';
|
|
332
|
+
const channelCount = multichannel ? (desc.channels ?? 1) : 1;
|
|
333
|
+
const samples = await Promise.all(Array.from({ length: channelCount }, (_, c) =>
|
|
334
|
+
// budget 1 → coarsest single tile; a failed channel leaves its sample unset.
|
|
335
|
+
this.ctx.tiles.fetchChannelData(info, z, multichannel ? c : undefined, 1).then((d) => d.data, () => null)));
|
|
336
|
+
if (gen !== this.histGen)
|
|
337
|
+
return;
|
|
338
|
+
samples.forEach((data, c) => {
|
|
339
|
+
if (data)
|
|
340
|
+
this.histSamples.set(c, data);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
/** Channel states + grayscale colormap → live-apply to the rendered layers (no re-fetch; only z
|
|
344
|
+
* changes re-fetch), and recolour the navigator thumbnail. */
|
|
345
|
+
followDisplayState() {
|
|
346
|
+
this.displaySub = this.ctx.display.watch((channels) => {
|
|
347
|
+
this.applyDisplayState(channels);
|
|
348
|
+
this.recolorNavigator();
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/** Apply the current channel states / colormap to the live layers (no re-fetch), delegating the
|
|
352
|
+
* per-channel layer mutations to the {@link MultiChannelImageView}. */
|
|
353
|
+
applyDisplayState(channels) {
|
|
354
|
+
const view = this.channelView;
|
|
355
|
+
const { display } = this.ctx;
|
|
356
|
+
if (!view)
|
|
357
|
+
return;
|
|
358
|
+
if (this.imageMode === 'rgb') {
|
|
359
|
+
this.syncRgbBands(channels);
|
|
360
|
+
}
|
|
361
|
+
else if (this.imageMode === 'multichannel') {
|
|
362
|
+
view.layers.forEach((_, c) => {
|
|
363
|
+
const st = channels.find((s) => s.index === c);
|
|
364
|
+
if (!st)
|
|
365
|
+
return;
|
|
366
|
+
view.updateChannel(c, {
|
|
367
|
+
tint: st.color,
|
|
368
|
+
contrastLimits: [st.min, st.max],
|
|
369
|
+
gamma: toNapariGamma(st.gamma), // ImageJ γ → napari-js γ
|
|
370
|
+
visible: st.visible,
|
|
371
|
+
invert: display.invert,
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
mergeOntoBlack(view.layers);
|
|
375
|
+
}
|
|
376
|
+
else if (this.imageMode === 'grayscale') {
|
|
377
|
+
const st = channels[0];
|
|
378
|
+
view.updateChannel(0, {
|
|
379
|
+
colormap: display.grayscaleColormap(),
|
|
380
|
+
invert: display.invert,
|
|
381
|
+
...(st ? { contrastLimits: [st.min, st.max], gamma: toNapariGamma(st.gamma) } : {}),
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* RGB: draw the image as it is while its channel states leave it so (default R/G/B tints, full
|
|
387
|
+
* window, γ 1, all shown, no invert: {@link rgbNeedsRecolor}) — the RGB layer, unchanged, with
|
|
388
|
+
* the coarse underlay a tiled one keeps while it pans. Otherwise draw its R, G and B bands as
|
|
389
|
+
* three additive layers, each with its channel's window, invert, gamma, tint and visibility —
|
|
390
|
+
* what OSD's RGB recolour computes per pixel (the merge order of `osd/display-pipeline`). The
|
|
391
|
+
* band layers sit just above the hidden RGB layer, so whatever is drawn over the image stays
|
|
392
|
+
* over it. A host with no R/G/B channel model (fewer than three states) gets only the invert.
|
|
393
|
+
*/
|
|
394
|
+
syncRgbBands(channels) {
|
|
395
|
+
const { viewer, display } = this.ctx;
|
|
396
|
+
const rgb = this.channelView?.layers[0];
|
|
397
|
+
const bands = this.rgbBands;
|
|
398
|
+
if (!rgb || !bands)
|
|
399
|
+
return;
|
|
400
|
+
const states = channels.length >= 3 ? channels : [];
|
|
401
|
+
if (!rgbNeedsRecolor(states, display.invert)) {
|
|
402
|
+
this.bandLayers?.forEach((layer) => viewer.layers.remove(layer));
|
|
403
|
+
this.bandLayers = null;
|
|
404
|
+
rgb.visible = true;
|
|
405
|
+
viewer.requestRender();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (!this.bandLayers) {
|
|
409
|
+
const at = viewer.layers.items.indexOf(rgb);
|
|
410
|
+
this.bandLayers = bands.sources.map((source, c) => {
|
|
411
|
+
const layer = viewer.addImage(source, {
|
|
412
|
+
name: `rgb${c}`,
|
|
413
|
+
blending: 'additive',
|
|
414
|
+
interpolation: rgb.interpolation,
|
|
415
|
+
...(bands.scale ? { scale: bands.scale } : {}),
|
|
416
|
+
});
|
|
417
|
+
viewer.layers.move(layer, at + 1 + c);
|
|
418
|
+
return layer;
|
|
419
|
+
});
|
|
420
|
+
rgb.visible = false;
|
|
421
|
+
}
|
|
422
|
+
this.bandLayers.forEach((layer, c) => {
|
|
423
|
+
const st = states.find((s) => s.index === c);
|
|
424
|
+
layer.colormap = tintColormap(st?.color ?? tintFor(c));
|
|
425
|
+
layer.contrastLimits = [st?.min ?? 0, st?.max ?? 255];
|
|
426
|
+
layer.gamma = toNapariGamma(st?.gamma); // ImageJ γ → napari-js γ
|
|
427
|
+
layer.visible = st?.visible ?? true;
|
|
428
|
+
layer.invert = display.invert;
|
|
429
|
+
});
|
|
430
|
+
mergeOntoBlack(this.bandLayers);
|
|
431
|
+
viewer.requestRender();
|
|
432
|
+
}
|
|
433
|
+
/** (Re)install the physical scale bar (napari-js's `ScaleBarOverlay` on the 2D camera's zoom),
|
|
434
|
+
* sized from the image's µm/pixel (`/tiles/info` mppX, falling back to the image metadata).
|
|
435
|
+
* No-op without a physical size. */
|
|
436
|
+
installScaleBar() {
|
|
437
|
+
const { ctx } = this;
|
|
438
|
+
this.scaleBar?.dispose();
|
|
439
|
+
this.scaleBar = null;
|
|
440
|
+
const mppX = ctx.tiles.mppX(ctx.info());
|
|
441
|
+
if (mppX > 0)
|
|
442
|
+
this.scaleBar = new ScaleBarOverlay(ctx.host, ctx.viewer, { unitPerWorld: mppX, mode: '2d' });
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* The overview navigator (napari-js's `NavigatorOverlay`): a coarse thumbnail of the whole
|
|
446
|
+
* image with the viewport on it; click or drag to pan at the current zoom (as OSD).
|
|
447
|
+
*/
|
|
448
|
+
installNavigator(z) {
|
|
449
|
+
const { ctx } = this;
|
|
450
|
+
this.navigator?.dispose();
|
|
451
|
+
this.navigator = null;
|
|
452
|
+
const { width, height } = ctx.imageSize();
|
|
453
|
+
if (!width || !height)
|
|
454
|
+
return;
|
|
455
|
+
this.navigator = new NavigatorOverlay(ctx.host, ctx.viewer, {
|
|
456
|
+
worldWidth: width,
|
|
457
|
+
worldHeight: height,
|
|
458
|
+
onEnter: () => this.opts.onNavigatorInteract?.(),
|
|
459
|
+
visible: ctx.settings.navigatorVisible,
|
|
460
|
+
});
|
|
461
|
+
void this.refreshNavigatorImage(z);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Draw the navigator's thumbnail from the coarsest pyramid level. A multichannel image
|
|
465
|
+
* is composited from its channels in their display colours (see {@link recolorNavigator}),
|
|
466
|
+
* so the overview looks like the view rather than like channel 0 in grey.
|
|
467
|
+
*/
|
|
468
|
+
async refreshNavigatorImage(z) {
|
|
469
|
+
const nav = this.navigator;
|
|
470
|
+
if (!nav)
|
|
471
|
+
return;
|
|
472
|
+
const token = ++this.navigatorToken;
|
|
473
|
+
const { tiles } = this.ctx;
|
|
474
|
+
const info = this.ctx.info();
|
|
475
|
+
try {
|
|
476
|
+
const desc = await tiles.ensureDescriptor(info);
|
|
477
|
+
// Superseded (a newer slice, or the scene was torn down): fetch nothing.
|
|
478
|
+
if (token !== this.navigatorToken || this.navigator !== nav)
|
|
479
|
+
return;
|
|
480
|
+
// A serverless multichannel stack's thumbnails are its own channel planes.
|
|
481
|
+
const count = desc?.multichannel
|
|
482
|
+
? (desc.channelInfo?.length ?? 0)
|
|
483
|
+
: isServerlessMultichannel(tiles.isSimple(info), info)
|
|
484
|
+
? (info?.imageMeta?.[0]?.channelCount ?? 0)
|
|
485
|
+
: 0;
|
|
486
|
+
if (count > 1) {
|
|
487
|
+
const bitmaps = await Promise.all(Array.from({ length: count }, (_c, c) => tiles.overviewImage(info, z, c)));
|
|
488
|
+
if (token !== this.navigatorToken || this.navigator !== nav)
|
|
489
|
+
return;
|
|
490
|
+
this.setNavigatorChannels(bitmaps);
|
|
491
|
+
this.recolorNavigator();
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
const image = await tiles.overviewImage(info, z);
|
|
495
|
+
if (token !== this.navigatorToken || this.navigator !== nav)
|
|
496
|
+
return;
|
|
497
|
+
this.setNavigatorChannels(null);
|
|
498
|
+
nav.setImage(image);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
console.warn('[napari-js] navigator thumbnail unavailable', err);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** Replace the per-channel thumbnail bitmaps (closing the previous ones). */
|
|
506
|
+
setNavigatorChannels(bitmaps) {
|
|
507
|
+
for (const bmp of this.navigatorChannels ?? [])
|
|
508
|
+
if ('close' in bmp)
|
|
509
|
+
bmp.close?.();
|
|
510
|
+
this.navigatorChannels = bitmaps;
|
|
511
|
+
this.navigatorTintKey = '';
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Composite the multichannel thumbnail in the channels' CURRENT display tints, skipping hidden
|
|
515
|
+
* channels — the store's channel states, as the 2D layers use, not the server's defaults.
|
|
516
|
+
* Re-run on every display-state change; it only redraws (never re-fetches), and only when a
|
|
517
|
+
* tint or a visibility actually changed, so a window/gamma drag costs a string compare.
|
|
518
|
+
*/
|
|
519
|
+
recolorNavigator() {
|
|
520
|
+
const nav = this.navigator;
|
|
521
|
+
const bitmaps = this.navigatorChannels;
|
|
522
|
+
if (!nav || !bitmaps)
|
|
523
|
+
return;
|
|
524
|
+
const info = this.ctx.tiles.currentDescriptor(this.ctx.info())?.channelInfo;
|
|
525
|
+
const states = this.ctx.store.currentChannelStates();
|
|
526
|
+
const shown = bitmaps
|
|
527
|
+
.map((bmp, c) => {
|
|
528
|
+
const st = states.find((s) => s.index === c);
|
|
529
|
+
return { bmp, visible: st?.visible ?? true, color: st?.color ?? info?.[c]?.color ?? tintFor(c) };
|
|
530
|
+
})
|
|
531
|
+
.filter((ch) => ch.visible);
|
|
532
|
+
const key = shown.map((ch) => `${bitmaps.indexOf(ch.bmp)}:${ch.color}`).join('|');
|
|
533
|
+
if (key === this.navigatorTintKey)
|
|
534
|
+
return;
|
|
535
|
+
this.navigatorTintKey = key;
|
|
536
|
+
nav.setImage(tintedComposite(shown.map((ch) => ch.bmp), shown.map((ch) => ch.color)));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* NAPARI_SCATTER (review Appendix B, cluster H): the slice image with a points layer at each
|
|
541
|
+
* region's centroid (the napari-js analog of Plotly's region-centroid scatter), rebuilt live as
|
|
542
|
+
* regions change. This mode plots REGION centroids, so the image's region tools come with it —
|
|
543
|
+
* drawing a region adds a point at once.
|
|
544
|
+
*/
|
|
545
|
+
export class ScatterRegionsScene {
|
|
546
|
+
constructor(ctx) {
|
|
547
|
+
this.ctx = ctx;
|
|
548
|
+
this.points = null;
|
|
549
|
+
this.regionSub = null;
|
|
550
|
+
this.image = new Image2dScene(ctx, {
|
|
551
|
+
// The region-centroid points went with the re-render's layer clear.
|
|
552
|
+
onSlice: (rerendered) => {
|
|
553
|
+
if (rerendered && this.points)
|
|
554
|
+
this.rebuildPoints();
|
|
555
|
+
},
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
async mount() {
|
|
559
|
+
await this.image.mount();
|
|
560
|
+
// Disposed while the image loaded: a subscription now would outlive the scene.
|
|
561
|
+
if (this.ctx.signal.aborted)
|
|
562
|
+
return;
|
|
563
|
+
this.rebuildPoints();
|
|
564
|
+
this.regionSub = this.ctx.regionStore.getRegionUpdateEvent().subscribe(() => this.rebuildPoints());
|
|
565
|
+
this.ctx.tools.scheduleReadback();
|
|
566
|
+
}
|
|
567
|
+
setZ(z) {
|
|
568
|
+
this.image.setZ(z);
|
|
569
|
+
}
|
|
570
|
+
histogram(channel, bins) {
|
|
571
|
+
return this.image.histogram(channel, bins);
|
|
572
|
+
}
|
|
573
|
+
setImageSmoothing(enabled) {
|
|
574
|
+
this.image.setImageSmoothing(enabled);
|
|
575
|
+
}
|
|
576
|
+
setNavigatorVisible(visible) {
|
|
577
|
+
this.image.setNavigatorVisible(visible);
|
|
578
|
+
}
|
|
579
|
+
dispose() {
|
|
580
|
+
this.regionSub?.unsubscribe();
|
|
581
|
+
this.regionSub = null;
|
|
582
|
+
this.image.dispose();
|
|
583
|
+
}
|
|
584
|
+
/** (Re)build the point layer at the current region centroids. */
|
|
585
|
+
rebuildPoints() {
|
|
586
|
+
const v = this.ctx.viewer;
|
|
587
|
+
if (this.points) {
|
|
588
|
+
v.layers.remove(this.points);
|
|
589
|
+
this.points = null;
|
|
590
|
+
}
|
|
591
|
+
const centroids = regionCentroids(this.ctx.regionStore.getRegions());
|
|
592
|
+
if (centroids.length === 0)
|
|
593
|
+
return;
|
|
594
|
+
this.points = v.addPoints(centroids, {
|
|
595
|
+
size: 12,
|
|
596
|
+
faceColor: [1, 0.85, 0.2, 1],
|
|
597
|
+
borderColor: [0, 0, 0, 1],
|
|
598
|
+
borderWidth: 2,
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLWltYWdlLTJkLXNjZW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvbmFwYXJpLWpzL25hcGFyaS1pbWFnZS0yZC1zY2VuZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFbEcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSXZFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUxRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUVMLHdCQUF3QixFQUN4QixhQUFhLEVBQ2IsT0FBTyxFQUNQLGVBQWUsRUFDZixZQUFZLEVBQ1osYUFBYSxFQUNiLFVBQVUsR0FDWCxNQUFNLGtCQUFrQixDQUFDO0FBZ0IxQjs7OztHQUlHO0FBQ0gsU0FBUyxjQUFjLENBQUMsTUFBNkI7SUFDbkQsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ25ELEtBQUssTUFBTSxLQUFLLElBQUksTUFBTTtRQUFFLEtBQUssQ0FBQyxRQUFRLEdBQUcsS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7QUFDM0YsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFrQ3ZCLFlBQ21CLEdBQWlCLEVBQ2pCLE9BQXVCLEVBQUU7UUFEekIsUUFBRyxHQUFILEdBQUcsQ0FBYztRQUNqQixTQUFJLEdBQUosSUFBSSxDQUFxQjtRQW5DNUMsd0ZBQXdGO1FBQ3hGLGNB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TCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE11bHRpQ2hhbm5lbEltYWdlVmlldywgZGVjb2RlSW1hZ2VSR0JBLCBoaXN0b2dyYW1TY2FsYXIsIHRpbnRDb2xvcm1hcCB9IGZyb20gJ25hcGFyaS1qcyc7XG5pbXBvcnQgdHlwZSB7IENoYW5uZWxWaWV3LCBJbWFnZUxheWVyLCBQb2ludHNMYXllciwgVGlsZWRTb3VyY2UgfSBmcm9tICduYXBhcmktanMnO1xuaW1wb3J0IHsgTmF2aWdhdG9yT3ZlcmxheSwgU2NhbGVCYXJPdmVybGF5IH0gZnJvbSAnbmFwYXJpLWpzL292ZXJsYXlzJztcblxuaW1wb3J0IHsgSUNoYW5uZWxTdGF0ZSwgSUhpc3RvZ3JhbSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jaGFubmVsLWhpc3RvZ3JhbS1hcGkuY29udHJhY3QnO1xuaW1wb3J0IHsgVGlsZURlc2NyaXB0b3IgfSBmcm9tICcuLi90aWxlLXNlcnZlcic7XG5pbXBvcnQgeyByZ2JOZWVkc1JlY29sb3IgfSBmcm9tICcuLi9vc2QvZGlzcGxheS1waXBlbGluZSc7XG5pbXBvcnQgdHlwZSB7IE92ZXJ2aWV3SW1hZ2UgfSBmcm9tICcuL25hcGFyaS10aWxlLWNsaWVudCc7XG5pbXBvcnQgeyByZWdpb25DZW50cm9pZHMgfSBmcm9tICcuLi9yZWdpb24tY2VudHJvaWRzJztcbmltcG9ydCB7XG4gIEx1bWFQbGFuZSxcbiAgaXNTZXJ2ZXJsZXNzTXVsdGljaGFubmVsLFxuICBzcGxpdFJnYkJhbmRzLFxuICB0aW50Rm9yLFxuICB0aW50ZWRDb21wb3NpdGUsXG4gIHRvSUhpc3RvZ3JhbSxcbiAgdG9OYXBhcmlHYW1tYSxcbiAgdHlwZWRQbGFuZSxcbn0gZnJvbSAnLi9uYXBhcmktaGVscGVycyc7XG5pbXBvcnQgdHlwZSB7IE5hcGFyaVNjZW5lLCBTY2VuZUNvbnRleHQgfSBmcm9tICcuL25hcGFyaS1zY2VuZSc7XG5cbi8qKiBXaGF0IHRoZSBzY2VuZXMgYnVpbHQgb3ZlciB0aGUgMkQgaW1hZ2UgYWRkIHRvIGl0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbWFnZTJkT3B0aW9ucyB7XG4gIC8qKiBEcmF3IHRoZSBsb2FkZWQgaW1hZ2UgKGZhbHNlOiBhbiBpbWFnZS1sZXNzIHNwYXRpYWwgZGF0YXNldCwgdGhlIG9ic2VydmF0aW9ucyBhbG9uZSkuICovXG4gIGltYWdlPzogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgdG8gZml0IHRoZSBjYW1lcmEgdG8gdGhlIGltYWdlIG9uY2UgaXQgaXMgZHJhd24gKGRlZmF1bHQ6IHdoZW4gdGhlcmUgaXMgb25lKS4gKi9cbiAgZml0PzogKCkgPT4gYm9vbGVhbjtcbiAgLyoqIEFmdGVyIGEgc2xpY2UgY2hhbmdlLiBgcmVyZW5kZXJlZGAgd2hlbiB0aGUgc3RpdGNoZWQgcGF0aCByZS1yZW5kZXJlZCB0aGUgaW1hZ2Ug4oCUIHdoaWNoXG4gICAqICBDTEVBUlMgdGhlIGxheWVyIGxpc3QsIHRha2luZyBldmVyeSBvdGhlciBsYXllciB3aXRoIGl0LiAqL1xuICBvblNsaWNlPzogKHJlcmVuZGVyZWQ6IGJvb2xlYW4pID0+IHZvaWQ7XG4gIC8qKiBUaGUgcG9pbnRlciBlbnRlcmVkIHRoZSBuYXZpZ2F0b3IgKGUuZy4gdG8gaGlkZSBhIGhvdmVyIHRvb2x0aXAgb3ZlciB0aGUgY2FudmFzKS4gKi9cbiAgb25OYXZpZ2F0b3JJbnRlcmFjdD86ICgpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogQ29tcG9zaXRlIGFkZGl0aXZlIGNoYW5uZWwgbGF5ZXJzIG9udG8gYmxhY2ssIGFzIE9TRCBhbmQgUGxvdGx5IG1lcmdlIHRoZW06IHRoZSBib3R0b20tbW9zdFxuICogU0hPV04gbGF5ZXIgcmVwbGFjZXMgd2hhdCBpcyB1bmRlciBpdCwgdGhlIG90aGVycyBhZGQgb250byBpdC4gQWxsLWFkZGl0aXZlIGxheWVycyBhZGRlZCBvbnRvXG4gKiB0aGUgdmlld2VyJ3MgZGFyay1ncmV5IGJhY2tncm91bmQgaW5zdGVhZCwgbGlmdGluZyBldmVyeSBibGFjayBwaXhlbCB0byB0aGF0IGdyZXkuXG4gKi9cbmZ1bmN0aW9uIG1lcmdlT250b0JsYWNrKGxheWVyczogcmVhZG9ubHkgSW1hZ2VMYXllcltdKTogdm9pZCB7XG4gIGNvbnN0IGJhc2UgPSBsYXllcnMuZmluZCgobGF5ZXIpID0+IGxheWVyLnZpc2libGUpO1xuICBmb3IgKGNvbnN0IGxheWVyIG9mIGxheWVycykgbGF5ZXIuYmxlbmRpbmcgPSBsYXllciA9PT0gYmFzZSA/ICd0cmFuc2x1Y2VudCcgOiAnYWRkaXRpdmUnO1xufVxuXG4vKipcbiAqIFRoZSAyRCBpbWFnZSAocmV2aWV3IEFwcGVuZGl4IEIsIGNsdXN0ZXIgRSk6IHB5cmFtaWRhbCBgVGlsZWRTb3VyY2VgcyBhZ2FpbnN0IHRoZSBgL3RpbGVgXG4gKiBlbmRwb2ludCB3aGVuIGAvdGlsZXMvaW5mb2AgZGVzY3JpYmVzIHRoZSBpbWFnZSwgZWxzZSBhIHNpbmdsZSBzdGl0Y2hlZCBsZXZlbCAoYHRpbGVkOmZhbHNlYFxuICogc3RhY2tzIGZldGNoIGVhY2ggc2xpY2UncyBvd24gVVJMLCBhIHNlcnZlcmxlc3MgbXVsdGljaGFubmVsIHN0YWNrIGVhY2ggY2hhbm5lbCdzIG93biBwbGFuZSk7XG4gKiBtdWx0aWNoYW5uZWwgYWRkaXRpdmUgdGludHMsIGdyYXlzY2FsZSBjb2xvcm1hcCBvciBSR0IgKHJlY29sb3VyZWQgcGVyIGJhbmQsIHNlZVxuICoge0BsaW5rIHN5bmNSZ2JCYW5kc30pOyB0aGUgY29hcnNlIGhpc3RvZ3JhbSBzYW1wbGVzIG9mIHRoZSB0aWxlZCBwYXRoLCB0aGUgc2NhbGUgYmFyLCB0aGVcbiAqIG92ZXJ2aWV3IG5hdmlnYXRvciBhbmQgdGhlIDJEIGludGVyYWN0aW9uIHN0YWNrIChyZWdpb24gb3ZlcmxheSArIHBpeGVsIHRvb2xzKS4gVGhlXG4gKiByZWdpb24tY2VudHJvaWQgc2NhdHRlciBhbmQgdGhlIHNwYXRpYWwgMkQgc2NlbmUgYXJlIGJ1aWx0IG92ZXIgaXQuXG4gKi9cbmV4cG9ydCBjbGFzcyBJbWFnZTJkU2NlbmUgaW1wbGVtZW50cyBOYXBhcmlTY2VuZSB7XG4gIC8qKiBIb3cgdGhlIGltYWdlIGlzIGNvbXBvc2l0ZWQgKGRyaXZlcyB0aGUgaGlzdG9ncmFtIGFuZCB0aGUgZGlzcGxheS1zdGF0ZSB1cGRhdGVzKS4gKi9cbiAgaW1hZ2VNb2RlOiAnZ3JheXNjYWxlJyB8ICdtdWx0aWNoYW5uZWwnIHwgJ3JnYicgPSAncmdiJztcbiAgLyoqIFRydWUgd2hlbiB0aGUgaW1hZ2UgaXMgcmVuZGVyZWQgdmlhIHB5cmFtaWRhbCBUaWxlZFNvdXJjZXMgKGRlc2NyaXB0b3IgYXZhaWxhYmxlKS4gKi9cbiAgdGlsZWQgPSBmYWxzZTtcbiAgLyoqIG5hcGFyaS1qcyBoaWdoLWxldmVsIHZpZXcgb3duaW5nIHRoZSBwZXItY2hhbm5lbCBsYXllciBzZXQgZm9yIHtAbGluayBpbWFnZU1vZGV9LiAqL1xuICBwcml2YXRlIGNoYW5uZWxWaWV3OiBNdWx0aUNoYW5uZWxJbWFnZVZpZXcgfCBudWxsID0gbnVsbDtcbiAgLyoqIExhdGVzdCB3aW5zIGZvciBhIHN0aXRjaGVkIHNsaWNlOiBhIHNsb3cgb2xkZXIgc2xpY2UgY2FuJ3QgY2xvYmJlciBhIG5ld2VyIG9uZS4gKi9cbiAgcHJpdmF0ZSBzbGljZVJlcSA9IDA7XG4gIC8qKiBSR0I6IHRoZSBSLCBHIGFuZCBCIGJhbmRzIGFzIGxheWVyIHNvdXJjZXMgKHR5cGVkIHBsYW5lcywgb3IgYmFuZCBgVGlsZWRTb3VyY2VgcyB0aGF0IHNoYXJlXG4gICAqICBvbmUgcmVxdWVzdCBwZXIgdGlsZSkgYW5kIHRoZSBzdGl0Y2hlZCBsZXZlbCdzIHNjYWxlIOKAlCB3aGF0IHtAbGluayBzeW5jUmdiQmFuZHN9IGRyYXdzLiAqL1xuICBwcml2YXRlIHJnYkJhbmRzOiB7IHNvdXJjZXM6IENoYW5uZWxWaWV3Wydzb3VyY2UnXVtdOyBzY2FsZT86IFtudW1iZXIsIG51bWJlcl0gfSB8IG51bGwgPSBudWxsO1xuICAvKiogUkdCOiB0aGUgdGhyZWUgYWRkaXRpdmUgYmFuZCBsYXllcnMgd2hpbGUgdGhlIGNoYW5uZWwgc3RhdGVzIHJlY29sb3VyIHRoZSBpbWFnZTsgbnVsbCB3aGlsZVxuICAgKiAgdGhlIFJHQiBsYXllciBkcmF3cyBpdCBhcyBpdCBpcy4gKi9cbiAgcHJpdmF0ZSBiYW5kTGF5ZXJzOiBJbWFnZUxheWVyW10gfCBudWxsID0gbnVsbDtcbiAgLyoqIENvYXJzZSBwZXItY2hhbm5lbCBsdW1pbmFuY2Ugc2FtcGxlIChrZXllZCBieSBjaGFubmVsIGluZGV4KSBmb3IgdGhlIGhpc3RvZ3JhbSBpbiB0aWxlZCBtb2RlLFxuICAgKiAgd2hlcmUgdGhlIGxheWVycyBoYXZlIG5vIGZ1bGwgaW4tbWVtb3J5IHBpeGVscyDigJQgYW5kIGFuIFJHQiBpbWFnZSdzIHJhdyBiYW5kcyBpbiBlaXRoZXIgbW9kZS5cbiAgICogIFJlZnJlc2hlZCBvbiBtb3VudCArIHNsaWNlIGNoYW5nZS4gKi9cbiAgcmVhZG9ubHkgaGlzdFNhbXBsZXMgPSBuZXcgTWFwPG51bWJlciwgVWludDhBcnJheT4oKTtcbiAgLyoqIExhdGVzdC13aW5zIHRva2VuIGZvciB7QGxpbmsgcmVmcmVzaEhpc3RvZ3JhbVNhbXBsZXN9LiAqL1xuICBwcml2YXRlIGhpc3RHZW4gPSAwO1xuICAvKiogUGh5c2ljYWwgc2NhbGUgYmFyIG92ZXJsYXkgKG51bGwgd2hlbiB0aGUgaW1hZ2UgaGFzIG5vIMK1bS9waXhlbCkuICovXG4gIHByaXZhdGUgc2NhbGVCYXI6IFNjYWxlQmFyT3ZlcmxheSB8IG51bGwgPSBudWxsO1xuICAvKiogT3ZlcnZpZXcgbWluaW1hcCAoYm90dG9tLXJpZ2h0KSwgYXMgT1NEJ3MgbmF2aWdhdG9yLiAqL1xuICBwcml2YXRlIG5hdmlnYXRvcjogTmF2aWdhdG9yT3ZlcmxheSB8IG51bGwgPSBudWxsO1xuICAvKiogQnVtcGVkIHBlciB0aHVtYm5haWwgcmVxdWVzdCwgc28gYSBzbG93IG9uZSBjYW5ub3Qgb3ZlcndyaXRlIGEgbmV3ZXIgc2xpY2Uncy4gKi9cbiAgcHJpdmF0ZSBuYXZpZ2F0b3JUb2tlbiA9IDA7XG4gIC8qKiBUaGUgY3VycmVudCBzbGljZSdzIHBlci1jaGFubmVsIHRodW1ibmFpbCBiaXRtYXBzIChtdWx0aWNoYW5uZWwgb25seSksIGtlcHQgc28gYSB0aW50IG9yXG4gICAqICB2aXNpYmlsaXR5IGNoYW5nZSByZWNvbG91cnMgdGhlIHRodW1ibmFpbCB3aXRob3V0IHJlLWZldGNoaW5nIGl0LiAqL1xuICBwcml2YXRlIG5hdmlnYXRvckNoYW5uZWxzOiBPdmVydmlld0ltYWdlW10gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSB0aW50cy92aXNpYmlsaXR5IHRoZSB0aHVtYm5haWwgd2FzIGxhc3QgY29tcG9zaXRlZCB3aXRoIOKAlCBzZWUge0BsaW5rIHJlY29sb3JOYXZpZ2F0b3J9LiAqL1xuICBwcml2YXRlIG5hdmlnYXRvclRpbnRLZXkgPSAnJztcbiAgcHJpdmF0ZSBkaXNwbGF5U3ViOiBTdWJzY3JpcHRpb24gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN0eDogU2NlbmVDb250ZXh0LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0czogSW1hZ2UyZE9wdGlvbnMgPSB7fSxcbiAgKSB7fVxuXG4gIHByaXZhdGUgZ2V0IGhhc0ltYWdlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLm9wdHMuaW1hZ2UgIT09IGZhbHNlO1xuICB9XG5cbiAgYXN5bmMgbW91bnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXM7XG4gICAgY29uc3QgeiA9IGN0eC56KCk7XG4gICAgaWYgKHRoaXMuaGFzSW1hZ2UpIGF3YWl0IHRoaXMucmVuZGVyKHopO1xuICAgIC8vIFJlc2V0IGludG8gYSBuZXdlciBzY2VuZSB3aGlsZSB0aGUgaW1hZ2UgbG9hZGVkOiB0aGlzIHNjZW5lIGlzIGFscmVhZHkgZGlzcG9zZWQsIGFuZCB0aGVcbiAgICAvLyB0b29sIGJyaWRnZSBpcyB0aGUgbmV4dCBzY2VuZSdzIOKAlCBpbnN0YWxsIG5vdGhpbmcgbW9yZS5cbiAgICBpZiAoY3R4LnNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgaWYgKHRoaXMub3B0cy5maXQgPyB0aGlzLm9wdHMuZml0KCkgOiB0aGlzLmhhc0ltYWdlKSBjdHguZml0Q2FtZXJhU29vbigpO1xuICAgIHRoaXMuZm9sbG93RGlzcGxheVN0YXRlKCk7XG4gICAgLy8gVGhlIHNjYWxlIGJhciBhbmQgbmF2aWdhdG9yIGRlc2NyaWJlIGFuIGltYWdlOyB3aXRoIG5vbmUgbG9hZGVkLCB3aGF0ZXZlciB0aGV5IHdvdWxkXG4gICAgLy8gcmVhZCBpcyBsZWZ0IG92ZXIgZnJvbSB0aGUgbGFzdCBvbmUuXG4gICAgaWYgKHRoaXMuaGFzSW1hZ2UpIHtcbiAgICAgIHRoaXMuaW5zdGFsbFNjYWxlQmFyKCk7XG4gICAgICB0aGlzLmluc3RhbGxOYXZpZ2F0b3Ioeik7XG4gICAgfVxuICAgIGN0eC50b29scy5pbnN0YWxsMmRJbnRlcmFjdGlvbihjdHgudmlld2VyLCBjdHguaG9zdCk7XG4gIH1cblxuICBzZXRaKHo6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzO1xuICAgIGlmICh0aGlzLm5hdmlnYXRvcikgdm9pZCB0aGlzLnJlZnJlc2hOYXZpZ2F0b3JJbWFnZSh6KTtcbiAgICAvLyBUaWxlZDoganVzdCBtb3ZlIHRoZSBkaW1zIHBsYW5lIOKAlCB0aGUgdGlsZWQgdmlzdWFsIGZldGNoZXMgdGhlIG5ldyBzbGljZSdzIHRpbGVzIChjYWNoZWQgcGVyXG4gICAgLy8geiksIG5vIGxheWVyIHJlYnVpbGQuIFJlZnJlc2ggdGhlIGNvYXJzZSBoaXN0b2dyYW0gc2FtcGxlIGZvciB0aGUgbmV3IHNsaWNlLlxuICAgIGlmICh0aGlzLnRpbGVkKSB7XG4gICAgICBjdHgudmlld2VyLmRpbXMueiA9IHo7XG4gICAgICBjb25zdCBkZXNjID0gY3R4LnRpbGVzLmN1cnJlbnREZXNjcmlwdG9yKGN0eC5pbmZvKCkpO1xuICAgICAgaWYgKGRlc2MpIHZvaWQgdGhpcy5yZWZyZXNoSGlzdG9ncmFtU2FtcGxlcyh6LCBkZXNjKTtcbiAgICAgIHRoaXMub3B0cy5vblNsaWNlPy4oZmFsc2UpO1xuICAgICAgY3R4LnRvb2xzLnNjaGVkdWxlUmVhZGJhY2soKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gU3RpdGNoIGZhbGxiYWNrOiByZS1yZW5kZXIgdGhlIHNsaWNlIChyZS1mZXRjaGVzIHBlci1jaGFubmVsIC8gY29tcG9zaXRlKS4gVGhlIHRva2VuIGxldHNcbiAgICAvLyByZW5kZXIgZHJvcCBhIHN1cGVyc2VkZWQgc2NydWIgc28gYSBzbG93IG9sZGVyIHNsaWNlIGNhbid0IGNsb2JiZXIgYSBuZXdlciBvbmUuXG4gICAgY29uc3QgcmVxID0gKyt0aGlzLnNsaWNlUmVxO1xuICAgIHZvaWQgdGhpcy5yZW5kZXIoeiwgcmVxKVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICBpZiAocmVxICE9PSB0aGlzLnNsaWNlUmVxIHx8IGN0eC5zaWduYWwuYWJvcnRlZCkgcmV0dXJuO1xuICAgICAgICAvLyBBRlRFUiB0aGUgaW1hZ2UsIG5ldmVyIGJlZm9yZTogdGhlIHJlbmRlciBjbGVhcnMgdGhlIGxheWVyIGxpc3QsIHNvIHdoYXRldmVyIHNpdHMgb3ZlclxuICAgICAgICAvLyB0aGUgaW1hZ2UgaXMgd2lwZWQgYnkgdGhlIHZlcnkgaW1hZ2UgbWVhbnQgdG8gc2l0IHVuZGVyIGl0LlxuICAgICAgICB0aGlzLm9wdHMub25TbGljZT8uKHRydWUpO1xuICAgICAgICBjdHgudG9vbHMuc2NoZWR1bGVSZWFkYmFjaygpO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoZXJyKSA9PiBjb25zb2xlLmVycm9yKCdbbmFwYXJpLWpzXSBzZXRaSW5kZXggc2xpY2UgZmFpbGVkOicsIGVycikpO1xuICB9XG5cbiAgaGlzdG9ncmFtKGNoYW5uZWw6IG51bWJlciwgYmluczogbnVtYmVyKTogSUhpc3RvZ3JhbSB8IG51bGwge1xuICAgIC8vIFRpbGVkIG1vZGUgaGFzIG5vIGZ1bGwgaW4tbWVtb3J5IHBpeGVscyDihpIgdGhlIGNvYXJzZSBwZXItY2hhbm5lbCBzYW1wbGUuIFJHQjogaXRzIHJhdyBiYW5kXG4gICAgLy8gKGVpdGhlciBtb2RlKSDigJQgbmV2ZXIgdGhlIGRpc3BsYXllZCBwaXhlbHMsIHdoaWNoIHRoZSBjaGFubmVsIHN0YXRlcyBoYXZlIHJlY29sb3VyZWQuXG4gICAgaWYgKHRoaXMudGlsZWQgfHwgdGhpcy5pbWFnZU1vZGUgPT09ICdyZ2InKSB7XG4gICAgICBjb25zdCBzYW1wbGUgPSB0aGlzLmhpc3RTYW1wbGVzLmdldCh0aGlzLmltYWdlTW9kZSA9PT0gJ2dyYXlzY2FsZScgPyAwIDogY2hhbm5lbCk7XG4gICAgICByZXR1cm4gc2FtcGxlID8gdG9JSGlzdG9ncmFtKGhpc3RvZ3JhbVNjYWxhcihzYW1wbGUsIGJpbnMsIDAsIDI1NSkpIDogbnVsbDtcbiAgICB9XG4gICAgLy8gR3JheXNjYWxlL211bHRpY2hhbm5lbCAoc3RpdGNoKTogbmF0aXZlIHBlci1jaGFubmVsIGhpc3RvZ3JhbSBzdHJhaWdodCBmcm9tIHRoZSBpbi1tZW1vcnlcbiAgICAvLyBzY2FsYXIgbGF5ZXIgKG5vIEdQVSByZWFkYmFjaykuXG4gICAgY29uc3QgbGF5ZXIgPSB0aGlzLmNoYW5uZWxWaWV3Py5sYXllcnNbdGhpcy5pbWFnZU1vZGUgPT09ICdncmF5c2NhbGUnID8gMCA6IGNoYW5uZWxdO1xuICAgIGNvbnN0IGggPSBsYXllciA/IHRoaXMuY3R4LnZpZXdlci5sYXllckhpc3RvZ3JhbShsYXllciwgYmlucykgOiBudWxsO1xuICAgIHJldHVybiBoID8gdG9JSGlzdG9ncmFtKGgpIDogbnVsbDtcbiAgfVxuXG4gIHNldEltYWdlU21vb3RoaW5nKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAvLyBBcHBseSBsaXZlIHRvIHRoZSByZW5kZXJlZCBpbWFnZSBsYXllcnM7IGJha2VkIGludG8gdGhlIG5leHQgcmVuZGVyIHRvby5cbiAgICBjb25zdCBpbnRlcnBvbGF0aW9uID0gZW5hYmxlZCA/ICdsaW5lYXInIDogJ25lYXJlc3QnO1xuICAgIHRoaXMuY2hhbm5lbFZpZXc/LnNldEludGVycG9sYXRpb24oaW50ZXJwb2xhdGlvbik7XG4gICAgdGhpcy5iYW5kTGF5ZXJzPy5mb3JFYWNoKChsYXllcikgPT4gKGxheWVyLmludGVycG9sYXRpb24gPSBpbnRlcnBvbGF0aW9uKSk7XG4gIH1cblxuICBzZXROYXZpZ2F0b3JWaXNpYmxlKHZpc2libGU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLm5hdmlnYXRvcj8uc2V0VmlzaWJsZSh2aXNpYmxlKTtcbiAgfVxuXG4gIC8qKiBTaG93IHRoZSBuYXZpZ2F0b3Igb25seSBmb3IgYSBkYXRhc2V0IHRoYXQgYnJpbmdzIHBpeGVscyBvZiBpdHMgb3duIChhbmQgd2hlbiB0aGUgdXNlclxuICAgKiAgd2FudHMgaXQpOiB3aXRoIG5vIGltYWdlIG9mIGl0cyBvd24gdGhlcmUgaXMgbm90aGluZyBmb3IgYW4gb3ZlcnZpZXcgdG8gc2hvdy4gKi9cbiAgc2hvd05hdmlnYXRvckZvcihkYXRhc2V0SGFzUGl4ZWxzOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5uYXZpZ2F0b3I/LnNldFZpc2libGUoZGF0YXNldEhhc1BpeGVscyAmJiB0aGlzLmN0eC5zZXR0aW5ncy5uYXZpZ2F0b3JWaXNpYmxlKTtcbiAgfVxuXG4gIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwbGF5U3ViPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuZGlzcGxheVN1YiA9IG51bGw7XG4gICAgdGhpcy5zY2FsZUJhcj8uZGlzcG9zZSgpO1xuICAgIHRoaXMuc2NhbGVCYXIgPSBudWxsO1xuICAgIHRoaXMubmF2aWdhdG9yPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5uYXZpZ2F0b3IgPSBudWxsO1xuICAgIHRoaXMuc2V0TmF2aWdhdG9yQ2hhbm5lbHMobnVsbCk7XG4gICAgdGhpcy5oaXN0R2VuKys7XG4gICAgdGhpcy5oaXN0U2FtcGxlcy5jbGVhcigpO1xuICAgIHRoaXMuY2hhbm5lbFZpZXcgPSBudWxsO1xuICAgIHRoaXMucmdiQmFuZHMgPSBudWxsO1xuICAgIHRoaXMuYmFuZExheWVycyA9IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogUmVuZGVyIHNsaWNlIGB6YC4gV2l0aCBhIHNlcnZlciBweXJhbWlkIGRlc2NyaXB0b3IgZWFjaCBsYXllciBpcyBhIHB5cmFtaWRhbFxuICAgKiB7QGxpbmsgVGlsZWRTb3VyY2V9LCBzbyB0aGUgdmlldyByZWZpbmVzIHRvIGhpZ2hlciByZXNvbHV0aW9uIG9uIHpvb20gKGxpa2UgT1NEKSBhbmQgc2l0c1xuICAgKiBuYXR1cmFsbHkgaW4gZnVsbC1yZXNvbHV0aW9uIGNvb3JkaW5hdGVzOyB3aXRob3V0IG9uZSwgdGhlIHNpbmdsZS1sZXZlbCBzdGl0Y2guIFRocmVlIGRpc3BsYXlcbiAgICogbW9kZXMgZWl0aGVyIHdheTogbXVsdGljaGFubmVsIGFkZGl0aXZlIHRpbnQsIGdyYXlzY2FsZSBjb2xvcm1hcCwgUkdCLlxuICAgKi9cbiAgYXN5bmMgcmVuZGVyKHo6IG51bWJlciwgdG9rZW4/OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcztcbiAgICBjb25zdCBzY2VuZSA9IGN0eC5zaWduYWw7XG4gICAgY29uc3QgZGVzYyA9IGF3YWl0IGN0eC50aWxlcy5lbnN1cmVEZXNjcmlwdG9yKGN0eC5pbmZvKCkpO1xuICAgIC8vIFJlc2V0IGludG8gYSBuZXdlciBzY2VuZSB3aGlsZSB0aGUgZGVzY3JpcHRvciB3YXMgaW4gZmxpZ2h0OiB0aGlzIHJlbmRlciBpcyBzdXBlcnNlZGVkLlxuICAgIGlmIChzY2VuZS5hYm9ydGVkKSByZXR1cm47XG4gICAgaWYgKGRlc2MgJiYgZGVzYy5sZXZlbHM/Lmxlbmd0aCkge1xuICAgICAgaWYgKHRva2VuICE9IG51bGwgJiYgdG9rZW4gIT09IHRoaXMuc2xpY2VSZXEpIHJldHVybjtcbiAgICAgIGF3YWl0IHRoaXMucmVuZGVyVGlsZWQoeiwgZGVzYywgc2NlbmUpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5yZW5kZXJTdGl0Y2hlZCh6LCB0b2tlbik7XG4gIH1cblxuICAvKiogU2luZ2xlLWxldmVsIHN0aXRjaCBmYWxsYmFjayAobm8gZGVzY3JpcHRvcik6IHRoZSBwcmUtdGlsaW5nIHBhdGguICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyU3RpdGNoZWQoejogbnVtYmVyLCB0b2tlbj86IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzO1xuICAgIGNvbnN0IGluZm8gPSBjdHguaW5mbygpO1xuICAgIGNvbnN0IGRlc2MgPSBhd2FpdCBjdHgudGlsZXMuZW5zdXJlRGVzY3JpcHRvcihpbmZvKTtcbiAgICBjb25zdCBzdGF0ZXMgPSBjdHguc3RvcmUuY3VycmVudENoYW5uZWxTdGF0ZXMoKTtcbiAgICAvLyBBIHNlcnZlcmxlc3MgbXVsdGljaGFubmVsIHN0YWNrIGhhcyBubyBkZXNjcmlwdG9yOiBpdHMgY2hhbm5lbHMgYXJlIGl0cyBvd24gcGxhbmUgVVJMc1xuICAgIC8vIChgY2hhbm5lbFVybHNbel1bY11gLCB3aGljaCBmZXRjaENoYW5uZWxEYXRhIHJlYWRzKSwgYW5kIGB1cmxzW3pdYCBvbmx5IGEgY29tcG9zaXRlLlxuICAgIGNvbnN0IHNlcnZlcmxlc3NNYyA9IGlzU2VydmVybGVzc011bHRpY2hhbm5lbChjdHgudGlsZXMuaXNTaW1wbGUoaW5mbyksIGluZm8pO1xuICAgIGNvbnN0IGNoYW5uZWxDb3VudCA9XG4gICAgICBkZXNjPy5jaGFubmVscyA/PyAoc2VydmVybGVzc01jID8gKGluZm8/LmltYWdlTWV0YT8uWzBdPy5jaGFubmVsQ291bnQgPz8gMSkgOiBzdGF0ZXMubGVuZ3RoIHx8IDEpO1xuICAgIGNvbnN0IG11bHRpY2hhbm5lbCA9ICghIWRlc2M/Lm11bHRpY2hhbm5lbCB8fCBzZXJ2ZXJsZXNzTWMpICYmIGNoYW5uZWxDb3VudCA+IDE7XG5cbiAgICAvLyAxKSBGZXRjaCBhbGwgcGl4ZWwgZGF0YSBCRUZPUkUgdG91Y2hpbmcgdGhlIHZpZXdlciwgc28gYSBzdXBlcnNlZGVkIHNjcnViIGNhbiBiYWlsIHdpdGhvdXRcbiAgICAvLyAgICBoYXZpbmcgdG9ybiBkb3duIHRoZSB2aXNpYmxlIGxheWVycyAoYXZvaWRzIGZsaWNrZXIgLyBvdXQtb2Ytb3JkZXIgbGF5ZXIgc3RhdGUpLlxuICAgIGxldCBtb2RlOiAnZ3JheXNjYWxlJyB8ICdtdWx0aWNoYW5uZWwnIHwgJ3JnYic7XG4gICAgbGV0IHBsYW5lczogTHVtYVBsYW5lW10gPSBbXTtcbiAgICBsZXQgYml0bWFwOiBJbWFnZUJpdG1hcCB8IG51bGwgPSBudWxsO1xuICAgIGlmIChtdWx0aWNoYW5uZWwpIHtcbiAgICAgIG1vZGUgPSAnbXVsdGljaGFubmVsJztcbiAgICAgIHBsYW5lcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBBcnJheS5mcm9tKHsgbGVuZ3RoOiBjaGFubmVsQ291bnQgfSwgKF8sIGMpID0+IGN0eC50aWxlcy5mZXRjaENoYW5uZWxEYXRhKGluZm8sIHosIGMpKSxcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChjaGFubmVsQ291bnQgPT09IDEpIHtcbiAgICAgIG1vZGUgPSAnZ3JheXNjYWxlJztcbiAgICAgIC8vIENvbXBvc2l0ZSBmZXRjaCAobm8gY2hhbm5lbCkg4oaSIGFsbCBvdmVydmlldyBsZXZlbHMgdXNhYmxlLCBzbyBhIGxhcmdlIGdyYXlzY2FsZSBpbWFnZVxuICAgICAgLy8gc2VsZWN0cyBhIGZpdHRpbmcgZG93bnNjYWxlZCBsZXZlbCBpbnN0ZWFkIG9mIHRoZSBmdWxsLXJlcyByZWFsIGxldmVsICh0ZXh0dXJlIGxpbWl0KS5cbiAgICAgIHBsYW5lcyA9IFthd2FpdCBjdHgudGlsZXMuZmV0Y2hDaGFubmVsRGF0YShpbmZvLCB6KV07XG4gICAgfSBlbHNlIHtcbiAgICAgIG1vZGUgPSAncmdiJztcbiAgICAgIC8vIFRoZSBiaXRtYXAgZHJhd3MgdGhlIGltYWdlIGFzIGl0IGlzOyBpdHMgcmF3IGJhbmRzLCB0aGUgcGVyLWJhbmQgbGF5ZXJzIGFuZCBoaXN0b2dyYW1zLlxuICAgICAgYml0bWFwID0gYXdhaXQgY3R4LnRpbGVzLmZldGNoSW1hZ2UoaW5mbywgeik7XG4gICAgICBwbGFuZXMgPSBzcGxpdFJnYkJhbmRzKGRlY29kZUltYWdlUkdCQShiaXRtYXApKTtcbiAgICB9XG5cbiAgICAvLyAyKSBDb21taXQg4oCUIHVubGVzcyBhIG5ld2VyIHNjcnViIHN1cGVyc2VkZWQgdXMgb3IgdGhlIHNjZW5lIHdhcyB0b3JuIGRvd24uXG4gICAgaWYgKCh0b2tlbiAhPSBudWxsICYmIHRva2VuICE9PSB0aGlzLnNsaWNlUmVxKSB8fCBjdHguc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgIGJpdG1hcD8uY2xvc2U/LigpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFRoZSBkaXNwbGF5ZWQgdGV4dHVyZSBtYXkgYmUgYSBkb3duc2NhbGVkIHB5cmFtaWQgbGV2ZWw7IHNjYWxlIHRoZSBsYXllciBpbnRvIEZVTEwtUkVTT0xVVElPTlxuICAgIC8vIHdvcmxkIGNvb3JkaW5hdGVzIChsZXZlbC0wIHBpeGVscykgc28gdGhlIGNhbWVyYSwgcmVhZGJhY2sgYW5kIOKAlCBjcml0aWNhbGx5IOKAlCBwcmUtc2F2ZWRcbiAgICAvLyByZWdpb25zIChzdG9yZWQgaW4gZnVsbC1yZXMgY29vcmRzLCBlLmcuIG5kcGkpIGFsbCBsaW5lIHVwIHJlZ2FyZGxlc3Mgb2Ygd2hpY2ggbGV2ZWwgaXMgc2hvd24uXG4gICAgLy8gVGhpcyBtaXJyb3JzIE9TRCwgd2hvc2UgY29vcmRpbmF0ZSBzeXN0ZW0gaXMgYWx3YXlzIGxldmVsIDAuXG4gICAgY29uc3QgdGV4VyA9IHBsYW5lc1swXT8ud2lkdGggPz8gMDtcbiAgICBjb25zdCB0ZXhIID0gcGxhbmVzWzBdPy5oZWlnaHQgPz8gMDtcbiAgICBjb25zdCBmdWxsVyA9IGRlc2M/LndpZHRoIHx8IHRleFcgfHwgMTtcbiAgICBjb25zdCBmdWxsSCA9IGRlc2M/LmhlaWdodCB8fCB0ZXhIIHx8IDE7XG4gICAgY29uc3Qgc2NhbGU6IFtudW1iZXIsIG51bWJlcl0gPSBbdGV4VyA/IGZ1bGxXIC8gdGV4VyA6IDEsIHRleEggPyBmdWxsSCAvIHRleEggOiAxXTtcblxuICAgIHRoaXMuaW1hZ2VNb2RlID0gbW9kZTtcbiAgICBjb25zdCBpbnRlcnBvbGF0aW9uOiAnbGluZWFyJyB8ICduZWFyZXN0JyA9IGN0eC5zZXR0aW5ncy5pbWFnZVNtb290aGluZyA/ICdsaW5lYXInIDogJ25lYXJlc3QnO1xuICAgIHRoaXMuY2hhbm5lbFZpZXcgPSBuZXcgTXVsdGlDaGFubmVsSW1hZ2VWaWV3KGN0eC52aWV3ZXIpO1xuICAgIHRoaXMuYmFuZExheWVycyA9IG51bGw7IC8vIHRoZSByZW5kZXIgY2xlYXJzIHRoZSBsYXllciBsaXN0LCBiYW5kIGxheWVycyBpbmNsdWRlZFxuICAgIGlmIChtb2RlID09PSAnbXVsdGljaGFubmVsJykge1xuICAgICAgY29uc3Qgdmlld3MgPSBwbGFuZXMubWFwKChkLCBjKSA9PiB0aGlzLnRpbnRlZENoYW5uZWxWaWV3KGMsIHN0YXRlcywgZGVzYywgdHlwZWRQbGFuZShkKSwgc2NhbGUpKTtcbiAgICAgIHRoaXMuY2hhbm5lbFZpZXcucmVuZGVyKCdtdWx0aWNoYW5uZWwnLCB2aWV3cywgeyBpbnRlcnBvbGF0aW9uIH0pO1xuICAgICAgbWVyZ2VPbnRvQmxhY2sodGhpcy5jaGFubmVsVmlldy5sYXllcnMpO1xuICAgIH0gZWxzZSBpZiAobW9kZSA9PT0gJ2dyYXlzY2FsZScpIHtcbiAgICAgIGNvbnN0IHZpZXcgPSB0aGlzLmdyYXlzY2FsZUNoYW5uZWxWaWV3KHN0YXRlc1swXSwgdHlwZWRQbGFuZShwbGFuZXNbMF0pLCBzY2FsZSk7XG4gICAgICB0aGlzLmNoYW5uZWxWaWV3LnJlbmRlcignZ3JheXNjYWxlJywgW3ZpZXddLCB7IGludGVycG9sYXRpb24gfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY2hhbm5lbFZpZXcucmVuZGVyKCdyZ2InLCBbeyBzb3VyY2U6IGJpdG1hcCBhcyBJbWFnZUJpdG1hcCwgc2NhbGUgfV0sIHsgaW50ZXJwb2xhdGlvbiB9KTtcbiAgICAgIHRoaXMucmdiQmFuZHMgPSB7IHNvdXJjZXM6IHBsYW5lcy5tYXAodHlwZWRQbGFuZSksIHNjYWxlIH07XG4gICAgICB0aGlzLmhpc3RTYW1wbGVzLmNsZWFyKCk7XG4gICAgICBwbGFuZXMuZm9yRWFjaCgoYmFuZCwgYykgPT4gdGhpcy5oaXN0U2FtcGxlcy5zZXQoYywgYmFuZC5kYXRhKSk7XG4gICAgICB0aGlzLnN5bmNSZ2JCYW5kcyhzdGF0ZXMpO1xuICAgIH1cbiAgICBjdHguc2V0SW1hZ2VTaXplKGZ1bGxXLCBmdWxsSCk7XG4gIH1cblxuICAvKipcbiAgICogUmVuZGVyIHdpdGggcHlyYW1pZGFsIHtAbGluayBUaWxlZFNvdXJjZX1zIOKAlCB0aGUgdmlldyByZWZpbmVzIHRvIGhpZ2hlciByZXNvbHV0aW9uIGFzIHlvdVxuICAgKiB6b29tIGluICh0aGUgdmlzdWFsIGZldGNoZXMgdGhlIGxldmVsIHdob3NlIHRleGVscyDiiYggc2NyZWVuIHBpeGVscykgYW5kIHNpdHMgaW4gZnVsbC1yZXNcbiAgICogY29vcmRpbmF0ZXMgc28gcmVnaW9ucyBhbGlnbi4gU2FtZSB0aHJlZSBtb2RlcyBhcyB0aGUgc3RpdGNoIHBhdGguIFBlci1jaGFubmVsIGxheWVycyB1c2UgdGhlXG4gICAqIFJFQUwgcHlyYW1pZCBsZXZlbHMgKHBlci1jaGFubmVsIHRpbGVzIG9ubHkgZXhpc3QgdGhlcmUpOyB0aGUgY29tcG9zaXRlIHVzZXMgYWxsIGxldmVscy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyVGlsZWQoejogbnVtYmVyLCBkZXNjOiBUaWxlRGVzY3JpcHRvciwgc2NlbmU6IEFib3J0U2lnbmFsKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXM7XG4gICAgY29uc3Qgc3RhdGVzID0gY3R4LnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCk7XG4gICAgY29uc3QgY2hhbm5lbENvdW50ID0gZGVzYy5jaGFubmVscyA/PyAoc3RhdGVzLmxlbmd0aCB8fCAxKTtcbiAgICBjb25zdCBtdWx0aWNoYW5uZWwgPSAhIWRlc2MubXVsdGljaGFubmVsICYmIGNoYW5uZWxDb3VudCA+IDE7XG4gICAgY29uc3QgaW50ZXJwb2xhdGlvbjogJ2xpbmVhcicgfCAnbmVhcmVzdCcgPSBjdHguc2V0dGluZ3MuaW1hZ2VTbW9vdGhpbmcgPyAnbGluZWFyJyA6ICduZWFyZXN0JztcblxuICAgIHRoaXMudGlsZWQgPSB0cnVlO1xuICAgIHRoaXMuY2hhbm5lbFZpZXcgPSBuZXcgTXVsdGlDaGFubmVsSW1hZ2VWaWV3KGN0eC52aWV3ZXIpO1xuXG4gICAgaWYgKG11bHRpY2hhbm5lbCkge1xuICAgICAgdGhpcy5pbWFnZU1vZGUgPSAnbXVsdGljaGFubmVsJztcbiAgICAgIGNvbnN0IHZpZXdzID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogY2hhbm5lbENvdW50IH0sIChfLCBjKSA9PlxuICAgICAgICB0aGlzLnRpbnRlZENoYW5uZWxWaWV3KGMsIHN0YXRlcywgZGVzYywgdGhpcy50aWxlZFNvdXJjZShkZXNjLCBjLCAxLCBzY2VuZSkpLFxuICAgICAgKTtcbiAgICAgIHRoaXMuY2hhbm5lbFZpZXcucmVuZGVyKCdtdWx0aWNoYW5uZWwnLCB2aWV3cywgeyBpbnRlcnBvbGF0aW9uIH0pO1xuICAgICAgbWVyZ2VPbnRvQmxhY2sodGhpcy5jaGFubmVsVmlldy5sYXllcnMpO1xuICAgIH0gZWxzZSBpZiAoY2hhbm5lbENvdW50ID09PSAxKSB7XG4gICAgICB0aGlzLmltYWdlTW9kZSA9ICdncmF5c2NhbGUnO1xuICAgICAgY29uc3QgdmlldyA9IHRoaXMuZ3JheXNjYWxlQ2hhbm5lbFZpZXcoc3RhdGVzWzBdLCB0aGlzLnRpbGVkU291cmNlKGRlc2MsIHVuZGVmaW5lZCwgMSwgc2NlbmUpKTtcbiAgICAgIHRoaXMuY2hhbm5lbFZpZXcucmVuZGVyKCdncmF5c2NhbGUnLCBbdmlld10sIHsgaW50ZXJwb2xhdGlvbiB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5pbWFnZU1vZGUgPSAncmdiJztcbiAgICAgIHRoaXMuY2hhbm5lbFZpZXcucmVuZGVyKCdyZ2InLCBbeyBzb3VyY2U6IHRoaXMudGlsZWRTb3VyY2UoZGVzYywgdW5kZWZpbmVkLCA0LCBzY2VuZSkgfV0sIHtcbiAgICAgICAgaW50ZXJwb2xhdGlvbixcbiAgICAgIH0pO1xuICAgICAgdGhpcy5yZ2JCYW5kcyA9IHtcbiAgICAgICAgc291cmNlczogY3R4LnRpbGVzLnJnYkJhbmRTb3VyY2VzKGRlc2MsIHNjZW5lLCAoKSA9PiB0aGlzLmN0eC5iYWRnZS5iZWdpbignSW1hZ2UnKSksXG4gICAgICB9O1xuICAgICAgdGhpcy5zeW5jUmdiQmFuZHMoc3RhdGVzKTtcbiAgICB9XG4gICAgY3R4LnNldEltYWdlU2l6ZShkZXNjLndpZHRoLCBkZXNjLmhlaWdodCk7XG4gICAgLy8gQXdhaXQgb24gdGhlIGluaXRpYWwgcmVuZGVyIHNvIGdldEhpc3RvZ3JhbS9hdXRvQ29udHJhc3QgaGF2ZSBkYXRhIGltbWVkaWF0ZWx5OyBzbGljZSBjaGFuZ2VzXG4gICAgLy8gcmVmcmVzaCBmaXJlLWFuZC1mb3JnZXQgKHRoZSBoaXN0b2dyYW0gcGFuZSByZXRyaWVzKS5cbiAgICBhd2FpdCB0aGlzLnJlZnJlc2hIaXN0b2dyYW1TYW1wbGVzKHosIGRlc2MpO1xuICB9XG5cbiAgLyoqIEEgcHlyYW1pZGFsIFRpbGVkU291cmNlIHdob3NlIHRpbGVzIGNvdW50IG9uIHRoZSBsb2FkaW5nIGJhZGdlIHdoaWxlIGBzY2VuZWAgKHRoZSByZW5kZXIgdGhhdFxuICAgKiAgYXNrZWQgZm9yIGl0LCB0YWtlbiBiZWZvcmUgaXRzIGF3YWl0cykgaXMgY3VycmVudC4gKi9cbiAgdGlsZWRTb3VyY2UoXG4gICAgZGVzYzogVGlsZURlc2NyaXB0b3IsXG4gICAgY2hhbm5lbDogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICAgIGNoYW5uZWxzOiAxIHwgNCxcbiAgICBzY2VuZTogQWJvcnRTaWduYWwsXG4gICk6IFRpbGVkU291cmNlIHtcbiAgICByZXR1cm4gdGhpcy5jdHgudGlsZXMudGlsZWRTb3VyY2UoZGVzYywgY2hhbm5lbCwgY2hhbm5lbHMsIHNjZW5lLCAoKSA9PiB0aGlzLmN0eC5iYWRnZS5iZWdpbignSW1hZ2UnKSk7XG4gIH1cblxuICAvKiogQ2hhbm5lbCBgY2AncyBsYXllciBpbiB0aGUgYWRkaXRpdmUgbXVsdGljaGFubmVsIGNvbXBvc2l0ZTogdGludGVkIGJ5IGl0cyBkaXNwbGF5IGNvbG91clxuICAgKiAgKHN0b3JlLCBlbHNlIGRlc2NyaXB0b3IsIGVsc2UgdGhlIEZpamkgcGFsZXR0ZSksIHdpdGggaXRzIHdpbmRvdywgZ2FtbWEgYW5kIHZpc2liaWxpdHkuICovXG4gIHByaXZhdGUgdGludGVkQ2hhbm5lbFZpZXcoXG4gICAgYzogbnVtYmVyLFxuICAgIHN0YXRlczogSUNoYW5uZWxTdGF0ZVtdLFxuICAgIGRlc2M6IFRpbGVEZXNjcmlwdG9yIHwgbnVsbCxcbiAgICBzb3VyY2U6IENoYW5uZWxWaWV3Wydzb3VyY2UnXSxcbiAgICBzY2FsZT86IFtudW1iZXIsIG51bWJlcl0sXG4gICk6IENoYW5uZWxWaWV3IHtcbiAgICBjb25zdCBzdCA9IHN0YXRlcy5maW5kKChzKSA9PiBzLmluZGV4ID09PSBjKTtcbiAgICByZXR1cm4ge1xuICAgICAgc291cmNlLFxuICAgICAgdGludDogc3Q/LmNvbG9yID8/IGRlc2M/LmNoYW5uZWxJbmZvPy5bY10/LmNvbG9yID8/IHRpbnRGb3IoYyksXG4gICAgICBuYW1lOiBzdD8ubmFtZSA/PyBgY2gke2N9YCxcbiAgICAgIGNvbnRyYXN0TGltaXRzOiBbc3Q/Lm1pbiA/PyAwLCBzdD8ubWF4ID8/IDI1NV0sXG4gICAgICBnYW1tYTogdG9OYXBhcmlHYW1tYShzdD8uZ2FtbWEpLCAvLyBJbWFnZUogzrMg4oaSIG5hcGFyaS1qcyDOs1xuICAgICAgdmlzaWJsZTogc3Q/LnZpc2libGUgPz8gdHJ1ZSxcbiAgICAgIGludmVydDogdGhpcy5jdHguZGlzcGxheS5pbnZlcnQsXG4gICAgICAuLi4oc2NhbGUgPyB7IHNjYWxlIH0gOiB7fSksXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBUaGUgc2luZ2xlIGdyYXlzY2FsZSBsYXllcjogdGhlIHNlbGVjdGVkIGNvbG9ybWFwLCB3aXRoIHRoZSBjaGFubmVsJ3Mgd2luZG93IGFuZCBnYW1tYS4gKi9cbiAgcHJpdmF0ZSBncmF5c2NhbGVDaGFubmVsVmlldyhcbiAgICBzdDogSUNoYW5uZWxTdGF0ZSB8IHVuZGVmaW5lZCxcbiAgICBzb3VyY2U6IENoYW5uZWxWaWV3Wydzb3VyY2UnXSxcbiAgICBzY2FsZT86IFtudW1iZXIsIG51bWJlcl0sXG4gICk6IENoYW5uZWxWaWV3IHtcbiAgICByZXR1cm4ge1xuICAgICAgc291cmNlLFxuICAgICAgY29sb3JtYXA6IHRoaXMuY3R4LmRpc3BsYXkuZ3JheXNjYWxlQ29sb3JtYXAoKSxcbiAgICAgIGNvbnRyYXN0TGltaXRzOiBbc3Q/Lm1pbiA/PyAwLCBzdD8ubWF4ID8/IDI1NV0sXG4gICAgICBnYW1tYTogdG9OYXBhcmlHYW1tYShzdD8uZ2FtbWEpLCAvLyBJbWFnZUogzrMg4oaSIG5hcGFyaS1qcyDOs1xuICAgICAgaW52ZXJ0OiB0aGlzLmN0eC5kaXNwbGF5LmludmVydCxcbiAgICAgIC4uLihzY2FsZSA/IHsgc2NhbGUgfSA6IHt9KSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIChSZSlmZXRjaCBhIGNvYXJzZSBwZXItY2hhbm5lbCBsdW1pbmFuY2Ugc2FtcGxlIGZvciB0aGUgaGlzdG9ncmFtICh0aWxlZCBtb2RlIGhhcyBubyBmdWxsXG4gICAqICBpbi1tZW1vcnkgcGl4ZWxzKS4gT25lIGNoZWFwIG92ZXJ2aWV3IHRpbGUgcGVyIGNoYW5uZWwsIGZldGNoZWQgdG9nZXRoZXI7IGNhY2hlZCBieSBjaGFubmVsXG4gICAqICBpbmRleC4gTGF0ZXN0IHdpbnM6IGEgc2NydWIgZmlyZXMgb25lIHJlZnJlc2ggcGVyIHNsaWNlLCBhbmQgYW4gb2xkZXIgc2xpY2UncyBzYW1wbGVzIHRoYXRcbiAgICogIGxhbmQgYWZ0ZXIgYSBuZXdlciBvbmUncyBhcmUgZHJvcHBlZCByYXRoZXIgdGhhbiBzaG93biBhcyB0aGUgY3VycmVudCBkaXN0cmlidXRpb24uICovXG4gIGFzeW5jIHJlZnJlc2hIaXN0b2dyYW1TYW1wbGVzKHo6IG51bWJlciwgZGVzYzogUGljazxUaWxlRGVzY3JpcHRvciwgJ2NoYW5uZWxzJz4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBnZW4gPSArK3RoaXMuaGlzdEdlbjtcbiAgICB0aGlzLmhpc3RTYW1wbGVzLmNsZWFyKCk7XG4gICAgY29uc3QgaW5mbyA9IHRoaXMuY3R4LmluZm8oKTtcbiAgICBpZiAodGhpcy5pbWFnZU1vZGUgPT09ICdyZ2InKSB7XG4gICAgICAvLyBPbmUgY29hcnNlIGNvbXBvc2l0ZSB0aWxlLCBzcGxpdCBpbnRvIGl0cyByYXcgUiwgRyBhbmQgQiBiYW5kcy5cbiAgICAgIGNvbnN0IGJhbmRzID0gYXdhaXQgdGhpcy5jdHgudGlsZXMucmVhZFJnYkJhbmRzKGluZm8sIHosIDEpLmNhdGNoKCgpID0+IG51bGwpO1xuICAgICAgaWYgKGdlbiAhPT0gdGhpcy5oaXN0R2VuIHx8ICFiYW5kcykgcmV0dXJuO1xuICAgICAgYmFuZHMuZm9yRWFjaCgoYmFuZCwgYykgPT4gdGhpcy5oaXN0U2FtcGxlcy5zZXQoYywgYmFuZC5kYXRhKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG11bHRpY2hhbm5lbCA9IHRoaXMuaW1hZ2VNb2RlID09PSAnbXVsdGljaGFubmVsJztcbiAgICBjb25zdCBjaGFubmVsQ291bnQgPSBtdWx0aWNoYW5uZWwgPyAoZGVzYy5jaGFubmVscyA/PyAxKSA6IDE7XG4gICAgY29uc3Qgc2FtcGxlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgQXJyYXkuZnJvbSh7IGxlbmd0aDogY2hhbm5lbENvdW50IH0sIChfLCBjKSA9PlxuICAgICAgICAvLyBidWRnZXQgMSDihpIgY29hcnNlc3Qgc2luZ2xlIHRpbGU7IGEgZmFpbGVkIGNoYW5uZWwgbGVhdmVzIGl0cyBzYW1wbGUgdW5zZXQuXG4gICAgICAgIHRoaXMuY3R4LnRpbGVzLmZldGNoQ2hhbm5lbERhdGEoaW5mbywgeiwgbXVsdGljaGFubmVsID8gYyA6IHVuZGVmaW5lZCwgMSkudGhlbihcbiAgICAgICAgICAoZCkgPT4gZC5kYXRhLFxuICAgICAgICAgICgpID0+IG51bGwsXG4gICAgICAgICksXG4gICAgICApLFxuICAgICk7XG4gICAgaWYgKGdlbiAhPT0gdGhpcy5oaXN0R2VuKSByZXR1cm47XG4gICAgc2FtcGxlcy5mb3JFYWNoKChkYXRhLCBjKSA9PiB7XG4gICAgICBpZiAoZGF0YSkgdGhpcy5oaXN0U2FtcGxlcy5zZXQoYywgZGF0YSk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogQ2hhbm5lbCBzdGF0ZXMgKyBncmF5c2NhbGUgY29sb3JtYXAg4oaSIGxpdmUtYXBwbHkgdG8gdGhlIHJlbmRlcmVkIGxheWVycyAobm8gcmUtZmV0Y2g7IG9ubHkgelxuICAgKiAgY2hhbmdlcyByZS1mZXRjaCksIGFuZCByZWNvbG91ciB0aGUgbmF2aWdhdG9yIHRodW1ibmFpbC4gKi9cbiAgcHJpdmF0ZSBmb2xsb3dEaXNwbGF5U3RhdGUoKTogdm9pZCB7XG4gICAgdGhpcy5kaXNwbGF5U3ViID0gdGhpcy5jdHguZGlzcGxheS53YXRjaCgoY2hhbm5lbHMpID0+IHtcbiAgICAgIHRoaXMuYXBwbHlEaXNwbGF5U3RhdGUoY2hhbm5lbHMpO1xuICAgICAgdGhpcy5yZWNvbG9yTmF2aWdhdG9yKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogQXBwbHkgdGhlIGN1cnJlbnQgY2hhbm5lbCBzdGF0ZXMgLyBjb2xvcm1hcCB0byB0aGUgbGl2ZSBsYXllcnMgKG5vIHJlLWZldGNoKSwgZGVsZWdhdGluZyB0aGVcbiAgICogIHBlci1jaGFubmVsIGxheWVyIG11dGF0aW9ucyB0byB0aGUge0BsaW5rIE11bHRpQ2hhbm5lbEltYWdlVmlld30uICovXG4gIHByaXZhdGUgYXBwbHlEaXNwbGF5U3RhdGUoY2hhbm5lbHM6IElDaGFubmVsU3RhdGVbXSk6IHZvaWQge1xuICAgIGNvbnN0IHZpZXcgPSB0aGlzLmNoYW5uZWxWaWV3O1xuICAgIGNvbnN0IHsgZGlzcGxheSB9ID0gdGhpcy5jdHg7XG4gICAgaWYgKCF2aWV3KSByZXR1cm47XG4gICAgaWYgKHRoaXMuaW1hZ2VNb2RlID09PSAncmdiJykge1xuICAgICAgdGhpcy5zeW5jUmdiQmFuZHMoY2hhbm5lbHMpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5pbWFnZU1vZGUgPT09ICdtdWx0aWNoYW5uZWwnKSB7XG4gICAgICB2aWV3LmxheWVycy5mb3JFYWNoKChfLCBjKSA9PiB7XG4gICAgICAgIGNvbnN0IHN0ID0gY2hhbm5lbHMuZmluZCgocykgPT4gcy5pbmRleCA9PT0gYyk7XG4gICAgICAgIGlmICghc3QpIHJldHVybjtcbiAgICAgICAgdmlldy51cGRhdGVDaGFubmVsKGMsIHtcbiAgICAgICAgICB0aW50OiBzdC5jb2xvcixcbiAgICAgICAgICBjb250cmFzdExpbWl0czogW3N0Lm1pbiwgc3QubWF4XSxcbiAgICAgICAgICBnYW1tYTogdG9OYXBhcmlHYW1tYShzdC5nYW1tYSksIC8vIEltYWdlSiDOsyDihpIgbmFwYXJpLWpzIM6zXG4gICAgICAgICAgdmlzaWJsZTogc3QudmlzaWJsZSxcbiAgICAgICAgICBpbnZlcnQ6IGRpc3BsYXkuaW52ZXJ0LFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgbWVyZ2VPbnRvQmxhY2sodmlldy5sYXllcnMpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5pbWFnZU1vZGUgPT09ICdncmF5c2NhbGUnKSB7XG4gICAgICBjb25zdCBzdCA9IGNoYW5uZWxzWzBdO1xuICAgICAgdmlldy51cGRhdGVDaGFubmVsKDAsIHtcbiAgICAgICAgY29sb3JtYXA6IGRpc3BsYXkuZ3JheXNjYWxlQ29sb3JtYXAoKSxcbiAgICAgICAgaW52ZXJ0OiBkaXNwbGF5LmludmVydCxcbiAgICAgICAgLi4uKHN0ID8geyBjb250cmFzdExpbWl0czogW3N0Lm1pbiwgc3QubWF4XSBhcyBbbnVtYmVyLCBudW1iZXJdLCBnYW1tYTogdG9OYXBhcmlHYW1tYShzdC5nYW1tYSkgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSR0I6IGRyYXcgdGhlIGltYWdlIGFzIGl0IGlzIHdoaWxlIGl0cyBjaGFubmVsIHN0YXRlcyBsZWF2ZSBpdCBzbyAoZGVmYXVsdCBSL0cvQiB0aW50cywgZnVsbFxuICAgKiB3aW5kb3csIM6zIDEsIGFsbCBzaG93biwgbm8gaW52ZXJ0OiB7QGxpbmsgcmdiTmVlZHNSZWNvbG9yfSkg4oCUIHRoZSBSR0IgbGF5ZXIsIHVuY2hhbmdlZCwgd2l0aFxuICAgKiB0aGUgY29hcnNlIHVuZGVybGF5IGEgdGlsZWQgb25lIGtlZXBzIHdoaWxlIGl0IHBhbnMuIE90aGVyd2lzZSBkcmF3IGl0cyBSLCBHIGFuZCBCIGJhbmRzIGFzXG4gICAqIHRocmVlIGFkZGl0aXZlIGxheWVycywgZWFjaCB3aXRoIGl0cyBjaGFubmVsJ3Mgd2luZG93LCBpbnZlcnQsIGdhbW1hLCB0aW50IGFuZCB2aXNpYmlsaXR5IOKAlFxuICAgKiB3aGF0IE9TRCdzIFJHQiByZWNvbG91ciBjb21wdXRlcyBwZXIgcGl4ZWwgKHRoZSBtZXJnZSBvcmRlciBvZiBgb3NkL2Rpc3BsYXktcGlwZWxpbmVgKS4gVGhlXG4gICAqIGJhbmQgbGF5ZXJzIHNpdCBqdXN0IGFib3ZlIHRoZSBoaWRkZW4gUkdCIGxheWVyLCBzbyB3aGF0ZXZlciBpcyBkcmF3biBvdmVyIHRoZSBpbWFnZSBzdGF5c1xuICAgKiBvdmVyIGl0LiBBIGhvc3Qgd2l0aCBubyBSL0cvQiBjaGFubmVsIG1vZGVsIChmZXdlciB0aGFuIHRocmVlIHN0YXRlcykgZ2V0cyBvbmx5IHRoZSBpbnZlcnQuXG4gICAqL1xuICBwcml2YXRlIHN5bmNSZ2JCYW5kcyhjaGFubmVsczogSUNoYW5uZWxTdGF0ZVtdKTogdm9pZCB7XG4gICAgY29uc3QgeyB2aWV3ZXIsIGRpc3BsYXkgfSA9IHRoaXMuY3R4O1xuICAgIGNvbnN0IHJnYiA9IHRoaXMuY2hhbm5lbFZpZXc/LmxheWVyc1swXTtcbiAgICBjb25zdCBiYW5kcyA9IHRoaXMucmdiQmFuZHM7XG4gICAgaWYgKCFyZ2IgfHwgIWJhbmRzKSByZXR1cm47XG4gICAgY29uc3Qgc3RhdGVzID0gY2hhbm5lbHMubGVuZ3RoID49IDMgPyBjaGFubmVscyA6IFtdO1xuICAgIGlmICghcmdiTmVlZHNSZWNvbG9yKHN0YXRlcywgZGlzcGxheS5pbnZlcnQpKSB7XG4gICAgICB0aGlzLmJhbmRMYXllcnM/LmZvckVhY2goKGxheWVyKSA9PiB2aWV3ZXIubGF5ZXJzLnJlbW92ZShsYXllcikpO1xuICAgICAgdGhpcy5iYW5kTGF5ZXJzID0gbnVsbDtcbiAgICAgIHJnYi52aXNpYmxlID0gdHJ1ZTtcbiAgICAgIHZpZXdlci5yZXF1ZXN0UmVuZGVyKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdGhpcy5iYW5kTGF5ZXJzKSB7XG4gICAgICBjb25zdCBhdCA9IHZpZXdlci5sYXllcnMuaXRlbXMuaW5kZXhPZihyZ2IpO1xuICAgICAgdGhpcy5iYW5kTGF5ZXJzID0gYmFuZHMuc291cmNlcy5tYXAoKHNvdXJjZSwgYykgPT4ge1xuICAgICAgICBjb25zdCBsYXllciA9IHZpZXdlci5hZGRJbWFnZShzb3VyY2UsIHtcbiAgICAgICAgICBuYW1lOiBgcmdiJHtjfWAsXG4gICAgICAgICAgYmxlbmRpbmc6ICdhZGRpdGl2ZScsXG4gICAgICAgICAgaW50ZXJwb2xhdGlvbjogcmdiLmludGVycG9sYXRpb24sXG4gICAgICAgICAgLi4uKGJhbmRzLnNjYWxlID8geyBzY2FsZTogYmFuZHMuc2NhbGUgfSA6IHt9KSxcbiAgICAgICAgfSk7XG4gICAgICAgIHZpZXdlci5sYXllcnMubW92ZShsYXllciwgYXQgKyAxICsgYyk7XG4gICAgICAgIHJldHVybiBsYXllcjtcbiAgICAgIH0pO1xuICAgICAgcmdiLnZpc2libGUgPSBmYWxzZTtcbiAgICB9XG4gICAgdGhpcy5iYW5kTGF5ZXJzLmZvckVhY2goKGxheWVyLCBjKSA9PiB7XG4gICAgICBjb25zdCBzdCA9IHN0YXRlcy5maW5kKChzKSA9PiBzLmluZGV4ID09PSBjKTtcbiAgICAgIGxheWVyLmNvbG9ybWFwID0gdGludENvbG9ybWFwKHN0Py5jb2xvciA/PyB0aW50Rm9yKGMpKTtcbiAgICAgIGxheWVyLmNvbnRyYXN0TGltaXRzID0gW3N0Py5taW4gPz8gMCwgc3Q/Lm1heCA/PyAyNTVdO1xuICAgICAgbGF5ZXIuZ2FtbWEgPSB0b05hcGFyaUdhbW1hKHN0Py5nYW1tYSk7IC8vIEltYWdlSiDOsyDihpIgbmFwYXJpLWpzIM6zXG4gICAgICBsYXllci52aXNpYmxlID0gc3Q/LnZpc2libGUgPz8gdHJ1ZTtcbiAgICAgIGxheWVyLmludmVydCA9IGRpc3BsYXkuaW52ZXJ0O1xuICAgIH0pO1xuICAgIG1lcmdlT250b0JsYWNrKHRoaXMuYmFuZExheWVycyk7XG4gICAgdmlld2VyLnJlcXVlc3RSZW5kZXIoKTtcbiAgfVxuXG4gIC8qKiAoUmUpaW5zdGFsbCB0aGUgcGh5c2ljYWwgc2NhbGUgYmFyIChuYXBhcmktanMncyBgU2NhbGVCYXJPdmVybGF5YCBvbiB0aGUgMkQgY2FtZXJhJ3Mgem9vbSksXG4gICAqICBzaXplZCBmcm9tIHRoZSBpbWFnZSdzIMK1bS9waXhlbCAoYC90aWxlcy9pbmZvYCBtcHBYLCBmYWxsaW5nIGJhY2sgdG8gdGhlIGltYWdlIG1ldGFkYXRhKS5cbiAgICogIE5vLW9wIHdpdGhvdXQgYSBwaHlzaWNhbCBzaXplLiAqL1xuICBpbnN0YWxsU2NhbGVCYXIoKTogdm9pZCB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXM7XG4gICAgdGhpcy5zY2FsZUJhcj8uZGlzcG9zZSgpO1xuICAgIHRoaXMuc2NhbGVCYXIgPSBudWxsO1xuICAgIGNvbnN0IG1wcFggPSBjdHgudGlsZXMubXBwWChjdHguaW5mbygpKTtcbiAgICBpZiAobXBwWCA+IDApIHRoaXMuc2NhbGVCYXIgPSBuZXcgU2NhbGVCYXJPdmVybGF5KGN0eC5ob3N0LCBjdHgudmlld2VyLCB7IHVuaXRQZXJXb3JsZDogbXBwWCwgbW9kZTogJzJkJyB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgb3ZlcnZpZXcgbmF2aWdhdG9yIChuYXBhcmktanMncyBgTmF2aWdhdG9yT3ZlcmxheWApOiBhIGNvYXJzZSB0aHVtYm5haWwgb2YgdGhlIHdob2xlXG4gICAqIGltYWdlIHdpdGggdGhlIHZpZXdwb3J0IG9uIGl0OyBjbGljayBvciBkcmFnIHRvIHBhbiBhdCB0aGUgY3VycmVudCB6b29tIChhcyBPU0QpLlxuICAgKi9cbiAgcHJpdmF0ZSBpbnN0YWxsTmF2aWdhdG9yKHo6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzO1xuICAgIHRoaXMubmF2aWdhdG9yPy5kaXNwb3NlKCk7XG4gICAgdGhpcy5uYXZpZ2F0b3IgPSBudWxsO1xuICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gY3R4LmltYWdlU2l6ZSgpO1xuICAgIGlmICghd2lkdGggfHwgIWhlaWdodCkgcmV0dXJuO1xuICAgIHRoaXMubmF2aWdhdG9yID0gbmV3IE5hdmlnYXRvck92ZXJsYXkoY3R4Lmhvc3QsIGN0eC52aWV3ZXIsIHtcbiAgICAgIHdvcmxkV2lkdGg6IHdpZHRoLFxuICAgICAgd29ybGRIZWlnaHQ6IGhlaWdodCxcbiAgICAgIG9uRW50ZXI6ICgpID0+IHRoaXMub3B0cy5vbk5hdmlnYXRvckludGVyYWN0Py4oKSxcbiAgICAgIHZpc2libGU6IGN0eC5zZXR0aW5ncy5uYXZpZ2F0b3JWaXNpYmxlLFxuICAgIH0pO1xuICAgIHZvaWQgdGhpcy5yZWZyZXNoTmF2aWdhdG9ySW1hZ2Uoeik7XG4gIH1cblxuICAvKipcbiAgICogRHJhdyB0aGUgbmF2aWdhdG9yJ3MgdGh1bWJuYWlsIGZyb20gdGhlIGNvYXJzZXN0IHB5cmFtaWQgbGV2ZWwuIEEgbXVsdGljaGFubmVsIGltYWdlXG4gICAqIGlzIGNvbXBvc2l0ZWQgZnJvbSBpdHMgY2hhbm5lbHMgaW4gdGhlaXIgZGlzcGxheSBjb2xvdXJzIChzZWUge0BsaW5rIHJlY29sb3JOYXZpZ2F0b3J9KSxcbiAgICogc28gdGhlIG92ZXJ2aWV3IGxvb2tzIGxpa2UgdGhlIHZpZXcgcmF0aGVyIHRoYW4gbGlrZSBjaGFubmVsIDAgaW4gZ3JleS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVmcmVzaE5hdmlnYXRvckltYWdlKHo6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG5hdiA9IHRoaXMubmF2aWdhdG9yO1xuICAgIGlmICghbmF2KSByZXR1cm47XG4gICAgY29uc3QgdG9rZW4gPSArK3RoaXMubmF2aWdhdG9yVG9rZW47XG4gICAgY29uc3QgeyB0aWxlcyB9ID0gdGhpcy5jdHg7XG4gICAgY29uc3QgaW5mbyA9IHRoaXMuY3R4LmluZm8oKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGVzYyA9IGF3YWl0IHRpbGVzLmVuc3VyZURlc2NyaXB0b3IoaW5mbyk7XG4gICAgICAvLyBTdXBlcnNlZGVkIChhIG5ld2VyIHNsaWNlLCBvciB0aGUgc2NlbmUgd2FzIHRvcm4gZG93bik6IGZldGNoIG5vdGhpbmcuXG4gICAgICBpZiAodG9rZW4gIT09IHRoaXMubmF2aWdhdG9yVG9rZW4gfHwgdGhpcy5uYXZpZ2F0b3IgIT09IG5hdikgcmV0dXJuO1xuICAgICAgLy8gQSBzZXJ2ZXJsZXNzIG11bHRpY2hhbm5lbCBzdGFjaydzIHRodW1ibmFpbHMgYXJlIGl0cyBvd24gY2hhbm5lbCBwbGFuZXMuXG4gICAgICBjb25zdCBjb3VudCA9IGRlc2M/Lm11bHRpY2hhbm5lbFxuICAgICAgICA/IChkZXNjLmNoYW5uZWxJbmZvPy5sZW5ndGggPz8gMClcbiAgICAgICAgOiBpc1NlcnZlcmxlc3NNdWx0aWNoYW5uZWwodGlsZXMuaXNTaW1wbGUoaW5mbyksIGluZm8pXG4gICAgICAgICAgPyAoaW5mbz8uaW1hZ2VNZXRhPy5bMF0/LmNoYW5uZWxDb3VudCA/PyAwKVxuICAgICAgICAgIDogMDtcbiAgICAgIGlmIChjb3VudCA+IDEpIHtcbiAgICAgICAgY29uc3QgYml0bWFwcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgIEFycmF5LmZyb20oeyBsZW5ndGg6IGNvdW50IH0sIChfYywgYykgPT4gdGlsZXMub3ZlcnZpZXdJbWFnZShpbmZvLCB6LCBjKSksXG4gICAgICAgICk7XG4gICAgICAgIGlmICh0b2tlbiAhPT0gdGhpcy5uYXZpZ2F0b3JUb2tlbiB8fCB0aGlzLm5hdmlnYXRvciAhPT0gbmF2KSByZXR1cm47XG4gICAgICAgIHRoaXMuc2V0TmF2aWdhdG9yQ2hhbm5lbHMoYml0bWFwcyk7XG4gICAgICAgIHRoaXMucmVjb2xvck5hdmlnYXRvcigpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgaW1hZ2UgPSBhd2FpdCB0aWxlcy5vdmVydmlld0ltYWdlKGluZm8sIHopO1xuICAgICAgICBpZiAodG9rZW4gIT09IHRoaXMubmF2aWdhdG9yVG9rZW4gfHwgdGhpcy5uYXZpZ2F0b3IgIT09IG5hdikgcmV0dXJuO1xuICAgICAgICB0aGlzLnNldE5hdmlnYXRvckNoYW5uZWxzKG51bGwpO1xuICAgICAgICBuYXYuc2V0SW1hZ2UoaW1hZ2UpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdbbmFwYXJpLWpzXSBuYXZpZ2F0b3IgdGh1bWJuYWlsIHVuYXZhaWxhYmxlJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKiogUmVwbGFjZSB0aGUgcGVyLWNoYW5uZWwgdGh1bWJuYWlsIGJpdG1hcHMgKGNsb3NpbmcgdGhlIHByZXZpb3VzIG9uZXMpLiAqL1xuICBwcml2YXRlIHNldE5hdmlnYXRvckNoYW5uZWxzKGJpdG1hcHM6IE92ZXJ2aWV3SW1hZ2VbXSB8IG51bGwpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGJtcCBvZiB0aGlzLm5hdmlnYXRvckNoYW5uZWxzID8/IFtdKSBpZiAoJ2Nsb3NlJyBpbiBibXApIGJtcC5jbG9zZT8uKCk7XG4gICAgdGhpcy5uYXZpZ2F0b3JDaGFubmVscyA9IGJpdG1hcHM7XG4gICAgdGhpcy5uYXZpZ2F0b3JUaW50S2V5ID0gJyc7XG4gIH1cblxuICAvKipcbiAgICogQ29tcG9zaXRlIHRoZSBtdWx0aWNoYW5uZWwgdGh1bWJuYWlsIGluIHRoZSBjaGFubmVscycgQ1VSUkVOVCBkaXNwbGF5IHRpbnRzLCBza2lwcGluZyBoaWRkZW5cbiAgICogY2hhbm5lbHMg4oCUIHRoZSBzdG9yZSdzIGNoYW5uZWwgc3RhdGVzLCBhcyB0aGUgMkQgbGF5ZXJzIHVzZSwgbm90IHRoZSBzZXJ2ZXIncyBkZWZhdWx0cy5cbiAgICogUmUtcnVuIG9uIGV2ZXJ5IGRpc3BsYXktc3RhdGUgY2hhbmdlOyBpdCBvbmx5IHJlZHJhd3MgKG5ldmVyIHJlLWZldGNoZXMpLCBhbmQgb25seSB3aGVuIGFcbiAgICogdGludCBvciBhIHZpc2liaWxpdHkgYWN0dWFsbHkgY2hhbmdlZCwgc28gYSB3aW5kb3cvZ2FtbWEgZHJhZyBjb3N0cyBhIHN0cmluZyBjb21wYXJlLlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvbG9yTmF2aWdhdG9yKCk6IHZvaWQge1xuICAgIGNvbnN0IG5hdiA9IHRoaXMubmF2aWdhdG9yO1xuICAgIGNvbnN0IGJpdG1hcHMgPSB0aGlzLm5hdmlnYXRvckNoYW5uZWxzO1xuICAgIGlmICghbmF2IHx8ICFiaXRtYXBzKSByZXR1cm47XG4gICAgY29uc3QgaW5mbyA9IHRoaXMuY3R4LnRpbGVzLmN1cnJlbnREZXNjcmlwdG9yKHRoaXMuY3R4LmluZm8oKSk/LmNoYW5uZWxJbmZvO1xuICAgIGNvbnN0IHN0YXRlcyA9IHRoaXMuY3R4LnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCk7XG4gICAgY29uc3Qgc2hvd24gPSBiaXRtYXBzXG4gICAgICAubWFwKChibXAsIGMpID0+IHtcbiAgICAgICAgY29uc3Qgc3QgPSBzdGF0ZXMuZmluZCgocykgPT4gcy5pbmRleCA9PT0gYyk7XG4gICAgICAgIHJldHVybiB7IGJtcCwgdmlzaWJsZTogc3Q/LnZpc2libGUgPz8gdHJ1ZSwgY29sb3I6IHN0Py5jb2xvciA/PyBpbmZvPy5bY10/LmNvbG9yID8/IHRpbnRGb3IoYykgfTtcbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKChjaCkgPT4gY2gudmlzaWJsZSk7XG4gICAgY29uc3Qga2V5ID0gc2hvd24ubWFwKChjaCkgPT4gYCR7Yml0bWFwcy5pbmRleE9mKGNoLmJtcCl9OiR7Y2guY29sb3J9YCkuam9pbignfCcpO1xuICAgIGlmIChrZXkgPT09IHRoaXMubmF2aWdhdG9yVGludEtleSkgcmV0dXJuO1xuICAgIHRoaXMubmF2aWdhdG9yVGludEtleSA9IGtleTtcbiAgICBuYXYuc2V0SW1hZ2UoXG4gICAgICB0aW50ZWRDb21wb3NpdGUoXG4gICAgICAgIHNob3duLm1hcCgoY2gpID0+IGNoLmJtcCksXG4gICAgICAgIHNob3duLm1hcCgoY2gpID0+IGNoLmNvbG9yKSxcbiAgICAgICksXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIE5BUEFSSV9TQ0FUVEVSIChyZXZpZXcgQXBwZW5kaXggQiwgY2x1c3RlciBIKTogdGhlIHNsaWNlIGltYWdlIHdpdGggYSBwb2ludHMgbGF5ZXIgYXQgZWFjaFxuICogcmVnaW9uJ3MgY2VudHJvaWQgKHRoZSBuYXBhcmktanMgYW5hbG9nIG9mIFBsb3RseSdzIHJlZ2lvbi1jZW50cm9pZCBzY2F0dGVyKSwgcmVidWlsdCBsaXZlIGFzXG4gKiByZWdpb25zIGNoYW5nZS4gVGhpcyBtb2RlIHBsb3RzIFJFR0lPTiBjZW50cm9pZHMsIHNvIHRoZSBpbWFnZSdzIHJlZ2lvbiB0b29scyBjb21lIHdpdGggaXQg4oCUXG4gKiBkcmF3aW5nIGEgcmVnaW9uIGFkZHMgYSBwb2ludCBhdCBvbmNlLlxuICovXG5leHBvcnQgY2xhc3MgU2NhdHRlclJlZ2lvbnNTY2VuZSBpbXBsZW1lbnRzIE5hcGFyaVNjZW5lIHtcbiAgcmVhZG9ubHkgaW1hZ2U6IEltYWdlMmRTY2VuZTtcbiAgcHJpdmF0ZSBwb2ludHM6IFBvaW50c0xheWVyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcmVnaW9uU3ViOiBTdWJzY3JpcHRpb24gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGN0eDogU2NlbmVDb250ZXh0KSB7XG4gICAgdGhpcy5pbWFnZSA9IG5ldyBJbWFnZTJkU2NlbmUoY3R4LCB7XG4gICAgICAvLyBUaGUgcmVnaW9uLWNlbnRyb2lkIHBvaW50cyB3ZW50IHdpdGggdGhlIHJlLXJlbmRlcidzIGxheWVyIGNsZWFyLlxuICAgICAgb25TbGljZTogKHJlcmVuZGVyZWQpID0+IHtcbiAgICAgICAgaWYgKHJlcmVuZGVyZWQgJiYgdGhpcy5wb2ludHMpIHRoaXMucmVidWlsZFBvaW50cygpO1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIG1vdW50KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuaW1hZ2UubW91bnQoKTtcbiAgICAvLyBEaXNwb3NlZCB3aGlsZSB0aGUgaW1hZ2UgbG9hZGVkOiBhIHN1YnNjcmlwdGlvbiBub3cgd291bGQgb3V0bGl2ZSB0aGUgc2NlbmUuXG4gICAgaWYgKHRoaXMuY3R4LnNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgdGhpcy5yZWJ1aWxkUG9pbnRzKCk7XG4gICAgdGhpcy5yZWdpb25TdWIgPSB0aGlzLmN0eC5yZWdpb25TdG9yZS5nZXRSZWdpb25VcGRhdGVFdmVudCgpLnN1YnNjcmliZSgoKSA9PiB0aGlzLnJlYnVpbGRQb2ludHMoKSk7XG4gICAgdGhpcy5jdHgudG9vbHMuc2NoZWR1bGVSZWFkYmFjaygpO1xuICB9XG5cbiAgc2V0Wih6OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmltYWdlLnNldFooeik7XG4gIH1cblxuICBoaXN0b2dyYW0oY2hhbm5lbDogbnVtYmVyLCBiaW5zOiBudW1iZXIpOiBJSGlzdG9ncmFtIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuaW1hZ2UuaGlzdG9ncmFtKGNoYW5uZWwsIGJpbnMpO1xuICB9XG5cbiAgc2V0SW1hZ2VTbW9vdGhpbmcoZW5hYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuaW1hZ2Uuc2V0SW1hZ2VTbW9vdGhpbmcoZW5hYmxlZCk7XG4gIH1cblxuICBzZXROYXZpZ2F0b3JWaXNpYmxlKHZpc2libGU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmltYWdlLnNldE5hdmlnYXRvclZpc2libGUodmlzaWJsZSk7XG4gIH1cblxuICBkaXNwb3NlKCk6IHZvaWQge1xuICAgIHRoaXMucmVnaW9uU3ViPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMucmVnaW9uU3ViID0gbnVsbDtcbiAgICB0aGlzLmltYWdlLmRpc3Bvc2UoKTtcbiAgfVxuXG4gIC8qKiAoUmUpYnVpbGQgdGhlIHBvaW50IGxheWVyIGF0IHRoZSBjdXJyZW50IHJlZ2lvbiBjZW50cm9pZHMuICovXG4gIHByaXZhdGUgcmVidWlsZFBvaW50cygpOiB2b2lkIHtcbiAgICBjb25zdCB2ID0gdGhpcy5jdHgudmlld2VyO1xuICAgIGlmICh0aGlzLnBvaW50cykge1xuICAgICAgdi5sYXllcnMucmVtb3ZlKHRoaXMucG9pbnRzKTtcbiAgICAgIHRoaXMucG9pbnRzID0gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgY2VudHJvaWRzID0gcmVnaW9uQ2VudHJvaWRzKHRoaXMuY3R4LnJlZ2lvblN0b3JlLmdldFJlZ2lvbnMoKSk7XG4gICAgaWYgKGNlbnRyb2lkcy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICB0aGlzLnBvaW50cyA9IHYuYWRkUG9pbnRzKGNlbnRyb2lkcywge1xuICAgICAgc2l6ZTogMTIsXG4gICAgICBmYWNlQ29sb3I6IFsxLCAwLjg1LCAwLjIsIDFdLFxuICAgICAgYm9yZGVyQ29sb3I6IFswLCAwLCAwLCAxXSxcbiAgICAgIGJvcmRlcldpZHRoOiAyLFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|