@jax-data-science/sci-image-visualizer 0.15.0 → 0.17.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 (47) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +2 -1
  2. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  3. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  4. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +10 -8
  5. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +226 -39
  6. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +269 -0
  7. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +11 -4
  8. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +6 -7
  9. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2 -1
  10. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +33 -8
  11. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +6 -2
  12. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +10 -6
  13. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +9 -5
  14. package/esm2022/lib/spatial/spatial-controls.facade.mjs +7 -4
  15. package/esm2022/lib/spatial/spatial-encoding.mjs +18 -1
  16. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +6 -2
  17. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +7 -3
  18. package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +7 -3
  19. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +67 -19
  20. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +61 -8
  21. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +3 -3
  22. package/esm2022/lib/toolbar/toolbar.component.mjs +13 -4
  23. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +7 -7
  24. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-qUeMuBb0.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs} +795 -165
  25. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs.map +1 -0
  26. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-U1ODcfYD.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs} +2 -2
  27. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-U1ODcfYD.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs.map} +1 -1
  28. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  29. package/lib/contracts/display-types.d.ts +9 -2
  30. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  31. package/lib/implementations/napari-js/napari-scene.d.ts +2 -0
  32. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +3 -3
  33. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +82 -9
  34. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +62 -0
  35. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +9 -2
  36. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +5 -6
  37. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +16 -3
  38. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +1 -1
  39. package/lib/spatial/spatial-encoding.d.ts +10 -0
  40. package/lib/spatial-controls/spatial-controls.component.d.ts +2 -0
  41. package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +3 -1
  42. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +25 -0
  43. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +14 -3
  44. package/lib/toolbar/toolbar.component.d.ts +6 -0
  45. package/lib/toolbar/view-controls/view-controls.component.d.ts +3 -3
  46. package/package.json +2 -2
  47. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-qUeMuBb0.mjs.map +0 -1
@@ -6,7 +6,7 @@ import { OverlayPanelModule } from 'primeng/overlaypanel';
6
6
  import { TooltipModule } from 'primeng/tooltip';
7
7
  import { ALL_GENES } from '../../contracts/ports/spatial-data.port';
8
8
  import { DEFAULT_SPATIAL_VIEW } from '../../contracts/display-types';
9
- import { DEFAULT_CATEGORICAL_PALETTE } from '../../spatial/spatial-encoding';
9
+ import { DEFAULT_CATEGORICAL_PALETTE, groupColorsKey } from '../../spatial/spatial-encoding';
10
10
  import { cellTypeColumnFor, clusterColorMap, clusterOfGene, defaultGlyphFor } from '../../spatial/spatial-tiles';
11
11
  import { buildGeneTree, glyphPoints, toggleHidden } from '../../spatial/spatial-panel-model';
12
12
  import { allGeneShownBy, allGenesHidden, toggleAllGeneHidden } from '../../spatial/spatial-tile-merge';
@@ -20,6 +20,8 @@ import * as i4 from "primeng/overlaypanel";
20
20
  import * as i5 from "primeng/tooltip";
21
21
  /** Rows of the all-genes list drawn at once; the filter narrows the rest. */
22
22
  const ALL_GENES_ROWS = 200;
