@dotglitch/ngx-common
Version:
Angular components and utilities that are commonly used.
433 lines • 91.1 kB
JavaScript
import { NgTemplateOutlet } from '@angular/common';
import { Component, HostListener, Inject, Input, Optional, TemplateRef } from '@angular/core';
import { createApplication } from '@angular/platform-browser';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
import { firstValueFrom } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@angular/platform-browser";
import * as i2 from "@angular/material/dialog";
import * as i3 from "@angular/cdk/portal";
import * as i4 from "@angular/material/icon";
import * as i5 from "@angular/material/progress-spinner";
const zone = new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} });
export const calcMenuItemBounds = async (menuItems, dataObj) => {
const data = {
data: dataObj,
items: menuItems,
config: {},
selfCords: { left: "0px", top: "0px" },
ownerCords: { x: 0, y: 0, width: 0, height: 0 },
id: null
};
return calcComponentBounds(MenuComponent, data);
};
const calcComponentBounds = async (component, data) => {
return new Promise((res, rej) => {
zone.run(async () => {
const app = await createApplication({
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data }
]
});
const del = document.createElement("div");
del.classList.add("ngx-menu");
del.style.position = "absolute";
del.style.left = '-1000vw';
document.body.append(del);
const base = app.bootstrap(component, del);
const { instance } = base;
await firstValueFrom(app.isStable);
const el = instance.viewContainer?.element?.nativeElement;
const rect = el.getBoundingClientRect();
app.destroy();
del.remove();
res(rect);
});
});
};
const $data = Symbol("data");
const $hover = Symbol("hover");
export class MenuComponent {
constructor(viewContainer, sanitizer, _data, dialog, // optional only for the purpose of estimating dimensions
dialogRef) {
this.viewContainer = viewContainer;
this.sanitizer = sanitizer;
this._data = _data;
this.dialog = dialog;
this.dialogRef = dialogRef;
this.overlayOverlap = 32;
this.hoverDelay = 400;
this.showDebugOverlay = false;
this.isLockedOpen = false;
this.hasBootstrapped = false;
this.pointerIsOnVoid = false;
this.pointerHasBeenOverMask = false;
this.parentIsNgxMenu = false;
this.coverRectCords = {
top: 0,
left: 0,
height: 0,
width: 0
};
// Check if there are any slashes or dots -- that will clearly exclude it from being a mat icon
this.matIconRx = /[\/\.]/i;
this.showIconColumn = true;
this.showShortcutColumn = true;
this.childDialogs = [];
// Defaults are set before @Input() hooks evaluate
this.dialog = this.dialog || this._data?.dialog;
this.data = this._data?.data;
this.ownerCords = this._data?.ownerCords;
this.selfCords = this._data?.selfCords;
this.items = this._data?.items;
this.config = this._data?.config;
this.id = this._data?.id;
this.parentItem = this._data?.parentItem;
this.parentContext = this._data?.parentContext;
this.isLockedOpen = this.isLockedOpen || this._data?.config?.['_isLockedOpen'];
this.parentIsNgxMenu = this._data?.parentIsNgxMenu;
this.targetBounds = this._data?.targetBounds;
this.template = this._data?.template;
this.templateType = this.template instanceof TemplateRef ? "template" : "component";
if (this.templateType == "component") {
this.componentPortal = new ComponentPortal(this.template);
}
}
ngOnInit() {
this.items?.forEach(i => {
if (typeof i == "string")
return;
// Set defaults
i['_disabled'] = false;
i['_visible'] = true;
i['_context'] = (typeof i.context == "function")
? i.context(this.data)
: i.context;
if (i.label)
try {
i['_formattedLabel'] = this.formatLabel(i.label);
}
catch (e) {
console.warn(e);
}
if (typeof i.isDisabled == "function")
try {
i['_disabled'] = i.isDisabled(this.data || {}, i['_context']);
}
catch (e) {
console.warn(e);
}
if (typeof i.isVisible == "function")
try {
i['_visible'] = i.isVisible(this.data || {}, i['_context']);
}
catch (e) {
console.warn(e);
}
if (typeof i.linkTemplate == "function")
try {
i['_link'] = i.linkTemplate(this.data || {}, i['_context']);
}
catch (e) {
console.warn(e);
}
if (typeof i.iconTemplate == "function")
try {
i['_icon'] = i.iconTemplate(this.data || {}, i['_context']);
}
catch (e) {
console.warn(e);
}
});
// Show the icon column if there are any items with an icon
this.showIconColumn = !!this.items?.find(i => typeof i == "object" &&
typeof i['icon'] == "string" &&
i['icon'].length > 2);
this.showShortcutColumn = !!this.items?.find(i => typeof i == "object" &&
typeof i['shortcut'] == "string" &&
i['shortcut'].length > 2);
if (this.ownerCords) {
const selfY = parseInt(this.selfCords.top?.replace('px', '') || '0');
const selfX = parseInt(this.selfCords.left?.replace('px', '') || '0');
this.coverRectCords = {
top: this.ownerCords.y - selfY - (this.overlayOverlap / 2),
left: this.ownerCords.x - selfX - (this.overlayOverlap / 2),
height: this.ownerCords.height + this.overlayOverlap,
width: this.ownerCords.width + this.overlayOverlap
};
}
if (this.config?.stayOpen)
this.isLockedOpen = true;
setTimeout(() => {
this.hasBootstrapped = true;
}, 200);
}
ngAfterViewInit() {
const el = this.viewContainer.element.nativeElement;
el.addEventListener("keydown", evt => {
this.isLockedOpen = true;
});
el.addEventListener("pointerdown", evt => {
this.isLockedOpen = true;
});
el.addEventListener("touch", evt => {
this.isLockedOpen = true;
});
}
ngOnDestroy() {
//
this.childDialogs.forEach(d => d.close({ [$data]: true }));
}
/**
*
*/
async onMenuItemClick(item, row, keepOpen = false) {
if (typeof item == 'string')
return null;
if (item.separator)
return null;
const context = await item['_context'];
// If cache is enabled, only load if we don't have any children.
const forceLoad = (item.cacheResolvedChildren ? !item.children : true);
if (item.childrenResolver && forceLoad) {
item['_isResolving'] = true;
item['_children'] = await item.childrenResolver(this.data, context);
item['_isResolving'] = false;
}
else if (typeof item.children == "function" && forceLoad) {
item['_isResolving'] = true;
item['_children'] = await item.children(this.data, context);
item['_isResolving'] = false;
}
else {
item['_children'] = item.children;
}
if (item['_children'] || item.childTemplate)
row['_open'] = true;
if (!item.childTemplate && !item.children) {
if (typeof item.action == "function") {
const res = await item.action(this.data, context);
this.close(res === undefined ? true : res);
return res;
}
// If no action, this is simply a text item.
return null;
}
// Need X pos, Y pos, width and height
const bounds = row.getBoundingClientRect();
const cords = {
top: null,
left: null,
bottom: null,
// right: null
};
// Set position coordinates
const targetBounds = await (item.childTemplate
? calcComponentBounds(MenuComponent, { template: item.childTemplate })
: calcMenuItemBounds(item['_children'], this.data));
const { width, height } = targetBounds;
if (bounds.y + height > window.innerHeight)
cords.bottom = "0px";
if (bounds.x + bounds.width + width > window.innerWidth)
cords.left = ((bounds.x - width)) + "px";
if (!cords.bottom)
cords.top = bounds.y + "px";
if (!cords.left)
cords.left = bounds.x + bounds.width + "px";
const config = structuredClone(this.config);
config['_isLockedOpen'] = keepOpen;
// Do not project in the top left corner -- this scenario
// happens when a dialog opens as the parent is killed.
if (cords.left == '0px' && cords.top == '0px')
return;
const dialogRef = this.dialog.open(MenuComponent, {
position: cords,
panelClass: ["ngx-menu"].concat(this.config?.customClass || []),
backdropClass: "ngx-menu-backdrop",
hasBackdrop: false,
data: {
data: this.data,
ownerCords: row.getBoundingClientRect(),
selfCords: cords,
parentItem: item,
parentContext: context,
items: item['_children'],
template: item.childTemplate,
config: config,
parentIsNgxMenu: true,
targetBounds
}
});
let _s = dialogRef
.afterClosed()
.subscribe(async (result) => {
// Clicked "void" on a submenu
if (typeof result == "object" && result[$data] == true) {
this.close(result);
}
// Went back to parent menu -- do not close (same as result == null)
else if (typeof result == "object" && result[$data] == false) {
}
// Got some other result value
else if (result != null) {
// Perform action callback
if (typeof item.action == 'function') {
this.close(await item.action(result, context));
}
// Just close.
else {
this.close();
}
}
row['_open'] = false;
this.childDialogs.splice(this.childDialogs.indexOf(dialogRef), 1);
_s.unsubscribe();
});
this.childDialogs.push(dialogRef);
return dialogRef;
}
/**
*
* @param label
* @returns
*/
formatLabel(label) {
return label.replace(/_([a-z0-9])_/i, (match, group) => `<u>${group}</u>`);
}
/**
* Close the context menu under these circumstances
*/
// @HostListener("window:resize", ['event'])
// @HostListener("window:blur", ['event'])
close(result) {
this.childDialogs.forEach(d => d.close());
this.dialogRef?.close(result);
}
closeOnVoid(force = false) {
if (!this.isLockedOpen || force) {
this.close({ [$data]: force });
}
}
startHoverTimer(item, row) {
// Invert check to make the logic simpler
// TL;DR: if (any) of these are true, we will do the hover action
if (!(Array.isArray(item.children) && item.children.length > 0 ||
typeof item.children == "function" ||
item.childTemplate ||
item.childrenResolver))
return;
item[$hover] = setTimeout(() => {
delete item[$hover];
if (!this.pointerIsOnVoid) {
this.childDialogs.forEach(cd => cd.close());
row['_open'] = true;
this.onMenuItemClick(item, row);
}
}, this.hoverDelay);
}
stopHoverTimer(item) {
item[$hover] && clearTimeout(item[$hover]);
delete item[$hover];
}
startCloseTimer() {
this.closeTimer = setTimeout(() => {
this.closeOnVoid();
}, 500);
}
stopCloseTimer() {
clearTimeout(this.closeTimer);
}
/**
* Check if the dialog is clipping offscreen
* if so, move it back into view.
*/
onResize() {
const el = this.viewContainer?.element?.nativeElement;
if (!el)
return;
const { width, height, x, y } = el.getBoundingClientRect();
const target = document.querySelector(".ngx-menu");
if (!target)
return;
// Move back into view if we're clipping outside of the bottom
if (y + height > window.innerHeight) {
const newTop = (window.innerHeight - (height + (this.config.edgePadding || 12))) + "px";
target.style['margin-top'] = newTop;
}
// Move back into view if we're clipping off the right
if (x + width > window.innerWidth) {
const newLeft = (window.innerWidth - (width + (this.config.edgePadding || 12))) + "px";
target.style['margin-left'] = newLeft;
}
}
// If the void element gets stuck open, make wheel events pass through.
onWheel(evt) {
const el = this.viewContainer.element.nativeElement;
el.style.display = "none";
const target = document.elementFromPoint(evt.clientX, evt.clientY);
el.style.display = "block";
target.scroll({
top: evt.deltaY + target.scrollTop,
left: evt.deltaX + target.scrollLeft,
behavior: "smooth"
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuComponent, deps: [{ token: i0.ViewContainerRef }, { token: i1.DomSanitizer }, { token: MAT_DIALOG_DATA, optional: true }, { token: i2.MatDialog, optional: true }, { token: i2.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: MenuComponent, isStandalone: true, selector: "ngx-menu", inputs: { data: "data", items: "items", config: "config", id: "id", overlayOverlap: "overlayOverlap", hoverDelay: "hoverDelay", showDebugOverlay: "showDebugOverlay", targetBounds: "targetBounds", ownerCords: "ownerCords", selfCords: "selfCords", parentItem: "parentItem", parentContext: "parentContext", isLockedOpen: "isLockedOpen" }, host: { listeners: { "window:resize": "onResize()" }, properties: { "attr.tx": "targetBounds?.x", "attr.ty": "targetBounds?.y", "attr.th": "targetBounds?.height", "attr.tw": "targetBounds?.width" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\n class=\"owner-mask\"\n [style.top]=\"coverRectCords.top + 'px'\"\n [style.left]=\"coverRectCords.left + 'px'\"\n [style.height]=\"coverRectCords.height + 'px'\"\n [style.width]=\"coverRectCords.width + 'px'\"\n [style.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true\"\n (pointerleave)=\"stopCloseTimer()\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table (pointerenter)=\"stopCloseTimer()\">\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n </div>\n }\n @else {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n </div>\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0;overflow:hidden}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%;position:relative;left:-16px;width:calc(100% + 32px);padding:0 16px}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-menu', imports: [
NgTemplateOutlet,
PortalModule,
MatIconModule,
MatProgressSpinnerModule
], standalone: true, host: {
"[attr.tx]": "targetBounds?.x",
"[attr.ty]": "targetBounds?.y",
"[attr.th]": "targetBounds?.height",
"[attr.tw]": "targetBounds?.width",
}, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\n class=\"owner-mask\"\n [style.top]=\"coverRectCords.top + 'px'\"\n [style.left]=\"coverRectCords.left + 'px'\"\n [style.height]=\"coverRectCords.height + 'px'\"\n [style.width]=\"coverRectCords.width + 'px'\"\n [style.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true\"\n (pointerleave)=\"stopCloseTimer()\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table (pointerenter)=\"stopCloseTimer()\">\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n </div>\n }\n @else {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n </div>\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0;overflow:hidden}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%;position:relative;left:-16px;width:calc(100% + 32px);padding:0 16px}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"] }]
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i1.DomSanitizer }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_DIALOG_DATA]
}] }, { type: i2.MatDialog, decorators: [{
type: Optional
}] }, { type: i2.MatDialogRef, decorators: [{
type: Optional
}] }], propDecorators: { data: [{
type: Input
}], items: [{
type: Input
}], config: [{
type: Input
}], id: [{
type: Input
}], overlayOverlap: [{
type: Input
}], hoverDelay: [{
type: Input
}], showDebugOverlay: [{
type: Input
}], targetBounds: [{
type: Input
}], ownerCords: [{
type: Input
}], selfCords: [{
type: Input
}], parentItem: [{
type: Input
}], parentContext: [{
type: Input
}], isLockedOpen: [{
type: Input
}], onResize: [{
type: HostListener,
args: ["window:resize"]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVudS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb21tb24vc3JjL2NvbXBvbmVudHMvbWVudS9tZW51LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbW1vbi9zcmMvY29tcG9uZW50cy9tZW51L21lbnUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUEwQixNQUFNLGVBQWUsQ0FBQztBQUN0SCxPQUFPLEVBQWdCLGlCQUFpQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUUsT0FBTyxFQUEyQixlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFFOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7O0FBSXRDLE1BQU0sSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFFakYsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxFQUFFLFNBQXFCLEVBQUUsT0FBWSxFQUFFLEVBQUU7SUFDNUUsTUFBTSxJQUFJLEdBQUc7UUFDVCxJQUFJLEVBQUUsT0FBTztRQUNiLEtBQUssRUFBRSxTQUFTO1FBQ2hCLE1BQU0sRUFBRSxFQUFFO1FBQ1YsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFO1FBQ3RDLFVBQVUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUU7UUFDL0MsRUFBRSxFQUFFLElBQUk7S0FDWCxDQUFBO0lBRUQsT0FBTyxtQkFBbUIsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDcEQsQ0FBQyxDQUFBO0FBRUQsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLEVBQUUsU0FBb0IsRUFBRSxJQUFTLEVBQUUsRUFBRTtJQUNsRSxPQUFPLElBQUksT0FBTyxDQUFVLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO1FBQ3JDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDaEIsTUFBTSxHQUFHLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQztnQkFDaEMsU0FBUyxFQUFFO29CQUNQLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2lCQUMvQzthQUNKLENBQUMsQ0FBQztZQUVILE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDOUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO1lBQ2hDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQztZQUMzQixRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUUxQixNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUMzQyxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDO1lBRTFCLE1BQU0sY0FBYyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUVuQyxNQUFNLEVBQUUsR0FBZ0IsUUFBUSxDQUFDLGFBQWEsRUFBRSxPQUFPLEVBQUUsYUFBYSxDQUFDO1lBRXZFLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQ3hDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNkLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUViLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNkLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUE7QUFFRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBb0IvQixNQUFNLE9BQU8sYUFBYTtJQXVDdEIsWUFDVyxhQUErQixFQUMvQixTQUF1QixFQUNlLEtBQVUsRUFDcEMsTUFBaUIsRUFBRSx5REFBeUQ7SUFDNUUsU0FBNEI7UUFKeEMsa0JBQWEsR0FBYixhQUFhLENBQWtCO1FBQy9CLGNBQVMsR0FBVCxTQUFTLENBQWM7UUFDZSxVQUFLLEdBQUwsS0FBSyxDQUFLO1FBQ3BDLFdBQU0sR0FBTixNQUFNLENBQVc7UUFDakIsY0FBUyxHQUFULFNBQVMsQ0FBbUI7UUF0Q25DLG1CQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLGVBQVUsR0FBRyxHQUFHLENBQUM7UUFDakIscUJBQWdCLEdBQUcsS0FBSyxDQUFDO1FBT2hDLGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBRXZCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLDJCQUFzQixHQUFHLEtBQUssQ0FBQztRQUN0QyxvQkFBZSxHQUFHLEtBQUssQ0FBQztRQUV4QixtQkFBYyxHQUFHO1lBQ2IsR0FBRyxFQUFFLENBQUM7WUFDTixJQUFJLEVBQUUsQ0FBQztZQUNQLE1BQU0sRUFBRSxDQUFDO1lBQ1QsS0FBSyxFQUFFLENBQUM7U0FDWCxDQUFBO1FBRUQsK0ZBQStGO1FBQy9FLGNBQVMsR0FBRyxTQUFTLENBQUM7UUFDdEMsbUJBQWMsR0FBRyxJQUFJLENBQUM7UUFDdEIsdUJBQWtCLEdBQUcsSUFBSSxDQUFDO1FBS2xCLGlCQUFZLEdBQXdCLEVBQUUsQ0FBQztRQVMzQyxrREFBa0Q7UUFDbEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDO1FBQ2hELElBQUksQ0FBQyxJQUFJLEdBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUM7UUFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQztRQUN6QyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUM7UUFDL0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQztRQUNqQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxVQUFVLENBQUM7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQztRQUMvQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUMvRSxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsZUFBZSxDQUFDO1FBQ25ELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxZQUFZLENBQUM7UUFFN0MsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztRQUVyQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxRQUFRLFlBQVksV0FBVyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztRQUVwRixJQUFJLElBQUksQ0FBQyxZQUFZLElBQUksV0FBVyxFQUFFLENBQUM7WUFDbkMsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBZSxDQUFDLENBQUM7UUFDckUsQ0FBQztJQUNMLENBQUM7SUFFRCxRQUFRO1FBRUosSUFBSSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDcEIsSUFBSSxPQUFPLENBQUMsSUFBSSxRQUFRO2dCQUFFLE9BQU87WUFFakMsZUFBZTtZQUNmLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDdkIsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUNyQixDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLElBQUksVUFBVSxDQUFDO2dCQUNsQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUN0QixDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztZQUUxQixJQUFJLENBQUMsQ0FBQyxLQUFLO2dCQUNQLElBQUksQ0FBQztvQkFBQyxDQUFDLENBQUMsaUJBQWlCLENBQUMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFBQyxDQUFDO2dCQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBRTNGLElBQUksT0FBTyxDQUFDLENBQUMsVUFBVSxJQUFJLFVBQVU7Z0JBQ2pDLElBQUksQ0FBQztvQkFBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDO2dCQUFDLE9BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBRXZHLElBQUksT0FBTyxDQUFDLENBQUMsU0FBUyxJQUFJLFVBQVU7Z0JBQ2hDLElBQUksQ0FBQztvQkFBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDO2dCQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBRXRHLElBQUksT0FBTyxDQUFDLENBQUMsWUFBWSxJQUFJLFVBQVU7Z0JBQ25DLElBQUksQ0FBQztvQkFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDO2dCQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBRXRHLElBQUksT0FBTyxDQUFDLENBQUMsWUFBWSxJQUFJLFVBQVU7Z0JBQ25DLElBQUksQ0FBQztvQkFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDO2dCQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDO1FBQzNHLENBQUMsQ0FBQyxDQUFDO1FBRUgsMkRBQTJEO1FBQzNELElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQ3JDLE9BQU8sQ0FBQyxJQUFJLFFBQVE7WUFDcEIsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksUUFBUTtZQUM1QixDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FDdkIsQ0FBQztRQUVOLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FDekMsT0FBTyxDQUFDLElBQUksUUFBUTtZQUNwQixPQUFPLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxRQUFRO1lBQ2hDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUMzQixDQUFDO1FBRU4sSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDbEIsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7WUFDckUsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7WUFFdEUsSUFBSSxDQUFDLGNBQWMsR0FBRztnQkFDbEIsR0FBRyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLEtBQUssR0FBRyxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUMsQ0FBQyxDQUFDO2dCQUN4RCxJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsR0FBQyxDQUFDLENBQUM7Z0JBQ3pELE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYztnQkFDcEQsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxjQUFjO2FBQ3JELENBQUE7UUFDTCxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVE7WUFDckIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7UUFFN0IsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNaLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO1FBQ2hDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNaLENBQUM7SUFFRCxlQUFlO1FBQ1gsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsYUFBNEIsQ0FBQztRQUNuRSxFQUFFLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxFQUFFO1lBQ2pDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQzdCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsRUFBRSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsRUFBRSxHQUFHLENBQUMsRUFBRTtZQUNyQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztRQUM3QixDQUFDLENBQUMsQ0FBQztRQUNILEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLEVBQUU7WUFDL0IsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7UUFDN0IsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsV0FBVztRQUNQLEVBQUU7UUFDRixJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBQyxDQUFDLEtBQUssQ0FBQyxFQUFFLElBQUksRUFBQyxDQUFDLENBQUMsQ0FBQTtJQUM1RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsZUFBZSxDQUFDLElBQWMsRUFBRSxHQUF3QixFQUFFLFFBQVEsR0FBRyxLQUFLO1FBQzVFLElBQUksT0FBTyxJQUFJLElBQUksUUFBUTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3pDLElBQUksSUFBSSxDQUFDLFNBQVM7WUFBRSxPQUFPLElBQUksQ0FBQztRQUVoQyxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUV2QyxnRUFBZ0U7UUFDaEUsTUFBTSxTQUFTLEdBQUcsQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFdkUsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLElBQUksU0FBUyxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUM1QixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNwRSxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQ2pDLENBQUM7YUFDSSxJQUFJLE9BQU8sSUFBSSxDQUFDLFFBQVEsSUFBSSxVQUFVLElBQUksU0FBUyxFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUM1QixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMs