@jax-data-science/sci-image-visualizer 0.16.0 → 0.18.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 +4 -2
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +1 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/geometry/cell-meshes.mjs +37 -0
- package/esm2022/lib/geometry/place.mjs +47 -0
- package/esm2022/lib/implementations/napari-js/napari-camera-depth.mjs +93 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +86 -18
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-cells.mjs +746 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +343 -18
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +427 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +11 -4
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +95 -5
- package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +15 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +35 -8
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +40 -1
- package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +136 -28
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +19 -3
- package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +188 -52
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +35 -11
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +2 -2
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +10 -1
- package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +30 -3
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +15 -3
- package/esm2022/lib/region-editor/region-editor.component.mjs +24 -4
- package/esm2022/lib/region-source/region-source-ops.mjs +7 -1
- package/esm2022/lib/region-source/region-tiles.mjs +1 -1
- package/esm2022/lib/region-source/worker-region-source.mjs +24 -1
- package/esm2022/lib/routing-visualizer.service.mjs +404 -7
- package/esm2022/lib/spatial/observations-in-selection.mjs +83 -0
- package/esm2022/lib/spatial/plane-cells.mjs +119 -0
- package/esm2022/lib/spatial/spatial-controls.facade.mjs +304 -8
- package/esm2022/lib/spatial/spatial-encoding.mjs +52 -3
- package/esm2022/lib/spatial/spatial-hover.mjs +34 -1
- package/esm2022/lib/spatial/spatial-planes.mjs +49 -0
- package/esm2022/lib/spatial/spatial-selection.mjs +2 -2
- package/esm2022/lib/spatial/spatial-tile-merge.mjs +38 -1
- package/esm2022/lib/spatial/transcripts-in-selection.mjs +208 -0
- package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +42 -65
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +6 -2
- package/esm2022/lib/spatial-controls/spatial-color-by/spatial-color-by.component.mjs +187 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +51 -12
- package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +7 -3
- package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +21 -6
- package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +94 -13
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +79 -57
- package/esm2022/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.mjs +101 -0
- package/esm2022/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.mjs +94 -0
- package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +9 -3
- package/esm2022/lib/store/region-source-scope.mjs +10 -1
- package/esm2022/lib/store/region-store.service.mjs +33 -2
- package/esm2022/lib/toolbar/toolbar.component.mjs +10 -3
- package/esm2022/lib/visualizer/spatial-region-set.mjs +95 -0
- package/esm2022/lib/visualizer.component.mjs +40 -4
- package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CYsPzX3J.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs} +4838 -656
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs.map +1 -0
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DaZVXq1s.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs} +2 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DaZVXq1s.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs.map} +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
- package/fesm2022/region-source.worker.js +84 -2
- package/lib/contracts/display-types.d.ts +99 -6
- package/lib/contracts/image.contract.d.ts +6 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +7 -0
- package/lib/contracts/region-editor-api.contract.d.ts +9 -0
- package/lib/contracts/region-store.contract.d.ts +6 -0
- package/lib/contracts/spatial-dataset.contract.d.ts +7 -1
- package/lib/contracts/visualizer.contract.d.ts +43 -1
- package/lib/geometry/cell-meshes.d.ts +27 -0
- package/lib/geometry/place.d.ts +45 -0
- package/lib/implementations/napari-js/napari-camera-depth.d.ts +23 -0
- package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
- package/lib/implementations/napari-js/napari-scene.d.ts +12 -0
- package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +19 -3
- package/lib/implementations/napari-js/napari-spatial-3d-cells.d.ts +141 -0
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +89 -0
- package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +103 -0
- package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +9 -2
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +22 -0
- package/lib/implementations/napari-js/napari-spatial-scene.d.ts +12 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +20 -6
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +27 -1
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +48 -16
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +2 -0
- package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +54 -1
- package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +11 -2
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +7 -0
- package/lib/region-editor/class-tree/class-tree.component.d.ts +16 -1
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +10 -1
- package/lib/region-editor/region-editor.component.d.ts +4 -0
- package/lib/region-source/region-source-ops.d.ts +12 -0
- package/lib/region-source/region-tiles.d.ts +8 -0
- package/lib/region-source/worker-region-source.d.ts +18 -0
- package/lib/routing-visualizer.service.d.ts +140 -1
- package/lib/spatial/observations-in-selection.d.ts +43 -0
- package/lib/spatial/plane-cells.d.ts +37 -0
- package/lib/spatial/spatial-controls.facade.d.ts +59 -0
- package/lib/spatial/spatial-encoding.d.ts +24 -1
- package/lib/spatial/spatial-hover.d.ts +23 -0
- package/lib/spatial/spatial-planes.d.ts +22 -0
- package/lib/spatial/spatial-selection.d.ts +2 -1
- package/lib/spatial/spatial-tile-merge.d.ts +9 -0
- package/lib/spatial/transcripts-in-selection.d.ts +95 -0
- package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +19 -28
- package/lib/spatial-controls/spatial-color-by/spatial-color-by.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +19 -2
- package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +3 -1
- package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +7 -0
- package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +28 -7
- package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +26 -23
- package/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.d.ts +48 -0
- package/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.d.ts +43 -0
- package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +3 -1
- package/lib/store/region-source-scope.d.ts +4 -0
- package/lib/store/region-store.service.d.ts +21 -0
- package/lib/toolbar/toolbar.component.d.ts +6 -1
- package/lib/visualizer/spatial-region-set.d.ts +55 -0
- package/lib/visualizer.component.d.ts +14 -0
- package/package.json +2 -2
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CYsPzX3J.mjs.map +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { ALL_GENES } from '../../contracts/ports/spatial-data.port';
|
|
2
|
+
import { NO_CATEGORY, NO_OBSERVATION, isCategoricalColumn, } from '../../contracts/spatial-dataset.contract';
|
|
3
|
+
import { DEFAULT_CATEGORICAL_PALETTE, DEFAULT_MUTED_OPACITY, categoryColorsFor, parseHex, } from '../../spatial/spatial-encoding';
|
|
4
|
+
import { allGeneShownBy, allGenesHidden } from '../../spatial/spatial-tile-merge';
|
|
5
|
+
import { cellTypeColumnFor } from '../../spatial/spatial-tiles';
|
|
6
|
+
import { clusterColorMap, clusterOfGene } from '../../spatial/transcript-grouping';
|
|
7
|
+
import { tilesInRect, transcriptLevelFor } from '../../spatial/lod';
|
|
8
|
+
import { Supersede } from '../../util/supersede';
|
|
9
|
+
/** Most transcripts drawn in the 3D view: past it, every k-th one is drawn (and the console says so). */
|
|
10
|
+
export const TRANSCRIPTS_3D_MAX = 2_000_000;
|
|
11
|
+
/** Most level-0 tiles read for the 3D view: a dataset needing more is too large to draw whole. */
|
|
12
|
+
export const TRANSCRIPTS_3D_MAX_TILES = 4096;
|
|
13
|
+
/** Tile reads in flight at once. */
|
|
14
|
+
const CONCURRENCY = 8;
|
|
15
|
+
/** The camera resting this long plans the transcripts' detail again. */
|
|
16
|
+
const CAMERA_REST_MS = 300;
|
|
17
|
+
/** Transcript tiles kept read. */
|
|
18
|
+
const TILE_CACHE_SIZE = 1024;
|
|
19
|
+
/** Most tiles read for one view: past them, a coarser level. */
|
|
20
|
+
const VIEW_TILES_MAX = 256;
|
|
21
|
+
/** How far along a ray that never meets the section's plane its reach is taken (world units). */
|
|
22
|
+
const HORIZON = 1e6;
|
|
23
|
+
/** A transcript's marker in the 3D view, in screen pixels at a transcript scale of 1. */
|
|
24
|
+
export const TRANSCRIPT_3D_BASE_SIZE = 2;
|
|
25
|
+
/** A transcript with no colour by cell type (in no cell, or a cell in no group), as the 2D markers. */
|
|
26
|
+
const UNASSIGNED_RGBA = [0.62, 0.62, 0.62, 0.55];
|
|
27
|
+
/** The genes a view draws in 3D, as the tile query takes them, or null when it draws none. */
|
|
28
|
+
export function transcripts3dGenes(dataset, view) {
|
|
29
|
+
if (view.transcriptMode === 'off')
|
|
30
|
+
return null;
|
|
31
|
+
if (view.transcriptAllGenes) {
|
|
32
|
+
if (allGenesHidden(view))
|
|
33
|
+
return null;
|
|
34
|
+
return { query: [ALL_GENES], allGenes: true };
|
|
35
|
+
}
|
|
36
|
+
const hidden = new Set(view.transcriptHiddenGenes);
|
|
37
|
+
const genes = view.transcriptGenes.filter((g) => !hidden.has(g));
|
|
38
|
+
return genes.length ? { query: genes, allGenes: false } : null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Each loaded transcript's colour, packed RGBA, as the 2D markers colour them by gene: a gene's
|
|
42
|
+
* chosen colour, else the palette's by its slot (the selection's order, or with "All genes" the
|
|
43
|
+
* dataset's gene code).
|
|
44
|
+
*/
|
|
45
|
+
export function transcripts3dColors(view, names, gene, count) {
|
|
46
|
+
const n = names ? names.length : DEFAULT_CATEGORICAL_PALETTE.length;
|
|
47
|
+
const table = Array.from({ length: n }, (_g, i) => rgba01((names && view.transcriptGeneColors[names[i]]) ||
|
|
48
|
+
DEFAULT_CATEGORICAL_PALETTE[i % DEFAULT_CATEGORICAL_PALETTE.length]));
|
|
49
|
+
return packed(count, (i) => table[names ? gene[i] : gene[i] % n]);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* How the panel's "Colour by" applies in 3D, as it does to the 2D markers (`colorViewFor`): by
|
|
53
|
+
* cell type when the dataset has one (else by gene), by cluster for the selected genes (with "All
|
|
54
|
+
* genes" a cluster is its gene), by gene otherwise.
|
|
55
|
+
*/
|
|
56
|
+
export function transcripts3dColorBy(dataset, view, allGenes) {
|
|
57
|
+
const by = view.transcriptColorBy;
|
|
58
|
+
if (by === 'cellType')
|
|
59
|
+
return cellTypeColumnFor(dataset, view) ? 'cellType' : 'gene';
|
|
60
|
+
if (by === 'cluster' && !allGenes)
|
|
61
|
+
return 'cluster';
|
|
62
|
+
return 'gene';
|
|
63
|
+
}
|
|
64
|
+
/** The colours the cells' grouping gives its groups, by name (none without a grouping). */
|
|
65
|
+
async function cellGroupColors(dataset, view, port) {
|
|
66
|
+
const name = cellTypeColumnFor(dataset, view);
|
|
67
|
+
if (!name)
|
|
68
|
+
return null;
|
|
69
|
+
const column = await port.getColumn(name);
|
|
70
|
+
if (!isCategoricalColumn(column))
|
|
71
|
+
return null;
|
|
72
|
+
const hex = categoryColorsFor(name, column.meta, view.groupColors);
|
|
73
|
+
const byName = new Map(column.meta.categories.map((c, k) => [c, hex[k]]));
|
|
74
|
+
return { codes: column.codes, colors: hex.map(rgba01), byName };
|
|
75
|
+
}
|
|
76
|
+
/** `#rrggbb` as an opaque 0..1 RGBA. */
|
|
77
|
+
function rgba01(hex) {
|
|
78
|
+
const [r, g, b] = parseHex(hex);
|
|
79
|
+
return [r / 255, g / 255, b / 255, 1];
|
|
80
|
+
}
|
|
81
|
+
/** `count` colours packed RGBA, unassigned where `at` has none. */
|
|
82
|
+
function packed(count, at) {
|
|
83
|
+
const out = new Float32Array(count * 4);
|
|
84
|
+
for (let i = 0; i < count; i++)
|
|
85
|
+
out.set(at(i) ?? UNASSIGNED_RGBA, i * 4);
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The transcripts of the 3D spatial view: the molecules of the genes the Transcripts panel draws
|
|
90
|
+
* (its selected genes, or "All genes"), at their own x, y and z, in the cloud's box and Z stretch.
|
|
91
|
+
*
|
|
92
|
+
* By level of detail, as the 2D view reads them: the pyramid level the camera's distance calls for
|
|
93
|
+
* (`transcriptLevelFor`, the markers per screen kept about constant: aggregates far out, every
|
|
94
|
+
* molecule close in on a cell), and only the tiles of the part of the section in view (the canvas's
|
|
95
|
+
* corners cast onto the section's plane). Planned again when the camera rests; tiles are cached, so
|
|
96
|
+
* coming back reads nothing. "Loading transcripts…" shows on the canvas while they load and draw.
|
|
97
|
+
* Drawn only for a dataset whose transcripts carry z.
|
|
98
|
+
*/
|
|
99
|
+
export class Spatial3dTranscripts {
|
|
100
|
+
constructor(viewer, begin) {
|
|
101
|
+
this.viewer = viewer;
|
|
102
|
+
this.begin = begin;
|
|
103
|
+
this.layer = null;
|
|
104
|
+
/** What {@link layer} was loaded from (dataset, genes, quality), and styled with. */
|
|
105
|
+
this.loadKey = null;
|
|
106
|
+
this.styleKey = null;
|
|
107
|
+
this.loaded = null;
|
|
108
|
+
this.loads = new Supersede();
|
|
109
|
+
/** Each drawn transcript's cell ({@link NO_OBSERVATION} for none), for fading by the selection. */
|
|
110
|
+
this.drawnCells = null;
|
|
111
|
+
/** The selection the layer's alphas fade by (null: none, every transcript as it is). */
|
|
112
|
+
this.fadedBy = null;
|
|
113
|
+
/** The last sync's inputs: the camera resting plans the detail again from them. */
|
|
114
|
+
this.last = null;
|
|
115
|
+
this.cameraTimer = null;
|
|
116
|
+
this.cameraOff = null;
|
|
117
|
+
/** Tiles read, by genes, quality, level and tile (least recently used dropped first). */
|
|
118
|
+
this.tileCache = new Map();
|
|
119
|
+
this.cameraOff = viewer.camera3d?.changed?.connect(() => this.cameraMoved()) ?? null;
|
|
120
|
+
}
|
|
121
|
+
/** The camera moved: once it rests, read the level and tiles it now calls for. */
|
|
122
|
+
cameraMoved() {
|
|
123
|
+
if (!this.last)
|
|
124
|
+
return;
|
|
125
|
+
if (this.cameraTimer)
|
|
126
|
+
clearTimeout(this.cameraTimer);
|
|
127
|
+
this.cameraTimer = setTimeout(() => {
|
|
128
|
+
this.cameraTimer = null;
|
|
129
|
+
const last = this.last;
|
|
130
|
+
if (last)
|
|
131
|
+
void this.sync(last.dataset, last.view, last.port, last.frame, last.selection);
|
|
132
|
+
}, CAMERA_REST_MS);
|
|
133
|
+
}
|
|
134
|
+
/** Stop following the camera (the scene went away). */
|
|
135
|
+
dispose() {
|
|
136
|
+
this.cameraOff?.();
|
|
137
|
+
this.cameraOff = null;
|
|
138
|
+
if (this.cameraTimer)
|
|
139
|
+
clearTimeout(this.cameraTimer);
|
|
140
|
+
this.cameraTimer = null;
|
|
141
|
+
this.last = null;
|
|
142
|
+
this.remove();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The level and the tiles the camera calls for: the level whose tiles come out about 512 screen
|
|
146
|
+
* pixels across at the target's depth, the tiles of the section in view (whole, when a corner of
|
|
147
|
+
* the canvas looks past the section's plane).
|
|
148
|
+
*/
|
|
149
|
+
plan(meta, frame) {
|
|
150
|
+
const [vw, vh] = this.viewer.viewportSize?.() ?? [0, 0];
|
|
151
|
+
const camera = this.viewer.camera3d;
|
|
152
|
+
const wpp = camera && vh > 0 ? camera.worldPerPixel(vh) : 0;
|
|
153
|
+
let level = wpp > 0 ? transcriptLevelFor(1 / wpp, meta.levels) : meta.levels.length - 1;
|
|
154
|
+
const [x0, y0, x1, y1] = meta.bounds;
|
|
155
|
+
let rect = { x0, y0, x1: x1 + 1e-6, y1: y1 + 1e-6 };
|
|
156
|
+
const seen = vw > 0 && vh > 0 ? this.footprint(vw, vh, frame) : null;
|
|
157
|
+
if (seen)
|
|
158
|
+
rect = seen;
|
|
159
|
+
// Close in but looking far across the section: coarser, until the tiles in view are few enough.
|
|
160
|
+
let keys = tilesInRect(rect, level, meta.levels, meta.bounds);
|
|
161
|
+
while (keys.length > VIEW_TILES_MAX && level < meta.levels.length - 1) {
|
|
162
|
+
level++;
|
|
163
|
+
keys = tilesInRect(rect, level, meta.levels, meta.bounds);
|
|
164
|
+
}
|
|
165
|
+
return { level, keys };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The part of the section the canvas sees, in observation units: its corners and centre cast onto
|
|
169
|
+
* the plane through the camera's target, widened by a quarter. A corner looking past the plane
|
|
170
|
+
* (towards the horizon) reaches far along its ray instead (the tiles are clipped to the section).
|
|
171
|
+
*/
|
|
172
|
+
footprint(vw, vh, frame) {
|
|
173
|
+
const z = this.viewer.camera3d?.target?.[2];
|
|
174
|
+
if (z === undefined || !this.viewer.canvasRay)
|
|
175
|
+
return null;
|
|
176
|
+
const [ox, oy] = frame.origin;
|
|
177
|
+
let xa = Infinity, ya = Infinity, xb = -Infinity, yb = -Infinity;
|
|
178
|
+
for (const [cx, cy] of [
|
|
179
|
+
[0, 0],
|
|
180
|
+
[vw, 0],
|
|
181
|
+
[0, vh],
|
|
182
|
+
[vw, vh],
|
|
183
|
+
[vw / 2, vh / 2],
|
|
184
|
+
]) {
|
|
185
|
+
const ray = this.viewer.canvasRay(cx, cy);
|
|
186
|
+
if (!ray)
|
|
187
|
+
return null;
|
|
188
|
+
const hit = Math.abs(ray.dir[2]) > 1e-6 ? (z - ray.origin[2]) / ray.dir[2] : -1;
|
|
189
|
+
const t = hit > 0 ? hit : HORIZON;
|
|
190
|
+
const x = ray.origin[0] + ray.dir[0] * t - ox;
|
|
191
|
+
const y = ray.origin[1] + ray.dir[1] * t - oy;
|
|
192
|
+
xa = Math.min(xa, x);
|
|
193
|
+
ya = Math.min(ya, y);
|
|
194
|
+
xb = Math.max(xb, x);
|
|
195
|
+
yb = Math.max(yb, y);
|
|
196
|
+
}
|
|
197
|
+
const mx = (xb - xa) / 4;
|
|
198
|
+
const my = (yb - ya) / 4;
|
|
199
|
+
return { x0: xa - mx, y0: ya - my, x1: xb + mx, y1: yb + my };
|
|
200
|
+
}
|
|
201
|
+
/** A tile, read once (and again only once dropped from the cache). */
|
|
202
|
+
tile(key, read) {
|
|
203
|
+
let hit = this.tileCache.get(key);
|
|
204
|
+
if (hit) {
|
|
205
|
+
this.tileCache.delete(key);
|
|
206
|
+
this.tileCache.set(key, hit);
|
|
207
|
+
return hit;
|
|
208
|
+
}
|
|
209
|
+
hit = read();
|
|
210
|
+
hit.catch(() => this.tileCache.delete(key));
|
|
211
|
+
this.tileCache.set(key, hit);
|
|
212
|
+
while (this.tileCache.size > TILE_CACHE_SIZE)
|
|
213
|
+
this.tileCache.delete(this.tileCache.keys().next().value);
|
|
214
|
+
return hit;
|
|
215
|
+
}
|
|
216
|
+
/** The layer drawn, if any (for tests and the scene's Z stretch). */
|
|
217
|
+
get drawn() {
|
|
218
|
+
return this.layer;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Draw what `view` asks for, loading the molecules when the genes changed. With a `selection`
|
|
222
|
+
* (a cell, or a cell type's cells), the transcripts of the selected cells keep their colour and
|
|
223
|
+
* the others fade, as the cells do.
|
|
224
|
+
*/
|
|
225
|
+
async sync(dataset, view, port, frame, selection = null) {
|
|
226
|
+
const meta = dataset.transcriptTiles;
|
|
227
|
+
const genes = meta?.hasZ && port?.getTranscriptTile ? transcripts3dGenes(dataset, view) : null;
|
|
228
|
+
if (!meta || !genes || !port) {
|
|
229
|
+
// Off (or no gene shown): a camera move must not bring back the last view that drew some.
|
|
230
|
+
this.last = null;
|
|
231
|
+
if (this.cameraTimer)
|
|
232
|
+
clearTimeout(this.cameraTimer);
|
|
233
|
+
this.cameraTimer = null;
|
|
234
|
+
this.remove();
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.last = { dataset, view, port, frame, selection };
|
|
238
|
+
const quality = view.transcriptQuality === 'all' ? 'all' : 'high';
|
|
239
|
+
const { level, keys } = this.plan(meta, frame);
|
|
240
|
+
const genesKey = `${dataset.id}|${genes.query.join('\u0001')}|${quality}`;
|
|
241
|
+
const loadKey = `${genesKey}|${level}|${keys.map((k) => `${k.gx},${k.gy}`).join(';')}`;
|
|
242
|
+
let end = null;
|
|
243
|
+
if (loadKey !== this.loadKey) {
|
|
244
|
+
const task = this.loads.next();
|
|
245
|
+
if (keys.length > TRANSCRIPTS_3D_MAX_TILES) {
|
|
246
|
+
console.warn(`[napari-js] ${keys.length} transcript tiles are too many to read for the 3D view`);
|
|
247
|
+
this.remove();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
end = this.begin('Loading transcripts…');
|
|
251
|
+
let tiles;
|
|
252
|
+
try {
|
|
253
|
+
tiles = await pooled(keys, CONCURRENCY, (k) => this.tile(`${genesKey}|${level}/${k.gx}/${k.gy}`, () => port.getTranscriptTile(level, k.gx, k.gy, { genes: genes.query, quality })));
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
console.warn('[napari-js] transcripts for the 3D view could not be read', err);
|
|
257
|
+
// The panel asked for other transcripts than those drawn: take them down rather than leave
|
|
258
|
+
// the old selection up as if it were the new one; the next change reads again. Only the
|
|
259
|
+
// current load may: a superseded one must not tear down what a newer one drew.
|
|
260
|
+
if (task())
|
|
261
|
+
this.clearLayer();
|
|
262
|
+
end();
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (!task()) {
|
|
266
|
+
end();
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this.loadKey = loadKey;
|
|
270
|
+
this.styleKey = null;
|
|
271
|
+
this.loaded = { tiles, names: genes.allGenes ? (meta.genes ?? null) : genes.query };
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
await this.draw(dataset, view, port, frame, genes.allGenes);
|
|
275
|
+
// The newest sync's selection: an older draw finishing late must not fade by a stale one.
|
|
276
|
+
if (this.last?.selection === selection)
|
|
277
|
+
this.fade(selection);
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
end?.();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/** Follow the scene's Z stretch (nothing is re-uploaded). */
|
|
284
|
+
setZScale(s) {
|
|
285
|
+
if (this.layer)
|
|
286
|
+
this.layer.scale3d = [1, 1, s];
|
|
287
|
+
}
|
|
288
|
+
/** Take the layer down and forget what it showed. */
|
|
289
|
+
remove() {
|
|
290
|
+
this.loads.cancel();
|
|
291
|
+
this.clearLayer();
|
|
292
|
+
}
|
|
293
|
+
clearLayer() {
|
|
294
|
+
if (this.layer)
|
|
295
|
+
this.viewer.layers.remove(this.layer);
|
|
296
|
+
this.layer = null;
|
|
297
|
+
this.loadKey = null;
|
|
298
|
+
this.styleKey = null;
|
|
299
|
+
this.loaded = null;
|
|
300
|
+
this.drawnCells = null;
|
|
301
|
+
this.fadedBy = null;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Fade the drawn transcripts outside the selection (their alpha only: the colours stay
|
|
305
|
+
* uploaded), or bring them all back without one. A no-op for the selection already applied.
|
|
306
|
+
*/
|
|
307
|
+
fade(selection) {
|
|
308
|
+
const live = selection && selection.count > 0 ? selection : null;
|
|
309
|
+
const layer = this.layer;
|
|
310
|
+
const cells = this.drawnCells;
|
|
311
|
+
if (!layer || !cells || live === this.fadedBy)
|
|
312
|
+
return;
|
|
313
|
+
this.fadedBy = live;
|
|
314
|
+
if (!live) {
|
|
315
|
+
layer.alphas = null;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const alphas = new Float32Array(cells.length);
|
|
319
|
+
for (let i = 0; i < cells.length; i++) {
|
|
320
|
+
const o = cells[i];
|
|
321
|
+
alphas[i] = o !== NO_OBSERVATION && o < live.mask.length && live.mask[o] ? 1 : DEFAULT_MUTED_OPACITY;
|
|
322
|
+
}
|
|
323
|
+
layer.alphas = alphas;
|
|
324
|
+
}
|
|
325
|
+
async draw(dataset, view, port, frame, allGenes) {
|
|
326
|
+
const loaded = this.loaded;
|
|
327
|
+
if (!loaded)
|
|
328
|
+
return;
|
|
329
|
+
const by = transcripts3dColorBy(dataset, view, allGenes);
|
|
330
|
+
const styleKey = [
|
|
331
|
+
frame.origin.join(','),
|
|
332
|
+
by,
|
|
333
|
+
by === 'gene' ? JSON.stringify(view.transcriptGeneColors) : '',
|
|
334
|
+
by !== 'gene' ? `${cellTypeColumnFor(dataset, view)}|${JSON.stringify(view.groupColors)}` : '',
|
|
335
|
+
by === 'cluster' ? JSON.stringify(view.transcriptGeneGroups) : '',
|
|
336
|
+
allGenes ? view.transcriptAllGenesHidden.join(',') : '',
|
|
337
|
+
].join('|');
|
|
338
|
+
const size = TRANSCRIPT_3D_BASE_SIZE * (view.transcriptScale > 0 ? view.transcriptScale : 1);
|
|
339
|
+
if (this.layer && styleKey === this.styleKey) {
|
|
340
|
+
this.layer.size = size;
|
|
341
|
+
this.layer.opacity = view.transcriptOpacity;
|
|
342
|
+
this.layer.scale3d = [1, 1, frame.zScale];
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const { names } = loaded;
|
|
346
|
+
const shown = allGenes && names ? allGeneShownBy(view.transcriptAllGenesHidden) : null;
|
|
347
|
+
const keep = shown && names ? (g) => !!names[g] && shown(names[g]) : () => true;
|
|
348
|
+
const total = loaded.tiles.reduce((n, t) => n + t.count, 0);
|
|
349
|
+
const stride = Math.max(1, Math.ceil(total / TRANSCRIPTS_3D_MAX));
|
|
350
|
+
if (stride > 1)
|
|
351
|
+
console.warn(`[napari-js] drawing every ${stride}th of ${total} transcripts in 3D`);
|
|
352
|
+
const [ox, oy, oz] = frame.origin;
|
|
353
|
+
const positions = [];
|
|
354
|
+
const genes = [];
|
|
355
|
+
const cells = [];
|
|
356
|
+
let seen = 0;
|
|
357
|
+
for (const t of loaded.tiles) {
|
|
358
|
+
for (let i = 0; i < t.count; i++) {
|
|
359
|
+
if (!keep(t.gene[i]) || seen++ % stride)
|
|
360
|
+
continue;
|
|
361
|
+
positions.push(t.x[i] + ox, t.y[i] + oy, t.z[i] + oz);
|
|
362
|
+
genes.push(t.gene[i]);
|
|
363
|
+
cells.push(t.observation[i]);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const count = genes.length;
|
|
367
|
+
let colors;
|
|
368
|
+
if (by === 'gene') {
|
|
369
|
+
colors = transcripts3dColors(view, names, Uint16Array.from(genes), count);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
const groups = await cellGroupColors(dataset, view, port).catch((err) => {
|
|
373
|
+
console.warn('[napari-js] the cells grouping for the 3D transcripts could not be read', err);
|
|
374
|
+
return null;
|
|
375
|
+
});
|
|
376
|
+
// A newer draw (another style, or the layer taken down) won while the column loaded.
|
|
377
|
+
if (this.loaded !== loaded)
|
|
378
|
+
return;
|
|
379
|
+
if (by === 'cellType') {
|
|
380
|
+
colors = packed(count, (i) => {
|
|
381
|
+
const o = cells[i];
|
|
382
|
+
const code = !groups || o === NO_OBSERVATION ? NO_CATEGORY : groups.codes[o];
|
|
383
|
+
return code === NO_CATEGORY ? undefined : groups.colors[code];
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
// A cluster named like a group of the cells' grouping takes that group's colour, as in 2D.
|
|
388
|
+
const byCluster = clusterColorMap(view.transcriptGenes, view.transcriptGeneGroups, groups?.byName ?? new Map(), DEFAULT_CATEGORICAL_PALETTE);
|
|
389
|
+
const table = (names ?? []).map((gene) => {
|
|
390
|
+
const hex = byCluster.get(clusterOfGene(gene, view.transcriptGeneGroups));
|
|
391
|
+
return hex ? rgba01(hex) : undefined;
|
|
392
|
+
});
|
|
393
|
+
colors = packed(count, (i) => table[genes[i]]);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (this.layer)
|
|
397
|
+
this.viewer.layers.remove(this.layer);
|
|
398
|
+
this.layer = null;
|
|
399
|
+
this.drawnCells = null;
|
|
400
|
+
this.fadedBy = null;
|
|
401
|
+
this.styleKey = styleKey;
|
|
402
|
+
if (!count)
|
|
403
|
+
return;
|
|
404
|
+
this.drawnCells = Uint32Array.from(cells);
|
|
405
|
+
this.layer = this.viewer.addPoints3D(Float32Array.from(positions), new Float32Array(count), {
|
|
406
|
+
name: 'transcripts',
|
|
407
|
+
size,
|
|
408
|
+
opacity: view.transcriptOpacity,
|
|
409
|
+
scale3d: [1, 1, frame.zScale],
|
|
410
|
+
colors,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/** `work` over `items`, at most `limit` at once, results in order. */
|
|
415
|
+
async function pooled(items, limit, work) {
|
|
416
|
+
const out = new Array(items.length);
|
|
417
|
+
let next = 0;
|
|
418
|
+
const run = async () => {
|
|
419
|
+
while (next < items.length) {
|
|
420
|
+
const i = next++;
|
|
421
|
+
out[i] = await work(items[i]);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, run));
|
|
425
|
+
return out;
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtM2QtdHJhbnNjcmlwdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtM2QtdHJhbnNjcmlwdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLFNBQVMsRUFBd0IsTUFBTSx5Q0FBeUMsQ0FBQztBQUUxRixPQUFPLEVBQ0wsV0FBVyxFQUNYLGNBQWMsRUFDZCxtQkFBbUIsR0FHcEIsTUFBTSwwQ0FBMEMsQ0FBQztBQUNsRCxPQUFPLEVBQ0wsMkJBQTJCLEVBQzNCLHFCQUFxQixFQUNyQixpQkFBaUIsRUFDakIsUUFBUSxHQUNULE1BQU0sZ0NBQWdDLENBQUM7QUFFeEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxjQUFjLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNsRixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ25GLE9BQU8sRUFBWSxXQUFXLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM5RSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFakQseUdBQXlHO0FBQ3pHLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLFNBQVMsQ0FBQztBQUM1QyxrR0FBa0c7QUFDbEcsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxDQUFDO0FBQzdDLG9DQUFvQztBQUNwQyxNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFDdEIsd0VBQXdFO0FBQ3hFLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQztBQUMzQixrQ0FBa0M7QUFDbEMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDO0FBQzdCLGdFQUFnRTtBQUNoRSxNQUFNLGNB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QUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM1RCxJQUFJLEtBQUssR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ3hGLE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3JDLElBQUksSUFBSSxHQUFhLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDO1FBQzlELE1BQU0sSUFBSSxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDckUsSUFBSSxJQUFJO1lBQUUsSUFBSSxHQUFHLElBQUksQ0FBQztRQUN0QixnR0FBZ0c7UUFDaEcsSUFBSSxJQUFJLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDOUQsT0FBTyxJQUFJLENBQUMsTUFBTSxHQUFHLGNBQWMsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEUsS0FBSyxFQUFFLENBQUM7WUFDUixJQUFJLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFB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LENBQUM7SUFDOUUsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBQb2ludHMzRExheWVyLCBWaWV3ZXIgfSBmcm9tICduYXBhcmktanMnO1xuXG5pbXBvcnQgeyBBTExfR0VORVMsIHR5cGUgU3BhdGlhbERhdGFQb3J0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7XG4gIE5PX0NBVEVHT1JZLFxuICBOT19PQlNFUlZBVElPTixcbiAgaXNDYXRlZ29yaWNhbENvbHVtbixcbiAgdHlwZSBTcGF0aWFsRGF0YXNldCxcbiAgdHlwZSBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLFxuICBERUZBVUxUX01VVEVEX09QQUNJVFksXG4gIGNhdGVnb3J5Q29sb3JzRm9yLFxuICBwYXJzZUhleCxcbn0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nJztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFNlbGVjdGlvbk1hc2sgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7IGFsbEdlbmVTaG93bkJ5LCBhbGxHZW5lc0hpZGRlbiB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC10aWxlLW1lcmdlJztcbmltcG9ydCB7IGNlbGxUeXBlQ29sdW1uRm9yIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXRpbGVzJztcbmltcG9ydCB7IGNsdXN0ZXJDb2xvck1hcCwgY2x1c3Rlck9mR2VuZSB9IGZyb20gJy4uLy4uL3NwYXRpYWwvdHJhbnNjcmlwdC1ncm91cGluZyc7XG5pbXBvcnQgeyBEYXRhUmVjdCwgdGlsZXNJblJlY3QsIHRyYW5zY3JpcHRMZXZlbEZvciB9IGZyb20gJy4uLy4uL3NwYXRpYWwvbG9kJztcbmltcG9ydCB7IFN1cGVyc2VkZSB9IGZyb20gJy4uLy4uL3V0aWwvc3VwZXJzZWRlJztcblxuLyoqIE1vc3QgdHJhbnNjcmlwdHMgZHJhd24gaW4gdGhlIDNEIHZpZXc6IHBhc3QgaXQsIGV2ZXJ5IGstdGggb25lIGlzIGRyYXduIChhbmQgdGhlIGNvbnNvbGUgc2F5cyBzbykuICovXG5leHBvcnQgY29uc3QgVFJBTlNDUklQVFNfM0RfTUFYID0gMl8wMDBfMDAwO1xuLyoqIE1vc3QgbGV2ZWwtMCB0aWxlcyByZWFkIGZvciB0aGUgM0QgdmlldzogYSBkYXRhc2V0IG5lZWRpbmcgbW9yZSBpcyB0b28gbGFyZ2UgdG8gZHJhdyB3aG9sZS4gKi9cbmV4cG9ydCBjb25zdCBUUkFOU0NSSVBUU18zRF9NQVhfVElMRVMgPSA0MDk2O1xuLyoqIFRpbGUgcmVhZHMgaW4gZmxpZ2h0IGF0IG9uY2UuICovXG5jb25zdCBDT05DVVJSRU5DWSA9IDg7XG4vKiogVGhlIGNhbWVyYSByZXN0aW5nIHRoaXMgbG9uZyBwbGFucyB0aGUgdHJhbnNjcmlwdHMnIGRldGFpbCBhZ2Fpbi4gKi9cbmNvbnN0IENBTUVSQV9SRVNUX01TID0gMzAwO1xuLyoqIFRyYW5zY3JpcHQgdGlsZXMga2VwdCByZWFkLiAqL1xuY29uc3QgVElMRV9DQUNIRV9TSVpFID0gMTAyNDtcbi8qKiBNb3N0IHRpbGVzIHJlYWQgZm9yIG9uZSB2aWV3OiBwYXN0IHRoZW0sIGEgY29hcnNlciBsZXZlbC4gKi9cbmNvbnN0IFZJRVdfVElMRVNfTUFYID0gMjU2O1xuLyoqIEhvdyBmYXIgYWxvbmcgYSByYXkgdGhhdCBuZXZlciBtZWV0cyB0aGUgc2VjdGlvbidzIHBsYW5lIGl0cyByZWFjaCBpcyB0YWtlbiAod29ybGQgdW5pdHMpLiAqL1xuY29uc3QgSE9SSVpPTiA9IDFlNjtcbi8qKiBBIHRyYW5zY3JpcHQncyBtYXJrZXIgaW4gdGhlIDNEIHZpZXcsIGluIHNjcmVlbiBwaXhlbHMgYXQgYSB0cmFuc2NyaXB0IHNjYWxlIG9mIDEuICovXG5leHBvcnQgY29uc3QgVFJBTlNDUklQVF8zRF9CQVNFX1NJWkUgPSAyO1xuLyoqIEEgdHJhbnNjcmlwdCB3aXRoIG5vIGNvbG91ciBieSBjZWxsIHR5cGUgKGluIG5vIGNlbGwsIG9yIGEgY2VsbCBpbiBubyBncm91cCksIGFzIHRoZSAyRCBtYXJrZXJzLiAqL1xuY29uc3QgVU5BU1NJR05FRF9SR0JBID0gWzAuNjIsIDAuNjIsIDAuNjIsIDAuNTVdIGFzIGNvbnN0O1xuXG4vKiogV2hhdCB0aGUgM0QgdHJhbnNjcmlwdHMgbmVlZCBvZiB0aGUgc2NlbmU6IHdoZXJlIHRoZSBjbG91ZCBzaXRzIGFuZCBob3cgWiBpcyBzdHJldGNoZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zY3JpcHRzM2RGcmFtZSB7XG4gIC8qKiBPZmZzZXQgYXBwbGllZCB0byBvYnNlcnZhdGlvbiBjb29yZGluYXRlcyB0byBzaXQgdGhlbSBpbiB0aGUgc2NlbmUncyBib3guICovXG4gIG9yaWdpbjogcmVhZG9ubHkgW251bWJlciwgbnVtYmVyLCBudW1iZXJdO1xuICB6U2NhbGU6IG51bWJlcjtcbn1cblxuLyoqIFRoZSBnZW5lcyBhIHZpZXcgZHJhd3MgaW4gM0QsIGFzIHRoZSB0aWxlIHF1ZXJ5IHRha2VzIHRoZW0sIG9yIG51bGwgd2hlbiBpdCBkcmF3cyBub25lLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zY3JpcHRzM2RHZW5lcyhcbiAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4pOiB7IHF1ZXJ5OiBzdHJpbmdbXTsgYWxsR2VuZXM6IGJvb2xlYW4gfSB8IG51bGwge1xuICBpZiAodmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ29mZicpIHJldHVybiBudWxsO1xuICBpZiAodmlldy50cmFuc2NyaXB0QWxsR2VuZXMpIHtcbiAgICBpZiAoYWxsR2VuZXNIaWRkZW4odmlldykpIHJldHVybiBudWxsO1xuICAgIHJldHVybiB7IHF1ZXJ5OiBbQUxMX0dFTkVTXSwgYWxsR2VuZXM6IHRydWUgfTtcbiAgfVxuICBjb25zdCBoaWRkZW4gPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lcy5maWx0ZXIoKGcpID0+ICFoaWRkZW4uaGFzKGcpKTtcbiAgcmV0dXJuIGdlbmVzLmxlbmd0aCA/IHsgcXVlcnk6IGdlbmVzLCBhbGxHZW5lczogZmFsc2UgfSA6IG51bGw7XG59XG5cbi8qKlxuICogRWFjaCBsb2FkZWQgdHJhbnNjcmlwdCdzIGNvbG91ciwgcGFja2VkIFJHQkEsIGFzIHRoZSAyRCBtYXJrZXJzIGNvbG91ciB0aGVtIGJ5IGdlbmU6IGEgZ2VuZSdzXG4gKiBjaG9zZW4gY29sb3VyLCBlbHNlIHRoZSBwYWxldHRlJ3MgYnkgaXRzIHNsb3QgKHRoZSBzZWxlY3Rpb24ncyBvcmRlciwgb3Igd2l0aCBcIkFsbCBnZW5lc1wiIHRoZVxuICogZGF0YXNldCdzIGdlbmUgY29kZSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2NyaXB0czNkQ29sb3JzKFxuICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10gfCBudWxsLFxuICBnZW5lOiBVaW50MTZBcnJheSxcbiAgY291bnQ6IG51bWJlcixcbik6IEZsb2F0MzJBcnJheSB7XG4gIGNvbnN0IG4gPSBuYW1lcyA/IG5hbWVzLmxlbmd0aCA6IERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGg7XG4gIGNvbnN0IHRhYmxlID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogbiB9LCAoX2csIGkpID0+XG4gICAgcmdiYTAxKFxuICAgICAgKG5hbWVzICYmIHZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnNbbmFtZXNbaV1dKSB8fFxuICAgICAgICBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEVbaSAlIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGhdLFxuICAgICksXG4gICk7XG4gIHJldHVybiBwYWNrZWQoY291bnQsIChpKSA9PiB0YWJsZVtuYW1lcyA/IGdlbmVbaV0gOiBnZW5lW2ldICUgbl0pO1xufVxuXG4vKipcbiAqIEhvdyB0aGUgcGFuZWwncyBcIkNvbG91ciBieVwiIGFwcGxpZXMgaW4gM0QsIGFzIGl0IGRvZXMgdG8gdGhlIDJEIG1hcmtlcnMgKGBjb2xvclZpZXdGb3JgKTogYnlcbiAqIGNlbGwgdHlwZSB3aGVuIHRoZSBkYXRhc2V0IGhhcyBvbmUgKGVsc2UgYnkgZ2VuZSksIGJ5IGNsdXN0ZXIgZm9yIHRoZSBzZWxlY3RlZCBnZW5lcyAod2l0aCBcIkFsbFxuICogZ2VuZXNcIiBhIGNsdXN0ZXIgaXMgaXRzIGdlbmUpLCBieSBnZW5lIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zY3JpcHRzM2RDb2xvckJ5KFxuICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgYWxsR2VuZXM6IGJvb2xlYW4sXG4pOiAnY2VsbFR5cGUnIHwgJ2NsdXN0ZXInIHwgJ2dlbmUnIHtcbiAgY29uc3QgYnkgPSB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5O1xuICBpZiAoYnkgPT09ICdjZWxsVHlwZScpIHJldHVybiBjZWxsVHlwZUNvbHVtbkZvcihkYXRhc2V0LCB2aWV3KSA/ICdjZWxsVHlwZScgOiAnZ2VuZSc7XG4gIGlmIChieSA9PT0gJ2NsdXN0ZXInICYmICFhbGxHZW5lcykgcmV0dXJuICdjbHVzdGVyJztcbiAgcmV0dXJuICdnZW5lJztcbn1cblxuLyoqIFRoZSBjb2xvdXJzIHRoZSBjZWxscycgZ3JvdXBpbmcgZ2l2ZXMgaXRzIGdyb3VwcywgYnkgbmFtZSAobm9uZSB3aXRob3V0IGEgZ3JvdXBpbmcpLiAqL1xuYXN5bmMgZnVuY3Rpb24gY2VsbEdyb3VwQ29sb3JzKFxuICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgcG9ydDogU3BhdGlhbERhdGFQb3J0LFxuKTogUHJvbWlzZTx7IGNvZGVzOiBVaW50MTZBcnJheTsgY29sb3JzOiAocmVhZG9ubHkgbnVtYmVyW10pW107IGJ5TmFtZTogTWFwPHN0cmluZywgc3RyaW5nPiB9IHwgbnVsbD4ge1xuICBjb25zdCBuYW1lID0gY2VsbFR5cGVDb2x1bW5Gb3IoZGF0YXNldCwgdmlldyk7XG4gIGlmICghbmFtZSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGNvbHVtbiA9IGF3YWl0IHBvcnQuZ2V0Q29sdW1uKG5hbWUpO1xuICBpZiAoIWlzQ2F0ZWdvcmljYWxDb2x1bW4oY29sdW1uKSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGhleCA9IGNhdGVnb3J5Q29sb3JzRm9yKG5hbWUsIGNvbHVtbi5tZXRhLCB2aWV3Lmdyb3VwQ29sb3JzKTtcbiAgY29uc3QgYnlOYW1lID0gbmV3IE1hcChjb2x1bW4ubWV0YS5jYXRlZ29yaWVzLm1hcCgoYywgaykgPT4gW2MsIGhleFtrXV0gYXMgY29uc3QpKTtcbiAgcmV0dXJuIHsgY29kZXM6IGNvbHVtbi5jb2RlcywgY29sb3JzOiBoZXgubWFwKHJnYmEwMSksIGJ5TmFtZSB9O1xufVxuXG4vKiogYCNycmdnYmJgIGFzIGFuIG9wYXF1ZSAwLi4xIFJHQkEuICovXG5mdW5jdGlvbiByZ2JhMDEoaGV4OiBzdHJpbmcpOiByZWFkb25seSBudW1iZXJbXSB7XG4gIGNvbnN0IFtyLCBnLCBiXSA9IHBhcnNlSGV4KGhleCk7XG4gIHJldHVybiBbciAvIDI1NSwgZyAvIDI1NSwgYiAvIDI1NSwgMV07XG59XG5cbi8qKiBgY291bnRgIGNvbG91cnMgcGFja2VkIFJHQkEsIHVuYXNzaWduZWQgd2hlcmUgYGF0YCBoYXMgbm9uZS4gKi9cbmZ1bmN0aW9uIHBhY2tlZChjb3VudDogbnVtYmVyLCBhdDogKGk6IG51bWJlcikgPT4gcmVhZG9ubHkgbnVtYmVyW10gfCB1bmRlZmluZWQpOiBGbG9hdDMyQXJyYXkge1xuICBjb25zdCBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KGNvdW50ICogNCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY291bnQ7IGkrKykgb3V0LnNldChhdChpKSA/PyBVTkFTU0lHTkVEX1JHQkEsIGkgKiA0KTtcbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBUaGUgdHJhbnNjcmlwdHMgb2YgdGhlIDNEIHNwYXRpYWwgdmlldzogdGhlIG1vbGVjdWxlcyBvZiB0aGUgZ2VuZXMgdGhlIFRyYW5zY3JpcHRzIHBhbmVsIGRyYXdzXG4gKiAoaXRzIHNlbGVjdGVkIGdlbmVzLCBvciBcIkFsbCBnZW5lc1wiKSwgYXQgdGhlaXIgb3duIHgsIHkgYW5kIHosIGluIHRoZSBjbG91ZCdzIGJveCBhbmQgWiBzdHJldGNoLlxuICpcbiAqIEJ5IGxldmVsIG9mIGRldGFpbCwgYXMgdGhlIDJEIHZpZXcgcmVhZHMgdGhlbTogdGhlIHB5cmFtaWQgbGV2ZWwgdGhlIGNhbWVyYSdzIGRpc3RhbmNlIGNhbGxzIGZvclxuICogKGB0cmFuc2NyaXB0TGV2ZWxGb3JgLCB0aGUgbWFya2VycyBwZXIgc2NyZWVuIGtlcHQgYWJvdXQgY29uc3RhbnQ6IGFnZ3JlZ2F0ZXMgZmFyIG91dCwgZXZlcnlcbiAqIG1vbGVjdWxlIGNsb3NlIGluIG9uIGEgY2VsbCksIGFuZCBvbmx5IHRoZSB0aWxlcyBvZiB0aGUgcGFydCBvZiB0aGUgc2VjdGlvbiBpbiB2aWV3ICh0aGUgY2FudmFzJ3NcbiAqIGNvcm5lcnMgY2FzdCBvbnRvIHRoZSBzZWN0aW9uJ3MgcGxhbmUpLiBQbGFubmVkIGFnYWluIHdoZW4gdGhlIGNhbWVyYSByZXN0czsgdGlsZXMgYXJlIGNhY2hlZCwgc29cbiAqIGNvbWluZyBiYWNrIHJlYWRzIG5vdGhpbmcuIFwiTG9hZGluZyB0cmFuc2NyaXB0c+KAplwiIHNob3dzIG9uIHRoZSBjYW52YXMgd2hpbGUgdGhleSBsb2FkIGFuZCBkcmF3LlxuICogRHJhd24gb25seSBmb3IgYSBkYXRhc2V0IHdob3NlIHRyYW5zY3JpcHRzIGNhcnJ5IHouXG4gKi9cbmV4cG9ydCBjbGFzcyBTcGF0aWFsM2RUcmFuc2NyaXB0cyB7XG4gIHByaXZhdGUgbGF5ZXI6IFBvaW50czNETGF5ZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIFdoYXQge0BsaW5rIGxheWVyfSB3YXMgbG9hZGVkIGZyb20gKGRhdGFzZXQsIGdlbmVzLCBxdWFsaXR5KSwgYW5kIHN0eWxlZCB3aXRoLiAqL1xuICBwcml2YXRlIGxvYWRLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHN0eWxlS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBsb2FkZWQ6IHsgdGlsZXM6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZVtdOyBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10gfCBudWxsIH0gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSBsb2FkcyA9IG5ldyBTdXBlcnNlZGUoKTtcbiAgLyoqIEVhY2ggZHJhd24gdHJhbnNjcmlwdCdzIGNlbGwgKHtAbGluayBOT19PQlNFUlZBVElPTn0gZm9yIG5vbmUpLCBmb3IgZmFkaW5nIGJ5IHRoZSBzZWxlY3Rpb24uICovXG4gIHByaXZhdGUgZHJhd25DZWxsczogVWludDMyQXJyYXkgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBzZWxlY3Rpb24gdGhlIGxheWVyJ3MgYWxwaGFzIGZhZGUgYnkgKG51bGw6IG5vbmUsIGV2ZXJ5IHRyYW5zY3JpcHQgYXMgaXQgaXMpLiAqL1xuICBwcml2YXRlIGZhZGVkQnk6IFNwYXRpYWxTZWxlY3Rpb25NYXNrIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgbGFzdCBzeW5jJ3MgaW5wdXRzOiB0aGUgY2FtZXJhIHJlc3RpbmcgcGxhbnMgdGhlIGRldGFpbCBhZ2FpbiBmcm9tIHRoZW0uICovXG4gIHByaXZhdGUgbGFzdDoge1xuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0O1xuICAgIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGU7XG4gICAgcG9ydDogU3BhdGlhbERhdGFQb3J0IHwgbnVsbDtcbiAgICBmcmFtZTogVHJhbnNjcmlwdHMzZEZyYW1lO1xuICAgIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2sgfCBudWxsO1xuICB9IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2FtZXJhVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2FtZXJhT2ZmOiAoKCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRpbGVzIHJlYWQsIGJ5IGdlbmVzLCBxdWFsaXR5LCBsZXZlbCBhbmQgdGlsZSAobGVhc3QgcmVjZW50bHkgdXNlZCBkcm9wcGVkIGZpcnN0KS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSB0aWxlQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxTcGF0aWFsVHJhbnNjcmlwdFRpbGU+PigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdmlld2VyOiBWaWV3ZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBiZWdpbjogKG1lc3NhZ2U6IHN0cmluZykgPT4gKCkgPT4gdm9pZCxcbiAgKSB7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSB2aWV3ZXIuY2FtZXJhM2Q/LmNoYW5nZWQ/LmNvbm5lY3QoKCkgPT4gdGhpcy5jYW1lcmFNb3ZlZCgpKSA/PyBudWxsO1xuICB9XG5cbiAgLyoqIFRoZSBjYW1lcmEgbW92ZWQ6IG9uY2UgaXQgcmVzdHMsIHJlYWQgdGhlIGxldmVsIGFuZCB0aWxlcyBpdCBub3cgY2FsbHMgZm9yLiAqL1xuICBwcml2YXRlIGNhbWVyYU1vdmVkKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5sYXN0KSByZXR1cm47XG4gICAgaWYgKHRoaXMuY2FtZXJhVGltZXIpIGNsZWFyVGltZW91dCh0aGlzLmNhbWVyYVRpbWVyKTtcbiAgICB0aGlzLmNhbWVyYVRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmNhbWVyYVRpbWVyID0gbnVsbDtcbiAgICAgIGNvbnN0IGxhc3QgPSB0aGlzLmxhc3Q7XG4gICAgICBpZiAobGFzdCkgdm9pZCB0aGlzLnN5bmMobGFzdC5kYXRhc2V0LCBsYXN0LnZpZXcsIGxhc3QucG9ydCwgbGFzdC5mcmFtZSwgbGFzdC5zZWxlY3Rpb24pO1xuICAgIH0sIENBTUVSQV9SRVNUX01TKTtcbiAgfVxuXG4gIC8qKiBTdG9wIGZvbGxvd2luZyB0aGUgY2FtZXJhICh0aGUgc2NlbmUgd2VudCBhd2F5KS4gKi9cbiAgZGlzcG9zZSgpOiB2b2lkIHtcbiAgICB0aGlzLmNhbWVyYU9mZj8uKCk7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSBudWxsO1xuICAgIGlmICh0aGlzLmNhbWVyYVRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy5jYW1lcmFUaW1lcik7XG4gICAgdGhpcy5jYW1lcmFUaW1lciA9IG51bGw7XG4gICAgdGhpcy5sYXN0ID0gbnVsbDtcbiAgICB0aGlzLnJlbW92ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBsZXZlbCBhbmQgdGhlIHRpbGVzIHRoZSBjYW1lcmEgY2FsbHMgZm9yOiB0aGUgbGV2ZWwgd2hvc2UgdGlsZXMgY29tZSBvdXQgYWJvdXQgNTEyIHNjcmVlblxuICAgKiBwaXhlbHMgYWNyb3NzIGF0IHRoZSB0YXJnZXQncyBkZXB0aCwgdGhlIHRpbGVzIG9mIHRoZSBzZWN0aW9uIGluIHZpZXcgKHdob2xlLCB3aGVuIGEgY29ybmVyIG9mXG4gICAqIHRoZSBjYW52YXMgbG9va3MgcGFzdCB0aGUgc2VjdGlvbidzIHBsYW5lKS5cbiAgICovXG4gIHByaXZhdGUgcGxhbihtZXRhOiBOb25OdWxsYWJsZTxTcGF0aWFsRGF0YXNldFsndHJhbnNjcmlwdFRpbGVzJ10+LCBmcmFtZTogVHJhbnNjcmlwdHMzZEZyYW1lKSB7XG4gICAgY29uc3QgW3Z3LCB2aF0gPSB0aGlzLnZpZXdlci52aWV3cG9ydFNpemU/LigpID8/IFswLCAwXTtcbiAgICBjb25zdCBjYW1lcmEgPSB0aGlzLnZpZXdlci5jYW1lcmEzZDtcbiAgICBjb25zdCB3cHAgPSBjYW1lcmEgJiYgdmggPiAwID8gY2FtZXJhLndvcmxkUGVyUGl4ZWwodmgpIDogMDtcbiAgICBsZXQgbGV2ZWwgPSB3cHAgPiAwID8gdHJhbnNjcmlwdExldmVsRm9yKDEgLyB3cHAsIG1ldGEubGV2ZWxzKSA6IG1ldGEubGV2ZWxzLmxlbmd0aCAtIDE7XG4gICAgY29uc3QgW3gwLCB5MCwgeDEsIHkxXSA9IG1ldGEuYm91bmRzO1xuICAgIGxldCByZWN0OiBEYXRhUmVjdCA9IHsgeDAsIHkwLCB4MTogeDEgKyAxZS02LCB5MTogeTEgKyAxZS02IH07XG4gICAgY29uc3Qgc2VlbiA9IHZ3ID4gMCAmJiB2aCA+IDAgPyB0aGlzLmZvb3RwcmludCh2dywgdmgsIGZyYW1lKSA6IG51bGw7XG4gICAgaWYgKHNlZW4pIHJlY3QgPSBzZWVuO1xuICAgIC8vIENsb3NlIGluIGJ1dCBsb29raW5nIGZhciBhY3Jvc3MgdGhlIHNlY3Rpb246IGNvYXJzZXIsIHVudGlsIHRoZSB0aWxlcyBpbiB2aWV3IGFyZSBmZXcgZW5vdWdoLlxuICAgIGxldCBrZXlzID0gdGlsZXNJblJlY3QocmVjdCwgbGV2ZWwsIG1ldGEubGV2ZWxzLCBtZXRhLmJvdW5kcyk7XG4gICAgd2hpbGUgKGtleXMubGVuZ3RoID4gVklFV19USUxFU19NQVggJiYgbGV2ZWwgPCBtZXRhLmxldmVscy5sZW5ndGggLSAxKSB7XG4gICAgICBsZXZlbCsrO1xuICAgICAga2V5cyA9IHRpbGVzSW5SZWN0KHJlY3QsIGxldmVsLCBtZXRhLmxldmVscywgbWV0YS5ib3VuZHMpO1xuICAgIH1cbiAgICByZXR1cm4geyBsZXZlbCwga2V5cyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBwYXJ0IG9mIHRoZSBzZWN0aW9uIHRoZSBjYW52YXMgc2VlcywgaW4gb2JzZXJ2YXRpb24gdW5pdHM6IGl0cyBjb3JuZXJzIGFuZCBjZW50cmUgY2FzdCBvbnRvXG4gICAqIHRoZSBwbGFuZSB0aHJvdWdoIHRoZSBjYW1lcmEncyB0YXJnZXQsIHdpZGVuZWQgYnkgYSBxdWFydGVyLiBBIGNvcm5lciBsb29raW5nIHBhc3QgdGhlIHBsYW5lXG4gICAqICh0b3dhcmRzIHRoZSBob3Jpem9uKSByZWFjaGVzIGZhciBhbG9uZyBpdHMgcmF5IGluc3RlYWQgKHRoZSB0aWxlcyBhcmUgY2xpcHBlZCB0byB0aGUgc2VjdGlvbikuXG4gICAqL1xuICBwcml2YXRlIGZvb3RwcmludCh2dzogbnVtYmVyLCB2aDogbnVtYmVyLCBmcmFtZTogVHJhbnNjcmlwdHMzZEZyYW1lKTogRGF0YVJlY3QgfCBudWxsIHtcbiAgICBjb25zdCB6ID0gdGhpcy52aWV3ZXIuY2FtZXJhM2Q/LnRhcmdldD8uWzJdO1xuICAgIGlmICh6ID09PSB1bmRlZmluZWQgfHwgIXRoaXMudmlld2VyLmNhbnZhc1JheSkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgW294LCBveV0gPSBmcmFtZS5vcmlnaW47XG4gICAgbGV0IHhhID0gSW5maW5pdHksXG4gICAgICB5YSA9IEluZmluaXR5LFxuICAgICAgeGIgPSAtSW5maW5pdHksXG4gICAgICB5YiA9IC1JbmZpbml0eTtcbiAgICBmb3IgKGNvbnN0IFtjeCwgY3ldIG9mIFtcbiAgICAgIFswLCAwXSxcbiAgICAgIFt2dywgMF0sXG4gICAgICBbMCwgdmhdLFxuICAgICAgW3Z3LCB2aF0sXG4gICAgICBbdncgLyAyLCB2aCAvIDJdLFxuICAgIF0pIHtcbiAgICAgIGNvbnN0IHJheSA9IHRoaXMudmlld2VyLmNhbnZhc1JheShjeCwgY3kpO1xuICAgICAgaWYgKCFyYXkpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgaGl0ID0gTWF0aC5hYnMocmF5LmRpclsyXSkgPiAxZS02ID8gKHogLSByYXkub3JpZ2luWzJdKSAvIHJheS5kaXJbMl0gOiAtMTtcbiAgICAgIGNvbnN0IHQgPSBoaXQgPiAwID8gaGl0IDogSE9SSVpPTjtcbiAgICAgIGNvbnN0IHggPSByYXkub3JpZ2luWzBdICsgcmF5LmRpclswXSAqIHQgLSBveDtcbiAgICAgIGNvbnN0IHkgPSByYXkub3JpZ2luWzFdICsgcmF5LmRpclsxXSAqIHQgLSBveTtcbiAgICAgIHhhID0gTWF0aC5taW4oeGEsIHgpO1xuICAgICAgeWEgPSBNYXRoLm1pbih5YSwgeSk7XG4gICAgICB4YiA9IE1hdGgubWF4KHhiLCB4KTtcbiAgICAgIHliID0gTWF0aC5tYXgoeWIsIHkpO1xuICAgIH1cbiAgICBjb25zdCBteCA9ICh4YiAtIHhhKSAvIDQ7XG4gICAgY29uc3QgbXkgPSAoeWIgLSB5YSkgLyA0O1xuICAgIHJldHVybiB7IHgwOiB4YSAtIG14LCB5MDogeWEgLSBteSwgeDE6IHhiICsgbXgsIHkxOiB5YiArIG15IH07XG4gIH1cblxuICAvKiogQSB0aWxlLCByZWFkIG9uY2UgKGFuZCBhZ2FpbiBvbmx5IG9uY2UgZHJvcHBlZCBmcm9tIHRoZSBjYWNoZSkuICovXG4gIHByaXZhdGUgdGlsZShrZXk6IHN0cmluZywgcmVhZDogKCkgPT4gUHJvbWlzZTxTcGF0aWFsVHJhbnNjcmlwdFRpbGU+KTogUHJvbWlzZTxTcGF0aWFsVHJhbnNjcmlwdFRpbGU+IHtcbiAgICBsZXQgaGl0ID0gdGhpcy50aWxlQ2FjaGUuZ2V0KGtleSk7XG4gICAgaWYgKGhpdCkge1xuICAgICAgdGhpcy50aWxlQ2FjaGUuZGVsZXRlKGtleSk7XG4gICAgICB0aGlzLnRpbGVDYWNoZS5zZXQoa2V5LCBoaXQpO1xuICAgICAgcmV0dXJuIGhpdDtcbiAgICB9XG4gICAgaGl0ID0gcmVhZCgpO1xuICAgIGhpdC5jYXRjaCgoKSA9PiB0aGlzLnRpbGVDYWNoZS5kZWxldGUoa2V5KSk7XG4gICAgdGhpcy50aWxlQ2FjaGUuc2V0KGtleSwgaGl0KTtcbiAgICB3aGlsZSAodGhpcy50aWxlQ2FjaGUuc2l6ZSA+IFRJTEVfQ0FDSEVfU0laRSlcbiAgICAgIHRoaXMudGlsZUNhY2hlLmRlbGV0ZSh0aGlzLnRpbGVDYWNoZS5rZXlzKCkubmV4dCgpLnZhbHVlIGFzIHN0cmluZyk7XG4gICAgcmV0dXJuIGhpdDtcbiAgfVxuXG4gIC8qKiBUaGUgbGF5ZXIgZHJhd24sIGlmIGFueSAoZm9yIHRlc3RzIGFuZCB0aGUgc2NlbmUncyBaIHN0cmV0Y2gpLiAqL1xuICBnZXQgZHJhd24oKTogUG9pbnRzM0RMYXllciB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmxheWVyO1xuICB9XG5cbiAgLyoqXG4gICAqIERyYXcgd2hhdCBgdmlld2AgYXNrcyBmb3IsIGxvYWRpbmcgdGhlIG1vbGVjdWxlcyB3aGVuIHRoZSBnZW5lcyBjaGFuZ2VkLiBXaXRoIGEgYHNlbGVjdGlvbmBcbiAgICogKGEgY2VsbCwgb3IgYSBjZWxsIHR5cGUncyBjZWxscyksIHRoZSB0cmFuc2NyaXB0cyBvZiB0aGUgc2VsZWN0ZWQgY2VsbHMga2VlcCB0aGVpciBjb2xvdXIgYW5kXG4gICAqIHRoZSBvdGhlcnMgZmFkZSwgYXMgdGhlIGNlbGxzIGRvLlxuICAgKi9cbiAgYXN5bmMgc3luYyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgICB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLFxuICAgIHBvcnQ6IFNwYXRpYWxEYXRhUG9ydCB8IG51bGwsXG4gICAgZnJhbWU6IFRyYW5zY3JpcHRzM2RGcmFtZSxcbiAgICBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrIHwgbnVsbCA9IG51bGwsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1ldGEgPSBkYXRhc2V0LnRyYW5zY3JpcHRUaWxlcztcbiAgICBjb25zdCBnZW5lcyA9IG1ldGE/Lmhhc1ogJiYgcG9ydD8uZ2V0VHJhbnNjcmlwdFRpbGUgPyB0cmFuc2NyaXB0czNkR2VuZXMoZGF0YXNldCwgdmlldykgOiBudWxsO1xuICAgIGlmICghbWV0YSB8fCAhZ2VuZXMgfHwgIXBvcnQpIHtcbiAgICAgIC8vIE9mZiAob3Igbm8gZ2VuZSBzaG93bik6IGEgY2FtZXJhIG1vdmUgbXVzdCBub3QgYnJpbmcgYmFjayB0aGUgbGFzdCB2aWV3IHRoYXQgZHJldyBzb21lLlxuICAgICAgdGhpcy5sYXN0ID0gbnVsbDtcbiAgICAgIGlmICh0aGlzLmNhbWVyYVRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy5jYW1lcmFUaW1lcik7XG4gICAgICB0aGlzLmNhbWVyYVRpbWVyID0gbnVsbDtcbiAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMubGFzdCA9IHsgZGF0YXNldCwgdmlldywgcG9ydCwgZnJhbWUsIHNlbGVjdGlvbiB9O1xuICAgIGNvbnN0IHF1YWxpdHkgPSB2aWV3LnRyYW5zY3JpcHRRdWFsaXR5ID09PSAnYWxsJyA/ICdhbGwnIDogJ2hpZ2gnO1xuICAgIGNvbnN0IHsgbGV2ZWwsIGtleXMgfSA9IHRoaXMucGxhbihtZXRhLCBmcmFtZSk7XG4gICAgY29uc3QgZ2VuZXNLZXkgPSBgJHtkYXRhc2V0LmlkfXwke2dlbmVzLnF1ZXJ5LmpvaW4oJ1xcdTAwMDEnKX18JHtxdWFsaXR5fWA7XG4gICAgY29uc3QgbG9hZEtleSA9IGAke2dlbmVzS2V5fXwke2xldmVsfXwke2tleXMubWFwKChrKSA9PiBgJHtrLmd4fSwke2suZ3l9YCkuam9pbignOycpfWA7XG4gICAgbGV0IGVuZDogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gICAgaWYgKGxvYWRLZXkgIT09IHRoaXMubG9hZEtleSkge1xuICAgICAgY29uc3QgdGFzayA9IHRoaXMubG9hZHMubmV4dCgpO1xuICAgICAgaWYgKGtleXMubGVuZ3RoID4gVFJBTlNDUklQVFNfM0RfTUFYX1RJTEVTKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgW25hcGFyaS1qc10gJHtrZXlzLmxlbmd0aH0gdHJhbnNjcmlwdCB0aWxlcyBhcmUgdG9vIG1hbnkgdG8gcmVhZCBmb3IgdGhlIDNEIHZpZXdgKTtcbiAgICAgICAgdGhpcy5yZW1vdmUoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgZW5kID0gdGhpcy5iZWdpbignTG9hZGluZyB0cmFuc2NyaXB0c+KApicpO1xuICAgICAgbGV0IHRpbGVzOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGVbXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRpbGVzID0gYXdhaXQgcG9vbGVkKGtleXMsIENPTkNVUlJFTkNZLCAoaykgPT5cbiAgICAgICAgICB0aGlzLnRpbGUoYCR7Z2VuZXNLZXl9fCR7bGV2ZWx9LyR7ay5neH0vJHtrLmd5fWAsICgpID0+XG4gICAgICAgICAgICBwb3J0LmdldFRyYW5zY3JpcHRUaWxlIShsZXZlbCwgay5neCwgay5neSwgeyBnZW5lczogZ2VuZXMucXVlcnksIHF1YWxpdHkgfSksXG4gICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHRyYW5zY3JpcHRzIGZvciB0aGUgM0QgdmlldyBjb3VsZCBub3QgYmUgcmVhZCcsIGVycik7XG4gICAgICAgIC8vIFRoZSBwYW5lbCBhc2tlZCBmb3Igb3RoZXIgdHJhbnNjcmlwdHMgdGhhbiB0aG9zZSBkcmF3bjogdGFrZSB0aGVtIGRvd24gcmF0aGVyIHRoYW4gbGVhdmVcbiAgICAgICAgLy8gdGhlIG9sZCBzZWxlY3Rpb24gdXAgYXMgaWYgaXQgd2VyZSB0aGUgbmV3IG9uZTsgdGhlIG5leHQgY2hhbmdlIHJlYWRzIGFnYWluLiBPbmx5IHRoZVxuICAgICAgICAvLyBjdXJyZW50IGxvYWQgbWF5OiBhIHN1cGVyc2VkZWQgb25lIG11c3Qgbm90IHRlYXIgZG93biB3aGF0IGEgbmV3ZXIgb25lIGRyZXcuXG4gICAgICAgIGlmICh0YXNrKCkpIHRoaXMuY2xlYXJMYXllcigpO1xuICAgICAgICBlbmQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKCF0YXNrKCkpIHtcbiAgICAgICAgZW5kKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMubG9hZEtleSA9IGxvYWRLZXk7XG4gICAgICB0aGlzLnN0eWxlS2V5ID0gbnVsbDtcbiAgICAgIHRoaXMubG9hZGVkID0geyB0aWxlcywgbmFtZXM6IGdlbmVzLmFsbEdlbmVzID8gKG1ldGEuZ2VuZXMgPz8gbnVsbCkgOiBnZW5lcy5xdWVyeSB9O1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5kcmF3KGRhdGFzZXQsIHZpZXcsIHBvcnQsIGZyYW1lLCBnZW5lcy5hbGxHZW5lcyk7XG4gICAgICAvLyBUaGUgbmV3ZXN0IHN5bmMncyBzZWxlY3Rpb246IGFuIG9sZGVyIGRyYXcgZmluaXNoaW5nIGxhdGUgbXVzdCBub3QgZmFkZSBieSBhIHN0YWxlIG9uZS5cbiAgICAgIGlmICh0aGlzLmxhc3Q/LnNlbGVjdGlvbiA9PT0gc2VsZWN0aW9uKSB0aGlzLmZhZGUoc2VsZWN0aW9uKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgZW5kPy4oKTtcbiAgICB9XG4gIH1cblxuICAvKiogRm9sbG93IHRoZSBzY2VuZSdzIFogc3RyZXRjaCAobm90aGluZyBpcyByZS11cGxvYWRlZCkuICovXG4gIHNldFpTY2FsZShzOiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5sYXllcikgdGhpcy5sYXllci5zY2FsZTNkID0gWzEsIDEsIHNdO1xuICB9XG5cbiAgLyoqIFRha2UgdGhlIGxheWVyIGRvd24gYW5kIGZvcmdldCB3aGF0IGl0IHNob3dlZC4gKi9cbiAgcmVtb3ZlKCk6IHZvaWQge1xuICAgIHRoaXMubG9hZHMuY2FuY2VsKCk7XG4gICAgdGhpcy5jbGVhckxheWVyKCk7XG4gIH1cblxuICBwcml2YXRlIGNsZWFyTGF5ZXIoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMubGF5ZXIpIHRoaXMudmlld2VyLmxheWVycy5yZW1vdmUodGhpcy5sYXllcik7XG4gICAgdGhpcy5sYXllciA9IG51bGw7XG4gICAgdGhpcy5sb2FkS2V5ID0gbnVsbDtcbiAgICB0aGlzLnN0eWxlS2V5ID0gbnVsbDtcbiAgICB0aGlzLmxvYWRlZCA9IG51bGw7XG4gICAgdGhpcy5kcmF3bkNlbGxzID0gbnVsbDtcbiAgICB0aGlzLmZhZGVkQnkgPSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEZhZGUgdGhlIGRyYXduIHRyYW5zY3JpcHRzIG91dHNpZGUgdGhlIHNlbGVjdGlvbiAodGhlaXIgYWxwaGEgb25seTogdGhlIGNvbG91cnMgc3RheVxuICAgKiB1cGxvYWRlZCksIG9yIGJyaW5nIHRoZW0gYWxsIGJhY2sgd2l0aG91dCBvbmUuIEEgbm8tb3AgZm9yIHRoZSBzZWxlY3Rpb24gYWxyZWFkeSBhcHBsaWVkLlxuICAgKi9cbiAgcHJpdmF0ZSBmYWRlKHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2sgfCBudWxsKTogdm9pZCB7XG4gICAgY29uc3QgbGl2ZSA9IHNlbGVjdGlvbiAmJiBzZWxlY3Rpb24uY291bnQgPiAwID8gc2VsZWN0aW9uIDogbnVsbDtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXI7XG4gICAgY29uc3QgY2VsbHMgPSB0aGlzLmRyYXduQ2VsbHM7XG4gICAgaWYgKCFsYXllciB8fCAhY2VsbHMgfHwgbGl2ZSA9PT0gdGhpcy5mYWRlZEJ5KSByZXR1cm47XG4gICAgdGhpcy5mYWRlZEJ5ID0gbGl2ZTtcbiAgICBpZiAoIWxpdmUpIHtcbiAgICAgIGxheWVyLmFscGhhcyA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGFscGhhcyA9IG5ldyBGbG9hdDMyQXJyYXkoY2VsbHMubGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNlbGxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvID0gY2VsbHNbaV07XG4gICAgICBhbHBoYXNbaV0gPSBvICE9PSBOT19PQlNFUlZBVElPTiAmJiBvIDwgbGl2ZS5tYXNrLmxlbmd0aCAmJiBsaXZlLm1hc2tbb10gPyAxIDogREVGQVVMVF9NVVRFRF9PUEFDSVRZO1xuICAgIH1cbiAgICBsYXllci5hbHBoYXMgPSBhbHBoYXM7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGRyYXcoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgICBwb3J0OiBTcGF0aWFsRGF0YVBvcnQsXG4gICAgZnJhbWU6IFRyYW5zY3JpcHRzM2RGcmFtZSxcbiAgICBhbGxHZW5lczogYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9hZGVkID0gdGhpcy5sb2FkZWQ7XG4gICAgaWYgKCFsb2FkZWQpIHJldHVybjtcbiAgICBjb25zdCBieSA9IHRyYW5zY3JpcHRzM2RDb2xvckJ5KGRhdGFzZXQsIHZpZXcsIGFsbEdlbmVzKTtcbiAgICBjb25zdCBzdHlsZUtleSA9IFtcbiAgICAgIGZyYW1lLm9yaWdpbi5qb2luKCcsJyksXG4gICAgICBieSxcbiAgICAgIGJ5ID09PSAnZ2VuZScgPyBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lQ29sb3JzKSA6ICcnLFxuICAgICAgYnkgIT09ICdnZW5lJyA/IGAke2NlbGxUeXBlQ29sdW1uRm9yKGRhdGFzZXQsIHZpZXcpfXwke0pTT04uc3RyaW5naWZ5KHZpZXcuZ3JvdXBDb2xvcnMpfWAgOiAnJyxcbiAgICAgIGJ5ID09PSAnY2x1c3RlcicgPyBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSA6ICcnLFxuICAgICAgYWxsR2VuZXMgPyB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc0hpZGRlbi5qb2luKCcsJykgOiAnJyxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBzaXplID0gVFJBTlNDUklQVF8zRF9CQVNFX1NJWkUgKiAodmlldy50cmFuc2NyaXB0U2NhbGUgPiAwID8gdmlldy50cmFuc2NyaXB0U2NhbGUgOiAxKTtcbiAgICBpZiAodGhpcy5sYXllciAmJiBzdHlsZUtleSA9PT0gdGhpcy5zdHlsZUtleSkge1xuICAgICAgdGhpcy5sYXllci5zaXplID0gc2l6ZTtcbiAgICAgIHRoaXMubGF5ZXIub3BhY2l0eSA9IHZpZXcudHJhbnNjcmlwdE9wYWNpdHk7XG4gICAgICB0aGlzLmxheWVyLnNjYWxlM2QgPSBbMSwgMSwgZnJhbWUuelNjYWxlXTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgeyBuYW1lcyB9ID0gbG9hZGVkO1xuICAgIGNvbnN0IHNob3duID0gYWxsR2VuZXMgJiYgbmFtZXMgPyBhbGxHZW5lU2hvd25CeSh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc0hpZGRlbikgOiBudWxsO1xuICAgIGNvbnN0IGtlZXAgPSBzaG93biAmJiBuYW1lcyA/IChnOiBudW1iZXIpID0+ICEhbmFtZXNbZ10gJiYgc2hvd24obmFtZXNbZ10pIDogKCkgPT4gdHJ1ZTtcbiAgICBjb25zdCB0b3RhbCA9IGxvYWRlZC50aWxlcy5yZWR1Y2UoKG4sIHQpID0+IG4gKyB0LmNvdW50LCAwKTtcbiAgICBjb25zdCBzdHJpZGUgPSBNYXRoLm1heCgxLCBNYXRoLmNlaWwodG90YWwgLyBUUkFOU0NSSVBUU18zRF9NQVgpKTtcbiAgICBpZiAoc3RyaWRlID4gMSkgY29uc29sZS53YXJuKGBbbmFwYXJpLWpzXSBkcmF3aW5nIGV2ZXJ5ICR7c3RyaWRlfXRoIG9mICR7dG90YWx9IHRyYW5zY3JpcHRzIGluIDNEYCk7XG5cbiAgICBjb25zdCBbb3gsIG95LCBvel0gPSBmcmFtZS5vcmlnaW47XG4gICAgY29uc3QgcG9zaXRpb25zOiBudW1iZXJbXSA9IFtdO1xuICAgIGNvbnN0IGdlbmVzOiBudW1iZXJbXSA9IFtdO1xuICAgIGNvbnN0IGNlbGxzOiBudW1iZXJbXSA9IFtdO1xuICAgIGxldCBzZWVuID0gMDtcbiAgICBmb3IgKGNvbnN0IHQgb2YgbG9hZGVkLnRpbGVzKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgICBpZiAoIWtlZXAodC5nZW5lW2ldKSB8fCBzZWVuKysgJSBzdHJpZGUpIGNvbnRpbnVlO1xuICAgICAgICBwb3NpdGlvbnMucHVzaCh0LnhbaV0gKyBveCwgdC55W2ldICsgb3ksIHQueltpXSArIG96KTtcbiAgICAgICAgZ2VuZXMucHVzaCh0LmdlbmVbaV0pO1xuICAgICAgICBjZWxscy5wdXNoKHQub2JzZXJ2YXRpb25baV0pO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBjb3VudCA9IGdlbmVzLmxlbmd0aDtcbiAgICBsZXQgY29sb3JzOiBGbG9hdDMyQXJyYXk7XG4gICAgaWYgKGJ5ID09PSAnZ2VuZScpIHtcbiAgICAgIGNvbG9ycyA9IHRyYW5zY3JpcHRzM2RDb2xvcnModmlldywgbmFtZXMsIFVpbnQxNkFycmF5LmZyb20oZ2VuZXMpLCBjb3VudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGdyb3VwcyA9IGF3YWl0IGNlbGxHcm91cENvbG9ycyhkYXRhc2V0LCB2aWV3LCBwb3J0KS5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgIGNvbnNvbGUud2FybignW25hcGFyaS1qc10gdGhlIGNlbGxzIGdyb3VwaW5nIGZvciB0aGUgM0QgdHJhbnNjcmlwdHMgY291bGQgbm90IGJlIHJlYWQnLCBlcnIpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH0pO1xuICAgICAgLy8gQSBuZXdlciBkcmF3IChhbm90aGVyIHN0eWxlLCBvciB0aGUgbGF5ZXIgdGFrZW4gZG93bikgd29uIHdoaWxlIHRoZSBjb2x1bW4gbG9hZGVkLlxuICAgICAgaWYgKHRoaXMubG9hZGVkICE9PSBsb2FkZWQpIHJldHVybjtcbiAgICAgIGlmIChieSA9PT0gJ2NlbGxUeXBlJykge1xuICAgICAgICBjb2xvcnMgPSBwYWNrZWQoY291bnQsIChpKSA9PiB7XG4gICAgICAgICAgY29uc3QgbyA9IGNlbGxzW2ldO1xuICAgICAgICAgIGNvbnN0IGNvZGUgPSAhZ3JvdXBzIHx8IG8gPT09IE5PX09CU0VSVkFUSU9OID8gTk9fQ0FURUdPUlkgOiBncm91cHMuY29kZXNbb107XG4gICAgICAgICAgcmV0dXJuIGNvZGUgPT09IE5PX0NBVEVHT1JZID8gdW5kZWZpbmVkIDogZ3JvdXBzIS5jb2xvcnNbY29kZV07XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQSBjbHVzdGVyIG5hbWVkIGxpa2UgYSBncm91cCBvZiB0aGUgY2VsbHMnIGdyb3VwaW5nIHRha2VzIHRoYXQgZ3JvdXAncyBjb2xvdXIsIGFzIGluIDJELlxuICAgICAgICBjb25zdCBieUNsdXN0ZXIgPSBjbHVzdGVyQ29sb3JNYXAoXG4gICAgICAgICAgdmlldy50cmFuc2NyaXB0R2VuZXMsXG4gICAgICAgICAgdmlldy50cmFuc2NyaXB0R2VuZUdyb3VwcyxcbiAgICAgICAgICBncm91cHM/LmJ5TmFtZSA/PyBuZXcgTWFwKCksXG4gICAgICAgICAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCB0YWJsZSA9IChuYW1lcyA/PyBbXSkubWFwKChnZW5lKSA9PiB7XG4gICAgICAgICAgY29uc3QgaGV4ID0gYnlDbHVzdGVyLmdldChjbHVzdGVyT2ZHZW5lKGdlbmUsIHZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHMpKTtcbiAgICAgICAgICByZXR1cm4gaGV4ID8gcmdiYTAxKGhleCkgOiB1bmRlZmluZWQ7XG4gICAgICAgIH0pO1xuICAgICAgICBjb2xvcnMgPSBwYWNrZWQoY291bnQsIChpKSA9PiB0YWJsZVtnZW5lc1tpXV0pO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGhpcy5sYXllcikgdGhpcy52aWV3ZXIubGF5ZXJzLnJlbW92ZSh0aGlzLmxheWVyKTtcbiAgICB0aGlzLmxheWVyID0gbnVsbDtcbiAgICB0aGlzLmRyYXduQ2VsbHMgPSBudWxsO1xuICAgIHRoaXMuZmFkZWRCeSA9IG51bGw7XG4gICAgdGhpcy5zdHlsZUtleSA9IHN0eWxlS2V5O1xuICAgIGlmICghY291bnQpIHJldHVybjtcbiAgICB0aGlzLmRyYXduQ2VsbHMgPSBVaW50MzJBcnJheS5mcm9tKGNlbGxzKTtcbiAgICB0aGlzLmxheWVyID0gdGhpcy52aWV3ZXIuYWRkUG9pbnRzM0QoRmxvYXQzMkFycmF5LmZyb20ocG9zaXRpb25zKSwgbmV3IEZsb2F0MzJBcnJheShjb3VudCksIHtcbiAgICAgIG5hbWU6ICd0cmFuc2NyaXB0cycsXG4gICAgICBzaXplLFxuICAgICAgb3BhY2l0eTogdmlldy50cmFuc2NyaXB0T3BhY2l0eSxcbiAgICAgIHNjYWxlM2Q6IFsxLCAxLCBmcmFtZS56U2NhbGVdLFxuICAgICAgY29sb3JzLFxuICAgIH0pO1xuICB9XG59XG5cbi8qKiBgd29ya2Agb3ZlciBgaXRlbXNgLCBhdCBtb3N0IGBsaW1pdGAgYXQgb25jZSwgcmVzdWx0cyBpbiBvcmRlci4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvb2xlZDxULCBSPihpdGVtczogcmVhZG9ubHkgVFtdLCBsaW1pdDogbnVtYmVyLCB3b3JrOiAoaXRlbTogVCkgPT4gUHJvbWlzZTxSPik6IFByb21pc2U8UltdPiB7XG4gIGNvbnN0IG91dCA9IG5ldyBBcnJheTxSPihpdGVtcy5sZW5ndGgpO1xuICBsZXQgbmV4dCA9IDA7XG4gIGNvbnN0IHJ1biA9IGFzeW5jICgpID0+IHtcbiAgICB3aGlsZSAobmV4dCA8IGl0ZW1zLmxlbmd0aCkge1xuICAgICAgY29uc3QgaSA9IG5leHQrKztcbiAgICAgIG91dFtpXSA9IGF3YWl0IHdvcmsoaXRlbXNbaV0pO1xuICAgIH1cbiAgfTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoQXJyYXkuZnJvbSh7IGxlbmd0aDogTWF0aC5taW4obGltaXQsIGl0ZW1zLmxlbmd0aCkgfSwgcnVuKSk7XG4gIHJldHVybiBvdXQ7XG59XG4iXX0=
|