23
+ /** Names in reading order: case aside, and `G9` before `G10`. */
24
+ const byName = (a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
23
25
  /**
24
26
  * The selected transcript genes as Xenium Explorer's tree: the gene groups, then the
25
27
  * ungrouped genes, each row with an eye that hides it without deselecting it, its marker
@@ -28,6 +30,11 @@ const ALL_GENES_ROWS = 200;
28
30
  * expands to every gene of the dataset, each with its eye when the dataset lists its genes
29
31
  * in code order (`transcriptTiles.genes`), filtered by name past a few hundred.
30
32
  *
33
+ * Both lists are ordered by name, or by their transcripts in view, most first (the
34
+ * sort switch, offered once the renderer reports counts). The all-genes list is sorted
35
+ * before it is cut to its first rows, so by count those are the genes with the most
36
+ * transcripts in view.
37
+ *
31
38
  * Writes only through `controls.setViewState`.
32
39
  */
33
40
  export class SpatialGeneTreeComponent {
@@ -47,6 +54,10 @@ export class SpatialGeneTreeComponent {
47
54
  /** Swatches in the picker: the categorical palette genes are coloured from by default. */
48
55
  /** The tree, rebuilt when the view changes — never per change-detection pass. */
49
56
  this.geneTree = [];
57
+ /** {@link geneTree} with each node's genes in {@link geneSort} order: what the template draws. */
58
+ this.sortedTree = [];
59
+ /** The rows' order. By count only while the renderer reports counts (see {@link sortShown}). */
60
+ this.geneSort = 'name';
50
61
  /** Per gene: its eye, swatch, glyph and count — rebuilt with the inputs (and when the
51
62
  * cells' group colours arrive), so the template does no per-row lookups per check. */
52
63
  this.rows = new Map();
@@ -108,8 +119,30 @@ export class SpatialGeneTreeComponent {
108
119
  .filter((node) => node.name)
109
120
  .map((node) => [node.name, this.areGenesShown(node.genes)]));
110
121
  this.rootShown = this.view.transcriptAllGenes ? this.anyOfAllGenesShown() : this.areGenesShown(genes);
122
+ this.sortedTree = this.geneTree.map((node) => ({ ...node, genes: this.sorted(node.genes) }));
111
123
  this.rebuildAllRows();
112
124
  }
125
+ /** Whether the rows are ordered by count: chosen, and counts to order by. */
126
+ get byCount() {
127
+ return this.geneSort === 'count' && !!this.geneCounts;
128
+ }
129
+ /** The sort switch is offered once there are counts to sort by. */
130
+ get sortShown() {
131
+ return !!this.geneCounts;
132
+ }
133
+ onGeneSort(sort) {
134
+ if (sort === this.geneSort)
135
+ return;
136
+ this.geneSort = sort;
137
+ this.rebuildRows();
138
+ }
139
+ /** `genes` in the rows' order: by count, most first (ties by name), else by name. */
140
+ sorted(genes) {
141
+ if (!this.byCount)
142
+ return [...genes].sort(byName);
143
+ const counts = this.geneCounts ?? {};
144
+ return [...genes].sort((a, b) => (counts[b] ?? 0) - (counts[a] ?? 0) || byName(a, b));
145
+ }
113
146
  /**
114
147
  * The all-genes list's rows: the genes matching the filter, up to the cap. Built only while
115
148
  * the list is open: the counts in view change with every pan, and the list can be thousands.
@@ -123,24 +156,25 @@ export class SpatialGeneTreeComponent {
123
156
  }
124
157
  const needle = this.allGenesFilter.trim().toLowerCase();
125
158
  const shown = allGeneShownBy(this.view.transcriptAllGenesHidden);
126
- const rows = [];
127
- let matched = 0;
159
+ // Every match, ordered, and only then cut: by count the first rows are the most abundant.
160
+ const codes = new Map();
128
161
  list.forEach((gene, code) => {
129
162
  // An empty name is a code no transcript carries (a control probe).
130
163
  if (!gene || (needle && !gene.toLowerCase().includes(needle)))
131
164
  return;
132
- matched++;
133
- if (rows.length >= ALL_GENES_ROWS)
134
- return;
135
- rows.push({
136
- gene,
137
- shown: shown(gene),
138
- swatch: this.canHideAllGenes ? this.allGeneColorOf(gene, code) : null,
139
- count: this.geneCountOf(gene),
140
- });
165
+ if (!codes.has(gene))
166
+ codes.set(gene, code);
141
167
  });
142
- this.allRows = rows;
143
- this.allGenesMatched = matched;
168
+ this.allRows = this.sorted([...codes.keys()])
169
+ .slice(0, ALL_GENES_ROWS)
170
+ .map((gene) => ({
171
+ gene,
172
+ shown: shown(gene),
173
+ swatch: this.canHideAllGenes ? this.allGeneColorOf(gene, codes.get(gene)) : null,
174
+ code: codes.get(gene),
175
+ count: this.geneCountOf(gene),
176
+ }));
177
+ this.allGenesMatched = codes.size;
144
178
  }
145
179
  /** Whether "All genes" draws anything: not switched off whole, nor every listed gene hidden. */
146
180
  anyOfAllGenesShown() {
@@ -242,6 +276,18 @@ export class SpatialGeneTreeComponent {
242
276
  geneColorOf(gene) {
243
277
  return this.geneColor(Math.max(0, this.view.transcriptGenes.indexOf(gene)));
244
278
  }
279
+ /**
280
+ * The colour the open picker shows: with "All genes", the gene's colour among every gene (its
281
+ * chosen one, else the palette's by its code), as its row and its markers have it.
282
+ */
283
+ styleColorOf(gene) {
284
+ if (this.view.transcriptAllGenes) {
285
+ const row = this.allRows.find((r) => r.gene === gene);
286
+ if (row)
287
+ return this.allGeneColorOf(gene, row.code);
288
+ }
289
+ return this.geneColorOf(gene);
290
+ }
245
291
  /** In Cluster colouring, a gene's swatch is its cluster's colour, as its markers are. */
246
292
  geneSwatchOf(gene) {
247
293
  if (this.view.transcriptColorBy !== 'cluster')
@@ -267,9 +313,11 @@ export class SpatialGeneTreeComponent {
267
313
  }
268
314
  async refreshCellGroupColors() {
269
315
  const column = this.dataset ? cellTypeColumnFor(this.dataset, this.view) : null;
270
- if (column === this.cellGroupColorsFor)
316
+ // The user's colours for the grouping are part of what the cluster swatches show.
317
+ const key = column === null ? null : `${column}\u0001${groupColorsKey(column, this.view.groupColors)}`;
318
+ if (key === this.cellGroupColorsFor)
271
319
  return;
272
- this.cellGroupColorsFor = column;
320
+ this.cellGroupColorsFor = key;
273
321
  const task = this.cellGroupColorsLoad.next();
274
322
  const map = new Map();
275
323
  const meta = column ? this.dataset?.columns.find((c) => c.name === column) : null;
@@ -295,7 +343,7 @@ export class SpatialGeneTreeComponent {
295
343
  });
296
344
  }
297
345
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialGeneTreeComponent, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
298
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialGeneTreeComponent, isStandalone: true, selector: "spatial-gene-tree", inputs: { controls: "controls", dataset: "dataset", view: "view", geneCounts: "geneCounts", geneTotal: "geneTotal" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"sc-subhead\">Selected genes</div>\n<div class=\"sc-gene-tree\">\n <div class=\"sc-gene-row sc-gene-root\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n (click)=\"\n view.transcriptAllGenes ? onAllGenesShown(!rootShown) : onGenesShown(view.transcriptGenes, !rootShown)\n \"\n >\n <i class=\"pi\" [class.pi-eye]=\"rootShown\" [class.pi-eye-slash]=\"!rootShown\"></i>\n </button>\n <span class=\"sc-group-label\">Genes</span>\n <span class=\"sc-count\"\n >({{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{\n geneTotal | number\n }})</span\n >\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"geneTreeOpen = !geneTreeOpen\"\n *ngIf=\"!view.transcriptAllGenes && view.transcriptGenes.length\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"geneTreeOpen\" [class.pi-chevron-right]=\"!geneTreeOpen\"></i>\n </button>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"toggleAllGenesOpen()\"\n *ngIf=\"view.transcriptAllGenes && allGeneList?.length\"\n [attr.aria-label]=\"allGenesOpen ? 'Hide the gene list' : 'Show every gene'\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"allGenesOpen\" [class.pi-chevron-right]=\"!allGenesOpen\"></i>\n </button>\n </div>\n <!-- \"All genes\": every gene of the dataset, each with its eye when the dataset says which\n transcripts are whose (its gene list in code order). -->\n <ng-container *ngIf=\"allGenesOpen && view.transcriptAllGenes && allGeneList?.length\">\n <input\n pInputText\n class=\"sc-gene-filter\"\n placeholder=\"Filter genes\u2026\"\n aria-label=\"Filter genes\"\n [value]=\"allGenesFilter\"\n (input)=\"onAllGenesFilter($any($event.target).value)\"\n />\n <small class=\"sc-hint\" *ngIf=\"!canHideAllGenes\">\n This dataset does not say which transcripts are whose, so its genes cannot be hidden one by one.\n </small>\n <small class=\"sc-hint\" *ngIf=\"canHideAllGenes && view.transcriptMode === 'density'\">\n The density map draws every gene as one raster: genes are hidden one by one as circles or icons.\n </small>\n <div class=\"sc-gene-row sc-gene-leaf nested\" *ngFor=\"let row of allRows; trackBy: trackByAllRow\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n [disabled]=\"!canHideAllGenes || view.transcriptMode === 'density'\"\n (click)=\"onAllGeneShown(row.gene, !row.shown)\"\n >\n <i class=\"pi\" [class.pi-eye]=\"row.shown\" [class.pi-eye-slash]=\"!row.shown\"></i>\n </button>\n <span class=\"sc-gene-icon\" *ngIf=\"row.swatch\" [style.color]=\"row.swatch\" aria-hidden=\"true\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\"><circle r=\"0.75\"></circle></svg>\n </span>\n <span class=\"sc-group-label\" [title]=\"row.gene\">{{ row.gene }}</span>\n <span class=\"sc-gene-count\" *ngIf=\"row.count !== null\" title=\"Transcripts in view\">{{\n row.count | number\n }}</span>\n </div>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched > allRows.length\">\n Showing {{ allRows.length | number }} of {{ allGenesMatched | number }} genes: filter to find the others.\n </small>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched === 0\">No gene matches.</small>\n </ng-container>\n <ng-container *ngIf=\"geneTreeOpen && !view.transcriptAllGenes\">\n <ng-container *ngFor=\"let node of geneTree; trackBy: trackByNode\">\n <div class=\"sc-gene-row sc-gene-group\" *ngIf=\"node.name\">\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown(node.genes, !groupShown.get(node.name))\">\n <i\n class=\"pi\"\n [class.pi-eye]=\"groupShown.get(node.name)\"\n [class.pi-eye-slash]=\"!groupShown.get(node.name)\"\n ></i>\n </button>\n <span class=\"sc-group-label\" [title]=\"node.name\">{{ node.name }}</span>\n <span class=\"sc-count\">({{ node.genes.length }})</span>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"toggleGeneGroup(node.name)\">\n <i\n class=\"pi\"\n [class.pi-chevron-down]=\"!collapsedGeneGroups.has(node.name)\"\n [class.pi-chevron-right]=\"collapsedGeneGroups.has(node.name)\"\n ></i>\n </button>\n </div>\n <ng-container *ngIf=\"!node.name || !collapsedGeneGroups.has(node.name)\">\n <div\n class=\"sc-gene-row sc-gene-leaf\"\n [class.nested]=\"!!node.name\"\n *ngFor=\"let gene of node.genes; trackBy: trackByLabelString\"\n >\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown([gene], !rows.get(gene)?.shown)\">\n <i class=\"pi\" [class.pi-eye]=\"rows.get(gene)?.shown\" [class.pi-eye-slash]=\"!rows.get(gene)?.shown\"></i>\n </button>\n <!-- The gene's marker, in its colour: its icon in Icons mode, a dot for circles.\n Clicking it opens the icon and colour picker (as Xenium Explorer does). -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"rows.get(gene)?.swatch\"\n [attr.aria-label]=\"'Icon and colour for ' + gene\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon\n *ngIf=\"view.transcriptMode === 'glyphs'; else dotIcon\"\n [attr.points]=\"rows.get(gene)?.points\"\n ></polygon>\n <ng-template #dotIcon><circle r=\"0.75\"></circle></ng-template>\n </svg>\n </button>\n <span class=\"sc-group-label\">{{ gene }}</span>\n <span\n class=\"sc-gene-count\"\n *ngIf=\"rows.get(gene)?.count as n; else zeroCount\"\n title=\"Transcripts in view\"\n >{{ n | number }}</span\n >\n <ng-template #zeroCount>\n <span class=\"sc-gene-count\" *ngIf=\"geneCounts\" title=\"Transcripts in view\">0</span>\n </ng-template>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n <!-- One picker for every gene row, filled for the gene that opened it. -->\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as gene\"\n [gene]=\"gene\"\n what=\"Transcript\"\n [color]=\"geneColorOf(gene)\"\n [glyph]=\"styleGlyph ?? 'circle'\"\n [iconHint]=\"\n view.transcriptMode !== 'glyphs' ? 'Icons show when the transcript point style is Icons.' : null\n \"\n (colorChange)=\"onGeneColor(gene, $event)\"\n (glyphChange)=\"onGlyph(gene, $event)\"\n (resetStyle)=\"resetGeneStyle(gene)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n <div class=\"sc-gene-footer\">\n {{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{ geneTotal | number }}\n genes selected\n </div>\n</div>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}:host{display:contents}.sc-gene-group,.sc-gene-leaf{padding-left:1rem}.sc-gene-leaf.nested{padding-left:2rem}.sc-eye{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:0;color:var(--text-color-secondary, #6c757d)}.sc-eye .pi-eye{color:var(--text-color, #333)}.sc-eye:disabled{cursor:default;opacity:.5}.sc-gene-filter{width:calc(100% - 1rem);margin:.2rem 0 .2rem 1rem;font-size:.8rem;padding:.2rem .4rem}.sc-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.sc-gene-count{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.8;padding-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: SharedModule }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: OverlayPanelModule }, { kind: "component", type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: SpatialGeneStyleComponent, selector: "spatial-gene-style", inputs: ["gene", "what", "color", "glyph", "iconHint"], outputs: ["colorChange", "glyphChange", "resetStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
346
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialGeneTreeComponent, isStandalone: true, selector: "spatial-gene-tree", inputs: { controls: "controls", dataset: "dataset", view: "view", geneCounts: "geneCounts", geneTotal: "geneTotal" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"sc-subhead\">Selected genes</div>\n<div class=\"sc-gene-sort\" *ngIf=\"sortShown\" role=\"group\" aria-label=\"Sort genes\">\n <span class=\"sc-lbl\">Sort by</span>\n <button\n type=\"button\"\n class=\"sc-sort-btn\"\n [class.active]=\"!byCount\"\n [attr.aria-pressed]=\"!byCount\"\n (click)=\"onGeneSort('name')\"\n >\n Name\n </button>\n <button\n type=\"button\"\n class=\"sc-sort-btn\"\n [class.active]=\"byCount\"\n [attr.aria-pressed]=\"byCount\"\n title=\"Transcripts in view, most first\"\n (click)=\"onGeneSort('count')\"\n >\n Count\n </button>\n</div>\n<div class=\"sc-gene-tree\">\n <div class=\"sc-gene-row sc-gene-root\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n (click)=\"\n view.transcriptAllGenes ? onAllGenesShown(!rootShown) : onGenesShown(view.transcriptGenes, !rootShown)\n \"\n >\n <i class=\"pi\" [class.pi-eye]=\"rootShown\" [class.pi-eye-slash]=\"!rootShown\"></i>\n </button>\n <span class=\"sc-group-label\">Genes</span>\n <span class=\"sc-count\"\n >({{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{\n geneTotal | number\n }})</span\n >\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"geneTreeOpen = !geneTreeOpen\"\n *ngIf=\"!view.transcriptAllGenes && view.transcriptGenes.length\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"geneTreeOpen\" [class.pi-chevron-right]=\"!geneTreeOpen\"></i>\n </button>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"toggleAllGenesOpen()\"\n *ngIf=\"view.transcriptAllGenes && allGeneList?.length\"\n [attr.aria-label]=\"allGenesOpen ? 'Hide the gene list' : 'Show every gene'\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"allGenesOpen\" [class.pi-chevron-right]=\"!allGenesOpen\"></i>\n </button>\n </div>\n <!-- \"All genes\": every gene of the dataset, each with its eye when the dataset says which\n transcripts are whose (its gene list in code order). -->\n <ng-container *ngIf=\"allGenesOpen && view.transcriptAllGenes && allGeneList?.length\">\n <input\n pInputText\n class=\"sc-gene-filter\"\n placeholder=\"Filter genes\u2026\"\n aria-label=\"Filter genes\"\n [value]=\"allGenesFilter\"\n (input)=\"onAllGenesFilter($any($event.target).value)\"\n />\n <small class=\"sc-hint\" *ngIf=\"!canHideAllGenes\">\n This dataset does not say which transcripts are whose, so its genes cannot be hidden one by one.\n </small>\n <small class=\"sc-hint\" *ngIf=\"canHideAllGenes && view.transcriptMode === 'density'\">\n The density map draws every gene as one raster: genes are hidden one by one as circles or icons.\n </small>\n <div class=\"sc-gene-row sc-gene-leaf nested\" *ngFor=\"let row of allRows; trackBy: trackByAllRow\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n [disabled]=\"!canHideAllGenes || view.transcriptMode === 'density'\"\n (click)=\"onAllGeneShown(row.gene, !row.shown)\"\n >\n <i class=\"pi\" [class.pi-eye]=\"row.shown\" [class.pi-eye-slash]=\"!row.shown\"></i>\n </button>\n <!-- The gene's colour among every gene; clicking it opens the colour picker. -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n *ngIf=\"row.swatch\"\n [style.color]=\"row.swatch\"\n [attr.aria-label]=\"'Colour for ' + row.gene\"\n pTooltip=\"Colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, row.gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\"><circle r=\"0.75\"></circle></svg>\n </button>\n <span class=\"sc-group-label\" [title]=\"row.gene\">{{ row.gene }}</span>\n <span class=\"sc-gene-count\" *ngIf=\"row.count !== null\" title=\"Transcripts in view\">{{\n row.count | number\n }}</span>\n </div>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched > allRows.length\">\n Showing {{ allRows.length | number }} of {{ allGenesMatched | number }} genes: filter to find the others.\n </small>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched === 0\">No gene matches.</small>\n </ng-container>\n <ng-container *ngIf=\"geneTreeOpen && !view.transcriptAllGenes\">\n <ng-container *ngFor=\"let node of sortedTree; trackBy: trackByNode\">\n <div class=\"sc-gene-row sc-gene-group\" *ngIf=\"node.name\">\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown(node.genes, !groupShown.get(node.name))\">\n <i\n class=\"pi\"\n [class.pi-eye]=\"groupShown.get(node.name)\"\n [class.pi-eye-slash]=\"!groupShown.get(node.name)\"\n ></i>\n </button>\n <span class=\"sc-group-label\" [title]=\"node.name\">{{ node.name }}</span>\n <span class=\"sc-count\">({{ node.genes.length }})</span>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"toggleGeneGroup(node.name)\">\n <i\n class=\"pi\"\n [class.pi-chevron-down]=\"!collapsedGeneGroups.has(node.name)\"\n [class.pi-chevron-right]=\"collapsedGeneGroups.has(node.name)\"\n ></i>\n </button>\n </div>\n <ng-container *ngIf=\"!node.name || !collapsedGeneGroups.has(node.name)\">\n <div\n class=\"sc-gene-row sc-gene-leaf\"\n [class.nested]=\"!!node.name\"\n *ngFor=\"let gene of node.genes; trackBy: trackByLabelString\"\n >\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown([gene], !rows.get(gene)?.shown)\">\n <i class=\"pi\" [class.pi-eye]=\"rows.get(gene)?.shown\" [class.pi-eye-slash]=\"!rows.get(gene)?.shown\"></i>\n </button>\n <!-- The gene's marker, in its colour: its icon in Icons mode, a dot for circles.\n Clicking it opens the icon and colour picker (as Xenium Explorer does). -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"rows.get(gene)?.swatch\"\n [attr.aria-label]=\"'Icon and colour for ' + gene\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon\n *ngIf=\"view.transcriptMode === 'glyphs'; else dotIcon\"\n [attr.points]=\"rows.get(gene)?.points\"\n ></polygon>\n <ng-template #dotIcon><circle r=\"0.75\"></circle></ng-template>\n </svg>\n </button>\n <span class=\"sc-group-label\">{{ gene }}</span>\n <span\n class=\"sc-gene-count\"\n *ngIf=\"rows.get(gene)?.count as n; else zeroCount\"\n title=\"Transcripts in view\"\n >{{ n | number }}</span\n >\n <ng-template #zeroCount>\n <span class=\"sc-gene-count\" *ngIf=\"geneCounts\" title=\"Transcripts in view\">0</span>\n </ng-template>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n <!-- One picker for every gene row, filled for the gene that opened it. -->\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as gene\"\n [gene]=\"gene\"\n what=\"Transcript\"\n [color]=\"styleColorOf(gene)\"\n [glyph]=\"styleGlyph ?? 'circle'\"\n [showIcons]=\"!view.transcriptAllGenes\"\n [iconHint]=\"\n view.transcriptMode !== 'glyphs' ? 'Icons show when the transcript point style is Icons.' : null\n \"\n (colorChange)=\"onGeneColor(gene, $event)\"\n (glyphChange)=\"onGlyph(gene, $event)\"\n (resetStyle)=\"resetGeneStyle(gene)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n <div class=\"sc-gene-footer\">\n {{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{ geneTotal | number }}\n genes selected\n </div>\n</div>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}:host{display:contents}.sc-gene-group,.sc-gene-leaf{padding-left:1rem}.sc-gene-leaf.nested{padding-left:2rem}.sc-eye{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:0;color:var(--text-color-secondary, #6c757d)}.sc-eye .pi-eye{color:var(--text-color, #333)}.sc-eye:disabled{cursor:default;opacity:.5}.sc-gene-sort{display:flex;align-items:center;gap:.25rem;font-size:.8rem}.sc-gene-sort .sc-lbl{margin-right:auto}.sc-sort-btn{border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);color:var(--text-color, #333);border-radius:4px;padding:.1rem .5rem;font:inherit;cursor:pointer}.sc-sort-btn.active{border-color:var(--primary-color, #2196f3);color:var(--primary-color, #2196f3);font-weight:600}.sc-gene-filter{width:calc(100% - 1rem);margin:.2rem 0 .2rem 1rem;font-size:.8rem;padding:.2rem .4rem}.sc-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.sc-gene-count{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.8;padding-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: SharedModule }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: OverlayPanelModule }, { kind: "component", type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: SpatialGeneStyleComponent, selector: "spatial-gene-style", inputs: ["gene", "what", "color", "glyph", "iconHint", "showIcons"], outputs: ["colorChange", "glyphChange", "resetStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
299
347
  }
300
348
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialGeneTreeComponent, decorators: [{
301
349
  type: Component,
@@ -306,7 +354,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
306
354
  OverlayPanelModule,
307
355
  TooltipModule,
308
356
  SpatialGeneStyleComponent,
309
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"sc-subhead\">Selected genes</div>\n<div class=\"sc-gene-tree\">\n <div class=\"sc-gene-row sc-gene-root\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n (click)=\"\n view.transcriptAllGenes ? onAllGenesShown(!rootShown) : onGenesShown(view.transcriptGenes, !rootShown)\n \"\n >\n <i class=\"pi\" [class.pi-eye]=\"rootShown\" [class.pi-eye-slash]=\"!rootShown\"></i>\n </button>\n <span class=\"sc-group-label\">Genes</span>\n <span class=\"sc-count\"\n >({{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{\n geneTotal | number\n }})</span\n >\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"geneTreeOpen = !geneTreeOpen\"\n *ngIf=\"!view.transcriptAllGenes && view.transcriptGenes.length\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"geneTreeOpen\" [class.pi-chevron-right]=\"!geneTreeOpen\"></i>\n </button>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"toggleAllGenesOpen()\"\n *ngIf=\"view.transcriptAllGenes && allGeneList?.length\"\n [attr.aria-label]=\"allGenesOpen ? 'Hide the gene list' : 'Show every gene'\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"allGenesOpen\" [class.pi-chevron-right]=\"!allGenesOpen\"></i>\n </button>\n </div>\n <!-- \"All genes\": every gene of the dataset, each with its eye when the dataset says which\n transcripts are whose (its gene list in code order). -->\n <ng-container *ngIf=\"allGenesOpen && view.transcriptAllGenes && allGeneList?.length\">\n <input\n pInputText\n class=\"sc-gene-filter\"\n placeholder=\"Filter genes\u2026\"\n aria-label=\"Filter genes\"\n [value]=\"allGenesFilter\"\n (input)=\"onAllGenesFilter($any($event.target).value)\"\n />\n <small class=\"sc-hint\" *ngIf=\"!canHideAllGenes\">\n This dataset does not say which transcripts are whose, so its genes cannot be hidden one by one.\n </small>\n <small class=\"sc-hint\" *ngIf=\"canHideAllGenes && view.transcriptMode === 'density'\">\n The density map draws every gene as one raster: genes are hidden one by one as circles or icons.\n </small>\n <div class=\"sc-gene-row sc-gene-leaf nested\" *ngFor=\"let row of allRows; trackBy: trackByAllRow\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n [disabled]=\"!canHideAllGenes || view.transcriptMode === 'density'\"\n (click)=\"onAllGeneShown(row.gene, !row.shown)\"\n >\n <i class=\"pi\" [class.pi-eye]=\"row.shown\" [class.pi-eye-slash]=\"!row.shown\"></i>\n </button>\n <span class=\"sc-gene-icon\" *ngIf=\"row.swatch\" [style.color]=\"row.swatch\" aria-hidden=\"true\">\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\"><circle r=\"0.75\"></circle></svg>\n </span>\n <span class=\"sc-group-label\" [title]=\"row.gene\">{{ row.gene }}</span>\n <span class=\"sc-gene-count\" *ngIf=\"row.count !== null\" title=\"Transcripts in view\">{{\n row.count | number\n }}</span>\n </div>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched > allRows.length\">\n Showing {{ allRows.length | number }} of {{ allGenesMatched | number }} genes: filter to find the others.\n </small>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched === 0\">No gene matches.</small>\n </ng-container>\n <ng-container *ngIf=\"geneTreeOpen && !view.transcriptAllGenes\">\n <ng-container *ngFor=\"let node of geneTree; trackBy: trackByNode\">\n <div class=\"sc-gene-row sc-gene-group\" *ngIf=\"node.name\">\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown(node.genes, !groupShown.get(node.name))\">\n <i\n class=\"pi\"\n [class.pi-eye]=\"groupShown.get(node.name)\"\n [class.pi-eye-slash]=\"!groupShown.get(node.name)\"\n ></i>\n </button>\n <span class=\"sc-group-label\" [title]=\"node.name\">{{ node.name }}</span>\n <span class=\"sc-count\">({{ node.genes.length }})</span>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"toggleGeneGroup(node.name)\">\n <i\n class=\"pi\"\n [class.pi-chevron-down]=\"!collapsedGeneGroups.has(node.name)\"\n [class.pi-chevron-right]=\"collapsedGeneGroups.has(node.name)\"\n ></i>\n </button>\n </div>\n <ng-container *ngIf=\"!node.name || !collapsedGeneGroups.has(node.name)\">\n <div\n class=\"sc-gene-row sc-gene-leaf\"\n [class.nested]=\"!!node.name\"\n *ngFor=\"let gene of node.genes; trackBy: trackByLabelString\"\n >\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown([gene], !rows.get(gene)?.shown)\">\n <i class=\"pi\" [class.pi-eye]=\"rows.get(gene)?.shown\" [class.pi-eye-slash]=\"!rows.get(gene)?.shown\"></i>\n </button>\n <!-- The gene's marker, in its colour: its icon in Icons mode, a dot for circles.\n Clicking it opens the icon and colour picker (as Xenium Explorer does). -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"rows.get(gene)?.swatch\"\n [attr.aria-label]=\"'Icon and colour for ' + gene\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon\n *ngIf=\"view.transcriptMode === 'glyphs'; else dotIcon\"\n [attr.points]=\"rows.get(gene)?.points\"\n ></polygon>\n <ng-template #dotIcon><circle r=\"0.75\"></circle></ng-template>\n </svg>\n </button>\n <span class=\"sc-group-label\">{{ gene }}</span>\n <span\n class=\"sc-gene-count\"\n *ngIf=\"rows.get(gene)?.count as n; else zeroCount\"\n title=\"Transcripts in view\"\n >{{ n | number }}</span\n >\n <ng-template #zeroCount>\n <span class=\"sc-gene-count\" *ngIf=\"geneCounts\" title=\"Transcripts in view\">0</span>\n </ng-template>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n <!-- One picker for every gene row, filled for the gene that opened it. -->\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as gene\"\n [gene]=\"gene\"\n what=\"Transcript\"\n [color]=\"geneColorOf(gene)\"\n [glyph]=\"styleGlyph ?? 'circle'\"\n [iconHint]=\"\n view.transcriptMode !== 'glyphs' ? 'Icons show when the transcript point style is Icons.' : null\n \"\n (colorChange)=\"onGeneColor(gene, $event)\"\n (glyphChange)=\"onGlyph(gene, $event)\"\n (resetStyle)=\"resetGeneStyle(gene)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n <div class=\"sc-gene-footer\">\n {{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{ geneTotal | number }}\n genes selected\n </div>\n</div>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}:host{display:contents}.sc-gene-group,.sc-gene-leaf{padding-left:1rem}.sc-gene-leaf.nested{padding-left:2rem}.sc-eye{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:0;color:var(--text-color-secondary, #6c757d)}.sc-eye .pi-eye{color:var(--text-color, #333)}.sc-eye:disabled{cursor:default;opacity:.5}.sc-gene-filter{width:calc(100% - 1rem);margin:.2rem 0 .2rem 1rem;font-size:.8rem;padding:.2rem .4rem}.sc-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.sc-gene-count{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.8;padding-left:.5rem}\n"] }]
357
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"sc-subhead\">Selected genes</div>\n<div class=\"sc-gene-sort\" *ngIf=\"sortShown\" role=\"group\" aria-label=\"Sort genes\">\n <span class=\"sc-lbl\">Sort by</span>\n <button\n type=\"button\"\n class=\"sc-sort-btn\"\n [class.active]=\"!byCount\"\n [attr.aria-pressed]=\"!byCount\"\n (click)=\"onGeneSort('name')\"\n >\n Name\n </button>\n <button\n type=\"button\"\n class=\"sc-sort-btn\"\n [class.active]=\"byCount\"\n [attr.aria-pressed]=\"byCount\"\n title=\"Transcripts in view, most first\"\n (click)=\"onGeneSort('count')\"\n >\n Count\n </button>\n</div>\n<div class=\"sc-gene-tree\">\n <div class=\"sc-gene-row sc-gene-root\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n (click)=\"\n view.transcriptAllGenes ? onAllGenesShown(!rootShown) : onGenesShown(view.transcriptGenes, !rootShown)\n \"\n >\n <i class=\"pi\" [class.pi-eye]=\"rootShown\" [class.pi-eye-slash]=\"!rootShown\"></i>\n </button>\n <span class=\"sc-group-label\">Genes</span>\n <span class=\"sc-count\"\n >({{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{\n geneTotal | number\n }})</span\n >\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"geneTreeOpen = !geneTreeOpen\"\n *ngIf=\"!view.transcriptAllGenes && view.transcriptGenes.length\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"geneTreeOpen\" [class.pi-chevron-right]=\"!geneTreeOpen\"></i>\n </button>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n (click)=\"toggleAllGenesOpen()\"\n *ngIf=\"view.transcriptAllGenes && allGeneList?.length\"\n [attr.aria-label]=\"allGenesOpen ? 'Hide the gene list' : 'Show every gene'\"\n >\n <i class=\"pi\" [class.pi-chevron-down]=\"allGenesOpen\" [class.pi-chevron-right]=\"!allGenesOpen\"></i>\n </button>\n </div>\n <!-- \"All genes\": every gene of the dataset, each with its eye when the dataset says which\n transcripts are whose (its gene list in code order). -->\n <ng-container *ngIf=\"allGenesOpen && view.transcriptAllGenes && allGeneList?.length\">\n <input\n pInputText\n class=\"sc-gene-filter\"\n placeholder=\"Filter genes\u2026\"\n aria-label=\"Filter genes\"\n [value]=\"allGenesFilter\"\n (input)=\"onAllGenesFilter($any($event.target).value)\"\n />\n <small class=\"sc-hint\" *ngIf=\"!canHideAllGenes\">\n This dataset does not say which transcripts are whose, so its genes cannot be hidden one by one.\n </small>\n <small class=\"sc-hint\" *ngIf=\"canHideAllGenes && view.transcriptMode === 'density'\">\n The density map draws every gene as one raster: genes are hidden one by one as circles or icons.\n </small>\n <div class=\"sc-gene-row sc-gene-leaf nested\" *ngFor=\"let row of allRows; trackBy: trackByAllRow\">\n <button\n type=\"button\"\n class=\"sc-eye\"\n [disabled]=\"!canHideAllGenes || view.transcriptMode === 'density'\"\n (click)=\"onAllGeneShown(row.gene, !row.shown)\"\n >\n <i class=\"pi\" [class.pi-eye]=\"row.shown\" [class.pi-eye-slash]=\"!row.shown\"></i>\n </button>\n <!-- The gene's colour among every gene; clicking it opens the colour picker. -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n *ngIf=\"row.swatch\"\n [style.color]=\"row.swatch\"\n [attr.aria-label]=\"'Colour for ' + row.gene\"\n pTooltip=\"Colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, row.gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\"><circle r=\"0.75\"></circle></svg>\n </button>\n <span class=\"sc-group-label\" [title]=\"row.gene\">{{ row.gene }}</span>\n <span class=\"sc-gene-count\" *ngIf=\"row.count !== null\" title=\"Transcripts in view\">{{\n row.count | number\n }}</span>\n </div>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched > allRows.length\">\n Showing {{ allRows.length | number }} of {{ allGenesMatched | number }} genes: filter to find the others.\n </small>\n <small class=\"sc-hint\" *ngIf=\"allGenesMatched === 0\">No gene matches.</small>\n </ng-container>\n <ng-container *ngIf=\"geneTreeOpen && !view.transcriptAllGenes\">\n <ng-container *ngFor=\"let node of sortedTree; trackBy: trackByNode\">\n <div class=\"sc-gene-row sc-gene-group\" *ngIf=\"node.name\">\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown(node.genes, !groupShown.get(node.name))\">\n <i\n class=\"pi\"\n [class.pi-eye]=\"groupShown.get(node.name)\"\n [class.pi-eye-slash]=\"!groupShown.get(node.name)\"\n ></i>\n </button>\n <span class=\"sc-group-label\" [title]=\"node.name\">{{ node.name }}</span>\n <span class=\"sc-count\">({{ node.genes.length }})</span>\n <button type=\"button\" class=\"sc-icon-btn\" (click)=\"toggleGeneGroup(node.name)\">\n <i\n class=\"pi\"\n [class.pi-chevron-down]=\"!collapsedGeneGroups.has(node.name)\"\n [class.pi-chevron-right]=\"collapsedGeneGroups.has(node.name)\"\n ></i>\n </button>\n </div>\n <ng-container *ngIf=\"!node.name || !collapsedGeneGroups.has(node.name)\">\n <div\n class=\"sc-gene-row sc-gene-leaf\"\n [class.nested]=\"!!node.name\"\n *ngFor=\"let gene of node.genes; trackBy: trackByLabelString\"\n >\n <button type=\"button\" class=\"sc-eye\" (click)=\"onGenesShown([gene], !rows.get(gene)?.shown)\">\n <i class=\"pi\" [class.pi-eye]=\"rows.get(gene)?.shown\" [class.pi-eye-slash]=\"!rows.get(gene)?.shown\"></i>\n </button>\n <!-- The gene's marker, in its colour: its icon in Icons mode, a dot for circles.\n Clicking it opens the icon and colour picker (as Xenium Explorer does). -->\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"rows.get(gene)?.swatch\"\n [attr.aria-label]=\"'Icon and colour for ' + gene\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, gene, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon\n *ngIf=\"view.transcriptMode === 'glyphs'; else dotIcon\"\n [attr.points]=\"rows.get(gene)?.points\"\n ></polygon>\n <ng-template #dotIcon><circle r=\"0.75\"></circle></ng-template>\n </svg>\n </button>\n <span class=\"sc-group-label\">{{ gene }}</span>\n <span\n class=\"sc-gene-count\"\n *ngIf=\"rows.get(gene)?.count as n; else zeroCount\"\n title=\"Transcripts in view\"\n >{{ n | number }}</span\n >\n <ng-template #zeroCount>\n <span class=\"sc-gene-count\" *ngIf=\"geneCounts\" title=\"Transcripts in view\">0</span>\n </ng-template>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n <!-- One picker for every gene row, filled for the gene that opened it. -->\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as gene\"\n [gene]=\"gene\"\n what=\"Transcript\"\n [color]=\"styleColorOf(gene)\"\n [glyph]=\"styleGlyph ?? 'circle'\"\n [showIcons]=\"!view.transcriptAllGenes\"\n [iconHint]=\"\n view.transcriptMode !== 'glyphs' ? 'Icons show when the transcript point style is Icons.' : null\n \"\n (colorChange)=\"onGeneColor(gene, $event)\"\n (glyphChange)=\"onGlyph(gene, $event)\"\n (resetStyle)=\"resetGeneStyle(gene)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n <div class=\"sc-gene-footer\">\n {{ (view.transcriptAllGenes ? geneTotal : view.transcriptGenes.length) | number }}/{{ geneTotal | number }}\n genes selected\n </div>\n</div>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}:host{display:contents}.sc-gene-group,.sc-gene-leaf{padding-left:1rem}.sc-gene-leaf.nested{padding-left:2rem}.sc-eye{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:0;color:var(--text-color-secondary, #6c757d)}.sc-eye .pi-eye{color:var(--text-color, #333)}.sc-eye:disabled{cursor:default;opacity:.5}.sc-gene-sort{display:flex;align-items:center;gap:.25rem;font-size:.8rem}.sc-gene-sort .sc-lbl{margin-right:auto}.sc-sort-btn{border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);color:var(--text-color, #333);border-radius:4px;padding:.1rem .5rem;font:inherit;cursor:pointer}.sc-sort-btn.active{border-color:var(--primary-color, #2196f3);color:var(--primary-color, #2196f3);font-weight:600}.sc-gene-filter{width:calc(100% - 1rem);margin:.2rem 0 .2rem 1rem;font-size:.8rem;padding:.2rem .4rem}.sc-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.sc-gene-count{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.8;padding-left:.5rem}\n"] }]
310
358
  }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { controls: [{
311
359
  type: Input
312
360
  }], dataset: [{
@@ -318,4 +366,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
318
366
  }], geneTotal: [{
319
367
  type: Input
320
368
  }] } });
