UNPKG

@vismaux/ngx-nordic-cool

Version:
128 lines 29.6 kB
import { Component, ChangeDetectionStrategy, ContentChildren, Host, } from '@angular/core'; import { fromEvent, Subject } from 'rxjs'; import { debounceTime, takeUntil } from 'rxjs/operators'; import { NcNavbarMenuItemComponent } from '../navbar-menu-item/navbar-menu-item.component'; import * as i0 from "@angular/core"; import * as i1 from "../navbar.component"; import * as i2 from "@angular/common"; import * as i3 from "../../dropdown/dropdown.directive"; import * as i4 from "../../dropdown/dropdown-toggle.directive"; import * as i5 from "../../dropdown/dropdown-menu.directive"; const MORE_ITEM_WIDTH = 100; export class NcNavbarMenuComponent { constructor(navbar, elRef, cdRef, ngZone) { this.navbar = navbar; this.elRef = elRef; this.cdRef = cdRef; this.ngZone = ngZone; this.resized$ = new Subject(); this.destroyed$ = new Subject(); this.menuItemsWidths = []; this.hiddenMenuItems = []; this.brandOptionsOpen = false; } get anyHiddenMenuItem() { return this.hiddenMenuItems.some((i) => i); } get activeBrandOption() { return this.navbar.brandOptions.find((n) => n.active); } ngAfterViewInit() { this.rerenderMenuItems(); // Re-render menu items whenever projection changes this.menuItems.changes .pipe(takeUntil(this.destroyed$)) .subscribe(() => this.rerenderMenuItems()); // Re-render menu items in case styles completes to load AFTER the initialization of this menu. // Ref issue: #28 fromEvent(window, 'load') .pipe(takeUntil(this.destroyed$)) .subscribe(() => this.rerenderMenuItems()); // Attach resize observer if available, // otherwise user will have to use `checkResponsiveness` manually. if (typeof window !== 'undefined' && window.ResizeObserver) { this.resizeObserver = new window.ResizeObserver(() => this.resized$.next()); this.resizeObserver.observe(this.elRef.nativeElement); this.resized$ .pipe(debounceTime(100), takeUntil(this.destroyed$)) .subscribe(() => { this.ngZone.run(() => this.checkResponsiveness()); }); } } ngOnDestroy() { this.destroyed$.next(); if (this.resizeObserver) { this.resizeObserver.unobserve(this.elRef.nativeElement); } } checkResponsiveness() { if (this.navbar.isMobile()) { return; } let changed = false; // Check if everything fits well const availableWidth = this.elRef.nativeElement.offsetWidth; const totalMenuItemsWidth = this.menuItemsWidths.reduce((a, b) => a + b, 0); let takenWidth = totalMenuItemsWidth; if (availableWidth > takenWidth) { this.menuItems.forEach((_, i) => { if (this.hiddenMenuItems[i]) { this.hiddenMenuItems[i] = false; changed = true; } }); } else { takenWidth = MORE_ITEM_WIDTH; // Go trough menu items and add ones that fit this.menuItems.forEach((_, i) => { const totalTaken = takenWidth + this.menuItemsWidths[i]; const doesNotFit = totalTaken > availableWidth; if (this.hiddenMenuItems[i] !== doesNotFit) { this.hiddenMenuItems[i] = doesNotFit; changed = true; } if (!doesNotFit) { takenWidth += this.menuItemsWidths[i]; } }); } if (changed) { this.cdRef.detectChanges(); } } rerenderMenuItems() { // Reset cached widths this.menuItemsWidths = []; this.hiddenMenuItems = []; // Needed for ngTemplateOutlet this.cdRef.detectChanges(); // Must wait for the menu items to be painted so that the menu can properly // calculate the correct visibility based on the size of the item content. Promise.resolve().then(() => { this.cacheMenuWidths(); this.checkResponsiveness(); }); } toggleBrandOptions() { this.brandOptionsOpen = !this.brandOptionsOpen; this.cdRef.detectChanges(); } cacheMenuWidths() { const items = this.elRef.nativeElement.querySelectorAll('ul.first-level > li.virtual > a.nav-item'); this.menuItemsWidths = Array.from(items).map((e) => e.offsetWidth); } } NcNavbarMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.3", ngImport: i0, type: NcNavbarMenuComponent, deps: [{ token: i1.NcNavbarComponent, host: true }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); NcNavbarMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.3", type: NcNavbarMenuComponent, selector: "nc-navbar-menu", queries: [{ propertyName: "menuItems", predicate: NcNavbarMenuItemComponent }], ngImport: i0, template: "<ul class=\"nav first-level\" role=\"menubar\">\n <!--\n \"Virtual\" menu items that are always hidden.\n Used for measurement.\n -->\n <ng-container\n *ngFor=\"let item of menuItems; let i = index\"\n [ngTemplateOutlet]=\"item.content\"\n [ngTemplateOutletContext]=\"{ virtual: true }\"\n ></ng-container>\n\n <!-- Main menu bar that is visible only for desktop -->\n <ng-container *ngIf=\"(navbar.isMobile$ | async) === false\">\n <ng-container *ngFor=\"let item of menuItems; let i = index\">\n <ng-container\n *ngIf=\"!hiddenMenuItems[i]\"\n [ngTemplateOutlet]=\"item.content\"\n ></ng-container>\n </ng-container>\n </ng-container>\n\n <!-- \"More\" button for opening the hidden menu (visible in both desktop and mobile) -->\n <li\n *ngIf=\"(navbar.isMobile$ | async) || anyHiddenMenuItem\"\n role=\"none\"\n ncDropdown\n #dropdown=\"ncDropdown\"\n class=\"menudrop dropdown\"\n [class.open]=\"dropdown.isOpen$ | async\"\n >\n <a\n id=\"nc-navbar-more-menu\"\n ncDropdownToggle\n role=\"menuitem\"\n class=\"dropdown-toggle\"\n data-toggle=\"dropdown\"\n [attr.aria-expanded]=\"dropdown.isOpen$ | async\"\n [attr.aria-haspopup]=\"(navbar.isMobile$ | async) || anyHiddenMenuItem\"\n (click)=\"dropdown.toggle()\"\n href=\"javascript: void(0)\"\n >\n <span [class.hidden]=\"(navbar.isMobile$ | async) === false\" i18n\n >Menu</span\n >\n <i class=\"icon-align-justify\"></i>\n </a>\n\n <ul\n ncDropdownMenu\n class=\"dropdown-menu dropdown-menu-right\"\n role=\"menu\"\n aria-labelledby=\"nc-navbar-more-menu\"\n >\n <!-- Brand information that's visible only for mobile -->\n <ng-container\n *ngIf=\"(navbar.isMobile$ | async) && navbar.brandOptions.length > 0\"\n >\n <li role=\"none\" class=\"navbar-brand\" [class.is-open]=\"brandOptionsOpen\">\n <a\n class=\"dropdown-toggle dropped-apps-toggle\"\n tabindex=\"-1\"\n role=\"button\"\n [attr.aria-expanded]=\"brandOptionsOpen\"\n (click)=\"toggleBrandOptions()\"\n >{{ activeBrandOption?.label }}<span class=\"caret\"></span\n ></a>\n </li>\n\n <ng-container *ngIf=\"brandOptionsOpen\">\n <li\n role=\"none\"\n *ngFor=\"let brandOption of navbar.brandOptions\"\n [class.active]=\"brandOption.active\"\n >\n <ng-container\n *ngIf=\"!brandOption.active\"\n [ngTemplateOutlet]=\"brandOption.content\"\n ></ng-container>\n </li>\n </ng-container>\n </ng-container>\n\n <!-- Hidden menu options that didn't fit in the main menu bar -->\n <ng-container *ngIf=\"!brandOptionsOpen\">\n <ng-container *ngFor=\"let item of menuItems; let i = index\">\n <ng-container\n *ngIf=\"(navbar.isMobile$ | async) || hiddenMenuItems[i]\"\n [ngTemplateOutlet]=\"item.content\"\n [ngTemplateOutletContext]=\"{ dropdown: dropdown }\"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ul>\n </li>\n</ul>\n", styles: [":host{display:block;min-width:0;flex:1}:host>ul{display:flex}:host>ul>li{float:none!important}:host>ul>li>a{white-space:nowrap}:host .hidden{display:none}\n"], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NcDropdownDirective, selector: "[ncDropdown]", inputs: ["isOpen"], exportAs: ["ncDropdown"] }, { type: i4.NcDropdownToggleDirective, selector: "[ncDropdownToggle]" }, { type: i5.NcDropdownMenuDirective, selector: "[ncDropdownMenu]" }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.3", ngImport: i0, type: NcNavbarMenuComponent, decorators: [{ type: Component, args: [{ selector: 'nc-navbar-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"nav first-level\" role=\"menubar\">\n <!--\n \"Virtual\" menu items that are always hidden.\n Used for measurement.\n -->\n <ng-container\n *ngFor=\"let item of menuItems; let i = index\"\n [ngTemplateOutlet]=\"item.content\"\n [ngTemplateOutletContext]=\"{ virtual: true }\"\n ></ng-container>\n\n <!-- Main menu bar that is visible only for desktop -->\n <ng-container *ngIf=\"(navbar.isMobile$ | async) === false\">\n <ng-container *ngFor=\"let item of menuItems; let i = index\">\n <ng-container\n *ngIf=\"!hiddenMenuItems[i]\"\n [ngTemplateOutlet]=\"item.content\"\n ></ng-container>\n </ng-container>\n </ng-container>\n\n <!-- \"More\" button for opening the hidden menu (visible in both desktop and mobile) -->\n <li\n *ngIf=\"(navbar.isMobile$ | async) || anyHiddenMenuItem\"\n role=\"none\"\n ncDropdown\n #dropdown=\"ncDropdown\"\n class=\"menudrop dropdown\"\n [class.open]=\"dropdown.isOpen$ | async\"\n >\n <a\n id=\"nc-navbar-more-menu\"\n ncDropdownToggle\n role=\"menuitem\"\n class=\"dropdown-toggle\"\n data-toggle=\"dropdown\"\n [attr.aria-expanded]=\"dropdown.isOpen$ | async\"\n [attr.aria-haspopup]=\"(navbar.isMobile$ | async) || anyHiddenMenuItem\"\n (click)=\"dropdown.toggle()\"\n href=\"javascript: void(0)\"\n >\n <span [class.hidden]=\"(navbar.isMobile$ | async) === false\" i18n\n >Menu</span\n >\n <i class=\"icon-align-justify\"></i>\n </a>\n\n <ul\n ncDropdownMenu\n class=\"dropdown-menu dropdown-menu-right\"\n role=\"menu\"\n aria-labelledby=\"nc-navbar-more-menu\"\n >\n <!-- Brand information that's visible only for mobile -->\n <ng-container\n *ngIf=\"(navbar.isMobile$ | async) && navbar.brandOptions.length > 0\"\n >\n <li role=\"none\" class=\"navbar-brand\" [class.is-open]=\"brandOptionsOpen\">\n <a\n class=\"dropdown-toggle dropped-apps-toggle\"\n tabindex=\"-1\"\n role=\"button\"\n [attr.aria-expanded]=\"brandOptionsOpen\"\n (click)=\"toggleBrandOptions()\"\n >{{ activeBrandOption?.label }}<span class=\"caret\"></span\n ></a>\n </li>\n\n <ng-container *ngIf=\"brandOptionsOpen\">\n <li\n role=\"none\"\n *ngFor=\"let brandOption of navbar.brandOptions\"\n [class.active]=\"brandOption.active\"\n >\n <ng-container\n *ngIf=\"!brandOption.active\"\n [ngTemplateOutlet]=\"brandOption.content\"\n ></ng-container>\n </li>\n </ng-container>\n </ng-container>\n\n <!-- Hidden menu options that didn't fit in the main menu bar -->\n <ng-container *ngIf=\"!brandOptionsOpen\">\n <ng-container *ngFor=\"let item of menuItems; let i = index\">\n <ng-container\n *ngIf=\"(navbar.isMobile$ | async) || hiddenMenuItems[i]\"\n [ngTemplateOutlet]=\"item.content\"\n [ngTemplateOutletContext]=\"{ dropdown: dropdown }\"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ul>\n </li>\n</ul>\n", styles: [":host{display:block;min-width:0;flex:1}:host>ul{display:flex}:host>ul>li{float:none!important}:host>ul>li>a{white-space:nowrap}:host .hidden{display:none}\n"] }] }], ctorParameters: function () { return [{ type: i1.NcNavbarComponent, decorators: [{ type: Host }] }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { menuItems: [{ type: ContentChildren, args: [NcNavbarMenuItemComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF2YmFyLW1lbnUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LW5vcmRpYy1jb29sL3NyYy9saWIvbmF2YmFyL25hdmJhci1tZW51L25hdmJhci1tZW51LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1ub3JkaWMtY29vbC9zcmMvbGliL25hdmJhci9uYXZiYXItbWVudS9uYXZiYXItbWVudS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULHVCQUF1QixFQUV2QixlQUFlLEVBS2YsSUFBSSxHQUVMLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDekQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sZ0RBQWdELENBQUM7Ozs7Ozs7QUFHM0YsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDO0FBUTVCLE1BQU0sT0FBTyxxQkFBcUI7SUFvQmhDLFlBQ2lCLE1BQXlCLEVBQ2hDLEtBQThCLEVBQzlCLEtBQXdCLEVBQ3hCLE1BQWM7UUFIUCxXQUFNLEdBQU4sTUFBTSxDQUFtQjtRQUNoQyxVQUFLLEdBQUwsS0FBSyxDQUF5QjtRQUM5QixVQUFLLEdBQUwsS0FBSyxDQUFtQjtRQUN4QixXQUFNLEdBQU4sTUFBTSxDQUFRO1FBdkJQLGFBQVEsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO1FBQy9CLGVBQVUsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO1FBRTFDLG9CQUFlLEdBQWEsRUFBRSxDQUFDO1FBRXZDLG9CQUFlLEdBQWMsRUFBRSxDQUFDO1FBQ2hDLHFCQUFnQixHQUFHLEtBQUssQ0FBQztJQWtCdEIsQ0FB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bUIsRUFBRSxDQUFDO1FBQzdCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGtCQUFrQjtRQUNoQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7UUFDL0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRU8sZUFBZTtRQUNyQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FDckQsMENBQTBDLENBQzNDLENBQUM7UUFDRixJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDckUsQ0FBQzs7a0hBaklVLHFCQUFxQjtzR0FBckIscUJBQXFCLGdGQVNmLHlCQUF5Qiw2QkNsQzVDLHdyR0ErRkE7MkZEdEVhLHFCQUFxQjtrQkFOakMsU0FBUzsrQkFDRSxnQkFBZ0IsbUJBR1QsdUJBQXVCLENBQUMsTUFBTTs7MEJBdUI1QyxJQUFJOzBIQVhQLFNBQVM7c0JBRFIsZUFBZTt1QkFBQyx5QkFBeUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBRdWVyeUxpc3QsXG4gIENvbnRlbnRDaGlsZHJlbixcbiAgRWxlbWVudFJlZixcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgT25EZXN0cm95LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgSG9zdCxcbiAgTmdab25lLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGZyb21FdmVudCwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBOY05hdmJhck1lbnVJdGVtQ29tcG9uZW50IH0gZnJvbSAnLi4vbmF2YmFyLW1lbnUtaXRlbS9uYXZiYXItbWVudS1pdGVtLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOY05hdmJhckNvbXBvbmVudCB9IGZyb20gJy4uL25hdmJhci5jb21wb25lbnQnO1xuXG5jb25zdCBNT1JFX0lURU1fV0lEVEggPSAxMDA7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25jLW5hdmJhci1tZW51JyxcbiAgdGVtcGxhdGVVcmw6ICcuL25hdmJhci1tZW51LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vbmF2YmFyLW1lbnUuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIE5jTmF2YmFyTWVudUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uRGVzdHJveSwgQWZ0ZXJWaWV3SW5pdCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVzaXplZCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3llZCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICBwcml2YXRlIHJlc2l6ZU9ic2VydmVyOiBhbnk7XG4gIHByaXZhdGUgbWVudUl0ZW1zV2lkdGhzOiBudW1iZXJbXSA9IFtdO1xuXG4gIGhpZGRlbk1lbnVJdGVtczogYm9vbGVhbltdID0gW107XG4gIGJyYW5kT3B0aW9uc09wZW4gPSBmYWxzZTtcblxuICBAQ29udGVudENoaWxkcmVuKE5jTmF2YmFyTWVudUl0ZW1Db21wb25lbnQpXG4gIG1lbnVJdGVtczogUXVlcnlMaXN0PE5jTmF2YmFyTWVudUl0ZW1Db21wb25lbnQ+O1xuXG4gIGdldCBhbnlIaWRkZW5NZW51SXRlbSgpIHtcbiAgICByZXR1cm4gdGhpcy5oaWRkZW5NZW51SXRlbXMuc29tZSgoaSkgPT4gaSk7XG4gIH1cblxuICBnZXQgYWN0aXZlQnJhbmRPcHRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMubmF2YmFyLmJyYW5kT3B0aW9ucy5maW5kKChuKSA9PiBuLmFjdGl2ZSk7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBASG9zdCgpIHB1YmxpYyBuYXZiYXI6IE5jTmF2YmFyQ29tcG9uZW50LFxuICAgIHByaXZhdGUgZWxSZWY6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LFxuICAgIHByaXZhdGUgY2RSZWY6IENoYW5nZURldGVjdG9yUmVmLFxuICAgIHByaXZhdGUgbmdab25lOiBOZ1pvbmVcbiAgKSB7fVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnJlcmVuZGVyTWVudUl0ZW1zKCk7XG5cbiAgICAvLyBSZS1yZW5kZXIgbWVudSBpdGVtcyB3aGVuZXZlciBwcm9qZWN0aW9uIGNoYW5nZXNcbiAgICB0aGlzLm1lbnVJdGVtcy5jaGFuZ2VzXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZXJlbmRlck1lbnVJdGVtcygpKTtcblxuICAgIC8vIFJlLXJlbmRlciBtZW51IGl0ZW1zIGluIGNhc2Ugc3R5bGVzIGNvbXBsZXRlcyB0byBsb2FkIEFGVEVSIHRoZSBpbml0aWFsaXphdGlvbiBvZiB0aGlzIG1lbnUuXG4gICAgLy8gUmVmIGlzc3VlOiAjMjhcbiAgICBmcm9tRXZlbnQod2luZG93LCAnbG9hZCcpXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZXJlbmRlck1lbnVJdGVtcygpKTtcblxuICAgIC8vIEF0dGFjaCByZXNpemUgb2JzZXJ2ZXIgaWYgYXZhaWxhYmxlLFxuICAgIC8vIG90aGVyd2lzZSB1c2VyIHdpbGwgaGF2ZSB0byB1c2UgYGNoZWNrUmVzcG9uc2l2ZW5lc3NgIG1hbnVhbGx5LlxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiAod2luZG93IGFzIGFueSkuUmVzaXplT2JzZXJ2ZXIpIHtcbiAgICAgIHRoaXMucmVzaXplT2JzZXJ2ZXIgPSBuZXcgKHdpbmRvdyBhcyBhbnkpLlJlc2l6ZU9ic2VydmVyKCgpID0+XG4gICAgICAgIHRoaXMucmVzaXplZCQubmV4dCgpXG4gICAgICApO1xuICAgICAgdGhpcy5yZXNpemVPYnNlcnZlci5vYnNlcnZlKHRoaXMuZWxSZWYubmF0aXZlRWxlbWVudCk7XG4gICAgICB0aGlzLnJlc2l6ZWQkXG4gICAgICAgIC5waXBlKGRlYm91bmNlVGltZSgxMDApLCB0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKSlcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuY2hlY2tSZXNwb25zaXZlbmVzcygpKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95ZWQkLm5leHQoKTtcbiAgICBpZiAodGhpcy5yZXNpemVPYnNlcnZlcikge1xuICAgICAgdGhpcy5yZXNpemVPYnNlcnZlci51bm9ic2VydmUodGhpcy5lbFJlZi5uYXRpdmVFbGVtZW50KTtcbiAgICB9XG4gIH1cblxuICBjaGVja1Jlc3BvbnNpdmVuZXNzKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm5hdmJhci5pc01vYmlsZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGNoYW5nZWQgPSBmYWxzZTtcbiAgICAvLyBDaGVjayBpZiBldmVyeXRoaW5nIGZpdHMgd2VsbFxuICAgIGNvbnN0IGF2YWlsYWJsZVdpZHRoID0gdGhpcy5lbFJlZi5uYXRpdmVFbGVtZW50Lm9mZnNldFdpZHRoO1xuICAgIGNvbnN0IHRvdGFsTWVudUl0ZW1zV2lkdGggPSB0aGlzLm1lbnVJdGVtc1dpZHRocy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcbiAgICBsZXQgdGFrZW5XaWR0aCA9IHRvdGFsTWVudUl0ZW1zV2lkdGg7XG5cbiAgICBpZiAoYXZhaWxhYmxlV2lkdGggPiB0YWtlbldpZHRoKSB7XG4gICAgICB0aGlzLm1lbnVJdGVtcy5mb3JFYWNoKChfLCBpKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmhpZGRlbk1lbnVJdGVtc1tpXSkge1xuICAgICAgICAgIHRoaXMuaGlkZGVuTWVudUl0ZW1zW2ldID0gZmFsc2U7XG4gICAgICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0YWtlbldpZHRoID0gTU9SRV9JVEVNX1dJRFRIO1xuXG4gICAgICAvLyBHbyB0cm91Z2ggbWVudSBpdGVtcyBhbmQgYWRkIG9uZXMgdGhhdCBmaXRcbiAgICAgIHRoaXMubWVudUl0ZW1zLmZvckVhY2goKF8sIGkpID0+IHtcbiAgICAgICAgY29uc3QgdG90YWxUYWtlbiA9IHRha2VuV2lkdGggKyB0aGlzLm1lbnVJdGVtc1dpZHRoc1tpXTtcbiAgICAgICAgY29uc3QgZG9lc05vdEZpdCA9IHRvdGFsVGFrZW4gPiBhdmFpbGFibGVXaWR0aDtcbiAgICAgICAgaWYgKHRoaXMuaGlkZGVuTWVudUl0ZW1zW2ldICE9PSBkb2VzTm90Rml0KSB7XG4gICAgICAgICAgdGhpcy5oaWRkZW5NZW51SXRlbXNbaV0gPSBkb2VzTm90Rml0O1xuICAgICAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghZG9lc05vdEZpdCkge1xuICAgICAgICAgIHRha2VuV2lkdGggKz0gdGhpcy5tZW51SXRlbXNXaWR0aHNbaV07XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChjaGFuZ2VkKSB7XG4gICAgICB0aGlzLmNkUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG4gIH1cblxuICByZXJlbmRlck1lbnVJdGVtcygpOiB2b2lkIHtcbiAgICAvLyBSZXNldCBjYWNoZWQgd2lkdGhzXG4gICAgdGhpcy5tZW51SXRlbXNXaWR0aHMgPSBbXTtcbiAgICB0aGlzLmhpZGRlbk1lbnVJdGVtcyA9IFtdO1xuXG4gICAgLy8gTmVlZGVkIGZvciBuZ1RlbXBsYXRlT3V0bGV0XG4gICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG5cbiAgICAvLyBNdXN0IHdhaXQgZm9yIHRoZSBtZW51IGl0ZW1zIHRvIGJlIHBhaW50ZWQgc28gdGhhdCB0aGUgbWVudSBjYW4gcHJvcGVybHlcbiAgICAvLyBjYWxjdWxhdGUgdGhlIGNvcnJlY3QgdmlzaWJpbGl0eSBiYXNlZCBvbiB0aGUgc2l6ZSBvZiB0aGUgaXRlbSBjb250ZW50LlxuICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5jYWNoZU1lbnVXaWR0aHMoKTtcbiAgICAgIHRoaXMuY2hlY2tSZXNwb25zaXZlbmVzcygpO1xuICAgIH0pO1xuICB9XG5cbiAgdG9nZ2xlQnJhbmRPcHRpb25zKCk6IHZvaWQge1xuICAgIHRoaXMuYnJhbmRPcHRpb25zT3BlbiA9ICF0aGlzLmJyYW5kT3B0aW9uc09wZW47XG4gICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cblxuICBwcml2YXRlIGNhY2hlTWVudVdpZHRocygpOiB2b2lkIHtcbiAgICBjb25zdCBpdGVtcyA9IHRoaXMuZWxSZWYubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsPEhUTUxFbGVtZW50PihcbiAgICAgICd1bC5maXJzdC1sZXZlbCA+IGxpLnZpcnR1YWwgPiBhLm5hdi1pdGVtJ1xuICAgICk7XG4gICAgdGhpcy5tZW51SXRlbXNXaWR0aHMgPSBBcnJheS5mcm9tKGl0ZW1zKS5tYXAoKGUpID0+IGUub2Zmc2V0V2lkdGgpO1xuICB9XG59XG4iLCI8dWwgY2xhc3M9XCJuYXYgZmlyc3QtbGV2ZWxcIiByb2xlPVwibWVudWJhclwiPlxuICA8IS0tXG4gICAgXCJWaXJ0dWFsXCIgbWVudSBpdGVtcyB0aGF0IGFyZSBhbHdheXMgaGlkZGVuLlxuICAgIFVzZWQgZm9yIG1lYXN1cmVtZW50LlxuICAtLT5cbiAgPG5nLWNvbnRhaW5lclxuICAgICpuZ0Zvcj1cImxldCBpdGVtIG9mIG1lbnVJdGVtczsgbGV0IGkgPSBpbmRleFwiXG4gICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiaXRlbS5jb250ZW50XCJcbiAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyB2aXJ0dWFsOiB0cnVlIH1cIlxuICA+PC9uZy1jb250YWluZXI+XG5cbiAgPCEtLSBNYWluIG1lbnUgYmFyIHRoYXQgaXMgdmlzaWJsZSBvbmx5IGZvciBkZXNrdG9wIC0tPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwiKG5hdmJhci5pc01vYmlsZSQgfCBhc3luYykgPT09IGZhbHNlXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgaXRlbSBvZiBtZW51SXRlbXM7IGxldCBpID0gaW5kZXhcIj5cbiAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgKm5nSWY9XCIhaGlkZGVuTWVudUl0ZW1zW2ldXCJcbiAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiaXRlbS5jb250ZW50XCJcbiAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9uZy1jb250YWluZXI+XG5cbiAgPCEtLSBcIk1vcmVcIiBidXR0b24gZm9yIG9wZW5pbmcgdGhlIGhpZGRlbiBtZW51ICh2aXNpYmxlIGluIGJvdGggZGVza3RvcCBhbmQgbW9iaWxlKSAtLT5cbiAgPGxpXG4gICAgKm5nSWY9XCIobmF2YmFyLmlzTW9iaWxlJCB8IGFzeW5jKSB8fCBhbnlIaWRkZW5NZW51SXRlbVwiXG4gICAgcm9sZT1cIm5vbmVcIlxuICAgIG5jRHJvcGRvd25cbiAgICAjZHJvcGRvd249XCJuY0Ryb3Bkb3duXCJcbiAgICBjbGFzcz1cIm1lbnVkcm9wIGRyb3Bkb3duXCJcbiAgICBbY2xhc3Mub3Blbl09XCJkcm9wZG93bi5pc09wZW4kIHwgYXN5bmNcIlxuICA+XG4gICAgPGFcbiAgICAgIGlkPVwibmMtbmF2YmFyLW1vcmUtbWVudVwiXG4gICAgICBuY0Ryb3Bkb3duVG9nZ2xlXG4gICAgICByb2xlPVwibWVudWl0ZW1cIlxuICAgICAgY2xhc3M9XCJkcm9wZG93bi10b2dnbGVcIlxuICAgICAgZGF0YS10b2dnbGU9XCJkcm9wZG93blwiXG4gICAgICBbYXR0ci5hcmlhLWV4cGFuZGVkXT1cImRyb3Bkb3duLmlzT3BlbiQgfCBhc3luY1wiXG4gICAgICBbYXR0ci5hcmlhLWhhc3BvcHVwXT1cIihuYXZiYXIuaXNNb2JpbGUkIHwgYXN5bmMpIHx8IGFueUhpZGRlbk1lbnVJdGVtXCJcbiAgICAgIChjbGljayk9XCJkcm9wZG93bi50b2dnbGUoKVwiXG4gICAgICBocmVmPVwiamF2YXNjcmlwdDogdm9pZCgwKVwiXG4gICAgPlxuICAgICAgPHNwYW4gW2NsYXNzLmhpZGRlbl09XCIobmF2YmFyLmlzTW9iaWxlJCB8IGFzeW5jKSA9PT0gZmFsc2VcIiBpMThuXG4gICAgICAgID5NZW51PC9zcGFuXG4gICAgICA+XG4gICAgICA8aSBjbGFzcz1cImljb24tYWxpZ24tanVzdGlmeVwiPjwvaT5cbiAgICA8L2E+XG5cbiAgICA8dWxcbiAgICAgIG5jRHJvcGRvd25NZW51XG4gICAgICBjbGFzcz1cImRyb3Bkb3duLW1lbnUgZHJvcGRvd24tbWVudS1yaWdodFwiXG4gICAgICByb2xlPVwibWVudVwiXG4gICAgICBhcmlhLWxhYmVsbGVkYnk9XCJuYy1uYXZiYXItbW9yZS1tZW51XCJcbiAgICA+XG4gICAgICA8IS0tIEJyYW5kIGluZm9ybWF0aW9uIHRoYXQncyB2aXNpYmxlIG9ubHkgZm9yIG1vYmlsZSAtLT5cbiAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgKm5nSWY9XCIobmF2YmFyLmlzTW9iaWxlJCB8IGFzeW5jKSAmJiBuYXZiYXIuYnJhbmRPcHRpb25zLmxlbmd0aCA+IDBcIlxuICAgICAgPlxuICAgICAgICA8bGkgcm9sZT1cIm5vbmVcIiBjbGFzcz1cIm5hdmJhci1icmFuZFwiIFtjbGFzcy5pcy1vcGVuXT1cImJyYW5kT3B0aW9uc09wZW5cIj5cbiAgICAgICAgICA8YVxuICAgICAgICAgICAgY2xhc3M9XCJkcm9wZG93bi10b2dnbGUgZHJvcHBlZC1hcHBzLXRvZ2dsZVwiXG4gICAgICAgICAgICB0YWJpbmRleD1cIi0xXCJcbiAgICAgICAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1leHBhbmRlZF09XCJicmFuZE9wdGlvbnNPcGVuXCJcbiAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVCcmFuZE9wdGlvbnMoKVwiXG4gICAgICAgICAgICA+e3sgYWN0aXZlQnJhbmRPcHRpb24/LmxhYmVsIH19PHNwYW4gY2xhc3M9XCJjYXJldFwiPjwvc3BhblxuICAgICAgICAgID48L2E+XG4gICAgICAgIDwvbGk+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImJyYW5kT3B0aW9uc09wZW5cIj5cbiAgICAgICAgICA8bGlcbiAgICAgICAgICAgIHJvbGU9XCJub25lXCJcbiAgICAgICAgICAgICpuZ0Zvcj1cImxldCBicmFuZE9wdGlvbiBvZiBuYXZiYXIuYnJhbmRPcHRpb25zXCJcbiAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiYnJhbmRPcHRpb24uYWN0aXZlXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICpuZ0lmPVwiIWJyYW5kT3B0aW9uLmFjdGl2ZVwiXG4gICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImJyYW5kT3B0aW9uLmNvbnRlbnRcIlxuICAgICAgICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gSGlkZGVuIG1lbnUgb3B0aW9ucyB0aGF0IGRpZG4ndCBmaXQgaW4gdGhlIG1haW4gbWVudSBiYXIgLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWJyYW5kT3B0aW9uc09wZW5cIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgaXRlbSBvZiBtZW51SXRlbXM7IGxldCBpID0gaW5kZXhcIj5cbiAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAqbmdJZj1cIihuYXZiYXIuaXNNb2JpbGUkIHwgYXN5bmMpIHx8IGhpZGRlbk1lbnVJdGVtc1tpXVwiXG4gICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJpdGVtLmNvbnRlbnRcIlxuICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgZHJvcGRvd246IGRyb3Bkb3duIH1cIlxuICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L3VsPlxuICA8L2xpPlxuPC91bD5cbiJdfQ==