@jax-data-science/sci-image-visualizer 0.13.0 → 0.15.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 (67) hide show
  1. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +39 -3
  2. package/esm2022/lib/channel-histogram/channel-tree.mjs +65 -0
  3. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +19 -1
  4. package/esm2022/lib/contracts/display-types.mjs +7 -1
  5. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +17 -2
  9. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +88 -10
  10. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +62 -13
  11. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +21 -1
  12. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +5 -1
  13. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +4 -1
  14. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +26 -3
  15. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +7 -9
  16. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +20 -4
  17. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +4 -2
  18. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +4 -2
  19. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +42 -15
  20. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +3 -1
  21. package/esm2022/lib/spatial/lod.mjs +24 -3
  22. package/esm2022/lib/spatial/spatial-controls.facade.mjs +8 -3
  23. package/esm2022/lib/spatial/spatial-gene-filter.mjs +138 -0
  24. package/esm2022/lib/spatial/spatial-tile-merge.mjs +42 -1
  25. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +47 -10
  26. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +4 -3
  27. package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +66 -0
  28. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +106 -26
  29. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +3 -3
  30. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
  31. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
  32. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +110 -8
  33. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +41 -9
  34. package/esm2022/lib/store/visualizer-store.service.mjs +67 -1
  35. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DURPqs5a.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-qUeMuBb0.mjs} +1250 -335
  36. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-qUeMuBb0.mjs.map +1 -0
  37. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-D0IQ6PjZ.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-U1ODcfYD.mjs} +3 -2
  38. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-D0IQ6PjZ.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-U1ODcfYD.mjs.map} +1 -1
  39. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +2 -1
  40. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  41. package/lib/channel-histogram/channel-histogram.component.d.ts +14 -0
  42. package/lib/channel-histogram/channel-tree.d.ts +30 -0
  43. package/lib/contracts/channel-histogram-api.contract.d.ts +16 -0
  44. package/lib/contracts/display-types.d.ts +27 -0
  45. package/lib/contracts/image.contract.d.ts +8 -0
  46. package/lib/contracts/spatial-dataset.contract.d.ts +7 -0
  47. package/lib/contracts/visualizer.contract.d.ts +3 -0
  48. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +7 -0
  49. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +13 -2
  50. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +5 -0
  51. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +4 -0
  52. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +2 -0
  53. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +6 -1
  54. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +4 -0
  55. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +3 -1
  56. package/lib/spatial/lod.d.ts +14 -2
  57. package/lib/spatial/spatial-controls.facade.d.ts +3 -0
  58. package/lib/spatial/spatial-gene-filter.d.ts +44 -0
  59. package/lib/spatial/spatial-tile-merge.d.ts +17 -0
  60. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +18 -1
  61. package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +30 -0
  62. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +39 -7
  63. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +33 -1
  64. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +13 -1
  65. package/lib/store/visualizer-store.service.d.ts +19 -0
  66. package/package.json +1 -1
  67. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DURPqs5a.mjs.map +0 -1
@@ -1,28 +1,32 @@
1
1
  import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, NgZone, } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { SharedModule } from 'primeng/api';
4
- import { ButtonModule } from 'primeng/button';
5
4
  import { InputTextModule } from 'primeng/inputtext';
6
5
  import { OverlayPanelModule } from 'primeng/overlaypanel';
7
6
  import { TooltipModule } from 'primeng/tooltip';
7
+ import { ALL_GENES } from '../../contracts/ports/spatial-data.port';
8
8
  import { DEFAULT_SPATIAL_VIEW } from '../../contracts/display-types';
9
- import { parseCssColor, rgbToHex } from '../../contracts/color';
10
9
  import { DEFAULT_CATEGORICAL_PALETTE } from '../../spatial/spatial-encoding';
11
10
  import { cellTypeColumnFor, clusterColorMap, clusterOfGene, defaultGlyphFor } from '../../spatial/spatial-tiles';
12
- import { GLYPH_OPTIONS, buildGeneTree, glyphPoints, toggleHidden, } from '../../spatial/spatial-panel-model';
11
+ import { buildGeneTree, glyphPoints, toggleHidden } from '../../spatial/spatial-panel-model';
12
+ import { allGeneShownBy, allGenesHidden, toggleAllGeneHidden } from '../../spatial/spatial-tile-merge';
13
13
  import { Supersede } from '../../util/supersede';
14
+ import { SpatialGeneStyleComponent } from '../spatial-gene-style/spatial-gene-style.component';
14
15
  import * as i0 from "@angular/core";
15
16
  import * as i1 from "@angular/common";
16
17
  import * as i2 from "primeng/api";
17
- import * as i3 from "primeng/button";
18
- import * as i4 from "primeng/inputtext";
19
- import * as i5 from "primeng/overlaypanel";
20
- import * as i6 from "primeng/tooltip";
18
+ import * as i3 from "primeng/inputtext";
19
+ import * as i4 from "primeng/overlaypanel";
20
+ import * as i5 from "primeng/tooltip";
21
+ /** Rows of the all-genes list drawn at once; the filter narrows the rest. */
22
+ const ALL_GENES_ROWS = 200;
21
23
  /**
22
24
  * The selected transcript genes as Xenium Explorer's tree: the gene groups, then the
23
25
  * ungrouped genes, each row with an eye that hides it without deselecting it, its marker
24
26
  * in its colour (opening one icon-and-colour picker per gene), and its transcript count in
25
- * view.
27
+ * view. With "All genes" on, the root eye hides or shows every transcript and the root
28
+ * expands to every gene of the dataset, each with its eye when the dataset lists its genes
29
+ * in code order (`transcriptTiles.genes`), filtered by name past a few hundred.
26
30
  *
27
31
  * Writes only through `controls.setViewState`.
28
32
  */
@@ -40,9 +44,7 @@ export class SpatialGeneTreeComponent {
40
44
  this.geneCounts = null;
41
45
  /** Real genes in the panel — the tree's denominator. */
42
46
  this.geneTotal = 0;
43
- this.glyphOptions = GLYPH_OPTIONS;
44
47
  /** Swatches in the picker: the categorical palette genes are coloured from by default. */
45
- this.colorPresets = DEFAULT_CATEGORICAL_PALETTE.slice(0, 10).map((c) => c.toLowerCase());
46
48
  /** The tree, rebuilt when the view changes — never per change-detection pass. */
47
49
  this.geneTree = [];
48
50
  /** Per gene: its eye, swatch, glyph and count — rebuilt with the inputs (and when the
@@ -53,6 +55,18 @@ export class SpatialGeneTreeComponent {
53
55
  this.rootShown = false;
54
56
  this.collapsedGeneGroups = new Set();
55
57
  this.geneTreeOpen = true;
58
+ /** The all-genes list starts closed: it can run to thousands of genes. */
59
+ this.allGenesOpen = false;
60
+ /** The genes "All genes" lists, or null when the dataset names none. */
61
+ this.allGeneList = null;
62
+ /** Whether a gene of "All genes" can be hidden: the dataset lists its genes in code order. */
63
+ this.canHideAllGenes = false;
64
+ this.allGenesFilter = '';
65
+ /** The list's rows matching the filter, at most {@link ALL_GENES_ROWS}. */
66
+ this.allRows = [];
67
+ /** How many genes match the filter, for the "showing n of m" line. */
68
+ this.allGenesMatched = 0;
69
+ this.allGenesRowCap = ALL_GENES_ROWS;
56
70
  /** The gene the open picker edits. */
57
71
  this.styleGene = null;
58
72
  /** Colours of the cells' groups, by name — what a cluster of the same name is drawn in. */
@@ -63,14 +77,19 @@ export class SpatialGeneTreeComponent {
63
77
  this.cellGroupColorsLoad = new Supersede();
64
78
  this.trackByNode = (_i, node) => node.name ?? '';
65
79
  this.trackByLabelString = (_i, s) => s;
80
+ this.trackByAllRow = (_i, row) => row.gene;
66
81
  this.clusterColorMemo = null;
67
82
  }
68
83
  ngOnChanges(changes) {
69
84
  if (changes['view'])
70
85
  this.geneTree = buildGeneTree(this.view.transcriptGenes, this.view.transcriptGeneGroups);
71
86
  // A same-named grouping of a new dataset is not the old one.
72
- if (changes['dataset'])
87
+ if (changes['dataset']) {
73
88
  this.cellGroupColorsFor = undefined;
89
+ const coded = this.dataset?.transcriptTiles?.genes;
90
+ this.canHideAllGenes = !!coded?.length;
91
+ this.allGeneList = coded?.length ? coded : (this.dataset?.features?.names ?? null);
92
+ }
74
93
  this.rebuildRows();
75
94
  void this.refreshCellGroupColors();
76
95
  }
@@ -88,7 +107,62 @@ export class SpatialGeneTreeComponent {
88
107
  this.groupShown = new Map(this.geneTree
89
108
  .filter((node) => node.name)
90
109
  .map((node) => [node.name, this.areGenesShown(node.genes)]));
91
- this.rootShown = this.areGenesShown(genes);
110
+ this.rootShown = this.view.transcriptAllGenes ? this.anyOfAllGenesShown() : this.areGenesShown(genes);
111
+ this.rebuildAllRows();
112
+ }
113
+ /**
114
+ * The all-genes list's rows: the genes matching the filter, up to the cap. Built only while
115
+ * the list is open: the counts in view change with every pan, and the list can be thousands.
116
+ */
117
+ rebuildAllRows() {
118
+ const list = this.view.transcriptAllGenes && this.allGenesOpen ? this.allGeneList : null;
119
+ if (!list) {
120
+ this.allRows = [];
121
+ this.allGenesMatched = 0;
122
+ return;
123
+ }
124
+ const needle = this.allGenesFilter.trim().toLowerCase();
125
+ const shown = allGeneShownBy(this.view.transcriptAllGenesHidden);
126
+ const rows = [];
127
+ let matched = 0;
128
+ list.forEach((gene, code) => {
129
+ // An empty name is a code no transcript carries (a control probe).
130
+ if (!gene || (needle && !gene.toLowerCase().includes(needle)))
131
+ 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
+ });
141
+ });
142
+ this.allRows = rows;
143
+ this.allGenesMatched = matched;
144
+ }
145
+ /** Whether "All genes" draws anything: not switched off whole, nor every listed gene hidden. */
146
+ anyOfAllGenesShown() {
147
+ if (allGenesHidden(this.view))
148
+ return false;
149
+ if (!this.canHideAllGenes || !this.allGeneList)
150
+ return true;
151
+ const shown = allGeneShownBy(this.view.transcriptAllGenesHidden);
152
+ return this.allGeneList.some((g) => g && shown(g));
153
+ }
154
+ /** A gene of "All genes" in its colour by gene: its chosen one, else the palette's by code. */
155
+ allGeneColorOf(gene, code) {
156
+ return (this.view.transcriptGeneColors[gene] ||
157
+ DEFAULT_CATEGORICAL_PALETTE[code % DEFAULT_CATEGORICAL_PALETTE.length]);
158
+ }
159
+ toggleAllGenesOpen() {
160
+ this.allGenesOpen = !this.allGenesOpen;
161
+ this.rebuildAllRows();
162
+ }
163
+ onAllGenesFilter(text) {
164
+ this.allGenesFilter = text;
165
+ this.rebuildAllRows();
92
166
  }
93
167
  toggleGeneGroup(name) {
94
168
  const next = new Set(this.collapsedGeneGroups);
@@ -110,11 +184,17 @@ export class SpatialGeneTreeComponent {
110
184
  transcriptHiddenGenes: toggleHidden(this.view.transcriptHiddenGenes, genes, on),
111
185
  });
112
186
  }
113
- /** The root eye while every gene is shown: back to the chosen list. */
114
- onToggleAllGenes() {
115
- if (!this.dataset?.transcriptBins)
187
+ /** The root eye while every gene is drawn: hide or show them all (the '±' leaves "All genes"). */
188
+ onAllGenesShown(on) {
189
+ this.controls?.setViewState({ transcriptAllGenesHidden: on ? [] : [ALL_GENES] });
190
+ }
191
+ /** One gene's eye in the all-genes list. Showing one while all are off shows it alone. */
192
+ onAllGeneShown(gene, on) {
193
+ if (!this.canHideAllGenes)
116
194
  return;
117
- this.controls?.setViewState({ transcriptAllGenes: !this.view.transcriptAllGenes });
195
+ this.controls?.setViewState({
196
+ transcriptAllGenesHidden: toggleAllGeneHidden(this.view.transcriptAllGenesHidden, gene, on),
197
+ });
118
198
  }
119
199
  onGeneColor(gene, hex) {
120
200
  this.controls?.setViewState({ transcriptGeneColors: { ...this.view.transcriptGeneColors, [gene]: hex } });
@@ -144,13 +224,6 @@ export class SpatialGeneTreeComponent {
144
224
  onGlyph(gene, glyph) {
145
225
  this.controls?.setViewState({ transcriptGlyphs: { ...this.view.transcriptGlyphs, [gene]: glyph } });
146
226
  }
147
- /** A typed hex colour, accepted as `#rrggbb` or `rrggbb`; anything else is ignored. */
148
- onGeneHex(gene, text) {
149
- const t = text.trim();
150
- const rgb = /^#?[0-9a-f]{6}$/i.test(t) ? parseCssColor(t) : null;
151
- if (rgb)
152
- this.onGeneColor(gene, rgbToHex(rgb));
153
- }
154
227
  /** Back to the gene's default icon and colour (by its position in the list). */
155
228
  resetGeneStyle(gene) {
156
229
  const colors = { ...this.view.transcriptGeneColors };
@@ -222,11 +295,18 @@ export class SpatialGeneTreeComponent {
222
295
  });
223
296
  }
224
297
  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 }); }
225
- 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)=\"view.transcriptAllGenes ? onToggleAllGenes() : onGenesShown(view.transcriptGenes, !rootShown)\"\n >\n <i\n class=\"pi\"\n [class.pi-eye]=\"view.transcriptAllGenes || rootShown\"\n [class.pi-eye-slash]=\"!view.transcriptAllGenes && !rootShown\"\n ></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 </div>\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 <div class=\"sc-style-pop\" *ngIf=\"styleGene as gene\">\n <div class=\"sc-style-title\">Transcript Icon</div>\n <div class=\"sc-style-icons\" role=\"radiogroup\" [attr.aria-label]=\"'Icon for ' + gene\">\n <button\n type=\"button\"\n *ngFor=\"let opt of glyphOptions\"\n class=\"sc-style-icon\"\n role=\"radio\"\n [attr.aria-checked]=\"opt.value === styleGlyph\"\n [class.active]=\"opt.value === styleGlyph\"\n [title]=\"opt.label\"\n (click)=\"onGlyph(gene, opt.value)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt.points\"></polygon>\n </svg>\n </button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.transcriptMode !== 'glyphs'\">\n Icons show when the transcript point style is Icons.\n </small>\n <div class=\"sc-style-title\">Transcript Color</div>\n <div class=\"sc-style-color\">\n <label class=\"sc-style-swatch\" [style.background]=\"geneColorOf(gene)\" title=\"Pick a colour\">\n <input\n type=\"color\"\n [value]=\"geneColorOf(gene)\"\n (change)=\"onGeneColor(gene, $any($event.target).value)\"\n />\n </label>\n <input\n pInputText\n class=\"sc-style-hex\"\n [value]=\"geneColorOf(gene)\"\n maxlength=\"7\"\n [attr.aria-label]=\"'Hex colour for ' + gene\"\n (change)=\"onGeneHex(gene, $any($event.target).value)\"\n (keydown.enter)=\"onGeneHex(gene, $any($event.target).value)\"\n />\n </div>\n <div class=\"sc-style-title sc-style-sub\">Presets</div>\n <div class=\"sc-style-presets\">\n <button\n type=\"button\"\n *ngFor=\"let c of colorPresets\"\n class=\"sc-style-preset\"\n [style.background]=\"c\"\n [class.active]=\"c === geneColorOf(gene).toLowerCase()\"\n [title]=\"c\"\n [attr.aria-label]=\"'Colour ' + c\"\n (click)=\"onGeneColor(gene, c)\"\n ></button>\n </div>\n <p-button\n label=\"Reset to default\"\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n styleClass=\"sc-style-reset\"\n (onClick)=\"resetGeneStyle(gene)\"\n ></p-button>\n </div>\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}: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-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.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))}::ng-deep .sc-gene-style .p-overlaypanel-content{padding:.75rem}.sc-style-pop{display:flex;flex-direction:column;gap:.5rem;width:15rem}.sc-style-title{font-weight:600;font-size:.9rem}.sc-style-sub{font-size:.75rem;text-transform:uppercase;opacity:.7}.sc-style-icons,.sc-style-presets{display:grid;grid-template-columns:repeat(5,1fr);gap:.35rem}.sc-style-icon{display:inline-flex;align-items:center;justify-content:center;height:1.9rem;border:1px solid var(--surface-border, rgba(0, 0, 0, .15));border-radius:4px;background:transparent;color:var(--text-color, inherit);cursor:pointer}.sc-style-icon .sc-glyph-svg{width:1.1rem;height:1.1rem}.sc-style-icon.active{border-color:var(--primary-color, #3b82f6);background:var(--highlight-bg, rgba(59, 130, 246, .12))}.sc-style-color{display:flex;gap:.5rem;align-items:center}.sc-style-swatch{position:relative;flex:0 0 3rem;height:2rem;border-radius:4px;border:1px solid rgba(0,0,0,.2);cursor:pointer}.sc-style-swatch input{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}.sc-style-hex{flex:1 1 auto;min-width:0;font-family:monospace}.sc-style-preset{width:1.4rem;height:1.4rem;justify-self:center;border-radius:50%;border:2px solid transparent;cursor:pointer}.sc-style-preset.active{border-color:var(--text-color, #000)}.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: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: OverlayPanelModule }, { kind: "component", type: i5.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: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
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 }); }
226
299
  }
