@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,369 @@
|
|
|
1
|
+
import { LruCache } from 'napari-js';
|
|
2
|
+
import { ALL_GENES } from '../../../contracts/ports/spatial-data.port';
|
|
3
|
+
import { tileId, tilesInRect, tilesInRectFrom, transcriptLevelFor } from '../../../spatial/lod';
|
|
4
|
+
import { allGenesPlan, clipTranscripts, geneBinSize, groupTranscripts, groupedMarkerPx, quantileOf, transcriptMarkerPx, } from '../../../spatial/transcript-grouping';
|
|
5
|
+
import { clusterMarkers, mergeTranscriptTiles } from '../../../spatial/spatial-tile-merge';
|
|
6
|
+
/** The all-gene pyramid's finest bin (250 µm source tiles / 128) and default level count, used
|
|
7
|
+
* to group a gene selection on the same ladder when a dataset has no pyramid. */
|
|
8
|
+
const PYRAMID_BASE_BIN_UM = 250 / 128;
|
|
9
|
+
const PYRAMID_LEVELS = 7;
|
|
10
|
+
/** Transcripts drawn at once. Past this a screen is solid colour anyway; the level
|
|
11
|
+
* policy keeps a normal view far below it. */
|
|
12
|
+
const MAX_TRANSCRIPTS = 400_000;
|
|
13
|
+
const MAX_TRANSCRIPT_TILES = 36;
|
|
14
|
+
const MAX_BIN_TILES = 64;
|
|
15
|
+
/** Summed per-cluster density grids kept (one per cluster × bin × dataset). */
|
|
16
|
+
const DENSITY_CACHE_SIZE = 256;
|
|
17
|
+
/**
|
|
18
|
+
* Decides which transcripts the 2D spatial view fetches, at which level, for the current
|
|
19
|
+
* camera and selection: a {@link TranscriptJob} that can be keyed before it runs (so an
|
|
20
|
+
* unchanged plan is a no-op) and that fetches and merges when run.
|
|
21
|
+
*
|
|
22
|
+
* Pure apart from the port, so the level policy is testable without a viewer. Owns the
|
|
23
|
+
* cache of summed per-cluster density grids a zoomed-out gene selection is drawn from.
|
|
24
|
+
*/
|
|
25
|
+
export class TranscriptJobPlanner {
|
|
26
|
+
constructor(port) {
|
|
27
|
+
this.port = port;
|
|
28
|
+
/** Summed per-cluster density grids (see densityFor). */
|
|
29
|
+
this.densityCache = new LruCache(DENSITY_CACHE_SIZE);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The job that draws the view's transcripts as markers (circles or icons), or null when the
|
|
33
|
+
* view draws none or the port cannot serve them.
|
|
34
|
+
*/
|
|
35
|
+
jobFor(dataset, view, rect, pxPerUnit) {
|
|
36
|
+
const mode = view.transcriptMode;
|
|
37
|
+
if (mode !== 'circles' && mode !== 'glyphs')
|
|
38
|
+
return null;
|
|
39
|
+
const geneBins = this.port.getTranscriptGeneBins && dataset.transcriptGeneBins;
|
|
40
|
+
if (!this.port.getTranscriptTile && !geneBins)
|
|
41
|
+
return null;
|
|
42
|
+
return view.transcriptAllGenes
|
|
43
|
+
? this.allGenesJob(dataset, view, rect, pxPerUnit)
|
|
44
|
+
: this.geneJob(dataset, view, rect, pxPerUnit);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The chosen genes, at the level the zoom calls for — or coarser, while the markers in
|
|
48
|
+
* view would exceed the budget.
|
|
49
|
+
*/
|
|
50
|
+
geneJob(dataset, view, rect, pxPerUnit) {
|
|
51
|
+
const meta = dataset.transcriptTiles;
|
|
52
|
+
const genes = view.transcriptGenes;
|
|
53
|
+
if (!meta || !genes.length)
|
|
54
|
+
return null;
|
|
55
|
+
const first = transcriptLevelFor(pxPerUnit, meta.levels);
|
|
56
|
+
const keysAt = (l) => tilesInRect(rect, l, meta.levels, meta.bounds, MAX_TRANSCRIPT_TILES);
|
|
57
|
+
const query = { genes, quality: view.transcriptQuality };
|
|
58
|
+
const pxPerMicron = pxPerMicronOf(dataset, pxPerUnit);
|
|
59
|
+
const clip = clipWindow(rect);
|
|
60
|
+
// Zoomed out, each gene's transcripts are grouped on the all-gene pyramid's bin ladder,
|
|
61
|
+
// so a gene selection reads like "all genes" does: one marker per gene per area, sized
|
|
62
|
+
// by how many it holds; zoomed in far enough, every transcript is its own marker.
|
|
63
|
+
const ladder = dataset.transcriptBins?.levels;
|
|
64
|
+
const baseBin = ladder?.[0]?.binSize ?? (dataset.micronsPerUnit ? PYRAMID_BASE_BIN_UM / dataset.micronsPerUnit : 0);
|
|
65
|
+
const bin = geneBinSize(pxPerUnit, baseBin, ladder?.length ?? PYRAMID_LEVELS);
|
|
66
|
+
// Zoomed out to bins as wide as the density grid, a selection is drawn from the per-gene
|
|
67
|
+
// density grids — one cached request per cluster — rather than 10x's coarse per-gene
|
|
68
|
+
// tiles, which take minutes for a few hundred genes.
|
|
69
|
+
// With the pyramid's per-gene levels, every zoom of a selection reads them: the level the
|
|
70
|
+
// zoom calls for, coarser while the markers would exceed the max.
|
|
71
|
+
// Both are built from high-quality calls only: with low-quality calls included, the
|
|
72
|
+
// quality-aware tiles below serve every zoom (as long as there are tiles to serve).
|
|
73
|
+
const highOnly = view.transcriptQuality !== 'all' || !this.port.getTranscriptTile;
|
|
74
|
+
const geneBins = dataset.transcriptGeneBins;
|
|
75
|
+
const fromGeneBins = highOnly && geneBins && this.port.getTranscriptGeneBins;
|
|
76
|
+
if (fromGeneBins && (bin !== null || !this.port.getTranscriptTile)) {
|
|
77
|
+
return this.geneBinsJob(dataset, view, clip, geneBins, bin ?? geneBins.levels[0].binSize);
|
|
78
|
+
}
|
|
79
|
+
const grid = dataset.density?.gridSize[0] ?? 0;
|
|
80
|
+
if (highOnly && bin !== null && grid > 0 && this.port.getDensity && bin >= grid * 0.75) {
|
|
81
|
+
return this.clusterDensityJob(dataset, view, clip, pxPerUnit, Math.max(bin, grid));
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
kind: 'genes',
|
|
85
|
+
// The clip window, in quarter-view steps: a pan past the margin re-clips.
|
|
86
|
+
key: `genes|${genes.join(',')}|${view.transcriptQuality}|${view.transcriptBudget}|${bin ?? 'each'}|` +
|
|
87
|
+
`${clip.key}|${keysAt(first).map(tileId)}`,
|
|
88
|
+
load: async (ctx) => {
|
|
89
|
+
// The zoom's own level only: over the budget, the transcripts are combined into
|
|
90
|
+
// larger markers (groupSelection), never fetched from slower coarse levels.
|
|
91
|
+
const tiles = await ctx.fetchAll(keysAt(first), (k) => this.port.getTranscriptTile(k.level, k.gx, k.gy, query));
|
|
92
|
+
// Only what is on screen (and a margin, so a small pan needs nothing new) counts
|
|
93
|
+
// against the budget and the cap; a tile reaches far past the view.
|
|
94
|
+
const merged = mergeTranscriptTiles(tiles.map((t) => clipTranscripts(t, clip.around)), MAX_TRANSCRIPTS);
|
|
95
|
+
const px = Float32Array.from(merged.weight, (w) => transcriptMarkerPx(w, view.transcriptScale, pxPerMicron));
|
|
96
|
+
return baseBin > 0
|
|
97
|
+
? { merged, px, ladder: { baseBin, levels: ladder?.length ?? PYRAMID_LEVELS, start: bin } }
|
|
98
|
+
: { merged, px };
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A gene selection from the pyramid's per-gene levels: starting at the level whose bins are
|
|
104
|
+
* `startBin`, fetch the view's tiles for the selected genes and step to a coarser level while
|
|
105
|
+
* one marker per cluster per bin would exceed the max. Hidden genes are fetched too (their
|
|
106
|
+
* counts in view still show) and dropped before drawing; grouping by cluster happens there.
|
|
107
|
+
*/
|
|
108
|
+
geneBinsJob(dataset, view, clip, meta, startBin) {
|
|
109
|
+
const genes = view.transcriptGenes;
|
|
110
|
+
const levels = meta.levels;
|
|
111
|
+
let first = levels.findIndex((l) => l.binSize >= startBin * 0.999);
|
|
112
|
+
if (first < 0)
|
|
113
|
+
first = levels.length - 1;
|
|
114
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
115
|
+
const hidden = new Set(view.transcriptHiddenGenes);
|
|
116
|
+
const clusters = this.selectionClusters(view);
|
|
117
|
+
const clusterOf = new Map();
|
|
118
|
+
clusters.forEach((c, ci) => c.genes.forEach((g) => clusterOf.set(genes.indexOf(g), ci)));
|
|
119
|
+
const keysAt = (m) => tilesInRectFrom(meta.origin, clip.around, m, levels.map((l) => ({ tileSize: l.tileSize })), null, MAX_BIN_TILES);
|
|
120
|
+
return {
|
|
121
|
+
kind: 'genes',
|
|
122
|
+
key: `gene-bins|${genes.join(',')}|${budget}|${first}|${JSON.stringify(view.transcriptGeneGroups)}|` + clip.key,
|
|
123
|
+
load: async (ctx) => {
|
|
124
|
+
let m = first;
|
|
125
|
+
for (;;) {
|
|
126
|
+
const tiles = await ctx.fetchAll(keysAt(m), (k) => this.port.getTranscriptGeneBins(k.level, k.gx, k.gy, genes));
|
|
127
|
+
const clipped = tiles.map((t) => clipTranscripts(t, clip.around));
|
|
128
|
+
// Past the cap a merge would drop whole genes (the tail of every tile): go coarser.
|
|
129
|
+
if (clipped.reduce((n, t) => n + t.count, 0) > MAX_TRANSCRIPTS && m < levels.length - 1) {
|
|
130
|
+
m++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const merged = mergeTranscriptTiles(clipped, MAX_TRANSCRIPTS);
|
|
134
|
+
// Markers this level would draw: one per (visible cluster, bin).
|
|
135
|
+
const seen = new Set();
|
|
136
|
+
const bin = levels[m].binSize;
|
|
137
|
+
for (let i = 0; i < merged.count; i++) {
|
|
138
|
+
if (hidden.has(genes[merged.gene[i]]))
|
|
139
|
+
continue;
|
|
140
|
+
const c = clusterOf.get(merged.gene[i]);
|
|
141
|
+
if (c === undefined)
|
|
142
|
+
continue;
|
|
143
|
+
seen.add(`${c}|${Math.floor(merged.x[i] / bin)}|${Math.floor(merged.y[i] / bin)}`);
|
|
144
|
+
}
|
|
145
|
+
if (seen.size <= budget || m >= levels.length - 1) {
|
|
146
|
+
return { merged, px: new Float32Array(merged.count), ladder: { baseBin: bin, levels: 1, start: bin } };
|
|
147
|
+
}
|
|
148
|
+
m++;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** The selection's clusters: each gene-tree group's visible genes, then each ungrouped gene. */
|
|
154
|
+
selectionClusters(view) {
|
|
155
|
+
const hidden = new Set(view.transcriptHiddenGenes);
|
|
156
|
+
const slots = new Map(view.transcriptGenes.map((g, i) => [g, i]));
|
|
157
|
+
const taken = new Set();
|
|
158
|
+
const out = [];
|
|
159
|
+
for (const g of view.transcriptGeneGroups) {
|
|
160
|
+
const genes = g.genes.filter((x) => slots.has(x) && !hidden.has(x) && !taken.has(x));
|
|
161
|
+
genes.forEach((x) => taken.add(x));
|
|
162
|
+
if (genes.length)
|
|
163
|
+
out.push({ name: g.name, genes, slot: slots.get(genes[0]) });
|
|
164
|
+
}
|
|
165
|
+
for (const gene of view.transcriptGenes) {
|
|
166
|
+
if (!taken.has(gene) && !hidden.has(gene))
|
|
167
|
+
out.push({ name: gene, genes: [gene], slot: slots.get(gene) });
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Per-gene density grids summed for `genes`, cached (a cluster is asked for once per bin).
|
|
173
|
+
* Keyed by dataset too: this manager outlives a dataset, and another may share gene names.
|
|
174
|
+
* Least-recently-USED eviction, so the clusters in view stay cached; a failed request is
|
|
175
|
+
* dropped so the next plan asks again.
|
|
176
|
+
*/
|
|
177
|
+
densityFor(dataset, genes, bin) {
|
|
178
|
+
const key = `${dataset}|${bin}|${genes.join(',')}`;
|
|
179
|
+
let p = this.densityCache.get(key);
|
|
180
|
+
if (!p) {
|
|
181
|
+
const request = this.port.getDensity(genes, bin);
|
|
182
|
+
request.catch(() => {
|
|
183
|
+
if (this.densityCache.get(key) === request)
|
|
184
|
+
this.densityCache.delete(key);
|
|
185
|
+
});
|
|
186
|
+
this.densityCache.set(key, request);
|
|
187
|
+
p = request;
|
|
188
|
+
}
|
|
189
|
+
return p;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* A gene selection zoomed out: one marker per cluster per bin, from the per-gene density
|
|
193
|
+
* grids. The bin starts where markers are 14 px apart and doubles until the markers fit the
|
|
194
|
+
* max; each marker sits at the count-weighted centre of the finer grid inside it, so markers
|
|
195
|
+
* follow the tissue rather than a lattice.
|
|
196
|
+
*/
|
|
197
|
+
clusterDensityJob(dataset, view, clip, pxPerUnit, startBin) {
|
|
198
|
+
const grid = dataset.density.gridSize[0];
|
|
199
|
+
const clusters = this.selectionClusters(view);
|
|
200
|
+
let first = grid;
|
|
201
|
+
while (first < startBin * 0.999)
|
|
202
|
+
first *= 2;
|
|
203
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
204
|
+
return {
|
|
205
|
+
kind: 'genes',
|
|
206
|
+
key: `clusters|${clusters.map((c) => `${c.name}:${c.genes.join('+')}`).join(';')}|${budget}|${first}|` +
|
|
207
|
+
clip.key,
|
|
208
|
+
load: async () => {
|
|
209
|
+
let bin = first;
|
|
210
|
+
for (;;) {
|
|
211
|
+
// The finer grid gives each marker its centre; the server bins 1, 2, 4 or 8 cells.
|
|
212
|
+
const fine = Math.min(bin >= grid * 2 ? bin / 2 : bin, grid * 8);
|
|
213
|
+
const rasters = await Promise.all(clusters.map((c) => this.densityFor(dataset.id, c.genes, fine)));
|
|
214
|
+
const out = clusterMarkers(rasters, clusters.map((c) => c.slot), bin, clip.around);
|
|
215
|
+
if (out.tile.count <= budget || bin >= grid * 2 ** 12) {
|
|
216
|
+
const px = groupedSizes(out.tile.weight, bin * pxPerUnit, view.transcriptScale);
|
|
217
|
+
return {
|
|
218
|
+
merged: out.tile,
|
|
219
|
+
px,
|
|
220
|
+
kind: 'genes',
|
|
221
|
+
clustered: {
|
|
222
|
+
group: out.group,
|
|
223
|
+
names: clusters.map((c) => c.name),
|
|
224
|
+
genes: clusters.map((c) => c.genes),
|
|
225
|
+
bin,
|
|
226
|
+
origin: rasters[0]?.meta.origin ?? [0, 0],
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
bin *= 2;
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Every gene: the transcripts themselves once they fit the budget, else bins of the
|
|
237
|
+
* all-gene pyramid sized by how many transcripts each holds.
|
|
238
|
+
*/
|
|
239
|
+
allGenesJob(dataset, view, rect, pxPerUnit) {
|
|
240
|
+
const bins = dataset.transcriptBins;
|
|
241
|
+
const tiles = dataset.transcriptTiles;
|
|
242
|
+
const bounds = bins?.bounds ?? tiles?.bounds;
|
|
243
|
+
if (!bounds)
|
|
244
|
+
return null;
|
|
245
|
+
const plan = allGenesPlan({
|
|
246
|
+
rect,
|
|
247
|
+
bounds,
|
|
248
|
+
pxPerUnit,
|
|
249
|
+
budget: view.transcriptBudget,
|
|
250
|
+
total: bins?.count ?? tiles?.count ?? 0,
|
|
251
|
+
levels: bins && this.port.getTranscriptBins ? bins.levels : [],
|
|
252
|
+
canIndividual: !!tiles,
|
|
253
|
+
});
|
|
254
|
+
if (plan.kind === 'individual' && tiles) {
|
|
255
|
+
const keys = tilesInRect(rect, 0, tiles.levels, tiles.bounds, MAX_TRANSCRIPT_TILES);
|
|
256
|
+
// Each tile clipped to the view, rounded outward to 10 units so small pans hit cache.
|
|
257
|
+
const r10 = (v, up) => (up ? Math.ceil(v / 10) : Math.floor(v / 10)) * 10;
|
|
258
|
+
const size = tiles.levels[0].tileSize;
|
|
259
|
+
const boxes = keys.map((k) => [
|
|
260
|
+
Math.max(k.gx * size, r10(rect.x0, false)),
|
|
261
|
+
Math.max(k.gy * size, r10(rect.y0, false)),
|
|
262
|
+
Math.min((k.gx + 1) * size, r10(rect.x1, true)),
|
|
263
|
+
Math.min((k.gy + 1) * size, r10(rect.y1, true)),
|
|
264
|
+
]);
|
|
265
|
+
const pxPerMicron = pxPerMicronOf(dataset, pxPerUnit);
|
|
266
|
+
return {
|
|
267
|
+
kind: 'individual',
|
|
268
|
+
key: `all|individual|${view.transcriptBudget}|${boxes.map((b) => b.join(',')).join(';')}`,
|
|
269
|
+
load: async (ctx) => {
|
|
270
|
+
const got = await ctx.fetchAll(keys.map((k, i) => ({ ...k, box: boxes[i] })), (k) => this.port.getTranscriptTile(0, k.gx, k.gy, { genes: [ALL_GENES], box: k.box }));
|
|
271
|
+
// The plan estimated the view from the dataset's average density; expression is
|
|
272
|
+
// uneven, so a dense view can hold far more. Rather than cut the excess off, show
|
|
273
|
+
// it grouped — the bin level the planner would pick if it had known.
|
|
274
|
+
const cap = Math.max(view.transcriptBudget * 1.5, 1);
|
|
275
|
+
const loaded = got.reduce((n, t) => n + t.count, 0);
|
|
276
|
+
if (loaded > cap && bins && this.port.getTranscriptBins) {
|
|
277
|
+
const fallback = allGenesPlan({
|
|
278
|
+
rect,
|
|
279
|
+
bounds,
|
|
280
|
+
pxPerUnit,
|
|
281
|
+
budget: view.transcriptBudget,
|
|
282
|
+
total: bins.count,
|
|
283
|
+
levels: bins.levels,
|
|
284
|
+
canIndividual: false,
|
|
285
|
+
});
|
|
286
|
+
if (fallback.kind === 'bins') {
|
|
287
|
+
const job = this.binsJob(view, rect, pxPerUnit, bounds, bins, fallback.level);
|
|
288
|
+
return { ...(await job.load(ctx)), kind: job.kind, bin: job.bin };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const merged = mergeTranscriptTiles(got, cap);
|
|
292
|
+
// One transcript per entry: every marker is the same size.
|
|
293
|
+
const px = new Float32Array(merged.count).fill(transcriptMarkerPx(1, view.transcriptScale, pxPerMicron));
|
|
294
|
+
return { merged, px };
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
if (plan.kind === 'bins' && bins && this.port.getTranscriptBins) {
|
|
299
|
+
return this.binsJob(view, rect, pxPerUnit, bounds, bins, plan.level);
|
|
300
|
+
}
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
/** Bins of the all-gene pyramid at `level`, sized by how many transcripts each holds. */
|
|
304
|
+
binsJob(view, rect, pxPerUnit, bounds, bins, level) {
|
|
305
|
+
const lv = bins.levels[level];
|
|
306
|
+
const keys = tilesInRectFrom(bins.origin, rect, level, bins.levels.map((l) => ({ tileSize: l.tileSize })), bounds, MAX_BIN_TILES);
|
|
307
|
+
return {
|
|
308
|
+
kind: 'bins',
|
|
309
|
+
bin: { size: lv.binSize, origin: bins.origin },
|
|
310
|
+
key: `all|bins|${level}|${view.transcriptBudget}|${keys.map(tileId)}`,
|
|
311
|
+
load: async (ctx) => {
|
|
312
|
+
const got = await ctx.fetchAll(keys, (k) => this.port.getTranscriptBins(k.level, k.gx, k.gy));
|
|
313
|
+
const merged = mergeTranscriptTiles(got, Math.max(view.transcriptBudget * 1.5, 1));
|
|
314
|
+
return { merged, px: groupedSizes(merged.weight, lv.binSize * pxPerUnit, view.transcriptScale) };
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Group a gene selection for the zoom: one marker per gene-tree cluster (a gene in no
|
|
321
|
+
* cluster is its own) per bin of the pyramid ladder, starting at the finest bin whose
|
|
322
|
+
* markers are 14 px apart and stepping up while the markers would exceed the budget.
|
|
323
|
+
* Null to draw every transcript: zoomed in, with the selection within the budget.
|
|
324
|
+
*/
|
|
325
|
+
export function groupSelection(t, view, ladder, pxPerUnit) {
|
|
326
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
327
|
+
const genes = view.transcriptGenes;
|
|
328
|
+
const groups = view.transcriptGeneGroups;
|
|
329
|
+
const names = [...groups.map((g) => g.name), ...genes];
|
|
330
|
+
const clusterOf = genes.map((gene, slot) => {
|
|
331
|
+
const g = groups.findIndex((x) => x.genes.includes(gene));
|
|
332
|
+
return g >= 0 ? g : groups.length + slot;
|
|
333
|
+
});
|
|
334
|
+
const keyOf = (slot) => clusterOf[slot] ?? groups.length + slot;
|
|
335
|
+
let bin = ladder.start;
|
|
336
|
+
if (bin === null) {
|
|
337
|
+
// Every transcript, if they fit the max and none was cut off at the cap.
|
|
338
|
+
if (t.count <= budget && t.count < MAX_TRANSCRIPTS)
|
|
339
|
+
return null;
|
|
340
|
+
bin = ladder.baseBin;
|
|
341
|
+
}
|
|
342
|
+
const top = ladder.baseBin * 2 ** (ladder.levels - 1);
|
|
343
|
+
let grouped = groupTranscripts(t, bin, keyOf);
|
|
344
|
+
// Over the max: combine into larger markers, a level at a time.
|
|
345
|
+
while (grouped.tile.count > budget && bin < top) {
|
|
346
|
+
bin *= 2;
|
|
347
|
+
grouped = groupTranscripts(t, bin, keyOf);
|
|
348
|
+
}
|
|
349
|
+
const px = groupedSizes(grouped.tile.weight, bin * pxPerUnit, view.transcriptScale);
|
|
350
|
+
return { merged: grouped.tile, px, bin, group: grouped.group, names };
|
|
351
|
+
}
|
|
352
|
+
/** Screen sizes of grouped markers: by weight against the 95th-percentile weight, over `binPx`. */
|
|
353
|
+
function groupedSizes(weight, binPx, scale) {
|
|
354
|
+
const refCount = quantileOf(weight, 0.95);
|
|
355
|
+
return Float32Array.from(weight, (w) => groupedMarkerPx(w, refCount, binPx, scale));
|
|
356
|
+
}
|
|
357
|
+
function clipWindow(rect) {
|
|
358
|
+
const mx = (rect.x1 - rect.x0) * 0.25;
|
|
359
|
+
const my = (rect.y1 - rect.y0) * 0.25;
|
|
360
|
+
return {
|
|
361
|
+
around: { x0: rect.x0 - mx, y0: rect.y0 - my, x1: rect.x1 + mx, y1: rect.y1 + my },
|
|
362
|
+
key: `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}`,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/** Physical marker size needs µm; undefined when the dataset's unit is unknown. */
|
|
366
|
+
function pxPerMicronOf(dataset, pxPerUnit) {
|
|
367
|
+
return dataset.micronsPerUnit ? pxPerUnit / dataset.micronsPerUnit : undefined;
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNjcmlwdC1qb2JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvbmFwYXJpLWpzL3NwYXRpYWwtdGlsZXMvdHJhbnNjcmlwdC1qb2JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFckMsT0FBTyxFQUFFLFNBQVMsRUFBd0IsTUFBTSw0Q0FBNEMsQ0FBQztBQVE3RixPQUFPLEVBQVksTUFBTSxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRyxPQUFPLEVBQ0wsWUFBWSxFQUNaLGVBQWUsRUFDZixXQUFXLEVBQ1gsZ0JBQWdCLEVBQ2hCLGVBQWUsRUFDZixVQUFVLEVBQ1Ysa0JBQWtCLEdBQ25CLE1BQU0sc0NBQXNDLENBQUM7QUFDOUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBSTNGO2tGQUNrRjtBQUNsRixNQUFNLG1CQUFtQixHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7QUFDdEMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxDQUFDO0FBQ3pCOytDQUMrQztBQUMvQyxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUM7QUFDaEMsTUFBTSxvQkFBb0IsR0FBRyxFQUFFLENBQUM7QUFDaEMsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO0FBQ3pCLCtFQUErRTtBQUMvRSxNQUFNLGtCQUFrQixHQUFHLEdBQUcsQ0FBQztBQTBCL0I7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxvQkFBb0I7SUFJL0IsWUFBNkIsSUFBcUI7UUFBckIsU0FBSSxHQUFKLElBQUksQ0FBaUI7UUFIbEQseURBQXlEO1FBQ3hDLGlCQUFZLEdBQUcsSUFBSSxRQUFRLENBQWdDLGtCQUFrQixDQUFDLENBQUM7SUFFM0MsQ0FB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QyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ3RGLENBQUM7QUFVRCxTQUFTLFVBQVUsQ0FBQyxJQUFjO0lBQ2hDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3RDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3RDLE9BQU87UUFDTCxNQUFNLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEVBQUU7UUFDbEYsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUU7S0FDN0UsQ0FBQztBQUNKLENBQUM7QUFFRCxtRkFBbUY7QUFDbkYsU0FBUyxhQUFhLENBQUMsT0FBdUIsRUFBRSxTQUFpQjtJQUMvRCxPQUFPLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDakYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExydUNhY2hlIH0gZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHsgQUxMX0dFTkVTLCB0eXBlIFNwYXRpYWxEYXRhUG9ydCB9IGZyb20gJy4uLy4uLy4uL2NvbnRyYWN0cy9wb3J0cy9zcGF0aWFsLWRhdGEucG9ydCc7XG5pbXBvcnQgdHlwZSB7IFNwYXRpYWxWaWV3U3RhdGUgfSBmcm9tICcuLi8uLi8uLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQge1xuICBTcGF0aWFsQm91bmRzLFxuICBTcGF0aWFsRGF0YXNldCxcbiAgU3BhdGlhbERlbnNpdHlSYXN0ZXIsXG4gIFNwYXRpYWxUcmFuc2NyaXB0VGlsZSxcbn0gZnJvbSAnLi4vLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBEYXRhUmVjdCwgdGlsZUlkLCB0aWxlc0luUmVjdCwgdGlsZXNJblJlY3RGcm9tLCB0cmFuc2NyaXB0TGV2ZWxGb3IgfSBmcm9tICcuLi8uLi8uLi9zcGF0aWFsL2xvZCc7XG5pbXBvcnQge1xuICBhbGxHZW5lc1BsYW4sXG4gIGNsaXBUcmFuc2NyaXB0cyxcbiAgZ2VuZUJpblNpemUsXG4gIGdyb3VwVHJhbnNjcmlwdHMsXG4gIGdyb3VwZWRNYXJrZXJQeCxcbiAgcXVhbnRpbGVPZixcbiAgdHJhbnNjcmlwdE1hcmtlclB4LFxufSBmcm9tICcuLi8uLi8uLi9zcGF0aWFsL3RyYW5zY3JpcHQtZ3JvdXBpbmcnO1xuaW1wb3J0IHsgY2x1c3Rlck1hcmtlcnMsIG1lcmdlVHJhbnNjcmlwdFRpbGVzIH0gZnJvbSAnLi4vLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXRpbGUtbWVyZ2UnO1xuaW1wb3J0IHR5cGUgeyBQbGFuQ29udGV4dCB9IGZyb20gJy4vcGxhbi1jb250ZXh0JztcbmltcG9ydCB0eXBlIHsgVHJhbnNjcmlwdEJpbiwgVHJhbnNjcmlwdEtpbmQgfSBmcm9tICcuL3RyYW5zY3JpcHQtaG92ZXInO1xuXG4vKiogVGhlIGFsbC1nZW5lIHB5cmFtaWQncyBmaW5lc3QgYmluICgyNTAgwrVtIHNvdXJjZSB0aWxlcyAvIDEyOCkgYW5kIGRlZmF1bHQgbGV2ZWwgY291bnQsIHVzZWRcbiAqICB0byBncm91cCBhIGdlbmUgc2VsZWN0aW9uIG9uIHRoZSBzYW1lIGxhZGRlciB3aGVuIGEgZGF0YXNldCBoYXMgbm8gcHlyYW1pZC4gKi9cbmNvbnN0IFBZUkFNSURfQkFTRV9CSU5fVU0gPSAyNTAgLyAxMjg7XG5jb25zdCBQWVJBTUlEX0xFVkVMUyA9IDc7XG4vKiogVHJhbnNjcmlwdHMgZHJhd24gYXQgb25jZS4gUGFzdCB0aGlzIGEgc2NyZWVuIGlzIHNvbGlkIGNvbG91ciBhbnl3YXk7IHRoZSBsZXZlbFxuICogIHBvbGljeSBrZWVwcyBhIG5vcm1hbCB2aWV3IGZhciBiZWxvdyBpdC4gKi9cbmNvbnN0IE1BWF9UUkFOU0NSSVBUUyA9IDQwMF8wMDA7XG5jb25zdCBNQVhfVFJBTlNDUklQVF9USUxFUyA9IDM2O1xuY29uc3QgTUFYX0JJTl9USUxFUyA9IDY0O1xuLyoqIFN1bW1lZCBwZXItY2x1c3RlciBkZW5zaXR5IGdyaWRzIGtlcHQgKG9uZSBwZXIgY2x1c3RlciDDlyBiaW4gw5cgZGF0YXNldCkuICovXG5jb25zdCBERU5TSVRZX0NBQ0hFX1NJWkUgPSAyNTY7XG5cbi8qKiBBIHRyYW5zY3JpcHQgZmV0Y2ggdGhlIHBsYW5uZXIgY2FuIGtleSBiZWZvcmUgcnVubmluZy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNjcmlwdEpvYiB7XG4gIC8qKiBXaGF0IG9uZSBlbnRyeSBpcyDigJQgZGVjaWRlcyB3aGF0IGhvdmVyaW5nIGl0IHNheXMuICovXG4gIGtpbmQ6IFRyYW5zY3JpcHRLaW5kO1xuICAvKiogRm9yIGJpbnM6IHRoZWlyIHNpemUgYW5kIGdyaWQgb3JpZ2luLCBzbyBhIGhvdmVyZWQgYmluJ3Mgc3F1YXJlIGNhbiBiZSByZWNvdmVyZWQuICovXG4gIGJpbj86IFRyYW5zY3JpcHRCaW47XG4gIC8qKiBJZGVudGlmaWVzIHdoYXQgd2lsbCBiZSBkcmF3biwgc28gYW4gdW5jaGFuZ2VkIHBsYW4gaXMgYSBuby1vcC4gKi9cbiAga2V5OiBzdHJpbmc7XG4gIC8qKiBGZXRjaCBhbmQgbWVyZ2U7IGBweGAgaXMgZWFjaCBlbnRyeSdzIG1hcmtlciBkaWFtZXRlciBpbiBzY3JlZW4gcGl4ZWxzLiBBIGpvYiBtYXlcbiAgICogIHN3aXRjaCB0byBhbm90aGVyIGtpbmQgb25jZSBpdCBzZWVzIHRoZSBkYXRhIChpbmRpdmlkdWFsIOKGkiBiaW5zKTsgaXQgdGhlbiBzYXlzIHNvLiAqL1xuICBsb2FkKGN0eDogUGxhbkNvbnRleHQpOiBQcm9taXNlPFRyYW5zY3JpcHRMb2FkPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2NyaXB0TG9hZCB7XG4gIG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlO1xuICBweDogRmxvYXQzMkFycmF5O1xuICAvKiogRm9yIGEgZ2VuZSBzZWxlY3Rpb246IGdyb3VwIGl0IG9uIHRoaXMgYmluIGxhZGRlciBvbmNlIGhpZGRlbiBnZW5lcyBhcmUgZHJvcHBlZC4gKi9cbiAgbGFkZGVyPzogeyBiYXNlQmluOiBudW1iZXI7IGxldmVsczogbnVtYmVyOyBzdGFydDogbnVtYmVyIHwgbnVsbCB9O1xuICAvKiogQWxyZWFkeSBvbmUgbWFya2VyIHBlciBjbHVzdGVyIHBlciBiaW4gKHpvb21lZCBvdXQsIGZyb20gdGhlIGRlbnNpdHkgZ3JpZHMpOiBubyBjZWxscy4gKi9cbiAgY2x1c3RlcmVkPzogeyBncm91cDogSW50MzJBcnJheTsgbmFtZXM6IHN0cmluZ1tdOyBnZW5lczogc3RyaW5nW11bXTsgYmluOiBudW1iZXI7IG9yaWdpbjogW251bWJlciwgbnVtYmVyXSB9O1xuICBraW5kPzogVHJhbnNjcmlwdEpvYlsna2luZCddO1xuICBiaW4/OiBUcmFuc2NyaXB0Sm9iWydiaW4nXTtcbn1cblxuLyoqXG4gKiBEZWNpZGVzIHdoaWNoIHRyYW5zY3JpcHRzIHRoZSAyRCBzcGF0aWFsIHZpZXcgZmV0Y2hlcywgYXQgd2hpY2ggbGV2ZWwsIGZvciB0aGUgY3VycmVudFxuICogY2FtZXJhIGFuZCBzZWxlY3Rpb246IGEge0BsaW5rIFRyYW5zY3JpcHRKb2J9IHRoYXQgY2FuIGJlIGtleWVkIGJlZm9yZSBpdCBydW5zIChzbyBhblxuICogdW5jaGFuZ2VkIHBsYW4gaXMgYSBuby1vcCkgYW5kIHRoYXQgZmV0Y2hlcyBhbmQgbWVyZ2VzIHdoZW4gcnVuLlxuICpcbiAqIFB1cmUgYXBhcnQgZnJvbSB0aGUgcG9ydCwgc28gdGhlIGxldmVsIHBvbGljeSBpcyB0ZXN0YWJsZSB3aXRob3V0IGEgdmlld2VyLiBPd25zIHRoZVxuICogY2FjaGUgb2Ygc3VtbWVkIHBlci1jbHVzdGVyIGRlbnNpdHkgZ3JpZHMgYSB6b29tZWQtb3V0IGdlbmUgc2VsZWN0aW9uIGlzIGRyYXduIGZyb20uXG4gKi9cbmV4cG9ydCBjbGFzcyBUcmFuc2NyaXB0Sm9iUGxhbm5lciB7XG4gIC8qKiBTdW1tZWQgcGVyLWNsdXN0ZXIgZGVuc2l0eSBncmlkcyAoc2VlIGRlbnNpdHlGb3IpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRlbnNpdHlDYWNoZSA9IG5ldyBMcnVDYWNoZTxQcm9taXNlPFNwYXRpYWxEZW5zaXR5UmFzdGVyPj4oREVOU0lUWV9DQUNIRV9TSVpFKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHBvcnQ6IFNwYXRpYWxEYXRhUG9ydCkge31cblxuICAvKipcbiAgICogVGhlIGpvYiB0aGF0IGRyYXdzIHRoZSB2aWV3J3MgdHJhbnNjcmlwdHMgYXMgbWFya2VycyAoY2lyY2xlcyBvciBpY29ucyksIG9yIG51bGwgd2hlbiB0aGVcbiAgICogdmlldyBkcmF3cyBub25lIG9yIHRoZSBwb3J0IGNhbm5vdCBzZXJ2ZSB0aGVtLlxuICAgKi9cbiAgam9iRm9yKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgcmVjdDogRGF0YVJlY3QsXG4gICAgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IFRyYW5zY3JpcHRKb2IgfCBudWxsIHtcbiAgICBjb25zdCBtb2RlID0gdmlldy50cmFuc2NyaXB0TW9kZTtcbiAgICBpZiAobW9kZSAhPT0gJ2NpcmNsZXMnICYmIG1vZGUgIT09ICdnbHlwaHMnKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBnZW5lQmlucyA9IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0R2VuZUJpbnMgJiYgZGF0YXNldC50cmFuc2NyaXB0R2VuZUJpbnM7XG4gICAgaWYgKCF0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUgJiYgIWdlbmVCaW5zKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gdGhpcy5hbGxHZW5lc0pvYihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQpXG4gICAgICA6IHRoaXMuZ2VuZUpvYihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjaG9zZW4gZ2VuZXMsIGF0IHRoZSBsZXZlbCB0aGUgem9vbSBjYWxscyBmb3Ig4oCUIG9yIGNvYXJzZXIsIHdoaWxlIHRoZSBtYXJrZXJzIGluXG4gICAqIHZpZXcgd291bGQgZXhjZWVkIHRoZSBidWRnZXQuXG4gICAqL1xuICBwcml2YXRlIGdlbmVKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICByZWN0OiBEYXRhUmVjdCxcbiAgICBweFBlclVuaXQ6IG51bWJlcixcbiAgKTogVHJhbnNjcmlwdEpvYiB8IG51bGwge1xuICAgIGNvbnN0IG1ldGEgPSBkYXRhc2V0LnRyYW5zY3JpcHRUaWxlcztcbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICAgIGlmICghbWV0YSB8fCAhZ2VuZXMubGVuZ3RoKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBmaXJzdCA9IHRyYW5zY3JpcHRMZXZlbEZvcihweFBlclVuaXQsIG1ldGEubGV2ZWxzKTtcbiAgICBjb25zdCBrZXlzQXQgPSAobDogbnVtYmVyKSA9PiB0aWxlc0luUmVjdChyZWN0LCBsLCBtZXRhLmxldmVscywgbWV0YS5ib3VuZHMsIE1BWF9UUkFOU0NSSVBUX1RJTEVTKTtcbiAgICBjb25zdCBxdWVyeSA9IHsgZ2VuZXMsIHF1YWxpdHk6IHZpZXcudHJhbnNjcmlwdFF1YWxpdHkgfTtcbiAgICBjb25zdCBweFBlck1pY3JvbiA9IHB4UGVyTWljcm9uT2YoZGF0YXNldCwgcHhQZXJVbml0KTtcbiAgICBjb25zdCBjbGlwID0gY2xpcFdpbmRvdyhyZWN0KTtcbiAgICAvLyBab29tZWQgb3V0LCBlYWNoIGdlbmUncyB0cmFuc2NyaXB0cyBhcmUgZ3JvdXBlZCBvbiB0aGUgYWxsLWdlbmUgcHlyYW1pZCdzIGJpbiBsYWRkZXIsXG4gICAgLy8gc28gYSBnZW5lIHNlbGVjdGlvbiByZWFkcyBsaWtlIFwiYWxsIGdlbmVzXCIgZG9lczogb25lIG1hcmtlciBwZXIgZ2VuZSBwZXIgYXJlYSwgc2l6ZWRcbiAgICAvLyBieSBob3cgbWFueSBpdCBob2xkczsgem9vbWVkIGluIGZhciBlbm91Z2gsIGV2ZXJ5IHRyYW5zY3JpcHQgaXMgaXRzIG93biBtYXJrZXIuXG4gICAgY29uc3QgbGFkZGVyID0gZGF0YXNldC50cmFuc2NyaXB0Qmlucz8ubGV2ZWxzO1xuICAgIGNvbnN0IGJhc2VCaW4gPVxuICAgICAgbGFkZGVyPy5bMF0/LmJpblNpemUgPz8gKGRhdGFzZXQubWljcm9uc1BlclVuaXQgPyBQWVJBTUlEX0JBU0VfQklOX1VNIC8gZGF0YXNldC5taWNyb25zUGVyVW5pdCA6IDApO1xuICAgIGNvbnN0IGJpbiA9IGdlbmVCaW5TaXplKHB4UGVyVW5pdCwgYmFzZUJpbiwgbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMpO1xuICAgIC8vIFpvb21lZCBvdXQgdG8gYmlucyBhcyB3aWRlIGFzIHRoZSBkZW5zaXR5IGdyaWQsIGEgc2VsZWN0aW9uIGlzIGRyYXduIGZyb20gdGhlIHBlci1nZW5lXG4gICAgLy8gZGVuc2l0eSBncmlkcyDigJQgb25lIGNhY2hlZCByZXF1ZXN0IHBlciBjbHVzdGVyIOKAlCByYXRoZXIgdGhhbiAxMHgncyBjb2Fyc2UgcGVyLWdlbmVcbiAgICAvLyB0aWxlcywgd2hpY2ggdGFrZSBtaW51dGVzIGZvciBhIGZldyBodW5kcmVkIGdlbmVzLlxuICAgIC8vIFdpdGggdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHMsIGV2ZXJ5IHpvb20gb2YgYSBzZWxlY3Rpb24gcmVhZHMgdGhlbTogdGhlIGxldmVsIHRoZVxuICAgIC8vIHpvb20gY2FsbHMgZm9yLCBjb2Fyc2VyIHdoaWxlIHRoZSBtYXJrZXJzIHdvdWxkIGV4Y2VlZCB0aGUgbWF4LlxuICAgIC8vIEJvdGggYXJlIGJ1aWx0IGZyb20gaGlnaC1xdWFsaXR5IGNhbGxzIG9ubHk6IHdpdGggbG93LXF1YWxpdHkgY2FsbHMgaW5jbHVkZWQsIHRoZVxuICAgIC8vIHF1YWxpdHktYXdhcmUgdGlsZXMgYmVsb3cgc2VydmUgZXZlcnkgem9vbSAoYXMgbG9uZyBhcyB0aGVyZSBhcmUgdGlsZXMgdG8gc2VydmUpLlxuICAgIGNvbnN0IGhpZ2hPbmx5ID0gdmlldy50cmFuc2NyaXB0UXVhbGl0eSAhPT0gJ2FsbCcgfHwgIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZTtcbiAgICBjb25zdCBnZW5lQmlucyA9IGRhdGFzZXQudHJhbnNjcmlwdEdlbmVCaW5zO1xuICAgIGNvbnN0IGZyb21HZW5lQmlucyA9IGhpZ2hPbmx5ICYmIGdlbmVCaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0R2VuZUJpbnM7XG4gICAgaWYgKGZyb21HZW5lQmlucyAmJiAoYmluICE9PSBudWxsIHx8ICF0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZW5lQmluc0pvYihkYXRhc2V0LCB2aWV3LCBjbGlwLCBnZW5lQmlucywgYmluID8/IGdlbmVCaW5zLmxldmVsc1swXS5iaW5TaXplKTtcbiAgICB9XG4gICAgY29uc3QgZ3JpZCA9IGRhdGFzZXQuZGVuc2l0eT8uZ3JpZFNpemVbMF0gPz8gMDtcbiAgICBpZiAoaGlnaE9ubHkgJiYgYmluICE9PSBudWxsICYmIGdyaWQgPiAwICYmIHRoaXMucG9ydC5nZXREZW5zaXR5ICYmIGJpbiA+PSBncmlkICogMC43NSkge1xuICAgICAgcmV0dXJuIHRoaXMuY2x1c3RlckRlbnNpdHlKb2IoZGF0YXNldCwgdmlldywgY2xpcCwgcHhQZXJVbml0LCBNYXRoLm1heChiaW4sIGdyaWQpKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGtpbmQ6ICdnZW5lcycsXG4gICAgICAvLyBUaGUgY2xpcCB3aW5kb3csIGluIHF1YXJ0ZXItdmlldyBzdGVwczogYSBwYW4gcGFzdCB0aGUgbWFyZ2luIHJlLWNsaXBzLlxuICAgICAga2V5OlxuICAgICAgICBgZ2VuZXN8JHtnZW5lcy5qb2luKCcsJyl9fCR7dmlldy50cmFuc2NyaXB0UXVhbGl0eX18JHt2aWV3LnRyYW5zY3JpcHRCdWRnZXR9fCR7YmluID8/ICdlYWNoJ318YCArXG4gICAgICAgIGAke2NsaXAua2V5fXwke2tleXNBdChmaXJzdCkubWFwKHRpbGVJZCl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jIChjdHgpID0+IHtcbiAgICAgICAgLy8gVGhlIHpvb20ncyBvd24gbGV2ZWwgb25seTogb3ZlciB0aGUgYnVkZ2V0LCB0aGUgdHJhbnNjcmlwdHMgYXJlIGNvbWJpbmVkIGludG9cbiAgICAgICAgLy8gbGFyZ2VyIG1hcmtlcnMgKGdyb3VwU2VsZWN0aW9uKSwgbmV2ZXIgZmV0Y2hlZCBmcm9tIHNsb3dlciBjb2Fyc2UgbGV2ZWxzLlxuICAgICAgICBjb25zdCB0aWxlcyA9IGF3YWl0IGN0eC5mZXRjaEFsbChrZXlzQXQoZmlyc3QpLCAoaykgPT5cbiAgICAgICAgICB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUhKGsubGV2ZWwsIGsuZ3gsIGsuZ3ksIHF1ZXJ5KSxcbiAgICAgICAgKTtcbiAgICAgICAgLy8gT25seSB3aGF0IGlzIG9uIHNjcmVlbiAoYW5kIGEgbWFyZ2luLCBzbyBhIHNtYWxsIHBhbiBuZWVkcyBub3RoaW5nIG5ldykgY291bnRzXG4gICAgICAgIC8vIGFnYWluc3QgdGhlIGJ1ZGdldCBhbmQgdGhlIGNhcDsgYSB0aWxlIHJlYWNoZXMgZmFyIHBhc3QgdGhlIHZpZXcuXG4gICAgICAgIGNvbnN0IG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKFxuICAgICAgICAgIHRpbGVzLm1hcCgodCkgPT4gY2xpcFRyYW5zY3JpcHRzKHQsIGNsaXAuYXJvdW5kKSksXG4gICAgICAgICAgTUFYX1RSQU5TQ1JJUFRTLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBweCA9IEZsb2F0MzJBcnJheS5mcm9tKG1lcmdlZC53ZWlnaHQsICh3KSA9PlxuICAgICAgICAgIHRyYW5zY3JpcHRNYXJrZXJQeCh3LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgcHhQZXJNaWNyb24pLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gYmFzZUJpbiA+IDBcbiAgICAgICAgICA/IHsgbWVyZ2VkLCBweCwgbGFkZGVyOiB7IGJhc2VCaW4sIGxldmVsczogbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMsIHN0YXJ0OiBiaW4gfSB9XG4gICAgICAgICAgOiB7IG1lcmdlZCwgcHggfTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGdlbmUgc2VsZWN0aW9uIGZyb20gdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHM6IHN0YXJ0aW5nIGF0IHRoZSBsZXZlbCB3aG9zZSBiaW5zIGFyZVxuICAgKiBgc3RhcnRCaW5gLCBmZXRjaCB0aGUgdmlldydzIHRpbGVzIGZvciB0aGUgc2VsZWN0ZWQgZ2VuZXMgYW5kIHN0ZXAgdG8gYSBjb2Fyc2VyIGxldmVsIHdoaWxlXG4gICAqIG9uZSBtYXJrZXIgcGVyIGNsdXN0ZXIgcGVyIGJpbiB3b3VsZCBleGNlZWQgdGhlIG1heC4gSGlkZGVuIGdlbmVzIGFyZSBmZXRjaGVkIHRvbyAodGhlaXJcbiAgICogY291bnRzIGluIHZpZXcgc3RpbGwgc2hvdykgYW5kIGRyb3BwZWQgYmVmb3JlIGRyYXdpbmc7IGdyb3VwaW5nIGJ5IGNsdXN0ZXIgaGFwcGVucyB0aGVyZS5cbiAgICovXG4gIHByaXZhdGUgZ2VuZUJpbnNKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICBjbGlwOiBDbGlwV2luZG93LFxuICAgIG1ldGE6IE5vbk51bGxhYmxlPFNwYXRpYWxEYXRhc2V0Wyd0cmFuc2NyaXB0R2VuZUJpbnMnXT4sXG4gICAgc3RhcnRCaW46IG51bWJlcixcbiAgKTogVHJhbnNjcmlwdEpvYiB7XG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lcztcbiAgICBjb25zdCBsZXZlbHMgPSBtZXRhLmxldmVscztcbiAgICBsZXQgZmlyc3QgPSBsZXZlbHMuZmluZEluZGV4KChsKSA9PiBsLmJpblNpemUgPj0gc3RhcnRCaW4gKiAwLjk5OSk7XG4gICAgaWYgKGZpcnN0IDwgMCkgZmlyc3QgPSBsZXZlbHMubGVuZ3RoIC0gMTtcbiAgICBjb25zdCBidWRnZXQgPSBNYXRoLm1heCgxLCB2aWV3LnRyYW5zY3JpcHRCdWRnZXQpO1xuICAgIGNvbnN0IGhpZGRlbiA9IG5ldyBTZXQodmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMpO1xuICAgIGNvbnN0IGNsdXN0ZXJzID0gdGhpcy5zZWxlY3Rpb25DbHVzdGVycyh2aWV3KTtcbiAgICBjb25zdCBjbHVzdGVyT2YgPSBuZXcgTWFwPG51bWJlciwgbnVtYmVyPigpO1xuICAgIGNsdXN0ZXJzLmZvckVhY2goKGMsIGNpKSA9PiBjLmdlbmVzLmZvckVhY2goKGcpID0+IGNsdXN0ZXJPZi5zZXQoZ2VuZXMuaW5kZXhPZihnKSwgY2kpKSk7XG4gICAgY29uc3Qga2V5c0F0ID0gKG06IG51bWJlcikgPT5cbiAgICAgIHRpbGVzSW5SZWN0RnJvbShcbiAgICAgICAgbWV0YS5vcmlnaW4sXG4gICAgICAgIGNsaXAuYXJvdW5kLFxuICAgICAgICBtLFxuICAgICAgICBsZXZlbHMubWFwKChsKSA9PiAoeyB0aWxlU2l6ZTogbC50aWxlU2l6ZSB9KSksXG4gICAgICAgIG51bGwsXG4gICAgICAgIE1BWF9CSU5fVElMRVMsXG4gICAgICApO1xuICAgIHJldHVybiB7XG4gICAgICBraW5kOiAnZ2VuZXMnLFxuICAgICAga2V5OlxuICAgICAgICBgZ2VuZS1iaW5zfCR7Z2VuZXMuam9pbignLCcpfXwke2J1ZGdldH18JHtmaXJzdH18JHtKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKX18YCArIGNsaXAua2V5LFxuICAgICAgbG9hZDogYXN5bmMgKGN0eCkgPT4ge1xuICAgICAgICBsZXQgbSA9IGZpcnN0O1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgY29uc3QgdGlsZXMgPSBhd2FpdCBjdHguZmV0Y2hBbGwoa2V5c0F0KG0pLCAoaykgPT5cbiAgICAgICAgICAgIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0R2VuZUJpbnMhKGsubGV2ZWwsIGsuZ3gsIGsuZ3ksIGdlbmVzKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IGNsaXBwZWQgPSB0aWxlcy5tYXAoKHQpID0+IGNsaXBUcmFuc2NyaXB0cyh0LCBjbGlwLmFyb3VuZCkpO1xuICAgICAgICAgIC8vIFBhc3QgdGhlIGNhcCBhIG1lcmdlIHdvdWxkIGRyb3Agd2hvbGUgZ2VuZXMgKHRoZSB0YWlsIG9mIGV2ZXJ5IHRpbGUpOiBnbyBjb2Fyc2VyLlxuICAgICAgICAgIGlmIChjbGlwcGVkLnJlZHVjZSgobiwgdCkgPT4gbiArIHQuY291bnQsIDApID4gTUFYX1RSQU5TQ1JJUFRTICYmIG0gPCBsZXZlbHMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgbSsrO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKGNsaXBwZWQsIE1BWF9UUkFOU0NSSVBUUyk7XG4gICAgICAgICAgLy8gTWFya2VycyB0aGlzIGxldmVsIHdvdWxkIGRyYXc6IG9uZSBwZXIgKHZpc2libGUgY2x1c3RlciwgYmluKS5cbiAgICAgICAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgICAgICAgY29uc3QgYmluID0gbGV2ZWxzW21dLmJpblNpemU7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXJnZWQuY291bnQ7IGkrKykge1xuICAgICAgICAgICAgaWYgKGhpZGRlbi5oYXMoZ2VuZXNbbWVyZ2VkLmdlbmVbaV1dKSkgY29udGludWU7XG4gICAgICAgICAgICBjb25zdCBjID0gY2x1c3Rlck9mLmdldChtZXJnZWQuZ2VuZVtpXSk7XG4gICAgICAgICAgICBpZiAoYyA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgICAgICAgIHNlZW4uYWRkKGAke2N9fCR7TWF0aC5mbG9vcihtZXJnZWQueFtpXSAvIGJpbil9fCR7TWF0aC5mbG9vcihtZXJnZWQueVtpXSAvIGJpbil9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzZWVuLnNpemUgPD0gYnVkZ2V0IHx8IG0gPj0gbGV2ZWxzLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgIHJldHVybiB7IG1lcmdlZCwgcHg6IG5ldyBGbG9hdDMyQXJyYXkobWVyZ2VkLmNvdW50KSwgbGFkZGVyOiB7IGJhc2VCaW46IGJpbiwgbGV2ZWxzOiAxLCBzdGFydDogYmluIH0gfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbSsrO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKiogVGhlIHNlbGVjdGlvbidzIGNsdXN0ZXJzOiBlYWNoIGdlbmUtdHJlZSBncm91cCdzIHZpc2libGUgZ2VuZXMsIHRoZW4gZWFjaCB1bmdyb3VwZWQgZ2VuZS4gKi9cbiAgcHJpdmF0ZSBzZWxlY3Rpb25DbHVzdGVycyh2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogeyBuYW1lOiBzdHJpbmc7IGdlbmVzOiBzdHJpbmdbXTsgc2xvdDogbnVtYmVyIH1bXSB7XG4gICAgY29uc3QgaGlkZGVuID0gbmV3IFNldCh2aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcyk7XG4gICAgY29uc3Qgc2xvdHMgPSBuZXcgTWFwKHZpZXcudHJhbnNjcmlwdEdlbmVzLm1hcCgoZywgaSkgPT4gW2csIGldKSk7XG4gICAgY29uc3QgdGFrZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBvdXQ6IHsgbmFtZTogc3RyaW5nOyBnZW5lczogc3RyaW5nW107IHNsb3Q6IG51bWJlciB9W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGcgb2Ygdmlldy50cmFuc2NyaXB0R2VuZUdyb3Vwcykge1xuICAgICAgY29uc3QgZ2VuZXMgPSBnLmdlbmVzLmZpbHRlcigoeCkgPT4gc2xvdHMuaGFzKHgpICYmICFoaWRkZW4uaGFzKHgpICYmICF0YWtlbi5oYXMoeCkpO1xuICAgICAgZ2VuZXMuZm9yRWFjaCgoeCkgPT4gdGFrZW4uYWRkKHgpKTtcbiAgICAgIGlmIChnZW5lcy5sZW5ndGgpIG91dC5wdXNoKHsgbmFtZTogZy5uYW1lLCBnZW5lcywgc2xvdDogc2xvdHMuZ2V0KGdlbmVzWzBdKSEgfSk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgZ2VuZSBvZiB2aWV3LnRyYW5zY3JpcHRHZW5lcykge1xuICAgICAgaWYgKCF0YWtlbi5oYXMoZ2VuZSkgJiYgIWhpZGRlbi5oYXMoZ2VuZSkpIG91dC5wdXNoKHsgbmFtZTogZ2VuZSwgZ2VuZXM6IFtnZW5lXSwgc2xvdDogc2xvdHMuZ2V0KGdlbmUpISB9KTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXItZ2VuZSBkZW5zaXR5IGdyaWRzIHN1bW1lZCBmb3IgYGdlbmVzYCwgY2FjaGVkIChhIGNsdXN0ZXIgaXMgYXNrZWQgZm9yIG9uY2UgcGVyIGJpbikuXG4gICAqIEtleWVkIGJ5IGRhdGFzZXQgdG9vOiB0aGlzIG1hbmFnZXIgb3V0bGl2ZXMgYSBkYXRhc2V0LCBhbmQgYW5vdGhlciBtYXkgc2hhcmUgZ2VuZSBuYW1lcy5cbiAgICogTGVhc3QtcmVjZW50bHktVVNFRCBldmljdGlvbiwgc28gdGhlIGNsdXN0ZXJzIGluIHZpZXcgc3RheSBjYWNoZWQ7IGEgZmFpbGVkIHJlcXVlc3QgaXNcbiAgICogZHJvcHBlZCBzbyB0aGUgbmV4dCBwbGFuIGFza3MgYWdhaW4uXG4gICAqL1xuICBwcml2YXRlIGRlbnNpdHlGb3IoZGF0YXNldDogc3RyaW5nLCBnZW5lczogc3RyaW5nW10sIGJpbjogbnVtYmVyKTogUHJvbWlzZTxTcGF0aWFsRGVuc2l0eVJhc3Rlcj4ge1xuICAgIGNvbnN0IGtleSA9IGAke2RhdGFzZXR9fCR7YmlufXwke2dlbmVzLmpvaW4oJywnKX1gO1xuICAgIGxldCBwID0gdGhpcy5kZW5zaXR5Q2FjaGUuZ2V0KGtleSk7XG4gICAgaWYgKCFwKSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gdGhpcy5wb3J0LmdldERlbnNpdHkhKGdlbmVzLCBiaW4pO1xuICAgICAgcmVxdWVzdC5jYXRjaCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmRlbnNpdHlDYWNoZS5nZXQoa2V5KSA9PT0gcmVxdWVzdCkgdGhpcy5kZW5zaXR5Q2FjaGUuZGVsZXRlKGtleSk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuZGVuc2l0eUNhY2hlLnNldChrZXksIHJlcXVlc3QpO1xuICAgICAgcCA9IHJlcXVlc3Q7XG4gICAgfVxuICAgIHJldHVybiBwO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgZ2VuZSBzZWxlY3Rpb24gem9vbWVkIG91dDogb25lIG1hcmtlciBwZXIgY2x1c3RlciBwZXIgYmluLCBmcm9tIHRoZSBwZXItZ2VuZSBkZW5zaXR5XG4gICAqIGdyaWRzLiBUaGUgYmluIHN0YXJ0cyB3aGVyZSBtYXJrZXJzIGFyZSAxNCBweCBhcGFydCBhbmQgZG91YmxlcyB1bnRpbCB0aGUgbWFya2VycyBmaXQgdGhlXG4gICAqIG1heDsgZWFjaCBtYXJrZXIgc2l0cyBhdCB0aGUgY291bnQtd2VpZ2h0ZWQgY2VudHJlIG9mIHRoZSBmaW5lciBncmlkIGluc2lkZSBpdCwgc28gbWFya2Vyc1xuICAgKiBmb2xsb3cgdGhlIHRpc3N1ZSByYXRoZXIgdGhhbiBhIGxhdHRpY2UuXG4gICAqL1xuICBwcml2YXRlIGNsdXN0ZXJEZW5zaXR5Sm9iKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgY2xpcDogQ2xpcFdpbmRvdyxcbiAgICBweFBlclVuaXQ6IG51bWJlcixcbiAgICBzdGFydEJpbjogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBncmlkID0gZGF0YXNldC5kZW5zaXR5IS5ncmlkU2l6ZVswXTtcbiAgICBjb25zdCBjbHVzdGVycyA9IHRoaXMuc2VsZWN0aW9uQ2x1c3RlcnModmlldyk7XG4gICAgbGV0IGZpcnN0ID0gZ3JpZDtcbiAgICB3aGlsZSAoZmlyc3QgPCBzdGFydEJpbiAqIDAuOTk5KSBmaXJzdCAqPSAyO1xuICAgIGNvbnN0IGJ1ZGdldCA9IE1hdGgubWF4KDEsIHZpZXcudHJhbnNjcmlwdEJ1ZGdldCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtpbmQ6ICdnZW5lcycsXG4gICAgICBrZXk6XG4gICAgICAgIGBjbHVzdGVyc3wke2NsdXN0ZXJzLm1hcCgoYykgPT4gYCR7Yy5uYW1lfToke2MuZ2VuZXMuam9pbignKycpfWApLmpvaW4oJzsnKX18JHtidWRnZXR9fCR7Zmlyc3R9fGAgK1xuICAgICAgICBjbGlwLmtleSxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGJpbiA9IGZpcnN0O1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgLy8gVGhlIGZpbmVyIGdyaWQgZ2l2ZXMgZWFjaCBtYXJrZXIgaXRzIGNlbnRyZTsgdGhlIHNlcnZlciBiaW5zIDEsIDIsIDQgb3IgOCBjZWxscy5cbiAgICAgICAgICBjb25zdCBmaW5lID0gTWF0aC5taW4oYmluID49IGdyaWQgKiAyID8gYmluIC8gMiA6IGJpbiwgZ3JpZCAqIDgpO1xuICAgICAgICAgIGNvbnN0IHJhc3RlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChjbHVzdGVycy5tYXAoKGMpID0+IHRoaXMuZGVuc2l0eUZvcihkYXRhc2V0LmlkLCBjLmdlbmVzLCBmaW5lKSkpO1xuICAgICAgICAgIGNvbnN0IG91dCA9IGNsdXN0ZXJNYXJrZXJzKFxuICAgICAgICAgICAgcmFzdGVycyxcbiAgICAgICAgICAgIGNsdXN0ZXJzLm1hcCgoYykgPT4gYy5zbG90KSxcbiAgICAgICAgICAgIGJpbixcbiAgICAgICAgICAgIGNsaXAuYXJvdW5kLFxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKG91dC50aWxlLmNvdW50IDw9IGJ1ZGdldCB8fCBiaW4gPj0gZ3JpZCAqIDIgKiogMTIpIHtcbiAgICAgICAgICAgIGNvbnN0IHB4ID0gZ3JvdXBlZFNpemVzKG91dC50aWxlLndlaWdodCwgYmluICogcHhQZXJVbml0LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSk7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBtZXJnZWQ6IG91dC50aWxlLFxuICAgICAgICAgICAgICBweCxcbiAgICAgICAgICAgICAga2luZDogJ2dlbmVzJyxcbiAgICAgICAgICAgICAgY2x1c3RlcmVkOiB7XG4gICAgICAgICAgICAgICAgZ3JvdXA6IG91dC5ncm91cCxcbiAgICAgICAgICAgICAgICBuYW1lczogY2x1c3RlcnMubWFwKChjKSA9PiBjLm5hbWUpLFxuICAgICAgICAgICAgICAgIGdlbmVzOiBjbHVzdGVycy5tYXAoKGMpID0+IGMuZ2VuZXMpLFxuICAgICAgICAgICAgICAgIGJpbixcbiAgICAgICAgICAgICAgICBvcmlnaW46IHJhc3RlcnNbMF0/Lm1ldGEub3JpZ2luID8/IFswLCAwXSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIGJpbiAqPSAyO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXZlcnkgZ2VuZTogdGhlIHRyYW5zY3JpcHRzIHRoZW1zZWx2ZXMgb25jZSB0aGV5IGZpdCB0aGUgYnVkZ2V0LCBlbHNlIGJpbnMgb2YgdGhlXG4gICAqIGFsbC1nZW5lIHB5cmFtaWQgc2l6ZWQgYnkgaG93IG1hbnkgdHJhbnNjcmlwdHMgZWFjaCBob2xkcy5cbiAgICovXG4gIHByaXZhdGUgYWxsR2VuZXNKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICByZWN0OiBEYXRhUmVjdCxcbiAgICBweFBlclVuaXQ6IG51bWJlcixcbiAgKTogVHJhbnNjcmlwdEpvYiB8IG51bGwge1xuICAgIGNvbnN0IGJpbnMgPSBkYXRhc2V0LnRyYW5zY3JpcHRCaW5zO1xuICAgIGNvbnN0IHRpbGVzID0gZGF0YXNldC50cmFuc2NyaXB0VGlsZXM7XG4gICAgY29uc3QgYm91bmRzID0gYmlucz8uYm91bmRzID8/IHRpbGVzPy5ib3VuZHM7XG4gICAgaWYgKCFib3VuZHMpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHBsYW4gPSBhbGxHZW5lc1BsYW4oe1xuICAgICAgcmVjdCxcbiAgICAgIGJvdW5kcyxcbiAgICAgIHB4UGVyVW5pdCxcbiAgICAgIGJ1ZGdldDogdmlldy50cmFuc2NyaXB0QnVkZ2V0LFxuICAgICAgdG90YWw6IGJpbnM/LmNvdW50ID8/IHRpbGVzPy5jb3VudCA/PyAwLFxuICAgICAgbGV2ZWxzOiBiaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0QmlucyA/IGJpbnMubGV2ZWxzIDogW10sXG4gICAgICBjYW5JbmRpdmlkdWFsOiAhIXRpbGVzLFxuICAgIH0pO1xuXG4gICAgaWYgKHBsYW4ua2luZCA9PT0gJ2luZGl2aWR1YWwnICYmIHRpbGVzKSB7XG4gICAgICBjb25zdCBrZXlzID0gdGlsZXNJblJlY3QocmVjdCwgMCwgdGlsZXMubGV2ZWxzLCB0aWxlcy5ib3VuZHMsIE1BWF9UUkFOU0NSSVBUX1RJTEVTKTtcbiAgICAgIC8vIEVhY2ggdGlsZSBjbGlwcGVkIHRvIHRoZSB2aWV3LCByb3VuZGVkIG91dHdhcmQgdG8gMTAgdW5pdHMgc28gc21hbGwgcGFucyBoaXQgY2FjaGUuXG4gICAgICBjb25zdCByMTAgPSAodjogbnVtYmVyLCB1cDogYm9vbGVhbikgPT4gKHVwID8gTWF0aC5jZWlsKHYgLyAxMCkgOiBNYXRoLmZsb29yKHYgLyAxMCkpICogMTA7XG4gICAgICBjb25zdCBzaXplID0gdGlsZXMubGV2ZWxzWzBdLnRpbGVTaXplO1xuICAgICAgY29uc3QgYm94ZXMgPSBrZXlzLm1hcCgoayk6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdID0+IFtcbiAgICAgICAgTWF0aC5tYXgoay5neCAqIHNpemUsIHIxMChyZWN0LngwLCBmYWxzZSkpLFxuICAgICAgICBNYXRoLm1heChrLmd5ICogc2l6ZSwgcjEwKHJlY3QueTAsIGZhbHNlKSksXG4gICAgICAgIE1hdGgubWluKChrLmd4ICsgMSkgKiBzaXplLCByMTAocmVjdC54MSwgdHJ1ZSkpLFxuICAgICAgICBNYXRoLm1pbigoay5neSArIDEpICogc2l6ZSwgcjEwKHJlY3QueTEsIHRydWUpKSxcbiAgICAgIF0pO1xuICAgICAgY29uc3QgcHhQZXJNaWNyb24gPSBweFBlck1pY3Jvbk9mKGRhdGFzZXQsIHB4UGVyVW5pdCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBraW5kOiAnaW5kaXZpZHVhbCcsXG4gICAgICAgIGtleTogYGFsbHxpbmRpdmlkdWFsfCR7dmlldy50cmFuc2NyaXB0QnVkZ2V0fXwke2JveGVzLm1hcCgoYikgPT4gYi5qb2luKCcsJykpLmpvaW4oJzsnKX1gLFxuICAgICAgICBsb2FkOiBhc3luYyAoY3R4KSA9PiB7XG4gICAgICAgICAgY29uc3QgZ290ID0gYXdhaXQgY3R4LmZldGNoQWxsKFxuICAgICAgICAgICAga2V5cy5tYXAoKGssIGkpID0+ICh7IC4uLmssIGJveDogYm94ZXNbaV0gfSkpLFxuICAgICAgICAgICAgKGspID0+IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZSEoMCwgay5neCwgay5neSwgeyBnZW5lczogW0FMTF9HRU5FU10sIGJveDogay5ib3ggfSksXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBUaGUgcGxhbiBlc3RpbWF0ZWQgdGhlIHZpZXcgZnJvbSB0aGUgZGF0YXNldCdzIGF2ZXJhZ2UgZGVuc2l0eTsgZXhwcmVzc2lvbiBpc1xuICAgICAgICAgIC8vIHVuZXZlbiwgc28gYSBkZW5zZSB2aWV3IGNhbiBob2xkIGZhciBtb3JlLiBSYXRoZXIgdGhhbiBjdXQgdGhlIGV4Y2VzcyBvZmYsIHNob3dcbiAgICAgICAgICAvLyBpdCBncm91cGVkIOKAlCB0aGUgYmluIGxldmVsIHRoZSBwbGFubmVyIHdvdWxkIHBpY2sgaWYgaXQgaGFkIGtub3duLlxuICAgICAgICAgIGNvbnN0IGNhcCA9IE1hdGgubWF4KHZpZXcudHJhbnNjcmlwdEJ1ZGdldCAqIDEuNSwgMSk7XG4gICAgICAgICAgY29uc3QgbG9hZGVkID0gZ290LnJlZHVjZSgobiwgdCkgPT4gbiArIHQuY291bnQsIDApO1xuICAgICAgICAgIGlmIChsb2FkZWQgPiBjYXAgJiYgYmlucyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMpIHtcbiAgICAgICAgICAgIGNvbnN0IGZhbGxiYWNrID0gYWxsR2VuZXNQbGFuKHtcbiAgICAgICAgICAgICAgcmVjdCxcbiAgICAgICAgICAgICAgYm91bmRzLFxuICAgICAgICAgICAgICBweFBlclVuaXQsXG4gICAgICAgICAgICAgIGJ1ZGdldDogdmlldy50cmFuc2NyaXB0QnVkZ2V0LFxuICAgICAgICAgICAgICB0b3RhbDogYmlucy5jb3VudCxcbiAgICAgICAgICAgICAgbGV2ZWxzOiBiaW5zLmxldmVscyxcbiAgICAgICAgICAgICAgY2FuSW5kaXZpZHVhbDogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChmYWxsYmFjay5raW5kID09PSAnYmlucycpIHtcbiAgICAgICAgICAgICAgY29uc3Qgam9iID0gdGhpcy5iaW5zSm9iKHZpZXcsIHJlY3QsIHB4UGVyVW5pdCwgYm91bmRzLCBiaW5zLCBmYWxsYmFjay5sZXZlbCk7XG4gICAgICAgICAgICAgIHJldHVybiB7IC4uLihhd2FpdCBqb2IubG9hZChjdHgpKSwga2luZDogam9iLmtpbmQsIGJpbjogam9iLmJpbiB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBtZXJnZWQgPSBtZXJnZVRyYW5zY3JpcHRUaWxlcyhnb3QsIGNhcCk7XG4gICAgICAgICAgLy8gT25lIHRyYW5zY3JpcHQgcGVyIGVudHJ5OiBldmVyeSBtYXJrZXIgaXMgdGhlIHNhbWUgc2l6ZS5cbiAgICAgICAgICBjb25zdCBweCA9IG5ldyBGbG9hdDMyQXJyYXkobWVyZ2VkLmNvdW50KS5maWxsKHRyYW5zY3JpcHRNYXJrZXJQeCgxLCB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgcHhQZXJNaWNyb24pKTtcbiAgICAgICAgICByZXR1cm4geyBtZXJnZWQsIHB4IH07XG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChwbGFuLmtpbmQgPT09ICdiaW5zJyAmJiBiaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Qmlucykge1xuICAgICAgcmV0dXJuIHRoaXMuYmluc0pvYih2aWV3LCByZWN0LCBweFBlclVuaXQsIGJvdW5kcywgYmlucywgcGxhbi5sZXZlbCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIEJpbnMgb2YgdGhlIGFsbC1nZW5lIHB5cmFtaWQgYXQgYGxldmVsYCwgc2l6ZWQgYnkgaG93IG1hbnkgdHJhbnNjcmlwdHMgZWFjaCBob2xkcy4gKi9cbiAgcHJpdmF0ZSBiaW5zSm9iKFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgcmVjdDogRGF0YVJlY3QsXG4gICAgcHhQZXJVbml0OiBudW1iZXIsXG4gICAgYm91bmRzOiBTcGF0aWFsQm91bmRzLFxuICAgIGJpbnM6IE5vbk51bGxhYmxlPFNwYXRpYWxEYXRhc2V0Wyd0cmFuc2NyaXB0QmlucyddPixcbiAgICBsZXZlbDogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBsdiA9IGJpbnMubGV2ZWxzW2xldmVsXTtcbiAgICBjb25zdCBrZXlzID0gdGlsZXNJblJlY3RGcm9tKFxuICAgICAgYmlucy5vcmlnaW4sXG4gICAgICByZWN0LFxuICAgICAgbGV2ZWwsXG4gICAgICBiaW5zLmxldmVscy5tYXAoKGwpID0+ICh7IHRpbGVTaXplOiBsLnRpbGVTaXplIH0pKSxcbiAgICAgIGJvdW5kcyxcbiAgICAgIE1BWF9CSU5fVElMRVMsXG4gICAgKTtcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2JpbnMnLFxuICAgICAgYmluOiB7IHNpemU6IGx2LmJpblNpemUsIG9yaWdpbjogYmlucy5vcmlnaW4gfSxcbiAgICAgIGtleTogYGFsbHxiaW5zfCR7bGV2ZWx9fCR7dmlldy50cmFuc2NyaXB0QnVkZ2V0fXwke2tleXMubWFwKHRpbGVJZCl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jIChjdHgpID0+IHtcbiAgICAgICAgY29uc3QgZ290ID0gYXdhaXQgY3R4LmZldGNoQWxsKGtleXMsIChrKSA9PiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMhKGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKTtcbiAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXMoZ290LCBNYXRoLm1heCh2aWV3LnRyYW5zY3JpcHRCdWRnZXQgKiAxLjUsIDEpKTtcbiAgICAgICAgcmV0dXJuIHsgbWVyZ2VkLCBweDogZ3JvdXBlZFNpemVzKG1lcmdlZC53ZWlnaHQsIGx2LmJpblNpemUgKiBweFBlclVuaXQsIHZpZXcudHJhbnNjcmlwdFNjYWxlKSB9O1xuICAgICAgfSxcbiAgICB9O1xuICB9XG59XG5cbi8qKlxuICogR3JvdXAgYSBnZW5lIHNlbGVjdGlvbiBmb3IgdGhlIHpvb206IG9uZSBtYXJrZXIgcGVyIGdlbmUtdHJlZSBjbHVzdGVyIChhIGdlbmUgaW4gbm9cbiAqIGNsdXN0ZXIgaXMgaXRzIG93bikgcGVyIGJpbiBvZiB0aGUgcHlyYW1pZCBsYWRkZXIsIHN0YXJ0aW5nIGF0IHRoZSBmaW5lc3QgYmluIHdob3NlXG4gKiBtYXJrZXJzIGFyZSAxNCBweCBhcGFydCBhbmQgc3RlcHBpbmcgdXAgd2hpbGUgdGhlIG1hcmtlcnMgd291bGQgZXhjZWVkIHRoZSBidWRnZXQuXG4gKiBOdWxsIHRvIGRyYXcgZXZlcnkgdHJhbnNjcmlwdDogem9vbWVkIGluLCB3aXRoIHRoZSBzZWxlY3Rpb24gd2l0aGluIHRoZSBidWRnZXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBncm91cFNlbGVjdGlvbihcbiAgdDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlLFxuICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICBsYWRkZXI6IE5vbk51bGxhYmxlPFRyYW5zY3JpcHRMb2FkWydsYWRkZXInXT4sXG4gIHB4UGVyVW5pdDogbnVtYmVyLFxuKTogeyBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTsgcHg6IEZsb2F0MzJBcnJheTsgYmluOiBudW1iZXI7IGdyb3VwOiBJbnQzMkFycmF5OyBuYW1lczogc3RyaW5nW10gfSB8IG51bGwge1xuICBjb25zdCBidWRnZXQgPSBNYXRoLm1heCgxLCB2aWV3LnRyYW5zY3JpcHRCdWRnZXQpO1xuICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICBjb25zdCBncm91cHMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzO1xuICBjb25zdCBuYW1lcyA9IFsuLi5ncm91cHMubWFwKChnKSA9PiBnLm5hbWUpLCAuLi5nZW5lc107XG4gIGNvbnN0IGNsdXN0ZXJPZiA9IGdlbmVzLm1hcCgoZ2VuZSwgc2xvdCkgPT4ge1xuICAgIGNvbnN0IGcgPSBncm91cHMuZmluZEluZGV4KCh4KSA9PiB4LmdlbmVzLmluY2x1ZGVzKGdlbmUpKTtcbiAgICByZXR1cm4gZyA+PSAwID8gZyA6IGdyb3Vwcy5sZW5ndGggKyBzbG90O1xuICB9KTtcbiAgY29uc3Qga2V5T2YgPSAoc2xvdDogbnVtYmVyKSA9PiBjbHVzdGVyT2Zbc2xvdF0gPz8gZ3JvdXBzLmxlbmd0aCArIHNsb3Q7XG4gIGxldCBiaW4gPSBsYWRkZXIuc3RhcnQ7XG4gIGlmIChiaW4gPT09IG51bGwpIHtcbiAgICAvLyBFdmVyeSB0cmFuc2NyaXB0LCBpZiB0aGV5IGZpdCB0aGUgbWF4IGFuZCBub25lIHdhcyBjdXQgb2ZmIGF0IHRoZSBjYXAuXG4gICAgaWYgKHQuY291bnQgPD0gYnVkZ2V0ICYmIHQuY291bnQgPCBNQVhfVFJBTlNDUklQVFMpIHJldHVybiBudWxsO1xuICAgIGJpbiA9IGxhZGRlci5iYXNlQmluO1xuICB9XG4gIGNvbnN0IHRvcCA9IGxhZGRlci5iYXNlQmluICogMiAqKiAobGFkZGVyLmxldmVscyAtIDEpO1xuICBsZXQgZ3JvdXBlZCA9IGdyb3VwVHJhbnNjcmlwdHModCwgYmluLCBrZXlPZik7XG4gIC8vIE92ZXIgdGhlIG1heDogY29tYmluZSBpbnRvIGxhcmdlciBtYXJrZXJzLCBhIGxldmVsIGF0IGEgdGltZS5cbiAgd2hpbGUgKGdyb3VwZWQudGlsZS5jb3VudCA+IGJ1ZGdldCAmJiBiaW4gPCB0b3ApIHtcbiAgICBiaW4gKj0gMjtcbiAgICBncm91cGVkID0gZ3JvdXBUcmFuc2NyaXB0cyh0LCBiaW4sIGtleU9mKTtcbiAgfVxuICBjb25zdCBweCA9IGdyb3VwZWRTaXplcyhncm91cGVkLnRpbGUud2VpZ2h0LCBiaW4gKiBweFBlclVuaXQsIHZpZXcudHJhbnNjcmlwdFNjYWxlKTtcbiAgcmV0dXJuIHsgbWVyZ2VkOiBncm91cGVkLnRpbGUsIHB4LCBiaW4sIGdyb3VwOiBncm91cGVkLmdyb3VwLCBuYW1lcyB9O1xufVxuXG4vKiogU2NyZWVuIHNpemVzIG9mIGdyb3VwZWQgbWFya2VyczogYnkgd2VpZ2h0IGFnYWluc3QgdGhlIDk1dGgtcGVyY2VudGlsZSB3ZWlnaHQsIG92ZXIgYGJpblB4YC4gKi9cbmZ1bmN0aW9uIGdyb3VwZWRTaXplcyh3ZWlnaHQ6IFVpbnQzMkFycmF5LCBiaW5QeDogbnVtYmVyLCBzY2FsZTogbnVtYmVyKTogRmxvYXQzMkFycmF5IHtcbiAgY29uc3QgcmVmQ291bnQgPSBxdWFudGlsZU9mKHdlaWdodCwgMC45NSk7XG4gIHJldHVybiBGbG9hdDMyQXJyYXkuZnJvbSh3ZWlnaHQsICh3KSA9PiBncm91cGVkTWFya2VyUHgodywgcmVmQ291bnQsIGJpblB4LCBzY2FsZSkpO1xufVxuXG4vKiogV2hhdCBhIGdlbmUgc2VsZWN0aW9uJ3Mgam9iIGZldGNoZXMgYW5kIGNsaXBzIHRvOiB0aGUgdmlldyBhbmQgYSBxdWFydGVyLXZpZXcgbWFyZ2luIGVhY2ggc2lkZSxcbiAqICBzbyBhIHNtYWxsIHBhbiBuZWVkcyBub3RoaW5nIG5ldy4gKi9cbmludGVyZmFjZSBDbGlwV2luZG93IHtcbiAgYXJvdW5kOiBEYXRhUmVjdDtcbiAgLyoqIFRoZSB3aW5kb3cgaW4gcXVhcnRlci12aWV3IHN0ZXBzLCBmb3IgYSBqb2Iga2V5OiBhIHBhbiBwYXN0IHRoZSBtYXJnaW4gcmUtY2xpcHMuICovXG4gIGtleTogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBjbGlwV2luZG93KHJlY3Q6IERhdGFSZWN0KTogQ2xpcFdpbmRvdyB7XG4gIGNvbnN0IG14ID0gKHJlY3QueDEgLSByZWN0LngwKSAqIDAuMjU7XG4gIGNvbnN0IG15ID0gKHJlY3QueTEgLSByZWN0LnkwKSAqIDAuMjU7XG4gIHJldHVybiB7XG4gICAgYXJvdW5kOiB7IHgwOiByZWN0LngwIC0gbXgsIHkwOiByZWN0LnkwIC0gbXksIHgxOiByZWN0LngxICsgbXgsIHkxOiByZWN0LnkxICsgbXkgfSxcbiAgICBrZXk6IGAke01hdGguZmxvb3IocmVjdC54MCAvIChteCB8fCAxKSl9LCR7TWF0aC5mbG9vcihyZWN0LnkwIC8gKG15IHx8IDEpKX1gLFxuICB9O1xufVxuXG4vKiogUGh5c2ljYWwgbWFya2VyIHNpemUgbmVlZHMgwrVtOyB1bmRlZmluZWQgd2hlbiB0aGUgZGF0YXNldCdzIHVuaXQgaXMgdW5rbm93bi4gKi9cbmZ1bmN0aW9uIHB4UGVyTWljcm9uT2YoZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHB4UGVyVW5pdDogbnVtYmVyKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIGRhdGFzZXQubWljcm9uc1BlclVuaXQgPyBweFBlclVuaXQgLyBkYXRhc2V0Lm1pY3JvbnNQZXJVbml0IDogdW5kZWZpbmVkO1xufVxuIl19
|