UNPKG

ngx-smart-modal

Version:

Smart modal handler to manage modals and data everywhere in Angular apps.

524 lines 49.5 kB
import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { Component, EventEmitter, HostListener, Inject, Input, Output, PLATFORM_ID, ViewChild, ViewChildren, ViewContainerRef } from '@angular/core'; import { NgxSmartModalConfig } from '../config/ngx-smart-modal.config'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; export class NgxSmartModalComponent { constructor(_renderer, _changeDetectorRef, _viewContainerRef, elementRef, _document, _platformId) { this._renderer = _renderer; this._changeDetectorRef = _changeDetectorRef; this._viewContainerRef = _viewContainerRef; this.elementRef = elementRef; this._document = _document; this._platformId = _platformId; this.closable = true; this.escapable = true; this.dismissable = true; this.identifier = ''; this.customClass = 'nsm-dialog-animation-fade'; this.visible = false; this.backdrop = true; this.force = true; this.hideDelay = 500; this.autostart = false; this.target = ''; this.ariaLabel = null; this.ariaLabelledBy = null; this.ariaDescribedBy = null; this.refocus = true; this.visibleChange = new EventEmitter(); this.onClose = new EventEmitter(); this.onCloseFinished = new EventEmitter(); this.onDismiss = new EventEmitter(); this.onDismissFinished = new EventEmitter(); this.onAnyCloseEvent = new EventEmitter(); this.onAnyCloseEventFinished = new EventEmitter(); this.onOpen = new EventEmitter(); this.onOpenFinished = new EventEmitter(); this.onEscape = new EventEmitter(); this.onDataAdded = new EventEmitter(); this.onDataRemoved = new EventEmitter(); this.layerPosition = 1041; this.overlayVisible = false; this.openedClass = false; this.createFrom = 'html'; } ngOnInit() { if (!this.identifier || !this.identifier.length) { throw new Error('identifier field isn’t set. Please set one before calling <ngx-smart-modal> in a template.'); } this._sendEvent('create'); } ngAfterViewChecked() { if (this.overlayVisible && this.contentComponent && this.dynamicContentContainer && this.dynamicContentContainer.length === 0) { this.createDynamicContent(); } } ngOnDestroy() { this._sendEvent('delete'); } /** * Open the modal instance * * @param top open the modal top of all other * @returns the modal component */ open(top) { this._sendEvent('open', { top: top }); return this; } /** * Close the modal instance * * @returns the modal component */ close() { this._sendEvent('close'); return this; } /** * Dismiss the modal instance * * @param e the event sent by the browser * @returns the modal component */ dismiss(e) { if (!this.dismissable || !e?.target?.classList.contains('overlay')) { return this; } this._sendEvent('dismiss'); return this; } /** * Toggle visibility of the modal instance * * @param top open the modal top of all other * @returns the modal component */ toggle(top) { this._sendEvent('toggle', { top: top }); return this; } /** * Add a custom class to the modal instance * * @param className the class to add * @returns the modal component */ addCustomClass(className) { if (!this.customClass.length) { this.customClass = className; } else { this.customClass += ' ' + className; } return this; } /** * Remove a custom class to the modal instance * * @param className the class to remove * @returns the modal component */ removeCustomClass(className) { if (className) { this.customClass = this.customClass.replace(className, '').trim(); } else { this.customClass = ''; } return this; } /** * Returns the visibility state of the modal instance */ isVisible() { return this.visible; } /** * Checks if data is attached to the modal instance */ hasData() { return this._data !== undefined; } /** * Attach data to the modal instance * * @param data the data to attach * @param force override potentially attached data * @returns the modal component */ setData(data, force) { if (!this.hasData() || (this.hasData() && force)) { this._data = data; this.assignModalDataToComponentData(this._componentRef); this.onDataAdded.emit(this._data); this.markForCheck(); } return this; } /** * Retrieve the data attached to the modal instance */ getData() { this.assignComponentDataToModalData(this._componentRef); return this._data; } /** * Remove the data attached to the modal instance * * @returns the modal component */ removeData() { this._data = undefined; this.onDataRemoved.emit(true); this.markForCheck(); return this; } /** * Add body class modal opened * * @returns the modal component */ addBodyClass() { this._renderer.addClass(this._document.body, NgxSmartModalConfig.bodyClassOpen); return this; } /** * Add body class modal opened * * @returns the modal component */ removeBodyClass() { this._renderer.removeClass(this._document.body, NgxSmartModalConfig.bodyClassOpen); return this; } markForCheck() { try { this._changeDetectorRef.detectChanges(); } catch (e) { /* empty */ } this._changeDetectorRef.markForCheck(); } /** * Listens for window resize event and recalculates modal instance position if it is element-relative */ targetPlacement() { if (!this.isBrowser || !this.nsmDialog.length || !this.nsmContent.length || !this.nsmOverlay.length || !this.target) { return false; } const targetElement = this._document.querySelector(this.target); if (!targetElement) { return false; } const targetElementRect = targetElement.getBoundingClientRect(); const bodyRect = this.nsmOverlay.first.nativeElement.getBoundingClientRect(); const nsmContentRect = this.nsmContent.first.nativeElement.getBoundingClientRect(); const nsmDialogRect = this.nsmDialog.first.nativeElement.getBoundingClientRect(); const marginLeft = parseInt(getComputedStyle(this.nsmContent.first.nativeElement).marginLeft, 10); const marginTop = parseInt(getComputedStyle(this.nsmContent.first.nativeElement).marginTop, 10); let offsetTop = targetElementRect.top - nsmDialogRect.top - (nsmContentRect.height - targetElementRect.height) / 2; let offsetLeft = targetElementRect.left - nsmDialogRect.left - (nsmContentRect.width - targetElementRect.width) / 2; if (offsetLeft + nsmDialogRect.left + nsmContentRect.width + marginLeft * 2 > bodyRect.width) { offsetLeft = bodyRect.width - (nsmDialogRect.left + nsmContentRect.width) - marginLeft * 2; } else if (offsetLeft + nsmDialogRect.left < 0) { offsetLeft = -nsmDialogRect.left; } if (offsetTop + nsmDialogRect.top + nsmContentRect.height + marginTop > bodyRect.height) { offsetTop = bodyRect.height - (nsmDialogRect.top + nsmContentRect.height) - marginTop; } this._renderer.setStyle(this.nsmContent.first.nativeElement, 'top', (offsetTop < 0 ? 0 : offsetTop) + 'px'); this._renderer.setStyle(this.nsmContent.first.nativeElement, 'left', offsetLeft + 'px'); } _sendEvent(name, extraData) { if (!this.isBrowser) { return false; } const data = { extraData: extraData, instance: { id: this.identifier, modal: this }, }; const event = new CustomEvent(NgxSmartModalConfig.prefixEvent + name, { detail: data, }); return window.dispatchEvent(event); } /** * Is current platform browser */ get isBrowser() { return isPlatformBrowser(this._platformId); } /** * Creates content inside provided ViewContainerRef */ createDynamicContent() { this.dynamicContentContainer.clear(); this._componentRef = this.dynamicContentContainer.createComponent(this.contentComponent); this.assignModalDataToComponentData(this._componentRef); this.markForCheck(); } /** * Assigns the modal data to the ComponentRef instance properties */ assignModalDataToComponentData(componentRef) { if (componentRef) { Object.assign(componentRef.instance, this._data); } } /** * Assigns the ComponentRef instance properties to the modal data object */ assignComponentDataToModalData(componentRef) { if (componentRef) { Object.assign(this._data, componentRef.instance); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.10", ngImport: i0, type: NgxSmartModalComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.10", type: NgxSmartModalComponent, selector: "ngx-smart-modal", inputs: { closable: "closable", escapable: "escapable", dismissable: "dismissable", identifier: "identifier", customClass: "customClass", visible: "visible", backdrop: "backdrop", force: "force", hideDelay: "hideDelay", autostart: "autostart", target: "target", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", ariaDescribedBy: "ariaDescribedBy", refocus: "refocus" }, outputs: { visibleChange: "visibleChange", onClose: "onClose", onCloseFinished: "onCloseFinished", onDismiss: "onDismiss", onDismissFinished: "onDismissFinished", onAnyCloseEvent: "onAnyCloseEvent", onAnyCloseEventFinished: "onAnyCloseEventFinished", onOpen: "onOpen", onOpenFinished: "onOpenFinished", onEscape: "onEscape", onDataAdded: "onDataAdded", onDataRemoved: "onDataRemoved" }, host: { listeners: { "window:resize": "targetPlacement()" } }, viewQueries: [{ propertyName: "dynamicContentContainer", first: true, predicate: ["dynamicContent"], descendants: true, read: ViewContainerRef }, { propertyName: "nsmContent", predicate: ["nsmContent"], descendants: true }, { propertyName: "nsmDialog", predicate: ["nsmDialog"], descendants: true }, { propertyName: "nsmOverlay", predicate: ["nsmOverlay"], descendants: true }], ngImport: i0, template: ` <div *ngIf="overlayVisible" [style.z-index]="visible ? layerPosition - 1 : -1" [ngClass]="{ transparent: !backdrop, overlay: true, 'nsm-overlay-open': openedClass }" (click)="dismiss($event)" #nsmOverlay > <div [style.z-index]="visible ? layerPosition : -1" [ngClass]="[ 'nsm-dialog', customClass, openedClass ? 'nsm-dialog-open' : 'nsm-dialog-close' ]" #nsmDialog [attr.aria-hidden]="openedClass ? false : true" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-describedby]="ariaDescribedBy" > <div class="nsm-content" #nsmContent> <div class="nsm-body"> <ng-template #dynamicContent></ng-template> <ng-content></ng-content> </div> <button type="button" *ngIf="closable" (click)="close()" aria-label="Close" class="nsm-dialog-btn-close" > <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 512 512" xml:space="preserve" width="16px" height="16px" role="img" aria-labelledby="closeIconTitle closeIconDesc" > <title id="closeIconTitle">Close Icon</title> <desc id="closeIconDesc"> A light-gray close icon used to close the modal </desc> <g> <path d="M505.943,6.058c-8.077-8.077-21.172-8.077-29.249,0L6.058,476.693c-8.077,8.077-8.077,21.172,0,29.249 C10.096,509.982,15.39,512,20.683,512c5.293,0,10.586-2.019,14.625-6.059L505.943,35.306 C514.019,27.23,514.019,14.135,505.943,6.058z" fill="currentColor" /> </g> <g> <path d="M505.942,476.694L35.306,6.059c-8.076-8.077-21.172-8.077-29.248,0c-8.077,8.076-8.077,21.171,0,29.248l470.636,470.636 c4.038,4.039,9.332,6.058,14.625,6.058c5.293,0,10.587-2.019,14.624-6.057C514.018,497.866,514.018,484.771,505.942,476.694z" fill="currentColor" /> </g> </svg> </button> </div> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.10", ngImport: i0, type: NgxSmartModalComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-smart-modal', template: ` <div *ngIf="overlayVisible" [style.z-index]="visible ? layerPosition - 1 : -1" [ngClass]="{ transparent: !backdrop, overlay: true, 'nsm-overlay-open': openedClass }" (click)="dismiss($event)" #nsmOverlay > <div [style.z-index]="visible ? layerPosition : -1" [ngClass]="[ 'nsm-dialog', customClass, openedClass ? 'nsm-dialog-open' : 'nsm-dialog-close' ]" #nsmDialog [attr.aria-hidden]="openedClass ? false : true" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-describedby]="ariaDescribedBy" > <div class="nsm-content" #nsmContent> <div class="nsm-body"> <ng-template #dynamicContent></ng-template> <ng-content></ng-content> </div> <button type="button" *ngIf="closable" (click)="close()" aria-label="Close" class="nsm-dialog-btn-close" > <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 512 512" xml:space="preserve" width="16px" height="16px" role="img" aria-labelledby="closeIconTitle closeIconDesc" > <title id="closeIconTitle">Close Icon</title> <desc id="closeIconDesc"> A light-gray close icon used to close the modal </desc> <g> <path d="M505.943,6.058c-8.077-8.077-21.172-8.077-29.249,0L6.058,476.693c-8.077,8.077-8.077,21.172,0,29.249 C10.096,509.982,15.39,512,20.683,512c5.293,0,10.586-2.019,14.625-6.059L505.943,35.306 C514.019,27.23,514.019,14.135,505.943,6.058z" fill="currentColor" /> </g> <g> <path d="M505.942,476.694L35.306,6.059c-8.076-8.077-21.172-8.077-29.248,0c-8.077,8.076-8.077,21.171,0,29.248l470.636,470.636 c4.038,4.039,9.332,6.058,14.625,6.058c5.293,0,10.587-2.019,14.624-6.057C514.018,497.866,514.018,484.771,505.942,476.694z" fill="currentColor" /> </g> </svg> </button> </div> </div> </div> ` }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { closable: [{ type: Input }], escapable: [{ type: Input }], dismissable: [{ type: Input }], identifier: [{ type: Input }], customClass: [{ type: Input }], visible: [{ type: Input }], backdrop: [{ type: Input }], force: [{ type: Input }], hideDelay: [{ type: Input }], autostart: [{ type: Input }], target: [{ type: Input }], ariaLabel: [{ type: Input }], ariaLabelledBy: [{ type: Input }], ariaDescribedBy: [{ type: Input }], refocus: [{ type: Input }], visibleChange: [{ type: Output }], onClose: [{ type: Output }], onCloseFinished: [{ type: Output }], onDismiss: [{ type: Output }], onDismissFinished: [{ type: Output }], onAnyCloseEvent: [{ type: Output }], onAnyCloseEventFinished: [{ type: Output }], onOpen: [{ type: Output }], onOpenFinished: [{ type: Output }], onEscape: [{ type: Output }], onDataAdded: [{ type: Output }], onDataRemoved: [{ type: Output }], nsmContent: [{ type: ViewChildren, args: ['nsmContent'] }], nsmDialog: [{ type: ViewChildren, args: ['nsmDialog'] }], nsmOverlay: [{ type: ViewChildren, args: ['nsmOverlay'] }], dynamicContentContainer: [{ type: ViewChild, args: ['dynamicContent', { read: ViewContainerRef }] }], targetPlacement: [{ type: HostListener, args: ['window:resize'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXNtYXJ0LW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zbWFydC1tb2RhbC9zcmMvbGliL2NvbXBvbmVudHMvbmd4LXNtYXJ0LW1vZGFsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDOUQsT0FBTyxFQUdMLFNBQVMsRUFHVCxZQUFZLEVBQ1osWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBR0wsTUFBTSxFQUNOLFdBQVcsRUFJWCxTQUFTLEVBQ1QsWUFBWSxFQUNaLGdCQUFnQixFQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7O0FBOEV2RSxNQUFNLE9BQU8sc0JBQXNCO0lBa0RqQyxZQUNVLFNBQW9CLEVBQ3BCLGtCQUFxQyxFQUNyQyxpQkFBbUMsRUFDM0IsVUFBc0IsRUFDWixTQUFtQixFQUNoQixXQUFtQjtRQUx4QyxjQUFTLEdBQVQsU0FBUyxDQUFXO1FBQ3BCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBbUI7UUFDckMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFrQjtRQUMzQixlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ1osY0FBUyxHQUFULFNBQVMsQ0FBVTtRQUNoQixnQkFBVyxHQUFYLFdBQVcsQ0FBUTtRQXJEbEMsYUFBUSxHQUFHLElBQUksQ0FBQztRQUNoQixjQUFTLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLGdCQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ25CLGVBQVUsR0FBRyxFQUFFLENBQUM7UUFDaEIsZ0JBQVcsR0FBRywyQkFBMkIsQ0FBQztRQUMxQyxZQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ2hCLGFBQVEsR0FBRyxJQUFJLENBQUM7UUFDaEIsVUFBSyxHQUFH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QUF0QixNQUFNO2dCQUNVLGNBQWM7c0JBQTlCLE1BQU07Z0JBQ1UsUUFBUTtzQkFBeEIsTUFBTTtnQkFDVSxXQUFXO3NCQUEzQixNQUFNO2dCQUNVLGFBQWE7c0JBQTdCLE1BQU07Z0JBWTZCLFVBQVU7c0JBQTdDLFlBQVk7dUJBQUMsWUFBWTtnQkFDUSxTQUFTO3NCQUExQyxZQUFZO3VCQUFDLFdBQVc7Z0JBQ1csVUFBVTtzQkFBN0MsWUFBWTt1QkFBQyxZQUFZO2dCQUVsQix1QkFBdUI7c0JBRDlCLFNBQVM7dUJBQUMsZ0JBQWdCLEVBQUUsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBME5oRCxlQUFlO3NCQURyQixZQUFZO3VCQUFDLGVBQWUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCwgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3Q2hlY2tlZCxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgQ29tcG9uZW50UmVmLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgUExBVEZPUk1fSUQsXG4gIFF1ZXJ5TGlzdCxcbiAgUmVuZGVyZXIyLFxuICBUeXBlLFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdDaGlsZHJlbixcbiAgVmlld0NvbnRhaW5lclJlZlxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5neFNtYXJ0TW9kYWxDb25maWcgfSBmcm9tICcuLi9jb25maWcvbmd4LXNtYXJ0LW1vZGFsLmNvbmZpZyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1zbWFydC1tb2RhbCcsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdlxuICAgICAgKm5nSWY9XCJvdmVybGF5VmlzaWJsZVwiXG4gICAgICBbc3R5bGUuei1pbmRleF09XCJ2aXNpYmxlID8gbGF5ZXJQb3NpdGlvbiAtIDEgOiAtMVwiXG4gICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgIHRyYW5zcGFyZW50OiAhYmFja2Ryb3AsXG4gICAgICAgIG92ZXJsYXk6IHRydWUsXG4gICAgICAgICduc20tb3ZlcmxheS1vcGVuJzogb3BlbmVkQ2xhc3NcbiAgICAgIH1cIlxuICAgICAgKGNsaWNrKT1cImRpc21pc3MoJGV2ZW50KVwiXG4gICAgICAjbnNtT3ZlcmxheVxuICAgID5cbiAgICAgIDxkaXZcbiAgICAgICAgW3N0eWxlLnotaW5kZXhdPVwidmlzaWJsZSA/IGxheWVyUG9zaXRpb24gOiAtMVwiXG4gICAgICAgIFtuZ0NsYXNzXT1cIltcbiAgICAgICAgICAnbnNtLWRpYWxvZycsXG4gICAgICAgICAgY3VzdG9tQ2xhc3MsXG4gICAgICAgICAgb3BlbmVkQ2xhc3MgPyAnbnNtLWRpYWxvZy1vcGVuJyA6ICduc20tZGlhbG9nLWNsb3NlJ1xuICAgICAgICBdXCJcbiAgICAgICAgI25zbURpYWxvZ1xuICAgICAgICBbYXR0ci5hcmlhLWhpZGRlbl09XCJvcGVuZWRDbGFzcyA/IGZhbHNlIDogdHJ1ZVwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcbiAgICAgICAgW2F0dHIuYXJpYS1sYWJlbGxlZGJ5XT1cImFyaWFMYWJlbGxlZEJ5XCJcbiAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJhcmlhRGVzY3JpYmVkQnlcIlxuICAgICAgPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibnNtLWNvbnRlbnRcIiAjbnNtQ29udGVudD5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibnNtLWJvZHlcIj5cbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjZHluYW1pY0NvbnRlbnQ+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICpuZ0lmPVwiY2xvc2FibGVcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImNsb3NlKClcIlxuICAgICAgICAgICAgYXJpYS1sYWJlbD1cIkNsb3NlXCJcbiAgICAgICAgICAgIGNsYXNzPVwibnNtLWRpYWxvZy1idG4tY2xvc2VcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxzdmdcbiAgICAgICAgICAgICAgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiXG4gICAgICAgICAgICAgIHZlcnNpb249XCIxLjFcIlxuICAgICAgICAgICAgICBpZD1cIkxheWVyXzFcIlxuICAgICAgICAgICAgICB4PVwiMHB4XCJcbiAgICAgICAgICAgICAgeT1cIjBweFwiXG4gICAgICAgICAgICAgIHZpZXdCb3g9XCIwIDAgNTEyIDUxMlwiXG4gICAgICAgICAgICAgIHhtbDpzcGFjZT1cInByZXNlcnZlXCJcbiAgICAgICAgICAgICAgd2lkdGg9XCIxNnB4XCJcbiAgICAgICAgICAgICAgaGVpZ2h0PVwiMTZweFwiXG4gICAgICAgICAgICAgIHJvbGU9XCJpbWdcIlxuICAgICAgICAgICAgICBhcmlhLWxhYmVsbGVkYnk9XCJjbG9zZUljb25UaXRsZSBjbG9zZUljb25EZXNjXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPHRpdGxlIGlkPVwiY2xvc2VJY29uVGl0bGVcIj5DbG9zZSBJY29uPC90aXRsZT5cbiAgICAgICAgICAgICAgPGRlc2MgaWQ9XCJjbG9zZUljb25EZXNjXCI+XG4gICAgICAgICAgICAgICAgQSBsaWdodC1ncmF5IGNsb3NlIGljb24gdXNlZCB0byBjbG9zZSB0aGUgbW9kYWxcbiAgICAgICAgICAgICAgPC9kZXNjPlxuICAgICAgICAgICAgICA8Zz5cbiAgICAgICAgICAgICAgICA8cGF0aFxuICAgICAgICAgICAgICAgICAgZD1cIk01MDUuOTQzLDYuMDU4Yy04LjA3Ny04LjA3Ny0yMS4xNzItOC4wNzctMjkuMjQ5LDBMNi4wNTgsNDc2LjY5M2MtOC4wNzcsOC4wNzctOC4wNzcsMjEuMTcyLDAsMjkuMjQ5ICAgIEMxMC4wOTYsNTA5Ljk4MiwxNS4zOSw1MTIsMjAuNjgzLDUxMmM1LjI5MywwLDEwLjU4Ni0yLjAxOSwxNC42MjUtNi4wNTlMNTA1Ljk0MywzNS4zMDYgICAgQzUxNC4wMTksMjcuMjMsNTE0LjAxOSwxNC4xMzUsNTA1Ljk0Myw2LjA1OHpcIlxuICAgICAgICAgICAgICAgICAgZmlsbD1cImN1cnJlbnRDb2xvclwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgPC9nPlxuICAgICAgICAgICAgICA8Zz5cbiAgICAgICAgICAgICAgICA8cGF0aFxuICAgICAgICAgICAgICAgICAgZD1cIk01MDUuOTQyLDQ3Ni42OTRMMzUuMzA2LDYuMDU5Yy04LjA3Ni04LjA3Ny0yMS4xNzItOC4wNzctMjkuMjQ4LDBjLTguMDc3LDguMDc2LTguMDc3LDIxLjE3MSwwLDI5LjI0OGw0NzAuNjM2LDQ3MC42MzYgICAgYzQuMDM4LDQuMDM5LDkuMzMyLDYuMDU4LDE0LjYyNSw2LjA1OGM1LjI5MywwLDEwLjU4Ny0yLjAxOSwxNC42MjQtNi4wNTdDNTE0LjAxOCw0OTcuODY2LDUxNC4wMTgsNDg0Ljc3MSw1MDUuOTQyLDQ3Ni42OTR6XCJcbiAgICAgICAgICAgICAgICAgIGZpbGw9XCJjdXJyZW50Q29sb3JcIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDwvZz5cbiAgICAgICAgICAgIDwvc3ZnPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZXM6IFtdLFxufSlcbmV4cG9ydCBjbGFzcyBOZ3hTbWFydE1vZGFsQ29tcG9uZW50XG4gIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3ksIEFmdGVyVmlld0NoZWNrZWRcbntcbiAgQElucHV0KCkgcHVibGljIGNsb3NhYmxlID0gdHJ1ZTtcbiAgQElucHV0KCkgcHVibGljIGVzY2FwYWJsZSA9IHRydWU7XG4gIEBJbnB1dCgpIHB1YmxpYyBkaXNtaXNzYWJsZSA9IHRydWU7XG4gIEBJbnB1dCgpIHB1YmxpYyBpZGVudGlmaWVyID0gJyc7XG4gIEBJbnB1dCgpIHB1YmxpYyBjdXN0b21DbGFzcyA9ICduc20tZGlhbG9nLWFuaW1hdGlvbi1mYWRlJztcbiAgQElucHV0KCkgcHVibGljIHZpc2libGUgPSBmYWxzZTtcbiAgQElucHV0KCkgcHVibGljIGJhY2tkcm9wID0gdHJ1ZTtcbiAgQElucHV0KCkgcHVibGljIGZvcmNlID0gdHJ1ZTtcbiAgQElucHV0KCkgcHVibGljIGhpZGVEZWxheSA9IDUwMDtcbiAgQElucHV0KCkgcHVibGljIGF1dG9zdGFydCA9IGZhbHNlO1xuICBASW5wdXQoKSBwdWJsaWMgdGFyZ2V0ID0gJyc7XG4gIEBJbnB1dCgpIHB1YmxpYyBhcmlhTGFiZWw6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBASW5wdXQoKSBwdWJsaWMgYXJpYUxhYmVsbGVkQnk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBASW5wdXQoKSBwdWJsaWMgYXJpYURlc2NyaWJlZEJ5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgQElucHV0KCkgcHVibGljIHJlZm9jdXMgPSB0cnVlO1xuXG4gIEBPdXRwdXQoKSBwdWJsaWMgdmlzaWJsZUNoYW5nZTogRXZlbnRFbWl0dGVyPGJvb2xlYW4+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgb25DbG9zZTogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgb25DbG9zZUZpbmlzaGVkOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIHB1YmxpYyBvbkRpc21pc3M6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG9uRGlzbWlzc0ZpbmlzaGVkOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIHB1YmxpYyBvbkFueUNsb3NlRXZlbnQ6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG9uQW55Q2xvc2VFdmVudEZpbmlzaGVkOiBFdmVudEVtaXR0ZXI8YW55PiA9XG4gICAgbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG9uT3BlbjogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgb25PcGVuRmluaXNoZWQ6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG9uRXNjYXBlOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIHB1YmxpYyBvbkRhdGFBZGRlZDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgb25EYXRhUmVtb3ZlZDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgcHVibGljIGNvbnRlbnRDb21wb25lbnQhOiBUeXBlPGFueT47XG4gIHB1YmxpYyBsYXllclBvc2l0aW9uID0gMTA0MTtcbiAgcHVibGljIG92ZXJsYXlWaXNpYmxlID0gZmFsc2U7XG4gIHB1YmxpYyBvcGVuZWRDbGFzcyA9IGZhbHNlO1xuXG4gIHB1YmxpYyBjcmVhdGVGcm9tID0gJ2h0bWwnO1xuXG4gIHByaXZhdGUgX2RhdGE6IGFueTtcbiAgcHJpdmF0ZSBfY29tcG9uZW50UmVmITogQ29tcG9uZW50UmVmPENvbXBvbmVudD47XG5cbiAgQFZpZXdDaGlsZHJlbignbnNtQ29udGVudCcpIHByaXZhdGUgbnNtQ29udGVudCE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZHJlbignbnNtRGlhbG9nJykgcHVibGljIG5zbURpYWxvZyE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZHJlbignbnNtT3ZlcmxheScpIHByaXZhdGUgbnNtT3ZlcmxheSE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZCgnZHluYW1pY0NvbnRlbnQnLCB7IHJlYWQ6IFZpZXdDb250YWluZXJSZWYgfSlcbiAgcHJpdmF0ZSBkeW5hbWljQ29udGVudENvbnRhaW5lciE6IFZpZXdDb250YWluZXJSZWY7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBfcmVuZGVyZXI6IFJlbmRlcmVyMixcbiAgICBwcml2YXRlIF9jaGFuZ2VEZXRlY3RvclJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBfdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcbiAgICBwdWJsaWMgcmVhZG9ubHkgZWxlbWVudFJlZjogRWxlbWVudFJlZixcbiAgICBASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIF9kb2N1bWVudDogRG9jdW1lbnQsXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBfcGxhdGZvcm1JZDogb2JqZWN0XG4gICkge31cblxuICBwdWJsaWMgbmdPbkluaXQoKSB7XG4gICAgaWYgKCF0aGlzLmlkZW50aWZpZXIgfHwgIXRoaXMuaWRlbnRpZmllci5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ2lkZW50aWZpZXIgZmllbGQgaXNu4oCZdCBzZXQuIFBsZWFzZSBzZXQgb25lIGJlZm9yZSBjYWxsaW5nIDxuZ3gtc21hcnQtbW9kYWw+IGluIGEgdGVtcGxhdGUuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLl9zZW5kRXZlbnQoJ2NyZWF0ZScpO1xuICB9XG5cbiAgcHVibGljIG5nQWZ0ZXJWaWV3Q2hlY2tlZCgpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLm92ZXJsYXlWaXNpYmxlICYmXG4gICAgICB0aGlzLmNvbnRlbnRDb21wb25lbnQgJiZcbiAgICAgIHRoaXMuZHluYW1pY0NvbnRlbnRDb250YWluZXIgJiZcbiAgICAgIHRoaXMuZHluYW1pY0NvbnRlbnRDb250YWluZXIubGVuZ3RoID09PSAwXG4gICAgKSB7XG4gICAgICB0aGlzLmNyZWF0ZUR5bmFtaWNDb250ZW50KCk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuX3NlbmRFdmVudCgnZGVsZXRlJyk7XG4gIH1cblxuICAvKipcbiAgICogT3BlbiB0aGUgbW9kYWwgaW5zdGFuY2VcbiAgICpcbiAgICogQHBhcmFtIHRvcCBvcGVuIHRoZSBtb2RhbCB0b3Agb2YgYWxsIG90aGVyXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyBvcGVuKHRvcD86IGJvb2xlYW4pOiBOZ3hTbWFydE1vZGFsQ29tcG9uZW50IHtcbiAgICB0aGlzLl9zZW5kRXZlbnQoJ29wZW4nLCB7IHRvcDogdG9wIH0pO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQ2xvc2UgdGhlIG1vZGFsIGluc3RhbmNlXG4gICAqXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyBjbG9zZSgpOiBOZ3hTbWFydE1vZGFsQ29tcG9uZW50IHtcbiAgICB0aGlzLl9zZW5kRXZlbnQoJ2Nsb3NlJyk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNtaXNzIHRoZSBtb2RhbCBpbnN0YW5jZVxuICAgKlxuICAgKiBAcGFyYW0gZSB0aGUgZXZlbnQgc2VudCBieSB0aGUgYnJvd3NlclxuICAgKiBAcmV0dXJucyB0aGUgbW9kYWwgY29tcG9uZW50XG4gICAqL1xuICBwdWJsaWMgZGlzbWlzcyhlOiBNb3VzZUV2ZW50KTogTmd4U21hcnRNb2RhbENvbXBvbmVudCB7XG4gICAgaWYgKFxuICAgICAgIXRoaXMuZGlzbWlzc2FibGUgfHxcbiAgICAgICEoZT8udGFyZ2V0IGFzIEVsZW1lbnQpPy5jbGFzc0xpc3QuY29udGFpbnMoJ292ZXJsYXknKVxuICAgICkge1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgdGhpcy5fc2VuZEV2ZW50KCdkaXNtaXNzJyk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBUb2dnbGUgdmlzaWJpbGl0eSBvZiB0aGUgbW9kYWwgaW5zdGFuY2VcbiAgICpcbiAgICogQHBhcmFtIHRvcCBvcGVuIHRoZSBtb2RhbCB0b3Agb2YgYWxsIG90aGVyXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyB0b2dnbGUodG9wPzogYm9vbGVhbik6IE5neFNtYXJ0TW9kYWxDb21wb25lbnQge1xuICAgIHRoaXMuX3NlbmRFdmVudCgndG9nZ2xlJywgeyB0b3A6IHRvcCB9KTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGN1c3RvbSBjbGFzcyB0byB0aGUgbW9kYWwgaW5zdGFuY2VcbiAgICpcbiAgICogQHBhcmFtIGNsYXNzTmFtZSB0aGUgY2xhc3MgdG8gYWRkXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyBhZGRDdXN0b21DbGFzcyhjbGFzc05hbWU6IHN0cmluZyk6IE5neFNtYXJ0TW9kYWxDb21wb25lbnQge1xuICAgIGlmICghdGhpcy5jdXN0b21DbGFzcy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuY3VzdG9tQ2xhc3MgPSBjbGFzc05hbWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3VzdG9tQ2xhc3MgKz0gJyAnICsgY2xhc3NOYW1lO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBhIGN1c3RvbSBjbGFzcyB0byB0aGUgbW9kYWwgaW5zdGFuY2VcbiAgICpcbiAgICogQHBhcmFtIGNsYXNzTmFtZSB0aGUgY2xhc3MgdG8gcmVtb3ZlXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyByZW1vdmVDdXN0b21DbGFzcyhjbGFzc05hbWU/OiBzdHJpbmcpOiBOZ3hTbWFydE1vZGFsQ29tcG9uZW50IHtcbiAgICBpZiAoY2xhc3NOYW1lKSB7XG4gICAgICB0aGlzLmN1c3RvbUNsYXNzID0gdGhpcy5jdXN0b21DbGFzcy5yZXBsYWNlKGNsYXNzTmFtZSwgJycpLnRyaW0oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jdXN0b21DbGFzcyA9ICcnO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHZpc2liaWxpdHkgc3RhdGUgb2YgdGhlIG1vZGFsIGluc3RhbmNlXG4gICAqL1xuICBwdWJsaWMgaXNWaXNpYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpc2libGU7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGRhdGEgaXMgYXR0YWNoZWQgdG8gdGhlIG1vZGFsIGluc3RhbmNlXG4gICAqL1xuICBwdWJsaWMgaGFzRGF0YSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCBkYXRhIHRvIHRoZSBtb2RhbCBpbnN0YW5jZVxuICAgKlxuICAgKiBAcGFyYW0gZGF0YSB0aGUgZGF0YSB0byBhdHRhY2hcbiAgICogQHBhcmFtIGZvcmNlIG92ZXJyaWRlIHBvdGVudGlhbGx5IGF0dGFjaGVkIGRhdGFcbiAgICogQHJldHVybnMgdGhlIG1vZGFsIGNvbXBvbmVudFxuICAgKi9cbiAgcHVibGljIHNldERhdGEoZGF0YTogdW5rbm93biwgZm9yY2U/OiBib29sZWFuKTogTmd4U21hcnRNb2RhbENvbXBvbmVudCB7XG4gICAgaWYgKCF0aGlzLmhhc0RhdGEoKSB8fCAodGhpcy5oYXNEYXRhKCkgJiYgZm9yY2UpKSB7XG4gICAgICB0aGlzLl9kYXRhID0gZGF0YTtcbiAgICAgIHRoaXMuYXNzaWduTW9kYWxEYXRhVG9Db21wb25lbnREYXRhKHRoaXMuX2NvbXBvbmVudFJlZik7XG4gICAgICB0aGlzLm9uRGF0YUFkZGVkLmVtaXQodGhpcy5fZGF0YSk7XG4gICAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlIHRoZSBkYXRhIGF0dGFjaGVkIHRvIHRoZSBtb2RhbCBpbnN0YW5jZVxuICAgKi9cbiAgcHVibGljIGdldERhdGE8VD4oKTogVCB7XG4gICAgdGhpcy5hc3NpZ25Db21wb25lbnREYXRhVG9Nb2RhbERhdGEodGhpcy5fY29tcG9uZW50UmVmKTtcbiAgICByZXR1cm4gdGhpcy5fZGF0YSBhcyBUO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSB0aGUgZGF0YSBhdHRhY2hlZCB0byB0aGUgbW9kYWwgaW5zdGFuY2VcbiAgICpcbiAgICogQHJldHVybnMgdGhlIG1vZGFsIGNvbXBvbmVudFxuICAgKi9cbiAgcHVibGljIHJlbW92ZURhdGEoKTogTmd4U21hcnRNb2RhbENvbXBvbmVudCB7XG4gICAgdGhpcy5fZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLm9uRGF0YVJlbW92ZWQuZW1pdCh0cnVlKTtcbiAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGJvZHkgY2xhc3MgbW9kYWwgb3BlbmVkXG4gICAqXG4gICAqIEByZXR1cm5zIHRoZSBtb2RhbCBjb21wb25lbnRcbiAgICovXG4gIHB1YmxpYyBhZGRCb2R5Q2xhc3MoKTogTmd4U21hcnRNb2RhbENvbXBvbmVudCB7XG4gICAgdGhpcy5fcmVuZGVyZXIuYWRkQ2xhc3MoXG4gICAgICB0aGlzLl9kb2N1bWVudC5ib2R5LFxuICAgICAgTmd4U21hcnRNb2RhbENvbmZpZy5ib2R5Q2xhc3NPcGVuXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBib2R5IGNsYXNzIG1vZGFsIG9wZW5lZFxuICAgKlxuICAgKiBAcmV0dXJucyB0aGUgbW9kYWwgY29tcG9uZW50XG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlQm9keUNsYXNzKCk6IE5neFNtYXJ0TW9kYWxDb21wb25lbnQge1xuICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKFxuICAgICAgdGhpcy5fZG9jdW1lbnQuYm9keSxcbiAgICAgIE5neFNtYXJ0TW9kYWxDb25maWcuYm9keUNsYXNzT3BlblxuICAgICk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHB1YmxpYyBtYXJrRm9yQ2hlY2soKSB7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvKiBlbXB0eSAqL1xuICAgIH1cblxuICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RlbnMgZm9yIHdpbmRvdyByZXNpemUgZXZlbnQgYW5kIHJlY2FsY3VsYXRlcyBtb2RhbCBpbnN0YW5jZSBwb3NpdGlvbiBpZiBpdCBpcyBlbGVtZW50LXJlbGF0aXZlXG4gICAqL1xuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6cmVzaXplJylcbiAgcHVibGljIHRhcmdldFBsYWNlbWVudCgpOiBib29sZWFuIHwgdm9pZCB7XG4gICAgaWYgKFxuICAgICAgIXRoaXMuaXNCcm93c2VyIHx8XG4gICAgICAhdGhpcy5uc21EaWFsb2cubGVuZ3RoIHx8XG4gICAgICAhdGhpcy5uc21Db250ZW50Lmxlbmd0aCB8fFxuICAgICAgIXRoaXMubnNtT3ZlcmxheS5sZW5ndGggfHxcbiAgICAgICF0aGlzLnRhcmdldFxuICAgICkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCB0YXJnZXRFbGVtZW50ID0gdGhpcy5fZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLnRhcmdldCk7XG5cbiAgICBpZiAoIXRhcmdldEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCB0YXJnZXRFbGVtZW50UmVjdCA9IHRhcmdldEVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgYm9keVJlY3QgPVxuICAgICAgdGhpcy5uc21PdmVybGF5LmZpcnN0Lm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICBjb25zdCBuc21Db250ZW50UmVjdCA9XG4gICAgICB0aGlzLm5zbUNvbnRlbnQuZmlyc3QubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBuc21EaWFsb2dSZWN0ID1cbiAgICAgIHRoaXMubnNtRGlhbG9nLmZpcnN0Lm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICBjb25zdCBtYXJnaW5MZWZ0ID0gcGFyc2VJbnQoXG4gICAgICBnZXRDb21wdXRlZFN0eWxlKHRoaXMubnNtQ29udGVudC5maXJzdC5uYXRpdmVFbGVtZW50KS5tYXJnaW5MZWZ0LFxuICAgICAgMTBcbiAgICApO1xuICAgIGNvbnN0IG1hcmdpblRvcCA9IHBhcnNlSW50KFxuICAgICAgZ2V0Q29tcHV0ZWRTdHlsZSh0aGlzLm5zbUNvbnRlbnQuZmlyc3QubmF0aXZlRWxlbWVudCkubWFyZ2luVG9wLFxuICAgICAgMTBcbiAgICApO1xuXG4gICAgbGV0IG9mZnNldFRvcCA9XG4gICAgICB0YXJnZXRFbGVtZW50UmVjdC50b3AgLVxuICAgICAgbnNtRGlhbG9nUmVjdC50b3AgLVxuICAgICAgKG5zbUNvbnRlbnRSZWN0LmhlaWdodCAtIHRhcmdldEVsZW1lbnRSZWN0LmhlaWdodCkgLyAyO1xuICAgIGxldCBvZmZzZXRMZWZ0ID1cbiAgICAgIHRhcmdldEVsZW1lbnRSZWN0LmxlZnQgLVxuICAgICAgbnNtRGlhbG9nUmVjdC5sZWZ0IC1cbiAgICAgIChuc21Db250ZW50UmVjdC53aWR0aCAtIHRhcmdldEVsZW1lbnRSZWN0LndpZHRoKSAvIDI7XG5cbiAgICBpZiAoXG4gICAgICBvZmZzZXRMZWZ0ICsgbnNtRGlhbG9nUmVjdC5sZWZ0ICsgbnNtQ29udGVudFJlY3Qud2lkdGggKyBtYXJnaW5MZWZ0ICogMiA+XG4gICAgICBib2R5UmVjdC53aWR0aFxuICAgICkge1xuICAgICAgb2Zmc2V0TGVmdCA9XG4gICAgICAgIGJvZHlSZWN0LndpZHRoIC1cbiAgICAgICAgKG5zbURpYWxvZ1JlY3QubGVmdCArIG5zbUNvbnRlbnRSZWN0LndpZHRoKSAtXG4gICAgICAgIG1hcmdpbkxlZnQgKiAyO1xuICAgIH0gZWxzZSBpZiAob2Zmc2V0TGVmdCArIG5zbURpYWxvZ1JlY3QubGVmdCA8IDApIHtcbiAgICAgIG9mZnNldExlZnQgPSAtbnNtRGlhbG9nUmVjdC5sZWZ0O1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIG9mZnNldFRvcCArIG5zbURpYWxvZ1JlY3QudG9wICsgbnNtQ29udGVudFJlY3QuaGVpZ2h0ICsgbWFyZ2luVG9wID5cbiAgICAgIGJvZHlSZWN0LmhlaWdodFxuICAgICkge1xuICAgICAgb2Zmc2V0VG9wID1cbiAgICAgICAgYm9keVJlY3QuaGVpZ2h0IC1cbiAgICAgICAgKG5zbURpYWxvZ1JlY3QudG9wICsgbnNtQ29udGVudFJlY3QuaGVpZ2h0KSAtXG4gICAgICAgIG1hcmdpblRvcDtcbiAgICB9XG5cbiAgICB0aGlzLl9yZW5kZXJlci5zZXRTdHlsZShcbiAgICAgIHRoaXMubnNtQ29udGVudC5maXJzdC5uYXRpdmVFbGVtZW50LFxuICAgICAgJ3RvcCcsXG4gICAgICAob2Zmc2V0VG9wIDwgMCA/IDAgOiBvZmZzZXRUb3ApICsgJ3B4J1xuICAgICk7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUoXG4gICAgICB0aGlzLm5zbUNvbnRlbnQuZmlyc3QubmF0aXZlRWxlbWVudCxcbiAgICAgICdsZWZ0JyxcbiAgICAgIG9mZnNldExlZnQgKyAncHgnXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgX3NlbmRFdmVudChuYW1lOiBzdHJpbmcsIGV4dHJhRGF0YT86IHVua25vd24pOiBib29sZWFuIHtcbiAgICBpZiAoIXRoaXMuaXNCcm93c2VyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIGV4dHJhRGF0YTogZXh0cmFEYXRhLFxuICAgICAgaW5zdGFuY2U6IHsgaWQ6IHRoaXMuaWRlbnRpZmllciwgbW9kYWw6IHRoaXMgfSxcbiAgICB9O1xuXG4gICAgY29uc3QgZXZlbnQgPSBuZXcgQ3VzdG9tRXZlbnQoTmd4U21hcnRNb2RhbENvbmZpZy5wcmVmaXhFdmVudCArIG5hbWUsIHtcbiAgICAgIGRldGFpbDogZGF0YSxcbiAgICB9KTtcblxuICAgIHJldHVybiB3aW5kb3cuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gIH1cblxuICAvKipcbiAgICogSXMgY3VycmVudCBwbGF0Zm9ybSBicm93c2VyXG4gICAqL1xuICBwcml2YXRlIGdldCBpc0Jyb3dzZXIoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMuX3BsYXRmb3JtSWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgY29udGVudCBpbnNpZGUgcHJvdmlkZWQgVmlld0NvbnRhaW5lclJlZlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVEeW5hbWljQ29udGVudCgpOiB2b2lkIHtcbiAgICB0aGlzLmR5bmFtaWNDb250ZW50Q29udGFpbmVyLmNsZWFyKCk7XG4gICAgdGhpcy5fY29tcG9uZW50UmVmID0gdGhpcy5keW5hbWljQ29udGVudENvbnRhaW5lci5jcmVhdGVDb21wb25lbnQoXG4gICAgICB0aGlzLmNvbnRlbnRDb21wb25lbnRcbiAgICApO1xuICAgIHRoaXMuYXNzaWduTW9kYWxEYXRhVG9Db21wb25lbnREYXRhKHRoaXMuX2NvbXBvbmVudFJlZik7XG4gICAgdGhpcy5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NpZ25zIHRoZSBtb2RhbCBkYXRhIHRvIHRoZSBDb21wb25lbnRSZWYgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3NpZ25Nb2RhbERhdGFUb0NvbXBvbmVudERhdGEoXG4gICAgY29tcG9uZW50UmVmOiBDb21wb25lbnRSZWY8Q29tcG9uZW50PlxuICApOiB2b2lkIHtcbiAgICBpZiAoY29tcG9uZW50UmVmKSB7XG4gICAgICBPYmplY3QuYXNzaWduKGNvbXBvbmVudFJlZi5pbnN0YW5jZSwgdGhpcy5fZGF0YSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFzc2lnbnMgdGhlIENvbXBvbmVudFJlZiBpbnN0YW5jZSBwcm9wZXJ0aWVzIHRvIHRoZSBtb2RhbCBkYXRhIG9iamVjdFxuICAgKi9cbiAgcHJpdmF0ZSBhc3NpZ25Db21wb25lbnREYXRhVG9Nb2RhbERhdGEoXG4gICAgY29tcG9uZW50UmVmOiBDb21wb25lbnRSZWY8Q29tcG9uZW50PlxuICApOiB2b2lkIHtcbiAgICBpZiAoY29tcG9uZW50UmVmKSB7XG4gICAgICBPYmplY3QuYXNzaWduKHRoaXMuX2RhdGEsIGNvbXBvbmVudFJlZi5pbnN0YW5jZSk7XG4gICAgfVxuICB9XG59XG4iXX0=