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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +2 -1
  2. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  3. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +10 -8
  4. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +25 -7
  5. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +269 -0
  6. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +11 -4
  7. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +6 -7
  8. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +33 -8
  9. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +6 -2
  10. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +10 -6
  11. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +9 -5
  12. package/esm2022/lib/spatial/spatial-controls.facade.mjs +7 -4
  13. package/esm2022/lib/spatial/spatial-encoding.mjs +18 -1
  14. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +6 -2
  15. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +7 -3
  16. package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +7 -3
  17. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +21 -6
  18. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +61 -8
  19. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +3 -3
  20. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CYsPzX3J.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs} +533 -113
  21. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs.map +1 -0
  22. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DaZVXq1s.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs} +2 -2
  23. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DaZVXq1s.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs.map} +1 -1
  24. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  25. package/lib/contracts/display-types.d.ts +9 -2
  26. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  27. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +3 -3
  28. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +2 -0
  29. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +62 -0
  30. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +9 -2
  31. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +5 -6
  32. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +16 -3
  33. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +1 -1
  34. package/lib/spatial/spatial-encoding.d.ts +10 -0
  35. package/lib/spatial-controls/spatial-controls.component.d.ts +2 -0
  36. package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +3 -1
  37. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +7 -0
  38. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +14 -3
  39. package/package.json +2 -2
  40. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CYsPzX3J.mjs.map +0 -1
@@ -355,7 +355,7 @@ export class SpatialObservationsPanelComponent {
355
355
  this.controls?.setViewState({ percentileClip: value });
356
356
  }
357
357
  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. With cell outlines on, circles are only drawn where cells are too small on screen to\n 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"], outputs: ["colorChange", "glyphChange", "resetStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
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 }); }
359
359
  }
