UNPKG

ngx-extended-pdf-viewer

Version:

Embedding PDF files in your Angular application. Highly configurable viewer including the toolbar, sidebar, and all the features you're used to.

165 lines 29.1 kB
import { isPlatformBrowser } from '@angular/common'; import { Component, EventEmitter, HostListener, Inject, Input, Output, PLATFORM_ID, } from '@angular/core'; import { take } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "./../../pdf-notification-service"; import * as i2 from "../../toolbar/pdf-shy-button/pdf-shy-button-service"; import * as i3 from "@angular/common"; import * as i4 from "../../responsive-visibility"; export class PdfSecondaryToolbarComponent { constructor(element, notificationService, platformId, pdfShyButtonService) { this.element = element; this.notificationService = notificationService; this.platformId = platformId; this.pdfShyButtonService = pdfShyButtonService; this.spreadChange = new EventEmitter(); this.secondaryMenuIsEmpty = new EventEmitter(); this.disablePreviousPage = true; this.disableNextPage = true; this.notificationService.onPDFJSInit.pipe(take(1)).subscribe(() => { this.onPdfJsInit(); }); } onPdfJsInit() { const PDFViewerApplication = window.PDFViewerApplication; PDFViewerApplication.eventBus.on('pagechanging', () => { this.updateUIState(); }); PDFViewerApplication.eventBus.on('pagerendered', () => { this.updateUIState(); }); } updateUIState() { setTimeout(() => { const PDFViewerApplication = window.PDFViewerApplication; const currentPage = PDFViewerApplication.pdfViewer.currentPageNumber; const previousButton = document.getElementById('previousPage'); if (previousButton) { this.disablePreviousPage = Number(currentPage) <= 1; previousButton.disabled = this.disablePreviousPage; } const nextButton = document.getElementById('nextPage'); if (nextButton) { this.disableNextPage = currentPage === PDFViewerApplication.pagesCount; nextButton.disabled = this.disableNextPage; } }); } onSpreadChange(newSpread) { this.spreadChange.emit(newSpread); } ngOnChanges(changes) { setTimeout(() => this.checkVisibility()); } onResize() { setTimeout(() => this.checkVisibility()); } ngAfterViewInit() { if (isPlatformBrowser(this.platformId)) { const targetNode = this.element.nativeElement; const config = { attributes: true, childList: true, subtree: true }; this.classMutationObserver = new MutationObserver((mutationList, observer) => { for (const mutation of mutationList) { if (mutation.type === 'attributes') { if (mutation.attributeName === 'class') { this.checkVisibility(); } } } }); this.classMutationObserver.observe(targetNode, config); } } ngOnDestroy() { if (this.classMutationObserver) { this.classMutationObserver.disconnect(); this.classMutationObserver = undefined; } } checkVisibility() { let visibleButtons = 0; const e = this.element.nativeElement; const f = e.children.item(0); if (f) { const g = f.children.item(0); if (g && g instanceof HTMLElement) { visibleButtons = this.checkVisibilityRecursively(g); } } this.secondaryMenuIsEmpty.emit(visibleButtons === 0); } checkVisibilityRecursively(e) { if (typeof window === 'undefined') { // server-side rendering return 0; } if (e.style.display === 'none') { return 0; } if (e.classList.contains('hidden')) { return 0; } if (e.classList.contains('invisible')) { return 0; } const style = window.getComputedStyle(e); if (style.display === 'none') { return 0; } if (e instanceof HTMLButtonElement || e instanceof HTMLAnchorElement) { return 1; } let count = 0; const children = e.children; if (children?.length) { for (let i = 0; i < children.length && count === 0; i++) { const child = children.item(i); if (child && child instanceof HTMLElement) { count += this.checkVisibilityRecursively(child); } } } return count; } onClick(htmlevent, action, eventBusName, closeOnClick) { const PDFViewerApplication = window.PDFViewerApplication; const origin = htmlevent.target; origin?.classList.add('toggled'); if (action) { action(); htmlevent.preventDefault(); } else if (eventBusName) { PDFViewerApplication.eventBus.dispatch(eventBusName); htmlevent.preventDefault(); } if (closeOnClick) { PDFViewerApplication.secondaryToolbar.close(); } } } PdfSecondaryToolbarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: PdfSecondaryToolbarComponent, deps: [{ token: i0.ElementRef }, { token: i1.PDFNotificationService }, { token: PLATFORM_ID }, { token: i2.PdfShyButtonService }], target: i0.ɵɵFactoryTarget.Component }); PdfSecondaryToolbarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: PdfSecondaryToolbarComponent, selector: "pdf-secondary-toolbar", inputs: { customSecondaryToolbar: "customSecondaryToolbar", secondaryToolbarTop: "secondaryToolbarTop", mobileFriendlyZoomScale: "mobileFriendlyZoomScale", localizationInitialized: "localizationInitialized" }, outputs: { spreadChange: "spreadChange", secondaryMenuIsEmpty: "secondaryMenuIsEmpty" }, host: { listeners: { "window:resize": "onResize()" } }, usesOnChanges: true, ngImport: i0, template: "<ng-container [ngTemplateOutlet]=\"customSecondaryToolbar ? customSecondaryToolbar : defaultSecondaryToolbar\"> </ng-container>\n\n<ng-template #defaultSecondaryToolbar>\n <div\n id=\"secondaryToolbar\"\n class=\"secondaryToolbar hidden doorHangerRight\"\n [style.top]=\"secondaryToolbarTop\"\n [style.transform]=\"'scale(' + mobileFriendlyZoomScale + ')'\"\n [style.transformOrigin]=\"'right top'\"\n >\n <div id=\"secondaryToolbarButtonContainer\">\n <button\n *ngFor=\"let button of pdfShyButtonService.buttons\"\n type=\"button\"\n [id]=\"button.id\"\n [ngClass]=\"button.cssClass | invertForSecondaryToolbar\"\n [class.toggled]=\"button.toggled\"\n class=\"secondaryToolbarButton\"\n [title]=\"button.title\"\n [attr.data-l10n-id]=\"button.l10nId\"\n (click)=\"onClick($event, button.action, button.eventBusName, button.closeOnClick)\"\n [attr.aria-label]=\"button.title\"\n role=\"button\"\n >\n <span class=\"icon\" role=\"img\" aria-hidden=\"true\" [attr.aria-label]=\"button.title\" *ngIf=\"button.image\" [innerHTML]=\"button.image\"></span>\n <span class=\"toolbar-caption\" [attr.data-l10n-id]=\"button.l10nLabel\">{{ button.title }}</span>\n </button>\n </div>\n </div>\n</ng-template>\n", styles: ["svg{position:absolute;display:inline-block;top:0;left:0}.secondaryToolbarButton{display:inline-flex;align-items:center;justify-content:flex-start;border:0 none;background:none;width:calc(100% - 4px);height:25px;position:relative;margin:0 0 4px;padding:3px 0 1px;min-height:25px;white-space:normal}.secondaryToolbarButton span{display:inline-block}.secondaryToolbarButton[disabled]{opacity:.5}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbarButton{padding-left:4px;text-align:left}::ng-deep html[dir=rtl] ngx-extended-pdf-viewer .secondaryToolbarButton{padding-right:4px;text-align:right}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbarButton>span{padding-right:4px}::ng-deep html[dir=rtl] ngx-extended-pdf-viewer .secondaryToolbarButton>span{padding-left:4px}.secondaryToolbar{height:auto;z-index:3000}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbar{right:4px}::ng-deep [dir=rtl] ngx-extended-pdf-viewer .secondaryToolbar{left:4px}#secondaryToolbarButtonContainer{width:250px;max-height:775px;overflow-y:auto;-webkit-overflow-scrolling:touch}.toolbar-caption{position:relative;top:-3px}.icon{width:24px}\n"], directives: [{ type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "invertForSecondaryToolbar": i4.NegativeResponsiveCSSClassPipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: PdfSecondaryToolbarComponent, decorators: [{ type: Component, args: [{ selector: 'pdf-secondary-toolbar', template: "<ng-container [ngTemplateOutlet]=\"customSecondaryToolbar ? customSecondaryToolbar : defaultSecondaryToolbar\"> </ng-container>\n\n<ng-template #defaultSecondaryToolbar>\n <div\n id=\"secondaryToolbar\"\n class=\"secondaryToolbar hidden doorHangerRight\"\n [style.top]=\"secondaryToolbarTop\"\n [style.transform]=\"'scale(' + mobileFriendlyZoomScale + ')'\"\n [style.transformOrigin]=\"'right top'\"\n >\n <div id=\"secondaryToolbarButtonContainer\">\n <button\n *ngFor=\"let button of pdfShyButtonService.buttons\"\n type=\"button\"\n [id]=\"button.id\"\n [ngClass]=\"button.cssClass | invertForSecondaryToolbar\"\n [class.toggled]=\"button.toggled\"\n class=\"secondaryToolbarButton\"\n [title]=\"button.title\"\n [attr.data-l10n-id]=\"button.l10nId\"\n (click)=\"onClick($event, button.action, button.eventBusName, button.closeOnClick)\"\n [attr.aria-label]=\"button.title\"\n role=\"button\"\n >\n <span class=\"icon\" role=\"img\" aria-hidden=\"true\" [attr.aria-label]=\"button.title\" *ngIf=\"button.image\" [innerHTML]=\"button.image\"></span>\n <span class=\"toolbar-caption\" [attr.data-l10n-id]=\"button.l10nLabel\">{{ button.title }}</span>\n </button>\n </div>\n </div>\n</ng-template>\n", styles: ["svg{position:absolute;display:inline-block;top:0;left:0}.secondaryToolbarButton{display:inline-flex;align-items:center;justify-content:flex-start;border:0 none;background:none;width:calc(100% - 4px);height:25px;position:relative;margin:0 0 4px;padding:3px 0 1px;min-height:25px;white-space:normal}.secondaryToolbarButton span{display:inline-block}.secondaryToolbarButton[disabled]{opacity:.5}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbarButton{padding-left:4px;text-align:left}::ng-deep html[dir=rtl] ngx-extended-pdf-viewer .secondaryToolbarButton{padding-right:4px;text-align:right}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbarButton>span{padding-right:4px}::ng-deep html[dir=rtl] ngx-extended-pdf-viewer .secondaryToolbarButton>span{padding-left:4px}.secondaryToolbar{height:auto;z-index:3000}::ng-deep html[dir=ltr] ngx-extended-pdf-viewer .secondaryToolbar{right:4px}::ng-deep [dir=rtl] ngx-extended-pdf-viewer .secondaryToolbar{left:4px}#secondaryToolbarButtonContainer{width:250px;max-height:775px;overflow-y:auto;-webkit-overflow-scrolling:touch}.toolbar-caption{position:relative;top:-3px}.icon{width:24px}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.PDFNotificationService }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: i2.PdfShyButtonService }]; }, propDecorators: { customSecondaryToolbar: [{ type: Input }], secondaryToolbarTop: [{ type: Input }], mobileFriendlyZoomScale: [{ type: Input }], localizationInitialized: [{ type: Input }], spreadChange: [{ type: Output }], secondaryMenuIsEmpty: [{ type: Output }], onResize: [{ type: HostListener, args: ['window:resize'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGRmLXNlY29uZGFyeS10b29sYmFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1leHRlbmRlZC1wZGYtdmlld2VyL3NyYy9saWIvc2Vjb25kYXJ5LXRvb2xiYXIvcGRmLXNlY29uZGFyeS10b29sYmFyL3BkZi1zZWNvbmRhcnktdG9vbGJhci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZXh0ZW5kZWQtcGRmLXZpZXdlci9zcmMvbGliL3NlY29uZGFyeS10b29sYmFyL3BkZi1zZWNvbmRhcnktdG9vbGJhci9wZGYtc2Vjb25kYXJ5LXRvb2xiYXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDcEQsT0FBTyxFQUVMLFNBQVMsRUFFVCxZQUFZLEVBQ1osWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBR0wsTUFBTSxFQUNOLFdBQVcsR0FHWixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7OztBQVV0QyxNQUFNLE9BQU8sNEJBQTRCO0lBeUJ2QyxZQUNVLE9BQW1CLEVBQ3BCLG1CQUEyQyxFQUNyQixVQUFrQixFQUN4QyxtQkFBd0M7UUFIdkMsWUFBTyxHQUFQLE9BQU8sQ0FBWTtRQUNwQix3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXdCO1FBQ3JCLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDeEMsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFxQjtRQWYxQyxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUEwQixDQUFDO1FBRzFELHlCQUFvQixHQUFHLElBQUksWUFBWSxFQUFXLENBQUM7UUFFbkQsd0JBQW1CLEdBQUcsSUFBSSxDQUFDO1FBRTNCLG9CQUFlLEdBQUcsSUFBSSxDQUFD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QixvQkFBb0IsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3JELFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztTQUM1QjtRQUNELElBQUksWUFBWSxFQUFFO1lBQ2hCLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1NBQy9DO0lBQ0gsQ0FBQzs7eUhBdEtVLDRCQUE0QixrRkE0QjdCLFdBQVc7NkdBNUJWLDRCQUE0QixxYkMxQnpDLG96Q0E4QkE7MkZESmEsNEJBQTRCO2tCQUx4QyxTQUFTOytCQUNFLHVCQUF1Qjt3SEFnQ1UsTUFBTTswQkFBOUMsTUFBTTsyQkFBQyxXQUFXOzhFQTFCZCxzQkFBc0I7c0JBRDVCLEtBQUs7Z0JBSUMsbUJBQW1CO3NCQUR6QixLQUFLO2dCQUlDLHVCQUF1QjtzQkFEN0IsS0FBSztnQkFJQyx1QkFBdUI7c0JBRDdCLEtBQUs7Z0JBSUMsWUFBWTtzQkFEbEIsTUFBTTtnQkFJQSxvQkFBb0I7c0JBRDFCLE1BQU07Z0JBd0RBLFFBQVE7c0JBRGQsWUFBWTt1QkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgUExBVEZPUk1fSUQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFRlbXBsYXRlUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IHRha2UgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBJUERGVmlld2VyQXBwbGljYXRpb24gfSBmcm9tICcuLi8uLi9vcHRpb25zL3BkZi12aWV3ZXItYXBwbGljYXRpb24nO1xuaW1wb3J0IHsgUGRmU2h5QnV0dG9uU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvcGRmLXNoeS1idXR0b24vcGRmLXNoeS1idXR0b24tc2VydmljZSc7XG5pbXBvcnQgeyBQREZOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi8uLi8uLi9wZGYtbm90aWZpY2F0aW9uLXNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdwZGYtc2Vjb25kYXJ5LXRvb2xiYXInLFxuICB0ZW1wbGF0ZVVybDogJy4vcGRmLXNlY29uZGFyeS10b29sYmFyLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vcGRmLXNlY29uZGFyeS10b29sYmFyLmNvbXBvbmVudC5jc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgUGRmU2Vjb25kYXJ5VG9vbGJhckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgQElucHV0KClcbiAgcHVibGljIGN1c3RvbVNlY29uZGFyeVRvb2xiYXI6IFRlbXBsYXRlUmVmPGFueT4gfCB1bmRlZmluZWQ7XG5cbiAgQElucHV0KClcbiAgcHVibGljIHNlY29uZGFyeVRvb2xiYXJUb3A7XG5cbiAgQElucHV0KClcbiAgcHVibGljIG1vYmlsZUZyaWVuZGx5Wm9vbVNjYWxlOiBudW1iZXI7XG5cbiAgQElucHV0KClcbiAgcHVibGljIGxvY2FsaXphdGlvbkluaXRpYWxpemVkOiBib29sZWFuO1xuXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgc3ByZWFkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjwnb2ZmJyB8ICdldmVuJyB8ICdvZGQnPigpO1xuXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgc2Vjb25kYXJ5TWVudUlzRW1wdHkgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgcHVibGljIGRpc2FibGVQcmV2aW91c1BhZ2UgPSB0cnVlO1xuXG4gIHB1YmxpYyBkaXNhYmxlTmV4dFBhZ2UgPSB0cnVlO1xuXG4gIHByaXZhdGUgY2xhc3NNdXRhdGlvbk9ic2VydmVyOiBNdXRhdGlvbk9ic2VydmVyIHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgZWxlbWVudDogRWxlbWVudFJlZixcbiAgICBwdWJsaWMgbm90aWZpY2F0aW9uU2VydmljZTogUERGTm90aWZpY2F0aW9uU2VydmljZSxcbiAgICBASW5qZWN0KFBMQVRGT1JNX0lEKSBwcml2YXRlIHBsYXRmb3JtSWQ6IE9iamVjdCxcbiAgICBwdWJsaWMgcGRmU2h5QnV0dG9uU2VydmljZTogUGRmU2h5QnV0dG9uU2VydmljZVxuICApIHtcbiAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2Uub25QREZKU0luaXQucGlwZSh0YWtlKDEpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5vblBkZkpzSW5pdCgpO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIG9uUGRmSnNJbml0KCk6IHZvaWQge1xuICAgIGNvbnN0IFBERlZpZXdlckFwcGxpY2F0aW9uOiBJUERGVmlld2VyQXBwbGljYXRpb24gPSAod2luZG93IGFzIGFueSkuUERGVmlld2VyQXBwbGljYXRpb247XG4gICAgUERGVmlld2VyQXBwbGljYXRpb24uZXZlbnRCdXMub24oJ3BhZ2VjaGFuZ2luZycsICgpID0+IHtcbiAgICAgIHRoaXMudXBkYXRlVUlTdGF0ZSgpO1xuICAgIH0pO1xuICAgIFBERlZpZXdlckFwcGxpY2F0aW9uLmV2ZW50QnVzLm9uKCdwYWdlcmVuZGVyZWQnLCAoKSA9PiB7XG4gICAgICB0aGlzLnVwZGF0ZVVJU3RhdGUoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyB1cGRhdGVVSVN0YXRlKCk6IHZvaWQge1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgY29uc3QgUERGVmlld2VyQXBwbGljYXRpb246IElQREZWaWV3ZXJBcHBsaWNhdGlvbiA9ICh3aW5kb3cgYXMgYW55KS5QREZWaWV3ZXJBcHBsaWNhdGlvbjtcbiAgICAgIGNvbnN0IGN1cnJlbnRQYWdlID0gUERGVmlld2VyQXBwbGljYXRpb24ucGRmVmlld2VyLmN1cnJlbnRQYWdlTnVtYmVyO1xuICAgICAgY29uc3QgcHJldmlvdXNCdXR0b24gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncHJldmlvdXNQYWdlJykgYXMgSFRNTEJ1dHRvbkVsZW1lbnQ7XG4gICAgICBpZiAocHJldmlvdXNCdXR0b24pIHtcbiAgICAgICAgdGhpcy5kaXNhYmxlUHJldmlvdXNQYWdlID0gTnVtYmVyKGN1cnJlbnRQYWdlKSA8PSAxO1xuICAgICAgICBwcmV2aW91c0J1dHRvbi5kaXNhYmxlZCA9IHRoaXMuZGlzYWJsZVByZXZpb3VzUGFnZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG5leHRCdXR0b24gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbmV4dFBhZ2UnKSBhcyBIVE1MQnV0dG9uRWxlbWVudDtcbiAgICAgIGlmIChuZXh0QnV0dG9uKSB7XG4gICAgICAgIHRoaXMuZGlzYWJsZU5leHRQYWdlID0gY3VycmVudFBhZ2UgPT09IFBERlZpZXdlckFwcGxpY2F0aW9uLnBhZ2VzQ291bnQ7XG4gICAgICAgIG5leHRCdXR0b24uZGlzYWJsZWQgPSB0aGlzLmRpc2FibGVOZXh0UGFnZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBvblNwcmVhZENoYW5nZShuZXdTcHJlYWQ6ICdvZmYnIHwgJ29kZCcgfCAnZXZlbicpOiB2b2lkIHtcbiAgICB0aGlzLnNwcmVhZENoYW5nZS5lbWl0KG5ld1NwcmVhZCk7XG4gIH1cblxuICBwdWJsaWMgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5jaGVja1Zpc2liaWxpdHkoKSk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6cmVzaXplJylcbiAgcHVibGljIG9uUmVzaXplKCkge1xuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5jaGVja1Zpc2liaWxpdHkoKSk7XG4gIH1cblxuICBwdWJsaWMgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGlmIChpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSB7XG4gICAgICBjb25zdCB0YXJnZXROb2RlID0gdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQ7XG5cbiAgICAgIGNvbnN0IGNvbmZpZyA9IHsgYXR0cmlidXRlczogdHJ1ZSwgY2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlIH07XG5cbiAgICAgIHRoaXMuY2xhc3NNdXRhdGlvbk9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKG11dGF0aW9uTGlzdDogTXV0YXRpb25SZWNvcmRbXSwgb2JzZXJ2ZXIpID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBtdXRhdGlvbiBvZiBtdXRhdGlvbkxpc3QpIHtcbiAgICAgICAgICBpZiAobXV0YXRpb24udHlwZSA9PT0gJ2F0dHJpYnV0ZXMnKSB7XG4gICAgICAgICAgICBpZiAobXV0YXRpb24uYXR0cmlidXRlTmFtZSA9PT0gJ2NsYXNzJykge1xuICAgICAgICAgICAgICB0aGlzLmNoZWNrVmlzaWJpbGl0eSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuY2xhc3NNdXRhdGlvbk9ic2VydmVyLm9ic2VydmUodGFyZ2V0Tm9kZSwgY29uZmlnKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY2xhc3NNdXRhdGlvbk9ic2VydmVyKSB7XG4gICAgICB0aGlzLmNsYXNzTXV0YXRpb25PYnNlcnZlci5kaXNjb25uZWN0KCk7XG4gICAgICB0aGlzLmNsYXNzTXV0YXRpb25PYnNlcnZlciA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgY2hlY2tWaXNpYmlsaXR5KCk6IHZvaWQge1xuICAgIGxldCB2aXNpYmxlQnV0dG9ucyA9IDA7XG4gICAgY29uc3QgZSA9IHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50IGFzIEhUTUxFbGVtZW50O1xuICAgIGNvbnN0IGYgPSBlLmNoaWxkcmVuLml0ZW0oMCk7XG4gICAgaWYgKGYpIHtcbiAgICAgIGNvbnN0IGcgPSBmLmNoaWxkcmVuLml0ZW0oMCk7XG4gICAgICBpZiAoZyAmJiBnIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgdmlzaWJsZUJ1dHRvbnMgPSB0aGlzLmNoZWNrVmlzaWJpbGl0eVJlY3Vyc2l2ZWx5KGcpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnNlY29uZGFyeU1lbnVJc0VtcHR5LmVtaXQodmlzaWJsZUJ1dHRvbnMgPT09IDApO1xuICB9XG5cbiAgcHJpdmF0ZSBjaGVja1Zpc2liaWxpdHlSZWN1cnNpdmVseShlOiBIVE1MRWxlbWVudCk6IG51bWJlciB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAvLyBzZXJ2ZXItc2lkZSByZW5kZXJpbmdcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBpZiAoZS5zdHlsZS5kaXNwbGF5ID09PSAnbm9uZScpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBpZiAoZS5jbGFzc0xpc3QuY29udGFpbnMoJ2hpZGRlbicpKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgaWYgKGUuY2xhc3NMaXN0LmNvbnRhaW5zKCdpbnZpc2libGUnKSkge1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgY29uc3Qgc3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlKTtcbiAgICBpZiAoc3R5bGUuZGlzcGxheSA9PT0gJ25vbmUnKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBpZiAoZSBpbnN0YW5jZW9mIEhUTUxCdXR0b25FbGVtZW50IHx8IGUgaW5zdGFuY2VvZiBIVE1MQW5jaG9yRWxlbWVudCkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICAgIGxldCBjb3VudCA9IDA7XG4gICAgY29uc3QgY2hpbGRyZW4gPSBlLmNoaWxkcmVuO1xuICAgIGlmIChjaGlsZHJlbj8ubGVuZ3RoKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aCAmJiBjb3VudCA9PT0gMDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGNoaWxkID0gY2hpbGRyZW4uaXRlbShpKTtcbiAgICAgICAgaWYgKGNoaWxkICYmIGNoaWxkIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgICBjb3VudCArPSB0aGlzLmNoZWNrVmlzaWJpbGl0eVJlY3Vyc2l2ZWx5KGNoaWxkKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY291bnQ7XG4gIH1cblxuICBwdWJsaWMgb25DbGljayhodG1sZXZlbnQ6IEV2ZW50LCBhY3Rpb246IHVuZGVmaW5lZCB8ICgoKSA9PiB2b2lkKSwgZXZlbnRCdXNOYW1lPzogc3RyaW5nLCBjbG9zZU9uQ2xpY2s/OiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgUERGVmlld2VyQXBwbGljYXRpb246IElQREZWaWV3ZXJBcHBsaWNhdGlvbiA9ICh3aW5kb3cgYXMgYW55KS5QREZWaWV3ZXJBcHBsaWNhdGlvbjtcbiAgICBjb25zdCBvcmlnaW4gPSBodG1sZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50O1xuICAgIG9yaWdpbj8uY2xhc3NMaXN0LmFkZCgndG9nZ2xlZCcpO1xuICAgIGlmIChhY3Rpb24pIHtcbiAgICAgIGFjdGlvbigpO1xuICAgICAgaHRtbGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSBlbHNlIGlmIChldmVudEJ1c05hbWUpIHtcbiAgICAgIFBERlZpZXdlckFwcGxpY2F0aW9uLmV2ZW50QnVzLmRpc3BhdGNoKGV2ZW50QnVzTmFtZSk7XG4gICAgICBodG1sZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gICAgaWYgKGNsb3NlT25DbGljaykge1xuICAgICAgUERGVmlld2VyQXBwbGljYXRpb24uc2Vjb25kYXJ5VG9vbGJhci5jbG9zZSgpO1xuICAgIH1cbiAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJjdXN0b21TZWNvbmRhcnlUb29sYmFyID8gY3VzdG9tU2Vjb25kYXJ5VG9vbGJhciA6IGRlZmF1bHRTZWNvbmRhcnlUb29sYmFyXCI+IDwvbmctY29udGFpbmVyPlxuXG48bmctdGVtcGxhdGUgI2RlZmF1bHRTZWNvbmRhcnlUb29sYmFyPlxuICA8ZGl2XG4gICAgaWQ9XCJzZWNvbmRhcnlUb29sYmFyXCJcbiAgICBjbGFzcz1cInNlY29uZGFyeVRvb2xiYXIgaGlkZGVuIGRvb3JIYW5nZXJSaWdodFwiXG4gICAgW3N0eWxlLnRvcF09XCJzZWNvbmRhcnlUb29sYmFyVG9wXCJcbiAgICBbc3R5bGUudHJhbnNmb3JtXT1cIidzY2FsZSgnICsgbW9iaWxlRnJpZW5kbHlab29tU2NhbGUgKyAnKSdcIlxuICAgIFtzdHlsZS50cmFuc2Zvcm1PcmlnaW5dPVwiJ3JpZ2h0IHRvcCdcIlxuICA+XG4gICAgPGRpdiBpZD1cInNlY29uZGFyeVRvb2xiYXJCdXR0b25Db250YWluZXJcIj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgKm5nRm9yPVwibGV0IGJ1dHRvbiBvZiBwZGZTaHlCdXR0b25TZXJ2aWNlLmJ1dHRvbnNcIlxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgW2lkXT1cImJ1dHRvbi5pZFwiXG4gICAgICAgIFtuZ0NsYXNzXT1cImJ1dHRvbi5jc3NDbGFzcyB8IGludmVydEZvclNlY29uZGFyeVRvb2xiYXJcIlxuICAgICAgICBbY2xhc3MudG9nZ2xlZF09XCJidXR0b24udG9nZ2xlZFwiXG4gICAgICAgIGNsYXNzPVwic2Vjb25kYXJ5VG9vbGJhckJ1dHRvblwiXG4gICAgICAgIFt0aXRsZV09XCJidXR0b24udGl0bGVcIlxuICAgICAgICBbYXR0ci5kYXRhLWwxMG4taWRdPVwiYnV0dG9uLmwxMG5JZFwiXG4gICAgICAgIChjbGljayk9XCJvbkNsaWNrKCRldmVudCwgYnV0dG9uLmFjdGlvbiwgYnV0dG9uLmV2ZW50QnVzTmFtZSwgYnV0dG9uLmNsb3NlT25DbGljaylcIlxuICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImJ1dHRvbi50aXRsZVwiXG4gICAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgPlxuICAgICAgICA8c3BhbiBjbGFzcz1cImljb25cIiByb2xlPVwiaW1nXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgW2F0dHIuYXJpYS1sYWJlbF09XCJidXR0b24udGl0bGVcIiAqbmdJZj1cImJ1dHRvbi5pbWFnZVwiIFtpbm5lckhUTUxdPVwiYnV0dG9uLmltYWdlXCI+PC9zcGFuPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInRvb2xiYXItY2FwdGlvblwiIFthdHRyLmRhdGEtbDEwbi1pZF09XCJidXR0b24ubDEwbkxhYmVsXCI+e3sgYnV0dG9uLnRpdGxlIH19PC9zcGFuPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==