@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,847 @@
|
|
|
1
|
+
import { Subscription } from 'rxjs';
|
|
2
|
+
import { Region, Rectangle, Polygon } from '../../models/region';
|
|
3
|
+
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
4
|
+
/** Min drag (image px) before a freehand path records another point. */
|
|
5
|
+
const FREEHAND_STEP = 2;
|
|
6
|
+
/** Click-distance (screen px) within which a polygon click snaps closed onto the first vertex. */
|
|
7
|
+
const CLOSE_SNAP_PX = 10;
|
|
8
|
+
/** Screen-px hit radius for grabbing a vertex / rectangle corner handle. */
|
|
9
|
+
const HANDLE_HIT_PX = 9;
|
|
10
|
+
/** Rendered handle size (screen px). */
|
|
11
|
+
const HANDLE_SIZE = 7;
|
|
12
|
+
/**
|
|
13
|
+
* SVG region overlay for the napari-js WebGPU image view (jit-ui#102), mirroring the OSD backend's
|
|
14
|
+
* {@link OsdRegionOverlay} but driven by napari's `canvasToWorld`/`worldToCanvas` transforms.
|
|
15
|
+
* Vector shapes are drawn in an absolutely-positioned `<svg>` over the canvas (no need to push
|
|
16
|
+
* them through WebGPU). It writes completed shapes to the shared {@link RegionStore} (so save /
|
|
17
|
+
* undo / export work identically to OSD) and re-renders from the store on every camera move,
|
|
18
|
+
* region change, and selection change.
|
|
19
|
+
*
|
|
20
|
+
* Supports (jit-ui#102): rectangle / polygon / freehand path drawing, click-select and rubber-band
|
|
21
|
+
* marquee select, pan/zoom gating via `setControlsEnabled`, body move, vertex move/add/delete,
|
|
22
|
+
* bezier handle editing, and donut holes (including hole vertex + hole-bezier-handle editing) —
|
|
23
|
+
* full parity with {@link OsdRegionOverlay}.
|
|
24
|
+
*/
|
|
25
|
+
export class NapariRegionOverlay {
|
|
26
|
+
constructor(host, viewer, store) {
|
|
27
|
+
this.host = host;
|
|
28
|
+
this.viewer = viewer;
|
|
29
|
+
this.store = store;
|
|
30
|
+
this.subs = new Subscription();
|
|
31
|
+
this.mode = 'none';
|
|
32
|
+
this.selected = [];
|
|
33
|
+
/** In-progress drawing state (image-space). */
|
|
34
|
+
this.draftRect = null;
|
|
35
|
+
/** In-progress rubber-band selection marquee (select mode), image-space. */
|
|
36
|
+
this.marquee = null;
|
|
37
|
+
/** Dedicated marquee rect element, updated directly during the drag (no full region redraw). */
|
|
38
|
+
this.marqueeEl = null;
|
|
39
|
+
this.draftPath = null; // freehand or click polygon
|
|
40
|
+
this.drawing = false; // pointer is down for rect / freehand
|
|
41
|
+
/** In-progress manipulation (select/move modes): dragging a body, a polygon vertex, or a
|
|
42
|
+
* rectangle corner. `anchor` is the fixed opposite corner for a rectangle resize. */
|
|
43
|
+
this.edit = null;
|
|
44
|
+
// ── pointer handlers ──────────────────────────────────────────────────────
|
|
45
|
+
this.onPointerDown = (e) => {
|
|
46
|
+
if (this.mode === 'none')
|
|
47
|
+
return;
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
const [ix, iy] = this.toImage(e.clientX, e.clientY);
|
|
50
|
+
if (this.mode === 'drawrect') {
|
|
51
|
+
this.draftRect = { x0: ix, y0: iy, x1: ix, y1: iy };
|
|
52
|
+
this.drawing = true;
|
|
53
|
+
this.svg.setPointerCapture(e.pointerId);
|
|
54
|
+
}
|
|
55
|
+
else if (this.mode === 'drawclosedpath' || this.mode === 'drawopenpath') {
|
|
56
|
+
this.draftPath = [[ix, iy]];
|
|
57
|
+
this.drawing = true;
|
|
58
|
+
this.svg.setPointerCapture(e.pointerId);
|
|
59
|
+
}
|
|
60
|
+
else if (this.mode === 'drawpolygon') {
|
|
61
|
+
this.handlePolygonClick(ix, iy, e.clientX, e.clientY);
|
|
62
|
+
}
|
|
63
|
+
else if (this.mode === 'select' || this.mode === 'move') {
|
|
64
|
+
this.beginManipulation(ix, iy, e);
|
|
65
|
+
}
|
|
66
|
+
else if (this.mode === 'addpoint') {
|
|
67
|
+
this.handleAddPoint(ix, iy);
|
|
68
|
+
}
|
|
69
|
+
else if (this.mode === 'deletepoint') {
|
|
70
|
+
this.handleDeletePoint(ix, iy);
|
|
71
|
+
}
|
|
72
|
+
this.redraw();
|
|
73
|
+
};
|
|
74
|
+
this.onPointerMove = (e) => {
|
|
75
|
+
const [ix, iy] = this.toImage(e.clientX, e.clientY);
|
|
76
|
+
if (this.marquee) {
|
|
77
|
+
this.marquee.x1 = ix;
|
|
78
|
+
this.marquee.y1 = iy;
|
|
79
|
+
this.updateMarqueeEl(); // update just the marquee rect — NOT a full region redraw
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (this.edit) {
|
|
83
|
+
this.applyManipulation(ix, iy);
|
|
84
|
+
this.redraw();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!this.drawing)
|
|
88
|
+
return;
|
|
89
|
+
if (this.draftRect) {
|
|
90
|
+
this.draftRect.x1 = ix;
|
|
91
|
+
this.draftRect.y1 = iy;
|
|
92
|
+
}
|
|
93
|
+
else if (this.draftPath) {
|
|
94
|
+
const last = this.draftPath[this.draftPath.length - 1];
|
|
95
|
+
if (Math.abs(ix - last[0]) >= FREEHAND_STEP || Math.abs(iy - last[1]) >= FREEHAND_STEP) {
|
|
96
|
+
this.draftPath.push([ix, iy]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.redraw();
|
|
100
|
+
};
|
|
101
|
+
this.onPointerUp = (e) => {
|
|
102
|
+
if (this.marquee) {
|
|
103
|
+
const m = this.marquee;
|
|
104
|
+
this.marquee = null;
|
|
105
|
+
this.clearMarqueeEl();
|
|
106
|
+
try {
|
|
107
|
+
this.svg.releasePointerCapture(e.pointerId);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* already released */
|
|
111
|
+
}
|
|
112
|
+
this.finishMarquee(m); // setSelectedShapeIndices → one redraw via the selection subscription
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (this.edit) {
|
|
116
|
+
this.store.endBatch();
|
|
117
|
+
this.edit = null;
|
|
118
|
+
try {
|
|
119
|
+
this.svg.releasePointerCapture(e.pointerId);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
/* already released */
|
|
123
|
+
}
|
|
124
|
+
this.redraw();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!this.drawing)
|
|
128
|
+
return;
|
|
129
|
+
this.drawing = false;
|
|
130
|
+
try {
|
|
131
|
+
this.svg.releasePointerCapture(e.pointerId);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
/* capture may already be released */
|
|
135
|
+
}
|
|
136
|
+
if (this.draftRect) {
|
|
137
|
+
const { x0, y0, x1, y1 } = this.draftRect;
|
|
138
|
+
const x = Math.min(x0, x1);
|
|
139
|
+
const y = Math.min(y0, y1);
|
|
140
|
+
const w = Math.abs(x1 - x0);
|
|
141
|
+
const h = Math.abs(y1 - y0);
|
|
142
|
+
this.draftRect = null;
|
|
143
|
+
if (w >= 2 && h >= 2)
|
|
144
|
+
this.commitRectangle(x, y, w, h);
|
|
145
|
+
}
|
|
146
|
+
else if (this.draftPath) {
|
|
147
|
+
const pts = this.draftPath;
|
|
148
|
+
this.draftPath = null;
|
|
149
|
+
const closed = this.mode === 'drawclosedpath';
|
|
150
|
+
if (pts.length >= (closed ? 3 : 2))
|
|
151
|
+
this.commitPolygon(pts, closed);
|
|
152
|
+
}
|
|
153
|
+
this.redraw();
|
|
154
|
+
};
|
|
155
|
+
this.onDblClick = (e) => {
|
|
156
|
+
if (this.mode !== 'drawpolygon' || !this.draftPath)
|
|
157
|
+
return;
|
|
158
|
+
e.preventDefault();
|
|
159
|
+
const pts = this.draftPath;
|
|
160
|
+
this.draftPath = null;
|
|
161
|
+
if (pts.length >= 3)
|
|
162
|
+
this.commitPolygon(pts, true);
|
|
163
|
+
this.redraw();
|
|
164
|
+
};
|
|
165
|
+
if (getComputedStyle(host).position === 'static')
|
|
166
|
+
host.style.position = 'relative';
|
|
167
|
+
this.svg = document.createElementNS(SVG_NS, 'svg');
|
|
168
|
+
Object.assign(this.svg.style, {
|
|
169
|
+
position: 'absolute',
|
|
170
|
+
inset: '0',
|
|
171
|
+
width: '100%',
|
|
172
|
+
height: '100%',
|
|
173
|
+
zIndex: '20',
|
|
174
|
+
pointerEvents: 'none', // until a tool activates
|
|
175
|
+
touchAction: 'none',
|
|
176
|
+
});
|
|
177
|
+
this.host.appendChild(this.svg);
|
|
178
|
+
this.svg.addEventListener('pointerdown', this.onPointerDown);
|
|
179
|
+
this.svg.addEventListener('pointermove', this.onPointerMove);
|
|
180
|
+
this.svg.addEventListener('pointerup', this.onPointerUp);
|
|
181
|
+
this.svg.addEventListener('dblclick', this.onDblClick);
|
|
182
|
+
this.subs.add(this.store.getRegionUpdateEvent().subscribe(() => this.redraw()));
|
|
183
|
+
this.subs.add(this.store.getSelectedShapeIndices$().subscribe((idx) => {
|
|
184
|
+
this.selected = idx ?? [];
|
|
185
|
+
this.redraw();
|
|
186
|
+
}));
|
|
187
|
+
this.disconnectCamera = this.viewer.camera.changed.connect(() => this.redraw());
|
|
188
|
+
this.redraw();
|
|
189
|
+
}
|
|
190
|
+
// ── IRegionOverlay ────────────────────────────────────────────────────────
|
|
191
|
+
setMode(mode) {
|
|
192
|
+
this.mode = mode;
|
|
193
|
+
this.draftRect = null;
|
|
194
|
+
this.draftPath = null;
|
|
195
|
+
this.marquee = null;
|
|
196
|
+
this.clearMarqueeEl();
|
|
197
|
+
this.drawing = false;
|
|
198
|
+
// The overlay owns pointer/navigation gating: while a tool is active it captures the pointer
|
|
199
|
+
// and the napari camera controls are disabled; 'none' hands the pointer back for pan/zoom.
|
|
200
|
+
const active = mode !== 'none';
|
|
201
|
+
this.viewer.setControlsEnabled(!active);
|
|
202
|
+
this.svg.style.pointerEvents = active ? 'auto' : 'none';
|
|
203
|
+
this.svg.style.cursor = active ? 'crosshair' : 'default';
|
|
204
|
+
this.redraw();
|
|
205
|
+
}
|
|
206
|
+
setSelectedBezier(bezier) {
|
|
207
|
+
const sel = this.selectedRegion();
|
|
208
|
+
if (sel?.id != null)
|
|
209
|
+
this.store.setBezier(sel.id, bezier);
|
|
210
|
+
}
|
|
211
|
+
destroy() {
|
|
212
|
+
this.svg.removeEventListener('pointerdown', this.onPointerDown);
|
|
213
|
+
this.svg.removeEventListener('pointermove', this.onPointerMove);
|
|
214
|
+
this.svg.removeEventListener('pointerup', this.onPointerUp);
|
|
215
|
+
this.svg.removeEventListener('dblclick', this.onDblClick);
|
|
216
|
+
this.disconnectCamera();
|
|
217
|
+
this.subs.unsubscribe();
|
|
218
|
+
if (this.svg.parentNode)
|
|
219
|
+
this.svg.parentNode.removeChild(this.svg);
|
|
220
|
+
}
|
|
221
|
+
// ── coordinate transforms ─────────────────────────────────────────────────
|
|
222
|
+
/** Pointer client coords → rounded image coords. */
|
|
223
|
+
toImage(clientX, clientY) {
|
|
224
|
+
const [wx, wy] = this.viewer.canvasToWorld(clientX, clientY);
|
|
225
|
+
return [Math.round(wx), Math.round(wy)];
|
|
226
|
+
}
|
|
227
|
+
/** Image coords → SVG-local px (the svg overlays the canvas at the same client rect). */
|
|
228
|
+
toLocal(imgX, imgY) {
|
|
229
|
+
const [cx, cy] = this.viewer.worldToCanvas(imgX, imgY);
|
|
230
|
+
const r = this.svg.getBoundingClientRect();
|
|
231
|
+
return [cx - r.left, cy - r.top];
|
|
232
|
+
}
|
|
233
|
+
/** Click-to-place polygon: add a vertex, or close when clicking near the first one. */
|
|
234
|
+
handlePolygonClick(ix, iy, clientX, clientY) {
|
|
235
|
+
if (!this.draftPath) {
|
|
236
|
+
this.draftPath = [[ix, iy]];
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const [fx, fy] = this.toLocal(this.draftPath[0][0], this.draftPath[0][1]);
|
|
240
|
+
const r = this.svg.getBoundingClientRect();
|
|
241
|
+
const near = Math.hypot(clientX - r.left - fx, clientY - r.top - fy) <= CLOSE_SNAP_PX &&
|
|
242
|
+
this.draftPath.length >= 3;
|
|
243
|
+
if (near) {
|
|
244
|
+
const pts = this.draftPath;
|
|
245
|
+
this.draftPath = null;
|
|
246
|
+
this.commitPolygon(pts, true);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.draftPath.push([ix, iy]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** The currently-selected region (single selection), or null. */
|
|
253
|
+
selectedRegion() {
|
|
254
|
+
const regions = this.store.getRegions();
|
|
255
|
+
const i = this.selected[0];
|
|
256
|
+
return i != null && i >= 0 && i < regions.length ? regions[i] : null;
|
|
257
|
+
}
|
|
258
|
+
/** Screen distance (px) between a client point and an image coord. */
|
|
259
|
+
screenDist(clientX, clientY, imgX, imgY) {
|
|
260
|
+
const [lx, ly] = this.toLocal(imgX, imgY);
|
|
261
|
+
const r = this.svg.getBoundingClientRect();
|
|
262
|
+
return Math.hypot(clientX - r.left - lx, clientY - r.top - ly);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Start a select/move interaction: grab a handle (rectangle corner) or vertex of the already-
|
|
266
|
+
* selected region first; otherwise select the topmost region under the cursor and drag its body.
|
|
267
|
+
*/
|
|
268
|
+
beginManipulation(ix, iy, e) {
|
|
269
|
+
const sel = this.selectedRegion();
|
|
270
|
+
if (sel?.bounds) {
|
|
271
|
+
const grab = this.hitHandle(sel, e.clientX, e.clientY);
|
|
272
|
+
if (grab) {
|
|
273
|
+
this.store.beginBatch();
|
|
274
|
+
this.edit = { ...grab, id: sel.id, last: [ix, iy] };
|
|
275
|
+
this.svg.setPointerCapture(e.pointerId);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Hit-test bodies, topmost first (last drawn renders on top).
|
|
280
|
+
const regions = this.store.getRegions();
|
|
281
|
+
for (let i = regions.length - 1; i >= 0; i--) {
|
|
282
|
+
if (this.hitTest(regions[i], ix, iy)) {
|
|
283
|
+
this.store.selectRegion(regions[i]);
|
|
284
|
+
this.store.beginBatch();
|
|
285
|
+
this.edit = { kind: 'body', id: regions[i].id, last: [ix, iy] };
|
|
286
|
+
this.svg.setPointerCapture(e.pointerId);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Empty space: in select mode start a rubber-band marquee (selects the regions it covers on
|
|
291
|
+
// release); in move mode just clear the selection.
|
|
292
|
+
if (this.mode === 'select') {
|
|
293
|
+
this.marquee = { x0: ix, y0: iy, x1: ix, y1: iy };
|
|
294
|
+
this.updateMarqueeEl();
|
|
295
|
+
this.svg.setPointerCapture(e.pointerId);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
this.store.setSelectedShapeIndices([]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** Create/update the marquee rect element directly (avoids a full region redraw per move). */
|
|
302
|
+
updateMarqueeEl() {
|
|
303
|
+
if (!this.marquee)
|
|
304
|
+
return;
|
|
305
|
+
if (!this.marqueeEl || !this.marqueeEl.parentNode) {
|
|
306
|
+
this.marqueeEl = document.createElementNS(SVG_NS, 'rect');
|
|
307
|
+
this.marqueeEl.setAttribute('stroke', '#4da3ff');
|
|
308
|
+
this.marqueeEl.setAttribute('stroke-width', '1');
|
|
309
|
+
this.marqueeEl.setAttribute('stroke-dasharray', '4 3');
|
|
310
|
+
this.marqueeEl.setAttribute('fill', '#4da3ff');
|
|
311
|
+
this.marqueeEl.setAttribute('fill-opacity', '0.12');
|
|
312
|
+
this.marqueeEl.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
313
|
+
this.svg.appendChild(this.marqueeEl);
|
|
314
|
+
}
|
|
315
|
+
const { x0, y0, x1, y1 } = this.marquee;
|
|
316
|
+
const [lx, ly] = this.toLocal(Math.min(x0, x1), Math.min(y0, y1));
|
|
317
|
+
const [rx, ry] = this.toLocal(Math.max(x0, x1), Math.max(y0, y1));
|
|
318
|
+
this.marqueeEl.setAttribute('x', `${lx}`);
|
|
319
|
+
this.marqueeEl.setAttribute('y', `${ly}`);
|
|
320
|
+
this.marqueeEl.setAttribute('width', `${Math.abs(rx - lx)}`);
|
|
321
|
+
this.marqueeEl.setAttribute('height', `${Math.abs(ry - ly)}`);
|
|
322
|
+
}
|
|
323
|
+
/** Remove the marquee element from the SVG. */
|
|
324
|
+
clearMarqueeEl() {
|
|
325
|
+
if (this.marqueeEl?.parentNode)
|
|
326
|
+
this.marqueeEl.parentNode.removeChild(this.marqueeEl);
|
|
327
|
+
this.marqueeEl = null;
|
|
328
|
+
}
|
|
329
|
+
/** Test whether a client point grabs a rectangle corner or a polygon vertex of `region`. */
|
|
330
|
+
hitHandle(region, clientX, clientY) {
|
|
331
|
+
const b = region.bounds;
|
|
332
|
+
if (!b)
|
|
333
|
+
return null;
|
|
334
|
+
if ('width' in b && 'x' in b) {
|
|
335
|
+
const r = b;
|
|
336
|
+
const corners = [
|
|
337
|
+
[r.x, r.y, [r.x + r.width, r.y + r.height]],
|
|
338
|
+
[r.x + r.width, r.y, [r.x, r.y + r.height]],
|
|
339
|
+
[r.x, r.y + r.height, [r.x + r.width, r.y]],
|
|
340
|
+
[r.x + r.width, r.y + r.height, [r.x, r.y]],
|
|
341
|
+
];
|
|
342
|
+
for (const [cx, cy, anchor] of corners) {
|
|
343
|
+
if (this.screenDist(clientX, clientY, cx, cy) <= HANDLE_HIT_PX)
|
|
344
|
+
return { kind: 'corner', anchor };
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else if ('npoints' in b) {
|
|
348
|
+
const p = b;
|
|
349
|
+
// Bezier control points first (they sit off the anchors), so they're grabbable.
|
|
350
|
+
if (p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints) {
|
|
351
|
+
for (let i = 0; i < p.npoints; i++) {
|
|
352
|
+
const out = p.handlesOut[i];
|
|
353
|
+
const inn = p.handlesIn[i];
|
|
354
|
+
if (this.screenDist(clientX, clientY, p.xpoints[i] + out[0], p.ypoints[i] + out[1]) <= HANDLE_HIT_PX) {
|
|
355
|
+
return { kind: 'bezier', vertexIndex: i, side: 'out' };
|
|
356
|
+
}
|
|
357
|
+
if (this.screenDist(clientX, clientY, p.xpoints[i] + inn[0], p.ypoints[i] + inn[1]) <= HANDLE_HIT_PX) {
|
|
358
|
+
return { kind: 'bezier', vertexIndex: i, side: 'in' };
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (let i = 0; i < p.npoints; i++) {
|
|
363
|
+
if (this.screenDist(clientX, clientY, p.xpoints[i], p.ypoints[i]) <= HANDLE_HIT_PX) {
|
|
364
|
+
return { kind: 'vertex', vertexIndex: i };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
// Hole (donut) ring: bezier control points first, then the vertices.
|
|
368
|
+
const holes = p.holes ?? [];
|
|
369
|
+
const holeBezier = !!(p.bezier && p.holeHandlesIn && p.holeHandlesOut);
|
|
370
|
+
for (let hi = 0; hi < holes.length; hi++) {
|
|
371
|
+
const ring = holes[hi];
|
|
372
|
+
if (holeBezier && p.holeHandlesIn[hi] && p.holeHandlesOut[hi]) {
|
|
373
|
+
for (let vi = 0; vi < ring.length; vi++) {
|
|
374
|
+
const out = p.holeHandlesOut[hi][vi] ?? [0, 0];
|
|
375
|
+
const inn = p.holeHandlesIn[hi][vi] ?? [0, 0];
|
|
376
|
+
if (this.screenDist(clientX, clientY, ring[vi][0] + out[0], ring[vi][1] + out[1]) <= HANDLE_HIT_PX) {
|
|
377
|
+
return { kind: 'holebezier', holeIndex: hi, vertexIndex: vi, side: 'out' };
|
|
378
|
+
}
|
|
379
|
+
if (this.screenDist(clientX, clientY, ring[vi][0] + inn[0], ring[vi][1] + inn[1]) <= HANDLE_HIT_PX) {
|
|
380
|
+
return { kind: 'holebezier', holeIndex: hi, vertexIndex: vi, side: 'in' };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
for (let vi = 0; vi < ring.length; vi++) {
|
|
385
|
+
if (this.screenDist(clientX, clientY, ring[vi][0], ring[vi][1]) <= HANDLE_HIT_PX) {
|
|
386
|
+
return { kind: 'holevertex', holeIndex: hi, vertexIndex: vi };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
/** Apply the live drag for the active manipulation (image coords `ix,iy`). */
|
|
394
|
+
applyManipulation(ix, iy) {
|
|
395
|
+
if (!this.edit)
|
|
396
|
+
return;
|
|
397
|
+
if (this.edit.kind === 'body') {
|
|
398
|
+
const [lx, ly] = this.edit.last;
|
|
399
|
+
this.store.moveRegion(this.edit.id, ix - lx, iy - ly);
|
|
400
|
+
this.edit.last = [ix, iy];
|
|
401
|
+
}
|
|
402
|
+
else if (this.edit.kind === 'vertex' && this.edit.vertexIndex != null) {
|
|
403
|
+
this.store.moveVertex(this.edit.id, this.edit.vertexIndex, ix, iy);
|
|
404
|
+
}
|
|
405
|
+
else if (this.edit.kind === 'corner' && this.edit.anchor) {
|
|
406
|
+
const [ax, ay] = this.edit.anchor;
|
|
407
|
+
const rect = new Rectangle();
|
|
408
|
+
rect.x = Math.min(ax, ix);
|
|
409
|
+
rect.y = Math.min(ay, iy);
|
|
410
|
+
rect.width = Math.abs(ix - ax);
|
|
411
|
+
rect.height = Math.abs(iy - ay);
|
|
412
|
+
this.store.updateBounds(this.edit.id, rect);
|
|
413
|
+
}
|
|
414
|
+
else if (this.edit.kind === 'bezier' && this.edit.vertexIndex != null && this.edit.side) {
|
|
415
|
+
this.store.moveBezierHandle(this.edit.id, this.edit.vertexIndex, this.edit.side, ix, iy);
|
|
416
|
+
}
|
|
417
|
+
else if (this.edit.kind === 'holevertex' &&
|
|
418
|
+
this.edit.holeIndex != null &&
|
|
419
|
+
this.edit.vertexIndex != null) {
|
|
420
|
+
this.store.moveHoleVertex(this.edit.id, this.edit.holeIndex, this.edit.vertexIndex, ix, iy);
|
|
421
|
+
}
|
|
422
|
+
else if (this.edit.kind === 'holebezier' &&
|
|
423
|
+
this.edit.holeIndex != null &&
|
|
424
|
+
this.edit.vertexIndex != null &&
|
|
425
|
+
this.edit.side) {
|
|
426
|
+
this.store.moveHoleBezierHandle(this.edit.id, this.edit.holeIndex, this.edit.vertexIndex, this.edit.side, ix, iy);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/** addpoint mode: insert a vertex on the selected polygon's nearest edge at the click. */
|
|
430
|
+
handleAddPoint(ix, iy) {
|
|
431
|
+
const sel = this.selectedRegion();
|
|
432
|
+
const b = sel?.bounds;
|
|
433
|
+
if (!sel || !b || !('npoints' in b))
|
|
434
|
+
return;
|
|
435
|
+
const p = b;
|
|
436
|
+
let bestSeg = 0;
|
|
437
|
+
let bestD = Infinity;
|
|
438
|
+
const segs = p.closed === false ? p.npoints - 1 : p.npoints;
|
|
439
|
+
for (let s = 0; s < segs; s++) {
|
|
440
|
+
const j = (s + 1) % p.npoints;
|
|
441
|
+
const d = this.pointSegDist(ix, iy, p.xpoints[s], p.ypoints[s], p.xpoints[j], p.ypoints[j]);
|
|
442
|
+
if (d < bestD) {
|
|
443
|
+
bestD = d;
|
|
444
|
+
bestSeg = s;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
this.store.addVertex(sel.id, bestSeg, ix, iy);
|
|
448
|
+
}
|
|
449
|
+
/** deletepoint mode: remove the selected polygon's vertex nearest the click. */
|
|
450
|
+
handleDeletePoint(ix, iy) {
|
|
451
|
+
const sel = this.selectedRegion();
|
|
452
|
+
const b = sel?.bounds;
|
|
453
|
+
if (!sel || !b || !('npoints' in b))
|
|
454
|
+
return;
|
|
455
|
+
const p = b;
|
|
456
|
+
let best = -1;
|
|
457
|
+
let bestD = Infinity;
|
|
458
|
+
for (let i = 0; i < p.npoints; i++) {
|
|
459
|
+
const d = Math.hypot(p.xpoints[i] - ix, p.ypoints[i] - iy);
|
|
460
|
+
if (d < bestD) {
|
|
461
|
+
bestD = d;
|
|
462
|
+
best = i;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (best >= 0)
|
|
466
|
+
this.store.deleteVertex(sel.id, best);
|
|
467
|
+
}
|
|
468
|
+
/** Distance from point (px,py) to segment (ax,ay)-(bx,by), in image units. */
|
|
469
|
+
pointSegDist(px, py, ax, ay, bx, by) {
|
|
470
|
+
const dx = bx - ax;
|
|
471
|
+
const dy = by - ay;
|
|
472
|
+
const len2 = dx * dx + dy * dy || 1;
|
|
473
|
+
let t = ((px - ax) * dx + (py - ay) * dy) / len2;
|
|
474
|
+
t = Math.max(0, Math.min(1, t));
|
|
475
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
476
|
+
}
|
|
477
|
+
/** Finalize a rubber-band marquee: select every region whose bounding box it overlaps (a tiny
|
|
478
|
+
* marquee is treated as a click on empty space → clear the selection). */
|
|
479
|
+
finishMarquee(m) {
|
|
480
|
+
const x0 = Math.min(m.x0, m.x1);
|
|
481
|
+
const x1 = Math.max(m.x0, m.x1);
|
|
482
|
+
const y0 = Math.min(m.y0, m.y1);
|
|
483
|
+
const y1 = Math.max(m.y0, m.y1);
|
|
484
|
+
if (x1 - x0 < 3 && y1 - y0 < 3) {
|
|
485
|
+
this.store.setSelectedShapeIndices([]);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const indices = [];
|
|
489
|
+
this.store.getRegions().forEach((r, i) => {
|
|
490
|
+
if (r.isProfile?.())
|
|
491
|
+
return;
|
|
492
|
+
const bb = this.regionBBox(r);
|
|
493
|
+
if (bb && bb.x0 <= x1 && bb.x1 >= x0 && bb.y0 <= y1 && bb.y1 >= y0)
|
|
494
|
+
indices.push(i);
|
|
495
|
+
});
|
|
496
|
+
this.store.setSelectedShapeIndices(indices);
|
|
497
|
+
}
|
|
498
|
+
/** A region's bounding box in image coords (rectangle, polygon, or multipolygon), or null. */
|
|
499
|
+
regionBBox(region) {
|
|
500
|
+
const b = region.bounds;
|
|
501
|
+
if (!b)
|
|
502
|
+
return null;
|
|
503
|
+
if ('width' in b && 'x' in b) {
|
|
504
|
+
const r = b;
|
|
505
|
+
return { x0: r.x, y0: r.y, x1: r.x + r.width, y1: r.y + r.height };
|
|
506
|
+
}
|
|
507
|
+
const acc = { x0: Infinity, y0: Infinity, x1: -Infinity, y1: -Infinity };
|
|
508
|
+
const addRing = (xs, ys) => {
|
|
509
|
+
for (let i = 0; i < xs.length; i++) {
|
|
510
|
+
if (xs[i] < acc.x0)
|
|
511
|
+
acc.x0 = xs[i];
|
|
512
|
+
if (xs[i] > acc.x1)
|
|
513
|
+
acc.x1 = xs[i];
|
|
514
|
+
if (ys[i] < acc.y0)
|
|
515
|
+
acc.y0 = ys[i];
|
|
516
|
+
if (ys[i] > acc.y1)
|
|
517
|
+
acc.y1 = ys[i];
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
if ('npoints' in b) {
|
|
521
|
+
const p = b;
|
|
522
|
+
addRing(p.xpoints, p.ypoints);
|
|
523
|
+
}
|
|
524
|
+
else if ('polygons' in b) {
|
|
525
|
+
for (const p of b.polygons)
|
|
526
|
+
addRing(p.xpoints, p.ypoints);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
return isFinite(acc.x0) ? acc : null;
|
|
532
|
+
}
|
|
533
|
+
// ── shape commit ──────────────────────────────────────────────────────────
|
|
534
|
+
commitRectangle(x, y, width, height) {
|
|
535
|
+
const rect = new Rectangle();
|
|
536
|
+
rect.x = x;
|
|
537
|
+
rect.y = y;
|
|
538
|
+
rect.width = width;
|
|
539
|
+
rect.height = height;
|
|
540
|
+
const region = new Region();
|
|
541
|
+
region.bounds = rect;
|
|
542
|
+
region.color = this.store.getShapeColor();
|
|
543
|
+
this.store.addRegion(region);
|
|
544
|
+
}
|
|
545
|
+
commitPolygon(points, closed) {
|
|
546
|
+
const poly = new Polygon();
|
|
547
|
+
poly.npoints = points.length;
|
|
548
|
+
poly.xpoints = points.map((p) => p[0]);
|
|
549
|
+
poly.ypoints = points.map((p) => p[1]);
|
|
550
|
+
poly.coordinates = points.map((p) => [p[0], p[1]]);
|
|
551
|
+
poly.closed = closed;
|
|
552
|
+
const region = new Region();
|
|
553
|
+
region.bounds = poly;
|
|
554
|
+
region.color = this.store.getShapeColor();
|
|
555
|
+
region.label = 'Region';
|
|
556
|
+
this.store.addRegion(region);
|
|
557
|
+
}
|
|
558
|
+
// ── rendering ─────────────────────────────────────────────────────────────
|
|
559
|
+
hitTest(region, x, y) {
|
|
560
|
+
const b = region.bounds;
|
|
561
|
+
if (!b)
|
|
562
|
+
return false;
|
|
563
|
+
if ('width' in b && 'x' in b) {
|
|
564
|
+
const r = b;
|
|
565
|
+
return x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;
|
|
566
|
+
}
|
|
567
|
+
if ('npoints' in b) {
|
|
568
|
+
const p = b;
|
|
569
|
+
let inside = false;
|
|
570
|
+
for (let i = 0, j = p.npoints - 1; i < p.npoints; j = i++) {
|
|
571
|
+
const xi = p.xpoints[i];
|
|
572
|
+
const yi = p.ypoints[i];
|
|
573
|
+
const xj = p.xpoints[j];
|
|
574
|
+
const yj = p.ypoints[j];
|
|
575
|
+
if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi)
|
|
576
|
+
inside = !inside;
|
|
577
|
+
}
|
|
578
|
+
return inside;
|
|
579
|
+
}
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
redraw() {
|
|
583
|
+
while (this.svg.firstChild)
|
|
584
|
+
this.svg.removeChild(this.svg.firstChild);
|
|
585
|
+
const regions = this.store.getRegions();
|
|
586
|
+
regions.forEach((region, i) => {
|
|
587
|
+
if (region.isProfile?.())
|
|
588
|
+
return;
|
|
589
|
+
const isSel = this.selected.includes(i);
|
|
590
|
+
const el = this.buildRegionEl(region, isSel);
|
|
591
|
+
if (el)
|
|
592
|
+
this.svg.appendChild(el);
|
|
593
|
+
this.drawLabel(region);
|
|
594
|
+
if (isSel)
|
|
595
|
+
this.drawHandles(region);
|
|
596
|
+
});
|
|
597
|
+
this.drawDraft();
|
|
598
|
+
}
|
|
599
|
+
/** Draw a region's classification label at its top-left, when labels are enabled (matches OSD). */
|
|
600
|
+
drawLabel(region) {
|
|
601
|
+
if (!this.store.getShowShapeLabel() || region.isProfile?.())
|
|
602
|
+
return;
|
|
603
|
+
const label = region.label;
|
|
604
|
+
const b = region.bounds;
|
|
605
|
+
if (!label || !b)
|
|
606
|
+
return;
|
|
607
|
+
let ix;
|
|
608
|
+
let iy;
|
|
609
|
+
if ('width' in b && 'x' in b) {
|
|
610
|
+
ix = b.x;
|
|
611
|
+
iy = b.y;
|
|
612
|
+
}
|
|
613
|
+
else if ('npoints' in b) {
|
|
614
|
+
const p = b;
|
|
615
|
+
ix = p.xpoints.reduce((m, x) => Math.min(m, x), Infinity);
|
|
616
|
+
iy = p.ypoints.reduce((m, y) => Math.min(m, y), Infinity);
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
const [lx, ly] = this.toLocal(ix, iy);
|
|
622
|
+
const text = document.createElementNS(SVG_NS, 'text');
|
|
623
|
+
text.setAttribute('x', `${lx}`);
|
|
624
|
+
text.setAttribute('y', `${ly - 4}`);
|
|
625
|
+
text.setAttribute('fill', '#fff');
|
|
626
|
+
text.setAttribute('stroke', '#000');
|
|
627
|
+
text.setAttribute('stroke-width', '3');
|
|
628
|
+
text.setAttribute('paint-order', 'stroke');
|
|
629
|
+
text.setAttribute('font', '12px sans-serif');
|
|
630
|
+
text.setAttribute('pointer-events', 'none');
|
|
631
|
+
text.textContent = label;
|
|
632
|
+
this.svg.appendChild(text);
|
|
633
|
+
}
|
|
634
|
+
/** Draw grab handles for the selected region: rectangle corners or polygon vertices. */
|
|
635
|
+
drawHandles(region) {
|
|
636
|
+
const b = region.bounds;
|
|
637
|
+
if (!b)
|
|
638
|
+
return;
|
|
639
|
+
const stroke = region.color || this.store.getShapeColor() || '#00ffff';
|
|
640
|
+
const handle = (imgX, imgY) => {
|
|
641
|
+
const [lx, ly] = this.toLocal(imgX, imgY);
|
|
642
|
+
const el = document.createElementNS(SVG_NS, 'rect');
|
|
643
|
+
el.setAttribute('x', `${lx - HANDLE_SIZE / 2}`);
|
|
644
|
+
el.setAttribute('y', `${ly - HANDLE_SIZE / 2}`);
|
|
645
|
+
el.setAttribute('width', `${HANDLE_SIZE}`);
|
|
646
|
+
el.setAttribute('height', `${HANDLE_SIZE}`);
|
|
647
|
+
el.setAttribute('fill', '#fff');
|
|
648
|
+
el.setAttribute('stroke', stroke);
|
|
649
|
+
el.setAttribute('stroke-width', '1.5');
|
|
650
|
+
this.svg.appendChild(el);
|
|
651
|
+
};
|
|
652
|
+
if ('width' in b && 'x' in b) {
|
|
653
|
+
const r = b;
|
|
654
|
+
handle(r.x, r.y);
|
|
655
|
+
handle(r.x + r.width, r.y);
|
|
656
|
+
handle(r.x, r.y + r.height);
|
|
657
|
+
handle(r.x + r.width, r.y + r.height);
|
|
658
|
+
}
|
|
659
|
+
else if ('npoints' in b) {
|
|
660
|
+
const p = b;
|
|
661
|
+
const isBezier = p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints;
|
|
662
|
+
for (let i = 0; i < p.npoints; i++)
|
|
663
|
+
handle(p.xpoints[i], p.ypoints[i]);
|
|
664
|
+
for (const ring of p.holes ?? [])
|
|
665
|
+
for (const [hx, hy] of ring)
|
|
666
|
+
handle(hx, hy);
|
|
667
|
+
// Bezier regions also expose their tangent control points (circles) joined to the anchor
|
|
668
|
+
// by a thin line, matching the OSD overlay's editable bezier handles.
|
|
669
|
+
if (isBezier) {
|
|
670
|
+
const hIn = p.handlesIn;
|
|
671
|
+
const hOut = p.handlesOut;
|
|
672
|
+
for (let i = 0; i < p.npoints; i++) {
|
|
673
|
+
this.drawBezierHandle(p.xpoints[i], p.ypoints[i], hOut[i], stroke);
|
|
674
|
+
this.drawBezierHandle(p.xpoints[i], p.ypoints[i], hIn[i], stroke);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
// Donut hole bezier control handles.
|
|
678
|
+
if (p.bezier && p.holeHandlesIn && p.holeHandlesOut) {
|
|
679
|
+
(p.holes ?? []).forEach((ring, hi) => {
|
|
680
|
+
const hIn = p.holeHandlesIn[hi];
|
|
681
|
+
const hOut = p.holeHandlesOut[hi];
|
|
682
|
+
if (!hIn || !hOut)
|
|
683
|
+
return;
|
|
684
|
+
ring.forEach(([hx, hy], vi) => {
|
|
685
|
+
this.drawBezierHandle(hx, hy, hOut[vi], stroke);
|
|
686
|
+
this.drawBezierHandle(hx, hy, hIn[vi], stroke);
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
/** Draw one bezier control point (anchor + handle offset) as a small circle connected to its
|
|
693
|
+
* anchor by a tangent line. `handle` is the [dx,dy] offset from the anchor in image space. */
|
|
694
|
+
drawBezierHandle(ax, ay, handle, stroke) {
|
|
695
|
+
if (!handle || (handle[0] === 0 && handle[1] === 0))
|
|
696
|
+
return;
|
|
697
|
+
const [alx, aly] = this.toLocal(ax, ay);
|
|
698
|
+
const [hlx, hly] = this.toLocal(ax + handle[0], ay + handle[1]);
|
|
699
|
+
const line = document.createElementNS(SVG_NS, 'line');
|
|
700
|
+
line.setAttribute('x1', `${alx}`);
|
|
701
|
+
line.setAttribute('y1', `${aly}`);
|
|
702
|
+
line.setAttribute('x2', `${hlx}`);
|
|
703
|
+
line.setAttribute('y2', `${hly}`);
|
|
704
|
+
line.setAttribute('stroke', stroke);
|
|
705
|
+
line.setAttribute('stroke-width', '1');
|
|
706
|
+
line.setAttribute('stroke-opacity', '0.7');
|
|
707
|
+
this.svg.appendChild(line);
|
|
708
|
+
const dot = document.createElementNS(SVG_NS, 'circle');
|
|
709
|
+
dot.setAttribute('cx', `${hlx}`);
|
|
710
|
+
dot.setAttribute('cy', `${hly}`);
|
|
711
|
+
dot.setAttribute('r', `${HANDLE_SIZE / 2}`);
|
|
712
|
+
dot.setAttribute('fill', stroke);
|
|
713
|
+
dot.setAttribute('stroke', '#fff');
|
|
714
|
+
dot.setAttribute('stroke-width', '1');
|
|
715
|
+
this.svg.appendChild(dot);
|
|
716
|
+
}
|
|
717
|
+
buildRegionEl(region, isSelected) {
|
|
718
|
+
const b = region.bounds;
|
|
719
|
+
if (!b)
|
|
720
|
+
return null;
|
|
721
|
+
const stroke = region.color || this.store.getShapeColor() || '#00ffff';
|
|
722
|
+
if ('width' in b && 'x' in b) {
|
|
723
|
+
const r = b;
|
|
724
|
+
const [lx, ly] = this.toLocal(r.x, r.y);
|
|
725
|
+
const [rx, ry] = this.toLocal(r.x + r.width, r.y + r.height);
|
|
726
|
+
const el = document.createElementNS(SVG_NS, 'rect');
|
|
727
|
+
el.setAttribute('x', `${Math.min(lx, rx)}`);
|
|
728
|
+
el.setAttribute('y', `${Math.min(ly, ry)}`);
|
|
729
|
+
el.setAttribute('width', `${Math.abs(rx - lx)}`);
|
|
730
|
+
el.setAttribute('height', `${Math.abs(ry - ly)}`);
|
|
731
|
+
this.style(el, stroke, isSelected);
|
|
732
|
+
return el;
|
|
733
|
+
}
|
|
734
|
+
if ('npoints' in b) {
|
|
735
|
+
const p = b;
|
|
736
|
+
const isBezier = !!p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints;
|
|
737
|
+
const hasHoles = !!(p.holes && p.holes.length);
|
|
738
|
+
// Bezier or donut (holes) → a single <path>; holes use even-odd fill so they punch through.
|
|
739
|
+
if (isBezier || hasHoles) {
|
|
740
|
+
const el = document.createElementNS(SVG_NS, 'path');
|
|
741
|
+
el.setAttribute('d', this.polygonPathData(p, isBezier));
|
|
742
|
+
if (hasHoles)
|
|
743
|
+
el.setAttribute('fill-rule', 'evenodd');
|
|
744
|
+
this.style(el, stroke, isSelected);
|
|
745
|
+
return el;
|
|
746
|
+
}
|
|
747
|
+
const pts = p.xpoints
|
|
748
|
+
.map((_, i) => this.toLocal(p.xpoints[i], p.ypoints[i]).join(','))
|
|
749
|
+
.join(' ');
|
|
750
|
+
const el = document.createElementNS(SVG_NS, p.closed === false ? 'polyline' : 'polygon');
|
|
751
|
+
el.setAttribute('points', pts);
|
|
752
|
+
this.style(el, stroke, isSelected);
|
|
753
|
+
return el;
|
|
754
|
+
}
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
/** Path data for a polygon: the exterior ring (bezier or straight) plus any holes (bezier when
|
|
758
|
+
* the donut carries hole handles, else straight) as sub-paths — even-odd fill cuts them out. */
|
|
759
|
+
polygonPathData(p, isBezier) {
|
|
760
|
+
let d = isBezier
|
|
761
|
+
? this.ringBezierPath(p.xpoints, p.ypoints, p.handlesIn, p.handlesOut, p.closed !== false)
|
|
762
|
+
: this.straightPath(p.xpoints, p.ypoints, p.closed !== false);
|
|
763
|
+
const holeBezier = !!(p.bezier && p.holeHandlesIn && p.holeHandlesOut);
|
|
764
|
+
(p.holes ?? []).forEach((ring, hi) => {
|
|
765
|
+
if (ring.length < 3)
|
|
766
|
+
return;
|
|
767
|
+
const xs = ring.map((pt) => pt[0]);
|
|
768
|
+
const ys = ring.map((pt) => pt[1]);
|
|
769
|
+
if (holeBezier && p.holeHandlesIn[hi] && p.holeHandlesOut[hi]) {
|
|
770
|
+
d += ' ' + this.ringBezierPath(xs, ys, p.holeHandlesIn[hi], p.holeHandlesOut[hi], true);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
d += ' ' + this.straightPath(xs, ys, true);
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
return d;
|
|
777
|
+
}
|
|
778
|
+
/** SVG path data for a straight ring/polyline in image coords (closed appends `Z`). */
|
|
779
|
+
straightPath(xs, ys, closed) {
|
|
780
|
+
let d = '';
|
|
781
|
+
for (let i = 0; i < xs.length; i++) {
|
|
782
|
+
const [lx, ly] = this.toLocal(xs[i], ys[i]);
|
|
783
|
+
d += (i === 0 ? 'M' : ' L') + ` ${lx},${ly}`;
|
|
784
|
+
}
|
|
785
|
+
return closed ? d + ' Z' : d;
|
|
786
|
+
}
|
|
787
|
+
/** SVG cubic-bezier path data for any ring (exterior or hole): anchors joined by cubic segments
|
|
788
|
+
* whose control points are `anchor + handleOut` (leaving) and `nextAnchor + handleIn` (arriving),
|
|
789
|
+
* in image space. Used for both the exterior and (donut) hole rings. */
|
|
790
|
+
ringBezierPath(xs, ys, hIn, hOut, closed) {
|
|
791
|
+
const n = xs.length;
|
|
792
|
+
const anchor = (i) => this.toLocal(xs[i], ys[i]);
|
|
793
|
+
const ctrlOut = (i) => this.toLocal(xs[i] + (hOut[i]?.[0] ?? 0), ys[i] + (hOut[i]?.[1] ?? 0));
|
|
794
|
+
const ctrlIn = (i) => this.toLocal(xs[i] + (hIn[i]?.[0] ?? 0), ys[i] + (hIn[i]?.[1] ?? 0));
|
|
795
|
+
const [sx, sy] = anchor(0);
|
|
796
|
+
let d = `M ${sx},${sy}`;
|
|
797
|
+
const segments = closed ? n : n - 1;
|
|
798
|
+
for (let s = 0; s < segments; s++) {
|
|
799
|
+
const i = s;
|
|
800
|
+
const j = (s + 1) % n;
|
|
801
|
+
const [c1x, c1y] = ctrlOut(i);
|
|
802
|
+
const [c2x, c2y] = ctrlIn(j);
|
|
803
|
+
const [ex, ey] = anchor(j);
|
|
804
|
+
d += ` C ${c1x},${c1y} ${c2x},${c2y} ${ex},${ey}`;
|
|
805
|
+
}
|
|
806
|
+
if (closed)
|
|
807
|
+
d += ' Z';
|
|
808
|
+
return d;
|
|
809
|
+
}
|
|
810
|
+
style(el, stroke, isSelected) {
|
|
811
|
+
el.setAttribute('stroke', stroke);
|
|
812
|
+
el.setAttribute('stroke-width', isSelected ? '4' : '2');
|
|
813
|
+
el.setAttribute('fill', isSelected ? stroke : 'none');
|
|
814
|
+
el.setAttribute('fill-opacity', isSelected ? '0.35' : '0');
|
|
815
|
+
el.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
816
|
+
}
|
|
817
|
+
/** Draw the in-progress rectangle / path preview. */
|
|
818
|
+
drawDraft() {
|
|
819
|
+
if (this.draftRect) {
|
|
820
|
+
const { x0, y0, x1, y1 } = this.draftRect;
|
|
821
|
+
const [lx, ly] = this.toLocal(Math.min(x0, x1), Math.min(y0, y1));
|
|
822
|
+
const [rx, ry] = this.toLocal(Math.max(x0, x1), Math.max(y0, y1));
|
|
823
|
+
const el = document.createElementNS(SVG_NS, 'rect');
|
|
824
|
+
el.setAttribute('x', `${lx}`);
|
|
825
|
+
el.setAttribute('y', `${ly}`);
|
|
826
|
+
el.setAttribute('width', `${Math.abs(rx - lx)}`);
|
|
827
|
+
el.setAttribute('height', `${Math.abs(ry - ly)}`);
|
|
828
|
+
this.styleDraft(el);
|
|
829
|
+
this.svg.appendChild(el);
|
|
830
|
+
}
|
|
831
|
+
if (this.draftPath && this.draftPath.length) {
|
|
832
|
+
const pts = this.draftPath.map(([x, y]) => this.toLocal(x, y).join(',')).join(' ');
|
|
833
|
+
const el = document.createElementNS(SVG_NS, 'polyline');
|
|
834
|
+
el.setAttribute('points', pts);
|
|
835
|
+
this.styleDraft(el);
|
|
836
|
+
this.svg.appendChild(el);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
styleDraft(el) {
|
|
840
|
+
el.setAttribute('stroke', this.store.getShapeColor() || '#00ffff');
|
|
841
|
+
el.setAttribute('stroke-width', '2');
|
|
842
|
+
el.setAttribute('stroke-dasharray', '4 3');
|
|
843
|
+
el.setAttribute('fill', 'none');
|
|
844
|
+
el.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXJlZ2lvbi1vdmVybGF5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvbmFwYXJpLWpzL25hcGFyaS1yZWdpb24tb3ZlcmxheS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBR3BDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR2pFLE1BQU0sTUFBTSxHQUFHLDRCQUE0QixDQUFDO0FBQzVDLHdFQUF3RTtBQUN4RSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQUM7QUFDeEIsa0dBQWtHO0FBQ2xHLE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztBQUN6Qiw0RUFBNEU7QUFDNUUsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLHdDQUF3QztBQUN4QyxNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFVdEI7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxPQUFPLG1CQUFtQjtJQTZCOUIsWUFDbUIsSUFBaUIsRUFDakIsTUFBcUIsRUFDckIsS0FBa0I7UUFGbEIsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3JCLFVBQUssR0FBTCxLQUFLLENBQWE7UUE5QnBCLFNBQUksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBR25DLFNBQUksR0FBbUIsTUFBTSxDQUFDO1FBQzlCLGFBQVEsR0FBYSxFQUFFLENBQUM7UUFFaEMsK0NBQStDO1FBQ3ZDLGNBQVMsR0FBOEQsSUFBSSxDQUFDO1FBQ3BGLDRFQUE0RTtRQUNwRSxZQUFPLEdBQThELElBQUksQ0FBQztRQUNsRixnR0FBZ0c7UUFDeEYsY0FBUyxHQUEwQixJQUFJLENBQUM7UUFDeEMsY0FBUyxHQUFtQyxJQUFJLENBQUMsQ0FBQyw0QkFBNEI7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YUFBYSxFQUFFLElBQUksU0FBUyxDQUFDLENBQUM7UUFDbkUsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDckMsRUFBRSxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzQyxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNoQyxFQUFFLENBQUMsWUFBWSxDQUFDLGVBQWUsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJUmVnaW9uT3ZlcmxheSwgUmVnaW9uVG9vbE1vZGUgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcmVnaW9uLW92ZXJsYXkuY29udHJhY3QnO1xuaW1wb3J0IHsgUmVnaW9uLCBSZWN0YW5nbGUsIFBvbHlnb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vLi4vc3RvcmUvcmVnaW9uLXN0b3JlLnNlcnZpY2UnO1xuXG5jb25zdCBTVkdfTlMgPSAnaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnO1xuLyoqIE1pbiBkcmFnIChpbWFnZSBweCkgYmVmb3JlIGEgZnJlZWhhbmQgcGF0aCByZWNvcmRzIGFub3RoZXIgcG9pbnQuICovXG5jb25zdCBGUkVFSEFORF9TVEVQID0gMjtcbi8qKiBDbGljay1kaXN0YW5jZSAoc2NyZWVuIHB4KSB3aXRoaW4gd2hpY2ggYSBwb2x5Z29uIGNsaWNrIHNuYXBzIGNsb3NlZCBvbnRvIHRoZSBmaXJzdCB2ZXJ0ZXguICovXG5jb25zdCBDTE9TRV9TTkFQX1BYID0gMTA7XG4vKiogU2NyZWVuLXB4IGhpdCByYWRpdXMgZm9yIGdyYWJiaW5nIGEgdmVydGV4IC8gcmVjdGFuZ2xlIGNvcm5lciBoYW5kbGUuICovXG5jb25zdCBIQU5ETEVfSElUX1BYID0gOTtcbi8qKiBSZW5kZXJlZCBoYW5kbGUgc2l6ZSAoc2NyZWVuIHB4KS4gKi9cbmNvbnN0IEhBTkRMRV9TSVpFID0gNztcblxuLyoqIFRoZSBzbGljZSBvZiB0aGUgbmFwYXJpIFZpZXdlciB0aGUgb3ZlcmxheSBuZWVkcyAoY29vcmQgdHJhbnNmb3JtcyArIGNvbnRyb2wgZ2F0aW5nKS4gKi9cbmludGVyZmFjZSBPdmVybGF5Vmlld2VyIHtcbiAgY2FudmFzVG9Xb3JsZChjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl07XG4gIHdvcmxkVG9DYW52YXMod29ybGRYOiBudW1iZXIsIHdvcmxkWTogbnVtYmVyKTogW251bWJlciwgbnVtYmVyXTtcbiAgc2V0Q29udHJvbHNFbmFibGVkKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkO1xuICByZWFkb25seSBjYW1lcmE6IHsgcmVhZG9ubHkgY2hhbmdlZDogeyBjb25uZWN0KGxpc3RlbmVyOiAoKSA9PiB2b2lkKTogKCkgPT4gdm9pZCB9IH07XG59XG5cbi8qKlxuICogU1ZHIHJlZ2lvbiBvdmVybGF5IGZvciB0aGUgbmFwYXJpLWpzIFdlYkdQVSBpbWFnZSB2aWV3IChqaXQtdWkjMTAyKSwgbWlycm9yaW5nIHRoZSBPU0QgYmFja2VuZCdzXG4gKiB7QGxpbmsgT3NkUmVnaW9uT3ZlcmxheX0gYnV0IGRyaXZlbiBieSBuYXBhcmkncyBgY2FudmFzVG9Xb3JsZGAvYHdvcmxkVG9DYW52YXNgIHRyYW5zZm9ybXMuXG4gKiBWZWN0b3Igc2hhcGVzIGFyZSBkcmF3biBpbiBhbiBhYnNvbHV0ZWx5LXBvc2l0aW9uZWQgYDxzdmc+YCBvdmVyIHRoZSBjYW52YXMgKG5vIG5lZWQgdG8gcHVzaFxuICogdGhlbSB0aHJvdWdoIFdlYkdQVSkuIEl0IHdyaXRlcyBjb21wbGV0ZWQgc2hhcGVzIHRvIHRoZSBzaGFyZWQge0BsaW5rIFJlZ2lvblN0b3JlfSAoc28gc2F2ZSAvXG4gKiB1bmRvIC8gZXhwb3J0IHdvcmsgaWRlbnRpY2FsbHkgdG8gT1NEKSBhbmQgcmUtcmVuZGVycyBmcm9tIHRoZSBzdG9yZSBvbiBldmVyeSBjYW1lcmEgbW92ZSxcbiAqIHJlZ2lvbiBjaGFuZ2UsIGFuZCBzZWxlY3Rpb24gY2hhbmdlLlxuICpcbiAqIFN1cHBvcnRzIChqaXQtdWkjMTAyKTogcmVjdGFuZ2xlIC8gcG9seWdvbiAvIGZyZWVoYW5kIHBhdGggZHJhd2luZywgY2xpY2stc2VsZWN0IGFuZCBydWJiZXItYmFuZFxuICogbWFycXVlZSBzZWxlY3QsIHBhbi96b29tIGdhdGluZyB2aWEgYHNldENvbnRyb2xzRW5hYmxlZGAsIGJvZHkgbW92ZSwgdmVydGV4IG1vdmUvYWRkL2RlbGV0ZSxcbiAqIGJlemllciBoYW5kbGUgZWRpdGluZywgYW5kIGRvbnV0IGhvbGVzIChpbmNsdWRpbmcgaG9sZSB2ZXJ0ZXggKyBob2xlLWJlemllci1oYW5kbGUgZWRpdGluZykg4oCUXG4gKiBmdWxsIHBhcml0eSB3aXRoIHtAbGluayBPc2RSZWdpb25PdmVybGF5fS5cbiAqL1xuZXhwb3J0IGNsYXNzIE5hcGFyaVJlZ2lvbk92ZXJsYXkgaW1wbGVtZW50cyBJUmVnaW9uT3ZlcmxheSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3ZnOiBTVkdTVkdFbGVtZW50O1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGlzY29ubmVjdENhbWVyYTogKCkgPT4gdm9pZDtcblxuICBwcml2YXRlIG1vZGU6IFJlZ2lvblRvb2xNb2RlID0gJ25vbmUnO1xuICBwcml2YXRlIHNlbGVjdGVkOiBudW1iZXJbXSA9IFtdO1xuXG4gIC8qKiBJbi1wcm9ncmVzcyBkcmF3aW5nIHN0YXRlIChpbWFnZS1zcGFjZSkuICovXG4gIHByaXZhdGUgZHJhZnRSZWN0OiB7IHgwOiBudW1iZXI7IHkwOiBudW1iZXI7IHgxOiBudW1iZXI7IHkxOiBudW1iZXIgfSB8IG51bGwgPSBudWxsO1xuICAvKiogSW4tcHJvZ3Jlc3MgcnViYmVyLWJhbmQgc2VsZWN0aW9uIG1hcnF1ZWUgKHNlbGVjdCBtb2RlKSwgaW1hZ2Utc3BhY2UuICovXG4gIHByaXZhdGUgbWFycXVlZTogeyB4MDogbnVtYmVyOyB5MDogbnVtYmVyOyB4MTogbnVtYmVyOyB5MTogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIERlZGljYXRlZCBtYXJxdWVlIHJlY3QgZWxlbWVudCwgdXBkYXRlZCBkaXJlY3RseSBkdXJpbmcgdGhlIGRyYWcgKG5vIGZ1bGwgcmVnaW9uIHJlZHJhdykuICovXG4gIHByaXZhdGUgbWFycXVlZUVsOiBTVkdSZWN0RWxlbWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRyYWZ0UGF0aDogQXJyYXk8W251bWJlciwgbnVtYmVyXT4gfCBudWxsID0gbnVsbDsgLy8gZnJlZWhhbmQgb3IgY2xpY2sgcG9seWdvblxuICBwcml2YXRlIGRyYXdpbmcgPSBmYWxzZTsgLy8gcG9pbnRlciBpcyBkb3duIGZvciByZWN0IC8gZnJlZWhhbmRcblxuICAvKiogSW4tcHJvZ3Jlc3MgbWFuaXB1bGF0aW9uIChzZWxlY3QvbW92ZSBtb2Rlcyk6IGRyYWdnaW5nIGEgYm9keSwgYSBwb2x5Z29uIHZlcnRleCwgb3IgYVxuICAgKiAgcmVjdGFuZ2xlIGNvcm5lci4gYGFuY2hvcmAgaXMgdGhlIGZpeGVkIG9wcG9zaXRlIGNvcm5lciBmb3IgYSByZWN0YW5nbGUgcmVzaXplLiAqL1xuICBwcml2YXRlIGVkaXQ6IHtcbiAgICBraW5kOiAnYm9keScgfCAndmVydGV4JyB8ICdjb3JuZXInIHwgJ2JlemllcicgfCAnaG9sZXZlcnRleCcgfCAnaG9sZWJlemllcic7XG4gICAgaWQ6IG51bWJlcjtcbiAgICB2ZXJ0ZXhJbmRleD86IG51bWJlcjtcbiAgICBob2xlSW5kZXg/OiBudW1iZXI7XG4gICAgc2lkZT86ICdpbicgfCAnb3V0JztcbiAgICBhbmNob3I/OiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIGxhc3Q6IFtudW1iZXIsIG51bWJlcl07XG4gIH0gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IEhUTUxFbGVtZW50LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdmlld2VyOiBPdmVybGF5Vmlld2VyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RvcmU6IFJlZ2lvblN0b3JlLFxuICApIHtcbiAgICBpZiAoZ2V0Q29tcHV0ZWRTdHlsZShob3N0KS5wb3NpdGlvbiA9PT0gJ3N0YXRpYycpIGhvc3Quc3R5bGUucG9zaXRpb24gPSAncmVsYXRpdmUnO1xuICAgIHRoaXMuc3ZnID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3N2ZycpO1xuICAgIE9iamVjdC5hc3NpZ24odGhpcy5zdmcuc3R5bGUsIHtcbiAgICAgIHBvc2l0aW9uOiAnYWJzb2x1dGUnLFxuICAgICAgaW5zZXQ6ICcwJyxcbiAgICAgIHdpZHRoOiAnMTAwJScsXG4gICAgICBoZWlnaHQ6ICcxMDAlJyxcbiAgICAgIHpJbmRleDogJzIwJyxcbiAgICAgIHBvaW50ZXJFdmVudHM6ICdub25lJywgLy8gdW50aWwgYSB0b29sIGFjdGl2YXRlc1xuICAgICAgdG91Y2hBY3Rpb246ICdub25lJyxcbiAgICB9IGFzIFBhcnRpYWw8Q1NTU3R5bGVEZWNsYXJhdGlvbj4pO1xuICAgIHRoaXMuaG9zdC5hcHBlbmRDaGlsZCh0aGlzLnN2Zyk7XG5cbiAgICB0aGlzLnN2Zy5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsIHRoaXMub25Qb2ludGVyRG93bik7XG4gICAgdGhpcy5zdmcuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCB0aGlzLm9uUG9pbnRlck1vdmUpO1xuICAgIHRoaXMuc3ZnLmFkZEV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJ1cCcsIHRoaXMub25Qb2ludGVyVXApO1xuICAgIHRoaXMuc3ZnLmFkZEV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgdGhpcy5vbkRibENsaWNrKTtcblxuICAgIHRoaXMuc3Vicy5hZGQodGhpcy5zdG9yZS5nZXRSZWdpb25VcGRhdGVFdmVudCgpLnN1YnNjcmliZSgoKSA9PiB0aGlzLnJlZHJhdygpKSk7XG4gICAgdGhpcy5zdWJzLmFkZChcbiAgICAgIHRoaXMuc3RvcmUuZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCkuc3Vic2NyaWJlKChpZHgpID0+IHtcbiAgICAgICAgdGhpcy5zZWxlY3RlZCA9IGlkeCA/PyBbXTtcbiAgICAgICAgdGhpcy5yZWRyYXcoKTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5kaXNjb25uZWN0Q2FtZXJhID0gdGhpcy52aWV3ZXIuY2FtZXJhLmNoYW5nZWQuY29ubmVjdCgoKSA9PiB0aGlzLnJlZHJhdygpKTtcbiAgICB0aGlzLnJlZHJhdygpO1xuICB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25PdmVybGF5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBzZXRNb2RlKG1vZGU6IFJlZ2lvblRvb2xNb2RlKTogdm9pZCB7XG4gICAgdGhpcy5tb2RlID0gbW9kZTtcbiAgICB0aGlzLmRyYWZ0UmVjdCA9IG51bGw7XG4gICAgdGhpcy5kcmFmdFBhdGggPSBudWxsO1xuICAgIHRoaXMubWFycXVlZSA9IG51bGw7XG4gICAgdGhpcy5jbGVhck1hcnF1ZWVFbCgpO1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuICAgIC8vIFRoZSBvdmVybGF5IG93bnMgcG9pbnRlci9uYXZpZ2F0aW9uIGdhdGluZzogd2hpbGUgYSB0b29sIGlzIGFjdGl2ZSBpdCBjYXB0dXJlcyB0aGUgcG9pbnRlclxuICAgIC8vIGFuZCB0aGUgbmFwYXJpIGNhbWVyYSBjb250cm9scyBhcmUgZGlzYWJsZWQ7ICdub25lJyBoYW5kcyB0aGUgcG9pbnRlciBiYWNrIGZvciBwYW4vem9vbS5cbiAgICBjb25zdCBhY3RpdmUgPSBtb2RlICE9PSAnbm9uZSc7XG4gICAgdGhpcy52aWV3ZXIuc2V0Q29udHJvbHNFbmFibGVkKCFhY3RpdmUpO1xuICAgIHRoaXMuc3ZnLnN0eWxlLnBvaW50ZXJFdmVudHMgPSBhY3RpdmUgPyAnYXV0bycgOiAnbm9uZSc7XG4gICAgdGhpcy5zdmcuc3R5bGUuY3Vyc29yID0gYWN0aXZlID8gJ2Nyb3NzaGFpcicgOiAnZGVmYXVsdCc7XG4gICAgdGhpcy5yZWRyYXcoKTtcbiAgfVxuXG4gIHNldFNlbGVjdGVkQmV6aWVyKGJlemllcjogYm9vbGVhbik6IHZvaWQge1xuICAgIGNvbnN0IHNlbCA9IHRoaXMuc2VsZWN0ZWRSZWdpb24oKTtcbiAgICBpZiAoc2VsPy5pZCAhPSBudWxsKSB0aGlzLnN0b3JlLnNldEJlemllcihzZWwuaWQsIGJlemllcik7XG4gIH1cblxuICBkZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3ZnLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJkb3duJywgdGhpcy5vblBvaW50ZXJEb3duKTtcbiAgICB0aGlzLnN2Zy5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIHRoaXMub25Qb2ludGVyTW92ZSk7XG4gICAgdGhpcy5zdmcucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywgdGhpcy5vblBvaW50ZXJVcCk7XG4gICAgdGhpcy5zdmcucmVtb3ZlRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCB0aGlzLm9uRGJsQ2xpY2spO1xuICAgIHRoaXMuZGlzY29ubmVjdENhbWVyYSgpO1xuICAgIHRoaXMuc3Vicy51bnN1YnNjcmliZSgpO1xuICAgIGlmICh0aGlzLnN2Zy5wYXJlbnROb2RlKSB0aGlzLnN2Zy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRoaXMuc3ZnKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBjb29yZGluYXRlIHRyYW5zZm9ybXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8qKiBQb2ludGVyIGNsaWVudCBjb29yZHMg4oaSIHJvdW5kZWQgaW1hZ2UgY29vcmRzLiAqL1xuICBwcml2YXRlIHRvSW1hZ2UoY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIpOiBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICBjb25zdCBbd3gsIHd5XSA9IHRoaXMudmlld2VyLmNhbnZhc1RvV29ybGQoY2xpZW50WCwgY2xpZW50WSk7XG4gICAgcmV0dXJuIFtNYXRoLnJvdW5kKHd4KSwgTWF0aC5yb3VuZCh3eSldO1xuICB9XG5cbiAgLyoqIEltYWdlIGNvb3JkcyDihpIgU1ZHLWxvY2FsIHB4ICh0aGUgc3ZnIG92ZXJsYXlzIHRoZSBjYW52YXMgYXQgdGhlIHNhbWUgY2xpZW50IHJlY3QpLiAqL1xuICBwcml2YXRlIHRvTG9jYWwoaW1nWDogbnVtYmVyLCBpbWdZOiBudW1iZXIpOiBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICBjb25zdCBbY3gsIGN5XSA9IHRoaXMudmlld2VyLndvcmxkVG9DYW52YXMoaW1nWCwgaW1nWSk7XG4gICAgY29uc3QgciA9IHRoaXMuc3ZnLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHJldHVybiBbY3ggLSByLmxlZnQsIGN5IC0gci50b3BdO1xuICB9XG5cbiAgLy8g4pSA4pSAIHBvaW50ZXIgaGFuZGxlcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyRG93biA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBpZiAodGhpcy5tb2RlID09PSAnbm9uZScpIHJldHVybjtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgY29uc3QgW2l4LCBpeV0gPSB0aGlzLnRvSW1hZ2UoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xuICAgIGlmICh0aGlzLm1vZGUgPT09ICdkcmF3cmVjdCcpIHtcbiAgICAgIHRoaXMuZHJhZnRSZWN0ID0geyB4MDogaXgsIHkwOiBpeSwgeDE6IGl4LCB5MTogaXkgfTtcbiAgICAgIHRoaXMuZHJhd2luZyA9IHRydWU7XG4gICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdkcmF3Y2xvc2VkcGF0aCcgfHwgdGhpcy5tb2RlID09PSAnZHJhd29wZW5wYXRoJykge1xuICAgICAgdGhpcy5kcmFmdFBhdGggPSBbW2l4LCBpeV1dO1xuICAgICAgdGhpcy5kcmF3aW5nID0gdHJ1ZTtcbiAgICAgIHRoaXMuc3ZnLnNldFBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubW9kZSA9PT0gJ2RyYXdwb2x5Z29uJykge1xuICAgICAgdGhpcy5oYW5kbGVQb2x5Z29uQ2xpY2soaXgsIGl5LCBlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdzZWxlY3QnIHx8IHRoaXMubW9kZSA9PT0gJ21vdmUnKSB7XG4gICAgICB0aGlzLmJlZ2luTWFuaXB1bGF0aW9uKGl4LCBpeSwgZSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdhZGRwb2ludCcpIHtcbiAgICAgIHRoaXMuaGFuZGxlQWRkUG9pbnQoaXgsIGl5KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubW9kZSA9PT0gJ2RlbGV0ZXBvaW50Jykge1xuICAgICAgdGhpcy5oYW5kbGVEZWxldGVQb2ludChpeCwgaXkpO1xuICAgIH1cbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyTW92ZSA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBjb25zdCBbaXgsIGl5XSA9IHRoaXMudG9JbWFnZShlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgaWYgKHRoaXMubWFycXVlZSkge1xuICAgICAgdGhpcy5tYXJxdWVlLngxID0gaXg7XG4gICAgICB0aGlzLm1hcnF1ZWUueTEgPSBpeTtcbiAgICAgIHRoaXMudXBkYXRlTWFycXVlZUVsKCk7IC8vIHVwZGF0ZSBqdXN0IHRoZSBtYXJxdWVlIHJlY3Qg4oCUIE5PVCBhIGZ1bGwgcmVnaW9uIHJlZHJhd1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy5lZGl0KSB7XG4gICAgICB0aGlzLmFwcGx5TWFuaXB1bGF0aW9uKGl4LCBpeSk7XG4gICAgICB0aGlzLnJlZHJhdygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuZHJhd2luZykgcmV0dXJuO1xuICAgIGlmICh0aGlzLmRyYWZ0UmVjdCkge1xuICAgICAgdGhpcy5kcmFmdFJlY3QueDEgPSBpeDtcbiAgICAgIHRoaXMuZHJhZnRSZWN0LnkxID0gaXk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmRyYWZ0UGF0aCkge1xuICAgICAgY29uc3QgbGFzdCA9IHRoaXMuZHJhZnRQYXRoW3RoaXMuZHJhZnRQYXRoLmxlbmd0aCAtIDFdO1xuICAgICAgaWYgKE1hdGguYWJzKGl4IC0gbGFzdFswXSkgPj0gRlJFRUhBTkRfU1RFUCB8fCBNYXRoLmFicyhpeSAtIGxhc3RbMV0pID49IEZSRUVIQU5EX1NURVApIHtcbiAgICAgICAgdGhpcy5kcmFmdFBhdGgucHVzaChbaXgsIGl5XSk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVkcmF3KCk7XG4gIH07XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvblBvaW50ZXJVcCA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBpZiAodGhpcy5tYXJxdWVlKSB7XG4gICAgICBjb25zdCBtID0gdGhpcy5tYXJxdWVlO1xuICAgICAgdGhpcy5tYXJxdWVlID0gbnVsbDtcbiAgICAgIHRoaXMuY2xlYXJNYXJxdWVlRWwoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuc3ZnLnJlbGVhc2VQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogYWxyZWFkeSByZWxlYXNlZCAqL1xuICAgICAgfVxuICAgICAgdGhpcy5maW5pc2hNYXJxdWVlKG0pOyAvLyBzZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyDihpIgb25lIHJlZHJhdyB2aWEgdGhlIHNlbGVjdGlvbiBzdWJzY3JpcHRpb25cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRoaXMuZWRpdCkge1xuICAgICAgdGhpcy5zdG9yZS5lbmRCYXRjaCgpO1xuICAgICAgdGhpcy5lZGl0ID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuc3ZnLnJlbGVhc2VQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogYWxyZWFkeSByZWxlYXNlZCAqL1xuICAgICAgfVxuICAgICAgdGhpcy5yZWRyYXcoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmRyYXdpbmcpIHJldHVybjtcbiAgICB0aGlzLmRyYXdpbmcgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgdGhpcy5zdmcucmVsZWFzZVBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8qIGNhcHR1cmUgbWF5IGFscmVhZHkgYmUgcmVsZWFzZWQgKi9cbiAgICB9XG4gICAgaWYgKHRoaXMuZHJhZnRSZWN0KSB7XG4gICAgICBjb25zdCB7IHgwLCB5MCwgeDEsIHkxIH0gPSB0aGlzLmRyYWZ0UmVjdDtcbiAgICAgIGNvbnN0IHggPSBNYXRoLm1pbih4MCwgeDEpO1xuICAgICAgY29uc3QgeSA9IE1hdGgubWluKHkwLCB5MSk7XG4gICAgICBjb25zdCB3ID0gTWF0aC5hYnMoeDEgLSB4MCk7XG4gICAgICBjb25zdCBoID0gTWF0aC5hYnMoeTEgLSB5MCk7XG4gICAgICB0aGlzLmRyYWZ0UmVjdCA9IG51bGw7XG4gICAgICBpZiAodyA+PSAyICYmIGggPj0gMikgdGhpcy5jb21taXRSZWN0YW5nbGUoeCwgeSwgdywgaCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmRyYWZ0UGF0aCkge1xuICAgICAgY29uc3QgcHRzID0gdGhpcy5kcmFmdFBhdGg7XG4gICAgICB0aGlzLmRyYWZ0UGF0aCA9IG51bGw7XG4gICAgICBjb25zdCBjbG9zZWQgPSB0aGlzLm1vZGUgPT09ICdkcmF3Y2xvc2VkcGF0aCc7XG4gICAgICBpZiAocHRzLmxlbmd0aCA+PSAoY2xvc2VkID8gMyA6IDIpKSB0aGlzLmNvbW1pdFBvbHlnb24ocHRzLCBjbG9zZWQpO1xuICAgIH1cbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIC8qKiBDbGljay10by1wbGFjZSBwb2x5Z29uOiBhZGQgYSB2ZXJ0ZXgsIG9yIGNsb3NlIHdoZW4gY2xpY2tpbmcgbmVhciB0aGUgZmlyc3Qgb25lLiAqL1xuICBwcml2YXRlIGhhbmRsZVBvbHlnb25DbGljayhpeDogbnVtYmVyLCBpeTogbnVtYmVyLCBjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICghdGhpcy5kcmFmdFBhdGgpIHtcbiAgICAgIHRoaXMuZHJhZnRQYXRoID0gW1tpeCwgaXldXTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW2Z4LCBmeV0gPSB0aGlzLnRvTG9jYWwodGhpcy5kcmFmdFBhdGhbMF1bMF0sIHRoaXMuZHJhZnRQYXRoWzBdWzFdKTtcbiAgICBjb25zdCByID0gdGhpcy5zdmcuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgbmVhciA9XG4gICAgICBNYXRoLmh5cG90KGNsaWVudFggLSByLmxlZnQgLSBmeCwgY2xpZW50WSAtIHIudG9wIC0gZnkpIDw9IENMT1NFX1NOQVBfUFggJiZcbiAgICAgIHRoaXMuZHJhZnRQYXRoLmxlbmd0aCA+PSAzO1xuICAgIGlmIChuZWFyKSB7XG4gICAgICBjb25zdCBwdHMgPSB0aGlzLmRyYWZ0UGF0aDtcbiAgICAgIHRoaXMuZHJhZnRQYXRoID0gbnVsbDtcbiAgICAgIHRoaXMuY29tbWl0UG9seWdvbihwdHMsIHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRyYWZ0UGF0aC5wdXNoKFtpeCwgaXldKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IG9uRGJsQ2xpY2sgPSAoZTogTW91c2VFdmVudCk6IHZvaWQgPT4ge1xuICAgIGlmICh0aGlzLm1vZGUgIT09ICdkcmF3cG9seWdvbicgfHwgIXRoaXMuZHJhZnRQYXRoKSByZXR1cm47XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHB0cyA9IHRoaXMuZHJhZnRQYXRoO1xuICAgIHRoaXMuZHJhZnRQYXRoID0gbnVsbDtcbiAgICBpZiAocHRzLmxlbmd0aCA+PSAzKSB0aGlzLmNvbW1pdFBvbHlnb24ocHRzLCB0cnVlKTtcbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIC8qKiBUaGUgY3VycmVudGx5LXNlbGVjdGVkIHJlZ2lvbiAoc2luZ2xlIHNlbGVjdGlvbiksIG9yIG51bGwuICovXG4gIHByaXZhdGUgc2VsZWN0ZWRSZWdpb24oKTogUmVnaW9uIHwgbnVsbCB7XG4gICAgY29uc3QgcmVnaW9ucyA9IHRoaXMuc3RvcmUuZ2V0UmVnaW9ucygpO1xuICAgIGNvbnN0IGkgPSB0aGlzLnNlbGVjdGVkWzBdO1xuICAgIHJldHVybiBpICE9IG51bGwgJiYgaSA+PSAwICYmIGkgPCByZWdpb25zLmxlbmd0aCA/IHJlZ2lvbnNbaV0gOiBudWxsO1xuICB9XG5cbiAgLyoqIFNjcmVlbiBkaXN0YW5jZSAocHgpIGJldHdlZW4gYSBjbGllbnQgcG9pbnQgYW5kIGFuIGltYWdlIGNvb3JkLiAqL1xuICBwcml2YXRlIHNjcmVlbkRpc3QoY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIsIGltZ1g6IG51bWJlciwgaW1nWTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBjb25zdCBbbHgsIGx5XSA9IHRoaXMudG9Mb2NhbChpbWdYLCBpbWdZKTtcbiAgICBjb25zdCByID0gdGhpcy5zdmcuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIE1hdGguaHlwb3QoY2xpZW50WCAtIHIubGVmdCAtIGx4LCBjbGllbnRZIC0gci50b3AgLSBseSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYSBzZWxlY3QvbW92ZSBpbnRlcmFjdGlvbjogZ3JhYiBhIGhhbmRsZSAocmVjdGFuZ2xlIGNvcm5lcikgb3IgdmVydGV4IG9mIHRoZSBhbHJlYWR5LVxuICAgKiBzZWxlY3RlZCByZWdpb24gZmlyc3Q7IG90aGVyd2lzZSBzZWxlY3QgdGhlIHRvcG1vc3QgcmVnaW9uIHVuZGVyIHRoZSBjdXJzb3IgYW5kIGRyYWcgaXRzIGJvZHkuXG4gICAqL1xuICBwcml2YXRlIGJlZ2luTWFuaXB1bGF0aW9uKGl4OiBudW1iZXIsIGl5OiBudW1iZXIsIGU6IFBvaW50ZXJFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHNlbCA9IHRoaXMuc2VsZWN0ZWRSZWdpb24oKTtcbiAgICBpZiAoc2VsPy5ib3VuZHMpIHtcbiAgICAgIGNvbnN0IGdyYWIgPSB0aGlzLmhpdEhhbmRsZShzZWwsIGUuY2xpZW50WCwgZS5jbGllbnRZKTtcbiAgICAgIGlmIChncmFiKSB7XG4gICAgICAgIHRoaXMuc3RvcmUuYmVnaW5CYXRjaCgpO1xuICAgICAgICB0aGlzLmVkaXQgPSB7IC4uLmdyYWIsIGlkOiBzZWwuaWQsIGxhc3Q6IFtpeCwgaXldIH07XG4gICAgICAgIHRoaXMuc3ZnLnNldFBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBIaXQtdGVzdCBib2RpZXMsIHRvcG1vc3QgZmlyc3QgKGxhc3QgZHJhd24gcmVuZGVycyBvbiB0b3ApLlxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLnN0b3JlLmdldFJlZ2lvbnMoKTtcbiAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgaWYgKHRoaXMuaGl0VGVzdChyZWdpb25zW2ldLCBpeCwgaXkpKSB7XG4gICAgICAgIHRoaXMuc3RvcmUuc2VsZWN0UmVnaW9uKHJlZ2lvbnNbaV0pO1xuICAgICAgICB0aGlzLnN0b3JlLmJlZ2luQmF0Y2goKTtcbiAgICAgICAgdGhpcy5lZGl0ID0geyBraW5kOiAnYm9keScsIGlkOiByZWdpb25zW2ldLmlkLCBsYXN0OiBbaXgsIGl5XSB9O1xuICAgICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gRW1wdHkgc3BhY2U6IGluIHNlbGVjdCBtb2RlIHN0YXJ0IGEgcnViYmVyLWJhbmQgbWFycXVlZSAoc2VsZWN0cyB0aGUgcmVnaW9ucyBpdCBjb3ZlcnMgb25cbiAgICAvLyByZWxlYXNlKTsgaW4gbW92ZSBtb2RlIGp1c3QgY2xlYXIgdGhlIHNlbGVjdGlvbi5cbiAgICBpZiAodGhpcy5tb2RlID09PSAnc2VsZWN0Jykge1xuICAgICAgdGhpcy5tYXJxdWVlID0geyB4MDogaXgsIHkwOiBpeSwgeDE6IGl4LCB5MTogaXkgfTtcbiAgICAgIHRoaXMudXBkYXRlTWFycXVlZUVsKCk7XG4gICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc3RvcmUuc2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoW10pO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDcmVhdGUvdXBkYXRlIHRoZSBtYXJxdWVlIHJlY3QgZWxlbWVudCBkaXJlY3RseSAoYXZvaWRzIGEgZnVsbCByZWdpb24gcmVkcmF3IHBlciBtb3ZlKS4gKi9cbiAgcHJpdmF0ZSB1cGRhdGVNYXJxdWVlRWwoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1hcnF1ZWUpIHJldHVybjtcbiAgICBpZiAoIXRoaXMubWFycXVlZUVsIHx8ICF0aGlzLm1hcnF1ZWVFbC5wYXJlbnROb2RlKSB7XG4gICAgICB0aGlzLm1hcnF1ZWVFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsICcjNGRhM2ZmJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1kYXNoYXJyYXknLCAnNCAzJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCAnIzRkYTNmZicpO1xuICAgICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCdmaWxsLW9wYWNpdHknLCAnMC4xMicpO1xuICAgICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd2ZWN0b3ItZWZmZWN0JywgJ25vbi1zY2FsaW5nLXN0cm9rZScpO1xuICAgICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQodGhpcy5tYXJxdWVlRWwpO1xuICAgIH1cbiAgICBjb25zdCB7IHgwLCB5MCwgeDEsIHkxIH0gPSB0aGlzLm1hcnF1ZWU7XG4gICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5taW4oeDAsIHgxKSwgTWF0aC5taW4oeTAsIHkxKSk7XG4gICAgY29uc3QgW3J4LCByeV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5tYXgoeDAsIHgxKSwgTWF0aC5tYXgoeTAsIHkxKSk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd4JywgYCR7bHh9YCk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd5JywgYCR7bHl9YCk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd3aWR0aCcsIGAke01hdGguYWJzKHJ4IC0gbHgpfWApO1xuICAgIHRoaXMubWFycXVlZUVsLnNldEF0dHJpYnV0ZSgnaGVpZ2h0JywgYCR7TWF0aC5hYnMocnkgLSBseSl9YCk7XG4gIH1cblxuICAvKiogUmVtb3ZlIHRoZSBtYXJxdWVlIGVsZW1lbnQgZnJvbSB0aGUgU1ZHLiAqL1xuICBwcml2YXRlIGNsZWFyTWFycXVlZUVsKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm1hcnF1ZWVFbD8ucGFyZW50Tm9kZSkgdGhpcy5tYXJxdWVlRWwucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLm1hcnF1ZWVFbCk7XG4gICAgdGhpcy5tYXJxdWVlRWwgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRlc3Qgd2hldGhlciBhIGNsaWVudCBwb2ludCBncmFicyBhIHJlY3RhbmdsZSBjb3JuZXIgb3IgYSBwb2x5Z29uIHZlcnRleCBvZiBgcmVnaW9uYC4gKi9cbiAgcHJpdmF0ZSBoaXRIYW5kbGUoXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICAgY2xpZW50WDogbnVtYmVyLFxuICAgIGNsaWVudFk6IG51bWJlcixcbiAgKTpcbiAgICB8IHsga2luZDogJ2Nvcm5lcic7IGFuY2hvcjogW251bWJlciwgbnVtYmVyXSB9XG4gICAgfCB7IGtpbmQ6ICd2ZXJ0ZXgnOyB2ZXJ0ZXhJbmRleDogbnVtYmVyIH1cbiAgICB8IHsga2luZDogJ2Jlemllcic7IHZlcnRleEluZGV4OiBudW1iZXI7IHNpZGU6ICdpbicgfCAnb3V0JyB9XG4gICAgfCB7IGtpbmQ6ICdob2xldmVydGV4JzsgaG9sZUluZGV4OiBudW1iZXI7IHZlcnRleEluZGV4OiBudW1iZXIgfVxuICAgIHwgeyBraW5kOiAnaG9sZWJlemllcic7IGhvbGVJbmRleDogbnVtYmVyOyB2ZXJ0ZXhJbmRleDogbnVtYmVyOyBzaWRlOiAnaW4nIHwgJ291dCcgfVxuICAgIHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbi5ib3VuZHM7XG4gICAgaWYgKCFiKSByZXR1cm4gbnVsbDtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICBjb25zdCBjb3JuZXJzOiBBcnJheTxbbnVtYmVyLCBudW1iZXIsIFtudW1iZXIsIG51bWJlcl1dPiA9IFtcbiAgICAgICAgW3IueCwgci55LCBbci54ICsgci53aWR0aCwgci55ICsgci5oZWlnaHRdXSxcbiAgICAgICAgW3IueCArIHIud2lkdGgsIHIueSwgW3IueCwgci55ICsgci5oZWlnaHRdXSxcbiAgICAgICAgW3IueCwgci55ICsgci5oZWlnaHQsIFtyLnggKyByLndpZHRoLCByLnldXSxcbiAgICAgICAgW3IueCArIHIud2lkdGgsIHIueSArIHIuaGVpZ2h0LCBbci54LCByLnldXSxcbiAgICAgIF07XG4gICAgICBmb3IgKGNvbnN0IFtjeCwgY3ksIGFuY2hvcl0gb2YgY29ybmVycykge1xuICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIGN4LCBjeSkgPD0gSEFORExFX0hJVF9QWCkgcmV0dXJuIHsga2luZDogJ2Nvcm5lcicsIGFuY2hvciB9O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICAvLyBCZXppZXIgY29udHJvbCBwb2ludHMgZmlyc3QgKHRoZXkgc2l0IG9mZiB0aGUgYW5jaG9ycyksIHNvIHRoZXkncmUgZ3JhYmJhYmxlLlxuICAgICAgaWYgKHAuYmV6aWVyICYmIHAuaGFuZGxlc0luPy5sZW5ndGggPT09IHAubnBvaW50cyAmJiBwLmhhbmRsZXNPdXQ/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcC5ucG9pbnRzOyBpKyspIHtcbiAgICAgICAgICBjb25zdCBvdXQgPSBwLmhhbmRsZXNPdXRbaV07XG4gICAgICAgICAgY29uc3QgaW5uID0gcC5oYW5kbGVzSW5baV07XG4gICAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCBwLnhwb2ludHNbaV0gKyBvdXRbMF0sIHAueXBvaW50c1tpXSArIG91dFsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2JlemllcicsIHZlcnRleEluZGV4OiBpLCBzaWRlOiAnb3V0JyB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHAueHBvaW50c1tpXSArIGlublswXSwgcC55cG9pbnRzW2ldICsgaW5uWzFdKSA8PSBIQU5ETEVfSElUX1BYKSB7XG4gICAgICAgICAgICByZXR1cm4geyBraW5kOiAnYmV6aWVyJywgdmVydGV4SW5kZXg6IGksIHNpZGU6ICdpbicgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcC5ucG9pbnRzOyBpKyspIHtcbiAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCBwLnhwb2ludHNbaV0sIHAueXBvaW50c1tpXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgIHJldHVybiB7IGtpbmQ6ICd2ZXJ0ZXgnLCB2ZXJ0ZXhJbmRleDogaSB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBIb2xlIChkb251dCkgcmluZzogYmV6aWVyIGNvbnRyb2wgcG9pbnRzIGZpcnN0LCB0aGVuIHRoZSB2ZXJ0aWNlcy5cbiAgICAgIGNvbnN0IGhvbGVzID0gcC5ob2xlcyA/PyBbXTtcbiAgICAgIGNvbnN0IGhvbGVCZXppZXIgPSAhIShwLmJlemllciAmJiBwLmhvbGVIYW5kbGVzSW4gJiYgcC5ob2xlSGFuZGxlc091dCk7XG4gICAgICBmb3IgKGxldCBoaSA9IDA7IGhpIDwgaG9sZXMubGVuZ3RoOyBoaSsrKSB7XG4gICAgICAgIGNvbnN0IHJpbmcgPSBob2xlc1toaV07XG4gICAgICAgIGlmIChob2xlQmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiFbaGldICYmIHAuaG9sZUhhbmRsZXNPdXQhW2hpXSkge1xuICAgICAgICAgIGZvciAobGV0IHZpID0gMDsgdmkgPCByaW5nLmxlbmd0aDsgdmkrKykge1xuICAgICAgICAgICAgY29uc3Qgb3V0ID0gcC5ob2xlSGFuZGxlc091dCFbaGldW3ZpXSA/PyBbMCwgMF07XG4gICAgICAgICAgICBjb25zdCBpbm4gPSBwLmhvbGVIYW5kbGVzSW4hW2hpXVt2aV0gPz8gWzAsIDBdO1xuICAgICAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCByaW5nW3ZpXVswXSArIG91dFswXSwgcmluZ1t2aV1bMV0gKyBvdXRbMV0pIDw9IEhBTkRMRV9ISVRfUFgpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2hvbGViZXppZXInLCBob2xlSW5kZXg6IGhpLCB2ZXJ0ZXhJbmRleDogdmksIHNpZGU6ICdvdXQnIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHJpbmdbdmldWzBdICsgaW5uWzBdLCByaW5nW3ZpXVsxXSArIGlublsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgICByZXR1cm4geyBraW5kOiAnaG9sZWJlemllcicsIGhvbGVJbmRleDogaGksIHZlcnRleEluZGV4OiB2aSwgc2lkZTogJ2luJyB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCB2aSA9IDA7IHZpIDwgcmluZy5sZW5ndGg7IHZpKyspIHtcbiAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHJpbmdbdmldWzBdLCByaW5nW3ZpXVsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2hvbGV2ZXJ0ZXgnLCBob2xlSW5kZXg6IGhpLCB2ZXJ0ZXhJbmRleDogdmkgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQXBwbHkgdGhlIGxpdmUgZHJhZyBmb3IgdGhlIGFjdGl2ZSBtYW5pcHVsYXRpb24gKGltYWdlIGNvb3JkcyBgaXgsaXlgKS4gKi9cbiAgcHJpdmF0ZSBhcHBseU1hbmlwdWxhdGlvbihpeDogbnVtYmVyLCBpeTogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVkaXQpIHJldHVybjtcbiAgICBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdib2R5Jykge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLmVkaXQubGFzdDtcbiAgICAgIHRoaXMuc3RvcmUubW92ZVJlZ2lvbih0aGlzLmVkaXQuaWQsIGl4IC0gbHgsIGl5IC0gbHkpO1xuICAgICAgdGhpcy5lZGl0Lmxhc3QgPSBbaXgsIGl5XTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuZWRpdC5raW5kID09PSAndmVydGV4JyAmJiB0aGlzLmVkaXQudmVydGV4SW5kZXggIT0gbnVsbCkge1xuICAgICAgdGhpcy5zdG9yZS5tb3ZlVmVydGV4KHRoaXMuZWRpdC5pZCwgdGhpcy5lZGl0LnZlcnRleEluZGV4LCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdjb3JuZXInICYmIHRoaXMuZWRpdC5hbmNob3IpIHtcbiAgICAgIGNvbnN0IFtheCwgYXldID0gdGhpcy5lZGl0LmFuY2hvcjtcbiAgICAgIGNvbnN0IHJlY3QgPSBuZXcgUmVjdGFuZ2xlKCk7XG4gICAgICByZWN0LnggPSBNYXRoLm1pbihheCwgaXgpO1xuICAgICAgcmVjdC55ID0gTWF0aC5taW4oYXksIGl5KTtcbiAgICAgIHJlY3Qud2lkdGggPSBNYXRoLmFicyhpeCAtIGF4KTtcbiAgICAgIHJlY3QuaGVpZ2h0ID0gTWF0aC5hYnMoaXkgLSBheSk7XG4gICAgICB0aGlzLnN0b3JlLnVwZGF0ZUJvdW5kcyh0aGlzLmVkaXQuaWQsIHJlY3QpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdiZXppZXInICYmIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsICYmIHRoaXMuZWRpdC5zaWRlKSB7XG4gICAgICB0aGlzLnN0b3JlLm1vdmVCZXppZXJIYW5kbGUodGhpcy5lZGl0LmlkLCB0aGlzLmVkaXQudmVydGV4SW5kZXgsIHRoaXMuZWRpdC5zaWRlLCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLmVkaXQua2luZCA9PT0gJ2hvbGV2ZXJ0ZXgnICYmXG4gICAgICB0aGlzLmVkaXQuaG9sZUluZGV4ICE9IG51bGwgJiZcbiAgICAgIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsXG4gICAgKSB7XG4gICAgICB0aGlzLnN0b3JlLm1vdmVIb2xlVmVydGV4KHRoaXMuZWRpdC5pZCwgdGhpcy5lZGl0LmhvbGVJbmRleCwgdGhpcy5lZGl0LnZlcnRleEluZGV4LCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLmVkaXQua2luZCA9PT0gJ2hvbGViZXppZXInICYmXG4gICAgICB0aGlzLmVkaXQuaG9sZUluZGV4ICE9IG51bGwgJiZcbiAgICAgIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsICYmXG4gICAgICB0aGlzLmVkaXQuc2lkZVxuICAgICkge1xuICAgICAgdGhpcy5zdG9yZS5tb3ZlSG9sZUJlemllckhhbmRsZShcbiAgICAgICAgdGhpcy5lZGl0LmlkLFxuICAgICAgICB0aGlzLmVkaXQuaG9sZUluZGV4LFxuICAgICAgICB0aGlzLmVkaXQudmVydGV4SW5kZXgsXG4gICAgICAgIHRoaXMuZWRpdC5zaWRlLFxuICAgICAgICBpeCxcbiAgICAgICAgaXksXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBhZGRwb2ludCBtb2RlOiBpbnNlcnQgYSB2ZXJ0ZXggb24gdGhlIHNlbGVjdGVkIHBvbHlnb24ncyBuZWFyZXN0IGVkZ2UgYXQgdGhlIGNsaWNrLiAqL1xuICBwcml2YXRlIGhhbmRsZUFkZFBvaW50KGl4OiBudW1iZXIsIGl5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBzZWwgPSB0aGlzLnNlbGVjdGVkUmVnaW9uKCk7XG4gICAgY29uc3QgYiA9IHNlbD8uYm91bmRzO1xuICAgIGlmICghc2VsIHx8ICFiIHx8ICEoJ25wb2ludHMnIGluIGIpKSByZXR1cm47XG4gICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICBsZXQgYmVzdFNlZyA9IDA7XG4gICAgbGV0IGJlc3REID0gSW5maW5pdHk7XG4gICAgY29uc3Qgc2VncyA9IHAuY2xvc2VkID09PSBmYWxzZSA/IHAubnBvaW50cyAtIDEgOiBwLm5wb2ludHM7XG4gICAgZm9yIChsZXQgcyA9IDA7IHMgPCBzZWdzOyBzKyspIHtcbiAgICAgIGNvbnN0IGogPSAocyArIDEpICUgcC5ucG9pbnRzO1xuICAgICAgY29uc3QgZCA9IHRoaXMucG9pbnRTZWdEaXN0KGl4LCBpeSwgcC54cG9pbnRzW3NdLCBwLnlwb2ludHNbc10sIHAueHBvaW50c1tqXSwgcC55cG9pbnRzW2pdKTtcbiAgICAgIGlmIChkIDwgYmVzdEQpIHtcbiAgICAgICAgYmVzdEQgPSBkO1xuICAgICAgICBiZXN0U2VnID0gcztcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zdG9yZS5hZGRWZXJ0ZXgoc2VsLmlkLCBiZXN0U2VnLCBpeCwgaXkpO1xuICB9XG5cbiAgLyoqIGRlbGV0ZXBvaW50IG1vZGU6IHJlbW92ZSB0aGUgc2VsZWN0ZWQgcG9seWdvbidzIHZlcnRleCBuZWFyZXN0IHRoZSBjbGljay4gKi9cbiAgcHJpdmF0ZSBoYW5kbGVEZWxldGVQb2ludChpeDogbnVtYmVyLCBpeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3Qgc2VsID0gdGhpcy5zZWxlY3RlZFJlZ2lvbigpO1xuICAgIGNvbnN0IGIgPSBzZWw/LmJvdW5kcztcbiAgICBpZiAoIXNlbCB8fCAhYiB8fCAhKCducG9pbnRzJyBpbiBiKSkgcmV0dXJuO1xuICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgbGV0IGJlc3QgPSAtMTtcbiAgICBsZXQgYmVzdEQgPSBJbmZpbml0eTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHAubnBvaW50czsgaSsrKSB7XG4gICAgICBjb25zdCBkID0gTWF0aC5oeXBvdChwLnhwb2ludHNbaV0gLSBpeCwgcC55cG9pbnRzW2ldIC0gaXkpO1xuICAgICAgaWYgKGQgPCBiZXN0RCkge1xuICAgICAgICBiZXN0RCA9IGQ7XG4gICAgICAgIGJlc3QgPSBpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoYmVzdCA+PSAwKSB0aGlzLnN0b3JlLmRlbGV0ZVZlcnRleChzZWwuaWQsIGJlc3QpO1xuICB9XG5cbiAgLyoqIERpc3RhbmNlIGZyb20gcG9pbnQgKHB4LHB5KSB0byBzZWdtZW50IChheCxheSktKGJ4LGJ5KSwgaW4gaW1hZ2UgdW5pdHMuICovXG4gIHByaXZhdGUgcG9pbnRTZWdEaXN0KFxuICAgIHB4OiBudW1iZXIsXG4gICAgcHk6IG51bWJlcixcbiAgICBheDogbnVtYmVyLFxuICAgIGF5OiBudW1iZXIsXG4gICAgYng6IG51bWJlcixcbiAgICBieTogbnVtYmVyLFxuICApOiBudW1iZXIge1xuICAgIGNvbnN0IGR4ID0gYnggLSBheDtcbiAgICBjb25zdCBkeSA9IGJ5IC0gYXk7XG4gICAgY29uc3QgbGVuMiA9IGR4ICogZHggKyBkeSAqIGR5IHx8IDE7XG4gICAgbGV0IHQgPSAoKHB4IC0gYXgpICogZHggKyAocHkgLSBheSkgKiBkeSkgLyBsZW4yO1xuICAgIHQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB0KSk7XG4gICAgcmV0dXJuIE1hdGguaHlwb3QocHggLSAoYXggKyB0ICogZHgpLCBweSAtIChheSArIHQgKiBkeSkpO1xuICB9XG5cbiAgLyoqIEZpbmFsaXplIGEgcnViYmVyLWJhbmQgbWFycXVlZTogc2VsZWN0IGV2ZXJ5IHJlZ2lvbiB3aG9zZSBib3VuZGluZyBib3ggaXQgb3ZlcmxhcHMgKGEgdGlueVxuICAgKiAgbWFycXVlZSBpcyB0cmVhdGVkIGFzIGEgY2xpY2sgb24gZW1wdHkgc3BhY2Ug4oaSIGNsZWFyIHRoZSBzZWxlY3Rpb24pLiAqL1xuICBwcml2YXRlIGZpbmlzaE1hcnF1ZWUobTogeyB4MDogbnVtYmVyOyB5MDogbnVtYmVyOyB4MTogbnVtYmVyOyB5MTogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICBjb25zdCB4MCA9IE1hdGgubWluKG0ueDAsIG0ueDEpO1xuICAgIGNvbnN0IHgxID0gTWF0aC5tYXgobS54MCwgbS54MSk7XG4gICAgY29uc3QgeTAgPSBNYXRoLm1pbihtLnkwLCBtLnkxKTtcbiAgICBjb25zdCB5MSA9IE1hdGgubWF4KG0ueTAsIG0ueTEpO1xuICAgIGlmICh4MSAtIHgwIDwgMyAmJiB5MSAtIHkwIDwgMykge1xuICAgICAgdGhpcy5zdG9yZS5zZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhbXSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGluZGljZXM6IG51bWJlcltdID0gW107XG4gICAgdGhpcy5zdG9yZS5nZXRSZWdpb25zKCkuZm9yRWFjaCgociwgaSkgPT4ge1xuICAgICAgaWYgKHIuaXNQcm9maWxlPy4oKSkgcmV0dXJuO1xuICAgICAgY29uc3QgYmIgPSB0aGlzLnJlZ2lvbkJCb3gocik7XG4gICAgICBpZiAoYmIgJiYgYmIueDAgPD0geDEgJiYgYmIueDEgPj0geDAgJiYgYmIueTAgPD0geTEgJiYgYmIueTEgPj0geTApIGluZGljZXMucHVzaChpKTtcbiAgICB9KTtcbiAgICB0aGlzLnN0b3JlLnNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGluZGljZXMpO1xuICB9XG5cbiAgLyoqIEEgcmVnaW9uJ3MgYm91bmRpbmcgYm94IGluIGltYWdlIGNvb3JkcyAocmVjdGFuZ2xlLCBwb2x5Z29uLCBvciBtdWx0aXBvbHlnb24pLCBvciBudWxsLiAqL1xuICBwcml2YXRlIHJlZ2lvbkJCb3goXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICk6IHsgeDA6IG51bWJlcjsgeTA6IG51bWJlcjsgeDE6IG51bWJlcjsgeTE6IG51bWJlciB9IHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbi5ib3VuZHM7XG4gICAgaWYgKCFiKSByZXR1cm4gbnVsbDtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICByZXR1cm4geyB4MDogci54LCB5MDogci55LCB4MTogci54ICsgci53aWR0aCwgeTE6IHIueSArIHIuaGVpZ2h0IH07XG4gICAgfVxuICAgIGNvbnN0IGFjYyA9IHsgeDA6IEluZmluaXR5LCB5MDogSW5maW5pdHksIHgxOiAtSW5maW5pdHksIHkxOiAtSW5maW5pdHkgfTtcbiAgICBjb25zdCBhZGRSaW5nID0gKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdKTogdm9pZCA9PiB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICh4c1tpXSA8IGFjYy54MCkgYWNjLngwID0geHNbaV07XG4gICAgICAgIGlmICh4c1tpXSA+IGFjYy54MSkgYWNjLngxID0geHNbaV07XG4gICAgICAgIGlmICh5c1tpXSA8IGFjYy55MCkgYWNjLnkwID0geXNbaV07XG4gICAgICAgIGlmICh5c1tpXSA+IGFjYy55MSkgYWNjLnkxID0geXNbaV07XG4gICAgICB9XG4gICAgfTtcbiAgICBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBhZGRSaW5nKHAueHBvaW50cywgcC55cG9pbnRzKTtcbiAgICB9IGVsc2UgaWYgKCdwb2x5Z29ucycgaW4gYikge1xuICAgICAgZm9yIChjb25zdCBwIG9mIChiIGFzIHsgcG9seWdvbnM6IFBvbHlnb25bXSB9KS5wb2x5Z29ucykgYWRkUmluZyhwLnhwb2ludHMsIHAueXBvaW50cyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gaXNGaW5pdGUoYWNjLngwKSA/IGFjYyA6IG51bGw7XG4gIH1cblxuICAvLyDilIDilIAgc2hhcGUgY29tbWl0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBwcml2YXRlIGNvbW1pdFJlY3RhbmdsZSh4OiBudW1iZXIsIHk6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCByZWN0ID0gbmV3IFJlY3RhbmdsZSgpO1xuICAgIHJlY3QueCA9IHg7XG4gICAgcmVjdC55ID0geTtcbiAgICByZWN0LndpZHRoID0gd2lkdGg7XG4gICAgcmVjdC5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgY29uc3QgcmVnaW9uID0gbmV3IFJlZ2lvbigpO1xuICAgIHJlZ2lvbi5ib3VuZHMgPSByZWN0O1xuICAgIHJlZ2lvbi5jb2xvciA9IHRoaXMuc3RvcmUuZ2V0U2hhcGVDb2xvcigpO1xuICAgIHRoaXMuc3RvcmUuYWRkUmVnaW9uKHJlZ2lvbik7XG4gIH1cblxuICBwcml2YXRlIGNvbW1pdFBvbHlnb24ocG9pbnRzOiBBcnJheTxbbnVtYmVyLCBudW1iZXJdPiwgY2xvc2VkOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9pbnRzLmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSBwb2ludHMubWFwKChwKSA9PiBwWzBdKTtcbiAgICBwb2x5Lnlwb2ludHMgPSBwb2ludHMubWFwKChwKSA9PiBwWzFdKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9pbnRzLm1hcCgocCkgPT4gW3BbMF0sIHBbMV1dKTtcbiAgICBwb2x5LmNsb3NlZCA9IGNsb3NlZDtcbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCk7XG4gICAgcmVnaW9uLmxhYmVsID0gJ1JlZ2lvbic7XG4gICAgdGhpcy5zdG9yZS5hZGRSZWdpb24ocmVnaW9uKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCByZW5kZXJpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHByaXZhdGUgaGl0VGVzdChyZWdpb246IFJlZ2lvbiwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoIWIpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICByZXR1cm4geCA+PSByLnggJiYgeCA8PSByLnggKyByLndpZHRoICYmIHkgPj0gci55ICYmIHkgPD0gci55ICsgci5oZWlnaHQ7XG4gICAgfVxuICAgIGlmICgnbnBvaW50cycgaW4gYikge1xuICAgICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICAgIGxldCBpbnNpZGUgPSBmYWxzZTtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBqID0gcC5ucG9pbnRzIC0gMTsgaSA8IHAubnBvaW50czsgaiA9IGkrKykge1xuICAgICAgICBjb25zdCB4aSA9IHAueHBvaW50c1tpXTtcbiAgICAgICAgY29uc3QgeWkgPSBwLnlwb2ludHNbaV07XG4gICAgICAgIGNvbnN0IHhqID0gcC54cG9pbnRzW2pdO1xuICAgICAgICBjb25zdCB5aiA9IHAueXBvaW50c1tqXTtcbiAgICAgICAgaWYgKHlpID4geSAhPT0geWogPiB5ICYmIHggPCAoKHhqIC0geGkpICogKHkgLSB5aSkpIC8gKHlqIC0geWkpICsgeGkpIGluc2lkZSA9ICFpbnNpZGU7XG4gICAgICB9XG4gICAgICByZXR1cm4gaW5zaWRlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZWRyYXcoKTogdm9pZCB7XG4gICAgd2hpbGUgKHRoaXMuc3ZnLmZpcnN0Q2hpbGQpIHRoaXMuc3ZnLnJlbW92ZUNoaWxkKHRoaXMuc3ZnLmZpcnN0Q2hpbGQpO1xuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLnN0b3JlLmdldFJlZ2lvbnMoKTtcbiAgICByZWdpb25zLmZvckVhY2goKHJlZ2lvbiwgaSkgPT4ge1xuICAgICAgaWYgKHJlZ2lvbi5pc1Byb2ZpbGU/LigpKSByZXR1cm47XG4gICAgICBjb25zdCBpc1NlbCA9IHRoaXMuc2VsZWN0ZWQuaW5jbHVkZXMoaSk7XG4gICAgICBjb25zdCBlbCA9IHRoaXMuYnVpbGRSZWdpb25FbChyZWdpb24sIGlzU2VsKTtcbiAgICAgIGlmIChlbCkgdGhpcy5zdmcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgICAgdGhpcy5kcmF3TGFiZWwocmVnaW9uKTtcbiAgICAgIGlmIChpc1NlbCkgdGhpcy5kcmF3SGFuZGxlcyhyZWdpb24pO1xuICAgIH0pO1xuICAgIHRoaXMuZHJhd0RyYWZ0KCk7XG4gIH1cblxuICAvKiogRHJhdyBhIHJlZ2lvbidzIGNsYXNzaWZpY2F0aW9uIGxhYmVsIGF0IGl0cyB0b3AtbGVmdCwgd2hlbiBsYWJlbHMgYXJlIGVuYWJsZWQgKG1hdGNoZXMgT1NEKS4gKi9cbiAgcHJpdmF0ZSBkcmF3TGFiZWwocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSB8fCByZWdpb24uaXNQcm9maWxlPy4oKSkgcmV0dXJuO1xuICAgIGNvbnN0IGxhYmVsID0gcmVnaW9uLmxhYmVsO1xuICAgIGNvbnN0IGIgPSByZWdpb24uYm91bmRzO1xuICAgIGlmICghbGFiZWwgfHwgIWIpIHJldHVybjtcbiAgICBsZXQgaXg6IG51bWJlcjtcbiAgICBsZXQgaXk6IG51bWJlcjtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBpeCA9IChiIGFzIFJlY3RhbmdsZSkueDtcbiAgICAgIGl5ID0gKGIgYXMgUmVjdGFuZ2xlKS55O1xuICAgIH0gZWxzZSBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBpeCA9IHAueHBvaW50cy5yZWR1Y2UoKG0sIHgpID0+IE1hdGgubWluKG0sIHgpLCBJbmZpbml0eSk7XG4gICAgICBpeSA9IHAueXBvaW50cy5yZWR1Y2UoKG0sIHkpID0+IE1hdGgubWluKG0sIHkpLCBJbmZpbml0eSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoaXgsIGl5KTtcbiAgICBjb25zdCB0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3RleHQnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgneCcsIGAke2x4fWApO1xuICAgIHRleHQuc2V0QXR0cmlidXRlKCd5JywgYCR7bHkgLSA0fWApO1xuICAgIHRleHQuc2V0QXR0cmlidXRlKCdmaWxsJywgJyNmZmYnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgJyMwMDAnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgJzMnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgncGFpbnQtb3JkZXInLCAnc3Ryb2tlJyk7XG4gICAgdGV4dC5zZXRBdHRyaWJ1dGUoJ2ZvbnQnLCAnMTJweCBzYW5zLXNlcmlmJyk7XG4gICAgdGV4dC5zZXRBdHRyaWJ1dGUoJ3BvaW50ZXItZXZlbnRzJywgJ25vbmUnKTtcbiAgICB0ZXh0LnRleHRDb250ZW50ID0gbGFiZWw7XG4gICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQodGV4dCk7XG4gIH1cblxuICAvKiogRHJhdyBncmFiIGhhbmRsZXMgZm9yIHRoZSBzZWxlY3RlZCByZWdpb246IHJlY3RhbmdsZSBjb3JuZXJzIG9yIHBvbHlnb24gdmVydGljZXMuICovXG4gIHByaXZhdGUgZHJhd0hhbmRsZXMocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoIWIpIHJldHVybjtcbiAgICBjb25zdCBzdHJva2UgPSByZWdpb24uY29sb3IgfHwgdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCkgfHwgJyMwMGZmZmYnO1xuICAgIGNvbnN0IGhhbmRsZSA9IChpbWdYOiBudW1iZXIsIGltZ1k6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoaW1nWCwgaW1nWSk7XG4gICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3gnLCBgJHtseCAtIEhBTkRMRV9TSVpFIC8gMn1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgneScsIGAke2x5IC0gSEFORExFX1NJWkUgLyAyfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd3aWR0aCcsIGAke0hBTkRMRV9TSVpFfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCdoZWlnaHQnLCBgJHtIQU5ETEVfU0laRX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnZmlsbCcsICcjZmZmJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsIHN0cm9rZSk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxLjUnKTtcbiAgICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGVsKTtcbiAgICB9O1xuICAgIGlmICgnd2lkdGgnIGluIGIgJiYgJ3gnIGluIGIpIHtcbiAgICAgIGNvbnN0IHIgPSBiIGFzIFJlY3RhbmdsZTtcbiAgICAgIGhhbmRsZShyLngsIHIueSk7XG4gICAgICBoYW5kbGUoci54ICsgci53aWR0aCwgci55KTtcbiAgICAgIGhhbmRsZShyLngsIHIueSArIHIuaGVpZ2h0KTtcbiAgICAgIGhhbmRsZShyLnggKyByLndpZHRoLCByLnkgKyByLmhlaWdodCk7XG4gICAgfSBlbHNlIGlmICgnbnBvaW50cycgaW4gYikge1xuICAgICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICAgIGNvbnN0IGlzQmV6aWVyID0gcC5iZXppZXIgJiYgcC5oYW5kbGVzSW4/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzICYmIHAuaGFuZGxlc091dD8ubGVuZ3RoID09PSBwLm5wb2ludHM7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHAubnBvaW50czsgaSsrKSBoYW5kbGUocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0pO1xuICAgICAgZm9yIChjb25zdCByaW5nIG9mIHAuaG9sZXMgPz8gW10pIGZvciAoY29uc3QgW2h4LCBoeV0gb2YgcmluZykgaGFuZGxlKGh4LCBoeSk7XG4gICAgICAvLyBCZXppZXIgcmVnaW9ucyBhbHNvIGV4cG9zZSB0aGVpciB0YW5nZW50IGNvbnRyb2wgcG9pbnRzIChjaXJjbGVzKSBqb2luZWQgdG8gdGhlIGFuY2hvclxuICAgICAgLy8gYnkgYSB0aGluIGxpbmUsIG1hdGNoaW5nIHRoZSBPU0Qgb3ZlcmxheSdzIGVkaXRhYmxlIGJlemllciBoYW5kbGVzLlxuICAgICAgaWYgKGlzQmV6aWVyKSB7XG4gICAgICAgIGNvbnN0IGhJbiA9IHAuaGFuZGxlc0luIGFzIG51bWJlcltdW107XG4gICAgICAgIGNvbnN0IGhPdXQgPSBwLmhhbmRsZXNPdXQgYXMgbnVtYmVyW11bXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwLm5wb2ludHM7IGkrKykge1xuICAgICAgICAgIHRoaXMuZHJhd0JlemllckhhbmRsZShwLnhwb2ludHNbaV0sIHAueXBvaW50c1tpXSwgaE91dFtpXSwgc3Ryb2tlKTtcbiAgICAgICAgICB0aGlzLmRyYXdCZXppZXJIYW5kbGUocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0sIGhJbltpXSwgc3Ryb2tlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gRG9udXQgaG9sZSBiZXppZXIgY29udHJvbCBoYW5kbGVzLlxuICAgICAgaWYgKHAuYmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiAmJiBwLmhvbGVIYW5kbGVzT3V0KSB7XG4gICAgICAgIChwLmhvbGVzID8/IFtdKS5mb3JFYWNoKChyaW5nLCBoaSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGhJbiA9IHAuaG9sZUhhbmRsZXNJbiFbaGldO1xuICAgICAgICAgIGNvbnN0IGhPdXQgPSBwLmhvbGVIYW5kbGVzT3V0IVtoaV07XG4gICAgICAgICAgaWYgKCFoSW4gfHwgIWhPdXQpIHJldHVybjtcbiAgICAgICAgICByaW5nLmZvckVhY2goKFtoeCwgaHldLCB2aSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5kcmF3QmV6aWVySGFuZGxlKGh4LCBoeSwgaE91dFt2aV0sIHN0cm9rZSk7XG4gICAgICAgICAgICB0aGlzLmRyYXdCZXppZXJIYW5kbGUoaHgsIGh5LCBoSW5bdmldLCBzdHJva2UpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKiogRHJhdyBvbmUgYmV6aWVyIGNvbnRyb2wgcG9pbnQgKGFuY2hvciArIGhhbmRsZSBvZmZzZXQpIGFzIGEgc21hbGwgY2lyY2xlIGNvbm5lY3RlZCB0byBpdHNcbiAgICogIGFuY2hvciBieSBhIHRhbmdlbnQgbGluZS4gYGhhbmRsZWAgaXMgdGhlIFtkeCxkeV0gb2Zmc2V0IGZyb20gdGhlIGFuY2hvciBpbiBpbWFnZSBzcGFjZS4gKi9cbiAgcHJpdmF0ZSBkcmF3QmV6aWVySGFuZGxlKGF4OiBudW1iZXIsIGF5OiBudW1iZXIsIGhhbmRsZTogbnVtYmVyW10sIHN0cm9rZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKCFoYW5kbGUgfHwgKGhhbmRsZVswXSA9PT0gMCAmJiBoYW5kbGVbMV0gPT09IDApKSByZXR1cm47XG4gICAgY29uc3QgW2FseCwgYWx5XSA9IHRoaXMudG9Mb2NhbChheCwgYXkpO1xuICAgIGNvbnN0IFtobHgsIGhseV0gPSB0aGlzLnRvTG9jYWwoYXggKyBoYW5kbGVbMF0sIGF5ICsgaGFuZGxlWzFdKTtcbiAgICBjb25zdCBsaW5lID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ2xpbmUnKTtcbiAgICBsaW5lLnNldEF0dHJpYnV0ZSgneDEnLCBgJHthbHh9YCk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3kxJywgYCR7YWx5fWApO1xuICAgIGxpbmUuc2V0QXR0cmlidXRlKCd4MicsIGAke2hseH1gKTtcbiAgICBsaW5lLnNldEF0dHJpYnV0ZSgneTInLCBgJHtobHl9YCk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsIHN0cm9rZSk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxJyk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1vcGFjaXR5JywgJzAuNycpO1xuICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGxpbmUpO1xuICAgIGNvbnN0IGRvdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdjaXJjbGUnKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdjeCcsIGAke2hseH1gKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdjeScsIGAke2hseX1gKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdyJywgYCR7SEFORExFX1NJWkUgLyAyfWApO1xuICAgIGRvdC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCBzdHJva2UpO1xuICAgIGRvdC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsICcjZmZmJyk7XG4gICAgZG90LnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgJzEnKTtcbiAgICB0aGlzLnN2Zy5hcHBlbmRDaGlsZChkb3QpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFJlZ2lvbkVsKHJlZ2lvbjogUmVnaW9uLCBpc1NlbGVjdGVkOiBib29sZWFuKTogU1ZHRWxlbWVudCB8IG51bGwge1xuICAgIGNvbnN0IGIgPSByZWdpb24uYm91bmRzO1xuICAgIGlmICghYikgcmV0dXJuIG51bGw7XG4gICAgY29uc3Qgc3Ryb2tlID0gcmVnaW9uLmNvbG9yIHx8IHRoaXMuc3RvcmUuZ2V0U2hhcGVDb2xvcigpIHx8ICcjMDBmZmZmJztcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICBjb25zdCBbbHgsIGx5XSA9IHRoaXMudG9Mb2NhbChyLngsIHIueSk7XG4gICAgICBjb25zdCBbcngsIHJ5XSA9IHRoaXMudG9Mb2NhbChyLnggKyByLndpZHRoLCByLnkgKyByLmhlaWdodCk7XG4gICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3gnLCBgJHtNYXRoLm1pbihseCwgcngpfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd5JywgYCR7TWF0aC5taW4obHksIHJ5KX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnd2lkdGgnLCBgJHtNYXRoLmFicyhyeCAtIGx4KX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnaGVpZ2h0JywgYCR7TWF0aC5hYnMocnkgLSBseSl9YCk7XG4gICAgICB0aGlzLnN0eWxlKGVsLCBzdHJva2UsIGlzU2VsZWN0ZWQpO1xuICAgICAgcmV0dXJuIGVsO1xuICAgIH1cbiAgICBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBjb25zdCBpc0JlemllciA9XG4gICAgICAgICEhcC5iZXppZXIgJiYgcC5oYW5kbGVzSW4/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzICYmIHAuaGFuZGxlc091dD8ubGVuZ3RoID09PSBwLm5wb2ludHM7XG4gICAgICBjb25zdCBoYXNIb2xlcyA9ICEhKHAuaG9sZXMgJiYgcC5ob2xlcy5sZW5ndGgpO1xuICAgICAgLy8gQmV6aWVyIG9yIGRvbnV0IChob2xlcykg4oaSIGEgc2luZ2xlIDxwYXRoPjsgaG9sZXMgdXNlIGV2ZW4tb2RkIGZpbGwgc28gdGhleSBwdW5jaCB0aHJvdWdoLlxuICAgICAgaWYgKGlzQmV6aWVyIHx8IGhhc0hvbGVzKSB7XG4gICAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3BhdGgnKTtcbiAgICAgICAgZWwuc2V0QXR0cmlidXRlKCdkJywgdGhpcy5wb2x5Z29uUGF0aERhdGEocCwgaXNCZXppZXIpKTtcbiAgICAgICAgaWYgKGhhc0hvbGVzKSBlbC5zZXRBdHRyaWJ1dGUoJ2ZpbGwtcnVsZScsICdldmVub2RkJyk7XG4gICAgICAgIHRoaXMuc3R5bGUoZWwsIHN0cm9rZSwgaXNTZWxlY3RlZCk7XG4gICAgICAgIHJldHVybiBlbDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHB0cyA9IHAueHBvaW50c1xuICAgICAgICAubWFwKChfLCBpKSA9PiB0aGlzLnRvTG9jYWwocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0pLmpvaW4oJywnKSlcbiAgICAgICAgLmpvaW4oJyAnKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgcC5jbG9zZWQgPT09IGZhbHNlID8gJ3BvbHlsaW5lJyA6ICdwb2x5Z29uJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3BvaW50cycsIHB0cyk7XG4gICAgICB0aGlzLnN0eWxlKGVsLCBzdHJva2UsIGlzU2VsZWN0ZWQpO1xuICAgICAgcmV0dXJuIGVsO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBQYXRoIGRhdGEgZm9yIGEgcG9seWdvbjogdGhlIGV4dGVyaW9yIHJpbmcgKGJlemllciBvciBzdHJhaWdodCkgcGx1cyBhbnkgaG9sZXMgKGJlemllciB3aGVuXG4gICAqICB0aGUgZG9udXQgY2FycmllcyBob2xlIGhhbmRsZXMsIGVsc2Ugc3RyYWlnaHQpIGFzIHN1Yi1wYXRocyDigJQgZXZlbi1vZGQgZmlsbCBjdXRzIHRoZW0gb3V0LiAqL1xuICBwcml2YXRlIHBvbHlnb25QYXRoRGF0YShwOiBQb2x5Z29uLCBpc0JlemllcjogYm9vbGVhbik6IHN0cmluZyB7XG4gICAgbGV0IGQgPSBpc0JlemllclxuICAgICAgPyB0aGlzLnJpbmdCZXppZXJQYXRoKHAueHBvaW50cywgcC55cG9pbnRzLCBwLmhhbmRsZXNJbiEsIHAuaGFuZGxlc091dCEsIHAuY2xvc2VkICE9PSBmYWxzZSlcbiAgICAgIDogdGhpcy5zdHJhaWdodFBhdGgocC54cG9pbnRzLCBwLnlwb2ludHMsIHAuY2xvc2VkICE9PSBmYWxzZSk7XG4gICAgY29uc3QgaG9sZUJlemllciA9ICEhKHAuYmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiAmJiBwLmhvbGVIYW5kbGVzT3V0KTtcbiAgICAocC5ob2xlcyA/PyBbXSkuZm9yRWFjaCgocmluZywgaGkpID0+IHtcbiAgICAgIGlmIChyaW5nLmxlbmd0aCA8IDMpIHJldHVybjtcbiAgICAgIGNvbnN0IHhzID0gcmluZy5tYXAoKHB0KSA9PiBwdFswXSk7XG4gICAgICBjb25zdCB5cyA9IHJpbmcubWFwKChwdCkgPT4gcHRbMV0pO1xuICAgICAgaWYgKGhvbGVCZXppZXIgJiYgcC5ob2xlSGFuZGxlc0luIVtoaV0gJiYgcC5ob2xlSGFuZGxlc091dCFbaGldKSB7XG4gICAgICAgIGQgKz0gJyAnICsgdGhpcy5yaW5nQmV6aWVyUGF0aCh4cywgeXMsIHAuaG9sZUhhbmRsZXNJbiFbaGldLCBwLmhvbGVIYW5kbGVzT3V0IVtoaV0sIHRydWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZCArPSAnICcgKyB0aGlzLnN0cmFpZ2h0UGF0aCh4cywgeXMsIHRydWUpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBkO1xuICB9XG5cbiAgLyoqIFNWRyBwYXRoIGRhdGEgZm9yIGEgc3RyYWlnaHQgcmluZy9wb2x5bGluZSBpbiBpbWFnZSBjb29yZHMgKGNsb3NlZCBhcHBlbmRzIGBaYCkuICovXG4gIHByaXZhdGUgc3RyYWlnaHRQYXRoKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLCBjbG9zZWQ6IGJvb2xlYW4pOiBzdHJpbmcge1xuICAgIGxldCBkID0gJyc7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB4cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoeHNbaV0sIHlzW2ldKTtcbiAgICAgIGQgKz0gKGkgPT09IDAgPyAnTScgOiAnIEwnKSArIGAgJHtseH0sJHtseX1gO1xuICAgIH1cbiAgICByZXR1cm4gY2xvc2VkID8gZCArICcgWicgOiBkO1xuICB9XG5cbiAgLyoqIFNWRyBjdWJpYy1iZXppZXIgcGF0aCBkYXRhIGZvciBhbnkgcmluZyAoZXh0ZXJpb3Igb3IgaG9sZSk6IGFuY2hvcnMgam9pbmVkIGJ5IGN1YmljIHNlZ21lbnRzXG4gICAqICB3aG9zZSBjb250cm9sIHBvaW50cyBhcmUgYGFuY2hvciArIGhhbmRsZU91dGAgKGxlYXZpbmcpIGFuZCBgbmV4dEFuY2hvciArIGhhbmRsZUluYCAoYXJyaXZpbmcpLFxuICAgKiAgaW4gaW1hZ2Ugc3BhY2UuIFVzZWQgZm9yIGJvdGggdGhlIGV4dGVyaW9yIGFuZCAoZG9udXQpIGhvbGUgcmluZ3MuICovXG4gIHByaXZhdGUgcmluZ0JlemllclBhdGgoXG4gICAgeHM6IG51bWJlcltdLFxuICAgIHlzOiBudW1iZXJbXSxcbiAgICBoSW46IG51bWJlcltdW10sXG4gICAgaE91dDogbnVtYmVyW11bXSxcbiAgICBjbG9zZWQ6IGJvb2xlYW4sXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3QgbiA9IHhzLmxlbmd0aDtcbiAgICBjb25zdCBhbmNob3IgPSAoaTogbnVtYmVyKTogW251bWJlciwgbnVtYmVyXSA9PiB0aGlzLnRvTG9jYWwoeHNbaV0sIHlzW2ldKTtcbiAgICBjb25zdCBjdHJsT3V0ID0gKGk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0gPT5cbiAgICAgIHRoaXMudG9Mb2NhbCh4c1tpXSArIChoT3V0W2ldPy5bMF0gPz8gMCksIHlzW2ldICsgKGhPdXRbaV0/LlsxXSA/PyAwKSk7XG4gICAgY29uc3QgY3RybEluID0gKGk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0gPT5cbiAgICAgIHRoaXMudG9Mb2NhbCh4c1tpXSArIChoSW5baV0/LlswXSA/PyAwKSwgeXNbaV0gKyAoaEluW2ldPy5bMV0gPz8gMCkpO1xuICAgIGNvbnN0IFtzeCwgc3ldID0gYW5jaG9yKDApO1xuICAgIGxldCBkID0gYE0gJHtzeH0sJHtzeX1gO1xuICAgIGNvbnN0IHNlZ21lbnRzID0gY2xvc2VkID8gbiA6IG4gLSAxO1xuICAgIGZvciAobGV0IHMgPSAwOyBzIDwgc2VnbWVudHM7IHMrKykge1xuICAgICAgY29uc3QgaSA9IHM7XG4gICAgICBjb25zdCBqID0gKHMgKyAxKSAlIG47XG4gICAgICBjb25zdCBbYzF4LCBjMXldID0gY3RybE91dChpKTtcbiAgICAgIGNvbnN0IFtjMngsIGMyeV0gPSBjdHJsSW4oaik7XG4gICAgICBjb25zdCBbZXgsIGV5XSA9IGFuY2hvcihqKTtcbiAgICAgIGQgKz0gYCBDICR7YzF4fSwke2MxeX0gJHtjMnh9LCR7YzJ5fSAke2V4fSwke2V5fWA7XG4gICAgfVxuICAgIGlmIChjbG9zZWQpIGQgKz0gJyBaJztcbiAgICByZXR1cm4gZDtcbiAgfVxuXG4gIHByaXZhdGUgc3R5bGUoZWw6IFNWR0VsZW1lbnQsIHN0cm9rZTogc3RyaW5nLCBpc1NlbGVjdGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdzdHJva2UnLCBzdHJva2UpO1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgaXNTZWxlY3RlZCA/ICc0JyA6ICcyJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdmaWxsJywgaXNTZWxlY3RlZCA/IHN0cm9rZSA6ICdub25lJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdmaWxsLW9wYWNpdHknLCBpc1NlbGVjdGVkID8gJzAuMzUnIDogJzAnKTtcbiAgICBlbC5zZXRBdHRyaWJ1dGUoJ3ZlY3Rvci1lZmZlY3QnLCAnbm9uLXNjYWxpbmctc3Ryb2tlJyk7XG4gIH1cblxuICAvKiogRHJhdyB0aGUgaW4tcHJvZ3Jlc3MgcmVjdGFuZ2xlIC8gcGF0aCBwcmV2aWV3LiAqL1xuICBwcml2YXRlIGRyYXdEcmFmdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kcmFmdFJlY3QpIHtcbiAgICAgIGNvbnN0IHsgeDAsIHkwLCB4MSwgeTEgfSA9IHRoaXMuZHJhZnRSZWN0O1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5taW4oeDAsIHgxKSwgTWF0aC5taW4oeTAsIHkxKSk7XG4gICAgICBjb25zdCBbcngsIHJ5XSA9IHRoaXMudG9Mb2NhbChNYXRoLm1heCh4MCwgeDEpLCBNYXRoLm1heCh5MCwgeTEpKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3JlY3QnKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgneCcsIGAke2x4fWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd5JywgYCR7bHl9YCk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3dpZHRoJywgYCR7TWF0aC5hYnMocnggLSBseCl9YCk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ2hlaWdodCcsIGAke01hdGguYWJzKHJ5IC0gbHkpfWApO1xuICAgICAgdGhpcy5zdHlsZURyYWZ0KGVsKTtcbiAgICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGVsKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZHJhZnRQYXRoICYmIHRoaXMuZHJhZnRQYXRoLmxlbmd0aCkge1xuICAgICAgY29uc3QgcHRzID0gdGhpcy5kcmFmdFBhdGgubWFwKChbeCwgeV0pID0+IHRoaXMudG9Mb2NhbCh4LCB5KS5qb2luKCcsJykpLmpvaW4oJyAnKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3BvbHlsaW5lJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3BvaW50cycsIHB0cyk7XG4gICAgICB0aGlzLnN0eWxlRHJhZnQoZWwpO1xuICAgICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3R5bGVEcmFmdChlbDogU1ZHRWxlbWVudCk6IHZvaWQge1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCkgfHwgJyMwMGZmZmYnKTtcbiAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcyJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdzdHJva2UtZGFzaGFycmF5JywgJzQgMycpO1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnZmlsbCcsICdub25lJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCd2ZWN0b3ItZWZmZWN0JywgJ25vbi1zY2FsaW5nLXN0cm9rZScpO1xuICB9XG59XG4iXX0=
|