UNPKG

ng-hub-ui-portal

Version:

A flexible Angular portal library for dynamic content rendering with advanced positioning and interaction control

208 lines 21.4 kB
import { DOCUMENT, NgIf } from '@angular/common'; import { Component, ElementRef, EventEmitter, inject, Input, NgZone, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { getFocusableBoundaryElements, hubRunTransition, reflow } from 'ng-hub-ui-utils'; import { Subject, zip } from 'rxjs'; import { take } from 'rxjs/operators'; import * as i0 from "@angular/core"; export class HubPortalWindow { constructor() { this._document = inject(DOCUMENT); this._elRef = inject((ElementRef)); this._zone = inject(NgZone); this._closed$ = new Subject(); this._elWithFocus = null; // element that is focused prior to portal opening this.dismissEvent = new EventEmitter(); this.shown = new Subject(); this.hidden = new Subject(); } dismiss(reason) { this.dismissEvent.emit(reason); } ngOnInit() { this._elWithFocus = this._document.activeElement; this._zone.onStable .asObservable() .pipe(take(1)) .subscribe(() => { this._show(); }); } ngOnDestroy() { this._disableEventHandling(); } hide() { const { nativeElement } = this._elRef; const context = { animation: this.animation, runningTransition: 'stop' }; const windowTransition$ = hubRunTransition(this._zone, nativeElement, () => nativeElement.classList.remove('show'), context); const dialogTransition$ = hubRunTransition(this._zone, this._dialogEl.nativeElement, () => { }, context); const transitions$ = zip(windowTransition$, dialogTransition$); transitions$.subscribe(() => { this.hidden.next(); this.hidden.complete(); }); this._disableEventHandling(); this._restoreFocus(); return transitions$; } _show() { const context = { animation: this.animation, runningTransition: 'continue' }; const windowTransition$ = hubRunTransition(this._zone, this._elRef.nativeElement, (element, animation) => { if (animation) { reflow(element); } element.classList.add('show'); }, context); const dialogTransition$ = hubRunTransition(this._zone, this._dialogEl.nativeElement, () => { }, context); zip(windowTransition$, dialogTransition$).subscribe(() => { this.shown.next(); this.shown.complete(); }); this._setFocus(); } _disableEventHandling() { this._closed$.next(); } _setFocus() { const { nativeElement } = this._elRef; if (!nativeElement.contains(document.activeElement)) { const autoFocusable = nativeElement.querySelector(`[hubAutofocus]`); const firstFocusable = getFocusableBoundaryElements(nativeElement)[0]; const elementToFocus = autoFocusable || firstFocusable || nativeElement; elementToFocus.focus(); } } _restoreFocus() { const body = this._document.body; const elWithFocus = this._elWithFocus; let elementToFocus; if (elWithFocus && elWithFocus['focus'] && body.contains(elWithFocus)) { elementToFocus = elWithFocus; } else { elementToFocus = body; } this._zone.runOutsideAngular(() => { setTimeout(() => elementToFocus.focus()); this._elWithFocus = null; }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: HubPortalWindow, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.5", type: HubPortalWindow, isStandalone: true, selector: "hub-portal-window", inputs: { animation: "animation", ariaLabelledBy: "ariaLabelledBy", ariaDescribedBy: "ariaDescribedBy", scrollable: "scrollable", windowClass: "windowClass", portalDialogClass: "portalDialogClass", portalContentClass: "portalContentClass" }, outputs: { dismissEvent: "dismiss" }, host: { attributes: { "role": "dialog", "tabindex": "-1" }, properties: { "class": "\"portal d-block\" + (windowClass ? \" \" + windowClass : \"\")", "class.fade": "animation", "attr.aria-portal": "true", "attr.aria-labelledby": "ariaLabelledBy", "attr.aria-describedby": "ariaDescribedBy" } }, viewQueries: [{ propertyName: "_dialogEl", first: true, predicate: ["dialog"], descendants: true, static: true }], ngImport: i0, template: ` <div #dialog [class]=" 'portal-dialog' + (scrollable ? ' portal-dialog-scrollable' : '') + (portalDialogClass ? ' ' + portalDialogClass : '') " role="document" > <div [class]=" 'portal-content' + (portalContentClass ? ' ' + portalContentClass : '') " > <ng-container *ngIf="singleContent; else multipleContent"> <ng-content></ng-content> </ng-container> <ng-template #multipleContent> <div class="portal-header"> <ng-content /> <button type="button" class="btn-close" data-bs-dismiss="portal" aria-label="Close" (click)="dismiss(null)" ></button> </div> <div class="portal-body"> <ng-content /> </div> <div class="portal-footer"> <ng-content /> </div> </ng-template> </div> </div> `, isInline: true, styles: ["hub-portal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: HubPortalWindow, decorators: [{ type: Component, args: [{ selector: 'hub-portal-window', standalone: true, imports: [NgIf], host: { '[class]': '"portal d-block" + (windowClass ? " " + windowClass : "")', '[class.fade]': 'animation', role: 'dialog', tabindex: '-1', '[attr.aria-portal]': 'true', '[attr.aria-labelledby]': 'ariaLabelledBy', '[attr.aria-describedby]': 'ariaDescribedBy' }, template: ` <div #dialog [class]=" 'portal-dialog' + (scrollable ? ' portal-dialog-scrollable' : '') + (portalDialogClass ? ' ' + portalDialogClass : '') " role="document" > <div [class]=" 'portal-content' + (portalContentClass ? ' ' + portalContentClass : '') " > <ng-container *ngIf="singleContent; else multipleContent"> <ng-content></ng-content> </ng-container> <ng-template #multipleContent> <div class="portal-header"> <ng-content /> <button type="button" class="btn-close" data-bs-dismiss="portal" aria-label="Close" (click)="dismiss(null)" ></button> </div> <div class="portal-body"> <ng-content /> </div> <div class="portal-footer"> <ng-content /> </div> </ng-template> </div> </div> `, encapsulation: ViewEncapsulation.None, styles: ["hub-portal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"] }] }], propDecorators: { _dialogEl: [{ type: ViewChild, args: ['dialog', { static: true }] }], animation: [{ type: Input }], ariaLabelledBy: [{ type: Input }], ariaDescribedBy: [{ type: Input }], scrollable: [{ type: Input }], windowClass: [{ type: Input }], portalDialogClass: [{ type: Input }], portalContentClass: [{ type: Input }], dismissEvent: [{ type: Output, args: ['dismiss'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9ydGFsLXdpbmRvdy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3BvcnRhbC9zcmMvbGliL3BvcnRhbC13aW5kb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNqRCxPQUFPLEVBQ04sU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFDTCxNQUFNLEVBR04sTUFBTSxFQUNOLFNBQVMsRUFDVCxpQkFBaUIsRUFDakIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNOLDRCQUE0QixFQUM1QixnQkFBZ0IsRUFDaEIsTUFBTSxFQUVOLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFjLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDaEQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDOztBQTBEdEMsTUFBTSxPQUFPLGVBQWU7SUF4RDVCO1FBeURTLGNBQVMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDN0IsV0FBTSxHQUFHLE1BQU0sQ0FBQyxDQUFBLFVBQXVCLENBQUEsQ0FBQyxDQUFDO1FBQ3pDLFVBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFdkIsYUFBUSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFDL0IsaUJBQVksR0FBbUIsSUFBSSxDQUFDLENBQUMsa0RBQWtEO1FBZTVFLGlCQUFZLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUVyRCxVQUFLLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUM1QixXQUFNLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztLQXNIN0I7SUFwSEEsT0FBTyxDQUFDLE1BQU07UUFDYixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFN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QUNQLENBQUMsSUFBSSxDQUFDLFFBQ1Q7d0JBQ0wsU0FBUyxFQUFFLDJEQUEyRDt3QkFDdEUsY0FBYyxFQUFFLFdBQVc7d0JBQzNCLElBQUksRUFBRSxRQUFRO3dCQUNkLFFBQVEsRUFBRSxJQUFJO3dCQUNkLG9CQUFvQixFQUFFLE1BQU07d0JBQzVCLHdCQUF3QixFQUFFLGdCQUFnQjt3QkFDMUMseUJBQXlCLEVBQUUsaUJBQWlCO3FCQUM1QyxZQUNTOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUF1Q1QsaUJBQ2MsaUJBQWlCLENBQUMsSUFBSTs4QkFZN0IsU0FBUztzQkFEaEIsU0FBUzt1QkFBQyxRQUFRLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUc1QixTQUFTO3NCQUFqQixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUNHLGtCQUFrQjtzQkFBMUIsS0FBSztnQkFJYSxZQUFZO3NCQUE5QixNQUFNO3VCQUFDLFNBQVMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCwgTmdJZiB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuXHRDb21wb25lbnQsXG5cdEVsZW1lbnRSZWYsXG5cdEV2ZW50RW1pdHRlcixcblx0aW5qZWN0LFxuXHRJbnB1dCxcblx0Tmdab25lLFxuXHRPbkRlc3Ryb3ksXG5cdE9uSW5pdCxcblx0T3V0cHV0LFxuXHRWaWV3Q2hpbGQsXG5cdFZpZXdFbmNhcHN1bGF0aW9uXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcblx0Z2V0Rm9jdXNhYmxlQm91bmRhcnlFbGVtZW50cyxcblx0aHViUnVuVHJhbnNpdGlvbixcblx0cmVmbG93LFxuXHRUcmFuc2l0aW9uT3B0aW9uc1xufSBmcm9tICduZy1odWItdWktdXRpbHMnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCwgemlwIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6ICdodWItcG9ydGFsLXdpbmRvdycsXG5cdHN0YW5kYWxvbmU6IHRydWUsXG5cdGltcG9ydHM6IFtOZ0lmXSxcblx0aG9zdDoge1xuXHRcdCdbY2xhc3NdJzogJ1wicG9ydGFsIGQtYmxvY2tcIiArICh3aW5kb3dDbGFzcyA/IFwiIFwiICsgd2luZG93Q2xhc3MgOiBcIlwiKScsXG5cdFx0J1tjbGFzcy5mYWRlXSc6ICdhbmltYXRpb24nLFxuXHRcdHJvbGU6ICdkaWFsb2cnLFxuXHRcdHRhYmluZGV4OiAnLTEnLFxuXHRcdCdbYXR0ci5hcmlhLXBvcnRhbF0nOiAndHJ1ZScsXG5cdFx0J1thdHRyLmFyaWEtbGFiZWxsZWRieV0nOiAnYXJpYUxhYmVsbGVkQnknLFxuXHRcdCdbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XSc6ICdhcmlhRGVzY3JpYmVkQnknXG5cdH0sXG5cdHRlbXBsYXRlOiBgXG5cdFx0PGRpdlxuXHRcdFx0I2RpYWxvZ1xuXHRcdFx0W2NsYXNzXT1cIlxuXHRcdFx0XHQncG9ydGFsLWRpYWxvZycgK1xuXHRcdFx0XHQoc2Nyb2xsYWJsZSA/ICcgcG9ydGFsLWRpYWxvZy1zY3JvbGxhYmxlJyA6ICcnKSArXG5cdFx0XHRcdChwb3J0YWxEaWFsb2dDbGFzcyA/ICcgJyArIHBvcnRhbERpYWxvZ0NsYXNzIDogJycpXG5cdFx0XHRcIlxuXHRcdFx0cm9sZT1cImRvY3VtZW50XCJcblx0XHQ+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdFtjbGFzc109XCJcblx0XHRcdFx0XHQncG9ydGFsLWNvbnRlbnQnICtcblx0XHRcdFx0XHQocG9ydGFsQ29udGVudENsYXNzID8gJyAnICsgcG9ydGFsQ29udGVudENsYXNzIDogJycpXG5cdFx0XHRcdFwiXG5cdFx0XHQ+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJzaW5nbGVDb250ZW50OyBlbHNlIG11bHRpcGxlQ29udGVudFwiPlxuXHRcdFx0XHRcdDxuZy1jb250ZW50PjwvbmctY29udGVudD5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy10ZW1wbGF0ZSAjbXVsdGlwbGVDb250ZW50PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJwb3J0YWwtaGVhZGVyXCI+XG5cdFx0XHRcdFx0XHQ8bmctY29udGVudCAvPlxuXHRcdFx0XHRcdFx0PGJ1dHRvblxuXHRcdFx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0XHRcdFx0Y2xhc3M9XCJidG4tY2xvc2VcIlxuXHRcdFx0XHRcdFx0XHRkYXRhLWJzLWRpc21pc3M9XCJwb3J0YWxcIlxuXHRcdFx0XHRcdFx0XHRhcmlhLWxhYmVsPVwiQ2xvc2VcIlxuXHRcdFx0XHRcdFx0XHQoY2xpY2spPVwiZGlzbWlzcyhudWxsKVwiXG5cdFx0XHRcdFx0XHQ+PC9idXR0b24+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cInBvcnRhbC1ib2R5XCI+XG5cdFx0XHRcdFx0XHQ8bmctY29udGVudCAvPlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJwb3J0YWwtZm9vdGVyXCI+XG5cdFx0XHRcdFx0XHQ8bmctY29udGVudCAvPlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdFx0PC9kaXY+XG5cdFx0PC9kaXY+XG5cdGAsXG5cdGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG5cdHN0eWxlVXJsOiAnLi9wb3J0YWwuc2Nzcydcbn0pXG5leHBvcnQgY2xhc3MgSHViUG9ydGFsV2luZG93IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXHRwcml2YXRlIF9kb2N1bWVudCA9IGluamVjdChET0NVTUVOVCk7XG5cdHByaXZhdGUgX2VsUmVmID0gaW5qZWN0KEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+KTtcblx0cHJpdmF0ZSBfem9uZSA9IGluamVjdChOZ1pvbmUpO1xuXG5cdHByaXZhdGUgX2Nsb3NlZCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXHRwcml2YXRlIF9lbFdpdGhGb2N1czogRWxlbWVudCB8IG51bGwgPSBudWxsOyAvLyBlbGVtZW50IHRoYXQgaXMgZm9jdXNlZCBwcmlvciB0byBwb3J0YWwgb3BlbmluZ1xuXG5cdEBWaWV3Q2hpbGQoJ2RpYWxvZycsIHsgc3RhdGljOiB0cnVlIH0pXG5cdHByaXZhdGUgX2RpYWxvZ0VsOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcblxuXHRASW5wdXQoKSBhbmltYXRpb246IGJvb2xlYW47XG5cdEBJbnB1dCgpIGFyaWFMYWJlbGxlZEJ5OiBzdHJpbmc7XG5cdEBJbnB1dCgpIGFyaWFEZXNjcmliZWRCeTogc3RyaW5nO1xuXHRASW5wdXQoKSBzY3JvbGxhYmxlOiBzdHJpbmc7XG5cdEBJbnB1dCgpIHdpbmRvd0NsYXNzOiBzdHJpbmc7XG5cdEBJbnB1dCgpIHBvcnRhbERpYWxvZ0NsYXNzOiBzdHJpbmc7XG5cdEBJbnB1dCgpIHBvcnRhbENvbnRlbnRDbGFzczogc3RyaW5nO1xuXG5cdHNpbmdsZUNvbnRlbnQhOiBib29sZWFuO1xuXG5cdEBPdXRwdXQoJ2Rpc21pc3MnKSBkaXNtaXNzRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cblx0c2hvd24gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXHRoaWRkZW4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG5cdGRpc21pc3MocmVhc29uKTogdm9pZCB7XG5cdFx0dGhpcy5kaXNtaXNzRXZlbnQuZW1pdChyZWFzb24pO1xuXHR9XG5cblx0bmdPbkluaXQoKSB7XG5cdFx0dGhpcy5fZWxXaXRoRm9jdXMgPSB0aGlzLl9kb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXHRcdHRoaXMuX3pvbmUub25TdGFibGVcblx0XHRcdC5hc09ic2VydmFibGUoKVxuXHRcdFx0LnBpcGUodGFrZSgxKSlcblx0XHRcdC5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0XHR0aGlzLl9zaG93KCk7XG5cdFx0XHR9KTtcblx0fVxuXG5cdG5nT25EZXN0cm95KCkge1xuXHRcdHRoaXMuX2Rpc2FibGVFdmVudEhhbmRsaW5nKCk7XG5cdH1cblxuXHRoaWRlKCk6IE9ic2VydmFibGU8YW55PiB7XG5cdFx0Y29uc3QgeyBuYXRpdmVFbGVtZW50IH0gPSB0aGlzLl9lbFJlZjtcblx0XHRjb25zdCBjb250ZXh0OiBUcmFuc2l0aW9uT3B0aW9uczxhbnk+ID0ge1xuXHRcdFx0YW5pbWF0aW9uOiB0aGlzLmFuaW1hdGlvbixcblx0XHRcdHJ1bm5pbmdUcmFuc2l0aW9uOiAnc3RvcCdcblx0XHR9O1xuXG5cdFx0Y29uc3Qgd2luZG93VHJhbnNpdGlvbiQgPSBodWJSdW5UcmFuc2l0aW9uKFxuXHRcdFx0dGhpcy5fem9uZSxcblx0XHRcdG5hdGl2ZUVsZW1lbnQsXG5cdFx0XHQoKSA9PiBuYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoJ3Nob3cnKSxcblx0XHRcdGNvbnRleHRcblx0XHQpO1xuXHRcdGNvbnN0IGRpYWxvZ1RyYW5zaXRpb24kID0gaHViUnVuVHJhbnNpdGlvbihcblx0XHRcdHRoaXMuX3pvbmUsXG5cdFx0XHR0aGlzLl9kaWFsb2dFbC5uYXRpdmVFbGVtZW50LFxuXHRcdFx0KCkgPT4ge30sXG5cdFx0XHRjb250ZXh0XG5cdFx0KTtcblxuXHRcdGNvbnN0IHRyYW5zaXRpb25zJCA9IHppcCh3aW5kb3dUcmFuc2l0aW9uJCwgZGlhbG9nVHJhbnNpdGlvbiQpO1xuXHRcdHRyYW5zaXRpb25zJC5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0dGhpcy5oaWRkZW4ubmV4dCgpO1xuXHRcdFx0dGhpcy5oaWRkZW4uY29tcGxldGUoKTtcblx0XHR9KTtcblxuXHRcdHRoaXMuX2Rpc2FibGVFdmVudEhhbmRsaW5nKCk7XG5cdFx0dGhpcy5fcmVzdG9yZUZvY3VzKCk7XG5cblx0XHRyZXR1cm4gdHJhbnNpdGlvbnMkO1xuXHR9XG5cblx0cHJpdmF0ZSBfc2hvdygpIHtcblx0XHRjb25zdCBjb250ZXh0OiBUcmFuc2l0aW9uT3B0aW9uczxhbnk+ID0ge1xuXHRcdFx0YW5pbWF0aW9uOiB0aGlzLmFuaW1hdGlvbixcblx0XHRcdHJ1bm5pbmdUcmFuc2l0aW9uOiAnY29udGludWUnXG5cdFx0fTtcblxuXHRcdGNvbnN0IHdpbmRvd1RyYW5zaXRpb24kID0gaHViUnVuVHJhbnNpdGlvbihcblx0XHRcdHRoaXMuX3pvbmUsXG5cdFx0XHR0aGlzLl9lbFJlZi5uYXRpdmVFbGVtZW50LFxuXHRcdFx0KGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBhbmltYXRpb246IGJvb2xlYW4pID0+IHtcblx0XHRcdFx0aWYgKGFuaW1hdGlvbikge1xuXHRcdFx0XHRcdHJlZmxvdyhlbGVtZW50KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3Nob3cnKTtcblx0XHRcdH0sXG5cdFx0XHRjb250ZXh0XG5cdFx0KTtcblx0XHRjb25zdCBkaWFsb2dUcmFuc2l0aW9uJCA9IGh1YlJ1blRyYW5zaXRpb24oXG5cdFx0XHR0aGlzLl96b25lLFxuXHRcdFx0dGhpcy5fZGlhbG9nRWwubmF0aXZlRWxlbWVudCxcblx0XHRcdCgpID0+IHt9LFxuXHRcdFx0Y29udGV4dFxuXHRcdCk7XG5cblx0XHR6aXAod2luZG93VHJhbnNpdGlvbiQsIGRpYWxvZ1RyYW5zaXRpb24kKS5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0dGhpcy5zaG93bi5uZXh0KCk7XG5cdFx0XHR0aGlzLnNob3duLmNvbXBsZXRlKCk7XG5cdFx0fSk7XG5cblx0XHR0aGlzLl9zZXRGb2N1cygpO1xuXHR9XG5cblx0cHJpdmF0ZSBfZGlzYWJsZUV2ZW50SGFuZGxpbmcoKSB7XG5cdFx0dGhpcy5fY2xvc2VkJC5uZXh0KCk7XG5cdH1cblxuXHRwcml2YXRlIF9zZXRGb2N1cygpIHtcblx0XHRjb25zdCB7IG5hdGl2ZUVsZW1lbnQgfSA9IHRoaXMuX2VsUmVmO1xuXHRcdGlmICghbmF0aXZlRWxlbWVudC5jb250YWlucyhkb2N1bWVudC5hY3RpdmVFbGVtZW50KSkge1xuXHRcdFx0Y29uc3QgYXV0b0ZvY3VzYWJsZSA9IG5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3Rvcihcblx0XHRcdFx0YFtodWJBdXRvZm9jdXNdYFxuXHRcdFx0KSBhcyBIVE1MRWxlbWVudDtcblx0XHRcdGNvbnN0IGZpcnN0Rm9jdXNhYmxlID1cblx0XHRcdFx0Z2V0Rm9jdXNhYmxlQm91bmRhcnlFbGVtZW50cyhuYXRpdmVFbGVtZW50KVswXTtcblxuXHRcdFx0Y29uc3QgZWxlbWVudFRvRm9jdXMgPVxuXHRcdFx0XHRhdXRvRm9jdXNhYmxlIHx8IGZpcnN0Rm9jdXNhYmxlIHx8IG5hdGl2ZUVsZW1lbnQ7XG5cdFx0XHRlbGVtZW50VG9Gb2N1cy5mb2N1cygpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgX3Jlc3RvcmVGb2N1cygpIHtcblx0XHRjb25zdCBib2R5ID0gdGhpcy5fZG9jdW1lbnQuYm9keTtcblx0XHRjb25zdCBlbFdpdGhGb2N1cyA9IHRoaXMuX2VsV2l0aEZvY3VzO1xuXG5cdFx0bGV0IGVsZW1lbnRUb0ZvY3VzO1xuXHRcdGlmIChlbFdpdGhGb2N1cyAmJiBlbFdpdGhGb2N1c1snZm9jdXMnXSAmJiBib2R5LmNvbnRhaW5zKGVsV2l0aEZvY3VzKSkge1xuXHRcdFx0ZWxlbWVudFRvRm9jdXMgPSBlbFdpdGhGb2N1cztcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbWVudFRvRm9jdXMgPSBib2R5O1xuXHRcdH1cblx0XHR0aGlzLl96b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcblx0XHRcdHNldFRpbWVvdXQoKCkgPT4gZWxlbWVudFRvRm9jdXMuZm9jdXMoKSk7XG5cdFx0XHR0aGlzLl9lbFdpdGhGb2N1cyA9IG51bGw7XG5cdFx0fSk7XG5cdH1cbn1cbiJdfQ==