UNPKG

ng-cw-v12

Version:

Angular UI component library

402 lines 66.3 kB
import { __awaiter } from "tslib"; import { Component, EventEmitter, Input, Output } from '@angular/core'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/forms"; export class ImgClipComponent { constructor(eleRef) { this.eleRef = eleRef; this.ncConfirm = new EventEmitter(); //确认裁剪回调 this.ncImgType = 'base64'; //裁剪回调返回图片格式 this.ncWidth = 300; //容器宽度 this.ncClipSize = 0.7; //默认裁剪框的尺寸占图片比例 this.ncClipMinWidth = 50; //裁剪框最小宽度 this.ncClipMinHeight = 50; //裁剪框最小高度 this.downloadMode = false; this.toolMode = false; this.uploadMode = false; this.hasImage = false; // 图片当前宽高 this.clipImageWidth = 0; this.clipImageHeight = 0; // 图片原始宽高 this.clipImageOriginWidth = 0; this.clipImageOriginHeight = 0; this.scale = 0; //缩放比例 this.clipWidth = 0; //裁剪框宽度 this.clipHeight = 0; //裁剪框高度 this.clipX = 0; //裁剪框x this.clipY = 0; //裁剪框y } set ncUrl(value) { setTimeout(() => { //加延迟,防止其他传入参数未获取到 this.readImage(value); }); } ; //确认裁剪时是否下载图片 set ncDownload(value) { this.downloadMode = value !== null && value !== undefined && value !== false && value !== 'false'; } //调整工具栏 set ncTool(value) { this.toolMode = value !== null && value !== undefined && value !== false && value !== 'false'; } //上传 set ncUpload(value) { this.uploadMode = value !== null && value !== undefined && value !== false && value !== 'false'; } ngOnInit() { this.clipImage = this.eleRef.nativeElement.querySelector('#clipImage'); this.clipPathImg = this.eleRef.nativeElement.querySelector('#clipPathImg'); this.clip = this.eleRef.nativeElement.querySelector('#clip'); if (this.uploadMode) { setTimeout(() => { this.file = this.eleRef.nativeElement.querySelector('#file'); // 监听上传状态 浏览图片 this.file.addEventListener('change', (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { this.readImage(reader.result); }; }); }); } //裁剪框缩放、拖拽 this.clipBoxZoom(); this.clipBpxDrag(); } //读取图片 readImage(url) { // 读取到的图片数据 this.clipImage.src = url; // 裁剪使用的图片 this.clipPathImg.src = url; //获取当前图片的宽高 this.getClipImageSize(url).then((res) => { // 初始化 this.init(); this.hasImage = true; }); } // 获取上传图片的当前尺寸和原始尺寸 getClipImageSize(dataurl) { return __awaiter(this, void 0, void 0, function* () { const data = yield new Promise((resolve) => { this.clipImage.onload = () => { resolve(this.clipImage); }; }); // 获取图片当前宽高 this.clipImageWidth = data.width; this.clipImageHeight = data.height; const data_1 = yield new Promise((resolve_1) => { // 获取图片原始宽高 let img = document.createElement('img'); img.src = dataurl; img.onload = () => { resolve_1(img); }; }); // 获取图片原始宽高 this.clipImageOriginWidth = data_1.width; this.clipImageOriginHeight = data_1.height; return yield Promise.resolve(); }); } // 初始化 init() { // 显示裁剪框 this.clip.style.display = 'block'; // 缩放比例 this.scale = this.clipImageOriginWidth / this.clipImageWidth; // 设置裁剪框的宽高 let clipWidth = Math.floor(this.clipImageWidth * this.ncClipSize); let clipHeight = Math.floor(this.clipImageHeight * this.ncClipSize); this.setClipSize(clipWidth, clipHeight); // 设置裁剪框的位置 let x = Math.floor((this.clipImageWidth - clipWidth) / 2); let y = Math.floor((this.clipImageHeight - clipHeight) / 2); this.setClipPosition(x, y); } // 设置裁剪框的尺寸 setClipSize(clipWidth, clipHeight) { this.clip.style.setProperty('--clipWidth', clipWidth + 'px'); this.clip.style.setProperty('--clipHeight', clipHeight + 'px'); this.clipWidth = clipWidth; this.clipHeight = clipHeight; } // 设置裁剪框的位置 setClipPosition(x, y) { this.clip.style.setProperty('--clipX', x + 'px'); this.clip.style.setProperty('--clipY', y + 'px'); this.clipX = x; this.clipY = y; // 设置裁剪阴影 this.setClipPath(); } // 设置裁剪阴影 setClipPath() { let lt = this.clip.offsetLeft + 'px' + ' ' + this.clip.offsetTop + 'px'; let rt = (this.clip.offsetLeft + this.clip.offsetWidth) + 'px' + ' ' + this.clip.offsetTop + 'px'; let rb = (this.clip.offsetLeft + this.clip.offsetWidth) + 'px' + ' ' + (this.clip.offsetTop + this.clip.offsetHeight) + 'px'; let lb = this.clip.offsetLeft + 'px' + ' ' + (this.clip.offsetTop + this.clip.offsetHeight) + 'px'; this.clipPathImg.style.setProperty('--clipPath', `polygon(${lt}, ${rt}, ${rb}, ${lb})`); } // 裁剪 clipImg(x, y, cutWidth, cutHeight, width, height) { return __awaiter(this, void 0, void 0, function* () { let canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; canvas.getContext('2d').drawImage(this.clipImage, x, y, cutWidth, cutHeight, 0, 0, width, height); //下载 if (this.downloadMode) { const a = document.createElement('a'); a.download = '裁剪图片'; a.href = canvas.toDataURL('image/png'); a.click(); } // 返回裁剪后的图片 return new Promise((resolve) => { if (this.ncImgType == 'base64') { resolve(canvas.toDataURL('image/png')); } else { canvas.toBlob((blob) => { resolve(new File([blob], 'clip.png', { type: 'image/png' })); }); } }); }); } //确认裁剪 confirm() { return __awaiter(this, void 0, void 0, function* () { let res = yield this.clipImg(this.clip.offsetLeft * this.scale, this.clip.offsetTop * this.scale, this.clip.offsetWidth * this.scale, this.clip.offsetHeight * this.scale, this.clip.offsetWidth, this.clip.offsetHeight); this.ncConfirm.emit(res); }); } //裁剪框的拖拽 clipBpxDrag() { // 鼠标按下 this.clip.onmousedown = (e) => { // 偏移量 let py = { x: e.clientX - this.clip.offsetLeft, y: e.clientY - this.clip.offsetTop }; // 鼠标移动 window.onmousemove = (e) => { // 鼠标移动的距离 let moveX = e.clientX - py.x; let moveY = e.clientY - py.y; // 裁剪框的位置 let left = moveX; let top = moveY; // 裁剪框的位置限制 if (left < 0) { left = 0; } if (top < 0) { top = 0; } if (left > this.clipImageWidth - this.clip.offsetWidth) { left = this.clipImageWidth - this.clip.offsetWidth; } if (top > this.clipImageHeight - this.clip.offsetHeight) { top = this.clipImageHeight - this.clip.offsetHeight; } // 设置裁剪框的位置 this.setClipPosition(left, top); }; // 鼠标松开 window.onmouseup = () => { window.onmouseup = null; window.onmousemove = null; }; }; } //裁剪框缩放 clipBoxZoom() { // 获取裁剪框的四个角 let zoomDom = { lt: this.eleRef.nativeElement.querySelector('.lt'), rt: this.eleRef.nativeElement.querySelector('.rt'), rb: this.eleRef.nativeElement.querySelector('.rb'), lb: this.eleRef.nativeElement.querySelector('.lb'), }; // 鼠标按下时的位置 let zoomInfo = { x: 0, y: 0, minWidth: this.ncClipMinWidth, minHeight: this.ncClipMinHeight }; // 鼠标按下时裁剪框的位置 for (let key in zoomDom) { zoomDom[key].onmousedown = (e) => { // 禁止冒泡 e.stopPropagation(); // 鼠标按下时的位置 zoomInfo.x = e.clientX; zoomInfo.y = e.clientY; // 鼠标移动 window.onmousemove = (e) => { // 鼠标移动的距离 let moveX = e.clientX - zoomInfo.x; let moveY = e.clientY - zoomInfo.y; // 裁剪框的位置 let left = 0; let top = 0; // 裁剪框的尺寸 let width = 0; let height = 0; // 左上角 if (key === 'lt') { // 裁剪框的位置 left = this.clip.offsetLeft + moveX; top = this.clip.offsetTop + moveY; // 裁剪框的尺寸 width = this.clip.offsetWidth - moveX; height = this.clip.offsetHeight - moveY; // 裁剪框的位置限制 if (left < 0) { left = 0; // 原来宽度+原来left width = this.clip.offsetWidth + this.clip.offsetLeft; } if (top < 0) { top = 0; // 原来高度+原来top height = this.clip.offsetHeight + this.clip.offsetTop; } } // 右上角 if (key === 'rt') { // 裁剪框的位置 top = this.clip.offsetTop + moveY; left = this.clip.offsetLeft; // 裁剪框的尺寸 width = this.clip.offsetWidth + moveX; height = this.clip.offsetHeight - moveY; // 裁剪框的位置限制 if (top < 0) { top = 0; // 原来高度+原来top height = this.clip.offsetHeight + this.clip.offsetTop; } if (left + width > this.clipImageWidth) { // 图片当前宽-原来left width = this.clipImageWidth - left; } } // 右下角 if (key === 'rb') { // 裁剪框的尺寸 top = this.clip.offsetTop; left = this.clip.offsetLeft; width = this.clip.offsetWidth + moveX; height = this.clip.offsetHeight + moveY; // 裁剪框的位置限制 // 当前的left+当前的width>图片当前宽 if (this.clip.offsetLeft + width > this.clipImageWidth) { width = this.clipImageWidth - left; } // 当前的top+当前的height>图片当前宽 if (this.clip.offsetTop + height > this.clipImageHeight) { height = this.clipImageHeight - top; } } // 左下角 if (key === 'lb') { // 裁剪框的位置 left = this.clip.offsetLeft + moveX; top = this.clip.offsetTop; // 裁剪框的尺寸 width = this.clip.offsetWidth - moveX; height = this.clip.offsetHeight + moveY; // 裁剪框的位置限制 if (left < 0) { left = 0; width = this.clip.offsetWidth + this.clip.offsetLeft; } // 当前的top+当前的height>图片当前宽 if (this.clip.offsetTop + height > this.clipImageHeight) { height = this.clipImageHeight - top; } } // 裁剪框的限制 ({ width, height, left, top } = this.ClipWidthPosition(zoomInfo, width, height, left, top)); // 设置裁剪框的位置 this.setClipPosition(left, top); // 设置裁剪框的尺寸 this.setClipSize(width, height); // 记录上一次的位置 zoomInfo.x = e.clientX; zoomInfo.y = e.clientY; }; // 鼠标松开 window.onmouseup = () => { window.onmouseup = null; window.onmousemove = null; }; }; } } // 裁剪框的宽高限制以及位置限制 ClipWidthPosition(zoomInfo, w, h, l, t) { let width = w; //裁剪框宽度 let height = h; //裁剪框的高度 let left = l; //裁剪框的left let top = t; //裁剪框的top if (w < zoomInfo.minWidth) { width = zoomInfo.minWidth; left = this.clip.offsetLeft; } if (h < zoomInfo.minHeight) { height = zoomInfo.minHeight; top = this.clip.offsetTop; } return { width, height, left, top }; } //尺寸输入框变化 sizeInputChange() { this.setClipSize(this.clipWidth, this.clipHeight); this.setClipPosition(this.clipX, this.clipY); } } ImgClipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ImgClipComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ImgClipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: ImgClipComponent, selector: "nc-img-clip", inputs: { ncUrl: "ncUrl", ncImgType: "ncImgType", ncWidth: "ncWidth", ncClipSize: "ncClipSize", ncClipMinWidth: "ncClipMinWidth", ncClipMinHeight: "ncClipMinHeight", ncDownload: "ncDownload", ncTool: "ncTool", ncUpload: "ncUpload" }, outputs: { ncConfirm: "ncConfirm" }, ngImport: i0, template: "<div class=\"clipContainer\" [ngStyle]=\"{'width': ncWidth + 'px'}\">\r\n <div class=\"clipBtnContainer\">\r\n <div *ngIf=\"uploadMode\" class=\"filebutton\">\r\n <div>\u4E0A\u4F20\u56FE\u7247</div>\r\n <input type=\"file\" id=\"file\" class=\"fileInput\" accept=\"image/*\">\r\n </div>\r\n <div *ngIf=\"hasImage\" class=\"confirmBtn\" (click)=\"confirm()\">\u786E\u5B9A</div>\r\n </div>\r\n <div class=\"clipImageCantainer\">\r\n <img id=\"clipImage\" src=\"\" crossorigin=\"anonymous\">\r\n <img id=\"clipPathImg\" src=\"\">\r\n <div id=\"clip\">\r\n <div class=\"corner lt\"></div>\r\n <div class=\"corner rt\"></div>\r\n <div class=\"corner rb\"></div>\r\n <div class=\"corner lb\"></div>\r\n </div>\r\n </div>\r\n <div class=\"bottomInputContainer\" *ngIf=\"hasImage && toolMode\">\r\n <div class=\"inputRow\">\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">\u5BBD\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipWidth\" [min]=\"ncClipMinWidth\"\r\n [max]=\"clipImageWidth\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">\u9AD8\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipHeight\" [min]=\"ncClipMinHeight\"\r\n [max]=\"clipImageHeight\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n </div>\r\n <div class=\"inputRow\">\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">X\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipX\" [min]=\"0\"\r\n [max]=\"clipImageWidth - clipWidth\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">Y\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipY\" [min]=\"0\"\r\n [max]=\"clipImageHeight - clipHeight\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".clipContainer{margin:5px}.clipContainer .clipBtnContainer{display:flex;align-items:center;justify-content:space-between;margin-bottom:5px}.clipContainer .clipBtnContainer .filebutton{position:relative;display:inline-block;overflow:hidden}.clipContainer .clipBtnContainer .filebutton input{position:absolute;top:0;opacity:0;font-size:0;width:100%;height:100%;cursor:pointer}.clipContainer .clipBtnContainer .filebutton div{font-size:13px;background:#00aeff;color:#fff;padding:4px 8px;border-radius:3px}.clipContainer .clipBtnContainer .confirmBtn{font-size:13px;background:#00aeff;color:#fff;padding:4px 8px;border-radius:3px;cursor:pointer}.clipContainer .clipImageCantainer{width:100%;position:relative}.clipContainer .clipImageCantainer:after{content:\"\";position:absolute;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.5);z-index:1}.clipContainer .clipImageCantainer img{width:100%;top:0;left:0;display:block}.clipContainer .clipImageCantainer #clipPathImg{position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;clip-path:var(--clipPath)}.clipContainer .clipImageCantainer #clip{position:absolute;top:0;left:0;width:var(--clipWidth);height:var(--clipHeight);left:var(--clipX);top:var(--clipY);z-index:3;cursor:move;border:1px dashed white;display:none}.clipContainer .clipImageCantainer #clip .corner{position:absolute;width:10px;height:10px;background:#fff;border:1px solid #000}.clipContainer .clipImageCantainer #clip .lt{cursor:nw-resize;left:-5px;top:-5px}.clipContainer .clipImageCantainer #clip .rt{cursor:ne-resize;right:-5px;top:-5px}.clipContainer .clipImageCantainer #clip .lb{cursor:sw-resize;left:-5px;bottom:-5px}.clipContainer .clipImageCantainer #clip .rb{cursor:se-resize;right:-5px;bottom:-5px}.clipContainer .bottomInputContainer .inputRow{display:flex;align-items:center;margin-top:5px}.clipContainer .bottomInputContainer .inputRow .inputCol{display:flex;align-items:center;margin-right:10px}.clipContainer .bottomInputContainer .inputRow .inputCol .rowLabel{width:30px;display:flex;justify-content:flex-end;color:#b9b9b9;mix-blend-mode:difference}.clipContainer .bottomInputContainer .inputRow .inputCol .sizeInput{width:70px}\n"], directives: [{ type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ImgClipComponent, decorators: [{ type: Component, args: [{ selector: 'nc-img-clip', templateUrl: './img-clip.component.html', styleUrls: ['./img-clip.component.less'] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { ncUrl: [{ type: Input }], ncConfirm: [{ type: Output }], ncImgType: [{ type: Input }], ncWidth: [{ type: Input }], ncClipSize: [{ type: Input }], ncClipMinWidth: [{ type: Input }], ncClipMinHeight: [{ type: Input }], ncDownload: [{ type: Input }], ncTool: [{ type: Input }], ncUpload: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1nLWNsaXAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvY29tcG9uZW50cy9pbWctY2xpcC9pbWctY2xpcC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9jb21wb25lbnRzL2ltZy1jbGlwL2ltZy1jbGlwLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFjLFlBQVksRUFBRSxLQUFLLEVBQVUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7O0FBTzNGLE1BQU0sT0FBTyxnQkFBZ0I7SUErQ3pCLFlBQW9CLE1BQWtCO1FBQWxCLFdBQU0sR0FBTixNQUFNLENBQVk7UUF4QzVCLGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDLENBQUEsUUFBUTtRQUN4QyxjQUFTLEdBQXNCLFFBQVEsQ0FBQyxDQUFBLFlBQVk7UUFDcEQsWUFBTyxHQUFXLEdBQUcsQ0FBQyxDQUFBLE1BQU07UUFDNUIsZUFBVSxHQUFXLEdBQUcsQ0FBQyxDQUFBLGVBQWU7UUFDeEMsbUJBQWMsR0FBVyxFQUFFLENBQUMsQ0FBQSxTQUFTO1FBQ3JDLG9CQUFlLEdBQVcsRUFBRSxDQUFDLENBQUEsU0FBUztRQWMvQyxpQkFBWSxHQUFZLEtBQUssQ0FBQztRQUM5QixhQUFRLEdBQVksS0FBSyxDQUFDO1FBQzFCLGVBQVUsR0FBWSxLQUFLLENBQUM7UUFFNUIsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUsxQixTQUFTO1FBQ1QsbUJBQWMsR0FBVyxDQUFDLENBQUM7UUFDM0Isb0JBQWUsR0FBVyxDQUFDLENBQUM7UUFDNUIsU0FBUztRQUNULHlCQUFvQixHQUFXLENBQUMsQ0FBQztRQUNqQywwQkFBcUIsR0FBVyxDQUFDLENBQUM7UUFDbEMsVUFBSyxHQUFXLENBQUMsQ0FBQyxDQUFBLE1BQU07UUFDeEIsY0FBUyxHQUFXLENBQUMsQ0FBQyxDQUFB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LEtBQUssRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFFRCxTQUFTO0lBQ1QsZUFBZTtRQUNYLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRCxDQUFDOzs2R0ExWFEsZ0JBQWdCO2lHQUFoQixnQkFBZ0Isa1VDUDdCLHc0RUE0Q007MkZEckNPLGdCQUFnQjtrQkFMNUIsU0FBUzttQkFBQztvQkFDUCxRQUFRLEVBQUUsYUFBYTtvQkFDdkIsV0FBVyxFQUFFLDJCQUEyQjtvQkFDeEMsU0FBUyxFQUFFLENBQUMsMkJBQTJCLENBQUM7aUJBQzNDO2lHQUVnQixLQUFLO3NCQUFqQixLQUFLO2dCQU1JLFNBQVM7c0JBQWxCLE1BQU07Z0JBQ0UsU0FBUztzQkFBakIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxjQUFjO3NCQUF0QixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRU8sVUFBVTtzQkFBdEIsS0FBSztnQkFJTyxNQUFNO3NCQUFsQixLQUFLO2dCQUlPLFFBQVE7c0JBQXBCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiAnbmMtaW1nLWNsaXAnLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2ltZy1jbGlwLmNvbXBvbmVudC5odG1sJyxcclxuICAgIHN0eWxlVXJsczogWycuL2ltZy1jbGlwLmNvbXBvbmVudC5sZXNzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIEltZ0NsaXBDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG4gICAgQElucHV0KCkgc2V0IG5jVXJsKHZhbHVlOiBzdHJpbmcpIHtcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgLy/liqDlu7bov5/vvIzpmLLmraLlhbbku5bkvKDlhaXlj4LmlbDmnKrojrflj5bliLBcclxuICAgICAgICAgICAgdGhpcy5yZWFkSW1hZ2UodmFsdWUpO1xyXG4gICAgICAgIH0pXHJcbiAgICB9O1xyXG4gICAgQE91dHB1dCgpIG5jQ29uZmlybSA9IG5ldyBFdmVudEVtaXR0ZXIoKTsvL+ehruiupOijgeWJquWbnuiwg1xyXG4gICAgQElucHV0KCkgbmNJbWdUeXBlOiAnYmFzZTY0JyB8ICdmaWxlJyA9ICdiYXNlNjQnOy8v6KOB5Ymq5Zue6LCD6L+U5Zue5Zu+54mH5qC85byPXHJcbiAgICBASW5wdXQoKSBuY1dpZHRoOiBudW1iZXIgPSAzMDA7Ly/lrrnlmajlrr3luqZcclxuICAgIEBJbnB1dCgpIG5jQ2xpcFNpemU6IG51bWJlciA9IDAuNzsvL+m7mOiupOijgeWJquahhueahOWwuuWvuOWNoOWbvueJh+avlOS+i1xyXG4gICAgQElucHV0KCkgbmNDbGlwTWluV2lkdGg6IG51bWJlciA9IDUwOy8v6KOB5Ymq5qGG5pyA5bCP5a695bqmXHJcbiAgICBASW5wdXQoKSBuY0NsaXBNaW5IZWlnaHQ6IG51bWJlciA9IDUwOy8v6KOB5Ymq5qGG5pyA5bCP6auY5bqmXHJcbiAgICAvL+ehruiupOijgeWJquaXtuaYr+WQpuS4i+i9veWbvueJh1xyXG4gICAgQElucHV0KCkgc2V0IG5jRG93bmxvYWQodmFsdWU6IGJvb2xlYW4gfCBzdHJpbmcpIHtcclxuICAgICAgICB0aGlzLmRvd25sb2FkTW9kZSA9IHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IGZhbHNlICYmIHZhbHVlICE9PSAnZmFsc2UnO1xyXG4gICAgfVxyXG4gICAgLy/osIPmlbTlt6XlhbfmoI9cclxuICAgIEBJbnB1dCgpIHNldCBuY1Rvb2wodmFsdWU6IGJvb2xlYW4gfCBzdHJpbmcpIHtcclxuICAgICAgICB0aGlzLnRvb2xNb2RlID0gdmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZSAhPT0gZmFsc2UgJiYgdmFsdWUgIT09ICdmYWxzZSc7XHJcbiAgICB9XHJcbiAgICAvL+S4iuS8oFxyXG4gICAgQElucHV0KCkgc2V0IG5jVXBsb2FkKHZhbHVlOiBib29sZWFuIHwgc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy51cGxvYWRNb2RlID0gdmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZSAhPT0gZmFsc2UgJiYgdmFsdWUgIT09ICdmYWxzZSc7XHJcbiAgICB9XHJcblxyXG4gICAgZG93bmxvYWRNb2RlOiBib29sZWFuID0gZmFsc2U7XHJcbiAgICB0b29sTW9kZTogYm9vbGVhbiA9IGZhbHNlO1xyXG4gICAgdXBsb2FkTW9kZTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgIGhhc0ltYWdlOiBib29sZWFuID0gZmFsc2U7XHJcbiAgICBmaWxlOiBhbnk7Ly9maWxl6YCJ5oup5qGGXHJcbiAgICBjbGlwSW1hZ2U6IGFueTsvL+ijgeWJquiDjOaZr+WbvueJh1xyXG4gICAgY2xpcFBhdGhJbWc6IGFueTsvL+ijgeWJquS9v+eUqOeahOWbvueJh1xyXG4gICAgY2xpcDogYW55Oy8v6KOB5Ymq5qGGXHJcbiAgICAvLyDlm77niYflvZPliY3lrr3pq5hcclxuICAgIGNsaXBJbWFnZVdpZHRoOiBudW1iZXIgPSAwO1xyXG4gICAgY2xpcEltYWdlSGVpZ2h0OiBudW1iZXIgPSAwO1xyXG4gICAgLy8g5Zu+54mH5Y6f5aeL5a696auYXHJcbiAgICBjbGlwSW1hZ2VPcmlnaW5XaWR0aDogbnVtYmVyID0gMDtcclxuICAgIGNsaXBJbWFnZU9yaWdpbkhlaWdodDogbnVtYmVyID0gMDtcclxuICAgIHNjYWxlOiBudW1iZXIgPSAwOy8v57yp5pS+5q+U5L6LXHJcbiAgICBjbGlwV2lkdGg6IG51bWJlciA9IDA7Ly/oo4HliarmoYblrr3luqZcclxuICAgIGNsaXBIZWlnaHQ6IG51bWJlciA9IDA7Ly/oo4HliarmoYbpq5jluqZcclxuICAgIGNsaXBYOiBudW1iZXIgPSAwOy8v6KOB5Ymq5qGGeFxyXG4gICAgY2xpcFk6IG51bWJlciA9IDA7Ly/oo4HliarmoYZ5XHJcblxyXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBlbGVSZWY6IEVsZW1lbnRSZWYpIHsgfVxyXG5cclxuICAgIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuY2xpcEltYWdlID0gdGhpcy5lbGVSZWYubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCcjY2xpcEltYWdlJyk7XHJcbiAgICAgICAgdGhpcy5jbGlwUGF0aEltZyA9IHRoaXMuZWxlUmVmLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcignI2NsaXBQYXRoSW1nJyk7XHJcbiAgICAgICAgdGhpcy5jbGlwID0gdGhpcy5lbGVSZWYubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCcjY2xpcCcpO1xyXG4gICAgICAgIGlmICh0aGlzLnVwbG9hZE1vZGUpIHtcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmZpbGUgPSB0aGlzLmVsZVJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJyNmaWxlJyk7XHJcbiAgICAgICAgICAgICAgICAvLyDnm5HlkKzkuIrkvKDnirbmgIEg5rWP6KeI5Zu+54mHXHJcbiAgICAgICAgICAgICAgICB0aGlzLmZpbGUuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKGU6IGFueSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbGUgPSBlLnRhcmdldC5maWxlc1swXTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVhZEltYWdlKHJlYWRlci5yZXN1bHQpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8v6KOB5Ymq5qGG57yp5pS+44CB5ouW5ou9XHJcbiAgICAgICAgdGhpcy5jbGlwQm94Wm9vbSgpO1xyXG4gICAgICAgIHRoaXMuY2xpcEJweERyYWcoKTtcclxuICAgIH1cclxuXHJcbiAgICAvL+ivu+WPluWbvueJh1xyXG4gICAgcmVhZEltYWdlKHVybDogYW55KSB7XHJcbiAgICAgICAgLy8g6K+75Y+W5Yiw55qE5Zu+54mH5pWw5o2uXHJcbiAgICAgICAgdGhpcy5jbGlwSW1hZ2Uuc3JjID0gdXJsO1xyXG4gICAgICAgIC8vIOijgeWJquS9v+eUqOeahOWbvueJh1xyXG4gICAgICAgIHRoaXMuY2xpcFBhdGhJbWcuc3JjID0gdXJsO1xyXG4gICAgICAgIC8v6I635Y+W5b2T5YmN5Zu+54mH55qE5a696auYXHJcbiAgICAgICAgdGhpcy5nZXRDbGlwSW1hZ2VTaXplKHVybCkudGhlbigocmVzOiBhbnkpID0+IHtcclxuICAgICAgICAgICAgLy8g5Yid5aeL5YyWXHJcbiAgICAgICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgICAgICAgICB0aGlzLmhhc0ltYWdlID0gdHJ1ZTtcclxuICAgICAgICB9KVxyXG4gICAgfVxyXG5cclxuICAgIC8vIOiOt+WPluS4iuS8oOWbvueJh+eahOW9k+WJjeWwuuWvuOWSjOWOn+Wni+WwuuWvuFxyXG4gICAgYXN5bmMgZ2V0Q2xpcEltYWdlU2l6ZShkYXRhdXJsOiBhbnkpIHtcclxuICAgICAgICBjb25zdCBkYXRhOiBhbnkgPSBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmNsaXBJbWFnZS5vbmxvYWQgPSAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICByZXNvbHZlKHRoaXMuY2xpcEltYWdlKTtcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuICAgICAgICAvLyDojrflj5blm77niYflvZPliY3lrr3pq5hcclxuICAgICAgICB0aGlzLmNsaXBJbWFnZVdpZHRoID0gZGF0YS53aWR0aDtcclxuICAgICAgICB0aGlzLmNsaXBJbWFnZUhlaWdodCA9IGRhdGEuaGVpZ2h0O1xyXG4gICAgICAgIGNvbnN0IGRhdGFfMTogYW55ID0gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmVfMSkgPT4ge1xyXG4gICAgICAgICAgICAvLyDojrflj5blm77niYfljp/lp4vlrr3pq5hcclxuICAgICAgICAgICAgbGV0IGltZyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpO1xyXG4gICAgICAgICAgICBpbWcuc3JjID0gZGF0YXVybDtcclxuICAgICAgICAgICAgaW1nLm9ubG9hZCA9ICgpID0+IHtcclxuICAgICAgICAgICAgICAgIHJlc29sdmVfMShpbWcpO1xyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIC8vIOiOt+WPluWbvueJh+WOn+Wni+WuvemrmFxyXG4gICAgICAgIHRoaXMuY2xpcEltYWdlT3JpZ2luV2lkdGggPSBkYXRhXzEud2lkdGg7XHJcbiAgICAgICAgdGhpcy5jbGlwSW1hZ2VPcmlnaW5IZWlnaHQgPSBkYXRhXzEuaGVpZ2h0O1xyXG4gICAgICAgIHJldHVybiBhd2FpdCBQcm9taXNlLnJlc29sdmUoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyDliJ3lp4vljJZcclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgLy8g5pi+56S66KOB5Ymq5qGGXHJcbiAgICAgICAgdGhpcy5jbGlwLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgIC8vIOe8qeaUvuavlOS+i1xyXG4gICAgICAgIHRoaXMuc2NhbGUgPSB0aGlzLmNsaXBJbWFnZU9yaWdpbldpZHRoIC8gdGhpcy5jbGlwSW1hZ2VXaWR0aDtcclxuICAgICAgICAvLyDorr7nva7oo4HliarmoYbnmoTlrr3pq5hcclxuICAgICAgICBsZXQgY2xpcFdpZHRoID0gTWF0aC5mbG9vcih0aGlzLmNsaXBJbWFnZVdpZHRoICogdGhpcy5uY0NsaXBTaXplKTtcclxuICAgICAgICBsZXQgY2xpcEhlaWdodCA9IE1hdGguZmxvb3IodGhpcy5jbGlwSW1hZ2VIZWlnaHQgKiB0aGlzLm5jQ2xpcFNpemUpO1xyXG4gICAgICAgIHRoaXMuc2V0Q2xpcFNpemUoY2xpcFdpZHRoLCBjbGlwSGVpZ2h0KTtcclxuXHJcbiAgICAgICAgLy8g6K6+572u6KOB5Ymq5qGG55qE5L2N572uXHJcbiAgICAgICAgbGV0IHggPSBNYXRoLmZsb29yKCh0aGlzLmNsaXBJbWFnZVdpZHRoIC0gY2xpcFdpZHRoKSAvIDIpO1xyXG4gICAgICAgIGxldCB5ID0gTWF0aC5mbG9vcigodGhpcy5jbGlwSW1hZ2VIZWlnaHQgLSBjbGlwSGVpZ2h0KSAvIDIpO1xyXG4gICAgICAgIHRoaXMuc2V0Q2xpcFBvc2l0aW9uKHgsIHkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIOiuvue9ruijgeWJquahhueahOWwuuWvuFxyXG4gICAgc2V0Q2xpcFNpemUoY2xpcFdpZHRoOiBudW1iZXIsIGNsaXBIZWlnaHQ6IG51bWJlcikge1xyXG4gICAgICAgIHRoaXMuY2xpcC5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1jbGlwV2lkdGgnLCBjbGlwV2lkdGggKyAncHgnKTtcclxuICAgICAgICB0aGlzLmNsaXAuc3R5bGUuc2V0UHJvcGVydHkoJy0tY2xpcEhlaWdodCcsIGNsaXBIZWlnaHQgKyAncHgnKTtcclxuICAgICAgICB0aGlzLmNsaXBXaWR0aCA9IGNsaXBXaWR0aDtcclxuICAgICAgICB0aGlzLmNsaXBIZWlnaHQgPSBjbGlwSGVpZ2h0O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIOiuvue9ruijgeWJquahhueahOS9jee9rlxyXG4gICAgc2V0Q2xpcFBvc2l0aW9uKHg6IG51bWJlciwgeTogbnVtYmVyKSB7XHJcbiAgICAgICAgdGhpcy5jbGlwLnN0eWxlLnNldFByb3BlcnR5KCctLWNsaXBYJywgeCArICdweCcpO1xyXG4gICAgICAgIHRoaXMuY2xpcC5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1jbGlwWScsIHkgKyAncHgnKTtcclxuICAgICAgICB0aGlzLmNsaXBYID0geDtcclxuICAgICAgICB0aGlzLmNsaXBZID0geTtcclxuICAgICAgICAvLyDorr7nva7oo4HliarpmLTlvbFcclxuICAgICAgICB0aGlzLnNldENsaXBQYXRoKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8g6K6+572u6KOB5Ymq6Zi05b2xXHJcbiAgICBzZXRDbGlwUGF0aCgpIHtcclxuICAgICAgICBsZXQgbHQgPSB0aGlzLmNsaXAub2Zmc2V0TGVmdCArICdweCcgKyAnICcgKyB0aGlzLmNsaXAub2Zmc2V0VG9wICsgJ3B4JztcclxuICAgICAgICBsZXQgcnQgPSAodGhpcy5jbGlwLm9mZnNldExlZnQgKyB0aGlzLmNsaXAub2Zmc2V0V2lkdGgpICsgJ3B4JyArICcgJyArIHRoaXMuY2xpcC5vZmZzZXRUb3AgKyAncHgnO1xyXG4gICAgICAgIGxldCByYiA9ICh0aGlzLmNsaXAub2Zmc2V0TGVmdCArIHRoaXMuY2xpcC5vZmZzZXRXaWR0aCkgKyAncHgnICsgJyAnICsgKHRoaXMuY2xpcC5vZmZzZXRUb3AgKyB0aGlzLmNsaXAub2Zmc2V0SGVpZ2h0KSArICdweCc7XHJcbiAgICAgICAgbGV0IGxiID0gdGhpcy5jbGlwLm9mZnNldExlZnQgKyAncHgnICsgJyAnICsgKHRoaXMuY2xpcC5vZmZzZXRUb3AgKyB0aGlzLmNsaXAub2Zmc2V0SGVpZ2h0KSArICdweCc7XHJcbiAgICAgICAgdGhpcy5jbGlwUGF0aEltZy5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1jbGlwUGF0aCcsIGBwb2x5Z29uKCR7bHR9LCAke3J0fSwgJHtyYn0sICR7bGJ9KWApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIOijgeWJqlxyXG4gICAgYXN5bmMgY2xpcEltZyh4OiBudW1iZXIsIHk6IG51bWJlciwgY3V0V2lkdGg6IG51bWJlciwgY3V0SGVpZ2h0OiBudW1iZXIsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyKSB7XHJcbiAgICAgICAgbGV0IGNhbnZhczogSFRNTENhbnZhc0VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcclxuICAgICAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcclxuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG4gICAgICAgIGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpIS5kcmF3SW1hZ2UodGhpcy5jbGlwSW1hZ2UsIHgsIHksIGN1dFdpZHRoLCBjdXRIZWlnaHQsIDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xyXG5cclxuICAgICAgICAvL+S4i+i9vVxyXG4gICAgICAgIGlmICh0aGlzLmRvd25sb2FkTW9kZSkge1xyXG4gICAgICAgICAgICBjb25zdCBhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xyXG4gICAgICAgICAgICBhLmRvd25sb2FkID0gJ+ijgeWJquWbvueJhyc7XHJcbiAgICAgICAgICAgIGEuaHJlZiA9IGNhbnZhcy50b0RhdGFVUkwoJ2ltYWdlL3BuZycpO1xyXG4gICAgICAgICAgICBhLmNsaWNrKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyDov5Tlm57oo4HliarlkI7nmoTlm77niYdcclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRoaXMubmNJbWdUeXBlID09ICdiYXNlNjQnKSB7XHJcbiAgICAgICAgICAgICAgICByZXNvbHZlKGNhbnZhcy50b0RhdGFVUkwoJ2ltYWdlL3BuZycpKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGNhbnZhcy50b0Jsb2IoKGJsb2I6IGFueSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUobmV3IEZpbGUoW2Jsb2JdLCAnY2xpcC5wbmcnLCB7IHR5cGU6ICdpbWFnZS9wbmcnIH0pKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9