@dotglitch/ngx-ctx-menu
Version:
Angular context menu that works with templates
135 lines • 22 kB
JavaScript
import { CommonModule } from '@angular/common';
import { Component, HostListener, Inject, Input, TemplateRef } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Optional } from '@angular/core';
import { createApplication } from '@angular/platform-browser';
import { firstValueFrom } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@angular/material/dialog";
import * as i2 from "@angular/common";
export const calcTooltipBounds = async (template, data) => {
const args = {
data: data || {},
template,
config: {},
selfCords: { left: "0px", top: "0px" },
ownerCords: { x: 0, y: 0, width: 0, height: 0 },
id: null
};
// Forcibly bootstrap the ctx menu outside of the client application's zone.
const app = await createApplication({
providers: [
{ provide: MAT_DIALOG_DATA, useValue: args }
]
});
const del = document.createElement("div");
del.style.position = "absolute";
del.style.left = '-1000vw';
document.body.append(del);
const base = app.bootstrap(TooltipComponent, del);
const { instance } = base;
await firstValueFrom(app.isStable);
const el = instance.viewContainer?.element?.nativeElement;
const rect = el.getBoundingClientRect();
app.destroy();
del.remove();
return rect;
};
export class TooltipComponent {
constructor(viewContainer, _data, dialog, // optional only for the purpose of estimating dimensions
dialogRef) {
this.viewContainer = viewContainer;
this._data = _data;
this.dialog = dialog;
this.dialogRef = dialogRef;
this.hasBootstrapped = false;
this.pointerIsOnVoid = false;
this.coverRectCords = {
top: 0,
left: 0,
height: 0,
width: 0
};
// Defaults are set before @Input() hooks evaluate
this.data = this.data || this._data?.data || {};
this.config = this.config || this._data?.config;
this.template = this.template || this._data?.template;
this.ownerCords = this.ownerCords || this._data?.ownerCords;
this.selfCords = this.selfCords || this._data?.selfCords;
}
ngOnInit() {
const selfY = parseInt(this.selfCords.top.replace('px', ''));
const selfX = parseInt(this.selfCords.left.replace('px', ''));
this.coverRectCords = {
top: this.ownerCords.y - selfY - 16,
left: this.ownerCords.x - selfX - 16,
height: this.ownerCords.height + 32,
width: this.ownerCords.width + 32
};
if (this.template instanceof TemplateRef)
this.isTemplate = true;
else if (typeof this.template == "function")
this.isTemplate = false;
else
throw new Error("Unrecognized template object provided.");
// TODO: resolve the event hook with the .void element
setTimeout(() => {
this.hasBootstrapped = true;
if (this.pointerIsOnVoid)
this.dialogRef.close();
}, 10);
}
/**
* Close the tooltip if these actions occur
*/
onClose() {
this.dialogRef?.close();
}
onPointerLeave() {
this.dialogRef?.close();
}
}
/** @nocollapse */ TooltipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: TooltipComponent, deps: [{ token: i0.ViewContainerRef }, { token: MAT_DIALOG_DATA, optional: true }, { token: i1.MatDialog, optional: true }, { token: i1.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TooltipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.0", type: TooltipComponent, isStandalone: true, selector: "ngx-tooltip", inputs: { data: "data", config: "config", ownerCords: "ownerCords", selfCords: "selfCords", template: "template" }, host: { listeners: { "window:resize": "onClose()", "window:blur": "onClose()", "pointerleave": "onPointerLeave()" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n<div\n *ngIf=\"coverRectCords\"\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=\"z-index: -1;\"\n></div>\n\n<div class=\"void\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && dialogRef.close()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && dialogRef.close()\"\n></div>\n\n<div class=\"container\">\n <ng-container\n *ngIf=\"isTemplate == false\"\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n\n <ng-container\n *ngIf=\"isTemplate == true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{ '$implicit': data }\"\n ></ng-container>\n </ng-container>\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type:
// NgIf,
// NgTemplateOutlet,
// NgComponentOutlet,
CommonModule }, { kind: "directive", type: i2.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: TooltipComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-tooltip', imports: [
// NgIf,
// NgTemplateOutlet,
// NgComponentOutlet,
CommonModule,
], standalone: true, template: "<!-- Mouse event blocker for pointer leave -->\n<div\n *ngIf=\"coverRectCords\"\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=\"z-index: -1;\"\n></div>\n\n<div class=\"void\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && dialogRef.close()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && dialogRef.close()\"\n></div>\n\n<div class=\"container\">\n <ng-container\n *ngIf=\"isTemplate == false\"\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n\n <ng-container\n *ngIf=\"isTemplate == true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{ '$implicit': data }\"\n ></ng-container>\n </ng-container>\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"] }]
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_DIALOG_DATA]
}] }, { type: i1.MatDialog, decorators: [{
type: Optional
}] }, { type: i1.MatDialogRef, decorators: [{
type: Optional
}] }]; }, propDecorators: { data: [{
type: Input
}], config: [{
type: Input
}], ownerCords: [{
type: Input
}], selfCords: [{
type: Input
}], template: [{
type: Input
}], onClose: [{
type: HostListener,
args: ["window:resize"]
}, {
type: HostListener,
args: ["window:blur"]
}], onPointerLeave: [{
type: HostListener,
args: ["pointerleave"]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHRpcC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2x0aXAvdG9vbHRpcC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2x0aXAvdG9vbHRpcC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQTBCLE1BQU0sZUFBZSxDQUFDO0FBQzVHLE9BQU8sRUFBMkIsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFcEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7O0FBRXRDLE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLEtBQUssRUFBRSxRQUFzQyxFQUFFLElBQUksRUFBRSxFQUFFO0lBQ3BGLE1BQU0sSUFBSSxHQUFHO1FBQ1QsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFO1FBQ2hCLFFBQVE7UUFDUixNQUFNLEVBQUUsRUFBRTtRQUNWLFNBQVMsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRTtRQUN0QyxVQUFVLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFO1FBQy9DLEVBQUUsRUFBRSxJQUFJO0tBQ1gsQ0FBQTtJQUNELDRFQUE0RTtJQUM1RSxNQUFNLEdBQUcsR0FBRyxNQUFNLGlCQUFpQixDQUFDO1FBQ2hDLFNBQVMs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O2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQTJERSxPQUFPO3NCQUZkLFlBQVk7dUJBQUMsZUFBZTs7c0JBQzVCLFlBQVk7dUJBQUMsYUFBYTtnQkFNbkIsY0FBYztzQkFEckIsWUFBWTt1QkFBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbXBvbmVudCwgSG9zdExpc3RlbmVyLCBJbmplY3QsIElucHV0LCBUZW1wbGF0ZVJlZiwgVHlwZSwgVmlld0NvbnRhaW5lclJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0RGlhbG9nLCBNYXREaWFsb2dSZWYsIE1BVF9ESUFMT0dfREFUQSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XG5pbXBvcnQgeyBOZ3hUb29sdGlwT3B0aW9ucyB9IGZyb20gJy4uL3Rvb2x0aXAuZGlyZWN0aXZlJztcbmltcG9ydCB7IE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBjcmVhdGVBcHBsaWNhdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcblxuZXhwb3J0IGNvbnN0IGNhbGNUb29sdGlwQm91bmRzID0gYXN5bmMgKHRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+IHwgVHlwZTxhbnk+LCBkYXRhKSA9PiB7XG4gICAgY29uc3QgYXJncyA9IHtcbiAgICAgICAgZGF0YTogZGF0YSB8fCB7fSxcbiAgICAgICAgdGVtcGxhdGUsXG4gICAgICAgIGNvbmZpZzoge30sXG4gICAgICAgIHNlbGZDb3JkczogeyBsZWZ0OiBcIjBweFwiLCB0b3A6IFwiMHB4XCIgfSxcbiAgICAgICAgb3duZXJDb3JkczogeyB4OiAwLCB5OiAwLCB3aWR0aDogMCwgaGVpZ2h0OiAwIH0sXG4gICAgICAgIGlkOiBudWxsXG4gICAgfVxuICAgIC8vIEZvcmNpYmx5IGJvb3RzdHJhcCB0aGUgY3R4IG1lbnUgb3V0c2lkZSBvZiB0aGUgY2xpZW50IGFwcGxpY2F0aW9uJ3Mgem9uZS5cbiAgICBjb25zdCBhcHAgPSBhd2FpdCBjcmVhdGVBcHBsaWNhdGlvbih7XG4gICAgICAgIHByb3ZpZGVyczogW1xuICAgICAgICAgICAgeyBwcm92aWRlOiBNQVRfRElBTE9HX0RBVEEsIHVzZVZhbHVlOiBhcmdzIH1cbiAgICAgICAgXVxuICAgIH0pO1xuXG4gICAgY29uc3QgZGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICBkZWwuc3R5bGUucG9zaXRpb24gPSBcImFic29sdXRlXCI7XG4gICAgZGVsLnN0eWxlLmxlZnQgPSAnLTEwMDB2dyc7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmQoZGVsKTtcblxuICAgIGNvbnN0IGJhc2UgPSBhcHAuYm9vdHN0cmFwKFRvb2x0aXBDb21wb25lbnQsIGRlbCk7XG4gICAgY29uc3QgeyBpbnN0YW5jZSB9ID0gYmFzZTtcblxuICAgIGF3YWl0IGZpcnN0VmFsdWVGcm9tKGFwcC5pc1N0YWJsZSk7XG5cbiAgICBjb25zdCBlbDogSFRNTEVsZW1lbnQgPSBpbnN0YW5jZS52aWV3Q29udGFpbmVyPy5lbGVtZW50Py5uYXRpdmVFbGVtZW50O1xuXG4gICAgY29uc3QgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGFwcC5kZXN0cm95KCk7XG4gICAgZGVsLnJlbW92ZSgpO1xuXG4gICAgcmV0dXJuIHJlY3Q7XG59XG5cblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICduZ3gtdG9vbHRpcCcsXG4gICAgdGVtcGxhdGVVcmw6ICcuL3Rvb2x0aXAuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3Rvb2x0aXAuY29tcG9uZW50LnNjc3MnXSxcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIC8vIE5nSWYsXG4gICAgICAgIC8vIE5nVGVtcGxhdGVPdXRsZXQsXG4gICAgICAgIC8vIE5nQ29tcG9uZW50T3V0bGV0LFxuICAgICAgICBDb21tb25Nb2R1bGUsXG4gICAgXSxcbiAgICBzdGFuZGFsb25lOiB0cnVlXG59KVxuZXhwb3J0IGNsYXNzIFRvb2x0aXBDb21wb25lbnQge1xuICAgIEBJbnB1dCgpIGRhdGE6IGFueTtcbiAgICBASW5wdXQoKSBjb25maWc6IE5neFRvb2x0aXBPcHRpb25zO1xuICAgIEBJbnB1dCgpIG93bmVyQ29yZHM6IERPTVJlY3Q7XG4gICAgQElucHV0KCkgc2VsZkNvcmRzO1xuICAgIEBJbnB1dCgpIHRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+IHwgVHlwZTxhbnk+O1xuXG4gICAgaXNUZW1wbGF0ZTogYm9vbGVhbjtcbiAgICBoYXNCb290c3RyYXBwZWQgPSBmYWxzZTtcbiAgICBwb2ludGVySXNPblZvaWQgPSBmYWxzZTtcblxuICAgIGNvdmVyUmVjdENvcmRzID0ge1xuICAgICAgICB0b3A6IDAsXG4gICAgICAgIGxlZnQ6IDAsXG4gICAgICAgIGhlaWdodDogMCxcbiAgICAgICAgd2lkdGg6IDBcbiAgICB9XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIHZpZXdDb250YWluZXI6IFZpZXdDb250YWluZXJSZWYsXG4gICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoTUFUX0RJQUxPR19EQVRBKSBwcml2YXRlIF9kYXRhOiBhbnksXG4gICAgICAgIEBPcHRpb25hbCgpIHB1YmxpYyBkaWFsb2c6IE1hdERpYWxvZywgLy8gb3B0aW9uYWwgb25seSBmb3IgdGhlIHB1cnBvc2Ugb2YgZXN0aW1hdGluZyBkaW1lbnNpb25zXG4gICAgICAgIEBPcHRpb25hbCgpIHB1YmxpYyBkaWFsb2dSZWY6IE1hdERpYWxvZ1JlZjxhbnk+LFxuICAgICkge1xuICAgICAgICAvLyBEZWZhdWx0cyBhcmUgc2V0IGJlZm9yZSBASW5wdXQoKSBob29rcyBldmFsdWF0ZVxuICAgICAgICB0aGlzLmRhdGEgPSB0aGlzLmRhdGEgfHwgdGhpcy5fZGF0YT8uZGF0YSB8fCB7fTtcbiAgICAgICAgdGhpcy5jb25maWcgPSB0aGlzLmNvbmZpZyB8fCB0aGlzLl9kYXRhPy5jb25maWc7XG4gICAgICAgIHRoaXMudGVtcGxhdGUgPSB0aGlzLnRlbXBsYXRlIHx8IHRoaXMuX2RhdGE/LnRlbXBsYXRlO1xuICAgICAgICB0aGlzLm93bmVyQ29yZHMgPSB0aGlzLm93bmVyQ29yZHMgfHwgdGhpcy5fZGF0YT8ub3duZXJDb3JkcztcbiAgICAgICAgdGhpcy5zZWxmQ29yZHMgPSB0aGlzLnNlbGZDb3JkcyB8fCB0aGlzLl9kYXRhPy5zZWxmQ29yZHM7XG4gICAgfVxuXG4gICAgbmdPbkluaXQoKSB7XG5cbiAgICAgICAgY29uc3Qgc2VsZlkgPSBwYXJzZUludCh0aGlzLnNlbGZDb3Jkcy50b3AucmVwbGFjZSgncHgnLCAnJykpO1xuICAgICAgICBjb25zdCBzZWxmWCA9IHBhcnNlSW50KHRoaXMuc2VsZkNvcmRzLmxlZnQucmVwbGFjZSgncHgnLCAnJykpO1xuXG4gICAgICAgIHRoaXMuY292ZXJSZWN0Q29yZHMgPSB7XG4gICAgICAgICAgICB0b3A6IHRoaXMub3duZXJDb3Jkcy55IC0gc2VsZlkgLSAxNixcbiAgICAgICAgICAgIGxlZnQ6IHRoaXMub3duZXJDb3Jkcy54IC0gc2VsZlggLSAxNixcbiAgICAgICAgICAgIGhlaWdodDogdGhpcy5vd25lckNvcmRzLmhlaWdodCArIDMyLFxuICAgICAgICAgICAgd2lkdGg6IHRoaXMub3duZXJDb3Jkcy53aWR0aCArIDMyXG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy50ZW1wbGF0ZSBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmKVxuICAgICAgICAgICAgdGhpcy5pc1RlbXBsYXRlID0gdHJ1ZTtcbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIHRoaXMudGVtcGxhdGUgPT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgdGhpcy5pc1RlbXBsYXRlID0gZmFsc2U7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVucmVjb2duaXplZCB0ZW1wbGF0ZSBvYmplY3QgcHJvdmlkZWQuXCIpO1xuXG4gICAgICAgIC8vIFRPRE86IHJlc29sdmUgdGhlIGV2ZW50IGhvb2sgd2l0aCB0aGUgLnZvaWQgZWxlbWVudFxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuaGFzQm9vdHN0cmFwcGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmICh0aGlzLnBvaW50ZXJJc09uVm9pZClcbiAgICAgICAgICAgICAgICB0aGlzLmRpYWxvZ1JlZi5jbG9zZSgpO1xuICAgICAgICB9LCAxMCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xvc2UgdGhlIHRvb2x0aXAgaWYgdGhlc2UgYWN0aW9ucyBvY2N1clxuICAgICAqL1xuICAgIEBIb3N0TGlzdGVuZXIoXCJ3aW5kb3c6cmVzaXplXCIpXG4gICAgQEhvc3RMaXN0ZW5lcihcIndpbmRvdzpibHVyXCIpXG4gICAgcHJpdmF0ZSBvbkNsb3NlKCkge1xuICAgICAgICB0aGlzLmRpYWxvZ1JlZj8uY2xvc2UoKTtcbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKFwicG9pbnRlcmxlYXZlXCIpXG4gICAgcHJpdmF0ZSBvblBvaW50ZXJMZWF2ZSgpIHtcblxuICAgICAgICB0aGlzLmRpYWxvZ1JlZj8uY2xvc2UoKTtcbiAgICB9XG59XG4iLCI8IS0tIE1vdXNlIGV2ZW50IGJsb2NrZXIgZm9yIHBvaW50ZXIgbGVhdmUgLS0+XG48ZGl2XG4gICAgKm5nSWY9XCJjb3ZlclJlY3RDb3Jkc1wiXG4gICAgY2xhc3M9XCJvd25lci1tYXNrXCJcbiAgICBbc3R5bGUudG9wXT1cImNvdmVyUmVjdENvcmRzLnRvcCArICdweCdcIlxuICAgIFtzdHlsZS5sZWZ0XT1cImNvdmVyUmVjdENvcmRzLmxlZnQgKyAncHgnXCJcbiAgICBbc3R5bGUuaGVpZ2h0XT1cImNvdmVyUmVjdENvcmRzLmhlaWdodCArICdweCdcIlxuICAgIFtzdHlsZS53aWR0aF09XCJjb3ZlclJlY3RDb3Jkcy53aWR0aCArICdweCdcIlxuICAgIHN0eWxlPVwiei1pbmRleDogLTE7XCJcbj48L2Rpdj5cblxuPGRpdiBjbGFzcz1cInZvaWRcIlxuICAgIChwb2ludGVyZW50ZXIpPVwicG9pbnRlcklzT25Wb2lkID0gdHJ1ZTsgaGFzQm9vdHN0cmFwcGVkICYmIGRpYWxvZ1JlZi5jbG9zZSgpXCJcbiAgICAocG9pbnRlcmxlYXZlKT1cInBvaW50ZXJJc09uVm9pZCA9IGZhbHNlXCJcbiAgICAocG9pbnRlcmRvd24pPVwiaGFzQm9vdHN0cmFwcGVkICYmIGRpYWxvZ1JlZi5jbG9zZSgpXCJcbj48L2Rpdj5cblxuPGRpdiBjbGFzcz1cImNvbnRhaW5lclwiPlxuICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgKm5nSWY9XCJpc1RlbXBsYXRlID09IGZhbHNlXCJcbiAgICAgICAgW25nQ29tcG9uZW50T3V0bGV0XT1cIiRhbnkodGVtcGxhdGUpXCJcbiAgICA+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctY29udGFpbmVyXG4gICAgICAgICpuZ0lmPVwiaXNUZW1wbGF0ZSA9PSB0cnVlXCJcbiAgICA+XG4gICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIiRhbnkodGVtcGxhdGUpXCJcbiAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7ICckaW1wbGljaXQnOiBkYXRhIH1cIlxuICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG48L2Rpdj5cbiJdfQ==