227
300
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialGeneTreeComponent, decorators: [{
228
301
  type: Component,
229
- args: [{ selector: 'spatial-gene-tree', standalone: true, imports: [CommonModule, SharedModule, ButtonModule, InputTextModule, OverlayPanelModule, TooltipModule], 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)=\"view.transcriptAllGenes ? onToggleAllGenes() : onGenesShown(view.transcriptGenes, !rootShown)\"\n >\n <i\n class=\"pi\"\n [class.pi-eye]=\"view.transcriptAllGenes || rootShown\"\n [class.pi-eye-slash]=\"!view.transcriptAllGenes && !rootShown\"\n ></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 </div>\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 <div class=\"sc-style-pop\" *ngIf=\"styleGene as gene\">\n <div class=\"sc-style-title\">Transcript Icon</div>\n <div class=\"sc-style-icons\" role=\"radiogroup\" [attr.aria-label]=\"'Icon for ' + gene\">\n <button\n type=\"button\"\n *ngFor=\"let opt of glyphOptions\"\n class=\"sc-style-icon\"\n role=\"radio\"\n [attr.aria-checked]=\"opt.value === styleGlyph\"\n [class.active]=\"opt.value === styleGlyph\"\n [title]=\"opt.label\"\n (click)=\"onGlyph(gene, opt.value)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"opt.points\"></polygon>\n </svg>\n </button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.transcriptMode !== 'glyphs'\">\n Icons show when the transcript point style is Icons.\n </small>\n <div class=\"sc-style-title\">Transcript Color</div>\n <div class=\"sc-style-color\">\n <label class=\"sc-style-swatch\" [style.background]=\"geneColorOf(gene)\" title=\"Pick a colour\">\n <input\n type=\"color\"\n [value]=\"geneColorOf(gene)\"\n (change)=\"onGeneColor(gene, $any($event.target).value)\"\n />\n </label>\n <input\n pInputText\n class=\"sc-style-hex\"\n [value]=\"geneColorOf(gene)\"\n maxlength=\"7\"\n [attr.aria-label]=\"'Hex colour for ' + gene\"\n (change)=\"onGeneHex(gene, $any($event.target).value)\"\n (keydown.enter)=\"onGeneHex(gene, $any($event.target).value)\"\n />\n </div>\n <div class=\"sc-style-title sc-style-sub\">Presets</div>\n <div class=\"sc-style-presets\">\n <button\n type=\"button\"\n *ngFor=\"let c of colorPresets\"\n class=\"sc-style-preset\"\n [style.background]=\"c\"\n [class.active]=\"c === geneColorOf(gene).toLowerCase()\"\n [title]=\"c\"\n [attr.aria-label]=\"'Colour ' + c\"\n (click)=\"onGeneColor(gene, c)\"\n ></button>\n </div>\n <p-button\n label=\"Reset to default\"\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n styleClass=\"sc-style-reset\"\n (onClick)=\"resetGeneStyle(gene)\"\n ></p-button>\n </div>\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}: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-gene-footer{text-align:right;font-size:.78rem;padding:.2rem 0;color:var(--text-color-secondary, #6c757d)}.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))}::ng-deep .sc-gene-style .p-overlaypanel-content{padding:.75rem}.sc-style-pop{display:flex;flex-direction:column;gap:.5rem;width:15rem}.sc-style-title{font-weight:600;font-size:.9rem}.sc-style-sub{font-size:.75rem;text-transform:uppercase;opacity:.7}.sc-style-icons,.sc-style-presets{display:grid;grid-template-columns:repeat(5,1fr);gap:.35rem}.sc-style-icon{display:inline-flex;align-items:center;justify-content:center;height:1.9rem;border:1px solid var(--surface-border, rgba(0, 0, 0, .15));border-radius:4px;background:transparent;color:var(--text-color, inherit);cursor:pointer}.sc-style-icon .sc-glyph-svg{width:1.1rem;height:1.1rem}.sc-style-icon.active{border-color:var(--primary-color, #3b82f6);background:var(--highlight-bg, rgba(59, 130, 246, .12))}.sc-style-color{display:flex;gap:.5rem;align-items:center}.sc-style-swatch{position:relative;flex:0 0 3rem;height:2rem;border-radius:4px;border:1px solid rgba(0,0,0,.2);cursor:pointer}.sc-style-swatch input{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}.sc-style-hex{flex:1 1 auto;min-width:0;font-family:monospace}.sc-style-preset{width:1.4rem;height:1.4rem;justify-self:center;border-radius:50%;border:2px solid transparent;cursor:pointer}.sc-style-preset.active{border-color:var(--text-color, #000)}.sc-gene-count{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.8;padding-left:.5rem}\n"] }]
302
+ args: [{ selector: 'spatial-gene-tree', standalone: true, imports: [
303
+ CommonModule,
304
+ SharedModule,
305
+ InputTextModule,
306
+ OverlayPanelModule,
307
+ TooltipModule,
308
+ 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"] }]
230
310
  }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { controls: [{
231
311
  type: Input
232
312
  }], dataset: [{
@@ -238,4 +318,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
238
318
  }], geneTotal: [{
239
319
  type: Input
240
320
  }] } });
