@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
64 lines • 21.6 kB
JavaScript
import { ChangeDetectionStrategy, Component, ContentChild, inject, Input } from '@angular/core';
import { getIconType } from '../../common/index';
import { NavigationService } from './navigation.service';
import * as i0 from "@angular/core";
import * as i1 from "../../directives/accessibility/tabbable-list/tabbable-list.directive";
import * as i2 from "../../directives/accessibility/tabbable-list/tabbable-list-item.directive";
import * as i3 from "@angular/common";
import * as i4 from "../icon/icon.component";
import * as i5 from "./navigation-link/navigation-link.directive";
export class NavigationComponent {
constructor() {
this._navigationService = inject(NavigationService);
/** Whether to present the menu as a hierarchical tree. */
this.tree = true;
/** The classes to be added to each different level */
this._hierarchyClasses = [
'',
'nav-second-level',
'nav-third-level',
'nav-fourth-level',
'nav-fifth-level',
];
}
/** The navigation items to populate the menu with. */
set items(items) {
this._navigationService.items = items;
}
get items() {
return this._navigationService.items;
}
/** Whether to collapse other menu items when expanding a menu item. */
set autoCollapse(autoCollapse) {
this._navigationService.autoCollapse = autoCollapse;
}
get _depthLimit() {
return this.tree ? this._hierarchyClasses.length : 2;
}
/**
* Returns true if the sets of items needs to be indented to make room for one or more expander.
*/
_needsIndent(items) {
return items && items.some(item => item.children && item.children.length > 0);
}
/** Determine the type of icon to display. We support `ux-icon` or `component` */
_getIconType(item) {
return getIconType(item.icon);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NavigationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: NavigationComponent, selector: "ux-navigation", inputs: { items: "items", tree: "tree", autoCollapse: "autoCollapse" }, providers: [NavigationService], queries: [{ propertyName: "navigationItemTemplate", first: true, predicate: ["uxNavigationItem"], descendants: true }], ngImport: i0, template: "<nav class=\"ux-side-nav\" [class.tree]=\"tree\" role=\"navigation\">\n\n @if (items) {\n <ol role=\"tree\" class=\"nav\" uxTabbableList [hierarchy]=\"true\">\n @for (item of items; track item; let rank = $index) {\n <ng-container\n [ngTemplateOutlet]=\"navigationNode\"\n [ngTemplateOutletContext]=\"{ item: item, level: 1, rank: rank, indent: _needsIndent(items) }\">\n </ng-container>\n }\n <ng-template #navigationNode let-item=\"item\" let-parent=\"parent\" let-level=\"level\" let-rank=\"rank\" let-indent=\"indent\">\n <li [attr.role]=\"(item.children && item.children.length > 0) ? 'treeitem' : 'none'\"\n [attr.aria-expanded]=\"(item.children && item.children.length > 0) ? item.expanded : null\"\n [class.selected]=\"item.expanded\"\n [class.disabled]=\"item.disabled\"\n [class.active]=\"navigationLink.isActive\">\n <a uxNavigationLink\n #navigationLink=\"uxNavigationLink\"\n #tli=\"ux-tabbable-list-item\"\n [navigationItem]=\"item\"\n [expanded]=\"item.expanded\"\n [canExpand]=\"level < _depthLimit\"\n [indent]=\"indent\"\n uxTabbableListItem\n [disabled]=\"item.disabled\"\n [parent]=\"parent\"\n [rank]=\"rank\"\n [(expanded)]=\"item.expanded\">\n @if (!navigationItemTemplate && item.children && item.children.length > 0 && level < _depthLimit) {\n <span\n aria-hidden=\"true\"\n class=\"nav-expander\"\n (click)=\"item.expanded = !item.expanded; $event.stopPropagation(); $event.preventDefault()\">\n </span>\n }\n <!-- Support UX Icons and Icon Component -->\n @if (!navigationItemTemplate && item.icon && !tree) {\n @if (_getIconType(item) !== 'component') {\n <span\n class=\"nav-icon\"\n [ngClass]=\"[_getIconType(item), item.icon]\">\n </span>\n }\n @if (_getIconType(item) === 'component') {\n <ux-icon\n class=\"nav-icon\"\n [name]=\"item.icon\">\n </ux-icon>\n }\n }\n @if (!navigationItemTemplate && item.iconUrl && !tree) {\n <img class=\"nav-icon\" [src]=\"item.iconUrl\" alt=\"item.iconLabel\">\n }\n @if (!navigationItemTemplate) {\n <span class=\"nav-title\">{{ item.title }}</span>\n }\n <ng-container\n [ngTemplateOutlet]=\"navigationItemTemplate\"\n [ngTemplateOutletContext]=\"{ item: item, level: level }\">\n </ng-container>\n </a>\n @if (item.children && item.expanded && level < _depthLimit) {\n <ol\n role=\"group\"\n class=\"nav\"\n [ngClass]=\"_hierarchyClasses[level]\">\n @for (child of item.children; track child; let rank = $index) {\n <ng-container\n [ngTemplateOutlet]=\"navigationNode\"\n [ngTemplateOutletContext]=\"{ item: child, parent: tli, level: level + 1, rank: rank, indent: navigationLink.indentChildren }\">\n </ng-container>\n }\n </ol>\n }\n </li>\n </ng-template>\n </ol>\n }\n\n <!-- Backward compatibility with the original ux-navigation -->\n @if (!items) {\n <ol role=\"tree\" class=\"nav\">\n <ng-content></ng-content>\n </ol>\n }\n\n</nav>\n", dependencies: [{ kind: "directive", type: i1.TabbableListDirective, selector: "[uxTabbableList]", inputs: ["direction", "wrap", "focusOnShow", "returnFocus", "hierarchy", "allowAltModifier", "allowCtrlModifier", "allowBoundaryKeys"], exportAs: ["ux-tabbable-list"] }, { kind: "directive", type: i2.TabbableListItemDirective, selector: "[uxTabbableListItem]", inputs: ["parent", "rank", "disabled", "expanded", "key"], outputs: ["expandedChange", "activated"], exportAs: ["ux-tabbable-list-item"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4.IconComponent, selector: "ux-icon", inputs: ["name", "size", "rotate", "flipHorizontal", "flipVertical"] }, { kind: "directive", type: i5.NavigationLinkDirective, selector: "[uxNavigationLink]", inputs: ["navigationItem", "expanded", "canExpand", "indent"], exportAs: ["uxNavigationLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NavigationComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-navigation', providers: [NavigationService], changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, template: "<nav class=\"ux-side-nav\" [class.tree]=\"tree\" role=\"navigation\">\n\n @if (items) {\n <ol role=\"tree\" class=\"nav\" uxTabbableList [hierarchy]=\"true\">\n @for (item of items; track item; let rank = $index) {\n <ng-container\n [ngTemplateOutlet]=\"navigationNode\"\n [ngTemplateOutletContext]=\"{ item: item, level: 1, rank: rank, indent: _needsIndent(items) }\">\n </ng-container>\n }\n <ng-template #navigationNode let-item=\"item\" let-parent=\"parent\" let-level=\"level\" let-rank=\"rank\" let-indent=\"indent\">\n <li [attr.role]=\"(item.children && item.children.length > 0) ? 'treeitem' : 'none'\"\n [attr.aria-expanded]=\"(item.children && item.children.length > 0) ? item.expanded : null\"\n [class.selected]=\"item.expanded\"\n [class.disabled]=\"item.disabled\"\n [class.active]=\"navigationLink.isActive\">\n <a uxNavigationLink\n #navigationLink=\"uxNavigationLink\"\n #tli=\"ux-tabbable-list-item\"\n [navigationItem]=\"item\"\n [expanded]=\"item.expanded\"\n [canExpand]=\"level < _depthLimit\"\n [indent]=\"indent\"\n uxTabbableListItem\n [disabled]=\"item.disabled\"\n [parent]=\"parent\"\n [rank]=\"rank\"\n [(expanded)]=\"item.expanded\">\n @if (!navigationItemTemplate && item.children && item.children.length > 0 && level < _depthLimit) {\n <span\n aria-hidden=\"true\"\n class=\"nav-expander\"\n (click)=\"item.expanded = !item.expanded; $event.stopPropagation(); $event.preventDefault()\">\n </span>\n }\n <!-- Support UX Icons and Icon Component -->\n @if (!navigationItemTemplate && item.icon && !tree) {\n @if (_getIconType(item) !== 'component') {\n <span\n class=\"nav-icon\"\n [ngClass]=\"[_getIconType(item), item.icon]\">\n </span>\n }\n @if (_getIconType(item) === 'component') {\n <ux-icon\n class=\"nav-icon\"\n [name]=\"item.icon\">\n </ux-icon>\n }\n }\n @if (!navigationItemTemplate && item.iconUrl && !tree) {\n <img class=\"nav-icon\" [src]=\"item.iconUrl\" alt=\"item.iconLabel\">\n }\n @if (!navigationItemTemplate) {\n <span class=\"nav-title\">{{ item.title }}</span>\n }\n <ng-container\n [ngTemplateOutlet]=\"navigationItemTemplate\"\n [ngTemplateOutletContext]=\"{ item: item, level: level }\">\n </ng-container>\n </a>\n @if (item.children && item.expanded && level < _depthLimit) {\n <ol\n role=\"group\"\n class=\"nav\"\n [ngClass]=\"_hierarchyClasses[level]\">\n @for (child of item.children; track child; let rank = $index) {\n <ng-container\n [ngTemplateOutlet]=\"navigationNode\"\n [ngTemplateOutletContext]=\"{ item: child, parent: tli, level: level + 1, rank: rank, indent: navigationLink.indentChildren }\">\n </ng-container>\n }\n </ol>\n }\n </li>\n </ng-template>\n </ol>\n }\n\n <!-- Backward compatibility with the original ux-navigation -->\n @if (!items) {\n <ol role=\"tree\" class=\"nav\">\n <ng-content></ng-content>\n </ol>\n }\n\n</nav>\n" }]
}], propDecorators: { items: [{
type: Input
}], tree: [{
type: Input
}], autoCollapse: [{
type: Input
}], navigationItemTemplate: [{
type: ContentChild,
args: ['uxNavigationItem', { static: false }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF2aWdhdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9uYXZpZ2F0aW9uL25hdmlnYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQWUsTUFBTSxlQUFlLENBQUM7QUFDN0csT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRWpELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7Ozs7O0FBU3pELE1BQU0sT0FBTyxtQkFBbUI7SUFQaEM7UUFRcUIsdUJBQWtCLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFXaEUsMERBQTBEO1FBQ2pELFNBQUksR0FBWSxJQUFJLENBQUM7UUFXOUIsc0RBQXNEO1FBQ3RELHNCQUFpQixHQUFHO1lBQ2hCLEVBQUU7WUFDRixrQkFBa0I7WUFDbEIsaUJBQWlCO1lBQ2pCLGtCQUFrQjtZQUNsQixpQkFBaUI7U0FDcEIsQ0FBQztLQWlCTDtJQTdDRyxzREFBc0Q7SUFDdEQsSUFDSSxLQUFLLENBQUMsS0FBdUI7UUFDN0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7SUFDMUMsQ0FBQztJQUNELElBQUksS0FBSztRQUNMLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQztJQUN6QyxDQUFDO0lBS0QsdUVBQXVFO0lBQ3ZFLElBQ0ksWUFBWSxDQUFDLFlBQXFCO1FBQ2xDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ3hELENBQUM7SUFjRCxJQUFJLFdBQVc7UUFDWCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxZQUFZLENBQUMsS0FBdUI7UUFDaEMsT0FBTyxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbEYsQ0FBQztJQUVELGlGQUFpRjtJQUNqRixZQUFZLENBQUMsSUFBb0I7UUFDN0IsT0FBTyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUM7K0dBL0NRLG1CQUFtQjttR0FBbkIsbUJBQW1CLGdIQUpqQixDQUFDLGlCQUFpQixDQUFDLGtKQ1JsQyx1bEhBdUZBOzs0RkQzRWEsbUJBQW1CO2tCQVAvQixTQUFTOytCQUNJLGVBQWUsYUFFZCxDQUFDLGlCQUFpQixDQUFDLG1CQUNiLHVCQUF1QixDQUFDLE1BQU0sdUJBQzFCLEtBQUs7OEJBT3RCLEtBQUs7c0JBRFIsS0FBSztnQkFTRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUYsWUFBWTtzQkFEZixLQUFLO2dCQU0rQyxzQkFBc0I7c0JBQTFFLFlBQVk7dUJBQUMsa0JBQWtCLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgQ29udGVudENoaWxkLCBpbmplY3QsIElucHV0LCBUZW1wbGF0ZVJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgZ2V0SWNvblR5cGUgfSBmcm9tICcuLi8uLi9jb21tb24vaW5kZXgnO1xuaW1wb3J0IHsgTmF2aWdhdGlvbkl0ZW0gfSBmcm9tICcuL25hdmlnYXRpb24taXRlbS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgTmF2aWdhdGlvblNlcnZpY2UgfSBmcm9tICcuL25hdmlnYXRpb24uc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAndXgtbmF2aWdhdGlvbicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL25hdmlnYXRpb24uY29tcG9uZW50Lmh0bWwnLFxuICAgIHByb3ZpZGVyczogW05hdmlnYXRpb25TZXJ2aWNlXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgICBwcmVzZXJ2ZVdoaXRlc3BhY2VzOiBmYWxzZVxufSlcbmV4cG9ydCBjbGFzcyBOYXZpZ2F0aW9uQ29tcG9uZW50IHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9uYXZpZ2F0aW9uU2VydmljZSA9IGluamVjdChOYXZpZ2F0aW9uU2VydmljZSk7XG5cbiAgICAvKiogVGhlIG5hdmlnYXRpb24gaXRlbXMgdG8gcG9wdWxhdGUgdGhlIG1lbnUgd2l0aC4gKi9cbiAgICBASW5wdXQoKVxuICAgIHNldCBpdGVtcyhpdGVtczogTmF2aWdhdGlvbkl0ZW1bXSkge1xuICAgICAgICB0aGlzLl9uYXZpZ2F0aW9uU2VydmljZS5pdGVtcyA9IGl0ZW1zO1xuICAgIH1cbiAgICBnZXQgaXRlbXMoKTogTmF2aWdhdGlvbkl0ZW1bXSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9uYXZpZ2F0aW9uU2VydmljZS5pdGVtcztcbiAgICB9XG5cbiAgICAvKiogV2hldGhlciB0byBwcmVzZW50IHRoZSBtZW51IGFzIGEgaGllcmFyY2hpY2FsIHRyZWUuICovXG4gICAgQElucHV0KCkgdHJlZTogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKiogV2hldGhlciB0byBjb2xsYXBzZSBvdGhlciBtZW51IGl0ZW1zIHdoZW4gZXhwYW5kaW5nIGEgbWVudSBpdGVtLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgc2V0IGF1dG9Db2xsYXBzZShhdXRvQ29sbGFwc2U6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fbmF2aWdhdGlvblNlcnZpY2UuYXV0b0NvbGxhcHNlID0gYXV0b0NvbGxhcHNlO1xuICAgIH1cblxuICAgIC8qKiBBY2Nlc3MgYSBjdXN0b20gbmF2aWdhdGlvbiBpdGVtIHRlbXBsYXRlIGlmIHByb3ZpZGVkICovXG4gICAgQENvbnRlbnRDaGlsZCgndXhOYXZpZ2F0aW9uSXRlbScsIHsgc3RhdGljOiBmYWxzZSB9KSBuYXZpZ2F0aW9uSXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjx2b2lkPjtcblxuICAgIC8qKiBUaGUgY2xhc3NlcyB0byBiZSBhZGRlZCB0byBlYWNoIGRpZmZlcmVudCBsZXZlbCAqL1xuICAgIF9oaWVyYXJjaHlDbGFzc2VzID0gW1xuICAgICAgICAnJyxcbiAgICAgICAgJ25hdi1zZWNvbmQtbGV2ZWwnLFxuICAgICAgICAnbmF2LXRoaXJkLWxldmVsJyxcbiAgICAgICAgJ25hdi1mb3VydGgtbGV2ZWwnLFxuICAgICAgICAnbmF2LWZpZnRoLWxldmVsJyxcbiAgICBdO1xuXG4gICAgZ2V0IF9kZXB0aExpbWl0KCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnRyZWUgPyB0aGlzLl9oaWVyYXJjaHlDbGFzc2VzLmxlbmd0aCA6IDI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBzZXRzIG9mIGl0ZW1zIG5lZWRzIHRvIGJlIGluZGVudGVkIHRvIG1ha2Ugcm9vbSBmb3Igb25lIG9yIG1vcmUgZXhwYW5kZXIuXG4gICAgICovXG4gICAgX25lZWRzSW5kZW50KGl0ZW1zOiBOYXZpZ2F0aW9uSXRlbVtdKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBpdGVtcyAmJiBpdGVtcy5zb21lKGl0ZW0gPT4gaXRlbS5jaGlsZHJlbiAmJiBpdGVtLmNoaWxkcmVuLmxlbmd0aCA+IDApO1xuICAgIH1cblxuICAgIC8qKiBEZXRlcm1pbmUgdGhlIHR5cGUgb2YgaWNvbiB0byBkaXNwbGF5LiBXZSBzdXBwb3J0IGB1eC1pY29uYCBvciBgY29tcG9uZW50YCAqL1xuICAgIF9nZXRJY29uVHlwZShpdGVtOiBOYXZpZ2F0aW9uSXRlbSk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBnZXRJY29uVHlwZShpdGVtLmljb24pO1xuICAgIH1cbn1cbiIsIjxuYXYgY2xhc3M9XCJ1eC1zaWRlLW5hdlwiIFtjbGFzcy50cmVlXT1cInRyZWVcIiByb2xlPVwibmF2aWdhdGlvblwiPlxuXG4gIEBpZiAoaXRlbXMpIHtcbiAgICA8b2wgcm9sZT1cInRyZWVcIiBjbGFzcz1cIm5hdlwiIHV4VGFiYmFibGVMaXN0IFtoaWVyYXJjaHldPVwidHJ1ZVwiPlxuICAgICAgQGZvciAoaXRlbSBvZiBpdGVtczsgdHJhY2sgaXRlbTsgbGV0IHJhbmsgPSAkaW5kZXgpIHtcbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIm5hdmlnYXRpb25Ob2RlXCJcbiAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyBpdGVtOiBpdGVtLCBsZXZlbDogMSwgcmFuazogcmFuaywgaW5kZW50OiBfbmVlZHNJbmRlbnQoaXRlbXMpIH1cIj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICB9XG4gICAgICA8bmctdGVtcGxhdGUgI25hdmlnYXRpb25Ob2RlIGxldC1pdGVtPVwiaXRlbVwiIGxldC1wYXJlbnQ9XCJwYXJlbnRcIiBsZXQtbGV2ZWw9XCJsZXZlbFwiIGxldC1yYW5rPVwicmFua1wiIGxldC1pbmRlbnQ9XCJpbmRlbnRcIj5cbiAgICAgICAgPGxpIFthdHRyLnJvbGVdPVwiKGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGggPiAwKSA/ICd0cmVlaXRlbScgOiAnbm9uZSdcIlxuICAgICAgICAgIFthdHRyLmFyaWEtZXhwYW5kZWRdPVwiKGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGggPiAwKSA/IGl0ZW0uZXhwYW5kZWQgOiBudWxsXCJcbiAgICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwiaXRlbS5leHBhbmRlZFwiXG4gICAgICAgICAgW2NsYXNzLmRpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIlxuICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwibmF2aWdhdGlvbkxpbmsuaXNBY3RpdmVcIj5cbiAgICAgICAgICA8YSB1eE5hdmlnYXRpb25MaW5rXG4gICAgICAgICAgICAjbmF2aWdhdGlvbkxpbms9XCJ1eE5hdmlnYXRpb25MaW5rXCJcbiAgICAgICAgICAgICN0bGk9XCJ1eC10YWJiYWJsZS1saXN0LWl0ZW1cIlxuICAgICAgICAgICAgW25hdmlnYXRpb25JdGVtXT1cIml0ZW1cIlxuICAgICAgICAgICAgW2V4cGFuZGVkXT1cIml0ZW0uZXhwYW5kZWRcIlxuICAgICAgICAgICAgW2NhbkV4cGFuZF09XCJsZXZlbCA8IF9kZXB0aExpbWl0XCJcbiAgICAgICAgICAgIFtpbmRlbnRdPVwiaW5kZW50XCJcbiAgICAgICAgICAgIHV4VGFiYmFibGVMaXN0SXRlbVxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIlxuICAgICAgICAgICAgW3BhcmVudF09XCJwYXJlbnRcIlxuICAgICAgICAgICAgW3JhbmtdPVwicmFua1wiXG4gICAgICAgICAgICBbKGV4cGFuZGVkKV09XCJpdGVtLmV4cGFuZGVkXCI+XG4gICAgICAgICAgICBAaWYgKCFuYXZpZ2F0aW9uSXRlbVRlbXBsYXRlICYmIGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGggPiAwICYmIGxldmVsIDwgX2RlcHRoTGltaXQpIHtcbiAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICBhcmlhLWhpZGRlbj1cInRydWVcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwibmF2LWV4cGFuZGVyXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiaXRlbS5leHBhbmRlZCA9ICFpdGVtLmV4cGFuZGVkOyAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7ICRldmVudC5wcmV2ZW50RGVmYXVsdCgpXCI+XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwhLS0gU3VwcG9ydCBVWCBJY29ucyBhbmQgSWNvbiBDb21wb25lbnQgLS0+XG4gICAgICAgICAgICBAaWYgKCFuYXZpZ2F0aW9uSXRlbVRlbXBsYXRlICYmIGl0ZW0uaWNvbiAmJiAhdHJlZSkge1xuICAgICAgICAgICAgICBAaWYgKF9nZXRJY29uVHlwZShpdGVtKSAhPT0gJ2NvbXBvbmVudCcpIHtcbiAgICAgICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJuYXYtaWNvblwiXG4gICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJbX2dldEljb25UeXBlKGl0ZW0pLCBpdGVtLmljb25dXCI+XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIEBpZiAoX2dldEljb25UeXBlKGl0ZW0pID09PSAnY29tcG9uZW50Jykge1xuICAgICAgICAgICAgICAgIDx1eC1pY29uXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cIm5hdi1pY29uXCJcbiAgICAgICAgICAgICAgICAgIFtuYW1lXT1cIml0ZW0uaWNvblwiPlxuICAgICAgICAgICAgICAgIDwvdXgtaWNvbj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgQGlmICghbmF2aWdhdGlvbkl0ZW1UZW1wbGF0ZSAmJiBpdGVtLmljb25VcmwgJiYgIXRyZWUpIHtcbiAgICAgICAgICAgICAgPGltZyBjbGFzcz1cIm5hdi1pY29uXCIgW3NyY109XCJpdGVtLmljb25VcmxcIiBhbHQ9XCJpdGVtLmljb25MYWJlbFwiPlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgQGlmICghbmF2aWdhdGlvbkl0ZW1UZW1wbGF0ZSkge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5hdi10aXRsZVwiPnt7IGl0ZW0udGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIm5hdmlnYXRpb25JdGVtVGVtcGxhdGVcIlxuICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyBpdGVtOiBpdGVtLCBsZXZlbDogbGV2ZWwgfVwiPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPC9hPlxuICAgICAgICAgIEBpZiAoaXRlbS5jaGlsZHJlbiAmJiBpdGVtLmV4cGFuZGVkICYmIGxldmVsIDwgX2RlcHRoTGltaXQpIHtcbiAgICAgICAgICAgIDxvbFxuICAgICAgICAgICAgICByb2xlPVwiZ3JvdXBcIlxuICAgICAgICAgICAgICBjbGFzcz1cIm5hdlwiXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cIl9oaWVyYXJjaHlDbGFzc2VzW2xldmVsXVwiPlxuICAgICAgICAgICAgICBAZm9yIChjaGlsZCBvZiBpdGVtLmNoaWxkcmVuOyB0cmFjayBjaGlsZDsgbGV0IHJhbmsgPSAkaW5kZXgpIHtcbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJuYXZpZ2F0aW9uTm9kZVwiXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyBpdGVtOiBjaGlsZCwgcGFyZW50OiB0bGksIGxldmVsOiBsZXZlbCArIDEsIHJhbms6IHJhbmssIGluZGVudDogbmF2aWdhdGlvbkxpbmsuaW5kZW50Q2hpbGRyZW4gfVwiPlxuICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L29sPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9saT5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9vbD5cbiAgfVxuXG4gIDwhLS0gQmFja3dhcmQgY29tcGF0aWJpbGl0eSB3aXRoIHRoZSBvcmlnaW5hbCB1eC1uYXZpZ2F0aW9uIC0tPlxuICBAaWYgKCFpdGVtcykge1xuICAgIDxvbCByb2xlPVwidHJlZVwiIGNsYXNzPVwibmF2XCI+XG4gICAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgPC9vbD5cbiAgfVxuXG48L25hdj5cbiJdfQ==