UNPKG

carbon-components-angular

Version:
412 lines 35.1 kB
import { Component, Input, Output, EventEmitter, TemplateRef } from "@angular/core"; import * as i0 from "@angular/core"; import * as i1 from "./treeview.service"; import * as i2 from "@angular/common"; import * as i3 from "carbon-components-angular/icon"; export class TreeNodeComponent { constructor(treeViewService) { this.treeViewService = treeViewService; this.id = `tree-node-${TreeNodeComponent.treeNodeCount++}`; this.active = false; this.disabled = false; this.selectable = true; this.expanded = false; this.selected = false; this.gap = 0; this.children = []; /** * Determines the depth of the node * Calculated by default when passing `Node` array to `TreeViewComponent`, manual entry required otherwise */ this.depth = 0; this.nodeFocus = new EventEmitter(); this.nodeBlur = new EventEmitter(); this.nodeSelect = new EventEmitter(); this.nodetoggle = new EventEmitter(); } /** * Simple way to set all attributes of Node component via node object * Would simplify setting component attributes when dynamically rendering node. */ set node(node) { this._node = node; this.id = node.id ?? this.id; this.active = node.active ?? this.active; this.disabled = node.disabled ?? this.disabled; this.selectable = node.selectable ?? this.selectable; this.expanded = node.expanded ?? this.expanded; this.label = node.label ?? this.label; this.labelContext = node.labelContext ?? this.labelContext; this.value = node.value ?? this.value; this.icon = node.icon ?? this.icon; this.selected = node.selected ?? this.selected; this.depth = node.depth ?? this.depth; this.gap = node.gap ?? this.gap; this.children = node.children ?? this.children; this.iconContext = node.iconText ?? this.iconContext; } get node() { return this._node; } /** * Caclulate offset for margin/padding */ ngAfterContentChecked() { this.offset = this.calculateOffset(); } /** * Highlight the node */ ngOnInit() { // Highlight the node this.subscription = this.treeViewService.selectionObservable.subscribe((value) => { this.selected = this.selectable && value.has(this.id); this.active = this.selectable && this.selected; }); } /** * Unsubscribe from subscriptions */ ngOnDestroy() { this.subscription?.unsubscribe(); } /** * Selects the node and emits the event from the tree view component * @param event */ nodeClick(event) { if (!this.disabled) { event.target.parentElement.focus(); if (this.selectable || this.children.length === 0) { this.selected = true; this.active = true; const node = { id: this.id, label: this.label, value: this.value }; // Passes event to all nodes to update highlighting & parent to emit this.treeViewService.selectNode(node); this.nodeSelect.emit(node); } else { this.toggleExpanded(event); } } } /** * Calculate the node offset * @returns Number */ calculateOffset() { // Parent node with icon if (this.children.length && this.icon) { return this.depth + 1 + this.depth * 0.5; } // parent node without icon if (this.children.length) { return this.depth + 1; } // leaf node with icon if (this.icon) { return this.depth + 2 + this.depth * 0.5; } return this.depth + this.gap + 2.5; } emitFocusEvent(event) { const node = { id: this.id, label: this.label, value: this.value }; this.nodeFocus.emit({ node, event }); this.treeViewService.focusNode(node); } emitBlurEvent(event) { this.nodeBlur.emit({ node: { id: this.id, label: this.label, value: this.value }, event }); } /** * Expand children if not disabled * @param event: Event */ toggleExpanded(event) { if (!this.disabled) { this.nodetoggle.emit({ node: { id: this.id, label: this.label, value: this.value }, event }); this.expanded = !this.expanded; // Prevent selection of the node event.stopPropagation(); } } /** * Manages the keyboard accessibility for children expansion & selection */ navigateTree(event) { if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "Enter") { event.stopPropagation(); } // Unexpand if (event.key === "ArrowLeft") { if (this.expanded && this.children) { this.toggleExpanded(event); } } if (event.key === "ArrowRight") { if (!this.expanded && this.children) { this.toggleExpanded(event); } } if (event.key === "Enter") { event.preventDefault(); this.nodeClick(event); } } isTemplate(value) { return value instanceof TemplateRef; } isProjected() { return this.treeViewService.contentProjected; } } TreeNodeComponent.treeNodeCount = 0; TreeNodeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeNodeComponent, deps: [{ token: i1.TreeViewService }], target: i0.ɵɵFactoryTarget.Component }); TreeNodeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TreeNodeComponent, selector: "cds-tree-node", inputs: { id: "id", active: "active", disabled: "disabled", selectable: "selectable", expanded: "expanded", label: "label", labelContext: "labelContext", selected: "selected", value: "value", icon: "icon", iconContext: "iconContext", gap: "gap", children: "children", depth: "depth", node: "node" }, outputs: { nodeFocus: "nodeFocus", nodeBlur: "nodeBlur", nodeSelect: "nodeSelect", nodetoggle: "nodetoggle" }, ngImport: i0, template: ` <div [id]="id" class="cds--tree-node" [ngClass]="{ 'cds--tree-node--active': active, 'cds--tree-node--disabled': disabled, 'cds--tree-node--selected': selected, 'cds--tree-leaf-node': !children.length, 'cds--tree-parent-node': children.length, 'cds--tree-node--with-icon': icon }" [attr.aria-expanded]="expanded || null" [attr.aria-current]="active || null" [attr.aria-selected]="disabled ? null : selected" [attr.aria-disabled]="disabled" role="treeitem" [attr.tabindex]="selected ? 0 : -1" (focus)="emitFocusEvent($event)" (blur)="emitBlurEvent($event)" (keydown)="navigateTree($event)"> <div *ngIf="!children.length" class="cds--tree-node__label" [style.padding-inline-start.rem]="offset" [style.margin-inline-start.rem]="-offset" (click)="nodeClick($event)"> <!-- Icon --> <ng-container *ngIf="icon && !isTemplate(icon)"> <svg class="cds--tree-node__icon" [cdsIcon]="icon" size="16"> </svg> </ng-container> <ng-template *ngIf="isTemplate(icon)" [ngTemplateOutlet]="icon"></ng-template> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </div> <div *ngIf="children.length" class="cds--tree-node__label" [style.padding-inline-start.rem]="offset" [style.margin-inline-start.rem]="-offset" role="group" (click)="nodeClick($event)"> <span class="cds--tree-parent-node__toggle" [attr.disabled]="disabled || null" (click)="toggleExpanded($event)"> <svg class="cds--tree-parent-node__toggle-icon" [ngClass]="{'cds--tree-parent-node__toggle-icon--expanded' : expanded}" ibmIcon="caret--down" size="16"> </svg> </span> <span class="cds--tree-node__label__details"> <!-- Icon --> <ng-container *ngIf="icon && !isTemplate(icon)"> <svg class="cds--tree-node__icon" [cdsIcon]="icon" size="16"> </svg> </ng-container> <ng-template *ngIf="isTemplate(icon)" [ngTemplateOutlet]="icon" [ngTemplateOutletContext]="{ $implicit: iconContext }"> </ng-template> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </span> </div> <div *ngIf="expanded" role="group" class="cds--tree-node__children"> <ng-container *ngIf="isProjected(); else notProjected"> <ng-content></ng-content> </ng-container> <ng-template #notProjected> <cds-tree-node *ngFor="let childNode of children" [node]="childNode" [depth]="depth + 1" [disabled]="disabled" (nodetoggle)="nodetoggle.emit($event)"> </cds-tree-node> </ng-template> </div> </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: "directive", type: i3.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: 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: TreeNodeComponent, decorators: [{ type: Component, args: [{ selector: "cds-tree-node", template: ` <div [id]="id" class="cds--tree-node" [ngClass]="{ 'cds--tree-node--active': active, 'cds--tree-node--disabled': disabled, 'cds--tree-node--selected': selected, 'cds--tree-leaf-node': !children.length, 'cds--tree-parent-node': children.length, 'cds--tree-node--with-icon': icon }" [attr.aria-expanded]="expanded || null" [attr.aria-current]="active || null" [attr.aria-selected]="disabled ? null : selected" [attr.aria-disabled]="disabled" role="treeitem" [attr.tabindex]="selected ? 0 : -1" (focus)="emitFocusEvent($event)" (blur)="emitBlurEvent($event)" (keydown)="navigateTree($event)"> <div *ngIf="!children.length" class="cds--tree-node__label" [style.padding-inline-start.rem]="offset" [style.margin-inline-start.rem]="-offset" (click)="nodeClick($event)"> <!-- Icon --> <ng-container *ngIf="icon && !isTemplate(icon)"> <svg class="cds--tree-node__icon" [cdsIcon]="icon" size="16"> </svg> </ng-container> <ng-template *ngIf="isTemplate(icon)" [ngTemplateOutlet]="icon"></ng-template> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </div> <div *ngIf="children.length" class="cds--tree-node__label" [style.padding-inline-start.rem]="offset" [style.margin-inline-start.rem]="-offset" role="group" (click)="nodeClick($event)"> <span class="cds--tree-parent-node__toggle" [attr.disabled]="disabled || null" (click)="toggleExpanded($event)"> <svg class="cds--tree-parent-node__toggle-icon" [ngClass]="{'cds--tree-parent-node__toggle-icon--expanded' : expanded}" ibmIcon="caret--down" size="16"> </svg> </span> <span class="cds--tree-node__label__details"> <!-- Icon --> <ng-container *ngIf="icon && !isTemplate(icon)"> <svg class="cds--tree-node__icon" [cdsIcon]="icon" size="16"> </svg> </ng-container> <ng-template *ngIf="isTemplate(icon)" [ngTemplateOutlet]="icon" [ngTemplateOutletContext]="{ $implicit: iconContext }"> </ng-template> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: labelContext }"> </ng-template> </span> </div> <div *ngIf="expanded" role="group" class="cds--tree-node__children"> <ng-container *ngIf="isProjected(); else notProjected"> <ng-content></ng-content> </ng-container> <ng-template #notProjected> <cds-tree-node *ngFor="let childNode of children" [node]="childNode" [depth]="depth + 1" [disabled]="disabled" (nodetoggle)="nodetoggle.emit($event)"> </cds-tree-node> </ng-template> </div> </div> ` }] }], ctorParameters: function () { return [{ type: i1.TreeViewService }]; }, propDecorators: { id: [{ type: Input }], active: [{ type: Input }], disabled: [{ type: Input }], selectable: [{ type: Input }], expanded: [{ type: Input }], label: [{ type: Input }], labelContext: [{ type: Input }], selected: [{ type: Input }], value: [{ type: Input }], icon: [{ type: Input }], iconContext: [{ type: Input }], gap: [{ type: Input }], children: [{ type: Input }], depth: [{ type: Input }], node: [{ type: Input }], nodeFocus: [{ type: Output }], nodeBlur: [{ type: Output }], nodeSelect: [{ type: Output }], nodetoggle: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ub2RlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmVldmlldy90cmVlLW5vZGUuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBSVosV0FBVyxFQUVYLE1BQU0sZUFBZSxDQUFDOzs7OztBQThHdkIsTUFBTSxPQUFPLGlCQUFpQjtJQTBEN0IsWUFBb0IsZUFBZ0M7UUFBaEMsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBeEQzQyxPQUFFLEdBQUcsYUFBYSxpQkFBaUIsQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBQ3RELFdBQU0sR0FBRyxLQUFLLENBQUM7UUFDZixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ2pCLGVBQVUsR0FBRyxJQUFJLENBQUM7UUFDbEIsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUdqQixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBSWpCLFFBQUcsR0FBRyxDQUFDLENBQUM7UUFDUixhQUFRLEdBQVcsRUFBRSxDQUFDO1FBRS9COzs7V0FHRztRQUNNLFVBQUssR0FBRyxDQUFDLENBQUM7UUE2QlQsY0FBUyxHQUFHLElBQUksWUFBWSxFQUFlLENBQUM7UUFDNUMsYUFBUSxHQUFHLElBQUksWUFBWSxFQUFlLENBQUM7UUFDM0MsZUFBVSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFDdEMsZUFBVSxHQUFHLElBQUksWUFBWSxFQUFlLENBQUM7SUFNQSxDQUFDO0lBcEN4RDs7O09BR0c7SUFDSCxJQUFhLElBQUksQ0FBQyxJQUFVO1FBQzNCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBRWxCLElBQUksQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFD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RyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csSUFBSTtzQkFBWixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csR0FBRztzQkFBWCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBTUcsS0FBSztzQkFBYixLQUFLO2dCQU1PLElBQUk7c0JBQWhCLEtBQUs7Z0JBdUJJLFNBQVM7c0JBQWxCLE1BQU07Z0JBQ0csUUFBUTtzQkFBakIsTUFBTTtnQkFDRyxVQUFVO3NCQUFuQixNQUFNO2dCQUNHLFVBQVU7c0JBQW5CLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRDb21wb25lbnQsXG5cdElucHV0LFxuXHRPdXRwdXQsXG5cdEV2ZW50RW1pdHRlcixcblx0T25Jbml0LFxuXHRPbkRlc3Ryb3ksXG5cdEFmdGVyQ29udGVudEluaXQsXG5cdFRlbXBsYXRlUmVmLFxuXHRBZnRlckNvbnRlbnRDaGVja2VkXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgVHJlZVZpZXdTZXJ2aWNlIH0gZnJvbSBcIi4vdHJlZXZpZXcuc2VydmljZVwiO1xuaW1wb3J0IHsgRXZlbnRPbk5vZGUsIE5vZGUgfSBmcm9tIFwiLi90cmVlLW5vZGUudHlwZXNcIjtcblxuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImNkcy10cmVlLW5vZGVcIixcblx0dGVtcGxhdGU6IGBcblx0XHQ8ZGl2XG5cdFx0XHRbaWRdPVwiaWRcIlxuXHRcdFx0Y2xhc3M9XCJjZHMtLXRyZWUtbm9kZVwiXG5cdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdCdjZHMtLXRyZWUtbm9kZS0tYWN0aXZlJzogYWN0aXZlLFxuXHRcdFx0XHQnY2RzLS10cmVlLW5vZGUtLWRpc2FibGVkJzogZGlzYWJsZWQsXG5cdFx0XHRcdCdjZHMtLXRyZWUtbm9kZS0tc2VsZWN0ZWQnOiBzZWxlY3RlZCxcblx0XHRcdFx0J2Nkcy0tdHJlZS1sZWFmLW5vZGUnOiAhY2hpbGRyZW4ubGVuZ3RoLFxuXHRcdFx0XHQnY2RzLS10cmVlLXBhcmVudC1ub2RlJzogY2hpbGRyZW4ubGVuZ3RoLFxuXHRcdFx0XHQnY2RzLS10cmVlLW5vZGUtLXdpdGgtaWNvbic6IGljb25cblx0XHRcdH1cIlxuXHRcdFx0W2F0dHIuYXJpYS1leHBhbmRlZF09XCJleHBhbmRlZCB8fCBudWxsXCJcblx0XHRcdFthdHRyLmFyaWEtY3VycmVudF09XCJhY3RpdmUgfHwgbnVsbFwiXG5cdFx0XHRbYXR0ci5hcmlhLXNlbGVjdGVkXT1cImRpc2FibGVkID8gbnVsbCA6IHNlbGVjdGVkXCJcblx0XHRcdFthdHRyLmFyaWEtZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuXHRcdFx0cm9sZT1cInRyZWVpdGVtXCJcblx0XHRcdFthdHRyLnRhYmluZGV4XT1cInNlbGVjdGVkID8gMCA6IC0xXCJcblx0XHRcdChmb2N1cyk9XCJlbWl0Rm9jdXNFdmVudCgkZXZlbnQpXCJcblx0XHRcdChibHVyKT1cImVtaXRCbHVyRXZlbnQoJGV2ZW50KVwiXG5cdFx0XHQoa2V5ZG93bik9XCJuYXZpZ2F0ZVRyZWUoJGV2ZW50KVwiPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHQqbmdJZj1cIiFjaGlsZHJlbi5sZW5ndGhcIlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tdHJlZS1ub2RlX19sYWJlbFwiXG5cdFx0XHRcdFtzdHlsZS5wYWRkaW5nLWlubGluZS1zdGFydC5yZW1dPVwib2Zmc2V0XCJcblx0XHRcdFx0W3N0eWxlLm1hcmdpbi1pbmxpbmUtc3RhcnQucmVtXT1cIi1vZmZzZXRcIlxuXHRcdFx0XHQoY2xpY2spPVwibm9kZUNsaWNrKCRldmVudClcIj5cblx0XHRcdFx0PCEtLSBJY29uIC0tPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiaWNvbiAmJiAhaXNUZW1wbGF0ZShpY29uKVwiPlxuXHRcdFx0XHRcdDxzdmdcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS10cmVlLW5vZGVfX2ljb25cIlxuXHRcdFx0XHRcdFx0W2Nkc0ljb25dPVwiaWNvblwiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIj5cblx0XHRcdFx0XHQ8L3N2Zz5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy10ZW1wbGF0ZSAqbmdJZj1cImlzVGVtcGxhdGUoaWNvbilcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJpY29uXCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKGxhYmVsKVwiPnt7bGFiZWx9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctdGVtcGxhdGVcblx0XHRcdFx0XHQqbmdJZj1cImlzVGVtcGxhdGUobGFiZWwpXCJcblx0XHRcdFx0XHRbbmdUZW1wbGF0ZU91dGxldF09XCJsYWJlbFwiXG5cdFx0XHRcdFx0W25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgJGltcGxpY2l0OiBsYWJlbENvbnRleHQgfVwiPlxuXHRcdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdCpuZ0lmPVwiY2hpbGRyZW4ubGVuZ3RoXCJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLXRyZWUtbm9kZV9fbGFiZWxcIlxuXHRcdFx0XHRbc3R5bGUucGFkZGluZy1pbmxpbmUtc3RhcnQucmVtXT1cIm9mZnNldFwiXG5cdFx0XHRcdFtzdHlsZS5tYXJnaW4taW5saW5lLXN0YXJ0LnJlbV09XCItb2Zmc2V0XCJcblx0XHRcdFx0cm9sZT1cImdyb3VwXCJcblx0XHRcdFx0KGNsaWNrKT1cIm5vZGVDbGljaygkZXZlbnQpXCI+XG5cdFx0XHRcdDxzcGFuXG5cdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXRyZWUtcGFyZW50LW5vZGVfX3RvZ2dsZVwiXG5cdFx0XHRcdFx0W2F0dHIuZGlzYWJsZWRdPVwiZGlzYWJsZWQgfHwgbnVsbFwiXG5cdFx0XHRcdFx0KGNsaWNrKT1cInRvZ2dsZUV4cGFuZGVkKCRldmVudClcIj5cblx0XHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tdHJlZS1wYXJlbnQtbm9kZV9fdG9nZ2xlLWljb25cIlxuXHRcdFx0XHRcdFx0W25nQ2xhc3NdPVwieydjZHMtLXRyZWUtcGFyZW50LW5vZGVfX3RvZ2dsZS1pY29uLS1leHBhbmRlZCcgOiBleHBhbmRlZH1cIlxuXHRcdFx0XHRcdFx0aWJtSWNvbj1cImNhcmV0LS1kb3duXCJcblx0XHRcdFx0XHRcdHNpemU9XCIxNlwiPlxuXHRcdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8L3NwYW4+XG5cdFx0XHRcdDxzcGFuIGNsYXNzPVwiY2RzLS10cmVlLW5vZGVfX2xhYmVsX19kZXRhaWxzXCI+XG5cdFx0XHRcdFx0PCEtLSBJY29uIC0tPlxuXHRcdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJpY29uICYmICFpc1RlbXBsYXRlKGljb24pXCI+XG5cdFx0XHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS10cmVlLW5vZGVfX2ljb25cIlxuXHRcdFx0XHRcdFx0XHRbY2RzSWNvbl09XCJpY29uXCJcblx0XHRcdFx0XHRcdFx0c2l6ZT1cIjE2XCI+XG5cdFx0XHRcdFx0XHQ8L3N2Zz5cblx0XHRcdFx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0XHQ8bmctdGVtcGxhdGVcblx0XHRcdFx0XHRcdCpuZ0lmPVwiaXNUZW1wbGF0ZShpY29uKVwiXG5cdFx0XHRcdFx0XHRbbmdUZW1wbGF0ZU91dGxldF09XCJpY29uXCJcblx0XHRcdFx0XHRcdFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7ICRpbXBsaWNpdDogaWNvbkNvbnRleHQgfVwiPlxuXHRcdFx0XHRcdDwvbmctdGVtcGxhdGU+XG5cdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKGxhYmVsKVwiPnt7bGFiZWx9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdDxuZy10ZW1wbGF0ZVxuXHRcdFx0XHRcdFx0Km5nSWY9XCJpc1RlbXBsYXRlKGxhYmVsKVwiXG5cdFx0XHRcdFx0XHRbbmdUZW1wbGF0ZU91dGxldF09XCJsYWJlbFwiXG5cdFx0XHRcdFx0XHRbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGxhYmVsQ29udGV4dCB9XCI+XG5cdFx0XHRcdFx0PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0PC9zcGFuPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdCpuZ0lmPVwiZXhwYW5kZWRcIlxuXHRcdFx0XHRyb2xlPVwiZ3JvdXBcIlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tdHJlZS1ub2RlX19jaGlsZHJlblwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiaXNQcm9qZWN0ZWQoKTsgZWxzZSBub3RQcm9qZWN0ZWRcIj5cblx0XHRcdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG5cdFx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctdGVtcGxhdGUgI25vdFByb2plY3RlZD5cblx0XHRcdFx0XHQ8Y2RzLXRyZWUtbm9kZVxuXHRcdFx0XHRcdFx0Km5nRm9yPVwibGV0IGNoaWxkTm9kZSBvZiBjaGlsZHJlblwiXG5cdFx0XHRcdFx0XHRbbm9kZV09XCJjaGlsZE5vZGVcIlxuXHRcdFx0XHRcdFx0W2RlcHRoXT1cImRlcHRoICsgMVwiXG5cdFx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuXHRcdFx0XHRcdFx0KG5vZGV0b2dnbGUpPVwibm9kZXRvZ2dsZS5lbWl0KCRldmVudClcIj5cblx0XHRcdFx0XHQ8L2Nkcy10cmVlLW5vZGU+XG5cdFx0XHRcdDwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L2Rpdj5cblx0YFxufSlcbmV4cG9ydCBjbGFzcyBUcmVlTm9kZUNvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyQ29udGVudENoZWNrZWQsIE9uSW5pdCwgT25EZXN0cm95IHtcblx0c3RhdGljIHRyZWVOb2RlQ291bnQgPSAwO1xuXHRASW5wdXQoKSBpZCA9IGB0cmVlLW5vZGUtJHtUcmVlTm9kZUNvbXBvbmVudC50cmVlTm9kZUNvdW50Kyt9YDtcblx0QElucHV0KCkgYWN0aXZlID0gZmFsc2U7XG5cdEBJbnB1dCgpIGRpc2FibGVkID0gZmFsc2U7XG5cdEBJbnB1dCgpIHNlbGVjdGFibGUgPSB0cnVlO1xuXHRASW5wdXQoKSBleHBhbmRlZCA9IGZhbHNlO1xuXHRASW5wdXQoKSBsYWJlbDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pjtcblx0QElucHV0KCkgbGFiZWxDb250ZXh0OiBhbnk7XG5cdEBJbnB1dCgpIHNlbGVjdGVkID0gZmFsc2U7XG5cdEBJbnB1dCgpIHZhbHVlO1xuXHRASW5wdXQoKSBpY29uOiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHRASW5wdXQoKSBpY29uQ29udGV4dDogYW55O1xuXHRASW5wdXQoKSBnYXAgPSAwO1xuXHRASW5wdXQoKSBjaGlsZHJlbjogTm9kZVtdID0gW107XG5cblx0LyoqXG5cdCAqIERldGVybWluZXMgdGhlIGRlcHRoIG9mIHRoZSBub2RlXG5cdCAqIENhbGN1bGF0ZWQgYnkgZGVmYXVsdCB3aGVuIHBhc3NpbmcgYE5vZGVgIGFycmF5IHRvIGBUcmVlVmlld0NvbXBvbmVudGAsIG1hbnVhbCBlbnRyeSByZXF1aXJlZCBvdGhlcndpc2Vcblx0ICovXG5cdEBJbnB1dCgpIGRlcHRoID0gMDtcblxuXHQvKipcblx0ICogU2ltcGxlIHdheSB0byBzZXQgYWxsIGF0dHJpYnV0ZXMgb2YgTm9kZSBjb21wb25lbnQgdmlhIG5vZGUgb2JqZWN0XG5cdCAqIFdvdWxkIHNpbXBsaWZ5IHNldHRpbmcgY29tcG9uZW50IGF0dHJpYnV0ZXMgd2hlbiBkeW5hbWljYWxseSByZW5kZXJpbmcgbm9kZS5cblx0ICovXG5cdEBJbnB1dCgpIHNldCBub2RlKG5vZGU6IE5vZGUpIHtcblx0XHR0aGlzLl9ub2RlID0gbm9kZTtcblxuXHRcdHRoaXMuaWQgPSBub2RlLmlkID8/IHRoaXMuaWQ7XG5cdFx0dGhpcy5hY3RpdmUgPSBub2RlLmFjdGl2ZSA/PyB0aGlzLmFjdGl2ZTtcblx0XHR0aGlzLmRpc2FibGVkID0gbm9kZS5kaXNhYmxlZCA/PyB0aGlzLmRpc2FibGVkO1xuXHRcdHRoaXMuc2VsZWN0YWJsZSA9IG5vZGUuc2VsZWN0YWJsZSA/PyB0aGlzLnNlbGVjdGFibGU7XG5cdFx0dGhpcy5leHBhbmRlZCA9IG5vZGUuZXhwYW5kZWQgPz8gdGhpcy5leHBhbmRlZDtcblx0XHR0aGlzLmxhYmVsID0gbm9kZS5sYWJlbCA/PyB0aGlzLmxhYmVsO1xuXHRcdHRoaXMubGFiZWxDb250ZXh0ID0gbm9kZS5sYWJlbENvbnRleHQgPz8gdGhpcy5sYWJlbENvbnRleHQ7XG5cdFx0dGhpcy52YWx1ZSA9IG5vZGUudmFsdWUgPz8gdGhpcy52YWx1ZTtcblx0XHR0aGlzLmljb24gPSBub2RlLmljb24gPz8gdGhpcy5pY29uO1xuXHRcdHRoaXMuc2VsZWN0ZWQgPSBub2RlLnNlbGVjdGVkID8/IHRoaXMuc2VsZWN0ZWQ7XG5cdFx0dGhpcy5kZXB0aCA9IG5vZGUuZGVwdGggPz8gdGhpcy5kZXB0aDtcblx0XHR0aGlzLmdhcCA9IG5vZGUuZ2FwID8/IHRoaXMuZ2FwO1xuXHRcdHRoaXMuY2hpbGRyZW4gPSBub2RlLmNoaWxkcmVuID8/IHRoaXMuY2hpbGRyZW47XG5cdFx0dGhpcy5pY29uQ29udGV4dCA9IG5vZGUuaWNvblRleHQgPz8gdGhpcy5pY29uQ29udGV4dDtcblx0fVxuXG5cdGdldCBub2RlKCkge1xuXHRcdHJldHVybiB0aGlzLl9ub2RlO1xuXHR9XG5cblx0QE91dHB1dCgpIG5vZGVGb2N1cyA9IG5ldyBFdmVudEVtaXR0ZXI8RXZlbnRPbk5vZGU+KCk7XG5cdEBPdXRwdXQoKSBub2RlQmx1ciA9IG5ldyBFdmVudEVtaXR0ZXI8RXZlbnRPbk5vZGU+KCk7XG5cdEBPdXRwdXQoKSBub2RlU2VsZWN0ID0gbmV3IEV2ZW50RW1pdHRlcjxOb2RlPigpO1xuXHRAT3V0cHV0KCkgbm9kZXRvZ2dsZSA9IG5ldyBFdmVudEVtaXR0ZXI8RXZlbnRPbk5vZGU+KCk7XG5cblx0b2Zmc2V0O1xuXHRwcml2YXRlIF9ub2RlO1xuXHRwcml2YXRlIHN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG5cdGNvbnN0cnVjdG9yKHByaXZhdGUgdHJlZVZpZXdTZXJ2aWNlOiBUcmVlVmlld1NlcnZpY2UpIHt9XG5cblx0LyoqXG5cdCAqIENhY2x1bGF0ZSBvZmZzZXQgZm9yIG1hcmdpbi9wYWRkaW5nXG5cdCAqL1xuXHRuZ0FmdGVyQ29udGVudENoZWNrZWQoKTogdm9pZCB7XG5cdFx0dGhpcy5vZmZzZXQgPSB0aGlzLmNhbGN1bGF0ZU9mZnNldCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEhpZ2hsaWdodCB0aGUgbm9kZVxuXHQgKi9cblx0bmdPbkluaXQoKTogdm9pZCB7XG5cdFx0Ly8gSGlnaGxpZ2h0IHRoZSBub2RlXG5cdFx0dGhpcy5zdWJzY3JpcHRpb24gPSB0aGlzLnRyZWVWaWV3U2VydmljZS5zZWxlY3Rpb25PYnNlcnZhYmxlLnN1YnNjcmliZSgodmFsdWU6IE1hcDxzdHJpbmcsIE5vZGU+KSA9PiB7XG5cdFx0XHR0aGlzLnNlbGVjdGVkID0gdGhpcy5zZWxlY3RhYmxlICYmIHZhbHVlLmhhcyh0aGlzLmlkKTtcblx0XHRcdHRoaXMuYWN0aXZlID0gdGhpcy5zZWxlY3RhYmxlICYmIHRoaXMuc2VsZWN0ZWQ7XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogVW5zdWJzY3JpYmUgZnJvbSBzdWJzY3JpcHRpb25zXG5cdCAqL1xuXHRuZ09uRGVzdHJveSgpOiB2b2lkIHtcblx0XHR0aGlzLnN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZWxlY3RzIHRoZSBub2RlIGFuZCBlbWl0cyB0aGUgZXZlbnQgZnJvbSB0aGUgdHJlZSB2aWV3IGNvbXBvbmVudFxuXHQgKiBAcGFyYW0gZXZlbnRcblx0ICovXG5cdG5vZGVDbGljayhldmVudCkge1xuXHRcdGlmICghdGhpcy5kaXNhYmxlZCkge1xuXHRcdFx0ZXZlbnQudGFyZ2V0LnBhcmVudEVsZW1lbnQuZm9jdXMoKTtcblx0XHRcdGlmICh0aGlzLnNlbGVjdGFibGUgfHwgdGhpcy5jaGlsZHJlbi5sZW5ndGggPT09IDApIHtcblx0XHRcdFx0dGhpcy5zZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRcdHRoaXMuYWN0aXZlID0gdHJ1ZTtcblx0XHRcdFx0Y29uc3Qgbm9kZSA9IHsgaWQ6IHRoaXMuaWQsIGxhYmVsOiB0aGlzLmxhYmVsLCB2YWx1ZTogdGhpcy52YWx1ZSB9O1xuXHRcdFx0XHQvLyBQYXNzZXMgZXZlbnQgdG8gYWxsIG5vZGVzIHRvIHVwZGF0ZSBoaWdobGlnaHRpbmcgJiBwYXJlbnQgdG8gZW1pdFxuXHRcdFx0XHR0aGlzLnRyZWVWaWV3U2VydmljZS5zZWxlY3ROb2RlKG5vZGUpO1xuXHRcdFx0XHR0aGlzLm5vZGVTZWxlY3QuZW1pdChub2RlKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMudG9nZ2xlRXhwYW5kZWQoZXZlbnQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxjdWxhdGUgdGhlIG5vZGUgb2Zmc2V0XG5cdCAqIEByZXR1cm5zIE51bWJlclxuXHQgKi9cblx0Y2FsY3VsYXRlT2Zmc2V0KCkge1xuXHRcdC8vIFBhcmVudCBub2RlIHdpdGggaWNvblxuXHRcdGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCAmJiB0aGlzLmljb24pIHtcblx0XHRcdHJldHVybiB0aGlzLmRlcHRoICsgMSArIHRoaXMuZGVwdGggKiAwLjU7XG5cdFx0fVxuXG5cdFx0Ly8gcGFyZW50IG5vZGUgd2l0aG91dCBpY29uXG5cdFx0aWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5kZXB0aCArIDE7XG5cdFx0fVxuXG5cdFx0Ly8gbGVhZiBub2RlIHdpdGggaWNvblxuXHRcdGlmICh0aGlzLmljb24pIHtcblx0XHRcdHJldHVybiB0aGlzLmRlcHRoICsgMiArIHRoaXMuZGVwdGggKiAwLjU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZGVwdGggKyB0aGlzLmdhcCArIDIuNTtcblx0fVxuXG5cdGVtaXRGb2N1c0V2ZW50KGV2ZW50KSB7XG5cdFx0Y29uc3Qgbm9kZSA9IHsgaWQ6IHRoaXMuaWQsIGxhYmVsOiB0aGlzLmxhYmVsLCB2YWx1ZTogdGhpcy52YWx1ZSB9O1xuXHRcdHRoaXMubm9kZUZvY3VzLmVtaXQoeyBub2RlLCBldmVudCB9KTtcblx0XHR0aGlzLnRyZWVWaWV3U2VydmljZS5mb2N1c05vZGUobm9kZSk7XG5cdH1cblxuXHRlbWl0Qmx1ckV2ZW50KGV2ZW50KSB7XG5cdFx0dGhpcy5ub2RlQmx1ci5lbWl0KHsgbm9kZTogeyBpZDogdGhpcy5pZCwgbGFiZWw6IHRoaXMubGFiZWwsIHZhbHVlOiB0aGlzLnZhbHVlIH0sIGV2ZW50IH0pO1xuXHR9XG5cblx0LyoqXG5cdCAqIEV4cGFuZCBjaGlsZHJlbiBpZiBub3QgZGlzYWJsZWRcblx0ICogQHBhcmFtIGV2ZW50OiBFdmVudFxuXHQgKi9cblx0dG9nZ2xlRXhwYW5kZWQoZXZlbnQpIHtcblx0XHRpZiAoIXRoaXMuZGlzYWJsZWQpIHtcblx0XHRcdHRoaXMubm9kZXRvZ2dsZS5lbWl0KHsgbm9kZTogeyBpZDogdGhpcy5pZCwgbGFiZWw6IHRoaXMubGFiZWwsIHZhbHVlOiB0aGlzLnZhbHVlIH0sIGV2ZW50IH0pO1xuXHRcdFx0dGhpcy5leHBhbmRlZCA9ICF0aGlzLmV4cGFuZGVkO1xuXHRcdFx0Ly8gUHJldmVudCBzZWxlY3Rpb24gb2YgdGhlIG5vZGVcblx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBNYW5hZ2VzIHRoZSBrZXlib2FyZCBhY2Nlc3NpYmlsaXR5IGZvciBjaGlsZHJlbiBleHBhbnNpb24gJiBzZWxlY3Rpb25cblx0ICovXG5cdG5hdmlnYXRlVHJlZShldmVudDogS2V5Ym9hcmRFdmVudCkge1xuXHRcdGlmIChldmVudC5rZXkgPT09IFwiQXJyb3dMZWZ0XCIgfHwgZXZlbnQua2V5ID09PSBcIkFycm93UmlnaHRcIiB8fCBldmVudC5rZXkgPT09IFwiRW50ZXJcIikge1xuXHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0fVxuXHRcdC8vIFVuZXhwYW5kXG5cdFx0aWYgKGV2ZW50LmtleSA9PT0gXCJBcnJvd0xlZnRcIikge1xuXHRcdFx0aWYgKHRoaXMuZXhwYW5kZWQgJiYgdGhpcy5jaGlsZHJlbikge1xuXHRcdFx0XHR0aGlzLnRvZ2dsZUV4cGFuZGVkKGV2ZW50KTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoZXZlbnQua2V5ID09PSBcIkFycm93UmlnaHRcIikge1xuXHRcdFx0aWYgKCF0aGlzLmV4cGFuZGVkICYmIHRoaXMuY2hpbGRyZW4pIHtcblx0XHRcdFx0dGhpcy50b2dnbGVFeHBhbmRlZChldmVudCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKGV2ZW50LmtleSA9PT0gXCJFbnRlclwiKSB7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0dGhpcy5ub2RlQ2xpY2soZXZlbnQpO1xuXHRcdH1cblx0fVxuXG5cdHB1YmxpYyBpc1RlbXBsYXRlKHZhbHVlKSB7XG5cdFx0cmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgVGVtcGxhdGVSZWY7XG5cdH1cblxuXHRwdWJsaWMgaXNQcm9qZWN0ZWQoKSB7XG5cdFx0cmV0dXJuIHRoaXMudHJlZVZpZXdTZXJ2aWNlLmNvbnRlbnRQcm9qZWN0ZWQ7XG5cdH1cbn1cbiJdfQ==