@jax-data-science/sci-image-visualizer 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.mjs +7 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
- package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/contracts/viz-config.mjs +1 -1
- package/esm2022/lib/geometry/loft.mjs +128 -0
- package/esm2022/lib/geometry/polylabel.mjs +156 -0
- package/esm2022/lib/geometry/reconstruct.mjs +315 -0
- package/esm2022/lib/geometry/reslice-image.mjs +57 -0
- package/esm2022/lib/geometry/section.mjs +215 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +11 -7
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +20 -3
- package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +28 -5
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +9 -2
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +5 -2
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +81 -1
- package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +115 -4
- package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +15 -3
- package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +18 -7
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +38 -8
- package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +1 -1
- package/esm2022/lib/models/class-preset.mjs +1 -1
- package/esm2022/lib/models/polygon-factory.mjs +17 -1
- package/esm2022/lib/models/region-geojson.mjs +44 -6
- package/esm2022/lib/models/region.mjs +1 -1
- package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
- package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +77 -13
- package/esm2022/lib/region-editor/region-editor.component.mjs +527 -42
- package/esm2022/lib/region-editor/region-metrics.mjs +20 -2
- package/esm2022/lib/region-editor/region-persistence.service.mjs +36 -10
- package/esm2022/lib/region-editor/region-table/region-table.component.mjs +24 -8
- package/esm2022/lib/region-overlay/region-geometry.mjs +3 -3
- package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
- package/esm2022/lib/region-overlay/region-style.mjs +97 -0
- package/esm2022/lib/region-source/http-region-source.mjs +104 -0
- package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
- package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
- package/esm2022/lib/region-source/region-source.mjs +67 -0
- package/esm2022/lib/region-source/region-tiles.mjs +708 -0
- package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
- package/esm2022/lib/routing-visualizer.service.mjs +418 -22
- package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
- package/esm2022/lib/store/class-color.util.mjs +10 -5
- package/esm2022/lib/store/class-signatures.mjs +63 -0
- package/esm2022/lib/store/region-scope-cache.mjs +5 -1
- package/esm2022/lib/store/region-source-scope.mjs +171 -0
- package/esm2022/lib/store/region-store.service.mjs +724 -12
- package/esm2022/lib/store/visualizer-store.service.mjs +33 -6
- package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +8 -2
- package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +55 -15
- package/esm2022/lib/toolbar/toolbar.component.mjs +19 -5
- package/esm2022/lib/visualizer/region-load.mjs +67 -4
- package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
- package/esm2022/lib/visualizer.component.mjs +128 -6
- package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs} +7239 -1153
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +1 -0
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs} +4 -4
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map} +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -3
- package/fesm2022/region-source.worker.js +1067 -0
- package/index.d.ts +6 -0
- package/lib/contracts/image.contract.d.ts +4 -0
- package/lib/contracts/region-editor-api.contract.d.ts +84 -0
- package/lib/contracts/region-store.contract.d.ts +22 -0
- package/lib/contracts/section-view.contract.d.ts +44 -0
- package/lib/contracts/visualizer.contract.d.ts +10 -0
- package/lib/contracts/viz-config.d.ts +8 -0
- package/lib/geometry/loft.d.ts +22 -0
- package/lib/geometry/polylabel.d.ts +23 -0
- package/lib/geometry/reconstruct.d.ts +54 -0
- package/lib/geometry/reslice-image.d.ts +33 -0
- package/lib/geometry/section.d.ts +52 -0
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -2
- package/lib/implementations/napari-js/napari-loading-state.d.ts +8 -1
- package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +6 -1
- package/lib/implementations/napari-js/napari-scene.d.ts +33 -0
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +3 -1
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +48 -0
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +45 -1
- package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
- package/lib/implementations/osd/osd-region-overlay-draw.d.ts +4 -3
- package/lib/implementations/osd/osd-region-overlay.d.ts +10 -3
- package/lib/implementations/tile-server/tile-protocol.d.ts +3 -0
- package/lib/models/class-preset.d.ts +7 -0
- package/lib/models/polygon-factory.d.ts +5 -0
- package/lib/models/region-geojson.d.ts +40 -0
- package/lib/models/region.d.ts +19 -0
- package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
- package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +36 -6
- package/lib/region-editor/region-editor.component.d.ts +133 -17
- package/lib/region-editor/region-metrics.d.ts +8 -0
- package/lib/region-editor/region-persistence.service.d.ts +12 -4
- package/lib/region-editor/region-table/region-table.component.d.ts +10 -4
- package/lib/region-overlay/region-geometry.d.ts +4 -3
- package/lib/region-overlay/region-source-layer.d.ts +96 -0
- package/lib/region-overlay/region-style.d.ts +52 -0
- package/lib/region-source/http-region-source.d.ts +45 -0
- package/lib/region-source/region-source-ops.d.ts +89 -0
- package/lib/region-source/region-source-worker.d.ts +7 -0
- package/lib/region-source/region-source.d.ts +82 -0
- package/lib/region-source/region-tiles.d.ts +289 -0
- package/lib/region-source/worker-region-source.d.ts +65 -0
- package/lib/routing-visualizer.service.d.ts +138 -1
- package/lib/section-pane/section-pane.component.d.ts +47 -0
- package/lib/store/class-color.util.d.ts +6 -3
- package/lib/store/class-signatures.d.ts +11 -0
- package/lib/store/region-scope-cache.d.ts +2 -0
- package/lib/store/region-source-scope.d.ts +68 -0
- package/lib/store/region-store.service.d.ts +206 -2
- package/lib/store/visualizer-store.service.d.ts +10 -0
- package/lib/toolbar/region-tools/region-tools.component.d.ts +3 -1
- package/lib/toolbar/stack-controls/stack-controls.component.d.ts +20 -9
- package/lib/toolbar/toolbar.component.d.ts +9 -2
- package/lib/visualizer/region-load.d.ts +23 -4
- package/lib/visualizer/volume-sections.d.ts +64 -0
- package/lib/visualizer.component.d.ts +31 -0
- package/package.json +2 -2
- package/src/lib/assets/slice.svg +23 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +0 -1
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pure core of a tiled region source: a large GeoJSON region set cut into tiles per level
|
|
3
|
+
* of detail, the outlines simplified per level, so a view only ever holds and draws what is on
|
|
4
|
+
* screen at the detail the zoom can show.
|
|
5
|
+
*
|
|
6
|
+
* Levels: level 0 is exact; a level-k tile covers `tileSize · 2ᵏ` image pixels and its outlines
|
|
7
|
+
* are simplified (Douglas–Peucker) to `2ᵏ⁻¹` image pixels — half to one screen pixel at the zooms
|
|
8
|
+
* that pick that level ({@link regionLevelFor}). A feature under `2ᵏ` image pixels (one to two
|
|
9
|
+
* screen pixels there) is left out of the level. A tile holds the WHOLE simplified feature (not
|
|
10
|
+
* clipped) for every feature whose box meets it, so a view de-duplicates features by id, and at
|
|
11
|
+
* level 0 the tiles in view hold the exact outline of everything visible.
|
|
12
|
+
*
|
|
13
|
+
* No DOM, no Angular: the same code runs in the region-source worker and, where workers do not
|
|
14
|
+
* exist, on the main thread.
|
|
15
|
+
*/
|
|
16
|
+
import { rgbToHex } from '../contracts/color';
|
|
17
|
+
import { simplifyRing } from '../geometry/ring';
|
|
18
|
+
import { polylabel } from '../geometry/polylabel';
|
|
19
|
+
import { ringsArea } from '../geometry/reconstruct';
|
|
20
|
+
/** Edge of a level-0 tile, in image pixels. */
|
|
21
|
+
export const REGION_TILE_SIZE = 512;
|
|
22
|
+
/**
|
|
23
|
+
* The level whose tiles suit a zoom of `pxPerImagePx` screen pixels per image pixel: exact (0)
|
|
24
|
+
* at 1:1 and closer, else level k for zooms in [2⁻ᵏ, 2¹⁻ᵏ), where its tolerance is half to one
|
|
25
|
+
* screen pixel and the features it leaves out are under one or two.
|
|
26
|
+
*/
|
|
27
|
+
export function regionLevelFor(pxPerImagePx, levels) {
|
|
28
|
+
if (!(pxPerImagePx > 0) || levels <= 1)
|
|
29
|
+
return 0;
|
|
30
|
+
const level = Math.ceil(-Math.log2(pxPerImagePx) - 1e-9);
|
|
31
|
+
return Math.max(0, Math.min(levels - 1, level));
|
|
32
|
+
}
|
|
33
|
+
/** Simplification tolerance of a level, in image pixels (0 = exact). */
|
|
34
|
+
export function levelTolerance(level) {
|
|
35
|
+
return level <= 0 ? 0 : 2 ** (level - 1);
|
|
36
|
+
}
|
|
37
|
+
/** Features smaller than this (their box's longer side, image pixels) are left out of a level. */
|
|
38
|
+
export function levelMinExtent(level) {
|
|
39
|
+
return level <= 0 ? 0 : 2 ** level;
|
|
40
|
+
}
|
|
41
|
+
/** Tile edge of a level, in image pixels. */
|
|
42
|
+
export function levelTileSize(level, tileSize = REGION_TILE_SIZE) {
|
|
43
|
+
return tileSize * 2 ** level;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Tiles of `level` that meet `rect`, clipped to `bounds` (none past the data), ordered from the
|
|
47
|
+
* rectangle's centre outward so the middle of the screen fills first. At most `limit`.
|
|
48
|
+
*/
|
|
49
|
+
export function regionTilesInRect(rect, level, tileSize, bounds, limit = Infinity) {
|
|
50
|
+
if (!bounds)
|
|
51
|
+
return [];
|
|
52
|
+
const x0 = Math.max(rect[0], bounds[0]);
|
|
53
|
+
const y0 = Math.max(rect[1], bounds[1]);
|
|
54
|
+
const x1 = Math.min(rect[2], bounds[2]);
|
|
55
|
+
const y1 = Math.min(rect[3], bounds[3]);
|
|
56
|
+
if (x1 < x0 || y1 < y0)
|
|
57
|
+
return [];
|
|
58
|
+
const size = levelTileSize(level, tileSize);
|
|
59
|
+
const gx0 = Math.floor(x0 / size);
|
|
60
|
+
const gy0 = Math.floor(y0 / size);
|
|
61
|
+
const gx1 = Math.floor(x1 / size);
|
|
62
|
+
const gy1 = Math.floor(y1 / size);
|
|
63
|
+
const cx = (rect[0] + rect[2]) / 2 / size;
|
|
64
|
+
const cy = (rect[1] + rect[3]) / 2 / size;
|
|
65
|
+
const out = [];
|
|
66
|
+
for (let gy = gy0; gy <= gy1; gy++) {
|
|
67
|
+
for (let gx = gx0; gx <= gx1; gx++)
|
|
68
|
+
out.push({ level, gx, gy });
|
|
69
|
+
}
|
|
70
|
+
const d = (k) => (k.gx + 0.5 - cx) ** 2 + (k.gy + 0.5 - cy) ** 2;
|
|
71
|
+
out.sort((a, b) => d(a) - d(b));
|
|
72
|
+
return out.length > limit ? out.slice(0, limit) : out;
|
|
73
|
+
}
|
|
74
|
+
/** `level/gx/gy`, a tile's id within one plane. */
|
|
75
|
+
export function regionTileId(k) {
|
|
76
|
+
return `${k.level}/${k.gx}/${k.gy}`;
|
|
77
|
+
}
|
|
78
|
+
/** The tile of `level` holding image point (x, y). */
|
|
79
|
+
export function tileAt(x, y, level, tileSize = REGION_TILE_SIZE) {
|
|
80
|
+
const size = levelTileSize(level, tileSize);
|
|
81
|
+
return { level, gx: Math.floor(x / size), gy: Math.floor(y / size) };
|
|
82
|
+
}
|
|
83
|
+
/** True when two boxes meet (edges included). */
|
|
84
|
+
export function bboxesMeet(a, b) {
|
|
85
|
+
return a[0] <= b[2] && a[2] >= b[0] && a[1] <= b[3] && a[3] >= b[1];
|
|
86
|
+
}
|
|
87
|
+
// ── Picking ──────────────────────────────────────────────────────────────────────────────
|
|
88
|
+
/**
|
|
89
|
+
* The feature under image point (x, y): inside an area (even-odd over its rings, so holes are
|
|
90
|
+
* outside) or within `tolerance` image pixels of a polyline. Of several, the one with the
|
|
91
|
+
* smallest box — the innermost of nested outlines. Null when none is.
|
|
92
|
+
*/
|
|
93
|
+
export function featureAt(features, x, y, tolerance = 0) {
|
|
94
|
+
let best = null;
|
|
95
|
+
let bestArea = Infinity;
|
|
96
|
+
for (const f of features) {
|
|
97
|
+
const b = f.bbox;
|
|
98
|
+
if (x < b[0] - tolerance || x > b[2] + tolerance || y < b[1] - tolerance || y > b[3] + tolerance)
|
|
99
|
+
continue;
|
|
100
|
+
const hit = f.open ? nearPolylines(f.rings, x, y, tolerance) : insideRings(f.rings, x, y);
|
|
101
|
+
if (!hit)
|
|
102
|
+
continue;
|
|
103
|
+
const area = (b[2] - b[0]) * (b[3] - b[1]);
|
|
104
|
+
if (area < bestArea) {
|
|
105
|
+
best = f;
|
|
106
|
+
bestArea = area;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return best;
|
|
110
|
+
}
|
|
111
|
+
/** Features whose box meets `rect` (the rubber band's rule for regions). */
|
|
112
|
+
export function featuresInRect(features, rect) {
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const f of features)
|
|
115
|
+
if (bboxesMeet(f.bbox, rect))
|
|
116
|
+
out.push(f);
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
/** Even-odd containment over interleaved rings. */
|
|
120
|
+
export function insideRings(rings, x, y) {
|
|
121
|
+
let inside = false;
|
|
122
|
+
for (const r of rings) {
|
|
123
|
+
const n = r.length >> 1;
|
|
124
|
+
if (n < 3)
|
|
125
|
+
continue;
|
|
126
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
127
|
+
const xi = r[2 * i], yi = r[2 * i + 1], xj = r[2 * j], yj = r[2 * j + 1];
|
|
128
|
+
if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi)
|
|
129
|
+
inside = !inside;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return inside;
|
|
133
|
+
}
|
|
134
|
+
function nearPolylines(lines, x, y, tolerance) {
|
|
135
|
+
for (const l of lines) {
|
|
136
|
+
for (let i = 2; i + 1 < l.length; i += 2) {
|
|
137
|
+
if (segmentDistance(x, y, l[i - 2], l[i - 1], l[i], l[i + 1]) <= tolerance)
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function segmentDistance(px, py, ax, ay, bx, by) {
|
|
144
|
+
const dx = bx - ax, dy = by - ay;
|
|
145
|
+
const len2 = dx * dx + dy * dy;
|
|
146
|
+
const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / len2));
|
|
147
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
148
|
+
}
|
|
149
|
+
// ── Simplification ───────────────────────────────────────────────────────────────────────
|
|
150
|
+
/** Douglas–Peucker over an open polyline (both ends kept). */
|
|
151
|
+
export function simplifyPolyline(xs, ys, epsilon) {
|
|
152
|
+
const n = xs.length;
|
|
153
|
+
if (n <= 2 || !(epsilon > 0))
|
|
154
|
+
return { xs: xs.slice(), ys: ys.slice() };
|
|
155
|
+
const keep = new Uint8Array(n);
|
|
156
|
+
keep[0] = keep[n - 1] = 1;
|
|
157
|
+
const stack = [[0, n - 1]];
|
|
158
|
+
while (stack.length) {
|
|
159
|
+
const [a, b] = stack.pop();
|
|
160
|
+
let maxD = -1, idx = -1;
|
|
161
|
+
for (let i = a + 1; i < b; i++) {
|
|
162
|
+
const d = segmentDistance(xs[i], ys[i], xs[a], ys[a], xs[b], ys[b]);
|
|
163
|
+
if (d > maxD) {
|
|
164
|
+
maxD = d;
|
|
165
|
+
idx = i;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (maxD > epsilon) {
|
|
169
|
+
keep[idx] = 1;
|
|
170
|
+
stack.push([a, idx], [idx, b]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const ox = [], oy = [];
|
|
174
|
+
for (let i = 0; i < n; i++) {
|
|
175
|
+
if (keep[i]) {
|
|
176
|
+
ox.push(xs[i]);
|
|
177
|
+
oy.push(ys[i]);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { xs: ox, ys: oy };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Rings simplified for a level: every ring through Douglas–Peucker at the level's tolerance,
|
|
184
|
+
* rings whose box is under the level's minimum extent dropped, and rings left with too few
|
|
185
|
+
* vertices to draw (3 for a closed ring, 2 for a polyline) dropped. Level 0 returns the rings
|
|
186
|
+
* as they are.
|
|
187
|
+
*/
|
|
188
|
+
export function simplifyRings(rings, open, level) {
|
|
189
|
+
const tol = levelTolerance(level);
|
|
190
|
+
const minExtent = levelMinExtent(level);
|
|
191
|
+
const minVertices = open ? 2 : 3;
|
|
192
|
+
const out = [];
|
|
193
|
+
for (const ring of rings) {
|
|
194
|
+
const n = ring.length >> 1;
|
|
195
|
+
if (n < minVertices)
|
|
196
|
+
continue;
|
|
197
|
+
if (tol === 0) {
|
|
198
|
+
out.push(Float32Array.from(ring));
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const xs = new Array(n), ys = new Array(n);
|
|
202
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
203
|
+
for (let i = 0; i < n; i++) {
|
|
204
|
+
const x = ring[2 * i], y = ring[2 * i + 1];
|
|
205
|
+
xs[i] = x;
|
|
206
|
+
ys[i] = y;
|
|
207
|
+
if (x < x0)
|
|
208
|
+
x0 = x;
|
|
209
|
+
if (x > x1)
|
|
210
|
+
x1 = x;
|
|
211
|
+
if (y < y0)
|
|
212
|
+
y0 = y;
|
|
213
|
+
if (y > y1)
|
|
214
|
+
y1 = y;
|
|
215
|
+
}
|
|
216
|
+
if (Math.max(x1 - x0, y1 - y0) < minExtent)
|
|
217
|
+
continue;
|
|
218
|
+
const s = open ? simplifyPolyline(xs, ys, tol) : simplifyRing(xs, ys, tol);
|
|
219
|
+
if (s.xs.length < minVertices)
|
|
220
|
+
continue;
|
|
221
|
+
const flat = new Float32Array(s.xs.length * 2);
|
|
222
|
+
for (let i = 0; i < s.xs.length; i++) {
|
|
223
|
+
flat[2 * i] = s.xs[i];
|
|
224
|
+
flat[2 * i + 1] = s.ys[i];
|
|
225
|
+
}
|
|
226
|
+
out.push(flat);
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
// ── The feature table ────────────────────────────────────────────────────────────────────
|
|
231
|
+
/** Features (and their simplified outlines) cached per level, past which the oldest go. */
|
|
232
|
+
const SIMPLIFIED_CACHE_LIMIT = 200_000;
|
|
233
|
+
/**
|
|
234
|
+
* A parsed GeoJSON region set, indexed for tiles. Holds the raw features (for the exact
|
|
235
|
+
* geometry and the export), each feature's rings, box, plane and class, and builds a level's
|
|
236
|
+
* tile buckets the first time that level of a plane is asked for.
|
|
237
|
+
*/
|
|
238
|
+
export class RegionFeatureTable {
|
|
239
|
+
constructor(raw, tileSize = REGION_TILE_SIZE) {
|
|
240
|
+
this.raw = raw;
|
|
241
|
+
this.tileSize = tileSize;
|
|
242
|
+
this.ids = [];
|
|
243
|
+
this.labels = [];
|
|
244
|
+
this.colors = [];
|
|
245
|
+
this.planes = [];
|
|
246
|
+
this.boxes = [];
|
|
247
|
+
this.rings = [];
|
|
248
|
+
this.open = [];
|
|
249
|
+
/** Per feature, its parts as ring indices (the exterior first, then its holes). */
|
|
250
|
+
this.parts = [];
|
|
251
|
+
this.labelPoints = new Map();
|
|
252
|
+
/** Each feature's area, worked out the first time its row is asked for. */
|
|
253
|
+
this.areas = new Map();
|
|
254
|
+
this.byId = new Map();
|
|
255
|
+
this.buckets = new Map();
|
|
256
|
+
this.simplified = new Map();
|
|
257
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
258
|
+
raw.forEach((feature, i) => {
|
|
259
|
+
const own = featureIdOf(feature);
|
|
260
|
+
let id = own;
|
|
261
|
+
if (id === undefined || this.byId.has(id)) {
|
|
262
|
+
// Its position, unless a feature already has that id (an explicit "#1", say): ids are unique,
|
|
263
|
+
// or a take, an exclusion or an export would act on both.
|
|
264
|
+
id = `#${i}`;
|
|
265
|
+
for (let k = 1; this.byId.has(id); k++)
|
|
266
|
+
id = `#${i}-${k}`;
|
|
267
|
+
}
|
|
268
|
+
this.byId.set(id, i);
|
|
269
|
+
this.ids.push(id);
|
|
270
|
+
const { label, color } = classificationOf(feature);
|
|
271
|
+
this.labels.push(label);
|
|
272
|
+
this.colors.push(color);
|
|
273
|
+
this.planes.push(feature?.geometry?.plane?.z ?? 0);
|
|
274
|
+
const { rings, open, parts } = ringsOf(feature);
|
|
275
|
+
this.rings.push(rings);
|
|
276
|
+
this.open.push(open);
|
|
277
|
+
this.parts.push(parts);
|
|
278
|
+
const box = ringsBox(rings);
|
|
279
|
+
this.boxes.push(box);
|
|
280
|
+
if (rings.length) {
|
|
281
|
+
x0 = Math.min(x0, box[0]);
|
|
282
|
+
y0 = Math.min(y0, box[1]);
|
|
283
|
+
x1 = Math.max(x1, box[2]);
|
|
284
|
+
y1 = Math.max(y1, box[3]);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
this.bounds = x0 <= x1 ? [x0, y0, x1, y1] : null;
|
|
288
|
+
const extent = this.bounds ? Math.max(Math.abs(x0), Math.abs(y0), Math.abs(x1), Math.abs(y1)) : 0;
|
|
289
|
+
this.levels = 1 + Math.max(0, Math.ceil(Math.log2(Math.max(extent, tileSize) / tileSize)));
|
|
290
|
+
}
|
|
291
|
+
/** Parse a GeoJSON FeatureCollection string. Throws on invalid JSON or no `features`. */
|
|
292
|
+
static fromGeoJson(text, tileSize = REGION_TILE_SIZE) {
|
|
293
|
+
const parsed = JSON.parse(text);
|
|
294
|
+
if (!parsed || !Array.isArray(parsed.features)) {
|
|
295
|
+
throw new Error("Invalid GeoJson file: must contain the 'features' key.");
|
|
296
|
+
}
|
|
297
|
+
const table = new RegionFeatureTable(parsed.features, tileSize);
|
|
298
|
+
table.describe(parsed.classHierarchy, parsed.style);
|
|
299
|
+
return table;
|
|
300
|
+
}
|
|
301
|
+
/** Attach a class hierarchy and a style hint (each ignored when not well formed). */
|
|
302
|
+
describe(hierarchy, style) {
|
|
303
|
+
this.hierarchy = readHierarchy(hierarchy) ?? this.hierarchy;
|
|
304
|
+
this.style = readStyle(style) ?? this.style;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* The outlines of every feature of these classes, plane by plane, simplified for `level` (what a
|
|
308
|
+
* 3D reconstruction of the classes stacks), without the `exclude`d ids: closed features' rings,
|
|
309
|
+
* open features' polylines as `lines`, each ring with its feature (`ringGroups`). Planes without
|
|
310
|
+
* one are left out. `classes` null reads every labelled feature, each outline with its class
|
|
311
|
+
* (`ringLabels`, `lineLabels`).
|
|
312
|
+
*/
|
|
313
|
+
classOutlines(classes, level, exclude = []) {
|
|
314
|
+
const wanted = classes ? new Set(classes) : null;
|
|
315
|
+
const skip = new Set(exclude);
|
|
316
|
+
const byPlane = new Map();
|
|
317
|
+
for (let i = 0; i < this.ids.length; i++) {
|
|
318
|
+
const label = this.labels[i];
|
|
319
|
+
if (!label || (wanted && !wanted.has(label)) || skip.has(this.ids[i]))
|
|
320
|
+
continue;
|
|
321
|
+
const rings = this.ringsAt(i, level);
|
|
322
|
+
if (!rings.length)
|
|
323
|
+
continue;
|
|
324
|
+
const z = this.planes[i];
|
|
325
|
+
let plane = byPlane.get(z);
|
|
326
|
+
if (!plane)
|
|
327
|
+
byPlane.set(z, (plane = { z, rings: [] }));
|
|
328
|
+
if (this.open[i]) {
|
|
329
|
+
(plane.lines ??= []).push(...rings);
|
|
330
|
+
if (!wanted)
|
|
331
|
+
(plane.lineLabels ??= []).push(...rings.map(() => label));
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
plane.rings.push(...rings);
|
|
335
|
+
(plane.ringGroups ??= []).push(...rings.map(() => i));
|
|
336
|
+
if (!wanted)
|
|
337
|
+
(plane.ringLabels ??= []).push(...rings.map(() => label));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return Array.from(byPlane.values()).sort((a, b) => a.z - b.z);
|
|
341
|
+
}
|
|
342
|
+
/** Features per class on plane `z` (null: on every plane), without the `exclude`d ids. */
|
|
343
|
+
classCounts(z, exclude = []) {
|
|
344
|
+
const skip = new Set(exclude);
|
|
345
|
+
const counts = {};
|
|
346
|
+
for (let i = 0; i < this.ids.length; i++) {
|
|
347
|
+
const label = this.labels[i];
|
|
348
|
+
if ((z !== null && this.planes[i] !== z) || !label || skip.has(this.ids[i]))
|
|
349
|
+
continue;
|
|
350
|
+
counts[label] = (counts[label] ?? 0) + 1;
|
|
351
|
+
}
|
|
352
|
+
return counts;
|
|
353
|
+
}
|
|
354
|
+
info() {
|
|
355
|
+
const classColors = {};
|
|
356
|
+
this.labels.forEach((label, i) => {
|
|
357
|
+
const color = this.colors[i];
|
|
358
|
+
if (label && color && !(label in classColors))
|
|
359
|
+
classColors[label] = color;
|
|
360
|
+
});
|
|
361
|
+
return {
|
|
362
|
+
featureCount: this.ids.length,
|
|
363
|
+
bounds: this.bounds,
|
|
364
|
+
tileSize: this.tileSize,
|
|
365
|
+
levels: this.levels,
|
|
366
|
+
planes: Array.from(new Set(this.planes)).sort((a, b) => a - b),
|
|
367
|
+
classColors,
|
|
368
|
+
...(this.hierarchy ? { hierarchy: this.hierarchy } : {}),
|
|
369
|
+
...(this.style ? { style: this.style } : {}),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/** One tile of plane `z`. */
|
|
373
|
+
tile(z, level, gx, gy) {
|
|
374
|
+
const { cells, wide } = this.bucketsFor(z, level);
|
|
375
|
+
const bucket = cells.get(`${gx}/${gy}`) ?? [];
|
|
376
|
+
const size = levelTileSize(level, this.tileSize);
|
|
377
|
+
const features = [];
|
|
378
|
+
// The tile's cell features and the wide ones that meet it, merged back into file order.
|
|
379
|
+
const order = [];
|
|
380
|
+
for (let a = 0, w = 0; a < bucket.length || w < wide.length;) {
|
|
381
|
+
if (w >= wide.length || (a < bucket.length && bucket[a] < wide[w]))
|
|
382
|
+
order.push(bucket[a++]);
|
|
383
|
+
else {
|
|
384
|
+
const i = wide[w++];
|
|
385
|
+
if (cellMeets(this.boxes[i], size, gx, gy))
|
|
386
|
+
order.push(i);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
for (const i of order) {
|
|
390
|
+
const rings = this.ringsAt(i, level);
|
|
391
|
+
if (!rings.length)
|
|
392
|
+
continue;
|
|
393
|
+
const labels = this.labelsAt(i, level);
|
|
394
|
+
features.push({
|
|
395
|
+
id: this.ids[i],
|
|
396
|
+
label: this.labels[i],
|
|
397
|
+
color: this.colors[i],
|
|
398
|
+
bbox: this.boxes[i],
|
|
399
|
+
rings,
|
|
400
|
+
open: this.open[i],
|
|
401
|
+
...(labels ? { labels } : {}),
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
return { z, level, gx, gy, features };
|
|
405
|
+
}
|
|
406
|
+
/** The raw GeoJSON features with these ids, in the order asked (unknown ids skipped). */
|
|
407
|
+
features(ids) {
|
|
408
|
+
const out = [];
|
|
409
|
+
for (const id of ids) {
|
|
410
|
+
const i = this.byId.get(id);
|
|
411
|
+
if (i !== undefined)
|
|
412
|
+
out.push({ id, feature: this.raw[i] });
|
|
413
|
+
}
|
|
414
|
+
return out;
|
|
415
|
+
}
|
|
416
|
+
/** Feature `i`'s area in px² (0 for a polyline). */
|
|
417
|
+
areaOf(i) {
|
|
418
|
+
let area = this.areas.get(i);
|
|
419
|
+
if (area === undefined) {
|
|
420
|
+
area = this.open[i] ? 0 : ringsArea(this.rings[i]);
|
|
421
|
+
this.areas.set(i, area);
|
|
422
|
+
}
|
|
423
|
+
return area;
|
|
424
|
+
}
|
|
425
|
+
/** A page of plane `z`'s features, in file order. */
|
|
426
|
+
index(z, query) {
|
|
427
|
+
const exclude = new Set(query.exclude ?? []);
|
|
428
|
+
const classes = query.classes ? new Set(query.classes) : null;
|
|
429
|
+
const needle = query.label?.trim().toLowerCase() || null;
|
|
430
|
+
const rows = [];
|
|
431
|
+
let total = 0;
|
|
432
|
+
for (let i = 0; i < this.ids.length; i++) {
|
|
433
|
+
if (this.planes[i] !== z || exclude.has(this.ids[i]))
|
|
434
|
+
continue;
|
|
435
|
+
if (needle && !(this.labels[i] ?? '').toLowerCase().includes(needle))
|
|
436
|
+
continue;
|
|
437
|
+
if (classes && !classes.has(this.labels[i] ?? ''))
|
|
438
|
+
continue;
|
|
439
|
+
if (total >= query.offset && rows.length < query.limit) {
|
|
440
|
+
rows.push({
|
|
441
|
+
id: this.ids[i],
|
|
442
|
+
label: this.labels[i],
|
|
443
|
+
color: this.colors[i],
|
|
444
|
+
bbox: this.boxes[i],
|
|
445
|
+
area: this.areaOf(i),
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
total++;
|
|
449
|
+
}
|
|
450
|
+
return { total, rows };
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* The source as a GeoJSON FeatureCollection string, through the working set: features whose
|
|
454
|
+
* id is in `exclude` (taken for editing, or deleted) are left out, `extra` (the working set's
|
|
455
|
+
* features) appended. Every feature keeps an `id`; the set keeps its hierarchy and style.
|
|
456
|
+
*/
|
|
457
|
+
exportGeoJson(exclude, extra) {
|
|
458
|
+
const skip = new Set(exclude);
|
|
459
|
+
const parts = [];
|
|
460
|
+
this.raw.forEach((feature, i) => {
|
|
461
|
+
const id = this.ids[i];
|
|
462
|
+
if (skip.has(id))
|
|
463
|
+
return;
|
|
464
|
+
parts.push(JSON.stringify(feature.id === undefined ? { type: 'Feature', id, ...feature } : feature));
|
|
465
|
+
});
|
|
466
|
+
for (const f of extra)
|
|
467
|
+
parts.push(JSON.stringify(f));
|
|
468
|
+
return featureCollectionJson(parts, this.hierarchy, this.style);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Feature `i`'s label points (one per part with room for a label at `level`: a part under the
|
|
472
|
+
* level's minimum extent is not drawn there), from the exact geometry, computed once.
|
|
473
|
+
*/
|
|
474
|
+
labelsAt(i, level) {
|
|
475
|
+
if (this.open[i] || !this.labels[i])
|
|
476
|
+
return null;
|
|
477
|
+
let points = this.labelPoints.get(i);
|
|
478
|
+
if (!points) {
|
|
479
|
+
const out = [];
|
|
480
|
+
for (const part of this.parts[i]) {
|
|
481
|
+
const pole = polylabel(part.map((r) => this.rings[i][r]));
|
|
482
|
+
if (pole && pole.distance > 0)
|
|
483
|
+
out.push(pole.x, pole.y, pole.distance);
|
|
484
|
+
}
|
|
485
|
+
points = Float32Array.from(out);
|
|
486
|
+
this.labelPoints.set(i, points);
|
|
487
|
+
}
|
|
488
|
+
const min = levelMinExtent(level) / 2;
|
|
489
|
+
if (!min)
|
|
490
|
+
return points.length ? points : null;
|
|
491
|
+
const kept = [];
|
|
492
|
+
for (let k = 0; k + 2 < points.length; k += 3)
|
|
493
|
+
if (points[k + 2] >= min)
|
|
494
|
+
kept.push(points[k], points[k + 1], points[k + 2]);
|
|
495
|
+
return kept.length ? Float32Array.from(kept) : null;
|
|
496
|
+
}
|
|
497
|
+
/** Feature `i`'s rings at `level`, simplified once and cached. */
|
|
498
|
+
ringsAt(i, level) {
|
|
499
|
+
const key = `${level}/${i}`;
|
|
500
|
+
let rings = this.simplified.get(key);
|
|
501
|
+
if (!rings) {
|
|
502
|
+
rings = simplifyRings(this.rings[i], this.open[i], level);
|
|
503
|
+
if (this.simplified.size >= SIMPLIFIED_CACHE_LIMIT) {
|
|
504
|
+
const oldest = this.simplified.keys().next().value;
|
|
505
|
+
this.simplified.delete(oldest);
|
|
506
|
+
}
|
|
507
|
+
this.simplified.set(key, rings);
|
|
508
|
+
}
|
|
509
|
+
return rings;
|
|
510
|
+
}
|
|
511
|
+
/** Entries in plane `z`'s level-`level` index: cell listings plus wide features (tests). */
|
|
512
|
+
indexEntries(z, level) {
|
|
513
|
+
const { cells, wide } = this.bucketsFor(z, level);
|
|
514
|
+
let n = wide.length;
|
|
515
|
+
for (const list of cells.values())
|
|
516
|
+
n += list.length;
|
|
517
|
+
return n;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Plane `z`'s level-`level` index, built on first use: features by tile cell (`gx/gy` → feature
|
|
521
|
+
* indices), and the wide ones (more than {@link MAX_CELLS_PER_FEATURE} cells, or past the
|
|
522
|
+
* number range), tested against a tile when it is asked for.
|
|
523
|
+
*/
|
|
524
|
+
bucketsFor(z, level) {
|
|
525
|
+
const key = `${z}/${level}`;
|
|
526
|
+
let index = this.buckets.get(key);
|
|
527
|
+
if (index)
|
|
528
|
+
return index;
|
|
529
|
+
const cells = new Map();
|
|
530
|
+
const wide = [];
|
|
531
|
+
const size = levelTileSize(level, this.tileSize);
|
|
532
|
+
const minExtent = levelMinExtent(level);
|
|
533
|
+
for (let i = 0; i < this.ids.length; i++) {
|
|
534
|
+
if (this.planes[i] !== z || !this.rings[i].length)
|
|
535
|
+
continue;
|
|
536
|
+
const b = this.boxes[i];
|
|
537
|
+
if (Math.max(b[2] - b[0], b[3] - b[1]) < minExtent)
|
|
538
|
+
continue;
|
|
539
|
+
const gx0 = Math.floor(b[0] / size), gx1 = Math.floor(b[2] / size), gy0 = Math.floor(b[1] / size), gy1 = Math.floor(b[3] / size);
|
|
540
|
+
// A box with a NaN coordinate meets no tile.
|
|
541
|
+
if ([gx0, gx1, gy0, gy1].some(Number.isNaN))
|
|
542
|
+
continue;
|
|
543
|
+
const count = (gx1 - gx0 + 1) * (gy1 - gy0 + 1);
|
|
544
|
+
if (!(count <= MAX_CELLS_PER_FEATURE) || ![gx0, gx1, gy0, gy1].every(Number.isSafeInteger)) {
|
|
545
|
+
wide.push(i);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
for (let gy = gy0; gy <= gy1; gy++) {
|
|
549
|
+
for (let gx = gx0; gx <= gx1; gx++) {
|
|
550
|
+
const id = `${gx}/${gy}`;
|
|
551
|
+
const list = cells.get(id);
|
|
552
|
+
if (list)
|
|
553
|
+
list.push(i);
|
|
554
|
+
else
|
|
555
|
+
cells.set(id, [i]);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
index = { cells, wide };
|
|
560
|
+
this.buckets.set(key, index);
|
|
561
|
+
return index;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* A feature spanning more tiles than this is not listed in each of them but kept aside and tested
|
|
566
|
+
* against a tile when one is asked for: one huge box (an outline around a whole slide, or a corrupt
|
|
567
|
+
* coordinate) must not make a plane's index millions of entries.
|
|
568
|
+
*/
|
|
569
|
+
export const MAX_CELLS_PER_FEATURE = 64;
|
|
570
|
+
/** Whether box `b` meets cell (gx, gy) of tiles `size` pixels wide, as a cell lists it. */
|
|
571
|
+
function cellMeets(b, size, gx, gy) {
|
|
572
|
+
return (Math.floor(b[0] / size) <= gx &&
|
|
573
|
+
gx <= Math.floor(b[2] / size) &&
|
|
574
|
+
Math.floor(b[1] / size) <= gy &&
|
|
575
|
+
gy <= Math.floor(b[3] / size));
|
|
576
|
+
}
|
|
577
|
+
/** A feature's own id (`id`, else `properties.id`) as a string. */
|
|
578
|
+
export function featureIdOf(feature) {
|
|
579
|
+
const id = feature?.id ?? feature?.properties?.id;
|
|
580
|
+
return typeof id === 'string' || typeof id === 'number' ? String(id) : undefined;
|
|
581
|
+
}
|
|
582
|
+
/** Class name and colour from QuPath's `classification` (`{name, color}`, or a bare name). */
|
|
583
|
+
function classificationOf(feature) {
|
|
584
|
+
const c = feature?.properties?.classification;
|
|
585
|
+
if (!c)
|
|
586
|
+
return { label: 'Cell', color: null };
|
|
587
|
+
if (typeof c === 'string')
|
|
588
|
+
return { label: c, color: null };
|
|
589
|
+
const color = Array.isArray(c.color) && c.color.length >= 3 ? rgbToHex([c.color[0], c.color[1], c.color[2]]) : null;
|
|
590
|
+
return { label: c.name ?? null, color };
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* A feature's rings, interleaved, without the closing vertex; whether it is a polyline; and its
|
|
594
|
+
* parts as ring indices (each part's exterior first, then its holes).
|
|
595
|
+
*/
|
|
596
|
+
function ringsOf(feature) {
|
|
597
|
+
const g = feature?.geometry;
|
|
598
|
+
const coords = g?.coordinates;
|
|
599
|
+
if (!g || !Array.isArray(coords))
|
|
600
|
+
return { rings: [], open: false, parts: [] };
|
|
601
|
+
const polygons = (list) => {
|
|
602
|
+
const rings = [];
|
|
603
|
+
const parts = [];
|
|
604
|
+
for (const polygon of list) {
|
|
605
|
+
const part = [];
|
|
606
|
+
for (const r of polygon) {
|
|
607
|
+
part.push(rings.length);
|
|
608
|
+
rings.push(flatRing(r, true));
|
|
609
|
+
}
|
|
610
|
+
if (part.length)
|
|
611
|
+
parts.push(part);
|
|
612
|
+
}
|
|
613
|
+
return { rings, open: false, parts };
|
|
614
|
+
};
|
|
615
|
+
switch (g.type) {
|
|
616
|
+
case 'Polygon':
|
|
617
|
+
return polygons([coords]);
|
|
618
|
+
case 'MultiPolygon':
|
|
619
|
+
return polygons(coords);
|
|
620
|
+
case 'LineString':
|
|
621
|
+
return { rings: [flatRing(coords, false)], open: true, parts: [] };
|
|
622
|
+
case 'MultiLineString':
|
|
623
|
+
return { rings: coords.map((r) => flatRing(r, false)), open: true, parts: [] };
|
|
624
|
+
default:
|
|
625
|
+
return { rings: [], open: false, parts: [] };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* A FeatureCollection string of `features` (each a feature's JSON), with the set's class hierarchy
|
|
630
|
+
* and style as its `classHierarchy` and `style` members when it has them: what
|
|
631
|
+
* {@link RegionFeatureTable.fromGeoJson} reads back.
|
|
632
|
+
*/
|
|
633
|
+
export function featureCollectionJson(features, hierarchy, style) {
|
|
634
|
+
const head = ['"type":"FeatureCollection"'];
|
|
635
|
+
if (hierarchy?.length)
|
|
636
|
+
head.push(`"classHierarchy":${JSON.stringify(hierarchy)}`);
|
|
637
|
+
if (style)
|
|
638
|
+
head.push(`"style":${JSON.stringify(style)}`);
|
|
639
|
+
return `{${head.join(',')},"features":[${features.join(',')}]}`;
|
|
640
|
+
}
|
|
641
|
+
/** A well-formed class hierarchy from a file (colours as `#rrggbb` or `[r, g, b]`), else undefined. */
|
|
642
|
+
export function readHierarchy(raw) {
|
|
643
|
+
if (!Array.isArray(raw))
|
|
644
|
+
return undefined;
|
|
645
|
+
const out = [];
|
|
646
|
+
for (const n of raw) {
|
|
647
|
+
if (!n || typeof n.name !== 'string')
|
|
648
|
+
continue;
|
|
649
|
+
const color = Array.isArray(n.color) ? rgbToHex([+n.color[0], +n.color[1], +n.color[2]]) : n.color;
|
|
650
|
+
out.push({
|
|
651
|
+
name: n.name,
|
|
652
|
+
...(typeof n.title === 'string' ? { title: n.title } : {}),
|
|
653
|
+
...(typeof n.parent === 'string' ? { parent: n.parent } : {}),
|
|
654
|
+
...(typeof color === 'string' ? { color } : {}),
|
|
655
|
+
...(typeof n.order === 'number' ? { order: n.order } : {}),
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return out.length ? out : undefined;
|
|
659
|
+
}
|
|
660
|
+
/** A well-formed style hint from a file, else undefined. */
|
|
661
|
+
export function readStyle(raw) {
|
|
662
|
+
if (!raw || typeof raw !== 'object')
|
|
663
|
+
return undefined;
|
|
664
|
+
const r = raw;
|
|
665
|
+
const style = {};
|
|
666
|
+
if (typeof r.fillOpacity === 'number')
|
|
667
|
+
style.fillOpacity = Math.max(0, Math.min(1, r.fillOpacity));
|
|
668
|
+
if (typeof r.stroke === 'string')
|
|
669
|
+
style.stroke = r.stroke;
|
|
670
|
+
if (typeof r.strokeWidth === 'number' && r.strokeWidth > 0)
|
|
671
|
+
style.strokeWidth = r.strokeWidth;
|
|
672
|
+
if (typeof r.labels === 'boolean')
|
|
673
|
+
style.labels = r.labels;
|
|
674
|
+
if (typeof r.highlight === 'string')
|
|
675
|
+
style.highlight = r.highlight;
|
|
676
|
+
return Object.keys(style).length ? style : undefined;
|
|
677
|
+
}
|
|
678
|
+
function flatRing(points, closed) {
|
|
679
|
+
let n = points?.length ?? 0;
|
|
680
|
+
if (closed && n > 1) {
|
|
681
|
+
const a = points[0], b = points[n - 1];
|
|
682
|
+
if (a[0] === b[0] && a[1] === b[1])
|
|
683
|
+
n--;
|
|
684
|
+
}
|
|
685
|
+
const out = new Float64Array(n * 2);
|
|
686
|
+
for (let i = 0; i < n; i++) {
|
|
687
|
+
out[2 * i] = +points[i][0];
|
|
688
|
+
out[2 * i + 1] = +points[i][1];
|
|
689
|
+
}
|
|
690
|
+
return out;
|
|
691
|
+
}
|
|
692
|
+
function ringsBox(rings) {
|
|
693
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
694
|
+
for (const r of rings) {
|
|
695
|
+
for (let i = 0; i + 1 < r.length; i += 2) {
|
|
696
|
+
if (r[i] < x0)
|
|
697
|
+
x0 = r[i];
|
|
698
|
+
if (r[i] > x1)
|
|
699
|
+
x1 = r[i];
|
|
700
|
+
if (r[i + 1] < y0)
|
|
701
|
+
y0 = r[i + 1];
|
|
702
|
+
if (r[i + 1] > y1)
|
|
703
|
+
y1 = r[i + 1];
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return [x0, y0, x1, y1];
|
|
707
|
+
}
|
|
708
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXRpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9yZWdpb24tc291cmNlL3JlZ2lvbi10aWxlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUNILE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUtwRCwrQ0FBK0M7QUFDL0MsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDO0FBc0pwQzs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxZQUFvQixFQUFFLE1BQWM7SUFDakUsSUFBSSxDQUFDLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQyxJQUFJLE1BQU0sSUFBSSxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDakQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDekQsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUNsRCxDQUFDO0FBRUQsd0VBQXdFO0FBQ3hFLE1BQU0sVUFBVSxjQUFjLENBQUMsS0FBYTtJQUMxQyxPQUFPLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQzNDLENBQUM7QUFFRCxrR0FBa0c7QUFDbEcsTUFBTSxVQUFVLGNBQWMsQ0FBQyxLQUFhO0lBQzFDLE9BQU8sS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDO0FBQ3JDLENBQUM7QUFFRCw2Q0FBNkM7QUFDN0MsTUFBTSxVQUFVLGFBQWEsQ0FBQyxLQUFhLEVBQUUsUUFBUSxHQUFHLGdCQUFnQjtJQUN0RSxPQUFPLFFBQVEsR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDO0FBQy9CLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsaUJBQWlCLENBQy9CLElBQVUsRUFDVixLQUFhLEVBQ2IsUUFBZ0IsRUFDaEIsTUFBbUIsRUFDbkIsS0FBSyxHQUFHLFFBQVE7SUFFaEIsSUFBSSxDQUFDLE1BQU07UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUN2QixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QyxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUU7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNsQyxNQUFNLElBQUksR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQzVDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDMUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztJQUMxQyxNQUFNLEdBQUcsR0FBb0IsRUFBRSxDQUFDO0lBQ2hDLEtBQUssSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUNuQyxLQUFLLElBQUksRUFBRSxHQUFHLEdBQUcsRUFBRSxFQUFFLElBQUksR0FBRyxFQUFFLEVBQUUsRUFBRTtZQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUNELE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBZ0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEYsR0FBRyxDQUFDLElBQUksQ0FB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QUFDO1lBQ2hELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3JCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3ZCLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNyQixJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDakIsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUMxQixFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzFCLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDMUIsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ2pELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUks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T0FBTyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUM7UUFDN0MsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDOUQsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsSUFBSSxJQUFJLENBQUM7UUFDekQsTUFBTSxJQUFJLEdBQXFCLEVBQUUsQ0FBQztRQUNsQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUN6QyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFBRSxTQUFTO1lBQy9ELElBQUksTUFBTSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7Z0JBQUUsU0FBUztZQUMvRSxJQUFJLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQUUsU0FBUztZQUM1RCxJQUFJLEtBQUssSUFBSSxLQUFLLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUN2RCxJQUFJLENBQUMsSUFBSSxDQUFDO29CQUNSLEVBQUUsRUFBRSxJQUFJLENBQUMs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RyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3pDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU07Z0JBQUUsU0FBUztZQUM1RCxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3hCLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFTO2dCQUFFLFNBQVM7WUFDN0QsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQ2pDLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFDN0IsR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUM3QixHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDaEMsNkNBQTZDO1lBQzdDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztnQkFBRSxTQUFTO1lBQ3RELE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDaEQsSUFBSSxDQUFDLENB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dGlsZWQgcmVnaW9uIHNvdXJjZTogYSBsYXJnZSBHZW9KU09OIHJlZ2lvbiBzZXQgY3V0IGludG8gdGlsZXMgcGVyIGxldmVsXG4gKiBvZiBkZXRhaWwsIHRoZSBvdXRsaW5lcyBzaW1wbGlmaWVkIHBlciBsZXZlbCwgc28gYSB2aWV3IG9ubHkgZXZlciBob2xkcyBhbmQgZHJhd3Mgd2hhdCBpcyBvblxuICogc2NyZWVuIGF0IHRoZSBkZXRhaWwgdGhlIHpvb20gY2FuIHNob3cuXG4gKlxuICogTGV2ZWxzOiBsZXZlbCAwIGlzIGV4YWN0OyBhIGxldmVsLWsgdGlsZSBjb3ZlcnMgYHRpbGVTaXplIMK3IDLhtY9gIGltYWdlIHBpeGVscyBhbmQgaXRzIG91dGxpbmVzXG4gKiBhcmUgc2ltcGxpZmllZCAoRG91Z2xhc+KAk1BldWNrZXIpIHRvIGAy4bWP4oG7wrlgIGltYWdlIHBpeGVscyDigJQgaGFsZiB0byBvbmUgc2NyZWVuIHBpeGVsIGF0IHRoZSB6b29tc1xuICogdGhhdCBwaWNrIHRoYXQgbGV2ZWwgKHtAbGluayByZWdpb25MZXZlbEZvcn0pLiBBIGZlYXR1cmUgdW5kZXIgYDLhtY9gIGltYWdlIHBpeGVscyAob25lIHRvIHR3b1xuICogc2NyZWVuIHBpeGVscyB0aGVyZSkgaXMgbGVmdCBvdXQgb2YgdGhlIGxldmVsLiBBIHRpbGUgaG9sZHMgdGhlIFdIT0xFIHNpbXBsaWZpZWQgZmVhdHVyZSAobm90XG4gKiBjbGlwcGVkKSBmb3IgZXZlcnkgZmVhdHVyZSB3aG9zZSBib3ggbWVldHMgaXQsIHNvIGEgdmlldyBkZS1kdXBsaWNhdGVzIGZlYXR1cmVzIGJ5IGlkLCBhbmQgYXRcbiAqIGxldmVsIDAgdGhlIHRpbGVzIGluIHZpZXcgaG9sZCB0aGUgZXhhY3Qgb3V0bGluZSBvZiBldmVyeXRoaW5nIHZpc2libGUuXG4gKlxuICogTm8gRE9NLCBubyBBbmd1bGFyOiB0aGUgc2FtZSBjb2RlIHJ1bnMgaW4gdGhlIHJlZ2lvbi1zb3VyY2Ugd29ya2VyIGFuZCwgd2hlcmUgd29ya2VycyBkbyBub3RcbiAqIGV4aXN0LCBvbiB0aGUgbWFpbiB0aHJlYWQuXG4gKi9cbmltcG9ydCB7IHJnYlRvSGV4IH0gZnJvbSAnLi4vY29udHJhY3RzL2NvbG9yJztcbmltcG9ydCB7IHNpbXBsaWZ5UmluZyB9IGZyb20gJy4uL2dlb21ldHJ5L3JpbmcnO1xuaW1wb3J0IHsgcG9seWxhYmVsIH0gZnJvbSAnLi4vZ2VvbWV0cnkvcG9seWxhYmVsJztcbmltcG9ydCB7IHJpbmdzQXJlYSB9IGZyb20gJy4uL2dlb21ldHJ5L3JlY29uc3RydWN0JztcblxuLyoqIEFuIGF4aXMtYWxpZ25lZCBib3ggYFt4MCwgeTAsIHgxLCB5MV1gIGluIGltYWdlIHBpeGVscy4gKi9cbmV4cG9ydCB0eXBlIEJib3ggPSBbbnVtYmVyLCBudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcblxuLyoqIEVkZ2Ugb2YgYSBsZXZlbC0wIHRpbGUsIGluIGltYWdlIHBpeGVscy4gKi9cbmV4cG9ydCBjb25zdCBSRUdJT05fVElMRV9TSVpFID0gNTEyO1xuXG4vKipcbiAqIE9uZSBjbGFzcyBvZiBhIGNsYXNzIGhpZXJhcmNoeSAoZS5nLiBhIGJyYWluLWF0bGFzIG9udG9sb2d5KTogdGhlIGNsYXNzIG5hbWUgdGhlIGZlYXR1cmVzIHVzZSxcbiAqIGl0cyBsb25nIG5hbWUsIGl0cyBwYXJlbnQgY2xhc3MgYW5kIGl0cyBjb2xvdXIuIEEgcmVnaW9uIHNldCBtYXkgY2Fycnkgb25lIChhIEdlb0pTT05cbiAqIEZlYXR1cmVDb2xsZWN0aW9uJ3MgYGNsYXNzSGllcmFyY2h5YCBtZW1iZXIpOyB0aGUgUmVnaW9uIEVkaXRvciB0aGVuIGxpc3RzIHRoZSBzZXQgYXMgYSB0cmVlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2lvbkNsYXNzTm9kZSB7XG4gIC8qKiBUaGUgY2xhc3MgbmFtZSwgYXMgZmVhdHVyZXMgdXNlIGl0IChgY2xhc3NpZmljYXRpb24ubmFtZWApOiBhbiBhdGxhcyBhY3JvbnltLCBzYXkuICovXG4gIG5hbWU6IHN0cmluZztcbiAgLyoqIFRoZSBsb25nIG5hbWUsIGUuZy4gXCJTb21hdG9tb3RvciBhcmVhcywgTGF5ZXIgNVwiLiAqL1xuICB0aXRsZT86IHN0cmluZztcbiAgLyoqIFRoZSBwYXJlbnQgY2xhc3MncyBuYW1lOyBhYnNlbnQgZm9yIGEgcm9vdC4gKi9cbiAgcGFyZW50Pzogc3RyaW5nIHwgbnVsbDtcbiAgLyoqIGAjcnJnZ2JiYC4gKi9cbiAgY29sb3I/OiBzdHJpbmc7XG4gIC8qKiBQb3NpdGlvbiBhbW9uZyBpdHMgc2libGluZ3MgKGFuIGF0bGFzJ3MgZ3JhcGggb3JkZXIpOyBmaWxlIG9yZGVyIHdpdGhvdXQgb25lLiAqL1xuICBvcmRlcj86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBIb3cgYSByZWdpb24gc2V0IHdhbnRzIHRvIGJlIGRyYXduLCBhIGhpbnQgdGhlIHZpZXdlciBhcHBsaWVzIHdoZW4gdGhlIHNldCBvcGVucyAoYSBHZW9KU09OXG4gKiBGZWF0dXJlQ29sbGVjdGlvbidzIGBzdHlsZWAgbWVtYmVyKTogYW4gYXRsYXMgZmlsbHMgaXRzIHN0cnVjdHVyZXMgYW5kIGxhYmVscyB0aGVtLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2lvblNvdXJjZVN0eWxlIHtcbiAgLyoqIEZpbGwgcmVnaW9ucyBpbiB0aGVpciBjb2xvdXIgYXQgdGhpcyBvcGFjaXR5ICgwID0gb3V0bGluZXMgb25seSkuICovXG4gIGZpbGxPcGFjaXR5PzogbnVtYmVyO1xuICAvKiogT3V0bGluZSBjb2xvdXIgd2hlbiBmaWxsZWQgKGRlZmF1bHQ6IHRoZSByZWdpb24ncyBjb2xvdXIpLiAqL1xuICBzdHJva2U/OiBzdHJpbmc7XG4gIC8qKiBPdXRsaW5lIHdpZHRoIGluIHNjcmVlbiBweC4gKi9cbiAgc3Ryb2tlV2lkdGg/OiBudW1iZXI7XG4gIC8qKiBTaG93IGNsYXNzIGxhYmVscyBpbnNpZGUgdGhlIHJlZ2lvbnMuICovXG4gIGxhYmVscz86IGJvb2xlYW47XG4gIC8qKiBGaWxsIGNvbG91ciBvZiBzZWxlY3RlZCByZWdpb25zLiAqL1xuICBoaWdobGlnaHQ/OiBzdHJpbmc7XG59XG5cbi8qKiBXaGF0IGEgcmVnaW9uIHNvdXJjZSBob2xkcywga25vd24gb25jZSBpdCBpcyBvcGVuLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpb25Tb3VyY2VJbmZvIHtcbiAgLyoqIEZlYXR1cmVzIGluIHRoZSBzb3VyY2UsIG92ZXIgZXZlcnkgcGxhbmUuICovXG4gIGZlYXR1cmVDb3VudDogbnVtYmVyO1xuICAvKiogVGhlIGJveCBhcm91bmQgZXZlcnkgZmVhdHVyZSdzIGdlb21ldHJ5OyBudWxsIHdoZW4gbm9uZSBoYXMgYW55LiAqL1xuICBib3VuZHM6IEJib3ggfCBudWxsO1xuICAvKiogRWRnZSBvZiBhIGxldmVsLTAgdGlsZSwgaW4gaW1hZ2UgcGl4ZWxzLiAqL1xuICB0aWxlU2l6ZTogbnVtYmVyO1xuICAvKiogTnVtYmVyIG9mIGxldmVsczsgdGhlIGxhc3Qgb25lJ3MgdGlsZXMgY292ZXIge0BsaW5rIGJvdW5kc30gaW4gYSBmZXcgdGlsZXMuICovXG4gIGxldmVsczogbnVtYmVyO1xuICAvKiogVGhlIHogcGxhbmVzIGZlYXR1cmVzIGFyZSBvbiAoUXVQYXRoJ3MgYGdlb21ldHJ5LnBsYW5lLnpgLCAwIHdpdGhvdXQgb25lKSwgYXNjZW5kaW5nLiAqL1xuICBwbGFuZXM6IG51bWJlcltdO1xuICAvKiogVGhlIGNvbG91ciB0aGUgZmlsZSBnaXZlcyBlYWNoIGNsYXNzIChpdHMgZmlyc3QgZmVhdHVyZSdzKSwgYnkgY2xhc3MgbmFtZS4gKi9cbiAgY2xhc3NDb2xvcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKiBUaGUgc2V0J3MgY2xhc3MgaGllcmFyY2h5LCB3aGVuIGl0IGhhcyBvbmUuICovXG4gIGhpZXJhcmNoeT86IFJlZ2lvbkNsYXNzTm9kZVtdO1xuICAvKiogSG93IHRoZSBzZXQgd2FudHMgdG8gYmUgZHJhd24sIHdoZW4gaXQgc2F5cy4gKi9cbiAgc3R5bGU/OiBSZWdpb25Tb3VyY2VTdHlsZTtcbn1cblxuLyoqIE9uZSBmZWF0dXJlIGFzIGEgdGlsZSBjYXJyaWVzIGl0OiBpZGVudGl0eSwgY2xhc3MgYW5kIG91dGxpbmUgYXQgdGhlIHRpbGUncyBsZXZlbC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVGlsZUZlYXR1cmUge1xuICBpZDogc3RyaW5nO1xuICAvKiogVGhlIGNsYXNzIG5hbWUuICovXG4gIGxhYmVsOiBzdHJpbmcgfCBudWxsO1xuICAvKiogVGhlIGZlYXR1cmUncyBvd24gY29sb3VyIChgI3JyZ2diYmApLCBmcm9tIGl0cyBjbGFzc2lmaWNhdGlvbi4gKi9cbiAgY29sb3I6IHN0cmluZyB8IG51bGw7XG4gIC8qKiBUaGUgYm94IGFyb3VuZCB0aGUgZXhhY3QgZ2VvbWV0cnkuICovXG4gIGJib3g6IEJib3g7XG4gIC8qKiBSaW5ncyBhcyBpbnRlcmxlYXZlZCBgeCwgeWAgKG5vIHJlcGVhdGVkIGNsb3NpbmcgdmVydGV4KTogZXh0ZXJpb3JzIGFuZCBob2xlcyBvZiBldmVyeVxuICAgKiAgcGFydCwgZHJhd24gYW5kIGhpdC10ZXN0ZWQgZXZlbi1vZGQuIEZvciBhbiBvcGVuIGZlYXR1cmUsIGl0cyBwb2x5bGluZXMuICovXG4gIHJpbmdzOiBGbG9hdDMyQXJyYXlbXTtcbiAgLyoqIEEgcG9seWxpbmUgKExpbmVTdHJpbmcpIHJhdGhlciB0aGFuIGFuIGFyZWEuICovXG4gIG9wZW46IGJvb2xlYW47XG4gIC8qKlxuICAgKiBXaGVyZSB0byBsYWJlbCB0aGUgZmVhdHVyZSwgcGVyIHBhcnQgYmlnIGVub3VnaDogYHgsIHksIHJvb21gIHRyaXBsZXMsIGByb29tYCB0aGUgZGlzdGFuY2VcbiAgICogZnJvbSB0aGUgcG9pbnQgdG8gdGhlIHBhcnQncyBuZWFyZXN0IGVkZ2UgKGltYWdlIHB4KSwgc28gYSBsYWJlbCBzaG93cyBvbmNlIGl0IGZpdHMuXG4gICAqL1xuICBsYWJlbHM/OiBGbG9hdDMyQXJyYXk7XG59XG5cbi8qKlxuICogQSBjbGFzcydzIG91dGxpbmVzIG9uIG9uZSBwbGFuZTogcmluZ3MgYXMgaW50ZXJsZWF2ZWQgYHgsIHlgIGltYWdlIHB4IChob2xlcyBpbmNsdWRlZCksIGFuZCBpdHNcbiAqIG9wZW4gZmVhdHVyZXMnIHBvbHlsaW5lcywgbGlrZXdpc2UgKGFic2VudCBmcm9tIGEgc2VydmVyIHRoYXQgcHJlZGF0ZXMgdGhlbSkuIFJlYWQgZm9yIGV2ZXJ5XG4gKiBjbGFzcyBhdCBvbmNlLCBlYWNoIHJpbmcncyBhbmQgbGluZSdzIGNsYXNzIGNvbWVzIHdpdGggaXQgKGByaW5nTGFiZWxzYCwgYGxpbmVMYWJlbHNgKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbGFzc091dGxpbmVzIHtcbiAgejogbnVtYmVyO1xuICByaW5nczogRmxvYXQzMkFycmF5W107XG4gIC8qKlxuICAgKiBUaGUgZmVhdHVyZSBlYWNoIHJpbmcgaXMgcGFydCBvZiAoc2VlIFNsaWNlT3V0bGluZXMucmluZ0dyb3Vwcyk6IGEgZmVhdHVyZSdzIHJpbmdzIGZpbGxcbiAgICogZXZlbi1vZGQsIHRoZSBmZWF0dXJlcyBhcyB0aGVpciB1bmlvbi4gQWJzZW50IGZyb20gYSBzZXJ2ZXIgdGhhdCBwcmVkYXRlcyB0aGVtLlxuICAgKi9cbiAgcmluZ0dyb3Vwcz86IG51bWJlcltdO1xuICBsaW5lcz86IEZsb2F0MzJBcnJheVtdO1xuICByaW5nTGFiZWxzPzogc3RyaW5nW107XG4gIGxpbmVMYWJlbHM/OiBzdHJpbmdbXTtcbn1cblxuLyoqIE9uZSB0aWxlIG9mIG9uZSBsZXZlbCBvZiBvbmUgcGxhbmUuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2lvblRpbGUge1xuICB6OiBudW1iZXI7XG4gIGxldmVsOiBudW1iZXI7XG4gIGd4OiBudW1iZXI7XG4gIGd5OiBudW1iZXI7XG4gIGZlYXR1cmVzOiBUaWxlRmVhdHVyZVtdO1xufVxuXG4vKiogQSB0aWxlJ3MgYWRkcmVzcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVnaW9uVGlsZUtleSB7XG4gIGxldmVsOiBudW1iZXI7XG4gIGd4OiBudW1iZXI7XG4gIGd5OiBudW1iZXI7XG59XG5cbi8qKiBPbmUgcm93IG9mIGEgc291cmNlJ3MgZmVhdHVyZSBpbmRleCAodGhlIFJlZ2lvbiBFZGl0b3IncyB0YWJsZSkuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2lvbkluZGV4Um93IHtcbiAgaWQ6IHN0cmluZztcbiAgbGFiZWw6IHN0cmluZyB8IG51bGw7XG4gIGNvbG9yOiBzdHJpbmcgfCBudWxsO1xuICBiYm94OiBCYm94O1xuICAvKiogVGhlIGFyZWEgaW5zaWRlIHRoZSBleGFjdCBvdXRsaW5lIChob2xlcyBsZWZ0IG91dCksIGltYWdlIHB4wrI7IDAgZm9yIGEgcG9seWxpbmUuIEFic2VudCBmcm9tIGFcbiAgICogIHNlcnZlciB0aGF0IHByZWRhdGVzIGl0LiAqL1xuICBhcmVhPzogbnVtYmVyO1xufVxuXG4vKiogQSBwYWdlIG9mIGEgcGxhbmUncyBmZWF0dXJlIGluZGV4LiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpb25JbmRleFBhZ2Uge1xuICAvKiogUm93cyBtYXRjaGluZyB0aGUgcXVlcnksIG92ZXIgdGhlIHdob2xlIHBsYW5lLiAqL1xuICB0b3RhbDogbnVtYmVyO1xuICByb3dzOiBSZWdpb25JbmRleFJvd1tdO1xufVxuXG4vKiogV2hpY2ggcm93cyBhIHBhZ2Ugb2YgdGhlIGluZGV4IGhvbGRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpb25JbmRleFF1ZXJ5IHtcbiAgb2Zmc2V0OiBudW1iZXI7XG4gIGxpbWl0OiBudW1iZXI7XG4gIC8qKiBPbmx5IHJvd3Mgd2hvc2UgY2xhc3MgbmFtZSBjb250YWlucyB0aGlzIChjYXNlLWluc2Vuc2l0aXZlKS4gKi9cbiAgbGFiZWw/OiBzdHJpbmc7XG4gIC8qKiBMZWF2ZSB0aGVzZSBpZHMgb3V0ICh0YWtlbiBpbnRvIHRoZSB3b3JraW5nIHNldCwgb3IgZGVsZXRlZCkuICovXG4gIGV4Y2x1ZGU/OiByZWFkb25seSBzdHJpbmdbXTtcbiAgLyoqIE9ubHkgcm93cyBvZiBleGFjdGx5IHRoZXNlIGNsYXNzZXMuICovXG4gIGNsYXNzZXM/OiByZWFkb25seSBzdHJpbmdbXTtcbn1cblxuLyoqIFRoZSBwYXJ0cyBvZiBhIEdlb0pTT04gZmVhdHVyZSB0aGUgdGlsZXIgcmVhZHMuIFBhcnNlZCBmcm9tIGEgZmlsZTogbm90aGluZyBpcyBndWFyYW50ZWVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW9Kc29uRmVhdHVyZUxpa2Uge1xuICB0eXBlPzogc3RyaW5nO1xuICBpZD86IHN0cmluZyB8IG51bWJlcjtcbiAgZ2VvbWV0cnk/OiB7IHR5cGU/OiBzdHJpbmc7IGNvb3JkaW5hdGVzPzogdW5rbm93bjsgcGxhbmU/OiB7IHo/OiBudW1iZXIgfSB9IHwgbnVsbDtcbiAgcHJvcGVydGllcz86IHsgaWQ/OiBzdHJpbmcgfCBudW1iZXI7IGNsYXNzaWZpY2F0aW9uPzogdW5rbm93biB9ICYgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbi8qKlxuICogVGhlIGxldmVsIHdob3NlIHRpbGVzIHN1aXQgYSB6b29tIG9mIGBweFBlckltYWdlUHhgIHNjcmVlbiBwaXhlbHMgcGVyIGltYWdlIHBpeGVsOiBleGFjdCAoMClcbiAqIGF0IDE6MSBhbmQgY2xvc2VyLCBlbHNlIGxldmVsIGsgZm9yIHpvb21zIGluIFsy4oG74bWPLCAywrnigbvhtY8pLCB3aGVyZSBpdHMgdG9sZXJhbmNlIGlzIGhhbGYgdG8gb25lXG4gKiBzY3JlZW4gcGl4ZWwgYW5kIHRoZSBmZWF0dXJlcyBpdCBsZWF2ZXMgb3V0IGFyZSB1bmRlciBvbmUgb3IgdHdvLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaW9uTGV2ZWxGb3IocHhQZXJJbWFnZVB4OiBudW1iZXIsIGxldmVsczogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKCEocHhQZXJJbWFnZVB4ID4gMCkgfHwgbGV2ZWxzIDw9IDEpIHJldHVybiAwO1xuICBjb25zdCBsZXZlbCA9IE1hdGguY2VpbCgtTWF0aC5sb2cyKHB4UGVySW1hZ2VQeCkgLSAxZS05KTtcbiAgcmV0dXJuIE1hdGgubWF4KDAsIE1hdGgubWluKGxldmVscyAtIDEsIGxldmVsKSk7XG59XG5cbi8qKiBTaW1wbGlmaWNhdGlvbiB0b2xlcmFuY2Ugb2YgYSBsZXZlbCwgaW4gaW1hZ2UgcGl4ZWxzICgwID0gZXhhY3QpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxldmVsVG9sZXJhbmNlKGxldmVsOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gbGV2ZWwgPD0gMCA/IDAgOiAyICoqIChsZXZlbCAtIDEpO1xufVxuXG4vKiogRmVhdHVyZXMgc21hbGxlciB0aGFuIHRoaXMgKHRoZWlyIGJveCdzIGxvbmdlciBzaWRlLCBpbWFnZSBwaXhlbHMpIGFyZSBsZWZ0IG91dCBvZiBhIGxldmVsLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxldmVsTWluRXh0ZW50KGxldmVsOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gbGV2ZWwgPD0gMCA/IDAgOiAyICoqIGxldmVsO1xufVxuXG4vKiogVGlsZSBlZGdlIG9mIGEgbGV2ZWwsIGluIGltYWdlIHBpeGVscy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsZXZlbFRpbGVTaXplKGxldmVsOiBudW1iZXIsIHRpbGVTaXplID0gUkVHSU9OX1RJTEVfU0laRSk6IG51bWJlciB7XG4gIHJldHVybiB0aWxlU2l6ZSAqIDIgKiogbGV2ZWw7XG59XG5cbi8qKlxuICogVGlsZXMgb2YgYGxldmVsYCB0aGF0IG1lZXQgYHJlY3RgLCBjbGlwcGVkIHRvIGBib3VuZHNgIChub25lIHBhc3QgdGhlIGRhdGEpLCBvcmRlcmVkIGZyb20gdGhlXG4gKiByZWN0YW5nbGUncyBjZW50cmUgb3V0d2FyZCBzbyB0aGUgbWlkZGxlIG9mIHRoZSBzY3JlZW4gZmlsbHMgZmlyc3QuIEF0IG1vc3QgYGxpbWl0YC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lvblRpbGVzSW5SZWN0KFxuICByZWN0OiBCYm94LFxuICBsZXZlbDogbnVtYmVyLFxuICB0aWxlU2l6ZTogbnVtYmVyLFxuICBib3VuZHM6IEJib3ggfCBudWxsLFxuICBsaW1pdCA9IEluZmluaXR5LFxuKTogUmVnaW9uVGlsZUtleVtdIHtcbiAgaWYgKCFib3VuZHMpIHJldHVybiBbXTtcbiAgY29uc3QgeDAgPSBNYXRoLm1heChyZWN0WzBdLCBib3VuZHNbMF0pO1xuICBjb25zdCB5MCA9IE1hdGgubWF4KHJlY3RbMV0sIGJvdW5kc1sxXSk7XG4gIGNvbnN0IHgxID0gTWF0aC5taW4ocmVjdFsyXSwgYm91bmRzWzJdKTtcbiAgY29uc3QgeTEgPSBNYXRoLm1pbihyZWN0WzNdLCBib3VuZHNbM10pO1xuICBpZiAoeDEgPCB4MCB8fCB5MSA8IHkwKSByZXR1cm4gW107XG4gIGNvbnN0IHNpemUgPSBsZXZlbFRpbGVTaXplKGxldmVsLCB0aWxlU2l6ZSk7XG4gIGNvbnN0IGd4MCA9IE1hdGguZmxvb3IoeDAgLyBzaXplKTtcbiAgY29uc3QgZ3kwID0gTWF0aC5mbG9vcih5MCAvIHNpemUpO1xuICBjb25zdCBneDEgPSBNYXRoLmZsb29yKHgxIC8gc2l6ZSk7XG4gIGNvbnN0IGd5MSA9IE1hdGguZmxvb3IoeTEgLyBzaXplKTtcbiAgY29uc3QgY3ggPSAocmVjdFswXSArIHJlY3RbMl0pIC8gMiAvIHNpemU7XG4gIGNvbnN0IGN5ID0gKHJlY3RbMV0gKyByZWN0WzNdKSAvIDIgLyBzaXplO1xuICBjb25zdCBvdXQ6IFJlZ2lvblRpbGVLZXlbXSA9IFtdO1xuICBmb3IgKGxldCBneSA9IGd5MDsgZ3kgPD0gZ3kxOyBneSsrKSB7XG4gICAgZm9yIChsZXQgZ3ggPSBneDA7IGd4IDw9IGd4MTsgZ3grKykgb3V0LnB1c2goeyBsZXZlbCwgZ3gsIGd5IH0pO1xuICB9XG4gIGNvbnN0IGQgPSAoazogUmVnaW9uVGlsZUtleSkgPT4gKGsuZ3ggKyAwLjUgLSBjeCkgKiogMiArIChrLmd5ICsgMC41IC0gY3kpICoqIDI7XG4gIG91dC5zb3J0KChhLCBiKSA9PiBkKGEpIC0gZChiKSk7XG4gIHJldHVybiBvdXQubGVuZ3RoID4gbGltaXQgPyBvdXQuc2xpY2UoMCwgbGltaXQpIDogb3V0O1xufVxuXG4vKiogYGxldmVsL2d4L2d5YCwgYSB0aWxlJ3MgaWQgd2l0aGluIG9uZSBwbGFuZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWdpb25UaWxlSWQoazogUmVnaW9uVGlsZUtleSk6IHN0cmluZyB7XG4gIHJldHVybiBgJHtrLmxldmVsfS8ke2suZ3h9LyR7ay5neX1gO1xufVxuXG4vKiogVGhlIHRpbGUgb2YgYGxldmVsYCBob2xkaW5nIGltYWdlIHBvaW50ICh4LCB5KS4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0aWxlQXQoeDogbnVtYmVyLCB5OiBudW1iZXIsIGxldmVsOiBudW1iZXIsIHRpbGVTaXplID0gUkVHSU9OX1RJTEVfU0laRSk6IFJlZ2lvblRpbGVLZXkge1xuICBjb25zdCBzaXplID0gbGV2ZWxUaWxlU2l6ZShsZXZlbCwgdGlsZVNpemUpO1xuICByZXR1cm4geyBsZXZlbCwgZ3g6IE1hdGguZmxvb3IoeCAvIHNpemUpLCBneTogTWF0aC5mbG9vcih5IC8gc2l6ZSkgfTtcbn1cblxuLyoqIFRydWUgd2hlbiB0d28gYm94ZXMgbWVldCAoZWRnZXMgaW5jbHVkZWQpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJib3hlc01lZXQoYTogUmVhZG9ubHk8QmJveD4sIGI6IFJlYWRvbmx5PEJib3g+KTogYm9vbGVhbiB7XG4gIHJldHVybiBhWzBdIDw9IGJbMl0gJiYgYVsyXSA+PSBiWzBdICYmIGFbMV0gPD0gYlszXSAmJiBhWzNdID49IGJbMV07XG59XG5cbi8vIOKUgOKUgCBQaWNraW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFRoZSBmZWF0dXJlIHVuZGVyIGltYWdlIHBvaW50ICh4LCB5KTogaW5zaWRlIGFuIGFyZWEgKGV2ZW4tb2RkIG92ZXIgaXRzIHJpbmdzLCBzbyBob2xlcyBhcmVcbiAqIG91dHNpZGUpIG9yIHdpdGhpbiBgdG9sZXJhbmNlYCBpbWFnZSBwaXhlbHMgb2YgYSBwb2x5bGluZS4gT2Ygc2V2ZXJhbCwgdGhlIG9uZSB3aXRoIHRoZVxuICogc21hbGxlc3QgYm94IOKAlCB0aGUgaW5uZXJtb3N0IG9mIG5lc3RlZCBvdXRsaW5lcy4gTnVsbCB3aGVuIG5vbmUgaXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmZWF0dXJlQXQoXG4gIGZlYXR1cmVzOiBJdGVyYWJsZTxUaWxlRmVhdHVyZT4sXG4gIHg6IG51bWJlcixcbiAgeTogbnVtYmVyLFxuICB0b2xlcmFuY2UgPSAwLFxuKTogVGlsZUZlYXR1cmUgfCBudWxsIHtcbiAgbGV0IGJlc3Q6IFRpbGVGZWF0dXJlIHwgbnVsbCA9IG51bGw7XG4gIGxldCBiZXN0QXJlYSA9IEluZmluaXR5O1xuICBmb3IgKGNvbnN0IGYgb2YgZmVhdHVyZXMpIHtcbiAgICBjb25zdCBiID0gZi5iYm94O1xuICAgIGlmICh4IDwgYlswXSAtIHRvbGVyYW5jZSB8fCB4ID4gYlsyXSArIHRvbGVyYW5jZSB8fCB5IDwgYlsxXSAtIHRvbGVyYW5jZSB8fCB5ID4gYlszXSArIHRvbGVyYW5jZSkgY29udGludWU7XG4gICAgY29uc3QgaGl0ID0gZi5vcGVuID8gbmVhclBvbHlsaW5lcyhmLnJpbmdzLCB4LCB5LCB0b2xlcmFuY2UpIDogaW5zaWRlUmluZ3MoZi5yaW5ncywgeCwgeSk7XG4gICAgaWYgKCFoaXQpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGFyZWEgPSAoYlsyXSAtIGJbMF0pICogKGJbM10gLSBiWzFdKTtcbiAgICBpZiAoYXJlYSA8IGJlc3RBcmVhKSB7XG4gICAgICBiZXN0ID0gZjtcbiAgICAgIGJlc3RBcmVhID0gYXJlYTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGJlc3Q7XG59XG5cbi8qKiBGZWF0dXJlcyB3aG9zZSBib3ggbWVldHMgYHJlY3RgICh0aGUgcnViYmVyIGJhbmQncyBydWxlIGZvciByZWdpb25zKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmZWF0dXJlc0luUmVjdChmZWF0dXJlczogSXRlcmFibGU8VGlsZUZlYXR1cmU+LCByZWN0OiBSZWFkb25seTxCYm94Pik6IFRpbGVGZWF0dXJlW10ge1xuICBjb25zdCBvdXQ6IFRpbGVGZWF0dXJlW10gPSBbXTtcbiAgZm9yIChjb25zdCBmIG9mIGZlYXR1cmVzKSBpZiAoYmJveGVzTWVldChmLmJib3gsIHJlY3QpKSBvdXQucHVzaChmKTtcbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIEV2ZW4tb2RkIGNvbnRhaW5tZW50IG92ZXIgaW50ZXJsZWF2ZWQgcmluZ3MuICovXG5leHBvcnQgZnVuY3Rpb24gaW5zaWRlUmluZ3MocmluZ3M6IHJlYWRvbmx5IEFycmF5TGlrZTxudW1iZXI+W10sIHg6IG51bWJlciwgeTogbnVtYmVyKTogYm9vbGVhbiB7XG4gIGxldCBpbnNpZGUgPSBmYWxzZTtcbiAgZm9yIChjb25zdCByIG9mIHJpbmdzKSB7XG4gICAgY29uc3QgbiA9IHIubGVuZ3RoID4+IDE7XG4gICAgaWYgKG4gPCAzKSBjb250aW51ZTtcbiAgICBmb3IgKGxldCBpID0gMCwgaiA9IG4gLSAxOyBpIDwgbjsgaiA9IGkrKykge1xuICAgICAgY29uc3QgeGkgPSByWzIgKiBpXSxcbiAgICAgICAgeWkgPSByWzIgKiBpICsgMV0sXG4gICAgICAgIHhqID0gclsyICogal0sXG4gICAgICAgIHlqID0gclsyICogaiArIDFdO1xuICAgICAgaWYgKHlpID4geSAhPT0geWogPiB5ICYmIHggPCAoKHhqIC0geGkpICogKHkgLSB5aSkpIC8gKHlqIC0geWkpICsgeGkpIGluc2lkZSA9ICFpbnNpZGU7XG4gICAgfVxuICB9XG4gIHJldHVybiBpbnNpZGU7XG59XG5cbmZ1bmN0aW9uIG5lYXJQb2x5bGluZXMobGluZXM6IHJlYWRvbmx5IEFycmF5TGlrZTxudW1iZXI+W10sIHg6IG51bWJlciwgeTogbnVtYmVyLCB0b2xlcmFuY2U6IG51bWJlcik6IGJvb2xlYW4ge1xuICBmb3IgKGNvbnN0IGwgb2YgbGluZXMpIHtcbiAgICBmb3IgKGxldCBpID0gMjsgaSArIDEgPCBsLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICBpZiAoc2VnbWVudERpc3RhbmNlKHgsIHksIGxbaSAtIDJdLCBsW2kgLSAxXSwgbFtpXSwgbFtpICsgMV0pIDw9IHRvbGVyYW5jZSkgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gc2VnbWVudERpc3RhbmNlKHB4OiBudW1iZXIsIHB5OiBudW1iZXIsIGF4OiBudW1iZXIsIGF5OiBudW1iZXIsIGJ4OiBudW1iZXIsIGJ5OiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCBkeCA9IGJ4IC0gYXgsXG4gICAgZHkgPSBieSAtIGF5O1xuICBjb25zdCBsZW4yID0gZHggKiBkeCArIGR5ICogZHk7XG4gIGNvbnN0IHQgPSBsZW4yID09PSAwID8gMCA6IE1hdGgubWF4KDAsIE1hdGgubWluKDEsICgocHggLSBheCkgKiBkeCArIChweSAtIGF5KSAqIGR5KSAvIGxlbjIpKTtcbiAgcmV0dXJuIE1hdGguaHlwb3QocHggLSAoYXggKyB0ICogZHgpLCBweSAtIChheSArIHQgKiBkeSkpO1xufVxuXG4vLyDilIDilIAgU2ltcGxpZmljYXRpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBEb3VnbGFz4oCTUGV1Y2tlciBvdmVyIGFuIG9wZW4gcG9seWxpbmUgKGJvdGggZW5kcyBrZXB0KS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaW1wbGlmeVBvbHlsaW5lKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLCBlcHNpbG9uOiBudW1iZXIpOiB7IHhzOiBudW1iZXJbXTsgeXM6IG51bWJlcltdIH0ge1xuICBjb25zdCBuID0geHMubGVuZ3RoO1xuICBpZiAobiA8PSAyIHx8ICEoZXBzaWxvbiA+IDApKSByZXR1cm4geyB4czogeHMuc2xpY2UoKSwgeXM6IHlzLnNsaWNlKCkgfTtcbiAgY29uc3Qga2VlcCA9IG5ldyBVaW50OEFycmF5KG4pO1xuICBrZWVwWzBdID0ga2VlcFtuIC0gMV0gPSAxO1xuICBjb25zdCBzdGFjazogQXJyYXk8W251bWJlciwgbnVtYmVyXT4gPSBbWzAsIG4gLSAxXV07XG4gIHdoaWxlIChzdGFjay5sZW5ndGgpIHtcbiAgICBjb25zdCBbYSwgYl0gPSBzdGFjay5wb3AoKSBhcyBbbnVtYmVyLCBudW1iZXJdO1xuICAgIGxldCBtYXhEID0gLTEsXG4gICAgICBpZHggPSAtMTtcbiAgICBmb3IgKGxldCBpID0gYSArIDE7IGkgPCBiOyBpKyspIHtcbiAgICAgIGNvbnN0IGQgPSBzZWdtZW50RGlzdGFuY2UoeHNbaV0sIHlzW2ldLCB4c1thXSwgeXNbYV0sIHhzW2JdLCB5c1tiXSk7XG4gICAgICBpZiAoZCA+IG1heEQpIHtcbiAgICAgICAgbWF4RCA9IGQ7XG4gICAgICAgIGlkeCA9IGk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChtYXhEID4gZXBzaWxvbikge1xuICAgICAga2VlcFtpZHhdID0gMTtcbiAgICAgIHN0YWNrLnB1c2goW2EsIGlkeF0sIFtpZHgsIGJdKTtcbiAgICB9XG4gIH1cbiAgY29uc3Qgb3g6IG51bWJlcltdID0gW10sXG4gICAgb3k6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgaWYgKGtlZXBbaV0pIHtcbiAgICAgIG94LnB1c2goeHNbaV0pO1xuICAgICAgb3kucHVzaCh5c1tpXSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB7IHhzOiBveCwgeXM6IG95IH07XG59XG5cbi8qKlxuICogUmluZ3Mgc2ltcGxpZmllZCBmb3IgYSBsZXZlbDogZXZlcnkgcmluZyB0aHJvdWdoIERvdWdsYXPigJNQZXVja2VyIGF0IHRoZSBsZXZlbCdzIHRvbGVyYW5jZSxcbiAqIHJpbmdzIHdob3NlIGJveCBpcyB1bmRlciB0aGUgbGV2ZWwncyBtaW5pbXVtIGV4dGVudCBkcm9wcGVkLCBhbmQgcmluZ3MgbGVmdCB3aXRoIHRvbyBmZXdcbiAqIHZlcnRpY2VzIHRvIGRyYXcgKDMgZm9yIGEgY2xvc2VkIHJpbmcsIDIgZm9yIGEgcG9seWxpbmUpIGRyb3BwZWQuIExldmVsIDAgcmV0dXJucyB0aGUgcmluZ3NcbiAqIGFzIHRoZXkgYXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2ltcGxpZnlSaW5ncyhyaW5nczogcmVhZG9ubHkgRmxvYXQ2NEFycmF5W10sIG9wZW46IGJvb2xlYW4sIGxldmVsOiBudW1iZXIpOiBGbG9hdDMyQXJyYXlbXSB7XG4gIGNvbnN0IHRvbCA9IGxldmVsVG9sZXJhbmNlKGxldmVsKTtcbiAgY29uc3QgbWluRXh0ZW50ID0gbGV2ZWxNaW5FeHRlbnQobGV2ZWwpO1xuICBjb25zdCBtaW5WZXJ0aWNlcyA9IG9wZW4gPyAyIDogMztcbiAgY29uc3Qgb3V0OiBGbG9hdDMyQXJyYXlbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHJpbmcgb2YgcmluZ3MpIHtcbiAgICBjb25zdCBuID0gcmluZy5sZW5ndGggPj4gMTtcbiAgICBpZiAobiA8IG1pblZlcnRpY2VzKSBjb250aW51ZTtcbiAgICBpZiAodG9sID09PSAwKSB7XG4gICAgICBvdXQucHVzaChGbG9hdDMyQXJyYXkuZnJvbShyaW5nKSk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgeHMgPSBuZXcgQXJyYXk8bnVtYmVyPihuKSxcbiAgICAgIHlzID0gbmV3IEFycmF5PG51bWJlcj4obik7XG4gICAgbGV0IHgwID0gSW5maW5pdHksXG4gICAgICB5MCA9IEluZmluaXR5LFxuICAgICAgeDEgPSAtSW5maW5pdHksXG4gICAgICB5MSA9IC1JbmZpbml0eTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgY29uc3QgeCA9IHJpbmdbMiAqIGldLFxuICAgICAgICB5ID0gcmluZ1syICogaSArIDFdO1xuICAgICAgeHNbaV0gPSB4O1xuICAgICAgeXNbaV0gPSB5O1xuICAgICAgaWYgKHggPCB4MCkgeDAgPSB4O1xuICAgICAgaWYgKHggPiB4MSkgeDEgPSB4O1xuICAgICAgaWYgKHkgPCB5MCkgeTAgPSB5O1xuICAgICAgaWYgKHkgPiB5MSkgeTEgPSB5O1xuICAgIH1cbiAgICBpZiAoTWF0aC5tYXgoeDEgLSB4MCwgeTEgLSB5MCkgPCBtaW5FeHRlbnQpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHMgPSBvcGVuID8gc2ltcGxpZnlQb2x5bGluZSh4cywgeXMsIHRvbCkgOiBzaW1wbGlmeVJpbmcoeHMsIHlzLCB0b2wpO1xuICAgIGlmIChzLnhzLmxlbmd0aCA8IG1pblZlcnRpY2VzKSBjb250aW51ZTtcbiAgICBjb25zdCBmbGF0ID0gbmV3IEZsb2F0MzJBcnJheShzLnhzLmxlbmd0aCAqIDIpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcy54cy5sZW5ndGg7IGkrKykge1xuICAgICAgZmxhdFsyICogaV0gPSBzLnhzW2ldO1xuICAgICAgZmxhdFsyICogaSArIDFdID0gcy55c1tpXTtcbiAgICB9XG4gICAgb3V0LnB1c2goZmxhdCk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLy8g4pSA4pSAIFRoZSBmZWF0dXJlIHRhYmxlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogRmVhdHVyZXMgKGFuZCB0aGVpciBzaW1wbGlmaWVkIG91dGxpbmVzKSBjYWNoZWQgcGVyIGxldmVsLCBwYXN0IHdoaWNoIHRoZSBvbGRlc3QgZ28uICovXG5jb25zdCBTSU1QTElGSUVEX0NBQ0hFX0xJTUlUID0gMjAwXzAwMDtcblxuLyoqXG4gKiBBIHBhcnNlZCBHZW9KU09OIHJlZ2lvbiBzZXQsIGluZGV4ZWQgZm9yIHRpbGVzLiBIb2xkcyB0aGUgcmF3IGZlYXR1cmVzIChmb3IgdGhlIGV4YWN0XG4gKiBnZW9tZXRyeSBhbmQgdGhlIGV4cG9ydCksIGVhY2ggZmVhdHVyZSdzIHJpbmdzLCBib3gsIHBsYW5lIGFuZCBjbGFzcywgYW5kIGJ1aWxkcyBhIGxldmVsJ3NcbiAqIHRpbGUgYnVja2V0cyB0aGUgZmlyc3QgdGltZSB0aGF0IGxldmVsIG9mIGEgcGxhbmUgaXMgYXNrZWQgZm9yLlxuICovXG5leHBvcnQgY2xhc3MgUmVnaW9uRmVhdHVyZVRhYmxlIHtcbiAgcmVhZG9ubHkgaWRzOiBzdHJpbmdbXSA9IFtdO1xuICByZWFkb25seSBsYWJlbHM6IEFycmF5PHN0cmluZyB8IG51bGw+ID0gW107XG4gIHJlYWRvbmx5IGNvbG9yczogQXJyYXk8c3RyaW5nIHwgbnVsbD4gPSBbXTtcbiAgcmVhZG9ubHkgcGxhbmVzOiBudW1iZXJbXSA9IFtdO1xuICByZWFkb25seSBib3hlczogQmJveFtdID0gW107XG4gIHJlYWRvbmx5IHJpbmdzOiBGbG9hdDY0QXJyYXlbXVtdID0gW107XG4gIHJlYWRvbmx5IG9wZW46IGJvb2xlYW5bXSA9IFtdO1xuICAvKiogUGVyIGZlYXR1cmUsIGl0cyBwYXJ0cyBhcyByaW5nIGluZGljZXMgKHRoZSBleHRlcmlvciBmaXJzdCwgdGhlbiBpdHMgaG9sZXMpLiAqL1xuICByZWFkb25seSBwYXJ0czogbnVtYmVyW11bXVtdID0gW107XG4gIHByaXZhdGUgcmVhZG9ubHkgbGFiZWxQb2ludHMgPSBuZXcgTWFwPG51bWJlciwgRmxvYXQzMkFycmF5PigpO1xuICAvKiogRWFjaCBmZWF0dXJlJ3MgYXJlYSwgd29ya2VkIG91dCB0aGUgZmlyc3QgdGltZSBpdHMgcm93IGlzIGFza2VkIGZvci4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBhcmVhcyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG4gIHByaXZhdGUgaGllcmFyY2h5PzogUmVnaW9uQ2xhc3NOb2RlW107XG4gIHByaXZhdGUgc3R5bGU/OiBSZWdpb25Tb3VyY2VTdHlsZTtcbiAgcHJpdmF0ZSByZWFkb25seSBieUlkID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBidWNrZXRzID0gbmV3IE1hcDxzdHJpbmcsIExldmVsSW5kZXg+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2ltcGxpZmllZCA9IG5ldyBNYXA8c3RyaW5nLCBGbG9hdDMyQXJyYXlbXT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBib3VuZHM6IEJib3ggfCBudWxsO1xuICBwcml2YXRlIHJlYWRvbmx5IGxldmVsczogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IHJhdzogR2VvSnNvbkZlYXR1cmVMaWtlW10sXG4gICAgcmVhZG9ubHkgdGlsZVNpemUgPSBSRUdJT05fVElMRV9TSVpFLFxuICApIHtcbiAgICBsZXQgeDAgPSBJbmZpbml0eSxcbiAgICAgIHkwID0gSW5maW5pdHksXG4gICAgICB4MSA9IC1JbmZpbml0eSxcbiAgICAgIHkxID0gLUluZmluaXR5O1xuICAgIHJhdy5mb3JFYWNoKChmZWF0dXJlLCBpKSA9PiB7XG4gICAgICBjb25zdCBvd24gPSBmZWF0dXJlSWRPZihmZWF0dXJlKTtcbiAgICAgIGxldCBpZCA9IG93bjtcbiAgICAgIGlmIChpZCA9PT0gdW5kZWZpbmVkIHx8IHRoaXMuYnlJZC5oYXMoaWQpKSB7XG4gICAgICAgIC8vIEl0cyBwb3NpdGlvbiwgdW5sZXNzIGEgZmVhdHVyZSBhbHJlYWR5IGhhcyB0aGF0IGlkIChhbiBleHBsaWNpdCBcIiMxXCIsIHNheSk6IGlkcyBhcmUgdW5pcXVlLFxuICAgICAgICAvLyBvciBhIHRha2UsIGFuIGV4Y2x1c2lvbiBvciBhbiBleHBvcnQgd291bGQgYWN0IG9uIGJvdGguXG4gICAgICAgIGlkID0gYCMke2l9YDtcbiAgICAgICAgZm9yIChsZXQgayA9IDE7IHRoaXMuYnlJZC5oYXMoaWQpOyBrKyspIGlkID0gYCMke2l9LSR7a31gO1xuICAgICAgfVxuICAgICAgdGhpcy5ieUlkLnNldChpZCwgaSk7XG4gICAgICB0aGlzLmlkcy5wdXNoKGlkKTtcbiAgICAgIGNvbnN0IHsgbGFiZWwsIGNvbG9yIH0gPSBjbGFzc2lmaWNhdGlvbk9mKGZlYXR1cmUpO1xuICAgICAgdGhpcy5sYWJlbHMucHVzaChsYWJlbCk7XG4gICAgICB0aGlzLmNvbG9ycy5wdXNoKGNvbG9yKTtcbiAgICAgIHRoaXMucGxhbmVzLnB1c2goZmVhdHVyZT8uZ2VvbWV0cnk/LnBsYW5lPy56ID8/IDApO1xuICAgICAgY29uc3QgeyByaW5ncywgb3BlbiwgcGFydHMgfSA9IHJpbmdzT2YoZmVhdHVyZSk7XG4gICAgICB0aGlzLnJpbmdzLnB1c2gocmluZ3MpO1xuICAgICAgdGhpcy5vcGVuLnB1c2gob3Blbik7XG4gICAgICB0aGlzLnBhcnRzLnB1c2gocGFydHMpO1xuICAgICAgY29uc3QgYm94ID0gcmluZ3NCb3gocmluZ3MpO1xuICAgICAgdGhpcy5ib3hlcy5wdXNoKGJveCk7XG4gICAgICBpZiAocmluZ3MubGVuZ3RoKSB7XG4gICAgICAgIHgwID0gTWF0aC5taW4oeDAsIGJveFswXSk7XG4gICAgICAgIHkwID0gTWF0aC5taW4oeTAsIGJveFsxXSk7XG4gICAgICAgIHgxID0gTWF0aC5tYXgoeDEsIGJveFsyXSk7XG4gICAgICAgIHkxID0gTWF0aC5tYXgoeTEsIGJveFszXSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5ib3VuZHMgPSB4MCA8PSB4MSA/IFt4MCwgeTAsIHgxLCB5MV0gOiBudWxsO1xuICAgIGNvbnN0IGV4dGVudCA9IHRoaXMuYm91bmRzID8gTWF0aC5tYXgoTWF0aC5hYnMoeDApLCBNYXRoLmFicyh5MCksIE1hdGguYWJzKHgxKSwgTWF0aC5hYnMoeTEpKSA6IDA7XG4gICAgdGhpcy5sZXZlbHMgPSAxICsgTWF0aC5tYXgoMCwgTWF0aC5jZWlsKE1hdGgubG9nMihNYXRoLm1heChleHRlbnQsIHRpbGVTaXplKSAvIHRpbGVTaXplKSkpO1xuICB9XG5cbiAgLyoqIFBhcnNlIGEgR2VvSlNPTiBGZWF0dXJlQ29sbGVjdGlvbiBzdHJpbmcuIFRocm93cyBvbiBpbnZhbGlkIEpTT04gb3Igbm8gYGZlYXR1cmVzYC4gKi9cbiAgc3RhdGljIGZyb21HZW9Kc29uKHRleHQ6IHN0cmluZywgdGlsZVNpemUgPSBSRUdJT05fVElMRV9TSVpFKTogUmVnaW9uRmVhdHVyZVRhYmxlIHtcbiAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHRleHQpO1xuICAgIGlmICghcGFyc2VkIHx8ICFBcnJheS5pc0FycmF5KHBhcnNlZC5mZWF0dXJlcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgR2VvSnNvbiBmaWxlOiBtdXN0IGNvbnRhaW4gdGhlICdmZWF0dXJlcycga2V5LlwiKTtcbiAgICB9XG4gICAgY29uc3QgdGFibGUgPSBuZXcgUmVnaW9uRmVhdHVyZVRhYmxlKHBhcnNlZC5mZWF0dXJlcywgdGlsZVNpemUpO1xuICAgIHRhYmxlLmRlc2NyaWJlKHBhcnNlZC5jbGFzc0hpZXJhcmNoeSwgcGFyc2VkLnN0eWxlKTtcbiAgICByZXR1cm4gdGFibGU7XG4gIH1cblxuICAvKiogQXR0YWNoIGEgY2xhc3MgaGllcmFyY2h5IGFuZCBhIHN0eWxlIGhpbnQgKGVhY2ggaWdub3JlZCB3aGVuIG5vdCB3ZWxsIGZvcm1lZCkuICovXG4gIGRlc2NyaWJlKGhpZXJhcmNoeT86IHVua25vd24sIHN0eWxlPzogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMuaGllcmFyY2h5ID0gcmVhZEhpZXJhcmNoeShoaWVyYXJjaHkpID8/IHRoaXMuaGllcmFyY2h5O1xuICAgIHRoaXMuc3R5bGUgPSByZWFkU3R5bGUoc3R5bGUpID8/IHRoaXMuc3R5bGU7XG4gIH1cblxuICAvKipcbiAgICogVGhlIG91dGxpbmVzIG9mIGV2ZXJ5IGZlYXR1cmUgb2YgdGhlc2UgY2xhc3NlcywgcGxhbmUgYnkgcGxhbmUsIHNpbXBsaWZpZWQgZm9yIGBsZXZlbGAgKHdoYXQgYVxuICAgKiAzRCByZWNvbnN0cnVjdGlvbiBvZiB0aGUgY2xhc3NlcyBzdGFja3MpLCB3aXRob3V0IHRoZSBgZXhjbHVkZWBkIGlkczogY2xvc2VkIGZlYXR1cmVzJyByaW5ncyxcbiAgICogb3BlbiBmZWF0dXJlcycgcG9seWxpbmVzIGFzIGBsaW5lc2AsIGVhY2ggcmluZyB3aXRoIGl0cyBmZWF0dXJlIChgcmluZ0dyb3Vwc2ApLiBQbGFuZXMgd2l0aG91dFxuICAgKiBvbmUgYXJlIGxlZnQgb3V0LiBgY2xhc3Nlc2AgbnVsbCByZWFkcyBldmVyeSBsYWJlbGxlZCBmZWF0dXJlLCBlYWNoIG91dGxpbmUgd2l0aCBpdHMgY2xhc3NcbiAgICogKGByaW5nTGFiZWxzYCwgYGxpbmVMYWJlbHNgKS5cbiAgICovXG4gIGNsYXNzT3V0bGluZXMoXG4gICAgY2xhc3NlczogcmVhZG9ubHkgc3RyaW5nW10gfCBudWxsLFxuICAgIGxldmVsOiBudW1iZXIsXG4gICAgZXhjbHVkZTogcmVhZG9ubHkgc3RyaW5nW10gPSBbXSxcbiAgKTogQ2xhc3NPdXRsaW5lc1tdIHtcbiAgICBjb25zdCB3YW50ZWQgPSBjbGFzc2VzID8gbmV3IFNldChjbGFzc2VzKSA6IG51bGw7XG4gICAgY29uc3Qgc2tpcCA9IG5ldyBTZXQoZXhjbHVkZSk7XG4gICAgY29uc3QgYnlQbGFuZSA9IG5ldyBNYXA8bnVtYmVyLCBDbGFzc091dGxpbmVzPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5pZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGxhYmVsID0gdGhpcy5sYWJlbHNbaV07XG4gICAgICBpZiAoIWxhYmVsIHx8ICh3YW50ZWQgJiYgIXdhbnRlZC5oYXMobGFiZWwpKSB8fCBza2lwLmhhcyh0aGlzLmlkc1tpXSkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgcmluZ3MgPSB0aGlzLnJpbmdzQXQoaSwgbGV2ZWwpO1xuICAgICAgaWYgKCFyaW5ncy5sZW5ndGgpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgeiA9IHRoaXMucGxhbmVzW2ldO1xuICAgICAgbGV0IHBsYW5lID0gYnlQbGFuZS5nZXQoeik7XG4gICAgICBpZiAoIXBsYW5lKSBieVBsYW5lLnNldCh6LCAocGxhbmUgPSB7IHosIHJpbmdzOiBbXSB9KSk7XG4gICAgICBpZiAodGhpcy5vcGVuW2ldKSB7XG4gICAgICAgIChwbGFuZS5saW5lcyA/Pz0gW10pLnB1c2goLi4ucmluZ3MpO1xuICAgICAgICBpZiAoIXdhbnRlZCkgKHBsYW5lLmxpbmVMYWJlbHMgPz89IFtdKS5wdXNoKC4uLnJpbmdzLm1hcCgoKSA9PiBsYWJlbCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGxhbmUucmluZ3MucHVzaCguLi5yaW5ncyk7XG4gICAgICAgIChwbGFuZS5yaW5nR3JvdXBzID8/PSBbXSkucHVzaCguLi5yaW5ncy5tYXAoKCkgPT4gaSkpO1xuICAgICAgICBpZiAoIXdhbnRlZCkgKHBsYW5lLnJpbmdMYWJlbHMgPz89IFtdKS5wdXNoKC4uLnJpbmdzLm1hcCgoKSA9PiBsYWJlbCkpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gQXJyYXkuZnJvbShieVBsYW5lLnZhbHVlcygpKS5zb3J0KChhLCBiKSA9PiBhLnogLSBiLnopO1xuICB9XG5cbiAgLyoqIEZlYXR1cmVzIHBlciBjbGFzcyBvbiBwbGFuZSBgemAgKG51bGw6IG9uIGV2ZXJ5IHBsYW5lKSwgd2l0aG91dCB0aGUgYGV4Y2x1ZGVgZCBpZHMuICovXG4gIGNsYXNzQ291bnRzKHo6IG51bWJlciB8IG51bGwsIGV4Y2x1ZGU6IHJlYWRvbmx5IHN0cmluZ1tdID0gW10pOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+IHtcbiAgICBjb25zdCBza2lwID0gbmV3IFNldChleGNsdWRlKTtcbiAgICBjb25zdCBjb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuaWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBsYWJlbCA9IHRoaXMubGFiZWxzW2ldO1xuICAgICAgaWYgKCh6ICE9PSBudWxsICYmIHRoaXMucGxhbmVzW2ldICE9PSB6KSB8fCAhbGFiZWwgfHwgc2tpcC5oYXModGhpcy5pZHNbaV0pKSBjb250aW51ZTtcbiAgICAgIGNvdW50c1tsYWJlbF0gPSAoY291bnRzW2xhYmVsXSA/PyAwKSArIDE7XG4gICAgfVxuICAgIHJldHVybiBjb3VudHM7XG4gIH1cblxuICBpbmZvKCk6IFJlZ2lvblNvdXJjZUluZm8ge1xuICAgIGNvbnN0IGNsYXNzQ29sb3JzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgdGhpcy5sYWJlbHMuZm9yRWFjaCgobGFiZWwsIGkpID0+IHtcbiAgICAgIGNvbnN0IGNvbG9yID0gdGhpcy5jb2xvcnNbaV07XG4gICAgICBpZiAobGFiZWwgJiYgY29sb3IgJiYgIShsYWJlbCBpbiBjbGFzc0NvbG9ycykpIGNsYXNzQ29sb3JzW2xhYmVsXSA9IGNvbG9yO1xuICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICBmZWF0dXJlQ291bnQ6IHRoaXMuaWRzLmxlbmd0aCxcbiAgICAgIGJvdW5kczogdGhpcy5ib3VuZHMsXG4gICAgICB0aWxlU2l6ZTogdGhpcy50aWxlU2l6ZSxcbiAgICAgIGxldmVsczogdGhpcy5sZXZlbHMsXG4gICAgICBwbGFuZXM6IEFycmF5LmZyb20obmV3IFNldCh0aGlzLnBsYW5lcykpLnNvcnQoKGEsIGIpID0+IGEgLSBiKSxcbiAgICAgIGNsYXNzQ29sb3JzLFxuICAgICAgLi4uKHRoaXMuaGllcmFyY2h5ID8geyBoaWVyYXJjaHk6IHRoaXMuaGllcmFyY2h5IH0gOiB7fSksXG4gICAgICAuLi4odGhpcy5zdHlsZSA/IHsgc3R5bGU6IHRoaXMuc3R5bGUgfSA6IHt9KSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIE9uZSB0aWxlIG9mIHBsYW5lIGB6YC4gKi9cbiAgdGlsZSh6OiBudW1iZXIsIGxldmVsOiBudW1iZXIsIGd4OiBudW1iZXIsIGd5OiBudW1iZXIpOiBSZWdpb25UaWxlIHtcbiAgICBjb25zdCB7IGNlbGxzLCB3aWRlIH0gPSB0aGlzLmJ1Y2tldHNGb3IoeiwgbGV2ZWwpO1xuICAgIGNvbnN0IGJ1Y2tldCA9IGNlbGxzLmdldChgJHtneH0vJHtneX1gKSA/PyBbXTtcbiAgICBjb25zdCBzaXplID0gbGV2ZWxUaWxlU2l6ZShsZXZlbCwgdGhpcy50aWxlU2l6ZSk7XG4gICAgY29uc3QgZmVhdHVyZXM6IFRpbGVGZWF0dXJlW10gPSBbXTtcbiAgICAvLyBUaGUgdGlsZSdzIGNlbGwgZmVhdHVyZXMgYW5kIHRoZSB3aWRlIG9uZXMgdGhhdCBtZWV0IGl0LCBtZXJnZWQgYmFjayBpbnRvIGZpbGUgb3JkZXIuXG4gICAgY29uc3Qgb3JkZXI6IG51bWJlcltdID0gW107XG4gICAgZm9yIChsZXQgYSA9IDAsIHcgPSAwOyBhIDwgYnVja2V0Lmxlbmd0aCB8fCB3IDwgd2lkZS5sZW5ndGg7KSB7XG4gICAgICBpZiAodyA+PSB3aWRlLmxlbmd0aCB8fCAoYSA8IGJ1Y2tldC5sZW5ndGggJiYgYnVja2V0W2FdIDwgd2lkZVt3XSkpIG9yZGVyLnB1c2goYnVja2V0W2ErK10pO1xuICAgICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IGkgPSB3aWRlW3crK107XG4gICAgICAgIGlmIChjZWxsTWVldHModGhpcy5ib3hlc1tpXSwgc2l6ZSwgZ3gsIGd5KSkgb3JkZXIucHVzaChpKTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBpIG9mIG9yZGVyKSB7XG4gICAgICBjb25zdCByaW5ncyA9IHRoaXMucmluZ3NBdChpLCBsZXZlbCk7XG4gICAgICBpZiAoIXJpbmdzLmxlbmd0aCkgY29udGludWU7XG4gICAgICBjb25zdCBsYWJlbHMgPSB0aGlzLmxhYmVsc0F0KGksIGxldmVsKTtcbiAgICAgIGZlYXR1cmVzLnB1c2goe1xuICAgICAgICBpZDogdGhpcy5pZHNbaV0sXG4gICAgICAgIGxhYmVsOiB0aGlzLmxhYmVsc1tpXSxcbiAgICAgICAgY29sb3I6IHRoaXMuY29sb3JzW2ldLFxuICAgICAgICBiYm94OiB0aGlzLmJveGVzW2ldLFxuICAgICAgICByaW5ncyxcbiAgICAgICAgb3BlbjogdGhpcy5vcGVuW2ldLFxuICAgICAgICAuLi4obGFiZWxzID8geyBsYWJlbHMgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4geyB6LCBsZXZlbCwgZ3gsIGd5LCBmZWF0dXJlcyB9O1xuICB9XG5cbiAgLyoqIFRoZSByYXcgR2VvSlNPTiBmZWF0dXJlcyB3aXRoIHRoZXNlIGlkcywgaW4gdGhlIG9yZGVyIGFza2VkICh1bmtub3duIGlkcyBza2lwcGVkKS4gKi9cbiAgZmVhdHVyZXMoaWRzOiByZWFkb25seSBzdHJpbmdbXSk6IEFycmF5PHsgaWQ6IHN0cmluZzsgZmVhdHVyZTogR2VvSnNvbkZlYXR1cmVMaWtlIH0+IHtcbiAgICBjb25zdCBvdXQ6IEFycmF5PHsgaWQ6IHN0cmluZzsgZmVhdHVyZTogR2VvSnNvbkZlYXR1cmVMaWtlIH0+ID0gW107XG4gICAgZm9yIChjb25zdCBpZCBvZiBpZHMpIHtcbiAgICAgIGNvbnN0IGkgPSB0aGlzLmJ5SWQuZ2V0KGlkKTtcbiAgICAgIGlmIChpICE9PSB1bmRlZmluZWQpIG91dC5wdXNoKHsgaWQsIGZlYXR1cmU6IHRoaXMucmF3W2ldIH0pO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqIEZlYXR1cmUgYGlgJ3MgYXJlYSBpbiBweMKyICgwIGZvciBhIHBvbHlsaW5lKS4gKi9cbiAgcHJpdmF0ZSBhcmVhT2YoaTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBsZXQgYXJlYSA9IHRoaXMuYXJlYXMuZ2V0KGkpO1xuICAgIGlmIChhcmVhID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGFyZWEgPSB0aGlzLm9wZW5baV0gPyAwIDogcmluZ3NBcmVhKHRoaXMucmluZ3NbaV0pO1xuICAgICAgdGhpcy5hcmVhcy5zZXQoaSwgYXJlYSk7XG4gICAgfVxuICAgIHJldHVybiBhcmVhO1xuICB9XG5cbiAgLyoqIEEgcGFnZSBvZiBwbGFuZSBgemAncyBmZWF0dXJlcywgaW4gZmlsZSBvcmRlci4gKi9cbiAgaW5kZXgoejogbnVtYmVyLCBxdWVyeTogUmVnaW9uSW5kZXhRdWVyeSk6IFJlZ2lvbkluZGV4UGFnZSB7XG4gICAgY29uc3QgZXhjbHVkZSA9IG5ldyBTZXQocXVlcnkuZXhjbHVkZSA/PyBbXSk7XG4gICAgY29uc3QgY2xhc3NlcyA9IHF1ZXJ5LmNsYXNzZXMgPyBuZXcgU2V0KHF1ZXJ5LmNsYXNzZXMpIDogbnVsbDtcbiAgICBjb25zdCBuZWVkbGUgPSBxdWVyeS5sYWJlbD8udHJpbSgpLnRvTG93ZXJDYXNlKCkgfHwgbnVsbDtcbiAgICBjb25zdCByb3dzOiBSZWdpb25JbmRleFJvd1tdID0gW107XG4gICAgbGV0IHRvdGFsID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuaWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy5wbGFuZXNbaV0gIT09IHogfHwgZXhjbHVkZS5oYXModGhpcy5pZHNbaV0pKSBjb250aW51ZTtcbiAgICAgIGlmIChuZWVkbGUgJiYgISh0aGlzLmxhYmVsc1tpXSA/PyAnJykudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhuZWVkbGUpKSBjb250aW51ZTtcbiAgICAgIGlmIChjbGFzc2VzICYmICFjbGFzc2VzLmhhcyh0aGlzLmxhYmVsc1tpXSA/PyAnJykpIGNvbnRpbnVlO1xuICAgICAgaWYgKHRvdGFsID49IHF1ZXJ5Lm9mZnNldCAmJiByb3dzLmxlbmd0aCA8IHF1ZXJ5LmxpbWl0KSB7XG4gICAgICAgIHJvd3MucHVzaCh7XG4gICAgICAgICAgaWQ6IHRoaXMuaWRzW2ldLFxuICAgICAgICAgIGxhYmVsOiB0aGlzLmxhYmVsc1tpXSxcbiAgICAgICAgICBjb2xvcjogdGhpcy5jb2xvcnNbaV0sXG4gICAgICAgICAgYmJveDogdGhpcy5ib3hlc1tpXSxcbiAgICAgICAgICBhcmVhOiB0aGlzLmFyZWFPZihpKSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICB0b3RhbCsrO1xuICAgIH1cbiAgICByZXR1cm4geyB0b3RhbCwgcm93cyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBzb3VyY2UgYXMgYSBHZW9KU09OIEZlYXR1cmVDb2xsZWN0aW9uIHN0cmluZywgdGhyb3VnaCB0aGUgd29ya2luZyBzZXQ6IGZlYXR1cmVzIHdob3NlXG4gICAqIGlkIGlzIGluIGBleGNsdWRlYCAodGFrZW4gZm9yIGVkaXRpbmcsIG9yIGRlbGV0ZWQpIGFyZSBsZWZ0IG91dCwgYGV4dHJhYCAodGhlIHdvcmtpbmcgc2V0J3NcbiAgICogZmVhdHVyZXMpIGFwcGVuZGVkLiBFdmVyeSBmZWF0dXJlIGtlZXBzIGFuIGBpZGA7IHRoZSBzZXQga2VlcHMgaXRzIGhpZXJhcmNoeSBhbmQgc3R5bGUuXG4gICAqL1xuICBleHBvcnRHZW9Kc29uKGV4Y2x1ZGU6IHJlYWRvbmx5IHN0cmluZ1tdLCBleHRyYTogcmVhZG9ubHkgb2JqZWN0W10pOiBzdHJpbmcge1xuICAgIGNvbnN0IHNraXAgPSBuZXcgU2V0KGV4Y2x1ZGUpO1xuICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIHRoaXMucmF3LmZvckVhY2goKGZlYXR1cmUsIGkpID0+IHtcbiAgICAgIGNvbnN0IGlkID0gdGhpcy5pZHNbaV07XG4gICAgICBpZiAoc2tpcC5oYXMoaWQpKSByZXR1cm47XG4gICAgICBwYXJ0cy5wdXNoKEpTT04uc3RyaW5naWZ5KGZlYXR1cmUuaWQgPT09IHVuZGVmaW5lZCA/IHsgdHlwZTogJ0ZlYXR1cmUnLCBpZCwgLi4uZmVhdHVyZSB9IDogZmVhdHVyZSkpO1xuICAgIH0pO1xuICAgIGZvciAoY29uc3QgZiBvZiBleHRyYSkgcGFydHMucHVzaChKU09OLnN0cmluZ2lmeShmKSk7XG4gICAgcmV0dXJuIGZlYXR1cmVDb2xsZWN0aW9uSnNvbihwYXJ0cywgdGhpcy5oaWVyYXJjaHksIHRoaXMuc3R5bGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZlYXR1cmUgYGlgJ3MgbGFiZWwgcG9pbnRzIChvbmUgcGVyIHBhcnQgd2l0aCByb29tIGZvciBhIGxhYmVsIGF0IGBsZXZlbGA6IGEgcGFydCB1bmRlciB0aGVcbiAgICogbGV2ZWwncyBtaW5pbXVtIGV4dGVudCBpcyBub3QgZHJhd24gdGhlcmUpLCBmcm9tIHRoZSBleGFjdCBnZW9tZXRyeSwgY29tcHV0ZWQgb25jZS5cbiAgICovXG4gIHByaXZhdGUgbGFiZWxzQXQoaTogbnVtYmVyLCBsZXZlbDogbnVtYmVyKTogRmxvYXQzMkFycmF5IHwgbnVsbCB7XG4gICAgaWYgKHRoaXMub3BlbltpXSB8fCAhdGhpcy5sYWJlbHNbaV0pIHJldHVybiBudWxsO1xuICAgIGxldCBwb2ludHMgPSB0aGlzLmxhYmVsUG9pbnRzLmdldChpKTtcbiAgICBpZiAoIXBvaW50cykge1xuICAgICAgY29uc3Qgb3V0OiBudW1iZXJbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBwYXJ0IG9mIHRoaXMucGFydHNbaV0pIHtcbiAgICAgICAgY29uc3QgcG9sZSA9IHBvbHlsYWJlbChwYXJ0Lm1hcCgocikgPT4gdGhpcy5yaW5nc1tpXVtyXSkpO1xuICAgICAgICBpZiAocG9sZSAmJiBwb2xlLmRpc3RhbmNlID4gMCkgb3V0LnB1c2gocG9sZS54LCBwb2xlLnksIHBvbGUuZGlzdGFuY2UpO1xuICAgICAgfVxuICAgICAgcG9pbnRzID0gRmxvYXQzMkFycmF5LmZyb20ob3V0KTtcbiAgICAgIHRoaXMubGFiZWxQb2ludHMuc2V0KGksIHBvaW50cyk7XG4gICAgfVxuICAgIGNvbnN0IG1pbiA9IGxldmVsTWluRXh0ZW50KGxldmVsKSAvIDI7XG4gICAgaWYgKCFtaW4pIHJldHVybiBwb2ludHMubGVuZ3RoID8gcG9pbnRzIDogbnVsbDtcbiAgICBjb25zdCBrZXB0OiBudW1iZXJbXSA9IFtdO1xuICAgIGZvciAobGV0IGsgPSAwOyBrICsgMiA8IHBvaW50cy5sZW5ndGg7IGsgKz0gMylcbiAgICAgIGlmIChwb2ludHNbayArIDJdID49IG1pbikga2VwdC5wdXNoKHBvaW50c1trXSwgcG9pbnRzW2sgKyAxXSwgcG9pbnRzW2sgKyAyXSk7XG4gICAgcmV0dXJuIGtlcHQubGVuZ3RoID8gRmxvYXQzMkFycmF5LmZyb20oa2VwdCkgOiBudWxsO1xuICB9XG5cbiAgLyoqIEZlYXR1cmUgYGlgJ3MgcmluZ3MgYXQgYGxldmVsYCwgc2ltcGxpZmllZCBvbmNlIGFuZCBjYWNoZWQuICovXG4gIHByaXZhdGUgcmluZ3NBdChpOiBudW1iZXIsIGxldmVsOiBudW1iZXIpOiBGbG9hdDMyQXJyYXlbXSB7XG4gICAgY29uc3Qga2V5ID0gYCR7bGV2ZWx9LyR7aX1gO1xuICAgIGxldCByaW5ncyA9IHRoaXMuc2ltcGxpZmllZC5nZXQoa2V5KTtcbiAgICBpZiAoIXJpbmdzKSB7XG4gICAgICByaW5ncyA9IHNpbXBsaWZ5UmluZ3ModGhpcy5yaW5nc1tpXSwgdGhpcy5vcGVuW2ldLCBsZXZlbCk7XG4gICAgICBpZiAodGhpcy5zaW1wbGlmaWVkLnNpemUgPj0gU0lNUExJRklFRF9DQUNIRV9MSU1JVCkge1xuICAgICAgICBjb25zdCBvbGRlc3QgPSB0aGlzLnNpbXBsaWZpZWQua2V5cygpLm5leHQoKS52YWx1ZSBhcyBzdHJpbmc7XG4gICAgICAgIHRoaXMuc2ltcGxpZmllZC5kZWxldGUob2xkZXN0KTtcbiAgICAgIH1cbiAgICAgIHRoaXMuc2ltcGxpZmllZC5zZXQoa2V5LCByaW5ncyk7XG4gICAgfVxuICAgIHJldHVybiByaW5ncztcbiAgfVxuXG4gIC8qKiBFbnRyaWVzIGluIHBsYW5lIGB6YCdzIGxldmVsLWBsZXZlbGAgaW5kZXg6IGNlbGwgbGlzdGluZ3MgcGx1cyB3aWRlIGZlYXR1cmVzICh0ZXN0cykuICovXG4gIGluZGV4RW50cmllcyh6OiBudW1iZXIsIGxldmVsOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IHsgY2VsbHMsIHdpZGUgfSA9IHRoaXMuYnVja2V0c0Zvcih6LCBsZXZlbCk7XG4gICAgbGV0IG4gPSB3aWRlLmxlbmd0aDtcbiAgICBmb3IgKGNvbnN0IGxpc3Qgb2YgY2VsbHMudmFsdWVzKCkpIG4gKz0gbGlzdC5sZW5ndGg7XG4gICAgcmV0dXJuIG47XG4gIH1cblxuICAvKipcbiAgICogUGxhbmUgYHpgJ3MgbGV2ZWwtYGxldmVsYCBpbmRleCwgYnVpbHQgb24gZmlyc3QgdXNlOiBmZWF0dXJlcyBieSB0aWxlIGNlbGwgKGBneC9neWAg4oaSIGZlYXR1cmVcbiAgICogaW5kaWNlcyksIGFuZCB0aGUgd2lkZSBvbmVzIChtb3JlIHRoYW4ge0BsaW5rIE1BWF9DRUxMU19QRVJfRkVBVFVSRX0gY2VsbHMsIG9yIHBhc3QgdGhlXG4gICAqIG51bWJlciByYW5nZSksIHRlc3RlZCBhZ2FpbnN0IGEgdGlsZSB3aGVuIGl0IGlzIGFza2VkIGZvci5cbiAgICovXG4gIHByaXZhdGUgYnVja2V0c0Zvcih6OiBudW1iZXIsIGxldmVsOiBudW1iZXIpOiBMZXZlbEluZGV4IHtcbiAgICBjb25zdCBrZXkgPSBgJHt6fS8ke2xldmVsfWA7XG4gICAgbGV0IGluZGV4ID0gdGhpcy5idWNrZXRzLmdldChrZXkpO1xuICAgIGlmIChpbmRleCkgcmV0dXJuIGluZGV4O1xuICAgIGNvbnN0IGNlbGxzID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcltdPigpO1xuICAgIGNvbnN0IHdpZGU6IG51bWJlcltdID0gW107XG4gICAgY29uc3Qgc2l6ZSA9IGxldmVsVGlsZVNpemUobGV2ZWwsIHRoaXMudGlsZVNpemUpO1xuICAgIGNvbnN0IG1pbkV4dGVudCA9IGxldmVsTWluRXh0ZW50KGxldmVsKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuaWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy5wbGFuZXNbaV0gIT09IHogfHwgIXRoaXMucmluZ3NbaV0ubGVuZ3RoKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGIgPSB0aGlzLmJveGVzW2ldO1xuICAgICAgaWYgKE1hdGgubWF4KGJbMl0gLSBiWzBdLCBiWzNdIC0gYlsxXSkgPCBtaW5FeHRlbnQpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZ3gwID0gTWF0aC5mbG9vcihiWzBdIC8gc2l6ZSksXG4gICAgICAgIGd4MSA9IE1hdGguZmxvb3IoYlsyXSAvIHNpemUpLFxuICAgICAgICBneTAgPSBNYXRoLmZsb29yKGJbMV0gLyBzaXplKSxcbiAgICAgICAgZ3kxID0gTWF0aC5mbG9vcihiWzNdIC8gc2l6ZSk7XG4gICAgICAvLyBBIGJveCB3aXRoIGEgTmFOIGNvb3JkaW5hdGUgbWVldHMgbm8gdGlsZS5cbiAgICAgIGlmIChbZ3gwLCBneDEsIGd5MCwgZ3kxXS5zb21lKE51bWJlci5pc05hTikpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgY291bnQgPSAoZ3gxIC0gZ3gwICsgMSkgKiAoZ3kxIC0gZ3kwICsgMSk7XG4gICAgICBpZiAoIShjb3VudCA8PSBNQVhfQ0VMTFNfUEVSX0ZFQVRVUkUpIHx8ICFbZ3gwLCBneDEsIGd5MCwgZ3kxXS5ldmVyeShOdW1iZXIuaXNTYWZlSW50ZWdlcikpIHtcbiAgICAgICAgd2lkZS5wdXNoKGkpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGZvciAobGV0IGd5ID0gZ3kwOyBneSA8PSBneTE7IGd5KyspIHtcbiAgICAgICAgZm9yIChsZXQgZ3ggPSBneDA7IGd4IDw9IGd4MTsgZ3grKykge1xuICAgICAgICAgIGNvbnN0IGlkID0gYCR7Z3h9LyR7Z3l9YDtcbiAgICAgICAgICBjb25zdCBsaXN0ID0gY2VsbHMuZ2V0KGlkKTtcbiAgICAgICAgICBpZiAobGlzdCkgbGlzdC5wdXNoKGkpO1xuICAgICAgICAgIGVsc2UgY2VsbHMuc2V0KGlkLCBbaV0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIGluZGV4ID0geyBjZWxscywgd2lkZSB9O1xuICAgIHRoaXMuYnVja2V0cy5zZXQoa2V5LCBpbmRleCk7XG4gICAgcmV0dXJuIGluZGV4O1xuICB9XG59XG5cbi8qKlxuICogQSBmZWF0dXJlIHNwYW5uaW5nIG1vcmUgdGlsZXMgdGhhbiB0aGlzIGlzIG5vdCBsaXN0ZWQgaW4gZWFjaCBvZiB0aGVtIGJ1dCBrZXB0IGFzaWRlIGFuZCB0ZXN0ZWRcbiAqIGFnYWluc3QgYSB0aWxlIHdoZW4gb25lIGlzIGFza2VkIGZvcjogb25lIGh1Z2UgYm94IChhbiBvdXRsaW5lIGFyb3VuZCBhIHdob2xlIHNsaWRlLCBvciBhIGNvcnJ1cHRcbiAqIGNvb3JkaW5hdGUpIG11c3Qgbm90IG1ha2UgYSBwbGFuZSdzIGluZGV4IG1pbGxpb25zIG9mIGVudHJpZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBNQVhfQ0VMTFNfUEVSX0ZFQVRVUkUgPSA2NDtcblxuLyoqIEEgcGxhbmUncyBsZXZlbDogZmVhdHVyZXMgYnkgdGlsZSBjZWxsLCBhbmQgdGhlIHdpZGUgb25lcyAoYXNjZW5kaW5nKSwgdGVzdGVkIHBlciB0aWxlLiAqL1xuaW50ZXJmYWNlIExldmVsSW5kZXgge1xuICBjZWxsczogTWFwPHN0cmluZywgbnVtYmVyW10+O1xuICB3aWRlOiBudW1iZXJbXTtcbn1cblxuLyoqIFdoZXRoZXIgYm94IGBiYCBtZWV0cyBjZWxsIChneCwgZ3kpIG9mIHRpbGVzIGBzaXplYCBwaXhlbHMgd2lkZSwgYXMgYSBjZWxsIGxpc3RzIGl0LiAqL1xuZnVuY3Rpb24gY2VsbE1lZXRzKGI6IFJlYWRvbmx5PEJib3g+LCBzaXplOiBudW1iZXIsIGd4OiBudW1iZXIsIGd5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBNYXRoLmZsb29yKGJbMF0gLyBzaXplKSA8PSBneCAmJlxuICAgIGd4IDw9IE1hdGguZmxvb3IoYlsyXSAvIHNpemUpICYmXG4gICAgTWF0aC5mbG9vcihiWzFdIC8gc2l6ZSkgPD0gZ3kgJiZcbiAgICBneSA8PSBNYXRoLmZsb29yKGJbM10gLyBzaXplKVxuICApO1xufVxuXG4vKiogQSBmZWF0dXJlJ3Mgb3duIGlkIChgaWRgLCBlbHNlIGBwcm9wZXJ0aWVzLmlkYCkgYXMgYSBzdHJpbmcuICovXG5leHBvcnQgZnVuY3Rpb24gZmVhdHVyZUlkT2YoZmVhdHVyZTogR2VvSnNvbkZlYXR1cmVMaWtlKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgaWQgPSBmZWF0dXJlPy5pZCA/PyBmZWF0dXJlPy5wcm9wZXJ0aWVzPy5pZDtcbiAgcmV0dXJuIHR5cGVvZiBpZCA9PT0gJ3N0cmluZycgfHwgdHlwZW9mIGlkID09PSAnbnVtYmVyJyA/IFN0cmluZyhpZCkgOiB1bmRlZmluZWQ7XG59XG5cbi8qKiBDbGFzcyBuYW1lIGFuZCBjb2xvdXIgZnJvbSBRdVBhdGgncyBgY2xhc3NpZmljYXRpb25gIChge25hbWUsIGNvbG9yfWAsIG9yIGEgYmFyZSBuYW1lKS4gKi9cbmZ1bmN0aW9uIGNsYXNzaWZpY2F0aW9uT2YoZmVhdHVyZTogR2VvSnNvbkZlYXR1cmVMaWtlKTogeyBsYWJlbDogc3RyaW5nIHwgbnVsbDsgY29sb3I6IHN0cmluZyB8IG51bGwgfSB7XG4gIGNvbnN0IGMgPSBmZWF0dXJlPy5wcm9wZXJ0aWVzPy5jbGFzc2lmaWNhdGlvbiBhcyB7IG5hbWU/OiBzdHJpbmc7IGNvbG9yPzogbnVtYmVyW10gfSB8IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaWYgKCFjKSByZXR1cm4geyBsYWJlbDogJ0NlbGwnLCBjb2xvcjogbnVsbCB9O1xuICBpZiAodHlwZW9mIGMgPT09ICdzdHJpbmcnKSByZXR1cm4geyBsYWJlbDogYywgY29sb3I6IG51bGwgfTtcbiAgY29uc3QgY29sb3IgPVxuICAgIEFycmF5LmlzQXJyYXkoYy5jb2xvcikgJiYgYy5jb2xvci5sZW5ndGggPj0gMyA/IHJnYlRvSGV4KFtjLmNvbG9yWzBdLCBjLmNvbG9yWzFdLCBjLmNvbG9yWzJdXSkgOiBudWxsO1xuICByZXR1cm4geyBsYWJlbDogYy5uYW1lID8/IG51bGwsIGNvbG9yIH07XG59XG5cbi8qKlxuICogQSBmZWF0dXJlJ3MgcmluZ3MsIGludGVybGVhdmVkLCB3aXRob3V0IHRoZSBjbG9zaW5nIHZlcnRleDsgd2hldGhlciBpdCBpcyBhIHBvbHlsaW5lOyBhbmQgaXRzXG4gKiBwYXJ0cyBhcyByaW5nIGluZGljZXMgKGVhY2ggcGFydCdzIGV4dGVyaW9yIGZpcnN0LCB0aGVuIGl0cyBob2xlcykuXG4gKi9cbmZ1bmN0aW9uIHJpbmdzT2YoZmVhdHVyZTogR2VvSnNvbkZlYXR1cmVMaWtlKTogeyByaW5nczogRmxvYXQ2NEFycmF5W107IG9wZW46IGJvb2xlYW47IHBhcnRzOiBudW1iZXJbXVtdIH0ge1xuICBjb25zdCBnID0gZmVhdHVyZT8uZ2VvbWV0cnk7XG4gIGNvbnN0IGNvb3JkcyA9IGc/LmNvb3JkaW5hdGVzIGFzIHVua25vd247XG4gIGlmICghZyB8fCAhQXJyYXkuaXNBcnJheShjb29yZHMpKSByZXR1cm4geyByaW5nczogW10sIG9wZW46IGZhbHNlLCBwYXJ0czogW10gfTtcbiAgY29uc3QgcG9seWdvbnMgPSAobGlzdDogbnVtYmVyW11bXVtdW10pID0+IHtcbiAgICBjb25zdCByaW5nczogRmxvYXQ2NEFycmF5W10gPSBbXTtcbiAgICBjb25zdCBwYXJ0czogbnVtYmVyW11bXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcG9seWdvbiBvZiBsaXN0KSB7XG4gICAgICBjb25zdCBwYXJ0OiBudW1iZXJbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCByIG9mIHBvbHlnb24pIHtcbiAgICAgICAgcGFydC5wdXNoKHJpbmdzLmxlbmd0aCk7XG4gICAgICAgIHJpbmdzLnB1c2goZmxhdFJpbmcociwgdHJ1ZSkpO1xuICAgICAgfVxuICAgICAgaWYgKHBhcnQubGVuZ3RoKSBwYXJ0cy5wdXNoKHBhcnQpO1xuICAgIH1cbiAgICByZXR1cm4geyByaW5ncywgb3BlbjogZmFsc2UsIHBhcnRzIH07XG4gIH07XG4gIHN3aXRjaCAoZy50eXBlKSB7XG4gICAgY2FzZSAnUG9seWdvbic6XG4gICAgICByZXR1cm4gcG9seWdvbnMoW2Nvb3JkcyBhcyBudW1iZXJbXVtdW11dKTtcbiAgICBjYXNlICdNdWx0aVBvbHlnb24nOlxuICAgICAgcmV0dXJuIHBvbHlnb25zKGNvb3JkcyBhcyBudW1iZXJbXVtdW11bXSk7XG4gICAgY2FzZSAnTGluZVN0cmluZyc6XG4gICAgICByZXR1cm4geyByaW5nczogW2ZsYXRSaW5nKGNvb3JkcyBhcyBudW1iZXJbXVtdLCBmYWxzZSldLCBvcGVuOiB0cnVlLCBwYXJ0czogW10gfTtcbiAgICBjYXNlICdNdWx0aUxpbmVTdHJpbmcnOlxuICAgICAgcmV0dXJuIHsgcmluZ3M6IChjb29yZHMgYXMgbnVtYmVyW11bXVtdKS5tYXAoKHIpID0+IGZsYXRSaW5nKHIsIGZhbHNlKSksIG9wZW46IHRydWUsIHBhcnRzOiBbXSB9O1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4geyByaW5nczogW10sIG9wZW46IGZhbHNlLCBwYXJ0czogW10gfTtcbiAgfVxufVxuXG4vKipcbiAqIEEgRmVhdHVyZUNvbGxlY3Rpb24gc3RyaW5nIG9mIGBmZWF0dXJlc2AgKGVhY2ggYSBmZWF0dXJlJ3MgSlNPTiksIHdpdGggdGhlIHNldCdzIGNsYXNzIGhpZXJhcmNoeVxuICogYW5kIHN0eWxlIGFzIGl0cyBgY2xhc3NIaWVyYXJjaHlgIGFuZCBgc3R5bGVgIG1lbWJlcnMgd2hlbiBpdCBoYXMgdGhlbTogd2hhdFxuICoge0BsaW5rIFJlZ2lvbkZlYXR1cmVUYWJsZS5mcm9tR2VvSnNvbn0gcmVhZHMgYmFjay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZlYXR1cmVDb2xsZWN0aW9uSnNvbihcbiAgZmVhdHVyZXM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBoaWVyYXJjaHk/OiByZWFkb25seSBSZWdpb25DbGFzc05vZGVbXSxcbiAgc3R5bGU/OiBSZWdpb25Tb3VyY2VTdHlsZSxcbik6IHN0cmluZyB7XG4gIGNvbnN0IGhlYWQgPSBbJ1widHlwZVwiOlwiRmVhdHVyZUNvbGxlY3Rpb25cIiddO1xuICBpZiAoaGllcmFyY2h5Py5sZW5ndGgpIGhlYWQucHVzaChgXCJjbGFzc0hpZXJhcmNoeVwiOiR7SlNPTi5zdHJpbmdpZnkoaGllcmFyY2h5KX1gKTtcbiAgaWYgKHN0eWxlKSBoZWFkLnB1c2goYFwic3R5bGVcIjoke0pTT04uc3RyaW5naWZ5KHN0eWxlKX1gKTtcbiAgcmV0dXJuIGB7JHtoZWFkLmpvaW4oJywnKX0sXCJmZWF0dXJlc1wiOlske2ZlYXR1cmVzLmpvaW4oJywnKX1dfWA7XG59XG5cbi8qKiBBIHdlbGwtZm9ybWVkIGNsYXNzIGhpZXJhcmNoeSBmcm9tIGEgZmlsZSAoY29sb3VycyBhcyBgI3JyZ2diYmAgb3IgYFtyLCBnLCBiXWApLCBlbHNlIHVuZGVmaW5lZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkSGllcmFyY2h5KHJhdzogdW5rbm93bik6IFJlZ2lvbkNsYXNzTm9kZVtdIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHJhdykpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IG91dDogUmVnaW9uQ2xhc3NOb2RlW10gPSBbXTtcbiAgZm9yIChjb25zdCBuIG9mIHJhdyBhcyBBcnJheTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4pIHtcbiAgICBpZiAoIW4gfHwgdHlwZW9mIG4ubmFtZSAhPT0gJ3N0cmluZycpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGNvbG9yID0gQXJyYXkuaXNBcnJheShuLmNvbG9yKSA/IHJnYlRvSGV4KFsrbi5jb2xvclswXSwgK24uY29sb3JbMV0sICtuLmNvbG9yWzJdXSkgOiBuLmNvbG9yO1xuICAgIG91dC5wdXNoKHtcbiAgICAgIG5hbWU6IG4ubmFtZSxcbiAgICAgIC4uLih0eXBlb2Ygbi50aXRsZSA9PT0gJ3N0cmluZycgPyB7IHRpdGxlOiBuLnRpdGxlIH0gOiB7fSksXG4gICAgICAuLi4odHlwZW9mIG4ucGFyZW50ID09PSAnc3RyaW5nJyA/IHsgcGFyZW50OiBuLnBhcmVudCB9IDoge30pLFxuICAgICAgLi4uKHR5cGVvZiBjb2xvciA9PT0gJ3N0cmluZycgPyB7IGNvbG9yIH0gOiB7fSksXG4gICAgICAuLi4odHlwZW9mIG4ub3JkZXIgPT09ICdudW1iZXInID8geyBvcmRlcjogbi5vcmRlciB9IDoge30pLFxuICAgIH0pO1xuICB9XG4gIHJldHVybiBvdXQubGVuZ3RoID8gb3V0IDogdW5kZWZpbmVkO1xufVxuXG4vKiogQSB3ZWxsLWZvcm1lZCBzdHlsZSBoaW50IGZyb20gYSBmaWxlLCBlbHNlIHVuZGVmaW5lZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkU3R5bGUocmF3OiB1bmtub3duKTogUmVnaW9uU291cmNlU3R5bGUgfCB1bmRlZmluZWQge1xuICBpZiAoIXJhdyB8fCB0eXBlb2YgcmF3ICE9PSAnb2JqZWN0JykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgciA9IHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29uc3Qgc3R5bGU6IFJlZ2lvblNvdXJjZVN0eWxlID0ge307XG4gIGlmICh0eXBlb2Ygci5maWxsT3BhY2l0eSA9PT0gJ251bWJlcicpIHN0eWxlLmZpbGxPcGFjaXR5ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMSwgci5maWxsT3BhY2l0eSkpO1xuICBpZiAodHlwZW9mIHIuc3Ryb2tlID09PSAnc3RyaW5nJykgc3R5bGUuc3Ryb2tlID0gci5zdHJva2U7XG4gIGlmICh0eXBlb2Ygci5zdHJva2VXaWR0aCA9PT0gJ251bWJlcicgJiYgci5zdHJva2VXaWR0aCA+IDApIHN0eWxlLnN0cm9rZVdpZHRoID0gci5zdHJva2VXaWR0aDtcbiAgaWYgKHR5cGVvZiByLmxhYmVscyA9PT0gJ2Jvb2xlYW4nKSBzdHlsZS5sYWJlbHMgPSByLmxhYmVscztcbiAgaWYgKHR5cGVvZiByLmhpZ2hsaWdodCA9PT0gJ3N0cmluZycpIHN0eWxlLmhpZ2hsaWdodCA9IHIuaGlnaGxpZ2h0O1xuICByZXR1cm4gT2JqZWN0LmtleXMoc3R5bGUpLmxlbmd0aCA/IHN0eWxlIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBmbGF0UmluZyhwb2ludHM6IG51bWJlcltdW10sIGNsb3NlZDogYm9vbGVhbik6IEZsb2F0NjRBcnJheSB7XG4gIGxldCBuID0gcG9pbnRzPy5sZW5ndGggPz8gMDtcbiAgaWYgKGNsb3NlZCAmJiBuID4gMSkge1xuICAgIGNvbnN0IGEgPSBwb2ludHNbMF0sXG4gICAgICBiID0gcG9pbnRzW24gLSAxXTtcbiAgICBpZiAoYVswXSA9PT0gYlswXSAmJiBhWzFdID09PSBiWzFdKSBuLS07XG4gIH1cbiAgY29uc3Qgb3V0ID0gbmV3IEZsb2F0NjRBcnJheShuICogMik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgb3V0WzIgKiBpXSA9ICtwb2ludHNbaV1bMF07XG4gICAgb3V0WzIgKiBpICsgMV0gPSArcG9pbnRzW2ldWzFdO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbmZ1bmN0aW9uIHJpbmdzQm94KHJpbmdzOiByZWFkb25seSBGbG9hdDY0QXJyYXlbXSk6IEJib3gge1xuICBsZXQgeDAgPSBJbmZpbml0eSxcbiAgICB5MCA9IEluZmluaXR5LFxuICAgIHgxID0gLUluZmluaXR5LFxuICAgIHkxID0gLUluZmluaXR5O1xuICBmb3IgKGNvbnN0IHIgb2YgcmluZ3MpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSArIDEgPCByLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICBpZiAocltpXSA8IHgwKSB4MCA9IHJbaV07XG4gICAgICBpZiAocltpXSA+IHgxKSB4MSA9IHJbaV07XG4gICAgICBpZiAocltpICsgMV0gPCB5MCkgeTAgPSByW2kgKyAxXTtcbiAgICAgIGlmIChyW2kgKyAxXSA+IHkxKSB5MSA9IHJbaSArIDFdO1xuICAgIH1cbiAgfVxuICByZXR1cm4gW3gwLCB5MCwgeDEsIHkxXTtcbn1cbiJdfQ==
|