ngx-image-drawing
Version:
Angular module to draw on images
463 lines • 59.6 kB
JavaScript
import * as tslib_1 from "tslib";
import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
import { fabric } from 'fabric';
import { I18nEn, i18nLanguages } from './i18n';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
let ImageDrawingComponent = class ImageDrawingComponent {
constructor() {
this.forceSizeCanvas = true;
this.forceSizeExport = false;
this.enableRemoveImage = false;
this.enableLoadAnotherImage = false;
this.enableTooltip = true;
this.showCancelButton = true;
this.locale = 'en';
/* @deprecated Use i18n.saveBtn */
this.saveBtnText = 'Save';
/* @deprecated Use i18n.cancelBtn */
this.cancelBtnText = 'Cancel';
/* @deprecated Use i18n.loading */
this.loadingText = 'Loading…';
/* @deprecated Use i18n.loadError */
this.errorText = 'Error loading %@';
this.outputMimeType = 'image/jpeg';
this.outputQuality = 0.8;
this.borderCss = 'none';
this.drawingSizes = {
small: 5,
medium: 10,
large: 25,
};
this.colors = {
black: '#000',
white: '#fff',
yellow: '#ffeb3b',
red: '#f44336',
blue: '#2196f3',
green: '#4caf50',
purple: '#7a08af',
};
this.save = new EventEmitter();
this.cancel = new EventEmitter();
this.currentTool = 'brush';
this.currentSize = 'medium';
this.currentColor = 'black';
this.i18n = I18nEn;
this.canUndo = false;
this.canRedo = false;
this.isLoading = false;
this.hasError = false;
this.errorMessage = '';
this.stack = [];
this.colorsName = [];
this.drawingSizesName = [];
}
ngOnInit() {
this.colorsName = Object.keys(this.colors);
this.drawingSizesName = Object.keys(this.drawingSizes);
this.canvas = new fabric.Canvas('canvas', {
hoverCursor: 'pointer',
isDrawingMode: true,
});
this.canvas.backgroundColor = 'white';
if (this.src) {
this.importPhotoFromSrc(this.src);
}
else {
if (!this.width || !this.height) {
throw new Error('No width or hight given !');
}
this.canvas.setWidth(this.width);
this.canvas.setHeight(this.height);
}
this.canvas.on('path:created', () => {
this.stack = [];
this.setUndoRedo();
});
this.selectTool(this.currentTool);
this.selectColor(this.currentColor);
this.selectDrawingSize(this.currentSize);
if (this.locale && i18nLanguages[this.locale.toLowerCase()]) {
this.i18n = i18nLanguages[this.locale.toLowerCase()];
}
// FIXME remove after a while because properties are now deprecated
if (this.saveBtnText) {
this.i18n.saveBtn = this.saveBtnText;
}
if (this.cancelBtnText) {
this.i18n.cancelBtn = this.cancelBtnText;
}
if (this.loadingText) {
this.i18n.loading = this.loadingText;
}
if (this.errorText) {
this.i18n.loadError = this.errorText;
}
}
// Tools
selectTool(tool) {
this.currentTool = tool;
}
selectDrawingSize(size) {
this.currentSize = size;
if (this.canvas) {
this.canvas.freeDrawingBrush.width = this.drawingSizes[size];
}
}
selectColor(color) {
this.currentColor = color;
if (this.canvas) {
this.canvas.freeDrawingBrush.color = this.colors[color];
}
}
// Actions
undo() {
if (this.canUndo) {
const lastId = this.canvas.getObjects().length - 1;
const lastObj = this.canvas.getObjects()[lastId];
this.stack.push(lastObj);
this.canvas.remove(lastObj);
this.setUndoRedo();
}
}
redo() {
if (this.canRedo) {
const firstInStack = this.stack.splice(-1, 1)[0];
if (firstInStack) {
this.canvas.insertAt(firstInStack, this.canvas.getObjects().length - 1, false);
}
this.setUndoRedo();
}
}
clearCanvas() {
if (this.canvas) {
this.canvas.remove(...this.canvas.getObjects());
this.setUndoRedo();
}
}
saveImage() {
if (!this.forceSizeExport || (this.forceSizeExport && this.width && this.height)) {
const canvasScaledElement = document.createElement('canvas');
const canvasScaled = new fabric.Canvas(canvasScaledElement);
canvasScaled.backgroundColor = 'white';
new Observable(observer => {
if (this.imageUsed) {
if (this.forceSizeExport) {
canvasScaled.setWidth(this.width);
canvasScaled.setHeight(this.height);
this.imageUsed.cloneAsImage(imageCloned => {
imageCloned.scaleToWidth(this.width, false);
imageCloned.scaleToHeight(this.height, false);
canvasScaled.setBackgroundImage(imageCloned, (img) => {
if (!img) {
observer.error(new Error('Impossible to draw the image on the temporary canvas'));
}
observer.next(canvasScaled);
observer.complete();
}, {
crossOrigin: 'anonymous',
originX: 'left',
originY: 'top'
});
});
}
else {
canvasScaled.setBackgroundImage(this.imageUsed, (img) => {
if (!img) {
observer.error(new Error('Impossible to draw the image on the temporary canvas'));
}
canvasScaled.setWidth(img.width);
canvasScaled.setHeight(img.height);
observer.next(canvasScaled);
observer.complete();
}, {
crossOrigin: 'anonymous',
originX: 'left',
originY: 'top'
});
}
}
else {
canvasScaled.setWidth(this.width);
canvasScaled.setHeight(this.height);
}
}).pipe(switchMap(() => {
let process = of(canvasScaled);
if (this.canvas.getObjects().length > 0) {
const ratioX = canvasScaled.getWidth() / this.canvas.getWidth();
const ratioY = canvasScaled.getHeight() / this.canvas.getHeight();
this.canvas.getObjects().forEach((originalObject, i) => {
process = process.pipe(switchMap(() => {
return new Observable(observerObject => {
originalObject.clone((clonedObject) => {
clonedObject.set('left', originalObject.left * ratioX);
clonedObject.set('top', originalObject.top * ratioY);
clonedObject.scaleToWidth(originalObject.width * ratioX);
clonedObject.scaleToHeight(originalObject.height * ratioY);
canvasScaled.insertAt(clonedObject, i, false);
canvasScaled.renderAll();
observerObject.next(canvasScaled);
observerObject.complete();
});
});
}));
});
}
return process;
})).subscribe(() => {
canvasScaled.renderAll();
canvasScaled.getElement().toBlob((data) => {
this.save.emit(data);
}, this.outputMimeType, this.outputQuality);
});
}
else {
this.canvas.getElement().toBlob((data) => {
this.save.emit(data);
}, this.outputMimeType, this.outputQuality);
}
}
cancelAction() {
this.cancel.emit();
}
getTextTranslated(name) {
let strOk = name.split('.').reduce((o, i) => o[i], this.i18n);
if (this.i18nUser) {
try {
const str = name.split('.').reduce((o, i) => o[i], this.i18nUser);
if (str) {
strOk = str;
}
}
catch (e) {
// if we pass here, ignored
}
}
if (!strOk) {
console.error(name + ' translation not found !');
}
return strOk;
}
getTooltipTranslated(name) {
if (this.enableTooltip) {
return this.getTextTranslated(name);
}
else {
return '';
}
}
setUndoRedo() {
this.canUndo = this.canvas.getObjects().length > 0;
this.canRedo = this.stack.length > 0;
this.canvas.renderAll();
}
importPhotoFromFile(event) {
if (event.target.files && event.target.files.length > 0) {
const file = event.target.files[0];
if (file.type.match('image.*')) {
this.importPhotoFromBlob(file);
}
else {
throw new Error('Not an image !');
}
}
}
removeImage() {
if (this.imageUsed) {
this.imageUsed.dispose();
this.imageUsed = null;
}
this.canvas.backgroundImage = null;
if (this.width && this.height) {
this.canvas.setWidth(this.width);
this.canvas.setHeight(this.height);
}
this.canvas.renderAll();
}
get hasImage() {
return !!this.canvas.backgroundImage;
}
importPhotoFromSrc(src) {
this.isLoading = true;
let isFirstTry = true;
const imgEl = new Image();
imgEl.setAttribute('crossOrigin', 'anonymous');
imgEl.src = src;
imgEl.onerror = () => {
// Retry with cors proxy
if (isFirstTry) {
imgEl.src = 'https://cors-anywhere.herokuapp.com/' + this.src;
isFirstTry = false;
}
else {
this.isLoading = false;
this.hasError = true;
this.errorMessage = this.getTextTranslated('loadError').replace('%@', this.src);
}
};
imgEl.onload = () => {
this.isLoading = false;
this.imageUsed = new fabric.Image(imgEl);
this.imageUsed.cloneAsImage(image => {
let width = imgEl.width;
let height = imgEl.height;
if (this.width) {
width = this.width;
}
if (this.height) {
height = this.height;
}
image.scaleToWidth(width, false);
image.scaleToHeight(height, false);
this.canvas.setBackgroundImage(image, ((img) => {
if (img) {
if (this.forceSizeCanvas) {
this.canvas.setWidth(width);
this.canvas.setHeight(height);
}
else {
this.canvas.setWidth(image.getScaledWidth());
this.canvas.setHeight(image.getScaledHeight());
}
}
}), {
crossOrigin: 'anonymous',
originX: 'left',
originY: 'top'
});
});
};
}
importPhotoFromBlob(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (evtReader) => {
if (evtReader.target.readyState == FileReader.DONE) {
this.importPhotoFromSrc(evtReader.target.result);
}
};
}
importPhotoFromUrl() {
const url = prompt(this.getTooltipTranslated('loadImageUrl'));
if (url) {
this.importPhotoFromSrc(url);
}
}
ngOnChanges(changes) {
if (changes.src && !changes.src.firstChange && changes.src.currentValue) {
if (typeof changes.src.currentValue === 'string') {
this.importPhotoFromSrc(changes.src.currentValue);
}
else if (changes.src.currentValue instanceof Blob) {
this.importPhotoFromBlob(changes.src.currentValue);
}
}
}
};
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", String)
], ImageDrawingComponent.prototype, "src", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Number)
], ImageDrawingComponent.prototype, "width", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Number)
], ImageDrawingComponent.prototype, "height", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "forceSizeCanvas", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "forceSizeExport", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "enableRemoveImage", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "enableLoadAnotherImage", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "enableTooltip", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "showCancelButton", void 0);
tslib_1.__decorate([
Input('i18n'),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "i18nUser", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", String)
], ImageDrawingComponent.prototype, "locale", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "saveBtnText", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "cancelBtnText", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "loadingText", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "errorText", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", TemplateRef)
], ImageDrawingComponent.prototype, "loadingTemplate", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", TemplateRef)
], ImageDrawingComponent.prototype, "errorTemplate", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "outputMimeType", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "outputQuality", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", String)
], ImageDrawingComponent.prototype, "borderCss", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "drawingSizes", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], ImageDrawingComponent.prototype, "colors", void 0);
tslib_1.__decorate([
Output(),
tslib_1.__metadata("design:type", EventEmitter)
], ImageDrawingComponent.prototype, "save", void 0);
tslib_1.__decorate([
Output(),
tslib_1.__metadata("design:type", EventEmitter)
], ImageDrawingComponent.prototype, "cancel", void 0);
ImageDrawingComponent = tslib_1.__decorate([
Component({
selector: 'image-drawing',
template: "<link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\" />\n\n<div class=\"loading\" *ngIf=\"isLoading\">\n <ng-container *ngTemplateOutlet=\"loadingTemplate ? loadingTemplate : defaultLoading\"></ng-container>\n</div>\n<div class=\"error\" *ngIf=\"hasError\">\n <ng-container *ngTemplateOutlet=\"errorTemplate ? errorTemplate : defaultError\"></ng-container>\n</div>\n\n<ng-template #defaultLoading><p>{{ getTextTranslated('loading') }}</p></ng-template>\n<ng-template #defaultError> <p>{{ errorMessage }}</p> </ng-template>\n\n<div [ngStyle]=\"{ border: borderCss }\">\n <canvas id=\"canvas\"></canvas>\n</div>\n<div class=\"toolbar\" *ngIf=\"!isLoading\">\n <div class=\"tools\">\n <div class=\"row\">\n <i class=\"material-icons btn\" [class.selected]=\"currentTool == 'brush'\" (click)=\"selectTool('brush')\"\n [title]=\"getTooltipTranslated('tools.brush')\">brush</i>\n <span *ngFor=\"let drawingSizeName of drawingSizesName\" class=\"size btn\"\n [style.width.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.height.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.borderRadius.px]=\"drawingSizes[drawingSizeName] * 0.4 + 4\"\n [class.selected]=\"currentSize == drawingSizeName\"\n [title]=\"getTooltipTranslated('sizes.' + drawingSizeName)\"\n (click)=\"selectDrawingSize(drawingSizeName)\">\n </span>\n\n <input style=\"display: none\" type=\"file\" #fileInput (change)=\"importPhotoFromFile($event)\"\n accept=\"image/*\"/>\n <i class=\"material-icons btn\" *ngIf=\"enableLoadAnotherImage && !hasImage\" (click)=\"fileInput.click();\"\n [title]=\"getTooltipTranslated('loadImage')\">attach_file</i>\n <i class=\"material-icons btn\" *ngIf=\"enableLoadAnotherImage && !hasImage\" (click)=\"importPhotoFromUrl()\"\n [title]=\"getTooltipTranslated('loadImageUrl')\">insert_drive_file</i>\n <i class=\"material-icons btn\" *ngIf=\"enableRemoveImage && hasImage\" (click)=\"removeImage()\"\n [title]=\"getTooltipTranslated('removeImage')\">clear</i>\n\n <i class=\"material-icons btn\" [class.disabled]=\"!canUndo\" (click)=\"undo()\"\n [title]=\"getTooltipTranslated('undo')\">undo</i>\n <i class=\"material-icons btn\" [class.disabled]=\"!canRedo\" (click)=\"redo()\"\n [title]=\"getTooltipTranslated('redo')\">redo</i>\n <i class=\"material-icons btn\" (click)=\"clearCanvas()\" [title]=\"getTooltipTranslated('clear')\">delete</i>\n </div>\n <div class=\"row\">\n <div *ngFor=\"let colorName of colorsName\" [class.selected]=\"currentColor == colorName\" class=\"color\"\n [ngClass]=\"colorName\"\n [style.background]=\"colors[colorName]\" [title]=\"getTooltipTranslated('colors.' + colorName)\"\n (click)=\"selectColor(colorName)\">\n </div>\n </div>\n </div>\n <div class=\"buttons\">\n <a href=\"#\" class=\"button btn-primary\"\n (click)=\"saveImage(); $event.preventDefault()\">{{ getTextTranslated('saveBtn') }}</a>\n <a href=\"#\" class=\"button btn-light\" *ngIf=\"showCancelButton\"\n (click)=\"cancelAction(); $event.preventDefault()\">{{ getTextTranslated('cancelBtn') }}</a>\n </div>\n <!-- Any additional toolbar buttons to be projected by the consuming app -->\n <ng-content></ng-content>\n</div>\n",
styles: [":host{display:flex;flex-direction:column;align-items:center}:host .toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap}:host .tools{display:inline-flex;flex-direction:column;padding:20px;margin:10px;background:#fff;border-radius:6px;box-shadow:0 3px 10px rgba(0,0,0,.4)}:host .row{display:flex;width:300px;justify-content:space-around;align-items:center}:host .row:first-child{margin-bottom:10px}:host .btn{cursor:pointer}:host .btn.selected{color:#bdbdbd}:host .btn.disabled{cursor:initial;color:#bdbdbd}:host .size{background-color:#000}:host .size.selected{background-color:#bdbdbd}:host .color{width:28px;height:28px;border-radius:14px;cursor:pointer;display:flex;align-items:center;justify-content:center}:host .color.selected::after{content:\"\";width:10px;height:10px;background:#000;display:flex;border-radius:5px}:host .color.black{background-color:#000}:host .color.black.selected::after{background:#fff}:host .color.white{border:1px solid #a7a7a7}:host .buttons{margin:10px;display:flex;flex-direction:column}:host .button{cursor:pointer;outline:0;border:none;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;min-width:64px;line-height:36px;padding:3px 16px;border-radius:4px;overflow:visible;transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);margin:10px}:host .button:hover{text-decoration:none!important}:host .button.btn-primary{background-color:#ef5f27;color:#fff}:host .button.btn-primary:hover{background-color:rgba(239,95,39,.8)}:host .button.btn-light{color:#ef5f27}:host .button.btn-light:hover{background-color:rgba(239,95,39,.1)}"]
}),
tslib_1.__metadata("design:paramtypes", [])
], ImageDrawingComponent);
export { ImageDrawingComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtZHJhd2luZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtaW1hZ2UtZHJhd2luZy8iLCJzb3VyY2VzIjpbInNyYy9pbWFnZS1kcmF3aW5nLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFxQixNQUFNLEVBQWlCLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN0SCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxNQUFNLEVBQWlCLGFBQWEsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUM5RCxPQUFPLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFPM0MsSUFBYSxxQkFBcUIsR0FBbEMsTUFBYSxxQkFBcUI7SUF3RTlCO1FBbEVnQixvQkFBZSxHQUFHLElBQUksQ0FBQztRQUN2QixvQkFBZSxHQUFHLEtBQUssQ0FBQztRQUN4QixzQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFDMUIsMkJBQXNCLEdBQUcsS0FBSyxDQUFDO1FBQy9CLGtCQUFhLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLHFCQUFnQixHQUFHLElBQUksQ0FBQztRQUl4QixXQUFNLEdBQVcsSUFBSSxDQUFDO1FBQ3RDLGtDQUFrQztRQUNsQixnQkFBVyxHQUFHLE1BQU0sQ0FBQztRQUNyQyxvQ0FBb0M7UUFDcEIsa0JBQWEsR0FBRyxRQUFRLENBQUM7UUFDekMsa0NBQWtDO1FBQ2xCLGdCQUFXLEdBQUcsVUFBVSxDQUFDO1FBQ3pDLG9DQUFvQztRQUNwQixjQUFTLEdBQUcsa0JBQWtCLENBQUM7UUFLL0IsbUJBQWMsR0FBRyxZQUFZLENBQUM7UUFDOUIsa0JBQWEsR0FBRyxHQUFHLENBQUM7UUFFcEIsY0FBUyxHQUFXLE1BQU0sQ0FB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WTtxREFBa0M7QUFsRDlELHFCQUFxQjtJQUxqQyxTQUFTLENBQUM7UUFDUCxRQUFRLEVBQUUsZUFBZTtRQUV6Qixta0hBQTZDOztLQUNoRCxDQUFDOztHQUNXLHFCQUFxQixDQXFhakM7U0FyYVkscUJBQXFCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uSW5pdCwgT3V0cHV0LCBTaW1wbGVDaGFuZ2VzLCBUZW1wbGF0ZVJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgZmFicmljIH0gZnJvbSAnZmFicmljJztcbmltcG9ydCB7IEkxOG5FbiwgSTE4bkludGVyZmFjZSwgaTE4bkxhbmd1YWdlcyB9IGZyb20gJy4vaTE4bic7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2ltYWdlLWRyYXdpbmcnLFxuICAgIHN0eWxlVXJsczogWycuL2ltYWdlLWRyYXdpbmcuY29tcG9uZW50LnNjc3MnXSxcbiAgICB0ZW1wbGF0ZVVybDogJy4vaW1hZ2UtZHJhd2luZy5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgSW1hZ2VEcmF3aW5nQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xuXG4gICAgQElucHV0KCkgcHVibGljIHNyYz86IHN0cmluZztcbiAgICBASW5wdXQoKSBwdWJsaWMgd2lkdGg/OiBudW1iZXI7XG4gICAgQElucHV0KCkgcHVibGljIGhlaWdodD86IG51bWJlcjtcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBmb3JjZVNpemVDYW52YXMgPSB0cnVlO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBmb3JjZVNpemVFeHBvcnQgPSBmYWxzZTtcbiAgICBASW5wdXQoKSBwdWJsaWMgZW5hYmxlUmVtb3ZlSW1hZ2UgPSBmYWxzZTtcbiAgICBASW5wdXQoKSBwdWJsaWMgZW5hYmxlTG9hZEFub3RoZXJJbWFnZSA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBlbmFibGVUb29sdGlwID0gdHJ1ZTtcbiAgICBASW5wdXQoKSBwdWJsaWMgc2hvd0NhbmNlbEJ1dHRvbiA9IHRydWU7XG5cbiAgICAvLyBAdHMtaWdub3JlXG4gICAgQElucHV0KCdpMThuJykgcHVibGljIGkxOG5Vc2VyOiBJMThuSW50ZXJmYWNlO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBsb2NhbGU6IHN0cmluZyA9ICdlbic7XG4gICAgLyogQGRlcHJlY2F0ZWQgVXNlIGkxOG4uc2F2ZUJ0biAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBzYXZlQnRuVGV4dCA9ICdTYXZlJztcbiAgICAvKiBAZGVwcmVjYXRlZCBVc2UgaTE4bi5jYW5jZWxCdG4gKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgY2FuY2VsQnRuVGV4dCA9ICdDYW5jZWwnO1xuICAgIC8qIEBkZXByZWNhdGVkIFVzZSBpMThuLmxvYWRpbmcgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgbG9hZGluZ1RleHQgPSAnTG9hZGluZ+KApic7XG4gICAgLyogQGRlcHJlY2F0ZWQgVXNlIGkxOG4ubG9hZEVycm9yICovXG4gICAgQElucHV0KCkgcHVibGljIGVycm9yVGV4dCA9ICdFcnJvciBsb2FkaW5nICVAJztcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBsb2FkaW5nVGVtcGxhdGU/OiBUZW1wbGF0ZVJlZjxhbnk+O1xuICAgIEBJbnB1dCgpIHB1YmxpYyBlcnJvclRlbXBsYXRlPzogVGVtcGxhdGVSZWY8YW55PjtcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBvdXRwdXRNaW1lVHlwZSA9ICdpbWFnZS9qcGVnJztcbiAgICBASW5wdXQoKSBwdWJsaWMgb3V0cHV0UXVhbGl0eSA9IDAuODtcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBib3JkZXJDc3M6IHN0cmluZyA9ICdub25lJztcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBkcmF3aW5nU2l6ZXM6IHsgW25hbWU6IHN0cmluZ106IG51bWJlciB9ID0ge1xuICAgICAgICBzbWFsbDogNSxcbiAgICAgICAgbWVkaXVtOiAxMCxcbiAgICAgICAgbGFyZ2U6IDI1LFxuICAgIH07XG5cbiAgICBASW5wdXQoKSBwdWJsaWMgY29sb3JzOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSA9IHtcbiAgICAgICAgYmxhY2s6ICcjMDAwJyxcbiAgICAgICAgd2hpdGU6ICcjZmZmJyxcbiAgICAgICAgeWVsbG93OiAnI2ZmZWIzYicsXG4gICAgICAgIHJlZDogJyNmNDQzMzYnLFxuICAgICAgICBibHVlOiAnIzIxOTZmMycsXG4gICAgICAgIGdyZWVuOiAnIzRjYWY1MCcsXG4gICAgICAgIHB1cnBsZTogJyM3YTA4YWYnLFxuICAgIH07XG5cbiAgICBAT3V0cHV0KCkgcHVibGljIHNhdmU6IEV2ZW50RW1pdHRlcjxCbG9iPiA9IG5ldyBFdmVudEVtaXR0ZXI8QmxvYj4oKTtcbiAgICBAT3V0cHV0KCkgcHVibGljIGNhbmNlbDogRXZlbnRFbWl0dGVyPHZvaWQ+ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG4gICAgcHVibGljIGN1cnJlbnRUb29sID0gJ2JydXNoJztcbiAgICBwdWJsaWMgY3VycmVudFNpemUgPSAnbWVkaXVtJztcbiAgICBwdWJsaWMgY3VycmVudENvbG9yID0gJ2JsYWNrJztcbiAgICBwdWJsaWMgaTE4bjogSTE4bkludGVyZmFjZSA9IEkxOG5FbjtcblxuICAgIHB1YmxpYyBjYW5VbmRvID0gZmFsc2U7XG4gICAgcHVibGljIGNhblJlZG8gPSBmYWxzZTtcblxuICAgIHB1YmxpYyBpc0xvYWRpbmcgPSBmYWxzZTtcbiAgICBwdWJsaWMgaGFzRXJyb3IgPSBmYWxzZTtcbiAgICBwdWJsaWMgZXJyb3JNZXNzYWdlID0gJyc7XG5cbiAgICBwcml2YXRlIGNhbnZhczogZmFicmljLkNhbnZhcztcbiAgICBwcml2YXRlIHN0YWNrOiBmYWJyaWMuT2JqZWN0W10gPSBbXTtcblxuICAgIHB1YmxpYyBjb2xvcnNOYW1lOiBzdHJpbmdbXSA9IFtdO1xuICAgIHB1YmxpYyBkcmF3aW5nU2l6ZXNOYW1lOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBpbWFnZVVzZWQ/OiBmYWJyaWMuSW1hZ2U7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICB9XG5cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY29sb3JzTmFtZSA9IE9iamVjdC5rZXlzKHRoaXMuY29sb3JzKTtcbiAgICAgICAgdGhpcy5kcmF3aW5nU2l6ZXNOYW1lID0gT2JqZWN0LmtleXModGhpcy5kcmF3aW5nU2l6ZXMpO1xuXG4gICAgICAgIHRoaXMuY2FudmFzID0gbmV3IGZhYnJpYy5DYW52YXMoJ2NhbnZhcycsIHtcbiAgICAgICAgICAgIGhvdmVyQ3Vyc29yOiAncG9pbnRlcicsXG4gICAgICAgICAgICBpc0RyYXdpbmdNb2RlOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5jYW52YXMuYmFja2dyb3VuZENvbG9yID0gJ3doaXRlJztcblxuICAgICAgICBpZiAodGhpcy5zcmMpIHtcbiAgICAgICAgICAgIHRoaXMuaW1wb3J0UGhvdG9Gcm9tU3JjKHRoaXMuc3JjKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghdGhpcy53aWR0aCB8fCAhdGhpcy5oZWlnaHQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHdpZHRoIG9yIGhpZ2h0IGdpdmVuICEnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jYW52YXMuc2V0V2lkdGgodGhpcy53aWR0aCk7XG4gICAgICAgICAgICB0aGlzLmNhbnZhcy5zZXRIZWlnaHQodGhpcy5oZWlnaHQpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jYW52YXMub24oJ3BhdGg6Y3JlYXRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RhY2sgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuc2V0VW5kb1JlZG8oKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5zZWxlY3RUb29sKHRoaXMuY3VycmVudFRvb2wpO1xuICAgICAgICB0aGlzLnNlbGVjdENvbG9yKHRoaXMuY3VycmVudENvbG9yKTtcbiAgICAgICAgdGhpcy5zZWxlY3REcmF3aW5nU2l6ZSh0aGlzLmN1cnJlbnRTaXplKTtcblxuICAgICAgICBpZiAodGhpcy5sb2NhbGUgJiYgaTE4bkxhbmd1YWdlc1t0aGlzLmxvY2FsZS50b0xvd2VyQ2FzZSgpXSkge1xuICAgICAgICAgICAgdGhpcy5pMThuID0gaTE4bkxhbmd1YWdlc1t0aGlzLmxvY2FsZS50b0xvd2VyQ2FzZSgpXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZJWE1FIHJlbW92ZSBhZnRlciBhIHdoaWxlIGJlY2F1c2UgcHJvcGVydGllcyBhcmUgbm93IGRlcHJlY2F0ZWRcbiAgICAgICAgaWYgKHRoaXMuc2F2ZUJ0blRleHQpIHtcbiAgICAgICAgICAgIHRoaXMuaTE4bi5zYXZlQnRuID0gdGhpcy5zYXZlQnRuVGV4dDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5jYW5jZWxCdG5UZXh0KSB7XG4gICAgICAgICAgICB0aGlzLmkxOG4uY2FuY2VsQnRuID0gdGhpcy5jYW5jZWxCdG5UZXh0O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmxvYWRpbmdUZXh0KSB7XG4gICAgICAgICAgICB0aGlzLmkxOG4ubG9hZGluZyA9IHRoaXMubG9hZGluZ1RleHQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZXJyb3JUZXh0KSB7XG4gICAgICAgICAgICB0aGlzLmkxOG4ubG9hZEVycm9yID0gdGhpcy5lcnJvclRleHQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUb29sc1xuICAgIHB1YmxpYyBzZWxlY3RUb29sKHRvb2w6IHN0cmluZykge1xuICAgICAgICB0aGlzLmN1cnJlbnRUb29sID0gdG9vbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2VsZWN0RHJhd2luZ1NpemUoc2l6ZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFNpemUgPSBzaXplO1xuICAgICAgICBpZiAodGhpcy5jYW52YXMpIHtcbiAgICAgICAgICAgIHRoaXMuY2FudmFzLmZyZWVEcmF3aW5nQnJ1c2gud2lkdGggPSB0aGlzLmRyYXdpbmdTaXplc1tzaXplXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzZWxlY3RDb2xvcihjb2xvcjogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuY3VycmVudENvbG9yID0gY29sb3I7XG4gICAgICAgIGlmICh0aGlzLmNhbnZhcykge1xuICAgICAgICAgICAgdGhpcy5jYW52YXMuZnJlZURyYXdpbmdCcnVzaC5jb2xvciA9IHRoaXMuY29sb3JzW2NvbG9yXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFjdGlvbnNcblxuICAgIHB1YmxpYyB1bmRvKCkge1xuICAgICAgICBpZiAodGhpcy5jYW5VbmRvKSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0SWQgPSB0aGlzLmNhbnZhcy5nZXRPYmplY3RzKCkubGVuZ3RoIC0gMTtcbiAgICAgICAgICAgIGNvbnN0IGxhc3RPYmogPSB0aGlzLmNhbnZhcy5nZXRPYmplY3RzKClbbGFzdElkXTtcbiAgICAgICAgICAgIHRoaXMuc3RhY2sucHVzaChsYXN0T2JqKTtcbiAgICAgICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZShsYXN0T2JqKTtcbiAgICAgICAgICAgIHRoaXMuc2V0VW5kb1JlZG8oKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyByZWRvKCkge1xuICAgICAgICBpZiAodGhpcy5jYW5SZWRvKSB7XG4gICAgICAgICAgICBjb25zdCBmaXJzdEluU3RhY2sgPSB0aGlzLnN0YWNrLnNwbGljZSgtMSwgMSlbMF07XG4gICAgICAgICAgICBpZiAoZmlyc3RJblN0YWNrKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jYW52YXMuaW5zZXJ0QXQoZmlyc3RJblN0YWNrLCB0aGlzLmNhbnZhcy5nZXRPYmplY3RzKCkubGVuZ3RoIC0gMSwgZmFsc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zZXRVbmRvUmVkbygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGNsZWFyQ2FudmFzKCkge1xuICAgICAgICBpZiAodGhpcy5jYW52YXMpIHtcbiAgICAgICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZSguLi50aGlzLmNhbnZhcy5nZXRPYmplY3RzKCkpO1xuICAgICAgICAgICAgdGhpcy5zZXRVbmRvUmVkbygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHNhdmVJbWFnZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmZvcmNlU2l6ZUV4cG9ydCB8fCAodGhpcy5mb3JjZVNpemVFeHBvcnQgJiYgdGhpcy53aWR0aCAmJiB0aGlzLmhlaWdodCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGNhbnZhc1NjYWxlZEVsZW1lbnQ6IEhUTUxDYW52YXNFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgICAgICAgICBjb25zdCBjYW52YXNTY2FsZWQgPSBuZXcgZmFicmljLkNhbnZhcyhjYW52YXNTY2FsZWRFbGVtZW50KTtcbiAgICAgICAgICAgIGNhbnZhc1NjYWxlZC5iYWNrZ3JvdW5kQ29sb3IgPSAnd2hpdGUnO1xuXG4gICAgICAgICAgICBuZXcgT2JzZXJ2YWJsZTxmYWJyaWMuQ2FudmFzPihvYnNlcnZlciA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaW1hZ2VVc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmZvcmNlU2l6ZUV4cG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzU2NhbGVkLnNldFdpZHRoKHRoaXMud2lkdGgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzU2NhbGVkLnNldEhlaWdodCh0aGlzLmhlaWdodCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW1hZ2VVc2VkLmNsb25lQXNJbWFnZShpbWFnZUNsb25lZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2VDbG9uZWQuc2NhbGVUb1dpZHRoKHRoaXMud2lkdGgsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZUNsb25lZC5zY2FsZVRvSGVpZ2h0KHRoaXMuaGVpZ2h0LCBmYWxzZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW52YXNTY2FsZWQuc2V0QmFja2dyb3VuZEltYWdlKGltYWdlQ2xvbmVkLCAoaW1nOiBIVE1MSW1hZ2VFbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaW1nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5lcnJvcihuZXcgRXJyb3IoJ0ltcG9zc2libGUgdG8gZHJhdyB0aGUgaW1hZ2Ugb24gdGhlIHRlbXBvcmFyeSBjYW52YXMnKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KGNhbnZhc1NjYWxlZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcm9zc09yaWdpbjogJ2Fub255bW91cycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpblg6ICdsZWZ0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZ2luWTogJ3RvcCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FudmFzU2NhbGVkLnNldEJhY2tncm91bmRJbWFnZSh0aGlzLmltYWdlVXNlZCwgKGltZzogSFRNTEltYWdlRWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaW1nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLmVycm9yKG5ldyBFcnJvcignSW1wb3NzaWJsZSB0byBkcmF3IHRoZSBpbWFnZSBvbiB0aGUgdGVtcG9yYXJ5IGNhbnZhcycpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW52YXNTY2FsZWQuc2V0V2lkdGgoaW1nLndpZHRoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW52YXNTY2FsZWQuc2V0SGVpZ2h0KGltZy5oZWlnaHQpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2ZXIubmV4dChjYW52YXNTY2FsZWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Jvc3NPcmlnaW46ICdhbm9ueW1vdXMnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpblg6ICdsZWZ0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW5ZOiAndG9wJ1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjYW52YXNTY2FsZWQuc2V0V2lkdGgodGhpcy53aWR0aCk7XG4gICAgICAgICAgICAgICAgICAgIGNhbnZhc1NjY