@jax-data-science/sci-image-visualizer 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/esm2022/lib/contracts/display-types.mjs +28 -1
- package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +3 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +46 -4
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +195 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +10 -2
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +1098 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +6 -3
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +186 -10
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +2 -2
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +2 -3
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +120 -2
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +76 -1
- package/esm2022/lib/routing-visualizer.service.mjs +10 -1
- package/esm2022/lib/spatial/spatial-tiles.mjs +506 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +659 -19
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +44 -3
- package/esm2022/lib/toolbar/toolbar.component.mjs +15 -3
- package/esm2022/lib/visualizer.component.mjs +221 -7
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3238 -84
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/lib/contracts/display-types.d.ts +104 -1
- package/lib/contracts/plot-type-contribution.contract.d.ts +27 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +59 -1
- package/lib/contracts/spatial-dataset.contract.d.ts +167 -0
- package/lib/contracts/toolbar-tool.contract.d.ts +84 -5
- package/lib/contracts/visualizer.contract.d.ts +22 -1
- package/lib/implementations/napari-js/napari-navigator.d.ts +72 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +3 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +240 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +42 -2
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +26 -2
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -1
- package/lib/spatial/spatial-tiles.d.ts +222 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +234 -3
- package/lib/toolbar/brush/brush-tool.service.d.ts +21 -0
- package/lib/toolbar/toolbar.component.d.ts +11 -3
- package/lib/visualizer.component.d.ts +54 -2
- package/package.json +1 -1
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level-of-detail planning for tiled spatial geometry — cell outlines and transcripts.
|
|
3
|
+
*
|
|
4
|
+
* The renderer knows its camera (a world-space centre, a zoom in canvas pixels per world
|
|
5
|
+
* unit, a canvas size); a tiled dataset knows its grids (one per level, in observation
|
|
6
|
+
* units). This module is the bridge: which level the zoom calls for, which tiles are on
|
|
7
|
+
* screen, how big a transcript marker should be. Everything here is pure, so the policy
|
|
8
|
+
* — the part that decides whether the view is fast and legible — is testable without a
|
|
9
|
+
* GPU.
|
|
10
|
+
*
|
|
11
|
+
* Observation units map onto world units through the dataset's `imageRef` affine
|
|
12
|
+
* (`world = data · scale + translate`), so "pixels per observation unit" is
|
|
13
|
+
* `zoom · scale`. For a Xenium bundle the data unit is the micron and the world unit the
|
|
14
|
+
* morphology pixel.
|
|
15
|
+
*/
|
|
16
|
+
/** Whether cell outlines are drawn: the user's choice, else on when the dataset has any. */
|
|
17
|
+
export function cellsShown(dataset, view) {
|
|
18
|
+
const available = !!(dataset?.polygonTiles || dataset?.polygons);
|
|
19
|
+
return available && (view.showCells ?? true);
|
|
20
|
+
}
|
|
21
|
+
/** A column holding a hand-curated cell-type annotation, by naming convention. */
|
|
22
|
+
export function isCuratedColumn(name) {
|
|
23
|
+
return /curated/i.test(name);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The categorical column that names each cell's type: the view's choice when it is a
|
|
27
|
+
* column of this dataset, else the first categorical column that is not a curated
|
|
28
|
+
* annotation (a pipeline's clustering is the default; curation is opted into), else
|
|
29
|
+
* any categorical column.
|
|
30
|
+
*/
|
|
31
|
+
export function cellTypeColumnFor(dataset, view) {
|
|
32
|
+
const categorical = dataset.columns.filter((c) => c.kind === 'categorical');
|
|
33
|
+
if (view.cellTypeColumn && categorical.some((c) => c.name === view.cellTypeColumn)) {
|
|
34
|
+
return view.cellTypeColumn;
|
|
35
|
+
}
|
|
36
|
+
return (categorical.find((c) => !isCuratedColumn(c.name)) ?? categorical[0])?.name ?? null;
|
|
37
|
+
}
|
|
38
|
+
export function tileId(k) {
|
|
39
|
+
return `${k.level}/${k.gx}/${k.gy}`;
|
|
40
|
+
}
|
|
41
|
+
/** Canvas pixels per observation unit along x, for a camera zoom and a data→world affine. */
|
|
42
|
+
export function pixelsPerDataUnit(zoom, ref) {
|
|
43
|
+
return zoom * Math.abs(ref?.scale?.[0] ?? 1);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The part of observation space the camera shows, padded by `margin` (a fraction of the
|
|
47
|
+
* viewport) so tiles just off screen are already there when a pan brings them in.
|
|
48
|
+
*/
|
|
49
|
+
export function visibleDataRect(center, zoom, canvasW, canvasH, ref, margin = 0.15) {
|
|
50
|
+
if (!(zoom > 0) || !(canvasW > 0) || !(canvasH > 0))
|
|
51
|
+
return null;
|
|
52
|
+
const sx = ref?.scale?.[0] ?? 1;
|
|
53
|
+
const sy = ref?.scale?.[1] ?? 1;
|
|
54
|
+
const tx = ref?.translate?.[0] ?? 0;
|
|
55
|
+
const ty = ref?.translate?.[1] ?? 0;
|
|
56
|
+
const halfW = (canvasW / zoom / 2) * (1 + 2 * margin);
|
|
57
|
+
const halfH = (canvasH / zoom / 2) * (1 + 2 * margin);
|
|
58
|
+
const wx0 = center[0] - halfW;
|
|
59
|
+
const wx1 = center[0] + halfW;
|
|
60
|
+
const wy0 = center[1] - halfH;
|
|
61
|
+
const wy1 = center[1] + halfH;
|
|
62
|
+
const ax = (wx0 - tx) / sx;
|
|
63
|
+
const bx = (wx1 - tx) / sx;
|
|
64
|
+
const ay = (wy0 - ty) / sy;
|
|
65
|
+
const by = (wy1 - ty) / sy;
|
|
66
|
+
return { x0: Math.min(ax, bx), y0: Math.min(ay, by), x1: Math.max(ax, bx), y1: Math.max(ay, by) };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Tiles of one level intersecting `rect`, clipped to the dataset's `bounds` (so zooming
|
|
70
|
+
* out over empty canvas does not ask for tiles that cannot exist). Ordered from the
|
|
71
|
+
* rectangle's centre outward, so the middle of the screen fills in first.
|
|
72
|
+
*/
|
|
73
|
+
export function tilesInRect(rect, level, levels, bounds, limit = Infinity) {
|
|
74
|
+
const size = levels[level]?.tileSize;
|
|
75
|
+
if (!(size > 0))
|
|
76
|
+
return [];
|
|
77
|
+
let { x0, y0, x1, y1 } = rect;
|
|
78
|
+
if (bounds) {
|
|
79
|
+
x0 = Math.max(x0, bounds[0]);
|
|
80
|
+
y0 = Math.max(y0, bounds[1]);
|
|
81
|
+
x1 = Math.min(x1, bounds[2]);
|
|
82
|
+
y1 = Math.min(y1, bounds[3]);
|
|
83
|
+
if (x1 < x0 || y1 < y0)
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const gx0 = Math.floor(x0 / size);
|
|
87
|
+
const gx1 = Math.floor(x1 / size);
|
|
88
|
+
const gy0 = Math.floor(y0 / size);
|
|
89
|
+
const gy1 = Math.floor(y1 / size);
|
|
90
|
+
const cx = (rect.x0 + rect.x1) / 2 / size;
|
|
91
|
+
const cy = (rect.y0 + rect.y1) / 2 / size;
|
|
92
|
+
const out = [];
|
|
93
|
+
for (let gy = gy0; gy <= gy1; gy++) {
|
|
94
|
+
for (let gx = gx0; gx <= gx1; gx++)
|
|
95
|
+
out.push({ level, gx, gy });
|
|
96
|
+
}
|
|
97
|
+
out.sort((a, b) => ((a.gx + 0.5 - cx) ** 2 + (a.gy + 0.5 - cy) ** 2)
|
|
98
|
+
- ((b.gx + 0.5 - cx) ** 2 + (b.gy + 0.5 - cy) ** 2));
|
|
99
|
+
return out.length > limit ? out.slice(0, limit) : out;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Typical cell diameter, in observation units, used to judge how large cells appear.
|
|
103
|
+
* Derived from the per-observation radius when there is one; 12 µm otherwise.
|
|
104
|
+
*/
|
|
105
|
+
export function typicalCellDiameter(radius, fallback = 12) {
|
|
106
|
+
if (typeof radius === 'number')
|
|
107
|
+
return radius > 0 ? radius * 2 : fallback;
|
|
108
|
+
if (!radius?.length)
|
|
109
|
+
return fallback;
|
|
110
|
+
// The median of a sample is plenty — this sets a threshold, not a measurement.
|
|
111
|
+
const step = Math.max(1, Math.floor(radius.length / 2048));
|
|
112
|
+
const sample = [];
|
|
113
|
+
for (let i = 0; i < radius.length; i += step) {
|
|
114
|
+
if (radius[i] > 0)
|
|
115
|
+
sample.push(radius[i]);
|
|
116
|
+
}
|
|
117
|
+
if (!sample.length)
|
|
118
|
+
return fallback;
|
|
119
|
+
sample.sort((a, b) => a - b);
|
|
120
|
+
return sample[sample.length >> 1] * 2;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* On-screen cell diameter (px) at or above which each polygon level is used. A level
|
|
124
|
+
* halves the vertices of the one below, so each should take over when the cell is about
|
|
125
|
+
* half as large on screen. Below the last finite threshold outlines are not drawn at
|
|
126
|
+
* all — a cell a few pixels wide is a dot, and the observation markers already draw it
|
|
127
|
+
* as one.
|
|
128
|
+
*
|
|
129
|
+
* Xenium's fourth level (3 vertices per cell) is deliberately never used: seen on
|
|
130
|
+
* screen it is a field of triangles, which reads as an artefact rather than as cells.
|
|
131
|
+
* The dots below 8 px say the same thing more honestly.
|
|
132
|
+
*/
|
|
133
|
+
export const POLYGON_LEVEL_MIN_CELL_PX = [36, 18, 8, Infinity];
|
|
134
|
+
/**
|
|
135
|
+
* Which polygon level suits this zoom, or -1 for "too small to outline".
|
|
136
|
+
* `detail` > 1 prefers finer levels (sharper, slower); < 1 coarser.
|
|
137
|
+
*/
|
|
138
|
+
export function polygonLevelFor(pxPerUnit, cellDiameter, levelCount, detail = 1) {
|
|
139
|
+
const cellPx = pxPerUnit * cellDiameter * detail;
|
|
140
|
+
const table = POLYGON_LEVEL_MIN_CELL_PX;
|
|
141
|
+
for (let l = 0; l < levelCount; l++) {
|
|
142
|
+
// Past the table, keep halving: each level still halves the vertices.
|
|
143
|
+
const min = table[l] ?? table[table.length - 1] / 2 ** (l - table.length + 1);
|
|
144
|
+
if (cellPx >= min)
|
|
145
|
+
return l;
|
|
146
|
+
}
|
|
147
|
+
return -1;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Which transcript level suits this zoom: the one whose tiles come out closest to
|
|
151
|
+
* `targetTilePx` on screen. Coarser levels aggregate more, so this keeps the number of
|
|
152
|
+
* markers per screen roughly constant however far out the camera is — the property that
|
|
153
|
+
* keeps the view fast.
|
|
154
|
+
*/
|
|
155
|
+
export function transcriptLevelFor(pxPerUnit, levels, targetTilePx = 512) {
|
|
156
|
+
if (!levels.length || !(pxPerUnit > 0))
|
|
157
|
+
return 0;
|
|
158
|
+
let best = 0;
|
|
159
|
+
let bestErr = Infinity;
|
|
160
|
+
for (let l = 0; l < levels.length; l++) {
|
|
161
|
+
const err = Math.abs(Math.log2((levels[l].tileSize * pxPerUnit) / targetTilePx));
|
|
162
|
+
if (err < bestErr) {
|
|
163
|
+
bestErr = err;
|
|
164
|
+
best = l;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return best;
|
|
168
|
+
}
|
|
169
|
+
/** Smallest and largest transcript marker, in canvas pixels. */
|
|
170
|
+
export const TRANSCRIPT_MIN_PX = 4;
|
|
171
|
+
export const TRANSCRIPT_MAX_PX = 32;
|
|
172
|
+
/**
|
|
173
|
+
* Physical diameter a single transcript is drawn at, in µm — clearly larger than the
|
|
174
|
+
* imaged spot (~0.3 µm) so it stays legible, and small enough that neighbouring
|
|
175
|
+
* molecules inside one cell stay apart.
|
|
176
|
+
*/
|
|
177
|
+
export const TRANSCRIPT_PHYSICAL_UM = 1.2;
|
|
178
|
+
/**
|
|
179
|
+
* Marker diameter in canvas pixels for an entry standing for `weight` transcripts.
|
|
180
|
+
*
|
|
181
|
+
* The convention spatial viewers share (deck.gl's `radiusMinPixels`/`radiusMaxPixels`,
|
|
182
|
+
* Xenium Explorer's transcript size): a PHYSICAL size, clamped to a screen-pixel range.
|
|
183
|
+
* Zoomed out, markers sit at the minimum and never vanish; zoomed in, they grow with the
|
|
184
|
+
* tissue instead of shrinking to specks next to cells hundreds of pixels wide. A fixed
|
|
185
|
+
* screen size does the opposite at high zoom, which is what made transcripts disappear
|
|
186
|
+
* at pixel-level zoom.
|
|
187
|
+
*
|
|
188
|
+
* Aggregates grow with the cube root of their count: area ∝ count would let one dense
|
|
189
|
+
* aggregate swallow its neighbours, the cube root keeps a 1000-transcript cluster clearly
|
|
190
|
+
* larger than a 10-transcript one without covering the tile.
|
|
191
|
+
*
|
|
192
|
+
* `pxPerMicron` is omitted for data with no known physical unit; the marker is then
|
|
193
|
+
* screen-sized only.
|
|
194
|
+
*/
|
|
195
|
+
export function transcriptMarkerPx(weight, scale = 1, pxPerMicron) {
|
|
196
|
+
const counted = TRANSCRIPT_MIN_PX * Math.cbrt(Math.max(1, weight));
|
|
197
|
+
const physical = pxPerMicron ? TRANSCRIPT_PHYSICAL_UM * pxPerMicron : 0;
|
|
198
|
+
const px = Math.max(counted, physical) * scale;
|
|
199
|
+
return Math.min(TRANSCRIPT_MAX_PX * Math.max(scale, 1), Math.max(TRANSCRIPT_MIN_PX * scale, px));
|
|
200
|
+
}
|
|
201
|
+
// ── Glyphs ────────────────────────────────────────────────────────────────────────────
|
|
202
|
+
/** Marker shapes for the transcript "icon" mode. All star-convex, so a fan fills them. */
|
|
203
|
+
export const TRANSCRIPT_GLYPHS = [
|
|
204
|
+
'circle', 'star', 'triangle', 'square', 'diamond', 'cross', 'hexagon', 'triangle-down',
|
|
205
|
+
'pentagon', 'x',
|
|
206
|
+
];
|
|
207
|
+
// The view state names glyphs without importing this module; keep the two in step.
|
|
208
|
+
const _glyphNamesMatch = true;
|
|
209
|
+
void _glyphNamesMatch;
|
|
210
|
+
/** Unit outline of a glyph, radius ≈ 1, centred on the origin, as `[x0, y0, x1, y1, …]`. */
|
|
211
|
+
export function glyphOutline(glyph) {
|
|
212
|
+
const poly = (n, rot = -Math.PI / 2, r = 1) => {
|
|
213
|
+
const out = new Float32Array(n * 2);
|
|
214
|
+
for (let i = 0; i < n; i++) {
|
|
215
|
+
const a = rot + (i * 2 * Math.PI) / n;
|
|
216
|
+
out[2 * i] = Math.cos(a) * r;
|
|
217
|
+
out[2 * i + 1] = Math.sin(a) * r;
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
};
|
|
221
|
+
const star = (points, inner, rot = -Math.PI / 2) => {
|
|
222
|
+
const out = new Float32Array(points * 4);
|
|
223
|
+
for (let i = 0; i < points * 2; i++) {
|
|
224
|
+
const a = rot + (i * Math.PI) / points;
|
|
225
|
+
const r = i % 2 === 0 ? 1 : inner;
|
|
226
|
+
out[2 * i] = Math.cos(a) * r;
|
|
227
|
+
out[2 * i + 1] = Math.sin(a) * r;
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
};
|
|
231
|
+
// A plus built as a 12-gon: arms of half-width w.
|
|
232
|
+
const plus = (w, rotate) => {
|
|
233
|
+
const pts = [
|
|
234
|
+
[w, -1], [w, -w], [1, -w], [1, w], [w, w], [w, 1],
|
|
235
|
+
[-w, 1], [-w, w], [-1, w], [-1, -w], [-w, -w], [-w, -1],
|
|
236
|
+
];
|
|
237
|
+
const out = new Float32Array(pts.length * 2);
|
|
238
|
+
const c = Math.SQRT1_2;
|
|
239
|
+
pts.forEach(([x, y], i) => {
|
|
240
|
+
out[2 * i] = rotate ? (x - y) * c : x;
|
|
241
|
+
out[2 * i + 1] = rotate ? (x + y) * c : y;
|
|
242
|
+
});
|
|
243
|
+
return out;
|
|
244
|
+
};
|
|
245
|
+
switch (glyph) {
|
|
246
|
+
case 'circle': return poly(12);
|
|
247
|
+
case 'star': return star(5, 0.45);
|
|
248
|
+
case 'triangle': return poly(3);
|
|
249
|
+
case 'triangle-down': return poly(3, Math.PI / 2);
|
|
250
|
+
case 'square': return poly(4, Math.PI / 4, Math.SQRT2 * 0.8);
|
|
251
|
+
case 'diamond': return poly(4, -Math.PI / 2);
|
|
252
|
+
case 'hexagon': return poly(6, 0);
|
|
253
|
+
case 'pentagon': return poly(5);
|
|
254
|
+
case 'cross': return plus(0.32, false);
|
|
255
|
+
case 'x': return plus(0.28, true);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** The glyph a gene gets by default: by its position in the selected list. */
|
|
259
|
+
export function defaultGlyphFor(slot) {
|
|
260
|
+
return TRANSCRIPT_GLYPHS[slot % TRANSCRIPT_GLYPHS.length];
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Expand point markers into glyph rings for a shapes layer: entry `i` becomes a copy of
|
|
264
|
+
* `glyphs[gene[i]]` scaled to `radius[i]` and centred on `(x[i], y[i])`.
|
|
265
|
+
*/
|
|
266
|
+
export function glyphRings(x, y, radius, glyphOf) {
|
|
267
|
+
const n = x.length;
|
|
268
|
+
const offsets = new Uint32Array(n + 1);
|
|
269
|
+
let total = 0;
|
|
270
|
+
for (let i = 0; i < n; i++) {
|
|
271
|
+
offsets[i] = total;
|
|
272
|
+
total += glyphOf(i).length / 2;
|
|
273
|
+
}
|
|
274
|
+
offsets[n] = total;
|
|
275
|
+
const coords = new Float32Array(total * 2);
|
|
276
|
+
for (let i = 0; i < n; i++) {
|
|
277
|
+
const g = glyphOf(i);
|
|
278
|
+
const r = radius[i];
|
|
279
|
+
let o = offsets[i] * 2;
|
|
280
|
+
for (let k = 0; k < g.length; k += 2) {
|
|
281
|
+
coords[o++] = x[i] + g[k] * r;
|
|
282
|
+
coords[o++] = y[i] + g[k + 1] * r;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return { coords, offsets };
|
|
286
|
+
}
|
|
287
|
+
// ── Discrete colouring through a colormap ─────────────────────────────────────────────
|
|
288
|
+
/**
|
|
289
|
+
* A shapes layer colours through a colormap LUT, not per-shape RGBA. A categorical
|
|
290
|
+
* palette becomes a piecewise-constant colormap: category `c` of `n` owns the band
|
|
291
|
+
* `[c/n, (c+1)/n)`, and a shape takes the value at its band's centre, so the LUT's
|
|
292
|
+
* linear filtering never blends two categories.
|
|
293
|
+
*
|
|
294
|
+
* Returns the stops (linear 0..1 RGB) and a function mapping a category code to the
|
|
295
|
+
* value to hand the layer. `missing` is the colour of the extra band used for "no
|
|
296
|
+
* category".
|
|
297
|
+
*/
|
|
298
|
+
export function discreteColormapStops(rgb, missing) {
|
|
299
|
+
const bands = [...rgb, missing];
|
|
300
|
+
const n = bands.length;
|
|
301
|
+
const stops = [];
|
|
302
|
+
const eps = 1e-6;
|
|
303
|
+
bands.forEach((c, i) => {
|
|
304
|
+
const color = [c[0] / 255, c[1] / 255, c[2] / 255];
|
|
305
|
+
stops.push({ t: i / n + (i === 0 ? 0 : eps), color });
|
|
306
|
+
stops.push({ t: (i + 1) / n - (i === n - 1 ? 0 : eps), color });
|
|
307
|
+
});
|
|
308
|
+
const missingCode = n - 1;
|
|
309
|
+
return {
|
|
310
|
+
stops,
|
|
311
|
+
valueOf: (code) => ((code < 0 || code >= missingCode ? missingCode : code) + 0.5) / n,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// ── Density raster ────────────────────────────────────────────────────────────────────
|
|
315
|
+
/**
|
|
316
|
+
* Separable Gaussian blur of a row-major raster, `sigma` in raster cells.
|
|
317
|
+
*
|
|
318
|
+
* A per-gene count raster at 10 µm is mostly zeros and ones — drawn as-is it is speckle,
|
|
319
|
+
* not a density. A σ of one to two cells (10–20 µm, about a cell diameter) turns it into
|
|
320
|
+
* a field that reads as territory while keeping structures a few cells wide.
|
|
321
|
+
*/
|
|
322
|
+
export function smoothRaster(values, rows, cols, sigma) {
|
|
323
|
+
if (!(sigma > 0))
|
|
324
|
+
return values.slice();
|
|
325
|
+
const r = Math.max(1, Math.ceil(sigma * 3));
|
|
326
|
+
const kernel = new Float32Array(2 * r + 1);
|
|
327
|
+
let sum = 0;
|
|
328
|
+
for (let i = -r; i <= r; i++)
|
|
329
|
+
sum += (kernel[i + r] = Math.exp(-(i * i) / (2 * sigma * sigma)));
|
|
330
|
+
for (let i = 0; i < kernel.length; i++)
|
|
331
|
+
kernel[i] /= sum;
|
|
332
|
+
const tmp = new Float32Array(values.length);
|
|
333
|
+
const out = new Float32Array(values.length);
|
|
334
|
+
for (let y = 0; y < rows; y++) {
|
|
335
|
+
const row = y * cols;
|
|
336
|
+
for (let x = 0; x < cols; x++) {
|
|
337
|
+
let acc = 0;
|
|
338
|
+
for (let k = -r; k <= r; k++) {
|
|
339
|
+
const xx = x + k;
|
|
340
|
+
if (xx >= 0 && xx < cols)
|
|
341
|
+
acc += values[row + xx] * kernel[k + r];
|
|
342
|
+
}
|
|
343
|
+
tmp[row + x] = acc;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
for (let y = 0; y < rows; y++) {
|
|
347
|
+
for (let x = 0; x < cols; x++) {
|
|
348
|
+
let acc = 0;
|
|
349
|
+
for (let k = -r; k <= r; k++) {
|
|
350
|
+
const yy = y + k;
|
|
351
|
+
if (yy >= 0 && yy < rows)
|
|
352
|
+
acc += tmp[yy * cols + x] * kernel[k + r];
|
|
353
|
+
}
|
|
354
|
+
out[y * cols + x] = acc;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Colour a density raster as RGBA bytes: log-scaled, windowed at a high percentile of the
|
|
361
|
+
* non-zero values, and faded in from transparent so empty tissue shows what is under it.
|
|
362
|
+
*/
|
|
363
|
+
export function colorDensity(values, lut, opacity, { log = true, percentile = 0.995 } = {}) {
|
|
364
|
+
const n = values.length;
|
|
365
|
+
const t = log ? values.map((v) => Math.log1p(Math.max(0, v))) : values;
|
|
366
|
+
const positive = [];
|
|
367
|
+
for (let i = 0; i < n; i++)
|
|
368
|
+
if (t[i] > 0)
|
|
369
|
+
positive.push(t[i]);
|
|
370
|
+
positive.sort((a, b) => a - b);
|
|
371
|
+
const at = Math.min(positive.length - 1, Math.floor(percentile * positive.length));
|
|
372
|
+
const hi = positive.length ? positive[at] : 1;
|
|
373
|
+
const rgba = new Uint8Array(n * 4);
|
|
374
|
+
for (let i = 0; i < n; i++) {
|
|
375
|
+
const f = Math.min(1, t[i] / (hi || 1));
|
|
376
|
+
if (f < 0.02)
|
|
377
|
+
continue;
|
|
378
|
+
const c = lut[Math.min(lut.length - 1, Math.round(f * (lut.length - 1)))];
|
|
379
|
+
rgba[4 * i] = c[0];
|
|
380
|
+
rgba[4 * i + 1] = c[1];
|
|
381
|
+
rgba[4 * i + 2] = c[2];
|
|
382
|
+
rgba[4 * i + 3] = Math.round(255 * opacity * Math.pow(f, 0.6));
|
|
383
|
+
}
|
|
384
|
+
return rgba;
|
|
385
|
+
}
|
|
386
|
+
// ── All-gene transcripts: grouping under a marker budget ─────────────────────────────
|
|
387
|
+
/** Smallest on-screen spacing between groups, in px — below it groups read as noise. */
|
|
388
|
+
export const GROUP_MIN_SPACING_PX = 14;
|
|
389
|
+
/** Area of `rect` inside `bounds` (the whole rect when there are none). */
|
|
390
|
+
export function visibleArea(rect, bounds) {
|
|
391
|
+
const x0 = bounds ? Math.max(rect.x0, bounds[0]) : rect.x0;
|
|
392
|
+
const y0 = bounds ? Math.max(rect.y0, bounds[1]) : rect.y0;
|
|
393
|
+
const x1 = bounds ? Math.min(rect.x1, bounds[2]) : rect.x1;
|
|
394
|
+
const y1 = bounds ? Math.min(rect.y1, bounds[3]) : rect.y1;
|
|
395
|
+
return Math.max(0, x1 - x0) * Math.max(0, y1 - y0);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* How to draw every transcript in view without exceeding `budget` markers.
|
|
399
|
+
*
|
|
400
|
+
* - The transcripts themselves, once the estimated count in view fits the budget.
|
|
401
|
+
* - Otherwise the finest pyramid level whose bins are at least `minSpacingPx` apart on
|
|
402
|
+
* screen and number no more than the budget — groups big enough to read, few enough
|
|
403
|
+
* to draw.
|
|
404
|
+
*
|
|
405
|
+
* The count in view is estimated from the average density, which over- or under-shoots
|
|
406
|
+
* locally; the renderer still caps what it draws, so an estimate is enough to choose.
|
|
407
|
+
*/
|
|
408
|
+
export function allGenesPlan(o) {
|
|
409
|
+
const area = visibleArea(o.rect, o.bounds);
|
|
410
|
+
if (!(area > 0))
|
|
411
|
+
return { kind: 'none' };
|
|
412
|
+
const b = o.bounds;
|
|
413
|
+
const density = o.total / Math.max(1, (b[2] - b[0]) * (b[3] - b[1]));
|
|
414
|
+
if (o.canIndividual && density * area <= o.budget)
|
|
415
|
+
return { kind: 'individual' };
|
|
416
|
+
if (!o.levels.length)
|
|
417
|
+
return { kind: 'none' };
|
|
418
|
+
const spacing = o.minSpacingPx ?? GROUP_MIN_SPACING_PX;
|
|
419
|
+
for (let l = 0; l < o.levels.length; l++) {
|
|
420
|
+
const bin = o.levels[l].binSize;
|
|
421
|
+
// Tissue rarely fills the view; 0.7 of the bins occupied is a fair guess.
|
|
422
|
+
if (bin * o.pxPerUnit >= spacing && (area / (bin * bin)) * 0.7 <= o.budget) {
|
|
423
|
+
return { kind: 'bins', level: l };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return { kind: 'bins', level: o.levels.length - 1 };
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Diameter in px of a group of `count` transcripts in a bin `binPx` wide, where
|
|
430
|
+
* `refCount` is a typical busy bin in view (its 95th percentile).
|
|
431
|
+
*
|
|
432
|
+
* Area grows with the count — a bin with a quarter of the transcripts gets half the
|
|
433
|
+
* diameter — between a third of the bin (so a sparse bin is still visible) and a little
|
|
434
|
+
* over the full bin (so dense neighbours just touch rather than pile up).
|
|
435
|
+
*/
|
|
436
|
+
export function groupedMarkerPx(count, refCount, binPx, scale = 1) {
|
|
437
|
+
const f = Math.sqrt(Math.min(1, count / Math.max(1, refCount)));
|
|
438
|
+
const d = binPx * (0.35 + 0.75 * f) * scale;
|
|
439
|
+
return Math.max(TRANSCRIPT_MIN_PX * scale, Math.min(d, binPx * 1.2 * Math.max(scale, 1)));
|
|
440
|
+
}
|
|
441
|
+
/** The `p` quantile (0..1) of a count vector — a sample of it for large vectors. */
|
|
442
|
+
export function quantileOf(values, p) {
|
|
443
|
+
const n = values.length;
|
|
444
|
+
if (!n)
|
|
445
|
+
return 0;
|
|
446
|
+
const step = Math.max(1, Math.floor(n / 4096));
|
|
447
|
+
const sample = [];
|
|
448
|
+
for (let i = 0; i < n; i += step)
|
|
449
|
+
sample.push(values[i]);
|
|
450
|
+
sample.sort((a, b) => a - b);
|
|
451
|
+
return sample[Math.min(sample.length - 1, Math.floor(p * sample.length))];
|
|
452
|
+
}
|
|
453
|
+
/** {@link tilesInRect} for a grid whose tile (0, 0) starts at `origin`. */
|
|
454
|
+
export function tilesInRectFrom(origin, rect, level, levels, bounds, limit = Infinity) {
|
|
455
|
+
const [ox, oy] = origin;
|
|
456
|
+
const shifted = { x0: rect.x0 - ox, y0: rect.y0 - oy, x1: rect.x1 - ox, y1: rect.y1 - oy };
|
|
457
|
+
const b = bounds ? [bounds[0] - ox, bounds[1] - oy, bounds[2] - ox, bounds[3] - oy] : null;
|
|
458
|
+
return tilesInRect(shifted, level, levels, b, limit);
|
|
459
|
+
}
|
|
460
|
+
/** A density window from the non-empty bins: 1st to 99th percentile. */
|
|
461
|
+
export function densityAutoRange(values) {
|
|
462
|
+
const positive = [];
|
|
463
|
+
for (let i = 0; i < values.length; i++)
|
|
464
|
+
if (values[i] > 0)
|
|
465
|
+
positive.push(values[i]);
|
|
466
|
+
if (!positive.length)
|
|
467
|
+
return [0, 1];
|
|
468
|
+
positive.sort((a, b) => a - b);
|
|
469
|
+
const at = (p) => positive[Math.min(positive.length - 1, Math.floor(p * positive.length))];
|
|
470
|
+
const lo = at(0.01);
|
|
471
|
+
const hi = at(0.99);
|
|
472
|
+
return hi > lo ? [lo, hi] : [0, hi || 1];
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Colour density bins through `lut` over the window `[lo, hi]` — Xenium Explorer's
|
|
476
|
+
* "scale threshold". Bins at or below `lo` are transparent, so empty tissue shows the
|
|
477
|
+
* image under it; bins at or above `hi` saturate.
|
|
478
|
+
*/
|
|
479
|
+
export function colorDensityWindow(values, lut, opacity, lo, hi) {
|
|
480
|
+
const n = values.length;
|
|
481
|
+
const rgba = new Uint8Array(n * 4);
|
|
482
|
+
const span = hi > lo ? hi - lo : 1;
|
|
483
|
+
const a = Math.round(255 * opacity);
|
|
484
|
+
for (let i = 0; i < n; i++) {
|
|
485
|
+
const v = values[i];
|
|
486
|
+
if (!(v > lo))
|
|
487
|
+
continue;
|
|
488
|
+
const f = Math.min(1, (v - lo) / span);
|
|
489
|
+
const c = lut[Math.min(lut.length - 1, Math.round(f * (lut.length - 1)))];
|
|
490
|
+
rgba[4 * i] = c[0];
|
|
491
|
+
rgba[4 * i + 1] = c[1];
|
|
492
|
+
rgba[4 * i + 2] = c[2];
|
|
493
|
+
rgba[4 * i + 3] = a;
|
|
494
|
+
}
|
|
495
|
+
return rgba;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Inferno (matplotlib), as an inline `[stop, colour]` scale: the density map's default,
|
|
499
|
+
* as in Xenium Explorer. Inline because the colormap tree's `INFERNO_LUT` key is resolved
|
|
500
|
+
* at runtime by the store, which the renderer does not see.
|
|
501
|
+
*/
|
|
502
|
+
export const INFERNO_SCALE = [
|
|
503
|
+
[0, '#000004'], [0.125, '#1b0c41'], [0.25, '#4a0c6b'], [0.375, '#781c6d'], [0.5, '#a52c60'],
|
|
504
|
+
[0.625, '#cf4446'], [0.75, '#ed6925'], [0.875, '#fb9b06'], [1, '#fcffa4'],
|
|
505
|
+
];
|
|
506
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC10aWxlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC9zcGF0aWFsLXRpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBdUJILDRGQUE0RjtBQUM1RixNQUFNLFVBQVUsVUFBVSxDQUN4QixPQUFpRSxFQUNqRSxJQUF5QztJQUV6QyxNQUFNLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsWUFBWSxJQUFJLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNqRSxPQUFPLFNBQVMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLENBQUM7QUFDL0MsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixNQUFNLFVBQVUsZUFBZSxDQUFDLElBQVk7SUFDMUMsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQy9CLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FDL0IsT0FBdUIsRUFBRSxJQUE4QztJQUV2RSxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxhQUFhLENBQUMsQ0FBQztJQUM1RSxJQUFJLElBQUksQ0FBQyxjQUFjLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztRQUNuRixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDN0IsQ0FBQztJQUNELE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLElBQUksSUFBSSxDQUFDO0FBQzdGLENBQUM7QUFFRCxNQUFNLFVBQVUsTUFBTSxDQUFDLENBQVU7SUFDL0IsT0FBTyxHQUFHLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7QUFDdEMsQ0FBQztBQUVELDZGQUE2RjtBQUM3RixNQUFNLFVBQVUsaUJBQWlCLENBQUMsSUFBWSxFQUFFLEdBQTRCO0lBQzFFLE9BQU8sSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUM3QixNQUFpQyxFQUFFLElBQVksRUFBRSxPQUFlLEVBQUUsT0FBZSxFQUNqRixHQUE0QixFQUFFLE1BQU0sR0FBRyxJQUFJO0lBRTNDLElBQUksQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDakUsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxNQUFNLEVBQUUsR0FBRyxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sRUFBRSxHQUFHLEdBQUcsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEMsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQyxNQUFNLEtBQUssR0FBRyxDQUFDLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELE1BQU0sS0FBSyxHQUFHLENBQUMsT0FBTyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUM7SUFDdEQsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUM5QixNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzlCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDOUIsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUM5QixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDM0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzNCLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMzQixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDM0IsT0FBTyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDO0FBQ3BHLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FDekIsSUFBYyxFQUFFLEtBQWEsRUFBRSxNQUFtQyxFQUNsRSxNQUE2QixFQUFFLEtBQUssR0FBRyxRQUFRO0lBRS9DLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxRQUFRLENBQUM7SUFDckMsSUFBSSxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztRQUFFLE9BQU8sRUFBRSxDQUFDO0lBQzNCLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDOUIsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3QixFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0IsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3QixJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUU7WUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBQ0QsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQzFDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztJQUMxQyxNQUFNLEdBQUcsR0FBYyxFQUFFLENBQUM7SUFDMUIsS0FBSyxJQUFJLEVBQUUsR0FBRyxHQUFHLEVBQUUsRUFBRSxJQUFJLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ25DLEtBQUssSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxFQUFFO1lBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7VUFDaEUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkQsT0FBTyxHQUFHLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUs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LElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUU7UUFDakUsTUFBTSxHQUFHLEdBQUcsSUFBSSxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3pDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDcEMsTUFBTSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDdkMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1lBQ2xDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDN0IsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkMsQ0FBQztRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQyxDQUFDO0lBQ0Ysa0RBQWtEO0lBQ2xELE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBUyxFQUFFLE1BQWUsRUFBRSxFQUFFO1FBQzFDLE1BQU0sR0FBRyxHQUFHO1lBQ1YsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2pELENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVB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QUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzVDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUM5QixNQUFNLEdBQUcsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUM5QixJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDWixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJO29CQUFFLEdBQUcsSUFBSSxNQUFNLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDcEUsQ0FBQztZQUNELEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO1FBQ3JCLENBQUM7SUFDSCxDQUFDO0lBQ0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUM5QixJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDWixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJO29CQUFFLEdBQUcsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7WUFDRCxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUMxQixNQUFvQixFQUFFLEdBQW1ELEVBQUUsT0FBZSxFQUMxRixFQUFFLEdBQUcsR0FBRyxJQUFJLEVBQUUsVUFBVSxHQUFHLEtBQUssRUFBRSxHQUFHLEVBQUU7SUFFdkMsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN4QixNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDdkUsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1FBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztZQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDOUQsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMvQixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ25GLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlDLE1BQU0sSUFBSSxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNuQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDM0IsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDeEMsSUFBSSxDQUFDLEdBQUcsSUFBSTtZQUFFLFNBQVM7UUFDdkIsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25CLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFD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Q0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxRSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBdUI7SUFDL0MsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsU0FBUyxDQUFDO0lBQzNGLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQztDQUMxRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBMZXZlbC1vZi1kZXRhaWwgcGxhbm5pbmcgZm9yIHRpbGVkIHNwYXRpYWwgZ2VvbWV0cnkg4oCUIGNlbGwgb3V0bGluZXMgYW5kIHRyYW5zY3JpcHRzLlxuICpcbiAqIFRoZSByZW5kZXJlciBrbm93cyBpdHMgY2FtZXJhIChhIHdvcmxkLXNwYWNlIGNlbnRyZSwgYSB6b29tIGluIGNhbnZhcyBwaXhlbHMgcGVyIHdvcmxkXG4gKiB1bml0LCBhIGNhbnZhcyBzaXplKTsgYSB0aWxlZCBkYXRhc2V0IGtub3dzIGl0cyBncmlkcyAob25lIHBlciBsZXZlbCwgaW4gb2JzZXJ2YXRpb25cbiAqIHVuaXRzKS4gVGhpcyBtb2R1bGUgaXMgdGhlIGJyaWRnZTogd2hpY2ggbGV2ZWwgdGhlIHpvb20gY2FsbHMgZm9yLCB3aGljaCB0aWxlcyBhcmUgb25cbiAqIHNjcmVlbiwgaG93IGJpZyBhIHRyYW5zY3JpcHQgbWFya2VyIHNob3VsZCBiZS4gRXZlcnl0aGluZyBoZXJlIGlzIHB1cmUsIHNvIHRoZSBwb2xpY3lcbiAqIOKAlCB0aGUgcGFydCB0aGF0IGRlY2lkZXMgd2hldGhlciB0aGUgdmlldyBpcyBmYXN0IGFuZCBsZWdpYmxlIOKAlCBpcyB0ZXN0YWJsZSB3aXRob3V0IGFcbiAqIEdQVS5cbiAqXG4gKiBPYnNlcnZhdGlvbiB1bml0cyBtYXAgb250byB3b3JsZCB1bml0cyB0aHJvdWdoIHRoZSBkYXRhc2V0J3MgYGltYWdlUmVmYCBhZmZpbmVcbiAqIChgd29ybGQgPSBkYXRhIMK3IHNjYWxlICsgdHJhbnNsYXRlYCksIHNvIFwicGl4ZWxzIHBlciBvYnNlcnZhdGlvbiB1bml0XCIgaXNcbiAqIGB6b29tIMK3IHNjYWxlYC4gRm9yIGEgWGVuaXVtIGJ1bmRsZSB0aGUgZGF0YSB1bml0IGlzIHRoZSBtaWNyb24gYW5kIHRoZSB3b3JsZCB1bml0IHRoZVxuICogbW9ycGhvbG9neSBwaXhlbC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIFNwYXRpYWxCb3VuZHMsIFNwYXRpYWxJbWFnZVJlZiwgU3BhdGlhbFRpbGVMZXZlbCxcbn0gZnJvbSAnLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgdHlwZSB7IFNwYXRpYWxWaWV3U3RhdGUsIFRyYW5zY3JpcHRHbHlwaE5hbWUgfSBmcm9tICcuLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQgdHlwZSB7IFNwYXRpYWxEYXRhc2V0IH0gZnJvbSAnLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5cbi8qKiBBIHJlY3RhbmdsZSBpbiBvYnNlcnZhdGlvbiBjb29yZGluYXRlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YVJlY3Qge1xuICB4MDogbnVtYmVyO1xuICB5MDogbnVtYmVyO1xuICB4MTogbnVtYmVyO1xuICB5MTogbnVtYmVyO1xufVxuXG4vKiogVGlsZSBhZGRyZXNzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUaWxlS2V5IHtcbiAgbGV2ZWw6IG51bWJlcjtcbiAgZ3g6IG51bWJlcjtcbiAgZ3k6IG51bWJlcjtcbn1cblxuLyoqIFdoZXRoZXIgY2VsbCBvdXRsaW5lcyBhcmUgZHJhd246IHRoZSB1c2VyJ3MgY2hvaWNlLCBlbHNlIG9uIHdoZW4gdGhlIGRhdGFzZXQgaGFzIGFueS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjZWxsc1Nob3duKFxuICBkYXRhc2V0OiBQaWNrPFNwYXRpYWxEYXRhc2V0LCAncG9seWdvblRpbGVzJyB8ICdwb2x5Z29ucyc+IHwgbnVsbCxcbiAgdmlldzogUGljazxTcGF0aWFsVmlld1N0YXRlLCAnc2hvd0NlbGxzJz4sXG4pOiBib29sZWFuIHtcbiAgY29uc3QgYXZhaWxhYmxlID0gISEoZGF0YXNldD8ucG9seWdvblRpbGVzIHx8IGRhdGFzZXQ/LnBvbHlnb25zKTtcbiAgcmV0dXJuIGF2YWlsYWJsZSAmJiAodmlldy5zaG93Q2VsbHMgPz8gdHJ1ZSk7XG59XG5cbi8qKiBBIGNvbHVtbiBob2xkaW5nIGEgaGFuZC1jdXJhdGVkIGNlbGwtdHlwZSBhbm5vdGF0aW9uLCBieSBuYW1pbmcgY29udmVudGlvbi4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0N1cmF0ZWRDb2x1bW4obmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiAvY3VyYXRlZC9pLnRlc3QobmFtZSk7XG59XG5cbi8qKlxuICogVGhlIGNhdGVnb3JpY2FsIGNvbHVtbiB0aGF0IG5hbWVzIGVhY2ggY2VsbCdzIHR5cGU6IHRoZSB2aWV3J3MgY2hvaWNlIHdoZW4gaXQgaXMgYVxuICogY29sdW1uIG9mIHRoaXMgZGF0YXNldCwgZWxzZSB0aGUgZmlyc3QgY2F0ZWdvcmljYWwgY29sdW1uIHRoYXQgaXMgbm90IGEgY3VyYXRlZFxuICogYW5ub3RhdGlvbiAoYSBwaXBlbGluZSdzIGNsdXN0ZXJpbmcgaXMgdGhlIGRlZmF1bHQ7IGN1cmF0aW9uIGlzIG9wdGVkIGludG8pLCBlbHNlXG4gKiBhbnkgY2F0ZWdvcmljYWwgY29sdW1uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2VsbFR5cGVDb2x1bW5Gb3IoXG4gIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBQaWNrPFNwYXRpYWxWaWV3U3RhdGUsICdjZWxsVHlwZUNvbHVtbic+LFxuKTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IGNhdGVnb3JpY2FsID0gZGF0YXNldC5jb2x1bW5zLmZpbHRlcigoYykgPT4gYy5raW5kID09PSAnY2F0ZWdvcmljYWwnKTtcbiAgaWYgKHZpZXcuY2VsbFR5cGVDb2x1bW4gJiYgY2F0ZWdvcmljYWwuc29tZSgoYykgPT4gYy5uYW1lID09PSB2aWV3LmNlbGxUeXBlQ29sdW1uKSkge1xuICAgIHJldHVybiB2aWV3LmNlbGxUeXBlQ29sdW1uO1xuICB9XG4gIHJldHVybiAoY2F0ZWdvcmljYWwuZmluZCgoYykgPT4gIWlzQ3VyYXRlZENvbHVtbihjLm5hbWUpKSA/PyBjYXRlZ29yaWNhbFswXSk/Lm5hbWUgPz8gbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRpbGVJZChrOiBUaWxlS2V5KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2subGV2ZWx9LyR7ay5neH0vJHtrLmd5fWA7XG59XG5cbi8qKiBDYW52YXMgcGl4ZWxzIHBlciBvYnNlcnZhdGlvbiB1bml0IGFsb25nIHgsIGZvciBhIGNhbWVyYSB6b29tIGFuZCBhIGRhdGHihpJ3b3JsZCBhZmZpbmUuICovXG5leHBvcnQgZnVuY3Rpb24gcGl4ZWxzUGVyRGF0YVVuaXQoem9vbTogbnVtYmVyLCByZWY/OiBTcGF0aWFsSW1hZ2VSZWYgfCBudWxsKTogbnVtYmVyIHtcbiAgcmV0dXJuIHpvb20gKiBNYXRoLmFicyhyZWY/LnNjYWxlPy5bMF0gPz8gMSk7XG59XG5cbi8qKlxuICogVGhlIHBhcnQgb2Ygb2JzZXJ2YXRpb24gc3BhY2UgdGhlIGNhbWVyYSBzaG93cywgcGFkZGVkIGJ5IGBtYXJnaW5gIChhIGZyYWN0aW9uIG9mIHRoZVxuICogdmlld3BvcnQpIHNvIHRpbGVzIGp1c3Qgb2ZmIHNjcmVlbiBhcmUgYWxyZWFkeSB0aGVyZSB3aGVuIGEgcGFuIGJyaW5ncyB0aGVtIGluLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmlzaWJsZURhdGFSZWN0KFxuICBjZW50ZXI6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0sIHpvb206IG51bWJlciwgY2FudmFzVzogbnVtYmVyLCBjYW52YXNIOiBudW1iZXIsXG4gIHJlZj86IFNwYXRpYWxJbWFnZVJlZiB8IG51bGwsIG1hcmdpbiA9IDAuMTUsXG4pOiBEYXRhUmVjdCB8IG51bGwge1xuICBpZiAoISh6b29tID4gMCkgfHwgIShjYW52YXNXID4gMCkgfHwgIShjYW52YXNIID4gMCkpIHJldHVybiBudWxsO1xuICBjb25zdCBzeCA9IHJlZj8uc2NhbGU/LlswXSA/PyAxO1xuICBjb25zdCBzeSA9IHJlZj8uc2NhbGU/LlsxXSA/PyAxO1xuICBjb25zdCB0eCA9IHJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMDtcbiAgY29uc3QgdHkgPSByZWY/LnRyYW5zbGF0ZT8uWzFdID8/IDA7XG4gIGNvbnN0IGhhbGZXID0gKGNhbnZhc1cgLyB6b29tIC8gMikgKiAoMSArIDIgKiBtYXJnaW4pO1xuICBjb25zdCBoYWxmSCA9IChjYW52YXNIIC8gem9vbSAvIDIpICogKDEgKyAyICogbWFyZ2luKTtcbiAgY29uc3Qgd3gwID0gY2VudGVyWzBdIC0gaGFsZlc7XG4gIGNvbnN0IHd4MSA9IGNlbnRlclswXSArIGhhbGZXO1xuICBjb25zdCB3eTAgPSBjZW50ZXJbMV0gLSBoYWxmSDtcbiAgY29uc3Qgd3kxID0gY2VudGVyWzFdICsgaGFsZkg7XG4gIGNvbnN0IGF4ID0gKHd4MCAtIHR4KSAvIHN4O1xuICBjb25zdCBieCA9ICh3eDEgLSB0eCkgLyBzeDtcbiAgY29uc3QgYXkgPSAod3kwIC0gdHkpIC8gc3k7XG4gIGNvbnN0IGJ5ID0gKHd5MSAtIHR5KSAvIHN5O1xuICByZXR1cm4geyB4MDogTWF0aC5taW4oYXgsIGJ4KSwgeTA6IE1hdGgubWluKGF5LCBieSksIHgxOiBNYXRoLm1heChheCwgYngpLCB5MTogTWF0aC5tYXgoYXksIGJ5KSB9O1xufVxuXG4vKipcbiAqIFRpbGVzIG9mIG9uZSBsZXZlbCBpbnRlcnNlY3RpbmcgYHJlY3RgLCBjbGlwcGVkIHRvIHRoZSBkYXRhc2V0J3MgYGJvdW5kc2AgKHNvIHpvb21pbmdcbiAqIG91dCBvdmVyIGVtcHR5IGNhbnZhcyBkb2VzIG5vdCBhc2sgZm9yIHRpbGVzIHRoYXQgY2Fubm90IGV4aXN0KS4gT3JkZXJlZCBmcm9tIHRoZVxuICogcmVjdGFuZ2xlJ3MgY2VudHJlIG91dHdhcmQsIHNvIHRoZSBtaWRkbGUgb2YgdGhlIHNjcmVlbiBmaWxscyBpbiBmaXJzdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRpbGVzSW5SZWN0KFxuICByZWN0OiBEYXRhUmVjdCwgbGV2ZWw6IG51bWJlciwgbGV2ZWxzOiByZWFkb25seSBTcGF0aWFsVGlsZUxldmVsW10sXG4gIGJvdW5kcz86IFNwYXRpYWxCb3VuZHMgfCBudWxsLCBsaW1pdCA9IEluZmluaXR5LFxuKTogVGlsZUtleVtdIHtcbiAgY29uc3Qgc2l6ZSA9IGxldmVsc1tsZXZlbF0/LnRpbGVTaXplO1xuICBpZiAoIShzaXplID4gMCkpIHJldHVybiBbXTtcbiAgbGV0IHsgeDAsIHkwLCB4MSwgeTEgfSA9IHJlY3Q7XG4gIGlmIChib3VuZHMpIHtcbiAgICB4MCA9IE1hdGgubWF4KHgwLCBib3VuZHNbMF0pO1xuICAgIHkwID0gTWF0aC5tYXgoeTAsIGJvdW5kc1sxXSk7XG4gICAgeDEgPSBNYXRoLm1pbih4MSwgYm91bmRzWzJdKTtcbiAgICB5MSA9IE1hdGgubWluKHkxLCBib3VuZHNbM10pO1xuICAgIGlmICh4MSA8IHgwIHx8IHkxIDwgeTApIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBneDAgPSBNYXRoLmZsb29yKHgwIC8gc2l6ZSk7XG4gIGNvbnN0IGd4MSA9IE1hdGguZmxvb3IoeDEgLyBzaXplKTtcbiAgY29uc3QgZ3kwID0gTWF0aC5mbG9vcih5MCAvIHNpemUpO1xuICBjb25zdCBneTEgPSBNYXRoLmZsb29yKHkxIC8gc2l6ZSk7XG4gIGNvbnN0IGN4ID0gKHJlY3QueDAgKyByZWN0LngxKSAvIDIgLyBzaXplO1xuICBjb25zdCBjeSA9IChyZWN0LnkwICsgcmVjdC55MSkgLyAyIC8gc2l6ZTtcbiAgY29uc3Qgb3V0OiBUaWxlS2V5W10gPSBbXTtcbiAgZm9yIChsZXQgZ3kgPSBneTA7IGd5IDw9IGd5MTsgZ3krKykge1xuICAgIGZvciAobGV0IGd4ID0gZ3gwOyBneCA8PSBneDE7IGd4KyspIG91dC5wdXNoKHsgbGV2ZWwsIGd4LCBneSB9KTtcbiAgfVxuICBvdXQuc29ydCgoYSwgYikgPT4gKChhLmd4ICsgMC41IC0gY3gpICoqIDIgKyAoYS5neSArIDAuNSAtIGN5KSAqKiAyKVxuICAgIC0gKChiLmd4ICsgMC41IC0gY3gpICoqIDIgKyAoYi5neSArIDAuNSAtIGN5KSAqKiAyKSk7XG4gIHJldHVybiBvdXQubGVuZ3RoID4gbGltaXQgPyBvdXQuc2xpY2UoMCwgbGltaXQpIDogb3V0O1xufVxuXG4vKipcbiAqIFR5cGljYWwgY2VsbCBkaWFtZXRlciwgaW4gb2JzZXJ2YXRpb24gdW5pdHMsIHVzZWQgdG8ganVkZ2UgaG93IGxhcmdlIGNlbGxzIGFwcGVhci5cbiAqIERlcml2ZWQgZnJvbSB0aGUgcGVyLW9ic2VydmF0aW9uIHJhZGl1cyB3aGVuIHRoZXJlIGlzIG9uZTsgMTIgwrVtIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHR5cGljYWxDZWxsRGlhbWV0ZXIocmFkaXVzOiBGbG9hdDMyQXJyYXkgfCBudW1iZXIgfCB1bmRlZmluZWQsIGZhbGxiYWNrID0gMTIpOiBudW1iZXIge1xuICBpZiAodHlwZW9mIHJhZGl1cyA9PT0gJ251bWJlcicpIHJldHVybiByYWRpdXMgPiAwID8gcmFkaXVzICogMiA6IGZhbGxiYWNrO1xuICBpZiAoIXJhZGl1cz8ubGVuZ3RoKSByZXR1cm4gZmFsbGJhY2s7XG4gIC8vIFRoZSBtZWRpYW4gb2YgYSBzYW1wbGUgaXMgcGxlbnR5IOKAlCB0aGlzIHNldHMgYSB0aHJlc2hvbGQsIG5vdCBhIG1lYXN1cmVtZW50LlxuICBjb25zdCBzdGVwID0gTWF0aC5tYXgoMSwgTWF0aC5mbG9vcihyYWRpdXMubGVuZ3RoIC8gMjA0OCkpO1xuICBjb25zdCBzYW1wbGU6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmFkaXVzLmxlbmd0aDsgaSArPSBzdGVwKSB7XG4gICAgaWYgKHJhZGl1c1tpXSA+IDApIHNhbXBsZS5wdXNoKHJhZGl1c1tpXSk7XG4gIH1cbiAgaWYgKCFzYW1wbGUubGVuZ3RoKSByZXR1cm4gZmFsbGJhY2s7XG4gIHNhbXBsZS5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gIHJldHVybiBzYW1wbGVbc2FtcGxlLmxlbmd0aCA+PiAxXSAqIDI7XG59XG5cbi8qKlxuICogT24tc2NyZWVuIGNlbGwgZGlhbWV0ZXIgKHB4KSBhdCBvciBhYm92ZSB3aGljaCBlYWNoIHBvbHlnb24gbGV2ZWwgaXMgdXNlZC4gQSBsZXZlbFxuICogaGFsdmVzIHRoZSB2ZXJ0aWNlcyBvZiB0aGUgb25lIGJlbG93LCBzbyBlYWNoIHNob3VsZCB0YWtlIG92ZXIgd2hlbiB0aGUgY2VsbCBpcyBhYm91dFxuICogaGFsZiBhcyBsYXJnZSBvbiBzY3JlZW4uIEJlbG93IHRoZSBsYXN0IGZpbml0ZSB0aHJlc2hvbGQgb3V0bGluZXMgYXJlIG5vdCBkcmF3biBhdFxuICogYWxsIOKAlCBhIGNlbGwgYSBmZXcgcGl4ZWxzIHdpZGUgaXMgYSBkb3QsIGFuZCB0aGUgb2JzZXJ2YXRpb24gbWFya2VycyBhbHJlYWR5IGRyYXcgaXRcbiAqIGFzIG9uZS5cbiAqXG4gKiBYZW5pdW0ncyBmb3VydGggbGV2ZWwgKDMgdmVydGljZXMgcGVyIGNlbGwpIGlzIGRlbGliZXJhdGVseSBuZXZlciB1c2VkOiBzZWVuIG9uXG4gKiBzY3JlZW4gaXQgaXMgYSBmaWVsZCBvZiB0cmlhbmdsZXMsIHdoaWNoIHJlYWRzIGFzIGFuIGFydGVmYWN0IHJhdGhlciB0aGFuIGFzIGNlbGxzLlxuICogVGhlIGRvdHMgYmVsb3cgOCBweCBzYXkgdGhlIHNhbWUgdGhpbmcgbW9yZSBob25lc3RseS5cbiAqL1xuZXhwb3J0IGNvbnN0IFBPTFlHT05fTEVWRUxfTUlOX0NFTExfUFggPSBbMzYsIDE4LCA4LCBJbmZpbml0eV07XG5cbi8qKlxuICogV2hpY2ggcG9seWdvbiBsZXZlbCBzdWl0cyB0aGlzIHpvb20sIG9yIC0xIGZvciBcInRvbyBzbWFsbCB0byBvdXRsaW5lXCIuXG4gKiBgZGV0YWlsYCA+IDEgcHJlZmVycyBmaW5lciBsZXZlbHMgKHNoYXJwZXIsIHNsb3dlcik7IDwgMSBjb2Fyc2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcG9seWdvbkxldmVsRm9yKFxuICBweFBlclVuaXQ6IG51bWJlciwgY2VsbERpYW1ldGVyOiBudW1iZXIsIGxldmVsQ291bnQ6IG51bWJlciwgZGV0YWlsID0gMSxcbik6IG51bWJlciB7XG4gIGNvbnN0IGNlbGxQeCA9IHB4UGVyVW5pdCAqIGNlbGxEaWFtZXRlciAqIGRldGFpbDtcbiAgY29uc3QgdGFibGUgPSBQT0xZR09OX0xFVkVMX01JTl9DRUxMX1BYO1xuICBmb3IgKGxldCBsID0gMDsgbCA8IGxldmVsQ291bnQ7IGwrKykge1xuICAgIC8vIFBhc3QgdGhlIHRhYmxlLCBrZWVwIGhhbHZpbmc6IGVhY2ggbGV2ZWwgc3RpbGwgaGFsdmVzIHRoZSB2ZXJ0aWNlcy5cbiAgICBjb25zdCBtaW4gPSB0YWJsZVtsXSA/PyB0YWJsZVt0YWJsZS5sZW5ndGggLSAxXSAvIDIgKiogKGwgLSB0YWJsZS5sZW5ndGggKyAxKTtcbiAgICBpZiAoY2VsbFB4ID49IG1pbikgcmV0dXJuIGw7XG4gIH1cbiAgcmV0dXJuIC0xO1xufVxuXG4vKipcbiAqIFdoaWNoIHRyYW5zY3JpcHQgbGV2ZWwgc3VpdHMgdGhpcyB6b29tOiB0aGUgb25lIHdob3NlIHRpbGVzIGNvbWUgb3V0IGNsb3Nlc3QgdG9cbiAqIGB0YXJnZXRUaWxlUHhgIG9uIHNjcmVlbi4gQ29hcnNlciBsZXZlbHMgYWdncmVnYXRlIG1vcmUsIHNvIHRoaXMga2VlcHMgdGhlIG51bWJlciBvZlxuICogbWFya2VycyBwZXIgc2NyZWVuIHJvdWdobHkgY29uc3RhbnQgaG93ZXZlciBmYXIgb3V0IHRoZSBjYW1lcmEgaXMg4oCUIHRoZSBwcm9wZXJ0eSB0aGF0XG4gKiBrZWVwcyB0aGUgdmlldyBmYXN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNjcmlwdExldmVsRm9yKFxuICBweFBlclVuaXQ6IG51bWJlciwgbGV2ZWxzOiByZWFkb25seSBTcGF0aWFsVGlsZUxldmVsW10sIHRhcmdldFRpbGVQeCA9IDUxMixcbik6IG51bWJlciB7XG4gIGlmICghbGV2ZWxzLmxlbmd0aCB8fCAhKHB4UGVyVW5pdCA+IDApKSByZXR1cm4gMDtcbiAgbGV0IGJlc3QgPSAwO1xuICBsZXQgYmVzdEVyciA9IEluZmluaXR5O1xuICBmb3IgKGxldCBsID0gMDsgbCA8IGxldmVscy5sZW5ndGg7IGwrKykge1xuICAgIGNvbnN0IGVyciA9IE1hdGguYWJzKE1hdGgubG9nMigobGV2ZWxzW2xdLnRpbGVTaXplICogcHhQZXJVbml0KSAvIHRhcmdldFRpbGVQeCkpO1xuICAgIGlmIChlcnIgPCBiZXN0RXJyKSB7XG4gICAgICBiZXN0RXJyID0gZXJyO1xuICAgICAgYmVzdCA9IGw7XG4gICAgfVxuICB9XG4gIHJldHVybiBiZXN0O1xufVxuXG4vKiogU21hbGxlc3QgYW5kIGxhcmdlc3QgdHJhbnNjcmlwdCBtYXJrZXIsIGluIGNhbnZhcyBwaXhlbHMuICovXG5leHBvcnQgY29uc3QgVFJBTlNDUklQVF9NSU5fUFggPSA0O1xuZXhwb3J0IGNvbnN0IFRSQU5TQ1JJUFRfTUFYX1BYID0gMzI7XG4vKipcbiAqIFBoeXNpY2FsIGRpYW1ldGVyIGEgc2luZ2xlIHRyYW5zY3JpcHQgaXMgZHJhd24gYXQsIGluIMK1bSDigJQgY2xlYXJseSBsYXJnZXIgdGhhbiB0aGVcbiAqIGltYWdlZCBzcG90ICh+MC4zIMK1bSkgc28gaXQgc3RheXMgbGVnaWJsZSwgYW5kIHNtYWxsIGVub3VnaCB0aGF0IG5laWdoYm91cmluZ1xuICogbW9sZWN1bGVzIGluc2lkZSBvbmUgY2VsbCBzdGF5IGFwYXJ0LlxuICovXG5leHBvcnQgY29uc3QgVFJBTlNDUklQVF9QSFlTSUNBTF9VTSA9IDEuMjtcblxuLyoqXG4gKiBNYXJrZXIgZGlhbWV0ZXIgaW4gY2FudmFzIHBpeGVscyBmb3IgYW4gZW50cnkgc3RhbmRpbmcgZm9yIGB3ZWlnaHRgIHRyYW5zY3JpcHRzLlxuICpcbiAqIFRoZSBjb252ZW50aW9uIHNwYXRpYWwgdmlld2VycyBzaGFyZSAoZGVjay5nbCdzIGByYWRpdXNNaW5QaXhlbHNgL2ByYWRpdXNNYXhQaXhlbHNgLFxuICogWGVuaXVtIEV4cGxvcmVyJ3MgdHJhbnNjcmlwdCBzaXplKTogYSBQSFlTSUNBTCBzaXplLCBjbGFtcGVkIHRvIGEgc2NyZWVuLXBpeGVsIHJhbmdlLlxuICogWm9vbWVkIG91dCwgbWFya2VycyBzaXQgYXQgdGhlIG1pbmltdW0gYW5kIG5ldmVyIHZhbmlzaDsgem9vbWVkIGluLCB0aGV5IGdyb3cgd2l0aCB0aGVcbiAqIHRpc3N1ZSBpbnN0ZWFkIG9mIHNocmlua2luZyB0byBzcGVja3MgbmV4dCB0byBjZWxscyBodW5kcmVkcyBvZiBwaXhlbHMgd2lkZS4gQSBmaXhlZFxuICogc2NyZWVuIHNpemUgZG9lcyB0aGUgb3Bwb3NpdGUgYXQgaGlnaCB6b29tLCB3aGljaCBpcyB3aGF0IG1hZGUgdHJhbnNjcmlwdHMgZGlzYXBwZWFyXG4gKiBhdCBwaXhlbC1sZXZlbCB6b29tLlxuICpcbiAqIEFnZ3JlZ2F0ZXMgZ3JvdyB3aXRoIHRoZSBjdWJlIHJvb3Qgb2YgdGhlaXIgY291bnQ6IGFyZWEg4oidIGNvdW50IHdvdWxkIGxldCBvbmUgZGVuc2VcbiAqIGFnZ3JlZ2F0ZSBzd2FsbG93IGl0cyBuZWlnaGJvdXJzLCB0aGUgY3ViZSByb290IGtlZXBzIGEgMTAwMC10cmFuc2NyaXB0IGNsdXN0ZXIgY2xlYXJseVxuICogbGFyZ2VyIHRoYW4gYSAxMC10cmFuc2NyaXB0IG9uZSB3aXRob3V0IGNvdmVyaW5nIHRoZSB0aWxlLlxuICpcbiAqIGBweFBlck1pY3JvbmAgaXMgb21pdHRlZCBmb3IgZGF0YSB3aXRoIG5vIGtub3duIHBoeXNpY2FsIHVuaXQ7IHRoZSBtYXJrZXIgaXMgdGhlblxuICogc2NyZWVuLXNpemVkIG9ubHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2NyaXB0TWFya2VyUHgod2VpZ2h0OiBudW1iZXIsIHNjYWxlID0gMSwgcHhQZXJNaWNyb24/OiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCBjb3VudGVkID0gVFJBTlNDUklQVF9NSU5fUFggKiBNYXRoLmNicnQoTWF0aC5tYXgoMSwgd2VpZ2h0KSk7XG4gIGNvbnN0IHBoeXNpY2FsID0gcHhQZXJNaWNyb24gPyBUUkFOU0NSSVBUX1BIWVNJQ0FMX1VNICogcHhQZXJNaWNyb24gOiAwO1xuICBjb25zdCBweCA9IE1hdGgubWF4KGNvdW50ZWQsIHBoeXNpY2FsKSAqIHNjYWxlO1xuICByZXR1cm4gTWF0aC5taW4oVFJBTlNDUklQVF9NQVhfUFggKiBNYXRoLm1heChzY2FsZSwgMSksIE1hdGgubWF4KFRSQU5TQ1JJUFRfTUlOX1BYICogc2NhbGUsIHB4KSk7XG59XG5cbi8vIOKUgOKUgCBHbHlwaHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBNYXJrZXIgc2hhcGVzIGZvciB0aGUgdHJhbnNjcmlwdCBcImljb25cIiBtb2RlLiBBbGwgc3Rhci1jb252ZXgsIHNvIGEgZmFuIGZpbGxzIHRoZW0uICovXG5leHBvcnQgY29uc3QgVFJBTlNDUklQVF9HTFlQSFMgPSBbXG4gICdjaXJjbGUnLCAnc3RhcicsICd0cmlhbmdsZScsICdzcXVhcmUnLCAnZGlhbW9uZCcsICdjcm9zcycsICdoZXhhZ29uJywgJ3RyaWFuZ2xlLWRvd24nLFxuICAncGVudGFnb24nLCAneCcsXG5dIGFzIGNvbnN0O1xuZXhwb3J0IHR5cGUgVHJhbnNjcmlwdEdseXBoID0gdHlwZW9mIFRSQU5TQ1JJUFRfR0xZUEhTW251bWJlcl07XG4vLyBUaGUgdmlldyBzdGF0ZSBuYW1lcyBnbHlwaHMgd2l0aG91dCBpbXBvcnRpbmcgdGhpcyBtb2R1bGU7IGtlZXAgdGhlIHR3byBpbiBzdGVwLlxuY29uc3QgX2dseXBoTmFtZXNNYXRjaDogVHJhbnNjcmlwdEdseXBoIGV4dGVuZHMgVHJhbnNjcmlwdEdseXBoTmFtZVxuICA/IChUcmFuc2NyaXB0R2x5cGhOYW1lIGV4dGVuZHMgVHJhbnNjcmlwdEdseXBoID8gdHJ1ZSA6IG5ldmVyKSA6IG5ldmVyID0gdHJ1ZTtcbnZvaWQgX2dseXBoTmFtZXNNYXRjaDtcblxuLyoqIFVuaXQgb3V0bGluZSBvZiBhIGdseXBoLCByYWRpdXMg4omIIDEsIGNlbnRyZWQgb24gdGhlIG9yaWdpbiwgYXMgYFt4MCwgeTAsIHgxLCB5MSwg4oCmXWAuICovXG5leHBvcnQgZnVuY3Rpb24gZ2x5cGhPdXRsaW5lKGdseXBoOiBUcmFuc2NyaXB0R2x5cGgpOiBGbG9hdDMyQXJyYXkge1xuICBjb25zdCBwb2x5ID0gKG46IG51bWJlciwgcm90ID0gLU1hdGguUEkgLyAyLCByID0gMSkgPT4ge1xuICAgIGNvbnN0IG91dCA9IG5ldyBGbG9hdDMyQXJyYXkobiAqIDIpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICBjb25zdCBhID0gcm90ICsgKGkgKiAyICogTWF0aC5QSSkgLyBuO1xuICAgICAgb3V0WzIgKiBpXSA9IE1hdGguY29zKGEpICogcjtcbiAgICAgIG91dFsyICogaSArIDFdID0gTWF0aC5zaW4oYSkgKiByO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9O1xuICBjb25zdCBzdGFyID0gKHBvaW50czogbnVtYmVyLCBpbm5lcjogbnVtYmVyLCByb3QgPSAtTWF0aC5QSSAvIDIpID0+IHtcbiAgICBjb25zdCBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KHBvaW50cyAqIDQpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9pbnRzICogMjsgaSsrKSB7XG4gICAgICBjb25zdCBhID0gcm90ICsgKGkgKiBNYXRoLlBJKSAvIHBvaW50cztcbiAgICAgIGNvbnN0IHIgPSBpICUgMiA9PT0gMCA/IDEgOiBpbm5lcjtcbiAgICAgIG91dFsyICogaV0gPSBNYXRoLmNvcyhhKSAqIHI7XG4gICAgICBvdXRbMiAqIGkgKyAxXSA9IE1hdGguc2luKGEpICogcjtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfTtcbiAgLy8gQSBwbHVzIGJ1aWx0IGFzIGEgMTItZ29uOiBhcm1zIG9mIGhhbGYtd2lkdGggdy5cbiAgY29uc3QgcGx1cyA9ICh3OiBudW1iZXIsIHJvdGF0ZTogYm9vbGVhbikgPT4ge1xuICAgIGNvbnN0IHB0cyA9IFtcbiAgICAgIFt3LCAtMV0sIFt3LCAtd10sIFsxLCAtd10sIFsxLCB3XSwgW3csIHddLCBbdywgMV0sXG4gICAgICBbLXcsIDFdLCBbLXcsIHddLCBbLTEsIHddLCBbLTEsIC13XSwgWy13LCAtd10sIFstdywgLTFdLFxuICAgIF07XG4gICAgY29uc3Qgb3V0ID0gbmV3IEZsb2F0MzJBcnJheShwdHMubGVuZ3RoICogMik7XG4gICAgY29uc3QgYyA9IE1hdGguU1FSVDFfMjtcbiAgICBwdHMuZm9yRWFjaCgoW3gsIHldLCBpKSA9PiB7XG4gICAgICBvdXRbMiAqIGldID0gcm90YXRlID8gKHggLSB5KSAqIGMgOiB4O1xuICAgICAgb3V0WzIgKiBpICsgMV0gPSByb3RhdGUgPyAoeCArIHkpICogYyA6IHk7XG4gICAgfSk7XG4gICAgcmV0dXJuIG91dDtcbiAgfTtcbiAgc3dpdGNoIChnbHlwaCkge1xuICAgIGNhc2UgJ2NpcmNsZSc6IHJldHVybiBwb2x5KDEyKTtcbiAgICBjYXNlICdzdGFyJzogcmV0dXJuIHN0YXIoNSwgMC40NSk7XG4gICAgY2FzZSAndHJpYW5nbGUnOiByZXR1cm4gcG9seSgzKTtcbiAgICBjYXNlICd0cmlhbmdsZS1kb3duJzogcmV0dXJuIHBvbHkoMywgTWF0aC5QSSAvIDIpO1xuICAgIGNhc2UgJ3NxdWFyZSc6IHJldHVybiBwb2x5KDQsIE1hdGguUEkgLyA0LCBNYXRoLlNRUlQyICogMC44KTtcbiAgICBjYXNlICdkaWFtb25kJzogcmV0dXJuIHBvbHkoNCwgLU1hdGguUEkgLyAyKTtcbiAgICBjYXNlICdoZXhhZ29uJzogcmV0dXJuIHBvbHkoNiwgMCk7XG4gICAgY2FzZSAncGVudGFnb24nOiByZXR1cm4gcG9seSg1KTtcbiAgICBjYXNlICdjcm9zcyc6IHJldHVybiBwbHVzKDAuMzIsIGZhbHNlKTtcbiAgICBjYXNlICd4JzogcmV0dXJuIHBsdXMoMC4yOCwgdHJ1ZSk7XG4gIH1cbn1cblxuLyoqIFRoZSBnbHlwaCBhIGdlbmUgZ2V0cyBieSBkZWZhdWx0OiBieSBpdHMgcG9zaXRpb24gaW4gdGhlIHNlbGVjdGVkIGxpc3QuICovXG5leHBvcnQgZnVuY3Rpb24gZGVmYXVsdEdseXBoRm9yKHNsb3Q6IG51bWJlcik6IFRyYW5zY3JpcHRHbHlwaCB7XG4gIHJldHVybiBUUkFOU0NSSVBUX0dMWVBIU1tzbG90ICUgVFJBTlNDUklQVF9HTFlQSFMubGVuZ3RoXTtcbn1cblxuLyoqXG4gKiBFeHBhbmQgcG9pbnQgbWFya2VycyBpbnRvIGdseXBoIHJpbmdzIGZvciBhIHNoYXBlcyBsYXllcjogZW50cnkgYGlgIGJlY29tZXMgYSBjb3B5IG9mXG4gKiBgZ2x5cGhzW2dlbmVbaV1dYCBzY2FsZWQgdG8gYHJhZGl1c1tpXWAgYW5kIGNlbnRyZWQgb24gYCh4W2ldLCB5W2ldKWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnbHlwaFJpbmdzKFxuICB4OiBGbG9hdDMyQXJyYXksIHk6IEZsb2F0MzJBcnJheSwgcmFkaXVzOiBGbG9hdDMyQXJyYXksIGdseXBoT2Y6IChpOiBudW1iZXIpID0+IEZsb2F0MzJBcnJheSxcbik6IHsgY29vcmRzOiBGbG9hdDMyQXJyYXk7IG9mZnNldHM6IFVpbnQzMkFycmF5IH0ge1xuICBjb25zdCBuID0geC5sZW5ndGg7XG4gIGNvbnN0IG9mZnNldHMgPSBuZXcgVWludDMyQXJyYXkobiArIDEpO1xuICBsZXQgdG90YWwgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIG9mZnNldHNbaV0gPSB0b3RhbDtcbiAgICB0b3RhbCArPSBnbHlwaE9mKGkpLmxlbmd0aCAvIDI7XG4gIH1cbiAgb2Zmc2V0c1tuXSA9IHRvdGFsO1xuICBjb25zdCBjb29yZHMgPSBuZXcgRmxvYXQzMkFycmF5KHRvdGFsICogMik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgY29uc3QgZyA9IGdseXBoT2YoaSk7XG4gICAgY29uc3QgciA9IHJhZGl1c1tpXTtcbiAgICBsZXQgbyA9IG9mZnNldHNbaV0gKiAyO1xuICAgIGZvciAobGV0IGsgPSAwOyBrIDwgZy5sZW5ndGg7IGsgKz0gMikge1xuICAgICAgY29vcmRzW28rK10gPSB4W2ldICsgZ1trXSAqIHI7XG4gICAgICBjb29yZHNbbysrXSA9IHlbaV0gKyBnW2sgKyAxXSAqIHI7XG4gICAgfVxuICB9XG4gIHJldHVybiB7IGNvb3Jkcywgb2Zmc2V0cyB9O1xufVxuXG4vLyDilIDilIAgRGlzY3JldGUgY29sb3VyaW5nIHRocm91Z2ggYSBjb2xvcm1hcCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBBIHNoYXBlcyBsYXllciBjb2xvdXJzIHRocm91Z2ggYSBjb2xvcm1hcCBMVVQsIG5vdCBwZXItc2hhcGUgUkdCQS4gQSBjYXRlZ29yaWNhbFxuICogcGFsZXR0ZSBiZWNvbWVzIGEgcGllY2V3aXNlLWNvbnN0YW50IGNvbG9ybWFwOiBjYXRlZ29yeSBgY2Agb2YgYG5gIG93bnMgdGhlIGJhbmRcbiAqIGBbYy9uLCAoYysxKS9uKWAsIGFuZCBhIHNoYXBlIHRha2VzIHRoZSB2YWx1ZSBhdCBpdHMgYmFuZCdzIGNlbnRyZSwgc28gdGhlIExVVCdzXG4gKiBsaW5lYXIgZmlsdGVyaW5nIG5ldmVyIGJsZW5kcyB0d28gY2F0ZWdvcmllcy5cbiAqXG4gKiBSZXR1cm5zIHRoZSBzdG9wcyAobGluZWFyIDAuLjEgUkdCKSBhbmQgYSBmdW5jdGlvbiBtYXBwaW5nIGEgY2F0ZWdvcnkgY29kZSB0byB0aGVcbiAqIHZhbHVlIHRvIGhhbmQgdGhlIGxheWVyLiBgbWlzc2luZ2AgaXMgdGhlIGNvbG91ciBvZiB0aGUgZXh0cmEgYmFuZCB1c2VkIGZvciBcIm5vXG4gKiBjYXRlZ29yeVwiLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlzY3JldGVDb2xvcm1hcFN0b3BzKFxuICByZ2I6IHJlYWRvbmx5IChyZWFkb25seSBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0pW10sIG1pc3Npbmc6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSxcbik6IHsgc3RvcHM6IHsgdDogbnVtYmVyOyBjb2xvcjogW251bWJlciwgbnVtYmVyLCBudW1iZXJdIH1bXTsgdmFsdWVPZjogKGNvZGU6IG51bWJlcikgPT4gbnVtYmVyIH0ge1xuICBjb25zdCBiYW5kcyA9IFsuLi5yZ2IsIG1pc3NpbmddO1xuICBjb25zdCBuID0gYmFuZHMubGVuZ3RoO1xuICBjb25zdCBzdG9wczogeyB0OiBudW1iZXI7IGNvbG9yOiBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gfVtdID0gW107XG4gIGNvbnN0IGVwcyA9IDFlLTY7XG4gIGJhbmRzLmZvckVhY2goKGMsIGkpID0+IHtcbiAgICBjb25zdCBjb2xvcjogW251bWJlciwgbnVtYmVyLCBudW1iZXJdID0gW2NbMF0gLyAyNTUsIGNbMV0gLyAyNTUsIGNbMl0gLyAyNTVdO1xuICAgIHN0b3BzLnB1c2goeyB0OiBpIC8gbiArIChpID09PSAwID8gMCA6IGVwcyksIGNvbG9yIH0pO1xuICAgIHN0b3BzLnB1c2goeyB0OiAoaSArIDEpIC8gbiAtIChpID09PSBuIC0gMSA/IDAgOiBlcHMpLCBjb2xvciB9KTtcbiAgfSk7XG4gIGNvbnN0IG1pc3NpbmdDb2RlID0gbiAtIDE7XG4gIHJldHVybiB7XG4gICAgc3RvcHMsXG4gICAgdmFsdWVPZjogKGNvZGU6IG51bWJlcikgPT4gKChjb2RlIDwgMCB8fCBjb2RlID49IG1pc3NpbmdDb2RlID8gbWlzc2luZ0NvZGUgOiBjb2RlKSArIDAuNSkgLyBuLFxuICB9O1xufVxuXG4vLyDilIDilIAgRGVuc2l0eSByYXN0ZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogU2VwYXJhYmxlIEdhdXNzaWFuIGJsdXIgb2YgYSByb3ctbWFqb3IgcmFzdGVyLCBgc2lnbWFgIGluIHJhc3RlciBjZWxscy5cbiAqXG4gKiBBIHBlci1nZW5lIGNvdW50IHJhc3RlciBhdCAxMCDCtW0gaXMgbW9zdGx5IHplcm9zIGFuZCBvbmVzIOKAlCBkcmF3biBhcy1pcyBpdCBpcyBzcGVja2xlLFxuICogbm90IGEgZGVuc2l0eS4gQSDPgyBvZiBvbmUgdG8gdHdvIGNlbGxzICgxMOKAkzIwIMK1bSwgYWJvdXQgYSBjZWxsIGRpYW1ldGVyKSB0dXJucyBpdCBpbnRvXG4gKiBhIGZpZWxkIHRoYXQgcmVhZHMgYXMgdGVycml0b3J5IHdoaWxlIGtlZXBpbmcgc3RydWN0dXJlcyBhIGZldyBjZWxscyB3aWRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc21vb3RoUmFzdGVyKHZhbHVlczogRmxvYXQzMkFycmF5LCByb3dzOiBudW1iZXIsIGNvbHM6IG51bWJlciwgc2lnbWE6IG51bWJlcik6IEZsb2F0MzJBcnJheSB7XG4gIGlmICghKHNpZ21hID4gMCkpIHJldHVybiB2YWx1ZXMuc2xpY2UoKTtcbiAgY29uc3QgciA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChzaWdtYSAqIDMpKTtcbiAgY29uc3Qga2VybmVsID0gbmV3IEZsb2F0MzJBcnJheSgyICogciArIDEpO1xuICBsZXQgc3VtID0gMDtcbiAgZm9yIChsZXQgaSA9IC1yOyBpIDw9IHI7IGkrKykgc3VtICs9IChrZXJuZWxbaSArIHJdID0gTWF0aC5leHAoLShpICogaSkgLyAoMiAqIHNpZ21hICogc2lnbWEpKSk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwga2VybmVsLmxlbmd0aDsgaSsrKSBrZXJuZWxbaV0gLz0gc3VtO1xuICBjb25zdCB0bXAgPSBuZXcgRmxvYXQzMkFycmF5KHZhbHVlcy5sZW5ndGgpO1xuICBjb25zdCBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KHZhbHVlcy5sZW5ndGgpO1xuICBmb3IgKGxldCB5ID0gMDsgeSA8IHJvd3M7IHkrKykge1xuICAgIGNvbnN0IHJvdyA9IHkgKiBjb2xzO1xuICAgIGZvciAobGV0IHggPSAwOyB4IDwgY29sczsgeCsrKSB7XG4gICAgICBsZXQgYWNjID0gMDtcbiAgICAgIGZvciAobGV0IGsgPSAtcjsgayA8PSByOyBrKyspIHtcbiAgICAgICAgY29uc3QgeHggPSB4ICsgaztcbiAgICAgICAgaWYgKHh4ID49IDAgJiYgeHggPCBjb2xzKSBhY2MgKz0gdmFsdWVzW3JvdyArIHh4XSAqIGtlcm5lbFtrICsgcl07XG4gICAgICB9XG4gICAgICB0bXBbcm93ICsgeF0gPSBhY2M7XG4gICAgfVxuICB9XG4gIGZvciAobGV0IHkgPSAwOyB5IDwgcm93czsgeSsrKSB7XG4gICAgZm9yIChsZXQgeCA9IDA7IHggPCBjb2xzOyB4KyspIHtcbiAgICAgIGxldCBhY2MgPSAwO1xuICAgICAgZm9yIChsZXQgayA9IC1yOyBrIDw9IHI7IGsrKykge1xuICAgICAgICBjb25zdCB5eSA9IHkgKyBrO1xuICAgICAgICBpZiAoeXkgPj0gMCAmJiB5eSA8IHJvd3MpIGFjYyArPSB0bXBbeXkgKiBjb2xzICsgeF0gKiBrZXJuZWxbayArIHJdO1xuICAgICAgfVxuICAgICAgb3V0W3kgKiBjb2xzICsgeF0gPSBhY2M7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICogQ29sb3VyIGEgZGVuc2l0eSByYXN0ZXIgYXMgUkdCQSBieXRlczogbG9nLXNjYWxlZCwgd2luZG93ZWQgYXQgYSBoaWdoIHBlcmNlbnRpbGUgb2YgdGhlXG4gKiBub24temVybyB2YWx1ZXMsIGFuZCBmYWRlZCBpbiBmcm9tIHRyYW5zcGFyZW50IHNvIGVtcHR5IHRpc3N1ZSBzaG93cyB3aGF0IGlzIHVuZGVyIGl0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JEZW5zaXR5KFxuICB2YWx1ZXM6IEZsb2F0MzJBcnJheSwgbHV0OiByZWFkb25seSAocmVhZG9ubHkgW251bWJlciwgbnVtYmVyLCBudW1iZXJdKVtdLCBvcGFjaXR5OiBudW1iZXIsXG4gIHsgbG9nID0gdHJ1ZSwgcGVyY2VudGlsZSA9IDAuOTk1IH0gPSB7fSxcbik6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBuID0gdmFsdWVzLmxlbmd0aDtcbiAgY29uc3QgdCA9IGxvZyA/IHZhbHVlcy5tYXAoKHYpID0+IE1hdGgubG9nMXAoTWF0aC5tYXgoMCwgdikpKSA6IHZhbHVlcztcbiAgY29uc3QgcG9zaXRpdmU6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSBpZiAodFtpXSA+IDApIHBvc2l0aXZlLnB1c2godFtpXSk7XG4gIHBvc2l0aXZlLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgY29uc3QgYXQgPSBNYXRoLm1pbihwb3NpdGl2ZS5sZW5ndGggLSAxLCBNYXRoLmZsb29yKHBlcmNlbnRpbGUgKiBwb3NpdGl2ZS5sZW5ndGgpKTtcbiAgY29uc3QgaGkgPSBwb3NpdGl2ZS5sZW5ndGggPyBwb3NpdGl2ZVthdF0gOiAxO1xuICBjb25zdCByZ2JhID0gbmV3IFVpbnQ4QXJyYXkobiAqIDQpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIGNvbnN0IGYgPSBNYXRoLm1pbigxLCB0W2ldIC8gKGhpIHx8IDEpKTtcbiAgICBpZiAoZiA8IDAuMDIpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGMgPSBsdXRbTWF0aC5taW4obHV0Lmxlbmd0aCAtIDEsIE1hdGgucm91bmQoZiAqIChsdXQubGVuZ3RoIC0gMSkpKV07XG4gICAgcmdiYVs0ICogaV0gPSBjWzBdO1xuICAgIHJnYmFbNCAqIGkgKyAxXSA9IGNbMV07XG4gICAgcmdiYVs0ICogaSArIDJdID0gY1syXTtcbiAgICByZ2JhWzQgKiBpICsgM10gPSBNYXRoLnJvdW5kKDI1NSAqIG9wYWNpdHkgKiBNYXRoLnBvdyhmLCAwLjYpKTtcbiAgfVxuICByZXR1cm4gcmdiYTtcbn1cblxuLy8g4pSA4pSAIEFsbC1nZW5lIHRyYW5zY3JpcHRzOiBncm91cGluZyB1bmRlciBhIG1hcmtlciBidWRnZXQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBTbWFsbGVzdCBvbi1zY3JlZW4gc3BhY2luZyBiZXR3ZWVuIGdyb3VwcywgaW4gcHgg4oCUIGJlbG93IGl0IGdyb3VwcyByZWFkIGFzIG5vaXNlLiAqL1xuZXhwb3J0IGNvbnN0IEdST1VQX01JTl9TUEFDSU5HX1BYID0gMTQ7XG5cbi8qKiBBcmVhIG9mIGByZWN0YCBpbnNpZGUgYGJvdW5kc2AgKHRoZSB3aG9sZSByZWN0IHdoZW4gdGhlcmUgYXJlIG5vbmUpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZpc2libGVBcmVhKHJlY3Q6IERhdGFSZWN0LCBib3VuZHM/OiBTcGF0aWFsQm91bmRzIHwgbnVsbCk6IG51bWJlciB7XG4gIGNvbnN0IHgwID0gYm91bmRzID8gTWF0aC5tYXgocmVjdC54MCwgYm91bmRzWzBdKSA6IHJlY3QueDA7XG4gIGNvbnN0IHkwID0gYm91bmRzID8gTWF0aC5tYXgocmVjdC55MCwgYm91bmRzWzFdKSA6IHJlY3QueTA7XG4gIGNvbnN0IHgxID0gYm91bmRzID8gTWF0aC5taW4ocmVjdC54MSwgYm91bmRzWzJdKSA6IHJlY3QueDE7XG4gIGNvbnN0IHkxID0gYm91bmRzID8gTWF0aC5taW4ocmVjdC55MSwgYm91bmRzWzNdKSA6IHJlY3QueTE7XG4gIHJldHVybiBNYXRoLm1heCgwLCB4MSAtIHgwKSAqIE1hdGgubWF4KDAsIHkxIC0geTApO1xufVxuXG5leHBvcnQgdHlwZSBBbGxHZW5lc1BsYW4gPSB7IGtpbmQ6ICdpbmRpdmlkdWFsJyB9IHwgeyBraW5kOiAnYmlucyc7IGxldmVsOiBudW1iZXIgfSB8IHsga2luZDogJ25vbmUnIH07XG5cbi8qKlxuICogSG93IHRvIGRyYXcgZXZlcnkgdHJhbnNjcmlwdCBpbiB2aWV3IHdpdGhvdXQgZXhjZWVkaW5nIGBidWRnZXRgIG1hcmtlcnMuXG4gKlxuICogLSBUaGUgdHJhbnNjcmlwdHMgdGhlbXNlbHZlcywgb25jZSB0aGUgZXN0aW1hdGVkIGNvdW50IGluIHZpZXcgZml0cyB0aGUgYnVkZ2V0LlxuICogLSBPdGhlcndpc2UgdGhlIGZpbmVzdCBweXJhbWlkIGxldmVsIHdob3NlIGJpbnMgYXJlIGF0IGxlYXN0IGBtaW5TcGFjaW5nUHhgIGFwYXJ0IG9uXG4gKiAgIHNjcmVlbiBhbmQgbnVtYmVyIG5vIG1vcmUgdGhhbiB0aGUgYnVkZ2V0IOKAlCBncm91cHMgYmlnIGVub3VnaCB0byByZWFkLCBmZXcgZW5vdWdoXG4gKiAgIHRvIGRyYXcuXG4gKlxuICogVGhlIGNvdW50IGluIHZpZXcgaXMgZXN0aW1hdGVkIGZyb20gdGhlIGF2ZXJhZ2UgZGVuc2l0eSwgd2hpY2ggb3Zlci0gb3IgdW5kZXItc2hvb3RzXG4gKiBsb2NhbGx5OyB0aGUgcmVuZGVyZXIgc3RpbGwgY2FwcyB3aGF0IGl0IGRyYXdzLCBzbyBhbiBlc3RpbWF0ZSBpcyBlbm91Z2ggdG8gY2hvb3NlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWxsR2VuZXNQbGFuKG86IHtcbiAgcmVjdDogRGF0YVJlY3Q7IGJvdW5kczogU3BhdGlhbEJvdW5kczsgdG90YWw6IG51bWJlcjsgcHhQZXJVbml0OiBudW1iZXI7XG4gIGxldmVsczogcmVhZG9ubHkgeyBiaW5TaXplOiBudW1iZXIgfVtdOyBidWRnZXQ6IG51bWJlcjsgY2FuSW5kaXZpZHVhbDogYm9vbGVhbjtcbiAgbWluU3BhY2luZ1B4PzogbnVtYmVyO1xufSk6IEFsbEdlbmVzUGxhbiB7XG4gIGNvbnN0IGFyZWEgPSB2aXNpYmxlQXJlYShvLnJlY3QsIG8uYm91bmRzKTtcbiAgaWYgKCEoYXJlYSA+IDApKSByZXR1cm4geyBraW5kOiAnbm9uZScgfTtcbiAgY29uc3QgYiA9IG8uYm91bmRzO1xuICBjb25zdCBkZW5zaXR5ID0gby50b3RhbCAvIE1hdGgubWF4KDEsIChiWzJdIC0gYlswXSkgKiAoYlszXSAtIGJbMV0pKTtcbiAgaWYgKG8uY2FuSW5kaXZpZHVhbCAmJiBkZW5zaXR5ICogYXJlYSA8PSBvLmJ1ZGdldCkgcmV0dXJuIHsga2luZDogJ2luZGl2aWR1YWwnIH07XG4gIGlmICghby5sZXZlbHMubGVuZ3RoKSByZXR1cm4geyBraW5kOiAnbm9uZScgfTtcbiAgY29uc3Qgc3BhY2luZyA9IG8ubWluU3BhY2luZ1B4ID8/IEdST1VQX01JTl9TUEFDSU5HX1BYO1xuICBmb3IgKGxldCBsID0gMDsgbCA8IG8ubGV2ZWxzLmxlbmd0aDsgbCsrKSB7XG4gICAgY29uc3QgYmluID0gby5sZXZlbHNbbF0uYmluU2l6ZTtcbiAgICAvLyBUaXNzdWUgcmFyZWx5IGZpbGxzIHRoZSB2aWV3OyAwLjcgb2YgdGhlIGJpbnMgb2NjdXBpZWQgaXMgYSBmYWlyIGd1ZXNzLlxuICAgIGlmIChiaW4gKiBvLnB4UGVyVW5pdCA+PSBzcGFjaW5nICYmIChhcmVhIC8gKGJpbiAqIGJpbikpICogMC43IDw9IG8uYnVkZ2V0KSB7XG4gICAgICByZXR1cm4geyBraW5kOiAnYmlucycsIGxldmVsOiBsIH07XG4gICAgfVxuICB9XG4gIHJldHVybiB7IGtpbmQ6ICdiaW5zJywgbGV2ZWw6IG8ubGV2ZWxzLmxlbmd0aCAtIDEgfTtcbn1cblxuLyoqXG4gKiBEaWFtZXRlciBpbiBweCBvZiBhIGdyb3VwIG9mIGBjb3VudGAgdHJhbnNjcmlwdHMgaW4gYSBiaW4gYGJpblB4YCB3aWRlLCB3aGVyZVxuICogYHJlZkNvdW50YCBpcyBhIHR5cGljYWwgYnVzeSBiaW4gaW4gdmlldyAoaXRzIDk1dGggcGVyY2VudGlsZSkuXG4gKlxuICogQXJlYSBncm93cyB3aXRoIHRoZSBjb3VudCDigJQgYSBiaW4gd2l0aCBhIHF1YXJ0ZXIgb2YgdGhlIHRyYW5zY3JpcHRzIGdldHMgaGFsZiB0aGVcbiAqIGRpYW1ldGVyIOKAlCBiZXR3ZWVuIGEgdGhpcmQgb2YgdGhlIGJpbiAoc28gYSBzcGFyc2UgYmluIGlzIHN0aWxsIHZpc2libGUpIGFuZCBhIGxpdHRsZVxuICogb3ZlciB0aGUgZnVsbCBiaW4gKHNvIGRlbnNlIG5laWdoYm91cnMganVzdCB0b3VjaCByYXRoZXIgdGhhbiBwaWxlIHVwKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwZWRNYXJrZXJQeChjb3VudDogbnVtYmVyLCByZWZDb3VudDogbnVtYmVyLCBiaW5QeDogbnVtYmVyLCBzY2FsZSA9IDEpOiBudW1iZXIge1xuICBjb25zdCBmID0gTWF0aC5zcXJ0KE1hdGgubWluKDEsIGNvdW50IC8gTWF0aC5tYXgoMSwgcmVmQ291bnQpKSk7XG4gIGNvbnN0IGQgPSBiaW5QeCAqICgwLjM1ICsgMC43NSAqIGYpICogc2NhbGU7XG4gIHJldHVybiBNYXRoLm1heChUUkFOU0NSSVBUX01JTl9QWCAqIHNjYWxlLCBNYXRoLm1pbihkLCBiaW5QeCAqIDEuMiAqIE1hdGgubWF4KHNjYWxlLCAxKSkpO1xufVxuXG4vKiogVGhlIGBwYCBxdWFudGlsZSAoMC4uMSkgb2YgYSBjb3VudCB2ZWN0b3Ig4oCUIGEgc2FtcGxlIG9mIGl0IGZvciBsYXJnZSB2ZWN0b3JzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHF1YW50aWxlT2YodmFsdWVzOiBBcnJheUxpa2U8bnVtYmVyPiwgcDogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgbiA9IHZhbHVlcy5sZW5ndGg7XG4gIGlmICghbikgcmV0dXJuIDA7XG4gIGNvbnN0IHN0ZXAgPSBNYXRoLm1heCgxLCBNYXRoLmZsb29yKG4gLyA0MDk2KSk7XG4gIGNvbnN0IHNhbXBsZTogbnVtYmVyW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpICs9IHN0ZXApIHNhbXBsZS5wdXNoKHZhbHVlc1tpXSk7XG4gIHNhbXBsZS5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gIHJldHVybiBzYW1wbGVbTWF0aC5taW4oc2FtcGxlLmxlbmd0aCAtIDEsIE1hdGguZmxvb3IocCAqIHNhbXBsZS5sZW5ndGgpKV07XG59XG5cbi8qKiB7QGxpbmsgdGlsZXNJblJlY3R9IGZvciBhIGdyaWQgd2hvc2UgdGlsZSAoMCwgMCkgc3RhcnRzIGF0IGBvcmlnaW5gLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRpbGVzSW5SZWN0RnJvbShcbiAgb3JpZ2luOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdLCByZWN0OiBEYXRhUmVjdCwgbGV2ZWw6IG51bWJlcixcbiAgbGV2ZWxzOiByZWFkb25seSBTcGF0aWFsVGlsZUxldmVsW10sIGJvdW5kcz86IFNwYXRpYWxCb3VuZHMgfCBudWxsLCBsaW1pdCA9IEluZmluaXR5LFxuKTogVGlsZUtleVtdIHtcbiAgY29uc3QgW294LCBveV0gPSBvcmlnaW47XG4gIGNvbnN0IHNoaWZ0ZWQgPSB7IHgwOiByZWN0LngwIC0gb3gsIHkwOiByZWN0LnkwIC0gb3ksIHgxOiByZWN0LngxIC0gb3gsIHkxOiByZWN0LnkxIC0gb3kgfTtcbiAgY29uc3QgYjogU3BhdGlhbEJvdW5kcyB8IG51bGwgPSBib3VuZHMgPyBbYm91bmRzWzBdIC0gb3gsIGJvdW5kc1sxXSAtIG95LCBib3VuZHNbMl0gLSBveCwgYm91bmRzWzNdIC0gb3ldIDogbnVsbDtcbiAgcmV0dXJuIHRpbGVzSW5SZWN0KHNoaWZ0ZWQsIGxldmVsLCBsZXZlbHMsIGIsIGxpbWl0KTtcbn1cblxuLyoqIEEgZGVuc2l0eSB3aW5kb3cgZnJvbSB0aGUgbm9uLWVtcHR5IGJpbnM6IDFzdCB0byA5OXRoIHBlcmNlbnRpbGUuICovXG5leHBvcnQgZnVuY3Rpb24gZGVuc2l0eUF1dG9SYW5nZSh2YWx1ZXM6IEFycmF5TGlrZTxudW1iZXI+KTogW251bWJlciwgbnVtYmVyXSB7XG4gIGNvbnN0IHBvc2l0aXZlOiBudW1iZXJbXSA9IFtdO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbHVlcy5sZW5ndGg7IGkrKykgaWYgKHZhbHVlc1tpXSA+IDApIHBvc2l0aXZlLnB1c2godmFsdWVzW2ldKTtcbiAgaWYgKCFwb3NpdGl2ZS5sZW5ndGgpIHJldHVybiBbMCwgMV07XG4gIHBvc2l0aXZlLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgY29uc3QgYXQgPSAocDogbnVtYmVyKSA9PiBwb3NpdGl2ZVtNYXRoLm1pbihwb3NpdGl2ZS5sZW5ndGggLSAxLCBNYXRoLmZsb29yKHAgKiBwb3NpdGl2ZS5sZW5ndGgpKV07XG4gIGNvbnN0IGxvID0gYXQoMC4wMSk7XG4gIGNvbnN0IGhpID0gYXQoMC45OSk7XG4gIHJldHVybiBoaSA+IGxvID8gW2xvLCBoaV0gOiBbMCwgaGkgfHwgMV07XG59XG5cbi8qKlxuICogQ29sb3VyIGRlbnNpdHkgYmlucyB0aHJvdWdoIGBsdXRgIG92ZXIgdGhlIHdpbmRvdyBgW2xvLCBoaV1gIOKAlCBYZW5pdW0gRXhwbG9yZXInc1xuICogXCJzY2FsZSB0aHJlc2hvbGRcIi4gQmlucyBhdCBvciBiZWxvdyBgbG9gIGFyZSB0cmFuc3BhcmVudCwgc28gZW1wdHkgdGlzc3VlIHNob3dzIHRoZVxuICogaW1hZ2UgdW5kZXIgaXQ7IGJpbnMgYXQgb3IgYWJvdmUgYGhpYCBzYXR1cmF0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yRGVuc2l0eVdpbmRvdyhcbiAgdmFsdWVzOiBBcnJheUxpa2U8bnVtYmVyPiwgbHV0OiByZWFkb25seSAocmVhZG9ubHkgW251bWJlciwgbnVtYmVyLCBudW1iZXJdKVtdLFxuICBvcGFjaXR5OiBudW1iZXIsIGxvOiBudW1iZXIsIGhpOiBudW1iZXIsXG4pOiBVaW50OEFycmF5IHtcbiAgY29uc3QgbiA9IHZhbHVlcy5sZW5ndGg7XG4gIGNvbnN0IHJnYmEgPSBuZXcgVWludDhBcnJheShuICogNCk7XG4gIGNvbnN0IHNwYW4gPSBoaSA+IGxvID8gaGkgLSBsbyA6IDE7XG4gIGNvbnN0IGEgPSBNYXRoLnJvdW5kKDI1NSAqIG9wYWNpdHkpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIGNvbnN0IHYgPSB2YWx1ZXNbaV07XG4gICAgaWYgKCEodiA+IGxvKSkgY29udGludWU7XG4gICAgY29uc3QgZiA9IE1hdGgubWluKDEsICh2IC0gbG8pIC8gc3Bhbik7XG4gICAgY29uc3QgYyA9IGx1dFtNYXRoLm1pbihsdXQubGVuZ3RoIC0gMSwgTWF0aC5yb3VuZChmICogKGx1dC5sZW5ndGggLSAxKSkpXTtcbiAgICByZ2JhWzQgKiBpXSA9IGNbMF07XG4gICAgcmdiYVs0ICogaSArIDFdID0gY1sxXTtcbiAgICByZ2JhWzQgKiBpICsgMl0gPSBjWzJdO1xuICAgIHJnYmFbNCAqIGkgKyAzXSA9IGE7XG4gIH1cbiAgcmV0dXJuIHJnYmE7XG59XG5cbi8qKlxuICogSW5mZXJubyAobWF0cGxvdGxpYiksIGFzIGFuIGlubGluZSBgW3N0b3AsIGNvbG91cl1gIHNjYWxlOiB0aGUgZGVuc2l0eSBtYXAncyBkZWZhdWx0LFxuICogYXMgaW4gWGVuaXVtIEV4cGxvcmVyLiBJbmxpbmUgYmVjYXVzZSB0aGUgY29sb3JtYXAgdHJlZSdzIGBJTkZFUk5PX0xVVGAga2V5IGlzIHJlc29sdmVkXG4gKiBhdCBydW50aW1lIGJ5IHRoZSBzdG9yZSwgd2hpY2ggdGhlIHJlbmRlcmVyIGRvZXMgbm90IHNlZS5cbiAqL1xuZXhwb3J0IGNvbnN0IElORkVSTk9fU0NBTEU6IFtudW1iZXIsIHN0cmluZ11bXSA9IFtcbiAgWzAsICcjMDAwMDA0J10sIFswLjEyNSwgJyMxYjBjNDEnXSwgWzAuMjUsICcjNGEwYzZiJ10sIFswLjM3NSwgJyM3ODFjNmQnXSwgWzAuNSwgJyNhNTJjNjAnXSxcbiAgWzAuNjI1LCAnI2NmNDQ0NiddLCBbMC43NSwgJyNlZDY5MjUnXSwgWzAuODc1LCAnI2ZiOWIwNiddLCBbMSwgJyNmY2ZmYTQnXSxcbl07XG4iXX0=
|