@jax-data-science/sci-image-visualizer 0.6.0 → 0.8.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/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/visualizer.contract.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +73 -0
- 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 +1487 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +6 -3
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +219 -8
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +8 -1
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +131 -2
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +77 -1
- package/esm2022/lib/routing-visualizer.service.mjs +14 -1
- package/esm2022/lib/spatial/spatial-tiles.mjs +649 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +848 -19
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3773 -78
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/lib/contracts/display-types.d.ts +96 -1
- package/lib/contracts/plot-type-contribution.contract.d.ts +9 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +70 -1
- package/lib/contracts/spatial-dataset.contract.d.ts +197 -0
- package/lib/contracts/visualizer.contract.d.ts +28 -1
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +20 -0
- 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 +315 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +49 -2
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +28 -2
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +35 -1
- package/lib/spatial/spatial-tiles.d.ts +259 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +288 -3
- package/package.json +1 -1
|
@@ -0,0 +1,1487 @@
|
|
|
1
|
+
import { Colormap, colormapFromLut } from 'napari-js';
|
|
2
|
+
import { ALL_GENES } from '../../contracts/ports/spatial-data.port';
|
|
3
|
+
import { NO_CATEGORY, NO_OBSERVATION, isCategoricalColumn, } from '../../contracts/spatial-dataset.contract';
|
|
4
|
+
import { DEFAULT_CATEGORICAL_PALETTE, MISSING_COLOR, contrastWindow, lutFor, parseHex, resolveCategoryColors, } from '../../spatial/spatial-encoding';
|
|
5
|
+
import { INFERNO_SCALE, POLYGON_LEVEL_MIN_CELL_PX, allGenesPlan, cellTypeColumnFor, cellsShown, colorDensityWindow, densityAutoRange, groupedMarkerPx, quantileOf, tilesInRectFrom, defaultGlyphFor, discreteColormapStops, glyphOutline, glyphRings, pixelsPerDataUnit, polygonLevelFor, tileId, tilesInRect, transcriptLevelFor, transcriptMarkerPx, typicalCellDiameter, visibleArea, visibleDataRect, geneBinSize, groupTranscripts, clipTranscripts, clusterColorMap, } from '../../spatial/spatial-tiles';
|
|
6
|
+
/** The all-gene pyramid's finest bin (250 µm source tiles / 128) and default level count, used
|
|
7
|
+
* to group a gene selection on the same ladder when a dataset has no pyramid. */
|
|
8
|
+
const PYRAMID_BASE_BIN_UM = 250 / 128;
|
|
9
|
+
const PYRAMID_LEVELS = 7;
|
|
10
|
+
/** Icons get a dark rim only while there are at most this many, at least this big (px). */
|
|
11
|
+
const GLYPH_OUTLINE_MAX = 20_000;
|
|
12
|
+
const GLYPH_OUTLINE_MIN_PX = 8;
|
|
13
|
+
const ORDER = [
|
|
14
|
+
'cellFill', 'cellOutline', 'nucleusOutline', 'density', 'transcripts', 'transcriptOutline',
|
|
15
|
+
];
|
|
16
|
+
/** Transcripts drawn at once. Past this a screen is solid colour anyway; the level
|
|
17
|
+
* policy keeps a normal view far below it. */
|
|
18
|
+
const MAX_TRANSCRIPTS = 400_000;
|
|
19
|
+
const MAX_CELL_TILES = 48;
|
|
20
|
+
const MAX_TRANSCRIPT_TILES = 36;
|
|
21
|
+
const MAX_BIN_TILES = 64;
|
|
22
|
+
const CAMERA_IDLE_MS = 120;
|
|
23
|
+
/** First retry of a view with a failed tile; doubles each time, up to MAX_TILE_RETRIES. */
|
|
24
|
+
const TILE_RETRY_MS = 1000;
|
|
25
|
+
const MAX_TILE_RETRIES = 3;
|
|
26
|
+
const UNASSIGNED_RGBA = [0.62, 0.62, 0.62, 0.55];
|
|
27
|
+
export class NapariSpatialTileLayers {
|
|
28
|
+
constructor(port, host) {
|
|
29
|
+
this.port = port;
|
|
30
|
+
this.host = host;
|
|
31
|
+
this.viewer = null;
|
|
32
|
+
this.cameraOff = null;
|
|
33
|
+
this.timer = null;
|
|
34
|
+
/** Set when a tile of the current plan failed to load (see fetchAll). */
|
|
35
|
+
this.planIncomplete = false;
|
|
36
|
+
/** Consecutive retries of an incomplete view. */
|
|
37
|
+
this.tileRetries = 0;
|
|
38
|
+
this.token = 0;
|
|
39
|
+
this.layers = new Map();
|
|
40
|
+
/** What each group currently shows, so an unchanged plan is a no-op. */
|
|
41
|
+
this.keys = new Map();
|
|
42
|
+
this.polygonsShown = false;
|
|
43
|
+
/** Rings currently drawn and the (dataset, set, tiles) they came from. */
|
|
44
|
+
this.currentRings = null;
|
|
45
|
+
this.cellGeometryKey = null;
|
|
46
|
+
this.currentNuclei = null;
|
|
47
|
+
this.cellStyleKey = null;
|
|
48
|
+
/** Selection identity → revision, so a change key can name a selection cheaply. */
|
|
49
|
+
this.lastSelection = null;
|
|
50
|
+
this.selectionRevision = 0;
|
|
51
|
+
/** µm per observation unit of the drawn dataset, for describing a grouped marker's area. */
|
|
52
|
+
this.micronsPerUnit = null;
|
|
53
|
+
/** Loads in flight, per layer label, for the loading badge. */
|
|
54
|
+
this.loading = new Map();
|
|
55
|
+
/** The loaded per-gene transcripts the in-view counts are taken from. */
|
|
56
|
+
this.countSource = null;
|
|
57
|
+
// ── hover ─────────────────────────────────────────────────────────────────────────
|
|
58
|
+
this.drawn = null;
|
|
59
|
+
this.hoverTypes = null;
|
|
60
|
+
/** Details already fetched, by hovered entry. */
|
|
61
|
+
this.hoverCache = new Map();
|
|
62
|
+
this.hoverKey = null;
|
|
63
|
+
this.hoverTimer = null;
|
|
64
|
+
this.densityCache = new Map();
|
|
65
|
+
this.countsCache = null;
|
|
66
|
+
/** The density window in use and the densest bin, for the panel's threshold control. */
|
|
67
|
+
this.densityStats = null;
|
|
68
|
+
}
|
|
69
|
+
// ── lifecycle ─────────────────────────────────────────────────────────────────────
|
|
70
|
+
attach(viewer) {
|
|
71
|
+
if (this.viewer === viewer)
|
|
72
|
+
return;
|
|
73
|
+
this.detach();
|
|
74
|
+
this.viewer = viewer;
|
|
75
|
+
this.cameraOff = viewer.camera.changed.connect(() => this.schedule());
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Group a gene selection for the zoom: one marker per gene-tree cluster (a gene in no
|
|
79
|
+
* cluster is its own) per bin of the pyramid ladder, starting at the finest bin whose
|
|
80
|
+
* markers are 14 px apart and stepping up while the markers would exceed the budget.
|
|
81
|
+
* Null to draw every transcript: zoomed in, with the selection within the budget.
|
|
82
|
+
*/
|
|
83
|
+
groupSelection(t, view, ladder, pxPerUnit) {
|
|
84
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
85
|
+
const genes = view.transcriptGenes;
|
|
86
|
+
const groups = view.transcriptGeneGroups;
|
|
87
|
+
const names = [...groups.map((g) => g.name), ...genes];
|
|
88
|
+
const clusterOf = genes.map((gene, slot) => {
|
|
89
|
+
const g = groups.findIndex((x) => x.genes.includes(gene));
|
|
90
|
+
return g >= 0 ? g : groups.length + slot;
|
|
91
|
+
});
|
|
92
|
+
const keyOf = (slot) => clusterOf[slot] ?? groups.length + slot;
|
|
93
|
+
let bin = ladder.start;
|
|
94
|
+
if (bin === null) {
|
|
95
|
+
// Every transcript, if they fit the max and none was cut off at the cap.
|
|
96
|
+
if (t.count <= budget && t.count < MAX_TRANSCRIPTS)
|
|
97
|
+
return null;
|
|
98
|
+
bin = ladder.baseBin;
|
|
99
|
+
}
|
|
100
|
+
const top = ladder.baseBin * 2 ** (ladder.levels - 1);
|
|
101
|
+
let grouped = groupTranscripts(t, bin, keyOf);
|
|
102
|
+
// Over the max: combine into larger markers, a level at a time.
|
|
103
|
+
while (grouped.tile.count > budget && bin < top) {
|
|
104
|
+
bin *= 2;
|
|
105
|
+
grouped = groupTranscripts(t, bin, keyOf);
|
|
106
|
+
}
|
|
107
|
+
const refCount = quantileOf(grouped.tile.weight, 0.95);
|
|
108
|
+
const binPx = bin * pxPerUnit;
|
|
109
|
+
const px = new Float32Array(grouped.tile.count);
|
|
110
|
+
for (let i = 0; i < grouped.tile.count; i++) {
|
|
111
|
+
px[i] = groupedMarkerPx(grouped.tile.weight[i], refCount, binPx, view.transcriptScale);
|
|
112
|
+
}
|
|
113
|
+
return { merged: grouped.tile, px, bin, group: grouped.group, names };
|
|
114
|
+
}
|
|
115
|
+
/** Report `label` loading while `work` is in flight. */
|
|
116
|
+
async track(label, work) {
|
|
117
|
+
this.loading.set(label, (this.loading.get(label) ?? 0) + 1);
|
|
118
|
+
this.host.loadingChanged?.([...this.loading.keys()]);
|
|
119
|
+
try {
|
|
120
|
+
return await work;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
const n = (this.loading.get(label) ?? 1) - 1;
|
|
124
|
+
if (n > 0)
|
|
125
|
+
this.loading.set(label, n);
|
|
126
|
+
else
|
|
127
|
+
this.loading.delete(label);
|
|
128
|
+
this.host.loadingChanged?.([...this.loading.keys()]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Transcripts of each selected gene inside `rect`: each entry counts for the transcripts it
|
|
133
|
+
* stands for (an aggregate at a coarse level holds several). Null without per-gene data.
|
|
134
|
+
*/
|
|
135
|
+
geneCountsIn(rect) {
|
|
136
|
+
const src = this.countSource;
|
|
137
|
+
if (!src)
|
|
138
|
+
return null;
|
|
139
|
+
const out = {};
|
|
140
|
+
for (const g of src.genes)
|
|
141
|
+
out[g] = 0;
|
|
142
|
+
const { x, y, weight, gene } = src.merged;
|
|
143
|
+
for (let i = 0; i < src.merged.count; i++) {
|
|
144
|
+
if (x[i] < rect.x0 || x[i] > rect.x1 || y[i] < rect.y0 || y[i] > rect.y1)
|
|
145
|
+
continue;
|
|
146
|
+
const name = src.genes[gene[i]];
|
|
147
|
+
if (name !== undefined)
|
|
148
|
+
out[name] += weight[i];
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
/** Whether `layer` is one of the overlays drawn here (density, cells, transcripts). */
|
|
153
|
+
owns(layer) {
|
|
154
|
+
for (const l of this.layers.values())
|
|
155
|
+
if (l === layer)
|
|
156
|
+
return true;
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
detach() {
|
|
160
|
+
if (this.hoverTimer)
|
|
161
|
+
clearTimeout(this.hoverTimer);
|
|
162
|
+
this.hoverTimer = null;
|
|
163
|
+
this.drawn = null;
|
|
164
|
+
this.cameraOff?.();
|
|
165
|
+
this.cameraOff = null;
|
|
166
|
+
if (this.timer)
|
|
167
|
+
clearTimeout(this.timer);
|
|
168
|
+
this.timer = null;
|
|
169
|
+
this.token++;
|
|
170
|
+
this.tileRetries = 0;
|
|
171
|
+
this.countSource = null;
|
|
172
|
+
this.loading.clear();
|
|
173
|
+
this.host.loadingChanged?.([]);
|
|
174
|
+
if (this.viewer) {
|
|
175
|
+
for (const layer of this.layers.values()) {
|
|
176
|
+
if (this.viewer.layers.items.includes(layer))
|
|
177
|
+
this.viewer.layers.remove(layer);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
this.layers.clear();
|
|
181
|
+
this.keys.clear();
|
|
182
|
+
this.setPolygonsShown(false);
|
|
183
|
+
this.viewer = null;
|
|
184
|
+
}
|
|
185
|
+
/** True while outlines are on screen — the service hides its dots then. */
|
|
186
|
+
get outlinesShown() {
|
|
187
|
+
return this.polygonsShown;
|
|
188
|
+
}
|
|
189
|
+
/** Dataset, view or selection changed: re-plan now rather than on camera idle. */
|
|
190
|
+
refresh() {
|
|
191
|
+
this.schedule(0);
|
|
192
|
+
}
|
|
193
|
+
/** Called right after the service adds its marker layer: everything goes back on top. */
|
|
194
|
+
afterObservations() {
|
|
195
|
+
const v = this.viewer;
|
|
196
|
+
if (!v)
|
|
197
|
+
return;
|
|
198
|
+
for (const g of ORDER) {
|
|
199
|
+
const layer = this.layers.get(g);
|
|
200
|
+
if (!layer)
|
|
201
|
+
continue;
|
|
202
|
+
if (v.layers.items.includes(layer))
|
|
203
|
+
v.layers.remove(layer);
|
|
204
|
+
v.layers.add(layer);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// ── planning ──────────────────────────────────────────────────────────────────────
|
|
208
|
+
schedule(delay = CAMERA_IDLE_MS) {
|
|
209
|
+
if (this.timer)
|
|
210
|
+
clearTimeout(this.timer);
|
|
211
|
+
this.timer = setTimeout(() => {
|
|
212
|
+
this.timer = null;
|
|
213
|
+
void this.plan();
|
|
214
|
+
}, delay);
|
|
215
|
+
}
|
|
216
|
+
async plan() {
|
|
217
|
+
const viewer = this.viewer;
|
|
218
|
+
const latest = this.host.latest();
|
|
219
|
+
if (!viewer || !latest)
|
|
220
|
+
return;
|
|
221
|
+
const [dataset, view, selection] = latest;
|
|
222
|
+
const token = ++this.token;
|
|
223
|
+
const stale = () => token !== this.token || this.viewer !== viewer;
|
|
224
|
+
this.planIncomplete = false;
|
|
225
|
+
if (!dataset) {
|
|
226
|
+
for (const g of ORDER)
|
|
227
|
+
this.drop(g);
|
|
228
|
+
this.dropCells();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const [w, h] = this.host.canvasSize();
|
|
232
|
+
const ref = dataset.imageRef;
|
|
233
|
+
const rect = visibleDataRect(viewer.camera.center, viewer.camera.zoom, w, h, ref);
|
|
234
|
+
const pxPerUnit = pixelsPerDataUnit(viewer.camera.zoom, ref);
|
|
235
|
+
if (!rect)
|
|
236
|
+
return;
|
|
237
|
+
void this.planEstimate(dataset, view, viewer, w, h, stale);
|
|
238
|
+
await Promise.all([
|
|
239
|
+
this.planDensity(dataset, view, stale),
|
|
240
|
+
this.planCells(dataset, view, selection, rect, pxPerUnit, stale),
|
|
241
|
+
this.planTranscripts(dataset, view, rect, pxPerUnit, stale),
|
|
242
|
+
]);
|
|
243
|
+
if (stale())
|
|
244
|
+
return;
|
|
245
|
+
this.host.geneCountsChanged?.(this.geneCountsIn(rect));
|
|
246
|
+
// A tile that failed left a hole the cache keys do not record, so try the same view
|
|
247
|
+
// again, backing off, a bounded number of times.
|
|
248
|
+
if (!this.planIncomplete) {
|
|
249
|
+
this.tileRetries = 0;
|
|
250
|
+
}
|
|
251
|
+
else if (this.tileRetries < MAX_TILE_RETRIES) {
|
|
252
|
+
this.schedule(TILE_RETRY_MS * 2 ** this.tileRetries++);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// ── cells ─────────────────────────────────────────────────────────────────────────
|
|
256
|
+
async planCells(dataset, view, selection, rect, pxPerUnit, stale) {
|
|
257
|
+
const tiled = dataset.polygonTiles;
|
|
258
|
+
const whole = !tiled && dataset.polygons && this.port.getPolygons;
|
|
259
|
+
if (!cellsShown(dataset, view) || (!tiled && !whole)) {
|
|
260
|
+
this.dropCells();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const diameter = typicalCellDiameter(dataset.observations.radius);
|
|
264
|
+
// Whole-dataset rings have one level and no coarser fallback, so they are drawn as
|
|
265
|
+
// soon as a cell is big enough to read as a shape rather than a dot.
|
|
266
|
+
const level = tiled
|
|
267
|
+
? polygonLevelFor(pxPerUnit, diameter, tiled.levels.length)
|
|
268
|
+
: (pxPerUnit * diameter >= POLYGON_LEVEL_MIN_CELL_PX[2] ? 0 : -1);
|
|
269
|
+
if (level < 0) {
|
|
270
|
+
this.dropCells();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
// Groups switched off in the list: their cells are left out of the geometry.
|
|
274
|
+
const hidden = await this.hiddenCodes(dataset, view);
|
|
275
|
+
if (stale())
|
|
276
|
+
return;
|
|
277
|
+
const label = view.cellSet === 'both' ? 'Cells and nuclei'
|
|
278
|
+
: view.cellSet === 'nucleus' ? 'Nuclei' : 'Cells';
|
|
279
|
+
const geometry = await this.track(label, this.cellGeometry(dataset, view, rect, level, hidden, stale));
|
|
280
|
+
if (!geometry)
|
|
281
|
+
return;
|
|
282
|
+
const { rings, nuclei, geometryKey } = geometry;
|
|
283
|
+
const geometryChanged = geometryKey !== this.cellGeometryKey;
|
|
284
|
+
const styleKey = [
|
|
285
|
+
geometryKey, view.cellColorMode, view.cellColorGene, view.cellSingleColor,
|
|
286
|
+
this.cellTypeColumnName(dataset, view),
|
|
287
|
+
this.selectionRev(selection), view.logScale, view.percentileClip.join(),
|
|
288
|
+
JSON.stringify(view.continuousColormap), view.cellDraw, view.cellOpacity,
|
|
289
|
+
].join('|');
|
|
290
|
+
const present = ['cellFill', 'cellOutline', 'nucleusOutline'].some((g) => {
|
|
291
|
+
const l = this.layers.get(g);
|
|
292
|
+
return l && this.viewer.layers.items.includes(l);
|
|
293
|
+
});
|
|
294
|
+
if (!geometryChanged && styleKey === this.cellStyleKey && present) {
|
|
295
|
+
this.setPolygonsShown(true);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const colors = await this.cellColors(dataset, view, selection, rings.observation);
|
|
299
|
+
if (stale())
|
|
300
|
+
return;
|
|
301
|
+
this.currentRings = rings;
|
|
302
|
+
this.currentNuclei = nuclei;
|
|
303
|
+
// A geometry missing a failed tile is drawn but not remembered, so the retry refetches it.
|
|
304
|
+
this.cellGeometryKey = this.planIncomplete ? null : geometryKey;
|
|
305
|
+
this.cellStyleKey = styleKey;
|
|
306
|
+
const ref = dataset.imageRef;
|
|
307
|
+
const common = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
|
|
308
|
+
const fill = view.cellDraw !== 'outline';
|
|
309
|
+
const outline = view.cellDraw !== 'fill';
|
|
310
|
+
this.upsertShapes('cellFill', fill, geometryChanged, rings, {
|
|
311
|
+
name: 'cells', draw: 'fill', opacity: view.cellOpacity, ...colors, ...common,
|
|
312
|
+
});
|
|
313
|
+
this.upsertShapes('cellOutline', outline, geometryChanged, rings, fill
|
|
314
|
+
// Over a fill, a dark outline separates neighbours of the same type.
|
|
315
|
+
? { name: 'cell outlines', draw: 'outline', color: [0.08, 0.08, 0.1, 1], opacity: 0.7, ...common }
|
|
316
|
+
: { name: 'cell outlines', draw: 'outline', opacity: 1, ...colors, ...common });
|
|
317
|
+
// "Both": nuclei outlined over the cells, light so they read against any fill.
|
|
318
|
+
if (nuclei) {
|
|
319
|
+
this.upsertShapes('nucleusOutline', true, geometryChanged, nuclei, {
|
|
320
|
+
name: 'nucleus outlines', draw: 'outline', color: [0.95, 0.95, 0.98, 1], opacity: 0.8, ...common,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
this.drop('nucleusOutline');
|
|
325
|
+
}
|
|
326
|
+
this.setPolygonsShown(true);
|
|
327
|
+
}
|
|
328
|
+
selectionRev(selection) {
|
|
329
|
+
if (selection !== this.lastSelection) {
|
|
330
|
+
this.lastSelection = selection;
|
|
331
|
+
this.selectionRevision++;
|
|
332
|
+
}
|
|
333
|
+
return this.selectionRevision;
|
|
334
|
+
}
|
|
335
|
+
/** Per-shape values + colormap for the rings' owners. */
|
|
336
|
+
/**
|
|
337
|
+
* Per-shape values + colormap for the rings' owners, by the view's cell-colour mode
|
|
338
|
+
* (Xenium Explorer's "Cell Color"). A selection mutes what it leaves out.
|
|
339
|
+
*/
|
|
340
|
+
async cellColors(dataset, view, selection, owners) {
|
|
341
|
+
const muted = selection.count > 0 ? selection.mask : null;
|
|
342
|
+
const mode = view.cellColorMode;
|
|
343
|
+
if (mode === 'single') {
|
|
344
|
+
const [r, g, b] = parseHex(view.cellSingleColor);
|
|
345
|
+
return { color: [r / 255, g / 255, b / 255, 1] };
|
|
346
|
+
}
|
|
347
|
+
const continuous = async (raw, log) => {
|
|
348
|
+
const values = new Float32Array(owners.length);
|
|
349
|
+
for (let i = 0; i < owners.length; i++) {
|
|
350
|
+
const v = raw[owners[i]] ?? NaN;
|
|
351
|
+
values[i] = log ? Math.log1p(Math.max(0, v)) : v;
|
|
352
|
+
}
|
|
353
|
+
const [lo, hi] = contrastWindow(log ? raw.map((v) => Math.log1p(Math.max(0, v))) : raw, view.percentileClip[0], view.percentileClip[1]);
|
|
354
|
+
return {
|
|
355
|
+
values,
|
|
356
|
+
colormap: colormapFromLut('spatial-continuous', this.host.continuousLut(view)),
|
|
357
|
+
contrastLimits: [lo, hi],
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
if (mode === 'gene' && view.cellColorGene) {
|
|
361
|
+
return continuous(await this.port.getFeatureVector(view.cellColorGene), true);
|
|
362
|
+
}
|
|
363
|
+
if (mode === 'transcriptDensity' && dataset.columns.some((c) => c.name === 'transcript_density')) {
|
|
364
|
+
const column = await this.port.getColumn('transcript_density');
|
|
365
|
+
if (!isCategoricalColumn(column))
|
|
366
|
+
return continuous(column.values, false);
|
|
367
|
+
}
|
|
368
|
+
const name = mode === 'segmentation' && dataset.columns.some((c) => c.name === 'segmentation_method')
|
|
369
|
+
? 'segmentation_method'
|
|
370
|
+
: this.cellTypeColumnName(dataset, view);
|
|
371
|
+
const codes = name ? await this.categoricalCodes(name) : null;
|
|
372
|
+
const { colormap, valueOf } = this.categoricalColormap(codes?.meta ?? null);
|
|
373
|
+
const values = new Float32Array(owners.length);
|
|
374
|
+
for (let i = 0; i < owners.length; i++) {
|
|
375
|
+
const o = owners[i];
|
|
376
|
+
const code = !codes || (muted && !muted[o]) ? -1 : codes.codes[o];
|
|
377
|
+
values[i] = valueOf(code === NO_CATEGORY ? -1 : code);
|
|
378
|
+
}
|
|
379
|
+
return { values, colormap, contrastLimits: [0, 1] };
|
|
380
|
+
}
|
|
381
|
+
/** Codes of the group column that are switched off, or null when none are. */
|
|
382
|
+
async hiddenCodes(dataset, view) {
|
|
383
|
+
if (!view.hiddenGroups.length)
|
|
384
|
+
return null;
|
|
385
|
+
const name = this.cellTypeColumnName(dataset, view);
|
|
386
|
+
const col = name ? await this.categoricalCodes(name) : null;
|
|
387
|
+
if (!col || col.meta.kind !== 'categorical')
|
|
388
|
+
return null;
|
|
389
|
+
const off = new Set(view.hiddenGroups);
|
|
390
|
+
const hidden = Uint8Array.from(col.meta.categories, (c) => (off.has(c) ? 1 : 0));
|
|
391
|
+
return { codes: col.codes, hidden };
|
|
392
|
+
}
|
|
393
|
+
cellTypeColumnName(dataset, view) {
|
|
394
|
+
return cellTypeColumnFor(dataset, view);
|
|
395
|
+
}
|
|
396
|
+
async categoricalCodes(name) {
|
|
397
|
+
const column = await this.port.getColumn(name);
|
|
398
|
+
return isCategoricalColumn(column) ? { codes: column.codes, meta: column.meta } : null;
|
|
399
|
+
}
|
|
400
|
+
categoricalColormap(meta) {
|
|
401
|
+
const hex = meta && meta.kind === 'categorical'
|
|
402
|
+
? resolveCategoryColors(meta)
|
|
403
|
+
: [DEFAULT_CATEGORICAL_PALETTE[0]];
|
|
404
|
+
const rgb = hex.map(parseHex);
|
|
405
|
+
const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
|
|
406
|
+
return { colormap: new Colormap('spatial-categories', stops), valueOf, rgb };
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* The cell rings (and, for "both", the nucleus rings) covering `rect` at `level`, minus
|
|
410
|
+
* the hidden groups — reused when nothing that decides them changed. Null when the
|
|
411
|
+
* view went stale or the dataset has no set to draw.
|
|
412
|
+
*/
|
|
413
|
+
async cellGeometry(dataset, view, rect, level, hidden, stale) {
|
|
414
|
+
const tiled = dataset.polygonTiles;
|
|
415
|
+
const hiddenKey = view.hiddenGroups.join('\u0001');
|
|
416
|
+
let rings;
|
|
417
|
+
let nuclei = null;
|
|
418
|
+
let geometryKey;
|
|
419
|
+
if (tiled) {
|
|
420
|
+
const both = view.cellSet === 'both';
|
|
421
|
+
const set = !both && view.cellSet && tiled.sets.some((s) => s.name === view.cellSet)
|
|
422
|
+
? view.cellSet : (tiled.defaultSet ?? tiled.sets[0]?.name);
|
|
423
|
+
if (!set)
|
|
424
|
+
return null;
|
|
425
|
+
const nucleusSet = both ? tiled.sets.find((s) => s.name !== set)?.name : undefined;
|
|
426
|
+
const keys = tilesInRect(rect, level, tiled.levels, tiled.bounds, MAX_CELL_TILES);
|
|
427
|
+
geometryKey = `${dataset.id}|${set}|${nucleusSet ?? ''}|${hiddenKey}|${keys.map(tileId).join(',')}`;
|
|
428
|
+
if (geometryKey === this.cellGeometryKey && this.currentRings) {
|
|
429
|
+
rings = this.currentRings;
|
|
430
|
+
nuclei = this.currentNuclei;
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
const [tiles, nucleusTiles] = await Promise.all([
|
|
434
|
+
this.fetchAll(keys, (k) => this.port.getPolygonTile(set, k.level, k.gx, k.gy)),
|
|
435
|
+
nucleusSet
|
|
436
|
+
? this.fetchAll(keys, (k) => this.port.getPolygonTile(nucleusSet, k.level, k.gx, k.gy))
|
|
437
|
+
: Promise.resolve(null),
|
|
438
|
+
]);
|
|
439
|
+
if (stale())
|
|
440
|
+
return null;
|
|
441
|
+
rings = filterRings(mergePolygonTiles(tiles), hidden);
|
|
442
|
+
nuclei = nucleusTiles ? filterRings(mergePolygonTiles(nucleusTiles), hidden) : null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
geometryKey = `${dataset.id}|whole|${hiddenKey}`;
|
|
447
|
+
if (geometryKey === this.cellGeometryKey && this.currentRings) {
|
|
448
|
+
rings = this.currentRings;
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
const polys = await this.port.getPolygons();
|
|
452
|
+
if (stale())
|
|
453
|
+
return null;
|
|
454
|
+
// Whole-dataset rings are index-aligned with the observations.
|
|
455
|
+
rings = filterRings({ ...polys, observation: Uint32Array.from({ length: polys.count }, (_v, i) => i) }, hidden);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return { rings, nuclei, geometryKey };
|
|
459
|
+
}
|
|
460
|
+
// ── transcripts ───────────────────────────────────────────────────────────────────
|
|
461
|
+
async planTranscripts(dataset, view, rect, pxPerUnit, stale) {
|
|
462
|
+
const mode = view.transcriptMode;
|
|
463
|
+
const job = (mode === 'circles' || mode === 'glyphs')
|
|
464
|
+
&& (this.port.getTranscriptTile || (this.port.getTranscriptGeneBins && dataset.transcriptGeneBins))
|
|
465
|
+
? (view.transcriptAllGenes
|
|
466
|
+
? this.allGenesJob(dataset, view, rect, pxPerUnit)
|
|
467
|
+
: this.geneJob(dataset, view, rect, pxPerUnit))
|
|
468
|
+
: null;
|
|
469
|
+
if (!job) {
|
|
470
|
+
this.drop('transcripts');
|
|
471
|
+
this.drop('transcriptOutline');
|
|
472
|
+
this.drawn = null;
|
|
473
|
+
this.countSource = null;
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
// Marker sizes follow the zoom, so the zoom is part of the key; a pan that keeps
|
|
477
|
+
// the same tiles on screen changes nothing.
|
|
478
|
+
const planKey = [
|
|
479
|
+
dataset.id, mode, job.key, view.transcriptColorBy, this.cellTypeColumnName(dataset, view),
|
|
480
|
+
view.transcriptScale, view.transcriptOpacity, JSON.stringify(view.transcriptGlyphs),
|
|
481
|
+
pxPerUnit.toPrecision(4), view.hiddenGroups.join('\u0001'), view.transcriptHiddenGenes.join(','),
|
|
482
|
+
JSON.stringify(view.transcriptGeneColors), JSON.stringify(view.transcriptGeneGroups),
|
|
483
|
+
].join('|');
|
|
484
|
+
const current = this.layers.get('transcripts');
|
|
485
|
+
if (planKey === this.keys.get('transcripts') && current && this.viewer.layers.items.includes(current)) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const loaded = await this.track('Transcripts', job.load());
|
|
489
|
+
if (stale())
|
|
490
|
+
return;
|
|
491
|
+
// Per-gene counts in view come from what was loaded, before hidden genes are dropped:
|
|
492
|
+
// a hidden gene still has transcripts there. Summed density grids (no per-gene levels,
|
|
493
|
+
// zoomed out) hold clusters, not genes: no per-gene counts there, rather than a guess.
|
|
494
|
+
this.countSource = (loaded.kind ?? job.kind) === 'genes' && !loaded.clustered
|
|
495
|
+
? { merged: loaded.merged, genes: [...view.transcriptGenes] } : null;
|
|
496
|
+
const hidden = await this.hiddenCodes(dataset, view);
|
|
497
|
+
if (stale())
|
|
498
|
+
return;
|
|
499
|
+
// Density-grid markers carry no cells and were built from the visible genes only.
|
|
500
|
+
const filtered = loaded.clustered ? { merged: loaded.merged, px: loaded.px }
|
|
501
|
+
: filterTranscripts(loaded.merged, loaded.px, hidden, (loaded.kind ?? job.kind) === 'genes' ? hiddenGeneSlots(view) : null);
|
|
502
|
+
let { merged, px } = filtered;
|
|
503
|
+
let selectionBin = loaded.clustered?.bin ?? null;
|
|
504
|
+
let entryGroup = loaded.clustered?.group ?? null;
|
|
505
|
+
let groupNames = loaded.clustered?.names ?? null;
|
|
506
|
+
if (loaded.ladder) {
|
|
507
|
+
const g = this.groupSelection(merged, view, loaded.ladder, pxPerUnit);
|
|
508
|
+
if (g)
|
|
509
|
+
({ merged, px, bin: selectionBin, group: entryGroup, names: groupNames } = g);
|
|
510
|
+
}
|
|
511
|
+
// A bin of the all-gene pyramid mixes genes and carries none, so it cannot be coloured
|
|
512
|
+
// by gene: colour it by its dominant cell's type until individual transcripts show.
|
|
513
|
+
const kind = loaded.kind ?? job.kind;
|
|
514
|
+
const colorView = kind === 'bins' && view.transcriptColorBy !== 'cellType'
|
|
515
|
+
? { ...view, transcriptColorBy: 'cellType' }
|
|
516
|
+
// Density-grid markers have no cell to take a type from: they take their cluster's colour.
|
|
517
|
+
: loaded.clustered && view.transcriptColorBy === 'cellType'
|
|
518
|
+
? { ...view, transcriptColorBy: 'cluster' } : view;
|
|
519
|
+
// Each entry's cluster: its marker's group, or the gene-tree group its gene is in.
|
|
520
|
+
const geneCluster = view.transcriptGenes.map((g) => view.transcriptGeneGroups.find((x) => x.genes.includes(g))?.name ?? g);
|
|
521
|
+
const clusterOf = (i) => (entryGroup && groupNames
|
|
522
|
+
? groupNames[entryGroup[i]] ?? null
|
|
523
|
+
: geneCluster[merged.gene[i]] ?? null);
|
|
524
|
+
const faces = await this.transcriptColors(dataset, colorView, merged, kind === 'genes' ? clusterOf : undefined);
|
|
525
|
+
if (stale())
|
|
526
|
+
return;
|
|
527
|
+
if (this.planIncomplete)
|
|
528
|
+
this.keys.delete('transcripts');
|
|
529
|
+
else
|
|
530
|
+
this.keys.set('transcripts', planKey);
|
|
531
|
+
const diam = px.map((d) => d / pxPerUnit);
|
|
532
|
+
this.drawn = {
|
|
533
|
+
kind: loaded.kind ?? job.kind,
|
|
534
|
+
bin: selectionBin ? { size: selectionBin, origin: loaded.clustered?.origin ?? [0, 0] }
|
|
535
|
+
: (loaded.kind ? loaded.bin : job.bin),
|
|
536
|
+
merged, radius: diam.map((d) => d / 2),
|
|
537
|
+
genes: [...view.transcriptGenes], ref: dataset.imageRef ?? null, grid: null,
|
|
538
|
+
...(entryGroup && groupNames ? { entryGroup, groupNames } : {}),
|
|
539
|
+
...(loaded.clustered ? { groupGenes: loaded.clustered.genes } : {}),
|
|
540
|
+
};
|
|
541
|
+
this.hoverCache.clear();
|
|
542
|
+
this.micronsPerUnit = dataset.micronsPerUnit ?? null;
|
|
543
|
+
const typeColumn = this.cellTypeColumnName(dataset, view);
|
|
544
|
+
this.hoverTypes = typeColumn ? await this.categoricalCodes(typeColumn).catch(() => null) : null;
|
|
545
|
+
if (stale())
|
|
546
|
+
return;
|
|
547
|
+
const ref = dataset.imageRef;
|
|
548
|
+
const place = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
|
|
549
|
+
if (mode === 'circles') {
|
|
550
|
+
this.drop('transcriptOutline');
|
|
551
|
+
this.drawTranscriptCircles(merged, diam, faces.rgba, view, place);
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
this.drawTranscriptGlyphs(merged, diam, faces, view, place, pxPerUnit);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
/** One sized circle per entry, the size saying how many transcripts it stands for. */
|
|
558
|
+
drawTranscriptCircles(merged, diam, rgba, view, { scale, translate }) {
|
|
559
|
+
const positions = new Float32Array(merged.count * 2);
|
|
560
|
+
for (let i = 0; i < merged.count; i++) {
|
|
561
|
+
positions[2 * i] = merged.x[i];
|
|
562
|
+
positions[2 * i + 1] = merged.y[i];
|
|
563
|
+
}
|
|
564
|
+
const layer = this.viewer.addPoints(positions, {
|
|
565
|
+
name: 'transcripts',
|
|
566
|
+
size: diam,
|
|
567
|
+
faceColor: rgba,
|
|
568
|
+
// A dark rim: a transcript coloured by its cell's type is otherwise the same
|
|
569
|
+
// colour as the cell fill it sits on, and vanishes into it.
|
|
570
|
+
borderColor: [0.04, 0.04, 0.05, 0.9],
|
|
571
|
+
borderWidth: 0.18 * median(diam),
|
|
572
|
+
opacity: view.transcriptOpacity,
|
|
573
|
+
scale,
|
|
574
|
+
translate,
|
|
575
|
+
});
|
|
576
|
+
this.replace('transcripts', layer);
|
|
577
|
+
}
|
|
578
|
+
drawTranscriptGlyphs(merged, diam, faces, view, { scale, translate }, pxPerUnit) {
|
|
579
|
+
// Glyphs: each entry becomes its gene's icon polygon, filled through a discrete
|
|
580
|
+
// colormap and outlined dark so small icons stay readable over the tissue. With every
|
|
581
|
+
// gene drawn there is one icon for all of them — 18,000 shapes would say nothing.
|
|
582
|
+
const genes = view.transcriptGenes;
|
|
583
|
+
const glyphFor = (slot) => view.transcriptGlyphs[genes[slot]] ?? defaultGlyphFor(slot);
|
|
584
|
+
const single = view.transcriptAllGenes
|
|
585
|
+
? glyphOutline(view.transcriptGlyphs[ALL_GENES] ?? 'circle')
|
|
586
|
+
: null;
|
|
587
|
+
const outlines = single ? [] : genes.map((_g, slot) => glyphOutline(glyphFor(slot)));
|
|
588
|
+
const radius = diam.map((d) => d / 2);
|
|
589
|
+
const { coords, offsets } = glyphRings(merged.x, merged.y, radius, (i) => single ?? outlines[merged.gene[i]]);
|
|
590
|
+
const fill = this.viewer.addShapes(coords, offsets, {
|
|
591
|
+
name: 'transcripts',
|
|
592
|
+
draw: 'fill',
|
|
593
|
+
values: faces.values,
|
|
594
|
+
colormap: faces.colormap,
|
|
595
|
+
contrastLimits: [0, 1],
|
|
596
|
+
opacity: view.transcriptOpacity,
|
|
597
|
+
scale,
|
|
598
|
+
translate,
|
|
599
|
+
});
|
|
600
|
+
this.replace('transcripts', fill);
|
|
601
|
+
// A dark rim keeps a few large icons readable over the tissue; on many small ones the
|
|
602
|
+
// rims merge into a solid dark sheet that hides every colour, so they are left off.
|
|
603
|
+
const medianPx = median(diam) * pxPerUnit;
|
|
604
|
+
if (merged.count > GLYPH_OUTLINE_MAX || medianPx < GLYPH_OUTLINE_MIN_PX) {
|
|
605
|
+
this.drop('transcriptOutline');
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const edge = this.viewer.addShapes(coords, offsets, {
|
|
609
|
+
name: 'transcript outlines',
|
|
610
|
+
draw: 'outline',
|
|
611
|
+
color: [0.05, 0.05, 0.05, 1],
|
|
612
|
+
opacity: Math.min(1, view.transcriptOpacity + 0.1),
|
|
613
|
+
scale,
|
|
614
|
+
translate,
|
|
615
|
+
});
|
|
616
|
+
this.replace('transcriptOutline', edge);
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Tooltip lines for the transcript marker under world point `(wx, wy)`, or null.
|
|
620
|
+
*
|
|
621
|
+
* Returns what is known at once (gene, count, cell type); anything that needs the
|
|
622
|
+
* server — distinct genes in a group, its top genes and cells, the cell's display id —
|
|
623
|
+
* arrives through `onDetails` once the pointer has rested on the marker briefly.
|
|
624
|
+
*/
|
|
625
|
+
hoverAt(wx, wy, radiusWorld, onDetails) {
|
|
626
|
+
const d = this.drawn;
|
|
627
|
+
const layer = this.layers.get('transcripts');
|
|
628
|
+
if (!d || !layer || !this.viewer?.layers.items.includes(layer) || !d.merged.count) {
|
|
629
|
+
this.hoverKey = null;
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
const sx = d.ref?.scale?.[0] ?? 1;
|
|
633
|
+
const sy = d.ref?.scale?.[1] ?? 1;
|
|
634
|
+
const x = (wx - (d.ref?.translate?.[0] ?? 0)) / sx;
|
|
635
|
+
const y = (wy - (d.ref?.translate?.[1] ?? 0)) / sy;
|
|
636
|
+
const i = pickNearest(d, x, y, radiusWorld / Math.abs(sx));
|
|
637
|
+
if (i < 0) {
|
|
638
|
+
this.hoverKey = null;
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
const key = `${d.kind}|${d.merged.x[i]}|${d.merged.y[i]}|${d.merged.gene[i]}`;
|
|
642
|
+
const cached = this.hoverCache.get(key);
|
|
643
|
+
if (cached)
|
|
644
|
+
return cached;
|
|
645
|
+
if (key !== this.hoverKey) {
|
|
646
|
+
this.hoverKey = key;
|
|
647
|
+
if (this.hoverTimer)
|
|
648
|
+
clearTimeout(this.hoverTimer);
|
|
649
|
+
this.hoverTimer = setTimeout(() => void this.fetchDetails(d, i, key, onDetails), 150);
|
|
650
|
+
}
|
|
651
|
+
return this.describe(d, i, null);
|
|
652
|
+
}
|
|
653
|
+
async fetchDetails(d, i, key, onDetails) {
|
|
654
|
+
if (!this.port.getTranscriptSummary || this.hoverKey !== key)
|
|
655
|
+
return;
|
|
656
|
+
const obs = d.merged.observation[i];
|
|
657
|
+
const cells = obs === NO_OBSERVATION ? [] : [obs];
|
|
658
|
+
let box;
|
|
659
|
+
if ((d.kind === 'bins' || d.kind === 'genes') && d.bin) {
|
|
660
|
+
const { size, origin } = d.bin;
|
|
661
|
+
const bx = Math.floor((d.merged.x[i] - origin[0]) / size);
|
|
662
|
+
const by = Math.floor((d.merged.y[i] - origin[1]) / size);
|
|
663
|
+
const x0 = origin[0] + bx * size;
|
|
664
|
+
const y0 = origin[1] + by * size;
|
|
665
|
+
box = [x0, y0, x0 + size, y0 + size];
|
|
666
|
+
}
|
|
667
|
+
else if (d.kind === 'individual') {
|
|
668
|
+
const e = 0.02;
|
|
669
|
+
box = [d.merged.x[i] - e, d.merged.y[i] - e, d.merged.x[i] + e, d.merged.y[i] + e];
|
|
670
|
+
}
|
|
671
|
+
const genes = d.groupGenes && d.entryGroup ? d.groupGenes[d.entryGroup[i]] : undefined;
|
|
672
|
+
try {
|
|
673
|
+
const summary = await this.port.getTranscriptSummary({ box, cells, ...(genes ? { genes } : {}) });
|
|
674
|
+
const lines = this.describe(d, i, summary);
|
|
675
|
+
this.hoverCache.set(key, lines);
|
|
676
|
+
if (this.hoverKey === key)
|
|
677
|
+
onDetails(lines);
|
|
678
|
+
}
|
|
679
|
+
catch (err) {
|
|
680
|
+
console.warn('[napari-js] transcript details unavailable', err);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/** The tooltip text for entry `i`, with the server's details when they have arrived. */
|
|
684
|
+
describe(d, i, s) {
|
|
685
|
+
const t = d.merged;
|
|
686
|
+
const n = t.weight[i];
|
|
687
|
+
const obs = t.observation[i];
|
|
688
|
+
const fmt = (v) => v.toLocaleString();
|
|
689
|
+
const typeOf = (o) => {
|
|
690
|
+
const types = this.hoverTypes;
|
|
691
|
+
if (!types || o === NO_OBSERVATION || types.meta.kind !== 'categorical')
|
|
692
|
+
return null;
|
|
693
|
+
const c = types.codes[o];
|
|
694
|
+
return c === NO_CATEGORY ? null : types.meta.categories[c] ?? null;
|
|
695
|
+
};
|
|
696
|
+
const cellLine = (o, prefix) => {
|
|
697
|
+
if (o === NO_OBSERVATION)
|
|
698
|
+
return 'outside any cell';
|
|
699
|
+
const id = s?.cellIds?.[o] ?? `#${o}`;
|
|
700
|
+
const type = typeOf(o);
|
|
701
|
+
return `${prefix} ${id}${type ? ` · ${type}` : ''}`;
|
|
702
|
+
};
|
|
703
|
+
if (d.kind === 'bins') {
|
|
704
|
+
const lines = [`${fmt(n)} transcripts · all genes`];
|
|
705
|
+
if (d.bin)
|
|
706
|
+
lines.push(`${d.bin.size.toFixed(1)} × ${d.bin.size.toFixed(1)} µm area`);
|
|
707
|
+
if (s?.transcripts !== undefined) {
|
|
708
|
+
lines.push(`${fmt(s.genes ?? 0)} distinct genes · ${fmt(s.cells ?? 0)} cell${s.cells === 1 ? '' : 's'}`
|
|
709
|
+
+ (s.unassigned ? ` · ${fmt(s.unassigned)} outside cells` : ''));
|
|
710
|
+
if (s.topGenes?.length) {
|
|
711
|
+
lines.push(`top genes: ${s.topGenes.slice(0, 5).map((g) => `${g.name} ${fmt(g.count)}`).join(', ')}`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
lines.push(cellLine(obs, 'mostly cell'));
|
|
715
|
+
if (!s && this.port.getTranscriptSummary)
|
|
716
|
+
lines.push('loading details…');
|
|
717
|
+
return lines;
|
|
718
|
+
}
|
|
719
|
+
if (d.kind === 'individual') {
|
|
720
|
+
const gene = s?.topGenes?.[0]?.name;
|
|
721
|
+
return [
|
|
722
|
+
gene ? `${gene} transcript` : 'Transcript',
|
|
723
|
+
cellLine(obs, 'in cell'),
|
|
724
|
+
...(!s && this.port.getTranscriptSummary ? ['loading details…'] : []),
|
|
725
|
+
];
|
|
726
|
+
}
|
|
727
|
+
const gene = d.genes[t.gene[i]] ?? 'transcript';
|
|
728
|
+
if (d.bin) {
|
|
729
|
+
const um = d.bin.size * (this.micronsPerUnit ?? 1);
|
|
730
|
+
const group = d.entryGroup && d.groupNames ? d.groupNames[d.entryGroup[i]] : gene;
|
|
731
|
+
const top = s?.topGenes?.length
|
|
732
|
+
? [s.topGenes.slice(0, 6).map((g) => `${g.name} ${fmt(g.count)}`).join(', ')] : [];
|
|
733
|
+
return [
|
|
734
|
+
`${group} · ${fmt(n)} transcript${n === 1 ? '' : 's'}`,
|
|
735
|
+
...(d.groupGenes ? top : group !== gene ? [`mostly ${gene}`] : []),
|
|
736
|
+
`${um.toFixed(1)} × ${um.toFixed(1)} µm area · zoom in to split`,
|
|
737
|
+
...(obs === NO_OBSERVATION && d.groupGenes ? [] : [cellLine(obs, 'mostly cell')]),
|
|
738
|
+
...(!s && d.groupGenes && this.port.getTranscriptSummary ? ['loading details…'] : []),
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
return n > 1
|
|
742
|
+
? [`${gene} · ${fmt(n)} transcripts`, 'grouped: zoom in to split', cellLine(obs, 'near cell')]
|
|
743
|
+
: [`${gene} transcript`, cellLine(obs, 'in cell')];
|
|
744
|
+
}
|
|
745
|
+
/** Physical marker size needs µm; null when the dataset's unit is unknown. */
|
|
746
|
+
pxPerMicron(dataset, pxPerUnit) {
|
|
747
|
+
return dataset.micronsPerUnit ? pxPerUnit / dataset.micronsPerUnit : undefined;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* The chosen genes, at the level the zoom calls for — or coarser, while the markers in
|
|
751
|
+
* view would exceed the budget.
|
|
752
|
+
*/
|
|
753
|
+
geneJob(dataset, view, rect, pxPerUnit) {
|
|
754
|
+
const meta = dataset.transcriptTiles;
|
|
755
|
+
const genes = view.transcriptGenes;
|
|
756
|
+
if (!meta || !genes.length)
|
|
757
|
+
return null;
|
|
758
|
+
const first = transcriptLevelFor(pxPerUnit, meta.levels);
|
|
759
|
+
const keysAt = (l) => tilesInRect(rect, l, meta.levels, meta.bounds, MAX_TRANSCRIPT_TILES);
|
|
760
|
+
const query = { genes, quality: view.transcriptQuality };
|
|
761
|
+
const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
|
|
762
|
+
const mx = (rect.x1 - rect.x0) * 0.25;
|
|
763
|
+
const my = (rect.y1 - rect.y0) * 0.25;
|
|
764
|
+
const around = { x0: rect.x0 - mx, y0: rect.y0 - my, x1: rect.x1 + mx, y1: rect.y1 + my };
|
|
765
|
+
// Zoomed out, each gene's transcripts are grouped on the all-gene pyramid's bin ladder,
|
|
766
|
+
// so a gene selection reads like "all genes" does: one marker per gene per area, sized
|
|
767
|
+
// by how many it holds; zoomed in far enough, every transcript is its own marker.
|
|
768
|
+
const ladder = dataset.transcriptBins?.levels;
|
|
769
|
+
const baseBin = ladder?.[0]?.binSize
|
|
770
|
+
?? (dataset.micronsPerUnit ? PYRAMID_BASE_BIN_UM / dataset.micronsPerUnit : 0);
|
|
771
|
+
const bin = geneBinSize(pxPerUnit, baseBin, ladder?.length ?? PYRAMID_LEVELS);
|
|
772
|
+
// Zoomed out to bins as wide as the density grid, a selection is drawn from the per-gene
|
|
773
|
+
// density grids — one cached request per cluster — rather than 10x's coarse per-gene
|
|
774
|
+
// tiles, which take minutes for a few hundred genes.
|
|
775
|
+
// With the pyramid's per-gene levels, every zoom of a selection reads them: the level the
|
|
776
|
+
// zoom calls for, coarser while the markers would exceed the max.
|
|
777
|
+
// Both are built from high-quality calls only: with low-quality calls included, the
|
|
778
|
+
// quality-aware tiles below serve every zoom (as long as there are tiles to serve).
|
|
779
|
+
const highOnly = view.transcriptQuality !== 'all' || !this.port.getTranscriptTile;
|
|
780
|
+
const geneBins = dataset.transcriptGeneBins;
|
|
781
|
+
const fromGeneBins = highOnly && geneBins && this.port.getTranscriptGeneBins;
|
|
782
|
+
if (fromGeneBins && (bin !== null || !this.port.getTranscriptTile)) {
|
|
783
|
+
return this.geneBinsJob(dataset, view, around, geneBins, bin ?? geneBins.levels[0].binSize, mx, my, rect);
|
|
784
|
+
}
|
|
785
|
+
const grid = dataset.density?.gridSize[0] ?? 0;
|
|
786
|
+
if (highOnly && bin !== null && grid > 0 && this.port.getDensity && bin >= grid * 0.75) {
|
|
787
|
+
return this.clusterDensityJob(dataset, view, around, pxPerUnit, Math.max(bin, grid), mx, my, rect);
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
kind: 'genes',
|
|
791
|
+
// The clip window, in quarter-view steps: a pan past the margin re-clips.
|
|
792
|
+
key: `genes|${genes.join(',')}|${view.transcriptQuality}|${view.transcriptBudget}|${bin ?? 'each'}|`
|
|
793
|
+
+ `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}|${keysAt(first).map(tileId)}`,
|
|
794
|
+
load: async () => {
|
|
795
|
+
// The zoom's own level only: over the budget, the transcripts are combined into
|
|
796
|
+
// larger markers (groupSelection), never fetched from slower coarse levels.
|
|
797
|
+
const tiles = await this.fetchAll(keysAt(first), (k) => this.port.getTranscriptTile(k.level, k.gx, k.gy, query));
|
|
798
|
+
// Only what is on screen (and a margin, so a small pan needs nothing new) counts
|
|
799
|
+
// against the budget and the cap; a tile reaches far past the view.
|
|
800
|
+
const merged = mergeTranscriptTiles(tiles.map((t) => clipTranscripts(t, around)), MAX_TRANSCRIPTS);
|
|
801
|
+
const px = new Float32Array(merged.count);
|
|
802
|
+
for (let i = 0; i < merged.count; i++) {
|
|
803
|
+
px[i] = transcriptMarkerPx(merged.weight[i], view.transcriptScale, pxPerMicron);
|
|
804
|
+
}
|
|
805
|
+
return baseBin > 0
|
|
806
|
+
? { merged, px, ladder: { baseBin, levels: ladder?.length ?? PYRAMID_LEVELS, start: bin } }
|
|
807
|
+
: { merged, px };
|
|
808
|
+
},
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* A gene selection from the pyramid's per-gene levels: starting at the level whose bins are
|
|
813
|
+
* `startBin`, fetch the view's tiles for the selected genes and step to a coarser level while
|
|
814
|
+
* one marker per cluster per bin would exceed the max. Hidden genes are fetched too (their
|
|
815
|
+
* counts in view still show) and dropped before drawing; grouping by cluster happens there.
|
|
816
|
+
*/
|
|
817
|
+
geneBinsJob(dataset, view, around, meta, startBin, mx, my, rect) {
|
|
818
|
+
const genes = view.transcriptGenes;
|
|
819
|
+
const levels = meta.levels;
|
|
820
|
+
let first = levels.findIndex((l) => l.binSize >= startBin * 0.999);
|
|
821
|
+
if (first < 0)
|
|
822
|
+
first = levels.length - 1;
|
|
823
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
824
|
+
const hidden = new Set(view.transcriptHiddenGenes);
|
|
825
|
+
const clusters = this.selectionClusters(view);
|
|
826
|
+
const clusterOf = new Map();
|
|
827
|
+
clusters.forEach((c, ci) => c.genes.forEach((g) => clusterOf.set(genes.indexOf(g), ci)));
|
|
828
|
+
const keysAt = (m) => tilesInRectFrom(meta.origin, around, m, levels.map((l) => ({ tileSize: l.tileSize })), null, MAX_BIN_TILES);
|
|
829
|
+
return {
|
|
830
|
+
kind: 'genes',
|
|
831
|
+
key: `gene-bins|${genes.join(',')}|${budget}|${first}|${JSON.stringify(view.transcriptGeneGroups)}|`
|
|
832
|
+
+ `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}`,
|
|
833
|
+
load: async () => {
|
|
834
|
+
let m = first;
|
|
835
|
+
for (;;) {
|
|
836
|
+
const tiles = await this.fetchAll(keysAt(m), (k) => this.port.getTranscriptGeneBins(k.level, k.gx, k.gy, genes));
|
|
837
|
+
const clipped = tiles.map((t) => clipTranscripts(t, around));
|
|
838
|
+
// Past the cap a merge would drop whole genes (the tail of every tile): go coarser.
|
|
839
|
+
if (clipped.reduce((n, t) => n + t.count, 0) > MAX_TRANSCRIPTS && m < levels.length - 1) {
|
|
840
|
+
m++;
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
const merged = mergeTranscriptTiles(clipped, MAX_TRANSCRIPTS);
|
|
844
|
+
// Markers this level would draw: one per (visible cluster, bin).
|
|
845
|
+
const seen = new Set();
|
|
846
|
+
const bin = levels[m].binSize;
|
|
847
|
+
for (let i = 0; i < merged.count; i++) {
|
|
848
|
+
if (hidden.has(genes[merged.gene[i]]))
|
|
849
|
+
continue;
|
|
850
|
+
const c = clusterOf.get(merged.gene[i]);
|
|
851
|
+
if (c === undefined)
|
|
852
|
+
continue;
|
|
853
|
+
seen.add(`${c}|${Math.floor(merged.x[i] / bin)}|${Math.floor(merged.y[i] / bin)}`);
|
|
854
|
+
}
|
|
855
|
+
if (seen.size <= budget || m >= levels.length - 1) {
|
|
856
|
+
return { merged, px: new Float32Array(merged.count), ladder: { baseBin: bin, levels: 1, start: bin } };
|
|
857
|
+
}
|
|
858
|
+
m++;
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
/** The selection's clusters: each gene-tree group's visible genes, then each ungrouped gene. */
|
|
864
|
+
selectionClusters(view) {
|
|
865
|
+
const hidden = new Set(view.transcriptHiddenGenes);
|
|
866
|
+
const slots = new Map(view.transcriptGenes.map((g, i) => [g, i]));
|
|
867
|
+
const taken = new Set();
|
|
868
|
+
const out = [];
|
|
869
|
+
for (const g of view.transcriptGeneGroups) {
|
|
870
|
+
const genes = g.genes.filter((x) => slots.has(x) && !hidden.has(x) && !taken.has(x));
|
|
871
|
+
genes.forEach((x) => taken.add(x));
|
|
872
|
+
if (genes.length)
|
|
873
|
+
out.push({ name: g.name, genes, slot: slots.get(genes[0]) });
|
|
874
|
+
}
|
|
875
|
+
for (const gene of view.transcriptGenes) {
|
|
876
|
+
if (!taken.has(gene) && !hidden.has(gene))
|
|
877
|
+
out.push({ name: gene, genes: [gene], slot: slots.get(gene) });
|
|
878
|
+
}
|
|
879
|
+
return out;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Per-gene density grids summed for `genes`, cached (a cluster is asked for once per bin).
|
|
883
|
+
* Keyed by dataset too: this manager outlives a dataset, and another may share gene names.
|
|
884
|
+
*/
|
|
885
|
+
densityFor(dataset, genes, bin) {
|
|
886
|
+
const key = `${dataset}|${bin}|${genes.join(',')}`;
|
|
887
|
+
let p = this.densityCache.get(key);
|
|
888
|
+
if (!p) {
|
|
889
|
+
p = this.port.getDensity(genes, bin);
|
|
890
|
+
p.catch(() => this.densityCache.delete(key));
|
|
891
|
+
this.densityCache.set(key, p);
|
|
892
|
+
if (this.densityCache.size > 256)
|
|
893
|
+
this.densityCache.delete(this.densityCache.keys().next().value);
|
|
894
|
+
}
|
|
895
|
+
return p;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* A gene selection zoomed out: one marker per cluster per bin, from the per-gene density
|
|
899
|
+
* grids. The bin starts where markers are 14 px apart and doubles until the markers fit the
|
|
900
|
+
* max; each marker sits at the count-weighted centre of the finer grid inside it, so markers
|
|
901
|
+
* follow the tissue rather than a lattice.
|
|
902
|
+
*/
|
|
903
|
+
clusterDensityJob(dataset, view, around, pxPerUnit, startBin, mx, my, rect) {
|
|
904
|
+
const grid = dataset.density.gridSize[0];
|
|
905
|
+
const clusters = this.selectionClusters(view);
|
|
906
|
+
let first = grid;
|
|
907
|
+
while (first < startBin * 0.999)
|
|
908
|
+
first *= 2;
|
|
909
|
+
const budget = Math.max(1, view.transcriptBudget);
|
|
910
|
+
return {
|
|
911
|
+
kind: 'genes',
|
|
912
|
+
key: `clusters|${clusters.map((c) => `${c.name}:${c.genes.join('+')}`).join(';')}|${budget}|${first}|`
|
|
913
|
+
+ `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}`,
|
|
914
|
+
load: async () => {
|
|
915
|
+
let bin = first;
|
|
916
|
+
for (;;) {
|
|
917
|
+
// The finer grid gives each marker its centre; the server bins 1, 2, 4 or 8 cells.
|
|
918
|
+
const fine = Math.min(bin >= grid * 2 ? bin / 2 : bin, grid * 8);
|
|
919
|
+
const rasters = await Promise.all(clusters.map((c) => this.densityFor(dataset.id, c.genes, fine)));
|
|
920
|
+
const out = clusterMarkers(rasters, clusters.map((c) => c.slot), bin, around);
|
|
921
|
+
if (out.tile.count <= budget || bin >= grid * 2 ** 12) {
|
|
922
|
+
const refCount = quantileOf(out.tile.weight, 0.95);
|
|
923
|
+
const binPx = bin * pxPerUnit;
|
|
924
|
+
const px = new Float32Array(out.tile.count);
|
|
925
|
+
for (let i = 0; i < out.tile.count; i++) {
|
|
926
|
+
px[i] = groupedMarkerPx(out.tile.weight[i], refCount, binPx, view.transcriptScale);
|
|
927
|
+
}
|
|
928
|
+
return {
|
|
929
|
+
merged: out.tile, px, kind: 'genes',
|
|
930
|
+
clustered: {
|
|
931
|
+
group: out.group, names: clusters.map((c) => c.name), genes: clusters.map((c) => c.genes), bin,
|
|
932
|
+
origin: rasters[0]?.meta.origin ?? [0, 0],
|
|
933
|
+
},
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
bin *= 2;
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Every gene: the transcripts themselves once they fit the budget, else bins of the
|
|
943
|
+
* all-gene pyramid sized by how many transcripts each holds.
|
|
944
|
+
*/
|
|
945
|
+
allGenesJob(dataset, view, rect, pxPerUnit) {
|
|
946
|
+
const bins = dataset.transcriptBins;
|
|
947
|
+
const tiles = dataset.transcriptTiles;
|
|
948
|
+
const bounds = bins?.bounds ?? tiles?.bounds;
|
|
949
|
+
if (!bounds)
|
|
950
|
+
return null;
|
|
951
|
+
const plan = allGenesPlan({
|
|
952
|
+
rect, bounds, pxPerUnit, budget: view.transcriptBudget,
|
|
953
|
+
total: bins?.count ?? tiles?.count ?? 0,
|
|
954
|
+
levels: bins && this.port.getTranscriptBins ? bins.levels : [],
|
|
955
|
+
canIndividual: !!tiles,
|
|
956
|
+
});
|
|
957
|
+
if (plan.kind === 'individual' && tiles) {
|
|
958
|
+
const keys = tilesInRect(rect, 0, tiles.levels, tiles.bounds, MAX_TRANSCRIPT_TILES);
|
|
959
|
+
// Each tile clipped to the view, rounded outward to 10 units so small pans hit cache.
|
|
960
|
+
const r10 = (v, up) => (up ? Math.ceil(v / 10) : Math.floor(v / 10)) * 10;
|
|
961
|
+
const size = tiles.levels[0].tileSize;
|
|
962
|
+
const boxes = keys.map((k) => [
|
|
963
|
+
Math.max(k.gx * size, r10(rect.x0, false)), Math.max(k.gy * size, r10(rect.y0, false)),
|
|
964
|
+
Math.min((k.gx + 1) * size, r10(rect.x1, true)), Math.min((k.gy + 1) * size, r10(rect.y1, true)),
|
|
965
|
+
]);
|
|
966
|
+
const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
|
|
967
|
+
return {
|
|
968
|
+
kind: 'individual',
|
|
969
|
+
key: `all|individual|${view.transcriptBudget}|${boxes.map((b) => b.join(',')).join(';')}`,
|
|
970
|
+
load: async () => {
|
|
971
|
+
const got = await this.fetchAll(keys.map((k, i) => ({ ...k, box: boxes[i] })), (k) => this.port.getTranscriptTile(0, k.gx, k.gy, { genes: [ALL_GENES], box: k.box }));
|
|
972
|
+
// The plan estimated the view from the dataset's average density; expression is
|
|
973
|
+
// uneven, so a dense view can hold far more. Rather than cut the excess off, show
|
|
974
|
+
// it grouped — the bin level the planner would pick if it had known.
|
|
975
|
+
const cap = Math.max(view.transcriptBudget * 1.5, 1);
|
|
976
|
+
const loaded = got.reduce((n, t) => n + t.count, 0);
|
|
977
|
+
if (loaded > cap && bins && this.port.getTranscriptBins) {
|
|
978
|
+
const fallback = allGenesPlan({
|
|
979
|
+
rect, bounds, pxPerUnit, budget: view.transcriptBudget, total: bins.count,
|
|
980
|
+
levels: bins.levels, canIndividual: false,
|
|
981
|
+
});
|
|
982
|
+
if (fallback.kind === 'bins') {
|
|
983
|
+
const job = this.binsJob(view, rect, pxPerUnit, bounds, bins, fallback.level);
|
|
984
|
+
return { ...(await job.load()), kind: job.kind, bin: job.bin };
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
const merged = mergeTranscriptTiles(got, cap);
|
|
988
|
+
const px = new Float32Array(merged.count);
|
|
989
|
+
for (let i = 0; i < merged.count; i++)
|
|
990
|
+
px[i] = transcriptMarkerPx(1, view.transcriptScale, pxPerMicron);
|
|
991
|
+
return { merged, px };
|
|
992
|
+
},
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
if (plan.kind === 'bins' && bins && this.port.getTranscriptBins) {
|
|
996
|
+
return this.binsJob(view, rect, pxPerUnit, bounds, bins, plan.level);
|
|
997
|
+
}
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
/** Bins of the all-gene pyramid at `level`, sized by how many transcripts each holds. */
|
|
1001
|
+
binsJob(view, rect, pxPerUnit, bounds, bins, level) {
|
|
1002
|
+
const lv = bins.levels[level];
|
|
1003
|
+
const keys = tilesInRectFrom(bins.origin, rect, level, bins.levels.map((l) => ({ tileSize: l.tileSize })), bounds, MAX_BIN_TILES);
|
|
1004
|
+
return {
|
|
1005
|
+
kind: 'bins',
|
|
1006
|
+
bin: { size: lv.binSize, origin: bins.origin },
|
|
1007
|
+
key: `all|bins|${level}|${view.transcriptBudget}|${keys.map(tileId)}`,
|
|
1008
|
+
load: async () => {
|
|
1009
|
+
const got = await this.fetchAll(keys, (k) => this.port.getTranscriptBins(k.level, k.gx, k.gy));
|
|
1010
|
+
const merged = mergeTranscriptTiles(got, Math.max(view.transcriptBudget * 1.5, 1));
|
|
1011
|
+
const refCount = quantileOf(merged.weight, 0.95);
|
|
1012
|
+
const binPx = lv.binSize * pxPerUnit;
|
|
1013
|
+
const px = new Float32Array(merged.count);
|
|
1014
|
+
for (let i = 0; i < merged.count; i++) {
|
|
1015
|
+
px[i] = groupedMarkerPx(merged.weight[i], refCount, binPx, view.transcriptScale);
|
|
1016
|
+
}
|
|
1017
|
+
return { merged, px };
|
|
1018
|
+
},
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
/** Per-entry colours both as RGBA (points) and as colormap values (glyph shapes). */
|
|
1022
|
+
async transcriptColors(dataset, view, t, clusterOf) {
|
|
1023
|
+
let rgb;
|
|
1024
|
+
let codeOf;
|
|
1025
|
+
if (view.transcriptColorBy === 'cluster' && clusterOf) {
|
|
1026
|
+
// A cluster named like a group of the cells' grouping takes that group's colour, so a
|
|
1027
|
+
// cluster's transcripts and its cells agree; any other cluster takes a palette colour.
|
|
1028
|
+
const name = this.cellTypeColumnName(dataset, view);
|
|
1029
|
+
const codes = name ? await this.categoricalCodes(name).catch(() => null) : null;
|
|
1030
|
+
const cellColor = new Map();
|
|
1031
|
+
if (codes?.meta.kind === 'categorical') {
|
|
1032
|
+
const colors = resolveCategoryColors(codes.meta);
|
|
1033
|
+
codes.meta.categories.forEach((c, k) => cellColor.set(c, colors[k]));
|
|
1034
|
+
}
|
|
1035
|
+
const colors = clusterColorMap(view.transcriptGenes, view.transcriptGeneGroups, cellColor, DEFAULT_CATEGORICAL_PALETTE);
|
|
1036
|
+
const index = new Map();
|
|
1037
|
+
const hex = [];
|
|
1038
|
+
const codeFor = (cluster) => {
|
|
1039
|
+
let k = index.get(cluster);
|
|
1040
|
+
if (k === undefined) {
|
|
1041
|
+
k = hex.length;
|
|
1042
|
+
index.set(cluster, k);
|
|
1043
|
+
hex.push(colors.get(cluster) ?? cellColor.get(cluster) ?? DEFAULT_CATEGORICAL_PALETTE[0]);
|
|
1044
|
+
}
|
|
1045
|
+
return k;
|
|
1046
|
+
};
|
|
1047
|
+
const code = new Int32Array(t.count);
|
|
1048
|
+
for (let i = 0; i < t.count; i++) {
|
|
1049
|
+
const c = clusterOf(i);
|
|
1050
|
+
code[i] = c === null ? -1 : codeFor(c);
|
|
1051
|
+
}
|
|
1052
|
+
rgb = hex.map(parseHex);
|
|
1053
|
+
codeOf = (i) => code[i];
|
|
1054
|
+
}
|
|
1055
|
+
else if (view.transcriptColorBy === 'gene' || view.transcriptColorBy === 'cluster') {
|
|
1056
|
+
// All genes: codes are the dataset's gene indices, folded onto the palette.
|
|
1057
|
+
const n = view.transcriptAllGenes ? DEFAULT_CATEGORICAL_PALETTE.length : view.transcriptGenes.length;
|
|
1058
|
+
rgb = Array.from({ length: n }, (_g, i) => parseHex((!view.transcriptAllGenes && view.transcriptGeneColors[view.transcriptGenes[i]])
|
|
1059
|
+
|| DEFAULT_CATEGORICAL_PALETTE[i % DEFAULT_CATEGORICAL_PALETTE.length]));
|
|
1060
|
+
codeOf = view.transcriptAllGenes ? (i) => t.gene[i] % n : (i) => t.gene[i];
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
const name = this.cellTypeColumnName(dataset, view);
|
|
1064
|
+
const codes = name ? await this.categoricalCodes(name) : null;
|
|
1065
|
+
rgb = codes?.meta.kind === 'categorical' ? resolveCategoryColors(codes.meta).map(parseHex) : [];
|
|
1066
|
+
codeOf = (i) => {
|
|
1067
|
+
const o = t.observation[i];
|
|
1068
|
+
if (!codes || o === NO_OBSERVATION)
|
|
1069
|
+
return -1;
|
|
1070
|
+
const c = codes.codes[o];
|
|
1071
|
+
return c === NO_CATEGORY ? -1 : c;
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
|
|
1075
|
+
const rgba = new Array(t.count);
|
|
1076
|
+
const values = new Float32Array(t.count);
|
|
1077
|
+
const tuples = rgb.map(([r, g, b]) => [r / 255, g / 255, b / 255, 1]);
|
|
1078
|
+
for (let i = 0; i < t.count; i++) {
|
|
1079
|
+
const c = codeOf(i);
|
|
1080
|
+
rgba[i] = c < 0 ? UNASSIGNED_RGBA : tuples[c];
|
|
1081
|
+
values[i] = valueOf(c);
|
|
1082
|
+
}
|
|
1083
|
+
return { rgba, values, colormap: new Colormap('transcript-categories', stops) };
|
|
1084
|
+
}
|
|
1085
|
+
// ── density ───────────────────────────────────────────────────────────────────────
|
|
1086
|
+
async planDensity(dataset, view, stale) {
|
|
1087
|
+
const hiddenGenes = new Set(view.transcriptHiddenGenes);
|
|
1088
|
+
const genes = view.transcriptAllGenes
|
|
1089
|
+
? [ALL_GENES]
|
|
1090
|
+
: view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
|
|
1091
|
+
if (!dataset.density || !this.port.getDensity || view.transcriptMode !== 'density' || !genes.length) {
|
|
1092
|
+
this.drop('density');
|
|
1093
|
+
this.densityStats = null;
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
const lut = lutFor(view.densityColormap ?? INFERNO_SCALE);
|
|
1097
|
+
const key = [dataset.id, genes.join(','), view.densityBin, view.densityOpacity,
|
|
1098
|
+
JSON.stringify(view.densityRange), JSON.stringify(view.densityColormap)].join('|');
|
|
1099
|
+
if (key === this.keys.get('density') && this.layers.has('density'))
|
|
1100
|
+
return;
|
|
1101
|
+
const raster = await this.track('Transcript density', this.port.getDensity(genes, view.densityBin));
|
|
1102
|
+
if (stale())
|
|
1103
|
+
return;
|
|
1104
|
+
// Bins drawn as squares, as Xenium Explorer does; the window is in transcripts/µm².
|
|
1105
|
+
const meta = raster.meta;
|
|
1106
|
+
const area = meta.gridSize[0] * meta.gridSize[1];
|
|
1107
|
+
const perArea = raster.values.map((v) => v / area);
|
|
1108
|
+
const [lo, hi] = view.densityRange ?? densityAutoRange(perArea);
|
|
1109
|
+
this.densityStats = { lo, hi, max: perArea.reduce((m, v) => (v > m ? v : m), 0) };
|
|
1110
|
+
const rgba = colorDensityWindow(perArea, lut, view.densityOpacity, lo, hi);
|
|
1111
|
+
const ref = dataset.imageRef;
|
|
1112
|
+
const sx = ref?.scale?.[0] ?? 1;
|
|
1113
|
+
const sy = ref?.scale?.[1] ?? 1;
|
|
1114
|
+
const layer = this.viewer.addImage({ kind: 'typed', width: meta.cols, height: meta.rows, channels: 4, dtype: 'uint8', data: rgba }, {
|
|
1115
|
+
name: `density · ${view.transcriptAllGenes ? 'all genes' : genes.join(', ')}`,
|
|
1116
|
+
scale: [meta.gridSize[0] * sx, meta.gridSize[1] * sy],
|
|
1117
|
+
translate: [
|
|
1118
|
+
meta.origin[0] * sx + (ref?.translate?.[0] ?? 0),
|
|
1119
|
+
meta.origin[1] * sy + (ref?.translate?.[1] ?? 0),
|
|
1120
|
+
],
|
|
1121
|
+
blending: 'translucent',
|
|
1122
|
+
interpolation: 'nearest',
|
|
1123
|
+
});
|
|
1124
|
+
this.keys.set('density', key);
|
|
1125
|
+
this.replace('density', layer);
|
|
1126
|
+
this.host.densityChanged?.(this.densityStats);
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Transcripts in view for the visible genes: each gene's dataset total times the share
|
|
1130
|
+
* of the tissue on screen. An estimate — expression is not uniform — which is also what
|
|
1131
|
+
* Xenium Explorer shows; it tells the user whether the budget will force grouping.
|
|
1132
|
+
*/
|
|
1133
|
+
async planEstimate(dataset, view, viewer, w, h, stale) {
|
|
1134
|
+
const tiles = dataset.transcriptTiles;
|
|
1135
|
+
if (!tiles || !this.port.getTranscriptCounts || view.transcriptMode === 'off') {
|
|
1136
|
+
this.host.estimateChanged?.(null);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const hiddenGenes = new Set(view.transcriptHiddenGenes);
|
|
1140
|
+
const genes = view.transcriptAllGenes ? [] : view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
|
|
1141
|
+
const key = `${dataset.id}|${genes.join(',')}`;
|
|
1142
|
+
if (this.countsCache?.key !== key) {
|
|
1143
|
+
this.countsCache = { key, counts: this.port.getTranscriptCounts(genes) };
|
|
1144
|
+
}
|
|
1145
|
+
let counts;
|
|
1146
|
+
try {
|
|
1147
|
+
counts = await this.countsCache.counts;
|
|
1148
|
+
}
|
|
1149
|
+
catch {
|
|
1150
|
+
this.countsCache = null;
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
if (stale())
|
|
1154
|
+
return;
|
|
1155
|
+
const inView = visibleDataRect(viewer.camera.center, viewer.camera.zoom, w, h, dataset.imageRef, 0);
|
|
1156
|
+
if (!inView)
|
|
1157
|
+
return;
|
|
1158
|
+
const b = counts.bounds;
|
|
1159
|
+
const share = Math.min(1, visibleArea(inView, b) / Math.max(1, (b[2] - b[0]) * (b[3] - b[1])));
|
|
1160
|
+
const selected = view.transcriptAllGenes
|
|
1161
|
+
? counts.total
|
|
1162
|
+
: genes.reduce((sum, g) => sum + (counts.counts[g] ?? 0), 0);
|
|
1163
|
+
this.host.estimateChanged?.({ points: Math.round(selected * share), max: view.transcriptBudget });
|
|
1164
|
+
}
|
|
1165
|
+
// ── layer bookkeeping ─────────────────────────────────────────────────────────────
|
|
1166
|
+
/**
|
|
1167
|
+
* Fetch every tile, drawing what arrived. A failure does not fail the view, but it marks the
|
|
1168
|
+
* plan incomplete: the caller must not cache it as done, and `plan()` retries it.
|
|
1169
|
+
*/
|
|
1170
|
+
async fetchAll(keys, load) {
|
|
1171
|
+
const settled = await Promise.allSettled(keys.map(load));
|
|
1172
|
+
const out = [];
|
|
1173
|
+
for (const s of settled) {
|
|
1174
|
+
if (s.status === 'fulfilled')
|
|
1175
|
+
out.push(s.value);
|
|
1176
|
+
else
|
|
1177
|
+
console.warn('[napari-js] spatial tile failed', s.reason);
|
|
1178
|
+
}
|
|
1179
|
+
if (out.length < keys.length)
|
|
1180
|
+
this.planIncomplete = true;
|
|
1181
|
+
return out;
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Put a shapes layer in place for `group`: a geometry change builds a new layer, a
|
|
1185
|
+
* colour-only change mutates values/colormap on the existing one.
|
|
1186
|
+
*/
|
|
1187
|
+
upsertShapes(group, wanted, geometryChanged, rings, opts) {
|
|
1188
|
+
if (!wanted) {
|
|
1189
|
+
this.drop(group);
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
const existing = this.layers.get(group);
|
|
1193
|
+
if (existing && !geometryChanged && this.viewer.layers.items.includes(existing)) {
|
|
1194
|
+
// Flat colour has no values; clearing them is what switches the layer to `color`.
|
|
1195
|
+
existing.values = opts.values ?? null;
|
|
1196
|
+
if (opts.colormap)
|
|
1197
|
+
existing.colormap = opts.colormap;
|
|
1198
|
+
if (opts.contrastLimits)
|
|
1199
|
+
existing.contrastLimits = opts.contrastLimits;
|
|
1200
|
+
if (opts.color)
|
|
1201
|
+
existing.color = opts.color;
|
|
1202
|
+
if (opts.opacity !== undefined)
|
|
1203
|
+
existing.opacity = opts.opacity;
|
|
1204
|
+
this.viewer.requestRender();
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
const layer = this.viewer.addShapes(rings.coords, rings.offsets, opts);
|
|
1208
|
+
this.replace(group, layer);
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Install `layer` as `group`'s layer and restore the order of the groups above it.
|
|
1212
|
+
* The layer was just added by the caller (so it is on top); groups that belong above
|
|
1213
|
+
* it are removed and re-added.
|
|
1214
|
+
*/
|
|
1215
|
+
replace(group, layer) {
|
|
1216
|
+
const v = this.viewer;
|
|
1217
|
+
const old = this.layers.get(group);
|
|
1218
|
+
if (old && old !== layer && v.layers.items.includes(old))
|
|
1219
|
+
v.layers.remove(old);
|
|
1220
|
+
this.layers.set(group, layer);
|
|
1221
|
+
for (const g of ORDER.slice(ORDER.indexOf(group) + 1)) {
|
|
1222
|
+
const above = this.layers.get(g);
|
|
1223
|
+
if (!above || !v.layers.items.includes(above))
|
|
1224
|
+
continue;
|
|
1225
|
+
v.layers.remove(above);
|
|
1226
|
+
v.layers.add(above);
|
|
1227
|
+
}
|
|
1228
|
+
v.requestRender();
|
|
1229
|
+
}
|
|
1230
|
+
drop(group) {
|
|
1231
|
+
const layer = this.layers.get(group);
|
|
1232
|
+
if (layer && this.viewer?.layers.items.includes(layer))
|
|
1233
|
+
this.viewer.layers.remove(layer);
|
|
1234
|
+
this.layers.delete(group);
|
|
1235
|
+
this.keys.delete(group);
|
|
1236
|
+
}
|
|
1237
|
+
dropCells() {
|
|
1238
|
+
this.drop('cellFill');
|
|
1239
|
+
this.drop('cellOutline');
|
|
1240
|
+
this.drop('nucleusOutline');
|
|
1241
|
+
this.currentNuclei = null;
|
|
1242
|
+
this.cellGeometryKey = null;
|
|
1243
|
+
this.cellStyleKey = null;
|
|
1244
|
+
this.currentRings = null;
|
|
1245
|
+
this.setPolygonsShown(false);
|
|
1246
|
+
}
|
|
1247
|
+
setPolygonsShown(shown) {
|
|
1248
|
+
if (shown === this.polygonsShown)
|
|
1249
|
+
return;
|
|
1250
|
+
this.polygonsShown = shown;
|
|
1251
|
+
this.host.polygonsShownChanged(shown);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
/** Index of the entry under `(x, y)` — within its own radius or `tolerance` — or -1. */
|
|
1255
|
+
export function pickNearest(d, x, y, tolerance) {
|
|
1256
|
+
const t = d.merged;
|
|
1257
|
+
if (!d.grid) {
|
|
1258
|
+
let maxR = 0;
|
|
1259
|
+
for (let i = 0; i < t.count; i++)
|
|
1260
|
+
if (d.radius[i] > maxR)
|
|
1261
|
+
maxR = d.radius[i];
|
|
1262
|
+
const size = Math.max(maxR * 2, tolerance * 2, 1e-6);
|
|
1263
|
+
const buckets = new Map();
|
|
1264
|
+
for (let i = 0; i < t.count; i++) {
|
|
1265
|
+
const k = bucketKey(Math.floor(t.x[i] / size), Math.floor(t.y[i] / size));
|
|
1266
|
+
let b = buckets.get(k);
|
|
1267
|
+
if (!b)
|
|
1268
|
+
buckets.set(k, (b = []));
|
|
1269
|
+
b.push(i);
|
|
1270
|
+
}
|
|
1271
|
+
d.grid = { size, buckets };
|
|
1272
|
+
}
|
|
1273
|
+
const { size, buckets } = d.grid;
|
|
1274
|
+
const gx = Math.floor(x / size);
|
|
1275
|
+
const gy = Math.floor(y / size);
|
|
1276
|
+
let best = -1;
|
|
1277
|
+
let bestD = Infinity;
|
|
1278
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
1279
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
1280
|
+
for (const i of buckets.get(bucketKey(gx + dx, gy + dy)) ?? []) {
|
|
1281
|
+
const dist = Math.hypot(t.x[i] - x, t.y[i] - y);
|
|
1282
|
+
if (dist <= Math.max(d.radius[i], tolerance) && dist < bestD) {
|
|
1283
|
+
bestD = dist;
|
|
1284
|
+
best = i;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return best;
|
|
1290
|
+
}
|
|
1291
|
+
function bucketKey(gx, gy) {
|
|
1292
|
+
return (gx + 32768) * 65536 + (gy + 32768);
|
|
1293
|
+
}
|
|
1294
|
+
/** Rings whose owning cell is in a switched-off group removed. */
|
|
1295
|
+
export function filterRings(rings, hidden) {
|
|
1296
|
+
if (!hidden)
|
|
1297
|
+
return rings;
|
|
1298
|
+
const keep = [];
|
|
1299
|
+
let vertices = 0;
|
|
1300
|
+
for (let i = 0; i < rings.count; i++) {
|
|
1301
|
+
const code = hidden.codes[rings.observation[i]];
|
|
1302
|
+
if (code !== NO_CATEGORY && hidden.hidden[code])
|
|
1303
|
+
continue;
|
|
1304
|
+
keep.push(i);
|
|
1305
|
+
vertices += rings.offsets[i + 1] - rings.offsets[i];
|
|
1306
|
+
}
|
|
1307
|
+
if (keep.length === rings.count)
|
|
1308
|
+
return rings;
|
|
1309
|
+
const observation = new Uint32Array(keep.length);
|
|
1310
|
+
const offsets = new Uint32Array(keep.length + 1);
|
|
1311
|
+
const coords = new Float32Array(vertices * 2);
|
|
1312
|
+
let v = 0;
|
|
1313
|
+
keep.forEach((i, r) => {
|
|
1314
|
+
observation[r] = rings.observation[i];
|
|
1315
|
+
offsets[r] = v;
|
|
1316
|
+
const a = rings.offsets[i] * 2;
|
|
1317
|
+
const b = rings.offsets[i + 1] * 2;
|
|
1318
|
+
coords.set(rings.coords.subarray(a, b), v * 2);
|
|
1319
|
+
v += (b - a) / 2;
|
|
1320
|
+
});
|
|
1321
|
+
offsets[keep.length] = v;
|
|
1322
|
+
return { count: keep.length, observation, offsets, coords };
|
|
1323
|
+
}
|
|
1324
|
+
/** Slots (indices into the selected genes) switched off with their eye toggle. */
|
|
1325
|
+
function hiddenGeneSlots(view) {
|
|
1326
|
+
if (!view.transcriptHiddenGenes.length)
|
|
1327
|
+
return null;
|
|
1328
|
+
const off = new Set(view.transcriptHiddenGenes);
|
|
1329
|
+
return Uint8Array.from(view.transcriptGenes, (g) => (off.has(g) ? 1 : 0));
|
|
1330
|
+
}
|
|
1331
|
+
/** Entries in a hidden group's cell, or of a hidden gene, removed (with their sizes). */
|
|
1332
|
+
export function filterTranscripts(t, px, hidden, hiddenGenes) {
|
|
1333
|
+
if (!hidden && !hiddenGenes)
|
|
1334
|
+
return { merged: t, px };
|
|
1335
|
+
const keep = [];
|
|
1336
|
+
for (let i = 0; i < t.count; i++) {
|
|
1337
|
+
if (hiddenGenes && hiddenGenes[t.gene[i]])
|
|
1338
|
+
continue;
|
|
1339
|
+
const o = t.observation[i];
|
|
1340
|
+
if (hidden && o !== NO_OBSERVATION) {
|
|
1341
|
+
const code = hidden.codes[o];
|
|
1342
|
+
if (code !== NO_CATEGORY && hidden.hidden[code])
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
keep.push(i);
|
|
1346
|
+
}
|
|
1347
|
+
const pick = (a) => {
|
|
1348
|
+
const out = new a.constructor(keep.length);
|
|
1349
|
+
keep.forEach((i, k) => { out[k] = a[i]; });
|
|
1350
|
+
return out;
|
|
1351
|
+
};
|
|
1352
|
+
return {
|
|
1353
|
+
merged: {
|
|
1354
|
+
count: keep.length, aggregated: t.aggregated, x: pick(t.x), y: pick(t.y), z: pick(t.z),
|
|
1355
|
+
weight: pick(t.weight), observation: pick(t.observation), gene: pick(t.gene),
|
|
1356
|
+
},
|
|
1357
|
+
px: pick(px),
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
function median(v) {
|
|
1361
|
+
if (!v.length)
|
|
1362
|
+
return 0;
|
|
1363
|
+
const step = Math.max(1, Math.floor(v.length / 1024));
|
|
1364
|
+
const sample = [];
|
|
1365
|
+
for (let i = 0; i < v.length; i += step)
|
|
1366
|
+
sample.push(v[i]);
|
|
1367
|
+
sample.sort((a, b) => a - b);
|
|
1368
|
+
return sample[sample.length >> 1];
|
|
1369
|
+
}
|
|
1370
|
+
/** Concatenate tiles' rings into one set, dropping rings already seen (a cell straddling
|
|
1371
|
+
* two tiles may be listed by both). */
|
|
1372
|
+
export function mergePolygonTiles(tiles) {
|
|
1373
|
+
const seen = new Set();
|
|
1374
|
+
let rings = 0;
|
|
1375
|
+
let vertices = 0;
|
|
1376
|
+
for (const t of tiles) {
|
|
1377
|
+
for (let i = 0; i < t.count; i++) {
|
|
1378
|
+
if (seen.has(t.observation[i]))
|
|
1379
|
+
continue;
|
|
1380
|
+
seen.add(t.observation[i]);
|
|
1381
|
+
rings++;
|
|
1382
|
+
vertices += t.offsets[i + 1] - t.offsets[i];
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
seen.clear();
|
|
1386
|
+
const observation = new Uint32Array(rings);
|
|
1387
|
+
const offsets = new Uint32Array(rings + 1);
|
|
1388
|
+
const coords = new Float32Array(vertices * 2);
|
|
1389
|
+
let r = 0;
|
|
1390
|
+
let v = 0;
|
|
1391
|
+
for (const t of tiles) {
|
|
1392
|
+
for (let i = 0; i < t.count; i++) {
|
|
1393
|
+
const o = t.observation[i];
|
|
1394
|
+
if (seen.has(o))
|
|
1395
|
+
continue;
|
|
1396
|
+
seen.add(o);
|
|
1397
|
+
observation[r] = o;
|
|
1398
|
+
offsets[r] = v;
|
|
1399
|
+
const a = t.offsets[i] * 2;
|
|
1400
|
+
const b = t.offsets[i + 1] * 2;
|
|
1401
|
+
coords.set(t.coords.subarray(a, b), v * 2);
|
|
1402
|
+
v += (b - a) / 2;
|
|
1403
|
+
r++;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
offsets[rings] = v;
|
|
1407
|
+
return { count: rings, observation, offsets, coords };
|
|
1408
|
+
}
|
|
1409
|
+
/** Concatenate transcript tiles, stopping at `limit` entries. */
|
|
1410
|
+
export function mergeTranscriptTiles(tiles, limit = Infinity) {
|
|
1411
|
+
let n = 0;
|
|
1412
|
+
for (const t of tiles)
|
|
1413
|
+
n += t.count;
|
|
1414
|
+
n = Math.min(n, limit);
|
|
1415
|
+
const out = {
|
|
1416
|
+
count: n,
|
|
1417
|
+
aggregated: tiles.some((t) => t.aggregated),
|
|
1418
|
+
x: new Float32Array(n), y: new Float32Array(n), z: new Float32Array(n),
|
|
1419
|
+
weight: new Uint32Array(n), observation: new Uint32Array(n), gene: new Uint16Array(n),
|
|
1420
|
+
};
|
|
1421
|
+
let o = 0;
|
|
1422
|
+
for (const t of tiles) {
|
|
1423
|
+
const k = Math.min(t.count, n - o);
|
|
1424
|
+
if (k <= 0)
|
|
1425
|
+
break;
|
|
1426
|
+
for (const f of ['x', 'y', 'z', 'weight', 'observation', 'gene']) {
|
|
1427
|
+
out[f].set(t[f].subarray(0, k), o);
|
|
1428
|
+
}
|
|
1429
|
+
o += k;
|
|
1430
|
+
}
|
|
1431
|
+
return out;
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* One marker per (cluster, `bin` square) from per-cluster density grids: the counts of the grid
|
|
1435
|
+
* cells inside `area` summed per square, at their count-weighted centre. `slots[c]` is the gene
|
|
1436
|
+
* slot whose icon cluster c's markers take.
|
|
1437
|
+
*/
|
|
1438
|
+
export function clusterMarkers(rasters, slots, bin, area) {
|
|
1439
|
+
const x = [];
|
|
1440
|
+
const y = [];
|
|
1441
|
+
const w = [];
|
|
1442
|
+
const gene = [];
|
|
1443
|
+
const group = [];
|
|
1444
|
+
rasters.forEach((r, c) => {
|
|
1445
|
+
const [cw, ch] = r.meta.gridSize;
|
|
1446
|
+
const [ox, oy] = r.meta.origin;
|
|
1447
|
+
const { rows, cols } = r.meta;
|
|
1448
|
+
const c0 = Math.max(0, Math.floor((area.x0 - ox) / cw));
|
|
1449
|
+
const c1 = Math.min(cols - 1, Math.floor((area.x1 - ox) / cw));
|
|
1450
|
+
const r0 = Math.max(0, Math.floor((area.y0 - oy) / ch));
|
|
1451
|
+
const r1 = Math.min(rows - 1, Math.floor((area.y1 - oy) / ch));
|
|
1452
|
+
const squares = new Map();
|
|
1453
|
+
for (let row = r0; row <= r1; row++) {
|
|
1454
|
+
for (let col = c0; col <= c1; col++) {
|
|
1455
|
+
const v = r.values[row * cols + col];
|
|
1456
|
+
if (!(v > 0))
|
|
1457
|
+
continue;
|
|
1458
|
+
const cx = ox + (col + 0.5) * cw;
|
|
1459
|
+
const cy = oy + (row + 0.5) * ch;
|
|
1460
|
+
const key = Math.floor((cy - oy) / bin) * 1e6 + Math.floor((cx - ox) / bin);
|
|
1461
|
+
const s = squares.get(key) ?? { n: 0, sx: 0, sy: 0 };
|
|
1462
|
+
s.n += v;
|
|
1463
|
+
s.sx += v * cx;
|
|
1464
|
+
s.sy += v * cy;
|
|
1465
|
+
squares.set(key, s);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
for (const s of squares.values()) {
|
|
1469
|
+
x.push(s.sx / s.n);
|
|
1470
|
+
y.push(s.sy / s.n);
|
|
1471
|
+
w.push(Math.round(s.n));
|
|
1472
|
+
gene.push(slots[c]);
|
|
1473
|
+
group.push(c);
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
const n = w.length;
|
|
1477
|
+
return {
|
|
1478
|
+
tile: {
|
|
1479
|
+
count: n, aggregated: true,
|
|
1480
|
+
x: Float32Array.from(x), y: Float32Array.from(y), z: new Float32Array(n),
|
|
1481
|
+
weight: Uint32Array.from(w), observation: new Uint32Array(n).fill(NO_OBSERVATION),
|
|
1482
|
+
gene: Uint16Array.from(gene),
|
|
1483
|
+
},
|
|
1484
|
+
group: Int32Array.from(group),
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtdGlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtdGlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFJdEQsT0FBTyxFQUFFLFNBQVMsRUFBd0IsTUFBTSx5Q0FBeUMsQ0FBQztBQUUxRixPQUFPLEVBQ0wsV0FBVyxFQUFFLGNBQWMsRUFHM0IsbUJBQW1CLEdBQ3BCLE1BQU0sMENBQTBDLENBQUM7QUFDbEQsT0FBTyxFQUNMLDJCQUEyQixFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsR0FDcEcsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV4QyxPQUFPLEVBQ0ssYUFBYSxFQUFFLHlCQUF5QixFQUFtQixZQUFZLEVBQUUsaUJBQWlCLEVBQ3BHLFVBQVUsRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFDOUYsZUFBZSxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQ25GLGVBQWUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLGtCQUFrQixFQUM1RSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQ2pHLGVBQWUsR0FDaEIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQztrRkFDa0Y7QUFDbEYsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0FBQ3RDLE1BQU0sY0FBYyxHQUFHLENBQUMsQ0FBQztBQUN6QiwyRkFBMkY7QUFDM0YsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUM7QUFDakMs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QUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUMxRCxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDMUQsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7WUFDakMsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7WUFDakMsR0FBRyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUN2QyxDQUFDO2FBQU0sSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLFlBQVksRUFBRSxDQUFDO1lBQ25DLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQztZQUNmLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFVBQVUs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RUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDMUUsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN2QixJQUFJLENBQUMsQ0FBQztnQkFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2pDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDWixDQUFDO1FBQ0QsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBQ0QsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ2pDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2hDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ2QsSUFBSSxLQUFLLEdBQUcsUUFBUSxDQUFDO0lBQ3JCLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1lBQ2hDLEtBQUssTUFBTSxDQUFDLElBQUksT0FB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ICduYXBhcmktanMnO1xuaW1wb3J0IHR5cGUgeyBJbWFnZUxheWVyLCBMYXllciwgUkdCQSwgU2hhcGVzTGF5ZXIsIFZpZXdlciB9IGZyb20gJ25hcGFyaS1qcyc7XG5cbmltcG9ydCB0eXBlIHsgUmdiIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NvbG9ybWFwLWx1dCc7XG5pbXBvcnQgeyBBTExfR0VORVMsIHR5cGUgU3BhdGlhbERhdGFQb3J0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7XG4gIE5PX0NBVEVHT1JZLCBOT19PQlNFUlZBVElPTiwgU3BhdGlhbEJvdW5kcywgU3BhdGlhbENvbHVtbiwgU3BhdGlhbERhdGFzZXQsIFNwYXRpYWxEZW5zaXR5UmFzdGVyLCBTcGF0aWFsSW1hZ2VSZWYsXG4gIFNwYXRpYWxQb2x5Z29uVGlsZSxcbiAgU3BhdGlhbFBvbHlnb25zLCBTcGF0aWFsVHJhbnNjcmlwdENvdW50cywgU3BhdGlhbFRyYW5zY3JpcHRTdW1tYXJ5LCBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsXG4gIGlzQ2F0ZWdvcmljYWxDb2x1bW4sXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLCBNSVNTSU5HX0NPTE9SLCBjb250cmFzdFdpbmRvdywgbHV0Rm9yLCBwYXJzZUhleCwgcmVzb2x2ZUNhdGVnb3J5Q29sb3JzLFxufSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtZW5jb2RpbmcnO1xuaW1wb3J0IHsgU3BhdGlhbFNlbGVjdGlvbk1hc2sgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7XG4gIERhdGFSZWN0LCBJTkZFUk5PX1NDQUxFLCBQT0xZR09OX0xFVkVMX01JTl9DRUxMX1BYLCBUcmFuc2NyaXB0R2x5cGgsIGFsbEdlbmVzUGxhbiwgY2VsbFR5cGVDb2x1bW5Gb3IsXG4gIGNlbGxzU2hvd24sIGNvbG9yRGVuc2l0eVdpbmRvdywgZGVuc2l0eUF1dG9SYW5nZSwgZ3JvdXBlZE1hcmtlclB4LCBxdWFudGlsZU9mLCB0aWxlc0luUmVjdEZyb20sXG4gIGRlZmF1bHRHbHlwaEZvciwgZGlzY3JldGVDb2xvcm1hcFN0b3BzLCBnbHlwaE91dGxpbmUsIGdseXBoUmluZ3MsIHBpeGVsc1BlckRhdGFVbml0LFxuICBwb2x5Z29uTGV2ZWxGb3IsIHRpbGVJZCwgdGlsZXNJblJlY3QsIHRyYW5zY3JpcHRMZXZlbEZvciwgdHJhbnNjcmlwdE1hcmtlclB4LFxuICB0eXBpY2FsQ2VsbERpYW1ldGVyLCB2aXNpYmxlQXJlYSwgdmlzaWJsZURhdGFSZWN0LCBnZW5lQmluU2l6ZSwgZ3JvdXBUcmFuc2NyaXB0cywgY2xpcFRyYW5zY3JpcHRzLFxuICBjbHVzdGVyQ29sb3JNYXAsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC10aWxlcyc7XG5cbi8qKiBUaGUgYWxsLWdlbmUgcHlyYW1pZCdzIGZpbmVzdCBiaW4gKDI1MCDCtW0gc291cmNlIHRpbGVzIC8gMTI4KSBhbmQgZGVmYXVsdCBsZXZlbCBjb3VudCwgdXNlZFxuICogIHRvIGdyb3VwIGEgZ2VuZSBzZWxlY3Rpb24gb24gdGhlIHNhbWUgbGFkZGVyIHdoZW4gYSBkYXRhc2V0IGhhcyBubyBweXJhbWlkLiAqL1xuY29uc3QgUFlSQU1JRF9CQVNFX0JJTl9VTSA9IDI1MCAvIDEyODtcbmNvbnN0IFBZUkFNSURfTEVWRUxTID0gNztcbi8qKiBJY29ucyBnZXQgYSBkYXJrIHJpbSBvbmx5IHdoaWxlIHRoZXJlIGFyZSBhdCBtb3N0IHRoaXMgbWFueSwgYXQgbGVhc3QgdGhpcyBiaWcgKHB4KS4gKi9cbmNvbnN0IEdMWVBIX09VVExJTkVfTUFYID0gMjBfMDAwO1xuY29uc3QgR0xZUEhfT1VUTElORV9NSU5fUFggPSA4O1xuXG4vKipcbiAqIExldmVsLW9mLWRldGFpbCBjZWxsIG91dGxpbmVzLCB0cmFuc2NyaXB0cyBhbmQgdHJhbnNjcmlwdCBkZW5zaXR5IGZvciB0aGUgMkQgc3BhdGlhbCB2aWV3LlxuICpcbiAqIFdIWSBBIFNFUEFSQVRFIENMQVNTXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogRXZlcnl0aGluZyBlbHNlIHRoZSBzcGF0aWFsIHZpZXcgZHJhd3MgaXMgYnVpbHQgb25jZSBwZXIgKGRhdGFzZXQsIHZpZXcpIGFuZCBvbmx5XG4gKiByZXN0eWxlZCBhZnRlcndhcmRzLiBUaGVzZSBsYXllcnMgYWxzbyBkZXBlbmQgb24gdGhlIENBTUVSQTogd2hpY2ggdGlsZXMgYXJlIG9uIHNjcmVlblxuICogYW5kIHdoaWNoIGxldmVsIG9mIGRldGFpbCB0aGUgem9vbSBjYWxscyBmb3IuIEtlZXBpbmcgdGhhdCBsb29wIOKAlCBwbGFuIG9uIGNhbWVyYSBpZGxlLFxuICogZmV0Y2ggdGlsZXMsIG1lcmdlLCBkcmF3IOKAlCBvdXQgb2YgdGhlIHZpc3VhbGl6ZXIgc2VydmljZSBrZWVwcyBib3RoIHJlYWRhYmxlLlxuICpcbiAqIExBWUVSIE9SREVSXG4gKiAtLS0tLS0tLS0tLVxuICogbmFwYXJpLWpzJ3MgbGF5ZXIgbGlzdCBpcyBhcHBlbmQtb25seSAoYWRkIC8gcmVtb3ZlIC8gY2xlYXIpLCBzbyBvcmRlciBpcyBrZXB0IGJ5XG4gKiByZS1hZGRpbmc6IGNlbGwgZmlsbCwgY2VsbCBvdXRsaW5lLCB0aGUgdHJhbnNjcmlwdCBkZW5zaXR5LCB0aGVuIHRyYW5zY3JpcHRzIG9uIHRvcC5cbiAqIFRoZSBzZXJ2aWNlJ3Mgb2JzZXJ2YXRpb24gbWFya2VycyBzaXQgdW5kZXIgYWxsIG9mIHRoZW07IHdoaWxlIG91dGxpbmVzIGFyZSBkcmF3biB0aGVcbiAqIG1hcmtlcnMgYXJlIGhpZGRlbiAoYSBjZWxsIGlzIGl0cyBvdXRsaW5lIHRoZW4sIG5vdCBhIGRvdCksIHNvIHRoZSBjZWxscyBuZXZlciBoYXZlIHRvXG4gKiBiZSBvcmRlcmVkIGFnYWluc3QgdGhlbS4gVGhlIGRlbnNpdHkgZ29lcyBPVkVSIHRoZSBtYXJrZXJzIG9uIHB1cnBvc2U6IHVuZGVyIDEwXjVcbiAqIGRvdHMgaXQgd291bGQgb25seSBzaG93IGluIHRoZSBnYXBzIGJldHdlZW4gY2VsbHMuIHtAbGluayBhZnRlck9ic2VydmF0aW9uc30gcmVzdG9yZXNcbiAqIHRoZSBvcmRlciBhZnRlciB0aGUgc2VydmljZSByZS1hZGRzIGl0cyBtYXJrZXJzLlxuICpcbiAqIE9ORSBMQVlFUiBQRVIgR1JPVVBcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEVhY2ggZ3JvdXAgaXMgb25lIG1lcmdlZCBsYXllciBvdmVyIGV2ZXJ5IHZpc2libGUgdGlsZSwgcmVidWlsdCB3aGVuIHRoZSB0aWxlIHNldCBvclxuICogbGV2ZWwgY2hhbmdlcy4gUmVjb2xvdXJpbmcgKGEgbmV3IGNlbGwtdHlwZSBjb2x1bW4sIGEgc2VsZWN0aW9uKSBvbmx5IHJld3JpdGVzIHRoZVxuICogcGVyLXNoYXBlIHZhbHVlcyDigJQgdGhlIGdlb21ldHJ5IGlzIG5vdCByZS1leHBhbmRlZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGF0aWFsVGlsZUhvc3Qge1xuICAvKiogTGF0ZXN0IGRhdGFzZXQvdmlldy9zZWxlY3Rpb24sIGFzIHRoZSBzcGF0aWFsIHN1YnNjcmlwdGlvbiBzYXcgdGhlbS4gKi9cbiAgbGF0ZXN0KCk6IFtTcGF0aWFsRGF0YXNldCB8IG51bGwsIFNwYXRpYWxWaWV3U3RhdGUsIFNwYXRpYWxTZWxlY3Rpb25NYXNrXSB8IG51bGw7XG4gIC8qKiBDYW52YXMgc2l6ZSBpbiBDU1MgcGl4ZWxzLiAqL1xuICBjYW52YXNTaXplKCk6IFtudW1iZXIsIG51bWJlcl07XG4gIC8qKiBUaGUgY29udGludW91cyBMVVQgdGhlIHZpZXcgaXMgdXNpbmcgKHNvIGNlbGxzIGNvbG91cmVkIGJ5IGEgZ2VuZSBtYXRjaCB0aGUgbWFya2VycykuICovXG4gIGNvbnRpbnVvdXNMdXQodmlldzogU3BhdGlhbFZpZXdTdGF0ZSk6IFJnYltdO1xuICAvKiogT3V0bGluZXMgYXBwZWFyZWQgb3IgZGlzYXBwZWFyZWQ6IHRoZSBtYXJrZXJzJyB2aXNpYmlsaXR5IGZvbGxvd3MuICovXG4gIHBvbHlnb25zU2hvd25DaGFuZ2VkKHNob3duOiBib29sZWFuKTogdm9pZDtcbiAgLyoqIFRoZSBkZW5zaXR5IHdpbmRvdyBjaGFuZ2VkIChhdXRvLWRlcml2ZWQgb3Igc2V0KS4gKi9cbiAgZGVuc2l0eUNoYW5nZWQ/KHN0YXRzOiB7IGxvOiBudW1iZXI7IGhpOiBudW1iZXI7IG1heDogbnVtYmVyIH0pOiB2b2lkO1xuICAvKiogRXN0aW1hdGVkIHRyYW5zY3JpcHRzIGluIHZpZXcgZm9yIHRoZSBjdXJyZW50IHNlbGVjdGlvbiwgYWdhaW5zdCB0aGUgYnVkZ2V0LiAqL1xuICBlc3RpbWF0ZUNoYW5nZWQ/KGVzdGltYXRlOiBUcmFuc2NyaXB0RXN0aW1hdGUgfCBudWxsKTogdm9pZDtcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIGVhY2ggc2VsZWN0ZWQgZ2VuZSBpbnNpZGUgdGhlIHZpZXcsIG9yIG51bGwgd2hlbiBub3Qga25vd24uICovXG4gIGdlbmVDb3VudHNDaGFuZ2VkPyhjb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gfCBudWxsKTogdm9pZDtcbiAgLyoqIFRoZSBsYXllcnMgd2hvc2UgZGF0YSBpcyBpbiBmbGlnaHQgbm93IChcIlRyYW5zY3JpcHRzXCIsIFwiQ2VsbHNcIuKApik7IGVtcHR5IHdoZW4gbm9uZS4gKi9cbiAgbG9hZGluZ0NoYW5nZWQ/KGxheWVyczogc3RyaW5nW10pOiB2b2lkO1xufVxuXG4vKiogWGVuaXVtIEV4cGxvcmVyJ3MgXCJFc3RpbWF0ZWQgVHJhbnNjcmlwdCBQb2ludHNcIi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNjcmlwdEVzdGltYXRlIHtcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIHRoZSB2aXNpYmxlIGdlbmVzIGVzdGltYXRlZCB0byBiZSBpbiB2aWV3LiAqL1xuICBwb2ludHM6IG51bWJlcjtcbiAgLyoqIFRoZSBtYXJrZXIgYnVkZ2V0LiAqL1xuICBtYXg6IG51bWJlcjtcbn1cblxudHlwZSBHcm91cCA9ICdkZW5zaXR5JyB8ICdjZWxsRmlsbCcgfCAnY2VsbE91dGxpbmUnIHwgJ251Y2xldXNPdXRsaW5lJyB8ICd0cmFuc2NyaXB0cycgfCAndHJhbnNjcmlwdE91dGxpbmUnO1xuY29uc3QgT1JERVI6IEdyb3VwW10gPSBbXG4gICdjZWxsRmlsbCcsICdjZWxsT3V0bGluZScsICdudWNsZXVzT3V0bGluZScsICdkZW5zaXR5JywgJ3RyYW5zY3JpcHRzJywgJ3RyYW5zY3JpcHRPdXRsaW5lJyxcbl07XG5cbi8qKiBUcmFuc2NyaXB0cyBkcmF3biBhdCBvbmNlLiBQYXN0IHRoaXMgYSBzY3JlZW4gaXMgc29saWQgY29sb3VyIGFueXdheTsgdGhlIGxldmVsXG4gKiAgcG9saWN5IGtlZXBzIGEgbm9ybWFsIHZpZXcgZmFyIGJlbG93IGl0LiAqL1xuY29uc3QgTUFYX1RSQU5TQ1JJUFRTID0gNDAwXzAwMDtcbmNvbnN0IE1BWF9DRUxMX1RJTEVTID0gNDg7XG5jb25zdCBNQVhfVFJBTlNDUklQVF9USUxFUyA9IDM2O1xuY29uc3QgTUFYX0JJTl9USUxFUyA9IDY0O1xuXG4vKiogQSB0cmFuc2NyaXB0IGZldGNoIHRoZSBwbGFubmVyIGNhbiBrZXkgYmVmb3JlIHJ1bm5pbmcuICovXG5pbnRlcmZhY2UgVHJhbnNjcmlwdEpvYiB7XG4gIC8qKiBXaGF0IG9uZSBlbnRyeSBpcyDigJQgZGVjaWRlcyB3aGF0IGhvdmVyaW5nIGl0IHNheXMuICovXG4gIGtpbmQ6ICdnZW5lcycgfCAnaW5kaXZpZHVhbCcgfCAnYmlucyc7XG4gIC8qKiBGb3IgYmluczogdGhlaXIgc2l6ZSBhbmQgZ3JpZCBvcmlnaW4sIHNvIGEgaG92ZXJlZCBiaW4ncyBzcXVhcmUgY2FuIGJlIHJlY292ZXJlZC4gKi9cbiAgYmluPzogeyBzaXplOiBudW1iZXI7IG9yaWdpbjogW251bWJlciwgbnVtYmVyXSB9O1xuICAvKiogSWRlbnRpZmllcyB3aGF0IHdpbGwgYmUgZHJhd24sIHNvIGFuIHVuY2hhbmdlZCBwbGFuIGlzIGEgbm8tb3AuICovXG4gIGtleTogc3RyaW5nO1xuICAvKiogRmV0Y2ggYW5kIG1lcmdlOyBgcHhgIGlzIGVhY2ggZW50cnkncyBtYXJrZXIgZGlhbWV0ZXIgaW4gc2NyZWVuIHBpeGVscy4gQSBqb2IgbWF5XG4gICAqICBzd2l0Y2ggdG8gYW5vdGhlciBraW5kIG9uY2UgaXQgc2VlcyB0aGUgZGF0YSAoaW5kaXZpZHVhbCDihpIgYmlucyk7IGl0IHRoZW4gc2F5cyBzby4gKi9cbiAgbG9hZCgpOiBQcm9taXNlPFRyYW5zY3JpcHRMb2FkPjtcbn1cblxuaW50ZXJmYWNlIFRyYW5zY3JpcHRMb2FkIHtcbiAgbWVyZ2VkOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGU7XG4gIHB4OiBGbG9hdDMyQXJyYXk7XG4gIC8qKiBGb3IgYSBnZW5lIHNlbGVjdGlvbjogZ3JvdXAgaXQgb24gdGhpcyBiaW4gbGFkZGVyIG9uY2UgaGlkZGVuIGdlbmVzIGFyZSBkcm9wcGVkLiAqL1xuICBsYWRkZXI/OiB7IGJhc2VCaW46IG51bWJlcjsgbGV2ZWxzOiBudW1iZXI7IHN0YXJ0OiBudW1iZXIgfCBudWxsIH07XG4gIC8qKiBBbHJlYWR5IG9uZSBtYXJrZXIgcGVyIGNsdXN0ZXIgcGVyIGJpbiAoem9vbWVkIG91dCwgZnJvbSB0aGUgZGVuc2l0eSBncmlkcyk6IG5vIGNlbGxzLiAqL1xuICBjbHVzdGVyZWQ/OiB7IGdyb3VwOiBJbnQzMkFycmF5OyBuYW1lczogc3RyaW5nW107IGdlbmVzOiBzdHJpbmdbXVtdOyBiaW46IG51bWJlcjsgb3JpZ2luOiBbbnVtYmVyLCBudW1iZXJdIH07XG4gIGtpbmQ/OiBUcmFuc2NyaXB0Sm9iWydraW5kJ107XG4gIGJpbj86IFRyYW5zY3JpcHRKb2JbJ2JpbiddO1xufVxuXG4vKiogV2hlcmUgYSBsYXllciBzaXRzIGluIHdvcmxkIHNwYWNlOiB0aGUgZGF0YXNldCdzIGFmZmluZSBvbnRvIGl0cyB0aXNzdWUgaW1hZ2UuICovXG5pbnRlcmZhY2UgUGxhY2VtZW50IHsgc2NhbGU6IFtudW1iZXIsIG51bWJlcl07IHRyYW5zbGF0ZTogW251bWJlciwgbnVtYmVyXSB9XG5cbi8qKiBUcmFuc2NyaXB0IGNvbG91cnM6IHBlci1lbnRyeSBSR0JBIGZvciBwb2ludHMsIHZhbHVlcyArIGNvbG9ybWFwIGZvciBzaGFwZXMuICovXG5pbnRlcmZhY2UgVHJhbnNjcmlwdEZhY2VzIHsgcmdiYTogUkdCQVtdOyB2YWx1ZXM6IEZsb2F0MzJBcnJheTsgY29sb3JtYXA6IENvbG9ybWFwIH1cbmNvbnN0IENBTUVSQV9JRExFX01TID0gMTIwO1xuLyoqIEZpcnN0IHJldHJ5IG9mIGEgdmlldyB3aXRoIGEgZmFpbGVkIHRpbGU7IGRvdWJsZXMgZWFjaCB0aW1lLCB1cCB0byBNQVhfVElMRV9SRVRSSUVTLiAqL1xuY29uc3QgVElMRV9SRVRSWV9NUyA9IDEwMDA7XG5jb25zdCBNQVhfVElMRV9SRVRSSUVTID0gMztcblxuY29uc3QgVU5BU1NJR05FRF9SR0JBOiBSR0JBID0gWzAuNjIsIDAuNjIsIDAuNjIsIDAuNTVdO1xuXG5leHBvcnQgY2xhc3MgTmFwYXJpU3BhdGlhbFRpbGVMYXllcnMge1xuICBwcml2YXRlIHZpZXdlcjogVmlld2VyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2FtZXJhT2ZmOiAoKCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB0aW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFNldCB3aGVuIGEgdGlsZSBvZiB0aGUgY3VycmVudCBwbGFuIGZhaWxlZCB0byBsb2FkIChzZWUgZmV0Y2hBbGwpLiAqL1xuICBwcml2YXRlIHBsYW5JbmNvbXBsZXRlID0gZmFsc2U7XG4gIC8qKiBDb25zZWN1dGl2ZSByZXRyaWVzIG9mIGFuIGluY29tcGxldGUgdmlldy4gKi9cbiAgcHJpdmF0ZSB0aWxlUmV0cmllcyA9IDA7XG4gIHByaXZhdGUgdG9rZW4gPSAwO1xuICBwcml2YXRlIHJlYWRvbmx5IGxheWVycyA9IG5ldyBNYXA8R3JvdXAsIExheWVyPigpO1xuICAvKiogV2hhdCBlYWNoIGdyb3VwIGN1cnJlbnRseSBzaG93cywgc28gYW4gdW5jaGFuZ2VkIHBsYW4gaXMgYSBuby1vcC4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBrZXlzID0gbmV3IE1hcDxHcm91cCwgc3RyaW5nPigpO1xuICBwcml2YXRlIHBvbHlnb25zU2hvd24gPSBmYWxzZTtcbiAgLyoqIFJpbmdzIGN1cnJlbnRseSBkcmF3biBhbmQgdGhlIChkYXRhc2V0LCBzZXQsIHRpbGVzKSB0aGV5IGNhbWUgZnJvbS4gKi9cbiAgcHJpdmF0ZSBjdXJyZW50UmluZ3M6IFNwYXRpYWxQb2x5Z29uVGlsZSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGNlbGxHZW9tZXRyeUtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY3VycmVudE51Y2xlaTogU3BhdGlhbFBvbHlnb25UaWxlIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2VsbFN0eWxlS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFNlbGVjdGlvbiBpZGVudGl0eSDihpIgcmV2aXNpb24sIHNvIGEgY2hhbmdlIGtleSBjYW4gbmFtZSBhIHNlbGVjdGlvbiBjaGVhcGx5LiAqL1xuICBwcml2YXRlIGxhc3RTZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2VsZWN0aW9uUmV2aXNpb24gPSAwO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgcG9ydDogU3BhdGlhbERhdGFQb3J0LCBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IFNwYXRpYWxUaWxlSG9zdCkge31cblxuICAvLyDilIDilIAgbGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGF0dGFjaCh2aWV3ZXI6IFZpZXdlcik6IHZvaWQge1xuICAgIGlmICh0aGlzLnZpZXdlciA9PT0gdmlld2VyKSByZXR1cm47XG4gICAgdGhpcy5kZXRhY2goKTtcbiAgICB0aGlzLnZpZXdlciA9IHZpZXdlcjtcbiAgICB0aGlzLmNhbWVyYU9mZiA9IHZpZXdlci5jYW1lcmEuY2hhbmdlZC5jb25uZWN0KCgpID0+IHRoaXMuc2NoZWR1bGUoKSk7XG4gIH1cblxuICAvKipcbiAgICogR3JvdXAgYSBnZW5lIHNlbGVjdGlvbiBmb3IgdGhlIHpvb206IG9uZSBtYXJrZXIgcGVyIGdlbmUtdHJlZSBjbHVzdGVyIChhIGdlbmUgaW4gbm9cbiAgICogY2x1c3RlciBpcyBpdHMgb3duKSBwZXIgYmluIG9mIHRoZSBweXJhbWlkIGxhZGRlciwgc3RhcnRpbmcgYXQgdGhlIGZpbmVzdCBiaW4gd2hvc2VcbiAgICogbWFya2VycyBhcmUgMTQgcHggYXBhcnQgYW5kIHN0ZXBwaW5nIHVwIHdoaWxlIHRoZSBtYXJrZXJzIHdvdWxkIGV4Y2VlZCB0aGUgYnVkZ2V0LlxuICAgKiBOdWxsIHRvIGRyYXcgZXZlcnkgdHJhbnNjcmlwdDogem9vbWVkIGluLCB3aXRoIHRoZSBzZWxlY3Rpb24gd2l0aGluIHRoZSBidWRnZXQuXG4gICAqL1xuICBwcml2YXRlIGdyb3VwU2VsZWN0aW9uKFxuICAgIHQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgbGFkZGVyOiBOb25OdWxsYWJsZTxUcmFuc2NyaXB0TG9hZFsnbGFkZGVyJ10+LFxuICAgIHB4UGVyVW5pdDogbnVtYmVyLFxuICApOiB7IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlOyBweDogRmxvYXQzMkFycmF5OyBiaW46IG51bWJlcjsgZ3JvdXA6IEludDMyQXJyYXk7IG5hbWVzOiBzdHJpbmdbXSB9IHwgbnVsbCB7XG4gICAgY29uc3QgYnVkZ2V0ID0gTWF0aC5tYXgoMSwgdmlldy50cmFuc2NyaXB0QnVkZ2V0KTtcbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICAgIGNvbnN0IGdyb3VwcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHM7XG4gICAgY29uc3QgbmFtZXMgPSBbLi4uZ3JvdXBzLm1hcCgoZykgPT4gZy5uYW1lKSwgLi4uZ2VuZXNdO1xuICAgIGNvbnN0IGNsdXN0ZXJPZiA9IGdlbmVzLm1hcCgoZ2VuZSwgc2xvdCkgPT4ge1xuICAgICAgY29uc3QgZyA9IGdyb3Vwcy5maW5kSW5kZXgoKHgpID0+IHguZ2VuZXMuaW5jbHVkZXMoZ2VuZSkpO1xuICAgICAgcmV0dXJuIGcgPj0gMCA/IGcgOiBncm91cHMubGVuZ3RoICsgc2xvdDtcbiAgICB9KTtcbiAgICBjb25zdCBrZXlPZiA9IChzbG90OiBudW1iZXIpID0+IGNsdXN0ZXJPZltzbG90XSA/PyBncm91cHMubGVuZ3RoICsgc2xvdDtcbiAgICBsZXQgYmluID0gbGFkZGVyLnN0YXJ0O1xuICAgIGlmIChiaW4gPT09IG51bGwpIHtcbiAgICAgIC8vIEV2ZXJ5IHRyYW5zY3JpcHQsIGlmIHRoZXkgZml0IHRoZSBtYXggYW5kIG5vbmUgd2FzIGN1dCBvZmYgYXQgdGhlIGNhcC5cbiAgICAgIGlmICh0LmNvdW50IDw9IGJ1ZGdldCAmJiB0LmNvdW50IDwgTUFYX1RSQU5TQ1JJUFRTKSByZXR1cm4gbnVsbDtcbiAgICAgIGJpbiA9IGxhZGRlci5iYXNlQmluO1xuICAgIH1cbiAgICBjb25zdCB0b3AgPSBsYWRkZXIuYmFzZUJpbiAqIDIgKiogKGxhZGRlci5sZXZlbHMgLSAxKTtcbiAgICBsZXQgZ3JvdXBlZCA9IGdyb3VwVHJhbnNjcmlwdHModCwgYmluLCBrZXlPZik7XG4gICAgLy8gT3ZlciB0aGUgbWF4OiBjb21iaW5lIGludG8gbGFyZ2VyIG1hcmtlcnMsIGEgbGV2ZWwgYXQgYSB0aW1lLlxuICAgIHdoaWxlIChncm91cGVkLnRpbGUuY291bnQgPiBidWRnZXQgJiYgYmluIDwgdG9wKSB7XG4gICAgICBiaW4gKj0gMjtcbiAgICAgIGdyb3VwZWQgPSBncm91cFRyYW5zY3JpcHRzKHQsIGJpbiwga2V5T2YpO1xuICAgIH1cbiAgICBjb25zdCByZWZDb3VudCA9IHF1YW50aWxlT2YoZ3JvdXBlZC50aWxlLndlaWdodCwgMC45NSk7XG4gICAgY29uc3QgYmluUHggPSBiaW4gKiBweFBlclVuaXQ7XG4gICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KGdyb3VwZWQudGlsZS5jb3VudCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBncm91cGVkLnRpbGUuY291bnQ7IGkrKykge1xuICAgICAgcHhbaV0gPSBncm91cGVkTWFya2VyUHgoZ3JvdXBlZC50aWxlLndlaWdodFtpXSwgcmVmQ291bnQsIGJpblB4LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSk7XG4gICAgfVxuICAgIHJldHVybiB7IG1lcmdlZDogZ3JvdXBlZC50aWxlLCBweCwgYmluLCBncm91cDogZ3JvdXBlZC5ncm91cCwgbmFtZXMgfTtcbiAgfVxuXG4gIC8qKiDCtW0gcGVyIG9ic2VydmF0aW9uIHVuaXQgb2YgdGhlIGRyYXduIGRhdGFzZXQsIGZvciBkZXNjcmliaW5nIGEgZ3JvdXBlZCBtYXJrZXIncyBhcmVhLiAqL1xuICBwcml2YXRlIG1pY3JvbnNQZXJVbml0OiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAvKiogTG9hZHMgaW4gZmxpZ2h0LCBwZXIgbGF5ZXIgbGFiZWwsIGZvciB0aGUgbG9hZGluZyBiYWRnZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsb2FkaW5nID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICAvKiogUmVwb3J0IGBsYWJlbGAgbG9hZGluZyB3aGlsZSBgd29ya2AgaXMgaW4gZmxpZ2h0LiAqL1xuICBwcml2YXRlIGFzeW5jIHRyYWNrPFQ+KGxhYmVsOiBzdHJpbmcsIHdvcms6IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICB0aGlzLmxvYWRpbmcuc2V0KGxhYmVsLCAodGhpcy5sb2FkaW5nLmdldChsYWJlbCkgPz8gMCkgKyAxKTtcbiAgICB0aGlzLmhvc3QubG9hZGluZ0NoYW5nZWQ/LihbLi4udGhpcy5sb2FkaW5nLmtleXMoKV0pO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgd29yaztcbiAgICB9IGZpbmFsbHkge1xuICAgICAgY29uc3QgbiA9ICh0aGlzLmxvYWRpbmcuZ2V0KGxhYmVsKSA/PyAxKSAtIDE7XG4gICAgICBpZiAobiA+IDApIHRoaXMubG9hZGluZy5zZXQobGFiZWwsIG4pO1xuICAgICAgZWxzZSB0aGlzLmxvYWRpbmcuZGVsZXRlKGxhYmVsKTtcbiAgICAgIHRoaXMuaG9zdC5sb2FkaW5nQ2hhbmdlZD8uKFsuLi50aGlzLmxvYWRpbmcua2V5cygpXSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSBsb2FkZWQgcGVyLWdlbmUgdHJhbnNjcmlwdHMgdGhlIGluLXZpZXcgY291bnRzIGFyZSB0YWtlbiBmcm9tLiAqL1xuICBwcml2YXRlIGNvdW50U291cmNlOiB7IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlOyBnZW5lczogc3RyaW5nW10gfSB8IG51bGwgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBUcmFuc2NyaXB0cyBvZiBlYWNoIHNlbGVjdGVkIGdlbmUgaW5zaWRlIGByZWN0YDogZWFjaCBlbnRyeSBjb3VudHMgZm9yIHRoZSB0cmFuc2NyaXB0cyBpdFxuICAgKiBzdGFuZHMgZm9yIChhbiBhZ2dyZWdhdGUgYXQgYSBjb2Fyc2UgbGV2ZWwgaG9sZHMgc2V2ZXJhbCkuIE51bGwgd2l0aG91dCBwZXItZ2VuZSBkYXRhLlxuICAgKi9cbiAgZ2VuZUNvdW50c0luKHJlY3Q6IERhdGFSZWN0KTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB8IG51bGwge1xuICAgIGNvbnN0IHNyYyA9IHRoaXMuY291bnRTb3VyY2U7XG4gICAgaWYgKCFzcmMpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG91dDogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuICAgIGZvciAoY29uc3QgZyBvZiBzcmMuZ2VuZXMpIG91dFtnXSA9IDA7XG4gICAgY29uc3QgeyB4LCB5LCB3ZWlnaHQsIGdlbmUgfSA9IHNyYy5tZXJnZWQ7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcmMubWVyZ2VkLmNvdW50OyBpKyspIHtcbiAgICAgIGlmICh4W2ldIDwgcmVjdC54MCB8fCB4W2ldID4gcmVjdC54MSB8fCB5W2ldIDwgcmVjdC55MCB8fCB5W2ldID4gcmVjdC55MSkgY29udGludWU7XG4gICAgICBjb25zdCBuYW1lID0gc3JjLmdlbmVzW2dlbmVbaV1dO1xuICAgICAgaWYgKG5hbWUgIT09IHVuZGVmaW5lZCkgb3V0W25hbWVdICs9IHdlaWdodFtpXTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGBsYXllcmAgaXMgb25lIG9mIHRoZSBvdmVybGF5cyBkcmF3biBoZXJlIChkZW5zaXR5LCBjZWxscywgdHJhbnNjcmlwdHMpLiAqL1xuICBvd25zKGxheWVyOiBMYXllcik6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgbCBvZiB0aGlzLmxheWVycy52YWx1ZXMoKSkgaWYgKGwgPT09IGxheWVyKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBkZXRhY2goKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaG92ZXJUaW1lcikgY2xlYXJUaW1lb3V0KHRoaXMuaG92ZXJUaW1lcik7XG4gICAgdGhpcy5ob3ZlclRpbWVyID0gbnVsbDtcbiAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICB0aGlzLmNhbWVyYU9mZj8uKCk7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSBudWxsO1xuICAgIGlmICh0aGlzLnRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgdGhpcy50b2tlbisrO1xuICAgIHRoaXMudGlsZVJldHJpZXMgPSAwO1xuICAgIHRoaXMuY291bnRTb3VyY2UgPSBudWxsO1xuICAgIHRoaXMubG9hZGluZy5jbGVhcigpO1xuICAgIHRoaXMuaG9zdC5sb2FkaW5nQ2hhbmdlZD8uKFtdKTtcbiAgICBpZiAodGhpcy52aWV3ZXIpIHtcbiAgICAgIGZvciAoY29uc3QgbGF5ZXIgb2YgdGhpcy5sYXllcnMudmFsdWVzKCkpIHtcbiAgICAgICAgaWYgKHRoaXMudmlld2VyLmxheWVycy5pdGVtcy5pbmNsdWRlcyhsYXllcikpIHRoaXMudmlld2VyLmxheWVycy5yZW1vdmUobGF5ZXIpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmxheWVycy5jbGVhcigpO1xuICAgIHRoaXMua2V5cy5jbGVhcigpO1xuICAgIHRoaXMuc2V0UG9seWdvbnNTaG93bihmYWxzZSk7XG4gICAgdGhpcy52aWV3ZXIgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRydWUgd2hpbGUgb3V0bGluZXMgYXJlIG9uIHNjcmVlbiDigJQgdGhlIHNlcnZpY2UgaGlkZXMgaXRzIGRvdHMgdGhlbi4gKi9cbiAgZ2V0IG91dGxpbmVzU2hvd24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucG9seWdvbnNTaG93bjtcbiAgfVxuXG4gIC8qKiBEYXRhc2V0LCB2aWV3IG9yIHNlbGVjdGlvbiBjaGFuZ2VkOiByZS1wbGFuIG5vdyByYXRoZXIgdGhhbiBvbiBjYW1lcmEgaWRsZS4gKi9cbiAgcmVmcmVzaCgpOiB2b2lkIHtcbiAgICB0aGlzLnNjaGVkdWxlKDApO1xuICB9XG5cbiAgLyoqIENhbGxlZCByaWdodCBhZnRlciB0aGUgc2VydmljZSBhZGRzIGl0cyBtYXJrZXIgbGF5ZXI6IGV2ZXJ5dGhpbmcgZ29lcyBiYWNrIG9uIHRvcC4gKi9cbiAgYWZ0ZXJPYnNlcnZhdGlvbnMoKTogdm9pZCB7XG4gICAgY29uc3QgdiA9IHRoaXMudmlld2VyO1xuICAgIGlmICghdikgcmV0dXJuO1xuICAgIGZvciAoY29uc3QgZyBvZiBPUkRFUikge1xuICAgICAgY29uc3QgbGF5ZXIgPSB0aGlzLmxheWVycy5nZXQoZyk7XG4gICAgICBpZiAoIWxheWVyKSBjb250aW51ZTtcbiAgICAgIGlmICh2LmxheWVycy5pdGVtcy5pbmNsdWRlcyhsYXllcikpIHYubGF5ZXJzLnJlbW92ZShsYXllcik7XG4gICAgICB2LmxheWVycy5hZGQobGF5ZXIpO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBwbGFubmluZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIHNjaGVkdWxlKGRlbGF5ID0gQ0FNRVJBX0lETEVfTVMpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50aW1lcikgY2xlYXJUaW1lb3V0KHRoaXMudGltZXIpO1xuICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudGltZXIgPSBudWxsO1xuICAgICAgdm9pZCB0aGlzLnBsYW4oKTtcbiAgICB9LCBkZWxheSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHBsYW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgdmlld2VyID0gdGhpcy52aWV3ZXI7XG4gICAgY29uc3QgbGF0ZXN0ID0gdGhpcy5ob3N0LmxhdGVzdCgpO1xuICAgIGlmICghdmlld2VyIHx8ICFsYXRlc3QpIHJldHVybjtcbiAgICBjb25zdCBbZGF0YXNldCwgdmlldywgc2VsZWN0aW9uXSA9IGxhdGVzdDtcbiAgICBjb25zdCB0b2tlbiA9ICsrdGhpcy50b2tlbjtcbiAgICBjb25zdCBzdGFsZSA9ICgpID0+IHRva2VuICE9PSB0aGlzLnRva2VuIHx8IHRoaXMudmlld2VyICE9PSB2aWV3ZXI7XG4gICAgdGhpcy5wbGFuSW5jb21wbGV0ZSA9IGZhbHNlO1xuXG4gICAgaWYgKCFkYXRhc2V0KSB7XG4gICAgICBmb3IgKGNvbnN0IGcgb2YgT1JERVIpIHRoaXMuZHJvcChnKTtcbiAgICAgIHRoaXMuZHJvcENlbGxzKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IFt3LCBoXSA9IHRoaXMuaG9zdC5jYW52YXNTaXplKCk7XG4gICAgY29uc3QgcmVmID0gZGF0YXNldC5pbWFnZVJlZjtcbiAgICBjb25zdCByZWN0ID0gdmlzaWJsZURhdGFSZWN0KHZpZXdlci5jYW1lcmEuY2VudGVyLCB2aWV3ZXIuY2FtZXJhLnpvb20sIHcsIGgsIHJlZik7XG4gICAgY29uc3QgcHhQZXJVbml0ID0gcGl4ZWxzUGVyRGF0YVVuaXQodmlld2VyLmNhbWVyYS56b29tLCByZWYpO1xuICAgIGlmICghcmVjdCkgcmV0dXJuO1xuXG4gICAgdm9pZCB0aGlzLnBsYW5Fc3RpbWF0ZShkYXRhc2V0LCB2aWV3LCB2aWV3ZXIsIHcsIGgsIHN0YWxlKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLnBsYW5EZW5zaXR5KGRhdGFzZXQsIHZpZXcsIHN0YWxlKSxcbiAgICAgIHRoaXMucGxhbkNlbGxzKGRhdGFzZXQsIHZpZXcsIHNlbGVjdGlvbiwgcmVjdCwgcHhQZXJVbml0LCBzdGFsZSksXG4gICAgICB0aGlzLnBsYW5UcmFuc2NyaXB0cyhkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQsIHN0YWxlKSxcbiAgICBdKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuICAgIHRoaXMuaG9zdC5nZW5lQ291bnRzQ2hhbmdlZD8uKHRoaXMuZ2VuZUNvdW50c0luKHJlY3QpKTtcbiAgICAvLyBBIHRpbGUgdGhhdCBmYWlsZWQgbGVmdCBhIGhvbGUgdGhlIGNhY2hlIGtleXMgZG8gbm90IHJlY29yZCwgc28gdHJ5IHRoZSBzYW1lIHZpZXdcbiAgICAvLyBhZ2FpbiwgYmFja2luZyBvZmYsIGEgYm91bmRlZCBudW1iZXIgb2YgdGltZXMuXG4gICAgaWYgKCF0aGlzLnBsYW5JbmNvbXBsZXRlKSB7XG4gICAgICB0aGlzLnRpbGVSZXRyaWVzID0gMDtcbiAgICB9IGVsc2UgaWYgKHRoaXMudGlsZVJldHJpZXMgPCBNQVhfVElMRV9SRVRSSUVTKSB7XG4gICAgICB0aGlzLnNjaGVkdWxlKFRJTEVfUkVUUllfTVMgKiAyICoqIHRoaXMudGlsZVJldHJpZXMrKyk7XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIGNlbGxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgYXN5bmMgcGxhbkNlbGxzKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrLFxuICAgIHJlY3Q6IERhdGFSZWN0LCBweFBlclVuaXQ6IG51bWJlciwgc3RhbGU6ICgpID0+IGJvb2xlYW4sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRpbGVkID0gZGF0YXNldC5wb2x5Z29uVGlsZXM7XG4gICAgY29uc3Qgd2hvbGUgPSAhdGlsZWQgJiYgZGF0YXNldC5wb2x5Z29ucyAmJiB0aGlzLnBvcnQuZ2V0UG9seWdvbnM7XG4gICAgaWYgKCFjZWxsc1Nob3duKGRhdGFzZXQsIHZpZXcpIHx8ICghdGlsZWQgJiYgIXdob2xlKSkge1xuICAgICAgdGhpcy5kcm9wQ2VsbHMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZGlhbWV0ZXIgPSB0eXBpY2FsQ2VsbERpYW1ldGVyKGRhdGFzZXQub2JzZXJ2YXRpb25zLnJhZGl1cyk7XG4gICAgLy8gV2hvbGUtZGF0YXNldCByaW5ncyBoYXZlIG9uZSBsZXZlbCBhbmQgbm8gY29hcnNlciBmYWxsYmFjaywgc28gdGhleSBhcmUgZHJhd24gYXNcbiAgICAvLyBzb29uIGFzIGEgY2VsbCBpcyBiaWcgZW5vdWdoIHRvIHJlYWQgYXMgYSBzaGFwZSByYXRoZXIgdGhhbiBhIGRvdC5cbiAgICBjb25zdCBsZXZlbCA9IHRpbGVkXG4gICAgICA/IHBvbHlnb25MZXZlbEZvcihweFBlclVuaXQsIGRpYW1ldGVyLCB0aWxlZC5sZXZlbHMubGVuZ3RoKVxuICAgICAgOiAocHhQZXJVbml0ICogZGlhbWV0ZXIgPj0gUE9MWUdPTl9MRVZFTF9NSU5fQ0VMTF9QWFsyXSA/IDAgOiAtMSk7XG4gICAgaWYgKGxldmVsIDwgMCkge1xuICAgICAgdGhpcy5kcm9wQ2VsbHMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBHcm91cHMgc3dpdGNoZWQgb2ZmIGluIHRoZSBsaXN0OiB0aGVpciBjZWxscyBhcmUgbGVmdCBvdXQgb2YgdGhlIGdlb21ldHJ5LlxuICAgIGNvbnN0IGhpZGRlbiA9IGF3YWl0IHRoaXMuaGlkZGVuQ29kZXMoZGF0YXNldCwgdmlldyk7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCBsYWJlbCA9IHZpZXcuY2VsbFNldCA9PT0gJ2JvdGgnID8gJ0NlbGxzIGFuZCBudWNsZWknXG4gICAgICA6IHZpZXcuY2VsbFNldCA9PT0gJ251Y2xldXMnID8gJ051Y2xlaScgOiAnQ2VsbHMnO1xuICAgIGNvbnN0IGdlb21ldHJ5ID0gYXdhaXQgdGhpcy50cmFjayhsYWJlbCwgdGhpcy5jZWxsR2VvbWV0cnkoZGF0YXNldCwgdmlldywgcmVjdCwgbGV2ZWwsIGhpZGRlbiwgc3RhbGUpKTtcbiAgICBpZiAoIWdlb21ldHJ5KSByZXR1cm47XG4gICAgY29uc3QgeyByaW5ncywgbnVjbGVpLCBnZW9tZXRyeUtleSB9ID0gZ2VvbWV0cnk7XG5cbiAgICBjb25zdCBnZW9tZXRyeUNoYW5nZWQgPSBnZW9tZXRyeUtleSAhPT0gdGhpcy5jZWxsR2VvbWV0cnlLZXk7XG4gICAgY29uc3Qgc3R5bGVLZXkgPSBbXG4gICAgICBnZW9tZXRyeUtleSwgdmlldy5jZWxsQ29sb3JNb2RlLCB2aWV3LmNlbGxDb2xvckdlbmUsIHZpZXcuY2VsbFNpbmdsZUNvbG9yLFxuICAgICAgdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyksXG4gICAgICB0aGlzLnNlbGVjdGlvblJldihzZWxlY3Rpb24pLCB2aWV3LmxvZ1NjYWxlLCB2aWV3LnBlcmNlbnRpbGVDbGlwLmpvaW4oKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcuY29udGludW91c0NvbG9ybWFwKSwgdmlldy5jZWxsRHJhdywgdmlldy5jZWxsT3BhY2l0eSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBwcmVzZW50ID0gWydjZWxsRmlsbCcsICdjZWxsT3V0bGluZScsICdudWNsZXVzT3V0bGluZSddLnNvbWUoKGcpID0+IHtcbiAgICAgIGNvbnN0IGwgPSB0aGlzLmxheWVycy5nZXQoZyBhcyBHcm91cCk7XG4gICAgICByZXR1cm4gbCAmJiB0aGlzLnZpZXdlciEubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGwpO1xuICAgIH0pO1xuICAgIGlmICghZ2VvbWV0cnlDaGFuZ2VkICYmIHN0eWxlS2V5ID09PSB0aGlzLmNlbGxTdHlsZUtleSAmJiBwcmVzZW50KSB7XG4gICAgICB0aGlzLnNldFBvbHlnb25zU2hvd24odHJ1ZSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNvbG9ycyA9IGF3YWl0IHRoaXMuY2VsbENvbG9ycyhkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb24sIHJpbmdzLm9ic2VydmF0aW9uKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuXG4gICAgdGhpcy5jdXJyZW50UmluZ3MgPSByaW5ncztcbiAgICB0aGlzLmN1cnJlbnROdWNsZWkgPSBudWNsZWk7XG4gICAgLy8gQSBnZW9tZXRyeSBtaXNzaW5nIGEgZmFpbGVkIHRpbGUgaXMgZHJhd24gYnV0IG5vdCByZW1lbWJlcmVkLCBzbyB0aGUgcmV0cnkgcmVmZXRjaGVzIGl0LlxuICAgIHRoaXMuY2VsbEdlb21ldHJ5S2V5ID0gdGhpcy5wbGFuSW5jb21wbGV0ZSA/IG51bGwgOiBnZW9tZXRyeUtleTtcbiAgICB0aGlzLmNlbGxTdHlsZUtleSA9IHN0eWxlS2V5O1xuICAgIGNvbnN0IHJlZiA9IGRhdGFzZXQuaW1hZ2VSZWY7XG4gICAgY29uc3QgY29tbW9uID0geyBzY2FsZTogcmVmPy5zY2FsZSA/PyBbMSwgMV0sIHRyYW5zbGF0ZTogcmVmPy50cmFuc2xhdGUgPz8gWzAsIDBdIH0gYXMgY29uc3Q7XG4gICAgY29uc3QgZmlsbCA9IHZpZXcuY2VsbERyYXcgIT09ICdvdXRsaW5lJztcbiAgICBjb25zdCBvdXRsaW5lID0gdmlldy5jZWxsRHJhdyAhPT0gJ2ZpbGwnO1xuXG4gICAgdGhpcy51cHNlcnRTaGFwZXMoJ2NlbGxGaWxsJywgZmlsbCwgZ2VvbWV0cnlDaGFuZ2VkLCByaW5ncywge1xuICAgICAgbmFtZTogJ2NlbGxzJywgZHJhdzogJ2ZpbGwnLCBvcGFjaXR5OiB2aWV3LmNlbGxPcGFjaXR5LCAuLi5jb2xvcnMsIC4uLmNvbW1vbixcbiAgICB9KTtcbiAgICB0aGlzLnVwc2VydFNoYXBlcygnY2VsbE91dGxpbmUnLCBvdXRsaW5lLCBnZW9tZXRyeUNoYW5nZWQsIHJpbmdzLCBmaWxsXG4gICAgICAvLyBPdmVyIGEgZmlsbCwgYSBkYXJrIG91dGxpbmUgc2VwYXJhdGVzIG5laWdoYm91cnMgb2YgdGhlIHNhbWUgdHlwZS5cbiAgICAgID8geyBuYW1lOiAnY2VsbCBvdXRsaW5lcycsIGRyYXc6ICdvdXRsaW5lJywgY29sb3I6IFswLjA4LCAwLjA4LCAwLjEsIDFdLCBvcGFjaXR5OiAwLjcsIC4uLmNvbW1vbiB9XG4gICAgICA6IHsgbmFtZTogJ2NlbGwgb3V0bGluZXMnLCBkcmF3OiAnb3V0bGluZScsIG9wYWNpdHk6IDEsIC4uLmNvbG9ycywgLi4uY29tbW9uIH0pO1xuICAgIC8vIFwiQm90aFwiOiBudWNsZWkgb3V0bGluZWQgb3ZlciB0aGUgY2VsbHMsIGxpZ2h0IHNvIHRoZXkgcmVhZCBhZ2FpbnN0IGFueSBmaWxsLlxuICAgIGlmIChudWNsZWkpIHtcbiAgICAgIHRoaXMudXBzZXJ0U2hhcGVzKCdudWNsZXVzT3V0bGluZScsIHRydWUsIGdlb21ldHJ5Q2hhbmdlZCwgbnVjbGVpLCB7XG4gICAgICAgIG5hbWU6ICdudWNsZXVzIG91dGxpbmVzJywgZHJhdzogJ291dGxpbmUnLCBjb2xvcjogWzAuOTUsIDAuOTUsIDAuOTgsIDFdLCBvcGFjaXR5OiAwLjgsIC4uLmNvbW1vbixcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRyb3AoJ251Y2xldXNPdXRsaW5lJyk7XG4gICAgfVxuICAgIHRoaXMuc2V0UG9seWdvbnNTaG93bih0cnVlKTtcbiAgfVxuXG4gIHByaXZhdGUgc2VsZWN0aW9uUmV2KHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2spOiBudW1iZXIge1xuICAgIGlmIChzZWxlY3Rpb24gIT09IHRoaXMubGFzdFNlbGVjdGlvbikge1xuICAgICAgdGhpcy5sYXN0U2VsZWN0aW9uID0gc2VsZWN0aW9uO1xuICAgICAgdGhpcy5zZWxlY3Rpb25SZXZpc2lvbisrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5zZWxlY3Rpb25SZXZpc2lvbjtcbiAgfVxuXG4gIC8qKiBQZXItc2hhcGUgdmFsdWVzICsgY29sb3JtYXAgZm9yIHRoZSByaW5ncycgb3duZXJzLiAqL1xuICAvKipcbiAgICogUGVyLXNoYXBlIHZhbHVlcyArIGNvbG9ybWFwIGZvciB0aGUgcmluZ3MnIG93bmVycywgYnkgdGhlIHZpZXcncyBjZWxsLWNvbG91ciBtb2RlXG4gICAqIChYZW5pdW0gRXhwbG9yZXIncyBcIkNlbGwgQ29sb3JcIikuIEEgc2VsZWN0aW9uIG11dGVzIHdoYXQgaXQgbGVhdmVzIG91dC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2VsbENvbG9ycyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgICBvd25lcnM6IFVpbnQzMkFycmF5LFxuICApOiBQcm9taXNlPHsgdmFsdWVzPzogRmxvYXQzMkFycmF5OyBjb2xvcm1hcD86IENvbG9ybWFwOyBjb250cmFzdExpbWl0cz86IFtudW1iZXIsIG51bWJlcl07IGNvbG9yPzogUkdCQSB9PiB7XG4gICAgY29uc3QgbXV0ZWQgPSBzZWxlY3Rpb24uY291bnQgPiAwID8gc2VsZWN0aW9uLm1hc2sgOiBudWxsO1xuICAgIGNvbnN0IG1vZGUgPSB2aWV3LmNlbGxDb2xvck1vZGU7XG5cbiAgICBpZiAobW9kZSA9PT0gJ3NpbmdsZScpIHtcbiAgICAgIGNvbnN0IFtyLCBnLCBiXSA9IHBhcnNlSGV4KHZpZXcuY2VsbFNpbmdsZUNvbG9yKTtcbiAgICAgIHJldHVybiB7IGNvbG9yOiBbciAvIDI1NSwgZyAvIDI1NSwgYiAvIDI1NSwgMV0gfTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250aW51b3VzID0gYXN5bmMgKHJhdzogRmxvYXQzMkFycmF5LCBsb2c6IGJvb2xlYW4pID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkob3duZXJzLmxlbmd0aCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG93bmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCB2ID0gcmF3W293bmVyc1tpXV0gPz8gTmFOO1xuICAgICAgICB2YWx1ZXNbaV0gPSBsb2cgPyBNYXRoLmxvZzFwKE1hdGgubWF4KDAsIHYpKSA6IHY7XG4gICAgICB9XG4gICAgICBjb25zdCBbbG8sIGhpXSA9IGNvbnRyYXN0V2luZG93KFxuICAgICAgICBsb2cgPyByYXcubWFwKCh2KSA9PiBNYXRoLmxvZzFwKE1hdGgubWF4KDAsIHYpKSkgOiByYXcsXG4gICAgICAgIHZpZXcucGVyY2VudGlsZUNsaXBbMF0sIHZpZXcucGVyY2VudGlsZUNsaXBbMV0sXG4gICAgICApO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWVzLFxuICAgICAgICBjb2xvcm1hcDogY29sb3JtYXBGcm9tTHV0KCdzcGF0aWFsLWNvbnRpbnVvdXMnLCB0aGlzLmhvc3QuY29udGludW91c0x1dCh2aWV3KSksXG4gICAgICAgIGNvbnRyYXN0TGltaXRzOiBbbG8sIGhpXSBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgfTtcbiAgICB9O1xuICAgIGlmIChtb2RlID09PSAnZ2VuZScgJiYgdmlldy5jZWxsQ29sb3JHZW5lKSB7XG4gICAgICByZXR1cm4gY29udGludW91cyhhd2FpdCB0aGlzLnBvcnQuZ2V0RmVhdHVyZVZlY3Rvcih2aWV3LmNlbGxDb2xvckdlbmUpLCB0cnVlKTtcbiAgICB9XG4gICAgaWYgKG1vZGUgPT09ICd0cmFuc2NyaXB0RGVuc2l0eScgJiYgZGF0YXNldC5jb2x1bW5zLnNvbWUoKGMpID0+IGMubmFtZSA9PT0gJ3RyYW5zY3JpcHRfZGVuc2l0eScpKSB7XG4gICAgICBjb25zdCBjb2x1bW4gPSBhd2FpdCB0aGlzLnBvcnQuZ2V0Q29sdW1uKCd0cmFuc2NyaXB0X2RlbnNpdHknKTtcbiAgICAgIGlmICghaXNDYXRlZ29yaWNhbENvbHVtbihjb2x1bW4pKSByZXR1cm4gY29udGludW91cyhjb2x1bW4udmFsdWVzLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgY29uc3QgbmFtZSA9IG1vZGUgPT09ICdzZWdtZW50YXRpb24nICYmIGRhdGFzZXQuY29sdW1ucy5zb21lKChjKSA9PiBjLm5hbWUgPT09ICdzZWdtZW50YXRpb25fbWV0aG9kJylcbiAgICAgID8gJ3NlZ21lbnRhdGlvbl9tZXRob2QnXG4gICAgICA6IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgIGNvbnN0IGNvZGVzID0gbmFtZSA/IGF3YWl0IHRoaXMuY2F0ZWdvcmljYWxDb2RlcyhuYW1lKSA6IG51bGw7XG4gICAgY29uc3QgeyBjb2xvcm1hcCwgdmFsdWVPZiB9ID0gdGhpcy5jYXRlZ29yaWNhbENvbG9ybWFwKGNvZGVzPy5tZXRhID8/IG51bGwpO1xuICAgIGNvbnN0IHZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkob3duZXJzLmxlbmd0aCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvd25lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG8gPSBvd25lcnNbaV07XG4gICAgICBjb25zdCBjb2RlID0gIWNvZGVzIHx8IChtdXRlZCAmJiAhbXV0ZWRbb10pID8gLTEgOiBjb2Rlcy5jb2Rlc1tvXTtcbiAgICAgIHZhbHVlc1tpXSA9IHZhbHVlT2YoY29kZSA9PT0gTk9fQ0FURUdPUlkgPyAtMSA6IGNvZGUpO1xuICAgIH1cbiAgICByZXR1cm4geyB2YWx1ZXMsIGNvbG9ybWFwLCBjb250cmFzdExpbWl0czogWzAsIDFdIH07XG4gIH1cblxuICAvKiogQ29kZXMgb2YgdGhlIGdyb3VwIGNvbHVtbiB0aGF0IGFyZSBzd2l0Y2hlZCBvZmYsIG9yIG51bGwgd2hlbiBub25lIGFyZS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBoaWRkZW5Db2RlcyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgKTogUHJvbWlzZTx7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsPiB7XG4gICAgaWYgKCF2aWV3LmhpZGRlbkdyb3Vwcy5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG5hbWUgPSB0aGlzLmNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0LCB2aWV3KTtcbiAgICBjb25zdCBjb2wgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpIDogbnVsbDtcbiAgICBpZiAoIWNvbCB8fCBjb2wubWV0YS5raW5kICE9PSAnY2F0ZWdvcmljYWwnKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBvZmYgPSBuZXcgU2V0KHZpZXcuaGlkZGVuR3JvdXBzKTtcbiAgICBjb25zdCBoaWRkZW4gPSBVaW50OEFycmF5LmZyb20oY29sLm1ldGEuY2F0ZWdvcmllcywgKGMpID0+IChvZmYuaGFzKGMpID8gMSA6IDApKTtcbiAgICByZXR1cm4geyBjb2RlczogY29sLmNvZGVzLCBoaWRkZW4gfTtcbiAgfVxuXG4gIHByaXZhdGUgY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIGNlbGxUeXBlQ29sdW1uRm9yKGRhdGFzZXQsIHZpZXcpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYXRlZ29yaWNhbENvZGVzKG5hbWU6IHN0cmluZyk6XG4gICAgUHJvbWlzZTx7IGNvZGVzOiBVaW50MTZBcnJheTsgbWV0YTogU3BhdGlhbENvbHVtblsnbWV0YSddIH0gfCBudWxsPiB7XG4gICAgY29uc3QgY29sdW1uID0gYXdhaXQgdGhpcy5wb3J0LmdldENvbHVtbihuYW1lKTtcbiAgICByZXR1cm4gaXNDYXRlZ29yaWNhbENvbHVtbihjb2x1bW4pID8geyBjb2RlczogY29sdW1uLmNvZGVzLCBtZXRhOiBjb2x1bW4ubWV0YSB9IDogbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgY2F0ZWdvcmljYWxDb2xvcm1hcChtZXRhOiBTcGF0aWFsQ29sdW1uWydtZXRhJ10gfCBudWxsKTpcbiAgICB7IGNvbG9ybWFwOiBDb2xvcm1hcDsgdmFsdWVPZjogKGNvZGU6IG51bWJlcikgPT4gbnVtYmVyOyByZ2I6IFJnYltdIH0ge1xuICAgIGNvbnN0IGhleCA9IG1ldGEgJiYgbWV0YS5raW5kID09PSAnY2F0ZWdvcmljYWwnXG4gICAgICA/IHJlc29sdmVDYXRlZ29yeUNvbG9ycyhtZXRhKVxuICAgICAgOiBbREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFWzBdXTtcbiAgICBjb25zdCByZ2IgPSBoZXgubWFwKHBhcnNlSGV4KTtcbiAgICBjb25zdCB7IHN0b3BzLCB2YWx1ZU9mIH0gPSBkaXNjcmV0ZUNvbG9ybWFwU3RvcHMocmdiLCBNSVNTSU5HX0NPTE9SKTtcbiAgICByZXR1cm4geyBjb2xvcm1hcDogbmV3IENvbG9ybWFwKCdzcGF0aWFsLWNhdGVnb3JpZXMnLCBzdG9wcyksIHZhbHVlT2YsIHJnYiB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjZWxsIHJpbmdzIChhbmQsIGZvciBcImJvdGhcIiwgdGhlIG51Y2xldXMgcmluZ3MpIGNvdmVyaW5nIGByZWN0YCBhdCBgbGV2ZWxgLCBtaW51c1xuICAgKiB0aGUgaGlkZGVuIGdyb3VwcyDigJQgcmV1c2VkIHdoZW4gbm90aGluZyB0aGF0IGRlY2lkZXMgdGhlbSBjaGFuZ2VkLiBOdWxsIHdoZW4gdGhlXG4gICAqIHZpZXcgd2VudCBzdGFsZSBvciB0aGUgZGF0YXNldCBoYXMgbm8gc2V0IHRvIGRyYXcuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNlbGxHZW9tZXRyeShcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIGxldmVsOiBudW1iZXIsXG4gICAgaGlkZGVuOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsLCBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx7IHJpbmdzOiBTcGF0aWFsUG9seWdvblRpbGU7IG51Y2xlaTogU3BhdGlhbFBvbHlnb25UaWxlIHwgbnVsbDsgZ2VvbWV0cnlLZXk6IHN0cmluZyB9IHwgbnVsbD4ge1xuICAgIGNvbnN0IHRpbGVkID0gZGF0YXNldC5wb2x5Z29uVGlsZXM7XG4gICAgY29uc3QgaGlkZGVuS2V5ID0gdmlldy5oaWRkZW5Hcm91cHMuam9pbignXFx1MDAwMScpO1xuICAgIGxldCByaW5nczogU3BhdGlhbFBvbHlnb25UaWxlO1xuICAgIGxldCBudWNsZWk6IFNwYXRpYWxQb2x5Z29uVGlsZSB8IG51bGwgPSBudWxsO1xuICAgIGxldCBnZW9tZXRyeUtleTogc3RyaW5nO1xuICAgIGlmICh0aWxlZCkge1xuICAgICAgY29uc3QgYm90aCA9IHZpZXcuY2VsbFNldCA9PT0gJ2JvdGgnO1xuICAgICAgY29uc3Qgc2V0ID0gIWJvdGggJiYgdmlldy5jZWxsU2V0ICYmIHRpbGVkLnNldHMuc29tZSgocykgPT4gcy5uYW1lID09PSB2aWV3LmNlbGxTZXQpXG4gICAgICAgID8gdmlldy5jZWxsU2V0IDogKHRpbGVkLmRlZmF1bHRTZXQgPz8gdGlsZWQuc2V0c1swXT8ubmFtZSk7XG4gICAgICBpZiAoIXNldCkgcmV0dXJuIG51bGw7XG4gICAgICBjb25zdCBudWNsZXVzU2V0ID0gYm90aCA/IHRpbGVkLnNldHMuZmluZCgocykgPT4gcy5uYW1lICE9PSBzZXQpPy5uYW1lIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3Qga2V5cyA9IHRpbGVzSW5SZWN0KHJlY3QsIGxldmVsLCB0aWxlZC5sZXZlbHMsIHRpbGVkLmJvdW5kcywgTUFYX0NFTExfVElMRVMpO1xuICAgICAgZ2VvbWV0cnlLZXkgPSBgJHtkYXRhc2V0LmlkfXwke3NldH18JHtudWNsZXVzU2V0ID8/ICcnfXwke2hpZGRlbktleX18JHtrZXlzLm1hcCh0aWxlSWQpLmpvaW4oJywnKX1gO1xuICAgICAgaWYgKGdlb21ldHJ5S2V5ID09PSB0aGlzLmNlbGxHZW9tZXRyeUtleSAmJiB0aGlzLmN1cnJlbnRSaW5ncykge1xuICAgICAgICByaW5ncyA9IHRoaXMuY3VycmVudFJpbmdzO1xuICAgICAgICBudWNsZWkgPSB0aGlzLmN1cnJlbnROdWNsZWk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBbdGlsZXMsIG51Y2xldXNUaWxlc10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgdGhpcy5mZXRjaEFsbChrZXlzLCAoaykgPT4gdGhpcy5wb3J0LmdldFBvbHlnb25UaWxlIShzZXQsIGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKSxcbiAgICAgICAgICBudWNsZXVzU2V0XG4gICAgICAgICAgICA/IHRoaXMuZmV0Y2hBbGwoa2V5cywgKGspID0+IHRoaXMucG9ydC5nZXRQb2x5Z29uVGlsZSEobnVjbGV1c1NldCwgay5sZXZlbCwgay5neCwgay5neSkpXG4gICAgICAgICAgICA6IFByb21pc2UucmVzb2x2ZShudWxsKSxcbiAgICAgICAgXSk7XG4gICAgICAgIGlmIChzdGFsZSgpKSByZXR1cm4gbnVsbDtcbiAgICAgICAgcmluZ3MgPSBmaWx0ZXJSaW5ncyhtZXJnZVBvbHlnb25UaWxlcyh0aWxlcyksIGhpZGRlbik7XG4gICAgICAgIG51Y2xlaSA9IG51Y2xldXNUaWxlcyA/IGZpbHRlclJpbmdzKG1lcmdlUG9seWdvblRpbGVzKG51Y2xldXNUaWxlcyksIGhpZGRlbikgOiBudWxsO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBnZW9tZXRyeUtleSA9IGAke2RhdGFzZXQuaWR9fHdob2xlfCR7aGlkZGVuS2V5fWA7XG4gICAgICBpZiAoZ2VvbWV0cnlLZXkgPT09IHRoaXMuY2VsbEdlb21ldHJ5S2V5ICYmIHRoaXMuY3VycmVudFJpbmdzKSB7XG4gICAgICAgIHJpbmdzID0gdGhpcy5jdXJyZW50UmluZ3M7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBwb2x5czogU3BhdGlhbFBvbHlnb25zID0gYXdhaXQgdGhpcy5wb3J0LmdldFBvbHlnb25zISgpO1xuICAgICAgICBpZiAoc3RhbGUoKSkgcmV0dXJuIG51bGw7XG4gICAgICAgIC8vIFdob2xlLWRhdGFzZXQgcmluZ3MgYXJlIGluZGV4LWFsaWduZWQgd2l0aCB0aGUgb2JzZXJ2YXRpb25zLlxuICAgICAgICByaW5ncyA9IGZpbHRlclJpbmdzKFxuICAgICAgICAgIHsgLi4ucG9seXMsIG9ic2VydmF0aW9uOiBVaW50MzJBcnJheS5mcm9tKHsgbGVuZ3RoOiBwb2x5cy5jb3VudCB9LCAoX3YsIGkpID0+IGkpIH0sIGhpZGRlbixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgcmluZ3MsIG51Y2xlaSwgZ2VvbWV0cnlLZXkgfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCB0cmFuc2NyaXB0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIHBsYW5UcmFuc2NyaXB0cyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLFxuICAgIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtb2RlID0gdmlldy50cmFuc2NyaXB0TW9kZTtcbiAgICBjb25zdCBqb2IgPSAobW9kZSA9PT0gJ2NpcmNsZXMnIHx8IG1vZGUgPT09ICdnbHlwaHMnKVxuICAgICAgJiYgKHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZSB8fCAodGhpcy5wb3J0LmdldFRyYW5zY3JpcHRHZW5lQmlucyAmJiBkYXRhc2V0LnRyYW5zY3JpcHRHZW5lQmlucykpXG4gICAgICA/ICh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1xuICAgICAgICA/IHRoaXMuYWxsR2VuZXNKb2IoZGF0YXNldCwgdmlldywgcmVjdCwgcHhQZXJVbml0KVxuICAgICAgICA6IHRoaXMuZ2VuZUpvYihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQpKVxuICAgICAgOiBudWxsO1xuICAgIGlmICgham9iKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRzJyk7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICAgIHRoaXMuY291bnRTb3VyY2UgPSBudWxsO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBNYXJrZXIgc2l6ZXMgZm9sbG93IHRoZSB6b29tLCBzbyB0aGUgem9vbSBpcyBwYXJ0IG9mIHRoZSBrZXk7IGEgcGFuIHRoYXQga2VlcHNcbiAgICAvLyB0aGUgc2FtZSB0aWxlcyBvbiBzY3JlZW4gY2hhbmdlcyBub3RoaW5nLlxuICAgIGNvbnN0IHBsYW5LZXkgPSBbXG4gICAgICBkYXRhc2V0LmlkLCBtb2RlLCBqb2Iua2V5LCB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5LCB0aGlzLmNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0LCB2aWV3KSxcbiAgICAgIHZpZXcudHJhbnNjcmlwdFNjYWxlLCB2aWV3LnRyYW5zY3JpcHRPcGFjaXR5LCBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHbHlwaHMpLFxuICAgICAgcHhQZXJVbml0LnRvUHJlY2lzaW9uKDQpLCB2aWV3LmhpZGRlbkdyb3Vwcy5qb2luKCdcXHUwMDAxJyksIHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmpvaW4oJywnKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnMpLCBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5sYXllcnMuZ2V0KCd0cmFuc2NyaXB0cycpO1xuICAgIGlmIChwbGFuS2V5ID09PSB0aGlzLmtleXMuZ2V0KCd0cmFuc2NyaXB0cycpICYmIGN1cnJlbnQgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhjdXJyZW50KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCB0aGlzLnRyYWNrKCdUcmFuc2NyaXB0cycsIGpvYi5sb2FkKCkpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgLy8gUGVyLWdlbmUgY291bnRzIGluIHZpZXcgY29tZSBmcm9tIHdoYXQgd2FzIGxvYWRlZCwgYmVmb3JlIGhpZGRlbiBnZW5lcyBhcmUgZHJvcHBlZDpcbiAgICAvLyBhIGhpZGRlbiBnZW5lIHN0aWxsIGhhcyB0cmFuc2NyaXB0cyB0aGVyZS4gU3VtbWVkIGRlbnNpdHkgZ3JpZHMgKG5vIHBlci1nZW5lIGxldmVscyxcbiAgICAvLyB6b29tZWQgb3V0KSBob2xkIGNsdXN0ZXJzLCBub3QgZ2VuZXM6IG5vIHBlci1nZW5lIGNvdW50cyB0aGVyZSwgcmF0aGVyIHRoYW4gYSBndWVzcy5cbiAgICB0aGlzLmNvdW50U291cmNlID0gKGxvYWRlZC5raW5kID8/IGpvYi5raW5kKSA9PT0gJ2dlbmVzJyAmJiAhbG9hZGVkLmNsdXN0ZXJlZFxuICAgICAgPyB7IG1lcmdlZDogbG9hZGVkLm1lcmdlZCwgZ2VuZXM6IFsuLi52aWV3LnRyYW5zY3JpcHRHZW5lc10gfSA6IG51bGw7XG4gICAgY29uc3QgaGlkZGVuID0gYXdhaXQgdGhpcy5oaWRkZW5Db2RlcyhkYXRhc2V0LCB2aWV3KTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuICAgIC8vIERlbnNpdHktZ3JpZCBtYXJrZXJzIGNhcnJ5IG5vIGNlbGxzIGFuZCB3ZXJlIGJ1aWx0IGZyb20gdGhlIHZpc2libGUgZ2VuZXMgb25seS5cbiAgICBjb25zdCBmaWx0ZXJlZCA9IGxvYWRlZC5jbHVzdGVyZWQgPyB7IG1lcmdlZDogbG9hZGVkLm1lcmdlZCwgcHg6IGxvYWRlZC5weCB9XG4gICAgICA6IGZpbHRlclRyYW5zY3JpcHRzKGxvYWRlZC5tZXJnZWQsIGxvYWRlZC5weCwgaGlkZGVuLFxuICAgICAgICAobG9hZGVkLmtpbmQgPz8gam9iLmtpbmQpID09PSAnZ2VuZXMnID8gaGlkZGVuR2VuZVNsb3RzKHZpZXcpIDogbnVsbCk7XG4gICAgbGV0IHsgbWVyZ2VkLCBweCB9ID0gZmlsdGVyZWQ7XG4gICAgbGV0IHNlbGVjdGlvbkJpbjogbnVtYmVyIHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/LmJpbiA/PyBudWxsO1xuICAgIGxldCBlbnRyeUdyb3VwOiBJbnQzMkFycmF5IHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/Lmdyb3VwID8/IG51bGw7XG4gICAgbGV0IGdyb3VwTmFtZXM6IHN0cmluZ1tdIHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/Lm5hbWVzID8/IG51bGw7XG4gICAgaWYgKGxvYWRlZC5sYWRkZXIpIHtcbiAgICAgIGNvbnN0IGcgPSB0aGlzLmdyb3VwU2VsZWN0aW9uKG1lcmdlZCwgdmlldywgbG9hZGVkLmxhZGRlciwgcHhQZXJVbml0KTtcbiAgICAgIGlmIChnKSAoeyBtZXJnZWQsIHB4LCBiaW46IHNlbGVjdGlvbkJpbiwgZ3JvdXA6IGVudHJ5R3JvdXAsIG5hbWVzOiBncm91cE5hbWVzIH0gPSBnKTtcbiAgICB9XG4gICAgLy8gQSBiaW4gb2YgdGhlIGFsbC1nZW5lIHB5cmFtaWQgbWl4ZXMgZ2VuZXMgYW5kIGNhcnJpZXMgbm9uZSwgc28gaXQgY2Fubm90IGJlIGNvbG91cmVkXG4gICAgLy8gYnkgZ2VuZTogY29sb3VyIGl0IGJ5IGl0cyBkb21pbmFudCBjZWxsJ3MgdHlwZSB1bnRpbCBpbmRpdmlkdWFsIHRyYW5zY3JpcHRzIHNob3cuXG4gICAgY29uc3Qga2luZCA9IGxvYWRlZC5raW5kID8/IGpvYi5raW5kO1xuICAgIGNvbnN0IGNvbG9yVmlldyA9IGtpbmQgPT09ICdiaW5zJyAmJiB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ICE9PSAnY2VsbFR5cGUnXG4gICAgICA/IHsgLi4udmlldywgdHJhbnNjcmlwdENvbG9yQnk6ICdjZWxsVHlwZScgYXMgY29uc3QgfVxuICAgICAgLy8gRGVuc2l0eS1ncmlkIG1hcmtlcnMgaGF2ZSBubyBjZWxsIHRvIHRha2UgYSB0eXBlIGZyb206IHRoZXkgdGFrZSB0aGVpciBjbHVzdGVyJ3MgY29sb3VyLlxuICAgICAgOiBsb2FkZWQuY2x1c3RlcmVkICYmIHZpZXcudHJhbnNjcmlwdENvbG9yQnkgPT09ICdjZWxsVHlwZSdcbiAgICAgICAgPyB7IC4uLnZpZXcsIHRyYW5zY3JpcHRDb2xvckJ5OiAnY2x1c3RlcicgYXMgY29uc3QgfSA6IHZpZXc7XG4gICAgLy8gRWFjaCBlbnRyeSdzIGNsdXN0ZXI6IGl0cyBtYXJrZXIncyBncm91cCwgb3IgdGhlIGdlbmUtdHJlZSBncm91cCBpdHMgZ2VuZSBpcyBpbi5cbiAgICBjb25zdCBnZW5lQ2x1c3RlciA9IHZpZXcudHJhbnNjcmlwdEdlbmVzLm1hcCgoZykgPT5cbiAgICAgIHZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHMuZmluZCgoeCkgPT4geC5nZW5lcy5pbmNsdWRlcyhnKSk/Lm5hbWUgPz8gZyk7XG4gICAgY29uc3QgY2x1c3Rlck9mID0gKGk6IG51bWJlcik6IHN0cmluZyB8IG51bGwgPT4gKGVudHJ5R3JvdXAgJiYgZ3JvdXBOYW1lc1xuICAgICAgPyBncm91cE5hbWVzW2VudHJ5R3JvdXBbaV1dID8/IG51bGxcbiAgICAgIDogZ2VuZUNsdXN0ZXJbbWVyZ2VkLmdlbmVbaV1dID8/IG51bGwpO1xuICAgIGNvbnN0IGZhY2VzID0gYXdhaXQgdGhpcy50cmFuc2NyaXB0Q29sb3JzKGRhdGFzZXQsIGNvbG9yVmlldywgbWVyZ2VkLCBraW5kID09PSAnZ2VuZXMnID8gY2x1c3Rlck9mIDogdW5kZWZpbmVkKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuXG4gICAgaWYgKHRoaXMucGxhbkluY29tcGxldGUpIHRoaXMua2V5cy5kZWxldGUoJ3RyYW5zY3JpcHRzJyk7XG4gICAgZWxzZSB0aGlzLmtleXMuc2V0KCd0cmFuc2NyaXB0cycsIHBsYW5LZXkpO1xuICAgIGNvbnN0IGRpYW0gPSBweC5tYXAoKGQpID0+IGQgLyBweFBlclVuaXQpO1xuICAgIHRoaXMuZHJhd24gPSB7XG4gICAgICBraW5kOiBsb2FkZWQua2luZCA/PyBqb2Iua2luZCxcbiAgICAgIGJpbjogc2VsZWN0aW9uQmluID8geyBzaXplOiBzZWxlY3Rpb25CaW4sIG9yaWdpbjogbG9hZGVkLmNsdXN0ZXJlZD8ub3JpZ2luID8/IFswLCAwXSB9XG4gICAgICAgIDogKGxvYWRlZC5raW5kID8gbG9hZGVkLmJpbiA6IGpvYi5iaW4pLFxuICAgICAgbWVyZ2VkLCByYWRpdXM6IGRpYW0ubWFwKChkKSA9PiBkIC8gMiksXG4gICAgICBnZW5lczogWy4uLnZpZXcudHJhbnNjcmlwdEdlbmVzXSwgcmVmOiBkYXRhc2V0LmltYWdlUmVmID8/IG51bGwsIGdyaWQ6IG51bGwsXG4gICAgICAuLi4oZW50cnlHcm91cCAmJiBncm91cE5hbWVzID8geyBlbnRyeUdyb3VwLCBncm91cE5hbWVzIH0gOiB7fSksXG4gICAgICAuLi4obG9hZGVkLmNsdXN0ZXJlZCA/IHsgZ3JvdXBHZW5lczogbG9hZGVkLmNsdXN0ZXJlZC5nZW5lcyB9IDoge30pLFxuICAgIH07XG4gICAgdGhpcy5ob3ZlckNhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5taWNyb25zUGVyVW5pdCA9IGRhdGFzZXQubWljcm9uc1BlclVuaXQgPz8gbnVsbDtcbiAgICBjb25zdCB0eXBlQ29sdW1uID0gdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyk7XG4gICAgdGhpcy5ob3ZlclR5cGVzID0gdHlwZUNvbHVtbiA/IGF3YWl0IHRoaXMuY2F0ZWdvcmljYWxDb2Rlcyh0eXBlQ29sdW1uKS5jYXRjaCgoKSA9PiBudWxsKSA6IG51bGw7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHBsYWNlOiBQbGFjZW1lbnQgPSB7IHNjYWxlOiByZWY/LnNjYWxlID8/IFsxLCAxXSwgdHJhbnNsYXRlOiByZWY/LnRyYW5zbGF0ZSA/PyBbMCwgMF0gfTtcbiAgICBpZiAobW9kZSA9PT0gJ2NpcmNsZXMnKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICB0aGlzLmRyYXdUcmFuc2NyaXB0Q2lyY2xlcyhtZXJnZWQsIGRpYW0sIGZhY2VzLnJnYmEsIHZpZXcsIHBsYWNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kcmF3VHJhbnNjcmlwdEdseXBocyhtZXJnZWQsIGRpYW0sIGZhY2VzLCB2aWV3LCBwbGFjZSwgcHhQZXJVbml0KTtcbiAgICB9XG4gIH1cblxuICAvKiogT25lIHNpemVkIGNpcmNsZSBwZXIgZW50cnksIHRoZSBzaXplIHNheWluZyBob3cgbWFueSB0cmFuc2NyaXB0cyBpdCBzdGFuZHMgZm9yLiAqL1xuICBwcml2YXRlIGRyYXdUcmFuc2NyaXB0Q2lyY2xlcyhcbiAgICBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSwgZGlhbTogRmxvYXQzMkFycmF5LCByZ2JhOiBSR0JBW10sIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgeyBzY2FsZSwgdHJhbnNsYXRlIH06IFBsYWNlbWVudCxcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQgKiAyKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICBwb3NpdGlvbnNbMiAqIGldID0gbWVyZ2VkLnhbaV07XG4gICAgICBwb3NpdGlvbnNbMiAqIGkgKyAxXSA9IG1lcmdlZC55W2ldO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9IHRoaXMudmlld2VyIS5hZGRQb2ludHMocG9zaXRpb25zLCB7XG4gICAgICBuYW1lOiAndHJhbnNjcmlwdHMnLFxuICAgICAgc2l6ZTogZGlhbSxcbiAgICAgIGZhY2VDb2xvcjogcmdiYSxcbiAgICAgIC8vIEEgZGFyayByaW06IGEgdHJhbnNjcmlwdCBjb2xvdXJlZCBieSBpdHMgY2VsbCdzIHR5cGUgaXMgb3RoZXJ3aXNlIHRoZSBzYW1lXG4gICAgICAvLyBjb2xvdXIgYXMgdGhlIGNlbGwgZmlsbCBpdCBzaXRzIG9uLCBhbmQgdmFuaXNoZXMgaW50byBpdC5cbiAgICAgIGJvcmRlckNvbG9yOiBbMC4wNCwgMC4wNCwgMC4wNSwgMC45XSxcbiAgICAgIGJvcmRlcldpZHRoOiAwLjE4ICogbWVkaWFuKGRpYW0pLFxuICAgICAgb3BhY2l0eTogdmlldy50cmFuc2NyaXB0T3BhY2l0eSxcbiAgICAgIHNjYWxlLFxuICAgICAgdHJhbnNsYXRlLFxuICAgIH0pO1xuICAgIHRoaXMucmVwbGFjZSgndHJhbnNjcmlwdHMnLCBsYXllcik7XG4gIH1cblxuICBwcml2YXRlIGRyYXdUcmFuc2NyaXB0R2x5cGhzKFxuICAgIG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlLCBkaWFtOiBGbG9hdDMyQXJyYXksIGZhY2VzOiBUcmFuc2NyaXB0RmFjZXMsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgeyBzY2FsZSwgdHJhbnNsYXRlIH06IFBsYWNlbWVudCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IHZvaWQge1xuICAgIC8vIEdseXBoczogZWFjaCBlbnRyeSBiZWNvbWVzIGl0cyBnZW5lJ3MgaWNvbiBwb2x5Z29uLCBmaWxsZWQgdGhyb3VnaCBhIGRpc2NyZXRlXG4gICAgLy8gY29sb3JtYXAgYW5kIG91dGxpbmVkIGRhcmsgc28gc21hbGwgaWNvbnMgc3RheSByZWFkYWJsZSBvdmVyIHRoZSB0aXNzdWUuIFdpdGggZXZlcnlcbiAgICAvLyBnZW5lIGRyYXduIHRoZXJlIGlzIG9uZSBpY29uIGZvciBhbGwgb2YgdGhlbSDigJQgMTgsMDAwIHNoYXBlcyB3b3VsZCBzYXkgbm90aGluZy5cbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICAgIGNvbnN0IGdseXBoRm9yID0gKHNsb3Q6IG51bWJlcik6IFRyYW5zY3JpcHRHbHlwaCA9PlxuICAgICAgKHZpZXcudHJhbnNjcmlwdEdseXBoc1tnZW5lc1tzbG90XV0gYXMgVHJhbnNjcmlwdEdseXBoIHwgdW5kZWZpbmVkKSA/PyBkZWZhdWx0R2x5cGhGb3Ioc2xvdCk7XG4gICAgY29uc3Qgc2luZ2xlID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gZ2x5cGhPdXRsaW5lKCh2aWV3LnRyYW5zY3JpcHRHbHlwaHNbQUxMX0dFTkVTXSBhcyBUcmFuc2NyaXB0R2x5cGggfCB1bmRlZmluZWQpID8/ICdjaXJjbGUnKVxuICAgICAgOiBudWxsO1xuICAgIGNvbnN0IG91dGxpbmVzID0gc2luZ2xlID8gW10gOiBnZW5lcy5tYXAoKF9nLCBzbG90KSA9PiBnbHlwaE91dGxpbmUoZ2x5cGhGb3Ioc2xvdCkpKTtcbiAgICBjb25zdCByYWRpdXMgPSBkaWFtLm1hcCgoZCkgPT4gZCAvIDIpO1xuICAgIGNvbnN0IHsgY29vcmRzLCBvZmZzZXRzIH0gPSBnbHlwaFJpbmdzKFxuICAgICAgbWVyZ2VkLngsIG1lcmdlZC55LCByYWRpdXMsIChpKSA9PiBzaW5nbGUgPz8gb3V0bGluZXNbbWVyZ2VkLmdlbmVbaV1dLFxuICAgICk7XG4gICAgY29uc3QgZmlsbCA9IHRoaXMudmlld2VyIS5hZGRTaGFwZXMoY29vcmRzLCBvZmZzZXRzLCB7XG4gICAgICBuYW1lOiAndHJhbnNjcmlwdHMnLFxuICAgICAgZHJhdzogJ2ZpbGwnLFxuICAgICAgdmFsdWVzOiBmYWNlcy52YWx1ZXMsXG4gICAgICBjb2xvcm1hcDogZmFjZXMuY29sb3JtYXAsXG4gICAgICBjb250cmFzdExpbWl0czogWzAsIDFdLFxuICAgICAgb3BhY2l0eTogdmlldy50cmFuc2NyaXB0T3BhY2l0eSxcbiAgICAgIHNjYWxlLFxuICAgICAgdHJhbnNsYXRlLFxuICAgIH0pO1xuICAgIHRoaXMucmVwbGFjZSgndHJhbnNjcmlwdHMnLCBmaWxsKTtcbiAgICAvLyBBIGRhcmsgcmltIGtlZXBzIGEgZmV3IGxhcmdlIGljb25zIHJlYWRhYmxlIG92ZXIgdGhlIHRpc3N1ZTsgb24gbWFueSBzbWFsbCBvbmVzIHRoZVxuICAgIC8vIHJpbXMgbWVyZ2UgaW50byBhIHNvbGlkIGRhcmsgc2hlZXQgdGhhdCBoaWRlcyBldmVyeSBjb2xvdXIsIHNvIHRoZXkgYXJlIGxlZnQgb2ZmLlxuICAgIGNvbnN0IG1lZGlhblB4ID0gbWVkaWFuKGRpYW0pICogcHhQZXJVbml0O1xuICAgIGlmIChtZXJnZWQuY291bnQgPiBHTFlQSF9PVVRMSU5FX01BWCB8fCBtZWRpYW5QeCA8IEdMWVBIX09VVExJTkVfTUlOX1BYKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGVkZ2UgPSB0aGlzLnZpZXdlciEuYWRkU2hhcGVzKGNvb3Jkcywgb2Zmc2V0cywge1xuICAgICAgbmFtZTogJ3RyYW5zY3JpcHQgb3V0bGluZXMnLFxuICAgICAgZHJhdzogJ291dGxpbmUnLFxuICAgICAgY29sb3I6IFswLjA1LCAwLjA1LCAwLjA1LCAxXSxcbiAgICAgIG9wYWNpdHk6IE1hdGgubWluKDEsIHZpZXcudHJhbnNjcmlwdE9wYWNpdHkgKyAwLjEpLFxuICAgICAgc2NhbGUsXG4gICAgICB0cmFuc2xhdGUsXG4gICAgfSk7XG4gICAgdGhpcy5yZXBsYWNlKCd0cmFuc2NyaXB0T3V0bGluZScsIGVkZ2UpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGhvdmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgZHJhd246IERyYXduVHJhbnNjcmlwdHMgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBob3ZlclR5cGVzOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgbWV0YTogU3BhdGlhbENvbHVtblsnbWV0YSddIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIERldGFpbHMgYWxyZWFkeSBmZXRjaGVkLCBieSBob3ZlcmVkIGVudHJ5LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhvdmVyQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gIHByaXZhdGUgaG92ZXJLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGhvdmVyVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFRvb2x0aXAgbGluZXMgZm9yIHRoZSB0cmFuc2NyaXB0IG1hcmtlciB1bmRlciB3b3JsZCBwb2ludCBgKHd4LCB3eSlgLCBvciBudWxsLlxuICAgKlxuICAgKiBSZXR1cm5zIHdoYXQgaXMga25vd24gYXQgb25jZSAoZ2VuZSwgY291bnQsIGNlbGwgdHlwZSk7IGFueXRoaW5nIHRoYXQgbmVlZHMgdGhlXG4gICAqIHNlcnZlciDigJQgZGlzdGluY3QgZ2VuZXMgaW4gYSBncm91cCwgaXRzIHRvcCBnZW5lcyBhbmQgY2VsbHMsIHRoZSBjZWxsJ3MgZGlzcGxheSBpZCDigJRcbiAgICogYXJyaXZlcyB0aHJvdWdoIGBvbkRldGFpbHNgIG9uY2UgdGhlIHBvaW50ZXIgaGFzIHJlc3RlZCBvbiB0aGUgbWFya2VyIGJyaWVmbHkuXG4gICAqL1xuICBob3ZlckF0KFxuICAgIHd4OiBudW1iZXIsIHd5OiBudW1iZXIsIHJhZGl1c1dvcmxkOiBudW1iZXIsIG9uRGV0YWlsczogKGxpbmVzOiBzdHJpbmdbXSkgPT4gdm9pZCxcbiAgKTogc3RyaW5nW10gfCBudWxsIHtcbiAgICBjb25zdCBkID0gdGhpcy5kcmF3bjtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXJzLmdldCgndHJhbnNjcmlwdHMnKTtcbiAgICBpZiAoIWQgfHwgIWxheWVyIHx8ICF0aGlzLnZpZXdlcj8ubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGxheWVyKSB8fCAhZC5tZXJnZWQuY291bnQpIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBudWxsO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IHN4ID0gZC5yZWY/LnNjYWxlPy5bMF0gPz8gMTtcbiAgICBjb25zdCBzeSA9IGQucmVmPy5zY2FsZT8uWzFdID8/IDE7XG4gICAgY29uc3QgeCA9ICh3eCAtIChkLnJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMCkpIC8gc3g7XG4gICAgY29uc3QgeSA9ICh3eSAtIChkLnJlZj8udHJhbnNsYXRlPy5bMV0gPz8gMCkpIC8gc3k7XG4gICAgY29uc3QgaSA9IHBpY2tOZWFyZXN0KGQsIHgsIHksIHJhZGl1c1dvcmxkIC8gTWF0aC5hYnMoc3gpKTtcbiAgICBpZiAoaSA8IDApIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBudWxsO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IGtleSA9IGAke2Qua2luZH18JHtkLm1lcmdlZC54W2ldfXwke2QubWVyZ2VkLnlbaV19fCR7ZC5tZXJnZWQuZ2VuZVtpXX1gO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG92ZXJDYWNoZS5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuICAgIGlmIChrZXkgIT09IHRoaXMuaG92ZXJLZXkpIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBrZXk7XG4gICAgICBpZiAodGhpcy5ob3ZlclRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy5ob3ZlclRpbWVyKTtcbiAgICAgIHRoaXMuaG92ZXJUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4gdm9pZCB0aGlzLmZldGNoRGV0YWlscyhkLCBpLCBrZXksIG9uRGV0YWlscyksIDE1MCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmRlc2NyaWJlKGQsIGksIG51bGwpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaERldGFpbHMoXG4gICAgZDogRHJhd25UcmFuc2NyaXB0cywgaTogbnVtYmVyLCBrZXk6IHN0cmluZywgb25EZXRhaWxzOiAobGluZXM6IHN0cmluZ1tdKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0U3VtbWFyeSB8fCB0aGlzLmhvdmVyS2V5ICE9PSBrZXkpIHJldHVybjtcbiAgICBjb25zdCBvYnMgPSBkLm1lcmdlZC5vYnNlcnZhdGlvbltpXTtcbiAgICBjb25zdCBjZWxscyA9IG9icyA9PT0gTk9fT0JTRVJWQVRJT04gPyBbXSA6IFtvYnNdO1xuICAgIGxldCBib3g6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdIHwgdW5kZWZpbmVkO1xuICAgIGlmICgoZC5raW5kID09PSAnYmlucycgfHwgZC5raW5kID09PSAnZ2VuZXMnKSAmJiBkLmJpbikge1xuICAgICAgY29uc3QgeyBzaXplLCBvcmlnaW4gfSA9IGQuYmluO1xuICAgICAgY29uc3QgYnggPSBNYXRoLmZsb29yKChkLm1lcmdlZC54W2ldIC0gb3JpZ2luWzBdKSAvIHNpemUpO1xuICAgICAgY29uc3QgYnkgPSBNYXRoLmZsb29yKChkLm1lcmdlZC55W2ldIC0gb3JpZ2luWzFdKSAvIHNpemUpO1xuICAgICAgY29uc3QgeDAgPSBvcmlnaW5bMF0gKyBieCAqIHNpemU7XG4gICAgICBjb25zdCB5MCA9IG9yaWdpblsxXSArIGJ5ICogc2l6ZTtcbiAgICAgIGJveCA9IFt4MCwgeTAsIHgwICsgc2l6ZSwgeTAgKyBzaXplXTtcbiAgICB9IGVsc2UgaWYgKGQua2luZCA9PT0gJ2luZGl2aWR1YWwnKSB7XG4gICAgICBjb25zdCBlID0gMC4wMjtcbiAgICAgIGJveCA9IFtkLm1lcmdlZC54W2ldIC0gZSwgZC5tZXJnZWQueVtpXSAtIGUsIGQubWVyZ2VkLnhbaV0gKyBlLCBkLm1lcmdlZC55W2ldICsgZV07XG4gICAgfVxuICAgIGNvbnN0IGdlbmVzID0gZC5ncm91cEdlbmVzICYmIGQuZW50cnlHcm91cCA/IGQuZ3JvdXBHZW5lc1tkLmVudHJ5R3JvdXBbaV1dIDogdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gYXdhaXQgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRTdW1tYXJ5KHsgYm94LCBjZWxscywgLi4uKGdlbmVzID8geyBnZW5lcyB9IDoge30pIH0pO1xuICAgICAgY29uc3QgbGluZXMgPSB0aGlzLmRlc2NyaWJlKGQsIGksIHN1bW1hcnkpO1xuICAgICAgdGhpcy5ob3ZlckNhY2hlLnNldChrZXksIGxpbmVzKTtcbiAgICAgIGlmICh0aGlzLmhvdmVyS2V5ID09PSBrZXkpIG9uRGV0YWlscyhsaW5lcyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHRyYW5zY3JpcHQgZGV0YWlscyB1bmF2YWlsYWJsZScsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSB0b29sdGlwIHRleHQgZm9yIGVudHJ5IGBpYCwgd2l0aCB0aGUgc2VydmVyJ3MgZGV0YWlscyB3aGVuIHRoZXkgaGF2ZSBhcnJpdmVkLiAqL1xuICBwcml2YXRlIGRlc2NyaWJlKGQ6IERyYXduVHJhbnNjcmlwdHMsIGk6IG51bWJlciwgczogU3BhdGlhbFRyYW5zY3JpcHRTdW1tYXJ5IHwgbnVsbCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB0ID0gZC5tZXJnZWQ7XG4gICAgY29uc3QgbiA9IHQud2VpZ2h0W2ldO1xuICAgIGNvbnN0IG9icyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgY29uc3QgZm10ID0gKHY6IG51bWJlcikgPT4gdi50b0xvY2FsZVN0cmluZygpO1xuICAgIGNvbnN0IHR5cGVPZiA9IChvOiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IHR5cGVzID0gdGhpcy5ob3ZlclR5cGVzO1xuICAgICAgaWYgKCF0eXBlcyB8fCBvID09PSBOT19PQlNFUlZBVElPTiB8fCB0eXBlcy5tZXRhLmtpbmQgIT09ICdjYXRlZ29yaWNhbCcpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgYyA9IHR5cGVzLmNvZGVzW29dO1xuICAgICAgcmV0dXJuIGMgPT09IE5PX0NBVEVHT1JZID8gbnVsbCA6IHR5cGVzLm1ldGEuY2F0ZWdvcmllc1tjXSA/PyBudWxsO1xuICAgIH07XG4gICAgY29uc3QgY2VsbExpbmUgPSAobzogbnVtYmVyLCBwcmVmaXg6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKG8gPT09IE5PX09CU0VSVkFUSU9OKSByZXR1cm4gJ291dHNpZGUgYW55IGNlbGwnO1xuICAgICAgY29uc3QgaWQgPSBzPy5jZWxsSWRzPy5bb10gPz8gYCMke299YDtcbiAgICAgIGNvbnN0IHR5cGUgPSB0eXBlT2Yobyk7XG4gICAgICByZXR1cm4gYCR7cHJlZml4fSAke2lkfSR7dHlwZSA/IGAgwrcgJHt0eXBlfWAgOiAnJ31gO1xuICAgIH07XG5cbiAgICBpZiAoZC5raW5kID09PSAnYmlucycpIHtcbiAgICAgIGNvbnN0IGxpbmVzID0gW2Ake2ZtdChuKX0gdHJhbnNjcmlwdHMgwrcgYWxsIGdlbmVzYF07XG4gICAgICBpZiAoZC5iaW4pIGxpbmVzLnB1c2goYCR7ZC5iaW4uc2l6ZS50b0ZpeGVkKDEpfSDDlyAke2QuYmluLnNpemUudG9GaXhlZCgxKX0gwrVtIGFyZWFgKTtcbiAgICAgIGlmIChzPy50cmFuc2NyaXB0cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYCR7Zm10KHMuZ2VuZXMgPz8gMCl9IGRpc3RpbmN0IGdlbmVzIMK3ICR7Zm10KHMuY2VsbHMgPz8gMCl9IGNlbGwke3MuY2VsbHMgPT09IDEgPyAnJyA6ICdzJ31gXG4gICAgICAgICAgKyAocy51bmFzc2lnbmVkID8gYCDCtyAke2ZtdChzLnVuYXNzaWduZWQpfSBvdXRzaWRlIGNlbGxzYCA6ICcnKSk7XG4gICAgICAgIGlmIChzLnRvcEdlbmVzPy5sZW5ndGgpIHtcbiAgICAgICAgICBsaW5lcy5wdXNoKGB0b3AgZ2VuZXM6ICR7cy50b3BHZW5lcy5zbGljZSgwLCA1KS5tYXAoKGcpID0+IGAke2cubmFtZX0gJHtmbXQoZy5jb3VudCl9YCkuam9pbignLCAnKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbGluZXMucHVzaChjZWxsTGluZShvYnMsICdtb3N0bHkgY2VsbCcpKTtcbiAgICAgIGlmICghcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkpIGxpbmVzLnB1c2goJ2xvYWRpbmcgZGV0YWlsc+KApicpO1xuICAgICAgcmV0dXJuIGxpbmVzO1xuICAgIH1cbiAgICBpZiAoZC5raW5kID09PSAnaW5kaXZpZHVhbCcpIHtcbiAgICAgIGNvbnN0IGdlbmUgPSBzPy50b3BHZW5lcz8uWzBdPy5uYW1lO1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgZ2VuZSA/IGAke2dlbmV9IHRyYW5zY3JpcHRgIDogJ1RyYW5zY3JpcHQnLFxuICAgICAgICBjZWxsTGluZShvYnMsICdpbiBjZWxsJyksXG4gICAgICAgIC4uLighcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkgPyBbJ2xvYWRpbmcgZGV0YWlsc+KApiddIDogW10pLFxuICAgICAgXTtcbiAgICB9XG4gICAgY29uc3QgZ2VuZSA9IGQuZ2VuZXNbdC5nZW5lW2ldXSA/PyAndHJhbnNjcmlwdCc7XG4gICAgaWYgKGQuYmluKSB7XG4gICAgICBjb25zdCB1bSA9IGQuYmluLnNpemUgKiAodGhpcy5taWNyb25zUGVyVW5pdCA/PyAxKTtcbiAgICAgIGNvbnN0IGdyb3VwID0gZC5lbnRyeUdyb3VwICYmIGQuZ3JvdXBOYW1lcyA/IGQuZ3JvdXBOYW1lc1tkLmVudHJ5R3JvdXBbaV1dIDogZ2VuZTtcbiAgICAgIGNvbnN0IHRvcCA9IHM/LnRvcEdlbmVzPy5sZW5ndGhcbiAgICAgICAgPyBbcy50b3BHZW5lcy5zbGljZSgwLCA2KS5tYXAoKGcpID0+IGAke2cubmFtZX0gJHtmbXQoZy5jb3VudCl9YCkuam9pbignLCAnKV0gOiBbXTtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGAke2dyb3VwfSDCtyAke2ZtdChuKX0gdHJhbnNjcmlwdCR7biA9PT0gMSA/ICcnIDogJ3MnfWAsXG4gICAgICAgIC4uLihkLmdyb3VwR2VuZXMgPyB0b3AgOiBncm91cCAhPT0gZ2VuZSA/IFtgbW9zdGx5ICR7Z2VuZX1gXSA6IFtdKSxcbiAgICAgICAgYCR7dW0udG9GaXhlZCgxKX0gw5cgJHt1bS50b0ZpeGVkKDEpfSDCtW0gYXJlYSDCtyB6b29tIGluIHRvIHNwbGl0YCxcbiAgICAgICAgLi4uKG9icyA9PT0gTk9fT0JTRVJWQVRJT04gJiYgZC5ncm91cEdlbmVzID8gW10gOiBbY2VsbExpbmUob2JzLCAnbW9zdGx5IGNlbGwnKV0pLFxuICAgICAgICAuLi4oIXMgJiYgZC5ncm91cEdlbmVzICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0U3VtbWFyeSA/IFsnbG9hZGluZyBkZXRhaWxz4oCmJ10gOiBbXSksXG4gICAgICBdO1xuICAgIH1cbiAgICByZXR1cm4gbiA+IDFcbiAgICAgID8gW2Ake2dlbmV9IMK3ICR7Zm10KG4pfSB0cmFuc2NyaXB0c2AsICdncm91cGVkOiB6b29tIGluIHRvIHNwbGl0JywgY2VsbExpbmUob2JzLCAnbmVhciBjZWxsJyldXG4gICAgICA6IFtgJHtnZW5lfSB0cmFuc2NyaXB0YCwgY2VsbExpbmUob2JzLCAnaW4gY2VsbCcpXTtcbiAgfVxuXG4gIC8qKiBQaHlzaWNhbCBtYXJrZXIgc2l6ZSBuZWVkcyDCtW07IG51bGwgd2hlbiB0aGUgZGF0YXNldCdzIHVuaXQgaXMgdW5rbm93bi4gKi9cbiAgcHJpdmF0ZSBweFBlck1pY3JvbihkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgcHhQZXJVbml0OiBudW1iZXIpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBkYXRhc2V0Lm1pY3JvbnNQZXJVbml0ID8gcHhQZXJVbml0IC8gZGF0YXNldC5taWNyb25zUGVyVW5pdCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY2hvc2VuIGdlbmVzLCBhdCB0aGUgbGV2ZWwgdGhlIHpvb20gY2FsbHMgZm9yIOKAlCBvciBjb2Fyc2VyLCB3aGlsZSB0aGUgbWFya2VycyBpblxuICAgKiB2aWV3IHdvdWxkIGV4Y2VlZCB0aGUgYnVkZ2V0LlxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lSm9iKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCByZWN0OiBEYXRhUmVjdCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IFRyYW5zY3JpcHRKb2IgfCBudWxsIHtcbiAgICBjb25zdCBtZXRhID0gZGF0YXNldC50cmFuc2NyaXB0VGlsZXM7XG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lcztcbiAgICBpZiAoIW1ldGEgfHwgIWdlbmVzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgZmlyc3QgPSB0cmFuc2NyaXB0TGV2ZWxGb3IocHhQZXJVbml0LCBtZXRhLmxldmVscyk7XG4gICAgY29uc3Qga2V5c0F0ID0gKGw6IG51bWJlcikgPT4gdGlsZXNJblJlY3QocmVjdCwgbCwgbWV0YS5sZXZlbHMsIG1ldGEuYm91bmRzLCBNQVhfVFJBTlNDUklQVF9USUxFUyk7XG4gICAgY29uc3QgcXVlcnkgPSB7IGdlbmVzLCBxdWFsaXR5OiB2aWV3LnRyYW5zY3JpcHRRdWFsaXR5IH07XG4gICAgY29uc3QgcHhQZXJNaWNyb24gPSB0aGlzLnB4UGVyTWljcm9uKGRhdGFzZXQsIHB4UGVyVW5pdCk7XG4gICAgY29uc3QgbXggPSAocmVjdC54MSAtIHJlY3QueDApICogMC4yNTtcbiAgICBjb25zdCBteSA9IChyZWN0LnkxIC0gcmVjdC55MCkgKiAwLjI1O1xuICAgIGNvbnN0IGFyb3VuZDogRGF0YVJlY3QgPSB7IHgwOiByZWN0LngwIC0gbXgsIHkwOiByZWN0LnkwIC0gbXksIHgxOiByZWN0LngxICsgbXgsIHkxOiByZWN0LnkxICsgbXkgfTtcbiAgICAvLyBab29tZWQgb3V0LCBlYWNoIGdlbmUncyB0cmFuc2NyaXB0cyBhcmUgZ3JvdXBlZCBvbiB0aGUgYWxsLWdlbmUgcHlyYW1pZCdzIGJpbiBsYWRkZXIsXG4gICAgLy8gc28gYSBnZW5lIHNlbGVjdGlvbiByZWFkcyBsaWtlIFwiYWxsIGdlbmVzXCIgZG9lczogb25lIG1hcmtlciBwZXIgZ2VuZSBwZXIgYXJlYSwgc2l6ZWRcbiAgICAvLyBieSBob3cgbWFueSBpdCBob2xkczsgem9vbWVkIGluIGZhciBlbm91Z2gsIGV2ZXJ5IHRyYW5zY3JpcHQgaXMgaXRzIG93biBtYXJrZXIuXG4gICAgY29uc3QgbGFkZGVyID0gZGF0YXNldC50cmFuc2NyaXB0Qmlucz8ubGV2ZWxzO1xuICAgIGNvbnN0IGJhc2VCaW4gPSBsYWRkZXI/LlswXT8uYmluU2l6ZVxuICAgICAgPz8gKGRhdGFzZXQubWljcm9uc1BlclVuaXQgPyBQWVJBTUlEX0JBU0VfQklOX1VNIC8gZGF0YXNldC5taWNyb25zUGVyVW5pdCA6IDApO1xuICAgIGNvbnN0IGJpbiA9IGdlbmVCaW5TaXplKHB4UGVyVW5pdCwgYmFzZUJpbiwgbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMpO1xuICAgIC8vIFpvb21lZCBvdXQgdG8gYmlucyBhcyB3aWRlIGFzIHRoZSBkZW5zaXR5IGdyaWQsIGEgc2VsZWN0aW9uIGlzIGRyYXduIGZyb20gdGhlIHBlci1nZW5lXG4gICAgLy8gZGVuc2l0eSBncmlkcyDigJQgb25lIGNhY2hlZCByZXF1ZXN0IHBlciBjbHVzdGVyIOKAlCByYXRoZXIgdGhhbiAxMHgncyBjb2Fyc2UgcGVyLWdlbmVcbiAgICAvLyB0aWxlcywgd2hpY2ggdGFrZSBtaW51dGVzIGZvciBhIGZldyBodW5kcmVkIGdlbmVzLlxuICAgIC8vIFdpdGggdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHMsIGV2ZXJ5IHpvb20gb2YgYSBzZWxlY3Rpb24gcmVhZHMgdGhlbTogdGhlIGxldmVsIHRoZVxuICAgIC8vIHpvb20gY2FsbHMgZm9yLCBjb2Fyc2VyIHdoaWxlIHRoZSBtYXJrZXJzIHdvdWxkIGV4Y2VlZCB0aGUgbWF4LlxuICAgIC8vIEJvdGggYXJlIGJ1aWx0IGZyb20gaGlnaC1xdWFsaXR5IGNhbGxzIG9ubHk6IHdpdGggbG93LXF1YWxpdHkgY2FsbHMgaW5jbHVkZWQsIHRoZVxuICAgIC8vIHF1YWxpdHktYXdhcmUgdGlsZXMgYmVsb3cgc2VydmUgZXZlcnkgem9vbSAoYXMgbG9uZyBhcyB0aGVyZSBhcmUgdGlsZXMgdG8gc2VydmUpLlxuICAgIGNvbnN0IGhpZ2hPbmx5ID0gdmlldy50cmFuc2NyaXB0UXVhbGl0eSAhPT0gJ2FsbCcgfHwgIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZTtcbiAgICBjb25zdCBnZW5lQmlucyA9IGRhdGFzZXQudHJhbnNjcmlwdEdlbmVCaW5zO1xuICAgIGNvbnN0IGZyb21HZW5lQmlucyA9IGhpZ2hPbmx5ICYmIGdlbmVCaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0R2VuZUJpbnM7XG4gICAgaWYgKGZyb21HZW5lQmlucyAmJiAoYmluICE9PSBudWxsIHx8ICF0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZW5lQmluc0pvYihkYXRhc2V0LCB2aWV3LCBhcm91bmQsIGdlbmVCaW5zLCBiaW4gPz8gZ2VuZUJpbnMubGV2ZWxzWzBdLmJpblNpemUsIG14LCBteSwgcmVjdCk7XG4gICAgfVxuICAgIGNvbnN0IGdyaWQgPSBkYXRhc2V0LmRlbnNpdHk/LmdyaWRTaXplWzBdID8/IDA7XG4gICAgaWYgKGhpZ2hPbmx5ICYmIGJpbiAhPT0gbnVsbCAmJiBncmlkID4gMCAmJiB0aGlzLnBvcnQuZ2V0RGVuc2l0eSAmJiBiaW4gPj0gZ3JpZCAqIDAuNzUpIHtcbiAgICAgIHJldHVybiB0aGlzLmNsdXN0ZXJEZW5zaXR5Sm9iKGRhdGFzZXQsIHZpZXcsIGFyb3VuZCwgcHhQZXJVbml0LCBNYXRoLm1heChiaW4sIGdyaWQpLCBteCwgbXksIHJlY3QpO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2dlbmVzJyxcbiAgICAgIC8vIFRoZSBjbGlwIHdpbmRvdywgaW4gcXVhcnRlci12aWV3IHN0ZXBzOiBhIHBhbiBwYXN0IHRoZSBtYXJnaW4gcmUtY2xpcHMuXG4gICAgICBrZXk6IGBnZW5lc3wke2dlbmVzLmpvaW4oJywnKX18JHt2aWV3LnRyYW5zY3JpcHRRdWFsaXR5fXwke3ZpZXcudHJhbnNjcmlwdEJ1ZGdldH18JHtiaW4gPz8gJ2VhY2gnfXxgXG4gICAgICAgICsgYCR7TWF0aC5mbG9vcihyZWN0LngwIC8gKG14IHx8IDEpKX0sJHtNYXRoLmZsb29yKHJlY3QueTAgLyAobXkgfHwgMSkpfXwke2tleXNBdChmaXJzdCkubWFwKHRpbGVJZCl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgLy8gVGhlIHpvb20ncyBvd24gbGV2ZWwgb25seTogb3ZlciB0aGUgYnVkZ2V0LCB0aGUgdHJhbnNjcmlwdHMgYXJlIGNvbWJpbmVkIGludG9cbiAgICAgICAgLy8gbGFyZ2VyIG1hcmtlcnMgKGdyb3VwU2VsZWN0aW9uKSwgbmV2ZXIgZmV0Y2hlZCBmcm9tIHNsb3dlciBjb2Fyc2UgbGV2ZWxzLlxuICAgICAgICBjb25zdCB0aWxlcyA9IGF3YWl0IHRoaXMuZmV0Y2hBbGwoa2V5c0F0KGZpcnN0KSxcbiAgICAgICAgICAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRUaWxlIShrLmxldmVsLCBrLmd4LCBrLmd5LCBxdWVyeSkpO1xuICAgICAgICAvLyBPbmx5IHdoYXQgaXMgb24gc2NyZWVuIChhbmQgYSBtYXJnaW4sIHNvIGEgc21hbGwgcGFuIG5lZWRzIG5vdGhpbmcgbmV3KSBjb3VudHNcbiAgICAgICAgLy8gYWdhaW5zdCB0aGUgYnVkZ2V0IGFuZCB0aGUgY2FwOyBhIHRpbGUgcmVhY2hlcyBmYXIgcGFzdCB0aGUgdmlldy5cbiAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXModGlsZXMubWFwKCh0KSA9PiBjbGlwVHJhbnNjcmlwdHModCwgYXJvdW5kKSksIE1BWF9UUkFOU0NSSVBUUyk7XG4gICAgICAgIGNvbnN0IHB4ID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgcHhbaV0gPSB0cmFuc2NyaXB0TWFya2VyUHgobWVyZ2VkLndlaWdodFtpXSwgdmlldy50cmFuc2NyaXB0U2NhbGUsIHB4UGVyTWljcm9uKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYmFzZUJpbiA+IDBcbiAgICAgICAgICA/IHsgbWVyZ2VkLCBweCwgbGFkZGVyOiB7IGJhc2VCaW4sIGxldmVsczogbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMsIHN0YXJ0OiBiaW4gfSB9XG4gICAgICAgICAgOiB7IG1lcmdlZCwgcHggfTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGdlbmUgc2VsZWN0aW9uIGZyb20gdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHM6IHN0YXJ0aW5nIGF0IHRoZSBsZXZlbCB3aG9zZSBiaW5zIGFyZVxuICAgKiBgc3RhcnRCaW5gLCBmZXRjaCB0aGUgdmlldydzIHRpbGVzIGZvciB0aGUgc2VsZWN0ZWQgZ2VuZXMgYW5kIHN0ZXAgdG8gYSBjb2Fyc2VyIGxldmVsIHdoaWxlXG4gICAqIG9uZSBtYXJrZXIgcGVyIGNsdXN0ZXIgcGVyIGJpbiB3b3VsZCBleGNlZWQgdGhlIG1heC4gSGlkZGVuIGdlbmVzIGFyZSBmZXRjaGVkIHRvbyAodGhlaXJcbiAgICogY291bnRzIGluIHZpZXcgc3RpbGwgc2hvdykgYW5kIGRyb3BwZWQgYmVmb3JlIGRyYXdpbmc7IGdyb3VwaW5nIGJ5IGNsdXN0ZXIgaGFwcGVucyB0aGVyZS5cbiAgICovXG4gIHByaXZhdGUgZ2VuZUJpbnNKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIGFyb3VuZDogRGF0YVJlY3QsXG4gICAgbWV0YTogTm9uTnVsbGFibGU8U3BhdGlhbERhdGFzZXRbJ3RyYW5zY3JpcHRHZW5lQmlucyddPiwgc3RhcnRCaW46IG51bWJlciwgbXg6IG51bWJlciwgbXk6IG51bWJlciwgcmVjdDogRGF0YVJlY3QsXG4gICk6IFRyYW5zY3JpcHRKb2Ige1xuICAgIGNvbnN0IGdlbmVzID0gdmlldy50cmFuc2NyaXB0R2VuZXM7XG4gICAgY29uc3QgbGV2ZWxzID0gbWV0YS5sZXZlbHM7XG4gICAgbGV0IGZpcnN0ID0gbGV2ZWxzLmZpbmRJbmRleCgobCkgPT4gbC5iaW5TaXplID49IHN0YXJ0QmluICogMC45OTkpO1xuICAgIGlmIChmaXJzdCA8IDApIGZpcnN0ID0gbGV2ZWxzLmxlbmd0aCAtIDE7XG4gICAgY29uc3QgYnVkZ2V0ID0gTWF0aC5tYXgoMSwgdmlldy50cmFuc2NyaXB0QnVkZ2V0KTtcbiAgICBjb25zdCBoaWRkZW4gPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBjbHVzdGVycyA9IHRoaXMuc2VsZWN0aW9uQ2x1c3RlcnModmlldyk7XG4gICAgY29uc3QgY2x1c3Rlck9mID0gbmV3IE1hcDxudW1iZXIsIG51bWJlcj4oKTtcbiAgICBjbHVzdGVycy5mb3JFYWNoKChjLCBjaSkgPT4gYy5nZW5lcy5mb3JFYWNoKChnKSA9PiBjbHVzdGVyT2Yuc2V0KGdlbmVzLmluZGV4T2YoZyksIGNpKSkpO1xuICAgIGNvbnN0IGtleXNBdCA9IChtOiBudW1iZXIpID0+IHRpbGVzSW5SZWN0RnJvbShtZXRhLm9yaWdpbiwgYXJvdW5kLCBtLFxuICAgICAgbGV2ZWxzLm1hcCgobCkgPT4gKHsgdGlsZVNpemU6IGwudGlsZVNpemUgfSkpLCBudWxsLCBNQVhfQklOX1RJTEVTKTtcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2dlbmVzJyxcbiAgICAgIGtleTogYGdlbmUtYmluc3wke2dlbmVzLmpvaW4oJywnKX18JHtidWRnZXR9fCR7Zmlyc3R9fCR7SlNPTi5zdHJpbmdpZnkodmlldy50cmFuc2NyaXB0R2VuZUdyb3Vwcyl9fGBcbiAgICAgICAgKyBgJHtNYXRoLmZsb29yKHJlY3QueDAgLyAobXggfHwgMSkpfSwke01hdGguZmxvb3IocmVjdC55MCAvIChteSB8fCAxKSl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IG0gPSBmaXJzdDtcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgIGNvbnN0IHRpbGVzID0gYXdhaXQgdGhpcy5mZXRjaEFsbChrZXlzQXQobSksXG4gICAgICAgICAgICAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRHZW5lQmlucyEoay5sZXZlbCwgay5neCwgay5neSwgZ2VuZXMpKTtcbiAgICAgICAgICBjb25zdCBjbGlwcGVkID0gdGlsZXMubWFwKCh0KSA9PiBjbGlwVHJhbnNjcmlwdHModCwgYXJvdW5kKSk7XG4gICAgICAgICAgLy8gUGFzdCB0aGUgY2FwIGEgbWVyZ2Ugd291bGQgZHJvcCB3aG9sZSBnZW5lcyAodGhlIHRhaWwgb2YgZXZlcnkgdGlsZSk6IGdvIGNvYXJzZXIuXG4gICAgICAgICAgaWYgKGNsaXBwZWQucmVkdWNlKChuLCB0KSA9PiBuICsgdC5jb3VudCwgMCkgPiBNQVhfVFJBTlNDUklQVFMgJiYgbSA8IGxldmVscy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICBtKys7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXMoY2xpcHBlZCwgTUFYX1RSQU5TQ1JJUFRTKTtcbiAgICAgICAgICAvLyBNYXJrZXJzIHRoaXMgbGV2ZWwgd291bGQgZHJhdzogb25lIHBlciAodmlzaWJsZSBjbHVzdGVyLCBiaW4pLlxuICAgICAgICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICBjb25zdCBiaW4gPSBsZXZlbHNbbV0uYmluU2l6ZTtcbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoaGlkZGVuLmhhcyhnZW5lc1ttZXJnZWQuZ2VuZVtpXV0pKSBjb250aW51ZTtcbiAgICAgICAgICAgIGNvbnN0IGMgPSBjbHVzdGVyT2YuZ2V0KG1lcmdlZC5nZW5lW2ldKTtcbiAgICAgICAgICAgIGlmIChjID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgc2Vlbi5hZGQoYCR7Y318JHtNYXRoLmZsb29yKG1lcmdlZC54W2ldIC8gYmluKX18JHtNYXRoLmZsb29yKG1lcmdlZC55W2ldIC8gYmluKX1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHNlZW4uc2l6ZSA8PSBidWRnZXQgfHwgbSA+PSBsZXZlbHMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgbWVyZ2VkLCBweDogbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpLCBsYWRkZXI6IHsgYmFzZUJpbjogYmluLCBsZXZlbHM6IDEsIHN0YXJ0OiBiaW4gfSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBtKys7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBUaGUgc2VsZWN0aW9uJ3MgY2x1c3RlcnM6IGVhY2ggZ2VuZS10cmVlIGdyb3VwJ3MgdmlzaWJsZSBnZW5lcywgdGhlbiBlYWNoIHVuZ3JvdXBlZCBnZW5lLiAqL1xuICBwcml2YXRlIHNlbGVjdGlvbkNsdXN0ZXJzKHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiB7IG5hbWU6IHN0cmluZzsgZ2VuZXM6IHN0cmluZ1tdOyBzbG90OiBudW1iZXIgfVtdIHtcbiAgICBjb25zdCBoaWRkZW4gPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBzbG90cyA9IG5ldyBNYXAodmlldy50cmFuc2NyaXB0R2VuZXMubWFwKChnLCBpKSA9PiBbZywgaV0pKTtcbiAgICBjb25zdCB0YWtlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IG91dDogeyBuYW1lOiBzdHJpbmc7IGdlbmVzOiBzdHJpbmdbXTsgc2xvdDogbnVtYmVyIH1bXSA9IFtdO1xuICAgIGZvciAoY29uc3QgZyBvZiB2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSB7XG4gICAgICBjb25zdCBnZW5lcyA9IGcuZ2VuZXMuZmlsdGVyKCh4KSA9PiBzbG90cy5oYXMoeCkgJiYgIWhpZGRlbi5oYXMoeCkgJiYgIXRha2VuLmhhcyh4KSk7XG4gICAgICBnZW5lcy5mb3JFYWNoKCh4KSA9PiB0YWtlbi5hZGQoeCkpO1xuICAgICAgaWYgKGdlbmVzLmxlbmd0aCkgb3V0LnB1c2goeyBuYW1lOiBnLm5hbWUsIGdlbmVzLCBzbG90OiBzbG90cy5nZXQoZ2VuZXNbMF0pISB9KTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBnZW5lIG9mIHZpZXcudHJhbnNjcmlwdEdlbmVzKSB7XG4gICAgICBpZiAoIXRha2VuLmhhcyhnZW5lKSAmJiAhaGlkZGVuLmhhcyhnZW5lKSkgb3V0LnB1c2goeyBuYW1lOiBnZW5lLCBnZW5lczogW2dlbmVdLCBzbG90OiBzbG90cy5nZXQoZ2VuZSkhIH0pO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFBlci1nZW5lIGRlbnNpdHkgZ3JpZHMgc3VtbWVkIGZvciBgZ2VuZXNgLCBjYWNoZWQgKGEgY2x1c3RlciBpcyBhc2tlZCBmb3Igb25jZSBwZXIgYmluKS5cbiAgICogS2V5ZWQgYnkgZGF0YXNldCB0b286IHRoaXMgbWFuYWdlciBvdXRsaXZlcyBhIGRhdGFzZXQsIGFuZCBhbm90aGVyIG1heSBzaGFyZSBnZW5lIG5hbWVzLlxuICAgKi9cbiAgcHJpdmF0ZSBkZW5zaXR5Rm9yKGRhdGFzZXQ6IHN0cmluZywgZ2VuZXM6IHN0cmluZ1tdLCBiaW46IG51bWJlcik6IFByb21pc2U8U3BhdGlhbERlbnNpdHlSYXN0ZXI+IHtcbiAgICBjb25zdCBrZXkgPSBgJHtkYXRhc2V0fXwke2Jpbn18JHtnZW5lcy5qb2luKCcsJyl9YDtcbiAgICBsZXQgcCA9IHRoaXMuZGVuc2l0eUNhY2hlLmdldChrZXkpO1xuICAgIGlmICghcCkge1xuICAgICAgcCA9IHRoaXMucG9ydC5nZXREZW5zaXR5IShnZW5lcywgYmluKTtcbiAgICAgIHAuY2F0Y2goKCkgPT4gdGhpcy5kZW5zaXR5Q2FjaGUuZGVsZXRlKGtleSkpO1xuICAgICAgdGhpcy5kZW5zaXR5Q2FjaGUuc2V0KGtleSwgcCk7XG4gICAgICBpZiAodGhpcy5kZW5zaXR5Q2FjaGUuc2l6ZSA+IDI1NikgdGhpcy5kZW5zaXR5Q2FjaGUuZGVsZXRlKHRoaXMuZGVuc2l0eUNhY2hlLmtleXMoKS5uZXh0KCkudmFsdWUhKTtcbiAgICB9XG4gICAgcmV0dXJuIHA7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IGRlbnNpdHlDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPFNwYXRpYWxEZW5zaXR5UmFzdGVyPj4oKTtcblxuICAvKipcbiAgICogQSBnZW5lIHNlbGVjdGlvbiB6b29tZWQgb3V0OiBvbmUgbWFya2VyIHBlciBjbHVzdGVyIHBlciBiaW4sIGZyb20gdGhlIHBlci1nZW5lIGRlbnNpdHlcbiAgICogZ3JpZHMuIFRoZSBiaW4gc3RhcnRzIHdoZXJlIG1hcmtlcnMgYXJlIDE0IHB4IGFwYXJ0IGFuZCBkb3VibGVzIHVudGlsIHRoZSBtYXJrZXJzIGZpdCB0aGVcbiAgICogbWF4OyBlYWNoIG1hcmtlciBzaXRzIGF0IHRoZSBjb3VudC13ZWlnaHRlZCBjZW50cmUgb2YgdGhlIGZpbmVyIGdyaWQgaW5zaWRlIGl0LCBzbyBtYXJrZXJzXG4gICAqIGZvbGxvdyB0aGUgdGlzc3VlIHJhdGhlciB0aGFuIGEgbGF0dGljZS5cbiAgICovXG4gIHByaXZhdGUgY2x1c3RlckRlbnNpdHlKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIGFyb3VuZDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLCBzdGFydEJpbjogbnVtYmVyLFxuICAgIG14OiBudW1iZXIsIG15OiBudW1iZXIsIHJlY3Q6IERhdGFSZWN0LFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBncmlkID0gZGF0YXNldC5kZW5zaXR5IS5ncmlkU2l6ZVswXTtcbiAgICBjb25zdCBjbHVzdGVycyA9IHRoaXMuc2VsZWN0aW9uQ2x1c3RlcnModmlldyk7XG4gICAgbGV0IGZpcnN0ID0gZ3JpZDtcbiAgICB3aGlsZSAoZmlyc3QgPCBzdGFydEJpbiAqIDAuOTk5KSBmaXJzdCAqPSAyO1xuICAgIGNvbnN0IGJ1ZGdldCA9IE1hdGgubWF4KDEsIHZpZXcudHJhbnNjcmlwdEJ1ZGdldCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtpbmQ6ICdnZW5lcycsXG4gICAgICBrZXk6IGBjbHVzdGVyc3wke2NsdXN0ZXJzLm1hcCgoYykgPT4gYCR7Yy5uYW1lfToke2MuZ2VuZXMuam9pbignKycpfWApLmpvaW4oJzsnKX18JHtidWRnZXR9fCR7Zmlyc3R9fGBcbiAgICAgICAgKyBgJHtNYXRoLmZsb29yKHJlY3QueDAgLyAobXggfHwgMSkpfSwke01hdGguZmxvb3IocmVjdC55MCAvIChteSB8fCAxKSl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGJpbiA9IGZpcnN0O1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgLy8gVGhlIGZpbmVyIGdyaWQgZ2l2ZXMgZWFjaCBtYXJrZXIgaXRzIGNlbnRyZTsgdGhlIHNlcnZlciBiaW5zIDEsIDIsIDQgb3IgOCBjZWxscy5cbiAgICAgICAgICBjb25zdCBmaW5lID0gTWF0aC5taW4oYmluID49IGdyaWQgKiAyID8gYmluIC8gMiA6IGJpbiwgZ3JpZCAqIDgpO1xuICAgICAgICAgIGNvbnN0IHJhc3RlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChjbHVzdGVycy5tYXAoKGMpID0+IHRoaXMuZGVuc2l0eUZvcihkYXRhc2V0LmlkLCBjLmdlbmVzLCBmaW5lKSkpO1xuICAgICAgICAgIGNvbnN0IG91dCA9IGNsdXN0ZXJNYXJrZXJzKHJhc3RlcnMsIGNsdXN0ZXJzLm1hcCgoYykgPT4gYy5zbG90KSwgYmluLCBhcm91bmQpO1xuICAgICAgICAgIGlmIChvdXQudGlsZS5jb3VudCA8PSBidWRnZXQgfHwgYmluID49IGdyaWQgKiAyICoqIDEyKSB7XG4gICAgICAgICAgICBjb25zdCByZWZDb3VudCA9IHF1YW50aWxlT2Yob3V0LnRpbGUud2VpZ2h0LCAwLjk1KTtcbiAgICAgICAgICAgIGNvbnN0IGJpblB4ID0gYmluICogcHhQZXJVbml0O1xuICAgICAgICAgICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KG91dC50aWxlLmNvdW50KTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0LnRpbGUuY291bnQ7IGkrKykge1xuICAgICAgICAgICAgICBweFtpXSA9IGdyb3VwZWRNYXJrZXJQeChvdXQudGlsZS53ZWlnaHRbaV0sIHJlZkNvdW50LCBiaW5QeCwgdmlldy50cmFuc2NyaXB0U2NhbGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgbWVyZ2VkOiBvdXQudGlsZSwgcHgsIGtpbmQ6ICdnZW5lcycsXG4gICAgICAgICAgICAgIGNsdXN0ZXJlZDoge1xuICAgICAgICAgICAgICAgIGdyb3VwOiBvdXQuZ3JvdXAsIG5hbWVzOiBjbHVzdGVycy5tYXAoKGMpID0+IGMubmFtZSksIGdlbmVzOiBjbHVzdGVycy5tYXAoKGMpID0+IGMuZ2VuZXMpLCBiaW4sXG4gICAgICAgICAgICAgICAgb3JpZ2luOiByYXN0ZXJzWzBdPy5tZXRhLm9yaWdpbiA/PyBbMCwgMF0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBiaW4gKj0gMjtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV2ZXJ5IGdlbmU6IHRoZSB0cmFuc2NyaXB0cyB0aGVtc2VsdmVzIG9uY2UgdGhleSBmaXQgdGhlIGJ1ZGdldCwgZWxzZSBiaW5zIG9mIHRoZVxuICAgKiBhbGwtZ2VuZSBweXJhbWlkIHNpemVkIGJ5IGhvdyBtYW55IHRyYW5zY3JpcHRzIGVhY2ggaG9sZHMuXG4gICAqL1xuICBwcml2YXRlIGFsbEdlbmVzSm9iKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCByZWN0OiBEYXRhUmVjdCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IFRyYW5zY3JpcHRKb2IgfCBudWxsIHtcbiAgICBjb25zdCBiaW5zID0gZGF0YXNldC50cmFuc2NyaXB0QmlucztcbiAgICBjb25zdCB0aWxlcyA9IGRhdGFzZXQudHJhbnNjcmlwdFRpbGVzO1xuICAgIGNvbnN0IGJvdW5kcyA9IGJpbnM/LmJvdW5kcyA/PyB0aWxlcz8uYm91bmRzO1xuICAgIGlmICghYm91bmRzKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBwbGFuID0gYWxsR2VuZXNQbGFuKHtcbiAgICAgIHJlY3QsIGJvdW5kcywgcHhQZXJVbml0LCBidWRnZXQ6IHZpZXcudHJhbnNjcmlwdEJ1ZGdldCxcbiAgICAgIHRvdGFsOiBiaW5zPy5jb3VudCA/PyB0aWxlcz8uY291bnQgPz8gMCxcbiAgICAgIGxldmVsczogYmlucyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMgPyBiaW5zLmxldmVscyA6IFtdLFxuICAgICAgY2FuSW5kaXZpZHVhbDogISF0aWxlcyxcbiAgICB9KTtcblxuICAgIGlmIChwbGFuLmtpbmQgPT09ICdpbmRpdmlkdWFsJyAmJiB0aWxlcykge1xuICAgICAgY29uc3Qga2V5cyA9IHRpbGVzSW5SZWN0KHJlY3QsIDAsIHRpbGVzLmxldmVscywgdGlsZXMuYm91bmRzLCBNQVhfVFJBTlNDUklQVF9USUxFUyk7XG4gICAgICAvLyBFYWNoIHRpbGUgY2xpcHBlZCB0byB0aGUgdmlldywgcm91bmRlZCBvdXR3YXJkIHRvIDEwIHVuaXRzIHNvIHNtYWxsIHBhbnMgaGl0IGNhY2hlLlxuICAgICAgY29uc3QgcjEwID0gKHY6IG51bWJlciwgdXA6IGJvb2xlYW4pID0+ICh1cCA/IE1hdGguY2VpbCh2IC8gMTApIDogTWF0aC5mbG9vcih2IC8gMTApKSAqIDEwO1xuICAgICAgY29uc3Qgc2l6ZSA9IHRpbGVzLmxldmVsc1swXS50aWxlU2l6ZTtcbiAgICAgIGNvbnN0IGJveGVzID0ga2V5cy5tYXAoKGspOiBbbnVtYmVyLCBudW1iZXIsIG51bWJlciwgbnVtYmVyXSA9PiBbXG4gICAgICAgIE1hdGgubWF4KGsuZ3ggKiBzaXplLCByMTAocmVjdC54MCwgZmFsc2UpKSwgTWF0aC5tYXgoay5neSAqIHNpemUsIHIxMChyZWN0LnkwLCBmYWxzZSkpLFxuICAgICAgICBNYXRoLm1pbigoay5neCArIDEpICogc2l6ZSwgcjEwKHJlY3QueDEsIHRydWUpKSwgTWF0aC5taW4oKGsuZ3kgKyAxKSAqIHNpemUsIHIxMChyZWN0LnkxLCB0cnVlKSksXG4gICAgICBdKTtcbiAgICAgIGNvbnN0IHB4UGVyTWljcm9uID0gdGhpcy5weFBlck1pY3JvbihkYXRhc2V0LCBweFBlclVuaXQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAga2luZDogJ2luZGl2aWR1YWwnLFxuICAgICAgICBrZXk6IGBhbGx8aW5kaXZpZHVhbHwke3ZpZXcudHJhbnNjcmlwdEJ1ZGdldH18JHtib3hlcy5tYXAoKGIpID0+IGIuam9pbignLCcpKS5qb2luKCc7Jyl9YCxcbiAgICAgICAgbG9hZDogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGdvdCA9IGF3YWl0IHRoaXMuZmV0Y2hBbGwoa2V5cy5tYXAoKGssIGkpID0+ICh7IC4uLmssIGJveDogYm94ZXNbaV0gfSkpLFxuICAgICAgICAgICAgKGspID0+IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZSEoMCwgay5neCwgay5neSwgeyBnZW5lczogW0FMTF9HRU5FU10sIGJveDogay5ib3ggfSkpO1xuICAgICAgICAgIC8vIFRoZSBwbGFuIGVzdGltYXRlZCB0aGUgdmlldyBmcm9tIHRoZSBkYXRhc2V0J3MgYXZlcmFnZSBkZW5zaXR5OyBleHByZXNzaW9uIGlzXG4gICAgICAgICAgLy8gdW5ldmVuLCBzbyBhIGRlbnNlIHZpZXcgY2FuIGhvbGQgZmFyIG1vcmUuIFJhdGhlciB0aGFuIGN1dCB0aGUgZXhjZXNzIG9mZiwgc2hvd1xuICAgICAgICAgIC8vIGl0IGdyb3VwZWQg4oCUIHRoZSBiaW4gbGV2ZWwgdGhlIHBsYW5uZXIgd291bGQgcGljayBpZiBpdCBoYWQga25vd24uXG4gICAgICAgICAgY29uc3QgY2FwID0gTWF0aC5tYXgodmlldy50cmFuc2NyaXB0QnVkZ2V0ICogMS41LCAxKTtcbiAgICAgICAgICBjb25zdCBsb2FkZWQgPSBnb3QucmVkdWNlKChuLCB0KSA9PiBuICsgdC5jb3VudCwgMCk7XG4gICAgICAgICAgaWYgKGxvYWRlZCA+IGNhcCAmJiBiaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Qmlucykge1xuICAgICAgICAgICAgY29uc3QgZmFsbGJhY2sgPSBhbGxHZW5lc1BsYW4oe1xuICAgICAgICAgICAgICByZWN0LCBib3VuZHMsIHB4UGVyVW5pdCwgYnVkZ2V0OiB2aWV3LnRyYW5zY3JpcHRCdWRnZXQsIHRvdGFsOiBiaW5zLmNvdW50LFxuICAgICAgICAgICAgICBsZXZlbHM6IGJpbnMubGV2ZWxzLCBjYW5JbmRpdmlkdWFsOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGZhbGxiYWNrLmtpbmQgPT09ICdiaW5zJykge1xuICAgICAgICAgICAgICBjb25zdCBqb2IgPSB0aGlzLmJpbnNKb2IodmlldywgcmVjdCwgcHhQZXJVbml0LCBib3VuZHMsIGJpbnMsIGZhbGxiYWNrLmxldmVsKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgLi4uKGF3YWl0IGpvYi5sb2FkKCkpLCBraW5kOiBqb2Iua2luZCwgYmluOiBqb2IuYmluIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKGdvdCwgY2FwKTtcbiAgICAgICAgICBjb25zdCBweCA9IG5ldyBGbG9hdDMyQXJyYXkobWVyZ2VkLmNvdW50KTtcbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSBweFtpXSA9IHRyYW5zY3JpcHRNYXJrZXJQeCgxLCB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgcHhQZXJNaWNyb24pO1xuICAgICAgICAgIHJldHVybiB7IG1lcmdlZCwgcHggfTtcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKHBsYW4ua2luZCA9PT0gJ2JpbnMnICYmIGJpbnMgJiYgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRCaW5zKSB7XG4gICAgICByZXR1cm4gdGhpcy5iaW5zSm9iKHZpZXcsIHJlY3QsIHB4UGVyVW5pdCwgYm91bmRzLCBiaW5zLCBwbGFuLmxldmVsKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQmlucyBvZiB0aGUgYWxsLWdlbmUgcHlyYW1pZCBhdCBgbGV2ZWxgLCBzaXplZCBieSBob3cgbWFueSB0cmFuc2NyaXB0cyBlYWNoIGhvbGRzLiAqL1xuICBwcml2YXRlIGJpbnNKb2IoXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLCBib3VuZHM6IFNwYXRpYWxCb3VuZHMsXG4gICAgYmluczogTm9uTnVsbGFibGU8U3BhdGlhbERhdGFzZXRbJ3RyYW5zY3JpcHRCaW5zJ10+LCBsZXZlbDogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBsdiA9IGJpbnMubGV2ZWxzW2xldmVsXTtcbiAgICBjb25zdCBrZXlzID0gdGlsZXNJblJlY3RGcm9tKGJpbnMub3JpZ2luLCByZWN0LCBsZXZlbCxcbiAgICAgIGJpbnMubGV2ZWxzLm1hcCgobCkgPT4gKHsgdGlsZVNpemU6IGwudGlsZVNpemUgfSkpLCBib3VuZHMsIE1BWF9CSU5fVElMRVMpO1xuICAgIHJldHVybiB7XG4gICAgICBraW5kOiAnYmlucycsXG4gICAgICBiaW46IHsgc2l6ZTogbHYuYmluU2l6ZSwgb3JpZ2luOiBiaW5zLm9yaWdpbiB9LFxuICAgICAga2V5OiBgYWxsfGJpbnN8JHtsZXZlbH18JHt2aWV3LnRyYW5zY3JpcHRCdWRnZXR9fCR7a2V5cy5tYXAodGlsZUlkKX1gLFxuICAgICAgbG9hZDogYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBnb3QgPSBhd2FpdCB0aGlzLmZldGNoQWxsKGtleXMsIChrKSA9PiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMhKGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKTtcbiAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXMoZ290LCBNYXRoLm1heCh2aWV3LnRyYW5zY3JpcHRCdWRnZXQgKiAxLjUsIDEpKTtcbiAgICAgICAgY29uc3QgcmVmQ291bnQgPSBxdWFudGlsZU9mKG1lcmdlZC53ZWlnaHQsIDAuOTUpO1xuICAgICAgICBjb25zdCBiaW5QeCA9IGx2LmJpblNpemUgKiBweFBlclVuaXQ7XG4gICAgICAgIGNvbnN0IHB4ID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgcHhbaV0gPSBncm91cGVkTWFya2VyUHgobWVyZ2VkLndlaWdodFtpXSwgcmVmQ291bnQsIGJpblB4LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgbWVyZ2VkLCBweCB9O1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIFBlci1lbnRyeSBjb2xvdXJzIGJvdGggYXMgUkdCQSAocG9pbnRzKSBhbmQgYXMgY29sb3JtYXAgdmFsdWVzIChnbHlwaCBzaGFwZXMpLiAqL1xuICBwcml2YXRlIGFzeW5jIHRyYW5zY3JpcHRDb2xvcnMoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSxcbiAgICBjbHVzdGVyT2Y/OiAoaTogbnVtYmVyKSA9PiBzdHJpbmcgfCBudWxsLFxuICApOiBQcm9taXNlPFRyYW5zY3JpcHRGYWNlcz4ge1xuICAgIGxldCByZ2I6IFJnYltdO1xuICAgIGxldCBjb2RlT2Y6IChpOiBudW1iZXIpID0+IG51bWJlcjtcbiAgICBpZiAodmlldy50cmFuc2NyaXB0Q29sb3JCeSA9PT0gJ2NsdXN0ZXInICYmIGNsdXN0ZXJPZikge1xuICAgICAgLy8gQSBjbHVzdGVyIG5hbWVkIGxpa2UgYSBncm91cCBvZiB0aGUgY2VsbHMnIGdyb3VwaW5nIHRha2VzIHRoYXQgZ3JvdXAncyBjb2xvdXIsIHNvIGFcbiAgICAgIC8vIGNsdXN0ZXIncyB0cmFuc2NyaXB0cyBhbmQgaXRzIGNlbGxzIGFncmVlOyBhbnkgb3RoZXIgY2x1c3RlciB0YWtlcyBhIHBhbGV0dGUgY29sb3VyLlxuICAgICAgY29uc3QgbmFtZSA9IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgICAgY29uc3QgY29kZXMgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpLmNhdGNoKCgpID0+IG51bGwpIDogbnVsbDtcbiAgICAgIGNvbnN0IGNlbGxDb2xvciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgICBpZiAoY29kZXM/Lm1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJykge1xuICAgICAgICBjb25zdCBjb2xvcnMgPSByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMoY29kZXMubWV0YSk7XG4gICAgICAgIGNvZGVzLm1ldGEuY2F0ZWdvcmllcy5mb3JFYWNoKChjLCBrKSA9PiBjZWxsQ29sb3Iuc2V0KGMsIGNvbG9yc1trXSkpO1xuICAgICAgfVxuICAgICAgY29uc3QgY29sb3JzID0gY2x1c3RlckNvbG9yTWFwKHZpZXcudHJhbnNjcmlwdEdlbmVzLCB2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzLCBjZWxsQ29sb3IsXG4gICAgICAgIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURSk7XG4gICAgICBjb25zdCBpbmRleCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgICBjb25zdCBoZXg6IHN0cmluZ1tdID0gW107XG4gICAgICBjb25zdCBjb2RlRm9yID0gKGNsdXN0ZXI6IHN0cmluZykgPT4ge1xuICAgICAgICBsZXQgayA9IGluZGV4LmdldChjbHVzdGVyKTtcbiAgICAgICAgaWYgKGsgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGsgPSBoZXgubGVuZ3RoO1xuICAgICAgICAgIGluZGV4LnNldChjbHVzdGVyLCBrKTtcbiAgICAgICAgICBoZXgucHVzaChjb2xvcnMuZ2V0KGNsdXN0ZXIpID8/IGNlbGxDb2xvci5nZXQoY2x1c3RlcikgPz8gREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFWzBdKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaztcbiAgICAgIH07XG4gICAgICBjb25zdCBjb2RlID0gbmV3IEludDMyQXJyYXkodC5jb3VudCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgICBjb25zdCBjID0gY2x1c3Rlck9mKGkpO1xuICAgICAgICBjb2RlW2ldID0gYyA9PT0gbnVsbCA/IC0xIDogY29kZUZvcihjKTtcbiAgICAgIH1cbiAgICAgIHJnYiA9IGhleC5tYXAocGFyc2VIZXgpO1xuICAgICAgY29kZU9mID0gKGkpID0+IGNvZGVbaV07XG4gICAgfSBlbHNlIGlmICh2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ID09PSAnZ2VuZScgfHwgdmlldy50cmFuc2NyaXB0Q29sb3JCeSA9PT0gJ2NsdXN0ZXInKSB7XG4gICAgICAvLyBBbGwgZ2VuZXM6IGNvZGVzIGFyZSB0aGUgZGF0YXNldCdzIGdlbmUgaW5kaWNlcywgZm9sZGVkIG9udG8gdGhlIHBhbGV0dGUuXG4gICAgICBjb25zdCBuID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXMgPyBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEUubGVuZ3RoIDogdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoO1xuICAgICAgcmdiID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogbiB9LCAoX2csIGkpID0+IHBhcnNlSGV4KFxuICAgICAgICAoIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIHZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnNbdmlldy50cmFuc2NyaXB0R2VuZXNbaV1dKVxuICAgICAgICB8fCBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEVbaSAlIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGhdKSk7XG4gICAgICBjb2RlT2YgPSB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IChpKSA9PiB0LmdlbmVbaV0gJSBuIDogKGkpID0+IHQuZ2VuZVtpXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmFtZSA9IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgICAgY29uc3QgY29kZXMgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpIDogbnVsbDtcbiAgICAgIHJnYiA9IGNvZGVzPy5tZXRhLmtpbmQgPT09ICdjYXRlZ29yaWNhbCcgPyByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMoY29kZXMubWV0YSkubWFwKHBhcnNlSGV4KSA6IFtdO1xuICAgICAgY29kZU9mID0gKGkpID0+IHtcbiAgICAgICAgY29uc3QgbyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgICAgIGlmICghY29kZXMgfHwgbyA9PT0gTk9fT0JTRVJWQVRJT04pIHJldHVybiAtMTtcbiAgICAgICAgY29uc3QgYyA9IGNvZGVzLmNvZGVzW29dO1xuICAgICAgICByZXR1cm4gYyA9PT0gTk9fQ0FURUdPUlkgPyAtMSA6IGM7XG4gICAgICB9O1xuICAgIH1cbiAgICBjb25zdCB7IHN0b3BzLCB2YWx1ZU9mIH0gPSBkaXNjcmV0ZUNvbG9ybWFwU3RvcHMocmdiLCBNSVNTSU5HX0NPTE9SKTtcbiAgICBjb25zdCByZ2JhOiBSR0JBW10gPSBuZXcgQXJyYXkodC5jb3VudCk7XG4gICAgY29uc3QgdmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSh0LmNvdW50KTtcbiAgICBjb25zdCB0dXBsZXM6IFJHQkFbXSA9IHJnYi5tYXAoKFtyLCBnLCBiXSkgPT4gW3IgLyAyNTUsIGcgLyAyNTUsIGIgLyAyNTUsIDFdKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgY29uc3QgYyA9IGNvZGVPZihpKTtcbiAgICAgIHJnYmFbaV0gPSBjIDwgMCA/IFVOQVNTSUdORURfUkdCQSA6IHR1cGxlc1tjXTtcbiAgICAgIHZhbHVlc1tpXSA9IHZhbHVlT2YoYyk7XG4gICAgfVxuICAgIHJldHVybiB7IHJnYmEsIHZhbHVlcywgY29sb3JtYXA6IG5ldyBDb2xvcm1hcCgndHJhbnNjcmlwdC1jYXRlZ29yaWVzJywgc3RvcHMpIH07XG4gIH1cblxuICAvLyDilIDilIAgZGVuc2l0eSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIHBsYW5EZW5zaXR5KFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGlkZGVuR2VuZXMgPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXG4gICAgICA/IFtBTExfR0VORVNdXG4gICAgICA6IHZpZXcudHJhbnNjcmlwdEdlbmVzLmZpbHRlcigoZykgPT4gIWhpZGRlbkdlbmVzLmhhcyhnKSk7XG4gICAgaWYgKCFkYXRhc2V0LmRlbnNpdHkgfHwgIXRoaXMucG9ydC5nZXREZW5zaXR5IHx8IHZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdkZW5zaXR5JyB8fCAhZ2VuZXMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmRyb3AoJ2RlbnNpdHknKTtcbiAgICAgIHRoaXMuZGVuc2l0eVN0YXRzID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbHV0ID0gbHV0Rm9yKHZpZXcuZGVuc2l0eUNvbG9ybWFwID8/IElORkVSTk9fU0NBTEUpO1xuICAgIGNvbnN0IGtleSA9IFtkYXRhc2V0LmlkLCBnZW5lcy5qb2luKCcsJyksIHZpZXcuZGVuc2l0eUJpbiwgdmlldy5kZW5zaXR5T3BhY2l0eSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcuZGVuc2l0eVJhbmdlKSwgSlNPTi5zdHJpbmdpZnkodmlldy5kZW5zaXR5Q29sb3JtYXApXS5qb2luKCd8Jyk7XG4gICAgaWYgKGtleSA9PT0gdGhpcy5rZXlzLmdldCgnZGVuc2l0eScpICYmIHRoaXMubGF5ZXJzLmhhcygnZGVuc2l0eScpKSByZXR1cm47XG4gICAgY29uc3QgcmFzdGVyID0gYXdhaXQgdGhpcy50cmFjaygnVHJhbnNjcmlwdCBkZW5zaXR5JywgdGhpcy5wb3J0LmdldERlbnNpdHkoZ2VuZXMsIHZpZXcuZGVuc2l0eUJpbikpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG5cbiAgICAvLyBCaW5zIGRyYXduIGFzIHNxdWFyZXMsIGFzIFhlbml1bSBFeHBsb3JlciBkb2VzOyB0aGUgd2luZG93IGlzIGluIHRyYW5zY3JpcHRzL8K1bcKyLlxuICAgIGNvbnN0IG1ldGEgPSByYXN0ZXIubWV0YTtcbiAgICBjb25zdCBhcmVhID0gbWV0YS5ncmlkU2l6ZVswXSAqIG1ldGEuZ3JpZFNpemVbMV07XG4gICAgY29uc3QgcGVyQXJlYSA9IHJhc3Rlci52YWx1ZXMubWFwKCh2KSA9PiB2IC8gYXJlYSk7XG4gICAgY29uc3QgW2xvLCBoaV0gPSB2aWV3LmRlbnNpdHlSYW5nZSA/PyBkZW5zaXR5QXV0b1JhbmdlKHBlckFyZWEpO1xuICAgIHRoaXMuZGVuc2l0eVN0YXRzID0geyBsbywgaGksIG1heDogcGVyQXJlYS5yZWR1Y2UoKG0sIHYpID0+ICh2ID4gbSA/IHYgOiBtKSwgMCkgfTtcbiAgICBjb25zdCByZ2JhID0gY29sb3JEZW5zaXR5V2luZG93KHBlckFyZWEsIGx1dCwgdmlldy5kZW5zaXR5T3BhY2l0eSwgbG8sIGhpKTtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHN4ID0gcmVmPy5zY2FsZT8uWzBdID8/IDE7XG4gICAgY29uc3Qgc3kgPSByZWY/LnNjYWxlPy5bMV0gPz8gMTtcbiAgICBjb25zdCBsYXllcjogSW1hZ2VMYXllciA9IHRoaXMudmlld2VyIS5hZGRJbWFnZShcbiAgICAgIHsga2luZDogJ3R5cGVkJywgd2lkdGg6IG1ldGEuY29scywgaGVpZ2h0OiBtZXRhLnJvd3MsIGNoYW5uZWxzOiA0LCBkdHlwZTogJ3VpbnQ4JywgZGF0YTogcmdiYSB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiBgZGVuc2l0eSDCtyAke3ZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gJ2FsbCBnZW5lcycgOiBnZW5lcy5qb2luKCcsICcpfWAsXG4gICAgICAgIHNjYWxlOiBbbWV0YS5ncmlkU2l6ZVswXSAqIHN4LCBtZXRhLmdyaWRTaXplWzFdICogc3ldLFxuICAgICAgICB0cmFuc2xhdGU6IFtcbiAgICAgICAgICBtZXRhLm9yaWdpblswXSAqIHN4ICsgKHJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMCksXG4gICAgICAgICAgbWV0YS5vcmlnaW5bMV0gKiBzeSArIChyZWY/LnRyYW5zbGF0ZT8uWzFdID8/IDApLFxuICAgICAgICBdLFxuICAgICAgICBibGVuZGluZzogJ3RyYW5zbHVjZW50JyxcbiAgICAgICAgaW50ZXJwb2xhdGlvbjogJ25lYXJlc3QnLFxuICAgICAgfSxcbiAgICApO1xuICAgIHRoaXMua2V5cy5zZXQoJ2RlbnNpdHknLCBrZXkpO1xuICAgIHRoaXMucmVwbGFjZSgnZGVuc2l0eScsIGxheWVyKTtcbiAgICB0aGlzLmhvc3QuZGVuc2l0eUNoYW5nZWQ/Lih0aGlzLmRlbnNpdHlTdGF0cyk7XG4gIH1cblxuICBwcml2YXRlIGNvdW50c0NhY2hlOiB7IGtleTogc3RyaW5nOyBjb3VudHM6IFByb21pc2U8U3BhdGlhbFRyYW5zY3JpcHRDb3VudHM+IH0gfCBudWxsID0gbnVsbDtcblxuICAvKipcbiAgICogVHJhbnNjcmlwdHMgaW4gdmlldyBmb3IgdGhlIHZpc2libGUgZ2VuZXM6IGVhY2ggZ2VuZSdzIGRhdGFzZXQgdG90YWwgdGltZXMgdGhlIHNoYXJlXG4gICAqIG9mIHRoZSB0aXNzdWUgb24gc2NyZWVuLiBBbiBlc3RpbWF0ZSDigJQgZXhwcmVzc2lvbiBpcyBub3QgdW5pZm9ybSDigJQgd2hpY2ggaXMgYWxzbyB3aGF0XG4gICAqIFhlbml1bSBFeHBsb3JlciBzaG93czsgaXQgdGVsbHMgdGhlIHVzZXIgd2hldGhlciB0aGUgYnVkZ2V0IHdpbGwgZm9yY2UgZ3JvdXBpbmcuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBsYW5Fc3RpbWF0ZShcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgdmlld2VyOiBWaWV3ZXIsIHc6IG51bWJlciwgaDogbnVtYmVyLFxuICAgIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB0aWxlcyA9IGRhdGFzZXQudHJhbnNjcmlwdFRpbGVzO1xuICAgIGlmICghdGlsZXMgfHwgIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzIHx8IHZpZXcudHJhbnNjcmlwdE1vZGUgPT09ICdvZmYnKSB7XG4gICAgICB0aGlzLmhvc3QuZXN0aW1hdGVDaGFuZ2VkPy4obnVsbCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGhpZGRlbkdlbmVzID0gbmV3IFNldCh2aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcyk7XG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IFtdIDogdmlldy50cmFuc2NyaXB0R2VuZXMuZmlsdGVyKChnKSA9PiAhaGlkZGVuR2VuZXMuaGFzKGcpKTtcbiAgICBjb25zdCBrZXkgPSBgJHtkYXRhc2V0LmlkfXwke2dlbmVzLmpvaW4oJywnKX1gO1xuICAgIGlmICh0aGlzLmNvdW50c0NhY2hlPy5rZXkgIT09IGtleSkge1xuICAgICAgdGhpcy5jb3VudHNDYWNoZSA9IHsga2V5LCBjb3VudHM6IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzKGdlbmVzKSB9O1xuICAgIH1cbiAgICBsZXQgY291bnRzOiBTcGF0aWFsVHJhbnNjcmlwdENvdW50cztcbiAgICB0cnkge1xuICAgICAgY291bnRzID0gYXdhaXQgdGhpcy5jb3VudHNDYWNoZS5jb3VudHM7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLmNvdW50c0NhY2hlID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCBpblZpZXcgPSB2aXNpYmxlRGF0YVJlY3Qodmlld2VyLmNhbWVyYS5jZW50ZXIsIHZpZXdlci5jYW1lcmEuem9vbSwgdywgaCwgZGF0YXNldC5pbWFnZVJlZiwgMCk7XG4gICAgaWYgKCFpblZpZXcpIHJldHVybjtcbiAgICBjb25zdCBiID0gY291bnRzLmJvdW5kcztcbiAgICBjb25zdCBzaGFyZSA9IE1hdGgubWluKDEsIHZpc2libGVBcmVhKGluVmlldywgYikgLyBNYXRoLm1heCgxLCAoYlsyXSAtIGJbMF0pICogKGJbM10gLSBiWzFdKSkpO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gY291bnRzLnRvdGFsXG4gICAgICA6IGdlbmVzLnJlZHVjZSgoc3VtLCBnKSA9PiBzdW0gKyAoY291bnRzLmNvdW50c1tnXSA/PyAwKSwgMCk7XG4gICAgdGhpcy5ob3N0LmVzdGltYXRlQ2hhbmdlZD8uKHsgcG9pbnRzOiBNYXRoLnJvdW5kKHNlbGVjdGVkICogc2hhcmUpLCBtYXg6IHZpZXcudHJhbnNjcmlwdEJ1ZGdldCB9KTtcbiAgfVxuXG4gIC8qKiBUaGUgZGVuc2l0eSB3aW5kb3cgaW4gdXNlIGFuZCB0aGUgZGVuc2VzdCBiaW4sIGZvciB0aGUgcGFuZWwncyB0aHJlc2hvbGQgY29udHJvbC4gKi9cbiAgZGVuc2l0eVN0YXRzOiB7IGxvOiBudW1iZXI7IGhpOiBudW1iZXI7IG1heDogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcblxuICAvLyDilIDilIAgbGF5ZXIgYm9va2tlZXBpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIEZldGNoIGV2ZXJ5IHRpbGUsIGRyYXdpbmcgd2hhdCBhcnJpdmVkLiBBIGZhaWx1cmUgZG9lcyBub3QgZmFpbCB0aGUgdmlldywgYnV0IGl0IG1hcmtzIHRoZVxuICAgKiBwbGFuIGluY29tcGxldGU6IHRoZSBjYWxsZXIgbXVzdCBub3QgY2FjaGUgaXQgYXMgZG9uZSwgYW5kIGBwbGFuKClgIHJldHJpZXMgaXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoQWxsPEssIFQ+KGtleXM6IEtbXSwgbG9hZDogKGs6IEspID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoa2V5cy5tYXAobG9hZCkpO1xuICAgIGNvbnN0IG91dDogVFtdID0gW107XG4gICAgZm9yIChjb25zdCBzIG9mIHNldHRsZWQpIHtcbiAgICAgIGlmIChzLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcpIG91dC5wdXNoKHMudmFsdWUpO1xuICAgICAgZWxzZSBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHNwYXRpYWwgdGlsZSBmYWlsZWQnLCBzLnJlYXNvbik7XG4gICAgfVxuICAgIGlmIChvdXQubGVuZ3RoIDwga2V5cy5sZW5ndGgpIHRoaXMucGxhbkluY29tcGxldGUgPSB0cnVlO1xuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGEgc2hhcGVzIGxheWVyIGluIHBsYWNlIGZvciBgZ3JvdXBgOiBhIGdlb21ldHJ5IGNoYW5nZSBidWlsZHMgYSBuZXcgbGF5ZXIsIGFcbiAgICogY29sb3VyLW9ubHkgY2hhbmdlIG11dGF0ZXMgdmFsdWVzL2NvbG9ybWFwIG9uIHRoZSBleGlzdGluZyBvbmUuXG4gICAqL1xuICBwcml2YXRlIHVwc2VydFNoYXBlcyhcbiAgICBncm91cDogR3JvdXAsIHdhbnRlZDogYm9vbGVhbiwgZ2VvbWV0cnlDaGFuZ2VkOiBib29sZWFuLCByaW5nczogU3BhdGlhbFBvbHlnb25zLFxuICAgIG9wdHM6IFBhcmFtZXRlcnM8Vmlld2VyWydhZGRTaGFwZXMnXT5bMl0gJiBvYmplY3QsXG4gICk6IHZvaWQge1xuICAgIGlmICghd2FudGVkKSB7XG4gICAgICB0aGlzLmRyb3AoZ3JvdXApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMubGF5ZXJzLmdldChncm91cCkgYXMgU2hhcGVzTGF5ZXIgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGV4aXN0aW5nICYmICFnZW9tZXRyeUNoYW5nZWQgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhleGlzdGluZykpIHtcbiAgICAgIC8vIEZsYXQgY29sb3VyIGhhcyBubyB2YWx1ZXM7IGNsZWFyaW5nIHRoZW0gaXMgd2hhdCBzd2l0Y2hlcyB0aGUgbGF5ZXIgdG8gYGNvbG9yYC5cbiAgICAgIGV4aXN0aW5nLnZhbHVlcyA9IG9wdHMudmFsdWVzID8/IG51bGw7XG4gICAgICBpZiAob3B0cy5jb2xvcm1hcCkgZXhpc3RpbmcuY29sb3JtYXAgPSBvcHRzLmNvbG9ybWFwO1xuICAgICAgaWYgKG9wdHMuY29udHJhc3RMaW1pdHMpIGV4aXN0aW5nLmNvbnRyYXN0TGltaXRzID0gb3B0cy5jb250cmFzdExpbWl0cztcbiAgICAgIGlmIChvcHRzLmNvbG9yKSBleGlzdGluZy5jb2xvciA9IG9wdHMuY29sb3I7XG4gICAgICBpZiAob3B0cy5vcGFjaXR5ICE9PSB1bmRlZmluZWQpIGV4aXN0aW5nLm9wYWNpdHkgPSBvcHRzLm9wYWNpdHk7XG4gICAgICB0aGlzLnZpZXdlciEucmVxdWVzdFJlbmRlcigpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9IHRoaXMudmlld2VyIS5hZGRTaGFwZXMocmluZ3MuY29vcmRzLCByaW5ncy5vZmZzZXRzLCBvcHRzKTtcbiAgICB0aGlzLnJlcGxhY2UoZ3JvdXAsIGxheWVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnN0YWxsIGBsYXllcmAgYXMgYGdyb3VwYCdzIGxheWVyIGFuZCByZXN0b3JlIHRoZSBvcmRlciBvZiB0aGUgZ3JvdXBzIGFib3ZlIGl0LlxuICAgKiBUaGUgbGF5ZXIgd2FzIGp1c3QgYWRkZWQgYnkgdGhlIGNhbGxlciAoc28gaXQgaXMgb24gdG9wKTsgZ3JvdXBzIHRoYXQgYmVsb25nIGFib3ZlXG4gICAqIGl0IGFyZSByZW1vdmVkIGFuZCByZS1hZGRlZC5cbiAgICovXG4gIHByaXZhdGUgcmVwbGFjZShncm91cDogR3JvdXAsIGxheWVyOiBMYXllcik6IHZvaWQge1xuICAgIGNvbnN0IHYgPSB0aGlzLnZpZXdlciE7XG4gICAgY29uc3Qgb2xkID0gdGhpcy5sYXllcnMuZ2V0KGdyb3VwKTtcbiAgICBpZiAob2xkICYmIG9sZCAhPT0gbGF5ZXIgJiYgdi5sYXllcnMuaXRlbXMuaW5jbHVkZXMob2xkKSkgdi5sYXllcnMucmVtb3ZlKG9sZCk7XG4gICAgdGhpcy5sYXllcnMuc2V0KGdyb3VwLCBsYXllcik7XG4gICAgZm9yIChjb25zdCBnIG9mIE9SREVSLnNsaWNlKE9SREVSLmluZGV4T2YoZ3JvdXApICsgMSkpIHtcbiAgICAgIGNvbnN0IGFib3ZlID0gdGhpcy5sYXllcnMuZ2V0KGcpO1xuICAgICAgaWYgKCFhYm92ZSB8fCAhdi5sYXllcnMuaXRlbXMuaW5jbHVkZXMoYWJvdmUpKSBjb250aW51ZTtcbiAgICAgIHYubGF5ZXJzLnJlbW92ZShhYm92ZSk7XG4gICAgICB2LmxheWVycy5hZGQoYWJvdmUpO1xuICAgIH1cbiAgICB2LnJlcXVlc3RSZW5kZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgZHJvcChncm91cDogR3JvdXApOiB2b2lkIHtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXJzLmdldChncm91cCk7XG4gICAgaWYgKGxheWVyICYmIHRoaXMudmlld2VyPy5sYXllcnMuaXRlbXMuaW5jbHVkZXMobGF5ZXIpKSB0aGlzLnZpZXdlci5sYXllcnMucmVtb3ZlKGxheWVyKTtcbiAgICB0aGlzLmxheWVycy5kZWxldGUoZ3JvdXApO1xuICAgIHRoaXMua2V5cy5kZWxldGUoZ3JvdXApO1xuICB9XG5cbiAgcHJpdmF0ZSBkcm9wQ2VsbHMoKTogdm9pZCB7XG4gICAgdGhpcy5kcm9wKCdjZWxsRmlsbCcpO1xuICAgIHRoaXMuZHJvcCgnY2VsbE91dGxpbmUnKTtcbiAgICB0aGlzLmRyb3AoJ251Y2xldXNPdXRsaW5lJyk7XG4gICAgdGhpcy5jdXJyZW50TnVjbGVpID0gbnVsbDtcbiAgICB0aGlzLmNlbGxHZW9tZXRyeUtleSA9IG51bGw7XG4gICAgdGhpcy5jZWxsU3R5bGVLZXkgPSBudWxsO1xuICAgIHRoaXMuY3VycmVudFJpbmdzID0gbnVsbDtcbiAgICB0aGlzLnNldFBvbHlnb25zU2hvd24oZmFsc2UpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRQb2x5Z29uc1Nob3duKHNob3duOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKHNob3duID09PSB0aGlzLnBvbHlnb25zU2hvd24pIHJldHVybjtcbiAgICB0aGlzLnBvbHlnb25zU2hvd24gPSBzaG93bjtcbiAgICB0aGlzLmhvc3QucG9seWdvbnNTaG93bkNoYW5nZWQoc2hvd24pO1xuICB9XG59XG5cbi8qKiBXaGF0IHRoZSB0cmFuc2NyaXB0IGxheWVyIGN1cnJlbnRseSBzaG93cyDigJQgd2hhdCBob3ZlcmluZyBuZWVkcyB0byBuYW1lIGEgbWFya2VyLiAqL1xuaW50ZXJmYWNlIERyYXduVHJhbnNjcmlwdHMge1xuICBraW5kOiBUcmFuc2NyaXB0Sm9iWydraW5kJ107XG4gIGJpbj86IFRyYW5zY3JpcHRKb2JbJ2JpbiddO1xuICBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTtcbiAgLyoqIE1hcmtlciByYWRpdXMgcGVyIGVudHJ5LCBpbiBvYnNlcnZhdGlvbiB1bml0cy4gKi9cbiAgcmFkaXVzOiBGbG9hdDMyQXJyYXk7XG4gIGdlbmVzOiBzdHJpbmdbXTtcbiAgcmVmOiBTcGF0aWFsSW1hZ2VSZWYgfCBudWxsO1xuICAvKiogRm9yIGEgZ3JvdXBlZCBnZW5lIHNlbGVjdGlvbjogZWFjaCBlbnRyeSdzIGdyb3VwLCBhbmQgdGhlIGdyb3VwcycgbmFtZXMuICovXG4gIGVudHJ5R3JvdXA/OiBJbnQzMkFycmF5O1xuICBncm91cE5hbWVzPzogc3RyaW5nW107XG4gIC8qKiBFYWNoIGdyb3VwJ3MgZ2VuZXMsIHdoZW4gdGhlIG1hcmtlcnMgY2FtZSBmcm9tIHRoZSBkZW5zaXR5IGdyaWRzIChmb3IgdGhlIGhvdmVyKS4gKi9cbiAgZ3JvdXBHZW5lcz86IHN0cmluZ1tdW107XG4gIC8qKiBMYXppbHkgYnVpbHQgc3BhdGlhbCBpbmRleDogYnVja2V0IOKGkiBlbnRyeSBpbmRpY2VzLiAqL1xuICBncmlkOiB7IHNpemU6IG51bWJlcjsgYnVja2V0czogTWFwPG51bWJlciwgbnVtYmVyW10+IH0gfCBudWxsO1xufVxuXG4vKiogSW5kZXggb2YgdGhlIGVudHJ5IHVuZGVyIGAoeCwgeSlgIOKAlCB3aXRoaW4gaXRzIG93biByYWRpdXMgb3IgYHRvbGVyYW5jZWAg4oCUIG9yIC0xLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBpY2tOZWFyZXN0KFxuICBkOiBQaWNrPERyYXduVHJhbnNjcmlwdHMsICdtZXJnZWQnIHwgJ3JhZGl1cycgfCAnZ3JpZCc+LCB4OiBudW1iZXIsIHk6IG51bWJlciwgdG9sZXJhbmNlOiBudW1iZXIsXG4pOiBudW1iZXIge1xuICBjb25zdCB0ID0gZC5tZXJnZWQ7XG4gIGlmICghZC5ncmlkKSB7XG4gICAgbGV0IG1heFIgPSAwO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSBpZiAoZC5yYWRpdXNbaV0gPiBtYXhSKSBtYXhSID0gZC5yYWRpdXNbaV07XG4gICAgY29uc3Qgc2l6ZSA9IE1hdGgubWF4KG1heFIgKiAyLCB0b2xlcmFuY2UgKiAyLCAxZS02KTtcbiAgICBjb25zdCBidWNrZXRzID0gbmV3IE1hcDxudW1iZXIsIG51bWJlcltdPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCBrID0gYnVja2V0S2V5KE1hdGguZmxvb3IodC54W2ldIC8gc2l6ZSksIE1hdGguZmxvb3IodC55W2ldIC8gc2l6ZSkpO1xuICAgICAgbGV0IGIgPSBidWNrZXRzLmdldChrKTtcbiAgICAgIGlmICghYikgYnVja2V0cy5zZXQoaywgKGIgPSBbXSkpO1xuICAgICAgYi5wdXNoKGkpO1xuICAgIH1cbiAgICBkLmdyaWQgPSB7IHNpemUsIGJ1Y2tldHMgfTtcbiAgfVxuICBjb25zdCB7IHNpemUsIGJ1Y2tldHMgfSA9IGQuZ3JpZDtcbiAgY29uc3QgZ3ggPSBNYXRoLmZsb29yKHggLyBzaXplKTtcbiAgY29uc3QgZ3kgPSBNYXRoLmZsb29yKHkgLyBzaXplKTtcbiAgbGV0IGJlc3QgPSAtMTtcbiAgbGV0IGJlc3REID0gSW5maW5pdHk7XG4gIGZvciAobGV0IGR5ID0gLTE7IGR5IDw9IDE7IGR5KyspIHtcbiAgICBmb3IgKGxldCBkeCA9IC0xOyBkeCA8PSAxOyBkeCsrKSB7XG4gICAgICBmb3IgKGNvbnN0IGkgb2YgYnVja2V0cy5nZXQoYnVja2V0S2V5KGd4ICsgZHgsIGd5ICsgZHkpKSA/PyBbXSkge1xuICAgICAgICBjb25zdCBkaXN0ID0gTWF0aC5oeXBvdCh0LnhbaV0gLSB4LCB0LnlbaV0gLSB5KTtcbiAgICAgICAgaWYgKGRpc3QgPD0gTWF0aC5tYXgoZC5yYWRpdXNbaV0sIHRvbGVyYW5jZSkgJiYgZGlzdCA8IGJlc3REKSB7XG4gICAgICAgICAgYmVzdEQgPSBkaXN0O1xuICAgICAgICAgIGJlc3QgPSBpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBiZXN0O1xufVxuXG5mdW5jdGlvbiBidWNrZXRLZXkoZ3g6IG51bWJlciwgZ3k6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiAoZ3ggKyAzMjc2OCkgKiA2NTUzNiArIChneSArIDMyNzY4KTtcbn1cblxuLyoqIFJpbmdzIHdob3NlIG93bmluZyBjZWxsIGlzIGluIGEgc3dpdGNoZWQtb2ZmIGdyb3VwIHJlbW92ZWQuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyUmluZ3MoXG4gIHJpbmdzOiBTcGF0aWFsUG9seWdvblRpbGUsIGhpZGRlbjogeyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbCxcbik6IFNwYXRpYWxQb2x5Z29uVGlsZSB7XG4gIGlmICghaGlkZGVuKSByZXR1cm4gcmluZ3M7XG4gIGNvbnN0IGtlZXA6IG51bWJlcltdID0gW107XG4gIGxldCB2ZXJ0aWNlcyA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmluZ3MuY291bnQ7IGkrKykge1xuICAgIGNvbnN0IGNvZGUgPSBoaWRkZW4uY29kZXNbcmluZ3Mub2JzZXJ2YXRpb25baV1dO1xuICAgIGlmIChjb2RlICE9PSBOT19DQVRFR09SWSAmJiBoaWRkZW4uaGlkZGVuW2NvZGVdKSBjb250aW51ZTtcbiAgICBrZWVwLnB1c2goaSk7XG4gICAgdmVydGljZXMgKz0gcmluZ3Mub2Zmc2V0c1tpICsgMV0gLSByaW5ncy5vZmZzZXRzW2ldO1xuICB9XG4gIGlmIChrZWVwLmxlbmd0aCA9PT0gcmluZ3MuY291bnQpIHJldHVybiByaW5ncztcbiAgY29uc3Qgb2JzZXJ2YXRpb24gPSBuZXcgVWludDMyQXJyYXkoa2VlcC5sZW5ndGgpO1xuICBjb25zdCBvZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KGtlZXAubGVuZ3RoICsgMSk7XG4gIGNvbnN0IGNvb3JkcyA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGljZXMgKiAyKTtcbiAgbGV0IHYgPSAwO1xuICBrZWVwLmZvckVhY2goKGksIHIpID0+IHtcbiAgICBvYnNlcnZhdGlvbltyXSA9IHJpbmdzLm9ic2VydmF0aW9uW2ldO1xuICAgIG9mZnNldHNbcl0gPSB2O1xuICAgIGNvbnN0IGEgPSByaW5ncy5vZmZzZXRzW2ldICogMjtcbiAgICBjb25zdCBiID0gcmluZ3Mub2Zmc2V0c1tpICsgMV0gKiAyO1xuICAgIGNvb3Jkcy5zZXQocmluZ3MuY29vcmRzLnN1YmFycmF5KGEsIGIpLCB2ICogMik7XG4gICAgdiArPSAoYiAtIGEpIC8gMjtcbiAgfSk7XG4gIG9mZnNldHNba2VlcC5sZW5ndGhdID0gdjtcbiAgcmV0dXJuIHsgY291bnQ6IGtlZXAubGVuZ3RoLCBvYnNlcnZhdGlvbiwgb2Zmc2V0cywgY29vcmRzIH07XG59XG5cbi8qKiBTbG90cyAoaW5kaWNlcyBpbnRvIHRoZSBzZWxlY3RlZCBnZW5lcykgc3dpdGNoZWQgb2ZmIHdpdGggdGhlaXIgZXllIHRvZ2dsZS4gKi9cbmZ1bmN0aW9uIGhpZGRlbkdlbmVTbG90cyh2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogVWludDhBcnJheSB8IG51bGwge1xuICBpZiAoIXZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IG9mZiA9IG5ldyBTZXQodmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMpO1xuICByZXR1cm4gVWludDhBcnJheS5mcm9tKHZpZXcudHJhbnNjcmlwdEdlbmVzLCAoZykgPT4gKG9mZi5oYXMoZykgPyAxIDogMCkpO1xufVxuXG4vKiogRW50cmllcyBpbiBhIGhpZGRlbiBncm91cCdzIGNlbGwsIG9yIG9mIGEgaGlkZGVuIGdlbmUsIHJlbW92ZWQgKHdpdGggdGhlaXIgc2l6ZXMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlclRyYW5zY3JpcHRzKFxuICB0OiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsIHB4OiBGbG9hdDMyQXJyYXksXG4gIGhpZGRlbjogeyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbCwgaGlkZGVuR2VuZXM6IFVpbnQ4QXJyYXkgfCBudWxsLFxuKTogeyBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTsgcHg6IEZsb2F0MzJBcnJheSB9IHtcbiAgaWYgKCFoaWRkZW4gJiYgIWhpZGRlbkdlbmVzKSByZXR1cm4geyBtZXJnZWQ6IHQsIHB4IH07XG4gIGNvbnN0IGtlZXA6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgaWYgKGhpZGRlbkdlbmVzICYmIGhpZGRlbkdlbmVzW3QuZ2VuZVtpXV0pIGNvbnRpbnVlO1xuICAgIGNvbnN0IG8gPSB0Lm9ic2VydmF0aW9uW2ldO1xuICAgIGlmIChoaWRkZW4gJiYgbyAhPT0gTk9fT0JTRVJWQVRJT04pIHtcbiAgICAgIGNvbnN0IGNvZGUgPSBoaWRkZW4uY29kZXNbb107XG4gICAgICBpZiAoY29kZSAhPT0gTk9fQ0FURUdPUlkgJiYgaGlkZGVuLmhpZGRlbltjb2RlXSkgY29udGludWU7XG4gICAgfVxuICAgIGtlZXAucHVzaChpKTtcbiAgfVxuICBjb25zdCBwaWNrID0gPFQgZXh0ZW5kcyBGbG9hdDMyQXJyYXkgfCBVaW50MzJBcnJheSB8IFVpbnQxNkFycmF5PihhOiBUKTogVCA9PiB7XG4gICAgY29uc3Qgb3V0ID0gbmV3IChhLmNvbnN0cnVjdG9yIGFzIG5ldyAobjogbnVtYmVyKSA9PiBUKShrZWVwLmxlbmd0aCk7XG4gICAga2VlcC5mb3JFYWNoKChpLCBrKSA9PiB7IG91dFtrXSA9IGFbaV07IH0pO1xuICAgIHJldHVybiBvdXQ7XG4gIH07XG4gIHJldHVybiB7XG4gICAgbWVyZ2VkOiB7XG4gICAgICBjb3VudDoga2VlcC5sZW5ndGgsIGFnZ3JlZ2F0ZWQ6IHQuYWdncmVnYXRlZCwgeDogcGljayh0LngpLCB5OiBwaWNrKHQueSksIHo6IHBpY2sodC56KSxcbiAgICAgIHdlaWdodDogcGljayh0LndlaWdodCksIG9ic2VydmF0aW9uOiBwaWNrKHQub2JzZXJ2YXRpb24pLCBnZW5lOiBwaWNrKHQuZ2VuZSksXG4gICAgfSxcbiAgICBweDogcGljayhweCksXG4gIH07XG59XG5cbmZ1bmN0aW9uIG1lZGlhbih2OiBGbG9hdDMyQXJyYXkpOiBudW1iZXIge1xuICBpZiAoIXYubGVuZ3RoKSByZXR1cm4gMDtcbiAgY29uc3Qgc3RlcCA9IE1hdGgubWF4KDEsIE1hdGguZmxvb3Iodi5sZW5ndGggLyAxMDI0KSk7XG4gIGNvbnN0IHNhbXBsZTogbnVtYmVyW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB2Lmxlbmd0aDsgaSArPSBzdGVwKSBzYW1wbGUucHVzaCh2W2ldKTtcbiAgc2FtcGxlLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgcmV0dXJuIHNhbXBsZVtzYW1wbGUubGVuZ3RoID4+IDFdO1xufVxuXG4vKiogQ29uY2F0ZW5hdGUgdGlsZXMnIHJpbmdzIGludG8gb25lIHNldCwgZHJvcHBpbmcgcmluZ3MgYWxyZWFkeSBzZWVuIChhIGNlbGwgc3RyYWRkbGluZ1xuICogIHR3byB0aWxlcyBtYXkgYmUgbGlzdGVkIGJ5IGJvdGgpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlUG9seWdvblRpbGVzKHRpbGVzOiBTcGF0aWFsUG9seWdvblRpbGVbXSk6IFNwYXRpYWxQb2x5Z29uVGlsZSB7XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgbGV0IHJpbmdzID0gMDtcbiAgbGV0IHZlcnRpY2VzID0gMDtcbiAgZm9yIChjb25zdCB0IG9mIHRpbGVzKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0LmNvdW50OyBpKyspIHtcbiAgICAgIGlmIChzZWVuLmhhcyh0Lm9ic2VydmF0aW9uW2ldKSkgY29udGludWU7XG4gICAgICBzZWVuLmFkZCh0Lm9ic2VydmF0aW9uW2ldKTtcbiAgICAgIHJpbmdzKys7XG4gICAgICB2ZXJ0aWNlcyArPSB0Lm9mZnNldHNbaSArIDFdIC0gdC5vZmZzZXRzW2ldO1xuICAgIH1cbiAgfVxuICBzZWVuLmNsZWFyKCk7XG4gIGNvbnN0IG9ic2VydmF0aW9uID0gbmV3IFVpbnQzMkFycmF5KHJpbmdzKTtcbiAgY29uc3Qgb2Zmc2V0cyA9IG5ldyBVaW50MzJBcnJheShyaW5ncyArIDEpO1xuICBjb25zdCBjb29yZHMgPSBuZXcgRmxvYXQzMkFycmF5KHZlcnRpY2VzICogMik7XG4gIGxldCByID0gMDtcbiAgbGV0IHYgPSAwO1xuICBmb3IgKGNvbnN0IHQgb2YgdGlsZXMpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgY29uc3QgbyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgICBpZiAoc2Vlbi5oYXMobykpIGNvbnRpbnVlO1xuICAgICAgc2Vlbi5hZGQobyk7XG4gICAgICBvYnNlcnZhdGlvbltyXSA9IG87XG4gICAgICBvZmZzZXRzW3JdID0gdjtcbiAgICAgIGNvbnN0IGEgPSB0Lm9mZnNldHNbaV0gKiAyO1xuICAgICAgY29uc3QgYiA9IHQub2Zmc2V0c1tpICsgMV0gKiAyO1xuICAgICAgY29vcmRzLnNldCh0LmNvb3Jkcy5zdWJhcnJheShhLCBiKSwgdiAqIDIpO1xuICAgICAgdiArPSAoYiAtIGEpIC8gMjtcbiAgICAgIHIrKztcbiAgICB9XG4gIH1cbiAgb2Zmc2V0c1tyaW5nc10gPSB2O1xuICByZXR1cm4geyBjb3VudDogcmluZ3MsIG9ic2VydmF0aW9uLCBvZmZzZXRzLCBjb29yZHMgfTtcbn1cblxuLyoqIENvbmNhdGVuYXRlIHRyYW5zY3JpcHQgdGlsZXMsIHN0b3BwaW5nIGF0IGBsaW1pdGAgZW50cmllcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVRyYW5zY3JpcHRUaWxlcyh0aWxlczogU3BhdGlhbFRyYW5zY3JpcHRUaWxlW10sIGxpbWl0ID0gSW5maW5pdHkpOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUge1xuICBsZXQgbiA9IDA7XG4gIGZvciAoY29uc3QgdCBvZiB0aWxlcykgbiArPSB0LmNvdW50O1xuICBuID0gTWF0aC5taW4obiwgbGltaXQpO1xuICBjb25zdCBvdXQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSA9IHtcbiAgICBjb3VudDogbixcbiAgICBhZ2dyZWdhdGVkOiB0aWxlcy5zb21lKCh0KSA9PiB0LmFnZ3JlZ2F0ZWQpLFxuICAgIHg6IG5ldyBGbG9hdDMyQXJyYXkobiksIHk6IG5ldyBGbG9hdDMyQXJyYXkobiksIHo6IG5ldyBGbG9hdDMyQXJyYXkobiksXG4gICAgd2VpZ2h0OiBuZXcgVWludDMyQXJyYXkobiksIG9ic2VydmF0aW9uOiBuZXcgVWludDMyQXJyYXkobiksIGdlbmU6IG5ldyBVaW50MTZBcnJheShuKSxcbiAgfTtcbiAgbGV0IG8gPSAwO1xuICBmb3IgKGNvbnN0IHQgb2YgdGlsZXMpIHtcbiAgICBjb25zdCBrID0gTWF0aC5taW4odC5jb3VudCwgbiAtIG8pO1xuICAgIGlmIChrIDw9IDApIGJyZWFrO1xuICAgIGZvciAoY29uc3QgZiBvZiBbJ3gnLCAneScsICd6JywgJ3dlaWdodCcsICdvYnNlcnZhdGlvbicsICdnZW5lJ10gYXMgY29uc3QpIHtcbiAgICAgIChvdXRbZl0gYXMgRmxvYXQzMkFycmF5KS5zZXQoKHRbZl0gYXMgRmxvYXQzMkFycmF5KS5zdWJhcnJheSgwLCBrKSwgbyk7XG4gICAgfVxuICAgIG8gKz0gaztcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIE9uZSBtYXJrZXIgcGVyIChjbHVzdGVyLCBgYmluYCBzcXVhcmUpIGZyb20gcGVyLWNsdXN0ZXIgZGVuc2l0eSBncmlkczogdGhlIGNvdW50cyBvZiB0aGUgZ3JpZFxuICogY2VsbHMgaW5zaWRlIGBhcmVhYCBzdW1tZWQgcGVyIHNxdWFyZSwgYXQgdGhlaXIgY291bnQtd2VpZ2h0ZWQgY2VudHJlLiBgc2xvdHNbY11gIGlzIHRoZSBnZW5lXG4gKiBzbG90IHdob3NlIGljb24gY2x1c3RlciBjJ3MgbWFya2VycyB0YWtlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2x1c3Rlck1hcmtlcnMoXG4gIHJhc3RlcnM6IFNwYXRpYWxEZW5zaXR5UmFzdGVyW10sIHNsb3RzOiBudW1iZXJbXSwgYmluOiBudW1iZXIsIGFyZWE6IERhdGFSZWN0LFxuKTogeyB0aWxlOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGU7IGdyb3VwOiBJbnQzMkFycmF5IH0ge1xuICBjb25zdCB4OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCB5OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCB3OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCBnZW5lOiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCBncm91cDogbnVtYmVyW10gPSBbXTtcbiAgcmFzdGVycy5mb3JFYWNoKChyLCBjKSA9PiB7XG4gICAgY29uc3QgW2N3LCBjaF0gPSByLm1ldGEuZ3JpZFNpemU7XG4gICAgY29uc3QgW294LCBveV0gPSByLm1ldGEub3JpZ2luO1xuICAgIGNvbnN0IHsgcm93cywgY29scyB9ID0gci5tZXRhO1xuICAgIGNvbnN0IGMwID0gTWF0aC5tYXgoMCwgTWF0aC5mbG9vcigoYXJlYS54MCAtIG94KSAvIGN3KSk7XG4gICAgY29uc3QgYzEgPSBNYXRoLm1pbihjb2xzIC0gMSwgTWF0aC5mbG9vcigoYXJlYS54MSAtIG94KSAvIGN3KSk7XG4gICAgY29uc3QgcjAgPSBNYXRoLm1heCgwLCBNYXRoLmZsb29yKChhcmVhLnkwIC0gb3kpIC8gY2gpKTtcbiAgICBjb25zdCByMSA9IE1hdGgubWluKHJvd3MgLSAxLCBNYXRoLmZsb29yKChhcmVhLnkxIC0gb3kpIC8gY2gpKTtcbiAgICBjb25zdCBzcXVhcmVzID0gbmV3IE1hcDxudW1iZXIsIHsgbjogbnVtYmVyOyBzeDogbnVtYmVyOyBzeTogbnVtYmVyIH0+KCk7XG4gICAgZm9yIChsZXQgcm93ID0gcjA7IHJvdyA8PSByMTsgcm93KyspIHtcbiAgICAgIGZvciAobGV0IGNvbCA9IGMwOyBjb2wgPD0gYzE7IGNvbCsrKSB7XG4gICAgICAgIGNvbnN0IHYgPSByLnZhbHVlc1tyb3cgKiBjb2xzICsgY29sXTtcbiAgICAgICAgaWYgKCEodiA+IDApKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgY3ggPSBveCArIChjb2wgKyAwLjUpICogY3c7XG4gICAgICAgIGNvbnN0IGN5ID0gb3kgKyAocm93ICsgMC41KSAqIGNoO1xuICAgICAgICBjb25zdCBrZXkgPSBNYXRoLmZsb29yKChjeSAtIG95KSAvIGJpbikgKiAxZTYgKyBNYXRoLmZsb29yKChjeCAtIG94KSAvIGJpbik7XG4gICAgICAgIGNvbnN0IHMgPSBzcXVhcmVzLmdldChrZXkpID8/IHsgbjogMCwgc3g6IDAsIHN5OiAwIH07XG4gICAgICAgIHMubiArPSB2O1xuICAgICAgICBzLnN4ICs9IHYgKiBjeDtcbiAgICAgICAgcy5zeSArPSB2ICogY3k7XG4gICAgICAgIHNxdWFyZXMuc2V0KGtleSwgcyk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoY29uc3QgcyBvZiBzcXVhcmVzLnZhbHVlcygpKSB7XG4gICAgICB4LnB1c2gocy5zeCAvIHMubik7XG4gICAgICB5LnB1c2gocy5zeSAvIHMubik7XG4gICAgICB3LnB1c2goTWF0aC5yb3VuZChzLm4pKTtcbiAgICAgIGdlbmUucHVzaChzbG90c1tjXSk7XG4gICAgICBncm91cC5wdXNoKGMpO1xuICAgIH1cbiAgfSk7XG4gIGNvbnN0IG4gPSB3Lmxlbmd0aDtcbiAgcmV0dXJuIHtcbiAgICB0aWxlOiB7XG4gICAgICBjb3VudDogbiwgYWdncmVnYXRlZDogdHJ1ZSxcbiAgICAgIHg6IEZsb2F0MzJBcnJheS5mcm9tKHgpLCB5OiBGbG9hdDMyQXJyYXkuZnJvbSh5KSwgejogbmV3IEZsb2F0MzJBcnJheShuKSxcbiAgICAgIHdlaWdodDogVWludDMyQXJyYXkuZnJvbSh3KSwgb2JzZXJ2YXRpb246IG5ldyBVaW50MzJBcnJheShuKS5maWxsKE5PX09CU0VSVkFUSU9OKSxcbiAgICAgIGdlbmU6IFVpbnQxNkFycmF5LmZyb20oZ2VuZSksXG4gICAgfSxcbiAgICBncm91cDogSW50MzJBcnJheS5mcm9tKGdyb3VwKSxcbiAgfTtcbn1cbiJdfQ==
|