UNPKG

@asoftwareworld/form-builder-pro

Version:

ASW Form Builder Pro helps you with rapid development and designed web forms which includes several controls. The key feature of Form Builder is to make your content attractive and effective. We can customize our control at run time and preview the same b

191 lines 36.6 kB
/** * @license * Copyright ASW (A Software World) All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file */ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CSSFrameworkEnum } from '@asoftwareworld/form-builder-pro/api'; import { Constants, Icons } from '@asoftwareworld/form-builder-pro/common'; import { AswConfirmDialog } from '@asoftwareworld/form-builder-pro/form-control/confirm-dialog'; import { ObjectUtils } from '@asoftwareworld/form-builder-pro/utils'; import { AswFileUploadDialog } from './fileupload-dialog'; import * as i0 from "@angular/core"; import * as i1 from "@angular/material/dialog"; import * as i2 from "@asoftwareworld/form-builder-pro/common"; import * as i3 from "@angular/common"; import * as i4 from "@angular/material/button"; import * as i5 from "@angular/material/progress-bar"; import * as i6 from "@angular/material/tooltip"; import * as i7 from "./asw-drag-drop.directive"; import * as i8 from "@asoftwareworld/form-builder-pro/core"; export class AswFileUpload { dialog; notificationService; constants = Constants; icons = Icons; control; CSSFramework = CSSFrameworkEnum.Material; isPreviewTemplate = false; propertyPersonalization = []; fileUploadUpdateEvent = new EventEmitter(); fileUploadDeleteEvent = new EventEmitter(); onfileUploadChange = new EventEmitter(); duplicateControl = new EventEmitter(); constructor(dialog, notificationService) { this.dialog = dialog; this.notificationService = notificationService; } /** * on file drop handler */ onFileDropped(event) { this.validateFileList(event); } /** * handle file from browsing */ fileBrowseHandler(event) { this.validateFileList(event.target?.files); } /** * Delete file from files list * @param index (File index) */ deleteFile(index) { this.control.value.splice(index, 1); this.onfileUploadChange.emit(); } /** * Simulate the upload process */ uploadFilesSimulator(index) { setTimeout(() => { if (index === this.control.value.length) { return; } else { const progressInterval = setInterval(() => { if (this.control.value[index].progress === 100) { clearInterval(progressInterval); this.uploadFilesSimulator(index + 1); } else { this.control.value[index].progress += 5; } }, 200); } }, 1000); } /** * Convert Files list to normal array list * @param files (Files List) */ prepareFilesList(files) { for (const item of files) { item.progress = 0; this.control.value.push(item); this.onfileUploadChange.emit(item); } this.uploadFilesSimulator(0); } validateFileList(files) { if (!ObjectUtils.missingOrEmpty(this.control.allowMultipleFile)) { const fileCount = files.length + this.control.value.length; if (!(fileCount <= Number(this.control.allowMultipleFile))) { this.notificationService.openNotification('Only ' + this.control.allowMultipleFile + ' files are allowed to upload.', 'Close'); return; } } const fileTypes = this.control.fileTypes.split(','); for (const item of files) { if (!ObjectUtils.missingOrEmpty(this.control.fileTypes)) { const extension = item.name.split('.')[1]; if (!fileTypes.find((x) => x.trim() === extension)) { this.notificationService.openNotification(item.name + ' has invalid extension. Only ' + this.control.fileTypes + ' are allowed.', 'Close'); return; } } if (!ObjectUtils.missingOrEmpty(this.control.minSize)) { const minFileSize = Number(this.control.minSize) * 1000; if (item.size <= minFileSize) { this.notificationService.openNotification(item.name + ' is too small, minimum file size is ' + this.control.minSize + 'KB.', 'Close'); return; } } if (!ObjectUtils.missingOrEmpty(this.control.maxSize)) { const maxFileSize = Number(this.control.maxSize) * 1000; if (item.size >= maxFileSize) { this.notificationService.openNotification(item.name + ' is too large, maximum file size is ' + this.control.maxSize + 'KB.', 'Close'); return; } } } this.prepareFilesList(files); } /** * format bytes * @param bytes (File size in bytes) * @param decimals (Decimals point) */ formatBytes(bytes, decimals) { if (bytes === 0) { return '0 Bytes'; } const k = 1024; const dm = decimals <= 0 ? 0 : decimals || 2; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } editFileUploadDialog(control) { const dialogRef = this.dialog.open(AswFileUploadDialog, { width: '50%', disableClose: true, data: { control, CSSFramework: this.CSSFramework, propertyPersonalization: this.propertyPersonalization } }); dialogRef.afterClosed().subscribe((result) => { if (result !== undefined) { this.fileUploadUpdateEvent.emit(result); } }); } deleteFileUploadDialog(control) { const dialogRef = this.dialog.open(AswConfirmDialog, { width: '350px', data: { name: control.controlType, message: this.constants.messages.waringMessage } }); dialogRef.afterClosed().subscribe((result) => { if (result !== undefined) { this.fileUploadDeleteEvent.emit(control); } }); } duplicateFileUploadControl(control) { this.duplicateControl.emit(control); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AswFileUpload, deps: [{ token: i1.MatDialog }, { token: i2.NotificationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: AswFileUpload, selector: "asw-fileupload", inputs: { control: "control", CSSFramework: "CSSFramework", isPreviewTemplate: "isPreviewTemplate", propertyPersonalization: "propertyPersonalization" }, outputs: { fileUploadUpdateEvent: "fileUploadUpdateEvent", fileUploadDeleteEvent: "fileUploadDeleteEvent", onfileUploadChange: "onfileUploadChange", duplicateControl: "duplicateControl" }, ngImport: i0, template: "<div class=\"asw-upload-container\" aswDragAndDrop (fileDropped)=\"onFileDropped($event)\">\r\n\t<div class=\"asw-drop-area\">\r\n\t\t<input type=\"file\" #fileDropRef id=\"fileDropRef\" multiple (change)=\"fileBrowseHandler($event)\" />\r\n\t\t<span>\r\n\t\t\t{{'Drag and drop files here or' | aswTranslate}}\r\n\t\t\t<a href=\"javascript:void(0);\" for=\"fileDropRef\"><u>{{'Browse' | aswTranslate}}</u></a>\r\n\t\t</span>\r\n\t</div>\r\n</div>\r\n<ul class=\"asw-file-lists\">\r\n\t<li class=\"asw-single-list\" *ngFor=\"let file of control.value; let i = index\">\r\n\t\t<span class=\"asw-file-name\" [ngStyle]=\"{'color':file?.progress === 100 ? 'green' : '' }\">{{ file?.name }}</span>\r\n\t\t<span class=\"asw-file-size\" style=\"display: inline-block;\">{{ formatBytes(file?.size, undefined) }}</span>\r\n\t\t<span class=\"asw-delete-svg\" (click)=\"deleteFile(i)\" [innerHTML]=\"icons.delete2 | aswSafeHtml\"></span>\r\n\t\t<ng-container *ngIf=\"file?.progress < 100\">\r\n\t\t\t<mat-progress-bar mode=\"determinate\" [value]=\"file?.progress\"></mat-progress-bar>\r\n\t\t</ng-container>\r\n\t</li>\r\n</ul>\r\n<div class=\"asw-row\" *ngIf=\"isPreviewTemplate\">\r\n <div class=\"asw-col-md-12\" align=\"right\">\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Duplicate' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"duplicateFileUploadControl(control)\">\r\n <div [innerHTML]=\"icons.contentCopy | aswSafeHtml\"></div>\r\n </button>\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Edit' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"editFileUploadDialog(control)\">\r\n <div [innerHTML]=\"icons.edit | aswSafeHtml\"></div>\r\n </button>\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Delete' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"deleteFileUploadDialog(control)\">\r\n <div [innerHTML]=\"icons.delete2 | aswSafeHtml\"></div>\r\n </button>\r\n </div>\r\n</div>", styles: [".asw-upload-container{text-align:center;position:relative;margin:auto;min-width:245px}.asw-upload-container .asw-drop-area{min-height:50px;margin:10px 0;position:relative;font-size:14px}.asw-upload-container .asw-drop-area span{padding:3% 30%;display:inherit;border:dashed 1px #c3c3cc}.asw-upload-container .asw-drop-area input{opacity:0;position:absolute;z-index:2;width:100%;height:100%;top:0;left:0;cursor:pointer}.fileover{animation:shake 1s;animation-iteration-count:infinite}.asw-file-lists{list-style:none;width:100%;padding-left:0}.asw-file-lists li.asw-single-list{border:1px solid #d3d3d3;padding:0 6px;margin-top:10px;position:relative;background:#0000000a}.asw-file-lists .asw-file-name{padding:8px 6px 8px 0;width:46%;display:inline-block;position:relative}.asw-file-lists .asw-file-size{padding:8px 6px 8px 0;width:25%;display:inline-block;position:relative}.asw-file-lists .asw-delete-svg{cursor:pointer;padding:6px;position:absolute;right:0}@keyframes shake{0%{transform:translate(1px,1px) rotate(0)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0)}to{transform:translate(1px,-2px) rotate(-1deg)}}\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.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i5.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i7.AswDragAndDropDirective, selector: "[aswDragAndDrop]", outputs: ["fileDropped"] }, { kind: "pipe", type: i8.AswTranslatePipe, name: "aswTranslate" }, { kind: "pipe", type: i2.AswSafeHtmlPipe, name: "aswSafeHtml" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AswFileUpload, decorators: [{ type: Component, args: [{ selector: 'asw-fileupload', template: "<div class=\"asw-upload-container\" aswDragAndDrop (fileDropped)=\"onFileDropped($event)\">\r\n\t<div class=\"asw-drop-area\">\r\n\t\t<input type=\"file\" #fileDropRef id=\"fileDropRef\" multiple (change)=\"fileBrowseHandler($event)\" />\r\n\t\t<span>\r\n\t\t\t{{'Drag and drop files here or' | aswTranslate}}\r\n\t\t\t<a href=\"javascript:void(0);\" for=\"fileDropRef\"><u>{{'Browse' | aswTranslate}}</u></a>\r\n\t\t</span>\r\n\t</div>\r\n</div>\r\n<ul class=\"asw-file-lists\">\r\n\t<li class=\"asw-single-list\" *ngFor=\"let file of control.value; let i = index\">\r\n\t\t<span class=\"asw-file-name\" [ngStyle]=\"{'color':file?.progress === 100 ? 'green' : '' }\">{{ file?.name }}</span>\r\n\t\t<span class=\"asw-file-size\" style=\"display: inline-block;\">{{ formatBytes(file?.size, undefined) }}</span>\r\n\t\t<span class=\"asw-delete-svg\" (click)=\"deleteFile(i)\" [innerHTML]=\"icons.delete2 | aswSafeHtml\"></span>\r\n\t\t<ng-container *ngIf=\"file?.progress < 100\">\r\n\t\t\t<mat-progress-bar mode=\"determinate\" [value]=\"file?.progress\"></mat-progress-bar>\r\n\t\t</ng-container>\r\n\t</li>\r\n</ul>\r\n<div class=\"asw-row\" *ngIf=\"isPreviewTemplate\">\r\n <div class=\"asw-col-md-12\" align=\"right\">\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Duplicate' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"duplicateFileUploadControl(control)\">\r\n <div [innerHTML]=\"icons.contentCopy | aswSafeHtml\"></div>\r\n </button>\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Edit' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"editFileUploadDialog(control)\">\r\n <div [innerHTML]=\"icons.edit | aswSafeHtml\"></div>\r\n </button>\r\n <button mat-icon-button \r\n type=\"button\" \r\n matTooltip=\"{{'FormControl.Delete' | aswTranslate}}\" \r\n [matTooltipPosition]=\"'below'\" \r\n (click)=\"deleteFileUploadDialog(control)\">\r\n <div [innerHTML]=\"icons.delete2 | aswSafeHtml\"></div>\r\n </button>\r\n </div>\r\n</div>", styles: [".asw-upload-container{text-align:center;position:relative;margin:auto;min-width:245px}.asw-upload-container .asw-drop-area{min-height:50px;margin:10px 0;position:relative;font-size:14px}.asw-upload-container .asw-drop-area span{padding:3% 30%;display:inherit;border:dashed 1px #c3c3cc}.asw-upload-container .asw-drop-area input{opacity:0;position:absolute;z-index:2;width:100%;height:100%;top:0;left:0;cursor:pointer}.fileover{animation:shake 1s;animation-iteration-count:infinite}.asw-file-lists{list-style:none;width:100%;padding-left:0}.asw-file-lists li.asw-single-list{border:1px solid #d3d3d3;padding:0 6px;margin-top:10px;position:relative;background:#0000000a}.asw-file-lists .asw-file-name{padding:8px 6px 8px 0;width:46%;display:inline-block;position:relative}.asw-file-lists .asw-file-size{padding:8px 6px 8px 0;width:25%;display:inline-block;position:relative}.asw-file-lists .asw-delete-svg{cursor:pointer;padding:6px;position:absolute;right:0}@keyframes shake{0%{transform:translate(1px,1px) rotate(0)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0)}to{transform:translate(1px,-2px) rotate(-1deg)}}\n"] }] }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.NotificationService }], propDecorators: { control: [{ type: Input }], CSSFramework: [{ type: Input }], isPreviewTemplate: [{ type: Input }], propertyPersonalization: [{ type: Input }], fileUploadUpdateEvent: [{ type: Output }], fileUploadDeleteEvent: [{ type: Output }], onfileUploadChange: [{ type: Output }], duplicateControl: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXVwbG9hZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL2Zvcm0tY29udHJvbC9maWxldXBsb2FkL2ZpbGV1cGxvYWQudHMiLCIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9mb3JtLWNvbnRyb2wvZmlsZXVwbG9hZC9maWxldXBsb2FkLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV2RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUN4RSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBdUIsTUFBTSx5Q0FBeUMsQ0FBQztBQUNoRyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4REFBOEQsQ0FBQztBQUNoRyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFFckUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0scUJBQXFCLENBQUM7Ozs7Ozs7Ozs7QUFPMUQsTUFBTSxPQUFPLGFBQWE7SUFjWDtJQUNDO0lBZFosU0FBUyxHQUFRLFNBQVMsQ0FBQztJQUMzQixLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ0wsT0FBTyxDQUFNO0lBQ2IsWUFBWSxHQUFxQixnQkFBZ0IsQ0FBQyxRQUFRLENBQUM7SUFDM0QsaUJBQWlCLEdBQUcsS0FBSyxDQUFDO0lBQzFCLHVCQUF1QixHQUFhLEVBQUUsQ0FBQztJQUV0QyxxQkFBcUIsR0FBRyxJQUFJLFlBQVksRUFBcUIsQ0FBQztJQUM5RCxxQkFBcUIsR0FBRyxJQUFJLFlBQVksRUFBcUIsQ0FBQztJQUM5RCxrQkFBa0IsR0FBRyxJQUFJLFlBQVksRUFBcUIsQ0FBQztJQUMzRCxnQkFBZ0IsR0FBRyxJQUFJLFlBQVksRUFBcUIsQ0FBQztJQUVu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QUVELDBCQUEwQixDQUFDLE9BQVk7UUFDbkMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN4QyxDQUFDO3VHQXhKUSxhQUFhOzJGQUFiLGFBQWEsNllDckIxQixreEVBMkNNOzsyRkR0Qk8sYUFBYTtrQkFMekIsU0FBUzsrQkFDSSxnQkFBZ0I7Z0hBT2pCLE9BQU87c0JBQWYsS0FBSztnQkFDRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFDRyx1QkFBdUI7c0JBQS9CLEtBQUs7Z0JBRUkscUJBQXFCO3NCQUE5QixNQUFNO2dCQUNHLHFCQUFxQjtzQkFBOUIsTUFBTTtnQkFDRyxrQkFBa0I7c0JBQTNCLE1BQU07Z0JBQ0csZ0JBQWdCO3NCQUF6QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEFTVyAoQSBTb2Z0d2FyZSBXb3JsZCkgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZVxuICovXG5pbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IENTU0ZyYW1ld29ya0VudW0gfSBmcm9tICdAYXNvZnR3YXJld29ybGQvZm9ybS1idWlsZGVyLXByby9hcGknO1xuaW1wb3J0IHsgQ29uc3RhbnRzLCBJY29ucywgTm90aWZpY2F0aW9uU2VydmljZSB9IGZyb20gJ0Bhc29mdHdhcmV3b3JsZC9mb3JtLWJ1aWxkZXItcHJvL2NvbW1vbic7XG5pbXBvcnQgeyBBc3dDb25maXJtRGlhbG9nIH0gZnJvbSAnQGFzb2Z0d2FyZXdvcmxkL2Zvcm0tYnVpbGRlci1wcm8vZm9ybS1jb250cm9sL2NvbmZpcm0tZGlhbG9nJztcbmltcG9ydCB7IE9iamVjdFV0aWxzIH0gZnJvbSAnQGFzb2Z0d2FyZXdvcmxkL2Zvcm0tYnVpbGRlci1wcm8vdXRpbHMnO1xuaW1wb3J0IHsgRmlsZVVwbG9hZENvbnRyb2wgfSBmcm9tICcuL2ZpbGV1cGxvYWQtY29udHJvbCc7XG5pbXBvcnQgeyBBc3dGaWxlVXBsb2FkRGlhbG9nIH0gZnJvbSAnLi9maWxldXBsb2FkLWRpYWxvZyc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnYXN3LWZpbGV1cGxvYWQnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9maWxldXBsb2FkLmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL2ZpbGV1cGxvYWQuc2NzcyddXG59KVxuZXhwb3J0IGNsYXNzIEFzd0ZpbGVVcGxvYWQge1xuICAgIGNvbnN0YW50czogYW55ID0gQ29uc3RhbnRzO1xuICAgIGljb25zID0gSWNvbnM7XG4gICAgQElucHV0KCkgY29udHJvbDogYW55O1xuICAgIEBJbnB1dCgpIENTU0ZyYW1ld29yazogQ1NTRnJhbWV3b3JrRW51bSA9IENTU0ZyYW1ld29ya0VudW0uTWF0ZXJpYWw7XG4gICAgQElucHV0KCkgaXNQcmV2aWV3VGVtcGxhdGUgPSBmYWxzZTtcbiAgICBASW5wdXQoKSBwcm9wZXJ0eVBlcnNvbmFsaXphdGlvbjogc3RyaW5nW10gPSBbXTtcblxuICAgIEBPdXRwdXQoKSBmaWxlVXBsb2FkVXBkYXRlRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyPEZpbGVVcGxvYWRDb250cm9sPigpO1xuICAgIEBPdXRwdXQoKSBmaWxlVXBsb2FkRGVsZXRlRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyPEZpbGVVcGxvYWRDb250cm9sPigpO1xuICAgIEBPdXRwdXQoKSBvbmZpbGVVcGxvYWRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEZpbGVVcGxvYWRDb250cm9sPigpO1xuICAgIEBPdXRwdXQoKSBkdXBsaWNhdGVDb250cm9sID0gbmV3IEV2ZW50RW1pdHRlcjxGaWxlVXBsb2FkQ29udHJvbD4oKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgZGlhbG9nOiBNYXREaWFsb2csXG4gICAgICAgIHByaXZhdGUgbm90aWZpY2F0aW9uU2VydmljZTogTm90aWZpY2F0aW9uU2VydmljZVxuICAgICkge31cblxuICAgIC8qKlxuICAgICAqIG9uIGZpbGUgZHJvcCBoYW5kbGVyXG4gICAgICovXG4gICAgb25GaWxlRHJvcHBlZChldmVudDogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMudmFsaWRhdGVGaWxlTGlzdChldmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaGFuZGxlIGZpbGUgZnJvbSBicm93c2luZ1xuICAgICAqL1xuICAgIGZpbGVCcm93c2VIYW5kbGVyKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICAgICAgdGhpcy52YWxpZGF0ZUZpbGVMaXN0KGV2ZW50LnRhcmdldD8uZmlsZXMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlbGV0ZSBmaWxlIGZyb20gZmlsZXMgbGlzdFxuICAgICAqIEBwYXJhbSBpbmRleCAoRmlsZSBpbmRleClcbiAgICAgKi9cbiAgICBkZWxldGVGaWxlKGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jb250cm9sLnZhbHVlLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgIHRoaXMub25maWxlVXBsb2FkQ2hhbmdlLmVtaXQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTaW11bGF0ZSB0aGUgdXBsb2FkIHByb2Nlc3NcbiAgICAgKi9cbiAgICB1cGxvYWRGaWxlc1NpbXVsYXRvcihpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGluZGV4ID09PSB0aGlzLmNvbnRyb2wudmFsdWUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9ncmVzc0ludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5jb250cm9sLnZhbHVlW2luZGV4XS5wcm9ncmVzcyA9PT0gMTAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGVhckludGVydmFsKHByb2dyZXNzSW50ZXJ2YWwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy51cGxvYWRGaWxlc1NpbXVsYXRvcihpbmRleCArIDEpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250cm9sLnZhbHVlW2luZGV4XS5wcm9ncmVzcyArPSA1O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSwgMjAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgMTAwMCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydCBGaWxlcyBsaXN0IHRvIG5vcm1hbCBhcnJheSBsaXN0XG4gICAgICogQHBhcmFtIGZpbGVzIChGaWxlcyBMaXN0KVxuICAgICAqL1xuICAgIHByaXZhdGUgcHJlcGFyZUZpbGVzTGlzdChmaWxlczogQXJyYXk8YW55Pik6IHZvaWQge1xuICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgZmlsZXMpIHtcbiAgICAgICAgICAgIGl0ZW0ucHJvZ3Jlc3MgPSAwO1xuICAgICAgICAgICAgdGhpcy5jb250cm9sLnZhbHVlLnB1c2goaXRlbSk7XG4gICAgICAgICAgICB0aGlzLm9uZmlsZVVwbG9hZENoYW5nZS5lbWl0KGl0ZW0pO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBsb2FkRmlsZXNTaW11bGF0b3IoMCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZUZpbGVMaXN0KGZpbGVzOiBBcnJheTxhbnk+KTogdm9pZCB7XG4gICAgICAgIGlmICghT2JqZWN0VXRpbHMubWlzc2luZ09yRW1wdHkodGhpcy5jb250cm9sLmFsbG93TXVsdGlwbGVGaWxlKSkge1xuICAgICAgICAgICAgY29uc3QgZmlsZUNvdW50ID0gZmlsZXMubGVuZ3RoICsgdGhpcy5jb250cm9sLnZhbHVlLmxlbmd0aDtcbiAgICAgICAgICAgIGlmICghKGZpbGVDb3VudCA8PSBOdW1iZXIodGhpcy5jb250cm9sLmFsbG93TXVsdGlwbGVGaWxlKSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2Uub3Blbk5vdGlmaWNhdGlvbignT25seSAnICsgdGhpcy5jb250cm9sLmFsbG93TXVsdGlwbGVGaWxlICsgJyBmaWxlcyBhcmUgYWxsb3dlZCB0byB1cGxvYWQuJywgJ0Nsb3NlJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGZpbGVUeXBlcyA9IHRoaXMuY29udHJvbC5maWxlVHlwZXMuc3BsaXQoJywnKTtcbiAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICBpZiAoIU9iamVjdFV0aWxzLm1pc3NpbmdPckVtcHR5KHRoaXMuY29udHJvbC5maWxlVHlwZXMpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXh0ZW5zaW9uID0gaXRlbS5uYW1lLnNwbGl0KCcuJylbMV07XG4gICAgICAgICAgICAgICAgaWYgKCFmaWxlVHlwZXMuZmluZCgoeDogc3RyaW5nKSA9PiB4LnRyaW0oKSA9PT0gZXh0ZW5zaW9uKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2Uub3Blbk5vdGlmaWNhdGlvbihpdGVtLm5hbWUgKyAnIGhhcyBpbnZhbGlkIGV4dGVuc2lvbi4gT25seSAnICsgdGhpcy5jb250cm9sLmZpbGVUeXBlcyArICcgYXJlIGFsbG93ZWQuJywgJ0Nsb3NlJyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIU9iamVjdFV0aWxzLm1pc3NpbmdPckVtcHR5KHRoaXMuY29udHJvbC5taW5TaXplKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG1pbkZpbGVTaXplID0gTnVtYmVyKHRoaXMuY29udHJvbC5taW5TaXplKSAqIDEwMDA7XG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0uc2l6ZSA8PSBtaW5GaWxlU2l6ZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2Uub3Blbk5vdGlmaWNhdGlvbihpdGVtLm5hbWUgKyAnIGlzIHRvbyBzbWFsbCwgbWluaW11bSBmaWxlIHNpemUgaXMgJyArIHRoaXMuY29udHJvbC5taW5TaXplICsgJ0tCLicsICdDbG9zZScpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFPYmplY3RVdGlscy5taXNzaW5nT3JFbXB0eSh0aGlzLmNvbnRyb2wubWF4U2l6ZSkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXhGaWxlU2l6ZSA9IE51bWJlcih0aGlzLmNvbnRyb2wubWF4U2l6ZSkgKiAxMDAwO1xuICAgICAgICAgICAgICAgIGlmIChpdGVtLnNpemUgPj0gbWF4RmlsZVNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLm9wZW5Ob3RpZmljYXRpb24oaXRlbS5uYW1lICsgJyBpcyB0b28gbGFyZ2UsIG1heGltdW0gZmlsZSBzaXplIGlzICcgKyB0aGlzLmNvbnRyb2wubWF4U2l6ZSArICdLQi4nLCAnQ2xvc2UnKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnByZXBhcmVGaWxlc0xpc3QoZmlsZXMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGZvcm1hdCBieXRlc1xuICAgICAqIEBwYXJhbSBieXRlcyAoRmlsZSBzaXplIGluIGJ5dGVzKVxuICAgICAqIEBwYXJhbSBkZWNpbWFscyAoRGVjaW1hbHMgcG9pbnQpXG4gICAgICovXG4gICAgZm9ybWF0Qnl0ZXMoYnl0ZXM6IGFueSwgZGVjaW1hbHM6IGFueSk6IGFueSB7XG4gICAgICAgIGlmIChieXRlcyA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuICcwIEJ5dGVzJztcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBrID0gMTAyNDtcbiAgICAgICAgY29uc3QgZG0gPSBkZWNpbWFscyA8PSAwID8gMCA6IGRlY2ltYWxzIHx8IDI7XG4gICAgICAgIGNvbnN0IHNpemVzID0gWydCeXRlcycsICdLQicsICdNQicsICdHQicsICdUQicsICdQQicsICdFQicsICdaQicsICdZQiddO1xuICAgICAgICBjb25zdCBpID0gTWF0aC5mbG9vcihNYXRoLmxvZyhieXRlcykgLyBNYXRoLmxvZyhrKSk7XG4gICAgICAgIHJldHVybiBwYXJzZUZsb2F0KChieXRlcyAvIE1hdGgucG93KGssIGkpKS50b0ZpeGVkKGRtKSkgKyAnICcgKyBzaXplc1tpXTtcbiAgICB9XG5cbiAgICBlZGl0RmlsZVVwbG9hZERpYWxvZyhjb250cm9sOiBGaWxlVXBsb2FkQ29udHJvbCk6IHZvaWQge1xuICAgICAgICBjb25zdCBkaWFsb2dSZWYgPSB0aGlzLmRpYWxvZy5vcGVuKEFzd0ZpbGVVcGxvYWREaWFsb2csIHtcbiAgICAgICAgICAgIHdpZHRoOiAnNTAlJyxcbiAgICAgICAgICAgIGRpc2FibGVDbG9zZTogdHJ1ZSxcbiAgICAgICAgICAgIGRhdGE6IHsgY29udHJvbCwgQ1NTRnJhbWV3b3JrOiB0aGlzLkNTU0ZyYW1ld29yaywgcHJvcGVydHlQZXJzb25hbGl6YXRpb246IHRoaXMucHJvcGVydHlQZXJzb25hbGl6YXRpb24gfVxuICAgICAgICB9KTtcbiAgICAgICAgZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKCkuc3Vic2NyaWJlKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgIGlmIChyZXN1bHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZmlsZVVwbG9hZFVwZGF0ZUV2ZW50LmVtaXQocmVzdWx0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZGVsZXRlRmlsZVVwbG9hZERpYWxvZyhjb250cm9sOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5kaWFsb2cub3BlbihBc3dDb25maXJtRGlhbG9nLCB7XG4gICAgICAgICAgICB3aWR0aDogJzM1MHB4JyxcbiAgICAgICAgICAgIGRhdGE6IHsgbmFtZTogY29udHJvbC5jb250cm9sVHlwZSwgbWVzc2FnZTogdGhpcy5jb25zdGFudHMubWVzc2FnZXMud2FyaW5nTWVzc2FnZSB9XG4gICAgICAgIH0pO1xuICAgICAgICBkaWFsb2dSZWYuYWZ0ZXJDbG9zZWQoKS5zdWJzY3JpYmUoKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgaWYgKHJlc3VsdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5maWxlVXBsb2FkRGVsZXRlRXZlbnQuZW1pdChjb250cm9sKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZHVwbGljYXRlRmlsZVVwbG9hZENvbnRyb2woY29udHJvbDogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMuZHVwbGljYXRlQ29udHJvbC5lbWl0KGNvbnRyb2wpO1xuICAgIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJhc3ctdXBsb2FkLWNvbnRhaW5lclwiIGFzd0RyYWdBbmREcm9wIChmaWxlRHJvcHBlZCk9XCJvbkZpbGVEcm9wcGVkKCRldmVudClcIj5cclxuXHQ8ZGl2IGNsYXNzPVwiYXN3LWRyb3AtYXJlYVwiPlxyXG5cdFx0PGlucHV0IHR5cGU9XCJmaWxlXCIgI2ZpbGVEcm9wUmVmIGlkPVwiZmlsZURyb3BSZWZcIiBtdWx0aXBsZSAoY2hhbmdlKT1cImZpbGVCcm93c2VIYW5kbGVyKCRldmVudClcIiAvPlxyXG5cdFx0PHNwYW4+XHJcblx0XHRcdHt7J0RyYWcgYW5kIGRyb3AgZmlsZXMgaGVyZSBvcicgfCBhc3dUcmFuc2xhdGV9fVxyXG5cdFx0XHQ8YSBocmVmPVwiamF2YXNjcmlwdDp2b2lkKDApO1wiIGZvcj1cImZpbGVEcm9wUmVmXCI+PHU+e3snQnJvd3NlJyB8IGFzd1RyYW5zbGF0ZX19PC91PjwvYT5cclxuXHRcdDwvc3Bhbj5cclxuXHQ8L2Rpdj5cclxuPC9kaXY+XHJcbjx1bCBjbGFzcz1cImFzdy1maWxlLWxpc3RzXCI+XHJcblx0PGxpIGNsYXNzPVwiYXN3LXNpbmdsZS1saXN0XCIgKm5nRm9yPVwibGV0IGZpbGUgb2YgY29udHJvbC52YWx1ZTsgbGV0IGkgPSBpbmRleFwiPlxyXG5cdFx0PHNwYW4gY2xhc3M9XCJhc3ctZmlsZS1uYW1lXCIgW25nU3R5bGVdPVwieydjb2xvcic6ZmlsZT8ucHJvZ3Jlc3MgPT09IDEwMCA/ICdncmVlbicgOiAnJyB9XCI+e3sgZmlsZT8ubmFtZSB9fTwvc3Bhbj5cclxuXHRcdDxzcGFuIGNsYXNzPVwiYXN3LWZpbGUtc2l6ZVwiIHN0eWxlPVwiZGlzcGxheTogaW5saW5lLWJsb2NrO1wiPnt7IGZvcm1hdEJ5dGVzKGZpbGU/LnNpemUsIHVuZGVmaW5lZCkgfX08L3NwYW4+XHJcblx0XHQ8c3BhbiBjbGFzcz1cImFzdy1kZWxldGUtc3ZnXCIgKGNsaWNrKT1cImRlbGV0ZUZpbGUoaSlcIiBbaW5uZXJIVE1MXT1cImljb25zLmRlbGV0ZTIgfCBhc3dTYWZlSHRtbFwiPjwvc3Bhbj5cclxuXHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJmaWxlPy5wcm9ncmVzcyA8IDEwMFwiPlxyXG5cdFx0XHQ8bWF0LXByb2dyZXNzLWJhciBtb2RlPVwiZGV0ZXJtaW5hdGVcIiBbdmFsdWVdPVwiZmlsZT8ucHJvZ3Jlc3NcIj48L21hdC1wcm9ncmVzcy1iYXI+XHJcblx0XHQ8L25nLWNvbnRhaW5lcj5cclxuXHQ8L2xpPlxyXG48L3VsPlxyXG48ZGl2IGNsYXNzPVwiYXN3LXJvd1wiICpuZ0lmPVwiaXNQcmV2aWV3VGVtcGxhdGVcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJhc3ctY29sLW1kLTEyXCIgYWxpZ249XCJyaWdodFwiPlxyXG4gICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIFxyXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiIFxyXG4gICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cInt7J0Zvcm1Db250cm9sLkR1cGxpY2F0ZScgfCBhc3dUcmFuc2xhdGV9fVwiIFxyXG4gICAgICAgICAgICAgICAgW21hdFRvb2x0aXBQb3NpdGlvbl09XCInYmVsb3cnXCIgXHJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiZHVwbGljYXRlRmlsZVVwbG9hZENvbnRyb2woY29udHJvbClcIj5cclxuICAgICAgICAgICAgPGRpdiBbaW5uZXJIVE1MXT1cImljb25zLmNvbnRlbnRDb3B5IHwgYXN3U2FmZUh0bWxcIj48L2Rpdj5cclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiBcclxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIiBcclxuICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJ7eydGb3JtQ29udHJvbC5FZGl0JyB8IGFzd1RyYW5zbGF0ZX19XCIgXHJcbiAgICAgICAgICAgICAgICBbbWF0VG9vbHRpcFBvc2l0aW9uXT1cIidiZWxvdydcIiBcclxuICAgICAgICAgICAgICAgIChjbGljayk9XCJlZGl0RmlsZVVwbG9hZERpYWxvZyhjb250cm9sKVwiPlxyXG4gICAgICAgICAgICA8ZGl2IFtpbm5lckhUTUxdPVwiaWNvbnMuZWRpdCB8IGFzd1NhZmVIdG1sXCI+PC9kaXY+XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gXHJcbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCIgXHJcbiAgICAgICAgICAgICAgICBtYXRUb29sdGlwPVwie3snRm9ybUNvbnRyb2wuRGVsZXRlJyB8IGFzd1RyYW5zbGF0ZX19XCIgXHJcbiAgICAgICAgICAgICAgICBbbWF0VG9vbHRpcFBvc2l0aW9uXT1cIidiZWxvdydcIiBcclxuICAgICAgICAgICAgICAgIChjbGljayk9XCJkZWxldGVGaWxlVXBsb2FkRGlhbG9nKGNvbnRyb2wpXCI+XHJcbiAgICAgICAgICAgIDxkaXYgW2lubmVySFRNTF09XCJpY29ucy5kZWxldGUyIHwgYXN3U2FmZUh0bWxcIj48L2Rpdj5cclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgIDwvZGl2PlxyXG48L2Rpdj4iXX0=