ng-magnizoom
Version:
Angular image magnifier (based on HTML canvas)
290 lines • 39.5 kB
JavaScript
import { Component, Input, Output, ViewChild, EventEmitter } from '@angular/core';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class NgMagnizoomComponent {
get canvasWidth() { return this.image && this.image.width || 800; }
get canvasHeight() { return this.image && this.image.height || 600; }
constructor() {
this.zoomMode = 'COVER';
this.minZoomFactor = 1.2;
this.maxZoomFactor = 3;
this.zoomFactor = 2;
this.zoomFactorChange = new EventEmitter();
this.lensSizeUnit = 'NORMALIZED';
this.lensSize = { width: 0.5, height: 0.5 };
this.zoomCenterUnit = 'NORMALIZED';
this.zoomCenterChange = new EventEmitter();
this.updateOnMouseEvents = true;
this.imageReady = false;
}
ngOnInit() {
this.initContext();
this.loadImage(this.imageSrc);
}
ngOnChanges(changes) {
if (!changes) {
return;
}
if (changes.lensSize || changes.zoomCenter || changes.zoomFactor) {
this.updateParameters();
}
if (changes.imageSrc && !changes.imageSrc.firstChange) {
this.loadImage(changes.imageSrc.currentValue);
}
}
initContext() {
this.canvas = this.mainCanvasRef.nativeElement;
this.context = this.canvas.getContext('2d');
}
loadImage(src) {
this.image = new Image();
this.image.onload = () => {
this.imageReady = true;
this.updateParameters();
setTimeout(() => this.update());
};
this.image.src = src;
}
updateParameters() {
if (this.lensSizeUnit === 'NORMALIZED') {
if (this.imageReady) {
this._lensSize = {
width: this.lensSize.width * this.image.width,
height: this.lensSize.height * this.image.height
};
}
}
else {
this._lensSize = {
width: this.lensSize.width,
height: this.lensSize.height
};
}
if (!this.zoomCenter) {
this._centerPosition = undefined;
}
else if (this.zoomCenterUnit === 'NORMALIZED') {
if (this.imageReady) {
this._centerPosition = {
x: this.zoomCenter.x * this.image.width,
y: this.zoomCenter.y * this.image.height
};
}
}
else {
this._centerPosition = {
x: this.zoomCenter.x,
y: this.zoomCenter.y
};
}
this._zoomFactor = this.zoomFactor;
if (this._zoomFactor > this.maxZoomFactor) {
this._zoomFactor = this.maxZoomFactor;
}
if (this._zoomFactor < this.minZoomFactor) {
this._zoomFactor = this.minZoomFactor;
}
this.update();
}
update() {
this.render();
let currUnitCenter, needUpdate = false;
if (!this._centerPosition) {
currUnitCenter = undefined;
needUpdate = currUnitCenter !== this.zoomCenter;
}
else if (this.zoomCenterUnit === 'NORMALIZED') {
if (this.imageReady) {
currUnitCenter = {
x: this._centerPosition.x / this.image.width,
y: this._centerPosition.y / this.image.height
};
needUpdate = currUnitCenter.x !== this.zoomCenter?.x || currUnitCenter.y !== this.zoomCenter?.y;
}
}
else {
currUnitCenter = {
x: this._centerPosition.x,
y: this._centerPosition.y
};
needUpdate = currUnitCenter.x !== this.zoomCenter?.x || currUnitCenter.y !== this.zoomCenter?.y;
}
if (needUpdate) {
this.zoomCenterChange.emit(currUnitCenter);
}
}
render() {
if (!this.context || !this.imageReady) {
return;
}
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight); // clear canvas
this.context.lineWidth = 1; // border width
this.context.drawImage(this.image, 0, 0); // bg image
if (this._centerPosition) {
switch (this.zoomMode) {
case 'LENS':
this.renderLensMode();
break;
case 'COVER':
this.renderCoverMode();
break;
}
}
}
renderLensMode() {
this.context.lineWidth = 5; // border width
const zoomRect = this.getZoomRect();
this.context.fillRect(zoomRect.x, zoomRect.y, zoomRect.w, zoomRect.h); // bg (clear)
const clippingRect = this.getClippingRect();
// zoom image
this.context.drawImage(this.image, clippingRect.x, clippingRect.y, clippingRect.w, clippingRect.h, zoomRect.x, zoomRect.y, zoomRect.w, zoomRect.h);
this.context.strokeRect(zoomRect.x, zoomRect.y, zoomRect.w, zoomRect.h); // border
}
renderCoverMode() {
const covertRect = this.getCoverRect();
this.context.drawImage(this.image, covertRect.x, covertRect.y, covertRect.w, covertRect.h, 0, 0, this.canvasWidth, this.canvasHeight); // cover image
}
getZoomRect() {
const w = this._lensSize.width;
const h = this._lensSize.height;
const x = this._centerPosition.x - (w / 2);
const y = this._centerPosition.y - (h / 2);
return this.clampRect(x, y, w, h);
}
getClippingRect() {
const w = this._lensSize.width / this._zoomFactor;
const h = this._lensSize.height / this._zoomFactor;
const x = this._centerPosition.x - (w / 2);
const y = this._centerPosition.y - (h / 2);
return this.clampRect(x, y, w, h);
}
getCoverRect() {
const w = this.canvasWidth / this._zoomFactor;
const h = this.canvasHeight / this._zoomFactor;
// const x = this.mousePosition.x - (w / 2);
// const y = this.mousePosition.y - (h / 2);
const x = this._centerPosition.x - this._centerPosition.x / this._zoomFactor;
const y = this._centerPosition.y - this._centerPosition.y / this._zoomFactor;
return this.clampRect(x, y, w, h);
}
clampRect(x, y, w, h) {
if (x <= 0) {
x = 0;
}
if (x + w >= this.canvasWidth) {
x = this.canvasWidth - w;
}
if (y < 0) {
y = 0;
}
if (y + h >= this.canvasHeight) {
y = this.canvasHeight - h;
}
return { x, y, w, h };
}
calculateMousePosition(clientX, clientY) {
const boundingRect = this.canvas.getBoundingClientRect();
const boundingRectX = (clientX - boundingRect.left);
const boundingRectY = (clientY - boundingRect.top);
let elementX = boundingRectX, elementY = boundingRectY;
let elementWidth = boundingRect.width, elementHeight = boundingRect.height;
const computedStyle = window.getComputedStyle(this.canvas, null);
const domMatrix = new DOMMatrix(computedStyle.transform);
if (!domMatrix.isIdentity) {
const { a, b } = domMatrix;
const transformRot = Math.atan2(b, a);
const transformScale = Math.round(Math.sqrt(a * a + b * b) * 100) / 100;
if (transformRot) {
const boundingRectCenterX = boundingRect.width / 2;
const boundingRectCenterY = boundingRect.height / 2;
const dx = (boundingRectX - boundingRectCenterX);
const dy = (boundingRectY - boundingRectCenterY);
const d = Math.sqrt(dx * dx + dy * dy);
const r = Math.atan2(dy, dx);
elementWidth = this.canvas.clientWidth * transformScale;
elementHeight = this.canvas.clientHeight * transformScale;
elementX = (elementWidth / 2) + (d * Math.cos(r - transformRot));
elementY = (elementHeight / 2) + (d * Math.sin(r - transformRot));
}
}
const viewToModelX = this.canvasWidth / elementWidth;
const viewToModelY = this.canvasHeight / elementHeight;
const x = elementX * viewToModelX;
const y = elementY * viewToModelY;
this._centerPosition = { x, y };
}
onMouseLeave(event) {
if (!this.updateOnMouseEvents) {
return;
}
this._centerPosition = null;
this.update();
}
onMouseEnterOrMove(event) {
if (!this.updateOnMouseEvents) {
return;
}
this.calculateMousePosition(event.clientX, event.clientY);
this.update();
}
onMouseScroll(event) {
if (!this.updateOnMouseEvents) {
return;
}
let newZoomFactor = this._zoomFactor;
newZoomFactor -= event.deltaY / 1000;
if (newZoomFactor < this.minZoomFactor) {
newZoomFactor = this.minZoomFactor;
}
if (newZoomFactor > this.maxZoomFactor) {
newZoomFactor = this.maxZoomFactor;
}
if (this._zoomFactor !== newZoomFactor) {
this._zoomFactor = newZoomFactor;
if (this.zoomFactor !== this._zoomFactor) {
this.zoomFactorChange.emit(this._zoomFactor);
}
this.update();
}
event.preventDefault();
event.stopPropagation();
}
}
/** @nocollapse */ NgMagnizoomComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgMagnizoomComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ NgMagnizoomComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgMagnizoomComponent, selector: "ng-magnizoom", inputs: { imageSrc: "imageSrc", zoomMode: "zoomMode", minZoomFactor: "minZoomFactor", maxZoomFactor: "maxZoomFactor", zoomFactor: "zoomFactor", lensSizeUnit: "lensSizeUnit", lensSize: "lensSize", zoomCenterUnit: "zoomCenterUnit", zoomCenter: "zoomCenter", updateOnMouseEvents: "updateOnMouseEvents", imageStyle: "imageStyle", imageClass: "imageClass" }, outputs: { zoomFactorChange: "zoomFactorChange", zoomCenterChange: "zoomCenterChange" }, viewQueries: [{ propertyName: "mainCanvasRef", first: true, predicate: ["mainCanvas"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<canvas #mainCanvas\n class=\"main-canvas\"\n [ngClass]=\"imageClass\"\n [ngStyle]=\"imageStyle\"\n [width]=\"canvasWidth\"\n [height]=\"canvasHeight\"\n (mouseleave)=\"onMouseLeave($event)\"\n (mouseenter)=\"onMouseEnterOrMove($event)\"\n (mousemove)=\"onMouseEnterOrMove($event)\"\n (wheel)=\"onMouseScroll($event)\">\n</canvas>\n", styles: [""], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgMagnizoomComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-magnizoom', template: "<canvas #mainCanvas\n class=\"main-canvas\"\n [ngClass]=\"imageClass\"\n [ngStyle]=\"imageStyle\"\n [width]=\"canvasWidth\"\n [height]=\"canvasHeight\"\n (mouseleave)=\"onMouseLeave($event)\"\n (mouseenter)=\"onMouseEnterOrMove($event)\"\n (mousemove)=\"onMouseEnterOrMove($event)\"\n (wheel)=\"onMouseScroll($event)\">\n</canvas>\n" }]
}], ctorParameters: function () { return []; }, propDecorators: { imageSrc: [{
type: Input
}], zoomMode: [{
type: Input
}], minZoomFactor: [{
type: Input
}], maxZoomFactor: [{
type: Input
}], zoomFactor: [{
type: Input
}], zoomFactorChange: [{
type: Output
}], lensSizeUnit: [{
type: Input
}], lensSize: [{
type: Input
}], zoomCenterUnit: [{
type: Input
}], zoomCenter: [{
type: Input
}], zoomCenterChange: [{
type: Output
}], updateOnMouseEvents: [{
type: Input
}], imageStyle: [{
type: Input
}], imageClass: [{
type: Input
}], mainCanvasRef: [{
type: ViewChild,
args: ['mainCanvas', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFnbml6b29tLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLW1hZ25pem9vbS9zcmMvbGliL21hZ25pem9vbS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1tYWduaXpvb20vc3JjL2xpYi9tYWduaXpvb20uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFNBQVMsRUFBb0MsS0FBSyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7QUFVcEgsTUFBTSxPQUFPLG9CQUFvQjtJQW1DL0IsSUFBSSxXQUFXLEtBQUssT0FBTyxJQUFJLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbkUsSUFBSSxZQUFZLEtBQUssT0FBTyxJQUFJLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFckU7UUFuQ1MsYUFBUSxHQUFxQixPQUFPLENBQUM7UUFDckMsa0JBQWEsR0FBRyxHQUFHLENBQUM7UUFDcEIsa0JBQWEsR0FBRyxDQUFDLENBQUM7UUFFbEIsZUFBVSxHQUFHLENBQUMsQ0FBQztRQUNkLHFCQUFnQixHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFFL0MsaUJBQVksR0FBMkIsWUFBWSxDQUFDO1FBQ3BELGFBQVEsR0FBVyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDO1FBRS9DLG1CQUFjLEdBQTJCLFlBQVksQ0FBQztRQUVyRCxxQkFBZ0IsR0FBRyxJQUFJLFlBQVksRUFBdUIsQ0FBQztRQUc1RCx3QkFBbUIsR0FBRyxJQUFJLENBQUM7UUFnQnBDLGVBQVUsR0FBRyxLQUFLLENBQUM7SUFJ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Z0I7c0JBQXpCLE1BQU07Z0JBRUUsWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDSSxnQkFBZ0I7c0JBQXpCLE1BQU07Z0JBR0UsbUJBQW1CO3NCQUEzQixLQUFLO2dCQUdHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFFcUMsYUFBYTtzQkFBdkQsU0FBUzt1QkFBQyxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBFbGVtZW50UmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgT25DaGFuZ2VzLCBTaW1wbGVDaGFuZ2VzLCBJbnB1dCwgT3V0cHV0LCBWaWV3Q2hpbGQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbnRlcmZhY2UgU2l6ZTJEIHsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXI7IH1cbnR5cGUgUG9pbnQyRCA9IHsgeDogbnVtYmVyLCB5OiBudW1iZXIgfSB8IG51bGw7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25nLW1hZ25pem9vbScsXG4gIHRlbXBsYXRlVXJsOiAnLi9tYWduaXpvb20uY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9tYWduaXpvb20uY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBOZ01hZ25pem9vbUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcblxuICBASW5wdXQoKSBpbWFnZVNyYzogc3RyaW5nO1xuICBASW5wdXQoKSB6b29tTW9kZTogJ0xFTlMnIHwgJ0NPVkVSJyA9ICdDT1ZFUic7XG4gIEBJbnB1dCgpIG1pblpvb21GYWN0b3IgPSAxLjI7XG4gIEBJbnB1dCgpIG1heFpvb21GYWN0b3IgPSAzO1xuXG4gIEBJbnB1dCgpIHpvb21GYWN0b3IgPSAyO1xuICBAT3V0cHV0KCkgem9vbUZhY3RvckNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gIEBJbnB1dCgpIGxlbnNTaXplVW5pdDogJ05PUk1BTElaRUQnIHwgJ1BJWEVMJyA9ICdOT1JNQUxJWkVEJztcbiAgQElucHV0KCkgbGVuc1NpemU6IFNpemUyRCA9IHsgd2lkdGg6IDAuNSwgaGVpZ2h0OiAwLjUgfTtcblxuICBASW5wdXQoKSB6b29tQ2VudGVyVW5pdDogJ05PUk1BTElaRUQnIHwgJ1BJWEVMJyA9ICdOT1JNQUxJWkVEJztcbiAgQElucHV0KCkgem9vbUNlbnRlcj86IFBvaW50MkQ7XG4gIEBPdXRwdXQoKSB6b29tQ2VudGVyQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxQb2ludDJEIHwgdW5kZWZpbmVkPigpO1xuXG5cbiAgQElucHV0KCkgdXBkYXRlT25Nb3VzZUV2ZW50cyA9IHRydWU7XG5cblxuICBASW5wdXQoKSBpbWFnZVN0eWxlOiB7IFt4OiBzdHJpbmddOiBhbnk7IH07XG4gIEBJbnB1dCgpIGltYWdlQ2xhc3M6IGFueTtcblxuICBAVmlld0NoaWxkKCdtYWluQ2FudmFzJywgeyBzdGF0aWM6IHRydWUgfSkgbWFpbkNhbnZhc1JlZjogRWxlbWVudFJlZjtcblxuICBjYW52YXM6IEhUTUxDYW52YXNFbGVtZW50O1xuICBjb250ZXh0OiBDYW52YXNSZW5kZXJpbmdDb250ZXh0MkQ7XG4gIGltYWdlOiBIVE1MSW1hZ2VFbGVtZW50O1xuXG4gIF9jZW50ZXJQb3NpdGlvbjogUG9pbnQyRDtcbiAgX2xlbnNTaXplPzogU2l6ZTJEO1xuICBfem9vbUZhY3RvcjogbnVtYmVyO1xuXG4gIGltYWdlUmVhZHkgPSBmYWxzZTtcbiAgZ2V0IGNhbnZhc1dpZHRoKCkgeyByZXR1cm4gdGhpcy5pbWFnZSAmJiB0aGlzLmltYWdlLndpZHRoIHx8IDgwMDsgfVxuICBnZXQgY2FudmFzSGVpZ2h0KCkgeyByZXR1cm4gdGhpcy5pbWFnZSAmJiB0aGlzLmltYWdlLmhlaWdodCB8fCA2MDA7IH1cblxuICBjb25zdHJ1Y3RvcigpIHsgfVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuaW5pdENvbnRleHQoKTtcbiAgICB0aGlzLmxvYWRJbWFnZSh0aGlzLmltYWdlU3JjKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpIHtcbiAgICBpZiAoIWNoYW5nZXMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXMubGVuc1NpemUgfHwgY2hhbmdlcy56b29tQ2VudGVyIHx8IGNoYW5nZXMuem9vbUZhY3Rvcikge1xuICAgICAgdGhpcy51cGRhdGVQYXJhbWV0ZXJzKCk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzLmltYWdlU3JjICYmICFjaGFuZ2VzLmltYWdlU3JjLmZpcnN0Q2hhbmdlKSB7XG4gICAgICB0aGlzLmxvYWRJbWFnZShjaGFuZ2VzLmltYWdlU3JjLmN1cnJlbnRWYWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgaW5pdENvbnRleHQoKSB7XG4gICAgdGhpcy5jYW52YXMgPSAodGhpcy5tYWluQ2FudmFzUmVmLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTENhbnZhc0VsZW1lbnQpO1xuICAgIHRoaXMuY29udGV4dCA9IHRoaXMuY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gIH1cblxuICBsb2FkSW1hZ2Uoc3JjOiBzdHJpbmcpIHtcbiAgICB0aGlzLmltYWdlID0gbmV3IEltYWdlKCk7XG4gICAgdGhpcy5pbWFnZS5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICB0aGlzLmltYWdlUmVhZHkgPSB0cnVlO1xuICAgICAgdGhpcy51cGRhdGVQYXJhbWV0ZXJzKCk7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMudXBkYXRlKCkpO1xuICAgIH07XG4gICAgdGhpcy5pbWFnZS5zcmMgPSBzcmM7XG4gIH1cblxuICB1cGRhdGVQYXJhbWV0ZXJzKCkge1xuICAgIGlmICh0aGlzLmxlbnNTaXplVW5pdCA9PT0gJ05PUk1BTElaRUQnKSB7XG4gICAgICBpZiAodGhpcy5pbWFnZVJlYWR5KSB7XG4gICAgICAgIHRoaXMuX2xlbnNTaXplID0ge1xuICAgICAgICAgIHdpZHRoOiB0aGlzLmxlbnNTaXplLndpZHRoICogdGhpcy5pbWFnZS53aWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHRoaXMubGVuc1NpemUuaGVpZ2h0ICogdGhpcy5pbWFnZS5oZWlnaHRcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fbGVuc1NpemUgPSB7XG4gICAgICAgIHdpZHRoOiB0aGlzLmxlbnNTaXplLndpZHRoLFxuICAgICAgICBoZWlnaHQ6IHRoaXMubGVuc1NpemUuaGVpZ2h0XG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICghdGhpcy56b29tQ2VudGVyKSB7XG4gICAgICB0aGlzLl9jZW50ZXJQb3NpdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB9IGVsc2UgaWYgKHRoaXMuem9vbUNlbnRlclVuaXQgPT09ICdOT1JNQUxJWkVEJyl7XG4gICAgICBpZiAodGhpcy5pbWFnZVJlYWR5KSB7XG4gICAgICAgIHRoaXMuX2NlbnRlclBvc2l0aW9uID0ge1xuICAgICAgICAgIHg6IHRoaXMuem9vbUNlbnRlci54ICogdGhpcy5pbWFnZS53aWR0aCxcbiAgICAgICAgICB5OiB0aGlzLnpvb21DZW50ZXIueSAqIHRoaXMuaW1hZ2UuaGVpZ2h0XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX2NlbnRlclBvc2l0aW9uID0ge1xuICAgICAgICB4OiB0aGlzLnpvb21DZW50ZXIueCxcbiAgICAgICAgeTogdGhpcy56b29tQ2VudGVyLnlcbiAgICAgIH07XG4gICAgfVxuXG4gICAgdGhpcy5fem9vbUZhY3RvciA9IHRoaXMuem9vbUZhY3RvcjtcbiAgICBpZiAodGhpcy5fem9vbUZhY3RvciA+IHRoaXMubWF4Wm9vbUZhY3Rvcikge1xuICAgICAgdGhpcy5fem9vbUZhY3RvciA9IHRoaXMubWF4Wm9vbUZhY3RvcjtcbiAgICB9XG4gICAgaWYgKHRoaXMuX3pvb21GYWN0b3IgPCB0aGlzLm1pblpvb21GYWN0b3IpIHtcbiAgICAgIHRoaXMuX3pvb21GYWN0b3IgPSB0aGlzLm1pblpvb21GYWN0b3I7XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGUoKTtcbiAgfVxuXG4gIHVwZGF0ZSgpIHtcbiAgICB0aGlzLnJlbmRlcigpO1xuICAgIGxldCBjdXJyVW5pdENlbnRlcjogeyB4OiBudW1iZXIsIHk6IG51bWJlciB9IHwgdW5kZWZpbmVkLCBuZWVkVXBkYXRlID0gZmFsc2U7XG4gICAgaWYgKCF0aGlzLl9jZW50ZXJQb3NpdGlvbikge1xuICAgICAgY3VyclVuaXRDZW50ZXIgPSB1bmRlZmluZWQ7XG4gICAgICBuZWVkVXBkYXRlID0gY3VyclVuaXRDZW50ZXIgIT09IHRoaXMuem9vbUNlbnRlcjtcbiAgICB9IGVsc2UgaWYgKHRoaXMuem9vbUNlbnRlclVuaXQgPT09ICdOT1JNQUxJWkVEJykge1xuICAgICAgaWYgKHRoaXMuaW1hZ2VSZWFkeSkge1xuICAgICAgICBjdXJyVW5pdENlbnRlciA9IHtcbiAgICAgICAgICB4OiB0aGlzLl9jZW50ZXJQb3NpdGlvbi54IC8gdGhpcy5pbWFnZS53aWR0aCxcbiAgICAgICAgICB5OiB0aGlzLl9jZW50ZXJQb3NpdGlvbi55IC8gdGhpcy5pbWFnZS5oZWlnaHRcbiAgICAgICAgfTtcbiAgICAgICAgbmVlZFVwZGF0ZSA9IGN1cnJVbml0Q2VudGVyLnggIT09IHRoaXMuem9vbUNlbnRlcj8ueCB8fCBjdXJyVW5pdENlbnRlci55ICE9PSB0aGlzLnpvb21DZW50ZXI/Lnk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1cnJVbml0Q2VudGVyID0ge1xuICAgICAgICB4OiB0aGlzLl9jZW50ZXJQb3NpdGlvbi54LFxuICAgICAgICB5OiB0aGlzLl9jZW50ZXJQb3NpdGlvbi55XG4gICAgICB9O1xuICAgICAgbmVlZFVwZGF0ZSA9IGN1cnJVbml0Q2VudGVyLnggIT09IHRoaXMuem9vbUNlbnRlcj8ueCB8fCBjdXJyVW5pdENlbnRlci55ICE9PSB0aGlzLnpvb21DZW50ZXI/Lnk7XG4gICAgfVxuICAgIGlmIChuZWVkVXBkYXRlKSB7XG4gICAgICB0aGlzLnpvb21DZW50ZXJDaGFuZ2UuZW1pdChjdXJyVW5pdENlbnRlcik7XG4gICAgfVxuICB9XG5cbiAgcmVuZGVyKCkge1xuICAgIGlmICghdGhpcy5jb250ZXh0IHx8ICF0aGlzLmltYWdlUmVhZHkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmNvbnRleHQuY2xlYXJSZWN0KDAsIDAsIHRoaXMuY2FudmFzV2lkdGgsIHRoaXMuY2FudmFzSGVpZ2h0KTsgLy8gY2xlYXIgY2FudmFzXG4gICAgdGhpcy5jb250ZXh0LmxpbmVXaWR0aCA9IDE7IC8vIGJvcmRlciB3aWR0aFxuICAgIHRoaXMuY29udGV4dC5kcmF3SW1hZ2UodGhpcy5pbWFnZSwgMCwgMCk7IC8vIGJnIGltYWdlXG5cbiAgICBpZiAodGhpcy5fY2VudGVyUG9zaXRpb24pIHtcbiAgICAgIHN3aXRjaCAodGhpcy56b29tTW9kZSkge1xuICAgICAgICBjYXNlICdMRU5TJzogdGhpcy5yZW5kZXJMZW5zTW9kZSgpOyBicmVhaztcbiAgICAgICAgY2FzZSAnQ09WRVInOiB0aGlzLnJlbmRlckNvdmVyTW9kZSgpOyBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZW5kZXJMZW5zTW9kZSgpIHtcbiAgICB0aGlzLmNvbnRleHQubGluZVdpZHRoID0gNTsgLy8gYm9yZGVyIHdpZHRoXG4gICAgY29uc3Qgem9vbVJlY3QgPSB0aGlzLmdldFpvb21SZWN0KCk7XG4gICAgdGhpcy5jb250ZXh0LmZpbGxSZWN0KHpvb21SZWN0LngsIHpvb21SZWN0LnksIHpvb21SZWN0LncsIHpvb21SZWN0LmgpOyAvLyBiZyAoY2xlYXIpXG4gICAgY29uc3QgY2xpcHBpbmdSZWN0ID0gdGhpcy5nZXRDbGlwcGluZ1JlY3QoKTtcbiAgICAvLyB6b29tIGltYWdlXG4gICAgdGhpcy5jb250ZXh0LmRyYXdJbWFnZShcbiAgICAgIHRoaXMuaW1hZ2UsXG4gICAgICBjbGlwcGluZ1JlY3QueCwgY2xpcHBpbmdSZWN0LnksIGNsaXBwaW5nUmVjdC53LCBjbGlwcGluZ1JlY3QuaCxcbiAgICAgIHpvb21SZWN0LngsIHpvb21SZWN0LnksIHpvb21SZWN0LncsIHpvb21SZWN0LmhcbiAgICApO1xuICAgIHRoaXMuY29udGV4dC5zdHJva2VSZWN0KHpvb21SZWN0LngsIHpvb21SZWN0LnksIHpvb21SZWN0LncsIHpvb21SZWN0LmgpOyAvLyBib3JkZXJcbiAgfVxuXG4gIHJlbmRlckNvdmVyTW9kZSgpIHtcbiAgICBjb25zdCBjb3ZlcnRSZWN0ID0gdGhpcy5nZXRDb3ZlclJlY3QoKTtcbiAgICB0aGlzLmNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgdGhpcy5pbWFnZSxcbiAgICAgIGNvdmVydFJlY3QueCwgY292ZXJ0UmVjdC55LCBjb3ZlcnRSZWN0LncsIGNvdmVydFJlY3QuaCxcbiAgICAgIDAsIDAsIHRoaXMuY2FudmFzV2lkdGgsIHRoaXMuY2FudmFzSGVpZ2h0XG4gICAgKTsgLy8gY292ZXIgaW1hZ2VcbiAgfVxuXG4gIGdldFpvb21SZWN0KCkge1xuICAgIGNvbnN0IHcgPSB0aGlzLl9sZW5zU2l6ZS53aWR0aDtcbiAgICBjb25zdCBoID0gdGhpcy5fbGVuc1NpemUuaGVpZ2h0O1xuICAgIGNvbnN0IHggPSB0aGlzLl9jZW50ZXJQb3NpdGlvbi54IC0gKHcgLyAyKTtcbiAgICBjb25zdCB5ID0gdGhpcy5fY2VudGVyUG9zaXRpb24ueSAtIChoIC8gMik7XG4gICAgcmV0dXJuIHRoaXMuY2xhbXBSZWN0KHgsIHksIHcsIGgpO1xuICB9XG5cbiAgZ2V0Q2xpcHBpbmdSZWN0KCkge1xuICAgIGNvbnN0IHcgPSB0aGlzLl9sZW5zU2l6ZS53aWR0aCAvIHRoaXMuX3pvb21GYWN0b3I7XG4gICAgY29uc3QgaCA9IHRoaXMuX2xlbnNTaXplLmhlaWdodCAvIHRoaXMuX3pvb21GYWN0b3I7XG4gICAgY29uc3QgeCA9IHRoaXMuX2NlbnRlclBvc2l0aW9uLnggLSAodyAvIDIpO1xuICAgIGNvbnN0IHkgPSB0aGlzLl9jZW50ZXJQb3NpdGlvbi55IC0gKGggLyAyKTtcbiAgICByZXR1cm4gdGhpcy5jbGFtcFJlY3QoeCwgeSwgdywgaCk7XG4gIH1cblxuICBnZXRDb3ZlclJlY3QoKSB7XG4gICAgY29uc3QgdyA9IHRoaXMuY2FudmFzV2lkdGggLyB0aGlzLl96b29tRmFjdG9yO1xuICAgIGNvbnN0IGggPSB0aGlzLmNhbnZhc0hlaWdodCAvIHRoaXMuX3pvb21GYWN0b3I7XG4gICAgLy8gY29uc3QgeCA9IHRoaXMubW91c2VQb3NpdGlvbi54IC0gKHcgLyAyKTtcbiAgICAvLyBjb25zdCB5ID0gdGhpcy5tb3VzZVBvc2l0aW9uLnkgLSAoaCAvIDIpO1xuICAgIGNvbnN0IHggPSB0aGlzLl9jZW50ZXJQb3NpdGlvbi54IC0gdGhpcy5fY2VudGVyUG9zaXRpb24ueCAvIHRoaXMuX3pvb21GYWN0b3I7XG4gICAgY29uc3QgeSA9IHRoaXMuX2NlbnRlclBvc2l0aW9uLnkgLSB0aGlzLl9jZW50ZXJQb3NpdGlvbi55IC8gdGhpcy5fem9vbUZhY3RvcjtcbiAgICByZXR1cm4gdGhpcy5jbGFtcFJlY3QoeCwgeSwgdywgaCk7XG4gIH1cblxuICBjbGFtcFJlY3QoeDogbnVtYmVyLCB5OiBudW1iZXIsIHc6IG51bWJlciwgaDogbnVtYmVyKSB7XG4gICAgaWYgKHggPD0gMCkgeyB4ID0gMDsgfVxuICAgIGlmICh4ICsgdyA+PSB0aGlzLmNhbnZhc1dpZHRoKSB7IHggPSB0aGlzLmNhbnZhc1dpZHRoIC0gdzsgfVxuICAgIGlmICh5IDwgMCkgeyB5ID0gMDsgfVxuICAgIGlmICh5ICsgaCA+PSB0aGlzLmNhbnZhc0hlaWdodCkgeyB5ID0gdGhpcy5jYW52YXNIZWlnaHQgLSBoOyB9XG4gICAgcmV0dXJuIHsgeCwgeSwgdywgaCB9O1xuICB9XG5cbiAgY2FsY3VsYXRlTW91c2VQb3NpdGlvbihjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlcikge1xuICAgIGNvbnN0IGJvdW5kaW5nUmVjdCA9IHRoaXMuY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgY29uc3QgYm91bmRpbmdSZWN0WCA9IChjbGllbnRYIC0gYm91bmRpbmdSZWN0LmxlZnQpO1xuICAgIGNvbnN0IGJvdW5kaW5nUmVjdFkgPSAoY2xpZW50WSAtIGJvdW5kaW5nUmVjdC50b3ApO1xuXG4gICAgbGV0IGVsZW1lbnRYID0gYm91bmRpbmdSZWN0WCwgZWxlbWVudFkgPSBib3VuZGluZ1JlY3RZO1xuICAgIGxldCBlbGVtZW50V2lkdGggPSBib3VuZGluZ1JlY3Qud2lkdGgsIGVsZW1lbnRIZWlnaHQgPSBib3VuZGluZ1JlY3QuaGVpZ2h0O1xuXG4gICAgY29uc3QgY29tcHV0ZWRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHRoaXMuY2FudmFzLCBudWxsKTtcbiAgICBjb25zdCBkb21NYXRyaXggPSBuZXcgRE9NTWF0cml4KGNvbXB1dGVkU3R5bGUudHJhbnNmb3JtKTtcbiAgICBpZiAoIWRvbU1hdHJpeC5pc0lkZW50aXR5KSB7XG4gICAgICBjb25zdCB7IGEsIGIgfSA9IGRvbU1hdHJpeDtcbiAgICAgIGNvbnN0IHRyYW5zZm9ybVJvdCA9IE1hdGguYXRhbjIoYiwgYSk7XG4gICAgICBjb25zdCB0cmFuc2Zvcm1TY2FsZSA9IE1hdGgucm91bmQoIE1hdGguc3FydChhICogYSArIGIgKiBiKSAqIDEwMCApIC8gMTAwO1xuICAgICAgaWYgKHRyYW5zZm9ybVJvdCkge1xuICAgICAgICBjb25zdCBib3VuZGluZ1JlY3RDZW50ZXJYID0gYm91bmRpbmdSZWN0LndpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgYm91bmRpbmdSZWN0Q2VudGVyWSA9IGJvdW5kaW5nUmVjdC5oZWlnaHQgLyAyO1xuICAgICAgICBjb25zdCBkeCA9IChib3VuZGluZ1JlY3RYIC0gYm91bmRpbmdSZWN0Q2VudGVyWCk7XG4gICAgICAgIGNvbnN0IGR5ID0gKGJvdW5kaW5nUmVjdFkgLSBib3VuZGluZ1JlY3RDZW50ZXJZKTtcbiAgICAgICAgY29uc3QgZCA9IE1hdGguc3FydChkeCAqIGR4ICsgZHkgKiBkeSk7XG4gICAgICAgIGNvbnN0IHIgPSBNYXRoLmF0YW4yKGR5LCBkeCk7XG4gICAgICAgIGVsZW1lbnRXaWR0aCA9IHRoaXMuY2FudmFzLmNsaWVudFdpZHRoICogdHJhbnNmb3JtU2NhbGU7XG4gICAgICAgIGVsZW1lbnRIZWlnaHQgPSB0aGlzLmNhbnZhcy5jbGllbnRIZWlnaHQgKiB0cmFuc2Zvcm1TY2FsZTtcbiAgICAgICAgZWxlbWVudFggPSAoZWxlbWVudFdpZHRoIC8gMikgKyAoZCAqIE1hdGguY29zKHIgLSB0cmFuc2Zvcm1Sb3QpKTtcbiAgICAgICAgZWxlbWVudFkgPSAoZWxlbWVudEhlaWdodCAvIDIpICsgKGQgKiBNYXRoLnNpbihyIC0gdHJhbnNmb3JtUm90KSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgdmlld1RvTW9kZWxYID0gdGhpcy5jYW52YXNXaWR0aCAvIGVsZW1lbnRXaWR0aDtcbiAgICBjb25zdCB2aWV3VG9Nb2RlbFkgPSB0aGlzLmNhbnZhc0hlaWdodCAvIGVsZW1lbnRIZWlnaHQ7XG4gICAgY29uc3QgeCA9IGVsZW1lbnRYICogdmlld1RvTW9kZWxYO1xuICAgIGNvbnN0IHkgPSBlbGVtZW50WSAqIHZpZXdUb01vZGVsWTtcbiAgICB0aGlzLl9jZW50ZXJQb3NpdGlvbiA9IHsgeCwgeSB9O1xuICB9XG5cbiAgb25Nb3VzZUxlYXZlKGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgaWYgKCF0aGlzLnVwZGF0ZU9uTW91c2VFdmVudHMpIHsgcmV0dXJuOyB9XG4gICAgdGhpcy5fY2VudGVyUG9zaXRpb24gPSBudWxsO1xuICAgIHRoaXMudXBkYXRlKCk7XG4gIH1cblxuICBvbk1vdXNlRW50ZXJPck1vdmUoZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMudXBkYXRlT25Nb3VzZUV2ZW50cykgeyByZXR1cm47IH1cbiAgICB0aGlzLmNhbGN1bGF0ZU1vdXNlUG9zaXRpb24oZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSk7XG4gICAgdGhpcy51cGRhdGUoKTtcbiAgfVxuXG4gIG9uTW91c2VTY3JvbGwoZXZlbnQ6IFdoZWVsRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMudXBkYXRlT25Nb3VzZUV2ZW50cykgeyByZXR1cm47IH1cbiAgICBsZXQgbmV3Wm9vbUZhY3RvciA9IHRoaXMuX3pvb21GYWN0b3I7XG4gICAgbmV3Wm9vbUZhY3RvciAtPSBldmVudC5kZWx0YVkgLyAxMDAwO1xuICAgIGlmIChuZXdab29tRmFjdG9yIDwgdGhpcy5taW5ab29tRmFjdG9yKSB7IG5ld1pvb21GYWN0b3IgPSB0aGlzLm1pblpvb21GYWN0b3I7IH1cbiAgICBpZiAobmV3Wm9vbUZhY3RvciA+IHRoaXMubWF4Wm9vbUZhY3RvcikgeyBuZXdab29tRmFjdG9yID0gdGhpcy5tYXhab29tRmFjdG9yOyB9XG4gICAgaWYgKHRoaXMuX3pvb21GYWN0b3IgIT09IG5ld1pvb21GYWN0b3IpIHtcbiAgICAgIHRoaXMuX3pvb21GYWN0b3IgPSBuZXdab29tRmFjdG9yO1xuICAgICAgaWYgKHRoaXMuem9vbUZhY3RvciAhPT0gdGhpcy5fem9vbUZhY3Rvcikge1xuICAgICAgICB0aGlzLnpvb21GYWN0b3JDaGFuZ2UuZW1pdCh0aGlzLl96b29tRmFjdG9yKTtcbiAgICAgIH1cbiAgICAgIHRoaXMudXBkYXRlKCk7XG4gICAgfVxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH1cblxuXG59XG4iLCI8Y2FudmFzICNtYWluQ2FudmFzXG4gIGNsYXNzPVwibWFpbi1jYW52YXNcIlxuICBbbmdDbGFzc109XCJpbWFnZUNsYXNzXCJcbiAgW25nU3R5bGVdPVwiaW1hZ2VTdHlsZVwiXG4gIFt3aWR0aF09XCJjYW52YXNXaWR0aFwiXG4gIFtoZWlnaHRdPVwiY2FudmFzSGVpZ2h0XCJcbiAgKG1vdXNlbGVhdmUpPVwib25Nb3VzZUxlYXZlKCRldmVudClcIlxuICAobW91c2VlbnRlcik9XCJvbk1vdXNlRW50ZXJPck1vdmUoJGV2ZW50KVwiXG4gIChtb3VzZW1vdmUpPVwib25Nb3VzZUVudGVyT3JNb3ZlKCRldmVudClcIlxuICAod2hlZWwpPVwib25Nb3VzZVNjcm9sbCgkZXZlbnQpXCI+XG48L2NhbnZhcz5cbiJdfQ==