@jax-data-science/sci-image-visualizer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +404 -0
- package/esm2022/index.mjs +52 -0
- package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
- package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
- package/esm2022/lib/contracts/display-types.mjs +8 -0
- package/esm2022/lib/contracts/image.contract.mjs +11 -0
- package/esm2022/lib/contracts/intensity.mjs +28 -0
- package/esm2022/lib/contracts/plot-type.mjs +112 -0
- package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
- package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
- package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
- package/esm2022/lib/contracts/sam.contract.mjs +12 -0
- package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
- package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
- package/esm2022/lib/contracts/viz-config.mjs +3 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
- package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
- package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
- package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
- package/esm2022/lib/models/bezier.mjs +120 -0
- package/esm2022/lib/models/class-preset.mjs +46 -0
- package/esm2022/lib/models/geometry.mjs +198 -0
- package/esm2022/lib/models/region.mjs +166 -0
- package/esm2022/lib/models/shape.mjs +53 -0
- package/esm2022/lib/plot.utilities.mjs +693 -0
- package/esm2022/lib/processing/image-converter.service.mjs +90 -0
- package/esm2022/lib/processing/image-crop.mjs +62 -0
- package/esm2022/lib/processing/processing-image.mjs +50 -0
- package/esm2022/lib/provide-visualization.mjs +63 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
- package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
- package/esm2022/lib/region-ops.service.mjs +301 -0
- package/esm2022/lib/render-orchestrator.mjs +87 -0
- package/esm2022/lib/routing-visualizer.service.mjs +533 -0
- package/esm2022/lib/store/class-color.util.mjs +52 -0
- package/esm2022/lib/store/region-store.service.mjs +1029 -0
- package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
- package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
- package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
- package/esm2022/lib/visualization.module.mjs +162 -0
- package/esm2022/lib/visualizer.component.mjs +1597 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
- package/fesm2022/mask.worker.js +989 -0
- package/fesm2022/onnx-sam.worker.js +202 -0
- package/index.d.ts +39 -0
- package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
- package/lib/contracts/capabilities.contract.d.ts +30 -0
- package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
- package/lib/contracts/colormap-lut.d.ts +21 -0
- package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
- package/lib/contracts/display-types.d.ts +41 -0
- package/lib/contracts/image.contract.d.ts +72 -0
- package/lib/contracts/intensity.d.ts +18 -0
- package/lib/contracts/plot-type.d.ts +108 -0
- package/lib/contracts/ports/image-state.port.d.ts +29 -0
- package/lib/contracts/ports/preferences.port.d.ts +19 -0
- package/lib/contracts/ports/region-io.port.d.ts +29 -0
- package/lib/contracts/ports/tile-access.port.d.ts +27 -0
- package/lib/contracts/region-editor-api.contract.d.ts +83 -0
- package/lib/contracts/region-overlay.contract.d.ts +47 -0
- package/lib/contracts/region-store.contract.d.ts +74 -0
- package/lib/contracts/sam.contract.d.ts +98 -0
- package/lib/contracts/toolbar-config.d.ts +24 -0
- package/lib/contracts/visualizer.contract.d.ts +346 -0
- package/lib/contracts/viz-config.d.ts +25 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
- package/lib/implementations/base-store-visualizer.d.ts +71 -0
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
- package/lib/implementations/osd/display-pipeline.d.ts +47 -0
- package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
- package/lib/implementations/osd/osd-coords.d.ts +16 -0
- package/lib/implementations/osd/osd-lib.d.ts +19 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
- package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
- package/lib/implementations/osd/slice-cache.d.ts +161 -0
- package/lib/implementations/osd/tile-client.d.ts +32 -0
- package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
- package/lib/implementations/plotly/plotly.service.d.ts +594 -0
- package/lib/implementations/simple-slice-access.service.d.ts +64 -0
- package/lib/models/bezier.d.ts +59 -0
- package/lib/models/class-preset.d.ts +39 -0
- package/lib/models/geometry.d.ts +66 -0
- package/lib/models/region.d.ts +132 -0
- package/lib/models/shape.d.ts +44 -0
- package/lib/plot.utilities.d.ts +107 -0
- package/lib/processing/image-converter.service.d.ts +28 -0
- package/lib/processing/image-crop.d.ts +18 -0
- package/lib/processing/processing-image.d.ts +17 -0
- package/lib/provide-visualization.d.ts +34 -0
- package/lib/region-editor/mask-raster.d.ts +61 -0
- package/lib/region-editor/mask-worker.d.ts +7 -0
- package/lib/region-editor/region-editor.component.d.ts +305 -0
- package/lib/region-ops.service.d.ts +92 -0
- package/lib/render-orchestrator.d.ts +59 -0
- package/lib/routing-visualizer.service.d.ts +227 -0
- package/lib/store/class-color.util.d.ts +26 -0
- package/lib/store/region-store.service.d.ts +315 -0
- package/lib/store/visualizer-store.service.d.ts +123 -0
- package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
- package/lib/toolbar/crop/slide-crop.d.ts +30 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
- package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
- package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
- package/lib/toolbar/toolbar.component.d.ts +167 -0
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
- package/lib/toolbar/wand/wand.service.d.ts +133 -0
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
- package/lib/visualization.module.d.ts +45 -0
- package/lib/visualizer.component.d.ts +378 -0
- package/package.json +73 -0
- package/src/lib/assets/3d-coordinates.svg +49 -0
- package/src/lib/assets/cells.svg +1 -0
- package/src/lib/assets/click.svg +1 -0
- package/src/lib/assets/colormap-luts.json +1 -0
- package/src/lib/assets/contour.svg +48 -0
- package/src/lib/assets/cube-3d.svg +1 -0
- package/src/lib/assets/edit-selection-white.svg +47 -0
- package/src/lib/assets/heatmap.svg +1 -0
- package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
- package/src/lib/assets/icons/colormap-accent.png +0 -0
- package/src/lib/assets/icons/colormap-afmhot.png +0 -0
- package/src/lib/assets/icons/colormap-autumn.png +0 -0
- package/src/lib/assets/icons/colormap-berlin.png +0 -0
- package/src/lib/assets/icons/colormap-binary.png +0 -0
- package/src/lib/assets/icons/colormap-blackbody.png +0 -0
- package/src/lib/assets/icons/colormap-bluered.png +0 -0
- package/src/lib/assets/icons/colormap-blues.png +0 -0
- package/src/lib/assets/icons/colormap-bone.png +0 -0
- package/src/lib/assets/icons/colormap-brbg.png +0 -0
- package/src/lib/assets/icons/colormap-brg.png +0 -0
- package/src/lib/assets/icons/colormap-bugn.png +0 -0
- package/src/lib/assets/icons/colormap-bupu.png +0 -0
- package/src/lib/assets/icons/colormap-bwr.png +0 -0
- package/src/lib/assets/icons/colormap-cividis.png +0 -0
- package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
- package/src/lib/assets/icons/colormap-cool.png +0 -0
- package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
- package/src/lib/assets/icons/colormap-copper.png +0 -0
- package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
- package/src/lib/assets/icons/colormap-dark2.png +0 -0
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-electric.png +0 -0
- package/src/lib/assets/icons/colormap-flag.png +0 -0
- package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
- package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
- package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
- package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
- package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
- package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
- package/src/lib/assets/icons/colormap-gnbu.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
- package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
- package/src/lib/assets/icons/colormap-gray.png +0 -0
- package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greens.png +0 -0
- package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
- package/src/lib/assets/icons/colormap-greys.png +0 -0
- package/src/lib/assets/icons/colormap-hot.png +0 -0
- package/src/lib/assets/icons/colormap-hsv.png +0 -0
- package/src/lib/assets/icons/colormap-inferno.png +0 -0
- package/src/lib/assets/icons/colormap-jet.png +0 -0
- package/src/lib/assets/icons/colormap-magma.png +0 -0
- package/src/lib/assets/icons/colormap-managua.png +0 -0
- package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
- package/src/lib/assets/icons/colormap-ocean.png +0 -0
- package/src/lib/assets/icons/colormap-oranges.png +0 -0
- package/src/lib/assets/icons/colormap-orrd.png +0 -0
- package/src/lib/assets/icons/colormap-pastel2.png +0 -0
- package/src/lib/assets/icons/colormap-picnic.png +0 -0
- package/src/lib/assets/icons/colormap-pink.png +0 -0
- package/src/lib/assets/icons/colormap-piyg.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-plasma.png +0 -0
- package/src/lib/assets/icons/colormap-portland.png +0 -0
- package/src/lib/assets/icons/colormap-prgn.png +0 -0
- package/src/lib/assets/icons/colormap-prism.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/icons/colormap-pubugn.png +0 -0
- package/src/lib/assets/icons/colormap-puor.png +0 -0
- package/src/lib/assets/icons/colormap-purd.png +0 -0
- package/src/lib/assets/icons/colormap-purples.png +0 -0
- package/src/lib/assets/icons/colormap-rainbow.png +0 -0
- package/src/lib/assets/icons/colormap-rdbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdgy.png +0 -0
- package/src/lib/assets/icons/colormap-rdpu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
- package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
- package/src/lib/assets/icons/colormap-reds.png +0 -0
- package/src/lib/assets/icons/colormap-seismic.png +0 -0
- package/src/lib/assets/icons/colormap-set1.png +0 -0
- package/src/lib/assets/icons/colormap-set2.png +0 -0
- package/src/lib/assets/icons/colormap-set3.png +0 -0
- package/src/lib/assets/icons/colormap-spectral.png +0 -0
- package/src/lib/assets/icons/colormap-spring.png +0 -0
- package/src/lib/assets/icons/colormap-summer.png +0 -0
- package/src/lib/assets/icons/colormap-tab10.png +0 -0
- package/src/lib/assets/icons/colormap-tab20.png +0 -0
- package/src/lib/assets/icons/colormap-tab20b.png +0 -0
- package/src/lib/assets/icons/colormap-tab20c.png +0 -0
- package/src/lib/assets/icons/colormap-terrain.png +0 -0
- package/src/lib/assets/icons/colormap-turbo.png +0 -0
- package/src/lib/assets/icons/colormap-twilight.png +0 -0
- package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
- package/src/lib/assets/icons/colormap-vanimo.png +0 -0
- package/src/lib/assets/icons/colormap-viridis.png +0 -0
- package/src/lib/assets/icons/colormap-winter.png +0 -0
- package/src/lib/assets/icons/colormap-wistia.png +0 -0
- package/src/lib/assets/icons/colormap-ylgn.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
- package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
- package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
- package/src/lib/assets/invert.svg +1 -0
- package/src/lib/assets/isosurface.svg +7 -0
- package/src/lib/assets/mask.svg +1 -0
- package/src/lib/assets/paintbrush.svg +1 -0
- package/src/lib/assets/picture-segmentation.svg +43 -0
- package/src/lib/assets/polygon-vertices.svg +13 -0
- package/src/lib/assets/polyline.svg +3 -0
- package/src/lib/assets/redo.svg +39 -0
- package/src/lib/assets/region-editor.svg +37 -0
- package/src/lib/assets/region-move.svg +7 -0
- package/src/lib/assets/smooth.svg +56 -0
- package/src/lib/assets/spline-chart.svg +7 -0
- package/src/lib/assets/surface.svg +37 -0
- package/src/lib/assets/test/download-379.svg +1 -0
- package/src/lib/assets/test/download-98.svg +1 -0
- package/src/lib/assets/test/json-1.svg +1 -0
- package/src/lib/assets/test/load-53.svg +1 -0
- package/src/lib/assets/test/mask-44.svg +1 -0
- package/src/lib/assets/test/mask-download-44.svg +15 -0
- package/src/lib/assets/test/mask-save-44.svg +11 -0
- package/src/lib/assets/test/overlay-1.svg +1 -0
- package/src/lib/assets/test/overlay-4.svg +1 -0
- package/src/lib/assets/test/region-26.svg +1 -0
- package/src/lib/assets/test/save-56.svg +1 -0
- package/src/lib/assets/test/upload-43.svg +1 -0
- package/src/lib/assets/to-bezier.svg +15 -0
- package/src/lib/assets/to-polygon.svg +11 -0
- package/src/lib/assets/undo.svg +38 -0
- package/src/lib/assets/vertex-add.svg +12 -0
- package/src/lib/assets/vertex-delete.svg +12 -0
- package/src/lib/assets/wand.svg +54 -0
- package/src/lib/assets/zoom-box.svg +10 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { WandService } from './wand.service';
|
|
3
|
+
import { masksOverlap, unionMasks } from '../../models/geometry';
|
|
4
|
+
import { Region, Polygon } from '../../models/region';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "./wand.service";
|
|
7
|
+
/**
|
|
8
|
+
* The wand drawing tool. Owns its own canvas overlay, mouse handlers, and
|
|
9
|
+
* stroke accumulator. Reads/writes the shape list via the WandToolHost
|
|
10
|
+
* interface so it stays decoupled from PlotlyService internals.
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle: PlotlyService injects this service, calls `bindHost(this)` once
|
|
13
|
+
* during its own construction, then calls `setMode(true | false, options)` to
|
|
14
|
+
* activate/deactivate the tool.
|
|
15
|
+
*/
|
|
16
|
+
export class WandToolService {
|
|
17
|
+
constructor(wandService) {
|
|
18
|
+
this.wandService = wandService;
|
|
19
|
+
this.overlay = null;
|
|
20
|
+
this.active = false;
|
|
21
|
+
/**
|
|
22
|
+
* Accumulated wand region. Every per-tick patch mask is OR'd into `mask`
|
|
23
|
+
* over a bbox that grows with the stroke, so the region keeps expanding
|
|
24
|
+
* as the user drags. The accumulator persists across mouseup/mousedown so
|
|
25
|
+
* that subsequent strokes extend the *same* region — matching QuPath's
|
|
26
|
+
* brush behaviour where the active annotation stays editable until the
|
|
27
|
+
* user switches tool.
|
|
28
|
+
*/
|
|
29
|
+
this.stroke = null;
|
|
30
|
+
/** Id of the region this wand stroke is editing (null = a fresh region). */
|
|
31
|
+
this.strokeRegionId = null;
|
|
32
|
+
/** Readback ratio/origin signature the active stroke's matrix coords are tied to; a change
|
|
33
|
+
* (zoom/pan) invalidates the stroke so it isn't re-committed at a different scale (jit-ui#102). */
|
|
34
|
+
this.strokeRatioSig = null;
|
|
35
|
+
this.dragging = false;
|
|
36
|
+
this.options = {};
|
|
37
|
+
this.boundMouseDown = (e) => this.onMouseDown(e);
|
|
38
|
+
this.boundMouseMove = (e) => this.onMouseMove(e);
|
|
39
|
+
this.boundMouseUp = (e) => this.onMouseUp(e);
|
|
40
|
+
}
|
|
41
|
+
/** Wire the tool to its host. Must be called once before `setMode(true)`. */
|
|
42
|
+
bindHost(host) {
|
|
43
|
+
this.host = host;
|
|
44
|
+
}
|
|
45
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
46
|
+
/** Toggle the wand on/off. */
|
|
47
|
+
setMode(active, options = {}) {
|
|
48
|
+
this.active = active;
|
|
49
|
+
this.options = options;
|
|
50
|
+
if (active) {
|
|
51
|
+
this.createOverlay();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.destroyOverlay();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Merge new options (e.g. live sensitivity slider updates). */
|
|
58
|
+
setOptions(options) {
|
|
59
|
+
this.options = { ...this.options, ...options };
|
|
60
|
+
}
|
|
61
|
+
/** Drop the active wand region so the next click starts a new one. */
|
|
62
|
+
clearActiveRegion() {
|
|
63
|
+
this.resetStroke();
|
|
64
|
+
}
|
|
65
|
+
// ── Overlay lifecycle ───────────────────────────────────────────────
|
|
66
|
+
createOverlay() {
|
|
67
|
+
const plotEl = this.host.getOverlayContainer();
|
|
68
|
+
if (!plotEl || this.overlay)
|
|
69
|
+
return;
|
|
70
|
+
const canvas = document.createElement('canvas');
|
|
71
|
+
canvas.style.position = 'absolute';
|
|
72
|
+
canvas.style.top = '0';
|
|
73
|
+
canvas.style.left = '0';
|
|
74
|
+
canvas.style.width = '100%';
|
|
75
|
+
canvas.style.height = '100%';
|
|
76
|
+
canvas.style.cursor = 'crosshair';
|
|
77
|
+
canvas.style.zIndex = '100';
|
|
78
|
+
canvas.width = plotEl.offsetWidth;
|
|
79
|
+
canvas.height = plotEl.offsetHeight;
|
|
80
|
+
plotEl.appendChild(canvas);
|
|
81
|
+
this.overlay = canvas;
|
|
82
|
+
canvas.addEventListener('mousedown', this.boundMouseDown);
|
|
83
|
+
canvas.addEventListener('mousemove', this.boundMouseMove);
|
|
84
|
+
canvas.addEventListener('mouseup', this.boundMouseUp);
|
|
85
|
+
canvas.addEventListener('mouseleave', this.boundMouseUp);
|
|
86
|
+
}
|
|
87
|
+
destroyOverlay() {
|
|
88
|
+
if (!this.overlay)
|
|
89
|
+
return;
|
|
90
|
+
this.overlay.removeEventListener('mousedown', this.boundMouseDown);
|
|
91
|
+
this.overlay.removeEventListener('mousemove', this.boundMouseMove);
|
|
92
|
+
this.overlay.removeEventListener('mouseup', this.boundMouseUp);
|
|
93
|
+
this.overlay.removeEventListener('mouseleave', this.boundMouseUp);
|
|
94
|
+
this.overlay.remove();
|
|
95
|
+
this.overlay = null;
|
|
96
|
+
this.resetStroke();
|
|
97
|
+
}
|
|
98
|
+
onMouseDown(e) {
|
|
99
|
+
if (e.button !== 0)
|
|
100
|
+
return;
|
|
101
|
+
this.dragging = true;
|
|
102
|
+
this.applyAtClient(e, true);
|
|
103
|
+
}
|
|
104
|
+
onMouseMove(e) {
|
|
105
|
+
if (!this.dragging)
|
|
106
|
+
return;
|
|
107
|
+
if ((e.buttons & 1) === 0) {
|
|
108
|
+
this.dragging = false;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.applyAtClient(e, false);
|
|
112
|
+
}
|
|
113
|
+
onMouseUp(_) {
|
|
114
|
+
// Stop accumulating from this drag, but keep the region alive so the
|
|
115
|
+
// next mousedown extends it instead of starting fresh.
|
|
116
|
+
this.dragging = false;
|
|
117
|
+
}
|
|
118
|
+
resetStroke() {
|
|
119
|
+
this.stroke = null;
|
|
120
|
+
this.strokeRegionId = null;
|
|
121
|
+
this.dragging = false;
|
|
122
|
+
}
|
|
123
|
+
// ── Per-tick stroke logic ───────────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Sample the cached image at the click location, OR (or AND-NOT) the
|
|
126
|
+
* wand's per-tick patch mask into the active region's bbox-relative mask,
|
|
127
|
+
* re-trace the boundary, and update the in-progress shape — matching
|
|
128
|
+
* QuPath's additive brush/wand behaviour. Shift = erase. Cmd/Ctrl =
|
|
129
|
+
* exact-match flood fill.
|
|
130
|
+
*/
|
|
131
|
+
applyAtClient(e, isStart = false) {
|
|
132
|
+
if (!this.overlay)
|
|
133
|
+
return;
|
|
134
|
+
const cached = this.host.getCachedImageData();
|
|
135
|
+
if (!cached || cached.frames.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
// The current regions (neutral model). Mutated locally across this tick and
|
|
138
|
+
// committed once via host.setRegions().
|
|
139
|
+
const regions = this.host.getRegions();
|
|
140
|
+
const transform = this.host.getCoordinateTransform();
|
|
141
|
+
if (!transform.isReady())
|
|
142
|
+
return;
|
|
143
|
+
const { x: dataX, y: dataY } = transform.clientToData(e.clientX, e.clientY);
|
|
144
|
+
if (!Number.isFinite(dataX) || !Number.isFinite(dataY))
|
|
145
|
+
return;
|
|
146
|
+
// ratios = [xRatio, yRatio] from both backends. Use the X ratio for the
|
|
147
|
+
// column and the Y ratio for the row: they differ when the pixel aspect
|
|
148
|
+
// isn't 1:1 (e.g. a non-square OSD viewport), and reusing ratios[0] for
|
|
149
|
+
// both would distort the sampled region vertically. Fall back to the X
|
|
150
|
+
// ratio if only one was supplied.
|
|
151
|
+
const rx = cached.ratios[0] || 1;
|
|
152
|
+
const ry = cached.ratios[1] || cached.ratios[0] || 1;
|
|
153
|
+
const ox = cached.originX ?? 0;
|
|
154
|
+
const oy = cached.originY ?? 0;
|
|
155
|
+
// The stroke accumulator is in matrix (viewport-pixel) coordinates tied to the readback's
|
|
156
|
+
// ratio/origin. If the view changed (zoom/pan) since the stroke was built, those coords no
|
|
157
|
+
// longer mean the same thing — re-committing would rescale the region by the zoom factor
|
|
158
|
+
// (jit-ui#102). Drop the stale stroke so a fresh one is built at the current view.
|
|
159
|
+
const sig = `${rx},${ry},${ox},${oy}`;
|
|
160
|
+
if (this.stroke && this.strokeRatioSig !== sig) {
|
|
161
|
+
this.stroke = null;
|
|
162
|
+
this.strokeRegionId = null;
|
|
163
|
+
}
|
|
164
|
+
this.strokeRatioSig = sig;
|
|
165
|
+
const matrixX = (dataX - ox) / rx;
|
|
166
|
+
const matrixY = (dataY - oy) / ry;
|
|
167
|
+
if (matrixX < 0 || matrixX >= cached.width)
|
|
168
|
+
return;
|
|
169
|
+
if (matrixY < 0 || matrixY >= cached.height)
|
|
170
|
+
return;
|
|
171
|
+
const frameIdx = this.host.getActiveFrameIndex();
|
|
172
|
+
const frame = cached.frames[frameIdx] ?? cached.frames[0];
|
|
173
|
+
const wandImage = {
|
|
174
|
+
data: frame,
|
|
175
|
+
width: cached.width,
|
|
176
|
+
height: cached.height,
|
|
177
|
+
isGrayscale: cached.isGrayscale,
|
|
178
|
+
};
|
|
179
|
+
// Shift = erase (subtract pixels from an existing region).
|
|
180
|
+
// Cmd/Ctrl alone = simple flood fill (no smoothing/threshold).
|
|
181
|
+
const erase = e.shiftKey;
|
|
182
|
+
const opts = {
|
|
183
|
+
...this.options,
|
|
184
|
+
simpleMode: this.options.simpleMode || ((e.metaKey || e.ctrlKey) && !erase),
|
|
185
|
+
};
|
|
186
|
+
// If this is the first tick of a new drag and the click is NOT inside the
|
|
187
|
+
// current accumulator and NOT inside any existing path-shape, drop the old
|
|
188
|
+
// stroke so a brand-new region starts here. Without this, the accumulator
|
|
189
|
+
// bbox grows to span both areas and `maskToPolygon` keeps only the largest
|
|
190
|
+
// connected blob — making the new click appear to do nothing.
|
|
191
|
+
if (isStart && !erase && this.stroke && !this.pointInStroke(matrixX, matrixY)) {
|
|
192
|
+
// Will fall through to tryAdoptShapeAt below; if that also misses, a
|
|
193
|
+
// fresh stroke is created from the patch.
|
|
194
|
+
this.stroke = null;
|
|
195
|
+
this.strokeRegionId = null;
|
|
196
|
+
}
|
|
197
|
+
const patch = this.wandService.computePatchMask(wandImage, matrixX, matrixY, opts);
|
|
198
|
+
if (!patch)
|
|
199
|
+
return;
|
|
200
|
+
const W = patch.size;
|
|
201
|
+
const half = (W - 1) / 2;
|
|
202
|
+
const px0 = Math.round(matrixX) - half;
|
|
203
|
+
const py0 = Math.round(matrixY) - half;
|
|
204
|
+
const px1 = px0 + W;
|
|
205
|
+
const py1 = py0 + W;
|
|
206
|
+
// If there's no active wand region, see if the click landed on an
|
|
207
|
+
// existing path-shape — adopt it so this stroke extends (or erases
|
|
208
|
+
// from) it instead of creating a new region.
|
|
209
|
+
if (!this.stroke) {
|
|
210
|
+
this.tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached);
|
|
211
|
+
}
|
|
212
|
+
// Erasing requires an existing region. Shift-clicking empty space is a
|
|
213
|
+
// no-op — we don't create a region only to immediately delete from it.
|
|
214
|
+
if (erase && !this.stroke)
|
|
215
|
+
return;
|
|
216
|
+
// Grow the region's accumulated mask only when adding. Erasing never
|
|
217
|
+
// expands the region beyond its current bbox.
|
|
218
|
+
if (!this.stroke) {
|
|
219
|
+
const bx = Math.max(0, px0);
|
|
220
|
+
const by = Math.max(0, py0);
|
|
221
|
+
const bx1 = Math.min(cached.width, px1);
|
|
222
|
+
const by1 = Math.min(cached.height, py1);
|
|
223
|
+
const bw = Math.max(0, bx1 - bx);
|
|
224
|
+
const bh = Math.max(0, by1 - by);
|
|
225
|
+
if (bw === 0 || bh === 0)
|
|
226
|
+
return;
|
|
227
|
+
this.stroke = { bx, by, bw, bh, mask: new Uint8Array(bw * bh) };
|
|
228
|
+
}
|
|
229
|
+
else if (!erase) {
|
|
230
|
+
// Don't clamp the accumulator to the viewport: an adopted region may extend off-screen, and
|
|
231
|
+
// clamping here would discard its off-screen part when the stroke grows (jit-ui#102).
|
|
232
|
+
const bx = Math.min(this.stroke.bx, px0);
|
|
233
|
+
const by = Math.min(this.stroke.by, py0);
|
|
234
|
+
const bx1 = Math.max(this.stroke.bx + this.stroke.bw, px1);
|
|
235
|
+
const by1 = Math.max(this.stroke.by + this.stroke.bh, py1);
|
|
236
|
+
const bw = bx1 - bx;
|
|
237
|
+
const bh = by1 - by;
|
|
238
|
+
if (bw !== this.stroke.bw || bh !== this.stroke.bh || bx !== this.stroke.bx || by !== this.stroke.by) {
|
|
239
|
+
// Reallocate the larger mask and copy the previous mask into it.
|
|
240
|
+
const next = new Uint8Array(bw * bh);
|
|
241
|
+
const dx = this.stroke.bx - bx;
|
|
242
|
+
const dy = this.stroke.by - by;
|
|
243
|
+
for (let row = 0; row < this.stroke.bh; row++) {
|
|
244
|
+
const srcOff = row * this.stroke.bw;
|
|
245
|
+
const dstOff = (row + dy) * bw + dx;
|
|
246
|
+
next.set(this.stroke.mask.subarray(srcOff, srcOff + this.stroke.bw), dstOff);
|
|
247
|
+
}
|
|
248
|
+
this.stroke = { bx, by, bw, bh, mask: next };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Apply the patch: OR (add) or AND-NOT (erase).
|
|
252
|
+
const stroke = this.stroke;
|
|
253
|
+
for (let py = 0; py < W; py++) {
|
|
254
|
+
const iy = py0 + py;
|
|
255
|
+
const my = iy - stroke.by;
|
|
256
|
+
if (my < 0 || my >= stroke.bh)
|
|
257
|
+
continue;
|
|
258
|
+
const srcRow = py * W;
|
|
259
|
+
const dstRow = my * stroke.bw;
|
|
260
|
+
for (let px = 0; px < W; px++) {
|
|
261
|
+
if (!patch.mask[srcRow + px])
|
|
262
|
+
continue;
|
|
263
|
+
const ix = px0 + px;
|
|
264
|
+
const mx = ix - stroke.bx;
|
|
265
|
+
if (mx < 0 || mx >= stroke.bw)
|
|
266
|
+
continue;
|
|
267
|
+
if (erase)
|
|
268
|
+
stroke.mask[dstRow + mx] = 0;
|
|
269
|
+
else
|
|
270
|
+
stroke.mask[dstRow + mx] = 1;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!erase) {
|
|
274
|
+
// If the grown stroke now overlaps another path-shape, fold those
|
|
275
|
+
// shapes into this one and drop them — matching QuPath's
|
|
276
|
+
// merge-on-touch behaviour.
|
|
277
|
+
this.mergeOverlappingShapes(regions, rx, ry, cached);
|
|
278
|
+
}
|
|
279
|
+
// Trace the union boundary in image-pixel coords.
|
|
280
|
+
const stroke2 = this.stroke;
|
|
281
|
+
const poly = this.wandService.maskToPolygon(stroke2.mask, stroke2.bw, stroke2.bh, cached.width, cached.height, stroke2.bx, stroke2.by);
|
|
282
|
+
if (!poly) {
|
|
283
|
+
// Erased to nothing — remove the shape entirely.
|
|
284
|
+
if (erase)
|
|
285
|
+
this.dropActiveShape(regions);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// Convert from matrix coords back to plot data coords.
|
|
289
|
+
const xPlot = poly.xpoints.map((x) => ox + x * rx);
|
|
290
|
+
const yPlot = poly.ypoints.map((y) => oy + y * ry);
|
|
291
|
+
this.commitStroke(regions, xPlot, yPlot);
|
|
292
|
+
}
|
|
293
|
+
/** True if (matrixX, matrixY) lies inside the current stroke accumulator. */
|
|
294
|
+
pointInStroke(matrixX, matrixY) {
|
|
295
|
+
const s = this.stroke;
|
|
296
|
+
if (!s)
|
|
297
|
+
return false;
|
|
298
|
+
const mx = Math.floor(matrixX) - s.bx;
|
|
299
|
+
const my = Math.floor(matrixY) - s.by;
|
|
300
|
+
if (mx < 0 || my < 0 || mx >= s.bw || my >= s.bh)
|
|
301
|
+
return false;
|
|
302
|
+
return s.mask[my * s.bw + mx] === 1;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Remove the region referenced by `strokeRegionId` from the region list and
|
|
306
|
+
* reset the active stroke — used when an erase stroke deletes every pixel.
|
|
307
|
+
*/
|
|
308
|
+
dropActiveShape(regions) {
|
|
309
|
+
if (this.strokeRegionId != null) {
|
|
310
|
+
const idx = regions.findIndex((r) => r.id === this.strokeRegionId);
|
|
311
|
+
if (idx >= 0) {
|
|
312
|
+
regions.splice(idx, 1);
|
|
313
|
+
this.host.setRegions(regions);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.stroke = null;
|
|
317
|
+
this.strokeRegionId = null;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Whether a region can be faithfully rasterized into the wand stroke at the current view
|
|
321
|
+
* resolution (rx/ry = data units per matrix pixel). Editing rasterizes the region to the
|
|
322
|
+
* viewport grid and re-traces it, so a region whose matrix-space bbox exceeds the rasterizer's
|
|
323
|
+
* cap would be clipped/down-quantized and come back rescaled/corrupted (jit-ui#102) — e.g. a
|
|
324
|
+
* whole-slide annotation while zoomed out. Skip adopt/merge for those: leave them untouched and
|
|
325
|
+
* only edit them near native zoom.
|
|
326
|
+
*/
|
|
327
|
+
fitsForEdit(verts, rx, ry) {
|
|
328
|
+
const xs = verts.xpoints;
|
|
329
|
+
const ys = verts.ypoints;
|
|
330
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
331
|
+
for (let i = 0; i < xs.length; i++) {
|
|
332
|
+
if (xs[i] < minX)
|
|
333
|
+
minX = xs[i];
|
|
334
|
+
if (xs[i] > maxX)
|
|
335
|
+
maxX = xs[i];
|
|
336
|
+
if (ys[i] < minY)
|
|
337
|
+
minY = ys[i];
|
|
338
|
+
if (ys[i] > maxY)
|
|
339
|
+
maxY = ys[i];
|
|
340
|
+
}
|
|
341
|
+
const w = (maxX - minX) / (rx || 1);
|
|
342
|
+
const h = (maxY - minY) / (ry || 1);
|
|
343
|
+
return w > 0 && h > 0 && w * h <= 4096 * 4096;
|
|
344
|
+
}
|
|
345
|
+
/** A region's closed-polygon vertices (image/data coords), or null when it
|
|
346
|
+
* isn't a fillable closed polygon (rectangles, open polylines). */
|
|
347
|
+
regionVerts(region) {
|
|
348
|
+
const b = region?.bounds;
|
|
349
|
+
if (b instanceof Polygon && b.closed !== false && b.xpoints.length >= 3) {
|
|
350
|
+
return { xpoints: b.xpoints, ypoints: b.ypoints, holes: b.holes };
|
|
351
|
+
}
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
/** Convert a region's hole rings from image/data coords into matrix coords so
|
|
355
|
+
* they line up with the stroke accumulator (jit-ui#85). */
|
|
356
|
+
holesToMatrix(holes, ox, oy, rx, ry) {
|
|
357
|
+
return holes?.map((ring) => ring.map(([x, y]) => [(x - ox) / rx, (y - oy) / ry]));
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* If (matrixX, matrixY) falls inside an existing region, rasterize it into
|
|
361
|
+
* the wand stroke accumulator so subsequent wand input extends it rather than
|
|
362
|
+
* starting a new region.
|
|
363
|
+
*/
|
|
364
|
+
tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached) {
|
|
365
|
+
if (!regions || regions.length === 0)
|
|
366
|
+
return false;
|
|
367
|
+
// Most-recently-added regions are on top — check them first.
|
|
368
|
+
for (let i = regions.length - 1; i >= 0; i--) {
|
|
369
|
+
const verts = this.regionVerts(regions[i]);
|
|
370
|
+
if (!verts)
|
|
371
|
+
continue;
|
|
372
|
+
// Too large to rasterize at this zoom → don't adopt it (editing would rescale/corrupt it).
|
|
373
|
+
if (!this.fitsForEdit(verts, rx, ry))
|
|
374
|
+
continue;
|
|
375
|
+
const ox = cached.originX ?? 0;
|
|
376
|
+
const oy = cached.originY ?? 0;
|
|
377
|
+
const xs = verts.xpoints.map((x) => (x - ox) / rx);
|
|
378
|
+
const ys = verts.ypoints.map((y) => (y - oy) / ry);
|
|
379
|
+
const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
|
|
380
|
+
// Clicking inside a hole must NOT adopt the donut (it's empty there).
|
|
381
|
+
if (!this.wandService.pointInPolygonWithHoles(matrixX, matrixY, xs, ys, holes))
|
|
382
|
+
continue;
|
|
383
|
+
const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
|
|
384
|
+
if (!raster)
|
|
385
|
+
continue;
|
|
386
|
+
this.stroke = raster;
|
|
387
|
+
this.strokeRegionId = regions[i].id ?? null;
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Iterate every region; if its rasterized mask overlaps the wand stroke mask
|
|
394
|
+
* by at least one pixel, OR it into the stroke and remove it from the list.
|
|
395
|
+
* Called every tick so chained merges resolve. If the wand has no region id
|
|
396
|
+
* yet, the merged region's id is adopted so the merged region replaces it.
|
|
397
|
+
*/
|
|
398
|
+
mergeOverlappingShapes(regions, rx, ry, cached) {
|
|
399
|
+
if (!this.stroke)
|
|
400
|
+
return;
|
|
401
|
+
let didMerge = true;
|
|
402
|
+
while (didMerge) {
|
|
403
|
+
didMerge = false;
|
|
404
|
+
for (let i = regions.length - 1; i >= 0; i--) {
|
|
405
|
+
const region = regions[i];
|
|
406
|
+
if (region.id != null && region.id === this.strokeRegionId)
|
|
407
|
+
continue;
|
|
408
|
+
const verts = this.regionVerts(region);
|
|
409
|
+
if (!verts)
|
|
410
|
+
continue;
|
|
411
|
+
// Too large to rasterize at this zoom → don't merge it (would rescale/corrupt it).
|
|
412
|
+
if (!this.fitsForEdit(verts, rx, ry))
|
|
413
|
+
continue;
|
|
414
|
+
const ox = cached.originX ?? 0;
|
|
415
|
+
const oy = cached.originY ?? 0;
|
|
416
|
+
const xs = verts.xpoints.map((x) => (x - ox) / rx);
|
|
417
|
+
const ys = verts.ypoints.map((y) => (y - oy) / ry);
|
|
418
|
+
// Quick bbox reject before rasterizing.
|
|
419
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
420
|
+
for (let k = 0; k < xs.length; k++) {
|
|
421
|
+
if (xs[k] < minX)
|
|
422
|
+
minX = xs[k];
|
|
423
|
+
if (xs[k] > maxX)
|
|
424
|
+
maxX = xs[k];
|
|
425
|
+
if (ys[k] < minY)
|
|
426
|
+
minY = ys[k];
|
|
427
|
+
if (ys[k] > maxY)
|
|
428
|
+
maxY = ys[k];
|
|
429
|
+
}
|
|
430
|
+
const wx0 = this.stroke.bx, wy0 = this.stroke.by;
|
|
431
|
+
const wx1 = wx0 + this.stroke.bw, wy1 = wy0 + this.stroke.bh;
|
|
432
|
+
if (maxX < wx0 || minX > wx1 || maxY < wy0 || minY > wy1)
|
|
433
|
+
continue;
|
|
434
|
+
const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
|
|
435
|
+
const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
|
|
436
|
+
if (!raster)
|
|
437
|
+
continue;
|
|
438
|
+
if (!masksOverlap(this.stroke, raster))
|
|
439
|
+
continue;
|
|
440
|
+
this.stroke = unionMasks(this.stroke, raster);
|
|
441
|
+
if (this.strokeRegionId == null) {
|
|
442
|
+
this.strokeRegionId = region.id ?? null;
|
|
443
|
+
}
|
|
444
|
+
regions.splice(i, 1);
|
|
445
|
+
didMerge = true;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Commit the in-progress polygon as a region — a new region on the first tick
|
|
452
|
+
* of a stroke, or an in-place replacement of the active region on later ticks
|
|
453
|
+
* — then ask the host to render. The store mints an id on the first commit,
|
|
454
|
+
* which we adopt so subsequent ticks replace the same region.
|
|
455
|
+
*/
|
|
456
|
+
commitStroke(regions, xPlot, yPlot) {
|
|
457
|
+
if (xPlot.length < 3)
|
|
458
|
+
return;
|
|
459
|
+
const existing = this.strokeRegionId != null
|
|
460
|
+
? regions.find((r) => r.id === this.strokeRegionId) : null;
|
|
461
|
+
const poly = new Polygon();
|
|
462
|
+
poly.npoints = xPlot.length;
|
|
463
|
+
poly.xpoints = xPlot;
|
|
464
|
+
poly.ypoints = yPlot;
|
|
465
|
+
poly.coordinates = xPlot.map((x, i) => [x, yPlot[i]]);
|
|
466
|
+
poly.closed = true;
|
|
467
|
+
const region = new Region();
|
|
468
|
+
region.bounds = poly;
|
|
469
|
+
region.color = this.host.getShapeColor();
|
|
470
|
+
if (existing) {
|
|
471
|
+
// Preserve identity + class label across the stroke's drag ticks.
|
|
472
|
+
region.id = existing.id;
|
|
473
|
+
region.name = existing.name;
|
|
474
|
+
}
|
|
475
|
+
// Default class/annotation name, matching the overlay-drawn regions and the
|
|
476
|
+
// Region Editor's "Add" actions so a wand region isn't left unlabeled.
|
|
477
|
+
region.label = existing?.label ?? 'Region';
|
|
478
|
+
if (this.strokeRegionId == null) {
|
|
479
|
+
regions.push(region);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
const idx = regions.findIndex((r) => r.id === this.strokeRegionId);
|
|
483
|
+
if (idx >= 0)
|
|
484
|
+
regions[idx] = region;
|
|
485
|
+
else
|
|
486
|
+
regions.push(region);
|
|
487
|
+
}
|
|
488
|
+
this.host.setRegions(regions);
|
|
489
|
+
// The store assigns an id on the first commit — adopt it.
|
|
490
|
+
this.strokeRegionId = region.id ?? this.strokeRegionId;
|
|
491
|
+
}
|
|
492
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
493
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, providedIn: 'root' }); }
|
|
494
|
+
}
|
|
495
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, decorators: [{
|
|
496
|
+
type: Injectable,
|
|
497
|
+
args: [{ providedIn: 'root' }]
|
|
498
|
+
}], ctorParameters: () => [{ type: i1.WandService }] });
|
|
499
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FuZC10b29sLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvd2FuZC93YW5kLXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTNDLE9BQU8sRUFBMEIsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckUsT0FBTyxFQUFZLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUUzRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7QUFrRHREOzs7Ozs7OztHQVFHO0FBRUgsTUFBTSxPQUFPLGVBQWU7SUEyQjFCLFlBQW9CLFdBQXdCO1FBQXhCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBdkJwQyxZQUFPLEdBQTZCLElBQUksQ0FBQztRQUN6QyxXQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCOzs7Ozs7O1dBT0c7UUFDSyxXQUFNLEdBQW9CLElBQUksQ0FBQztRQUN2Qyw0RUFBNEU7UUFDcEUsbUJBQWMsR0FBa0IsSUFBSSxDQUFDO1FBQzdDOzRHQUNvRztRQUM1RixtQkFBYyxHQUFrQixJQUFJLENBQUM7UUFDckMsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixZQUFPLEdBQWdCLEVBQUUsQ0FBQztRQU9oQyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMs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QUM5QiwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDekQsQ0FBQzs4R0FyZ0JVLGVBQWU7a0hBQWYsZUFBZSxjQURGLE1BQU07OzJGQUNuQixlQUFlO2tCQUQzQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgV2FuZEltYWdlLCBXYW5kT3B0aW9ucywgV2FuZFNlcnZpY2UgfSBmcm9tICcuL3dhbmQuc2VydmljZSc7XG5pbXBvcnQgeyBCQm94TWFzaywgbWFza3NPdmVybGFwLCB1bmlvbk1hc2tzIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2dlb21ldHJ5JztcbmltcG9ydCB7IElWaWV3cG9ydEhvc3QsIElSZWdpb25EYXRhSG9zdCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jb29yZGluYXRlLXRyYW5zZm9ybS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb24sIFBvbHlnb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvcmVnaW9uJztcblxuLyoqXG4gKiBUaGUgcGl4ZWwgZGF0YSBhbmQgZnJhbWUgc3RhdGUgUGxvdGx5U2VydmljZSBjYWNoZXMgZm9yIHNhbXBsaW5nLiBSZXR1cm5lZFxuICogYnkgYFdhbmRUb29sSG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVkSW1hZ2VEYXRhIHtcbiAgLyoqIDItRCBtYXRyaWNlcywgb25lIHBlciBzdGFjayBmcmFtZSAobGVuZ3RoIDEgZm9yIG5vbi1zdGFjayBpbWFnZXMpLiAqL1xuICBmcmFtZXM6IGFueVtdO1xuICAvKiogSW1hZ2UtcGl4ZWwgd2lkdGggb2YgZWFjaCBmcmFtZSBtYXRyaXguICovXG4gIHdpZHRoOiBudW1iZXI7XG4gIC8qKiBJbWFnZS1waXhlbCBoZWlnaHQgb2YgZWFjaCBmcmFtZSBtYXRyaXguICovXG4gIGhlaWdodDogbnVtYmVyO1xuICAvKipcbiAgICogUGxvdC1kYXRhLWNvb3Jkcy1wZXItaW1hZ2UtcGl4ZWwgYWxvbmcgeCAoYW5kIHkg4oCUIHRoZXkncmUgdGhlIHNhbWVcbiAgICogZm9yIGhlYXRtYXAgYW5kIGltYWdlIHRyYWNlcykuXG4gICAqL1xuICByYXRpb3M6IG51bWJlcltdO1xuICAvKiogV2hldGhlciBlYWNoIGZyYW1lIGlzIGEgMi1EIHNjYWxhciBtYXRyaXggKHRydWUpIG9yIDMtY2hhbm5lbCBSR0IgKGZhbHNlKS4gKi9cbiAgaXNHcmF5c2NhbGU6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBEYXRhLWNvb3JkcyBvZiBtYXRyaXggcGl4ZWwgKDAsMCkuIExldHMgdGhlIG1hdHJpeCBiZSBhICpjcm9wKiBvZiB0aGUgZGF0YVxuICAgKiBzcGFjZSByYXRoZXIgdGhhbiBzdGFydGluZyBhdCB0aGUgb3JpZ2luIOKAlCBlLmcuIHRoZSBPU0QgYmFja2VuZCBzYW1wbGVzIHRoZVxuICAgKiBjdXJyZW50bHkgcmVuZGVyZWQgdmlld3BvcnQsIHNvIHdoZW4gem9vbWVkIGluIHRoZSBtYXRyaXggY292ZXJzIG9ubHkgdGhlXG4gICAqIHZpc2libGUgc3ViLXJlZ2lvbiBhdCBzY3JlZW4gcmVzb2x1dGlvbi4gRGVmYXVsdHMgdG8gMCAoZnVsbC1mcmFtZSBtYXRyaXgsXG4gICAqIGFzIFBsb3RseSBwcm92aWRlcykuIG1hdHJpeEluZGV4ID0gKGRhdGEgLSBvcmlnaW4pIC8gcmF0aW8uXG4gICAqL1xuICBvcmlnaW5YPzogbnVtYmVyO1xuICBvcmlnaW5ZPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFRoZSBjb2xsYWJvcmF0aW9uIGludGVyZmFjZSB0aGUgd2FuZCB0b29sIG5lZWRzIGZyb20gUGxvdGx5U2VydmljZS5cbiAqXG4gKiBLZWVwaW5nIGl0IGV4cGxpY2l0IG1ha2VzIHRoZSBkZXBlbmRlbmN5IG9uZS13YXk6IFdhbmRUb29sU2VydmljZSBuZXZlclxuICogaW1wb3J0cyBQbG90bHlTZXJ2aWNlIGRpcmVjdGx5LiBQbG90bHlTZXJ2aWNlIHNhdGlzZmllcyB0aGlzIGludGVyZmFjZVxuICogc3RydWN0dXJhbGx5IGFuZCBiaW5kcyBpdHNlbGYgdmlhIGBiaW5kSG9zdCh0aGlzKWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2FuZFRvb2xIb3N0IGV4dGVuZHMgSVZpZXdwb3J0SG9zdCwgSVJlZ2lvbkRhdGFIb3N0IHtcbiAgLyoqIFBpeGVsIGRhdGEgZm9yIHNhbXBsaW5nLiBudWxsIHdoZW4gbm8gaW1hZ2UgaXMgbG9hZGVkIHlldC4gKi9cbiAgZ2V0Q2FjaGVkSW1hZ2VEYXRhKCk6IENhY2hlZEltYWdlRGF0YSB8IG51bGw7XG4gIC8qKiBJbmRleCBvZiB0aGUgY3VycmVudGx5IHZpc2libGUgZnJhbWUgaW4gYSBzdGFjayAoMCBmb3Igbm9uLXN0YWNrKS4gKi9cbiAgZ2V0QWN0aXZlRnJhbWVJbmRleCgpOiBudW1iZXI7XG5cbiAgLyoqIEN1cnJlbnQgaW1hZ2UncyBmaWxlbmFtZSDigJQgc3RhbXBlZCBvbnRvIG5ldyBzaGFwZXMgZm9yIGZpbHRlcmluZy4gKi9cbiAgZ2V0RmlsZU5hbWUoKTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAvKiogRGVmYXVsdCBzdHJva2UgY29sb3VyIGZvciBuZXcgc2hhcGVzLiAqL1xuICBnZXRTaGFwZUNvbG9yKCk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgd2FuZCBkcmF3aW5nIHRvb2wuIE93bnMgaXRzIG93biBjYW52YXMgb3ZlcmxheSwgbW91c2UgaGFuZGxlcnMsIGFuZFxuICogc3Ryb2tlIGFjY3VtdWxhdG9yLiBSZWFkcy93cml0ZXMgdGhlIHNoYXBlIGxpc3QgdmlhIHRoZSBXYW5kVG9vbEhvc3RcbiAqIGludGVyZmFjZSBzbyBpdCBzdGF5cyBkZWNvdXBsZWQgZnJvbSBQbG90bHlTZXJ2aWNlIGludGVybmFscy5cbiAqXG4gKiBMaWZlY3ljbGU6IFBsb3RseVNlcnZpY2UgaW5qZWN0cyB0aGlzIHNlcnZpY2UsIGNhbGxzIGBiaW5kSG9zdCh0aGlzKWAgb25jZVxuICogZHVyaW5nIGl0cyBvd24gY29uc3RydWN0aW9uLCB0aGVuIGNhbGxzIGBzZXRNb2RlKHRydWUgfCBmYWxzZSwgb3B0aW9ucylgIHRvXG4gKiBhY3RpdmF0ZS9kZWFjdGl2YXRlIHRoZSB0b29sLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFdhbmRUb29sU2VydmljZSB7XG4gIC8vIOKUgOKUgCBUb29sIHN0YXRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgaG9zdCE6IFdhbmRUb29sSG9zdDtcbiAgcHJpdmF0ZSBvdmVybGF5OiBIVE1MQ2FudmFzRWxlbWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGFjdGl2ZSA9IGZhbHNlO1xuICAvKipcbiAgICogQWNjdW11bGF0ZWQgd2FuZCByZWdpb24uIEV2ZXJ5IHBlci10aWNrIHBhdGNoIG1hc2sgaXMgT1InZCBpbnRvIGBtYXNrYFxuICAgKiBvdmVyIGEgYmJveCB0aGF0IGdyb3dzIHdpdGggdGhlIHN0cm9rZSwgc28gdGhlIHJlZ2lvbiBrZWVwcyBleHBhbmRpbmdcbiAgICogYXMgdGhlIHVzZXIgZHJhZ3MuIFRoZSBhY2N1bXVsYXRvciBwZXJzaXN0cyBhY3Jvc3MgbW91c2V1cC9tb3VzZWRvd24gc29cbiAgICogdGhhdCBzdWJzZXF1ZW50IHN0cm9rZXMgZXh0ZW5kIHRoZSAqc2FtZSogcmVnaW9uIOKAlCBtYXRjaGluZyBRdVBhdGgnc1xuICAgKiBicnVzaCBiZWhhdmlvdXIgd2hlcmUgdGhlIGFjdGl2ZSBhbm5vdGF0aW9uIHN0YXlzIGVkaXRhYmxlIHVudGlsIHRoZVxuICAgKiB1c2VyIHN3aXRjaGVzIHRvb2wuXG4gICAqL1xuICBwcml2YXRlIHN0cm9rZTogQkJveE1hc2sgfCBudWxsID0gbnVsbDtcbiAgLyoqIElkIG9mIHRoZSByZWdpb24gdGhpcyB3YW5kIHN0cm9rZSBpcyBlZGl0aW5nIChudWxsID0gYSBmcmVzaCByZWdpb24pLiAqL1xuICBwcml2YXRlIHN0cm9rZVJlZ2lvbklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIFJlYWRiYWNrIHJhdGlvL29yaWdpbiBzaWduYXR1cmUgdGhlIGFjdGl2ZSBzdHJva2UncyBtYXRyaXggY29vcmRzIGFyZSB0aWVkIHRvOyBhIGNoYW5nZVxuICAgKiAgKHpvb20vcGFuKSBpbnZhbGlkYXRlcyB0aGUgc3Ryb2tlIHNvIGl0IGlzbid0IHJlLWNvbW1pdHRlZCBhdCBhIGRpZmZlcmVudCBzY2FsZSAoaml0LXVpIzEwMikuICovXG4gIHByaXZhdGUgc3Ryb2tlUmF0aW9TaWc6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRyYWdnaW5nID0gZmFsc2U7XG4gIHByaXZhdGUgb3B0aW9uczogV2FuZE9wdGlvbnMgPSB7fTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGJvdW5kTW91c2VEb3duOiAoZTogTW91c2VFdmVudCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBib3VuZE1vdXNlTW92ZTogKGU6IE1vdXNlRXZlbnQpID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgYm91bmRNb3VzZVVwOiAoZTogTW91c2VFdmVudCkgPT4gdm9pZDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSkge1xuICAgIHRoaXMuYm91bmRNb3VzZURvd24gPSAoZSkgPT4gdGhpcy5vbk1vdXNlRG93bihlKTtcbiAgICB0aGlzLmJvdW5kTW91c2VNb3ZlID0gKGUpID0+IHRoaXMub25Nb3VzZU1vdmUoZSk7XG4gICAgdGhpcy5ib3VuZE1vdXNlVXAgPSAoZSkgPT4gdGhpcy5vbk1vdXNlVXAoZSk7XG4gIH1cblxuICAvKiogV2lyZSB0aGUgdG9vbCB0byBpdHMgaG9zdC4gTXVzdCBiZSBjYWxsZWQgb25jZSBiZWZvcmUgYHNldE1vZGUodHJ1ZSlgLiAqL1xuICBiaW5kSG9zdChob3N0OiBXYW5kVG9vbEhvc3QpIHtcbiAgICB0aGlzLmhvc3QgPSBob3N0O1xuICB9XG5cbiAgLy8g4pSA4pSAIFB1YmxpYyBBUEkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRvZ2dsZSB0aGUgd2FuZCBvbi9vZmYuICovXG4gIHNldE1vZGUoYWN0aXZlOiBib29sZWFuLCBvcHRpb25zOiBXYW5kT3B0aW9ucyA9IHt9KSB7XG4gICAgdGhpcy5hY3RpdmUgPSBhY3RpdmU7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICBpZiAoYWN0aXZlKSB7XG4gICAgICB0aGlzLmNyZWF0ZU92ZXJsYXkoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kZXN0cm95T3ZlcmxheSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBNZXJnZSBuZXcgb3B0aW9ucyAoZS5nLiBsaXZlIHNlbnNpdGl2aXR5IHNsaWRlciB1cGRhdGVzKS4gKi9cbiAgc2V0T3B0aW9ucyhvcHRpb25zOiBXYW5kT3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IHsgLi4udGhpcy5vcHRpb25zLCAuLi5vcHRpb25zIH07XG4gIH1cblxuICAvKiogRHJvcCB0aGUgYWN0aXZlIHdhbmQgcmVnaW9uIHNvIHRoZSBuZXh0IGNsaWNrIHN0YXJ0cyBhIG5ldyBvbmUuICovXG4gIGNsZWFyQWN0aXZlUmVnaW9uKCkge1xuICAgIHRoaXMucmVzZXRTdHJva2UoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBPdmVybGF5IGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGNyZWF0ZU92ZXJsYXkoKSB7XG4gICAgY29uc3QgcGxvdEVsID0gdGhpcy5ob3N0LmdldE92ZXJsYXlDb250YWluZXIoKTtcbiAgICBpZiAoIXBsb3RFbCB8fCB0aGlzLm92ZXJsYXkpIHJldHVybjtcblxuICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIGNhbnZhcy5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgY2FudmFzLnN0eWxlLnRvcCA9ICcwJztcbiAgICBjYW52YXMuc3R5bGUubGVmdCA9ICcwJztcbiAgICBjYW52YXMuc3R5bGUud2lkdGggPSAnMTAwJSc7XG4gICAgY2FudmFzLnN0eWxlLmhlaWdodCA9ICcxMDAlJztcbiAgICBjYW52YXMuc3R5bGUuY3Vyc29yID0gJ2Nyb3NzaGFpcic7XG4gICAgY2FudmFzLnN0eWxlLnpJbmRleCA9ICcxMDAnO1xuICAgIGNhbnZhcy53aWR0aCA9IHBsb3RFbC5vZmZzZXRXaWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gcGxvdEVsLm9mZnNldEhlaWdodDtcblxuICAgIHBsb3RFbC5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgIHRoaXMub3ZlcmxheSA9IGNhbnZhcztcblxuICAgIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmJvdW5kTW91c2VEb3duKTtcbiAgICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5ib3VuZE1vdXNlTW92ZSk7XG4gICAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmJvdW5kTW91c2VVcCk7XG4gICAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCB0aGlzLmJvdW5kTW91c2VVcCk7XG4gIH1cblxuICBwcml2YXRlIGRlc3Ryb3lPdmVybGF5KCkge1xuICAgIGlmICghdGhpcy5vdmVybGF5KSByZXR1cm47XG4gICAgdGhpcy5vdmVybGF5LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuYm91bmRNb3VzZURvd24pO1xuICAgIHRoaXMub3ZlcmxheS5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLmJvdW5kTW91c2VNb3ZlKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlKCk7XG4gICAgdGhpcy5vdmVybGF5ID0gbnVsbDtcbiAgICB0aGlzLnJlc2V0U3Ryb2tlKCk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VEb3duKGU6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoZS5idXR0b24gIT09IDApIHJldHVybjtcbiAgICB0aGlzLmRyYWdnaW5nID0gdHJ1ZTtcbiAgICB0aGlzLmFwcGx5QXRDbGllbnQoZSwgdHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VNb3ZlKGU6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuZHJhZ2dpbmcpIHJldHVybjtcbiAgICBpZiAoKGUuYnV0dG9ucyAmIDEpID09PSAwKSB7XG4gICAgICB0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuYXBwbHlBdENsaWVudChlLCBmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VVcChfOiBNb3VzZUV2ZW50KSB7XG4gICAgLy8gU3RvcCBhY2N1bXVsYXRpbmcgZnJvbSB0aGlzIGRyYWcsIGJ1dCBrZWVwIHRoZSByZWdpb24gYWxpdmUgc28gdGhlXG4gICAgLy8gbmV4dCBtb3VzZWRvd24gZXh0ZW5kcyBpdCBpbnN0ZWFkIG9mIHN0YXJ0aW5nIGZyZXNoLlxuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRTdHJva2UoKSB7XG4gICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBQZXItdGljayBzdHJva2UgbG9naWMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFNhbXBsZSB0aGUgY2FjaGVkIGltYWdlIGF0IHRoZSBjbGljayBsb2NhdGlvbiwgT1IgKG9yIEFORC1OT1QpIHRoZVxuICAgKiB3YW5kJ3MgcGVyLXRpY2sgcGF0Y2ggbWFzayBpbnRvIHRoZSBhY3RpdmUgcmVnaW9uJ3MgYmJveC1yZWxhdGl2ZSBtYXNrLFxuICAgKiByZS10cmFjZSB0aGUgYm91bmRhcnksIGFuZCB1cGRhdGUgdGhlIGluLXByb2dyZXNzIHNoYXBlIOKAlCBtYXRjaGluZ1xuICAgKiBRdVBhdGgncyBhZGRpdGl2ZSBicnVzaC93YW5kIGJlaGF2aW91ci4gU2hpZnQgPSBlcmFzZS4gQ21kL0N0cmwgPVxuICAgKiBleGFjdC1tYXRjaCBmbG9vZCBmaWxsLlxuICAgKi9cbiAgcHJpdmF0ZSBhcHBseUF0Q2xpZW50KGU6IE1vdXNlRXZlbnQsIGlzU3RhcnQgPSBmYWxzZSkge1xuICAgIGlmICghdGhpcy5vdmVybGF5KSByZXR1cm47XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5ob3N0LmdldENhY2hlZEltYWdlRGF0YSgpO1xuICAgIGlmICghY2FjaGVkIHx8IGNhY2hlZC5mcmFtZXMubGVuZ3RoID09PSAwKSByZXR1cm47XG5cbiAgICAvLyBUaGUgY3VycmVudCByZWdpb25zIChuZXV0cmFsIG1vZGVsKS4gTXV0YXRlZCBsb2NhbGx5IGFjcm9zcyB0aGlzIHRpY2sgYW5kXG4gICAgLy8gY29tbWl0dGVkIG9uY2UgdmlhIGhvc3Quc2V0UmVnaW9ucygpLlxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLmhvc3QuZ2V0UmVnaW9ucygpO1xuXG4gICAgY29uc3QgdHJhbnNmb3JtID0gdGhpcy5ob3N0LmdldENvb3JkaW5hdGVUcmFuc2Zvcm0oKTtcbiAgICBpZiAoIXRyYW5zZm9ybS5pc1JlYWR5KCkpIHJldHVybjtcbiAgICBjb25zdCB7IHg6IGRhdGFYLCB5OiBkYXRhWSB9ID0gdHJhbnNmb3JtLmNsaWVudFRvRGF0YShlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoZGF0YVgpIHx8ICFOdW1iZXIuaXNGaW5pdGUoZGF0YVkpKSByZXR1cm47XG5cbiAgICAvLyByYXRpb3MgPSBbeFJhdGlvLCB5UmF0aW9dIGZyb20gYm90aCBiYWNrZW5kcy4gVXNlIHRoZSBYIHJhdGlvIGZvciB0aGVcbiAgICAvLyBjb2x1bW4gYW5kIHRoZSBZIHJhdGlvIGZvciB0aGUgcm93OiB0aGV5IGRpZmZlciB3aGVuIHRoZSBwaXhlbCBhc3BlY3RcbiAgICAvLyBpc24ndCAxOjEgKGUuZy4gYSBub24tc3F1YXJlIE9TRCB2aWV3cG9ydCksIGFuZCByZXVzaW5nIHJhdGlvc1swXSBmb3JcbiAgICAvLyBib3RoIHdvdWxkIGRpc3RvcnQgdGhlIHNhbXBsZWQgcmVnaW9uIHZlcnRpY2FsbHkuIEZhbGwgYmFjayB0byB0aGUgWFxuICAgIC8vIHJhdGlvIGlmIG9ubHkgb25lIHdhcyBzdXBwbGllZC5cbiAgICBjb25zdCByeCA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCByeSA9IGNhY2hlZC5yYXRpb3NbMV0gfHwgY2FjaGVkLnJhdGlvc1swXSB8fCAxO1xuICAgIGNvbnN0IG94ID0gY2FjaGVkLm9yaWdpblggPz8gMDtcbiAgICBjb25zdCBveSA9IGNhY2hlZC5vcmlnaW5ZID8/IDA7XG4gICAgLy8gVGhlIHN0cm9rZSBhY2N1bXVsYXRvciBpcyBpbiBtYXRyaXggKHZpZXdwb3J0LXBpeGVsKSBjb29yZGluYXRlcyB0aWVkIHRvIHRoZSByZWFkYmFjaydzXG4gICAgLy8gcmF0aW8vb3JpZ2luLiBJZiB0aGUgdmlldyBjaGFuZ2VkICh6b29tL3Bhbikgc2luY2UgdGhlIHN0cm9rZSB3YXMgYnVpbHQsIHRob3NlIGNvb3JkcyBub1xuICAgIC8vIGxvbmdlciBtZWFuIHRoZSBzYW1lIHRoaW5nIOKAlCByZS1jb21taXR0aW5nIHdvdWxkIHJlc2NhbGUgdGhlIHJlZ2lvbiBieSB0aGUgem9vbSBmYWN0b3JcbiAgICAvLyAoaml0LXVpIzEwMikuIERyb3AgdGhlIHN0YWxlIHN0cm9rZSBzbyBhIGZyZXNoIG9uZSBpcyBidWlsdCBhdCB0aGUgY3VycmVudCB2aWV3LlxuICAgIGNvbnN0IHNpZyA9IGAke3J4fSwke3J5fSwke294fSwke295fWA7XG4gICAgaWYgKHRoaXMuc3Ryb2tlICYmIHRoaXMuc3Ryb2tlUmF0aW9TaWcgIT09IHNpZykge1xuICAgICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgICAgdGhpcy5zdHJva2VSZWdpb25JZCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuc3Ryb2tlUmF0aW9TaWcgPSBzaWc7XG4gICAgY29uc3QgbWF0cml4WCA9IChkYXRhWCAtIG94KSAvIHJ4O1xuICAgIGNvbnN0IG1hdHJpeFkgPSAoZGF0YVkgLSBveSkgLyByeTtcbiAgICBpZiAobWF0cml4WCA8IDAgfHwgbWF0cml4WCA+PSBjYWNoZWQud2lkdGgpIHJldHVybjtcbiAgICBpZiAobWF0cml4WSA8IDAgfHwgbWF0cml4WSA+PSBjYWNoZWQuaGVpZ2h0KSByZXR1cm47XG5cbiAgICBjb25zdCBmcmFtZUlkeCA9IHRoaXMuaG9zdC5nZXRBY3RpdmVGcmFtZUluZGV4KCk7XG4gICAgY29uc3QgZnJhbWUgPSBjYWNoZWQuZnJhbWVzW2ZyYW1lSWR4XSA/PyBjYWNoZWQuZnJhbWVzWzBdO1xuXG4gICAgY29uc3Qgd2FuZEltYWdlOiBXYW5kSW1hZ2UgPSB7XG4gICAgICBkYXRhOiBmcmFtZSxcbiAgICAgIHdpZHRoOiBjYWNoZWQud2lkdGgsXG4gICAgICBoZWlnaHQ6IGNhY2hlZC5oZWlnaHQsXG4gICAgICBpc0dyYXlzY2FsZTogY2FjaGVkLmlzR3JheXNjYWxlLFxuICAgIH07XG4gICAgLy8gU2hpZnQgPSBlcmFzZSAoc3VidHJhY3QgcGl4ZWxzIGZyb20gYW4gZXhpc3RpbmcgcmVnaW9uKS5cbiAgICAvLyBDbWQvQ3RybCBhbG9uZSA9IHNpbXBsZSBmbG9vZCBmaWxsIChubyBzbW9vdGhpbmcvdGhyZXNob2xkKS5cbiAgICBjb25zdCBlcmFzZSA9IGUuc2hpZnRLZXk7XG4gICAgY29uc3Qgb3B0czogV2FuZE9wdGlvbnMgPSB7XG4gICAgICAuLi50aGlzLm9wdGlvbnMsXG4gICAgICBzaW1wbGVNb2RlOiB0aGlzLm9wdGlvbnMuc2ltcGxlTW9kZSB8fCAoKGUubWV0YUtleSB8fCBlLmN0cmxLZXkpICYmICFlcmFzZSksXG4gICAgfTtcblxuICAgIC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IHRpY2sgb2YgYSBuZXcgZHJhZyBhbmQgdGhlIGNsaWNrIGlzIE5PVCBpbnNpZGUgdGhlXG4gICAgLy8gY3VycmVudCBhY2N1bXVsYXRvciBhbmQgTk9UIGluc2lkZSBhbnkgZXhpc3RpbmcgcGF0aC1zaGFwZSwgZHJvcCB0aGUgb2xkXG4gICAgLy8gc3Ryb2tlIHNvIGEgYnJhbmQtbmV3IHJlZ2lvbiBzdGFydHMgaGVyZS4gV2l0aG91dCB0aGlzLCB0aGUgYWNjdW11bGF0b3JcbiAgICAvLyBiYm94IGdyb3dzIHRvIHNwYW4gYm90aCBhcmVhcyBhbmQgYG1hc2tUb1BvbHlnb25gIGtlZXBzIG9ubHkgdGhlIGxhcmdlc3RcbiAgICAvLyBjb25uZWN0ZWQgYmxvYiDigJQgbWFraW5nIHRoZSBuZXcgY2xpY2sgYXBwZWFyIHRvIGRvIG5vdGhpbmcuXG4gICAgaWYgKGlzU3RhcnQgJiYgIWVyYXNlICYmIHRoaXMuc3Ryb2tlICYmICF0aGlzLnBvaW50SW5TdHJva2UobWF0cml4WCwgbWF0cml4WSkpIHtcbiAgICAgIC8vIFdpbGwgZmFsbCB0aHJvdWdoIHRvIHRyeUFkb3B0U2hhcGVBdCBiZWxvdzsgaWYgdGhhdCBhbHNvIG1pc3NlcywgYVxuICAgICAgLy8gZnJlc2ggc3Ryb2tlIGlzIGNyZWF0ZWQgZnJvbSB0aGUgcGF0Y2guXG4gICAgICB0aGlzLnN0cm9rZSA9IG51bGw7XG4gICAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBwYXRjaCA9IHRoaXMud2FuZFNlcnZpY2UuY29tcHV0ZVBhdGNoTWFzayh3YW5kSW1hZ2UsIG1hdHJpeFgsIG1hdHJpeFksIG9wdHMpO1xuICAgIGlmICghcGF0Y2gpIHJldHVybjtcblxuICAgIGNvbnN0IFcgPSBwYXRjaC5zaXplO1xuICAgIGNvbnN0IGhhbGYgPSAoVyAtIDEpIC8gMjtcbiAgICBjb25zdCBweDAgPSBNYXRoLnJvdW5kKG1hdHJpeFgpIC0gaGFsZjtcbiAgICBjb25zdCBweTAgPSBNYXRoLnJvdW5kKG1hdHJpeFkpIC0gaGFsZjtcbiAgICBjb25zdCBweDEgPSBweDAgKyBXO1xuICAgIGNvbnN0IHB5MSA9IHB5MCArIFc7XG5cbiAgICAvLyBJZiB0aGVyZSdzIG5vIGFjdGl2ZSB3YW5kIHJlZ2lvbiwgc2VlIGlmIHRoZSBjbGljayBsYW5kZWQgb24gYW5cbiAgICAvLyBleGlzdGluZyBwYXRoLXNoYXBlIOKAlCBhZG9wdCBpdCBzbyB0aGlzIHN0cm9rZSBleHRlbmRzIChvciBlcmFzZXNcbiAgICAvLyBmcm9tKSBpdCBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IHJlZ2lvbi5cbiAgICBpZiAoIXRoaXMuc3Ryb2tlKSB7XG4gICAgICB0aGlzLnRyeUFkb3B0U2hhcGVBdChyZWdpb25zLCBtYXRyaXhYLCBtYXRyaXhZLCByeCwgcnksIGNhY2hlZCk7XG4gICAgfVxuXG4gICAgLy8gRXJhc2luZyByZXF1aXJlcyBhbiBleGlzdGluZyByZWdpb24uIFNoaWZ0LWNsaWNraW5nIGVtcHR5IHNwYWNlIGlzIGFcbiAgICAvLyBuby1vcCDigJQgd2UgZG9uJ3QgY3JlYXRlIGEgcmVnaW9uIG9ubHkgdG8gaW1tZWRpYXRlbHkgZGVsZXRlIGZyb20gaXQuXG4gICAgaWYgKGVyYXNlICYmICF0aGlzLnN0cm9rZSkgcmV0dXJuO1xuXG4gICAgLy8gR3JvdyB0aGUgcmVnaW9uJ3MgYWNjdW11bGF0ZWQgbWFzayBvbmx5IHdoZW4gYWRkaW5nLiBFcmFzaW5nIG5ldmVyXG4gICAgLy8gZXhwYW5kcyB0aGUgcmVnaW9uIGJleW9uZCBpdHMgY3VycmVudCBiYm94LlxuICAgIGlmICghdGhpcy5zdHJva2UpIHtcbiAgICAgIGNvbnN0IGJ4ID0gTWF0aC5tYXgoMCwgcHgwKTtcbiAgICAgIGNvbnN0IGJ5ID0gTWF0aC5tYXgoMCwgcHkwKTtcbiAgICAgIGNvbnN0IGJ4MSA9IE1hdGgubWluKGNhY2hlZC53aWR0aCwgcHgxKTtcbiAgICAgIGNvbnN0IGJ5MSA9IE1hdGgubWluKGNhY2hlZC5oZWlnaHQsIHB5MSk7XG4gICAgICBjb25zdCBidyA9IE1hdGgubWF4KDAsIGJ4MSAtIGJ4KTtcbiAgICAgIGNvbnN0IGJoID0gTWF0aC5tYXgoMCwgYnkxIC0gYnkpO1xuICAgICAgaWYgKGJ3ID09PSAwIHx8IGJoID09PSAwKSByZXR1cm47XG4gICAgICB0aGlzLnN0cm9rZSA9IHsgYngsIGJ5LCBidywgYmgsIG1hc2s6IG5ldyBVaW50OEFycmF5KGJ3ICogYmgpIH07XG4gICAgfSBlbHNlIGlmICghZXJhc2UpIHtcbiAgICAgIC8vIERvbid0IGNsYW1wIHRoZSBhY2N1bXVsYXRvciB0byB0aGUgdmlld3BvcnQ6IGFuIGFkb3B0ZWQgcmVnaW9uIG1heSBleHRlbmQgb2ZmLXNjcmVlbiwgYW5kXG4gICAgICAvLyBjbGFtcGluZyBoZXJlIHdvdWxkIGRpc2NhcmQgaXRzIG9mZi1zY3JlZW4gcGFydCB3aGVuIHRoZSBzdHJva2UgZ3Jvd3MgKGppdC11aSMxMDIpLlxuICAgICAgY29uc3QgYnggPSBNYXRoLm1pbih0aGlzLnN0cm9rZS5ieCwgcHgwKTtcbiAgICAgIGNvbnN0IGJ5ID0gTWF0aC5taW4odGhpcy5zdHJva2UuYnksIHB5MCk7XG4gICAgICBjb25zdCBieDEgPSBNYXRoLm1heCh0aGlzLnN0cm9rZS5ieCArIHRoaXMuc3Ryb2tlLmJ3LCBweDEpO1xuICAgICAgY29uc3QgYnkxID0gTWF0aC5tYXgodGhpcy5zdHJva2UuYnkgKyB0aGlzLnN0cm9rZS5iaCwgcHkxKTtcbiAgICAgIGNvbnN0IGJ3ID0gYngxIC0gYng7XG4gICAgICBjb25zdCBiaCA9IGJ5MSAtIGJ5O1xuICAgICAgaWYgKGJ3ICE9PSB0aGlzLnN0cm9rZS5idyB8fCBiaCAhPT0gdGhpcy5zdHJva2UuYmggfHwgYnggIT09IHRoaXMuc3Ryb2tlLmJ4IHx8IGJ5ICE9PSB0aGlzLnN0cm9rZS5ieSkge1xuICAgICAgICAvLyBSZWFsbG9jYXRlIHRoZSBsYXJnZXIgbWFzayBhbmQgY29weSB0aGUgcHJldmlvdXMgbWFzayBpbnRvIGl0LlxuICAgICAgICBjb25zdCBuZXh0ID0gbmV3IFVpbnQ4QXJyYXkoYncgKiBiaCk7XG4gICAgICAgIGNvbnN0IGR4ID0gdGhpcy5zdHJva2UuYnggLSBieDtcbiAgICAgICAgY29uc3QgZHkgPSB0aGlzLnN0cm9rZS5ieSAtIGJ5O1xuICAgICAgICBmb3IgKGxldCByb3cgPSAwOyByb3cgPCB0aGlzLnN0cm9rZS5iaDsgcm93KyspIHtcbiAgICAgICAgICBjb25zdCBzcmNPZmYgPSByb3cgKiB0aGlzLnN0cm9rZS5idztcbiAgICAgICAgICBjb25zdCBkc3RPZmYgPSAocm93ICsgZHkpICogYncgKyBkeDtcbiAgICAgICAgICBuZXh0LnNldCh0aGlzLnN0cm9rZS5tYXNrLnN1YmFycmF5KHNyY09mZiwgc3JjT2ZmICsgdGhpcy5zdHJva2UuYncpLCBkc3RPZmYpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3Ryb2tlID0geyBieCwgYnksIGJ3LCBiaCwgbWFzazogbmV4dCB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFwcGx5IHRoZSBwYXRjaDogT1IgKGFkZCkgb3IgQU5ELU5PVCAoZXJhc2UpLlxuICAgIGNvbnN0IHN0cm9rZSA9IHRoaXMuc3Ryb2tlO1xuICAgIGZvciAobGV0IHB5ID0gMDsgcHkgPCBXOyBweSsrKSB7XG4gICAgICBjb25zdCBpeSA9IHB5MCArIHB5O1xuICAgICAgY29uc3QgbXkgPSBpeSAtIHN0cm9rZS5ieTtcbiAgICAgIGlmIChteSA8IDAgfHwgbXkgPj0gc3Ryb2tlLmJoKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHNyY1JvdyA9IHB5ICogVztcbiAgICAgIGNvbnN0IGRzdFJvdyA9IG15ICogc3Ryb2tlLmJ3O1xuICAgICAgZm9yIChsZXQgcHggPSAwOyBweCA8IFc7IHB4KyspIHtcbiAgICAgICAgaWYgKCFwYXRjaC5tYXNrW3NyY1JvdyArIHB4XSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IGl4ID0gcHgwICsgcHg7XG4gICAgICAgIGNvbnN0IG14ID0gaXggLSBzdHJva2UuYng7XG4gICAgICAgIGlmIChteCA8IDAgfHwgbXggPj0gc3Ryb2tlLmJ3KSBjb250aW51ZTtcbiAgICAgICAgaWYgKGVyYXNlKSBzdHJva2UubWFza1tkc3RSb3cgKyBteF0gPSAwO1xuICAgICAgICBlbHNlIHN0cm9rZS5tYXNrW2RzdFJvdyArIG14XSA9IDE7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFlcmFzZSkge1xuICAgICAgLy8gSWYgdGhlIGdyb3duIHN0cm9rZSBub3cgb3ZlcmxhcHMgYW5vdGhlciBwYXRoLXNoYXBlLCBmb2xkIHRob3NlXG4gICAgICAvLyBzaGFwZXMgaW50byB0aGlzIG9uZSBhbmQgZHJvcCB0aGVtIOKAlCBtYXRjaGluZyBRdVBhdGgnc1xuICAgICAgLy8gbWVyZ2Utb24tdG91Y2ggYmVoYXZpb3VyLlxuICAgICAgdGhpcy5tZXJnZU92ZXJsYXBwaW5nU2hhcGVzKHJlZ2lvbnMsIHJ4LCByeSwgY2FjaGVkKTtcbiAgICB9XG5cbiAgICAvLyBUcmFjZSB0aGUgdW5pb24gYm91bmRhcnkgaW4gaW1hZ2UtcGl4ZWwgY29vcmRzLlxuICAgIGNvbnN0IHN0cm9rZTIgPSB0aGlzLnN0cm9rZSE7XG4gICAgY29uc3QgcG9seSA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbihcbiAgICAgIHN0cm9rZTIubWFzayxcbiAgICAgIHN0cm9rZTIuYncsXG4gICAgICBzdHJva2UyLmJoLFxuICAgICAgY2FjaGVkLndpZHRoLFxuICAgICAgY2FjaGVkLmhlaWdodCxcbiAgICAgIHN0cm9rZTIuYngsXG4gICAgICBzdHJva2UyLmJ5LFxuICAgICk7XG5cbiAgICBpZiAoIXBvbHkpIHtcbiAgICAgIC8vIEVyYXNlZCB0byBub3RoaW5nIOKAlCByZW1vdmUgdGhlIHNoYXBlIGVudGlyZWx5LlxuICAgICAgaWYgKGVyYXNlKSB0aGlzLmRyb3BBY3RpdmVTaGFwZShyZWdpb25zKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0IGZyb20gbWF0cml4IGNvb3JkcyBiYWNrIHRvIHBsb3QgZGF0YSBjb29yZHMuXG4gICAgY29uc3QgeFBsb3QgPSBwb2x5Lnhwb2ludHMubWFwKCh4KSA9PiBveCArIHggKiByeCk7XG4gICAgY29uc3QgeVBsb3QgPSBwb2x5Lnlwb2ludHMubWFwKCh5KSA9PiBveSArIHkgKiByeSk7XG5cbiAgICB0aGlzLmNvbW1pdFN0cm9rZShyZWdpb25zLCB4UGxvdCwgeVBsb3QpO1xuICB9XG5cbiAgLyoqIFRydWUgaWYgKG1hdHJpeFgsIG1hdHJpeFkpIGxpZXMgaW5zaWRlIHRoZSBjdXJyZW50IHN0cm9rZSBhY2N1bXVsYXRvci4gKi9cbiAgcHJpdmF0ZSBwb2ludEluU3Ryb2tlKG1hdHJpeFg6IG51bWJlciwgbWF0cml4WTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgY29uc3QgcyA9IHRoaXMuc3Ryb2tlO1xuICAgIGlmICghcykgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IG14ID0gTWF0aC5mbG9vcihtYXRyaXhYKSAtIHMuYng7XG4gICAgY29uc3QgbXkgPSBNYXRoLmZsb29yKG1hdHJpeFkpIC0gcy5ieTtcbiAgICBpZiAobXggPCAwIHx8IG15IDwgMCB8fCBteCA+PSBzLmJ3IHx8IG15ID49IHMuYmgpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gcy5tYXNrW215ICogcy5idyArIG14XSA9PT0gMTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlIHJlZ2lvbiByZWZlcmVuY2VkIGJ5IGBzdHJva2VSZWdpb25JZGAgZnJvbSB0aGUgcmVnaW9uIGxpc3QgYW5kXG4gICAqIHJlc2V0IHRoZSBhY3RpdmUgc3Ryb2tlIOKAlCB1c2VkIHdoZW4gYW4gZXJhc2Ugc3Ryb2tlIGRlbGV0ZXMgZXZlcnkgcGl4ZWwuXG4gICAqL1xuICBwcml2YXRlIGRyb3BBY3RpdmVTaGFwZShyZWdpb25zOiBSZWdpb25bXSkge1xuICAgIGlmICh0aGlzLnN0cm9rZVJlZ2lvbklkICE9IG51bGwpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKTtcbiAgICAgIGlmIChpZHggPj0gMCkge1xuICAgICAgICByZWdpb25zLnNwbGljZShpZHgsIDEpO1xuICAgICAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYSByZWdpb24gY2FuIGJlIGZhaXRoZnVsbHkgcmFzdGVyaXplZCBpbnRvIHRoZSB3YW5kIHN0cm9rZSBhdCB0aGUgY3VycmVudCB2aWV3XG4gICAqIHJlc29sdXRpb24gKHJ4L3J5ID0gZGF0YSB1bml0cyBwZXIgbWF0cml4IHBpeGVsKS4gRWRpdGluZyByYXN0ZXJpemVzIHRoZSByZWdpb24gdG8gdGhlXG4gICAqIHZpZXdwb3J0IGdyaWQgYW5kIHJlLXRyYWNlcyBpdCwgc28gYSByZWdpb24gd2hvc2UgbWF0cml4LXNwYWNlIGJib3ggZXhjZWVkcyB0aGUgcmFzdGVyaXplcidzXG4gICAqIGNhcCB3b3VsZCBiZSBjbGlwcGVkL2Rvd24tcXVhbnRpemVkIGFuZCBjb21lIGJhY2sgcmVzY2FsZWQvY29ycnVwdGVkIChqaXQtdWkjMTAyKSDigJQgZS5nLiBhXG4gICAqIHdob2xlLXNsaWRlIGFubm90YXRpb24gd2hpbGUgem9vbWVkIG91dC4gU2tpcCBhZG9wdC9tZXJnZSBmb3IgdGhvc2U6IGxlYXZlIHRoZW0gdW50b3VjaGVkIGFuZFxuICAgKiBvbmx5IGVkaXQgdGhlbSBuZWFyIG5hdGl2ZSB6b29tLlxuICAgKi9cbiAgcHJpdmF0ZSBmaXRzRm9yRWRpdChcbiAgICB2ZXJ0czogeyB4cG9pbnRzOiBudW1iZXJbXTsgeXBvaW50czogbnVtYmVyW10gfSxcbiAgICByeDogbnVtYmVyLFxuICAgIHJ5OiBudW1iZXIsXG4gICk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHhzID0gdmVydHMueHBvaW50cztcbiAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHM7XG4gICAgbGV0IG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5O1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh4c1tpXSA8IG1pblgpIG1pblggPSB4c1tpXTtcbiAgICAgIGlmICh4c1tpXSA+IG1heFgpIG1heFggPSB4c1tpXTtcbiAgICAgIGlmICh5c1tpXSA8IG1pblkpIG1pblkgPSB5c1tpXTtcbiAgICAgIGlmICh5c1tpXSA+IG1heFkpIG1heFkgPSB5c1tpXTtcbiAgICB9XG4gICAgY29uc3QgdyA9IChtYXhYIC0gbWluWCkgLyAocnggfHwgMSk7XG4gICAgY29uc3QgaCA9IChtYXhZIC0gbWluWSkgLyAocnkgfHwgMSk7XG4gICAgcmV0dXJuIHcgPiAwICYmIGggPiAwICYmIHcgKiBoIDw9IDQwOTYgKiA0MDk2O1xuICB9XG5cbiAgLyoqIEEgcmVnaW9uJ3MgY2xvc2VkLXBvbHlnb24gdmVydGljZXMgKGltYWdlL2RhdGEgY29vcmRzKSwgb3IgbnVsbCB3aGVuIGl0XG4gICAqICBpc24ndCBhIGZpbGxhYmxlIGNsb3NlZCBwb2x5Z29uIChyZWN0YW5nbGVzLCBvcGVuIHBvbHlsaW5lcykuICovXG4gIHByaXZhdGUgcmVnaW9uVmVydHMoXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICk6IHsgeHBvaW50czogbnVtYmVyW107IHlwb2ludHM6IG51bWJlcltdOyBob2xlcz86IG51bWJlcltdW11bXSB9IHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbj8uYm91bmRzO1xuICAgIGlmIChiIGluc3RhbmNlb2YgUG9seWdvbiAmJiBiLmNsb3NlZCAhPT0gZmFsc2UgJiYgYi54cG9pbnRzLmxlbmd0aCA+PSAzKSB7XG4gICAgICByZXR1cm4geyB4cG9pbnRzOiBiLnhwb2ludHMsIHlwb2ludHM6IGIueXBvaW50cywgaG9sZXM6IGIuaG9sZXMgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQ29udmVydCBhIHJlZ2lvbidzIGhvbGUgcmluZ3MgZnJvbSBpbWFnZS9kYXRhIGNvb3JkcyBpbnRvIG1hdHJpeCBjb29yZHMgc29cbiAgICogIHRoZXkgbGluZSB1cCB3aXRoIHRoZSBzdHJva2UgYWNjdW11bGF0b3IgKGppdC11aSM4NSkuICovXG4gIHByaXZhdGUgaG9sZXNUb01hdHJpeChcbiAgICBob2xlczogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkLCBveDogbnVtYmVyLCBveTogbnVtYmVyLCByeDogbnVtYmVyLCByeTogbnVtYmVyLFxuICApOiBudW1iZXJbXVtdW10gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBob2xlcz8ubWFwKChyaW5nKSA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbKHggLSBveCkgLyByeCwgKHkgLSBveSkgLyByeV0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiAobWF0cml4WCwgbWF0cml4WSkgZmFsbHMgaW5zaWRlIGFuIGV4aXN0aW5nIHJlZ2lvbiwgcmFzdGVyaXplIGl0IGludG9cbiAgICogdGhlIHdhbmQgc3Ryb2tlIGFjY3VtdWxhdG9yIHNvIHN1YnNlcXVlbnQgd2FuZCBpbnB1dCBleHRlbmRzIGl0IHJhdGhlciB0aGFuXG4gICAqIHN0YXJ0aW5nIGEgbmV3IHJlZ2lvbi5cbiAgICovXG4gIHByaXZhdGUgdHJ5QWRvcHRTaGFwZUF0KFxuICAgIHJlZ2lvbnM6IFJlZ2lvbltdLFxuICAgIG1hdHJpeFg6IG51bWJlcixcbiAgICBtYXRyaXhZOiBudW1iZXIsXG4gICAgcng6IG51bWJlcixcbiAgICByeTogbnVtYmVyLFxuICAgIGNhY2hlZDogQ2FjaGVkSW1hZ2VEYXRhLFxuICApOiBib29sZWFuIHtcbiAgICBpZiAoIXJlZ2lvbnMgfHwgcmVnaW9ucy5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcblxuICAgIC8vIE1vc3QtcmVjZW50bHktYWRkZWQgcmVnaW9ucyBhcmUgb24gdG9wIOKAlCBjaGVjayB0aGVtIGZpcnN0LlxuICAgIGZvciAobGV0IGkgPSByZWdpb25zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBjb25zdCB2ZXJ0cyA9IHRoaXMucmVnaW9uVmVydHMocmVnaW9uc1tpXSk7XG4gICAgICBpZiAoIXZlcnRzKSBjb250aW51ZTtcbiAgICAgIC8vIFRvbyBsYXJnZSB0byByYXN0ZXJpemUgYXQgdGhpcyB6b29tIOKGkiBkb24ndCBhZG9wdCBpdCAoZWRpdGluZyB3b3VsZCByZXNjYWxlL2NvcnJ1cHQgaXQpLlxuICAgICAgaWYgKCF0aGlzLmZpdHNGb3JFZGl0KHZlcnRzLCByeCwgcnkpKSBjb250aW51ZTtcblxuICAgICAgY29uc3Qgb3ggPSBjYWNoZWQub3JpZ2luWCA/PyAwO1xuICAgICAgY29uc3Qgb3kgPSBjYWNoZWQub3JpZ2luWSA/PyAwO1xuICAgICAgY29uc3QgeHMgPSB2ZXJ0cy54cG9pbnRzLm1hcCgoeCkgPT4gKHggLSBveCkgLyByeCk7XG4gICAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHMubWFwKCh5KSA9PiAoeSAtIG95KSAvIHJ5KTtcbiAgICAgIGNvbnN0IGhvbGVzID0gdGhpcy5ob2xlc1RvTWF0cml4KHZlcnRzLmhvbGVzLCBveCwgb3ksIHJ4LCByeSk7XG5cbiAgICAgIC8vIENsaWNraW5nIGluc2lkZSBhIGhvbGUgbXVzdCBOT1QgYWRvcHQgdGhlIGRvbnV0IChpdCdzIGVtcHR5IHRoZXJlKS5cbiAgICAgIGlmICghdGhpcy53YW5kU2VydmljZS5wb2ludEluUG9seWdvbldpdGhIb2xlcyhtYXRyaXhYLCBtYXRyaXhZLCB4cywgeXMsIGhvbGVzKSkgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHJhc3RlciA9IHRoaXMud2FuZFNlcnZpY2UucmFzdGVyaXplUG9seWdvbih4cywgeXMsIGNhY2hlZC53aWR0aCwgY2FjaGVkLmhlaWdodCwgaG9sZXMpO1xuICAgICAgaWYgKCFyYXN0ZXIpIGNvbnRpbnVlO1xuXG4gICAgICB0aGlzLnN0cm9rZSA9IHJhc3RlcjtcbiAgICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSByZWdpb25zW2ldLmlkID8/IG51bGw7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEl0ZXJhdGUgZXZlcnkgcmVnaW9uOyBpZiBpdHMgcmFzdGVyaXplZCBtYXNrIG92ZXJsYXBzIHRoZSB3YW5kIHN0cm9rZSBtYXNrXG4gICAqIGJ5IGF0IGxlYXN0IG9uZSBwaXhlbCwgT1IgaXQgaW50byB0aGUgc3Ryb2tlIGFuZCByZW1vdmUgaXQgZnJvbSB0aGUgbGlzdC5cbiAgICogQ2FsbGVkIGV2ZXJ5IHRpY2sgc28gY2hhaW5lZCBtZXJnZXMgcmVzb2x2ZS4gSWYgdGhlIHdhbmQgaGFzIG5vIHJlZ2lvbiBpZFxuICAgKiB5ZXQsIHRoZSBtZXJnZWQgcmVnaW9uJ3MgaWQgaXMgYWRvcHRlZCBzbyB0aGUgbWVyZ2VkIHJlZ2lvbiByZXBsYWNlcyBpdC5cbiAgICovXG4gIHByaXZhdGUgbWVyZ2VPdmVybGFwcGluZ1NoYXBlcyhyZWdpb25zOiBSZWdpb25bXSwgcng6IG51bWJlciwgcnk6IG51bWJlciwgY2FjaGVkOiBDYWNoZWRJbWFnZURhdGEpIHtcbiAgICBpZiAoIXRoaXMuc3Ryb2tlKSByZXR1cm47XG4gICAgbGV0IGRpZE1lcmdlID0gdHJ1ZTtcbiAgICB3aGlsZSAoZGlkTWVyZ2UpIHtcbiAgICAgIGRpZE1lcmdlID0gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICBjb25zdCByZWdpb24gPSByZWdpb25zW2ldO1xuICAgICAgICBpZiAocmVnaW9uLmlkICE9IG51bGwgJiYgcmVnaW9uLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCB2ZXJ0cyA9IHRoaXMucmVnaW9uVmVydHMocmVnaW9uKTtcbiAgICAgICAgaWYgKCF2ZXJ0cykgY29udGludWU7XG4gICAgICAgIC8vIFRvbyBsYXJnZSB0byByYXN0ZXJpemUgYXQgdGhpcyB6b29tIOKGkiBkb24ndCBtZXJnZSBpdCAod291bGQgcmVzY2FsZS9jb3JydXB0IGl0KS5cbiAgICAgICAgaWYgKCF0aGlzLmZpdHNGb3JFZGl0KHZlcnRzLCByeCwgcnkpKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCBveCA9IGNhY2hlZC5vcmlnaW5YID8/IDA7XG4gICAgICAgIGNvbnN0IG95ID0gY2FjaGVkLm9yaWdpblkgPz8gMDtcbiAgICAgICAgY29uc3QgeHMgPSB2ZXJ0cy54cG9pbnRzLm1hcCgoeCkgPT4gKHggLSBveCkgLyByeCk7XG4gICAgICAgIGNvbnN0IHlzID0gdmVydHMueXBvaW50cy5tYXAoKHkpID0+ICh5IC0gb3kpIC8gcnkpO1xuXG4gICAgICAgIC8vIFF1aWNrIGJib3ggcmVqZWN0IGJlZm9yZSByYXN0ZXJpemluZy5cbiAgICAgICAgbGV0IG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5O1xuICAgICAgICBmb3IgKGxldCBrID0gMDsgayA8IHhzLmxlbmd0aDsgaysrKSB7XG4gICAgICAgICAgaWYgKHhzW2tdIDwgbWluWCkgbWluWCA9IHhzW2tdO1xuICAgICAgICAgIGlmICh4c1trXSA+IG1heFgpIG1heFggPSB4c1trXTtcbiAgICAgICAgICBpZiAoeXNba10gPCBtaW5ZKSBtaW5ZID0geXNba107XG4gICAgICAgICAgaWYgKHlzW2tdID4gbWF4WSkgbWF4WSA9IHlzW2tdO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHd4MCA9IHRoaXMuc3Ryb2tlLmJ4LCB3eTAgPSB0aGlzLnN0cm9rZS5ieTtcbiAgICAgICAgY29uc3Qgd3gxID0gd3gwICsgdGhpcy5zdHJva2UuYncsIHd5MSA9IHd5MCArIHRoaXMuc3Ryb2tlLmJoO1xuICAgICAgICBpZiAobWF4WCA8IHd4MCB8fCBtaW5YID4gd3gxIHx8IG1heFkgPCB3eTAgfHwgbWluWSA+IHd5MSkgY29udGludWU7XG5cbiAgICAgICAgY29uc3QgaG9sZXMgPSB0aGlzLmhvbGVzVG9NYXRyaXgodmVydHMuaG9sZXMsIG94LCBveSwgcngsIHJ5KTtcbiAgICAgICAgY29uc3QgcmFzdGVyID0gdGhpcy53YW5kU2VydmljZS5yYXN0ZXJpemVQb2x5Z29uKHhzLCB5cywgY2FjaGVkLndpZHRoLCBjYWNoZWQuaGVpZ2h0LCBob2xlcyk7XG4gICAgICAgIGlmICghcmFzdGVyKSBjb250aW51ZTtcblxuICAgICAgICBpZiAoIW1hc2tzT3ZlcmxhcCh0aGlzLnN0cm9rZSwgcmFzdGVyKSkgY29udGludWU7XG5cbiAgICAgICAgdGhpcy5zdHJva2UgPSB1bmlvbk1hc2tzKHRoaXMuc3Ryb2tlLCByYXN0ZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLnN0cm9rZVJlZ2lvbklkID09IG51bGwpIHtcbiAgICAgICAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gcmVnaW9uLmlkID8/IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmVnaW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIGRpZE1lcmdlID0gdHJ1ZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbW1pdCB0aGUgaW4tcHJvZ3Jlc3MgcG9seWdvbiBhcyBhIHJlZ2lvbiDigJQgYSBuZXcgcmVnaW9uIG9uIHRoZSBmaXJzdCB0aWNrXG4gICAqIG9mIGEgc3Ryb2tlLCBvciBhbiBpbi1wbGFjZSByZXBsYWNlbWVudCBvZiB0aGUgYWN0aXZlIHJlZ2lvbiBvbiBsYXRlciB0aWNrc1xuICAgKiDigJQgdGhlbiBhc2sgdGhlIGhvc3QgdG8gcmVuZGVyLiBUaGUgc3RvcmUgbWludHMgYW4gaWQgb24gdGhlIGZpcnN0IGNvbW1pdCxcbiAgICogd2hpY2ggd2UgYWRvcHQgc28gc3Vic2VxdWVudCB0aWNrcyByZXBsYWNlIHRoZSBzYW1lIHJlZ2lvbi5cbiAgICovXG4gIHByaXZhdGUgY29tbWl0U3Ryb2tlKHJlZ2lvbnM6IFJlZ2lvbltdLCB4UGxvdDogbnVtYmVyW10sIHlQbG90OiBudW1iZXJbXSkge1xuICAgIGlmICh4UGxvdC5sZW5ndGggPCAzKSByZXR1cm47XG5cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMuc3Ryb2tlUmVnaW9uSWQgIT0gbnVsbFxuICAgICAgPyByZWdpb25zLmZpbmQoKHIpID0+IHIuaWQgPT09IHRoaXMuc3Ryb2tlUmVnaW9uSWQpIDogbnVsbDtcblxuICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgIHBvbHkubnBvaW50cyA9IHhQbG90Lmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSB4UGxvdDtcbiAgICBwb2x5Lnlwb2ludHMgPSB5UGxvdDtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0geFBsb3QubWFwKCh4LCBpKSA9PiBbeCwgeVBsb3RbaV1dKTtcbiAgICBwb2x5LmNsb3NlZCA9IHRydWU7XG5cbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5ob3N0LmdldFNoYXBlQ29sb3IoKTtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIC8vIFByZXNlcnZlIGlkZW50aXR5ICsgY2xhc3MgbGFiZWwgYWNyb3NzIHRoZSBzdHJva2UncyBkcmFnIHRpY2tzLlxuICAgICAgcmVnaW9uLmlkID0gZXhpc3RpbmcuaWQ7XG4gICAgICByZWdpb24ubmFtZSA9IGV4aXN0aW5nLm5hbWU7XG4gICAgfVxuICAgIC8vIERlZmF1bHQgY2xhc3MvYW5ub3RhdGlvbiBuYW1lLCBtYXRjaGluZyB0aGUgb3ZlcmxheS1kcmF3biByZWdpb25zIGFuZCB0aGVcbiAgICAvLyBSZWdpb24gRWRpdG9yJ3MgXCJBZGRcIiBhY3Rpb25zIHNvIGEgd2FuZCByZWdpb24gaXNuJ3QgbGVmdCB1bmxhYmVsZWQuXG4gICAgcmVnaW9uLmxhYmVsID0gZXhpc3Rpbmc/LmxhYmVsID8/ICdSZWdpb24nO1xuXG4gICAgaWYgKHRoaXMuc3Ryb2tlUmVnaW9uSWQgPT0gbnVsbCkge1xuICAgICAgcmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKTtcbiAgICAgIGlmIChpZHggPj0gMCkgcmVnaW9uc1tpZHhdID0gcmVnaW9uO1xuICAgICAgZWxzZSByZWdpb25zLnB1c2gocmVnaW9uKTtcbiAgICB9XG5cbiAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICAvLyBUaGUgc3RvcmUgYXNzaWducyBhbiBpZCBvbiB0aGUgZmlyc3QgY29tbWl0IOKAlCBhZG9wdCBpdC5cbiAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gcmVnaW9uLmlkID8/IHRoaXMuc3Ryb2tlUmVnaW9uSWQ7XG4gIH1cbn1cbiJdfQ==
|