@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,1029 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
3
|
+
import { Region, Rectangle, Polygon, MultiPolygon } from '../models/region';
|
|
4
|
+
import { PlotUtilities } from '../plot.utilities';
|
|
5
|
+
import { VisualizerStore } from './visualizer-store.service';
|
|
6
|
+
import { defaultHandleOffsets } from '../models/bezier';
|
|
7
|
+
import { findPreset, fallbackColorFor } from './class-color.util';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
import * as i1 from "./visualizer-store.service";
|
|
10
|
+
/**
|
|
11
|
+
* Backend-neutral region store — the single source of truth for region state.
|
|
12
|
+
*
|
|
13
|
+
* Holds the neutral {@link Region} model (never a backend's own shape
|
|
14
|
+
* representation), keyed per image so regions persist as the user switches
|
|
15
|
+
* files and survive a Plotly⇄OpenSeadragon backend switch (both backends read
|
|
16
|
+
* and write *this* store, so no migration is needed). Backends own *rendering*
|
|
17
|
+
* and react to {@link getRegionUpdateEvent}; this service owns *state* and the
|
|
18
|
+
* editing operations.
|
|
19
|
+
*
|
|
20
|
+
* Implements:
|
|
21
|
+
* - {@link IRegionStore} — the cross-backend CRUD/selection/colour contract
|
|
22
|
+
* every consumer (Region Editor, segmentation, etc.) already uses.
|
|
23
|
+
* - {@link IRegionEditApi} — Region-native geometry edits (move/resize, and
|
|
24
|
+
* add/delete/move vertex) the OSD overlay drives.
|
|
25
|
+
*
|
|
26
|
+
* Classification colours live in {@link VisualizerStore} (shared by both
|
|
27
|
+
* backends); GeoJSON import/export and the closed-polygon projection reuse the
|
|
28
|
+
* neutral {@link PlotUtilities} helpers. All coordinates are image pixels.
|
|
29
|
+
*/
|
|
30
|
+
export class RegionStore {
|
|
31
|
+
static { this.UNDO_LIMIT = 10; }
|
|
32
|
+
static { this.UNDO_COALESCE_MS = 250; }
|
|
33
|
+
constructor(store) {
|
|
34
|
+
this.store = store;
|
|
35
|
+
/** Per-image region cache. `regions` is always a snapshot of the entry for
|
|
36
|
+
* `currentImageKey`. */
|
|
37
|
+
this.regionsByImageKey = new Map();
|
|
38
|
+
/** The current image's regions — the live, edited array. */
|
|
39
|
+
this.regions = [];
|
|
40
|
+
/** Last saved snapshot, restorable via plotPreviousShapes(). */
|
|
41
|
+
this.previousRegions = [];
|
|
42
|
+
/**
|
|
43
|
+
* Undo/redo history (jit-ui#85): up to {@link UNDO_LIMIT} snapshots of the
|
|
44
|
+
* region set, each a deep clone captured immediately *before* a
|
|
45
|
+
* region-editing action. {@link undo} pops the newest off `undoStack`, pushes
|
|
46
|
+
* the current state onto `redoStack`, and restores it — so it can be invoked
|
|
47
|
+
* up to {@link UNDO_LIMIT} times in a row. {@link redo} is the mirror. Any new
|
|
48
|
+
* region action clears `redoStack` (the redo future is no longer reachable).
|
|
49
|
+
*
|
|
50
|
+
* A continuous gesture (a wand/brush/vertex drag commits to the store many
|
|
51
|
+
* times) is coalesced into a single entry: the first commit of a burst
|
|
52
|
+
* captures the pre-burst state and every commit within
|
|
53
|
+
* {@link UNDO_COALESCE_MS} of the previous one is folded into it. History
|
|
54
|
+
* never crosses an image load/switch — {@link resetUndoHistory} clears it.
|
|
55
|
+
*/
|
|
56
|
+
this.undoStack = [];
|
|
57
|
+
this.redoStack = [];
|
|
58
|
+
/** True while a coalescing burst is open (further commits fold into it). */
|
|
59
|
+
this.undoBurstOpen = false;
|
|
60
|
+
this.undoBurstTimer = null;
|
|
61
|
+
/** True while restoring a snapshot, so the restore records no new history. */
|
|
62
|
+
this.restoringUndo = false;
|
|
63
|
+
this.canUndo$ = new BehaviorSubject(false);
|
|
64
|
+
this.canRedo$ = new BehaviorSubject(false);
|
|
65
|
+
/** Monotonic id source — ids never repeat within the service lifetime, so
|
|
66
|
+
* selection stays correct across delete/add cycles even when names collide. */
|
|
67
|
+
this.nextId = 1;
|
|
68
|
+
this.showShapeLabel = false;
|
|
69
|
+
this.shapeColor = '#00FFFF';
|
|
70
|
+
this.fillColor = '#ff00ff';
|
|
71
|
+
this.isRegionSavedOn = true;
|
|
72
|
+
/**
|
|
73
|
+
* Per-slice region support for z-stacks (jit-ui#93). While {@link stackMode}
|
|
74
|
+
* is on (a z-stack is loaded), the live `regions` array always holds ONE
|
|
75
|
+
* slice — the {@link currentSliceZ} slice — so the on-canvas overlays, the
|
|
76
|
+
* selection projection, and the Regions table keep working unchanged
|
|
77
|
+
* (they all read {@link getRegions}). The other slices live in
|
|
78
|
+
* {@link regionsBySlice}; {@link setDisplaySlice} swaps the live set on scrub
|
|
79
|
+
* and {@link getSliceRegions} flattens every slice (each tagged with its
|
|
80
|
+
* zero-based {@link Region.z}) for save/export. Off by default (stackMode
|
|
81
|
+
* false, z 0), so single-plane images are completely unaffected.
|
|
82
|
+
*/
|
|
83
|
+
this.regionsBySlice = new Map();
|
|
84
|
+
this.stackMode = false;
|
|
85
|
+
this.currentSliceZ = 0;
|
|
86
|
+
/** How a stack's regions round-trip to disk (jit-ui#93): `combined` writes one
|
|
87
|
+
* z-indexed geojson (single-file z-stack, QuPath schema); `per-slice-file`
|
|
88
|
+
* writes one geojson per slice-file (a folder of numbered images). */
|
|
89
|
+
this.stackSaveLayout = 'combined';
|
|
90
|
+
/** Slices that were loaded with regions (jit-ui#93). A per-slice-file save
|
|
91
|
+
* re-writes these even when now empty, so clearing a slice's regions and
|
|
92
|
+
* saving removes its previously-saved geojson (writes an empty one). */
|
|
93
|
+
this.stackInitialNonEmpty = new Set();
|
|
94
|
+
/** Selection is tracked by region *id* internally (stable across edits) and
|
|
95
|
+
* projected to array indices on the IRegionStore boundary. */
|
|
96
|
+
this.selectedIds = [];
|
|
97
|
+
this.selectedIndices$ = new BehaviorSubject([]);
|
|
98
|
+
this.regionUpdate$ = new Subject();
|
|
99
|
+
/** Non-coalesced sibling of regionUpdate$: fires on every change even during a
|
|
100
|
+
* batched drag, so live consumers (intensity inset) update per frame. */
|
|
101
|
+
this.regionLiveEdit$ = new Subject();
|
|
102
|
+
/** Emit coalescing for live drags (see IRegionEditApi.beginBatch). */
|
|
103
|
+
this.batchDepth = 0;
|
|
104
|
+
this.pendingEmit = false;
|
|
105
|
+
this.plotUtilities = new PlotUtilities();
|
|
106
|
+
}
|
|
107
|
+
// ── IRegionStore: CRUD ─────────────────────────────────────────────────
|
|
108
|
+
/**
|
|
109
|
+
* Replace (or, with `append`, add to) the current image's regions. Mints ids
|
|
110
|
+
* and default names, applies stored classification colours, and emits. When
|
|
111
|
+
* `isRegionSaveOn` is false the regions are shown transiently (emitted) but
|
|
112
|
+
* not stored — mirrors the previous Plotly behaviour.
|
|
113
|
+
*/
|
|
114
|
+
setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append = false) {
|
|
115
|
+
if (showRegionLabel === undefined)
|
|
116
|
+
showRegionLabel = this.showShapeLabel;
|
|
117
|
+
if (isRegionSaveOn === undefined)
|
|
118
|
+
isRegionSaveOn = this.isRegionSavedOn;
|
|
119
|
+
if (fillColor === undefined)
|
|
120
|
+
fillColor = this.fillColor;
|
|
121
|
+
for (const region of regions) {
|
|
122
|
+
if (region.id == null)
|
|
123
|
+
region.id = this.nextId++;
|
|
124
|
+
if (region.name == null)
|
|
125
|
+
region.name = `shape${region.id}`;
|
|
126
|
+
}
|
|
127
|
+
this.applyClassificationColors(regions);
|
|
128
|
+
this.isRegionSavedOn = isRegionSaveOn;
|
|
129
|
+
if (isRegionSaveOn) {
|
|
130
|
+
this.recordUndoSnapshot();
|
|
131
|
+
this.showShapeLabel = showRegionLabel;
|
|
132
|
+
this.fillColor = fillColor;
|
|
133
|
+
if (append) {
|
|
134
|
+
// Reject by id collision (already tracked) or geometry equality (same
|
|
135
|
+
// coordinates) — the find button can push the same region repeatedly.
|
|
136
|
+
const added = regions.filter(r => !this.regions.some(existing => existing.id === r.id || this.regionsEqual(existing, r)));
|
|
137
|
+
this.regions = this.regions.concat(added);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
this.regions = regions.slice();
|
|
141
|
+
}
|
|
142
|
+
this.syncCache();
|
|
143
|
+
this.emitSelection();
|
|
144
|
+
this.emit();
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Transient display only — don't touch stored state.
|
|
148
|
+
this.regionUpdate$.next(regions.slice());
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** The canonical accessor: current image's regions (live instances). */
|
|
152
|
+
getRegions() {
|
|
153
|
+
return this.regions.slice();
|
|
154
|
+
}
|
|
155
|
+
// ── Per-slice regions for z-stacks (jit-ui#93) ─────────────────────────
|
|
156
|
+
/** True while a z-stack is loaded and the store holds regions per slice. */
|
|
157
|
+
isStackMode() { return this.stackMode; }
|
|
158
|
+
/** The current display slice (zero-based). */
|
|
159
|
+
getDisplaySlice() { return this.currentSliceZ; }
|
|
160
|
+
/** How the current stack persists to disk (jit-ui#93): `combined` = one
|
|
161
|
+
* z-indexed geojson (single-file z-stack); `per-slice-file` = one geojson per
|
|
162
|
+
* slice-file (folder stack). Meaningless outside stack mode. */
|
|
163
|
+
getStackSaveLayout() { return this.stackSaveLayout; }
|
|
164
|
+
/**
|
|
165
|
+
* Enter per-slice stack mode. `slices` maps each zero-based slice index to
|
|
166
|
+
* the regions imported for that slice; the store makes `initialZ`'s slice the
|
|
167
|
+
* live set, so the overlays / selection / Regions table are unchanged (they
|
|
168
|
+
* still read {@link getRegions}). Freshly-created regions are tagged with the
|
|
169
|
+
* current slice so they persist on it, and {@link getSliceRegions} returns
|
|
170
|
+
* every slice for save/export. Ids/names/classification colours are minted
|
|
171
|
+
* exactly as {@link setRegions} does.
|
|
172
|
+
*/
|
|
173
|
+
enterStackMode(slices, initialZ = 0, saveLayout = 'combined') {
|
|
174
|
+
this.stackMode = true;
|
|
175
|
+
this.stackSaveLayout = saveLayout;
|
|
176
|
+
this.currentSliceZ = initialZ || 0;
|
|
177
|
+
this.regionsBySlice = new Map();
|
|
178
|
+
this.stackInitialNonEmpty = new Set();
|
|
179
|
+
for (const [z, regs] of slices) {
|
|
180
|
+
const normalized = this.normalizeSlice(regs || [], z);
|
|
181
|
+
this.regionsBySlice.set(z, normalized);
|
|
182
|
+
if (normalized.length)
|
|
183
|
+
this.stackInitialNonEmpty.add(z);
|
|
184
|
+
}
|
|
185
|
+
this.regions = (this.regionsBySlice.get(this.currentSliceZ) ?? []).slice();
|
|
186
|
+
this.previousRegions = this.regions.slice();
|
|
187
|
+
this.selectedIds = [];
|
|
188
|
+
this.syncCache();
|
|
189
|
+
this.resetUndoHistory();
|
|
190
|
+
this.emitSelection();
|
|
191
|
+
this.emit();
|
|
192
|
+
}
|
|
193
|
+
/** Leave stack mode (single-plane image, or the stack was closed). */
|
|
194
|
+
exitStackMode() {
|
|
195
|
+
if (!this.stackMode)
|
|
196
|
+
return;
|
|
197
|
+
this.stackMode = false;
|
|
198
|
+
this.currentSliceZ = 0;
|
|
199
|
+
this.regionsBySlice = new Map();
|
|
200
|
+
this.stackInitialNonEmpty = new Set();
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Show a different slice: capture the current slice's (possibly edited)
|
|
204
|
+
* regions back into the per-slice store, then load the target slice's regions
|
|
205
|
+
* as the live set and emit. Undo never crosses a slice. Outside stack mode
|
|
206
|
+
* this only records the requested slice index (a no-op otherwise: single-plane
|
|
207
|
+
* regions stay on the default plane — addRegion tags Region.z only in stack
|
|
208
|
+
* mode, so the recorded index is unused until a stack is entered). (jit-ui#93)
|
|
209
|
+
*/
|
|
210
|
+
setDisplaySlice(z) {
|
|
211
|
+
const next = z || 0;
|
|
212
|
+
if (!this.stackMode) {
|
|
213
|
+
this.currentSliceZ = next;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (this.currentSliceZ === next)
|
|
217
|
+
return;
|
|
218
|
+
this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
|
|
219
|
+
this.currentSliceZ = next;
|
|
220
|
+
this.regions = (this.regionsBySlice.get(next) ?? []).slice();
|
|
221
|
+
this.previousRegions = this.regions.slice();
|
|
222
|
+
this.selectedIds = [];
|
|
223
|
+
this.syncCache();
|
|
224
|
+
this.resetUndoHistory();
|
|
225
|
+
this.emitSelection();
|
|
226
|
+
this.emit();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Every slice's regions for save/export, each tagged with its zero-based
|
|
230
|
+
* slice index in {@link Region.z}. Captures the current slice's live edits
|
|
231
|
+
* first. Returns the flat single-plane set when not in stack mode. (jit-ui#93)
|
|
232
|
+
*/
|
|
233
|
+
getSliceRegions() {
|
|
234
|
+
if (!this.stackMode)
|
|
235
|
+
return this.regions.slice();
|
|
236
|
+
this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
|
|
237
|
+
const out = [];
|
|
238
|
+
const zs = Array.from(this.regionsBySlice.keys()).sort((a, b) => a - b);
|
|
239
|
+
for (const z of zs) {
|
|
240
|
+
for (const r of this.regionsBySlice.get(z)) {
|
|
241
|
+
r.z = z;
|
|
242
|
+
out.push(r);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Slices to write on a per-slice-file save (folder stack, jit-ui#93): every
|
|
249
|
+
* slice that currently has regions, PLUS slices that were loaded non-empty but
|
|
250
|
+
* are now empty (so their file is re-written empty, clearing a slice whose
|
|
251
|
+
* regions the user deleted). Each returned region is tagged with its z, and
|
|
252
|
+
* the current live slice is captured first. Empty outside stack mode.
|
|
253
|
+
*/
|
|
254
|
+
getStackSaveSlices() {
|
|
255
|
+
const out = new Map();
|
|
256
|
+
if (!this.stackMode)
|
|
257
|
+
return out;
|
|
258
|
+
this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
|
|
259
|
+
const zs = new Set(this.stackInitialNonEmpty);
|
|
260
|
+
for (const [z, regs] of this.regionsBySlice)
|
|
261
|
+
if (regs.length)
|
|
262
|
+
zs.add(z);
|
|
263
|
+
for (const z of Array.from(zs).sort((a, b) => a - b)) {
|
|
264
|
+
const regs = (this.regionsBySlice.get(z) ?? []).map((r) => { r.z = z; return r; });
|
|
265
|
+
out.set(z, regs);
|
|
266
|
+
}
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
/** Mint ids/names + apply classification colours + tag the slice index, as
|
|
270
|
+
* {@link setRegions} does, for regions entering the per-slice store. */
|
|
271
|
+
normalizeSlice(regions, z) {
|
|
272
|
+
for (const region of regions) {
|
|
273
|
+
if (region.id == null)
|
|
274
|
+
region.id = this.nextId++;
|
|
275
|
+
if (region.name == null)
|
|
276
|
+
region.name = `shape${region.id}`;
|
|
277
|
+
region.z = z;
|
|
278
|
+
}
|
|
279
|
+
this.applyClassificationColors(regions);
|
|
280
|
+
return regions.slice();
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Closed polygons projected for image-processing consumers (segmentation,
|
|
284
|
+
* trace builders). Open polylines are annotation-only and excluded. Reuses
|
|
285
|
+
* the neutral PlotUtilities projection so output matches the previous path.
|
|
286
|
+
*/
|
|
287
|
+
getRegionPolygons() {
|
|
288
|
+
const ret = [];
|
|
289
|
+
for (const region of this.regions) {
|
|
290
|
+
const poly = this.plotUtilities.getPolygon({ ...region.getShape(this.showShapeLabel) });
|
|
291
|
+
if (poly == null || poly.closed === false)
|
|
292
|
+
continue;
|
|
293
|
+
ret.push(poly);
|
|
294
|
+
}
|
|
295
|
+
return ret;
|
|
296
|
+
}
|
|
297
|
+
getRegionUpdateEvent() {
|
|
298
|
+
return this.regionUpdate$.asObservable();
|
|
299
|
+
}
|
|
300
|
+
/** Live (non-coalesced) region-change stream — fires per frame during a drag.
|
|
301
|
+
* Used by the intensity-profile inset so it tracks line ROIs live. */
|
|
302
|
+
getRegionLiveEdit$() {
|
|
303
|
+
return this.regionLiveEdit$.asObservable();
|
|
304
|
+
}
|
|
305
|
+
// ── IRegionStore: selection ────────────────────────────────────────────
|
|
306
|
+
/** Select regions by array index (or [] to clear). Stored internally by id
|
|
307
|
+
* so the selection survives subsequent edits/reorders. */
|
|
308
|
+
setSelectedShapeIndices(indices) {
|
|
309
|
+
const ids = [];
|
|
310
|
+
const seen = new Set();
|
|
311
|
+
for (const i of indices || []) {
|
|
312
|
+
if (!Number.isFinite(i) || i < 0 || i >= this.regions.length)
|
|
313
|
+
continue;
|
|
314
|
+
const id = this.regions[i].id;
|
|
315
|
+
if (!seen.has(id)) {
|
|
316
|
+
seen.add(id);
|
|
317
|
+
ids.push(id);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
this.selectedIds = ids;
|
|
321
|
+
this.emitSelection();
|
|
322
|
+
}
|
|
323
|
+
/** Select a single region by identity (id). Backends call this from their
|
|
324
|
+
* `selectRegion()`; the OSD overlay + region editor highlight off the
|
|
325
|
+
* resulting selection emit. No-op if the region isn't in the store. */
|
|
326
|
+
selectRegion(region) {
|
|
327
|
+
if (region?.id == null || this.indexOfId(region.id) < 0)
|
|
328
|
+
return;
|
|
329
|
+
this.selectedIds = [region.id];
|
|
330
|
+
this.emitSelection();
|
|
331
|
+
}
|
|
332
|
+
getSelectedShapeIndices$() {
|
|
333
|
+
return this.selectedIndices$.asObservable();
|
|
334
|
+
}
|
|
335
|
+
/** Synchronous current selection (array indices) — for callers that need to
|
|
336
|
+
* read the selection without subscribing. */
|
|
337
|
+
getSelectedShapeIndices() {
|
|
338
|
+
return this.selectedIndices$.value;
|
|
339
|
+
}
|
|
340
|
+
/** Delete the currently selected regions and clear the selection. */
|
|
341
|
+
deleteActiveShape() {
|
|
342
|
+
if (this.selectedIds.length === 0)
|
|
343
|
+
return;
|
|
344
|
+
this.recordUndoSnapshot();
|
|
345
|
+
const ids = new Set(this.selectedIds);
|
|
346
|
+
this.regions = this.regions.filter(r => !ids.has(r.id));
|
|
347
|
+
this.selectedIds = [];
|
|
348
|
+
this.syncCache();
|
|
349
|
+
this.emitSelection();
|
|
350
|
+
this.emit();
|
|
351
|
+
}
|
|
352
|
+
// ── IRegionStore: colours / labels ─────────────────────────────────────
|
|
353
|
+
getShowShapeLabel() { return this.showShapeLabel; }
|
|
354
|
+
getShapeColor() { return this.shapeColor; }
|
|
355
|
+
getFillColor() { return this.fillColor; }
|
|
356
|
+
/** Convenience setters (not on the contract) for toolbar wiring. */
|
|
357
|
+
setShowShapeLabel(show) { this.showShapeLabel = show; }
|
|
358
|
+
setShapeColor(color) { this.shapeColor = color; }
|
|
359
|
+
setFillColor(color) { this.fillColor = color; }
|
|
360
|
+
getClassificationColors() { return this.store.getClassificationColors(); }
|
|
361
|
+
setClassificationColor(label, color) { this.store.setClassificationColor(label, color); }
|
|
362
|
+
// ── IRegionStore: previous-shapes buffer ───────────────────────────────
|
|
363
|
+
/** Re-show the last saved snapshot (transient — does not alter stored state). */
|
|
364
|
+
plotPreviousShapes() {
|
|
365
|
+
this.regionUpdate$.next(this.previousRegions.slice());
|
|
366
|
+
}
|
|
367
|
+
setPreviousShapes(shapes) { this.previousRegions = shapes.slice(); }
|
|
368
|
+
getPreviousShapes() { return this.previousRegions.slice(); }
|
|
369
|
+
// ── IRegionStore: undo / redo (jit-ui#85) ──────────────────────────────
|
|
370
|
+
/** Emits whether an undo step is currently available — drives the toolbar
|
|
371
|
+
* Undo button's enabled state (greyed out when false). */
|
|
372
|
+
getCanUndo$() {
|
|
373
|
+
return this.canUndo$.asObservable();
|
|
374
|
+
}
|
|
375
|
+
/** Emits whether a redo step is currently available — drives the toolbar
|
|
376
|
+
* Redo button's enabled state. */
|
|
377
|
+
getCanRedo$() {
|
|
378
|
+
return this.canRedo$.asObservable();
|
|
379
|
+
}
|
|
380
|
+
/** Synchronous read of {@link getCanUndo$} — true when at least one region
|
|
381
|
+
* action can be undone. */
|
|
382
|
+
canUndo() {
|
|
383
|
+
return this.undoStack.length > 0;
|
|
384
|
+
}
|
|
385
|
+
/** Synchronous read of {@link getCanRedo$} — true when an undone action can
|
|
386
|
+
* be re-applied. */
|
|
387
|
+
canRedo() {
|
|
388
|
+
return this.redoStack.length > 0;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Undo the most recent region action, restoring the region set to its state
|
|
392
|
+
* just before that action and pushing the current state onto the redo stack.
|
|
393
|
+
* Up to {@link UNDO_LIMIT} steps are retained, so this can be called up to
|
|
394
|
+
* {@link UNDO_LIMIT} times in a row before the history empties. No-op when
|
|
395
|
+
* nothing is left to undo.
|
|
396
|
+
*/
|
|
397
|
+
undo() {
|
|
398
|
+
if (this.undoStack.length === 0)
|
|
399
|
+
return;
|
|
400
|
+
const snapshot = this.undoStack.pop();
|
|
401
|
+
// Stash the current (post-action) state so redo can re-apply it.
|
|
402
|
+
this.redoStack.push(this.cloneRegions(this.regions));
|
|
403
|
+
if (this.redoStack.length > RegionStore.UNDO_LIMIT)
|
|
404
|
+
this.redoStack.shift();
|
|
405
|
+
this.restoreSnapshot(snapshot);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Redo the action most recently undone, restoring the region set to the state
|
|
409
|
+
* it had before that undo and pushing the current state back onto the undo
|
|
410
|
+
* stack. No-op when there's nothing to redo (the redo stack is cleared by any
|
|
411
|
+
* fresh region action).
|
|
412
|
+
*/
|
|
413
|
+
redo() {
|
|
414
|
+
if (this.redoStack.length === 0)
|
|
415
|
+
return;
|
|
416
|
+
const snapshot = this.redoStack.pop();
|
|
417
|
+
this.undoStack.push(this.cloneRegions(this.regions));
|
|
418
|
+
if (this.undoStack.length > RegionStore.UNDO_LIMIT)
|
|
419
|
+
this.undoStack.shift();
|
|
420
|
+
this.restoreSnapshot(snapshot);
|
|
421
|
+
}
|
|
422
|
+
/** Discard the undo/redo history (e.g. on image load/switch — history never
|
|
423
|
+
* crosses images). */
|
|
424
|
+
resetUndoHistory() {
|
|
425
|
+
this.undoStack = [];
|
|
426
|
+
this.redoStack = [];
|
|
427
|
+
this.closeUndoBurst();
|
|
428
|
+
if (this.canUndo$.value)
|
|
429
|
+
this.canUndo$.next(false);
|
|
430
|
+
if (this.canRedo$.value)
|
|
431
|
+
this.canRedo$.next(false);
|
|
432
|
+
}
|
|
433
|
+
/** Make `snapshot` the live region set and notify both backends. Shared by
|
|
434
|
+
* {@link undo} and {@link redo}; the snapshot is already a detached deep
|
|
435
|
+
* clone, so it becomes the live array directly. */
|
|
436
|
+
restoreSnapshot(snapshot) {
|
|
437
|
+
// Close any open coalescing burst so the next edit starts a fresh entry,
|
|
438
|
+
// and flag the restore so it doesn't record itself back into the history.
|
|
439
|
+
this.closeUndoBurst();
|
|
440
|
+
this.restoringUndo = true;
|
|
441
|
+
this.regions = snapshot;
|
|
442
|
+
// Drop any selected ids the restored set no longer contains.
|
|
443
|
+
this.selectedIds = this.selectedIds.filter(id => this.indexOfId(id) >= 0);
|
|
444
|
+
this.syncCache();
|
|
445
|
+
this.emitSelection();
|
|
446
|
+
this.restoringUndo = false;
|
|
447
|
+
this.emitUndoState();
|
|
448
|
+
// Notify the live + coalesced streams so whichever backend is on screen
|
|
449
|
+
// re-renders from the restored store state.
|
|
450
|
+
this.regionLiveEdit$.next(this.regions.slice());
|
|
451
|
+
this.regionUpdate$.next(this.getRegions());
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Capture the pre-action region set into the bounded undo history. Called at
|
|
455
|
+
* the top of every mutating operation, *before* it changes `regions`, so the
|
|
456
|
+
* snapshot is the state to return to. Rapid commits from one gesture coalesce
|
|
457
|
+
* into a single entry (see {@link undoStack}). A fresh action also abandons
|
|
458
|
+
* any redo future.
|
|
459
|
+
*/
|
|
460
|
+
recordUndoSnapshot() {
|
|
461
|
+
if (this.restoringUndo)
|
|
462
|
+
return;
|
|
463
|
+
const startsBurst = !this.undoBurstOpen;
|
|
464
|
+
this.armUndoBurst();
|
|
465
|
+
if (!startsBurst)
|
|
466
|
+
return; // mid-burst — keep first snapshot
|
|
467
|
+
this.undoStack.push(this.cloneRegions(this.regions));
|
|
468
|
+
if (this.undoStack.length > RegionStore.UNDO_LIMIT)
|
|
469
|
+
this.undoStack.shift();
|
|
470
|
+
this.redoStack = []; // a new edit invalidates redo
|
|
471
|
+
this.emitUndoState();
|
|
472
|
+
}
|
|
473
|
+
/** Push the current can-undo / can-redo availability to subscribers. */
|
|
474
|
+
emitUndoState() {
|
|
475
|
+
const canUndo = this.undoStack.length > 0;
|
|
476
|
+
const canRedo = this.redoStack.length > 0;
|
|
477
|
+
if (this.canUndo$.value !== canUndo)
|
|
478
|
+
this.canUndo$.next(canUndo);
|
|
479
|
+
if (this.canRedo$.value !== canRedo)
|
|
480
|
+
this.canRedo$.next(canRedo);
|
|
481
|
+
}
|
|
482
|
+
/** (Re)arm the idle timer that closes the current coalescing burst. */
|
|
483
|
+
armUndoBurst() {
|
|
484
|
+
this.undoBurstOpen = true;
|
|
485
|
+
if (this.undoBurstTimer)
|
|
486
|
+
clearTimeout(this.undoBurstTimer);
|
|
487
|
+
this.undoBurstTimer = setTimeout(() => {
|
|
488
|
+
this.undoBurstOpen = false;
|
|
489
|
+
this.undoBurstTimer = null;
|
|
490
|
+
}, RegionStore.UNDO_COALESCE_MS);
|
|
491
|
+
}
|
|
492
|
+
closeUndoBurst() {
|
|
493
|
+
this.undoBurstOpen = false;
|
|
494
|
+
if (this.undoBurstTimer) {
|
|
495
|
+
clearTimeout(this.undoBurstTimer);
|
|
496
|
+
this.undoBurstTimer = null;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
cloneRegions(regions) {
|
|
500
|
+
return regions.map(r => this.cloneRegion(r));
|
|
501
|
+
}
|
|
502
|
+
/** Deep clone a region so an in-place geometry edit can't mutate a stored
|
|
503
|
+
* history snapshot (bounds are cloned via {@link cloneBounds}). */
|
|
504
|
+
cloneRegion(r) {
|
|
505
|
+
const c = new Region();
|
|
506
|
+
Object.assign(c, r);
|
|
507
|
+
c.bounds = r.bounds ? this.cloneBounds(r.bounds) : r.bounds;
|
|
508
|
+
if (Array.isArray(r.tileCoordinates))
|
|
509
|
+
c.tileCoordinates = r.tileCoordinates.slice();
|
|
510
|
+
return c;
|
|
511
|
+
}
|
|
512
|
+
// ── IRegionStore: GeoJSON I/O (neutral helpers) ────────────────────────
|
|
513
|
+
importRegions(geoJsonStr) {
|
|
514
|
+
return this.plotUtilities.importROIsFromGeoJson(geoJsonStr);
|
|
515
|
+
}
|
|
516
|
+
exportRegions(regions) {
|
|
517
|
+
this.plotUtilities.saveToFile(this.plotUtilities.exportROIsToGeoJson(regions));
|
|
518
|
+
}
|
|
519
|
+
getGeoJsonString(regions) {
|
|
520
|
+
return this.plotUtilities.exportROIsToGeoJson(regions);
|
|
521
|
+
}
|
|
522
|
+
// ── IRegionEditApi: structural edits ───────────────────────────────────
|
|
523
|
+
addRegion(region) {
|
|
524
|
+
this.recordUndoSnapshot();
|
|
525
|
+
if (region.id == null)
|
|
526
|
+
region.id = this.nextId++;
|
|
527
|
+
if (region.name == null)
|
|
528
|
+
region.name = `shape${region.id}`;
|
|
529
|
+
// A region drawn on a stack belongs to the slice currently displayed, so
|
|
530
|
+
// it saves/reloads on that slice (jit-ui#93). No-op for single-plane images
|
|
531
|
+
// (currentSliceZ stays 0).
|
|
532
|
+
if (this.stackMode)
|
|
533
|
+
region.z = this.currentSliceZ;
|
|
534
|
+
this.applyClassificationColors([region]);
|
|
535
|
+
this.regions.push(region);
|
|
536
|
+
this.selectedIds = [region.id];
|
|
537
|
+
this.syncCache();
|
|
538
|
+
this.emitSelection();
|
|
539
|
+
this.emit();
|
|
540
|
+
return region.id;
|
|
541
|
+
}
|
|
542
|
+
removeRegion(id) {
|
|
543
|
+
const idx = this.indexOfId(id);
|
|
544
|
+
if (idx < 0)
|
|
545
|
+
return;
|
|
546
|
+
this.recordUndoSnapshot();
|
|
547
|
+
this.regions.splice(idx, 1);
|
|
548
|
+
this.selectedIds = this.selectedIds.filter(s => s !== id);
|
|
549
|
+
this.syncCache();
|
|
550
|
+
this.emitSelection();
|
|
551
|
+
this.emit();
|
|
552
|
+
}
|
|
553
|
+
updateBounds(id, bounds) {
|
|
554
|
+
const r = this.findById(id);
|
|
555
|
+
if (!r)
|
|
556
|
+
return;
|
|
557
|
+
this.recordUndoSnapshot();
|
|
558
|
+
r.bounds = this.cloneBounds(bounds);
|
|
559
|
+
this.syncCache();
|
|
560
|
+
this.emit();
|
|
561
|
+
}
|
|
562
|
+
moveRegion(id, dx, dy) {
|
|
563
|
+
const r = this.findById(id);
|
|
564
|
+
if (!r || !r.bounds)
|
|
565
|
+
return;
|
|
566
|
+
this.recordUndoSnapshot();
|
|
567
|
+
const b = r.bounds;
|
|
568
|
+
if (b instanceof Rectangle) {
|
|
569
|
+
b.x += dx;
|
|
570
|
+
b.y += dy;
|
|
571
|
+
}
|
|
572
|
+
else if (b instanceof Polygon) {
|
|
573
|
+
this.translatePolygon(b, dx, dy);
|
|
574
|
+
}
|
|
575
|
+
else if (b instanceof MultiPolygon) {
|
|
576
|
+
// Translate every part (and its holes) together (jit-ui#85).
|
|
577
|
+
for (const part of b.polygons)
|
|
578
|
+
this.translatePolygon(part, dx, dy);
|
|
579
|
+
}
|
|
580
|
+
this.syncCache();
|
|
581
|
+
this.emit();
|
|
582
|
+
}
|
|
583
|
+
/** Translate a polygon's vertices and any holes in place by (dx, dy). */
|
|
584
|
+
translatePolygon(p, dx, dy) {
|
|
585
|
+
p.xpoints = p.xpoints.map(x => x + dx);
|
|
586
|
+
p.ypoints = p.ypoints.map(y => y + dy);
|
|
587
|
+
p.coordinates = p.xpoints.map((x, i) => [x, p.ypoints[i]]);
|
|
588
|
+
if (p.holes)
|
|
589
|
+
p.holes = p.holes.map(ring => ring.map(([x, y]) => [x + dx, y + dy]));
|
|
590
|
+
}
|
|
591
|
+
// ── IRegionEditApi: vertex edits (polygons only) ───────────────────────
|
|
592
|
+
moveVertex(id, index, x, y) {
|
|
593
|
+
const poly = this.polygonOf(id);
|
|
594
|
+
if (!poly || index < 0 || index >= poly.xpoints.length)
|
|
595
|
+
return;
|
|
596
|
+
this.recordUndoSnapshot();
|
|
597
|
+
poly.xpoints[index] = x;
|
|
598
|
+
poly.ypoints[index] = y;
|
|
599
|
+
poly.coordinates[index] = [x, y];
|
|
600
|
+
this.syncCache();
|
|
601
|
+
this.emit();
|
|
602
|
+
}
|
|
603
|
+
/** Move a vertex on a polygon's interior ring (hole) — jit-ui#85. */
|
|
604
|
+
moveHoleVertex(id, holeIndex, index, x, y) {
|
|
605
|
+
const poly = this.polygonOf(id);
|
|
606
|
+
if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
|
|
607
|
+
return;
|
|
608
|
+
const ring = poly.holes[holeIndex];
|
|
609
|
+
if (index < 0 || index >= ring.length)
|
|
610
|
+
return;
|
|
611
|
+
this.recordUndoSnapshot();
|
|
612
|
+
ring[index] = [x, y];
|
|
613
|
+
this.syncCache();
|
|
614
|
+
this.emit();
|
|
615
|
+
}
|
|
616
|
+
/** Insert a vertex on a polygon's interior ring (hole), after `segIndex`
|
|
617
|
+
* (the edge's start vertex). No-op for an out-of-range hole — jit-ui#85. */
|
|
618
|
+
addHoleVertex(id, holeIndex, segIndex, x, y) {
|
|
619
|
+
const poly = this.polygonOf(id);
|
|
620
|
+
if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
|
|
621
|
+
return;
|
|
622
|
+
const ring = poly.holes[holeIndex];
|
|
623
|
+
this.recordUndoSnapshot();
|
|
624
|
+
const at = Math.max(0, Math.min(segIndex + 1, ring.length));
|
|
625
|
+
ring.splice(at, 0, [x, y]);
|
|
626
|
+
if (poly.bezier)
|
|
627
|
+
this.seedHoleHandles(poly); // keep hole handles aligned to the ring
|
|
628
|
+
this.syncCache();
|
|
629
|
+
this.emit();
|
|
630
|
+
}
|
|
631
|
+
/** Delete the vertex at `index` on a polygon's interior ring (hole). Removing
|
|
632
|
+
* it below 3 vertices drops the whole hole (a ring with < 3 points bounds no
|
|
633
|
+
* area) — jit-ui#85. */
|
|
634
|
+
deleteHoleVertex(id, holeIndex, index) {
|
|
635
|
+
const poly = this.polygonOf(id);
|
|
636
|
+
if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
|
|
637
|
+
return;
|
|
638
|
+
const ring = poly.holes[holeIndex];
|
|
639
|
+
if (index < 0 || index >= ring.length)
|
|
640
|
+
return;
|
|
641
|
+
this.recordUndoSnapshot();
|
|
642
|
+
if (ring.length <= 3) {
|
|
643
|
+
poly.holes.splice(holeIndex, 1);
|
|
644
|
+
if (poly.holes.length === 0)
|
|
645
|
+
poly.holes = undefined;
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
ring.splice(index, 1);
|
|
649
|
+
}
|
|
650
|
+
if (poly.bezier)
|
|
651
|
+
this.seedHoleHandles(poly); // keep hole handles aligned to the ring(s)
|
|
652
|
+
this.syncCache();
|
|
653
|
+
this.emit();
|
|
654
|
+
}
|
|
655
|
+
addVertex(id, segIndex, x, y) {
|
|
656
|
+
const poly = this.polygonOf(id);
|
|
657
|
+
if (!poly)
|
|
658
|
+
return;
|
|
659
|
+
this.recordUndoSnapshot();
|
|
660
|
+
// Insert after segIndex (the start vertex of the edge). Clamp to range.
|
|
661
|
+
const at = Math.max(0, Math.min(segIndex + 1, poly.xpoints.length));
|
|
662
|
+
poly.xpoints.splice(at, 0, x);
|
|
663
|
+
poly.ypoints.splice(at, 0, y);
|
|
664
|
+
poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
|
|
665
|
+
poly.npoints = poly.xpoints.length;
|
|
666
|
+
// Give the new vertex smooth handles from its neighbours; keep the others'
|
|
667
|
+
// (possibly hand-edited) handles intact.
|
|
668
|
+
if (poly.bezier && poly.handlesIn && poly.handlesOut) {
|
|
669
|
+
const n = poly.xpoints.length;
|
|
670
|
+
const closed = poly.closed !== false;
|
|
671
|
+
const prev = closed ? (at - 1 + n) % n : Math.max(0, at - 1);
|
|
672
|
+
const next = closed ? (at + 1) % n : Math.min(n - 1, at + 1);
|
|
673
|
+
const tx = (poly.xpoints[next] - poly.xpoints[prev]) / 6;
|
|
674
|
+
const ty = (poly.ypoints[next] - poly.ypoints[prev]) / 6;
|
|
675
|
+
poly.handlesIn.splice(at, 0, [-tx, -ty]);
|
|
676
|
+
poly.handlesOut.splice(at, 0, [tx, ty]);
|
|
677
|
+
}
|
|
678
|
+
this.syncCache();
|
|
679
|
+
this.emit();
|
|
680
|
+
}
|
|
681
|
+
deleteVertex(id, index) {
|
|
682
|
+
const poly = this.polygonOf(id);
|
|
683
|
+
if (!poly || index < 0 || index >= poly.xpoints.length)
|
|
684
|
+
return;
|
|
685
|
+
const min = poly.closed === false ? 2 : 3;
|
|
686
|
+
if (poly.xpoints.length <= min)
|
|
687
|
+
return; // refuse to degenerate the polygon
|
|
688
|
+
this.recordUndoSnapshot();
|
|
689
|
+
poly.xpoints.splice(index, 1);
|
|
690
|
+
poly.ypoints.splice(index, 1);
|
|
691
|
+
poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
|
|
692
|
+
poly.npoints = poly.xpoints.length;
|
|
693
|
+
if (poly.bezier && poly.handlesIn && poly.handlesOut) {
|
|
694
|
+
poly.handlesIn.splice(index, 1);
|
|
695
|
+
poly.handlesOut.splice(index, 1);
|
|
696
|
+
}
|
|
697
|
+
this.syncCache();
|
|
698
|
+
this.emit();
|
|
699
|
+
}
|
|
700
|
+
setBezier(id, bezier) {
|
|
701
|
+
const r = this.findById(id);
|
|
702
|
+
if (!r || !r.bounds)
|
|
703
|
+
return;
|
|
704
|
+
if (r.bounds instanceof Polygon) {
|
|
705
|
+
if (r.bounds.bezier === bezier)
|
|
706
|
+
return;
|
|
707
|
+
this.recordUndoSnapshot();
|
|
708
|
+
this.applyBezier(r.bounds, bezier);
|
|
709
|
+
}
|
|
710
|
+
else if (r.bounds instanceof Rectangle && bezier) {
|
|
711
|
+
this.recordUndoSnapshot();
|
|
712
|
+
// Smoothing a rectangle: convert it to a 4-anchor closed polygon first.
|
|
713
|
+
const b = r.bounds;
|
|
714
|
+
const xs = [b.x, b.x + b.width, b.x + b.width, b.x];
|
|
715
|
+
const ys = [b.y, b.y, b.y + b.height, b.y + b.height];
|
|
716
|
+
const poly = new Polygon();
|
|
717
|
+
poly.npoints = 4;
|
|
718
|
+
poly.xpoints = xs;
|
|
719
|
+
poly.ypoints = ys;
|
|
720
|
+
poly.coordinates = xs.map((x, i) => [x, ys[i]]);
|
|
721
|
+
poly.closed = true;
|
|
722
|
+
this.applyBezier(poly, true);
|
|
723
|
+
r.bounds = poly;
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
return; // bezier=false on a rectangle: nothing to do
|
|
727
|
+
}
|
|
728
|
+
this.syncCache();
|
|
729
|
+
this.emit();
|
|
730
|
+
}
|
|
731
|
+
/** Turn bezier on (and seed editable handles from the smooth default) or off
|
|
732
|
+
* (and drop the handles). */
|
|
733
|
+
applyBezier(poly, bezier) {
|
|
734
|
+
poly.bezier = bezier;
|
|
735
|
+
if (bezier) {
|
|
736
|
+
const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
|
|
737
|
+
poly.handlesIn = off.in;
|
|
738
|
+
poly.handlesOut = off.out;
|
|
739
|
+
this.seedHoleHandles(poly); // smooth the holes too (donut → bezier curves the holes)
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
poly.handlesIn = undefined;
|
|
743
|
+
poly.handlesOut = undefined;
|
|
744
|
+
poly.holeHandlesIn = undefined;
|
|
745
|
+
poly.holeHandlesOut = undefined;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
/** (Re)seed per-hole bezier handles from the Catmull-Rom default, parallel to `poly.holes`. */
|
|
749
|
+
seedHoleHandles(poly) {
|
|
750
|
+
if (!poly.holes || !poly.holes.length) {
|
|
751
|
+
poly.holeHandlesIn = undefined;
|
|
752
|
+
poly.holeHandlesOut = undefined;
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
const ins = [];
|
|
756
|
+
const outs = [];
|
|
757
|
+
for (const ring of poly.holes) {
|
|
758
|
+
const off = defaultHandleOffsets(ring.map((p) => p[0]), ring.map((p) => p[1]), true);
|
|
759
|
+
ins.push(off.in);
|
|
760
|
+
outs.push(off.out);
|
|
761
|
+
}
|
|
762
|
+
poly.holeHandlesIn = ins;
|
|
763
|
+
poly.holeHandlesOut = outs;
|
|
764
|
+
}
|
|
765
|
+
/** Drag a bezier control point on a hole ring vertex (donut bezier editing). */
|
|
766
|
+
moveHoleBezierHandle(id, holeIndex, index, side, x, y) {
|
|
767
|
+
const poly = this.polygonOf(id);
|
|
768
|
+
if (!poly || !poly.bezier || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length) {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const ring = poly.holes[holeIndex];
|
|
772
|
+
if (index < 0 || index >= ring.length)
|
|
773
|
+
return;
|
|
774
|
+
this.recordUndoSnapshot();
|
|
775
|
+
if (!poly.holeHandlesIn || !poly.holeHandlesOut)
|
|
776
|
+
this.seedHoleHandles(poly);
|
|
777
|
+
const offset = [x - ring[index][0], y - ring[index][1]];
|
|
778
|
+
if (side === 'in')
|
|
779
|
+
poly.holeHandlesIn[holeIndex][index] = offset;
|
|
780
|
+
else
|
|
781
|
+
poly.holeHandlesOut[holeIndex][index] = offset;
|
|
782
|
+
this.syncCache();
|
|
783
|
+
this.emit();
|
|
784
|
+
}
|
|
785
|
+
moveBezierHandle(id, index, side, x, y) {
|
|
786
|
+
const poly = this.polygonOf(id);
|
|
787
|
+
if (!poly || !poly.bezier || index < 0 || index >= poly.xpoints.length)
|
|
788
|
+
return;
|
|
789
|
+
this.recordUndoSnapshot();
|
|
790
|
+
if (!poly.handlesIn || !poly.handlesOut) {
|
|
791
|
+
const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
|
|
792
|
+
poly.handlesIn = off.in;
|
|
793
|
+
poly.handlesOut = off.out;
|
|
794
|
+
}
|
|
795
|
+
const offset = [x - poly.xpoints[index], y - poly.ypoints[index]];
|
|
796
|
+
if (side === 'in')
|
|
797
|
+
poly.handlesIn[index] = offset;
|
|
798
|
+
else
|
|
799
|
+
poly.handlesOut[index] = offset;
|
|
800
|
+
this.syncCache();
|
|
801
|
+
this.emit();
|
|
802
|
+
}
|
|
803
|
+
beginBatch() { this.batchDepth++; }
|
|
804
|
+
endBatch() {
|
|
805
|
+
if (this.batchDepth > 0)
|
|
806
|
+
this.batchDepth--;
|
|
807
|
+
if (this.batchDepth === 0 && this.pendingEmit) {
|
|
808
|
+
this.pendingEmit = false;
|
|
809
|
+
this.regionUpdate$.next(this.getRegions());
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// ── per-image lifecycle ────────────────────────────────────────────────
|
|
813
|
+
/**
|
|
814
|
+
* Switch the active image: snapshot the outgoing regions, restore the
|
|
815
|
+
* incoming image's (or [] if none), clear selection, and notify. Idempotent
|
|
816
|
+
* for the same image (so repeated replots of one image keep its regions).
|
|
817
|
+
*/
|
|
818
|
+
setActiveImage(imageInfo) {
|
|
819
|
+
const newKey = this.deriveImageKey(imageInfo);
|
|
820
|
+
if (this.currentImageKey === newKey)
|
|
821
|
+
return;
|
|
822
|
+
// Switching images ends any per-slice stack session (jit-ui#93); the loader
|
|
823
|
+
// re-enters stack mode afterwards if the new image is itself a z-stack.
|
|
824
|
+
this.exitStackMode();
|
|
825
|
+
if (this.currentImageKey) {
|
|
826
|
+
this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
|
|
827
|
+
}
|
|
828
|
+
this.currentImageKey = newKey;
|
|
829
|
+
this.regions = (newKey && this.regionsByImageKey.get(newKey))
|
|
830
|
+
? this.regionsByImageKey.get(newKey).slice()
|
|
831
|
+
: [];
|
|
832
|
+
this.previousRegions = this.regions.slice();
|
|
833
|
+
this.selectedIds = [];
|
|
834
|
+
// Undo never crosses an image switch.
|
|
835
|
+
this.resetUndoHistory();
|
|
836
|
+
this.emitSelection();
|
|
837
|
+
this.regionUpdate$.next(this.getRegions());
|
|
838
|
+
}
|
|
839
|
+
/** Drop the entire per-image cache (logout / project switch). */
|
|
840
|
+
clearRegionsByImageKey() {
|
|
841
|
+
this.regionsByImageKey.clear();
|
|
842
|
+
this.currentImageKey = undefined;
|
|
843
|
+
this.regions = [];
|
|
844
|
+
this.selectedIds = [];
|
|
845
|
+
this.resetUndoHistory();
|
|
846
|
+
}
|
|
847
|
+
// ── internals ──────────────────────────────────────────────────────────
|
|
848
|
+
deriveImageKey(imageInfo) {
|
|
849
|
+
if (!imageInfo)
|
|
850
|
+
return undefined;
|
|
851
|
+
if (imageInfo.urls && imageInfo.urls.length > 0 && imageInfo.urls[0]) {
|
|
852
|
+
return imageInfo.urls[0];
|
|
853
|
+
}
|
|
854
|
+
return imageInfo.fileName || undefined;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Resolve each region's colour from the annotation-class preset set (jit-ui#70).
|
|
858
|
+
* The presets are the source of truth for colour — this **overrides any colour
|
|
859
|
+
* embedded in the GeoJSON** (which the YOLO worker writes today). A matching
|
|
860
|
+
* preset gives the class colour; an unknown class gets a deterministic fallback
|
|
861
|
+
* colour (and, only when `autoPromote` is on, is added to the editable list).
|
|
862
|
+
* Regions the user explicitly recoloured (`colorOverridden`) are left untouched.
|
|
863
|
+
*/
|
|
864
|
+
applyClassificationColors(regions) {
|
|
865
|
+
const set = this.store.getPresetSet();
|
|
866
|
+
const keyOf = (label) => set.matchMode === 'normalized' ? label.trim().toLowerCase() : label;
|
|
867
|
+
const known = new Set(set.classes.map((c) => keyOf(c.name)));
|
|
868
|
+
for (const region of regions) {
|
|
869
|
+
if (!region.label || region.colorOverridden)
|
|
870
|
+
continue;
|
|
871
|
+
const preset = findPreset(region.label, set);
|
|
872
|
+
if (preset) {
|
|
873
|
+
region.color = preset.color;
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
const color = fallbackColorFor(region.label, set.fallbackPalette);
|
|
877
|
+
region.color = color;
|
|
878
|
+
if (set.autoPromote && !known.has(keyOf(region.label))) {
|
|
879
|
+
known.add(keyOf(region.label));
|
|
880
|
+
// In normalized mode, trim the promoted name so leading/trailing
|
|
881
|
+
// whitespace doesn't create invisible duplicates or odd display names.
|
|
882
|
+
const name = set.matchMode === 'normalized' ? region.label.trim() : region.label;
|
|
883
|
+
this.store.upsertClass({ name, color, source: 'auto' });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
syncCache() {
|
|
888
|
+
if (this.currentImageKey) {
|
|
889
|
+
this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
emit() {
|
|
893
|
+
// Live-edit listeners (e.g. the intensity-profile inset) react on EVERY
|
|
894
|
+
// change — including per-frame during a batched drag — so they track the
|
|
895
|
+
// region live. The main regionUpdate$ stays coalesced during a batch (fires
|
|
896
|
+
// once on endBatch) to keep heavier consumers (Regions tab) calm.
|
|
897
|
+
this.regionLiveEdit$.next(this.regions.slice());
|
|
898
|
+
if (this.batchDepth > 0) {
|
|
899
|
+
this.pendingEmit = true;
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
this.regionUpdate$.next(this.getRegions());
|
|
903
|
+
}
|
|
904
|
+
/** Project selected ids to current array indices, pruning ids that no longer
|
|
905
|
+
* exist, and emit if the index set changed. */
|
|
906
|
+
emitSelection() {
|
|
907
|
+
const indices = [];
|
|
908
|
+
const liveIds = [];
|
|
909
|
+
for (const id of this.selectedIds) {
|
|
910
|
+
const idx = this.indexOfId(id);
|
|
911
|
+
if (idx >= 0) {
|
|
912
|
+
indices.push(idx);
|
|
913
|
+
liveIds.push(id);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
this.selectedIds = liveIds;
|
|
917
|
+
if (!this.indicesEqual(this.selectedIndices$.value, indices)) {
|
|
918
|
+
this.selectedIndices$.next(indices);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
indicesEqual(a, b) {
|
|
922
|
+
if (a.length !== b.length)
|
|
923
|
+
return false;
|
|
924
|
+
for (let i = 0; i < a.length; i++)
|
|
925
|
+
if (a[i] !== b[i])
|
|
926
|
+
return false;
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
findById(id) {
|
|
930
|
+
return this.regions.find(r => r.id === id);
|
|
931
|
+
}
|
|
932
|
+
indexOfId(id) {
|
|
933
|
+
return this.regions.findIndex(r => r.id === id);
|
|
934
|
+
}
|
|
935
|
+
/** The region's bounds as a Polygon, or undefined if it isn't a polygon. */
|
|
936
|
+
polygonOf(id) {
|
|
937
|
+
const r = this.findById(id);
|
|
938
|
+
return r && r.bounds instanceof Polygon ? r.bounds : undefined;
|
|
939
|
+
}
|
|
940
|
+
clonePolygon(p) {
|
|
941
|
+
const poly = new Polygon();
|
|
942
|
+
poly.npoints = p.npoints;
|
|
943
|
+
poly.xpoints = p.xpoints.slice();
|
|
944
|
+
poly.ypoints = p.ypoints.slice();
|
|
945
|
+
poly.coordinates = p.coordinates.map(c => c.slice());
|
|
946
|
+
poly.closed = p.closed;
|
|
947
|
+
poly.bezier = p.bezier;
|
|
948
|
+
if (p.handlesIn)
|
|
949
|
+
poly.handlesIn = p.handlesIn.map(o => o.slice());
|
|
950
|
+
if (p.handlesOut)
|
|
951
|
+
poly.handlesOut = p.handlesOut.map(o => o.slice());
|
|
952
|
+
if (p.holes)
|
|
953
|
+
poly.holes = p.holes.map(ring => ring.map(pt => pt.slice()));
|
|
954
|
+
if (p.holeHandlesIn)
|
|
955
|
+
poly.holeHandlesIn = p.holeHandlesIn.map(r => r.map(o => o.slice()));
|
|
956
|
+
if (p.holeHandlesOut)
|
|
957
|
+
poly.holeHandlesOut = p.holeHandlesOut.map(r => r.map(o => o.slice()));
|
|
958
|
+
return poly;
|
|
959
|
+
}
|
|
960
|
+
cloneBounds(bounds) {
|
|
961
|
+
if (bounds instanceof Rectangle) {
|
|
962
|
+
const rect = new Rectangle();
|
|
963
|
+
rect.x = bounds.x;
|
|
964
|
+
rect.y = bounds.y;
|
|
965
|
+
rect.width = bounds.width;
|
|
966
|
+
rect.height = bounds.height;
|
|
967
|
+
return rect;
|
|
968
|
+
}
|
|
969
|
+
if (bounds instanceof MultiPolygon) {
|
|
970
|
+
const mp = new MultiPolygon();
|
|
971
|
+
mp.polygons = bounds.polygons.map(p => this.clonePolygon(p));
|
|
972
|
+
return mp;
|
|
973
|
+
}
|
|
974
|
+
return this.clonePolygon(bounds);
|
|
975
|
+
}
|
|
976
|
+
regionsEqual(a, b) {
|
|
977
|
+
const ba = a.bounds, bb = b.bounds;
|
|
978
|
+
if (ba instanceof Rectangle && bb instanceof Rectangle) {
|
|
979
|
+
return ba.x === bb.x && ba.y === bb.y && ba.width === bb.width && ba.height === bb.height;
|
|
980
|
+
}
|
|
981
|
+
if (ba instanceof MultiPolygon && bb instanceof MultiPolygon) {
|
|
982
|
+
if (ba.polygons.length !== bb.polygons.length)
|
|
983
|
+
return false;
|
|
984
|
+
for (let i = 0; i < ba.polygons.length; i++) {
|
|
985
|
+
if (!this.polygonsEqual(ba.polygons[i], bb.polygons[i]))
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
if (ba instanceof Polygon && bb instanceof Polygon) {
|
|
991
|
+
return this.polygonsEqual(ba, bb);
|
|
992
|
+
}
|
|
993
|
+
return false;
|
|
994
|
+
}
|
|
995
|
+
polygonsEqual(pa, pb) {
|
|
996
|
+
if ((pa.closed !== false) !== (pb.closed !== false))
|
|
997
|
+
return false;
|
|
998
|
+
if (pa.xpoints.length !== pb.xpoints.length)
|
|
999
|
+
return false;
|
|
1000
|
+
for (let i = 0; i < pa.xpoints.length; i++) {
|
|
1001
|
+
if (pa.xpoints[i] !== pb.xpoints[i] || pa.ypoints[i] !== pb.ypoints[i])
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
return this.holesEqual(pa.holes, pb.holes);
|
|
1005
|
+
}
|
|
1006
|
+
/** Compare two polygons' interior-ring (hole) sets for the dedupe path. */
|
|
1007
|
+
holesEqual(a, b) {
|
|
1008
|
+
const na = a?.length ?? 0, nb = b?.length ?? 0;
|
|
1009
|
+
if (na !== nb)
|
|
1010
|
+
return false;
|
|
1011
|
+
for (let h = 0; h < na; h++) {
|
|
1012
|
+
const ra = a[h], rb = b[h];
|
|
1013
|
+
if (ra.length !== rb.length)
|
|
1014
|
+
return false;
|
|
1015
|
+
for (let i = 0; i < ra.length; i++) {
|
|
1016
|
+
if (ra[i][0] !== rb[i][0] || ra[i][1] !== rb[i][1])
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
return true;
|
|
1021
|
+
}
|
|
1022
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, deps: [{ token: i1.VisualizerStore }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1023
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, providedIn: 'root' }); }
|
|
1024
|
+
}
|
|
1025
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, decorators: [{
|
|
1026
|
+
type: Injectable,
|
|
1027
|
+
args: [{ providedIn: 'root' }]
|
|
1028
|
+
}], ctorParameters: () => [{ type: i1.VisualizerStore }] });
|
|
1029
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFHeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7QUFFbEU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFFSCxNQUFNLE9BQU8sV0FBVzthQUVFLGVBQVUsR0FBRyxFQUFFLEFBQUwsQ0FBTTthQUNoQixxQkFBZ0IsR0FBRyxHQUFHLEFBQU4sQ0FBTztJQWtGL0MsWUFBb0IsS0FBc0I7UUFBdEIsVUFBSyxHQUFMLEtBQUssQ0FBaUI7UUFoRjFDO2lDQUN5QjtRQUNqQixzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQztRQUV4RCw0REFBNEQ7UUFDcEQsWUFBTyxHQUFhLEVBQUUsQ0FBQztRQUMvQixnRUFBZ0U7UUFDeEQsb0JBQWUsR0FBYSxFQUFFLENBQUM7UUFFdkM7Ozs7Ozs7Ozs7Ozs7V0FhRztRQUNLLGNBQVMsR0FBZSxFQUFFLENBQUM7UUFDM0IsY0FBUyxHQUFlLEVBQUUsQ0FBQztRQUNuQyw0RUFBNEU7UUFDcEUsa0JBQWEsR0FBRyxLQUFL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QUUsS0FBSyxFQUFFO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDNUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sRUFBRSxHQUFJLENBQWtCLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFJLENBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0QsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLEVBQUUsQ0FBQyxNQUFNO2dCQUFFLE9BQU8sS0FBSyxDQUFDO1lBQzFDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ25DLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFBRSxPQUFPLEtBQUssQ0FBQztZQUNuRSxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzs4R0FqK0JVLFdBQVc7a0hBQVgsV0FBVyxjQURFLE1BQU07OzJGQUNuQixXQUFXO2tCQUR2QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFJlZ2lvbiwgUmVjdGFuZ2xlLCBQb2x5Z29uLCBNdWx0aVBvbHlnb24gfSBmcm9tICcuLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFBsb3RVdGlsaXRpZXMgfSBmcm9tICcuLi9wbG90LnV0aWxpdGllcyc7XG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuL3Zpc3VhbGl6ZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBkZWZhdWx0SGFuZGxlT2Zmc2V0cyB9IGZyb20gJy4uL21vZGVscy9iZXppZXInO1xuaW1wb3J0IHsgSVJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHsgSVJlZ2lvbkVkaXRBcGkgfSBmcm9tICcuLi9jb250cmFjdHMvcmVnaW9uLXN0b3JlLmNvbnRyYWN0JztcbmltcG9ydCB7IGZpbmRQcmVzZXQsIGZhbGxiYWNrQ29sb3JGb3IgfSBmcm9tICcuL2NsYXNzLWNvbG9yLnV0aWwnO1xuXG4vKipcbiAqIEJhY2tlbmQtbmV1dHJhbCByZWdpb24gc3RvcmUg4oCUIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciByZWdpb24gc3RhdGUuXG4gKlxuICogSG9sZHMgdGhlIG5ldXRyYWwge0BsaW5rIFJlZ2lvbn0gbW9kZWwgKG5ldmVyIGEgYmFja2VuZCdzIG93biBzaGFwZVxuICogcmVwcmVzZW50YXRpb24pLCBrZXllZCBwZXIgaW1hZ2Ugc28gcmVnaW9ucyBwZXJzaXN0IGFzIHRoZSB1c2VyIHN3aXRjaGVzXG4gKiBmaWxlcyBhbmQgc3Vydml2ZSBhIFBsb3RseeKHhE9wZW5TZWFkcmFnb24gYmFja2VuZCBzd2l0Y2ggKGJvdGggYmFja2VuZHMgcmVhZFxuICogYW5kIHdyaXRlICp0aGlzKiBzdG9yZSwgc28gbm8gbWlncmF0aW9uIGlzIG5lZWRlZCkuIEJhY2tlbmRzIG93biAqcmVuZGVyaW5nKlxuICogYW5kIHJlYWN0IHRvIHtAbGluayBnZXRSZWdpb25VcGRhdGVFdmVudH07IHRoaXMgc2VydmljZSBvd25zICpzdGF0ZSogYW5kIHRoZVxuICogZWRpdGluZyBvcGVyYXRpb25zLlxuICpcbiAqIEltcGxlbWVudHM6XG4gKiAgLSB7QGxpbmsgSVJlZ2lvblN0b3JlfSDigJQgdGhlIGNyb3NzLWJhY2tlbmQgQ1JVRC9zZWxlY3Rpb24vY29sb3VyIGNvbnRyYWN0XG4gKiAgICBldmVyeSBjb25zdW1lciAoUmVnaW9uIEVkaXRvciwgc2VnbWVudGF0aW9uLCBldGMuKSBhbHJlYWR5IHVzZXMuXG4gKiAgLSB7QGxpbmsgSVJlZ2lvbkVkaXRBcGl9IOKAlCBSZWdpb24tbmF0aXZlIGdlb21ldHJ5IGVkaXRzIChtb3ZlL3Jlc2l6ZSwgYW5kXG4gKiAgICBhZGQvZGVsZXRlL21vdmUgdmVydGV4KSB0aGUgT1NEIG92ZXJsYXkgZHJpdmVzLlxuICpcbiAqIENsYXNzaWZpY2F0aW9uIGNvbG91cnMgbGl2ZSBpbiB7QGxpbmsgVmlzdWFsaXplclN0b3JlfSAoc2hhcmVkIGJ5IGJvdGhcbiAqIGJhY2tlbmRzKTsgR2VvSlNPTiBpbXBvcnQvZXhwb3J0IGFuZCB0aGUgY2xvc2VkLXBvbHlnb24gcHJvamVjdGlvbiByZXVzZSB0aGVcbiAqIG5ldXRyYWwge0BsaW5rIFBsb3RVdGlsaXRpZXN9IGhlbHBlcnMuIEFsbCBjb29yZGluYXRlcyBhcmUgaW1hZ2UgcGl4ZWxzLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJlZ2lvblN0b3JlIGltcGxlbWVudHMgSVJlZ2lvblN0b3JlLCBJUmVnaW9uRWRpdEFwaSB7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgVU5ET19MSU1JVCA9IDEwO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBVTkRPX0NPQUxFU0NFX01TID0gMjUwO1xuXG4gIC8qKiBQZXItaW1hZ2UgcmVnaW9uIGNhY2hlLiBgcmVnaW9uc2AgaXMgYWx3YXlzIGEgc25hcHNob3Qgb2YgdGhlIGVudHJ5IGZvclxuICAgKiAgYGN1cnJlbnRJbWFnZUtleWAuICovXG4gIHByaXZhdGUgcmVnaW9uc0J5SW1hZ2VLZXkgPSBuZXcgTWFwPHN0cmluZywgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgY3VycmVudEltYWdlS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBUaGUgY3VycmVudCBpbWFnZSdzIHJlZ2lvbnMg4oCUIHRoZSBsaXZlLCBlZGl0ZWQgYXJyYXkuICovXG4gIHByaXZhdGUgcmVnaW9uczogUmVnaW9uW10gPSBbXTtcbiAgLyoqIExhc3Qgc2F2ZWQgc25hcHNob3QsIHJlc3RvcmFibGUgdmlhIHBsb3RQcmV2aW91c1NoYXBlcygpLiAqL1xuICBwcml2YXRlIHByZXZpb3VzUmVnaW9uczogUmVnaW9uW10gPSBbXTtcblxuICAvKipcbiAgICogVW5kby9yZWRvIGhpc3RvcnkgKGppdC11aSM4NSk6IHVwIHRvIHtAbGluayBVTkRPX0xJTUlUfSBzbmFwc2hvdHMgb2YgdGhlXG4gICAqIHJlZ2lvbiBzZXQsIGVhY2ggYSBkZWVwIGNsb25lIGNhcHR1cmVkIGltbWVkaWF0ZWx5ICpiZWZvcmUqIGFcbiAgICogcmVnaW9uLWVkaXRpbmcgYWN0aW9uLiB7QGxpbmsgdW5kb30gcG9wcyB0aGUgbmV3ZXN0IG9mZiBgdW5kb1N0YWNrYCwgcHVzaGVzXG4gICAqIHRoZSBjdXJyZW50IHN0YXRlIG9udG8gYHJlZG9TdGFja2AsIGFuZCByZXN0b3JlcyBpdCDigJQgc28gaXQgY2FuIGJlIGludm9rZWRcbiAgICogdXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHRpbWVzIGluIGEgcm93LiB7QGxpbmsgcmVkb30gaXMgdGhlIG1pcnJvci4gQW55IG5ld1xuICAgKiByZWdpb24gYWN0aW9uIGNsZWFycyBgcmVkb1N0YWNrYCAodGhlIHJlZG8gZnV0dXJlIGlzIG5vIGxvbmdlciByZWFjaGFibGUpLlxuICAgKlxuICAgKiBBIGNvbnRpbnVvdXMgZ2VzdHVyZSAoYSB3YW5kL2JydXNoL3ZlcnRleCBkcmFnIGNvbW1pdHMgdG8gdGhlIHN0b3JlIG1hbnlcbiAgICogdGltZXMpIGlzIGNvYWxlc2NlZCBpbnRvIGEgc2luZ2xlIGVudHJ5OiB0aGUgZmlyc3QgY29tbWl0IG9mIGEgYnVyc3RcbiAgICogY2FwdHVyZXMgdGhlIHByZS1idXJzdCBzdGF0ZSBhbmQgZXZlcnkgY29tbWl0IHdpdGhpblxuICAgKiB7QGxpbmsgVU5ET19DT0FMRVNDRV9NU30gb2YgdGhlIHByZXZpb3VzIG9uZSBpcyBmb2xkZWQgaW50byBpdC4gSGlzdG9yeVxuICAgKiBuZXZlciBjcm9zc2VzIGFuIGltYWdlIGxvYWQvc3dpdGNoIOKAlCB7QGxpbmsgcmVzZXRVbmRvSGlzdG9yeX0gY2xlYXJzIGl0LlxuICAgKi9cbiAgcHJpdmF0ZSB1bmRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgcHJpdmF0ZSByZWRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgLyoqIFRydWUgd2hpbGUgYSBjb2FsZXNjaW5nIGJ1cnN0IGlzIG9wZW4gKGZ1cnRoZXIgY29tbWl0cyBmb2xkIGludG8gaXQpLiAqL1xuICBwcml2YXRlIHVuZG9CdXJzdE9wZW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSB1bmRvQnVyc3RUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRydWUgd2hpbGUgcmVzdG9yaW5nIGEgc25hcHNob3QsIHNvIHRoZSByZXN0b3JlIHJlY29yZHMgbm8gbmV3IGhpc3RvcnkuICovXG4gIHByaXZhdGUgcmVzdG9yaW5nVW5kbyA9IGZhbHNlO1xuICBwcml2YXRlIHJlYWRvbmx5IGNhblVuZG8kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2FuUmVkbyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICAvKiogTW9ub3RvbmljIGlkIHNvdXJjZSDigJQgaWRzIG5ldmVyIHJlcGVhdCB3aXRoaW4gdGhlIHNlcnZpY2UgbGlmZXRpbWUsIHNvXG4gICAqICBzZWxlY3Rpb24gc3RheXMgY29ycmVjdCBhY3Jvc3MgZGVsZXRlL2FkZCBjeWNsZXMgZXZlbiB3aGVuIG5hbWVzIGNvbGxpZGUuICovXG4gIHByaXZhdGUgbmV4dElkID0gMTtcblxuICBwcml2YXRlIHNob3dTaGFwZUxhYmVsID0gZmFsc2U7XG4gIHByaXZhdGUgc2hhcGVDb2xvciA9ICcjMDBGRkZGJztcbiAgcHJpdmF0ZSBmaWxsQ29sb3IgPSAnI2ZmMDBmZic7XG4gIHByaXZhdGUgaXNSZWdpb25TYXZlZE9uID0gdHJ1ZTtcblxuICAvKipcbiAgICogUGVyLXNsaWNlIHJlZ2lvbiBzdXBwb3J0IGZvciB6LXN0YWNrcyAoaml0LXVpIzkzKS4gV2hpbGUge0BsaW5rIHN0YWNrTW9kZX1cbiAgICogaXMgb24gKGEgei1zdGFjayBpcyBsb2FkZWQpLCB0aGUgbGl2ZSBgcmVnaW9uc2AgYXJyYXkgYWx3YXlzIGhvbGRzIE9ORVxuICAgKiBzbGljZSDigJQgdGhlIHtAbGluayBjdXJyZW50U2xpY2VafSBzbGljZSDigJQgc28gdGhlIG9uLWNhbnZhcyBvdmVybGF5cywgdGhlXG4gICAqIHNlbGVjdGlvbiBwcm9qZWN0aW9uLCBhbmQgdGhlIFJlZ2lvbnMgdGFibGUga2VlcCB3b3JraW5nIHVuY2hhbmdlZFxuICAgKiAodGhleSBhbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pLiBUaGUgb3RoZXIgc2xpY2VzIGxpdmUgaW5cbiAgICoge0BsaW5rIHJlZ2lvbnNCeVNsaWNlfTsge0BsaW5rIHNldERpc3BsYXlTbGljZX0gc3dhcHMgdGhlIGxpdmUgc2V0IG9uIHNjcnViXG4gICAqIGFuZCB7QGxpbmsgZ2V0U2xpY2VSZWdpb25zfSBmbGF0dGVucyBldmVyeSBzbGljZSAoZWFjaCB0YWdnZWQgd2l0aCBpdHNcbiAgICogemVyby1iYXNlZCB7QGxpbmsgUmVnaW9uLnp9KSBmb3Igc2F2ZS9leHBvcnQuIE9mZiBieSBkZWZhdWx0IChzdGFja01vZGVcbiAgICogZmFsc2UsIHogMCksIHNvIHNpbmdsZS1wbGFuZSBpbWFnZXMgYXJlIGNvbXBsZXRlbHkgdW5hZmZlY3RlZC5cbiAgICovXG4gIHByaXZhdGUgcmVnaW9uc0J5U2xpY2UgPSBuZXcgTWFwPG51bWJlciwgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgc3RhY2tNb2RlID0gZmFsc2U7XG4gIHByaXZhdGUgY3VycmVudFNsaWNlWiA9IDA7XG4gIC8qKiBIb3cgYSBzdGFjaydzIHJlZ2lvbnMgcm91bmQtdHJpcCB0byBkaXNrIChqaXQtdWkjOTMpOiBgY29tYmluZWRgIHdyaXRlcyBvbmVcbiAgICogIHotaW5kZXhlZCBnZW9qc29uIChzaW5nbGUtZmlsZSB6LXN0YWNrLCBRdVBhdGggc2NoZW1hKTsgYHBlci1zbGljZS1maWxlYFxuICAgKiAgd3JpdGVzIG9uZSBnZW9qc29uIHBlciBzbGljZS1maWxlIChhIGZvbGRlciBvZiBudW1iZXJlZCBpbWFnZXMpLiAqL1xuICBwcml2YXRlIHN0YWNrU2F2ZUxheW91dDogJ2NvbWJpbmVkJyB8ICdwZXItc2xpY2UtZmlsZScgPSAnY29tYmluZWQnO1xuICAvKiogU2xpY2VzIHRoYXQgd2VyZSBsb2FkZWQgd2l0aCByZWdpb25zIChqaXQtdWkjOTMpLiBBIHBlci1zbGljZS1maWxlIHNhdmVcbiAgICogIHJlLXdyaXRlcyB0aGVzZSBldmVuIHdoZW4gbm93IGVtcHR5LCBzbyBjbGVhcmluZyBhIHNsaWNlJ3MgcmVnaW9ucyBhbmRcbiAgICogIHNhdmluZyByZW1vdmVzIGl0cyBwcmV2aW91c2x5LXNhdmVkIGdlb2pzb24gKHdyaXRlcyBhbiBlbXB0eSBvbmUpLiAqL1xuICBwcml2YXRlIHN0YWNrSW5pdGlhbE5vbkVtcHR5ID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgLyoqIFNlbGVjdGlvbiBpcyB0cmFja2VkIGJ5IHJlZ2lvbiAqaWQqIGludGVybmFsbHkgKHN0YWJsZSBhY3Jvc3MgZWRpdHMpIGFuZFxuICAgKiAgcHJvamVjdGVkIHRvIGFycmF5IGluZGljZXMgb24gdGhlIElSZWdpb25TdG9yZSBib3VuZGFyeS4gKi9cbiAgcHJpdmF0ZSBzZWxlY3RlZElkczogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBzZWxlY3RlZEluZGljZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXJbXT4oW10pO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvblVwZGF0ZSQgPSBuZXcgU3ViamVjdDxSZWdpb25bXT4oKTtcbiAgLyoqIE5vbi1jb2FsZXNjZWQgc2libGluZyBvZiByZWdpb25VcGRhdGUkOiBmaXJlcyBvbiBldmVyeSBjaGFuZ2UgZXZlbiBkdXJpbmcgYVxuICAgKiAgYmF0Y2hlZCBkcmFnLCBzbyBsaXZlIGNvbnN1bWVycyAoaW50ZW5zaXR5IGluc2V0KSB1cGRhdGUgcGVyIGZyYW1lLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbkxpdmVFZGl0JCA9IG5ldyBTdWJqZWN0PFJlZ2lvbltdPigpO1xuXG4gIC8qKiBFbWl0IGNvYWxlc2NpbmcgZm9yIGxpdmUgZHJhZ3MgKHNlZSBJUmVnaW9uRWRpdEFwaS5iZWdpbkJhdGNoKS4gKi9cbiAgcHJpdmF0ZSBiYXRjaERlcHRoID0gMDtcbiAgcHJpdmF0ZSBwZW5kaW5nRW1pdCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGxvdFV0aWxpdGllcyA9IG5ldyBQbG90VXRpbGl0aWVzKCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzdG9yZTogVmlzdWFsaXplclN0b3JlKSB7fVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IENSVUQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlcGxhY2UgKG9yLCB3aXRoIGBhcHBlbmRgLCBhZGQgdG8pIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucy4gTWludHMgaWRzXG4gICAqIGFuZCBkZWZhdWx0IG5hbWVzLCBhcHBsaWVzIHN0b3JlZCBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzLCBhbmQgZW1pdHMuIFdoZW5cbiAgICogYGlzUmVnaW9uU2F2ZU9uYCBpcyBmYWxzZSB0aGUgcmVnaW9ucyBhcmUgc2hvd24gdHJhbnNpZW50bHkgKGVtaXR0ZWQpIGJ1dFxuICAgKiBub3Qgc3RvcmVkIOKAlCBtaXJyb3JzIHRoZSBwcmV2aW91cyBQbG90bHkgYmVoYXZpb3VyLlxuICAgKi9cbiAgc2V0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSwgc2hvd1JlZ2lvbkxhYmVsPzogYm9vbGVhbiwgaXNSZWdpb25TYXZlT24/OiBib29sZWFuLFxuICAgICAgICAgICAgIGZpbGxDb2xvcj86IHN0cmluZywgYXBwZW5kOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcbiAgICBpZiAoc2hvd1JlZ2lvbkxhYmVsID09PSB1bmRlZmluZWQpIHNob3dSZWdpb25MYWJlbCA9IHRoaXMuc2hvd1NoYXBlTGFiZWw7XG4gICAgaWYgKGlzUmVnaW9uU2F2ZU9uID09PSB1bmRlZmluZWQpIGlzUmVnaW9uU2F2ZU9uID0gdGhpcy5pc1JlZ2lvblNhdmVkT247XG4gICAgaWYgKGZpbGxDb2xvciA9PT0gdW5kZWZpbmVkKSBmaWxsQ29sb3IgPSB0aGlzLmZpbGxDb2xvcjtcblxuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHJlZ2lvbnMpIHtcbiAgICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgfVxuICAgIHRoaXMuYXBwbHlDbGFzc2lmaWNhdGlvbkNvbG9ycyhyZWdpb25zKTtcblxuICAgIHRoaXMuaXNSZWdpb25TYXZlZE9uID0gaXNSZWdpb25TYXZlT247XG4gICAgaWYgKGlzUmVnaW9uU2F2ZU9uKSB7XG4gICAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgICAgdGhpcy5zaG93U2hhcGVMYWJlbCA9IHNob3dSZWdpb25MYWJlbDtcbiAgICAgIHRoaXMuZmlsbENvbG9yID0gZmlsbENvbG9yO1xuICAgICAgaWYgKGFwcGVuZCkge1xuICAgICAgICAvLyBSZWplY3QgYnkgaWQgY29sbGlzaW9uIChhbHJlYWR5IHRyYWNrZWQpIG9yIGdlb21ldHJ5IGVxdWFsaXR5IChzYW1lXG4gICAgICAgIC8vIGNvb3JkaW5hdGVzKSDigJQgdGhlIGZpbmQgYnV0dG9uIGNhbiBwdXNoIHRoZSBzYW1lIHJlZ2lvbiByZXBlYXRlZGx5LlxuICAgICAgICBjb25zdCBhZGRlZCA9IHJlZ2lvbnMuZmlsdGVyKHIgPT5cbiAgICAgICAgICAhdGhpcy5yZWdpb25zLnNvbWUoZXhpc3RpbmcgPT4gZXhpc3RpbmcuaWQgPT09IHIuaWQgfHwgdGhpcy5yZWdpb25zRXF1YWwoZXhpc3RpbmcsIHIpKSk7XG4gICAgICAgIHRoaXMucmVnaW9ucyA9IHRoaXMucmVnaW9ucy5jb25jYXQoYWRkZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5yZWdpb25zID0gcmVnaW9ucy5zbGljZSgpO1xuICAgICAgfVxuICAgICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgICAgdGhpcy5lbWl0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRyYW5zaWVudCBkaXNwbGF5IG9ubHkg4oCUIGRvbid0IHRvdWNoIHN0b3JlZCBzdGF0ZS5cbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSBjYW5vbmljYWwgYWNjZXNzb3I6IGN1cnJlbnQgaW1hZ2UncyByZWdpb25zIChsaXZlIGluc3RhbmNlcykuICovXG4gIGdldFJlZ2lvbnMoKTogUmVnaW9uW10ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBQZXItc2xpY2UgcmVnaW9ucyBmb3Igei1zdGFja3MgKGppdC11aSM5Mykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRydWUgd2hpbGUgYSB6LXN0YWNrIGlzIGxvYWRlZCBhbmQgdGhlIHN0b3JlIGhvbGRzIHJlZ2lvbnMgcGVyIHNsaWNlLiAqL1xuICBpc1N0YWNrTW9kZSgpOiBib29sZWFuIHsgcmV0dXJuIHRoaXMuc3RhY2tNb2RlOyB9XG5cbiAgLyoqIFRoZSBjdXJyZW50IGRpc3BsYXkgc2xpY2UgKHplcm8tYmFzZWQpLiAqL1xuICBnZXREaXNwbGF5U2xpY2UoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuY3VycmVudFNsaWNlWjsgfVxuXG4gIC8qKiBIb3cgdGhlIGN1cnJlbnQgc3RhY2sgcGVyc2lzdHMgdG8gZGlzayAoaml0LXVpIzkzKTogYGNvbWJpbmVkYCA9IG9uZVxuICAgKiAgei1pbmRleGVkIGdlb2pzb24gKHNpbmdsZS1maWxlIHotc3RhY2spOyBgcGVyLXNsaWNlLWZpbGVgID0gb25lIGdlb2pzb24gcGVyXG4gICAqICBzbGljZS1maWxlIChmb2xkZXIgc3RhY2spLiBNZWFuaW5nbGVzcyBvdXRzaWRlIHN0YWNrIG1vZGUuICovXG4gIGdldFN0YWNrU2F2ZUxheW91dCgpOiAnY29tYmluZWQnIHwgJ3Blci1zbGljZS1maWxlJyB7IHJldHVybiB0aGlzLnN0YWNrU2F2ZUxheW91dDsgfVxuXG4gIC8qKlxuICAgKiBFbnRlciBwZXItc2xpY2Ugc3RhY2sgbW9kZS4gYHNsaWNlc2AgbWFwcyBlYWNoIHplcm8tYmFzZWQgc2xpY2UgaW5kZXggdG9cbiAgICogdGhlIHJlZ2lvbnMgaW1wb3J0ZWQgZm9yIHRoYXQgc2xpY2U7IHRoZSBzdG9yZSBtYWtlcyBgaW5pdGlhbFpgJ3Mgc2xpY2UgdGhlXG4gICAqIGxpdmUgc2V0LCBzbyB0aGUgb3ZlcmxheXMgLyBzZWxlY3Rpb24gLyBSZWdpb25zIHRhYmxlIGFyZSB1bmNoYW5nZWQgKHRoZXlcbiAgICogc3RpbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pLiBGcmVzaGx5LWNyZWF0ZWQgcmVnaW9ucyBhcmUgdGFnZ2VkIHdpdGggdGhlXG4gICAqIGN1cnJlbnQgc2xpY2Ugc28gdGhleSBwZXJzaXN0IG9uIGl0LCBhbmQge0BsaW5rIGdldFNsaWNlUmVnaW9uc30gcmV0dXJuc1xuICAgKiBldmVyeSBzbGljZSBmb3Igc2F2ZS9leHBvcnQuIElkcy9uYW1lcy9jbGFzc2lmaWNhdGlvbiBjb2xvdXJzIGFyZSBtaW50ZWRcbiAgICogZXhhY3RseSBhcyB7QGxpbmsgc2V0UmVnaW9uc30gZG9lcy5cbiAgICovXG4gIGVudGVyU3RhY2tNb2RlKHNsaWNlczogTWFwPG51bWJlciwgUmVnaW9uW10+LCBpbml0aWFsWiA9IDAsXG4gICAgICAgICAgICAgICAgIHNhdmVMYXlvdXQ6ICdjb21iaW5lZCcgfCAncGVyLXNsaWNlLWZpbGUnID0gJ2NvbWJpbmVkJyk6IHZvaWQge1xuICAgIHRoaXMuc3RhY2tNb2RlID0gdHJ1ZTtcbiAgICB0aGlzLnN0YWNrU2F2ZUxheW91dCA9IHNhdmVMYXlvdXQ7XG4gICAgdGhpcy5jdXJyZW50U2xpY2VaID0gaW5pdGlhbFogfHwgMDtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IFt6LCByZWdzXSBvZiBzbGljZXMpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB0aGlzLm5vcm1hbGl6ZVNsaWNlKHJlZ3MgfHwgW10sIHopO1xuICAgICAgdGhpcy5yZWdpb25zQnlTbGljZS5zZXQoeiwgbm9ybWFsaXplZCk7XG4gICAgICBpZiAobm9ybWFsaXplZC5sZW5ndGgpIHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkuYWRkKHopO1xuICAgIH1cbiAgICB0aGlzLnJlZ2lvbnMgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQodGhpcy5jdXJyZW50U2xpY2VaKSA/PyBbXSkuc2xpY2UoKTtcbiAgICB0aGlzLnByZXZpb3VzUmVnaW9ucyA9IHRoaXMucmVnaW9ucy5zbGljZSgpO1xuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBbXTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqIExlYXZlIHN0YWNrIG1vZGUgKHNpbmdsZS1wbGFuZSBpbWFnZSwgb3IgdGhlIHN0YWNrIHdhcyBjbG9zZWQpLiAqL1xuICBleGl0U3RhY2tNb2RlKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5zdGFja01vZGUpIHJldHVybjtcbiAgICB0aGlzLnN0YWNrTW9kZSA9IGZhbHNlO1xuICAgIHRoaXMuY3VycmVudFNsaWNlWiA9IDA7XG4gICAgdGhpcy5yZWdpb25zQnlTbGljZSA9IG5ldyBNYXA8bnVtYmVyLCBSZWdpb25bXT4oKTtcbiAgICB0aGlzLnN0YWNrSW5pdGlhbE5vbkVtcHR5ID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIH1cblxuICAvKipcbiAgICogU2hvdyBhIGRpZmZlcmVudCBzbGljZTogY2FwdHVyZSB0aGUgY3VycmVudCBzbGljZSdzIChwb3NzaWJseSBlZGl0ZWQpXG4gICAqIHJlZ2lvbnMgYmFjayBpbnRvIHRoZSBwZXItc2xpY2Ugc3RvcmUsIHRoZW4gbG9hZCB0aGUgdGFyZ2V0IHNsaWNlJ3MgcmVnaW9uc1xuICAgKiBhcyB0aGUgbGl2ZSBzZXQgYW5kIGVtaXQuIFVuZG8gbmV2ZXIgY3Jvc3NlcyBhIHNsaWNlLiBPdXRzaWRlIHN0YWNrIG1vZGVcbiAgICogdGhpcyBvbmx5IHJlY29yZHMgdGhlIHJlcXVlc3RlZCBzbGljZSBpbmRleCAoYSBuby1vcCBvdGhlcndpc2U6IHNpbmdsZS1wbGFuZVxuICAgKiByZWdpb25zIHN0YXkgb24gdGhlIGRlZmF1bHQgcGxhbmUg4oCUIGFkZFJlZ2lvbiB0YWdzIFJlZ2lvbi56IG9ubHkgaW4gc3RhY2tcbiAgICogbW9kZSwgc28gdGhlIHJlY29yZGVkIGluZGV4IGlzIHVudXNlZCB1bnRpbCBhIHN0YWNrIGlzIGVudGVyZWQpLiAoaml0LXVpIzkzKVxuICAgKi9cbiAgc2V0RGlzcGxheVNsaWNlKHo6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB6IHx8IDA7XG4gICAgaWYgKCF0aGlzLnN0YWNrTW9kZSkgeyB0aGlzLmN1cnJlbnRTbGljZVogPSBuZXh0OyByZXR1cm47IH1cbiAgICBpZiAodGhpcy5jdXJyZW50U2xpY2VaID09PSBuZXh0KSByZXR1cm47XG4gICAgdGhpcy5yZWdpb25zQnlTbGljZS5zZXQodGhpcy5jdXJyZW50U2xpY2VaLCB0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgdGhpcy5jdXJyZW50U2xpY2VaID0gbmV4dDtcbiAgICB0aGlzLnJlZ2lvbnMgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQobmV4dCkgPz8gW10pLnNsaWNlKCk7XG4gICAgdGhpcy5wcmV2aW91c1JlZ2lvbnMgPSB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gW107XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLnJlc2V0VW5kb0hpc3RvcnkoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmVyeSBzbGljZSdzIHJlZ2lvbnMgZm9yIHNhdmUvZXhwb3J0LCBlYWNoIHRhZ2dlZCB3aXRoIGl0cyB6ZXJvLWJhc2VkXG4gICAqIHNsaWNlIGluZGV4IGluIHtAbGluayBSZWdpb24uen0uIENhcHR1cmVzIHRoZSBjdXJyZW50IHNsaWNlJ3MgbGl2ZSBlZGl0c1xuICAgKiBmaXJzdC4gUmV0dXJucyB0aGUgZmxhdCBzaW5nbGUtcGxhbmUgc2V0IHdoZW4gbm90IGluIHN0YWNrIG1vZGUuIChqaXQtdWkjOTMpXG4gICAqL1xuICBnZXRTbGljZVJlZ2lvbnMoKTogUmVnaW9uW10ge1xuICAgIGlmICghdGhpcy5zdGFja01vZGUpIHJldHVybiB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlLnNldCh0aGlzLmN1cnJlbnRTbGljZVosIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICBjb25zdCBvdXQ6IFJlZ2lvbltdID0gW107XG4gICAgY29uc3QgenMgPSBBcnJheS5mcm9tKHRoaXMucmVnaW9uc0J5U2xpY2Uua2V5cygpKS5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gICAgZm9yIChjb25zdCB6IG9mIHpzKSB7XG4gICAgICBmb3IgKGNvbnN0IHIgb2YgdGhpcy5yZWdpb25zQnlTbGljZS5nZXQoeikgYXMgUmVnaW9uW10pIHtcbiAgICAgICAgci56ID0gejtcbiAgICAgICAgb3V0LnB1c2gocik7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKipcbiAgICogU2xpY2VzIHRvIHdyaXRlIG9uIGEgcGVyLXNsaWNlLWZpbGUgc2F2ZSAoZm9sZGVyIHN0YWNrLCBqaXQtdWkjOTMpOiBldmVyeVxuICAgKiBzbGljZSB0aGF0IGN1cnJlbnRseSBoYXMgcmVnaW9ucywgUExVUyBzbGljZXMgdGhhdCB3ZXJlIGxvYWRlZCBub24tZW1wdHkgYnV0XG4gICAqIGFyZSBub3cgZW1wdHkgKHNvIHRoZWlyIGZpbGUgaXMgcmUtd3JpdHRlbiBlbXB0eSwgY2xlYXJpbmcgYSBzbGljZSB3aG9zZVxuICAgKiByZWdpb25zIHRoZSB1c2VyIGRlbGV0ZWQpLiBFYWNoIHJldHVybmVkIHJlZ2lvbiBpcyB0YWdnZWQgd2l0aCBpdHMgeiwgYW5kXG4gICAqIHRoZSBjdXJyZW50IGxpdmUgc2xpY2UgaXMgY2FwdHVyZWQgZmlyc3QuIEVtcHR5IG91dHNpZGUgc3RhY2sgbW9kZS5cbiAgICovXG4gIGdldFN0YWNrU2F2ZVNsaWNlcygpOiBNYXA8bnVtYmVyLCBSZWdpb25bXT4ge1xuICAgIGNvbnN0IG91dCA9IG5ldyBNYXA8bnVtYmVyLCBSZWdpb25bXT4oKTtcbiAgICBpZiAoIXRoaXMuc3RhY2tNb2RlKSByZXR1cm4gb3V0O1xuICAgIHRoaXMucmVnaW9uc0J5U2xpY2Uuc2V0KHRoaXMuY3VycmVudFNsaWNlWiwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIGNvbnN0IHpzID0gbmV3IFNldDxudW1iZXI+KHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkpO1xuICAgIGZvciAoY29uc3QgW3osIHJlZ3NdIG9mIHRoaXMucmVnaW9uc0J5U2xpY2UpIGlmIChyZWdzLmxlbmd0aCkgenMuYWRkKHopO1xuICAgIGZvciAoY29uc3QgeiBvZiBBcnJheS5mcm9tKHpzKS5zb3J0KChhLCBiKSA9PiBhIC0gYikpIHtcbiAgICAgIGNvbnN0IHJlZ3MgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQoeikgPz8gW10pLm1hcCgocikgPT4geyByLnogPSB6OyByZXR1cm4gcjsgfSk7XG4gICAgICBvdXQuc2V0KHosIHJlZ3MpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqIE1pbnQgaWRzL25hbWVzICsgYXBwbHkgY2xhc3NpZmljYXRpb24gY29sb3VycyArIHRhZyB0aGUgc2xpY2UgaW5kZXgsIGFzXG4gICAqICB7QGxpbmsgc2V0UmVnaW9uc30gZG9lcywgZm9yIHJlZ2lvbnMgZW50ZXJpbmcgdGhlIHBlci1zbGljZSBzdG9yZS4gKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVTbGljZShyZWdpb25zOiBSZWdpb25bXSwgejogbnVtYmVyKTogUmVnaW9uW10ge1xuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHJlZ2lvbnMpIHtcbiAgICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgICByZWdpb24ueiA9IHo7XG4gICAgfVxuICAgIHRoaXMuYXBwbHlDbGFzc2lmaWNhdGlvbkNvbG9ycyhyZWdpb25zKTtcbiAgICByZXR1cm4gcmVnaW9ucy5zbGljZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlZCBwb2x5Z29ucyBwcm9qZWN0ZWQgZm9yIGltYWdlLXByb2Nlc3NpbmcgY29uc3VtZXJzIChzZWdtZW50YXRpb24sXG4gICAqIHRyYWNlIGJ1aWxkZXJzKS4gT3BlbiBwb2x5bGluZXMgYXJlIGFubm90YXRpb24tb25seSBhbmQgZXhjbHVkZWQuIFJldXNlc1xuICAgKiB0aGUgbmV1dHJhbCBQbG90VXRpbGl0aWVzIHByb2plY3Rpb24gc28gb3V0cHV0IG1hdGNoZXMgdGhlIHByZXZpb3VzIHBhdGguXG4gICAqL1xuICBnZXRSZWdpb25Qb2x5Z29ucygpOiBhbnlbXSB7XG4gICAgY29uc3QgcmV0OiBhbnlbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHRoaXMucmVnaW9ucykge1xuICAgICAgY29uc3QgcG9seTogYW55ID0gdGhpcy5wbG90VXRpbGl0aWVzLmdldFBvbHlnb24oeyAuLi5yZWdpb24uZ2V0U2hhcGUodGhpcy5zaG93U2hhcGVMYWJlbCkgfSk7XG4gICAgICBpZiAocG9seSA9PSBudWxsIHx8IHBvbHkuY2xvc2VkID09PSBmYWxzZSkgY29udGludWU7XG4gICAgICByZXQucHVzaChwb2x5KTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIGdldFJlZ2lvblVwZGF0ZUV2ZW50KCk6IE9ic2VydmFibGU8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25VcGRhdGUkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIExpdmUgKG5vbi1jb2FsZXNjZWQpIHJlZ2lvbi1jaGFuZ2Ugc3RyZWFtIOKAlCBmaXJlcyBwZXIgZnJhbWUgZHVyaW5nIGEgZHJhZy5cbiAgICogIFVzZWQgYnkgdGhlIGludGVuc2l0eS1wcm9maWxlIGluc2V0IHNvIGl0IHRyYWNrcyBsaW5lIFJPSXMgbGl2ZS4gKi9cbiAgZ2V0UmVnaW9uTGl2ZUVkaXQkKCk6IE9ic2VydmFibGU8UmVnaW9uW10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25MaXZlRWRpdCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBzZWxlY3Rpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFNlbGVjdCByZWdpb25zIGJ5IGFycmF5IGluZGV4IChvciBbXSB0byBjbGVhcikuIFN0b3JlZCBpbnRlcm5hbGx5IGJ5IGlkXG4gICAqICBzbyB0aGUgc2VsZWN0aW9uIHN1cnZpdmVzIHN1YnNlcXVlbnQgZWRpdHMvcmVvcmRlcnMuICovXG4gIHNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGluZGljZXM6IG51bWJlcltdKTogdm9pZCB7XG4gICAgY29uc3QgaWRzOiBudW1iZXJbXSA9IFtdO1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IGkgb2YgaW5kaWNlcyB8fCBbXSkge1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoaSkgfHwgaSA8IDAgfHwgaSA+PSB0aGlzLnJlZ2lvbnMubGVuZ3RoKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGlkID0gdGhpcy5yZWdpb25zW2ldLmlkO1xuICAgICAgaWYgKCFzZWVuLmhhcyhpZCkpIHsgc2Vlbi5hZGQoaWQpOyBpZHMucHVzaChpZCk7IH1cbiAgICB9XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IGlkcztcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgfVxuXG4gIC8qKiBTZWxlY3QgYSBzaW5nbGUgcmVnaW9uIGJ5IGlkZW50aXR5IChpZCkuIEJhY2tlbmRzIGNhbGwgdGhpcyBmcm9tIHRoZWlyXG4gICAqICBgc2VsZWN0UmVnaW9uKClgOyB0aGUgT1NEIG92ZXJsYXkgKyByZWdpb24gZWRpdG9yIGhpZ2hsaWdodCBvZmYgdGhlXG4gICAqICByZXN1bHRpbmcgc2VsZWN0aW9uIGVtaXQuIE5vLW9wIGlmIHRoZSByZWdpb24gaXNuJ3QgaW4gdGhlIHN0b3JlLiAqL1xuICBzZWxlY3RSZWdpb24ocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBpZiAocmVnaW9uPy5pZCA9PSBudWxsIHx8IHRoaXMuaW5kZXhPZklkKHJlZ2lvbi5pZCkgPCAwKSByZXR1cm47XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtyZWdpb24uaWRdO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICB9XG5cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCk6IE9ic2VydmFibGU8bnVtYmVyW10+IHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZEluZGljZXMkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIGN1cnJlbnQgc2VsZWN0aW9uIChhcnJheSBpbmRpY2VzKSDigJQgZm9yIGNhbGxlcnMgdGhhdCBuZWVkIHRvXG4gICAqICByZWFkIHRoZSBzZWxlY3Rpb24gd2l0aG91dCBzdWJzY3JpYmluZy4gKi9cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGVkSW5kaWNlcyQudmFsdWU7XG4gIH1cblxuICAvKiogRGVsZXRlIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgcmVnaW9ucyBhbmQgY2xlYXIgdGhlIHNlbGVjdGlvbi4gKi9cbiAgZGVsZXRlQWN0aXZlU2hhcGUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRJZHMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0KHRoaXMuc2VsZWN0ZWRJZHMpO1xuICAgIHRoaXMucmVnaW9ucyA9IHRoaXMucmVnaW9ucy5maWx0ZXIociA9PiAhaWRzLmhhcyhyLmlkKSk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBjb2xvdXJzIC8gbGFiZWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGdldFNob3dTaGFwZUxhYmVsKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5zaG93U2hhcGVMYWJlbDsgfVxuICBnZXRTaGFwZUNvbG9yKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLnNoYXBlQ29sb3I7IH1cbiAgZ2V0RmlsbENvbG9yKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLmZpbGxDb2xvcjsgfVxuXG4gIC8qKiBDb252ZW5pZW5jZSBzZXR0ZXJzIChub3Qgb24gdGhlIGNvbnRyYWN0KSBmb3IgdG9vbGJhciB3aXJpbmcuICovXG4gIHNldFNob3dTaGFwZUxhYmVsKHNob3c6IGJvb2xlYW4pOiB2b2lkIHsgdGhpcy5zaG93U2hhcGVMYWJlbCA9IHNob3c7IH1cbiAgc2V0U2hhcGVDb2xvcihjb2xvcjogc3RyaW5nKTogdm9pZCB7IHRoaXMuc2hhcGVDb2xvciA9IGNvbG9yOyB9XG4gIHNldEZpbGxDb2xvcihjb2xvcjogc3RyaW5nKTogdm9pZCB7IHRoaXMuZmlsbENvbG9yID0gY29sb3I7IH1cblxuICBnZXRDbGFzc2lmaWNhdGlvbkNvbG9ycygpOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTsgfVxuICBzZXRDbGFzc2lmaWNhdGlvbkNvbG9yKGxhYmVsOiBzdHJpbmcsIGNvbG9yOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5zdG9yZS5zZXRDbGFzc2lmaWNhdGlvbkNvbG9yKGxhYmVsLCBjb2xvcik7IH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBwcmV2aW91cy1zaGFwZXMgYnVmZmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBSZS1zaG93IHRoZSBsYXN0IHNhdmVkIHNuYXBzaG90ICh0cmFuc2llbnQg4oCUIGRvZXMgbm90IGFsdGVyIHN0b3JlZCBzdGF0ZSkuICovXG4gIHBsb3RQcmV2aW91c1NoYXBlcygpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLnByZXZpb3VzUmVnaW9ucy5zbGljZSgpKTtcbiAgfVxuICBzZXRQcmV2aW91c1NoYXBlcyhzaGFwZXM6IGFueVtdKTogdm9pZCB7IHRoaXMucHJldmlvdXNSZWdpb25zID0gKHNoYXBlcyBhcyBSZWdpb25bXSkuc2xpY2UoKTsgfVxuICBnZXRQcmV2aW91c1NoYXBlcygpOiBhbnlbXSB7IHJldHVybiB0aGlzLnByZXZpb3VzUmVnaW9ucy5zbGljZSgpOyB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25TdG9yZTogdW5kbyAvIHJlZG8gKGppdC11aSM4NSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIEVtaXRzIHdoZXRoZXIgYW4gdW5kbyBzdGVwIGlzIGN1cnJlbnRseSBhdmFpbGFibGUg4oCUIGRyaXZlcyB0aGUgdG9vbGJhclxuICAgKiAgVW5kbyBidXR0b24ncyBlbmFibGVkIHN0YXRlIChncmV5ZWQgb3V0IHdoZW4gZmFsc2UpLiAqL1xuICBnZXRDYW5VbmRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5jYW5VbmRvJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBFbWl0cyB3aGV0aGVyIGEgcmVkbyBzdGVwIGlzIGN1cnJlbnRseSBhdmFpbGFibGUg4oCUIGRyaXZlcyB0aGUgdG9vbGJhclxuICAgKiAgUmVkbyBidXR0b24ncyBlbmFibGVkIHN0YXRlLiAqL1xuICBnZXRDYW5SZWRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5jYW5SZWRvJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBTeW5jaHJvbm91cyByZWFkIG9mIHtAbGluayBnZXRDYW5VbmRvJH0g4oCUIHRydWUgd2hlbiBhdCBsZWFzdCBvbmUgcmVnaW9uXG4gICAqICBhY3Rpb24gY2FuIGJlIHVuZG9uZS4gKi9cbiAgY2FuVW5kbygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy51bmRvU3RhY2subGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKiBTeW5jaHJvbm91cyByZWFkIG9mIHtAbGluayBnZXRDYW5SZWRvJH0g4oCUIHRydWUgd2hlbiBhbiB1bmRvbmUgYWN0aW9uIGNhblxuICAgKiAgYmUgcmUtYXBwbGllZC4gKi9cbiAgY2FuUmVkbygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5yZWRvU3RhY2subGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBVbmRvIHRoZSBtb3N0IHJlY2VudCByZWdpb24gYWN0aW9uLCByZXN0b3JpbmcgdGhlIHJlZ2lvbiBzZXQgdG8gaXRzIHN0YXRlXG4gICAqIGp1c3QgYmVmb3JlIHRoYXQgYWN0aW9uIGFuZCBwdXNoaW5nIHRoZSBjdXJyZW50IHN0YXRlIG9udG8gdGhlIHJlZG8gc3RhY2suXG4gICAqIFVwIHRvIHtAbGluayBVTkRPX0xJTUlUfSBzdGVwcyBhcmUgcmV0YWluZWQsIHNvIHRoaXMgY2FuIGJlIGNhbGxlZCB1cCB0b1xuICAgKiB7QGxpbmsgVU5ET19MSU1JVH0gdGltZXMgaW4gYSByb3cgYmVmb3JlIHRoZSBoaXN0b3J5IGVtcHRpZXMuIE5vLW9wIHdoZW5cbiAgICogbm90aGluZyBpcyBsZWZ0IHRvIHVuZG8uXG4gICAqL1xuICB1bmRvKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnVuZG9TdGFjay5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMudW5kb1N0YWNrLnBvcCgpIGFzIFJlZ2lvbltdO1xuICAgIC8vIFN0YXNoIHRoZSBjdXJyZW50IChwb3N0LWFjdGlvbikgc3RhdGUgc28gcmVkbyBjYW4gcmUtYXBwbHkgaXQuXG4gICAgdGhpcy5yZWRvU3RhY2sucHVzaCh0aGlzLmNsb25lUmVnaW9ucyh0aGlzLnJlZ2lvbnMpKTtcbiAgICBpZiAodGhpcy5yZWRvU3RhY2subGVuZ3RoID4gUmVnaW9uU3RvcmUuVU5ET19MSU1JVCkgdGhpcy5yZWRvU3RhY2suc2hpZnQoKTtcbiAgICB0aGlzLnJlc3RvcmVTbmFwc2hvdChzbmFwc2hvdCk7XG4gIH1cblxuICAvKipcbiAgICogUmVkbyB0aGUgYWN0aW9uIG1vc3QgcmVjZW50bHkgdW5kb25lLCByZXN0b3JpbmcgdGhlIHJlZ2lvbiBzZXQgdG8gdGhlIHN0YXRlXG4gICAqIGl0IGhhZCBiZWZvcmUgdGhhdCB1bmRvIGFuZCBwdXNoaW5nIHRoZSBjdXJyZW50IHN0YXRlIGJhY2sgb250byB0aGUgdW5kb1xuICAgKiBzdGFjay4gTm8tb3Agd2hlbiB0aGVyZSdzIG5vdGhpbmcgdG8gcmVkbyAodGhlIHJlZG8gc3RhY2sgaXMgY2xlYXJlZCBieSBhbnlcbiAgICogZnJlc2ggcmVnaW9uIGFjdGlvbikuXG4gICAqL1xuICByZWRvKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJlZG9TdGFjay5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMucmVkb1N0YWNrLnBvcCgpIGFzIFJlZ2lvbltdO1xuICAgIHRoaXMudW5kb1N0YWNrLnB1c2godGhpcy5jbG9uZVJlZ2lvbnModGhpcy5yZWdpb25zKSk7XG4gICAgaWYgKHRoaXMudW5kb1N0YWNrLmxlbmd0aCA+IFJlZ2lvblN0b3JlLlVORE9fTElNSVQpIHRoaXMudW5kb1N0YWNrLnNoaWZ0KCk7XG4gICAgdGhpcy5yZXN0b3JlU25hcHNob3Qoc25hcHNob3QpO1xuICB9XG5cbiAgLyoqIERpc2NhcmQgdGhlIHVuZG8vcmVkbyBoaXN0b3J5IChlLmcuIG9uIGltYWdlIGxvYWQvc3dpdGNoIOKAlCBoaXN0b3J5IG5ldmVyXG4gICAqICBjcm9zc2VzIGltYWdlcykuICovXG4gIHJlc2V0VW5kb0hpc3RvcnkoKTogdm9pZCB7XG4gICAgdGhpcy51bmRvU3RhY2sgPSBbXTtcbiAgICB0aGlzLnJlZG9TdGFjayA9IFtdO1xuICAgIHRoaXMuY2xvc2VVbmRvQnVyc3QoKTtcbiAgICBpZiAodGhpcy5jYW5VbmRvJC52YWx1ZSkgdGhpcy5jYW5VbmRvJC5uZXh0KGZhbHNlKTtcbiAgICBpZiAodGhpcy5jYW5SZWRvJC52YWx1ZSkgdGhpcy5jYW5SZWRvJC5uZXh0KGZhbHNlKTtcbiAgfVxuXG4gIC8qKiBNYWtlIGBzbmFwc2hvdGAgdGhlIGxpdmUgcmVnaW9uIHNldCBhbmQgbm90aWZ5IGJvdGggYmFja2VuZHMuIFNoYXJlZCBieVxuICAgKiAge0BsaW5rIHVuZG99IGFuZCB7QGxpbmsgcmVkb307IHRoZSBzbmFwc2hvdCBpcyBhbHJlYWR5IGEgZGV0YWNoZWQgZGVlcFxuICAgKiAgY2xvbmUsIHNvIGl0IGJlY29tZXMgdGhlIGxpdmUgYXJyYXkgZGlyZWN0bHkuICovXG4gIHByaXZhdGUgcmVzdG9yZVNuYXBzaG90KHNuYXBzaG90OiBSZWdpb25bXSk6IHZvaWQge1xuICAgIC8vIENsb3NlIGFueSBvcGVuIGNvYWxlc2NpbmcgYnVyc3Qgc28gdGhlIG5leHQgZWRpdCBzdGFydHMgYSBmcmVzaCBlbnRyeSxcbiAgICAvLyBhbmQgZmxhZyB0aGUgcmVzdG9yZSBzbyBpdCBkb2Vzbid0IHJlY29yZCBpdHNlbGYgYmFjayBpbnRvIHRoZSBoaXN0b3J5LlxuICAgIHRoaXMuY2xvc2VVbmRvQnVyc3QoKTtcbiAgICB0aGlzLnJlc3RvcmluZ1VuZG8gPSB0cnVlO1xuICAgIHRoaXMucmVnaW9ucyA9IHNuYXBzaG90O1xuICAgIC8vIERyb3AgYW55IHNlbGVjdGVkIGlkcyB0aGUgcmVzdG9yZWQgc2V0IG5vIGxvbmdlciBjb250YWlucy5cbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gdGhpcy5zZWxlY3RlZElkcy5maWx0ZXIoaWQgPT4gdGhpcy5pbmRleE9mSWQoaWQpID49IDApO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5yZXN0b3JpbmdVbmRvID0gZmFsc2U7XG4gICAgdGhpcy5lbWl0VW5kb1N0YXRlKCk7XG4gICAgLy8gTm90aWZ5IHRoZSBsaXZlICsgY29hbGVzY2VkIHN0cmVhbXMgc28gd2hpY2hldmVyIGJhY2tlbmQgaXMgb24gc2NyZWVuXG4gICAgLy8gcmUtcmVuZGVycyBmcm9tIHRoZSByZXN0b3JlZCBzdG9yZSBzdGF0ZS5cbiAgICB0aGlzLnJlZ2lvbkxpdmVFZGl0JC5uZXh0KHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLmdldFJlZ2lvbnMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FwdHVyZSB0aGUgcHJlLWFjdGlvbiByZWdpb24gc2V0IGludG8gdGhlIGJvdW5kZWQgdW5kbyBoaXN0b3J5LiBDYWxsZWQgYXRcbiAgICogdGhlIHRvcCBvZiBldmVyeSBtdXRhdGluZyBvcGVyYXRpb24sICpiZWZvcmUqIGl0IGNoYW5nZXMgYHJlZ2lvbnNgLCBzbyB0aGVcbiAgICogc25hcHNob3QgaXMgdGhlIHN0YXRlIHRvIHJldHVybiB0by4gUmFwaWQgY29tbWl0cyBmcm9tIG9uZSBnZXN0dXJlIGNvYWxlc2NlXG4gICAqIGludG8gYSBzaW5nbGUgZW50cnkgKHNlZSB7QGxpbmsgdW5kb1N0YWNrfSkuIEEgZnJlc2ggYWN0aW9uIGFsc28gYWJhbmRvbnNcbiAgICogYW55IHJlZG8gZnV0dXJlLlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRVbmRvU25hcHNob3QoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVzdG9yaW5nVW5kbykgcmV0dXJuO1xuICAgIGNvbnN0IHN0YXJ0c0J1cnN0ID0gIXRoaXMudW5kb0J1cnN0T3BlbjtcbiAgICB0aGlzLmFybVVuZG9CdXJzdCgpO1xuICAgIGlmICghc3RhcnRzQnVyc3QpIHJldHVybjsgICAgICAgICAgICAgICAgICAgICAgLy8gbWlkLWJ1cnN0IOKAlCBrZWVwIGZpcnN0IHNuYXBzaG90XG4gICAgdGhpcy51bmRvU3RhY2sucHVzaCh0aGlzLmNsb25lUmVnaW9ucyh0aGlzLnJlZ2lvbnMpKTtcbiAgICBpZiAodGhpcy51bmRvU3RhY2subGVuZ3RoID4gUmVnaW9uU3RvcmUuVU5ET19MSU1JVCkgdGhpcy51bmRvU3RhY2suc2hpZnQoKTtcbiAgICB0aGlzLnJlZG9TdGFjayA9IFtdOyAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGEgbmV3IGVkaXQgaW52YWxpZGF0ZXMgcmVkb1xuICAgIHRoaXMuZW1pdFVuZG9TdGF0ZSgpO1xuICB9XG5cbiAgLyoqIFB1c2ggdGhlIGN1cnJlbnQgY2FuLXVuZG8gLyBjYW4tcmVkbyBhdmFpbGFiaWxpdHkgdG8gc3Vic2NyaWJlcnMuICovXG4gIHByaXZhdGUgZW1pdFVuZG9TdGF0ZSgpOiB2b2lkIHtcbiAgICBjb25zdCBjYW5VbmRvID0gdGhpcy51bmRvU3RhY2subGVuZ3RoID4gMDtcbiAgICBjb25zdCBjYW5SZWRvID0gdGhpcy5yZWRvU3RhY2subGVuZ3RoID4gMDtcbiAgICBpZiAodGhpcy5jYW5VbmRvJC52YWx1ZSAhPT0gY2FuVW5kbykgdGhpcy5jYW5VbmRvJC5uZXh0KGNhblVuZG8pO1xuICAgIGlmICh0aGlzLmNhblJlZG8kLnZhbHVlICE9PSBjYW5SZWRvKSB0aGlzLmNhblJlZG8kLm5leHQoY2FuUmVkbyk7XG4gIH1cblxuICAvKiogKFJlKWFybSB0aGUgaWRsZSB0aW1lciB0aGF0IGNsb3NlcyB0aGUgY3VycmVudCBjb2FsZXNjaW5nIGJ1cnN0LiAqL1xuICBwcml2YXRlIGFybVVuZG9CdXJzdCgpOiB2b2lkIHtcbiAgICB0aGlzLnVuZG9CdXJzdE9wZW4gPSB0cnVlO1xuICAgIGlmICh0aGlzLnVuZG9CdXJzdFRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy51bmRvQnVyc3RUaW1lcik7XG4gICAgdGhpcy51bmRvQnVyc3RUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy51bmRvQnVyc3RPcGVuID0gZmFsc2U7XG4gICAgICB0aGlzLnVuZG9CdXJzdFRpbWVyID0gbnVsbDtcbiAgICB9LCBSZWdpb25TdG9yZS5VTkRPX0NPQUxFU0NFX01TKTtcbiAgfVxuXG4gIHByaXZhdGUgY2xvc2VVbmRvQnVyc3QoKTogdm9pZCB7XG4gICAgdGhpcy51bmRvQnVyc3RPcGVuID0gZmFsc2U7XG4gICAgaWYgKHRoaXMudW5kb0J1cnN0VGltZXIpIHsgY2xlYXJUaW1lb3V0KHRoaXMudW5kb0J1cnN0VGltZXIpOyB0aGlzLnVuZG9CdXJzdFRpbWVyID0gbnVsbDsgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbG9uZVJlZ2lvbnMocmVnaW9uczogUmVnaW9uW10pOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHJlZ2lvbnMubWFwKHIgPT4gdGhpcy5jbG9uZVJlZ2lvbihyKSk7XG4gIH1cblxuICAvKiogRGVlcCBjbG9uZSBhIHJlZ2lvbiBzbyBhbiBpbi1wbGFjZSBnZW9tZXRyeSBlZGl0IGNhbid0IG11dGF0ZSBhIHN0b3JlZFxuICAgKiAgaGlzdG9yeSBzbmFwc2hvdCAoYm91bmRzIGFyZSBjbG9uZWQgdmlhIHtAbGluayBjbG9uZUJvdW5kc30pLiAqL1xuICBwcml2YXRlIGNsb25lUmVnaW9uKHI6IFJlZ2lvbik6IFJlZ2lvbiB7XG4gICAgY29uc3QgYyA9IG5ldyBSZWdpb24oKTtcbiAgICBPYmplY3QuYXNzaWduKGMsIHIpO1xuICAgIGMuYm91bmRzID0gci5ib3VuZHMgPyB0aGlzLmNsb25lQm91bmRzKHIuYm91bmRzKSA6IHIuYm91bmRzO1xuICAgIGlmIChBcnJheS5pc0FycmF5KHIudGlsZUNvb3JkaW5hdGVzKSkgYy50aWxlQ29vcmRpbmF0ZXMgPSByLnRpbGVDb29yZGluYXRlcy5zbGljZSgpO1xuICAgIHJldHVybiBjO1xuICB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25TdG9yZTogR2VvSlNPTiBJL08gKG5ldXRyYWwgaGVscGVycykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgaW1wb3J0UmVnaW9ucyhnZW9Kc29uU3RyOiBzdHJpbmcpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucGxvdFV0aWxpdGllcy5pbXBvcnRST0lzRnJvbUdlb0pzb24oZ2VvSnNvblN0cik7XG4gIH1cbiAgZXhwb3J0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSk6IHZvaWQge1xuICAgIHRoaXMucGxvdFV0aWxpdGllcy5zYXZlVG9GaWxlKHRoaXMucGxvdFV0aWxpdGllcy5leHBvcnRST0lzVG9HZW9Kc29uKHJlZ2lvbnMpKTtcbiAgfVxuICBnZXRHZW9Kc29uU3RyaW5nKHJlZ2lvbnM6IFJlZ2lvbltdKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wbG90VXRpbGl0aWVzLmV4cG9ydFJPSXNUb0dlb0pzb24ocmVnaW9ucyk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHN0cnVjdHVyYWwgZWRpdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYWRkUmVnaW9uKHJlZ2lvbjogUmVnaW9uKTogbnVtYmVyIHtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICBpZiAocmVnaW9uLm5hbWUgPT0gbnVsbCkgcmVnaW9uLm5hbWUgPSBgc2hhcGUke3JlZ2lvbi5pZH1gO1xuICAgIC8vIEEgcmVnaW9uIGRyYXduIG9uIGEgc3RhY2sgYmVsb25ncyB0byB0aGUgc2xpY2UgY3VycmVudGx5IGRpc3BsYXllZCwgc29cbiAgICAvLyBpdCBzYXZlcy9yZWxvYWRzIG9uIHRoYXQgc2xpY2UgKGppdC11aSM5MykuIE5vLW9wIGZvciBzaW5nbGUtcGxhbmUgaW1hZ2VzXG4gICAgLy8gKGN1cnJlbnRTbGljZVogc3RheXMgMCkuXG4gICAgaWYgKHRoaXMuc3RhY2tNb2RlKSByZWdpb24ueiA9IHRoaXMuY3VycmVudFNsaWNlWjtcbiAgICB0aGlzLmFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMoW3JlZ2lvbl0pO1xuICAgIHRoaXMucmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtyZWdpb24uaWRdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gICAgcmV0dXJuIHJlZ2lvbi5pZDtcbiAgfVxuXG4gIHJlbW92ZVJlZ2lvbihpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgIGlmIChpZHggPCAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICB0aGlzLnJlZ2lvbnMuc3BsaWNlKGlkeCwgMSk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IHRoaXMuc2VsZWN0ZWRJZHMuZmlsdGVyKHMgPT4gcyAhPT0gaWQpO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICB1cGRhdGVCb3VuZHMoaWQ6IG51bWJlciwgYm91bmRzOiBSZWN0YW5nbGUgfCBQb2x5Z29uIHwgTXVsdGlQb2x5Z29uKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghcikgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgci5ib3VuZHMgPSB0aGlzLmNsb25lQm91bmRzKGJvdW5kcyk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVSZWdpb24oaWQ6IG51bWJlciwgZHg6IG51bWJlciwgZHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHIgPSB0aGlzLmZpbmRCeUlkKGlkKTtcbiAgICBpZiAoIXIgfHwgIXIuYm91bmRzKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGIueCArPSBkeDtcbiAgICAgIGIueSArPSBkeTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICB0aGlzLnRyYW5zbGF0ZVBvbHlnb24oYiwgZHgsIGR5KTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHtcbiAgICAgIC8vIFRyYW5zbGF0ZSBldmVyeSBwYXJ0IChhbmQgaXRzIGhvbGVzKSB0b2dldGhlciAoaml0LXVpIzg1KS5cbiAgICAgIGZvciAoY29uc3QgcGFydCBvZiBiLnBvbHlnb25zKSB0aGlzLnRyYW5zbGF0ZVBvbHlnb24ocGFydCwgZHgsIGR5KTtcbiAgICB9XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBUcmFuc2xhdGUgYSBwb2x5Z29uJ3MgdmVydGljZXMgYW5kIGFueSBob2xlcyBpbiBwbGFjZSBieSAoZHgsIGR5KS4gKi9cbiAgcHJpdmF0ZSB0cmFuc2xhdGVQb2x5Z29uKHA6IFBvbHlnb24sIGR4OiBudW1iZXIsIGR5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBwLnhwb2ludHMgPSBwLnhwb2ludHMubWFwKHggPT4geCArIGR4KTtcbiAgICBwLnlwb2ludHMgPSBwLnlwb2ludHMubWFwKHkgPT4geSArIGR5KTtcbiAgICBwLmNvb3JkaW5hdGVzID0gcC54cG9pbnRzLm1hcCgoeCwgaSkgPT4gW3gsIHAueXBvaW50c1tpXV0pO1xuICAgIGlmIChwLmhvbGVzKSBwLmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbeCArIGR4LCB5ICsgZHldKSk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHZlcnRleCBlZGl0cyAocG9seWdvbnMgb25seSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgbW92ZVZlcnRleChpZDogbnVtYmVyLCBpbmRleDogbnVtYmVyLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHNbaW5kZXhdID0geDtcbiAgICBwb2x5Lnlwb2ludHNbaW5kZXhdID0geTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzW2luZGV4XSA9IFt4LCB5XTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqIE1vdmUgYSB2ZXJ0ZXggb24gYSBwb2x5Z29uJ3MgaW50ZXJpb3IgcmluZyAoaG9sZSkg4oCUIGppdC11aSM4NS4gKi9cbiAgbW92ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcG9seSA9IHRoaXMucG9seWdvbk9mKGlkKTtcbiAgICBpZiAoIXBvbHkgfHwgIXBvbHkuaG9sZXMgfHwgaG9sZUluZGV4IDwgMCB8fCBob2xlSW5kZXggPj0gcG9seS5ob2xlcy5sZW5ndGgpIHJldHVybjtcbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIHJpbmdbaW5kZXhdID0gW3gsIHldO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogSW5zZXJ0IGEgdmVydGV4IG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLCBhZnRlciBgc2VnSW5kZXhgXG4gICAqICAodGhlIGVkZ2UncyBzdGFydCB2ZXJ0ZXgpLiBOby1vcCBmb3IgYW4gb3V0LW9mLXJhbmdlIGhvbGUg4oCUIGppdC11aSM4NS4gKi9cbiAgYWRkSG9sZVZlcnRleChpZDogbnVtYmVyLCBob2xlSW5kZXg6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBhdCA9IE1hdGgubWF4KDAsIE1hdGgubWluKHNlZ0luZGV4ICsgMSwgcmluZy5sZW5ndGgpKTtcbiAgICByaW5nLnNwbGljZShhdCwgMCwgW3gsIHldKTtcbiAgICBpZiAocG9seS5iZXppZXIpIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBrZWVwIGhvbGUgaGFuZGxlcyBhbGlnbmVkIHRvIHRoZSByaW5nXG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBEZWxldGUgdGhlIHZlcnRleCBhdCBgaW5kZXhgIG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLiBSZW1vdmluZ1xuICAgKiAgaXQgYmVsb3cgMyB2ZXJ0aWNlcyBkcm9wcyB0aGUgd2hvbGUgaG9sZSAoYSByaW5nIHdpdGggPCAzIHBvaW50cyBib3VuZHMgbm9cbiAgICogIGFyZWEpIOKAlCBqaXQtdWkjODUuICovXG4gIGRlbGV0ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSByaW5nLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKHJpbmcubGVuZ3RoIDw9IDMpIHtcbiAgICAgIHBvbHkuaG9sZXMuc3BsaWNlKGhvbGVJbmRleCwgMSk7XG4gICAgICBpZiAocG9seS5ob2xlcy5sZW5ndGggPT09IDApIHBvbHkuaG9sZXMgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJpbmcuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gICAgaWYgKHBvbHkuYmV6aWVyKSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTsgLy8ga2VlcCBob2xlIGhhbmRsZXMgYWxpZ25lZCB0byB0aGUgcmluZyhzKVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBhZGRWZXJ0ZXgoaWQ6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgLy8gSW5zZXJ0IGFmdGVyIHNlZ0luZGV4ICh0aGUgc3RhcnQgdmVydGV4IG9mIHRoZSBlZGdlKS4gQ2xhbXAgdG8gcmFuZ2UuXG4gICAgY29uc3QgYXQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihzZWdJbmRleCArIDEsIHBvbHkueHBvaW50cy5sZW5ndGgpKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGF0LCAwLCB4KTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGF0LCAwLCB5KTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICAvLyBHaXZlIHRoZSBuZXcgdmVydGV4IHNtb290aCBoYW5kbGVzIGZyb20gaXRzIG5laWdoYm91cnM7IGtlZXAgdGhlIG90aGVycydcbiAgICAvLyAocG9zc2libHkgaGFuZC1lZGl0ZWQpIGhhbmRsZXMgaW50YWN0LlxuICAgIGlmIChwb2x5LmJlemllciAmJiBwb2x5LmhhbmRsZXNJbiAmJiBwb2x5LmhhbmRsZXNPdXQpIHtcbiAgICAgIGNvbnN0IG4gPSBwb2x5Lnhwb2ludHMubGVuZ3RoO1xuICAgICAgY29uc3QgY2xvc2VkID0gcG9seS5jbG9zZWQgIT09IGZhbHNlO1xuICAgICAgY29uc3QgcHJldiA9IGNsb3NlZCA/IChhdCAtIDEgKyBuKSAlIG4gOiBNYXRoLm1heCgwLCBhdCAtIDEpO1xuICAgICAgY29uc3QgbmV4dCA9IGNsb3NlZCA/IChhdCArIDEpICUgbiA6IE1hdGgubWluKG4gLSAxLCBhdCArIDEpO1xuICAgICAgY29uc3QgdHggPSAocG9seS54cG9pbnRzW25leHRdIC0gcG9seS54cG9pbnRzW3ByZXZdKSAvIDY7XG4gICAgICBjb25zdCB0eSA9IChwb2x5Lnlwb2ludHNbbmV4dF0gLSBwb2x5Lnlwb2ludHNbcHJldl0pIC8gNjtcbiAgICAgIHBvbHkuaGFuZGxlc0luLnNwbGljZShhdCwgMCwgWy10eCwgLXR5XSk7XG4gICAgICBwb2x5LmhhbmRsZXNPdXQuc3BsaWNlKGF0LCAwLCBbdHgsIHR5XSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBkZWxldGVWZXJ0ZXgoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgY29uc3QgbWluID0gcG9seS5jbG9zZWQgPT09IGZhbHNlID8gMiA6IDM7XG4gICAgaWYgKHBvbHkueHBvaW50cy5sZW5ndGggPD0gbWluKSByZXR1cm47IC8vIHJlZnVzZSB0byBkZWdlbmVyYXRlIHRoZSBwb2x5Z29uXG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICBpZiAocG9seS5iZXppZXIgJiYgcG9seS5oYW5kbGVzSW4gJiYgcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbi5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgcG9seS5oYW5kbGVzT3V0LnNwbGljZShpbmRleCwgMSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBzZXRCZXppZXIoaWQ6IG51bWJlciwgYmV6aWVyOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhci5ib3VuZHMpIHJldHVybjtcbiAgICBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICBpZiAoci5ib3VuZHMuYmV6aWVyID09PSBiZXppZXIpIHJldHVybjtcbiAgICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgICB0aGlzLmFwcGx5QmV6aWVyKHIuYm91bmRzLCBiZXppZXIpO1xuICAgIH0gZWxzZSBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUgJiYgYmV6aWVyKSB7XG4gICAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgICAgLy8gU21vb3RoaW5nIGEgcmVjdGFuZ2xlOiBjb252ZXJ0IGl0IHRvIGEgNC1hbmNob3IgY2xvc2VkIHBvbHlnb24gZmlyc3QuXG4gICAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgICBjb25zdCB4cyA9IFtiLngsIGIueCArIGIud2lkdGgsIGIueCArIGIud2lkdGgsIGIueF07XG4gICAgICBjb25zdCB5cyA9IFtiLnksIGIueSwgYi55ICsgYi5oZWlnaHQsIGIueSArIGIuaGVpZ2h0XTtcbiAgICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgICAgcG9seS5ucG9pbnRzID0gNDtcbiAgICAgIHBvbHkueHBvaW50cyA9IHhzO1xuICAgICAgcG9seS55cG9pbnRzID0geXM7XG4gICAgICBwb2x5LmNvb3JkaW5hdGVzID0geHMubWFwKCh4LCBpKSA9PiBbeCwgeXNbaV1dKTtcbiAgICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcbiAgICAgIHRoaXMuYXBwbHlCZXppZXIocG9seSwgdHJ1ZSk7XG4gICAgICByLmJvdW5kcyA9IHBvbHk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjsgLy8gYmV6aWVyPWZhbHNlIG9uIGEgcmVjdGFuZ2xlOiBub3RoaW5nIHRvIGRvXG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogVHVybiBiZXppZXIgb24gKGFuZCBzZWVkIGVkaXRhYmxlIGhhbmRsZXMgZnJvbSB0aGUgc21vb3RoIGRlZmF1bHQpIG9yIG9mZlxuICAgKiAgKGFuZCBkcm9wIHRoZSBoYW5kbGVzKS4gKi9cbiAgcHJpdmF0ZSBhcHBseUJlemllcihwb2x5OiBQb2x5Z29uLCBiZXppZXI6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBwb2x5LmJlemllciA9IGJlemllcjtcbiAgICBpZiAoYmV6aWVyKSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICAgIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBzbW9vdGggdGhlIGhvbGVzIHRvbyAoZG9udXQg4oaSIGJlemllciBjdXJ2ZXMgdGhlIGhvbGVzKVxuICAgIH0gZWxzZSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaGFuZGxlc091dCA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqIChSZSlzZWVkIHBlci1ob2xlIGJlemllciBoYW5kbGVzIGZyb20gdGhlIENhdG11bGwtUm9tIGRlZmF1bHQsIHBhcmFsbGVsIHRvIGBwb2x5LmhvbGVzYC4gKi9cbiAgcHJpdmF0ZSBzZWVkSG9sZUhhbmRsZXMocG9seTogUG9seWdvbik6IHZvaWQge1xuICAgIGlmICghcG9seS5ob2xlcyB8fCAhcG9seS5ob2xlcy5sZW5ndGgpIHtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGluczogbnVtYmVyW11bXVtdID0gW107XG4gICAgY29uc3Qgb3V0czogbnVtYmVyW11bXVtdID0gW107XG4gICAgZm9yIChjb25zdCByaW5nIG9mIHBvbHkuaG9sZXMpIHtcbiAgICAgIGNvbnN0IG9mZiA9IGRlZmF1bHRIYW5kbGVPZmZzZXRzKFxuICAgICAgICByaW5nLm1hcCgocCkgPT4gcFswXSksXG4gICAgICAgIHJpbmcubWFwKChwKSA9PiBwWzFdKSxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICk7XG4gICAgICBpbnMucHVzaChvZmYuaW4pO1xuICAgICAgb3V0cy5wdXNoKG9mZi5vdXQpO1xuICAgIH1cbiAgICBwb2x5LmhvbGVIYW5kbGVzSW4gPSBpbnM7XG4gICAgcG9seS5ob2xlSGFuZGxlc091dCA9IG91dHM7XG4gIH1cblxuICAvKiogRHJhZyBhIGJlemllciBjb250cm9sIHBvaW50IG9uIGEgaG9sZSByaW5nIHZlcnRleCAoZG9udXQgYmV6aWVyIGVkaXRpbmcpLiAqL1xuICBtb3ZlSG9sZUJlemllckhhbmRsZShcbiAgICBpZDogbnVtYmVyLFxuICAgIGhvbGVJbmRleDogbnVtYmVyLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgc2lkZTogJ2luJyB8ICdvdXQnLFxuICAgIHg6IG51bWJlcixcbiAgICB5OiBudW1iZXIsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmICghcG9seS5ob2xlSGFuZGxlc0luIHx8ICFwb2x5LmhvbGVIYW5kbGVzT3V0KSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTtcbiAgICBjb25zdCBvZmZzZXQgPSBbeCAtIHJpbmdbaW5kZXhdWzBdLCB5IC0gcmluZ1tpbmRleF1bMV1dO1xuICAgIGlmIChzaWRlID09PSAnaW4nKSBwb2x5LmhvbGVIYW5kbGVzSW4hW2hvbGVJbmRleF1baW5kZXhdID0gb2Zmc2V0O1xuICAgIGVsc2UgcG9seS5ob2xlSGFuZGxlc091dCFbaG9sZUluZGV4XVtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVCZXppZXJIYW5kbGUoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlciwgc2lkZTogJ2luJyB8ICdvdXQnLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCBpbmRleCA8IDAgfHwgaW5kZXggPj0gcG9seS54cG9pbnRzLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKCFwb2x5LmhhbmRsZXNJbiB8fCAhcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICB9XG4gICAgY29uc3Qgb2Zmc2V0ID0gW3ggLSBwb2x5Lnhwb2ludHNbaW5kZXhdLCB5IC0gcG9seS55cG9pbnRzW2luZGV4XV07XG4gICAgaWYgKHNpZGUgPT09ICdpbicpIHBvbHkuaGFuZGxlc0luW2luZGV4XSA9IG9mZnNldDtcbiAgICBlbHNlIHBvbHkuaGFuZGxlc091dFtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIGJlZ2luQmF0Y2goKTogdm9pZCB7IHRoaXMuYmF0Y2hEZXB0aCsrOyB9XG4gIGVuZEJhdGNoKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmJhdGNoRGVwdGggPiAwKSB0aGlzLmJhdGNoRGVwdGgtLTtcbiAgICBpZiAodGhpcy5iYXRjaERlcHRoID09PSAwICYmIHRoaXMucGVuZGluZ0VtaXQpIHtcbiAgICAgIHRoaXMucGVuZGluZ0VtaXQgPSBmYWxzZTtcbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgcGVyLWltYWdlIGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogU3dpdGNoIHRoZSBhY3RpdmUgaW1hZ2U6IHNuYXBzaG90IHRoZSBvdXRnb2luZyByZWdpb25zLCByZXN0b3JlIHRoZVxuICAgKiBpbmNvbWluZyBpbWFnZSdzIChvciBbXSBpZiBub25lKSwgY2xlYXIgc2VsZWN0aW9uLCBhbmQgbm90aWZ5LiBJZGVtcG90ZW50XG4gICAqIGZvciB0aGUgc2FtZSBpbWFnZSAoc28gcmVwZWF0ZWQgcmVwbG90cyBvZiBvbmUgaW1hZ2Uga2VlcCBpdHMgcmVnaW9ucykuXG4gICAqL1xuICBzZXRBY3RpdmVJbWFnZShpbWFnZUluZm86IElJbWFnZUluZm8pOiB2b2lkIHtcbiAgICBjb25zdCBuZXdLZXkgPSB0aGlzLmRlcml2ZUltYWdlS2V5KGltYWdlSW5mbyk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5ID09PSBuZXdLZXkpIHJldHVybjtcbiAgICAvLyBTd2l0Y2hpbmcgaW1hZ2VzIGVuZHMgYW55IHBlci1zbGljZSBzdGFjayBzZXNzaW9uIChqaXQtdWkjOTMpOyB0aGUgbG9hZGVyXG4gICAgLy8gcmUtZW50ZXJzIHN0YWNrIG1vZGUgYWZ0ZXJ3YXJkcyBpZiB0aGUgbmV3IGltYWdlIGlzIGl0c2VsZiBhIHotc3RhY2suXG4gICAgdGhpcy5leGl0U3RhY2tNb2RlKCk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5KSB7XG4gICAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LnNldCh0aGlzLmN1cnJlbnRJbWFnZUtleSwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRJbWFnZUtleSA9IG5ld0tleTtcbiAgICB0aGlzLnJlZ2lvbnMgPSAobmV3S2V5ICYmIHRoaXMucmVnaW9uc0J5SW1hZ2VLZXkuZ2V0KG5ld0tleSkpXG4gICAgICA/ICh0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmdldChuZXdLZXkpIGFzIFJlZ2lvbltdKS5zbGljZSgpXG4gICAgICA6IFtdO1xuICAgIHRoaXMucHJldmlvdXNSZWdpb25zID0gdGhpcy5yZWdpb25zLnNsaWNlKCk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIC8vIFVuZG8gbmV2ZXIgY3Jvc3NlcyBhbiBpbWFnZSBzd2l0Y2guXG4gICAgdGhpcy5yZXNldFVuZG9IaXN0b3J5KCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQodGhpcy5nZXRSZWdpb25zKCkpO1xuICB9XG5cbiAgLyoqIERyb3AgdGhlIGVudGlyZSBwZXItaW1hZ2UgY2FjaGUgKGxvZ291dCAvIHByb2plY3Qgc3dpdGNoKS4gKi9cbiAgY2xlYXJSZWdpb25zQnlJbWFnZUtleSgpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmNsZWFyKCk7XG4gICAgdGhpcy5jdXJyZW50SW1hZ2VLZXkgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5yZWdpb25zID0gW107XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGRlcml2ZUltYWdlS2V5KGltYWdlSW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFpbWFnZUluZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgaWYgKGltYWdlSW5mby51cmxzICYmIGltYWdlSW5mby51cmxzLmxlbmd0aCA+IDAgJiYgaW1hZ2VJbmZvLnVybHNbMF0pIHtcbiAgICAgIHJldHVybiBpbWFnZUluZm8udXJsc1swXTtcbiAgICB9XG4gICAgcmV0dXJuIGltYWdlSW5mby5maWxlTmFtZSB8fCB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSBlYWNoIHJlZ2lvbidzIGNvbG91ciBmcm9tIHRoZSBhbm5vdGF0aW9uLWNsYXNzIHByZXNldCBzZXQgKGppdC11aSM3MCkuXG4gICAqIFRoZSBwcmVzZXRzIGFyZSB0aGUgc291cmNlIG9mIHRydXRoIGZvciBjb2xvdXIg4oCUIHRoaXMgKipvdmVycmlkZXMgYW55IGNvbG91clxuICAgKiBlbWJlZGRlZCBpbiB0aGUgR2VvSlNPTioqICh3aGljaCB0aGUgWU9MTyB3b3JrZXIgd3JpdGVzIHRvZGF5KS4gQSBtYXRjaGluZ1xuICAgKiBwcmVzZXQgZ2l2ZXMgdGhlIGNsYXNzIGNvbG91cjsgYW4gdW5rbm93biBjbGFzcyBnZXRzIGEgZGV0ZXJtaW5pc3RpYyBmYWxsYmFja1xuICAgKiBjb2xvdXIgKGFuZCwgb25seSB3aGVuIGBhdXRvUHJvbW90ZWAgaXMgb24sIGlzIGFkZGVkIHRvIHRoZSBlZGl0YWJsZSBsaXN0KS5cbiAgICogUmVnaW9ucyB0aGUgdXNlciBleHBsaWNpdGx5IHJlY29sb3VyZWQgKGBjb2xvck92ZXJyaWRkZW5gKSBhcmUgbGVmdCB1bnRvdWNoZWQuXG4gICAqL1xuICBwcml2YXRlIGFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMocmVnaW9uczogUmVnaW9uW10pOiB2b2lkIHtcbiAgICBjb25zdCBzZXQgPSB0aGlzLnN0b3JlLmdldFByZXNldFNldCgpO1xuICAgIGNvbnN0IGtleU9mID0gKGxhYmVsOiBzdHJpbmcpID0+XG4gICAgICBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyBsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKSA6IGxhYmVsO1xuICAgIGNvbnN0IGtub3duID0gbmV3IFNldChzZXQuY2xhc3Nlcy5tYXAoKGMpID0+IGtleU9mKGMubmFtZSkpKTtcbiAgICBmb3IgKGNvbnN0IHJlZ2lvbiBvZiByZWdpb25zKSB7XG4gICAgICBpZiAoIXJlZ2lvbi5sYWJlbCB8fCByZWdpb24uY29sb3JPdmVycmlkZGVuKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHByZXNldCA9IGZpbmRQcmVzZXQocmVnaW9uLmxhYmVsLCBzZXQpO1xuICAgICAgaWYgKHByZXNldCkge1xuICAgICAgICByZWdpb24uY29sb3IgPSBwcmVzZXQuY29sb3I7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgY29sb3IgPSBmYWxsYmFja0NvbG9yRm9yKHJlZ2lvbi5sYWJlbCwgc2V0LmZhbGxiYWNrUGFsZXR0ZSk7XG4gICAgICByZWdpb24uY29sb3IgPSBjb2xvcjtcbiAgICAgIGlmIChzZXQuYXV0b1Byb21vdGUgJiYgIWtub3duLmhhcyhrZXlPZihyZWdpb24ubGFiZWwpKSkge1xuICAgICAgICBrbm93bi5hZGQoa2V5T2YocmVnaW9uLmxhYmVsKSk7XG4gICAgICAgIC8vIEluIG5vcm1hbGl6ZWQgbW9kZSwgdHJpbSB0aGUgcHJvbW90ZWQgbmFtZSBzbyBsZWFkaW5nL3RyYWlsaW5nXG4gICAgICAgIC8vIHdoaXRlc3BhY2UgZG9lc24ndCBjcmVhdGUgaW52aXNpYmxlIGR1cGxpY2F0ZXMgb3Igb2RkIGRpc3BsYXkgbmFtZXMuXG4gICAgICAgIGNvbnN0IG5hbWUgPSBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyByZWdpb24ubGFiZWwudHJpbSgpIDogcmVnaW9uLmxhYmVsO1xuICAgICAgICB0aGlzLnN0b3JlLnVwc2VydENsYXNzKHsgbmFtZSwgY29sb3IsIHNvdXJjZTogJ2F1dG8nIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3luY0NhY2hlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmN1cnJlbnRJbWFnZUtleSkge1xuICAgICAgdGhpcy5yZWdpb25zQnlJbWFnZUtleS5zZXQodGhpcy5jdXJyZW50SW1hZ2VLZXksIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGVtaXQoKTogdm9pZCB7XG4gICAgLy8gTGl2ZS1lZGl0IGxpc3RlbmVycyAoZS5nLiB0aGUgaW50ZW5zaXR5LXByb2ZpbGUgaW5zZXQpIHJlYWN0IG9uIEVWRVJZXG4gICAgLy8gY2hhbmdlIOKAlCBpbmNsdWRpbmcgcGVyLWZyYW1lIGR1cmluZyBhIGJhdGNoZWQgZHJhZyDigJQgc28gdGhleSB0cmFjayB0aGVcbiAgICAvLyByZWdpb24gbGl2ZS4gVGhlIG1haW4gcmVnaW9uVXBkYXRlJCBzdGF5cyBjb2FsZXNjZWQgZHVyaW5nIGEgYmF0Y2ggKGZpcmVzXG4gICAgLy8gb25jZSBvbiBlbmRCYXRjaCkgdG8ga2VlcCBoZWF2aWVyIGNvbnN1bWVycyAoUmVnaW9ucyB0YWIpIGNhbG0uXG4gICAgdGhpcy5yZWdpb25MaXZlRWRpdCQubmV4dCh0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgaWYgKHRoaXMuYmF0Y2hEZXB0aCA+IDApIHsgdGhpcy5wZW5kaW5nRW1pdCA9IHRydWU7IHJldHVybjsgfVxuICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgfVxuXG4gIC8qKiBQcm9qZWN0IHNlbGVjdGVkIGlkcyB0byBjdXJyZW50IGFycmF5IGluZGljZXMsIHBydW5pbmcgaWRzIHRoYXQgbm8gbG9uZ2VyXG4gICAqICBleGlzdCwgYW5kIGVtaXQgaWYgdGhlIGluZGV4IHNldCBjaGFuZ2VkLiAqL1xuICBwcml2YXRlIGVtaXRTZWxlY3Rpb24oKTogdm9pZCB7XG4gICAgY29uc3QgaW5kaWNlczogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBsaXZlSWRzOiBudW1iZXJbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgaWQgb2YgdGhpcy5zZWxlY3RlZElkcykge1xuICAgICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgICAgaWYgKGlkeCA+PSAwKSB7IGluZGljZXMucHVzaChpZHgpOyBsaXZlSWRzLnB1c2goaWQpOyB9XG4gICAgfVxuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBsaXZlSWRzO1xuICAgIGlmICghdGhpcy5pbmRpY2VzRXF1YWwodGhpcy5zZWxlY3RlZEluZGljZXMkLnZhbHVlLCBpbmRpY2VzKSkge1xuICAgICAgdGhpcy5zZWxlY3RlZEluZGljZXMkLm5leHQoaW5kaWNlcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbmRpY2VzRXF1YWwoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogYm9vbGVhbiB7XG4gICAgaWYgKGEubGVuZ3RoICE9PSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykgaWYgKGFbaV0gIT09IGJbaV0pIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZEJ5SWQoaWQ6IG51bWJlcik6IFJlZ2lvbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kKHIgPT4gci5pZCA9PT0gaWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbmRleE9mSWQoaWQ6IG51bWJlcik6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kSW5kZXgociA9PiByLmlkID09PSBpZCk7XG4gIH1cblxuICAvKiogVGhlIHJlZ2lvbidzIGJvdW5kcyBhcyBhIFBvbHlnb24sIG9yIHVuZGVmaW5lZCBpZiBpdCBpc24ndCBhIHBvbHlnb24uICovXG4gIHByaXZhdGUgcG9seWdvbk9mKGlkOiBudW1iZXIpOiBQb2x5Z29uIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByID0gdGhpcy5maW5kQnlJZChpZCk7XG4gICAgcmV0dXJuIHIgJiYgci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uID8gci5ib3VuZHMgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGNsb25lUG9seWdvbihwOiBQb2x5Z29uKTogUG9seWdvbiB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gcC5ucG9pbnRzO1xuICAgIHBvbHkueHBvaW50cyA9IHAueHBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkueXBvaW50cyA9IHAueXBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBwLmNvb3JkaW5hdGVzLm1hcChjID0+IGMuc2xpY2UoKSk7XG4gICAgcG9seS5jbG9zZWQgPSBwLmNsb3NlZDtcbiAgICBwb2x5LmJlemllciA9IHAuYmV6aWVyO1xuICAgIGlmIChwLmhhbmRsZXNJbikgcG9seS5oYW5kbGVzSW4gPSBwLmhhbmRsZXNJbi5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhhbmRsZXNPdXQpIHBvbHkuaGFuZGxlc091dCA9IHAuaGFuZGxlc091dC5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhvbGVzKSBwb2x5LmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcChwdCA9PiBwdC5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNJbikgcG9seS5ob2xlSGFuZGxlc0luID0gcC5ob2xlSGFuZGxlc0luLm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNPdXQpIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSBwLmhvbGVIYW5kbGVzT3V0Lm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgcmV0dXJuIHBvbHk7XG4gIH1cblxuICBwcml2YXRlIGNsb25lQm91bmRzKGJvdW5kczogUmVjdGFuZ2xlIHwgUG9seWdvbiB8IE11bHRpUG9seWdvbik6IFJlY3RhbmdsZSB8IFBvbHlnb24gfCBNdWx0aVBvbHlnb24ge1xuICAgIGlmIChib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGNvbnN0IHJlY3QgPSBuZXcgUmVjdGFuZ2xlKCk7XG4gICAgICByZWN0LnggPSBib3VuZHMueDsgcmVjdC55ID0gYm91bmRzLnk7IHJlY3Qud2lkdGggPSBib3VuZHMud2lkdGg7IHJlY3QuaGVpZ2h0ID0gYm91bmRzLmhlaWdodDtcbiAgICAgIHJldHVybiByZWN0O1xuICAgIH1cbiAgICBpZiAoYm91bmRzIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBjb25zdCBtcCA9IG5ldyBNdWx0aVBvbHlnb24oKTtcbiAgICAgIG1wLnBvbHlnb25zID0gYm91bmRzLnBvbHlnb25zLm1hcChwID0+IHRoaXMuY2xvbmVQb2x5Z29uKHApKTtcbiAgICAgIHJldHVybiBtcDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xvbmVQb2x5Z29uKGJvdW5kcyk7XG4gIH1cblxuICBwcml2YXRlIHJlZ2lvbnNFcXVhbChhOiBSZWdpb24sIGI6IFJlZ2lvbik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGJhID0gYS5ib3VuZHMsIGJiID0gYi5ib3VuZHM7XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgUmVjdGFuZ2xlICYmIGJiIGluc3RhbmNlb2YgUmVjdGFuZ2xlKSB7XG4gICAgICByZXR1cm4gYmEueCA9PT0gYmIueCAmJiBiYS55ID09PSBiYi55ICYmIGJhLndpZHRoID09PSBiYi53aWR0aCAmJiBiYS5oZWlnaHQgPT09IGJiLmhlaWdodDtcbiAgICB9XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uICYmIGJiIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBpZiAoYmEucG9seWdvbnMubGVuZ3RoICE9PSBiYi5wb2x5Z29ucy5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmEucG9seWdvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKCF0aGlzLnBvbHlnb25zRXF1YWwoYmEucG9seWdvbnNbaV0sIGJiLnBvbHlnb25zW2ldKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChiYSBpbnN0YW5jZW9mIFBvbHlnb24gJiYgYmIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICByZXR1cm4gdGhpcy5wb2x5Z29uc0VxdWFsKGJhLCBiYik7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcG9seWdvbnNFcXVhbChwYTogUG9seWdvbiwgcGI6IFBvbHlnb24pOiBib29sZWFuIHtcbiAgICBpZiAoKHBhLmNsb3NlZCAhPT0gZmFsc2UpICE9PSAocGIuY2xvc2VkICE9PSBmYWxzZSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAocGEueHBvaW50cy5sZW5ndGggIT09IHBiLnhwb2ludHMubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwYS54cG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAocGEueHBvaW50c1tpXSAhPT0gcGIueHBvaW50c1tpXSB8fCBwYS55cG9pbnRzW2ldICE9PSBwYi55cG9pbnRzW2ldKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmhvbGVzRXF1YWwocGEuaG9sZXMsIHBiLmhvbGVzKTtcbiAgfVxuXG4gIC8qKiBDb21wYXJlIHR3byBwb2x5Z29ucycgaW50ZXJpb3ItcmluZyAoaG9sZSkgc2V0cyBmb3IgdGhlIGRlZHVwZSBwYXRoLiAqL1xuICBwcml2YXRlIGhvbGVzRXF1YWwoYTogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkLCBiOiBudW1iZXJbXVtdW10gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBjb25zdCBuYSA9IGE/Lmxlbmd0aCA/PyAwLCBuYiA9IGI/Lmxlbmd0aCA/PyAwO1xuICAgIGlmIChuYSAhPT0gbmIpIHJldHVybiBmYWxzZTtcbiAgICBmb3IgKGxldCBoID0gMDsgaCA8IG5hOyBoKyspIHtcbiAgICAgIGNvbnN0IHJhID0gKGEgYXMgbnVtYmVyW11bXVtdKVtoXSwgcmIgPSAoYiBhcyBudW1iZXJbXVtdW10pW2hdO1xuICAgICAgaWYgKHJhLmxlbmd0aCAhPT0gcmIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChyYVtpXVswXSAhPT0gcmJbaV1bMF0gfHwgcmFbaV1bMV0gIT09IHJiW2ldWzFdKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG59XG4iXX0=
|