@herdwatch/ngx-ionic-image-viewer
Version:
The angular workspace to develop the ngx-ionic-image-viewer component
232 lines • 35.8 kB
JavaScript
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==