UNPKG

angular-file-uploader

Version:

Angular file uploader is an Angular 2/4/5/6/7/8/9/10/11/12/13 + file uploader module with Real-Time Progress Bar, Responsive design, Angular Universal Compatibility and multiple themes which includes Drag and Drop and much more.

262 lines (261 loc) 41 kB
import { Component, EventEmitter, Input, Output, SkipSelf, } from '@angular/core'; import { HttpClient, HttpEventType, } from '@angular/common/http'; export class AngularFileUploaderComponent { constructor(http) { this.http = http; this.resetUpload = false; // Outputs this.ApiResponse = new EventEmitter(); this.fileSelected = new EventEmitter(); this.allowedFiles = []; this.notAllowedFiles = []; this.Caption = []; this.isAllowedFileSingle = true; this.progressBarShow = false; this.enableUploadBtn = false; this.uploadMsg = false; this.afterUpload = false; this.uploadStarted = false; this.currentUploads = []; this.fileNameIndex = true; this.withCredentials = false; this.autoUpload = false; this.idDate = +new Date(); } ngOnChanges(changes) { // Track changes in Configuration and see if user has even provided Configuration. if (changes.config && this.config) { // Assign User Configurations to Library Properties. this.theme = this.config.theme || ''; this.id = this.config.id || parseInt((this.idDate / 10000).toString().split('.')[1], 10) + Math.floor(Math.random() * 20) * 10000; this.hideProgressBar = this.config.hideProgressBar || false; this.hideResetBtn = this.config.hideResetBtn || false; this.hideSelectBtn = this.config.hideSelectBtn || false; this.maxSize = (this.config.maxSize || 20) * 1024000; // mb to bytes. this.uploadAPI = this.config.uploadAPI.url; this.method = this.config.uploadAPI.method || 'POST'; this.formatsAllowed = this.config.formatsAllowed || '*'; this.formatsAllowedText = this.formatsAllowed === '*' ? '' : '(' + this.formatsAllowed + ')'; this.multiple = this.config.multiple || false; this.headers = this.config.uploadAPI.headers || {}; this.params = this.config.uploadAPI.params || {}; this.responseType = this.config.uploadAPI.responseType || 'json'; this.withCredentials = this.config.uploadAPI.withCredentials || false; this.fileNameIndex = this.config.fileNameIndex === false ? false : true; this.autoUpload = this.config.autoUpload || false; this.replaceTexts = { selectFileBtn: this.multiple ? 'Select Files' : 'Select File', resetBtn: 'Reset', uploadBtn: 'Upload', dragNDropBox: 'Drag N Drop', attachPinBtn: this.multiple ? 'Attach Files...' : 'Attach File...', afterUploadMsg_success: 'Successfully Uploaded !', afterUploadMsg_error: 'Upload Failed !', sizeLimit: 'Size Limit', }; // default replaceText. if (this.config.replaceTexts) { // updated replaceText if user has provided any. this.replaceTexts = Object.assign(Object.assign({}, this.replaceTexts), this.config.replaceTexts); } } // Reset when resetUpload value changes from false to true. if (changes.resetUpload) { if (changes.resetUpload.currentValue === true) { this.resetFileUpload(); } } } // Reset following properties. resetFileUpload() { this.allowedFiles = []; this.Caption = []; this.notAllowedFiles = []; this.uploadMsg = false; this.enableUploadBtn = false; } // When user selects files. onChange(event) { this.fileSelected.emit(event); this.notAllowedFiles = []; const fileExtRegExp = /(?:\.([^.]+))?$/; let fileList; if (this.afterUpload || !this.multiple) { this.allowedFiles = []; this.Caption = []; this.afterUpload = false; } if (event.type === 'drop') { fileList = event.dataTransfer.files; } else { fileList = event.target.files || event.srcElement.files; } // 'forEach' does not exist on 'filelist' that's why this good old 'for' is used. for (let i = 0; i < fileList.length; i++) { const currentFileExt = fileExtRegExp .exec(fileList[i].name)[1] .toLowerCase(); // Get file extension. const isFormatValid = this.formatsAllowed.includes('*') ? true : this.formatsAllowed.includes(currentFileExt); const isSizeValid = fileList[i].size <= this.maxSize; // Check whether current file format and size is correct as specified in the configurations. if (isFormatValid && isSizeValid) { this.allowedFiles.push(fileList[i]); } else { this.notAllowedFiles.push({ fileName: fileList[i].name, fileSize: this.convertSize(fileList[i].size), errorMsg: !isFormatValid ? 'Invalid format' : 'Invalid size', }); } } // If there's any allowedFiles. if (this.allowedFiles.length > 0) { this.enableUploadBtn = true; // Upload the files directly if theme is attach pin (as upload btn is not there for this theme) or autoUpload is true. if (this.theme === 'attachPin' || this.autoUpload) { this.uploadFiles(); } } else { this.enableUploadBtn = false; } this.uploadMsg = false; this.uploadStarted = false; this.uploadPercent = 0; event.target.value = null; } uploadFiles() { this.progressBarShow = true; this.uploadStarted = true; this.notAllowedFiles = []; let isError = false; this.isAllowedFileSingle = this.allowedFiles.length <= 1; const formData = new FormData(); // Add data to be sent in this request this.allowedFiles.forEach((file, i) => { formData.append(this.Caption[i] || 'file' + (this.fileNameIndex ? i : ''), this.allowedFiles[i]); }); /* Not Working, Headers null // Contruct Headers const headers = new HttpHeaders(); for (const key of Object.keys(this.headers)) { headers.append(key, this.headers[key]); } // Contruct Params const params = new HttpParams(); for (const key of Object.keys(this.params)) { params.append(key, this.params[key]); } */ this.http .request(this.method.toUpperCase(), this.uploadAPI, { body: formData, reportProgress: true, observe: 'events', headers: this.headers, params: this.params, responseType: this.responseType, withCredentials: this.withCredentials, }) .subscribe((event) => { // Upload Progress if (event.type === HttpEventType.UploadProgress) { this.enableUploadBtn = false; // button should be disabled if process uploading const currentDone = event.loaded / event.total; this.uploadPercent = Math.round((event.loaded / event.total) * 100); } else if (event.type === HttpEventType.Response) { if (event.status === 200 || event.status === 201) { // Success this.progressBarShow = false; this.enableUploadBtn = false; this.uploadMsg = true; this.afterUpload = true; if (!isError) { this.uploadMsgText = this.replaceTexts.afterUploadMsg_success; this.uploadMsgClass = 'text-success lead'; } } else { // Failure isError = true; this.handleErrors(); } this.ApiResponse.emit(event); } else { //console.log('Event Other: ', event); } }, (error) => { // Failure isError = true; this.handleErrors(); this.ApiResponse.emit(error); }); } handleErrors() { this.progressBarShow = false; this.enableUploadBtn = false; this.uploadMsg = true; this.afterUpload = true; this.uploadMsgText = this.replaceTexts.afterUploadMsg_error; this.uploadMsgClass = 'text-danger lead'; } removeFile(i, sf_na) { if (sf_na === 'sf') { this.allowedFiles.splice(i, 1); this.Caption.splice(i, 1); } else { this.notAllowedFiles.splice(i, 1); } if (this.allowedFiles.length === 0) { this.enableUploadBtn = false; } } convertSize(fileSize) { return fileSize < 1024000 ? (fileSize / 1024).toFixed(2) + ' KB' : (fileSize / 1024000).toFixed(2) + ' MB'; } attachpinOnclick() { const element = document.getElementById('sel' + this.id); if (element !== null) { element.click(); } } drop(event) { event.stopPropagation(); event.preventDefault(); this.onChange(event); } allowDrop(event) { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = 'copy'; } } AngularFileUploaderComponent.decorators = [ { type: Component, args: [{ selector: 'angular-file-uploader', template: "<div class=\"container\" *ngIf=\"(theme !== 'attachPin')\" id=\"default\">\r\n\r\n <!-- Drag n Drop theme Starts -->\r\n <div *ngIf=\"theme == 'dragNDrop'\" id=\"dragNDrop\"\r\n [ngClass]=\"(hideSelectBtn && hideResetBtn) ? null : 'dragNDropBtmPad'\" class=\"dragNDrop\">\r\n <div style=\"position:relative;\">\r\n <div id=\"div1\" class=\"div1 afu-dragndrop-box\" (drop)=\"drop($event)\" (dragover)=\"allowDrop($event)\">\r\n <p class=\"afu-dragndrop-text\">{{replaceTexts?.dragNDropBox}}</p>\r\n </div>\r\n <!-- <span class='label label-info' id=\"upload-file-info{{id}}\">{{allowedFiles[0]?.name}}</span> -->\r\n </div>\r\n </div>\r\n <!-- Drag n Drop theme Ends -->\r\n\r\n <label for=\"sel{{id}}\" class=\"btn btn-primary btn-sm afu-select-btn\" [ngClass]=\"progressBarShow ? 'disabled' : null\"\r\n *ngIf=\"!hideSelectBtn\">{{replaceTexts?.selectFileBtn}}</label>\r\n <input type=\"file\" id=\"sel{{id}}\" style=\"display: none\" *ngIf=\"!hideSelectBtn\" [disabled]=\"progressBarShow\"\r\n (change)=\"onChange($event)\" title=\"Select file\" name=\"files[]\" [accept]=formatsAllowed\r\n [attr.multiple]=\"multiple ? '' : null\" />\r\n <button class=\"btn btn-info btn-sm resetBtn afu-reset-btn\" (click)=\"resetFileUpload()\" *ngIf=\"!hideResetBtn\"\r\n [disabled]=\"progressBarShow\">{{replaceTexts?.resetBtn}}</button>\r\n <br *ngIf=\"!hideSelectBtn\">\r\n <p class=\"constraints-info afu-constraints-info\">{{formatsAllowedText}} {{replaceTexts?.sizeLimit}}:\r\n {{(convertSize(maxSize))}}\r\n </p>\r\n <!--Allowed file list-->\r\n <div class=\"row afu-valid-file\" *ngFor=\"let sf of allowedFiles;let i=index\">\r\n <p class=\"col-xs-3 textOverflow\"><span class=\"text-primary\">{{sf.name}}</span></p>\r\n <p class=\"col-xs-3 padMarg sizeC\"><strong>({{convertSize(sf.size)}})</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\r\n <!-- <input class=\"col-xs-3 progress caption\" type=\"text\" placeholder=\"Caption..\" [(ngModel)]=\"Caption[i]\" *ngIf=\"!uploadStarted\"/> -->\r\n <div class=\"progress col-xs-3 padMarg afu-progress-bar\"\r\n *ngIf=\"isAllowedFileSingle && progressBarShow && !hideProgressBar\">\r\n <span class=\"progress-bar progress-bar-success\" role=\"progressbar\"\r\n [ngStyle]=\"{'width':uploadPercent+'%'}\">{{uploadPercent}}%</span>\r\n </div>\r\n <a class=\"col-xs-1\" role=\"button\" (click)=\"removeFile(i,'sf')\" *ngIf=\"!uploadStarted\"><i\r\n class=\"fa fa-times\"></i></a>\r\n </div>\r\n <!--Not Allowed file list-->\r\n <div class=\"row text-danger afu-invalid-file\" *ngFor=\"let na of notAllowedFiles;let j=index\">\r\n <p class=\"col-xs-3 textOverflow\"><span>{{na['fileName']}}</span></p>\r\n <p class=\"col-xs-3 padMarg sizeC\"><strong>({{na['fileSize']}})</strong></p>\r\n <p class=\"col-xs-3 \">{{na['errorMsg']}}</p>\r\n <a class=\"col-xs-1 delFileIcon\" role=\"button\" (click)=\"removeFile(j,'na')\" *ngIf=\"!uploadStarted\">&nbsp;<i\r\n class=\"fa fa-times\"></i></a>\r\n </div>\r\n\r\n <p *ngIf=\"uploadMsg\" class=\"{{uploadMsgClass}} + afu-upload-status\">{{uploadMsgText}}\r\n <p>\r\n <div *ngIf=\"!isAllowedFileSingle && progressBarShow && !hideProgressBar\">\r\n <div class=\"progress col-xs-4 padMarg afu-progress-bar\">\r\n <span class=\"progress-bar progress-bar-success\" role=\"progressbar\"\r\n [ngStyle]=\"{'width':uploadPercent+'%'}\">{{uploadPercent}}%</span>\r\n </div>\r\n <br>\r\n <br>\r\n </div>\r\n <button class=\"btn btn-success afu-upload-btn\" type=\"button\" (click)=\"uploadFiles()\"\r\n [disabled]=\"!enableUploadBtn && progressBarShow\" *ngIf=\"!autoUpload\">{{replaceTexts?.uploadBtn}}</button>\r\n <br>\r\n</div>\r\n\r\n<!--/////////////////////////// ATTACH PIN THEME //////////////////////////////////////////////////////////-->\r\n<div *ngIf=\"theme == 'attachPin'\" id=\"attachPin\">\r\n <div style=\"position:relative;padding-left:6px\">\r\n <a class='btn up_btn afu-attach-pin' (click)=\"attachpinOnclick()\">\r\n {{replaceTexts?.attachPinBtn}}\r\n <i class=\"fa fa-paperclip\" aria-hidden=\"true\"></i>\r\n <!-- <p style=\"margin-top:10px\">({{formatsAllowedText}}) Size limit- {{(convertSize(maxSize))}}</p> -->\r\n <input type=\"file\" id=\"sel{{id}}\" (change)=\"onChange($event)\" style=\"display: none\" title=\"Select file\"\r\n name=\"files[]\" [accept]=formatsAllowed [attr.multiple]=\"multiple ? '' : null\" />\r\n <br>\r\n </a>\r\n &nbsp;\r\n <span class='label label-info' id=\"upload-file-info{{id}}\">{{allowedFiles[0]?.name}}</span>\r\n </div>\r\n</div>", styles: [".constraints-info{font-style:italic;margin-top:10px}.padMarg{margin-bottom:0;padding:0}.caption{margin-right:5px}.textOverflow{overflow:hidden;padding-right:0;text-overflow:ellipsis;white-space:nowrap}.up_btn{background-color:transparent;border:2px solid #5c5b5b;border-radius:22px;color:#000}.delFileIcon{color:#ce0909;text-decoration:none}.selectBtnDisabled{background-color:#ccc;border:1px solid #999;color:#666;cursor:no-drop}.dragNDrop .div1{border:2px dashed #5c5b5b;display:border-box;height:6rem;width:20rem}.dragNDrop .div1>p{color:#5c5b5b;font-weight:700;margin-top:1.4em;text-align:center}.dragNDropBtmPad{padding-bottom:2rem}@media screen and (max-width:620px){.caption{padding:0}}@media screen and (max-width:510px){.sizeC{width:25%}}@media screen and (max-width:260px){.caption,.sizeC{font-size:10px}}.resetBtn{margin-left:3px}"] },] } ]; AngularFileUploaderComponent.ctorParameters = () => [ { type: HttpClient, decorators: [{ type: SkipSelf }] } ]; AngularFileUploaderComponent.propDecorators = { config: [{ type: Input }], resetUpload: [{ type: Input }], ApiResponse: [{ type: Output }], fileSelected: [{ type: Output }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci1maWxlLXVwbG9hZGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItZmlsZS11cGxvYWRlci9zcmMvbGliL2FuZ3VsYXItZmlsZS11cGxvYWRlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFFTixRQUFRLEdBQ1QsTUFBTSxlQUFlLENBQUM7QUFPdkIsT0FBTyxFQUNMLFVBQVUsRUFHVixhQUFhLEdBQ2QsTUFBTSxzQkFBc0IsQ0FBQztBQVE5QixNQUFNLE9BQU8sNEJBQTRCO0lBc0R2QyxZQUFnQyxJQUFnQjtRQUFoQixTQUFJLEdBQUosSUFBSSxDQUFZO1FBaERoRCxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUVwQixVQUFVO1FBRVYsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBR2pDLGlCQUFZLEdBQStCLElBQUksWUFBWSxFQUFnQixDQUFDO1FBaUI1RSxpQkFBWSxHQUFXLEVBQUUsQ0FBQztRQUMxQixvQkFBZSxHQUlULEVBQUUsQ0FBQztRQUNULFlBQU8sR0FBYSxFQUFFLENBQUM7UUFDdkIsd0JBQW1CLEdBQUcsSUFBSSxDQUFDO1FBQzNCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFDbEIsZ0JBQVcsR0FBRyxLQUFLLENBQUM7UUFDcEIsa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFLdEIsbUJBQWMsR0FBVSxFQUFFLENBQUM7UUFDM0Isa0JBQWEsR0FBRyxJQUFJLENBQUM7UUFDckIsb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFDeEIsZUFBVSxHQUFHLEtBQUssQ0FBQztRQUVYLFdBQU0sR0FBVyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUM7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QUN4QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBRUQsU0FBUyxDQUFDLEtBQVU7UUFDbEIsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7SUFDekMsQ0FBQzs7O1lBalRGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsdUJBQXVCO2dCQUNqQyxra0pBQXFEOzthQUV0RDs7O1lBWEMsVUFBVSx1QkFrRUcsUUFBUTs7O3FCQXBEcEIsS0FBSzswQkFHTCxLQUFLOzBCQUlMLE1BQU07MkJBR04sTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgU2tpcFNlbGYsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgUmVwbGFjZVRleHRzLFxuICBBbmd1bGFyRmlsZVVwbG9hZGVyQ29uZmlnLFxuICBVcGxvYWRJbmZvLFxuICBVcGxvYWRBcGksXG59IGZyb20gJy4vYW5ndWxhci1maWxlLXVwbG9hZGVyLnR5cGVzJztcbmltcG9ydCB7XG4gIEh0dHBDbGllbnQsXG4gIEh0dHBIZWFkZXJzLFxuICBIdHRwUGFyYW1zLFxuICBIdHRwRXZlbnRUeXBlLFxufSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBtYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FuZ3VsYXItZmlsZS11cGxvYWRlcicsXG4gIHRlbXBsYXRlVXJsOiAnLi9hbmd1bGFyLWZpbGUtdXBsb2FkZXIuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9hbmd1bGFyLWZpbGUtdXBsb2FkZXIuY29tcG9uZW50LmNzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBBbmd1bGFyRmlsZVVwbG9hZGVyQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLy8gSW5wdXRzXG4gIEBJbnB1dCgpXG4gIGNvbmZpZzogQW5ndWxhckZpbGVVcGxvYWRlckNvbmZpZztcblxuICBASW5wdXQoKVxuICByZXNldFVwbG9hZCA9IGZhbHNlO1xuXG4gIC8vIE91dHB1dHNcbiAgQE91dHB1dCgpXG4gIEFwaVJlc3BvbnNlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBPdXRwdXQoKVxuICBmaWxlU2VsZWN0ZWQ6IEV2ZW50RW1pdHRlcjxVcGxvYWRJbmZvW10+ID0gbmV3IEV2ZW50RW1pdHRlcjxVcGxvYWRJbmZvW10+KCk7XG5cbiAgLy8gUHJvcGVydGllc1xuICB0aGVtZTogc3RyaW5nO1xuICBpZDogbnVtYmVyO1xuICBoaWRlUHJvZ3Jlc3NCYXI6IGJvb2xlYW47XG4gIG1heFNpemU6IG51bWJlcjtcbiAgdXBsb2FkQVBJOiBzdHJpbmc7XG4gIG1ldGhvZDogc3RyaW5nO1xuICBmb3JtYXRzQWxsb3dlZDogc3RyaW5nO1xuICBmb3JtYXRzQWxsb3dlZFRleHQ6IHN0cmluZztcbiAgbXVsdGlwbGU6IGJvb2xlYW47XG4gIGhlYWRlcnM6IEh0dHBIZWFkZXJzIHwgeyBbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXSB9O1xuICBwYXJhbXM6IEh0dHBQYXJhbXMgfCB7IFtwYXJhbTogc3RyaW5nXTogc3RyaW5nIHwgc3RyaW5nW10gfTtcbiAgcmVzcG9uc2VUeXBlOiAnanNvbicgfCAnYXJyYXlidWZmZXInIHwgJ2Jsb2InIHwgJ3RleHQnO1xuICBoaWRlUmVzZXRCdG46IGJvb2xlYW47XG4gIGhpZGVTZWxlY3RCdG46IGJvb2xlYW47XG4gIGFsbG93ZWRGaWxlczogRmlsZVtdID0gW107XG4gIG5vdEFsbG93ZWRGaWxlczoge1xuICAgIGZpbGVOYW1lOiBzdHJpbmc7XG4gICAgZmlsZVNpemU6IHN0cmluZztcbiAgICBlcnJvck1zZzogc3RyaW5nO1xuICB9W10gPSBbXTtcbiAgQ2FwdGlvbjogc3RyaW5nW10gPSBbXTtcbiAgaXNBbGxvd2VkRmlsZVNpbmdsZSA9IHRydWU7XG4gIHByb2dyZXNzQmFyU2hvdyA9IGZhbHNlO1xuICBlbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgdXBsb2FkTXNnID0gZmFsc2U7XG4gIGFmdGVyVXBsb2FkID0gZmFsc2U7XG4gIHVwbG9hZFN0YXJ0ZWQgPSBmYWxzZTtcbiAgdXBsb2FkTXNnVGV4dDogc3RyaW5nO1xuICB1cGxvYWRNc2dDbGFzczogc3RyaW5nO1xuICB1cGxvYWRQZXJjZW50OiBudW1iZXI7XG4gIHJlcGxhY2VUZXh0czogUmVwbGFjZVRleHRzO1xuICBjdXJyZW50VXBsb2FkczogYW55W10gPSBbXTtcbiAgZmlsZU5hbWVJbmRleCA9IHRydWU7XG4gIHdpdGhDcmVkZW50aWFscyA9IGZhbHNlO1xuICBhdXRvVXBsb2FkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBpZERhdGU6IG51bWJlciA9ICtuZXcgRGF0ZSgpO1xuXG4gIGNvbnN0cnVjdG9yKEBTa2lwU2VsZigpIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCkge31cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgLy8gVHJhY2sgY2hhbmdlcyBpbiBDb25maWd1cmF0aW9uIGFuZCBzZWUgaWYgdXNlciBoYXMgZXZlbiBwcm92aWRlZCBDb25maWd1cmF0aW9uLlxuICAgIGlmIChjaGFuZ2VzLmNvbmZpZyAmJiB0aGlzLmNvbmZpZykge1xuICAgICAgLy8gQXNzaWduIFVzZXIgQ29uZmlndXJhdGlvbnMgdG8gTGlicmFyeSBQcm9wZXJ0aWVzLlxuICAgICAgdGhpcy50aGVtZSA9IHRoaXMuY29uZmlnLnRoZW1lIHx8ICcnO1xuICAgICAgdGhpcy5pZCA9XG4gICAgICAgIHRoaXMuY29uZmlnLmlkIHx8XG4gICAgICAgIHBhcnNlSW50KCh0aGlzLmlkRGF0ZSAvIDEwMDAwKS50b1N0cmluZygpLnNwbGl0KCcuJylbMV0sIDEwKSArXG4gICAgICAgICAgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjApICogMTAwMDA7XG4gICAgICB0aGlzLmhpZGVQcm9ncmVzc0JhciA9IHRoaXMuY29uZmlnLmhpZGVQcm9ncmVzc0JhciB8fCBmYWxzZTtcbiAgICAgIHRoaXMuaGlkZVJlc2V0QnRuID0gdGhpcy5jb25maWcuaGlkZVJlc2V0QnRuIHx8IGZhbHNlO1xuICAgICAgdGhpcy5oaWRlU2VsZWN0QnRuID0gdGhpcy5jb25maWcuaGlkZVNlbGVjdEJ0biB8fCBmYWxzZTtcbiAgICAgIHRoaXMubWF4U2l6ZSA9ICh0aGlzLmNvbmZpZy5tYXhTaXplIHx8IDIwKSAqIDEwMjQwMDA7IC8vIG1iIHRvIGJ5dGVzLlxuICAgICAgdGhpcy51cGxvYWRBUEkgPSB0aGlzLmNvbmZpZy51cGxvYWRBUEkudXJsO1xuICAgICAgdGhpcy5tZXRob2QgPSB0aGlzLmNvbmZpZy51cGxvYWRBUEkubWV0aG9kIHx8ICdQT1NUJztcbiAgICAgIHRoaXMuZm9ybWF0c0FsbG93ZWQgPSB0aGlzLmNvbmZpZy5mb3JtYXRzQWxsb3dlZCB8fCAnKic7XG4gICAgICB0aGlzLmZvcm1hdHNBbGxvd2VkVGV4dCA9XG4gICAgICAgIHRoaXMuZm9ybWF0c0FsbG93ZWQgPT09ICcqJyA/ICcnIDogJygnICsgdGhpcy5mb3JtYXRzQWxsb3dlZCArICcpJztcbiAgICAgIHRoaXMubXVsdGlwbGUgPSB0aGlzLmNvbmZpZy5tdWx0aXBsZSB8fCBmYWxzZTtcbiAgICAgIHRoaXMuaGVhZGVycyA9IHRoaXMuY29uZmlnLnVwbG9hZEFQSS5oZWFkZXJzIHx8IHt9O1xuICAgICAgdGhpcy5wYXJhbXMgPSB0aGlzLmNvbmZpZy51cGxvYWRBUEkucGFyYW1zIHx8IHt9O1xuICAgICAgdGhpcy5yZXNwb25zZVR5cGUgPSB0aGlzLmNvbmZpZy51cGxvYWRBUEkucmVzcG9uc2VUeXBlIHx8ICdqc29uJztcbiAgICAgIHRoaXMud2l0aENyZWRlbnRpYWxzID0gdGhpcy5jb25maWcudXBsb2FkQVBJLndpdGhDcmVkZW50aWFscyB8fCBmYWxzZTtcbiAgICAgIHRoaXMuZmlsZU5hbWVJbmRleCA9IHRoaXMuY29uZmlnLmZpbGVOYW1lSW5kZXggPT09IGZhbHNlID8gZmFsc2UgOiB0cnVlO1xuICAgICAgdGhpcy5hdXRvVXBsb2FkID0gdGhpcy5jb25maWcuYXV0b1VwbG9hZCB8fCBmYWxzZTtcblxuICAgICAgdGhpcy5yZXBsYWNlVGV4dHMgPSB7XG4gICAgICAgIHNlbGVjdEZpbGVCdG46IHRoaXMubXVsdGlwbGUgPyAnU2VsZWN0IEZpbGVzJyA6ICdTZWxlY3QgRmlsZScsXG4gICAgICAgIHJlc2V0QnRuOiAnUmVzZXQnLFxuICAgICAgICB1cGxvYWRCdG46ICdVcGxvYWQnLFxuICAgICAgICBkcmFnTkRyb3BCb3g6ICdEcmFnIE4gRHJvcCcsXG4gICAgICAgIGF0dGFjaFBpbkJ0bjogdGhpcy5tdWx0aXBsZSA/ICdBdHRhY2ggRmlsZXMuLi4nIDogJ0F0dGFjaCBGaWxlLi4uJyxcbiAgICAgICAgYWZ0ZXJVcGxvYWRNc2dfc3VjY2VzczogJ1N1Y2Nlc3NmdWxseSBVcGxvYWRlZCAhJyxcbiAgICAgICAgYWZ0ZXJVcGxvYWRNc2dfZXJyb3I6ICdVcGxvYWQgRmFpbGVkICEnLFxuICAgICAgICBzaXplTGltaXQ6ICdTaXplIExpbWl0JyxcbiAgICAgIH07IC8vIGRlZmF1bHQgcmVwbGFjZVRleHQuXG4gICAgICBpZiAodGhpcy5jb25maWcucmVwbGFjZVRleHRzKSB7XG4gICAgICAgIC8vIHVwZGF0ZWQgcmVwbGFjZVRleHQgaWYgdXNlciBoYXMgcHJvdmlkZWQgYW55LlxuICAgICAgICB0aGlzLnJlcGxhY2VUZXh0cyA9IHtcbiAgICAgICAgICAuLi50aGlzLnJlcGxhY2VUZXh0cyxcbiAgICAgICAgICAuLi50aGlzLmNvbmZpZy5yZXBsYWNlVGV4dHMsXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgd2hlbiByZXNldFVwbG9hZCB2YWx1ZSBjaGFuZ2VzIGZyb20gZmFsc2UgdG8gdHJ1ZS5cbiAgICBpZiAoY2hhbmdlcy5yZXNldFVwbG9hZCkge1xuICAgICAgaWYgKGNoYW5nZXMucmVzZXRVcGxvYWQuY3VycmVudFZhbHVlID09PSB0cnVlKSB7XG4gICAgICAgIHRoaXMucmVzZXRGaWxlVXBsb2FkKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmVzZXQgZm9sbG93aW5nIHByb3BlcnRpZXMuXG4gIHJlc2V0RmlsZVVwbG9hZCgpIHtcbiAgICB0aGlzLmFsbG93ZWRGaWxlcyA9IFtdO1xuICAgIHRoaXMuQ2FwdGlvbiA9IFtdO1xuICAgIHRoaXMubm90QWxsb3dlZEZpbGVzID0gW107XG4gICAgdGhpcy51cGxvYWRNc2cgPSBmYWxzZTtcbiAgICB0aGlzLmVuYWJsZVVwbG9hZEJ0biA9IGZhbHNlO1xuICB9XG5cbiAgLy8gV2hlbiB1c2VyIHNlbGVjdHMgZmlsZXMuXG4gIG9uQ2hhbmdlKGV2ZW50OiBhbnkpIHtcbiAgICB0aGlzLmZpbGVTZWxlY3RlZC5lbWl0KGV2ZW50KTtcbiAgICB0aGlzLm5vdEFsbG93ZWRGaWxlcyA9IFtdO1xuICAgIGNvbnN0IGZpbGVFeHRSZWdFeHA6IFJlZ0V4cCA9IC8oPzpcXC4oW14uXSspKT8kLztcbiAgICBsZXQgZmlsZUxpc3Q6IEZpbGVMaXN0O1xuXG4gICAgaWYgKHRoaXMuYWZ0ZXJVcGxvYWQgfHwgIXRoaXMubXVsdGlwbGUpIHtcbiAgICAgIHRoaXMuYWxsb3dlZEZpbGVzID0gW107XG4gICAgICB0aGlzLkNhcHRpb24gPSBbXTtcbiAgICAgIHRoaXMuYWZ0ZXJVcGxvYWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnQudHlwZSA9PT0gJ2Ryb3AnKSB7XG4gICAgICBmaWxlTGlzdCA9IGV2ZW50LmRhdGFUcmFuc2Zlci5maWxlcztcbiAgICB9IGVsc2Uge1xuICAgICAgZmlsZUxpc3QgPSBldmVudC50YXJnZXQuZmlsZXMgfHwgZXZlbnQuc3JjRWxlbWVudC5maWxlcztcbiAgICB9XG5cbiAgICAvLyAnZm9yRWFjaCcgZG9lcyBub3QgZXhpc3Qgb24gJ2ZpbGVsaXN0JyB0aGF0J3Mgd2h5IHRoaXMgZ29vZCBvbGQgJ2ZvcicgaXMgdXNlZC5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZpbGVMaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjdXJyZW50RmlsZUV4dCA9IGZpbGVFeHRSZWdFeHBcbiAgICAgICAgLmV4ZWMoZmlsZUxpc3RbaV0ubmFtZSlbMV1cbiAgICAgICAgLnRvTG93ZXJDYXNlKCk7IC8vIEdldCBmaWxlIGV4dGVuc2lvbi5cbiAgICAgIGNvbnN0IGlzRm9ybWF0VmFsaWQgPSB0aGlzLmZvcm1hdHNBbGxvd2VkLmluY2x1ZGVzKCcqJylcbiAgICAgICAgPyB0cnVlXG4gICAgICAgIDogdGhpcy5mb3JtYXRzQWxsb3dlZC5pbmNsdWRlcyhjdXJyZW50RmlsZUV4dCk7XG5cbiAgICAgIGNvbnN0IGlzU2l6ZVZhbGlkID0gZmlsZUxpc3RbaV0uc2l6ZSA8PSB0aGlzLm1heFNpemU7XG5cbiAgICAgIC8vIENoZWNrIHdoZXRoZXIgY3VycmVudCBmaWxlIGZvcm1hdCBhbmQgc2l6ZSBpcyBjb3JyZWN0IGFzIHNwZWNpZmllZCBpbiB0aGUgY29uZmlndXJhdGlvbnMuXG4gICAgICBpZiAoaXNGb3JtYXRWYWxpZCAmJiBpc1NpemVWYWxpZCkge1xuICAgICAgICB0aGlzLmFsbG93ZWRGaWxlcy5wdXNoKGZpbGVMaXN0W2ldKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubm90QWxsb3dlZEZpbGVzLnB1c2goe1xuICAgICAgICAgIGZpbGVOYW1lOiBmaWxlTGlzdFtpXS5uYW1lLFxuICAgICAgICAgIGZpbGVTaXplOiB0aGlzLmNvbnZlcnRTaXplKGZpbGVMaXN0W2ldLnNpemUpLFxuICAgICAgICAgIGVycm9yTXNnOiAhaXNGb3JtYXRWYWxpZCA/ICdJbnZhbGlkIGZvcm1hdCcgOiAnSW52YWxpZCBzaXplJyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlcmUncyBhbnkgYWxsb3dlZEZpbGVzLlxuICAgIGlmICh0aGlzLmFsbG93ZWRGaWxlcy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLmVuYWJsZVVwbG9hZEJ0biA9IHRydWU7XG4gICAgICAvLyBVcGxvYWQgdGhlIGZpbGVzIGRpcmVjdGx5IGlmIHRoZW1lIGlzIGF0dGFjaCBwaW4gKGFzIHVwbG9hZCBidG4gaXMgbm90IHRoZXJlIGZvciB0aGlzIHRoZW1lKSBvciBhdXRvVXBsb2FkIGlzIHRydWUuXG4gICAgICBpZiAodGhpcy50aGVtZSA9PT0gJ2F0dGFjaFBpbicgfHwgdGhpcy5hdXRvVXBsb2FkKSB7XG4gICAgICAgIHRoaXMudXBsb2FkRmlsZXMoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLnVwbG9hZE1zZyA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkU3RhcnRlZCA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkUGVyY2VudCA9IDA7XG4gICAgZXZlbnQudGFyZ2V0LnZhbHVlID0gbnVsbDtcbiAgfVxuXG4gIHVwbG9hZEZpbGVzKCkge1xuICAgIHRoaXMucHJvZ3Jlc3NCYXJTaG93ID0gdHJ1ZTtcbiAgICB0aGlzLnVwbG9hZFN0YXJ0ZWQgPSB0cnVlO1xuICAgIHRoaXMubm90QWxsb3dlZEZpbGVzID0gW107XG4gICAgbGV0IGlzRXJyb3IgPSBmYWxzZTtcbiAgICB0aGlzLmlzQWxsb3dlZEZpbGVTaW5nbGUgPSB0aGlzLmFsbG93ZWRGaWxlcy5sZW5ndGggPD0gMTtcbiAgICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuXG4gICAgLy8gQWRkIGRhdGEgdG8gYmUgc2VudCBpbiB0aGlzIHJlcXVlc3RcbiAgICB0aGlzLmFsbG93ZWRGaWxlcy5mb3JFYWNoKChmaWxlLCBpKSA9PiB7XG4gICAgICBmb3JtRGF0YS5hcHBlbmQoXG4gICAgICAgIHRoaXMuQ2FwdGlvbltpXSB8fCAnZmlsZScgKyAodGhpcy5maWxlTmFtZUluZGV4ID8gaSA6ICcnKSxcbiAgICAgICAgdGhpcy5hbGxvd2VkRmlsZXNbaV1cbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICAvKlxuICAgIE5vdCBXb3JraW5nLCBIZWFkZXJzIG51bGxcbiAgICAvLyBDb250cnVjdCBIZWFkZXJzXG4gICAgY29uc3QgaGVhZGVycyA9IG5ldyBIdHRwSGVhZGVycygpO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHRoaXMuaGVhZGVycykpIHtcbiAgICAgIGhlYWRlcnMuYXBwZW5kKGtleSwgdGhpcy5oZWFkZXJzW2tleV0pO1xuICAgIH1cblxuICAgIC8vIENvbnRydWN0IFBhcmFtc1xuICAgIGNvbnN0IHBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKCk7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXModGhpcy5wYXJhbXMpKSB7XG4gICAgICBwYXJhbXMuYXBwZW5kKGtleSwgdGhpcy5wYXJhbXNba2V5XSk7XG4gICAgfSAqL1xuXG4gICAgdGhpcy5odHRwXG4gICAgICAucmVxdWVzdCh0aGlzLm1ldGhvZC50b1VwcGVyQ2FzZSgpLCB0aGlzLnVwbG9hZEFQSSwge1xuICAgICAgICBib2R5OiBmb3JtRGF0YSxcbiAgICAgICAgcmVwb3J0UHJvZ3Jlc3M6IHRydWUsXG4gICAgICAgIG9ic2VydmU6ICdldmVudHMnLFxuICAgICAgICBoZWFkZXJzOiB0aGlzLmhlYWRlcnMsXG4gICAgICAgIHBhcmFtczogdGhpcy5wYXJhbXMsXG4gICAgICAgIHJlc3BvbnNlVHlwZTogdGhpcy5yZXNwb25zZVR5cGUsXG4gICAgICAgIHdpdGhDcmVkZW50aWFsczogdGhpcy53aXRoQ3JlZGVudGlhbHMsXG4gICAgICB9KVxuICAgICAgLnN1YnNjcmliZShcbiAgICAgICAgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgLy8gVXBsb2FkIFByb2dyZXNzXG4gICAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IEh0dHBFdmVudFR5cGUuVXBsb2FkUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgIHRoaXMuZW5hYmxlVXBsb2FkQnRuID0gZmFsc2U7IC8vIGJ1dHRvbiBzaG91bGQgYmUgZGlzYWJsZWQgaWYgcHJvY2VzcyB1cGxvYWRpbmdcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnREb25lID0gZXZlbnQubG9hZGVkIC8gZXZlbnQudG90YWw7XG4gICAgICAgICAgICB0aGlzLnVwbG9hZFBlcmNlbnQgPSBNYXRoLnJvdW5kKChldmVudC5sb2FkZWQgLyBldmVudC50b3RhbCkgKiAxMDApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gSHR0cEV2ZW50VHlwZS5SZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGV2ZW50LnN0YXR1cyA9PT0gMjAwIHx8IGV2ZW50LnN0YXR1cyA9PT0gMjAxKSB7XG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcbiAgICAgICAgICAgICAgdGhpcy5wcm9ncmVzc0JhclNob3cgPSBmYWxzZTtcbiAgICAgICAgICAgICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgICAgICAgICAgICAgdGhpcy51cGxvYWRNc2cgPSB0cnVlO1xuICAgICAgICAgICAgICB0aGlzLmFmdGVyVXBsb2FkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgaWYgKCFpc0Vycm9yKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGxvYWRNc2dUZXh0ID0gdGhpcy5yZXBsYWNlVGV4dHMuYWZ0ZXJVcGxvYWRNc2dfc3VjY2VzcztcbiAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZE1zZ0NsYXNzID0gJ3RleHQtc3VjY2VzcyBsZWFkJztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gRmFpbHVyZVxuICAgICAgICAgICAgICBpc0Vycm9yID0gdHJ1ZTtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVFcnJvcnMoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5BcGlSZXNwb25zZS5lbWl0KGV2ZW50KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy9jb25zb2xlLmxvZygnRXZlbnQgT3RoZXI6ICcsIGV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICAgIC8vIEZhaWx1cmVcbiAgICAgICAgICBpc0Vycm9yID0gdHJ1ZTtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVycm9ycygpO1xuICAgICAgICAgIHRoaXMuQXBpUmVzcG9uc2UuZW1pdChlcnJvcik7XG4gICAgICAgIH1cbiAgICAgICk7XG4gIH1cblxuICBoYW5kbGVFcnJvcnMoKSB7XG4gICAgdGhpcy5wcm9ncmVzc0JhclNob3cgPSBmYWxzZTtcbiAgICB0aGlzLmVuYWJsZVVwbG9hZEJ0biA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkTXNnID0gdHJ1ZTtcbiAgICB0aGlzLmFmdGVyVXBsb2FkID0gdHJ1ZTtcbiAgICB0aGlzLnVwbG9hZE1zZ1RleHQgPSB0aGlzLnJlcGxhY2VUZXh0cy5hZnRlclVwbG9hZE1zZ19lcnJvcjtcbiAgICB0aGlzLnVwbG9hZE1zZ0NsYXNzID0gJ3RleHQtZGFuZ2VyIGxlYWQnO1xuICB9XG5cbiAgcmVtb3ZlRmlsZShpOiBhbnksIHNmX25hOiBhbnkpIHtcbiAgICBpZiAoc2ZfbmEgPT09ICdzZicpIHtcbiAgICAgIHRoaXMuYWxsb3dlZEZpbGVzLnNwbGljZShpLCAxKTtcbiAgICAgIHRoaXMuQ2FwdGlvbi5zcGxpY2UoaSwgMSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubm90QWxsb3dlZEZpbGVzLnNwbGljZShpLCAxKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5hbGxvd2VkRmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLmVuYWJsZVVwbG9hZEJ0biA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIGNvbnZlcnRTaXplKGZpbGVTaXplOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIHJldHVybiBmaWxlU2l6ZSA8IDEwMjQwMDBcbiAgICAgID8gKGZpbGVTaXplIC8gMTAyNCkudG9GaXhlZCgyKSArICcgS0InXG4gICAgICA6IChmaWxlU2l6ZSAvIDEwMjQwMDApLnRvRml4ZWQoMikgKyAnIE1CJztcbiAgfVxuXG4gIGF0dGFjaHBpbk9uY2xpY2soKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZWwnICsgdGhpcy5pZCk7XG4gICAgaWYgKGVsZW1lbnQgIT09IG51bGwpIHtcbiAgICAgIGVsZW1lbnQuY2xpY2soKTtcbiAgICB9XG4gIH1cblxuICBkcm9wKGV2ZW50OiBhbnkpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMub25DaGFuZ2UoZXZlbnQpO1xuICB9XG5cbiAgYWxsb3dEcm9wKGV2ZW50OiBhbnkpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGV2ZW50LmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0ID0gJ2NvcHknO1xuICB9XG59XG4iXX0=