UNPKG

carbon-components-angular

Version:
239 lines 22.6 kB
import { DOCUMENT } from "@angular/common"; import { Component, Input, Output, TemplateRef, EventEmitter, Inject, ViewChild } from "@angular/core"; import { TreeViewService } from "./treeview.service"; import * as i0 from "@angular/core"; import * as i1 from "./treeview.service"; import * as i2 from "@angular/common"; import * as i3 from "./tree-node.component"; /** * Get started with importing the module: * * ```typescript * import { TreeviewModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-tree-view--basic) */ export class TreeViewComponent { constructor(document, treeViewService, elementRef) { this.document = document; this.treeViewService = treeViewService; this.elementRef = elementRef; this.id = `tree-view-${TreeViewComponent.treeViewCount++}`; /** * Set to `true` to visually hide the label while keeping it available to assistive technologies. */ this.hideLabel = false; /** * Specify the size of the list items in the tree */ this.size = "sm"; this.select = new EventEmitter(); this.toggle = new EventEmitter(); this._tree = []; } /** * Pass `Node[]` array to have tree view render the nodes * Passing value will disregard projected content */ set tree(treeNodes) { this._tree = treeNodes.map((node) => this.copyNode(node)); this.treeViewService.contentProjected = false; } get tree() { return this._tree; } /** * **Experimental** - Enable to select multiple nodes */ set isMultiSelect(isMulti) { this.treeViewService.isMultiSelect = isMulti; } /** * Subscribe for node selection */ ngOnInit() { this.subscription = this.treeViewService.selectionObservable.subscribe((nodesMap) => { // Get all values from the map to emit const nodes = [...nodesMap.values()]; this.select.emit(this.treeViewService.isMultiSelect ? nodes : nodes[0]); }); this.subscription.add(this.treeViewService.focusNodeObservable.subscribe(node => this.onNodeFocusChange(node))); } ngOnDestroy() { this.subscription.unsubscribe(); } /** * Initialize tree walker to support keyboard navigation */ ngAfterViewInit() { this.treeWalker = this.document.createTreeWalker(this.root.nativeElement, NodeFilter.SHOW_ELEMENT, { acceptNode: function (node) { if (node.classList.contains(`cds--tree-node--disabled`)) { return NodeFilter.FILTER_REJECT; } if (node.matches(`div.cds--tree-node`)) { return NodeFilter.FILTER_ACCEPT; } return NodeFilter.FILTER_SKIP; } }); } /** * Navigate tree using tree walker * @param event - KeyboardEvent */ navigateTree(event) { if (event.key === "ArrowUp") { this.treeWalker.previousNode()?.focus(); } if (event.key === "ArrowDown") { this.treeWalker.nextNode()?.focus(); } } /** * Propagate node toggle event * @param eventOnNode - EventOnNode */ onNodeToggle(eventOnNode) { if (!eventOnNode) { return; } this.toggle.emit(eventOnNode.node); } /** * Node focus change * @param node - Node */ onNodeFocusChange(node) { if (!node) { // if for some reason the focused node is not defined we fallback on the root element of the treeview this.treeWalker.currentNode = this.treeWalker.root; return; } // Update current node based on focus change to have a better keyboard navigation experience this.treeWalker.currentNode = this.elementRef.nativeElement.querySelector(`#${CSS.escape(node.id)}`); } isTemplate(value) { return value instanceof TemplateRef; } isProjected() { return this.treeViewService.contentProjected; } copyNode(node) { // making a recursive shallow copy to avoid performance issues when deeply cloning templateRefs if defined in the node const copiedNode = Object.assign({}, node); if (node.children) { copiedNode.children = node.children.map(child => this.copyNode(child)); } return copiedNode; } } TreeViewComponent.treeViewCount = 0; TreeViewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeViewComponent, deps: [{ token: DOCUMENT }, { token: i1.TreeViewService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); TreeViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TreeViewComponent, selector: "cds-tree-view", inputs: { tree: "tree", id: "id", label: "label", hideLabel: "hideLabel", labelContext: "labelContext", size: "size", isMultiSelect: "isMultiSelect" }, outputs: { select: "select", toggle: "toggle" }, providers: [TreeViewService], viewQueries: [{ propertyName: "root", first: true, predicate: ["treeWrapper"], descendants: true }], ngImport: i0, template: ` <label *ngIf="label" [id]="id" class="cds--label" [ngClass]="{'cds--visually-hidden': hideLabel}"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </label> <div class="cds--tree" [ngClass]="{ 'cds--tree--sm': size === 'sm', 'cds--tree--xs': size === 'xs' }" [attr.aria-label]="label ? label : null" [attr.aria-labelledby]="!label ? id : null" [attr.aria-multiselectable]="isMultiSelect || null" role="tree" (keydown)="navigateTree($event)" #treeWrapper> <ng-container *ngIf="isProjected(); else notProjected"> <ng-content></ng-content> </ng-container> <ng-template #notProjected> <cds-tree-node *ngFor="let node of tree" [node]="node" (nodetoggle)="onNodeToggle($event)"> </cds-tree-node> </ng-template> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.TreeNodeComponent, selector: "cds-tree-node", inputs: ["id", "active", "disabled", "selectable", "expanded", "label", "labelContext", "selected", "value", "icon", "iconContext", "gap", "children", "depth", "node"], outputs: ["nodeFocus", "nodeBlur", "nodeSelect", "nodetoggle"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeViewComponent, decorators: [{ type: Component, args: [{ selector: "cds-tree-view", template: ` <label *ngIf="label" [id]="id" class="cds--label" [ngClass]="{'cds--visually-hidden': hideLabel}"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </label> <div class="cds--tree" [ngClass]="{ 'cds--tree--sm': size === 'sm', 'cds--tree--xs': size === 'xs' }" [attr.aria-label]="label ? label : null" [attr.aria-labelledby]="!label ? id : null" [attr.aria-multiselectable]="isMultiSelect || null" role="tree" (keydown)="navigateTree($event)" #treeWrapper> <ng-container *ngIf="isProjected(); else notProjected"> <ng-content></ng-content> </ng-container> <ng-template #notProjected> <cds-tree-node *ngFor="let node of tree" [node]="node" (nodetoggle)="onNodeToggle($event)"> </cds-tree-node> </ng-template> </div> `, providers: [TreeViewService] }] }], ctorParameters: function () { return [{ type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i1.TreeViewService }, { type: i0.ElementRef }]; }, propDecorators: { tree: [{ type: Input }], id: [{ type: Input }], label: [{ type: Input }], hideLabel: [{ type: Input }], labelContext: [{ type: Input }], size: [{ type: Input }], isMultiSelect: [{ type: Input }], select: [{ type: Output }], toggle: [{ type: Output }], root: [{ type: ViewChild, args: ["treeWrapper"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZXZpZXcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyZWV2aWV3L3RyZWV2aWV3LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUNOLFNBQVMsRUFDVCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFdBQVcsRUFDWCxZQUFZLEVBRVosTUFBTSxFQUNOLFNBQVMsRUFJVCxNQUFNLGVBQWUsQ0FBQztBQUd2QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7Ozs7O0FBRXJEOzs7Ozs7OztHQVFHO0FBMENILE1BQU0sT0FBTyxpQkFBaUI7SUFpRDdCLFlBQzJCLFFBQWtCLEVBQ3JDLGVBQWdDLEVBQy9CLFVBQXNCO1FBRkosYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNyQyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDL0IsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQXBDdEIsT0FBRSxHQUFHLGFBQWEsaUJBQWlCLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztRQU0vRDs7V0FFRztRQUNNLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFLM0I7O1dBRUc7UUFDTSxTQUFJLEdBQWdCLElBQUksQ0FBQztRQVF4QixXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7UUFDM0MsV0FBTSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFJcEMsVUFBSyxHQUFXLEVBQUUsQ0FBQztJQU94QixDQUFDO0lBcERKOzs7T0FHRztJQUNILElBQWEsSUFBSSxDQUFDLFNBQWlCO1FBQ2xDLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQzFELElBQUksQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLElBQUk7UUFDUCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDbkIsQ0FBQztJQXNCRDs7T0FFRztJQUNILElBQWEsYUFBYSxDQUFDLE9BQWdCO1FBQzFDLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQztJQUM5QyxDQUFDO0lBZ0JEOztPQUVHO0lBQ0gsUUFBUTtRQUNQLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUEyQixFQUFFLEVBQUU7WUFDdEcsc0NBQXNDO1lBQ3RDLE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUVyQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6RSxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqSCxDQUFDO0lBRUQsV0FBVztRQUNWLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsZUFBZTtRQUNkLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFO1lBQ2xHLFVBQVUsRUFBRSxVQUFVLElBQWlCO2dCQUN0QyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLDBCQUEwQixDQUFDLEVBQUU7b0JBQ3hELE9BQU8sVUFBVSxDQUFDLGFBQWEsQ0FBQztpQkFDaEM7Z0JBQ0QsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLEVBQUU7b0JBQ3ZDLE9BQU8sVUFBVSxDQUFDLGFBQWEsQ0FBQztpQkFDaEM7Z0JBQ0QsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUFDO1lBQy9CLENBQUM7U0FDRCxDQUFDLENBQUM7SUFDSixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsWUFBWSxDQUFDLEtBQW9CO1FBQ2hDLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxTQUFTLEVBQUU7WUFDM0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQWtCLEVBQUUsS0FBSyxFQUFFLENBQUM7U0FDekQ7UUFFRCxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssV0FBVyxFQUFFO1lBQzdCLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFrQixFQUFFLEtBQUssRUFBRSxDQUFDO1NBQ3JEO0lBQ0YsQ0FBQztJQUVEOzs7T0FHRztJQUNILFlBQVksQ0FBQyxXQUF3QjtRQUNwQyxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ2pCLE9BQU87U0FDUDtRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCLENBQUMsSUFBVTtRQUMzQixJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ1YscUdBQXFHO1lBQ3JHLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ25ELE9BQU87U0FDUDtRQUNELDRGQUE0RjtRQUM1RixJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEcsQ0FBQztJQUVNLFVBQVUsQ0FBQyxLQUFLO1FBQ3RCLE9BQU8sS0FBSyxZQUFZLFdBQVcsQ0FBQztJQUNyQyxDQUFDO0lBRU0sV0FBVztRQUNqQixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7SUFDOUMsQ0FBQztJQUVPLFFBQVEsQ0FBQyxJQUFVO1FBQzFCLHNIQUFzSDtRQUN0SCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMzQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDbEIsVUFBVSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN2RTtRQUNELE9BQU8sVUFBVSxDQUFDO0lBQ25CLENBQUM7O0FBaklNLCtCQUFhLEdBQUcsQ0FBQyxDQUFDOzhHQWRiLGlCQUFpQixrQkFrRHBCLFFBQVE7a0dBbERMLGlCQUFpQixpUEFGbEIsQ0FBQyxlQUFlLENBQUMsK0hBckNsQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBb0NUOzJGQUdXLGlCQUFpQjtrQkF6QzdCLFNBQVM7bUJBQUM7b0JBQ1YsUUFBUSxFQUFFLGVBQWU7b0JBQ3pCLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBb0NUO29CQUNELFNBQVMsRUFBRSxDQUFDLGVBQWUsQ0FBQztpQkFDNUI7OzBCQW1ERSxNQUFNOzJCQUFDLFFBQVE7bUdBN0NKLElBQUk7c0JBQWhCLEtBQUs7Z0JBV0csRUFBRTtzQkFBVixLQUFLO2dCQUlHLEtBQUs7c0JBQWIsS0FBSztnQkFLRyxTQUFTO3NCQUFqQixLQUFLO2dCQUlHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBSUcsSUFBSTtzQkFBWixLQUFLO2dCQUlPLGFBQWE7c0JBQXpCLEtBQUs7Z0JBSUksTUFBTTtzQkFBZixNQUFNO2dCQUNHLE1BQU07c0JBQWYsTUFBTTtnQkFDbUIsSUFBSTtzQkFBN0IsU0FBUzt1QkFBQyxhQUFhIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRE9DVU1FTlQgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XG5pbXBvcnQge1xuXHRDb21wb25lbnQsXG5cdElucHV0LFxuXHRPdXRwdXQsXG5cdFRlbXBsYXRlUmVmLFxuXHRFdmVudEVtaXR0ZXIsXG5cdEFmdGVyVmlld0luaXQsXG5cdEluamVjdCxcblx0Vmlld0NoaWxkLFxuXHRFbGVtZW50UmVmLFxuXHRPbkluaXQsXG5cdE9uRGVzdHJveVxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IEV2ZW50T25Ob2RlLCBOb2RlIH0gZnJvbSBcIi4vdHJlZS1ub2RlLnR5cGVzXCI7XG5pbXBvcnQgeyBUcmVlVmlld1NlcnZpY2UgfSBmcm9tIFwiLi90cmVldmlldy5zZXJ2aWNlXCI7XG5cbi8qKlxuICogR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBUcmVldmlld01vZHVsZSB9IGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXInO1xuICogYGBgXG4gKlxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy10cmVlLXZpZXctLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLXRyZWUtdmlld1wiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxsYWJlbFxuXHRcdFx0Km5nSWY9XCJsYWJlbFwiXG5cdFx0XHRbaWRdPVwiaWRcIlxuXHRcdFx0Y2xhc3M9XCJjZHMtLWxhYmVsXCJcblx0XHRcdFtuZ0NsYXNzXT1cInsnY2RzLS12aXN1YWxseS1oaWRkZW4nOiBoaWRlTGFiZWx9XCI+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzVGVtcGxhdGUobGFiZWwpXCI+e3tsYWJlbH19PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8bmctdGVtcGxhdGVcblx0XHRcdFx0Km5nSWY9XCJpc1RlbXBsYXRlKGxhYmVsKVwiXG5cdFx0XHRcdFtuZ1RlbXBsYXRlT3V0bGV0XT1cImxhYmVsXCJcblx0XHRcdFx0W25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgJGltcGxpY2l0OiBsYWJlbENvbnRleHQgfVwiPlxuXHRcdFx0PC9uZy10ZW1wbGF0ZT5cblx0XHQ8L2xhYmVsPlxuXHRcdDxkaXZcblx0XHRcdGNsYXNzPVwiY2RzLS10cmVlXCJcblx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0J2Nkcy0tdHJlZS0tc20nOiBzaXplID09PSAnc20nLFxuXHRcdFx0XHQnY2RzLS10cmVlLS14cyc6IHNpemUgPT09ICd4cydcblx0XHRcdH1cIlxuXHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJsYWJlbCA/IGxhYmVsIDogbnVsbFwiXG5cdFx0XHRbYXR0ci5hcmlhLWxhYmVsbGVkYnldPVwiIWxhYmVsID8gaWQgOiBudWxsXCJcblx0XHRcdFthdHRyLmFyaWEtbXVsdGlzZWxlY3RhYmxlXT1cImlzTXVsdGlTZWxlY3QgfHwgbnVsbFwiXG5cdFx0XHRyb2xlPVwidHJlZVwiXG5cdFx0XHQoa2V5ZG93bik9XCJuYXZpZ2F0ZVRyZWUoJGV2ZW50KVwiXG5cdFx0XHQjdHJlZVdyYXBwZXI+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiaXNQcm9qZWN0ZWQoKTsgZWxzZSBub3RQcm9qZWN0ZWRcIj5cblx0XHRcdFx0PG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuXHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8bmctdGVtcGxhdGUgI25vdFByb2plY3RlZD5cblx0XHRcdFx0PGNkcy10cmVlLW5vZGVcblx0XHRcdFx0XHQqbmdGb3I9XCJsZXQgbm9kZSBvZiB0cmVlXCJcblx0XHRcdFx0XHRbbm9kZV09XCJub2RlXCJcblx0XHRcdFx0XHQobm9kZXRvZ2dsZSk9XCJvbk5vZGVUb2dnbGUoJGV2ZW50KVwiPlxuXHRcdFx0XHQ8L2Nkcy10cmVlLW5vZGU+XG5cdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdDwvZGl2PlxuXHRgLFxuXHRwcm92aWRlcnM6IFtUcmVlVmlld1NlcnZpY2VdXG59KVxuZXhwb3J0IGNsYXNzIFRyZWVWaWV3Q29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25Jbml0LCBPbkRlc3Ryb3kge1xuXHQvKipcblx0ICogUGFzcyBgTm9kZVtdYCBhcnJheSB0byBoYXZlIHRyZWUgdmlldyByZW5kZXIgdGhlIG5vZGVzXG5cdCAqIFBhc3NpbmcgdmFsdWUgd2lsbCBkaXNyZWdhcmQgcHJvamVjdGVkIGNvbnRlbnRcblx0ICovXG5cdEBJbnB1dCgpIHNldCB0cmVlKHRyZWVOb2RlczogTm9kZVtdKSB7XG5cdFx0dGhpcy5fdHJlZSA9IHRyZWVOb2Rlcy5tYXAoKG5vZGUpID0+IHRoaXMuY29weU5vZGUobm9kZSkpO1xuXHRcdHRoaXMudHJlZVZpZXdTZXJ2aWNlLmNvbnRlbnRQcm9qZWN0ZWQgPSBmYWxzZTtcblx0fVxuXG5cdGdldCB0cmVlKCkge1xuXHRcdHJldHVybiB0aGlzLl90cmVlO1xuXHR9XG5cblx0c3RhdGljIHRyZWVWaWV3Q291bnQgPSAwO1xuXG5cdEBJbnB1dCgpIGlkID0gYHRyZWUtdmlldy0ke1RyZWVWaWV3Q29tcG9uZW50LnRyZWVWaWV3Q291bnQrK31gO1xuXHQvKipcblx0ICogVHJlZSB2aWV3IGxhYmVsXG5cdCAqL1xuXHRASW5wdXQoKSBsYWJlbDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55PjtcblxuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byB2aXN1YWxseSBoaWRlIHRoZSBsYWJlbCB3aGlsZSBrZWVwaW5nIGl0IGF2YWlsYWJsZSB0byBhc3Npc3RpdmUgdGVjaG5vbG9naWVzLlxuXHQgKi9cblx0QElucHV0KCkgaGlkZUxhYmVsID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBPcHRpb25hbCBjb250ZXh0IGZvciBsYWJlbCBpZiBpdCdzIGEgdGVtcGxhdGVcblx0ICovXG5cdEBJbnB1dCgpIGxhYmVsQ29udGV4dDogYW55O1xuXHQvKipcblx0ICogU3BlY2lmeSB0aGUgc2l6ZSBvZiB0aGUgbGlzdCBpdGVtcyBpbiB0aGUgdHJlZVxuXHQgKi9cblx0QElucHV0KCkgc2l6ZTogXCJ4c1wiIHwgXCJzbVwiID0gXCJzbVwiO1xuXHQvKipcblx0ICogKipFeHBlcmltZW50YWwqKiAtIEVuYWJsZSB0byBzZWxlY3QgbXVsdGlwbGUgbm9kZXNcblx0ICovXG5cdEBJbnB1dCgpIHNldCBpc011bHRpU2VsZWN0KGlzTXVsdGk6IGJvb2xlYW4pIHtcblx0XHR0aGlzLnRyZWVWaWV3U2VydmljZS5pc011bHRpU2VsZWN0ID0gaXNNdWx0aTtcblx0fVxuXG5cdEBPdXRwdXQoKSBzZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPE5vZGUgfCBOb2RlW10+KCk7XG5cdEBPdXRwdXQoKSB0b2dnbGUgPSBuZXcgRXZlbnRFbWl0dGVyPE5vZGU+KCk7XG5cdEBWaWV3Q2hpbGQoXCJ0cmVlV3JhcHBlclwiKSByb290OiBFbGVtZW50UmVmO1xuXG5cdHByaXZhdGUgdHJlZVdhbGtlcjogVHJlZVdhbGtlcjtcblx0cHJpdmF0ZSBfdHJlZTogTm9kZVtdID0gW107XG5cdHByaXZhdGUgc3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cblx0Y29uc3RydWN0b3IoXG5cdFx0QEluamVjdChET0NVTUVOVCkgcHJpdmF0ZSBkb2N1bWVudDogRG9jdW1lbnQsXG5cdFx0cHVibGljIHRyZWVWaWV3U2VydmljZTogVHJlZVZpZXdTZXJ2aWNlLFxuXHRcdHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZlxuXHQpIHt9XG5cblx0LyoqXG5cdCAqIFN1YnNjcmliZSBmb3Igbm9kZSBzZWxlY3Rpb25cblx0ICovXG5cdG5nT25Jbml0KCk6IHZvaWQge1xuXHRcdHRoaXMuc3Vic2NyaXB0aW9uID0gdGhpcy50cmVlVmlld1NlcnZpY2Uuc2VsZWN0aW9uT2JzZXJ2YWJsZS5zdWJzY3JpYmUoKG5vZGVzTWFwOiBNYXA8c3RyaW5nLCBOb2RlPikgPT4ge1xuXHRcdFx0Ly8gR2V0IGFsbCB2YWx1ZXMgZnJvbSB0aGUgbWFwIHRvIGVtaXRcblx0XHRcdGNvbnN0IG5vZGVzID0gWy4uLm5vZGVzTWFwLnZhbHVlcygpXTtcblxuXHRcdFx0dGhpcy5zZWxlY3QuZW1pdCh0aGlzLnRyZWVWaWV3U2VydmljZS5pc011bHRpU2VsZWN0ID8gbm9kZXMgOiBub2Rlc1swXSk7XG5cdFx0fSk7XG5cdFx0dGhpcy5zdWJzY3JpcHRpb24uYWRkKHRoaXMudHJlZVZpZXdTZXJ2aWNlLmZvY3VzTm9kZU9ic2VydmFibGUuc3Vic2NyaWJlKG5vZGUgPT4gdGhpcy5vbk5vZGVGb2N1c0NoYW5nZShub2RlKSkpO1xuXHR9XG5cblx0bmdPbkRlc3Ryb3koKTogdm9pZCB7XG5cdFx0dGhpcy5zdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHRyZWUgd2Fsa2VyIHRvIHN1cHBvcnQga2V5Ym9hcmQgbmF2aWdhdGlvblxuXHQgKi9cblx0bmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuXHRcdHRoaXMudHJlZVdhbGtlciA9IHRoaXMuZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcih0aGlzLnJvb3QubmF0aXZlRWxlbWVudCwgTm9kZUZpbHRlci5TSE9XX0VMRU1FTlQsIHtcblx0XHRcdGFjY2VwdE5vZGU6IGZ1bmN0aW9uIChub2RlOiBIVE1MRWxlbWVudCkge1xuXHRcdFx0XHRpZiAobm9kZS5jbGFzc0xpc3QuY29udGFpbnMoYGNkcy0tdHJlZS1ub2RlLS1kaXNhYmxlZGApKSB7XG5cdFx0XHRcdFx0cmV0dXJuIE5vZGVGaWx0ZXIuRklMVEVSX1JFSkVDVDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAobm9kZS5tYXRjaGVzKGBkaXYuY2RzLS10cmVlLW5vZGVgKSkge1xuXHRcdFx0XHRcdHJldHVybiBOb2RlRmlsdGVyLkZJTFRFUl9BQ0NFUFQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIE5vZGVGaWx0ZXIuRklMVEVSX1NLSVA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogTmF2aWdhdGUgdHJlZSB1c2luZyB0cmVlIHdhbGtlclxuXHQgKiBAcGFyYW0gZXZlbnQgLSBLZXlib2FyZEV2ZW50XG5cdCAqL1xuXHRuYXZpZ2F0ZVRyZWUoZXZlbnQ6IEtleWJvYXJkRXZlbnQpIHtcblx0XHRpZiAoZXZlbnQua2V5ID09PSBcIkFycm93VXBcIikge1xuXHRcdFx0KHRoaXMudHJlZVdhbGtlci5wcmV2aW91c05vZGUoKSBhcyBIVE1MRWxlbWVudCk/LmZvY3VzKCk7XG5cdFx0fVxuXG5cdFx0aWYgKGV2ZW50LmtleSA9PT0gXCJBcnJvd0Rvd25cIikge1xuXHRcdFx0KHRoaXMudHJlZVdhbGtlci5uZXh0Tm9kZSgpIGFzIEhUTUxFbGVtZW50KT8uZm9jdXMoKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogUHJvcGFnYXRlIG5vZGUgdG9nZ2xlIGV2ZW50XG5cdCAqIEBwYXJhbSBldmVudE9uTm9kZSAtIEV2ZW50T25Ob2RlXG5cdCAqL1xuXHRvbk5vZGVUb2dnbGUoZXZlbnRPbk5vZGU6IEV2ZW50T25Ob2RlKSB7XG5cdFx0aWYgKCFldmVudE9uTm9kZSkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLnRvZ2dsZS5lbWl0KGV2ZW50T25Ob2RlLm5vZGUpO1xuXHR9XG5cblx0LyoqXG5cdCAqIE5vZGUgZm9jdXMgY2hhbmdlXG5cdCAqIEBwYXJhbSBub2RlIC0gTm9kZVxuXHQgKi9cblx0b25Ob2RlRm9jdXNDaGFuZ2Uobm9kZTogTm9kZSkge1xuXHRcdGlmICghbm9kZSkge1xuXHRcdFx0Ly8gaWYgZm9yIHNvbWUgcmVhc29uIHRoZSBmb2N1c2VkIG5vZGUgaXMgbm90IGRlZmluZWQgd2UgZmFsbGJhY2sgb24gdGhlIHJvb3QgZWxlbWVudCBvZiB0aGUgdHJlZXZpZXdcblx0XHRcdHRoaXMudHJlZVdhbGtlci5jdXJyZW50Tm9kZSA9IHRoaXMudHJlZVdhbGtlci5yb290O1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHQvLyBVcGRhdGUgY3VycmVudCBub2RlIGJhc2VkIG9uIGZvY3VzIGNoYW5nZSB0byBoYXZlIGEgYmV0dGVyIGtleWJvYXJkIG5hdmlnYXRpb24gZXhwZXJpZW5jZVxuXHRcdHRoaXMudHJlZVdhbGtlci5jdXJyZW50Tm9kZSA9IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYCMke0NTUy5lc2NhcGUobm9kZS5pZCl9YCk7XG5cdH1cblxuXHRwdWJsaWMgaXNUZW1wbGF0ZSh2YWx1ZSkge1xuXHRcdHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmO1xuXHR9XG5cblx0cHVibGljIGlzUHJvamVjdGVkKCkge1xuXHRcdHJldHVybiB0aGlzLnRyZWVWaWV3U2VydmljZS5jb250ZW50UHJvamVjdGVkO1xuXHR9XG5cblx0cHJpdmF0ZSBjb3B5Tm9kZShub2RlOiBOb2RlKTogTm9kZSB7XG5cdFx0Ly8gbWFraW5nIGEgcmVjdXJzaXZlIHNoYWxsb3cgY29weSB0byBhdm9pZCBwZXJmb3JtYW5jZSBpc3N1ZXMgd2hlbiBkZWVwbHkgY2xvbmluZyB0ZW1wbGF0ZVJlZnMgaWYgZGVmaW5lZCBpbiB0aGUgbm9kZVxuXHRcdGNvbnN0IGNvcGllZE5vZGUgPSBPYmplY3QuYXNzaWduKHt9LCBub2RlKTtcblx0XHRpZiAobm9kZS5jaGlsZHJlbikge1xuXHRcdFx0Y29waWVkTm9kZS5jaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW4ubWFwKGNoaWxkID0+IHRoaXMuY29weU5vZGUoY2hpbGQpKTtcblx0XHR9XG5cdFx0cmV0dXJuIGNvcGllZE5vZGU7XG5cdH1cbn1cbiJdfQ==