UNPKG

ngxc-file-uploader

Version:

Ngxc file uploader is an Angular 9/10 + file uploader

339 lines 44.1 kB
import { Component, EventEmitter, Input, Output, ViewEncapsulation, } from '@angular/core'; import { HttpClient, HttpEventType, } from '@angular/common/http'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; export class NgxFileUploaderComponent { /** * constructor * * @param {HttpClient} http * */ constructor(http) { this.http = http; this.resetUpload = false; // Outputs this.ApiResponse = new EventEmitter(); this.uploadInitiated = new EventEmitter(); this.everythingDone = 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.idDate = +new Date(); this.destroy = new Subject(); } /** * ngOnChanges * * @param {SimpleChanges} changes * * @return {void} */ 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 || '.jpg,.png,.pdf,.docx,.txt,.gif,.jpeg'; this.multiple = this.config.multiple || false; this.headers = this.config.uploadAPI.headers || {}; this.params = this.config.uploadAPI.params || {}; this.responseType = this.config.uploadAPI.responseType || null; this.fileNameIndex = this.config.fileNameIndex === false ? false : true; this.replaceTexts = { selectFileBtn: this.multiple ? 'Select Files' : 'Select File', resetBtn: 'Reset', uploadBtn: 'Upload', dragNDropBox: 'Drag N Drop', pleaseWaitMessage: 'Please wait until file is uploaded', 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(); } } } /** * ngOnDestroy * * @return {void} */ ngOnDestroy() { this.destroy.next(); this.destroy.complete(); } /** * resetFileUpload * Reset following properties. * * @return {void} */ resetFileUpload() { this.allowedFiles = []; this.Caption = []; this.notAllowedFiles = []; this.uploadMsg = false; this.enableUploadBtn = false; } /** * onChange hook * - Check when user selects files. * * @param {any} event * * @return {void} */ onChange(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(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). if (this.theme === 'attachPin') { this.uploadFiles(); } } else { this.enableUploadBtn = false; } this.uploadMsg = false; this.uploadStarted = false; this.uploadPercent = 0; event.target.value = null; } /** * uploadFiles * * @return {void} */ uploadFiles() { this.uploadInitiated.emit(true); 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]); }); const options = { headers: this.headers, params: this.params, }; if (this.responseType) { options.responseType = this.responseType; } this.httpCallSubscription = this.http .request(this.method.toUpperCase(), this.uploadAPI, Object.assign({ body: formData, reportProgress: true, observe: 'events' }, options)).pipe(takeUntil(this.destroy)).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.uploadStarted = false; this.uploadInitiated.emit(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 * * @return {void} */ handleErrors() { this.progressBarShow = false; this.enableUploadBtn = false; this.uploadMsg = true; this.afterUpload = true; this.uploadMsgText = this.replaceTexts.afterUploadMsg_error; this.uploadMsgClass = 'text-danger lead'; this.uploadStarted = false; this.uploadInitiated.emit(false); } /** * removeFile * * @param {any} i * @param {any} sfNa * * @return {void} */ removeFile(i, sfNa) { if (sfNa === '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 * * @param {number} fileSize * * @return {string} */ convertSize(fileSize) { return fileSize < 1024000 ? (fileSize / 1024).toFixed(2) + ' KB' : (fileSize / 1024000).toFixed(2) + ' MB'; } /** * attachpinOnclick * * @return {void} */ attachpinOnclick() { const element = document.getElementById('sel' + this.id); if (element !== null) { element.click(); } } /** * drop * * @param {any} event * * @return {void} */ drop(event) { event.stopPropagation(); event.preventDefault(); this.onChange(event); } /** * allowDrop * * @param {any} event * * @return {void} */ allowDrop(event) { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = 'copy'; } /** * cancelApiCall * * @return {void} */ cancelApiCall() { if (this.httpCallSubscription) { this.httpCallSubscription.unsubscribe(); } } } NgxFileUploaderComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-file-uploader', template: "<div class=\"container\" *ngIf=\"(theme !== 'attachPin')\" id=\"default\">\n\n <!-- Drag n Drop theme Starts -->\n <div *ngIf=\"!uploadStarted && theme == 'dragNDrop'\" id=\"dragNDrop\"\n [ngClass]=\"(hideSelectBtn && hideResetBtn) ? null : 'dragNDropBtmPad'\" class=\"dragNDrop\">\n <div style=\"position:relative;\">\n <div id=\"div1\" class=\"div1 afu-dragndrop-box\" (drop)=\"drop($event)\" (dragover)=\"allowDrop($event)\">\n <p class=\"afu-dragndrop-text\">{{replaceTexts?.dragNDropBox}}</p>\n </div>\n <!-- <span class='label label-info' id=\"upload-file-info{{id}}\">{{allowedFiles[0]?.name}}</span> -->\n </div>\n </div>\n <!-- Drag n Drop theme Ends -->\n <label for=\"sel{{id}}\" class=\"btn btn-primary btn-sm afu-select-btn\"\n *ngIf=\"!uploadStarted && !hideSelectBtn\">{{replaceTexts?.selectFileBtn}}</label>\n <input type=\"file\" id=\"sel{{id}}\" style=\"display: none\" *ngIf=\"!hideSelectBtn\" (change)=\"onChange($event)\"\n title=\"Select file\" name=\"files[]\" [accept]=formatsAllowed [attr.multiple]=\"multiple ? '' : null\" />\n <button class=\"btn btn-info btn-sm resetBtn afu-reset-btn\" (click)=\"resetFileUpload()\"\n *ngIf=\"!hideResetBtn\">{{replaceTexts?.resetBtn}}</button>\n <br *ngIf=\"!hideSelectBtn\">\n <p class=\"constraints-info afu-constraints-info\">({{formatsAllowed}}) {{replaceTexts?.sizeLimit}}: {{(convertSize(maxSize))}}\n </p>\n <!--Allowed file list-->\n <div class=\"row afu-valid-file\" *ngFor=\"let sf of allowedFiles;let i=index\">\n <p class=\"col-xs-3 textOverflow\"><span class=\"text-primary\">{{sf.name}}</span></p>\n <p class=\"col-xs-3 padMarg sizeC\"><strong>({{convertSize(sf.size)}})</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\n <!-- <input class=\"col-xs-3 progress caption\" type=\"text\" placeholder=\"Caption..\" [(ngModel)]=\"Caption[i]\" *ngIf=\"!uploadStarted\"/> -->\n <div class=\"progress col-xs-3 padMarg afu-progress-bar\" *ngIf=\"isAllowedFileSingle && progressBarShow && !hideProgressBar\">\n <span class=\"progress-bar progress-bar-success\" role=\"progressbar\"\n [ngStyle]=\"{'width':uploadPercent+'%'}\">{{uploadPercent}}%</span>\n </div>\n <a class=\"col-xs-1\" role=\"button\" (click)=\"removeFile(i,'sf')\" *ngIf=\"!uploadStarted\"><i class=\"fa fa-times\"></i></a>\n </div>\n <!--Not Allowed file list-->\n <div class=\"row text-danger afu-invalid-file\" *ngFor=\"let na of notAllowedFiles;let j=index\">\n <p class=\"col-xs-3 textOverflow\"><span>{{na['fileName']}}</span></p>\n <p class=\"col-xs-3 padMarg sizeC\"><strong>({{na['fileSize']}})</strong></p>\n <p class=\"col-xs-3 \">{{na['errorMsg']}}</p>\n <a class=\"col-xs-1 delFileIcon\" role=\"button\" (click)=\"removeFile(j,'na')\" *ngIf=\"!uploadStarted\">&nbsp;<i\n class=\"fa fa-times\"></i></a>\n </div>\n\n <p *ngIf=\"uploadMsg\" class=\"{{uploadMsgClass}} + afu-upload-status\">{{uploadMsgText}}<p>\n <div *ngIf=\"!isAllowedFileSingle && progressBarShow && !hideProgressBar\">\n <div class=\"progress col-xs-4 padMarg afu-progress-bar\">\n <span class=\"progress-bar progress-bar-success\" role=\"progressbar\"\n [ngStyle]=\"{'width':uploadPercent+'%'}\">{{uploadPercent}}%</span>\n </div>\n <br />\n <br />\n </div>\n <button *ngIf=\"!uploadStarted && enableUploadBtn\" class=\"btn btn-success afu-upload-btn\" type=\"button\" (click)=\"uploadFiles()\"\n >{{replaceTexts?.uploadBtn}}</button>\n <div *ngIf=\"uploadStarted\" class=\"uploading-message\" >{{replaceTexts?.pleaseWaitMessage}}</div>\n <br>\n</div>\n\n<!--/////////////////////////// ATTACH PIN THEME //////////////////////////////////////////////////////////-->\n<div *ngIf=\"theme == 'attachPin'\" id=\"attachPin\">\n <div style=\"position:relative;padding-left:6px\">\n <a class='btn up_btn afu-attach-pin' (click)=\"attachpinOnclick()\">\n {{replaceTexts?.attachPinBtn}}\n <i class=\"fa fa-paperclip\" aria-hidden=\"true\"></i>\n <!-- <p style=\"margin-top:10px\">({{formatsAllowed}}) Size limit- {{(convertSize(maxSize))}}</p> -->\n <input type=\"file\" id=\"sel{{id}}\" (change)=\"onChange($event)\" style=\"display: none\" title=\"Select file\"\n name=\"files[]\" [accept]=formatsAllowed [attr.multiple]=\"multiple ? '' : null\" />\n <br>\n </a>\n &nbsp;\n <span class='label label-info' id=\"upload-file-info{{id}}\">{{allowedFiles[0]?.name}}</span>\n </div>\n</div>\n\n", encapsulation: ViewEncapsulation.None, 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}.uploading-message{margin:15px 0}.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}"] },] } ]; NgxFileUploaderComponent.ctorParameters = () => [ { type: HttpClient } ]; NgxFileUploaderComponent.propDecorators = { config: [{ type: Input }], resetUpload: [{ type: Input }], ApiResponse: [{ type: Output }], uploadInitiated: [{ type: Output }], everythingDone: [{ type: Output }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZpbGUtdXBsb2FkZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Ii92YXIvd3d3L2h0bWwvbmd4LWZpbGUtdXBsb2FkZXIvcHJvamVjdHMvbmd4LWZpbGUtdXBsb2FkZXIvc3JjLyIsInNvdXJjZXMiOlsibGliL25neC1maWxlLXVwbG9hZGVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxFQUVOLGlCQUFpQixHQUNsQixNQUFNLGVBQWUsQ0FBQztBQU12QixPQUFPLEVBQ0wsVUFBVSxFQUdWLGFBQWEsR0FDZCxNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBZ0IsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVEzQyxNQUFNLE9BQU8sd0JBQXdCO0lBb0RuQzs7Ozs7T0FLRztJQUNILFlBQW9CLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7UUFyRDdCLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQzNCLFVBQVU7UUFFSCxnQkFBVyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFakMsb0JBQWUsR0FBMEIsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUU1RCxtQkFBYyxHQUErQixJQUFJLFlBQVksRUFBZ0IsQ0FBQztRQWdCOUUsaUJBQVksR0FBVyxFQUFFLENBQUM7UUFDMUIsb0JBQWUsR0FJaEIsRUFBRSxDQUFDO1FBQ0YsWUFBTyxHQUFhLEVBQUUsQ0FBQztRQUN2Qix3QkFBbUIsR0FBRyxJQUFJLENBQUM7UUFDM0Isb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFDeEIsb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFDeEIsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUNwQixrQkFBYSxHQUFHLEtBQUssQ0FB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Q0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzlDLENBQUM7SUFDRDs7OztPQUlHO0lBQ0ksZ0JBQWdCO1FBQ3JCLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6RCxJQUFJLE9BQU8sS0FBSyxJQUFJLEVBQUU7WUFDcEIsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ2pCO0lBQ0gsQ0FBQztJQUNEOzs7Ozs7T0FNRztJQUNJLElBQUksQ0FBQyxLQUFVO1FBQ3BCLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN4QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBQ0Q7Ozs7OztPQU1HO0lBQ0ksU0FBUyxDQUFDLEtBQVU7UUFDekIsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7SUFDekMsQ0FBQztJQUNEOzs7O09BSUc7SUFDSSxhQUFhO1FBQ2xCLElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFO1lBQzdCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztTQUN6QztJQUNILENBQUM7OztZQXZYRixTQUFTLFNBQUM7Z0JBQ1QsUUFBUSxFQUFFLG1CQUFtQjtnQkFDN0IsMjdJQUFpRDtnQkFFakQsYUFBYSxFQUFFLGlCQUFpQixDQUFDLElBQUk7O2FBQ3RDOzs7WUFiQyxVQUFVOzs7cUJBZ0JULEtBQUs7MEJBRUwsS0FBSzswQkFHTCxNQUFNOzhCQUVOLE1BQU07NkJBRU4sTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIFJlcGxhY2VUZXh0cyxcbiAgQW5ndWxhckZpbGVVcGxvYWRlckNvbmZpZyxcbiAgVXBsb2FkSW5mb1xufSBmcm9tICcuL25neC1maWxlLXVwbG9hZGVyLnR5cGVzJztcbmltcG9ydCB7XG4gIEh0dHBDbGllbnQsXG4gIEh0dHBIZWFkZXJzLFxuICBIdHRwUGFyYW1zLFxuICBIdHRwRXZlbnRUeXBlLFxufSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24sIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWZpbGUtdXBsb2FkZXInLFxuICB0ZW1wbGF0ZVVybDogJy4vbmd4LWZpbGUtdXBsb2FkZXIuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9uZ3gtZmlsZS11cGxvYWRlci5jb21wb25lbnQuc2NzcyddLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lXG59KVxuZXhwb3J0IGNsYXNzIE5neEZpbGVVcGxvYWRlckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8vIElucHV0c1xuICBASW5wdXQoKVxuICBwdWJsaWMgY29uZmlnOiBBbmd1bGFyRmlsZVVwbG9hZGVyQ29uZmlnO1xuICBASW5wdXQoKVxuICBwdWJsaWMgcmVzZXRVcGxvYWQgPSBmYWxzZTtcbiAgLy8gT3V0cHV0c1xuICBAT3V0cHV0KClcbiAgcHVibGljIEFwaVJlc3BvbnNlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KClcbiAgcHVibGljIHVwbG9hZEluaXRpYXRlZDogRXZlbnRFbWl0dGVyPGJvb2xlYW4+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KClcbiAgcHVibGljIGV2ZXJ5dGhpbmdEb25lOiBFdmVudEVtaXR0ZXI8VXBsb2FkSW5mb1tdPiA9IG5ldyBFdmVudEVtaXR0ZXI8VXBsb2FkSW5mb1tdPigpO1xuXG4gIC8vIFByb3BlcnRpZXNcbiAgcHVibGljIHRoZW1lOiBzdHJpbmc7XG4gIHB1YmxpYyBpZDogbnVtYmVyO1xuICBwdWJsaWMgaGlkZVByb2dyZXNzQmFyOiBib29sZWFuO1xuICBwdWJsaWMgbWF4U2l6ZTogbnVtYmVyO1xuICBwdWJsaWMgdXBsb2FkQVBJOiBzdHJpbmc7XG4gIHB1YmxpYyBtZXRob2Q6IHN0cmluZztcbiAgcHVibGljIGZvcm1hdHNBbGxvd2VkOiBzdHJpbmc7XG4gIHB1YmxpYyBtdWx0aXBsZTogYm9vbGVhbjtcbiAgcHVibGljIGhlYWRlcnM6IEh0dHBIZWFkZXJzIHwgeyBbaGVhZGVyOiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXSB9O1xuICBwdWJsaWMgcGFyYW1zOiBIdHRwUGFyYW1zIHwgeyBbcGFyYW06IHN0cmluZ106IHN0cmluZyB8IHN0cmluZ1tdIH07XG4gIHB1YmxpYyByZXNwb25zZVR5cGU6IHN0cmluZztcbiAgcHVibGljIGhpZGVSZXNldEJ0bjogYm9vbGVhbjtcbiAgcHVibGljIGhpZGVTZWxlY3RCdG46IGJvb2xlYW47XG4gIHB1YmxpYyBhbGxvd2VkRmlsZXM6IEZpbGVbXSA9IFtdO1xuICBwdWJsaWMgbm90QWxsb3dlZEZpbGVzOiB7XG4gICAgZmlsZU5hbWU6IHN0cmluZztcbiAgICBmaWxlU2l6ZTogc3RyaW5nO1xuICAgIGVycm9yTXNnOiBzdHJpbmc7XG4gIH1bXSA9IFtdO1xuICBwdWJsaWMgQ2FwdGlvbjogc3RyaW5nW10gPSBbXTtcbiAgcHVibGljIGlzQWxsb3dlZEZpbGVTaW5nbGUgPSB0cnVlO1xuICBwdWJsaWMgcHJvZ3Jlc3NCYXJTaG93ID0gZmFsc2U7XG4gIHB1YmxpYyBlbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgcHVibGljIHVwbG9hZE1zZyA9IGZhbHNlO1xuICBwdWJsaWMgYWZ0ZXJVcGxvYWQgPSBmYWxzZTtcbiAgcHVibGljIHVwbG9hZFN0YXJ0ZWQgPSBmYWxzZTtcbiAgcHVibGljIHVwbG9hZE1zZ1RleHQ6IHN0cmluZztcbiAgcHVibGljIHVwbG9hZE1zZ0NsYXNzOiBzdHJpbmc7XG4gIHB1YmxpYyB1cGxvYWRQZXJjZW50OiBudW1iZXI7XG4gIHB1YmxpYyByZXBsYWNlVGV4dHM6IFJlcGxhY2VUZXh0cztcbiAgcHVibGljIGN1cnJlbnRVcGxvYWRzOiBhbnlbXSA9IFtdO1xuICBwdWJsaWMgZmlsZU5hbWVJbmRleCA9IHRydWU7XG5cbiAgcHJpdmF0ZSBpZERhdGU6IG51bWJlciA9ICtuZXcgRGF0ZSgpO1xuICAvKiBTdWJzY3JpcHRpb25zICovXG4gIHByaXZhdGUgaHR0cENhbGxTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBkZXN0cm95ID0gbmV3IFN1YmplY3QoKTtcbiAgLyoqXG4gICAqIGNvbnN0cnVjdG9yXG4gICAqXG4gICAqIEBwYXJhbSAgIHtIdHRwQ2xpZW50fSAgaHR0cFxuICAgKlxuICAgKi9cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50KSB7fVxuICAvKipcbiAgICogbmdPbkNoYW5nZXNcbiAgICpcbiAgICogQHBhcmFtICAge1NpbXBsZUNoYW5nZXN9ICBjaGFuZ2VzXG4gICAqXG4gICAqIEByZXR1cm4gIHt2b2lkfVxuICAgKi9cbiAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAvLyBUcmFjayBjaGFuZ2VzIGluIENvbmZpZ3VyYXRpb24gYW5kIHNlZSBpZiB1c2VyIGhhcyBldmVuIHByb3ZpZGVkIENvbmZpZ3VyYXRpb24uXG4gICAgaWYgKGNoYW5nZXMuY29uZmlnICYmIHRoaXMuY29uZmlnKSB7XG4gICAgICAvLyBBc3NpZ24gVXNlciBDb25maWd1cmF0aW9ucyB0byBMaWJyYXJ5IFByb3BlcnRpZXMuXG4gICAgICB0aGlzLnRoZW1lID0gdGhpcy5jb25maWcudGhlbWUgfHwgJyc7XG4gICAgICB0aGlzLmlkID1cbiAgICAgICAgdGhpcy5jb25maWcuaWQgfHxcbiAgICAgICAgcGFyc2VJbnQoKHRoaXMuaWREYXRlIC8gMTAwMDApLnRvU3RyaW5nKCkuc3BsaXQoJy4nKVsxXSwgMTApICtcbiAgICAgICAgICBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAyMCkgKiAxMDAwMDtcbiAgICAgIHRoaXMuaGlkZVByb2dyZXNzQmFyID0gdGhpcy5jb25maWcuaGlkZVByb2dyZXNzQmFyIHx8IGZhbHNlO1xuICAgICAgdGhpcy5oaWRlUmVzZXRCdG4gPSB0aGlzLmNvbmZpZy5oaWRlUmVzZXRCdG4gfHwgZmFsc2U7XG4gICAgICB0aGlzLmhpZGVTZWxlY3RCdG4gPSB0aGlzLmNvbmZpZy5oaWRlU2VsZWN0QnRuIHx8IGZhbHNlO1xuICAgICAgdGhpcy5tYXhTaXplID0gKHRoaXMuY29uZmlnLm1heFNpemUgfHwgMjApICogMTAyNDAwMDsgLy8gbWIgdG8gYnl0ZXMuXG4gICAgICB0aGlzLnVwbG9hZEFQSSA9IHRoaXMuY29uZmlnLnVwbG9hZEFQSS51cmw7XG4gICAgICB0aGlzLm1ldGhvZCA9IHRoaXMuY29uZmlnLnVwbG9hZEFQSS5tZXRob2QgfHwgJ1BPU1QnO1xuICAgICAgdGhpcy5mb3JtYXRzQWxsb3dlZCA9XG4gICAgICAgIHRoaXMuY29uZmlnLmZvcm1hdHNBbGxvd2VkIHx8ICcuanBnLC5wbmcsLnBkZiwuZG9jeCwudHh0LC5naWYsLmpwZWcnO1xuICAgICAgdGhpcy5tdWx0aXBsZSA9IHRoaXMuY29uZmlnLm11bHRpcGxlIHx8IGZhbHNlO1xuICAgICAgdGhpcy5oZWFkZXJzID0gdGhpcy5jb25maWcudXBsb2FkQVBJLmhlYWRlcnMgfHwge307XG4gICAgICB0aGlzLnBhcmFtcyA9IHRoaXMuY29uZmlnLnVwbG9hZEFQSS5wYXJhbXMgfHwge307XG4gICAgICB0aGlzLnJlc3BvbnNlVHlwZSA9IHRoaXMuY29uZmlnLnVwbG9hZEFQSS5yZXNwb25zZVR5cGUgfHwgbnVsbDtcbiAgICAgIHRoaXMuZmlsZU5hbWVJbmRleCA9IHRoaXMuY29uZmlnLmZpbGVOYW1lSW5kZXggPT09IGZhbHNlID8gZmFsc2UgOiB0cnVlO1xuICAgICAgdGhpcy5yZXBsYWNlVGV4dHMgPSB7XG4gICAgICAgIHNlbGVjdEZpbGVCdG46IHRoaXMubXVsdGlwbGUgPyAnU2VsZWN0IEZpbGVzJyA6ICdTZWxlY3QgRmlsZScsXG4gICAgICAgIHJlc2V0QnRuOiAnUmVzZXQnLFxuICAgICAgICB1cGxvYWRCdG46ICdVcGxvYWQnLFxuICAgICAgICBkcmFnTkRyb3BCb3g6ICdEcmFnIE4gRHJvcCcsXG4gICAgICAgIHBsZWFzZVdhaXRNZXNzYWdlOiAnUGxlYXNlIHdhaXQgdW50aWwgZmlsZSBpcyB1cGxvYWRlZCcsXG4gICAgICAgIGF0dGFjaFBpbkJ0bjogdGhpcy5tdWx0aXBsZSA/ICdBdHRhY2ggRmlsZXMuLi4nIDogJ0F0dGFjaCBGaWxlLi4uJyxcbiAgICAgICAgYWZ0ZXJVcGxvYWRNc2dfc3VjY2VzczogJ1N1Y2Nlc3NmdWxseSBVcGxvYWRlZCAhJyxcbiAgICAgICAgYWZ0ZXJVcGxvYWRNc2dfZXJyb3I6ICdVcGxvYWQgRmFpbGVkICEnLFxuICAgICAgICBzaXplTGltaXQ6ICdTaXplIExpbWl0JyxcbiAgICAgIH07IC8vIGRlZmF1bHQgcmVwbGFjZVRleHQuXG4gICAgICBpZiAodGhpcy5jb25maWcucmVwbGFjZVRleHRzKSB7XG4gICAgICAgIC8vIHVwZGF0ZWQgcmVwbGFjZVRleHQgaWYgdXNlciBoYXMgcHJvdmlkZWQgYW55LlxuICAgICAgICB0aGlzLnJlcGxhY2VUZXh0cyA9IHtcbiAgICAgICAgICAuLi50aGlzLnJlcGxhY2VUZXh0cyxcbiAgICAgICAgICAuLi50aGlzLmNvbmZpZy5yZXBsYWNlVGV4dHMsXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgd2hlbiByZXNldFVwbG9hZCB2YWx1ZSBjaGFuZ2VzIGZyb20gZmFsc2UgdG8gdHJ1ZS5cbiAgICBpZiAoY2hhbmdlcy5yZXNldFVwbG9hZCkge1xuICAgICAgaWYgKGNoYW5nZXMucmVzZXRVcGxvYWQuY3VycmVudFZhbHVlID09PSB0cnVlKSB7XG4gICAgICAgIHRoaXMucmVzZXRGaWxlVXBsb2FkKCk7XG4gICAgICB9XG4gICAgfVxuXG4gIH1cbiAgLyoqXG4gICAqIG5nT25EZXN0cm95XG4gICAqXG4gICAqIEByZXR1cm4gIHt2b2lkfVxuICAgKi9cbiAgcHVibGljIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveS5uZXh0KCk7XG4gICAgdGhpcy5kZXN0cm95LmNvbXBsZXRlKCk7XG4gIH1cblxuICAvKipcbiAgICogcmVzZXRGaWxlVXBsb2FkXG4gICAqIFJlc2V0IGZvbGxvd2luZyBwcm9wZXJ0aWVzLlxuICAgKlxuICAgKiBAcmV0dXJuICB7dm9pZH1cbiAgICovXG4gIHB1YmxpYyByZXNldEZpbGVVcGxvYWQoKTogdm9pZCB7XG4gICAgdGhpcy5hbGxvd2VkRmlsZXMgPSBbXTtcbiAgICB0aGlzLkNhcHRpb24gPSBbXTtcbiAgICB0aGlzLm5vdEFsbG93ZWRGaWxlcyA9IFtdO1xuICAgIHRoaXMudXBsb2FkTXNnID0gZmFsc2U7XG4gICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBvbkNoYW5nZSBob29rXG4gICAqICAtIENoZWNrIHdoZW4gdXNlciBzZWxlY3RzIGZpbGVzLlxuICAgKlxuICAgKiBAcGFyYW0gICB7YW55fSAgIGV2ZW50XG4gICAqXG4gICAqIEByZXR1cm4gIHt2b2lkfVxuICAgKi9cbiAgcHVibGljIG9uQ2hhbmdlKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLm5vdEFsbG93ZWRGaWxlcyA9IFtdO1xuICAgIGNvbnN0IGZpbGVFeHRSZWdFeHA6IFJlZ0V4cCA9IC8oPzpcXC4oW14uXSspKT8kLztcbiAgICBsZXQgZmlsZUxpc3Q6IEZpbGVMaXN0O1xuXG4gICAgaWYgKHRoaXMuYWZ0ZXJVcGxvYWQgfHwgIXRoaXMubXVsdGlwbGUpIHtcbiAgICAgIHRoaXMuYWxsb3dlZEZpbGVzID0gW107XG4gICAgICB0aGlzLkNhcHRpb24gPSBbXTtcbiAgICAgIHRoaXMuYWZ0ZXJVcGxvYWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnQudHlwZSA9PT0gJ2Ryb3AnKSB7XG4gICAgICBmaWxlTGlzdCA9IGV2ZW50LmRhdGFUcmFuc2Zlci5maWxlcztcbiAgICB9IGVsc2Uge1xuICAgICAgZmlsZUxpc3QgPSBldmVudC50YXJnZXQuZmlsZXMgfHwgZXZlbnQuc3JjRWxlbWVudC5maWxlcztcbiAgICB9XG5cbiAgICAvLyAnZm9yRWFjaCcgZG9lcyBub3QgZXhpc3Qgb24gJ2ZpbGVsaXN0JyB0aGF0J3Mgd2h5IHRoaXMgZ29vZCBvbGQgJ2ZvcicgaXMgdXNlZC5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZpbGVMaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjdXJyZW50RmlsZUV4dCA9IGZpbGVFeHRSZWdFeHBcbiAgICAgICAgLmV4ZWMoZmlsZUxpc3RbaV0ubmFtZSlbMV1cbiAgICAgICAgLnRvTG93ZXJDYXNlKCk7IC8vIEdldCBmaWxlIGV4dGVuc2lvbi5cbiAgICAgIGNvbnN0IGlzRm9ybWF0VmFsaWQgPSB0aGlzLmZvcm1hdHNBbGxvd2VkLmluY2x1ZGVzKGN1cnJlbnRGaWxlRXh0KTtcblxuICAgICAgY29uc3QgaXNTaXplVmFsaWQgPSBmaWxlTGlzdFtpXS5zaXplIDw9IHRoaXMubWF4U2l6ZTtcblxuICAgICAgLy8gQ2hlY2sgd2hldGhlciBjdXJyZW50IGZpbGUgZm9ybWF0IGFuZCBzaXplIGlzIGNvcnJlY3QgYXMgc3BlY2lmaWVkIGluIHRoZSBjb25maWd1cmF0aW9ucy5cbiAgICAgIGlmIChpc0Zvcm1hdFZhbGlkICYmIGlzU2l6ZVZhbGlkKSB7XG4gICAgICAgIHRoaXMuYWxsb3dlZEZpbGVzLnB1c2goZmlsZUxpc3RbaV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ub3RBbGxvd2VkRmlsZXMucHVzaCh7XG4gICAgICAgICAgZmlsZU5hbWU6IGZpbGVMaXN0W2ldLm5hbWUsXG4gICAgICAgICAgZmlsZVNpemU6IHRoaXMuY29udmVydFNpemUoZmlsZUxpc3RbaV0uc2l6ZSksXG4gICAgICAgICAgZXJyb3JNc2c6ICFpc0Zvcm1hdFZhbGlkID8gJ0ludmFsaWQgZm9ybWF0JyA6ICdJbnZhbGlkIHNpemUnLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiB0aGVyZSdzIGFueSBhbGxvd2VkRmlsZXMuXG4gICAgaWYgKHRoaXMuYWxsb3dlZEZpbGVzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuZW5hYmxlVXBsb2FkQnRuID0gdHJ1ZTtcbiAgICAgIC8vIFVwbG9hZCB0aGUgZmlsZXMgZGlyZWN0bHkgaWYgdGhlbWUgaXMgYXR0YWNoIHBpbiAoYXMgdXBsb2FkIGJ0biBpcyBub3QgdGhlcmUgZm9yIHRoaXMgdGhlbWUpLlxuICAgICAgaWYgKHRoaXMudGhlbWUgPT09ICdhdHRhY2hQaW4nKSB7XG4gICAgICAgIHRoaXMudXBsb2FkRmlsZXMoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLnVwbG9hZE1zZyA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkU3RhcnRlZCA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkUGVyY2VudCA9IDA7XG4gICAgZXZlbnQudGFyZ2V0LnZhbHVlID0gbnVsbDtcbiAgfVxuICAvKipcbiAgICogdXBsb2FkRmlsZXNcbiAgICpcbiAgICogQHJldHVybiAge3ZvaWR9XG4gICAqL1xuICBwdWJsaWMgdXBsb2FkRmlsZXMoKTogdm9pZCB7XG4gICAgdGhpcy51cGxvYWRJbml0aWF0ZWQuZW1pdCh0cnVlKTtcbiAgICB0aGlzLnByb2dyZXNzQmFyU2hvdyA9IHRydWU7XG4gICAgdGhpcy51cGxvYWRTdGFydGVkID0gdHJ1ZTtcbiAgICB0aGlzLm5vdEFsbG93ZWRGaWxlcyA9IFtdO1xuICAgIGxldCBpc0Vycm9yID0gZmFsc2U7XG4gICAgdGhpcy5pc0FsbG93ZWRGaWxlU2luZ2xlID0gdGhpcy5hbGxvd2VkRmlsZXMubGVuZ3RoIDw9IDE7XG4gICAgY29uc3QgZm9ybURhdGEgPSBuZXcgRm9ybURhdGEoKTtcblxuICAgIC8vIEFkZCBkYXRhIHRvIGJlIHNlbnQgaW4gdGhpcyByZXF1ZXN0XG4gICAgdGhpcy5hbGxvd2VkRmlsZXMuZm9yRWFjaCgoZmlsZSwgaSkgPT4ge1xuICAgICAgZm9ybURhdGEuYXBwZW5kKFxuICAgICAgICB0aGlzLkNhcHRpb25baV0gfHwgJ2ZpbGUnICsgKHRoaXMuZmlsZU5hbWVJbmRleCA/IGkgOiAnJyksXG4gICAgICAgIHRoaXMuYWxsb3dlZEZpbGVzW2ldXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgIGhlYWRlcnM6IHRoaXMuaGVhZGVycyxcbiAgICAgIHBhcmFtczogdGhpcy5wYXJhbXMsXG4gICAgfTtcblxuICAgIGlmICh0aGlzLnJlc3BvbnNlVHlwZSkge1xuICAgICAgIChvcHRpb25zIGFzIGFueSkucmVzcG9uc2VUeXBlID0gdGhpcy5yZXNwb25zZVR5cGU7XG4gICAgfVxuXG4gICAgdGhpcy5odHRwQ2FsbFN1YnNjcmlwdGlvbiA9IHRoaXMuaHR0cFxuICAgICAgLnJlcXVlc3QodGhpcy5tZXRob2QudG9VcHBlckNhc2UoKSwgdGhpcy51cGxvYWRBUEksIHtcbiAgICAgICAgYm9keTogZm9ybURhdGEsXG4gICAgICAgIHJlcG9ydFByb2dyZXNzOiB0cnVlLFxuICAgICAgICBvYnNlcnZlOiAnZXZlbnRzJyxcbiAgICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIH0pLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSkpLnN1YnNjcmliZShcbiAgICAgICAgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgLy8gVXBsb2FkIFByb2dyZXNzXG4gICAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IEh0dHBFdmVudFR5cGUuVXBsb2FkUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgIHRoaXMuZW5hYmxlVXBsb2FkQnRuID0gZmFsc2U7IC8vIGJ1dHRvbiBzaG91bGQgYmUgZGlzYWJsZWQgaWYgcHJvY2VzcyB1cGxvYWRpbmdcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnREb25lID0gZXZlbnQubG9hZGVkIC8gZXZlbnQudG90YWw7XG4gICAgICAgICAgICB0aGlzLnVwbG9hZFBlcmNlbnQgPSBNYXRoLnJvdW5kKChldmVudC5sb2FkZWQgLyBldmVudC50b3RhbCkgKiAxMDApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gSHR0cEV2ZW50VHlwZS5SZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGV2ZW50LnN0YXR1cyA9PT0gMjAwIHx8IGV2ZW50LnN0YXR1cyA9PT0gMjAxKSB7XG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcbiAgICAgICAgICAgICAgdGhpcy5wcm9ncmVzc0JhclNob3cgPSBmYWxzZTtcbiAgICAgICAgICAgICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgICAgICAgICAgICAgdGhpcy51cGxvYWRTdGFydGVkID0gZmFsc2U7XG4gICAgICAgICAgICAgIHRoaXMudXBsb2FkSW5pdGlhdGVkLmVtaXQoZmFsc2UpO1xuICAgICAgICAgICAgICB0aGlzLnVwbG9hZE1zZyA9IHRydWU7XG4gICAgICAgICAgICAgIHRoaXMuYWZ0ZXJVcGxvYWQgPSB0cnVlO1xuICAgICAgICAgICAgICBpZiAoIWlzRXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZE1zZ1RleHQgPSB0aGlzLnJlcGxhY2VUZXh0cy5hZnRlclVwbG9hZE1zZ19zdWNjZXNzO1xuICAgICAgICAgICAgICAgIHRoaXMudXBsb2FkTXNnQ2xhc3MgPSAndGV4dC1zdWNjZXNzIGxlYWQnO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBGYWlsdXJlXG4gICAgICAgICAgICAgIGlzRXJyb3IgPSB0cnVlO1xuICAgICAgICAgICAgICB0aGlzLmhhbmRsZUVycm9ycygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLkFwaVJlc3BvbnNlLmVtaXQoZXZlbnQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnRXZlbnQgT3RoZXI6ICcsIGV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICAgIC8vIEZhaWx1cmVcbiAgICAgICAgICBpc0Vycm9yID0gdHJ1ZTtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVycm9ycygpO1xuICAgICAgICAgIHRoaXMuQXBpUmVzcG9uc2UuZW1pdChlcnJvcik7XG4gICAgICAgIH1cbiAgICAgICk7XG4gIH1cbiAgLyoqXG4gICAqIGhhbmRsZUVycm9yc1xuICAgKlxuICAgKiBAcmV0dXJuICB7dm9pZH1cbiAgICovXG4gIHB1YmxpYyBoYW5kbGVFcnJvcnMoKTogdm9pZCB7XG4gICAgdGhpcy5wcm9ncmVzc0JhclNob3cgPSBmYWxzZTtcbiAgICB0aGlzLmVuYWJsZVVwbG9hZEJ0biA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkTXNnID0gdHJ1ZTtcbiAgICB0aGlzLmFmdGVyVXBsb2FkID0gdHJ1ZTtcbiAgICB0aGlzLnVwbG9hZE1zZ1RleHQgPSB0aGlzLnJlcGxhY2VUZXh0cy5hZnRlclVwbG9hZE1zZ19lcnJvcjtcbiAgICB0aGlzLnVwbG9hZE1zZ0NsYXNzID0gJ3RleHQtZGFuZ2VyIGxlYWQnO1xuICAgIHRoaXMudXBsb2FkU3RhcnRlZCA9IGZhbHNlO1xuICAgIHRoaXMudXBsb2FkSW5pdGlhdGVkLmVtaXQoZmFsc2UpO1xuICB9XG4gIC8qKlxuICAgKiByZW1vdmVGaWxlXG4gICAqXG4gICAqIEBwYXJhbSAgIHthbnl9ICAgaVxuICAgKiBAcGFyYW0gICB7YW55fSAgIHNmTmFcbiAgICpcbiAgICogQHJldHVybiAge3ZvaWR9XG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlRmlsZShpOiBhbnksIHNmTmE6IGFueSk6IHZvaWQge1xuICAgIGlmIChzZk5hID09PSAnc2YnKSB7XG4gICAgICB0aGlzLmFsbG93ZWRGaWxlcy5zcGxpY2UoaSwgMSk7XG4gICAgICB0aGlzLkNhcHRpb24uc3BsaWNlKGksIDEpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm5vdEFsbG93ZWRGaWxlcy5zcGxpY2UoaSwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuYWxsb3dlZEZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5lbmFibGVVcGxvYWRCdG4gPSBmYWxzZTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIGNvbnZlcnRTaXplXG4gICAqXG4gICAqIEBwYXJhbSAgIHtudW1iZXJ9ICBmaWxlU2l6ZVxuICAgKlxuICAgKiBAcmV0dXJuICB7c3RyaW5nfVxuICAgKi9cbiAgcHVibGljIGNvbnZlcnRTaXplKGZpbGVTaXplOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIHJldHVybiBmaWxlU2l6ZSA8IDEwMjQwMDBcbiAgICAgID8gKGZpbGVTaXplIC8gMTAyNCkudG9GaXhlZCgyKSArICcgS0InXG4gICAgICA6IChmaWxlU2l6ZSAvIDEwMjQwMDApLnRvRml4ZWQoMikgKyAnIE1CJztcbiAgfVxuICAvKipcbiAgICogYXR0YWNocGluT25jbGlja1xuICAgKlxuICAgKiBAcmV0dXJuICB7dm9pZH1cbiAgICovXG4gIHB1YmxpYyBhdHRhY2hwaW5PbmNsaWNrKCk6IHZvaWQge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2VsJyArIHRoaXMuaWQpO1xuICAgIGlmIChlbGVtZW50ICE9PSBudWxsKSB7XG4gICAgICBlbGVtZW50LmNsaWNrKCk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBkcm9wXG4gICAqXG4gICAqIEBwYXJhbSAgIHthbnl9ICAgZXZlbnRcbiAgICpcbiAgICogQHJldHVybiAge3ZvaWR9XG4gICAqL1xuICBwdWJsaWMgZHJvcChldmVudDogYW55KTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLm9uQ2hhbmdlKGV2ZW50KTtcbiAgfVxuICAvKipcbiAgICogYWxsb3dEcm9wXG4gICAqXG4gICAqIEBwYXJhbSAgIHthbnl9ICAgZXZlbnRcbiAgICpcbiAgICogQHJldHVybiAge3ZvaWR9XG4gICAqL1xuICBwdWJsaWMgYWxsb3dEcm9wKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGV2ZW50LmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0ID0gJ2NvcHknO1xuICB9XG4gIC8qKlxuICAgKiBjYW5jZWxBcGlDYWxsXG4gICAqXG4gICAqIEByZXR1cm4gIHt2b2lkfVxuICAgKi9cbiAgcHVibGljIGNhbmNlbEFwaUNhbGwoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaHR0cENhbGxTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuaHR0cENhbGxTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==