@jax-data-science/sci-image-visualizer 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/contracts/display-types.mjs +28 -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-navigator.mjs +195 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +10 -2
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +1098 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +6 -3
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +185 -8
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +120 -2
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +76 -1
- package/esm2022/lib/routing-visualizer.service.mjs +10 -1
- package/esm2022/lib/spatial/spatial-tiles.mjs +506 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +659 -19
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +2909 -62
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/lib/contracts/display-types.d.ts +94 -1
- package/lib/contracts/ports/spatial-data.port.d.ts +59 -1
- package/lib/contracts/spatial-dataset.contract.d.ts +167 -0
- package/lib/contracts/visualizer.contract.d.ts +22 -1
- package/lib/implementations/napari-js/napari-navigator.d.ts +72 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +3 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +240 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +42 -2
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +26 -2
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -1
- package/lib/spatial/spatial-tiles.d.ts +222 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +234 -3
- package/package.json +1 -1
|
@@ -0,0 +1,1098 @@
|
|
|
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, } from '../../spatial/spatial-tiles';
|
|
6
|
+
const ORDER = [
|
|
7
|
+
'cellFill', 'cellOutline', 'nucleusOutline', 'density', 'transcripts', 'transcriptOutline',
|
|
8
|
+
];
|
|
9
|
+
/** Transcripts drawn at once. Past this a screen is solid colour anyway; the level
|
|
10
|
+
* policy keeps a normal view far below it. */
|
|
11
|
+
const MAX_TRANSCRIPTS = 400_000;
|
|
12
|
+
const MAX_CELL_TILES = 48;
|
|
13
|
+
const MAX_TRANSCRIPT_TILES = 36;
|
|
14
|
+
const MAX_BIN_TILES = 64;
|
|
15
|
+
const CAMERA_IDLE_MS = 120;
|
|
16
|
+
/** First retry of a view with a failed tile; doubles each time, up to MAX_TILE_RETRIES. */
|
|
17
|
+
const TILE_RETRY_MS = 1000;
|
|
18
|
+
const MAX_TILE_RETRIES = 3;
|
|
19
|
+
const UNASSIGNED_RGBA = [0.62, 0.62, 0.62, 0.55];
|
|
20
|
+
export class NapariSpatialTileLayers {
|
|
21
|
+
constructor(port, host) {
|
|
22
|
+
this.port = port;
|
|
23
|
+
this.host = host;
|
|
24
|
+
this.viewer = null;
|
|
25
|
+
this.cameraOff = null;
|
|
26
|
+
this.timer = null;
|
|
27
|
+
/** Set when a tile of the current plan failed to load (see fetchAll). */
|
|
28
|
+
this.planIncomplete = false;
|
|
29
|
+
/** Consecutive retries of an incomplete view. */
|
|
30
|
+
this.tileRetries = 0;
|
|
31
|
+
this.token = 0;
|
|
32
|
+
this.layers = new Map();
|
|
33
|
+
/** What each group currently shows, so an unchanged plan is a no-op. */
|
|
34
|
+
this.keys = new Map();
|
|
35
|
+
this.polygonsShown = false;
|
|
36
|
+
/** Rings currently drawn and the (dataset, set, tiles) they came from. */
|
|
37
|
+
this.currentRings = null;
|
|
38
|
+
this.cellGeometryKey = null;
|
|
39
|
+
this.currentNuclei = null;
|
|
40
|
+
this.cellStyleKey = null;
|
|
41
|
+
/** Selection identity → revision, so a change key can name a selection cheaply. */
|
|
42
|
+
this.lastSelection = null;
|
|
43
|
+
this.selectionRevision = 0;
|
|
44
|
+
// ── hover ─────────────────────────────────────────────────────────────────────────
|
|
45
|
+
this.drawn = null;
|
|
46
|
+
this.hoverTypes = null;
|
|
47
|
+
/** Details already fetched, by hovered entry. */
|
|
48
|
+
this.hoverCache = new Map();
|
|
49
|
+
this.hoverKey = null;
|
|
50
|
+
this.hoverTimer = null;
|
|
51
|
+
this.countsCache = null;
|
|
52
|
+
/** The density window in use and the densest bin, for the panel's threshold control. */
|
|
53
|
+
this.densityStats = null;
|
|
54
|
+
}
|
|
55
|
+
// ── lifecycle ─────────────────────────────────────────────────────────────────────
|
|
56
|
+
attach(viewer) {
|
|
57
|
+
if (this.viewer === viewer)
|
|
58
|
+
return;
|
|
59
|
+
this.detach();
|
|
60
|
+
this.viewer = viewer;
|
|
61
|
+
this.cameraOff = viewer.camera.changed.connect(() => this.schedule());
|
|
62
|
+
}
|
|
63
|
+
/** Whether `layer` is one of the overlays drawn here (density, cells, transcripts). */
|
|
64
|
+
owns(layer) {
|
|
65
|
+
for (const l of this.layers.values())
|
|
66
|
+
if (l === layer)
|
|
67
|
+
return true;
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
detach() {
|
|
71
|
+
if (this.hoverTimer)
|
|
72
|
+
clearTimeout(this.hoverTimer);
|
|
73
|
+
this.hoverTimer = null;
|
|
74
|
+
this.drawn = null;
|
|
75
|
+
this.cameraOff?.();
|
|
76
|
+
this.cameraOff = null;
|
|
77
|
+
if (this.timer)
|
|
78
|
+
clearTimeout(this.timer);
|
|
79
|
+
this.timer = null;
|
|
80
|
+
this.token++;
|
|
81
|
+
this.tileRetries = 0;
|
|
82
|
+
if (this.viewer) {
|
|
83
|
+
for (const layer of this.layers.values()) {
|
|
84
|
+
if (this.viewer.layers.items.includes(layer))
|
|
85
|
+
this.viewer.layers.remove(layer);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
this.layers.clear();
|
|
89
|
+
this.keys.clear();
|
|
90
|
+
this.setPolygonsShown(false);
|
|
91
|
+
this.viewer = null;
|
|
92
|
+
}
|
|
93
|
+
/** True while outlines are on screen — the service hides its dots then. */
|
|
94
|
+
get outlinesShown() {
|
|
95
|
+
return this.polygonsShown;
|
|
96
|
+
}
|
|
97
|
+
/** Dataset, view or selection changed: re-plan now rather than on camera idle. */
|
|
98
|
+
refresh() {
|
|
99
|
+
this.schedule(0);
|
|
100
|
+
}
|
|
101
|
+
/** Called right after the service adds its marker layer: everything goes back on top. */
|
|
102
|
+
afterObservations() {
|
|
103
|
+
const v = this.viewer;
|
|
104
|
+
if (!v)
|
|
105
|
+
return;
|
|
106
|
+
for (const g of ORDER) {
|
|
107
|
+
const layer = this.layers.get(g);
|
|
108
|
+
if (!layer)
|
|
109
|
+
continue;
|
|
110
|
+
if (v.layers.items.includes(layer))
|
|
111
|
+
v.layers.remove(layer);
|
|
112
|
+
v.layers.add(layer);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ── planning ──────────────────────────────────────────────────────────────────────
|
|
116
|
+
schedule(delay = CAMERA_IDLE_MS) {
|
|
117
|
+
if (this.timer)
|
|
118
|
+
clearTimeout(this.timer);
|
|
119
|
+
this.timer = setTimeout(() => {
|
|
120
|
+
this.timer = null;
|
|
121
|
+
void this.plan();
|
|
122
|
+
}, delay);
|
|
123
|
+
}
|
|
124
|
+
async plan() {
|
|
125
|
+
const viewer = this.viewer;
|
|
126
|
+
const latest = this.host.latest();
|
|
127
|
+
if (!viewer || !latest)
|
|
128
|
+
return;
|
|
129
|
+
const [dataset, view, selection] = latest;
|
|
130
|
+
const token = ++this.token;
|
|
131
|
+
const stale = () => token !== this.token || this.viewer !== viewer;
|
|
132
|
+
this.planIncomplete = false;
|
|
133
|
+
if (!dataset) {
|
|
134
|
+
for (const g of ORDER)
|
|
135
|
+
this.drop(g);
|
|
136
|
+
this.dropCells();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const [w, h] = this.host.canvasSize();
|
|
140
|
+
const ref = dataset.imageRef;
|
|
141
|
+
const rect = visibleDataRect(viewer.camera.center, viewer.camera.zoom, w, h, ref);
|
|
142
|
+
const pxPerUnit = pixelsPerDataUnit(viewer.camera.zoom, ref);
|
|
143
|
+
if (!rect)
|
|
144
|
+
return;
|
|
145
|
+
void this.planEstimate(dataset, view, viewer, w, h, stale);
|
|
146
|
+
await Promise.all([
|
|
147
|
+
this.planDensity(dataset, view, stale),
|
|
148
|
+
this.planCells(dataset, view, selection, rect, pxPerUnit, stale),
|
|
149
|
+
this.planTranscripts(dataset, view, rect, pxPerUnit, stale),
|
|
150
|
+
]);
|
|
151
|
+
if (stale())
|
|
152
|
+
return;
|
|
153
|
+
// A tile that failed left a hole the cache keys do not record, so try the same view
|
|
154
|
+
// again, backing off, a bounded number of times.
|
|
155
|
+
if (!this.planIncomplete) {
|
|
156
|
+
this.tileRetries = 0;
|
|
157
|
+
}
|
|
158
|
+
else if (this.tileRetries < MAX_TILE_RETRIES) {
|
|
159
|
+
this.schedule(TILE_RETRY_MS * 2 ** this.tileRetries++);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// ── cells ─────────────────────────────────────────────────────────────────────────
|
|
163
|
+
async planCells(dataset, view, selection, rect, pxPerUnit, stale) {
|
|
164
|
+
const tiled = dataset.polygonTiles;
|
|
165
|
+
const whole = !tiled && dataset.polygons && this.port.getPolygons;
|
|
166
|
+
if (!cellsShown(dataset, view) || (!tiled && !whole)) {
|
|
167
|
+
this.dropCells();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const diameter = typicalCellDiameter(dataset.observations.radius);
|
|
171
|
+
// Whole-dataset rings have one level and no coarser fallback, so they are drawn as
|
|
172
|
+
// soon as a cell is big enough to read as a shape rather than a dot.
|
|
173
|
+
const level = tiled
|
|
174
|
+
? polygonLevelFor(pxPerUnit, diameter, tiled.levels.length)
|
|
175
|
+
: (pxPerUnit * diameter >= POLYGON_LEVEL_MIN_CELL_PX[2] ? 0 : -1);
|
|
176
|
+
if (level < 0) {
|
|
177
|
+
this.dropCells();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// Groups switched off in the list: their cells are left out of the geometry.
|
|
181
|
+
const hidden = await this.hiddenCodes(dataset, view);
|
|
182
|
+
if (stale())
|
|
183
|
+
return;
|
|
184
|
+
const geometry = await this.cellGeometry(dataset, view, rect, level, hidden, stale);
|
|
185
|
+
if (!geometry)
|
|
186
|
+
return;
|
|
187
|
+
const { rings, nuclei, geometryKey } = geometry;
|
|
188
|
+
const geometryChanged = geometryKey !== this.cellGeometryKey;
|
|
189
|
+
const styleKey = [
|
|
190
|
+
geometryKey, view.cellColorMode, view.cellColorGene, view.cellSingleColor,
|
|
191
|
+
this.cellTypeColumnName(dataset, view),
|
|
192
|
+
this.selectionRev(selection), view.logScale, view.percentileClip.join(),
|
|
193
|
+
JSON.stringify(view.continuousColormap), view.cellDraw, view.cellOpacity,
|
|
194
|
+
].join('|');
|
|
195
|
+
const present = ['cellFill', 'cellOutline', 'nucleusOutline'].some((g) => {
|
|
196
|
+
const l = this.layers.get(g);
|
|
197
|
+
return l && this.viewer.layers.items.includes(l);
|
|
198
|
+
});
|
|
199
|
+
if (!geometryChanged && styleKey === this.cellStyleKey && present) {
|
|
200
|
+
this.setPolygonsShown(true);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const colors = await this.cellColors(dataset, view, selection, rings.observation);
|
|
204
|
+
if (stale())
|
|
205
|
+
return;
|
|
206
|
+
this.currentRings = rings;
|
|
207
|
+
this.currentNuclei = nuclei;
|
|
208
|
+
// A geometry missing a failed tile is drawn but not remembered, so the retry refetches it.
|
|
209
|
+
this.cellGeometryKey = this.planIncomplete ? null : geometryKey;
|
|
210
|
+
this.cellStyleKey = styleKey;
|
|
211
|
+
const ref = dataset.imageRef;
|
|
212
|
+
const common = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
|
|
213
|
+
const fill = view.cellDraw !== 'outline';
|
|
214
|
+
const outline = view.cellDraw !== 'fill';
|
|
215
|
+
this.upsertShapes('cellFill', fill, geometryChanged, rings, {
|
|
216
|
+
name: 'cells', draw: 'fill', opacity: view.cellOpacity, ...colors, ...common,
|
|
217
|
+
});
|
|
218
|
+
this.upsertShapes('cellOutline', outline, geometryChanged, rings, fill
|
|
219
|
+
// Over a fill, a dark outline separates neighbours of the same type.
|
|
220
|
+
? { name: 'cell outlines', draw: 'outline', color: [0.08, 0.08, 0.1, 1], opacity: 0.7, ...common }
|
|
221
|
+
: { name: 'cell outlines', draw: 'outline', opacity: 1, ...colors, ...common });
|
|
222
|
+
// "Both": nuclei outlined over the cells, light so they read against any fill.
|
|
223
|
+
if (nuclei) {
|
|
224
|
+
this.upsertShapes('nucleusOutline', true, geometryChanged, nuclei, {
|
|
225
|
+
name: 'nucleus outlines', draw: 'outline', color: [0.95, 0.95, 0.98, 1], opacity: 0.8, ...common,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
this.drop('nucleusOutline');
|
|
230
|
+
}
|
|
231
|
+
this.setPolygonsShown(true);
|
|
232
|
+
}
|
|
233
|
+
selectionRev(selection) {
|
|
234
|
+
if (selection !== this.lastSelection) {
|
|
235
|
+
this.lastSelection = selection;
|
|
236
|
+
this.selectionRevision++;
|
|
237
|
+
}
|
|
238
|
+
return this.selectionRevision;
|
|
239
|
+
}
|
|
240
|
+
/** Per-shape values + colormap for the rings' owners. */
|
|
241
|
+
/**
|
|
242
|
+
* Per-shape values + colormap for the rings' owners, by the view's cell-colour mode
|
|
243
|
+
* (Xenium Explorer's "Cell Color"). A selection mutes what it leaves out.
|
|
244
|
+
*/
|
|
245
|
+
async cellColors(dataset, view, selection, owners) {
|
|
246
|
+
const muted = selection.count > 0 ? selection.mask : null;
|
|
247
|
+
const mode = view.cellColorMode;
|
|
248
|
+
if (mode === 'single') {
|
|
249
|
+
const [r, g, b] = parseHex(view.cellSingleColor);
|
|
250
|
+
return { color: [r / 255, g / 255, b / 255, 1] };
|
|
251
|
+
}
|
|
252
|
+
const continuous = async (raw, log) => {
|
|
253
|
+
const values = new Float32Array(owners.length);
|
|
254
|
+
for (let i = 0; i < owners.length; i++) {
|
|
255
|
+
const v = raw[owners[i]] ?? NaN;
|
|
256
|
+
values[i] = log ? Math.log1p(Math.max(0, v)) : v;
|
|
257
|
+
}
|
|
258
|
+
const [lo, hi] = contrastWindow(log ? raw.map((v) => Math.log1p(Math.max(0, v))) : raw, view.percentileClip[0], view.percentileClip[1]);
|
|
259
|
+
return {
|
|
260
|
+
values,
|
|
261
|
+
colormap: colormapFromLut('spatial-continuous', this.host.continuousLut(view)),
|
|
262
|
+
contrastLimits: [lo, hi],
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
if (mode === 'gene' && view.cellColorGene) {
|
|
266
|
+
return continuous(await this.port.getFeatureVector(view.cellColorGene), true);
|
|
267
|
+
}
|
|
268
|
+
if (mode === 'transcriptDensity' && dataset.columns.some((c) => c.name === 'transcript_density')) {
|
|
269
|
+
const column = await this.port.getColumn('transcript_density');
|
|
270
|
+
if (!isCategoricalColumn(column))
|
|
271
|
+
return continuous(column.values, false);
|
|
272
|
+
}
|
|
273
|
+
const name = mode === 'segmentation' && dataset.columns.some((c) => c.name === 'segmentation_method')
|
|
274
|
+
? 'segmentation_method'
|
|
275
|
+
: this.cellTypeColumnName(dataset, view);
|
|
276
|
+
const codes = name ? await this.categoricalCodes(name) : null;
|
|
277
|
+
const { colormap, valueOf } = this.categoricalColormap(codes?.meta ?? null);
|
|
278
|
+
const values = new Float32Array(owners.length);
|
|
279
|
+
for (let i = 0; i < owners.length; i++) {
|
|
280
|
+
const o = owners[i];
|
|
281
|
+
const code = !codes || (muted && !muted[o]) ? -1 : codes.codes[o];
|
|
282
|
+
values[i] = valueOf(code === NO_CATEGORY ? -1 : code);
|
|
283
|
+
}
|
|
284
|
+
return { values, colormap, contrastLimits: [0, 1] };
|
|
285
|
+
}
|
|
286
|
+
/** Codes of the group column that are switched off, or null when none are. */
|
|
287
|
+
async hiddenCodes(dataset, view) {
|
|
288
|
+
if (!view.hiddenGroups.length)
|
|
289
|
+
return null;
|
|
290
|
+
const name = this.cellTypeColumnName(dataset, view);
|
|
291
|
+
const col = name ? await this.categoricalCodes(name) : null;
|
|
292
|
+
if (!col || col.meta.kind !== 'categorical')
|
|
293
|
+
return null;
|
|
294
|
+
const off = new Set(view.hiddenGroups);
|
|
295
|
+
const hidden = Uint8Array.from(col.meta.categories, (c) => (off.has(c) ? 1 : 0));
|
|
296
|
+
return { codes: col.codes, hidden };
|
|
297
|
+
}
|
|
298
|
+
cellTypeColumnName(dataset, view) {
|
|
299
|
+
return cellTypeColumnFor(dataset, view);
|
|
300
|
+
}
|
|
301
|
+
async categoricalCodes(name) {
|
|
302
|
+
const column = await this.port.getColumn(name);
|
|
303
|
+
return isCategoricalColumn(column) ? { codes: column.codes, meta: column.meta } : null;
|
|
304
|
+
}
|
|
305
|
+
categoricalColormap(meta) {
|
|
306
|
+
const hex = meta && meta.kind === 'categorical'
|
|
307
|
+
? resolveCategoryColors(meta)
|
|
308
|
+
: [DEFAULT_CATEGORICAL_PALETTE[0]];
|
|
309
|
+
const rgb = hex.map(parseHex);
|
|
310
|
+
const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
|
|
311
|
+
return { colormap: new Colormap('spatial-categories', stops), valueOf, rgb };
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The cell rings (and, for "both", the nucleus rings) covering `rect` at `level`, minus
|
|
315
|
+
* the hidden groups — reused when nothing that decides them changed. Null when the
|
|
316
|
+
* view went stale or the dataset has no set to draw.
|
|
317
|
+
*/
|
|
318
|
+
async cellGeometry(dataset, view, rect, level, hidden, stale) {
|
|
319
|
+
const tiled = dataset.polygonTiles;
|
|
320
|
+
const hiddenKey = view.hiddenGroups.join('\u0001');
|
|
321
|
+
let rings;
|
|
322
|
+
let nuclei = null;
|
|
323
|
+
let geometryKey;
|
|
324
|
+
if (tiled) {
|
|
325
|
+
const both = view.cellSet === 'both';
|
|
326
|
+
const set = !both && view.cellSet && tiled.sets.some((s) => s.name === view.cellSet)
|
|
327
|
+
? view.cellSet : (tiled.defaultSet ?? tiled.sets[0]?.name);
|
|
328
|
+
if (!set)
|
|
329
|
+
return null;
|
|
330
|
+
const nucleusSet = both ? tiled.sets.find((s) => s.name !== set)?.name : undefined;
|
|
331
|
+
const keys = tilesInRect(rect, level, tiled.levels, tiled.bounds, MAX_CELL_TILES);
|
|
332
|
+
geometryKey = `${dataset.id}|${set}|${nucleusSet ?? ''}|${hiddenKey}|${keys.map(tileId).join(',')}`;
|
|
333
|
+
if (geometryKey === this.cellGeometryKey && this.currentRings) {
|
|
334
|
+
rings = this.currentRings;
|
|
335
|
+
nuclei = this.currentNuclei;
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
const [tiles, nucleusTiles] = await Promise.all([
|
|
339
|
+
this.fetchAll(keys, (k) => this.port.getPolygonTile(set, k.level, k.gx, k.gy)),
|
|
340
|
+
nucleusSet
|
|
341
|
+
? this.fetchAll(keys, (k) => this.port.getPolygonTile(nucleusSet, k.level, k.gx, k.gy))
|
|
342
|
+
: Promise.resolve(null),
|
|
343
|
+
]);
|
|
344
|
+
if (stale())
|
|
345
|
+
return null;
|
|
346
|
+
rings = filterRings(mergePolygonTiles(tiles), hidden);
|
|
347
|
+
nuclei = nucleusTiles ? filterRings(mergePolygonTiles(nucleusTiles), hidden) : null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
geometryKey = `${dataset.id}|whole|${hiddenKey}`;
|
|
352
|
+
if (geometryKey === this.cellGeometryKey && this.currentRings) {
|
|
353
|
+
rings = this.currentRings;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
const polys = await this.port.getPolygons();
|
|
357
|
+
if (stale())
|
|
358
|
+
return null;
|
|
359
|
+
// Whole-dataset rings are index-aligned with the observations.
|
|
360
|
+
rings = filterRings({ ...polys, observation: Uint32Array.from({ length: polys.count }, (_v, i) => i) }, hidden);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return { rings, nuclei, geometryKey };
|
|
364
|
+
}
|
|
365
|
+
// ── transcripts ───────────────────────────────────────────────────────────────────
|
|
366
|
+
async planTranscripts(dataset, view, rect, pxPerUnit, stale) {
|
|
367
|
+
const mode = view.transcriptMode;
|
|
368
|
+
const job = (mode === 'circles' || mode === 'glyphs') && this.port.getTranscriptTile
|
|
369
|
+
? (view.transcriptAllGenes
|
|
370
|
+
? this.allGenesJob(dataset, view, rect, pxPerUnit)
|
|
371
|
+
: this.geneJob(dataset, view, rect, pxPerUnit))
|
|
372
|
+
: null;
|
|
373
|
+
if (!job) {
|
|
374
|
+
this.drop('transcripts');
|
|
375
|
+
this.drop('transcriptOutline');
|
|
376
|
+
this.drawn = null;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
// Marker sizes follow the zoom, so the zoom is part of the key; a pan that keeps
|
|
380
|
+
// the same tiles on screen changes nothing.
|
|
381
|
+
const planKey = [
|
|
382
|
+
dataset.id, mode, job.key, view.transcriptColorBy, this.cellTypeColumnName(dataset, view),
|
|
383
|
+
view.transcriptScale, view.transcriptOpacity, JSON.stringify(view.transcriptGlyphs),
|
|
384
|
+
pxPerUnit.toPrecision(4), view.hiddenGroups.join('\u0001'), view.transcriptHiddenGenes.join(','),
|
|
385
|
+
JSON.stringify(view.transcriptGeneColors),
|
|
386
|
+
].join('|');
|
|
387
|
+
const current = this.layers.get('transcripts');
|
|
388
|
+
if (planKey === this.keys.get('transcripts') && current && this.viewer.layers.items.includes(current)) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const loaded = await job.load();
|
|
392
|
+
if (stale())
|
|
393
|
+
return;
|
|
394
|
+
const hidden = await this.hiddenCodes(dataset, view);
|
|
395
|
+
if (stale())
|
|
396
|
+
return;
|
|
397
|
+
const { merged, px } = filterTranscripts(loaded.merged, loaded.px, hidden, (loaded.kind ?? job.kind) === 'genes' ? hiddenGeneSlots(view) : null);
|
|
398
|
+
// A bin of the all-gene pyramid mixes genes and carries none, so it cannot be coloured
|
|
399
|
+
// by gene: colour it by its dominant cell's type until individual transcripts show.
|
|
400
|
+
const kind = loaded.kind ?? job.kind;
|
|
401
|
+
const colorView = kind === 'bins' && view.transcriptColorBy === 'gene'
|
|
402
|
+
? { ...view, transcriptColorBy: 'cellType' } : view;
|
|
403
|
+
const faces = await this.transcriptColors(dataset, colorView, merged);
|
|
404
|
+
if (stale())
|
|
405
|
+
return;
|
|
406
|
+
if (this.planIncomplete)
|
|
407
|
+
this.keys.delete('transcripts');
|
|
408
|
+
else
|
|
409
|
+
this.keys.set('transcripts', planKey);
|
|
410
|
+
const diam = px.map((d) => d / pxPerUnit);
|
|
411
|
+
this.drawn = {
|
|
412
|
+
kind: loaded.kind ?? job.kind, bin: loaded.kind ? loaded.bin : job.bin,
|
|
413
|
+
merged, radius: diam.map((d) => d / 2),
|
|
414
|
+
genes: [...view.transcriptGenes], ref: dataset.imageRef ?? null, grid: null,
|
|
415
|
+
};
|
|
416
|
+
this.hoverCache.clear();
|
|
417
|
+
const typeColumn = this.cellTypeColumnName(dataset, view);
|
|
418
|
+
this.hoverTypes = typeColumn ? await this.categoricalCodes(typeColumn).catch(() => null) : null;
|
|
419
|
+
if (stale())
|
|
420
|
+
return;
|
|
421
|
+
const ref = dataset.imageRef;
|
|
422
|
+
const place = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
|
|
423
|
+
if (mode === 'circles') {
|
|
424
|
+
this.drop('transcriptOutline');
|
|
425
|
+
this.drawTranscriptCircles(merged, diam, faces.rgba, view, place);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
this.drawTranscriptGlyphs(merged, diam, faces, view, place);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/** One sized circle per entry, the size saying how many transcripts it stands for. */
|
|
432
|
+
drawTranscriptCircles(merged, diam, rgba, view, { scale, translate }) {
|
|
433
|
+
const positions = new Float32Array(merged.count * 2);
|
|
434
|
+
for (let i = 0; i < merged.count; i++) {
|
|
435
|
+
positions[2 * i] = merged.x[i];
|
|
436
|
+
positions[2 * i + 1] = merged.y[i];
|
|
437
|
+
}
|
|
438
|
+
const layer = this.viewer.addPoints(positions, {
|
|
439
|
+
name: 'transcripts',
|
|
440
|
+
size: diam,
|
|
441
|
+
faceColor: rgba,
|
|
442
|
+
// A dark rim: a transcript coloured by its cell's type is otherwise the same
|
|
443
|
+
// colour as the cell fill it sits on, and vanishes into it.
|
|
444
|
+
borderColor: [0.04, 0.04, 0.05, 0.9],
|
|
445
|
+
borderWidth: 0.18 * median(diam),
|
|
446
|
+
opacity: view.transcriptOpacity,
|
|
447
|
+
scale,
|
|
448
|
+
translate,
|
|
449
|
+
});
|
|
450
|
+
this.replace('transcripts', layer);
|
|
451
|
+
}
|
|
452
|
+
drawTranscriptGlyphs(merged, diam, faces, view, { scale, translate }) {
|
|
453
|
+
// Glyphs: each entry becomes its gene's icon polygon, filled through a discrete
|
|
454
|
+
// colormap and outlined dark so small icons stay readable over the tissue. With every
|
|
455
|
+
// gene drawn there is one icon for all of them — 18,000 shapes would say nothing.
|
|
456
|
+
const genes = view.transcriptGenes;
|
|
457
|
+
const glyphFor = (slot) => view.transcriptGlyphs[genes[slot]] ?? defaultGlyphFor(slot);
|
|
458
|
+
const single = view.transcriptAllGenes
|
|
459
|
+
? glyphOutline(view.transcriptGlyphs[ALL_GENES] ?? 'circle')
|
|
460
|
+
: null;
|
|
461
|
+
const outlines = single ? [] : genes.map((_g, slot) => glyphOutline(glyphFor(slot)));
|
|
462
|
+
const radius = diam.map((d) => d / 2);
|
|
463
|
+
const { coords, offsets } = glyphRings(merged.x, merged.y, radius, (i) => single ?? outlines[merged.gene[i]]);
|
|
464
|
+
const fill = this.viewer.addShapes(coords, offsets, {
|
|
465
|
+
name: 'transcripts',
|
|
466
|
+
draw: 'fill',
|
|
467
|
+
values: faces.values,
|
|
468
|
+
colormap: faces.colormap,
|
|
469
|
+
contrastLimits: [0, 1],
|
|
470
|
+
opacity: view.transcriptOpacity,
|
|
471
|
+
scale,
|
|
472
|
+
translate,
|
|
473
|
+
});
|
|
474
|
+
this.replace('transcripts', fill);
|
|
475
|
+
const edge = this.viewer.addShapes(coords, offsets, {
|
|
476
|
+
name: 'transcript outlines',
|
|
477
|
+
draw: 'outline',
|
|
478
|
+
color: [0.05, 0.05, 0.05, 1],
|
|
479
|
+
opacity: Math.min(1, view.transcriptOpacity + 0.1),
|
|
480
|
+
scale,
|
|
481
|
+
translate,
|
|
482
|
+
});
|
|
483
|
+
this.replace('transcriptOutline', edge);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Tooltip lines for the transcript marker under world point `(wx, wy)`, or null.
|
|
487
|
+
*
|
|
488
|
+
* Returns what is known at once (gene, count, cell type); anything that needs the
|
|
489
|
+
* server — distinct genes in a group, its top genes and cells, the cell's display id —
|
|
490
|
+
* arrives through `onDetails` once the pointer has rested on the marker briefly.
|
|
491
|
+
*/
|
|
492
|
+
hoverAt(wx, wy, radiusWorld, onDetails) {
|
|
493
|
+
const d = this.drawn;
|
|
494
|
+
const layer = this.layers.get('transcripts');
|
|
495
|
+
if (!d || !layer || !this.viewer?.layers.items.includes(layer) || !d.merged.count) {
|
|
496
|
+
this.hoverKey = null;
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
const sx = d.ref?.scale?.[0] ?? 1;
|
|
500
|
+
const sy = d.ref?.scale?.[1] ?? 1;
|
|
501
|
+
const x = (wx - (d.ref?.translate?.[0] ?? 0)) / sx;
|
|
502
|
+
const y = (wy - (d.ref?.translate?.[1] ?? 0)) / sy;
|
|
503
|
+
const i = pickNearest(d, x, y, radiusWorld / Math.abs(sx));
|
|
504
|
+
if (i < 0) {
|
|
505
|
+
this.hoverKey = null;
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
const key = `${d.kind}|${d.merged.x[i]}|${d.merged.y[i]}|${d.merged.gene[i]}`;
|
|
509
|
+
const cached = this.hoverCache.get(key);
|
|
510
|
+
if (cached)
|
|
511
|
+
return cached;
|
|
512
|
+
if (key !== this.hoverKey) {
|
|
513
|
+
this.hoverKey = key;
|
|
514
|
+
if (this.hoverTimer)
|
|
515
|
+
clearTimeout(this.hoverTimer);
|
|
516
|
+
this.hoverTimer = setTimeout(() => void this.fetchDetails(d, i, key, onDetails), 150);
|
|
517
|
+
}
|
|
518
|
+
return this.describe(d, i, null);
|
|
519
|
+
}
|
|
520
|
+
async fetchDetails(d, i, key, onDetails) {
|
|
521
|
+
if (!this.port.getTranscriptSummary || this.hoverKey !== key)
|
|
522
|
+
return;
|
|
523
|
+
const obs = d.merged.observation[i];
|
|
524
|
+
const cells = obs === NO_OBSERVATION ? [] : [obs];
|
|
525
|
+
let box;
|
|
526
|
+
if (d.kind === 'bins' && d.bin) {
|
|
527
|
+
const { size, origin } = d.bin;
|
|
528
|
+
const bx = Math.floor((d.merged.x[i] - origin[0]) / size);
|
|
529
|
+
const by = Math.floor((d.merged.y[i] - origin[1]) / size);
|
|
530
|
+
const x0 = origin[0] + bx * size;
|
|
531
|
+
const y0 = origin[1] + by * size;
|
|
532
|
+
box = [x0, y0, x0 + size, y0 + size];
|
|
533
|
+
}
|
|
534
|
+
else if (d.kind === 'individual') {
|
|
535
|
+
const e = 0.02;
|
|
536
|
+
box = [d.merged.x[i] - e, d.merged.y[i] - e, d.merged.x[i] + e, d.merged.y[i] + e];
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
const summary = await this.port.getTranscriptSummary({ box, cells });
|
|
540
|
+
const lines = this.describe(d, i, summary);
|
|
541
|
+
this.hoverCache.set(key, lines);
|
|
542
|
+
if (this.hoverKey === key)
|
|
543
|
+
onDetails(lines);
|
|
544
|
+
}
|
|
545
|
+
catch (err) {
|
|
546
|
+
console.warn('[napari-js] transcript details unavailable', err);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/** The tooltip text for entry `i`, with the server's details when they have arrived. */
|
|
550
|
+
describe(d, i, s) {
|
|
551
|
+
const t = d.merged;
|
|
552
|
+
const n = t.weight[i];
|
|
553
|
+
const obs = t.observation[i];
|
|
554
|
+
const fmt = (v) => v.toLocaleString();
|
|
555
|
+
const typeOf = (o) => {
|
|
556
|
+
const types = this.hoverTypes;
|
|
557
|
+
if (!types || o === NO_OBSERVATION || types.meta.kind !== 'categorical')
|
|
558
|
+
return null;
|
|
559
|
+
const c = types.codes[o];
|
|
560
|
+
return c === NO_CATEGORY ? null : types.meta.categories[c] ?? null;
|
|
561
|
+
};
|
|
562
|
+
const cellLine = (o, prefix) => {
|
|
563
|
+
if (o === NO_OBSERVATION)
|
|
564
|
+
return 'outside any cell';
|
|
565
|
+
const id = s?.cellIds?.[o] ?? `#${o}`;
|
|
566
|
+
const type = typeOf(o);
|
|
567
|
+
return `${prefix} ${id}${type ? ` · ${type}` : ''}`;
|
|
568
|
+
};
|
|
569
|
+
if (d.kind === 'bins') {
|
|
570
|
+
const lines = [`${fmt(n)} transcripts · all genes`];
|
|
571
|
+
if (d.bin)
|
|
572
|
+
lines.push(`${d.bin.size.toFixed(1)} × ${d.bin.size.toFixed(1)} µm area`);
|
|
573
|
+
if (s?.transcripts !== undefined) {
|
|
574
|
+
lines.push(`${fmt(s.genes ?? 0)} distinct genes · ${fmt(s.cells ?? 0)} cell${s.cells === 1 ? '' : 's'}`
|
|
575
|
+
+ (s.unassigned ? ` · ${fmt(s.unassigned)} outside cells` : ''));
|
|
576
|
+
if (s.topGenes?.length) {
|
|
577
|
+
lines.push(`top genes: ${s.topGenes.slice(0, 5).map((g) => `${g.name} ${fmt(g.count)}`).join(', ')}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
lines.push(cellLine(obs, 'mostly cell'));
|
|
581
|
+
if (!s && this.port.getTranscriptSummary)
|
|
582
|
+
lines.push('loading details…');
|
|
583
|
+
return lines;
|
|
584
|
+
}
|
|
585
|
+
if (d.kind === 'individual') {
|
|
586
|
+
const gene = s?.topGenes?.[0]?.name;
|
|
587
|
+
return [
|
|
588
|
+
gene ? `${gene} transcript` : 'Transcript',
|
|
589
|
+
cellLine(obs, 'in cell'),
|
|
590
|
+
...(!s && this.port.getTranscriptSummary ? ['loading details…'] : []),
|
|
591
|
+
];
|
|
592
|
+
}
|
|
593
|
+
const gene = d.genes[t.gene[i]] ?? 'transcript';
|
|
594
|
+
return n > 1
|
|
595
|
+
? [`${gene} · ${fmt(n)} transcripts`, 'grouped: zoom in to split', cellLine(obs, 'near cell')]
|
|
596
|
+
: [`${gene} transcript`, cellLine(obs, 'in cell')];
|
|
597
|
+
}
|
|
598
|
+
/** Physical marker size needs µm; null when the dataset's unit is unknown. */
|
|
599
|
+
pxPerMicron(dataset, pxPerUnit) {
|
|
600
|
+
return dataset.micronsPerUnit ? pxPerUnit / dataset.micronsPerUnit : undefined;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* The chosen genes, at the level the zoom calls for — or coarser, while the markers in
|
|
604
|
+
* view would exceed the budget.
|
|
605
|
+
*/
|
|
606
|
+
geneJob(dataset, view, rect, pxPerUnit) {
|
|
607
|
+
const meta = dataset.transcriptTiles;
|
|
608
|
+
const genes = view.transcriptGenes;
|
|
609
|
+
if (!meta || !genes.length)
|
|
610
|
+
return null;
|
|
611
|
+
const first = transcriptLevelFor(pxPerUnit, meta.levels);
|
|
612
|
+
const keysAt = (l) => tilesInRect(rect, l, meta.levels, meta.bounds, MAX_TRANSCRIPT_TILES);
|
|
613
|
+
const query = { genes, quality: view.transcriptQuality };
|
|
614
|
+
const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
|
|
615
|
+
return {
|
|
616
|
+
kind: 'genes',
|
|
617
|
+
key: `genes|${genes.join(',')}|${view.transcriptQuality}|${view.transcriptBudget}|${keysAt(first).map(tileId)}`,
|
|
618
|
+
load: async () => {
|
|
619
|
+
let level = first;
|
|
620
|
+
let merged;
|
|
621
|
+
for (;;) {
|
|
622
|
+
const tiles = await this.fetchAll(keysAt(level), (k) => this.port.getTranscriptTile(k.level, k.gx, k.gy, query));
|
|
623
|
+
merged = mergeTranscriptTiles(tiles, MAX_TRANSCRIPTS);
|
|
624
|
+
if (merged.count <= view.transcriptBudget || level >= meta.levels.length - 1)
|
|
625
|
+
break;
|
|
626
|
+
level++;
|
|
627
|
+
}
|
|
628
|
+
const px = new Float32Array(merged.count);
|
|
629
|
+
for (let i = 0; i < merged.count; i++) {
|
|
630
|
+
px[i] = transcriptMarkerPx(merged.weight[i], view.transcriptScale, pxPerMicron);
|
|
631
|
+
}
|
|
632
|
+
return { merged, px };
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Every gene: the transcripts themselves once they fit the budget, else bins of the
|
|
638
|
+
* all-gene pyramid sized by how many transcripts each holds.
|
|
639
|
+
*/
|
|
640
|
+
allGenesJob(dataset, view, rect, pxPerUnit) {
|
|
641
|
+
const bins = dataset.transcriptBins;
|
|
642
|
+
const tiles = dataset.transcriptTiles;
|
|
643
|
+
const bounds = bins?.bounds ?? tiles?.bounds;
|
|
644
|
+
if (!bounds)
|
|
645
|
+
return null;
|
|
646
|
+
const plan = allGenesPlan({
|
|
647
|
+
rect, bounds, pxPerUnit, budget: view.transcriptBudget,
|
|
648
|
+
total: bins?.count ?? tiles?.count ?? 0,
|
|
649
|
+
levels: bins && this.port.getTranscriptBins ? bins.levels : [],
|
|
650
|
+
canIndividual: !!tiles,
|
|
651
|
+
});
|
|
652
|
+
if (plan.kind === 'individual' && tiles) {
|
|
653
|
+
const keys = tilesInRect(rect, 0, tiles.levels, tiles.bounds, MAX_TRANSCRIPT_TILES);
|
|
654
|
+
// Each tile clipped to the view, rounded outward to 10 units so small pans hit cache.
|
|
655
|
+
const r10 = (v, up) => (up ? Math.ceil(v / 10) : Math.floor(v / 10)) * 10;
|
|
656
|
+
const size = tiles.levels[0].tileSize;
|
|
657
|
+
const boxes = keys.map((k) => [
|
|
658
|
+
Math.max(k.gx * size, r10(rect.x0, false)), Math.max(k.gy * size, r10(rect.y0, false)),
|
|
659
|
+
Math.min((k.gx + 1) * size, r10(rect.x1, true)), Math.min((k.gy + 1) * size, r10(rect.y1, true)),
|
|
660
|
+
]);
|
|
661
|
+
const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
|
|
662
|
+
return {
|
|
663
|
+
kind: 'individual',
|
|
664
|
+
key: `all|individual|${view.transcriptBudget}|${boxes.map((b) => b.join(',')).join(';')}`,
|
|
665
|
+
load: async () => {
|
|
666
|
+
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 }));
|
|
667
|
+
// The plan estimated the view from the dataset's average density; expression is
|
|
668
|
+
// uneven, so a dense view can hold far more. Rather than cut the excess off, show
|
|
669
|
+
// it grouped — the bin level the planner would pick if it had known.
|
|
670
|
+
const cap = Math.max(view.transcriptBudget * 1.5, 1);
|
|
671
|
+
const loaded = got.reduce((n, t) => n + t.count, 0);
|
|
672
|
+
if (loaded > cap && bins && this.port.getTranscriptBins) {
|
|
673
|
+
const fallback = allGenesPlan({
|
|
674
|
+
rect, bounds, pxPerUnit, budget: view.transcriptBudget, total: bins.count,
|
|
675
|
+
levels: bins.levels, canIndividual: false,
|
|
676
|
+
});
|
|
677
|
+
if (fallback.kind === 'bins') {
|
|
678
|
+
const job = this.binsJob(view, rect, pxPerUnit, bounds, bins, fallback.level);
|
|
679
|
+
return { ...(await job.load()), kind: job.kind, bin: job.bin };
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
const merged = mergeTranscriptTiles(got, cap);
|
|
683
|
+
const px = new Float32Array(merged.count);
|
|
684
|
+
for (let i = 0; i < merged.count; i++)
|
|
685
|
+
px[i] = transcriptMarkerPx(1, view.transcriptScale, pxPerMicron);
|
|
686
|
+
return { merged, px };
|
|
687
|
+
},
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
if (plan.kind === 'bins' && bins && this.port.getTranscriptBins) {
|
|
691
|
+
return this.binsJob(view, rect, pxPerUnit, bounds, bins, plan.level);
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
/** Bins of the all-gene pyramid at `level`, sized by how many transcripts each holds. */
|
|
696
|
+
binsJob(view, rect, pxPerUnit, bounds, bins, level) {
|
|
697
|
+
const lv = bins.levels[level];
|
|
698
|
+
const keys = tilesInRectFrom(bins.origin, rect, level, bins.levels.map((l) => ({ tileSize: l.tileSize })), bounds, MAX_BIN_TILES);
|
|
699
|
+
return {
|
|
700
|
+
kind: 'bins',
|
|
701
|
+
bin: { size: lv.binSize, origin: bins.origin },
|
|
702
|
+
key: `all|bins|${level}|${view.transcriptBudget}|${keys.map(tileId)}`,
|
|
703
|
+
load: async () => {
|
|
704
|
+
const got = await this.fetchAll(keys, (k) => this.port.getTranscriptBins(k.level, k.gx, k.gy));
|
|
705
|
+
const merged = mergeTranscriptTiles(got, Math.max(view.transcriptBudget * 1.5, 1));
|
|
706
|
+
const refCount = quantileOf(merged.weight, 0.95);
|
|
707
|
+
const binPx = lv.binSize * pxPerUnit;
|
|
708
|
+
const px = new Float32Array(merged.count);
|
|
709
|
+
for (let i = 0; i < merged.count; i++) {
|
|
710
|
+
px[i] = groupedMarkerPx(merged.weight[i], refCount, binPx, view.transcriptScale);
|
|
711
|
+
}
|
|
712
|
+
return { merged, px };
|
|
713
|
+
},
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
/** Per-entry colours both as RGBA (points) and as colormap values (glyph shapes). */
|
|
717
|
+
async transcriptColors(dataset, view, t) {
|
|
718
|
+
let rgb;
|
|
719
|
+
let codeOf;
|
|
720
|
+
if (view.transcriptColorBy === 'gene') {
|
|
721
|
+
// All genes: codes are the dataset's gene indices, folded onto the palette.
|
|
722
|
+
const n = view.transcriptAllGenes ? DEFAULT_CATEGORICAL_PALETTE.length : view.transcriptGenes.length;
|
|
723
|
+
rgb = Array.from({ length: n }, (_g, i) => parseHex((!view.transcriptAllGenes && view.transcriptGeneColors[view.transcriptGenes[i]])
|
|
724
|
+
|| DEFAULT_CATEGORICAL_PALETTE[i % DEFAULT_CATEGORICAL_PALETTE.length]));
|
|
725
|
+
codeOf = view.transcriptAllGenes ? (i) => t.gene[i] % n : (i) => t.gene[i];
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
const name = this.cellTypeColumnName(dataset, view);
|
|
729
|
+
const codes = name ? await this.categoricalCodes(name) : null;
|
|
730
|
+
rgb = codes?.meta.kind === 'categorical' ? resolveCategoryColors(codes.meta).map(parseHex) : [];
|
|
731
|
+
codeOf = (i) => {
|
|
732
|
+
const o = t.observation[i];
|
|
733
|
+
if (!codes || o === NO_OBSERVATION)
|
|
734
|
+
return -1;
|
|
735
|
+
const c = codes.codes[o];
|
|
736
|
+
return c === NO_CATEGORY ? -1 : c;
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
|
|
740
|
+
const rgba = new Array(t.count);
|
|
741
|
+
const values = new Float32Array(t.count);
|
|
742
|
+
const tuples = rgb.map(([r, g, b]) => [r / 255, g / 255, b / 255, 1]);
|
|
743
|
+
for (let i = 0; i < t.count; i++) {
|
|
744
|
+
const c = codeOf(i);
|
|
745
|
+
rgba[i] = c < 0 ? UNASSIGNED_RGBA : tuples[c];
|
|
746
|
+
values[i] = valueOf(c);
|
|
747
|
+
}
|
|
748
|
+
return { rgba, values, colormap: new Colormap('transcript-categories', stops) };
|
|
749
|
+
}
|
|
750
|
+
// ── density ───────────────────────────────────────────────────────────────────────
|
|
751
|
+
async planDensity(dataset, view, stale) {
|
|
752
|
+
const hiddenGenes = new Set(view.transcriptHiddenGenes);
|
|
753
|
+
const genes = view.transcriptAllGenes
|
|
754
|
+
? [ALL_GENES]
|
|
755
|
+
: view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
|
|
756
|
+
if (!dataset.density || !this.port.getDensity || view.transcriptMode !== 'density' || !genes.length) {
|
|
757
|
+
this.drop('density');
|
|
758
|
+
this.densityStats = null;
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const lut = lutFor(view.densityColormap ?? INFERNO_SCALE);
|
|
762
|
+
const key = [dataset.id, genes.join(','), view.densityBin, view.densityOpacity,
|
|
763
|
+
JSON.stringify(view.densityRange), JSON.stringify(view.densityColormap)].join('|');
|
|
764
|
+
if (key === this.keys.get('density') && this.layers.has('density'))
|
|
765
|
+
return;
|
|
766
|
+
const raster = await this.port.getDensity(genes, view.densityBin);
|
|
767
|
+
if (stale())
|
|
768
|
+
return;
|
|
769
|
+
// Bins drawn as squares, as Xenium Explorer does; the window is in transcripts/µm².
|
|
770
|
+
const meta = raster.meta;
|
|
771
|
+
const area = meta.gridSize[0] * meta.gridSize[1];
|
|
772
|
+
const perArea = raster.values.map((v) => v / area);
|
|
773
|
+
const [lo, hi] = view.densityRange ?? densityAutoRange(perArea);
|
|
774
|
+
this.densityStats = { lo, hi, max: perArea.reduce((m, v) => (v > m ? v : m), 0) };
|
|
775
|
+
const rgba = colorDensityWindow(perArea, lut, view.densityOpacity, lo, hi);
|
|
776
|
+
const ref = dataset.imageRef;
|
|
777
|
+
const sx = ref?.scale?.[0] ?? 1;
|
|
778
|
+
const sy = ref?.scale?.[1] ?? 1;
|
|
779
|
+
const layer = this.viewer.addImage({ kind: 'typed', width: meta.cols, height: meta.rows, channels: 4, dtype: 'uint8', data: rgba }, {
|
|
780
|
+
name: `density · ${view.transcriptAllGenes ? 'all genes' : genes.join(', ')}`,
|
|
781
|
+
scale: [meta.gridSize[0] * sx, meta.gridSize[1] * sy],
|
|
782
|
+
translate: [
|
|
783
|
+
meta.origin[0] * sx + (ref?.translate?.[0] ?? 0),
|
|
784
|
+
meta.origin[1] * sy + (ref?.translate?.[1] ?? 0),
|
|
785
|
+
],
|
|
786
|
+
blending: 'translucent',
|
|
787
|
+
interpolation: 'nearest',
|
|
788
|
+
});
|
|
789
|
+
this.keys.set('density', key);
|
|
790
|
+
this.replace('density', layer);
|
|
791
|
+
this.host.densityChanged?.(this.densityStats);
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Transcripts in view for the visible genes: each gene's dataset total times the share
|
|
795
|
+
* of the tissue on screen. An estimate — expression is not uniform — which is also what
|
|
796
|
+
* Xenium Explorer shows; it tells the user whether the budget will force grouping.
|
|
797
|
+
*/
|
|
798
|
+
async planEstimate(dataset, view, viewer, w, h, stale) {
|
|
799
|
+
const tiles = dataset.transcriptTiles;
|
|
800
|
+
if (!tiles || !this.port.getTranscriptCounts || view.transcriptMode === 'off') {
|
|
801
|
+
this.host.estimateChanged?.(null);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const hiddenGenes = new Set(view.transcriptHiddenGenes);
|
|
805
|
+
const genes = view.transcriptAllGenes ? [] : view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
|
|
806
|
+
const key = `${dataset.id}|${genes.join(',')}`;
|
|
807
|
+
if (this.countsCache?.key !== key) {
|
|
808
|
+
this.countsCache = { key, counts: this.port.getTranscriptCounts(genes) };
|
|
809
|
+
}
|
|
810
|
+
let counts;
|
|
811
|
+
try {
|
|
812
|
+
counts = await this.countsCache.counts;
|
|
813
|
+
}
|
|
814
|
+
catch {
|
|
815
|
+
this.countsCache = null;
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
if (stale())
|
|
819
|
+
return;
|
|
820
|
+
const inView = visibleDataRect(viewer.camera.center, viewer.camera.zoom, w, h, dataset.imageRef, 0);
|
|
821
|
+
if (!inView)
|
|
822
|
+
return;
|
|
823
|
+
const b = counts.bounds;
|
|
824
|
+
const share = Math.min(1, visibleArea(inView, b) / Math.max(1, (b[2] - b[0]) * (b[3] - b[1])));
|
|
825
|
+
const selected = view.transcriptAllGenes
|
|
826
|
+
? counts.total
|
|
827
|
+
: genes.reduce((sum, g) => sum + (counts.counts[g] ?? 0), 0);
|
|
828
|
+
this.host.estimateChanged?.({ points: Math.round(selected * share), max: view.transcriptBudget });
|
|
829
|
+
}
|
|
830
|
+
// ── layer bookkeeping ─────────────────────────────────────────────────────────────
|
|
831
|
+
/**
|
|
832
|
+
* Fetch every tile, drawing what arrived. A failure does not fail the view, but it marks the
|
|
833
|
+
* plan incomplete: the caller must not cache it as done, and `plan()` retries it.
|
|
834
|
+
*/
|
|
835
|
+
async fetchAll(keys, load) {
|
|
836
|
+
const settled = await Promise.allSettled(keys.map(load));
|
|
837
|
+
const out = [];
|
|
838
|
+
for (const s of settled) {
|
|
839
|
+
if (s.status === 'fulfilled')
|
|
840
|
+
out.push(s.value);
|
|
841
|
+
else
|
|
842
|
+
console.warn('[napari-js] spatial tile failed', s.reason);
|
|
843
|
+
}
|
|
844
|
+
if (out.length < keys.length)
|
|
845
|
+
this.planIncomplete = true;
|
|
846
|
+
return out;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Put a shapes layer in place for `group`: a geometry change builds a new layer, a
|
|
850
|
+
* colour-only change mutates values/colormap on the existing one.
|
|
851
|
+
*/
|
|
852
|
+
upsertShapes(group, wanted, geometryChanged, rings, opts) {
|
|
853
|
+
if (!wanted) {
|
|
854
|
+
this.drop(group);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const existing = this.layers.get(group);
|
|
858
|
+
if (existing && !geometryChanged && this.viewer.layers.items.includes(existing)) {
|
|
859
|
+
// Flat colour has no values; clearing them is what switches the layer to `color`.
|
|
860
|
+
existing.values = opts.values ?? null;
|
|
861
|
+
if (opts.colormap)
|
|
862
|
+
existing.colormap = opts.colormap;
|
|
863
|
+
if (opts.contrastLimits)
|
|
864
|
+
existing.contrastLimits = opts.contrastLimits;
|
|
865
|
+
if (opts.color)
|
|
866
|
+
existing.color = opts.color;
|
|
867
|
+
if (opts.opacity !== undefined)
|
|
868
|
+
existing.opacity = opts.opacity;
|
|
869
|
+
this.viewer.requestRender();
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
const layer = this.viewer.addShapes(rings.coords, rings.offsets, opts);
|
|
873
|
+
this.replace(group, layer);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Install `layer` as `group`'s layer and restore the order of the groups above it.
|
|
877
|
+
* The layer was just added by the caller (so it is on top); groups that belong above
|
|
878
|
+
* it are removed and re-added.
|
|
879
|
+
*/
|
|
880
|
+
replace(group, layer) {
|
|
881
|
+
const v = this.viewer;
|
|
882
|
+
const old = this.layers.get(group);
|
|
883
|
+
if (old && old !== layer && v.layers.items.includes(old))
|
|
884
|
+
v.layers.remove(old);
|
|
885
|
+
this.layers.set(group, layer);
|
|
886
|
+
for (const g of ORDER.slice(ORDER.indexOf(group) + 1)) {
|
|
887
|
+
const above = this.layers.get(g);
|
|
888
|
+
if (!above || !v.layers.items.includes(above))
|
|
889
|
+
continue;
|
|
890
|
+
v.layers.remove(above);
|
|
891
|
+
v.layers.add(above);
|
|
892
|
+
}
|
|
893
|
+
v.requestRender();
|
|
894
|
+
}
|
|
895
|
+
drop(group) {
|
|
896
|
+
const layer = this.layers.get(group);
|
|
897
|
+
if (layer && this.viewer?.layers.items.includes(layer))
|
|
898
|
+
this.viewer.layers.remove(layer);
|
|
899
|
+
this.layers.delete(group);
|
|
900
|
+
this.keys.delete(group);
|
|
901
|
+
}
|
|
902
|
+
dropCells() {
|
|
903
|
+
this.drop('cellFill');
|
|
904
|
+
this.drop('cellOutline');
|
|
905
|
+
this.drop('nucleusOutline');
|
|
906
|
+
this.currentNuclei = null;
|
|
907
|
+
this.cellGeometryKey = null;
|
|
908
|
+
this.cellStyleKey = null;
|
|
909
|
+
this.currentRings = null;
|
|
910
|
+
this.setPolygonsShown(false);
|
|
911
|
+
}
|
|
912
|
+
setPolygonsShown(shown) {
|
|
913
|
+
if (shown === this.polygonsShown)
|
|
914
|
+
return;
|
|
915
|
+
this.polygonsShown = shown;
|
|
916
|
+
this.host.polygonsShownChanged(shown);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
/** Index of the entry under `(x, y)` — within its own radius or `tolerance` — or -1. */
|
|
920
|
+
export function pickNearest(d, x, y, tolerance) {
|
|
921
|
+
const t = d.merged;
|
|
922
|
+
if (!d.grid) {
|
|
923
|
+
let maxR = 0;
|
|
924
|
+
for (let i = 0; i < t.count; i++)
|
|
925
|
+
if (d.radius[i] > maxR)
|
|
926
|
+
maxR = d.radius[i];
|
|
927
|
+
const size = Math.max(maxR * 2, tolerance * 2, 1e-6);
|
|
928
|
+
const buckets = new Map();
|
|
929
|
+
for (let i = 0; i < t.count; i++) {
|
|
930
|
+
const k = bucketKey(Math.floor(t.x[i] / size), Math.floor(t.y[i] / size));
|
|
931
|
+
let b = buckets.get(k);
|
|
932
|
+
if (!b)
|
|
933
|
+
buckets.set(k, (b = []));
|
|
934
|
+
b.push(i);
|
|
935
|
+
}
|
|
936
|
+
d.grid = { size, buckets };
|
|
937
|
+
}
|
|
938
|
+
const { size, buckets } = d.grid;
|
|
939
|
+
const gx = Math.floor(x / size);
|
|
940
|
+
const gy = Math.floor(y / size);
|
|
941
|
+
let best = -1;
|
|
942
|
+
let bestD = Infinity;
|
|
943
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
944
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
945
|
+
for (const i of buckets.get(bucketKey(gx + dx, gy + dy)) ?? []) {
|
|
946
|
+
const dist = Math.hypot(t.x[i] - x, t.y[i] - y);
|
|
947
|
+
if (dist <= Math.max(d.radius[i], tolerance) && dist < bestD) {
|
|
948
|
+
bestD = dist;
|
|
949
|
+
best = i;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return best;
|
|
955
|
+
}
|
|
956
|
+
function bucketKey(gx, gy) {
|
|
957
|
+
return (gx + 32768) * 65536 + (gy + 32768);
|
|
958
|
+
}
|
|
959
|
+
/** Rings whose owning cell is in a switched-off group removed. */
|
|
960
|
+
export function filterRings(rings, hidden) {
|
|
961
|
+
if (!hidden)
|
|
962
|
+
return rings;
|
|
963
|
+
const keep = [];
|
|
964
|
+
let vertices = 0;
|
|
965
|
+
for (let i = 0; i < rings.count; i++) {
|
|
966
|
+
const code = hidden.codes[rings.observation[i]];
|
|
967
|
+
if (code !== NO_CATEGORY && hidden.hidden[code])
|
|
968
|
+
continue;
|
|
969
|
+
keep.push(i);
|
|
970
|
+
vertices += rings.offsets[i + 1] - rings.offsets[i];
|
|
971
|
+
}
|
|
972
|
+
if (keep.length === rings.count)
|
|
973
|
+
return rings;
|
|
974
|
+
const observation = new Uint32Array(keep.length);
|
|
975
|
+
const offsets = new Uint32Array(keep.length + 1);
|
|
976
|
+
const coords = new Float32Array(vertices * 2);
|
|
977
|
+
let v = 0;
|
|
978
|
+
keep.forEach((i, r) => {
|
|
979
|
+
observation[r] = rings.observation[i];
|
|
980
|
+
offsets[r] = v;
|
|
981
|
+
const a = rings.offsets[i] * 2;
|
|
982
|
+
const b = rings.offsets[i + 1] * 2;
|
|
983
|
+
coords.set(rings.coords.subarray(a, b), v * 2);
|
|
984
|
+
v += (b - a) / 2;
|
|
985
|
+
});
|
|
986
|
+
offsets[keep.length] = v;
|
|
987
|
+
return { count: keep.length, observation, offsets, coords };
|
|
988
|
+
}
|
|
989
|
+
/** Slots (indices into the selected genes) switched off with their eye toggle. */
|
|
990
|
+
function hiddenGeneSlots(view) {
|
|
991
|
+
if (!view.transcriptHiddenGenes.length)
|
|
992
|
+
return null;
|
|
993
|
+
const off = new Set(view.transcriptHiddenGenes);
|
|
994
|
+
return Uint8Array.from(view.transcriptGenes, (g) => (off.has(g) ? 1 : 0));
|
|
995
|
+
}
|
|
996
|
+
/** Entries in a hidden group's cell, or of a hidden gene, removed (with their sizes). */
|
|
997
|
+
export function filterTranscripts(t, px, hidden, hiddenGenes) {
|
|
998
|
+
if (!hidden && !hiddenGenes)
|
|
999
|
+
return { merged: t, px };
|
|
1000
|
+
const keep = [];
|
|
1001
|
+
for (let i = 0; i < t.count; i++) {
|
|
1002
|
+
if (hiddenGenes && hiddenGenes[t.gene[i]])
|
|
1003
|
+
continue;
|
|
1004
|
+
const o = t.observation[i];
|
|
1005
|
+
if (hidden && o !== NO_OBSERVATION) {
|
|
1006
|
+
const code = hidden.codes[o];
|
|
1007
|
+
if (code !== NO_CATEGORY && hidden.hidden[code])
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
keep.push(i);
|
|
1011
|
+
}
|
|
1012
|
+
const pick = (a) => {
|
|
1013
|
+
const out = new a.constructor(keep.length);
|
|
1014
|
+
keep.forEach((i, k) => { out[k] = a[i]; });
|
|
1015
|
+
return out;
|
|
1016
|
+
};
|
|
1017
|
+
return {
|
|
1018
|
+
merged: {
|
|
1019
|
+
count: keep.length, aggregated: t.aggregated, x: pick(t.x), y: pick(t.y), z: pick(t.z),
|
|
1020
|
+
weight: pick(t.weight), observation: pick(t.observation), gene: pick(t.gene),
|
|
1021
|
+
},
|
|
1022
|
+
px: pick(px),
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function median(v) {
|
|
1026
|
+
if (!v.length)
|
|
1027
|
+
return 0;
|
|
1028
|
+
const step = Math.max(1, Math.floor(v.length / 1024));
|
|
1029
|
+
const sample = [];
|
|
1030
|
+
for (let i = 0; i < v.length; i += step)
|
|
1031
|
+
sample.push(v[i]);
|
|
1032
|
+
sample.sort((a, b) => a - b);
|
|
1033
|
+
return sample[sample.length >> 1];
|
|
1034
|
+
}
|
|
1035
|
+
/** Concatenate tiles' rings into one set, dropping rings already seen (a cell straddling
|
|
1036
|
+
* two tiles may be listed by both). */
|
|
1037
|
+
export function mergePolygonTiles(tiles) {
|
|
1038
|
+
const seen = new Set();
|
|
1039
|
+
let rings = 0;
|
|
1040
|
+
let vertices = 0;
|
|
1041
|
+
for (const t of tiles) {
|
|
1042
|
+
for (let i = 0; i < t.count; i++) {
|
|
1043
|
+
if (seen.has(t.observation[i]))
|
|
1044
|
+
continue;
|
|
1045
|
+
seen.add(t.observation[i]);
|
|
1046
|
+
rings++;
|
|
1047
|
+
vertices += t.offsets[i + 1] - t.offsets[i];
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
seen.clear();
|
|
1051
|
+
const observation = new Uint32Array(rings);
|
|
1052
|
+
const offsets = new Uint32Array(rings + 1);
|
|
1053
|
+
const coords = new Float32Array(vertices * 2);
|
|
1054
|
+
let r = 0;
|
|
1055
|
+
let v = 0;
|
|
1056
|
+
for (const t of tiles) {
|
|
1057
|
+
for (let i = 0; i < t.count; i++) {
|
|
1058
|
+
const o = t.observation[i];
|
|
1059
|
+
if (seen.has(o))
|
|
1060
|
+
continue;
|
|
1061
|
+
seen.add(o);
|
|
1062
|
+
observation[r] = o;
|
|
1063
|
+
offsets[r] = v;
|
|
1064
|
+
const a = t.offsets[i] * 2;
|
|
1065
|
+
const b = t.offsets[i + 1] * 2;
|
|
1066
|
+
coords.set(t.coords.subarray(a, b), v * 2);
|
|
1067
|
+
v += (b - a) / 2;
|
|
1068
|
+
r++;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
offsets[rings] = v;
|
|
1072
|
+
return { count: rings, observation, offsets, coords };
|
|
1073
|
+
}
|
|
1074
|
+
/** Concatenate transcript tiles, stopping at `limit` entries. */
|
|
1075
|
+
export function mergeTranscriptTiles(tiles, limit = Infinity) {
|
|
1076
|
+
let n = 0;
|
|
1077
|
+
for (const t of tiles)
|
|
1078
|
+
n += t.count;
|
|
1079
|
+
n = Math.min(n, limit);
|
|
1080
|
+
const out = {
|
|
1081
|
+
count: n,
|
|
1082
|
+
aggregated: tiles.some((t) => t.aggregated),
|
|
1083
|
+
x: new Float32Array(n), y: new Float32Array(n), z: new Float32Array(n),
|
|
1084
|
+
weight: new Uint32Array(n), observation: new Uint32Array(n), gene: new Uint16Array(n),
|
|
1085
|
+
};
|
|
1086
|
+
let o = 0;
|
|
1087
|
+
for (const t of tiles) {
|
|
1088
|
+
const k = Math.min(t.count, n - o);
|
|
1089
|
+
if (k <= 0)
|
|
1090
|
+
break;
|
|
1091
|
+
for (const f of ['x', 'y', 'z', 'weight', 'observation', 'gene']) {
|
|
1092
|
+
out[f].set(t[f].subarray(0, k), o);
|
|
1093
|
+
}
|
|
1094
|
+
o += k;
|
|
1095
|
+
}
|
|
1096
|
+
return out;
|
|
1097
|
+
}
|
|
1098
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtdGlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtdGlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFJdEQsT0FBTyxFQUFFLFNBQVMsRUFBd0IsTUFBTSx5Q0FBeUMsQ0FBQztBQUUxRixPQUFPLEVBQ0wsV0FBVyxFQUFFLGNBQWMsRUFFM0IsbUJBQW1CLEdBQ3BCLE1BQU0sMENBQTBDLENBQUM7QUFDbEQsT0FBTyxFQUNMLDJCQUEyQixFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsR0FDcEcsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV4QyxPQUFPLEVBQ0ssYUFBYSxFQUFFLHlCQUF5QixFQUFtQixZQUFZLEVBQUUsaUJBQWlCLEVBQ3BHLFVBQVUsRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFDOUYsZUFBZSxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQ25GLGVBQWUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLGtCQUFrQixFQUM1RSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsZUFBZSxHQUNsRCxNQUFNLDZCQUE2QixDQUFDO0FBb0RyQyxNQUFNLEtBQUssR0FBWTtJQUNyQixVQUFVLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsbUJBQW1CO0NBQzNGLENBQUM7QUFFRjsrQ0FDK0M7QUFDL0MsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDO0FBQ2hDLE1BQU0sY0FBYyxHQUFHLEVBQUUsQ0FBQztBQUMxQixNQUFN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QUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsSUFBSSxHQUFHLElBQUksR0FBRyxLQUFLLEtBQUssSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDO1lBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDL0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzlCLEtBQUssTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDdEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakMsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7Z0JBQUUsU0FBUztZQUN4RCxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUN2QixDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0QixDQUFDO1FBQ0QsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFFTyxJQUFJLENBQUMsS0FBWTtRQUN2QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyQyxJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQztZQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6RixJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRU8sU0FBUztRQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFDMUIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7UUFDNUIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxLQUFjO1FBQ3JDLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxhQUFhO1lBQUUsT0FBTztRQUN6QyxJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3hDLENBQUM7Q0FDRjtBQWVELHdGQUF3RjtBQUN4RixNQUFNLFVBQVUsV0FBVyxDQUN6QixDQUF1RCxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsU0FBaUI7SUFFaEcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNuQixJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1osSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFO1lBQUUsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUk7Z0JBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0UsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLFNBQVMsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDckQsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7UUFDNUMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNqQyxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQzFFLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkIsSUFBSSxDQUFDLENBQUM7Z0JBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNqQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ1osQ0FBQztRQUNELENBQUMsQ0FBQyxJQUFJLEdBQUcsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUNELE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNqQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUNoQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztJ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TCxNQUFNLEVBQUU7WUFDTixLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdEYsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1NBQzdFO1FBQ0QsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUM7S0FDYixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsTUFBTSxDQUFDLENBQWU7SUFDN0IsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDeEIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdEQsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBQzVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxJQUFJO1FBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzRCxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzdCLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLENBQUM7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VCxDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29sb3JtYXAsIGNvbG9ybWFwRnJvbUx1dCB9IGZyb20gJ25hcGFyaS1qcyc7XG5pbXBvcnQgdHlwZSB7IEltYWdlTGF5ZXIsIExheWVyLCBSR0JBLCBTaGFwZXNMYXllciwgVmlld2VyIH0gZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHR5cGUgeyBSZ2IgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY29sb3JtYXAtbHV0JztcbmltcG9ydCB7IEFMTF9HRU5FUywgdHlwZSBTcGF0aWFsRGF0YVBvcnQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcG9ydHMvc3BhdGlhbC1kYXRhLnBvcnQnO1xuaW1wb3J0IHR5cGUgeyBTcGF0aWFsVmlld1N0YXRlIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHtcbiAgTk9fQ0FURUdPUlksIE5PX09CU0VSVkFUSU9OLCBTcGF0aWFsQm91bmRzLCBTcGF0aWFsQ29sdW1uLCBTcGF0aWFsRGF0YXNldCwgU3BhdGlhbEltYWdlUmVmLCBTcGF0aWFsUG9seWdvblRpbGUsXG4gIFNwYXRpYWxQb2x5Z29ucywgU3BhdGlhbFRyYW5zY3JpcHRDb3VudHMsIFNwYXRpYWxUcmFuc2NyaXB0U3VtbWFyeSwgU3BhdGlhbFRyYW5zY3JpcHRUaWxlLFxuICBpc0NhdGVnb3JpY2FsQ29sdW1uLFxufSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7XG4gIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURSwgTUlTU0lOR19DT0xPUiwgY29udHJhc3RXaW5kb3csIGx1dEZvciwgcGFyc2VIZXgsIHJlc29sdmVDYXRlZ29yeUNvbG9ycyxcbn0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nJztcbmltcG9ydCB7IFNwYXRpYWxTZWxlY3Rpb25NYXNrIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXNlbGVjdGlvbic7XG5pbXBvcnQge1xuICBEYXRhUmVjdCwgSU5GRVJOT19TQ0FMRSwgUE9MWUdPTl9MRVZFTF9NSU5fQ0VMTF9QWCwgVHJhbnNjcmlwdEdseXBoLCBhbGxHZW5lc1BsYW4sIGNlbGxUeXBlQ29sdW1uRm9yLFxuICBjZWxsc1Nob3duLCBjb2xvckRlbnNpdHlXaW5kb3csIGRlbnNpdHlBdXRvUmFuZ2UsIGdyb3VwZWRNYXJrZXJQeCwgcXVhbnRpbGVPZiwgdGlsZXNJblJlY3RGcm9tLFxuICBkZWZhdWx0R2x5cGhGb3IsIGRpc2NyZXRlQ29sb3JtYXBTdG9wcywgZ2x5cGhPdXRsaW5lLCBnbHlwaFJpbmdzLCBwaXhlbHNQZXJEYXRhVW5pdCxcbiAgcG9seWdvbkxldmVsRm9yLCB0aWxlSWQsIHRpbGVzSW5SZWN0LCB0cmFuc2NyaXB0TGV2ZWxGb3IsIHRyYW5zY3JpcHRNYXJrZXJQeCxcbiAgdHlwaWNhbENlbGxEaWFtZXRlciwgdmlzaWJsZUFyZWEsIHZpc2libGVEYXRhUmVjdCxcbn0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXRpbGVzJztcblxuLyoqXG4gKiBMZXZlbC1vZi1kZXRhaWwgY2VsbCBvdXRsaW5lcywgdHJhbnNjcmlwdHMgYW5kIHRyYW5zY3JpcHQgZGVuc2l0eSBmb3IgdGhlIDJEIHNwYXRpYWwgdmlldy5cbiAqXG4gKiBXSFkgQSBTRVBBUkFURSBDTEFTU1xuICogLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEV2ZXJ5dGhpbmcgZWxzZSB0aGUgc3BhdGlhbCB2aWV3IGRyYXdzIGlzIGJ1aWx0IG9uY2UgcGVyIChkYXRhc2V0LCB2aWV3KSBhbmQgb25seVxuICogcmVzdHlsZWQgYWZ0ZXJ3YXJkcy4gVGhlc2UgbGF5ZXJzIGFsc28gZGVwZW5kIG9uIHRoZSBDQU1FUkE6IHdoaWNoIHRpbGVzIGFyZSBvbiBzY3JlZW5cbiAqIGFuZCB3aGljaCBsZXZlbCBvZiBkZXRhaWwgdGhlIHpvb20gY2FsbHMgZm9yLiBLZWVwaW5nIHRoYXQgbG9vcCDigJQgcGxhbiBvbiBjYW1lcmEgaWRsZSxcbiAqIGZldGNoIHRpbGVzLCBtZXJnZSwgZHJhdyDigJQgb3V0IG9mIHRoZSB2aXN1YWxpemVyIHNlcnZpY2Uga2VlcHMgYm90aCByZWFkYWJsZS5cbiAqXG4gKiBMQVlFUiBPUkRFUlxuICogLS0tLS0tLS0tLS1cbiAqIG5hcGFyaS1qcydzIGxheWVyIGxpc3QgaXMgYXBwZW5kLW9ubHkgKGFkZCAvIHJlbW92ZSAvIGNsZWFyKSwgc28gb3JkZXIgaXMga2VwdCBieVxuICogcmUtYWRkaW5nOiBjZWxsIGZpbGwsIGNlbGwgb3V0bGluZSwgdGhlIHRyYW5zY3JpcHQgZGVuc2l0eSwgdGhlbiB0cmFuc2NyaXB0cyBvbiB0b3AuXG4gKiBUaGUgc2VydmljZSdzIG9ic2VydmF0aW9uIG1hcmtlcnMgc2l0IHVuZGVyIGFsbCBvZiB0aGVtOyB3aGlsZSBvdXRsaW5lcyBhcmUgZHJhd24gdGhlXG4gKiBtYXJrZXJzIGFyZSBoaWRkZW4gKGEgY2VsbCBpcyBpdHMgb3V0bGluZSB0aGVuLCBub3QgYSBkb3QpLCBzbyB0aGUgY2VsbHMgbmV2ZXIgaGF2ZSB0b1xuICogYmUgb3JkZXJlZCBhZ2FpbnN0IHRoZW0uIFRoZSBkZW5zaXR5IGdvZXMgT1ZFUiB0aGUgbWFya2VycyBvbiBwdXJwb3NlOiB1bmRlciAxMF41XG4gKiBkb3RzIGl0IHdvdWxkIG9ubHkgc2hvdyBpbiB0aGUgZ2FwcyBiZXR3ZWVuIGNlbGxzLiB7QGxpbmsgYWZ0ZXJPYnNlcnZhdGlvbnN9IHJlc3RvcmVzXG4gKiB0aGUgb3JkZXIgYWZ0ZXIgdGhlIHNlcnZpY2UgcmUtYWRkcyBpdHMgbWFya2Vycy5cbiAqXG4gKiBPTkUgTEFZRVIgUEVSIEdST1VQXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBFYWNoIGdyb3VwIGlzIG9uZSBtZXJnZWQgbGF5ZXIgb3ZlciBldmVyeSB2aXNpYmxlIHRpbGUsIHJlYnVpbHQgd2hlbiB0aGUgdGlsZSBzZXQgb3JcbiAqIGxldmVsIGNoYW5nZXMuIFJlY29sb3VyaW5nIChhIG5ldyBjZWxsLXR5cGUgY29sdW1uLCBhIHNlbGVjdGlvbikgb25seSByZXdyaXRlcyB0aGVcbiAqIHBlci1zaGFwZSB2YWx1ZXMg4oCUIHRoZSBnZW9tZXRyeSBpcyBub3QgcmUtZXhwYW5kZWQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BhdGlhbFRpbGVIb3N0IHtcbiAgLyoqIExhdGVzdCBkYXRhc2V0L3ZpZXcvc2VsZWN0aW9uLCBhcyB0aGUgc3BhdGlhbCBzdWJzY3JpcHRpb24gc2F3IHRoZW0uICovXG4gIGxhdGVzdCgpOiBbU3BhdGlhbERhdGFzZXQgfCBudWxsLCBTcGF0aWFsVmlld1N0YXRlLCBTcGF0aWFsU2VsZWN0aW9uTWFza10gfCBudWxsO1xuICAvKiogQ2FudmFzIHNpemUgaW4gQ1NTIHBpeGVscy4gKi9cbiAgY2FudmFzU2l6ZSgpOiBbbnVtYmVyLCBudW1iZXJdO1xuICAvKiogVGhlIGNvbnRpbnVvdXMgTFVUIHRoZSB2aWV3IGlzIHVzaW5nIChzbyBjZWxscyBjb2xvdXJlZCBieSBhIGdlbmUgbWF0Y2ggdGhlIG1hcmtlcnMpLiAqL1xuICBjb250aW51b3VzTHV0KHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiBSZ2JbXTtcbiAgLyoqIE91dGxpbmVzIGFwcGVhcmVkIG9yIGRpc2FwcGVhcmVkOiB0aGUgbWFya2VycycgdmlzaWJpbGl0eSBmb2xsb3dzLiAqL1xuICBwb2x5Z29uc1Nob3duQ2hhbmdlZChzaG93bjogYm9vbGVhbik6IHZvaWQ7XG4gIC8qKiBUaGUgZGVuc2l0eSB3aW5kb3cgY2hhbmdlZCAoYXV0by1kZXJpdmVkIG9yIHNldCkuICovXG4gIGRlbnNpdHlDaGFuZ2VkPyhzdGF0czogeyBsbzogbnVtYmVyOyBoaTogbnVtYmVyOyBtYXg6IG51bWJlciB9KTogdm9pZDtcbiAgLyoqIEVzdGltYXRlZCB0cmFuc2NyaXB0cyBpbiB2aWV3IGZvciB0aGUgY3VycmVudCBzZWxlY3Rpb24sIGFnYWluc3QgdGhlIGJ1ZGdldC4gKi9cbiAgZXN0aW1hdGVDaGFuZ2VkPyhlc3RpbWF0ZTogVHJhbnNjcmlwdEVzdGltYXRlIHwgbnVsbCk6IHZvaWQ7XG59XG5cbi8qKiBYZW5pdW0gRXhwbG9yZXIncyBcIkVzdGltYXRlZCBUcmFuc2NyaXB0IFBvaW50c1wiLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUcmFuc2NyaXB0RXN0aW1hdGUge1xuICAvKiogVHJhbnNjcmlwdHMgb2YgdGhlIHZpc2libGUgZ2VuZXMgZXN0aW1hdGVkIHRvIGJlIGluIHZpZXcuICovXG4gIHBvaW50czogbnVtYmVyO1xuICAvKiogVGhlIG1hcmtlciBidWRnZXQuICovXG4gIG1heDogbnVtYmVyO1xufVxuXG50eXBlIEdyb3VwID0gJ2RlbnNpdHknIHwgJ2NlbGxGaWxsJyB8ICdjZWxsT3V0bGluZScgfCAnbnVjbGV1c091dGxpbmUnIHwgJ3RyYW5zY3JpcHRzJyB8ICd0cmFuc2NyaXB0T3V0bGluZSc7XG5jb25zdCBPUkRFUjogR3JvdXBbXSA9IFtcbiAgJ2NlbGxGaWxsJywgJ2NlbGxPdXRsaW5lJywgJ251Y2xldXNPdXRsaW5lJywgJ2RlbnNpdHknLCAndHJhbnNjcmlwdHMnLCAndHJhbnNjcmlwdE91dGxpbmUnLFxuXTtcblxuLyoqIFRyYW5zY3JpcHRzIGRyYXduIGF0IG9uY2UuIFBhc3QgdGhpcyBhIHNjcmVlbiBpcyBzb2xpZCBjb2xvdXIgYW55d2F5OyB0aGUgbGV2ZWxcbiAqICBwb2xpY3kga2VlcHMgYSBub3JtYWwgdmlldyBmYXIgYmVsb3cgaXQuICovXG5jb25zdCBNQVhfVFJBTlNDUklQVFMgPSA0MDBfMDAwO1xuY29uc3QgTUFYX0NFTExfVElMRVMgPSA0ODtcbmNvbnN0IE1BWF9UUkFOU0NSSVBUX1RJTEVTID0gMzY7XG5jb25zdCBNQVhfQklOX1RJTEVTID0gNjQ7XG5cbi8qKiBBIHRyYW5zY3JpcHQgZmV0Y2ggdGhlIHBsYW5uZXIgY2FuIGtleSBiZWZvcmUgcnVubmluZy4gKi9cbmludGVyZmFjZSBUcmFuc2NyaXB0Sm9iIHtcbiAgLyoqIFdoYXQgb25lIGVudHJ5IGlzIOKAlCBkZWNpZGVzIHdoYXQgaG92ZXJpbmcgaXQgc2F5cy4gKi9cbiAga2luZDogJ2dlbmVzJyB8ICdpbmRpdmlkdWFsJyB8ICdiaW5zJztcbiAgLyoqIEZvciBiaW5zOiB0aGVpciBzaXplIGFuZCBncmlkIG9yaWdpbiwgc28gYSBob3ZlcmVkIGJpbidzIHNxdWFyZSBjYW4gYmUgcmVjb3ZlcmVkLiAqL1xuICBiaW4/OiB7IHNpemU6IG51bWJlcjsgb3JpZ2luOiBbbnVtYmVyLCBudW1iZXJdIH07XG4gIC8qKiBJZGVudGlmaWVzIHdoYXQgd2lsbCBiZSBkcmF3biwgc28gYW4gdW5jaGFuZ2VkIHBsYW4gaXMgYSBuby1vcC4gKi9cbiAga2V5OiBzdHJpbmc7XG4gIC8qKiBGZXRjaCBhbmQgbWVyZ2U7IGBweGAgaXMgZWFjaCBlbnRyeSdzIG1hcmtlciBkaWFtZXRlciBpbiBzY3JlZW4gcGl4ZWxzLiBBIGpvYiBtYXlcbiAgICogIHN3aXRjaCB0byBhbm90aGVyIGtpbmQgb25jZSBpdCBzZWVzIHRoZSBkYXRhIChpbmRpdmlkdWFsIOKGkiBiaW5zKTsgaXQgdGhlbiBzYXlzIHNvLiAqL1xuICBsb2FkKCk6IFByb21pc2U8VHJhbnNjcmlwdExvYWQ+O1xufVxuXG5pbnRlcmZhY2UgVHJhbnNjcmlwdExvYWQge1xuICBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTtcbiAgcHg6IEZsb2F0MzJBcnJheTtcbiAga2luZD86IFRyYW5zY3JpcHRKb2JbJ2tpbmQnXTtcbiAgYmluPzogVHJhbnNjcmlwdEpvYlsnYmluJ107XG59XG5cbi8qKiBXaGVyZSBhIGxheWVyIHNpdHMgaW4gd29ybGQgc3BhY2U6IHRoZSBkYXRhc2V0J3MgYWZmaW5lIG9udG8gaXRzIHRpc3N1ZSBpbWFnZS4gKi9cbmludGVyZmFjZSBQbGFjZW1lbnQgeyBzY2FsZTogW251bWJlciwgbnVtYmVyXTsgdHJhbnNsYXRlOiBbbnVtYmVyLCBudW1iZXJdIH1cblxuLyoqIFRyYW5zY3JpcHQgY29sb3VyczogcGVyLWVudHJ5IFJHQkEgZm9yIHBvaW50cywgdmFsdWVzICsgY29sb3JtYXAgZm9yIHNoYXBlcy4gKi9cbmludGVyZmFjZSBUcmFuc2NyaXB0RmFjZXMgeyByZ2JhOiBSR0JBW107IHZhbHVlczogRmxvYXQzMkFycmF5OyBjb2xvcm1hcDogQ29sb3JtYXAgfVxuY29uc3QgQ0FNRVJBX0lETEVfTVMgPSAxMjA7XG4vKiogRmlyc3QgcmV0cnkgb2YgYSB2aWV3IHdpdGggYSBmYWlsZWQgdGlsZTsgZG91YmxlcyBlYWNoIHRpbWUsIHVwIHRvIE1BWF9USUxFX1JFVFJJRVMuICovXG5jb25zdCBUSUxFX1JFVFJZX01TID0gMTAwMDtcbmNvbnN0IE1BWF9USUxFX1JFVFJJRVMgPSAzO1xuXG5jb25zdCBVTkFTU0lHTkVEX1JHQkE6IFJHQkEgPSBbMC42MiwgMC42MiwgMC42MiwgMC41NV07XG5cbmV4cG9ydCBjbGFzcyBOYXBhcmlTcGF0aWFsVGlsZUxheWVycyB7XG4gIHByaXZhdGUgdmlld2VyOiBWaWV3ZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjYW1lcmFPZmY6ICgoKSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGwgPSBudWxsO1xuICAvKiogU2V0IHdoZW4gYSB0aWxlIG9mIHRoZSBjdXJyZW50IHBsYW4gZmFpbGVkIHRvIGxvYWQgKHNlZSBmZXRjaEFsbCkuICovXG4gIHByaXZhdGUgcGxhbkluY29tcGxldGUgPSBmYWxzZTtcbiAgLyoqIENvbnNlY3V0aXZlIHJldHJpZXMgb2YgYW4gaW5jb21wbGV0ZSB2aWV3LiAqL1xuICBwcml2YXRlIHRpbGVSZXRyaWVzID0gMDtcbiAgcHJpdmF0ZSB0b2tlbiA9IDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgbGF5ZXJzID0gbmV3IE1hcDxHcm91cCwgTGF5ZXI+KCk7XG4gIC8qKiBXaGF0IGVhY2ggZ3JvdXAgY3VycmVudGx5IHNob3dzLCBzbyBhbiB1bmNoYW5nZWQgcGxhbiBpcyBhIG5vLW9wLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGtleXMgPSBuZXcgTWFwPEdyb3VwLCBzdHJpbmc+KCk7XG4gIHByaXZhdGUgcG9seWdvbnNTaG93biA9IGZhbHNlO1xuICAvKiogUmluZ3MgY3VycmVudGx5IGRyYXduIGFuZCB0aGUgKGRhdGFzZXQsIHNldCwgdGlsZXMpIHRoZXkgY2FtZSBmcm9tLiAqL1xuICBwcml2YXRlIGN1cnJlbnRSaW5nczogU3BhdGlhbFBvbHlnb25UaWxlIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2VsbEdlb21ldHJ5S2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjdXJyZW50TnVjbGVpOiBTcGF0aWFsUG9seWdvblRpbGUgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjZWxsU3R5bGVLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogU2VsZWN0aW9uIGlkZW50aXR5IOKGkiByZXZpc2lvbiwgc28gYSBjaGFuZ2Uga2V5IGNhbiBuYW1lIGEgc2VsZWN0aW9uIGNoZWFwbHkuICovXG4gIHByaXZhdGUgbGFzdFNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2sgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzZWxlY3Rpb25SZXZpc2lvbiA9IDA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBwb3J0OiBTcGF0aWFsRGF0YVBvcnQsIHByaXZhdGUgcmVhZG9ubHkgaG9zdDogU3BhdGlhbFRpbGVIb3N0KSB7fVxuXG4gIC8vIOKUgOKUgCBsaWZlY3ljbGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYXR0YWNoKHZpZXdlcjogVmlld2VyKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudmlld2VyID09PSB2aWV3ZXIpIHJldHVybjtcbiAgICB0aGlzLmRldGFjaCgpO1xuICAgIHRoaXMudmlld2VyID0gdmlld2VyO1xuICAgIHRoaXMuY2FtZXJhT2ZmID0gdmlld2VyLmNhbWVyYS5jaGFuZ2VkLmNvbm5lY3QoKCkgPT4gdGhpcy5zY2hlZHVsZSgpKTtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGBsYXllcmAgaXMgb25lIG9mIHRoZSBvdmVybGF5cyBkcmF3biBoZXJlIChkZW5zaXR5LCBjZWxscywgdHJhbnNjcmlwdHMpLiAqL1xuICBvd25zKGxheWVyOiBMYXllcik6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgbCBvZiB0aGlzLmxheWVycy52YWx1ZXMoKSkgaWYgKGwgPT09IGxheWVyKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBkZXRhY2goKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaG92ZXJUaW1lcikgY2xlYXJUaW1lb3V0KHRoaXMuaG92ZXJUaW1lcik7XG4gICAgdGhpcy5ob3ZlclRpbWVyID0gbnVsbDtcbiAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICB0aGlzLmNhbWVyYU9mZj8uKCk7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSBudWxsO1xuICAgIGlmICh0aGlzLnRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgdGhpcy50b2tlbisrO1xuICAgIHRoaXMudGlsZVJldHJpZXMgPSAwO1xuICAgIGlmICh0aGlzLnZpZXdlcikge1xuICAgICAgZm9yIChjb25zdCBsYXllciBvZiB0aGlzLmxheWVycy52YWx1ZXMoKSkge1xuICAgICAgICBpZiAodGhpcy52aWV3ZXIubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGxheWVyKSkgdGhpcy52aWV3ZXIubGF5ZXJzLnJlbW92ZShsYXllcik7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMubGF5ZXJzLmNsZWFyKCk7XG4gICAgdGhpcy5rZXlzLmNsZWFyKCk7XG4gICAgdGhpcy5zZXRQb2x5Z29uc1Nob3duKGZhbHNlKTtcbiAgICB0aGlzLnZpZXdlciA9IG51bGw7XG4gIH1cblxuICAvKiogVHJ1ZSB3aGlsZSBvdXRsaW5lcyBhcmUgb24gc2NyZWVuIOKAlCB0aGUgc2VydmljZSBoaWRlcyBpdHMgZG90cyB0aGVuLiAqL1xuICBnZXQgb3V0bGluZXNTaG93bigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5wb2x5Z29uc1Nob3duO1xuICB9XG5cbiAgLyoqIERhdGFzZXQsIHZpZXcgb3Igc2VsZWN0aW9uIGNoYW5nZWQ6IHJlLXBsYW4gbm93IHJhdGhlciB0aGFuIG9uIGNhbWVyYSBpZGxlLiAqL1xuICByZWZyZXNoKCk6IHZvaWQge1xuICAgIHRoaXMuc2NoZWR1bGUoMCk7XG4gIH1cblxuICAvKiogQ2FsbGVkIHJpZ2h0IGFmdGVyIHRoZSBzZXJ2aWNlIGFkZHMgaXRzIG1hcmtlciBsYXllcjogZXZlcnl0aGluZyBnb2VzIGJhY2sgb24gdG9wLiAqL1xuICBhZnRlck9ic2VydmF0aW9ucygpOiB2b2lkIHtcbiAgICBjb25zdCB2ID0gdGhpcy52aWV3ZXI7XG4gICAgaWYgKCF2KSByZXR1cm47XG4gICAgZm9yIChjb25zdCBnIG9mIE9SREVSKSB7XG4gICAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXJzLmdldChnKTtcbiAgICAgIGlmICghbGF5ZXIpIGNvbnRpbnVlO1xuICAgICAgaWYgKHYubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGxheWVyKSkgdi5sYXllcnMucmVtb3ZlKGxheWVyKTtcbiAgICAgIHYubGF5ZXJzLmFkZChsYXllcik7XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIHBsYW5uaW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgc2NoZWR1bGUoZGVsYXkgPSBDQU1FUkFfSURMRV9NUyk6IHZvaWQge1xuICAgIGlmICh0aGlzLnRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgdGhpcy50aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgICB2b2lkIHRoaXMucGxhbigpO1xuICAgIH0sIGRlbGF5KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcGxhbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB2aWV3ZXIgPSB0aGlzLnZpZXdlcjtcbiAgICBjb25zdCBsYXRlc3QgPSB0aGlzLmhvc3QubGF0ZXN0KCk7XG4gICAgaWYgKCF2aWV3ZXIgfHwgIWxhdGVzdCkgcmV0dXJuO1xuICAgIGNvbnN0IFtkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb25dID0gbGF0ZXN0O1xuICAgIGNvbnN0IHRva2VuID0gKyt0aGlzLnRva2VuO1xuICAgIGNvbnN0IHN0YWxlID0gKCkgPT4gdG9rZW4gIT09IHRoaXMudG9rZW4gfHwgdGhpcy52aWV3ZXIgIT09IHZpZXdlcjtcbiAgICB0aGlzLnBsYW5JbmNvbXBsZXRlID0gZmFsc2U7XG5cbiAgICBpZiAoIWRhdGFzZXQpIHtcbiAgICAgIGZvciAoY29uc3QgZyBvZiBPUkRFUikgdGhpcy5kcm9wKGcpO1xuICAgICAgdGhpcy5kcm9wQ2VsbHMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW3csIGhdID0gdGhpcy5ob3N0LmNhbnZhc1NpemUoKTtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHJlY3QgPSB2aXNpYmxlRGF0YVJlY3Qodmlld2VyLmNhbWVyYS5jZW50ZXIsIHZpZXdlci5jYW1lcmEuem9vbSwgdywgaCwgcmVmKTtcbiAgICBjb25zdCBweFBlclVuaXQgPSBwaXhlbHNQZXJEYXRhVW5pdCh2aWV3ZXIuY2FtZXJhLnpvb20sIHJlZik7XG4gICAgaWYgKCFyZWN0KSByZXR1cm47XG5cbiAgICB2b2lkIHRoaXMucGxhbkVzdGltYXRlKGRhdGFzZXQsIHZpZXcsIHZpZXdlciwgdywgaCwgc3RhbGUpO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIHRoaXMucGxhbkRlbnNpdHkoZGF0YXNldCwgdmlldywgc3RhbGUpLFxuICAgICAgdGhpcy5wbGFuQ2VsbHMoZGF0YXNldCwgdmlldywgc2VsZWN0aW9uLCByZWN0LCBweFBlclVuaXQsIHN0YWxlKSxcbiAgICAgIHRoaXMucGxhblRyYW5zY3JpcHRzKGRhdGFzZXQsIHZpZXcsIHJlY3QsIHB4UGVyVW5pdCwgc3RhbGUpLFxuICAgIF0pO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgLy8gQSB0aWxlIHRoYXQgZmFpbGVkIGxlZnQgYSBob2xlIHRoZSBjYWNoZSBrZXlzIGRvIG5vdCByZWNvcmQsIHNvIHRyeSB0aGUgc2FtZSB2aWV3XG4gICAgLy8gYWdhaW4sIGJhY2tpbmcgb2ZmLCBhIGJvdW5kZWQgbnVtYmVyIG9mIHRpbWVzLlxuICAgIGlmICghdGhpcy5wbGFuSW5jb21wbGV0ZSkge1xuICAgICAgdGhpcy50aWxlUmV0cmllcyA9IDA7XG4gICAgfSBlbHNlIGlmICh0aGlzLnRpbGVSZXRyaWVzIDwgTUFYX1RJTEVfUkVUUklFUykge1xuICAgICAgdGhpcy5zY2hlZHVsZShUSUxFX1JFVFJZX01TICogMiAqKiB0aGlzLnRpbGVSZXRyaWVzKyspO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBjZWxscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIHBsYW5DZWxscyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgICByZWN0OiBEYXRhUmVjdCwgcHhQZXJVbml0OiBudW1iZXIsIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB0aWxlZCA9IGRhdGFzZXQucG9seWdvblRpbGVzO1xuICAgIGNvbnN0IHdob2xlID0gIXRpbGVkICYmIGRhdGFzZXQucG9seWdvbnMgJiYgdGhpcy5wb3J0LmdldFBvbHlnb25zO1xuICAgIGlmICghY2VsbHNTaG93bihkYXRhc2V0LCB2aWV3KSB8fCAoIXRpbGVkICYmICF3aG9sZSkpIHtcbiAgICAgIHRoaXMuZHJvcENlbGxzKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGRpYW1ldGVyID0gdHlwaWNhbENlbGxEaWFtZXRlcihkYXRhc2V0Lm9ic2VydmF0aW9ucy5yYWRpdXMpO1xuICAgIC8vIFdob2xlLWRhdGFzZXQgcmluZ3MgaGF2ZSBvbmUgbGV2ZWwgYW5kIG5vIGNvYXJzZXIgZmFsbGJhY2ssIHNvIHRoZXkgYXJlIGRyYXduIGFzXG4gICAgLy8gc29vbiBhcyBhIGNlbGwgaXMgYmlnIGVub3VnaCB0byByZWFkIGFzIGEgc2hhcGUgcmF0aGVyIHRoYW4gYSBkb3QuXG4gICAgY29uc3QgbGV2ZWwgPSB0aWxlZFxuICAgICAgPyBwb2x5Z29uTGV2ZWxGb3IocHhQZXJVbml0LCBkaWFtZXRlciwgdGlsZWQubGV2ZWxzLmxlbmd0aClcbiAgICAgIDogKHB4UGVyVW5pdCAqIGRpYW1ldGVyID49IFBPTFlHT05fTEVWRUxfTUlOX0NFTExfUFhbMl0gPyAwIDogLTEpO1xuICAgIGlmIChsZXZlbCA8IDApIHtcbiAgICAgIHRoaXMuZHJvcENlbGxzKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gR3JvdXBzIHN3aXRjaGVkIG9mZiBpbiB0aGUgbGlzdDogdGhlaXIgY2VsbHMgYXJlIGxlZnQgb3V0IG9mIHRoZSBnZW9tZXRyeS5cbiAgICBjb25zdCBoaWRkZW4gPSBhd2FpdCB0aGlzLmhpZGRlbkNvZGVzKGRhdGFzZXQsIHZpZXcpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgY29uc3QgZ2VvbWV0cnkgPSBhd2FpdCB0aGlzLmNlbGxHZW9tZXRyeShkYXRhc2V0LCB2aWV3LCByZWN0LCBsZXZlbCwgaGlkZGVuLCBzdGFsZSk7XG4gICAgaWYgKCFnZW9tZXRyeSkgcmV0dXJuO1xuICAgIGNvbnN0IHsgcmluZ3MsIG51Y2xlaSwgZ2VvbWV0cnlLZXkgfSA9IGdlb21ldHJ5O1xuXG4gICAgY29uc3QgZ2VvbWV0cnlDaGFuZ2VkID0gZ2VvbWV0cnlLZXkgIT09IHRoaXMuY2VsbEdlb21ldHJ5S2V5O1xuICAgIGNvbnN0IHN0eWxlS2V5ID0gW1xuICAgICAgZ2VvbWV0cnlLZXksIHZpZXcuY2VsbENvbG9yTW9kZSwgdmlldy5jZWxsQ29sb3JHZW5lLCB2aWV3LmNlbGxTaW5nbGVDb2xvcixcbiAgICAgIHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpLFxuICAgICAgdGhpcy5zZWxlY3Rpb25SZXYoc2VsZWN0aW9uKSwgdmlldy5sb2dTY2FsZSwgdmlldy5wZXJjZW50aWxlQ2xpcC5qb2luKCksXG4gICAgICBKU09OLnN0cmluZ2lmeSh2aWV3LmNvbnRpbnVvdXNDb2xvcm1hcCksIHZpZXcuY2VsbERyYXcsIHZpZXcuY2VsbE9wYWNpdHksXG4gICAgXS5qb2luKCd8Jyk7XG4gICAgY29uc3QgcHJlc2VudCA9IFsnY2VsbEZpbGwnLCAnY2VsbE91dGxpbmUnLCAnbnVjbGV1c091dGxpbmUnXS5zb21lKChnKSA9PiB7XG4gICAgICBjb25zdCBsID0gdGhpcy5sYXllcnMuZ2V0KGcgYXMgR3JvdXApO1xuICAgICAgcmV0dXJuIGwgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhsKTtcbiAgICB9KTtcbiAgICBpZiAoIWdlb21ldHJ5Q2hhbmdlZCAmJiBzdHlsZUtleSA9PT0gdGhpcy5jZWxsU3R5bGVLZXkgJiYgcHJlc2VudCkge1xuICAgICAgdGhpcy5zZXRQb2x5Z29uc1Nob3duKHRydWUpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjb2xvcnMgPSBhd2FpdCB0aGlzLmNlbGxDb2xvcnMoZGF0YXNldCwgdmlldywgc2VsZWN0aW9uLCByaW5ncy5vYnNlcnZhdGlvbik7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcblxuICAgIHRoaXMuY3VycmVudFJpbmdzID0gcmluZ3M7XG4gICAgdGhpcy5jdXJyZW50TnVjbGVpID0gbnVjbGVpO1xuICAgIC8vIEEgZ2VvbWV0cnkgbWlzc2luZyBhIGZhaWxlZCB0aWxlIGlzIGRyYXduIGJ1dCBub3QgcmVtZW1iZXJlZCwgc28gdGhlIHJldHJ5IHJlZmV0Y2hlcyBpdC5cbiAgICB0aGlzLmNlbGxHZW9tZXRyeUtleSA9IHRoaXMucGxhbkluY29tcGxldGUgPyBudWxsIDogZ2VvbWV0cnlLZXk7XG4gICAgdGhpcy5jZWxsU3R5bGVLZXkgPSBzdHlsZUtleTtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IGNvbW1vbiA9IHsgc2NhbGU6IHJlZj8uc2NhbGUgPz8gWzEsIDFdLCB0cmFuc2xhdGU6IHJlZj8udHJhbnNsYXRlID8/IFswLCAwXSB9IGFzIGNvbnN0O1xuICAgIGNvbnN0IGZpbGwgPSB2aWV3LmNlbGxEcmF3ICE9PSAnb3V0bGluZSc7XG4gICAgY29uc3Qgb3V0bGluZSA9IHZpZXcuY2VsbERyYXcgIT09ICdmaWxsJztcblxuICAgIHRoaXMudXBzZXJ0U2hhcGVzKCdjZWxsRmlsbCcsIGZpbGwsIGdlb21ldHJ5Q2hhbmdlZCwgcmluZ3MsIHtcbiAgICAgIG5hbWU6ICdjZWxscycsIGRyYXc6ICdmaWxsJywgb3BhY2l0eTogdmlldy5jZWxsT3BhY2l0eSwgLi4uY29sb3JzLCAuLi5jb21tb24sXG4gICAgfSk7XG4gICAgdGhpcy51cHNlcnRTaGFwZXMoJ2NlbGxPdXRsaW5lJywgb3V0bGluZSwgZ2VvbWV0cnlDaGFuZ2VkLCByaW5ncywgZmlsbFxuICAgICAgLy8gT3ZlciBhIGZpbGwsIGEgZGFyayBvdXRsaW5lIHNlcGFyYXRlcyBuZWlnaGJvdXJzIG9mIHRoZSBzYW1lIHR5cGUuXG4gICAgICA/IHsgbmFtZTogJ2NlbGwgb3V0bGluZXMnLCBkcmF3OiAnb3V0bGluZScsIGNvbG9yOiBbMC4wOCwgMC4wOCwgMC4xLCAxXSwgb3BhY2l0eTogMC43LCAuLi5jb21tb24gfVxuICAgICAgOiB7IG5hbWU6ICdjZWxsIG91dGxpbmVzJywgZHJhdzogJ291dGxpbmUnLCBvcGFjaXR5OiAxLCAuLi5jb2xvcnMsIC4uLmNvbW1vbiB9KTtcbiAgICAvLyBcIkJvdGhcIjogbnVjbGVpIG91dGxpbmVkIG92ZXIgdGhlIGNlbGxzLCBsaWdodCBzbyB0aGV5IHJlYWQgYWdhaW5zdCBhbnkgZmlsbC5cbiAgICBpZiAobnVjbGVpKSB7XG4gICAgICB0aGlzLnVwc2VydFNoYXBlcygnbnVjbGV1c091dGxpbmUnLCB0cnVlLCBnZW9tZXRyeUNoYW5nZWQsIG51Y2xlaSwge1xuICAgICAgICBuYW1lOiAnbnVjbGV1cyBvdXRsaW5lcycsIGRyYXc6ICdvdXRsaW5lJywgY29sb3I6IFswLjk1LCAwLjk1LCAwLjk4LCAxXSwgb3BhY2l0eTogMC44LCAuLi5jb21tb24sXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kcm9wKCdudWNsZXVzT3V0bGluZScpO1xuICAgIH1cbiAgICB0aGlzLnNldFBvbHlnb25zU2hvd24odHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIHNlbGVjdGlvblJldihzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrKTogbnVtYmVyIHtcbiAgICBpZiAoc2VsZWN0aW9uICE9PSB0aGlzLmxhc3RTZWxlY3Rpb24pIHtcbiAgICAgIHRoaXMubGFzdFNlbGVjdGlvbiA9IHNlbGVjdGlvbjtcbiAgICAgIHRoaXMuc2VsZWN0aW9uUmV2aXNpb24rKztcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0aW9uUmV2aXNpb247XG4gIH1cblxuICAvKiogUGVyLXNoYXBlIHZhbHVlcyArIGNvbG9ybWFwIGZvciB0aGUgcmluZ3MnIG93bmVycy4gKi9cbiAgLyoqXG4gICAqIFBlci1zaGFwZSB2YWx1ZXMgKyBjb2xvcm1hcCBmb3IgdGhlIHJpbmdzJyBvd25lcnMsIGJ5IHRoZSB2aWV3J3MgY2VsbC1jb2xvdXIgbW9kZVxuICAgKiAoWGVuaXVtIEV4cGxvcmVyJ3MgXCJDZWxsIENvbG9yXCIpLiBBIHNlbGVjdGlvbiBtdXRlcyB3aGF0IGl0IGxlYXZlcyBvdXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNlbGxDb2xvcnMoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2ssXG4gICAgb3duZXJzOiBVaW50MzJBcnJheSxcbiAgKTogUHJvbWlzZTx7IHZhbHVlcz86IEZsb2F0MzJBcnJheTsgY29sb3JtYXA/OiBDb2xvcm1hcDsgY29udHJhc3RMaW1pdHM/OiBbbnVtYmVyLCBudW1iZXJdOyBjb2xvcj86IFJHQkEgfT4ge1xuICAgIGNvbnN0IG11dGVkID0gc2VsZWN0aW9uLmNvdW50ID4gMCA/IHNlbGVjdGlvbi5tYXNrIDogbnVsbDtcbiAgICBjb25zdCBtb2RlID0gdmlldy5jZWxsQ29sb3JNb2RlO1xuXG4gICAgaWYgKG1vZGUgPT09ICdzaW5nbGUnKSB7XG4gICAgICBjb25zdCBbciwgZywgYl0gPSBwYXJzZUhleCh2aWV3LmNlbGxTaW5nbGVDb2xvcik7XG4gICAgICByZXR1cm4geyBjb2xvcjogW3IgLyAyNTUsIGcgLyAyNTUsIGIgLyAyNTUsIDFdIH07XG4gICAgfVxuXG4gICAgY29uc3QgY29udGludW91cyA9IGFzeW5jIChyYXc6IEZsb2F0MzJBcnJheSwgbG9nOiBib29sZWFuKSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KG93bmVycy5sZW5ndGgpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvd25lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgdiA9IHJhd1tvd25lcnNbaV1dID8/IE5hTjtcbiAgICAgICAgdmFsdWVzW2ldID0gbG9nID8gTWF0aC5sb2cxcChNYXRoLm1heCgwLCB2KSkgOiB2O1xuICAgICAgfVxuICAgICAgY29uc3QgW2xvLCBoaV0gPSBjb250cmFzdFdpbmRvdyhcbiAgICAgICAgbG9nID8gcmF3Lm1hcCgodikgPT4gTWF0aC5sb2cxcChNYXRoLm1heCgwLCB2KSkpIDogcmF3LFxuICAgICAgICB2aWV3LnBlcmNlbnRpbGVDbGlwWzBdLCB2aWV3LnBlcmNlbnRpbGVDbGlwWzFdLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlcyxcbiAgICAgICAgY29sb3JtYXA6IGNvbG9ybWFwRnJvbUx1dCgnc3BhdGlhbC1jb250aW51b3VzJywgdGhpcy5ob3N0LmNvbnRpbnVvdXNMdXQodmlldykpLFxuICAgICAgICBjb250cmFzdExpbWl0czogW2xvLCBoaV0gYXMgW251bWJlciwgbnVtYmVyXSxcbiAgICAgIH07XG4gICAgfTtcbiAgICBpZiAobW9kZSA9PT0gJ2dlbmUnICYmIHZpZXcuY2VsbENvbG9yR2VuZSkge1xuICAgICAgcmV0dXJuIGNvbnRpbnVvdXMoYXdhaXQgdGhpcy5wb3J0LmdldEZlYXR1cmVWZWN0b3Iodmlldy5jZWxsQ29sb3JHZW5lKSwgdHJ1ZSk7XG4gICAgfVxuICAgIGlmIChtb2RlID09PSAndHJhbnNjcmlwdERlbnNpdHknICYmIGRhdGFzZXQuY29sdW1ucy5zb21lKChjKSA9PiBjLm5hbWUgPT09ICd0cmFuc2NyaXB0X2RlbnNpdHknKSkge1xuICAgICAgY29uc3QgY29sdW1uID0gYXdhaXQgdGhpcy5wb3J0LmdldENvbHVtbigndHJhbnNjcmlwdF9kZW5zaXR5Jyk7XG4gICAgICBpZiAoIWlzQ2F0ZWdvcmljYWxDb2x1bW4oY29sdW1uKSkgcmV0dXJuIGNvbnRpbnVvdXMoY29sdW1uLnZhbHVlcywgZmFsc2UpO1xuICAgIH1cblxuICAgIGNvbnN0IG5hbWUgPSBtb2RlID09PSAnc2VnbWVudGF0aW9uJyAmJiBkYXRhc2V0LmNvbHVtbnMuc29tZSgoYykgPT4gYy5uYW1lID09PSAnc2VnbWVudGF0aW9uX21ldGhvZCcpXG4gICAgICA/ICdzZWdtZW50YXRpb25fbWV0aG9kJ1xuICAgICAgOiB0aGlzLmNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0LCB2aWV3KTtcbiAgICBjb25zdCBjb2RlcyA9IG5hbWUgPyBhd2FpdCB0aGlzLmNhdGVnb3JpY2FsQ29kZXMobmFtZSkgOiBudWxsO1xuICAgIGNvbnN0IHsgY29sb3JtYXAsIHZhbHVlT2YgfSA9IHRoaXMuY2F0ZWdvcmljYWxDb2xvcm1hcChjb2Rlcz8ubWV0YSA/PyBudWxsKTtcbiAgICBjb25zdCB2YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KG93bmVycy5sZW5ndGgpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb3duZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvID0gb3duZXJzW2ldO1xuICAgICAgY29uc3QgY29kZSA9ICFjb2RlcyB8fCAobXV0ZWQgJiYgIW11dGVkW29dKSA/IC0xIDogY29kZXMuY29kZXNbb107XG4gICAgICB2YWx1ZXNbaV0gPSB2YWx1ZU9mKGNvZGUgPT09IE5PX0NBVEVHT1JZID8gLTEgOiBjb2RlKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgdmFsdWVzLCBjb2xvcm1hcCwgY29udHJhc3RMaW1pdHM6IFswLCAxXSB9O1xuICB9XG5cbiAgLyoqIENvZGVzIG9mIHRoZSBncm91cCBjb2x1bW4gdGhhdCBhcmUgc3dpdGNoZWQgb2ZmLCBvciBudWxsIHdoZW4gbm9uZSBhcmUuICovXG4gIHByaXZhdGUgYXN5bmMgaGlkZGVuQ29kZXMoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICk6IFByb21pc2U8eyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbD4ge1xuICAgIGlmICghdmlldy5oaWRkZW5Hcm91cHMubGVuZ3RoKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBuYW1lID0gdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyk7XG4gICAgY29uc3QgY29sID0gbmFtZSA/IGF3YWl0IHRoaXMuY2F0ZWdvcmljYWxDb2RlcyhuYW1lKSA6IG51bGw7XG4gICAgaWYgKCFjb2wgfHwgY29sLm1ldGEua2luZCAhPT0gJ2NhdGVnb3JpY2FsJykgcmV0dXJuIG51bGw7XG4gICAgY29uc3Qgb2ZmID0gbmV3IFNldCh2aWV3LmhpZGRlbkdyb3Vwcyk7XG4gICAgY29uc3QgaGlkZGVuID0gVWludDhBcnJheS5mcm9tKGNvbC5tZXRhLmNhdGVnb3JpZXMsIChjKSA9PiAob2ZmLmhhcyhjKSA/IDEgOiAwKSk7XG4gICAgcmV0dXJuIHsgY29kZXM6IGNvbC5jb2RlcywgaGlkZGVuIH07XG4gIH1cblxuICBwcml2YXRlIGNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiBjZWxsVHlwZUNvbHVtbkZvcihkYXRhc2V0LCB2aWV3KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY2F0ZWdvcmljYWxDb2RlcyhuYW1lOiBzdHJpbmcpOlxuICAgIFByb21pc2U8eyBjb2RlczogVWludDE2QXJyYXk7IG1ldGE6IFNwYXRpYWxDb2x1bW5bJ21ldGEnXSB9IHwgbnVsbD4ge1xuICAgIGNvbnN0IGNvbHVtbiA9IGF3YWl0IHRoaXMucG9ydC5nZXRDb2x1bW4obmFtZSk7XG4gICAgcmV0dXJuIGlzQ2F0ZWdvcmljYWxDb2x1bW4oY29sdW1uKSA/IHsgY29kZXM6IGNvbHVtbi5jb2RlcywgbWV0YTogY29sdW1uLm1ldGEgfSA6IG51bGw7XG4gIH1cblxuICBwcml2YXRlIGNhdGVnb3JpY2FsQ29sb3JtYXAobWV0YTogU3BhdGlhbENvbHVtblsnbWV0YSddIHwgbnVsbCk6XG4gICAgeyBjb2xvcm1hcDogQ29sb3JtYXA7IHZhbHVlT2Y6IChjb2RlOiBudW1iZXIpID0+IG51bWJlcjsgcmdiOiBSZ2JbXSB9IHtcbiAgICBjb25zdCBoZXggPSBtZXRhICYmIG1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJ1xuICAgICAgPyByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMobWV0YSlcbiAgICAgIDogW0RFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURVswXV07XG4gICAgY29uc3QgcmdiID0gaGV4Lm1hcChwYXJzZUhleCk7XG4gICAgY29uc3QgeyBzdG9wcywgdmFsdWVPZiB9ID0gZGlzY3JldGVDb2xvcm1hcFN0b3BzKHJnYiwgTUlTU0lOR19DT0xPUik7XG4gICAgcmV0dXJuIHsgY29sb3JtYXA6IG5ldyBDb2xvcm1hcCgnc3BhdGlhbC1jYXRlZ29yaWVzJywgc3RvcHMpLCB2YWx1ZU9mLCByZ2IgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY2VsbCByaW5ncyAoYW5kLCBmb3IgXCJib3RoXCIsIHRoZSBudWNsZXVzIHJpbmdzKSBjb3ZlcmluZyBgcmVjdGAgYXQgYGxldmVsYCwgbWludXNcbiAgICogdGhlIGhpZGRlbiBncm91cHMg4oCUIHJldXNlZCB3aGVuIG5vdGhpbmcgdGhhdCBkZWNpZGVzIHRoZW0gY2hhbmdlZC4gTnVsbCB3aGVuIHRoZVxuICAgKiB2aWV3IHdlbnQgc3RhbGUgb3IgdGhlIGRhdGFzZXQgaGFzIG5vIHNldCB0byBkcmF3LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjZWxsR2VvbWV0cnkoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHJlY3Q6IERhdGFSZWN0LCBsZXZlbDogbnVtYmVyLFxuICAgIGhpZGRlbjogeyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbCwgc3RhbGU6ICgpID0+IGJvb2xlYW4sXG4gICk6IFByb21pc2U8eyByaW5nczogU3BhdGlhbFBvbHlnb25UaWxlOyBudWNsZWk6IFNwYXRpYWxQb2x5Z29uVGlsZSB8IG51bGw7IGdlb21ldHJ5S2V5OiBzdHJpbmcgfSB8IG51bGw+IHtcbiAgICBjb25zdCB0aWxlZCA9IGRhdGFzZXQucG9seWdvblRpbGVzO1xuICAgIGNvbnN0IGhpZGRlbktleSA9IHZpZXcuaGlkZGVuR3JvdXBzLmpvaW4oJ1xcdTAwMDEnKTtcbiAgICBsZXQgcmluZ3M6IFNwYXRpYWxQb2x5Z29uVGlsZTtcbiAgICBsZXQgbnVjbGVpOiBTcGF0aWFsUG9seWdvblRpbGUgfCBudWxsID0gbnVsbDtcbiAgICBsZXQgZ2VvbWV0cnlLZXk6IHN0cmluZztcbiAgICBpZiAodGlsZWQpIHtcbiAgICAgIGNvbnN0IGJvdGggPSB2aWV3LmNlbGxTZXQgPT09ICdib3RoJztcbiAgICAgIGNvbnN0IHNldCA9ICFib3RoICYmIHZpZXcuY2VsbFNldCAmJiB0aWxlZC5zZXRzLnNvbWUoKHMpID0+IHMubmFtZSA9PT0gdmlldy5jZWxsU2V0KVxuICAgICAgICA/IHZpZXcuY2VsbFNldCA6ICh0aWxlZC5kZWZhdWx0U2V0ID8/IHRpbGVkLnNldHNbMF0/Lm5hbWUpO1xuICAgICAgaWYgKCFzZXQpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgbnVjbGV1c1NldCA9IGJvdGggPyB0aWxlZC5zZXRzLmZpbmQoKHMpID0+IHMubmFtZSAhPT0gc2V0KT8ubmFtZSA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IGtleXMgPSB0aWxlc0luUmVjdChyZWN0LCBsZXZlbCwgdGlsZWQubGV2ZWxzLCB0aWxlZC5ib3VuZHMsIE1BWF9DRUxMX1RJTEVTKTtcbiAgICAgIGdlb21ldHJ5S2V5ID0gYCR7ZGF0YXNldC5pZH18JHtzZXR9fCR7bnVjbGV1c1NldCA/PyAnJ318JHtoaWRkZW5LZXl9fCR7a2V5cy5tYXAodGlsZUlkKS5qb2luKCcsJyl9YDtcbiAgICAgIGlmIChnZW9tZXRyeUtleSA9PT0gdGhpcy5jZWxsR2VvbWV0cnlLZXkgJiYgdGhpcy5jdXJyZW50UmluZ3MpIHtcbiAgICAgICAgcmluZ3MgPSB0aGlzLmN1cnJlbnRSaW5ncztcbiAgICAgICAgbnVjbGVpID0gdGhpcy5jdXJyZW50TnVjbGVpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgW3RpbGVzLCBudWNsZXVzVGlsZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIHRoaXMuZmV0Y2hBbGwoa2V5cywgKGspID0+IHRoaXMucG9ydC5nZXRQb2x5Z29uVGlsZSEoc2V0LCBrLmxldmVsLCBrLmd4LCBrLmd5KSksXG4gICAgICAgICAgbnVjbGV1c1NldFxuICAgICAgICAgICAgPyB0aGlzLmZldGNoQWxsKGtleXMsIChrKSA9PiB0aGlzLnBvcnQuZ2V0UG9seWdvblRpbGUhKG51Y2xldXNTZXQsIGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKVxuICAgICAgICAgICAgOiBQcm9taXNlLnJlc29sdmUobnVsbCksXG4gICAgICAgIF0pO1xuICAgICAgICBpZiAoc3RhbGUoKSkgcmV0dXJuIG51bGw7XG4gICAgICAgIHJpbmdzID0gZmlsdGVyUmluZ3MobWVyZ2VQb2x5Z29uVGlsZXModGlsZXMpLCBoaWRkZW4pO1xuICAgICAgICBudWNsZWkgPSBudWNsZXVzVGlsZXMgPyBmaWx0ZXJSaW5ncyhtZXJnZVBvbHlnb25UaWxlcyhudWNsZXVzVGlsZXMpLCBoaWRkZW4pIDogbnVsbDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZ2VvbWV0cnlLZXkgPSBgJHtkYXRhc2V0LmlkfXx3aG9sZXwke2hpZGRlbktleX1gO1xuICAgICAgaWYgKGdlb21ldHJ5S2V5ID09PSB0aGlzLmNlbGxHZW9tZXRyeUtleSAmJiB0aGlzLmN1cnJlbnRSaW5ncykge1xuICAgICAgICByaW5ncyA9IHRoaXMuY3VycmVudFJpbmdzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcG9seXM6IFNwYXRpYWxQb2x5Z29ucyA9IGF3YWl0IHRoaXMucG9ydC5nZXRQb2x5Z29ucyEoKTtcbiAgICAgICAgaWYgKHN0YWxlKCkpIHJldHVybiBudWxsO1xuICAgICAgICAvLyBXaG9sZS1kYXRhc2V0IHJpbmdzIGFyZSBpbmRleC1hbGlnbmVkIHdpdGggdGhlIG9ic2VydmF0aW9ucy5cbiAgICAgICAgcmluZ3MgPSBmaWx0ZXJSaW5ncyhcbiAgICAgICAgICB7IC4uLnBvbHlzLCBvYnNlcnZhdGlvbjogVWludDMyQXJyYXkuZnJvbSh7IGxlbmd0aDogcG9seXMuY291bnQgfSwgKF92LCBpKSA9PiBpKSB9LCBoaWRkZW4sXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7IHJpbmdzLCBudWNsZWksIGdlb21ldHJ5S2V5IH07XG4gIH1cblxuICAvLyDilIDilIAgdHJhbnNjcmlwdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBhc3luYyBwbGFuVHJhbnNjcmlwdHMoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHJlY3Q6IERhdGFSZWN0LCBweFBlclVuaXQ6IG51bWJlcixcbiAgICBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbW9kZSA9IHZpZXcudHJhbnNjcmlwdE1vZGU7XG4gICAgY29uc3Qgam9iID0gKG1vZGUgPT09ICdjaXJjbGVzJyB8fCBtb2RlID09PSAnZ2x5cGhzJykgJiYgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRUaWxlXG4gICAgICA/ICh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1xuICAgICAgICA/IHRoaXMuYWxsR2VuZXNKb2IoZGF0YXNldCwgdmlldywgcmVjdCwgcHhQZXJVbml0KVxuICAgICAgICA6IHRoaXMuZ2VuZUpvYihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQpKVxuICAgICAgOiBudWxsO1xuICAgIGlmICgham9iKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRzJyk7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gTWFya2VyIHNpemVzIGZvbGxvdyB0aGUgem9vbSwgc28gdGhlIHpvb20gaXMgcGFydCBvZiB0aGUga2V5OyBhIHBhbiB0aGF0IGtlZXBzXG4gICAgLy8gdGhlIHNhbWUgdGlsZXMgb24gc2NyZWVuIGNoYW5nZXMgbm90aGluZy5cbiAgICBjb25zdCBwbGFuS2V5ID0gW1xuICAgICAgZGF0YXNldC5pZCwgbW9kZSwgam9iLmtleSwgdmlldy50cmFuc2NyaXB0Q29sb3JCeSwgdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyksXG4gICAgICB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgdmlldy50cmFuc2NyaXB0T3BhY2l0eSwgSlNPTi5zdHJpbmdpZnkodmlldy50cmFuc2NyaXB0R2x5cGhzKSxcbiAgICAgIHB4UGVyVW5pdC50b1ByZWNpc2lvbig0KSwgdmlldy5oaWRkZW5Hcm91cHMuam9pbignXFx1MDAwMScpLCB2aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcy5qb2luKCcsJyksXG4gICAgICBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lQ29sb3JzKSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5sYXllcnMuZ2V0KCd0cmFuc2NyaXB0cycpO1xuICAgIGlmIChwbGFuS2V5ID09PSB0aGlzLmtleXMuZ2V0KCd0cmFuc2NyaXB0cycpICYmIGN1cnJlbnQgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhjdXJyZW50KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCBqb2IubG9hZCgpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgY29uc3QgaGlkZGVuID0gYXdhaXQgdGhpcy5oaWRkZW5Db2RlcyhkYXRhc2V0LCB2aWV3KTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuICAgIGNvbnN0IHsgbWVyZ2VkLCBweCB9ID0gZmlsdGVyVHJhbnNjcmlwdHMobG9hZGVkLm1lcmdlZCwgbG9hZGVkLnB4LCBoaWRkZW4sXG4gICAgICAobG9hZGVkLmtpbmQgPz8gam9iLmtpbmQpID09PSAnZ2VuZXMnID8gaGlkZGVuR2VuZVNsb3RzKHZpZXcpIDogbnVsbCk7XG4gICAgLy8gQSBiaW4gb2YgdGhlIGFsbC1nZW5lIHB5cmFtaWQgbWl4ZXMgZ2VuZXMgYW5kIGNhcnJpZXMgbm9uZSwgc28gaXQgY2Fubm90IGJlIGNvbG91cmVkXG4gICAgLy8gYnkgZ2VuZTogY29sb3VyIGl0IGJ5IGl0cyBkb21pbmFudCBjZWxsJ3MgdHlwZSB1bnRpbCBpbmRpdmlkdWFsIHRyYW5zY3JpcHRzIHNob3cuXG4gICAgY29uc3Qga2luZCA9IGxvYWRlZC5raW5kID8/IGpvYi5raW5kO1xuICAgIGNvbnN0IGNvbG9yVmlldyA9IGtpbmQgPT09ICdiaW5zJyAmJiB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ID09PSAnZ2VuZSdcbiAgICAgID8geyAuLi52aWV3LCB0cmFuc2NyaXB0Q29sb3JCeTogJ2NlbGxUeXBlJyBhcyBjb25zdCB9IDogdmlldztcbiAgICBjb25zdCBmYWNlcyA9IGF3YWl0IHRoaXMudHJhbnNjcmlwdENvbG9ycyhkYXRhc2V0LCBjb2xvclZpZXcsIG1lcmdlZCk7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcblxuICAgIGlmICh0aGlzLnBsYW5JbmNvbXBsZXRlKSB0aGlzLmtleXMuZGVsZXRlKCd0cmFuc2NyaXB0cycpO1xuICAgIGVsc2UgdGhpcy5rZXlzLnNldCgndHJhbnNjcmlwdHMnLCBwbGFuS2V5KTtcbiAgICBjb25zdCBkaWFtID0gcHgubWFwKChkKSA9PiBkIC8gcHhQZXJVbml0KTtcbiAgICB0aGlzLmRyYXduID0ge1xuICAgICAga2luZDogbG9hZGVkLmtpbmQgPz8gam9iLmtpbmQsIGJpbjogbG9hZGVkLmtpbmQgPyBsb2FkZWQuYmluIDogam9iLmJpbixcbiAgICAgIG1lcmdlZCwgcmFkaXVzOiBkaWFtLm1hcCgoZCkgPT4gZCAvIDIpLFxuICAgICAgZ2VuZXM6IFsuLi52aWV3LnRyYW5zY3JpcHRHZW5lc10sIHJlZjogZGF0YXNldC5pbWFnZVJlZiA/PyBudWxsLCBncmlkOiBudWxsLFxuICAgIH07XG4gICAgdGhpcy5ob3ZlckNhY2hlLmNsZWFyKCk7XG4gICAgY29uc3QgdHlwZUNvbHVtbiA9IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgIHRoaXMuaG92ZXJUeXBlcyA9IHR5cGVDb2x1bW4gPyBhd2FpdCB0aGlzLmNhdGVnb3JpY2FsQ29kZXModHlwZUNvbHVtbikuY2F0Y2goKCkgPT4gbnVsbCkgOiBudWxsO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgY29uc3QgcmVmID0gZGF0YXNldC5pbWFnZVJlZjtcbiAgICBjb25zdCBwbGFjZTogUGxhY2VtZW50ID0geyBzY2FsZTogcmVmPy5zY2FsZSA/PyBbMSwgMV0sIHRyYW5zbGF0ZTogcmVmPy50cmFuc2xhdGUgPz8gWzAsIDBdIH07XG4gICAgaWYgKG1vZGUgPT09ICdjaXJjbGVzJykge1xuICAgICAgdGhpcy5kcm9wKCd0cmFuc2NyaXB0T3V0bGluZScpO1xuICAgICAgdGhpcy5kcmF3VHJhbnNjcmlwdENpcmNsZXMobWVyZ2VkLCBkaWFtLCBmYWNlcy5yZ2JhLCB2aWV3LCBwbGFjZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZHJhd1RyYW5zY3JpcHRHbHlwaHMobWVyZ2VkLCBkaWFtLCBmYWNlcywgdmlldywgcGxhY2UpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBPbmUgc2l6ZWQgY2lyY2xlIHBlciBlbnRyeSwgdGhlIHNpemUgc2F5aW5nIGhvdyBtYW55IHRyYW5zY3JpcHRzIGl0IHN0YW5kcyBmb3IuICovXG4gIHByaXZhdGUgZHJhd1RyYW5zY3JpcHRDaXJjbGVzKFxuICAgIG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlLCBkaWFtOiBGbG9hdDMyQXJyYXksIHJnYmE6IFJHQkFbXSwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICB7IHNjYWxlLCB0cmFuc2xhdGUgfTogUGxhY2VtZW50LFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KG1lcmdlZC5jb3VudCAqIDIpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbWVyZ2VkLmNvdW50OyBpKyspIHtcbiAgICAgIHBvc2l0aW9uc1syICogaV0gPSBtZXJnZWQueFtpXTtcbiAgICAgIHBvc2l0aW9uc1syICogaSArIDFdID0gbWVyZ2VkLnlbaV07XG4gICAgfVxuICAgIGNvbnN0IGxheWVyID0gdGhpcy52aWV3ZXIhLmFkZFBvaW50cyhwb3NpdGlvbnMsIHtcbiAgICAgIG5hbWU6ICd0cmFuc2NyaXB0cycsXG4gICAgICBzaXplOiBkaWFtLFxuICAgICAgZmFjZUNvbG9yOiByZ2JhLFxuICAgICAgLy8gQSBkYXJrIHJpbTogYSB0cmFuc2NyaXB0IGNvbG91cmVkIGJ5IGl0cyBjZWxsJ3MgdHlwZSBpcyBvdGhlcndpc2UgdGhlIHNhbWVcbiAgICAgIC8vIGNvbG91ciBhcyB0aGUgY2VsbCBmaWxsIGl0IHNpdHMgb24sIGFuZCB2YW5pc2hlcyBpbnRvIGl0LlxuICAgICAgYm9yZGVyQ29sb3I6IFswLjA0LCAwLjA0LCAwLjA1LCAwLjldLFxuICAgICAgYm9yZGVyV2lkdGg6IDAuMTggKiBtZWRpYW4oZGlhbSksXG4gICAgICBvcGFjaXR5OiB2aWV3LnRyYW5zY3JpcHRPcGFjaXR5LFxuICAgICAgc2NhbGUsXG4gICAgICB0cmFuc2xhdGUsXG4gICAgfSk7XG4gICAgdGhpcy5yZXBsYWNlKCd0cmFuc2NyaXB0cycsIGxheWVyKTtcbiAgfVxuXG4gIHByaXZhdGUgZHJhd1RyYW5zY3JpcHRHbHlwaHMoXG4gICAgbWVyZ2VkOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsIGRpYW06IEZsb2F0MzJBcnJheSwgZmFjZXM6IFRyYW5zY3JpcHRGYWNlcywgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICB7IHNjYWxlLCB0cmFuc2xhdGUgfTogUGxhY2VtZW50LFxuICApOiB2b2lkIHtcbiAgICAvLyBHbHlwaHM6IGVhY2ggZW50cnkgYmVjb21lcyBpdHMgZ2VuZSdzIGljb24gcG9seWdvbiwgZmlsbGVkIHRocm91Z2ggYSBkaXNjcmV0ZVxuICAgIC8vIGNvbG9ybWFwIGFuZCBvdXRsaW5lZCBkYXJrIHNvIHNtYWxsIGljb25zIHN0YXkgcmVhZGFibGUgb3ZlciB0aGUgdGlzc3VlLiBXaXRoIGV2ZXJ5XG4gICAgLy8gZ2VuZSBkcmF3biB0aGVyZSBpcyBvbmUgaWNvbiBmb3IgYWxsIG9mIHRoZW0g4oCUIDE4LDAwMCBzaGFwZXMgd291bGQgc2F5IG5vdGhpbmcuXG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lcztcbiAgICBjb25zdCBnbHlwaEZvciA9IChzbG90OiBudW1iZXIpOiBUcmFuc2NyaXB0R2x5cGggPT5cbiAgICAgICh2aWV3LnRyYW5zY3JpcHRHbHlwaHNbZ2VuZXNbc2xvdF1dIGFzIFRyYW5zY3JpcHRHbHlwaCB8IHVuZGVmaW5lZCkgPz8gZGVmYXVsdEdseXBoRm9yKHNsb3QpO1xuICAgIGNvbnN0IHNpbmdsZSA9IHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXG4gICAgICA/IGdseXBoT3V0bGluZSgodmlldy50cmFuc2NyaXB0R2x5cGhzW0FMTF9HRU5FU10gYXMgVHJhbnNjcmlwdEdseXBoIHwgdW5kZWZpbmVkKSA/PyAnY2lyY2xlJylcbiAgICAgIDogbnVsbDtcbiAgICBjb25zdCBvdXRsaW5lcyA9IHNpbmdsZSA/IFtdIDogZ2VuZXMubWFwKChfZywgc2xvdCkgPT4gZ2x5cGhPdXRsaW5lKGdseXBoRm9yKHNsb3QpKSk7XG4gICAgY29uc3QgcmFkaXVzID0gZGlhbS5tYXAoKGQpID0+IGQgLyAyKTtcbiAgICBjb25zdCB7IGNvb3Jkcywgb2Zmc2V0cyB9ID0gZ2x5cGhSaW5ncyhcbiAgICAgIG1lcmdlZC54LCBtZXJnZWQueSwgcmFkaXVzLCAoaSkgPT4gc2luZ2xlID8/IG91dGxpbmVzW21lcmdlZC5nZW5lW2ldXSxcbiAgICApO1xuICAgIGNvbnN0IGZpbGwgPSB0aGlzLnZpZXdlciEuYWRkU2hhcGVzKGNvb3Jkcywgb2Zmc2V0cywge1xuICAgICAgbmFtZTogJ3RyYW5zY3JpcHRzJyxcbiAgICAgIGRyYXc6ICdmaWxsJyxcbiAgICAgIHZhbHVlczogZmFjZXMudmFsdWVzLFxuICAgICAgY29sb3JtYXA6IGZhY2VzLmNvbG9ybWFwLFxuICAgICAgY29udHJhc3RMaW1pdHM6IFswLCAxXSxcbiAgICAgIG9wYWNpdHk6IHZpZXcudHJhbnNjcmlwdE9wYWNpdHksXG4gICAgICBzY2FsZSxcbiAgICAgIHRyYW5zbGF0ZSxcbiAgICB9KTtcbiAgICB0aGlzLnJlcGxhY2UoJ3RyYW5zY3JpcHRzJywgZmlsbCk7XG4gICAgY29uc3QgZWRnZSA9IHRoaXMudmlld2VyIS5hZGRTaGFwZXMoY29vcmRzLCBvZmZzZXRzLCB7XG4gICAgICBuYW1lOiAndHJhbnNjcmlwdCBvdXRsaW5lcycsXG4gICAgICBkcmF3OiAnb3V0bGluZScsXG4gICAgICBjb2xvcjogWzAuMDUsIDAuMDUsIDAuMDUsIDFdLFxuICAgICAgb3BhY2l0eTogTWF0aC5taW4oMSwgdmlldy50cmFuc2NyaXB0T3BhY2l0eSArIDAuMSksXG4gICAgICBzY2FsZSxcbiAgICAgIHRyYW5zbGF0ZSxcbiAgICB9KTtcbiAgICB0aGlzLnJlcGxhY2UoJ3RyYW5zY3JpcHRPdXRsaW5lJywgZWRnZSk7XG4gIH1cblxuICAvLyDilIDilIAgaG92ZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBkcmF3bjogRHJhd25UcmFuc2NyaXB0cyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGhvdmVyVHlwZXM6IHsgY29kZXM6IFVpbnQxNkFycmF5OyBtZXRhOiBTcGF0aWFsQ29sdW1uWydtZXRhJ10gfSB8IG51bGwgPSBudWxsO1xuICAvKiogRGV0YWlscyBhbHJlYWR5IGZldGNoZWQsIGJ5IGhvdmVyZWQgZW50cnkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaG92ZXJDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgcHJpdmF0ZSBob3ZlcktleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgaG92ZXJUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcblxuICAvKipcbiAgICogVG9vbHRpcCBsaW5lcyBmb3IgdGhlIHRyYW5zY3JpcHQgbWFya2VyIHVuZGVyIHdvcmxkIHBvaW50IGAod3gsIHd5KWAsIG9yIG51bGwuXG4gICAqXG4gICAqIFJldHVybnMgd2hhdCBpcyBrbm93biBhdCBvbmNlIChnZW5lLCBjb3VudCwgY2VsbCB0eXBlKTsgYW55dGhpbmcgdGhhdCBuZWVkcyB0aGVcbiAgICogc2VydmVyIOKAlCBkaXN0aW5jdCBnZW5lcyBpbiBhIGdyb3VwLCBpdHMgdG9wIGdlbmVzIGFuZCBjZWxscywgdGhlIGNlbGwncyBkaXNwbGF5IGlkIOKAlFxuICAgKiBhcnJpdmVzIHRocm91Z2ggYG9uRGV0YWlsc2Agb25jZSB0aGUgcG9pbnRlciBoYXMgcmVzdGVkIG9uIHRoZSBtYXJrZXIgYnJpZWZseS5cbiAgICovXG4gIGhvdmVyQXQoXG4gICAgd3g6IG51bWJlciwgd3k6IG51bWJlciwgcmFkaXVzV29ybGQ6IG51bWJlciwgb25EZXRhaWxzOiAobGluZXM6IHN0cmluZ1tdKSA9PiB2b2lkLFxuICApOiBzdHJpbmdbXSB8IG51bGwge1xuICAgIGNvbnN0IGQgPSB0aGlzLmRyYXduO1xuICAgIGNvbnN0IGxheWVyID0gdGhpcy5sYXllcnMuZ2V0KCd0cmFuc2NyaXB0cycpO1xuICAgIGlmICghZCB8fCAhbGF5ZXIgfHwgIXRoaXMudmlld2VyPy5sYXllcnMuaXRlbXMuaW5jbHVkZXMobGF5ZXIpIHx8ICFkLm1lcmdlZC5jb3VudCkge1xuICAgICAgdGhpcy5ob3ZlcktleSA9IG51bGw7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3Qgc3ggPSBkLnJlZj8uc2NhbGU/LlswXSA/PyAxO1xuICAgIGNvbnN0IHN5ID0gZC5yZWY/LnNjYWxlPy5bMV0gPz8gMTtcbiAgICBjb25zdCB4ID0gKHd4IC0gKGQucmVmPy50cmFuc2xhdGU/LlswXSA/PyAwKSkgLyBzeDtcbiAgICBjb25zdCB5ID0gKHd5IC0gKGQucmVmPy50cmFuc2xhdGU/LlsxXSA/PyAwKSkgLyBzeTtcbiAgICBjb25zdCBpID0gcGlja05lYXJlc3QoZCwgeCwgeSwgcmFkaXVzV29ybGQgLyBNYXRoLmFicyhzeCkpO1xuICAgIGlmIChpIDwgMCkge1xuICAgICAgdGhpcy5ob3ZlcktleSA9IG51bGw7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3Qga2V5ID0gYCR7ZC5raW5kfXwke2QubWVyZ2VkLnhbaV19fCR7ZC5tZXJnZWQueVtpXX18JHtkLm1lcmdlZC5nZW5lW2ldfWA7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5ob3ZlckNhY2hlLmdldChrZXkpO1xuICAgIGlmIChjYWNoZWQpIHJldHVybiBjYWNoZWQ7XG4gICAgaWYgKGtleSAhPT0gdGhpcy5ob3ZlcktleSkge1xuICAgICAgdGhpcy5ob3ZlcktleSA9IGtleTtcbiAgICAgIGlmICh0aGlzLmhvdmVyVGltZXIpIGNsZWFyVGltZW91dCh0aGlzLmhvdmVyVGltZXIpO1xuICAgICAgdGhpcy5ob3ZlclRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB2b2lkIHRoaXMuZmV0Y2hEZXRhaWxzKGQsIGksIGtleSwgb25EZXRhaWxzKSwgMTUwKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZGVzY3JpYmUoZCwgaSwgbnVsbCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoRGV0YWlscyhcbiAgICBkOiBEcmF3blRyYW5zY3JpcHRzLCBpOiBudW1iZXIsIGtleTogc3RyaW5nLCBvbkRldGFpbHM6IChsaW5lczogc3RyaW5nW10pID0+IHZvaWQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRTdW1tYXJ5IHx8IHRoaXMuaG92ZXJLZXkgIT09IGtleSkgcmV0dXJuO1xuICAgIGNvbnN0IG9icyA9IGQubWVyZ2VkLm9ic2VydmF0aW9uW2ldO1xuICAgIGNvbnN0IGNlbGxzID0gb2JzID09PSBOT19PQlNFUlZBVElPTiA/IFtdIDogW29ic107XG4gICAgbGV0IGJveDogW251bWJlciwgbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gfCB1bmRlZmluZWQ7XG4gICAgaWYgKGQua2luZCA9PT0gJ2JpbnMnICYmIGQuYmluKSB7XG4gICAgICBjb25zdCB7IHNpemUsIG9yaWdpbiB9ID0gZC5iaW47XG4gICAgICBjb25zdCBieCA9IE1hdGguZmxvb3IoKGQubWVyZ2VkLnhbaV0gLSBvcmlnaW5bMF0pIC8gc2l6ZSk7XG4gICAgICBjb25zdCBieSA9IE1hdGguZmxvb3IoKGQubWVyZ2VkLnlbaV0gLSBvcmlnaW5bMV0pIC8gc2l6ZSk7XG4gICAgICBjb25zdCB4MCA9IG9yaWdpblswXSArIGJ4ICogc2l6ZTtcbiAgICAgIGNvbnN0IHkwID0gb3JpZ2luWzFdICsgYnkgKiBzaXplO1xuICAgICAgYm94ID0gW3gwLCB5MCwgeDAgKyBzaXplLCB5MCArIHNpemVdO1xuICAgIH0gZWxzZSBpZiAoZC5raW5kID09PSAnaW5kaXZpZHVhbCcpIHtcbiAgICAgIGNvbnN0IGUgPSAwLjAyO1xuICAgICAgYm94ID0gW2QubWVyZ2VkLnhbaV0gLSBlLCBkLm1lcmdlZC55W2ldIC0gZSwgZC5tZXJnZWQueFtpXSArIGUsIGQubWVyZ2VkLnlbaV0gKyBlXTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN1bW1hcnkgPSBhd2FpdCB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkoeyBib3gsIGNlbGxzIH0pO1xuICAgICAgY29uc3QgbGluZXMgPSB0aGlzLmRlc2NyaWJlKGQsIGksIHN1bW1hcnkpO1xuICAgICAgdGhpcy5ob3ZlckNhY2hlLnNldChrZXksIGxpbmVzKTtcbiAgICAgIGlmICh0aGlzLmhvdmVyS2V5ID09PSBrZXkpIG9uRGV0YWlscyhsaW5lcyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHRyYW5zY3JpcHQgZGV0YWlscyB1bmF2YWlsYWJsZScsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSB0b29sdGlwIHRleHQgZm9yIGVudHJ5IGBpYCwgd2l0aCB0aGUgc2VydmVyJ3MgZGV0YWlscyB3aGVuIHRoZXkgaGF2ZSBhcnJpdmVkLiAqL1xuICBwcml2YXRlIGRlc2NyaWJlKGQ6IERyYXduVHJhbnNjcmlwdHMsIGk6IG51bWJlciwgczogU3BhdGlhbFRyYW5zY3JpcHRTdW1tYXJ5IHwgbnVsbCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB0ID0gZC5tZXJnZWQ7XG4gICAgY29uc3QgbiA9IHQud2VpZ2h0W2ldO1xuICAgIGNvbnN0IG9icyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgY29uc3QgZm10ID0gKHY6IG51bWJlcikgPT4gdi50b0xvY2FsZVN0cmluZygpO1xuICAgIGNvbnN0IHR5cGVPZiA9IChvOiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IHR5cGVzID0gdGhpcy5ob3ZlclR5cGVzO1xuICAgICAgaWYgKCF0eXBlcyB8fCBvID09PSBOT19PQlNFUlZBVElPTiB8fCB0eXBlcy5tZXRhLmtpbmQgIT09ICdjYXRlZ29yaWNhbCcpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgYyA9IHR5cGVzLmNvZGVzW29dO1xuICAgICAgcmV0dXJuIGMgPT09IE5PX0NBVEVHT1JZID8gbnVsbCA6IHR5cGVzLm1ldGEuY2F0ZWdvcmllc1tjXSA/PyBudWxsO1xuICAgIH07XG4gICAgY29uc3QgY2VsbExpbmUgPSAobzogbnVtYmVyLCBwcmVmaXg6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKG8gPT09IE5PX09CU0VSVkFUSU9OKSByZXR1cm4gJ291dHNpZGUgYW55IGNlbGwnO1xuICAgICAgY29uc3QgaWQgPSBzPy5jZWxsSWRzPy5bb10gPz8gYCMke299YDtcbiAgICAgIGNvbnN0IHR5cGUgPSB0eXBlT2Yobyk7XG4gICAgICByZXR1cm4gYCR7cHJlZml4fSAke2lkfSR7dHlwZSA/IGAgwrcgJHt0eXBlfWAgOiAnJ31gO1xuICAgIH07XG5cbiAgICBpZiAoZC5raW5kID09PSAnYmlucycpIHtcbiAgICAgIGNvbnN0IGxpbmVzID0gW2Ake2ZtdChuKX0gdHJhbnNjcmlwdHMgwrcgYWxsIGdlbmVzYF07XG4gICAgICBpZiAoZC5iaW4pIGxpbmVzLnB1c2goYCR7ZC5iaW4uc2l6ZS50b0ZpeGVkKDEpfSDDlyAke2QuYmluLnNpemUudG9GaXhlZCgxKX0gwrVtIGFyZWFgKTtcbiAgICAgIGlmIChzPy50cmFuc2NyaXB0cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYCR7Zm10KHMuZ2VuZXMgPz8gMCl9IGRpc3RpbmN0IGdlbmVzIMK3ICR7Zm10KHMuY2VsbHMgPz8gMCl9IGNlbGwke3MuY2VsbHMgPT09IDEgPyAnJyA6ICdzJ31gXG4gICAgICAgICAgKyAocy51bmFzc2lnbmVkID8gYCDCtyAke2ZtdChzLnVuYXNzaWduZWQpfSBvdXRzaWRlIGNlbGxzYCA6ICcnKSk7XG4gICAgICAgIGlmIChzLnRvcEdlbmVzPy5sZW5ndGgpIHtcbiAgICAgICAgICBsaW5lcy5wdXNoKGB0b3AgZ2VuZXM6ICR7cy50b3BHZW5lcy5zbGljZSgwLCA1KS5tYXAoKGcpID0+IGAke2cubmFtZX0gJHtmbXQoZy5jb3VudCl9YCkuam9pbignLCAnKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbGluZXMucHVzaChjZWxsTGluZShvYnMsICdtb3N0bHkgY2VsbCcpKTtcbiAgICAgIGlmICghcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkpIGxpbmVzLnB1c2goJ2xvYWRpbmcgZGV0YWlsc+KApicpO1xuICAgICAgcmV0dXJuIGxpbmVzO1xuICAgIH1cbiAgICBpZiAoZC5raW5kID09PSAnaW5kaXZpZHVhbCcpIHtcbiAgICAgIGNvbnN0IGdlbmUgPSBzPy50b3BHZW5lcz8uWzBdPy5uYW1lO1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgZ2VuZSA/IGAke2dlbmV9IHRyYW5zY3JpcHRgIDogJ1RyYW5zY3JpcHQnLFxuICAgICAgICBjZWxsTGluZShvYnMsICdpbiBjZWxsJyksXG4gICAgICAgIC4uLighcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkgPyBbJ2xvYWRpbmcgZGV0YWlsc+KApiddIDogW10pLFxuICAgICAgXTtcbiAgICB9XG4gICAgY29uc3QgZ2VuZSA9IGQuZ2VuZXNbdC5nZW5lW2ldXSA/PyAndHJhbnNjcmlwdCc7XG4gICAgcmV0dXJuIG4gPiAxXG4gICAgICA/IFtgJHtnZW5lfSDCtyAke2ZtdChuKX0gdHJhbnNjcmlwdHNgLCAnZ3JvdXBlZDogem9vbSBpbiB0byBzcGxpdCcsIGNlbGxMaW5lKG9icywgJ25lYXIgY2VsbCcpXVxuICAgICAgOiBbYCR7Z2VuZX0gdHJhbnNjcmlwdGAsIGNlbGxMaW5lKG9icywgJ2luIGNlbGwnKV07XG4gIH1cblxuICAvKiogUGh5c2ljYWwgbWFya2VyIHNpemUgbmVlZHMgwrVtOyBudWxsIHdoZW4gdGhlIGRhdGFzZXQncyB1bml0IGlzIHVua25vd24uICovXG4gIHByaXZhdGUgcHhQZXJNaWNyb24oZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHB4UGVyVW5pdDogbnVtYmVyKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gZGF0YXNldC5taWNyb25zUGVyVW5pdCA/IHB4UGVyVW5pdCAvIGRhdGFzZXQubWljcm9uc1BlclVuaXQgOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGNob3NlbiBnZW5lcywgYXQgdGhlIGxldmVsIHRoZSB6b29tIGNhbGxzIGZvciDigJQgb3IgY29hcnNlciwgd2hpbGUgdGhlIG1hcmtlcnMgaW5cbiAgICogdmlldyB3b3VsZCBleGNlZWQgdGhlIGJ1ZGdldC5cbiAgICovXG4gIHByaXZhdGUgZ2VuZUpvYihcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHwgbnVsbCB7XG4gICAgY29uc3QgbWV0YSA9IGRhdGFzZXQudHJhbnNjcmlwdFRpbGVzO1xuICAgIGNvbnN0IGdlbmVzID0gdmlldy50cmFuc2NyaXB0R2VuZXM7XG4gICAgaWYgKCFtZXRhIHx8ICFnZW5lcy5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IGZpcnN0ID0gdHJhbnNjcmlwdExldmVsRm9yKHB4UGVyVW5pdCwgbWV0YS5sZXZlbHMpO1xuICAgIGNvbnN0IGtleXNBdCA9IChsOiBudW1iZXIpID0+IHRpbGVzSW5SZWN0KHJlY3QsIGwsIG1ldGEubGV2ZWxzLCBtZXRhLmJvdW5kcywgTUFYX1RSQU5TQ1JJUFRfVElMRVMpO1xuICAgIGNvbnN0IHF1ZXJ5ID0geyBnZW5lcywgcXVhbGl0eTogdmlldy50cmFuc2NyaXB0UXVhbGl0eSB9O1xuICAgIGNvbnN0IHB4UGVyTWljcm9uID0gdGhpcy5weFBlck1pY3JvbihkYXRhc2V0LCBweFBlclVuaXQpO1xuICAgIHJldHVybiB7XG4gICAgICBraW5kOiAnZ2VuZXMnLFxuICAgICAga2V5OiBgZ2VuZXN8JHtnZW5lcy5qb2luKCcsJyl9fCR7dmlldy50cmFuc2NyaXB0UXVhbGl0eX18JHt2aWV3LnRyYW5zY3JpcHRCdWRnZXR9fCR7a2V5c0F0KGZpcnN0KS5tYXAodGlsZUlkKX1gLFxuICAgICAgbG9hZDogYXN5bmMgKCkgPT4ge1xuICAgICAgICBsZXQgbGV2ZWwgPSBmaXJzdDtcbiAgICAgICAgbGV0IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlO1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgY29uc3QgdGlsZXMgPSBhd2FpdCB0aGlzLmZldGNoQWxsKGtleXNBdChsZXZlbCksXG4gICAgICAgICAgICAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRUaWxlIShrLmxldmVsLCBrLmd4LCBrLmd5LCBxdWVyeSkpO1xuICAgICAgICAgIG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKHRpbGVzLCBNQVhfVFJBTlNDUklQVFMpO1xuICAgICAgICAgIGlmIChtZXJnZWQuY291bnQgPD0gdmlldy50cmFuc2NyaXB0QnVkZ2V0IHx8IGxldmVsID49IG1ldGEubGV2ZWxzLmxlbmd0aCAtIDEpIGJyZWFrO1xuICAgICAgICAgIGxldmVsKys7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KG1lcmdlZC5jb3VudCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbWVyZ2VkLmNvdW50OyBpKyspIHtcbiAgICAgICAgICBweFtpXSA9IHRyYW5zY3JpcHRNYXJrZXJQeChtZXJnZWQud2VpZ2h0W2ldLCB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgcHhQZXJNaWNyb24pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1lcmdlZCwgcHggfTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmVyeSBnZW5lOiB0aGUgdHJhbnNjcmlwdHMgdGhlbXNlbHZlcyBvbmNlIHRoZXkgZml0IHRoZSBidWRnZXQsIGVsc2UgYmlucyBvZiB0aGVcbiAgICogYWxsLWdlbmUgcHlyYW1pZCBzaXplZCBieSBob3cgbWFueSB0cmFuc2NyaXB0cyBlYWNoIGhvbGRzLlxuICAgKi9cbiAgcHJpdmF0ZSBhbGxHZW5lc0pvYihcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHwgbnVsbCB7XG4gICAgY29uc3QgYmlucyA9IGRhdGFzZXQudHJhbnNjcmlwdEJpbnM7XG4gICAgY29uc3QgdGlsZXMgPSBkYXRhc2V0LnRyYW5zY3JpcHRUaWxlcztcbiAgICBjb25zdCBib3VuZHMgPSBiaW5zPy5ib3VuZHMgPz8gdGlsZXM/LmJvdW5kcztcbiAgICBpZiAoIWJvdW5kcykgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgcGxhbiA9IGFsbEdlbmVzUGxhbih7XG4gICAgICByZWN0LCBib3VuZHMsIHB4UGVyVW5pdCwgYnVkZ2V0OiB2aWV3LnRyYW5zY3JpcHRCdWRnZXQsXG4gICAgICB0b3RhbDogYmlucz8uY291bnQgPz8gdGlsZXM/LmNvdW50ID8/IDAsXG4gICAgICBsZXZlbHM6IGJpbnMgJiYgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRCaW5zID8gYmlucy5sZXZlbHMgOiBbXSxcbiAgICAgIGNhbkluZGl2aWR1YWw6ICEhdGlsZXMsXG4gICAgfSk7XG5cbiAgICBpZiAocGxhbi5raW5kID09PSAnaW5kaXZpZHVhbCcgJiYgdGlsZXMpIHtcbiAgICAgIGNvbnN0IGtleXMgPSB0aWxlc0luUmVjdChyZWN0LCAwLCB0aWxlcy5sZXZlbHMsIHRpbGVzLmJvdW5kcywgTUFYX1RSQU5TQ1JJUFRfVElMRVMpO1xuICAgICAgLy8gRWFjaCB0aWxlIGNsaXBwZWQgdG8gdGhlIHZpZXcsIHJvdW5kZWQgb3V0d2FyZCB0byAxMCB1bml0cyBzbyBzbWFsbCBwYW5zIGhpdCBjYWNoZS5cbiAgICAgIGNvbnN0IHIxMCA9ICh2OiBudW1iZXIsIHVwOiBib29sZWFuKSA9PiAodXAgPyBNYXRoLmNlaWwodiAvIDEwKSA6IE1hdGguZmxvb3IodiAvIDEwKSkgKiAxMDtcbiAgICAgIGNvbnN0IHNpemUgPSB0aWxlcy5sZXZlbHNbMF0udGlsZVNpemU7XG4gICAgICBjb25zdCBib3hlcyA9IGtleXMubWFwKChrKTogW251bWJlciwgbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gPT4gW1xuICAgICAgICBNYXRoLm1heChrLmd4ICogc2l6ZSwgcjEwKHJlY3QueDAsIGZhbHNlKSksIE1hdGgubWF4KGsuZ3kgKiBzaXplLCByMTAocmVjdC55MCwgZmFsc2UpKSxcbiAgICAgICAgTWF0aC5taW4oKGsuZ3ggKyAxKSAqIHNpemUsIHIxMChyZWN0LngxLCB0cnVlKSksIE1hdGgubWluKChrLmd5ICsgMSkgKiBzaXplLCByMTAocmVjdC55MSwgdHJ1ZSkpLFxuICAgICAgXSk7XG4gICAgICBjb25zdCBweFBlck1pY3JvbiA9IHRoaXMucHhQZXJNaWNyb24oZGF0YXNldCwgcHhQZXJVbml0KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGtpbmQ6ICdpbmRpdmlkdWFsJyxcbiAgICAgICAga2V5OiBgYWxsfGluZGl2aWR1YWx8JHt2aWV3LnRyYW5zY3JpcHRCdWRnZXR9fCR7Ym94ZXMubWFwKChiKSA9PiBiLmpvaW4oJywnKSkuam9pbignOycpfWAsXG4gICAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCBnb3QgPSBhd2FpdCB0aGlzLmZldGNoQWxsKGtleXMubWFwKChrLCBpKSA9PiAoeyAuLi5rLCBib3g6IGJveGVzW2ldIH0pKSxcbiAgICAgICAgICAgIChrKSA9PiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUhKDAsIGsuZ3gsIGsuZ3ksIHsgZ2VuZXM6IFtBTExfR0VORVNdLCBib3g6IGsuYm94IH0pKTtcbiAgICAgICAgICAvLyBUaGUgcGxhbiBlc3RpbWF0ZWQgdGhlIHZpZXcgZnJvbSB0aGUgZGF0YXNldCdzIGF2ZXJhZ2UgZGVuc2l0eTsgZXhwcmVzc2lvbiBpc1xuICAgICAgICAgIC8vIHVuZXZlbiwgc28gYSBkZW5zZSB2aWV3IGNhbiBob2xkIGZhciBtb3JlLiBSYXRoZXIgdGhhbiBjdXQgdGhlIGV4Y2VzcyBvZmYsIHNob3dcbiAgICAgICAgICAvLyBpdCBncm91cGVkIOKAlCB0aGUgYmluIGxldmVsIHRoZSBwbGFubmVyIHdvdWxkIHBpY2sgaWYgaXQgaGFkIGtub3duLlxuICAgICAgICAgIGNvbnN0IGNhcCA9IE1hdGgubWF4KHZpZXcudHJhbnNjcmlwdEJ1ZGdldCAqIDEuNSwgMSk7XG4gICAgICAgICAgY29uc3QgbG9hZGVkID0gZ290LnJlZHVjZSgobiwgdCkgPT4gbiArIHQuY291bnQsIDApO1xuICAgICAgICAgIGlmIChsb2FkZWQgPiBjYXAgJiYgYmlucyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMpIHtcbiAgICAgICAgICAgIGNvbnN0IGZhbGxiYWNrID0gYWxsR2VuZXNQbGFuKHtcbiAgICAgICAgICAgICAgcmVjdCwgYm91bmRzLCBweFBlclVuaXQsIGJ1ZGdldDogdmlldy50cmFuc2NyaXB0QnVkZ2V0LCB0b3RhbDogYmlucy5jb3VudCxcbiAgICAgICAgICAgICAgbGV2ZWxzOiBiaW5zLmxldmVscywgY2FuSW5kaXZpZHVhbDogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChmYWxsYmFjay5raW5kID09PSAnYmlucycpIHtcbiAgICAgICAgICAgICAgY29uc3Qgam9iID0gdGhpcy5iaW5zSm9iKHZpZXcsIHJlY3QsIHB4UGVyVW5pdCwgYm91bmRzLCBiaW5zLCBmYWxsYmFjay5sZXZlbCk7XG4gICAgICAgICAgICAgIHJldHVybiB7IC4uLihhd2FpdCBqb2IubG9hZCgpKSwga2luZDogam9iLmtpbmQsIGJpbjogam9iLmJpbiB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBtZXJnZWQgPSBtZXJnZVRyYW5zY3JpcHRUaWxlcyhnb3QsIGNhcCk7XG4gICAgICAgICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KG1lcmdlZC5jb3VudCk7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXJnZWQuY291bnQ7IGkrKykgcHhbaV0gPSB0cmFuc2NyaXB0TWFya2VyUHgoMSwgdmlldy50cmFuc2NyaXB0U2NhbGUsIHB4UGVyTWljcm9uKTtcbiAgICAgICAgICByZXR1cm4geyBtZXJnZWQsIHB4IH07XG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChwbGFuLmtpbmQgPT09ICdiaW5zJyAmJiBiaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Qmlucykge1xuICAgICAgcmV0dXJuIHRoaXMuYmluc0pvYih2aWV3LCByZWN0LCBweFBlclVuaXQsIGJvdW5kcywgYmlucywgcGxhbi5sZXZlbCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIEJpbnMgb2YgdGhlIGFsbC1nZW5lIHB5cmFtaWQgYXQgYGxldmVsYCwgc2l6ZWQgYnkgaG93IG1hbnkgdHJhbnNjcmlwdHMgZWFjaCBob2xkcy4gKi9cbiAgcHJpdmF0ZSBiaW5zSm9iKFxuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHJlY3Q6IERhdGFSZWN0LCBweFBlclVuaXQ6IG51bWJlciwgYm91bmRzOiBTcGF0aWFsQm91bmRzLFxuICAgIGJpbnM6IE5vbk51bGxhYmxlPFNwYXRpYWxEYXRhc2V0Wyd0cmFuc2NyaXB0QmlucyddPiwgbGV2ZWw6IG51bWJlcixcbiAgKTogVHJhbnNjcmlwdEpvYiB7XG4gICAgY29uc3QgbHYgPSBiaW5zLmxldmVsc1tsZXZlbF07XG4gICAgY29uc3Qga2V5cyA9IHRpbGVzSW5SZWN0RnJvbShiaW5zLm9yaWdpbiwgcmVjdCwgbGV2ZWwsXG4gICAgICBiaW5zLmxldmVscy5tYXAoKGwpID0+ICh7IHRpbGVTaXplOiBsLnRpbGVTaXplIH0pKSwgYm91bmRzLCBNQVhfQklOX1RJTEVTKTtcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2JpbnMnLFxuICAgICAgYmluOiB7IHNpemU6IGx2LmJpblNpemUsIG9yaWdpbjogYmlucy5vcmlnaW4gfSxcbiAgICAgIGtleTogYGFsbHxiaW5zfCR7bGV2ZWx9fCR7dmlldy50cmFuc2NyaXB0QnVkZ2V0fXwke2tleXMubWFwKHRpbGVJZCl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgZ290ID0gYXdhaXQgdGhpcy5mZXRjaEFsbChrZXlzLCAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRCaW5zIShrLmxldmVsLCBrLmd4LCBrLmd5KSk7XG4gICAgICAgIGNvbnN0IG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKGdvdCwgTWF0aC5tYXgodmlldy50cmFuc2NyaXB0QnVkZ2V0ICogMS41LCAxKSk7XG4gICAgICAgIGNvbnN0IHJlZkNvdW50ID0gcXVhbnRpbGVPZihtZXJnZWQud2VpZ2h0LCAwLjk1KTtcbiAgICAgICAgY29uc3QgYmluUHggPSBsdi5iaW5TaXplICogcHhQZXJVbml0O1xuICAgICAgICBjb25zdCBweCA9IG5ldyBGbG9hdDMyQXJyYXkobWVyZ2VkLmNvdW50KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXJnZWQuY291bnQ7IGkrKykge1xuICAgICAgICAgIHB4W2ldID0gZ3JvdXBlZE1hcmtlclB4KG1lcmdlZC53ZWlnaHRbaV0sIHJlZkNvdW50LCBiaW5QeCwgdmlldy50cmFuc2NyaXB0U2NhbGUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1lcmdlZCwgcHggfTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBQZXItZW50cnkgY29sb3VycyBib3RoIGFzIFJHQkEgKHBvaW50cykgYW5kIGFzIGNvbG9ybWFwIHZhbHVlcyAoZ2x5cGggc2hhcGVzKS4gKi9cbiAgcHJpdmF0ZSBhc3luYyB0cmFuc2NyaXB0Q29sb3JzKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCB0OiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsXG4gICk6IFByb21pc2U8VHJhbnNjcmlwdEZhY2VzPiB7XG4gICAgbGV0IHJnYjogUmdiW107XG4gICAgbGV0IGNvZGVPZjogKGk6IG51bWJlcikgPT4gbnVtYmVyO1xuICAgIGlmICh2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ID09PSAnZ2VuZScpIHtcbiAgICAgIC8vIEFsbCBnZW5lczogY29kZXMgYXJlIHRoZSBkYXRhc2V0J3MgZ2VuZSBpbmRpY2VzLCBmb2xkZWQgb250byB0aGUgcGFsZXR0ZS5cbiAgICAgIGNvbnN0IG4gPSB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGggOiB2aWV3LnRyYW5zY3JpcHRHZW5lcy5sZW5ndGg7XG4gICAgICByZ2IgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiBuIH0sIChfZywgaSkgPT4gcGFyc2VIZXgoXG4gICAgICAgICghdmlldy50cmFuc2NyaXB0QWxsR2VuZXMgJiYgdmlldy50cmFuc2NyaXB0R2VuZUNvbG9yc1t2aWV3LnRyYW5zY3JpcHRHZW5lc1tpXV0pXG4gICAgICAgIHx8IERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURVtpICUgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLmxlbmd0aF0pKTtcbiAgICAgIGNvZGVPZiA9IHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gKGkpID0+IHQuZ2VuZVtpXSAlIG4gOiAoaSkgPT4gdC5nZW5lW2ldO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBuYW1lID0gdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyk7XG4gICAgICBjb25zdCBjb2RlcyA9IG5hbWUgPyBhd2FpdCB0aGlzLmNhdGVnb3JpY2FsQ29kZXMobmFtZSkgOiBudWxsO1xuICAgICAgcmdiID0gY29kZXM/Lm1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJyA/IHJlc29sdmVDYXRlZ29yeUNvbG9ycyhjb2Rlcy5tZXRhKS5tYXAocGFyc2VIZXgpIDogW107XG4gICAgICBjb2RlT2YgPSAoaSkgPT4ge1xuICAgICAgICBjb25zdCBvID0gdC5vYnNlcnZhdGlvbltpXTtcbiAgICAgICAgaWYgKCFjb2RlcyB8fCBvID09PSBOT19PQlNFUlZBVElPTikgcmV0dXJuIC0xO1xuICAgICAgICBjb25zdCBjID0gY29kZXMuY29kZXNbb107XG4gICAgICAgIHJldHVybiBjID09PSBOT19DQVRFR09SWSA/IC0xIDogYztcbiAgICAgIH07XG4gICAgfVxuICAgIGNvbnN0IHsgc3RvcHMsIHZhbHVlT2YgfSA9IGRpc2NyZXRlQ29sb3JtYXBTdG9wcyhyZ2IsIE1JU1NJTkdfQ09MT1IpO1xuICAgIGNvbnN0IHJnYmE6IFJHQkFbXSA9IG5ldyBBcnJheSh0LmNvdW50KTtcbiAgICBjb25zdCB2YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KHQuY291bnQpO1xuICAgIGNvbnN0IHR1cGxlczogUkdCQVtdID0gcmdiLm1hcCgoW3IsIGcsIGJdKSA9PiBbciAvIDI1NSwgZyAvIDI1NSwgYiAvIDI1NSwgMV0pO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCBjID0gY29kZU9mKGkpO1xuICAgICAgcmdiYVtpXSA9IGMgPCAwID8gVU5BU1NJR05FRF9SR0JBIDogdHVwbGVzW2NdO1xuICAgICAgdmFsdWVzW2ldID0gdmFsdWVPZihjKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcmdiYSwgdmFsdWVzLCBjb2xvcm1hcDogbmV3IENvbG9ybWFwKCd0cmFuc2NyaXB0LWNhdGVnb3JpZXMnLCBzdG9wcykgfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBkZW5zaXR5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgYXN5bmMgcGxhbkRlbnNpdHkoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBoaWRkZW5HZW5lcyA9IG5ldyBTZXQodmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMpO1xuICAgIGNvbnN0IGdlbmVzID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gW0FMTF9HRU5FU11cbiAgICAgIDogdmlldy50cmFuc2NyaXB0R2VuZXMuZmlsdGVyKChnKSA9PiAhaGlkZGVuR2VuZXMuaGFzKGcpKTtcbiAgICBpZiAoIWRhdGFzZXQuZGVuc2l0eSB8fCAhdGhpcy5wb3J0LmdldERlbnNpdHkgfHwgdmlldy50cmFuc2NyaXB0TW9kZSAhPT0gJ2RlbnNpdHknIHx8ICFnZW5lcy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuZHJvcCgnZGVuc2l0eScpO1xuICAgICAgdGhpcy5kZW5zaXR5U3RhdHMgPSBudWxsO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsdXQgPSBsdXRGb3Iodmlldy5kZW5zaXR5Q29sb3JtYXAgPz8gSU5GRVJOT19TQ0FMRSk7XG4gICAgY29uc3Qga2V5ID0gW2RhdGFzZXQuaWQsIGdlbmVzLmpvaW4oJywnKSwgdmlldy5kZW5zaXR5QmluLCB2aWV3LmRlbnNpdHlPcGFjaXR5LFxuICAgICAgSlNPTi5zdHJpbmdpZnkodmlldy5kZW5zaXR5UmFuZ2UpLCBKU09OLnN0cmluZ2lmeSh2aWV3LmRlbnNpdHlDb2xvcm1hcCldLmpvaW4oJ3wnKTtcbiAgICBpZiAoa2V5ID09PSB0aGlzLmtleXMuZ2V0KCdkZW5zaXR5JykgJiYgdGhpcy5sYXllcnMuaGFzKCdkZW5zaXR5JykpIHJldHVybjtcbiAgICBjb25zdCByYXN0ZXIgPSBhd2FpdCB0aGlzLnBvcnQuZ2V0RGVuc2l0eShnZW5lcywgdmlldy5kZW5zaXR5QmluKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuXG4gICAgLy8gQmlucyBkcmF3biBhcyBzcXVhcmVzLCBhcyBYZW5pdW0gRXhwbG9yZXIgZG9lczsgdGhlIHdpbmRvdyBpcyBpbiB0cmFuc2NyaXB0cy/CtW3Csi5cbiAgICBjb25zdCBtZXRhID0gcmFzdGVyLm1ldGE7XG4gICAgY29uc3QgYXJlYSA9IG1ldGEuZ3JpZFNpemVbMF0gKiBtZXRhLmdyaWRTaXplWzFdO1xuICAgIGNvbnN0IHBlckFyZWEgPSByYXN0ZXIudmFsdWVzLm1hcCgodikgPT4gdiAvIGFyZWEpO1xuICAgIGNvbnN0IFtsbywgaGldID0gdmlldy5kZW5zaXR5UmFuZ2UgPz8gZGVuc2l0eUF1dG9SYW5nZShwZXJBcmVhKTtcbiAgICB0aGlzLmRlbnNpdHlTdGF0cyA9IHsgbG8sIGhpLCBtYXg6IHBlckFyZWEucmVkdWNlKChtLCB2KSA9PiAodiA+IG0gPyB2IDogbSksIDApIH07XG4gICAgY29uc3QgcmdiYSA9IGNvbG9yRGVuc2l0eVdpbmRvdyhwZXJBcmVhLCBsdXQsIHZpZXcuZGVuc2l0eU9wYWNpdHksIGxvLCBoaSk7XG4gICAgY29uc3QgcmVmID0gZGF0YXNldC5pbWFnZVJlZjtcbiAgICBjb25zdCBzeCA9IHJlZj8uc2NhbGU/LlswXSA/PyAxO1xuICAgIGNvbnN0IHN5ID0gcmVmPy5zY2FsZT8uWzFdID8/IDE7XG4gICAgY29uc3QgbGF5ZXI6IEltYWdlTGF5ZXIgPSB0aGlzLnZpZXdlciEuYWRkSW1hZ2UoXG4gICAgICB7IGtpbmQ6ICd0eXBlZCcsIHdpZHRoOiBtZXRhLmNvbHMsIGhlaWdodDogbWV0YS5yb3dzLCBjaGFubmVsczogNCwgZHR5cGU6ICd1aW50OCcsIGRhdGE6IHJnYmEgfSxcbiAgICAgIHtcbiAgICAgICAgbmFtZTogYGRlbnNpdHkgwrcgJHt2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/ICdhbGwgZ2VuZXMnIDogZ2VuZXMuam9pbignLCAnKX1gLFxuICAgICAgICBzY2FsZTogW21ldGEuZ3JpZFNpemVbMF0gKiBzeCwgbWV0YS5ncmlkU2l6ZVsxXSAqIHN5XSxcbiAgICAgICAgdHJhbnNsYXRlOiBbXG4gICAgICAgICAgbWV0YS5vcmlnaW5bMF0gKiBzeCArIChyZWY/LnRyYW5zbGF0ZT8uWzBdID8/IDApLFxuICAgICAgICAgIG1ldGEub3JpZ2luWzFdICogc3kgKyAocmVmPy50cmFuc2xhdGU/LlsxXSA/PyAwKSxcbiAgICAgICAgXSxcbiAgICAgICAgYmxlbmRpbmc6ICd0cmFuc2x1Y2VudCcsXG4gICAgICAgIGludGVycG9sYXRpb246ICduZWFyZXN0JyxcbiAgICAgIH0sXG4gICAgKTtcbiAgICB0aGlzLmtleXMuc2V0KCdkZW5zaXR5Jywga2V5KTtcbiAgICB0aGlzLnJlcGxhY2UoJ2RlbnNpdHknLCBsYXllcik7XG4gICAgdGhpcy5ob3N0LmRlbnNpdHlDaGFuZ2VkPy4odGhpcy5kZW5zaXR5U3RhdHMpO1xuICB9XG5cbiAgcHJpdmF0ZSBjb3VudHNDYWNoZTogeyBrZXk6IHN0cmluZzsgY291bnRzOiBQcm9taXNlPFNwYXRpYWxUcmFuc2NyaXB0Q291bnRzPiB9IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFRyYW5zY3JpcHRzIGluIHZpZXcgZm9yIHRoZSB2aXNpYmxlIGdlbmVzOiBlYWNoIGdlbmUncyBkYXRhc2V0IHRvdGFsIHRpbWVzIHRoZSBzaGFyZVxuICAgKiBvZiB0aGUgdGlzc3VlIG9uIHNjcmVlbi4gQW4gZXN0aW1hdGUg4oCUIGV4cHJlc3Npb24gaXMgbm90IHVuaWZvcm0g4oCUIHdoaWNoIGlzIGFsc28gd2hhdFxuICAgKiBYZW5pdW0gRXhwbG9yZXIgc2hvd3M7IGl0IHRlbGxzIHRoZSB1c2VyIHdoZXRoZXIgdGhlIGJ1ZGdldCB3aWxsIGZvcmNlIGdyb3VwaW5nLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwbGFuRXN0aW1hdGUoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHZpZXdlcjogVmlld2VyLCB3OiBudW1iZXIsIGg6IG51bWJlcixcbiAgICBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdGlsZXMgPSBkYXRhc2V0LnRyYW5zY3JpcHRUaWxlcztcbiAgICBpZiAoIXRpbGVzIHx8ICF0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdENvdW50cyB8fCB2aWV3LnRyYW5zY3JpcHRNb2RlID09PSAnb2ZmJykge1xuICAgICAgdGhpcy5ob3N0LmVzdGltYXRlQ2hhbmdlZD8uKG51bGwpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBoaWRkZW5HZW5lcyA9IG5ldyBTZXQodmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMpO1xuICAgIGNvbnN0IGdlbmVzID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXMgPyBbXSA6IHZpZXcudHJhbnNjcmlwdEdlbmVzLmZpbHRlcigoZykgPT4gIWhpZGRlbkdlbmVzLmhhcyhnKSk7XG4gICAgY29uc3Qga2V5ID0gYCR7ZGF0YXNldC5pZH18JHtnZW5lcy5qb2luKCcsJyl9YDtcbiAgICBpZiAodGhpcy5jb3VudHNDYWNoZT8ua2V5ICE9PSBrZXkpIHtcbiAgICAgIHRoaXMuY291bnRzQ2FjaGUgPSB7IGtleSwgY291bnRzOiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdENvdW50cyhnZW5lcykgfTtcbiAgICB9XG4gICAgbGV0IGNvdW50czogU3BhdGlhbFRyYW5zY3JpcHRDb3VudHM7XG4gICAgdHJ5IHtcbiAgICAgIGNvdW50cyA9IGF3YWl0IHRoaXMuY291bnRzQ2FjaGUuY291bnRzO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5jb3VudHNDYWNoZSA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgY29uc3QgaW5WaWV3ID0gdmlzaWJsZURhdGFSZWN0KHZpZXdlci5jYW1lcmEuY2VudGVyLCB2aWV3ZXIuY2FtZXJhLnpvb20sIHcsIGgsIGRhdGFzZXQuaW1hZ2VSZWYsIDApO1xuICAgIGlmICghaW5WaWV3KSByZXR1cm47XG4gICAgY29uc3QgYiA9IGNvdW50cy5ib3VuZHM7XG4gICAgY29uc3Qgc2hhcmUgPSBNYXRoLm1pbigxLCB2aXNpYmxlQXJlYShpblZpZXcsIGIpIC8gTWF0aC5tYXgoMSwgKGJbMl0gLSBiWzBdKSAqIChiWzNdIC0gYlsxXSkpKTtcbiAgICBjb25zdCBzZWxlY3RlZCA9IHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXG4gICAgICA/IGNvdW50cy50b3RhbFxuICAgICAgOiBnZW5lcy5yZWR1Y2UoKHN1bSwgZykgPT4gc3VtICsgKGNvdW50cy5jb3VudHNbZ10gPz8gMCksIDApO1xuICAgIHRoaXMuaG9zdC5lc3RpbWF0ZUNoYW5nZWQ/Lih7IHBvaW50czogTWF0aC5yb3VuZChzZWxlY3RlZCAqIHNoYXJlKSwgbWF4OiB2aWV3LnRyYW5zY3JpcHRCdWRnZXQgfSk7XG4gIH1cblxuICAvKiogVGhlIGRlbnNpdHkgd2luZG93IGluIHVzZSBhbmQgdGhlIGRlbnNlc3QgYmluLCBmb3IgdGhlIHBhbmVsJ3MgdGhyZXNob2xkIGNvbnRyb2wuICovXG4gIGRlbnNpdHlTdGF0czogeyBsbzogbnVtYmVyOyBoaTogbnVtYmVyOyBtYXg6IG51bWJlciB9IHwgbnVsbCA9IG51bGw7XG5cbiAgLy8g4pSA4pSAIGxheWVyIGJvb2trZWVwaW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBGZXRjaCBldmVyeSB0aWxlLCBkcmF3aW5nIHdoYXQgYXJyaXZlZC4gQSBmYWlsdXJlIGRvZXMgbm90IGZhaWwgdGhlIHZpZXcsIGJ1dCBpdCBtYXJrcyB0aGVcbiAgICogcGxhbiBpbmNvbXBsZXRlOiB0aGUgY2FsbGVyIG11c3Qgbm90IGNhY2hlIGl0IGFzIGRvbmUsIGFuZCBgcGxhbigpYCByZXRyaWVzIGl0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEFsbDxLLCBUPihrZXlzOiBLW10sIGxvYWQ6IChrOiBLKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUW10+IHtcbiAgICBjb25zdCBzZXR0bGVkID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGtleXMubWFwKGxvYWQpKTtcbiAgICBjb25zdCBvdXQ6IFRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcyBvZiBzZXR0bGVkKSB7XG4gICAgICBpZiAocy5zdGF0dXMgPT09ICdmdWxmaWxsZWQnKSBvdXQucHVzaChzLnZhbHVlKTtcbiAgICAgIGVsc2UgY29uc29sZS53YXJuKCdbbmFwYXJpLWpzXSBzcGF0aWFsIHRpbGUgZmFpbGVkJywgcy5yZWFzb24pO1xuICAgIH1cbiAgICBpZiAob3V0Lmxlbmd0aCA8IGtleXMubGVuZ3RoKSB0aGlzLnBsYW5JbmNvbXBsZXRlID0gdHJ1ZTtcbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFB1dCBhIHNoYXBlcyBsYXllciBpbiBwbGFjZSBmb3IgYGdyb3VwYDogYSBnZW9tZXRyeSBjaGFuZ2UgYnVpbGRzIGEgbmV3IGxheWVyLCBhXG4gICAqIGNvbG91ci1vbmx5IGNoYW5nZSBtdXRhdGVzIHZhbHVlcy9jb2xvcm1hcCBvbiB0aGUgZXhpc3Rpbmcgb25lLlxuICAgKi9cbiAgcHJpdmF0ZSB1cHNlcnRTaGFwZXMoXG4gICAgZ3JvdXA6IEdyb3VwLCB3YW50ZWQ6IGJvb2xlYW4sIGdlb21ldHJ5Q2hhbmdlZDogYm9vbGVhbiwgcmluZ3M6IFNwYXRpYWxQb2x5Z29ucyxcbiAgICBvcHRzOiBQYXJhbWV0ZXJzPFZpZXdlclsnYWRkU2hhcGVzJ10+WzJdICYgb2JqZWN0LFxuICApOiB2b2lkIHtcbiAgICBpZiAoIXdhbnRlZCkge1xuICAgICAgdGhpcy5kcm9wKGdyb3VwKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLmxheWVycy5nZXQoZ3JvdXApIGFzIFNoYXBlc0xheWVyIHwgdW5kZWZpbmVkO1xuICAgIGlmIChleGlzdGluZyAmJiAhZ2VvbWV0cnlDaGFuZ2VkICYmIHRoaXMudmlld2VyIS5sYXllcnMuaXRlbXMuaW5jbHVkZXMoZXhpc3RpbmcpKSB7XG4gICAgICAvLyBGbGF0IGNvbG91ciBoYXMgbm8gdmFsdWVzOyBjbGVhcmluZyB0aGVtIGlzIHdoYXQgc3dpdGNoZXMgdGhlIGxheWVyIHRvIGBjb2xvcmAuXG4gICAgICBleGlzdGluZy52YWx1ZXMgPSBvcHRzLnZhbHVlcyA/PyBudWxsO1xuICAgICAgaWYgKG9wdHMuY29sb3JtYXApIGV4aXN0aW5nLmNvbG9ybWFwID0gb3B0cy5jb2xvcm1hcDtcbiAgICAgIGlmIChvcHRzLmNvbnRyYXN0TGltaXRzKSBleGlzdGluZy5jb250cmFzdExpbWl0cyA9IG9wdHMuY29udHJhc3RMaW1pdHM7XG4gICAgICBpZiAob3B0cy5jb2xvcikgZXhpc3RpbmcuY29sb3IgPSBvcHRzLmNvbG9yO1xuICAgICAgaWYgKG9wdHMub3BhY2l0eSAhPT0gdW5kZWZpbmVkKSBleGlzdGluZy5vcGFjaXR5ID0gb3B0cy5vcGFjaXR5O1xuICAgICAgdGhpcy52aWV3ZXIhLnJlcXVlc3RSZW5kZXIoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbGF5ZXIgPSB0aGlzLnZpZXdlciEuYWRkU2hhcGVzKHJpbmdzLmNvb3JkcywgcmluZ3Mub2Zmc2V0cywgb3B0cyk7XG4gICAgdGhpcy5yZXBsYWNlKGdyb3VwLCBsYXllcik7XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFsbCBgbGF5ZXJgIGFzIGBncm91cGAncyBsYXllciBhbmQgcmVzdG9yZSB0aGUgb3JkZXIgb2YgdGhlIGdyb3VwcyBhYm92ZSBpdC5cbiAgICogVGhlIGxheWVyIHdhcyBqdXN0IGFkZGVkIGJ5IHRoZSBjYWxsZXIgKHNvIGl0IGlzIG9uIHRvcCk7IGdyb3VwcyB0aGF0IGJlbG9uZyBhYm92ZVxuICAgKiBpdCBhcmUgcmVtb3ZlZCBhbmQgcmUtYWRkZWQuXG4gICAqL1xuICBwcml2YXRlIHJlcGxhY2UoZ3JvdXA6IEdyb3VwLCBsYXllcjogTGF5ZXIpOiB2b2lkIHtcbiAgICBjb25zdCB2ID0gdGhpcy52aWV3ZXIhO1xuICAgIGNvbnN0IG9sZCA9IHRoaXMubGF5ZXJzLmdldChncm91cCk7XG4gICAgaWYgKG9sZCAmJiBvbGQgIT09IGxheWVyICYmIHYubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKG9sZCkpIHYubGF5ZXJzLnJlbW92ZShvbGQpO1xuICAgIHRoaXMubGF5ZXJzLnNldChncm91cCwgbGF5ZXIpO1xuICAgIGZvciAoY29uc3QgZyBvZiBPUkRFUi5zbGljZShPUkRFUi5pbmRleE9mKGdyb3VwKSArIDEpKSB7XG4gICAgICBjb25zdCBhYm92ZSA9IHRoaXMubGF5ZXJzLmdldChnKTtcbiAgICAgIGlmICghYWJvdmUgfHwgIXYubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGFib3ZlKSkgY29udGludWU7XG4gICAgICB2LmxheWVycy5yZW1vdmUoYWJvdmUpO1xuICAgICAgdi5sYXllcnMuYWRkKGFib3ZlKTtcbiAgICB9XG4gICAgdi5yZXF1ZXN0UmVuZGVyKCk7XG4gIH1cblxuICBwcml2YXRlIGRyb3AoZ3JvdXA6IEdyb3VwKTogdm9pZCB7XG4gICAgY29uc3QgbGF5ZXIgPSB0aGlzLmxheWVycy5nZXQoZ3JvdXApO1xuICAgIGlmIChsYXllciAmJiB0aGlzLnZpZXdlcj8ubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGxheWVyKSkgdGhpcy52aWV3ZXIubGF5ZXJzLnJlbW92ZShsYXllcik7XG4gICAgdGhpcy5sYXllcnMuZGVsZXRlKGdyb3VwKTtcbiAgICB0aGlzLmtleXMuZGVsZXRlKGdyb3VwKTtcbiAgfVxuXG4gIHByaXZhdGUgZHJvcENlbGxzKCk6IHZvaWQge1xuICAgIHRoaXMuZHJvcCgnY2VsbEZpbGwnKTtcbiAgICB0aGlzLmRyb3AoJ2NlbGxPdXRsaW5lJyk7XG4gICAgdGhpcy5kcm9wKCdudWNsZXVzT3V0bGluZScpO1xuICAgIHRoaXMuY3VycmVudE51Y2xlaSA9IG51bGw7XG4gICAgdGhpcy5jZWxsR2VvbWV0cnlLZXkgPSBudWxsO1xuICAgIHRoaXMuY2VsbFN0eWxlS2V5ID0gbnVsbDtcbiAgICB0aGlzLmN1cnJlbnRSaW5ncyA9IG51bGw7XG4gICAgdGhpcy5zZXRQb2x5Z29uc1Nob3duKGZhbHNlKTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0UG9seWdvbnNTaG93bihzaG93bjogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmIChzaG93biA9PT0gdGhpcy5wb2x5Z29uc1Nob3duKSByZXR1cm47XG4gICAgdGhpcy5wb2x5Z29uc1Nob3duID0gc2hvd247XG4gICAgdGhpcy5ob3N0LnBvbHlnb25zU2hvd25DaGFuZ2VkKHNob3duKTtcbiAgfVxufVxuXG4vKiogV2hhdCB0aGUgdHJhbnNjcmlwdCBsYXllciBjdXJyZW50bHkgc2hvd3Mg4oCUIHdoYXQgaG92ZXJpbmcgbmVlZHMgdG8gbmFtZSBhIG1hcmtlci4gKi9cbmludGVyZmFjZSBEcmF3blRyYW5zY3JpcHRzIHtcbiAga2luZDogVHJhbnNjcmlwdEpvYlsna2luZCddO1xuICBiaW4/OiBUcmFuc2NyaXB0Sm9iWydiaW4nXTtcbiAgbWVyZ2VkOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGU7XG4gIC8qKiBNYXJrZXIgcmFkaXVzIHBlciBlbnRyeSwgaW4gb2JzZXJ2YXRpb24gdW5pdHMuICovXG4gIHJhZGl1czogRmxvYXQzMkFycmF5O1xuICBnZW5lczogc3RyaW5nW107XG4gIHJlZjogU3BhdGlhbEltYWdlUmVmIHwgbnVsbDtcbiAgLyoqIExhemlseSBidWlsdCBzcGF0aWFsIGluZGV4OiBidWNrZXQg4oaSIGVudHJ5IGluZGljZXMuICovXG4gIGdyaWQ6IHsgc2l6ZTogbnVtYmVyOyBidWNrZXRzOiBNYXA8bnVtYmVyLCBudW1iZXJbXT4gfSB8IG51bGw7XG59XG5cbi8qKiBJbmRleCBvZiB0aGUgZW50cnkgdW5kZXIgYCh4LCB5KWAg4oCUIHdpdGhpbiBpdHMgb3duIHJhZGl1cyBvciBgdG9sZXJhbmNlYCDigJQgb3IgLTEuICovXG5leHBvcnQgZnVuY3Rpb24gcGlja05lYXJlc3QoXG4gIGQ6IFBpY2s8RHJhd25UcmFuc2NyaXB0cywgJ21lcmdlZCcgfCAncmFkaXVzJyB8ICdncmlkJz4sIHg6IG51bWJlciwgeTogbnVtYmVyLCB0b2xlcmFuY2U6IG51bWJlcixcbik6IG51bWJlciB7XG4gIGNvbnN0IHQgPSBkLm1lcmdlZDtcbiAgaWYgKCFkLmdyaWQpIHtcbiAgICBsZXQgbWF4UiA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0LmNvdW50OyBpKyspIGlmIChkLnJhZGl1c1tpXSA+IG1heFIpIG1heFIgPSBkLnJhZGl1c1tpXTtcbiAgICBjb25zdCBzaXplID0gTWF0aC5tYXgobWF4UiAqIDIsIHRvbGVyYW5jZSAqIDIsIDFlLTYpO1xuICAgIGNvbnN0IGJ1Y2tldHMgPSBuZXcgTWFwPG51bWJlciwgbnVtYmVyW10+KCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0LmNvdW50OyBpKyspIHtcbiAgICAgIGNvbnN0IGsgPSBidWNrZXRLZXkoTWF0aC5mbG9vcih0LnhbaV0gLyBzaXplKSwgTWF0aC5mbG9vcih0LnlbaV0gLyBzaXplKSk7XG4gICAgICBsZXQgYiA9IGJ1Y2tldHMuZ2V0KGspO1xuICAgICAgaWYgKCFiKSBidWNrZXRzLnNldChrLCAoYiA9IFtdKSk7XG4gICAgICBiLnB1c2goaSk7XG4gICAgfVxuICAgIGQuZ3JpZCA9IHsgc2l6ZSwgYnVja2V0cyB9O1xuICB9XG4gIGNvbnN0IHsgc2l6ZSwgYnVja2V0cyB9ID0gZC5ncmlkO1xuICBjb25zdCBneCA9IE1hdGguZmxvb3IoeCAvIHNpemUpO1xuICBjb25zdCBneSA9IE1hdGguZmxvb3IoeSAvIHNpemUpO1xuICBsZXQgYmVzdCA9IC0xO1xuICBsZXQgYmVzdEQgPSBJbmZpbml0eTtcbiAgZm9yIChsZXQgZHkgPSAtMTsgZHkgPD0gMTsgZHkrKykge1xuICAgIGZvciAobGV0IGR4ID0gLTE7IGR4IDw9IDE7IGR4KyspIHtcbiAgICAgIGZvciAoY29uc3QgaSBvZiBidWNrZXRzLmdldChidWNrZXRLZXkoZ3ggKyBkeCwgZ3kgKyBkeSkpID8/IFtdKSB7XG4gICAgICAgIGNvbnN0IGRpc3QgPSBNYXRoLmh5cG90KHQueFtpXSAtIHgsIHQueVtpXSAtIHkpO1xuICAgICAgICBpZiAoZGlzdCA8PSBNYXRoLm1heChkLnJhZGl1c1tpXSwgdG9sZXJhbmNlKSAmJiBkaXN0IDwgYmVzdEQpIHtcbiAgICAgICAgICBiZXN0RCA9IGRpc3Q7XG4gICAgICAgICAgYmVzdCA9IGk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGJlc3Q7XG59XG5cbmZ1bmN0aW9uIGJ1Y2tldEtleShneDogbnVtYmVyLCBneTogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIChneCArIDMyNzY4KSAqIDY1NTM2ICsgKGd5ICsgMzI3NjgpO1xufVxuXG4vKiogUmluZ3Mgd2hvc2Ugb3duaW5nIGNlbGwgaXMgaW4gYSBzd2l0Y2hlZC1vZmYgZ3JvdXAgcmVtb3ZlZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXJSaW5ncyhcbiAgcmluZ3M6IFNwYXRpYWxQb2x5Z29uVGlsZSwgaGlkZGVuOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsLFxuKTogU3BhdGlhbFBvbHlnb25UaWxlIHtcbiAgaWYgKCFoaWRkZW4pIHJldHVybiByaW5ncztcbiAgY29uc3Qga2VlcDogbnVtYmVyW10gPSBbXTtcbiAgbGV0IHZlcnRpY2VzID0gMDtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCByaW5ncy5jb3VudDsgaSsrKSB7XG4gICAgY29uc3QgY29kZSA9IGhpZGRlbi5jb2Rlc1tyaW5ncy5vYnNlcnZhdGlvbltpXV07XG4gICAgaWYgKGNvZGUgIT09IE5PX0NBVEVHT1JZICYmIGhpZGRlbi5oaWRkZW5bY29kZV0pIGNvbnRpbnVlO1xuICAgIGtlZXAucHVzaChpKTtcbiAgICB2ZXJ0aWNlcyArPSByaW5ncy5vZmZzZXRzW2kgKyAxXSAtIHJpbmdzLm9mZnNldHNbaV07XG4gIH1cbiAgaWYgKGtlZXAubGVuZ3RoID09PSByaW5ncy5jb3VudCkgcmV0dXJuIHJpbmdzO1xuICBjb25zdCBvYnNlcnZhdGlvbiA9IG5ldyBVaW50MzJBcnJheShrZWVwLmxlbmd0aCk7XG4gIGNvbnN0IG9mZnNldHMgPSBuZXcgVWludDMyQXJyYXkoa2VlcC5sZW5ndGggKyAxKTtcbiAgY29uc3QgY29vcmRzID0gbmV3IEZsb2F0MzJBcnJheSh2ZXJ0aWNlcyAqIDIpO1xuICBsZXQgdiA9IDA7XG4gIGtlZXAuZm9yRWFjaCgoaSwgcikgPT4ge1xuICAgIG9ic2VydmF0aW9uW3JdID0gcmluZ3Mub2JzZXJ2YXRpb25baV07XG4gICAgb2Zmc2V0c1tyXSA9IHY7XG4gICAgY29uc3QgYSA9IHJpbmdzLm9mZnNldHNbaV0gKiAyO1xuICAgIGNvbnN0IGIgPSByaW5ncy5vZmZzZXRzW2kgKyAxXSAqIDI7XG4gICAgY29vcmRzLnNldChyaW5ncy5jb29yZHMuc3ViYXJyYXkoYSwgYiksIHYgKiAyKTtcbiAgICB2ICs9IChiIC0gYSkgLyAyO1xuICB9KTtcbiAgb2Zmc2V0c1trZWVwLmxlbmd0aF0gPSB2O1xuICByZXR1cm4geyBjb3VudDoga2VlcC5sZW5ndGgsIG9ic2VydmF0aW9uLCBvZmZzZXRzLCBjb29yZHMgfTtcbn1cblxuLyoqIFNsb3RzIChpbmRpY2VzIGludG8gdGhlIHNlbGVjdGVkIGdlbmVzKSBzd2l0Y2hlZCBvZmYgd2l0aCB0aGVpciBleWUgdG9nZ2xlLiAqL1xuZnVuY3Rpb24gaGlkZGVuR2VuZVNsb3RzKHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiBVaW50OEFycmF5IHwgbnVsbCB7XG4gIGlmICghdmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMubGVuZ3RoKSByZXR1cm4gbnVsbDtcbiAgY29uc3Qgb2ZmID0gbmV3IFNldCh2aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcyk7XG4gIHJldHVybiBVaW50OEFycmF5LmZyb20odmlldy50cmFuc2NyaXB0R2VuZXMsIChnKSA9PiAob2ZmLmhhcyhnKSA/IDEgOiAwKSk7XG59XG5cbi8qKiBFbnRyaWVzIGluIGEgaGlkZGVuIGdyb3VwJ3MgY2VsbCwgb3Igb2YgYSBoaWRkZW4gZ2VuZSwgcmVtb3ZlZCAod2l0aCB0aGVpciBzaXplcykuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyVHJhbnNjcmlwdHMoXG4gIHQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSwgcHg6IEZsb2F0MzJBcnJheSxcbiAgaGlkZGVuOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsLCBoaWRkZW5HZW5lczogVWludDhBcnJheSB8IG51bGwsXG4pOiB7IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlOyBweDogRmxvYXQzMkFycmF5IH0ge1xuICBpZiAoIWhpZGRlbiAmJiAhaGlkZGVuR2VuZXMpIHJldHVybiB7IG1lcmdlZDogdCwgcHggfTtcbiAgY29uc3Qga2VlcDogbnVtYmVyW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0LmNvdW50OyBpKyspIHtcbiAgICBpZiAoaGlkZGVuR2VuZXMgJiYgaGlkZGVuR2VuZXNbdC5nZW5lW2ldXSkgY29udGludWU7XG4gICAgY29uc3QgbyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgaWYgKGhpZGRlbiAmJiBvICE9PSBOT19PQlNFUlZBVElPTikge1xuICAgICAgY29uc3QgY29kZSA9IGhpZGRlbi5jb2Rlc1tvXTtcbiAgICAgIGlmIChjb2RlICE9PSBOT19DQVRFR09SWSAmJiBoaWRkZW4uaGlkZGVuW2NvZGVdKSBjb250aW51ZTtcbiAgICB9XG4gICAga2VlcC5wdXNoKGkpO1xuICB9XG4gIGNvbnN0IHBpY2sgPSA8VCBleHRlbmRzIEZsb2F0MzJBcnJheSB8IFVpbnQzMkFycmF5IHwgVWludDE2QXJyYXk+KGE6IFQpOiBUID0+IHtcbiAgICBjb25zdCBvdXQgPSBuZXcgKGEuY29uc3RydWN0b3IgYXMgbmV3IChuOiBudW1iZXIpID0+IFQpKGtlZXAubGVuZ3RoKTtcbiAgICBrZWVwLmZvckVhY2goKGksIGspID0+IHsgb3V0W2tdID0gYVtpXTsgfSk7XG4gICAgcmV0dXJuIG91dDtcbiAgfTtcbiAgcmV0dXJuIHtcbiAgICBtZXJnZWQ6IHtcbiAgICAgIGNvdW50OiBrZWVwLmxlbmd0aCwgYWdncmVnYXRlZDogdC5hZ2dyZWdhdGVkLCB4OiBwaWNrKHQueCksIHk6IHBpY2sodC55KSwgejogcGljayh0LnopLFxuICAgICAgd2VpZ2h0OiBwaWNrKHQud2VpZ2h0KSwgb2JzZXJ2YXRpb246IHBpY2sodC5vYnNlcnZhdGlvbiksIGdlbmU6IHBpY2sodC5nZW5lKSxcbiAgICB9LFxuICAgIHB4OiBwaWNrKHB4KSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gbWVkaWFuKHY6IEZsb2F0MzJBcnJheSk6IG51bWJlciB7XG4gIGlmICghdi5sZW5ndGgpIHJldHVybiAwO1xuICBjb25zdCBzdGVwID0gTWF0aC5tYXgoMSwgTWF0aC5mbG9vcih2Lmxlbmd0aCAvIDEwMjQpKTtcbiAgY29uc3Qgc2FtcGxlOiBudW1iZXJbXSA9IFtdO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHYubGVuZ3RoOyBpICs9IHN0ZXApIHNhbXBsZS5wdXNoKHZbaV0pO1xuICBzYW1wbGUuc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICByZXR1cm4gc2FtcGxlW3NhbXBsZS5sZW5ndGggPj4gMV07XG59XG5cbi8qKiBDb25jYXRlbmF0ZSB0aWxlcycgcmluZ3MgaW50byBvbmUgc2V0LCBkcm9wcGluZyByaW5ncyBhbHJlYWR5IHNlZW4gKGEgY2VsbCBzdHJhZGRsaW5nXG4gKiAgdHdvIHRpbGVzIG1heSBiZSBsaXN0ZWQgYnkgYm90aCkuICovXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VQb2x5Z29uVGlsZXModGlsZXM6IFNwYXRpYWxQb2x5Z29uVGlsZVtdKTogU3BhdGlhbFBvbHlnb25UaWxlIHtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICBsZXQgcmluZ3MgPSAwO1xuICBsZXQgdmVydGljZXMgPSAwO1xuICBmb3IgKGNvbnN0IHQgb2YgdGlsZXMpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgaWYgKHNlZW4uaGFzKHQub2JzZXJ2YXRpb25baV0pKSBjb250aW51ZTtcbiAgICAgIHNlZW4uYWRkKHQub2JzZXJ2YXRpb25baV0pO1xuICAgICAgcmluZ3MrKztcbiAgICAgIHZlcnRpY2VzICs9IHQub2Zmc2V0c1tpICsgMV0gLSB0Lm9mZnNldHNbaV07XG4gICAgfVxuICB9XG4gIHNlZW4uY2xlYXIoKTtcbiAgY29uc3Qgb2JzZXJ2YXRpb24gPSBuZXcgVWludDMyQXJyYXkocmluZ3MpO1xuICBjb25zdCBvZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KHJpbmdzICsgMSk7XG4gIGNvbnN0IGNvb3JkcyA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGljZXMgKiAyKTtcbiAgbGV0IHIgPSAwO1xuICBsZXQgdiA9IDA7XG4gIGZvciAoY29uc3QgdCBvZiB0aWxlcykge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCBvID0gdC5vYnNlcnZhdGlvbltpXTtcbiAgICAgIGlmIChzZWVuLmhhcyhvKSkgY29udGludWU7XG4gICAgICBzZWVuLmFkZChvKTtcbiAgICAgIG9ic2VydmF0aW9uW3JdID0gbztcbiAgICAgIG9mZnNldHNbcl0gPSB2O1xuICAgICAgY29uc3QgYSA9IHQub2Zmc2V0c1tpXSAqIDI7XG4gICAgICBjb25zdCBiID0gdC5vZmZzZXRzW2kgKyAxXSAqIDI7XG4gICAgICBjb29yZHMuc2V0KHQuY29vcmRzLnN1YmFycmF5KGEsIGIpLCB2ICogMik7XG4gICAgICB2ICs9IChiIC0gYSkgLyAyO1xuICAgICAgcisrO1xuICAgIH1cbiAgfVxuICBvZmZzZXRzW3JpbmdzXSA9IHY7XG4gIHJldHVybiB7IGNvdW50OiByaW5ncywgb2JzZXJ2YXRpb24sIG9mZnNldHMsIGNvb3JkcyB9O1xufVxuXG4vKiogQ29uY2F0ZW5hdGUgdHJhbnNjcmlwdCB0aWxlcywgc3RvcHBpbmcgYXQgYGxpbWl0YCBlbnRyaWVzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlVHJhbnNjcmlwdFRpbGVzKHRpbGVzOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGVbXSwgbGltaXQgPSBJbmZpbml0eSk6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSB7XG4gIGxldCBuID0gMDtcbiAgZm9yIChjb25zdCB0IG9mIHRpbGVzKSBuICs9IHQuY291bnQ7XG4gIG4gPSBNYXRoLm1pbihuLCBsaW1pdCk7XG4gIGNvbnN0IG91dDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlID0ge1xuICAgIGNvdW50OiBuLFxuICAgIGFnZ3JlZ2F0ZWQ6IHRpbGVzLnNvbWUoKHQpID0+IHQuYWdncmVnYXRlZCksXG4gICAgeDogbmV3IEZsb2F0MzJBcnJheShuKSwgeTogbmV3IEZsb2F0MzJBcnJheShuKSwgejogbmV3IEZsb2F0MzJBcnJheShuKSxcbiAgICB3ZWlnaHQ6IG5ldyBVaW50MzJBcnJheShuKSwgb2JzZXJ2YXRpb246IG5ldyBVaW50MzJBcnJheShuKSwgZ2VuZTogbmV3IFVpbnQxNkFycmF5KG4pLFxuICB9O1xuICBsZXQgbyA9IDA7XG4gIGZvciAoY29uc3QgdCBvZiB0aWxlcykge1xuICAgIGNvbnN0IGsgPSBNYXRoLm1pbih0LmNvdW50LCBuIC0gbyk7XG4gICAgaWYgKGsgPD0gMCkgYnJlYWs7XG4gICAgZm9yIChjb25zdCBmIG9mIFsneCcsICd5JywgJ3onLCAnd2VpZ2h0JywgJ29ic2VydmF0aW9uJywgJ2dlbmUnXSBhcyBjb25zdCkge1xuICAgICAgKG91dFtmXSBhcyBGbG9hdDMyQXJyYXkpLnNldCgodFtmXSBhcyBGbG9hdDMyQXJyYXkpLnN1YmFycmF5KDAsIGspLCBvKTtcbiAgICB9XG4gICAgbyArPSBrO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG4iXX0=
|