321
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1nZW5lLXRyZWUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtZ2VuZS10cmVlL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWdlbmUtdHJlZS9zcGF0aWFsLWdlbmUtdHJlZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sR0FHUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBSWhELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsb0JBQW9CLEVBQXlDLE1BQU0sK0JBQStCLENBQUM7QUFDNUcsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDN0UsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakgsT0FBTyxFQUFnQixhQUFhLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQzNHLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLG1C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WixZQUFZO3dCQUNaLGVBQWU7d0JBQ2Ysa0JBQWtCO3dCQUNsQixhQUFhO3dCQUNiLHlCQUF5QjtxQkFDMUIsbUJBR2dCLHVCQUF1QixDQUFDLE1BQU07MkdBSXRDLFFBQVE7c0JBQWhCLEtBQUs7Z0JBRUcsT0FBTztzQkFBZixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFRyxVQUFVO3NCQUFsQixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgSW5wdXQsXG4gIE5nWm9uZSxcbiAgT25DaGFuZ2VzLFxuICBTaW1wbGVDaGFuZ2VzLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBTaGFyZWRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2FwaSc7XG5pbXBvcnQgeyBJbnB1dFRleHRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2lucHV0dGV4dCc7XG5pbXBvcnQgeyBPdmVybGF5UGFuZWxNb2R1bGUgfSBmcm9tICdwcmltZW5nL292ZXJsYXlwYW5lbCc7XG5pbXBvcnQgeyBUb29sdGlwTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90b29sdGlwJztcblxuaW1wb3J0IHR5cGUgeyBJU3BhdGlhbENvbnRyb2xzIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHR5cGUgeyBTcGF0aWFsRGF0YXNldCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHsgQUxMX0dFTkVTIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB7IERFRkFVTFRfU1BBVElBTF9WSUVXLCBTcGF0aWFsVmlld1N0YXRlLCBUcmFuc2NyaXB0R2x5cGhOYW1lIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nJztcbmltcG9ydCB7IGNlbGxUeXBlQ29sdW1uRm9yLCBjbHVzdGVyQ29sb3JNYXAsIGNsdXN0ZXJPZkdlbmUsIGRlZmF1bHRHbHlwaEZvciB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC10aWxlcyc7XG5pbXBvcnQgeyBHZW5lVHJlZU5vZGUsIGJ1aWxkR2VuZVRyZWUsIGdseXBoUG9pbnRzLCB0b2dnbGVIaWRkZW4gfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtcGFuZWwtbW9kZWwnO1xuaW1wb3J0IHsgYWxsR2VuZVNob3duQnksIGFsbEdlbmVzSGlkZGVuLCB0b2dnbGVBbGxHZW5lSGlkZGVuIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXRpbGUtbWVyZ2UnO1xuaW1wb3J0IHsgU3VwZXJzZWRlIH0gZnJvbSAnLi4vLi4vdXRpbC9zdXBlcnNlZGUnO1xuaW1wb3J0IHsgU3BhdGlhbEdlbmVTdHlsZUNvbXBvbmVudCB9IGZyb20gJy4uL3NwYXRpYWwtZ2VuZS1zdHlsZS9zcGF0aWFsLWdlbmUtc3R5bGUuY29tcG9uZW50JztcblxuLyoqIFJvd3Mgb2YgdGhlIGFsbC1nZW5lcyBsaXN0IGRyYXduIGF0IG9uY2U7IHRoZSBmaWx0ZXIgbmFycm93cyB0aGUgcmVzdC4gKi9cbmNvbnN0IEFMTF9HRU5FU19ST1dTID0gMjAwO1xuXG4vKiogT25lIGdlbmUgcm93IGFzIHRoZSB0ZW1wbGF0ZSBkcmF3cyBpdCwgZGVyaXZlZCBvbmNlIHBlciBpbnB1dCBjaGFuZ2UuICovXG5pbnRlcmZhY2UgR2VuZVJvd1ZpZXcge1xuICBzaG93bjogYm9vbGVhbjtcbiAgc3dhdGNoOiBzdHJpbmc7XG4gIC8qKiBUaGUgcm93J3MgZ2x5cGggb3V0bGluZSAoZHJhd24gaW4gSWNvbnMgbW9kZSkuICovXG4gIHBvaW50czogc3RyaW5nO1xuICAvKiogVHJhbnNjcmlwdHMgaW4gdmlldywgb3IgbnVsbCBiZWZvcmUgdGhlIHJlbmRlcmVyIHJlcG9ydHMgYW55LiAqL1xuICBjb3VudDogbnVtYmVyIHwgbnVsbDtcbn1cblxuLyoqIE9uZSByb3cgb2YgdGhlIGFsbC1nZW5lcyBsaXN0LiAqL1xuaW50ZXJmYWNlIEFsbEdlbmVSb3dWaWV3IHtcbiAgZ2VuZTogc3RyaW5nO1xuICBzaG93bjogYm9vbGVhbjtcbiAgLyoqIEl0cyBjb2xvdXIgd2hlbiBjb2xvdXJlZCBieSBnZW5lLCBvciBudWxsIHdoZW4gdGhlIGRhdGFzZXQncyBjb2RlIG9yZGVyIGlzIHVua25vd24uICovXG4gIHN3YXRjaDogc3RyaW5nIHwgbnVsbDtcbiAgY291bnQ6IG51bWJlciB8IG51bGw7XG59XG5cbi8qKlxuICogVGhlIHNlbGVjdGVkIHRyYW5zY3JpcHQgZ2VuZXMgYXMgWGVuaXVtIEV4cGxvcmVyJ3MgdHJlZTogdGhlIGdlbmUgZ3JvdXBzLCB0aGVuIHRoZVxuICogdW5ncm91cGVkIGdlbmVzLCBlYWNoIHJvdyB3aXRoIGFuIGV5ZSB0aGF0IGhpZGVzIGl0IHdpdGhvdXQgZGVzZWxlY3RpbmcgaXQsIGl0cyBtYXJrZXJcbiAqIGluIGl0cyBjb2xvdXIgKG9wZW5pbmcgb25lIGljb24tYW5kLWNvbG91ciBwaWNrZXIgcGVyIGdlbmUpLCBhbmQgaXRzIHRyYW5zY3JpcHQgY291bnQgaW5cbiAqIHZpZXcuIFdpdGggXCJBbGwgZ2VuZXNcIiBvbiwgdGhlIHJvb3QgZXllIGhpZGVzIG9yIHNob3dzIGV2ZXJ5IHRyYW5zY3JpcHQgYW5kIHRoZSByb290XG4gKiBleHBhbmRzIHRvIGV2ZXJ5IGdlbmUgb2YgdGhlIGRhdGFzZXQsIGVhY2ggd2l0aCBpdHMgZXllIHdoZW4gdGhlIGRhdGFzZXQgbGlzdHMgaXRzIGdlbmVzXG4gKiBpbiBjb2RlIG9yZGVyIChgdHJhbnNjcmlwdFRpbGVzLmdlbmVzYCksIGZpbHRlcmVkIGJ5IG5hbWUgcGFzdCBhIGZldyBodW5kcmVkLlxuICpcbiAqIFdyaXRlcyBvbmx5IHRocm91Z2ggYGNvbnRyb2xzLnNldFZpZXdTdGF0ZWAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NwYXRpYWwtZ2VuZS10cmVlJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIENvbW1vbk1vZHVsZSxcbiAgICBTaGFyZWRNb2R1bGUsXG4gICAgSW5wdXRUZXh0TW9kdWxlLFxuICAgIE92ZXJsYXlQYW5lbE1vZHVsZSxcbiAgICBUb29sdGlwTW9kdWxlLFxuICAgIFNwYXRpYWxHZW5lU3R5bGVDb21wb25lbnQsXG4gIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9zcGF0aWFsLWdlbmUtdHJlZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBTcGF0aWFsR2VuZVRyZWVDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xuICAvKiogVGhlIHNwYXRpYWwgY29udHJvbHMgdGhpcyBwYW5lbCByZWFkcyBhbmQgd3JpdGVzIHRocm91Z2g7IG51bGwgd2l0aG91dCBhIGBTUEFUSUFMX0RBVEFfUE9SVGAuICovXG4gIEBJbnB1dCgpIGNvbnRyb2xzOiBJU3BhdGlhbENvbnRyb2xzIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgZGF0YXNldCBvbiBvZmZlciwgb3IgbnVsbC4gKi9cbiAgQElucHV0KCkgZGF0YXNldDogU3BhdGlhbERhdGFzZXQgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBjdXJyZW50IHNwYXRpYWwgdmlldyBzdGF0ZTogd2hhdCBpcyBkcmF3biwgYW5kIGhvdy4gKi9cbiAgQElucHV0KCkgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSA9IERFRkFVTFRfU1BBVElBTF9WSUVXO1xuICAvKiogVHJhbnNjcmlwdHMgb2YgZWFjaCBzZWxlY3RlZCBnZW5lIGluIHRoZSBjdXJyZW50IHZpZXcsIGZyb20gdGhlIHJlbmRlcmVyLiAqL1xuICBASW5wdXQoKSBnZW5lQ291bnRzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBSZWFsIGdlbmVzIGluIHRoZSBwYW5lbCDigJQgdGhlIHRyZWUncyBkZW5vbWluYXRvci4gKi9cbiAgQElucHV0KCkgZ2VuZVRvdGFsID0gMDtcblxuICAvKiogU3dhdGNoZXMgaW4gdGhlIHBpY2tlcjogdGhlIGNhdGVnb3JpY2FsIHBhbGV0dGUgZ2VuZXMgYXJlIGNvbG91cmVkIGZyb20gYnkgZGVmYXVsdC4gKi9cblxuICAvKiogVGhlIHRyZWUsIHJlYnVpbHQgd2hlbiB0aGUgdmlldyBjaGFuZ2VzIOKAlCBuZXZlciBwZXIgY2hhbmdlLWRldGVjdGlvbiBwYXNzLiAqL1xuICBwcm90ZWN0ZWQgZ2VuZVRyZWU6IEdlbmVUcmVlTm9kZVtdID0gW107XG4gIC8qKiBQZXIgZ2VuZTogaXRzIGV5ZSwgc3dhdGNoLCBnbHlwaCBhbmQgY291bnQg4oCUIHJlYnVpbHQgd2l0aCB0aGUgaW5wdXRzIChhbmQgd2hlbiB0aGVcbiAgICogIGNlbGxzJyBncm91cCBjb2xvdXJzIGFycml2ZSksIHNvIHRoZSB0ZW1wbGF0ZSBkb2VzIG5vIHBlci1yb3cgbG9va3VwcyBwZXIgY2hlY2suICovXG4gIHByb3RlY3RlZCByb3dzID0gbmV3IE1hcDxzdHJpbmcsIEdlbmVSb3dWaWV3PigpO1xuICAvKiogUGVyIG5hbWVkIGdyb3VwLCBhbmQgZm9yIHRoZSByb290OiB3aGV0aGVyIGFueSBvZiBpdHMgZ2VuZXMgaXMgc2hvd24uICovXG4gIHByb3RlY3RlZCBncm91cFNob3duID0gbmV3IE1hcDxzdHJpbmcsIGJvb2xlYW4+KCk7XG4gIHByb3RlY3RlZCByb290U2hvd24gPSBmYWxzZTtcbiAgcHJvdGVjdGVkIGNvbGxhcHNlZEdlbmVHcm91cHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJvdGVjdGVkIGdlbmVUcmVlT3BlbiA9IHRydWU7XG4gIC8qKiBUaGUgYWxsLWdlbmVzIGxpc3Qgc3RhcnRzIGNsb3NlZDogaXQgY2FuIHJ1biB0byB0aG91c2FuZHMgb2YgZ2VuZXMuICovXG4gIHByb3RlY3RlZCBhbGxHZW5lc09wZW4gPSBmYWxzZTtcbiAgLyoqIFRoZSBnZW5lcyBcIkFsbCBnZW5lc1wiIGxpc3RzLCBvciBudWxsIHdoZW4gdGhlIGRhdGFzZXQgbmFtZXMgbm9uZS4gKi9cbiAgcHJvdGVjdGVkIGFsbEdlbmVMaXN0OiByZWFkb25seSBzdHJpbmdbXSB8IG51bGwgPSBudWxsO1xuICAvKiogV2hldGhlciBhIGdlbmUgb2YgXCJBbGwgZ2VuZXNcIiBjYW4gYmUgaGlkZGVuOiB0aGUgZGF0YXNldCBsaXN0cyBpdHMgZ2VuZXMgaW4gY29kZSBvcmRlci4gKi9cbiAgcHJvdGVjdGVkIGNhbkhpZGVBbGxHZW5lcyA9IGZhbHNlO1xuICBwcm90ZWN0ZWQgYWxsR2VuZXNGaWx0ZXIgPSAnJztcbiAgLyoqIFRoZSBsaXN0J3Mgcm93cyBtYXRjaGluZyB0aGUgZmlsdGVyLCBhdCBtb3N0IHtAbGluayBBTExfR0VORVNfUk9XU30uICovXG4gIHByb3RlY3RlZCBhbGxSb3dzOiBBbGxHZW5lUm93Vmlld1tdID0gW107XG4gIC8qKiBIb3cgbWFueSBnZW5lcyBtYXRjaCB0aGUgZmlsdGVyLCBmb3IgdGhlIFwic2hvd2luZyBuIG9mIG1cIiBsaW5lLiAqL1xuICBwcm90ZWN0ZWQgYWxsR2VuZXNNYXRjaGVkID0gMDtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGFsbEdlbmVzUm93Q2FwID0gQUxMX0dFTkVTX1JPV1M7XG4gIC8qKiBUaGUgZ2VuZSB0aGUgb3BlbiBwaWNrZXIgZWRpdHMuICovXG4gIHByb3RlY3RlZCBzdHlsZUdlbmU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBDb2xvdXJzIG9mIHRoZSBjZWxscycgZ3JvdXBzLCBieSBuYW1lIOKAlCB3aGF0IGEgY2x1c3RlciBvZiB0aGUgc2FtZSBuYW1lIGlzIGRyYXduIGluLiAqL1xuICBwcml2YXRlIGNlbGxHcm91cENvbG9ycyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gIC8qKiBUaGUgZ3JvdXBpbmcge0BsaW5rIGNlbGxHcm91cENvbG9yc30gYmVsb25ncyB0byDigJQgYSByZXBlYXQgcmVxdWVzdCBmb3IgaXQgaXMgYSBuby1vcC4gKi9cbiAgcHJpdmF0ZSBjZWxsR3JvdXBDb2xvcnNGb3I6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIC8qKiBMYXRlc3Qgd2lucyBhbW9uZyBjb2xvdXIgbG9hZHMgZm9yIHtAbGluayBjZWxsR3JvdXBDb2xvcnN9LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNlbGxHcm91cENvbG9yc0xvYWQgPSBuZXcgU3VwZXJzZWRlKCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSB6b25lOiBOZ1pvbmUsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICApIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWyd2aWV3J10pIHRoaXMuZ2VuZVRyZWUgPSBidWlsZEdlbmVUcmVlKHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUdyb3Vwcyk7XG4gICAgLy8gQSBzYW1lLW5hbWVkIGdyb3VwaW5nIG9mIGEgbmV3IGRhdGFzZXQgaXMgbm90IHRoZSBvbGQgb25lLlxuICAgIGlmIChjaGFuZ2VzWydkYXRhc2V0J10pIHtcbiAgICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzRm9yID0gdW5kZWZpbmVkO1xuICAgICAgY29uc3QgY29kZWQgPSB0aGlzLmRhdGFzZXQ/LnRyYW5zY3JpcHRUaWxlcz8uZ2VuZXM7XG4gICAgICB0aGlzLmNhbkhpZGVBbGxHZW5lcyA9ICEhY29kZWQ/Lmxlbmd0aDtcbiAgICAgIHRoaXMuYWxsR2VuZUxpc3QgPSBjb2RlZD8ubGVuZ3RoID8gY29kZWQgOiAodGhpcy5kYXRhc2V0Py5mZWF0dXJlcz8ubmFtZXMgPz8gbnVsbCk7XG4gICAgfVxuICAgIHRoaXMucmVidWlsZFJvd3MoKTtcbiAgICB2b2lkIHRoaXMucmVmcmVzaENlbGxHcm91cENvbG9ycygpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWJ1aWxkUm93cygpOiB2b2lkIHtcbiAgICBjb25zdCBnZW5lcyA9IHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXM7XG4gICAgdGhpcy5yb3dzID0gbmV3IE1hcChcbiAgICAgIGdlbmVzLm1hcCgoZ2VuZSwgc2xvdCkgPT4gW1xuICAgICAgICBnZW5lLFxuICAgICAgICB7XG4gICAgICAgICAgc2hvd246IHRoaXMuaXNHZW5lU2hvd24oZ2VuZSksXG4gICAgICAgICAgc3dhdGNoOiB0aGlzLmdlbmVTd2F0Y2hPZihnZW5lKSxcbiAgICAgICAgICBwb2ludHM6IGdseXBoUG9pbnRzKHRoaXMuZ2x5cGhPZihnZW5lLCBzbG90KSksXG4gICAgICAgICAgY291bnQ6IHRoaXMuZ2VuZUNvdW50T2YoZ2VuZSksXG4gICAgICAgIH0sXG4gICAgICBdKSxcbiAgICApO1xuICAgIHRoaXMuZ3JvdXBTaG93biA9IG5ldyBNYXAoXG4gICAgICB0aGlzLmdlbmVUcmVlXG4gICAgICAgIC5maWx0ZXIoKG5vZGUpID0+IG5vZGUubmFtZSlcbiAgICAgICAgLm1hcCgobm9kZSkgPT4gW25vZGUubmFtZSBhcyBzdHJpbmcsIHRoaXMuYXJlR2VuZXNTaG93bihub2RlLmdlbmVzKV0pLFxuICAgICk7XG4gICAgdGhpcy5yb290U2hvd24gPSB0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gdGhpcy5hbnlPZkFsbEdlbmVzU2hvd24oKSA6IHRoaXMuYXJlR2VuZXNTaG93bihnZW5lcyk7XG4gICAgdGhpcy5yZWJ1aWxkQWxsUm93cygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBhbGwtZ2VuZXMgbGlzdCdzIHJvd3M6IHRoZSBnZW5lcyBtYXRjaGluZyB0aGUgZmlsdGVyLCB1cCB0byB0aGUgY2FwLiBCdWlsdCBvbmx5IHdoaWxlXG4gICAqIHRoZSBsaXN0IGlzIG9wZW46IHRoZSBjb3VudHMgaW4gdmlldyBjaGFuZ2Ugd2l0aCBldmVyeSBwYW4sIGFuZCB0aGUgbGlzdCBjYW4gYmUgdGhvdXNhbmRzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWJ1aWxkQWxsUm93cygpOiB2b2lkIHtcbiAgICBjb25zdCBsaXN0ID0gdGhpcy52aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyAmJiB0aGlzLmFsbEdlbmVzT3BlbiA/IHRoaXMuYWxsR2VuZUxpc3QgOiBudWxsO1xuICAgIGlmICghbGlzdCkge1xuICAgICAgdGhpcy5hbGxSb3dzID0gW107XG4gICAgICB0aGlzLmFsbEdlbmVzTWF0Y2hlZCA9IDA7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG5lZWRsZSA9IHRoaXMuYWxsR2VuZXNGaWx0ZXIudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gICAgY29uc3Qgc2hvd24gPSBhbGxHZW5lU2hvd25CeSh0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzSGlkZGVuKTtcbiAgICBjb25zdCByb3dzOiBBbGxHZW5lUm93Vmlld1tdID0gW107XG4gICAgbGV0IG1hdGNoZWQgPSAwO1xuICAgIGxpc3QuZm9yRWFjaCgoZ2VuZSwgY29kZSkgPT4ge1xuICAgICAgLy8gQW4gZW1wdHkgbmFtZSBpcyBhIGNvZGUgbm8gdHJhbnNjcmlwdCBjYXJyaWVzIChhIGNvbnRyb2wgcHJvYmUpLlxuICAgICAgaWYgKCFnZW5lIHx8IChuZWVkbGUgJiYgIWdlbmUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhuZWVkbGUpKSkgcmV0dXJuO1xuICAgICAgbWF0Y2hlZCsrO1xuICAgICAgaWYgKHJvd3MubGVuZ3RoID49IEFMTF9HRU5FU19ST1dTKSByZXR1cm47XG4gICAgICByb3dzLnB1c2goe1xuICAgICAgICBnZW5lLFxuICAgICAgICBzaG93bjogc2hvd24oZ2VuZSksXG4gICAgICAgIHN3YXRjaDogdGhpcy5jYW5IaWRlQWxsR2VuZXMgPyB0aGlzLmFsbEdlbmVDb2xvck9mKGdlbmUsIGNvZGUpIDogbnVsbCxcbiAgICAgICAgY291bnQ6IHRoaXMuZ2VuZUNvdW50T2YoZ2VuZSksXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICB0aGlzLmFsbFJvd3MgPSByb3dzO1xuICAgIHRoaXMuYWxsR2VuZXNNYXRjaGVkID0gbWF0Y2hlZDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIFwiQWxsIGdlbmVzXCIgZHJhd3MgYW55dGhpbmc6IG5vdCBzd2l0Y2hlZCBvZmYgd2hvbGUsIG5vciBldmVyeSBsaXN0ZWQgZ2VuZSBoaWRkZW4uICovXG4gIHByaXZhdGUgYW55T2ZBbGxHZW5lc1Nob3duKCk6IGJvb2xlYW4ge1xuICAgIGlmIChhbGxHZW5lc0hpZGRlbih0aGlzLnZpZXcpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKCF0aGlzLmNhbkhpZGVBbGxHZW5lcyB8fCAhdGhpcy5hbGxHZW5lTGlzdCkgcmV0dXJuIHRydWU7XG4gICAgY29uc3Qgc2hvd24gPSBhbGxHZW5lU2hvd25CeSh0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzSGlkZGVuKTtcbiAgICByZXR1cm4gdGhpcy5hbGxHZW5lTGlzdC5zb21lKChnKSA9PiBnICYmIHNob3duKGcpKTtcbiAgfVxuXG4gIC8qKiBBIGdlbmUgb2YgXCJBbGwgZ2VuZXNcIiBpbiBpdHMgY29sb3VyIGJ5IGdlbmU6IGl0cyBjaG9zZW4gb25lLCBlbHNlIHRoZSBwYWxldHRlJ3MgYnkgY29kZS4gKi9cbiAgcHJpdmF0ZSBhbGxHZW5lQ29sb3JPZihnZW5lOiBzdHJpbmcsIGNvZGU6IG51bWJlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUNvbG9yc1tnZW5lXSB8fFxuICAgICAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFW2NvZGUgJSBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEUubGVuZ3RoXVxuICAgICk7XG4gIH1cblxuICBwcm90ZWN0ZWQgdG9nZ2xlQWxsR2VuZXNPcGVuKCk6IHZvaWQge1xuICAgIHRoaXMuYWxsR2VuZXNPcGVuID0gIXRoaXMuYWxsR2VuZXNPcGVuO1xuICAgIHRoaXMucmVidWlsZEFsbFJvd3MoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkFsbEdlbmVzRmlsdGVyKHRleHQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuYWxsR2VuZXNGaWx0ZXIgPSB0ZXh0O1xuICAgIHRoaXMucmVidWlsZEFsbFJvd3MoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0b2dnbGVHZW5lR3JvdXAobmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IG5ldyBTZXQodGhpcy5jb2xsYXBzZWRHZW5lR3JvdXBzKTtcbiAgICBpZiAobmV4dC5oYXMobmFtZSkpIG5leHQuZGVsZXRlKG5hbWUpO1xuICAgIGVsc2UgbmV4dC5hZGQobmFtZSk7XG4gICAgdGhpcy5jb2xsYXBzZWRHZW5lR3JvdXBzID0gbmV4dDtcbiAgfVxuXG4gIHByb3RlY3RlZCBpc0dlbmVTaG93bihnZW5lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMudmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMuaW5jbHVkZXMoZ2VuZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXJlR2VuZXNTaG93bihnZW5lczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgICByZXR1cm4gZ2VuZXMuc29tZSgoZykgPT4gdGhpcy5pc0dlbmVTaG93bihnKSk7XG4gIH1cblxuICAvKiogVGhlIGV5ZSB0b2dnbGU6IGhpZGUgb3Igc2hvdyBnZW5lcyB3aXRob3V0IHJlbW92aW5nIHRoZW0gZnJvbSB0aGUgc2VsZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25HZW5lc1Nob3duKGdlbmVzOiBzdHJpbmdbXSwgb246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoe1xuICAgICAgdHJhbnNjcmlwdEhpZGRlbkdlbmVzOiB0b2dnbGVIaWRkZW4odGhpcy52aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcywgZ2VuZXMsIG9uKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBUaGUgcm9vdCBleWUgd2hpbGUgZXZlcnkgZ2VuZSBpcyBkcmF3bjogaGlkZSBvciBzaG93IHRoZW0gYWxsICh0aGUgJ8KxJyBsZWF2ZXMgXCJBbGwgZ2VuZXNcIikuICovXG4gIHByb3RlY3RlZCBvbkFsbEdlbmVzU2hvd24ob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0QWxsR2VuZXNIaWRkZW46IG9uID8gW10gOiBbQUxMX0dFTkVTXSB9KTtcbiAgfVxuXG4gIC8qKiBPbmUgZ2VuZSdzIGV5ZSBpbiB0aGUgYWxsLWdlbmVzIGxpc3QuIFNob3dpbmcgb25lIHdoaWxlIGFsbCBhcmUgb2ZmIHNob3dzIGl0IGFsb25lLiAqL1xuICBwcm90ZWN0ZWQgb25BbGxHZW5lU2hvd24oZ2VuZTogc3RyaW5nLCBvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICghdGhpcy5jYW5IaWRlQWxsR2VuZXMpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoe1xuICAgICAgdHJhbnNjcmlwdEFsbEdlbmVzSGlkZGVuOiB0b2dnbGVBbGxHZW5lSGlkZGVuKHRoaXMudmlldy50cmFuc2NyaXB0QWxsR2VuZXNIaWRkZW4sIGdlbmUsIG9uKSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkdlbmVDb2xvcihnZW5lOiBzdHJpbmcsIGhleDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdHJhbnNjcmlwdEdlbmVDb2xvcnM6IHsgLi4udGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lQ29sb3JzLCBbZ2VuZV06IGhleCB9IH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIHBlci1nZW5lIGljb24gYW5kIGNvbG91ciBwaWNrZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJvdGVjdGVkIG9wZW5HZW5lU3R5bGUoZXZlbnQ6IEV2ZW50LCBnZW5lOiBzdHJpbmcsIHBhbmVsOiB7IHRvZ2dsZShlOiBFdmVudCk6IHZvaWQ7IGhpZGUoKTogdm9pZCB9KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc3R5bGVHZW5lID09PSBnZW5lKSB7XG4gICAgICBwYW5lbC50b2dnbGUoZXZlbnQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnN0eWxlR2VuZSA9IGdlbmU7XG4gICAgcGFuZWwuaGlkZSgpO1xuICAgIC8vIFJlLW9wZW4gYW5jaG9yZWQgb24gdGhlIHJvdyB0aGF0IHdhcyBjbGlja2VkLCBvbmNlIHRoZSBwYW5lbCBoYXMgY2xvc2VkLlxuICAgIHNldFRpbWVvdXQoKCkgPT4gcGFuZWwudG9nZ2xlKGV2ZW50KSk7XG4gIH1cblxuICAvKiogVGhlIGljb24gdGhlIG9wZW4gcGlja2VyIHNob3dzIGFzIGNob3Nlbi4gKi9cbiAgcHJvdGVjdGVkIGdldCBzdHlsZUdseXBoKCk6IFRyYW5zY3JpcHRHbHlwaE5hbWUgfCBudWxsIHtcbiAgICBjb25zdCBnZW5lID0gdGhpcy5zdHlsZUdlbmU7XG4gICAgcmV0dXJuIGdlbmUgPyB0aGlzLmdseXBoT2YoZ2VuZSwgTWF0aC5tYXgoMCwgdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lcy5pbmRleE9mKGdlbmUpKSkgOiBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdseXBoUG9pbnRzKGdseXBoOiBUcmFuc2NyaXB0R2x5cGhOYW1lKTogc3RyaW5nIHtcbiAgICByZXR1cm4gZ2x5cGhQb2ludHMoZ2x5cGgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdseXBoT2YoZ2VuZTogc3RyaW5nLCBzbG90OiBudW1iZXIpOiBUcmFuc2NyaXB0R2x5cGhOYW1lIHtcbiAgICByZXR1cm4gdGhpcy52aWV3LnRyYW5zY3JpcHRHbHlwaHNbZ2VuZV0gPz8gZGVmYXVsdEdseXBoRm9yKHNsb3QpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uR2x5cGgoZ2VuZTogc3RyaW5nLCBnbHlwaDogVHJhbnNjcmlwdEdseXBoTmFtZSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRHbHlwaHM6IHsgLi4udGhpcy52aWV3LnRyYW5zY3JpcHRHbHlwaHMsIFtnZW5lXTogZ2x5cGggfSB9KTtcbiAgfVxuXG4gIC8qKiBCYWNrIHRvIHRoZSBnZW5lJ3MgZGVmYXVsdCBpY29uIGFuZCBjb2xvdXIgKGJ5IGl0cyBwb3NpdGlvbiBpbiB0aGUgbGlzdCkuICovXG4gIHByb3RlY3RlZCByZXNldEdlbmVTdHlsZShnZW5lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjb2xvcnMgPSB7IC4uLnRoaXMudmlldy50cmFuc2NyaXB0R2VuZUNvbG9ycyB9O1xuICAgIGNvbnN0IGdseXBocyA9IHsgLi4udGhpcy52aWV3LnRyYW5zY3JpcHRHbHlwaHMgfTtcbiAgICBkZWxldGUgY29sb3JzW2dlbmVdO1xuICAgIGRlbGV0ZSBnbHlwaHNbZ2VuZV07XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdHJhbnNjcmlwdEdlbmVDb2xvcnM6IGNvbG9ycywgdHJhbnNjcmlwdEdseXBoczogZ2x5cGhzIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIGNvbG91cnMgYW5kIGNvdW50cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogVGhlIGNvbG91ciBnZW5lIGBzbG90YCBpcyBkcmF3biBpbiB3aGVuIHRyYW5zY3JpcHRzIGFyZSBjb2xvdXJlZCBieSBnZW5lLiAqL1xuICBnZW5lQ29sb3Ioc2xvdDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBnZW5lID0gdGhpcy52aWV3Py50cmFuc2NyaXB0R2VuZXNbc2xvdF07XG4gICAgcmV0dXJuIChcbiAgICAgIChnZW5lICYmIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUNvbG9yc1tnZW5lXSkgfHxcbiAgICAgIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURVtzbG90ICUgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLmxlbmd0aF1cbiAgICApO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdlbmVDb2xvck9mKGdlbmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZ2VuZUNvbG9yKE1hdGgubWF4KDAsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMuaW5kZXhPZihnZW5lKSkpO1xuICB9XG5cbiAgLyoqIEluIENsdXN0ZXIgY29sb3VyaW5nLCBhIGdlbmUncyBzd2F0Y2ggaXMgaXRzIGNsdXN0ZXIncyBjb2xvdXIsIGFzIGl0cyBtYXJrZXJzIGFyZS4gKi9cbiAgcHJvdGVjdGVkIGdlbmVTd2F0Y2hPZihnZW5lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLnZpZXcudHJhbnNjcmlwdENvbG9yQnkgIT09ICdjbHVzdGVyJykgcmV0dXJuIHRoaXMuZ2VuZUNvbG9yT2YoZ2VuZSk7XG4gICAgcmV0dXJuIHRoaXMuY2x1c3RlckNvbG9ycygpLmdldChjbHVzdGVyT2ZHZW5lKGdlbmUsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUdyb3VwcykpID8/IHRoaXMuZ2VuZUNvbG9yT2YoZ2VuZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2VuZUNvdW50T2YoZ2VuZTogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZ2VuZUNvdW50cyA/ICh0aGlzLmdlbmVDb3VudHNbZ2VuZV0gPz8gMCkgOiBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRyYWNrQnlOb2RlID0gKF9pOiBudW1iZXIsIG5vZGU6IHsgbmFtZTogc3RyaW5nIHwgbnVsbCB9KSA9PiBub2RlLm5hbWUgPz8gJyc7XG4gIHByb3RlY3RlZCB0cmFja0J5TGFiZWxTdHJpbmcgPSAoX2k6IG51bWJlciwgczogc3RyaW5nKSA9PiBzO1xuICBwcm90ZWN0ZWQgdHJhY2tCeUFsbFJvdyA9IChfaTogbnVtYmVyLCByb3c6IEFsbEdlbmVSb3dWaWV3KSA9PiByb3cuZ2VuZTtcblxuICAvKipcbiAgICogVGhlIGNsdXN0ZXIgY29sb3VycywgcmVidWlsdCBvbmx5IHdoZW4gd2hhdCB0aGV5IGNvbWUgZnJvbSBjaGFuZ2VzLiBUaGUgdGVtcGxhdGUgYXNrc1xuICAgKiBvbmNlIHBlciBnZW5lIHJvdyBwZXIgY2hhbmdlLWRldGVjdGlvbiBwYXNzLCBhbmQgcmVidWlsZGluZyBwZXIgY2FsbCBtYWRlIHRoYXQgTyhHwrIpLlxuICAgKi9cbiAgcHJpdmF0ZSBjbHVzdGVyQ29sb3JzKCk6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICAgIGNvbnN0IHsgdHJhbnNjcmlwdEdlbmVzOiBnZW5lcywgdHJhbnNjcmlwdEdlbmVHcm91cHM6IGdyb3VwcyB9ID0gdGhpcy52aWV3O1xuICAgIGNvbnN0IGhpdCA9IHRoaXMuY2x1c3RlckNvbG9yTWVtbztcbiAgICBpZiAoaGl0ICYmIGhpdC5nZW5lcyA9PT0gZ2VuZXMgJiYgaGl0Lmdyb3VwcyA9PT0gZ3JvdXBzICYmIGhpdC5jZWxsQ29sb3JzID09PSB0aGlzLmNlbGxHcm91cENvbG9ycykge1xuICAgICAgcmV0dXJuIGhpdC5jb2xvcnM7XG4gICAgfVxuICAgIGNvbnN0IGNvbG9ycyA9IGNsdXN0ZXJDb2xvck1hcChnZW5lcywgZ3JvdXBzLCB0aGlzLmNlbGxHcm91cENvbG9ycywgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFKTtcbiAgICB0aGlzLmNsdXN0ZXJDb2xvck1lbW8gPSB7IGdlbmVzLCBncm91cHMsIGNlbGxDb2xvcnM6IHRoaXMuY2VsbEdyb3VwQ29sb3JzLCBjb2xvcnMgfTtcbiAgICByZXR1cm4gY29sb3JzO1xuICB9XG4gIHByaXZhdGUgY2x1c3RlckNvbG9yTWVtbzoge1xuICAgIGdlbmVzOiBTcGF0aWFsVmlld1N0YXRlWyd0cmFuc2NyaXB0R2VuZXMnXTtcbiAgICBncm91cHM6IFNwYXRpYWxWaWV3U3RhdGVbJ3RyYW5zY3JpcHRHZW5lR3JvdXBzJ107XG4gICAgY2VsbENvbG9yczogTWFwPHN0cmluZywgc3RyaW5nPjtcbiAgICBjb2xvcnM6IE1hcDxzdHJpbmcsIHN0cmluZz47XG4gIH0gfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIGFzeW5jIHJlZnJlc2hDZWxsR3JvdXBDb2xvcnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29sdW1uID0gdGhpcy5kYXRhc2V0ID8gY2VsbFR5cGVDb2x1bW5Gb3IodGhpcy5kYXRhc2V0LCB0aGlzLnZpZXcpIDogbnVsbDtcbiAgICBpZiAoY29sdW1uID09PSB0aGlzLmNlbGxHcm91cENvbG9yc0ZvcikgcmV0dXJuO1xuICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzRm9yID0gY29sdW1uO1xuICAgIGNvbnN0IHRhc2sgPSB0aGlzLmNlbGxHcm91cENvbG9yc0xvYWQubmV4dCgpO1xuICAgIGNvbnN0IG1hcCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgY29uc3QgbWV0YSA9IGNvbHVtbiA/IHRoaXMuZGF0YXNldD8uY29sdW1ucy5maW5kKChjKSA9PiBjLm5hbWUgPT09IGNvbHVtbikgOiBudWxsO1xuICAgIGlmIChtZXRhICYmIG1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJyAmJiB0aGlzLmNvbnRyb2xzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb2xvcnMgPSBhd2FpdCB0aGlzLmNvbnRyb2xzLmNhdGVnb3J5Q29sb3JzKGNvbHVtbiEpO1xuICAgICAgICBtZXRhLmNhdGVnb3JpZXMuZm9yRWFjaCgoYywgaykgPT4ge1xuICAgICAgICAgIGlmIChjb2xvcnNba10pIG1hcC5zZXQoYywgY29sb3JzW2tdKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gTm8gY29sb3VyczogcGFsZXR0ZSBjb2xvdXJzLCBhcyB0aGUgbWFya2VycyBmYWxsIGJhY2sgdG8uXG4gICAgICB9XG4gICAgfVxuICAgIC8vIFRoZSBjZWxscycgZ3JvdXBpbmcgY2hhbmdlZCB3aGlsZSB0aGUgY29sb3VycyBsb2FkZWQ6IHRoZSBuZXdlciByZXF1ZXN0IGFwcGxpZXMgaXRzIG93bi5cbiAgICBpZiAoIXRhc2suaXNDdXJyZW50KCkpIHJldHVybjtcbiAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcbiAgICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzID0gbWFwO1xuICAgICAgdGhpcy5yZWJ1aWxkUm93cygpO1xuICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgfSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJzYy1zdWJoZWFkXCI+U2VsZWN0ZWQgZ2VuZXM8L2Rpdj5cbjxkaXYgY2xhc3M9XCJzYy1nZW5lLXRyZWVcIj5cbiAgPGRpdiBjbGFzcz1cInNjLWdlbmUtcm93IHNjLWdlbmUtcm9vdFwiPlxuICAgIDxidXR0b25cbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgY2xhc3M9XCJzYy1leWVcIlxuICAgICAgKGNsaWNrKT1cIlxuICAgICAgICB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IG9uQWxsR2VuZXNTaG93bighcm9vdFNob3duKSA6IG9uR2VuZXNTaG93bih2aWV3LnRyYW5zY3JpcHRHZW5lcywgIXJvb3RTaG93bilcbiAgICAgIFwiXG4gICAgPlxuICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1leWVdPVwicm9vdFNob3duXCIgW2NsYXNzLnBpLWV5ZS1zbGFzaF09XCIhcm9vdFNob3duXCI+PC9pPlxuICAgIDwvYnV0dG9uPlxuICAgIDxzcGFuIGNsYXNzPVwic2MtZ3JvdXAtbGFiZWxcIj5HZW5lczwvc3Bhbj5cbiAgICA8c3BhbiBjbGFzcz1cInNjLWNvdW50XCJcbiAgICAgID4oe3sgKHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gZ2VuZVRvdGFsIDogdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoKSB8IG51bWJlciB9fS97e1xuICAgICAgICBnZW5lVG90YWwgfCBudW1iZXJcbiAgICAgIH19KTwvc3BhblxuICAgID5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwic2MtaWNvbi1idG5cIlxuICAgICAgKGNsaWNrKT1cImdlbmVUcmVlT3BlbiA9ICFnZW5lVHJlZU9wZW5cIlxuICAgICAgKm5nSWY9XCIhdmlldy50cmFuc2NyaXB0QWxsR2VuZXMgJiYgdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoXCJcbiAgICA+XG4gICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWNoZXZyb24tZG93bl09XCJnZW5lVHJlZU9wZW5cIiBbY2xhc3MucGktY2hldnJvbi1yaWdodF09XCIhZ2VuZVRyZWVPcGVuXCI+PC9pPlxuICAgIDwvYnV0dG9uPlxuICAgIDxidXR0b25cbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgY2xhc3M9XCJzYy1pY29uLWJ0blwiXG4gICAgICAoY2xpY2spPVwidG9nZ2xlQWxsR2VuZXNPcGVuKClcIlxuICAgICAgKm5nSWY9XCJ2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyAmJiBhbGxHZW5lTGlzdD8ubGVuZ3RoXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYWxsR2VuZXNPcGVuID8gJ0hpZGUgdGhlIGdlbmUgbGlzdCcgOiAnU2hvdyBldmVyeSBnZW5lJ1wiXG4gICAgPlxuICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1jaGV2cm9uLWRvd25dPVwiYWxsR2VuZXNPcGVuXCIgW2NsYXNzLnBpLWNoZXZyb24tcmlnaHRdPVwiIWFsbEdlbmVzT3BlblwiPjwvaT5cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG4gIDwhLS0gXCJBbGwgZ2VuZXNcIjogZXZlcnkgZ2VuZSBvZiB0aGUgZGF0YXNldCwgZWFjaCB3aXRoIGl0cyBleWUgd2hlbiB0aGUgZGF0YXNldCBzYXlzIHdoaWNoXG4gICAgICAgdHJhbnNjcmlwdHMgYXJlIHdob3NlIChpdHMgZ2VuZSBsaXN0IGluIGNvZGUgb3JkZXIpLiAtLT5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImFsbEdlbmVzT3BlbiAmJiB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyAmJiBhbGxHZW5lTGlzdD8ubGVuZ3RoXCI+XG4gICAgPGlucHV0XG4gICAgICBwSW5wdXRUZXh0XG4gICAgICBjbGFzcz1cInNjLWdlbmUtZmlsdGVyXCJcbiAgICAgIHBsYWNlaG9sZGVyPVwiRmlsdGVyIGdlbmVz4oCmXCJcbiAgICAgIGFyaWEtbGFiZWw9XCJGaWx0ZXIgZ2VuZXNcIlxuICAgICAgW3ZhbHVlXT1cImFsbEdlbmVzRmlsdGVyXCJcbiAgICAgIChpbnB1dCk9XCJvbkFsbEdlbmVzRmlsdGVyKCRhbnkoJGV2ZW50LnRhcmdldCkudmFsdWUpXCJcbiAgICAvPlxuICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cIiFjYW5IaWRlQWxsR2VuZXNcIj5cbiAgICAgIFRoaXMgZGF0YXNldCBkb2VzIG5vdCBzYXkgd2hpY2ggdHJhbnNjcmlwdHMgYXJlIHdob3NlLCBzbyBpdHMgZ2VuZXMgY2Fubm90IGJlIGhpZGRlbiBvbmUgYnkgb25lLlxuICAgIDwvc21hbGw+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiY2FuSGlkZUFsbEdlbmVzICYmIHZpZXcudHJhbnNjcmlwdE1vZGUgPT09ICdkZW5zaXR5J1wiPlxuICAgICAgVGhlIGRlbnNpdHkgbWFwIGRyYXdzIGV2ZXJ5IGdlbmUgYXMgb25lIHJhc3RlcjogZ2VuZXMgYXJlIGhpZGRlbiBvbmUgYnkgb25lIGFzIGNpcmNsZXMgb3IgaWNvbnMuXG4gICAgPC9zbWFsbD5cbiAgICA8ZGl2IGNsYXNzPVwic2MtZ2VuZS1yb3cgc2MtZ2VuZS1sZWFmIG5lc3RlZFwiICpuZ0Zvcj1cImxldCByb3cgb2YgYWxsUm93czsgdHJhY2tCeTogdHJhY2tCeUFsbFJvd1wiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJzYy1leWVcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkhpZGVBbGxHZW5lcyB8fCB2aWV3LnRyYW5zY3JpcHRNb2RlID09PSAnZGVuc2l0eSdcIlxuICAgICAgICAoY2xpY2spPVwib25BbGxHZW5lU2hvd24ocm93LmdlbmUsICFyb3cuc2hvd24pXCJcbiAgICAgID5cbiAgICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1leWVdPVwicm93LnNob3duXCIgW2NsYXNzLnBpLWV5ZS1zbGFzaF09XCIhcm93LnNob3duXCI+PC9pPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWdlbmUtaWNvblwiICpuZ0lmPVwicm93LnN3YXRjaFwiIFtzdHlsZS5jb2xvcl09XCJyb3cuc3dhdGNoXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+XG4gICAgICAgIDxzdmcgdmlld0JveD1cIi0xLjIgLTEuMiAyLjQgMi40XCIgY2xhc3M9XCJzYy1nbHlwaC1zdmdcIj48Y2lyY2xlIHI9XCIwLjc1XCI+PC9jaXJjbGU+PC9zdmc+XG4gICAgICA8L3NwYW4+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWdyb3VwLWxhYmVsXCIgW3RpdGxlXT1cInJvdy5nZW5lXCI+e3sgcm93LmdlbmUgfX08L3NwYW4+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWdlbmUtY291bnRcIiAqbmdJZj1cInJvdy5jb3VudCAhPT0gbnVsbFwiIHRpdGxlPVwiVHJhbnNjcmlwdHMgaW4gdmlld1wiPnt7XG4gICAgICAgIHJvdy5jb3VudCB8IG51bWJlclxuICAgICAgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiYWxsR2VuZXNNYXRjaGVkID4gYWxsUm93cy5sZW5ndGhcIj5cbiAgICAgIFNob3dpbmcge3sgYWxsUm93cy5sZW5ndGggfCBudW1iZXIgfX0gb2Yge3sgYWxsR2VuZXNNYXRjaGVkIHwgbnVtYmVyIH19IGdlbmVzOiBmaWx0ZXIgdG8gZmluZCB0aGUgb3RoZXJzLlxuICAgIDwvc21hbGw+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiYWxsR2VuZXNNYXRjaGVkID09PSAwXCI+Tm8gZ2VuZSBtYXRjaGVzLjwvc21hbGw+XG4gIDwvbmctY29udGFpbmVyPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwiZ2VuZVRyZWVPcGVuICYmICF2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1wiPlxuICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG5vZGUgb2YgZ2VuZVRyZWU7IHRyYWNrQnk6IHRyYWNrQnlOb2RlXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwic2MtZ2VuZS1yb3cgc2MtZ2VuZS1ncm91cFwiICpuZ0lmPVwibm9kZS5uYW1lXCI+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwic2MtZXllXCIgKGNsaWNrKT1cIm9uR2VuZXNTaG93bihub2RlLmdlbmVzLCAhZ3JvdXBTaG93bi5nZXQobm9kZS5uYW1lKSlcIj5cbiAgICAgICAgICA8aVxuICAgICAgICAgICAgY2xhc3M9XCJwaVwiXG4gICAgICAgICAgICBbY2xhc3MucGktZXllXT1cImdyb3VwU2hvd24uZ2V0KG5vZGUubmFtZSlcIlxuICAgICAgICAgICAgW2NsYXNzLnBpLWV5ZS1zbGFzaF09XCIhZ3JvdXBTaG93bi5nZXQobm9kZS5uYW1lKVwiXG4gICAgICAgICAgPjwvaT5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ3JvdXAtbGFiZWxcIiBbdGl0bGVdPVwibm9kZS5uYW1lXCI+e3sgbm9kZS5uYW1lIH19PC9zcGFuPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWNvdW50XCI+KHt7IG5vZGUuZ2VuZXMubGVuZ3RoIH19KTwvc3Bhbj5cbiAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJzYy1pY29uLWJ0blwiIChjbGljayk9XCJ0b2dnbGVHZW5lR3JvdXAobm9kZS5uYW1lKVwiPlxuICAgICAgICAgIDxpXG4gICAgICAgICAgICBjbGFzcz1cInBpXCJcbiAgICAgICAgICAgIFtjbGFzcy5waS1jaGV2cm9uLWRvd25dPVwiIWNvbGxhcHNlZEdlbmVHcm91cHMuaGFzKG5vZGUubmFtZSlcIlxuICAgICAgICAgICAgW2NsYXNzLnBpLWNoZXZyb24tcmlnaHRdPVwiY29sbGFwc2VkR2VuZUdyb3Vwcy5oYXMobm9kZS5uYW1lKVwiXG4gICAgICAgICAgPjwvaT5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCIhbm9kZS5uYW1lIHx8ICFjb2xsYXBzZWRHZW5lR3JvdXBzLmhhcyhub2RlLm5hbWUpXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cInNjLWdlbmUtcm93IHNjLWdlbmUtbGVhZlwiXG4gICAgICAgICAgW2NsYXNzLm5lc3RlZF09XCIhIW5vZGUubmFtZVwiXG4gICAgICAgICAgKm5nRm9yPVwibGV0IGdlbmUgb2Ygbm9kZS5nZW5lczsgdHJhY2tCeTogdHJhY2tCeUxhYmVsU3RyaW5nXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwic2MtZXllXCIgKGNsaWNrKT1cIm9uR2VuZXNTaG93bihbZ2VuZV0sICFyb3dzLmdldChnZW5lKT8uc2hvd24pXCI+XG4gICAgICAgICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWV5ZV09XCJyb3dzLmdldChnZW5lKT8uc2hvd25cIiBbY2xhc3MucGktZXllLXNsYXNoXT1cIiFyb3dzLmdldChnZW5lKT8uc2hvd25cIj48L2k+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPCEtLSBUaGUgZ2VuZSdzIG1hcmtlciwgaW4gaXRzIGNvbG91cjogaXRzIGljb24gaW4gSWNvbnMgbW9kZSwgYSBkb3QgZm9yIGNpcmNsZXMuXG4gICAgICAgICAgICAgICBDbGlja2luZyBpdCBvcGVucyB0aGUgaWNvbiBhbmQgY29sb3VyIHBpY2tlciAoYXMgWGVuaXVtIEV4cGxvcmVyIGRvZXMpLiAtLT5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwic2MtZ2VuZS1pY29uXCJcbiAgICAgICAgICAgIFtzdHlsZS5jb2xvcl09XCJyb3dzLmdldChnZW5lKT8uc3dhdGNoXCJcbiAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0ljb24gYW5kIGNvbG91ciBmb3IgJyArIGdlbmVcIlxuICAgICAgICAgICAgcFRvb2x0aXA9XCJJY29uIGFuZCBjb2xvdXJcIlxuICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvcGVuR2VuZVN0eWxlKCRldmVudCwgZ2VuZSwgZ2VuZVBvcClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxzdmcgdmlld0JveD1cIi0xLjIgLTEuMiAyLjQgMi40XCIgY2xhc3M9XCJzYy1nbHlwaC1zdmdcIj5cbiAgICAgICAgICAgICAgPHBvbHlnb25cbiAgICAgICAgICAgICAgICAqbmdJZj1cInZpZXcudHJhbnNjcmlwdE1vZGUgPT09ICdnbHlwaHMnOyBlbHNlIGRvdEljb25cIlxuICAgICAgICAgICAgICAgIFthdHRyLnBvaW50c109XCJyb3dzLmdldChnZW5lKT8ucG9pbnRzXCJcbiAgICAgICAgICAgICAgPjwvcG9seWdvbj5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNkb3RJY29uPjxjaXJjbGUgcj1cIjAuNzVcIj48L2NpcmNsZT48L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1ncm91cC1sYWJlbFwiPnt7IGdlbmUgfX08L3NwYW4+XG4gICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgIGNsYXNzPVwic2MtZ2VuZS1jb3VudFwiXG4gICAgICAgICAgICAqbmdJZj1cInJvd3MuZ2V0KGdlbmUpPy5jb3VudCBhcyBuOyBlbHNlIHplcm9Db3VudFwiXG4gICAgICAgICAgICB0aXRsZT1cIlRyYW5zY3JpcHRzIGluIHZpZXdcIlxuICAgICAgICAgICAgPnt7IG4gfCBudW1iZXIgfX08L3NwYW5cbiAgICAgICAgICA+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICN6ZXJvQ291bnQ+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWdlbmUtY291bnRcIiAqbmdJZj1cImdlbmVDb3VudHNcIiB0aXRsZT1cIlRyYW5zY3JpcHRzIGluIHZpZXdcIj4wPC9zcGFuPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvbmctY29udGFpbmVyPlxuICA8IS0tIE9uZSBwaWNrZXIgZm9yIGV2ZXJ5IGdlbmUgcm93LCBmaWxsZWQgZm9yIHRoZSBnZW5lIHRoYXQgb3BlbmVkIGl0LiAtLT5cbiAgPHAtb3ZlcmxheVBhbmVsICNnZW5lUG9wIHN0eWxlQ2xhc3M9XCJzYy1nZW5lLXN0eWxlXCIgYXBwZW5kVG89XCJib2R5XCI+XG4gICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImNvbnRlbnRcIj5cbiAgICAgIDxzcGF0aWFsLWdlbmUtc3R5bGVcbiAgICAgICAgKm5nSWY9XCJzdHlsZUdlbmUgYXMgZ2VuZVwiXG4gICAgICAgIFtnZW5lXT1cImdlbmVcIlxuICAgICAgICB3aGF0PVwiVHJhbnNjcmlwdFwiXG4gICAgICAgIFtjb2xvcl09XCJnZW5lQ29sb3JPZihnZW5lKVwiXG4gICAgICAgIFtnbHlwaF09XCJzdHlsZUdseXBoID8/ICdjaXJjbGUnXCJcbiAgICAgICAgW2ljb25IaW50XT1cIlxuICAgICAgICAgIHZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdnbHlwaHMnID8gJ0ljb25zIHNob3cgd2hlbiB0aGUgdHJhbnNjcmlwdCBwb2ludCBzdHlsZSBpcyBJY29ucy4nIDogbnVsbFxuICAgICAgICBcIlxuICAgICAgICAoY29sb3JDaGFuZ2UpPVwib25HZW5lQ29sb3IoZ2VuZSwgJGV2ZW50KVwiXG4gICAgICAgIChnbHlwaENoYW5nZSk9XCJvbkdseXBoKGdlbmUsICRldmVudClcIlxuICAgICAgICAocmVzZXRTdHlsZSk9XCJyZXNldEdlbmVTdHlsZShnZW5lKVwiXG4gICAgICA+PC9zcGF0aWFsLWdlbmUtc3R5bGU+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9wLW92ZXJsYXlQYW5lbD5cbiAgPGRpdiBjbGFzcz1cInNjLWdlbmUtZm9vdGVyXCI+XG4gICAge3sgKHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gZ2VuZVRvdGFsIDogdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoKSB8IG51bWJlciB9fS97eyBnZW5lVG90YWwgfCBudW1iZXIgfX1cbiAgICBnZW5lcyBzZWxlY3RlZFxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
369
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1nZW5lLXRyZWUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtZ2VuZS10cmVlL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWdlbmUtdHJlZS9zcGF0aWFsLWdlbmUtdHJlZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sR0FHUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBSWhELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsb0JBQW9CLEVBQXlDLE1BQU0sK0JBQStCLENBQUM7QUFDNUcsT0FBTyxFQUFFLDJCQUEyQixFQUFFLGNBQWMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQzdGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLGVBQWUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pILE9BQU8sRUFBZ0IsYUFBYSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUMzRyxPQUFPLEVBQUUsY0FBYyxFQUFFLGNB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QUF5Qjs7MkZBTWhCLHdCQUF3QjtrQkFmcEMsU0FBUzsrQkFDRSxtQkFBbUIsY0FDakIsSUFBSSxXQUNQO3dCQUNQLFlBQVk7d0JBQ1osWUFBWTt3QkFDWixlQUFlO3dCQUNmLGtCQUFrQjt3QkFDbEIsYUFBYTt3QkFDYix5QkFBeUI7cUJBQzFCLG1CQUdnQix1QkFBdUIsQ0FBQyxNQUFNOzJHQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsVUFBVTtzQkFBbEIsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgU2hhcmVkTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuaW1wb3J0IHsgSW5wdXRUZXh0TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dHRleHQnO1xuaW1wb3J0IHsgT3ZlcmxheVBhbmVsTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9vdmVybGF5cGFuZWwnO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB0eXBlIHsgSVNwYXRpYWxDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFzZXQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7IEFMTF9HRU5FUyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9wb3J0cy9zcGF0aWFsLWRhdGEucG9ydCc7XG5pbXBvcnQgeyBERUZBVUxUX1NQQVRJQUxfVklFVywgU3BhdGlhbFZpZXdTdGF0ZSwgVHJhbnNjcmlwdEdseXBoTmFtZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURSwgZ3JvdXBDb2xvcnNLZXkgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtZW5jb2RpbmcnO1xuaW1wb3J0IHsgY2VsbFR5cGVDb2x1bW5Gb3IsIGNsdXN0ZXJDb2xvck1hcCwgY2x1c3Rlck9mR2VuZSwgZGVmYXVsdEdseXBoRm9yIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLXRpbGVzJztcbmltcG9ydCB7IEdlbmVUcmVlTm9kZSwgYnVpbGRHZW5lVHJlZSwgZ2x5cGhQb2ludHMsIHRvZ2dsZUhpZGRlbiB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgeyBhbGxHZW5lU2hvd25CeSwgYWxsR2VuZXNIaWRkZW4sIHRvZ2dsZUFsbEdlbmVIaWRkZW4gfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtdGlsZS1tZXJnZSc7XG5pbXBvcnQgeyBTdXBlcnNlZGUgfSBmcm9tICcuLi8uLi91dGlsL3N1cGVyc2VkZSc7XG5pbXBvcnQgeyBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1nZW5lLXN0eWxlL3NwYXRpYWwtZ2VuZS1zdHlsZS5jb21wb25lbnQnO1xuXG4vKiogUm93cyBvZiB0aGUgYWxsLWdlbmVzIGxpc3QgZHJhd24gYXQgb25jZTsgdGhlIGZpbHRlciBuYXJyb3dzIHRoZSByZXN0LiAqL1xuY29uc3QgQUxMX0dFTkVTX1JPV1MgPSAyMDA7XG5cbi8qKiBIb3cgdGhlIGdlbmUgcm93cyBhcmUgb3JkZXJlZDogYnkgbmFtZSwgb3IgYnkgdGhlaXIgdHJhbnNjcmlwdHMgaW4gdmlldywgbW9zdCBmaXJzdC4gKi9cbmV4cG9ydCB0eXBlIEdlbmVTb3J0ID0gJ25hbWUnIHwgJ2NvdW50JztcblxuLyoqIE5hbWVzIGluIHJlYWRpbmcgb3JkZXI6IGNhc2UgYXNpZGUsIGFuZCBgRzlgIGJlZm9yZSBgRzEwYC4gKi9cbmNvbnN0IGJ5TmFtZSA9IChhOiBzdHJpbmcsIGI6IHN0cmluZyk6IG51bWJlciA9PlxuICBhLmxvY2FsZUNvbXBhcmUoYiwgdW5kZWZpbmVkLCB7IG51bWVyaWM6IHRydWUsIHNlbnNpdGl2aXR5OiAnYmFzZScgfSk7XG5cbi8qKiBPbmUgZ2VuZSByb3cgYXMgdGhlIHRlbXBsYXRlIGRyYXdzIGl0LCBkZXJpdmVkIG9uY2UgcGVyIGlucHV0IGNoYW5nZS4gKi9cbmludGVyZmFjZSBHZW5lUm93VmlldyB7XG4gIHNob3duOiBib29sZWFuO1xuICBzd2F0Y2g6IHN0cmluZztcbiAgLyoqIFRoZSByb3cncyBnbHlwaCBvdXRsaW5lIChkcmF3biBpbiBJY29ucyBtb2RlKS4gKi9cbiAgcG9pbnRzOiBzdHJpbmc7XG4gIC8qKiBUcmFuc2NyaXB0cyBpbiB2aWV3LCBvciBudWxsIGJlZm9yZSB0aGUgcmVuZGVyZXIgcmVwb3J0cyBhbnkuICovXG4gIGNvdW50OiBudW1iZXIgfCBudWxsO1xufVxuXG4vKiogT25lIHJvdyBvZiB0aGUgYWxsLWdlbmVzIGxpc3QuICovXG5pbnRlcmZhY2UgQWxsR2VuZVJvd1ZpZXcge1xuICBnZW5lOiBzdHJpbmc7XG4gIHNob3duOiBib29sZWFuO1xuICAvKiogSXRzIGNvbG91ciB3aGVuIGNvbG91cmVkIGJ5IGdlbmUsIG9yIG51bGwgd2hlbiB0aGUgZGF0YXNldCdzIGNvZGUgb3JkZXIgaXMgdW5rbm93bi4gKi9cbiAgc3dhdGNoOiBzdHJpbmcgfCBudWxsO1xuICAvKiogSXRzIGNvZGUgaW4gdGhlIGRhdGFzZXQncyBnZW5lIGxpc3QgKHdoYXQgaXRzIHBhbGV0dGUgY29sb3VyIGlzIHBpY2tlZCBieSkuICovXG4gIGNvZGU6IG51bWJlcjtcbiAgY291bnQ6IG51bWJlciB8IG51bGw7XG59XG5cbi8qKlxuICogVGhlIHNlbGVjdGVkIHRyYW5zY3JpcHQgZ2VuZXMgYXMgWGVuaXVtIEV4cGxvcmVyJ3MgdHJlZTogdGhlIGdlbmUgZ3JvdXBzLCB0aGVuIHRoZVxuICogdW5ncm91cGVkIGdlbmVzLCBlYWNoIHJvdyB3aXRoIGFuIGV5ZSB0aGF0IGhpZGVzIGl0IHdpdGhvdXQgZGVzZWxlY3RpbmcgaXQsIGl0cyBtYXJrZXJcbiAqIGluIGl0cyBjb2xvdXIgKG9wZW5pbmcgb25lIGljb24tYW5kLWNvbG91ciBwaWNrZXIgcGVyIGdlbmUpLCBhbmQgaXRzIHRyYW5zY3JpcHQgY291bnQgaW5cbiAqIHZpZXcuIFdpdGggXCJBbGwgZ2VuZXNcIiBvbiwgdGhlIHJvb3QgZXllIGhpZGVzIG9yIHNob3dzIGV2ZXJ5IHRyYW5zY3JpcHQgYW5kIHRoZSByb290XG4gKiBleHBhbmRzIHRvIGV2ZXJ5IGdlbmUgb2YgdGhlIGRhdGFzZXQsIGVhY2ggd2l0aCBpdHMgZXllIHdoZW4gdGhlIGRhdGFzZXQgbGlzdHMgaXRzIGdlbmVzXG4gKiBpbiBjb2RlIG9yZGVyIChgdHJhbnNjcmlwdFRpbGVzLmdlbmVzYCksIGZpbHRlcmVkIGJ5IG5hbWUgcGFzdCBhIGZldyBodW5kcmVkLlxuICpcbiAqIEJvdGggbGlzdHMgYXJlIG9yZGVyZWQgYnkgbmFtZSwgb3IgYnkgdGhlaXIgdHJhbnNjcmlwdHMgaW4gdmlldywgbW9zdCBmaXJzdCAodGhlXG4gKiBzb3J0IHN3aXRjaCwgb2ZmZXJlZCBvbmNlIHRoZSByZW5kZXJlciByZXBvcnRzIGNvdW50cykuIFRoZSBhbGwtZ2VuZXMgbGlzdCBpcyBzb3J0ZWRcbiAqIGJlZm9yZSBpdCBpcyBjdXQgdG8gaXRzIGZpcnN0IHJvd3MsIHNvIGJ5IGNvdW50IHRob3NlIGFyZSB0aGUgZ2VuZXMgd2l0aCB0aGUgbW9zdFxuICogdHJhbnNjcmlwdHMgaW4gdmlldy5cbiAqXG4gKiBXcml0ZXMgb25seSB0aHJvdWdoIGBjb250cm9scy5zZXRWaWV3U3RhdGVgLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzcGF0aWFsLWdlbmUtdHJlZScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgU2hhcmVkTW9kdWxlLFxuICAgIElucHV0VGV4dE1vZHVsZSxcbiAgICBPdmVybGF5UGFuZWxNb2R1bGUsXG4gICAgVG9vbHRpcE1vZHVsZSxcbiAgICBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vc3BhdGlhbC1nZW5lLXRyZWUuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zcGF0aWFsLWdlbmUtdHJlZS5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbEdlbmVUcmVlQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLyoqIFRoZSBzcGF0aWFsIGNvbnRyb2xzIHRoaXMgcGFuZWwgcmVhZHMgYW5kIHdyaXRlcyB0aHJvdWdoOyBudWxsIHdpdGhvdXQgYSBgU1BBVElBTF9EQVRBX1BPUlRgLiAqL1xuICBASW5wdXQoKSBjb250cm9sczogSVNwYXRpYWxDb250cm9scyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGRhdGFzZXQgb24gb2ZmZXIsIG9yIG51bGwuICovXG4gIEBJbnB1dCgpIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgY3VycmVudCBzcGF0aWFsIHZpZXcgc3RhdGU6IHdoYXQgaXMgZHJhd24sIGFuZCBob3cuICovXG4gIEBJbnB1dCgpIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUgPSBERUZBVUxUX1NQQVRJQUxfVklFVztcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIGVhY2ggc2VsZWN0ZWQgZ2VuZSBpbiB0aGUgY3VycmVudCB2aWV3LCBmcm9tIHRoZSByZW5kZXJlci4gKi9cbiAgQElucHV0KCkgZ2VuZUNvdW50czogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB8IG51bGwgPSBudWxsO1xuICAvKiogUmVhbCBnZW5lcyBpbiB0aGUgcGFuZWwg4oCUIHRoZSB0cmVlJ3MgZGVub21pbmF0b3IuICovXG4gIEBJbnB1dCgpIGdlbmVUb3RhbCA9IDA7XG5cbiAgLyoqIFN3YXRjaGVzIGluIHRoZSBwaWNrZXI6IHRoZSBjYXRlZ29yaWNhbCBwYWxldHRlIGdlbmVzIGFyZSBjb2xvdXJlZCBmcm9tIGJ5IGRlZmF1bHQuICovXG5cbiAgLyoqIFRoZSB0cmVlLCByZWJ1aWx0IHdoZW4gdGhlIHZpZXcgY2hhbmdlcyDigJQgbmV2ZXIgcGVyIGNoYW5nZS1kZXRlY3Rpb24gcGFzcy4gKi9cbiAgcHJvdGVjdGVkIGdlbmVUcmVlOiBHZW5lVHJlZU5vZGVbXSA9IFtdO1xuICAvKioge0BsaW5rIGdlbmVUcmVlfSB3aXRoIGVhY2ggbm9kZSdzIGdlbmVzIGluIHtAbGluayBnZW5lU29ydH0gb3JkZXI6IHdoYXQgdGhlIHRlbXBsYXRlIGRyYXdzLiAqL1xuICBwcm90ZWN0ZWQgc29ydGVkVHJlZTogR2VuZVRyZWVOb2RlW10gPSBbXTtcbiAgLyoqIFRoZSByb3dzJyBvcmRlci4gQnkgY291bnQgb25seSB3aGlsZSB0aGUgcmVuZGVyZXIgcmVwb3J0cyBjb3VudHMgKHNlZSB7QGxpbmsgc29ydFNob3dufSkuICovXG4gIHByb3RlY3RlZCBnZW5lU29ydDogR2VuZVNvcnQgPSAnbmFtZSc7XG4gIC8qKiBQZXIgZ2VuZTogaXRzIGV5ZSwgc3dhdGNoLCBnbHlwaCBhbmQgY291bnQg4oCUIHJlYnVpbHQgd2l0aCB0aGUgaW5wdXRzIChhbmQgd2hlbiB0aGVcbiAgICogIGNlbGxzJyBncm91cCBjb2xvdXJzIGFycml2ZSksIHNvIHRoZSB0ZW1wbGF0ZSBkb2VzIG5vIHBlci1yb3cgbG9va3VwcyBwZXIgY2hlY2suICovXG4gIHByb3RlY3RlZCByb3dzID0gbmV3IE1hcDxzdHJpbmcsIEdlbmVSb3dWaWV3PigpO1xuICAvKiogUGVyIG5hbWVkIGdyb3VwLCBhbmQgZm9yIHRoZSByb290OiB3aGV0aGVyIGFueSBvZiBpdHMgZ2VuZXMgaXMgc2hvd24uICovXG4gIHByb3RlY3RlZCBncm91cFNob3duID0gbmV3IE1hcDxzdHJpbmcsIGJvb2xlYW4+KCk7XG4gIHByb3RlY3RlZCByb290U2hvd24gPSBmYWxzZTtcbiAgcHJvdGVjdGVkIGNvbGxhcHNlZEdlbmVHcm91cHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJvdGVjdGVkIGdlbmVUcmVlT3BlbiA9IHRydWU7XG4gIC8qKiBUaGUgYWxsLWdlbmVzIGxpc3Qgc3RhcnRzIGNsb3NlZDogaXQgY2FuIHJ1biB0byB0aG91c2FuZHMgb2YgZ2VuZXMuICovXG4gIHByb3RlY3RlZCBhbGxHZW5lc09wZW4gPSBmYWxzZTtcbiAgLyoqIFRoZSBnZW5lcyBcIkFsbCBnZW5lc1wiIGxpc3RzLCBvciBudWxsIHdoZW4gdGhlIGRhdGFzZXQgbmFtZXMgbm9uZS4gKi9cbiAgcHJvdGVjdGVkIGFsbEdlbmVMaXN0OiByZWFkb25seSBzdHJpbmdbXSB8IG51bGwgPSBudWxsO1xuICAvKiogV2hldGhlciBhIGdlbmUgb2YgXCJBbGwgZ2VuZXNcIiBjYW4gYmUgaGlkZGVuOiB0aGUgZGF0YXNldCBsaXN0cyBpdHMgZ2VuZXMgaW4gY29kZSBvcmRlci4gKi9cbiAgcHJvdGVjdGVkIGNhbkhpZGVBbGxHZW5lcyA9IGZhbHNlO1xuICBwcm90ZWN0ZWQgYWxsR2VuZXNGaWx0ZXIgPSAnJztcbiAgLyoqIFRoZSBsaXN0J3Mgcm93cyBtYXRjaGluZyB0aGUgZmlsdGVyLCBhdCBtb3N0IHtAbGluayBBTExfR0VORVNfUk9XU30uICovXG4gIHByb3RlY3RlZCBhbGxSb3dzOiBBbGxHZW5lUm93Vmlld1tdID0gW107XG4gIC8qKiBIb3cgbWFueSBnZW5lcyBtYXRjaCB0aGUgZmlsdGVyLCBmb3IgdGhlIFwic2hvd2luZyBuIG9mIG1cIiBsaW5lLiAqL1xuICBwcm90ZWN0ZWQgYWxsR2VuZXNNYXRjaGVkID0gMDtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGFsbEdlbmVzUm93Q2FwID0gQUxMX0dFTkVTX1JPV1M7XG4gIC8qKiBUaGUgZ2VuZSB0aGUgb3BlbiBwaWNrZXIgZWRpdHMuICovXG4gIHByb3RlY3RlZCBzdHlsZUdlbmU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBDb2xvdXJzIG9mIHRoZSBjZWxscycgZ3JvdXBzLCBieSBuYW1lIOKAlCB3aGF0IGEgY2x1c3RlciBvZiB0aGUgc2FtZSBuYW1lIGlzIGRyYXduIGluLiAqL1xuICBwcml2YXRlIGNlbGxHcm91cENvbG9ycyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gIC8qKiBUaGUgZ3JvdXBpbmcge0BsaW5rIGNlbGxHcm91cENvbG9yc30gYmVsb25ncyB0byDigJQgYSByZXBlYXQgcmVxdWVzdCBmb3IgaXQgaXMgYSBuby1vcC4gKi9cbiAgcHJpdmF0ZSBjZWxsR3JvdXBDb2xvcnNGb3I6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIC8qKiBMYXRlc3Qgd2lucyBhbW9uZyBjb2xvdXIgbG9hZHMgZm9yIHtAbGluayBjZWxsR3JvdXBDb2xvcnN9LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNlbGxHcm91cENvbG9yc0xvYWQgPSBuZXcgU3VwZXJzZWRlKCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSB6b25lOiBOZ1pvbmUsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICApIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWyd2aWV3J10pIHRoaXMuZ2VuZVRyZWUgPSBidWlsZEdlbmVUcmVlKHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUdyb3Vwcyk7XG4gICAgLy8gQSBzYW1lLW5hbWVkIGdyb3VwaW5nIG9mIGEgbmV3IGRhdGFzZXQgaXMgbm90IHRoZSBvbGQgb25lLlxuICAgIGlmIChjaGFuZ2VzWydkYXRhc2V0J10pIHtcbiAgICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzRm9yID0gdW5kZWZpbmVkO1xuICAgICAgY29uc3QgY29kZWQgPSB0aGlzLmRhdGFzZXQ/LnRyYW5zY3JpcHRUaWxlcz8uZ2VuZXM7XG4gICAgICB0aGlzLmNhbkhpZGVBbGxHZW5lcyA9ICEhY29kZWQ/Lmxlbmd0aDtcbiAgICAgIHRoaXMuYWxsR2VuZUxpc3QgPSBjb2RlZD8ubGVuZ3RoID8gY29kZWQgOiAodGhpcy5kYXRhc2V0Py5mZWF0dXJlcz8ubmFtZXMgPz8gbnVsbCk7XG4gICAgfVxuICAgIHRoaXMucmVidWlsZFJvd3MoKTtcbiAgICB2b2lkIHRoaXMucmVmcmVzaENlbGxHcm91cENvbG9ycygpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWJ1aWxkUm93cygpOiB2b2lkIHtcbiAgICBjb25zdCBnZW5lcyA9IHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXM7XG4gICAgdGhpcy5yb3dzID0gbmV3IE1hcChcbiAgICAgIGdlbmVzLm1hcCgoZ2VuZSwgc2xvdCkgPT4gW1xuICAgICAgICBnZW5lLFxuICAgICAgICB7XG4gICAgICAgICAgc2hvd246IHRoaXMuaXNHZW5lU2hvd24oZ2VuZSksXG4gICAgICAgICAgc3dhdGNoOiB0aGlzLmdlbmVTd2F0Y2hPZihnZW5lKSxcbiAgICAgICAgICBwb2ludHM6IGdseXBoUG9pbnRzKHRoaXMuZ2x5cGhPZihnZW5lLCBzbG90KSksXG4gICAgICAgICAgY291bnQ6IHRoaXMuZ2VuZUNvdW50T2YoZ2VuZSksXG4gICAgICAgIH0sXG4gICAgICBdKSxcbiAgICApO1xuICAgIHRoaXMuZ3JvdXBTaG93biA9IG5ldyBNYXAoXG4gICAgICB0aGlzLmdlbmVUcmVlXG4gICAgICAgIC5maWx0ZXIoKG5vZGUpID0+IG5vZGUubmFtZSlcbiAgICAgICAgLm1hcCgobm9kZSkgPT4gW25vZGUubmFtZSBhcyBzdHJpbmcsIHRoaXMuYXJlR2VuZXNTaG93bihub2RlLmdlbmVzKV0pLFxuICAgICk7XG4gICAgdGhpcy5yb290U2hvd24gPSB0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gdGhpcy5hbnlPZkFsbEdlbmVzU2hvd24oKSA6IHRoaXMuYXJlR2VuZXNTaG93bihnZW5lcyk7XG4gICAgdGhpcy5zb3J0ZWRUcmVlID0gdGhpcy5nZW5lVHJlZS5tYXAoKG5vZGUpID0+ICh7IC4uLm5vZGUsIGdlbmVzOiB0aGlzLnNvcnRlZChub2RlLmdlbmVzKSB9KSk7XG4gICAgdGhpcy5yZWJ1aWxkQWxsUm93cygpO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgdGhlIHJvd3MgYXJlIG9yZGVyZWQgYnkgY291bnQ6IGNob3NlbiwgYW5kIGNvdW50cyB0byBvcmRlciBieS4gKi9cbiAgcHJvdGVjdGVkIGdldCBieUNvdW50KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmdlbmVTb3J0ID09PSAnY291bnQnICYmICEhdGhpcy5nZW5lQ291bnRzO1xuICB9XG5cbiAgLyoqIFRoZSBzb3J0IHN3aXRjaCBpcyBvZmZlcmVkIG9uY2UgdGhlcmUgYXJlIGNvdW50cyB0byBzb3J0IGJ5LiAqL1xuICBwcm90ZWN0ZWQgZ2V0IHNvcnRTaG93bigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmdlbmVDb3VudHM7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25HZW5lU29ydChzb3J0OiBHZW5lU29ydCk6IHZvaWQge1xuICAgIGlmIChzb3J0ID09PSB0aGlzLmdlbmVTb3J0KSByZXR1cm47XG4gICAgdGhpcy5nZW5lU29ydCA9IHNvcnQ7XG4gICAgdGhpcy5yZWJ1aWxkUm93cygpO1xuICB9XG5cbiAgLyoqIGBnZW5lc2AgaW4gdGhlIHJvd3MnIG9yZGVyOiBieSBjb3VudCwgbW9zdCBmaXJzdCAodGllcyBieSBuYW1lKSwgZWxzZSBieSBuYW1lLiAqL1xuICBwcml2YXRlIHNvcnRlZChnZW5lczogcmVhZG9ubHkgc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gICAgaWYgKCF0aGlzLmJ5Q291bnQpIHJldHVybiBbLi4uZ2VuZXNdLnNvcnQoYnlOYW1lKTtcbiAgICBjb25zdCBjb3VudHMgPSB0aGlzLmdlbmVDb3VudHMgPz8ge307XG4gICAgcmV0dXJuIFsuLi5nZW5lc10uc29ydCgoYSwgYikgPT4gKGNvdW50c1tiXSA/PyAwKSAtIChjb3VudHNbYV0gPz8gMCkgfHwgYnlOYW1lKGEsIGIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgYWxsLWdlbmVzIGxpc3QncyByb3dzOiB0aGUgZ2VuZXMgbWF0Y2hpbmcgdGhlIGZpbHRlciwgdXAgdG8gdGhlIGNhcC4gQnVpbHQgb25seSB3aGlsZVxuICAgKiB0aGUgbGlzdCBpcyBvcGVuOiB0aGUgY291bnRzIGluIHZpZXcgY2hhbmdlIHdpdGggZXZlcnkgcGFuLCBhbmQgdGhlIGxpc3QgY2FuIGJlIHRob3VzYW5kcy5cbiAgICovXG4gIHByaXZhdGUgcmVidWlsZEFsbFJvd3MoKTogdm9pZCB7XG4gICAgY29uc3QgbGlzdCA9IHRoaXMudmlldy50cmFuc2NyaXB0QWxsR2VuZXMgJiYgdGhpcy5hbGxHZW5lc09wZW4gPyB0aGlzLmFsbEdlbmVMaXN0IDogbnVsbDtcbiAgICBpZiAoIWxpc3QpIHtcbiAgICAgIHRoaXMuYWxsUm93cyA9IFtdO1xuICAgICAgdGhpcy5hbGxHZW5lc01hdGNoZWQgPSAwO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBuZWVkbGUgPSB0aGlzLmFsbEdlbmVzRmlsdGVyLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IHNob3duID0gYWxsR2VuZVNob3duQnkodGhpcy52aWV3LnRyYW5zY3JpcHRBbGxHZW5lc0hpZGRlbik7XG4gICAgLy8gRXZlcnkgbWF0Y2gsIG9yZGVyZWQsIGFuZCBvbmx5IHRoZW4gY3V0OiBieSBjb3VudCB0aGUgZmlyc3Qgcm93cyBhcmUgdGhlIG1vc3QgYWJ1bmRhbnQuXG4gICAgY29uc3QgY29kZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIGxpc3QuZm9yRWFjaCgoZ2VuZSwgY29kZSkgPT4ge1xuICAgICAgLy8gQW4gZW1wdHkgbmFtZSBpcyBhIGNvZGUgbm8gdHJhbnNjcmlwdCBjYXJyaWVzIChhIGNvbnRyb2wgcHJvYmUpLlxuICAgICAgaWYgKCFnZW5lIHx8IChuZWVkbGUgJiYgIWdlbmUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhuZWVkbGUpKSkgcmV0dXJuO1xuICAgICAgaWYgKCFjb2Rlcy5oYXMoZ2VuZSkpIGNvZGVzLnNldChnZW5lLCBjb2RlKTtcbiAgICB9KTtcbiAgICB0aGlzLmFsbFJvd3MgPSB0aGlzLnNvcnRlZChbLi4uY29kZXMua2V5cygpXSlcbiAgICAgIC5zbGljZSgwLCBBTExfR0VORVNfUk9XUylcbiAgICAgIC5tYXAoKGdlbmUpID0+ICh7XG4gICAgICAgIGdlbmUsXG4gICAgICAgIHNob3duOiBzaG93bihnZW5lKSxcbiAgICAgICAgc3dhdGNoOiB0aGlzLmNhbkhpZGVBbGxHZW5lcyA/IHRoaXMuYWxsR2VuZUNvbG9yT2YoZ2VuZSwgY29kZXMuZ2V0KGdlbmUpISkgOiBudWxsLFxuICAgICAgICBjb2RlOiBjb2Rlcy5nZXQoZ2VuZSkhLFxuICAgICAgICBjb3VudDogdGhpcy5nZW5lQ291bnRPZihnZW5lKSxcbiAgICAgIH0pKTtcbiAgICB0aGlzLmFsbEdlbmVzTWF0Y2hlZCA9IGNvZGVzLnNpemU7XG4gIH1cblxuICAvKiogV2hldGhlciBcIkFsbCBnZW5lc1wiIGRyYXdzIGFueXRoaW5nOiBub3Qgc3dpdGNoZWQgb2ZmIHdob2xlLCBub3IgZXZlcnkgbGlzdGVkIGdlbmUgaGlkZGVuLiAqL1xuICBwcml2YXRlIGFueU9mQWxsR2VuZXNTaG93bigpOiBib29sZWFuIHtcbiAgICBpZiAoYWxsR2VuZXNIaWRkZW4odGhpcy52aWV3KSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghdGhpcy5jYW5IaWRlQWxsR2VuZXMgfHwgIXRoaXMuYWxsR2VuZUxpc3QpIHJldHVybiB0cnVlO1xuICAgIGNvbnN0IHNob3duID0gYWxsR2VuZVNob3duQnkodGhpcy52aWV3LnRyYW5zY3JpcHRBbGxHZW5lc0hpZGRlbik7XG4gICAgcmV0dXJuIHRoaXMuYWxsR2VuZUxpc3Quc29tZSgoZykgPT4gZyAmJiBzaG93bihnKSk7XG4gIH1cblxuICAvKiogQSBnZW5lIG9mIFwiQWxsIGdlbmVzXCIgaW4gaXRzIGNvbG91ciBieSBnZW5lOiBpdHMgY2hvc2VuIG9uZSwgZWxzZSB0aGUgcGFsZXR0ZSdzIGJ5IGNvZGUuICovXG4gIHByaXZhdGUgYWxsR2VuZUNvbG9yT2YoZ2VuZTogc3RyaW5nLCBjb2RlOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnNbZ2VuZV0gfHxcbiAgICAgIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURVtjb2RlICUgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLmxlbmd0aF1cbiAgICApO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRvZ2dsZUFsbEdlbmVzT3BlbigpOiB2b2lkIHtcbiAgICB0aGlzLmFsbEdlbmVzT3BlbiA9ICF0aGlzLmFsbEdlbmVzT3BlbjtcbiAgICB0aGlzLnJlYnVpbGRBbGxSb3dzKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25BbGxHZW5lc0ZpbHRlcih0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmFsbEdlbmVzRmlsdGVyID0gdGV4dDtcbiAgICB0aGlzLnJlYnVpbGRBbGxSb3dzKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgdG9nZ2xlR2VuZUdyb3VwKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSBuZXcgU2V0KHRoaXMuY29sbGFwc2VkR2VuZUdyb3Vwcyk7XG4gICAgaWYgKG5leHQuaGFzKG5hbWUpKSBuZXh0LmRlbGV0ZShuYW1lKTtcbiAgICBlbHNlIG5leHQuYWRkKG5hbWUpO1xuICAgIHRoaXMuY29sbGFwc2VkR2VuZUdyb3VwcyA9IG5leHQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXNHZW5lU2hvd24oZ2VuZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLnZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmluY2x1ZGVzKGdlbmUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFyZUdlbmVzU2hvd24oZ2VuZXM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGdlbmVzLnNvbWUoKGcpID0+IHRoaXMuaXNHZW5lU2hvd24oZykpO1xuICB9XG5cbiAgLyoqIFRoZSBleWUgdG9nZ2xlOiBoaWRlIG9yIHNob3cgZ2VuZXMgd2l0aG91dCByZW1vdmluZyB0aGVtIGZyb20gdGhlIHNlbGVjdGlvbi4gKi9cbiAgcHJvdGVjdGVkIG9uR2VuZXNTaG93bihnZW5lczogc3RyaW5nW10sIG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHtcbiAgICAgIHRyYW5zY3JpcHRIaWRkZW5HZW5lczogdG9nZ2xlSGlkZGVuKHRoaXMudmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMsIGdlbmVzLCBvbiksXG4gICAgfSk7XG4gIH1cblxuICAvKiogVGhlIHJvb3QgZXllIHdoaWxlIGV2ZXJ5IGdlbmUgaXMgZHJhd246IGhpZGUgb3Igc2hvdyB0aGVtIGFsbCAodGhlICfCsScgbGVhdmVzIFwiQWxsIGdlbmVzXCIpLiAqL1xuICBwcm90ZWN0ZWQgb25BbGxHZW5lc1Nob3duKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdHJhbnNjcmlwdEFsbEdlbmVzSGlkZGVuOiBvbiA/IFtdIDogW0FMTF9HRU5FU10gfSk7XG4gIH1cblxuICAvKiogT25lIGdlbmUncyBleWUgaW4gdGhlIGFsbC1nZW5lcyBsaXN0LiBTaG93aW5nIG9uZSB3aGlsZSBhbGwgYXJlIG9mZiBzaG93cyBpdCBhbG9uZS4gKi9cbiAgcHJvdGVjdGVkIG9uQWxsR2VuZVNob3duKGdlbmU6IHN0cmluZywgb246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY2FuSGlkZUFsbEdlbmVzKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHtcbiAgICAgIHRyYW5zY3JpcHRBbGxHZW5lc0hpZGRlbjogdG9nZ2xlQWxsR2VuZUhpZGRlbih0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzSGlkZGVuLCBnZW5lLCBvbiksXG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25HZW5lQ29sb3IoZ2VuZTogc3RyaW5nLCBoZXg6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRHZW5lQ29sb3JzOiB7IC4uLnRoaXMudmlldy50cmFuc2NyaXB0R2VuZUNvbG9ycywgW2dlbmVdOiBoZXggfSB9KTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBwZXItZ2VuZSBpY29uIGFuZCBjb2xvdXIgcGlja2VyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByb3RlY3RlZCBvcGVuR2VuZVN0eWxlKGV2ZW50OiBFdmVudCwgZ2VuZTogc3RyaW5nLCBwYW5lbDogeyB0b2dnbGUoZTogRXZlbnQpOiB2b2lkOyBoaWRlKCk6IHZvaWQgfSk6IHZvaWQge1xuICAgIGlmICh0aGlzLnN0eWxlR2VuZSA9PT0gZ2VuZSkge1xuICAgICAgcGFuZWwudG9nZ2xlKGV2ZW50KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zdHlsZUdlbmUgPSBnZW5lO1xuICAgIHBhbmVsLmhpZGUoKTtcbiAgICAvLyBSZS1vcGVuIGFuY2hvcmVkIG9uIHRoZSByb3cgdGhhdCB3YXMgY2xpY2tlZCwgb25jZSB0aGUgcGFuZWwgaGFzIGNsb3NlZC5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHBhbmVsLnRvZ2dsZShldmVudCkpO1xuICB9XG5cbiAgLyoqIFRoZSBpY29uIHRoZSBvcGVuIHBpY2tlciBzaG93cyBhcyBjaG9zZW4uICovXG4gIHByb3RlY3RlZCBnZXQgc3R5bGVHbHlwaCgpOiBUcmFuc2NyaXB0R2x5cGhOYW1lIHwgbnVsbCB7XG4gICAgY29uc3QgZ2VuZSA9IHRoaXMuc3R5bGVHZW5lO1xuICAgIHJldHVybiBnZW5lID8gdGhpcy5nbHlwaE9mKGdlbmUsIE1hdGgubWF4KDAsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZXMuaW5kZXhPZihnZW5lKSkpIDogbnVsbDtcbiAgfVxuXG4gIHByb3RlY3RlZCBnbHlwaFBvaW50cyhnbHlwaDogVHJhbnNjcmlwdEdseXBoTmFtZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGdseXBoUG9pbnRzKGdseXBoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnbHlwaE9mKGdlbmU6IHN0cmluZywgc2xvdDogbnVtYmVyKTogVHJhbnNjcmlwdEdseXBoTmFtZSB7XG4gICAgcmV0dXJuIHRoaXMudmlldy50cmFuc2NyaXB0R2x5cGhzW2dlbmVdID8/IGRlZmF1bHRHbHlwaEZvcihzbG90KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkdseXBoKGdlbmU6IHN0cmluZywgZ2x5cGg6IFRyYW5zY3JpcHRHbHlwaE5hbWUpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2x5cGhzOiB7IC4uLnRoaXMudmlldy50cmFuc2NyaXB0R2x5cGhzLCBbZ2VuZV06IGdseXBoIH0gfSk7XG4gIH1cblxuICAvKiogQmFjayB0byB0aGUgZ2VuZSdzIGRlZmF1bHQgaWNvbiBhbmQgY29sb3VyIChieSBpdHMgcG9zaXRpb24gaW4gdGhlIGxpc3QpLiAqL1xuICBwcm90ZWN0ZWQgcmVzZXRHZW5lU3R5bGUoZ2VuZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgY29sb3JzID0geyAuLi50aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnMgfTtcbiAgICBjb25zdCBnbHlwaHMgPSB7IC4uLnRoaXMudmlldy50cmFuc2NyaXB0R2x5cGhzIH07XG4gICAgZGVsZXRlIGNvbG9yc1tnZW5lXTtcbiAgICBkZWxldGUgZ2x5cGhzW2dlbmVdO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHRyYW5zY3JpcHRHZW5lQ29sb3JzOiBjb2xvcnMsIHRyYW5zY3JpcHRHbHlwaHM6IGdseXBocyB9KTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBjb2xvdXJzIGFuZCBjb3VudHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRoZSBjb2xvdXIgZ2VuZSBgc2xvdGAgaXMgZHJhd24gaW4gd2hlbiB0cmFuc2NyaXB0cyBhcmUgY29sb3VyZWQgYnkgZ2VuZS4gKi9cbiAgZ2VuZUNvbG9yKHNsb3Q6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgZ2VuZSA9IHRoaXMudmlldz8udHJhbnNjcmlwdEdlbmVzW3Nsb3RdO1xuICAgIHJldHVybiAoXG4gICAgICAoZ2VuZSAmJiB0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnNbZ2VuZV0pIHx8XG4gICAgICBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEVbc2xvdCAlIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGhdXG4gICAgKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lQ29sb3JPZihnZW5lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdlbmVDb2xvcihNYXRoLm1heCgwLCB0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVzLmluZGV4T2YoZ2VuZSkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY29sb3VyIHRoZSBvcGVuIHBpY2tlciBzaG93czogd2l0aCBcIkFsbCBnZW5lc1wiLCB0aGUgZ2VuZSdzIGNvbG91ciBhbW9uZyBldmVyeSBnZW5lIChpdHNcbiAgICogY2hvc2VuIG9uZSwgZWxzZSB0aGUgcGFsZXR0ZSdzIGJ5IGl0cyBjb2RlKSwgYXMgaXRzIHJvdyBhbmQgaXRzIG1hcmtlcnMgaGF2ZSBpdC5cbiAgICovXG4gIHByb3RlY3RlZCBzdHlsZUNvbG9yT2YoZ2VuZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy52aWV3LnRyYW5zY3JpcHRBbGxHZW5lcykge1xuICAgICAgY29uc3Qgcm93ID0gdGhpcy5hbGxSb3dzLmZpbmQoKHIpID0+IHIuZ2VuZSA9PT0gZ2VuZSk7XG4gICAgICBpZiAocm93KSByZXR1cm4gdGhpcy5hbGxHZW5lQ29sb3JPZihnZW5lLCByb3cuY29kZSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmdlbmVDb2xvck9mKGdlbmUpO1xuICB9XG5cbiAgLyoqIEluIENsdXN0ZXIgY29sb3VyaW5nLCBhIGdlbmUncyBzd2F0Y2ggaXMgaXRzIGNsdXN0ZXIncyBjb2xvdXIsIGFzIGl0cyBtYXJrZXJzIGFyZS4gKi9cbiAgcHJvdGVjdGVkIGdlbmVTd2F0Y2hPZihnZW5lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLnZpZXcudHJhbnNjcmlwdENvbG9yQnkgIT09ICdjbHVzdGVyJykgcmV0dXJuIHRoaXMuZ2VuZUNvbG9yT2YoZ2VuZSk7XG4gICAgcmV0dXJuIHRoaXMuY2x1c3RlckNvbG9ycygpLmdldChjbHVzdGVyT2ZHZW5lKGdlbmUsIHRoaXMudmlldy50cmFuc2NyaXB0R2VuZUdyb3VwcykpID8/IHRoaXMuZ2VuZUNvbG9yT2YoZ2VuZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2VuZUNvdW50T2YoZ2VuZTogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZ2VuZUNvdW50cyA/ICh0aGlzLmdlbmVDb3VudHNbZ2VuZV0gPz8gMCkgOiBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRyYWNrQnlOb2RlID0gKF9pOiBudW1iZXIsIG5vZGU6IHsgbmFtZTogc3RyaW5nIHwgbnVsbCB9KSA9PiBub2RlLm5hbWUgPz8gJyc7XG4gIHByb3RlY3RlZCB0cmFja0J5TGFiZWxTdHJpbmcgPSAoX2k6IG51bWJlciwgczogc3RyaW5nKSA9PiBzO1xuICBwcm90ZWN0ZWQgdHJhY2tCeUFsbFJvdyA9IChfaTogbnVtYmVyLCByb3c6IEFsbEdlbmVSb3dWaWV3KSA9PiByb3cuZ2VuZTtcblxuICAvKipcbiAgICogVGhlIGNsdXN0ZXIgY29sb3VycywgcmVidWlsdCBvbmx5IHdoZW4gd2hhdCB0aGV5IGNvbWUgZnJvbSBjaGFuZ2VzLiBUaGUgdGVtcGxhdGUgYXNrc1xuICAgKiBvbmNlIHBlciBnZW5lIHJvdyBwZXIgY2hhbmdlLWRldGVjdGlvbiBwYXNzLCBhbmQgcmVidWlsZGluZyBwZXIgY2FsbCBtYWRlIHRoYXQgTyhHwrIpLlxuICAgKi9cbiAgcHJpdmF0ZSBjbHVzdGVyQ29sb3JzKCk6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICAgIGNvbnN0IHsgdHJhbnNjcmlwdEdlbmVzOiBnZW5lcywgdHJhbnNjcmlwdEdlbmVHcm91cHM6IGdyb3VwcyB9ID0gdGhpcy52aWV3O1xuICAgIGNvbnN0IGhpdCA9IHRoaXMuY2x1c3RlckNvbG9yTWVtbztcbiAgICBpZiAoaGl0ICYmIGhpdC5nZW5lcyA9PT0gZ2VuZXMgJiYgaGl0Lmdyb3VwcyA9PT0gZ3JvdXBzICYmIGhpdC5jZWxsQ29sb3JzID09PSB0aGlzLmNlbGxHcm91cENvbG9ycykge1xuICAgICAgcmV0dXJuIGhpdC5jb2xvcnM7XG4gICAgfVxuICAgIGNvbnN0IGNvbG9ycyA9IGNsdXN0ZXJDb2xvck1hcChnZW5lcywgZ3JvdXBzLCB0aGlzLmNlbGxHcm91cENvbG9ycywgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFKTtcbiAgICB0aGlzLmNsdXN0ZXJDb2xvck1lbW8gPSB7IGdlbmVzLCBncm91cHMsIGNlbGxDb2xvcnM6IHRoaXMuY2VsbEdyb3VwQ29sb3JzLCBjb2xvcnMgfTtcbiAgICByZXR1cm4gY29sb3JzO1xuICB9XG4gIHByaXZhdGUgY2x1c3RlckNvbG9yTWVtbzoge1xuICAgIGdlbmVzOiBTcGF0aWFsVmlld1N0YXRlWyd0cmFuc2NyaXB0R2VuZXMnXTtcbiAgICBncm91cHM6IFNwYXRpYWxWaWV3U3RhdGVbJ3RyYW5zY3JpcHRHZW5lR3JvdXBzJ107XG4gICAgY2VsbENvbG9yczogTWFwPHN0cmluZywgc3RyaW5nPjtcbiAgICBjb2xvcnM6IE1hcDxzdHJpbmcsIHN0cmluZz47XG4gIH0gfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIGFzeW5jIHJlZnJlc2hDZWxsR3JvdXBDb2xvcnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29sdW1uID0gdGhpcy5kYXRhc2V0ID8gY2VsbFR5cGVDb2x1bW5Gb3IodGhpcy5kYXRhc2V0LCB0aGlzLnZpZXcpIDogbnVsbDtcbiAgICAvLyBUaGUgdXNlcidzIGNvbG91cnMgZm9yIHRoZSBncm91cGluZyBhcmUgcGFydCBvZiB3aGF0IHRoZSBjbHVzdGVyIHN3YXRjaGVzIHNob3cuXG4gICAgY29uc3Qga2V5ID0gY29sdW1uID09PSBudWxsID8gbnVsbCA6IGAke2NvbHVtbn1cXHUwMDAxJHtncm91cENvbG9yc0tleShjb2x1bW4sIHRoaXMudmlldy5ncm91cENvbG9ycyl9YDtcbiAgICBpZiAoa2V5ID09PSB0aGlzLmNlbGxHcm91cENvbG9yc0ZvcikgcmV0dXJuO1xuICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzRm9yID0ga2V5O1xuICAgIGNvbnN0IHRhc2sgPSB0aGlzLmNlbGxHcm91cENvbG9yc0xvYWQubmV4dCgpO1xuICAgIGNvbnN0IG1hcCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgY29uc3QgbWV0YSA9IGNvbHVtbiA/IHRoaXMuZGF0YXNldD8uY29sdW1ucy5maW5kKChjKSA9PiBjLm5hbWUgPT09IGNvbHVtbikgOiBudWxsO1xuICAgIGlmIChtZXRhICYmIG1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJyAmJiB0aGlzLmNvbnRyb2xzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb2xvcnMgPSBhd2FpdCB0aGlzLmNvbnRyb2xzLmNhdGVnb3J5Q29sb3JzKGNvbHVtbiEpO1xuICAgICAgICBtZXRhLmNhdGVnb3JpZXMuZm9yRWFjaCgoYywgaykgPT4ge1xuICAgICAgICAgIGlmIChjb2xvcnNba10pIG1hcC5zZXQoYywgY29sb3JzW2tdKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gTm8gY29sb3VyczogcGFsZXR0ZSBjb2xvdXJzLCBhcyB0aGUgbWFya2VycyBmYWxsIGJhY2sgdG8uXG4gICAgICB9XG4gICAgfVxuICAgIC8vIFRoZSBjZWxscycgZ3JvdXBpbmcgY2hhbmdlZCB3aGlsZSB0aGUgY29sb3VycyBsb2FkZWQ6IHRoZSBuZXdlciByZXF1ZXN0IGFwcGxpZXMgaXRzIG93bi5cbiAgICBpZiAoIXRhc2suaXNDdXJyZW50KCkpIHJldHVybjtcbiAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcbiAgICAgIHRoaXMuY2VsbEdyb3VwQ29sb3JzID0gbWFwO1xuICAgICAgdGhpcy5yZWJ1aWxkUm93cygpO1xuICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgfSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJzYy1zdWJoZWFkXCI+U2VsZWN0ZWQgZ2VuZXM8L2Rpdj5cbjxkaXYgY2xhc3M9XCJzYy1nZW5lLXNvcnRcIiAqbmdJZj1cInNvcnRTaG93blwiIHJvbGU9XCJncm91cFwiIGFyaWEtbGFiZWw9XCJTb3J0IGdlbmVzXCI+XG4gIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U29ydCBieTwvc3Bhbj5cbiAgPGJ1dHRvblxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIGNsYXNzPVwic2Mtc29ydC1idG5cIlxuICAgIFtjbGFzcy5hY3RpdmVdPVwiIWJ5Q291bnRcIlxuICAgIFthdHRyLmFyaWEtcHJlc3NlZF09XCIhYnlDb3VudFwiXG4gICAgKGNsaWNrKT1cIm9uR2VuZVNvcnQoJ25hbWUnKVwiXG4gID5cbiAgICBOYW1lXG4gIDwvYnV0dG9uPlxuICA8YnV0dG9uXG4gICAgdHlwZT1cImJ1dHRvblwiXG4gICAgY2xhc3M9XCJzYy1zb3J0LWJ0blwiXG4gICAgW2NsYXNzLmFjdGl2ZV09XCJieUNvdW50XCJcbiAgICBbYXR0ci5hcmlhLXByZXNzZWRdPVwiYnlDb3VudFwiXG4gICAgdGl0bGU9XCJUcmFuc2NyaXB0cyBpbiB2aWV3LCBtb3N0IGZpcnN0XCJcbiAgICAoY2xpY2spPVwib25HZW5lU29ydCgnY291bnQnKVwiXG4gID5cbiAgICBDb3VudFxuICA8L2J1dHRvbj5cbjwvZGl2PlxuPGRpdiBjbGFzcz1cInNjLWdlbmUtdHJlZVwiPlxuICA8ZGl2IGNsYXNzPVwic2MtZ2VuZS1yb3cgc2MtZ2VuZS1yb290XCI+XG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInNjLWV5ZVwiXG4gICAgICAoY2xpY2spPVwiXG4gICAgICAgIHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gb25BbGxHZW5lc1Nob3duKCFyb290U2hvd24pIDogb25HZW5lc1Nob3duKHZpZXcudHJhbnNjcmlwdEdlbmVzLCAhcm9vdFNob3duKVxuICAgICAgXCJcbiAgICA+XG4gICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWV5ZV09XCJyb290U2hvd25cIiBbY2xhc3MucGktZXllLXNsYXNoXT1cIiFyb290U2hvd25cIj48L2k+XG4gICAgPC9idXR0b24+XG4gICAgPHNwYW4gY2xhc3M9XCJzYy1ncm91cC1sYWJlbFwiPkdlbmVzPC9zcGFuPlxuICAgIDxzcGFuIGNsYXNzPVwic2MtY291bnRcIlxuICAgICAgPih7eyAodmlldy50cmFuc2NyaXB0QWxsR2VuZXMgPyBnZW5lVG90YWwgOiB2aWV3LnRyYW5zY3JpcHRHZW5lcy5sZW5ndGgpIHwgbnVtYmVyIH19L3t7XG4gICAgICAgIGdlbmVUb3RhbCB8IG51bWJlclxuICAgICAgfX0pPC9zcGFuXG4gICAgPlxuICAgIDxidXR0b25cbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgY2xhc3M9XCJzYy1pY29uLWJ0blwiXG4gICAgICAoY2xpY2spPVwiZ2VuZVRyZWVPcGVuID0gIWdlbmVUcmVlT3BlblwiXG4gICAgICAqbmdJZj1cIiF2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyAmJiB2aWV3LnRyYW5zY3JpcHRHZW5lcy5sZW5ndGhcIlxuICAgID5cbiAgICAgIDxpIGNsYXNzPVwicGlcIiBbY2xhc3MucGktY2hldnJvbi1kb3duXT1cImdlbmVUcmVlT3BlblwiIFtjbGFzcy5waS1jaGV2cm9uLXJpZ2h0XT1cIiFnZW5lVHJlZU9wZW5cIj48L2k+XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInNjLWljb24tYnRuXCJcbiAgICAgIChjbGljayk9XCJ0b2dnbGVBbGxHZW5lc09wZW4oKVwiXG4gICAgICAqbmdJZj1cInZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIGFsbEdlbmVMaXN0Py5sZW5ndGhcIlxuICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJhbGxHZW5lc09wZW4gPyAnSGlkZSB0aGUgZ2VuZSBsaXN0JyA6ICdTaG93IGV2ZXJ5IGdlbmUnXCJcbiAgICA+XG4gICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWNoZXZyb24tZG93bl09XCJhbGxHZW5lc09wZW5cIiBbY2xhc3MucGktY2hldnJvbi1yaWdodF09XCIhYWxsR2VuZXNPcGVuXCI+PC9pPlxuICAgIDwvYnV0dG9uPlxuICA8L2Rpdj5cbiAgPCEtLSBcIkFsbCBnZW5lc1wiOiBldmVyeSBnZW5lIG9mIHRoZSBkYXRhc2V0LCBlYWNoIHdpdGggaXRzIGV5ZSB3aGVuIHRoZSBkYXRhc2V0IHNheXMgd2hpY2hcbiAgICAgICB0cmFuc2NyaXB0cyBhcmUgd2hvc2UgKGl0cyBnZW5lIGxpc3QgaW4gY29kZSBvcmRlcikuIC0tPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwiYWxsR2VuZXNPcGVuICYmIHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIGFsbEdlbmVMaXN0Py5sZW5ndGhcIj5cbiAgICA8aW5wdXRcbiAgICAgIHBJbnB1dFRleHRcbiAgICAgIGNsYXNzPVwic2MtZ2VuZS1maWx0ZXJcIlxuICAgICAgcGxhY2Vob2xkZXI9XCJGaWx0ZXIgZ2VuZXPigKZcIlxuICAgICAgYXJpYS1sYWJlbD1cIkZpbHRlciBnZW5lc1wiXG4gICAgICBbdmFsdWVdPVwiYWxsR2VuZXNGaWx0ZXJcIlxuICAgICAgKGlucHV0KT1cIm9uQWxsR2VuZXNGaWx0ZXIoJGFueSgkZXZlbnQudGFyZ2V0KS52YWx1ZSlcIlxuICAgIC8+XG4gICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiIWNhbkhpZGVBbGxHZW5lc1wiPlxuICAgICAgVGhpcyBkYXRhc2V0IGRvZXMgbm90IHNheSB3aGljaCB0cmFuc2NyaXB0cyBhcmUgd2hvc2UsIHNvIGl0cyBnZW5lcyBjYW5ub3QgYmUgaGlkZGVuIG9uZSBieSBvbmUuXG4gICAgPC9zbWFsbD5cbiAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJjYW5IaWRlQWxsR2VuZXMgJiYgdmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ2RlbnNpdHknXCI+XG4gICAgICBUaGUgZGVuc2l0eSBtYXAgZHJhd3MgZXZlcnkgZ2VuZSBhcyBvbmUgcmFzdGVyOiBnZW5lcyBhcmUgaGlkZGVuIG9uZSBieSBvbmUgYXMgY2lyY2xlcyBvciBpY29ucy5cbiAgICA8L3NtYWxsPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1nZW5lLXJvdyBzYy1nZW5lLWxlYWYgbmVzdGVkXCIgKm5nRm9yPVwibGV0IHJvdyBvZiBhbGxSb3dzOyB0cmFja0J5OiB0cmFja0J5QWxsUm93XCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cInNjLWV5ZVwiXG4gICAgICAgIFtkaXNhYmxlZF09XCIhY2FuSGlkZUFsbEdlbmVzIHx8IHZpZXcudHJhbnNjcmlwdE1vZGUgPT09ICdkZW5zaXR5J1wiXG4gICAgICAgIChjbGljayk9XCJvbkFsbEdlbmVTaG93bihyb3cuZ2VuZSwgIXJvdy5zaG93bilcIlxuICAgICAgPlxuICAgICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWV5ZV09XCJyb3cuc2hvd25cIiBbY2xhc3MucGktZXllLXNsYXNoXT1cIiFyb3cuc2hvd25cIj48L2k+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDwhLS0gVGhlIGdlbmUncyBjb2xvdXIgYW1vbmcgZXZlcnkgZ2VuZTsgY2xpY2tpbmcgaXQgb3BlbnMgdGhlIGNvbG91ciBwaWNrZXIuIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJzYy1nZW5lLWljb25cIlxuICAgICAgICAqbmdJZj1cInJvdy5zd2F0Y2hcIlxuICAgICAgICBbc3R5bGUuY29sb3JdPVwicm93LnN3YXRjaFwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0NvbG91ciBmb3IgJyArIHJvdy5nZW5lXCJcbiAgICAgICAgcFRvb2x0aXA9XCJDb2xvdXJcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgICAoY2xpY2spPVwib3BlbkdlbmVTdHlsZSgkZXZlbnQsIHJvdy5nZW5lLCBnZW5lUG9wKVwiXG4gICAgICA+XG4gICAgICAgIDxzdmcgdmlld0JveD1cIi0xLjIgLTEuMiAyLjQgMi40XCIgY2xhc3M9XCJzYy1nbHlwaC1zdmdcIj48Y2lyY2xlIHI9XCIwLjc1XCI+PC9jaXJjbGU+PC9zdmc+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ3JvdXAtbGFiZWxcIiBbdGl0bGVdPVwicm93LmdlbmVcIj57eyByb3cuZ2VuZSB9fTwvc3Bhbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ2VuZS1jb3VudFwiICpuZ0lmPVwicm93LmNvdW50ICE9PSBudWxsXCIgdGl0bGU9XCJUcmFuc2NyaXB0cyBpbiB2aWV3XCI+e3tcbiAgICAgICAgcm93LmNvdW50IHwgbnVtYmVyXG4gICAgICB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJhbGxHZW5lc01hdGNoZWQgPiBhbGxSb3dzLmxlbmd0aFwiPlxuICAgICAgU2hvd2luZyB7eyBhbGxSb3dzLmxlbmd0aCB8IG51bWJlciB9fSBvZiB7eyBhbGxHZW5lc01hdGNoZWQgfCBudW1iZXIgfX0gZ2VuZXM6IGZpbHRlciB0byBmaW5kIHRoZSBvdGhlcnMuXG4gICAgPC9zbWFsbD5cbiAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJhbGxHZW5lc01hdGNoZWQgPT09IDBcIj5ObyBnZW5lIG1hdGNoZXMuPC9zbWFsbD5cbiAgPC9uZy1jb250YWluZXI+XG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJnZW5lVHJlZU9wZW4gJiYgIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgbm9kZSBvZiBzb3J0ZWRUcmVlOyB0cmFja0J5OiB0cmFja0J5Tm9kZVwiPlxuICAgICAgPGRpdiBjbGFzcz1cInNjLWdlbmUtcm93IHNjLWdlbmUtZ3JvdXBcIiAqbmdJZj1cIm5vZGUubmFtZVwiPlxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLWV5ZVwiIChjbGljayk9XCJvbkdlbmVzU2hvd24obm9kZS5nZW5lcywgIWdyb3VwU2hvd24uZ2V0KG5vZGUubmFtZSkpXCI+XG4gICAgICAgICAgPGlcbiAgICAgICAgICAgIGNsYXNzPVwicGlcIlxuICAgICAgICAgICAgW2NsYXNzLnBpLWV5ZV09XCJncm91cFNob3duLmdldChub2RlLm5hbWUpXCJcbiAgICAgICAgICAgIFtjbGFzcy5waS1leWUtc2xhc2hdPVwiIWdyb3VwU2hvd24uZ2V0KG5vZGUubmFtZSlcIlxuICAgICAgICAgID48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWdyb3VwLWxhYmVsXCIgW3RpdGxlXT1cIm5vZGUubmFtZVwiPnt7IG5vZGUubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1jb3VudFwiPih7eyBub2RlLmdlbmVzLmxlbmd0aCB9fSk8L3NwYW4+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwic2MtaWNvbi1idG5cIiAoY2xpY2spPVwidG9nZ2xlR2VuZUdyb3VwKG5vZGUubmFtZSlcIj5cbiAgICAgICAgICA8aVxuICAgICAgICAgICAgY2xhc3M9XCJwaVwiXG4gICAgICAgICAgICBbY2xhc3MucGktY2hldnJvbi1kb3duXT1cIiFjb2xsYXBzZWRHZW5lR3JvdXBzLmhhcyhub2RlLm5hbWUpXCJcbiAgICAgICAgICAgIFtjbGFzcy5waS1jaGV2cm9uLXJpZ2h0XT1cImNvbGxhcHNlZEdlbmVHcm91cHMuaGFzKG5vZGUubmFtZSlcIlxuICAgICAgICAgID48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIW5vZGUubmFtZSB8fCAhY29sbGFwc2VkR2VuZUdyb3Vwcy5oYXMobm9kZS5uYW1lKVwiPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJzYy1nZW5lLXJvdyBzYy1nZW5lLWxlYWZcIlxuICAgICAgICAgIFtjbGFzcy5uZXN0ZWRdPVwiISFub2RlLm5hbWVcIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBnZW5lIG9mIG5vZGUuZ2VuZXM7IHRyYWNrQnk6IHRyYWNrQnlMYWJlbFN0cmluZ1wiXG4gICAgICAgID5cbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLWV5ZVwiIChjbGljayk9XCJvbkdlbmVzU2hvd24oW2dlbmVdLCAhcm93cy5nZXQoZ2VuZSk/LnNob3duKVwiPlxuICAgICAgICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1leWVdPVwicm93cy5nZXQoZ2VuZSk/LnNob3duXCIgW2NsYXNzLnBpLWV5ZS1zbGFzaF09XCIhcm93cy5nZXQoZ2VuZSk/LnNob3duXCI+PC9pPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwhLS0gVGhlIGdlbmUncyBtYXJrZXIsIGluIGl0cyBjb2xvdXI6IGl0cyBpY29uIGluIEljb25zIG1vZGUsIGEgZG90IGZvciBjaXJjbGVzLlxuICAgICAgICAgICAgICAgQ2xpY2tpbmcgaXQgb3BlbnMgdGhlIGljb24gYW5kIGNvbG91ciBwaWNrZXIgKGFzIFhlbml1bSBFeHBsb3JlciBkb2VzKS4gLS0+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInNjLWdlbmUtaWNvblwiXG4gICAgICAgICAgICBbc3R5bGUuY29sb3JdPVwicm93cy5nZXQoZ2VuZSk/LnN3YXRjaFwiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidJY29uIGFuZCBjb2xvdXIgZm9yICcgKyBnZW5lXCJcbiAgICAgICAgICAgIHBUb29sdGlwPVwiSWNvbiBhbmQgY29sb3VyXCJcbiAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgICAgICAoY2xpY2spPVwib3BlbkdlbmVTdHlsZSgkZXZlbnQsIGdlbmUsIGdlbmVQb3ApXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8c3ZnIHZpZXdCb3g9XCItMS4yIC0xLjIgMi40IDIuNFwiIGNsYXNzPVwic2MtZ2x5cGgtc3ZnXCI+XG4gICAgICAgICAgICAgIDxwb2x5Z29uXG4gICAgICAgICAgICAgICAgKm5nSWY9XCJ2aWV3LnRyYW5zY3JpcHRNb2RlID09PSAnZ2x5cGhzJzsgZWxzZSBkb3RJY29uXCJcbiAgICAgICAgICAgICAgICBbYXR0ci5wb2ludHNdPVwicm93cy5nZXQoZ2VuZSk/LnBvaW50c1wiXG4gICAgICAgICAgICAgID48L3BvbHlnb24+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjZG90SWNvbj48Y2lyY2xlIHI9XCIwLjc1XCI+PC9jaXJjbGU+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvc3ZnPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ3JvdXAtbGFiZWxcIj57eyBnZW5lIH19PC9zcGFuPlxuICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICBjbGFzcz1cInNjLWdlbmUtY291bnRcIlxuICAgICAgICAgICAgKm5nSWY9XCJyb3dzLmdldChnZW5lKT8uY291bnQgYXMgbjsgZWxzZSB6ZXJvQ291bnRcIlxuICAgICAgICAgICAgdGl0bGU9XCJUcmFuc2NyaXB0cyBpbiB2aWV3XCJcbiAgICAgICAgICAgID57eyBuIHwgbnVtYmVyIH19PC9zcGFuXG4gICAgICAgICAgPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjemVyb0NvdW50PlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1nZW5lLWNvdW50XCIgKm5nSWY9XCJnZW5lQ291bnRzXCIgdGl0bGU9XCJUcmFuc2NyaXB0cyBpbiB2aWV3XCI+MDwvc3Bhbj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L25nLWNvbnRhaW5lcj5cbiAgPCEtLSBPbmUgcGlja2VyIGZvciBldmVyeSBnZW5lIHJvdywgZmlsbGVkIGZvciB0aGUgZ2VuZSB0aGF0IG9wZW5lZCBpdC4gLS0+XG4gIDxwLW92ZXJsYXlQYW5lbCAjZ2VuZVBvcCBzdHlsZUNsYXNzPVwic2MtZ2VuZS1zdHlsZVwiIGFwcGVuZFRvPVwiYm9keVwiPlxuICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJjb250ZW50XCI+XG4gICAgICA8c3BhdGlhbC1nZW5lLXN0eWxlXG4gICAgICAgICpuZ0lmPVwic3R5bGVHZW5lIGFzIGdlbmVcIlxuICAgICAgICBbZ2VuZV09XCJnZW5lXCJcbiAgICAgICAgd2hhdD1cIlRyYW5zY3JpcHRcIlxuICAgICAgICBbY29sb3JdPVwic3R5bGVDb2xvck9mKGdlbmUpXCJcbiAgICAgICAgW2dseXBoXT1cInN0eWxlR2x5cGggPz8gJ2NpcmNsZSdcIlxuICAgICAgICBbc2hvd0ljb25zXT1cIiF2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1wiXG4gICAgICAgIFtpY29uSGludF09XCJcbiAgICAgICAgICB2aWV3LnRyYW5zY3JpcHRNb2RlICE9PSAnZ2x5cGhzJyA/ICdJY29ucyBzaG93IHdoZW4gdGhlIHRyYW5zY3JpcHQgcG9pbnQgc3R5bGUgaXMgSWNvbnMuJyA6IG51bGxcbiAgICAgICAgXCJcbiAgICAgICAgKGNvbG9yQ2hhbmdlKT1cIm9uR2VuZUNvbG9yKGdlbmUsICRldmVudClcIlxuICAgICAgICAoZ2x5cGhDaGFuZ2UpPVwib25HbHlwaChnZW5lLCAkZXZlbnQpXCJcbiAgICAgICAgKHJlc2V0U3R5bGUpPVwicmVzZXRHZW5lU3R5bGUoZ2VuZSlcIlxuICAgICAgPjwvc3BhdGlhbC1nZW5lLXN0eWxlPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcC1vdmVybGF5UGFuZWw+XG4gIDxkaXYgY2xhc3M9XCJzYy1nZW5lLWZvb3RlclwiPlxuICAgIHt7ICh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IGdlbmVUb3RhbCA6IHZpZXcudHJhbnNjcmlwdEdlbmVzLmxlbmd0aCkgfCBudW1iZXIgfX0ve3sgZ2VuZVRvdGFsIHwgbnVtYmVyIH19XG4gICAgZ2VuZXMgc2VsZWN0ZWRcbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==