@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.
Files changed (127) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +4 -2
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/geometry/cell-meshes.mjs +37 -0
  9. package/esm2022/lib/geometry/place.mjs +47 -0
  10. package/esm2022/lib/implementations/napari-js/napari-camera-depth.mjs +93 -0
  11. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  12. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +2 -2
  13. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  14. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +86 -18
  15. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-cells.mjs +746 -0
  16. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +343 -18
  17. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +427 -0
  18. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +11 -4
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +95 -5
  20. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +15 -1
  21. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +35 -8
  22. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +40 -1
  23. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +136 -28
  24. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +19 -3
  25. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +188 -52
  26. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +35 -11
  27. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +2 -2
  28. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +10 -1
  29. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +30 -3
  30. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +15 -3
  31. package/esm2022/lib/region-editor/region-editor.component.mjs +24 -4
  32. package/esm2022/lib/region-source/region-source-ops.mjs +7 -1
  33. package/esm2022/lib/region-source/region-tiles.mjs +1 -1
  34. package/esm2022/lib/region-source/worker-region-source.mjs +24 -1
  35. package/esm2022/lib/routing-visualizer.service.mjs +404 -7
  36. package/esm2022/lib/spatial/observations-in-selection.mjs +83 -0
  37. package/esm2022/lib/spatial/plane-cells.mjs +119 -0
  38. package/esm2022/lib/spatial/spatial-controls.facade.mjs +304 -8
  39. package/esm2022/lib/spatial/spatial-encoding.mjs +52 -3
  40. package/esm2022/lib/spatial/spatial-hover.mjs +34 -1
  41. package/esm2022/lib/spatial/spatial-planes.mjs +49 -0
  42. package/esm2022/lib/spatial/spatial-selection.mjs +2 -2
  43. package/esm2022/lib/spatial/spatial-tile-merge.mjs +38 -1
  44. package/esm2022/lib/spatial/transcripts-in-selection.mjs +208 -0
  45. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +42 -65
  46. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +6 -2
  47. package/esm2022/lib/spatial-controls/spatial-color-by/spatial-color-by.component.mjs +187 -0
  48. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +51 -12
  49. package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +7 -3
  50. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +21 -6
  51. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +94 -13
  52. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
  53. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
  54. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +79 -57
  55. package/esm2022/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.mjs +101 -0
  56. package/esm2022/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.mjs +94 -0
  57. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +9 -3
  58. package/esm2022/lib/store/region-source-scope.mjs +10 -1
  59. package/esm2022/lib/store/region-store.service.mjs +33 -2
  60. package/esm2022/lib/toolbar/toolbar.component.mjs +10 -3
  61. package/esm2022/lib/visualizer/spatial-region-set.mjs +95 -0
  62. package/esm2022/lib/visualizer.component.mjs +40 -4
  63. 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
  64. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs.map +1 -0
  65. 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
  66. 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
  67. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  68. package/fesm2022/region-source.worker.js +84 -2
  69. package/lib/contracts/display-types.d.ts +99 -6
  70. package/lib/contracts/image.contract.d.ts +6 -0
  71. package/lib/contracts/ports/spatial-data.port.d.ts +7 -0
  72. package/lib/contracts/region-editor-api.contract.d.ts +9 -0
  73. package/lib/contracts/region-store.contract.d.ts +6 -0
  74. package/lib/contracts/spatial-dataset.contract.d.ts +7 -1
  75. package/lib/contracts/visualizer.contract.d.ts +43 -1
  76. package/lib/geometry/cell-meshes.d.ts +27 -0
  77. package/lib/geometry/place.d.ts +45 -0
  78. package/lib/implementations/napari-js/napari-camera-depth.d.ts +23 -0
  79. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  80. package/lib/implementations/napari-js/napari-scene.d.ts +12 -0
  81. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +19 -3
  82. package/lib/implementations/napari-js/napari-spatial-3d-cells.d.ts +141 -0
  83. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +89 -0
  84. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +103 -0
  85. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +9 -2
  86. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +22 -0
  87. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +12 -0
  88. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +20 -6
  89. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +27 -1
  90. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +48 -16
  91. package/lib/implementations/napari-js/napari-volume-scene.d.ts +2 -0
  92. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +54 -1
  93. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +11 -2
  94. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +7 -0
  95. package/lib/region-editor/class-tree/class-tree.component.d.ts +16 -1
  96. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +10 -1
  97. package/lib/region-editor/region-editor.component.d.ts +4 -0
  98. package/lib/region-source/region-source-ops.d.ts +12 -0
  99. package/lib/region-source/region-tiles.d.ts +8 -0
  100. package/lib/region-source/worker-region-source.d.ts +18 -0
  101. package/lib/routing-visualizer.service.d.ts +140 -1
  102. package/lib/spatial/observations-in-selection.d.ts +43 -0
  103. package/lib/spatial/plane-cells.d.ts +37 -0
  104. package/lib/spatial/spatial-controls.facade.d.ts +59 -0
  105. package/lib/spatial/spatial-encoding.d.ts +24 -1
  106. package/lib/spatial/spatial-hover.d.ts +23 -0
  107. package/lib/spatial/spatial-planes.d.ts +22 -0
  108. package/lib/spatial/spatial-selection.d.ts +2 -1
  109. package/lib/spatial/spatial-tile-merge.d.ts +9 -0
  110. package/lib/spatial/transcripts-in-selection.d.ts +95 -0
  111. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +19 -28
  112. package/lib/spatial-controls/spatial-color-by/spatial-color-by.component.d.ts +64 -0
  113. package/lib/spatial-controls/spatial-controls.component.d.ts +19 -2
  114. package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +3 -1
  115. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +7 -0
  116. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +28 -7
  117. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +26 -23
  118. package/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.d.ts +48 -0
  119. package/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.d.ts +43 -0
  120. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +3 -1
  121. package/lib/store/region-source-scope.d.ts +4 -0
  122. package/lib/store/region-store.service.d.ts +21 -0
  123. package/lib/toolbar/toolbar.component.d.ts +6 -1
  124. package/lib/visualizer/spatial-region-set.d.ts +55 -0
  125. package/lib/visualizer.component.d.ts +14 -0
  126. package/package.json +2 -2
  127. 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=