ngxc-file-uploader
Version:
Ngxc file uploader is an Angular 9/10 + file uploader
339 lines • 44.1 kB
JavaScript
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> </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\"> <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 \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==