UNPKG

@herdwatch/ngx-ionic-image-viewer

Version:

The angular workspace to develop the ngx-ionic-image-viewer component

232 lines 35.8 kB
import { Component, Input, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { IonHeader, IonToolbar, IonButton, IonButtons, IonIcon, IonTitle, IonContent, IonFooter, IonText } from '@ionic/angular/standalone'; import { NgClass } from '@angular/common'; import { addIcons } from 'ionicons'; import { close } from 'ionicons/icons'; import * as i0 from "@angular/core"; import * as i1 from "@ionic/angular/standalone"; export class ViewerModalComponent { // @ViewChild('sliderRef', { static: true }) slides!: IonSlides; constructor(modalController) { this.modalController = modalController; this.alt = ''; this.scheme = 'auto'; this.slideOptions = {}; this.srcFallback = ''; this.srcHighRes = ''; this.swipeToClose = true; this.text = ''; this.title = ''; this.titleSize = ''; this.defaultSlideOptions = { zoom: { enabled: true, }, }; this.options = {}; this.swipeState = { phase: 'init', direction: 'none', swipeType: 'none', startX: 0, startY: 0, distance: 0, distanceX: 0, distanceY: 0, threshold: 150, // required min distance traveled to be considered swipe restraint: 100, // maximum distance allowed at the same time in perpendicular direction allowedTime: 500, // maximum time allowed to travel that distance elapsedTime: 0, startTime: 0, }; addIcons({ close }); } async ngOnInit() { this.options = { ...this.defaultSlideOptions, ...this.slideOptions }; this.src = this.srcHighRes || this.src; this.setStyle(); this.setScheme(this.scheme); this.initSwipeToClose(this.swipeToClose); /** * Current Workaround * See reported bug: https://github.com/ionic-team/ionic/issues/19638#issuecomment-584828315 * Hint: Comment in '<ion-slide>' in component */ } setStyle() { const el = document.querySelector('.ion-img-viewer'); el?.style.setProperty('--height', '100%'); el?.style.setProperty('--width', '100%'); el?.style.setProperty('--border-radius', '0'); } setScheme(scheme) { if (scheme && scheme === 'auto') { return; } const el = document.querySelector('.ion-img-viewer'); if (this.scheme === 'light') { el?.style.setProperty('--ion-background-color', '#ffffff'); el?.style.setProperty('--ion-background-color-rgb', '255, 255, 255'); el?.style.setProperty('--ion-text-color', '#000'); el?.style.setProperty('--ion-text-color-rgb', '0,0,0'); } if (this.scheme === 'dark') { if (el?.classList.contains('ios')) { el?.style.setProperty('--ion-background-color', '#000000'); el?.style.setProperty('--ion-background-color-rgb', '0, 0, 0'); } else { el?.style.setProperty('--ion-background-color', '#121212'); el?.style.setProperty('--ion-background-color-rgb', '18,18,18'); } el?.style.setProperty('--ion-text-color', '#ffffff'); el?.style.setProperty('--ion-text-color-rgb', '255,255,255'); } } /** * @see http://www.javascriptkit.com/javatutors/touchevents3.shtml */ initSwipeToClose(isActive = true) { if (!isActive) { return; } const el = document.querySelector('ion-modal'); el?.addEventListener('mousedown', (event) => this.swipeStart(event), true); el?.addEventListener('mousemove', (event) => this.swipeMove(event), true); el?.addEventListener('mouseup', () => this.swipeEnd(), true); el?.addEventListener('touchstart', (event) => this.swipeStart(event), true); el?.addEventListener('touchmove', (event) => this.swipeMove(event), true); el?.addEventListener('touchend', () => this.swipeEnd(), true); this.modalController.getTop().then((modal) => { modal?.onWillDismiss().then(() => { document.removeEventListener('mousedown', this.swipeStart, true); document.removeEventListener('mousemove', this.swipeMove, true); document.removeEventListener('mouseup', this.swipeMove, true); document.removeEventListener('touchstart', this.swipeStart, true); document.removeEventListener('touchmove', this.swipeMove, true); document.removeEventListener('touchend', this.swipeMove, true); }); }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any swipeStart(event) { const { pageX, pageY } = event.type === 'touchstart' && event?.changedTouches ? event.changedTouches[0] : event; this.swipeState = { ...this.swipeState, phase: 'start', direction: 'none', distance: 0, startX: pageX, startY: pageY, startTime: new Date().getTime(), }; } // eslint-disable-next-line @typescript-eslint/no-explicit-any swipeMove(event) { const { pageX, pageY } = event.type === 'touchmove' && event?.changedTouches ? event.changedTouches[0] : event; // get horizontal dist traveled by finger while in contact with surface const distanceX = pageX - this.swipeState.startX; // get vertical dist traveled by finger while in contact with surface const distanceY = pageY - this.swipeState.startY; let direction; let distance; if (Math.abs(distanceX) > Math.abs(distanceY)) { // if distance traveled horizontally is greater than vertically, consider this a horizontal swipe direction = distanceX < 0 ? 'left' : 'right'; distance = distanceX; } else { // else consider this a vertical swipe direction = distanceY < 0 ? 'up' : 'down'; distance = distanceY; } this.swipeState = { ...this.swipeState, phase: 'move', direction, distance, distanceX, distanceY, }; if (event.cancelable) { event.preventDefault(); } } swipeEnd() { if (this.swipeState.phase === 'none') { return; } const { allowedTime, direction, restraint, startTime, threshold, distanceX, distanceY, } = this.swipeState; let swipeType = null; const elapsedTime = new Date().getTime() - startTime; // get time elapsed if (elapsedTime <= allowedTime) { // first condition for a swipe met if (Math.abs(distanceX) >= threshold && Math.abs(distanceY) <= restraint) { // 2nd condition for horizontal swipe met swipeType = direction; // set swipeType to either "left" or "right" } else if (Math.abs(distanceY) >= threshold && Math.abs(distanceX) <= restraint) { // 2nd condition for vertical swipe met swipeType = direction; // set swipeType to either "top" or "down" } } this.swipeState = { ...this.swipeState, phase: 'end', swipeType: swipeType ?? '', }; if (swipeType === 'down') { return this.closeModal(); } } closeModal() { this.modalController.dismiss(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.10", ngImport: i0, type: ViewerModalComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.10", type: ViewerModalComponent, isStandalone: true, selector: "ion-viewer-modal", inputs: { alt: "alt", scheme: "scheme", slideOptions: "slideOptions", src: "src", srcFallback: "srcFallback", srcHighRes: "srcHighRes", swipeToClose: "swipeToClose", text: "text", title: "title", titleSize: "titleSize" }, viewQueries: [{ propertyName: "swiperRef", first: true, predicate: ["swiper"], descendants: true }], ngImport: i0, template: "<ion-header [ngClass]=\"{ 'no-title': title && title.length <= 0 }\">\n <ion-toolbar>\n <ion-buttons slot=\"primary\">\n <ion-button data-cy=\"closeModal\" (click)=\"closeModal()\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title [size]=\"titleSize\">{{ title }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [forceOverscroll]=\"false\">\n <swiper-container [options]=\"options\" centeredSlides=\"true\" passiveListeners=\"false\" zoom=\"true\" #swiper>\n <swiper-slide>\n <div class=\"swiper-zoom-container\">\n <img [alt]=\"this.alt\" [src]=\"this.src\"/>\n </div>\n </swiper-slide>\n </swiper-container>\n</ion-content>\n\n<ion-footer [ngClass]=\"{ 'no-text': text && text.length <= 0 }\">\n <ion-toolbar class=\"ion-text-center\">\n <ion-text>{{ text }}</ion-text>\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-slides{--height: 100%;height:100%}ion-toolbar{--border-style: none;--background: rgba(var(--ion-background-color-rgb, (255, 255, 255)), .6);background:rgba(var(--ion-background-color-rgb, 255, 255, 255),.6)}ion-header{opacity:1;position:absolute}ion-header.no-title:after{content:none}ion-header.no-title ion-toolbar{--background: rgba(0, 0, 0, 0);background:#0000}ion-footer{position:absolute;bottom:0}ion-footer.no-text:before{content:none}ion-footer.no-text ion-toolbar{--background: rgba(0, 0, 0, 0);background:#0000}swiper-container{width:100%;height:100%}swiper-slide{overflow:hidden}\n"], dependencies: [{ kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.10", ngImport: i0, type: ViewerModalComponent, decorators: [{ type: Component, args: [{ selector: 'ion-viewer-modal', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], imports: [ IonHeader, IonToolbar, IonButton, NgClass, IonButtons, IonIcon, IonTitle, IonContent, IonFooter, IonText, ], template: "<ion-header [ngClass]=\"{ 'no-title': title && title.length <= 0 }\">\n <ion-toolbar>\n <ion-buttons slot=\"primary\">\n <ion-button data-cy=\"closeModal\" (click)=\"closeModal()\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title [size]=\"titleSize\">{{ title }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [forceOverscroll]=\"false\">\n <swiper-container [options]=\"options\" centeredSlides=\"true\" passiveListeners=\"false\" zoom=\"true\" #swiper>\n <swiper-slide>\n <div class=\"swiper-zoom-container\">\n <img [alt]=\"this.alt\" [src]=\"this.src\"/>\n </div>\n </swiper-slide>\n </swiper-container>\n</ion-content>\n\n<ion-footer [ngClass]=\"{ 'no-text': text && text.length <= 0 }\">\n <ion-toolbar class=\"ion-text-center\">\n <ion-text>{{ text }}</ion-text>\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-slides{--height: 100%;height:100%}ion-toolbar{--border-style: none;--background: rgba(var(--ion-background-color-rgb, (255, 255, 255)), .6);background:rgba(var(--ion-background-color-rgb, 255, 255, 255),.6)}ion-header{opacity:1;position:absolute}ion-header.no-title:after{content:none}ion-header.no-title ion-toolbar{--background: rgba(0, 0, 0, 0);background:#0000}ion-footer{position:absolute;bottom:0}ion-footer.no-text:before{content:none}ion-footer.no-text ion-toolbar{--background: rgba(0, 0, 0, 0);background:#0000}swiper-container{width:100%;height:100%}swiper-slide{overflow:hidden}\n"] }] }], ctorParameters: () => [{ type: i1.ModalController }], propDecorators: { alt: [{ type: Input }], scheme: [{ type: Input }], slideOptions: [{ type: Input }], src: [{ type: Input }], srcFallback: [{ type: Input }], srcHighRes: [{ type: Input }], swipeToClose: [{ type: Input }], text: [{ type: Input }], title: [{ type: Input }], titleSize: [{ type: Input }], swiperRef: [{ type: ViewChild, args: ['swiper'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld2VyLW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvbmd4LWlvbmljLWltYWdlLXZpZXdlci9zcmMvbGliL3ZpZXdlci1tb2RhbC92aWV3ZXItbW9kYWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9uZ3gtaW9uaWMtaW1hZ2Utdmlld2VyL3NyYy9saWIvdmlld2VyLW1vZGFsL3ZpZXdlci1tb2RhbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxTQUFTLEVBQWMsc0JBQXNCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFeEcsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUksT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDcEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFvQnZDLE1BQU0sT0FBTyxvQkFBb0I7SUFzQy9CLGdFQUFnRTtJQUVoRSxZQUFvQixlQUFnQztRQUFoQyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUF2QzNDLFFBQUcsR0FBWSxFQUFFLENBQUM7UUFDbEIsV0FBTSxHQUFZLE1BQU0sQ0FBQztRQUN6QixpQkFBWSxHQUFZLEVBQUUsQ0FBQztRQUUzQixnQkFBVyxHQUFZLEVBQUUsQ0FBQztRQUMxQixlQUFVLEdBQVksRUFBRSxDQUFDO1FBQ3pCLGlCQUFZLEdBQWEsSUFBSSxDQUFDO1FBQzlCLFNBQUksR0FBWSxFQUFFLENBQUM7UUFDbkIsVUFBSyxHQUFZ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QWxCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBMEJlLFNBQVM7c0JBQTdCLFNBQVM7dUJBQUMsUUFBUSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgVmlld0NoaWxkLCBFbGVtZW50UmVmLCBDVVNUT01fRUxFTUVOVFNfU0NIRU1BIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBNb2RhbENvbnRyb2xsZXIgfSBmcm9tICdAaW9uaWMvYW5ndWxhci9zdGFuZGFsb25lJztcbmltcG9ydCB7IElvbkhlYWRlciwgSW9uVG9vbGJhciwgSW9uQnV0dG9uLCBJb25CdXR0b25zLCBJb25JY29uLCBJb25UaXRsZSwgSW9uQ29udGVudCwgSW9uRm9vdGVyLCBJb25UZXh0IH0gZnJvbSAnQGlvbmljL2FuZ3VsYXIvc3RhbmRhbG9uZSc7XG5pbXBvcnQgeyBOZ0NsYXNzIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IGFkZEljb25zIH0gZnJvbSAnaW9uaWNvbnMnO1xuaW1wb3J0IHsgY2xvc2UgfSBmcm9tICdpb25pY29ucy9pY29ucyc7XG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdpb24tdmlld2VyLW1vZGFsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3ZpZXdlci1tb2RhbC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3ZpZXdlci1tb2RhbC5jb21wb25lbnQuc2NzcyddLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBzY2hlbWFzOiBbQ1VTVE9NX0VMRU1FTlRTX1NDSEVNQV0sXG4gIGltcG9ydHM6IFtcbiAgICBJb25IZWFkZXIsXG4gICAgSW9uVG9vbGJhcixcbiAgICBJb25CdXR0b24sXG4gICAgTmdDbGFzcyxcbiAgICBJb25CdXR0b25zLFxuICAgIElvbkljb24sXG4gICAgSW9uVGl0bGUsXG4gICAgSW9uQ29udGVudCxcbiAgICBJb25Gb290ZXIsXG4gICAgSW9uVGV4dCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgVmlld2VyTW9kYWxDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBASW5wdXQoKSBhbHQ/OiBzdHJpbmcgPSAnJztcbiAgQElucHV0KCkgc2NoZW1lPzogc3RyaW5nID0gJ2F1dG8nO1xuICBASW5wdXQoKSBzbGlkZU9wdGlvbnM/OiBvYmplY3QgPSB7fTtcbiAgQElucHV0KCkgc3JjITogc3RyaW5nO1xuICBASW5wdXQoKSBzcmNGYWxsYmFjaz86IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBzcmNIaWdoUmVzPzogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIHN3aXBlVG9DbG9zZT86IGJvb2xlYW4gPSB0cnVlO1xuICBASW5wdXQoKSB0ZXh0Pzogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIHRpdGxlPzogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIHRpdGxlU2l6ZT86IHN0cmluZyA9ICcnO1xuXG4gIGRlZmF1bHRTbGlkZU9wdGlvbnMgPSB7XG4gICAgem9vbToge1xuICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICB9LFxuICB9O1xuXG4gIG9wdGlvbnMgPSB7fTtcblxuICBzd2lwZVN0YXRlID0ge1xuICAgIHBoYXNlOiAnaW5pdCcsXG4gICAgZGlyZWN0aW9uOiAnbm9uZScsXG4gICAgc3dpcGVUeXBlOiAnbm9uZScsXG4gICAgc3RhcnRYOiAwLFxuICAgIHN0YXJ0WTogMCxcbiAgICBkaXN0YW5jZTogMCxcbiAgICBkaXN0YW5jZVg6IDAsXG4gICAgZGlzdGFuY2VZOiAwLFxuICAgIHRocmVzaG9sZDogMTUwLCAvLyByZXF1aXJlZCBtaW4gZGlzdGFuY2UgdHJhdmVsZWQgdG8gYmUgY29uc2lkZXJlZCBzd2lwZVxuICAgIHJlc3RyYWludDogMTAwLCAvLyBtYXhpbXVtIGRpc3RhbmNlIGFsbG93ZWQgYXQgdGhlIHNhbWUgdGltZSBpbiBwZXJwZW5kaWN1bGFyIGRpcmVjdGlvblxuICAgIGFsbG93ZWRUaW1lOiA1MDAsIC8vIG1heGltdW0gdGltZSBhbGxvd2VkIHRvIHRyYXZlbCB0aGF0IGRpc3RhbmNlXG4gICAgZWxhcHNlZFRpbWU6IDAsXG4gICAgc3RhcnRUaW1lOiAwLFxuICB9O1xuXG4gIEBWaWV3Q2hpbGQoJ3N3aXBlcicpIHN3aXBlclJlZjogRWxlbWVudFJlZiB8IHVuZGVmaW5lZDtcblxuICAvLyBAVmlld0NoaWxkKCdzbGlkZXJSZWYnLCB7IHN0YXRpYzogdHJ1ZSB9KSBzbGlkZXMhOiBJb25TbGlkZXM7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBtb2RhbENvbnRyb2xsZXI6IE1vZGFsQ29udHJvbGxlcikge1xuICAgIGFkZEljb25zKHtjbG9zZX0pXG4gIH1cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7IC4uLnRoaXMuZGVmYXVsdFNsaWRlT3B0aW9ucywgLi4udGhpcy5zbGlkZU9wdGlvbnMgfTtcbiAgICB0aGlzLnNyYyA9IHRoaXMuc3JjSGlnaFJlcyB8fCB0aGlzLnNyYztcbiAgICB0aGlzLnNldFN0eWxlKCk7XG4gICAgdGhpcy5zZXRTY2hlbWUodGhpcy5zY2hlbWUpO1xuICAgIHRoaXMuaW5pdFN3aXBlVG9DbG9zZSh0aGlzLnN3aXBlVG9DbG9zZSk7XG5cbiAgICAvKipcbiAgICAgKiBDdXJyZW50IFdvcmthcm91bmRcbiAgICAgKiBTZWUgcmVwb3J0ZWQgYnVnOiBodHRwczovL2dpdGh1Yi5jb20vaW9uaWMtdGVhbS9pb25pYy9pc3N1ZXMvMTk2MzgjaXNzdWVjb21tZW50LTU4NDgyODMxNVxuICAgICAqIEhpbnQ6IENvbW1lbnQgaW4gJzxpb24tc2xpZGU+JyBpbiBjb21wb25lbnRcbiAgICAgKi9cbiAgfVxuXG4gIHNldFN0eWxlKCkge1xuICAgIGNvbnN0IGVsOiBIVE1MRWxlbWVudCB8IG51bGwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuaW9uLWltZy12aWV3ZXInKTtcbiAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taGVpZ2h0JywgJzEwMCUnKTtcbiAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0td2lkdGgnLCAnMTAwJScpO1xuICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1ib3JkZXItcmFkaXVzJywgJzAnKTtcbiAgfVxuXG4gIHNldFNjaGVtZShzY2hlbWU6IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICAgIGlmIChzY2hlbWUgJiYgc2NoZW1lID09PSAnYXV0bycpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBlbDogSFRNTEVsZW1lbnQgfCBudWxsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmlvbi1pbWctdmlld2VyJyk7XG5cbiAgICBpZiAodGhpcy5zY2hlbWUgPT09ICdsaWdodCcpIHtcbiAgICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1pb24tYmFja2dyb3VuZC1jb2xvcicsICcjZmZmZmZmJyk7XG4gICAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taW9uLWJhY2tncm91bmQtY29sb3ItcmdiJywgJzI1NSwgMjU1LCAyNTUnKTtcbiAgICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1pb24tdGV4dC1jb2xvcicsICcjMDAwJyk7XG4gICAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taW9uLXRleHQtY29sb3ItcmdiJywgJzAsMCwwJyk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2NoZW1lID09PSAnZGFyaycpIHtcbiAgICAgIGlmIChlbD8uY2xhc3NMaXN0LmNvbnRhaW5zKCdpb3MnKSkge1xuICAgICAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taW9uLWJhY2tncm91bmQtY29sb3InLCAnIzAwMDAwMCcpO1xuICAgICAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taW9uLWJhY2tncm91bmQtY29sb3ItcmdiJywgJzAsIDAsIDAnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1pb24tYmFja2dyb3VuZC1jb2xvcicsICcjMTIxMjEyJyk7XG4gICAgICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1pb24tYmFja2dyb3VuZC1jb2xvci1yZ2InLCAnMTgsMTgsMTgnKTtcbiAgICAgIH1cbiAgICAgIGVsPy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1pb24tdGV4dC1jb2xvcicsICcjZmZmZmZmJyk7XG4gICAgICBlbD8uc3R5bGUuc2V0UHJvcGVydHkoJy0taW9uLXRleHQtY29sb3ItcmdiJywgJzI1NSwyNTUsMjU1Jyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBzZWUgaHR0cDovL3d3dy5qYXZhc2NyaXB0a2l0LmNvbS9qYXZhdHV0b3JzL3RvdWNoZXZlbnRzMy5zaHRtbFxuICAgKi9cbiAgaW5pdFN3aXBlVG9DbG9zZShpc0FjdGl2ZSA9IHRydWUpIHtcbiAgICBpZiAoIWlzQWN0aXZlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdpb24tbW9kYWwnKTtcbiAgICBlbD8uYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgKGV2ZW50KSA9PiB0aGlzLnN3aXBlU3RhcnQoZXZlbnQpLCB0cnVlKTtcbiAgICBlbD8uYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgKGV2ZW50KSA9PiB0aGlzLnN3aXBlTW92ZShldmVudCksIHRydWUpO1xuICAgIGVsPy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgKCkgPT4gdGhpcy5zd2lwZUVuZCgpLCB0cnVlKTtcbiAgICBlbD8uYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsIChldmVudCkgPT4gdGhpcy5zd2lwZVN0YXJ0KGV2ZW50KSwgdHJ1ZSk7XG4gICAgZWw/LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIChldmVudCkgPT4gdGhpcy5zd2lwZU1vdmUoZXZlbnQpLCB0cnVlKTtcbiAgICBlbD8uYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCAoKSA9PiB0aGlzLnN3aXBlRW5kKCksIHRydWUpO1xuXG4gICAgdGhpcy5tb2RhbENvbnRyb2xsZXIuZ2V0VG9wKCkudGhlbigobW9kYWwpID0+IHtcbiAgICAgIG1vZGFsPy5vbldpbGxEaXNtaXNzKCkudGhlbigoKSA9PiB7XG4gICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuc3dpcGVTdGFydCwgdHJ1ZSk7XG4gICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHRoaXMuc3dpcGVNb3ZlLCB0cnVlKTtcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuc3dpcGVNb3ZlLCB0cnVlKTtcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsIHRoaXMuc3dpcGVTdGFydCwgdHJ1ZSk7XG4gICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIHRoaXMuc3dpcGVNb3ZlLCB0cnVlKTtcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCB0aGlzLnN3aXBlTW92ZSwgdHJ1ZSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gIHN3aXBlU3RhcnQoZXZlbnQ6IGFueSkge1xuICAgIGNvbnN0IHsgcGFnZVgsIHBhZ2VZIH0gPVxuICAgICAgZXZlbnQudHlwZSA9PT0gJ3RvdWNoc3RhcnQnICYmIGV2ZW50Py5jaGFuZ2VkVG91Y2hlc1xuICAgICAgICA/IGV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdXG4gICAgICAgIDogZXZlbnQ7XG5cbiAgICB0aGlzLnN3aXBlU3RhdGUgPSB7XG4gICAgICAuLi50aGlzLnN3aXBlU3RhdGUsXG4gICAgICBwaGFzZTogJ3N0YXJ0JyxcbiAgICAgIGRpcmVjdGlvbjogJ25vbmUnLFxuICAgICAgZGlzdGFuY2U6IDAsXG4gICAgICBzdGFydFg6IHBhZ2VYLFxuICAgICAgc3RhcnRZOiBwYWdlWSxcbiAgICAgIHN0YXJ0VGltZTogbmV3IERhdGUoKS5nZXRUaW1lKCksXG4gICAgfTtcbiAgfVxuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gIHN3aXBlTW92ZShldmVudDogYW55KSB7XG4gICAgY29uc3QgeyBwYWdlWCwgcGFnZVkgfSA9XG4gICAgICBldmVudC50eXBlID09PSAndG91Y2htb3ZlJyAmJiBldmVudD8uY2hhbmdlZFRvdWNoZXNcbiAgICAgICAgPyBldmVudC5jaGFuZ2VkVG91Y2hlc1swXVxuICAgICAgICA6IGV2ZW50O1xuICAgIC8vIGdldCBob3Jpem9udGFsIGRpc3QgdHJhdmVsZWQgYnkgZmluZ2VyIHdoaWxlIGluIGNvbnRhY3Qgd2l0aCBzdXJmYWNlXG4gICAgY29uc3QgZGlzdGFuY2VYID0gcGFnZVggLSB0aGlzLnN3aXBlU3RhdGUuc3RhcnRYO1xuICAgIC8vIGdldCB2ZXJ0aWNhbCBkaXN0IHRyYXZlbGVkIGJ5IGZpbmdlciB3aGlsZSBpbiBjb250YWN0IHdpdGggc3VyZmFjZVxuICAgIGNvbnN0IGRpc3RhbmNlWSA9IHBhZ2VZIC0gdGhpcy5zd2lwZVN0YXRlLnN0YXJ0WTtcbiAgICBsZXQgZGlyZWN0aW9uO1xuICAgIGxldCBkaXN0YW5jZTtcblxuICAgIGlmIChNYXRoLmFicyhkaXN0YW5jZVgpID4gTWF0aC5hYnMoZGlzdGFuY2VZKSkge1xuICAgICAgLy8gaWYgZGlzdGFuY2UgdHJhdmVsZWQgaG9yaXpvbnRhbGx5IGlzIGdyZWF0ZXIgdGhhbiB2ZXJ0aWNhbGx5LCBjb25zaWRlciB0aGlzIGEgaG9yaXpvbnRhbCBzd2lwZVxuICAgICAgZGlyZWN0aW9uID0gZGlzdGFuY2VYIDwgMCA/ICdsZWZ0JyA6ICdyaWdodCc7XG4gICAgICBkaXN0YW5jZSA9IGRpc3RhbmNlWDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gZWxzZSBjb25zaWRlciB0aGlzIGEgdmVydGljYWwgc3dpcGVcbiAgICAgIGRpcmVjdGlvbiA9IGRpc3RhbmNlWSA8IDAgPyAndXAnIDogJ2Rvd24nO1xuICAgICAgZGlzdGFuY2UgPSBkaXN0YW5jZVk7XG4gICAgfVxuICAgIHRoaXMuc3dpcGVTdGF0ZSA9IHtcbiAgICAgIC4uLnRoaXMuc3dpcGVTdGF0ZSxcbiAgICAgIHBoYXNlOiAnbW92ZScsXG4gICAgICBkaXJlY3Rpb24sXG4gICAgICBkaXN0YW5jZSxcbiAgICAgIGRpc3RhbmNlWCxcbiAgICAgIGRpc3RhbmNlWSxcbiAgICB9O1xuICAgIGlmIChldmVudC5jYW5jZWxhYmxlKSB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cbiAgfVxuXG4gIHN3aXBlRW5kKCkge1xuICAgIGlmICh0aGlzLnN3aXBlU3RhdGUucGhhc2UgPT09ICdub25lJykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB7XG4gICAgICBhbGxvd2VkVGltZSxcbiAgICAgIGRpcmVjdGlvbixcbiAgICAgIHJlc3RyYWludCxcbiAgICAgIHN0YXJ0VGltZSxcbiAgICAgIHRocmVzaG9sZCxcbiAgICAgIGRpc3RhbmNlWCxcbiAgICAgIGRpc3RhbmNlWSxcbiAgICB9ID0gdGhpcy5zd2lwZVN0YXRlO1xuICAgIGxldCBzd2lwZVR5cGUgPSBudWxsO1xuXG4gICAgY29uc3QgZWxhcHNlZFRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0VGltZTsgLy8gZ2V0IHRpbWUgZWxhcHNlZFxuICAgIGlmIChlbGFwc2VkVGltZSA8PSBhbGxvd2VkVGltZSkge1xuICAgICAgLy8gZmlyc3QgY29uZGl0aW9uIGZvciBhIHN3aXBlIG1ldFxuICAgICAgaWYgKFxuICAgICAgICBNYXRoLmFicyhkaXN0YW5jZVgpID49IHRocmVzaG9sZCAmJlxuICAgICAgICBNYXRoLmFicyhkaXN0YW5jZVkpIDw9IHJlc3RyYWludFxuICAgICAgKSB7XG4gICAgICAgIC8vIDJuZCBjb25kaXRpb24gZm9yIGhvcml6b250YWwgc3dpcGUgbWV0XG4gICAgICAgIHN3aXBlVHlwZSA9IGRpcmVjdGlvbjsgLy8gc2V0IHN3aXBlVHlwZSB0byBlaXRoZXIgXCJsZWZ0XCIgb3IgXCJyaWdodFwiXG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBNYXRoLmFicyhkaXN0YW5jZVkpID49IHRocmVzaG9sZCAmJlxuICAgICAgICBNYXRoLmFicyhkaXN0YW5jZVgpIDw9IHJlc3RyYWludFxuICAgICAgKSB7XG4gICAgICAgIC8vIDJuZCBjb25kaXRpb24gZm9yIHZlcnRpY2FsIHN3aXBlIG1ldFxuICAgICAgICBzd2lwZVR5cGUgPSBkaXJlY3Rpb247IC8vIHNldCBzd2lwZVR5cGUgdG8gZWl0aGVyIFwidG9wXCIgb3IgXCJkb3duXCJcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnN3aXBlU3RhdGUgPSB7XG4gICAgICAuLi50aGlzLnN3aXBlU3RhdGUsXG4gICAgICBwaGFzZTogJ2VuZCcsXG4gICAgICBzd2lwZVR5cGU6IHN3aXBlVHlwZSA/PyAnJyxcbiAgICB9O1xuXG4gICAgaWYgKHN3aXBlVHlwZSA9PT0gJ2Rvd24nKSB7XG4gICAgICByZXR1cm4gdGhpcy5jbG9zZU1vZGFsKCk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2VNb2RhbCgpIHtcbiAgICB0aGlzLm1vZGFsQ29udHJvbGxlci5kaXNtaXNzKCk7XG4gIH1cbn1cbiIsIjxpb24taGVhZGVyIFtuZ0NsYXNzXT1cInsgJ25vLXRpdGxlJzogdGl0bGUgJiYgdGl0bGUubGVuZ3RoIDw9IDAgfVwiPlxuICA8aW9uLXRvb2xiYXI+XG4gICAgPGlvbi1idXR0b25zIHNsb3Q9XCJwcmltYXJ5XCI+XG4gICAgICA8aW9uLWJ1dHRvbiBkYXRhLWN5PVwiY2xvc2VNb2RhbFwiIChjbGljayk9XCJjbG9zZU1vZGFsKClcIj5cbiAgICAgICAgPGlvbi1pY29uIHNsb3Q9XCJpY29uLW9ubHlcIiBuYW1lPVwiY2xvc2VcIj48L2lvbi1pY29uPlxuICAgICAgPC9pb24tYnV0dG9uPlxuICAgIDwvaW9uLWJ1dHRvbnM+XG4gICAgPGlvbi10aXRsZSBbc2l6ZV09XCJ0aXRsZVNpemVcIj57eyB0aXRsZSB9fTwvaW9uLXRpdGxlPlxuICA8L2lvbi10b29sYmFyPlxuPC9pb24taGVhZGVyPlxuXG48aW9uLWNvbnRlbnQgW2ZvcmNlT3ZlcnNjcm9sbF09XCJmYWxzZVwiPlxuICA8c3dpcGVyLWNvbnRhaW5lciBbb3B0aW9uc109XCJvcHRpb25zXCIgY2VudGVyZWRTbGlkZXM9XCJ0cnVlXCIgcGFzc2l2ZUxpc3RlbmVycz1cImZhbHNlXCIgem9vbT1cInRydWVcIiAjc3dpcGVyPlxuICAgIDxzd2lwZXItc2xpZGU+XG4gICAgICA8ZGl2IGNsYXNzPVwic3dpcGVyLXpvb20tY29udGFpbmVyXCI+XG4gICAgICAgIDxpbWcgW2FsdF09XCJ0aGlzLmFsdFwiIFtzcmNdPVwidGhpcy5zcmNcIi8+XG4gICAgICA8L2Rpdj5cbiAgICA8L3N3aXBlci1zbGlkZT5cbiAgPC9zd2lwZXItY29udGFpbmVyPlxuPC9pb24tY29udGVudD5cblxuPGlvbi1mb290ZXIgW25nQ2xhc3NdPVwieyAnbm8tdGV4dCc6IHRleHQgJiYgdGV4dC5sZW5ndGggPD0gMCB9XCI+XG4gIDxpb24tdG9vbGJhciBjbGFzcz1cImlvbi10ZXh0LWNlbnRlclwiPlxuICAgIDxpb24tdGV4dD57eyB0ZXh0IH19PC9pb24tdGV4dD5cbiAgPC9pb24tdG9vbGJhcj5cbjwvaW9uLWZvb3Rlcj5cbiJdfQ==