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
JavaScript
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> </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\"> <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 \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=