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