241
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1nZW5lLXRyZWUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtZ2VuZS10cmVlL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWdlbmUtdHJlZS9zcGF0aWFsLWdlbmUtdHJlZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sR0FHUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUloRCxPQUFPLEVBQUUsb0JBQW9CLEVBQXlDLE1BQU0sK0JBQStCLENBQUM7QUFDNUcsT0FBTyxFQUFFLGFBQWEsRUFBRSxRQUFRLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNqSCxPQUFPLEVBQ0wsYUFBYSxFQUViLGFBQWEsRUFDYixXQUFXLEVBQ1gsWUFB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SSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7WUFDakIsSUFBSSxDQUFDLGVBQWUsR0FBRyxHQUFHLENBQUM7WUFDM0IsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDMUIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDOzhHQTlOVSx3QkFBd0I7a0dBQXhCLHdCQUF3Qix3TkN6RHJDLDgwTkFtS0EsOCtNRC9HWSxZQUFZLHVUQUFFLFlBQVkscUlBQUUsWUFBWSw2WEFBRSxlQUFlLHdIQUFFLGtCQUFrQixrV0FBRSxhQUFhOzsyRkFLM0Ysd0JBQXdCO2tCQVJwQyxTQUFTOytCQUNFLG1CQUFtQixjQUNqQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsa0JBQWtCLEVBQUUsYUFBYSxDQUFDLG1CQUd0Rix1QkFBdUIsQ0FBQyxNQUFNOzJHQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsVUFBVTtzQkFBbEIsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgU2hhcmVkTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuaW1wb3J0IHsgQnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9idXR0b24nO1xuaW1wb3J0IHsgSW5wdXRUZXh0TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dHRleHQnO1xuaW1wb3J0IHsgT3ZlcmxheVBhbmVsTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9vdmVybGF5cGFuZWwnO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB0eXBlIHsgSVNwYXRpYWxDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFzZXQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7IERFRkFVTFRfU1BBVElBTF9WSUVXLCBTcGF0aWFsVmlld1N0YXRlLCBUcmFuc2NyaXB0R2x5cGhOYW1lIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgcGFyc2VDc3NDb2xvciwgcmdiVG9IZXggfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY29sb3InO1xuaW1wb3J0IHsgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nJztcbmltcG9ydCB7IGNlbGxUeXBlQ29sdW1uRm9yLCBjbHVzdGVyQ29sb3JNYXAsIGNsdXN0ZXJPZkdlbmUsIGRlZmF1bHRHbHlwaEZvciB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC10aWxlcyc7XG5pbXBvcnQge1xuICBHTFlQSF9PUFRJT05TLFxuICBHZW5lVHJlZU5vZGUsXG4gIGJ1aWxkR2VuZVRyZWUsXG4gIGdseXBoUG9pbnRzLFxuICB0b2dnbGVIaWRkZW4sXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgeyBTdXBlcnNlZGUgfSBmcm9tICcuLi8uLi91dGlsL3N1cGVyc2VkZSc7XG5cbi8qKiBPbmUgZ2VuZSByb3cgYXMgdGhlIHRlbXBsYXRlIGRyYXdzIGl0LCBkZXJpdmVkIG9uY2UgcGVyIGlucHV0IGNoYW5nZS4gKi9cbmludGVyZmFjZSBHZW5lUm93VmlldyB7XG4gIHNob3duOiBib29sZWFuO1xuICBzd2F0Y2g6IHN0cmluZztcbiAgLyoqIFRoZSByb3cncyBnbHlwaCBvdXRsaW5lIChkcmF3biBpbiBJY29ucyBtb2RlKS4gKi9cbiAgcG9pbnRzOiBzdHJpbmc7XG4gIC8qKiBUcmFuc2NyaXB0cyBpbiB2aWV3LCBvciBudWxsIGJlZm9yZSB0aGUgcmVuZGVyZXIgcmVwb3J0cyBhbnkuICovXG4gIGNvdW50OiBudW1iZXIgfCBudWxsO1xufVxuXG4vKipcbiAqIFRoZSBzZWxlY3RlZCB0cmFuc2NyaXB0IGdlbmVzIGFzIFhlbml1bSBFeHBsb3JlcidzIHRyZWU6IHRoZSBnZW5lIGdyb3VwcywgdGhlbiB0aGVcbiAqIHVuZ3JvdXBlZCBnZW5lcywgZWFjaCByb3cgd2l0aCBhbiBleWUgdGhhdCBoaWRlcyBpdCB3aXRob3V0IGRlc2VsZWN0aW5nIGl0LCBpdHMgbWFya2VyXG4gKiBpbiBpdHMgY29sb3VyIChvcGVuaW5nIG9uZSBpY29uLWFuZC1jb2xvdXIgcGlja2VyIHBlciBnZW5lKSwgYW5kIGl0cyB0cmFuc2NyaXB0IGNvdW50IGluXG4gKiB2aWV3LlxuICpcbiAqIFdyaXRlcyBvbmx5IHRocm91Z2ggYGNvbnRyb2xzLnNldFZpZXdTdGF0ZWAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NwYXRpYWwtZ2VuZS10cmVlJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgU2hhcmVkTW9kdWxlLCBCdXR0b25Nb2R1bGUsIElucHV0VGV4dE1vZHVsZSwgT3ZlcmxheVBhbmVsTW9kdWxlLCBUb29sdGlwTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3NwYXRpYWwtZ2VuZS10cmVlLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3BhdGlhbC1nZW5lLXRyZWUuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNwYXRpYWxHZW5lVHJlZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8qKiBUaGUgc3BhdGlhbCBjb250cm9scyB0aGlzIHBhbmVsIHJlYWRzIGFuZCB3cml0ZXMgdGhyb3VnaDsgbnVsbCB3aXRob3V0IGEgYFNQQVRJQUxfREFUQV9QT1JUYC4gKi9cbiAgQElucHV0KCkgY29udHJvbHM6IElTcGF0aWFsQ29udHJvbHMgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBkYXRhc2V0IG9uIG9mZmVyLCBvciBudWxsLiAqL1xuICBASW5wdXQoKSBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGN1cnJlbnQgc3BhdGlhbCB2aWV3IHN0YXRlOiB3aGF0IGlzIGRyYXduLCBhbmQgaG93LiAqL1xuICBASW5wdXQoKSB2aWV3OiBTcGF0aWFsVmlld1N0YXRlID0gREVGQVVMVF9TUEFUSUFMX1ZJRVc7XG4gIC8qKiBUcmFuc2NyaXB0cyBvZiBlYWNoIHNlbGVjdGVkIGdlbmUgaW4gdGhlIGN1cnJlbnQgdmlldywgZnJvbSB0aGUgcmVuZGVyZXIuICovXG4gIEBJbnB1dCgpIGdlbmVDb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFJlYWwgZ2VuZXMgaW4gdGhlIHBhbmVsIOKAlCB0aGUgdHJlZSdzIGRlbm9taW5hdG9yLiAqL1xuICBASW5wdXQoKSBnZW5lVG90YWwgPSAwO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBnbHlwaE9wdGlvbnMgPSBHTFlQSF9PUFRJT05TO1xuICAvKiogU3dhdGNoZXMgaW4gdGhlIHBpY2tlcjogdGhlIGNhdGVnb3JpY2FsIHBhbGV0dGUgZ2VuZXMgYXJlIGNvbG91cmVkIGZyb20gYnkgZGVmYXVsdC4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNvbG9yUHJlc2V0cyA9IERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5zbGljZSgwLCAxMCkubWFwKChjKSA9PiBjLnRvTG93ZXJDYXNlKCkpO1xuXG4gIC8qKiBUaGUgdHJlZSwgcmVidWlsdCB3aGVuIHRoZSB2aWV3IGNoYW5nZXMg4oCUIG5ldmVyIHBlciBjaGFuZ2UtZGV0ZWN0aW9uIHBhc3MuICovXG4gIHByb3RlY3RlZCBnZW5lVHJlZTogR2VuZVRyZWVOb2RlW10gPSBbXTtcbiAgLyoqIFBlciBnZW5lOiBpdHMgZXllLCBzd2F0Y2gsIGdseXBoIGFuZCBjb3VudCDigJQgcmVidWlsdCB3aXRoIHRoZSBpbnB1dHMgKGFuZCB3aGVuIHRoZVxuICAgKiAgY2VsbHMnIGdyb3VwIGNvbG91cnMgYXJyaXZlKSwgc28gdGhlIHRlbXBsYXRlIGRvZXMgbm8gcGVyLXJvdyBsb29rdXBzIHBlciBjaGVjay4gKi9cbiAgcHJvdGVjdGVkIHJvd3MgPSBuZXcgTWFwPHN0cmluZywgR2VuZVJvd1ZpZXc+KCk7XG4gIC8qKiBQZXIgbmFtZWQgZ3JvdXAsIGFuZCBmb3IgdGhlIHJvb3Q6IHdoZXRoZXIgYW55IG9mIGl0cyBnZW5lcyBpcyBzaG93bi4gKi9cbiAgcHJvdGVjdGVkIGdyb3VwU2hvd24gPSBuZXcgTWFwPHN0cmluZywgYm9vbGVhbj4oKTtcbiAgcHJvdGVjdGVkIHJvb3RTaG93biA9IGZhbHNlO1xuICBwcm90ZWN0ZWQgY29sbGFwc2VkR2VuZUdyb3VwcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBwcm90ZWN0ZWQgZ2VuZVRyZWVPcGVuID0gdHJ1ZTtcbiAgLyoqIFRoZSBnZW5lIHRoZSBvcGVuIHBpY2tlciBlZGl0cy4gKi9cbiAgcHJvdGVjdGVkIHN0eWxlR2VuZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIENvbG91cnMgb2YgdGhlIGNlbGxzJyBncm91cHMsIGJ5IG5hbWUg4oCUIHdoYXQgYSBjbHVzdGVyIG9mIHRoZSBzYW1lIG5hbWUgaXMgZHJhd24gaW4uICovXG4gIHByaXZhdGUgY2VsbEdyb3VwQ29sb3JzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgLyoqIFRoZSBncm91cGluZyB7QGxpbmsgY2VsbEdyb3VwQ29sb3JzfSBiZWxvbmdzIHRvIOKAlCBhIHJlcGVhdCByZXF1ZXN0IGZvciBpdCBpcyBhIG5vLW9wLiAqL1xuICBwcml2YXRlIGNlbGxHcm91cENvbG9yc0Zvcjogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgLyoqIExhdGVzdCB3aW5zIGFtb25nIGNvbG91ciBsb2FkcyBmb3Ige0BsaW5rIGNlbGxHcm91cENvbG9yc30uICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY2VsbEdyb3VwQ29sb3JzTG9hZCA9IG5ldyBTdXBlcnNlZGUoKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHpvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICkge31cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ3ZpZXcnXSkgdGhpcy5nZW5lVHJlZSA9IGJ1aWxkR2VuZVRyZWUodGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lcywgdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKTtcbiAgICAvLyBBIHNhbWUtbmFtZWQgZ3JvdXBpbmcgb2YgYSBuZXcgZGF0YXNldCBpcyBub3QgdGhlIG9sZCBvbmUuXG4gICAgaWYgKGNoYW5nZXNbJ2RhdGFzZXQnXSkgdGhpcy5jZWxsR3JvdXBDb2xvcnNGb3IgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5yZWJ1aWxkUm93cygpO1xuICAgIHZvaWQgdGhpcy5yZWZyZXNoQ2VsbEdyb3VwQ29sb3JzKCk7XG4gIH1cblxuICBwcml2YXRlIHJlYnVpbGRSb3dzKCk6IHZvaWQge1xuICAgIGNvbnN0IGdlbmVzID0gdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lcztcbiAgICB0aGlzLnJvd3MgPSBuZXcgTWFwKFxuICAgICAgZ2VuZXMubWFwKChnZW5lLCBzbG90KSA9PiBbXG4gICAgICAgIGdlbmUsXG4gICAgICAgIHtcbiAgICAgICAgICBzaG93bjogdGhpcy5pc0dlbmVTaG93bihnZW5lKSxcbiAgICAgICAgICBzd2F0Y2g6IHRoaXMuZ2VuZVN3YXRjaE9mKGdlbmUpLFxuICAgICAgICAgIHBvaW50czogZ2x5cGhQb2ludHModGhpcy5nbHlwaE9mKGdlbmUsIHNsb3QpKSxcbiAgICAgICAgICBjb3VudDogdGhpcy5nZW5lQ291bnRPZihnZW5lKSxcbiAgICAgICAgfSxcbiAgICAgIF0pLFxuICAgICk7XG4gICAgdGhpcy5ncm91cFNob3duID0gbmV3IE1hcChcbiAgICAgIHRoaXMuZ2VuZVRyZWVcbiAgICAgICAgLmZpbHRlcigobm9kZSkgPT4gbm9kZS5uYW1lKVxuICAgICAgICAubWFwKChub2RlKSA9PiBbbm9kZS5uYW1lIGFzIHN0cmluZywgdGhpcy5hcmVHZW5lc1Nob3duKG5vZGUuZ2VuZXMpXSksXG4gICAgKTtcbiAgICB0aGlzLnJvb3RTaG93biA9IHRoaXMuYXJlR2VuZXNTaG93bihnZW5lcyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgdG9nZ2xlR2VuZUdyb3VwKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSBuZXcgU2V0KHRoaXMuY29sbGFwc2VkR2VuZUdyb3Vwcyk7XG4gICAgaWYgKG5leHQuaGFzKG5hbWUpKSBuZXh0LmRlbGV0ZShuYW1lKTtcbiAgICBlbHNlIG5leHQuYWRkKG5hbWUpO1xuICAgIHRoaXMuY29sbGFwc2VkR2VuZUdyb3VwcyA9IG5leHQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXNHZW5lU2hvd24oZ2VuZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLnZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmluY2x1ZGVzKGdlbmUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFyZUdlbmVzU2hvd24oZ2VuZXM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGdlbmVzLnNvbWUoKGcpID0+IHRoaXMuaXNHZW5lU2hvd24oZykpO1xuICB9XG5cbiAgLyoqIFRoZSBleWUgdG9nZ2xlOiBoaWRlIG9yIHNob3cgZ2VuZXMgd2l0aG91dCByZW1vdmluZyB0aGVtIGZyb20gdGhlIHNlbGVjdGlvbi4gKi9cbiAgcHJvdGVjdGVkIG9uR2VuZXNTaG93bihnZW5lczogc3RyaW5nW10sIG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHtcbiAgICAgIHRyYW5zY3JpcHRIaWRkZW5HZW5lczogdG9nZ2xlSGlkZGVuKHRoaXMudmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMsIGdlbmVzLCBvbiksXG4gICAgfSk7XG4gIH1cblxuICAvKiogVGhlIHJvb3QgZXllIHdoaWxlIGV2ZXJ5IGdlbmUgaXMgc2hvd246IGJhY2sgdG8gdGhlIGNob3NlbiBsaXN0LiAqL1xuICBwcm90ZWN0ZWQgb25Ub2dnbGVBbGxHZW5lcygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZGF0YXNldD8udHJhbnNjcmlwdEJpbnMpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0QWxsR2VuZXM6ICF0aGlzLnZpZXcudHJhbnNjcmlwdEFsbEdlbmVzIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uR2VuZUNvbG9yKGdlbmU6IHN0cmluZywgaGV4OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2VuZUNvbG9yczogeyAuLi50aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnMsIFtnZW5lXTogaGV4IH0gfSk7XG4gIH1cblxuICAvLyDilIDilIAgcGVyLWdlbmUgaWNvbiBhbmQgY29sb3VyIHBpY2tlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcm90ZWN0ZWQgb3BlbkdlbmVTdHlsZShldmVudDogRXZlbnQsIGdlbmU6IHN0cmluZywgcGFuZWw6IHsgdG9nZ2xlKGU6IEV2ZW50KTogdm9pZDsgaGlkZSgpOiB2b2lkIH0pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zdHlsZUdlbmUgPT09IGdlbmUpIHtcbiAgICAgIHBhbmVsLnRvZ2dsZShldmVudCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuc3R5bGVHZW5lID0gZ2VuZTtcbiAgICBwYW5lbC5oaWRlKCk7XG4gICAgLy8gUmUtb3BlbiBhbmNob3JlZCBvbiB0aGUgcm93IHRoYXQgd2FzIGNsaWNrZWQsIG9uY2UgdGhlIHBhbmVsIGhhcyBjbG9zZWQuXG4gICAgc2V0VGltZW91dCgoKSA9PiBwYW5lbC50b2dnbGUoZXZlbnQpKTtcbiAgfVxuXG4gIC8qKiBUaGUgaWNvbiB0aGUgb3BlbiBwaWNrZXIgc2hvd3MgYXMgY2hvc2VuLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IHN0eWxlR2x5cGgoKTogVHJhbnNjcmlwdEdseXBoTmFtZSB8IG51bGwge1xuICAgIGNvbnN0IGdlbmUgPSB0aGlzLnN0eWxlR2VuZTtcbiAgICByZXR1cm4gZ2VuZSA/IHRoaXMuZ2x5cGhPZihnZW5lLCBNYXRoLm1heCgwLCB0aGlzLnZpZXcudHJhbnNjcmlwdEdlbmVzLmluZGV4T2YoZ2VuZSkpKSA6IG51bGw7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2x5cGhQb2ludHMoZ2x5cGg6IFRyYW5zY3JpcHRHbHlwaE5hbWUpOiBzdHJpbmcge1xuICAgIHJldHVybiBnbHlwaFBvaW50cyhnbHlwaCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2x5cGhPZihnZW5lOiBzdHJpbmcsIHNsb3Q6IG51bWJlcik6IFRyYW5zY3JpcHRHbHlwaE5hbWUge1xuICAgIHJldHVybiB0aGlzLnZpZXcudHJhbnNjcmlwdEdseXBoc1tnZW5lXSA/PyBkZWZhdWx0R2x5cGhGb3Ioc2xvdCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25HbHlwaChnZW5lOiBzdHJpbmcsIGdseXBoOiBUcmFuc2NyaXB0R2x5cGhOYW1lKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdHJhbnNjcmlwdEdseXBoczogeyAuLi50aGlzLnZpZXcudHJhbnNjcmlwdEdseXBocywgW2dlbmVdOiBnbHlwaCB9IH0pO1xuICB9XG5cbiAgLyoqIEEgdHlwZWQgaGV4IGNvbG91ciwgYWNjZXB0ZWQgYXMgYCNycmdnYmJgIG9yIGBycmdnYmJgOyBhbnl0aGluZyBlbHNlIGlzIGlnbm9yZWQuICovXG4gIHByb3RlY3RlZCBvbkdlbmVIZXgoZ2VuZTogc3RyaW5nLCB0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCB0ID0gdGV4dC50cmltKCk7XG4gICAgY29uc3QgcmdiID0gL14jP1swLTlhLWZdezZ9JC9pLnRlc3QodCkgPyBwYXJzZUNzc0NvbG9yKHQpIDogbnVsbDtcbiAgICBpZiAocmdiKSB0aGlzLm9uR2VuZUNvbG9yKGdlbmUsIHJnYlRvSGV4KHJnYikpO1xuICB9XG5cbiAgLyoqIEJhY2sgdG8gdGhlIGdlbmUncyBkZWZhdWx0IGljb24gYW5kIGNvbG91ciAoYnkgaXRzIHBvc2l0aW9uIGluIHRoZSBsaXN0KS4gKi9cbiAgcHJvdGVjdGVkIHJlc2V0R2VuZVN0eWxlKGdlbmU6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGNvbG9ycyA9IHsgLi4udGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lQ29sb3JzIH07XG4gICAgY29uc3QgZ2x5cGhzID0geyAuLi50aGlzLnZpZXcudHJhbnNjcmlwdEdseXBocyB9O1xuICAgIGRlbGV0ZSBjb2xvcnNbZ2VuZV07XG4gICAgZGVsZXRlIGdseXBoc1tnZW5lXTtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyB0cmFuc2NyaXB0R2VuZUNvbG9yczogY29sb3JzLCB0cmFuc2NyaXB0R2x5cGhzOiBnbHlwaHMgfSk7XG4gIH1cblxuICAvLyDilIDilIAgY29sb3VycyBhbmQgY291bnRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBUaGUgY29sb3VyIGdlbmUgYHNsb3RgIGlzIGRyYXduIGluIHdoZW4gdHJhbnNjcmlwdHMgYXJlIGNvbG91cmVkIGJ5IGdlbmUuICovXG4gIGdlbmVDb2xvcihzbG90OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IGdlbmUgPSB0aGlzLnZpZXc/LnRyYW5zY3JpcHRHZW5lc1tzbG90XTtcbiAgICByZXR1cm4gKFxuICAgICAgKGdlbmUgJiYgdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lQ29sb3JzW2dlbmVdKSB8fFxuICAgICAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFW3Nsb3QgJSBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEUubGVuZ3RoXVxuICAgICk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2VuZUNvbG9yT2YoZ2VuZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZW5lQ29sb3IoTWF0aC5tYXgoMCwgdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lcy5pbmRleE9mKGdlbmUpKSk7XG4gIH1cblxuICAvKiogSW4gQ2x1c3RlciBjb2xvdXJpbmcsIGEgZ2VuZSdzIHN3YXRjaCBpcyBpdHMgY2x1c3RlcidzIGNvbG91ciwgYXMgaXRzIG1hcmtlcnMgYXJlLiAqL1xuICBwcm90ZWN0ZWQgZ2VuZVN3YXRjaE9mKGdlbmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMudmlldy50cmFuc2NyaXB0Q29sb3JCeSAhPT0gJ2NsdXN0ZXInKSByZXR1cm4gdGhpcy5nZW5lQ29sb3JPZihnZW5lKTtcbiAgICByZXR1cm4gdGhpcy5jbHVzdGVyQ29sb3JzKCkuZ2V0KGNsdXN0ZXJPZkdlbmUoZ2VuZSwgdGhpcy52aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSkgPz8gdGhpcy5nZW5lQ29sb3JPZihnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lQ291bnRPZihnZW5lOiBzdHJpbmcpOiBudW1iZXIgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5nZW5lQ291bnRzID8gKHRoaXMuZ2VuZUNvdW50c1tnZW5lXSA/PyAwKSA6IG51bGw7XG4gIH1cblxuICBwcm90ZWN0ZWQgdHJhY2tCeU5vZGUgPSAoX2k6IG51bWJlciwgbm9kZTogeyBuYW1lOiBzdHJpbmcgfCBudWxsIH0pID0+IG5vZGUubmFtZSA/PyAnJztcbiAgcHJvdGVjdGVkIHRyYWNrQnlMYWJlbFN0cmluZyA9IChfaTogbnVtYmVyLCBzOiBzdHJpbmcpID0+IHM7XG5cbiAgLyoqXG4gICAqIFRoZSBjbHVzdGVyIGNvbG91cnMsIHJlYnVpbHQgb25seSB3aGVuIHdoYXQgdGhleSBjb21lIGZyb20gY2hhbmdlcy4gVGhlIHRlbXBsYXRlIGFza3NcbiAgICogb25jZSBwZXIgZ2VuZSByb3cgcGVyIGNoYW5nZS1kZXRlY3Rpb24gcGFzcywgYW5kIHJlYnVpbGRpbmcgcGVyIGNhbGwgbWFkZSB0aGF0IE8oR8KyKS5cbiAgICovXG4gIHByaXZhdGUgY2x1c3RlckNvbG9ycygpOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IHRyYW5zY3JpcHRHZW5lczogZ2VuZXMsIHRyYW5zY3JpcHRHZW5lR3JvdXBzOiBncm91cHMgfSA9IHRoaXMudmlldztcbiAgICBjb25zdCBoaXQgPSB0aGlzLmNsdXN0ZXJDb2xvck1lbW87XG4gICAgaWYgKGhpdCAmJiBoaXQuZ2VuZXMgPT09IGdlbmVzICYmIGhpdC5ncm91cHMgPT09IGdyb3VwcyAmJiBoaXQuY2VsbENvbG9ycyA9PT0gdGhpcy5jZWxsR3JvdXBDb2xvcnMpIHtcbiAgICAgIHJldHVybiBoaXQuY29sb3JzO1xuICAgIH1cbiAgICBjb25zdCBjb2xvcnMgPSBjbHVzdGVyQ29sb3JNYXAoZ2VuZXMsIGdyb3VwcywgdGhpcy5jZWxsR3JvdXBDb2xvcnMsIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURSk7XG4gICAgdGhpcy5jbHVzdGVyQ29sb3JNZW1vID0geyBnZW5lcywgZ3JvdXBzLCBjZWxsQ29sb3JzOiB0aGlzLmNlbGxHcm91cENvbG9ycywgY29sb3JzIH07XG4gICAgcmV0dXJuIGNvbG9ycztcbiAgfVxuICBwcml2YXRlIGNsdXN0ZXJDb2xvck1lbW86IHtcbiAgICBnZW5lczogU3BhdGlhbFZpZXdTdGF0ZVsndHJhbnNjcmlwdEdlbmVzJ107XG4gICAgZ3JvdXBzOiBTcGF0aWFsVmlld1N0YXRlWyd0cmFuc2NyaXB0R2VuZUdyb3VwcyddO1xuICAgIGNlbGxDb2xvcnM6IE1hcDxzdHJpbmcsIHN0cmluZz47XG4gICAgY29sb3JzOiBNYXA8c3RyaW5nLCBzdHJpbmc+O1xuICB9IHwgbnVsbCA9IG51bGw7XG5cbiAgcHJpdmF0ZSBhc3luYyByZWZyZXNoQ2VsbEdyb3VwQ29sb3JzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbHVtbiA9IHRoaXMuZGF0YXNldCA/IGNlbGxUeXBlQ29sdW1uRm9yKHRoaXMuZGF0YXNldCwgdGhpcy52aWV3KSA6IG51bGw7XG4gICAgaWYgKGNvbHVtbiA9PT0gdGhpcy5jZWxsR3JvdXBDb2xvcnNGb3IpIHJldHVybjtcbiAgICB0aGlzLmNlbGxHcm91cENvbG9yc0ZvciA9IGNvbHVtbjtcbiAgICBjb25zdCB0YXNrID0gdGhpcy5jZWxsR3JvdXBDb2xvcnNMb2FkLm5leHQoKTtcbiAgICBjb25zdCBtYXAgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICAgIGNvbnN0IG1ldGEgPSBjb2x1bW4gPyB0aGlzLmRhdGFzZXQ/LmNvbHVtbnMuZmluZCgoYykgPT4gYy5uYW1lID09PSBjb2x1bW4pIDogbnVsbDtcbiAgICBpZiAobWV0YSAmJiBtZXRhLmtpbmQgPT09ICdjYXRlZ29yaWNhbCcgJiYgdGhpcy5jb250cm9scykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY29sb3JzID0gYXdhaXQgdGhpcy5jb250cm9scy5jYXRlZ29yeUNvbG9ycyhjb2x1bW4hKTtcbiAgICAgICAgbWV0YS5jYXRlZ29yaWVzLmZvckVhY2goKGMsIGspID0+IHtcbiAgICAgICAgICBpZiAoY29sb3JzW2tdKSBtYXAuc2V0KGMsIGNvbG9yc1trXSk7XG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIE5vIGNvbG91cnM6IHBhbGV0dGUgY29sb3VycywgYXMgdGhlIG1hcmtlcnMgZmFsbCBiYWNrIHRvLlxuICAgICAgfVxuICAgIH1cbiAgICAvLyBUaGUgY2VsbHMnIGdyb3VwaW5nIGNoYW5nZWQgd2hpbGUgdGhlIGNvbG91cnMgbG9hZGVkOiB0aGUgbmV3ZXIgcmVxdWVzdCBhcHBsaWVzIGl0cyBvd24uXG4gICAgaWYgKCF0YXNrLmlzQ3VycmVudCgpKSByZXR1cm47XG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XG4gICAgICB0aGlzLmNlbGxHcm91cENvbG9ycyA9IG1hcDtcbiAgICAgIHRoaXMucmVidWlsZFJvd3MoKTtcbiAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICAgIH0pO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwic2Mtc3ViaGVhZFwiPlNlbGVjdGVkIGdlbmVzPC9kaXY+XG48ZGl2IGNsYXNzPVwic2MtZ2VuZS10cmVlXCI+XG4gIDxkaXYgY2xhc3M9XCJzYy1nZW5lLXJvdyBzYy1nZW5lLXJvb3RcIj5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwic2MtZXllXCJcbiAgICAgIChjbGljayk9XCJ2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IG9uVG9nZ2xlQWxsR2VuZXMoKSA6IG9uR2VuZXNTaG93bih2aWV3LnRyYW5zY3JpcHRHZW5lcywgIXJvb3RTaG93bilcIlxuICAgID5cbiAgICAgIDxpXG4gICAgICAgIGNsYXNzPVwicGlcIlxuICAgICAgICBbY2xhc3MucGktZXllXT1cInZpZXcudHJhbnNjcmlwdEFsbEdlbmVzIHx8IHJvb3RTaG93blwiXG4gICAgICAgIFtjbGFzcy5waS1leWUtc2xhc2hdPVwiIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmICFyb290U2hvd25cIlxuICAgICAgPjwvaT5cbiAgICA8L2J1dHRvbj5cbiAgICA8c3BhbiBjbGFzcz1cInNjLWdyb3VwLWxhYmVsXCI+R2VuZXM8L3NwYW4+XG4gICAgPHNwYW4gY2xhc3M9XCJzYy1jb3VudFwiXG4gICAgICA+KHt7ICh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IGdlbmVUb3RhbCA6IHZpZXcudHJhbnNjcmlwdEdlbmVzLmxlbmd0aCkgfCBudW1iZXIgfX0ve3tcbiAgICAgICAgZ2VuZVRvdGFsIHwgbnVtYmVyXG4gICAgICB9fSk8L3NwYW5cbiAgICA+XG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInNjLWljb24tYnRuXCJcbiAgICAgIChjbGljayk9XCJnZW5lVHJlZU9wZW4gPSAhZ2VuZVRyZWVPcGVuXCJcbiAgICAgICpuZ0lmPVwiIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIHZpZXcudHJhbnNjcmlwdEdlbmVzLmxlbmd0aFwiXG4gICAgPlxuICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1jaGV2cm9uLWRvd25dPVwiZ2VuZVRyZWVPcGVuXCIgW2NsYXNzLnBpLWNoZXZyb24tcmlnaHRdPVwiIWdlbmVUcmVlT3BlblwiPjwvaT5cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJnZW5lVHJlZU9wZW4gJiYgIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgbm9kZSBvZiBnZW5lVHJlZTsgdHJhY2tCeTogdHJhY2tCeU5vZGVcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1nZW5lLXJvdyBzYy1nZW5lLWdyb3VwXCIgKm5nSWY9XCJub2RlLm5hbWVcIj5cbiAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJzYy1leWVcIiAoY2xpY2spPVwib25HZW5lc1Nob3duKG5vZGUuZ2VuZXMsICFncm91cFNob3duLmdldChub2RlLm5hbWUpKVwiPlxuICAgICAgICAgIDxpXG4gICAgICAgICAgICBjbGFzcz1cInBpXCJcbiAgICAgICAgICAgIFtjbGFzcy5waS1leWVdPVwiZ3JvdXBTaG93bi5nZXQobm9kZS5uYW1lKVwiXG4gICAgICAgICAgICBbY2xhc3MucGktZXllLXNsYXNoXT1cIiFncm91cFNob3duLmdldChub2RlLm5hbWUpXCJcbiAgICAgICAgICA+PC9pPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1ncm91cC1sYWJlbFwiIFt0aXRsZV09XCJub2RlLm5hbWVcIj57eyBub2RlLm5hbWUgfX08L3NwYW4+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwic2MtY291bnRcIj4oe3sgbm9kZS5nZW5lcy5sZW5ndGggfX0pPC9zcGFuPlxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLWljb24tYnRuXCIgKGNsaWNrKT1cInRvZ2dsZUdlbmVHcm91cChub2RlLm5hbWUpXCI+XG4gICAgICAgICAgPGlcbiAgICAgICAgICAgIGNsYXNzPVwicGlcIlxuICAgICAgICAgICAgW2NsYXNzLnBpLWNoZXZyb24tZG93bl09XCIhY29sbGFwc2VkR2VuZUdyb3Vwcy5oYXMobm9kZS5uYW1lKVwiXG4gICAgICAgICAgICBbY2xhc3MucGktY2hldnJvbi1yaWdodF09XCJjb2xsYXBzZWRHZW5lR3JvdXBzLmhhcyhub2RlLm5hbWUpXCJcbiAgICAgICAgICA+PC9pPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFub2RlLm5hbWUgfHwgIWNvbGxhcHNlZEdlbmVHcm91cHMuaGFzKG5vZGUubmFtZSlcIj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwic2MtZ2VuZS1yb3cgc2MtZ2VuZS1sZWFmXCJcbiAgICAgICAgICBbY2xhc3MubmVzdGVkXT1cIiEhbm9kZS5uYW1lXCJcbiAgICAgICAgICAqbmdGb3I9XCJsZXQgZ2VuZSBvZiBub2RlLmdlbmVzOyB0cmFja0J5OiB0cmFja0J5TGFiZWxTdHJpbmdcIlxuICAgICAgICA+XG4gICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJzYy1leWVcIiAoY2xpY2spPVwib25HZW5lc1Nob3duKFtnZW5lXSwgIXJvd3MuZ2V0KGdlbmUpPy5zaG93bilcIj5cbiAgICAgICAgICAgIDxpIGNsYXNzPVwicGlcIiBbY2xhc3MucGktZXllXT1cInJvd3MuZ2V0KGdlbmUpPy5zaG93blwiIFtjbGFzcy5waS1leWUtc2xhc2hdPVwiIXJvd3MuZ2V0KGdlbmUpPy5zaG93blwiPjwvaT5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8IS0tIFRoZSBnZW5lJ3MgbWFya2VyLCBpbiBpdHMgY29sb3VyOiBpdHMgaWNvbiBpbiBJY29ucyBtb2RlLCBhIGRvdCBmb3IgY2lyY2xlcy5cbiAgICAgICAgICAgICAgIENsaWNraW5nIGl0IG9wZW5zIHRoZSBpY29uIGFuZCBjb2xvdXIgcGlja2VyIChhcyBYZW5pdW0gRXhwbG9yZXIgZG9lcykuIC0tPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJzYy1nZW5lLWljb25cIlxuICAgICAgICAgICAgW3N0eWxlLmNvbG9yXT1cInJvd3MuZ2V0KGdlbmUpPy5zd2F0Y2hcIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSWNvbiBhbmQgY29sb3VyIGZvciAnICsgZ2VuZVwiXG4gICAgICAgICAgICBwVG9vbHRpcD1cIkljb24gYW5kIGNvbG91clwiXG4gICAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9wZW5HZW5lU3R5bGUoJGV2ZW50LCBnZW5lLCBnZW5lUG9wKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHN2ZyB2aWV3Qm94PVwiLTEuMiAtMS4yIDIuNCAyLjRcIiBjbGFzcz1cInNjLWdseXBoLXN2Z1wiPlxuICAgICAgICAgICAgICA8cG9seWdvblxuICAgICAgICAgICAgICAgICpuZ0lmPVwidmlldy50cmFuc2NyaXB0TW9kZSA9PT0gJ2dseXBocyc7IGVsc2UgZG90SWNvblwiXG4gICAgICAgICAgICAgICAgW2F0dHIucG9pbnRzXT1cInJvd3MuZ2V0KGdlbmUpPy5wb2ludHNcIlxuICAgICAgICAgICAgICA+PC9wb2x5Z29uPlxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI2RvdEljb24+PGNpcmNsZSByPVwiMC43NVwiPjwvY2lyY2xlPjwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWdyb3VwLWxhYmVsXCI+e3sgZ2VuZSB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgY2xhc3M9XCJzYy1nZW5lLWNvdW50XCJcbiAgICAgICAgICAgICpuZ0lmPVwicm93cy5nZXQoZ2VuZSk/LmNvdW50IGFzIG47IGVsc2UgemVyb0NvdW50XCJcbiAgICAgICAgICAgIHRpdGxlPVwiVHJhbnNjcmlwdHMgaW4gdmlld1wiXG4gICAgICAgICAgICA+e3sgbiB8IG51bWJlciB9fTwvc3BhblxuICAgICAgICAgID5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3plcm9Db3VudD5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtZ2VuZS1jb3VudFwiICpuZ0lmPVwiZ2VuZUNvdW50c1wiIHRpdGxlPVwiVHJhbnNjcmlwdHMgaW4gdmlld1wiPjA8L3NwYW4+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9uZy1jb250YWluZXI+XG4gIDwhLS0gT25lIHBpY2tlciBmb3IgZXZlcnkgZ2VuZSByb3csIGZpbGxlZCBmb3IgdGhlIGdlbmUgdGhhdCBvcGVuZWQgaXQuIC0tPlxuICA8cC1vdmVybGF5UGFuZWwgI2dlbmVQb3Agc3R5bGVDbGFzcz1cInNjLWdlbmUtc3R5bGVcIiBhcHBlbmRUbz1cImJvZHlcIj5cbiAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiY29udGVudFwiPlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXN0eWxlLXBvcFwiICpuZ0lmPVwic3R5bGVHZW5lIGFzIGdlbmVcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXN0eWxlLXRpdGxlXCI+VHJhbnNjcmlwdCBJY29uPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1zdHlsZS1pY29uc1wiIHJvbGU9XCJyYWRpb2dyb3VwXCIgW2F0dHIuYXJpYS1sYWJlbF09XCInSWNvbiBmb3IgJyArIGdlbmVcIj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHQgb2YgZ2x5cGhPcHRpb25zXCJcbiAgICAgICAgICAgIGNsYXNzPVwic2Mtc3R5bGUtaWNvblwiXG4gICAgICAgICAgICByb2xlPVwicmFkaW9cIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1jaGVja2VkXT1cIm9wdC52YWx1ZSA9PT0gc3R5bGVHbHlwaFwiXG4gICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cIm9wdC52YWx1ZSA9PT0gc3R5bGVHbHlwaFwiXG4gICAgICAgICAgICBbdGl0bGVdPVwib3B0LmxhYmVsXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvbkdseXBoKGdlbmUsIG9wdC52YWx1ZSlcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxzdmcgdmlld0JveD1cIi0xLjIgLTEuMiAyLjQgMi40XCIgY2xhc3M9XCJzYy1nbHlwaC1zdmdcIj5cbiAgICAgICAgICAgICAgPHBvbHlnb24gW2F0dHIucG9pbnRzXT1cIm9wdC5wb2ludHNcIj48L3BvbHlnb24+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cInZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdnbHlwaHMnXCI+XG4gICAgICAgICAgSWNvbnMgc2hvdyB3aGVuIHRoZSB0cmFuc2NyaXB0IHBvaW50IHN0eWxlIGlzIEljb25zLlxuICAgICAgICA8L3NtYWxsPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc3R5bGUtdGl0bGVcIj5UcmFuc2NyaXB0IENvbG9yPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1zdHlsZS1jb2xvclwiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cInNjLXN0eWxlLXN3YXRjaFwiIFtzdHlsZS5iYWNrZ3JvdW5kXT1cImdlbmVDb2xvck9mKGdlbmUpXCIgdGl0bGU9XCJQaWNrIGEgY29sb3VyXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNvbG9yXCJcbiAgICAgICAgICAgICAgW3ZhbHVlXT1cImdlbmVDb2xvck9mKGdlbmUpXCJcbiAgICAgICAgICAgICAgKGNoYW5nZSk9XCJvbkdlbmVDb2xvcihnZW5lLCAkYW55KCRldmVudC50YXJnZXQpLnZhbHVlKVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBwSW5wdXRUZXh0XG4gICAgICAgICAgICBjbGFzcz1cInNjLXN0eWxlLWhleFwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiZ2VuZUNvbG9yT2YoZ2VuZSlcIlxuICAgICAgICAgICAgbWF4bGVuZ3RoPVwiN1wiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZXggY29sb3VyIGZvciAnICsgZ2VuZVwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uR2VuZUhleChnZW5lLCAkYW55KCRldmVudC50YXJnZXQpLnZhbHVlKVwiXG4gICAgICAgICAgICAoa2V5ZG93bi5lbnRlcik9XCJvbkdlbmVIZXgoZ2VuZSwgJGFueSgkZXZlbnQudGFyZ2V0KS52YWx1ZSlcIlxuICAgICAgICAgIC8+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc3R5bGUtdGl0bGUgc2Mtc3R5bGUtc3ViXCI+UHJlc2V0czwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc3R5bGUtcHJlc2V0c1wiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgKm5nRm9yPVwibGV0IGMgb2YgY29sb3JQcmVzZXRzXCJcbiAgICAgICAgICAgIGNsYXNzPVwic2Mtc3R5bGUtcHJlc2V0XCJcbiAgICAgICAgICAgIFtzdHlsZS5iYWNrZ3JvdW5kXT1cImNcIlxuICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJjID09PSBnZW5lQ29sb3JPZihnZW5lKS50b0xvd2VyQ2FzZSgpXCJcbiAgICAgICAgICAgIFt0aXRsZV09XCJjXCJcbiAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0NvbG91ciAnICsgY1wiXG4gICAgICAgICAgICAoY2xpY2spPVwib25HZW5lQ29sb3IoZ2VuZSwgYylcIlxuICAgICAgICAgID48L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxwLWJ1dHRvblxuICAgICAgICAgIGxhYmVsPVwiUmVzZXQgdG8gZGVmYXVsdFwiXG4gICAgICAgICAgaWNvbj1cInBpIHBpLXJlZnJlc2hcIlxuICAgICAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICAgICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgICAgICAgc3R5bGVDbGFzcz1cInNjLXN0eWxlLXJlc2V0XCJcbiAgICAgICAgICAob25DbGljayk9XCJyZXNldEdlbmVTdHlsZShnZW5lKVwiXG4gICAgICAgID48L3AtYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9wLW92ZXJsYXlQYW5lbD5cbiAgPGRpdiBjbGFzcz1cInNjLWdlbmUtZm9vdGVyXCI+XG4gICAge3sgKHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gZ2VuZVRvdGFsIDogdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoKSB8IG51bWJlciB9fS97eyBnZW5lVG90YWwgfCBudW1iZXIgfX1cbiAgICBnZW5lcyBzZWxlY3RlZFxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
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