@jax-data-science/sci-image-visualizer 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +3 -2
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/geometry/cell-meshes.mjs +37 -0
  9. package/esm2022/lib/geometry/place.mjs +47 -0
  10. package/esm2022/lib/implementations/napari-js/napari-camera-depth.mjs +93 -0
  11. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  12. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +2 -2
  13. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  14. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +81 -15
  15. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-cells.mjs +746 -0
  16. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +325 -18
  17. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +182 -24
  18. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +95 -5
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +15 -1
  20. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +30 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +40 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +111 -28
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +14 -2
  24. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +180 -48
  25. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +28 -8
  26. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +2 -2
  27. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +10 -1
  28. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +30 -3
  29. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +15 -3
  30. package/esm2022/lib/region-editor/region-editor.component.mjs +24 -4
  31. package/esm2022/lib/region-source/region-source-ops.mjs +7 -1
  32. package/esm2022/lib/region-source/region-tiles.mjs +1 -1
  33. package/esm2022/lib/region-source/worker-region-source.mjs +24 -1
  34. package/esm2022/lib/routing-visualizer.service.mjs +404 -7
  35. package/esm2022/lib/spatial/observations-in-selection.mjs +83 -0
  36. package/esm2022/lib/spatial/plane-cells.mjs +119 -0
  37. package/esm2022/lib/spatial/spatial-controls.facade.mjs +298 -5
  38. package/esm2022/lib/spatial/spatial-encoding.mjs +35 -3
  39. package/esm2022/lib/spatial/spatial-hover.mjs +34 -1
  40. package/esm2022/lib/spatial/spatial-planes.mjs +49 -0
  41. package/esm2022/lib/spatial/spatial-selection.mjs +2 -2
  42. package/esm2022/lib/spatial/spatial-tile-merge.mjs +38 -1
  43. package/esm2022/lib/spatial/transcripts-in-selection.mjs +208 -0
  44. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +42 -65
  45. package/esm2022/lib/spatial-controls/spatial-color-by/spatial-color-by.component.mjs +187 -0
  46. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +47 -12
  47. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +3 -3
  48. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +38 -10
  49. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
  50. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
  51. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +79 -57
  52. package/esm2022/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.mjs +101 -0
  53. package/esm2022/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.mjs +94 -0
  54. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +9 -3
  55. package/esm2022/lib/store/region-source-scope.mjs +10 -1
  56. package/esm2022/lib/store/region-store.service.mjs +33 -2
  57. package/esm2022/lib/toolbar/toolbar.component.mjs +10 -3
  58. package/esm2022/lib/visualizer/spatial-region-set.mjs +95 -0
  59. package/esm2022/lib/visualizer.component.mjs +40 -4
  60. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs} +4521 -759
  61. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs.map +1 -0
  62. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs} +2 -2
  63. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs.map} +1 -1
  64. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  65. package/fesm2022/region-source.worker.js +84 -2
  66. package/lib/contracts/display-types.d.ts +90 -4
  67. package/lib/contracts/image.contract.d.ts +6 -0
  68. package/lib/contracts/ports/spatial-data.port.d.ts +7 -0
  69. package/lib/contracts/region-editor-api.contract.d.ts +9 -0
  70. package/lib/contracts/region-store.contract.d.ts +6 -0
  71. package/lib/contracts/spatial-dataset.contract.d.ts +7 -1
  72. package/lib/contracts/visualizer.contract.d.ts +43 -1
  73. package/lib/geometry/cell-meshes.d.ts +27 -0
  74. package/lib/geometry/place.d.ts +45 -0
  75. package/lib/implementations/napari-js/napari-camera-depth.d.ts +23 -0
  76. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  77. package/lib/implementations/napari-js/napari-scene.d.ts +12 -0
  78. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +19 -3
  79. package/lib/implementations/napari-js/napari-spatial-3d-cells.d.ts +141 -0
  80. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +87 -0
  81. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +49 -8
  82. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +22 -0
  83. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +12 -0
  84. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +15 -0
  85. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +27 -1
  86. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +38 -19
  87. package/lib/implementations/napari-js/napari-volume-scene.d.ts +2 -0
  88. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +53 -0
  89. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +11 -2
  90. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +7 -0
  91. package/lib/region-editor/class-tree/class-tree.component.d.ts +16 -1
  92. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +10 -1
  93. package/lib/region-editor/region-editor.component.d.ts +4 -0
  94. package/lib/region-source/region-source-ops.d.ts +12 -0
  95. package/lib/region-source/region-tiles.d.ts +8 -0
  96. package/lib/region-source/worker-region-source.d.ts +18 -0
  97. package/lib/routing-visualizer.service.d.ts +140 -1
  98. package/lib/spatial/observations-in-selection.d.ts +43 -0
  99. package/lib/spatial/plane-cells.d.ts +37 -0
  100. package/lib/spatial/spatial-controls.facade.d.ts +59 -0
  101. package/lib/spatial/spatial-encoding.d.ts +14 -1
  102. package/lib/spatial/spatial-hover.d.ts +23 -0
  103. package/lib/spatial/spatial-planes.d.ts +22 -0
  104. package/lib/spatial/spatial-selection.d.ts +2 -1
  105. package/lib/spatial/spatial-tile-merge.d.ts +9 -0
  106. package/lib/spatial/transcripts-in-selection.d.ts +95 -0
  107. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +19 -28
  108. package/lib/spatial-controls/spatial-color-by/spatial-color-by.component.d.ts +64 -0
  109. package/lib/spatial-controls/spatial-controls.component.d.ts +17 -2
  110. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +16 -6
  111. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +26 -23
  112. package/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.d.ts +48 -0
  113. package/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.d.ts +43 -0
  114. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +3 -1
  115. package/lib/store/region-source-scope.d.ts +4 -0
  116. package/lib/store/region-store.service.d.ts +21 -0
  117. package/lib/toolbar/toolbar.component.d.ts +6 -1
  118. package/lib/visualizer/spatial-region-set.d.ts +55 -0
  119. package/lib/visualizer.component.d.ts +14 -0
  120. package/package.json +1 -1
  121. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs.map +0 -1
@@ -12,9 +12,22 @@ import { TooltipModule } from 'primeng/tooltip';
12
12
  import { DEFAULT_SPATIAL_VIEW, } from '../../contracts/display-types';
13
13
  import { observationGeneColor, observationGeneGlyph } from '../../spatial/spatial-gene-filter';
14
14
  import { emptySelection } from '../../spatial/spatial-selection';
15
- import { CLIP_OPTIONS, columnOptions, glyphPoints, middleSection, sectionLabel, } from '../../spatial/spatial-panel-model';
15
+ import { CLIP_OPTIONS, glyphPoints, middleSection, sectionLabel, } from '../../spatial/spatial-panel-model';
16
16
  import { SpatialGeneStyleComponent } from '../spatial-gene-style/spatial-gene-style.component';
17
- import { SpatialKeyComponent } from '../spatial-key/spatial-key.component';
17
+ import { SpatialColorByComponent } from '../spatial-color-by/spatial-color-by.component';
18
+ import { cellsShown } from '../../spatial/lod';
19
+ /**
20
+ * The Observations section — one marker per observation (cell centroid, Visium spot), or, with a
21
+ * cell segmentation, the cells' own shapes — and what else draws them: whether they are shown and
22
+ * as what (Markers or Cell segmentations), one {@link SpatialColorByComponent colouring} for
23
+ * either, the gene filter, the markers' size and opacity or the cells' drawing (projected by the
24
+ * dialog), the gene map, the 3D scene (volume, cloud, sections, density volumes) and the
25
+ * continuous-only knobs.
26
+ *
27
+ * Renders the section and the sections after it as siblings in the dialog body
28
+ * (`display: contents`). Writes only through `controls.setViewState`.
29
+ */
30
+ import { SpatialSelectionObservationsComponent } from '../spatial-selection-observations/spatial-selection-observations.component';
18
31
  import * as i0 from "@angular/core";
19
32
  import * as i1 from "@angular/common";
20
33
  import * as i2 from "@angular/forms";
@@ -26,16 +39,6 @@ import * as i7 from "primeng/overlaypanel";
26
39
  import * as i8 from "primeng/selectbutton";
27
40
  import * as i9 from "primeng/slider";
28
41
  import * as i10 from "primeng/tooltip";
