UNPKG

@edugouvfr/ngx-dsfr-ext

Version:

NgxDsfrExt est une extension au package @edugouvfr/ngx-dsfr (portage Angular des éléments DSFR)

216 lines 44.8 kB
import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, EventEmitter, Input, Output, ViewEncapsulation, inject, } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { EduCheckboxComponent } from '../shared/components/checkbox/checkbox.component'; import { TreeFocusManager } from '../shared/utils/tree/tree-focus-manager'; import { TreeSelectManager } from '../shared/utils/tree/tree-select-manager'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; export class DsfrTreeComponent { constructor(elementRef) { this.elementRef = elementRef; /** Un tableau de nœuds d'arbre */ this.value = []; /** Indique le changement d'état d'un nœud. */ this.nodeSelect = new EventEmitter(); /** Indique un changement sur la sélection. Renvoie le noeud concerné et liste des noeuds (feuilles) sélectionnés */ this.selectionChange = new EventEmitter(); this.isModeSelectable = false; this.cd = inject(ChangeDetectorRef); this.focusManager = new TreeFocusManager(this); this.selectManager = new TreeSelectManager(this); this._viewNodes = []; // noeuds internes avec état (selected, expand) } get selectionMode() { return this.selectManager.selectionMode; } /** Synonyme de value, mais plus explicite. */ get nodes() { return this._viewNodes; } /** Mode de sélection, `undefined` par défaut. */ set selectionMode(value) { this.selectManager.selectionMode = value; this.isModeSelectable = this.selectManager.isSelectable(); } /** * Permet la récupération du modèle interne de l'arbre. * * @returns Un tableau de DsfrNode[]. */ getTreeState() { return this.nodes; } /** * Permet la récupération de la sélection courante de l'arbre. * * @returns Un tableau de DsfrNode[]. */ getSelection() { return this.selectManager.selectedNodes; } /** @internal */ ngAfterViewInit() { // Mise à jour des tabindex this.focusManager.initTabindex(); } /** @internal */ ngOnChanges({ value }) { if (value) { if (this._viewNodes.length === 0) { // première initialisation this._viewNodes = this.selectManager.init(this.value); } else { // mise à jour avec conservation des états d'expansion et de sélection (si noeuds fournis avec identifiants) this._viewNodes = this.selectManager.updateNodesContent(this.value, this._viewNodes, 1); } } } /** @internal */ getCheckboxId(node) { return 'cb' + node.id; } /** @internal */ isCheckboxMode() { return this.selectManager.isCheckboxMode(); } /** @internal */ isSelectable() { return this.selectManager.isSelectable(); } /** * Ouvre tous les nœuds de l'arborescence. */ /** @internal */ onNodeButton(node) { this.focusManager.doToggleExpand(node); } /** * Sélection du label d'un nœud lorsque que l'on a un label sans checkbox. Si le mode est `selectable` : * - on inverse la sélection, uniquement du nœud, on émet un événement. */ /** @internal */ onNodeSelect(node, event) { // const targetElt = <HTMLElement>event.target; // ne pas activer si la target est le bouton expand/collapse //if (!targetElt.classList?.contains('tree-button')) { const nodeElt = event.currentTarget; this.selectManager.doSelectNode(node, nodeElt); //} } /** * Gestion des touches de navigation. * On transfère la gestion au composant qui gère la liste. */ /** @internal */ onNodeKeydown(node, event) { this.focusManager.doKeyEvent(node, event, true); } // -- TreeFocusable -------------------------------------------------------------------------------------------------- /** Ouvre tous les nœuds de l'arborescence. */ /** @internal */ expandAll() { this.focusManager.expandAll(this.nodes); this.cd.markForCheck(); } /** Ferme tous les nœuds de l'arborescence. */ /** @internal */ collapseAll() { this.focusManager.collapseAll(this.nodes); this.cd.markForCheck(); } /** @internal */ doNodeDefaultAction(node, event) { const nodeElt = event.currentTarget; this.selectManager.doSelectNode(node, nodeElt); } /** * Trouver tous les noeuds <li> visibles (possèdent une hauteur minimale). * * @internal */ findVisibleNodesElt() { const nativeElt = this.elementRef.nativeElement; const nodeList = nativeElt.querySelectorAll('.tree-node-content'); const nodesArr = []; nodeList.forEach((n) => nodesArr.push(n)); return nodesArr; } /** Retourne l'élément avec focus ou undefined. */ /** @internal */ findFocusElement() { return this.elementRef.nativeElement.querySelector('.tree-node-content:focus') || undefined; } /** * Mise a jour du contenu de l'arbre. Conserve l'état (nœuds étendus et sélectionnés) si l'id des nœuds est renseigné. * @internal */ updateContent() { this._viewNodes = this.selectManager.updateNodesContent(this.value, this._viewNodes, 1); this.cd.markForCheck(); } /** * Réinitialise l'état de l'arbre (nœuds étendus et sélectionnés) * @internal */ reinitializeState() { this._viewNodes = this.selectManager.init(this.value); this.cd.markForCheck(); } // -- TreeSelectable ------------------------------------------------------------------------------------------------- /** Sélectionne / désélectionne tous les nœuds en mode multiple ou checkbox. * @internal */ selectAll(selected = true) { this.selectManager.selectAllNodes(this.nodes, selected); this.cd.markForCheck(); this.selectionChange.emit({ node: null, nodesSelected: this.selectManager.selectedNodes }); } /** Emission d'un événement pour un nœud. * @internal */ notifySelectEvent(node) { // la variable 'nodeContent' correspond à node sans les enfants const { children, ...nodeContent } = node; this.nodeSelect.emit(nodeContent); this.selectionChange.emit({ node: nodeContent, nodesSelected: this.selectManager.selectedNodes.map((a) => a), }); } /** * Met à jour la propriété `indeterminate` de la checkbox `node.inputId` en fonction de la valeur de 'node.selected'. * @param node Nœud de l'arbre */ /** @internal */ updateIndeterminate(node) { const nativeElt = this.elementRef.nativeElement; const checkboxId = this.getCheckboxId(node); const inputElt = nativeElt?.querySelector('#' + checkboxId); if (inputElt) inputElt.indeterminate = node.selected === undefined; } /** @internal */ trackById(index, item) { return item.id; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrTreeComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DsfrTreeComponent, isStandalone: true, selector: "dsfr-ext-tree, dsfrx-tree", inputs: { value: "value", selectionMode: "selectionMode" }, outputs: { nodeSelect: "nodeSelect", selectionChange: "selectionChange" }, queries: [{ propertyName: "nodeTemplate", first: true, predicate: ["nodeTemplate"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"dsfrx-tree-component\">\n <ng-container\n [ngTemplateOutlet]=\"nodesTemplate\"\n [ngTemplateOutletContext]=\"{ nodes: nodes || [], root: true }\"></ng-container>\n</div>\n\n<ng-template #nodesTemplate let-nodes=\"nodes\" let-root=\"root\">\n <ul\n class=\"tree-node\"\n [attr.aria-multiselectable]=\"root ? selectionMode === 'multiple' || selectionMode === 'checkbox' : null\"\n [attr.role]=\"root ? 'tree' : 'group'\">\n @for (node of nodes; track trackById(i, node); let i = $index) {\n @if (!node.hidden) {\n <li\n role=\"treeitem\"\n tabindex=\"-1\"\n class=\"tree-node-content\"\n (keydown)=\"onNodeKeydown(node, $event)\"\n [attr.aria-selected]=\"isModeSelectable ? node.selected : null\"\n [attr.aria-level]=\"node.ariaLevel\"\n [attr.aria-setsize]=\"node.ariaSize\"\n [attr.aria-posinset]=\"i + 1\"\n [class.leaf]=\"!node.children\"\n [attr.aria-expanded]=\"node.children ? node.expanded ?? false : null\">\n <ng-container\n [ngTemplateOutlet]=\"defaultNodeTemplate\"\n [ngTemplateOutletContext]=\"{ node: node }\"></ng-container>\n </li>\n }\n }\n </ul>\n</ng-template>\n\n<ng-template #defaultNodeTemplate let-node=\"node\">\n <div class=\"tree-node-content-inside\" [class.selectable]=\"isModeSelectable\" [class.selected]=\"node.selected\">\n <!-- Bouton collapse / expand -->\n @if (node.children) {\n <span\n class=\"tree-button\"\n [class]=\"!node.expanded ? 'fr-icon-arrow-right-s-line' : 'fr-icon-arrow-down-s-line'\"\n (click)=\"onNodeButton(node)\"></span>\n }\n\n @if (!isCheckboxMode()) {\n <div (click)=\"isModeSelectable ? onNodeSelect(node, $event) : onNodeButton(node)\" class=\"tree-node-label\">\n <!-- Label seul -->\n @if (!nodeTemplate) {\n <span class=\"fr-label\">\n @if (node.icon) {\n <span aria-hidden=\"true\" [class]=\"node.icon + ' fr-icon--sm'\">&nbsp;</span>\n }\n {{ node.label }}\n </span>\n } @else {\n <!-- Label seul et template custom -->\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node }\"></ng-container>\n }\n </div>\n } @else {\n <div class=\"tree-node-label\">\n <!-- Checkbox + label -->\n <dsfr-ext-checkbox\n [id]=\"getCheckboxId(node)\"\n [disabled]=\"node.disabled\"\n [tabIndex]=\"-1\"\n [icon]=\"node.icon\"\n [label]=\"node.label\"\n (checkboxClick)=\"onNodeSelect(node, $event)\"\n [selected]=\"node.selected\"></dsfr-ext-checkbox>\n <!-- Template custom additionnel -->\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node }\"></ng-container>\n </div>\n }\n </div>\n\n <!-- Children -->\n @if (node.children && node.expanded) {\n <ng-container\n [ngTemplateOutlet]=\"nodesTemplate\"\n [ngTemplateOutletContext]=\"{ nodes: node.children, root: false }\"></ng-container>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.dsfrx-tree-component{padding-top:1px;margin-bottom:.5rem}.dsfrx-tree-component ul.tree-node{list-style:none;margin-top:.25rem}.dsfrx-tree-component ul.tree-node li.leaf{margin-left:1.5rem}.dsfrx-tree-component .tree-node-label{width:100%;display:inline-block}.dsfrx-tree-component .tree-node-content{padding-bottom:0}.dsfrx-tree-component .tree-node-content-inside{--hover-tint: var(--hover);display:flex;align-items:center;margin-bottom:var(--li-bottom);padding-left:.25rem;margin-left:-.25rem;position:relative}.dsfrx-tree-component .tree-node-content-inside .fr-checkbox-group--sm{left:0;z-index:9;margin-top:0}.dsfrx-tree-component .tree-node-content-inside .tree-button{margin-left:-.25rem;padding:.5rem .25rem;cursor:pointer;margin-top:0}.dsfrx-tree-component .tree-node-content-inside .tree-node-label .fr-label{cursor:pointer;padding:.5rem .25rem;box-sizing:border-box}.dsfrx-tree-component .tree-node-content-inside .tree-node-label .fr-checkbox-group--sm input[type=checkbox]+label:before{margin-top:.75rem}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)):after{mask-image:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path d=\"m10 15.172 9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95Z\"/></svg>');content:\"\";--icon-size: 1rem;height:var(--icon-size);mask-size:100% 100%;width:var(--icon-size);background-color:var(--text-action-high-blue-france);right:1rem;position:absolute}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label{outline:1px solid var(--border-action-high-blue-france);background-color:var(--background-open-blue-france)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label:hover{background-color:var(--background-open-blue-france-hover)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label .fr-label{color:var(--text-action-high-blue-france)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label:has(.fr-checkbox-group){outline:none}.dsfrx-tree-component .tree-node-content-inside[tabindex=\"0\"]:focus{outline-style:solid!important}.dsfrx-tree-component .tree-node-content-inside.selectable:not(.selected) .tree-node-label .fr-label:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content-inside.selectable .tree-button:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content-inside:focus{outline-offset:1px;outline:#0a76f6 solid 2px;width:calc(100% - 3px)}.dsfrx-tree-component .tree-node-content-inside button{padding:0 2px 0 0}.dsfrx-tree-component .tree-node-content .tree-node-content-inside:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content.leaf .tree-node-content-inside:not(.selectable) .tree-node-label .fr-label{cursor:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: EduCheckboxComponent, selector: "dsfr-ext-checkbox, dsfrx-checkbox", inputs: ["id", "label", "selected", "tabIndex", "disabled", "icon"], outputs: ["checkboxClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrTreeComponent, decorators: [{ type: Component, args: [{ selector: 'dsfr-ext-tree, dsfrx-tree', encapsulation: ViewEncapsulation.None, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, EduCheckboxComponent], template: "<div class=\"dsfrx-tree-component\">\n <ng-container\n [ngTemplateOutlet]=\"nodesTemplate\"\n [ngTemplateOutletContext]=\"{ nodes: nodes || [], root: true }\"></ng-container>\n</div>\n\n<ng-template #nodesTemplate let-nodes=\"nodes\" let-root=\"root\">\n <ul\n class=\"tree-node\"\n [attr.aria-multiselectable]=\"root ? selectionMode === 'multiple' || selectionMode === 'checkbox' : null\"\n [attr.role]=\"root ? 'tree' : 'group'\">\n @for (node of nodes; track trackById(i, node); let i = $index) {\n @if (!node.hidden) {\n <li\n role=\"treeitem\"\n tabindex=\"-1\"\n class=\"tree-node-content\"\n (keydown)=\"onNodeKeydown(node, $event)\"\n [attr.aria-selected]=\"isModeSelectable ? node.selected : null\"\n [attr.aria-level]=\"node.ariaLevel\"\n [attr.aria-setsize]=\"node.ariaSize\"\n [attr.aria-posinset]=\"i + 1\"\n [class.leaf]=\"!node.children\"\n [attr.aria-expanded]=\"node.children ? node.expanded ?? false : null\">\n <ng-container\n [ngTemplateOutlet]=\"defaultNodeTemplate\"\n [ngTemplateOutletContext]=\"{ node: node }\"></ng-container>\n </li>\n }\n }\n </ul>\n</ng-template>\n\n<ng-template #defaultNodeTemplate let-node=\"node\">\n <div class=\"tree-node-content-inside\" [class.selectable]=\"isModeSelectable\" [class.selected]=\"node.selected\">\n <!-- Bouton collapse / expand -->\n @if (node.children) {\n <span\n class=\"tree-button\"\n [class]=\"!node.expanded ? 'fr-icon-arrow-right-s-line' : 'fr-icon-arrow-down-s-line'\"\n (click)=\"onNodeButton(node)\"></span>\n }\n\n @if (!isCheckboxMode()) {\n <div (click)=\"isModeSelectable ? onNodeSelect(node, $event) : onNodeButton(node)\" class=\"tree-node-label\">\n <!-- Label seul -->\n @if (!nodeTemplate) {\n <span class=\"fr-label\">\n @if (node.icon) {\n <span aria-hidden=\"true\" [class]=\"node.icon + ' fr-icon--sm'\">&nbsp;</span>\n }\n {{ node.label }}\n </span>\n } @else {\n <!-- Label seul et template custom -->\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node }\"></ng-container>\n }\n </div>\n } @else {\n <div class=\"tree-node-label\">\n <!-- Checkbox + label -->\n <dsfr-ext-checkbox\n [id]=\"getCheckboxId(node)\"\n [disabled]=\"node.disabled\"\n [tabIndex]=\"-1\"\n [icon]=\"node.icon\"\n [label]=\"node.label\"\n (checkboxClick)=\"onNodeSelect(node, $event)\"\n [selected]=\"node.selected\"></dsfr-ext-checkbox>\n <!-- Template custom additionnel -->\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: node }\"></ng-container>\n </div>\n }\n </div>\n\n <!-- Children -->\n @if (node.children && node.expanded) {\n <ng-container\n [ngTemplateOutlet]=\"nodesTemplate\"\n [ngTemplateOutletContext]=\"{ nodes: node.children, root: false }\"></ng-container>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.dsfrx-tree-component{padding-top:1px;margin-bottom:.5rem}.dsfrx-tree-component ul.tree-node{list-style:none;margin-top:.25rem}.dsfrx-tree-component ul.tree-node li.leaf{margin-left:1.5rem}.dsfrx-tree-component .tree-node-label{width:100%;display:inline-block}.dsfrx-tree-component .tree-node-content{padding-bottom:0}.dsfrx-tree-component .tree-node-content-inside{--hover-tint: var(--hover);display:flex;align-items:center;margin-bottom:var(--li-bottom);padding-left:.25rem;margin-left:-.25rem;position:relative}.dsfrx-tree-component .tree-node-content-inside .fr-checkbox-group--sm{left:0;z-index:9;margin-top:0}.dsfrx-tree-component .tree-node-content-inside .tree-button{margin-left:-.25rem;padding:.5rem .25rem;cursor:pointer;margin-top:0}.dsfrx-tree-component .tree-node-content-inside .tree-node-label .fr-label{cursor:pointer;padding:.5rem .25rem;box-sizing:border-box}.dsfrx-tree-component .tree-node-content-inside .tree-node-label .fr-checkbox-group--sm input[type=checkbox]+label:before{margin-top:.75rem}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)):after{mask-image:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path d=\"m10 15.172 9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95Z\"/></svg>');content:\"\";--icon-size: 1rem;height:var(--icon-size);mask-size:100% 100%;width:var(--icon-size);background-color:var(--text-action-high-blue-france);right:1rem;position:absolute}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label{outline:1px solid var(--border-action-high-blue-france);background-color:var(--background-open-blue-france)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label:hover{background-color:var(--background-open-blue-france-hover)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label .fr-label{color:var(--text-action-high-blue-france)}.dsfrx-tree-component .tree-node-content-inside.selectable.selected:not(:has(dsfr-ext-checkbox)) .tree-node-label:has(.fr-checkbox-group){outline:none}.dsfrx-tree-component .tree-node-content-inside[tabindex=\"0\"]:focus{outline-style:solid!important}.dsfrx-tree-component .tree-node-content-inside.selectable:not(.selected) .tree-node-label .fr-label:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content-inside.selectable .tree-button:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content-inside:focus{outline-offset:1px;outline:#0a76f6 solid 2px;width:calc(100% - 3px)}.dsfrx-tree-component .tree-node-content-inside button{padding:0 2px 0 0}.dsfrx-tree-component .tree-node-content .tree-node-content-inside:hover{background:var(--hover-tint)}.dsfrx-tree-component .tree-node-content.leaf .tree-node-content-inside:not(.selectable) .tree-node-label .fr-label{cursor:inherit}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { value: [{ type: Input }], nodeTemplate: [{ type: ContentChild, args: ['nodeTemplate', { static: true }] }], nodeSelect: [{ type: Output }], selectionChange: [{ type: Output }], selectionMode: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZHNmci1leHQvc3JjL2xpYi90cmVlL3RyZWUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWRzZnItZXh0L3NyYy9saWIvdHJlZS90cmVlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsWUFBWSxFQUVaLFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxFQUdOLGlCQUFpQixFQUNqQixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtEQUFrRCxDQUFDO0FBRXhGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBaUIsTUFBTSx5Q0FBeUMsQ0FBQztBQUMxRixPQUFPLEVBQUUsaUJBQWlCLEVBQWtCLE1BQU0sMENBQTBDLENBQUM7OztBQW1CN0YsTUFBTSxPQUFPLGlCQUFpQjtJQTBCNUIsWUFBb0IsVUFBc0I7UUFBdEIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQXpCMUMsa0NBQWtDO1FBQ3pCLFVBQUssR0FBZSxFQUFFLENBQUM7UUFNaEMsOENBQThDO1FBQ3BDLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBaUIsQ0FBQztRQUV6RCxvSEFBb0g7UUFDMUcsb0JBQWUsR0FBRyxJQUFJLFlBQVksRUFBcUIsQ0FBQztRQU14RCxxQkFBZ0IsR0FBWSxLQUFLLENBQUM7UUFFcEMsT0FBRSxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRS9CLGlCQUFZLEdBQUcsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQyxrQkFBYSxHQUFHLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsZUFBVSxHQUFtQixFQUFFLENBQUMsQ0FBQywrQ0FBK0M7SUFFM0MsQ0FBQztJQUU5QyxJQUFJLGFBQWE7UUFDZixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDO0lBQzFDLENBQUM7SUFFRCw4Q0FBOEM7SUFDOUMsSUFBSSxLQUFLO1FBQ1AsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRCxpREFBaUQ7SUFDakQsSUFBYSxhQUFhLENBQUMsS0FBd0I7UUFDakQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzVELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksWUFBWTtRQUNqQixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxZQUFZO1FBQ2pCLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUM7SUFDMUMsQ0FBQztJQUVELGdCQUFnQjtJQUNoQixlQUFlO1FBQ2IsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDbkMsQ0FBQztJQUVELGdCQUFnQjtJQUNoQixXQUFXLENBQUMsRUFBRSxLQUFLLEVBQWlCO1FBQ2xDLElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUNqQywwQkFBMEI7Z0JBQzFCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3hELENBQUM7aUJBQU0sQ0FBQztnQkFDTiw0R0FBNEc7Z0JBQzVHLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUYsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsZ0JBQWdCO0lBQ2hCLGFBQWEsQ0FBQyxJQUFjO1FBQzFCLE9BQU8sSUFBSSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVELGdCQUFnQjtJQUNoQixjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzdDLENBQUM7SUFFRCxnQkFBZ0I7SUFDaEIsWUFBWTtRQUNWLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxnQkFBZ0I7SUFDaEIsWUFBWSxDQUFDLElBQWM7UUFDekIsSUFBSSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7T0FHRztJQUNILGdCQUFnQjtJQUNoQixZQUFZLENBQUMsSUFBYyxFQUFFLEtBQVk7UUFDdkMsK0NBQStDO1FBQy9DLDREQUE0RDtRQUM1RCxzREFBc0Q7UUFDdEQsTUFBTSxPQUFPLEdBQWdCLEtBQUssQ0FBQyxhQUFhLENBQUM7UUFDakQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQy9DLEdBQUc7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCO0lBQ2hCLGFBQWEsQ0FBQyxJQUFjLEVBQUUsS0FBb0I7UUFDaEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQsc0hBQXNIO0lBRXRILDhDQUE4QztJQUM5QyxnQkFBZ0I7SUFDaEIsU0FBUztRQUNQLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsRUFBRSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRCwrQ0FBK0M7SUFDL0MsZ0JBQWdCO0lBQ2hCLFdBQVc7UUFDVCxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQsZ0JBQWdCO0lBQ2hCLG1CQUFtQixDQUFDLElBQWMsRUFBRSxLQUFZO1FBQzlDLE1BQU0sT0FBTyxHQUFnQixLQUFLLENBQUMsYUFBYSxDQUFDO1FBQ2pELElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILG1CQUFtQjtRQUNqQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQztRQUNoRCxNQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNsRSxNQUFNLFFBQVEsR0FBa0IsRUFBRSxDQUFDO1FBRW5DLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFjLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUV2RCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsa0RBQWtEO0lBQ2xELGdCQUFnQjtJQUNoQixnQkFBZ0I7UUFDZCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLFNBQVMsQ0FBQztJQUM5RixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsYUFBYTtRQUNYLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDeEYsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCO1FBQ2YsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQsc0hBQXNIO0lBRXRIOztPQUVHO0lBQ0gsU0FBUyxDQUFDLFFBQVEsR0FBRyxJQUFJO1FBQ3ZCLElBQUksQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBRUQ7O09BRUc7SUFDSCxpQkFBaUIsQ0FBQyxJQUFjO1FBQzlCLCtEQUErRDtRQUMvRCxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsV0FBVyxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQzFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFnQixXQUFXLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQztZQUN4QixJQUFJLEVBQUUsV0FBVztZQUNqQixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFhLENBQUM7U0FDMUUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUVILGdCQUFnQjtJQUNoQixtQkFBbUIsQ0FBQyxJQUFjO1FBQ2hDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDO1FBQ2hELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsTUFBTSxRQUFRLEdBQXFCLFNBQVMsRUFBRSxhQUFhLENBQUMsR0FBRyxHQUFHLFVBQVUsQ0FBQyxDQUFDO1FBRTlFLElBQUksUUFBUTtZQUFFLFFBQVEsQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLFFBQVEsS0FBSyxTQUFTLENBQUM7SUFDckUsQ0FBQztJQUVELGdCQUFnQjtJQUNoQixTQUFTLENBQUMsS0FBYSxFQUFFLElBQWM7UUFDckMsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2pCLENBQUM7K0dBcE9VLGlCQUFpQjttR0FBakIsaUJBQWlCLHlXQ3hDOUIsbW1HQWtGQSxvaEdENUNZLFlBQVkscU1BQUUsV0FBVywrQkFBRSxvQkFBb0I7OzRGQUU5QyxpQkFBaUI7a0JBVDdCLFNBQVM7K0JBQ0UsMkJBQTJCLGlCQUd0QixpQkFBaUIsQ0FBQyxJQUFJLGNBQ3pCLElBQUksbUJBQ0MsdUJBQXVCLENBQUMsTUFBTSxXQUN0QyxDQUFDLFlBQVksRUFBRSxXQUFXLEVBQUUsb0JBQW9CLENBQUM7K0VBSWpELEtBQUs7c0JBQWIsS0FBSztnQkFJMEMsWUFBWTtzQkFBM0QsWUFBWTt1QkFBQyxjQUFjLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUdwQyxVQUFVO3NCQUFuQixNQUFNO2dCQUdHLGVBQWU7c0JBQXhCLE1BQU07Z0JBMEJNLGFBQWE7c0JBQXpCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgaW5qZWN0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgRWR1Q2hlY2tib3hDb21wb25lbnQgfSBmcm9tICcuLi9zaGFyZWQvY29tcG9uZW50cy9jaGVja2JveC9jaGVja2JveC5jb21wb25lbnQnO1xuaW1wb3J0IHsgRHNmclNlbGVjdGlvbk1vZGUgfSBmcm9tICcuLi9zaGFyZWQvbW9kZWxzL3NlbGVjdGlvbi1tb2RlLnR5cGUnO1xuaW1wb3J0IHsgVHJlZUZvY3VzTWFuYWdlciwgVHJlZUZvY3VzYWJsZSB9IGZyb20gJy4uL3NoYXJlZC91dGlscy90cmVlL3RyZWUtZm9jdXMtbWFuYWdlcic7XG5pbXBvcnQgeyBUcmVlU2VsZWN0TWFuYWdlciwgVHJlZVNlbGVjdGFibGUgfSBmcm9tICcuLi9zaGFyZWQvdXRpbHMvdHJlZS90cmVlLXNlbGVjdC1tYW5hZ2VyJztcbmltcG9ydCB7IERzZnJOb2RlLCBEc2ZyVmlld05vZGUgfSBmcm9tICcuLi9zaGFyZWQvdXRpbHMvdHJlZS90cmVlLm1vZGVsJztcblxuLyoqIMOJdsOpbmVtZW50IMOpbWlzIGxvcnMgZGUgbGEgc8OpbGVjdGlvbiBkJ3VuIG7Fk3VkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBEc2ZyTm9kZUV2ZW50IGV4dGVuZHMgT21pdDxEc2ZyTm9kZSwgJ2NoaWxkcmVuJz4ge31cbmV4cG9ydCBpbnRlcmZhY2UgRHNmclRyZWVOb2RlRXZlbnQge1xuICBub2RlOiBEc2ZyTm9kZUV2ZW50IHwgbnVsbDtcbiAgbm9kZXNTZWxlY3RlZDogRHNmck5vZGVbXTtcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZHNmci1leHQtdHJlZSwgZHNmcngtdHJlZScsXG4gIHRlbXBsYXRlVXJsOiAnLi90cmVlLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vdHJlZS5jb21wb25lbnQuc2NzcyddLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgRm9ybXNNb2R1bGUsIEVkdUNoZWNrYm94Q29tcG9uZW50XSxcbn0pXG5leHBvcnQgY2xhc3MgRHNmclRyZWVDb21wb25lbnQgaW1wbGVtZW50cyBUcmVlRm9jdXNhYmxlLCBUcmVlU2VsZWN0YWJsZSwgQWZ0ZXJWaWV3SW5pdCwgT25DaGFuZ2VzIHtcbiAgLyoqIFVuIHRhYmxlYXUgZGUgbsWTdWRzIGQnYXJicmUgKi9cbiAgQElucHV0KCkgdmFsdWU6IERzZnJOb2RlW10gPSBbXTtcblxuICAvKiogVGVtcGxhdGUgcG91ciBwZXJzb25uYWxpc2VyIGxlIGNvbnRlbnUgZCd1biBub2V1ZC5cbiAgICogTGUgc2xvdCBzJ2Fqb3V0ZSBhcHLDqHMgbGUgbGFiZWwgZW4gbW9kZSBjaGVja2JveCBldCBsZSByZW1wbGFjZSBkYW5zIGxlcyBhdXRyZXMgbW9kZXMuICAqL1xuICBAQ29udGVudENoaWxkKCdub2RlVGVtcGxhdGUnLCB7IHN0YXRpYzogdHJ1ZSB9KSBub2RlVGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgLyoqIEluZGlxdWUgbGUgY2hhbmdlbWVudCBkJ8OpdGF0IGQndW4gbsWTdWQuICovXG4gIEBPdXRwdXQoKSBub2RlU2VsZWN0ID0gbmV3IEV2ZW50RW1pdHRlcjxEc2ZyTm9kZUV2ZW50PigpO1xuXG4gIC8qKiBJbmRpcXVlIHVuIGNoYW5nZW1lbnQgc3VyIGxhIHPDqWxlY3Rpb24uIFJlbnZvaWUgbGUgbm9ldWQgY29uY2VybsOpIGV0IGxpc3RlIGRlcyBub2V1ZHMgKGZldWlsbGVzKSBzw6lsZWN0aW9ubsOpcyAqL1xuICBAT3V0cHV0KCkgc2VsZWN0aW9uQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxEc2ZyVHJlZU5vZGVFdmVudD4oKTtcblxuICAvKiogSW5kaXF1ZSBzaSB0b3V0ZXMgbGVzIG9wdGlvbnMgc29udCBzw6lsZWN0aW9ubsOpZXMgb3Ugbm9uLiAqL1xuICAvKiogQGludGVybmFsICovXG4gIGlzQWxsU2VsZWN0ZWQ6IGJvb2xlYW47IC8vIEfDqXLDqSBwYXIgVHJlZVNlbGVjdE1hbmFnZXJcblxuICBwcm90ZWN0ZWQgaXNNb2RlU2VsZWN0YWJsZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIHByaXZhdGUgY2QgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXG4gIHByaXZhdGUgZm9jdXNNYW5hZ2VyID0gbmV3IFRyZWVGb2N1c01hbmFnZXIodGhpcyk7XG4gIHByaXZhdGUgc2VsZWN0TWFuYWdlciA9IG5ldyBUcmVlU2VsZWN0TWFuYWdlcih0aGlzKTtcbiAgcHJpdmF0ZSBfdmlld05vZGVzOiBEc2ZyVmlld05vZGVbXSA9IFtdOyAvLyBub2V1ZHMgaW50ZXJuZXMgYXZlYyDDqXRhdCAoc2VsZWN0ZWQsIGV4cGFuZClcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYpIHt9XG5cbiAgZ2V0IHNlbGVjdGlvbk1vZGUoKTogRHNmclNlbGVjdGlvbk1vZGUge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdE1hbmFnZXIuc2VsZWN0aW9uTW9kZTtcbiAgfVxuXG4gIC8qKiBTeW5vbnltZSBkZSB2YWx1ZSwgbWFpcyBwbHVzIGV4cGxpY2l0ZS4gKi9cbiAgZ2V0IG5vZGVzKCk6IERzZnJOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLl92aWV3Tm9kZXM7XG4gIH1cblxuICAvKiogTW9kZSBkZSBzw6lsZWN0aW9uLCBgdW5kZWZpbmVkYCBwYXIgZMOpZmF1dC4gKi9cbiAgQElucHV0KCkgc2V0IHNlbGVjdGlvbk1vZGUodmFsdWU6IERzZnJTZWxlY3Rpb25Nb2RlKSB7XG4gICAgdGhpcy5zZWxlY3RNYW5hZ2VyLnNlbGVjdGlvbk1vZGUgPSB2YWx1ZTtcbiAgICB0aGlzLmlzTW9kZVNlbGVjdGFibGUgPSB0aGlzLnNlbGVjdE1hbmFnZXIuaXNTZWxlY3RhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogUGVybWV0IGxhIHLDqWN1cMOpcmF0aW9uIGR1IG1vZMOobGUgaW50ZXJuZSBkZSBsJ2FyYnJlLlxuICAgKlxuICAgKiBAcmV0dXJucyBVbiB0YWJsZWF1IGRlIERzZnJOb2RlW10uXG4gICAqL1xuICBwdWJsaWMgZ2V0VHJlZVN0YXRlKCk6IERzZnJOb2RlW10ge1xuICAgIHJldHVybiB0aGlzLm5vZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcm1ldCBsYSByw6ljdXDDqXJhdGlvbiBkZSBsYSBzw6lsZWN0aW9uIGNvdXJhbnRlIGRlIGwnYXJicmUuXG4gICAqXG4gICAqIEByZXR1cm5zIFVuIHRhYmxlYXUgZGUgRHNmck5vZGVbXS5cbiAgICovXG4gIHB1YmxpYyBnZXRTZWxlY3Rpb24oKTogRHNmck5vZGVbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0TWFuYWdlci5zZWxlY3RlZE5vZGVzO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgLy8gTWlzZSDDoCBqb3VyIGRlcyB0YWJpbmRleFxuICAgIHRoaXMuZm9jdXNNYW5hZ2VyLmluaXRUYWJpbmRleCgpO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBuZ09uQ2hhbmdlcyh7IHZhbHVlIH06IFNpbXBsZUNoYW5nZXMpIHtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIGlmICh0aGlzLl92aWV3Tm9kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIHByZW1pw6hyZSBpbml0aWFsaXNhdGlvblxuICAgICAgICB0aGlzLl92aWV3Tm9kZXMgPSB0aGlzLnNlbGVjdE1hbmFnZXIuaW5pdCh0aGlzLnZhbHVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG1pc2Ugw6Agam91ciBhdmVjIGNvbnNlcnZhdGlvbiBkZXMgw6l0YXRzIGQnZXhwYW5zaW9uIGV0IGRlIHPDqWxlY3Rpb24gKHNpIG5vZXVkcyBmb3VybmlzIGF2ZWMgaWRlbnRpZmlhbnRzKVxuICAgICAgICB0aGlzLl92aWV3Tm9kZXMgPSB0aGlzLnNlbGVjdE1hbmFnZXIudXBkYXRlTm9kZXNDb250ZW50KHRoaXMudmFsdWUsIHRoaXMuX3ZpZXdOb2RlcywgMSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBnZXRDaGVja2JveElkKG5vZGU6IERzZnJOb2RlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ2NiJyArIG5vZGUuaWQ7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIGlzQ2hlY2tib3hNb2RlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdE1hbmFnZXIuaXNDaGVja2JveE1vZGUoKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgaXNTZWxlY3RhYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdE1hbmFnZXIuaXNTZWxlY3RhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogT3V2cmUgdG91cyBsZXMgbsWTdWRzIGRlIGwnYXJib3Jlc2NlbmNlLlxuICAgKi9cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBvbk5vZGVCdXR0b24obm9kZTogRHNmck5vZGUpIHtcbiAgICB0aGlzLmZvY3VzTWFuYWdlci5kb1RvZ2dsZUV4cGFuZChub2RlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTw6lsZWN0aW9uIGR1IGxhYmVsIGQndW4gbsWTdWQgbG9yc3F1ZSBxdWUgbCdvbiBhIHVuIGxhYmVsIHNhbnMgY2hlY2tib3guIFNpIGxlIG1vZGUgZXN0IGBzZWxlY3RhYmxlYCA6XG4gICAqIC0gb24gaW52ZXJzZSBsYSBzw6lsZWN0aW9uLCB1bmlxdWVtZW50IGR1IG7Fk3VkLCBvbiDDqW1ldCB1biDDqXbDqW5lbWVudC5cbiAgICovXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgb25Ob2RlU2VsZWN0KG5vZGU6IERzZnJOb2RlLCBldmVudDogRXZlbnQpIHtcbiAgICAvLyBjb25zdCB0YXJnZXRFbHQgPSA8SFRNTEVsZW1lbnQ+ZXZlbnQudGFyZ2V0O1xuICAgIC8vIG5lIHBhcyBhY3RpdmVyIHNpIGxhIHRhcmdldCBlc3QgbGUgYm91dG9uIGV4cGFuZC9jb2xsYXBzZVxuICAgIC8vaWYgKCF0YXJnZXRFbHQuY2xhc3NMaXN0Py5jb250YWlucygndHJlZS1idXR0b24nKSkge1xuICAgIGNvbnN0IG5vZGVFbHQgPSA8SFRNTEVsZW1lbnQ+ZXZlbnQuY3VycmVudFRhcmdldDtcbiAgICB0aGlzLnNlbGVjdE1hbmFnZXIuZG9TZWxlY3ROb2RlKG5vZGUsIG5vZGVFbHQpO1xuICAgIC8vfVxuICB9XG5cbiAgLyoqXG4gICAqIEdlc3Rpb24gZGVzIHRvdWNoZXMgZGUgbmF2aWdhdGlvbi5cbiAgICogT24gdHJhbnNmw6hyZSBsYSBnZXN0aW9uIGF1IGNvbXBvc2FudCBxdWkgZ8OocmUgbGEgbGlzdGUuXG4gICAqL1xuICAvKiogQGludGVybmFsICovXG4gIG9uTm9kZUtleWRvd24obm9kZTogRHNmck5vZGUsIGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgdGhpcy5mb2N1c01hbmFnZXIuZG9LZXlFdmVudChub2RlLCBldmVudCwgdHJ1ZSk7XG4gIH1cblxuICAvLyAtLSBUcmVlRm9jdXNhYmxlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLyoqIE91dnJlIHRvdXMgbGVzIG7Fk3VkcyBkZSBsJ2FyYm9yZXNjZW5jZS4gKi9cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBleHBhbmRBbGwoKSB7XG4gICAgdGhpcy5mb2N1c01hbmFnZXIuZXhwYW5kQWxsKHRoaXMubm9kZXMpO1xuICAgIHRoaXMuY2QubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvKiogRmVybWUgdG91cyBsZXMgbsWTdWRzIGRlIGwnYXJib3Jlc2NlbmNlLiAgKi9cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBjb2xsYXBzZUFsbCgpIHtcbiAgICB0aGlzLmZvY3VzTWFuYWdlci5jb2xsYXBzZUFsbCh0aGlzLm5vZGVzKTtcbiAgICB0aGlzLmNkLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBkb05vZGVEZWZhdWx0QWN0aW9uKG5vZGU6IERzZnJOb2RlLCBldmVudDogRXZlbnQpIHtcbiAgICBjb25zdCBub2RlRWx0ID0gPEhUTUxFbGVtZW50PmV2ZW50LmN1cnJlbnRUYXJnZXQ7XG4gICAgdGhpcy5zZWxlY3RNYW5hZ2VyLmRvU2VsZWN0Tm9kZShub2RlLCBub2RlRWx0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcm91dmVyIHRvdXMgbGVzIG5vZXVkcyA8bGk+IHZpc2libGVzIChwb3Nzw6hkZW50IHVuZSBoYXV0ZXVyIG1pbmltYWxlKS5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBmaW5kVmlzaWJsZU5vZGVzRWx0KCk6IEhUTUxFbGVtZW50W10ge1xuICAgIGNvbnN0IG5hdGl2ZUVsdCA9IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50O1xuICAgIGNvbnN0IG5vZGVMaXN0ID0gbmF0aXZlRWx0LnF1ZXJ5U2VsZWN0b3JBbGwoJy50cmVlLW5vZGUtY29udGVudCcpO1xuICAgIGNvbnN0IG5vZGVzQXJyOiBIVE1MRWxlbWVudFtdID0gW107XG5cbiAgICBub2RlTGlzdC5mb3JFYWNoKChuOiBIVE1MRWxlbWVudCkgPT4gbm9kZXNBcnIucHVzaChuKSk7XG5cbiAgICByZXR1cm4gbm9kZXNBcnI7XG4gIH1cblxuICAvKiogUmV0b3VybmUgbCfDqWzDqW1lbnQgYXZlYyBmb2N1cyBvdSB1bmRlZmluZWQuICovXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgZmluZEZvY3VzRWxlbWVudCgpOiBIVE1MRWxlbWVudCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJy50cmVlLW5vZGUtY29udGVudDpmb2N1cycpIHx8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBNaXNlIGEgam91ciBkdSBjb250ZW51IGRlIGwnYXJicmUuIENvbnNlcnZlIGwnw6l0YXQgKG7Fk3VkcyDDqXRlbmR1cyBldCBzw6lsZWN0aW9ubsOpcykgc2kgbCdpZCBkZXMgbsWTdWRzIGVzdCByZW5zZWlnbsOpLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVwZGF0ZUNvbnRlbnQoKTogdm9pZCB7XG4gICAgdGhpcy5fdmlld05vZGVzID0gdGhpcy5zZWxlY3RNYW5hZ2VyLnVwZGF0ZU5vZGVzQ29udGVudCh0aGlzLnZhbHVlLCB0aGlzLl92aWV3Tm9kZXMsIDEpO1xuICAgIHRoaXMuY2QubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvKipcbiAgICogUsOpaW5pdGlhbGlzZSBsJ8OpdGF0IGRlIGwnYXJicmUgKG7Fk3VkcyDDqXRlbmR1cyBldCBzw6lsZWN0aW9ubsOpcylcbiAgICogQGludGVybmFsXG4gICAqL1xuICByZWluaXRpYWxpemVTdGF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLl92aWV3Tm9kZXMgPSB0aGlzLnNlbGVjdE1hbmFnZXIuaW5pdCh0aGlzLnZhbHVlKTtcbiAgICB0aGlzLmNkLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgLy8gLS0gVHJlZVNlbGVjdGFibGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKiBTw6lsZWN0aW9ubmUgLyBkw6lzw6lsZWN0aW9ubmUgdG91cyBsZXMgbsWTdWRzIGVuIG1vZGUgbXVsdGlwbGUgb3UgY2hlY2tib3guXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgc2VsZWN0QWxsKHNlbGVjdGVkID0gdHJ1ZSk6IHZvaWQge1xuICAgIHRoaXMuc2VsZWN0TWFuYWdlci5zZWxlY3RBbGxOb2Rlcyh0aGlzLm5vZGVzLCBzZWxlY3RlZCk7XG4gICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgICB0aGlzLnNlbGVjdGlvbkNoYW5nZS5lbWl0KHsgbm9kZTogbnVsbCwgbm9kZXNTZWxlY3RlZDogdGhpcy5zZWxlY3RNYW5hZ2VyLnNlbGVjdGVkTm9kZXMgfSk7XG4gIH1cblxuICAvKiogRW1pc3Npb24gZCd1biDDqXbDqW5lbWVudCBwb3VyIHVuIG7Fk3VkLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIG5vdGlmeVNlbGVjdEV2ZW50KG5vZGU6IERzZnJOb2RlKTogdm9pZCB7XG4gICAgLy8gbGEgdmFyaWFibGUgJ25vZGVDb250ZW50JyBjb3JyZXNwb25kIMOgIG5vZGUgc2FucyBsZXMgZW5mYW50c1xuICAgIGNvbnN0IHsgY2hpbGRyZW4sIC4uLm5vZGVDb250ZW50IH0gPSBub2RlO1xuICAgIHRoaXMubm9kZVNlbGVjdC5lbWl0KDxEc2ZyTm9kZUV2ZW50Pm5vZGVDb250ZW50KTtcbiAgICB0aGlzLnNlbGVjdGlvbkNoYW5nZS5lbWl0KHtcbiAgICAgIG5vZGU6IG5vZGVDb250ZW50LFxuICAgICAgbm9kZXNTZWxlY3RlZDogdGhpcy5zZWxlY3RNYW5hZ2VyLnNlbGVjdGVkTm9kZXMubWFwKChhKSA9PiBhIGFzIERzZnJOb2RlKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXQgw6Agam91ciBsYSBwcm9wcmnDqXTDqSBgaW5kZXRlcm1pbmF0ZWAgZGUgbGEgY2hlY2tib3ggYG5vZGUuaW5wdXRJZGAgZW4gZm9uY3Rpb24gZGUgbGEgdmFsZXVyIGRlICdub2RlLnNlbGVjdGVkJy5cbiAgICogQHBhcmFtIG5vZGUgTsWTdWQgZGUgbCdhcmJyZVxuICAgKi9cblxuICAvKiogQGludGVybmFsICovXG4gIHVwZGF0ZUluZGV0ZXJtaW5hdGUobm9kZTogRHNmck5vZGUpIHtcbiAgICBjb25zdCBuYXRpdmVFbHQgPSB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBjaGVja2JveElkID0gdGhpcy5nZXRDaGVja2JveElkKG5vZGUpO1xuICAgIGNvbnN0IGlucHV0RWx0ID0gPEhUTUxJbnB1dEVsZW1lbnQ+bmF0aXZlRWx0Py5xdWVyeVNlbGVjdG9yKCcjJyArIGNoZWNrYm94SWQpO1xuXG4gICAgaWYgKGlucHV0RWx0KSBpbnB1dEVsdC5pbmRldGVybWluYXRlID0gbm9kZS5zZWxlY3RlZCA9PT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICB0cmFja0J5SWQoaW5kZXg6IG51bWJlciwgaXRlbTogRHNmck5vZGUpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBpdGVtLmlkO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZHNmcngtdHJlZS1jb21wb25lbnRcIj5cbiAgPG5nLWNvbnRhaW5lclxuICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIm5vZGVzVGVtcGxhdGVcIlxuICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IG5vZGVzOiBub2RlcyB8fCBbXSwgcm9vdDogdHJ1ZSB9XCI+PC9uZy1jb250YWluZXI+XG48L2Rpdj5cblxuPG5nLXRlbXBsYXRlICNub2Rlc1RlbXBsYXRlIGxldC1ub2Rlcz1cIm5vZGVzXCIgbGV0LXJvb3Q9XCJyb290XCI+XG4gIDx1bFxuICAgIGNsYXNzPVwidHJlZS1ub2RlXCJcbiAgICBbYXR0ci5hcmlhLW11bHRpc2VsZWN0YWJsZV09XCJyb290ID8gc2VsZWN0aW9uTW9kZSA9PT0gJ211bHRpcGxlJyB8fCBzZWxlY3Rpb25Nb2RlID09PSAnY2hlY2tib3gnIDogbnVsbFwiXG4gICAgW2F0dHIucm9sZV09XCJyb290ID8gJ3RyZWUnIDogJ2dyb3VwJ1wiPlxuICAgIEBmb3IgKG5vZGUgb2Ygbm9kZXM7IHRyYWNrIHRyYWNrQnlJZChpLCBub2RlKTsgbGV0IGkgPSAkaW5kZXgpIHtcbiAgICAgIEBpZiAoIW5vZGUuaGlkZGVuKSB7XG4gICAgICAgIDxsaVxuICAgICAgICAgIHJvbGU9XCJ0cmVlaXRlbVwiXG4gICAgICAgICAgdGFiaW5kZXg9XCItMVwiXG4gICAgICAgICAgY2xhc3M9XCJ0cmVlLW5vZGUtY29udGVudFwiXG4gICAgICAgICAgKGtleWRvd24pPVwib25Ob2RlS2V5ZG93bihub2RlLCAkZXZlbnQpXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLXNlbGVjdGVkXT1cImlzTW9kZVNlbGVjdGFibGUgPyBub2RlLnNlbGVjdGVkIDogbnVsbFwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1sZXZlbF09XCJub2RlLmFyaWFMZXZlbFwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1zZXRzaXplXT1cIm5vZGUuYXJpYVNpemVcIlxuICAgICAgICAgIFthdHRyLmFyaWEtcG9zaW5zZXRdPVwiaSArIDFcIlxuICAgICAgICAgIFtjbGFzcy5sZWFmXT1cIiFub2RlLmNoaWxkcmVuXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWV4cGFuZGVkXT1cIm5vZGUuY2hpbGRyZW4gPyBub2RlLmV4cGFuZGVkID8/IGZhbHNlIDogbnVsbFwiPlxuICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImRlZmF1bHROb2RlVGVtcGxhdGVcIlxuICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgbm9kZTogbm9kZSB9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvbGk+XG4gICAgICB9XG4gICAgfVxuICA8L3VsPlxuPC9uZy10ZW1wbGF0ZT5cblxuPG5nLXRlbXBsYXRlICNkZWZhdWx0Tm9kZVRlbXBsYXRlIGxldC1ub2RlPVwibm9kZVwiPlxuICA8ZGl2IGNsYXNzPVwidHJlZS1ub2RlLWNvbnRlbnQtaW5zaWRlXCIgW2NsYXNzLnNlbGVjdGFibGVdPVwiaXNNb2RlU2VsZWN0YWJsZVwiIFtjbGFzcy5zZWxlY3RlZF09XCJub2RlLnNlbGVjdGVkXCI+XG4gICAgPCEtLSBCb3V0b24gY29sbGFwc2UgLyBleHBhbmQgLS0+XG4gICAgQGlmIChub2RlLmNoaWxkcmVuKSB7XG4gICAgICA8c3BhblxuICAgICAgICBjbGFzcz1cInRyZWUtYnV0dG9uXCJcbiAgICAgICAgW2NsYXNzXT1cIiFub2RlLmV4cGFuZGVkID8gJ2ZyLWljb24tYXJyb3ctcmlnaHQtcy1saW5lJyA6ICdmci1pY29uLWFycm93LWRvd24tcy1saW5lJ1wiXG4gICAgICAgIChjbGljayk9XCJvbk5vZGVCdXR0b24obm9kZSlcIj48L3NwYW4+XG4gICAgfVxuXG4gICAgQGlmICghaXNDaGVja2JveE1vZGUoKSkge1xuICAgICAgPGRpdiAoY2xpY2spPVwiaXNNb2RlU2VsZWN0YWJsZSA/IG9uTm9kZVNlbGVjdChub2RlLCAkZXZlbnQpIDogb25Ob2RlQnV0dG9uKG5vZGUpXCIgY2xhc3M9XCJ0cmVlLW5vZGUtbGFiZWxcIj5cbiAgICAgICAgPCEtLSBMYWJlbCBzZXVsIC0tPlxuICAgICAgICBAaWYgKCFub2RlVGVtcGxhdGUpIHtcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImZyLWxhYmVsXCI+XG4gICAgICAgICAgICBAaWYgKG5vZGUuaWNvbikge1xuICAgICAgICAgICAgICA8c3BhbiBhcmlhLWhpZGRlbj1cInRydWVcIiBbY2xhc3NdPVwibm9kZS5pY29uICsgJyBmci1pY29uLS1zbSdcIj4mbmJzcDs8L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB7eyBub2RlLmxhYmVsIH19XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8IS0tIExhYmVsIHNldWwgZXQgdGVtcGxhdGUgY3VzdG9tIC0tPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJub2RlVGVtcGxhdGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBub2RlIH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfSBAZWxzZSB7XG4gICAgICA8ZGl2IGNsYXNzPVwidHJlZS1ub2RlLWxhYmVsXCI+XG4gICAgICAgIDwhLS0gQ2hlY2tib3ggKyBsYWJlbCAtLT5cbiAgICAgICAgPGRzZnItZXh0LWNoZWNrYm94XG4gICAgICAgICAgW2lkXT1cImdldENoZWNrYm94SWQobm9kZSlcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJub2RlLmRpc2FibGVkXCJcbiAgICAgICAgICBbdGFiSW5kZXhdPVwiLTFcIlxuICAgICAgICAgIFtpY29uXT1cIm5vZGUuaWNvblwiXG4gICAgICAgICAgW2xhYmVsXT1cIm5vZGUubGFiZWxcIlxuICAgICAgICAgIChjaGVja2JveENsaWNrKT1cIm9uTm9kZVNlbGVjdChub2RlLCAkZXZlbnQpXCJcbiAgICAgICAgICBbc2VsZWN0ZWRdPVwibm9kZS5zZWxlY3RlZFwiPjwvZHNmci1leHQtY2hlY2tib3g+XG4gICAgICAgIDwhLS0gVGVtcGxhdGUgY3VzdG9tIGFkZGl0aW9ubmVsIC0tPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwibm9kZVRlbXBsYXRlOyBjb250ZXh0OiB7ICRpbXBsaWNpdDogbm9kZSB9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICA8L2Rpdj5cbiAgICB9XG4gIDwvZGl2PlxuXG4gIDwhLS0gQ2hpbGRyZW4gLS0+XG4gIEBpZiAobm9kZS5jaGlsZHJlbiAmJiBub2RlLmV4cGFuZGVkKSB7XG4gICAgPG5nLWNvbnRhaW5lclxuICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwibm9kZXNUZW1wbGF0ZVwiXG4gICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyBub2Rlczogbm9kZS5jaGlsZHJlbiwgcm9vdDogZmFsc2UgfVwiPjwvbmctY29udGFpbmVyPlxuICB9XG48L25nLXRlbXBsYXRlPlxuIl19