360
360
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialObservationsPanelComponent, decorators: [{
361
361
  type: Component,
@@ -371,7 +371,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
371
371
  TooltipModule,
372
372
  SpatialKeyComponent,
373
373
  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. With cell outlines on, circles are only drawn where cells are too small on screen to\n 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"] }]
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"] }]
375
375
  }], propDecorators: { controls: [{
376
376
  type: Input
377
377
  }], dataset: [{
@@ -399,4 +399,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
399
399
  }], categoryClicked: [{
400
400
  type: Output
401
401
  }] } });
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+XG4gICAgICAgIE9uZSBjaXJjbGUgcGVyIGNlbGwuIFdpdGggY2VsbCBvdXRsaW5lcyBvbiwgY2lyY2xlcyBhcmUgb25seSBkcmF3biB3aGVyZSBjZWxscyBhcmUgdG9vIHNtYWxsIG9uIHNjcmVlbiB0b1xuICAgICAgICBvdXRsaW5lLlxuICAgICAgPC9zbWFsbD5cbiAgICAgIDwhLS0gQ29sb3VyIHNvdXJjZS4gQ29sdW1uIGFuZCBnZW5lIGFyZSBtdXR1YWxseSBleGNsdXNpdmU6IHBpY2tpbmcgb25lXG4gICAgIGNsZWFycyB0aGUgb3RoZXIsIHNvIHdoYXQgZHJpdmVzIHRoZSBjb2xvdXJzIGlzIG5ldmVyIGFtYmlndW91cy4gLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiPlxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJzYy1sYmxcIiBmb3I9XCJzYy1jb2x1bW5cIj5Db2xvdXIgYnkgY29sdW1uPC9sYWJlbD5cbiAgICAgICAgPHAtZHJvcGRvd25cbiAgICAgICAgICBpbnB1dElkPVwic2MtY29sdW1uXCJcbiAgICAgICAgICBbb3B0aW9uc109XCJjb2x1bW5PcHRpb25zXCJcbiAgICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICBbbmdNb2RlbF09XCJzZWxlY3RlZENvbHVtblwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25Db2x1bW4oJGV2ZW50KVwiXG4gICAgICAgICAgcGxhY2Vob2xkZXI9XCJOb25lIChmbGF0IGNvbG91cilcIlxuICAgICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgc3R5bGVDbGFzcz1cInNjLWZ1bGxcIlxuICAgICAgICA+PC9wLWRyb3Bkb3duPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJnZW5lcz8uc3RhdGUkIHwgYXN5bmMgYXMgZ2VuZVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiZHMuZmVhdHVyZXNcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJzYy1sYmxcIiBmb3I9XCJzYy1nZW5lXCI+Q29sb3VyIGJ5IGdlbmU8L2xhYmVsPlxuICAgICAgICAgIDwhLS0gQSBmaWx0ZXJhYmxlIGRyb3Bkb3duLCBub3QgYSBmcmVlLXRleHQgYm94OiB0aGUgZ2VuZXMgYXJlIHZpc2libGUgYmVmb3JlXG4gICAgICAgYW55dGhpbmcgaXMgdHlwZWQsIGFuZCBlYWNoIGtleXN0cm9rZSBuYXJyb3dzIGEgbGlzdCB0aGUgdXNlciBjYW4gc2VlLlxuICAgICAgIFZpcnR1YWwtc2Nyb2xsZWQgYmVjYXVzZSBhIHRhcmdldGVkIHBhbmVsIHJ1bnMgdG8gYSBmZXcgdGhvdXNhbmQgbmFtZXMuIC0tPlxuICAgICAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgICAgICBpbnB1dElkPVwic2MtZ2VuZVwiXG4gICAgICAgICAgICBbb3B0aW9uc109XCJnZW5lLm9wdGlvbnNcIlxuICAgICAgICAgICAgb3B0aW9uTGFiZWw9XCJsYWJlbFwiXG4gICAgICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgICAgIFtuZ01vZGVsXT1cInNlbGVjdGVkR2VuZVwiXG4gICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkdlbmUoJGV2ZW50KVwiXG4gICAgICAgICAgICBbZmlsdGVyXT1cInRydWVcIlxuICAgICAgICAgICAgZmlsdGVyQnk9XCJsYWJlbFwiXG4gICAgICAgICAgICBbcmVzZXRGaWx0ZXJPbkhpZGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAob25GaWx0ZXIpPVwiZ2VuZXM/Lm9uRmlsdGVyKCRldmVudC5maWx0ZXIpXCJcbiAgICAgICAgICAgIChvblNob3cpPVwiZ2VuZXM/LmVuc3VyZUxpc3QoKVwiXG4gICAgICAgICAgICBbc2hvd0NsZWFyXT1cInRydWVcIlxuICAgICAgICAgICAgW3ZpcnR1YWxTY3JvbGxdPVwiZ2VuZS5vcHRpb25zLmxlbmd0aCA+IGdlbmVWaXJ0dWFsU2Nyb2xsRnJvbVwiXG4gICAgICAgICAgICBbdmlydHVhbFNjcm9sbEl0ZW1TaXplXT1cIjMwXCJcbiAgICAgICAgICAgIFtlbXB0eUZpbHRlck1lc3NhZ2VdPVwiZ2VuZS5yZW1vdGUgPyAnTm8gbWF0Y2gg4oCUIGtlZXAgdHlwaW5nJyA6ICdObyBtYXRjaCdcIlxuICAgICAgICAgICAgW2VtcHR5TWVzc2FnZV09XCJnZW5lLnJlbW90ZSA/ICdUeXBlIHRvIHNlYXJjaCBnZW5lcycgOiAnTm8gZ2VuZXMnXCJcbiAgICAgICAgICAgIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cIlNlYXJjaCB7eyBkcy5mZWF0dXJlcy5jb3VudCB8IG51bWJlciB9fSBnZW5lc+KAplwiXG4gICAgICAgICAgICBzdHlsZUNsYXNzPVwic2MtZnVsbFwiXG4gICAgICAgICAgPjwvcC1kcm9wZG93bj5cbiAgICAgICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJnZW5lLmZhaWxlZFwiPkdlbmUgbG9va3VwIGZhaWxlZC48L3NtYWxsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFdoaWNoIG9ic2VydmF0aW9ucyBhcmUgZHJhd24gYXQgYWxsLCBieSB3aGF0IHRoZXkgZXhwcmVzcy4gU2V2ZXJhbCBnZW5lcyBhdFxuICAgICAgIG9uY2UsIHVubGlrZSB0aGUgY29sb3VyLCB3aGljaCByZWFkcyBvbmU6IHBpY2tpbmcgZ2VuZXMgaGVyZSBoaWRlcyBldmVyeVxuICAgICAgIG9ic2VydmF0aW9uIHRoYXQgZXhwcmVzc2VzIG5vbmUgb2YgdGhlbSAob3Igbm90IGFsbCBvZiB0aGVtKSwgYW5kIGJ5IGRlZmF1bHRcbiAgICAgICBjb2xvdXJzIChhbmQsIGluIDJELCBtYXJrcykgZWFjaCBkcmF3biBvbmUgYnkgaXRzIGdlbmUuIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VjdGlvblwiICpuZ0lmPVwiZHMuZmVhdHVyZXNcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJzYy1sYmxcIiBmb3I9XCJzYy1zaG93LWdlbmVzXCI+U2hvdyBvYnNlcnZhdGlvbnMgZXhwcmVzc2luZzwvbGFiZWw+XG4gICAgICAgICAgPHAtbXVsdGlTZWxlY3RcbiAgICAgICAgICAgIGlucHV0SWQ9XCJzYy1zaG93LWdlbmVzXCJcbiAgICAgICAgICAgIFtvcHRpb25zXT1cImdlbmUub3B0aW9uc1wiXG4gICAgICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgICAgIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzXCJcbiAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvbk9ic2VydmF0aW9uR2VuZXMoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgICBbZmlsdGVyXT1cInRydWVcIlxuICAgICAgICAgICAgZmlsdGVyQnk9XCJsYWJlbFwiXG4gICAgICAgICAgICBbcmVzZXRGaWx0ZXJPbkhpZGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAob25GaWx0ZXIpPVwiZ2VuZXM/Lm9uRmlsdGVyKCRldmVudC5maWx0ZXIpXCJcbiAgICAgICAgICAgIChvblBhbmVsU2hvdyk9XCJnZW5lcz8uZW5zdXJlTGlzdCgpXCJcbiAgICAgICAgICAgIFt2aXJ0dWFsU2Nyb2xsXT1cImdlbmUub3B0aW9ucy5sZW5ndGggPiBnZW5lVmlydHVhbFNjcm9sbEZyb21cIlxuICAgICAgICAgICAgW3ZpcnR1YWxTY3JvbGxJdGVtU2l6ZV09XCIzMFwiXG4gICAgICAgICAgICBbc2hvd1RvZ2dsZUFsbF09XCJmYWxzZVwiXG4gICAgICAgICAgICBbc2hvd0NsZWFyXT1cInRydWVcIlxuICAgICAgICAgICAgW2VtcHR5RmlsdGVyTWVzc2FnZV09XCJnZW5lLnJlbW90ZSA/ICdObyBtYXRjaCDigJQga2VlcCB0eXBpbmcnIDogJ05vIG1hdGNoJ1wiXG4gICAgICAgICAgICBbZW1wdHlNZXNzYWdlXT1cImdlbmUucmVtb3RlID8gJ1R5cGUgdG8gc2VhcmNoIGdlbmVzJyA6ICdObyBnZW5lcydcIlxuICAgICAgICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiQW55IGdlbmUgKGV2ZXJ5IG9ic2VydmF0aW9uKVwiXG4gICAgICAgICAgICBbc2VsZWN0ZWRJdGVtc0xhYmVsXT1cIid7MH0gZ2VuZXMnXCJcbiAgICAgICAgICAgIFttYXhTZWxlY3RlZExhYmVsc109XCIzXCJcbiAgICAgICAgICAgIHN0eWxlQ2xhc3M9XCJzYy1mdWxsXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8IS0tIEEgcGlja2VkIGdlbmUgc2hvd3MgaXRzIGljb24gaW4gaXRzIGNvbG91cjsgY2xpY2tpbmcgaXQgZWRpdHMgdGhlbS4gLS0+XG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgbGV0LW9wdGlvbiBwVGVtcGxhdGU9XCJpdGVtXCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzYy1vYnMtZ2VuZS1vcHRpb25cIj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLW9icy1nZW5lLW5hbWVcIj57eyBvcHRpb24ubGFiZWwgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImlzT2JzZXJ2YXRpb25HZW5lKG9wdGlvbi52YWx1ZSlcIj5cbiAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJnZW5lTWFyazsgY29udGV4dDogeyAkaW1wbGljaXQ6IG9wdGlvbi52YWx1ZSB9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8L3AtbXVsdGlTZWxlY3Q+XG4gICAgICAgICAgPHAtc2VsZWN0QnV0dG9uXG4gICAgICAgICAgICAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGggPiAxXCJcbiAgICAgICAgICAgIFtvcHRpb25zXT1cIm1hdGNoT3B0aW9uc1wiXG4gICAgICAgICAgICBvcHRpb25MYWJlbD1cImxhYmVsXCJcbiAgICAgICAgICAgIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzTWF0Y2hcIlxuICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25PYnNlcnZhdGlvbkdlbmVzTWF0Y2goJGV2ZW50KVwiXG4gICAgICAgICAgICBbYWxsb3dFbXB0eV09XCJmYWxzZVwiXG4gICAgICAgICAgICBzdHlsZUNsYXNzPVwic2MtYnV0dG9uc1wiXG4gICAgICAgICAgPjwvcC1zZWxlY3RCdXR0b24+XG4gICAgICAgICAgPCEtLSBUaGUgcGlja2VkIGdlbmVzOiBlYWNoIG9uZSdzIGljb24gYW5kIGNvbG91ciAoY2xpY2sgdG8gZWRpdCksIGFuZCBhIHdheSBvdXQuIC0tPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzYy1vYnMtZ2VuZXNcIiAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGhcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzYy1vYnMtZ2VuZS1yb3dcIiAqbmdGb3I9XCJsZXQgZyBvZiB2aWV3Lm9ic2VydmF0aW9uR2VuZXM7IHRyYWNrQnk6IHRyYWNrQnlHZW5lXCI+XG4gICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJnZW5lTWFyazsgY29udGV4dDogeyAkaW1wbGljaXQ6IGcgfVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLW9icy1nZW5lLW5hbWVcIj57eyBnIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJzYy1pY29uLWJ0blwiXG4gICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInU3RvcCBzaG93aW5nICcgKyBnXCJcbiAgICAgICAgICAgICAgICBwVG9vbHRpcD1cIlJlbW92ZVwiXG4gICAgICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwicmVtb3ZlT2JzZXJ2YXRpb25HZW5lKGcpXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwicGkgcGktdGltZXNcIj48L2k+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzLmxlbmd0aFwiPlxuICAgICAgICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzQ29sb3JCeVwiXG4gICAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvbk9ic2VydmF0aW9uR2VuZXNDb2xvckJ5KCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgICAgICAgIGxhYmVsPVwiQ29sb3VyIGJ5IHRoZXNlIGdlbmVzXCJcbiAgICAgICAgICAgICAgcFRvb2x0aXA9XCJFYWNoIG9ic2VydmF0aW9uIGluIHRoZSBjb2xvdXIgKGFuZCwgaW4gMkQsIHRoZSBpY29uKSBvZiB0aGUgcGlja2VkIGdlbmUgaXQgZXhwcmVzc2VzIG1vc3QsIHJlbGF0aXZlIHRvIHRoYXQgZ2VuZSdzIGhpZ2hlc3QgdmFsdWUuIE9mZiwgQ29sb3VyIGJ5IGNvbHVtbiBvciBnZW5lIGFwcGxpZXMuXCJcbiAgICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgICAgICAgID48L3AtY2hlY2tib3g+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwidmlldy5vYnNlcnZhdGlvbkdlbmVzLmxlbmd0aFwiPnt7IGdlbmVGaWx0ZXJIaW50IH19PC9zbWFsbD5cbiAgICAgICAgICA8IS0tIFRoZSBmaWx0ZXIgaXMgbmV2ZXIgZHJvcHBlZCBzaWxlbnRseTogYSBmYWlsZWQgZXhwcmVzc2lvbiByZWFkIGtlZXBzIHRoZSBvYnNlcnZhdGlvbnNcbiAgICAgICAgICAgICAgIGFzIHRoZXkgd2VyZSBkcmF3biwgYW5kIHNheXMgc28uIC0tPlxuICAgICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnQgc2MtZXJyb3JcIiAqbmdJZj1cInZpZXcub2JzZXJ2YXRpb25HZW5lcy5sZW5ndGggJiYgKGdlbmVGaWx0ZXJGYWlsZWQkIHwgYXN5bmMpXCI+XG4gICAgICAgICAgICBUaGUgZXhwcmVzc2lvbiBvZiB0aGUgcGlja2VkIGdlbmVzIGNvdWxkIG5vdCBiZSByZWFkLCBzbyB0aGUgb2JzZXJ2YXRpb25zIHN0aWxsIHNob3cgdGhlIHByZXZpb3VzXG4gICAgICAgICAgICBmaWx0ZXIuXG4gICAgICAgICAgICA8YSBocmVmPVwiXCIgKGNsaWNrKT1cIiRldmVudC5wcmV2ZW50RGVmYXVsdCgpOyByZXRyeUdlbmVGaWx0ZXIoKVwiPlRyeSBhZ2FpbjwvYT5cbiAgICAgICAgICA8L3NtYWxsPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8c3BhdGlhbC1rZXlcbiAgICAgICAgW2NvbnRyb2xzXT1cImNvbnRyb2xzXCJcbiAgICAgICAgW2RhdGFzZXRdPVwiZHNcIlxuICAgICAgICBbdmlld109XCJ2aWV3XCJcbiAgICAgICAgW2xlZ2VuZF09XCJsZWdlbmRcIlxuICAgICAgICBbY29sb3JCYXJDc3NdPVwiY29sb3JCYXJDc3NcIlxuICAgICAgICBbc2VsZWN0ZWRDYXRlZ29yeV09XCJzZWxlY3RlZENhdGVnb3J5XCJcbiAgICAgICAgW2NvbG9ybWFwT3B0aW9uc109XCJjb2xvcm1hcE9wdGlvbnNcIlxuICAgICAgICAoY2F0ZWdvcnlDbGlja2VkKT1cImNhdGVnb3J5Q2xpY2tlZC5lbWl0KCRldmVudClcIlxuICAgICAgPjwvc3BhdGlhbC1rZXk+XG5cbiAgICAgIDwhLS0gRGlzcGxheSAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlBvaW50IHNpemU8L3NwYW4+XG4gICAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnBvaW50U2NhbGVcIlxuICAgICAgICAgICAgW21pbl09XCIwLjI1XCJcbiAgICAgICAgICAgIFttYXhdPVwiNVwiXG4gICAgICAgICAgICBbc3RlcF09XCIwLjI1XCJcbiAgICAgICAgICAgIChvbkNoYW5nZSk9XCJvblBvaW50U2NhbGUoJGV2ZW50LnZhbHVlKVwiXG4gICAgICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LnBvaW50U2NhbGUgfX3Dlzwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPk9wYWNpdHk8L3NwYW4+XG4gICAgICAgICAgPHAtc2xpZGVyXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJ2aWV3Lm9wYWNpdHlcIlxuICAgICAgICAgICAgW21pbl09XCIwLjFcIlxuICAgICAgICAgICAgW21heF09XCIxXCJcbiAgICAgICAgICAgIFtzdGVwXT1cIjAuMDVcIlxuICAgICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uT3BhY2l0eSgkZXZlbnQudmFsdWUpXCJcbiAgICAgICAgICA+PC9wLXNsaWRlcj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcub3BhY2l0eSB9fTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBPbmx5IGZvciBhIGdlbmU6IHRoZSBtYXAgZHJhd3MgdGhhdCBnZW5lJ3MgZXhwcmVzc2lvbiBhcyBhIGZpZWxkLiBJbiAyRFxuICAgICBpdCBnb2VzIHVuZGVyIHRoZSBjZWxscyBvZiB0aGUgZGlzcGxheWVkIHBsYW5lOyBpbiAzRCBpdCBpcyBvbmUgc2hlZXQgcGVyXG4gICAgIGltYWdlZCBzZWN0aW9uLCBvcHRpb25hbGx5IHNtb290aGVkIGFsb25nIHogaW50byBhIHZvbHVtZS4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJjYW5NYXBHZW5lXCI+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcCgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIkdlbmUgbWFwIChleHByZXNzaW9uIGZpZWxkKVwiXG4gICAgICAgIFtwVG9vbHRpcF09XCJcbiAgICAgICAgICBpczNkXG4gICAgICAgICAgICA/ICdEcmF3IHRoaXMgZ2VuZVxcJ3MgZXhwcmVzc2lvbiBhcyBvbmUgZmllbGQgcGVyIGltYWdlZCBzZWN0aW9uIOKAlCBhbiBlc3RpbWF0ZSBiZXR3ZWVuIHRoZSBjZWxscywgZW1wdHkgd2hlcmUgbm90aGluZyB3YXMgbWVhc3VyZWQnXG4gICAgICAgICAgICA6ICdEcmF3IHRoaXMgZ2VuZVxcJ3MgZXhwcmVzc2lvbiBhcyBhIHNtb290aCBmaWVsZCBVTkRFUiB0aGUgY2VsbHMg4oCUIGFuIGVzdGltYXRlIGJldHdlZW4gdGhlbSwgdHJhbnNwYXJlbnQgd2hlcmUgbm90aGluZyB3YXMgbWVhc3VyZWQnXG4gICAgICAgIFwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDwhLS0gM0Qgb25seTogaW50ZXJwb2xhdGluZyBhbG9uZyB6IHR1cm5zIHRoZSBtZWFzdXJlZCBzaGVldHMgaW50byBhblxuICAgICAgIGVzdGltYXRlLCBzbyBpdCBpcyBpdHMgb3duIGRlY2lzaW9uIGFuZCBpdHMgb3duIGxhYmVsLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXAgJiYgaXMzZFwiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5nZW5lTWFwVm9sdW1lXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uR2VuZU1hcFZvbHVtZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIlZvbHVtZSByZW5kZXJpbmcgKGludGVycG9sYXRlIGFsb25nIHopXCJcbiAgICAgICAgcFRvb2x0aXA9XCJTbW9vdGggdGhlIHBlci1zZWN0aW9uIGZpZWxkcyBpbnRvIGEgY29udGludW91cyB2b2x1bWUg4oCUIGFuIEVTVElNQVRFIGJldHdlZW4gdGhlIGltYWdlZCBzZWN0aW9ucywgbm90IG1lYXN1cmVkIHRpc3N1ZVwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDwhLS0gTWVhbmluZ2xlc3Mgd2hpbGUgaW50ZXJwb2xhdGluZzogYSB2b2x1bWUgYnVpbHQgZnJvbSBvbmUgc2VjdGlvbiB3b3VsZFxuICAgICAgIHNtZWFyIHRoYXQgc2xpZGUgdGhyb3VnaCB0aGUgc3BlY2ltZW4ncyB3aG9sZSBkZXB0aC4gLS0+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwICYmIGlzM2QgJiYgaXNTZWN0aW9uZWQgJiYgIXZpZXcuZ2VuZU1hcFZvbHVtZVwiPlxuICAgICAgPHAtY2hlY2tib3hcbiAgICAgICAgW2JpbmFyeV09XCJ0cnVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwiZ2VuZU1hcE9uZVNlY3Rpb25cIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwT25lU2VjdGlvbigkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICBsYWJlbD1cIk9uZSBtYXAgc2VjdGlvbiBhdCBhIHRpbWVcIlxuICAgICAgICBwVG9vbHRpcD1cIkRyYXcgYSBzaW5nbGUgaW1hZ2VkIHNlY3Rpb24ncyBmaWVsZCBpbnN0ZWFkIG9mIHRoZSB3aG9sZSBzdGFjayBvZiBzaGVldHNcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXAgJiYgaXMzZCAmJiBpc1NlY3Rpb25lZCAmJiAhdmlldy5nZW5lTWFwVm9sdW1lICYmIGdlbmVNYXBPbmVTZWN0aW9uXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPk1hcCBzZWN0aW9uPC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcFNlY3Rpb25cIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cImxhc3RTZWN0aW9uXCJcbiAgICAgICAgW3N0ZXBdPVwiMVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBTZWN0aW9uKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IGdlbmVNYXBTZWN0aW9uTGFiZWwgfX08L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlNtb290aGluZzwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmdlbmVNYXBTbW9vdGhpbmdcIlxuICAgICAgICBbbWluXT1cIjAuNVwiXG4gICAgICAgIFttYXhdPVwiNFwiXG4gICAgICAgIFtzdGVwXT1cIjAuNVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvbkdlbmVNYXBTbW9vdGhpbmcoJGV2ZW50LnZhbHVlKVwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy5nZW5lTWFwU21vb3RoaW5nIH19w5c8L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5nZW5lTWFwXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPk1hcCBvcGFjaXR5PC9zcGFuPlxuICAgICAgPHAtc2xpZGVyXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuZ2VuZU1hcE9wYWNpdHlcIlxuICAgICAgICBbbWluXT1cIjAuMVwiXG4gICAgICAgIFttYXhdPVwiMVwiXG4gICAgICAgIFtzdGVwXT1cIjAuMDVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25HZW5lTWFwT3BhY2l0eSgkZXZlbnQudmFsdWUpXCJcbiAgICAgID48L3Atc2xpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy12YWxcIj57eyB2aWV3LmdlbmVNYXBPcGFjaXR5IH19PC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXAgJiYgIWlzM2RcIj5cbiAgICAgIEtlcm5lbC13ZWlnaHRlZCBtZWFuIHBlciBjZWxsLCBub3QgYSBzdW0g4oCUIHNvIGEgY3Jvd2RlZCByZWdpb24gZG9lcyBub3QgZ2xvdyBmb3IgYmVpbmcgY3Jvd2RlZC4gVHJhbnNwYXJlbnRcbiAgICAgIHdoZXJlIG5vIGNlbGwgd2FzIG1lYXN1cmVkLiBUdXJuIHRoZSBjZWxscycgb3duIE9wYWNpdHkgZG93biB0byByZWFkIHRoZSBmaWVsZCB1bmRlciB0aGVtLlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJ2aWV3LmdlbmVNYXAgJiYgaXMzZFwiPlxuICAgICAge3sgZ2VuZU1hcFZvbHVtZU5vdGUgfX1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSAzRCBvbmx5OiB0aGUgdm9sdW1lLCB0aGUgY2xvdWQgYW5kIHRoZSBkZW5zaXR5IHZvbHVtZXMgb2NjdXB5IHRoZSBzYW1lXG4gICAgIHNwYWNlLCBzbyBlYWNoIGhpZGVzIHRoZSBvdGhlcnMuIEluZGVwZW5kZW50IHRvZ2dsZXMsIGJlY2F1c2UgdGhlIHVzZWZ1bFxuICAgICB2aWV3cyBhcmUgdGhlIGNvbWJpbmF0aW9ucyDigJQgdGhlIGZpZWxkIGFsb25lLCBvbmUgc2VjdGlvbidzIGNlbGxzIG92ZXIgaXQsXG4gICAgIHRoZSBhbmF0b215IGFsb25lLiAtLT5cbiAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImlzM2RcIj5cbiAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPlNob3c8L3NwYW4+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwiZHMudm9sdW1lXCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnNob3dWb2x1bWVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25TaG93Vm9sdW1lKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiUmVmZXJlbmNlIHZvbHVtZVwiXG4gICAgICAgIHBUb29sdGlwPVwiVGhlIHJlZ2lzdGVyZWQgYW5hdG9teSB0aGUgb2JzZXJ2YXRpb25zIHNpdCBpblwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDwhLS0gVGhlIGJhY2tkcm9wJ3Mgb3duIG9wYWNpdHk6IHJlYWRpbmcgdGhlIGNsb3VkIG9yIGEgZGVuc2l0eSBmaWVsZFxuICAgICAgIHRocm91Z2ggdGhlIGFuYXRvbXkgbWVhbnMgdHVybmluZyB0aGUgYW5hdG9teSBkb3duLCBub3QgdGhlIGRhdGEuIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cImRzLnZvbHVtZSAmJiB2aWV3LnNob3dWb2x1bWVcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+Vm9sdW1lIG9wYWNpdHk8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy52b2x1bWVPcGFjaXR5XCJcbiAgICAgICAgW21pbl09XCIwLjA1XCJcbiAgICAgICAgW21heF09XCIxXCJcbiAgICAgICAgW3N0ZXBdPVwiMC4wNVwiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvblZvbHVtZU9wYWNpdHkoJGV2ZW50LnZhbHVlKVwiXG4gICAgICA+PC9wLXNsaWRlcj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+e3sgdmlldy52b2x1bWVPcGFjaXR5IH19PC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cInZpZXcuc2hvd1BvaW50c1wiXG4gICAgICAgIChvbkNoYW5nZSk9XCJvblNob3dQb2ludHMoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJPYnNlcnZhdGlvbnNcIlxuICAgICAgICBwVG9vbHRpcD1cIlRoZSBtZWFzdXJlZCBjZWxscy4gSGlkZSB0aGVtIHRvIHJlYWQgdGhlIGRlbnNpdHkgdm9sdW1lcyB1bmRlcm5lYXRoXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPCEtLSBPbmx5IGZvciBkYXRhIHRoYXQgcmVhbGx5IGlzIHNlY3Rpb25lZDsgYSBjb250aW51b3VzIHogaGFzIG5vIHNlY3Rpb25zXG4gICAgICAgdG8gc3RlcCB0aHJvdWdoLiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCIgKm5nSWY9XCJ2aWV3LnNob3dQb2ludHMgJiYgaXNTZWN0aW9uZWRcIj5cbiAgICAgIDxwLWNoZWNrYm94XG4gICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXG4gICAgICAgIFtuZ01vZGVsXT1cIm9uZVNlY3Rpb25cIlxuICAgICAgICAob25DaGFuZ2UpPVwib25PbmVTZWN0aW9uKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiT25lIHNlY3Rpb24gYXQgYSB0aW1lXCJcbiAgICAgICAgcFRvb2x0aXA9XCJEcmF3IGEgc2luZ2xlIGltYWdlZCBzZWN0aW9uJ3MgY2VsbHMsIHNvIHRoZSBkZW5zaXR5IHZvbHVtZXMgYmV0d2VlbiB0aGUgc2VjdGlvbnMgc3RheSB2aXNpYmxlXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgID48L3AtY2hlY2tib3g+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInNjLXJvd1wiICpuZ0lmPVwidmlldy5zaG93UG9pbnRzICYmIGlzU2VjdGlvbmVkICYmIG9uZVNlY3Rpb25cIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtbGJsXCI+U2VjdGlvbjwvc3Bhbj5cbiAgICAgIDxwLXNsaWRlclxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LnBvaW50U2VjdGlvblwiXG4gICAgICAgIFttaW5dPVwiMFwiXG4gICAgICAgIFttYXhdPVwibGFzdFNlY3Rpb25cIlxuICAgICAgICBbc3RlcF09XCIxXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uUG9pbnRTZWN0aW9uKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHNlY3Rpb25MYWJlbCB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cInNjLXNlY3Rpb25cIiAqbmdJZj1cImlzM2RcIj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25EZW5zaXR5Vm9sdW1lKCRldmVudC5jaGVja2VkKVwiXG4gICAgICAgIGxhYmVsPVwiQ2x1c3RlciBkZW5zaXR5IHZvbHVtZXNcIlxuICAgICAgICBwVG9vbHRpcD1cIlJheW1hcmNoIGVhY2ggY2x1c3RlciBhcyBhIHNtb290aCBkZW5zaXR5IGZpZWxkIOKAlCBhbiBFU1RJTUFURSBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnMsIG5vdCBtZWFzdXJlZCBjZWxsc1wiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICA+PC9wLWNoZWNrYm94PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1yb3dcIiAqbmdJZj1cInZpZXcuZGVuc2l0eVZvbHVtZVwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJzYy1sYmxcIj5TbW9vdGhpbmc8L3NwYW4+XG4gICAgICA8cC1zbGlkZXJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5kZW5zaXR5U21vb3RoaW5nXCJcbiAgICAgICAgW21pbl09XCIwLjVcIlxuICAgICAgICBbbWF4XT1cIjRcIlxuICAgICAgICBbc3RlcF09XCIwLjVcIlxuICAgICAgICAob25DaGFuZ2UpPVwib25EZW5zaXR5U21vb3RoaW5nKCRldmVudC52YWx1ZSlcIlxuICAgICAgPjwvcC1zbGlkZXI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLXZhbFwiPnt7IHZpZXcuZGVuc2l0eVNtb290aGluZyB9fcOXPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJ2aWV3LmRlbnNpdHlWb2x1bWVcIj57eyBkZW5zaXR5Tm90ZSB9fTwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIENvbnRpbnVvdXMtb25seSBrbm9iczogbWVhbmluZ2xlc3MgZm9yIGEgY2F0ZWdvcmljYWwgcGFsZXR0ZS4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzYy1zZWN0aW9uXCIgKm5nSWY9XCJpc0NvbnRpbnVvdXNcIj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8cC1jaGVja2JveFxuICAgICAgICBbYmluYXJ5XT1cInRydWVcIlxuICAgICAgICBbbmdNb2RlbF09XCJ2aWV3LmxvZ1NjYWxlXCJcbiAgICAgICAgKG9uQ2hhbmdlKT1cIm9uTG9nU2NhbGUoJGV2ZW50LmNoZWNrZWQpXCJcbiAgICAgICAgbGFiZWw9XCJMb2cgc2NhbGVcIlxuICAgICAgICBwVG9vbHRpcD1cIkNvdW50cyBjb2xsYXBzZSBhZ2FpbnN0IHRoZWlyIG91dGxpZXJzIG9uIGEgbGluZWFyIHJhbXBcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1jaGVja2JveD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwic2Mtcm93XCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInNjLWxibFwiPkNsaXAgb3V0bGllcnM8L3NwYW4+XG4gICAgICA8cC1kcm9wZG93blxuICAgICAgICBbb3B0aW9uc109XCJjbGlwT3B0aW9uc1wiXG4gICAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgICBvcHRpb25WYWx1ZT1cInZhbHVlXCJcbiAgICAgICAgW25nTW9kZWxdPVwidmlldy5wZXJjZW50aWxlQ2xpcFwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ2xpcCgkZXZlbnQpXCJcbiAgICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgcFRvb2x0aXA9XCJQZXJjZW50aWxlIHRoZSBjb250cmFzdCB3aW5kb3cgaXMgdGFrZW4gYXRcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgICAgPjwvcC1kcm9wZG93bj5cbiAgICAgIDwhLS0gUmVzZXJ2ZXMgdGhlIHJlYWRvdXQgY29sdW1uIHRoaXMgcm93IGhhcyBubyByZWFkb3V0IGZvciwgc28gdGhlXG4gICAgICAgICBjb250cm9sJ3MgcmlnaHQgZWRnZSBsaW5lcyB1cCB3aXRoIGV2ZXJ5IHNsaWRlcidzLiAtLT5cbiAgICAgIDxzcGFuIGNsYXNzPVwic2MtdmFsXCI+PC9zcGFuPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIEEgZ2VuZSdzIGljb24gaW4gaXRzIGNvbG91cjogdGhlIGJ1dHRvbiB0aGF0IG9wZW5zIGl0cyBpY29uIGFuZCBjb2xvdXIgcGlja2VyLiAtLT5cbiAgPG5nLXRlbXBsYXRlICNnZW5lTWFyayBsZXQtZz5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwic2MtZ2VuZS1pY29uXCJcbiAgICAgIFtzdHlsZS5jb2xvcl09XCJnZW5lQ29sb3JPZihnKVwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidJY29uIGFuZCBjb2xvdXIgZm9yICcgKyBnXCJcbiAgICAgIHBUb29sdGlwPVwiSWNvbiBhbmQgY29sb3VyXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAoY2xpY2spPVwib3BlbkdlbmVTdHlsZSgkZXZlbnQsIGcsIGdlbmVQb3ApXCJcbiAgICA+XG4gICAgICA8c3ZnIHZpZXdCb3g9XCItMS4yIC0xLjIgMi40IDIuNFwiIGNsYXNzPVwic2MtZ2x5cGgtc3ZnXCI+XG4gICAgICAgIDxwb2x5Z29uIFthdHRyLnBvaW50c109XCJnbHlwaFBvaW50c09mKGcpXCI+PC9wb2x5Z29uPlxuICAgICAgPC9zdmc+XG4gICAgPC9idXR0b24+XG4gIDwvbmctdGVtcGxhdGU+XG4gIDxwLW92ZXJsYXlQYW5lbCAjZ2VuZVBvcCBzdHlsZUNsYXNzPVwic2MtZ2VuZS1zdHlsZVwiIGFwcGVuZFRvPVwiYm9keVwiPlxuICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJjb250ZW50XCI+XG4gICAgICA8c3BhdGlhbC1nZW5lLXN0eWxlXG4gICAgICAgICpuZ0lmPVwic3R5bGVHZW5lIGFzIGdcIlxuICAgICAgICBbZ2VuZV09XCJnXCJcbiAgICAgICAgd2hhdD1cIk9ic2VydmF0aW9uXCJcbiAgICAgICAgW2NvbG9yXT1cImdlbmVDb2xvck9mKGcpXCJcbiAgICAgICAgW2dseXBoXT1cImdlbmVHbHlwaE9mKGcpXCJcbiAgICAgICAgaWNvbkhpbnQ9XCJJY29ucyBzaG93IG9uIHRoZSAyRCBvYnNlcnZhdGlvbiBtYXJrZXJzLlwiXG4gICAgICAgIChjb2xvckNoYW5nZSk9XCJvbkdlbmVDb2xvcihnLCAkZXZlbnQpXCJcbiAgICAgICAgKGdseXBoQ2hhbmdlKT1cIm9uR2VuZUdseXBoKGcsICRldmVudClcIlxuICAgICAgICAocmVzZXRTdHlsZSk9XCJyZXNldEdlbmVTdHlsZShnKVwiXG4gICAgICA+PC9zcGF0aWFsLWdlbmUtc3R5bGU+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9wLW92ZXJsYXlQYW5lbD5cbjwvbmctY29udGFpbmVyPlxuIl19
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==