29
- /**
30
- * The Observations section — one marker per observation (cell centroid, Visium spot) — and
31
- * what else draws them: what colours them (a column or a gene, mutually exclusive, with
32
- * the {@link SpatialKeyComponent key}), point size and opacity, the gene map, the 3D scene
33
- * (volume, cloud, sections, density volumes) and the continuous-only knobs.
34
- *
35
- * Renders the section and the sections after it as siblings in the dialog body
36
- * (`display: contents`). Writes only through the port: `setViewState`, and the colour
37
- * source's own `colorByColumn` / `colorByFeature` / `clearColorBy`.
38
- */
39
42
  export class SpatialObservationsPanelComponent {
40
43
  constructor() {
41
44
  /** The spatial controls this panel reads and writes through; null without a `SPATIAL_DATA_PORT`. */
@@ -62,6 +65,11 @@ export class SpatialObservationsPanelComponent {
62
65
  this.open = false;
63
66
  /** Asks to open or close it; two-way with `open`. */
64
67
  this.openChange = new EventEmitter();
68
+ /**
69
+ * Whether the dataset's cells can be drawn here (a cell segmentation, and in 3D a 3D one): the
70
+ * observations are shown as Markers or as Cell segmentations.
71
+ */
72
+ this.cellsAvailable = false;
65
73
  /** A legend row was clicked (see the key). */
66
74
  this.categoryClicked = new EventEmitter();
67
75
  this.clipOptions = CLIP_OPTIONS;
@@ -72,10 +80,13 @@ export class SpatialObservationsPanelComponent {
72
80
  ];
73
81
  /** Virtual-scrolled only past this many options (see the cells panel's gene dropdown). */
74
82
  this.geneVirtualScrollFrom = 200;
75
- /** Colour-by column choices — "None" plus every column the dataset declares. */
76
- this.columnOptions = [];
77
- this.selectedColumn = null;
78
- this.selectedGene = null;
83
+ /** What the observations are shown as, with a cell segmentation. */
84
+ this.showAsOptions = [
85
+ { label: 'Markers', value: 'markers' },
86
+ { label: 'Cell segmentations', value: 'cells' },
87
+ ];
88
+ /** The choice of Markers or Cell segmentations, kept while the observations are hidden. */
89
+ this.chosenShownAs = null;
79
90
  /**
80
91
  * The dataset's imaged section positions, or null when its z is continuous rather than
81
92
  * sectioned. Read once per dataset — the scan walks the z of every observation, so it
@@ -94,36 +105,56 @@ export class SpatialObservationsPanelComponent {
94
105
  this.geneFilterFailed$ = this.controls?.getGeneFilterFailed$?.() ?? of(false);
95
106
  }
96
107
  if (changes['dataset'] || changes['controls']) {
97
- this.columnOptions = columnOptions(this.dataset);
98
- // A new dataset almost certainly has different columns; drop stale UI state.
99
- this.selectedGene = null;
108
+ if (changes['dataset'])
109
+ this.chosenShownAs = null;
100
110
  this.sections = this.controls?.sampledSections() ?? null;
101
111
  }
102
- if (changes['view']) {
103
- this.selectedColumn = this.view.colorBy?.kind === 'column' ? this.view.colorBy.name : null;
104
- this.selectedGene = this.view.colorBy?.kind === 'feature' ? this.view.colorBy.name : null;
105
- }
106
112
  }
107
- // ── colour source ───────────────────────────────────────────────────────
108
- /** Column dropdown. Choosing a column supersedes any gene selection. */
109
- onColumn(name) {
110
- this.selectedColumn = name;
111
- this.selectedGene = null;
112
- if (!name) {
113
- this.controls?.clearColorBy();
113
+ // ── shown, and as what ──────────────────────────────────────────────────
114
+ /** Whether the cells are drawn (the explicit choice, or automatically for data that has them). */
115
+ get cellsOn() {
116
+ return this.cellsAvailable && cellsShown(this.dataset, this.view);
117
+ }
118
+ /** Whether the observations are shown at all, as markers or as cells. */
119
+ get observationsShown() {
120
+ return this.view.showPoints || this.cellsOn;
121
+ }
122
+ /** What the observations are shown as (the toggle): the cells while they are drawn, else the
123
+ * markers, or, hidden, what was last chosen. */
124
+ get shownAs() {
125
+ if (!this.cellsAvailable)
126
+ return 'markers';
127
+ if (this.cellsOn)
128
+ return 'cells';
129
+ if (this.view.showPoints)
130
+ return 'markers';
131
+ return this.chosenShownAs ?? 'cells';
132
+ }
133
+ /** Show or hide the observations, as what they were shown as. */
134
+ onShowObservations(on) {
135
+ if (on)
136
+ this.showAs(this.shownAs);
137
+ else
138
+ this.controls?.setViewState({ showPoints: false, ...(this.cellsAvailable ? { showCells: false } : {}) });
139
+ }
140
+ onShownAs(as) {
141
+ if (!as)
114
142
  return;
115
- }
116
- this.controls?.colorByColumn(name);
143
+ this.chosenShownAs = as;
144
+ if (this.observationsShown)
145
+ this.showAs(as);
117
146
  }
118
- /** A gene was picked; it supersedes any column selection. */
119
- onGene(name) {
120
- this.selectedGene = name;
121
- if (!name) {
122
- this.controls?.clearColorBy();
123
- return;
124
- }
125
- this.selectedColumn = null;
126
- this.controls?.colorByFeature(name);
147
+ /**
148
+ * Draw the observations as the markers, or as the cells: one or the other, never both (the
149
+ * renderers draw no markers while the cells are drawn). The markers stay switched on under the
150
+ * cells, so a view without them (spatial 3D of a 2D segmentation) still shows the markers.
151
+ */
152
+ showAs(as) {
153
+ this.chosenShownAs = as;
154
+ this.controls?.setViewState({
155
+ showPoints: true,
156
+ ...(this.cellsAvailable ? { showCells: as === 'cells' } : {}),
157
+ });
127
158
  }
128
159
  // ── which observations are drawn ────────────────────────────────────────
129
160
  /** Genes picked for the observation filter; none draws every observation. */
@@ -199,10 +230,6 @@ export class SpatialObservationsPanelComponent {
199
230
  'transcripts assigned to them. The transcript density map, and transcripts grouped by area when zoomed ' +
200
231
  'out, are hidden while this is on: they carry no cells to filter by.');
201
232
  }
202
- /** Cell outlines on offer, which changes what the circles mean. */
203
- get hasCells() {
204
- return !!(this.dataset?.polygonTiles || this.dataset?.polygons);
205
- }
206
233
  /** True while a selection is active — everything else renders muted. */
207
234
  get hasSelection() {
208
235
  return this.selection.count > 0;
@@ -291,14 +318,6 @@ export class SpatialObservationsPanelComponent {
291
318
  // The volume, the cloud and the density volumes share one space, so each one
292
319
  // hides the others to some degree. Independent toggles because the useful views
293
320
  // are the combinations, not a single "3D mode".
294
- onShowVolume(on) {
295
- this.controls?.setViewState({ showVolume: on });
296
- }
297
- onVolumeOpacity(value) {
298
- if (value === undefined)
299
- return;
300
- this.controls?.setViewState({ volumeOpacity: value });
301
- }
302
321
  onShowPoints(on) {
303
322
  this.controls?.setViewState({ showPoints: on });
304
323
  }
@@ -355,7 +374,7 @@ export class SpatialObservationsPanelComponent {
355
374
  this.controls?.setViewState({ percentileClip: value });
356
375
  }
357
376
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialObservationsPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
358
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialObservationsPanelComponent, isStandalone: true, selector: "spatial-observations-panel", inputs: { controls: "controls", dataset: "dataset", view: "view", genes: "genes", legend: "legend", colorBarCss: "colorBarCss", selection: "selection", selectedCategory: "selectedCategory", colormapOptions: "colormapOptions", is3d: "is3d", open: "open" }, outputs: { openChange: "openChange", categoryClicked: "categoryClicked" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowPoints($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <small class=\"sc-hint\" *ngIf=\"hasCells && !is3d\">\n One circle per cell, at every zoom. Cell outlines are drawn over the circles once cells are big enough on\n screen to outline.\n </small>\n <!-- Colour source. Column and gene are mutually exclusive: picking one\n clears the other, so what drives the colours is never ambiguous. -->\n <div class=\"sc-section\">\n <label class=\"sc-lbl\" for=\"sc-column\">Colour by column</label>\n <p-dropdown\n inputId=\"sc-column\"\n [options]=\"columnOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedColumn\"\n (ngModelChange)=\"onColumn($event)\"\n placeholder=\"None (flat colour)\"\n appendTo=\"body\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n </div>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-gene\">Colour by gene</label>\n <!-- A filterable dropdown, not a free-text box: the genes are visible before\n anything is typed, and each keystroke narrows a list the user can see.\n Virtual-scrolled because a targeted panel runs to a few thousand names. -->\n <p-dropdown\n inputId=\"sc-gene\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedGene\"\n (ngModelChange)=\"onGene($event)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onShow)=\"genes?.ensureList()\"\n [showClear]=\"true\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Search {{ ds.features.count | number }} genes\u2026\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n <small class=\"sc-hint\" *ngIf=\"gene.failed\">Gene lookup failed.</small>\n </div>\n\n <!-- Which observations are drawn at all, by what they express. Several genes at\n once, unlike the colour, which reads one: picking genes here hides every\n observation that expresses none of them (or not all of them), and by default\n colours (and, in 2D, marks) each drawn one by its gene. -->\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-show-genes\">Show observations expressing</label>\n <p-multiSelect\n inputId=\"sc-show-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenes\"\n (onChange)=\"onObservationGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\n [showClear]=\"true\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Any gene (every observation)\"\n [selectedItemsLabel]=\"'{0} genes'\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"sc-full\"\n >\n <!-- A picked gene shows its icon in its colour; clicking it edits them. -->\n <ng-template let-option pTemplate=\"item\">\n <div class=\"sc-obs-gene-option\">\n <span class=\"sc-obs-gene-name\">{{ option.label }}</span>\n <ng-container *ngIf=\"isObservationGene(option.value)\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: option.value }\"></ng-container>\n </ng-container>\n </div>\n </ng-template>\n </p-multiSelect>\n <p-selectButton\n *ngIf=\"view.observationGenes.length > 1\"\n [options]=\"matchOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenesMatch\"\n (ngModelChange)=\"onObservationGenesMatch($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n <!-- The picked genes: each one's icon and colour (click to edit), and a way out. -->\n <div class=\"sc-obs-genes\" *ngIf=\"view.observationGenes.length\">\n <div class=\"sc-obs-gene-row\" *ngFor=\"let g of view.observationGenes; trackBy: trackByGene\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: g }\"></ng-container>\n <span class=\"sc-obs-gene-name\">{{ g }}</span>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n [attr.aria-label]=\"'Stop showing ' + g\"\n pTooltip=\"Remove\"\n tooltipPosition=\"top\"\n (click)=\"removeObservationGene(g)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.observationGenes.length\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.observationGenesColorBy\"\n (onChange)=\"onObservationGenesColorBy($event.checked)\"\n label=\"Colour by these genes\"\n pTooltip=\"Each observation in the colour (and, in 2D, the icon) of the picked gene it expresses most, relative to that gene's highest value. Off, Colour by column or gene applies.\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.observationGenes.length\">{{ geneFilterHint }}</small>\n <!-- The filter is never dropped silently: a failed expression read keeps the observations\n as they were drawn, and says so. -->\n <small class=\"sc-hint sc-error\" *ngIf=\"view.observationGenes.length && (geneFilterFailed$ | async)\">\n The expression of the picked genes could not be read, so the observations still show the previous\n filter.\n <a href=\"\" (click)=\"$event.preventDefault(); retryGeneFilter()\">Try again</a>\n </small>\n </div>\n </ng-container>\n\n <spatial-key\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-key>\n\n <!-- Display -->\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <div class=\"sc-row\" *ngIf=\"ds.volume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showVolume\"\n (onChange)=\"onShowVolume($event.checked)\"\n label=\"Reference volume\"\n pTooltip=\"The registered anatomy the observations sit in\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- The backdrop's own opacity: reading the cloud or a density field\n through the anatomy means turning the anatomy down, not the data. -->\n <div class=\"sc-row\" *ngIf=\"ds.volume && view.showVolume\">\n <span class=\"sc-lbl\">Volume opacity</span>\n <p-slider\n [ngModel]=\"view.volumeOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onVolumeOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.volumeOpacity }}</span>\n </div>\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (onChange)=\"onShowPoints($event.checked)\"\n label=\"Observations\"\n pTooltip=\"The measured cells. Hide them to read the density volumes underneath\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n\n <!-- A gene's icon in its colour: the button that opens its icon and colour picker. -->\n <ng-template #geneMark let-g>\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"geneColorOf(g)\"\n [attr.aria-label]=\"'Icon and colour for ' + g\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, g, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"glyphPointsOf(g)\"></polygon>\n </svg>\n </button>\n </ng-template>\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as g\"\n [gene]=\"g\"\n what=\"Observation\"\n [color]=\"geneColorOf(g)\"\n [glyph]=\"geneGlyphOf(g)\"\n iconHint=\"Icons show on the 2D observation markers.\"\n (colorChange)=\"onGeneColor(g, $event)\"\n (glyphChange)=\"onGeneGlyph(g, $event)\"\n (resetStyle)=\"resetGeneStyle(g)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n</ng-container>\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-obs-genes{display:flex;flex-direction:column;gap:.15rem;margin-top:.35rem}.sc-obs-gene-row,.sc-obs-gene-option{display:flex;align-items:center;gap:.4rem;min-width:0}.sc-obs-gene-option{flex:1 1 auto;justify-content:space-between}.sc-obs-gene-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i3.Checkbox, selector: "p-checkbox", inputs: ["value", "name", "disabled", "binary", "label", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "styleClass", "labelStyleClass", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i5.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i6.MultiSelect, selector: "p-multiSelect", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: OverlayPanelModule }, { kind: "component", type: i7.OverlayPanel, selector: "p-overlayPanel", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i8.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey", "autofocus"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i9.Slider, selector: "p-slider", inputs: ["animate", "disabled", "min", "max", "orientation", "step", "range", "style", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i10.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: SpatialKeyComponent, selector: "spatial-key", inputs: ["controls", "dataset", "view", "legend", "colorBarCss", "selectedCategory", "colormapOptions"], outputs: ["categoryClicked"] }, { kind: "component", type: SpatialGeneStyleComponent, selector: "spatial-gene-style", inputs: ["gene", "what", "color", "glyph", "iconHint", "showIcons"], outputs: ["colorChange", "glyphChange", "resetStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
377
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialObservationsPanelComponent, isStandalone: true, selector: "spatial-observations-panel", inputs: { controls: "controls", dataset: "dataset", view: "view", genes: "genes", legend: "legend", colorBarCss: "colorBarCss", selection: "selection", selectedCategory: "selectedCategory", colormapOptions: "colormapOptions", is3d: "is3d", open: "open", cellsAvailable: "cellsAvailable" }, outputs: { openChange: "openChange", categoryClicked: "categoryClicked" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <!-- Shows or hides the observations, as whichever the toggle below shows them as. -->\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"observationsShown\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowObservations($event.checked)\"\n pTooltip=\"Show the observations\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <!-- With a cell segmentation: shown as the markers OR as the cells' own shapes, one at a time.\n One colouring for either, below. -->\n <div class=\"sc-row sc-show-as\" *ngIf=\"cellsAvailable\">\n <span class=\"sc-lbl\">Show as</span>\n <p-selectButton\n [options]=\"showAsOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"shownAs\"\n (ngModelChange)=\"onShownAs($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n </div>\n\n <spatial-color-by\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [genes]=\"genes\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-color-by>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <!-- Which observations are drawn at all, by what they express. Several genes at\n once, unlike the colour, which reads one: picking genes here hides every\n observation that expresses none of them (or not all of them), and by default\n colours (and, in 2D, marks) each drawn one by its gene. -->\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-show-genes\">Show observations expressing</label>\n <p-multiSelect\n inputId=\"sc-show-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenes\"\n (onChange)=\"onObservationGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\n [showClear]=\"true\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Any gene (every observation)\"\n [selectedItemsLabel]=\"'{0} genes'\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"sc-full\"\n >\n <!-- A picked gene shows its icon in its colour; clicking it edits them. -->\n <ng-template let-option pTemplate=\"item\">\n <div class=\"sc-obs-gene-option\">\n <span class=\"sc-obs-gene-name\">{{ option.label }}</span>\n <ng-container *ngIf=\"isObservationGene(option.value)\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: option.value }\"></ng-container>\n </ng-container>\n </div>\n </ng-template>\n </p-multiSelect>\n <p-selectButton\n *ngIf=\"view.observationGenes.length > 1\"\n [options]=\"matchOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenesMatch\"\n (ngModelChange)=\"onObservationGenesMatch($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n <!-- The picked genes: each one's icon and colour (click to edit), and a way out. -->\n <div class=\"sc-obs-genes\" *ngIf=\"view.observationGenes.length\">\n <div class=\"sc-obs-gene-row\" *ngFor=\"let g of view.observationGenes; trackBy: trackByGene\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: g }\"></ng-container>\n <span class=\"sc-obs-gene-name\">{{ g }}</span>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n [attr.aria-label]=\"'Stop showing ' + g\"\n pTooltip=\"Remove\"\n tooltipPosition=\"top\"\n (click)=\"removeObservationGene(g)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.observationGenes.length\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.observationGenesColorBy\"\n (onChange)=\"onObservationGenesColorBy($event.checked)\"\n label=\"Colour by these genes\"\n pTooltip=\"Each observation in the colour (and, in 2D, the icon) of the picked gene it expresses most, relative to that gene's highest value. Off, Colour by applies.\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.observationGenes.length\">{{ geneFilterHint }}</small>\n <!-- The filter is never dropped silently: a failed expression read keeps the observations\n as they were drawn, and says so. -->\n <small class=\"sc-hint sc-error\" *ngIf=\"view.observationGenes.length && (geneFilterFailed$ | async)\">\n The expression of the picked genes could not be read, so the observations still show the previous\n filter.\n <a href=\"\" (click)=\"$event.preventDefault(); retryGeneFilter()\">Try again</a>\n </small>\n </div>\n </ng-container>\n\n <!-- Markers: how they are drawn. -->\n <ng-container *ngIf=\"!cellsAvailable || shownAs === 'markers'\">\n <div class=\"sc-subhead\">Markers</div>\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </ng-container>\n\n <!-- Cell segmentations: how the cells are drawn, projected by the dialog. -->\n <ng-container *ngIf=\"cellsAvailable && shownAs === 'cells'\">\n <ng-content select=\"spatial-cells-panel\"></ng-content>\n </ng-container>\n\n <!-- The selected cell's (or cell type's, or region's) observations, by group: through the\n volume in 3D, on the plane shown in 2D. -->\n <spatial-selection-observations [controls]=\"controls\" [is3d]=\"is3d\"></spatial-selection-observations>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <!-- The reference volume is the Volume section's, the observations this section's own header\n checkbox. -->\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n\n <!-- A gene's icon in its colour: the button that opens its icon and colour picker. -->\n <ng-template #geneMark let-g>\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"geneColorOf(g)\"\n [attr.aria-label]=\"'Icon and colour for ' + g\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, g, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"glyphPointsOf(g)\"></polygon>\n </svg>\n </button>\n </ng-template>\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as g\"\n [gene]=\"g\"\n what=\"Observation\"\n [color]=\"geneColorOf(g)\"\n [glyph]=\"geneGlyphOf(g)\"\n iconHint=\"Icons show on the 2D observation markers.\"\n (colorChange)=\"onGeneColor(g, $event)\"\n (glyphChange)=\"onGeneGlyph(g, $event)\"\n (resetStyle)=\"resetGeneStyle(g)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n</ng-container>\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)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px 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))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}.sc-obs-genes{display:flex;flex-direction:column;gap:.15rem;margin-top:.35rem}.sc-obs-gene-row,.sc-obs-gene-option{display:flex;align-items:center;gap:.4rem;min-width:0}.sc-obs-gene-option{flex:1 1 auto;justify-content:space-between}.sc-obs-gene-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i3.Checkbox, selector: "p-checkbox", inputs: ["value", "name", "disabled", "binary", "label", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "styleClass", "labelStyleClass", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i5.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i6.MultiSelect, selector: "p-multiSelect", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: OverlayPanelModule }, { kind: "component", type: i7.OverlayPanel, selector: "p-overlayPanel", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i8.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey", "autofocus"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i9.Slider, selector: "p-slider", inputs: ["animate", "disabled", "min", "max", "orientation", "step", "range", "style", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i10.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: SpatialColorByComponent, selector: "spatial-color-by", inputs: ["controls", "dataset", "view", "genes", "legend", "colorBarCss", "selectedCategory", "colormapOptions"], outputs: ["categoryClicked"] }, { kind: "component", type: SpatialGeneStyleComponent, selector: "spatial-gene-style", inputs: ["gene", "what", "color", "glyph", "iconHint", "showIcons"], outputs: ["colorChange", "glyphChange", "resetStyle"] }, { kind: "component", type: SpatialSelectionObservationsComponent, selector: "spatial-selection-observations", inputs: ["controls", "is3d"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
359
378
  }
360
379
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialObservationsPanelComponent, decorators: [{
361
380
  type: Component,
@@ -369,9 +388,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
369
388
  SelectButtonModule,
370
389
  SliderModule,
371
390
  TooltipModule,
372
- SpatialKeyComponent,
391
+ SpatialColorByComponent,
373
392
  SpatialGeneStyleComponent,
374
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowPoints($event.checked)\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <small class=\"sc-hint\" *ngIf=\"hasCells && !is3d\">\n One circle per cell, at every zoom. Cell outlines are drawn over the circles once cells are big enough on\n screen to outline.\n </small>\n <!-- Colour source. Column and gene are mutually exclusive: picking one\n clears the other, so what drives the colours is never ambiguous. -->\n <div class=\"sc-section\">\n <label class=\"sc-lbl\" for=\"sc-column\">Colour by column</label>\n <p-dropdown\n inputId=\"sc-column\"\n [options]=\"columnOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedColumn\"\n (ngModelChange)=\"onColumn($event)\"\n placeholder=\"None (flat colour)\"\n appendTo=\"body\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n </div>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-gene\">Colour by gene</label>\n <!-- A filterable dropdown, not a free-text box: the genes are visible before\n anything is typed, and each keystroke narrows a list the user can see.\n Virtual-scrolled because a targeted panel runs to a few thousand names. -->\n <p-dropdown\n inputId=\"sc-gene\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"selectedGene\"\n (ngModelChange)=\"onGene($event)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onShow)=\"genes?.ensureList()\"\n [showClear]=\"true\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Search {{ ds.features.count | number }} genes\u2026\"\n styleClass=\"sc-full\"\n ></p-dropdown>\n <small class=\"sc-hint\" *ngIf=\"gene.failed\">Gene lookup failed.</small>\n </div>\n\n <!-- Which observations are drawn at all, by what they express. Several genes at\n once, unlike the colour, which reads one: picking genes here hides every\n observation that expresses none of them (or not all of them), and by default\n colours (and, in 2D, marks) each drawn one by its gene. -->\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-show-genes\">Show observations expressing</label>\n <p-multiSelect\n inputId=\"sc-show-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenes\"\n (onChange)=\"onObservationGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\n [showClear]=\"true\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Any gene (every observation)\"\n [selectedItemsLabel]=\"'{0} genes'\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"sc-full\"\n >\n <!-- A picked gene shows its icon in its colour; clicking it edits them. -->\n <ng-template let-option pTemplate=\"item\">\n <div class=\"sc-obs-gene-option\">\n <span class=\"sc-obs-gene-name\">{{ option.label }}</span>\n <ng-container *ngIf=\"isObservationGene(option.value)\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: option.value }\"></ng-container>\n </ng-container>\n </div>\n </ng-template>\n </p-multiSelect>\n <p-selectButton\n *ngIf=\"view.observationGenes.length > 1\"\n [options]=\"matchOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenesMatch\"\n (ngModelChange)=\"onObservationGenesMatch($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n <!-- The picked genes: each one's icon and colour (click to edit), and a way out. -->\n <div class=\"sc-obs-genes\" *ngIf=\"view.observationGenes.length\">\n <div class=\"sc-obs-gene-row\" *ngFor=\"let g of view.observationGenes; trackBy: trackByGene\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: g }\"></ng-container>\n <span class=\"sc-obs-gene-name\">{{ g }}</span>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n [attr.aria-label]=\"'Stop showing ' + g\"\n pTooltip=\"Remove\"\n tooltipPosition=\"top\"\n (click)=\"removeObservationGene(g)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.observationGenes.length\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.observationGenesColorBy\"\n (onChange)=\"onObservationGenesColorBy($event.checked)\"\n label=\"Colour by these genes\"\n pTooltip=\"Each observation in the colour (and, in 2D, the icon) of the picked gene it expresses most, relative to that gene's highest value. Off, Colour by column or gene applies.\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.observationGenes.length\">{{ geneFilterHint }}</small>\n <!-- The filter is never dropped silently: a failed expression read keeps the observations\n as they were drawn, and says so. -->\n <small class=\"sc-hint sc-error\" *ngIf=\"view.observationGenes.length && (geneFilterFailed$ | async)\">\n The expression of the picked genes could not be read, so the observations still show the previous\n filter.\n <a href=\"\" (click)=\"$event.preventDefault(); retryGeneFilter()\">Try again</a>\n </small>\n </div>\n </ng-container>\n\n <spatial-key\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-key>\n\n <!-- Display -->\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <div class=\"sc-row\" *ngIf=\"ds.volume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showVolume\"\n (onChange)=\"onShowVolume($event.checked)\"\n label=\"Reference volume\"\n pTooltip=\"The registered anatomy the observations sit in\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- The backdrop's own opacity: reading the cloud or a density field\n through the anatomy means turning the anatomy down, not the data. -->\n <div class=\"sc-row\" *ngIf=\"ds.volume && view.showVolume\">\n <span class=\"sc-lbl\">Volume opacity</span>\n <p-slider\n [ngModel]=\"view.volumeOpacity\"\n [min]=\"0.05\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onVolumeOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.volumeOpacity }}</span>\n </div>\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.showPoints\"\n (onChange)=\"onShowPoints($event.checked)\"\n label=\"Observations\"\n pTooltip=\"The measured cells. Hide them to read the density volumes underneath\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n\n <!-- A gene's icon in its colour: the button that opens its icon and colour picker. -->\n <ng-template #geneMark let-g>\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"geneColorOf(g)\"\n [attr.aria-label]=\"'Icon and colour for ' + g\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, g, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"glyphPointsOf(g)\"></polygon>\n </svg>\n </button>\n </ng-template>\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as g\"\n [gene]=\"g\"\n what=\"Observation\"\n [color]=\"geneColorOf(g)\"\n [glyph]=\"geneGlyphOf(g)\"\n iconHint=\"Icons show on the 2D observation markers.\"\n (colorChange)=\"onGeneColor(g, $event)\"\n (glyphChange)=\"onGeneGlyph(g, $event)\"\n (resetStyle)=\"resetGeneStyle(g)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n</ng-container>\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-obs-genes{display:flex;flex-direction:column;gap:.15rem;margin-top:.35rem}.sc-obs-gene-row,.sc-obs-gene-option{display:flex;align-items:center;gap:.4rem;min-width:0}.sc-obs-gene-option{flex:1 1 auto;justify-content:space-between}.sc-obs-gene-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
393
+ SpatialSelectionObservationsComponent,
394
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"dataset as ds\">\n <!-- Observations: one marker per observation (cell centroid, Visium spot), and what\n colours them. The lead section for datasets without cell outlines. -->\n <div class=\"sc-panel\" [class.open]=\"open\">\n <div class=\"sc-panel-head\" (click)=\"openChange.emit(!open)\">\n <!-- Shows or hides the observations, as whichever the toggle below shows them as. -->\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"observationsShown\"\n (click)=\"$event.stopPropagation()\"\n (onChange)=\"onShowObservations($event.checked)\"\n pTooltip=\"Show the observations\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n <span class=\"sc-panel-title\">Observations</span>\n <i class=\"pi\" [class.pi-chevron-down]=\"open\" [class.pi-chevron-right]=\"!open\"></i>\n </div>\n <div class=\"sc-panel-body\" *ngIf=\"open\">\n <!-- With a cell segmentation: shown as the markers OR as the cells' own shapes, one at a time.\n One colouring for either, below. -->\n <div class=\"sc-row sc-show-as\" *ngIf=\"cellsAvailable\">\n <span class=\"sc-lbl\">Show as</span>\n <p-selectButton\n [options]=\"showAsOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"shownAs\"\n (ngModelChange)=\"onShownAs($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n </div>\n\n <spatial-color-by\n [controls]=\"controls\"\n [dataset]=\"ds\"\n [view]=\"view\"\n [genes]=\"genes\"\n [legend]=\"legend\"\n [colorBarCss]=\"colorBarCss\"\n [selectedCategory]=\"selectedCategory\"\n [colormapOptions]=\"colormapOptions\"\n (categoryClicked)=\"categoryClicked.emit($event)\"\n ></spatial-color-by>\n\n <ng-container *ngIf=\"genes?.state$ | async as gene\">\n <!-- Which observations are drawn at all, by what they express. Several genes at\n once, unlike the colour, which reads one: picking genes here hides every\n observation that expresses none of them (or not all of them), and by default\n colours (and, in 2D, marks) each drawn one by its gene. -->\n <div class=\"sc-section\" *ngIf=\"ds.features\">\n <label class=\"sc-lbl\" for=\"sc-show-genes\">Show observations expressing</label>\n <p-multiSelect\n inputId=\"sc-show-genes\"\n [options]=\"gene.options\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenes\"\n (onChange)=\"onObservationGenes($event.value)\"\n [filter]=\"true\"\n filterBy=\"label\"\n [resetFilterOnHide]=\"true\"\n (onFilter)=\"genes?.onFilter($event.filter)\"\n (onPanelShow)=\"genes?.ensureList()\"\n [virtualScroll]=\"gene.options.length > geneVirtualScrollFrom\"\n [virtualScrollItemSize]=\"30\"\n [showToggleAll]=\"false\"\n [showClear]=\"true\"\n [emptyFilterMessage]=\"gene.remote ? 'No match \u2014 keep typing' : 'No match'\"\n [emptyMessage]=\"gene.remote ? 'Type to search genes' : 'No genes'\"\n appendTo=\"body\"\n placeholder=\"Any gene (every observation)\"\n [selectedItemsLabel]=\"'{0} genes'\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"sc-full\"\n >\n <!-- A picked gene shows its icon in its colour; clicking it edits them. -->\n <ng-template let-option pTemplate=\"item\">\n <div class=\"sc-obs-gene-option\">\n <span class=\"sc-obs-gene-name\">{{ option.label }}</span>\n <ng-container *ngIf=\"isObservationGene(option.value)\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: option.value }\"></ng-container>\n </ng-container>\n </div>\n </ng-template>\n </p-multiSelect>\n <p-selectButton\n *ngIf=\"view.observationGenes.length > 1\"\n [options]=\"matchOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.observationGenesMatch\"\n (ngModelChange)=\"onObservationGenesMatch($event)\"\n [allowEmpty]=\"false\"\n styleClass=\"sc-buttons\"\n ></p-selectButton>\n <!-- The picked genes: each one's icon and colour (click to edit), and a way out. -->\n <div class=\"sc-obs-genes\" *ngIf=\"view.observationGenes.length\">\n <div class=\"sc-obs-gene-row\" *ngFor=\"let g of view.observationGenes; trackBy: trackByGene\">\n <ng-container *ngTemplateOutlet=\"geneMark; context: { $implicit: g }\"></ng-container>\n <span class=\"sc-obs-gene-name\">{{ g }}</span>\n <button\n type=\"button\"\n class=\"sc-icon-btn\"\n [attr.aria-label]=\"'Stop showing ' + g\"\n pTooltip=\"Remove\"\n tooltipPosition=\"top\"\n (click)=\"removeObservationGene(g)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.observationGenes.length\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.observationGenesColorBy\"\n (onChange)=\"onObservationGenesColorBy($event.checked)\"\n label=\"Colour by these genes\"\n pTooltip=\"Each observation in the colour (and, in 2D, the icon) of the picked gene it expresses most, relative to that gene's highest value. Off, Colour by applies.\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <small class=\"sc-hint\" *ngIf=\"view.observationGenes.length\">{{ geneFilterHint }}</small>\n <!-- The filter is never dropped silently: a failed expression read keeps the observations\n as they were drawn, and says so. -->\n <small class=\"sc-hint sc-error\" *ngIf=\"view.observationGenes.length && (geneFilterFailed$ | async)\">\n The expression of the picked genes could not be read, so the observations still show the previous\n filter.\n <a href=\"\" (click)=\"$event.preventDefault(); retryGeneFilter()\">Try again</a>\n </small>\n </div>\n </ng-container>\n\n <!-- Markers: how they are drawn. -->\n <ng-container *ngIf=\"!cellsAvailable || shownAs === 'markers'\">\n <div class=\"sc-subhead\">Markers</div>\n <div class=\"sc-section\">\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Point size</span>\n <p-slider\n [ngModel]=\"view.pointScale\"\n [min]=\"0.25\"\n [max]=\"5\"\n [step]=\"0.25\"\n (onChange)=\"onPointScale($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.pointScale }}\u00D7</span>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Opacity</span>\n <p-slider\n [ngModel]=\"view.opacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.opacity }}</span>\n </div>\n </div>\n </ng-container>\n\n <!-- Cell segmentations: how the cells are drawn, projected by the dialog. -->\n <ng-container *ngIf=\"cellsAvailable && shownAs === 'cells'\">\n <ng-content select=\"spatial-cells-panel\"></ng-content>\n </ng-container>\n\n <!-- The selected cell's (or cell type's, or region's) observations, by group: through the\n volume in 3D, on the plane shown in 2D. -->\n <spatial-selection-observations [controls]=\"controls\" [is3d]=\"is3d\"></spatial-selection-observations>\n </div>\n </div>\n\n <!-- Only for a gene: the map draws that gene's expression as a field. In 2D\n it goes under the cells of the displayed plane; in 3D it is one sheet per\n imaged section, optionally smoothed along z into a volume. -->\n <div class=\"sc-section\" *ngIf=\"canMapGene\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMap\"\n (onChange)=\"onGeneMap($event.checked)\"\n label=\"Gene map (expression field)\"\n [pTooltip]=\"\n is3d\n ? 'Draw this gene\\'s expression as one field per imaged section \u2014 an estimate between the cells, empty where nothing was measured'\n : 'Draw this gene\\'s expression as a smooth field UNDER the cells \u2014 an estimate between them, transparent where nothing was measured'\n \"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- 3D only: interpolating along z turns the measured sheets into an\n estimate, so it is its own decision and its own label. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.geneMapVolume\"\n (onChange)=\"onGeneMapVolume($event.checked)\"\n label=\"Volume rendering (interpolate along z)\"\n pTooltip=\"Smooth the per-section fields into a continuous volume \u2014 an ESTIMATE between the imaged sections, not measured tissue\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <!-- Meaningless while interpolating: a volume built from one section would\n smear that slide through the specimen's whole depth. -->\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"geneMapOneSection\"\n (onChange)=\"onGeneMapOneSection($event.checked)\"\n label=\"One map section at a time\"\n pTooltip=\"Draw a single imaged section's field instead of the whole stack of sheets\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap && is3d && isSectioned && !view.geneMapVolume && geneMapOneSection\">\n <span class=\"sc-lbl\">Map section</span>\n <p-slider\n [ngModel]=\"view.geneMapSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onGeneMapSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ geneMapSectionLabel }}</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.geneMapSmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onGeneMapSmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapSmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.geneMap\">\n <span class=\"sc-lbl\">Map opacity</span>\n <p-slider\n [ngModel]=\"view.geneMapOpacity\"\n [min]=\"0.1\"\n [max]=\"1\"\n [step]=\"0.05\"\n (onChange)=\"onGeneMapOpacity($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.geneMapOpacity }}</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && !is3d\">\n Kernel-weighted mean per cell, not a sum \u2014 so a crowded region does not glow for being crowded. Transparent\n where no cell was measured. Turn the cells' own Opacity down to read the field under them.\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.geneMap && is3d\">\n {{ geneMapVolumeNote }}\n </div>\n </div>\n\n <!-- 3D only: the volume, the cloud and the density volumes occupy the same\n space, so each hides the others. Independent toggles, because the useful\n views are the combinations \u2014 the field alone, one section's cells over it,\n the anatomy alone. -->\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <span class=\"sc-lbl\">Show</span>\n <!-- The reference volume is the Volume section's, the observations this section's own header\n checkbox. -->\n <!-- Only for data that really is sectioned; a continuous z has no sections\n to step through. -->\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"oneSection\"\n (onChange)=\"onOneSection($event.checked)\"\n label=\"One section at a time\"\n pTooltip=\"Draw a single imaged section's cells, so the density volumes between the sections stay visible\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.showPoints && isSectioned && oneSection\">\n <span class=\"sc-lbl\">Section</span>\n <p-slider\n [ngModel]=\"view.pointSection\"\n [min]=\"0\"\n [max]=\"lastSection\"\n [step]=\"1\"\n (onChange)=\"onPointSection($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ sectionLabel }}</span>\n </div>\n </div>\n\n <div class=\"sc-section\" *ngIf=\"is3d\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.densityVolume\"\n (onChange)=\"onDensityVolume($event.checked)\"\n label=\"Cluster density volumes\"\n pTooltip=\"Raymarch each cluster as a smooth density field \u2014 an ESTIMATE between the imaged sections, not measured cells\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\" *ngIf=\"view.densityVolume\">\n <span class=\"sc-lbl\">Smoothing</span>\n <p-slider\n [ngModel]=\"view.densitySmoothing\"\n [min]=\"0.5\"\n [max]=\"4\"\n [step]=\"0.5\"\n (onChange)=\"onDensitySmoothing($event.value)\"\n ></p-slider>\n <span class=\"sc-val\">{{ view.densitySmoothing }}\u00D7</span>\n </div>\n <div class=\"sc-hint\" *ngIf=\"view.densityVolume\">{{ densityNote }}</div>\n </div>\n\n <!-- Continuous-only knobs: meaningless for a categorical palette. -->\n <div class=\"sc-section\" *ngIf=\"isContinuous\">\n <div class=\"sc-row\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"view.logScale\"\n (onChange)=\"onLogScale($event.checked)\"\n label=\"Log scale\"\n pTooltip=\"Counts collapse against their outliers on a linear ramp\"\n tooltipPosition=\"top\"\n ></p-checkbox>\n </div>\n <div class=\"sc-row\">\n <span class=\"sc-lbl\">Clip outliers</span>\n <p-dropdown\n [options]=\"clipOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"view.percentileClip\"\n (ngModelChange)=\"onClip($event)\"\n appendTo=\"body\"\n pTooltip=\"Percentile the contrast window is taken at\"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- Reserves the readout column this row has no readout for, so the\n control's right edge lines up with every slider's. -->\n <span class=\"sc-val\"></span>\n </div>\n </div>\n\n <!-- A gene's icon in its colour: the button that opens its icon and colour picker. -->\n <ng-template #geneMark let-g>\n <button\n type=\"button\"\n class=\"sc-gene-icon\"\n [style.color]=\"geneColorOf(g)\"\n [attr.aria-label]=\"'Icon and colour for ' + g\"\n pTooltip=\"Icon and colour\"\n tooltipPosition=\"top\"\n (click)=\"openGeneStyle($event, g, genePop)\"\n >\n <svg viewBox=\"-1.2 -1.2 2.4 2.4\" class=\"sc-glyph-svg\">\n <polygon [attr.points]=\"glyphPointsOf(g)\"></polygon>\n </svg>\n </button>\n </ng-template>\n <p-overlayPanel #genePop styleClass=\"sc-gene-style\" appendTo=\"body\">\n <ng-template pTemplate=\"content\">\n <spatial-gene-style\n *ngIf=\"styleGene as g\"\n [gene]=\"g\"\n what=\"Observation\"\n [color]=\"geneColorOf(g)\"\n [glyph]=\"geneGlyphOf(g)\"\n iconHint=\"Icons show on the 2D observation markers.\"\n (colorChange)=\"onGeneColor(g, $event)\"\n (glyphChange)=\"onGeneGlyph(g, $event)\"\n (resetStyle)=\"resetGeneStyle(g)\"\n ></spatial-gene-style>\n </ng-template>\n </p-overlayPanel>\n</ng-container>\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)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px 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))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}.sc-obs-genes{display:flex;flex-direction:column;gap:.15rem;margin-top:.35rem}.sc-obs-gene-row,.sc-obs-gene-option{display:flex;align-items:center;gap:.4rem;min-width:0}.sc-obs-gene-option{flex:1 1 auto;justify-content:space-between}.sc-obs-gene-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
375
395
  }], propDecorators: { controls: [{
376
396
  type: Input
377
397
  }], dataset: [{
@@ -396,7 +416,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
396
416
  type: Input
397
417
  }], openChange: [{
398
418
  type: Output
419
+ }], cellsAvailable: [{
420
+ type: Input
399
421
  }], categoryClicked: [{
400
422
  type: Output
401
423
  }] } });
402
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUVMLE1BQU0sR0FFUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBSWhELE9BQU8sRUFFTCxvQkFBb0IsR0FHckIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2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Qix5QkFBeUI7cUJBQzFCLG1CQUdnQix1QkFBdUIsQ0FBQyxNQUFNOzhCQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLE1BQU07c0JBQWQsS0FBSztnQkFFRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUVHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsSUFBSTtzQkFBWixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFYSxVQUFVO3NCQUE1QixNQUFNO2dCQUVZLGVBQWU7c0JBQWpDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQ2hlY2tib3hNb2R1bGUgfSBmcm9tICdwcmltZW5nL2NoZWNrYm94JztcbmltcG9ydCB7IERyb3Bkb3duTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9kcm9wZG93bic7XG5pbXBvcnQgeyBNdWx0aVNlbGVjdE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvbXVsdGlzZWxlY3QnO1xuaW1wb3J0IHsgT3ZlcmxheVBhbmVsTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9vdmVybGF5cGFuZWwnO1xuaW1wb3J0IHsgU2VsZWN0QnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9zZWxlY3RidXR0b24nO1xuaW1wb3J0IHsgU2xpZGVyTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9zbGlkZXInO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB0eXBlIHsgSVNwYXRpYWxDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFzZXQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7XG4gIENvbG9ybWFwTm9kZSxcbiAgREVGQVVMVF9TUEFUSUFMX1ZJRVcsXG4gIFNwYXRpYWxWaWV3U3RhdGUsXG4gIFRyYW5zY3JpcHRHbHlwaE5hbWUsXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IG9ic2VydmF0aW9uR2VuZUNvbG9yLCBvYnNlcnZhdGlvbkdlbmVHbHlwaCB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1nZW5lLWZpbHRlcic7XG5pbXBvcnQgeyBTcGF0aWFsU2VsZWN0aW9uTWFzaywgZW1wdHlTZWxlY3Rpb24gfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7XG4gIENMSVBfT1BUSU9OUyxcbiAgUGFuZWxPcHRpb24sXG4gIGNvbHVtbk9wdGlvbnMsXG4gIGdseXBoUG9pbnRzLFxuICBtaWRkbGVTZWN0aW9uLFxuICBzZWN0aW9uTGFiZWwsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgeyBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1nZW5lLXN0eWxlL3NwYXRpYWwtZ2VuZS1zdHlsZS5jb21wb25lbnQnO1xuaW1wb3J0IHR5cGUgeyBHZW5lUGlja2VyTW9kZWwgfSBmcm9tICcuLi9zcGF0aWFsLWdlbmUtcGlja2VyJztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbExlZ2VuZEVudHJ5IH0gZnJvbSAnLi4vc3BhdGlhbC1rZXkvc3BhdGlhbC1rZXkubW9kZWwnO1xuaW1wb3J0IHsgU3BhdGlhbEtleUNvbXBvbmVudCB9IGZyb20gJy4uL3NwYXRpYWwta2V5L3NwYXRpYWwta2V5LmNvbXBvbmVudCc7XG5cbi8qKlxuICogVGhlIE9ic2VydmF0aW9ucyBzZWN0aW9uIOKAlCBvbmUgbWFya2VyIHBlciBvYnNlcnZhdGlvbiAoY2VsbCBjZW50cm9pZCwgVmlzaXVtIHNwb3QpIOKAlCBhbmRcbiAqIHdoYXQgZWxzZSBkcmF3cyB0aGVtOiB3aGF0IGNvbG91cnMgdGhlbSAoYSBjb2x1bW4gb3IgYSBnZW5lLCBtdXR1YWxseSBleGNsdXNpdmUsIHdpdGhcbiAqIHRoZSB7QGxpbmsgU3BhdGlhbEtleUNvbXBvbmVudCBrZXl9KSwgcG9pbnQgc2l6ZSBhbmQgb3BhY2l0eSwgdGhlIGdlbmUgbWFwLCB0aGUgM0Qgc2NlbmVcbiAqICh2b2x1bWUsIGNsb3VkLCBzZWN0aW9ucywgZGVuc2l0eSB2b2x1bWVzKSBhbmQgdGhlIGNvbnRpbnVvdXMtb25seSBrbm9icy5cbiAqXG4gKiBSZW5kZXJzIHRoZSBzZWN0aW9uIGFuZCB0aGUgc2VjdGlvbnMgYWZ0ZXIgaXQgYXMgc2libGluZ3MgaW4gdGhlIGRpYWxvZyBib2R5XG4gKiAoYGRpc3BsYXk6IGNvbnRlbnRzYCkuIFdyaXRlcyBvbmx5IHRocm91Z2ggdGhlIHBvcnQ6IGBzZXRWaWV3U3RhdGVgLCBhbmQgdGhlIGNvbG91clxuICogc291cmNlJ3Mgb3duIGBjb2xvckJ5Q29sdW1uYCAvIGBjb2xvckJ5RmVhdHVyZWAgLyBgY2xlYXJDb2xvckJ5YC5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIENoZWNrYm94TW9kdWxlLFxuICAgIERyb3Bkb3duTW9kdWxlLFxuICAgIE11bHRpU2VsZWN0TW9kdWxlLFxuICAgIE92ZXJsYXlQYW5lbE1vZHVsZSxcbiAgICBTZWxlY3RCdXR0b25Nb2R1bGUsXG4gICAgU2xpZGVyTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gICAgU3BhdGlhbEtleUNvbXBvbmVudCxcbiAgICBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vc3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbE9ic2VydmF0aW9uc1BhbmVsQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLyoqIFRoZSBzcGF0aWFsIGNvbnRyb2xzIHRoaXMgcGFuZWwgcmVhZHMgYW5kIHdyaXRlcyB0aHJvdWdoOyBudWxsIHdpdGhvdXQgYSBgU1BBVElBTF9EQVRBX1BPUlRgLiAqL1xuICBASW5wdXQoKSBjb250cm9sczogSVNwYXRpYWxDb250cm9scyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGRhdGFzZXQgb24gb2ZmZXIsIG9yIG51bGwuICovXG4gIEBJbnB1dCgpIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgY3VycmVudCBzcGF0aWFsIHZpZXcgc3RhdGU6IHdoYXQgaXMgZHJhd24sIGFuZCBob3cuICovXG4gIEBJbnB1dCgpIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUgPSBERUZBVUxUX1NQQVRJQUxfVklFVztcbiAgLyoqIFRoZSBnZW5lIGxpc3QgXCJDb2xvdXIgYnkgZ2VuZVwiIHBpY2tzIGZyb20sIHNoYXJlZCB3aXRoIHRoZSBvdGhlciBnZW5lIGRyb3Bkb3ducy4gKi9cbiAgQElucHV0KCkgZ2VuZXM6IEdlbmVQaWNrZXJNb2RlbCB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGtleSdzIGNhdGVnb3JpY2FsIGxlZ2VuZCwgb3IgbnVsbCDigJQgd2hpY2ggYWxzbyBkZWNpZGVzIHRoZSBjb250aW51b3VzIGtub2JzLiAqL1xuICBASW5wdXQoKSBsZWdlbmQ6IFNwYXRpYWxMZWdlbmRFbnRyeVtdIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUga2V5J3MgY29udGludW91cyBjb2xvdXIgYmFyIChhIENTUyBncmFkaWVudCksIG9yIG51bGwgd2hlbiBjYXRlZ29yaWNhbC4gKi9cbiAgQElucHV0KCkgY29sb3JCYXJDc3M6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIGN1cnJlbnQgc2VsZWN0aW9uIChpdHMgY291bnQsIGFuZCB3aGF0IGlzIG11dGVkKS4gKi9cbiAgQElucHV0KCkgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayA9IGVtcHR5U2VsZWN0aW9uKCk7XG4gIC8qKiBUaGUgbGVnZW5kIHJvdyB3aG9zZSBjYXRlZ29yeSBpcyBzZWxlY3RlZCwgZm9yIGhpZ2hsaWdodGluZy4gKi9cbiAgQElucHV0KCkgc2VsZWN0ZWRDYXRlZ29yeTogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBDb2xvcm1hcCB0cmVlIGZvciB0aGUgY29udGludW91cyBjb2xvdXIgc2NhbGUuICovXG4gIEBJbnB1dCgpIGNvbG9ybWFwT3B0aW9uczogQ29sb3JtYXBOb2RlW10gPSBbXTtcbiAgLyoqIFNldCB3aGlsZSB0aGUgM0QgY2xvdWQgaXMgdGhlIGFjdGl2ZSBtb2RlLiAqL1xuICBASW5wdXQoKSBpczNkID0gZmFsc2U7XG4gIC8qKiBXaGV0aGVyIHRoZSBPYnNlcnZhdGlvbnMgc2VjdGlvbiBpcyBleHBhbmRlZC4gKi9cbiAgQElucHV0KCkgb3BlbiA9IGZhbHNlO1xuICAvKiogQXNrcyB0byBvcGVuIG9yIGNsb3NlIGl0OyB0d28td2F5IHdpdGggYG9wZW5gLiAqL1xuICBAT3V0cHV0KCkgcmVhZG9ubHkgb3BlbkNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKTtcbiAgLyoqIEEgbGVnZW5kIHJvdyB3YXMgY2xpY2tlZCAoc2VlIHRoZSBrZXkpLiAqL1xuICBAT3V0cHV0KCkgcmVhZG9ubHkgY2F0ZWdvcnlDbGlja2VkID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNsaXBPcHRpb25zID0gQ0xJUF9PUFRJT05TO1xuICAvKiogSG93IHNldmVyYWwgZ2VuZXMgb2YgdGhlIG9ic2VydmF0aW9uIGZpbHRlciBjb21iaW5lLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWF0Y2hPcHRpb25zOiBQYW5lbE9wdGlvbjxTcGF0aWFsVmlld1N0YXRlWydvYnNlcnZhdGlvbkdlbmVzTWF0Y2gnXT5bXSA9IFtcbiAgICB7IGxhYmVsOiAnQW55IGdlbmUnLCB2YWx1ZTogJ2FueScgfSxcbiAgICB7IGxhYmVsOiAnQWxsIGdlbmVzJywgdmFsdWU6ICdhbGwnIH0sXG4gIF07XG4gIC8qKiBWaXJ0dWFsLXNjcm9sbGVkIG9ubHkgcGFzdCB0aGlzIG1hbnkgb3B0aW9ucyAoc2VlIHRoZSBjZWxscyBwYW5lbCdzIGdlbmUgZHJvcGRvd24pLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZ2VuZVZpcnR1YWxTY3JvbGxGcm9tID0gMjAwO1xuXG4gIC8qKiBDb2xvdXItYnkgY29sdW1uIGNob2ljZXMg4oCUIFwiTm9uZVwiIHBsdXMgZXZlcnkgY29sdW1uIHRoZSBkYXRhc2V0IGRlY2xhcmVzLiAqL1xuICBwcm90ZWN0ZWQgY29sdW1uT3B0aW9uczogUGFuZWxPcHRpb248c3RyaW5nIHwgbnVsbD5bXSA9IFtdO1xuICBwcm90ZWN0ZWQgc2VsZWN0ZWRDb2x1bW46IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcm90ZWN0ZWQgc2VsZWN0ZWRHZW5lOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqXG4gICAqIFRoZSBkYXRhc2V0J3MgaW1hZ2VkIHNlY3Rpb24gcG9zaXRpb25zLCBvciBudWxsIHdoZW4gaXRzIHogaXMgY29udGludW91cyByYXRoZXIgdGhhblxuICAgKiBzZWN0aW9uZWQuIFJlYWQgb25jZSBwZXIgZGF0YXNldCDigJQgdGhlIHNjYW4gd2Fsa3MgdGhlIHogb2YgZXZlcnkgb2JzZXJ2YXRpb24sIHNvIGl0XG4gICAqIG11c3Qgbm90IHNpdCBpbiBhIHRlbXBsYXRlIGdldHRlci5cbiAgICovXG4gIHByb3RlY3RlZCBzZWN0aW9uczogRmxvYXQzMkFycmF5IHwgbnVsbCA9IG51bGw7XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydjb250cm9scyddKSB7XG4gICAgICB0aGlzLmdlbmVGaWx0ZXJGYWlsZWQkID0gdGhpcy5jb250cm9scz8uZ2V0R2VuZUZpbHRlckZhaWxlZCQ/LigpID8/IG9mKGZhbHNlKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ2RhdGFzZXQnXSB8fCBjaGFuZ2VzWydjb250cm9scyddKSB7XG4gICAgICB0aGlzLmNvbHVtbk9wdGlvbnMgPSBjb2x1bW5PcHRpb25zKHRoaXMuZGF0YXNldCk7XG4gICAgICAvLyBBIG5ldyBkYXRhc2V0IGFsbW9zdCBjZXJ0YWlubHkgaGFzIGRpZmZlcmVudCBjb2x1bW5zOyBkcm9wIHN0YWxlIFVJIHN0YXRlLlxuICAgICAgdGhpcy5zZWxlY3RlZEdlbmUgPSBudWxsO1xuICAgICAgdGhpcy5zZWN0aW9ucyA9IHRoaXMuY29udHJvbHM/LnNhbXBsZWRTZWN0aW9ucygpID8/IG51bGw7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWyd2aWV3J10pIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRDb2x1bW4gPSB0aGlzLnZpZXcuY29sb3JCeT8ua2luZCA9PT0gJ2NvbHVtbicgPyB0aGlzLnZpZXcuY29sb3JCeS5uYW1lIDogbnVsbDtcbiAgICAgIHRoaXMuc2VsZWN0ZWRHZW5lID0gdGhpcy52aWV3LmNvbG9yQnk/LmtpbmQgPT09ICdmZWF0dXJlJyA/IHRoaXMudmlldy5jb2xvckJ5Lm5hbWUgOiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBjb2xvdXIgc291cmNlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBDb2x1bW4gZHJvcGRvd24uIENob29zaW5nIGEgY29sdW1uIHN1cGVyc2VkZXMgYW55IGdlbmUgc2VsZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25Db2x1bW4obmFtZTogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgIHRoaXMuc2VsZWN0ZWRDb2x1bW4gPSBuYW1lO1xuICAgIHRoaXMuc2VsZWN0ZWRHZW5lID0gbnVsbDtcbiAgICBpZiAoIW5hbWUpIHtcbiAgICAgIHRoaXMuY29udHJvbHM/LmNsZWFyQ29sb3JCeSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNvbnRyb2xzPy5jb2xvckJ5Q29sdW1uKG5hbWUpO1xuICB9XG5cbiAgLyoqIEEgZ2VuZSB3YXMgcGlja2VkOyBpdCBzdXBlcnNlZGVzIGFueSBjb2x1bW4gc2VsZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25HZW5lKG5hbWU6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGVkR2VuZSA9IG5hbWU7XG4gICAgaWYgKCFuYW1lKSB7XG4gICAgICB0aGlzLmNvbnRyb2xzPy5jbGVhckNvbG9yQnkoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zZWxlY3RlZENvbHVtbiA9IG51bGw7XG4gICAgdGhpcy5jb250cm9scz8uY29sb3JCeUZlYXR1cmUobmFtZSk7XG4gIH1cblxuICAvLyDilIDilIAgd2hpY2ggb2JzZXJ2YXRpb25zIGFyZSBkcmF3biDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogR2VuZXMgcGlja2VkIGZvciB0aGUgb2JzZXJ2YXRpb24gZmlsdGVyOyBub25lIGRyYXdzIGV2ZXJ5IG9ic2VydmF0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25PYnNlcnZhdGlvbkdlbmVzKGdlbmVzOiBzdHJpbmdbXSB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzOiBnZW5lcyA/PyBbXSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbk9ic2VydmF0aW9uR2VuZXNNYXRjaChtYXRjaDogU3BhdGlhbFZpZXdTdGF0ZVsnb2JzZXJ2YXRpb25HZW5lc01hdGNoJ10gfCBudWxsKTogdm9pZCB7XG4gICAgaWYgKCFtYXRjaCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IG9ic2VydmF0aW9uR2VuZXNNYXRjaDogbWF0Y2ggfSk7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGUgZ2VuZSBmaWx0ZXIgY291bGQgbm90IGJlIGFwcGxpZWQgKGFuIGV4cHJlc3Npb24gcmVhZCBmYWlsZWQpOyBvbmUgc3RyZWFtIHBlclxuICAgKiAgYGNvbnRyb2xzYCwgc28gdGhlIHRlbXBsYXRlJ3MgYXN5bmMgcGlwZSBrZWVwcyBpdHMgc3Vic2NyaXB0aW9uLiAqL1xuICBwcm90ZWN0ZWQgZ2VuZUZpbHRlckZhaWxlZCQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSBvZihmYWxzZSk7XG5cbiAgLyoqIEFzayBmb3IgdGhlIHBpY2tlZCBnZW5lcycgZXhwcmVzc2lvbiBhZ2FpbiAoYSBmYWlsZWQgcmVhZCBpcyBub3QgY2FjaGVkKS4gKi9cbiAgcHJvdGVjdGVkIHJldHJ5R2VuZUZpbHRlcigpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzOiBbLi4udGhpcy52aWV3Lm9ic2VydmF0aW9uR2VuZXNdIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uT2JzZXJ2YXRpb25HZW5lc0NvbG9yQnkob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzQ29sb3JCeTogb24gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVtb3ZlT2JzZXJ2YXRpb25HZW5lKGdlbmU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMub25PYnNlcnZhdGlvbkdlbmVzKHRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVzLmZpbHRlcigoZykgPT4gZyAhPT0gZ2VuZSkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGlzT2JzZXJ2YXRpb25HZW5lKGdlbmU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcub2JzZXJ2YXRpb25HZW5lcy5pbmNsdWRlcyhnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0cmFja0J5R2VuZShfaTogbnVtYmVyLCBnZW5lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBnZW5lO1xuICB9XG5cbiAgLy8g4pSA4pSAIGEgcGlja2VkIGdlbmUncyBpY29uIGFuZCBjb2xvdXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRoZSBnZW5lIHRoZSBpY29uIGFuZCBjb2xvdXIgcGlja2VyIGlzIG9wZW4gZm9yLiAqL1xuICBwcm90ZWN0ZWQgc3R5bGVHZW5lOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICBwcm90ZWN0ZWQgZ2VuZUNvbG9yT2YoZ2VuZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gb2JzZXJ2YXRpb25HZW5lQ29sb3IodGhpcy52aWV3LCBnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lR2x5cGhPZihnZW5lOiBzdHJpbmcpOiBUcmFuc2NyaXB0R2x5cGhOYW1lIHtcbiAgICByZXR1cm4gb2JzZXJ2YXRpb25HZW5lR2x5cGgodGhpcy52aWV3LCBnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnbHlwaFBvaW50c09mKGdlbmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGdseXBoUG9pbnRzKHRoaXMuZ2VuZUdseXBoT2YoZ2VuZSkpO1xuICB9XG5cbiAgLyoqIE9wZW4gdGhlIHBpY2tlciBvbiB0aGUgZ2VuZSdzIHN3YXRjaC4gSW5zaWRlIHRoZSBnZW5lcyBkcm9wZG93biB0aGUgY2xpY2sgbXVzdCBub3QgYWxzb1xuICAgKiAgcmVhY2ggdGhlIG9wdGlvbiwgd2hpY2ggd291bGQgdW5waWNrIHRoZSBnZW5lLiAqL1xuICBwcm90ZWN0ZWQgb3BlbkdlbmVTdHlsZShldmVudDogRXZlbnQsIGdlbmU6IHN0cmluZywgcGFuZWw6IHsgdG9nZ2xlKGU6IEV2ZW50KTogdm9pZDsgaGlkZSgpOiB2b2lkIH0pOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBpZiAodGhpcy5zdHlsZUdlbmUgPT09IGdlbmUpIHtcbiAgICAgIHBhbmVsLnRvZ2dsZShldmVudCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuc3R5bGVHZW5lID0gZ2VuZTtcbiAgICBwYW5lbC5oaWRlKCk7XG4gICAgLy8gUmUtb3BlbiBhbmNob3JlZCBvbiB0aGUgc3dhdGNoIHRoYXQgd2FzIGNsaWNrZWQsIG9uY2UgdGhlIHBhbmVsIGhhcyBjbG9zZWQuXG4gICAgc2V0VGltZW91dCgoKSA9PiBwYW5lbC50b2dnbGUoZXZlbnQpKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkdlbmVDb2xvcihnZW5lOiBzdHJpbmcsIGhleDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgb2JzZXJ2YXRpb25HZW5lQ29sb3JzOiB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVDb2xvcnMsIFtnZW5lXTogaGV4IH0gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25HZW5lR2x5cGgoZ2VuZTogc3RyaW5nLCBnbHlwaDogVHJhbnNjcmlwdEdseXBoTmFtZSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IG9ic2VydmF0aW9uR2VuZUdseXBoczogeyAuLi50aGlzLnZpZXcub2JzZXJ2YXRpb25HZW5lR2x5cGhzLCBbZ2VuZV06IGdseXBoIH0gfSk7XG4gIH1cblxuICAvKiogQmFjayB0byB0aGUgZ2VuZSdzIGRlZmF1bHQgY29sb3VyIChpdHMgcGxhY2UgaW4gdGhlIGxpc3QpIGFuZCBpY29uIChhIGNpcmNsZSkuICovXG4gIHByb3RlY3RlZCByZXNldEdlbmVTdHlsZShnZW5lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjb2xvcnMgPSB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVDb2xvcnMgfTtcbiAgICBjb25zdCBnbHlwaHMgPSB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVHbHlwaHMgfTtcbiAgICBkZWxldGUgY29sb3JzW2dlbmVdO1xuICAgIGRlbGV0ZSBnbHlwaHNbZ2VuZV07XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgb2JzZXJ2YXRpb25HZW5lQ29sb3JzOiBjb2xvcnMsIG9ic2VydmF0aW9uR2VuZUdseXBoczogZ2x5cGhzIH0pO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGZpbHRlciBoaWRlcywgaW4gd29yZHMuICovXG4gIHByb3RlY3RlZCBnZXQgZ2VuZUZpbHRlckhpbnQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBnZW5lcyA9IHRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVzO1xuICAgIGNvbnN0IHdoaWNoID1cbiAgICAgIGdlbmVzLmxlbmd0aCA9PT0gMVxuICAgICAgICA/IGdlbmVzWzBdXG4gICAgICAgIDogdGhpcy52aWV3Lm9ic2VydmF0aW9uR2VuZXNNYXRjaCA9PT0gJ2FsbCdcbiAgICAgICAgICA/ICdhbGwgb2YgdGhlc2UgZ2VuZXMnXG4gICAgICAgICAgOiAnYW55IG9mIHRoZXNlIGdlbmVzJztcbiAgICByZXR1cm4gKFxuICAgICAgYE9ubHkgb2JzZXJ2YXRpb25zIGV4cHJlc3NpbmcgJHt3aGljaH0gYXJlIGRyYXduOyB0aGUgb3RoZXJzIGFyZSBoaWRkZW4sIHdpdGggdGhlaXIgY2VsbCBvdXRsaW5lcyBhbmQgdGhlIGAgK1xuICAgICAgJ3RyYW5zY3JpcHRzIGFzc2lnbmVkIHRvIHRoZW0uIFRoZSB0cmFuc2NyaXB0IGRlbnNpdHkgbWFwLCBhbmQgdHJhbnNjcmlwdHMgZ3JvdXBlZCBieSBhcmVhIHdoZW4gem9vbWVkICcgK1xuICAgICAgJ291dCwgYXJlIGhpZGRlbiB3aGlsZSB0aGlzIGlzIG9uOiB0aGV5IGNhcnJ5IG5vIGNlbGxzIHRvIGZpbHRlciBieS4nXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBDZWxsIG91dGxpbmVzIG9uIG9mZmVyLCB3aGljaCBjaGFuZ2VzIHdoYXQgdGhlIGNpcmNsZXMgbWVhbi4gKi9cbiAgcHJvdGVjdGVkIGdldCBoYXNDZWxscygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISEodGhpcy5kYXRhc2V0Py5wb2x5Z29uVGlsZXMgfHwgdGhpcy5kYXRhc2V0Py5wb2x5Z29ucyk7XG4gIH1cblxuICAvKiogVHJ1ZSB3aGlsZSBhIHNlbGVjdGlvbiBpcyBhY3RpdmUg4oCUIGV2ZXJ5dGhpbmcgZWxzZSByZW5kZXJzIG11dGVkLiAqL1xuICBnZXQgaGFzU2VsZWN0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGlvbi5jb3VudCA+IDA7XG4gIH1cblxuICAvKiogV2hldGhlciBsb2cvY2xpcCBhcHBseSDigJQgdGhleSBhcmUgY29udGludW91cy1vbmx5IGtub2JzLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGlzQ29udGludW91cygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLnZpZXcuY29sb3JCeSAmJiB0aGlzLmxlZ2VuZCA9PT0gbnVsbDtcbiAgfVxuXG4gIC8vIOKUgOKUgCBkaXNwbGF5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8vIFByaW1lTkcncyBzbGlkZXIgcmVwb3J0cyBgbnVtYmVyIHwgdW5kZWZpbmVkYDsgaWdub3JlIHRoZSBlbXB0eSBjYXNlIHJhdGhlclxuICAvLyB0aGFuIHdyaXRpbmcgYHVuZGVmaW5lZGAgaW50byB0aGUgc3RvcmUgYW5kIHJlbmRlcmluZyBOYU4tc2l6ZWQgbWFya2Vycy5cbiAgcHJvdGVjdGVkIG9uUG9pbnRTY2FsZSh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBwb2ludFNjYWxlOiB2YWx1ZSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25PcGFjaXR5KHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IG9wYWNpdHk6IHZhbHVlIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbkxvZ1NjYWxlKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgbG9nU2NhbGU6IG9uIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbkdlbmVNYXAob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwOiBvbiB9KTtcbiAgfVxuICAvKiogM0Q6IHNtb290aCB0aGUgcGVyLXNlY3Rpb24gc2hlZXRzIGFsb25nIHogaW50byBhIGNvbnRpbnVvdXMgdm9sdW1lLiAqL1xuICBwcm90ZWN0ZWQgb25HZW5lTWFwVm9sdW1lKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcFZvbHVtZTogb24gfSk7XG4gIH1cbiAgLyoqIDNEOiByZXN0cmljdCB0aGUgc2hlZXRzIHRvIG9uZSBpbWFnZWQgc2VjdGlvbi4gKi9cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcE9uZVNlY3Rpb24ob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoIW9uKSB7XG4gICAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwU2VjdGlvbjogbnVsbCB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcFNlY3Rpb246IG1pZGRsZVNlY3Rpb24odGhpcy5zZWN0aW9ucykgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcFNlY3Rpb24odmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcFNlY3Rpb246IHZhbHVlIH0pO1xuICB9XG4gIHByb3RlY3RlZCBnZXQgZ2VuZU1hcE9uZVNlY3Rpb24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMudmlldy5nZW5lTWFwU2VjdGlvbiAhPSBudWxsO1xuICB9XG4gIC8qKiBcIjEyIG9mIDUzXCIgZm9yIHRoZSBnZW5lIG1hcCdzIG93biBzZWN0aW9uLCAxLWJhc2VkIGxpa2UgdGhlIGNsb3VkJ3MuICovXG4gIHByb3RlY3RlZCBnZXQgZ2VuZU1hcFNlY3Rpb25MYWJlbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBzZWN0aW9uTGFiZWwodGhpcy5zZWN0aW9ucywgdGhpcy52aWV3LmdlbmVNYXBTZWN0aW9uKTtcbiAgfVxuICBwcm90ZWN0ZWQgb25HZW5lTWFwU21vb3RoaW5nKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBTbW9vdGhpbmc6IHZhbHVlIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbkdlbmVNYXBPcGFjaXR5KHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBPcGFjaXR5OiB2YWx1ZSB9KTtcbiAgfVxuICAvKipcbiAgICogV2hhdCB0aGUgM0QgZ2VuZSBtYXAgaXMgY3VycmVudGx5IHNob3dpbmcsIHNhaWQgcGxhaW5seSDigJQgdGhlIHNoZWV0cyBhcmUgYVxuICAgKiBtZWFzdXJlbWVudCBhbmQgdGhlIHZvbHVtZSBpcyBhbiBlc3RpbWF0ZSwgYW5kIHRoZSBwYW5lbCBoYXMgdG8gYmUgdGhlIHBsYWNlXG4gICAqIHRoYXQgc2F5cyB3aGljaCBvbmUgaXMgb24gc2NyZWVuLlxuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBnZW5lTWFwVm9sdW1lTm90ZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IHRvdGFsID0gdGhpcy5zZWN0aW9ucz8ubGVuZ3RoID8/IDA7XG4gICAgaWYgKHRoaXMudmlldy5nZW5lTWFwVm9sdW1lKSB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICAnSW50ZXJwb2xhdGVkIGFsb25nIHo6IHRoZSBwbGFuZXMgYmV0d2VlbiB0aGUgaW1hZ2VkIHNlY3Rpb25zIGNhcnJ5IGFuICcgK1xuICAgICAgICBcIkVTVElNQVRFLCBzbW9vdGhlZCBmcm9tIHRoZWlyIG5laWdoYm91cnMnIG1lYW4uIE5vdGhpbmcgaXMgZHJhd24gYmV5b25kIHRoZSBcIiArXG4gICAgICAgICdvdXRlcm1vc3Qgc2VjdGlvbi4nXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodGhpcy5nZW5lTWFwT25lU2VjdGlvbikge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgXCJPbmUgaW1hZ2VkIHNlY3Rpb24ncyBmaWVsZCDigJQgbWVhc3VyZWQsIG5vdCBpbnRlcnBvbGF0ZWQuIEhpZGUgdGhlIFwiICtcbiAgICAgICAgJ29ic2VydmF0aW9ucyB0byByZWFkIGl0LCBvciBsZWF2ZSB0aGVtIG9uIHRvIGNoZWNrIHRoZSBmaWVsZCBhZ2FpbnN0IHRoZW0uJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIChcbiAgICAgIGBPbmUgZmllbGQgcGVyIGltYWdlZCBzZWN0aW9uJHt0b3RhbCA/IGAgKCR7dG90YWx9KWAgOiAnJ30sIGF0IGl0cyBvd24gZGVwdGgsIGAgK1xuICAgICAgJ3dpdGggdGhlIGdhcHMgYmV0d2VlbiBzZWN0aW9ucyBlbXB0eS4gS2VybmVsLXdlaWdodGVkIG1lYW4gcGVyIGNlbGwsIG5vdCBhIHN1bS4nXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBUcnVlIHdoaWxlIGEgZ2VuZSBpcyB0aGUgY29sb3VyIHNvdXJjZSDigJQgdGhlIG9ubHkgdGhpbmcgYSBnZW5lIG1hcCBjYW4gbWFwLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGNhbk1hcEdlbmUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMudmlldy5jb2xvckJ5Py5raW5kID09PSAnZmVhdHVyZSc7XG4gIH1cblxuICAvLyDilIDilIAgd2hhdCB0aGUgM0Qgc2NlbmUgZHJhd3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIFRoZSB2b2x1bWUsIHRoZSBjbG91ZCBhbmQgdGhlIGRlbnNpdHkgdm9sdW1lcyBzaGFyZSBvbmUgc3BhY2UsIHNvIGVhY2ggb25lXG4gIC8vIGhpZGVzIHRoZSBvdGhlcnMgdG8gc29tZSBkZWdyZWUuIEluZGVwZW5kZW50IHRvZ2dsZXMgYmVjYXVzZSB0aGUgdXNlZnVsIHZpZXdzXG4gIC8vIGFyZSB0aGUgY29tYmluYXRpb25zLCBub3QgYSBzaW5nbGUgXCIzRCBtb2RlXCIuXG5cbiAgcHJvdGVjdGVkIG9uU2hvd1ZvbHVtZShvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHNob3dWb2x1bWU6IG9uIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvblZvbHVtZU9wYWNpdHkodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgdm9sdW1lT3BhY2l0eTogdmFsdWUgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uU2hvd1BvaW50cyhvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHNob3dQb2ludHM6IG9uIH0pO1xuICB9XG4gIC8qKiBUaGUgXCJvbmUgc2VjdGlvbiBhdCBhIHRpbWVcIiBzd2l0Y2g6IG51bGwgcmVzdG9yZXMgdGhlIHdob2xlIHN0YWNrLiAqL1xuICBwcm90ZWN0ZWQgb25PbmVTZWN0aW9uKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKCFvbikge1xuICAgICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgcG9pbnRTZWN0aW9uOiBudWxsIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBPcGVuIGluIHRoZSBtaWRkbGUgb2YgdGhlIHN0YWNrIHJhdGhlciB0aGFuIG9uIHRoZSBmaXJzdCBzZWN0aW9uLCB3aGljaCBmb3JcbiAgICAvLyBhIGJyYWluIGlzIGEgbmVhcmx5IGVtcHR5IG9sZmFjdG9yeS1idWxiIHNsaWRlLlxuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHBvaW50U2VjdGlvbjogbWlkZGxlU2VjdGlvbih0aGlzLnNlY3Rpb25zKSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25Qb2ludFNlY3Rpb24odmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgcG9pbnRTZWN0aW9uOiB2YWx1ZSB9KTtcbiAgfVxuICAvKiogVHJ1ZSB3aGlsZSB0aGUgY2xvdWQgaXMgcmVzdHJpY3RlZCB0byBhIHNpbmdsZSBzZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IG9uZVNlY3Rpb24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMudmlldy5wb2ludFNlY3Rpb24gIT0gbnVsbDtcbiAgfVxuICAvKiogSGlnaGVzdCBzZWN0aW9uIGluZGV4IHRoZSBzbGlkZXIgY2FuIHJlYWNoLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGxhc3RTZWN0aW9uKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIE1hdGgubWF4KDAsICh0aGlzLnNlY3Rpb25zPy5sZW5ndGggPz8gMSkgLSAxKTtcbiAgfVxuICAvKiogXCIxMiBvZiA1M1wiIOKAlCAxLWJhc2VkLCBiZWNhdXNlIHRoZSBzZWN0aW9ucyBhcmUgc2xpZGVzLCBub3QgYXJyYXkgc2xvdHMuICovXG4gIHByb3RlY3RlZCBnZXQgc2VjdGlvbkxhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHNlY3Rpb25MYWJlbCh0aGlzLnNlY3Rpb25zLCB0aGlzLnZpZXcucG9pbnRTZWN0aW9uKTtcbiAgfVxuICAvKiogV2hldGhlciB0aGlzIGRhdGFzZXQgaGFzIHNlY3Rpb25zIHRvIHBpY2sgZnJvbSBhdCBhbGwuICovXG4gIHByb3RlY3RlZCBnZXQgaXNTZWN0aW9uZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICh0aGlzLnNlY3Rpb25zPy5sZW5ndGggPz8gMCkgPiAxO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uRGVuc2l0eVZvbHVtZShvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGRlbnNpdHlWb2x1bWU6IG9uIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbkRlbnNpdHlTbW9vdGhpbmcodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZGVuc2l0eVNtb290aGluZzogdmFsdWUgfSk7XG4gIH1cblxuICAvKiogV2hhdCB0aGUgZGVuc2l0eSB2b2x1bWVzIGFyZSBhY3R1YWxseSBzaG93aW5nLCBzYWlkIHBsYWlubHkg4oCUIGFuIGVzdGltYXRlIGlzXG4gICAqICBvbmx5IGhvbmVzdCBpZiB0aGUgcmVhZGVyIGtub3dzIGl0IGlzIG9uZSwgYW5kIHdoaWNoIGNsdXN0ZXJzIGFyZSBpbiB2aWV3LiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGRlbnNpdHlOb3RlKCk6IHN0cmluZyB7XG4gICAgY29uc3QgY2FwcGVkID0gYHRoZSAke1NwYXRpYWxPYnNlcnZhdGlvbnNQYW5lbENvbXBvbmVudC5ERU5TSVRZX01BWF9DTFVTVEVSU30gbGFyZ2VzdCBjbHVzdGVyc2A7XG4gICAgY29uc3Qgd2hhdCA9IHRoaXMubGVnZW5kID8gY2FwcGVkIDogdGhpcy5oYXNTZWxlY3Rpb24gPyAndGhlIHNlbGVjdGVkIGNlbGxzJyA6ICdhbGwgY2VsbHMnO1xuICAgIHJldHVybiAoXG4gICAgICBgRGVuc2l0eSBlc3RpbWF0ZSBvdmVyICR7d2hhdH0g4oCUIHNtb290aGVkIGJldHdlZW4gdGhlIGltYWdlZCBzZWN0aW9ucywgYCArXG4gICAgICAnbm90IG1lYXN1cmVkIGNlbGxzLiBMb3dlciBPcGFjaXR5IHRvIHJlYWQgdGhlIGZpZWxkcyB1bmRlciB0aGUgY2xvdWQuJ1xuICAgICk7XG4gIH1cblxuICAvKiogTWlycm9ycyB0aGUgcmVuZGVyZXIncyBjYXAsIGZvciB0aGUgbm90ZSBvbmx5LiAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBERU5TSVRZX01BWF9DTFVTVEVSUyA9IDY7XG4gIHByb3RlY3RlZCBvbkNsaXAodmFsdWU6IFtudW1iZXIsIG51bWJlcl0pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBwZXJjZW50aWxlQ2xpcDogdmFsdWUgfSk7XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXIgKm5nSWY9XCJkYXRhc2V0IGFzIGRzXCI+XG4gIDwhLS0gT2JzZXJ2YXRpb25zOiBvbmUgbWFya2VyIHBlciBvYnNlcnZhdGlvbiAoY2VsbCBjZW50cm9pZCwgVmlzaXVtIHNwb3QpLCBhbmQgd2hhdFxuICAgICBjb2xvdXJzIHRoZW0uIFRoZSBsZWFkIHNlY3Rpb24gZm9yIGRhdGFzZXRzIHdpdGhvdXQgY2VsbCBvdXRsaW5lcy4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1wYW5lbFwiIFtjbGFzcy5vcGVuXT1cIm9wZW5cIj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtcGFuZWwtaGVhZFwiIChjbGljayk9XCJvcGVuQ2hhbmdlLmVtaXQoIW9wZW4pXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnNob3dQb2ludHNcIlxuICAgICAgICAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uU2hvd1BvaW50cygkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtcGFuZWwtdGl0bGVcIj5PYnNlcnZhdGlvbnM8L3NwYW4+XG4gICAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWNoZXZyb24tZG93bl09XCJvcGVuXCIgW2NsYXNzLnBpLWNoZXZyb24tcmlnaHRdPVwiIW9wZW5cIj48L2k+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXBhbmVsLWJvZHlcIiAqbmdJZj1cIm9wZW5cIj5cbiAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cImhhc0NlbGxzICYmICFpczNkXCI+XG4gICAgICAgIE9uZSBjaXJjbGUgcGVyIGNlbGwsIGF0IGV2ZXJ5IHpvb20uIENlbGwgb3V0bGluZXMgYXJlIGRyYXduIG92ZXIgdGhlIGNpcmNsZXMgb25jZSBjZWxscyBhcmUgYmlnIGVub3VnaCBvblxuICAgICAgICBzY3JlZW4gdG8gb3V0bGluZS5cbiAgICAgIDwvc21hbGw+XG4gICAgICA8IS0tIENvbG91ciBzb3VyY2UuIENvbHVtbiBhbmQgZ2VuZSBhcmUgbXV0dWFsbHkgZXhjbHVzaXZlOiBwaWNraW5nIG9uZVxuICAgICBjbGVhcnMgdGhlIG90aGVyLCBzbyB3aGF0IGRyaXZlcyB0aGUgY29sb3VycyBpcyBuZXZlciBhbWJpZ3VvdXMuIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2MtY29sdW1uXCI+Q29sb3VyIGJ5IGNvbHVtbjwvbGFiZWw+XG4gICAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgICAgaW5wdXRJZD1cInNjLWNvbHVtblwiXG4gICAgICAgICAgW29wdGlvbnNdPVwiY29sdW1uT3B0aW9uc1wiXG4gICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgW25nTW9kZWxdPVwic2VsZWN0ZWRDb2x1bW5cIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ29sdW1uKCRldmVudClcIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwiTm9uZSAoZmxhdCBjb2xvdXIpXCJcbiAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1mdWxsXCJcbiAgICAgICAgPjwvcC1kcm9wZG93bj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZ2VuZXM/LnN0YXRlJCB8IGFzeW5jIGFzIGdlbmVcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImRzLmZlYXR1cmVzXCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2MtZ2VuZVwiPkNvbG91ciBieSBnZW5lPC9sYWJlbD5cbiAgICAgICAgICA8IS0tIEEgZmlsdGVyYWJsZSBkcm9wZG93biwgbm90IGEgZnJlZS10ZXh0IGJveDogdGhlIGdlbmVzIGFyZSB2aXNpYmxlIGJlZm9yZVxuICAgICAgIGFueXRoaW5nIGlzIHR5cGVkLCBhbmQgZWFjaCBrZXlzdHJva2UgbmFycm93cyBhIGxpc3QgdGhlIHVzZXIgY2FuIHNlZS5cbiAgICAgICBWaXJ0dWFsLXNjcm9sbGVkIGJlY2F1c2UgYSB0YXJnZXRlZCBwYW5lbCBydW5zIHRvIGEgZmV3IHRob3VzYW5kIG5hbWVzLiAtLT5cbiAgICAgICAgICA8cC1kcm9wZG93blxuICAgICAgICAgICAgaW5wdXRJZD1cInNjLWdlbmVcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwiZ2VuZS5vcHRpb25zXCJcbiAgICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJzZWxlY3RlZEdlbmVcIlxuICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25HZW5lKCRldmVudClcIlxuICAgICAgICAgICAgW2ZpbHRlcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIGZpbHRlckJ5PVwibGFiZWxcIlxuICAgICAgICAgICAgW3Jlc2V0RmlsdGVyT25IaWRlXT1cInRydWVcIlxuICAgICAgICAgICAgKG9uRmlsdGVyKT1cImdlbmVzPy5vbkZpbHRlcigkZXZlbnQuZmlsdGVyKVwiXG4gICAgICAgICAgICAob25TaG93KT1cImdlbmVzPy5lbnN1cmVMaXN0KClcIlxuICAgICAgICAgICAgW3Nob3dDbGVhcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIFt2aXJ0dWFsU2Nyb2xsXT1cImdlbmUub3B0aW9ucy5sZW5ndGggPiBnZW5lVmlydHVhbFNjcm9sbEZyb21cIlxuICAgICAgICAgICAgW3ZpcnR1YWxTY3JvbGxJdGVtU2l6ZV09XCIzMFwiXG4gICAgICAgICAgICBbZW1wdHlGaWx0ZXJNZXNzYWdlXT1cImdlbmUucmVtb3RlID8gJ05vIG1hdGNoIOKAlCBrZWVwIHR5cGluZycgOiAnTm8gbWF0Y2gnXCJcbiAgICAgICAgICAgIFtlbXB0eU1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnVHlwZSB0byBzZWFyY2ggZ2VuZXMnIDogJ05vIGdlbmVzJ1wiXG4gICAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJTZWFyY2gge3sgZHMuZmVhdHVyZXMuY291bnQgfCBudW1iZXIgfX0gZ2VuZXPigKZcIlxuICAgICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWZ1bGxcIlxuICAgICAgICAgID48L3AtZHJvcGRvd24+XG4gICAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiZ2VuZS5mYWlsZWRcIj5HZW5lIGxvb2t1cCBmYWlsZWQuPC9zbWFsbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBXaGljaCBvYnNlcnZhdGlvbnMgYXJlIGRyYXduIGF0IGFsbCwgYnkgd2hhdCB0aGV5IGV4cHJlc3MuIFNldmVyYWwgZ2VuZXMgYXRcbiAgICAgICBvbmNlLCB1bmxpa2UgdGhlIGNvbG91ciwgd2hpY2ggcmVhZHMgb25lOiBwaWNraW5nIGdlbmVzIGhlcmUgaGlkZXMgZXZlcnlcbiAgICAgICBvYnNlcnZhdGlvbiB0aGF0IGV4cHJlc3NlcyBub25lIG9mIHRoZW0gKG9yIG5vdCBhbGwgb2YgdGhlbSksIGFuZCBieSBkZWZhdWx0XG4gICAgICAgY29sb3VycyAoYW5kLCBpbiAyRCwgbWFya3MpIGVhY2ggZHJhd24gb25lIGJ5IGl0cyBnZW5lLiAtLT5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImRzLmZlYXR1cmVzXCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwic2MtbGJsXCIgZm9yPVwic2Mtc2hvdy1nZW5lc1wiPlNob3cgb2JzZXJ2YXRpb25zIGV4cHJlc3Npbmc8L2xhYmVsPlxuICAgICAgICAgIDxwLW11bHRpU2VsZWN0XG4gICAgICAgICAgICBpbnB1dElkPVwic2Mtc2hvdy1nZW5lc1wiXG4gICAgICAgICAgICBbb3B0aW9uc109XCJnZW5lLm9wdGlvbnNcIlxuICAgICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcub2JzZXJ2YXRpb25HZW5lc1wiXG4gICAgICAgICAgICAob25DaGFuZ2UpPVwib25PYnNlcnZhdGlvbkdlbmVzKCRldmVudC52YWx1ZSlcIlxuICAgICAgICAgICAgW2ZpbHRlcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIGZpbHRlckJ5PVwibGFiZWxcIlxuICAgICAgICAgICAgW3Jlc2V0RmlsdGVyT25IaWRlXT1cInRydWVcIlxuICAgICAgICAgICAgKG9uRmlsdGVyKT1cImdlbmVzPy5vbkZpbHRlcigkZXZlbnQuZmlsdGVyKVwiXG4gICAgICAgICAgICAob25QYW5lbFNob3cpPVwiZ2VuZXM/LmVuc3VyZUxpc3QoKVwiXG4gICAgICAgICAgICBbdmlydHVhbFNjcm9sbF09XCJnZW5lLm9wdGlvbnMubGVuZ3RoID4gZ2VuZVZpcnR1YWxTY3JvbGxGcm9tXCJcbiAgICAgICAgICAgIFt2aXJ0dWFsU2Nyb2xsSXRlbVNpemVdPVwiMzBcIlxuICAgICAgICAgICAgW3Nob3dUb2dnbGVBbGxdPVwiZmFsc2VcIlxuICAgICAgICAgICAgW3Nob3dDbGVhcl09XCJ0cnVlXCJcbiAgICAgICAgICAgIFtlbXB0eUZpbHRlck1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnTm8gbWF0Y2gg4oCUIGtlZXAgdHlwaW5nJyA6ICdObyBtYXRjaCdcIlxuICAgICAgICAgICAgW2VtcHR5TWVzc2FnZV09XCJnZW5lLnJlbW90ZSA/ICdUeXBlIHRvIHNlYXJjaCBnZW5lcycgOiAnTm8gZ2VuZXMnXCJcbiAgICAgICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cIkFueSBnZW5lIChldmVyeSBvYnNlcnZhdGlvbilcIlxuICAgICAgICAgICAgW3NlbGVjdGVkSXRlbXNMYWJlbF09XCInezB9IGdlbmVzJ1wiXG4gICAgICAgICAgICBbbWF4U2VsZWN0ZWRMYWJlbHNdPVwiM1wiXG4gICAgICAgICAgICBzdHlsZUNsYXNzPVwic2MtZnVsbFwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPCEtLSBBIHBpY2tlZCBnZW5lIHNob3dzIGl0cyBpY29uIGluIGl0cyBjb2xvdXI7IGNsaWNraW5nIGl0IGVkaXRzIHRoZW0uIC0tPlxuICAgICAgICAgICAgPG5nLXRlbXBsYXRlIGxldC1vcHRpb24gcFRlbXBsYXRlPVwiaXRlbVwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtb2JzLWdlbmUtb3B0aW9uXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1vYnMtZ2VuZS1uYW1lXCI+e3sgb3B0aW9uLmxhYmVsIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpc09ic2VydmF0aW9uR2VuZShvcHRpb24udmFsdWUpXCI+XG4gICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiZ2VuZU1hcms7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBvcHRpb24udmFsdWUgfVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPC9wLW11bHRpU2VsZWN0PlxuICAgICAgICAgIDxwLXNlbGVjdEJ1dHRvblxuICAgICAgICAgICAgKm5nSWY9XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXMubGVuZ3RoID4gMVwiXG4gICAgICAgICAgICBbb3B0aW9uc109XCJtYXRjaE9wdGlvbnNcIlxuICAgICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcub2JzZXJ2YXRpb25HZW5lc01hdGNoXCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uT2JzZXJ2YXRpb25HZW5lc01hdGNoKCRldmVudClcIlxuICAgICAgICAgICAgW2FsbG93RW1wdHldPVwiZmFsc2VcIlxuICAgICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWJ1dHRvbnNcIlxuICAgICAgICAgID48L3Atc2VsZWN0QnV0dG9uPlxuICAgICAgICAgIDwhLS0gVGhlIHBpY2tlZCBnZW5lczogZWFjaCBvbmUncyBpY29uIGFuZCBjb2xvdXIgKGNsaWNrIHRvIGVkaXQpLCBhbmQgYSB3YXkgb3V0LiAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtb2JzLWdlbmVzXCIgKm5nSWY9XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXMubGVuZ3RoXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtb2JzLWdlbmUtcm93XCIgKm5nRm9yPVwibGV0IGcgb2Ygdmlldy5vYnNlcnZhdGlvbkdlbmVzOyB0cmFja0J5OiB0cmFja0J5R2VuZVwiPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiZ2VuZU1hcms7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBnIH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1vYnMtZ2VuZS1uYW1lXCI+e3sgZyB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwic2MtaWNvbi1idG5cIlxuICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ1N0b3Agc2hvd2luZyAnICsgZ1wiXG4gICAgICAgICAgICAgICAgcFRvb2x0aXA9XCJSZW1vdmVcIlxuICAgICAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInJlbW92ZU9ic2VydmF0aW9uR2VuZShnKVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8aSBjbGFzcz1cInBpIHBpLXRpbWVzXCI+PC9pPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGhcIj5cbiAgICAgICAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcub2JzZXJ2YXRpb25HZW5lc0NvbG9yQnlcIlxuICAgICAgICAgICAgICAob25DaGFuZ2UpPVwib25PYnNlcnZhdGlvbkdlbmVzQ29sb3JCeSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICAgICAgICBsYWJlbD1cIkNvbG91ciBieSB0aGVzZSBnZW5lc1wiXG4gICAgICAgICAgICAgIHBUb29sdGlwPVwiRWFjaCBvYnNlcnZhdGlvbiBpbiB0aGUgY29sb3VyIChhbmQsIGluIDJELCB0aGUgaWNvbikgb2YgdGhlIHBpY2tlZCBnZW5lIGl0IGV4cHJlc3NlcyBtb3N0LCByZWxhdGl2ZSB0byB0aGF0IGdlbmUncyBoaWdoZXN0IHZhbHVlLiBPZmYsIENvbG91ciBieSBjb2x1bW4gb3IgZ2VuZSBhcHBsaWVzLlwiXG4gICAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgICAgICA+PC9wLWNoZWNrYm94PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGhcIj57eyBnZW5lRmlsdGVySGludCB9fTwvc21hbGw+XG4gICAgICAgICAgPCEtLSBUaGUgZmlsdGVyIGlzIG5ldmVyIGRyb3BwZWQgc2lsZW50bHk6IGEgZmFpbGVkIGV4cHJlc3Npb24gcmVhZCBrZWVwcyB0aGUgb2JzZXJ2YXRpb25zXG4gICAgICAgICAgICAgICBhcyB0aGV5IHdlcmUgZHJhd24sIGFuZCBzYXlzIHNvLiAtLT5cbiAgICAgICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50IHNjLWVycm9yXCIgKm5nSWY9XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXMubGVuZ3RoICYmIChnZW5lRmlsdGVyRmFpbGVkJCB8IGFzeW5jKVwiPlxuICAgICAgICAgICAgVGhlIGV4cHJlc3Npb24gb2YgdGhlIHBpY2tlZCBnZW5lcyBjb3VsZCBub3QgYmUgcmVhZCwgc28gdGhlIG9ic2VydmF0aW9ucyBzdGlsbCBzaG93IHRoZSBwcmV2aW91c1xuICAgICAgICAgICAgZmlsdGVyLlxuICAgICAgICAgICAgPGEgaHJlZj1cIlwiIChjbGljayk9XCIkZXZlbnQucHJldmVudERlZmF1bHQoKTsgcmV0cnlHZW5lRmlsdGVyKClcIj5UcnkgYWdhaW48L2E+XG4gICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPHNwYXRpYWwta2V5XG4gICAgICAgIFtjb250cm9sc109XCJjb250cm9sc1wiXG4gICAgICAgIFtkYXRhc2V0XT1cImRzXCJcbiAgICAgICAgW3ZpZXddPVwidmlld1wiXG4gICAgICAgIFtsZWdlbmRdPVwibGVnZW5kXCJcbiAgICAgICAgW2NvbG9yQmFyQ3NzXT1cImNvbG9yQmFyQ3NzXCJcbiAgICAgICAgW3NlbGVjdGVkQ2F0ZWdvcnldPVwic2VsZWN0ZWRDYXRlZ29yeVwiXG4gICAgICAgIFtjb2xvcm1hcE9wdGlvbnNdPVwiY29sb3JtYXBPcHRpb25zXCJcbiAgICAgICAgKGNhdGVnb3J5Q2xpY2tlZCk9XCJjYXRlZ29yeUNsaWNrZWQuZW1pdCgkZXZlbnQpXCJcbiAgICAgID48L3NwYXRpYWwta2V5PlxuXG4gICAgICA8IS0tIERpc3BsYXkgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5Qb2ludCBzaXplPC9zcGFuPlxuICAgICAgICAgIDxwLXNsaWRlclxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5wb2ludFNjYWxlXCJcbiAgICAgICAgICAgIFttaW5dPVwiMC4yNVwiXG4gICAgICAgICAgICBbbWF4XT1cIjVcIlxuICAgICAgICAgICAgW3N0ZXBdPVwiMC4yNVwiXG4gICAgICAgICAgICAob25DaGFuZ2UpPVwib25Qb2ludFNjYWxlKCRldmVudC52YWx1ZSlcIlxuICAgICAgICAgID48L3Atc2xpZGVyPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5wb2ludFNjYWxlIH19w5c8L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5PcGFjaXR5PC9zcGFuPlxuICAgICAgICAgIDxwLXNsaWRlclxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5vcGFjaXR5XCJcbiAgICAgICAgICAgIFttaW5dPVwiMC4xXCJcbiAgICAgICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgICAgICBbc3RlcF09XCIwLjA1XCJcbiAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvbk9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3Lm9wYWNpdHkgfX08L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gT25seSBmb3IgYSBnZW5lOiB0aGUgbWFwIGRyYXdzIHRoYXQgZ2VuZSdzIGV4cHJlc3Npb24gYXMgYSBmaWVsZC4gSW4gMkRcbiAgICAgaXQgZ29lcyB1bmRlciB0aGUgY2VsbHMgb2YgdGhlIGRpc3BsYXllZCBwbGFuZTsgaW4gM0QgaXQgaXMgb25lIHNoZWV0IHBlclxuICAgICBpbWFnZWQgc2VjdGlvbiwgb3B0aW9uYWxseSBzbW9vdGhlZCBhbG9uZyB6IGludG8gYSB2b2x1bWUuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiY2FuTWFwR2VuZVwiPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXAoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJHZW5lIG1hcCAoZXhwcmVzc2lvbiBmaWVsZClcIlxuICAgICAgICBbcFRvb2x0aXBdPVwiXG4gICAgICAgICAgaXMzZFxuICAgICAgICAgICAgPyAnRHJhdyB0aGlzIGdlbmVcXCdzIGV4cHJlc3Npb24gYXMgb25lIGZpZWxkIHBlciBpbWFnZWQgc2VjdGlvbiDigJQgYW4gZXN0aW1hdGUgYmV0d2VlbiB0aGUgY2VsbHMsIGVtcHR5IHdoZXJlIG5vdGhpbmcgd2FzIG1lYXN1cmVkJ1xuICAgICAgICAgICAgOiAnRHJhdyB0aGlzIGdlbmVcXCdzIGV4cHJlc3Npb24gYXMgYSBzbW9vdGggZmllbGQgVU5ERVIgdGhlIGNlbGxzIOKAlCBhbiBlc3RpbWF0ZSBiZXR3ZWVuIHRoZW0sIHRyYW5zcGFyZW50IHdoZXJlIG5vdGhpbmcgd2FzIG1lYXN1cmVkJ1xuICAgICAgICBcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIDNEIG9ubHk6IGludGVycG9sYXRpbmcgYWxvbmcgeiB0dXJucyB0aGUgbWVhc3VyZWQgc2hlZXRzIGludG8gYW5cbiAgICAgICBlc3RpbWF0ZSwgc28gaXQgaXMgaXRzIG93biBkZWNpc2lvbiBhbmQgaXRzIG93biBsYWJlbC4gLS0+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2RcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFZvbHVtZVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBWb2x1bWUoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJWb2x1bWUgcmVuZGVyaW5nIChpbnRlcnBvbGF0ZSBhbG9uZyB6KVwiXG4gICAgICAgIHBUb29sdGlwPVwiU21vb3RoIHRoZSBwZXItc2VjdGlvbiBmaWVsZHMgaW50byBhIGNvbnRpbnVvdXMgdm9sdW1lIOKAlCBhbiBFU1RJTUFURSBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMsIG5vdCBtZWFzdXJlZCB0aXNzdWVcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIE1lYW5pbmdsZXNzIHdoaWxlIGludGVycG9sYXRpbmc6IGEgdm9sdW1lIGJ1aWx0IGZyb20gb25lIHNlY3Rpb24gd291bGRcbiAgICAgICBzbWVhciB0aGF0IHNsaWRlIHRocm91Z2ggdGhlIHNwZWNpbWVuJ3Mgd2hvbGUgZGVwdGguIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiBpczNkICYmIGlzU2VjdGlvbmVkICYmICF2aWV3LmdlbmVNYXBWb2x1bWVcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cImdlbmVNYXBPbmVTZWN0aW9uXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcE9uZVNlY3Rpb24oJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJPbmUgbWFwIHNlY3Rpb24gYXQgYSB0aW1lXCJcbiAgICAgICAgcFRvb2x0aXA9XCJEcmF3IGEgc2luZ2xlIGltYWdlZCBzZWN0aW9uJ3MgZmllbGQgaW5zdGVhZCBvZiB0aGUgd2hvbGUgc3RhY2sgb2Ygc2hlZXRzXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2QgJiYgaXNTZWN0aW9uZWQgJiYgIXZpZXcuZ2VuZU1hcFZvbHVtZSAmJiBnZW5lTWFwT25lU2VjdGlvblwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5NYXAgc2VjdGlvbjwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBTZWN0aW9uXCJcbiAgICAgICAgW21pbl09XCIwXCJcbiAgICAgICAgW21heF09XCJsYXN0U2VjdGlvblwiXG4gICAgICAgIFtzdGVwXT1cIjFcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwU2VjdGlvbigkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyBnZW5lTWFwU2VjdGlvbkxhYmVsIH19PC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcFwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TbW9vdGhpbmc8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwU21vb3RoaW5nXCJcbiAgICAgICAgW21pbl09XCIwLjVcIlxuICAgICAgICBbbWF4XT1cIjRcIlxuICAgICAgICBbc3RlcF09XCIwLjVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwU21vb3RoaW5nKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcuZ2VuZU1hcFNtb290aGluZyB9fcOXPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcFwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5NYXAgb3BhY2l0eTwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBPcGFjaXR5XCJcbiAgICAgICAgW21pbl09XCIwLjFcIlxuICAgICAgICBbbWF4XT1cIjFcIlxuICAgICAgICBbc3RlcF09XCIwLjA1XCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcE9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5nZW5lTWFwT3BhY2l0eSB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmICFpczNkXCI+XG4gICAgICBLZXJuZWwtd2VpZ2h0ZWQgbWVhbiBwZXIgY2VsbCwgbm90IGEgc3VtIOKAlCBzbyBhIGNyb3dkZWQgcmVnaW9uIGRvZXMgbm90IGdsb3cgZm9yIGJlaW5nIGNyb3dkZWQuIFRyYW5zcGFyZW50XG4gICAgICB3aGVyZSBubyBjZWxsIHdhcyBtZWFzdXJlZC4gVHVybiB0aGUgY2VsbHMnIG93biBPcGFjaXR5IGRvd24gdG8gcmVhZCB0aGUgZmllbGQgdW5kZXIgdGhlbS5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2RcIj5cbiAgICAgIHt7IGdlbmVNYXBWb2x1bWVOb3RlIH19XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gM0Qgb25seTogdGhlIHZvbHVtZSwgdGhlIGNsb3VkIGFuZCB0aGUgZGVuc2l0eSB2b2x1bWVzIG9jY3VweSB0aGUgc2FtZVxuICAgICBzcGFjZSwgc28gZWFjaCBoaWRlcyB0aGUgb3RoZXJzLiBJbmRlcGVuZGVudCB0b2dnbGVzLCBiZWNhdXNlIHRoZSB1c2VmdWxcbiAgICAgdmlld3MgYXJlIHRoZSBjb21iaW5hdGlvbnMg4oCUIHRoZSBmaWVsZCBhbG9uZSwgb25lIHNlY3Rpb24ncyBjZWxscyBvdmVyIGl0LFxuICAgICB0aGUgYW5hdG9teSBhbG9uZS4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpczNkXCI+XG4gICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TaG93PC9zcGFuPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cImRzLnZvbHVtZVwiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5zaG93Vm9sdW1lXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uU2hvd1ZvbHVtZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIlJlZmVyZW5jZSB2b2x1bWVcIlxuICAgICAgICBwVG9vbHRpcD1cIlRoZSByZWdpc3RlcmVkIGFuYXRvbXkgdGhlIG9ic2VydmF0aW9ucyBzaXQgaW5cIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8IS0tIFRoZSBiYWNrZHJvcCdzIG93biBvcGFjaXR5OiByZWFkaW5nIHRoZSBjbG91ZCBvciBhIGRlbnNpdHkgZmllbGRcbiAgICAgICB0aHJvdWdoIHRoZSBhbmF0b215IG1lYW5zIHR1cm5pbmcgdGhlIGFuYXRvbXkgZG93biwgbm90IHRoZSBkYXRhLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJkcy52b2x1bWUgJiYgdmlldy5zaG93Vm9sdW1lXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlZvbHVtZSBvcGFjaXR5PC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcudm9sdW1lT3BhY2l0eVwiXG4gICAgICAgIFttaW5dPVwiMC4wNVwiXG4gICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgIFtzdGVwXT1cIjAuMDVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25Wb2x1bWVPcGFjaXR5KCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcudm9sdW1lT3BhY2l0eSB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnNob3dQb2ludHNcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25TaG93UG9pbnRzKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiT2JzZXJ2YXRpb25zXCJcbiAgICAgICAgcFRvb2x0aXA9XCJUaGUgbWVhc3VyZWQgY2VsbHMuIEhpZGUgdGhlbSB0byByZWFkIHRoZSBkZW5zaXR5IHZvbHVtZXMgdW5kZXJuZWF0aFwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDwhLS0gT25seSBmb3IgZGF0YSB0aGF0IHJlYWxseSBpcyBzZWN0aW9uZWQ7IGEgY29udGludW91cyB6IGhhcyBubyBzZWN0aW9uc1xuICAgICAgIHRvIHN0ZXAgdGhyb3VnaC4gLS0+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5zaG93UG9pbnRzICYmIGlzU2VjdGlvbmVkXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJvbmVTZWN0aW9uXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uT25lU2VjdGlvbigkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIk9uZSBzZWN0aW9uIGF0IGEgdGltZVwiXG4gICAgICAgIHBUb29sdGlwPVwiRHJhdyBhIHNpbmdsZSBpbWFnZWQgc2VjdGlvbidzIGNlbGxzLCBzbyB0aGUgZGVuc2l0eSB2b2x1bWVzIGJldHdlZW4gdGhlIHNlY3Rpb25zIHN0YXkgdmlzaWJsZVwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuc2hvd1BvaW50cyAmJiBpc1NlY3Rpb25lZCAmJiBvbmVTZWN0aW9uXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlNlY3Rpb248L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5wb2ludFNlY3Rpb25cIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cImxhc3RTZWN0aW9uXCJcbiAgICAgICAgW3N0ZXBdPVwiMVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvblBvaW50U2VjdGlvbigkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyBzZWN0aW9uTGFiZWwgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpczNkXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5kZW5zaXR5Vm9sdW1lXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eVZvbHVtZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIkNsdXN0ZXIgZGVuc2l0eSB2b2x1bWVzXCJcbiAgICAgICAgcFRvb2x0aXA9XCJSYXltYXJjaCBlYWNoIGNsdXN0ZXIgYXMgYSBzbW9vdGggZGVuc2l0eSBmaWVsZCDigJQgYW4gRVNUSU1BVEUgYmV0d2VlbiB0aGUgaW1hZ2VkIHNlY3Rpb25zLCBub3QgbWVhc3VyZWQgY2VsbHNcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U21vb3RoaW5nPC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZGVuc2l0eVNtb290aGluZ1wiXG4gICAgICAgIFttaW5dPVwiMC41XCJcbiAgICAgICAgW21heF09XCI0XCJcbiAgICAgICAgW3N0ZXBdPVwiMC41XCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uRGVuc2l0eVNtb290aGluZygkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LmRlbnNpdHlTbW9vdGhpbmcgfX3Dlzwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5kZW5zaXR5Vm9sdW1lXCI+e3sgZGVuc2l0eU5vdGUgfX08L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBDb250aW51b3VzLW9ubHkga25vYnM6IG1lYW5pbmdsZXNzIGZvciBhIGNhdGVnb3JpY2FsIHBhbGV0dGUuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiaXNDb250aW51b3VzXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5sb2dTY2FsZVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkxvZ1NjYWxlKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiTG9nIHNjYWxlXCJcbiAgICAgICAgcFRvb2x0aXA9XCJDb3VudHMgY29sbGFwc2UgYWdhaW5zdCB0aGVpciBvdXRsaWVycyBvbiBhIGxpbmVhciByYW1wXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5DbGlwIG91dGxpZXJzPC9zcGFuPlxuICAgICAgPHAtZHJvcGRvd25cbiAgICAgICAgW29wdGlvbnNdPVwiY2xpcE9wdGlvbnNcIlxuICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcucGVyY2VudGlsZUNsaXBcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkNsaXAoJGV2ZW50KVwiXG4gICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgIHBUb29sdGlwPVwiUGVyY2VudGlsZSB0aGUgY29udHJhc3Qgd2luZG93IGlzIHRha2VuIGF0XCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtZHJvcGRvd24+XG4gICAgICA8IS0tIFJlc2VydmVzIHRoZSByZWFkb3V0IGNvbHVtbiB0aGlzIHJvdyBoYXMgbm8gcmVhZG91dCBmb3IsIHNvIHRoZVxuICAgICAgICAgY29udHJvbCdzIHJpZ2h0IGVkZ2UgbGluZXMgdXAgd2l0aCBldmVyeSBzbGlkZXIncy4gLS0+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPjwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBBIGdlbmUncyBpY29uIGluIGl0cyBjb2xvdXI6IHRoZSBidXR0b24gdGhhdCBvcGVucyBpdHMgaWNvbiBhbmQgY29sb3VyIHBpY2tlci4gLS0+XG4gIDxuZy10ZW1wbGF0ZSAjZ2VuZU1hcmsgbGV0LWc+XG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInNjLWdlbmUtaWNvblwiXG4gICAgICBbc3R5bGUuY29sb3JdPVwiZ2VuZUNvbG9yT2YoZylcIlxuICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSWNvbiBhbmQgY29sb3VyIGZvciAnICsgZ1wiXG4gICAgICBwVG9vbHRpcD1cIkljb24gYW5kIGNvbG91clwiXG4gICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgKGNsaWNrKT1cIm9wZW5HZW5lU3R5bGUoJGV2ZW50LCBnLCBnZW5lUG9wKVwiXG4gICAgPlxuICAgICAgPHN2ZyB2aWV3Qm94PVwiLTEuMiAtMS4yIDIuNCAyLjRcIiBjbGFzcz1cInNjLWdseXBoLXN2Z1wiPlxuICAgICAgICA8cG9seWdvbiBbYXR0ci5wb2ludHNdPVwiZ2x5cGhQb2ludHNPZihnKVwiPjwvcG9seWdvbj5cbiAgICAgIDwvc3ZnPlxuICAgIDwvYnV0dG9uPlxuICA8L25nLXRlbXBsYXRlPlxuICA8cC1vdmVybGF5UGFuZWwgI2dlbmVQb3Agc3R5bGVDbGFzcz1cInNjLWdlbmUtc3R5bGVcIiBhcHBlbmRUbz1cImJvZHlcIj5cbiAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiY29udGVudFwiPlxuICAgICAgPHNwYXRpYWwtZ2VuZS1zdHlsZVxuICAgICAgICAqbmdJZj1cInN0eWxlR2VuZSBhcyBnXCJcbiAgICAgICAgW2dlbmVdPVwiZ1wiXG4gICAgICAgIHdoYXQ9XCJPYnNlcnZhdGlvblwiXG4gICAgICAgIFtjb2xvcl09XCJnZW5lQ29sb3JPZihnKVwiXG4gICAgICAgIFtnbHlwaF09XCJnZW5lR2x5cGhPZihnKVwiXG4gICAgICAgIGljb25IaW50PVwiSWNvbnMgc2hvdyBvbiB0aGUgMkQgb2JzZXJ2YXRpb24gbWFya2Vycy5cIlxuICAgICAgICAoY29sb3JDaGFuZ2UpPVwib25HZW5lQ29sb3IoZywgJGV2ZW50KVwiXG4gICAgICAgIChnbHlwaENoYW5nZSk9XCJvbkdlbmVHbHlwaChnLCAkZXZlbnQpXCJcbiAgICAgICAgKHJlc2V0U3R5bGUpPVwicmVzZXRHZW5lU3R5bGUoZylcIlxuICAgICAgPjwvc3BhdGlhbC1nZW5lLXN0eWxlPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcC1vdmVybGF5UGFuZWw+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==
424
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1vYnNlcnZhdGlvbnMtcGFuZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUVMLE1BQU0sR0FFUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBSWhELE9BQU8sRUFFTCxvQkFBb0IsR0FHckIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2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LFdBQVc7d0JBQ1gsY0FBYzt3QkFDZCxjQUFjO3dCQUNkLGlCQUFpQjt3QkFDakIsa0JBQWtCO3dCQUNsQixrQkFBa0I7d0JBQ2xCLFlBQVk7d0JBQ1osYUFBYTt3QkFDYix1QkFBdUI7d0JBQ3ZCLHlCQUF5Qjt3QkFDekIscUNBQXFDO3FCQUN0QyxtQkFHZ0IsdUJBQXVCLENBQUMsTUFBTTs4QkFJdEMsUUFBUTtzQkFBaEIsS0FBSztnQkFFRyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsSUFBSTtzQkFBWixLQUFLO2dCQUVHLEtBQUs7c0JBQWIsS0FBSztnQkFFRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsV0FBVztzQkFBbkIsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFFRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRWEsVUFBVTtzQkFBNUIsTUFBTTtnQkFLRSxjQUFjO3NCQUF0QixLQUFLO2dCQUVhLGVBQWU7c0JBQWpDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQ2hlY2tib3hNb2R1bGUgfSBmcm9tICdwcmltZW5nL2NoZWNrYm94JztcbmltcG9ydCB7IERyb3Bkb3duTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9kcm9wZG93bic7XG5pbXBvcnQgeyBNdWx0aVNlbGVjdE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvbXVsdGlzZWxlY3QnO1xuaW1wb3J0IHsgT3ZlcmxheVBhbmVsTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9vdmVybGF5cGFuZWwnO1xuaW1wb3J0IHsgU2VsZWN0QnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9zZWxlY3RidXR0b24nO1xuaW1wb3J0IHsgU2xpZGVyTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9zbGlkZXInO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB0eXBlIHsgSVNwYXRpYWxDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFzZXQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7XG4gIENvbG9ybWFwTm9kZSxcbiAgREVGQVVMVF9TUEFUSUFMX1ZJRVcsXG4gIFNwYXRpYWxWaWV3U3RhdGUsXG4gIFRyYW5zY3JpcHRHbHlwaE5hbWUsXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IG9ic2VydmF0aW9uR2VuZUNvbG9yLCBvYnNlcnZhdGlvbkdlbmVHbHlwaCB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1nZW5lLWZpbHRlcic7XG5pbXBvcnQgeyBTcGF0aWFsU2VsZWN0aW9uTWFzaywgZW1wdHlTZWxlY3Rpb24gfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7XG4gIENMSVBfT1BUSU9OUyxcbiAgUGFuZWxPcHRpb24sXG4gIGdseXBoUG9pbnRzLFxuICBtaWRkbGVTZWN0aW9uLFxuICBzZWN0aW9uTGFiZWwsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1wYW5lbC1tb2RlbCc7XG5pbXBvcnQgeyBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1nZW5lLXN0eWxlL3NwYXRpYWwtZ2VuZS1zdHlsZS5jb21wb25lbnQnO1xuaW1wb3J0IHR5cGUgeyBHZW5lUGlja2VyTW9kZWwgfSBmcm9tICcuLi9zcGF0aWFsLWdlbmUtcGlja2VyJztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbExlZ2VuZEVudHJ5IH0gZnJvbSAnLi4vc3BhdGlhbC1rZXkvc3BhdGlhbC1rZXkubW9kZWwnO1xuaW1wb3J0IHsgU3BhdGlhbENvbG9yQnlDb21wb25lbnQgfSBmcm9tICcuLi9zcGF0aWFsLWNvbG9yLWJ5L3NwYXRpYWwtY29sb3ItYnkuY29tcG9uZW50JztcbmltcG9ydCB7IGNlbGxzU2hvd24gfSBmcm9tICcuLi8uLi9zcGF0aWFsL2xvZCc7XG5cbi8qKlxuICogVGhlIE9ic2VydmF0aW9ucyBzZWN0aW9uIOKAlCBvbmUgbWFya2VyIHBlciBvYnNlcnZhdGlvbiAoY2VsbCBjZW50cm9pZCwgVmlzaXVtIHNwb3QpLCBvciwgd2l0aCBhXG4gKiBjZWxsIHNlZ21lbnRhdGlvbiwgdGhlIGNlbGxzJyBvd24gc2hhcGVzIOKAlCBhbmQgd2hhdCBlbHNlIGRyYXdzIHRoZW06IHdoZXRoZXIgdGhleSBhcmUgc2hvd24gYW5kXG4gKiBhcyB3aGF0IChNYXJrZXJzIG9yIENlbGwgc2VnbWVudGF0aW9ucyksIG9uZSB7QGxpbmsgU3BhdGlhbENvbG9yQnlDb21wb25lbnQgY29sb3VyaW5nfSBmb3JcbiAqIGVpdGhlciwgdGhlIGdlbmUgZmlsdGVyLCB0aGUgbWFya2Vycycgc2l6ZSBhbmQgb3BhY2l0eSBvciB0aGUgY2VsbHMnIGRyYXdpbmcgKHByb2plY3RlZCBieSB0aGVcbiAqIGRpYWxvZyksIHRoZSBnZW5lIG1hcCwgdGhlIDNEIHNjZW5lICh2b2x1bWUsIGNsb3VkLCBzZWN0aW9ucywgZGVuc2l0eSB2b2x1bWVzKSBhbmQgdGhlXG4gKiBjb250aW51b3VzLW9ubHkga25vYnMuXG4gKlxuICogUmVuZGVycyB0aGUgc2VjdGlvbiBhbmQgdGhlIHNlY3Rpb25zIGFmdGVyIGl0IGFzIHNpYmxpbmdzIGluIHRoZSBkaWFsb2cgYm9keVxuICogKGBkaXNwbGF5OiBjb250ZW50c2ApLiBXcml0ZXMgb25seSB0aHJvdWdoIGBjb250cm9scy5zZXRWaWV3U3RhdGVgLlxuICovXG5pbXBvcnQgeyBTcGF0aWFsU2VsZWN0aW9uT2JzZXJ2YXRpb25zQ29tcG9uZW50IH0gZnJvbSAnLi4vc3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zL3NwYXRpYWwtc2VsZWN0aW9uLW9ic2VydmF0aW9ucy5jb21wb25lbnQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgQ2hlY2tib3hNb2R1bGUsXG4gICAgRHJvcGRvd25Nb2R1bGUsXG4gICAgTXVsdGlTZWxlY3RNb2R1bGUsXG4gICAgT3ZlcmxheVBhbmVsTW9kdWxlLFxuICAgIFNlbGVjdEJ1dHRvbk1vZHVsZSxcbiAgICBTbGlkZXJNb2R1bGUsXG4gICAgVG9vbHRpcE1vZHVsZSxcbiAgICBTcGF0aWFsQ29sb3JCeUNvbXBvbmVudCxcbiAgICBTcGF0aWFsR2VuZVN0eWxlQ29tcG9uZW50LFxuICAgIFNwYXRpYWxTZWxlY3Rpb25PYnNlcnZhdGlvbnNDb21wb25lbnQsXG4gIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9zcGF0aWFsLW9ic2VydmF0aW9ucy1wYW5lbC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NwYXRpYWwtb2JzZXJ2YXRpb25zLXBhbmVsLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBTcGF0aWFsT2JzZXJ2YXRpb25zUGFuZWxDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xuICAvKiogVGhlIHNwYXRpYWwgY29udHJvbHMgdGhpcyBwYW5lbCByZWFkcyBhbmQgd3JpdGVzIHRocm91Z2g7IG51bGwgd2l0aG91dCBhIGBTUEFUSUFMX0RBVEFfUE9SVGAuICovXG4gIEBJbnB1dCgpIGNvbnRyb2xzOiBJU3BhdGlhbENvbnRyb2xzIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgZGF0YXNldCBvbiBvZmZlciwgb3IgbnVsbC4gKi9cbiAgQElucHV0KCkgZGF0YXNldDogU3BhdGlhbERhdGFzZXQgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBjdXJyZW50IHNwYXRpYWwgdmlldyBzdGF0ZTogd2hhdCBpcyBkcmF3biwgYW5kIGhvdy4gKi9cbiAgQElucHV0KCkgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSA9IERFRkFVTFRfU1BBVElBTF9WSUVXO1xuICAvKiogVGhlIGdlbmUgbGlzdCBcIkNvbG91ciBieSBnZW5lXCIgcGlja3MgZnJvbSwgc2hhcmVkIHdpdGggdGhlIG90aGVyIGdlbmUgZHJvcGRvd25zLiAqL1xuICBASW5wdXQoKSBnZW5lczogR2VuZVBpY2tlck1vZGVsIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUga2V5J3MgY2F0ZWdvcmljYWwgbGVnZW5kLCBvciBudWxsIOKAlCB3aGljaCBhbHNvIGRlY2lkZXMgdGhlIGNvbnRpbnVvdXMga25vYnMuICovXG4gIEBJbnB1dCgpIGxlZ2VuZDogU3BhdGlhbExlZ2VuZEVudHJ5W10gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBrZXkncyBjb250aW51b3VzIGNvbG91ciBiYXIgKGEgQ1NTIGdyYWRpZW50KSwgb3IgbnVsbCB3aGVuIGNhdGVnb3JpY2FsLiAqL1xuICBASW5wdXQoKSBjb2xvckJhckNzczogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgY3VycmVudCBzZWxlY3Rpb24gKGl0cyBjb3VudCwgYW5kIHdoYXQgaXMgbXV0ZWQpLiAqL1xuICBASW5wdXQoKSBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrID0gZW1wdHlTZWxlY3Rpb24oKTtcbiAgLyoqIFRoZSBsZWdlbmQgcm93IHdob3NlIGNhdGVnb3J5IGlzIHNlbGVjdGVkLCBmb3IgaGlnaGxpZ2h0aW5nLiAqL1xuICBASW5wdXQoKSBzZWxlY3RlZENhdGVnb3J5OiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIENvbG9ybWFwIHRyZWUgZm9yIHRoZSBjb250aW51b3VzIGNvbG91ciBzY2FsZS4gKi9cbiAgQElucHV0KCkgY29sb3JtYXBPcHRpb25zOiBDb2xvcm1hcE5vZGVbXSA9IFtdO1xuICAvKiogU2V0IHdoaWxlIHRoZSAzRCBjbG91ZCBpcyB0aGUgYWN0aXZlIG1vZGUuICovXG4gIEBJbnB1dCgpIGlzM2QgPSBmYWxzZTtcbiAgLyoqIFdoZXRoZXIgdGhlIE9ic2VydmF0aW9ucyBzZWN0aW9uIGlzIGV4cGFuZGVkLiAqL1xuICBASW5wdXQoKSBvcGVuID0gZmFsc2U7XG4gIC8qKiBBc2tzIHRvIG9wZW4gb3IgY2xvc2UgaXQ7IHR3by13YXkgd2l0aCBgb3BlbmAuICovXG4gIEBPdXRwdXQoKSByZWFkb25seSBvcGVuQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuICAvKipcbiAgICogV2hldGhlciB0aGUgZGF0YXNldCdzIGNlbGxzIGNhbiBiZSBkcmF3biBoZXJlIChhIGNlbGwgc2VnbWVudGF0aW9uLCBhbmQgaW4gM0QgYSAzRCBvbmUpOiB0aGVcbiAgICogb2JzZXJ2YXRpb25zIGFyZSBzaG93biBhcyBNYXJrZXJzIG9yIGFzIENlbGwgc2VnbWVudGF0aW9ucy5cbiAgICovXG4gIEBJbnB1dCgpIGNlbGxzQXZhaWxhYmxlID0gZmFsc2U7XG4gIC8qKiBBIGxlZ2VuZCByb3cgd2FzIGNsaWNrZWQgKHNlZSB0aGUga2V5KS4gKi9cbiAgQE91dHB1dCgpIHJlYWRvbmx5IGNhdGVnb3J5Q2xpY2tlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBjbGlwT3B0aW9ucyA9IENMSVBfT1BUSU9OUztcbiAgLyoqIEhvdyBzZXZlcmFsIGdlbmVzIG9mIHRoZSBvYnNlcnZhdGlvbiBmaWx0ZXIgY29tYmluZS4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IG1hdGNoT3B0aW9uczogUGFuZWxPcHRpb248U3BhdGlhbFZpZXdTdGF0ZVsnb2JzZXJ2YXRpb25HZW5lc01hdGNoJ10+W10gPSBbXG4gICAgeyBsYWJlbDogJ0FueSBnZW5lJywgdmFsdWU6ICdhbnknIH0sXG4gICAgeyBsYWJlbDogJ0FsbCBnZW5lcycsIHZhbHVlOiAnYWxsJyB9LFxuICBdO1xuICAvKiogVmlydHVhbC1zY3JvbGxlZCBvbmx5IHBhc3QgdGhpcyBtYW55IG9wdGlvbnMgKHNlZSB0aGUgY2VsbHMgcGFuZWwncyBnZW5lIGRyb3Bkb3duKS4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGdlbmVWaXJ0dWFsU2Nyb2xsRnJvbSA9IDIwMDtcblxuICAvKiogV2hhdCB0aGUgb2JzZXJ2YXRpb25zIGFyZSBzaG93biBhcywgd2l0aCBhIGNlbGwgc2VnbWVudGF0aW9uLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2hvd0FzT3B0aW9uczogUGFuZWxPcHRpb248J21hcmtlcnMnIHwgJ2NlbGxzJz5bXSA9IFtcbiAgICB7IGxhYmVsOiAnTWFya2VycycsIHZhbHVlOiAnbWFya2VycycgfSxcbiAgICB7IGxhYmVsOiAnQ2VsbCBzZWdtZW50YXRpb25zJywgdmFsdWU6ICdjZWxscycgfSxcbiAgXTtcbiAgLyoqIFRoZSBjaG9pY2Ugb2YgTWFya2VycyBvciBDZWxsIHNlZ21lbnRhdGlvbnMsIGtlcHQgd2hpbGUgdGhlIG9ic2VydmF0aW9ucyBhcmUgaGlkZGVuLiAqL1xuICBwcml2YXRlIGNob3NlblNob3duQXM6ICdtYXJrZXJzJyB8ICdjZWxscycgfCBudWxsID0gbnVsbDtcbiAgLyoqXG4gICAqIFRoZSBkYXRhc2V0J3MgaW1hZ2VkIHNlY3Rpb24gcG9zaXRpb25zLCBvciBudWxsIHdoZW4gaXRzIHogaXMgY29udGludW91cyByYXRoZXIgdGhhblxuICAgKiBzZWN0aW9uZWQuIFJlYWQgb25jZSBwZXIgZGF0YXNldCDigJQgdGhlIHNjYW4gd2Fsa3MgdGhlIHogb2YgZXZlcnkgb2JzZXJ2YXRpb24sIHNvIGl0XG4gICAqIG11c3Qgbm90IHNpdCBpbiBhIHRlbXBsYXRlIGdldHRlci5cbiAgICovXG4gIHByb3RlY3RlZCBzZWN0aW9uczogRmxvYXQzMkFycmF5IHwgbnVsbCA9IG51bGw7XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydjb250cm9scyddKSB7XG4gICAgICB0aGlzLmdlbmVGaWx0ZXJGYWlsZWQkID0gdGhpcy5jb250cm9scz8uZ2V0R2VuZUZpbHRlckZhaWxlZCQ/LigpID8/IG9mKGZhbHNlKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ2RhdGFzZXQnXSB8fCBjaGFuZ2VzWydjb250cm9scyddKSB7XG4gICAgICBpZiAoY2hhbmdlc1snZGF0YXNldCddKSB0aGlzLmNob3NlblNob3duQXMgPSBudWxsO1xuICAgICAgdGhpcy5zZWN0aW9ucyA9IHRoaXMuY29udHJvbHM/LnNhbXBsZWRTZWN0aW9ucygpID8/IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIHNob3duLCBhbmQgYXMgd2hhdCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogV2hldGhlciB0aGUgY2VsbHMgYXJlIGRyYXduICh0aGUgZXhwbGljaXQgY2hvaWNlLCBvciBhdXRvbWF0aWNhbGx5IGZvciBkYXRhIHRoYXQgaGFzIHRoZW0pLiAqL1xuICBwcml2YXRlIGdldCBjZWxsc09uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNlbGxzQXZhaWxhYmxlICYmIGNlbGxzU2hvd24odGhpcy5kYXRhc2V0LCB0aGlzLnZpZXcpO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgdGhlIG9ic2VydmF0aW9ucyBhcmUgc2hvd24gYXQgYWxsLCBhcyBtYXJrZXJzIG9yIGFzIGNlbGxzLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IG9ic2VydmF0aW9uc1Nob3duKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcuc2hvd1BvaW50cyB8fCB0aGlzLmNlbGxzT247XG4gIH1cblxuICAvKiogV2hhdCB0aGUgb2JzZXJ2YXRpb25zIGFyZSBzaG93biBhcyAodGhlIHRvZ2dsZSk6IHRoZSBjZWxscyB3aGlsZSB0aGV5IGFyZSBkcmF3biwgZWxzZSB0aGVcbiAgICogIG1hcmtlcnMsIG9yLCBoaWRkZW4sIHdoYXQgd2FzIGxhc3QgY2hvc2VuLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IHNob3duQXMoKTogJ21hcmtlcnMnIHwgJ2NlbGxzJyB7XG4gICAgaWYgKCF0aGlzLmNlbGxzQXZhaWxhYmxlKSByZXR1cm4gJ21hcmtlcnMnO1xuICAgIGlmICh0aGlzLmNlbGxzT24pIHJldHVybiAnY2VsbHMnO1xuICAgIGlmICh0aGlzLnZpZXcuc2hvd1BvaW50cykgcmV0dXJuICdtYXJrZXJzJztcbiAgICByZXR1cm4gdGhpcy5jaG9zZW5TaG93bkFzID8/ICdjZWxscyc7XG4gIH1cblxuICAvKiogU2hvdyBvciBoaWRlIHRoZSBvYnNlcnZhdGlvbnMsIGFzIHdoYXQgdGhleSB3ZXJlIHNob3duIGFzLiAqL1xuICBwcm90ZWN0ZWQgb25TaG93T2JzZXJ2YXRpb25zKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKG9uKSB0aGlzLnNob3dBcyh0aGlzLnNob3duQXMpO1xuICAgIGVsc2UgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgc2hvd1BvaW50czogZmFsc2UsIC4uLih0aGlzLmNlbGxzQXZhaWxhYmxlID8geyBzaG93Q2VsbHM6IGZhbHNlIH0gOiB7fSkgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25TaG93bkFzKGFzOiAnbWFya2VycycgfCAnY2VsbHMnIHwgbnVsbCk6IHZvaWQge1xuICAgIGlmICghYXMpIHJldHVybjtcbiAgICB0aGlzLmNob3NlblNob3duQXMgPSBhcztcbiAgICBpZiAodGhpcy5vYnNlcnZhdGlvbnNTaG93bikgdGhpcy5zaG93QXMoYXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIERyYXcgdGhlIG9ic2VydmF0aW9ucyBhcyB0aGUgbWFya2Vycywgb3IgYXMgdGhlIGNlbGxzOiBvbmUgb3IgdGhlIG90aGVyLCBuZXZlciBib3RoICh0aGVcbiAgICogcmVuZGVyZXJzIGRyYXcgbm8gbWFya2VycyB3aGlsZSB0aGUgY2VsbHMgYXJlIGRyYXduKS4gVGhlIG1hcmtlcnMgc3RheSBzd2l0Y2hlZCBvbiB1bmRlciB0aGVcbiAgICogY2VsbHMsIHNvIGEgdmlldyB3aXRob3V0IHRoZW0gKHNwYXRpYWwgM0Qgb2YgYSAyRCBzZWdtZW50YXRpb24pIHN0aWxsIHNob3dzIHRoZSBtYXJrZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBzaG93QXMoYXM6ICdtYXJrZXJzJyB8ICdjZWxscycpOiB2b2lkIHtcbiAgICB0aGlzLmNob3NlblNob3duQXMgPSBhcztcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoe1xuICAgICAgc2hvd1BvaW50czogdHJ1ZSxcbiAgICAgIC4uLih0aGlzLmNlbGxzQXZhaWxhYmxlID8geyBzaG93Q2VsbHM6IGFzID09PSAnY2VsbHMnIH0gOiB7fSksXG4gICAgfSk7XG4gIH1cblxuICAvLyDilIDilIAgd2hpY2ggb2JzZXJ2YXRpb25zIGFyZSBkcmF3biDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogR2VuZXMgcGlja2VkIGZvciB0aGUgb2JzZXJ2YXRpb24gZmlsdGVyOyBub25lIGRyYXdzIGV2ZXJ5IG9ic2VydmF0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25PYnNlcnZhdGlvbkdlbmVzKGdlbmVzOiBzdHJpbmdbXSB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzOiBnZW5lcyA/PyBbXSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbk9ic2VydmF0aW9uR2VuZXNNYXRjaChtYXRjaDogU3BhdGlhbFZpZXdTdGF0ZVsnb2JzZXJ2YXRpb25HZW5lc01hdGNoJ10gfCBudWxsKTogdm9pZCB7XG4gICAgaWYgKCFtYXRjaCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IG9ic2VydmF0aW9uR2VuZXNNYXRjaDogbWF0Y2ggfSk7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGUgZ2VuZSBmaWx0ZXIgY291bGQgbm90IGJlIGFwcGxpZWQgKGFuIGV4cHJlc3Npb24gcmVhZCBmYWlsZWQpOyBvbmUgc3RyZWFtIHBlclxuICAgKiAgYGNvbnRyb2xzYCwgc28gdGhlIHRlbXBsYXRlJ3MgYXN5bmMgcGlwZSBrZWVwcyBpdHMgc3Vic2NyaXB0aW9uLiAqL1xuICBwcm90ZWN0ZWQgZ2VuZUZpbHRlckZhaWxlZCQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSBvZihmYWxzZSk7XG5cbiAgLyoqIEFzayBmb3IgdGhlIHBpY2tlZCBnZW5lcycgZXhwcmVzc2lvbiBhZ2FpbiAoYSBmYWlsZWQgcmVhZCBpcyBub3QgY2FjaGVkKS4gKi9cbiAgcHJvdGVjdGVkIHJldHJ5R2VuZUZpbHRlcigpOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzOiBbLi4udGhpcy52aWV3Lm9ic2VydmF0aW9uR2VuZXNdIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uT2JzZXJ2YXRpb25HZW5lc0NvbG9yQnkob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBvYnNlcnZhdGlvbkdlbmVzQ29sb3JCeTogb24gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVtb3ZlT2JzZXJ2YXRpb25HZW5lKGdlbmU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMub25PYnNlcnZhdGlvbkdlbmVzKHRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVzLmZpbHRlcigoZykgPT4gZyAhPT0gZ2VuZSkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGlzT2JzZXJ2YXRpb25HZW5lKGdlbmU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXcub2JzZXJ2YXRpb25HZW5lcy5pbmNsdWRlcyhnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0cmFja0J5R2VuZShfaTogbnVtYmVyLCBnZW5lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBnZW5lO1xuICB9XG5cbiAgLy8g4pSA4pSAIGEgcGlja2VkIGdlbmUncyBpY29uIGFuZCBjb2xvdXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRoZSBnZW5lIHRoZSBpY29uIGFuZCBjb2xvdXIgcGlja2VyIGlzIG9wZW4gZm9yLiAqL1xuICBwcm90ZWN0ZWQgc3R5bGVHZW5lOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICBwcm90ZWN0ZWQgZ2VuZUNvbG9yT2YoZ2VuZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gb2JzZXJ2YXRpb25HZW5lQ29sb3IodGhpcy52aWV3LCBnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lR2x5cGhPZihnZW5lOiBzdHJpbmcpOiBUcmFuc2NyaXB0R2x5cGhOYW1lIHtcbiAgICByZXR1cm4gb2JzZXJ2YXRpb25HZW5lR2x5cGgodGhpcy52aWV3LCBnZW5lKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnbHlwaFBvaW50c09mKGdlbmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGdseXBoUG9pbnRzKHRoaXMuZ2VuZUdseXBoT2YoZ2VuZSkpO1xuICB9XG5cbiAgLyoqIE9wZW4gdGhlIHBpY2tlciBvbiB0aGUgZ2VuZSdzIHN3YXRjaC4gSW5zaWRlIHRoZSBnZW5lcyBkcm9wZG93biB0aGUgY2xpY2sgbXVzdCBub3QgYWxzb1xuICAgKiAgcmVhY2ggdGhlIG9wdGlvbiwgd2hpY2ggd291bGQgdW5waWNrIHRoZSBnZW5lLiAqL1xuICBwcm90ZWN0ZWQgb3BlbkdlbmVTdHlsZShldmVudDogRXZlbnQsIGdlbmU6IHN0cmluZywgcGFuZWw6IHsgdG9nZ2xlKGU6IEV2ZW50KTogdm9pZDsgaGlkZSgpOiB2b2lkIH0pOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBpZiAodGhpcy5zdHlsZUdlbmUgPT09IGdlbmUpIHtcbiAgICAgIHBhbmVsLnRvZ2dsZShldmVudCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuc3R5bGVHZW5lID0gZ2VuZTtcbiAgICBwYW5lbC5oaWRlKCk7XG4gICAgLy8gUmUtb3BlbiBhbmNob3JlZCBvbiB0aGUgc3dhdGNoIHRoYXQgd2FzIGNsaWNrZWQsIG9uY2UgdGhlIHBhbmVsIGhhcyBjbG9zZWQuXG4gICAgc2V0VGltZW91dCgoKSA9PiBwYW5lbC50b2dnbGUoZXZlbnQpKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvbkdlbmVDb2xvcihnZW5lOiBzdHJpbmcsIGhleDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgb2JzZXJ2YXRpb25HZW5lQ29sb3JzOiB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVDb2xvcnMsIFtnZW5lXTogaGV4IH0gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25HZW5lR2x5cGgoZ2VuZTogc3RyaW5nLCBnbHlwaDogVHJhbnNjcmlwdEdseXBoTmFtZSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IG9ic2VydmF0aW9uR2VuZUdseXBoczogeyAuLi50aGlzLnZpZXcub2JzZXJ2YXRpb25HZW5lR2x5cGhzLCBbZ2VuZV06IGdseXBoIH0gfSk7XG4gIH1cblxuICAvKiogQmFjayB0byB0aGUgZ2VuZSdzIGRlZmF1bHQgY29sb3VyIChpdHMgcGxhY2UgaW4gdGhlIGxpc3QpIGFuZCBpY29uIChhIGNpcmNsZSkuICovXG4gIHByb3RlY3RlZCByZXNldEdlbmVTdHlsZShnZW5lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjb2xvcnMgPSB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVDb2xvcnMgfTtcbiAgICBjb25zdCBnbHlwaHMgPSB7IC4uLnRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVHbHlwaHMgfTtcbiAgICBkZWxldGUgY29sb3JzW2dlbmVdO1xuICAgIGRlbGV0ZSBnbHlwaHNbZ2VuZV07XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgb2JzZXJ2YXRpb25HZW5lQ29sb3JzOiBjb2xvcnMsIG9ic2VydmF0aW9uR2VuZUdseXBoczogZ2x5cGhzIH0pO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGZpbHRlciBoaWRlcywgaW4gd29yZHMuICovXG4gIHByb3RlY3RlZCBnZXQgZ2VuZUZpbHRlckhpbnQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBnZW5lcyA9IHRoaXMudmlldy5vYnNlcnZhdGlvbkdlbmVzO1xuICAgIGNvbnN0IHdoaWNoID1cbiAgICAgIGdlbmVzLmxlbmd0aCA9PT0gMVxuICAgICAgICA/IGdlbmVzWzBdXG4gICAgICAgIDogdGhpcy52aWV3Lm9ic2VydmF0aW9uR2VuZXNNYXRjaCA9PT0gJ2FsbCdcbiAgICAgICAgICA/ICdhbGwgb2YgdGhlc2UgZ2VuZXMnXG4gICAgICAgICAgOiAnYW55IG9mIHRoZXNlIGdlbmVzJztcbiAgICByZXR1cm4gKFxuICAgICAgYE9ubHkgb2JzZXJ2YXRpb25zIGV4cHJlc3NpbmcgJHt3aGljaH0gYXJlIGRyYXduOyB0aGUgb3RoZXJzIGFyZSBoaWRkZW4sIHdpdGggdGhlaXIgY2VsbCBvdXRsaW5lcyBhbmQgdGhlIGAgK1xuICAgICAgJ3RyYW5zY3JpcHRzIGFzc2lnbmVkIHRvIHRoZW0uIFRoZSB0cmFuc2NyaXB0IGRlbnNpdHkgbWFwLCBhbmQgdHJhbnNjcmlwdHMgZ3JvdXBlZCBieSBhcmVhIHdoZW4gem9vbWVkICcgK1xuICAgICAgJ291dCwgYXJlIGhpZGRlbiB3aGlsZSB0aGlzIGlzIG9uOiB0aGV5IGNhcnJ5IG5vIGNlbGxzIHRvIGZpbHRlciBieS4nXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBUcnVlIHdoaWxlIGEgc2VsZWN0aW9uIGlzIGFjdGl2ZSDigJQgZXZlcnl0aGluZyBlbHNlIHJlbmRlcnMgbXV0ZWQuICovXG4gIGdldCBoYXNTZWxlY3Rpb24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGxvZy9jbGlwIGFwcGx5IOKAlCB0aGV5IGFyZSBjb250aW51b3VzLW9ubHkga25vYnMuICovXG4gIHByb3RlY3RlZCBnZXQgaXNDb250aW51b3VzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMudmlldy5jb2xvckJ5ICYmIHRoaXMubGVnZW5kID09PSBudWxsO1xuICB9XG5cbiAgLy8g4pSA4pSAIGRpc3BsYXkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLy8gUHJpbWVORydzIHNsaWRlciByZXBvcnRzIGBudW1iZXIgfCB1bmRlZmluZWRgOyBpZ25vcmUgdGhlIGVtcHR5IGNhc2UgcmF0aGVyXG4gIC8vIHRoYW4gd3JpdGluZyBgdW5kZWZpbmVkYCBpbnRvIHRoZSBzdG9yZSBhbmQgcmVuZGVyaW5nIE5hTi1zaXplZCBtYXJrZXJzLlxuICBwcm90ZWN0ZWQgb25Qb2ludFNjYWxlKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHBvaW50U2NhbGU6IHZhbHVlIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvbk9wYWNpdHkodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgb3BhY2l0eTogdmFsdWUgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uTG9nU2NhbGUob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBsb2dTY2FsZTogb24gfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcChvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXA6IG9uIH0pO1xuICB9XG4gIC8qKiAzRDogc21vb3RoIHRoZSBwZXItc2VjdGlvbiBzaGVldHMgYWxvbmcgeiBpbnRvIGEgY29udGludW91cyB2b2x1bWUuICovXG4gIHByb3RlY3RlZCBvbkdlbmVNYXBWb2x1bWUob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwVm9sdW1lOiBvbiB9KTtcbiAgfVxuICAvKiogM0Q6IHJlc3RyaWN0IHRoZSBzaGVldHMgdG8gb25lIGltYWdlZCBzZWN0aW9uLiAqL1xuICBwcm90ZWN0ZWQgb25HZW5lTWFwT25lU2VjdGlvbihvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICghb24pIHtcbiAgICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IGdlbmVNYXBTZWN0aW9uOiBudWxsIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwU2VjdGlvbjogbWlkZGxlU2VjdGlvbih0aGlzLnNlY3Rpb25zKSB9KTtcbiAgfVxuICBwcm90ZWN0ZWQgb25HZW5lTWFwU2VjdGlvbih2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBnZW5lTWFwU2VjdGlvbjogdmFsdWUgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIGdldCBnZW5lTWFwT25lU2VjdGlvbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52aWV3LmdlbmVNYXBTZWN0aW9uICE9IG51bGw7XG4gIH1cbiAgLyoqIFwiMTIgb2YgNTNcIiBmb3IgdGhlIGdlbmUgbWFwJ3Mgb3duIHNlY3Rpb24sIDEtYmFzZWQgbGlrZSB0aGUgY2xvdWQncy4gKi9cbiAgcHJvdGVjdGVkIGdldCBnZW5lTWFwU2VjdGlvbkxhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHNlY3Rpb25MYWJlbCh0aGlzLnNlY3Rpb25zLCB0aGlzLnZpZXcuZ2VuZU1hcFNlY3Rpb24pO1xuICB9XG4gIHByb3RlY3RlZCBvbkdlbmVNYXBTbW9vdGhpbmcodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcFNtb290aGluZzogdmFsdWUgfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uR2VuZU1hcE9wYWNpdHkodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZ2VuZU1hcE9wYWNpdHk6IHZhbHVlIH0pO1xuICB9XG4gIC8qKlxuICAgKiBXaGF0IHRoZSAzRCBnZW5lIG1hcCBpcyBjdXJyZW50bHkgc2hvd2luZywgc2FpZCBwbGFpbmx5IOKAlCB0aGUgc2hlZXRzIGFyZSBhXG4gICAqIG1lYXN1cmVtZW50IGFuZCB0aGUgdm9sdW1lIGlzIGFuIGVzdGltYXRlLCBhbmQgdGhlIHBhbmVsIGhhcyB0byBiZSB0aGUgcGxhY2VcbiAgICogdGhhdCBzYXlzIHdoaWNoIG9uZSBpcyBvbiBzY3JlZW4uXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0IGdlbmVNYXBWb2x1bWVOb3RlKCk6IHN0cmluZyB7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLnNlY3Rpb25zPy5sZW5ndGggPz8gMDtcbiAgICBpZiAodGhpcy52aWV3LmdlbmVNYXBWb2x1bWUpIHtcbiAgICAgIHJldHVybiAoXG4gICAgICAgICdJbnRlcnBvbGF0ZWQgYWxvbmcgejogdGhlIHBsYW5lcyBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMgY2FycnkgYW4gJyArXG4gICAgICAgIFwiRVNUSU1BVEUsIHNtb290aGVkIGZyb20gdGhlaXIgbmVpZ2hib3VycycgbWVhbi4gTm90aGluZyBpcyBkcmF3biBiZXlvbmQgdGhlIFwiICtcbiAgICAgICAgJ291dGVybW9zdCBzZWN0aW9uLidcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICh0aGlzLmdlbmVNYXBPbmVTZWN0aW9uKSB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICBcIk9uZSBpbWFnZWQgc2VjdGlvbidzIGZpZWxkIOKAlCBtZWFzdXJlZCwgbm90IGludGVycG9sYXRlZC4gSGlkZSB0aGUgXCIgK1xuICAgICAgICAnb2JzZXJ2YXRpb25zIHRvIHJlYWQgaXQsIG9yIGxlYXZlIHRoZW0gb24gdG8gY2hlY2sgdGhlIGZpZWxkIGFnYWluc3QgdGhlbS4nXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gKFxuICAgICAgYE9uZSBmaWVsZCBwZXIgaW1hZ2VkIHNlY3Rpb24ke3RvdGFsID8gYCAoJHt0b3RhbH0pYCA6ICcnfSwgYXQgaXRzIG93biBkZXB0aCwgYCArXG4gICAgICAnd2l0aCB0aGUgZ2FwcyBiZXR3ZWVuIHNlY3Rpb25zIGVtcHR5LiBLZXJuZWwtd2VpZ2h0ZWQgbWVhbiBwZXIgY2VsbCwgbm90IGEgc3VtLidcbiAgICApO1xuICB9XG5cbiAgLyoqIFRydWUgd2hpbGUgYSBnZW5lIGlzIHRoZSBjb2xvdXIgc291cmNlIOKAlCB0aGUgb25seSB0aGluZyBhIGdlbmUgbWFwIGNhbiBtYXAuICovXG4gIHByb3RlY3RlZCBnZXQgY2FuTWFwR2VuZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52aWV3LmNvbG9yQnk/LmtpbmQgPT09ICdmZWF0dXJlJztcbiAgfVxuXG4gIC8vIOKUgOKUgCB3aGF0IHRoZSAzRCBzY2VuZSBkcmF3cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVGhlIHZvbHVtZSwgdGhlIGNsb3VkIGFuZCB0aGUgZGVuc2l0eSB2b2x1bWVzIHNoYXJlIG9uZSBzcGFjZSwgc28gZWFjaCBvbmVcbiAgLy8gaGlkZXMgdGhlIG90aGVycyB0byBzb21lIGRlZ3JlZS4gSW5kZXBlbmRlbnQgdG9nZ2xlcyBiZWNhdXNlIHRoZSB1c2VmdWwgdmlld3NcbiAgLy8gYXJlIHRoZSBjb21iaW5hdGlvbnMsIG5vdCBhIHNpbmdsZSBcIjNEIG1vZGVcIi5cblxuICBwcm90ZWN0ZWQgb25TaG93UG9pbnRzKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgc2hvd1BvaW50czogb24gfSk7XG4gIH1cbiAgLyoqIFRoZSBcIm9uZSBzZWN0aW9uIGF0IGEgdGltZVwiIHN3aXRjaDogbnVsbCByZXN0b3JlcyB0aGUgd2hvbGUgc3RhY2suICovXG4gIHByb3RlY3RlZCBvbk9uZVNlY3Rpb24ob246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoIW9uKSB7XG4gICAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBwb2ludFNlY3Rpb246IG51bGwgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIE9wZW4gaW4gdGhlIG1pZGRsZSBvZiB0aGUgc3RhY2sgcmF0aGVyIHRoYW4gb24gdGhlIGZpcnN0IHNlY3Rpb24sIHdoaWNoIGZvclxuICAgIC8vIGEgYnJhaW4gaXMgYSBuZWFybHkgZW1wdHkgb2xmYWN0b3J5LWJ1bGIgc2xpZGUuXG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgcG9pbnRTZWN0aW9uOiBtaWRkbGVTZWN0aW9uKHRoaXMuc2VjdGlvbnMpIH0pO1xuICB9XG4gIHByb3RlY3RlZCBvblBvaW50U2VjdGlvbih2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBwb2ludFNlY3Rpb246IHZhbHVlIH0pO1xuICB9XG4gIC8qKiBUcnVlIHdoaWxlIHRoZSBjbG91ZCBpcyByZXN0cmljdGVkIHRvIGEgc2luZ2xlIHNlY3Rpb24uICovXG4gIHByb3RlY3RlZCBnZXQgb25lU2VjdGlvbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52aWV3LnBvaW50U2VjdGlvbiAhPSBudWxsO1xuICB9XG4gIC8qKiBIaWdoZXN0IHNlY3Rpb24gaW5kZXggdGhlIHNsaWRlciBjYW4gcmVhY2guICovXG4gIHByb3RlY3RlZCBnZXQgbGFzdFNlY3Rpb24oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5tYXgoMCwgKHRoaXMuc2VjdGlvbnM/Lmxlbmd0aCA/PyAxKSAtIDEpO1xuICB9XG4gIC8qKiBcIjEyIG9mIDUzXCIg4oCUIDEtYmFzZWQsIGJlY2F1c2UgdGhlIHNlY3Rpb25zIGFyZSBzbGlkZXMsIG5vdCBhcnJheSBzbG90cy4gKi9cbiAgcHJvdGVjdGVkIGdldCBzZWN0aW9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gc2VjdGlvbkxhYmVsKHRoaXMuc2VjdGlvbnMsIHRoaXMudmlldy5wb2ludFNlY3Rpb24pO1xuICB9XG4gIC8qKiBXaGV0aGVyIHRoaXMgZGF0YXNldCBoYXMgc2VjdGlvbnMgdG8gcGljayBmcm9tIGF0IGFsbC4gKi9cbiAgcHJvdGVjdGVkIGdldCBpc1NlY3Rpb25lZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKHRoaXMuc2VjdGlvbnM/Lmxlbmd0aCA/PyAwKSA+IDE7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EZW5zaXR5Vm9sdW1lKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9scz8uc2V0Vmlld1N0YXRlKHsgZGVuc2l0eVZvbHVtZTogb24gfSk7XG4gIH1cbiAgcHJvdGVjdGVkIG9uRGVuc2l0eVNtb290aGluZyh2YWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmNvbnRyb2xzPy5zZXRWaWV3U3RhdGUoeyBkZW5zaXR5U21vb3RoaW5nOiB2YWx1ZSB9KTtcbiAgfVxuXG4gIC8qKiBXaGF0IHRoZSBkZW5zaXR5IHZvbHVtZXMgYXJlIGFjdHVhbGx5IHNob3dpbmcsIHNhaWQgcGxhaW5seSDigJQgYW4gZXN0aW1hdGUgaXNcbiAgICogIG9ubHkgaG9uZXN0IGlmIHRoZSByZWFkZXIga25vd3MgaXQgaXMgb25lLCBhbmQgd2hpY2ggY2x1c3RlcnMgYXJlIGluIHZpZXcuICovXG4gIHByb3RlY3RlZCBnZXQgZGVuc2l0eU5vdGUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBjYXBwZWQgPSBgdGhlICR7U3BhdGlhbE9ic2VydmF0aW9uc1BhbmVsQ29tcG9uZW50LkRFTlNJVFlfTUFYX0NMVVNURVJTfSBsYXJnZXN0IGNsdXN0ZXJzYDtcbiAgICBjb25zdCB3aGF0ID0gdGhpcy5sZWdlbmQgPyBjYXBwZWQgOiB0aGlzLmhhc1NlbGVjdGlvbiA/ICd0aGUgc2VsZWN0ZWQgY2VsbHMnIDogJ2FsbCBjZWxscyc7XG4gICAgcmV0dXJuIChcbiAgICAgIGBEZW5zaXR5IGVzdGltYXRlIG92ZXIgJHt3aGF0fSDigJQgc21vb3RoZWQgYmV0d2VlbiB0aGUgaW1hZ2VkIHNlY3Rpb25zLCBgICtcbiAgICAgICdub3QgbWVhc3VyZWQgY2VsbHMuIExvd2VyIE9wYWNpdHkgdG8gcmVhZCB0aGUgZmllbGRzIHVuZGVyIHRoZSBjbG91ZC4nXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBNaXJyb3JzIHRoZSByZW5kZXJlcidzIGNhcCwgZm9yIHRoZSBub3RlIG9ubHkuICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IERFTlNJVFlfTUFYX0NMVVNURVJTID0gNjtcbiAgcHJvdGVjdGVkIG9uQ2xpcCh2YWx1ZTogW251bWJlciwgbnVtYmVyXSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHM/LnNldFZpZXdTdGF0ZSh7IHBlcmNlbnRpbGVDbGlwOiB2YWx1ZSB9KTtcbiAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cImRhdGFzZXQgYXMgZHNcIj5cbiAgPCEtLSBPYnNlcnZhdGlvbnM6IG9uZSBtYXJrZXIgcGVyIG9ic2VydmF0aW9uIChjZWxsIGNlbnRyb2lkLCBWaXNpdW0gc3BvdCksIGFuZCB3aGF0XG4gICAgIGNvbG91cnMgdGhlbS4gVGhlIGxlYWQgc2VjdGlvbiBmb3IgZGF0YXNldHMgd2l0aG91dCBjZWxsIG91dGxpbmVzLiAtLT5cbiAgPGRpdiBjbGFzcz1cInNjLXBhbmVsXCIgW2NsYXNzLm9wZW5dPVwib3BlblwiPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1wYW5lbC1oZWFkXCIgKGNsaWNrKT1cIm9wZW5DaGFuZ2UuZW1pdCghb3BlbilcIj5cbiAgICAgIDwhLS0gU2hvd3Mgb3IgaGlkZXMgdGhlIG9ic2VydmF0aW9ucywgYXMgd2hpY2hldmVyIHRoZSB0b2dnbGUgYmVsb3cgc2hvd3MgdGhlbSBhcy4gLS0+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJvYnNlcnZhdGlvbnNTaG93blwiXG4gICAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25TaG93T2JzZXJ2YXRpb25zKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIHBUb29sdGlwPVwiU2hvdyB0aGUgb2JzZXJ2YXRpb25zXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXBhbmVsLXRpdGxlXCI+T2JzZXJ2YXRpb25zPC9zcGFuPlxuICAgICAgPGkgY2xhc3M9XCJwaVwiIFtjbGFzcy5waS1jaGV2cm9uLWRvd25dPVwib3BlblwiIFtjbGFzcy5waS1jaGV2cm9uLXJpZ2h0XT1cIiFvcGVuXCI+PC9pPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1wYW5lbC1ib2R5XCIgKm5nSWY9XCJvcGVuXCI+XG4gICAgICA8IS0tIFdpdGggYSBjZWxsIHNlZ21lbnRhdGlvbjogc2hvd24gYXMgdGhlIG1hcmtlcnMgT1IgYXMgdGhlIGNlbGxzJyBvd24gc2hhcGVzLCBvbmUgYXQgYSB0aW1lLlxuICAgICAgICAgICBPbmUgY29sb3VyaW5nIGZvciBlaXRoZXIsIGJlbG93LiAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3cgc2Mtc2hvdy1hc1wiICpuZ0lmPVwiY2VsbHNBdmFpbGFibGVcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TaG93IGFzPC9zcGFuPlxuICAgICAgICA8cC1zZWxlY3RCdXR0b25cbiAgICAgICAgICBbb3B0aW9uc109XCJzaG93QXNPcHRpb25zXCJcbiAgICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICBbbmdNb2RlbF09XCJzaG93bkFzXCJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblNob3duQXMoJGV2ZW50KVwiXG4gICAgICAgICAgW2FsbG93RW1wdHldPVwiZmFsc2VcIlxuICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1idXR0b25zXCJcbiAgICAgICAgPjwvcC1zZWxlY3RCdXR0b24+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPHNwYXRpYWwtY29sb3ItYnlcbiAgICAgICAgW2NvbnRyb2xzXT1cImNvbnRyb2xzXCJcbiAgICAgICAgW2RhdGFzZXRdPVwiZHNcIlxuICAgICAgICBbdmlld109XCJ2aWV3XCJcbiAgICAgICAgW2dlbmVzXT1cImdlbmVzXCJcbiAgICAgICAgW2xlZ2VuZF09XCJsZWdlbmRcIlxuICAgICAgICBbY29sb3JCYXJDc3NdPVwiY29sb3JCYXJDc3NcIlxuICAgICAgICBbc2VsZWN0ZWRDYXRlZ29yeV09XCJzZWxlY3RlZENhdGVnb3J5XCJcbiAgICAgICAgW2NvbG9ybWFwT3B0aW9uc109XCJjb2xvcm1hcE9wdGlvbnNcIlxuICAgICAgICAoY2F0ZWdvcnlDbGlja2VkKT1cImNhdGVnb3J5Q2xpY2tlZC5lbWl0KCRldmVudClcIlxuICAgICAgPjwvc3BhdGlhbC1jb2xvci1ieT5cblxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImdlbmVzPy5zdGF0ZSQgfCBhc3luYyBhcyBnZW5lXCI+XG4gICAgICAgIDwhLS0gV2hpY2ggb2JzZXJ2YXRpb25zIGFyZSBkcmF3biBhdCBhbGwsIGJ5IHdoYXQgdGhleSBleHByZXNzLiBTZXZlcmFsIGdlbmVzIGF0XG4gICAgICAgIG9uY2UsIHVubGlrZSB0aGUgY29sb3VyLCB3aGljaCByZWFkcyBvbmU6IHBpY2tpbmcgZ2VuZXMgaGVyZSBoaWRlcyBldmVyeVxuICAgICAgICBvYnNlcnZhdGlvbiB0aGF0IGV4cHJlc3NlcyBub25lIG9mIHRoZW0gKG9yIG5vdCBhbGwgb2YgdGhlbSksIGFuZCBieSBkZWZhdWx0XG4gICAgICAgIGNvbG91cnMgKGFuZCwgaW4gMkQsIG1hcmtzKSBlYWNoIGRyYXduIG9uZSBieSBpdHMgZ2VuZS4gLS0+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJkcy5mZWF0dXJlc1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cInNjLWxibFwiIGZvcj1cInNjLXNob3ctZ2VuZXNcIj5TaG93IG9ic2VydmF0aW9ucyBleHByZXNzaW5nPC9sYWJlbD5cbiAgICAgICAgICA8cC1tdWx0aVNlbGVjdFxuICAgICAgICAgICAgaW5wdXRJZD1cInNjLXNob3ctZ2VuZXNcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwiZ2VuZS5vcHRpb25zXCJcbiAgICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXNcIlxuICAgICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uT2JzZXJ2YXRpb25HZW5lcygkZXZlbnQudmFsdWUpXCJcbiAgICAgICAgICAgIFtmaWx0ZXJdPVwidHJ1ZVwiXG4gICAgICAgICAgICBmaWx0ZXJCeT1cImxhYmVsXCJcbiAgICAgICAgICAgIFtyZXNldEZpbHRlck9uSGlkZV09XCJ0cnVlXCJcbiAgICAgICAgICAgIChvbkZpbHRlcik9XCJnZW5lcz8ub25GaWx0ZXIoJGV2ZW50LmZpbHRlcilcIlxuICAgICAgICAgICAgKG9uUGFuZWxTaG93KT1cImdlbmVzPy5lbnN1cmVMaXN0KClcIlxuICAgICAgICAgICAgW3ZpcnR1YWxTY3JvbGxdPVwiZ2VuZS5vcHRpb25zLmxlbmd0aCA+IGdlbmVWaXJ0dWFsU2Nyb2xsRnJvbVwiXG4gICAgICAgICAgICBbdmlydHVhbFNjcm9sbEl0ZW1TaXplXT1cIjMwXCJcbiAgICAgICAgICAgIFtzaG93VG9nZ2xlQWxsXT1cImZhbHNlXCJcbiAgICAgICAgICAgIFtzaG93Q2xlYXJdPVwidHJ1ZVwiXG4gICAgICAgICAgICBbZW1wdHlGaWx0ZXJNZXNzYWdlXT1cImdlbmUucmVtb3RlID8gJ05vIG1hdGNoIOKAlCBrZWVwIHR5cGluZycgOiAnTm8gbWF0Y2gnXCJcbiAgICAgICAgICAgIFtlbXB0eU1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnVHlwZSB0byBzZWFyY2ggZ2VuZXMnIDogJ05vIGdlbmVzJ1wiXG4gICAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJBbnkgZ2VuZSAoZXZlcnkgb2JzZXJ2YXRpb24pXCJcbiAgICAgICAgICAgIFtzZWxlY3RlZEl0ZW1zTGFiZWxdPVwiJ3swfSBnZW5lcydcIlxuICAgICAgICAgICAgW21heFNlbGVjdGVkTGFiZWxzXT1cIjNcIlxuICAgICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWZ1bGxcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDwhLS0gQSBwaWNrZWQgZ2VuZSBzaG93cyBpdHMgaWNvbiBpbiBpdHMgY29sb3VyOyBjbGlja2luZyBpdCBlZGl0cyB0aGVtLiAtLT5cbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBsZXQtb3B0aW9uIHBUZW1wbGF0ZT1cIml0ZW1cIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNjLW9icy1nZW5lLW9wdGlvblwiPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2Mtb2JzLWdlbmUtbmFtZVwiPnt7IG9wdGlvbi5sYWJlbCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXNPYnNlcnZhdGlvbkdlbmUob3B0aW9uLnZhbHVlKVwiPlxuICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImdlbmVNYXJrOyBjb250ZXh0OiB7ICRpbXBsaWNpdDogb3B0aW9uLnZhbHVlIH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDwvcC1tdWx0aVNlbGVjdD5cbiAgICAgICAgICA8cC1zZWxlY3RCdXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzLmxlbmd0aCA+IDFcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwibWF0Y2hPcHRpb25zXCJcbiAgICAgICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXNNYXRjaFwiXG4gICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbk9ic2VydmF0aW9uR2VuZXNNYXRjaCgkZXZlbnQpXCJcbiAgICAgICAgICAgIFthbGxvd0VtcHR5XT1cImZhbHNlXCJcbiAgICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1idXR0b25zXCJcbiAgICAgICAgICA+PC9wLXNlbGVjdEJ1dHRvbj5cbiAgICAgICAgICA8IS0tIFRoZSBwaWNrZWQgZ2VuZXM6IGVhY2ggb25lJ3MgaWNvbiBhbmQgY29sb3VyIChjbGljayB0byBlZGl0KSwgYW5kIGEgd2F5IG91dC4gLS0+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInNjLW9icy1nZW5lc1wiICpuZ0lmPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzLmxlbmd0aFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNjLW9icy1nZW5lLXJvd1wiICpuZ0Zvcj1cImxldCBnIG9mIHZpZXcub2JzZXJ2YXRpb25HZW5lczsgdHJhY2tCeTogdHJhY2tCeUdlbmVcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImdlbmVNYXJrOyBjb250ZXh0OiB7ICRpbXBsaWNpdDogZyB9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2Mtb2JzLWdlbmUtbmFtZVwiPnt7IGcgfX08L3NwYW4+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInNjLWljb24tYnRuXCJcbiAgICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidTdG9wIHNob3dpbmcgJyArIGdcIlxuICAgICAgICAgICAgICAgIHBUb29sdGlwPVwiUmVtb3ZlXCJcbiAgICAgICAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJyZW1vdmVPYnNlcnZhdGlvbkdlbmUoZylcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJwaSBwaS10aW1lc1wiPjwvaT5cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXMubGVuZ3RoXCI+XG4gICAgICAgICAgICA8cC1jaGVja2JveFxuICAgICAgICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXNDb2xvckJ5XCJcbiAgICAgICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uT2JzZXJ2YXRpb25HZW5lc0NvbG9yQnkoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgICAgICAgbGFiZWw9XCJDb2xvdXIgYnkgdGhlc2UgZ2VuZXNcIlxuICAgICAgICAgICAgICBwVG9vbHRpcD1cIkVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIGNvbG91ciAoYW5kLCBpbiAyRCwgdGhlIGljb24pIG9mIHRoZSBwaWNrZWQgZ2VuZSBpdCBleHByZXNzZXMgbW9zdCwgcmVsYXRpdmUgdG8gdGhhdCBnZW5lJ3MgaGlnaGVzdCB2YWx1ZS4gT2ZmLCBDb2xvdXIgYnkgYXBwbGllcy5cIlxuICAgICAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgICAgICAgPjwvcC1jaGVja2JveD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJ2aWV3Lm9ic2VydmF0aW9uR2VuZXMubGVuZ3RoXCI+e3sgZ2VuZUZpbHRlckhpbnQgfX08L3NtYWxsPlxuICAgICAgICAgIDwhLS0gVGhlIGZpbHRlciBpcyBuZXZlciBkcm9wcGVkIHNpbGVudGx5OiBhIGZhaWxlZCBleHByZXNzaW9uIHJlYWQga2VlcHMgdGhlIG9ic2VydmF0aW9uc1xuICAgICAgICAgICAgICAgIGFzIHRoZXkgd2VyZSBkcmF3biwgYW5kIHNheXMgc28uIC0tPlxuICAgICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnQgc2MtZXJyb3JcIiAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGggJiYgKGdlbmVGaWx0ZXJGYWlsZWQkIHwgYXN5bmMpXCI+XG4gICAgICAgICAgICBUaGUgZXhwcmVzc2lvbiBvZiB0aGUgcGlja2VkIGdlbmVzIGNvdWxkIG5vdCBiZSByZWFkLCBzbyB0aGUgb2JzZXJ2YXRpb25zIHN0aWxsIHNob3cgdGhlIHByZXZpb3VzXG4gICAgICAgICAgICBmaWx0ZXIuXG4gICAgICAgICAgICA8YSBocmVmPVwiXCIgKGNsaWNrKT1cIiRldmVudC5wcmV2ZW50RGVmYXVsdCgpOyByZXRyeUdlbmVGaWx0ZXIoKVwiPlRyeSBhZ2FpbjwvYT5cbiAgICAgICAgICA8L3NtYWxsPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIE1hcmtlcnM6IGhvdyB0aGV5IGFyZSBkcmF3bi4gLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWNlbGxzQXZhaWxhYmxlIHx8IHNob3duQXMgPT09ICdtYXJrZXJzJ1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc3ViaGVhZFwiPk1hcmtlcnM8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlBvaW50IHNpemU8L3NwYW4+XG4gICAgICAgICAgICA8cC1zbGlkZXJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5wb2ludFNjYWxlXCJcbiAgICAgICAgICAgICAgW21pbl09XCIwLjI1XCJcbiAgICAgICAgICAgICAgW21heF09XCI1XCJcbiAgICAgICAgICAgICAgW3N0ZXBdPVwiMC4yNVwiXG4gICAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvblBvaW50U2NhbGUoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgICA+PC9wLXNsaWRlcj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5wb2ludFNjYWxlIH19w5c8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5PcGFjaXR5PC9zcGFuPlxuICAgICAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInZpZXcub3BhY2l0eVwiXG4gICAgICAgICAgICAgIFttaW5dPVwiMC4xXCJcbiAgICAgICAgICAgICAgW21heF09XCIxXCJcbiAgICAgICAgICAgICAgW3N0ZXBdPVwiMC4wNVwiXG4gICAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvbk9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgICA+PC9wLXNsaWRlcj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5vcGFjaXR5IH19PC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIENlbGwgc2VnbWVudGF0aW9uczogaG93IHRoZSBjZWxscyBhcmUgZHJhd24sIHByb2plY3RlZCBieSB0aGUgZGlhbG9nLiAtLT5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJjZWxsc0F2YWlsYWJsZSAmJiBzaG93bkFzID09PSAnY2VsbHMnXCI+XG4gICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInNwYXRpYWwtY2VsbHMtcGFuZWxcIj48L25nLWNvbnRlbnQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBUaGUgc2VsZWN0ZWQgY2VsbCdzIChvciBjZWxsIHR5cGUncywgb3IgcmVnaW9uJ3MpIG9ic2VydmF0aW9ucywgYnkgZ3JvdXA6IHRocm91Z2ggdGhlXG4gICAgICAgICAgIHZvbHVtZSBpbiAzRCwgb24gdGhlIHBsYW5lIHNob3duIGluIDJELiAtLT5cbiAgICAgIDxzcGF0aWFsLXNlbGVjdGlvbi1vYnNlcnZhdGlvbnMgW2NvbnRyb2xzXT1cImNvbnRyb2xzXCIgW2lzM2RdPVwiaXMzZFwiPjwvc3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIE9ubHkgZm9yIGEgZ2VuZTogdGhlIG1hcCBkcmF3cyB0aGF0IGdlbmUncyBleHByZXNzaW9uIGFzIGEgZmllbGQuIEluIDJEXG4gICAgIGl0IGdvZXMgdW5kZXIgdGhlIGNlbGxzIG9mIHRoZSBkaXNwbGF5ZWQgcGxhbmU7IGluIDNEIGl0IGlzIG9uZSBzaGVldCBwZXJcbiAgICAgaW1hZ2VkIHNlY3Rpb24sIG9wdGlvbmFsbHkgc21vb3RoZWQgYWxvbmcgeiBpbnRvIGEgdm9sdW1lLiAtLT5cbiAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImNhbk1hcEdlbmVcIj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiR2VuZSBtYXAgKGV4cHJlc3Npb24gZmllbGQpXCJcbiAgICAgICAgW3BUb29sdGlwXT1cIlxuICAgICAgICAgIGlzM2RcbiAgICAgICAgICAgID8gJ0RyYXcgdGhpcyBnZW5lXFwncyBleHByZXNzaW9uIGFzIG9uZSBmaWVsZCBwZXIgaW1hZ2VkIHNlY3Rpb24g4oCUIGFuIGVzdGltYXRlIGJldHdlZW4gdGhlIGNlbGxzLCBlbXB0eSB3aGVyZSBub3RoaW5nIHdhcyBtZWFzdXJlZCdcbiAgICAgICAgICAgIDogJ0RyYXcgdGhpcyBnZW5lXFwncyBleHByZXNzaW9uIGFzIGEgc21vb3RoIGZpZWxkIFVOREVSIHRoZSBjZWxscyDigJQgYW4gZXN0aW1hdGUgYmV0d2VlbiB0aGVtLCB0cmFuc3BhcmVudCB3aGVyZSBub3RoaW5nIHdhcyBtZWFzdXJlZCdcbiAgICAgICAgXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPCEtLSAzRCBvbmx5OiBpbnRlcnBvbGF0aW5nIGFsb25nIHogdHVybnMgdGhlIG1lYXN1cmVkIHNoZWV0cyBpbnRvIGFuXG4gICAgICAgZXN0aW1hdGUsIHNvIGl0IGlzIGl0cyBvd24gZGVjaXNpb24gYW5kIGl0cyBvd24gbGFiZWwuIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiBpczNkXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBWb2x1bWVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwVm9sdW1lKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiVm9sdW1lIHJlbmRlcmluZyAoaW50ZXJwb2xhdGUgYWxvbmcgeilcIlxuICAgICAgICBwVG9vbHRpcD1cIlNtb290aCB0aGUgcGVyLXNlY3Rpb24gZmllbGRzIGludG8gYSBjb250aW51b3VzIHZvbHVtZSDigJQgYW4gRVNUSU1BVEUgYmV0d2VlbiB0aGUgaW1hZ2VkIHNlY3Rpb25zLCBub3QgbWVhc3VyZWQgdGlzc3VlXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPCEtLSBNZWFuaW5nbGVzcyB3aGlsZSBpbnRlcnBvbGF0aW5nOiBhIHZvbHVtZSBidWlsdCBmcm9tIG9uZSBzZWN0aW9uIHdvdWxkXG4gICAgICAgc21lYXIgdGhhdCBzbGlkZSB0aHJvdWdoIHRoZSBzcGVjaW1lbidzIHdob2xlIGRlcHRoLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXAgJiYgaXMzZCAmJiBpc1NlY3Rpb25lZCAmJiAhdmlldy5nZW5lTWFwVm9sdW1lXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJnZW5lTWFwT25lU2VjdGlvblwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBPbmVTZWN0aW9uKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiT25lIG1hcCBzZWN0aW9uIGF0IGEgdGltZVwiXG4gICAgICAgIHBUb29sdGlwPVwiRHJhdyBhIHNpbmdsZSBpbWFnZWQgc2VjdGlvbidzIGZpZWxkIGluc3RlYWQgb2YgdGhlIHdob2xlIHN0YWNrIG9mIHNoZWV0c1wiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiBpczNkICYmIGlzU2VjdGlvbmVkICYmICF2aWV3LmdlbmVNYXBWb2x1bWUgJiYgZ2VuZU1hcE9uZVNlY3Rpb25cIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+TWFwIHNlY3Rpb248L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwU2VjdGlvblwiXG4gICAgICAgIFttaW5dPVwiMFwiXG4gICAgICAgIFttYXhdPVwibGFzdFNlY3Rpb25cIlxuICAgICAgICBbc3RlcF09XCIxXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcFNlY3Rpb24oJGV2ZW50LnZhbHVlKVwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgZ2VuZU1hcFNlY3Rpb25MYWJlbCB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXBcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U21vb3RoaW5nPC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFNtb290aGluZ1wiXG4gICAgICAgIFttaW5dPVwiMC41XCJcbiAgICAgICAgW21heF09XCI0XCJcbiAgICAgICAgW3N0ZXBdPVwiMC41XCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcFNtb290aGluZygkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LmdlbmVNYXBTbW9vdGhpbmcgfX3Dlzwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXBcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+TWFwIG9wYWNpdHk8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwT3BhY2l0eVwiXG4gICAgICAgIFttaW5dPVwiMC4xXCJcbiAgICAgICAgW21heF09XCIxXCJcbiAgICAgICAgW3N0ZXBdPVwiMC4wNVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBPcGFjaXR5KCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcuZ2VuZU1hcE9wYWNpdHkgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiAhaXMzZFwiPlxuICAgICAgS2VybmVsLXdlaWdodGVkIG1lYW4gcGVyIGNlbGwsIG5vdCBhIHN1bSDigJQgc28gYSBjcm93ZGVkIHJlZ2lvbiBkb2VzIG5vdCBnbG93IGZvciBiZWluZyBjcm93ZGVkLiBUcmFuc3BhcmVudFxuICAgICAgd2hlcmUgbm8gY2VsbCB3YXMgbWVhc3VyZWQuIFR1cm4gdGhlIGNlbGxzJyBvd24gT3BhY2l0eSBkb3duIHRvIHJlYWQgdGhlIGZpZWxkIHVuZGVyIHRoZW0uXG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cInZpZXcuZ2VuZU1hcCAmJiBpczNkXCI+XG4gICAgICB7eyBnZW5lTWFwVm9sdW1lTm90ZSB9fVxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIDNEIG9ubHk6IHRoZSB2b2x1bWUsIHRoZSBjbG91ZCBhbmQgdGhlIGRlbnNpdHkgdm9sdW1lcyBvY2N1cHkgdGhlIHNhbWVcbiAgICAgc3BhY2UsIHNvIGVhY2ggaGlkZXMgdGhlIG90aGVycy4gSW5kZXBlbmRlbnQgdG9nZ2xlcywgYmVjYXVzZSB0aGUgdXNlZnVsXG4gICAgIHZpZXdzIGFyZSB0aGUgY29tYmluYXRpb25zIOKAlCB0aGUgZmllbGQgYWxvbmUsIG9uZSBzZWN0aW9uJ3MgY2VsbHMgb3ZlciBpdCxcbiAgICAgdGhlIGFuYXRvbXkgYWxvbmUuIC0tPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiaXMzZFwiPlxuICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U2hvdzwvc3Bhbj5cbiAgICA8IS0tIFRoZSByZWZlcmVuY2Ugdm9sdW1lIGlzIHRoZSBWb2x1bWUgc2VjdGlvbidzLCB0aGUgb2JzZXJ2YXRpb25zIHRoaXMgc2VjdGlvbidzIG93biBoZWFkZXJcbiAgICAgICBjaGVja2JveC4gLS0+XG4gICAgPCEtLSBPbmx5IGZvciBkYXRhIHRoYXQgcmVhbGx5IGlzIHNlY3Rpb25lZDsgYSBjb250aW51b3VzIHogaGFzIG5vIHNlY3Rpb25zXG4gICAgICAgdG8gc3RlcCB0aHJvdWdoLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LnNob3dQb2ludHMgJiYgaXNTZWN0aW9uZWRcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cIm9uZVNlY3Rpb25cIlxuICAgICAgICAob25DaGFuZ2UpPVwib25PbmVTZWN0aW9uKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiT25lIHNlY3Rpb24gYXQgYSB0aW1lXCJcbiAgICAgICAgcFRvb2x0aXA9XCJEcmF3IGEgc2luZ2xlIGltYWdlZCBzZWN0aW9uJ3MgY2VsbHMsIHNvIHRoZSBkZW5zaXR5IHZvbHVtZXMgYmV0d2VlbiB0aGUgc2VjdGlvbnMgc3RheSB2aXNpYmxlXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5zaG93UG9pbnRzICYmIGlzU2VjdGlvbmVkICYmIG9uZVNlY3Rpb25cIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U2VjdGlvbjwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnBvaW50U2VjdGlvblwiXG4gICAgICAgIFttaW5dPVwiMFwiXG4gICAgICAgIFttYXhdPVwibGFzdFNlY3Rpb25cIlxuICAgICAgICBbc3RlcF09XCIxXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uUG9pbnRTZWN0aW9uKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHNlY3Rpb25MYWJlbCB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImlzM2RcIj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25EZW5zaXR5Vm9sdW1lKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiQ2x1c3RlciBkZW5zaXR5IHZvbHVtZXNcIlxuICAgICAgICBwVG9vbHRpcD1cIlJheW1hcmNoIGVhY2ggY2x1c3RlciBhcyBhIHNtb290aCBkZW5zaXR5IGZpZWxkIOKAlCBhbiBFU1RJTUFURSBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMsIG5vdCBtZWFzdXJlZCBjZWxsc1wiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZGVuc2l0eVZvbHVtZVwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TbW9vdGhpbmc8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5kZW5zaXR5U21vb3RoaW5nXCJcbiAgICAgICAgW21pbl09XCIwLjVcIlxuICAgICAgICBbbWF4XT1cIjRcIlxuICAgICAgICBbc3RlcF09XCIwLjVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25EZW5zaXR5U21vb3RoaW5nKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcuZGVuc2l0eVNtb290aGluZyB9fcOXPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIj57eyBkZW5zaXR5Tm90ZSB9fTwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIENvbnRpbnVvdXMtb25seSBrbm9iczogbWVhbmluZ2xlc3MgZm9yIGEgY2F0ZWdvcmljYWwgcGFsZXR0ZS4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpc0NvbnRpbnVvdXNcIj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmxvZ1NjYWxlXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uTG9nU2NhbGUoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJMb2cgc2NhbGVcIlxuICAgICAgICBwVG9vbHRpcD1cIkNvdW50cyBjb2xsYXBzZSBhZ2FpbnN0IHRoZWlyIG91dGxpZXJzIG9uIGEgbGluZWFyIHJhbXBcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPkNsaXAgb3V0bGllcnM8L3NwYW4+XG4gICAgICA8cC1kcm9wZG93blxuICAgICAgICBbb3B0aW9uc109XCJjbGlwT3B0aW9uc1wiXG4gICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5wZXJjZW50aWxlQ2xpcFwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ2xpcCgkZXZlbnQpXCJcbiAgICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgcFRvb2x0aXA9XCJQZXJjZW50aWxlIHRoZSBjb250cmFzdCB3aW5kb3cgaXMgdGFrZW4gYXRcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1kcm9wZG93bj5cbiAgICAgIDwhLS0gUmVzZXJ2ZXMgdGhlIHJlYWRvdXQgY29sdW1uIHRoaXMgcm93IGhhcyBubyByZWFkb3V0IGZvciwgc28gdGhlXG4gICAgICAgICBjb250cm9sJ3MgcmlnaHQgZWRnZSBsaW5lcyB1cCB3aXRoIGV2ZXJ5IHNsaWRlcidzLiAtLT5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+PC9zcGFuPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIEEgZ2VuZSdzIGljb24gaW4gaXRzIGNvbG91cjogdGhlIGJ1dHRvbiB0aGF0IG9wZW5zIGl0cyBpY29uIGFuZCBjb2xvdXIgcGlja2VyLiAtLT5cbiAgPG5nLXRlbXBsYXRlICNnZW5lTWFyayBsZXQtZz5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwic2MtZ2VuZS1pY29uXCJcbiAgICAgIFtzdHlsZS5jb2xvcl09XCJnZW5lQ29sb3JPZihnKVwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidJY29uIGFuZCBjb2xvdXIgZm9yICcgKyBnXCJcbiAgICAgIHBUb29sdGlwPVwiSWNvbiBhbmQgY29sb3VyXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAoY2xpY2spPVwib3BlbkdlbmVTdHlsZSgkZXZlbnQsIGcsIGdlbmVQb3ApXCJcbiAgICA+XG4gICAgICA8c3ZnIHZpZXdCb3g9XCItMS4yIC0xLjIgMi40IDIuNFwiIGNsYXNzPVwic2MtZ2x5cGgtc3ZnXCI+XG4gICAgICAgIDxwb2x5Z29uIFthdHRyLnBvaW50c109XCJnbHlwaFBvaW50c09mKGcpXCI+PC9wb2x5Z29uPlxuICAgICAgPC9zdmc+XG4gICAgPC9idXR0b24+XG4gIDwvbmctdGVtcGxhdGU+XG4gIDxwLW92ZXJsYXlQYW5lbCAjZ2VuZVBvcCBzdHlsZUNsYXNzPVwic2MtZ2VuZS1zdHlsZVwiIGFwcGVuZFRvPVwiYm9keVwiPlxuICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJjb250ZW50XCI+XG4gICAgICA8c3BhdGlhbC1nZW5lLXN0eWxlXG4gICAgICAgICpuZ0lmPVwic3R5bGVHZW5lIGFzIGdcIlxuICAgICAgICBbZ2VuZV09XCJnXCJcbiAgICAgICAgd2hhdD1cIk9ic2VydmF0aW9uXCJcbiAgICAgICAgW2NvbG9yXT1cImdlbmVDb2xvck9mKGcpXCJcbiAgICAgICAgW2dseXBoXT1cImdlbmVHbHlwaE9mKGcpXCJcbiAgICAgICAgaWNvbkhpbnQ9XCJJY29ucyBzaG93IG9uIHRoZSAyRCBvYnNlcnZhdGlvbiBtYXJrZXJzLlwiXG4gICAgICAgIChjb2xvckNoYW5nZSk9XCJvbkdlbmVDb2xvcihnLCAkZXZlbnQpXCJcbiAgICAgICAgKGdseXBoQ2hhbmdlKT1cIm9uR2VuZUdseXBoKGcsICRldmVudClcIlxuICAgICAgICAocmVzZXRTdHlsZSk9XCJyZXNldEdlbmVTdHlsZShnKVwiXG4gICAgICA+PC9zcGF0aWFsLWdlbmUtc3R5bGU+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9wLW92ZXJsYXlQYW5lbD5cbjwvbmctY29udGFpbmVyPlxuIl19