UNPKG

truly-ui

Version:

Web Components for Desktop Applications.

222 lines (220 loc) 39.3 kB
/* MIT License Copyright (c) 2018 Temainfo Software Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { debounceTime } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "../i18n/i18n.service"; import * as i2 from "../lightbox/services/lightbox.service"; import * as i3 from "@angular/common"; import * as i4 from "@angular/forms"; import * as i5 from "../icons/icons"; import * as i6 from "../textarea/textarea"; import * as i7 from "../thumbnail/thumbnail"; export class TlUpload { set imageList(value) { this._imageList = value.sort((a, b) => a.index - b.index); } get imageList() { return this._imageList; } constructor(i18nService, lightboxService) { this.i18nService = i18nService; this.lightboxService = lightboxService; this.type = 'dragndrop'; this.showAsList = true; this.action = ''; this.height = '100%'; this.resizeDragndrop = false; this.isLoading = false; this.debounce = 380; this.deleteControl = true; this.viewControl = true; this.acceptFiles = 'image/*,application/pdf'; this.view = new EventEmitter(); this.uploadChange = new EventEmitter(); this.deleteChange = new EventEmitter(); this.updateChange = new EventEmitter(); this.filtering = new Subject(); this.uploading = new Subject(); this.subscription = new Subscription(); this._imageList = []; this.boxDescription = this.i18nService.getLocale().Upload.boxDescription; this.placeholder = this.i18nService.getLocale().Upload.placeholder; this.upload = this.i18nService.getLocale().Upload.upload; } ngOnInit() { this.filtering.pipe(debounceTime(this.debounce)).subscribe((value) => { this.updateChange.emit(value); }); this.subscription.add(this.uploading.subscribe(value => { this.uploadChange.emit(value); })); } open($event) { if (this.inputSingle || this.inputMultiple) { this.type !== 'dragndrop' ? this.inputSingle.nativeElement.click() : this.inputMultiple.nativeElement.click(); $event.stopPropagation(); } } onDragOver(ev) { ev.stopPropagation(); ev.preventDefault(); ev.dataTransfer.dropEffect = 'copy'; } onDrop(ev) { ev.stopPropagation(); ev.preventDefault(); const fileList = ev.dataTransfer.files; this.readFiles(fileList); } onChangeDescription() { this.filtering.next(this.imageList); } readFiles(fileList) { for (let i = 0; i < fileList.length; i++) { this.readFile(fileList[i], i).then((value) => { value = Object.assign({ title: '', description: '', type: this.getBase64MimeType(value.file) }, value); value.index = this.imageList.length; this.imageList = [...this.imageList, value]; if (fileList.length <= this.imageList.length) { this.uploading.next(this.imageList); } }); } } readFile(file, index) { const reader = new FileReader(); return new Promise(resolve => { reader.readAsDataURL(file); reader.onloadend = (event) => { resolve({ index: index, file: event.target.result }); }; }); } viewImage($event, file) { $event.stopPropagation(); if (this.type === 'box') { return this.view.emit(this.imageSrc); } this.lightboxService.create(this.imageList, file); } remove(file, imgSrc, event) { event.stopPropagation(); if (imgSrc) { this.imageSrc = null; this.deleteChange.emit(this.imageSrc); } if (file) { this.imageList = this.imageList.filter((item, idx) => file.index !== idx); this.imageList.forEach((item, idx) => item.index = idx); this.deleteChange.emit(this.imageList); } } hasRisize() { return (this.resizeDragndrop && this.type === 'dragndrop' && this.imageList.length > 0); } onChange($event) { if ($event.target.files.length > 0) { const filesAccepet = this.filterFilesAccpet($event.target.files); if (this.type === 'dragndrop') { return this.readFiles(filesAccepet); } const reader = new FileReader(); reader.readAsDataURL(filesAccepet[0]); reader.onload = (event) => { this.imageSrc = event.target.result; this.uploadChange.emit(this.imageSrc); }; } } filterFilesAccpet(files) { const acceptFiles = []; for (let i = 0; i < files.length; i++) { const regexExpresison = this.acceptFiles .replace(/\*/g, '.\*') .replace(/\,/g, '|'); const isAccept = new RegExp(regexExpresison).test(files[i].type); if (isAccept) { acceptFiles.push(files[i]); } } return acceptFiles; } getBase64MimeType(encoded) { let result = null; if (typeof encoded !== 'string') { return result; } const mime = encoded.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/); if (mime && mime.length) { result = mime[1]; } return result || 'image'; } } /** @nocollapse */ TlUpload.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TlUpload, deps: [{ token: i1.I18nService }, { token: i2.LightboxService }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ TlUpload.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TlUpload, selector: "tl-upload", inputs: { type: "type", showAsList: "showAsList", action: "action", height: "height", resizeDragndrop: "resizeDragndrop", imageList: "imageList", imageSrc: "imageSrc", imageSrcMimeType: "imageSrcMimeType", isLoading: "isLoading", debounce: "debounce", deleteControl: "deleteControl", viewControl: "viewControl", acceptFiles: "acceptFiles" }, outputs: { view: "view", uploadChange: "uploadChange", deleteChange: "deleteChange", updateChange: "updateChange" }, viewQueries: [{ propertyName: "inputMultiple", first: true, predicate: ["inputMultiple"], descendants: true }, { propertyName: "inputSingle", first: true, predicate: ["inputSingle"], descendants: true }], ngImport: i0, template: "<div class=\"drag-wrapper\">\n <div *ngIf=\"type === 'dragndrop'\" class=\"dragndrop\"\n [style.height]=\"hasRisize() ? 'calc('+height+' - '+imageList.length * 90+'px)': height\" (click)=\"open($event)\"\n (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\">\n <ng-container *ngIf=\"imageList.length === 0 || showAsList; else imagesContainerTemplate\">\n <span><tl-icon class=\"icon\" [lib]=\"'fa'\" [style]=\"'fas'\">inbox</tl-icon></span>\n <p style=\"white-space: pre-line\">{{ boxDescription }}</p>\n <input #inputMultiple type=\"file\" style=\"display: none;\" (change)=\"onChange($event)\" multiple [accept]=\"acceptFiles\">\n </ng-container>\n\n <ng-template #imagesContainerTemplate>\n <div class=\"images-container\">\n <ng-container *ngFor=\"let item of imageList\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate; context: { $implicit: item }\"></ng-container>\n </ng-container>\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate\"></ng-container>\n </div>\n </ng-template>\n </div>\n <div class=\"image-list\" *ngIf=\"showAsList\"\n [style.maxHeight]=\"hasRisize() ? 'calc( '+height+' - 100px )': ''\">\n <ng-container *ngFor=\"let item of imageList\">\n <div class=\"image-item\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate; context: { $implicit: item }\"></ng-container>\n <tl-textarea class=\"image-description\" [(ngModel)]=\"item.description\" (ngModelChange)=\"onChangeDescription()\" [placeholder]=\"placeholder\"></tl-textarea>\n </div>\n </ng-container>\n </div>\n</div>\n\n\n<div *ngIf=\"type === 'box'\" (click)=\"open($event)\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate\"></ng-container>\n</div>\n\n<ng-template #uploadboxTemplate let-item>\n <input #inputSingle type=\"file\" style=\"display: none;\" (change)=\"onChange($event)\" [accept]=\"acceptFiles\">\n <tl-thumbnail\n [shape]=\"'square'\"\n [bordered]=\"!item\"\n [image]=\"item?.file || imageSrc\"\n [mimeType]=\"item?.type || imageSrcMimeType\"\n [emptyTemplate]=\"emptyTemplate\"\n [overlayTemplate]=\"controlsTemplate\">\n <ng-template #emptyTemplate>\n <tl-icon [lib]=\"'dx'\">add</tl-icon>\n <div class=\"upload-title\">{{ upload }}</div>\n </ng-template>\n <ng-template #controlsTemplate>\n <tl-icon *ngIf=\"viewControl\" style=\"margin-right: 5px; cursor: pointer\" (click)=\"viewImage($event, item || imageSrc)\" [lib]=\"'dx'\">find</tl-icon>\n <tl-icon *ngIf=\"deleteControl\" style=\"cursor: pointer\" (click)=\"remove(item, imageSrc, $event)\" [lib]=\"'dx'\">trash</tl-icon>\n </ng-template>\n </tl-thumbnail>\n</ng-template>\n", styles: [".dragndrop{position:relative;width:100%;height:100%;min-height:100px;text-align:center;background:#fafafa;border:1px dashed #d9d9d9;border-radius:2px;cursor:pointer;transition:border-color .3s;display:flex;align-items:center;justify-content:center;flex-flow:column;padding:10px 0;font-family:Segoe UI;box-sizing:border-box}.dragndrop>.images-container{position:relative;display:flex;align-items:center;justify-content:flex-start;min-height:80px;flex-wrap:wrap;width:100%}.dragndrop>.images-container>.image-item{padding:0 10px}.dragndrop:hover{border-color:#6c9}.dragndrop .icon{font-size:28px}.image-list{display:flex;flex-flow:column;overflow:auto}.image-list>.image-item{margin-top:10px;display:flex}.image-list>.image-item>.image-description{width:100%}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.TlIcons, selector: "tl-icon", inputs: ["icon", "lib", "style", "size", "animation", "color", "align"] }, { kind: "component", type: i6.TlTextarea, selector: "tl-textarea", inputs: ["label", "labelPlacement", "labelSize", "name", "placeholder", "height", "tabindex", "maxlength", "textAlign", "readonly", "disabled", "clearButton", "color", "withBorder", "resize", "showCount"], outputs: ["click", "focus", "blur", "clear", "overlayOrigin"] }, { kind: "component", type: i7.TlThumbnail, selector: "tl-thumbnail", inputs: ["image", "mimeType", "data", "bordered", "shape", "size", "showDeleteButton", "confirmationDeleteMessage", "showConfirmationOnDelete", "modalDeleteOptions", "overlayTemplate", "emptyTemplate"], outputs: ["clickThumbnail", "clickDeleteThumbail"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TlUpload, decorators: [{ type: Component, args: [{ selector: 'tl-upload', template: "<div class=\"drag-wrapper\">\n <div *ngIf=\"type === 'dragndrop'\" class=\"dragndrop\"\n [style.height]=\"hasRisize() ? 'calc('+height+' - '+imageList.length * 90+'px)': height\" (click)=\"open($event)\"\n (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\">\n <ng-container *ngIf=\"imageList.length === 0 || showAsList; else imagesContainerTemplate\">\n <span><tl-icon class=\"icon\" [lib]=\"'fa'\" [style]=\"'fas'\">inbox</tl-icon></span>\n <p style=\"white-space: pre-line\">{{ boxDescription }}</p>\n <input #inputMultiple type=\"file\" style=\"display: none;\" (change)=\"onChange($event)\" multiple [accept]=\"acceptFiles\">\n </ng-container>\n\n <ng-template #imagesContainerTemplate>\n <div class=\"images-container\">\n <ng-container *ngFor=\"let item of imageList\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate; context: { $implicit: item }\"></ng-container>\n </ng-container>\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate\"></ng-container>\n </div>\n </ng-template>\n </div>\n <div class=\"image-list\" *ngIf=\"showAsList\"\n [style.maxHeight]=\"hasRisize() ? 'calc( '+height+' - 100px )': ''\">\n <ng-container *ngFor=\"let item of imageList\">\n <div class=\"image-item\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate; context: { $implicit: item }\"></ng-container>\n <tl-textarea class=\"image-description\" [(ngModel)]=\"item.description\" (ngModelChange)=\"onChangeDescription()\" [placeholder]=\"placeholder\"></tl-textarea>\n </div>\n </ng-container>\n </div>\n</div>\n\n\n<div *ngIf=\"type === 'box'\" (click)=\"open($event)\">\n <ng-container *ngTemplateOutlet=\"uploadboxTemplate\"></ng-container>\n</div>\n\n<ng-template #uploadboxTemplate let-item>\n <input #inputSingle type=\"file\" style=\"display: none;\" (change)=\"onChange($event)\" [accept]=\"acceptFiles\">\n <tl-thumbnail\n [shape]=\"'square'\"\n [bordered]=\"!item\"\n [image]=\"item?.file || imageSrc\"\n [mimeType]=\"item?.type || imageSrcMimeType\"\n [emptyTemplate]=\"emptyTemplate\"\n [overlayTemplate]=\"controlsTemplate\">\n <ng-template #emptyTemplate>\n <tl-icon [lib]=\"'dx'\">add</tl-icon>\n <div class=\"upload-title\">{{ upload }}</div>\n </ng-template>\n <ng-template #controlsTemplate>\n <tl-icon *ngIf=\"viewControl\" style=\"margin-right: 5px; cursor: pointer\" (click)=\"viewImage($event, item || imageSrc)\" [lib]=\"'dx'\">find</tl-icon>\n <tl-icon *ngIf=\"deleteControl\" style=\"cursor: pointer\" (click)=\"remove(item, imageSrc, $event)\" [lib]=\"'dx'\">trash</tl-icon>\n </ng-template>\n </tl-thumbnail>\n</ng-template>\n", styles: [".dragndrop{position:relative;width:100%;height:100%;min-height:100px;text-align:center;background:#fafafa;border:1px dashed #d9d9d9;border-radius:2px;cursor:pointer;transition:border-color .3s;display:flex;align-items:center;justify-content:center;flex-flow:column;padding:10px 0;font-family:Segoe UI;box-sizing:border-box}.dragndrop>.images-container{position:relative;display:flex;align-items:center;justify-content:flex-start;min-height:80px;flex-wrap:wrap;width:100%}.dragndrop>.images-container>.image-item{padding:0 10px}.dragndrop:hover{border-color:#6c9}.dragndrop .icon{font-size:28px}.image-list{display:flex;flex-flow:column;overflow:auto}.image-list>.image-item{margin-top:10px;display:flex}.image-list>.image-item>.image-description{width:100%}\n"] }] }], ctorParameters: function () { return [{ type: i1.I18nService }, { type: i2.LightboxService }]; }, propDecorators: { type: [{ type: Input }], showAsList: [{ type: Input }], action: [{ type: Input }], height: [{ type: Input }], resizeDragndrop: [{ type: Input }], imageList: [{ type: Input, args: ['imageList'] }], imageSrc: [{ type: Input }], imageSrcMimeType: [{ type: Input }], isLoading: [{ type: Input }], debounce: [{ type: Input }], deleteControl: [{ type: Input }], viewControl: [{ type: Input }], acceptFiles: [{ type: Input }], inputMultiple: [{ type: ViewChild, args: ['inputMultiple', { static: false }] }], inputSingle: [{ type: ViewChild, args: ['inputSingle', { static: false }] }], view: [{ type: Output }], uploadChange: [{ type: Output }], deleteChange: [{ type: Output }], updateChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBsb2FkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdHJ1bHktdWkvc3JjL2NvbXBvbmVudHMvdXBsb2FkL3VwbG9hZC50cyIsIi4uLy4uLy4uLy4uL3Byb2plY3RzL3RydWx5LXVpL3NyYy9jb21wb25lbnRzL3VwbG9hZC91cGxvYWQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUFvQkU7QUFDRixPQUFPLEVBQUMsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQVUsTUFBTSxFQUFFLFNBQVMsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUd4RixPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUMsT0FBTyxFQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUMsTUFBTSxNQUFNLENBQUM7Ozs7Ozs7OztBQVEzQyxNQUFNLE9BQU8sUUFBUTtJQVluQixJQUNJLFNBQVMsQ0FBRSxLQUE2QjtRQUMxQyxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUUsQ0FBQztJQUM3RCxDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUEwQ0QsWUFBb0IsV0FBd0IsRUFBVSxlQUFnQztRQUFsRSxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUFVLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQTNEN0UsU0FBSSxHQUF3QixXQUFXLENBQUM7UUFFeEMsZUFBVSxHQUFHLElBQUksQ0FBQztRQUVsQixXQUFNLEdBQUcsRUFBRSxDQUFDO1FBRVosV0FBTSxHQUFHLE1BQU0sQ0FBQztRQUVoQixvQkFBZSxHQUFHLEtBQUssQ0FBQztRQWV4QixjQUFTLEdBQUcsS0FB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QkFFRyxZQUFZO3NCQUFyQixNQUFNO2dCQUVHLFlBQVk7c0JBQXJCLE1BQU07Z0JBRUcsWUFBWTtzQkFBckIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gICAgTUlUIExpY2Vuc2VcblxuICAgIENvcHlyaWdodCAoYykgMjAxOCBUZW1haW5mbyBTb2Z0d2FyZVxuXG4gICAgUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICAgIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbiAgICBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4gICAgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICAgIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuICAgIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gICAgVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsXG4gICAgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAgICBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gICAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gICAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4gICAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICAgIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4gICAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEVcbiAgICBTT0ZUV0FSRS5cbiovXG5pbXBvcnQge0NvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT25Jbml0LCBPdXRwdXQsIFZpZXdDaGlsZH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0xpZ2h0Ym94U2VydmljZX0gZnJvbSAnLi4vbGlnaHRib3gvc2VydmljZXMvbGlnaHRib3guc2VydmljZSc7XG5pbXBvcnQge0ltYWdlVXBsb2FkSW50ZXJmYWNlfSBmcm9tICcuL2ludGVyZmFjZXMvaW1hZ2UtdXBsb2FkLmludGVyZmFjZSc7XG5pbXBvcnQge2RlYm91bmNlVGltZX0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtTdWJqZWN0LCBTdWJzY3JpcHRpb259IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtJMThuU2VydmljZX0gZnJvbSAnLi4vaTE4bi9pMThuLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0bC11cGxvYWQnLFxuICB0ZW1wbGF0ZVVybDogJy4vdXBsb2FkLmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi91cGxvYWQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBUbFVwbG9hZCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgQElucHV0KCkgdHlwZTogJ2RyYWduZHJvcCcgfCAnYm94JyA9ICdkcmFnbmRyb3AnO1xuXG4gIEBJbnB1dCgpIHNob3dBc0xpc3QgPSB0cnVlO1xuXG4gIEBJbnB1dCgpIGFjdGlvbiA9ICcnO1xuXG4gIEBJbnB1dCgpIGhlaWdodCA9ICcxMDAlJztcblxuICBASW5wdXQoKSByZXNpemVEcmFnbmRyb3AgPSBmYWxzZTtcblxuICBASW5wdXQoJ2ltYWdlTGlzdCcpXG4gIHNldCBpbWFnZUxpc3QoIHZhbHVlOiBJbWFnZVVwbG9hZEludGVyZmFjZVtdICkge1xuICAgIHRoaXMuX2ltYWdlTGlzdCA9IHZhbHVlLnNvcnQoKGEsIGIpID0+IGEuaW5kZXggLSBiLmluZGV4ICk7XG4gIH1cblxuICBnZXQgaW1hZ2VMaXN0KCkge1xuICAgIHJldHVybiB0aGlzLl9pbWFnZUxpc3Q7XG4gIH1cblxuICBASW5wdXQoKSBpbWFnZVNyYztcblxuICBASW5wdXQoKSBpbWFnZVNyY01pbWVUeXBlO1xuXG4gIEBJbnB1dCgpIGlzTG9hZGluZyA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIGRlYm91bmNlID0gMzgwO1xuXG4gIEBJbnB1dCgpIGRlbGV0ZUNvbnRyb2wgPSB0cnVlO1xuXG4gIEBJbnB1dCgpIHZpZXdDb250cm9sID0gdHJ1ZTtcblxuICBASW5wdXQoKSBhY2NlcHRGaWxlcyA9ICdpbWFnZS8qLGFwcGxpY2F0aW9uL3BkZic7XG5cbiAgQFZpZXdDaGlsZCgnaW5wdXRNdWx0aXBsZScsIHtzdGF0aWM6IGZhbHNlfSkgaW5wdXRNdWx0aXBsZTtcblxuICBAVmlld0NoaWxkKCdpbnB1dFNpbmdsZScsIHtzdGF0aWM6IGZhbHNlfSkgaW5wdXRTaW5nbGU7XG5cbiAgQE91dHB1dCgpIHZpZXcgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQE91dHB1dCgpIHVwbG9hZENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBAT3V0cHV0KCkgZGVsZXRlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBPdXRwdXQoKSB1cGRhdGVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgcHJpdmF0ZSBmaWx0ZXJpbmc6IFN1YmplY3Q8YW55PiA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgcHJpdmF0ZSB1cGxvYWRpbmc6IFN1YmplY3Q8YW55PiA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiA9IG5ldyBTdWJzY3JpcHRpb24oKTtcblxuICBwcml2YXRlIF9pbWFnZUxpc3QgPSBbXTtcblxuICBwdWJsaWMgYm94RGVzY3JpcHRpb24gPSB0aGlzLmkxOG5TZXJ2aWNlLmdldExvY2FsZSgpLlVwbG9hZC5ib3hEZXNjcmlwdGlvbjtcblxuICBwdWJsaWMgcGxhY2Vob2xkZXIgPSB0aGlzLmkxOG5TZXJ2aWNlLmdldExvY2FsZSgpLlVwbG9hZC5wbGFjZWhvbGRlcjtcblxuICBwdWJsaWMgdXBsb2FkID0gdGhpcy5pMThuU2VydmljZS5nZXRMb2NhbGUoKS5VcGxvYWQudXBsb2FkO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgaTE4blNlcnZpY2U6IEkxOG5TZXJ2aWNlLCBwcml2YXRlIGxpZ2h0Ym94U2VydmljZTogTGlnaHRib3hTZXJ2aWNlKSB7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLmZpbHRlcmluZy5waXBlKFxuICAgICAgZGVib3VuY2VUaW1lKCB0aGlzLmRlYm91bmNlICksXG4gICAgKS5zdWJzY3JpYmUoKHZhbHVlKSA9PiB7XG4gICAgICB0aGlzLnVwZGF0ZUNoYW5nZS5lbWl0KHZhbHVlKTtcbiAgICB9KTtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQodGhpcy51cGxvYWRpbmcuc3Vic2NyaWJlKHZhbHVlID0+IHtcbiAgICAgIHRoaXMudXBsb2FkQ2hhbmdlLmVtaXQoIHZhbHVlICk7XG4gICAgfSkpO1xuICB9XG5cbiAgb3BlbigkZXZlbnQpIHtcbiAgICBpZiAodGhpcy5pbnB1dFNpbmdsZSB8fCB0aGlzLmlucHV0TXVsdGlwbGUpIHtcbiAgICAgIHRoaXMudHlwZSAhPT0gJ2RyYWduZHJvcCcgPyB0aGlzLmlucHV0U2luZ2xlLm5hdGl2ZUVsZW1lbnQuY2xpY2soKSA6IHRoaXMuaW5wdXRNdWx0aXBsZS5uYXRpdmVFbGVtZW50LmNsaWNrKCk7XG4gICAgICAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfVxuICB9XG5cbiAgb25EcmFnT3Zlcihldikge1xuICAgIGV2LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgZXYuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSAnY29weSc7XG4gIH1cblxuICBvbkRyb3AoZXYpIHtcbiAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IGZpbGVMaXN0ID0gZXYuZGF0YVRyYW5zZmVyLmZpbGVzO1xuICAgIHRoaXMucmVhZEZpbGVzKGZpbGVMaXN0KTtcbiAgfVxuXG4gIG9uQ2hhbmdlRGVzY3JpcHRpb24oKSB7XG4gICAgdGhpcy5maWx0ZXJpbmcubmV4dCh0aGlzLmltYWdlTGlzdCk7XG4gIH1cblxuICByZWFkRmlsZXMoZmlsZUxpc3QpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZpbGVMaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGlzLnJlYWRGaWxlKGZpbGVMaXN0W2ldLCBpKS50aGVuKCh2YWx1ZTogSW1hZ2VVcGxvYWRJbnRlcmZhY2UpID0+IHtcbiAgICAgICAgdmFsdWUgPSBPYmplY3QuYXNzaWduKHt0aXRsZTogJycsIGRlc2NyaXB0aW9uOiAnJywgdHlwZTogdGhpcy5nZXRCYXNlNjRNaW1lVHlwZSh2YWx1ZS5maWxlKX0sIHZhbHVlKTtcbiAgICAgICAgdmFsdWUuaW5kZXggPSB0aGlzLmltYWdlTGlzdC5sZW5ndGg7XG4gICAgICAgIHRoaXMuaW1hZ2VMaXN0ID0gWyAuLi50aGlzLmltYWdlTGlzdCwgdmFsdWUgXTtcbiAgICAgICAgaWYgKCBmaWxlTGlzdC5sZW5ndGggPD0gdGhpcy5pbWFnZUxpc3QubGVuZ3RoICkge1xuICAgICAgICAgIHRoaXMudXBsb2FkaW5nLm5leHQoIHRoaXMuaW1hZ2VMaXN0ICk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJlYWRGaWxlKGZpbGUsIGluZGV4KSB7XG4gICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcbiAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICByZWFkZXIucmVhZEFzRGF0YVVSTChmaWxlKTtcbiAgICAgIHJlYWRlci5vbmxvYWRlbmQgPSAoIGV2ZW50ICkgPT4ge1xuICAgICAgICByZXNvbHZlKHtpbmRleDogaW5kZXgsIGZpbGU6ICg8RmlsZVJlYWRlcj5ldmVudC50YXJnZXQpLnJlc3VsdH0pO1xuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIHZpZXdJbWFnZSgkZXZlbnQsIGZpbGUpIHtcbiAgICAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgaWYgKHRoaXMudHlwZSA9PT0gJ2JveCcpIHtcbiAgICAgIHJldHVybiB0aGlzLnZpZXcuZW1pdCh0aGlzLmltYWdlU3JjKTtcbiAgICB9XG4gICAgdGhpcy5saWdodGJveFNlcnZpY2UuY3JlYXRlKHRoaXMuaW1hZ2VMaXN0LCBmaWxlKTtcbiAgfVxuXG4gIHJlbW92ZShmaWxlLCBpbWdTcmMsIGV2ZW50KSB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgaWYgKGltZ1NyYykge1xuICAgICAgdGhpcy5pbWFnZVNyYyA9IG51bGw7XG4gICAgICB0aGlzLmRlbGV0ZUNoYW5nZS5lbWl0KHRoaXMuaW1hZ2VTcmMpO1xuICAgIH1cbiAgICBpZiAoZmlsZSkge1xuICAgICAgdGhpcy5pbWFnZUxpc3QgPSB0aGlzLmltYWdlTGlzdC5maWx0ZXIoKGl0ZW0sIGlkeCkgPT4gZmlsZS5pbmRleCAhPT0gaWR4KTtcbiAgICAgIHRoaXMuaW1hZ2VMaXN0LmZvckVhY2goKGl0ZW0sIGlkeCkgPT4gaXRlbS5pbmRleCA9IGlkeCk7XG4gICAgICB0aGlzLmRlbGV0ZUNoYW5nZS5lbWl0KHRoaXMuaW1hZ2VMaXN0KTtcbiAgICB9XG4gIH1cblxuICBoYXNSaXNpemUoKSB7XG4gICAgcmV0dXJuICh0aGlzLnJlc2l6ZURyYWduZHJvcCAmJiB0aGlzLnR5cGUgPT09ICdkcmFnbmRyb3AnICYmIHRoaXMuaW1hZ2VMaXN0Lmxlbmd0aCA+IDApO1xuICB9XG5cbiAgb25DaGFuZ2UoJGV2ZW50KSB7XG4gICAgaWYgKCRldmVudC50YXJnZXQuZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZmlsZXNBY2NlcGV0ID0gdGhpcy5maWx0ZXJGaWxlc0FjY3BldCgkZXZlbnQudGFyZ2V0LmZpbGVzKTtcbiAgICAgIGlmICh0aGlzLnR5cGUgPT09ICdkcmFnbmRyb3AnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRGaWxlcyhmaWxlc0FjY2VwZXQpO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcbiAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGVzQWNjZXBldFswXSk7XG4gICAgICByZWFkZXIub25sb2FkID0gKGV2ZW50KSA9PiB7XG4gICAgICAgIHRoaXMuaW1hZ2VTcmMgPSAoPEZpbGVSZWFkZXI+ZXZlbnQudGFyZ2V0KS5yZXN1bHQ7XG4gICAgICAgIHRoaXMudXBsb2FkQ2hhbmdlLmVtaXQodGhpcy5pbWFnZVNyYyk7XG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsdGVyRmlsZXNBY2NwZXQoIGZpbGVzICkge1xuICAgIGNvbnN0IGFjY2VwdEZpbGVzID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmaWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgcmVnZXhFeHByZXNpc29uID0gdGhpcy5hY2NlcHRGaWxlc1xuICAgICAgICAucmVwbGFjZSggIC9cXCovZywgJy5cXConIClcbiAgICAgICAgLnJlcGxhY2UoIC9cXCwvZywgJ3wnICkgO1xuICAgICAgY29uc3QgaXNBY2NlcHQgPSBuZXcgUmVnRXhwKCByZWdleEV4cHJlc2lzb24gKS50ZXN0KCBmaWxlc1sgaSBdLnR5cGUgKTtcbiAgICAgIGlmICggaXNBY2NlcHQgKSB7XG4gICAgICAgIGFjY2VwdEZpbGVzLnB1c2goZmlsZXNbaV0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYWNjZXB0RmlsZXM7XG4gIH1cblxuICBwcml2YXRlIGdldEJhc2U2NE1pbWVUeXBlKGVuY29kZWQpIHtcbiAgICBsZXQgcmVzdWx0ID0gbnVsbDtcblxuICAgIGlmICh0eXBlb2YgZW5jb2RlZCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgY29uc3QgbWltZSA9IGVuY29kZWQubWF0Y2goL2RhdGE6KFthLXpBLVowLTldK1xcL1thLXpBLVowLTktLitdKykuKiwuKi8pO1xuXG4gICAgaWYgKG1pbWUgJiYgbWltZS5sZW5ndGgpIHtcbiAgICAgIHJlc3VsdCA9IG1pbWVbMV07XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdCB8fCAnaW1hZ2UnO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZHJhZy13cmFwcGVyXCI+XG4gIDxkaXYgKm5nSWY9XCJ0eXBlID09PSAnZHJhZ25kcm9wJ1wiIGNsYXNzPVwiZHJhZ25kcm9wXCJcbiAgICAgICBbc3R5bGUuaGVpZ2h0XT1cImhhc1Jpc2l6ZSgpID8gJ2NhbGMoJytoZWlnaHQrJyAtICcraW1hZ2VMaXN0Lmxlbmd0aCAqIDkwKydweCknOiBoZWlnaHRcIiAoY2xpY2spPVwib3BlbigkZXZlbnQpXCJcbiAgICAgICAoZHJvcCk9XCJvbkRyb3AoJGV2ZW50KVwiIChkcmFnb3Zlcik9XCJvbkRyYWdPdmVyKCRldmVudClcIj5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaW1hZ2VMaXN0Lmxlbmd0aCA9PT0gMCB8fCBzaG93QXNMaXN0OyBlbHNlIGltYWdlc0NvbnRhaW5lclRlbXBsYXRlXCI+XG4gICAgICA8c3Bhbj48dGwtaWNvbiBjbGFzcz1cImljb25cIiBbbGliXT1cIidmYSdcIiBbc3R5bGVdPVwiJ2ZhcydcIj5pbmJveDwvdGwtaWNvbj48L3NwYW4+XG4gICAgICA8cCBzdHlsZT1cIndoaXRlLXNwYWNlOiBwcmUtbGluZVwiPnt7IGJveERlc2NyaXB0aW9uIH19PC9wPlxuICAgICAgPGlucHV0ICNpbnB1dE11bHRpcGxlIHR5cGU9XCJmaWxlXCIgc3R5bGU9XCJkaXNwbGF5OiBub25lO1wiIChjaGFuZ2UpPVwib25DaGFuZ2UoJGV2ZW50KVwiIG11bHRpcGxlIFthY2NlcHRdPVwiYWNjZXB0RmlsZXNcIj5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy10ZW1wbGF0ZSAjaW1hZ2VzQ29udGFpbmVyVGVtcGxhdGU+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW1hZ2VzLWNvbnRhaW5lclwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBpdGVtIG9mIGltYWdlTGlzdFwiPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJ1cGxvYWRib3hUZW1wbGF0ZTsgY29udGV4dDogeyAkaW1wbGljaXQ6IGl0ZW0gfVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInVwbG9hZGJveFRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgICA8L2Rpdj5cbiAgICA8L25nLXRlbXBsYXRlPlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImltYWdlLWxpc3RcIiAqbmdJZj1cInNob3dBc0xpc3RcIlxuICAgICAgIFtzdHlsZS5tYXhIZWlnaHRdPVwiaGFzUmlzaXplKCkgPyAnY2FsYyggJytoZWlnaHQrJyAtIDEwMHB4ICknOiAnJ1wiPlxuICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGl0ZW0gb2YgaW1hZ2VMaXN0XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW1hZ2UtaXRlbVwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwidXBsb2FkYm94VGVtcGxhdGU7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBpdGVtIH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPHRsLXRleHRhcmVhIGNsYXNzPVwiaW1hZ2UtZGVzY3JpcHRpb25cIiBbKG5nTW9kZWwpXT1cIml0ZW0uZGVzY3JpcHRpb25cIiAobmdNb2RlbENoYW5nZSk9XCJvbkNoYW5nZURlc2NyaXB0aW9uKClcIiBbcGxhY2Vob2xkZXJdPVwicGxhY2Vob2xkZXJcIj48L3RsLXRleHRhcmVhPlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvZGl2PlxuPC9kaXY+XG5cblxuPGRpdiAqbmdJZj1cInR5cGUgPT09ICdib3gnXCIgKGNsaWNrKT1cIm9wZW4oJGV2ZW50KVwiPlxuICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwidXBsb2FkYm94VGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI3VwbG9hZGJveFRlbXBsYXRlIGxldC1pdGVtPlxuICA8aW5wdXQgI2lucHV0U2luZ2xlIHR5cGU9XCJmaWxlXCIgc3R5bGU9XCJkaXNwbGF5OiBub25lO1wiIChjaGFuZ2UpPVwib25DaGFuZ2UoJGV2ZW50KVwiIFthY2NlcHRdPVwiYWNjZXB0RmlsZXNcIj5cbiAgPHRsLXRodW1ibmFpbFxuICAgIFtzaGFwZV09XCInc3F1YXJlJ1wiXG4gICAgW2JvcmRlcmVkXT1cIiFpdGVtXCJcbiAgICBbaW1hZ2VdPVwiaXRlbT8uZmlsZSB8fCBpbWFnZVNyY1wiXG4gICAgW21pbWVUeXBlXT1cIml0ZW0/LnR5cGUgfHwgaW1hZ2VTcmNNaW1lVHlwZVwiXG4gICAgW2VtcHR5VGVtcGxhdGVdPVwiZW1wdHlUZW1wbGF0ZVwiXG4gICAgW292ZXJsYXlUZW1wbGF0ZV09XCJjb250cm9sc1RlbXBsYXRlXCI+XG4gICAgPG5nLXRlbXBsYXRlICNlbXB0eVRlbXBsYXRlPlxuICAgICAgPHRsLWljb24gW2xpYl09XCInZHgnXCI+YWRkPC90bC1pY29uPlxuICAgICAgPGRpdiBjbGFzcz1cInVwbG9hZC10aXRsZVwiPnt7IHVwbG9hZCB9fTwvZGl2PlxuICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPG5nLXRlbXBsYXRlICNjb250cm9sc1RlbXBsYXRlPlxuICAgICAgPHRsLWljb24gKm5nSWY9XCJ2aWV3Q29udHJvbFwiICAgc3R5bGU9XCJtYXJnaW4tcmlnaHQ6IDVweDsgY3Vyc29yOiBwb2ludGVyXCIgKGNsaWNrKT1cInZpZXdJbWFnZSgkZXZlbnQsIGl0ZW0gfHwgaW1hZ2VTcmMpXCIgW2xpYl09XCInZHgnXCI+ZmluZDwvdGwtaWNvbj5cbiAgICAgIDx0bC1pY29uICpuZ0lmPVwiZGVsZXRlQ29udHJvbFwiIHN0eWxlPVwiY3Vyc29yOiBwb2ludGVyXCIgKGNsaWNrKT1cInJlbW92ZShpdGVtLCBpbWFnZVNyYywgJGV2ZW50KVwiIFtsaWJdPVwiJ2R4J1wiPnRyYXNoPC90bC1pY29uPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvdGwtdGh1bWJuYWlsPlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==